Skip to content

Commit 60781d2

Browse files
committed
ASoC: Intel: bytcr_wm5102: add various quirks
Merge series from Hans de Goede <hdegoede@redhat.com>: Hi Mark, As requested here is a v2 of my series to add various quirks to the bytcr_wm5102 Intel board driver to make it more flexible. Changes in v2: - Dropped 2 already merged patches - Rebased on top of broonie/sound/for-6.7 Regards, Hans Hans de Goede (4): ASoC: Intel: bytcr_wm5102: Add BYT_WM5102_SSP2 quirk ASoC: Intel: bytcr_wm5102: Add BYT_WM5102_MCLK_19_2MHZ quirk ASoC: Intel: bytcr_wm5102: Add BYT_WM5102_OUT_MAP quirk ASoC: Intel: bytcr_wm5102: Add BYT_WM5102_IN_MAP quirk sound/soc/intel/boards/bytcr_wm5102.c | 229 +++++++++++++++++++++++--- 1 file changed, 202 insertions(+), 27 deletions(-) -- 2.41.0
2 parents 246f388 + 8619fd0 commit 60781d2

File tree

1 file changed

+202
-27
lines changed

1 file changed

+202
-27
lines changed

sound/soc/intel/boards/bytcr_wm5102.c

Lines changed: 202 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@
1010
*/
1111

1212
#include <linux/acpi.h>
13+
#include <linux/bitfield.h>
1314
#include <linux/clk.h>
1415
#include <linux/device.h>
1516
#include <linux/init.h>
1617
#include <linux/module.h>
1718
#include <linux/moduleparam.h>
19+
#include <linux/platform_data/x86/soc.h>
1820
#include <linux/platform_device.h>
1921
#include <linux/slab.h>
2022
#include <linux/spi/spi.h>
@@ -26,17 +28,74 @@
2628
#include "../../codecs/wm5102.h"
2729
#include "../atom/sst-atom-controls.h"
2830

29-
#define MCLK_FREQ 25000000
30-
3131
#define WM5102_MAX_SYSCLK_4K 49152000 /* max sysclk for 4K family */
3232
#define WM5102_MAX_SYSCLK_11025 45158400 /* max sysclk for 11.025K family */
3333

3434
struct byt_wm5102_private {
3535
struct snd_soc_jack jack;
3636
struct clk *mclk;
3737
struct gpio_desc *spkvdd_en_gpio;
38+
int mclk_freq;
3839
};
3940

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+
4099
static int byt_wm5102_spkvdd_power_event(struct snd_soc_dapm_widget *w,
41100
struct snd_kcontrol *kcontrol, int event)
42101
{
@@ -52,6 +111,7 @@ static int byt_wm5102_spkvdd_power_event(struct snd_soc_dapm_widget *w,
52111
static int byt_wm5102_prepare_and_enable_pll1(struct snd_soc_dai *codec_dai, int rate)
53112
{
54113
struct snd_soc_component *codec_component = codec_dai->component;
114+
struct byt_wm5102_private *priv = snd_soc_card_get_drvdata(codec_component->card);
55115
int sr_mult = ((rate % 4000) == 0) ?
56116
(WM5102_MAX_SYSCLK_4K / rate) :
57117
(WM5102_MAX_SYSCLK_11025 / rate);
@@ -63,7 +123,7 @@ static int byt_wm5102_prepare_and_enable_pll1(struct snd_soc_dai *codec_dai, int
63123

64124
/* Configure the FLL1 PLL before selecting it */
65125
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);
67127
if (ret) {
68128
dev_err(codec_component->dev, "Error setting PLL: %d\n", ret);
69129
return ret;
@@ -145,35 +205,58 @@ static const struct snd_soc_dapm_route byt_wm5102_audio_map[] = {
145205
{"Headset Mic", NULL, "Platform Clock"},
146206
{"Internal Mic", NULL, "Platform Clock"},
147207
{"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"},
154208
{"Speaker", NULL, "Speaker VDD"},
155209

156210
{"Headphone", NULL, "HPOUT1L"},
157211
{"Headphone", NULL, "HPOUT1R"},
158212

159-
{"Internal Mic", NULL, "MICBIAS3"},
160-
{"IN3L", NULL, "Internal Mic"},
161-
162213
/*
163214
* The Headset Mix uses MICBIAS1 or 2 depending on if a CTIA/OMTP Headset
164215
* is connected, as the MICBIAS is applied after the CTIA/OMTP cross-switch.
165216
*/
166217
{"Headset Mic", NULL, "MICBIAS1"},
167218
{"Headset Mic", NULL, "MICBIAS2"},
168-
{"IN1L", NULL, "Headset Mic"},
219+
{"Internal Mic", NULL, "MICBIAS3"},
220+
};
169221

222+
static const struct snd_soc_dapm_route bytcr_wm5102_ssp0_map[] = {
170223
{"AIF1 Playback", NULL, "ssp0 Tx"},
171224
{"ssp0 Tx", NULL, "modem_out"},
172-
173225
{"modem_in", NULL, "ssp0 Rx"},
174226
{"ssp0 Rx", NULL, "AIF1 Capture"},
175227
};
176228

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+
177260
static const struct snd_kcontrol_new byt_wm5102_controls[] = {
178261
SOC_DAPM_PIN_SWITCH("Headphone"),
179262
SOC_DAPM_PIN_SWITCH("Headset Mic"),
@@ -202,7 +285,8 @@ static int byt_wm5102_init(struct snd_soc_pcm_runtime *runtime)
202285
struct snd_soc_card *card = runtime->card;
203286
struct byt_wm5102_private *priv = snd_soc_card_get_drvdata(card);
204287
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;
206290

207291
card->dapm.idle_bias_off = true;
208292

@@ -213,6 +297,50 @@ static int byt_wm5102_init(struct snd_soc_pcm_runtime *runtime)
213297
return ret;
214298
}
215299

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+
216344
/*
217345
* The firmware might enable the clock at boot (this information
218346
* 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)
225353
if (!ret)
226354
clk_disable_unprepare(priv->mclk);
227355

228-
ret = clk_set_rate(priv->mclk, MCLK_FREQ);
356+
ret = clk_set_rate(priv->mclk, priv->mclk_freq);
229357
if (ret) {
230358
dev_err(card->dev, "Error setting MCLK rate: %d\n", ret);
231359
return ret;
@@ -253,16 +381,23 @@ static int byt_wm5102_codec_fixup(struct snd_soc_pcm_runtime *rtd,
253381
SNDRV_PCM_HW_PARAM_RATE);
254382
struct snd_interval *channels = hw_param_interval(params,
255383
SNDRV_PCM_HW_PARAM_CHANNELS);
256-
int ret;
384+
int ret, bits;
257385

258386
/* The DSP will convert the FE rate to 48k, stereo */
259387
rate->min = 48000;
260388
rate->max = 48000;
261389
channels->min = 2;
262390
channels->max = 2;
263391

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+
}
266401

267402
/*
268403
* 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,
278413
return ret;
279414
}
280415

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);
282417
if (ret) {
283418
dev_err(rtd->dev, "Error setting I2S config: %d\n", ret);
284419
return ret;
@@ -345,12 +480,9 @@ static struct snd_soc_dai_link byt_wm5102_dais[] = {
345480
/* back ends */
346481
{
347482
/*
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.
354486
*/
355487
.name = "SSP2-Codec",
356488
.id = 0,
@@ -384,17 +516,23 @@ static struct snd_soc_card byt_wm5102_card = {
384516
.fully_routed = true,
385517
};
386518

519+
static char byt_wm5102_components[64]; /* = "cfg-spk:* cfg-int-mic:* cfg-hs-mic:* ..." */
520+
387521
static int snd_byt_wm5102_mc_probe(struct platform_device *pdev)
388522
{
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" };
389526
char codec_name[SND_ACPI_I2C_ID_LEN];
390527
struct device *dev = &pdev->dev;
391528
struct byt_wm5102_private *priv;
392529
struct snd_soc_acpi_mach *mach;
393530
const char *platform_name;
394531
struct acpi_device *adev;
395532
struct device *codec_dev;
533+
int dai_index = 0;
396534
bool sof_parent;
397-
int ret;
535+
int i, ret;
398536

399537
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
400538
if (!priv)
@@ -441,13 +579,50 @@ static int snd_byt_wm5102_mc_probe(struct platform_device *pdev)
441579
return dev_err_probe(dev, ret, "getting spkvdd-GPIO\n");
442580
}
443581

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+
444615
/* override platform name, if required */
445616
byt_wm5102_card.dev = dev;
446617
platform_name = mach->mach_params.platform;
447618
ret = snd_soc_fixup_dai_links_platform_name(&byt_wm5102_card, platform_name);
448619
if (ret)
449620
goto out_put_gpio;
450621

622+
/* override SSP port, if required */
623+
if (quirk & BYT_WM5102_SSP2)
624+
byt_wm5102_dais[dai_index].cpus->dai_name = "ssp2-port";
625+
451626
/* set card and driver name and pm-ops */
452627
sof_parent = snd_soc_acpi_sof_parent(dev);
453628
if (sof_parent) {

0 commit comments

Comments
 (0)