diff --git a/sound/soc/qcom/sc8280xp.c b/sound/soc/qcom/sc8280xp.c index 98b15a527e37..2ecba74d736e 100644 --- a/sound/soc/qcom/sc8280xp.c +++ b/sound/soc/qcom/sc8280xp.c @@ -12,17 +12,78 @@ #include #include #include "qdsp6/q6afe.h" +#include "qdsp6/q6apm.h" +#include "qdsp6/q6prm.h" #include "common.h" #include "sdw.h" +#define I2S_MCLKFS 256 + +#define I2S_MCLK_RATE(rate) \ + ((rate) * (I2S_MCLKFS)) +#define I2S_BIT_RATE(rate, channels, format) \ + ((rate) * (channels) * (format)) + +static struct snd_soc_dapm_widget sc8280xp_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Mic Jack", NULL), + SND_SOC_DAPM_SPK("DP0 Jack", NULL), + SND_SOC_DAPM_SPK("DP1 Jack", NULL), + SND_SOC_DAPM_SPK("DP2 Jack", NULL), + SND_SOC_DAPM_SPK("DP3 Jack", NULL), + SND_SOC_DAPM_SPK("DP4 Jack", NULL), + SND_SOC_DAPM_SPK("DP5 Jack", NULL), + SND_SOC_DAPM_SPK("DP6 Jack", NULL), + SND_SOC_DAPM_SPK("DP7 Jack", NULL), +}; + +struct snd_soc_common { + const char *driver_name; + const struct snd_soc_dapm_widget *dapm_widgets; + int num_dapm_widgets; + const struct snd_soc_dapm_route *dapm_routes; + int num_dapm_routes; + const struct snd_kcontrol_new *controls; + int num_controls; + unsigned int codec_dai_fmt; + bool codec_sysclk_set; + bool mi2s_mclk_enable; + bool mi2s_bclk_enable; + bool wcd_jack; +}; + struct sc8280xp_snd_data { bool stream_prepared[AFE_PORT_MAX]; struct snd_soc_card *card; struct snd_soc_jack jack; struct snd_soc_jack dp_jack[8]; + const struct snd_soc_common *snd_soc_common_priv; bool jack_setup; }; +static inline int sc8280xp_get_mclk_freq(struct snd_pcm_hw_params *params) +{ + int rate = params_rate(params); + + switch (rate) { + case 11025: + case 44100: + case 88200: + return I2S_MCLK_RATE(44100); + default: + break; + } + + return I2S_MCLK_RATE(rate); +} + +static inline int sc8280xp_get_bclk_freq(struct snd_pcm_hw_params *params) +{ + return I2S_BIT_RATE(params_rate(params), + params_channels(params), + snd_pcm_format_width(params_format(params))); +} + static int sc8280xp_snd_init(struct snd_soc_pcm_runtime *rtd) { struct sc8280xp_snd_data *data = snd_soc_card_get_drvdata(rtd->card); @@ -32,10 +93,6 @@ static int sc8280xp_snd_init(struct snd_soc_pcm_runtime *rtd) int dp_pcm_id = 0; switch (cpu_dai->id) { - case PRIMARY_MI2S_RX...QUATERNARY_MI2S_TX: - case QUINARY_MI2S_RX...QUINARY_MI2S_TX: - snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_BP_FP); - break; case WSA_CODEC_DMA_RX_0: case WSA_CODEC_DMA_RX_1: /* @@ -64,7 +121,10 @@ static int sc8280xp_snd_init(struct snd_soc_pcm_runtime *rtd) if (dp_jack) return qcom_snd_dp_jack_setup(rtd, dp_jack, dp_pcm_id); - return qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup); + if (data->snd_soc_common_priv->wcd_jack) + return qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup); + + return 0; } static int sc8280xp_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, @@ -96,6 +156,63 @@ static int sc8280xp_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } +static int sc8280xp_snd_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + struct sc8280xp_snd_data *data = snd_soc_card_get_drvdata(rtd->card); + int mclk_freq = sc8280xp_get_mclk_freq(params); + int bclk_freq = sc8280xp_get_bclk_freq(params); + int ret; + + switch (cpu_dai->id) { + case PRIMARY_MI2S_RX ... QUATERNARY_MI2S_TX: + case QUINARY_MI2S_RX ... QUINARY_MI2S_TX: + case SENARY_MI2S_RX ... SENARY_MI2S_TX: + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_BP_FP); + if (ret && ret != -ENOTSUPP) + return ret; + + if (data->snd_soc_common_priv->codec_dai_fmt) { + ret = snd_soc_dai_set_fmt(codec_dai, + data->snd_soc_common_priv->codec_dai_fmt); + if (ret && ret != -ENOTSUPP) + return ret; + } + + if (data->snd_soc_common_priv->mi2s_mclk_enable) { + ret = snd_soc_dai_set_sysclk(cpu_dai, + LPAIF_MI2S_MCLK, mclk_freq, + SND_SOC_CLOCK_OUT); + if (ret) + return ret; + } + + if (data->snd_soc_common_priv->mi2s_bclk_enable) { + ret = snd_soc_dai_set_sysclk(cpu_dai, + LPAIF_MI2S_BCLK, bclk_freq, + SND_SOC_CLOCK_OUT); + if (ret) + return ret; + } + + if (data->snd_soc_common_priv->codec_sysclk_set) { + ret = snd_soc_dai_set_sysclk(codec_dai, + 0, mclk_freq, + SND_SOC_CLOCK_IN); + if (ret) + return ret; + } + break; + default: + break; + } + + return 0; +} + static int sc8280xp_snd_prepare(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); @@ -117,6 +234,7 @@ static int sc8280xp_snd_hw_free(struct snd_pcm_substream *substream) static const struct snd_soc_ops sc8280xp_be_ops = { .startup = qcom_snd_sdw_startup, .shutdown = qcom_snd_sdw_shutdown, + .hw_params = sc8280xp_snd_hw_params, .hw_free = sc8280xp_snd_hw_free, .prepare = sc8280xp_snd_prepare, }; @@ -145,38 +263,131 @@ static int sc8280xp_platform_probe(struct platform_device *pdev) card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); if (!card) return -ENOMEM; - card->owner = THIS_MODULE; + /* Allocate the private data */ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; + data->snd_soc_common_priv = of_device_get_match_data(dev); + if (!data->snd_soc_common_priv) + return -ENODEV; + + card->owner = THIS_MODULE; card->dev = dev; dev_set_drvdata(dev, card); snd_soc_card_set_drvdata(card, data); + card->dapm_widgets = data->snd_soc_common_priv->dapm_widgets; + card->num_dapm_widgets = data->snd_soc_common_priv->num_dapm_widgets; + card->dapm_routes = data->snd_soc_common_priv->dapm_routes; + card->num_dapm_routes = data->snd_soc_common_priv->num_dapm_routes; + card->controls = data->snd_soc_common_priv->controls; + card->num_controls = data->snd_soc_common_priv->num_controls; + ret = qcom_snd_parse_of(card); if (ret) return ret; - card->driver_name = of_device_get_match_data(dev); + card->driver_name = data->snd_soc_common_priv->driver_name; sc8280xp_add_be_ops(card); return devm_snd_soc_register_card(dev, card); } +static const struct snd_soc_common eliza_priv_data = { + .driver_name = "eliza", + .dapm_widgets = sc8280xp_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), + .wcd_jack = true, +}; + +static const struct snd_soc_common kaanapali_priv_data = { + .driver_name = "kaanapali", + .dapm_widgets = sc8280xp_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), + .wcd_jack = true, +}; + +static const struct snd_soc_common qcs9100_priv_data = { + .driver_name = "sa8775p", + .dapm_widgets = sc8280xp_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), +}; + +static const struct snd_soc_common qcs615_priv_data = { + .driver_name = "qcs615", + .dapm_widgets = sc8280xp_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), +}; + +static const struct snd_soc_common qcm6490_priv_data = { + .driver_name = "qcm6490", + .dapm_widgets = sc8280xp_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), + .wcd_jack = true, +}; + +static const struct snd_soc_common qcs6490_priv_data = { + .driver_name = "qcs6490", + .dapm_widgets = sc8280xp_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), + .wcd_jack = true, +}; + +static const struct snd_soc_common qcs8275_priv_data = { + .driver_name = "qcs8300", + .dapm_widgets = sc8280xp_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), +}; + +static const struct snd_soc_common sc8280xp_priv_data = { + .driver_name = "sc8280xp", + .dapm_widgets = sc8280xp_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), + .wcd_jack = true, +}; + +static const struct snd_soc_common sm8450_priv_data = { + .driver_name = "sm8450", + .dapm_widgets = sc8280xp_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), + .wcd_jack = true, +}; + +static const struct snd_soc_common sm8550_priv_data = { + .driver_name = "sm8550", + .dapm_widgets = sc8280xp_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), + .wcd_jack = true, +}; + +static const struct snd_soc_common sm8650_priv_data = { + .driver_name = "sm8650", + .dapm_widgets = sc8280xp_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), + .wcd_jack = true, +}; + +static const struct snd_soc_common sm8750_priv_data = { + .driver_name = "sm8750", + .dapm_widgets = sc8280xp_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets), + .wcd_jack = true, +}; + static const struct of_device_id snd_sc8280xp_dt_match[] = { - {.compatible = "qcom,eliza-sndcard", "eliza"}, - {.compatible = "qcom,kaanapali-sndcard", "kaanapali"}, - {.compatible = "qcom,qcm6490-idp-sndcard", "qcm6490"}, - {.compatible = "qcom,qcs615-sndcard", "qcs615"}, - {.compatible = "qcom,qcs6490-rb3gen2-sndcard", "qcs6490"}, - {.compatible = "qcom,qcs8275-sndcard", "qcs8300"}, - {.compatible = "qcom,qcs9075-sndcard", "sa8775p"}, - {.compatible = "qcom,qcs9100-sndcard", "sa8775p"}, - {.compatible = "qcom,sc8280xp-sndcard", "sc8280xp"}, - {.compatible = "qcom,sm8450-sndcard", "sm8450"}, - {.compatible = "qcom,sm8550-sndcard", "sm8550"}, - {.compatible = "qcom,sm8650-sndcard", "sm8650"}, - {.compatible = "qcom,sm8750-sndcard", "sm8750"}, + { .compatible = "qcom,eliza-sndcard", .data = &eliza_priv_data }, + { .compatible = "qcom,kaanapali-sndcard", .data = &kaanapali_priv_data }, + { .compatible = "qcom,qcm6490-idp-sndcard", .data = &qcm6490_priv_data }, + { .compatible = "qcom,qcs615-sndcard", .data = &qcs615_priv_data }, + { .compatible = "qcom,qcs6490-rb3gen2-sndcard", .data = &qcs6490_priv_data }, + { .compatible = "qcom,qcs8275-sndcard", .data = &qcs8275_priv_data }, + { .compatible = "qcom,qcs9075-sndcard", .data = &qcs9100_priv_data }, + { .compatible = "qcom,qcs9100-sndcard", .data = &qcs9100_priv_data }, + { .compatible = "qcom,sc8280xp-sndcard", .data = &sc8280xp_priv_data }, + { .compatible = "qcom,sm8450-sndcard", .data = &sm8450_priv_data }, + { .compatible = "qcom,sm8550-sndcard", .data = &sm8550_priv_data }, + { .compatible = "qcom,sm8650-sndcard", .data = &sm8650_priv_data }, + { .compatible = "qcom,sm8750-sndcard", .data = &sm8750_priv_data }, {} };