1af873fceSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
232a726b2SArnaud Pouliquen /*
332a726b2SArnaud Pouliquen * Copyright (C) STMicroelectronics SA 2015
432a726b2SArnaud Pouliquen * Authors: Arnaud Pouliquen <arnaud.pouliquen@st.com>
532a726b2SArnaud Pouliquen * for STMicroelectronics.
632a726b2SArnaud Pouliquen */
732a726b2SArnaud Pouliquen
832a726b2SArnaud Pouliquen #include <linux/io.h>
932a726b2SArnaud Pouliquen #include <linux/module.h>
1032a726b2SArnaud Pouliquen #include <linux/regmap.h>
1132a726b2SArnaud Pouliquen #include <linux/reset.h>
1232a726b2SArnaud Pouliquen #include <linux/mfd/syscon.h>
1332a726b2SArnaud Pouliquen
1432a726b2SArnaud Pouliquen #include <sound/soc.h>
1532a726b2SArnaud Pouliquen #include <sound/soc-dapm.h>
1632a726b2SArnaud Pouliquen
1732a726b2SArnaud Pouliquen /* DAC definitions */
1832a726b2SArnaud Pouliquen
1932a726b2SArnaud Pouliquen /* stih407 DAC registers */
2032a726b2SArnaud Pouliquen /* sysconf 5041: Audio-Gue-Control */
2132a726b2SArnaud Pouliquen #define STIH407_AUDIO_GLUE_CTRL 0x000000A4
2232a726b2SArnaud Pouliquen /* sysconf 5042: Audio-DAC-Control */
2332a726b2SArnaud Pouliquen #define STIH407_AUDIO_DAC_CTRL 0x000000A8
2432a726b2SArnaud Pouliquen
2532a726b2SArnaud Pouliquen /* DAC definitions */
2632a726b2SArnaud Pouliquen #define STIH407_DAC_SOFTMUTE 0x0
2732a726b2SArnaud Pouliquen #define STIH407_DAC_STANDBY_ANA 0x1
2832a726b2SArnaud Pouliquen #define STIH407_DAC_STANDBY 0x2
2932a726b2SArnaud Pouliquen
3032a726b2SArnaud Pouliquen #define STIH407_DAC_SOFTMUTE_MASK BIT(STIH407_DAC_SOFTMUTE)
3132a726b2SArnaud Pouliquen #define STIH407_DAC_STANDBY_ANA_MASK BIT(STIH407_DAC_STANDBY_ANA)
3232a726b2SArnaud Pouliquen #define STIH407_DAC_STANDBY_MASK BIT(STIH407_DAC_STANDBY)
3332a726b2SArnaud Pouliquen
3432a726b2SArnaud Pouliquen /* SPDIF definitions */
3532a726b2SArnaud Pouliquen #define SPDIF_BIPHASE_ENABLE 0x6
3632a726b2SArnaud Pouliquen #define SPDIF_BIPHASE_IDLE 0x7
3732a726b2SArnaud Pouliquen
3832a726b2SArnaud Pouliquen #define SPDIF_BIPHASE_ENABLE_MASK BIT(SPDIF_BIPHASE_ENABLE)
3932a726b2SArnaud Pouliquen #define SPDIF_BIPHASE_IDLE_MASK BIT(SPDIF_BIPHASE_IDLE)
4032a726b2SArnaud Pouliquen
4132a726b2SArnaud Pouliquen enum {
4232a726b2SArnaud Pouliquen STI_SAS_DAI_SPDIF_OUT,
4332a726b2SArnaud Pouliquen STI_SAS_DAI_ANALOG_OUT,
4432a726b2SArnaud Pouliquen };
4532a726b2SArnaud Pouliquen
4632a726b2SArnaud Pouliquen static const struct reg_default stih407_sas_reg_defaults[] = {
47165a57a3SArnaud Pouliquen { STIH407_AUDIO_DAC_CTRL, 0x000000000 },
48165a57a3SArnaud Pouliquen { STIH407_AUDIO_GLUE_CTRL, 0x00000040 },
4932a726b2SArnaud Pouliquen };
5032a726b2SArnaud Pouliquen
5132a726b2SArnaud Pouliquen struct sti_dac_audio {
5232a726b2SArnaud Pouliquen struct regmap *regmap;
5332a726b2SArnaud Pouliquen struct regmap *virt_regmap;
5432a726b2SArnaud Pouliquen int mclk;
5532a726b2SArnaud Pouliquen };
5632a726b2SArnaud Pouliquen
5732a726b2SArnaud Pouliquen struct sti_spdif_audio {
5832a726b2SArnaud Pouliquen struct regmap *regmap;
5932a726b2SArnaud Pouliquen int mclk;
6032a726b2SArnaud Pouliquen };
6132a726b2SArnaud Pouliquen
6232a726b2SArnaud Pouliquen /* device data structure */
6332a726b2SArnaud Pouliquen struct sti_sas_dev_data {
6432a726b2SArnaud Pouliquen const struct regmap_config *regmap;
6532a726b2SArnaud Pouliquen const struct snd_soc_dai_ops *dac_ops; /* DAC function callbacks */
6632a726b2SArnaud Pouliquen const struct snd_soc_dapm_widget *dapm_widgets; /* dapms declaration */
6732a726b2SArnaud Pouliquen const int num_dapm_widgets; /* dapms declaration */
6832a726b2SArnaud Pouliquen const struct snd_soc_dapm_route *dapm_routes; /* route declaration */
6932a726b2SArnaud Pouliquen const int num_dapm_routes; /* route declaration */
7032a726b2SArnaud Pouliquen };
7132a726b2SArnaud Pouliquen
7232a726b2SArnaud Pouliquen /* driver data structure */
7332a726b2SArnaud Pouliquen struct sti_sas_data {
7432a726b2SArnaud Pouliquen struct device *dev;
7532a726b2SArnaud Pouliquen const struct sti_sas_dev_data *dev_data;
7632a726b2SArnaud Pouliquen struct sti_dac_audio dac;
7732a726b2SArnaud Pouliquen struct sti_spdif_audio spdif;
7832a726b2SArnaud Pouliquen };
7932a726b2SArnaud Pouliquen
8032a726b2SArnaud Pouliquen /* Read a register from the sysconf reg bank */
sti_sas_read_reg(void * context,unsigned int reg,unsigned int * value)8132a726b2SArnaud Pouliquen static int sti_sas_read_reg(void *context, unsigned int reg,
8232a726b2SArnaud Pouliquen unsigned int *value)
8332a726b2SArnaud Pouliquen {
8432a726b2SArnaud Pouliquen struct sti_sas_data *drvdata = context;
8532a726b2SArnaud Pouliquen int status;
8632a726b2SArnaud Pouliquen u32 val;
8732a726b2SArnaud Pouliquen
8832a726b2SArnaud Pouliquen status = regmap_read(drvdata->dac.regmap, reg, &val);
8932a726b2SArnaud Pouliquen *value = (unsigned int)val;
9032a726b2SArnaud Pouliquen
9132a726b2SArnaud Pouliquen return status;
9232a726b2SArnaud Pouliquen }
9332a726b2SArnaud Pouliquen
9432a726b2SArnaud Pouliquen /* Read a register from the sysconf reg bank */
sti_sas_write_reg(void * context,unsigned int reg,unsigned int value)9532a726b2SArnaud Pouliquen static int sti_sas_write_reg(void *context, unsigned int reg,
9632a726b2SArnaud Pouliquen unsigned int value)
9732a726b2SArnaud Pouliquen {
9832a726b2SArnaud Pouliquen struct sti_sas_data *drvdata = context;
9932a726b2SArnaud Pouliquen
100b075f21eSye xingchen return regmap_write(drvdata->dac.regmap, reg, value);
10132a726b2SArnaud Pouliquen }
10232a726b2SArnaud Pouliquen
sti_sas_init_sas_registers(struct snd_soc_component * component,struct sti_sas_data * data)103049c1bfcSKuninori Morimoto static int sti_sas_init_sas_registers(struct snd_soc_component *component,
10432a726b2SArnaud Pouliquen struct sti_sas_data *data)
10532a726b2SArnaud Pouliquen {
10632a726b2SArnaud Pouliquen int ret;
10732a726b2SArnaud Pouliquen /*
10832a726b2SArnaud Pouliquen * DAC and SPDIF are activated by default
10932a726b2SArnaud Pouliquen * put them in IDLE to save power
11032a726b2SArnaud Pouliquen */
11132a726b2SArnaud Pouliquen
11232a726b2SArnaud Pouliquen /* Initialise bi-phase formatter to disabled */
113049c1bfcSKuninori Morimoto ret = snd_soc_component_update_bits(component, STIH407_AUDIO_GLUE_CTRL,
11432a726b2SArnaud Pouliquen SPDIF_BIPHASE_ENABLE_MASK, 0);
11532a726b2SArnaud Pouliquen
11632a726b2SArnaud Pouliquen if (!ret)
11732a726b2SArnaud Pouliquen /* Initialise bi-phase formatter idle value to 0 */
118049c1bfcSKuninori Morimoto ret = snd_soc_component_update_bits(component, STIH407_AUDIO_GLUE_CTRL,
11932a726b2SArnaud Pouliquen SPDIF_BIPHASE_IDLE_MASK, 0);
12032a726b2SArnaud Pouliquen if (ret < 0) {
121049c1bfcSKuninori Morimoto dev_err(component->dev, "Failed to update SPDIF registers\n");
12232a726b2SArnaud Pouliquen return ret;
12332a726b2SArnaud Pouliquen }
12432a726b2SArnaud Pouliquen
12532a726b2SArnaud Pouliquen /* Init DAC configuration */
12632a726b2SArnaud Pouliquen /* init configuration */
127049c1bfcSKuninori Morimoto ret = snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
12832a726b2SArnaud Pouliquen STIH407_DAC_STANDBY_MASK,
12932a726b2SArnaud Pouliquen STIH407_DAC_STANDBY_MASK);
13032a726b2SArnaud Pouliquen
13132a726b2SArnaud Pouliquen if (!ret)
132049c1bfcSKuninori Morimoto ret = snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
13332a726b2SArnaud Pouliquen STIH407_DAC_STANDBY_ANA_MASK,
13432a726b2SArnaud Pouliquen STIH407_DAC_STANDBY_ANA_MASK);
13532a726b2SArnaud Pouliquen if (!ret)
136049c1bfcSKuninori Morimoto ret = snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
13732a726b2SArnaud Pouliquen STIH407_DAC_SOFTMUTE_MASK,
13832a726b2SArnaud Pouliquen STIH407_DAC_SOFTMUTE_MASK);
13932a726b2SArnaud Pouliquen
14032a726b2SArnaud Pouliquen if (ret < 0) {
141049c1bfcSKuninori Morimoto dev_err(component->dev, "Failed to update DAC registers\n");
14232a726b2SArnaud Pouliquen return ret;
14332a726b2SArnaud Pouliquen }
14432a726b2SArnaud Pouliquen
14532a726b2SArnaud Pouliquen return ret;
14632a726b2SArnaud Pouliquen }
14732a726b2SArnaud Pouliquen
14832a726b2SArnaud Pouliquen /*
14932a726b2SArnaud Pouliquen * DAC
15032a726b2SArnaud Pouliquen */
sti_sas_dac_set_fmt(struct snd_soc_dai * dai,unsigned int fmt)15132a726b2SArnaud Pouliquen static int sti_sas_dac_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
15232a726b2SArnaud Pouliquen {
15332a726b2SArnaud Pouliquen /* Sanity check only */
154a325068eSMark Brown if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_CBC_CFC) {
155049c1bfcSKuninori Morimoto dev_err(dai->component->dev,
156a325068eSMark Brown "%s: ERROR: Unsupported clocking 0x%x\n",
157a325068eSMark Brown __func__, fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK);
15832a726b2SArnaud Pouliquen return -EINVAL;
15932a726b2SArnaud Pouliquen }
16032a726b2SArnaud Pouliquen
16132a726b2SArnaud Pouliquen return 0;
16232a726b2SArnaud Pouliquen }
16332a726b2SArnaud Pouliquen
164589bef32SAxel Lin static const struct snd_soc_dapm_widget stih407_sas_dapm_widgets[] = {
16532a726b2SArnaud Pouliquen SND_SOC_DAPM_OUT_DRV("DAC standby ana", STIH407_AUDIO_DAC_CTRL,
16632a726b2SArnaud Pouliquen STIH407_DAC_STANDBY_ANA, 1, NULL, 0),
16732a726b2SArnaud Pouliquen SND_SOC_DAPM_DAC("DAC standby", "dac_p", STIH407_AUDIO_DAC_CTRL,
16832a726b2SArnaud Pouliquen STIH407_DAC_STANDBY, 1),
16932a726b2SArnaud Pouliquen SND_SOC_DAPM_OUTPUT("DAC Output"),
17032a726b2SArnaud Pouliquen };
17132a726b2SArnaud Pouliquen
172589bef32SAxel Lin static const struct snd_soc_dapm_route stih407_sas_route[] = {
17332a726b2SArnaud Pouliquen {"DAC Output", NULL, "DAC standby ana"},
17432a726b2SArnaud Pouliquen {"DAC standby ana", NULL, "DAC standby"},
17532a726b2SArnaud Pouliquen };
17632a726b2SArnaud Pouliquen
17732a726b2SArnaud Pouliquen
stih407_sas_dac_mute(struct snd_soc_dai * dai,int mute,int stream)17832a726b2SArnaud Pouliquen static int stih407_sas_dac_mute(struct snd_soc_dai *dai, int mute, int stream)
17932a726b2SArnaud Pouliquen {
180049c1bfcSKuninori Morimoto struct snd_soc_component *component = dai->component;
18132a726b2SArnaud Pouliquen
18232a726b2SArnaud Pouliquen if (mute) {
183049c1bfcSKuninori Morimoto return snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
18432a726b2SArnaud Pouliquen STIH407_DAC_SOFTMUTE_MASK,
18532a726b2SArnaud Pouliquen STIH407_DAC_SOFTMUTE_MASK);
18632a726b2SArnaud Pouliquen } else {
187049c1bfcSKuninori Morimoto return snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
18832a726b2SArnaud Pouliquen STIH407_DAC_SOFTMUTE_MASK,
18932a726b2SArnaud Pouliquen 0);
19032a726b2SArnaud Pouliquen }
19132a726b2SArnaud Pouliquen }
19232a726b2SArnaud Pouliquen
19332a726b2SArnaud Pouliquen /*
19432a726b2SArnaud Pouliquen * SPDIF
19532a726b2SArnaud Pouliquen */
sti_sas_spdif_set_fmt(struct snd_soc_dai * dai,unsigned int fmt)19632a726b2SArnaud Pouliquen static int sti_sas_spdif_set_fmt(struct snd_soc_dai *dai,
19732a726b2SArnaud Pouliquen unsigned int fmt)
19832a726b2SArnaud Pouliquen {
199d7e98b57SMark Brown if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_CBC_CFC) {
200049c1bfcSKuninori Morimoto dev_err(dai->component->dev,
201d7e98b57SMark Brown "%s: ERROR: Unsupported clocking mask 0x%x\n",
202d7e98b57SMark Brown __func__, fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK);
20332a726b2SArnaud Pouliquen return -EINVAL;
20432a726b2SArnaud Pouliquen }
20532a726b2SArnaud Pouliquen
20632a726b2SArnaud Pouliquen return 0;
20732a726b2SArnaud Pouliquen }
20832a726b2SArnaud Pouliquen
20932a726b2SArnaud Pouliquen /*
21032a726b2SArnaud Pouliquen * sti_sas_spdif_trigger:
21132a726b2SArnaud Pouliquen * Trigger function is used to ensure that BiPhase Formater is disabled
21232a726b2SArnaud Pouliquen * before CPU dai is stopped.
21332a726b2SArnaud Pouliquen * This is mandatory to avoid that BPF is stalled
21432a726b2SArnaud Pouliquen */
sti_sas_spdif_trigger(struct snd_pcm_substream * substream,int cmd,struct snd_soc_dai * dai)21532a726b2SArnaud Pouliquen static int sti_sas_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
21632a726b2SArnaud Pouliquen struct snd_soc_dai *dai)
21732a726b2SArnaud Pouliquen {
218049c1bfcSKuninori Morimoto struct snd_soc_component *component = dai->component;
21932a726b2SArnaud Pouliquen
22032a726b2SArnaud Pouliquen switch (cmd) {
22132a726b2SArnaud Pouliquen case SNDRV_PCM_TRIGGER_START:
22232a726b2SArnaud Pouliquen case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
223049c1bfcSKuninori Morimoto return snd_soc_component_update_bits(component, STIH407_AUDIO_GLUE_CTRL,
22432a726b2SArnaud Pouliquen SPDIF_BIPHASE_ENABLE_MASK,
22532a726b2SArnaud Pouliquen SPDIF_BIPHASE_ENABLE_MASK);
22632a726b2SArnaud Pouliquen case SNDRV_PCM_TRIGGER_RESUME:
22732a726b2SArnaud Pouliquen case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
22832a726b2SArnaud Pouliquen case SNDRV_PCM_TRIGGER_STOP:
22932a726b2SArnaud Pouliquen case SNDRV_PCM_TRIGGER_SUSPEND:
230049c1bfcSKuninori Morimoto return snd_soc_component_update_bits(component, STIH407_AUDIO_GLUE_CTRL,
23132a726b2SArnaud Pouliquen SPDIF_BIPHASE_ENABLE_MASK,
23232a726b2SArnaud Pouliquen 0);
23332a726b2SArnaud Pouliquen default:
23432a726b2SArnaud Pouliquen return -EINVAL;
23532a726b2SArnaud Pouliquen }
23632a726b2SArnaud Pouliquen }
23732a726b2SArnaud Pouliquen
sti_sas_volatile_register(struct device * dev,unsigned int reg)23832a726b2SArnaud Pouliquen static bool sti_sas_volatile_register(struct device *dev, unsigned int reg)
23932a726b2SArnaud Pouliquen {
24032a726b2SArnaud Pouliquen if (reg == STIH407_AUDIO_GLUE_CTRL)
24132a726b2SArnaud Pouliquen return true;
24232a726b2SArnaud Pouliquen
24332a726b2SArnaud Pouliquen return false;
24432a726b2SArnaud Pouliquen }
24532a726b2SArnaud Pouliquen
24632a726b2SArnaud Pouliquen /*
24732a726b2SArnaud Pouliquen * CODEC DAIS
24832a726b2SArnaud Pouliquen */
24932a726b2SArnaud Pouliquen
25032a726b2SArnaud Pouliquen /*
25132a726b2SArnaud Pouliquen * sti_sas_set_sysclk:
25232a726b2SArnaud Pouliquen * get MCLK input frequency to check that MCLK-FS ratio is coherent
25332a726b2SArnaud Pouliquen */
sti_sas_set_sysclk(struct snd_soc_dai * dai,int clk_id,unsigned int freq,int dir)25432a726b2SArnaud Pouliquen static int sti_sas_set_sysclk(struct snd_soc_dai *dai, int clk_id,
25532a726b2SArnaud Pouliquen unsigned int freq, int dir)
25632a726b2SArnaud Pouliquen {
257049c1bfcSKuninori Morimoto struct snd_soc_component *component = dai->component;
258049c1bfcSKuninori Morimoto struct sti_sas_data *drvdata = dev_get_drvdata(component->dev);
25932a726b2SArnaud Pouliquen
26032a726b2SArnaud Pouliquen if (dir == SND_SOC_CLOCK_OUT)
26132a726b2SArnaud Pouliquen return 0;
26232a726b2SArnaud Pouliquen
26332a726b2SArnaud Pouliquen if (clk_id != 0)
26432a726b2SArnaud Pouliquen return -EINVAL;
26532a726b2SArnaud Pouliquen
26632a726b2SArnaud Pouliquen switch (dai->id) {
26732a726b2SArnaud Pouliquen case STI_SAS_DAI_SPDIF_OUT:
26832a726b2SArnaud Pouliquen drvdata->spdif.mclk = freq;
26932a726b2SArnaud Pouliquen break;
27032a726b2SArnaud Pouliquen
27132a726b2SArnaud Pouliquen case STI_SAS_DAI_ANALOG_OUT:
27232a726b2SArnaud Pouliquen drvdata->dac.mclk = freq;
27332a726b2SArnaud Pouliquen break;
27432a726b2SArnaud Pouliquen }
27532a726b2SArnaud Pouliquen
27632a726b2SArnaud Pouliquen return 0;
27732a726b2SArnaud Pouliquen }
27832a726b2SArnaud Pouliquen
sti_sas_prepare(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)27932a726b2SArnaud Pouliquen static int sti_sas_prepare(struct snd_pcm_substream *substream,
28032a726b2SArnaud Pouliquen struct snd_soc_dai *dai)
28132a726b2SArnaud Pouliquen {
282049c1bfcSKuninori Morimoto struct snd_soc_component *component = dai->component;
283049c1bfcSKuninori Morimoto struct sti_sas_data *drvdata = dev_get_drvdata(component->dev);
28432a726b2SArnaud Pouliquen struct snd_pcm_runtime *runtime = substream->runtime;
28532a726b2SArnaud Pouliquen
28632a726b2SArnaud Pouliquen switch (dai->id) {
28732a726b2SArnaud Pouliquen case STI_SAS_DAI_SPDIF_OUT:
28832a726b2SArnaud Pouliquen if ((drvdata->spdif.mclk / runtime->rate) != 128) {
289049c1bfcSKuninori Morimoto dev_err(component->dev, "unexpected mclk-fs ratio\n");
29032a726b2SArnaud Pouliquen return -EINVAL;
29132a726b2SArnaud Pouliquen }
29232a726b2SArnaud Pouliquen break;
29332a726b2SArnaud Pouliquen case STI_SAS_DAI_ANALOG_OUT:
29432a726b2SArnaud Pouliquen if ((drvdata->dac.mclk / runtime->rate) != 256) {
295049c1bfcSKuninori Morimoto dev_err(component->dev, "unexpected mclk-fs ratio\n");
29632a726b2SArnaud Pouliquen return -EINVAL;
29732a726b2SArnaud Pouliquen }
29832a726b2SArnaud Pouliquen break;
29932a726b2SArnaud Pouliquen }
30032a726b2SArnaud Pouliquen
30132a726b2SArnaud Pouliquen return 0;
30232a726b2SArnaud Pouliquen }
30332a726b2SArnaud Pouliquen
304589bef32SAxel Lin static const struct snd_soc_dai_ops stih407_dac_ops = {
30532a726b2SArnaud Pouliquen .set_fmt = sti_sas_dac_set_fmt,
30632a726b2SArnaud Pouliquen .mute_stream = stih407_sas_dac_mute,
30732a726b2SArnaud Pouliquen .prepare = sti_sas_prepare,
30832a726b2SArnaud Pouliquen .set_sysclk = sti_sas_set_sysclk,
30932a726b2SArnaud Pouliquen };
31032a726b2SArnaud Pouliquen
311589bef32SAxel Lin static const struct regmap_config stih407_sas_regmap = {
31232a726b2SArnaud Pouliquen .reg_bits = 32,
31332a726b2SArnaud Pouliquen .val_bits = 32,
3147e235debSArnaud Pouliquen .fast_io = true,
31532a726b2SArnaud Pouliquen .max_register = STIH407_AUDIO_DAC_CTRL,
31632a726b2SArnaud Pouliquen .reg_defaults = stih407_sas_reg_defaults,
31732a726b2SArnaud Pouliquen .num_reg_defaults = ARRAY_SIZE(stih407_sas_reg_defaults),
31832a726b2SArnaud Pouliquen .volatile_reg = sti_sas_volatile_register,
319*66b1abc1SMark Brown .cache_type = REGCACHE_MAPLE,
32032a726b2SArnaud Pouliquen .reg_read = sti_sas_read_reg,
32132a726b2SArnaud Pouliquen .reg_write = sti_sas_write_reg,
32232a726b2SArnaud Pouliquen };
32332a726b2SArnaud Pouliquen
324589bef32SAxel Lin static const struct sti_sas_dev_data stih407_data = {
32532a726b2SArnaud Pouliquen .regmap = &stih407_sas_regmap,
32632a726b2SArnaud Pouliquen .dac_ops = &stih407_dac_ops,
32732a726b2SArnaud Pouliquen .dapm_widgets = stih407_sas_dapm_widgets,
32832a726b2SArnaud Pouliquen .num_dapm_widgets = ARRAY_SIZE(stih407_sas_dapm_widgets),
32932a726b2SArnaud Pouliquen .dapm_routes = stih407_sas_route,
33032a726b2SArnaud Pouliquen .num_dapm_routes = ARRAY_SIZE(stih407_sas_route),
33132a726b2SArnaud Pouliquen };
33232a726b2SArnaud Pouliquen
33332a726b2SArnaud Pouliquen static struct snd_soc_dai_driver sti_sas_dai[] = {
33432a726b2SArnaud Pouliquen {
33532a726b2SArnaud Pouliquen .name = "sas-dai-spdif-out",
33632a726b2SArnaud Pouliquen .id = STI_SAS_DAI_SPDIF_OUT,
33732a726b2SArnaud Pouliquen .playback = {
33832a726b2SArnaud Pouliquen .stream_name = "spdif_p",
33932a726b2SArnaud Pouliquen .channels_min = 2,
34032a726b2SArnaud Pouliquen .channels_max = 2,
34132a726b2SArnaud Pouliquen .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
34232a726b2SArnaud Pouliquen SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 |
34332a726b2SArnaud Pouliquen SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
34432a726b2SArnaud Pouliquen SNDRV_PCM_RATE_192000,
34532a726b2SArnaud Pouliquen .formats = SNDRV_PCM_FMTBIT_S16_LE |
34632a726b2SArnaud Pouliquen SNDRV_PCM_FMTBIT_S32_LE,
34732a726b2SArnaud Pouliquen },
34832a726b2SArnaud Pouliquen .ops = (struct snd_soc_dai_ops[]) {
34932a726b2SArnaud Pouliquen {
35032a726b2SArnaud Pouliquen .set_fmt = sti_sas_spdif_set_fmt,
35132a726b2SArnaud Pouliquen .trigger = sti_sas_spdif_trigger,
35232a726b2SArnaud Pouliquen .set_sysclk = sti_sas_set_sysclk,
35332a726b2SArnaud Pouliquen .prepare = sti_sas_prepare,
35432a726b2SArnaud Pouliquen }
35532a726b2SArnaud Pouliquen },
35632a726b2SArnaud Pouliquen },
35732a726b2SArnaud Pouliquen {
35832a726b2SArnaud Pouliquen .name = "sas-dai-dac",
35932a726b2SArnaud Pouliquen .id = STI_SAS_DAI_ANALOG_OUT,
36032a726b2SArnaud Pouliquen .playback = {
36132a726b2SArnaud Pouliquen .stream_name = "dac_p",
36232a726b2SArnaud Pouliquen .channels_min = 2,
36332a726b2SArnaud Pouliquen .channels_max = 2,
36432a726b2SArnaud Pouliquen .rates = SNDRV_PCM_RATE_8000_48000,
36532a726b2SArnaud Pouliquen .formats = SNDRV_PCM_FMTBIT_S16_LE |
36632a726b2SArnaud Pouliquen SNDRV_PCM_FMTBIT_S32_LE,
36732a726b2SArnaud Pouliquen },
36832a726b2SArnaud Pouliquen },
36932a726b2SArnaud Pouliquen };
37032a726b2SArnaud Pouliquen
37132a726b2SArnaud Pouliquen #ifdef CONFIG_PM_SLEEP
sti_sas_resume(struct snd_soc_component * component)372049c1bfcSKuninori Morimoto static int sti_sas_resume(struct snd_soc_component *component)
37332a726b2SArnaud Pouliquen {
374049c1bfcSKuninori Morimoto struct sti_sas_data *drvdata = dev_get_drvdata(component->dev);
37532a726b2SArnaud Pouliquen
376049c1bfcSKuninori Morimoto return sti_sas_init_sas_registers(component, drvdata);
37732a726b2SArnaud Pouliquen }
37832a726b2SArnaud Pouliquen #else
37932a726b2SArnaud Pouliquen #define sti_sas_resume NULL
38032a726b2SArnaud Pouliquen #endif
38132a726b2SArnaud Pouliquen
sti_sas_component_probe(struct snd_soc_component * component)382049c1bfcSKuninori Morimoto static int sti_sas_component_probe(struct snd_soc_component *component)
38332a726b2SArnaud Pouliquen {
384049c1bfcSKuninori Morimoto struct sti_sas_data *drvdata = dev_get_drvdata(component->dev);
38532a726b2SArnaud Pouliquen
386b075f21eSye xingchen return sti_sas_init_sas_registers(component, drvdata);
38732a726b2SArnaud Pouliquen }
38832a726b2SArnaud Pouliquen
389049c1bfcSKuninori Morimoto static struct snd_soc_component_driver sti_sas_driver = {
390049c1bfcSKuninori Morimoto .probe = sti_sas_component_probe,
39132a726b2SArnaud Pouliquen .resume = sti_sas_resume,
392049c1bfcSKuninori Morimoto .idle_bias_on = 1,
393049c1bfcSKuninori Morimoto .use_pmdown_time = 1,
394049c1bfcSKuninori Morimoto .endianness = 1,
39532a726b2SArnaud Pouliquen };
39632a726b2SArnaud Pouliquen
39732a726b2SArnaud Pouliquen static const struct of_device_id sti_sas_dev_match[] = {
39832a726b2SArnaud Pouliquen {
39932a726b2SArnaud Pouliquen .compatible = "st,stih407-sas-codec",
40032a726b2SArnaud Pouliquen .data = &stih407_data,
40132a726b2SArnaud Pouliquen },
40232a726b2SArnaud Pouliquen {},
40332a726b2SArnaud Pouliquen };
404e072b267SZou Wei MODULE_DEVICE_TABLE(of, sti_sas_dev_match);
40532a726b2SArnaud Pouliquen
sti_sas_driver_probe(struct platform_device * pdev)40632a726b2SArnaud Pouliquen static int sti_sas_driver_probe(struct platform_device *pdev)
40732a726b2SArnaud Pouliquen {
40832a726b2SArnaud Pouliquen struct device_node *pnode = pdev->dev.of_node;
40932a726b2SArnaud Pouliquen struct sti_sas_data *drvdata;
410601b9d9cSArnaud Pouliquen const struct of_device_id *of_id;
41132a726b2SArnaud Pouliquen
41232a726b2SArnaud Pouliquen /* Allocate device structure */
41332a726b2SArnaud Pouliquen drvdata = devm_kzalloc(&pdev->dev, sizeof(struct sti_sas_data),
41432a726b2SArnaud Pouliquen GFP_KERNEL);
41532a726b2SArnaud Pouliquen if (!drvdata)
41632a726b2SArnaud Pouliquen return -ENOMEM;
41732a726b2SArnaud Pouliquen
41832a726b2SArnaud Pouliquen /* Populate data structure depending on compatibility */
419601b9d9cSArnaud Pouliquen of_id = of_match_node(sti_sas_dev_match, pnode);
420601b9d9cSArnaud Pouliquen if (!of_id->data) {
42192591efaSArnaud Pouliquen dev_err(&pdev->dev, "data associated to device is missing\n");
42232a726b2SArnaud Pouliquen return -EINVAL;
42332a726b2SArnaud Pouliquen }
42432a726b2SArnaud Pouliquen
425601b9d9cSArnaud Pouliquen drvdata->dev_data = (struct sti_sas_dev_data *)of_id->data;
42632a726b2SArnaud Pouliquen
42732a726b2SArnaud Pouliquen /* Initialise device structure */
42832a726b2SArnaud Pouliquen drvdata->dev = &pdev->dev;
42932a726b2SArnaud Pouliquen
43032a726b2SArnaud Pouliquen /* Request the DAC & SPDIF registers memory region */
43132a726b2SArnaud Pouliquen drvdata->dac.virt_regmap = devm_regmap_init(&pdev->dev, NULL, drvdata,
43232a726b2SArnaud Pouliquen drvdata->dev_data->regmap);
433e27d9ee6SAxel Lin if (IS_ERR(drvdata->dac.virt_regmap)) {
43432a726b2SArnaud Pouliquen dev_err(&pdev->dev, "audio registers not enabled\n");
435e27d9ee6SAxel Lin return PTR_ERR(drvdata->dac.virt_regmap);
43632a726b2SArnaud Pouliquen }
43732a726b2SArnaud Pouliquen
43832a726b2SArnaud Pouliquen /* Request the syscon region */
43932a726b2SArnaud Pouliquen drvdata->dac.regmap =
44032a726b2SArnaud Pouliquen syscon_regmap_lookup_by_phandle(pnode, "st,syscfg");
441e27d9ee6SAxel Lin if (IS_ERR(drvdata->dac.regmap)) {
44232a726b2SArnaud Pouliquen dev_err(&pdev->dev, "syscon registers not available\n");
443e27d9ee6SAxel Lin return PTR_ERR(drvdata->dac.regmap);
44432a726b2SArnaud Pouliquen }
44532a726b2SArnaud Pouliquen drvdata->spdif.regmap = drvdata->dac.regmap;
44632a726b2SArnaud Pouliquen
44732a726b2SArnaud Pouliquen sti_sas_dai[STI_SAS_DAI_ANALOG_OUT].ops = drvdata->dev_data->dac_ops;
44832a726b2SArnaud Pouliquen
44932a726b2SArnaud Pouliquen /* Set dapms*/
450049c1bfcSKuninori Morimoto sti_sas_driver.dapm_widgets = drvdata->dev_data->dapm_widgets;
451049c1bfcSKuninori Morimoto sti_sas_driver.num_dapm_widgets = drvdata->dev_data->num_dapm_widgets;
45232a726b2SArnaud Pouliquen
453049c1bfcSKuninori Morimoto sti_sas_driver.dapm_routes = drvdata->dev_data->dapm_routes;
454049c1bfcSKuninori Morimoto sti_sas_driver.num_dapm_routes = drvdata->dev_data->num_dapm_routes;
45532a726b2SArnaud Pouliquen
45632a726b2SArnaud Pouliquen /* Store context */
45732a726b2SArnaud Pouliquen dev_set_drvdata(&pdev->dev, drvdata);
45832a726b2SArnaud Pouliquen
459049c1bfcSKuninori Morimoto return devm_snd_soc_register_component(&pdev->dev, &sti_sas_driver,
46032a726b2SArnaud Pouliquen sti_sas_dai,
46132a726b2SArnaud Pouliquen ARRAY_SIZE(sti_sas_dai));
46232a726b2SArnaud Pouliquen }
46332a726b2SArnaud Pouliquen
46432a726b2SArnaud Pouliquen static struct platform_driver sti_sas_platform_driver = {
46532a726b2SArnaud Pouliquen .driver = {
46632a726b2SArnaud Pouliquen .name = "sti-sas-codec",
46732a726b2SArnaud Pouliquen .of_match_table = sti_sas_dev_match,
46832a726b2SArnaud Pouliquen },
46932a726b2SArnaud Pouliquen .probe = sti_sas_driver_probe,
47032a726b2SArnaud Pouliquen };
47132a726b2SArnaud Pouliquen
47232a726b2SArnaud Pouliquen module_platform_driver(sti_sas_platform_driver);
47332a726b2SArnaud Pouliquen
47432a726b2SArnaud Pouliquen MODULE_DESCRIPTION("audio codec for STMicroelectronics sti platforms");
47532a726b2SArnaud Pouliquen MODULE_AUTHOR("Arnaud.pouliquen@st.com");
47632a726b2SArnaud Pouliquen MODULE_LICENSE("GPL v2");
477