xref: /openbmc/linux/sound/soc/codecs/sti-sas.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
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