0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #include <linux/dmi.h>
0015 #include <linux/gpio/consumer.h>
0016 #include <linux/module.h>
0017 #include <linux/platform_device.h>
0018 #include <linux/slab.h>
0019 #include <linux/acpi.h>
0020 #include <linux/clk.h>
0021 #include <sound/pcm.h>
0022 #include <sound/pcm_params.h>
0023 #include <sound/soc.h>
0024 #include <sound/soc-acpi.h>
0025 #include <sound/jack.h>
0026 #include "../../codecs/max98090.h"
0027 #include "../atom/sst-atom-controls.h"
0028 #include "../../codecs/ts3a227e.h"
0029
0030 #define CHT_PLAT_CLK_3_HZ 19200000
0031 #define CHT_CODEC_DAI "HiFi"
0032
0033 #define QUIRK_PMC_PLT_CLK_0 0x01
0034
0035 struct cht_mc_private {
0036 struct clk *mclk;
0037 struct snd_soc_jack jack;
0038 bool ts3a227e_present;
0039 int quirks;
0040 };
0041
0042 static int platform_clock_control(struct snd_soc_dapm_widget *w,
0043 struct snd_kcontrol *k, int event)
0044 {
0045 struct snd_soc_dapm_context *dapm = w->dapm;
0046 struct snd_soc_card *card = dapm->card;
0047 struct snd_soc_dai *codec_dai;
0048 struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card);
0049 int ret;
0050
0051
0052 if (ctx->quirks & QUIRK_PMC_PLT_CLK_0)
0053 return 0;
0054
0055 codec_dai = snd_soc_card_get_codec_dai(card, CHT_CODEC_DAI);
0056 if (!codec_dai) {
0057 dev_err(card->dev, "Codec dai not found; Unable to set platform clock\n");
0058 return -EIO;
0059 }
0060
0061 if (SND_SOC_DAPM_EVENT_ON(event)) {
0062 ret = clk_prepare_enable(ctx->mclk);
0063 if (ret < 0) {
0064 dev_err(card->dev,
0065 "could not configure MCLK state");
0066 return ret;
0067 }
0068 } else {
0069 clk_disable_unprepare(ctx->mclk);
0070 }
0071
0072 return 0;
0073 }
0074
0075 static const struct snd_soc_dapm_widget cht_dapm_widgets[] = {
0076 SND_SOC_DAPM_HP("Headphone", NULL),
0077 SND_SOC_DAPM_MIC("Headset Mic", NULL),
0078 SND_SOC_DAPM_MIC("Int Mic", NULL),
0079 SND_SOC_DAPM_SPK("Ext Spk", NULL),
0080 SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
0081 platform_clock_control, SND_SOC_DAPM_PRE_PMU |
0082 SND_SOC_DAPM_POST_PMD),
0083 };
0084
0085 static const struct snd_soc_dapm_route cht_audio_map[] = {
0086 {"IN34", NULL, "Headset Mic"},
0087 {"Headset Mic", NULL, "MICBIAS"},
0088 {"DMICL", NULL, "Int Mic"},
0089 {"Headphone", NULL, "HPL"},
0090 {"Headphone", NULL, "HPR"},
0091 {"Ext Spk", NULL, "SPKL"},
0092 {"Ext Spk", NULL, "SPKR"},
0093 {"HiFi Playback", NULL, "ssp2 Tx"},
0094 {"ssp2 Tx", NULL, "codec_out0"},
0095 {"ssp2 Tx", NULL, "codec_out1"},
0096 {"codec_in0", NULL, "ssp2 Rx" },
0097 {"codec_in1", NULL, "ssp2 Rx" },
0098 {"ssp2 Rx", NULL, "HiFi Capture"},
0099 {"Headphone", NULL, "Platform Clock"},
0100 {"Headset Mic", NULL, "Platform Clock"},
0101 {"Int Mic", NULL, "Platform Clock"},
0102 {"Ext Spk", NULL, "Platform Clock"},
0103 };
0104
0105 static const struct snd_kcontrol_new cht_mc_controls[] = {
0106 SOC_DAPM_PIN_SWITCH("Headphone"),
0107 SOC_DAPM_PIN_SWITCH("Headset Mic"),
0108 SOC_DAPM_PIN_SWITCH("Int Mic"),
0109 SOC_DAPM_PIN_SWITCH("Ext Spk"),
0110 };
0111
0112 static int cht_aif1_hw_params(struct snd_pcm_substream *substream,
0113 struct snd_pcm_hw_params *params)
0114 {
0115 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0116 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
0117 int ret;
0118
0119 ret = snd_soc_dai_set_sysclk(codec_dai, M98090_REG_SYSTEM_CLOCK,
0120 CHT_PLAT_CLK_3_HZ, SND_SOC_CLOCK_IN);
0121 if (ret < 0) {
0122 dev_err(rtd->dev, "can't set codec sysclk: %d\n", ret);
0123 return ret;
0124 }
0125
0126 return 0;
0127 }
0128
0129 static int cht_ti_jack_event(struct notifier_block *nb,
0130 unsigned long event, void *data)
0131 {
0132 struct snd_soc_jack *jack = (struct snd_soc_jack *)data;
0133 struct snd_soc_dapm_context *dapm = &jack->card->dapm;
0134
0135 if (event & SND_JACK_MICROPHONE) {
0136 snd_soc_dapm_force_enable_pin(dapm, "SHDN");
0137 snd_soc_dapm_force_enable_pin(dapm, "MICBIAS");
0138 snd_soc_dapm_sync(dapm);
0139 } else {
0140 snd_soc_dapm_disable_pin(dapm, "MICBIAS");
0141 snd_soc_dapm_disable_pin(dapm, "SHDN");
0142 snd_soc_dapm_sync(dapm);
0143 }
0144
0145 return 0;
0146 }
0147
0148 static struct notifier_block cht_jack_nb = {
0149 .notifier_call = cht_ti_jack_event,
0150 };
0151
0152 static struct snd_soc_jack_pin hs_jack_pins[] = {
0153 {
0154 .pin = "Headphone",
0155 .mask = SND_JACK_HEADPHONE,
0156 },
0157 {
0158 .pin = "Headset Mic",
0159 .mask = SND_JACK_MICROPHONE,
0160 },
0161 };
0162
0163 static struct snd_soc_jack_gpio hs_jack_gpios[] = {
0164 {
0165 .name = "hp",
0166 .report = SND_JACK_HEADPHONE | SND_JACK_LINEOUT,
0167 .debounce_time = 200,
0168 },
0169 {
0170 .name = "mic",
0171 .invert = 1,
0172 .report = SND_JACK_MICROPHONE,
0173 .debounce_time = 200,
0174 },
0175 };
0176
0177 static const struct acpi_gpio_params hp_gpios = { 0, 0, false };
0178 static const struct acpi_gpio_params mic_gpios = { 1, 0, false };
0179
0180 static const struct acpi_gpio_mapping acpi_max98090_gpios[] = {
0181 { "hp-gpios", &hp_gpios, 1 },
0182 { "mic-gpios", &mic_gpios, 1 },
0183 {},
0184 };
0185
0186 static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
0187 {
0188 int ret;
0189 int jack_type;
0190 struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card);
0191 struct snd_soc_jack *jack = &ctx->jack;
0192
0193 if (ctx->ts3a227e_present) {
0194
0195
0196
0197
0198 snd_soc_jack_notifier_register(jack, &cht_jack_nb);
0199 return 0;
0200 }
0201
0202 jack_type = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE;
0203
0204 ret = snd_soc_card_jack_new_pins(runtime->card, "Headset Jack",
0205 jack_type, jack,
0206 hs_jack_pins,
0207 ARRAY_SIZE(hs_jack_pins));
0208 if (ret) {
0209 dev_err(runtime->dev, "Headset Jack creation failed %d\n", ret);
0210 return ret;
0211 }
0212
0213 ret = snd_soc_jack_add_gpiods(runtime->card->dev->parent, jack,
0214 ARRAY_SIZE(hs_jack_gpios),
0215 hs_jack_gpios);
0216 if (ret) {
0217
0218
0219
0220
0221 dev_err(runtime->dev,
0222 "jack detection gpios not added, error %d\n", ret);
0223 }
0224
0225
0226 if (ctx->quirks & QUIRK_PMC_PLT_CLK_0)
0227 return 0;
0228
0229
0230
0231
0232
0233
0234
0235
0236
0237
0238
0239 ret = clk_prepare_enable(ctx->mclk);
0240 if (!ret)
0241 clk_disable_unprepare(ctx->mclk);
0242
0243 ret = clk_set_rate(ctx->mclk, CHT_PLAT_CLK_3_HZ);
0244
0245 if (ret)
0246 dev_err(runtime->dev, "unable to set MCLK rate\n");
0247
0248 return ret;
0249 }
0250
0251 static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
0252 struct snd_pcm_hw_params *params)
0253 {
0254 struct snd_interval *rate = hw_param_interval(params,
0255 SNDRV_PCM_HW_PARAM_RATE);
0256 struct snd_interval *channels = hw_param_interval(params,
0257 SNDRV_PCM_HW_PARAM_CHANNELS);
0258 int ret = 0;
0259 unsigned int fmt = 0;
0260
0261 ret = snd_soc_dai_set_tdm_slot(asoc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, 16);
0262 if (ret < 0) {
0263 dev_err(rtd->dev, "can't set cpu_dai slot fmt: %d\n", ret);
0264 return ret;
0265 }
0266
0267 fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_BP_FP;
0268
0269 ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), fmt);
0270 if (ret < 0) {
0271 dev_err(rtd->dev, "can't set cpu_dai set fmt: %d\n", ret);
0272 return ret;
0273 }
0274
0275
0276 rate->min = rate->max = 48000;
0277 channels->min = channels->max = 2;
0278
0279
0280 params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
0281 return 0;
0282 }
0283
0284 static int cht_aif1_startup(struct snd_pcm_substream *substream)
0285 {
0286 return snd_pcm_hw_constraint_single(substream->runtime,
0287 SNDRV_PCM_HW_PARAM_RATE, 48000);
0288 }
0289
0290 static int cht_max98090_headset_init(struct snd_soc_component *component)
0291 {
0292 struct snd_soc_card *card = component->card;
0293 struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card);
0294 struct snd_soc_jack *jack = &ctx->jack;
0295 int jack_type;
0296 int ret;
0297
0298
0299
0300
0301
0302
0303
0304
0305 jack_type = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
0306 SND_JACK_BTN_0 | SND_JACK_BTN_1 |
0307 SND_JACK_BTN_2 | SND_JACK_BTN_3;
0308
0309 ret = snd_soc_card_jack_new(card, "Headset Jack", jack_type, jack);
0310 if (ret) {
0311 dev_err(card->dev, "Headset Jack creation failed %d\n", ret);
0312 return ret;
0313 }
0314
0315 return ts3a227e_enable_jack_detect(component, jack);
0316 }
0317
0318 static const struct snd_soc_ops cht_aif1_ops = {
0319 .startup = cht_aif1_startup,
0320 };
0321
0322 static const struct snd_soc_ops cht_be_ssp2_ops = {
0323 .hw_params = cht_aif1_hw_params,
0324 };
0325
0326 static struct snd_soc_aux_dev cht_max98090_headset_dev = {
0327 .dlc = COMP_AUX("i2c-104C227E:00"),
0328 .init = cht_max98090_headset_init,
0329 };
0330
0331 SND_SOC_DAILINK_DEF(dummy,
0332 DAILINK_COMP_ARRAY(COMP_DUMMY()));
0333
0334 SND_SOC_DAILINK_DEF(media,
0335 DAILINK_COMP_ARRAY(COMP_CPU("media-cpu-dai")));
0336
0337 SND_SOC_DAILINK_DEF(deepbuffer,
0338 DAILINK_COMP_ARRAY(COMP_CPU("deepbuffer-cpu-dai")));
0339
0340 SND_SOC_DAILINK_DEF(ssp2_port,
0341 DAILINK_COMP_ARRAY(COMP_CPU("ssp2-port")));
0342 SND_SOC_DAILINK_DEF(ssp2_codec,
0343 DAILINK_COMP_ARRAY(COMP_CODEC("i2c-193C9890:00", "HiFi")));
0344
0345 SND_SOC_DAILINK_DEF(platform,
0346 DAILINK_COMP_ARRAY(COMP_PLATFORM("sst-mfld-platform")));
0347
0348 static struct snd_soc_dai_link cht_dailink[] = {
0349 [MERR_DPCM_AUDIO] = {
0350 .name = "Audio Port",
0351 .stream_name = "Audio",
0352 .nonatomic = true,
0353 .dynamic = 1,
0354 .dpcm_playback = 1,
0355 .dpcm_capture = 1,
0356 .ops = &cht_aif1_ops,
0357 SND_SOC_DAILINK_REG(media, dummy, platform),
0358 },
0359 [MERR_DPCM_DEEP_BUFFER] = {
0360 .name = "Deep-Buffer Audio Port",
0361 .stream_name = "Deep-Buffer Audio",
0362 .nonatomic = true,
0363 .dynamic = 1,
0364 .dpcm_playback = 1,
0365 .ops = &cht_aif1_ops,
0366 SND_SOC_DAILINK_REG(deepbuffer, dummy, platform),
0367 },
0368
0369 {
0370 .name = "SSP2-Codec",
0371 .id = 0,
0372 .no_pcm = 1,
0373 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
0374 | SND_SOC_DAIFMT_CBC_CFC,
0375 .init = cht_codec_init,
0376 .be_hw_params_fixup = cht_codec_fixup,
0377 .dpcm_playback = 1,
0378 .dpcm_capture = 1,
0379 .ops = &cht_be_ssp2_ops,
0380 SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform),
0381 },
0382 };
0383
0384
0385 #define SOF_CARD_NAME "bytcht max98090"
0386 #define SOF_DRIVER_NAME "SOF"
0387
0388 #define CARD_NAME "chtmax98090"
0389 #define DRIVER_NAME NULL
0390
0391
0392 static struct snd_soc_card snd_soc_card_cht = {
0393 .owner = THIS_MODULE,
0394 .dai_link = cht_dailink,
0395 .num_links = ARRAY_SIZE(cht_dailink),
0396 .aux_dev = &cht_max98090_headset_dev,
0397 .num_aux_devs = 1,
0398 .dapm_widgets = cht_dapm_widgets,
0399 .num_dapm_widgets = ARRAY_SIZE(cht_dapm_widgets),
0400 .dapm_routes = cht_audio_map,
0401 .num_dapm_routes = ARRAY_SIZE(cht_audio_map),
0402 .controls = cht_mc_controls,
0403 .num_controls = ARRAY_SIZE(cht_mc_controls),
0404 };
0405
0406 static const struct dmi_system_id cht_max98090_quirk_table[] = {
0407 {
0408
0409 .matches = {
0410 DMI_MATCH(DMI_PRODUCT_NAME, "Banjo"),
0411 },
0412 .driver_data = (void *)QUIRK_PMC_PLT_CLK_0,
0413 },
0414 {
0415
0416 .matches = {
0417 DMI_MATCH(DMI_PRODUCT_NAME, "Candy"),
0418 },
0419 .driver_data = (void *)QUIRK_PMC_PLT_CLK_0,
0420 },
0421 {
0422
0423 .matches = {
0424 DMI_MATCH(DMI_PRODUCT_NAME, "Clapper"),
0425 },
0426 .driver_data = (void *)QUIRK_PMC_PLT_CLK_0,
0427 },
0428 {
0429
0430 .matches = {
0431 DMI_MATCH(DMI_PRODUCT_NAME, "Cyan"),
0432 },
0433 .driver_data = (void *)QUIRK_PMC_PLT_CLK_0,
0434 },
0435 {
0436
0437 .matches = {
0438 DMI_MATCH(DMI_PRODUCT_NAME, "Enguarde"),
0439 },
0440 .driver_data = (void *)QUIRK_PMC_PLT_CLK_0,
0441 },
0442 {
0443
0444 .matches = {
0445 DMI_MATCH(DMI_PRODUCT_NAME, "Glimmer"),
0446 },
0447 .driver_data = (void *)QUIRK_PMC_PLT_CLK_0,
0448 },
0449 {
0450
0451 .matches = {
0452 DMI_MATCH(DMI_PRODUCT_NAME, "Gnawty"),
0453 },
0454 .driver_data = (void *)QUIRK_PMC_PLT_CLK_0,
0455 },
0456 {
0457
0458 .matches = {
0459 DMI_MATCH(DMI_PRODUCT_NAME, "Heli"),
0460 },
0461 .driver_data = (void *)QUIRK_PMC_PLT_CLK_0,
0462 },
0463 {
0464
0465 .matches = {
0466 DMI_MATCH(DMI_PRODUCT_NAME, "Kip"),
0467 },
0468 .driver_data = (void *)QUIRK_PMC_PLT_CLK_0,
0469 },
0470 {
0471
0472 .matches = {
0473 DMI_MATCH(DMI_PRODUCT_NAME, "Ninja"),
0474 },
0475 .driver_data = (void *)QUIRK_PMC_PLT_CLK_0,
0476 },
0477 {
0478
0479 .matches = {
0480 DMI_MATCH(DMI_PRODUCT_NAME, "Orco"),
0481 },
0482 .driver_data = (void *)QUIRK_PMC_PLT_CLK_0,
0483 },
0484 {
0485
0486 .matches = {
0487 DMI_MATCH(DMI_PRODUCT_NAME, "Quawks"),
0488 },
0489 .driver_data = (void *)QUIRK_PMC_PLT_CLK_0,
0490 },
0491 {
0492
0493 .matches = {
0494 DMI_MATCH(DMI_PRODUCT_NAME, "Rambi"),
0495 },
0496 .driver_data = (void *)QUIRK_PMC_PLT_CLK_0,
0497 },
0498 {
0499
0500 .matches = {
0501 DMI_MATCH(DMI_PRODUCT_NAME, "Squawks"),
0502 },
0503 .driver_data = (void *)QUIRK_PMC_PLT_CLK_0,
0504 },
0505 {
0506
0507 .matches = {
0508 DMI_MATCH(DMI_PRODUCT_NAME, "Sumo"),
0509 },
0510 .driver_data = (void *)QUIRK_PMC_PLT_CLK_0,
0511 },
0512 {
0513
0514 .matches = {
0515 DMI_MATCH(DMI_PRODUCT_NAME, "Swanky"),
0516 },
0517 .driver_data = (void *)QUIRK_PMC_PLT_CLK_0,
0518 },
0519 {
0520
0521 .matches = {
0522 DMI_MATCH(DMI_PRODUCT_NAME, "Winky"),
0523 },
0524 .driver_data = (void *)QUIRK_PMC_PLT_CLK_0,
0525 },
0526 {}
0527 };
0528
0529 static int snd_cht_mc_probe(struct platform_device *pdev)
0530 {
0531 const struct dmi_system_id *dmi_id;
0532 struct device *dev = &pdev->dev;
0533 int ret_val = 0;
0534 struct cht_mc_private *drv;
0535 const char *mclk_name;
0536 struct snd_soc_acpi_mach *mach;
0537 const char *platform_name;
0538 bool sof_parent;
0539
0540 drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL);
0541 if (!drv)
0542 return -ENOMEM;
0543
0544 dmi_id = dmi_first_match(cht_max98090_quirk_table);
0545 if (dmi_id)
0546 drv->quirks = (unsigned long)dmi_id->driver_data;
0547
0548 drv->ts3a227e_present = acpi_dev_found("104C227E");
0549 if (!drv->ts3a227e_present) {
0550
0551 snd_soc_card_cht.aux_dev = NULL;
0552 snd_soc_card_cht.num_aux_devs = 0;
0553
0554 ret_val = devm_acpi_dev_add_driver_gpios(dev->parent,
0555 acpi_max98090_gpios);
0556 if (ret_val)
0557 dev_dbg(dev, "Unable to add GPIO mapping table\n");
0558 }
0559
0560
0561 snd_soc_card_cht.dev = dev;
0562 mach = dev->platform_data;
0563 platform_name = mach->mach_params.platform;
0564
0565 ret_val = snd_soc_fixup_dai_links_platform_name(&snd_soc_card_cht,
0566 platform_name);
0567 if (ret_val)
0568 return ret_val;
0569
0570
0571 snd_soc_card_set_drvdata(&snd_soc_card_cht, drv);
0572
0573 if (drv->quirks & QUIRK_PMC_PLT_CLK_0)
0574 mclk_name = "pmc_plt_clk_0";
0575 else
0576 mclk_name = "pmc_plt_clk_3";
0577
0578 drv->mclk = devm_clk_get(dev, mclk_name);
0579 if (IS_ERR(drv->mclk)) {
0580 dev_err(dev,
0581 "Failed to get MCLK from %s: %ld\n",
0582 mclk_name, PTR_ERR(drv->mclk));
0583 return PTR_ERR(drv->mclk);
0584 }
0585
0586
0587
0588
0589
0590
0591
0592
0593 if (drv->quirks & QUIRK_PMC_PLT_CLK_0) {
0594 ret_val = clk_prepare_enable(drv->mclk);
0595 if (ret_val < 0) {
0596 dev_err(dev, "MCLK enable error: %d\n", ret_val);
0597 return ret_val;
0598 }
0599 }
0600
0601 sof_parent = snd_soc_acpi_sof_parent(dev);
0602
0603
0604 if (sof_parent) {
0605 snd_soc_card_cht.name = SOF_CARD_NAME;
0606 snd_soc_card_cht.driver_name = SOF_DRIVER_NAME;
0607 } else {
0608 snd_soc_card_cht.name = CARD_NAME;
0609 snd_soc_card_cht.driver_name = DRIVER_NAME;
0610 }
0611
0612
0613 if (sof_parent)
0614 dev->driver->pm = &snd_soc_pm_ops;
0615
0616 ret_val = devm_snd_soc_register_card(dev, &snd_soc_card_cht);
0617 if (ret_val) {
0618 dev_err(dev,
0619 "snd_soc_register_card failed %d\n", ret_val);
0620 return ret_val;
0621 }
0622 platform_set_drvdata(pdev, &snd_soc_card_cht);
0623 return ret_val;
0624 }
0625
0626 static int snd_cht_mc_remove(struct platform_device *pdev)
0627 {
0628 struct snd_soc_card *card = platform_get_drvdata(pdev);
0629 struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card);
0630
0631 if (ctx->quirks & QUIRK_PMC_PLT_CLK_0)
0632 clk_disable_unprepare(ctx->mclk);
0633
0634 return 0;
0635 }
0636
0637 static struct platform_driver snd_cht_mc_driver = {
0638 .driver = {
0639 .name = "cht-bsw-max98090",
0640 },
0641 .probe = snd_cht_mc_probe,
0642 .remove = snd_cht_mc_remove,
0643 };
0644
0645 module_platform_driver(snd_cht_mc_driver)
0646
0647 MODULE_DESCRIPTION("ASoC Intel(R) Braswell Machine driver");
0648 MODULE_AUTHOR("Fang, Yang A <yang.a.fang@intel.com>");
0649 MODULE_LICENSE("GPL v2");
0650 MODULE_ALIAS("platform:cht-bsw-max98090");