Path: blob/master/sound/soc/intel/boards/cht_bsw_max98090_ti.c
54408 views
// SPDX-License-Identifier: GPL-2.0-only1/*2* cht-bsw-max98090.c - ASoc Machine driver for Intel Cherryview-based3* platforms Cherrytrail and Braswell, with max98090 & TI codec.4*5* Copyright (C) 2015 Intel Corp6* Author: Fang, Yang A <[email protected]>7* This file is modified from cht_bsw_rt5645.c8* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~9*10* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~11*/1213#include <linux/dmi.h>14#include <linux/gpio/consumer.h>15#include <linux/module.h>16#include <linux/platform_device.h>17#include <linux/slab.h>18#include <linux/acpi.h>19#include <linux/clk.h>20#include <sound/pcm.h>21#include <sound/pcm_params.h>22#include <sound/soc.h>23#include <sound/soc-acpi.h>24#include <sound/jack.h>25#include "../../codecs/max98090.h"26#include "../atom/sst-atom-controls.h"27#include "../../codecs/ts3a227e.h"2829#define CHT_PLAT_CLK_3_HZ 1920000030#define CHT_CODEC_DAI "HiFi"3132#define QUIRK_PMC_PLT_CLK_0 0x013334struct cht_mc_private {35struct clk *mclk;36struct snd_soc_jack jack;37bool ts3a227e_present;38int quirks;39};4041static int platform_clock_control(struct snd_soc_dapm_widget *w,42struct snd_kcontrol *k, int event)43{44struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm);45struct snd_soc_dai *codec_dai;46struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card);47int ret;4849/* See the comment in snd_cht_mc_probe() */50if (ctx->quirks & QUIRK_PMC_PLT_CLK_0)51return 0;5253codec_dai = snd_soc_card_get_codec_dai(card, CHT_CODEC_DAI);54if (!codec_dai) {55dev_err(card->dev, "Codec dai not found; Unable to set platform clock\n");56return -EIO;57}5859if (SND_SOC_DAPM_EVENT_ON(event)) {60ret = clk_prepare_enable(ctx->mclk);61if (ret < 0) {62dev_err(card->dev,63"could not configure MCLK state");64return ret;65}66} else {67clk_disable_unprepare(ctx->mclk);68}6970return 0;71}7273static const struct snd_soc_dapm_widget cht_dapm_widgets[] = {74SND_SOC_DAPM_HP("Headphone", NULL),75SND_SOC_DAPM_MIC("Headset Mic", NULL),76SND_SOC_DAPM_MIC("Int Mic", NULL),77SND_SOC_DAPM_SPK("Ext Spk", NULL),78SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,79platform_clock_control, SND_SOC_DAPM_PRE_PMU |80SND_SOC_DAPM_POST_PMD),81};8283static const struct snd_soc_dapm_route cht_audio_map[] = {84{"IN34", NULL, "Headset Mic"},85{"Headset Mic", NULL, "MICBIAS"},86{"DMICL", NULL, "Int Mic"},87{"Headphone", NULL, "HPL"},88{"Headphone", NULL, "HPR"},89{"Ext Spk", NULL, "SPKL"},90{"Ext Spk", NULL, "SPKR"},91{"HiFi Playback", NULL, "ssp2 Tx"},92{"ssp2 Tx", NULL, "codec_out0"},93{"ssp2 Tx", NULL, "codec_out1"},94{"codec_in0", NULL, "ssp2 Rx" },95{"codec_in1", NULL, "ssp2 Rx" },96{"ssp2 Rx", NULL, "HiFi Capture"},97{"Headphone", NULL, "Platform Clock"},98{"Headset Mic", NULL, "Platform Clock"},99{"Int Mic", NULL, "Platform Clock"},100{"Ext Spk", NULL, "Platform Clock"},101};102103static const struct snd_kcontrol_new cht_mc_controls[] = {104SOC_DAPM_PIN_SWITCH("Headphone"),105SOC_DAPM_PIN_SWITCH("Headset Mic"),106SOC_DAPM_PIN_SWITCH("Int Mic"),107SOC_DAPM_PIN_SWITCH("Ext Spk"),108};109110static int cht_aif1_hw_params(struct snd_pcm_substream *substream,111struct snd_pcm_hw_params *params)112{113struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);114struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);115int ret;116117ret = snd_soc_dai_set_sysclk(codec_dai, M98090_REG_SYSTEM_CLOCK,118CHT_PLAT_CLK_3_HZ, SND_SOC_CLOCK_IN);119if (ret < 0) {120dev_err(rtd->dev, "can't set codec sysclk: %d\n", ret);121return ret;122}123124return 0;125}126127static int cht_ti_jack_event(struct notifier_block *nb,128unsigned long event, void *data)129{130struct snd_soc_jack *jack = (struct snd_soc_jack *)data;131struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(jack->card);132133if (event & SND_JACK_MICROPHONE) {134snd_soc_dapm_force_enable_pin(dapm, "SHDN");135snd_soc_dapm_force_enable_pin(dapm, "MICBIAS");136snd_soc_dapm_sync(dapm);137} else {138snd_soc_dapm_disable_pin(dapm, "MICBIAS");139snd_soc_dapm_disable_pin(dapm, "SHDN");140snd_soc_dapm_sync(dapm);141}142143return 0;144}145146static struct notifier_block cht_jack_nb = {147.notifier_call = cht_ti_jack_event,148};149150static struct snd_soc_jack_pin hs_jack_pins[] = {151{152.pin = "Headphone",153.mask = SND_JACK_HEADPHONE,154},155{156.pin = "Headset Mic",157.mask = SND_JACK_MICROPHONE,158},159};160161static struct snd_soc_jack_gpio hs_jack_gpios[] = {162{163.name = "hp",164.report = SND_JACK_HEADPHONE | SND_JACK_LINEOUT,165.debounce_time = 200,166},167{168.name = "mic",169.invert = 1,170.report = SND_JACK_MICROPHONE,171.debounce_time = 200,172},173};174175static const struct acpi_gpio_params hp_gpios = { 0, 0, false };176static const struct acpi_gpio_params mic_gpios = { 1, 0, false };177178static const struct acpi_gpio_mapping acpi_max98090_gpios[] = {179{ "hp-gpios", &hp_gpios, 1 },180{ "mic-gpios", &mic_gpios, 1 },181{},182};183184static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)185{186int ret;187int jack_type;188struct cht_mc_private *ctx = snd_soc_card_get_drvdata(runtime->card);189struct snd_soc_jack *jack = &ctx->jack;190191if (ctx->ts3a227e_present) {192/*193* The jack has already been created in the194* cht_max98090_headset_init() function.195*/196snd_soc_jack_notifier_register(jack, &cht_jack_nb);197return 0;198}199200jack_type = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE;201202ret = snd_soc_card_jack_new_pins(runtime->card, "Headset Jack",203jack_type, jack,204hs_jack_pins,205ARRAY_SIZE(hs_jack_pins));206if (ret) {207dev_err(runtime->dev, "Headset Jack creation failed %d\n", ret);208return ret;209}210211ret = snd_soc_jack_add_gpiods(runtime->card->dev->parent, jack,212ARRAY_SIZE(hs_jack_gpios),213hs_jack_gpios);214if (ret) {215/*216* flag error but don't bail if jack detect is broken217* due to platform issues or bad BIOS/configuration218*/219dev_err(runtime->dev,220"jack detection gpios not added, error %d\n", ret);221}222223/* See the comment in snd_cht_mc_probe() */224if (ctx->quirks & QUIRK_PMC_PLT_CLK_0)225return 0;226227/*228* The firmware might enable the clock at229* boot (this information may or may not230* be reflected in the enable clock register).231* To change the rate we must disable the clock232* first to cover these cases. Due to common233* clock framework restrictions that do not allow234* to disable a clock that has not been enabled,235* we need to enable the clock first.236*/237ret = clk_prepare_enable(ctx->mclk);238if (!ret)239clk_disable_unprepare(ctx->mclk);240241ret = clk_set_rate(ctx->mclk, CHT_PLAT_CLK_3_HZ);242243if (ret)244dev_err(runtime->dev, "unable to set MCLK rate\n");245246return ret;247}248249static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,250struct snd_pcm_hw_params *params)251{252struct snd_interval *rate = hw_param_interval(params,253SNDRV_PCM_HW_PARAM_RATE);254struct snd_interval *channels = hw_param_interval(params,255SNDRV_PCM_HW_PARAM_CHANNELS);256int ret = 0;257unsigned int fmt = 0;258259ret = snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, 16);260if (ret < 0) {261dev_err(rtd->dev, "can't set cpu_dai slot fmt: %d\n", ret);262return ret;263}264265fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_BP_FP;266267ret = snd_soc_dai_set_fmt(snd_soc_rtd_to_cpu(rtd, 0), fmt);268if (ret < 0) {269dev_err(rtd->dev, "can't set cpu_dai set fmt: %d\n", ret);270return ret;271}272273/* The DSP will convert the FE rate to 48k, stereo, 24bits */274rate->min = rate->max = 48000;275channels->min = channels->max = 2;276277/* set SSP2 to 16-bit */278params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);279return 0;280}281282static int cht_aif1_startup(struct snd_pcm_substream *substream)283{284return snd_pcm_hw_constraint_single(substream->runtime,285SNDRV_PCM_HW_PARAM_RATE, 48000);286}287288static int cht_max98090_headset_init(struct snd_soc_component *component)289{290struct snd_soc_card *card = component->card;291struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card);292struct snd_soc_jack *jack = &ctx->jack;293int jack_type;294int ret;295296/*297* TI supports 4 buttons headset detection298* KEY_MEDIA299* KEY_VOICECOMMAND300* KEY_VOLUMEUP301* KEY_VOLUMEDOWN302*/303jack_type = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |304SND_JACK_BTN_0 | SND_JACK_BTN_1 |305SND_JACK_BTN_2 | SND_JACK_BTN_3;306307ret = snd_soc_card_jack_new(card, "Headset Jack", jack_type, jack);308if (ret) {309dev_err(card->dev, "Headset Jack creation failed %d\n", ret);310return ret;311}312313return ts3a227e_enable_jack_detect(component, jack);314}315316static const struct snd_soc_ops cht_aif1_ops = {317.startup = cht_aif1_startup,318};319320static const struct snd_soc_ops cht_be_ssp2_ops = {321.hw_params = cht_aif1_hw_params,322};323324static struct snd_soc_aux_dev cht_max98090_headset_dev = {325.dlc = COMP_AUX("i2c-104C227E:00"),326.init = cht_max98090_headset_init,327};328329SND_SOC_DAILINK_DEF(dummy,330DAILINK_COMP_ARRAY(COMP_DUMMY()));331332SND_SOC_DAILINK_DEF(media,333DAILINK_COMP_ARRAY(COMP_CPU("media-cpu-dai")));334335SND_SOC_DAILINK_DEF(deepbuffer,336DAILINK_COMP_ARRAY(COMP_CPU("deepbuffer-cpu-dai")));337338SND_SOC_DAILINK_DEF(ssp2_port,339DAILINK_COMP_ARRAY(COMP_CPU("ssp2-port")));340SND_SOC_DAILINK_DEF(ssp2_codec,341DAILINK_COMP_ARRAY(COMP_CODEC("i2c-193C9890:00", "HiFi")));342343SND_SOC_DAILINK_DEF(platform,344DAILINK_COMP_ARRAY(COMP_PLATFORM("sst-mfld-platform")));345346static struct snd_soc_dai_link cht_dailink[] = {347[MERR_DPCM_AUDIO] = {348.name = "Audio Port",349.stream_name = "Audio",350.nonatomic = true,351.dynamic = 1,352.ops = &cht_aif1_ops,353SND_SOC_DAILINK_REG(media, dummy, platform),354},355[MERR_DPCM_DEEP_BUFFER] = {356.name = "Deep-Buffer Audio Port",357.stream_name = "Deep-Buffer Audio",358.nonatomic = true,359.dynamic = 1,360.playback_only = 1,361.ops = &cht_aif1_ops,362SND_SOC_DAILINK_REG(deepbuffer, dummy, platform),363},364/* back ends */365{366.name = "SSP2-Codec",367.id = 0,368.no_pcm = 1,369.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF370| SND_SOC_DAIFMT_CBC_CFC,371.init = cht_codec_init,372.be_hw_params_fixup = cht_codec_fixup,373.ops = &cht_be_ssp2_ops,374SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform),375},376};377378/* use space before codec name to simplify card ID, and simplify driver name */379#define SOF_CARD_NAME "bytcht max98090" /* card name will be 'sof-bytcht max98090 */380#define SOF_DRIVER_NAME "SOF"381382#define CARD_NAME "chtmax98090"383#define DRIVER_NAME NULL /* card name will be used for driver name */384385/* SoC card */386static struct snd_soc_card snd_soc_card_cht = {387.owner = THIS_MODULE,388.dai_link = cht_dailink,389.num_links = ARRAY_SIZE(cht_dailink),390.aux_dev = &cht_max98090_headset_dev,391.num_aux_devs = 1,392.dapm_widgets = cht_dapm_widgets,393.num_dapm_widgets = ARRAY_SIZE(cht_dapm_widgets),394.dapm_routes = cht_audio_map,395.num_dapm_routes = ARRAY_SIZE(cht_audio_map),396.controls = cht_mc_controls,397.num_controls = ARRAY_SIZE(cht_mc_controls),398};399400static const struct dmi_system_id cht_max98090_quirk_table[] = {401{402/* Banjo model Chromebook */403.matches = {404DMI_MATCH(DMI_PRODUCT_NAME, "Banjo"),405},406.driver_data = (void *)QUIRK_PMC_PLT_CLK_0,407},408{409/* Candy model Chromebook */410.matches = {411DMI_MATCH(DMI_PRODUCT_NAME, "Candy"),412},413.driver_data = (void *)QUIRK_PMC_PLT_CLK_0,414},415{416/* Clapper model Chromebook */417.matches = {418DMI_MATCH(DMI_PRODUCT_NAME, "Clapper"),419},420.driver_data = (void *)QUIRK_PMC_PLT_CLK_0,421},422{423/* Cyan model Chromebook */424.matches = {425DMI_MATCH(DMI_PRODUCT_NAME, "Cyan"),426},427.driver_data = (void *)QUIRK_PMC_PLT_CLK_0,428},429{430/* Enguarde model Chromebook */431.matches = {432DMI_MATCH(DMI_PRODUCT_NAME, "Enguarde"),433},434.driver_data = (void *)QUIRK_PMC_PLT_CLK_0,435},436{437/* Glimmer model Chromebook */438.matches = {439DMI_MATCH(DMI_PRODUCT_NAME, "Glimmer"),440},441.driver_data = (void *)QUIRK_PMC_PLT_CLK_0,442},443{444/* Gnawty model Chromebook (Acer Chromebook CB3-111) */445.matches = {446DMI_MATCH(DMI_PRODUCT_NAME, "Gnawty"),447},448.driver_data = (void *)QUIRK_PMC_PLT_CLK_0,449},450{451/* Heli model Chromebook */452.matches = {453DMI_MATCH(DMI_PRODUCT_NAME, "Heli"),454},455.driver_data = (void *)QUIRK_PMC_PLT_CLK_0,456},457{458/* Kip model Chromebook */459.matches = {460DMI_MATCH(DMI_PRODUCT_NAME, "Kip"),461},462.driver_data = (void *)QUIRK_PMC_PLT_CLK_0,463},464{465/* Ninja model Chromebook */466.matches = {467DMI_MATCH(DMI_PRODUCT_NAME, "Ninja"),468},469.driver_data = (void *)QUIRK_PMC_PLT_CLK_0,470},471{472/* Orco model Chromebook */473.matches = {474DMI_MATCH(DMI_PRODUCT_NAME, "Orco"),475},476.driver_data = (void *)QUIRK_PMC_PLT_CLK_0,477},478{479/* Quawks model Chromebook */480.matches = {481DMI_MATCH(DMI_PRODUCT_NAME, "Quawks"),482},483.driver_data = (void *)QUIRK_PMC_PLT_CLK_0,484},485{486/* Rambi model Chromebook */487.matches = {488DMI_MATCH(DMI_PRODUCT_NAME, "Rambi"),489},490.driver_data = (void *)QUIRK_PMC_PLT_CLK_0,491},492{493/* Squawks model Chromebook */494.matches = {495DMI_MATCH(DMI_PRODUCT_NAME, "Squawks"),496},497.driver_data = (void *)QUIRK_PMC_PLT_CLK_0,498},499{500/* Sumo model Chromebook */501.matches = {502DMI_MATCH(DMI_PRODUCT_NAME, "Sumo"),503},504.driver_data = (void *)QUIRK_PMC_PLT_CLK_0,505},506{507/* Swanky model Chromebook (Toshiba Chromebook 2) */508.matches = {509DMI_MATCH(DMI_PRODUCT_NAME, "Swanky"),510},511.driver_data = (void *)QUIRK_PMC_PLT_CLK_0,512},513{514/* Winky model Chromebook */515.matches = {516DMI_MATCH(DMI_PRODUCT_NAME, "Winky"),517},518.driver_data = (void *)QUIRK_PMC_PLT_CLK_0,519},520{}521};522523static int snd_cht_mc_probe(struct platform_device *pdev)524{525const struct dmi_system_id *dmi_id;526struct device *dev = &pdev->dev;527int ret_val = 0;528struct cht_mc_private *drv;529const char *mclk_name;530struct snd_soc_acpi_mach *mach;531const char *platform_name;532bool sof_parent;533534drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL);535if (!drv)536return -ENOMEM;537538dmi_id = dmi_first_match(cht_max98090_quirk_table);539if (dmi_id)540drv->quirks = (unsigned long)dmi_id->driver_data;541542drv->ts3a227e_present = acpi_dev_found("104C227E");543if (!drv->ts3a227e_present) {544/* no need probe TI jack detection chip */545snd_soc_card_cht.aux_dev = NULL;546snd_soc_card_cht.num_aux_devs = 0;547548ret_val = devm_acpi_dev_add_driver_gpios(dev->parent,549acpi_max98090_gpios);550if (ret_val)551dev_dbg(dev, "Unable to add GPIO mapping table\n");552}553554/* override platform name, if required */555snd_soc_card_cht.dev = dev;556mach = dev->platform_data;557platform_name = mach->mach_params.platform;558559ret_val = snd_soc_fixup_dai_links_platform_name(&snd_soc_card_cht,560platform_name);561if (ret_val)562return ret_val;563564/* register the soc card */565snd_soc_card_set_drvdata(&snd_soc_card_cht, drv);566567if (drv->quirks & QUIRK_PMC_PLT_CLK_0)568mclk_name = "pmc_plt_clk_0";569else570mclk_name = "pmc_plt_clk_3";571572drv->mclk = devm_clk_get(dev, mclk_name);573if (IS_ERR(drv->mclk)) {574dev_err(dev,575"Failed to get MCLK from %s: %ld\n",576mclk_name, PTR_ERR(drv->mclk));577return PTR_ERR(drv->mclk);578}579580/*581* Boards which have the MAX98090's clk connected to clk_0 do not seem582* to like it if we muck with the clock. If we disable the clock when583* it is unused we get "max98090 i2c-193C9890:00: PLL unlocked" errors584* and the PLL never seems to lock again.585* So for these boards we enable it here once and leave it at that.586*/587if (drv->quirks & QUIRK_PMC_PLT_CLK_0) {588ret_val = clk_prepare_enable(drv->mclk);589if (ret_val < 0) {590dev_err(dev, "MCLK enable error: %d\n", ret_val);591return ret_val;592}593}594595sof_parent = snd_soc_acpi_sof_parent(dev);596597/* set card and driver name */598if (sof_parent) {599snd_soc_card_cht.name = SOF_CARD_NAME;600snd_soc_card_cht.driver_name = SOF_DRIVER_NAME;601} else {602snd_soc_card_cht.name = CARD_NAME;603snd_soc_card_cht.driver_name = DRIVER_NAME;604}605606/* set pm ops */607if (sof_parent)608dev->driver->pm = &snd_soc_pm_ops;609610ret_val = devm_snd_soc_register_card(dev, &snd_soc_card_cht);611if (ret_val) {612dev_err(dev,613"snd_soc_register_card failed %d\n", ret_val);614return ret_val;615}616platform_set_drvdata(pdev, &snd_soc_card_cht);617return ret_val;618}619620static void snd_cht_mc_remove(struct platform_device *pdev)621{622struct snd_soc_card *card = platform_get_drvdata(pdev);623struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card);624625if (ctx->quirks & QUIRK_PMC_PLT_CLK_0)626clk_disable_unprepare(ctx->mclk);627}628629static struct platform_driver snd_cht_mc_driver = {630.driver = {631.name = "cht-bsw-max98090",632},633.probe = snd_cht_mc_probe,634.remove = snd_cht_mc_remove,635};636637module_platform_driver(snd_cht_mc_driver)638639MODULE_DESCRIPTION("ASoC Intel(R) Braswell Machine driver");640MODULE_AUTHOR("Fang, Yang A <[email protected]>");641MODULE_LICENSE("GPL v2");642MODULE_ALIAS("platform:cht-bsw-max98090");643644645