aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/intel/boards
diff options
context:
space:
mode:
authorIrina Tirdea <irina.tirdea@intel.com>2016-08-12 17:27:57 -0400
committerMark Brown <broonie@kernel.org>2016-08-15 10:14:57 -0400
commitdf1a2776a795848f4dbc7c0cb396158b43eb8aa3 (patch)
treeddcd5d5cf15b8702744bb61b2089776d80b2dbd1 /sound/soc/intel/boards
parent59e8b6520c6e2e867b35bc402d9a3f28aef3b2bc (diff)
ASoC: Intel: bytcr_rt5640: add MCLK support
Use platform clocks "pmc_plt_clk_3" when MCLK quirk is defined. By default always enable the 19.2 MHz PLL. Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> Signed-off-by: Irina Tirdea <irina.tirdea@intel.com> Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound/soc/intel/boards')
-rw-r--r--sound/soc/intel/boards/bytcr_rt5640.c187
1 files changed, 172 insertions, 15 deletions
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c
index 9b9d380d1cbb..11e11c6caa89 100644
--- a/sound/soc/intel/boards/bytcr_rt5640.c
+++ b/sound/soc/intel/boards/bytcr_rt5640.c
@@ -26,6 +26,7 @@
26#include <linux/slab.h> 26#include <linux/slab.h>
27#include <asm/cpu_device_id.h> 27#include <asm/cpu_device_id.h>
28#include <asm/platform_sst_audio.h> 28#include <asm/platform_sst_audio.h>
29#include <linux/clk.h>
29#include <sound/pcm.h> 30#include <sound/pcm.h>
30#include <sound/pcm_params.h> 31#include <sound/pcm_params.h>
31#include <sound/soc.h> 32#include <sound/soc.h>
@@ -49,18 +50,104 @@ enum {
49#define BYT_RT5640_SSP2_AIF2 BIT(19) /* default is using AIF1 */ 50#define BYT_RT5640_SSP2_AIF2 BIT(19) /* default is using AIF1 */
50#define BYT_RT5640_SSP0_AIF1 BIT(20) 51#define BYT_RT5640_SSP0_AIF1 BIT(20)
51#define BYT_RT5640_SSP0_AIF2 BIT(21) 52#define BYT_RT5640_SSP0_AIF2 BIT(21)
53#define BYT_RT5640_MCLK_EN BIT(22)
54#define BYT_RT5640_MCLK_25MHZ BIT(23)
55
56struct byt_rt5640_private {
57 struct clk *mclk;
58};
52 59
53static unsigned long byt_rt5640_quirk = BYT_RT5640_DMIC1_MAP | 60static unsigned long byt_rt5640_quirk = BYT_RT5640_DMIC1_MAP |
54 BYT_RT5640_DMIC_EN; 61 BYT_RT5640_DMIC_EN |
62 BYT_RT5640_MCLK_EN;
63
64#define BYT_CODEC_DAI1 "rt5640-aif1"
65#define BYT_CODEC_DAI2 "rt5640-aif2"
66
67static inline struct snd_soc_dai *byt_get_codec_dai(struct snd_soc_card *card)
68{
69 struct snd_soc_pcm_runtime *rtd;
70
71 list_for_each_entry(rtd, &card->rtd_list, list) {
72 if (!strncmp(rtd->codec_dai->name, BYT_CODEC_DAI1,
73 strlen(BYT_CODEC_DAI1)))
74 return rtd->codec_dai;
75 if (!strncmp(rtd->codec_dai->name, BYT_CODEC_DAI2,
76 strlen(BYT_CODEC_DAI2)))
77 return rtd->codec_dai;
78
79 }
80 return NULL;
81}
82
83static int platform_clock_control(struct snd_soc_dapm_widget *w,
84 struct snd_kcontrol *k, int event)
85{
86 struct snd_soc_dapm_context *dapm = w->dapm;
87 struct snd_soc_card *card = dapm->card;
88 struct snd_soc_dai *codec_dai;
89 struct byt_rt5640_private *priv = snd_soc_card_get_drvdata(card);
90 int ret;
91
92 codec_dai = byt_get_codec_dai(card);
93 if (!codec_dai) {
94 dev_err(card->dev,
95 "Codec dai not found; Unable to set platform clock\n");
96 return -EIO;
97 }
98
99 if (SND_SOC_DAPM_EVENT_ON(event)) {
100 if ((byt_rt5640_quirk & BYT_RT5640_MCLK_EN) && priv->mclk) {
101 ret = clk_prepare_enable(priv->mclk);
102 if (ret < 0) {
103 dev_err(card->dev,
104 "could not configure MCLK state");
105 return ret;
106 }
107 }
108 ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1,
109 48000 * 512,
110 SND_SOC_CLOCK_IN);
111 } else {
112 /*
113 * Set codec clock source to internal clock before
114 * turning off the platform clock. Codec needs clock
115 * for Jack detection and button press
116 */
117 ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_RCCLK,
118 0,
119 SND_SOC_CLOCK_IN);
120 if (!ret) {
121 if ((byt_rt5640_quirk & BYT_RT5640_MCLK_EN) && priv->mclk)
122 clk_disable_unprepare(priv->mclk);
123 }
124 }
125
126 if (ret < 0) {
127 dev_err(card->dev, "can't set codec sysclk: %d\n", ret);
128 return ret;
129 }
130
131 return 0;
132}
55 133
56static const struct snd_soc_dapm_widget byt_rt5640_widgets[] = { 134static const struct snd_soc_dapm_widget byt_rt5640_widgets[] = {
57 SND_SOC_DAPM_HP("Headphone", NULL), 135 SND_SOC_DAPM_HP("Headphone", NULL),
58 SND_SOC_DAPM_MIC("Headset Mic", NULL), 136 SND_SOC_DAPM_MIC("Headset Mic", NULL),
59 SND_SOC_DAPM_MIC("Internal Mic", NULL), 137 SND_SOC_DAPM_MIC("Internal Mic", NULL),
60 SND_SOC_DAPM_SPK("Speaker", NULL), 138 SND_SOC_DAPM_SPK("Speaker", NULL),
139 SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
140 platform_clock_control, SND_SOC_DAPM_PRE_PMU |
141 SND_SOC_DAPM_POST_PMD),
142
61}; 143};
62 144
63static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = { 145static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = {
146 {"Headphone", NULL, "Platform Clock"},
147 {"Headset Mic", NULL, "Platform Clock"},
148 {"Internal Mic", NULL, "Platform Clock"},
149 {"Speaker", NULL, "Platform Clock"},
150
64 {"Headset Mic", NULL, "MICBIAS1"}, 151 {"Headset Mic", NULL, "MICBIAS1"},
65 {"IN2P", NULL, "Headset Mic"}, 152 {"IN2P", NULL, "Headset Mic"},
66 {"Headphone", NULL, "HPOL"}, 153 {"Headphone", NULL, "HPOL"},
@@ -150,21 +237,41 @@ static int byt_rt5640_aif1_hw_params(struct snd_pcm_substream *substream,
150 ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1, 237 ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1,
151 params_rate(params) * 512, 238 params_rate(params) * 512,
152 SND_SOC_CLOCK_IN); 239 SND_SOC_CLOCK_IN);
240
153 if (ret < 0) { 241 if (ret < 0) {
154 dev_err(rtd->dev, "can't set codec clock %d\n", ret); 242 dev_err(rtd->dev, "can't set codec clock %d\n", ret);
155 return ret; 243 return ret;
156 } 244 }
157 245
158 if ((byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) || 246 if (!(byt_rt5640_quirk & BYT_RT5640_MCLK_EN)) {
159 (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2)) { 247 /* use bitclock as PLL input */
160 248 if ((byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) ||
161 ret = snd_soc_dai_set_pll(codec_dai, 0, RT5640_PLL1_S_BCLK1, 249 (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2)) {
162 params_rate(params) * 32, /* FIXME */ 250
163 params_rate(params) * 512); 251 /* 2x16 bit slots on SSP0 */
252 ret = snd_soc_dai_set_pll(codec_dai, 0,
253 RT5640_PLL1_S_BCLK1,
254 params_rate(params) * 32,
255 params_rate(params) * 512);
256 } else {
257 /* 2x15 bit slots on SSP2 */
258 ret = snd_soc_dai_set_pll(codec_dai, 0,
259 RT5640_PLL1_S_BCLK1,
260 params_rate(params) * 50,
261 params_rate(params) * 512);
262 }
164 } else { 263 } else {
165 ret = snd_soc_dai_set_pll(codec_dai, 0, RT5640_PLL1_S_BCLK1, 264 if (byt_rt5640_quirk & BYT_RT5640_MCLK_25MHZ) {
166 params_rate(params) * 50, 265 ret = snd_soc_dai_set_pll(codec_dai, 0,
167 params_rate(params) * 512); 266 RT5640_PLL1_S_MCLK,
267 25000000,
268 params_rate(params) * 512);
269 } else {
270 ret = snd_soc_dai_set_pll(codec_dai, 0,
271 RT5640_PLL1_S_MCLK,
272 19200000,
273 params_rate(params) * 512);
274 }
168 } 275 }
169 276
170 if (ret < 0) { 277 if (ret < 0) {
@@ -188,7 +295,8 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
188 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), 295 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
189 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TA"), 296 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TA"),
190 }, 297 },
191 .driver_data = (unsigned long *)BYT_RT5640_IN1_MAP, 298 .driver_data = (unsigned long *)(BYT_RT5640_IN1_MAP |
299 BYT_RT5640_MCLK_EN),
192 }, 300 },
193 { 301 {
194 .callback = byt_rt5640_quirk_cb, 302 .callback = byt_rt5640_quirk_cb,
@@ -199,7 +307,8 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
199 .driver_data = (unsigned long *)(BYT_RT5640_IN1_MAP | 307 .driver_data = (unsigned long *)(BYT_RT5640_IN1_MAP |
200 BYT_RT5640_MONO_SPEAKER | 308 BYT_RT5640_MONO_SPEAKER |
201 BYT_RT5640_DIFF_MIC | 309 BYT_RT5640_DIFF_MIC |
202 BYT_RT5640_SSP0_AIF2 310 BYT_RT5640_SSP0_AIF2 |
311 BYT_RT5640_MCLK_EN
203 ), 312 ),
204 }, 313 },
205 { 314 {
@@ -209,7 +318,8 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
209 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5830"), 318 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5830"),
210 }, 319 },
211 .driver_data = (unsigned long *)(BYT_RT5640_DMIC2_MAP | 320 .driver_data = (unsigned long *)(BYT_RT5640_DMIC2_MAP |
212 BYT_RT5640_DMIC_EN), 321 BYT_RT5640_DMIC_EN |
322 BYT_RT5640_MCLK_EN),
213 }, 323 },
214 { 324 {
215 .callback = byt_rt5640_quirk_cb, 325 .callback = byt_rt5640_quirk_cb,
@@ -217,7 +327,8 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
217 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), 327 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
218 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HP ElitePad 1000 G2"), 328 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HP ElitePad 1000 G2"),
219 }, 329 },
220 .driver_data = (unsigned long *)BYT_RT5640_IN1_MAP, 330 .driver_data = (unsigned long *)(BYT_RT5640_IN1_MAP |
331 BYT_RT5640_MCLK_EN),
221 }, 332 },
222 {} 333 {}
223}; 334};
@@ -228,13 +339,18 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
228 struct snd_soc_codec *codec = runtime->codec; 339 struct snd_soc_codec *codec = runtime->codec;
229 struct snd_soc_card *card = runtime->card; 340 struct snd_soc_card *card = runtime->card;
230 const struct snd_soc_dapm_route *custom_map; 341 const struct snd_soc_dapm_route *custom_map;
342 struct byt_rt5640_private *priv = snd_soc_card_get_drvdata(card);
231 int num_routes; 343 int num_routes;
232 344
233 card->dapm.idle_bias_off = true; 345 card->dapm.idle_bias_off = true;
234 346
235 rt5640_sel_asrc_clk_src(codec, 347 rt5640_sel_asrc_clk_src(codec,
236 RT5640_DA_STEREO_FILTER | 348 RT5640_DA_STEREO_FILTER |
237 RT5640_AD_STEREO_FILTER, 349 RT5640_DA_MONO_L_FILTER |
350 RT5640_DA_MONO_R_FILTER |
351 RT5640_AD_STEREO_FILTER |
352 RT5640_AD_MONO_L_FILTER |
353 RT5640_AD_MONO_R_FILTER,
238 RT5640_CLK_SEL_ASRC); 354 RT5640_CLK_SEL_ASRC);
239 355
240 ret = snd_soc_add_card_controls(card, byt_rt5640_controls, 356 ret = snd_soc_add_card_controls(card, byt_rt5640_controls,
@@ -312,6 +428,30 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
312 snd_soc_dapm_ignore_suspend(&card->dapm, "Headphone"); 428 snd_soc_dapm_ignore_suspend(&card->dapm, "Headphone");
313 snd_soc_dapm_ignore_suspend(&card->dapm, "Speaker"); 429 snd_soc_dapm_ignore_suspend(&card->dapm, "Speaker");
314 430
431 if ((byt_rt5640_quirk & BYT_RT5640_MCLK_EN) && priv->mclk) {
432 /*
433 * The firmware might enable the clock at
434 * boot (this information may or may not
435 * be reflected in the enable clock register).
436 * To change the rate we must disable the clock
437 * first to cover these cases. Due to common
438 * clock framework restrictions that do not allow
439 * to disable a clock that has not been enabled,
440 * we need to enable the clock first.
441 */
442 ret = clk_prepare_enable(priv->mclk);
443 if (!ret)
444 clk_disable_unprepare(priv->mclk);
445
446 if (byt_rt5640_quirk & BYT_RT5640_MCLK_25MHZ)
447 ret = clk_set_rate(priv->mclk, 25000000);
448 else
449 ret = clk_set_rate(priv->mclk, 19200000);
450
451 if (ret)
452 dev_err(card->dev, "unable to set MCLK rate\n");
453 }
454
315 return ret; 455 return ret;
316} 456}
317 457
@@ -490,6 +630,7 @@ static bool is_valleyview(void)
490 return true; 630 return true;
491} 631}
492 632
633
493static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) 634static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
494{ 635{
495 int ret_val = 0; 636 int ret_val = 0;
@@ -497,10 +638,16 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
497 const char *i2c_name = NULL; 638 const char *i2c_name = NULL;
498 int i; 639 int i;
499 int dai_index; 640 int dai_index;
641 struct byt_rt5640_private *priv;
642
643 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC);
644 if (!priv)
645 return -ENOMEM;
500 646
501 /* register the soc card */ 647 /* register the soc card */
502 byt_rt5640_card.dev = &pdev->dev; 648 byt_rt5640_card.dev = &pdev->dev;
503 mach = byt_rt5640_card.dev->platform_data; 649 mach = byt_rt5640_card.dev->platform_data;
650 snd_soc_card_set_drvdata(&byt_rt5640_card, priv);
504 651
505 /* fix index of codec dai */ 652 /* fix index of codec dai */
506 dai_index = MERR_DPCM_COMPR + 1; 653 dai_index = MERR_DPCM_COMPR + 1;
@@ -561,6 +708,16 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
561 byt_rt5640_cpu_dai_name; 708 byt_rt5640_cpu_dai_name;
562 } 709 }
563 710
711 if ((byt_rt5640_quirk & BYT_RT5640_MCLK_EN) && (is_valleyview())) {
712 priv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3");
713 if (IS_ERR(priv->mclk)) {
714 dev_err(&pdev->dev,
715 "Failed to get MCLK from pmc_plt_clk_3: %ld\n",
716 PTR_ERR(priv->mclk));
717 return PTR_ERR(priv->mclk);
718 }
719 }
720
564 ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5640_card); 721 ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5640_card);
565 722
566 if (ret_val) { 723 if (ret_val) {