summaryrefslogtreecommitdiffstats
path: root/sound/soc/qcom/sc7280.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2022-05-23 16:03:04 +0200
committerTakashi Iwai <tiwai@suse.de>2022-05-23 16:03:04 +0200
commit0163717ed5dec4fc3aaf937baa9f66f21ca11c1d (patch)
treeb0618a944385d1d35bd829c9aa09eddb5c9633fa /sound/soc/qcom/sc7280.c
parent1693e265e0a5dbe11fba21b48272dd15dbb71ec0 (diff)
parente5cd20e0d6713138444cc3f3f982712cf9a36143 (diff)
downloadlinux-0163717ed5dec4fc3aaf937baa9f66f21ca11c1d.tar.gz
linux-0163717ed5dec4fc3aaf937baa9f66f21ca11c1d.tar.bz2
linux-0163717ed5dec4fc3aaf937baa9f66f21ca11c1d.zip
Merge tag 'asoc-v5.19' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-linus
ASoC: Updates for v5.19 This is quite a big update, partly due to the addition of some larger drivers (more of which is to follow since at least the AVS driver is still a work in progress) and partly due to Charles' work sorting out our handling of endianness. As has been the case recently it's much more about drivers than the core. - Overhaul of endianness specification for data formats, avoiding needless restrictions due to CODECs. - Initial stages of Intel AVS driver merge. - Introduction of v4 IPC mechanism for SOF. - TDM mode support for AK4613. - Support for Analog Devices ADAU1361, Cirrus Logic CS35L45, Maxim MAX98396, MediaTek MT8186, NXP i.MX8 micfil and SAI interfaces, nVidia Tegra186 ASRC, and Texas Instruments TAS2764 and TAS2780
Diffstat (limited to 'sound/soc/qcom/sc7280.c')
-rw-r--r--sound/soc/qcom/sc7280.c99
1 files changed, 97 insertions, 2 deletions
diff --git a/sound/soc/qcom/sc7280.c b/sound/soc/qcom/sc7280.c
index bd0bf9c8cb28..34cdb99d4ed6 100644
--- a/sound/soc/qcom/sc7280.c
+++ b/sound/soc/qcom/sc7280.c
@@ -12,14 +12,21 @@
#include <sound/jack.h>
#include <sound/pcm.h>
#include <sound/soc.h>
+#include <sound/rt5682s.h>
#include <linux/soundwire/sdw.h>
+#include "../codecs/rt5682.h"
+#include "../codecs/rt5682s.h"
#include "common.h"
#include "lpass.h"
+#define DEFAULT_MCLK_RATE 19200000
+#define RT5682_PLL_FREQ (48000 * 512)
+
struct sc7280_snd_data {
struct snd_soc_card card;
struct sdw_stream_runtime *sruntime[LPASS_MAX_PORTS];
+ u32 pri_mi2s_clk_count;
struct snd_soc_jack hs_jack;
struct snd_soc_jack hdmi_jack;
bool jack_setup;
@@ -50,7 +57,7 @@ static int sc7280_headset_init(struct snd_soc_pcm_runtime *rtd)
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
SND_JACK_BTN_2 | SND_JACK_BTN_3 |
SND_JACK_BTN_4 | SND_JACK_BTN_5,
- &pdata->hs_jack, NULL, 0);
+ &pdata->hs_jack);
if (rval < 0) {
dev_err(card->dev, "Unable to add Headset Jack\n");
@@ -69,6 +76,7 @@ static int sc7280_headset_init(struct snd_soc_pcm_runtime *rtd)
pdata->jack_setup = true;
}
switch (cpu_dai->id) {
+ case MI2S_PRIMARY:
case LPASS_CDC_DMA_RX0:
case LPASS_CDC_DMA_TX3:
for_each_rtd_codec_dais(rtd, i, codec_dai) {
@@ -96,7 +104,7 @@ static int sc7280_hdmi_init(struct snd_soc_pcm_runtime *rtd)
int rval;
rval = snd_soc_card_jack_new(card, "HDMI Jack", SND_JACK_LINEOUT,
- &pdata->hdmi_jack, NULL, 0);
+ &pdata->hdmi_jack);
if (rval < 0) {
dev_err(card->dev, "Unable to add HDMI Jack\n");
@@ -110,11 +118,51 @@ static int sc7280_hdmi_init(struct snd_soc_pcm_runtime *rtd)
return snd_soc_component_set_jack(component, &pdata->hdmi_jack, NULL);
}
+static int sc7280_rt5682_init(struct snd_soc_pcm_runtime *rtd)
+{
+ 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_card *card = rtd->card;
+ struct sc7280_snd_data *data = snd_soc_card_get_drvdata(card);
+ int ret;
+
+ if (++data->pri_mi2s_clk_count == 1) {
+ snd_soc_dai_set_sysclk(cpu_dai,
+ LPASS_MCLK0,
+ DEFAULT_MCLK_RATE,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ }
+ snd_soc_dai_set_fmt(codec_dai,
+ SND_SOC_DAIFMT_CBC_CFC |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_I2S);
+
+ ret = snd_soc_dai_set_pll(codec_dai, RT5682S_PLL2, RT5682S_PLL_S_MCLK,
+ DEFAULT_MCLK_RATE, RT5682_PLL_FREQ);
+ if (ret) {
+ dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, RT5682S_SCLK_S_PLL2,
+ RT5682_PLL_FREQ,
+ SND_SOC_CLOCK_IN);
+
+ if (ret) {
+ dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n",
+ ret);
+ return ret;
+ }
+
+ return 0;
+}
+
static int sc7280_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
switch (cpu_dai->id) {
+ case MI2S_PRIMARY:
case LPASS_CDC_DMA_TX3:
return sc7280_headset_init(rtd);
case LPASS_CDC_DMA_RX0:
@@ -227,10 +275,54 @@ static int sc7280_snd_hw_free(struct snd_pcm_substream *substream)
return 0;
}
+static void sc7280_snd_shutdown(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_card *card = rtd->card;
+ struct sc7280_snd_data *data = snd_soc_card_get_drvdata(card);
+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+
+ switch (cpu_dai->id) {
+ case MI2S_PRIMARY:
+ if (--data->pri_mi2s_clk_count == 0) {
+ snd_soc_dai_set_sysclk(cpu_dai,
+ LPASS_MCLK0,
+ 0,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static int sc7280_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);
+ int ret = 0;
+
+ switch (cpu_dai->id) {
+ case MI2S_PRIMARY:
+ ret = sc7280_rt5682_init(rtd);
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
static const struct snd_soc_ops sc7280_ops = {
+ .startup = sc7280_snd_startup,
.hw_params = sc7280_snd_hw_params,
.hw_free = sc7280_snd_hw_free,
.prepare = sc7280_snd_prepare,
+ .shutdown = sc7280_snd_shutdown,
+};
+
+static const struct snd_soc_dapm_widget sc7280_snd_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
};
static int sc7280_snd_platform_probe(struct platform_device *pdev)
@@ -252,6 +344,9 @@ static int sc7280_snd_platform_probe(struct platform_device *pdev)
card->driver_name = "SC7280";
card->dev = dev;
+ card->dapm_widgets = sc7280_snd_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(sc7280_snd_widgets);
+
ret = qcom_snd_parse_of(card);
if (ret)
return ret;