1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) STMicroelectronics SA 2015
4 * Authors: Arnaud Pouliquen <arnaud.pouliquen@st.com>
5 * for STMicroelectronics.
9 #include <linux/module.h>
10 #include <linux/regmap.h>
11 #include <linux/reset.h>
12 #include <linux/mfd/syscon.h>
14 #include <sound/soc.h>
15 #include <sound/soc-dapm.h>
19 /* stih407 DAC registers */
20 /* sysconf 5041: Audio-Gue-Control */
21 #define STIH407_AUDIO_GLUE_CTRL 0x000000A4
22 /* sysconf 5042: Audio-DAC-Control */
23 #define STIH407_AUDIO_DAC_CTRL 0x000000A8
26 #define STIH407_DAC_SOFTMUTE 0x0
27 #define STIH407_DAC_STANDBY_ANA 0x1
28 #define STIH407_DAC_STANDBY 0x2
30 #define STIH407_DAC_SOFTMUTE_MASK BIT(STIH407_DAC_SOFTMUTE)
31 #define STIH407_DAC_STANDBY_ANA_MASK BIT(STIH407_DAC_STANDBY_ANA)
32 #define STIH407_DAC_STANDBY_MASK BIT(STIH407_DAC_STANDBY)
34 /* SPDIF definitions */
35 #define SPDIF_BIPHASE_ENABLE 0x6
36 #define SPDIF_BIPHASE_IDLE 0x7
38 #define SPDIF_BIPHASE_ENABLE_MASK BIT(SPDIF_BIPHASE_ENABLE)
39 #define SPDIF_BIPHASE_IDLE_MASK BIT(SPDIF_BIPHASE_IDLE)
42 STI_SAS_DAI_SPDIF_OUT
,
43 STI_SAS_DAI_ANALOG_OUT
,
46 static const struct reg_default stih407_sas_reg_defaults
[] = {
47 { STIH407_AUDIO_DAC_CTRL
, 0x000000000 },
48 { STIH407_AUDIO_GLUE_CTRL
, 0x00000040 },
51 struct sti_dac_audio
{
52 struct regmap
*regmap
;
53 struct regmap
*virt_regmap
;
54 struct regmap_field
**field
;
55 struct reset_control
*rst
;
59 struct sti_spdif_audio
{
60 struct regmap
*regmap
;
61 struct regmap_field
**field
;
65 /* device data structure */
66 struct sti_sas_dev_data
{
67 const struct regmap_config
*regmap
;
68 const struct snd_soc_dai_ops
*dac_ops
; /* DAC function callbacks */
69 const struct snd_soc_dapm_widget
*dapm_widgets
; /* dapms declaration */
70 const int num_dapm_widgets
; /* dapms declaration */
71 const struct snd_soc_dapm_route
*dapm_routes
; /* route declaration */
72 const int num_dapm_routes
; /* route declaration */
75 /* driver data structure */
78 const struct sti_sas_dev_data
*dev_data
;
79 struct sti_dac_audio dac
;
80 struct sti_spdif_audio spdif
;
83 /* Read a register from the sysconf reg bank */
84 static int sti_sas_read_reg(void *context
, unsigned int reg
,
87 struct sti_sas_data
*drvdata
= context
;
91 status
= regmap_read(drvdata
->dac
.regmap
, reg
, &val
);
92 *value
= (unsigned int)val
;
97 /* Read a register from the sysconf reg bank */
98 static int sti_sas_write_reg(void *context
, unsigned int reg
,
101 struct sti_sas_data
*drvdata
= context
;
104 status
= regmap_write(drvdata
->dac
.regmap
, reg
, value
);
109 static int sti_sas_init_sas_registers(struct snd_soc_component
*component
,
110 struct sti_sas_data
*data
)
114 * DAC and SPDIF are activated by default
115 * put them in IDLE to save power
118 /* Initialise bi-phase formatter to disabled */
119 ret
= snd_soc_component_update_bits(component
, STIH407_AUDIO_GLUE_CTRL
,
120 SPDIF_BIPHASE_ENABLE_MASK
, 0);
123 /* Initialise bi-phase formatter idle value to 0 */
124 ret
= snd_soc_component_update_bits(component
, STIH407_AUDIO_GLUE_CTRL
,
125 SPDIF_BIPHASE_IDLE_MASK
, 0);
127 dev_err(component
->dev
, "Failed to update SPDIF registers\n");
131 /* Init DAC configuration */
132 /* init configuration */
133 ret
= snd_soc_component_update_bits(component
, STIH407_AUDIO_DAC_CTRL
,
134 STIH407_DAC_STANDBY_MASK
,
135 STIH407_DAC_STANDBY_MASK
);
138 ret
= snd_soc_component_update_bits(component
, STIH407_AUDIO_DAC_CTRL
,
139 STIH407_DAC_STANDBY_ANA_MASK
,
140 STIH407_DAC_STANDBY_ANA_MASK
);
142 ret
= snd_soc_component_update_bits(component
, STIH407_AUDIO_DAC_CTRL
,
143 STIH407_DAC_SOFTMUTE_MASK
,
144 STIH407_DAC_SOFTMUTE_MASK
);
147 dev_err(component
->dev
, "Failed to update DAC registers\n");
157 static int sti_sas_dac_set_fmt(struct snd_soc_dai
*dai
, unsigned int fmt
)
159 /* Sanity check only */
160 if ((fmt
& SND_SOC_DAIFMT_MASTER_MASK
) != SND_SOC_DAIFMT_CBS_CFS
) {
161 dev_err(dai
->component
->dev
,
162 "%s: ERROR: Unsupporter master mask 0x%x\n",
163 __func__
, fmt
& SND_SOC_DAIFMT_MASTER_MASK
);
170 static const struct snd_soc_dapm_widget stih407_sas_dapm_widgets
[] = {
171 SND_SOC_DAPM_OUT_DRV("DAC standby ana", STIH407_AUDIO_DAC_CTRL
,
172 STIH407_DAC_STANDBY_ANA
, 1, NULL
, 0),
173 SND_SOC_DAPM_DAC("DAC standby", "dac_p", STIH407_AUDIO_DAC_CTRL
,
174 STIH407_DAC_STANDBY
, 1),
175 SND_SOC_DAPM_OUTPUT("DAC Output"),
178 static const struct snd_soc_dapm_route stih407_sas_route
[] = {
179 {"DAC Output", NULL
, "DAC standby ana"},
180 {"DAC standby ana", NULL
, "DAC standby"},
184 static int stih407_sas_dac_mute(struct snd_soc_dai
*dai
, int mute
, int stream
)
186 struct snd_soc_component
*component
= dai
->component
;
189 return snd_soc_component_update_bits(component
, STIH407_AUDIO_DAC_CTRL
,
190 STIH407_DAC_SOFTMUTE_MASK
,
191 STIH407_DAC_SOFTMUTE_MASK
);
193 return snd_soc_component_update_bits(component
, STIH407_AUDIO_DAC_CTRL
,
194 STIH407_DAC_SOFTMUTE_MASK
,
202 static int sti_sas_spdif_set_fmt(struct snd_soc_dai
*dai
,
205 if ((fmt
& SND_SOC_DAIFMT_MASTER_MASK
) != SND_SOC_DAIFMT_CBS_CFS
) {
206 dev_err(dai
->component
->dev
,
207 "%s: ERROR: Unsupporter master mask 0x%x\n",
208 __func__
, fmt
& SND_SOC_DAIFMT_MASTER_MASK
);
216 * sti_sas_spdif_trigger:
217 * Trigger function is used to ensure that BiPhase Formater is disabled
218 * before CPU dai is stopped.
219 * This is mandatory to avoid that BPF is stalled
221 static int sti_sas_spdif_trigger(struct snd_pcm_substream
*substream
, int cmd
,
222 struct snd_soc_dai
*dai
)
224 struct snd_soc_component
*component
= dai
->component
;
227 case SNDRV_PCM_TRIGGER_START
:
228 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
229 return snd_soc_component_update_bits(component
, STIH407_AUDIO_GLUE_CTRL
,
230 SPDIF_BIPHASE_ENABLE_MASK
,
231 SPDIF_BIPHASE_ENABLE_MASK
);
232 case SNDRV_PCM_TRIGGER_RESUME
:
233 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
234 case SNDRV_PCM_TRIGGER_STOP
:
235 case SNDRV_PCM_TRIGGER_SUSPEND
:
236 return snd_soc_component_update_bits(component
, STIH407_AUDIO_GLUE_CTRL
,
237 SPDIF_BIPHASE_ENABLE_MASK
,
244 static bool sti_sas_volatile_register(struct device
*dev
, unsigned int reg
)
246 if (reg
== STIH407_AUDIO_GLUE_CTRL
)
257 * sti_sas_set_sysclk:
258 * get MCLK input frequency to check that MCLK-FS ratio is coherent
260 static int sti_sas_set_sysclk(struct snd_soc_dai
*dai
, int clk_id
,
261 unsigned int freq
, int dir
)
263 struct snd_soc_component
*component
= dai
->component
;
264 struct sti_sas_data
*drvdata
= dev_get_drvdata(component
->dev
);
266 if (dir
== SND_SOC_CLOCK_OUT
)
273 case STI_SAS_DAI_SPDIF_OUT
:
274 drvdata
->spdif
.mclk
= freq
;
277 case STI_SAS_DAI_ANALOG_OUT
:
278 drvdata
->dac
.mclk
= freq
;
285 static int sti_sas_prepare(struct snd_pcm_substream
*substream
,
286 struct snd_soc_dai
*dai
)
288 struct snd_soc_component
*component
= dai
->component
;
289 struct sti_sas_data
*drvdata
= dev_get_drvdata(component
->dev
);
290 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
293 case STI_SAS_DAI_SPDIF_OUT
:
294 if ((drvdata
->spdif
.mclk
/ runtime
->rate
) != 128) {
295 dev_err(component
->dev
, "unexpected mclk-fs ratio\n");
299 case STI_SAS_DAI_ANALOG_OUT
:
300 if ((drvdata
->dac
.mclk
/ runtime
->rate
) != 256) {
301 dev_err(component
->dev
, "unexpected mclk-fs ratio\n");
310 static const struct snd_soc_dai_ops stih407_dac_ops
= {
311 .set_fmt
= sti_sas_dac_set_fmt
,
312 .mute_stream
= stih407_sas_dac_mute
,
313 .prepare
= sti_sas_prepare
,
314 .set_sysclk
= sti_sas_set_sysclk
,
317 static const struct regmap_config stih407_sas_regmap
= {
321 .max_register
= STIH407_AUDIO_DAC_CTRL
,
322 .reg_defaults
= stih407_sas_reg_defaults
,
323 .num_reg_defaults
= ARRAY_SIZE(stih407_sas_reg_defaults
),
324 .volatile_reg
= sti_sas_volatile_register
,
325 .cache_type
= REGCACHE_RBTREE
,
326 .reg_read
= sti_sas_read_reg
,
327 .reg_write
= sti_sas_write_reg
,
330 static const struct sti_sas_dev_data stih407_data
= {
331 .regmap
= &stih407_sas_regmap
,
332 .dac_ops
= &stih407_dac_ops
,
333 .dapm_widgets
= stih407_sas_dapm_widgets
,
334 .num_dapm_widgets
= ARRAY_SIZE(stih407_sas_dapm_widgets
),
335 .dapm_routes
= stih407_sas_route
,
336 .num_dapm_routes
= ARRAY_SIZE(stih407_sas_route
),
339 static struct snd_soc_dai_driver sti_sas_dai
[] = {
341 .name
= "sas-dai-spdif-out",
342 .id
= STI_SAS_DAI_SPDIF_OUT
,
344 .stream_name
= "spdif_p",
347 .rates
= SNDRV_PCM_RATE_32000
| SNDRV_PCM_RATE_44100
|
348 SNDRV_PCM_RATE_48000
| SNDRV_PCM_RATE_64000
|
349 SNDRV_PCM_RATE_88200
| SNDRV_PCM_RATE_96000
|
350 SNDRV_PCM_RATE_192000
,
351 .formats
= SNDRV_PCM_FMTBIT_S16_LE
|
352 SNDRV_PCM_FMTBIT_S32_LE
,
354 .ops
= (struct snd_soc_dai_ops
[]) {
356 .set_fmt
= sti_sas_spdif_set_fmt
,
357 .trigger
= sti_sas_spdif_trigger
,
358 .set_sysclk
= sti_sas_set_sysclk
,
359 .prepare
= sti_sas_prepare
,
364 .name
= "sas-dai-dac",
365 .id
= STI_SAS_DAI_ANALOG_OUT
,
367 .stream_name
= "dac_p",
370 .rates
= SNDRV_PCM_RATE_8000_48000
,
371 .formats
= SNDRV_PCM_FMTBIT_S16_LE
|
372 SNDRV_PCM_FMTBIT_S32_LE
,
377 #ifdef CONFIG_PM_SLEEP
378 static int sti_sas_resume(struct snd_soc_component
*component
)
380 struct sti_sas_data
*drvdata
= dev_get_drvdata(component
->dev
);
382 return sti_sas_init_sas_registers(component
, drvdata
);
385 #define sti_sas_resume NULL
388 static int sti_sas_component_probe(struct snd_soc_component
*component
)
390 struct sti_sas_data
*drvdata
= dev_get_drvdata(component
->dev
);
393 ret
= sti_sas_init_sas_registers(component
, drvdata
);
398 static struct snd_soc_component_driver sti_sas_driver
= {
399 .probe
= sti_sas_component_probe
,
400 .resume
= sti_sas_resume
,
402 .use_pmdown_time
= 1,
404 .non_legacy_dai_naming
= 1,
407 static const struct of_device_id sti_sas_dev_match
[] = {
409 .compatible
= "st,stih407-sas-codec",
410 .data
= &stih407_data
,
415 static int sti_sas_driver_probe(struct platform_device
*pdev
)
417 struct device_node
*pnode
= pdev
->dev
.of_node
;
418 struct sti_sas_data
*drvdata
;
419 const struct of_device_id
*of_id
;
421 /* Allocate device structure */
422 drvdata
= devm_kzalloc(&pdev
->dev
, sizeof(struct sti_sas_data
),
427 /* Populate data structure depending on compatibility */
428 of_id
= of_match_node(sti_sas_dev_match
, pnode
);
430 dev_err(&pdev
->dev
, "data associated to device is missing\n");
434 drvdata
->dev_data
= (struct sti_sas_dev_data
*)of_id
->data
;
436 /* Initialise device structure */
437 drvdata
->dev
= &pdev
->dev
;
439 /* Request the DAC & SPDIF registers memory region */
440 drvdata
->dac
.virt_regmap
= devm_regmap_init(&pdev
->dev
, NULL
, drvdata
,
441 drvdata
->dev_data
->regmap
);
442 if (IS_ERR(drvdata
->dac
.virt_regmap
)) {
443 dev_err(&pdev
->dev
, "audio registers not enabled\n");
444 return PTR_ERR(drvdata
->dac
.virt_regmap
);
447 /* Request the syscon region */
448 drvdata
->dac
.regmap
=
449 syscon_regmap_lookup_by_phandle(pnode
, "st,syscfg");
450 if (IS_ERR(drvdata
->dac
.regmap
)) {
451 dev_err(&pdev
->dev
, "syscon registers not available\n");
452 return PTR_ERR(drvdata
->dac
.regmap
);
454 drvdata
->spdif
.regmap
= drvdata
->dac
.regmap
;
456 sti_sas_dai
[STI_SAS_DAI_ANALOG_OUT
].ops
= drvdata
->dev_data
->dac_ops
;
459 sti_sas_driver
.dapm_widgets
= drvdata
->dev_data
->dapm_widgets
;
460 sti_sas_driver
.num_dapm_widgets
= drvdata
->dev_data
->num_dapm_widgets
;
462 sti_sas_driver
.dapm_routes
= drvdata
->dev_data
->dapm_routes
;
463 sti_sas_driver
.num_dapm_routes
= drvdata
->dev_data
->num_dapm_routes
;
466 dev_set_drvdata(&pdev
->dev
, drvdata
);
468 return devm_snd_soc_register_component(&pdev
->dev
, &sti_sas_driver
,
470 ARRAY_SIZE(sti_sas_dai
));
473 static struct platform_driver sti_sas_platform_driver
= {
475 .name
= "sti-sas-codec",
476 .of_match_table
= sti_sas_dev_match
,
478 .probe
= sti_sas_driver_probe
,
481 module_platform_driver(sti_sas_platform_driver
);
483 MODULE_DESCRIPTION("audio codec for STMicroelectronics sti platforms");
484 MODULE_AUTHOR("Arnaud.pouliquen@st.com");
485 MODULE_LICENSE("GPL v2");