10
10
*/
11
11
12
12
#include <linux/acpi.h>
13
+ #include <linux/bitfield.h>
13
14
#include <linux/clk.h>
14
15
#include <linux/device.h>
15
16
#include <linux/init.h>
16
17
#include <linux/module.h>
17
18
#include <linux/moduleparam.h>
19
+ #include <linux/platform_data/x86/soc.h>
18
20
#include <linux/platform_device.h>
19
21
#include <linux/slab.h>
20
22
#include <linux/spi/spi.h>
26
28
#include "../../codecs/wm5102.h"
27
29
#include "../atom/sst-atom-controls.h"
28
30
29
- #define MCLK_FREQ 25000000
30
-
31
31
#define WM5102_MAX_SYSCLK_4K 49152000 /* max sysclk for 4K family */
32
32
#define WM5102_MAX_SYSCLK_11025 45158400 /* max sysclk for 11.025K family */
33
33
34
34
struct byt_wm5102_private {
35
35
struct snd_soc_jack jack ;
36
36
struct clk * mclk ;
37
37
struct gpio_desc * spkvdd_en_gpio ;
38
+ int mclk_freq ;
38
39
};
39
40
41
+ #define BYT_WM5102_IN_MAP GENMASK(3, 0)
42
+ #define BYT_WM5102_OUT_MAP GENMASK(7, 4)
43
+ #define BYT_WM5102_SSP2 BIT(16)
44
+ #define BYT_WM5102_MCLK_19_2MHZ BIT(17)
45
+
46
+ enum {
47
+ BYT_WM5102_INTMIC_IN3L_HSMIC_IN1L ,
48
+ BYT_WM5102_INTMIC_IN1L_HSMIC_IN2L ,
49
+ };
50
+
51
+ /* Note these values are pre-shifted for easy use of setting quirks */
52
+ enum {
53
+ BYT_WM5102_SPK_SPK_MAP = FIELD_PREP_CONST (BYT_WM5102_OUT_MAP , 0 ),
54
+ BYT_WM5102_SPK_HPOUT2_MAP = FIELD_PREP_CONST (BYT_WM5102_OUT_MAP , 1 ),
55
+ };
56
+
57
+ static unsigned long quirk ;
58
+
59
+ static int quirk_override = -1 ;
60
+ module_param_named (quirk , quirk_override , int , 0444 );
61
+ MODULE_PARM_DESC (quirk , "Board-specific quirk override" );
62
+
63
+ static void log_quirks (struct device * dev )
64
+ {
65
+ switch (quirk & BYT_WM5102_IN_MAP ) {
66
+ case BYT_WM5102_INTMIC_IN3L_HSMIC_IN1L :
67
+ dev_info_once (dev , "quirk INTMIC_IN3L_HSMIC_IN1L enabled\n" );
68
+ break ;
69
+ case BYT_WM5102_INTMIC_IN1L_HSMIC_IN2L :
70
+ dev_info_once (dev , "quirk INTMIC_IN1L_HSMIC_IN2L enabled\n" );
71
+ break ;
72
+ default :
73
+ dev_warn_once (dev , "quirk sets invalid input map: 0x%lx, defaulting to INTMIC_IN3L_HSMIC_IN1L\n" ,
74
+ quirk & BYT_WM5102_IN_MAP );
75
+ quirk &= ~BYT_WM5102_IN_MAP ;
76
+ quirk |= BYT_WM5102_INTMIC_IN3L_HSMIC_IN1L ;
77
+ break ;
78
+ }
79
+ switch (quirk & BYT_WM5102_OUT_MAP ) {
80
+ case BYT_WM5102_SPK_SPK_MAP :
81
+ dev_info_once (dev , "quirk SPK_SPK_MAP enabled\n" );
82
+ break ;
83
+ case BYT_WM5102_SPK_HPOUT2_MAP :
84
+ dev_info_once (dev , "quirk SPK_HPOUT2_MAP enabled\n" );
85
+ break ;
86
+ default :
87
+ dev_warn_once (dev , "quirk sets invalid output map: 0x%lx, defaulting to SPK_SPK_MAP\n" ,
88
+ quirk & BYT_WM5102_OUT_MAP );
89
+ quirk &= ~BYT_WM5102_OUT_MAP ;
90
+ quirk |= BYT_WM5102_SPK_SPK_MAP ;
91
+ break ;
92
+ }
93
+ if (quirk & BYT_WM5102_SSP2 )
94
+ dev_info_once (dev , "quirk SSP2 enabled" );
95
+ if (quirk & BYT_WM5102_MCLK_19_2MHZ )
96
+ dev_info_once (dev , "quirk MCLK 19.2MHz enabled" );
97
+ }
98
+
40
99
static int byt_wm5102_spkvdd_power_event (struct snd_soc_dapm_widget * w ,
41
100
struct snd_kcontrol * kcontrol , int event )
42
101
{
@@ -52,6 +111,7 @@ static int byt_wm5102_spkvdd_power_event(struct snd_soc_dapm_widget *w,
52
111
static int byt_wm5102_prepare_and_enable_pll1 (struct snd_soc_dai * codec_dai , int rate )
53
112
{
54
113
struct snd_soc_component * codec_component = codec_dai -> component ;
114
+ struct byt_wm5102_private * priv = snd_soc_card_get_drvdata (codec_component -> card );
55
115
int sr_mult = ((rate % 4000 ) == 0 ) ?
56
116
(WM5102_MAX_SYSCLK_4K / rate ) :
57
117
(WM5102_MAX_SYSCLK_11025 / rate );
@@ -63,7 +123,7 @@ static int byt_wm5102_prepare_and_enable_pll1(struct snd_soc_dai *codec_dai, int
63
123
64
124
/* Configure the FLL1 PLL before selecting it */
65
125
ret = snd_soc_dai_set_pll (codec_dai , WM5102_FLL1 , ARIZONA_CLK_SRC_MCLK1 ,
66
- MCLK_FREQ , rate * sr_mult );
126
+ priv -> mclk_freq , rate * sr_mult );
67
127
if (ret ) {
68
128
dev_err (codec_component -> dev , "Error setting PLL: %d\n" , ret );
69
129
return ret ;
@@ -145,35 +205,58 @@ static const struct snd_soc_dapm_route byt_wm5102_audio_map[] = {
145
205
{"Headset Mic" , NULL , "Platform Clock" },
146
206
{"Internal Mic" , NULL , "Platform Clock" },
147
207
{"Speaker" , NULL , "Platform Clock" },
148
- {"Line Out" , NULL , "Platform Clock" },
149
-
150
- {"Speaker" , NULL , "SPKOUTLP" },
151
- {"Speaker" , NULL , "SPKOUTLN" },
152
- {"Speaker" , NULL , "SPKOUTRP" },
153
- {"Speaker" , NULL , "SPKOUTRN" },
154
208
{"Speaker" , NULL , "Speaker VDD" },
155
209
156
210
{"Headphone" , NULL , "HPOUT1L" },
157
211
{"Headphone" , NULL , "HPOUT1R" },
158
212
159
- {"Internal Mic" , NULL , "MICBIAS3" },
160
- {"IN3L" , NULL , "Internal Mic" },
161
-
162
213
/*
163
214
* The Headset Mix uses MICBIAS1 or 2 depending on if a CTIA/OMTP Headset
164
215
* is connected, as the MICBIAS is applied after the CTIA/OMTP cross-switch.
165
216
*/
166
217
{"Headset Mic" , NULL , "MICBIAS1" },
167
218
{"Headset Mic" , NULL , "MICBIAS2" },
168
- {"IN1L" , NULL , "Headset Mic" },
219
+ {"Internal Mic" , NULL , "MICBIAS3" },
220
+ };
169
221
222
+ static const struct snd_soc_dapm_route bytcr_wm5102_ssp0_map [] = {
170
223
{"AIF1 Playback" , NULL , "ssp0 Tx" },
171
224
{"ssp0 Tx" , NULL , "modem_out" },
172
-
173
225
{"modem_in" , NULL , "ssp0 Rx" },
174
226
{"ssp0 Rx" , NULL , "AIF1 Capture" },
175
227
};
176
228
229
+ static const struct snd_soc_dapm_route bytcr_wm5102_ssp2_map [] = {
230
+ {"AIF1 Playback" , NULL , "ssp2 Tx" },
231
+ {"ssp2 Tx" , NULL , "codec_out0" },
232
+ {"ssp2 Tx" , NULL , "codec_out1" },
233
+ {"codec_in0" , NULL , "ssp2 Rx" },
234
+ {"codec_in1" , NULL , "ssp2 Rx" },
235
+ {"ssp2 Rx" , NULL , "AIF1 Capture" },
236
+ };
237
+
238
+ static const struct snd_soc_dapm_route byt_wm5102_spk_spk_map [] = {
239
+ {"Speaker" , NULL , "SPKOUTLP" },
240
+ {"Speaker" , NULL , "SPKOUTLN" },
241
+ {"Speaker" , NULL , "SPKOUTRP" },
242
+ {"Speaker" , NULL , "SPKOUTRN" },
243
+ };
244
+
245
+ static const struct snd_soc_dapm_route byt_wm5102_spk_hpout2_map [] = {
246
+ {"Speaker" , NULL , "HPOUT2L" },
247
+ {"Speaker" , NULL , "HPOUT2R" },
248
+ };
249
+
250
+ static const struct snd_soc_dapm_route byt_wm5102_intmic_in3l_hsmic_in1l_map [] = {
251
+ {"IN3L" , NULL , "Internal Mic" },
252
+ {"IN1L" , NULL , "Headset Mic" },
253
+ };
254
+
255
+ static const struct snd_soc_dapm_route byt_wm5102_intmic_in1l_hsmic_in2l_map [] = {
256
+ {"IN1L" , NULL , "Internal Mic" },
257
+ {"IN2L" , NULL , "Headset Mic" },
258
+ };
259
+
177
260
static const struct snd_kcontrol_new byt_wm5102_controls [] = {
178
261
SOC_DAPM_PIN_SWITCH ("Headphone" ),
179
262
SOC_DAPM_PIN_SWITCH ("Headset Mic" ),
@@ -202,7 +285,8 @@ static int byt_wm5102_init(struct snd_soc_pcm_runtime *runtime)
202
285
struct snd_soc_card * card = runtime -> card ;
203
286
struct byt_wm5102_private * priv = snd_soc_card_get_drvdata (card );
204
287
struct snd_soc_component * component = snd_soc_rtd_to_codec (runtime , 0 )-> component ;
205
- int ret , jack_type ;
288
+ const struct snd_soc_dapm_route * custom_map = NULL ;
289
+ int ret , jack_type , num_routes = 0 ;
206
290
207
291
card -> dapm .idle_bias_off = true;
208
292
@@ -213,6 +297,50 @@ static int byt_wm5102_init(struct snd_soc_pcm_runtime *runtime)
213
297
return ret ;
214
298
}
215
299
300
+ switch (quirk & BYT_WM5102_IN_MAP ) {
301
+ case BYT_WM5102_INTMIC_IN3L_HSMIC_IN1L :
302
+ custom_map = byt_wm5102_intmic_in3l_hsmic_in1l_map ;
303
+ num_routes = ARRAY_SIZE (byt_wm5102_intmic_in3l_hsmic_in1l_map );
304
+ break ;
305
+ case BYT_WM5102_INTMIC_IN1L_HSMIC_IN2L :
306
+ custom_map = byt_wm5102_intmic_in1l_hsmic_in2l_map ;
307
+ num_routes = ARRAY_SIZE (byt_wm5102_intmic_in1l_hsmic_in2l_map );
308
+ break ;
309
+ }
310
+ ret = snd_soc_dapm_add_routes (& card -> dapm , custom_map , num_routes );
311
+ if (ret )
312
+ return ret ;
313
+
314
+ switch (quirk & BYT_WM5102_OUT_MAP ) {
315
+ case BYT_WM5102_SPK_SPK_MAP :
316
+ custom_map = byt_wm5102_spk_spk_map ;
317
+ num_routes = ARRAY_SIZE (byt_wm5102_spk_spk_map );
318
+ break ;
319
+ case BYT_WM5102_SPK_HPOUT2_MAP :
320
+ custom_map = byt_wm5102_spk_hpout2_map ;
321
+ num_routes = ARRAY_SIZE (byt_wm5102_spk_hpout2_map );
322
+ break ;
323
+ }
324
+ ret = snd_soc_dapm_add_routes (& card -> dapm , custom_map , num_routes );
325
+ if (ret )
326
+ return ret ;
327
+
328
+ if (quirk & BYT_WM5102_SSP2 ) {
329
+ custom_map = bytcr_wm5102_ssp2_map ;
330
+ num_routes = ARRAY_SIZE (bytcr_wm5102_ssp2_map );
331
+ } else {
332
+ custom_map = bytcr_wm5102_ssp0_map ;
333
+ num_routes = ARRAY_SIZE (bytcr_wm5102_ssp0_map );
334
+ }
335
+ ret = snd_soc_dapm_add_routes (& card -> dapm , custom_map , num_routes );
336
+ if (ret )
337
+ return ret ;
338
+
339
+ if (quirk & BYT_WM5102_MCLK_19_2MHZ )
340
+ priv -> mclk_freq = 19200000 ;
341
+ else
342
+ priv -> mclk_freq = 25000000 ;
343
+
216
344
/*
217
345
* The firmware might enable the clock at boot (this information
218
346
* may or may not be reflected in the enable clock register).
@@ -225,7 +353,7 @@ static int byt_wm5102_init(struct snd_soc_pcm_runtime *runtime)
225
353
if (!ret )
226
354
clk_disable_unprepare (priv -> mclk );
227
355
228
- ret = clk_set_rate (priv -> mclk , MCLK_FREQ );
356
+ ret = clk_set_rate (priv -> mclk , priv -> mclk_freq );
229
357
if (ret ) {
230
358
dev_err (card -> dev , "Error setting MCLK rate: %d\n" , ret );
231
359
return ret ;
@@ -253,16 +381,23 @@ static int byt_wm5102_codec_fixup(struct snd_soc_pcm_runtime *rtd,
253
381
SNDRV_PCM_HW_PARAM_RATE );
254
382
struct snd_interval * channels = hw_param_interval (params ,
255
383
SNDRV_PCM_HW_PARAM_CHANNELS );
256
- int ret ;
384
+ int ret , bits ;
257
385
258
386
/* The DSP will convert the FE rate to 48k, stereo */
259
387
rate -> min = 48000 ;
260
388
rate -> max = 48000 ;
261
389
channels -> min = 2 ;
262
390
channels -> max = 2 ;
263
391
264
- /* set SSP0 to 16-bit */
265
- params_set_format (params , SNDRV_PCM_FORMAT_S16_LE );
392
+ if (quirk & BYT_WM5102_SSP2 ) {
393
+ /* set SSP2 to 24-bit */
394
+ params_set_format (params , SNDRV_PCM_FORMAT_S24_LE );
395
+ bits = 24 ;
396
+ } else {
397
+ /* set SSP0 to 16-bit */
398
+ params_set_format (params , SNDRV_PCM_FORMAT_S16_LE );
399
+ bits = 16 ;
400
+ }
266
401
267
402
/*
268
403
* Default mode for SSP configuration is TDM 4 slot, override config
@@ -278,7 +413,7 @@ static int byt_wm5102_codec_fixup(struct snd_soc_pcm_runtime *rtd,
278
413
return ret ;
279
414
}
280
415
281
- ret = snd_soc_dai_set_tdm_slot (snd_soc_rtd_to_cpu (rtd , 0 ), 0x3 , 0x3 , 2 , 16 );
416
+ ret = snd_soc_dai_set_tdm_slot (snd_soc_rtd_to_cpu (rtd , 0 ), 0x3 , 0x3 , 2 , bits );
282
417
if (ret ) {
283
418
dev_err (rtd -> dev , "Error setting I2S config: %d\n" , ret );
284
419
return ret ;
@@ -345,12 +480,9 @@ static struct snd_soc_dai_link byt_wm5102_dais[] = {
345
480
/* back ends */
346
481
{
347
482
/*
348
- * This must be named SSP2-Codec even though this machine driver
349
- * always uses SSP0. Most machine drivers support both and dynamically
350
- * update the dailink to point to SSP0 or SSP2, while keeping the name
351
- * as "SSP2-Codec". The SOF tplg files hardcode the "SSP2-Codec" even
352
- * in the byt-foo-ssp0.tplg versions because the other machine-drivers
353
- * use "SSP2-Codec" even when SSP0 is used.
483
+ * This dailink is updated dynamically to point to SSP0 or SSP2.
484
+ * Yet its name is always kept as "SSP2-Codec" because the SOF
485
+ * tplg files hardcode "SSP2-Codec" even in byt-foo-ssp0.tplg.
354
486
*/
355
487
.name = "SSP2-Codec" ,
356
488
.id = 0 ,
@@ -384,17 +516,23 @@ static struct snd_soc_card byt_wm5102_card = {
384
516
.fully_routed = true,
385
517
};
386
518
519
+ static char byt_wm5102_components [64 ]; /* = "cfg-spk:* cfg-int-mic:* cfg-hs-mic:* ..." */
520
+
387
521
static int snd_byt_wm5102_mc_probe (struct platform_device * pdev )
388
522
{
523
+ static const char * const out_map_name [] = { "spk" , "hpout2" };
524
+ static const char * const intmic_map_name [] = { "in3l" , "in1l" };
525
+ static const char * const hsmic_map_name [] = { "in1l" , "in2l" };
389
526
char codec_name [SND_ACPI_I2C_ID_LEN ];
390
527
struct device * dev = & pdev -> dev ;
391
528
struct byt_wm5102_private * priv ;
392
529
struct snd_soc_acpi_mach * mach ;
393
530
const char * platform_name ;
394
531
struct acpi_device * adev ;
395
532
struct device * codec_dev ;
533
+ int dai_index = 0 ;
396
534
bool sof_parent ;
397
- int ret ;
535
+ int i , ret ;
398
536
399
537
priv = devm_kzalloc (dev , sizeof (* priv ), GFP_KERNEL );
400
538
if (!priv )
@@ -441,13 +579,50 @@ static int snd_byt_wm5102_mc_probe(struct platform_device *pdev)
441
579
return dev_err_probe (dev , ret , "getting spkvdd-GPIO\n" );
442
580
}
443
581
582
+ if (soc_intel_is_cht ()) {
583
+ /*
584
+ * CHT always uses SSP2 and 19.2 MHz; and
585
+ * the one currently supported CHT design uses HPOUT2 as
586
+ * speaker output and has the intmic on IN1L + hsmic on IN2L.
587
+ */
588
+ quirk = BYT_WM5102_SSP2 | BYT_WM5102_MCLK_19_2MHZ |
589
+ BYT_WM5102_INTMIC_IN1L_HSMIC_IN2L |
590
+ BYT_WM5102_SPK_HPOUT2_MAP ;
591
+ }
592
+ if (quirk_override != -1 ) {
593
+ dev_info_once (dev , "Overriding quirk 0x%lx => 0x%x\n" ,
594
+ quirk , quirk_override );
595
+ quirk = quirk_override ;
596
+ }
597
+ log_quirks (dev );
598
+
599
+ snprintf (byt_wm5102_components , sizeof (byt_wm5102_components ),
600
+ "cfg-spk:%s cfg-intmic:%s cfg-hsmic:%s" ,
601
+ out_map_name [FIELD_GET (BYT_WM5102_OUT_MAP , quirk )],
602
+ intmic_map_name [FIELD_GET (BYT_WM5102_IN_MAP , quirk )],
603
+ hsmic_map_name [FIELD_GET (BYT_WM5102_IN_MAP , quirk )]);
604
+ byt_wm5102_card .components = byt_wm5102_components ;
605
+
606
+ /* find index of codec dai */
607
+ for (i = 0 ; i < ARRAY_SIZE (byt_wm5102_dais ); i ++ ) {
608
+ if (!strcmp (byt_wm5102_dais [i ].codecs -> name ,
609
+ "wm5102-codec" )) {
610
+ dai_index = i ;
611
+ break ;
612
+ }
613
+ }
614
+
444
615
/* override platform name, if required */
445
616
byt_wm5102_card .dev = dev ;
446
617
platform_name = mach -> mach_params .platform ;
447
618
ret = snd_soc_fixup_dai_links_platform_name (& byt_wm5102_card , platform_name );
448
619
if (ret )
449
620
goto out_put_gpio ;
450
621
622
+ /* override SSP port, if required */
623
+ if (quirk & BYT_WM5102_SSP2 )
624
+ byt_wm5102_dais [dai_index ].cpus -> dai_name = "ssp2-port" ;
625
+
451
626
/* set card and driver name and pm-ops */
452
627
sof_parent = snd_soc_acpi_sof_parent (dev );
453
628
if (sof_parent ) {
0 commit comments