diff options
Diffstat (limited to 'sound/soc/qcom/sc7180.c')
-rw-r--r-- | sound/soc/qcom/sc7180.c | 216 |
1 files changed, 183 insertions, 33 deletions
diff --git a/sound/soc/qcom/sc7180.c b/sound/soc/qcom/sc7180.c index 57c5f35dfc..b0320a74d5 100644 --- a/sound/soc/qcom/sc7180.c +++ b/sound/soc/qcom/sc7180.c @@ -5,10 +5,11 @@ // sc7180.c -- ALSA SoC Machine driver for SC7180 #include <dt-bindings/sound/sc7180-lpass.h> +#include <dt-bindings/sound/qcom,q6afe.h> #include <linux/gpio.h> #include <linux/gpio/consumer.h> #include <linux/module.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <sound/core.h> #include <sound/jack.h> @@ -19,9 +20,10 @@ #include "../codecs/rt5682.h" #include "../codecs/rt5682s.h" #include "common.h" -#include "lpass.h" +#include "qdsp6/q6afe.h" #define DEFAULT_MCLK_RATE 19200000 +#define MI2S_BCLK_RATE 1536000 #define RT5682_PLL1_FREQ (48000 * 512) #define DRIVER_NAME "SC7180" @@ -57,7 +59,7 @@ static int sc7180_headset_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; struct sc7180_snd_data *pdata = snd_soc_card_get_drvdata(card); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); struct snd_soc_component *component = codec_dai->component; struct snd_jack *jack; int rval; @@ -93,7 +95,7 @@ static int sc7180_hdmi_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; struct sc7180_snd_data *pdata = snd_soc_card_get_drvdata(card); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); struct snd_soc_component *component = codec_dai->component; struct snd_jack *jack; int rval; @@ -117,7 +119,7 @@ static int sc7180_hdmi_init(struct snd_soc_pcm_runtime *rtd) static int sc7180_init(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); switch (cpu_dai->id) { case MI2S_PRIMARY: @@ -134,13 +136,29 @@ static int sc7180_init(struct snd_soc_pcm_runtime *rtd) return 0; } -static int sc7180_snd_startup(struct snd_pcm_substream *substream) +static int sc7180_qdsp_init(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_card *card = rtd->card; - struct sc7180_snd_data *data = snd_soc_card_get_drvdata(card); - struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + + switch (cpu_dai->id) { + case PRIMARY_MI2S_RX: + return sc7180_headset_init(rtd); + case PRIMARY_MI2S_TX: + case TERTIARY_MI2S_RX: + return 0; + case DISPLAY_PORT_RX: + return sc7180_hdmi_init(rtd); + default: + dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__, + cpu_dai->id); + return -EINVAL; + } + return 0; +} + +static int sc7180_startup_realtek_codec(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); int pll_id, pll_source, pll_in, pll_out, clk_id, ret; if (!strcmp(codec_dai->name, "rt5682-aif1")) { @@ -155,7 +173,39 @@ static int sc7180_snd_startup(struct snd_pcm_substream *substream) clk_id = RT5682S_SCLK_S_PLL2; pll_out = RT5682_PLL1_FREQ; pll_in = DEFAULT_MCLK_RATE; + } else { + return 0; } + snd_soc_dai_set_fmt(codec_dai, + SND_SOC_DAIFMT_BC_FC | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_I2S); + + /* Configure PLL1 for codec */ + ret = snd_soc_dai_set_pll(codec_dai, pll_id, pll_source, + pll_in, pll_out); + if (ret) { + dev_err(rtd->dev, "can't set codec pll: %d\n", ret); + return ret; + } + + /* Configure sysclk for codec */ + ret = snd_soc_dai_set_sysclk(codec_dai, clk_id, pll_out, + SND_SOC_CLOCK_IN); + if (ret) + dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", + ret); + + return ret; +} + +static int sc7180_snd_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_card *card = rtd->card; + struct sc7180_snd_data *data = snd_soc_card_get_drvdata(card); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + int ret; switch (cpu_dai->id) { case MI2S_PRIMARY: @@ -166,30 +216,66 @@ static int sc7180_snd_startup(struct snd_pcm_substream *substream) SNDRV_PCM_STREAM_PLAYBACK); } - snd_soc_dai_set_fmt(codec_dai, - SND_SOC_DAIFMT_BC_FC | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_I2S); - - /* Configure PLL1 for codec */ - ret = snd_soc_dai_set_pll(codec_dai, pll_id, pll_source, - pll_in, pll_out); - if (ret) { - dev_err(rtd->dev, "can't set codec pll: %d\n", ret); + ret = sc7180_startup_realtek_codec(rtd); + if (ret) return ret; + + break; + case MI2S_SECONDARY: + break; + case LPASS_DP_RX: + break; + default: + dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__, + cpu_dai->id); + return -EINVAL; + } + return 0; +} + +static int sc7180_qdsp_snd_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_card *card = rtd->card; + struct sc7180_snd_data *data = snd_soc_card_get_drvdata(card); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); + int ret; + + switch (cpu_dai->id) { + case PRIMARY_MI2S_RX: + case PRIMARY_MI2S_TX: + if (++data->pri_mi2s_clk_count == 1) { + snd_soc_dai_set_sysclk(cpu_dai, + Q6AFE_LPASS_CLK_ID_MCLK_1, + DEFAULT_MCLK_RATE, + SNDRV_PCM_STREAM_PLAYBACK); + snd_soc_dai_set_sysclk(cpu_dai, + Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT, + MI2S_BCLK_RATE, + SNDRV_PCM_STREAM_PLAYBACK); } - /* Configure sysclk for codec */ - ret = snd_soc_dai_set_sysclk(codec_dai, clk_id, pll_out, - SND_SOC_CLOCK_IN); + snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_BP_FP); + + ret = sc7180_startup_realtek_codec(rtd); if (ret) - dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", - ret); + return ret; break; - case MI2S_SECONDARY: + case TERTIARY_MI2S_RX: + snd_soc_dai_set_sysclk(cpu_dai, + Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT, + MI2S_BCLK_RATE, + SNDRV_PCM_STREAM_PLAYBACK); + + snd_soc_dai_set_fmt(codec_dai, + SND_SOC_DAIFMT_BC_FC | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_I2S); + snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_BP_FP); break; - case LPASS_DP_RX: + case DISPLAY_PORT_RX: break; default: dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__, @@ -225,7 +311,7 @@ static void sc7180_snd_shutdown(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_card *card = rtd->card; struct sc7180_snd_data *data = snd_soc_card_get_drvdata(card); - struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); switch (cpu_dai->id) { case MI2S_PRIMARY: @@ -247,9 +333,45 @@ static void sc7180_snd_shutdown(struct snd_pcm_substream *substream) } } +static void sc7180_qdsp_snd_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_card *card = rtd->card; + struct sc7180_snd_data *data = snd_soc_card_get_drvdata(card); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + + switch (cpu_dai->id) { + case PRIMARY_MI2S_RX: + case PRIMARY_MI2S_TX: + if (--data->pri_mi2s_clk_count == 0) { + snd_soc_dai_set_sysclk(cpu_dai, + Q6AFE_LPASS_CLK_ID_MCLK_1, + 0, + SNDRV_PCM_STREAM_PLAYBACK); + snd_soc_dai_set_sysclk(cpu_dai, + Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT, + 0, + SNDRV_PCM_STREAM_PLAYBACK); + } + break; + case TERTIARY_MI2S_RX: + snd_soc_dai_set_sysclk(cpu_dai, + Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT, + 0, + SNDRV_PCM_STREAM_PLAYBACK); + break; + case DISPLAY_PORT_RX: + break; + default: + dev_err(rtd->dev, "%s: invalid dai id 0x%x\n", __func__, + cpu_dai->id); + break; + } +} + static int sc7180_adau7002_init(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); switch (cpu_dai->id) { case MI2S_PRIMARY: @@ -269,8 +391,8 @@ static int sc7180_adau7002_init(struct snd_soc_pcm_runtime *rtd) static int sc7180_adau7002_snd_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); struct snd_pcm_runtime *runtime = substream->runtime; switch (cpu_dai->id) { @@ -295,11 +417,30 @@ static int sc7180_adau7002_snd_startup(struct snd_pcm_substream *substream) return 0; } +static int sc7180_qdsp_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + + return 0; +} + static const struct snd_soc_ops sc7180_ops = { .startup = sc7180_snd_startup, .shutdown = sc7180_snd_shutdown, }; +static const struct snd_soc_ops sc7180_qdsp_ops = { + .startup = sc7180_qdsp_snd_startup, + .shutdown = sc7180_qdsp_snd_shutdown, +}; + static const struct snd_soc_ops sc7180_adau7002_ops = { .startup = sc7180_adau7002_snd_startup, }; @@ -355,7 +496,7 @@ static int sc7180_snd_platform_probe(struct platform_device *pdev) struct snd_soc_dai_link *link; int ret; int i; - bool no_headphone = false; + bool qdsp = false, no_headphone = false; /* Allocate the private data */ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); @@ -391,6 +532,8 @@ static int sc7180_snd_platform_probe(struct platform_device *pdev) no_headphone = true; card->dapm_widgets = sc7180_adau7002_snd_widgets; card->num_dapm_widgets = ARRAY_SIZE(sc7180_adau7002_snd_widgets); + } else if (of_device_is_compatible(dev->of_node, "qcom,sc7180-qdsp6-sndcard")) { + qdsp = true; } ret = qcom_snd_parse_of(card); @@ -401,6 +544,12 @@ static int sc7180_snd_platform_probe(struct platform_device *pdev) if (no_headphone) { link->ops = &sc7180_adau7002_ops; link->init = sc7180_adau7002_init; + } else if (qdsp) { + if (link->no_pcm == 1) { + link->ops = &sc7180_qdsp_ops; + link->be_hw_params_fixup = sc7180_qdsp_be_hw_params_fixup; + link->init = sc7180_qdsp_init; + } } else { link->ops = &sc7180_ops; link->init = sc7180_init; @@ -413,6 +562,7 @@ static int sc7180_snd_platform_probe(struct platform_device *pdev) static const struct of_device_id sc7180_snd_device_id[] = { {.compatible = "google,sc7180-trogdor"}, {.compatible = "google,sc7180-coachz"}, + {.compatible = "qcom,sc7180-qdsp6-sndcard"}, {}, }; MODULE_DEVICE_TABLE(of, sc7180_snd_device_id); |