5
5
// sc7180.c -- ALSA SoC Machine driver for SC7180
6
6
7
7
#include <dt-bindings/sound/sc7180-lpass.h>
8
+ #include <dt-bindings/sound/qcom,q6afe.h>
8
9
#include <linux/gpio.h>
9
10
#include <linux/gpio/consumer.h>
10
11
#include <linux/module.h>
19
20
#include "../codecs/rt5682.h"
20
21
#include "../codecs/rt5682s.h"
21
22
#include "common.h"
23
+ #include "qdsp6/q6afe.h"
22
24
23
25
#define DEFAULT_MCLK_RATE 19200000
26
+ #define MI2S_BCLK_RATE 1536000
24
27
#define RT5682_PLL1_FREQ (48000 * 512)
25
28
26
29
#define DRIVER_NAME "SC7180"
@@ -133,12 +136,28 @@ static int sc7180_init(struct snd_soc_pcm_runtime *rtd)
133
136
return 0 ;
134
137
}
135
138
136
- static int sc7180_snd_startup (struct snd_pcm_substream * substream )
139
+ static int sc7180_qdsp_init (struct snd_soc_pcm_runtime * rtd )
137
140
{
138
- struct snd_soc_pcm_runtime * rtd = substream -> private_data ;
139
- struct snd_soc_card * card = rtd -> card ;
140
- struct sc7180_snd_data * data = snd_soc_card_get_drvdata (card );
141
141
struct snd_soc_dai * cpu_dai = snd_soc_rtd_to_cpu (rtd , 0 );
142
+
143
+ switch (cpu_dai -> id ) {
144
+ case PRIMARY_MI2S_RX :
145
+ return sc7180_headset_init (rtd );
146
+ case PRIMARY_MI2S_TX :
147
+ case TERTIARY_MI2S_RX :
148
+ return 0 ;
149
+ case DISPLAY_PORT_RX :
150
+ return sc7180_hdmi_init (rtd );
151
+ default :
152
+ dev_err (rtd -> dev , "%s: invalid dai id 0x%x\n" , __func__ ,
153
+ cpu_dai -> id );
154
+ return - EINVAL ;
155
+ }
156
+ return 0 ;
157
+ }
158
+
159
+ static int sc7180_startup_realtek_codec (struct snd_soc_pcm_runtime * rtd )
160
+ {
142
161
struct snd_soc_dai * codec_dai = snd_soc_rtd_to_codec (rtd , 0 );
143
162
int pll_id , pll_source , pll_in , pll_out , clk_id , ret ;
144
163
@@ -154,8 +173,40 @@ static int sc7180_snd_startup(struct snd_pcm_substream *substream)
154
173
clk_id = RT5682S_SCLK_S_PLL2 ;
155
174
pll_out = RT5682_PLL1_FREQ ;
156
175
pll_in = DEFAULT_MCLK_RATE ;
176
+ } else {
177
+ return 0 ;
178
+ }
179
+ snd_soc_dai_set_fmt (codec_dai ,
180
+ SND_SOC_DAIFMT_BC_FC |
181
+ SND_SOC_DAIFMT_NB_NF |
182
+ SND_SOC_DAIFMT_I2S );
183
+
184
+ /* Configure PLL1 for codec */
185
+ ret = snd_soc_dai_set_pll (codec_dai , pll_id , pll_source ,
186
+ pll_in , pll_out );
187
+ if (ret ) {
188
+ dev_err (rtd -> dev , "can't set codec pll: %d\n" , ret );
189
+ return ret ;
157
190
}
158
191
192
+ /* Configure sysclk for codec */
193
+ ret = snd_soc_dai_set_sysclk (codec_dai , clk_id , pll_out ,
194
+ SND_SOC_CLOCK_IN );
195
+ if (ret )
196
+ dev_err (rtd -> dev , "snd_soc_dai_set_sysclk err = %d\n" ,
197
+ ret );
198
+
199
+ return ret ;
200
+ }
201
+
202
+ static int sc7180_snd_startup (struct snd_pcm_substream * substream )
203
+ {
204
+ struct snd_soc_pcm_runtime * rtd = substream -> private_data ;
205
+ struct snd_soc_card * card = rtd -> card ;
206
+ struct sc7180_snd_data * data = snd_soc_card_get_drvdata (card );
207
+ struct snd_soc_dai * cpu_dai = snd_soc_rtd_to_cpu (rtd , 0 );
208
+ int ret ;
209
+
159
210
switch (cpu_dai -> id ) {
160
211
case MI2S_PRIMARY :
161
212
if (++ data -> pri_mi2s_clk_count == 1 ) {
@@ -165,30 +216,66 @@ static int sc7180_snd_startup(struct snd_pcm_substream *substream)
165
216
SNDRV_PCM_STREAM_PLAYBACK );
166
217
}
167
218
168
- snd_soc_dai_set_fmt (codec_dai ,
169
- SND_SOC_DAIFMT_BC_FC |
170
- SND_SOC_DAIFMT_NB_NF |
171
- SND_SOC_DAIFMT_I2S );
172
-
173
- /* Configure PLL1 for codec */
174
- ret = snd_soc_dai_set_pll (codec_dai , pll_id , pll_source ,
175
- pll_in , pll_out );
176
- if (ret ) {
177
- dev_err (rtd -> dev , "can't set codec pll: %d\n" , ret );
219
+ ret = sc7180_startup_realtek_codec (rtd );
220
+ if (ret )
178
221
return ret ;
222
+
223
+ break ;
224
+ case MI2S_SECONDARY :
225
+ break ;
226
+ case LPASS_DP_RX :
227
+ break ;
228
+ default :
229
+ dev_err (rtd -> dev , "%s: invalid dai id 0x%x\n" , __func__ ,
230
+ cpu_dai -> id );
231
+ return - EINVAL ;
232
+ }
233
+ return 0 ;
234
+ }
235
+
236
+ static int sc7180_qdsp_snd_startup (struct snd_pcm_substream * substream )
237
+ {
238
+ struct snd_soc_pcm_runtime * rtd = substream -> private_data ;
239
+ struct snd_soc_card * card = rtd -> card ;
240
+ struct sc7180_snd_data * data = snd_soc_card_get_drvdata (card );
241
+ struct snd_soc_dai * cpu_dai = snd_soc_rtd_to_cpu (rtd , 0 );
242
+ struct snd_soc_dai * codec_dai = snd_soc_rtd_to_codec (rtd , 0 );
243
+ int ret ;
244
+
245
+ switch (cpu_dai -> id ) {
246
+ case PRIMARY_MI2S_RX :
247
+ case PRIMARY_MI2S_TX :
248
+ if (++ data -> pri_mi2s_clk_count == 1 ) {
249
+ snd_soc_dai_set_sysclk (cpu_dai ,
250
+ Q6AFE_LPASS_CLK_ID_MCLK_1 ,
251
+ DEFAULT_MCLK_RATE ,
252
+ SNDRV_PCM_STREAM_PLAYBACK );
253
+ snd_soc_dai_set_sysclk (cpu_dai ,
254
+ Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT ,
255
+ MI2S_BCLK_RATE ,
256
+ SNDRV_PCM_STREAM_PLAYBACK );
179
257
}
180
258
181
- /* Configure sysclk for codec */
182
- ret = snd_soc_dai_set_sysclk ( codec_dai , clk_id , pll_out ,
183
- SND_SOC_CLOCK_IN );
259
+ snd_soc_dai_set_fmt ( cpu_dai , SND_SOC_DAIFMT_BP_FP );
260
+
261
+ ret = sc7180_startup_realtek_codec ( rtd );
184
262
if (ret )
185
- dev_err (rtd -> dev , "snd_soc_dai_set_sysclk err = %d\n" ,
186
- ret );
263
+ return ret ;
187
264
188
265
break ;
189
- case MI2S_SECONDARY :
266
+ case TERTIARY_MI2S_RX :
267
+ snd_soc_dai_set_sysclk (cpu_dai ,
268
+ Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT ,
269
+ MI2S_BCLK_RATE ,
270
+ SNDRV_PCM_STREAM_PLAYBACK );
271
+
272
+ snd_soc_dai_set_fmt (codec_dai ,
273
+ SND_SOC_DAIFMT_BC_FC |
274
+ SND_SOC_DAIFMT_NB_NF |
275
+ SND_SOC_DAIFMT_I2S );
276
+ snd_soc_dai_set_fmt (cpu_dai , SND_SOC_DAIFMT_BP_FP );
190
277
break ;
191
- case LPASS_DP_RX :
278
+ case DISPLAY_PORT_RX :
192
279
break ;
193
280
default :
194
281
dev_err (rtd -> dev , "%s: invalid dai id 0x%x\n" , __func__ ,
@@ -246,6 +333,42 @@ static void sc7180_snd_shutdown(struct snd_pcm_substream *substream)
246
333
}
247
334
}
248
335
336
+ static void sc7180_qdsp_snd_shutdown (struct snd_pcm_substream * substream )
337
+ {
338
+ struct snd_soc_pcm_runtime * rtd = substream -> private_data ;
339
+ struct snd_soc_card * card = rtd -> card ;
340
+ struct sc7180_snd_data * data = snd_soc_card_get_drvdata (card );
341
+ struct snd_soc_dai * cpu_dai = snd_soc_rtd_to_cpu (rtd , 0 );
342
+
343
+ switch (cpu_dai -> id ) {
344
+ case PRIMARY_MI2S_RX :
345
+ case PRIMARY_MI2S_TX :
346
+ if (-- data -> pri_mi2s_clk_count == 0 ) {
347
+ snd_soc_dai_set_sysclk (cpu_dai ,
348
+ Q6AFE_LPASS_CLK_ID_MCLK_1 ,
349
+ 0 ,
350
+ SNDRV_PCM_STREAM_PLAYBACK );
351
+ snd_soc_dai_set_sysclk (cpu_dai ,
352
+ Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT ,
353
+ 0 ,
354
+ SNDRV_PCM_STREAM_PLAYBACK );
355
+ }
356
+ break ;
357
+ case TERTIARY_MI2S_RX :
358
+ snd_soc_dai_set_sysclk (cpu_dai ,
359
+ Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT ,
360
+ 0 ,
361
+ SNDRV_PCM_STREAM_PLAYBACK );
362
+ break ;
363
+ case DISPLAY_PORT_RX :
364
+ break ;
365
+ default :
366
+ dev_err (rtd -> dev , "%s: invalid dai id 0x%x\n" , __func__ ,
367
+ cpu_dai -> id );
368
+ break ;
369
+ }
370
+ }
371
+
249
372
static int sc7180_adau7002_init (struct snd_soc_pcm_runtime * rtd )
250
373
{
251
374
struct snd_soc_dai * cpu_dai = snd_soc_rtd_to_cpu (rtd , 0 );
@@ -294,11 +417,30 @@ static int sc7180_adau7002_snd_startup(struct snd_pcm_substream *substream)
294
417
return 0 ;
295
418
}
296
419
420
+ static int sc7180_qdsp_be_hw_params_fixup (struct snd_soc_pcm_runtime * rtd ,
421
+ struct snd_pcm_hw_params * params )
422
+ {
423
+ struct snd_interval * rate = hw_param_interval (params ,
424
+ SNDRV_PCM_HW_PARAM_RATE );
425
+ struct snd_interval * channels = hw_param_interval (params ,
426
+ SNDRV_PCM_HW_PARAM_CHANNELS );
427
+
428
+ rate -> min = rate -> max = 48000 ;
429
+ channels -> min = channels -> max = 2 ;
430
+
431
+ return 0 ;
432
+ }
433
+
297
434
static const struct snd_soc_ops sc7180_ops = {
298
435
.startup = sc7180_snd_startup ,
299
436
.shutdown = sc7180_snd_shutdown ,
300
437
};
301
438
439
+ static const struct snd_soc_ops sc7180_qdsp_ops = {
440
+ .startup = sc7180_qdsp_snd_startup ,
441
+ .shutdown = sc7180_qdsp_snd_shutdown ,
442
+ };
443
+
302
444
static const struct snd_soc_ops sc7180_adau7002_ops = {
303
445
.startup = sc7180_adau7002_snd_startup ,
304
446
};
@@ -354,7 +496,7 @@ static int sc7180_snd_platform_probe(struct platform_device *pdev)
354
496
struct snd_soc_dai_link * link ;
355
497
int ret ;
356
498
int i ;
357
- bool no_headphone = false;
499
+ bool qdsp = false, no_headphone = false;
358
500
359
501
/* Allocate the private data */
360
502
data = devm_kzalloc (dev , sizeof (* data ), GFP_KERNEL );
@@ -390,6 +532,8 @@ static int sc7180_snd_platform_probe(struct platform_device *pdev)
390
532
no_headphone = true;
391
533
card -> dapm_widgets = sc7180_adau7002_snd_widgets ;
392
534
card -> num_dapm_widgets = ARRAY_SIZE (sc7180_adau7002_snd_widgets );
535
+ } else if (of_device_is_compatible (dev -> of_node , "qcom,sc7180-qdsp6-sndcard" )) {
536
+ qdsp = true;
393
537
}
394
538
395
539
ret = qcom_snd_parse_of (card );
@@ -400,6 +544,12 @@ static int sc7180_snd_platform_probe(struct platform_device *pdev)
400
544
if (no_headphone ) {
401
545
link -> ops = & sc7180_adau7002_ops ;
402
546
link -> init = sc7180_adau7002_init ;
547
+ } else if (qdsp ) {
548
+ if (link -> no_pcm == 1 ) {
549
+ link -> ops = & sc7180_qdsp_ops ;
550
+ link -> be_hw_params_fixup = sc7180_qdsp_be_hw_params_fixup ;
551
+ link -> init = sc7180_qdsp_init ;
552
+ }
403
553
} else {
404
554
link -> ops = & sc7180_ops ;
405
555
link -> init = sc7180_init ;
@@ -412,6 +562,7 @@ static int sc7180_snd_platform_probe(struct platform_device *pdev)
412
562
static const struct of_device_id sc7180_snd_device_id [] = {
413
563
{.compatible = "google,sc7180-trogdor" },
414
564
{.compatible = "google,sc7180-coachz" },
565
+ {.compatible = "qcom,sc7180-qdsp6-sndcard" },
415
566
{},
416
567
};
417
568
MODULE_DEVICE_TABLE (of , sc7180_snd_device_id );
0 commit comments