diff options
Diffstat (limited to 'sound/soc/intel/boards/cht_bsw_rt5672.c')
-rw-r--r-- | sound/soc/intel/boards/cht_bsw_rt5672.c | 89 |
1 files changed, 80 insertions, 9 deletions
diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index e4d46d4360d7..bc2a52de06a3 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c | |||
@@ -19,6 +19,8 @@ | |||
19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
20 | #include <linux/platform_device.h> | 20 | #include <linux/platform_device.h> |
21 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
22 | #include <linux/clk.h> | ||
23 | #include <asm/cpu_device_id.h> | ||
22 | #include <sound/pcm.h> | 24 | #include <sound/pcm.h> |
23 | #include <sound/pcm_params.h> | 25 | #include <sound/pcm_params.h> |
24 | #include <sound/soc.h> | 26 | #include <sound/soc.h> |
@@ -31,8 +33,11 @@ | |||
31 | #define CHT_PLAT_CLK_3_HZ 19200000 | 33 | #define CHT_PLAT_CLK_3_HZ 19200000 |
32 | #define CHT_CODEC_DAI "rt5670-aif1" | 34 | #define CHT_CODEC_DAI "rt5670-aif1" |
33 | 35 | ||
34 | static struct snd_soc_jack cht_bsw_headset; | 36 | struct cht_mc_private { |
35 | static char cht_bsw_codec_name[16]; | 37 | struct snd_soc_jack headset; |
38 | char codec_name[16]; | ||
39 | struct clk *mclk; | ||
40 | }; | ||
36 | 41 | ||
37 | /* Headset jack detection DAPM pins */ | 42 | /* Headset jack detection DAPM pins */ |
38 | static struct snd_soc_jack_pin cht_bsw_headset_pins[] = { | 43 | static struct snd_soc_jack_pin cht_bsw_headset_pins[] = { |
@@ -64,6 +69,7 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, | |||
64 | struct snd_soc_dapm_context *dapm = w->dapm; | 69 | struct snd_soc_dapm_context *dapm = w->dapm; |
65 | struct snd_soc_card *card = dapm->card; | 70 | struct snd_soc_card *card = dapm->card; |
66 | struct snd_soc_dai *codec_dai; | 71 | struct snd_soc_dai *codec_dai; |
72 | struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card); | ||
67 | int ret; | 73 | int ret; |
68 | 74 | ||
69 | codec_dai = cht_get_codec_dai(card); | 75 | codec_dai = cht_get_codec_dai(card); |
@@ -73,6 +79,15 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, | |||
73 | } | 79 | } |
74 | 80 | ||
75 | if (SND_SOC_DAPM_EVENT_ON(event)) { | 81 | if (SND_SOC_DAPM_EVENT_ON(event)) { |
82 | if (ctx->mclk) { | ||
83 | ret = clk_prepare_enable(ctx->mclk); | ||
84 | if (ret < 0) { | ||
85 | dev_err(card->dev, | ||
86 | "could not configure MCLK state"); | ||
87 | return ret; | ||
88 | } | ||
89 | } | ||
90 | |||
76 | /* set codec PLL source to the 19.2MHz platform clock (MCLK) */ | 91 | /* set codec PLL source to the 19.2MHz platform clock (MCLK) */ |
77 | ret = snd_soc_dai_set_pll(codec_dai, 0, RT5670_PLL1_S_MCLK, | 92 | ret = snd_soc_dai_set_pll(codec_dai, 0, RT5670_PLL1_S_MCLK, |
78 | CHT_PLAT_CLK_3_HZ, 48000 * 512); | 93 | CHT_PLAT_CLK_3_HZ, 48000 * 512); |
@@ -96,6 +111,9 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, | |||
96 | */ | 111 | */ |
97 | snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_RCCLK, | 112 | snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_RCCLK, |
98 | 48000 * 512, SND_SOC_CLOCK_IN); | 113 | 48000 * 512, SND_SOC_CLOCK_IN); |
114 | |||
115 | if (ctx->mclk) | ||
116 | clk_disable_unprepare(ctx->mclk); | ||
99 | } | 117 | } |
100 | return 0; | 118 | return 0; |
101 | } | 119 | } |
@@ -171,6 +189,7 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) | |||
171 | int ret; | 189 | int ret; |
172 | struct snd_soc_dai *codec_dai = runtime->codec_dai; | 190 | struct snd_soc_dai *codec_dai = runtime->codec_dai; |
173 | struct snd_soc_codec *codec = codec_dai->codec; | 191 | struct snd_soc_codec *codec = codec_dai->codec; |
192 | struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card); | ||
174 | 193 | ||
175 | /* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */ | 194 | /* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */ |
176 | ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24); | 195 | ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24); |
@@ -194,13 +213,37 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) | |||
194 | RT5670_CLK_SEL_I2S1_ASRC); | 213 | RT5670_CLK_SEL_I2S1_ASRC); |
195 | 214 | ||
196 | ret = snd_soc_card_jack_new(runtime->card, "Headset", | 215 | ret = snd_soc_card_jack_new(runtime->card, "Headset", |
197 | SND_JACK_HEADSET | SND_JACK_BTN_0 | | 216 | SND_JACK_HEADSET | SND_JACK_BTN_0 | |
198 | SND_JACK_BTN_1 | SND_JACK_BTN_2, &cht_bsw_headset, | 217 | SND_JACK_BTN_1 | SND_JACK_BTN_2, |
199 | cht_bsw_headset_pins, ARRAY_SIZE(cht_bsw_headset_pins)); | 218 | &ctx->headset, |
219 | cht_bsw_headset_pins, | ||
220 | ARRAY_SIZE(cht_bsw_headset_pins)); | ||
200 | if (ret) | 221 | if (ret) |
201 | return ret; | 222 | return ret; |
202 | 223 | ||
203 | rt5670_set_jack_detect(codec, &cht_bsw_headset); | 224 | rt5670_set_jack_detect(codec, &ctx->headset); |
225 | if (ctx->mclk) { | ||
226 | /* | ||
227 | * The firmware might enable the clock at | ||
228 | * boot (this information may or may not | ||
229 | * be reflected in the enable clock register). | ||
230 | * To change the rate we must disable the clock | ||
231 | * first to cover these cases. Due to common | ||
232 | * clock framework restrictions that do not allow | ||
233 | * to disable a clock that has not been enabled, | ||
234 | * we need to enable the clock first. | ||
235 | */ | ||
236 | ret = clk_prepare_enable(ctx->mclk); | ||
237 | if (!ret) | ||
238 | clk_disable_unprepare(ctx->mclk); | ||
239 | |||
240 | ret = clk_set_rate(ctx->mclk, CHT_PLAT_CLK_3_HZ); | ||
241 | |||
242 | if (ret) { | ||
243 | dev_err(runtime->dev, "unable to set MCLK rate\n"); | ||
244 | return ret; | ||
245 | } | ||
246 | } | ||
204 | return 0; | 247 | return 0; |
205 | } | 248 | } |
206 | 249 | ||
@@ -341,34 +384,62 @@ static struct snd_soc_card snd_soc_card_cht = { | |||
341 | .resume_post = cht_resume_post, | 384 | .resume_post = cht_resume_post, |
342 | }; | 385 | }; |
343 | 386 | ||
387 | static bool is_valleyview(void) | ||
388 | { | ||
389 | static const struct x86_cpu_id cpu_ids[] = { | ||
390 | { X86_VENDOR_INTEL, 6, 55 }, /* Valleyview, Bay Trail */ | ||
391 | {} | ||
392 | }; | ||
393 | |||
394 | if (!x86_match_cpu(cpu_ids)) | ||
395 | return false; | ||
396 | return true; | ||
397 | } | ||
398 | |||
344 | #define RT5672_I2C_DEFAULT "i2c-10EC5670:00" | 399 | #define RT5672_I2C_DEFAULT "i2c-10EC5670:00" |
345 | 400 | ||
346 | static int snd_cht_mc_probe(struct platform_device *pdev) | 401 | static int snd_cht_mc_probe(struct platform_device *pdev) |
347 | { | 402 | { |
348 | int ret_val = 0; | 403 | int ret_val = 0; |
404 | struct cht_mc_private *drv; | ||
349 | struct sst_acpi_mach *mach = pdev->dev.platform_data; | 405 | struct sst_acpi_mach *mach = pdev->dev.platform_data; |
350 | const char *i2c_name; | 406 | const char *i2c_name; |
351 | int i; | 407 | int i; |
352 | 408 | ||
353 | strcpy(cht_bsw_codec_name, RT5672_I2C_DEFAULT); | 409 | drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC); |
410 | if (!drv) | ||
411 | return -ENOMEM; | ||
412 | |||
413 | strcpy(drv->codec_name, RT5672_I2C_DEFAULT); | ||
354 | 414 | ||
355 | /* fixup codec name based on HID */ | 415 | /* fixup codec name based on HID */ |
356 | if (mach) { | 416 | if (mach) { |
357 | i2c_name = sst_acpi_find_name_from_hid(mach->id); | 417 | i2c_name = sst_acpi_find_name_from_hid(mach->id); |
358 | if (i2c_name) { | 418 | if (i2c_name) { |
359 | snprintf(cht_bsw_codec_name, sizeof(cht_bsw_codec_name), | 419 | snprintf(drv->codec_name, sizeof(drv->codec_name), |
360 | "i2c-%s", i2c_name); | 420 | "i2c-%s", i2c_name); |
361 | for (i = 0; i < ARRAY_SIZE(cht_dailink); i++) { | 421 | for (i = 0; i < ARRAY_SIZE(cht_dailink); i++) { |
362 | if (!strcmp(cht_dailink[i].codec_name, | 422 | if (!strcmp(cht_dailink[i].codec_name, |
363 | RT5672_I2C_DEFAULT)) { | 423 | RT5672_I2C_DEFAULT)) { |
364 | cht_dailink[i].codec_name = | 424 | cht_dailink[i].codec_name = |
365 | cht_bsw_codec_name; | 425 | drv->codec_name; |
366 | break; | 426 | break; |
367 | } | 427 | } |
368 | } | 428 | } |
369 | } | 429 | } |
370 | } | 430 | } |
371 | 431 | ||
432 | if (is_valleyview()) { | ||
433 | drv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); | ||
434 | if (IS_ERR(drv->mclk)) { | ||
435 | dev_err(&pdev->dev, | ||
436 | "Failed to get MCLK from pmc_plt_clk_3: %ld\n", | ||
437 | PTR_ERR(drv->mclk)); | ||
438 | return PTR_ERR(drv->mclk); | ||
439 | } | ||
440 | } | ||
441 | snd_soc_card_set_drvdata(&snd_soc_card_cht, drv); | ||
442 | |||
372 | /* register the soc card */ | 443 | /* register the soc card */ |
373 | snd_soc_card_cht.dev = &pdev->dev; | 444 | snd_soc_card_cht.dev = &pdev->dev; |
374 | ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht); | 445 | ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht); |