1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (C) STMicroelectronics SA 2015
4 * Authors: Arnaud Pouliquen <arnaud.pouliquen@st.com>
5 * for STMicroelectronics.
6 */
7
8 #include <linux/io.h>
9 #include <linux/module.h>
10 #include <linux/regmap.h>
11 #include <linux/reset.h>
12 #include <linux/mfd/syscon.h>
13
14 #include <sound/soc.h>
15 #include <sound/soc-dapm.h>
16
17 /* DAC definitions */
18
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
24
25 /* DAC definitions */
26 #define STIH407_DAC_SOFTMUTE 0x0
27 #define STIH407_DAC_STANDBY_ANA 0x1
28 #define STIH407_DAC_STANDBY 0x2
29
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)
33
34 /* SPDIF definitions */
35 #define SPDIF_BIPHASE_ENABLE 0x6
36 #define SPDIF_BIPHASE_IDLE 0x7
37
38 #define SPDIF_BIPHASE_ENABLE_MASK BIT(SPDIF_BIPHASE_ENABLE)
39 #define SPDIF_BIPHASE_IDLE_MASK BIT(SPDIF_BIPHASE_IDLE)
40
41 enum {
42 STI_SAS_DAI_SPDIF_OUT,
43 STI_SAS_DAI_ANALOG_OUT,
44 };
45
46 static const struct reg_default stih407_sas_reg_defaults[] = {
47 { STIH407_AUDIO_DAC_CTRL, 0x000000000 },
48 { STIH407_AUDIO_GLUE_CTRL, 0x00000040 },
49 };
50
51 struct sti_dac_audio {
52 struct regmap *regmap;
53 struct regmap *virt_regmap;
54 int mclk;
55 };
56
57 struct sti_spdif_audio {
58 struct regmap *regmap;
59 int mclk;
60 };
61
62 /* device data structure */
63 struct sti_sas_dev_data {
64 const struct regmap_config *regmap;
65 const struct snd_soc_dai_ops *dac_ops; /* DAC function callbacks */
66 };
67
68 /* driver data structure */
69 struct sti_sas_data {
70 struct device *dev;
71 const struct sti_sas_dev_data *dev_data;
72 struct sti_dac_audio dac;
73 struct sti_spdif_audio spdif;
74 };
75
76 /* Read a register from the sysconf reg bank */
sti_sas_read_reg(void * context,unsigned int reg,unsigned int * value)77 static int sti_sas_read_reg(void *context, unsigned int reg,
78 unsigned int *value)
79 {
80 struct sti_sas_data *drvdata = context;
81 int status;
82 u32 val;
83
84 status = regmap_read(drvdata->dac.regmap, reg, &val);
85 *value = (unsigned int)val;
86
87 return status;
88 }
89
90 /* Read a register from the sysconf reg bank */
sti_sas_write_reg(void * context,unsigned int reg,unsigned int value)91 static int sti_sas_write_reg(void *context, unsigned int reg,
92 unsigned int value)
93 {
94 struct sti_sas_data *drvdata = context;
95
96 return regmap_write(drvdata->dac.regmap, reg, value);
97 }
98
sti_sas_init_sas_registers(struct snd_soc_component * component,struct sti_sas_data * data)99 static int sti_sas_init_sas_registers(struct snd_soc_component *component,
100 struct sti_sas_data *data)
101 {
102 int ret;
103 /*
104 * DAC and SPDIF are activated by default
105 * put them in IDLE to save power
106 */
107
108 /* Initialise bi-phase formatter to disabled */
109 ret = snd_soc_component_update_bits(component, STIH407_AUDIO_GLUE_CTRL,
110 SPDIF_BIPHASE_ENABLE_MASK, 0);
111
112 if (!ret)
113 /* Initialise bi-phase formatter idle value to 0 */
114 ret = snd_soc_component_update_bits(component, STIH407_AUDIO_GLUE_CTRL,
115 SPDIF_BIPHASE_IDLE_MASK, 0);
116 if (ret < 0) {
117 dev_err(component->dev, "Failed to update SPDIF registers\n");
118 return ret;
119 }
120
121 /* Init DAC configuration */
122 /* init configuration */
123 ret = snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
124 STIH407_DAC_STANDBY_MASK,
125 STIH407_DAC_STANDBY_MASK);
126
127 if (!ret)
128 ret = snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
129 STIH407_DAC_STANDBY_ANA_MASK,
130 STIH407_DAC_STANDBY_ANA_MASK);
131 if (!ret)
132 ret = snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
133 STIH407_DAC_SOFTMUTE_MASK,
134 STIH407_DAC_SOFTMUTE_MASK);
135
136 if (ret < 0) {
137 dev_err(component->dev, "Failed to update DAC registers\n");
138 return ret;
139 }
140
141 return ret;
142 }
143
144 /*
145 * DAC
146 */
sti_sas_dac_set_fmt(struct snd_soc_dai * dai,unsigned int fmt)147 static int sti_sas_dac_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
148 {
149 /* Sanity check only */
150 if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_CBC_CFC) {
151 dev_err(dai->component->dev,
152 "%s: ERROR: Unsupported clocking 0x%x\n",
153 __func__, fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK);
154 return -EINVAL;
155 }
156
157 return 0;
158 }
159
160 static const struct snd_soc_dapm_widget stih407_sas_dapm_widgets[] = {
161 SND_SOC_DAPM_OUT_DRV("DAC standby ana", STIH407_AUDIO_DAC_CTRL,
162 STIH407_DAC_STANDBY_ANA, 1, NULL, 0),
163 SND_SOC_DAPM_DAC("DAC standby", "dac_p", STIH407_AUDIO_DAC_CTRL,
164 STIH407_DAC_STANDBY, 1),
165 SND_SOC_DAPM_OUTPUT("DAC Output"),
166 };
167
168 static const struct snd_soc_dapm_route stih407_sas_route[] = {
169 {"DAC Output", NULL, "DAC standby ana"},
170 {"DAC standby ana", NULL, "DAC standby"},
171 };
172
173
stih407_sas_dac_mute(struct snd_soc_dai * dai,int mute,int stream)174 static int stih407_sas_dac_mute(struct snd_soc_dai *dai, int mute, int stream)
175 {
176 struct snd_soc_component *component = dai->component;
177
178 if (mute) {
179 return snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
180 STIH407_DAC_SOFTMUTE_MASK,
181 STIH407_DAC_SOFTMUTE_MASK);
182 } else {
183 return snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
184 STIH407_DAC_SOFTMUTE_MASK,
185 0);
186 }
187 }
188
189 /*
190 * SPDIF
191 */
sti_sas_spdif_set_fmt(struct snd_soc_dai * dai,unsigned int fmt)192 static int sti_sas_spdif_set_fmt(struct snd_soc_dai *dai,
193 unsigned int fmt)
194 {
195 if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_CBC_CFC) {
196 dev_err(dai->component->dev,
197 "%s: ERROR: Unsupported clocking mask 0x%x\n",
198 __func__, fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK);
199 return -EINVAL;
200 }
201
202 return 0;
203 }
204
205 /*
206 * sti_sas_spdif_trigger:
207 * Trigger function is used to ensure that BiPhase Formater is disabled
208 * before CPU dai is stopped.
209 * This is mandatory to avoid that BPF is stalled
210 */
sti_sas_spdif_trigger(struct snd_pcm_substream * substream,int cmd,struct snd_soc_dai * dai)211 static int sti_sas_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
212 struct snd_soc_dai *dai)
213 {
214 struct snd_soc_component *component = dai->component;
215
216 switch (cmd) {
217 case SNDRV_PCM_TRIGGER_START:
218 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
219 return snd_soc_component_update_bits(component, STIH407_AUDIO_GLUE_CTRL,
220 SPDIF_BIPHASE_ENABLE_MASK,
221 SPDIF_BIPHASE_ENABLE_MASK);
222 case SNDRV_PCM_TRIGGER_RESUME:
223 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
224 case SNDRV_PCM_TRIGGER_STOP:
225 case SNDRV_PCM_TRIGGER_SUSPEND:
226 return snd_soc_component_update_bits(component, STIH407_AUDIO_GLUE_CTRL,
227 SPDIF_BIPHASE_ENABLE_MASK,
228 0);
229 default:
230 return -EINVAL;
231 }
232 }
233
sti_sas_volatile_register(struct device * dev,unsigned int reg)234 static bool sti_sas_volatile_register(struct device *dev, unsigned int reg)
235 {
236 if (reg == STIH407_AUDIO_GLUE_CTRL)
237 return true;
238
239 return false;
240 }
241
242 /*
243 * CODEC DAIS
244 */
245
246 /*
247 * sti_sas_set_sysclk:
248 * get MCLK input frequency to check that MCLK-FS ratio is coherent
249 */
sti_sas_set_sysclk(struct snd_soc_dai * dai,int clk_id,unsigned int freq,int dir)250 static int sti_sas_set_sysclk(struct snd_soc_dai *dai, int clk_id,
251 unsigned int freq, int dir)
252 {
253 struct snd_soc_component *component = dai->component;
254 struct sti_sas_data *drvdata = dev_get_drvdata(component->dev);
255
256 if (dir == SND_SOC_CLOCK_OUT)
257 return 0;
258
259 if (clk_id != 0)
260 return -EINVAL;
261
262 switch (dai->id) {
263 case STI_SAS_DAI_SPDIF_OUT:
264 drvdata->spdif.mclk = freq;
265 break;
266
267 case STI_SAS_DAI_ANALOG_OUT:
268 drvdata->dac.mclk = freq;
269 break;
270 }
271
272 return 0;
273 }
274
sti_sas_prepare(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)275 static int sti_sas_prepare(struct snd_pcm_substream *substream,
276 struct snd_soc_dai *dai)
277 {
278 struct snd_soc_component *component = dai->component;
279 struct sti_sas_data *drvdata = dev_get_drvdata(component->dev);
280 struct snd_pcm_runtime *runtime = substream->runtime;
281
282 switch (dai->id) {
283 case STI_SAS_DAI_SPDIF_OUT:
284 if ((drvdata->spdif.mclk / runtime->rate) != 128) {
285 dev_err(component->dev, "unexpected mclk-fs ratio\n");
286 return -EINVAL;
287 }
288 break;
289 case STI_SAS_DAI_ANALOG_OUT:
290 if ((drvdata->dac.mclk / runtime->rate) != 256) {
291 dev_err(component->dev, "unexpected mclk-fs ratio\n");
292 return -EINVAL;
293 }
294 break;
295 }
296
297 return 0;
298 }
299
300 static const struct snd_soc_dai_ops stih407_dac_ops = {
301 .set_fmt = sti_sas_dac_set_fmt,
302 .mute_stream = stih407_sas_dac_mute,
303 .prepare = sti_sas_prepare,
304 .set_sysclk = sti_sas_set_sysclk,
305 };
306
307 static const struct regmap_config stih407_sas_regmap = {
308 .reg_bits = 32,
309 .val_bits = 32,
310 .fast_io = true,
311 .max_register = STIH407_AUDIO_DAC_CTRL,
312 .reg_defaults = stih407_sas_reg_defaults,
313 .num_reg_defaults = ARRAY_SIZE(stih407_sas_reg_defaults),
314 .volatile_reg = sti_sas_volatile_register,
315 .cache_type = REGCACHE_MAPLE,
316 .reg_read = sti_sas_read_reg,
317 .reg_write = sti_sas_write_reg,
318 };
319
320 static const struct sti_sas_dev_data stih407_data = {
321 .regmap = &stih407_sas_regmap,
322 .dac_ops = &stih407_dac_ops,
323 };
324
325 static struct snd_soc_dai_driver sti_sas_dai[] = {
326 {
327 .name = "sas-dai-spdif-out",
328 .id = STI_SAS_DAI_SPDIF_OUT,
329 .playback = {
330 .stream_name = "spdif_p",
331 .channels_min = 2,
332 .channels_max = 2,
333 .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
334 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 |
335 SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
336 SNDRV_PCM_RATE_192000,
337 .formats = SNDRV_PCM_FMTBIT_S16_LE |
338 SNDRV_PCM_FMTBIT_S32_LE,
339 },
340 .ops = (struct snd_soc_dai_ops[]) {
341 {
342 .set_fmt = sti_sas_spdif_set_fmt,
343 .trigger = sti_sas_spdif_trigger,
344 .set_sysclk = sti_sas_set_sysclk,
345 .prepare = sti_sas_prepare,
346 }
347 },
348 },
349 {
350 .name = "sas-dai-dac",
351 .id = STI_SAS_DAI_ANALOG_OUT,
352 .playback = {
353 .stream_name = "dac_p",
354 .channels_min = 2,
355 .channels_max = 2,
356 .rates = SNDRV_PCM_RATE_8000_48000,
357 .formats = SNDRV_PCM_FMTBIT_S16_LE |
358 SNDRV_PCM_FMTBIT_S32_LE,
359 },
360 },
361 };
362
363 #ifdef CONFIG_PM_SLEEP
sti_sas_resume(struct snd_soc_component * component)364 static int sti_sas_resume(struct snd_soc_component *component)
365 {
366 struct sti_sas_data *drvdata = dev_get_drvdata(component->dev);
367
368 return sti_sas_init_sas_registers(component, drvdata);
369 }
370 #else
371 #define sti_sas_resume NULL
372 #endif
373
sti_sas_component_probe(struct snd_soc_component * component)374 static int sti_sas_component_probe(struct snd_soc_component *component)
375 {
376 struct sti_sas_data *drvdata = dev_get_drvdata(component->dev);
377
378 return sti_sas_init_sas_registers(component, drvdata);
379 }
380
381 static const struct snd_soc_component_driver sti_sas_driver = {
382 .probe = sti_sas_component_probe,
383 .resume = sti_sas_resume,
384 .idle_bias_on = 1,
385 .use_pmdown_time = 1,
386 .endianness = 1,
387 .dapm_widgets = stih407_sas_dapm_widgets,
388 .num_dapm_widgets = ARRAY_SIZE(stih407_sas_dapm_widgets),
389 .dapm_routes = stih407_sas_route,
390 .num_dapm_routes = ARRAY_SIZE(stih407_sas_route),
391 };
392
393 static const struct of_device_id sti_sas_dev_match[] = {
394 {
395 .compatible = "st,stih407-sas-codec",
396 .data = &stih407_data,
397 },
398 {},
399 };
400 MODULE_DEVICE_TABLE(of, sti_sas_dev_match);
401
sti_sas_driver_probe(struct platform_device * pdev)402 static int sti_sas_driver_probe(struct platform_device *pdev)
403 {
404 struct device_node *pnode = pdev->dev.of_node;
405 struct sti_sas_data *drvdata;
406 const struct of_device_id *of_id;
407
408 /* Allocate device structure */
409 drvdata = devm_kzalloc(&pdev->dev, sizeof(struct sti_sas_data),
410 GFP_KERNEL);
411 if (!drvdata)
412 return -ENOMEM;
413
414 /* Populate data structure depending on compatibility */
415 of_id = of_match_node(sti_sas_dev_match, pnode);
416 if (!of_id->data) {
417 dev_err(&pdev->dev, "data associated to device is missing\n");
418 return -EINVAL;
419 }
420
421 drvdata->dev_data = (struct sti_sas_dev_data *)of_id->data;
422
423 /* Initialise device structure */
424 drvdata->dev = &pdev->dev;
425
426 /* Request the DAC & SPDIF registers memory region */
427 drvdata->dac.virt_regmap = devm_regmap_init(&pdev->dev, NULL, drvdata,
428 drvdata->dev_data->regmap);
429 if (IS_ERR(drvdata->dac.virt_regmap)) {
430 dev_err(&pdev->dev, "audio registers not enabled\n");
431 return PTR_ERR(drvdata->dac.virt_regmap);
432 }
433
434 /* Request the syscon region */
435 drvdata->dac.regmap =
436 syscon_regmap_lookup_by_phandle(pnode, "st,syscfg");
437 if (IS_ERR(drvdata->dac.regmap)) {
438 dev_err(&pdev->dev, "syscon registers not available\n");
439 return PTR_ERR(drvdata->dac.regmap);
440 }
441 drvdata->spdif.regmap = drvdata->dac.regmap;
442
443 sti_sas_dai[STI_SAS_DAI_ANALOG_OUT].ops = drvdata->dev_data->dac_ops;
444
445 /* Store context */
446 dev_set_drvdata(&pdev->dev, drvdata);
447
448 return devm_snd_soc_register_component(&pdev->dev, &sti_sas_driver,
449 sti_sas_dai,
450 ARRAY_SIZE(sti_sas_dai));
451 }
452
453 static struct platform_driver sti_sas_platform_driver = {
454 .driver = {
455 .name = "sti-sas-codec",
456 .of_match_table = sti_sas_dev_match,
457 },
458 .probe = sti_sas_driver_probe,
459 };
460
461 module_platform_driver(sti_sas_platform_driver);
462
463 MODULE_DESCRIPTION("audio codec for STMicroelectronics sti platforms");
464 MODULE_AUTHOR("Arnaud.pouliquen@st.com");
465 MODULE_LICENSE("GPL v2");
466