1 // SPDX-License-Identifier: GPL-2.0-only
3 * cht_bsw_rt5672.c - ASoc Machine driver for Intel Cherryview-based platforms
4 * Cherrytrail and Braswell, with RT5672 codec.
6 * Copyright (C) 2014 Intel Corp
7 * Author: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
8 * Mengdong Lin <mengdong.lin@intel.com>
11 #include <linux/gpio/consumer.h>
12 #include <linux/input.h>
13 #include <linux/module.h>
14 #include <linux/platform_device.h>
15 #include <linux/slab.h>
16 #include <linux/clk.h>
17 #include <sound/pcm.h>
18 #include <sound/pcm_params.h>
19 #include <sound/soc.h>
20 #include <sound/jack.h>
21 #include <sound/soc-acpi.h>
22 #include "../../codecs/rt5670.h"
23 #include "../atom/sst-atom-controls.h"
26 /* The platform clock #3 outputs 19.2Mhz clock to codec as I2S MCLK */
27 #define CHT_PLAT_CLK_3_HZ 19200000
28 #define CHT_CODEC_DAI "rt5670-aif1"
30 struct cht_mc_private
{
31 struct snd_soc_jack headset
;
32 char codec_name
[SND_ACPI_I2C_ID_LEN
];
36 /* Headset jack detection DAPM pins */
37 static struct snd_soc_jack_pin cht_bsw_headset_pins
[] = {
40 .mask
= SND_JACK_MICROPHONE
,
44 .mask
= SND_JACK_HEADPHONE
,
48 static int platform_clock_control(struct snd_soc_dapm_widget
*w
,
49 struct snd_kcontrol
*k
, int event
)
51 struct snd_soc_dapm_context
*dapm
= w
->dapm
;
52 struct snd_soc_card
*card
= dapm
->card
;
53 struct snd_soc_dai
*codec_dai
;
54 struct cht_mc_private
*ctx
= snd_soc_card_get_drvdata(card
);
57 codec_dai
= snd_soc_card_get_codec_dai(card
, CHT_CODEC_DAI
);
59 dev_err(card
->dev
, "Codec dai not found; Unable to set platform clock\n");
63 if (SND_SOC_DAPM_EVENT_ON(event
)) {
65 ret
= clk_prepare_enable(ctx
->mclk
);
68 "could not configure MCLK state");
73 /* set codec PLL source to the 19.2MHz platform clock (MCLK) */
74 ret
= snd_soc_dai_set_pll(codec_dai
, 0, RT5670_PLL1_S_MCLK
,
75 CHT_PLAT_CLK_3_HZ
, 48000 * 512);
77 dev_err(card
->dev
, "can't set codec pll: %d\n", ret
);
81 /* set codec sysclk source to PLL */
82 ret
= snd_soc_dai_set_sysclk(codec_dai
, RT5670_SCLK_S_PLL1
,
83 48000 * 512, SND_SOC_CLOCK_IN
);
85 dev_err(card
->dev
, "can't set codec sysclk: %d\n", ret
);
89 /* Set codec sysclk source to its internal clock because codec
90 * PLL will be off when idle and MCLK will also be off by ACPI
91 * when codec is runtime suspended. Codec needs clock for jack
92 * detection and button press.
94 snd_soc_dai_set_sysclk(codec_dai
, RT5670_SCLK_S_RCCLK
,
95 48000 * 512, SND_SOC_CLOCK_IN
);
98 clk_disable_unprepare(ctx
->mclk
);
103 static const struct snd_soc_dapm_widget cht_dapm_widgets
[] = {
104 SND_SOC_DAPM_HP("Headphone", NULL
),
105 SND_SOC_DAPM_MIC("Headset Mic", NULL
),
106 SND_SOC_DAPM_MIC("Int Mic", NULL
),
107 SND_SOC_DAPM_SPK("Ext Spk", NULL
),
108 SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM
, 0, 0,
109 platform_clock_control
, SND_SOC_DAPM_PRE_PMU
|
110 SND_SOC_DAPM_POST_PMD
),
113 static const struct snd_soc_dapm_route cht_audio_map
[] = {
114 {"IN1P", NULL
, "Headset Mic"},
115 {"IN1N", NULL
, "Headset Mic"},
116 {"DMIC L1", NULL
, "Int Mic"},
117 {"DMIC R1", NULL
, "Int Mic"},
118 {"Headphone", NULL
, "HPOL"},
119 {"Headphone", NULL
, "HPOR"},
120 {"Ext Spk", NULL
, "SPOLP"},
121 {"Ext Spk", NULL
, "SPOLN"},
122 {"Ext Spk", NULL
, "SPORP"},
123 {"Ext Spk", NULL
, "SPORN"},
124 {"AIF1 Playback", NULL
, "ssp2 Tx"},
125 {"ssp2 Tx", NULL
, "codec_out0"},
126 {"ssp2 Tx", NULL
, "codec_out1"},
127 {"codec_in0", NULL
, "ssp2 Rx"},
128 {"codec_in1", NULL
, "ssp2 Rx"},
129 {"ssp2 Rx", NULL
, "AIF1 Capture"},
130 {"Headphone", NULL
, "Platform Clock"},
131 {"Headset Mic", NULL
, "Platform Clock"},
132 {"Int Mic", NULL
, "Platform Clock"},
133 {"Ext Spk", NULL
, "Platform Clock"},
136 static const struct snd_kcontrol_new cht_mc_controls
[] = {
137 SOC_DAPM_PIN_SWITCH("Headphone"),
138 SOC_DAPM_PIN_SWITCH("Headset Mic"),
139 SOC_DAPM_PIN_SWITCH("Int Mic"),
140 SOC_DAPM_PIN_SWITCH("Ext Spk"),
143 static int cht_aif1_hw_params(struct snd_pcm_substream
*substream
,
144 struct snd_pcm_hw_params
*params
)
146 struct snd_soc_pcm_runtime
*rtd
= asoc_substream_to_rtd(substream
);
147 struct snd_soc_dai
*codec_dai
= asoc_rtd_to_codec(rtd
, 0);
150 /* set codec PLL source to the 19.2MHz platform clock (MCLK) */
151 ret
= snd_soc_dai_set_pll(codec_dai
, 0, RT5670_PLL1_S_MCLK
,
152 CHT_PLAT_CLK_3_HZ
, params_rate(params
) * 512);
154 dev_err(rtd
->dev
, "can't set codec pll: %d\n", ret
);
158 /* set codec sysclk source to PLL */
159 ret
= snd_soc_dai_set_sysclk(codec_dai
, RT5670_SCLK_S_PLL1
,
160 params_rate(params
) * 512,
163 dev_err(rtd
->dev
, "can't set codec sysclk: %d\n", ret
);
169 static const struct acpi_gpio_params headset_gpios
= { 0, 0, false };
171 static const struct acpi_gpio_mapping cht_rt5672_gpios
[] = {
172 { "headset-gpios", &headset_gpios
, 1 },
176 static int cht_codec_init(struct snd_soc_pcm_runtime
*runtime
)
179 struct snd_soc_dai
*codec_dai
= asoc_rtd_to_codec(runtime
, 0);
180 struct snd_soc_component
*component
= codec_dai
->component
;
181 struct cht_mc_private
*ctx
= snd_soc_card_get_drvdata(runtime
->card
);
183 if (devm_acpi_dev_add_driver_gpios(component
->dev
, cht_rt5672_gpios
))
184 dev_warn(runtime
->dev
, "Unable to add GPIO mapping table\n");
186 /* Select codec ASRC clock source to track I2S1 clock, because codec
187 * is in slave mode and 100fs I2S format (BCLK = 100 * LRCLK) cannot
188 * be supported by RT5672. Otherwise, ASRC will be disabled and cause
191 rt5670_sel_asrc_clk_src(component
,
192 RT5670_DA_STEREO_FILTER
193 | RT5670_DA_MONO_L_FILTER
194 | RT5670_DA_MONO_R_FILTER
195 | RT5670_AD_STEREO_FILTER
196 | RT5670_AD_MONO_L_FILTER
197 | RT5670_AD_MONO_R_FILTER
,
198 RT5670_CLK_SEL_I2S1_ASRC
);
200 ret
= snd_soc_card_jack_new(runtime
->card
, "Headset",
201 SND_JACK_HEADSET
| SND_JACK_BTN_0
|
202 SND_JACK_BTN_1
| SND_JACK_BTN_2
,
204 cht_bsw_headset_pins
,
205 ARRAY_SIZE(cht_bsw_headset_pins
));
209 snd_jack_set_key(ctx
->headset
.jack
, SND_JACK_BTN_0
, KEY_PLAYPAUSE
);
210 snd_jack_set_key(ctx
->headset
.jack
, SND_JACK_BTN_1
, KEY_VOLUMEUP
);
211 snd_jack_set_key(ctx
->headset
.jack
, SND_JACK_BTN_2
, KEY_VOLUMEDOWN
);
213 rt5670_set_jack_detect(component
, &ctx
->headset
);
216 * The firmware might enable the clock at
217 * boot (this information may or may not
218 * be reflected in the enable clock register).
219 * To change the rate we must disable the clock
220 * first to cover these cases. Due to common
221 * clock framework restrictions that do not allow
222 * to disable a clock that has not been enabled,
223 * we need to enable the clock first.
225 ret
= clk_prepare_enable(ctx
->mclk
);
227 clk_disable_unprepare(ctx
->mclk
);
229 ret
= clk_set_rate(ctx
->mclk
, CHT_PLAT_CLK_3_HZ
);
232 dev_err(runtime
->dev
, "unable to set MCLK rate\n");
239 static int cht_codec_fixup(struct snd_soc_pcm_runtime
*rtd
,
240 struct snd_pcm_hw_params
*params
)
242 struct snd_interval
*rate
= hw_param_interval(params
,
243 SNDRV_PCM_HW_PARAM_RATE
);
244 struct snd_interval
*channels
= hw_param_interval(params
,
245 SNDRV_PCM_HW_PARAM_CHANNELS
);
248 /* The DSP will covert the FE rate to 48k, stereo, 24bits */
249 rate
->min
= rate
->max
= 48000;
250 channels
->min
= channels
->max
= 2;
252 /* set SSP2 to 24-bit */
253 params_set_format(params
, SNDRV_PCM_FORMAT_S24_LE
);
256 * The default mode for the cpu-dai is TDM 4 slot. The default mode
257 * for the codec-dai is I2S. So we need to either set the cpu-dai to
258 * I2S mode to match the codec-dai, or set the codec-dai to TDM 4 slot
259 * (or program both to yet another mode).
260 * One board, the Lenovo Miix 2 10, uses not 1 but 2 codecs connected
261 * to SSP2. The second piggy-backed, output-only codec is inside the
262 * keyboard-dock (which has extra speakers). Unlike the main rt5672
263 * codec, we cannot configure this codec, it is hard coded to use
264 * 2 channel 24 bit I2S. For this to work we must use I2S mode on this
265 * board. Since we only support 2 channels anyways, there is no need
266 * for TDM on any cht-bsw-rt5672 designs. So we use I2S 2ch everywhere.
268 ret
= snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd
, 0),
270 SND_SOC_DAIFMT_NB_NF
|
271 SND_SOC_DAIFMT_CBS_CFS
);
273 dev_err(rtd
->dev
, "can't set format to I2S, err %d\n", ret
);
280 static int cht_aif1_startup(struct snd_pcm_substream
*substream
)
282 return snd_pcm_hw_constraint_single(substream
->runtime
,
283 SNDRV_PCM_HW_PARAM_RATE
, 48000);
286 static const struct snd_soc_ops cht_aif1_ops
= {
287 .startup
= cht_aif1_startup
,
290 static const struct snd_soc_ops cht_be_ssp2_ops
= {
291 .hw_params
= cht_aif1_hw_params
,
294 SND_SOC_DAILINK_DEF(dummy
,
295 DAILINK_COMP_ARRAY(COMP_DUMMY()));
297 SND_SOC_DAILINK_DEF(media
,
298 DAILINK_COMP_ARRAY(COMP_CPU("media-cpu-dai")));
300 SND_SOC_DAILINK_DEF(deepbuffer
,
301 DAILINK_COMP_ARRAY(COMP_CPU("deepbuffer-cpu-dai")));
303 SND_SOC_DAILINK_DEF(ssp2_port
,
304 DAILINK_COMP_ARRAY(COMP_CPU("ssp2-port")));
305 SND_SOC_DAILINK_DEF(ssp2_codec
,
306 DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC5670:00",
309 SND_SOC_DAILINK_DEF(platform
,
310 DAILINK_COMP_ARRAY(COMP_PLATFORM("sst-mfld-platform")));
312 static struct snd_soc_dai_link cht_dailink
[] = {
313 /* Front End DAI links */
314 [MERR_DPCM_AUDIO
] = {
315 .name
= "Audio Port",
316 .stream_name
= "Audio",
321 .ops
= &cht_aif1_ops
,
322 SND_SOC_DAILINK_REG(media
, dummy
, platform
),
324 [MERR_DPCM_DEEP_BUFFER
] = {
325 .name
= "Deep-Buffer Audio Port",
326 .stream_name
= "Deep-Buffer Audio",
330 .ops
= &cht_aif1_ops
,
331 SND_SOC_DAILINK_REG(deepbuffer
, dummy
, platform
),
334 /* Back End DAI links */
337 .name
= "SSP2-Codec",
341 .init
= cht_codec_init
,
342 .be_hw_params_fixup
= cht_codec_fixup
,
345 .ops
= &cht_be_ssp2_ops
,
346 SND_SOC_DAILINK_REG(ssp2_port
, ssp2_codec
, platform
),
350 static int cht_suspend_pre(struct snd_soc_card
*card
)
352 struct snd_soc_component
*component
;
353 struct cht_mc_private
*ctx
= snd_soc_card_get_drvdata(card
);
355 for_each_card_components(card
, component
) {
356 if (!strncmp(component
->name
,
357 ctx
->codec_name
, sizeof(ctx
->codec_name
))) {
359 dev_dbg(component
->dev
, "disabling jack detect before going to suspend.\n");
360 rt5670_jack_suspend(component
);
367 static int cht_resume_post(struct snd_soc_card
*card
)
369 struct snd_soc_component
*component
;
370 struct cht_mc_private
*ctx
= snd_soc_card_get_drvdata(card
);
372 for_each_card_components(card
, component
) {
373 if (!strncmp(component
->name
,
374 ctx
->codec_name
, sizeof(ctx
->codec_name
))) {
376 dev_dbg(component
->dev
, "enabling jack detect for resume.\n");
377 rt5670_jack_resume(component
);
385 /* use space before codec name to simplify card ID, and simplify driver name */
386 #define SOF_CARD_NAME "bytcht rt5672" /* card name will be 'sof-bytcht rt5672' */
387 #define SOF_DRIVER_NAME "SOF"
389 #define CARD_NAME "cht-bsw-rt5672"
390 #define DRIVER_NAME NULL /* card name will be used for driver name */
393 static struct snd_soc_card snd_soc_card_cht
= {
394 .owner
= THIS_MODULE
,
395 .dai_link
= cht_dailink
,
396 .num_links
= ARRAY_SIZE(cht_dailink
),
397 .dapm_widgets
= cht_dapm_widgets
,
398 .num_dapm_widgets
= ARRAY_SIZE(cht_dapm_widgets
),
399 .dapm_routes
= cht_audio_map
,
400 .num_dapm_routes
= ARRAY_SIZE(cht_audio_map
),
401 .controls
= cht_mc_controls
,
402 .num_controls
= ARRAY_SIZE(cht_mc_controls
),
403 .suspend_pre
= cht_suspend_pre
,
404 .resume_post
= cht_resume_post
,
407 #define RT5672_I2C_DEFAULT "i2c-10EC5670:00"
409 static int snd_cht_mc_probe(struct platform_device
*pdev
)
412 struct cht_mc_private
*drv
;
413 struct snd_soc_acpi_mach
*mach
= pdev
->dev
.platform_data
;
414 const char *platform_name
;
415 struct acpi_device
*adev
;
419 drv
= devm_kzalloc(&pdev
->dev
, sizeof(*drv
), GFP_KERNEL
);
423 strcpy(drv
->codec_name
, RT5672_I2C_DEFAULT
);
425 /* fixup codec name based on HID */
426 adev
= acpi_dev_get_first_match_dev(mach
->id
, NULL
, -1);
428 snprintf(drv
->codec_name
, sizeof(drv
->codec_name
),
429 "i2c-%s", acpi_dev_name(adev
));
430 put_device(&adev
->dev
);
431 for (i
= 0; i
< ARRAY_SIZE(cht_dailink
); i
++) {
432 if (!strcmp(cht_dailink
[i
].codecs
->name
,
433 RT5672_I2C_DEFAULT
)) {
434 cht_dailink
[i
].codecs
->name
= drv
->codec_name
;
440 /* override plaform name, if required */
441 snd_soc_card_cht
.dev
= &pdev
->dev
;
442 platform_name
= mach
->mach_params
.platform
;
444 ret_val
= snd_soc_fixup_dai_links_platform_name(&snd_soc_card_cht
,
449 drv
->mclk
= devm_clk_get(&pdev
->dev
, "pmc_plt_clk_3");
450 if (IS_ERR(drv
->mclk
)) {
452 "Failed to get MCLK from pmc_plt_clk_3: %ld\n",
454 return PTR_ERR(drv
->mclk
);
456 snd_soc_card_set_drvdata(&snd_soc_card_cht
, drv
);
458 sof_parent
= snd_soc_acpi_sof_parent(&pdev
->dev
);
460 /* set card and driver name */
462 snd_soc_card_cht
.name
= SOF_CARD_NAME
;
463 snd_soc_card_cht
.driver_name
= SOF_DRIVER_NAME
;
465 snd_soc_card_cht
.name
= CARD_NAME
;
466 snd_soc_card_cht
.driver_name
= DRIVER_NAME
;
471 pdev
->dev
.driver
->pm
= &snd_soc_pm_ops
;
473 /* register the soc card */
474 ret_val
= devm_snd_soc_register_card(&pdev
->dev
, &snd_soc_card_cht
);
477 "snd_soc_register_card failed %d\n", ret_val
);
480 platform_set_drvdata(pdev
, &snd_soc_card_cht
);
484 static struct platform_driver snd_cht_mc_driver
= {
486 .name
= "cht-bsw-rt5672",
488 .probe
= snd_cht_mc_probe
,
491 module_platform_driver(snd_cht_mc_driver
);
493 MODULE_DESCRIPTION("ASoC Intel(R) Baytrail CR Machine driver");
494 MODULE_AUTHOR("Subhransu S. Prusty, Mengdong Lin");
495 MODULE_LICENSE("GPL v2");
496 MODULE_ALIAS("platform:cht-bsw-rt5672");