0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/gpio/consumer.h>
0012 #include <linux/input.h>
0013 #include <linux/module.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/slab.h>
0016 #include <linux/clk.h>
0017 #include <sound/pcm.h>
0018 #include <sound/pcm_params.h>
0019 #include <sound/soc.h>
0020 #include <sound/jack.h>
0021 #include <sound/soc-acpi.h>
0022 #include "../../codecs/rt5670.h"
0023 #include "../atom/sst-atom-controls.h"
0024 #include "../common/soc-intel-quirks.h"
0025
0026
0027
0028 #define CHT_PLAT_CLK_3_HZ 19200000
0029 #define CHT_CODEC_DAI "rt5670-aif1"
0030
0031 struct cht_mc_private {
0032 struct snd_soc_jack headset;
0033 char codec_name[SND_ACPI_I2C_ID_LEN];
0034 struct clk *mclk;
0035 bool use_ssp0;
0036 };
0037
0038
0039 static struct snd_soc_jack_pin cht_bsw_headset_pins[] = {
0040 {
0041 .pin = "Headset Mic",
0042 .mask = SND_JACK_MICROPHONE,
0043 },
0044 {
0045 .pin = "Headphone",
0046 .mask = SND_JACK_HEADPHONE,
0047 },
0048 };
0049
0050 static int platform_clock_control(struct snd_soc_dapm_widget *w,
0051 struct snd_kcontrol *k, int event)
0052 {
0053 struct snd_soc_dapm_context *dapm = w->dapm;
0054 struct snd_soc_card *card = dapm->card;
0055 struct snd_soc_dai *codec_dai;
0056 struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card);
0057 int ret;
0058
0059 codec_dai = snd_soc_card_get_codec_dai(card, CHT_CODEC_DAI);
0060 if (!codec_dai) {
0061 dev_err(card->dev, "Codec dai not found; Unable to set platform clock\n");
0062 return -EIO;
0063 }
0064
0065 if (SND_SOC_DAPM_EVENT_ON(event)) {
0066 if (ctx->mclk) {
0067 ret = clk_prepare_enable(ctx->mclk);
0068 if (ret < 0) {
0069 dev_err(card->dev,
0070 "could not configure MCLK state");
0071 return ret;
0072 }
0073 }
0074
0075
0076 ret = snd_soc_dai_set_pll(codec_dai, 0, RT5670_PLL1_S_MCLK,
0077 CHT_PLAT_CLK_3_HZ, 48000 * 512);
0078 if (ret < 0) {
0079 dev_err(card->dev, "can't set codec pll: %d\n", ret);
0080 return ret;
0081 }
0082
0083
0084 ret = snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_PLL1,
0085 48000 * 512, SND_SOC_CLOCK_IN);
0086 if (ret < 0) {
0087 dev_err(card->dev, "can't set codec sysclk: %d\n", ret);
0088 return ret;
0089 }
0090 } else {
0091
0092
0093
0094
0095
0096 snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_RCCLK,
0097 48000 * 512, SND_SOC_CLOCK_IN);
0098
0099 if (ctx->mclk)
0100 clk_disable_unprepare(ctx->mclk);
0101 }
0102 return 0;
0103 }
0104
0105 static const struct snd_soc_dapm_widget cht_dapm_widgets[] = {
0106 SND_SOC_DAPM_HP("Headphone", NULL),
0107 SND_SOC_DAPM_MIC("Headset Mic", NULL),
0108 SND_SOC_DAPM_MIC("Int Mic", NULL),
0109 SND_SOC_DAPM_SPK("Ext Spk", NULL),
0110 SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
0111 platform_clock_control, SND_SOC_DAPM_PRE_PMU |
0112 SND_SOC_DAPM_POST_PMD),
0113 };
0114
0115 static const struct snd_soc_dapm_route cht_audio_map[] = {
0116 {"IN1P", NULL, "Headset Mic"},
0117 {"IN1N", NULL, "Headset Mic"},
0118 {"DMIC L1", NULL, "Int Mic"},
0119 {"DMIC R1", NULL, "Int Mic"},
0120 {"Headphone", NULL, "HPOL"},
0121 {"Headphone", NULL, "HPOR"},
0122 {"Ext Spk", NULL, "SPOLP"},
0123 {"Ext Spk", NULL, "SPOLN"},
0124 {"Ext Spk", NULL, "SPORP"},
0125 {"Ext Spk", NULL, "SPORN"},
0126 {"Headphone", NULL, "Platform Clock"},
0127 {"Headset Mic", NULL, "Platform Clock"},
0128 {"Int Mic", NULL, "Platform Clock"},
0129 {"Ext Spk", NULL, "Platform Clock"},
0130 };
0131
0132 static const struct snd_soc_dapm_route cht_audio_ssp0_map[] = {
0133 {"AIF1 Playback", NULL, "ssp0 Tx"},
0134 {"ssp0 Tx", NULL, "modem_out"},
0135 {"modem_in", NULL, "ssp0 Rx"},
0136 {"ssp0 Rx", NULL, "AIF1 Capture"},
0137 };
0138
0139 static const struct snd_soc_dapm_route cht_audio_ssp2_map[] = {
0140 {"AIF1 Playback", NULL, "ssp2 Tx"},
0141 {"ssp2 Tx", NULL, "codec_out0"},
0142 {"ssp2 Tx", NULL, "codec_out1"},
0143 {"codec_in0", NULL, "ssp2 Rx"},
0144 {"codec_in1", NULL, "ssp2 Rx"},
0145 {"ssp2 Rx", NULL, "AIF1 Capture"},
0146 };
0147
0148 static const struct snd_kcontrol_new cht_mc_controls[] = {
0149 SOC_DAPM_PIN_SWITCH("Headphone"),
0150 SOC_DAPM_PIN_SWITCH("Headset Mic"),
0151 SOC_DAPM_PIN_SWITCH("Int Mic"),
0152 SOC_DAPM_PIN_SWITCH("Ext Spk"),
0153 };
0154
0155 static int cht_aif1_hw_params(struct snd_pcm_substream *substream,
0156 struct snd_pcm_hw_params *params)
0157 {
0158 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0159 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
0160 int ret;
0161
0162
0163 ret = snd_soc_dai_set_pll(codec_dai, 0, RT5670_PLL1_S_MCLK,
0164 CHT_PLAT_CLK_3_HZ, params_rate(params) * 512);
0165 if (ret < 0) {
0166 dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
0167 return ret;
0168 }
0169
0170
0171 ret = snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_PLL1,
0172 params_rate(params) * 512,
0173 SND_SOC_CLOCK_IN);
0174 if (ret < 0) {
0175 dev_err(rtd->dev, "can't set codec sysclk: %d\n", ret);
0176 return ret;
0177 }
0178 return 0;
0179 }
0180
0181 static const struct acpi_gpio_params headset_gpios = { 0, 0, false };
0182
0183 static const struct acpi_gpio_mapping cht_rt5672_gpios[] = {
0184 { "headset-gpios", &headset_gpios, 1 },
0185 {},
0186 };
0187
0188 static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
0189 {
0190 int ret;
0191 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0);
0192 struct snd_soc_component *component = codec_dai->component;
0193 struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card);
0194
0195 if (devm_acpi_dev_add_driver_gpios(component->dev, cht_rt5672_gpios))
0196 dev_warn(runtime->dev, "Unable to add GPIO mapping table\n");
0197
0198
0199
0200
0201
0202
0203 rt5670_sel_asrc_clk_src(component,
0204 RT5670_DA_STEREO_FILTER
0205 | RT5670_DA_MONO_L_FILTER
0206 | RT5670_DA_MONO_R_FILTER
0207 | RT5670_AD_STEREO_FILTER
0208 | RT5670_AD_MONO_L_FILTER
0209 | RT5670_AD_MONO_R_FILTER,
0210 RT5670_CLK_SEL_I2S1_ASRC);
0211
0212 if (ctx->use_ssp0) {
0213 ret = snd_soc_dapm_add_routes(&runtime->card->dapm,
0214 cht_audio_ssp0_map,
0215 ARRAY_SIZE(cht_audio_ssp0_map));
0216 } else {
0217 ret = snd_soc_dapm_add_routes(&runtime->card->dapm,
0218 cht_audio_ssp2_map,
0219 ARRAY_SIZE(cht_audio_ssp2_map));
0220 }
0221 if (ret)
0222 return ret;
0223
0224 ret = snd_soc_card_jack_new_pins(runtime->card, "Headset",
0225 SND_JACK_HEADSET | SND_JACK_BTN_0 |
0226 SND_JACK_BTN_1 | SND_JACK_BTN_2,
0227 &ctx->headset,
0228 cht_bsw_headset_pins,
0229 ARRAY_SIZE(cht_bsw_headset_pins));
0230 if (ret)
0231 return ret;
0232
0233 snd_jack_set_key(ctx->headset.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
0234 snd_jack_set_key(ctx->headset.jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
0235 snd_jack_set_key(ctx->headset.jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
0236
0237 rt5670_set_jack_detect(component, &ctx->headset);
0238 if (ctx->mclk) {
0239
0240
0241
0242
0243
0244
0245
0246
0247
0248
0249 ret = clk_prepare_enable(ctx->mclk);
0250 if (!ret)
0251 clk_disable_unprepare(ctx->mclk);
0252
0253 ret = clk_set_rate(ctx->mclk, CHT_PLAT_CLK_3_HZ);
0254
0255 if (ret) {
0256 dev_err(runtime->dev, "unable to set MCLK rate\n");
0257 return ret;
0258 }
0259 }
0260 return 0;
0261 }
0262
0263 static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
0264 struct snd_pcm_hw_params *params)
0265 {
0266 struct cht_mc_private *ctx = snd_soc_card_get_drvdata(rtd->card);
0267 struct snd_interval *rate = hw_param_interval(params,
0268 SNDRV_PCM_HW_PARAM_RATE);
0269 struct snd_interval *channels = hw_param_interval(params,
0270 SNDRV_PCM_HW_PARAM_CHANNELS);
0271 int ret, bits;
0272
0273
0274 rate->min = rate->max = 48000;
0275 channels->min = channels->max = 2;
0276
0277 if (ctx->use_ssp0) {
0278
0279 params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
0280 bits = 16;
0281 } else {
0282
0283 params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
0284 bits = 24;
0285 }
0286
0287
0288
0289
0290
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300 ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0),
0301 SND_SOC_DAIFMT_I2S |
0302 SND_SOC_DAIFMT_NB_NF |
0303 SND_SOC_DAIFMT_BP_FP);
0304 if (ret < 0) {
0305 dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
0306 return ret;
0307 }
0308
0309 ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, bits);
0310 if (ret < 0) {
0311 dev_err(rtd->dev, "can't set I2S config, err %d\n", ret);
0312 return ret;
0313 }
0314
0315 return 0;
0316 }
0317
0318 static int cht_aif1_startup(struct snd_pcm_substream *substream)
0319 {
0320 return snd_pcm_hw_constraint_single(substream->runtime,
0321 SNDRV_PCM_HW_PARAM_RATE, 48000);
0322 }
0323
0324 static const struct snd_soc_ops cht_aif1_ops = {
0325 .startup = cht_aif1_startup,
0326 };
0327
0328 static const struct snd_soc_ops cht_be_ssp2_ops = {
0329 .hw_params = cht_aif1_hw_params,
0330 };
0331
0332 SND_SOC_DAILINK_DEF(dummy,
0333 DAILINK_COMP_ARRAY(COMP_DUMMY()));
0334
0335 SND_SOC_DAILINK_DEF(media,
0336 DAILINK_COMP_ARRAY(COMP_CPU("media-cpu-dai")));
0337
0338 SND_SOC_DAILINK_DEF(deepbuffer,
0339 DAILINK_COMP_ARRAY(COMP_CPU("deepbuffer-cpu-dai")));
0340
0341 SND_SOC_DAILINK_DEF(ssp2_port,
0342 DAILINK_COMP_ARRAY(COMP_CPU("ssp2-port")));
0343 SND_SOC_DAILINK_DEF(ssp2_codec,
0344 DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC5670:00",
0345 "rt5670-aif1")));
0346
0347 SND_SOC_DAILINK_DEF(platform,
0348 DAILINK_COMP_ARRAY(COMP_PLATFORM("sst-mfld-platform")));
0349
0350 static struct snd_soc_dai_link cht_dailink[] = {
0351
0352 [MERR_DPCM_AUDIO] = {
0353 .name = "Audio Port",
0354 .stream_name = "Audio",
0355 .nonatomic = true,
0356 .dynamic = 1,
0357 .dpcm_playback = 1,
0358 .dpcm_capture = 1,
0359 .ops = &cht_aif1_ops,
0360 SND_SOC_DAILINK_REG(media, dummy, platform),
0361 },
0362 [MERR_DPCM_DEEP_BUFFER] = {
0363 .name = "Deep-Buffer Audio Port",
0364 .stream_name = "Deep-Buffer Audio",
0365 .nonatomic = true,
0366 .dynamic = 1,
0367 .dpcm_playback = 1,
0368 .ops = &cht_aif1_ops,
0369 SND_SOC_DAILINK_REG(deepbuffer, dummy, platform),
0370 },
0371
0372
0373 {
0374
0375 .name = "SSP2-Codec",
0376 .id = 0,
0377 .no_pcm = 1,
0378 .init = cht_codec_init,
0379 .be_hw_params_fixup = cht_codec_fixup,
0380 .dpcm_playback = 1,
0381 .dpcm_capture = 1,
0382 .ops = &cht_be_ssp2_ops,
0383 SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform),
0384 },
0385 };
0386
0387 static int cht_suspend_pre(struct snd_soc_card *card)
0388 {
0389 struct snd_soc_component *component;
0390 struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card);
0391
0392 for_each_card_components(card, component) {
0393 if (!strncmp(component->name,
0394 ctx->codec_name, sizeof(ctx->codec_name))) {
0395
0396 dev_dbg(component->dev, "disabling jack detect before going to suspend.\n");
0397 rt5670_jack_suspend(component);
0398 break;
0399 }
0400 }
0401 return 0;
0402 }
0403
0404 static int cht_resume_post(struct snd_soc_card *card)
0405 {
0406 struct snd_soc_component *component;
0407 struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card);
0408
0409 for_each_card_components(card, component) {
0410 if (!strncmp(component->name,
0411 ctx->codec_name, sizeof(ctx->codec_name))) {
0412
0413 dev_dbg(component->dev, "enabling jack detect for resume.\n");
0414 rt5670_jack_resume(component);
0415 break;
0416 }
0417 }
0418
0419 return 0;
0420 }
0421
0422
0423 #define SOF_CARD_NAME "bytcht rt5672"
0424 #define SOF_DRIVER_NAME "SOF"
0425
0426 #define CARD_NAME "cht-bsw-rt5672"
0427 #define DRIVER_NAME NULL
0428
0429
0430 static struct snd_soc_card snd_soc_card_cht = {
0431 .owner = THIS_MODULE,
0432 .dai_link = cht_dailink,
0433 .num_links = ARRAY_SIZE(cht_dailink),
0434 .dapm_widgets = cht_dapm_widgets,
0435 .num_dapm_widgets = ARRAY_SIZE(cht_dapm_widgets),
0436 .dapm_routes = cht_audio_map,
0437 .num_dapm_routes = ARRAY_SIZE(cht_audio_map),
0438 .controls = cht_mc_controls,
0439 .num_controls = ARRAY_SIZE(cht_mc_controls),
0440 .suspend_pre = cht_suspend_pre,
0441 .resume_post = cht_resume_post,
0442 };
0443
0444 #define RT5672_I2C_DEFAULT "i2c-10EC5670:00"
0445
0446 static int snd_cht_mc_probe(struct platform_device *pdev)
0447 {
0448 int ret_val = 0;
0449 struct cht_mc_private *drv;
0450 struct snd_soc_acpi_mach *mach = pdev->dev.platform_data;
0451 const char *platform_name;
0452 struct acpi_device *adev;
0453 bool sof_parent;
0454 int dai_index = 0;
0455 int i;
0456
0457 drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
0458 if (!drv)
0459 return -ENOMEM;
0460
0461 strcpy(drv->codec_name, RT5672_I2C_DEFAULT);
0462
0463
0464 for (i = 0; i < ARRAY_SIZE(cht_dailink); i++) {
0465 if (!strcmp(cht_dailink[i].codecs->name, RT5672_I2C_DEFAULT)) {
0466 dai_index = i;
0467 break;
0468 }
0469 }
0470
0471
0472 adev = acpi_dev_get_first_match_dev(mach->id, NULL, -1);
0473 if (adev) {
0474 snprintf(drv->codec_name, sizeof(drv->codec_name),
0475 "i2c-%s", acpi_dev_name(adev));
0476 put_device(&adev->dev);
0477 cht_dailink[dai_index].codecs->name = drv->codec_name;
0478 }
0479
0480
0481 if (soc_intel_is_byt() && mach->mach_params.acpi_ipc_irq_index == 0) {
0482 cht_dailink[dai_index].cpus->dai_name = "ssp0-port";
0483 drv->use_ssp0 = true;
0484 }
0485
0486
0487 snd_soc_card_cht.dev = &pdev->dev;
0488 platform_name = mach->mach_params.platform;
0489
0490 ret_val = snd_soc_fixup_dai_links_platform_name(&snd_soc_card_cht,
0491 platform_name);
0492 if (ret_val)
0493 return ret_val;
0494
0495 snd_soc_card_cht.components = rt5670_components();
0496
0497 drv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3");
0498 if (IS_ERR(drv->mclk)) {
0499 dev_err(&pdev->dev,
0500 "Failed to get MCLK from pmc_plt_clk_3: %ld\n",
0501 PTR_ERR(drv->mclk));
0502 return PTR_ERR(drv->mclk);
0503 }
0504 snd_soc_card_set_drvdata(&snd_soc_card_cht, drv);
0505
0506 sof_parent = snd_soc_acpi_sof_parent(&pdev->dev);
0507
0508
0509 if (sof_parent) {
0510 snd_soc_card_cht.name = SOF_CARD_NAME;
0511 snd_soc_card_cht.driver_name = SOF_DRIVER_NAME;
0512 } else {
0513 snd_soc_card_cht.name = CARD_NAME;
0514 snd_soc_card_cht.driver_name = DRIVER_NAME;
0515 }
0516
0517
0518 if (sof_parent)
0519 pdev->dev.driver->pm = &snd_soc_pm_ops;
0520
0521
0522 ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht);
0523 if (ret_val) {
0524 dev_err(&pdev->dev,
0525 "snd_soc_register_card failed %d\n", ret_val);
0526 return ret_val;
0527 }
0528 platform_set_drvdata(pdev, &snd_soc_card_cht);
0529 return ret_val;
0530 }
0531
0532 static struct platform_driver snd_cht_mc_driver = {
0533 .driver = {
0534 .name = "cht-bsw-rt5672",
0535 },
0536 .probe = snd_cht_mc_probe,
0537 };
0538
0539 module_platform_driver(snd_cht_mc_driver);
0540
0541 MODULE_DESCRIPTION("ASoC Intel(R) Baytrail CR Machine driver");
0542 MODULE_AUTHOR("Subhransu S. Prusty, Mengdong Lin");
0543 MODULE_LICENSE("GPL v2");
0544 MODULE_ALIAS("platform:cht-bsw-rt5672");