162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci// 362306a36Sopenharmony_ci// Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. 462306a36Sopenharmony_ci// 562306a36Sopenharmony_ci// ALSA SoC Machine driver for sc7280 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/input.h> 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <linux/of_device.h> 1062306a36Sopenharmony_ci#include <linux/platform_device.h> 1162306a36Sopenharmony_ci#include <sound/core.h> 1262306a36Sopenharmony_ci#include <sound/jack.h> 1362306a36Sopenharmony_ci#include <sound/pcm.h> 1462306a36Sopenharmony_ci#include <sound/soc.h> 1562306a36Sopenharmony_ci#include <sound/rt5682s.h> 1662306a36Sopenharmony_ci#include <linux/soundwire/sdw.h> 1762306a36Sopenharmony_ci#include <sound/pcm_params.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include "../codecs/rt5682.h" 2062306a36Sopenharmony_ci#include "../codecs/rt5682s.h" 2162306a36Sopenharmony_ci#include "common.h" 2262306a36Sopenharmony_ci#include "lpass.h" 2362306a36Sopenharmony_ci#include "qdsp6/q6afe.h" 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define DEFAULT_MCLK_RATE 19200000 2662306a36Sopenharmony_ci#define RT5682_PLL_FREQ (48000 * 512) 2762306a36Sopenharmony_ci#define MI2S_BCLK_RATE 1536000 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistruct sc7280_snd_data { 3062306a36Sopenharmony_ci struct snd_soc_card card; 3162306a36Sopenharmony_ci struct sdw_stream_runtime *sruntime[LPASS_MAX_PORTS]; 3262306a36Sopenharmony_ci u32 pri_mi2s_clk_count; 3362306a36Sopenharmony_ci struct snd_soc_jack hs_jack; 3462306a36Sopenharmony_ci struct snd_soc_jack hdmi_jack; 3562306a36Sopenharmony_ci bool jack_setup; 3662306a36Sopenharmony_ci bool stream_prepared[LPASS_MAX_PORTS]; 3762306a36Sopenharmony_ci}; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic void sc7280_jack_free(struct snd_jack *jack) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci struct snd_soc_component *component = jack->private_data; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci snd_soc_component_set_jack(component, NULL, NULL); 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic struct snd_soc_jack_pin sc7280_jack_pins[] = { 4762306a36Sopenharmony_ci { 4862306a36Sopenharmony_ci .pin = "Headphone Jack", 4962306a36Sopenharmony_ci .mask = SND_JACK_HEADPHONE, 5062306a36Sopenharmony_ci }, 5162306a36Sopenharmony_ci { 5262306a36Sopenharmony_ci .pin = "Headset Mic", 5362306a36Sopenharmony_ci .mask = SND_JACK_MICROPHONE, 5462306a36Sopenharmony_ci }, 5562306a36Sopenharmony_ci}; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistatic int sc7280_headset_init(struct snd_soc_pcm_runtime *rtd) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci struct snd_soc_card *card = rtd->card; 6062306a36Sopenharmony_ci struct sc7280_snd_data *pdata = snd_soc_card_get_drvdata(card); 6162306a36Sopenharmony_ci struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); 6262306a36Sopenharmony_ci struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); 6362306a36Sopenharmony_ci struct snd_soc_component *component = codec_dai->component; 6462306a36Sopenharmony_ci struct snd_jack *jack; 6562306a36Sopenharmony_ci int rval, i; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci if (!pdata->jack_setup) { 6862306a36Sopenharmony_ci rval = snd_soc_card_jack_new_pins(card, "Headset Jack", 6962306a36Sopenharmony_ci SND_JACK_HEADSET | SND_JACK_LINEOUT | 7062306a36Sopenharmony_ci SND_JACK_MECHANICAL | 7162306a36Sopenharmony_ci SND_JACK_BTN_0 | SND_JACK_BTN_1 | 7262306a36Sopenharmony_ci SND_JACK_BTN_2 | SND_JACK_BTN_3 | 7362306a36Sopenharmony_ci SND_JACK_BTN_4 | SND_JACK_BTN_5, 7462306a36Sopenharmony_ci &pdata->hs_jack, 7562306a36Sopenharmony_ci sc7280_jack_pins, 7662306a36Sopenharmony_ci ARRAY_SIZE(sc7280_jack_pins)); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci if (rval < 0) { 7962306a36Sopenharmony_ci dev_err(card->dev, "Unable to add Headset Jack\n"); 8062306a36Sopenharmony_ci return rval; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci jack = pdata->hs_jack.jack; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci snd_jack_set_key(jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); 8662306a36Sopenharmony_ci snd_jack_set_key(jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); 8762306a36Sopenharmony_ci snd_jack_set_key(jack, SND_JACK_BTN_2, KEY_VOLUMEUP); 8862306a36Sopenharmony_ci snd_jack_set_key(jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci jack->private_data = component; 9162306a36Sopenharmony_ci jack->private_free = sc7280_jack_free; 9262306a36Sopenharmony_ci pdata->jack_setup = true; 9362306a36Sopenharmony_ci } 9462306a36Sopenharmony_ci switch (cpu_dai->id) { 9562306a36Sopenharmony_ci case MI2S_PRIMARY: 9662306a36Sopenharmony_ci case LPASS_CDC_DMA_RX0: 9762306a36Sopenharmony_ci case LPASS_CDC_DMA_TX3: 9862306a36Sopenharmony_ci case TX_CODEC_DMA_TX_3: 9962306a36Sopenharmony_ci for_each_rtd_codec_dais(rtd, i, codec_dai) { 10062306a36Sopenharmony_ci rval = snd_soc_component_set_jack(component, &pdata->hs_jack, NULL); 10162306a36Sopenharmony_ci if (rval != 0 && rval != -ENOTSUPP) { 10262306a36Sopenharmony_ci dev_err(card->dev, "Failed to set jack: %d\n", rval); 10362306a36Sopenharmony_ci return rval; 10462306a36Sopenharmony_ci } 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ci break; 10762306a36Sopenharmony_ci default: 10862306a36Sopenharmony_ci break; 10962306a36Sopenharmony_ci } 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci return 0; 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic int sc7280_hdmi_init(struct snd_soc_pcm_runtime *rtd) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci struct snd_soc_card *card = rtd->card; 11762306a36Sopenharmony_ci struct sc7280_snd_data *pdata = snd_soc_card_get_drvdata(card); 11862306a36Sopenharmony_ci struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); 11962306a36Sopenharmony_ci struct snd_soc_component *component = codec_dai->component; 12062306a36Sopenharmony_ci struct snd_jack *jack; 12162306a36Sopenharmony_ci int rval; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci rval = snd_soc_card_jack_new(card, "HDMI Jack", SND_JACK_LINEOUT, 12462306a36Sopenharmony_ci &pdata->hdmi_jack); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci if (rval < 0) { 12762306a36Sopenharmony_ci dev_err(card->dev, "Unable to add HDMI Jack\n"); 12862306a36Sopenharmony_ci return rval; 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci jack = pdata->hdmi_jack.jack; 13262306a36Sopenharmony_ci jack->private_data = component; 13362306a36Sopenharmony_ci jack->private_free = sc7280_jack_free; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci return snd_soc_component_set_jack(component, &pdata->hdmi_jack, NULL); 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic int sc7280_rt5682_init(struct snd_soc_pcm_runtime *rtd) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); 14162306a36Sopenharmony_ci struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); 14262306a36Sopenharmony_ci struct snd_soc_card *card = rtd->card; 14362306a36Sopenharmony_ci struct sc7280_snd_data *data = snd_soc_card_get_drvdata(card); 14462306a36Sopenharmony_ci int ret; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci if (++data->pri_mi2s_clk_count == 1) { 14762306a36Sopenharmony_ci snd_soc_dai_set_sysclk(cpu_dai, 14862306a36Sopenharmony_ci LPASS_MCLK0, 14962306a36Sopenharmony_ci DEFAULT_MCLK_RATE, 15062306a36Sopenharmony_ci SNDRV_PCM_STREAM_PLAYBACK); 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci snd_soc_dai_set_fmt(codec_dai, 15362306a36Sopenharmony_ci SND_SOC_DAIFMT_CBC_CFC | 15462306a36Sopenharmony_ci SND_SOC_DAIFMT_NB_NF | 15562306a36Sopenharmony_ci SND_SOC_DAIFMT_I2S); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci ret = snd_soc_dai_set_pll(codec_dai, RT5682S_PLL2, RT5682S_PLL_S_MCLK, 15862306a36Sopenharmony_ci DEFAULT_MCLK_RATE, RT5682_PLL_FREQ); 15962306a36Sopenharmony_ci if (ret) { 16062306a36Sopenharmony_ci dev_err(rtd->dev, "can't set codec pll: %d\n", ret); 16162306a36Sopenharmony_ci return ret; 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci ret = snd_soc_dai_set_sysclk(codec_dai, RT5682S_SCLK_S_PLL2, 16562306a36Sopenharmony_ci RT5682_PLL_FREQ, 16662306a36Sopenharmony_ci SND_SOC_CLOCK_IN); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci if (ret) { 16962306a36Sopenharmony_ci dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", 17062306a36Sopenharmony_ci ret); 17162306a36Sopenharmony_ci return ret; 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci return 0; 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cistatic int sc7280_init(struct snd_soc_pcm_runtime *rtd) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci switch (cpu_dai->id) { 18262306a36Sopenharmony_ci case MI2S_PRIMARY: 18362306a36Sopenharmony_ci case LPASS_CDC_DMA_TX3: 18462306a36Sopenharmony_ci case TX_CODEC_DMA_TX_3: 18562306a36Sopenharmony_ci return sc7280_headset_init(rtd); 18662306a36Sopenharmony_ci case LPASS_CDC_DMA_RX0: 18762306a36Sopenharmony_ci case LPASS_CDC_DMA_VA_TX0: 18862306a36Sopenharmony_ci case MI2S_SECONDARY: 18962306a36Sopenharmony_ci case RX_CODEC_DMA_RX_0: 19062306a36Sopenharmony_ci case SECONDARY_MI2S_RX: 19162306a36Sopenharmony_ci case VA_CODEC_DMA_TX_0: 19262306a36Sopenharmony_ci return 0; 19362306a36Sopenharmony_ci case LPASS_DP_RX: 19462306a36Sopenharmony_ci return sc7280_hdmi_init(rtd); 19562306a36Sopenharmony_ci default: 19662306a36Sopenharmony_ci dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__, cpu_dai->id); 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci return -EINVAL; 20062306a36Sopenharmony_ci} 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_cistatic int sc7280_snd_hw_params(struct snd_pcm_substream *substream, 20362306a36Sopenharmony_ci struct snd_pcm_hw_params *params) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 20662306a36Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = substream->private_data; 20762306a36Sopenharmony_ci struct snd_soc_dai *codec_dai; 20862306a36Sopenharmony_ci const struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); 20962306a36Sopenharmony_ci struct sc7280_snd_data *pdata = snd_soc_card_get_drvdata(rtd->card); 21062306a36Sopenharmony_ci struct sdw_stream_runtime *sruntime; 21162306a36Sopenharmony_ci int i; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci if (!rtd->dai_link->no_pcm) { 21462306a36Sopenharmony_ci snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_CHANNELS, 2, 2); 21562306a36Sopenharmony_ci snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_RATE, 48000, 48000); 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci switch (cpu_dai->id) { 21962306a36Sopenharmony_ci case LPASS_CDC_DMA_TX3: 22062306a36Sopenharmony_ci case LPASS_CDC_DMA_RX0: 22162306a36Sopenharmony_ci case RX_CODEC_DMA_RX_0: 22262306a36Sopenharmony_ci case SECONDARY_MI2S_RX: 22362306a36Sopenharmony_ci case TX_CODEC_DMA_TX_3: 22462306a36Sopenharmony_ci case VA_CODEC_DMA_TX_0: 22562306a36Sopenharmony_ci for_each_rtd_codec_dais(rtd, i, codec_dai) { 22662306a36Sopenharmony_ci sruntime = snd_soc_dai_get_stream(codec_dai, substream->stream); 22762306a36Sopenharmony_ci if (sruntime != ERR_PTR(-ENOTSUPP)) 22862306a36Sopenharmony_ci pdata->sruntime[cpu_dai->id] = sruntime; 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci break; 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci return 0; 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic int sc7280_snd_swr_prepare(struct snd_pcm_substream *substream) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = substream->private_data; 23962306a36Sopenharmony_ci const struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); 24062306a36Sopenharmony_ci struct sc7280_snd_data *data = snd_soc_card_get_drvdata(rtd->card); 24162306a36Sopenharmony_ci struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; 24262306a36Sopenharmony_ci int ret; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci if (!sruntime) 24562306a36Sopenharmony_ci return 0; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci if (data->stream_prepared[cpu_dai->id]) { 24862306a36Sopenharmony_ci sdw_disable_stream(sruntime); 24962306a36Sopenharmony_ci sdw_deprepare_stream(sruntime); 25062306a36Sopenharmony_ci data->stream_prepared[cpu_dai->id] = false; 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci ret = sdw_prepare_stream(sruntime); 25462306a36Sopenharmony_ci if (ret) 25562306a36Sopenharmony_ci return ret; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci ret = sdw_enable_stream(sruntime); 25862306a36Sopenharmony_ci if (ret) { 25962306a36Sopenharmony_ci sdw_deprepare_stream(sruntime); 26062306a36Sopenharmony_ci return ret; 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci data->stream_prepared[cpu_dai->id] = true; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci return ret; 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_cistatic int sc7280_snd_prepare(struct snd_pcm_substream *substream) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = substream->private_data; 27062306a36Sopenharmony_ci const struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci switch (cpu_dai->id) { 27362306a36Sopenharmony_ci case LPASS_CDC_DMA_RX0: 27462306a36Sopenharmony_ci case LPASS_CDC_DMA_TX3: 27562306a36Sopenharmony_ci case RX_CODEC_DMA_RX_0: 27662306a36Sopenharmony_ci case TX_CODEC_DMA_TX_3: 27762306a36Sopenharmony_ci case VA_CODEC_DMA_TX_0: 27862306a36Sopenharmony_ci return sc7280_snd_swr_prepare(substream); 27962306a36Sopenharmony_ci default: 28062306a36Sopenharmony_ci break; 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci return 0; 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic int sc7280_snd_hw_free(struct snd_pcm_substream *substream) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = substream->private_data; 28962306a36Sopenharmony_ci struct sc7280_snd_data *data = snd_soc_card_get_drvdata(rtd->card); 29062306a36Sopenharmony_ci const struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); 29162306a36Sopenharmony_ci struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id]; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci switch (cpu_dai->id) { 29462306a36Sopenharmony_ci case LPASS_CDC_DMA_RX0: 29562306a36Sopenharmony_ci case LPASS_CDC_DMA_TX3: 29662306a36Sopenharmony_ci case RX_CODEC_DMA_RX_0: 29762306a36Sopenharmony_ci case TX_CODEC_DMA_TX_3: 29862306a36Sopenharmony_ci case VA_CODEC_DMA_TX_0: 29962306a36Sopenharmony_ci if (sruntime && data->stream_prepared[cpu_dai->id]) { 30062306a36Sopenharmony_ci sdw_disable_stream(sruntime); 30162306a36Sopenharmony_ci sdw_deprepare_stream(sruntime); 30262306a36Sopenharmony_ci data->stream_prepared[cpu_dai->id] = false; 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci break; 30562306a36Sopenharmony_ci default: 30662306a36Sopenharmony_ci break; 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci return 0; 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_cistatic void sc7280_snd_shutdown(struct snd_pcm_substream *substream) 31262306a36Sopenharmony_ci{ 31362306a36Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = substream->private_data; 31462306a36Sopenharmony_ci struct snd_soc_card *card = rtd->card; 31562306a36Sopenharmony_ci struct sc7280_snd_data *data = snd_soc_card_get_drvdata(card); 31662306a36Sopenharmony_ci struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci switch (cpu_dai->id) { 31962306a36Sopenharmony_ci case MI2S_PRIMARY: 32062306a36Sopenharmony_ci if (--data->pri_mi2s_clk_count == 0) { 32162306a36Sopenharmony_ci snd_soc_dai_set_sysclk(cpu_dai, 32262306a36Sopenharmony_ci LPASS_MCLK0, 32362306a36Sopenharmony_ci 0, 32462306a36Sopenharmony_ci SNDRV_PCM_STREAM_PLAYBACK); 32562306a36Sopenharmony_ci } 32662306a36Sopenharmony_ci break; 32762306a36Sopenharmony_ci case SECONDARY_MI2S_RX: 32862306a36Sopenharmony_ci snd_soc_dai_set_sysclk(cpu_dai, Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT, 32962306a36Sopenharmony_ci 0, SNDRV_PCM_STREAM_PLAYBACK); 33062306a36Sopenharmony_ci break; 33162306a36Sopenharmony_ci default: 33262306a36Sopenharmony_ci break; 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_cistatic int sc7280_snd_startup(struct snd_pcm_substream *substream) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS; 33962306a36Sopenharmony_ci unsigned int codec_dai_fmt = SND_SOC_DAIFMT_CBS_CFS; 34062306a36Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = substream->private_data; 34162306a36Sopenharmony_ci struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); 34262306a36Sopenharmony_ci struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); 34362306a36Sopenharmony_ci int ret = 0; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci switch (cpu_dai->id) { 34662306a36Sopenharmony_ci case MI2S_PRIMARY: 34762306a36Sopenharmony_ci ret = sc7280_rt5682_init(rtd); 34862306a36Sopenharmony_ci break; 34962306a36Sopenharmony_ci case SECONDARY_MI2S_RX: 35062306a36Sopenharmony_ci codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci snd_soc_dai_set_sysclk(cpu_dai, Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT, 35362306a36Sopenharmony_ci MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci snd_soc_dai_set_fmt(cpu_dai, fmt); 35662306a36Sopenharmony_ci snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt); 35762306a36Sopenharmony_ci break; 35862306a36Sopenharmony_ci default: 35962306a36Sopenharmony_ci break; 36062306a36Sopenharmony_ci } 36162306a36Sopenharmony_ci return ret; 36262306a36Sopenharmony_ci} 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_cistatic const struct snd_soc_ops sc7280_ops = { 36562306a36Sopenharmony_ci .startup = sc7280_snd_startup, 36662306a36Sopenharmony_ci .hw_params = sc7280_snd_hw_params, 36762306a36Sopenharmony_ci .hw_free = sc7280_snd_hw_free, 36862306a36Sopenharmony_ci .prepare = sc7280_snd_prepare, 36962306a36Sopenharmony_ci .shutdown = sc7280_snd_shutdown, 37062306a36Sopenharmony_ci}; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_cistatic const struct snd_soc_dapm_widget sc7280_snd_widgets[] = { 37362306a36Sopenharmony_ci SND_SOC_DAPM_HP("Headphone Jack", NULL), 37462306a36Sopenharmony_ci SND_SOC_DAPM_MIC("Headset Mic", NULL), 37562306a36Sopenharmony_ci}; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_cistatic const struct snd_kcontrol_new sc7280_snd_controls[] = { 37862306a36Sopenharmony_ci SOC_DAPM_PIN_SWITCH("Headphone Jack"), 37962306a36Sopenharmony_ci SOC_DAPM_PIN_SWITCH("Headset Mic"), 38062306a36Sopenharmony_ci}; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_cistatic int sc7280_snd_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, 38362306a36Sopenharmony_ci struct snd_pcm_hw_params *params) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); 38662306a36Sopenharmony_ci struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); 38762306a36Sopenharmony_ci struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci rate->min = rate->max = 48000; 39062306a36Sopenharmony_ci channels->min = channels->max = 2; 39162306a36Sopenharmony_ci snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci return 0; 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_cistatic int sc7280_snd_platform_probe(struct platform_device *pdev) 39762306a36Sopenharmony_ci{ 39862306a36Sopenharmony_ci struct snd_soc_card *card; 39962306a36Sopenharmony_ci struct sc7280_snd_data *data; 40062306a36Sopenharmony_ci struct device *dev = &pdev->dev; 40162306a36Sopenharmony_ci struct snd_soc_dai_link *link; 40262306a36Sopenharmony_ci int ret, i; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 40562306a36Sopenharmony_ci if (!data) 40662306a36Sopenharmony_ci return -ENOMEM; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci card = &data->card; 40962306a36Sopenharmony_ci snd_soc_card_set_drvdata(card, data); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci card->owner = THIS_MODULE; 41262306a36Sopenharmony_ci card->driver_name = "SC7280"; 41362306a36Sopenharmony_ci card->dev = dev; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci card->dapm_widgets = sc7280_snd_widgets; 41662306a36Sopenharmony_ci card->num_dapm_widgets = ARRAY_SIZE(sc7280_snd_widgets); 41762306a36Sopenharmony_ci card->controls = sc7280_snd_controls; 41862306a36Sopenharmony_ci card->num_controls = ARRAY_SIZE(sc7280_snd_controls); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci ret = qcom_snd_parse_of(card); 42162306a36Sopenharmony_ci if (ret) 42262306a36Sopenharmony_ci return ret; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci for_each_card_prelinks(card, i, link) { 42562306a36Sopenharmony_ci link->init = sc7280_init; 42662306a36Sopenharmony_ci link->ops = &sc7280_ops; 42762306a36Sopenharmony_ci if (link->no_pcm == 1) 42862306a36Sopenharmony_ci link->be_hw_params_fixup = sc7280_snd_be_hw_params_fixup; 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci return devm_snd_soc_register_card(dev, card); 43262306a36Sopenharmony_ci} 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_cistatic const struct of_device_id sc7280_snd_device_id[] = { 43562306a36Sopenharmony_ci { .compatible = "google,sc7280-herobrine" }, 43662306a36Sopenharmony_ci {} 43762306a36Sopenharmony_ci}; 43862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, sc7280_snd_device_id); 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_cistatic struct platform_driver sc7280_snd_driver = { 44162306a36Sopenharmony_ci .probe = sc7280_snd_platform_probe, 44262306a36Sopenharmony_ci .driver = { 44362306a36Sopenharmony_ci .name = "msm-snd-sc7280", 44462306a36Sopenharmony_ci .of_match_table = sc7280_snd_device_id, 44562306a36Sopenharmony_ci .pm = &snd_soc_pm_ops, 44662306a36Sopenharmony_ci }, 44762306a36Sopenharmony_ci}; 44862306a36Sopenharmony_cimodule_platform_driver(sc7280_snd_driver); 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ciMODULE_DESCRIPTION("sc7280 ASoC Machine Driver"); 45162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 452