462 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2//3// Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.4//5// ALSA SoC Machine driver for sc72806 7#include <dt-bindings/sound/qcom,lpass.h>8#include <dt-bindings/sound/qcom,q6afe.h>9#include <linux/input.h>10#include <linux/mod_devicetable.h>11#include <linux/module.h>12#include <linux/platform_device.h>13#include <sound/core.h>14#include <sound/jack.h>15#include <sound/pcm.h>16#include <sound/soc.h>17#include <sound/rt5682s.h>18#include <linux/soundwire/sdw.h>19#include <sound/pcm_params.h>20 21#include "../codecs/rt5682.h"22#include "../codecs/rt5682s.h"23#include "common.h"24#include "lpass.h"25#include "qdsp6/q6afe.h"26#include "sdw.h"27 28#define DEFAULT_MCLK_RATE 1920000029#define RT5682_PLL_FREQ (48000 * 512)30#define MI2S_BCLK_RATE 153600031 32struct sc7280_snd_data {33 struct snd_soc_card card;34 struct sdw_stream_runtime *sruntime[LPASS_MAX_PORTS];35 u32 pri_mi2s_clk_count;36 struct snd_soc_jack hs_jack;37 struct snd_soc_jack hdmi_jack;38 bool jack_setup;39 bool stream_prepared[LPASS_MAX_PORTS];40};41 42static void sc7280_jack_free(struct snd_jack *jack)43{44 struct snd_soc_component *component = jack->private_data;45 46 snd_soc_component_set_jack(component, NULL, NULL);47}48 49static struct snd_soc_jack_pin sc7280_jack_pins[] = {50 {51 .pin = "Headphone Jack",52 .mask = SND_JACK_HEADPHONE,53 },54 {55 .pin = "Headset Mic",56 .mask = SND_JACK_MICROPHONE,57 },58};59 60static int sc7280_headset_init(struct snd_soc_pcm_runtime *rtd)61{62 struct snd_soc_card *card = rtd->card;63 struct sc7280_snd_data *pdata = snd_soc_card_get_drvdata(card);64 struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);65 struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);66 struct snd_soc_component *component = codec_dai->component;67 struct snd_jack *jack;68 int rval, i;69 70 if (!pdata->jack_setup) {71 rval = snd_soc_card_jack_new_pins(card, "Headset Jack",72 SND_JACK_HEADSET | SND_JACK_LINEOUT |73 SND_JACK_MECHANICAL |74 SND_JACK_BTN_0 | SND_JACK_BTN_1 |75 SND_JACK_BTN_2 | SND_JACK_BTN_3 |76 SND_JACK_BTN_4 | SND_JACK_BTN_5,77 &pdata->hs_jack,78 sc7280_jack_pins,79 ARRAY_SIZE(sc7280_jack_pins));80 81 if (rval < 0) {82 dev_err(card->dev, "Unable to add Headset Jack\n");83 return rval;84 }85 86 jack = pdata->hs_jack.jack;87 88 snd_jack_set_key(jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);89 snd_jack_set_key(jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);90 snd_jack_set_key(jack, SND_JACK_BTN_2, KEY_VOLUMEUP);91 snd_jack_set_key(jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);92 93 jack->private_data = component;94 jack->private_free = sc7280_jack_free;95 pdata->jack_setup = true;96 }97 switch (cpu_dai->id) {98 case MI2S_PRIMARY:99 case LPASS_CDC_DMA_RX0:100 case LPASS_CDC_DMA_TX3:101 case TX_CODEC_DMA_TX_3:102 for_each_rtd_codec_dais(rtd, i, codec_dai) {103 rval = snd_soc_component_set_jack(component, &pdata->hs_jack, NULL);104 if (rval != 0 && rval != -ENOTSUPP) {105 dev_err(card->dev, "Failed to set jack: %d\n", rval);106 return rval;107 }108 }109 break;110 default:111 break;112 }113 114 return 0;115}116 117static int sc7280_hdmi_init(struct snd_soc_pcm_runtime *rtd)118{119 struct snd_soc_card *card = rtd->card;120 struct sc7280_snd_data *pdata = snd_soc_card_get_drvdata(card);121 struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);122 struct snd_soc_component *component = codec_dai->component;123 struct snd_jack *jack;124 int rval;125 126 rval = snd_soc_card_jack_new(card, "HDMI Jack", SND_JACK_LINEOUT,127 &pdata->hdmi_jack);128 129 if (rval < 0) {130 dev_err(card->dev, "Unable to add HDMI Jack\n");131 return rval;132 }133 134 jack = pdata->hdmi_jack.jack;135 jack->private_data = component;136 jack->private_free = sc7280_jack_free;137 138 return snd_soc_component_set_jack(component, &pdata->hdmi_jack, NULL);139}140 141static int sc7280_rt5682_init(struct snd_soc_pcm_runtime *rtd)142{143 struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);144 struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);145 struct snd_soc_card *card = rtd->card;146 struct sc7280_snd_data *data = snd_soc_card_get_drvdata(card);147 int ret;148 149 if (++data->pri_mi2s_clk_count == 1) {150 snd_soc_dai_set_sysclk(cpu_dai,151 LPASS_MCLK0,152 DEFAULT_MCLK_RATE,153 SNDRV_PCM_STREAM_PLAYBACK);154 }155 snd_soc_dai_set_fmt(codec_dai,156 SND_SOC_DAIFMT_CBC_CFC |157 SND_SOC_DAIFMT_NB_NF |158 SND_SOC_DAIFMT_I2S);159 160 ret = snd_soc_dai_set_pll(codec_dai, RT5682S_PLL2, RT5682S_PLL_S_MCLK,161 DEFAULT_MCLK_RATE, RT5682_PLL_FREQ);162 if (ret) {163 dev_err(rtd->dev, "can't set codec pll: %d\n", ret);164 return ret;165 }166 167 ret = snd_soc_dai_set_sysclk(codec_dai, RT5682S_SCLK_S_PLL2,168 RT5682_PLL_FREQ,169 SND_SOC_CLOCK_IN);170 171 if (ret) {172 dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n",173 ret);174 return ret;175 }176 177 return 0;178}179 180static int sc7280_init(struct snd_soc_pcm_runtime *rtd)181{182 struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);183 184 switch (cpu_dai->id) {185 case MI2S_PRIMARY:186 case LPASS_CDC_DMA_TX3:187 case TX_CODEC_DMA_TX_3:188 return sc7280_headset_init(rtd);189 case LPASS_CDC_DMA_RX0:190 case LPASS_CDC_DMA_VA_TX0:191 case MI2S_SECONDARY:192 case RX_CODEC_DMA_RX_0:193 case SECONDARY_MI2S_RX:194 case VA_CODEC_DMA_TX_0:195 return 0;196 case LPASS_DP_RX:197 return sc7280_hdmi_init(rtd);198 default:199 dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__, cpu_dai->id);200 }201 202 return -EINVAL;203}204 205static int sc7280_snd_hw_params(struct snd_pcm_substream *substream,206 struct snd_pcm_hw_params *params)207{208 struct snd_pcm_runtime *runtime = substream->runtime;209 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);210 struct snd_soc_dai *codec_dai;211 const struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);212 struct sc7280_snd_data *pdata = snd_soc_card_get_drvdata(rtd->card);213 struct sdw_stream_runtime *sruntime;214 int i;215 216 if (!rtd->dai_link->no_pcm) {217 snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_CHANNELS, 2, 2);218 snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_RATE, 48000, 48000);219 }220 221 switch (cpu_dai->id) {222 case LPASS_CDC_DMA_TX3:223 case LPASS_CDC_DMA_RX0:224 case RX_CODEC_DMA_RX_0:225 case SECONDARY_MI2S_RX:226 case TX_CODEC_DMA_TX_3:227 case VA_CODEC_DMA_TX_0:228 for_each_rtd_codec_dais(rtd, i, codec_dai) {229 sruntime = snd_soc_dai_get_stream(codec_dai, substream->stream);230 if (sruntime != ERR_PTR(-ENOTSUPP))231 pdata->sruntime[cpu_dai->id] = sruntime;232 }233 break;234 }235 236 return 0;237}238 239static int sc7280_snd_swr_prepare(struct snd_pcm_substream *substream)240{241 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);242 const struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);243 struct sc7280_snd_data *data = snd_soc_card_get_drvdata(rtd->card);244 struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];245 int ret;246 247 if (!sruntime)248 return 0;249 250 if (data->stream_prepared[cpu_dai->id]) {251 sdw_disable_stream(sruntime);252 sdw_deprepare_stream(sruntime);253 data->stream_prepared[cpu_dai->id] = false;254 }255 256 ret = sdw_prepare_stream(sruntime);257 if (ret)258 return ret;259 260 ret = sdw_enable_stream(sruntime);261 if (ret) {262 sdw_deprepare_stream(sruntime);263 return ret;264 }265 data->stream_prepared[cpu_dai->id] = true;266 267 return ret;268}269 270static int sc7280_snd_prepare(struct snd_pcm_substream *substream)271{272 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);273 const struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);274 275 switch (cpu_dai->id) {276 case LPASS_CDC_DMA_RX0:277 case LPASS_CDC_DMA_TX3:278 case RX_CODEC_DMA_RX_0:279 case TX_CODEC_DMA_TX_3:280 case VA_CODEC_DMA_TX_0:281 return sc7280_snd_swr_prepare(substream);282 default:283 break;284 }285 286 return 0;287}288 289static int sc7280_snd_hw_free(struct snd_pcm_substream *substream)290{291 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);292 struct sc7280_snd_data *data = snd_soc_card_get_drvdata(rtd->card);293 const struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);294 struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];295 296 switch (cpu_dai->id) {297 case LPASS_CDC_DMA_RX0:298 case LPASS_CDC_DMA_TX3:299 case RX_CODEC_DMA_RX_0:300 case TX_CODEC_DMA_TX_3:301 case VA_CODEC_DMA_TX_0:302 if (sruntime && data->stream_prepared[cpu_dai->id]) {303 sdw_disable_stream(sruntime);304 sdw_deprepare_stream(sruntime);305 data->stream_prepared[cpu_dai->id] = false;306 }307 break;308 default:309 break;310 }311 return 0;312}313 314static void sc7280_snd_shutdown(struct snd_pcm_substream *substream)315{316 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);317 struct snd_soc_card *card = rtd->card;318 struct sc7280_snd_data *data = snd_soc_card_get_drvdata(card);319 struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);320 struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];321 322 switch (cpu_dai->id) {323 case MI2S_PRIMARY:324 if (--data->pri_mi2s_clk_count == 0) {325 snd_soc_dai_set_sysclk(cpu_dai,326 LPASS_MCLK0,327 0,328 SNDRV_PCM_STREAM_PLAYBACK);329 }330 break;331 case SECONDARY_MI2S_RX:332 snd_soc_dai_set_sysclk(cpu_dai, Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT,333 0, SNDRV_PCM_STREAM_PLAYBACK);334 break;335 default:336 break;337 }338 339 data->sruntime[cpu_dai->id] = NULL;340 sdw_release_stream(sruntime);341}342 343static int sc7280_snd_startup(struct snd_pcm_substream *substream)344{345 unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS;346 unsigned int codec_dai_fmt = SND_SOC_DAIFMT_CBS_CFS;347 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);348 struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);349 struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);350 int ret = 0;351 352 switch (cpu_dai->id) {353 case MI2S_PRIMARY:354 ret = sc7280_rt5682_init(rtd);355 if (ret)356 return ret;357 break;358 case SECONDARY_MI2S_RX:359 codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S;360 361 snd_soc_dai_set_sysclk(cpu_dai, Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT,362 MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);363 364 snd_soc_dai_set_fmt(cpu_dai, fmt);365 snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);366 break;367 default:368 break;369 }370 371 return qcom_snd_sdw_startup(substream);372}373 374static const struct snd_soc_ops sc7280_ops = {375 .startup = sc7280_snd_startup,376 .hw_params = sc7280_snd_hw_params,377 .hw_free = sc7280_snd_hw_free,378 .prepare = sc7280_snd_prepare,379 .shutdown = sc7280_snd_shutdown,380};381 382static const struct snd_soc_dapm_widget sc7280_snd_widgets[] = {383 SND_SOC_DAPM_HP("Headphone Jack", NULL),384 SND_SOC_DAPM_MIC("Headset Mic", NULL),385};386 387static const struct snd_kcontrol_new sc7280_snd_controls[] = {388 SOC_DAPM_PIN_SWITCH("Headphone Jack"),389 SOC_DAPM_PIN_SWITCH("Headset Mic"),390};391 392static int sc7280_snd_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,393 struct snd_pcm_hw_params *params)394{395 struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);396 struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);397 struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);398 399 rate->min = rate->max = 48000;400 channels->min = channels->max = 2;401 snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);402 403 return 0;404}405 406static int sc7280_snd_platform_probe(struct platform_device *pdev)407{408 struct snd_soc_card *card;409 struct sc7280_snd_data *data;410 struct device *dev = &pdev->dev;411 struct snd_soc_dai_link *link;412 int ret, i;413 414 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);415 if (!data)416 return -ENOMEM;417 418 card = &data->card;419 snd_soc_card_set_drvdata(card, data);420 421 card->owner = THIS_MODULE;422 card->driver_name = "SC7280";423 card->dev = dev;424 425 card->dapm_widgets = sc7280_snd_widgets;426 card->num_dapm_widgets = ARRAY_SIZE(sc7280_snd_widgets);427 card->controls = sc7280_snd_controls;428 card->num_controls = ARRAY_SIZE(sc7280_snd_controls);429 430 ret = qcom_snd_parse_of(card);431 if (ret)432 return ret;433 434 for_each_card_prelinks(card, i, link) {435 link->init = sc7280_init;436 link->ops = &sc7280_ops;437 if (link->no_pcm == 1)438 link->be_hw_params_fixup = sc7280_snd_be_hw_params_fixup;439 }440 441 return devm_snd_soc_register_card(dev, card);442}443 444static const struct of_device_id sc7280_snd_device_id[] = {445 { .compatible = "google,sc7280-herobrine" },446 {}447};448MODULE_DEVICE_TABLE(of, sc7280_snd_device_id);449 450static struct platform_driver sc7280_snd_driver = {451 .probe = sc7280_snd_platform_probe,452 .driver = {453 .name = "msm-snd-sc7280",454 .of_match_table = sc7280_snd_device_id,455 .pm = &snd_soc_pm_ops,456 },457};458module_platform_driver(sc7280_snd_driver);459 460MODULE_DESCRIPTION("sc7280 ASoC Machine Driver");461MODULE_LICENSE("GPL");462