xref: /OK3568_Linux_fs/kernel/sound/soc/codecs/arizona.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * arizona.c - Wolfson Arizona class device shared support
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright 2012 Wolfson Microelectronics plc
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <linux/delay.h>
11*4882a593Smuzhiyun #include <linux/gcd.h>
12*4882a593Smuzhiyun #include <linux/module.h>
13*4882a593Smuzhiyun #include <linux/of.h>
14*4882a593Smuzhiyun #include <linux/pm_runtime.h>
15*4882a593Smuzhiyun #include <sound/pcm.h>
16*4882a593Smuzhiyun #include <sound/pcm_params.h>
17*4882a593Smuzhiyun #include <sound/tlv.h>
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun #include <linux/mfd/arizona/core.h>
20*4882a593Smuzhiyun #include <linux/mfd/arizona/registers.h>
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #include "arizona.h"
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun #define ARIZONA_AIF_BCLK_CTRL                   0x00
25*4882a593Smuzhiyun #define ARIZONA_AIF_TX_PIN_CTRL                 0x01
26*4882a593Smuzhiyun #define ARIZONA_AIF_RX_PIN_CTRL                 0x02
27*4882a593Smuzhiyun #define ARIZONA_AIF_RATE_CTRL                   0x03
28*4882a593Smuzhiyun #define ARIZONA_AIF_FORMAT                      0x04
29*4882a593Smuzhiyun #define ARIZONA_AIF_TX_BCLK_RATE                0x05
30*4882a593Smuzhiyun #define ARIZONA_AIF_RX_BCLK_RATE                0x06
31*4882a593Smuzhiyun #define ARIZONA_AIF_FRAME_CTRL_1                0x07
32*4882a593Smuzhiyun #define ARIZONA_AIF_FRAME_CTRL_2                0x08
33*4882a593Smuzhiyun #define ARIZONA_AIF_FRAME_CTRL_3                0x09
34*4882a593Smuzhiyun #define ARIZONA_AIF_FRAME_CTRL_4                0x0A
35*4882a593Smuzhiyun #define ARIZONA_AIF_FRAME_CTRL_5                0x0B
36*4882a593Smuzhiyun #define ARIZONA_AIF_FRAME_CTRL_6                0x0C
37*4882a593Smuzhiyun #define ARIZONA_AIF_FRAME_CTRL_7                0x0D
38*4882a593Smuzhiyun #define ARIZONA_AIF_FRAME_CTRL_8                0x0E
39*4882a593Smuzhiyun #define ARIZONA_AIF_FRAME_CTRL_9                0x0F
40*4882a593Smuzhiyun #define ARIZONA_AIF_FRAME_CTRL_10               0x10
41*4882a593Smuzhiyun #define ARIZONA_AIF_FRAME_CTRL_11               0x11
42*4882a593Smuzhiyun #define ARIZONA_AIF_FRAME_CTRL_12               0x12
43*4882a593Smuzhiyun #define ARIZONA_AIF_FRAME_CTRL_13               0x13
44*4882a593Smuzhiyun #define ARIZONA_AIF_FRAME_CTRL_14               0x14
45*4882a593Smuzhiyun #define ARIZONA_AIF_FRAME_CTRL_15               0x15
46*4882a593Smuzhiyun #define ARIZONA_AIF_FRAME_CTRL_16               0x16
47*4882a593Smuzhiyun #define ARIZONA_AIF_FRAME_CTRL_17               0x17
48*4882a593Smuzhiyun #define ARIZONA_AIF_FRAME_CTRL_18               0x18
49*4882a593Smuzhiyun #define ARIZONA_AIF_TX_ENABLES                  0x19
50*4882a593Smuzhiyun #define ARIZONA_AIF_RX_ENABLES                  0x1A
51*4882a593Smuzhiyun #define ARIZONA_AIF_FORCE_WRITE                 0x1B
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun #define ARIZONA_FLL_VCO_CORNER 141900000
54*4882a593Smuzhiyun #define ARIZONA_FLL_MAX_FREF   13500000
55*4882a593Smuzhiyun #define ARIZONA_FLL_MIN_FVCO   90000000
56*4882a593Smuzhiyun #define ARIZONA_FLL_MAX_FRATIO 16
57*4882a593Smuzhiyun #define ARIZONA_FLL_MAX_REFDIV 8
58*4882a593Smuzhiyun #define ARIZONA_FLL_MIN_OUTDIV 2
59*4882a593Smuzhiyun #define ARIZONA_FLL_MAX_OUTDIV 7
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun #define ARIZONA_FMT_DSP_MODE_A          0
62*4882a593Smuzhiyun #define ARIZONA_FMT_DSP_MODE_B          1
63*4882a593Smuzhiyun #define ARIZONA_FMT_I2S_MODE            2
64*4882a593Smuzhiyun #define ARIZONA_FMT_LEFT_JUSTIFIED_MODE 3
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun #define arizona_fll_err(_fll, fmt, ...) \
67*4882a593Smuzhiyun 	dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
68*4882a593Smuzhiyun #define arizona_fll_warn(_fll, fmt, ...) \
69*4882a593Smuzhiyun 	dev_warn(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
70*4882a593Smuzhiyun #define arizona_fll_dbg(_fll, fmt, ...) \
71*4882a593Smuzhiyun 	dev_dbg(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun #define arizona_aif_err(_dai, fmt, ...) \
74*4882a593Smuzhiyun 	dev_err(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
75*4882a593Smuzhiyun #define arizona_aif_warn(_dai, fmt, ...) \
76*4882a593Smuzhiyun 	dev_warn(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
77*4882a593Smuzhiyun #define arizona_aif_dbg(_dai, fmt, ...) \
78*4882a593Smuzhiyun 	dev_dbg(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
79*4882a593Smuzhiyun 
arizona_spk_ev(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)80*4882a593Smuzhiyun static int arizona_spk_ev(struct snd_soc_dapm_widget *w,
81*4882a593Smuzhiyun 			  struct snd_kcontrol *kcontrol,
82*4882a593Smuzhiyun 			  int event)
83*4882a593Smuzhiyun {
84*4882a593Smuzhiyun 	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
85*4882a593Smuzhiyun 	struct arizona *arizona = dev_get_drvdata(component->dev->parent);
86*4882a593Smuzhiyun 	int val;
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun 	switch (event) {
89*4882a593Smuzhiyun 	case SND_SOC_DAPM_POST_PMU:
90*4882a593Smuzhiyun 		val = snd_soc_component_read(component,
91*4882a593Smuzhiyun 					       ARIZONA_INTERRUPT_RAW_STATUS_3);
92*4882a593Smuzhiyun 		if (val & ARIZONA_SPK_OVERHEAT_STS) {
93*4882a593Smuzhiyun 			dev_crit(arizona->dev,
94*4882a593Smuzhiyun 				 "Speaker not enabled due to temperature\n");
95*4882a593Smuzhiyun 			return -EBUSY;
96*4882a593Smuzhiyun 		}
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 		regmap_update_bits_async(arizona->regmap,
99*4882a593Smuzhiyun 					 ARIZONA_OUTPUT_ENABLES_1,
100*4882a593Smuzhiyun 					 1 << w->shift, 1 << w->shift);
101*4882a593Smuzhiyun 		break;
102*4882a593Smuzhiyun 	case SND_SOC_DAPM_PRE_PMD:
103*4882a593Smuzhiyun 		regmap_update_bits_async(arizona->regmap,
104*4882a593Smuzhiyun 					 ARIZONA_OUTPUT_ENABLES_1,
105*4882a593Smuzhiyun 					 1 << w->shift, 0);
106*4882a593Smuzhiyun 		break;
107*4882a593Smuzhiyun 	default:
108*4882a593Smuzhiyun 		break;
109*4882a593Smuzhiyun 	}
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	return arizona_out_ev(w, kcontrol, event);
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun 
arizona_thermal_warn(int irq,void * data)114*4882a593Smuzhiyun static irqreturn_t arizona_thermal_warn(int irq, void *data)
115*4882a593Smuzhiyun {
116*4882a593Smuzhiyun 	struct arizona *arizona = data;
117*4882a593Smuzhiyun 	unsigned int val;
118*4882a593Smuzhiyun 	int ret;
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_3,
121*4882a593Smuzhiyun 			  &val);
122*4882a593Smuzhiyun 	if (ret != 0) {
123*4882a593Smuzhiyun 		dev_err(arizona->dev, "Failed to read thermal status: %d\n",
124*4882a593Smuzhiyun 			ret);
125*4882a593Smuzhiyun 	} else if (val & ARIZONA_SPK_OVERHEAT_WARN_STS) {
126*4882a593Smuzhiyun 		dev_crit(arizona->dev, "Thermal warning\n");
127*4882a593Smuzhiyun 	}
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun 	return IRQ_HANDLED;
130*4882a593Smuzhiyun }
131*4882a593Smuzhiyun 
arizona_thermal_shutdown(int irq,void * data)132*4882a593Smuzhiyun static irqreturn_t arizona_thermal_shutdown(int irq, void *data)
133*4882a593Smuzhiyun {
134*4882a593Smuzhiyun 	struct arizona *arizona = data;
135*4882a593Smuzhiyun 	unsigned int val;
136*4882a593Smuzhiyun 	int ret;
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_3,
139*4882a593Smuzhiyun 			  &val);
140*4882a593Smuzhiyun 	if (ret != 0) {
141*4882a593Smuzhiyun 		dev_err(arizona->dev, "Failed to read thermal status: %d\n",
142*4882a593Smuzhiyun 			ret);
143*4882a593Smuzhiyun 	} else if (val & ARIZONA_SPK_OVERHEAT_STS) {
144*4882a593Smuzhiyun 		dev_crit(arizona->dev, "Thermal shutdown\n");
145*4882a593Smuzhiyun 		ret = regmap_update_bits(arizona->regmap,
146*4882a593Smuzhiyun 					 ARIZONA_OUTPUT_ENABLES_1,
147*4882a593Smuzhiyun 					 ARIZONA_OUT4L_ENA |
148*4882a593Smuzhiyun 					 ARIZONA_OUT4R_ENA, 0);
149*4882a593Smuzhiyun 		if (ret != 0)
150*4882a593Smuzhiyun 			dev_crit(arizona->dev,
151*4882a593Smuzhiyun 				 "Failed to disable speaker outputs: %d\n",
152*4882a593Smuzhiyun 				 ret);
153*4882a593Smuzhiyun 	}
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	return IRQ_HANDLED;
156*4882a593Smuzhiyun }
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun static const struct snd_soc_dapm_widget arizona_spkl =
159*4882a593Smuzhiyun 	SND_SOC_DAPM_PGA_E("OUT4L", SND_SOC_NOPM,
160*4882a593Smuzhiyun 			   ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev,
161*4882a593Smuzhiyun 			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
162*4882a593Smuzhiyun 			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD);
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun static const struct snd_soc_dapm_widget arizona_spkr =
165*4882a593Smuzhiyun 	SND_SOC_DAPM_PGA_E("OUT4R", SND_SOC_NOPM,
166*4882a593Smuzhiyun 			   ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev,
167*4882a593Smuzhiyun 			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
168*4882a593Smuzhiyun 			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD);
169*4882a593Smuzhiyun 
arizona_init_spk(struct snd_soc_component * component)170*4882a593Smuzhiyun int arizona_init_spk(struct snd_soc_component *component)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun 	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
173*4882a593Smuzhiyun 	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
174*4882a593Smuzhiyun 	struct arizona *arizona = priv->arizona;
175*4882a593Smuzhiyun 	int ret;
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 	ret = snd_soc_dapm_new_controls(dapm, &arizona_spkl, 1);
178*4882a593Smuzhiyun 	if (ret != 0)
179*4882a593Smuzhiyun 		return ret;
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	switch (arizona->type) {
182*4882a593Smuzhiyun 	case WM8997:
183*4882a593Smuzhiyun 	case CS47L24:
184*4882a593Smuzhiyun 	case WM1831:
185*4882a593Smuzhiyun 		break;
186*4882a593Smuzhiyun 	default:
187*4882a593Smuzhiyun 		ret = snd_soc_dapm_new_controls(dapm, &arizona_spkr, 1);
188*4882a593Smuzhiyun 		if (ret != 0)
189*4882a593Smuzhiyun 			return ret;
190*4882a593Smuzhiyun 		break;
191*4882a593Smuzhiyun 	}
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 	return 0;
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_init_spk);
196*4882a593Smuzhiyun 
arizona_init_spk_irqs(struct arizona * arizona)197*4882a593Smuzhiyun int arizona_init_spk_irqs(struct arizona *arizona)
198*4882a593Smuzhiyun {
199*4882a593Smuzhiyun 	int ret;
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT_WARN,
202*4882a593Smuzhiyun 				  "Thermal warning", arizona_thermal_warn,
203*4882a593Smuzhiyun 				  arizona);
204*4882a593Smuzhiyun 	if (ret != 0)
205*4882a593Smuzhiyun 		dev_err(arizona->dev,
206*4882a593Smuzhiyun 			"Failed to get thermal warning IRQ: %d\n",
207*4882a593Smuzhiyun 			ret);
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 	ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT,
210*4882a593Smuzhiyun 				  "Thermal shutdown", arizona_thermal_shutdown,
211*4882a593Smuzhiyun 				  arizona);
212*4882a593Smuzhiyun 	if (ret != 0)
213*4882a593Smuzhiyun 		dev_err(arizona->dev,
214*4882a593Smuzhiyun 			"Failed to get thermal shutdown IRQ: %d\n",
215*4882a593Smuzhiyun 			ret);
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun 	return 0;
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_init_spk_irqs);
220*4882a593Smuzhiyun 
arizona_free_spk_irqs(struct arizona * arizona)221*4882a593Smuzhiyun int arizona_free_spk_irqs(struct arizona *arizona)
222*4882a593Smuzhiyun {
223*4882a593Smuzhiyun 	arizona_free_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT_WARN, arizona);
224*4882a593Smuzhiyun 	arizona_free_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT, arizona);
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun 	return 0;
227*4882a593Smuzhiyun }
228*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_free_spk_irqs);
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun static const struct snd_soc_dapm_route arizona_mono_routes[] = {
231*4882a593Smuzhiyun 	{ "OUT1R", NULL, "OUT1L" },
232*4882a593Smuzhiyun 	{ "OUT2R", NULL, "OUT2L" },
233*4882a593Smuzhiyun 	{ "OUT3R", NULL, "OUT3L" },
234*4882a593Smuzhiyun 	{ "OUT4R", NULL, "OUT4L" },
235*4882a593Smuzhiyun 	{ "OUT5R", NULL, "OUT5L" },
236*4882a593Smuzhiyun 	{ "OUT6R", NULL, "OUT6L" },
237*4882a593Smuzhiyun };
238*4882a593Smuzhiyun 
arizona_init_mono(struct snd_soc_component * component)239*4882a593Smuzhiyun int arizona_init_mono(struct snd_soc_component *component)
240*4882a593Smuzhiyun {
241*4882a593Smuzhiyun 	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
242*4882a593Smuzhiyun 	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
243*4882a593Smuzhiyun 	struct arizona *arizona = priv->arizona;
244*4882a593Smuzhiyun 	int i;
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	for (i = 0; i < ARIZONA_MAX_OUTPUT; ++i) {
247*4882a593Smuzhiyun 		if (arizona->pdata.out_mono[i])
248*4882a593Smuzhiyun 			snd_soc_dapm_add_routes(dapm,
249*4882a593Smuzhiyun 						&arizona_mono_routes[i], 1);
250*4882a593Smuzhiyun 	}
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 	return 0;
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_init_mono);
255*4882a593Smuzhiyun 
arizona_init_gpio(struct snd_soc_component * component)256*4882a593Smuzhiyun int arizona_init_gpio(struct snd_soc_component *component)
257*4882a593Smuzhiyun {
258*4882a593Smuzhiyun 	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
259*4882a593Smuzhiyun 	struct arizona *arizona = priv->arizona;
260*4882a593Smuzhiyun 	int i;
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun 	switch (arizona->type) {
263*4882a593Smuzhiyun 	case WM5110:
264*4882a593Smuzhiyun 	case WM8280:
265*4882a593Smuzhiyun 		snd_soc_component_disable_pin(component,
266*4882a593Smuzhiyun 					      "DRC2 Signal Activity");
267*4882a593Smuzhiyun 		break;
268*4882a593Smuzhiyun 	default:
269*4882a593Smuzhiyun 		break;
270*4882a593Smuzhiyun 	}
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun 	snd_soc_component_disable_pin(component, "DRC1 Signal Activity");
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) {
275*4882a593Smuzhiyun 		switch (arizona->pdata.gpio_defaults[i] & ARIZONA_GPN_FN_MASK) {
276*4882a593Smuzhiyun 		case ARIZONA_GP_FN_DRC1_SIGNAL_DETECT:
277*4882a593Smuzhiyun 			snd_soc_component_enable_pin(component,
278*4882a593Smuzhiyun 						     "DRC1 Signal Activity");
279*4882a593Smuzhiyun 			break;
280*4882a593Smuzhiyun 		case ARIZONA_GP_FN_DRC2_SIGNAL_DETECT:
281*4882a593Smuzhiyun 			snd_soc_component_enable_pin(component,
282*4882a593Smuzhiyun 						     "DRC2 Signal Activity");
283*4882a593Smuzhiyun 			break;
284*4882a593Smuzhiyun 		default:
285*4882a593Smuzhiyun 			break;
286*4882a593Smuzhiyun 		}
287*4882a593Smuzhiyun 	}
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun 	return 0;
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_init_gpio);
292*4882a593Smuzhiyun 
arizona_init_common(struct arizona * arizona)293*4882a593Smuzhiyun int arizona_init_common(struct arizona *arizona)
294*4882a593Smuzhiyun {
295*4882a593Smuzhiyun 	struct arizona_pdata *pdata = &arizona->pdata;
296*4882a593Smuzhiyun 	unsigned int val, mask;
297*4882a593Smuzhiyun 	int i;
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun 	BLOCKING_INIT_NOTIFIER_HEAD(&arizona->notifier);
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 	for (i = 0; i < ARIZONA_MAX_OUTPUT; ++i) {
302*4882a593Smuzhiyun 		/* Default is 0 so noop with defaults */
303*4882a593Smuzhiyun 		if (pdata->out_mono[i])
304*4882a593Smuzhiyun 			val = ARIZONA_OUT1_MONO;
305*4882a593Smuzhiyun 		else
306*4882a593Smuzhiyun 			val = 0;
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 		regmap_update_bits(arizona->regmap,
309*4882a593Smuzhiyun 				   ARIZONA_OUTPUT_PATH_CONFIG_1L + (i * 8),
310*4882a593Smuzhiyun 				   ARIZONA_OUT1_MONO, val);
311*4882a593Smuzhiyun 	}
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun 	for (i = 0; i < ARIZONA_MAX_PDM_SPK; i++) {
314*4882a593Smuzhiyun 		if (pdata->spk_mute[i])
315*4882a593Smuzhiyun 			regmap_update_bits(arizona->regmap,
316*4882a593Smuzhiyun 					   ARIZONA_PDM_SPK1_CTRL_1 + (i * 2),
317*4882a593Smuzhiyun 					   ARIZONA_SPK1_MUTE_ENDIAN_MASK |
318*4882a593Smuzhiyun 					   ARIZONA_SPK1_MUTE_SEQ1_MASK,
319*4882a593Smuzhiyun 					   pdata->spk_mute[i]);
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun 		if (pdata->spk_fmt[i])
322*4882a593Smuzhiyun 			regmap_update_bits(arizona->regmap,
323*4882a593Smuzhiyun 					   ARIZONA_PDM_SPK1_CTRL_2 + (i * 2),
324*4882a593Smuzhiyun 					   ARIZONA_SPK1_FMT_MASK,
325*4882a593Smuzhiyun 					   pdata->spk_fmt[i]);
326*4882a593Smuzhiyun 	}
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun 	for (i = 0; i < ARIZONA_MAX_INPUT; i++) {
329*4882a593Smuzhiyun 		/* Default for both is 0 so noop with defaults */
330*4882a593Smuzhiyun 		val = pdata->dmic_ref[i] << ARIZONA_IN1_DMIC_SUP_SHIFT;
331*4882a593Smuzhiyun 		if (pdata->inmode[i] & ARIZONA_INMODE_DMIC)
332*4882a593Smuzhiyun 			val |= 1 << ARIZONA_IN1_MODE_SHIFT;
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun 		switch (arizona->type) {
335*4882a593Smuzhiyun 		case WM8998:
336*4882a593Smuzhiyun 		case WM1814:
337*4882a593Smuzhiyun 			regmap_update_bits(arizona->regmap,
338*4882a593Smuzhiyun 				ARIZONA_ADC_DIGITAL_VOLUME_1L + (i * 8),
339*4882a593Smuzhiyun 				ARIZONA_IN1L_SRC_SE_MASK,
340*4882a593Smuzhiyun 				(pdata->inmode[i] & ARIZONA_INMODE_SE)
341*4882a593Smuzhiyun 					<< ARIZONA_IN1L_SRC_SE_SHIFT);
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun 			regmap_update_bits(arizona->regmap,
344*4882a593Smuzhiyun 				ARIZONA_ADC_DIGITAL_VOLUME_1R + (i * 8),
345*4882a593Smuzhiyun 				ARIZONA_IN1R_SRC_SE_MASK,
346*4882a593Smuzhiyun 				(pdata->inmode[i] & ARIZONA_INMODE_SE)
347*4882a593Smuzhiyun 					<< ARIZONA_IN1R_SRC_SE_SHIFT);
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun 			mask = ARIZONA_IN1_DMIC_SUP_MASK |
350*4882a593Smuzhiyun 			       ARIZONA_IN1_MODE_MASK;
351*4882a593Smuzhiyun 			break;
352*4882a593Smuzhiyun 		default:
353*4882a593Smuzhiyun 			if (pdata->inmode[i] & ARIZONA_INMODE_SE)
354*4882a593Smuzhiyun 				val |= 1 << ARIZONA_IN1_SINGLE_ENDED_SHIFT;
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun 			mask = ARIZONA_IN1_DMIC_SUP_MASK |
357*4882a593Smuzhiyun 			       ARIZONA_IN1_MODE_MASK |
358*4882a593Smuzhiyun 			       ARIZONA_IN1_SINGLE_ENDED_MASK;
359*4882a593Smuzhiyun 			break;
360*4882a593Smuzhiyun 		}
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun 		regmap_update_bits(arizona->regmap,
363*4882a593Smuzhiyun 				   ARIZONA_IN1L_CONTROL + (i * 8),
364*4882a593Smuzhiyun 				   mask, val);
365*4882a593Smuzhiyun 	}
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 	return 0;
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_init_common);
370*4882a593Smuzhiyun 
arizona_init_vol_limit(struct arizona * arizona)371*4882a593Smuzhiyun int arizona_init_vol_limit(struct arizona *arizona)
372*4882a593Smuzhiyun {
373*4882a593Smuzhiyun 	int i;
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(arizona->pdata.out_vol_limit); ++i) {
376*4882a593Smuzhiyun 		if (arizona->pdata.out_vol_limit[i])
377*4882a593Smuzhiyun 			regmap_update_bits(arizona->regmap,
378*4882a593Smuzhiyun 					   ARIZONA_DAC_VOLUME_LIMIT_1L + i * 4,
379*4882a593Smuzhiyun 					   ARIZONA_OUT1L_VOL_LIM_MASK,
380*4882a593Smuzhiyun 					   arizona->pdata.out_vol_limit[i]);
381*4882a593Smuzhiyun 	}
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun 	return 0;
384*4882a593Smuzhiyun }
385*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_init_vol_limit);
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun const char * const arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
388*4882a593Smuzhiyun 	"None",
389*4882a593Smuzhiyun 	"Tone Generator 1",
390*4882a593Smuzhiyun 	"Tone Generator 2",
391*4882a593Smuzhiyun 	"Haptics",
392*4882a593Smuzhiyun 	"AEC",
393*4882a593Smuzhiyun 	"AEC2",
394*4882a593Smuzhiyun 	"Mic Mute Mixer",
395*4882a593Smuzhiyun 	"Noise Generator",
396*4882a593Smuzhiyun 	"IN1L",
397*4882a593Smuzhiyun 	"IN1R",
398*4882a593Smuzhiyun 	"IN2L",
399*4882a593Smuzhiyun 	"IN2R",
400*4882a593Smuzhiyun 	"IN3L",
401*4882a593Smuzhiyun 	"IN3R",
402*4882a593Smuzhiyun 	"IN4L",
403*4882a593Smuzhiyun 	"IN4R",
404*4882a593Smuzhiyun 	"AIF1RX1",
405*4882a593Smuzhiyun 	"AIF1RX2",
406*4882a593Smuzhiyun 	"AIF1RX3",
407*4882a593Smuzhiyun 	"AIF1RX4",
408*4882a593Smuzhiyun 	"AIF1RX5",
409*4882a593Smuzhiyun 	"AIF1RX6",
410*4882a593Smuzhiyun 	"AIF1RX7",
411*4882a593Smuzhiyun 	"AIF1RX8",
412*4882a593Smuzhiyun 	"AIF2RX1",
413*4882a593Smuzhiyun 	"AIF2RX2",
414*4882a593Smuzhiyun 	"AIF2RX3",
415*4882a593Smuzhiyun 	"AIF2RX4",
416*4882a593Smuzhiyun 	"AIF2RX5",
417*4882a593Smuzhiyun 	"AIF2RX6",
418*4882a593Smuzhiyun 	"AIF3RX1",
419*4882a593Smuzhiyun 	"AIF3RX2",
420*4882a593Smuzhiyun 	"SLIMRX1",
421*4882a593Smuzhiyun 	"SLIMRX2",
422*4882a593Smuzhiyun 	"SLIMRX3",
423*4882a593Smuzhiyun 	"SLIMRX4",
424*4882a593Smuzhiyun 	"SLIMRX5",
425*4882a593Smuzhiyun 	"SLIMRX6",
426*4882a593Smuzhiyun 	"SLIMRX7",
427*4882a593Smuzhiyun 	"SLIMRX8",
428*4882a593Smuzhiyun 	"EQ1",
429*4882a593Smuzhiyun 	"EQ2",
430*4882a593Smuzhiyun 	"EQ3",
431*4882a593Smuzhiyun 	"EQ4",
432*4882a593Smuzhiyun 	"DRC1L",
433*4882a593Smuzhiyun 	"DRC1R",
434*4882a593Smuzhiyun 	"DRC2L",
435*4882a593Smuzhiyun 	"DRC2R",
436*4882a593Smuzhiyun 	"LHPF1",
437*4882a593Smuzhiyun 	"LHPF2",
438*4882a593Smuzhiyun 	"LHPF3",
439*4882a593Smuzhiyun 	"LHPF4",
440*4882a593Smuzhiyun 	"DSP1.1",
441*4882a593Smuzhiyun 	"DSP1.2",
442*4882a593Smuzhiyun 	"DSP1.3",
443*4882a593Smuzhiyun 	"DSP1.4",
444*4882a593Smuzhiyun 	"DSP1.5",
445*4882a593Smuzhiyun 	"DSP1.6",
446*4882a593Smuzhiyun 	"DSP2.1",
447*4882a593Smuzhiyun 	"DSP2.2",
448*4882a593Smuzhiyun 	"DSP2.3",
449*4882a593Smuzhiyun 	"DSP2.4",
450*4882a593Smuzhiyun 	"DSP2.5",
451*4882a593Smuzhiyun 	"DSP2.6",
452*4882a593Smuzhiyun 	"DSP3.1",
453*4882a593Smuzhiyun 	"DSP3.2",
454*4882a593Smuzhiyun 	"DSP3.3",
455*4882a593Smuzhiyun 	"DSP3.4",
456*4882a593Smuzhiyun 	"DSP3.5",
457*4882a593Smuzhiyun 	"DSP3.6",
458*4882a593Smuzhiyun 	"DSP4.1",
459*4882a593Smuzhiyun 	"DSP4.2",
460*4882a593Smuzhiyun 	"DSP4.3",
461*4882a593Smuzhiyun 	"DSP4.4",
462*4882a593Smuzhiyun 	"DSP4.5",
463*4882a593Smuzhiyun 	"DSP4.6",
464*4882a593Smuzhiyun 	"ASRC1L",
465*4882a593Smuzhiyun 	"ASRC1R",
466*4882a593Smuzhiyun 	"ASRC2L",
467*4882a593Smuzhiyun 	"ASRC2R",
468*4882a593Smuzhiyun 	"ISRC1INT1",
469*4882a593Smuzhiyun 	"ISRC1INT2",
470*4882a593Smuzhiyun 	"ISRC1INT3",
471*4882a593Smuzhiyun 	"ISRC1INT4",
472*4882a593Smuzhiyun 	"ISRC1DEC1",
473*4882a593Smuzhiyun 	"ISRC1DEC2",
474*4882a593Smuzhiyun 	"ISRC1DEC3",
475*4882a593Smuzhiyun 	"ISRC1DEC4",
476*4882a593Smuzhiyun 	"ISRC2INT1",
477*4882a593Smuzhiyun 	"ISRC2INT2",
478*4882a593Smuzhiyun 	"ISRC2INT3",
479*4882a593Smuzhiyun 	"ISRC2INT4",
480*4882a593Smuzhiyun 	"ISRC2DEC1",
481*4882a593Smuzhiyun 	"ISRC2DEC2",
482*4882a593Smuzhiyun 	"ISRC2DEC3",
483*4882a593Smuzhiyun 	"ISRC2DEC4",
484*4882a593Smuzhiyun 	"ISRC3INT1",
485*4882a593Smuzhiyun 	"ISRC3INT2",
486*4882a593Smuzhiyun 	"ISRC3INT3",
487*4882a593Smuzhiyun 	"ISRC3INT4",
488*4882a593Smuzhiyun 	"ISRC3DEC1",
489*4882a593Smuzhiyun 	"ISRC3DEC2",
490*4882a593Smuzhiyun 	"ISRC3DEC3",
491*4882a593Smuzhiyun 	"ISRC3DEC4",
492*4882a593Smuzhiyun };
493*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_mixer_texts);
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun unsigned int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {
496*4882a593Smuzhiyun 	0x00,  /* None */
497*4882a593Smuzhiyun 	0x04,  /* Tone */
498*4882a593Smuzhiyun 	0x05,
499*4882a593Smuzhiyun 	0x06,  /* Haptics */
500*4882a593Smuzhiyun 	0x08,  /* AEC */
501*4882a593Smuzhiyun 	0x09,  /* AEC2 */
502*4882a593Smuzhiyun 	0x0c,  /* Noise mixer */
503*4882a593Smuzhiyun 	0x0d,  /* Comfort noise */
504*4882a593Smuzhiyun 	0x10,  /* IN1L */
505*4882a593Smuzhiyun 	0x11,
506*4882a593Smuzhiyun 	0x12,
507*4882a593Smuzhiyun 	0x13,
508*4882a593Smuzhiyun 	0x14,
509*4882a593Smuzhiyun 	0x15,
510*4882a593Smuzhiyun 	0x16,
511*4882a593Smuzhiyun 	0x17,
512*4882a593Smuzhiyun 	0x20,  /* AIF1RX1 */
513*4882a593Smuzhiyun 	0x21,
514*4882a593Smuzhiyun 	0x22,
515*4882a593Smuzhiyun 	0x23,
516*4882a593Smuzhiyun 	0x24,
517*4882a593Smuzhiyun 	0x25,
518*4882a593Smuzhiyun 	0x26,
519*4882a593Smuzhiyun 	0x27,
520*4882a593Smuzhiyun 	0x28,  /* AIF2RX1 */
521*4882a593Smuzhiyun 	0x29,
522*4882a593Smuzhiyun 	0x2a,
523*4882a593Smuzhiyun 	0x2b,
524*4882a593Smuzhiyun 	0x2c,
525*4882a593Smuzhiyun 	0x2d,
526*4882a593Smuzhiyun 	0x30,  /* AIF3RX1 */
527*4882a593Smuzhiyun 	0x31,
528*4882a593Smuzhiyun 	0x38,  /* SLIMRX1 */
529*4882a593Smuzhiyun 	0x39,
530*4882a593Smuzhiyun 	0x3a,
531*4882a593Smuzhiyun 	0x3b,
532*4882a593Smuzhiyun 	0x3c,
533*4882a593Smuzhiyun 	0x3d,
534*4882a593Smuzhiyun 	0x3e,
535*4882a593Smuzhiyun 	0x3f,
536*4882a593Smuzhiyun 	0x50,  /* EQ1 */
537*4882a593Smuzhiyun 	0x51,
538*4882a593Smuzhiyun 	0x52,
539*4882a593Smuzhiyun 	0x53,
540*4882a593Smuzhiyun 	0x58,  /* DRC1L */
541*4882a593Smuzhiyun 	0x59,
542*4882a593Smuzhiyun 	0x5a,
543*4882a593Smuzhiyun 	0x5b,
544*4882a593Smuzhiyun 	0x60,  /* LHPF1 */
545*4882a593Smuzhiyun 	0x61,
546*4882a593Smuzhiyun 	0x62,
547*4882a593Smuzhiyun 	0x63,
548*4882a593Smuzhiyun 	0x68,  /* DSP1.1 */
549*4882a593Smuzhiyun 	0x69,
550*4882a593Smuzhiyun 	0x6a,
551*4882a593Smuzhiyun 	0x6b,
552*4882a593Smuzhiyun 	0x6c,
553*4882a593Smuzhiyun 	0x6d,
554*4882a593Smuzhiyun 	0x70,  /* DSP2.1 */
555*4882a593Smuzhiyun 	0x71,
556*4882a593Smuzhiyun 	0x72,
557*4882a593Smuzhiyun 	0x73,
558*4882a593Smuzhiyun 	0x74,
559*4882a593Smuzhiyun 	0x75,
560*4882a593Smuzhiyun 	0x78,  /* DSP3.1 */
561*4882a593Smuzhiyun 	0x79,
562*4882a593Smuzhiyun 	0x7a,
563*4882a593Smuzhiyun 	0x7b,
564*4882a593Smuzhiyun 	0x7c,
565*4882a593Smuzhiyun 	0x7d,
566*4882a593Smuzhiyun 	0x80,  /* DSP4.1 */
567*4882a593Smuzhiyun 	0x81,
568*4882a593Smuzhiyun 	0x82,
569*4882a593Smuzhiyun 	0x83,
570*4882a593Smuzhiyun 	0x84,
571*4882a593Smuzhiyun 	0x85,
572*4882a593Smuzhiyun 	0x90,  /* ASRC1L */
573*4882a593Smuzhiyun 	0x91,
574*4882a593Smuzhiyun 	0x92,
575*4882a593Smuzhiyun 	0x93,
576*4882a593Smuzhiyun 	0xa0,  /* ISRC1INT1 */
577*4882a593Smuzhiyun 	0xa1,
578*4882a593Smuzhiyun 	0xa2,
579*4882a593Smuzhiyun 	0xa3,
580*4882a593Smuzhiyun 	0xa4,  /* ISRC1DEC1 */
581*4882a593Smuzhiyun 	0xa5,
582*4882a593Smuzhiyun 	0xa6,
583*4882a593Smuzhiyun 	0xa7,
584*4882a593Smuzhiyun 	0xa8,  /* ISRC2DEC1 */
585*4882a593Smuzhiyun 	0xa9,
586*4882a593Smuzhiyun 	0xaa,
587*4882a593Smuzhiyun 	0xab,
588*4882a593Smuzhiyun 	0xac,  /* ISRC2INT1 */
589*4882a593Smuzhiyun 	0xad,
590*4882a593Smuzhiyun 	0xae,
591*4882a593Smuzhiyun 	0xaf,
592*4882a593Smuzhiyun 	0xb0,  /* ISRC3DEC1 */
593*4882a593Smuzhiyun 	0xb1,
594*4882a593Smuzhiyun 	0xb2,
595*4882a593Smuzhiyun 	0xb3,
596*4882a593Smuzhiyun 	0xb4,  /* ISRC3INT1 */
597*4882a593Smuzhiyun 	0xb5,
598*4882a593Smuzhiyun 	0xb6,
599*4882a593Smuzhiyun 	0xb7,
600*4882a593Smuzhiyun };
601*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_mixer_values);
602*4882a593Smuzhiyun 
603*4882a593Smuzhiyun const DECLARE_TLV_DB_SCALE(arizona_mixer_tlv, -3200, 100, 0);
604*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_mixer_tlv);
605*4882a593Smuzhiyun 
606*4882a593Smuzhiyun const char * const arizona_sample_rate_text[ARIZONA_SAMPLE_RATE_ENUM_SIZE] = {
607*4882a593Smuzhiyun 	"12kHz", "24kHz", "48kHz", "96kHz", "192kHz",
608*4882a593Smuzhiyun 	"11.025kHz", "22.05kHz", "44.1kHz", "88.2kHz", "176.4kHz",
609*4882a593Smuzhiyun 	"4kHz", "8kHz", "16kHz", "32kHz",
610*4882a593Smuzhiyun };
611*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_sample_rate_text);
612*4882a593Smuzhiyun 
613*4882a593Smuzhiyun const unsigned int arizona_sample_rate_val[ARIZONA_SAMPLE_RATE_ENUM_SIZE] = {
614*4882a593Smuzhiyun 	0x01, 0x02, 0x03, 0x04, 0x05, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
615*4882a593Smuzhiyun 	0x10, 0x11, 0x12, 0x13,
616*4882a593Smuzhiyun };
617*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_sample_rate_val);
618*4882a593Smuzhiyun 
arizona_sample_rate_val_to_name(unsigned int rate_val)619*4882a593Smuzhiyun const char *arizona_sample_rate_val_to_name(unsigned int rate_val)
620*4882a593Smuzhiyun {
621*4882a593Smuzhiyun 	int i;
622*4882a593Smuzhiyun 
623*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(arizona_sample_rate_val); ++i) {
624*4882a593Smuzhiyun 		if (arizona_sample_rate_val[i] == rate_val)
625*4882a593Smuzhiyun 			return arizona_sample_rate_text[i];
626*4882a593Smuzhiyun 	}
627*4882a593Smuzhiyun 
628*4882a593Smuzhiyun 	return "Illegal";
629*4882a593Smuzhiyun }
630*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_sample_rate_val_to_name);
631*4882a593Smuzhiyun 
632*4882a593Smuzhiyun const char * const arizona_rate_text[ARIZONA_RATE_ENUM_SIZE] = {
633*4882a593Smuzhiyun 	"SYNCCLK rate", "8kHz", "16kHz", "ASYNCCLK rate",
634*4882a593Smuzhiyun };
635*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_rate_text);
636*4882a593Smuzhiyun 
637*4882a593Smuzhiyun const unsigned int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE] = {
638*4882a593Smuzhiyun 	0, 1, 2, 8,
639*4882a593Smuzhiyun };
640*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_rate_val);
641*4882a593Smuzhiyun 
642*4882a593Smuzhiyun const struct soc_enum arizona_isrc_fsh[] = {
643*4882a593Smuzhiyun 	SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_1,
644*4882a593Smuzhiyun 			      ARIZONA_ISRC1_FSH_SHIFT, 0xf,
645*4882a593Smuzhiyun 			      ARIZONA_RATE_ENUM_SIZE,
646*4882a593Smuzhiyun 			      arizona_rate_text, arizona_rate_val),
647*4882a593Smuzhiyun 	SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_1,
648*4882a593Smuzhiyun 			      ARIZONA_ISRC2_FSH_SHIFT, 0xf,
649*4882a593Smuzhiyun 			      ARIZONA_RATE_ENUM_SIZE,
650*4882a593Smuzhiyun 			      arizona_rate_text, arizona_rate_val),
651*4882a593Smuzhiyun 	SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_1,
652*4882a593Smuzhiyun 			      ARIZONA_ISRC3_FSH_SHIFT, 0xf,
653*4882a593Smuzhiyun 			      ARIZONA_RATE_ENUM_SIZE,
654*4882a593Smuzhiyun 			      arizona_rate_text, arizona_rate_val),
655*4882a593Smuzhiyun };
656*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_isrc_fsh);
657*4882a593Smuzhiyun 
658*4882a593Smuzhiyun const struct soc_enum arizona_isrc_fsl[] = {
659*4882a593Smuzhiyun 	SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_2,
660*4882a593Smuzhiyun 			      ARIZONA_ISRC1_FSL_SHIFT, 0xf,
661*4882a593Smuzhiyun 			      ARIZONA_RATE_ENUM_SIZE,
662*4882a593Smuzhiyun 			      arizona_rate_text, arizona_rate_val),
663*4882a593Smuzhiyun 	SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_2,
664*4882a593Smuzhiyun 			      ARIZONA_ISRC2_FSL_SHIFT, 0xf,
665*4882a593Smuzhiyun 			      ARIZONA_RATE_ENUM_SIZE,
666*4882a593Smuzhiyun 			      arizona_rate_text, arizona_rate_val),
667*4882a593Smuzhiyun 	SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_2,
668*4882a593Smuzhiyun 			      ARIZONA_ISRC3_FSL_SHIFT, 0xf,
669*4882a593Smuzhiyun 			      ARIZONA_RATE_ENUM_SIZE,
670*4882a593Smuzhiyun 			      arizona_rate_text, arizona_rate_val),
671*4882a593Smuzhiyun };
672*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_isrc_fsl);
673*4882a593Smuzhiyun 
674*4882a593Smuzhiyun const struct soc_enum arizona_asrc_rate1 =
675*4882a593Smuzhiyun 	SOC_VALUE_ENUM_SINGLE(ARIZONA_ASRC_RATE1,
676*4882a593Smuzhiyun 			      ARIZONA_ASRC_RATE1_SHIFT, 0xf,
677*4882a593Smuzhiyun 			      ARIZONA_RATE_ENUM_SIZE - 1,
678*4882a593Smuzhiyun 			      arizona_rate_text, arizona_rate_val);
679*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_asrc_rate1);
680*4882a593Smuzhiyun 
681*4882a593Smuzhiyun static const char * const arizona_vol_ramp_text[] = {
682*4882a593Smuzhiyun 	"0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB",
683*4882a593Smuzhiyun 	"15ms/6dB", "30ms/6dB",
684*4882a593Smuzhiyun };
685*4882a593Smuzhiyun 
686*4882a593Smuzhiyun SOC_ENUM_SINGLE_DECL(arizona_in_vd_ramp,
687*4882a593Smuzhiyun 		     ARIZONA_INPUT_VOLUME_RAMP,
688*4882a593Smuzhiyun 		     ARIZONA_IN_VD_RAMP_SHIFT,
689*4882a593Smuzhiyun 		     arizona_vol_ramp_text);
690*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_in_vd_ramp);
691*4882a593Smuzhiyun 
692*4882a593Smuzhiyun SOC_ENUM_SINGLE_DECL(arizona_in_vi_ramp,
693*4882a593Smuzhiyun 		     ARIZONA_INPUT_VOLUME_RAMP,
694*4882a593Smuzhiyun 		     ARIZONA_IN_VI_RAMP_SHIFT,
695*4882a593Smuzhiyun 		     arizona_vol_ramp_text);
696*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_in_vi_ramp);
697*4882a593Smuzhiyun 
698*4882a593Smuzhiyun SOC_ENUM_SINGLE_DECL(arizona_out_vd_ramp,
699*4882a593Smuzhiyun 		     ARIZONA_OUTPUT_VOLUME_RAMP,
700*4882a593Smuzhiyun 		     ARIZONA_OUT_VD_RAMP_SHIFT,
701*4882a593Smuzhiyun 		     arizona_vol_ramp_text);
702*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_out_vd_ramp);
703*4882a593Smuzhiyun 
704*4882a593Smuzhiyun SOC_ENUM_SINGLE_DECL(arizona_out_vi_ramp,
705*4882a593Smuzhiyun 		     ARIZONA_OUTPUT_VOLUME_RAMP,
706*4882a593Smuzhiyun 		     ARIZONA_OUT_VI_RAMP_SHIFT,
707*4882a593Smuzhiyun 		     arizona_vol_ramp_text);
708*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_out_vi_ramp);
709*4882a593Smuzhiyun 
710*4882a593Smuzhiyun static const char * const arizona_lhpf_mode_text[] = {
711*4882a593Smuzhiyun 	"Low-pass", "High-pass"
712*4882a593Smuzhiyun };
713*4882a593Smuzhiyun 
714*4882a593Smuzhiyun SOC_ENUM_SINGLE_DECL(arizona_lhpf1_mode,
715*4882a593Smuzhiyun 		     ARIZONA_HPLPF1_1,
716*4882a593Smuzhiyun 		     ARIZONA_LHPF1_MODE_SHIFT,
717*4882a593Smuzhiyun 		     arizona_lhpf_mode_text);
718*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_lhpf1_mode);
719*4882a593Smuzhiyun 
720*4882a593Smuzhiyun SOC_ENUM_SINGLE_DECL(arizona_lhpf2_mode,
721*4882a593Smuzhiyun 		     ARIZONA_HPLPF2_1,
722*4882a593Smuzhiyun 		     ARIZONA_LHPF2_MODE_SHIFT,
723*4882a593Smuzhiyun 		     arizona_lhpf_mode_text);
724*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_lhpf2_mode);
725*4882a593Smuzhiyun 
726*4882a593Smuzhiyun SOC_ENUM_SINGLE_DECL(arizona_lhpf3_mode,
727*4882a593Smuzhiyun 		     ARIZONA_HPLPF3_1,
728*4882a593Smuzhiyun 		     ARIZONA_LHPF3_MODE_SHIFT,
729*4882a593Smuzhiyun 		     arizona_lhpf_mode_text);
730*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_lhpf3_mode);
731*4882a593Smuzhiyun 
732*4882a593Smuzhiyun SOC_ENUM_SINGLE_DECL(arizona_lhpf4_mode,
733*4882a593Smuzhiyun 		     ARIZONA_HPLPF4_1,
734*4882a593Smuzhiyun 		     ARIZONA_LHPF4_MODE_SHIFT,
735*4882a593Smuzhiyun 		     arizona_lhpf_mode_text);
736*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_lhpf4_mode);
737*4882a593Smuzhiyun 
738*4882a593Smuzhiyun static const char * const arizona_ng_hold_text[] = {
739*4882a593Smuzhiyun 	"30ms", "120ms", "250ms", "500ms",
740*4882a593Smuzhiyun };
741*4882a593Smuzhiyun 
742*4882a593Smuzhiyun SOC_ENUM_SINGLE_DECL(arizona_ng_hold,
743*4882a593Smuzhiyun 		     ARIZONA_NOISE_GATE_CONTROL,
744*4882a593Smuzhiyun 		     ARIZONA_NGATE_HOLD_SHIFT,
745*4882a593Smuzhiyun 		     arizona_ng_hold_text);
746*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_ng_hold);
747*4882a593Smuzhiyun 
748*4882a593Smuzhiyun static const char * const arizona_in_hpf_cut_text[] = {
749*4882a593Smuzhiyun 	"2.5Hz", "5Hz", "10Hz", "20Hz", "40Hz"
750*4882a593Smuzhiyun };
751*4882a593Smuzhiyun 
752*4882a593Smuzhiyun SOC_ENUM_SINGLE_DECL(arizona_in_hpf_cut_enum,
753*4882a593Smuzhiyun 		     ARIZONA_HPF_CONTROL,
754*4882a593Smuzhiyun 		     ARIZONA_IN_HPF_CUT_SHIFT,
755*4882a593Smuzhiyun 		     arizona_in_hpf_cut_text);
756*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_in_hpf_cut_enum);
757*4882a593Smuzhiyun 
758*4882a593Smuzhiyun static const char * const arizona_in_dmic_osr_text[] = {
759*4882a593Smuzhiyun 	"1.536MHz", "3.072MHz", "6.144MHz", "768kHz",
760*4882a593Smuzhiyun };
761*4882a593Smuzhiyun 
762*4882a593Smuzhiyun const struct soc_enum arizona_in_dmic_osr[] = {
763*4882a593Smuzhiyun 	SOC_ENUM_SINGLE(ARIZONA_IN1L_CONTROL, ARIZONA_IN1_OSR_SHIFT,
764*4882a593Smuzhiyun 			ARRAY_SIZE(arizona_in_dmic_osr_text),
765*4882a593Smuzhiyun 			arizona_in_dmic_osr_text),
766*4882a593Smuzhiyun 	SOC_ENUM_SINGLE(ARIZONA_IN2L_CONTROL, ARIZONA_IN2_OSR_SHIFT,
767*4882a593Smuzhiyun 			ARRAY_SIZE(arizona_in_dmic_osr_text),
768*4882a593Smuzhiyun 			arizona_in_dmic_osr_text),
769*4882a593Smuzhiyun 	SOC_ENUM_SINGLE(ARIZONA_IN3L_CONTROL, ARIZONA_IN3_OSR_SHIFT,
770*4882a593Smuzhiyun 			ARRAY_SIZE(arizona_in_dmic_osr_text),
771*4882a593Smuzhiyun 			arizona_in_dmic_osr_text),
772*4882a593Smuzhiyun 	SOC_ENUM_SINGLE(ARIZONA_IN4L_CONTROL, ARIZONA_IN4_OSR_SHIFT,
773*4882a593Smuzhiyun 			ARRAY_SIZE(arizona_in_dmic_osr_text),
774*4882a593Smuzhiyun 			arizona_in_dmic_osr_text),
775*4882a593Smuzhiyun };
776*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_in_dmic_osr);
777*4882a593Smuzhiyun 
778*4882a593Smuzhiyun static const char * const arizona_anc_input_src_text[] = {
779*4882a593Smuzhiyun 	"None", "IN1", "IN2", "IN3", "IN4",
780*4882a593Smuzhiyun };
781*4882a593Smuzhiyun 
782*4882a593Smuzhiyun static const char * const arizona_anc_channel_src_text[] = {
783*4882a593Smuzhiyun 	"None", "Left", "Right", "Combine",
784*4882a593Smuzhiyun };
785*4882a593Smuzhiyun 
786*4882a593Smuzhiyun const struct soc_enum arizona_anc_input_src[] = {
787*4882a593Smuzhiyun 	SOC_ENUM_SINGLE(ARIZONA_ANC_SRC,
788*4882a593Smuzhiyun 			ARIZONA_IN_RXANCL_SEL_SHIFT,
789*4882a593Smuzhiyun 			ARRAY_SIZE(arizona_anc_input_src_text),
790*4882a593Smuzhiyun 			arizona_anc_input_src_text),
791*4882a593Smuzhiyun 	SOC_ENUM_SINGLE(ARIZONA_FCL_ADC_REFORMATTER_CONTROL,
792*4882a593Smuzhiyun 			ARIZONA_FCL_MIC_MODE_SEL_SHIFT,
793*4882a593Smuzhiyun 			ARRAY_SIZE(arizona_anc_channel_src_text),
794*4882a593Smuzhiyun 			arizona_anc_channel_src_text),
795*4882a593Smuzhiyun 	SOC_ENUM_SINGLE(ARIZONA_ANC_SRC,
796*4882a593Smuzhiyun 			ARIZONA_IN_RXANCR_SEL_SHIFT,
797*4882a593Smuzhiyun 			ARRAY_SIZE(arizona_anc_input_src_text),
798*4882a593Smuzhiyun 			arizona_anc_input_src_text),
799*4882a593Smuzhiyun 	SOC_ENUM_SINGLE(ARIZONA_FCR_ADC_REFORMATTER_CONTROL,
800*4882a593Smuzhiyun 			ARIZONA_FCR_MIC_MODE_SEL_SHIFT,
801*4882a593Smuzhiyun 			ARRAY_SIZE(arizona_anc_channel_src_text),
802*4882a593Smuzhiyun 			arizona_anc_channel_src_text),
803*4882a593Smuzhiyun };
804*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_anc_input_src);
805*4882a593Smuzhiyun 
806*4882a593Smuzhiyun static const char * const arizona_anc_ng_texts[] = {
807*4882a593Smuzhiyun 	"None",
808*4882a593Smuzhiyun 	"Internal",
809*4882a593Smuzhiyun 	"External",
810*4882a593Smuzhiyun };
811*4882a593Smuzhiyun 
812*4882a593Smuzhiyun SOC_ENUM_SINGLE_DECL(arizona_anc_ng_enum, SND_SOC_NOPM, 0,
813*4882a593Smuzhiyun 		     arizona_anc_ng_texts);
814*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_anc_ng_enum);
815*4882a593Smuzhiyun 
816*4882a593Smuzhiyun static const char * const arizona_output_anc_src_text[] = {
817*4882a593Smuzhiyun 	"None", "RXANCL", "RXANCR",
818*4882a593Smuzhiyun };
819*4882a593Smuzhiyun 
820*4882a593Smuzhiyun const struct soc_enum arizona_output_anc_src[] = {
821*4882a593Smuzhiyun 	SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1L,
822*4882a593Smuzhiyun 			ARIZONA_OUT1L_ANC_SRC_SHIFT,
823*4882a593Smuzhiyun 			ARRAY_SIZE(arizona_output_anc_src_text),
824*4882a593Smuzhiyun 			arizona_output_anc_src_text),
825*4882a593Smuzhiyun 	SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1R,
826*4882a593Smuzhiyun 			ARIZONA_OUT1R_ANC_SRC_SHIFT,
827*4882a593Smuzhiyun 			ARRAY_SIZE(arizona_output_anc_src_text),
828*4882a593Smuzhiyun 			arizona_output_anc_src_text),
829*4882a593Smuzhiyun 	SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_2L,
830*4882a593Smuzhiyun 			ARIZONA_OUT2L_ANC_SRC_SHIFT,
831*4882a593Smuzhiyun 			ARRAY_SIZE(arizona_output_anc_src_text),
832*4882a593Smuzhiyun 			arizona_output_anc_src_text),
833*4882a593Smuzhiyun 	SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_2R,
834*4882a593Smuzhiyun 			ARIZONA_OUT2R_ANC_SRC_SHIFT,
835*4882a593Smuzhiyun 			ARRAY_SIZE(arizona_output_anc_src_text),
836*4882a593Smuzhiyun 			arizona_output_anc_src_text),
837*4882a593Smuzhiyun 	SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_3L,
838*4882a593Smuzhiyun 			ARIZONA_OUT3L_ANC_SRC_SHIFT,
839*4882a593Smuzhiyun 			ARRAY_SIZE(arizona_output_anc_src_text),
840*4882a593Smuzhiyun 			arizona_output_anc_src_text),
841*4882a593Smuzhiyun 	SOC_ENUM_SINGLE(ARIZONA_DAC_VOLUME_LIMIT_3R,
842*4882a593Smuzhiyun 			ARIZONA_OUT3R_ANC_SRC_SHIFT,
843*4882a593Smuzhiyun 			ARRAY_SIZE(arizona_output_anc_src_text),
844*4882a593Smuzhiyun 			arizona_output_anc_src_text),
845*4882a593Smuzhiyun 	SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_4L,
846*4882a593Smuzhiyun 			ARIZONA_OUT4L_ANC_SRC_SHIFT,
847*4882a593Smuzhiyun 			ARRAY_SIZE(arizona_output_anc_src_text),
848*4882a593Smuzhiyun 			arizona_output_anc_src_text),
849*4882a593Smuzhiyun 	SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_4R,
850*4882a593Smuzhiyun 			ARIZONA_OUT4R_ANC_SRC_SHIFT,
851*4882a593Smuzhiyun 			ARRAY_SIZE(arizona_output_anc_src_text),
852*4882a593Smuzhiyun 			arizona_output_anc_src_text),
853*4882a593Smuzhiyun 	SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_5L,
854*4882a593Smuzhiyun 			ARIZONA_OUT5L_ANC_SRC_SHIFT,
855*4882a593Smuzhiyun 			ARRAY_SIZE(arizona_output_anc_src_text),
856*4882a593Smuzhiyun 			arizona_output_anc_src_text),
857*4882a593Smuzhiyun 	SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_5R,
858*4882a593Smuzhiyun 			ARIZONA_OUT5R_ANC_SRC_SHIFT,
859*4882a593Smuzhiyun 			ARRAY_SIZE(arizona_output_anc_src_text),
860*4882a593Smuzhiyun 			arizona_output_anc_src_text),
861*4882a593Smuzhiyun 	SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_6L,
862*4882a593Smuzhiyun 			ARIZONA_OUT6L_ANC_SRC_SHIFT,
863*4882a593Smuzhiyun 			ARRAY_SIZE(arizona_output_anc_src_text),
864*4882a593Smuzhiyun 			arizona_output_anc_src_text),
865*4882a593Smuzhiyun 	SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_6R,
866*4882a593Smuzhiyun 			ARIZONA_OUT6R_ANC_SRC_SHIFT,
867*4882a593Smuzhiyun 			ARRAY_SIZE(arizona_output_anc_src_text),
868*4882a593Smuzhiyun 			arizona_output_anc_src_text),
869*4882a593Smuzhiyun };
870*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_output_anc_src);
871*4882a593Smuzhiyun 
872*4882a593Smuzhiyun const struct snd_kcontrol_new arizona_voice_trigger_switch[] = {
873*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0),
874*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 1, 1, 0),
875*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 2, 1, 0),
876*4882a593Smuzhiyun 	SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 3, 1, 0),
877*4882a593Smuzhiyun };
878*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_voice_trigger_switch);
879*4882a593Smuzhiyun 
arizona_in_set_vu(struct snd_soc_component * component,int ena)880*4882a593Smuzhiyun static void arizona_in_set_vu(struct snd_soc_component *component, int ena)
881*4882a593Smuzhiyun {
882*4882a593Smuzhiyun 	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
883*4882a593Smuzhiyun 	unsigned int val;
884*4882a593Smuzhiyun 	int i;
885*4882a593Smuzhiyun 
886*4882a593Smuzhiyun 	if (ena)
887*4882a593Smuzhiyun 		val = ARIZONA_IN_VU;
888*4882a593Smuzhiyun 	else
889*4882a593Smuzhiyun 		val = 0;
890*4882a593Smuzhiyun 
891*4882a593Smuzhiyun 	for (i = 0; i < priv->num_inputs; i++)
892*4882a593Smuzhiyun 		snd_soc_component_update_bits(component,
893*4882a593Smuzhiyun 				    ARIZONA_ADC_DIGITAL_VOLUME_1L + (i * 4),
894*4882a593Smuzhiyun 				    ARIZONA_IN_VU, val);
895*4882a593Smuzhiyun }
896*4882a593Smuzhiyun 
arizona_input_analog(struct snd_soc_component * component,int shift)897*4882a593Smuzhiyun bool arizona_input_analog(struct snd_soc_component *component, int shift)
898*4882a593Smuzhiyun {
899*4882a593Smuzhiyun 	unsigned int reg = ARIZONA_IN1L_CONTROL + ((shift / 2) * 8);
900*4882a593Smuzhiyun 	unsigned int val = snd_soc_component_read(component, reg);
901*4882a593Smuzhiyun 
902*4882a593Smuzhiyun 	return !(val & ARIZONA_IN1_MODE_MASK);
903*4882a593Smuzhiyun }
904*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_input_analog);
905*4882a593Smuzhiyun 
arizona_in_ev(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)906*4882a593Smuzhiyun int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
907*4882a593Smuzhiyun 		  int event)
908*4882a593Smuzhiyun {
909*4882a593Smuzhiyun 	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
910*4882a593Smuzhiyun 	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
911*4882a593Smuzhiyun 	unsigned int reg;
912*4882a593Smuzhiyun 
913*4882a593Smuzhiyun 	if (w->shift % 2)
914*4882a593Smuzhiyun 		reg = ARIZONA_ADC_DIGITAL_VOLUME_1L + ((w->shift / 2) * 8);
915*4882a593Smuzhiyun 	else
916*4882a593Smuzhiyun 		reg = ARIZONA_ADC_DIGITAL_VOLUME_1R + ((w->shift / 2) * 8);
917*4882a593Smuzhiyun 
918*4882a593Smuzhiyun 	switch (event) {
919*4882a593Smuzhiyun 	case SND_SOC_DAPM_PRE_PMU:
920*4882a593Smuzhiyun 		priv->in_pending++;
921*4882a593Smuzhiyun 		break;
922*4882a593Smuzhiyun 	case SND_SOC_DAPM_POST_PMU:
923*4882a593Smuzhiyun 		snd_soc_component_update_bits(component, reg,
924*4882a593Smuzhiyun 					      ARIZONA_IN1L_MUTE, 0);
925*4882a593Smuzhiyun 
926*4882a593Smuzhiyun 		/* If this is the last input pending then allow VU */
927*4882a593Smuzhiyun 		priv->in_pending--;
928*4882a593Smuzhiyun 		if (priv->in_pending == 0) {
929*4882a593Smuzhiyun 			msleep(1);
930*4882a593Smuzhiyun 			arizona_in_set_vu(component, 1);
931*4882a593Smuzhiyun 		}
932*4882a593Smuzhiyun 		break;
933*4882a593Smuzhiyun 	case SND_SOC_DAPM_PRE_PMD:
934*4882a593Smuzhiyun 		snd_soc_component_update_bits(component, reg,
935*4882a593Smuzhiyun 				    ARIZONA_IN1L_MUTE | ARIZONA_IN_VU,
936*4882a593Smuzhiyun 				    ARIZONA_IN1L_MUTE | ARIZONA_IN_VU);
937*4882a593Smuzhiyun 		break;
938*4882a593Smuzhiyun 	case SND_SOC_DAPM_POST_PMD:
939*4882a593Smuzhiyun 		/* Disable volume updates if no inputs are enabled */
940*4882a593Smuzhiyun 		reg = snd_soc_component_read(component, ARIZONA_INPUT_ENABLES);
941*4882a593Smuzhiyun 		if (reg == 0)
942*4882a593Smuzhiyun 			arizona_in_set_vu(component, 0);
943*4882a593Smuzhiyun 		break;
944*4882a593Smuzhiyun 	default:
945*4882a593Smuzhiyun 		break;
946*4882a593Smuzhiyun 	}
947*4882a593Smuzhiyun 
948*4882a593Smuzhiyun 	return 0;
949*4882a593Smuzhiyun }
950*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_in_ev);
951*4882a593Smuzhiyun 
arizona_out_ev(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)952*4882a593Smuzhiyun int arizona_out_ev(struct snd_soc_dapm_widget *w,
953*4882a593Smuzhiyun 		   struct snd_kcontrol *kcontrol,
954*4882a593Smuzhiyun 		   int event)
955*4882a593Smuzhiyun {
956*4882a593Smuzhiyun 	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
957*4882a593Smuzhiyun 	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
958*4882a593Smuzhiyun 	struct arizona *arizona = priv->arizona;
959*4882a593Smuzhiyun 
960*4882a593Smuzhiyun 	switch (event) {
961*4882a593Smuzhiyun 	case SND_SOC_DAPM_PRE_PMU:
962*4882a593Smuzhiyun 		switch (w->shift) {
963*4882a593Smuzhiyun 		case ARIZONA_OUT1L_ENA_SHIFT:
964*4882a593Smuzhiyun 		case ARIZONA_OUT1R_ENA_SHIFT:
965*4882a593Smuzhiyun 		case ARIZONA_OUT2L_ENA_SHIFT:
966*4882a593Smuzhiyun 		case ARIZONA_OUT2R_ENA_SHIFT:
967*4882a593Smuzhiyun 		case ARIZONA_OUT3L_ENA_SHIFT:
968*4882a593Smuzhiyun 		case ARIZONA_OUT3R_ENA_SHIFT:
969*4882a593Smuzhiyun 			priv->out_up_pending++;
970*4882a593Smuzhiyun 			priv->out_up_delay += 17;
971*4882a593Smuzhiyun 			break;
972*4882a593Smuzhiyun 		case ARIZONA_OUT4L_ENA_SHIFT:
973*4882a593Smuzhiyun 		case ARIZONA_OUT4R_ENA_SHIFT:
974*4882a593Smuzhiyun 			priv->out_up_pending++;
975*4882a593Smuzhiyun 			switch (arizona->type) {
976*4882a593Smuzhiyun 			case WM5102:
977*4882a593Smuzhiyun 			case WM8997:
978*4882a593Smuzhiyun 				break;
979*4882a593Smuzhiyun 			default:
980*4882a593Smuzhiyun 				priv->out_up_delay += 10;
981*4882a593Smuzhiyun 				break;
982*4882a593Smuzhiyun 			}
983*4882a593Smuzhiyun 			break;
984*4882a593Smuzhiyun 		default:
985*4882a593Smuzhiyun 			break;
986*4882a593Smuzhiyun 		}
987*4882a593Smuzhiyun 		break;
988*4882a593Smuzhiyun 	case SND_SOC_DAPM_POST_PMU:
989*4882a593Smuzhiyun 		switch (w->shift) {
990*4882a593Smuzhiyun 		case ARIZONA_OUT1L_ENA_SHIFT:
991*4882a593Smuzhiyun 		case ARIZONA_OUT1R_ENA_SHIFT:
992*4882a593Smuzhiyun 		case ARIZONA_OUT2L_ENA_SHIFT:
993*4882a593Smuzhiyun 		case ARIZONA_OUT2R_ENA_SHIFT:
994*4882a593Smuzhiyun 		case ARIZONA_OUT3L_ENA_SHIFT:
995*4882a593Smuzhiyun 		case ARIZONA_OUT3R_ENA_SHIFT:
996*4882a593Smuzhiyun 		case ARIZONA_OUT4L_ENA_SHIFT:
997*4882a593Smuzhiyun 		case ARIZONA_OUT4R_ENA_SHIFT:
998*4882a593Smuzhiyun 			priv->out_up_pending--;
999*4882a593Smuzhiyun 			if (!priv->out_up_pending && priv->out_up_delay) {
1000*4882a593Smuzhiyun 				dev_dbg(component->dev, "Power up delay: %d\n",
1001*4882a593Smuzhiyun 					priv->out_up_delay);
1002*4882a593Smuzhiyun 				msleep(priv->out_up_delay);
1003*4882a593Smuzhiyun 				priv->out_up_delay = 0;
1004*4882a593Smuzhiyun 			}
1005*4882a593Smuzhiyun 			break;
1006*4882a593Smuzhiyun 
1007*4882a593Smuzhiyun 		default:
1008*4882a593Smuzhiyun 			break;
1009*4882a593Smuzhiyun 		}
1010*4882a593Smuzhiyun 		break;
1011*4882a593Smuzhiyun 	case SND_SOC_DAPM_PRE_PMD:
1012*4882a593Smuzhiyun 		switch (w->shift) {
1013*4882a593Smuzhiyun 		case ARIZONA_OUT1L_ENA_SHIFT:
1014*4882a593Smuzhiyun 		case ARIZONA_OUT1R_ENA_SHIFT:
1015*4882a593Smuzhiyun 		case ARIZONA_OUT2L_ENA_SHIFT:
1016*4882a593Smuzhiyun 		case ARIZONA_OUT2R_ENA_SHIFT:
1017*4882a593Smuzhiyun 		case ARIZONA_OUT3L_ENA_SHIFT:
1018*4882a593Smuzhiyun 		case ARIZONA_OUT3R_ENA_SHIFT:
1019*4882a593Smuzhiyun 			priv->out_down_pending++;
1020*4882a593Smuzhiyun 			priv->out_down_delay++;
1021*4882a593Smuzhiyun 			break;
1022*4882a593Smuzhiyun 		case ARIZONA_OUT4L_ENA_SHIFT:
1023*4882a593Smuzhiyun 		case ARIZONA_OUT4R_ENA_SHIFT:
1024*4882a593Smuzhiyun 			priv->out_down_pending++;
1025*4882a593Smuzhiyun 			switch (arizona->type) {
1026*4882a593Smuzhiyun 			case WM5102:
1027*4882a593Smuzhiyun 			case WM8997:
1028*4882a593Smuzhiyun 				break;
1029*4882a593Smuzhiyun 			case WM8998:
1030*4882a593Smuzhiyun 			case WM1814:
1031*4882a593Smuzhiyun 				priv->out_down_delay += 5;
1032*4882a593Smuzhiyun 				break;
1033*4882a593Smuzhiyun 			default:
1034*4882a593Smuzhiyun 				priv->out_down_delay++;
1035*4882a593Smuzhiyun 				break;
1036*4882a593Smuzhiyun 			}
1037*4882a593Smuzhiyun 		default:
1038*4882a593Smuzhiyun 			break;
1039*4882a593Smuzhiyun 		}
1040*4882a593Smuzhiyun 		break;
1041*4882a593Smuzhiyun 	case SND_SOC_DAPM_POST_PMD:
1042*4882a593Smuzhiyun 		switch (w->shift) {
1043*4882a593Smuzhiyun 		case ARIZONA_OUT1L_ENA_SHIFT:
1044*4882a593Smuzhiyun 		case ARIZONA_OUT1R_ENA_SHIFT:
1045*4882a593Smuzhiyun 		case ARIZONA_OUT2L_ENA_SHIFT:
1046*4882a593Smuzhiyun 		case ARIZONA_OUT2R_ENA_SHIFT:
1047*4882a593Smuzhiyun 		case ARIZONA_OUT3L_ENA_SHIFT:
1048*4882a593Smuzhiyun 		case ARIZONA_OUT3R_ENA_SHIFT:
1049*4882a593Smuzhiyun 		case ARIZONA_OUT4L_ENA_SHIFT:
1050*4882a593Smuzhiyun 		case ARIZONA_OUT4R_ENA_SHIFT:
1051*4882a593Smuzhiyun 			priv->out_down_pending--;
1052*4882a593Smuzhiyun 			if (!priv->out_down_pending && priv->out_down_delay) {
1053*4882a593Smuzhiyun 				dev_dbg(component->dev, "Power down delay: %d\n",
1054*4882a593Smuzhiyun 					priv->out_down_delay);
1055*4882a593Smuzhiyun 				msleep(priv->out_down_delay);
1056*4882a593Smuzhiyun 				priv->out_down_delay = 0;
1057*4882a593Smuzhiyun 			}
1058*4882a593Smuzhiyun 			break;
1059*4882a593Smuzhiyun 		default:
1060*4882a593Smuzhiyun 			break;
1061*4882a593Smuzhiyun 		}
1062*4882a593Smuzhiyun 		break;
1063*4882a593Smuzhiyun 	default:
1064*4882a593Smuzhiyun 		break;
1065*4882a593Smuzhiyun 	}
1066*4882a593Smuzhiyun 
1067*4882a593Smuzhiyun 	return 0;
1068*4882a593Smuzhiyun }
1069*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_out_ev);
1070*4882a593Smuzhiyun 
arizona_hp_ev(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)1071*4882a593Smuzhiyun int arizona_hp_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
1072*4882a593Smuzhiyun 		  int event)
1073*4882a593Smuzhiyun {
1074*4882a593Smuzhiyun 	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
1075*4882a593Smuzhiyun 	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
1076*4882a593Smuzhiyun 	struct arizona *arizona = priv->arizona;
1077*4882a593Smuzhiyun 	unsigned int mask = 1 << w->shift;
1078*4882a593Smuzhiyun 	unsigned int val;
1079*4882a593Smuzhiyun 
1080*4882a593Smuzhiyun 	switch (event) {
1081*4882a593Smuzhiyun 	case SND_SOC_DAPM_POST_PMU:
1082*4882a593Smuzhiyun 		val = mask;
1083*4882a593Smuzhiyun 		break;
1084*4882a593Smuzhiyun 	case SND_SOC_DAPM_PRE_PMD:
1085*4882a593Smuzhiyun 		val = 0;
1086*4882a593Smuzhiyun 		break;
1087*4882a593Smuzhiyun 	case SND_SOC_DAPM_PRE_PMU:
1088*4882a593Smuzhiyun 	case SND_SOC_DAPM_POST_PMD:
1089*4882a593Smuzhiyun 		return arizona_out_ev(w, kcontrol, event);
1090*4882a593Smuzhiyun 	default:
1091*4882a593Smuzhiyun 		return -EINVAL;
1092*4882a593Smuzhiyun 	}
1093*4882a593Smuzhiyun 
1094*4882a593Smuzhiyun 	/* Store the desired state for the HP outputs */
1095*4882a593Smuzhiyun 	priv->arizona->hp_ena &= ~mask;
1096*4882a593Smuzhiyun 	priv->arizona->hp_ena |= val;
1097*4882a593Smuzhiyun 
1098*4882a593Smuzhiyun 	/* Force off if HPDET clamp is active */
1099*4882a593Smuzhiyun 	if (priv->arizona->hpdet_clamp)
1100*4882a593Smuzhiyun 		val = 0;
1101*4882a593Smuzhiyun 
1102*4882a593Smuzhiyun 	regmap_update_bits_async(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1,
1103*4882a593Smuzhiyun 				 mask, val);
1104*4882a593Smuzhiyun 
1105*4882a593Smuzhiyun 	return arizona_out_ev(w, kcontrol, event);
1106*4882a593Smuzhiyun }
1107*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_hp_ev);
1108*4882a593Smuzhiyun 
arizona_dvfs_enable(struct snd_soc_component * component)1109*4882a593Smuzhiyun static int arizona_dvfs_enable(struct snd_soc_component *component)
1110*4882a593Smuzhiyun {
1111*4882a593Smuzhiyun 	const struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
1112*4882a593Smuzhiyun 	struct arizona *arizona = priv->arizona;
1113*4882a593Smuzhiyun 	int ret;
1114*4882a593Smuzhiyun 
1115*4882a593Smuzhiyun 	ret = regulator_set_voltage(arizona->dcvdd, 1800000, 1800000);
1116*4882a593Smuzhiyun 	if (ret) {
1117*4882a593Smuzhiyun 		dev_err(component->dev, "Failed to boost DCVDD: %d\n", ret);
1118*4882a593Smuzhiyun 		return ret;
1119*4882a593Smuzhiyun 	}
1120*4882a593Smuzhiyun 
1121*4882a593Smuzhiyun 	ret = regmap_update_bits(arizona->regmap,
1122*4882a593Smuzhiyun 				 ARIZONA_DYNAMIC_FREQUENCY_SCALING_1,
1123*4882a593Smuzhiyun 				 ARIZONA_SUBSYS_MAX_FREQ,
1124*4882a593Smuzhiyun 				 ARIZONA_SUBSYS_MAX_FREQ);
1125*4882a593Smuzhiyun 	if (ret) {
1126*4882a593Smuzhiyun 		dev_err(component->dev, "Failed to enable subsys max: %d\n", ret);
1127*4882a593Smuzhiyun 		regulator_set_voltage(arizona->dcvdd, 1200000, 1800000);
1128*4882a593Smuzhiyun 		return ret;
1129*4882a593Smuzhiyun 	}
1130*4882a593Smuzhiyun 
1131*4882a593Smuzhiyun 	return 0;
1132*4882a593Smuzhiyun }
1133*4882a593Smuzhiyun 
arizona_dvfs_disable(struct snd_soc_component * component)1134*4882a593Smuzhiyun static int arizona_dvfs_disable(struct snd_soc_component *component)
1135*4882a593Smuzhiyun {
1136*4882a593Smuzhiyun 	const struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
1137*4882a593Smuzhiyun 	struct arizona *arizona = priv->arizona;
1138*4882a593Smuzhiyun 	int ret;
1139*4882a593Smuzhiyun 
1140*4882a593Smuzhiyun 	ret = regmap_update_bits(arizona->regmap,
1141*4882a593Smuzhiyun 				 ARIZONA_DYNAMIC_FREQUENCY_SCALING_1,
1142*4882a593Smuzhiyun 				 ARIZONA_SUBSYS_MAX_FREQ, 0);
1143*4882a593Smuzhiyun 	if (ret) {
1144*4882a593Smuzhiyun 		dev_err(component->dev, "Failed to disable subsys max: %d\n", ret);
1145*4882a593Smuzhiyun 		return ret;
1146*4882a593Smuzhiyun 	}
1147*4882a593Smuzhiyun 
1148*4882a593Smuzhiyun 	ret = regulator_set_voltage(arizona->dcvdd, 1200000, 1800000);
1149*4882a593Smuzhiyun 	if (ret) {
1150*4882a593Smuzhiyun 		dev_err(component->dev, "Failed to unboost DCVDD: %d\n", ret);
1151*4882a593Smuzhiyun 		return ret;
1152*4882a593Smuzhiyun 	}
1153*4882a593Smuzhiyun 
1154*4882a593Smuzhiyun 	return 0;
1155*4882a593Smuzhiyun }
1156*4882a593Smuzhiyun 
arizona_dvfs_up(struct snd_soc_component * component,unsigned int flags)1157*4882a593Smuzhiyun int arizona_dvfs_up(struct snd_soc_component *component, unsigned int flags)
1158*4882a593Smuzhiyun {
1159*4882a593Smuzhiyun 	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
1160*4882a593Smuzhiyun 	int ret = 0;
1161*4882a593Smuzhiyun 
1162*4882a593Smuzhiyun 	mutex_lock(&priv->dvfs_lock);
1163*4882a593Smuzhiyun 
1164*4882a593Smuzhiyun 	if (!priv->dvfs_cached && !priv->dvfs_reqs) {
1165*4882a593Smuzhiyun 		ret = arizona_dvfs_enable(component);
1166*4882a593Smuzhiyun 		if (ret)
1167*4882a593Smuzhiyun 			goto err;
1168*4882a593Smuzhiyun 	}
1169*4882a593Smuzhiyun 
1170*4882a593Smuzhiyun 	priv->dvfs_reqs |= flags;
1171*4882a593Smuzhiyun err:
1172*4882a593Smuzhiyun 	mutex_unlock(&priv->dvfs_lock);
1173*4882a593Smuzhiyun 	return ret;
1174*4882a593Smuzhiyun }
1175*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_dvfs_up);
1176*4882a593Smuzhiyun 
arizona_dvfs_down(struct snd_soc_component * component,unsigned int flags)1177*4882a593Smuzhiyun int arizona_dvfs_down(struct snd_soc_component *component, unsigned int flags)
1178*4882a593Smuzhiyun {
1179*4882a593Smuzhiyun 	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
1180*4882a593Smuzhiyun 	unsigned int old_reqs;
1181*4882a593Smuzhiyun 	int ret = 0;
1182*4882a593Smuzhiyun 
1183*4882a593Smuzhiyun 	mutex_lock(&priv->dvfs_lock);
1184*4882a593Smuzhiyun 
1185*4882a593Smuzhiyun 	old_reqs = priv->dvfs_reqs;
1186*4882a593Smuzhiyun 	priv->dvfs_reqs &= ~flags;
1187*4882a593Smuzhiyun 
1188*4882a593Smuzhiyun 	if (!priv->dvfs_cached && old_reqs && !priv->dvfs_reqs)
1189*4882a593Smuzhiyun 		ret = arizona_dvfs_disable(component);
1190*4882a593Smuzhiyun 
1191*4882a593Smuzhiyun 	mutex_unlock(&priv->dvfs_lock);
1192*4882a593Smuzhiyun 	return ret;
1193*4882a593Smuzhiyun }
1194*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_dvfs_down);
1195*4882a593Smuzhiyun 
arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)1196*4882a593Smuzhiyun int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w,
1197*4882a593Smuzhiyun 			   struct snd_kcontrol *kcontrol, int event)
1198*4882a593Smuzhiyun {
1199*4882a593Smuzhiyun 	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
1200*4882a593Smuzhiyun 	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
1201*4882a593Smuzhiyun 	int ret = 0;
1202*4882a593Smuzhiyun 
1203*4882a593Smuzhiyun 	mutex_lock(&priv->dvfs_lock);
1204*4882a593Smuzhiyun 
1205*4882a593Smuzhiyun 	switch (event) {
1206*4882a593Smuzhiyun 	case SND_SOC_DAPM_POST_PMU:
1207*4882a593Smuzhiyun 		if (priv->dvfs_reqs)
1208*4882a593Smuzhiyun 			ret = arizona_dvfs_enable(component);
1209*4882a593Smuzhiyun 
1210*4882a593Smuzhiyun 		priv->dvfs_cached = false;
1211*4882a593Smuzhiyun 		break;
1212*4882a593Smuzhiyun 	case SND_SOC_DAPM_PRE_PMD:
1213*4882a593Smuzhiyun 		/* We must ensure DVFS is disabled before the codec goes into
1214*4882a593Smuzhiyun 		 * suspend so that we are never in an illegal state of DVFS
1215*4882a593Smuzhiyun 		 * enabled without enough DCVDD
1216*4882a593Smuzhiyun 		 */
1217*4882a593Smuzhiyun 		priv->dvfs_cached = true;
1218*4882a593Smuzhiyun 
1219*4882a593Smuzhiyun 		if (priv->dvfs_reqs)
1220*4882a593Smuzhiyun 			ret = arizona_dvfs_disable(component);
1221*4882a593Smuzhiyun 		break;
1222*4882a593Smuzhiyun 	default:
1223*4882a593Smuzhiyun 		break;
1224*4882a593Smuzhiyun 	}
1225*4882a593Smuzhiyun 
1226*4882a593Smuzhiyun 	mutex_unlock(&priv->dvfs_lock);
1227*4882a593Smuzhiyun 	return ret;
1228*4882a593Smuzhiyun }
1229*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_dvfs_sysclk_ev);
1230*4882a593Smuzhiyun 
arizona_init_dvfs(struct arizona_priv * priv)1231*4882a593Smuzhiyun void arizona_init_dvfs(struct arizona_priv *priv)
1232*4882a593Smuzhiyun {
1233*4882a593Smuzhiyun 	mutex_init(&priv->dvfs_lock);
1234*4882a593Smuzhiyun }
1235*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_init_dvfs);
1236*4882a593Smuzhiyun 
arizona_anc_ev(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)1237*4882a593Smuzhiyun int arizona_anc_ev(struct snd_soc_dapm_widget *w,
1238*4882a593Smuzhiyun 		   struct snd_kcontrol *kcontrol,
1239*4882a593Smuzhiyun 		   int event)
1240*4882a593Smuzhiyun {
1241*4882a593Smuzhiyun 	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
1242*4882a593Smuzhiyun 	unsigned int val;
1243*4882a593Smuzhiyun 
1244*4882a593Smuzhiyun 	switch (event) {
1245*4882a593Smuzhiyun 	case SND_SOC_DAPM_POST_PMU:
1246*4882a593Smuzhiyun 		val = 1 << w->shift;
1247*4882a593Smuzhiyun 		break;
1248*4882a593Smuzhiyun 	case SND_SOC_DAPM_PRE_PMD:
1249*4882a593Smuzhiyun 		val = 1 << (w->shift + 1);
1250*4882a593Smuzhiyun 		break;
1251*4882a593Smuzhiyun 	default:
1252*4882a593Smuzhiyun 		return 0;
1253*4882a593Smuzhiyun 	}
1254*4882a593Smuzhiyun 
1255*4882a593Smuzhiyun 	snd_soc_component_write(component, ARIZONA_CLOCK_CONTROL, val);
1256*4882a593Smuzhiyun 
1257*4882a593Smuzhiyun 	return 0;
1258*4882a593Smuzhiyun }
1259*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_anc_ev);
1260*4882a593Smuzhiyun 
1261*4882a593Smuzhiyun static unsigned int arizona_opclk_ref_48k_rates[] = {
1262*4882a593Smuzhiyun 	6144000,
1263*4882a593Smuzhiyun 	12288000,
1264*4882a593Smuzhiyun 	24576000,
1265*4882a593Smuzhiyun 	49152000,
1266*4882a593Smuzhiyun };
1267*4882a593Smuzhiyun 
1268*4882a593Smuzhiyun static unsigned int arizona_opclk_ref_44k1_rates[] = {
1269*4882a593Smuzhiyun 	5644800,
1270*4882a593Smuzhiyun 	11289600,
1271*4882a593Smuzhiyun 	22579200,
1272*4882a593Smuzhiyun 	45158400,
1273*4882a593Smuzhiyun };
1274*4882a593Smuzhiyun 
arizona_set_opclk(struct snd_soc_component * component,unsigned int clk,unsigned int freq)1275*4882a593Smuzhiyun static int arizona_set_opclk(struct snd_soc_component *component,
1276*4882a593Smuzhiyun 			     unsigned int clk, unsigned int freq)
1277*4882a593Smuzhiyun {
1278*4882a593Smuzhiyun 	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
1279*4882a593Smuzhiyun 	unsigned int reg;
1280*4882a593Smuzhiyun 	unsigned int *rates;
1281*4882a593Smuzhiyun 	int ref, div, refclk;
1282*4882a593Smuzhiyun 
1283*4882a593Smuzhiyun 	switch (clk) {
1284*4882a593Smuzhiyun 	case ARIZONA_CLK_OPCLK:
1285*4882a593Smuzhiyun 		reg = ARIZONA_OUTPUT_SYSTEM_CLOCK;
1286*4882a593Smuzhiyun 		refclk = priv->sysclk;
1287*4882a593Smuzhiyun 		break;
1288*4882a593Smuzhiyun 	case ARIZONA_CLK_ASYNC_OPCLK:
1289*4882a593Smuzhiyun 		reg = ARIZONA_OUTPUT_ASYNC_CLOCK;
1290*4882a593Smuzhiyun 		refclk = priv->asyncclk;
1291*4882a593Smuzhiyun 		break;
1292*4882a593Smuzhiyun 	default:
1293*4882a593Smuzhiyun 		return -EINVAL;
1294*4882a593Smuzhiyun 	}
1295*4882a593Smuzhiyun 
1296*4882a593Smuzhiyun 	if (refclk % 8000)
1297*4882a593Smuzhiyun 		rates = arizona_opclk_ref_44k1_rates;
1298*4882a593Smuzhiyun 	else
1299*4882a593Smuzhiyun 		rates = arizona_opclk_ref_48k_rates;
1300*4882a593Smuzhiyun 
1301*4882a593Smuzhiyun 	for (ref = 0; ref < ARRAY_SIZE(arizona_opclk_ref_48k_rates) &&
1302*4882a593Smuzhiyun 	     rates[ref] <= refclk; ref++) {
1303*4882a593Smuzhiyun 		div = 1;
1304*4882a593Smuzhiyun 		while (rates[ref] / div >= freq && div < 32) {
1305*4882a593Smuzhiyun 			if (rates[ref] / div == freq) {
1306*4882a593Smuzhiyun 				dev_dbg(component->dev, "Configured %dHz OPCLK\n",
1307*4882a593Smuzhiyun 					freq);
1308*4882a593Smuzhiyun 				snd_soc_component_update_bits(component, reg,
1309*4882a593Smuzhiyun 						    ARIZONA_OPCLK_DIV_MASK |
1310*4882a593Smuzhiyun 						    ARIZONA_OPCLK_SEL_MASK,
1311*4882a593Smuzhiyun 						    (div <<
1312*4882a593Smuzhiyun 						     ARIZONA_OPCLK_DIV_SHIFT) |
1313*4882a593Smuzhiyun 						    ref);
1314*4882a593Smuzhiyun 				return 0;
1315*4882a593Smuzhiyun 			}
1316*4882a593Smuzhiyun 			div++;
1317*4882a593Smuzhiyun 		}
1318*4882a593Smuzhiyun 	}
1319*4882a593Smuzhiyun 
1320*4882a593Smuzhiyun 	dev_err(component->dev, "Unable to generate %dHz OPCLK\n", freq);
1321*4882a593Smuzhiyun 	return -EINVAL;
1322*4882a593Smuzhiyun }
1323*4882a593Smuzhiyun 
arizona_clk_ev(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)1324*4882a593Smuzhiyun int arizona_clk_ev(struct snd_soc_dapm_widget *w,
1325*4882a593Smuzhiyun 		   struct snd_kcontrol *kcontrol, int event)
1326*4882a593Smuzhiyun {
1327*4882a593Smuzhiyun 	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
1328*4882a593Smuzhiyun 	struct arizona *arizona = dev_get_drvdata(component->dev->parent);
1329*4882a593Smuzhiyun 	unsigned int val;
1330*4882a593Smuzhiyun 	int clk_idx;
1331*4882a593Smuzhiyun 	int ret;
1332*4882a593Smuzhiyun 
1333*4882a593Smuzhiyun 	ret = regmap_read(arizona->regmap, w->reg, &val);
1334*4882a593Smuzhiyun 	if (ret) {
1335*4882a593Smuzhiyun 		dev_err(component->dev, "Failed to check clock source: %d\n", ret);
1336*4882a593Smuzhiyun 		return ret;
1337*4882a593Smuzhiyun 	}
1338*4882a593Smuzhiyun 
1339*4882a593Smuzhiyun 	val = (val & ARIZONA_SYSCLK_SRC_MASK) >> ARIZONA_SYSCLK_SRC_SHIFT;
1340*4882a593Smuzhiyun 
1341*4882a593Smuzhiyun 	switch (val) {
1342*4882a593Smuzhiyun 	case ARIZONA_CLK_SRC_MCLK1:
1343*4882a593Smuzhiyun 		clk_idx = ARIZONA_MCLK1;
1344*4882a593Smuzhiyun 		break;
1345*4882a593Smuzhiyun 	case ARIZONA_CLK_SRC_MCLK2:
1346*4882a593Smuzhiyun 		clk_idx = ARIZONA_MCLK2;
1347*4882a593Smuzhiyun 		break;
1348*4882a593Smuzhiyun 	default:
1349*4882a593Smuzhiyun 		return 0;
1350*4882a593Smuzhiyun 	}
1351*4882a593Smuzhiyun 
1352*4882a593Smuzhiyun 	switch (event) {
1353*4882a593Smuzhiyun 	case SND_SOC_DAPM_PRE_PMU:
1354*4882a593Smuzhiyun 		return clk_prepare_enable(arizona->mclk[clk_idx]);
1355*4882a593Smuzhiyun 	case SND_SOC_DAPM_POST_PMD:
1356*4882a593Smuzhiyun 		clk_disable_unprepare(arizona->mclk[clk_idx]);
1357*4882a593Smuzhiyun 		return 0;
1358*4882a593Smuzhiyun 	default:
1359*4882a593Smuzhiyun 		return 0;
1360*4882a593Smuzhiyun 	}
1361*4882a593Smuzhiyun }
1362*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_clk_ev);
1363*4882a593Smuzhiyun 
arizona_set_sysclk(struct snd_soc_component * component,int clk_id,int source,unsigned int freq,int dir)1364*4882a593Smuzhiyun int arizona_set_sysclk(struct snd_soc_component *component, int clk_id,
1365*4882a593Smuzhiyun 		       int source, unsigned int freq, int dir)
1366*4882a593Smuzhiyun {
1367*4882a593Smuzhiyun 	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
1368*4882a593Smuzhiyun 	struct arizona *arizona = priv->arizona;
1369*4882a593Smuzhiyun 	char *name;
1370*4882a593Smuzhiyun 	unsigned int reg;
1371*4882a593Smuzhiyun 	unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK;
1372*4882a593Smuzhiyun 	unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT;
1373*4882a593Smuzhiyun 	int *clk;
1374*4882a593Smuzhiyun 
1375*4882a593Smuzhiyun 	switch (clk_id) {
1376*4882a593Smuzhiyun 	case ARIZONA_CLK_SYSCLK:
1377*4882a593Smuzhiyun 		name = "SYSCLK";
1378*4882a593Smuzhiyun 		reg = ARIZONA_SYSTEM_CLOCK_1;
1379*4882a593Smuzhiyun 		clk = &priv->sysclk;
1380*4882a593Smuzhiyun 		mask |= ARIZONA_SYSCLK_FRAC;
1381*4882a593Smuzhiyun 		break;
1382*4882a593Smuzhiyun 	case ARIZONA_CLK_ASYNCCLK:
1383*4882a593Smuzhiyun 		name = "ASYNCCLK";
1384*4882a593Smuzhiyun 		reg = ARIZONA_ASYNC_CLOCK_1;
1385*4882a593Smuzhiyun 		clk = &priv->asyncclk;
1386*4882a593Smuzhiyun 		break;
1387*4882a593Smuzhiyun 	case ARIZONA_CLK_OPCLK:
1388*4882a593Smuzhiyun 	case ARIZONA_CLK_ASYNC_OPCLK:
1389*4882a593Smuzhiyun 		return arizona_set_opclk(component, clk_id, freq);
1390*4882a593Smuzhiyun 	default:
1391*4882a593Smuzhiyun 		return -EINVAL;
1392*4882a593Smuzhiyun 	}
1393*4882a593Smuzhiyun 
1394*4882a593Smuzhiyun 	switch (freq) {
1395*4882a593Smuzhiyun 	case  5644800:
1396*4882a593Smuzhiyun 	case  6144000:
1397*4882a593Smuzhiyun 		break;
1398*4882a593Smuzhiyun 	case 11289600:
1399*4882a593Smuzhiyun 	case 12288000:
1400*4882a593Smuzhiyun 		val |= ARIZONA_CLK_12MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
1401*4882a593Smuzhiyun 		break;
1402*4882a593Smuzhiyun 	case 22579200:
1403*4882a593Smuzhiyun 	case 24576000:
1404*4882a593Smuzhiyun 		val |= ARIZONA_CLK_24MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
1405*4882a593Smuzhiyun 		break;
1406*4882a593Smuzhiyun 	case 45158400:
1407*4882a593Smuzhiyun 	case 49152000:
1408*4882a593Smuzhiyun 		val |= ARIZONA_CLK_49MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
1409*4882a593Smuzhiyun 		break;
1410*4882a593Smuzhiyun 	case 67737600:
1411*4882a593Smuzhiyun 	case 73728000:
1412*4882a593Smuzhiyun 		val |= ARIZONA_CLK_73MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
1413*4882a593Smuzhiyun 		break;
1414*4882a593Smuzhiyun 	case 90316800:
1415*4882a593Smuzhiyun 	case 98304000:
1416*4882a593Smuzhiyun 		val |= ARIZONA_CLK_98MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
1417*4882a593Smuzhiyun 		break;
1418*4882a593Smuzhiyun 	case 135475200:
1419*4882a593Smuzhiyun 	case 147456000:
1420*4882a593Smuzhiyun 		val |= ARIZONA_CLK_147MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
1421*4882a593Smuzhiyun 		break;
1422*4882a593Smuzhiyun 	case 0:
1423*4882a593Smuzhiyun 		dev_dbg(arizona->dev, "%s cleared\n", name);
1424*4882a593Smuzhiyun 		*clk = freq;
1425*4882a593Smuzhiyun 		return 0;
1426*4882a593Smuzhiyun 	default:
1427*4882a593Smuzhiyun 		return -EINVAL;
1428*4882a593Smuzhiyun 	}
1429*4882a593Smuzhiyun 
1430*4882a593Smuzhiyun 	*clk = freq;
1431*4882a593Smuzhiyun 
1432*4882a593Smuzhiyun 	if (freq % 6144000)
1433*4882a593Smuzhiyun 		val |= ARIZONA_SYSCLK_FRAC;
1434*4882a593Smuzhiyun 
1435*4882a593Smuzhiyun 	dev_dbg(arizona->dev, "%s set to %uHz", name, freq);
1436*4882a593Smuzhiyun 
1437*4882a593Smuzhiyun 	return regmap_update_bits(arizona->regmap, reg, mask, val);
1438*4882a593Smuzhiyun }
1439*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_set_sysclk);
1440*4882a593Smuzhiyun 
arizona_set_fmt(struct snd_soc_dai * dai,unsigned int fmt)1441*4882a593Smuzhiyun static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
1442*4882a593Smuzhiyun {
1443*4882a593Smuzhiyun 	struct snd_soc_component *component = dai->component;
1444*4882a593Smuzhiyun 	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
1445*4882a593Smuzhiyun 	struct arizona *arizona = priv->arizona;
1446*4882a593Smuzhiyun 	int lrclk, bclk, mode, base;
1447*4882a593Smuzhiyun 
1448*4882a593Smuzhiyun 	base = dai->driver->base;
1449*4882a593Smuzhiyun 
1450*4882a593Smuzhiyun 	lrclk = 0;
1451*4882a593Smuzhiyun 	bclk = 0;
1452*4882a593Smuzhiyun 
1453*4882a593Smuzhiyun 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
1454*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_DSP_A:
1455*4882a593Smuzhiyun 		mode = ARIZONA_FMT_DSP_MODE_A;
1456*4882a593Smuzhiyun 		break;
1457*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_DSP_B:
1458*4882a593Smuzhiyun 		if ((fmt & SND_SOC_DAIFMT_MASTER_MASK)
1459*4882a593Smuzhiyun 				!= SND_SOC_DAIFMT_CBM_CFM) {
1460*4882a593Smuzhiyun 			arizona_aif_err(dai, "DSP_B not valid in slave mode\n");
1461*4882a593Smuzhiyun 			return -EINVAL;
1462*4882a593Smuzhiyun 		}
1463*4882a593Smuzhiyun 		mode = ARIZONA_FMT_DSP_MODE_B;
1464*4882a593Smuzhiyun 		break;
1465*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_I2S:
1466*4882a593Smuzhiyun 		mode = ARIZONA_FMT_I2S_MODE;
1467*4882a593Smuzhiyun 		break;
1468*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_LEFT_J:
1469*4882a593Smuzhiyun 		if ((fmt & SND_SOC_DAIFMT_MASTER_MASK)
1470*4882a593Smuzhiyun 				!= SND_SOC_DAIFMT_CBM_CFM) {
1471*4882a593Smuzhiyun 			arizona_aif_err(dai, "LEFT_J not valid in slave mode\n");
1472*4882a593Smuzhiyun 			return -EINVAL;
1473*4882a593Smuzhiyun 		}
1474*4882a593Smuzhiyun 		mode = ARIZONA_FMT_LEFT_JUSTIFIED_MODE;
1475*4882a593Smuzhiyun 		break;
1476*4882a593Smuzhiyun 	default:
1477*4882a593Smuzhiyun 		arizona_aif_err(dai, "Unsupported DAI format %d\n",
1478*4882a593Smuzhiyun 				fmt & SND_SOC_DAIFMT_FORMAT_MASK);
1479*4882a593Smuzhiyun 		return -EINVAL;
1480*4882a593Smuzhiyun 	}
1481*4882a593Smuzhiyun 
1482*4882a593Smuzhiyun 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
1483*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_CBS_CFS:
1484*4882a593Smuzhiyun 		break;
1485*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_CBS_CFM:
1486*4882a593Smuzhiyun 		lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
1487*4882a593Smuzhiyun 		break;
1488*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_CBM_CFS:
1489*4882a593Smuzhiyun 		bclk |= ARIZONA_AIF1_BCLK_MSTR;
1490*4882a593Smuzhiyun 		break;
1491*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_CBM_CFM:
1492*4882a593Smuzhiyun 		bclk |= ARIZONA_AIF1_BCLK_MSTR;
1493*4882a593Smuzhiyun 		lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
1494*4882a593Smuzhiyun 		break;
1495*4882a593Smuzhiyun 	default:
1496*4882a593Smuzhiyun 		arizona_aif_err(dai, "Unsupported master mode %d\n",
1497*4882a593Smuzhiyun 				fmt & SND_SOC_DAIFMT_MASTER_MASK);
1498*4882a593Smuzhiyun 		return -EINVAL;
1499*4882a593Smuzhiyun 	}
1500*4882a593Smuzhiyun 
1501*4882a593Smuzhiyun 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
1502*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_NB_NF:
1503*4882a593Smuzhiyun 		break;
1504*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_IB_IF:
1505*4882a593Smuzhiyun 		bclk |= ARIZONA_AIF1_BCLK_INV;
1506*4882a593Smuzhiyun 		lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
1507*4882a593Smuzhiyun 		break;
1508*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_IB_NF:
1509*4882a593Smuzhiyun 		bclk |= ARIZONA_AIF1_BCLK_INV;
1510*4882a593Smuzhiyun 		break;
1511*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_NB_IF:
1512*4882a593Smuzhiyun 		lrclk |= ARIZONA_AIF1TX_LRCLK_INV;
1513*4882a593Smuzhiyun 		break;
1514*4882a593Smuzhiyun 	default:
1515*4882a593Smuzhiyun 		return -EINVAL;
1516*4882a593Smuzhiyun 	}
1517*4882a593Smuzhiyun 
1518*4882a593Smuzhiyun 	regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_BCLK_CTRL,
1519*4882a593Smuzhiyun 				 ARIZONA_AIF1_BCLK_INV |
1520*4882a593Smuzhiyun 				 ARIZONA_AIF1_BCLK_MSTR,
1521*4882a593Smuzhiyun 				 bclk);
1522*4882a593Smuzhiyun 	regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_TX_PIN_CTRL,
1523*4882a593Smuzhiyun 				 ARIZONA_AIF1TX_LRCLK_INV |
1524*4882a593Smuzhiyun 				 ARIZONA_AIF1TX_LRCLK_MSTR, lrclk);
1525*4882a593Smuzhiyun 	regmap_update_bits_async(arizona->regmap,
1526*4882a593Smuzhiyun 				 base + ARIZONA_AIF_RX_PIN_CTRL,
1527*4882a593Smuzhiyun 				 ARIZONA_AIF1RX_LRCLK_INV |
1528*4882a593Smuzhiyun 				 ARIZONA_AIF1RX_LRCLK_MSTR, lrclk);
1529*4882a593Smuzhiyun 	regmap_update_bits(arizona->regmap, base + ARIZONA_AIF_FORMAT,
1530*4882a593Smuzhiyun 			   ARIZONA_AIF1_FMT_MASK, mode);
1531*4882a593Smuzhiyun 
1532*4882a593Smuzhiyun 	return 0;
1533*4882a593Smuzhiyun }
1534*4882a593Smuzhiyun 
1535*4882a593Smuzhiyun static const int arizona_48k_bclk_rates[] = {
1536*4882a593Smuzhiyun 	-1,
1537*4882a593Smuzhiyun 	48000,
1538*4882a593Smuzhiyun 	64000,
1539*4882a593Smuzhiyun 	96000,
1540*4882a593Smuzhiyun 	128000,
1541*4882a593Smuzhiyun 	192000,
1542*4882a593Smuzhiyun 	256000,
1543*4882a593Smuzhiyun 	384000,
1544*4882a593Smuzhiyun 	512000,
1545*4882a593Smuzhiyun 	768000,
1546*4882a593Smuzhiyun 	1024000,
1547*4882a593Smuzhiyun 	1536000,
1548*4882a593Smuzhiyun 	2048000,
1549*4882a593Smuzhiyun 	3072000,
1550*4882a593Smuzhiyun 	4096000,
1551*4882a593Smuzhiyun 	6144000,
1552*4882a593Smuzhiyun 	8192000,
1553*4882a593Smuzhiyun 	12288000,
1554*4882a593Smuzhiyun 	24576000,
1555*4882a593Smuzhiyun };
1556*4882a593Smuzhiyun 
1557*4882a593Smuzhiyun static const int arizona_44k1_bclk_rates[] = {
1558*4882a593Smuzhiyun 	-1,
1559*4882a593Smuzhiyun 	44100,
1560*4882a593Smuzhiyun 	58800,
1561*4882a593Smuzhiyun 	88200,
1562*4882a593Smuzhiyun 	117600,
1563*4882a593Smuzhiyun 	177640,
1564*4882a593Smuzhiyun 	235200,
1565*4882a593Smuzhiyun 	352800,
1566*4882a593Smuzhiyun 	470400,
1567*4882a593Smuzhiyun 	705600,
1568*4882a593Smuzhiyun 	940800,
1569*4882a593Smuzhiyun 	1411200,
1570*4882a593Smuzhiyun 	1881600,
1571*4882a593Smuzhiyun 	2822400,
1572*4882a593Smuzhiyun 	3763200,
1573*4882a593Smuzhiyun 	5644800,
1574*4882a593Smuzhiyun 	7526400,
1575*4882a593Smuzhiyun 	11289600,
1576*4882a593Smuzhiyun 	22579200,
1577*4882a593Smuzhiyun };
1578*4882a593Smuzhiyun 
1579*4882a593Smuzhiyun static const unsigned int arizona_sr_vals[] = {
1580*4882a593Smuzhiyun 	0,
1581*4882a593Smuzhiyun 	12000,
1582*4882a593Smuzhiyun 	24000,
1583*4882a593Smuzhiyun 	48000,
1584*4882a593Smuzhiyun 	96000,
1585*4882a593Smuzhiyun 	192000,
1586*4882a593Smuzhiyun 	384000,
1587*4882a593Smuzhiyun 	768000,
1588*4882a593Smuzhiyun 	0,
1589*4882a593Smuzhiyun 	11025,
1590*4882a593Smuzhiyun 	22050,
1591*4882a593Smuzhiyun 	44100,
1592*4882a593Smuzhiyun 	88200,
1593*4882a593Smuzhiyun 	176400,
1594*4882a593Smuzhiyun 	352800,
1595*4882a593Smuzhiyun 	705600,
1596*4882a593Smuzhiyun 	4000,
1597*4882a593Smuzhiyun 	8000,
1598*4882a593Smuzhiyun 	16000,
1599*4882a593Smuzhiyun 	32000,
1600*4882a593Smuzhiyun 	64000,
1601*4882a593Smuzhiyun 	128000,
1602*4882a593Smuzhiyun 	256000,
1603*4882a593Smuzhiyun 	512000,
1604*4882a593Smuzhiyun };
1605*4882a593Smuzhiyun 
1606*4882a593Smuzhiyun #define ARIZONA_48K_RATE_MASK	0x0F003E
1607*4882a593Smuzhiyun #define ARIZONA_44K1_RATE_MASK	0x003E00
1608*4882a593Smuzhiyun #define ARIZONA_RATE_MASK	(ARIZONA_48K_RATE_MASK | ARIZONA_44K1_RATE_MASK)
1609*4882a593Smuzhiyun 
1610*4882a593Smuzhiyun static const struct snd_pcm_hw_constraint_list arizona_constraint = {
1611*4882a593Smuzhiyun 	.count	= ARRAY_SIZE(arizona_sr_vals),
1612*4882a593Smuzhiyun 	.list	= arizona_sr_vals,
1613*4882a593Smuzhiyun };
1614*4882a593Smuzhiyun 
arizona_startup(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)1615*4882a593Smuzhiyun static int arizona_startup(struct snd_pcm_substream *substream,
1616*4882a593Smuzhiyun 			   struct snd_soc_dai *dai)
1617*4882a593Smuzhiyun {
1618*4882a593Smuzhiyun 	struct snd_soc_component *component = dai->component;
1619*4882a593Smuzhiyun 	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
1620*4882a593Smuzhiyun 	struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
1621*4882a593Smuzhiyun 	unsigned int base_rate;
1622*4882a593Smuzhiyun 
1623*4882a593Smuzhiyun 	if (!substream->runtime)
1624*4882a593Smuzhiyun 		return 0;
1625*4882a593Smuzhiyun 
1626*4882a593Smuzhiyun 	switch (dai_priv->clk) {
1627*4882a593Smuzhiyun 	case ARIZONA_CLK_SYSCLK:
1628*4882a593Smuzhiyun 		base_rate = priv->sysclk;
1629*4882a593Smuzhiyun 		break;
1630*4882a593Smuzhiyun 	case ARIZONA_CLK_ASYNCCLK:
1631*4882a593Smuzhiyun 		base_rate = priv->asyncclk;
1632*4882a593Smuzhiyun 		break;
1633*4882a593Smuzhiyun 	default:
1634*4882a593Smuzhiyun 		return 0;
1635*4882a593Smuzhiyun 	}
1636*4882a593Smuzhiyun 
1637*4882a593Smuzhiyun 	if (base_rate == 0)
1638*4882a593Smuzhiyun 		dai_priv->constraint.mask = ARIZONA_RATE_MASK;
1639*4882a593Smuzhiyun 	else if (base_rate % 8000)
1640*4882a593Smuzhiyun 		dai_priv->constraint.mask = ARIZONA_44K1_RATE_MASK;
1641*4882a593Smuzhiyun 	else
1642*4882a593Smuzhiyun 		dai_priv->constraint.mask = ARIZONA_48K_RATE_MASK;
1643*4882a593Smuzhiyun 
1644*4882a593Smuzhiyun 	return snd_pcm_hw_constraint_list(substream->runtime, 0,
1645*4882a593Smuzhiyun 					  SNDRV_PCM_HW_PARAM_RATE,
1646*4882a593Smuzhiyun 					  &dai_priv->constraint);
1647*4882a593Smuzhiyun }
1648*4882a593Smuzhiyun 
arizona_wm5102_set_dac_comp(struct snd_soc_component * component,unsigned int rate)1649*4882a593Smuzhiyun static void arizona_wm5102_set_dac_comp(struct snd_soc_component *component,
1650*4882a593Smuzhiyun 					unsigned int rate)
1651*4882a593Smuzhiyun {
1652*4882a593Smuzhiyun 	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
1653*4882a593Smuzhiyun 	struct arizona *arizona = priv->arizona;
1654*4882a593Smuzhiyun 	struct reg_sequence dac_comp[] = {
1655*4882a593Smuzhiyun 		{ 0x80, 0x3 },
1656*4882a593Smuzhiyun 		{ ARIZONA_DAC_COMP_1, 0 },
1657*4882a593Smuzhiyun 		{ ARIZONA_DAC_COMP_2, 0 },
1658*4882a593Smuzhiyun 		{ 0x80, 0x0 },
1659*4882a593Smuzhiyun 	};
1660*4882a593Smuzhiyun 
1661*4882a593Smuzhiyun 	mutex_lock(&arizona->dac_comp_lock);
1662*4882a593Smuzhiyun 
1663*4882a593Smuzhiyun 	dac_comp[1].def = arizona->dac_comp_coeff;
1664*4882a593Smuzhiyun 	if (rate >= 176400)
1665*4882a593Smuzhiyun 		dac_comp[2].def = arizona->dac_comp_enabled;
1666*4882a593Smuzhiyun 
1667*4882a593Smuzhiyun 	mutex_unlock(&arizona->dac_comp_lock);
1668*4882a593Smuzhiyun 
1669*4882a593Smuzhiyun 	regmap_multi_reg_write(arizona->regmap,
1670*4882a593Smuzhiyun 			       dac_comp,
1671*4882a593Smuzhiyun 			       ARRAY_SIZE(dac_comp));
1672*4882a593Smuzhiyun }
1673*4882a593Smuzhiyun 
arizona_hw_params_rate(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)1674*4882a593Smuzhiyun static int arizona_hw_params_rate(struct snd_pcm_substream *substream,
1675*4882a593Smuzhiyun 				  struct snd_pcm_hw_params *params,
1676*4882a593Smuzhiyun 				  struct snd_soc_dai *dai)
1677*4882a593Smuzhiyun {
1678*4882a593Smuzhiyun 	struct snd_soc_component *component = dai->component;
1679*4882a593Smuzhiyun 	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
1680*4882a593Smuzhiyun 	struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
1681*4882a593Smuzhiyun 	int base = dai->driver->base;
1682*4882a593Smuzhiyun 	int i, sr_val, ret;
1683*4882a593Smuzhiyun 
1684*4882a593Smuzhiyun 	/*
1685*4882a593Smuzhiyun 	 * We will need to be more flexible than this in future,
1686*4882a593Smuzhiyun 	 * currently we use a single sample rate for SYSCLK.
1687*4882a593Smuzhiyun 	 */
1688*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++)
1689*4882a593Smuzhiyun 		if (arizona_sr_vals[i] == params_rate(params))
1690*4882a593Smuzhiyun 			break;
1691*4882a593Smuzhiyun 	if (i == ARRAY_SIZE(arizona_sr_vals)) {
1692*4882a593Smuzhiyun 		arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1693*4882a593Smuzhiyun 				params_rate(params));
1694*4882a593Smuzhiyun 		return -EINVAL;
1695*4882a593Smuzhiyun 	}
1696*4882a593Smuzhiyun 	sr_val = i;
1697*4882a593Smuzhiyun 
1698*4882a593Smuzhiyun 	switch (priv->arizona->type) {
1699*4882a593Smuzhiyun 	case WM5102:
1700*4882a593Smuzhiyun 	case WM8997:
1701*4882a593Smuzhiyun 		if (arizona_sr_vals[sr_val] >= 88200)
1702*4882a593Smuzhiyun 			ret = arizona_dvfs_up(component, ARIZONA_DVFS_SR1_RQ);
1703*4882a593Smuzhiyun 		else
1704*4882a593Smuzhiyun 			ret = arizona_dvfs_down(component, ARIZONA_DVFS_SR1_RQ);
1705*4882a593Smuzhiyun 
1706*4882a593Smuzhiyun 		if (ret) {
1707*4882a593Smuzhiyun 			arizona_aif_err(dai, "Failed to change DVFS %d\n", ret);
1708*4882a593Smuzhiyun 			return ret;
1709*4882a593Smuzhiyun 		}
1710*4882a593Smuzhiyun 		break;
1711*4882a593Smuzhiyun 	default:
1712*4882a593Smuzhiyun 		break;
1713*4882a593Smuzhiyun 	}
1714*4882a593Smuzhiyun 
1715*4882a593Smuzhiyun 	switch (dai_priv->clk) {
1716*4882a593Smuzhiyun 	case ARIZONA_CLK_SYSCLK:
1717*4882a593Smuzhiyun 		switch (priv->arizona->type) {
1718*4882a593Smuzhiyun 		case WM5102:
1719*4882a593Smuzhiyun 			arizona_wm5102_set_dac_comp(component,
1720*4882a593Smuzhiyun 						    params_rate(params));
1721*4882a593Smuzhiyun 			break;
1722*4882a593Smuzhiyun 		default:
1723*4882a593Smuzhiyun 			break;
1724*4882a593Smuzhiyun 		}
1725*4882a593Smuzhiyun 
1726*4882a593Smuzhiyun 		snd_soc_component_update_bits(component, ARIZONA_SAMPLE_RATE_1,
1727*4882a593Smuzhiyun 					      ARIZONA_SAMPLE_RATE_1_MASK,
1728*4882a593Smuzhiyun 					      sr_val);
1729*4882a593Smuzhiyun 		if (base)
1730*4882a593Smuzhiyun 			snd_soc_component_update_bits(component,
1731*4882a593Smuzhiyun 					base + ARIZONA_AIF_RATE_CTRL,
1732*4882a593Smuzhiyun 					ARIZONA_AIF1_RATE_MASK, 0);
1733*4882a593Smuzhiyun 		break;
1734*4882a593Smuzhiyun 	case ARIZONA_CLK_ASYNCCLK:
1735*4882a593Smuzhiyun 		snd_soc_component_update_bits(component,
1736*4882a593Smuzhiyun 					      ARIZONA_ASYNC_SAMPLE_RATE_1,
1737*4882a593Smuzhiyun 					      ARIZONA_ASYNC_SAMPLE_RATE_1_MASK,
1738*4882a593Smuzhiyun 					      sr_val);
1739*4882a593Smuzhiyun 		if (base)
1740*4882a593Smuzhiyun 			snd_soc_component_update_bits(component,
1741*4882a593Smuzhiyun 					base + ARIZONA_AIF_RATE_CTRL,
1742*4882a593Smuzhiyun 					ARIZONA_AIF1_RATE_MASK,
1743*4882a593Smuzhiyun 					8 << ARIZONA_AIF1_RATE_SHIFT);
1744*4882a593Smuzhiyun 		break;
1745*4882a593Smuzhiyun 	default:
1746*4882a593Smuzhiyun 		arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk);
1747*4882a593Smuzhiyun 		return -EINVAL;
1748*4882a593Smuzhiyun 	}
1749*4882a593Smuzhiyun 
1750*4882a593Smuzhiyun 	return 0;
1751*4882a593Smuzhiyun }
1752*4882a593Smuzhiyun 
arizona_aif_cfg_changed(struct snd_soc_component * component,int base,int bclk,int lrclk,int frame)1753*4882a593Smuzhiyun static bool arizona_aif_cfg_changed(struct snd_soc_component *component,
1754*4882a593Smuzhiyun 				    int base, int bclk, int lrclk, int frame)
1755*4882a593Smuzhiyun {
1756*4882a593Smuzhiyun 	int val;
1757*4882a593Smuzhiyun 
1758*4882a593Smuzhiyun 	val = snd_soc_component_read(component, base + ARIZONA_AIF_BCLK_CTRL);
1759*4882a593Smuzhiyun 	if (bclk != (val & ARIZONA_AIF1_BCLK_FREQ_MASK))
1760*4882a593Smuzhiyun 		return true;
1761*4882a593Smuzhiyun 
1762*4882a593Smuzhiyun 	val = snd_soc_component_read(component, base + ARIZONA_AIF_TX_BCLK_RATE);
1763*4882a593Smuzhiyun 	if (lrclk != (val & ARIZONA_AIF1TX_BCPF_MASK))
1764*4882a593Smuzhiyun 		return true;
1765*4882a593Smuzhiyun 
1766*4882a593Smuzhiyun 	val = snd_soc_component_read(component, base + ARIZONA_AIF_FRAME_CTRL_1);
1767*4882a593Smuzhiyun 	if (frame != (val & (ARIZONA_AIF1TX_WL_MASK |
1768*4882a593Smuzhiyun 			     ARIZONA_AIF1TX_SLOT_LEN_MASK)))
1769*4882a593Smuzhiyun 		return true;
1770*4882a593Smuzhiyun 
1771*4882a593Smuzhiyun 	return false;
1772*4882a593Smuzhiyun }
1773*4882a593Smuzhiyun 
arizona_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)1774*4882a593Smuzhiyun static int arizona_hw_params(struct snd_pcm_substream *substream,
1775*4882a593Smuzhiyun 			     struct snd_pcm_hw_params *params,
1776*4882a593Smuzhiyun 			     struct snd_soc_dai *dai)
1777*4882a593Smuzhiyun {
1778*4882a593Smuzhiyun 	struct snd_soc_component *component = dai->component;
1779*4882a593Smuzhiyun 	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
1780*4882a593Smuzhiyun 	struct arizona *arizona = priv->arizona;
1781*4882a593Smuzhiyun 	int base = dai->driver->base;
1782*4882a593Smuzhiyun 	const int *rates;
1783*4882a593Smuzhiyun 	int i, ret, val;
1784*4882a593Smuzhiyun 	int channels = params_channels(params);
1785*4882a593Smuzhiyun 	int chan_limit = arizona->pdata.max_channels_clocked[dai->id - 1];
1786*4882a593Smuzhiyun 	int tdm_width = arizona->tdm_width[dai->id - 1];
1787*4882a593Smuzhiyun 	int tdm_slots = arizona->tdm_slots[dai->id - 1];
1788*4882a593Smuzhiyun 	int bclk, lrclk, wl, frame, bclk_target;
1789*4882a593Smuzhiyun 	bool reconfig;
1790*4882a593Smuzhiyun 	unsigned int aif_tx_state, aif_rx_state;
1791*4882a593Smuzhiyun 
1792*4882a593Smuzhiyun 	if (params_rate(params) % 4000)
1793*4882a593Smuzhiyun 		rates = &arizona_44k1_bclk_rates[0];
1794*4882a593Smuzhiyun 	else
1795*4882a593Smuzhiyun 		rates = &arizona_48k_bclk_rates[0];
1796*4882a593Smuzhiyun 
1797*4882a593Smuzhiyun 	wl = params_width(params);
1798*4882a593Smuzhiyun 
1799*4882a593Smuzhiyun 	if (tdm_slots) {
1800*4882a593Smuzhiyun 		arizona_aif_dbg(dai, "Configuring for %d %d bit TDM slots\n",
1801*4882a593Smuzhiyun 				tdm_slots, tdm_width);
1802*4882a593Smuzhiyun 		bclk_target = tdm_slots * tdm_width * params_rate(params);
1803*4882a593Smuzhiyun 		channels = tdm_slots;
1804*4882a593Smuzhiyun 	} else {
1805*4882a593Smuzhiyun 		bclk_target = snd_soc_params_to_bclk(params);
1806*4882a593Smuzhiyun 		tdm_width = wl;
1807*4882a593Smuzhiyun 	}
1808*4882a593Smuzhiyun 
1809*4882a593Smuzhiyun 	if (chan_limit && chan_limit < channels) {
1810*4882a593Smuzhiyun 		arizona_aif_dbg(dai, "Limiting to %d channels\n", chan_limit);
1811*4882a593Smuzhiyun 		bclk_target /= channels;
1812*4882a593Smuzhiyun 		bclk_target *= chan_limit;
1813*4882a593Smuzhiyun 	}
1814*4882a593Smuzhiyun 
1815*4882a593Smuzhiyun 	/* Force multiple of 2 channels for I2S mode */
1816*4882a593Smuzhiyun 	val = snd_soc_component_read(component, base + ARIZONA_AIF_FORMAT);
1817*4882a593Smuzhiyun 	val &= ARIZONA_AIF1_FMT_MASK;
1818*4882a593Smuzhiyun 	if ((channels & 1) && (val == ARIZONA_FMT_I2S_MODE)) {
1819*4882a593Smuzhiyun 		arizona_aif_dbg(dai, "Forcing stereo mode\n");
1820*4882a593Smuzhiyun 		bclk_target /= channels;
1821*4882a593Smuzhiyun 		bclk_target *= channels + 1;
1822*4882a593Smuzhiyun 	}
1823*4882a593Smuzhiyun 
1824*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
1825*4882a593Smuzhiyun 		if (rates[i] >= bclk_target &&
1826*4882a593Smuzhiyun 		    rates[i] % params_rate(params) == 0) {
1827*4882a593Smuzhiyun 			bclk = i;
1828*4882a593Smuzhiyun 			break;
1829*4882a593Smuzhiyun 		}
1830*4882a593Smuzhiyun 	}
1831*4882a593Smuzhiyun 	if (i == ARRAY_SIZE(arizona_44k1_bclk_rates)) {
1832*4882a593Smuzhiyun 		arizona_aif_err(dai, "Unsupported sample rate %dHz\n",
1833*4882a593Smuzhiyun 				params_rate(params));
1834*4882a593Smuzhiyun 		return -EINVAL;
1835*4882a593Smuzhiyun 	}
1836*4882a593Smuzhiyun 
1837*4882a593Smuzhiyun 	lrclk = rates[bclk] / params_rate(params);
1838*4882a593Smuzhiyun 
1839*4882a593Smuzhiyun 	arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n",
1840*4882a593Smuzhiyun 			rates[bclk], rates[bclk] / lrclk);
1841*4882a593Smuzhiyun 
1842*4882a593Smuzhiyun 	frame = wl << ARIZONA_AIF1TX_WL_SHIFT | tdm_width;
1843*4882a593Smuzhiyun 
1844*4882a593Smuzhiyun 	reconfig = arizona_aif_cfg_changed(component, base, bclk, lrclk, frame);
1845*4882a593Smuzhiyun 
1846*4882a593Smuzhiyun 	if (reconfig) {
1847*4882a593Smuzhiyun 		/* Save AIF TX/RX state */
1848*4882a593Smuzhiyun 		aif_tx_state = snd_soc_component_read(component,
1849*4882a593Smuzhiyun 					    base + ARIZONA_AIF_TX_ENABLES);
1850*4882a593Smuzhiyun 		aif_rx_state = snd_soc_component_read(component,
1851*4882a593Smuzhiyun 					    base + ARIZONA_AIF_RX_ENABLES);
1852*4882a593Smuzhiyun 		/* Disable AIF TX/RX before reconfiguring it */
1853*4882a593Smuzhiyun 		regmap_update_bits_async(arizona->regmap,
1854*4882a593Smuzhiyun 					 base + ARIZONA_AIF_TX_ENABLES,
1855*4882a593Smuzhiyun 					 0xff, 0x0);
1856*4882a593Smuzhiyun 		regmap_update_bits(arizona->regmap,
1857*4882a593Smuzhiyun 				   base + ARIZONA_AIF_RX_ENABLES, 0xff, 0x0);
1858*4882a593Smuzhiyun 	}
1859*4882a593Smuzhiyun 
1860*4882a593Smuzhiyun 	ret = arizona_hw_params_rate(substream, params, dai);
1861*4882a593Smuzhiyun 	if (ret != 0)
1862*4882a593Smuzhiyun 		goto restore_aif;
1863*4882a593Smuzhiyun 
1864*4882a593Smuzhiyun 	if (reconfig) {
1865*4882a593Smuzhiyun 		regmap_update_bits_async(arizona->regmap,
1866*4882a593Smuzhiyun 					 base + ARIZONA_AIF_BCLK_CTRL,
1867*4882a593Smuzhiyun 					 ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
1868*4882a593Smuzhiyun 		regmap_update_bits_async(arizona->regmap,
1869*4882a593Smuzhiyun 					 base + ARIZONA_AIF_TX_BCLK_RATE,
1870*4882a593Smuzhiyun 					 ARIZONA_AIF1TX_BCPF_MASK, lrclk);
1871*4882a593Smuzhiyun 		regmap_update_bits_async(arizona->regmap,
1872*4882a593Smuzhiyun 					 base + ARIZONA_AIF_RX_BCLK_RATE,
1873*4882a593Smuzhiyun 					 ARIZONA_AIF1RX_BCPF_MASK, lrclk);
1874*4882a593Smuzhiyun 		regmap_update_bits_async(arizona->regmap,
1875*4882a593Smuzhiyun 					 base + ARIZONA_AIF_FRAME_CTRL_1,
1876*4882a593Smuzhiyun 					 ARIZONA_AIF1TX_WL_MASK |
1877*4882a593Smuzhiyun 					 ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
1878*4882a593Smuzhiyun 		regmap_update_bits(arizona->regmap,
1879*4882a593Smuzhiyun 				   base + ARIZONA_AIF_FRAME_CTRL_2,
1880*4882a593Smuzhiyun 				   ARIZONA_AIF1RX_WL_MASK |
1881*4882a593Smuzhiyun 				   ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);
1882*4882a593Smuzhiyun 	}
1883*4882a593Smuzhiyun 
1884*4882a593Smuzhiyun restore_aif:
1885*4882a593Smuzhiyun 	if (reconfig) {
1886*4882a593Smuzhiyun 		/* Restore AIF TX/RX state */
1887*4882a593Smuzhiyun 		regmap_update_bits_async(arizona->regmap,
1888*4882a593Smuzhiyun 					 base + ARIZONA_AIF_TX_ENABLES,
1889*4882a593Smuzhiyun 					 0xff, aif_tx_state);
1890*4882a593Smuzhiyun 		regmap_update_bits(arizona->regmap,
1891*4882a593Smuzhiyun 				   base + ARIZONA_AIF_RX_ENABLES,
1892*4882a593Smuzhiyun 				   0xff, aif_rx_state);
1893*4882a593Smuzhiyun 	}
1894*4882a593Smuzhiyun 	return ret;
1895*4882a593Smuzhiyun }
1896*4882a593Smuzhiyun 
arizona_dai_clk_str(int clk_id)1897*4882a593Smuzhiyun static const char *arizona_dai_clk_str(int clk_id)
1898*4882a593Smuzhiyun {
1899*4882a593Smuzhiyun 	switch (clk_id) {
1900*4882a593Smuzhiyun 	case ARIZONA_CLK_SYSCLK:
1901*4882a593Smuzhiyun 		return "SYSCLK";
1902*4882a593Smuzhiyun 	case ARIZONA_CLK_ASYNCCLK:
1903*4882a593Smuzhiyun 		return "ASYNCCLK";
1904*4882a593Smuzhiyun 	default:
1905*4882a593Smuzhiyun 		return "Unknown clock";
1906*4882a593Smuzhiyun 	}
1907*4882a593Smuzhiyun }
1908*4882a593Smuzhiyun 
arizona_dai_set_sysclk(struct snd_soc_dai * dai,int clk_id,unsigned int freq,int dir)1909*4882a593Smuzhiyun static int arizona_dai_set_sysclk(struct snd_soc_dai *dai,
1910*4882a593Smuzhiyun 				  int clk_id, unsigned int freq, int dir)
1911*4882a593Smuzhiyun {
1912*4882a593Smuzhiyun 	struct snd_soc_component *component = dai->component;
1913*4882a593Smuzhiyun 	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
1914*4882a593Smuzhiyun 	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
1915*4882a593Smuzhiyun 	struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1];
1916*4882a593Smuzhiyun 	struct snd_soc_dapm_route routes[2];
1917*4882a593Smuzhiyun 
1918*4882a593Smuzhiyun 	switch (clk_id) {
1919*4882a593Smuzhiyun 	case ARIZONA_CLK_SYSCLK:
1920*4882a593Smuzhiyun 	case ARIZONA_CLK_ASYNCCLK:
1921*4882a593Smuzhiyun 		break;
1922*4882a593Smuzhiyun 	default:
1923*4882a593Smuzhiyun 		return -EINVAL;
1924*4882a593Smuzhiyun 	}
1925*4882a593Smuzhiyun 
1926*4882a593Smuzhiyun 	if (clk_id == dai_priv->clk)
1927*4882a593Smuzhiyun 		return 0;
1928*4882a593Smuzhiyun 
1929*4882a593Smuzhiyun 	if (snd_soc_dai_active(dai)) {
1930*4882a593Smuzhiyun 		dev_err(component->dev, "Can't change clock on active DAI %d\n",
1931*4882a593Smuzhiyun 			dai->id);
1932*4882a593Smuzhiyun 		return -EBUSY;
1933*4882a593Smuzhiyun 	}
1934*4882a593Smuzhiyun 
1935*4882a593Smuzhiyun 	dev_dbg(component->dev, "Setting AIF%d to %s\n", dai->id + 1,
1936*4882a593Smuzhiyun 		arizona_dai_clk_str(clk_id));
1937*4882a593Smuzhiyun 
1938*4882a593Smuzhiyun 	memset(&routes, 0, sizeof(routes));
1939*4882a593Smuzhiyun 	routes[0].sink = dai->driver->capture.stream_name;
1940*4882a593Smuzhiyun 	routes[1].sink = dai->driver->playback.stream_name;
1941*4882a593Smuzhiyun 
1942*4882a593Smuzhiyun 	routes[0].source = arizona_dai_clk_str(dai_priv->clk);
1943*4882a593Smuzhiyun 	routes[1].source = arizona_dai_clk_str(dai_priv->clk);
1944*4882a593Smuzhiyun 	snd_soc_dapm_del_routes(dapm, routes, ARRAY_SIZE(routes));
1945*4882a593Smuzhiyun 
1946*4882a593Smuzhiyun 	routes[0].source = arizona_dai_clk_str(clk_id);
1947*4882a593Smuzhiyun 	routes[1].source = arizona_dai_clk_str(clk_id);
1948*4882a593Smuzhiyun 	snd_soc_dapm_add_routes(dapm, routes, ARRAY_SIZE(routes));
1949*4882a593Smuzhiyun 
1950*4882a593Smuzhiyun 	dai_priv->clk = clk_id;
1951*4882a593Smuzhiyun 
1952*4882a593Smuzhiyun 	return snd_soc_dapm_sync(dapm);
1953*4882a593Smuzhiyun }
1954*4882a593Smuzhiyun 
arizona_set_tristate(struct snd_soc_dai * dai,int tristate)1955*4882a593Smuzhiyun static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate)
1956*4882a593Smuzhiyun {
1957*4882a593Smuzhiyun 	struct snd_soc_component *component = dai->component;
1958*4882a593Smuzhiyun 	int base = dai->driver->base;
1959*4882a593Smuzhiyun 	unsigned int reg;
1960*4882a593Smuzhiyun 
1961*4882a593Smuzhiyun 	if (tristate)
1962*4882a593Smuzhiyun 		reg = ARIZONA_AIF1_TRI;
1963*4882a593Smuzhiyun 	else
1964*4882a593Smuzhiyun 		reg = 0;
1965*4882a593Smuzhiyun 
1966*4882a593Smuzhiyun 	return snd_soc_component_update_bits(component,
1967*4882a593Smuzhiyun 					     base + ARIZONA_AIF_RATE_CTRL,
1968*4882a593Smuzhiyun 					     ARIZONA_AIF1_TRI, reg);
1969*4882a593Smuzhiyun }
1970*4882a593Smuzhiyun 
arizona_set_channels_to_mask(struct snd_soc_dai * dai,unsigned int base,int channels,unsigned int mask)1971*4882a593Smuzhiyun static void arizona_set_channels_to_mask(struct snd_soc_dai *dai,
1972*4882a593Smuzhiyun 					 unsigned int base,
1973*4882a593Smuzhiyun 					 int channels, unsigned int mask)
1974*4882a593Smuzhiyun {
1975*4882a593Smuzhiyun 	struct snd_soc_component *component = dai->component;
1976*4882a593Smuzhiyun 	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
1977*4882a593Smuzhiyun 	struct arizona *arizona = priv->arizona;
1978*4882a593Smuzhiyun 	int slot, i;
1979*4882a593Smuzhiyun 
1980*4882a593Smuzhiyun 	for (i = 0; i < channels; ++i) {
1981*4882a593Smuzhiyun 		slot = ffs(mask) - 1;
1982*4882a593Smuzhiyun 		if (slot < 0)
1983*4882a593Smuzhiyun 			return;
1984*4882a593Smuzhiyun 
1985*4882a593Smuzhiyun 		regmap_write(arizona->regmap, base + i, slot);
1986*4882a593Smuzhiyun 
1987*4882a593Smuzhiyun 		mask &= ~(1 << slot);
1988*4882a593Smuzhiyun 	}
1989*4882a593Smuzhiyun 
1990*4882a593Smuzhiyun 	if (mask)
1991*4882a593Smuzhiyun 		arizona_aif_warn(dai, "Too many channels in TDM mask\n");
1992*4882a593Smuzhiyun }
1993*4882a593Smuzhiyun 
arizona_set_tdm_slot(struct snd_soc_dai * dai,unsigned int tx_mask,unsigned int rx_mask,int slots,int slot_width)1994*4882a593Smuzhiyun static int arizona_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
1995*4882a593Smuzhiyun 				unsigned int rx_mask, int slots, int slot_width)
1996*4882a593Smuzhiyun {
1997*4882a593Smuzhiyun 	struct snd_soc_component *component = dai->component;
1998*4882a593Smuzhiyun 	struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
1999*4882a593Smuzhiyun 	struct arizona *arizona = priv->arizona;
2000*4882a593Smuzhiyun 	int base = dai->driver->base;
2001*4882a593Smuzhiyun 	int rx_max_chan = dai->driver->playback.channels_max;
2002*4882a593Smuzhiyun 	int tx_max_chan = dai->driver->capture.channels_max;
2003*4882a593Smuzhiyun 
2004*4882a593Smuzhiyun 	/* Only support TDM for the physical AIFs */
2005*4882a593Smuzhiyun 	if (dai->id > ARIZONA_MAX_AIF)
2006*4882a593Smuzhiyun 		return -ENOTSUPP;
2007*4882a593Smuzhiyun 
2008*4882a593Smuzhiyun 	if (slots == 0) {
2009*4882a593Smuzhiyun 		tx_mask = (1 << tx_max_chan) - 1;
2010*4882a593Smuzhiyun 		rx_mask = (1 << rx_max_chan) - 1;
2011*4882a593Smuzhiyun 	}
2012*4882a593Smuzhiyun 
2013*4882a593Smuzhiyun 	arizona_set_channels_to_mask(dai, base + ARIZONA_AIF_FRAME_CTRL_3,
2014*4882a593Smuzhiyun 				     tx_max_chan, tx_mask);
2015*4882a593Smuzhiyun 	arizona_set_channels_to_mask(dai, base + ARIZONA_AIF_FRAME_CTRL_11,
2016*4882a593Smuzhiyun 				     rx_max_chan, rx_mask);
2017*4882a593Smuzhiyun 
2018*4882a593Smuzhiyun 	arizona->tdm_width[dai->id - 1] = slot_width;
2019*4882a593Smuzhiyun 	arizona->tdm_slots[dai->id - 1] = slots;
2020*4882a593Smuzhiyun 
2021*4882a593Smuzhiyun 	return 0;
2022*4882a593Smuzhiyun }
2023*4882a593Smuzhiyun 
2024*4882a593Smuzhiyun const struct snd_soc_dai_ops arizona_dai_ops = {
2025*4882a593Smuzhiyun 	.startup = arizona_startup,
2026*4882a593Smuzhiyun 	.set_fmt = arizona_set_fmt,
2027*4882a593Smuzhiyun 	.set_tdm_slot = arizona_set_tdm_slot,
2028*4882a593Smuzhiyun 	.hw_params = arizona_hw_params,
2029*4882a593Smuzhiyun 	.set_sysclk = arizona_dai_set_sysclk,
2030*4882a593Smuzhiyun 	.set_tristate = arizona_set_tristate,
2031*4882a593Smuzhiyun };
2032*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_dai_ops);
2033*4882a593Smuzhiyun 
2034*4882a593Smuzhiyun const struct snd_soc_dai_ops arizona_simple_dai_ops = {
2035*4882a593Smuzhiyun 	.startup = arizona_startup,
2036*4882a593Smuzhiyun 	.hw_params = arizona_hw_params_rate,
2037*4882a593Smuzhiyun 	.set_sysclk = arizona_dai_set_sysclk,
2038*4882a593Smuzhiyun };
2039*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_simple_dai_ops);
2040*4882a593Smuzhiyun 
arizona_init_dai(struct arizona_priv * priv,int id)2041*4882a593Smuzhiyun int arizona_init_dai(struct arizona_priv *priv, int id)
2042*4882a593Smuzhiyun {
2043*4882a593Smuzhiyun 	struct arizona_dai_priv *dai_priv = &priv->dai[id];
2044*4882a593Smuzhiyun 
2045*4882a593Smuzhiyun 	dai_priv->clk = ARIZONA_CLK_SYSCLK;
2046*4882a593Smuzhiyun 	dai_priv->constraint = arizona_constraint;
2047*4882a593Smuzhiyun 
2048*4882a593Smuzhiyun 	return 0;
2049*4882a593Smuzhiyun }
2050*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_init_dai);
2051*4882a593Smuzhiyun 
2052*4882a593Smuzhiyun static struct {
2053*4882a593Smuzhiyun 	unsigned int min;
2054*4882a593Smuzhiyun 	unsigned int max;
2055*4882a593Smuzhiyun 	u16 fratio;
2056*4882a593Smuzhiyun 	int ratio;
2057*4882a593Smuzhiyun } fll_fratios[] = {
2058*4882a593Smuzhiyun 	{       0,    64000, 4, 16 },
2059*4882a593Smuzhiyun 	{   64000,   128000, 3,  8 },
2060*4882a593Smuzhiyun 	{  128000,   256000, 2,  4 },
2061*4882a593Smuzhiyun 	{  256000,  1000000, 1,  2 },
2062*4882a593Smuzhiyun 	{ 1000000, 13500000, 0,  1 },
2063*4882a593Smuzhiyun };
2064*4882a593Smuzhiyun 
2065*4882a593Smuzhiyun static const unsigned int pseudo_fref_max[ARIZONA_FLL_MAX_FRATIO] = {
2066*4882a593Smuzhiyun 	13500000,
2067*4882a593Smuzhiyun 	 6144000,
2068*4882a593Smuzhiyun 	 6144000,
2069*4882a593Smuzhiyun 	 3072000,
2070*4882a593Smuzhiyun 	 3072000,
2071*4882a593Smuzhiyun 	 2822400,
2072*4882a593Smuzhiyun 	 2822400,
2073*4882a593Smuzhiyun 	 1536000,
2074*4882a593Smuzhiyun 	 1536000,
2075*4882a593Smuzhiyun 	 1536000,
2076*4882a593Smuzhiyun 	 1536000,
2077*4882a593Smuzhiyun 	 1536000,
2078*4882a593Smuzhiyun 	 1536000,
2079*4882a593Smuzhiyun 	 1536000,
2080*4882a593Smuzhiyun 	 1536000,
2081*4882a593Smuzhiyun 	  768000,
2082*4882a593Smuzhiyun };
2083*4882a593Smuzhiyun 
2084*4882a593Smuzhiyun static struct {
2085*4882a593Smuzhiyun 	unsigned int min;
2086*4882a593Smuzhiyun 	unsigned int max;
2087*4882a593Smuzhiyun 	u16 gain;
2088*4882a593Smuzhiyun } fll_gains[] = {
2089*4882a593Smuzhiyun 	{       0,   256000, 0 },
2090*4882a593Smuzhiyun 	{  256000,  1000000, 2 },
2091*4882a593Smuzhiyun 	{ 1000000, 13500000, 4 },
2092*4882a593Smuzhiyun };
2093*4882a593Smuzhiyun 
2094*4882a593Smuzhiyun struct arizona_fll_cfg {
2095*4882a593Smuzhiyun 	int n;
2096*4882a593Smuzhiyun 	unsigned int theta;
2097*4882a593Smuzhiyun 	unsigned int lambda;
2098*4882a593Smuzhiyun 	int refdiv;
2099*4882a593Smuzhiyun 	int outdiv;
2100*4882a593Smuzhiyun 	int fratio;
2101*4882a593Smuzhiyun 	int gain;
2102*4882a593Smuzhiyun };
2103*4882a593Smuzhiyun 
arizona_validate_fll(struct arizona_fll * fll,unsigned int Fref,unsigned int Fout)2104*4882a593Smuzhiyun static int arizona_validate_fll(struct arizona_fll *fll,
2105*4882a593Smuzhiyun 				unsigned int Fref,
2106*4882a593Smuzhiyun 				unsigned int Fout)
2107*4882a593Smuzhiyun {
2108*4882a593Smuzhiyun 	unsigned int Fvco_min;
2109*4882a593Smuzhiyun 
2110*4882a593Smuzhiyun 	if (fll->fout && Fout != fll->fout) {
2111*4882a593Smuzhiyun 		arizona_fll_err(fll,
2112*4882a593Smuzhiyun 				"Can't change output on active FLL\n");
2113*4882a593Smuzhiyun 		return -EINVAL;
2114*4882a593Smuzhiyun 	}
2115*4882a593Smuzhiyun 
2116*4882a593Smuzhiyun 	if (Fref / ARIZONA_FLL_MAX_REFDIV > ARIZONA_FLL_MAX_FREF) {
2117*4882a593Smuzhiyun 		arizona_fll_err(fll,
2118*4882a593Smuzhiyun 				"Can't scale %dMHz in to <=13.5MHz\n",
2119*4882a593Smuzhiyun 				Fref);
2120*4882a593Smuzhiyun 		return -EINVAL;
2121*4882a593Smuzhiyun 	}
2122*4882a593Smuzhiyun 
2123*4882a593Smuzhiyun 	Fvco_min = ARIZONA_FLL_MIN_FVCO * fll->vco_mult;
2124*4882a593Smuzhiyun 	if (Fout * ARIZONA_FLL_MAX_OUTDIV < Fvco_min) {
2125*4882a593Smuzhiyun 		arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n",
2126*4882a593Smuzhiyun 				Fout);
2127*4882a593Smuzhiyun 		return -EINVAL;
2128*4882a593Smuzhiyun 	}
2129*4882a593Smuzhiyun 
2130*4882a593Smuzhiyun 	return 0;
2131*4882a593Smuzhiyun }
2132*4882a593Smuzhiyun 
arizona_find_fratio(unsigned int Fref,int * fratio)2133*4882a593Smuzhiyun static int arizona_find_fratio(unsigned int Fref, int *fratio)
2134*4882a593Smuzhiyun {
2135*4882a593Smuzhiyun 	int i;
2136*4882a593Smuzhiyun 
2137*4882a593Smuzhiyun 	/* Find an appropriate FLL_FRATIO */
2138*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) {
2139*4882a593Smuzhiyun 		if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) {
2140*4882a593Smuzhiyun 			if (fratio)
2141*4882a593Smuzhiyun 				*fratio = fll_fratios[i].fratio;
2142*4882a593Smuzhiyun 			return fll_fratios[i].ratio;
2143*4882a593Smuzhiyun 		}
2144*4882a593Smuzhiyun 	}
2145*4882a593Smuzhiyun 
2146*4882a593Smuzhiyun 	return -EINVAL;
2147*4882a593Smuzhiyun }
2148*4882a593Smuzhiyun 
arizona_calc_fratio(struct arizona_fll * fll,struct arizona_fll_cfg * cfg,unsigned int target,unsigned int Fref,bool sync)2149*4882a593Smuzhiyun static int arizona_calc_fratio(struct arizona_fll *fll,
2150*4882a593Smuzhiyun 			       struct arizona_fll_cfg *cfg,
2151*4882a593Smuzhiyun 			       unsigned int target,
2152*4882a593Smuzhiyun 			       unsigned int Fref, bool sync)
2153*4882a593Smuzhiyun {
2154*4882a593Smuzhiyun 	int init_ratio, ratio;
2155*4882a593Smuzhiyun 	int refdiv, div;
2156*4882a593Smuzhiyun 
2157*4882a593Smuzhiyun 	/* Fref must be <=13.5MHz, find initial refdiv */
2158*4882a593Smuzhiyun 	div = 1;
2159*4882a593Smuzhiyun 	cfg->refdiv = 0;
2160*4882a593Smuzhiyun 	while (Fref > ARIZONA_FLL_MAX_FREF) {
2161*4882a593Smuzhiyun 		div *= 2;
2162*4882a593Smuzhiyun 		Fref /= 2;
2163*4882a593Smuzhiyun 		cfg->refdiv++;
2164*4882a593Smuzhiyun 
2165*4882a593Smuzhiyun 		if (div > ARIZONA_FLL_MAX_REFDIV)
2166*4882a593Smuzhiyun 			return -EINVAL;
2167*4882a593Smuzhiyun 	}
2168*4882a593Smuzhiyun 
2169*4882a593Smuzhiyun 	/* Find an appropriate FLL_FRATIO */
2170*4882a593Smuzhiyun 	init_ratio = arizona_find_fratio(Fref, &cfg->fratio);
2171*4882a593Smuzhiyun 	if (init_ratio < 0) {
2172*4882a593Smuzhiyun 		arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n",
2173*4882a593Smuzhiyun 				Fref);
2174*4882a593Smuzhiyun 		return init_ratio;
2175*4882a593Smuzhiyun 	}
2176*4882a593Smuzhiyun 
2177*4882a593Smuzhiyun 	switch (fll->arizona->type) {
2178*4882a593Smuzhiyun 	case WM5102:
2179*4882a593Smuzhiyun 	case WM8997:
2180*4882a593Smuzhiyun 		return init_ratio;
2181*4882a593Smuzhiyun 	case WM5110:
2182*4882a593Smuzhiyun 	case WM8280:
2183*4882a593Smuzhiyun 		if (fll->arizona->rev < 3 || sync)
2184*4882a593Smuzhiyun 			return init_ratio;
2185*4882a593Smuzhiyun 		break;
2186*4882a593Smuzhiyun 	default:
2187*4882a593Smuzhiyun 		if (sync)
2188*4882a593Smuzhiyun 			return init_ratio;
2189*4882a593Smuzhiyun 		break;
2190*4882a593Smuzhiyun 	}
2191*4882a593Smuzhiyun 
2192*4882a593Smuzhiyun 	cfg->fratio = init_ratio - 1;
2193*4882a593Smuzhiyun 
2194*4882a593Smuzhiyun 	/* Adjust FRATIO/refdiv to avoid integer mode if possible */
2195*4882a593Smuzhiyun 	refdiv = cfg->refdiv;
2196*4882a593Smuzhiyun 
2197*4882a593Smuzhiyun 	arizona_fll_dbg(fll, "pseudo: initial ratio=%u fref=%u refdiv=%u\n",
2198*4882a593Smuzhiyun 			init_ratio, Fref, refdiv);
2199*4882a593Smuzhiyun 
2200*4882a593Smuzhiyun 	while (div <= ARIZONA_FLL_MAX_REFDIV) {
2201*4882a593Smuzhiyun 		/* start from init_ratio because this may already give a
2202*4882a593Smuzhiyun 		 * fractional N.K
2203*4882a593Smuzhiyun 		 */
2204*4882a593Smuzhiyun 		for (ratio = init_ratio; ratio > 0; ratio--) {
2205*4882a593Smuzhiyun 			if (target % (ratio * Fref)) {
2206*4882a593Smuzhiyun 				cfg->refdiv = refdiv;
2207*4882a593Smuzhiyun 				cfg->fratio = ratio - 1;
2208*4882a593Smuzhiyun 				arizona_fll_dbg(fll,
2209*4882a593Smuzhiyun 					"pseudo: found fref=%u refdiv=%d(%d) ratio=%d\n",
2210*4882a593Smuzhiyun 					Fref, refdiv, div, ratio);
2211*4882a593Smuzhiyun 				return ratio;
2212*4882a593Smuzhiyun 			}
2213*4882a593Smuzhiyun 		}
2214*4882a593Smuzhiyun 
2215*4882a593Smuzhiyun 		for (ratio = init_ratio + 1; ratio <= ARIZONA_FLL_MAX_FRATIO;
2216*4882a593Smuzhiyun 		     ratio++) {
2217*4882a593Smuzhiyun 			if ((ARIZONA_FLL_VCO_CORNER / 2) /
2218*4882a593Smuzhiyun 			    (fll->vco_mult * ratio) < Fref) {
2219*4882a593Smuzhiyun 				arizona_fll_dbg(fll, "pseudo: hit VCO corner\n");
2220*4882a593Smuzhiyun 				break;
2221*4882a593Smuzhiyun 			}
2222*4882a593Smuzhiyun 
2223*4882a593Smuzhiyun 			if (Fref > pseudo_fref_max[ratio - 1]) {
2224*4882a593Smuzhiyun 				arizona_fll_dbg(fll,
2225*4882a593Smuzhiyun 					"pseudo: exceeded max fref(%u) for ratio=%u\n",
2226*4882a593Smuzhiyun 					pseudo_fref_max[ratio - 1],
2227*4882a593Smuzhiyun 					ratio);
2228*4882a593Smuzhiyun 				break;
2229*4882a593Smuzhiyun 			}
2230*4882a593Smuzhiyun 
2231*4882a593Smuzhiyun 			if (target % (ratio * Fref)) {
2232*4882a593Smuzhiyun 				cfg->refdiv = refdiv;
2233*4882a593Smuzhiyun 				cfg->fratio = ratio - 1;
2234*4882a593Smuzhiyun 				arizona_fll_dbg(fll,
2235*4882a593Smuzhiyun 					"pseudo: found fref=%u refdiv=%d(%d) ratio=%d\n",
2236*4882a593Smuzhiyun 					Fref, refdiv, div, ratio);
2237*4882a593Smuzhiyun 				return ratio;
2238*4882a593Smuzhiyun 			}
2239*4882a593Smuzhiyun 		}
2240*4882a593Smuzhiyun 
2241*4882a593Smuzhiyun 		div *= 2;
2242*4882a593Smuzhiyun 		Fref /= 2;
2243*4882a593Smuzhiyun 		refdiv++;
2244*4882a593Smuzhiyun 		init_ratio = arizona_find_fratio(Fref, NULL);
2245*4882a593Smuzhiyun 		arizona_fll_dbg(fll,
2246*4882a593Smuzhiyun 				"pseudo: change fref=%u refdiv=%d(%d) ratio=%u\n",
2247*4882a593Smuzhiyun 				Fref, refdiv, div, init_ratio);
2248*4882a593Smuzhiyun 	}
2249*4882a593Smuzhiyun 
2250*4882a593Smuzhiyun 	arizona_fll_warn(fll, "Falling back to integer mode operation\n");
2251*4882a593Smuzhiyun 	return cfg->fratio + 1;
2252*4882a593Smuzhiyun }
2253*4882a593Smuzhiyun 
arizona_calc_fll(struct arizona_fll * fll,struct arizona_fll_cfg * cfg,unsigned int Fref,bool sync)2254*4882a593Smuzhiyun static int arizona_calc_fll(struct arizona_fll *fll,
2255*4882a593Smuzhiyun 			    struct arizona_fll_cfg *cfg,
2256*4882a593Smuzhiyun 			    unsigned int Fref, bool sync)
2257*4882a593Smuzhiyun {
2258*4882a593Smuzhiyun 	unsigned int target, div, gcd_fll;
2259*4882a593Smuzhiyun 	int i, ratio;
2260*4882a593Smuzhiyun 
2261*4882a593Smuzhiyun 	arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, fll->fout);
2262*4882a593Smuzhiyun 
2263*4882a593Smuzhiyun 	/* Fvco should be over the targt; don't check the upper bound */
2264*4882a593Smuzhiyun 	div = ARIZONA_FLL_MIN_OUTDIV;
2265*4882a593Smuzhiyun 	while (fll->fout * div < ARIZONA_FLL_MIN_FVCO * fll->vco_mult) {
2266*4882a593Smuzhiyun 		div++;
2267*4882a593Smuzhiyun 		if (div > ARIZONA_FLL_MAX_OUTDIV)
2268*4882a593Smuzhiyun 			return -EINVAL;
2269*4882a593Smuzhiyun 	}
2270*4882a593Smuzhiyun 	target = fll->fout * div / fll->vco_mult;
2271*4882a593Smuzhiyun 	cfg->outdiv = div;
2272*4882a593Smuzhiyun 
2273*4882a593Smuzhiyun 	arizona_fll_dbg(fll, "Fvco=%dHz\n", target);
2274*4882a593Smuzhiyun 
2275*4882a593Smuzhiyun 	/* Find an appropriate FLL_FRATIO and refdiv */
2276*4882a593Smuzhiyun 	ratio = arizona_calc_fratio(fll, cfg, target, Fref, sync);
2277*4882a593Smuzhiyun 	if (ratio < 0)
2278*4882a593Smuzhiyun 		return ratio;
2279*4882a593Smuzhiyun 
2280*4882a593Smuzhiyun 	/* Apply the division for our remaining calculations */
2281*4882a593Smuzhiyun 	Fref = Fref / (1 << cfg->refdiv);
2282*4882a593Smuzhiyun 
2283*4882a593Smuzhiyun 	cfg->n = target / (ratio * Fref);
2284*4882a593Smuzhiyun 
2285*4882a593Smuzhiyun 	if (target % (ratio * Fref)) {
2286*4882a593Smuzhiyun 		gcd_fll = gcd(target, ratio * Fref);
2287*4882a593Smuzhiyun 		arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll);
2288*4882a593Smuzhiyun 
2289*4882a593Smuzhiyun 		cfg->theta = (target - (cfg->n * ratio * Fref))
2290*4882a593Smuzhiyun 			/ gcd_fll;
2291*4882a593Smuzhiyun 		cfg->lambda = (ratio * Fref) / gcd_fll;
2292*4882a593Smuzhiyun 	} else {
2293*4882a593Smuzhiyun 		cfg->theta = 0;
2294*4882a593Smuzhiyun 		cfg->lambda = 0;
2295*4882a593Smuzhiyun 	}
2296*4882a593Smuzhiyun 
2297*4882a593Smuzhiyun 	/* Round down to 16bit range with cost of accuracy lost.
2298*4882a593Smuzhiyun 	 * Denominator must be bigger than numerator so we only
2299*4882a593Smuzhiyun 	 * take care of it.
2300*4882a593Smuzhiyun 	 */
2301*4882a593Smuzhiyun 	while (cfg->lambda >= (1 << 16)) {
2302*4882a593Smuzhiyun 		cfg->theta >>= 1;
2303*4882a593Smuzhiyun 		cfg->lambda >>= 1;
2304*4882a593Smuzhiyun 	}
2305*4882a593Smuzhiyun 
2306*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(fll_gains); i++) {
2307*4882a593Smuzhiyun 		if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) {
2308*4882a593Smuzhiyun 			cfg->gain = fll_gains[i].gain;
2309*4882a593Smuzhiyun 			break;
2310*4882a593Smuzhiyun 		}
2311*4882a593Smuzhiyun 	}
2312*4882a593Smuzhiyun 	if (i == ARRAY_SIZE(fll_gains)) {
2313*4882a593Smuzhiyun 		arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n",
2314*4882a593Smuzhiyun 				Fref);
2315*4882a593Smuzhiyun 		return -EINVAL;
2316*4882a593Smuzhiyun 	}
2317*4882a593Smuzhiyun 
2318*4882a593Smuzhiyun 	arizona_fll_dbg(fll, "N=%d THETA=%d LAMBDA=%d\n",
2319*4882a593Smuzhiyun 			cfg->n, cfg->theta, cfg->lambda);
2320*4882a593Smuzhiyun 	arizona_fll_dbg(fll, "FRATIO=0x%x(%d) OUTDIV=%d REFCLK_DIV=0x%x(%d)\n",
2321*4882a593Smuzhiyun 			cfg->fratio, ratio, cfg->outdiv,
2322*4882a593Smuzhiyun 			cfg->refdiv, 1 << cfg->refdiv);
2323*4882a593Smuzhiyun 	arizona_fll_dbg(fll, "GAIN=0x%x(%d)\n", cfg->gain, 1 << cfg->gain);
2324*4882a593Smuzhiyun 
2325*4882a593Smuzhiyun 	return 0;
2326*4882a593Smuzhiyun }
2327*4882a593Smuzhiyun 
arizona_apply_fll(struct arizona * arizona,unsigned int base,struct arizona_fll_cfg * cfg,int source,bool sync)2328*4882a593Smuzhiyun static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
2329*4882a593Smuzhiyun 			      struct arizona_fll_cfg *cfg, int source,
2330*4882a593Smuzhiyun 			      bool sync)
2331*4882a593Smuzhiyun {
2332*4882a593Smuzhiyun 	regmap_update_bits_async(arizona->regmap, base + 3,
2333*4882a593Smuzhiyun 				 ARIZONA_FLL1_THETA_MASK, cfg->theta);
2334*4882a593Smuzhiyun 	regmap_update_bits_async(arizona->regmap, base + 4,
2335*4882a593Smuzhiyun 				 ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
2336*4882a593Smuzhiyun 	regmap_update_bits_async(arizona->regmap, base + 5,
2337*4882a593Smuzhiyun 				 ARIZONA_FLL1_FRATIO_MASK,
2338*4882a593Smuzhiyun 				 cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
2339*4882a593Smuzhiyun 	regmap_update_bits_async(arizona->regmap, base + 6,
2340*4882a593Smuzhiyun 				 ARIZONA_FLL1_CLK_REF_DIV_MASK |
2341*4882a593Smuzhiyun 				 ARIZONA_FLL1_CLK_REF_SRC_MASK,
2342*4882a593Smuzhiyun 				 cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
2343*4882a593Smuzhiyun 				 source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
2344*4882a593Smuzhiyun 
2345*4882a593Smuzhiyun 	if (sync) {
2346*4882a593Smuzhiyun 		regmap_update_bits(arizona->regmap, base + 0x7,
2347*4882a593Smuzhiyun 				   ARIZONA_FLL1_GAIN_MASK,
2348*4882a593Smuzhiyun 				   cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
2349*4882a593Smuzhiyun 	} else {
2350*4882a593Smuzhiyun 		regmap_update_bits(arizona->regmap, base + 0x5,
2351*4882a593Smuzhiyun 				   ARIZONA_FLL1_OUTDIV_MASK,
2352*4882a593Smuzhiyun 				   cfg->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
2353*4882a593Smuzhiyun 		regmap_update_bits(arizona->regmap, base + 0x9,
2354*4882a593Smuzhiyun 				   ARIZONA_FLL1_GAIN_MASK,
2355*4882a593Smuzhiyun 				   cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
2356*4882a593Smuzhiyun 	}
2357*4882a593Smuzhiyun 
2358*4882a593Smuzhiyun 	regmap_update_bits_async(arizona->regmap, base + 2,
2359*4882a593Smuzhiyun 				 ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
2360*4882a593Smuzhiyun 				 ARIZONA_FLL1_CTRL_UPD | cfg->n);
2361*4882a593Smuzhiyun }
2362*4882a593Smuzhiyun 
arizona_is_enabled_fll(struct arizona_fll * fll,int base)2363*4882a593Smuzhiyun static int arizona_is_enabled_fll(struct arizona_fll *fll, int base)
2364*4882a593Smuzhiyun {
2365*4882a593Smuzhiyun 	struct arizona *arizona = fll->arizona;
2366*4882a593Smuzhiyun 	unsigned int reg;
2367*4882a593Smuzhiyun 	int ret;
2368*4882a593Smuzhiyun 
2369*4882a593Smuzhiyun 	ret = regmap_read(arizona->regmap, base + 1, &reg);
2370*4882a593Smuzhiyun 	if (ret != 0) {
2371*4882a593Smuzhiyun 		arizona_fll_err(fll, "Failed to read current state: %d\n",
2372*4882a593Smuzhiyun 				ret);
2373*4882a593Smuzhiyun 		return ret;
2374*4882a593Smuzhiyun 	}
2375*4882a593Smuzhiyun 
2376*4882a593Smuzhiyun 	return reg & ARIZONA_FLL1_ENA;
2377*4882a593Smuzhiyun }
2378*4882a593Smuzhiyun 
arizona_set_fll_clks(struct arizona_fll * fll,int base,bool ena)2379*4882a593Smuzhiyun static int arizona_set_fll_clks(struct arizona_fll *fll, int base, bool ena)
2380*4882a593Smuzhiyun {
2381*4882a593Smuzhiyun 	struct arizona *arizona = fll->arizona;
2382*4882a593Smuzhiyun 	unsigned int val;
2383*4882a593Smuzhiyun 	struct clk *clk;
2384*4882a593Smuzhiyun 	int ret;
2385*4882a593Smuzhiyun 
2386*4882a593Smuzhiyun 	ret = regmap_read(arizona->regmap, base + 6, &val);
2387*4882a593Smuzhiyun 	if (ret != 0) {
2388*4882a593Smuzhiyun 		arizona_fll_err(fll, "Failed to read current source: %d\n",
2389*4882a593Smuzhiyun 				ret);
2390*4882a593Smuzhiyun 		return ret;
2391*4882a593Smuzhiyun 	}
2392*4882a593Smuzhiyun 
2393*4882a593Smuzhiyun 	val &= ARIZONA_FLL1_CLK_REF_SRC_MASK;
2394*4882a593Smuzhiyun 	val >>= ARIZONA_FLL1_CLK_REF_SRC_SHIFT;
2395*4882a593Smuzhiyun 
2396*4882a593Smuzhiyun 	switch (val) {
2397*4882a593Smuzhiyun 	case ARIZONA_FLL_SRC_MCLK1:
2398*4882a593Smuzhiyun 		clk = arizona->mclk[ARIZONA_MCLK1];
2399*4882a593Smuzhiyun 		break;
2400*4882a593Smuzhiyun 	case ARIZONA_FLL_SRC_MCLK2:
2401*4882a593Smuzhiyun 		clk = arizona->mclk[ARIZONA_MCLK2];
2402*4882a593Smuzhiyun 		break;
2403*4882a593Smuzhiyun 	default:
2404*4882a593Smuzhiyun 		return 0;
2405*4882a593Smuzhiyun 	}
2406*4882a593Smuzhiyun 
2407*4882a593Smuzhiyun 	if (ena) {
2408*4882a593Smuzhiyun 		return clk_prepare_enable(clk);
2409*4882a593Smuzhiyun 	} else {
2410*4882a593Smuzhiyun 		clk_disable_unprepare(clk);
2411*4882a593Smuzhiyun 		return 0;
2412*4882a593Smuzhiyun 	}
2413*4882a593Smuzhiyun }
2414*4882a593Smuzhiyun 
arizona_enable_fll(struct arizona_fll * fll)2415*4882a593Smuzhiyun static int arizona_enable_fll(struct arizona_fll *fll)
2416*4882a593Smuzhiyun {
2417*4882a593Smuzhiyun 	struct arizona *arizona = fll->arizona;
2418*4882a593Smuzhiyun 	bool use_sync = false;
2419*4882a593Smuzhiyun 	int already_enabled = arizona_is_enabled_fll(fll, fll->base);
2420*4882a593Smuzhiyun 	int sync_enabled = arizona_is_enabled_fll(fll, fll->base + 0x10);
2421*4882a593Smuzhiyun 	struct arizona_fll_cfg cfg;
2422*4882a593Smuzhiyun 	int i;
2423*4882a593Smuzhiyun 	unsigned int val;
2424*4882a593Smuzhiyun 
2425*4882a593Smuzhiyun 	if (already_enabled < 0)
2426*4882a593Smuzhiyun 		return already_enabled;
2427*4882a593Smuzhiyun 	if (sync_enabled < 0)
2428*4882a593Smuzhiyun 		return sync_enabled;
2429*4882a593Smuzhiyun 
2430*4882a593Smuzhiyun 	if (already_enabled) {
2431*4882a593Smuzhiyun 		/* Facilitate smooth refclk across the transition */
2432*4882a593Smuzhiyun 		regmap_update_bits(fll->arizona->regmap, fll->base + 1,
2433*4882a593Smuzhiyun 				   ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN);
2434*4882a593Smuzhiyun 		udelay(32);
2435*4882a593Smuzhiyun 		regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x9,
2436*4882a593Smuzhiyun 					 ARIZONA_FLL1_GAIN_MASK, 0);
2437*4882a593Smuzhiyun 
2438*4882a593Smuzhiyun 		if (arizona_is_enabled_fll(fll, fll->base + 0x10) > 0)
2439*4882a593Smuzhiyun 			arizona_set_fll_clks(fll, fll->base + 0x10, false);
2440*4882a593Smuzhiyun 		arizona_set_fll_clks(fll, fll->base, false);
2441*4882a593Smuzhiyun 	}
2442*4882a593Smuzhiyun 
2443*4882a593Smuzhiyun 	/*
2444*4882a593Smuzhiyun 	 * If we have both REFCLK and SYNCCLK then enable both,
2445*4882a593Smuzhiyun 	 * otherwise apply the SYNCCLK settings to REFCLK.
2446*4882a593Smuzhiyun 	 */
2447*4882a593Smuzhiyun 	if (fll->ref_src >= 0 && fll->ref_freq &&
2448*4882a593Smuzhiyun 	    fll->ref_src != fll->sync_src) {
2449*4882a593Smuzhiyun 		arizona_calc_fll(fll, &cfg, fll->ref_freq, false);
2450*4882a593Smuzhiyun 
2451*4882a593Smuzhiyun 		/* Ref path hardcodes lambda to 65536 when sync is on */
2452*4882a593Smuzhiyun 		if (fll->sync_src >= 0 && cfg.lambda)
2453*4882a593Smuzhiyun 			cfg.theta = (cfg.theta * (1 << 16)) / cfg.lambda;
2454*4882a593Smuzhiyun 
2455*4882a593Smuzhiyun 		arizona_apply_fll(arizona, fll->base, &cfg, fll->ref_src,
2456*4882a593Smuzhiyun 				  false);
2457*4882a593Smuzhiyun 		if (fll->sync_src >= 0) {
2458*4882a593Smuzhiyun 			arizona_calc_fll(fll, &cfg, fll->sync_freq, true);
2459*4882a593Smuzhiyun 
2460*4882a593Smuzhiyun 			arizona_apply_fll(arizona, fll->base + 0x10, &cfg,
2461*4882a593Smuzhiyun 					  fll->sync_src, true);
2462*4882a593Smuzhiyun 			use_sync = true;
2463*4882a593Smuzhiyun 		}
2464*4882a593Smuzhiyun 	} else if (fll->sync_src >= 0) {
2465*4882a593Smuzhiyun 		arizona_calc_fll(fll, &cfg, fll->sync_freq, false);
2466*4882a593Smuzhiyun 
2467*4882a593Smuzhiyun 		arizona_apply_fll(arizona, fll->base, &cfg,
2468*4882a593Smuzhiyun 				  fll->sync_src, false);
2469*4882a593Smuzhiyun 
2470*4882a593Smuzhiyun 		regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
2471*4882a593Smuzhiyun 					 ARIZONA_FLL1_SYNC_ENA, 0);
2472*4882a593Smuzhiyun 	} else {
2473*4882a593Smuzhiyun 		arizona_fll_err(fll, "No clocks provided\n");
2474*4882a593Smuzhiyun 		return -EINVAL;
2475*4882a593Smuzhiyun 	}
2476*4882a593Smuzhiyun 
2477*4882a593Smuzhiyun 	if (already_enabled && !!sync_enabled != use_sync)
2478*4882a593Smuzhiyun 		arizona_fll_warn(fll, "Synchroniser changed on active FLL\n");
2479*4882a593Smuzhiyun 
2480*4882a593Smuzhiyun 	/*
2481*4882a593Smuzhiyun 	 * Increase the bandwidth if we're not using a low frequency
2482*4882a593Smuzhiyun 	 * sync source.
2483*4882a593Smuzhiyun 	 */
2484*4882a593Smuzhiyun 	if (use_sync && fll->sync_freq > 100000)
2485*4882a593Smuzhiyun 		regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
2486*4882a593Smuzhiyun 					 ARIZONA_FLL1_SYNC_BW, 0);
2487*4882a593Smuzhiyun 	else
2488*4882a593Smuzhiyun 		regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
2489*4882a593Smuzhiyun 					 ARIZONA_FLL1_SYNC_BW,
2490*4882a593Smuzhiyun 					 ARIZONA_FLL1_SYNC_BW);
2491*4882a593Smuzhiyun 
2492*4882a593Smuzhiyun 	if (!already_enabled)
2493*4882a593Smuzhiyun 		pm_runtime_get_sync(arizona->dev);
2494*4882a593Smuzhiyun 
2495*4882a593Smuzhiyun 	if (use_sync) {
2496*4882a593Smuzhiyun 		arizona_set_fll_clks(fll, fll->base + 0x10, true);
2497*4882a593Smuzhiyun 		regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
2498*4882a593Smuzhiyun 					 ARIZONA_FLL1_SYNC_ENA,
2499*4882a593Smuzhiyun 					 ARIZONA_FLL1_SYNC_ENA);
2500*4882a593Smuzhiyun 	}
2501*4882a593Smuzhiyun 	arizona_set_fll_clks(fll, fll->base, true);
2502*4882a593Smuzhiyun 	regmap_update_bits_async(arizona->regmap, fll->base + 1,
2503*4882a593Smuzhiyun 				 ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
2504*4882a593Smuzhiyun 
2505*4882a593Smuzhiyun 	if (already_enabled)
2506*4882a593Smuzhiyun 		regmap_update_bits_async(arizona->regmap, fll->base + 1,
2507*4882a593Smuzhiyun 					 ARIZONA_FLL1_FREERUN, 0);
2508*4882a593Smuzhiyun 
2509*4882a593Smuzhiyun 	arizona_fll_dbg(fll, "Waiting for FLL lock...\n");
2510*4882a593Smuzhiyun 	val = 0;
2511*4882a593Smuzhiyun 	for (i = 0; i < 15; i++) {
2512*4882a593Smuzhiyun 		if (i < 5)
2513*4882a593Smuzhiyun 			usleep_range(200, 400);
2514*4882a593Smuzhiyun 		else
2515*4882a593Smuzhiyun 			msleep(20);
2516*4882a593Smuzhiyun 
2517*4882a593Smuzhiyun 		regmap_read(arizona->regmap,
2518*4882a593Smuzhiyun 			    ARIZONA_INTERRUPT_RAW_STATUS_5,
2519*4882a593Smuzhiyun 			    &val);
2520*4882a593Smuzhiyun 		if (val & (ARIZONA_FLL1_CLOCK_OK_STS << (fll->id - 1)))
2521*4882a593Smuzhiyun 			break;
2522*4882a593Smuzhiyun 	}
2523*4882a593Smuzhiyun 	if (i == 15)
2524*4882a593Smuzhiyun 		arizona_fll_warn(fll, "Timed out waiting for lock\n");
2525*4882a593Smuzhiyun 	else
2526*4882a593Smuzhiyun 		arizona_fll_dbg(fll, "FLL locked (%d polls)\n", i);
2527*4882a593Smuzhiyun 
2528*4882a593Smuzhiyun 	return 0;
2529*4882a593Smuzhiyun }
2530*4882a593Smuzhiyun 
arizona_disable_fll(struct arizona_fll * fll)2531*4882a593Smuzhiyun static void arizona_disable_fll(struct arizona_fll *fll)
2532*4882a593Smuzhiyun {
2533*4882a593Smuzhiyun 	struct arizona *arizona = fll->arizona;
2534*4882a593Smuzhiyun 	bool ref_change, sync_change;
2535*4882a593Smuzhiyun 
2536*4882a593Smuzhiyun 	regmap_update_bits_async(arizona->regmap, fll->base + 1,
2537*4882a593Smuzhiyun 				 ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN);
2538*4882a593Smuzhiyun 	regmap_update_bits_check(arizona->regmap, fll->base + 1,
2539*4882a593Smuzhiyun 				 ARIZONA_FLL1_ENA, 0, &ref_change);
2540*4882a593Smuzhiyun 	regmap_update_bits_check(arizona->regmap, fll->base + 0x11,
2541*4882a593Smuzhiyun 				 ARIZONA_FLL1_SYNC_ENA, 0, &sync_change);
2542*4882a593Smuzhiyun 	regmap_update_bits_async(arizona->regmap, fll->base + 1,
2543*4882a593Smuzhiyun 				 ARIZONA_FLL1_FREERUN, 0);
2544*4882a593Smuzhiyun 
2545*4882a593Smuzhiyun 	if (sync_change)
2546*4882a593Smuzhiyun 		arizona_set_fll_clks(fll, fll->base + 0x10, false);
2547*4882a593Smuzhiyun 
2548*4882a593Smuzhiyun 	if (ref_change) {
2549*4882a593Smuzhiyun 		arizona_set_fll_clks(fll, fll->base, false);
2550*4882a593Smuzhiyun 		pm_runtime_put_autosuspend(arizona->dev);
2551*4882a593Smuzhiyun 	}
2552*4882a593Smuzhiyun }
2553*4882a593Smuzhiyun 
arizona_set_fll_refclk(struct arizona_fll * fll,int source,unsigned int Fref,unsigned int Fout)2554*4882a593Smuzhiyun int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
2555*4882a593Smuzhiyun 			   unsigned int Fref, unsigned int Fout)
2556*4882a593Smuzhiyun {
2557*4882a593Smuzhiyun 	int ret = 0;
2558*4882a593Smuzhiyun 
2559*4882a593Smuzhiyun 	if (fll->ref_src == source && fll->ref_freq == Fref)
2560*4882a593Smuzhiyun 		return 0;
2561*4882a593Smuzhiyun 
2562*4882a593Smuzhiyun 	if (fll->fout && Fref > 0) {
2563*4882a593Smuzhiyun 		ret = arizona_validate_fll(fll, Fref, fll->fout);
2564*4882a593Smuzhiyun 		if (ret != 0)
2565*4882a593Smuzhiyun 			return ret;
2566*4882a593Smuzhiyun 	}
2567*4882a593Smuzhiyun 
2568*4882a593Smuzhiyun 	fll->ref_src = source;
2569*4882a593Smuzhiyun 	fll->ref_freq = Fref;
2570*4882a593Smuzhiyun 
2571*4882a593Smuzhiyun 	if (fll->fout && Fref > 0)
2572*4882a593Smuzhiyun 		ret = arizona_enable_fll(fll);
2573*4882a593Smuzhiyun 
2574*4882a593Smuzhiyun 	return ret;
2575*4882a593Smuzhiyun }
2576*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_set_fll_refclk);
2577*4882a593Smuzhiyun 
arizona_set_fll(struct arizona_fll * fll,int source,unsigned int Fref,unsigned int Fout)2578*4882a593Smuzhiyun int arizona_set_fll(struct arizona_fll *fll, int source,
2579*4882a593Smuzhiyun 		    unsigned int Fref, unsigned int Fout)
2580*4882a593Smuzhiyun {
2581*4882a593Smuzhiyun 	int ret = 0;
2582*4882a593Smuzhiyun 
2583*4882a593Smuzhiyun 	if (fll->sync_src == source &&
2584*4882a593Smuzhiyun 	    fll->sync_freq == Fref && fll->fout == Fout)
2585*4882a593Smuzhiyun 		return 0;
2586*4882a593Smuzhiyun 
2587*4882a593Smuzhiyun 	if (Fout) {
2588*4882a593Smuzhiyun 		if (fll->ref_src >= 0) {
2589*4882a593Smuzhiyun 			ret = arizona_validate_fll(fll, fll->ref_freq, Fout);
2590*4882a593Smuzhiyun 			if (ret != 0)
2591*4882a593Smuzhiyun 				return ret;
2592*4882a593Smuzhiyun 		}
2593*4882a593Smuzhiyun 
2594*4882a593Smuzhiyun 		ret = arizona_validate_fll(fll, Fref, Fout);
2595*4882a593Smuzhiyun 		if (ret != 0)
2596*4882a593Smuzhiyun 			return ret;
2597*4882a593Smuzhiyun 	}
2598*4882a593Smuzhiyun 
2599*4882a593Smuzhiyun 	fll->sync_src = source;
2600*4882a593Smuzhiyun 	fll->sync_freq = Fref;
2601*4882a593Smuzhiyun 	fll->fout = Fout;
2602*4882a593Smuzhiyun 
2603*4882a593Smuzhiyun 	if (Fout)
2604*4882a593Smuzhiyun 		ret = arizona_enable_fll(fll);
2605*4882a593Smuzhiyun 	else
2606*4882a593Smuzhiyun 		arizona_disable_fll(fll);
2607*4882a593Smuzhiyun 
2608*4882a593Smuzhiyun 	return ret;
2609*4882a593Smuzhiyun }
2610*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_set_fll);
2611*4882a593Smuzhiyun 
arizona_init_fll(struct arizona * arizona,int id,int base,int lock_irq,int ok_irq,struct arizona_fll * fll)2612*4882a593Smuzhiyun int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
2613*4882a593Smuzhiyun 		     int ok_irq, struct arizona_fll *fll)
2614*4882a593Smuzhiyun {
2615*4882a593Smuzhiyun 	unsigned int val;
2616*4882a593Smuzhiyun 
2617*4882a593Smuzhiyun 	fll->id = id;
2618*4882a593Smuzhiyun 	fll->base = base;
2619*4882a593Smuzhiyun 	fll->arizona = arizona;
2620*4882a593Smuzhiyun 	fll->sync_src = ARIZONA_FLL_SRC_NONE;
2621*4882a593Smuzhiyun 
2622*4882a593Smuzhiyun 	/* Configure default refclk to 32kHz if we have one */
2623*4882a593Smuzhiyun 	regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
2624*4882a593Smuzhiyun 	switch (val & ARIZONA_CLK_32K_SRC_MASK) {
2625*4882a593Smuzhiyun 	case ARIZONA_CLK_SRC_MCLK1:
2626*4882a593Smuzhiyun 	case ARIZONA_CLK_SRC_MCLK2:
2627*4882a593Smuzhiyun 		fll->ref_src = val & ARIZONA_CLK_32K_SRC_MASK;
2628*4882a593Smuzhiyun 		break;
2629*4882a593Smuzhiyun 	default:
2630*4882a593Smuzhiyun 		fll->ref_src = ARIZONA_FLL_SRC_NONE;
2631*4882a593Smuzhiyun 	}
2632*4882a593Smuzhiyun 	fll->ref_freq = 32768;
2633*4882a593Smuzhiyun 
2634*4882a593Smuzhiyun 	snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id);
2635*4882a593Smuzhiyun 	snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
2636*4882a593Smuzhiyun 		 "FLL%d clock OK", id);
2637*4882a593Smuzhiyun 
2638*4882a593Smuzhiyun 	regmap_update_bits(arizona->regmap, fll->base + 1,
2639*4882a593Smuzhiyun 			   ARIZONA_FLL1_FREERUN, 0);
2640*4882a593Smuzhiyun 
2641*4882a593Smuzhiyun 	return 0;
2642*4882a593Smuzhiyun }
2643*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_init_fll);
2644*4882a593Smuzhiyun 
2645*4882a593Smuzhiyun /**
2646*4882a593Smuzhiyun  * arizona_set_output_mode - Set the mode of the specified output
2647*4882a593Smuzhiyun  *
2648*4882a593Smuzhiyun  * @component: Device to configure
2649*4882a593Smuzhiyun  * @output: Output number
2650*4882a593Smuzhiyun  * @diff: True to set the output to differential mode
2651*4882a593Smuzhiyun  *
2652*4882a593Smuzhiyun  * Some systems use external analogue switches to connect more
2653*4882a593Smuzhiyun  * analogue devices to the CODEC than are supported by the device.  In
2654*4882a593Smuzhiyun  * some systems this requires changing the switched output from single
2655*4882a593Smuzhiyun  * ended to differential mode dynamically at runtime, an operation
2656*4882a593Smuzhiyun  * supported using this function.
2657*4882a593Smuzhiyun  *
2658*4882a593Smuzhiyun  * Most systems have a single static configuration and should use
2659*4882a593Smuzhiyun  * platform data instead.
2660*4882a593Smuzhiyun  */
arizona_set_output_mode(struct snd_soc_component * component,int output,bool diff)2661*4882a593Smuzhiyun int arizona_set_output_mode(struct snd_soc_component *component, int output,
2662*4882a593Smuzhiyun 			    bool diff)
2663*4882a593Smuzhiyun {
2664*4882a593Smuzhiyun 	unsigned int reg, val;
2665*4882a593Smuzhiyun 
2666*4882a593Smuzhiyun 	if (output < 1 || output > 6)
2667*4882a593Smuzhiyun 		return -EINVAL;
2668*4882a593Smuzhiyun 
2669*4882a593Smuzhiyun 	reg = ARIZONA_OUTPUT_PATH_CONFIG_1L + (output - 1) * 8;
2670*4882a593Smuzhiyun 
2671*4882a593Smuzhiyun 	if (diff)
2672*4882a593Smuzhiyun 		val = ARIZONA_OUT1_MONO;
2673*4882a593Smuzhiyun 	else
2674*4882a593Smuzhiyun 		val = 0;
2675*4882a593Smuzhiyun 
2676*4882a593Smuzhiyun 	return snd_soc_component_update_bits(component, reg,
2677*4882a593Smuzhiyun 					     ARIZONA_OUT1_MONO, val);
2678*4882a593Smuzhiyun }
2679*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_set_output_mode);
2680*4882a593Smuzhiyun 
2681*4882a593Smuzhiyun static const struct soc_enum arizona_adsp2_rate_enum[] = {
2682*4882a593Smuzhiyun 	SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP1_CONTROL_1,
2683*4882a593Smuzhiyun 			      ARIZONA_DSP1_RATE_SHIFT, 0xf,
2684*4882a593Smuzhiyun 			      ARIZONA_RATE_ENUM_SIZE,
2685*4882a593Smuzhiyun 			      arizona_rate_text, arizona_rate_val),
2686*4882a593Smuzhiyun 	SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP2_CONTROL_1,
2687*4882a593Smuzhiyun 			      ARIZONA_DSP1_RATE_SHIFT, 0xf,
2688*4882a593Smuzhiyun 			      ARIZONA_RATE_ENUM_SIZE,
2689*4882a593Smuzhiyun 			      arizona_rate_text, arizona_rate_val),
2690*4882a593Smuzhiyun 	SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP3_CONTROL_1,
2691*4882a593Smuzhiyun 			      ARIZONA_DSP1_RATE_SHIFT, 0xf,
2692*4882a593Smuzhiyun 			      ARIZONA_RATE_ENUM_SIZE,
2693*4882a593Smuzhiyun 			      arizona_rate_text, arizona_rate_val),
2694*4882a593Smuzhiyun 	SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP4_CONTROL_1,
2695*4882a593Smuzhiyun 			      ARIZONA_DSP1_RATE_SHIFT, 0xf,
2696*4882a593Smuzhiyun 			      ARIZONA_RATE_ENUM_SIZE,
2697*4882a593Smuzhiyun 			      arizona_rate_text, arizona_rate_val),
2698*4882a593Smuzhiyun };
2699*4882a593Smuzhiyun 
2700*4882a593Smuzhiyun const struct snd_kcontrol_new arizona_adsp2_rate_controls[] = {
2701*4882a593Smuzhiyun 	SOC_ENUM("DSP1 Rate", arizona_adsp2_rate_enum[0]),
2702*4882a593Smuzhiyun 	SOC_ENUM("DSP2 Rate", arizona_adsp2_rate_enum[1]),
2703*4882a593Smuzhiyun 	SOC_ENUM("DSP3 Rate", arizona_adsp2_rate_enum[2]),
2704*4882a593Smuzhiyun 	SOC_ENUM("DSP4 Rate", arizona_adsp2_rate_enum[3]),
2705*4882a593Smuzhiyun };
2706*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_adsp2_rate_controls);
2707*4882a593Smuzhiyun 
arizona_eq_filter_unstable(bool mode,__be16 _a,__be16 _b)2708*4882a593Smuzhiyun static bool arizona_eq_filter_unstable(bool mode, __be16 _a, __be16 _b)
2709*4882a593Smuzhiyun {
2710*4882a593Smuzhiyun 	s16 a = be16_to_cpu(_a);
2711*4882a593Smuzhiyun 	s16 b = be16_to_cpu(_b);
2712*4882a593Smuzhiyun 
2713*4882a593Smuzhiyun 	if (!mode) {
2714*4882a593Smuzhiyun 		return abs(a) >= 4096;
2715*4882a593Smuzhiyun 	} else {
2716*4882a593Smuzhiyun 		if (abs(b) >= 4096)
2717*4882a593Smuzhiyun 			return true;
2718*4882a593Smuzhiyun 
2719*4882a593Smuzhiyun 		return (abs((a << 16) / (4096 - b)) >= 4096 << 4);
2720*4882a593Smuzhiyun 	}
2721*4882a593Smuzhiyun }
2722*4882a593Smuzhiyun 
arizona_eq_coeff_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)2723*4882a593Smuzhiyun int arizona_eq_coeff_put(struct snd_kcontrol *kcontrol,
2724*4882a593Smuzhiyun 			 struct snd_ctl_elem_value *ucontrol)
2725*4882a593Smuzhiyun {
2726*4882a593Smuzhiyun 	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
2727*4882a593Smuzhiyun 	struct arizona *arizona = dev_get_drvdata(component->dev->parent);
2728*4882a593Smuzhiyun 	struct soc_bytes *params = (void *)kcontrol->private_value;
2729*4882a593Smuzhiyun 	unsigned int val;
2730*4882a593Smuzhiyun 	__be16 *data;
2731*4882a593Smuzhiyun 	int len;
2732*4882a593Smuzhiyun 	int ret;
2733*4882a593Smuzhiyun 
2734*4882a593Smuzhiyun 	len = params->num_regs * regmap_get_val_bytes(arizona->regmap);
2735*4882a593Smuzhiyun 
2736*4882a593Smuzhiyun 	data = kmemdup(ucontrol->value.bytes.data, len, GFP_KERNEL | GFP_DMA);
2737*4882a593Smuzhiyun 	if (!data)
2738*4882a593Smuzhiyun 		return -ENOMEM;
2739*4882a593Smuzhiyun 
2740*4882a593Smuzhiyun 	data[0] &= cpu_to_be16(ARIZONA_EQ1_B1_MODE);
2741*4882a593Smuzhiyun 
2742*4882a593Smuzhiyun 	if (arizona_eq_filter_unstable(!!data[0], data[1], data[2]) ||
2743*4882a593Smuzhiyun 	    arizona_eq_filter_unstable(true, data[4], data[5]) ||
2744*4882a593Smuzhiyun 	    arizona_eq_filter_unstable(true, data[8], data[9]) ||
2745*4882a593Smuzhiyun 	    arizona_eq_filter_unstable(true, data[12], data[13]) ||
2746*4882a593Smuzhiyun 	    arizona_eq_filter_unstable(false, data[16], data[17])) {
2747*4882a593Smuzhiyun 		dev_err(arizona->dev, "Rejecting unstable EQ coefficients\n");
2748*4882a593Smuzhiyun 		ret = -EINVAL;
2749*4882a593Smuzhiyun 		goto out;
2750*4882a593Smuzhiyun 	}
2751*4882a593Smuzhiyun 
2752*4882a593Smuzhiyun 	ret = regmap_read(arizona->regmap, params->base, &val);
2753*4882a593Smuzhiyun 	if (ret != 0)
2754*4882a593Smuzhiyun 		goto out;
2755*4882a593Smuzhiyun 
2756*4882a593Smuzhiyun 	val &= ~ARIZONA_EQ1_B1_MODE;
2757*4882a593Smuzhiyun 	data[0] |= cpu_to_be16(val);
2758*4882a593Smuzhiyun 
2759*4882a593Smuzhiyun 	ret = regmap_raw_write(arizona->regmap, params->base, data, len);
2760*4882a593Smuzhiyun 
2761*4882a593Smuzhiyun out:
2762*4882a593Smuzhiyun 	kfree(data);
2763*4882a593Smuzhiyun 	return ret;
2764*4882a593Smuzhiyun }
2765*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_eq_coeff_put);
2766*4882a593Smuzhiyun 
arizona_lhpf_coeff_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)2767*4882a593Smuzhiyun int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol,
2768*4882a593Smuzhiyun 			   struct snd_ctl_elem_value *ucontrol)
2769*4882a593Smuzhiyun {
2770*4882a593Smuzhiyun 	struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
2771*4882a593Smuzhiyun 	struct arizona *arizona = dev_get_drvdata(component->dev->parent);
2772*4882a593Smuzhiyun 	__be16 *data = (__be16 *)ucontrol->value.bytes.data;
2773*4882a593Smuzhiyun 	s16 val = be16_to_cpu(*data);
2774*4882a593Smuzhiyun 
2775*4882a593Smuzhiyun 	if (abs(val) >= 4096) {
2776*4882a593Smuzhiyun 		dev_err(arizona->dev, "Rejecting unstable LHPF coefficients\n");
2777*4882a593Smuzhiyun 		return -EINVAL;
2778*4882a593Smuzhiyun 	}
2779*4882a593Smuzhiyun 
2780*4882a593Smuzhiyun 	return snd_soc_bytes_put(kcontrol, ucontrol);
2781*4882a593Smuzhiyun }
2782*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_lhpf_coeff_put);
2783*4882a593Smuzhiyun 
arizona_of_get_audio_pdata(struct arizona * arizona)2784*4882a593Smuzhiyun int arizona_of_get_audio_pdata(struct arizona *arizona)
2785*4882a593Smuzhiyun {
2786*4882a593Smuzhiyun 	struct arizona_pdata *pdata = &arizona->pdata;
2787*4882a593Smuzhiyun 	struct device_node *np = arizona->dev->of_node;
2788*4882a593Smuzhiyun 	struct property *prop;
2789*4882a593Smuzhiyun 	const __be32 *cur;
2790*4882a593Smuzhiyun 	u32 val;
2791*4882a593Smuzhiyun 	u32 pdm_val[ARIZONA_MAX_PDM_SPK];
2792*4882a593Smuzhiyun 	int ret;
2793*4882a593Smuzhiyun 	int count = 0;
2794*4882a593Smuzhiyun 
2795*4882a593Smuzhiyun 	count = 0;
2796*4882a593Smuzhiyun 	of_property_for_each_u32(np, "wlf,inmode", prop, cur, val) {
2797*4882a593Smuzhiyun 		if (count == ARRAY_SIZE(pdata->inmode))
2798*4882a593Smuzhiyun 			break;
2799*4882a593Smuzhiyun 
2800*4882a593Smuzhiyun 		pdata->inmode[count] = val;
2801*4882a593Smuzhiyun 		count++;
2802*4882a593Smuzhiyun 	}
2803*4882a593Smuzhiyun 
2804*4882a593Smuzhiyun 	count = 0;
2805*4882a593Smuzhiyun 	of_property_for_each_u32(np, "wlf,dmic-ref", prop, cur, val) {
2806*4882a593Smuzhiyun 		if (count == ARRAY_SIZE(pdata->dmic_ref))
2807*4882a593Smuzhiyun 			break;
2808*4882a593Smuzhiyun 
2809*4882a593Smuzhiyun 		pdata->dmic_ref[count] = val;
2810*4882a593Smuzhiyun 		count++;
2811*4882a593Smuzhiyun 	}
2812*4882a593Smuzhiyun 
2813*4882a593Smuzhiyun 	count = 0;
2814*4882a593Smuzhiyun 	of_property_for_each_u32(np, "wlf,out-mono", prop, cur, val) {
2815*4882a593Smuzhiyun 		if (count == ARRAY_SIZE(pdata->out_mono))
2816*4882a593Smuzhiyun 			break;
2817*4882a593Smuzhiyun 
2818*4882a593Smuzhiyun 		pdata->out_mono[count] = !!val;
2819*4882a593Smuzhiyun 		count++;
2820*4882a593Smuzhiyun 	}
2821*4882a593Smuzhiyun 
2822*4882a593Smuzhiyun 	count = 0;
2823*4882a593Smuzhiyun 	of_property_for_each_u32(np, "wlf,max-channels-clocked", prop, cur, val) {
2824*4882a593Smuzhiyun 		if (count == ARRAY_SIZE(pdata->max_channels_clocked))
2825*4882a593Smuzhiyun 			break;
2826*4882a593Smuzhiyun 
2827*4882a593Smuzhiyun 		pdata->max_channels_clocked[count] = val;
2828*4882a593Smuzhiyun 		count++;
2829*4882a593Smuzhiyun 	}
2830*4882a593Smuzhiyun 
2831*4882a593Smuzhiyun 	count = 0;
2832*4882a593Smuzhiyun 	of_property_for_each_u32(np, "wlf,out-volume-limit", prop, cur, val) {
2833*4882a593Smuzhiyun 		if (count == ARRAY_SIZE(pdata->out_vol_limit))
2834*4882a593Smuzhiyun 			break;
2835*4882a593Smuzhiyun 
2836*4882a593Smuzhiyun 		pdata->out_vol_limit[count] = val;
2837*4882a593Smuzhiyun 		count++;
2838*4882a593Smuzhiyun 	}
2839*4882a593Smuzhiyun 
2840*4882a593Smuzhiyun 	ret = of_property_read_u32_array(np, "wlf,spk-fmt",
2841*4882a593Smuzhiyun 					 pdm_val, ARRAY_SIZE(pdm_val));
2842*4882a593Smuzhiyun 
2843*4882a593Smuzhiyun 	if (ret >= 0)
2844*4882a593Smuzhiyun 		for (count = 0; count < ARRAY_SIZE(pdata->spk_fmt); ++count)
2845*4882a593Smuzhiyun 			pdata->spk_fmt[count] = pdm_val[count];
2846*4882a593Smuzhiyun 
2847*4882a593Smuzhiyun 	ret = of_property_read_u32_array(np, "wlf,spk-mute",
2848*4882a593Smuzhiyun 					 pdm_val, ARRAY_SIZE(pdm_val));
2849*4882a593Smuzhiyun 
2850*4882a593Smuzhiyun 	if (ret >= 0)
2851*4882a593Smuzhiyun 		for (count = 0; count < ARRAY_SIZE(pdata->spk_mute); ++count)
2852*4882a593Smuzhiyun 			pdata->spk_mute[count] = pdm_val[count];
2853*4882a593Smuzhiyun 
2854*4882a593Smuzhiyun 	return 0;
2855*4882a593Smuzhiyun }
2856*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(arizona_of_get_audio_pdata);
2857*4882a593Smuzhiyun 
2858*4882a593Smuzhiyun MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
2859*4882a593Smuzhiyun MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
2860*4882a593Smuzhiyun MODULE_LICENSE("GPL");
2861