1// SPDX-License-Identifier: GPL-2.0-only
2//
3// Cirrus Logic Madera class codecs common support
4//
5// Copyright (C) 2015-2019 Cirrus Logic, Inc. and
6// Cirrus Logic International Semiconductor Ltd.
7//
8
9#include <linux/delay.h>
10#include <linux/gcd.h>
11#include <linux/module.h>
12#include <linux/pm_runtime.h>
13#include <linux/slab.h>
14#include <sound/pcm.h>
15#include <sound/pcm_params.h>
16#include <sound/tlv.h>
17
18#include <linux/irqchip/irq-madera.h>
19#include <linux/mfd/madera/core.h>
20#include <linux/mfd/madera/registers.h>
21#include <linux/mfd/madera/pdata.h>
22#include <sound/madera-pdata.h>
23
24#include <dt-bindings/sound/madera.h>
25
26#include "madera.h"
27
28#define MADERA_AIF_BCLK_CTRL 0x00
29#define MADERA_AIF_TX_PIN_CTRL 0x01
30#define MADERA_AIF_RX_PIN_CTRL 0x02
31#define MADERA_AIF_RATE_CTRL 0x03
32#define MADERA_AIF_FORMAT 0x04
33#define MADERA_AIF_RX_BCLK_RATE 0x06
34#define MADERA_AIF_FRAME_CTRL_1 0x07
35#define MADERA_AIF_FRAME_CTRL_2 0x08
36#define MADERA_AIF_FRAME_CTRL_3 0x09
37#define MADERA_AIF_FRAME_CTRL_4 0x0A
38#define MADERA_AIF_FRAME_CTRL_5 0x0B
39#define MADERA_AIF_FRAME_CTRL_6 0x0C
40#define MADERA_AIF_FRAME_CTRL_7 0x0D
41#define MADERA_AIF_FRAME_CTRL_8 0x0E
42#define MADERA_AIF_FRAME_CTRL_9 0x0F
43#define MADERA_AIF_FRAME_CTRL_10 0x10
44#define MADERA_AIF_FRAME_CTRL_11 0x11
45#define MADERA_AIF_FRAME_CTRL_12 0x12
46#define MADERA_AIF_FRAME_CTRL_13 0x13
47#define MADERA_AIF_FRAME_CTRL_14 0x14
48#define MADERA_AIF_FRAME_CTRL_15 0x15
49#define MADERA_AIF_FRAME_CTRL_16 0x16
50#define MADERA_AIF_FRAME_CTRL_17 0x17
51#define MADERA_AIF_FRAME_CTRL_18 0x18
52#define MADERA_AIF_TX_ENABLES 0x19
53#define MADERA_AIF_RX_ENABLES 0x1A
54#define MADERA_AIF_FORCE_WRITE 0x1B
55
56#define MADERA_DSP_CONFIG_1_OFFS 0x00
57#define MADERA_DSP_CONFIG_2_OFFS 0x02
58
59#define MADERA_DSP_CLK_SEL_MASK 0x70000
60#define MADERA_DSP_CLK_SEL_SHIFT 16
61
62#define MADERA_DSP_RATE_MASK 0x7800
63#define MADERA_DSP_RATE_SHIFT 11
64
65#define MADERA_SYSCLK_6MHZ 0
66#define MADERA_SYSCLK_12MHZ 1
67#define MADERA_SYSCLK_24MHZ 2
68#define MADERA_SYSCLK_49MHZ 3
69#define MADERA_SYSCLK_98MHZ 4
70
71#define MADERA_DSPCLK_9MHZ 0
72#define MADERA_DSPCLK_18MHZ 1
73#define MADERA_DSPCLK_36MHZ 2
74#define MADERA_DSPCLK_73MHZ 3
75#define MADERA_DSPCLK_147MHZ 4
76
77#define MADERA_FLL_VCO_CORNER 141900000
78#define MADERA_FLL_MAX_FREF 13500000
79#define MADERA_FLL_MAX_N 1023
80#define MADERA_FLL_MIN_FOUT 90000000
81#define MADERA_FLL_MAX_FOUT 100000000
82#define MADERA_FLL_MAX_FRATIO 16
83#define MADERA_FLL_MAX_REFDIV 8
84#define MADERA_FLL_OUTDIV 3
85#define MADERA_FLL_VCO_MULT 3
86#define MADERA_FLLAO_MAX_FREF 12288000
87#define MADERA_FLLAO_MIN_N 4
88#define MADERA_FLLAO_MAX_N 1023
89#define MADERA_FLLAO_MAX_FBDIV 254
90#define MADERA_FLLHJ_INT_MAX_N 1023
91#define MADERA_FLLHJ_INT_MIN_N 1
92#define MADERA_FLLHJ_FRAC_MAX_N 255
93#define MADERA_FLLHJ_FRAC_MIN_N 4
94#define MADERA_FLLHJ_LOW_THRESH 192000
95#define MADERA_FLLHJ_MID_THRESH 1152000
96#define MADERA_FLLHJ_MAX_THRESH 13000000
97#define MADERA_FLLHJ_LOW_GAINS 0x23f0
98#define MADERA_FLLHJ_MID_GAINS 0x22f2
99#define MADERA_FLLHJ_HIGH_GAINS 0x21f0
100
101#define MADERA_FLL_SYNCHRONISER_OFFS 0x10
102#define CS47L35_FLL_SYNCHRONISER_OFFS 0xE
103#define MADERA_FLL_CONTROL_1_OFFS 0x1
104#define MADERA_FLL_CONTROL_2_OFFS 0x2
105#define MADERA_FLL_CONTROL_3_OFFS 0x3
106#define MADERA_FLL_CONTROL_4_OFFS 0x4
107#define MADERA_FLL_CONTROL_5_OFFS 0x5
108#define MADERA_FLL_CONTROL_6_OFFS 0x6
109#define MADERA_FLL_GAIN_OFFS 0x8
110#define MADERA_FLL_CONTROL_7_OFFS 0x9
111#define MADERA_FLL_EFS_2_OFFS 0xA
112#define MADERA_FLL_SYNCHRONISER_1_OFFS 0x1
113#define MADERA_FLL_SYNCHRONISER_2_OFFS 0x2
114#define MADERA_FLL_SYNCHRONISER_3_OFFS 0x3
115#define MADERA_FLL_SYNCHRONISER_4_OFFS 0x4
116#define MADERA_FLL_SYNCHRONISER_5_OFFS 0x5
117#define MADERA_FLL_SYNCHRONISER_6_OFFS 0x6
118#define MADERA_FLL_SYNCHRONISER_7_OFFS 0x7
119#define MADERA_FLL_SPREAD_SPECTRUM_OFFS 0x9
120#define MADERA_FLL_GPIO_CLOCK_OFFS 0xA
121#define MADERA_FLL_CONTROL_10_OFFS 0xA
122#define MADERA_FLL_CONTROL_11_OFFS 0xB
123#define MADERA_FLL1_DIGITAL_TEST_1_OFFS 0xD
124
125#define MADERA_FLLAO_CONTROL_1_OFFS 0x1
126#define MADERA_FLLAO_CONTROL_2_OFFS 0x2
127#define MADERA_FLLAO_CONTROL_3_OFFS 0x3
128#define MADERA_FLLAO_CONTROL_4_OFFS 0x4
129#define MADERA_FLLAO_CONTROL_5_OFFS 0x5
130#define MADERA_FLLAO_CONTROL_6_OFFS 0x6
131#define MADERA_FLLAO_CONTROL_7_OFFS 0x8
132#define MADERA_FLLAO_CONTROL_8_OFFS 0xA
133#define MADERA_FLLAO_CONTROL_9_OFFS 0xB
134#define MADERA_FLLAO_CONTROL_10_OFFS 0xC
135#define MADERA_FLLAO_CONTROL_11_OFFS 0xD
136
137#define MADERA_FMT_DSP_MODE_A 0
138#define MADERA_FMT_DSP_MODE_B 1
139#define MADERA_FMT_I2S_MODE 2
140#define MADERA_FMT_LEFT_JUSTIFIED_MODE 3
141
142#define madera_fll_err(_fll, fmt, ...) \
143 dev_err(_fll->madera->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
144#define madera_fll_warn(_fll, fmt, ...) \
145 dev_warn(_fll->madera->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
146#define madera_fll_dbg(_fll, fmt, ...) \
147 dev_dbg(_fll->madera->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
148
149#define madera_aif_err(_dai, fmt, ...) \
150 dev_err(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
151#define madera_aif_warn(_dai, fmt, ...) \
152 dev_warn(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
153#define madera_aif_dbg(_dai, fmt, ...) \
154 dev_dbg(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
155
156static const int madera_dsp_bus_error_irqs[MADERA_MAX_ADSP] = {
157 MADERA_IRQ_DSP1_BUS_ERR,
158 MADERA_IRQ_DSP2_BUS_ERR,
159 MADERA_IRQ_DSP3_BUS_ERR,
160 MADERA_IRQ_DSP4_BUS_ERR,
161 MADERA_IRQ_DSP5_BUS_ERR,
162 MADERA_IRQ_DSP6_BUS_ERR,
163 MADERA_IRQ_DSP7_BUS_ERR,
164};
165
166int madera_clk_ev(struct snd_soc_dapm_widget *w,
167 struct snd_kcontrol *kcontrol, int event)
168{
169 struct snd_soc_component *component = snd_soc_dapm_to_component(dapm: w->dapm);
170 struct madera_priv *priv = snd_soc_component_get_drvdata(c: component);
171 struct madera *madera = priv->madera;
172 unsigned int val;
173 int clk_idx;
174 int ret;
175
176 ret = regmap_read(map: madera->regmap, reg: w->reg, val: &val);
177 if (ret) {
178 dev_err(madera->dev, "Failed to check clock source: %d\n", ret);
179 return ret;
180 }
181
182 switch ((val & MADERA_SYSCLK_SRC_MASK) >> MADERA_SYSCLK_SRC_SHIFT) {
183 case MADERA_CLK_SRC_MCLK1:
184 clk_idx = MADERA_MCLK1;
185 break;
186 case MADERA_CLK_SRC_MCLK2:
187 clk_idx = MADERA_MCLK2;
188 break;
189 case MADERA_CLK_SRC_MCLK3:
190 clk_idx = MADERA_MCLK3;
191 break;
192 default:
193 return 0;
194 }
195
196 switch (event) {
197 case SND_SOC_DAPM_PRE_PMU:
198 return clk_prepare_enable(clk: madera->mclk[clk_idx].clk);
199 case SND_SOC_DAPM_POST_PMD:
200 clk_disable_unprepare(clk: madera->mclk[clk_idx].clk);
201 return 0;
202 default:
203 return 0;
204 }
205}
206EXPORT_SYMBOL_GPL(madera_clk_ev);
207
208static void madera_spin_sysclk(struct madera_priv *priv)
209{
210 struct madera *madera = priv->madera;
211 unsigned int val;
212 int ret, i;
213
214 /* Skip this if the chip is down */
215 if (pm_runtime_suspended(dev: madera->dev))
216 return;
217
218 /*
219 * Just read a register a few times to ensure the internal
220 * oscillator sends out a few clocks.
221 */
222 for (i = 0; i < 4; i++) {
223 ret = regmap_read(map: madera->regmap, MADERA_SOFTWARE_RESET, val: &val);
224 if (ret)
225 dev_err(madera->dev,
226 "Failed to read sysclk spin %d: %d\n", i, ret);
227 }
228
229 udelay(300);
230}
231
232int madera_sysclk_ev(struct snd_soc_dapm_widget *w,
233 struct snd_kcontrol *kcontrol, int event)
234{
235 struct snd_soc_component *component = snd_soc_dapm_to_component(dapm: w->dapm);
236 struct madera_priv *priv = snd_soc_component_get_drvdata(c: component);
237
238 switch (event) {
239 case SND_SOC_DAPM_POST_PMU:
240 case SND_SOC_DAPM_PRE_PMD:
241 madera_spin_sysclk(priv);
242 break;
243 default:
244 break;
245 }
246
247 return madera_clk_ev(w, kcontrol, event);
248}
249EXPORT_SYMBOL_GPL(madera_sysclk_ev);
250
251static int madera_check_speaker_overheat(struct madera *madera,
252 bool *warn, bool *shutdown)
253{
254 unsigned int val;
255 int ret;
256
257 ret = regmap_read(map: madera->regmap, MADERA_IRQ1_RAW_STATUS_15, val: &val);
258 if (ret) {
259 dev_err(madera->dev, "Failed to read thermal status: %d\n",
260 ret);
261 return ret;
262 }
263
264 *warn = val & MADERA_SPK_OVERHEAT_WARN_STS1;
265 *shutdown = val & MADERA_SPK_OVERHEAT_STS1;
266
267 return 0;
268}
269
270int madera_spk_ev(struct snd_soc_dapm_widget *w,
271 struct snd_kcontrol *kcontrol, int event)
272{
273 struct snd_soc_component *component = snd_soc_dapm_to_component(dapm: w->dapm);
274 struct madera_priv *priv = snd_soc_component_get_drvdata(c: component);
275 struct madera *madera = priv->madera;
276 bool warn, shutdown;
277 int ret;
278
279 switch (event) {
280 case SND_SOC_DAPM_POST_PMU:
281 ret = madera_check_speaker_overheat(madera, warn: &warn, shutdown: &shutdown);
282 if (ret)
283 return ret;
284
285 if (shutdown) {
286 dev_crit(madera->dev,
287 "Speaker not enabled due to temperature\n");
288 return -EBUSY;
289 }
290
291 regmap_update_bits(map: madera->regmap, MADERA_OUTPUT_ENABLES_1,
292 mask: 1 << w->shift, val: 1 << w->shift);
293 break;
294 case SND_SOC_DAPM_PRE_PMD:
295 regmap_update_bits(map: madera->regmap, MADERA_OUTPUT_ENABLES_1,
296 mask: 1 << w->shift, val: 0);
297 break;
298 default:
299 break;
300 }
301
302 return 0;
303}
304EXPORT_SYMBOL_GPL(madera_spk_ev);
305
306static irqreturn_t madera_thermal_warn(int irq, void *data)
307{
308 struct madera *madera = data;
309 bool warn, shutdown;
310 int ret;
311
312 ret = madera_check_speaker_overheat(madera, warn: &warn, shutdown: &shutdown);
313 if (ret || shutdown) { /* for safety attempt to shutdown on error */
314 dev_crit(madera->dev, "Thermal shutdown\n");
315 ret = regmap_update_bits(map: madera->regmap,
316 MADERA_OUTPUT_ENABLES_1,
317 MADERA_OUT4L_ENA |
318 MADERA_OUT4R_ENA, val: 0);
319 if (ret != 0)
320 dev_crit(madera->dev,
321 "Failed to disable speaker outputs: %d\n",
322 ret);
323 } else if (warn) {
324 dev_alert(madera->dev, "Thermal warning\n");
325 } else {
326 dev_info(madera->dev, "Spurious thermal warning\n");
327 return IRQ_NONE;
328 }
329
330 return IRQ_HANDLED;
331}
332
333int madera_init_overheat(struct madera_priv *priv)
334{
335 struct madera *madera = priv->madera;
336 struct device *dev = madera->dev;
337 int ret;
338
339 ret = madera_request_irq(madera, MADERA_IRQ_SPK_OVERHEAT_WARN,
340 name: "Thermal warning", handler: madera_thermal_warn,
341 data: madera);
342 if (ret)
343 dev_err(dev, "Failed to get thermal warning IRQ: %d\n", ret);
344
345 ret = madera_request_irq(madera, MADERA_IRQ_SPK_OVERHEAT,
346 name: "Thermal shutdown", handler: madera_thermal_warn,
347 data: madera);
348 if (ret)
349 dev_err(dev, "Failed to get thermal shutdown IRQ: %d\n", ret);
350
351 return 0;
352}
353EXPORT_SYMBOL_GPL(madera_init_overheat);
354
355int madera_free_overheat(struct madera_priv *priv)
356{
357 struct madera *madera = priv->madera;
358
359 madera_free_irq(madera, MADERA_IRQ_SPK_OVERHEAT_WARN, data: madera);
360 madera_free_irq(madera, MADERA_IRQ_SPK_OVERHEAT, data: madera);
361
362 return 0;
363}
364EXPORT_SYMBOL_GPL(madera_free_overheat);
365
366static int madera_get_variable_u32_array(struct device *dev,
367 const char *propname,
368 u32 *dest, int n_max,
369 int multiple)
370{
371 int n, ret;
372
373 n = device_property_count_u32(dev, propname);
374 if (n < 0) {
375 if (n == -EINVAL)
376 return 0; /* missing, ignore */
377
378 dev_warn(dev, "%s malformed (%d)\n", propname, n);
379
380 return n;
381 } else if ((n % multiple) != 0) {
382 dev_warn(dev, "%s not a multiple of %d entries\n",
383 propname, multiple);
384
385 return -EINVAL;
386 }
387
388 if (n > n_max)
389 n = n_max;
390
391 ret = device_property_read_u32_array(dev, propname, val: dest, nval: n);
392 if (ret < 0)
393 return ret;
394
395 return n;
396}
397
398static void madera_prop_get_inmode(struct madera_priv *priv)
399{
400 struct madera *madera = priv->madera;
401 struct madera_codec_pdata *pdata = &madera->pdata.codec;
402 u32 tmp[MADERA_MAX_INPUT * MADERA_MAX_MUXED_CHANNELS];
403 int n, i, in_idx, ch_idx;
404
405 BUILD_BUG_ON(ARRAY_SIZE(pdata->inmode) != MADERA_MAX_INPUT);
406 BUILD_BUG_ON(ARRAY_SIZE(pdata->inmode[0]) != MADERA_MAX_MUXED_CHANNELS);
407
408 n = madera_get_variable_u32_array(dev: madera->dev, propname: "cirrus,inmode",
409 dest: tmp, ARRAY_SIZE(tmp),
410 MADERA_MAX_MUXED_CHANNELS);
411 if (n < 0)
412 return;
413
414 in_idx = 0;
415 ch_idx = 0;
416 for (i = 0; i < n; ++i) {
417 pdata->inmode[in_idx][ch_idx] = tmp[i];
418
419 if (++ch_idx == MADERA_MAX_MUXED_CHANNELS) {
420 ch_idx = 0;
421 ++in_idx;
422 }
423 }
424}
425
426static void madera_prop_get_pdata(struct madera_priv *priv)
427{
428 struct madera *madera = priv->madera;
429 struct madera_codec_pdata *pdata = &madera->pdata.codec;
430 u32 out_mono[ARRAY_SIZE(pdata->out_mono)];
431 int i, n;
432
433 madera_prop_get_inmode(priv);
434
435 n = madera_get_variable_u32_array(dev: madera->dev, propname: "cirrus,out-mono",
436 dest: out_mono, ARRAY_SIZE(out_mono), multiple: 1);
437 if (n > 0)
438 for (i = 0; i < n; ++i)
439 pdata->out_mono[i] = !!out_mono[i];
440
441 madera_get_variable_u32_array(dev: madera->dev,
442 propname: "cirrus,max-channels-clocked",
443 dest: pdata->max_channels_clocked,
444 ARRAY_SIZE(pdata->max_channels_clocked),
445 multiple: 1);
446
447 madera_get_variable_u32_array(dev: madera->dev, propname: "cirrus,pdm-fmt",
448 dest: pdata->pdm_fmt,
449 ARRAY_SIZE(pdata->pdm_fmt), multiple: 1);
450
451 madera_get_variable_u32_array(dev: madera->dev, propname: "cirrus,pdm-mute",
452 dest: pdata->pdm_mute,
453 ARRAY_SIZE(pdata->pdm_mute), multiple: 1);
454
455 madera_get_variable_u32_array(dev: madera->dev, propname: "cirrus,dmic-ref",
456 dest: pdata->dmic_ref,
457 ARRAY_SIZE(pdata->dmic_ref), multiple: 1);
458}
459
460int madera_core_init(struct madera_priv *priv)
461{
462 int i;
463
464 /* trap undersized array initializers */
465 BUILD_BUG_ON(!madera_mixer_texts[MADERA_NUM_MIXER_INPUTS - 1]);
466 BUILD_BUG_ON(!madera_mixer_values[MADERA_NUM_MIXER_INPUTS - 1]);
467
468 if (!dev_get_platdata(dev: priv->madera->dev))
469 madera_prop_get_pdata(priv);
470
471 mutex_init(&priv->rate_lock);
472
473 for (i = 0; i < MADERA_MAX_HP_OUTPUT; i++)
474 priv->madera->out_clamp[i] = true;
475
476 return 0;
477}
478EXPORT_SYMBOL_GPL(madera_core_init);
479
480int madera_core_free(struct madera_priv *priv)
481{
482 mutex_destroy(lock: &priv->rate_lock);
483
484 return 0;
485}
486EXPORT_SYMBOL_GPL(madera_core_free);
487
488static void madera_debug_dump_domain_groups(const struct madera_priv *priv)
489{
490 struct madera *madera = priv->madera;
491 int i;
492
493 for (i = 0; i < ARRAY_SIZE(priv->domain_group_ref); ++i)
494 dev_dbg(madera->dev, "domain_grp_ref[%d]=%d\n", i,
495 priv->domain_group_ref[i]);
496}
497
498int madera_domain_clk_ev(struct snd_soc_dapm_widget *w,
499 struct snd_kcontrol *kcontrol,
500 int event)
501{
502 struct snd_soc_component *component = snd_soc_dapm_to_component(dapm: w->dapm);
503 struct madera_priv *priv = snd_soc_component_get_drvdata(c: component);
504 int dom_grp = w->shift;
505
506 if (dom_grp >= ARRAY_SIZE(priv->domain_group_ref)) {
507 WARN(true, "%s dom_grp exceeds array size\n", __func__);
508 return -EINVAL;
509 }
510
511 /*
512 * We can't rely on the DAPM mutex for locking because we need a lock
513 * that can safely be called in hw_params
514 */
515 mutex_lock(&priv->rate_lock);
516
517 switch (event) {
518 case SND_SOC_DAPM_PRE_PMU:
519 dev_dbg(priv->madera->dev, "Inc ref on domain group %d\n",
520 dom_grp);
521 ++priv->domain_group_ref[dom_grp];
522 break;
523 case SND_SOC_DAPM_POST_PMD:
524 dev_dbg(priv->madera->dev, "Dec ref on domain group %d\n",
525 dom_grp);
526 --priv->domain_group_ref[dom_grp];
527 break;
528 default:
529 break;
530 }
531
532 madera_debug_dump_domain_groups(priv);
533
534 mutex_unlock(lock: &priv->rate_lock);
535
536 return 0;
537}
538EXPORT_SYMBOL_GPL(madera_domain_clk_ev);
539
540int madera_out1_demux_put(struct snd_kcontrol *kcontrol,
541 struct snd_ctl_elem_value *ucontrol)
542{
543 struct snd_soc_component *component =
544 snd_soc_dapm_kcontrol_component(kcontrol);
545 struct snd_soc_dapm_context *dapm =
546 snd_soc_dapm_kcontrol_dapm(kcontrol);
547 struct madera_priv *priv = snd_soc_component_get_drvdata(c: component);
548 struct madera *madera = priv->madera;
549 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
550 unsigned int ep_sel, mux, change;
551 bool out_mono;
552 int ret;
553
554 if (ucontrol->value.enumerated.item[0] > e->items - 1)
555 return -EINVAL;
556
557 mux = ucontrol->value.enumerated.item[0];
558
559 snd_soc_dapm_mutex_lock(dapm);
560
561 ep_sel = mux << MADERA_EP_SEL_SHIFT;
562
563 change = snd_soc_component_test_bits(component, MADERA_OUTPUT_ENABLES_1,
564 MADERA_EP_SEL_MASK,
565 value: ep_sel);
566 if (!change)
567 goto end;
568
569 /* EP_SEL should not be modified while HP or EP driver is enabled */
570 ret = regmap_update_bits(map: madera->regmap, MADERA_OUTPUT_ENABLES_1,
571 MADERA_OUT1L_ENA | MADERA_OUT1R_ENA, val: 0);
572 if (ret)
573 dev_warn(madera->dev, "Failed to disable outputs: %d\n", ret);
574
575 usleep_range(min: 2000, max: 3000); /* wait for wseq to complete */
576
577 /* change demux setting */
578 ret = 0;
579 if (madera->out_clamp[0])
580 ret = regmap_update_bits(map: madera->regmap,
581 MADERA_OUTPUT_ENABLES_1,
582 MADERA_EP_SEL_MASK, val: ep_sel);
583 if (ret) {
584 dev_err(madera->dev, "Failed to set OUT1 demux: %d\n", ret);
585 } else {
586 /* apply correct setting for mono mode */
587 if (!ep_sel && !madera->pdata.codec.out_mono[0])
588 out_mono = false; /* stereo HP */
589 else
590 out_mono = true; /* EP or mono HP */
591
592 ret = madera_set_output_mode(component, output: 1, differential: out_mono);
593 if (ret)
594 dev_warn(madera->dev,
595 "Failed to set output mode: %d\n", ret);
596 }
597
598 /*
599 * if HPDET has disabled the clamp while switching to HPOUT
600 * OUT1 should remain disabled
601 */
602 if (ep_sel ||
603 (madera->out_clamp[0] && !madera->out_shorted[0])) {
604 ret = regmap_update_bits(map: madera->regmap,
605 MADERA_OUTPUT_ENABLES_1,
606 MADERA_OUT1L_ENA | MADERA_OUT1R_ENA,
607 val: madera->hp_ena);
608 if (ret)
609 dev_warn(madera->dev,
610 "Failed to restore earpiece outputs: %d\n",
611 ret);
612 else if (madera->hp_ena)
613 msleep(msecs: 34); /* wait for enable wseq */
614 else
615 usleep_range(min: 2000, max: 3000); /* wait for disable wseq */
616 }
617
618end:
619 snd_soc_dapm_mutex_unlock(dapm);
620
621 ret = snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL);
622 if (ret < 0) {
623 dev_err(madera->dev, "Failed to update demux power state: %d\n", ret);
624 return ret;
625 }
626
627 return change;
628}
629EXPORT_SYMBOL_GPL(madera_out1_demux_put);
630
631int madera_out1_demux_get(struct snd_kcontrol *kcontrol,
632 struct snd_ctl_elem_value *ucontrol)
633{
634 struct snd_soc_component *component =
635 snd_soc_dapm_kcontrol_component(kcontrol);
636 unsigned int val;
637
638 val = snd_soc_component_read(component, MADERA_OUTPUT_ENABLES_1);
639 val &= MADERA_EP_SEL_MASK;
640 val >>= MADERA_EP_SEL_SHIFT;
641 ucontrol->value.enumerated.item[0] = val;
642
643 return 0;
644}
645EXPORT_SYMBOL_GPL(madera_out1_demux_get);
646
647static int madera_inmux_put(struct snd_kcontrol *kcontrol,
648 struct snd_ctl_elem_value *ucontrol)
649{
650 struct snd_soc_component *component =
651 snd_soc_dapm_kcontrol_component(kcontrol);
652 struct snd_soc_dapm_context *dapm =
653 snd_soc_dapm_kcontrol_dapm(kcontrol);
654 struct madera_priv *priv = snd_soc_component_get_drvdata(c: component);
655 struct madera *madera = priv->madera;
656 struct regmap *regmap = madera->regmap;
657 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
658 unsigned int mux, val, mask;
659 unsigned int inmode;
660 bool changed;
661 int ret;
662
663 mux = ucontrol->value.enumerated.item[0];
664 if (mux > 1)
665 return -EINVAL;
666
667 val = mux << e->shift_l;
668 mask = (e->mask << e->shift_l) | MADERA_IN1L_SRC_SE_MASK;
669
670 switch (e->reg) {
671 case MADERA_ADC_DIGITAL_VOLUME_1L:
672 inmode = madera->pdata.codec.inmode[0][2 * mux];
673 break;
674 case MADERA_ADC_DIGITAL_VOLUME_1R:
675 inmode = madera->pdata.codec.inmode[0][1 + (2 * mux)];
676 break;
677 case MADERA_ADC_DIGITAL_VOLUME_2L:
678 inmode = madera->pdata.codec.inmode[1][2 * mux];
679 break;
680 case MADERA_ADC_DIGITAL_VOLUME_2R:
681 inmode = madera->pdata.codec.inmode[1][1 + (2 * mux)];
682 break;
683 default:
684 return -EINVAL;
685 }
686
687 if (inmode & MADERA_INMODE_SE)
688 val |= 1 << MADERA_IN1L_SRC_SE_SHIFT;
689
690 dev_dbg(madera->dev, "mux=%u reg=0x%x inmode=0x%x mask=0x%x val=0x%x\n",
691 mux, e->reg, inmode, mask, val);
692
693 ret = regmap_update_bits_check(map: regmap, reg: e->reg, mask, val, change: &changed);
694 if (ret < 0)
695 return ret;
696
697 if (changed)
698 return snd_soc_dapm_mux_update_power(dapm, kcontrol,
699 mux, e, NULL);
700 else
701 return 0;
702}
703
704static const char * const madera_inmux_texts[] = {
705 "A",
706 "B",
707};
708
709static SOC_ENUM_SINGLE_DECL(madera_in1muxl_enum,
710 MADERA_ADC_DIGITAL_VOLUME_1L,
711 MADERA_IN1L_SRC_SHIFT,
712 madera_inmux_texts);
713
714static SOC_ENUM_SINGLE_DECL(madera_in1muxr_enum,
715 MADERA_ADC_DIGITAL_VOLUME_1R,
716 MADERA_IN1R_SRC_SHIFT,
717 madera_inmux_texts);
718
719static SOC_ENUM_SINGLE_DECL(madera_in2muxl_enum,
720 MADERA_ADC_DIGITAL_VOLUME_2L,
721 MADERA_IN2L_SRC_SHIFT,
722 madera_inmux_texts);
723
724static SOC_ENUM_SINGLE_DECL(madera_in2muxr_enum,
725 MADERA_ADC_DIGITAL_VOLUME_2R,
726 MADERA_IN2R_SRC_SHIFT,
727 madera_inmux_texts);
728
729const struct snd_kcontrol_new madera_inmux[] = {
730 SOC_DAPM_ENUM_EXT("IN1L Mux", madera_in1muxl_enum,
731 snd_soc_dapm_get_enum_double, madera_inmux_put),
732 SOC_DAPM_ENUM_EXT("IN1R Mux", madera_in1muxr_enum,
733 snd_soc_dapm_get_enum_double, madera_inmux_put),
734 SOC_DAPM_ENUM_EXT("IN2L Mux", madera_in2muxl_enum,
735 snd_soc_dapm_get_enum_double, madera_inmux_put),
736 SOC_DAPM_ENUM_EXT("IN2R Mux", madera_in2muxr_enum,
737 snd_soc_dapm_get_enum_double, madera_inmux_put),
738};
739EXPORT_SYMBOL_GPL(madera_inmux);
740
741static const char * const madera_dmode_texts[] = {
742 "Analog",
743 "Digital",
744};
745
746static SOC_ENUM_SINGLE_DECL(madera_in1dmode_enum,
747 MADERA_IN1L_CONTROL,
748 MADERA_IN1_MODE_SHIFT,
749 madera_dmode_texts);
750
751static SOC_ENUM_SINGLE_DECL(madera_in2dmode_enum,
752 MADERA_IN2L_CONTROL,
753 MADERA_IN2_MODE_SHIFT,
754 madera_dmode_texts);
755
756static SOC_ENUM_SINGLE_DECL(madera_in3dmode_enum,
757 MADERA_IN3L_CONTROL,
758 MADERA_IN3_MODE_SHIFT,
759 madera_dmode_texts);
760
761const struct snd_kcontrol_new madera_inmode[] = {
762 SOC_DAPM_ENUM("IN1 Mode", madera_in1dmode_enum),
763 SOC_DAPM_ENUM("IN2 Mode", madera_in2dmode_enum),
764 SOC_DAPM_ENUM("IN3 Mode", madera_in3dmode_enum),
765};
766EXPORT_SYMBOL_GPL(madera_inmode);
767
768static bool madera_can_change_grp_rate(const struct madera_priv *priv,
769 unsigned int reg)
770{
771 int count;
772
773 switch (reg) {
774 case MADERA_FX_CTRL1:
775 count = priv->domain_group_ref[MADERA_DOM_GRP_FX];
776 break;
777 case MADERA_ASRC1_RATE1:
778 case MADERA_ASRC1_RATE2:
779 count = priv->domain_group_ref[MADERA_DOM_GRP_ASRC1];
780 break;
781 case MADERA_ASRC2_RATE1:
782 case MADERA_ASRC2_RATE2:
783 count = priv->domain_group_ref[MADERA_DOM_GRP_ASRC2];
784 break;
785 case MADERA_ISRC_1_CTRL_1:
786 case MADERA_ISRC_1_CTRL_2:
787 count = priv->domain_group_ref[MADERA_DOM_GRP_ISRC1];
788 break;
789 case MADERA_ISRC_2_CTRL_1:
790 case MADERA_ISRC_2_CTRL_2:
791 count = priv->domain_group_ref[MADERA_DOM_GRP_ISRC2];
792 break;
793 case MADERA_ISRC_3_CTRL_1:
794 case MADERA_ISRC_3_CTRL_2:
795 count = priv->domain_group_ref[MADERA_DOM_GRP_ISRC3];
796 break;
797 case MADERA_ISRC_4_CTRL_1:
798 case MADERA_ISRC_4_CTRL_2:
799 count = priv->domain_group_ref[MADERA_DOM_GRP_ISRC4];
800 break;
801 case MADERA_OUTPUT_RATE_1:
802 count = priv->domain_group_ref[MADERA_DOM_GRP_OUT];
803 break;
804 case MADERA_SPD1_TX_CONTROL:
805 count = priv->domain_group_ref[MADERA_DOM_GRP_SPD];
806 break;
807 case MADERA_DSP1_CONFIG_1:
808 case MADERA_DSP1_CONFIG_2:
809 count = priv->domain_group_ref[MADERA_DOM_GRP_DSP1];
810 break;
811 case MADERA_DSP2_CONFIG_1:
812 case MADERA_DSP2_CONFIG_2:
813 count = priv->domain_group_ref[MADERA_DOM_GRP_DSP2];
814 break;
815 case MADERA_DSP3_CONFIG_1:
816 case MADERA_DSP3_CONFIG_2:
817 count = priv->domain_group_ref[MADERA_DOM_GRP_DSP3];
818 break;
819 case MADERA_DSP4_CONFIG_1:
820 case MADERA_DSP4_CONFIG_2:
821 count = priv->domain_group_ref[MADERA_DOM_GRP_DSP4];
822 break;
823 case MADERA_DSP5_CONFIG_1:
824 case MADERA_DSP5_CONFIG_2:
825 count = priv->domain_group_ref[MADERA_DOM_GRP_DSP5];
826 break;
827 case MADERA_DSP6_CONFIG_1:
828 case MADERA_DSP6_CONFIG_2:
829 count = priv->domain_group_ref[MADERA_DOM_GRP_DSP6];
830 break;
831 case MADERA_DSP7_CONFIG_1:
832 case MADERA_DSP7_CONFIG_2:
833 count = priv->domain_group_ref[MADERA_DOM_GRP_DSP7];
834 break;
835 case MADERA_AIF1_RATE_CTRL:
836 count = priv->domain_group_ref[MADERA_DOM_GRP_AIF1];
837 break;
838 case MADERA_AIF2_RATE_CTRL:
839 count = priv->domain_group_ref[MADERA_DOM_GRP_AIF2];
840 break;
841 case MADERA_AIF3_RATE_CTRL:
842 count = priv->domain_group_ref[MADERA_DOM_GRP_AIF3];
843 break;
844 case MADERA_AIF4_RATE_CTRL:
845 count = priv->domain_group_ref[MADERA_DOM_GRP_AIF4];
846 break;
847 case MADERA_SLIMBUS_RATES_1:
848 case MADERA_SLIMBUS_RATES_2:
849 case MADERA_SLIMBUS_RATES_3:
850 case MADERA_SLIMBUS_RATES_4:
851 case MADERA_SLIMBUS_RATES_5:
852 case MADERA_SLIMBUS_RATES_6:
853 case MADERA_SLIMBUS_RATES_7:
854 case MADERA_SLIMBUS_RATES_8:
855 count = priv->domain_group_ref[MADERA_DOM_GRP_SLIMBUS];
856 break;
857 case MADERA_PWM_DRIVE_1:
858 count = priv->domain_group_ref[MADERA_DOM_GRP_PWM];
859 break;
860 default:
861 return false;
862 }
863
864 dev_dbg(priv->madera->dev, "Rate reg 0x%x group ref %d\n", reg, count);
865
866 if (count)
867 return false;
868 else
869 return true;
870}
871
872static int madera_adsp_rate_get(struct snd_kcontrol *kcontrol,
873 struct snd_ctl_elem_value *ucontrol)
874{
875 struct snd_soc_component *component =
876 snd_soc_kcontrol_component(kcontrol);
877 struct madera_priv *priv = snd_soc_component_get_drvdata(c: component);
878 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
879 unsigned int cached_rate;
880 const int adsp_num = e->shift_l;
881 int item;
882
883 mutex_lock(&priv->rate_lock);
884 cached_rate = priv->adsp_rate_cache[adsp_num];
885 mutex_unlock(lock: &priv->rate_lock);
886
887 item = snd_soc_enum_val_to_item(e, val: cached_rate);
888 ucontrol->value.enumerated.item[0] = item;
889
890 return 0;
891}
892
893static int madera_adsp_rate_put(struct snd_kcontrol *kcontrol,
894 struct snd_ctl_elem_value *ucontrol)
895{
896 struct snd_soc_component *component =
897 snd_soc_kcontrol_component(kcontrol);
898 struct madera_priv *priv = snd_soc_component_get_drvdata(c: component);
899 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
900 const int adsp_num = e->shift_l;
901 const unsigned int item = ucontrol->value.enumerated.item[0];
902 int ret = 0;
903
904 if (item >= e->items)
905 return -EINVAL;
906
907 /*
908 * We don't directly write the rate register here but we want to
909 * maintain consistent behaviour that rate domains cannot be changed
910 * while in use since this is a hardware requirement
911 */
912 mutex_lock(&priv->rate_lock);
913
914 if (!madera_can_change_grp_rate(priv, reg: priv->adsp[adsp_num].cs_dsp.base)) {
915 dev_warn(priv->madera->dev,
916 "Cannot change '%s' while in use by active audio paths\n",
917 kcontrol->id.name);
918 ret = -EBUSY;
919 } else if (priv->adsp_rate_cache[adsp_num] != e->values[item]) {
920 /* Volatile register so defer until the codec is powered up */
921 priv->adsp_rate_cache[adsp_num] = e->values[item];
922 ret = 1;
923 }
924
925 mutex_unlock(lock: &priv->rate_lock);
926
927 return ret;
928}
929
930static const struct soc_enum madera_adsp_rate_enum[] = {
931 SOC_VALUE_ENUM_SINGLE(SND_SOC_NOPM, 0, 0xf, MADERA_RATE_ENUM_SIZE,
932 madera_rate_text, madera_rate_val),
933 SOC_VALUE_ENUM_SINGLE(SND_SOC_NOPM, 1, 0xf, MADERA_RATE_ENUM_SIZE,
934 madera_rate_text, madera_rate_val),
935 SOC_VALUE_ENUM_SINGLE(SND_SOC_NOPM, 2, 0xf, MADERA_RATE_ENUM_SIZE,
936 madera_rate_text, madera_rate_val),
937 SOC_VALUE_ENUM_SINGLE(SND_SOC_NOPM, 3, 0xf, MADERA_RATE_ENUM_SIZE,
938 madera_rate_text, madera_rate_val),
939 SOC_VALUE_ENUM_SINGLE(SND_SOC_NOPM, 4, 0xf, MADERA_RATE_ENUM_SIZE,
940 madera_rate_text, madera_rate_val),
941 SOC_VALUE_ENUM_SINGLE(SND_SOC_NOPM, 5, 0xf, MADERA_RATE_ENUM_SIZE,
942 madera_rate_text, madera_rate_val),
943 SOC_VALUE_ENUM_SINGLE(SND_SOC_NOPM, 6, 0xf, MADERA_RATE_ENUM_SIZE,
944 madera_rate_text, madera_rate_val),
945};
946
947const struct snd_kcontrol_new madera_adsp_rate_controls[] = {
948 SOC_ENUM_EXT("DSP1 Rate", madera_adsp_rate_enum[0],
949 madera_adsp_rate_get, madera_adsp_rate_put),
950 SOC_ENUM_EXT("DSP2 Rate", madera_adsp_rate_enum[1],
951 madera_adsp_rate_get, madera_adsp_rate_put),
952 SOC_ENUM_EXT("DSP3 Rate", madera_adsp_rate_enum[2],
953 madera_adsp_rate_get, madera_adsp_rate_put),
954 SOC_ENUM_EXT("DSP4 Rate", madera_adsp_rate_enum[3],
955 madera_adsp_rate_get, madera_adsp_rate_put),
956 SOC_ENUM_EXT("DSP5 Rate", madera_adsp_rate_enum[4],
957 madera_adsp_rate_get, madera_adsp_rate_put),
958 SOC_ENUM_EXT("DSP6 Rate", madera_adsp_rate_enum[5],
959 madera_adsp_rate_get, madera_adsp_rate_put),
960 SOC_ENUM_EXT("DSP7 Rate", madera_adsp_rate_enum[6],
961 madera_adsp_rate_get, madera_adsp_rate_put),
962};
963EXPORT_SYMBOL_GPL(madera_adsp_rate_controls);
964
965static int madera_write_adsp_clk_setting(struct madera_priv *priv,
966 struct wm_adsp *dsp,
967 unsigned int freq)
968{
969 unsigned int val;
970 unsigned int mask = MADERA_DSP_RATE_MASK;
971 int ret;
972
973 val = priv->adsp_rate_cache[dsp->cs_dsp.num - 1] << MADERA_DSP_RATE_SHIFT;
974
975 switch (priv->madera->type) {
976 case CS47L35:
977 case CS47L85:
978 case WM1840:
979 /* use legacy frequency registers */
980 mask |= MADERA_DSP_CLK_SEL_MASK;
981 val |= (freq << MADERA_DSP_CLK_SEL_SHIFT);
982 break;
983 default:
984 /* Configure exact dsp frequency */
985 dev_dbg(priv->madera->dev, "Set DSP frequency to 0x%x\n", freq);
986
987 ret = regmap_write(map: dsp->cs_dsp.regmap,
988 reg: dsp->cs_dsp.base + MADERA_DSP_CONFIG_2_OFFS, val: freq);
989 if (ret)
990 goto err;
991 break;
992 }
993
994 ret = regmap_update_bits(map: dsp->cs_dsp.regmap,
995 reg: dsp->cs_dsp.base + MADERA_DSP_CONFIG_1_OFFS,
996 mask, val);
997 if (ret)
998 goto err;
999
1000 dev_dbg(priv->madera->dev, "Set DSP clocking to 0x%x\n", val);
1001
1002 return 0;
1003
1004err:
1005 dev_err(dsp->cs_dsp.dev, "Failed to set DSP%d clock: %d\n", dsp->cs_dsp.num, ret);
1006
1007 return ret;
1008}
1009
1010int madera_set_adsp_clk(struct madera_priv *priv, int dsp_num,
1011 unsigned int freq)
1012{
1013 struct wm_adsp *dsp = &priv->adsp[dsp_num];
1014 struct madera *madera = priv->madera;
1015 unsigned int cur, new;
1016 int ret;
1017
1018 /*
1019 * This is called at a higher DAPM priority than the mux widgets so
1020 * the muxes are still off at this point and it's safe to change
1021 * the rate domain control.
1022 * Also called at a lower DAPM priority than the domain group widgets
1023 * so locking the reads of adsp_rate_cache is not necessary as we know
1024 * changes are locked out by the domain_group_ref reference count.
1025 */
1026
1027 ret = regmap_read(map: dsp->cs_dsp.regmap, reg: dsp->cs_dsp.base, val: &cur);
1028 if (ret) {
1029 dev_err(madera->dev,
1030 "Failed to read current DSP rate: %d\n", ret);
1031 return ret;
1032 }
1033
1034 cur &= MADERA_DSP_RATE_MASK;
1035
1036 new = priv->adsp_rate_cache[dsp->cs_dsp.num - 1] << MADERA_DSP_RATE_SHIFT;
1037
1038 if (new == cur) {
1039 dev_dbg(madera->dev, "DSP rate not changed\n");
1040 return madera_write_adsp_clk_setting(priv, dsp, freq);
1041 } else {
1042 dev_dbg(madera->dev, "DSP rate changed\n");
1043
1044 /* The write must be guarded by a number of SYSCLK cycles */
1045 madera_spin_sysclk(priv);
1046 ret = madera_write_adsp_clk_setting(priv, dsp, freq);
1047 madera_spin_sysclk(priv);
1048 return ret;
1049 }
1050}
1051EXPORT_SYMBOL_GPL(madera_set_adsp_clk);
1052
1053int madera_rate_put(struct snd_kcontrol *kcontrol,
1054 struct snd_ctl_elem_value *ucontrol)
1055{
1056 struct snd_soc_component *component =
1057 snd_soc_kcontrol_component(kcontrol);
1058 struct madera_priv *priv = snd_soc_component_get_drvdata(c: component);
1059 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
1060 unsigned int item = ucontrol->value.enumerated.item[0];
1061 unsigned int val;
1062 int ret;
1063
1064 if (item >= e->items)
1065 return -EINVAL;
1066
1067 /*
1068 * Prevent the domain powering up while we're checking whether it's
1069 * safe to change rate domain
1070 */
1071 mutex_lock(&priv->rate_lock);
1072
1073 val = snd_soc_component_read(component, reg: e->reg);
1074 val >>= e->shift_l;
1075 val &= e->mask;
1076 if (snd_soc_enum_item_to_val(e, item) == val) {
1077 ret = 0;
1078 goto out;
1079 }
1080
1081 if (!madera_can_change_grp_rate(priv, reg: e->reg)) {
1082 dev_warn(priv->madera->dev,
1083 "Cannot change '%s' while in use by active audio paths\n",
1084 kcontrol->id.name);
1085 ret = -EBUSY;
1086 } else {
1087 /* The write must be guarded by a number of SYSCLK cycles */
1088 madera_spin_sysclk(priv);
1089 ret = snd_soc_put_enum_double(kcontrol, ucontrol);
1090 madera_spin_sysclk(priv);
1091 }
1092out:
1093 mutex_unlock(lock: &priv->rate_lock);
1094
1095 return ret;
1096}
1097EXPORT_SYMBOL_GPL(madera_rate_put);
1098
1099static void madera_configure_input_mode(struct madera *madera)
1100{
1101 unsigned int dig_mode, ana_mode_l, ana_mode_r;
1102 int max_analogue_inputs, max_dmic_sup, i;
1103
1104 switch (madera->type) {
1105 case CS47L15:
1106 max_analogue_inputs = 1;
1107 max_dmic_sup = 2;
1108 break;
1109 case CS47L35:
1110 max_analogue_inputs = 2;
1111 max_dmic_sup = 2;
1112 break;
1113 case CS47L85:
1114 case WM1840:
1115 max_analogue_inputs = 3;
1116 max_dmic_sup = 3;
1117 break;
1118 case CS47L90:
1119 case CS47L91:
1120 max_analogue_inputs = 2;
1121 max_dmic_sup = 2;
1122 break;
1123 default:
1124 max_analogue_inputs = 2;
1125 max_dmic_sup = 4;
1126 break;
1127 }
1128
1129 /*
1130 * Initialize input modes from the A settings. For muxed inputs the
1131 * B settings will be applied if the mux is changed
1132 */
1133 for (i = 0; i < max_dmic_sup; i++) {
1134 dev_dbg(madera->dev, "IN%d mode %u:%u:%u:%u\n", i + 1,
1135 madera->pdata.codec.inmode[i][0],
1136 madera->pdata.codec.inmode[i][1],
1137 madera->pdata.codec.inmode[i][2],
1138 madera->pdata.codec.inmode[i][3]);
1139
1140 dig_mode = madera->pdata.codec.dmic_ref[i] <<
1141 MADERA_IN1_DMIC_SUP_SHIFT;
1142
1143 switch (madera->pdata.codec.inmode[i][0]) {
1144 case MADERA_INMODE_DIFF:
1145 ana_mode_l = 0;
1146 break;
1147 case MADERA_INMODE_SE:
1148 ana_mode_l = 1 << MADERA_IN1L_SRC_SE_SHIFT;
1149 break;
1150 default:
1151 dev_warn(madera->dev,
1152 "IN%dAL Illegal inmode %u ignored\n",
1153 i + 1, madera->pdata.codec.inmode[i][0]);
1154 continue;
1155 }
1156
1157 switch (madera->pdata.codec.inmode[i][1]) {
1158 case MADERA_INMODE_DIFF:
1159 ana_mode_r = 0;
1160 break;
1161 case MADERA_INMODE_SE:
1162 ana_mode_r = 1 << MADERA_IN1R_SRC_SE_SHIFT;
1163 break;
1164 default:
1165 dev_warn(madera->dev,
1166 "IN%dAR Illegal inmode %u ignored\n",
1167 i + 1, madera->pdata.codec.inmode[i][1]);
1168 continue;
1169 }
1170
1171 dev_dbg(madera->dev,
1172 "IN%dA DMIC mode=0x%x Analogue mode=0x%x,0x%x\n",
1173 i + 1, dig_mode, ana_mode_l, ana_mode_r);
1174
1175 regmap_update_bits(map: madera->regmap,
1176 MADERA_IN1L_CONTROL + (i * 8),
1177 MADERA_IN1_DMIC_SUP_MASK, val: dig_mode);
1178
1179 if (i >= max_analogue_inputs)
1180 continue;
1181
1182 regmap_update_bits(map: madera->regmap,
1183 MADERA_ADC_DIGITAL_VOLUME_1L + (i * 8),
1184 MADERA_IN1L_SRC_SE_MASK, val: ana_mode_l);
1185
1186 regmap_update_bits(map: madera->regmap,
1187 MADERA_ADC_DIGITAL_VOLUME_1R + (i * 8),
1188 MADERA_IN1R_SRC_SE_MASK, val: ana_mode_r);
1189 }
1190}
1191
1192int madera_init_inputs(struct snd_soc_component *component)
1193{
1194 struct madera_priv *priv = snd_soc_component_get_drvdata(c: component);
1195 struct madera *madera = priv->madera;
1196
1197 madera_configure_input_mode(madera);
1198
1199 return 0;
1200}
1201EXPORT_SYMBOL_GPL(madera_init_inputs);
1202
1203static const struct snd_soc_dapm_route madera_mono_routes[] = {
1204 { "OUT1R", NULL, "OUT1L" },
1205 { "OUT2R", NULL, "OUT2L" },
1206 { "OUT3R", NULL, "OUT3L" },
1207 { "OUT4R", NULL, "OUT4L" },
1208 { "OUT5R", NULL, "OUT5L" },
1209 { "OUT6R", NULL, "OUT6L" },
1210};
1211
1212int madera_init_outputs(struct snd_soc_component *component,
1213 const struct snd_soc_dapm_route *routes,
1214 int n_mono_routes, int n_real)
1215{
1216 struct snd_soc_dapm_context *dapm =
1217 snd_soc_component_get_dapm(component);
1218 struct madera_priv *priv = snd_soc_component_get_drvdata(c: component);
1219 struct madera *madera = priv->madera;
1220 const struct madera_codec_pdata *pdata = &madera->pdata.codec;
1221 unsigned int val;
1222 int i;
1223
1224 if (n_mono_routes > MADERA_MAX_OUTPUT) {
1225 dev_warn(madera->dev,
1226 "Requested %d mono outputs, using maximum allowed %d\n",
1227 n_mono_routes, MADERA_MAX_OUTPUT);
1228 n_mono_routes = MADERA_MAX_OUTPUT;
1229 }
1230
1231 if (!routes)
1232 routes = madera_mono_routes;
1233
1234 for (i = 0; i < n_mono_routes; i++) {
1235 /* Default is 0 so noop with defaults */
1236 if (pdata->out_mono[i]) {
1237 val = MADERA_OUT1_MONO;
1238 snd_soc_dapm_add_routes(dapm, route: &routes[i], num: 1);
1239 } else {
1240 val = 0;
1241 }
1242
1243 if (i >= n_real)
1244 continue;
1245
1246 regmap_update_bits(map: madera->regmap,
1247 MADERA_OUTPUT_PATH_CONFIG_1L + (i * 8),
1248 MADERA_OUT1_MONO, val);
1249
1250 dev_dbg(madera->dev, "OUT%d mono=0x%x\n", i + 1, val);
1251 }
1252
1253 for (i = 0; i < MADERA_MAX_PDM_SPK; i++) {
1254 dev_dbg(madera->dev, "PDM%d fmt=0x%x mute=0x%x\n", i + 1,
1255 pdata->pdm_fmt[i], pdata->pdm_mute[i]);
1256
1257 if (pdata->pdm_mute[i])
1258 regmap_update_bits(map: madera->regmap,
1259 MADERA_PDM_SPK1_CTRL_1 + (i * 2),
1260 MADERA_SPK1_MUTE_ENDIAN_MASK |
1261 MADERA_SPK1_MUTE_SEQ1_MASK,
1262 val: pdata->pdm_mute[i]);
1263
1264 if (pdata->pdm_fmt[i])
1265 regmap_update_bits(map: madera->regmap,
1266 MADERA_PDM_SPK1_CTRL_2 + (i * 2),
1267 MADERA_SPK1_FMT_MASK,
1268 val: pdata->pdm_fmt[i]);
1269 }
1270
1271 return 0;
1272}
1273EXPORT_SYMBOL_GPL(madera_init_outputs);
1274
1275int madera_init_bus_error_irq(struct madera_priv *priv, int dsp_num,
1276 irq_handler_t handler)
1277{
1278 struct madera *madera = priv->madera;
1279 int ret;
1280
1281 ret = madera_request_irq(madera,
1282 irq: madera_dsp_bus_error_irqs[dsp_num],
1283 name: "ADSP2 bus error",
1284 handler,
1285 data: &priv->adsp[dsp_num]);
1286 if (ret)
1287 dev_err(madera->dev,
1288 "Failed to request DSP Lock region IRQ: %d\n", ret);
1289
1290 return ret;
1291}
1292EXPORT_SYMBOL_GPL(madera_init_bus_error_irq);
1293
1294void madera_free_bus_error_irq(struct madera_priv *priv, int dsp_num)
1295{
1296 struct madera *madera = priv->madera;
1297
1298 madera_free_irq(madera,
1299 irq: madera_dsp_bus_error_irqs[dsp_num],
1300 data: &priv->adsp[dsp_num]);
1301}
1302EXPORT_SYMBOL_GPL(madera_free_bus_error_irq);
1303
1304const char * const madera_mixer_texts[] = {
1305 "None",
1306 "Tone Generator 1",
1307 "Tone Generator 2",
1308 "Haptics",
1309 "AEC1",
1310 "AEC2",
1311 "Mic Mute Mixer",
1312 "Noise Generator",
1313 "IN1L",
1314 "IN1R",
1315 "IN2L",
1316 "IN2R",
1317 "IN3L",
1318 "IN3R",
1319 "IN4L",
1320 "IN4R",
1321 "IN5L",
1322 "IN5R",
1323 "IN6L",
1324 "IN6R",
1325 "AIF1RX1",
1326 "AIF1RX2",
1327 "AIF1RX3",
1328 "AIF1RX4",
1329 "AIF1RX5",
1330 "AIF1RX6",
1331 "AIF1RX7",
1332 "AIF1RX8",
1333 "AIF2RX1",
1334 "AIF2RX2",
1335 "AIF2RX3",
1336 "AIF2RX4",
1337 "AIF2RX5",
1338 "AIF2RX6",
1339 "AIF2RX7",
1340 "AIF2RX8",
1341 "AIF3RX1",
1342 "AIF3RX2",
1343 "AIF3RX3",
1344 "AIF3RX4",
1345 "AIF4RX1",
1346 "AIF4RX2",
1347 "SLIMRX1",
1348 "SLIMRX2",
1349 "SLIMRX3",
1350 "SLIMRX4",
1351 "SLIMRX5",
1352 "SLIMRX6",
1353 "SLIMRX7",
1354 "SLIMRX8",
1355 "EQ1",
1356 "EQ2",
1357 "EQ3",
1358 "EQ4",
1359 "DRC1L",
1360 "DRC1R",
1361 "DRC2L",
1362 "DRC2R",
1363 "LHPF1",
1364 "LHPF2",
1365 "LHPF3",
1366 "LHPF4",
1367 "DSP1.1",
1368 "DSP1.2",
1369 "DSP1.3",
1370 "DSP1.4",
1371 "DSP1.5",
1372 "DSP1.6",
1373 "DSP2.1",
1374 "DSP2.2",
1375 "DSP2.3",
1376 "DSP2.4",
1377 "DSP2.5",
1378 "DSP2.6",
1379 "DSP3.1",
1380 "DSP3.2",
1381 "DSP3.3",
1382 "DSP3.4",
1383 "DSP3.5",
1384 "DSP3.6",
1385 "DSP4.1",
1386 "DSP4.2",
1387 "DSP4.3",
1388 "DSP4.4",
1389 "DSP4.5",
1390 "DSP4.6",
1391 "DSP5.1",
1392 "DSP5.2",
1393 "DSP5.3",
1394 "DSP5.4",
1395 "DSP5.5",
1396 "DSP5.6",
1397 "DSP6.1",
1398 "DSP6.2",
1399 "DSP6.3",
1400 "DSP6.4",
1401 "DSP6.5",
1402 "DSP6.6",
1403 "DSP7.1",
1404 "DSP7.2",
1405 "DSP7.3",
1406 "DSP7.4",
1407 "DSP7.5",
1408 "DSP7.6",
1409 "ASRC1IN1L",
1410 "ASRC1IN1R",
1411 "ASRC1IN2L",
1412 "ASRC1IN2R",
1413 "ASRC2IN1L",
1414 "ASRC2IN1R",
1415 "ASRC2IN2L",
1416 "ASRC2IN2R",
1417 "ISRC1INT1",
1418 "ISRC1INT2",
1419 "ISRC1INT3",
1420 "ISRC1INT4",
1421 "ISRC1DEC1",
1422 "ISRC1DEC2",
1423 "ISRC1DEC3",
1424 "ISRC1DEC4",
1425 "ISRC2INT1",
1426 "ISRC2INT2",
1427 "ISRC2INT3",
1428 "ISRC2INT4",
1429 "ISRC2DEC1",
1430 "ISRC2DEC2",
1431 "ISRC2DEC3",
1432 "ISRC2DEC4",
1433 "ISRC3INT1",
1434 "ISRC3INT2",
1435 "ISRC3INT3",
1436 "ISRC3INT4",
1437 "ISRC3DEC1",
1438 "ISRC3DEC2",
1439 "ISRC3DEC3",
1440 "ISRC3DEC4",
1441 "ISRC4INT1",
1442 "ISRC4INT2",
1443 "ISRC4DEC1",
1444 "ISRC4DEC2",
1445 "DFC1",
1446 "DFC2",
1447 "DFC3",
1448 "DFC4",
1449 "DFC5",
1450 "DFC6",
1451 "DFC7",
1452 "DFC8",
1453};
1454EXPORT_SYMBOL_GPL(madera_mixer_texts);
1455
1456const unsigned int madera_mixer_values[] = {
1457 0x00, /* None */
1458 0x04, /* Tone Generator 1 */
1459 0x05, /* Tone Generator 2 */
1460 0x06, /* Haptics */
1461 0x08, /* AEC */
1462 0x09, /* AEC2 */
1463 0x0c, /* Noise mixer */
1464 0x0d, /* Comfort noise */
1465 0x10, /* IN1L */
1466 0x11,
1467 0x12,
1468 0x13,
1469 0x14,
1470 0x15,
1471 0x16,
1472 0x17,
1473 0x18,
1474 0x19,
1475 0x1A,
1476 0x1B,
1477 0x20, /* AIF1RX1 */
1478 0x21,
1479 0x22,
1480 0x23,
1481 0x24,
1482 0x25,
1483 0x26,
1484 0x27,
1485 0x28, /* AIF2RX1 */
1486 0x29,
1487 0x2a,
1488 0x2b,
1489 0x2c,
1490 0x2d,
1491 0x2e,
1492 0x2f,
1493 0x30, /* AIF3RX1 */
1494 0x31,
1495 0x32,
1496 0x33,
1497 0x34, /* AIF4RX1 */
1498 0x35,
1499 0x38, /* SLIMRX1 */
1500 0x39,
1501 0x3a,
1502 0x3b,
1503 0x3c,
1504 0x3d,
1505 0x3e,
1506 0x3f,
1507 0x50, /* EQ1 */
1508 0x51,
1509 0x52,
1510 0x53,
1511 0x58, /* DRC1L */
1512 0x59,
1513 0x5a,
1514 0x5b,
1515 0x60, /* LHPF1 */
1516 0x61,
1517 0x62,
1518 0x63,
1519 0x68, /* DSP1.1 */
1520 0x69,
1521 0x6a,
1522 0x6b,
1523 0x6c,
1524 0x6d,
1525 0x70, /* DSP2.1 */
1526 0x71,
1527 0x72,
1528 0x73,
1529 0x74,
1530 0x75,
1531 0x78, /* DSP3.1 */
1532 0x79,
1533 0x7a,
1534 0x7b,
1535 0x7c,
1536 0x7d,
1537 0x80, /* DSP4.1 */
1538 0x81,
1539 0x82,
1540 0x83,
1541 0x84,
1542 0x85,
1543 0x88, /* DSP5.1 */
1544 0x89,
1545 0x8a,
1546 0x8b,
1547 0x8c,
1548 0x8d,
1549 0xc0, /* DSP6.1 */
1550 0xc1,
1551 0xc2,
1552 0xc3,
1553 0xc4,
1554 0xc5,
1555 0xc8, /* DSP7.1 */
1556 0xc9,
1557 0xca,
1558 0xcb,
1559 0xcc,
1560 0xcd,
1561 0x90, /* ASRC1IN1L */
1562 0x91,
1563 0x92,
1564 0x93,
1565 0x94, /* ASRC2IN1L */
1566 0x95,
1567 0x96,
1568 0x97,
1569 0xa0, /* ISRC1INT1 */
1570 0xa1,
1571 0xa2,
1572 0xa3,
1573 0xa4, /* ISRC1DEC1 */
1574 0xa5,
1575 0xa6,
1576 0xa7,
1577 0xa8, /* ISRC2DEC1 */
1578 0xa9,
1579 0xaa,
1580 0xab,
1581 0xac, /* ISRC2INT1 */
1582 0xad,
1583 0xae,
1584 0xaf,
1585 0xb0, /* ISRC3DEC1 */
1586 0xb1,
1587 0xb2,
1588 0xb3,
1589 0xb4, /* ISRC3INT1 */
1590 0xb5,
1591 0xb6,
1592 0xb7,
1593 0xb8, /* ISRC4INT1 */
1594 0xb9,
1595 0xbc, /* ISRC4DEC1 */
1596 0xbd,
1597 0xf8, /* DFC1 */
1598 0xf9,
1599 0xfa,
1600 0xfb,
1601 0xfc,
1602 0xfd,
1603 0xfe,
1604 0xff, /* DFC8 */
1605};
1606EXPORT_SYMBOL_GPL(madera_mixer_values);
1607
1608const DECLARE_TLV_DB_SCALE(madera_ana_tlv, 0, 100, 0);
1609EXPORT_SYMBOL_GPL(madera_ana_tlv);
1610
1611const DECLARE_TLV_DB_SCALE(madera_eq_tlv, -1200, 100, 0);
1612EXPORT_SYMBOL_GPL(madera_eq_tlv);
1613
1614const DECLARE_TLV_DB_SCALE(madera_digital_tlv, -6400, 50, 0);
1615EXPORT_SYMBOL_GPL(madera_digital_tlv);
1616
1617const DECLARE_TLV_DB_SCALE(madera_noise_tlv, -13200, 600, 0);
1618EXPORT_SYMBOL_GPL(madera_noise_tlv);
1619
1620const DECLARE_TLV_DB_SCALE(madera_ng_tlv, -12000, 600, 0);
1621EXPORT_SYMBOL_GPL(madera_ng_tlv);
1622
1623const DECLARE_TLV_DB_SCALE(madera_mixer_tlv, -3200, 100, 0);
1624EXPORT_SYMBOL_GPL(madera_mixer_tlv);
1625
1626const char * const madera_rate_text[MADERA_RATE_ENUM_SIZE] = {
1627 "SYNCCLK rate 1", "SYNCCLK rate 2", "SYNCCLK rate 3",
1628 "ASYNCCLK rate 1", "ASYNCCLK rate 2",
1629};
1630EXPORT_SYMBOL_GPL(madera_rate_text);
1631
1632const unsigned int madera_rate_val[MADERA_RATE_ENUM_SIZE] = {
1633 0x0, 0x1, 0x2, 0x8, 0x9,
1634};
1635EXPORT_SYMBOL_GPL(madera_rate_val);
1636
1637static const char * const madera_dfc_width_text[MADERA_DFC_WIDTH_ENUM_SIZE] = {
1638 "8 bit", "16 bit", "20 bit", "24 bit", "32 bit",
1639};
1640
1641static const unsigned int madera_dfc_width_val[MADERA_DFC_WIDTH_ENUM_SIZE] = {
1642 7, 15, 19, 23, 31,
1643};
1644
1645static const char * const madera_dfc_type_text[MADERA_DFC_TYPE_ENUM_SIZE] = {
1646 "Fixed", "Unsigned Fixed", "Single Precision Floating",
1647 "Half Precision Floating", "Arm Alternative Floating",
1648};
1649
1650static const unsigned int madera_dfc_type_val[MADERA_DFC_TYPE_ENUM_SIZE] = {
1651 0, 1, 2, 4, 5,
1652};
1653
1654const struct soc_enum madera_dfc_width[] = {
1655 SOC_VALUE_ENUM_SINGLE(MADERA_DFC1_RX,
1656 MADERA_DFC1_RX_DATA_WIDTH_SHIFT,
1657 MADERA_DFC1_RX_DATA_WIDTH_MASK >>
1658 MADERA_DFC1_RX_DATA_WIDTH_SHIFT,
1659 ARRAY_SIZE(madera_dfc_width_text),
1660 madera_dfc_width_text,
1661 madera_dfc_width_val),
1662 SOC_VALUE_ENUM_SINGLE(MADERA_DFC1_TX,
1663 MADERA_DFC1_TX_DATA_WIDTH_SHIFT,
1664 MADERA_DFC1_TX_DATA_WIDTH_MASK >>
1665 MADERA_DFC1_TX_DATA_WIDTH_SHIFT,
1666 ARRAY_SIZE(madera_dfc_width_text),
1667 madera_dfc_width_text,
1668 madera_dfc_width_val),
1669 SOC_VALUE_ENUM_SINGLE(MADERA_DFC2_RX,
1670 MADERA_DFC1_RX_DATA_WIDTH_SHIFT,
1671 MADERA_DFC1_RX_DATA_WIDTH_MASK >>
1672 MADERA_DFC1_RX_DATA_WIDTH_SHIFT,
1673 ARRAY_SIZE(madera_dfc_width_text),
1674 madera_dfc_width_text,
1675 madera_dfc_width_val),
1676 SOC_VALUE_ENUM_SINGLE(MADERA_DFC2_TX,
1677 MADERA_DFC1_TX_DATA_WIDTH_SHIFT,
1678 MADERA_DFC1_TX_DATA_WIDTH_MASK >>
1679 MADERA_DFC1_TX_DATA_WIDTH_SHIFT,
1680 ARRAY_SIZE(madera_dfc_width_text),
1681 madera_dfc_width_text,
1682 madera_dfc_width_val),
1683 SOC_VALUE_ENUM_SINGLE(MADERA_DFC3_RX,
1684 MADERA_DFC1_RX_DATA_WIDTH_SHIFT,
1685 MADERA_DFC1_RX_DATA_WIDTH_MASK >>
1686 MADERA_DFC1_RX_DATA_WIDTH_SHIFT,
1687 ARRAY_SIZE(madera_dfc_width_text),
1688 madera_dfc_width_text,
1689 madera_dfc_width_val),
1690 SOC_VALUE_ENUM_SINGLE(MADERA_DFC3_TX,
1691 MADERA_DFC1_TX_DATA_WIDTH_SHIFT,
1692 MADERA_DFC1_TX_DATA_WIDTH_MASK >>
1693 MADERA_DFC1_TX_DATA_WIDTH_SHIFT,
1694 ARRAY_SIZE(madera_dfc_width_text),
1695 madera_dfc_width_text,
1696 madera_dfc_width_val),
1697 SOC_VALUE_ENUM_SINGLE(MADERA_DFC4_RX,
1698 MADERA_DFC1_RX_DATA_WIDTH_SHIFT,
1699 MADERA_DFC1_RX_DATA_WIDTH_MASK >>
1700 MADERA_DFC1_RX_DATA_WIDTH_SHIFT,
1701 ARRAY_SIZE(madera_dfc_width_text),
1702 madera_dfc_width_text,
1703 madera_dfc_width_val),
1704 SOC_VALUE_ENUM_SINGLE(MADERA_DFC4_TX,
1705 MADERA_DFC1_TX_DATA_WIDTH_SHIFT,
1706 MADERA_DFC1_TX_DATA_WIDTH_MASK >>
1707 MADERA_DFC1_TX_DATA_WIDTH_SHIFT,
1708 ARRAY_SIZE(madera_dfc_width_text),
1709 madera_dfc_width_text,
1710 madera_dfc_width_val),
1711 SOC_VALUE_ENUM_SINGLE(MADERA_DFC5_RX,
1712 MADERA_DFC1_RX_DATA_WIDTH_SHIFT,
1713 MADERA_DFC1_RX_DATA_WIDTH_MASK >>
1714 MADERA_DFC1_RX_DATA_WIDTH_SHIFT,
1715 ARRAY_SIZE(madera_dfc_width_text),
1716 madera_dfc_width_text,
1717 madera_dfc_width_val),
1718 SOC_VALUE_ENUM_SINGLE(MADERA_DFC5_TX,
1719 MADERA_DFC1_TX_DATA_WIDTH_SHIFT,
1720 MADERA_DFC1_TX_DATA_WIDTH_MASK >>
1721 MADERA_DFC1_TX_DATA_WIDTH_SHIFT,
1722 ARRAY_SIZE(madera_dfc_width_text),
1723 madera_dfc_width_text,
1724 madera_dfc_width_val),
1725 SOC_VALUE_ENUM_SINGLE(MADERA_DFC6_RX,
1726 MADERA_DFC1_RX_DATA_WIDTH_SHIFT,
1727 MADERA_DFC1_RX_DATA_WIDTH_MASK >>
1728 MADERA_DFC1_RX_DATA_WIDTH_SHIFT,
1729 ARRAY_SIZE(madera_dfc_width_text),
1730 madera_dfc_width_text,
1731 madera_dfc_width_val),
1732 SOC_VALUE_ENUM_SINGLE(MADERA_DFC6_TX,
1733 MADERA_DFC1_TX_DATA_WIDTH_SHIFT,
1734 MADERA_DFC1_TX_DATA_WIDTH_MASK >>
1735 MADERA_DFC1_TX_DATA_WIDTH_SHIFT,
1736 ARRAY_SIZE(madera_dfc_width_text),
1737 madera_dfc_width_text,
1738 madera_dfc_width_val),
1739 SOC_VALUE_ENUM_SINGLE(MADERA_DFC7_RX,
1740 MADERA_DFC1_RX_DATA_WIDTH_SHIFT,
1741 MADERA_DFC1_RX_DATA_WIDTH_MASK >>
1742 MADERA_DFC1_RX_DATA_WIDTH_SHIFT,
1743 ARRAY_SIZE(madera_dfc_width_text),
1744 madera_dfc_width_text,
1745 madera_dfc_width_val),
1746 SOC_VALUE_ENUM_SINGLE(MADERA_DFC7_TX,
1747 MADERA_DFC1_TX_DATA_WIDTH_SHIFT,
1748 MADERA_DFC1_TX_DATA_WIDTH_MASK >>
1749 MADERA_DFC1_TX_DATA_WIDTH_SHIFT,
1750 ARRAY_SIZE(madera_dfc_width_text),
1751 madera_dfc_width_text,
1752 madera_dfc_width_val),
1753 SOC_VALUE_ENUM_SINGLE(MADERA_DFC8_RX,
1754 MADERA_DFC1_RX_DATA_WIDTH_SHIFT,
1755 MADERA_DFC1_RX_DATA_WIDTH_MASK >>
1756 MADERA_DFC1_RX_DATA_WIDTH_SHIFT,
1757 ARRAY_SIZE(madera_dfc_width_text),
1758 madera_dfc_width_text,
1759 madera_dfc_width_val),
1760 SOC_VALUE_ENUM_SINGLE(MADERA_DFC8_TX,
1761 MADERA_DFC1_TX_DATA_WIDTH_SHIFT,
1762 MADERA_DFC1_TX_DATA_WIDTH_MASK >>
1763 MADERA_DFC1_TX_DATA_WIDTH_SHIFT,
1764 ARRAY_SIZE(madera_dfc_width_text),
1765 madera_dfc_width_text,
1766 madera_dfc_width_val),
1767};
1768EXPORT_SYMBOL_GPL(madera_dfc_width);
1769
1770const struct soc_enum madera_dfc_type[] = {
1771 SOC_VALUE_ENUM_SINGLE(MADERA_DFC1_RX,
1772 MADERA_DFC1_RX_DATA_TYPE_SHIFT,
1773 MADERA_DFC1_RX_DATA_TYPE_MASK >>
1774 MADERA_DFC1_RX_DATA_TYPE_SHIFT,
1775 ARRAY_SIZE(madera_dfc_type_text),
1776 madera_dfc_type_text,
1777 madera_dfc_type_val),
1778 SOC_VALUE_ENUM_SINGLE(MADERA_DFC1_TX,
1779 MADERA_DFC1_TX_DATA_TYPE_SHIFT,
1780 MADERA_DFC1_TX_DATA_TYPE_MASK >>
1781 MADERA_DFC1_TX_DATA_TYPE_SHIFT,
1782 ARRAY_SIZE(madera_dfc_type_text),
1783 madera_dfc_type_text,
1784 madera_dfc_type_val),
1785 SOC_VALUE_ENUM_SINGLE(MADERA_DFC2_RX,
1786 MADERA_DFC1_RX_DATA_TYPE_SHIFT,
1787 MADERA_DFC1_RX_DATA_TYPE_MASK >>
1788 MADERA_DFC1_RX_DATA_TYPE_SHIFT,
1789 ARRAY_SIZE(madera_dfc_type_text),
1790 madera_dfc_type_text,
1791 madera_dfc_type_val),
1792 SOC_VALUE_ENUM_SINGLE(MADERA_DFC2_TX,
1793 MADERA_DFC1_TX_DATA_TYPE_SHIFT,
1794 MADERA_DFC1_TX_DATA_TYPE_MASK >>
1795 MADERA_DFC1_TX_DATA_TYPE_SHIFT,
1796 ARRAY_SIZE(madera_dfc_type_text),
1797 madera_dfc_type_text,
1798 madera_dfc_type_val),
1799 SOC_VALUE_ENUM_SINGLE(MADERA_DFC3_RX,
1800 MADERA_DFC1_RX_DATA_TYPE_SHIFT,
1801 MADERA_DFC1_RX_DATA_TYPE_MASK >>
1802 MADERA_DFC1_RX_DATA_TYPE_SHIFT,
1803 ARRAY_SIZE(madera_dfc_type_text),
1804 madera_dfc_type_text,
1805 madera_dfc_type_val),
1806 SOC_VALUE_ENUM_SINGLE(MADERA_DFC3_TX,
1807 MADERA_DFC1_TX_DATA_TYPE_SHIFT,
1808 MADERA_DFC1_TX_DATA_TYPE_MASK >>
1809 MADERA_DFC1_TX_DATA_TYPE_SHIFT,
1810 ARRAY_SIZE(madera_dfc_type_text),
1811 madera_dfc_type_text,
1812 madera_dfc_type_val),
1813 SOC_VALUE_ENUM_SINGLE(MADERA_DFC4_RX,
1814 MADERA_DFC1_RX_DATA_TYPE_SHIFT,
1815 MADERA_DFC1_RX_DATA_TYPE_MASK >>
1816 MADERA_DFC1_RX_DATA_TYPE_SHIFT,
1817 ARRAY_SIZE(madera_dfc_type_text),
1818 madera_dfc_type_text,
1819 madera_dfc_type_val),
1820 SOC_VALUE_ENUM_SINGLE(MADERA_DFC4_TX,
1821 MADERA_DFC1_TX_DATA_TYPE_SHIFT,
1822 MADERA_DFC1_TX_DATA_TYPE_MASK >>
1823 MADERA_DFC1_TX_DATA_TYPE_SHIFT,
1824 ARRAY_SIZE(madera_dfc_type_text),
1825 madera_dfc_type_text,
1826 madera_dfc_type_val),
1827 SOC_VALUE_ENUM_SINGLE(MADERA_DFC5_RX,
1828 MADERA_DFC1_RX_DATA_TYPE_SHIFT,
1829 MADERA_DFC1_RX_DATA_TYPE_MASK >>
1830 MADERA_DFC1_RX_DATA_TYPE_SHIFT,
1831 ARRAY_SIZE(madera_dfc_type_text),
1832 madera_dfc_type_text,
1833 madera_dfc_type_val),
1834 SOC_VALUE_ENUM_SINGLE(MADERA_DFC5_TX,
1835 MADERA_DFC1_TX_DATA_TYPE_SHIFT,
1836 MADERA_DFC1_TX_DATA_TYPE_MASK >>
1837 MADERA_DFC1_TX_DATA_TYPE_SHIFT,
1838 ARRAY_SIZE(madera_dfc_type_text),
1839 madera_dfc_type_text,
1840 madera_dfc_type_val),
1841 SOC_VALUE_ENUM_SINGLE(MADERA_DFC6_RX,
1842 MADERA_DFC1_RX_DATA_TYPE_SHIFT,
1843 MADERA_DFC1_RX_DATA_TYPE_MASK >>
1844 MADERA_DFC1_RX_DATA_TYPE_SHIFT,
1845 ARRAY_SIZE(madera_dfc_type_text),
1846 madera_dfc_type_text,
1847 madera_dfc_type_val),
1848 SOC_VALUE_ENUM_SINGLE(MADERA_DFC6_TX,
1849 MADERA_DFC1_TX_DATA_TYPE_SHIFT,
1850 MADERA_DFC1_TX_DATA_TYPE_MASK >>
1851 MADERA_DFC1_TX_DATA_TYPE_SHIFT,
1852 ARRAY_SIZE(madera_dfc_type_text),
1853 madera_dfc_type_text,
1854 madera_dfc_type_val),
1855 SOC_VALUE_ENUM_SINGLE(MADERA_DFC7_RX,
1856 MADERA_DFC1_RX_DATA_TYPE_SHIFT,
1857 MADERA_DFC1_RX_DATA_TYPE_MASK >>
1858 MADERA_DFC1_RX_DATA_TYPE_SHIFT,
1859 ARRAY_SIZE(madera_dfc_type_text),
1860 madera_dfc_type_text,
1861 madera_dfc_type_val),
1862 SOC_VALUE_ENUM_SINGLE(MADERA_DFC7_TX,
1863 MADERA_DFC1_TX_DATA_TYPE_SHIFT,
1864 MADERA_DFC1_TX_DATA_TYPE_MASK >>
1865 MADERA_DFC1_TX_DATA_TYPE_SHIFT,
1866 ARRAY_SIZE(madera_dfc_type_text),
1867 madera_dfc_type_text,
1868 madera_dfc_type_val),
1869 SOC_VALUE_ENUM_SINGLE(MADERA_DFC8_RX,
1870 MADERA_DFC1_RX_DATA_TYPE_SHIFT,
1871 MADERA_DFC1_RX_DATA_TYPE_MASK >>
1872 MADERA_DFC1_RX_DATA_TYPE_SHIFT,
1873 ARRAY_SIZE(madera_dfc_type_text),
1874 madera_dfc_type_text,
1875 madera_dfc_type_val),
1876 SOC_VALUE_ENUM_SINGLE(MADERA_DFC8_TX,
1877 MADERA_DFC1_TX_DATA_TYPE_SHIFT,
1878 MADERA_DFC1_TX_DATA_TYPE_MASK >>
1879 MADERA_DFC1_TX_DATA_TYPE_SHIFT,
1880 ARRAY_SIZE(madera_dfc_type_text),
1881 madera_dfc_type_text,
1882 madera_dfc_type_val),
1883};
1884EXPORT_SYMBOL_GPL(madera_dfc_type);
1885
1886const struct soc_enum madera_isrc_fsh[] = {
1887 SOC_VALUE_ENUM_SINGLE(MADERA_ISRC_1_CTRL_1,
1888 MADERA_ISRC1_FSH_SHIFT, 0xf,
1889 MADERA_RATE_ENUM_SIZE,
1890 madera_rate_text, madera_rate_val),
1891 SOC_VALUE_ENUM_SINGLE(MADERA_ISRC_2_CTRL_1,
1892 MADERA_ISRC2_FSH_SHIFT, 0xf,
1893 MADERA_RATE_ENUM_SIZE,
1894 madera_rate_text, madera_rate_val),
1895 SOC_VALUE_ENUM_SINGLE(MADERA_ISRC_3_CTRL_1,
1896 MADERA_ISRC3_FSH_SHIFT, 0xf,
1897 MADERA_RATE_ENUM_SIZE,
1898 madera_rate_text, madera_rate_val),
1899 SOC_VALUE_ENUM_SINGLE(MADERA_ISRC_4_CTRL_1,
1900 MADERA_ISRC4_FSH_SHIFT, 0xf,
1901 MADERA_RATE_ENUM_SIZE,
1902 madera_rate_text, madera_rate_val),
1903};
1904EXPORT_SYMBOL_GPL(madera_isrc_fsh);
1905
1906const struct soc_enum madera_isrc_fsl[] = {
1907 SOC_VALUE_ENUM_SINGLE(MADERA_ISRC_1_CTRL_2,
1908 MADERA_ISRC1_FSL_SHIFT, 0xf,
1909 MADERA_RATE_ENUM_SIZE,
1910 madera_rate_text, madera_rate_val),
1911 SOC_VALUE_ENUM_SINGLE(MADERA_ISRC_2_CTRL_2,
1912 MADERA_ISRC2_FSL_SHIFT, 0xf,
1913 MADERA_RATE_ENUM_SIZE,
1914 madera_rate_text, madera_rate_val),
1915 SOC_VALUE_ENUM_SINGLE(MADERA_ISRC_3_CTRL_2,
1916 MADERA_ISRC3_FSL_SHIFT, 0xf,
1917 MADERA_RATE_ENUM_SIZE,
1918 madera_rate_text, madera_rate_val),
1919 SOC_VALUE_ENUM_SINGLE(MADERA_ISRC_4_CTRL_2,
1920 MADERA_ISRC4_FSL_SHIFT, 0xf,
1921 MADERA_RATE_ENUM_SIZE,
1922 madera_rate_text, madera_rate_val),
1923};
1924EXPORT_SYMBOL_GPL(madera_isrc_fsl);
1925
1926const struct soc_enum madera_asrc1_rate[] = {
1927 SOC_VALUE_ENUM_SINGLE(MADERA_ASRC1_RATE1,
1928 MADERA_ASRC1_RATE1_SHIFT, 0xf,
1929 MADERA_SYNC_RATE_ENUM_SIZE,
1930 madera_rate_text, madera_rate_val),
1931 SOC_VALUE_ENUM_SINGLE(MADERA_ASRC1_RATE2,
1932 MADERA_ASRC1_RATE1_SHIFT, 0xf,
1933 MADERA_ASYNC_RATE_ENUM_SIZE,
1934 madera_rate_text + MADERA_SYNC_RATE_ENUM_SIZE,
1935 madera_rate_val + MADERA_SYNC_RATE_ENUM_SIZE),
1936};
1937EXPORT_SYMBOL_GPL(madera_asrc1_rate);
1938
1939const struct soc_enum madera_asrc1_bidir_rate[] = {
1940 SOC_VALUE_ENUM_SINGLE(MADERA_ASRC1_RATE1,
1941 MADERA_ASRC1_RATE1_SHIFT, 0xf,
1942 MADERA_RATE_ENUM_SIZE,
1943 madera_rate_text, madera_rate_val),
1944 SOC_VALUE_ENUM_SINGLE(MADERA_ASRC1_RATE2,
1945 MADERA_ASRC1_RATE2_SHIFT, 0xf,
1946 MADERA_RATE_ENUM_SIZE,
1947 madera_rate_text, madera_rate_val),
1948};
1949EXPORT_SYMBOL_GPL(madera_asrc1_bidir_rate);
1950
1951const struct soc_enum madera_asrc2_rate[] = {
1952 SOC_VALUE_ENUM_SINGLE(MADERA_ASRC2_RATE1,
1953 MADERA_ASRC2_RATE1_SHIFT, 0xf,
1954 MADERA_SYNC_RATE_ENUM_SIZE,
1955 madera_rate_text, madera_rate_val),
1956 SOC_VALUE_ENUM_SINGLE(MADERA_ASRC2_RATE2,
1957 MADERA_ASRC2_RATE2_SHIFT, 0xf,
1958 MADERA_ASYNC_RATE_ENUM_SIZE,
1959 madera_rate_text + MADERA_SYNC_RATE_ENUM_SIZE,
1960 madera_rate_val + MADERA_SYNC_RATE_ENUM_SIZE),
1961};
1962EXPORT_SYMBOL_GPL(madera_asrc2_rate);
1963
1964static const char * const madera_vol_ramp_text[] = {
1965 "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB",
1966 "15ms/6dB", "30ms/6dB",
1967};
1968
1969SOC_ENUM_SINGLE_DECL(madera_in_vd_ramp,
1970 MADERA_INPUT_VOLUME_RAMP,
1971 MADERA_IN_VD_RAMP_SHIFT,
1972 madera_vol_ramp_text);
1973EXPORT_SYMBOL_GPL(madera_in_vd_ramp);
1974
1975SOC_ENUM_SINGLE_DECL(madera_in_vi_ramp,
1976 MADERA_INPUT_VOLUME_RAMP,
1977 MADERA_IN_VI_RAMP_SHIFT,
1978 madera_vol_ramp_text);
1979EXPORT_SYMBOL_GPL(madera_in_vi_ramp);
1980
1981SOC_ENUM_SINGLE_DECL(madera_out_vd_ramp,
1982 MADERA_OUTPUT_VOLUME_RAMP,
1983 MADERA_OUT_VD_RAMP_SHIFT,
1984 madera_vol_ramp_text);
1985EXPORT_SYMBOL_GPL(madera_out_vd_ramp);
1986
1987SOC_ENUM_SINGLE_DECL(madera_out_vi_ramp,
1988 MADERA_OUTPUT_VOLUME_RAMP,
1989 MADERA_OUT_VI_RAMP_SHIFT,
1990 madera_vol_ramp_text);
1991EXPORT_SYMBOL_GPL(madera_out_vi_ramp);
1992
1993static const char * const madera_lhpf_mode_text[] = {
1994 "Low-pass", "High-pass"
1995};
1996
1997SOC_ENUM_SINGLE_DECL(madera_lhpf1_mode,
1998 MADERA_HPLPF1_1,
1999 MADERA_LHPF1_MODE_SHIFT,
2000 madera_lhpf_mode_text);
2001EXPORT_SYMBOL_GPL(madera_lhpf1_mode);
2002
2003SOC_ENUM_SINGLE_DECL(madera_lhpf2_mode,
2004 MADERA_HPLPF2_1,
2005 MADERA_LHPF2_MODE_SHIFT,
2006 madera_lhpf_mode_text);
2007EXPORT_SYMBOL_GPL(madera_lhpf2_mode);
2008
2009SOC_ENUM_SINGLE_DECL(madera_lhpf3_mode,
2010 MADERA_HPLPF3_1,
2011 MADERA_LHPF3_MODE_SHIFT,
2012 madera_lhpf_mode_text);
2013EXPORT_SYMBOL_GPL(madera_lhpf3_mode);
2014
2015SOC_ENUM_SINGLE_DECL(madera_lhpf4_mode,
2016 MADERA_HPLPF4_1,
2017 MADERA_LHPF4_MODE_SHIFT,
2018 madera_lhpf_mode_text);
2019EXPORT_SYMBOL_GPL(madera_lhpf4_mode);
2020
2021static const char * const madera_ng_hold_text[] = {
2022 "30ms", "120ms", "250ms", "500ms",
2023};
2024
2025SOC_ENUM_SINGLE_DECL(madera_ng_hold,
2026 MADERA_NOISE_GATE_CONTROL,
2027 MADERA_NGATE_HOLD_SHIFT,
2028 madera_ng_hold_text);
2029EXPORT_SYMBOL_GPL(madera_ng_hold);
2030
2031static const char * const madera_in_hpf_cut_text[] = {
2032 "2.5Hz", "5Hz", "10Hz", "20Hz", "40Hz"
2033};
2034
2035SOC_ENUM_SINGLE_DECL(madera_in_hpf_cut_enum,
2036 MADERA_HPF_CONTROL,
2037 MADERA_IN_HPF_CUT_SHIFT,
2038 madera_in_hpf_cut_text);
2039EXPORT_SYMBOL_GPL(madera_in_hpf_cut_enum);
2040
2041static const char * const madera_in_dmic_osr_text[MADERA_OSR_ENUM_SIZE] = {
2042 "384kHz", "768kHz", "1.536MHz", "3.072MHz", "6.144MHz",
2043};
2044
2045static const unsigned int madera_in_dmic_osr_val[MADERA_OSR_ENUM_SIZE] = {
2046 2, 3, 4, 5, 6,
2047};
2048
2049const struct soc_enum madera_in_dmic_osr[] = {
2050 SOC_VALUE_ENUM_SINGLE(MADERA_DMIC1L_CONTROL, MADERA_IN1_OSR_SHIFT,
2051 0x7, MADERA_OSR_ENUM_SIZE,
2052 madera_in_dmic_osr_text, madera_in_dmic_osr_val),
2053 SOC_VALUE_ENUM_SINGLE(MADERA_DMIC2L_CONTROL, MADERA_IN2_OSR_SHIFT,
2054 0x7, MADERA_OSR_ENUM_SIZE,
2055 madera_in_dmic_osr_text, madera_in_dmic_osr_val),
2056 SOC_VALUE_ENUM_SINGLE(MADERA_DMIC3L_CONTROL, MADERA_IN3_OSR_SHIFT,
2057 0x7, MADERA_OSR_ENUM_SIZE,
2058 madera_in_dmic_osr_text, madera_in_dmic_osr_val),
2059 SOC_VALUE_ENUM_SINGLE(MADERA_DMIC4L_CONTROL, MADERA_IN4_OSR_SHIFT,
2060 0x7, MADERA_OSR_ENUM_SIZE,
2061 madera_in_dmic_osr_text, madera_in_dmic_osr_val),
2062 SOC_VALUE_ENUM_SINGLE(MADERA_DMIC5L_CONTROL, MADERA_IN5_OSR_SHIFT,
2063 0x7, MADERA_OSR_ENUM_SIZE,
2064 madera_in_dmic_osr_text, madera_in_dmic_osr_val),
2065 SOC_VALUE_ENUM_SINGLE(MADERA_DMIC6L_CONTROL, MADERA_IN6_OSR_SHIFT,
2066 0x7, MADERA_OSR_ENUM_SIZE,
2067 madera_in_dmic_osr_text, madera_in_dmic_osr_val),
2068};
2069EXPORT_SYMBOL_GPL(madera_in_dmic_osr);
2070
2071static const char * const madera_anc_input_src_text[] = {
2072 "None", "IN1", "IN2", "IN3", "IN4", "IN5", "IN6",
2073};
2074
2075static const char * const madera_anc_channel_src_text[] = {
2076 "None", "Left", "Right", "Combine",
2077};
2078
2079const struct soc_enum madera_anc_input_src[] = {
2080 SOC_ENUM_SINGLE(MADERA_ANC_SRC,
2081 MADERA_IN_RXANCL_SEL_SHIFT,
2082 ARRAY_SIZE(madera_anc_input_src_text),
2083 madera_anc_input_src_text),
2084 SOC_ENUM_SINGLE(MADERA_FCL_ADC_REFORMATTER_CONTROL,
2085 MADERA_FCL_MIC_MODE_SEL_SHIFT,
2086 ARRAY_SIZE(madera_anc_channel_src_text),
2087 madera_anc_channel_src_text),
2088 SOC_ENUM_SINGLE(MADERA_ANC_SRC,
2089 MADERA_IN_RXANCR_SEL_SHIFT,
2090 ARRAY_SIZE(madera_anc_input_src_text),
2091 madera_anc_input_src_text),
2092 SOC_ENUM_SINGLE(MADERA_FCR_ADC_REFORMATTER_CONTROL,
2093 MADERA_FCR_MIC_MODE_SEL_SHIFT,
2094 ARRAY_SIZE(madera_anc_channel_src_text),
2095 madera_anc_channel_src_text),
2096};
2097EXPORT_SYMBOL_GPL(madera_anc_input_src);
2098
2099static const char * const madera_anc_ng_texts[] = {
2100 "None", "Internal", "External",
2101};
2102
2103SOC_ENUM_SINGLE_DECL(madera_anc_ng_enum, SND_SOC_NOPM, 0, madera_anc_ng_texts);
2104EXPORT_SYMBOL_GPL(madera_anc_ng_enum);
2105
2106static const char * const madera_out_anc_src_text[] = {
2107 "None", "RXANCL", "RXANCR",
2108};
2109
2110const struct soc_enum madera_output_anc_src[] = {
2111 SOC_ENUM_SINGLE(MADERA_OUTPUT_PATH_CONFIG_1L,
2112 MADERA_OUT1L_ANC_SRC_SHIFT,
2113 ARRAY_SIZE(madera_out_anc_src_text),
2114 madera_out_anc_src_text),
2115 SOC_ENUM_SINGLE(MADERA_OUTPUT_PATH_CONFIG_1R,
2116 MADERA_OUT1R_ANC_SRC_SHIFT,
2117 ARRAY_SIZE(madera_out_anc_src_text),
2118 madera_out_anc_src_text),
2119 SOC_ENUM_SINGLE(MADERA_OUTPUT_PATH_CONFIG_2L,
2120 MADERA_OUT2L_ANC_SRC_SHIFT,
2121 ARRAY_SIZE(madera_out_anc_src_text),
2122 madera_out_anc_src_text),
2123 SOC_ENUM_SINGLE(MADERA_OUTPUT_PATH_CONFIG_2R,
2124 MADERA_OUT2R_ANC_SRC_SHIFT,
2125 ARRAY_SIZE(madera_out_anc_src_text),
2126 madera_out_anc_src_text),
2127 SOC_ENUM_SINGLE(MADERA_OUTPUT_PATH_CONFIG_3L,
2128 MADERA_OUT3L_ANC_SRC_SHIFT,
2129 ARRAY_SIZE(madera_out_anc_src_text),
2130 madera_out_anc_src_text),
2131 SOC_ENUM_SINGLE(MADERA_OUTPUT_PATH_CONFIG_3R,
2132 MADERA_OUT3R_ANC_SRC_SHIFT,
2133 ARRAY_SIZE(madera_out_anc_src_text),
2134 madera_out_anc_src_text),
2135 SOC_ENUM_SINGLE(MADERA_OUTPUT_PATH_CONFIG_4L,
2136 MADERA_OUT4L_ANC_SRC_SHIFT,
2137 ARRAY_SIZE(madera_out_anc_src_text),
2138 madera_out_anc_src_text),
2139 SOC_ENUM_SINGLE(MADERA_OUTPUT_PATH_CONFIG_4R,
2140 MADERA_OUT4R_ANC_SRC_SHIFT,
2141 ARRAY_SIZE(madera_out_anc_src_text),
2142 madera_out_anc_src_text),
2143 SOC_ENUM_SINGLE(MADERA_OUTPUT_PATH_CONFIG_5L,
2144 MADERA_OUT5L_ANC_SRC_SHIFT,
2145 ARRAY_SIZE(madera_out_anc_src_text),
2146 madera_out_anc_src_text),
2147 SOC_ENUM_SINGLE(MADERA_OUTPUT_PATH_CONFIG_5R,
2148 MADERA_OUT5R_ANC_SRC_SHIFT,
2149 ARRAY_SIZE(madera_out_anc_src_text),
2150 madera_out_anc_src_text),
2151 SOC_ENUM_SINGLE(MADERA_OUTPUT_PATH_CONFIG_6L,
2152 MADERA_OUT6L_ANC_SRC_SHIFT,
2153 ARRAY_SIZE(madera_out_anc_src_text),
2154 madera_out_anc_src_text),
2155 SOC_ENUM_SINGLE(MADERA_OUTPUT_PATH_CONFIG_6R,
2156 MADERA_OUT6R_ANC_SRC_SHIFT,
2157 ARRAY_SIZE(madera_out_anc_src_text),
2158 madera_out_anc_src_text),
2159};
2160EXPORT_SYMBOL_GPL(madera_output_anc_src);
2161
2162int madera_dfc_put(struct snd_kcontrol *kcontrol,
2163 struct snd_ctl_elem_value *ucontrol)
2164{
2165 struct snd_soc_component *component =
2166 snd_soc_kcontrol_component(kcontrol);
2167 struct snd_soc_dapm_context *dapm =
2168 snd_soc_component_get_dapm(component);
2169 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
2170 unsigned int reg = e->reg;
2171 unsigned int val;
2172 int ret = 0;
2173
2174 reg = ((reg / 6) * 6) - 2;
2175
2176 snd_soc_dapm_mutex_lock(dapm);
2177
2178 val = snd_soc_component_read(component, reg);
2179 if (val & MADERA_DFC1_ENA) {
2180 ret = -EBUSY;
2181 dev_err(component->dev, "Can't change mode on an active DFC\n");
2182 goto exit;
2183 }
2184
2185 ret = snd_soc_put_enum_double(kcontrol, ucontrol);
2186exit:
2187 snd_soc_dapm_mutex_unlock(dapm);
2188
2189 return ret;
2190}
2191EXPORT_SYMBOL_GPL(madera_dfc_put);
2192
2193int madera_lp_mode_put(struct snd_kcontrol *kcontrol,
2194 struct snd_ctl_elem_value *ucontrol)
2195{
2196 struct soc_mixer_control *mc =
2197 (struct soc_mixer_control *)kcontrol->private_value;
2198 struct snd_soc_component *component =
2199 snd_soc_kcontrol_component(kcontrol);
2200 struct snd_soc_dapm_context *dapm =
2201 snd_soc_component_get_dapm(component);
2202 unsigned int val, mask;
2203 int ret;
2204
2205 snd_soc_dapm_mutex_lock(dapm);
2206
2207 /* Cannot change lp mode on an active input */
2208 val = snd_soc_component_read(component, MADERA_INPUT_ENABLES);
2209 mask = (mc->reg - MADERA_ADC_DIGITAL_VOLUME_1L) / 4;
2210 mask ^= 0x1; /* Flip bottom bit for channel order */
2211
2212 if (val & (1 << mask)) {
2213 ret = -EBUSY;
2214 dev_err(component->dev,
2215 "Can't change lp mode on an active input\n");
2216 goto exit;
2217 }
2218
2219 ret = snd_soc_put_volsw(kcontrol, ucontrol);
2220
2221exit:
2222 snd_soc_dapm_mutex_unlock(dapm);
2223
2224 return ret;
2225}
2226EXPORT_SYMBOL_GPL(madera_lp_mode_put);
2227
2228const struct snd_kcontrol_new madera_dsp_trigger_output_mux[] = {
2229 SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0),
2230 SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0),
2231 SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0),
2232 SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0),
2233 SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0),
2234 SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0),
2235 SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0),
2236};
2237EXPORT_SYMBOL_GPL(madera_dsp_trigger_output_mux);
2238
2239const struct snd_kcontrol_new madera_drc_activity_output_mux[] = {
2240 SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0),
2241 SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0),
2242};
2243EXPORT_SYMBOL_GPL(madera_drc_activity_output_mux);
2244
2245static void madera_in_set_vu(struct madera_priv *priv, bool enable)
2246{
2247 unsigned int val;
2248 int i, ret;
2249
2250 if (enable)
2251 val = MADERA_IN_VU;
2252 else
2253 val = 0;
2254
2255 for (i = 0; i < priv->num_inputs; i++) {
2256 ret = regmap_update_bits(map: priv->madera->regmap,
2257 MADERA_ADC_DIGITAL_VOLUME_1L + (i * 4),
2258 MADERA_IN_VU, val);
2259 if (ret)
2260 dev_warn(priv->madera->dev,
2261 "Failed to modify VU bits: %d\n", ret);
2262 }
2263}
2264
2265int madera_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
2266 int event)
2267{
2268 struct snd_soc_component *component = snd_soc_dapm_to_component(dapm: w->dapm);
2269 struct madera_priv *priv = snd_soc_component_get_drvdata(c: component);
2270 unsigned int reg, val;
2271
2272 if (w->shift % 2)
2273 reg = MADERA_ADC_DIGITAL_VOLUME_1L + ((w->shift / 2) * 8);
2274 else
2275 reg = MADERA_ADC_DIGITAL_VOLUME_1R + ((w->shift / 2) * 8);
2276
2277 switch (event) {
2278 case SND_SOC_DAPM_PRE_PMU:
2279 priv->in_pending++;
2280 break;
2281 case SND_SOC_DAPM_POST_PMU:
2282 priv->in_pending--;
2283 snd_soc_component_update_bits(component, reg,
2284 MADERA_IN1L_MUTE, val: 0);
2285
2286 /* If this is the last input pending then allow VU */
2287 if (priv->in_pending == 0) {
2288 usleep_range(min: 1000, max: 3000);
2289 madera_in_set_vu(priv, enable: true);
2290 }
2291 break;
2292 case SND_SOC_DAPM_PRE_PMD:
2293 snd_soc_component_update_bits(component, reg,
2294 MADERA_IN1L_MUTE | MADERA_IN_VU,
2295 MADERA_IN1L_MUTE | MADERA_IN_VU);
2296 break;
2297 case SND_SOC_DAPM_POST_PMD:
2298 /* Disable volume updates if no inputs are enabled */
2299 val = snd_soc_component_read(component, MADERA_INPUT_ENABLES);
2300 if (!val)
2301 madera_in_set_vu(priv, enable: false);
2302 break;
2303 default:
2304 break;
2305 }
2306
2307 return 0;
2308}
2309EXPORT_SYMBOL_GPL(madera_in_ev);
2310
2311int madera_out_ev(struct snd_soc_dapm_widget *w,
2312 struct snd_kcontrol *kcontrol, int event)
2313{
2314 struct snd_soc_component *component = snd_soc_dapm_to_component(dapm: w->dapm);
2315 struct madera_priv *priv = snd_soc_component_get_drvdata(c: component);
2316 struct madera *madera = priv->madera;
2317 int out_up_delay;
2318
2319 switch (madera->type) {
2320 case CS47L90:
2321 case CS47L91:
2322 case CS42L92:
2323 case CS47L92:
2324 case CS47L93:
2325 out_up_delay = 6;
2326 break;
2327 default:
2328 out_up_delay = 17;
2329 break;
2330 }
2331
2332 switch (event) {
2333 case SND_SOC_DAPM_PRE_PMU:
2334 switch (w->shift) {
2335 case MADERA_OUT1L_ENA_SHIFT:
2336 case MADERA_OUT1R_ENA_SHIFT:
2337 case MADERA_OUT2L_ENA_SHIFT:
2338 case MADERA_OUT2R_ENA_SHIFT:
2339 case MADERA_OUT3L_ENA_SHIFT:
2340 case MADERA_OUT3R_ENA_SHIFT:
2341 priv->out_up_pending++;
2342 priv->out_up_delay += out_up_delay;
2343 break;
2344 default:
2345 break;
2346 }
2347 break;
2348
2349 case SND_SOC_DAPM_POST_PMU:
2350 switch (w->shift) {
2351 case MADERA_OUT1L_ENA_SHIFT:
2352 case MADERA_OUT1R_ENA_SHIFT:
2353 case MADERA_OUT2L_ENA_SHIFT:
2354 case MADERA_OUT2R_ENA_SHIFT:
2355 case MADERA_OUT3L_ENA_SHIFT:
2356 case MADERA_OUT3R_ENA_SHIFT:
2357 priv->out_up_pending--;
2358 if (!priv->out_up_pending) {
2359 msleep(msecs: priv->out_up_delay);
2360 priv->out_up_delay = 0;
2361 }
2362 break;
2363
2364 default:
2365 break;
2366 }
2367 break;
2368
2369 case SND_SOC_DAPM_PRE_PMD:
2370 switch (w->shift) {
2371 case MADERA_OUT1L_ENA_SHIFT:
2372 case MADERA_OUT1R_ENA_SHIFT:
2373 case MADERA_OUT2L_ENA_SHIFT:
2374 case MADERA_OUT2R_ENA_SHIFT:
2375 case MADERA_OUT3L_ENA_SHIFT:
2376 case MADERA_OUT3R_ENA_SHIFT:
2377 priv->out_down_pending++;
2378 priv->out_down_delay++;
2379 break;
2380 default:
2381 break;
2382 }
2383 break;
2384
2385 case SND_SOC_DAPM_POST_PMD:
2386 switch (w->shift) {
2387 case MADERA_OUT1L_ENA_SHIFT:
2388 case MADERA_OUT1R_ENA_SHIFT:
2389 case MADERA_OUT2L_ENA_SHIFT:
2390 case MADERA_OUT2R_ENA_SHIFT:
2391 case MADERA_OUT3L_ENA_SHIFT:
2392 case MADERA_OUT3R_ENA_SHIFT:
2393 priv->out_down_pending--;
2394 if (!priv->out_down_pending) {
2395 msleep(msecs: priv->out_down_delay);
2396 priv->out_down_delay = 0;
2397 }
2398 break;
2399 default:
2400 break;
2401 }
2402 break;
2403 default:
2404 break;
2405 }
2406
2407 return 0;
2408}
2409EXPORT_SYMBOL_GPL(madera_out_ev);
2410
2411int madera_hp_ev(struct snd_soc_dapm_widget *w,
2412 struct snd_kcontrol *kcontrol, int event)
2413{
2414 struct snd_soc_component *component = snd_soc_dapm_to_component(dapm: w->dapm);
2415 struct madera_priv *priv = snd_soc_component_get_drvdata(c: component);
2416 struct madera *madera = priv->madera;
2417 unsigned int mask = 1 << w->shift;
2418 unsigned int out_num = w->shift / 2;
2419 unsigned int val;
2420 unsigned int ep_sel = 0;
2421
2422 switch (event) {
2423 case SND_SOC_DAPM_POST_PMU:
2424 val = mask;
2425 break;
2426 case SND_SOC_DAPM_PRE_PMD:
2427 val = 0;
2428 break;
2429 case SND_SOC_DAPM_PRE_PMU:
2430 case SND_SOC_DAPM_POST_PMD:
2431 return madera_out_ev(w, kcontrol, event);
2432 default:
2433 return 0;
2434 }
2435
2436 /* Store the desired state for the HP outputs */
2437 madera->hp_ena &= ~mask;
2438 madera->hp_ena |= val;
2439
2440 switch (madera->type) {
2441 case CS42L92:
2442 case CS47L92:
2443 case CS47L93:
2444 break;
2445 default:
2446 /* if OUT1 is routed to EPOUT, ignore HP clamp and impedance */
2447 regmap_read(map: madera->regmap, MADERA_OUTPUT_ENABLES_1, val: &ep_sel);
2448 ep_sel &= MADERA_EP_SEL_MASK;
2449 break;
2450 }
2451
2452 /* Force off if HPDET has disabled the clamp for this output */
2453 if (!ep_sel &&
2454 (!madera->out_clamp[out_num] || madera->out_shorted[out_num]))
2455 val = 0;
2456
2457 regmap_update_bits(map: madera->regmap, MADERA_OUTPUT_ENABLES_1, mask, val);
2458
2459 return madera_out_ev(w, kcontrol, event);
2460}
2461EXPORT_SYMBOL_GPL(madera_hp_ev);
2462
2463int madera_anc_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
2464 int event)
2465{
2466 struct snd_soc_component *component = snd_soc_dapm_to_component(dapm: w->dapm);
2467 unsigned int val;
2468
2469 switch (event) {
2470 case SND_SOC_DAPM_POST_PMU:
2471 val = 1 << w->shift;
2472 break;
2473 case SND_SOC_DAPM_PRE_PMD:
2474 val = 1 << (w->shift + 1);
2475 break;
2476 default:
2477 return 0;
2478 }
2479
2480 snd_soc_component_write(component, MADERA_CLOCK_CONTROL, val);
2481
2482 return 0;
2483}
2484EXPORT_SYMBOL_GPL(madera_anc_ev);
2485
2486static const unsigned int madera_opclk_ref_48k_rates[] = {
2487 6144000,
2488 12288000,
2489 24576000,
2490 49152000,
2491};
2492
2493static const unsigned int madera_opclk_ref_44k1_rates[] = {
2494 5644800,
2495 11289600,
2496 22579200,
2497 45158400,
2498};
2499
2500static int madera_set_opclk(struct snd_soc_component *component,
2501 unsigned int clk, unsigned int freq)
2502{
2503 struct madera_priv *priv = snd_soc_component_get_drvdata(c: component);
2504 unsigned int mask = MADERA_OPCLK_DIV_MASK | MADERA_OPCLK_SEL_MASK;
2505 unsigned int reg, val;
2506 const unsigned int *rates;
2507 int ref, div, refclk;
2508
2509 BUILD_BUG_ON(ARRAY_SIZE(madera_opclk_ref_48k_rates) !=
2510 ARRAY_SIZE(madera_opclk_ref_44k1_rates));
2511
2512 switch (clk) {
2513 case MADERA_CLK_OPCLK:
2514 reg = MADERA_OUTPUT_SYSTEM_CLOCK;
2515 refclk = priv->sysclk;
2516 break;
2517 case MADERA_CLK_ASYNC_OPCLK:
2518 reg = MADERA_OUTPUT_ASYNC_CLOCK;
2519 refclk = priv->asyncclk;
2520 break;
2521 default:
2522 return -EINVAL;
2523 }
2524
2525 if (refclk % 4000)
2526 rates = madera_opclk_ref_44k1_rates;
2527 else
2528 rates = madera_opclk_ref_48k_rates;
2529
2530 for (ref = 0; ref < ARRAY_SIZE(madera_opclk_ref_48k_rates); ++ref) {
2531 if (rates[ref] > refclk)
2532 continue;
2533
2534 div = 2;
2535 while ((rates[ref] / div >= freq) && (div <= 30)) {
2536 if (rates[ref] / div == freq) {
2537 dev_dbg(component->dev, "Configured %dHz OPCLK\n",
2538 freq);
2539
2540 val = (div << MADERA_OPCLK_DIV_SHIFT) | ref;
2541
2542 snd_soc_component_update_bits(component, reg,
2543 mask, val);
2544 return 0;
2545 }
2546 div += 2;
2547 }
2548 }
2549
2550 dev_err(component->dev, "Unable to generate %dHz OPCLK\n", freq);
2551
2552 return -EINVAL;
2553}
2554
2555static int madera_get_sysclk_setting(unsigned int freq)
2556{
2557 switch (freq) {
2558 case 0:
2559 case 5644800:
2560 case 6144000:
2561 return 0;
2562 case 11289600:
2563 case 12288000:
2564 return MADERA_SYSCLK_12MHZ << MADERA_SYSCLK_FREQ_SHIFT;
2565 case 22579200:
2566 case 24576000:
2567 return MADERA_SYSCLK_24MHZ << MADERA_SYSCLK_FREQ_SHIFT;
2568 case 45158400:
2569 case 49152000:
2570 return MADERA_SYSCLK_49MHZ << MADERA_SYSCLK_FREQ_SHIFT;
2571 case 90316800:
2572 case 98304000:
2573 return MADERA_SYSCLK_98MHZ << MADERA_SYSCLK_FREQ_SHIFT;
2574 default:
2575 return -EINVAL;
2576 }
2577}
2578
2579static int madera_get_legacy_dspclk_setting(struct madera *madera,
2580 unsigned int freq)
2581{
2582 switch (freq) {
2583 case 0:
2584 return 0;
2585 case 45158400:
2586 case 49152000:
2587 switch (madera->type) {
2588 case CS47L85:
2589 case WM1840:
2590 if (madera->rev < 3)
2591 return -EINVAL;
2592 else
2593 return MADERA_SYSCLK_49MHZ <<
2594 MADERA_SYSCLK_FREQ_SHIFT;
2595 default:
2596 return -EINVAL;
2597 }
2598 case 135475200:
2599 case 147456000:
2600 return MADERA_DSPCLK_147MHZ << MADERA_DSP_CLK_FREQ_LEGACY_SHIFT;
2601 default:
2602 return -EINVAL;
2603 }
2604}
2605
2606static int madera_get_dspclk_setting(struct madera *madera,
2607 unsigned int freq,
2608 unsigned int *clock_2_val)
2609{
2610 switch (madera->type) {
2611 case CS47L35:
2612 case CS47L85:
2613 case WM1840:
2614 *clock_2_val = 0; /* don't use MADERA_DSP_CLOCK_2 */
2615 return madera_get_legacy_dspclk_setting(madera, freq);
2616 default:
2617 if (freq > 150000000)
2618 return -EINVAL;
2619
2620 /* Use new exact frequency control */
2621 *clock_2_val = freq / 15625; /* freq * (2^6) / (10^6) */
2622 return 0;
2623 }
2624}
2625
2626static int madera_set_outclk(struct snd_soc_component *component,
2627 unsigned int source, unsigned int freq)
2628{
2629 int div, div_inc, rate;
2630
2631 switch (source) {
2632 case MADERA_OUTCLK_SYSCLK:
2633 dev_dbg(component->dev, "Configured OUTCLK to SYSCLK\n");
2634 snd_soc_component_update_bits(component, MADERA_OUTPUT_RATE_1,
2635 MADERA_OUT_CLK_SRC_MASK, val: source);
2636 return 0;
2637 case MADERA_OUTCLK_ASYNCCLK:
2638 dev_dbg(component->dev, "Configured OUTCLK to ASYNCCLK\n");
2639 snd_soc_component_update_bits(component, MADERA_OUTPUT_RATE_1,
2640 MADERA_OUT_CLK_SRC_MASK, val: source);
2641 return 0;
2642 case MADERA_OUTCLK_MCLK1:
2643 case MADERA_OUTCLK_MCLK2:
2644 case MADERA_OUTCLK_MCLK3:
2645 break;
2646 default:
2647 return -EINVAL;
2648 }
2649
2650 if (freq % 4000)
2651 rate = 5644800;
2652 else
2653 rate = 6144000;
2654
2655 div = 1;
2656 div_inc = 0;
2657 while (div <= 8) {
2658 if (freq / div == rate && !(freq % div)) {
2659 dev_dbg(component->dev, "Configured %dHz OUTCLK\n", rate);
2660 snd_soc_component_update_bits(component,
2661 MADERA_OUTPUT_RATE_1,
2662 MADERA_OUT_EXT_CLK_DIV_MASK |
2663 MADERA_OUT_CLK_SRC_MASK,
2664 val: (div_inc << MADERA_OUT_EXT_CLK_DIV_SHIFT) |
2665 source);
2666 return 0;
2667 }
2668 div_inc++;
2669 div *= 2;
2670 }
2671
2672 dev_err(component->dev,
2673 "Unable to generate %dHz OUTCLK from %dHz MCLK\n",
2674 rate, freq);
2675 return -EINVAL;
2676}
2677
2678int madera_set_sysclk(struct snd_soc_component *component, int clk_id,
2679 int source, unsigned int freq, int dir)
2680{
2681 struct madera_priv *priv = snd_soc_component_get_drvdata(c: component);
2682 struct madera *madera = priv->madera;
2683 char *name;
2684 unsigned int reg, clock_2_val = 0;
2685 unsigned int mask = MADERA_SYSCLK_FREQ_MASK | MADERA_SYSCLK_SRC_MASK;
2686 unsigned int val = source << MADERA_SYSCLK_SRC_SHIFT;
2687 int clk_freq_sel, *clk;
2688 int ret = 0;
2689
2690 switch (clk_id) {
2691 case MADERA_CLK_SYSCLK_1:
2692 name = "SYSCLK";
2693 reg = MADERA_SYSTEM_CLOCK_1;
2694 clk = &priv->sysclk;
2695 clk_freq_sel = madera_get_sysclk_setting(freq);
2696 mask |= MADERA_SYSCLK_FRAC;
2697 break;
2698 case MADERA_CLK_ASYNCCLK_1:
2699 name = "ASYNCCLK";
2700 reg = MADERA_ASYNC_CLOCK_1;
2701 clk = &priv->asyncclk;
2702 clk_freq_sel = madera_get_sysclk_setting(freq);
2703 break;
2704 case MADERA_CLK_DSPCLK:
2705 name = "DSPCLK";
2706 reg = MADERA_DSP_CLOCK_1;
2707 clk = &priv->dspclk;
2708 clk_freq_sel = madera_get_dspclk_setting(madera, freq,
2709 clock_2_val: &clock_2_val);
2710 break;
2711 case MADERA_CLK_OPCLK:
2712 case MADERA_CLK_ASYNC_OPCLK:
2713 return madera_set_opclk(component, clk: clk_id, freq);
2714 case MADERA_CLK_OUTCLK:
2715 return madera_set_outclk(component, source, freq);
2716 default:
2717 return -EINVAL;
2718 }
2719
2720 if (clk_freq_sel < 0) {
2721 dev_err(madera->dev,
2722 "Failed to get clk setting for %dHZ\n", freq);
2723 return clk_freq_sel;
2724 }
2725
2726 *clk = freq;
2727
2728 if (freq == 0) {
2729 dev_dbg(madera->dev, "%s cleared\n", name);
2730 return 0;
2731 }
2732
2733 val |= clk_freq_sel;
2734
2735 if (clock_2_val) {
2736 ret = regmap_write(map: madera->regmap, MADERA_DSP_CLOCK_2,
2737 val: clock_2_val);
2738 if (ret) {
2739 dev_err(madera->dev,
2740 "Failed to write DSP_CONFIG2: %d\n", ret);
2741 return ret;
2742 }
2743
2744 /*
2745 * We're using the frequency setting in MADERA_DSP_CLOCK_2 so
2746 * don't change the frequency select bits in MADERA_DSP_CLOCK_1
2747 */
2748 mask = MADERA_SYSCLK_SRC_MASK;
2749 }
2750
2751 if (freq % 6144000)
2752 val |= MADERA_SYSCLK_FRAC;
2753
2754 dev_dbg(madera->dev, "%s set to %uHz\n", name, freq);
2755
2756 return regmap_update_bits(map: madera->regmap, reg, mask, val);
2757}
2758EXPORT_SYMBOL_GPL(madera_set_sysclk);
2759
2760static int madera_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
2761{
2762 struct snd_soc_component *component = dai->component;
2763 struct madera_priv *priv = snd_soc_component_get_drvdata(c: component);
2764 struct madera *madera = priv->madera;
2765 int lrclk, bclk, mode, base;
2766
2767 base = dai->driver->base;
2768
2769 lrclk = 0;
2770 bclk = 0;
2771
2772 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
2773 case SND_SOC_DAIFMT_DSP_A:
2774 mode = MADERA_FMT_DSP_MODE_A;
2775 break;
2776 case SND_SOC_DAIFMT_DSP_B:
2777 if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) !=
2778 SND_SOC_DAIFMT_CBM_CFM) {
2779 madera_aif_err(dai, "DSP_B not valid in slave mode\n");
2780 return -EINVAL;
2781 }
2782 mode = MADERA_FMT_DSP_MODE_B;
2783 break;
2784 case SND_SOC_DAIFMT_I2S:
2785 mode = MADERA_FMT_I2S_MODE;
2786 break;
2787 case SND_SOC_DAIFMT_LEFT_J:
2788 if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) !=
2789 SND_SOC_DAIFMT_CBM_CFM) {
2790 madera_aif_err(dai, "LEFT_J not valid in slave mode\n");
2791 return -EINVAL;
2792 }
2793 mode = MADERA_FMT_LEFT_JUSTIFIED_MODE;
2794 break;
2795 default:
2796 madera_aif_err(dai, "Unsupported DAI format %d\n",
2797 fmt & SND_SOC_DAIFMT_FORMAT_MASK);
2798 return -EINVAL;
2799 }
2800
2801 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
2802 case SND_SOC_DAIFMT_CBS_CFS:
2803 break;
2804 case SND_SOC_DAIFMT_CBS_CFM:
2805 lrclk |= MADERA_AIF1TX_LRCLK_MSTR;
2806 break;
2807 case SND_SOC_DAIFMT_CBM_CFS:
2808 bclk |= MADERA_AIF1_BCLK_MSTR;
2809 break;
2810 case SND_SOC_DAIFMT_CBM_CFM:
2811 bclk |= MADERA_AIF1_BCLK_MSTR;
2812 lrclk |= MADERA_AIF1TX_LRCLK_MSTR;
2813 break;
2814 default:
2815 madera_aif_err(dai, "Unsupported master mode %d\n",
2816 fmt & SND_SOC_DAIFMT_MASTER_MASK);
2817 return -EINVAL;
2818 }
2819
2820 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
2821 case SND_SOC_DAIFMT_NB_NF:
2822 break;
2823 case SND_SOC_DAIFMT_IB_IF:
2824 bclk |= MADERA_AIF1_BCLK_INV;
2825 lrclk |= MADERA_AIF1TX_LRCLK_INV;
2826 break;
2827 case SND_SOC_DAIFMT_IB_NF:
2828 bclk |= MADERA_AIF1_BCLK_INV;
2829 break;
2830 case SND_SOC_DAIFMT_NB_IF:
2831 lrclk |= MADERA_AIF1TX_LRCLK_INV;
2832 break;
2833 default:
2834 madera_aif_err(dai, "Unsupported invert mode %d\n",
2835 fmt & SND_SOC_DAIFMT_INV_MASK);
2836 return -EINVAL;
2837 }
2838
2839 regmap_update_bits(map: madera->regmap, reg: base + MADERA_AIF_BCLK_CTRL,
2840 MADERA_AIF1_BCLK_INV | MADERA_AIF1_BCLK_MSTR,
2841 val: bclk);
2842 regmap_update_bits(map: madera->regmap, reg: base + MADERA_AIF_TX_PIN_CTRL,
2843 MADERA_AIF1TX_LRCLK_INV | MADERA_AIF1TX_LRCLK_MSTR,
2844 val: lrclk);
2845 regmap_update_bits(map: madera->regmap, reg: base + MADERA_AIF_RX_PIN_CTRL,
2846 MADERA_AIF1RX_LRCLK_INV | MADERA_AIF1RX_LRCLK_MSTR,
2847 val: lrclk);
2848 regmap_update_bits(map: madera->regmap, reg: base + MADERA_AIF_FORMAT,
2849 MADERA_AIF1_FMT_MASK, val: mode);
2850
2851 return 0;
2852}
2853
2854static const int madera_48k_bclk_rates[] = {
2855 -1,
2856 48000,
2857 64000,
2858 96000,
2859 128000,
2860 192000,
2861 256000,
2862 384000,
2863 512000,
2864 768000,
2865 1024000,
2866 1536000,
2867 2048000,
2868 3072000,
2869 4096000,
2870 6144000,
2871 8192000,
2872 12288000,
2873 24576000,
2874};
2875
2876static const int madera_44k1_bclk_rates[] = {
2877 -1,
2878 44100,
2879 58800,
2880 88200,
2881 117600,
2882 177640,
2883 235200,
2884 352800,
2885 470400,
2886 705600,
2887 940800,
2888 1411200,
2889 1881600,
2890 2822400,
2891 3763200,
2892 5644800,
2893 7526400,
2894 11289600,
2895 22579200,
2896};
2897
2898static const unsigned int madera_sr_vals[] = {
2899 0,
2900 12000,
2901 24000,
2902 48000,
2903 96000,
2904 192000,
2905 384000,
2906 768000,
2907 0,
2908 11025,
2909 22050,
2910 44100,
2911 88200,
2912 176400,
2913 352800,
2914 705600,
2915 4000,
2916 8000,
2917 16000,
2918 32000,
2919 64000,
2920 128000,
2921 256000,
2922 512000,
2923};
2924
2925#define MADERA_192K_48K_RATE_MASK 0x0F003E
2926#define MADERA_192K_44K1_RATE_MASK 0x003E00
2927#define MADERA_192K_RATE_MASK (MADERA_192K_48K_RATE_MASK | \
2928 MADERA_192K_44K1_RATE_MASK)
2929#define MADERA_384K_48K_RATE_MASK 0x0F007E
2930#define MADERA_384K_44K1_RATE_MASK 0x007E00
2931#define MADERA_384K_RATE_MASK (MADERA_384K_48K_RATE_MASK | \
2932 MADERA_384K_44K1_RATE_MASK)
2933
2934static const struct snd_pcm_hw_constraint_list madera_constraint = {
2935 .count = ARRAY_SIZE(madera_sr_vals),
2936 .list = madera_sr_vals,
2937};
2938
2939static int madera_startup(struct snd_pcm_substream *substream,
2940 struct snd_soc_dai *dai)
2941{
2942 struct snd_soc_component *component = dai->component;
2943 struct madera_priv *priv = snd_soc_component_get_drvdata(c: component);
2944 struct madera_dai_priv *dai_priv = &priv->dai[dai->id - 1];
2945 struct madera *madera = priv->madera;
2946 unsigned int base_rate;
2947
2948 if (!substream->runtime)
2949 return 0;
2950
2951 switch (dai_priv->clk) {
2952 case MADERA_CLK_SYSCLK_1:
2953 case MADERA_CLK_SYSCLK_2:
2954 case MADERA_CLK_SYSCLK_3:
2955 base_rate = priv->sysclk;
2956 break;
2957 case MADERA_CLK_ASYNCCLK_1:
2958 case MADERA_CLK_ASYNCCLK_2:
2959 base_rate = priv->asyncclk;
2960 break;
2961 default:
2962 return 0;
2963 }
2964
2965 switch (madera->type) {
2966 case CS42L92:
2967 case CS47L92:
2968 case CS47L93:
2969 if (base_rate == 0)
2970 dai_priv->constraint.mask = MADERA_384K_RATE_MASK;
2971 else if (base_rate % 4000)
2972 dai_priv->constraint.mask = MADERA_384K_44K1_RATE_MASK;
2973 else
2974 dai_priv->constraint.mask = MADERA_384K_48K_RATE_MASK;
2975 break;
2976 default:
2977 if (base_rate == 0)
2978 dai_priv->constraint.mask = MADERA_192K_RATE_MASK;
2979 else if (base_rate % 4000)
2980 dai_priv->constraint.mask = MADERA_192K_44K1_RATE_MASK;
2981 else
2982 dai_priv->constraint.mask = MADERA_192K_48K_RATE_MASK;
2983 break;
2984 }
2985
2986 return snd_pcm_hw_constraint_list(runtime: substream->runtime, cond: 0,
2987 SNDRV_PCM_HW_PARAM_RATE,
2988 l: &dai_priv->constraint);
2989}
2990
2991static int madera_hw_params_rate(struct snd_pcm_substream *substream,
2992 struct snd_pcm_hw_params *params,
2993 struct snd_soc_dai *dai)
2994{
2995 struct snd_soc_component *component = dai->component;
2996 struct madera_priv *priv = snd_soc_component_get_drvdata(c: component);
2997 struct madera_dai_priv *dai_priv = &priv->dai[dai->id - 1];
2998 int base = dai->driver->base;
2999 int i, sr_val;
3000 unsigned int reg, cur, tar;
3001 int ret;
3002
3003 for (i = 0; i < ARRAY_SIZE(madera_sr_vals); i++)
3004 if (madera_sr_vals[i] == params_rate(p: params))
3005 break;
3006
3007 if (i == ARRAY_SIZE(madera_sr_vals)) {
3008 madera_aif_err(dai, "Unsupported sample rate %dHz\n",
3009 params_rate(params));
3010 return -EINVAL;
3011 }
3012 sr_val = i;
3013
3014 switch (dai_priv->clk) {
3015 case MADERA_CLK_SYSCLK_1:
3016 reg = MADERA_SAMPLE_RATE_1;
3017 tar = 0 << MADERA_AIF1_RATE_SHIFT;
3018 break;
3019 case MADERA_CLK_SYSCLK_2:
3020 reg = MADERA_SAMPLE_RATE_2;
3021 tar = 1 << MADERA_AIF1_RATE_SHIFT;
3022 break;
3023 case MADERA_CLK_SYSCLK_3:
3024 reg = MADERA_SAMPLE_RATE_3;
3025 tar = 2 << MADERA_AIF1_RATE_SHIFT;
3026 break;
3027 case MADERA_CLK_ASYNCCLK_1:
3028 reg = MADERA_ASYNC_SAMPLE_RATE_1;
3029 tar = 8 << MADERA_AIF1_RATE_SHIFT;
3030 break;
3031 case MADERA_CLK_ASYNCCLK_2:
3032 reg = MADERA_ASYNC_SAMPLE_RATE_2;
3033 tar = 9 << MADERA_AIF1_RATE_SHIFT;
3034 break;
3035 default:
3036 madera_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
3037 return -EINVAL;
3038 }
3039
3040 snd_soc_component_update_bits(component, reg, MADERA_SAMPLE_RATE_1_MASK,
3041 val: sr_val);
3042
3043 if (!base)
3044 return 0;
3045
3046 ret = regmap_read(map: priv->madera->regmap,
3047 reg: base + MADERA_AIF_RATE_CTRL, val: &cur);
3048 if (ret != 0) {
3049 madera_aif_err(dai, "Failed to check rate: %d\n", ret);
3050 return ret;
3051 }
3052
3053 if ((cur & MADERA_AIF1_RATE_MASK) == (tar & MADERA_AIF1_RATE_MASK))
3054 return 0;
3055
3056 mutex_lock(&priv->rate_lock);
3057
3058 if (!madera_can_change_grp_rate(priv, reg: base + MADERA_AIF_RATE_CTRL)) {
3059 madera_aif_warn(dai, "Cannot change rate while active\n");
3060 ret = -EBUSY;
3061 goto out;
3062 }
3063
3064 /* Guard the rate change with SYSCLK cycles */
3065 madera_spin_sysclk(priv);
3066 snd_soc_component_update_bits(component, reg: base + MADERA_AIF_RATE_CTRL,
3067 MADERA_AIF1_RATE_MASK, val: tar);
3068 madera_spin_sysclk(priv);
3069
3070out:
3071 mutex_unlock(lock: &priv->rate_lock);
3072
3073 return ret;
3074}
3075
3076static int madera_aif_cfg_changed(struct snd_soc_component *component,
3077 int base, int bclk, int lrclk, int frame)
3078{
3079 unsigned int val;
3080
3081 val = snd_soc_component_read(component, reg: base + MADERA_AIF_BCLK_CTRL);
3082 if (bclk != (val & MADERA_AIF1_BCLK_FREQ_MASK))
3083 return 1;
3084
3085 val = snd_soc_component_read(component, reg: base + MADERA_AIF_RX_BCLK_RATE);
3086 if (lrclk != (val & MADERA_AIF1RX_BCPF_MASK))
3087 return 1;
3088
3089 val = snd_soc_component_read(component, reg: base + MADERA_AIF_FRAME_CTRL_1);
3090 if (frame != (val & (MADERA_AIF1TX_WL_MASK |
3091 MADERA_AIF1TX_SLOT_LEN_MASK)))
3092 return 1;
3093
3094 return 0;
3095}
3096
3097static int madera_hw_params(struct snd_pcm_substream *substream,
3098 struct snd_pcm_hw_params *params,
3099 struct snd_soc_dai *dai)
3100{
3101 struct snd_soc_component *component = dai->component;
3102 struct madera_priv *priv = snd_soc_component_get_drvdata(c: component);
3103 struct madera *madera = priv->madera;
3104 int base = dai->driver->base;
3105 const int *rates;
3106 int i, ret;
3107 unsigned int val;
3108 unsigned int channels = params_channels(p: params);
3109 unsigned int rate = params_rate(p: params);
3110 unsigned int chan_limit =
3111 madera->pdata.codec.max_channels_clocked[dai->id - 1];
3112 int tdm_width = priv->tdm_width[dai->id - 1];
3113 int tdm_slots = priv->tdm_slots[dai->id - 1];
3114 int bclk, lrclk, wl, frame, bclk_target, num_rates;
3115 int reconfig;
3116 unsigned int aif_tx_state = 0, aif_rx_state = 0;
3117
3118 if (rate % 4000) {
3119 rates = &madera_44k1_bclk_rates[0];
3120 num_rates = ARRAY_SIZE(madera_44k1_bclk_rates);
3121 } else {
3122 rates = &madera_48k_bclk_rates[0];
3123 num_rates = ARRAY_SIZE(madera_48k_bclk_rates);
3124 }
3125
3126 wl = snd_pcm_format_width(format: params_format(p: params));
3127
3128 if (tdm_slots) {
3129 madera_aif_dbg(dai, "Configuring for %d %d bit TDM slots\n",
3130 tdm_slots, tdm_width);
3131 bclk_target = tdm_slots * tdm_width * rate;
3132 channels = tdm_slots;
3133 } else {
3134 bclk_target = snd_soc_params_to_bclk(parms: params);
3135 tdm_width = wl;
3136 }
3137
3138 if (chan_limit && chan_limit < channels) {
3139 madera_aif_dbg(dai, "Limiting to %d channels\n", chan_limit);
3140 bclk_target /= channels;
3141 bclk_target *= chan_limit;
3142 }
3143
3144 /* Force multiple of 2 channels for I2S mode */
3145 val = snd_soc_component_read(component, reg: base + MADERA_AIF_FORMAT);
3146 val &= MADERA_AIF1_FMT_MASK;
3147 if ((channels & 1) && val == MADERA_FMT_I2S_MODE) {
3148 madera_aif_dbg(dai, "Forcing stereo mode\n");
3149 bclk_target /= channels;
3150 bclk_target *= channels + 1;
3151 }
3152
3153 for (i = 0; i < num_rates; i++) {
3154 if (rates[i] >= bclk_target && rates[i] % rate == 0) {
3155 bclk = i;
3156 break;
3157 }
3158 }
3159
3160 if (i == num_rates) {
3161 madera_aif_err(dai, "Unsupported sample rate %dHz\n", rate);
3162 return -EINVAL;
3163 }
3164
3165 lrclk = rates[bclk] / rate;
3166
3167 madera_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
3168 rates[bclk], rates[bclk] / lrclk);
3169
3170 frame = wl << MADERA_AIF1TX_WL_SHIFT | tdm_width;
3171
3172 reconfig = madera_aif_cfg_changed(component, base, bclk, lrclk, frame);
3173 if (reconfig < 0)
3174 return reconfig;
3175
3176 if (reconfig) {
3177 /* Save AIF TX/RX state */
3178 regmap_read(map: madera->regmap, reg: base + MADERA_AIF_TX_ENABLES,
3179 val: &aif_tx_state);
3180 regmap_read(map: madera->regmap, reg: base + MADERA_AIF_RX_ENABLES,
3181 val: &aif_rx_state);
3182 /* Disable AIF TX/RX before reconfiguring it */
3183 regmap_update_bits(map: madera->regmap,
3184 reg: base + MADERA_AIF_TX_ENABLES, mask: 0xff, val: 0x0);
3185 regmap_update_bits(map: madera->regmap,
3186 reg: base + MADERA_AIF_RX_ENABLES, mask: 0xff, val: 0x0);
3187 }
3188
3189 ret = madera_hw_params_rate(substream, params, dai);
3190 if (ret != 0)
3191 goto restore_aif;
3192
3193 if (reconfig) {
3194 regmap_update_bits(map: madera->regmap,
3195 reg: base + MADERA_AIF_BCLK_CTRL,
3196 MADERA_AIF1_BCLK_FREQ_MASK, val: bclk);
3197 regmap_update_bits(map: madera->regmap,
3198 reg: base + MADERA_AIF_RX_BCLK_RATE,
3199 MADERA_AIF1RX_BCPF_MASK, val: lrclk);
3200 regmap_update_bits(map: madera->regmap,
3201 reg: base + MADERA_AIF_FRAME_CTRL_1,
3202 MADERA_AIF1TX_WL_MASK |
3203 MADERA_AIF1TX_SLOT_LEN_MASK, val: frame);
3204 regmap_update_bits(map: madera->regmap,
3205 reg: base + MADERA_AIF_FRAME_CTRL_2,
3206 MADERA_AIF1RX_WL_MASK |
3207 MADERA_AIF1RX_SLOT_LEN_MASK, val: frame);
3208 }
3209
3210restore_aif:
3211 if (reconfig) {
3212 /* Restore AIF TX/RX state */
3213 regmap_update_bits(map: madera->regmap,
3214 reg: base + MADERA_AIF_TX_ENABLES,
3215 mask: 0xff, val: aif_tx_state);
3216 regmap_update_bits(map: madera->regmap,
3217 reg: base + MADERA_AIF_RX_ENABLES,
3218 mask: 0xff, val: aif_rx_state);
3219 }
3220
3221 return ret;
3222}
3223
3224static int madera_is_syncclk(int clk_id)
3225{
3226 switch (clk_id) {
3227 case MADERA_CLK_SYSCLK_1:
3228 case MADERA_CLK_SYSCLK_2:
3229 case MADERA_CLK_SYSCLK_3:
3230 return 1;
3231 case MADERA_CLK_ASYNCCLK_1:
3232 case MADERA_CLK_ASYNCCLK_2:
3233 return 0;
3234 default:
3235 return -EINVAL;
3236 }
3237}
3238
3239static int madera_dai_set_sysclk(struct snd_soc_dai *dai,
3240 int clk_id, unsigned int freq, int dir)
3241{
3242 struct snd_soc_component *component = dai->component;
3243 struct snd_soc_dapm_context *dapm =
3244 snd_soc_component_get_dapm(component);
3245 struct madera_priv *priv = snd_soc_component_get_drvdata(c: component);
3246 struct madera_dai_priv *dai_priv = &priv->dai[dai->id - 1];
3247 struct snd_soc_dapm_route routes[2];
3248 int is_sync;
3249
3250 is_sync = madera_is_syncclk(clk_id);
3251 if (is_sync < 0) {
3252 dev_err(component->dev, "Illegal DAI clock id %d\n", clk_id);
3253 return is_sync;
3254 }
3255
3256 if (is_sync == madera_is_syncclk(clk_id: dai_priv->clk))
3257 return 0;
3258
3259 if (snd_soc_dai_active(dai)) {
3260 dev_err(component->dev, "Can't change clock on active DAI %d\n",
3261 dai->id);
3262 return -EBUSY;
3263 }
3264
3265 dev_dbg(component->dev, "Setting AIF%d to %s\n", dai->id,
3266 is_sync ? "SYSCLK" : "ASYNCCLK");
3267
3268 /*
3269 * A connection to SYSCLK is always required, we only add and remove
3270 * a connection to ASYNCCLK
3271 */
3272 memset(&routes, 0, sizeof(routes));
3273 routes[0].sink = dai->driver->capture.stream_name;
3274 routes[1].sink = dai->driver->playback.stream_name;
3275 routes[0].source = "ASYNCCLK";
3276 routes[1].source = "ASYNCCLK";
3277
3278 if (is_sync)
3279 snd_soc_dapm_del_routes(dapm, route: routes, ARRAY_SIZE(routes));
3280 else
3281 snd_soc_dapm_add_routes(dapm, route: routes, ARRAY_SIZE(routes));
3282
3283 dai_priv->clk = clk_id;
3284
3285 return snd_soc_dapm_sync(dapm);
3286}
3287
3288static int madera_set_tristate(struct snd_soc_dai *dai, int tristate)
3289{
3290 struct snd_soc_component *component = dai->component;
3291 int base = dai->driver->base;
3292 unsigned int reg;
3293 int ret;
3294
3295 if (tristate)
3296 reg = MADERA_AIF1_TRI;
3297 else
3298 reg = 0;
3299
3300 ret = snd_soc_component_update_bits(component,
3301 reg: base + MADERA_AIF_RATE_CTRL,
3302 MADERA_AIF1_TRI, val: reg);
3303 if (ret < 0)
3304 return ret;
3305 else
3306 return 0;
3307}
3308
3309static void madera_set_channels_to_mask(struct snd_soc_dai *dai,
3310 unsigned int base,
3311 int channels, unsigned int mask)
3312{
3313 struct snd_soc_component *component = dai->component;
3314 struct madera_priv *priv = snd_soc_component_get_drvdata(c: component);
3315 struct madera *madera = priv->madera;
3316 int slot, i;
3317
3318 for (i = 0; i < channels; ++i) {
3319 slot = ffs(mask) - 1;
3320 if (slot < 0)
3321 return;
3322
3323 regmap_write(map: madera->regmap, reg: base + i, val: slot);
3324
3325 mask &= ~(1 << slot);
3326 }
3327
3328 if (mask)
3329 madera_aif_warn(dai, "Too many channels in TDM mask\n");
3330}
3331
3332static int madera_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
3333 unsigned int rx_mask, int slots, int slot_width)
3334{
3335 struct snd_soc_component *component = dai->component;
3336 struct madera_priv *priv = snd_soc_component_get_drvdata(c: component);
3337 int base = dai->driver->base;
3338 int rx_max_chan = dai->driver->playback.channels_max;
3339 int tx_max_chan = dai->driver->capture.channels_max;
3340
3341 /* Only support TDM for the physical AIFs */
3342 if (dai->id > MADERA_MAX_AIF)
3343 return -ENOTSUPP;
3344
3345 if (slots == 0) {
3346 tx_mask = (1 << tx_max_chan) - 1;
3347 rx_mask = (1 << rx_max_chan) - 1;
3348 }
3349
3350 madera_set_channels_to_mask(dai, base: base + MADERA_AIF_FRAME_CTRL_3,
3351 channels: tx_max_chan, mask: tx_mask);
3352 madera_set_channels_to_mask(dai, base: base + MADERA_AIF_FRAME_CTRL_11,
3353 channels: rx_max_chan, mask: rx_mask);
3354
3355 priv->tdm_width[dai->id - 1] = slot_width;
3356 priv->tdm_slots[dai->id - 1] = slots;
3357
3358 return 0;
3359}
3360
3361const struct snd_soc_dai_ops madera_dai_ops = {
3362 .startup = &madera_startup,
3363 .set_fmt = &madera_set_fmt,
3364 .set_tdm_slot = &madera_set_tdm_slot,
3365 .hw_params = &madera_hw_params,
3366 .set_sysclk = &madera_dai_set_sysclk,
3367 .set_tristate = &madera_set_tristate,
3368};
3369EXPORT_SYMBOL_GPL(madera_dai_ops);
3370
3371const struct snd_soc_dai_ops madera_simple_dai_ops = {
3372 .startup = &madera_startup,
3373 .hw_params = &madera_hw_params_rate,
3374 .set_sysclk = &madera_dai_set_sysclk,
3375};
3376EXPORT_SYMBOL_GPL(madera_simple_dai_ops);
3377
3378int madera_init_dai(struct madera_priv *priv, int id)
3379{
3380 struct madera_dai_priv *dai_priv = &priv->dai[id];
3381
3382 dai_priv->clk = MADERA_CLK_SYSCLK_1;
3383 dai_priv->constraint = madera_constraint;
3384
3385 return 0;
3386}
3387EXPORT_SYMBOL_GPL(madera_init_dai);
3388
3389static const struct {
3390 unsigned int min;
3391 unsigned int max;
3392 u16 fratio;
3393 int ratio;
3394} fll_sync_fratios[] = {
3395 { 0, 64000, 4, 16 },
3396 { 64000, 128000, 3, 8 },
3397 { 128000, 256000, 2, 4 },
3398 { 256000, 1000000, 1, 2 },
3399 { 1000000, 13500000, 0, 1 },
3400};
3401
3402static const unsigned int pseudo_fref_max[MADERA_FLL_MAX_FRATIO] = {
3403 13500000,
3404 6144000,
3405 6144000,
3406 3072000,
3407 3072000,
3408 2822400,
3409 2822400,
3410 1536000,
3411 1536000,
3412 1536000,
3413 1536000,
3414 1536000,
3415 1536000,
3416 1536000,
3417 1536000,
3418 768000,
3419};
3420
3421struct madera_fll_gains {
3422 unsigned int min;
3423 unsigned int max;
3424 int gain; /* main gain */
3425 int alt_gain; /* alternate integer gain */
3426};
3427
3428static const struct madera_fll_gains madera_fll_sync_gains[] = {
3429 { 0, 256000, 0, -1 },
3430 { 256000, 1000000, 2, -1 },
3431 { 1000000, 13500000, 4, -1 },
3432};
3433
3434static const struct madera_fll_gains madera_fll_main_gains[] = {
3435 { 0, 100000, 0, 2 },
3436 { 100000, 375000, 2, 2 },
3437 { 375000, 768000, 3, 2 },
3438 { 768001, 1500000, 3, 3 },
3439 { 1500000, 6000000, 4, 3 },
3440 { 6000000, 13500000, 5, 3 },
3441};
3442
3443static int madera_find_sync_fratio(unsigned int fref, int *fratio)
3444{
3445 int i;
3446
3447 for (i = 0; i < ARRAY_SIZE(fll_sync_fratios); i++) {
3448 if (fll_sync_fratios[i].min <= fref &&
3449 fref <= fll_sync_fratios[i].max) {
3450 if (fratio)
3451 *fratio = fll_sync_fratios[i].fratio;
3452
3453 return fll_sync_fratios[i].ratio;
3454 }
3455 }
3456
3457 return -EINVAL;
3458}
3459
3460static int madera_find_main_fratio(unsigned int fref, unsigned int fout,
3461 int *fratio)
3462{
3463 int ratio = 1;
3464
3465 while ((fout / (ratio * fref)) > MADERA_FLL_MAX_N)
3466 ratio++;
3467
3468 if (fratio)
3469 *fratio = ratio - 1;
3470
3471 return ratio;
3472}
3473
3474static int madera_find_fratio(struct madera_fll *fll, unsigned int fref,
3475 bool sync, int *fratio)
3476{
3477 switch (fll->madera->type) {
3478 case CS47L35:
3479 switch (fll->madera->rev) {
3480 case 0:
3481 /* rev A0 uses sync calculation for both loops */
3482 return madera_find_sync_fratio(fref, fratio);
3483 default:
3484 if (sync)
3485 return madera_find_sync_fratio(fref, fratio);
3486 else
3487 return madera_find_main_fratio(fref,
3488 fout: fll->fout,
3489 fratio);
3490 }
3491 break;
3492 case CS47L85:
3493 case WM1840:
3494 /* these use the same calculation for main and sync loops */
3495 return madera_find_sync_fratio(fref, fratio);
3496 default:
3497 if (sync)
3498 return madera_find_sync_fratio(fref, fratio);
3499 else
3500 return madera_find_main_fratio(fref, fout: fll->fout, fratio);
3501 }
3502}
3503
3504static int madera_calc_fratio(struct madera_fll *fll,
3505 struct madera_fll_cfg *cfg,
3506 unsigned int fref, bool sync)
3507{
3508 int init_ratio, ratio;
3509 int refdiv, div;
3510
3511 /* fref must be <=13.5MHz, find initial refdiv */
3512 div = 1;
3513 cfg->refdiv = 0;
3514 while (fref > MADERA_FLL_MAX_FREF) {
3515 div *= 2;
3516 fref /= 2;
3517 cfg->refdiv++;
3518
3519 if (div > MADERA_FLL_MAX_REFDIV)
3520 return -EINVAL;
3521 }
3522
3523 /* Find an appropriate FLL_FRATIO */
3524 init_ratio = madera_find_fratio(fll, fref, sync, fratio: &cfg->fratio);
3525 if (init_ratio < 0) {
3526 madera_fll_err(fll, "Unable to find FRATIO for fref=%uHz\n",
3527 fref);
3528 return init_ratio;
3529 }
3530
3531 if (!sync)
3532 cfg->fratio = init_ratio - 1;
3533
3534 switch (fll->madera->type) {
3535 case CS47L35:
3536 switch (fll->madera->rev) {
3537 case 0:
3538 if (sync)
3539 return init_ratio;
3540 break;
3541 default:
3542 return init_ratio;
3543 }
3544 break;
3545 case CS47L85:
3546 case WM1840:
3547 if (sync)
3548 return init_ratio;
3549 break;
3550 default:
3551 return init_ratio;
3552 }
3553
3554 /*
3555 * For CS47L35 rev A0, CS47L85 and WM1840 adjust FRATIO/refdiv to avoid
3556 * integer mode if possible
3557 */
3558 refdiv = cfg->refdiv;
3559
3560 while (div <= MADERA_FLL_MAX_REFDIV) {
3561 /*
3562 * start from init_ratio because this may already give a
3563 * fractional N.K
3564 */
3565 for (ratio = init_ratio; ratio > 0; ratio--) {
3566 if (fll->fout % (ratio * fref)) {
3567 cfg->refdiv = refdiv;
3568 cfg->fratio = ratio - 1;
3569 return ratio;
3570 }
3571 }
3572
3573 for (ratio = init_ratio + 1; ratio <= MADERA_FLL_MAX_FRATIO;
3574 ratio++) {
3575 if ((MADERA_FLL_VCO_CORNER / 2) /
3576 (MADERA_FLL_VCO_MULT * ratio) < fref)
3577 break;
3578
3579 if (fref > pseudo_fref_max[ratio - 1])
3580 break;
3581
3582 if (fll->fout % (ratio * fref)) {
3583 cfg->refdiv = refdiv;
3584 cfg->fratio = ratio - 1;
3585 return ratio;
3586 }
3587 }
3588
3589 div *= 2;
3590 fref /= 2;
3591 refdiv++;
3592 init_ratio = madera_find_fratio(fll, fref, sync, NULL);
3593 }
3594
3595 madera_fll_warn(fll, "Falling back to integer mode operation\n");
3596
3597 return cfg->fratio + 1;
3598}
3599
3600static int madera_find_fll_gain(struct madera_fll *fll,
3601 struct madera_fll_cfg *cfg,
3602 unsigned int fref,
3603 const struct madera_fll_gains *gains,
3604 int n_gains)
3605{
3606 int i;
3607
3608 for (i = 0; i < n_gains; i++) {
3609 if (gains[i].min <= fref && fref <= gains[i].max) {
3610 cfg->gain = gains[i].gain;
3611 cfg->alt_gain = gains[i].alt_gain;
3612 return 0;
3613 }
3614 }
3615
3616 madera_fll_err(fll, "Unable to find gain for fref=%uHz\n", fref);
3617
3618 return -EINVAL;
3619}
3620
3621static int madera_calc_fll(struct madera_fll *fll,
3622 struct madera_fll_cfg *cfg,
3623 unsigned int fref, bool sync)
3624{
3625 unsigned int gcd_fll;
3626 const struct madera_fll_gains *gains;
3627 int n_gains;
3628 int ratio, ret;
3629
3630 madera_fll_dbg(fll, "fref=%u Fout=%u fvco=%u\n",
3631 fref, fll->fout, fll->fout * MADERA_FLL_VCO_MULT);
3632
3633 /* Find an appropriate FLL_FRATIO and refdiv */
3634 ratio = madera_calc_fratio(fll, cfg, fref, sync);
3635 if (ratio < 0)
3636 return ratio;
3637
3638 /* Apply the division for our remaining calculations */
3639 fref = fref / (1 << cfg->refdiv);
3640
3641 cfg->n = fll->fout / (ratio * fref);
3642
3643 if (fll->fout % (ratio * fref)) {
3644 gcd_fll = gcd(a: fll->fout, b: ratio * fref);
3645 madera_fll_dbg(fll, "GCD=%u\n", gcd_fll);
3646
3647 cfg->theta = (fll->fout - (cfg->n * ratio * fref))
3648 / gcd_fll;
3649 cfg->lambda = (ratio * fref) / gcd_fll;
3650 } else {
3651 cfg->theta = 0;
3652 cfg->lambda = 0;
3653 }
3654
3655 /*
3656 * Round down to 16bit range with cost of accuracy lost.
3657 * Denominator must be bigger than numerator so we only
3658 * take care of it.
3659 */
3660 while (cfg->lambda >= (1 << 16)) {
3661 cfg->theta >>= 1;
3662 cfg->lambda >>= 1;
3663 }
3664
3665 switch (fll->madera->type) {
3666 case CS47L35:
3667 switch (fll->madera->rev) {
3668 case 0:
3669 /* Rev A0 uses the sync gains for both loops */
3670 gains = madera_fll_sync_gains;
3671 n_gains = ARRAY_SIZE(madera_fll_sync_gains);
3672 break;
3673 default:
3674 if (sync) {
3675 gains = madera_fll_sync_gains;
3676 n_gains = ARRAY_SIZE(madera_fll_sync_gains);
3677 } else {
3678 gains = madera_fll_main_gains;
3679 n_gains = ARRAY_SIZE(madera_fll_main_gains);
3680 }
3681 break;
3682 }
3683 break;
3684 case CS47L85:
3685 case WM1840:
3686 /* These use the sync gains for both loops */
3687 gains = madera_fll_sync_gains;
3688 n_gains = ARRAY_SIZE(madera_fll_sync_gains);
3689 break;
3690 default:
3691 if (sync) {
3692 gains = madera_fll_sync_gains;
3693 n_gains = ARRAY_SIZE(madera_fll_sync_gains);
3694 } else {
3695 gains = madera_fll_main_gains;
3696 n_gains = ARRAY_SIZE(madera_fll_main_gains);
3697 }
3698 break;
3699 }
3700
3701 ret = madera_find_fll_gain(fll, cfg, fref, gains, n_gains);
3702 if (ret)
3703 return ret;
3704
3705 madera_fll_dbg(fll, "N=%d THETA=%d LAMBDA=%d\n",
3706 cfg->n, cfg->theta, cfg->lambda);
3707 madera_fll_dbg(fll, "FRATIO=0x%x(%d) REFCLK_DIV=0x%x(%d)\n",
3708 cfg->fratio, ratio, cfg->refdiv, 1 << cfg->refdiv);
3709 madera_fll_dbg(fll, "GAIN=0x%x(%d)\n", cfg->gain, 1 << cfg->gain);
3710
3711 return 0;
3712}
3713
3714static bool madera_write_fll(struct madera *madera, unsigned int base,
3715 struct madera_fll_cfg *cfg, int source,
3716 bool sync, int gain)
3717{
3718 bool change, fll_change;
3719
3720 fll_change = false;
3721 regmap_update_bits_check(map: madera->regmap,
3722 reg: base + MADERA_FLL_CONTROL_3_OFFS,
3723 MADERA_FLL1_THETA_MASK,
3724 val: cfg->theta, change: &change);
3725 fll_change |= change;
3726 regmap_update_bits_check(map: madera->regmap,
3727 reg: base + MADERA_FLL_CONTROL_4_OFFS,
3728 MADERA_FLL1_LAMBDA_MASK,
3729 val: cfg->lambda, change: &change);
3730 fll_change |= change;
3731 regmap_update_bits_check(map: madera->regmap,
3732 reg: base + MADERA_FLL_CONTROL_5_OFFS,
3733 MADERA_FLL1_FRATIO_MASK,
3734 val: cfg->fratio << MADERA_FLL1_FRATIO_SHIFT,
3735 change: &change);
3736 fll_change |= change;
3737 regmap_update_bits_check(map: madera->regmap,
3738 reg: base + MADERA_FLL_CONTROL_6_OFFS,
3739 MADERA_FLL1_REFCLK_DIV_MASK |
3740 MADERA_FLL1_REFCLK_SRC_MASK,
3741 val: cfg->refdiv << MADERA_FLL1_REFCLK_DIV_SHIFT |
3742 source << MADERA_FLL1_REFCLK_SRC_SHIFT,
3743 change: &change);
3744 fll_change |= change;
3745
3746 if (sync) {
3747 regmap_update_bits_check(map: madera->regmap,
3748 reg: base + MADERA_FLL_SYNCHRONISER_7_OFFS,
3749 MADERA_FLL1_GAIN_MASK,
3750 val: gain << MADERA_FLL1_GAIN_SHIFT,
3751 change: &change);
3752 fll_change |= change;
3753 } else {
3754 regmap_update_bits_check(map: madera->regmap,
3755 reg: base + MADERA_FLL_CONTROL_7_OFFS,
3756 MADERA_FLL1_GAIN_MASK,
3757 val: gain << MADERA_FLL1_GAIN_SHIFT,
3758 change: &change);
3759 fll_change |= change;
3760 }
3761
3762 regmap_update_bits_check(map: madera->regmap,
3763 reg: base + MADERA_FLL_CONTROL_2_OFFS,
3764 MADERA_FLL1_CTRL_UPD | MADERA_FLL1_N_MASK,
3765 MADERA_FLL1_CTRL_UPD | cfg->n, change: &change);
3766 fll_change |= change;
3767
3768 return fll_change;
3769}
3770
3771static int madera_is_enabled_fll(struct madera_fll *fll, int base)
3772{
3773 struct madera *madera = fll->madera;
3774 unsigned int reg;
3775 int ret;
3776
3777 ret = regmap_read(map: madera->regmap,
3778 reg: base + MADERA_FLL_CONTROL_1_OFFS, val: &reg);
3779 if (ret != 0) {
3780 madera_fll_err(fll, "Failed to read current state: %d\n", ret);
3781 return ret;
3782 }
3783
3784 return reg & MADERA_FLL1_ENA;
3785}
3786
3787static int madera_wait_for_fll(struct madera_fll *fll, bool requested)
3788{
3789 struct madera *madera = fll->madera;
3790 unsigned int val = 0;
3791 bool status;
3792 int i;
3793
3794 madera_fll_dbg(fll, "Waiting for FLL...\n");
3795
3796 for (i = 0; i < 30; i++) {
3797 regmap_read(map: madera->regmap, MADERA_IRQ1_RAW_STATUS_2, val: &val);
3798 status = val & (MADERA_FLL1_LOCK_STS1 << (fll->id - 1));
3799 if (status == requested)
3800 return 0;
3801
3802 switch (i) {
3803 case 0 ... 5:
3804 usleep_range(min: 75, max: 125);
3805 break;
3806 case 11 ... 20:
3807 usleep_range(min: 750, max: 1250);
3808 break;
3809 default:
3810 msleep(msecs: 20);
3811 break;
3812 }
3813 }
3814
3815 madera_fll_warn(fll, "Timed out waiting for lock\n");
3816
3817 return -ETIMEDOUT;
3818}
3819
3820static bool madera_set_fll_phase_integrator(struct madera_fll *fll,
3821 struct madera_fll_cfg *ref_cfg,
3822 bool sync)
3823{
3824 unsigned int val;
3825 bool reg_change;
3826
3827 if (!sync && ref_cfg->theta == 0)
3828 val = (1 << MADERA_FLL1_PHASE_ENA_SHIFT) |
3829 (2 << MADERA_FLL1_PHASE_GAIN_SHIFT);
3830 else
3831 val = 2 << MADERA_FLL1_PHASE_GAIN_SHIFT;
3832
3833 regmap_update_bits_check(map: fll->madera->regmap,
3834 reg: fll->base + MADERA_FLL_EFS_2_OFFS,
3835 MADERA_FLL1_PHASE_ENA_MASK |
3836 MADERA_FLL1_PHASE_GAIN_MASK,
3837 val, change: &reg_change);
3838
3839 return reg_change;
3840}
3841
3842static int madera_set_fll_clks_reg(struct madera_fll *fll, bool ena,
3843 unsigned int reg, unsigned int mask,
3844 unsigned int shift)
3845{
3846 struct madera *madera = fll->madera;
3847 unsigned int src;
3848 struct clk *clk;
3849 int ret;
3850
3851 ret = regmap_read(map: madera->regmap, reg, val: &src);
3852 if (ret != 0) {
3853 madera_fll_err(fll, "Failed to read current source: %d\n",
3854 ret);
3855 return ret;
3856 }
3857
3858 src = (src & mask) >> shift;
3859
3860 switch (src) {
3861 case MADERA_FLL_SRC_MCLK1:
3862 clk = madera->mclk[MADERA_MCLK1].clk;
3863 break;
3864 case MADERA_FLL_SRC_MCLK2:
3865 clk = madera->mclk[MADERA_MCLK2].clk;
3866 break;
3867 case MADERA_FLL_SRC_MCLK3:
3868 clk = madera->mclk[MADERA_MCLK3].clk;
3869 break;
3870 default:
3871 return 0;
3872 }
3873
3874 if (ena) {
3875 return clk_prepare_enable(clk);
3876 } else {
3877 clk_disable_unprepare(clk);
3878 return 0;
3879 }
3880}
3881
3882static inline int madera_set_fll_clks(struct madera_fll *fll, int base, bool ena)
3883{
3884 return madera_set_fll_clks_reg(fll, ena,
3885 reg: base + MADERA_FLL_CONTROL_6_OFFS,
3886 MADERA_FLL1_REFCLK_SRC_MASK,
3887 MADERA_FLL1_REFCLK_SRC_SHIFT);
3888}
3889
3890static inline int madera_set_fllao_clks(struct madera_fll *fll, int base, bool ena)
3891{
3892 return madera_set_fll_clks_reg(fll, ena,
3893 reg: base + MADERA_FLLAO_CONTROL_6_OFFS,
3894 MADERA_FLL_AO_REFCLK_SRC_MASK,
3895 MADERA_FLL_AO_REFCLK_SRC_SHIFT);
3896}
3897
3898static inline int madera_set_fllhj_clks(struct madera_fll *fll, int base, bool ena)
3899{
3900 return madera_set_fll_clks_reg(fll, ena,
3901 reg: base + MADERA_FLL_CONTROL_1_OFFS,
3902 CS47L92_FLL1_REFCLK_SRC_MASK,
3903 CS47L92_FLL1_REFCLK_SRC_SHIFT);
3904}
3905
3906static void madera_disable_fll(struct madera_fll *fll)
3907{
3908 struct madera *madera = fll->madera;
3909 unsigned int sync_base;
3910 bool ref_change, sync_change;
3911
3912 switch (madera->type) {
3913 case CS47L35:
3914 sync_base = fll->base + CS47L35_FLL_SYNCHRONISER_OFFS;
3915 break;
3916 default:
3917 sync_base = fll->base + MADERA_FLL_SYNCHRONISER_OFFS;
3918 break;
3919 }
3920
3921 madera_fll_dbg(fll, "Disabling FLL\n");
3922
3923 regmap_update_bits(map: madera->regmap,
3924 reg: fll->base + MADERA_FLL_CONTROL_1_OFFS,
3925 MADERA_FLL1_FREERUN, MADERA_FLL1_FREERUN);
3926 regmap_update_bits_check(map: madera->regmap,
3927 reg: fll->base + MADERA_FLL_CONTROL_1_OFFS,
3928 MADERA_FLL1_ENA, val: 0, change: &ref_change);
3929 regmap_update_bits_check(map: madera->regmap,
3930 reg: sync_base + MADERA_FLL_SYNCHRONISER_1_OFFS,
3931 MADERA_FLL1_SYNC_ENA, val: 0, change: &sync_change);
3932 regmap_update_bits(map: madera->regmap,
3933 reg: fll->base + MADERA_FLL_CONTROL_1_OFFS,
3934 MADERA_FLL1_FREERUN, val: 0);
3935
3936 madera_wait_for_fll(fll, requested: false);
3937
3938 if (sync_change)
3939 madera_set_fll_clks(fll, base: sync_base, ena: false);
3940
3941 if (ref_change) {
3942 madera_set_fll_clks(fll, base: fll->base, ena: false);
3943 pm_runtime_put_autosuspend(dev: madera->dev);
3944 }
3945}
3946
3947static int madera_enable_fll(struct madera_fll *fll)
3948{
3949 struct madera *madera = fll->madera;
3950 bool have_sync = false;
3951 int already_enabled = madera_is_enabled_fll(fll, base: fll->base);
3952 int sync_enabled;
3953 struct madera_fll_cfg cfg;
3954 unsigned int sync_base;
3955 int gain, ret;
3956 bool fll_change = false;
3957
3958 if (already_enabled < 0)
3959 return already_enabled; /* error getting current state */
3960
3961 if (fll->ref_src < 0 || fll->ref_freq == 0) {
3962 madera_fll_err(fll, "No REFCLK\n");
3963 ret = -EINVAL;
3964 goto err;
3965 }
3966
3967 madera_fll_dbg(fll, "Enabling FLL, initially %s\n",
3968 already_enabled ? "enabled" : "disabled");
3969
3970 if (fll->fout < MADERA_FLL_MIN_FOUT ||
3971 fll->fout > MADERA_FLL_MAX_FOUT) {
3972 madera_fll_err(fll, "invalid fout %uHz\n", fll->fout);
3973 ret = -EINVAL;
3974 goto err;
3975 }
3976
3977 switch (madera->type) {
3978 case CS47L35:
3979 sync_base = fll->base + CS47L35_FLL_SYNCHRONISER_OFFS;
3980 break;
3981 default:
3982 sync_base = fll->base + MADERA_FLL_SYNCHRONISER_OFFS;
3983 break;
3984 }
3985
3986 sync_enabled = madera_is_enabled_fll(fll, base: sync_base);
3987 if (sync_enabled < 0)
3988 return sync_enabled;
3989
3990 if (already_enabled) {
3991 /* Facilitate smooth refclk across the transition */
3992 regmap_update_bits(map: fll->madera->regmap,
3993 reg: fll->base + MADERA_FLL_CONTROL_1_OFFS,
3994 MADERA_FLL1_FREERUN,
3995 MADERA_FLL1_FREERUN);
3996 udelay(32);
3997 regmap_update_bits(map: fll->madera->regmap,
3998 reg: fll->base + MADERA_FLL_CONTROL_7_OFFS,
3999 MADERA_FLL1_GAIN_MASK, val: 0);
4000
4001 if (sync_enabled > 0)
4002 madera_set_fll_clks(fll, base: sync_base, ena: false);
4003 madera_set_fll_clks(fll, base: fll->base, ena: false);
4004 }
4005
4006 /* Apply SYNCCLK setting */
4007 if (fll->sync_src >= 0) {
4008 ret = madera_calc_fll(fll, cfg: &cfg, fref: fll->sync_freq, sync: true);
4009 if (ret < 0)
4010 goto err;
4011
4012 fll_change |= madera_write_fll(madera, base: sync_base,
4013 cfg: &cfg, source: fll->sync_src,
4014 sync: true, gain: cfg.gain);
4015 have_sync = true;
4016 }
4017
4018 if (already_enabled && !!sync_enabled != have_sync)
4019 madera_fll_warn(fll, "Synchroniser changed on active FLL\n");
4020
4021 /* Apply REFCLK setting */
4022 ret = madera_calc_fll(fll, cfg: &cfg, fref: fll->ref_freq, sync: false);
4023 if (ret < 0)
4024 goto err;
4025
4026 /* Ref path hardcodes lambda to 65536 when sync is on */
4027 if (have_sync && cfg.lambda)
4028 cfg.theta = (cfg.theta * (1 << 16)) / cfg.lambda;
4029
4030 switch (fll->madera->type) {
4031 case CS47L35:
4032 switch (fll->madera->rev) {
4033 case 0:
4034 gain = cfg.gain;
4035 break;
4036 default:
4037 fll_change |=
4038 madera_set_fll_phase_integrator(fll, ref_cfg: &cfg,
4039 sync: have_sync);
4040 if (!have_sync && cfg.theta == 0)
4041 gain = cfg.alt_gain;
4042 else
4043 gain = cfg.gain;
4044 break;
4045 }
4046 break;
4047 case CS47L85:
4048 case WM1840:
4049 gain = cfg.gain;
4050 break;
4051 default:
4052 fll_change |= madera_set_fll_phase_integrator(fll, ref_cfg: &cfg,
4053 sync: have_sync);
4054 if (!have_sync && cfg.theta == 0)
4055 gain = cfg.alt_gain;
4056 else
4057 gain = cfg.gain;
4058 break;
4059 }
4060
4061 fll_change |= madera_write_fll(madera, base: fll->base,
4062 cfg: &cfg, source: fll->ref_src,
4063 sync: false, gain);
4064
4065 /*
4066 * Increase the bandwidth if we're not using a low frequency
4067 * sync source.
4068 */
4069 if (have_sync && fll->sync_freq > 100000)
4070 regmap_update_bits(map: madera->regmap,
4071 reg: sync_base + MADERA_FLL_SYNCHRONISER_7_OFFS,
4072 MADERA_FLL1_SYNC_DFSAT_MASK, val: 0);
4073 else
4074 regmap_update_bits(map: madera->regmap,
4075 reg: sync_base + MADERA_FLL_SYNCHRONISER_7_OFFS,
4076 MADERA_FLL1_SYNC_DFSAT_MASK,
4077 MADERA_FLL1_SYNC_DFSAT);
4078
4079 if (!already_enabled)
4080 pm_runtime_get_sync(dev: madera->dev);
4081
4082 if (have_sync) {
4083 madera_set_fll_clks(fll, base: sync_base, ena: true);
4084 regmap_update_bits(map: madera->regmap,
4085 reg: sync_base + MADERA_FLL_SYNCHRONISER_1_OFFS,
4086 MADERA_FLL1_SYNC_ENA,
4087 MADERA_FLL1_SYNC_ENA);
4088 }
4089
4090 madera_set_fll_clks(fll, base: fll->base, ena: true);
4091 regmap_update_bits(map: madera->regmap,
4092 reg: fll->base + MADERA_FLL_CONTROL_1_OFFS,
4093 MADERA_FLL1_ENA, MADERA_FLL1_ENA);
4094
4095 if (already_enabled)
4096 regmap_update_bits(map: madera->regmap,
4097 reg: fll->base + MADERA_FLL_CONTROL_1_OFFS,
4098 MADERA_FLL1_FREERUN, val: 0);
4099
4100 if (fll_change || !already_enabled)
4101 madera_wait_for_fll(fll, requested: true);
4102
4103 return 0;
4104
4105err:
4106 /* In case of error don't leave the FLL running with an old config */
4107 madera_disable_fll(fll);
4108
4109 return ret;
4110}
4111
4112static int madera_apply_fll(struct madera_fll *fll)
4113{
4114 if (fll->fout) {
4115 return madera_enable_fll(fll);
4116 } else {
4117 madera_disable_fll(fll);
4118 return 0;
4119 }
4120}
4121
4122int madera_set_fll_syncclk(struct madera_fll *fll, int source,
4123 unsigned int fref, unsigned int fout)
4124{
4125 /*
4126 * fout is ignored, since the synchronizer is an optional extra
4127 * constraint on the Fout generated from REFCLK, so the Fout is
4128 * set when configuring REFCLK
4129 */
4130
4131 if (fll->sync_src == source && fll->sync_freq == fref)
4132 return 0;
4133
4134 fll->sync_src = source;
4135 fll->sync_freq = fref;
4136
4137 return madera_apply_fll(fll);
4138}
4139EXPORT_SYMBOL_GPL(madera_set_fll_syncclk);
4140
4141int madera_set_fll_refclk(struct madera_fll *fll, int source,
4142 unsigned int fref, unsigned int fout)
4143{
4144 int ret;
4145
4146 if (fll->ref_src == source &&
4147 fll->ref_freq == fref && fll->fout == fout)
4148 return 0;
4149
4150 /*
4151 * Changes of fout on an enabled FLL aren't allowed except when
4152 * setting fout==0 to disable the FLL
4153 */
4154 if (fout && fout != fll->fout) {
4155 ret = madera_is_enabled_fll(fll, base: fll->base);
4156 if (ret < 0)
4157 return ret;
4158
4159 if (ret) {
4160 madera_fll_err(fll, "Can't change Fout on active FLL\n");
4161 return -EBUSY;
4162 }
4163 }
4164
4165 fll->ref_src = source;
4166 fll->ref_freq = fref;
4167 fll->fout = fout;
4168
4169 return madera_apply_fll(fll);
4170}
4171EXPORT_SYMBOL_GPL(madera_set_fll_refclk);
4172
4173int madera_init_fll(struct madera *madera, int id, int base,
4174 struct madera_fll *fll)
4175{
4176 fll->id = id;
4177 fll->base = base;
4178 fll->madera = madera;
4179 fll->ref_src = MADERA_FLL_SRC_NONE;
4180 fll->sync_src = MADERA_FLL_SRC_NONE;
4181
4182 regmap_update_bits(map: madera->regmap,
4183 reg: fll->base + MADERA_FLL_CONTROL_1_OFFS,
4184 MADERA_FLL1_FREERUN, val: 0);
4185
4186 return 0;
4187}
4188EXPORT_SYMBOL_GPL(madera_init_fll);
4189
4190static const struct reg_sequence madera_fll_ao_32K_49M_patch[] = {
4191 { MADERA_FLLAO_CONTROL_2, 0x02EE },
4192 { MADERA_FLLAO_CONTROL_3, 0x0000 },
4193 { MADERA_FLLAO_CONTROL_4, 0x0001 },
4194 { MADERA_FLLAO_CONTROL_5, 0x0002 },
4195 { MADERA_FLLAO_CONTROL_6, 0x8001 },
4196 { MADERA_FLLAO_CONTROL_7, 0x0004 },
4197 { MADERA_FLLAO_CONTROL_8, 0x0077 },
4198 { MADERA_FLLAO_CONTROL_10, 0x06D8 },
4199 { MADERA_FLLAO_CONTROL_11, 0x0085 },
4200 { MADERA_FLLAO_CONTROL_2, 0x82EE },
4201};
4202
4203static const struct reg_sequence madera_fll_ao_32K_45M_patch[] = {
4204 { MADERA_FLLAO_CONTROL_2, 0x02B1 },
4205 { MADERA_FLLAO_CONTROL_3, 0x0001 },
4206 { MADERA_FLLAO_CONTROL_4, 0x0010 },
4207 { MADERA_FLLAO_CONTROL_5, 0x0002 },
4208 { MADERA_FLLAO_CONTROL_6, 0x8001 },
4209 { MADERA_FLLAO_CONTROL_7, 0x0004 },
4210 { MADERA_FLLAO_CONTROL_8, 0x0077 },
4211 { MADERA_FLLAO_CONTROL_10, 0x06D8 },
4212 { MADERA_FLLAO_CONTROL_11, 0x0005 },
4213 { MADERA_FLLAO_CONTROL_2, 0x82B1 },
4214};
4215
4216struct madera_fllao_patch {
4217 unsigned int fin;
4218 unsigned int fout;
4219 const struct reg_sequence *patch;
4220 unsigned int patch_size;
4221};
4222
4223static const struct madera_fllao_patch madera_fllao_settings[] = {
4224 {
4225 .fin = 32768,
4226 .fout = 49152000,
4227 .patch = madera_fll_ao_32K_49M_patch,
4228 .patch_size = ARRAY_SIZE(madera_fll_ao_32K_49M_patch),
4229
4230 },
4231 {
4232 .fin = 32768,
4233 .fout = 45158400,
4234 .patch = madera_fll_ao_32K_45M_patch,
4235 .patch_size = ARRAY_SIZE(madera_fll_ao_32K_45M_patch),
4236 },
4237};
4238
4239static int madera_enable_fll_ao(struct madera_fll *fll,
4240 const struct reg_sequence *patch,
4241 unsigned int patch_size)
4242{
4243 struct madera *madera = fll->madera;
4244 int already_enabled = madera_is_enabled_fll(fll, base: fll->base);
4245 unsigned int val;
4246 int i;
4247
4248 if (already_enabled < 0)
4249 return already_enabled;
4250
4251 if (!already_enabled)
4252 pm_runtime_get_sync(dev: madera->dev);
4253
4254 madera_fll_dbg(fll, "Enabling FLL_AO, initially %s\n",
4255 already_enabled ? "enabled" : "disabled");
4256
4257 /* FLL_AO_HOLD must be set before configuring any registers */
4258 regmap_update_bits(map: fll->madera->regmap,
4259 reg: fll->base + MADERA_FLLAO_CONTROL_1_OFFS,
4260 MADERA_FLL_AO_HOLD, MADERA_FLL_AO_HOLD);
4261
4262 if (already_enabled)
4263 madera_set_fllao_clks(fll, base: fll->base, ena: false);
4264
4265 for (i = 0; i < patch_size; i++) {
4266 val = patch[i].def;
4267
4268 /* modify the patch to apply fll->ref_src as input clock */
4269 if (patch[i].reg == MADERA_FLLAO_CONTROL_6) {
4270 val &= ~MADERA_FLL_AO_REFCLK_SRC_MASK;
4271 val |= (fll->ref_src << MADERA_FLL_AO_REFCLK_SRC_SHIFT)
4272 & MADERA_FLL_AO_REFCLK_SRC_MASK;
4273 }
4274
4275 regmap_write(map: madera->regmap, reg: patch[i].reg, val);
4276 }
4277
4278 madera_set_fllao_clks(fll, base: fll->base, ena: true);
4279
4280 regmap_update_bits(map: madera->regmap,
4281 reg: fll->base + MADERA_FLLAO_CONTROL_1_OFFS,
4282 MADERA_FLL_AO_ENA, MADERA_FLL_AO_ENA);
4283
4284 /* Release the hold so that fll_ao locks to external frequency */
4285 regmap_update_bits(map: madera->regmap,
4286 reg: fll->base + MADERA_FLLAO_CONTROL_1_OFFS,
4287 MADERA_FLL_AO_HOLD, val: 0);
4288
4289 if (!already_enabled)
4290 madera_wait_for_fll(fll, requested: true);
4291
4292 return 0;
4293}
4294
4295static int madera_disable_fll_ao(struct madera_fll *fll)
4296{
4297 struct madera *madera = fll->madera;
4298 bool change;
4299
4300 madera_fll_dbg(fll, "Disabling FLL_AO\n");
4301
4302 regmap_update_bits(map: madera->regmap,
4303 reg: fll->base + MADERA_FLLAO_CONTROL_1_OFFS,
4304 MADERA_FLL_AO_HOLD, MADERA_FLL_AO_HOLD);
4305 regmap_update_bits_check(map: madera->regmap,
4306 reg: fll->base + MADERA_FLLAO_CONTROL_1_OFFS,
4307 MADERA_FLL_AO_ENA, val: 0, change: &change);
4308
4309 madera_wait_for_fll(fll, requested: false);
4310
4311 /*
4312 * ctrl_up gates the writes to all fll_ao register, setting it to 0
4313 * here ensures that after a runtime suspend/resume cycle when one
4314 * enables the fllao then ctrl_up is the last bit that is configured
4315 * by the fllao enable code rather than the cache sync operation which
4316 * would have updated it much earlier before writing out all fllao
4317 * registers
4318 */
4319 regmap_update_bits(map: madera->regmap,
4320 reg: fll->base + MADERA_FLLAO_CONTROL_2_OFFS,
4321 MADERA_FLL_AO_CTRL_UPD_MASK, val: 0);
4322
4323 if (change) {
4324 madera_set_fllao_clks(fll, base: fll->base, ena: false);
4325 pm_runtime_put_autosuspend(dev: madera->dev);
4326 }
4327
4328 return 0;
4329}
4330
4331int madera_set_fll_ao_refclk(struct madera_fll *fll, int source,
4332 unsigned int fin, unsigned int fout)
4333{
4334 int ret = 0;
4335 const struct reg_sequence *patch = NULL;
4336 int patch_size = 0;
4337 unsigned int i;
4338
4339 if (fll->ref_src == source &&
4340 fll->ref_freq == fin && fll->fout == fout)
4341 return 0;
4342
4343 madera_fll_dbg(fll, "Change FLL_AO refclk to fin=%u fout=%u source=%d\n",
4344 fin, fout, source);
4345
4346 if (fout && (fll->ref_freq != fin || fll->fout != fout)) {
4347 for (i = 0; i < ARRAY_SIZE(madera_fllao_settings); i++) {
4348 if (madera_fllao_settings[i].fin == fin &&
4349 madera_fllao_settings[i].fout == fout)
4350 break;
4351 }
4352
4353 if (i == ARRAY_SIZE(madera_fllao_settings)) {
4354 madera_fll_err(fll,
4355 "No matching configuration for FLL_AO\n");
4356 return -EINVAL;
4357 }
4358
4359 patch = madera_fllao_settings[i].patch;
4360 patch_size = madera_fllao_settings[i].patch_size;
4361 }
4362
4363 fll->ref_src = source;
4364 fll->ref_freq = fin;
4365 fll->fout = fout;
4366
4367 if (fout)
4368 ret = madera_enable_fll_ao(fll, patch, patch_size);
4369 else
4370 madera_disable_fll_ao(fll);
4371
4372 return ret;
4373}
4374EXPORT_SYMBOL_GPL(madera_set_fll_ao_refclk);
4375
4376static int madera_fllhj_disable(struct madera_fll *fll)
4377{
4378 struct madera *madera = fll->madera;
4379 bool change;
4380
4381 madera_fll_dbg(fll, "Disabling FLL\n");
4382
4383 /* Disable lockdet, but don't set ctrl_upd update but. This allows the
4384 * lock status bit to clear as normal, but should the FLL be enabled
4385 * again due to a control clock being required, the lock won't re-assert
4386 * as the FLL config registers are automatically applied when the FLL
4387 * enables.
4388 */
4389 regmap_update_bits(map: madera->regmap,
4390 reg: fll->base + MADERA_FLL_CONTROL_11_OFFS,
4391 MADERA_FLL1_LOCKDET_MASK, val: 0);
4392 regmap_update_bits(map: madera->regmap,
4393 reg: fll->base + MADERA_FLL_CONTROL_1_OFFS,
4394 MADERA_FLL1_HOLD_MASK, MADERA_FLL1_HOLD_MASK);
4395 regmap_update_bits_check(map: madera->regmap,
4396 reg: fll->base + MADERA_FLL_CONTROL_1_OFFS,
4397 MADERA_FLL1_ENA_MASK, val: 0, change: &change);
4398
4399 madera_wait_for_fll(fll, requested: false);
4400
4401 /* ctrl_up gates the writes to all the fll's registers, setting it to 0
4402 * here ensures that after a runtime suspend/resume cycle when one
4403 * enables the fll then ctrl_up is the last bit that is configured
4404 * by the fll enable code rather than the cache sync operation which
4405 * would have updated it much earlier before writing out all fll
4406 * registers
4407 */
4408 regmap_update_bits(map: madera->regmap,
4409 reg: fll->base + MADERA_FLL_CONTROL_2_OFFS,
4410 MADERA_FLL1_CTRL_UPD_MASK, val: 0);
4411
4412 if (change) {
4413 madera_set_fllhj_clks(fll, base: fll->base, ena: false);
4414 pm_runtime_put_autosuspend(dev: madera->dev);
4415 }
4416
4417 return 0;
4418}
4419
4420static int madera_fllhj_apply(struct madera_fll *fll, int fin)
4421{
4422 struct madera *madera = fll->madera;
4423 int refdiv, fref, fout, lockdet_thr, fbdiv, hp, fast_clk, fllgcd;
4424 bool frac = false;
4425 unsigned int fll_n, min_n, max_n, ratio, theta, lambda;
4426 unsigned int gains, val, num;
4427
4428 madera_fll_dbg(fll, "fin=%d, fout=%d\n", fin, fll->fout);
4429
4430 for (refdiv = 0; refdiv < 4; refdiv++)
4431 if ((fin / (1 << refdiv)) <= MADERA_FLLHJ_MAX_THRESH)
4432 break;
4433
4434 fref = fin / (1 << refdiv);
4435
4436 /* Use simple heuristic approach to find a configuration that
4437 * should work for most input clocks.
4438 */
4439 fast_clk = 0;
4440 fout = fll->fout;
4441 frac = fout % fref;
4442
4443 if (fref < MADERA_FLLHJ_LOW_THRESH) {
4444 lockdet_thr = 2;
4445 gains = MADERA_FLLHJ_LOW_GAINS;
4446 if (frac)
4447 fbdiv = 256;
4448 else
4449 fbdiv = 4;
4450 } else if (fref < MADERA_FLLHJ_MID_THRESH) {
4451 lockdet_thr = 8;
4452 gains = MADERA_FLLHJ_MID_GAINS;
4453 fbdiv = 1;
4454 } else {
4455 lockdet_thr = 8;
4456 gains = MADERA_FLLHJ_HIGH_GAINS;
4457 fbdiv = 1;
4458 /* For high speed input clocks, enable 300MHz fast oscillator
4459 * when we're in fractional divider mode.
4460 */
4461 if (frac) {
4462 fast_clk = 0x3;
4463 fout = fll->fout * 6;
4464 }
4465 }
4466 /* Use high performance mode for fractional configurations. */
4467 if (frac) {
4468 hp = 0x3;
4469 min_n = MADERA_FLLHJ_FRAC_MIN_N;
4470 max_n = MADERA_FLLHJ_FRAC_MAX_N;
4471 } else {
4472 hp = 0x0;
4473 min_n = MADERA_FLLHJ_INT_MIN_N;
4474 max_n = MADERA_FLLHJ_INT_MAX_N;
4475 }
4476
4477 ratio = fout / fref;
4478
4479 madera_fll_dbg(fll, "refdiv=%d, fref=%d, frac:%d\n",
4480 refdiv, fref, frac);
4481
4482 while (ratio / fbdiv < min_n) {
4483 fbdiv /= 2;
4484 if (fbdiv < 1) {
4485 madera_fll_err(fll, "FBDIV (%d) must be >= 1\n", fbdiv);
4486 return -EINVAL;
4487 }
4488 }
4489 while (frac && (ratio / fbdiv > max_n)) {
4490 fbdiv *= 2;
4491 if (fbdiv >= 1024) {
4492 madera_fll_err(fll, "FBDIV (%u) >= 1024\n", fbdiv);
4493 return -EINVAL;
4494 }
4495 }
4496
4497 madera_fll_dbg(fll, "lockdet=%d, hp=0x%x, fbdiv:%d\n",
4498 lockdet_thr, hp, fbdiv);
4499
4500 /* Calculate N.K values */
4501 fllgcd = gcd(a: fout, b: fbdiv * fref);
4502 num = fout / fllgcd;
4503 lambda = (fref * fbdiv) / fllgcd;
4504 fll_n = num / lambda;
4505 theta = num % lambda;
4506
4507 madera_fll_dbg(fll, "fll_n=%d, gcd=%d, theta=%d, lambda=%d\n",
4508 fll_n, fllgcd, theta, lambda);
4509
4510 /* Some sanity checks before any registers are written. */
4511 if (fll_n < min_n || fll_n > max_n) {
4512 madera_fll_err(fll, "N not in valid %s mode range %d-%d: %d\n",
4513 frac ? "fractional" : "integer", min_n, max_n,
4514 fll_n);
4515 return -EINVAL;
4516 }
4517 if (fbdiv < 1 || (frac && fbdiv >= 1024) || (!frac && fbdiv >= 256)) {
4518 madera_fll_err(fll, "Invalid fbdiv for %s mode (%u)\n",
4519 frac ? "fractional" : "integer", fbdiv);
4520 return -EINVAL;
4521 }
4522
4523 /* clear the ctrl_upd bit to guarantee we write to it later. */
4524 regmap_write(map: madera->regmap,
4525 reg: fll->base + MADERA_FLL_CONTROL_2_OFFS,
4526 val: fll_n << MADERA_FLL1_N_SHIFT);
4527 regmap_update_bits(map: madera->regmap,
4528 reg: fll->base + MADERA_FLL_CONTROL_3_OFFS,
4529 MADERA_FLL1_THETA_MASK,
4530 val: theta << MADERA_FLL1_THETA_SHIFT);
4531 regmap_update_bits(map: madera->regmap,
4532 reg: fll->base + MADERA_FLL_CONTROL_4_OFFS,
4533 MADERA_FLL1_LAMBDA_MASK,
4534 val: lambda << MADERA_FLL1_LAMBDA_SHIFT);
4535 regmap_update_bits(map: madera->regmap,
4536 reg: fll->base + MADERA_FLL_CONTROL_5_OFFS,
4537 MADERA_FLL1_FB_DIV_MASK,
4538 val: fbdiv << MADERA_FLL1_FB_DIV_SHIFT);
4539 regmap_update_bits(map: madera->regmap,
4540 reg: fll->base + MADERA_FLL_CONTROL_6_OFFS,
4541 MADERA_FLL1_REFCLK_DIV_MASK,
4542 val: refdiv << MADERA_FLL1_REFCLK_DIV_SHIFT);
4543 regmap_update_bits(map: madera->regmap,
4544 reg: fll->base + MADERA_FLL_GAIN_OFFS,
4545 mask: 0xffff,
4546 val: gains);
4547 val = hp << MADERA_FLL1_HP_SHIFT;
4548 val |= 1 << MADERA_FLL1_PHASEDET_ENA_SHIFT;
4549 regmap_update_bits(map: madera->regmap,
4550 reg: fll->base + MADERA_FLL_CONTROL_10_OFFS,
4551 MADERA_FLL1_HP_MASK | MADERA_FLL1_PHASEDET_ENA_MASK,
4552 val);
4553 regmap_update_bits(map: madera->regmap,
4554 reg: fll->base + MADERA_FLL_CONTROL_11_OFFS,
4555 MADERA_FLL1_LOCKDET_THR_MASK,
4556 val: lockdet_thr << MADERA_FLL1_LOCKDET_THR_SHIFT);
4557 regmap_update_bits(map: madera->regmap,
4558 reg: fll->base + MADERA_FLL1_DIGITAL_TEST_1_OFFS,
4559 MADERA_FLL1_SYNC_EFS_ENA_MASK |
4560 MADERA_FLL1_CLK_VCO_FAST_SRC_MASK,
4561 val: fast_clk);
4562
4563 return 0;
4564}
4565
4566static int madera_fllhj_enable(struct madera_fll *fll)
4567{
4568 struct madera *madera = fll->madera;
4569 int already_enabled = madera_is_enabled_fll(fll, base: fll->base);
4570 int ret;
4571
4572 if (already_enabled < 0)
4573 return already_enabled;
4574
4575 if (!already_enabled)
4576 pm_runtime_get_sync(dev: madera->dev);
4577
4578 madera_fll_dbg(fll, "Enabling FLL, initially %s\n",
4579 already_enabled ? "enabled" : "disabled");
4580
4581 /* FLLn_HOLD must be set before configuring any registers */
4582 regmap_update_bits(map: fll->madera->regmap,
4583 reg: fll->base + MADERA_FLL_CONTROL_1_OFFS,
4584 MADERA_FLL1_HOLD_MASK,
4585 MADERA_FLL1_HOLD_MASK);
4586
4587 if (already_enabled)
4588 madera_set_fllhj_clks(fll, base: fll->base, ena: false);
4589
4590 /* Apply refclk */
4591 ret = madera_fllhj_apply(fll, fin: fll->ref_freq);
4592 if (ret) {
4593 madera_fll_err(fll, "Failed to set FLL: %d\n", ret);
4594 goto out;
4595 }
4596 regmap_update_bits(map: madera->regmap,
4597 reg: fll->base + MADERA_FLL_CONTROL_1_OFFS,
4598 CS47L92_FLL1_REFCLK_SRC_MASK,
4599 val: fll->ref_src << CS47L92_FLL1_REFCLK_SRC_SHIFT);
4600
4601 madera_set_fllhj_clks(fll, base: fll->base, ena: true);
4602
4603 regmap_update_bits(map: madera->regmap,
4604 reg: fll->base + MADERA_FLL_CONTROL_1_OFFS,
4605 MADERA_FLL1_ENA_MASK,
4606 MADERA_FLL1_ENA_MASK);
4607
4608out:
4609 regmap_update_bits(map: madera->regmap,
4610 reg: fll->base + MADERA_FLL_CONTROL_11_OFFS,
4611 MADERA_FLL1_LOCKDET_MASK,
4612 MADERA_FLL1_LOCKDET_MASK);
4613
4614 regmap_update_bits(map: madera->regmap,
4615 reg: fll->base + MADERA_FLL_CONTROL_2_OFFS,
4616 MADERA_FLL1_CTRL_UPD_MASK,
4617 MADERA_FLL1_CTRL_UPD_MASK);
4618
4619 /* Release the hold so that flln locks to external frequency */
4620 regmap_update_bits(map: madera->regmap,
4621 reg: fll->base + MADERA_FLL_CONTROL_1_OFFS,
4622 MADERA_FLL1_HOLD_MASK,
4623 val: 0);
4624
4625 if (!already_enabled)
4626 madera_wait_for_fll(fll, requested: true);
4627
4628 return 0;
4629}
4630
4631static int madera_fllhj_validate(struct madera_fll *fll,
4632 unsigned int ref_in,
4633 unsigned int fout)
4634{
4635 if (fout && !ref_in) {
4636 madera_fll_err(fll, "fllout set without valid input clk\n");
4637 return -EINVAL;
4638 }
4639
4640 if (fll->fout && fout != fll->fout) {
4641 madera_fll_err(fll, "Can't change output on active FLL\n");
4642 return -EINVAL;
4643 }
4644
4645 if (ref_in / MADERA_FLL_MAX_REFDIV > MADERA_FLLHJ_MAX_THRESH) {
4646 madera_fll_err(fll, "Can't scale %dMHz to <=13MHz\n", ref_in);
4647 return -EINVAL;
4648 }
4649
4650 return 0;
4651}
4652
4653int madera_fllhj_set_refclk(struct madera_fll *fll, int source,
4654 unsigned int fin, unsigned int fout)
4655{
4656 int ret = 0;
4657
4658 /* To remain consistent with previous FLLs, we expect fout to be
4659 * provided in the form of the required sysclk rate, which is
4660 * 2x the calculated fll out.
4661 */
4662 if (fout)
4663 fout /= 2;
4664
4665 if (fll->ref_src == source && fll->ref_freq == fin &&
4666 fll->fout == fout)
4667 return 0;
4668
4669 if (fin && fout && madera_fllhj_validate(fll, ref_in: fin, fout))
4670 return -EINVAL;
4671
4672 fll->ref_src = source;
4673 fll->ref_freq = fin;
4674 fll->fout = fout;
4675
4676 if (fout)
4677 ret = madera_fllhj_enable(fll);
4678 else
4679 madera_fllhj_disable(fll);
4680
4681 return ret;
4682}
4683EXPORT_SYMBOL_GPL(madera_fllhj_set_refclk);
4684
4685/**
4686 * madera_set_output_mode - Set the mode of the specified output
4687 *
4688 * @component: Device to configure
4689 * @output: Output number
4690 * @differential: True to set the output to differential mode
4691 *
4692 * Some systems use external analogue switches to connect more
4693 * analogue devices to the CODEC than are supported by the device. In
4694 * some systems this requires changing the switched output from single
4695 * ended to differential mode dynamically at runtime, an operation
4696 * supported using this function.
4697 *
4698 * Most systems have a single static configuration and should use
4699 * platform data instead.
4700 */
4701int madera_set_output_mode(struct snd_soc_component *component, int output,
4702 bool differential)
4703{
4704 unsigned int reg, val;
4705 int ret;
4706
4707 if (output < 1 || output > MADERA_MAX_OUTPUT)
4708 return -EINVAL;
4709
4710 reg = MADERA_OUTPUT_PATH_CONFIG_1L + (output - 1) * 8;
4711
4712 if (differential)
4713 val = MADERA_OUT1_MONO;
4714 else
4715 val = 0;
4716
4717 ret = snd_soc_component_update_bits(component, reg, MADERA_OUT1_MONO,
4718 val);
4719 if (ret < 0)
4720 return ret;
4721 else
4722 return 0;
4723}
4724EXPORT_SYMBOL_GPL(madera_set_output_mode);
4725
4726static bool madera_eq_filter_unstable(bool mode, __be16 _a, __be16 _b)
4727{
4728 s16 a = be16_to_cpu(_a);
4729 s16 b = be16_to_cpu(_b);
4730
4731 if (!mode) {
4732 return abs(a) >= 4096;
4733 } else {
4734 if (abs(b) >= 4096)
4735 return true;
4736
4737 return (abs((a << 16) / (4096 - b)) >= 4096 << 4);
4738 }
4739}
4740
4741int madera_eq_coeff_put(struct snd_kcontrol *kcontrol,
4742 struct snd_ctl_elem_value *ucontrol)
4743{
4744 struct snd_soc_component *component =
4745 snd_soc_kcontrol_component(kcontrol);
4746 struct madera_priv *priv = snd_soc_component_get_drvdata(c: component);
4747 struct madera *madera = priv->madera;
4748 struct soc_bytes *params = (void *)kcontrol->private_value;
4749 unsigned int val;
4750 __be16 *data;
4751 int len;
4752 int ret;
4753
4754 len = params->num_regs * regmap_get_val_bytes(map: madera->regmap);
4755
4756 data = kmemdup(p: ucontrol->value.bytes.data, size: len, GFP_KERNEL | GFP_DMA);
4757 if (!data)
4758 return -ENOMEM;
4759
4760 data[0] &= cpu_to_be16(MADERA_EQ1_B1_MODE);
4761
4762 if (madera_eq_filter_unstable(mode: !!data[0], a: data[1], b: data[2]) ||
4763 madera_eq_filter_unstable(mode: true, a: data[4], b: data[5]) ||
4764 madera_eq_filter_unstable(mode: true, a: data[8], b: data[9]) ||
4765 madera_eq_filter_unstable(mode: true, a: data[12], b: data[13]) ||
4766 madera_eq_filter_unstable(mode: false, a: data[16], b: data[17])) {
4767 dev_err(madera->dev, "Rejecting unstable EQ coefficients\n");
4768 ret = -EINVAL;
4769 goto out;
4770 }
4771
4772 ret = regmap_read(map: madera->regmap, reg: params->base, val: &val);
4773 if (ret != 0)
4774 goto out;
4775
4776 val &= ~MADERA_EQ1_B1_MODE;
4777 data[0] |= cpu_to_be16(val);
4778
4779 ret = regmap_raw_write(map: madera->regmap, reg: params->base, val: data, val_len: len);
4780
4781out:
4782 kfree(objp: data);
4783
4784 return ret;
4785}
4786EXPORT_SYMBOL_GPL(madera_eq_coeff_put);
4787
4788int madera_lhpf_coeff_put(struct snd_kcontrol *kcontrol,
4789 struct snd_ctl_elem_value *ucontrol)
4790{
4791 struct snd_soc_component *component =
4792 snd_soc_kcontrol_component(kcontrol);
4793 struct madera_priv *priv = snd_soc_component_get_drvdata(c: component);
4794 struct madera *madera = priv->madera;
4795 __be16 *data = (__be16 *)ucontrol->value.bytes.data;
4796 s16 val = be16_to_cpu(*data);
4797
4798 if (abs(val) >= 4096) {
4799 dev_err(madera->dev, "Rejecting unstable LHPF coefficients\n");
4800 return -EINVAL;
4801 }
4802
4803 return snd_soc_bytes_put(kcontrol, ucontrol);
4804}
4805EXPORT_SYMBOL_GPL(madera_lhpf_coeff_put);
4806
4807MODULE_SOFTDEP("pre: madera");
4808MODULE_DESCRIPTION("ASoC Cirrus Logic Madera codec support");
4809MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.cirrus.com>");
4810MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
4811MODULE_LICENSE("GPL v2");
4812

source code of linux/sound/soc/codecs/madera.c