162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * ASoC machine driver for Intel Broadwell platforms with RT5677 codec 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2014, The Chromium OS Authors. All rights reserved. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/acpi.h> 962306a36Sopenharmony_ci#include <linux/module.h> 1062306a36Sopenharmony_ci#include <linux/platform_device.h> 1162306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 1262306a36Sopenharmony_ci#include <linux/delay.h> 1362306a36Sopenharmony_ci#include <sound/core.h> 1462306a36Sopenharmony_ci#include <sound/pcm.h> 1562306a36Sopenharmony_ci#include <sound/soc.h> 1662306a36Sopenharmony_ci#include <sound/pcm_params.h> 1762306a36Sopenharmony_ci#include <sound/jack.h> 1862306a36Sopenharmony_ci#include <sound/soc-acpi.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include "../../codecs/rt5677.h" 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistruct bdw_rt5677_priv { 2362306a36Sopenharmony_ci struct gpio_desc *gpio_hp_en; 2462306a36Sopenharmony_ci struct snd_soc_component *component; 2562306a36Sopenharmony_ci}; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic int bdw_rt5677_event_hp(struct snd_soc_dapm_widget *w, 2862306a36Sopenharmony_ci struct snd_kcontrol *k, int event) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci struct snd_soc_dapm_context *dapm = w->dapm; 3162306a36Sopenharmony_ci struct snd_soc_card *card = dapm->card; 3262306a36Sopenharmony_ci struct bdw_rt5677_priv *bdw_rt5677 = snd_soc_card_get_drvdata(card); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci if (SND_SOC_DAPM_EVENT_ON(event)) 3562306a36Sopenharmony_ci msleep(70); 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci gpiod_set_value_cansleep(bdw_rt5677->gpio_hp_en, 3862306a36Sopenharmony_ci SND_SOC_DAPM_EVENT_ON(event)); 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci return 0; 4162306a36Sopenharmony_ci} 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistatic const struct snd_soc_dapm_widget bdw_rt5677_widgets[] = { 4462306a36Sopenharmony_ci SND_SOC_DAPM_HP("Headphone", bdw_rt5677_event_hp), 4562306a36Sopenharmony_ci SND_SOC_DAPM_SPK("Speaker", NULL), 4662306a36Sopenharmony_ci SND_SOC_DAPM_MIC("Headset Mic", NULL), 4762306a36Sopenharmony_ci SND_SOC_DAPM_MIC("Local DMICs", NULL), 4862306a36Sopenharmony_ci SND_SOC_DAPM_MIC("Remote DMICs", NULL), 4962306a36Sopenharmony_ci}; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistatic const struct snd_soc_dapm_route bdw_rt5677_map[] = { 5262306a36Sopenharmony_ci /* Speakers */ 5362306a36Sopenharmony_ci {"Speaker", NULL, "PDM1L"}, 5462306a36Sopenharmony_ci {"Speaker", NULL, "PDM1R"}, 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci /* Headset jack connectors */ 5762306a36Sopenharmony_ci {"Headphone", NULL, "LOUT1"}, 5862306a36Sopenharmony_ci {"Headphone", NULL, "LOUT2"}, 5962306a36Sopenharmony_ci {"IN1P", NULL, "Headset Mic"}, 6062306a36Sopenharmony_ci {"IN1N", NULL, "Headset Mic"}, 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci /* Digital MICs 6362306a36Sopenharmony_ci * Local DMICs: the two DMICs on the mainboard 6462306a36Sopenharmony_ci * Remote DMICs: the two DMICs on the camera module 6562306a36Sopenharmony_ci */ 6662306a36Sopenharmony_ci {"DMIC L1", NULL, "Remote DMICs"}, 6762306a36Sopenharmony_ci {"DMIC R1", NULL, "Remote DMICs"}, 6862306a36Sopenharmony_ci {"DMIC L2", NULL, "Local DMICs"}, 6962306a36Sopenharmony_ci {"DMIC R2", NULL, "Local DMICs"}, 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci /* CODEC BE connections */ 7262306a36Sopenharmony_ci {"SSP0 CODEC IN", NULL, "AIF1 Capture"}, 7362306a36Sopenharmony_ci {"AIF1 Playback", NULL, "SSP0 CODEC OUT"}, 7462306a36Sopenharmony_ci {"DSP Capture", NULL, "DSP Buffer"}, 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci /* DSP Clock Connections */ 7762306a36Sopenharmony_ci { "DSP Buffer", NULL, "SSP0 CODEC IN" }, 7862306a36Sopenharmony_ci { "SSP0 CODEC IN", NULL, "DSPTX" }, 7962306a36Sopenharmony_ci}; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistatic const struct snd_kcontrol_new bdw_rt5677_controls[] = { 8262306a36Sopenharmony_ci SOC_DAPM_PIN_SWITCH("Speaker"), 8362306a36Sopenharmony_ci SOC_DAPM_PIN_SWITCH("Headphone"), 8462306a36Sopenharmony_ci SOC_DAPM_PIN_SWITCH("Headset Mic"), 8562306a36Sopenharmony_ci SOC_DAPM_PIN_SWITCH("Local DMICs"), 8662306a36Sopenharmony_ci SOC_DAPM_PIN_SWITCH("Remote DMICs"), 8762306a36Sopenharmony_ci}; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistatic struct snd_soc_jack headphone_jack; 9162306a36Sopenharmony_cistatic struct snd_soc_jack mic_jack; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistatic struct snd_soc_jack_pin headphone_jack_pin = { 9462306a36Sopenharmony_ci .pin = "Headphone", 9562306a36Sopenharmony_ci .mask = SND_JACK_HEADPHONE, 9662306a36Sopenharmony_ci}; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic struct snd_soc_jack_pin mic_jack_pin = { 9962306a36Sopenharmony_ci .pin = "Headset Mic", 10062306a36Sopenharmony_ci .mask = SND_JACK_MICROPHONE, 10162306a36Sopenharmony_ci}; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic struct snd_soc_jack_gpio headphone_jack_gpio = { 10462306a36Sopenharmony_ci .name = "plug-det", 10562306a36Sopenharmony_ci .report = SND_JACK_HEADPHONE, 10662306a36Sopenharmony_ci .debounce_time = 200, 10762306a36Sopenharmony_ci}; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic struct snd_soc_jack_gpio mic_jack_gpio = { 11062306a36Sopenharmony_ci .name = "mic-present", 11162306a36Sopenharmony_ci .report = SND_JACK_MICROPHONE, 11262306a36Sopenharmony_ci .debounce_time = 200, 11362306a36Sopenharmony_ci .invert = 1, 11462306a36Sopenharmony_ci}; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci/* GPIO indexes defined by ACPI */ 11762306a36Sopenharmony_cienum { 11862306a36Sopenharmony_ci RT5677_GPIO_PLUG_DET = 0, 11962306a36Sopenharmony_ci RT5677_GPIO_MIC_PRESENT_L = 1, 12062306a36Sopenharmony_ci RT5677_GPIO_HOTWORD_DET_L = 2, 12162306a36Sopenharmony_ci RT5677_GPIO_DSP_INT = 3, 12262306a36Sopenharmony_ci RT5677_GPIO_HP_AMP_SHDN_L = 4, 12362306a36Sopenharmony_ci}; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistatic const struct acpi_gpio_params plug_det_gpio = { RT5677_GPIO_PLUG_DET, 0, false }; 12662306a36Sopenharmony_cistatic const struct acpi_gpio_params mic_present_gpio = { RT5677_GPIO_MIC_PRESENT_L, 0, false }; 12762306a36Sopenharmony_cistatic const struct acpi_gpio_params headphone_enable_gpio = { RT5677_GPIO_HP_AMP_SHDN_L, 0, false }; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic const struct acpi_gpio_mapping bdw_rt5677_gpios[] = { 13062306a36Sopenharmony_ci { "plug-det-gpios", &plug_det_gpio, 1 }, 13162306a36Sopenharmony_ci { "mic-present-gpios", &mic_present_gpio, 1 }, 13262306a36Sopenharmony_ci { "headphone-enable-gpios", &headphone_enable_gpio, 1 }, 13362306a36Sopenharmony_ci { NULL }, 13462306a36Sopenharmony_ci}; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd, 13762306a36Sopenharmony_ci struct snd_pcm_hw_params *params) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci struct snd_interval *rate = hw_param_interval(params, 14062306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_RATE); 14162306a36Sopenharmony_ci struct snd_interval *chan = hw_param_interval(params, 14262306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_CHANNELS); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci /* The ADSP will convert the FE rate to 48k, stereo */ 14562306a36Sopenharmony_ci rate->min = rate->max = 48000; 14662306a36Sopenharmony_ci chan->min = chan->max = 2; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci /* set SSP0 to 16 bit */ 14962306a36Sopenharmony_ci params_set_format(params, SNDRV_PCM_FORMAT_S16_LE); 15062306a36Sopenharmony_ci return 0; 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cistatic int bdw_rt5677_hw_params(struct snd_pcm_substream *substream, 15462306a36Sopenharmony_ci struct snd_pcm_hw_params *params) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 15762306a36Sopenharmony_ci struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 15862306a36Sopenharmony_ci int ret; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci ret = snd_soc_dai_set_sysclk(codec_dai, RT5677_SCLK_S_MCLK, 24576000, 16162306a36Sopenharmony_ci SND_SOC_CLOCK_IN); 16262306a36Sopenharmony_ci if (ret < 0) { 16362306a36Sopenharmony_ci dev_err(rtd->dev, "can't set codec sysclk configuration\n"); 16462306a36Sopenharmony_ci return ret; 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci return ret; 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_cistatic int bdw_rt5677_dsp_hw_params(struct snd_pcm_substream *substream, 17162306a36Sopenharmony_ci struct snd_pcm_hw_params *params) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 17462306a36Sopenharmony_ci struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 17562306a36Sopenharmony_ci int ret; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci ret = snd_soc_dai_set_sysclk(codec_dai, RT5677_SCLK_S_PLL1, 24576000, 17862306a36Sopenharmony_ci SND_SOC_CLOCK_IN); 17962306a36Sopenharmony_ci if (ret < 0) { 18062306a36Sopenharmony_ci dev_err(rtd->dev, "can't set codec sysclk configuration\n"); 18162306a36Sopenharmony_ci return ret; 18262306a36Sopenharmony_ci } 18362306a36Sopenharmony_ci ret = snd_soc_dai_set_pll(codec_dai, 0, RT5677_PLL1_S_MCLK, 18462306a36Sopenharmony_ci 24000000, 24576000); 18562306a36Sopenharmony_ci if (ret < 0) { 18662306a36Sopenharmony_ci dev_err(rtd->dev, "can't set codec pll configuration\n"); 18762306a36Sopenharmony_ci return ret; 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci return 0; 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_cistatic const struct snd_soc_ops bdw_rt5677_ops = { 19462306a36Sopenharmony_ci .hw_params = bdw_rt5677_hw_params, 19562306a36Sopenharmony_ci}; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_cistatic const struct snd_soc_ops bdw_rt5677_dsp_ops = { 19862306a36Sopenharmony_ci .hw_params = bdw_rt5677_dsp_hw_params, 19962306a36Sopenharmony_ci}; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_cistatic const unsigned int channels[] = { 20262306a36Sopenharmony_ci 2, 20362306a36Sopenharmony_ci}; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cistatic const struct snd_pcm_hw_constraint_list constraints_channels = { 20662306a36Sopenharmony_ci .count = ARRAY_SIZE(channels), 20762306a36Sopenharmony_ci .list = channels, 20862306a36Sopenharmony_ci .mask = 0, 20962306a36Sopenharmony_ci}; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic int bdw_rt5677_fe_startup(struct snd_pcm_substream *substream) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci /* Board supports stereo configuration only */ 21662306a36Sopenharmony_ci runtime->hw.channels_max = 2; 21762306a36Sopenharmony_ci return snd_pcm_hw_constraint_list(runtime, 0, 21862306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_CHANNELS, 21962306a36Sopenharmony_ci &constraints_channels); 22062306a36Sopenharmony_ci} 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_cistatic const struct snd_soc_ops bdw_rt5677_fe_ops = { 22362306a36Sopenharmony_ci .startup = bdw_rt5677_fe_startup, 22462306a36Sopenharmony_ci}; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_cistatic int bdw_rt5677_init(struct snd_soc_pcm_runtime *rtd) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci struct bdw_rt5677_priv *bdw_rt5677 = 22962306a36Sopenharmony_ci snd_soc_card_get_drvdata(rtd->card); 23062306a36Sopenharmony_ci struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component; 23162306a36Sopenharmony_ci struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); 23262306a36Sopenharmony_ci int ret; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci ret = devm_acpi_dev_add_driver_gpios(component->dev, bdw_rt5677_gpios); 23562306a36Sopenharmony_ci if (ret) 23662306a36Sopenharmony_ci dev_warn(component->dev, "Failed to add driver gpios\n"); 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci /* Enable codec ASRC function for Stereo DAC/Stereo1 ADC/DMIC/I2S1. 23962306a36Sopenharmony_ci * The ASRC clock source is clk_i2s1_asrc. 24062306a36Sopenharmony_ci */ 24162306a36Sopenharmony_ci rt5677_sel_asrc_clk_src(component, RT5677_DA_STEREO_FILTER | 24262306a36Sopenharmony_ci RT5677_AD_STEREO1_FILTER | RT5677_I2S1_SOURCE, 24362306a36Sopenharmony_ci RT5677_CLK_SEL_I2S1_ASRC); 24462306a36Sopenharmony_ci /* Enable codec ASRC function for Mono ADC L. 24562306a36Sopenharmony_ci * The ASRC clock source is clk_sys2_asrc. 24662306a36Sopenharmony_ci */ 24762306a36Sopenharmony_ci rt5677_sel_asrc_clk_src(component, RT5677_AD_MONO_L_FILTER, 24862306a36Sopenharmony_ci RT5677_CLK_SEL_SYS2); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci /* Request rt5677 GPIO for headphone amp control */ 25162306a36Sopenharmony_ci bdw_rt5677->gpio_hp_en = gpiod_get(component->dev, "headphone-enable", 25262306a36Sopenharmony_ci GPIOD_OUT_LOW); 25362306a36Sopenharmony_ci if (IS_ERR(bdw_rt5677->gpio_hp_en)) { 25462306a36Sopenharmony_ci dev_err(component->dev, "Can't find HP_AMP_SHDN_L gpio\n"); 25562306a36Sopenharmony_ci return PTR_ERR(bdw_rt5677->gpio_hp_en); 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci /* Create and initialize headphone jack */ 25962306a36Sopenharmony_ci if (!snd_soc_card_jack_new_pins(rtd->card, "Headphone Jack", 26062306a36Sopenharmony_ci SND_JACK_HEADPHONE, &headphone_jack, 26162306a36Sopenharmony_ci &headphone_jack_pin, 1)) { 26262306a36Sopenharmony_ci headphone_jack_gpio.gpiod_dev = component->dev; 26362306a36Sopenharmony_ci if (snd_soc_jack_add_gpios(&headphone_jack, 1, 26462306a36Sopenharmony_ci &headphone_jack_gpio)) 26562306a36Sopenharmony_ci dev_err(component->dev, "Can't add headphone jack gpio\n"); 26662306a36Sopenharmony_ci } else { 26762306a36Sopenharmony_ci dev_err(component->dev, "Can't create headphone jack\n"); 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci /* Create and initialize mic jack */ 27162306a36Sopenharmony_ci if (!snd_soc_card_jack_new_pins(rtd->card, "Mic Jack", 27262306a36Sopenharmony_ci SND_JACK_MICROPHONE, &mic_jack, 27362306a36Sopenharmony_ci &mic_jack_pin, 1)) { 27462306a36Sopenharmony_ci mic_jack_gpio.gpiod_dev = component->dev; 27562306a36Sopenharmony_ci if (snd_soc_jack_add_gpios(&mic_jack, 1, &mic_jack_gpio)) 27662306a36Sopenharmony_ci dev_err(component->dev, "Can't add mic jack gpio\n"); 27762306a36Sopenharmony_ci } else { 27862306a36Sopenharmony_ci dev_err(component->dev, "Can't create mic jack\n"); 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci bdw_rt5677->component = component; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1"); 28362306a36Sopenharmony_ci return 0; 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic void bdw_rt5677_exit(struct snd_soc_pcm_runtime *rtd) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci struct bdw_rt5677_priv *bdw_rt5677 = 28962306a36Sopenharmony_ci snd_soc_card_get_drvdata(rtd->card); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci /* 29262306a36Sopenharmony_ci * The .exit() can be reached without going through the .init() 29362306a36Sopenharmony_ci * so explicitly test if the gpiod is valid 29462306a36Sopenharmony_ci */ 29562306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(bdw_rt5677->gpio_hp_en)) 29662306a36Sopenharmony_ci gpiod_put(bdw_rt5677->gpio_hp_en); 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci/* broadwell digital audio interface glue - connects codec <--> CPU */ 30062306a36Sopenharmony_ciSND_SOC_DAILINK_DEF(dummy, 30162306a36Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_DUMMY())); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ciSND_SOC_DAILINK_DEF(fe, 30462306a36Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CPU("System Pin"))); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ciSND_SOC_DAILINK_DEF(platform, 30762306a36Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_PLATFORM("haswell-pcm-audio"))); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ciSND_SOC_DAILINK_DEF(be, 31062306a36Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CODEC("i2c-RT5677CE:00", "rt5677-aif1"))); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ciSND_SOC_DAILINK_DEF(ssp0_port, 31362306a36Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CPU("ssp0-port"))); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci/* Wake on voice interface */ 31662306a36Sopenharmony_ciSND_SOC_DAILINK_DEFS(dsp, 31762306a36Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CPU("spi-RT5677AA:00")), 31862306a36Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CODEC("i2c-RT5677CE:00", "rt5677-dspbuffer")), 31962306a36Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_PLATFORM("spi-RT5677AA:00"))); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_cistatic struct snd_soc_dai_link bdw_rt5677_dais[] = { 32262306a36Sopenharmony_ci /* Front End DAI links */ 32362306a36Sopenharmony_ci { 32462306a36Sopenharmony_ci .name = "System PCM", 32562306a36Sopenharmony_ci .stream_name = "System Playback/Capture", 32662306a36Sopenharmony_ci .nonatomic = 1, 32762306a36Sopenharmony_ci .dynamic = 1, 32862306a36Sopenharmony_ci .trigger = { 32962306a36Sopenharmony_ci SND_SOC_DPCM_TRIGGER_POST, 33062306a36Sopenharmony_ci SND_SOC_DPCM_TRIGGER_POST 33162306a36Sopenharmony_ci }, 33262306a36Sopenharmony_ci .dpcm_capture = 1, 33362306a36Sopenharmony_ci .dpcm_playback = 1, 33462306a36Sopenharmony_ci .ops = &bdw_rt5677_fe_ops, 33562306a36Sopenharmony_ci SND_SOC_DAILINK_REG(fe, dummy, platform), 33662306a36Sopenharmony_ci }, 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci /* Non-DPCM links */ 33962306a36Sopenharmony_ci { 34062306a36Sopenharmony_ci .name = "Codec DSP", 34162306a36Sopenharmony_ci .stream_name = "Wake on Voice", 34262306a36Sopenharmony_ci .capture_only = 1, 34362306a36Sopenharmony_ci .ops = &bdw_rt5677_dsp_ops, 34462306a36Sopenharmony_ci SND_SOC_DAILINK_REG(dsp), 34562306a36Sopenharmony_ci }, 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci /* Back End DAI links */ 34862306a36Sopenharmony_ci { 34962306a36Sopenharmony_ci /* SSP0 - Codec */ 35062306a36Sopenharmony_ci .name = "Codec", 35162306a36Sopenharmony_ci .id = 0, 35262306a36Sopenharmony_ci .nonatomic = 1, 35362306a36Sopenharmony_ci .no_pcm = 1, 35462306a36Sopenharmony_ci .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | 35562306a36Sopenharmony_ci SND_SOC_DAIFMT_CBC_CFC, 35662306a36Sopenharmony_ci .ignore_pmdown_time = 1, 35762306a36Sopenharmony_ci .be_hw_params_fixup = broadwell_ssp0_fixup, 35862306a36Sopenharmony_ci .ops = &bdw_rt5677_ops, 35962306a36Sopenharmony_ci .dpcm_playback = 1, 36062306a36Sopenharmony_ci .dpcm_capture = 1, 36162306a36Sopenharmony_ci .init = bdw_rt5677_init, 36262306a36Sopenharmony_ci .exit = bdw_rt5677_exit, 36362306a36Sopenharmony_ci SND_SOC_DAILINK_REG(ssp0_port, be, platform), 36462306a36Sopenharmony_ci }, 36562306a36Sopenharmony_ci}; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_cistatic int bdw_rt5677_suspend_pre(struct snd_soc_card *card) 36862306a36Sopenharmony_ci{ 36962306a36Sopenharmony_ci struct bdw_rt5677_priv *bdw_rt5677 = snd_soc_card_get_drvdata(card); 37062306a36Sopenharmony_ci struct snd_soc_dapm_context *dapm; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci if (bdw_rt5677->component) { 37362306a36Sopenharmony_ci dapm = snd_soc_component_get_dapm(bdw_rt5677->component); 37462306a36Sopenharmony_ci snd_soc_dapm_disable_pin(dapm, "MICBIAS1"); 37562306a36Sopenharmony_ci } 37662306a36Sopenharmony_ci return 0; 37762306a36Sopenharmony_ci} 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_cistatic int bdw_rt5677_resume_post(struct snd_soc_card *card) 38062306a36Sopenharmony_ci{ 38162306a36Sopenharmony_ci struct bdw_rt5677_priv *bdw_rt5677 = snd_soc_card_get_drvdata(card); 38262306a36Sopenharmony_ci struct snd_soc_dapm_context *dapm; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci if (bdw_rt5677->component) { 38562306a36Sopenharmony_ci dapm = snd_soc_component_get_dapm(bdw_rt5677->component); 38662306a36Sopenharmony_ci snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1"); 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci return 0; 38962306a36Sopenharmony_ci} 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci/* use space before codec name to simplify card ID, and simplify driver name */ 39262306a36Sopenharmony_ci#define SOF_CARD_NAME "bdw rt5677" /* card name will be 'sof-bdw rt5677' */ 39362306a36Sopenharmony_ci#define SOF_DRIVER_NAME "SOF" 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci#define CARD_NAME "bdw-rt5677" 39662306a36Sopenharmony_ci#define DRIVER_NAME NULL /* card name will be used for driver name */ 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci/* ASoC machine driver for Broadwell DSP + RT5677 */ 39962306a36Sopenharmony_cistatic struct snd_soc_card bdw_rt5677_card = { 40062306a36Sopenharmony_ci .name = CARD_NAME, 40162306a36Sopenharmony_ci .driver_name = DRIVER_NAME, 40262306a36Sopenharmony_ci .owner = THIS_MODULE, 40362306a36Sopenharmony_ci .dai_link = bdw_rt5677_dais, 40462306a36Sopenharmony_ci .num_links = ARRAY_SIZE(bdw_rt5677_dais), 40562306a36Sopenharmony_ci .dapm_widgets = bdw_rt5677_widgets, 40662306a36Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(bdw_rt5677_widgets), 40762306a36Sopenharmony_ci .dapm_routes = bdw_rt5677_map, 40862306a36Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(bdw_rt5677_map), 40962306a36Sopenharmony_ci .controls = bdw_rt5677_controls, 41062306a36Sopenharmony_ci .num_controls = ARRAY_SIZE(bdw_rt5677_controls), 41162306a36Sopenharmony_ci .fully_routed = true, 41262306a36Sopenharmony_ci .suspend_pre = bdw_rt5677_suspend_pre, 41362306a36Sopenharmony_ci .resume_post = bdw_rt5677_resume_post, 41462306a36Sopenharmony_ci}; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_cistatic int bdw_rt5677_probe(struct platform_device *pdev) 41762306a36Sopenharmony_ci{ 41862306a36Sopenharmony_ci struct bdw_rt5677_priv *bdw_rt5677; 41962306a36Sopenharmony_ci struct snd_soc_acpi_mach *mach; 42062306a36Sopenharmony_ci int ret; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci bdw_rt5677_card.dev = &pdev->dev; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci /* Allocate driver private struct */ 42562306a36Sopenharmony_ci bdw_rt5677 = devm_kzalloc(&pdev->dev, sizeof(struct bdw_rt5677_priv), 42662306a36Sopenharmony_ci GFP_KERNEL); 42762306a36Sopenharmony_ci if (!bdw_rt5677) 42862306a36Sopenharmony_ci return -ENOMEM; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci /* override platform name, if required */ 43162306a36Sopenharmony_ci mach = pdev->dev.platform_data; 43262306a36Sopenharmony_ci ret = snd_soc_fixup_dai_links_platform_name(&bdw_rt5677_card, 43362306a36Sopenharmony_ci mach->mach_params.platform); 43462306a36Sopenharmony_ci if (ret) 43562306a36Sopenharmony_ci return ret; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci /* set card and driver name */ 43862306a36Sopenharmony_ci if (snd_soc_acpi_sof_parent(&pdev->dev)) { 43962306a36Sopenharmony_ci bdw_rt5677_card.name = SOF_CARD_NAME; 44062306a36Sopenharmony_ci bdw_rt5677_card.driver_name = SOF_DRIVER_NAME; 44162306a36Sopenharmony_ci } else { 44262306a36Sopenharmony_ci bdw_rt5677_card.name = CARD_NAME; 44362306a36Sopenharmony_ci bdw_rt5677_card.driver_name = DRIVER_NAME; 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci snd_soc_card_set_drvdata(&bdw_rt5677_card, bdw_rt5677); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci return devm_snd_soc_register_card(&pdev->dev, &bdw_rt5677_card); 44962306a36Sopenharmony_ci} 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_cistatic struct platform_driver bdw_rt5677_audio = { 45262306a36Sopenharmony_ci .probe = bdw_rt5677_probe, 45362306a36Sopenharmony_ci .driver = { 45462306a36Sopenharmony_ci .name = "bdw-rt5677", 45562306a36Sopenharmony_ci .pm = &snd_soc_pm_ops 45662306a36Sopenharmony_ci }, 45762306a36Sopenharmony_ci}; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_cimodule_platform_driver(bdw_rt5677_audio) 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci/* Module information */ 46262306a36Sopenharmony_ciMODULE_AUTHOR("Ben Zhang"); 46362306a36Sopenharmony_ciMODULE_DESCRIPTION("Intel Broadwell RT5677 machine driver"); 46462306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 46562306a36Sopenharmony_ciMODULE_ALIAS("platform:bdw-rt5677"); 466