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