xref: /OK3568_Linux_fs/kernel/sound/soc/codecs/adau1977.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * ADAU1977/ADAU1978/ADAU1979 driver
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright 2014 Analog Devices Inc.
6*4882a593Smuzhiyun  *  Author: Lars-Peter Clausen <lars@metafoo.de>
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <linux/delay.h>
10*4882a593Smuzhiyun #include <linux/device.h>
11*4882a593Smuzhiyun #include <linux/gpio/consumer.h>
12*4882a593Smuzhiyun #include <linux/i2c.h>
13*4882a593Smuzhiyun #include <linux/init.h>
14*4882a593Smuzhiyun #include <linux/module.h>
15*4882a593Smuzhiyun #include <linux/platform_data/adau1977.h>
16*4882a593Smuzhiyun #include <linux/regmap.h>
17*4882a593Smuzhiyun #include <linux/regulator/consumer.h>
18*4882a593Smuzhiyun #include <linux/slab.h>
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #include <sound/core.h>
21*4882a593Smuzhiyun #include <sound/initval.h>
22*4882a593Smuzhiyun #include <sound/pcm.h>
23*4882a593Smuzhiyun #include <sound/pcm_params.h>
24*4882a593Smuzhiyun #include <sound/soc.h>
25*4882a593Smuzhiyun #include <sound/tlv.h>
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun #include "adau1977.h"
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun #define ADAU1977_REG_POWER		0x00
30*4882a593Smuzhiyun #define ADAU1977_REG_PLL		0x01
31*4882a593Smuzhiyun #define ADAU1977_REG_BOOST		0x02
32*4882a593Smuzhiyun #define ADAU1977_REG_MICBIAS		0x03
33*4882a593Smuzhiyun #define ADAU1977_REG_BLOCK_POWER_SAI	0x04
34*4882a593Smuzhiyun #define ADAU1977_REG_SAI_CTRL0		0x05
35*4882a593Smuzhiyun #define ADAU1977_REG_SAI_CTRL1		0x06
36*4882a593Smuzhiyun #define ADAU1977_REG_CMAP12		0x07
37*4882a593Smuzhiyun #define ADAU1977_REG_CMAP34		0x08
38*4882a593Smuzhiyun #define ADAU1977_REG_SAI_OVERTEMP	0x09
39*4882a593Smuzhiyun #define ADAU1977_REG_POST_ADC_GAIN(x)	(0x0a + (x))
40*4882a593Smuzhiyun #define ADAU1977_REG_MISC_CONTROL	0x0e
41*4882a593Smuzhiyun #define ADAU1977_REG_DIAG_CONTROL	0x10
42*4882a593Smuzhiyun #define ADAU1977_REG_STATUS(x)		(0x11 + (x))
43*4882a593Smuzhiyun #define ADAU1977_REG_DIAG_IRQ1		0x15
44*4882a593Smuzhiyun #define ADAU1977_REG_DIAG_IRQ2		0x16
45*4882a593Smuzhiyun #define ADAU1977_REG_ADJUST1		0x17
46*4882a593Smuzhiyun #define ADAU1977_REG_ADJUST2		0x18
47*4882a593Smuzhiyun #define ADAU1977_REG_ADC_CLIP		0x19
48*4882a593Smuzhiyun #define ADAU1977_REG_DC_HPF_CAL		0x1a
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun #define ADAU1977_POWER_RESET			BIT(7)
51*4882a593Smuzhiyun #define ADAU1977_POWER_PWUP			BIT(0)
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun #define ADAU1977_PLL_CLK_S			BIT(4)
54*4882a593Smuzhiyun #define ADAU1977_PLL_MCS_MASK			0x7
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun #define ADAU1977_MICBIAS_MB_VOLTS_MASK		0xf0
57*4882a593Smuzhiyun #define ADAU1977_MICBIAS_MB_VOLTS_OFFSET	4
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun #define ADAU1977_BLOCK_POWER_SAI_LR_POL		BIT(7)
60*4882a593Smuzhiyun #define ADAU1977_BLOCK_POWER_SAI_BCLK_EDGE	BIT(6)
61*4882a593Smuzhiyun #define ADAU1977_BLOCK_POWER_SAI_LDO_EN		BIT(5)
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun #define ADAU1977_SAI_CTRL0_FMT_MASK		(0x3 << 6)
64*4882a593Smuzhiyun #define ADAU1977_SAI_CTRL0_FMT_I2S		(0x0 << 6)
65*4882a593Smuzhiyun #define ADAU1977_SAI_CTRL0_FMT_LJ		(0x1 << 6)
66*4882a593Smuzhiyun #define ADAU1977_SAI_CTRL0_FMT_RJ_24BIT		(0x2 << 6)
67*4882a593Smuzhiyun #define ADAU1977_SAI_CTRL0_FMT_RJ_16BIT		(0x3 << 6)
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun #define ADAU1977_SAI_CTRL0_SAI_MASK		(0x7 << 3)
70*4882a593Smuzhiyun #define ADAU1977_SAI_CTRL0_SAI_I2S		(0x0 << 3)
71*4882a593Smuzhiyun #define ADAU1977_SAI_CTRL0_SAI_TDM_2		(0x1 << 3)
72*4882a593Smuzhiyun #define ADAU1977_SAI_CTRL0_SAI_TDM_4		(0x2 << 3)
73*4882a593Smuzhiyun #define ADAU1977_SAI_CTRL0_SAI_TDM_8		(0x3 << 3)
74*4882a593Smuzhiyun #define ADAU1977_SAI_CTRL0_SAI_TDM_16		(0x4 << 3)
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun #define ADAU1977_SAI_CTRL0_FS_MASK		(0x7)
77*4882a593Smuzhiyun #define ADAU1977_SAI_CTRL0_FS_8000_12000	(0x0)
78*4882a593Smuzhiyun #define ADAU1977_SAI_CTRL0_FS_16000_24000	(0x1)
79*4882a593Smuzhiyun #define ADAU1977_SAI_CTRL0_FS_32000_48000	(0x2)
80*4882a593Smuzhiyun #define ADAU1977_SAI_CTRL0_FS_64000_96000	(0x3)
81*4882a593Smuzhiyun #define ADAU1977_SAI_CTRL0_FS_128000_192000	(0x4)
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun #define ADAU1977_SAI_CTRL1_SLOT_WIDTH_MASK	(0x3 << 5)
84*4882a593Smuzhiyun #define ADAU1977_SAI_CTRL1_SLOT_WIDTH_32	(0x0 << 5)
85*4882a593Smuzhiyun #define ADAU1977_SAI_CTRL1_SLOT_WIDTH_24	(0x1 << 5)
86*4882a593Smuzhiyun #define ADAU1977_SAI_CTRL1_SLOT_WIDTH_16	(0x2 << 5)
87*4882a593Smuzhiyun #define ADAU1977_SAI_CTRL1_DATA_WIDTH_MASK	(0x1 << 4)
88*4882a593Smuzhiyun #define ADAU1977_SAI_CTRL1_DATA_WIDTH_16BIT	(0x1 << 4)
89*4882a593Smuzhiyun #define ADAU1977_SAI_CTRL1_DATA_WIDTH_24BIT	(0x0 << 4)
90*4882a593Smuzhiyun #define ADAU1977_SAI_CTRL1_LRCLK_PULSE		BIT(3)
91*4882a593Smuzhiyun #define ADAU1977_SAI_CTRL1_MSB			BIT(2)
92*4882a593Smuzhiyun #define ADAU1977_SAI_CTRL1_BCLKRATE_16		(0x1 << 1)
93*4882a593Smuzhiyun #define ADAU1977_SAI_CTRL1_BCLKRATE_32		(0x0 << 1)
94*4882a593Smuzhiyun #define ADAU1977_SAI_CTRL1_BCLKRATE_MASK	(0x1 << 1)
95*4882a593Smuzhiyun #define ADAU1977_SAI_CTRL1_MASTER		BIT(0)
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun #define ADAU1977_SAI_OVERTEMP_DRV_C(x)		BIT(4 + (x))
98*4882a593Smuzhiyun #define ADAU1977_SAI_OVERTEMP_DRV_HIZ		BIT(3)
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun #define ADAU1977_MISC_CONTROL_SUM_MODE_MASK	(0x3 << 6)
101*4882a593Smuzhiyun #define ADAU1977_MISC_CONTROL_SUM_MODE_1CH	(0x2 << 6)
102*4882a593Smuzhiyun #define ADAU1977_MISC_CONTROL_SUM_MODE_2CH	(0x1 << 6)
103*4882a593Smuzhiyun #define ADAU1977_MISC_CONTROL_SUM_MODE_4CH	(0x0 << 6)
104*4882a593Smuzhiyun #define ADAU1977_MISC_CONTROL_MMUTE		BIT(4)
105*4882a593Smuzhiyun #define ADAU1977_MISC_CONTROL_DC_CAL		BIT(0)
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun #define ADAU1977_CHAN_MAP_SECOND_SLOT_OFFSET	4
108*4882a593Smuzhiyun #define ADAU1977_CHAN_MAP_FIRST_SLOT_OFFSET	0
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun struct adau1977 {
111*4882a593Smuzhiyun 	struct regmap *regmap;
112*4882a593Smuzhiyun 	bool right_j;
113*4882a593Smuzhiyun 	unsigned int sysclk;
114*4882a593Smuzhiyun 	enum adau1977_sysclk_src sysclk_src;
115*4882a593Smuzhiyun 	struct gpio_desc *reset_gpio;
116*4882a593Smuzhiyun 	enum adau1977_type type;
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 	struct regulator *avdd_reg;
119*4882a593Smuzhiyun 	struct regulator *dvdd_reg;
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	struct snd_pcm_hw_constraint_list constraints;
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 	struct device *dev;
124*4882a593Smuzhiyun 	void (*switch_mode)(struct device *dev);
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun 	unsigned int max_master_fs;
127*4882a593Smuzhiyun 	unsigned int slot_width;
128*4882a593Smuzhiyun 	bool enabled;
129*4882a593Smuzhiyun 	bool master;
130*4882a593Smuzhiyun };
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun static const struct reg_default adau1977_reg_defaults[] = {
133*4882a593Smuzhiyun 	{ 0x00, 0x00 },
134*4882a593Smuzhiyun 	{ 0x01, 0x41 },
135*4882a593Smuzhiyun 	{ 0x02, 0x4a },
136*4882a593Smuzhiyun 	{ 0x03, 0x7d },
137*4882a593Smuzhiyun 	{ 0x04, 0x3d },
138*4882a593Smuzhiyun 	{ 0x05, 0x02 },
139*4882a593Smuzhiyun 	{ 0x06, 0x00 },
140*4882a593Smuzhiyun 	{ 0x07, 0x10 },
141*4882a593Smuzhiyun 	{ 0x08, 0x32 },
142*4882a593Smuzhiyun 	{ 0x09, 0xf0 },
143*4882a593Smuzhiyun 	{ 0x0a, 0xa0 },
144*4882a593Smuzhiyun 	{ 0x0b, 0xa0 },
145*4882a593Smuzhiyun 	{ 0x0c, 0xa0 },
146*4882a593Smuzhiyun 	{ 0x0d, 0xa0 },
147*4882a593Smuzhiyun 	{ 0x0e, 0x02 },
148*4882a593Smuzhiyun 	{ 0x10, 0x0f },
149*4882a593Smuzhiyun 	{ 0x15, 0x20 },
150*4882a593Smuzhiyun 	{ 0x16, 0x00 },
151*4882a593Smuzhiyun 	{ 0x17, 0x00 },
152*4882a593Smuzhiyun 	{ 0x18, 0x00 },
153*4882a593Smuzhiyun 	{ 0x1a, 0x00 },
154*4882a593Smuzhiyun };
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun static const DECLARE_TLV_DB_MINMAX_MUTE(adau1977_adc_gain, -3562, 6000);
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun static const struct snd_soc_dapm_widget adau1977_micbias_dapm_widgets[] = {
159*4882a593Smuzhiyun 	SND_SOC_DAPM_SUPPLY("MICBIAS", ADAU1977_REG_MICBIAS,
160*4882a593Smuzhiyun 		3, 0, NULL, 0)
161*4882a593Smuzhiyun };
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun static const struct snd_soc_dapm_widget adau1977_dapm_widgets[] = {
164*4882a593Smuzhiyun 	SND_SOC_DAPM_SUPPLY("Vref", ADAU1977_REG_BLOCK_POWER_SAI,
165*4882a593Smuzhiyun 		4, 0, NULL, 0),
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	SND_SOC_DAPM_ADC("ADC1", "Capture", ADAU1977_REG_BLOCK_POWER_SAI, 0, 0),
168*4882a593Smuzhiyun 	SND_SOC_DAPM_ADC("ADC2", "Capture", ADAU1977_REG_BLOCK_POWER_SAI, 1, 0),
169*4882a593Smuzhiyun 	SND_SOC_DAPM_ADC("ADC3", "Capture", ADAU1977_REG_BLOCK_POWER_SAI, 2, 0),
170*4882a593Smuzhiyun 	SND_SOC_DAPM_ADC("ADC4", "Capture", ADAU1977_REG_BLOCK_POWER_SAI, 3, 0),
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	SND_SOC_DAPM_INPUT("AIN1"),
173*4882a593Smuzhiyun 	SND_SOC_DAPM_INPUT("AIN2"),
174*4882a593Smuzhiyun 	SND_SOC_DAPM_INPUT("AIN3"),
175*4882a593Smuzhiyun 	SND_SOC_DAPM_INPUT("AIN4"),
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 	SND_SOC_DAPM_OUTPUT("VREF"),
178*4882a593Smuzhiyun };
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun static const struct snd_soc_dapm_route adau1977_dapm_routes[] = {
181*4882a593Smuzhiyun 	{ "ADC1", NULL, "AIN1" },
182*4882a593Smuzhiyun 	{ "ADC2", NULL, "AIN2" },
183*4882a593Smuzhiyun 	{ "ADC3", NULL, "AIN3" },
184*4882a593Smuzhiyun 	{ "ADC4", NULL, "AIN4" },
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 	{ "ADC1", NULL, "Vref" },
187*4882a593Smuzhiyun 	{ "ADC2", NULL, "Vref" },
188*4882a593Smuzhiyun 	{ "ADC3", NULL, "Vref" },
189*4882a593Smuzhiyun 	{ "ADC4", NULL, "Vref" },
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	{ "VREF", NULL, "Vref" },
192*4882a593Smuzhiyun };
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun #define ADAU1977_VOLUME(x) \
195*4882a593Smuzhiyun 	SOC_SINGLE_TLV("ADC" #x " Capture Volume", \
196*4882a593Smuzhiyun 		ADAU1977_REG_POST_ADC_GAIN((x) - 1), \
197*4882a593Smuzhiyun 		0, 255, 1, adau1977_adc_gain)
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun #define ADAU1977_HPF_SWITCH(x) \
200*4882a593Smuzhiyun 	SOC_SINGLE("ADC" #x " Highpass-Filter Capture Switch", \
201*4882a593Smuzhiyun 		ADAU1977_REG_DC_HPF_CAL, (x) - 1, 1, 0)
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun #define ADAU1977_DC_SUB_SWITCH(x) \
204*4882a593Smuzhiyun 	SOC_SINGLE("ADC" #x " DC Subtraction Capture Switch", \
205*4882a593Smuzhiyun 		ADAU1977_REG_DC_HPF_CAL, (x) + 3, 1, 0)
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun static const struct snd_kcontrol_new adau1977_snd_controls[] = {
208*4882a593Smuzhiyun 	ADAU1977_VOLUME(1),
209*4882a593Smuzhiyun 	ADAU1977_VOLUME(2),
210*4882a593Smuzhiyun 	ADAU1977_VOLUME(3),
211*4882a593Smuzhiyun 	ADAU1977_VOLUME(4),
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	ADAU1977_HPF_SWITCH(1),
214*4882a593Smuzhiyun 	ADAU1977_HPF_SWITCH(2),
215*4882a593Smuzhiyun 	ADAU1977_HPF_SWITCH(3),
216*4882a593Smuzhiyun 	ADAU1977_HPF_SWITCH(4),
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 	ADAU1977_DC_SUB_SWITCH(1),
219*4882a593Smuzhiyun 	ADAU1977_DC_SUB_SWITCH(2),
220*4882a593Smuzhiyun 	ADAU1977_DC_SUB_SWITCH(3),
221*4882a593Smuzhiyun 	ADAU1977_DC_SUB_SWITCH(4),
222*4882a593Smuzhiyun };
223*4882a593Smuzhiyun 
adau1977_reset(struct adau1977 * adau1977)224*4882a593Smuzhiyun static int adau1977_reset(struct adau1977 *adau1977)
225*4882a593Smuzhiyun {
226*4882a593Smuzhiyun 	int ret;
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 	/*
229*4882a593Smuzhiyun 	 * The reset bit is obviously volatile, but we need to be able to cache
230*4882a593Smuzhiyun 	 * the other bits in the register, so we can't just mark the whole
231*4882a593Smuzhiyun 	 * register as volatile. Since this is the only place where we'll ever
232*4882a593Smuzhiyun 	 * touch the reset bit just bypass the cache for this operation.
233*4882a593Smuzhiyun 	 */
234*4882a593Smuzhiyun 	regcache_cache_bypass(adau1977->regmap, true);
235*4882a593Smuzhiyun 	ret = regmap_write(adau1977->regmap, ADAU1977_REG_POWER,
236*4882a593Smuzhiyun 			ADAU1977_POWER_RESET);
237*4882a593Smuzhiyun 	regcache_cache_bypass(adau1977->regmap, false);
238*4882a593Smuzhiyun 	if (ret)
239*4882a593Smuzhiyun 		return ret;
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 	return ret;
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun /*
245*4882a593Smuzhiyun  * Returns the appropriate setting for ths FS field in the CTRL0 register
246*4882a593Smuzhiyun  * depending on the rate.
247*4882a593Smuzhiyun  */
adau1977_lookup_fs(unsigned int rate)248*4882a593Smuzhiyun static int adau1977_lookup_fs(unsigned int rate)
249*4882a593Smuzhiyun {
250*4882a593Smuzhiyun 	if (rate >= 8000 && rate <= 12000)
251*4882a593Smuzhiyun 		return ADAU1977_SAI_CTRL0_FS_8000_12000;
252*4882a593Smuzhiyun 	else if (rate >= 16000 && rate <= 24000)
253*4882a593Smuzhiyun 		return ADAU1977_SAI_CTRL0_FS_16000_24000;
254*4882a593Smuzhiyun 	else if (rate >= 32000 && rate <= 48000)
255*4882a593Smuzhiyun 		return ADAU1977_SAI_CTRL0_FS_32000_48000;
256*4882a593Smuzhiyun 	else if (rate >= 64000 && rate <= 96000)
257*4882a593Smuzhiyun 		return ADAU1977_SAI_CTRL0_FS_64000_96000;
258*4882a593Smuzhiyun 	else if (rate >= 128000 && rate <= 192000)
259*4882a593Smuzhiyun 		return ADAU1977_SAI_CTRL0_FS_128000_192000;
260*4882a593Smuzhiyun 	else
261*4882a593Smuzhiyun 		return -EINVAL;
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun 
adau1977_lookup_mcs(struct adau1977 * adau1977,unsigned int rate,unsigned int fs)264*4882a593Smuzhiyun static int adau1977_lookup_mcs(struct adau1977 *adau1977, unsigned int rate,
265*4882a593Smuzhiyun 	unsigned int fs)
266*4882a593Smuzhiyun {
267*4882a593Smuzhiyun 	unsigned int mcs;
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun 	/*
270*4882a593Smuzhiyun 	 * rate = sysclk / (512 * mcs_lut[mcs]) * 2**fs
271*4882a593Smuzhiyun 	 * => mcs_lut[mcs] = sysclk / (512 * rate) * 2**fs
272*4882a593Smuzhiyun 	 * => mcs_lut[mcs] = sysclk / ((512 / 2**fs) * rate)
273*4882a593Smuzhiyun 	 */
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 	rate *= 512 >> fs;
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 	if (adau1977->sysclk % rate != 0)
278*4882a593Smuzhiyun 		return -EINVAL;
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 	mcs = adau1977->sysclk / rate;
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun 	/* The factors configured by MCS are 1, 2, 3, 4, 6 */
283*4882a593Smuzhiyun 	if (mcs < 1 || mcs > 6 || mcs == 5)
284*4882a593Smuzhiyun 		return -EINVAL;
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 	mcs = mcs - 1;
287*4882a593Smuzhiyun 	if (mcs == 5)
288*4882a593Smuzhiyun 		mcs = 4;
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 	return mcs;
291*4882a593Smuzhiyun }
292*4882a593Smuzhiyun 
adau1977_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)293*4882a593Smuzhiyun static int adau1977_hw_params(struct snd_pcm_substream *substream,
294*4882a593Smuzhiyun 	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
295*4882a593Smuzhiyun {
296*4882a593Smuzhiyun 	struct snd_soc_component *component = dai->component;
297*4882a593Smuzhiyun 	struct adau1977 *adau1977 = snd_soc_component_get_drvdata(component);
298*4882a593Smuzhiyun 	unsigned int rate = params_rate(params);
299*4882a593Smuzhiyun 	unsigned int slot_width;
300*4882a593Smuzhiyun 	unsigned int ctrl0, ctrl0_mask;
301*4882a593Smuzhiyun 	unsigned int ctrl1;
302*4882a593Smuzhiyun 	int mcs, fs;
303*4882a593Smuzhiyun 	int ret;
304*4882a593Smuzhiyun 
305*4882a593Smuzhiyun 	fs = adau1977_lookup_fs(rate);
306*4882a593Smuzhiyun 	if (fs < 0)
307*4882a593Smuzhiyun 		return fs;
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun 	if (adau1977->sysclk_src == ADAU1977_SYSCLK_SRC_MCLK) {
310*4882a593Smuzhiyun 		mcs = adau1977_lookup_mcs(adau1977, rate, fs);
311*4882a593Smuzhiyun 		if (mcs < 0)
312*4882a593Smuzhiyun 			return mcs;
313*4882a593Smuzhiyun 	} else {
314*4882a593Smuzhiyun 		mcs = 0;
315*4882a593Smuzhiyun 	}
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 	ctrl0_mask = ADAU1977_SAI_CTRL0_FS_MASK;
318*4882a593Smuzhiyun 	ctrl0 = fs;
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	if (adau1977->right_j) {
321*4882a593Smuzhiyun 		switch (params_width(params)) {
322*4882a593Smuzhiyun 		case 16:
323*4882a593Smuzhiyun 			ctrl0 |= ADAU1977_SAI_CTRL0_FMT_RJ_16BIT;
324*4882a593Smuzhiyun 			break;
325*4882a593Smuzhiyun 		case 24:
326*4882a593Smuzhiyun 			ctrl0 |= ADAU1977_SAI_CTRL0_FMT_RJ_24BIT;
327*4882a593Smuzhiyun 			break;
328*4882a593Smuzhiyun 		default:
329*4882a593Smuzhiyun 			return -EINVAL;
330*4882a593Smuzhiyun 		}
331*4882a593Smuzhiyun 		ctrl0_mask |= ADAU1977_SAI_CTRL0_FMT_MASK;
332*4882a593Smuzhiyun 	}
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun 	if (adau1977->master) {
335*4882a593Smuzhiyun 		switch (params_width(params)) {
336*4882a593Smuzhiyun 		case 16:
337*4882a593Smuzhiyun 			ctrl1 = ADAU1977_SAI_CTRL1_DATA_WIDTH_16BIT;
338*4882a593Smuzhiyun 			slot_width = 16;
339*4882a593Smuzhiyun 			break;
340*4882a593Smuzhiyun 		case 24:
341*4882a593Smuzhiyun 		case 32:
342*4882a593Smuzhiyun 			ctrl1 = ADAU1977_SAI_CTRL1_DATA_WIDTH_24BIT;
343*4882a593Smuzhiyun 			slot_width = 32;
344*4882a593Smuzhiyun 			break;
345*4882a593Smuzhiyun 		default:
346*4882a593Smuzhiyun 			return -EINVAL;
347*4882a593Smuzhiyun 		}
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun 		/* In TDM mode there is a fixed slot width */
350*4882a593Smuzhiyun 		if (adau1977->slot_width)
351*4882a593Smuzhiyun 			slot_width = adau1977->slot_width;
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 		if (slot_width == 16)
354*4882a593Smuzhiyun 			ctrl1 |= ADAU1977_SAI_CTRL1_BCLKRATE_16;
355*4882a593Smuzhiyun 		else
356*4882a593Smuzhiyun 			ctrl1 |= ADAU1977_SAI_CTRL1_BCLKRATE_32;
357*4882a593Smuzhiyun 
358*4882a593Smuzhiyun 		ret = regmap_update_bits(adau1977->regmap,
359*4882a593Smuzhiyun 			ADAU1977_REG_SAI_CTRL1,
360*4882a593Smuzhiyun 			ADAU1977_SAI_CTRL1_DATA_WIDTH_MASK |
361*4882a593Smuzhiyun 			ADAU1977_SAI_CTRL1_BCLKRATE_MASK,
362*4882a593Smuzhiyun 			ctrl1);
363*4882a593Smuzhiyun 		if (ret < 0)
364*4882a593Smuzhiyun 			return ret;
365*4882a593Smuzhiyun 	}
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 	ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL0,
368*4882a593Smuzhiyun 				ctrl0_mask, ctrl0);
369*4882a593Smuzhiyun 	if (ret < 0)
370*4882a593Smuzhiyun 		return ret;
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 	return regmap_update_bits(adau1977->regmap, ADAU1977_REG_PLL,
373*4882a593Smuzhiyun 				ADAU1977_PLL_MCS_MASK, mcs);
374*4882a593Smuzhiyun }
375*4882a593Smuzhiyun 
adau1977_power_disable(struct adau1977 * adau1977)376*4882a593Smuzhiyun static int adau1977_power_disable(struct adau1977 *adau1977)
377*4882a593Smuzhiyun {
378*4882a593Smuzhiyun 	int ret = 0;
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun 	if (!adau1977->enabled)
381*4882a593Smuzhiyun 		return 0;
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun 	ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_POWER,
384*4882a593Smuzhiyun 		ADAU1977_POWER_PWUP, 0);
385*4882a593Smuzhiyun 	if (ret)
386*4882a593Smuzhiyun 		return ret;
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun 	regcache_mark_dirty(adau1977->regmap);
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun 	gpiod_set_value_cansleep(adau1977->reset_gpio, 0);
391*4882a593Smuzhiyun 
392*4882a593Smuzhiyun 	regcache_cache_only(adau1977->regmap, true);
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun 	regulator_disable(adau1977->avdd_reg);
395*4882a593Smuzhiyun 	if (adau1977->dvdd_reg)
396*4882a593Smuzhiyun 		regulator_disable(adau1977->dvdd_reg);
397*4882a593Smuzhiyun 
398*4882a593Smuzhiyun 	adau1977->enabled = false;
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun 	return 0;
401*4882a593Smuzhiyun }
402*4882a593Smuzhiyun 
adau1977_power_enable(struct adau1977 * adau1977)403*4882a593Smuzhiyun static int adau1977_power_enable(struct adau1977 *adau1977)
404*4882a593Smuzhiyun {
405*4882a593Smuzhiyun 	unsigned int val;
406*4882a593Smuzhiyun 	int ret = 0;
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun 	if (adau1977->enabled)
409*4882a593Smuzhiyun 		return 0;
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun 	ret = regulator_enable(adau1977->avdd_reg);
412*4882a593Smuzhiyun 	if (ret)
413*4882a593Smuzhiyun 		return ret;
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun 	if (adau1977->dvdd_reg) {
416*4882a593Smuzhiyun 		ret = regulator_enable(adau1977->dvdd_reg);
417*4882a593Smuzhiyun 		if (ret)
418*4882a593Smuzhiyun 			goto err_disable_avdd;
419*4882a593Smuzhiyun 	}
420*4882a593Smuzhiyun 
421*4882a593Smuzhiyun 	gpiod_set_value_cansleep(adau1977->reset_gpio, 1);
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun 	regcache_cache_only(adau1977->regmap, false);
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun 	if (adau1977->switch_mode)
426*4882a593Smuzhiyun 		adau1977->switch_mode(adau1977->dev);
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun 	ret = adau1977_reset(adau1977);
429*4882a593Smuzhiyun 	if (ret)
430*4882a593Smuzhiyun 		goto err_disable_dvdd;
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun 	ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_POWER,
433*4882a593Smuzhiyun 		ADAU1977_POWER_PWUP, ADAU1977_POWER_PWUP);
434*4882a593Smuzhiyun 	if (ret)
435*4882a593Smuzhiyun 		goto err_disable_dvdd;
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun 	ret = regcache_sync(adau1977->regmap);
438*4882a593Smuzhiyun 	if (ret)
439*4882a593Smuzhiyun 		goto err_disable_dvdd;
440*4882a593Smuzhiyun 
441*4882a593Smuzhiyun 	/*
442*4882a593Smuzhiyun 	 * The PLL register is not affected by the software reset. It is
443*4882a593Smuzhiyun 	 * possible that the value of the register was changed to the
444*4882a593Smuzhiyun 	 * default value while we were in cache only mode. In this case
445*4882a593Smuzhiyun 	 * regcache_sync will skip over it and we have to manually sync
446*4882a593Smuzhiyun 	 * it.
447*4882a593Smuzhiyun 	 */
448*4882a593Smuzhiyun 	ret = regmap_read(adau1977->regmap, ADAU1977_REG_PLL, &val);
449*4882a593Smuzhiyun 	if (ret)
450*4882a593Smuzhiyun 		goto err_disable_dvdd;
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun 	if (val == 0x41) {
453*4882a593Smuzhiyun 		regcache_cache_bypass(adau1977->regmap, true);
454*4882a593Smuzhiyun 		ret = regmap_write(adau1977->regmap, ADAU1977_REG_PLL,
455*4882a593Smuzhiyun 			0x41);
456*4882a593Smuzhiyun 		if (ret)
457*4882a593Smuzhiyun 			goto err_disable_dvdd;
458*4882a593Smuzhiyun 		regcache_cache_bypass(adau1977->regmap, false);
459*4882a593Smuzhiyun 	}
460*4882a593Smuzhiyun 
461*4882a593Smuzhiyun 	adau1977->enabled = true;
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun 	return ret;
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun err_disable_dvdd:
466*4882a593Smuzhiyun 	if (adau1977->dvdd_reg)
467*4882a593Smuzhiyun 		regulator_disable(adau1977->dvdd_reg);
468*4882a593Smuzhiyun err_disable_avdd:
469*4882a593Smuzhiyun 		regulator_disable(adau1977->avdd_reg);
470*4882a593Smuzhiyun 	return ret;
471*4882a593Smuzhiyun }
472*4882a593Smuzhiyun 
adau1977_set_bias_level(struct snd_soc_component * component,enum snd_soc_bias_level level)473*4882a593Smuzhiyun static int adau1977_set_bias_level(struct snd_soc_component *component,
474*4882a593Smuzhiyun 	enum snd_soc_bias_level level)
475*4882a593Smuzhiyun {
476*4882a593Smuzhiyun 	struct adau1977 *adau1977 = snd_soc_component_get_drvdata(component);
477*4882a593Smuzhiyun 	int ret = 0;
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun 	switch (level) {
480*4882a593Smuzhiyun 	case SND_SOC_BIAS_ON:
481*4882a593Smuzhiyun 		break;
482*4882a593Smuzhiyun 	case SND_SOC_BIAS_PREPARE:
483*4882a593Smuzhiyun 		break;
484*4882a593Smuzhiyun 	case SND_SOC_BIAS_STANDBY:
485*4882a593Smuzhiyun 		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
486*4882a593Smuzhiyun 			ret = adau1977_power_enable(adau1977);
487*4882a593Smuzhiyun 		break;
488*4882a593Smuzhiyun 	case SND_SOC_BIAS_OFF:
489*4882a593Smuzhiyun 		ret = adau1977_power_disable(adau1977);
490*4882a593Smuzhiyun 		break;
491*4882a593Smuzhiyun 	}
492*4882a593Smuzhiyun 
493*4882a593Smuzhiyun 	return ret;
494*4882a593Smuzhiyun }
495*4882a593Smuzhiyun 
adau1977_set_tdm_slot(struct snd_soc_dai * dai,unsigned int tx_mask,unsigned int rx_mask,int slots,int width)496*4882a593Smuzhiyun static int adau1977_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
497*4882a593Smuzhiyun 	unsigned int rx_mask, int slots, int width)
498*4882a593Smuzhiyun {
499*4882a593Smuzhiyun 	struct adau1977 *adau1977 = snd_soc_component_get_drvdata(dai->component);
500*4882a593Smuzhiyun 	unsigned int ctrl0, ctrl1, drv;
501*4882a593Smuzhiyun 	unsigned int slot[4];
502*4882a593Smuzhiyun 	unsigned int i;
503*4882a593Smuzhiyun 	int ret;
504*4882a593Smuzhiyun 
505*4882a593Smuzhiyun 	if (slots == 0) {
506*4882a593Smuzhiyun 		/* 0 = No fixed slot width */
507*4882a593Smuzhiyun 		adau1977->slot_width = 0;
508*4882a593Smuzhiyun 		adau1977->max_master_fs = 192000;
509*4882a593Smuzhiyun 		return regmap_update_bits(adau1977->regmap,
510*4882a593Smuzhiyun 			ADAU1977_REG_SAI_CTRL0, ADAU1977_SAI_CTRL0_SAI_MASK,
511*4882a593Smuzhiyun 			ADAU1977_SAI_CTRL0_SAI_I2S);
512*4882a593Smuzhiyun 	}
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun 	if (rx_mask == 0 || tx_mask != 0)
515*4882a593Smuzhiyun 		return -EINVAL;
516*4882a593Smuzhiyun 
517*4882a593Smuzhiyun 	drv = 0;
518*4882a593Smuzhiyun 	for (i = 0; i < 4; i++) {
519*4882a593Smuzhiyun 		slot[i] = __ffs(rx_mask);
520*4882a593Smuzhiyun 		drv |= ADAU1977_SAI_OVERTEMP_DRV_C(i);
521*4882a593Smuzhiyun 		rx_mask &= ~(1 << slot[i]);
522*4882a593Smuzhiyun 		if (slot[i] >= slots)
523*4882a593Smuzhiyun 			return -EINVAL;
524*4882a593Smuzhiyun 		if (rx_mask == 0)
525*4882a593Smuzhiyun 			break;
526*4882a593Smuzhiyun 	}
527*4882a593Smuzhiyun 
528*4882a593Smuzhiyun 	if (rx_mask != 0)
529*4882a593Smuzhiyun 		return -EINVAL;
530*4882a593Smuzhiyun 
531*4882a593Smuzhiyun 	switch (width) {
532*4882a593Smuzhiyun 	case 16:
533*4882a593Smuzhiyun 		ctrl1 = ADAU1977_SAI_CTRL1_SLOT_WIDTH_16;
534*4882a593Smuzhiyun 		break;
535*4882a593Smuzhiyun 	case 24:
536*4882a593Smuzhiyun 		/* We can only generate 16 bit or 32 bit wide slots */
537*4882a593Smuzhiyun 		if (adau1977->master)
538*4882a593Smuzhiyun 			return -EINVAL;
539*4882a593Smuzhiyun 		ctrl1 = ADAU1977_SAI_CTRL1_SLOT_WIDTH_24;
540*4882a593Smuzhiyun 		break;
541*4882a593Smuzhiyun 	case 32:
542*4882a593Smuzhiyun 		ctrl1 = ADAU1977_SAI_CTRL1_SLOT_WIDTH_32;
543*4882a593Smuzhiyun 		break;
544*4882a593Smuzhiyun 	default:
545*4882a593Smuzhiyun 		return -EINVAL;
546*4882a593Smuzhiyun 	}
547*4882a593Smuzhiyun 
548*4882a593Smuzhiyun 	switch (slots) {
549*4882a593Smuzhiyun 	case 2:
550*4882a593Smuzhiyun 		ctrl0 = ADAU1977_SAI_CTRL0_SAI_TDM_2;
551*4882a593Smuzhiyun 		break;
552*4882a593Smuzhiyun 	case 4:
553*4882a593Smuzhiyun 		ctrl0 = ADAU1977_SAI_CTRL0_SAI_TDM_4;
554*4882a593Smuzhiyun 		break;
555*4882a593Smuzhiyun 	case 8:
556*4882a593Smuzhiyun 		ctrl0 = ADAU1977_SAI_CTRL0_SAI_TDM_8;
557*4882a593Smuzhiyun 		break;
558*4882a593Smuzhiyun 	case 16:
559*4882a593Smuzhiyun 		ctrl0 = ADAU1977_SAI_CTRL0_SAI_TDM_16;
560*4882a593Smuzhiyun 		break;
561*4882a593Smuzhiyun 	default:
562*4882a593Smuzhiyun 		return -EINVAL;
563*4882a593Smuzhiyun 	}
564*4882a593Smuzhiyun 
565*4882a593Smuzhiyun 	ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_OVERTEMP,
566*4882a593Smuzhiyun 		ADAU1977_SAI_OVERTEMP_DRV_C(0) |
567*4882a593Smuzhiyun 		ADAU1977_SAI_OVERTEMP_DRV_C(1) |
568*4882a593Smuzhiyun 		ADAU1977_SAI_OVERTEMP_DRV_C(2) |
569*4882a593Smuzhiyun 		ADAU1977_SAI_OVERTEMP_DRV_C(3), drv);
570*4882a593Smuzhiyun 	if (ret)
571*4882a593Smuzhiyun 		return ret;
572*4882a593Smuzhiyun 
573*4882a593Smuzhiyun 	ret = regmap_write(adau1977->regmap, ADAU1977_REG_CMAP12,
574*4882a593Smuzhiyun 		(slot[1] << ADAU1977_CHAN_MAP_SECOND_SLOT_OFFSET) |
575*4882a593Smuzhiyun 		(slot[0] << ADAU1977_CHAN_MAP_FIRST_SLOT_OFFSET));
576*4882a593Smuzhiyun 	if (ret)
577*4882a593Smuzhiyun 		return ret;
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun 	ret = regmap_write(adau1977->regmap, ADAU1977_REG_CMAP34,
580*4882a593Smuzhiyun 		(slot[3] << ADAU1977_CHAN_MAP_SECOND_SLOT_OFFSET) |
581*4882a593Smuzhiyun 		(slot[2] << ADAU1977_CHAN_MAP_FIRST_SLOT_OFFSET));
582*4882a593Smuzhiyun 	if (ret)
583*4882a593Smuzhiyun 		return ret;
584*4882a593Smuzhiyun 
585*4882a593Smuzhiyun 	ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL0,
586*4882a593Smuzhiyun 		ADAU1977_SAI_CTRL0_SAI_MASK, ctrl0);
587*4882a593Smuzhiyun 	if (ret)
588*4882a593Smuzhiyun 		return ret;
589*4882a593Smuzhiyun 
590*4882a593Smuzhiyun 	ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL1,
591*4882a593Smuzhiyun 		ADAU1977_SAI_CTRL1_SLOT_WIDTH_MASK, ctrl1);
592*4882a593Smuzhiyun 	if (ret)
593*4882a593Smuzhiyun 		return ret;
594*4882a593Smuzhiyun 
595*4882a593Smuzhiyun 	adau1977->slot_width = width;
596*4882a593Smuzhiyun 
597*4882a593Smuzhiyun 	/* In master mode the maximum bitclock is 24.576 MHz */
598*4882a593Smuzhiyun 	adau1977->max_master_fs = min(192000, 24576000 / width / slots);
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun 	return 0;
601*4882a593Smuzhiyun }
602*4882a593Smuzhiyun 
adau1977_mute(struct snd_soc_dai * dai,int mute,int stream)603*4882a593Smuzhiyun static int adau1977_mute(struct snd_soc_dai *dai, int mute, int stream)
604*4882a593Smuzhiyun {
605*4882a593Smuzhiyun 	struct adau1977 *adau1977 = snd_soc_component_get_drvdata(dai->component);
606*4882a593Smuzhiyun 	unsigned int val;
607*4882a593Smuzhiyun 
608*4882a593Smuzhiyun 	if (mute)
609*4882a593Smuzhiyun 		val = ADAU1977_MISC_CONTROL_MMUTE;
610*4882a593Smuzhiyun 	else
611*4882a593Smuzhiyun 		val = 0;
612*4882a593Smuzhiyun 
613*4882a593Smuzhiyun 	return regmap_update_bits(adau1977->regmap, ADAU1977_REG_MISC_CONTROL,
614*4882a593Smuzhiyun 			ADAU1977_MISC_CONTROL_MMUTE, val);
615*4882a593Smuzhiyun }
616*4882a593Smuzhiyun 
adau1977_set_dai_fmt(struct snd_soc_dai * dai,unsigned int fmt)617*4882a593Smuzhiyun static int adau1977_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
618*4882a593Smuzhiyun {
619*4882a593Smuzhiyun 	struct adau1977 *adau1977 = snd_soc_component_get_drvdata(dai->component);
620*4882a593Smuzhiyun 	unsigned int ctrl0 = 0, ctrl1 = 0, block_power = 0;
621*4882a593Smuzhiyun 	bool invert_lrclk;
622*4882a593Smuzhiyun 	int ret;
623*4882a593Smuzhiyun 
624*4882a593Smuzhiyun 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
625*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_CBS_CFS:
626*4882a593Smuzhiyun 		adau1977->master = false;
627*4882a593Smuzhiyun 		break;
628*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_CBM_CFM:
629*4882a593Smuzhiyun 		ctrl1 |= ADAU1977_SAI_CTRL1_MASTER;
630*4882a593Smuzhiyun 		adau1977->master = true;
631*4882a593Smuzhiyun 		break;
632*4882a593Smuzhiyun 	default:
633*4882a593Smuzhiyun 		return -EINVAL;
634*4882a593Smuzhiyun 	}
635*4882a593Smuzhiyun 
636*4882a593Smuzhiyun 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
637*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_NB_NF:
638*4882a593Smuzhiyun 		invert_lrclk = false;
639*4882a593Smuzhiyun 		break;
640*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_IB_NF:
641*4882a593Smuzhiyun 		block_power |= ADAU1977_BLOCK_POWER_SAI_BCLK_EDGE;
642*4882a593Smuzhiyun 		invert_lrclk = false;
643*4882a593Smuzhiyun 		break;
644*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_NB_IF:
645*4882a593Smuzhiyun 		invert_lrclk = true;
646*4882a593Smuzhiyun 		break;
647*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_IB_IF:
648*4882a593Smuzhiyun 		block_power |= ADAU1977_BLOCK_POWER_SAI_BCLK_EDGE;
649*4882a593Smuzhiyun 		invert_lrclk = true;
650*4882a593Smuzhiyun 		break;
651*4882a593Smuzhiyun 	default:
652*4882a593Smuzhiyun 		return -EINVAL;
653*4882a593Smuzhiyun 	}
654*4882a593Smuzhiyun 
655*4882a593Smuzhiyun 	adau1977->right_j = false;
656*4882a593Smuzhiyun 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
657*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_I2S:
658*4882a593Smuzhiyun 		ctrl0 |= ADAU1977_SAI_CTRL0_FMT_I2S;
659*4882a593Smuzhiyun 		break;
660*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_LEFT_J:
661*4882a593Smuzhiyun 		ctrl0 |= ADAU1977_SAI_CTRL0_FMT_LJ;
662*4882a593Smuzhiyun 		invert_lrclk = !invert_lrclk;
663*4882a593Smuzhiyun 		break;
664*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_RIGHT_J:
665*4882a593Smuzhiyun 		ctrl0 |= ADAU1977_SAI_CTRL0_FMT_RJ_24BIT;
666*4882a593Smuzhiyun 		adau1977->right_j = true;
667*4882a593Smuzhiyun 		invert_lrclk = !invert_lrclk;
668*4882a593Smuzhiyun 		break;
669*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_DSP_A:
670*4882a593Smuzhiyun 		ctrl1 |= ADAU1977_SAI_CTRL1_LRCLK_PULSE;
671*4882a593Smuzhiyun 		ctrl0 |= ADAU1977_SAI_CTRL0_FMT_I2S;
672*4882a593Smuzhiyun 		invert_lrclk = false;
673*4882a593Smuzhiyun 		break;
674*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_DSP_B:
675*4882a593Smuzhiyun 		ctrl1 |= ADAU1977_SAI_CTRL1_LRCLK_PULSE;
676*4882a593Smuzhiyun 		ctrl0 |= ADAU1977_SAI_CTRL0_FMT_LJ;
677*4882a593Smuzhiyun 		invert_lrclk = false;
678*4882a593Smuzhiyun 		break;
679*4882a593Smuzhiyun 	default:
680*4882a593Smuzhiyun 		return -EINVAL;
681*4882a593Smuzhiyun 	}
682*4882a593Smuzhiyun 
683*4882a593Smuzhiyun 	if (invert_lrclk)
684*4882a593Smuzhiyun 		block_power |= ADAU1977_BLOCK_POWER_SAI_LR_POL;
685*4882a593Smuzhiyun 
686*4882a593Smuzhiyun 	ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_BLOCK_POWER_SAI,
687*4882a593Smuzhiyun 		ADAU1977_BLOCK_POWER_SAI_LR_POL |
688*4882a593Smuzhiyun 		ADAU1977_BLOCK_POWER_SAI_BCLK_EDGE, block_power);
689*4882a593Smuzhiyun 	if (ret)
690*4882a593Smuzhiyun 		return ret;
691*4882a593Smuzhiyun 
692*4882a593Smuzhiyun 	ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL0,
693*4882a593Smuzhiyun 		ADAU1977_SAI_CTRL0_FMT_MASK,
694*4882a593Smuzhiyun 		ctrl0);
695*4882a593Smuzhiyun 	if (ret)
696*4882a593Smuzhiyun 		return ret;
697*4882a593Smuzhiyun 
698*4882a593Smuzhiyun 	return regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL1,
699*4882a593Smuzhiyun 		ADAU1977_SAI_CTRL1_MASTER | ADAU1977_SAI_CTRL1_LRCLK_PULSE,
700*4882a593Smuzhiyun 		ctrl1);
701*4882a593Smuzhiyun }
702*4882a593Smuzhiyun 
adau1977_startup(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)703*4882a593Smuzhiyun static int adau1977_startup(struct snd_pcm_substream *substream,
704*4882a593Smuzhiyun 	struct snd_soc_dai *dai)
705*4882a593Smuzhiyun {
706*4882a593Smuzhiyun 	struct adau1977 *adau1977 = snd_soc_component_get_drvdata(dai->component);
707*4882a593Smuzhiyun 	u64 formats = 0;
708*4882a593Smuzhiyun 
709*4882a593Smuzhiyun 	if (adau1977->slot_width == 16)
710*4882a593Smuzhiyun 		formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE;
711*4882a593Smuzhiyun 	else if (adau1977->right_j || adau1977->slot_width == 24)
712*4882a593Smuzhiyun 		formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
713*4882a593Smuzhiyun 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE;
714*4882a593Smuzhiyun 
715*4882a593Smuzhiyun 	snd_pcm_hw_constraint_list(substream->runtime, 0,
716*4882a593Smuzhiyun 		SNDRV_PCM_HW_PARAM_RATE, &adau1977->constraints);
717*4882a593Smuzhiyun 
718*4882a593Smuzhiyun 	if (adau1977->master)
719*4882a593Smuzhiyun 		snd_pcm_hw_constraint_minmax(substream->runtime,
720*4882a593Smuzhiyun 			SNDRV_PCM_HW_PARAM_RATE, 8000, adau1977->max_master_fs);
721*4882a593Smuzhiyun 
722*4882a593Smuzhiyun 	if (formats != 0)
723*4882a593Smuzhiyun 		snd_pcm_hw_constraint_mask64(substream->runtime,
724*4882a593Smuzhiyun 			SNDRV_PCM_HW_PARAM_FORMAT, formats);
725*4882a593Smuzhiyun 
726*4882a593Smuzhiyun 	return 0;
727*4882a593Smuzhiyun }
728*4882a593Smuzhiyun 
adau1977_set_tristate(struct snd_soc_dai * dai,int tristate)729*4882a593Smuzhiyun static int adau1977_set_tristate(struct snd_soc_dai *dai, int tristate)
730*4882a593Smuzhiyun {
731*4882a593Smuzhiyun 	struct adau1977 *adau1977 = snd_soc_component_get_drvdata(dai->component);
732*4882a593Smuzhiyun 	unsigned int val;
733*4882a593Smuzhiyun 
734*4882a593Smuzhiyun 	if (tristate)
735*4882a593Smuzhiyun 		val = ADAU1977_SAI_OVERTEMP_DRV_HIZ;
736*4882a593Smuzhiyun 	else
737*4882a593Smuzhiyun 		val = 0;
738*4882a593Smuzhiyun 
739*4882a593Smuzhiyun 	return regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_OVERTEMP,
740*4882a593Smuzhiyun 		ADAU1977_SAI_OVERTEMP_DRV_HIZ, val);
741*4882a593Smuzhiyun }
742*4882a593Smuzhiyun 
743*4882a593Smuzhiyun static const struct snd_soc_dai_ops adau1977_dai_ops = {
744*4882a593Smuzhiyun 	.startup	= adau1977_startup,
745*4882a593Smuzhiyun 	.hw_params	= adau1977_hw_params,
746*4882a593Smuzhiyun 	.mute_stream	= adau1977_mute,
747*4882a593Smuzhiyun 	.set_fmt	= adau1977_set_dai_fmt,
748*4882a593Smuzhiyun 	.set_tdm_slot	= adau1977_set_tdm_slot,
749*4882a593Smuzhiyun 	.set_tristate	= adau1977_set_tristate,
750*4882a593Smuzhiyun };
751*4882a593Smuzhiyun 
752*4882a593Smuzhiyun static struct snd_soc_dai_driver adau1977_dai = {
753*4882a593Smuzhiyun 	.name = "adau1977-hifi",
754*4882a593Smuzhiyun 	.capture = {
755*4882a593Smuzhiyun 		.stream_name = "Capture",
756*4882a593Smuzhiyun 		.channels_min = 1,
757*4882a593Smuzhiyun 		.channels_max = 4,
758*4882a593Smuzhiyun 		.rates = SNDRV_PCM_RATE_KNOT,
759*4882a593Smuzhiyun 		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
760*4882a593Smuzhiyun 		    SNDRV_PCM_FMTBIT_S32_LE,
761*4882a593Smuzhiyun 		.sig_bits = 24,
762*4882a593Smuzhiyun 	},
763*4882a593Smuzhiyun 	.ops = &adau1977_dai_ops,
764*4882a593Smuzhiyun };
765*4882a593Smuzhiyun 
766*4882a593Smuzhiyun static const unsigned int adau1977_rates[] = {
767*4882a593Smuzhiyun 	8000, 16000, 32000, 64000, 128000,
768*4882a593Smuzhiyun 	11025, 22050, 44100, 88200, 172400,
769*4882a593Smuzhiyun 	12000, 24000, 48000, 96000, 192000,
770*4882a593Smuzhiyun };
771*4882a593Smuzhiyun 
772*4882a593Smuzhiyun #define ADAU1977_RATE_CONSTRAINT_MASK_32000 0x001f
773*4882a593Smuzhiyun #define ADAU1977_RATE_CONSTRAINT_MASK_44100 0x03e0
774*4882a593Smuzhiyun #define ADAU1977_RATE_CONSTRAINT_MASK_48000 0x7c00
775*4882a593Smuzhiyun /* All rates >= 32000 */
776*4882a593Smuzhiyun #define ADAU1977_RATE_CONSTRAINT_MASK_LRCLK 0x739c
777*4882a593Smuzhiyun 
adau1977_check_sysclk(unsigned int mclk,unsigned int base_freq)778*4882a593Smuzhiyun static bool adau1977_check_sysclk(unsigned int mclk, unsigned int base_freq)
779*4882a593Smuzhiyun {
780*4882a593Smuzhiyun 	unsigned int mcs;
781*4882a593Smuzhiyun 
782*4882a593Smuzhiyun 	if (mclk % (base_freq * 128) != 0)
783*4882a593Smuzhiyun 		return false;
784*4882a593Smuzhiyun 
785*4882a593Smuzhiyun 	mcs = mclk / (128 * base_freq);
786*4882a593Smuzhiyun 	if (mcs < 1 || mcs > 6 || mcs == 5)
787*4882a593Smuzhiyun 		return false;
788*4882a593Smuzhiyun 
789*4882a593Smuzhiyun 	return true;
790*4882a593Smuzhiyun }
791*4882a593Smuzhiyun 
adau1977_set_sysclk(struct snd_soc_component * component,int clk_id,int source,unsigned int freq,int dir)792*4882a593Smuzhiyun static int adau1977_set_sysclk(struct snd_soc_component *component,
793*4882a593Smuzhiyun 	int clk_id, int source, unsigned int freq, int dir)
794*4882a593Smuzhiyun {
795*4882a593Smuzhiyun 	struct adau1977 *adau1977 = snd_soc_component_get_drvdata(component);
796*4882a593Smuzhiyun 	unsigned int mask = 0;
797*4882a593Smuzhiyun 	unsigned int clk_src;
798*4882a593Smuzhiyun 	unsigned int ret;
799*4882a593Smuzhiyun 
800*4882a593Smuzhiyun 	if (dir != SND_SOC_CLOCK_IN)
801*4882a593Smuzhiyun 		return -EINVAL;
802*4882a593Smuzhiyun 
803*4882a593Smuzhiyun 	if (clk_id != ADAU1977_SYSCLK)
804*4882a593Smuzhiyun 		return -EINVAL;
805*4882a593Smuzhiyun 
806*4882a593Smuzhiyun 	switch (source) {
807*4882a593Smuzhiyun 	case ADAU1977_SYSCLK_SRC_MCLK:
808*4882a593Smuzhiyun 		clk_src = 0;
809*4882a593Smuzhiyun 		break;
810*4882a593Smuzhiyun 	case ADAU1977_SYSCLK_SRC_LRCLK:
811*4882a593Smuzhiyun 		clk_src = ADAU1977_PLL_CLK_S;
812*4882a593Smuzhiyun 		break;
813*4882a593Smuzhiyun 	default:
814*4882a593Smuzhiyun 		return -EINVAL;
815*4882a593Smuzhiyun 	}
816*4882a593Smuzhiyun 
817*4882a593Smuzhiyun 	if (freq != 0 && source == ADAU1977_SYSCLK_SRC_MCLK) {
818*4882a593Smuzhiyun 		if (freq < 4000000 || freq > 36864000)
819*4882a593Smuzhiyun 			return -EINVAL;
820*4882a593Smuzhiyun 
821*4882a593Smuzhiyun 		if (adau1977_check_sysclk(freq, 32000))
822*4882a593Smuzhiyun 			mask |= ADAU1977_RATE_CONSTRAINT_MASK_32000;
823*4882a593Smuzhiyun 		if (adau1977_check_sysclk(freq, 44100))
824*4882a593Smuzhiyun 			mask |= ADAU1977_RATE_CONSTRAINT_MASK_44100;
825*4882a593Smuzhiyun 		if (adau1977_check_sysclk(freq, 48000))
826*4882a593Smuzhiyun 			mask |= ADAU1977_RATE_CONSTRAINT_MASK_48000;
827*4882a593Smuzhiyun 
828*4882a593Smuzhiyun 		if (mask == 0)
829*4882a593Smuzhiyun 			return -EINVAL;
830*4882a593Smuzhiyun 	} else if (source == ADAU1977_SYSCLK_SRC_LRCLK) {
831*4882a593Smuzhiyun 		mask = ADAU1977_RATE_CONSTRAINT_MASK_LRCLK;
832*4882a593Smuzhiyun 	}
833*4882a593Smuzhiyun 
834*4882a593Smuzhiyun 	ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_PLL,
835*4882a593Smuzhiyun 		ADAU1977_PLL_CLK_S, clk_src);
836*4882a593Smuzhiyun 	if (ret)
837*4882a593Smuzhiyun 		return ret;
838*4882a593Smuzhiyun 
839*4882a593Smuzhiyun 	adau1977->constraints.mask = mask;
840*4882a593Smuzhiyun 	adau1977->sysclk_src = source;
841*4882a593Smuzhiyun 	adau1977->sysclk = freq;
842*4882a593Smuzhiyun 
843*4882a593Smuzhiyun 	return 0;
844*4882a593Smuzhiyun }
845*4882a593Smuzhiyun 
adau1977_component_probe(struct snd_soc_component * component)846*4882a593Smuzhiyun static int adau1977_component_probe(struct snd_soc_component *component)
847*4882a593Smuzhiyun {
848*4882a593Smuzhiyun 	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
849*4882a593Smuzhiyun 	struct adau1977 *adau1977 = snd_soc_component_get_drvdata(component);
850*4882a593Smuzhiyun 	int ret;
851*4882a593Smuzhiyun 
852*4882a593Smuzhiyun 	switch (adau1977->type) {
853*4882a593Smuzhiyun 	case ADAU1977:
854*4882a593Smuzhiyun 		ret = snd_soc_dapm_new_controls(dapm,
855*4882a593Smuzhiyun 			adau1977_micbias_dapm_widgets,
856*4882a593Smuzhiyun 			ARRAY_SIZE(adau1977_micbias_dapm_widgets));
857*4882a593Smuzhiyun 		if (ret < 0)
858*4882a593Smuzhiyun 			return ret;
859*4882a593Smuzhiyun 		break;
860*4882a593Smuzhiyun 	default:
861*4882a593Smuzhiyun 		break;
862*4882a593Smuzhiyun 	}
863*4882a593Smuzhiyun 
864*4882a593Smuzhiyun 	return 0;
865*4882a593Smuzhiyun }
866*4882a593Smuzhiyun 
867*4882a593Smuzhiyun static const struct snd_soc_component_driver adau1977_component_driver = {
868*4882a593Smuzhiyun 	.probe			= adau1977_component_probe,
869*4882a593Smuzhiyun 	.set_bias_level		= adau1977_set_bias_level,
870*4882a593Smuzhiyun 	.set_sysclk		= adau1977_set_sysclk,
871*4882a593Smuzhiyun 	.controls		= adau1977_snd_controls,
872*4882a593Smuzhiyun 	.num_controls		= ARRAY_SIZE(adau1977_snd_controls),
873*4882a593Smuzhiyun 	.dapm_widgets		= adau1977_dapm_widgets,
874*4882a593Smuzhiyun 	.num_dapm_widgets	= ARRAY_SIZE(adau1977_dapm_widgets),
875*4882a593Smuzhiyun 	.dapm_routes		= adau1977_dapm_routes,
876*4882a593Smuzhiyun 	.num_dapm_routes	= ARRAY_SIZE(adau1977_dapm_routes),
877*4882a593Smuzhiyun 	.use_pmdown_time	= 1,
878*4882a593Smuzhiyun 	.endianness		= 1,
879*4882a593Smuzhiyun 	.non_legacy_dai_naming	= 1,
880*4882a593Smuzhiyun };
881*4882a593Smuzhiyun 
adau1977_setup_micbias(struct adau1977 * adau1977)882*4882a593Smuzhiyun static int adau1977_setup_micbias(struct adau1977 *adau1977)
883*4882a593Smuzhiyun {
884*4882a593Smuzhiyun 	struct adau1977_platform_data *pdata = adau1977->dev->platform_data;
885*4882a593Smuzhiyun 	unsigned int micbias;
886*4882a593Smuzhiyun 
887*4882a593Smuzhiyun 	if (pdata)
888*4882a593Smuzhiyun 		micbias = pdata->micbias;
889*4882a593Smuzhiyun 	else if (device_property_read_u32(adau1977->dev, "adi,micbias",
890*4882a593Smuzhiyun 					  &micbias))
891*4882a593Smuzhiyun 		micbias = ADAU1977_MICBIAS_8V5;
892*4882a593Smuzhiyun 
893*4882a593Smuzhiyun 	if (micbias > ADAU1977_MICBIAS_9V0) {
894*4882a593Smuzhiyun 		dev_err(adau1977->dev, "Invalid value for 'adi,micbias'\n");
895*4882a593Smuzhiyun 		return -EINVAL;
896*4882a593Smuzhiyun 	}
897*4882a593Smuzhiyun 
898*4882a593Smuzhiyun 	return regmap_update_bits(adau1977->regmap, ADAU1977_REG_MICBIAS,
899*4882a593Smuzhiyun 		ADAU1977_MICBIAS_MB_VOLTS_MASK,
900*4882a593Smuzhiyun 		micbias << ADAU1977_MICBIAS_MB_VOLTS_OFFSET);
901*4882a593Smuzhiyun }
902*4882a593Smuzhiyun 
adau1977_probe(struct device * dev,struct regmap * regmap,enum adau1977_type type,void (* switch_mode)(struct device * dev))903*4882a593Smuzhiyun int adau1977_probe(struct device *dev, struct regmap *regmap,
904*4882a593Smuzhiyun 	enum adau1977_type type, void (*switch_mode)(struct device *dev))
905*4882a593Smuzhiyun {
906*4882a593Smuzhiyun 	unsigned int power_off_mask;
907*4882a593Smuzhiyun 	struct adau1977 *adau1977;
908*4882a593Smuzhiyun 	int ret;
909*4882a593Smuzhiyun 
910*4882a593Smuzhiyun 	if (IS_ERR(regmap))
911*4882a593Smuzhiyun 		return PTR_ERR(regmap);
912*4882a593Smuzhiyun 
913*4882a593Smuzhiyun 	adau1977 = devm_kzalloc(dev, sizeof(*adau1977), GFP_KERNEL);
914*4882a593Smuzhiyun 	if (adau1977 == NULL)
915*4882a593Smuzhiyun 		return -ENOMEM;
916*4882a593Smuzhiyun 
917*4882a593Smuzhiyun 	adau1977->dev = dev;
918*4882a593Smuzhiyun 	adau1977->type = type;
919*4882a593Smuzhiyun 	adau1977->regmap = regmap;
920*4882a593Smuzhiyun 	adau1977->switch_mode = switch_mode;
921*4882a593Smuzhiyun 	adau1977->max_master_fs = 192000;
922*4882a593Smuzhiyun 
923*4882a593Smuzhiyun 	adau1977->constraints.list = adau1977_rates;
924*4882a593Smuzhiyun 	adau1977->constraints.count = ARRAY_SIZE(adau1977_rates);
925*4882a593Smuzhiyun 
926*4882a593Smuzhiyun 	adau1977->avdd_reg = devm_regulator_get(dev, "AVDD");
927*4882a593Smuzhiyun 	if (IS_ERR(adau1977->avdd_reg))
928*4882a593Smuzhiyun 		return PTR_ERR(adau1977->avdd_reg);
929*4882a593Smuzhiyun 
930*4882a593Smuzhiyun 	adau1977->dvdd_reg = devm_regulator_get_optional(dev, "DVDD");
931*4882a593Smuzhiyun 	if (IS_ERR(adau1977->dvdd_reg)) {
932*4882a593Smuzhiyun 		if (PTR_ERR(adau1977->dvdd_reg) != -ENODEV)
933*4882a593Smuzhiyun 			return PTR_ERR(adau1977->dvdd_reg);
934*4882a593Smuzhiyun 		adau1977->dvdd_reg = NULL;
935*4882a593Smuzhiyun 	}
936*4882a593Smuzhiyun 
937*4882a593Smuzhiyun 	adau1977->reset_gpio = devm_gpiod_get_optional(dev, "reset",
938*4882a593Smuzhiyun 						       GPIOD_OUT_LOW);
939*4882a593Smuzhiyun 	if (IS_ERR(adau1977->reset_gpio))
940*4882a593Smuzhiyun 		return PTR_ERR(adau1977->reset_gpio);
941*4882a593Smuzhiyun 
942*4882a593Smuzhiyun 	dev_set_drvdata(dev, adau1977);
943*4882a593Smuzhiyun 
944*4882a593Smuzhiyun 	if (adau1977->reset_gpio)
945*4882a593Smuzhiyun 		ndelay(100);
946*4882a593Smuzhiyun 
947*4882a593Smuzhiyun 	ret = adau1977_power_enable(adau1977);
948*4882a593Smuzhiyun 	if (ret)
949*4882a593Smuzhiyun 		return ret;
950*4882a593Smuzhiyun 
951*4882a593Smuzhiyun 	if (type == ADAU1977) {
952*4882a593Smuzhiyun 		ret = adau1977_setup_micbias(adau1977);
953*4882a593Smuzhiyun 		if (ret)
954*4882a593Smuzhiyun 			goto err_poweroff;
955*4882a593Smuzhiyun 	}
956*4882a593Smuzhiyun 
957*4882a593Smuzhiyun 	if (adau1977->dvdd_reg)
958*4882a593Smuzhiyun 		power_off_mask = ~0;
959*4882a593Smuzhiyun 	else
960*4882a593Smuzhiyun 		power_off_mask = (unsigned int)~ADAU1977_BLOCK_POWER_SAI_LDO_EN;
961*4882a593Smuzhiyun 
962*4882a593Smuzhiyun 	ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_BLOCK_POWER_SAI,
963*4882a593Smuzhiyun 				power_off_mask, 0x00);
964*4882a593Smuzhiyun 	if (ret)
965*4882a593Smuzhiyun 		goto err_poweroff;
966*4882a593Smuzhiyun 
967*4882a593Smuzhiyun 	ret = adau1977_power_disable(adau1977);
968*4882a593Smuzhiyun 	if (ret)
969*4882a593Smuzhiyun 		return ret;
970*4882a593Smuzhiyun 
971*4882a593Smuzhiyun 	return devm_snd_soc_register_component(dev, &adau1977_component_driver,
972*4882a593Smuzhiyun 			&adau1977_dai, 1);
973*4882a593Smuzhiyun 
974*4882a593Smuzhiyun err_poweroff:
975*4882a593Smuzhiyun 	adau1977_power_disable(adau1977);
976*4882a593Smuzhiyun 	return ret;
977*4882a593Smuzhiyun 
978*4882a593Smuzhiyun }
979*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(adau1977_probe);
980*4882a593Smuzhiyun 
adau1977_register_volatile(struct device * dev,unsigned int reg)981*4882a593Smuzhiyun static bool adau1977_register_volatile(struct device *dev, unsigned int reg)
982*4882a593Smuzhiyun {
983*4882a593Smuzhiyun 	switch (reg) {
984*4882a593Smuzhiyun 	case ADAU1977_REG_STATUS(0):
985*4882a593Smuzhiyun 	case ADAU1977_REG_STATUS(1):
986*4882a593Smuzhiyun 	case ADAU1977_REG_STATUS(2):
987*4882a593Smuzhiyun 	case ADAU1977_REG_STATUS(3):
988*4882a593Smuzhiyun 	case ADAU1977_REG_ADC_CLIP:
989*4882a593Smuzhiyun 		return true;
990*4882a593Smuzhiyun 	}
991*4882a593Smuzhiyun 
992*4882a593Smuzhiyun 	return false;
993*4882a593Smuzhiyun }
994*4882a593Smuzhiyun 
995*4882a593Smuzhiyun const struct regmap_config adau1977_regmap_config = {
996*4882a593Smuzhiyun 	.max_register = ADAU1977_REG_DC_HPF_CAL,
997*4882a593Smuzhiyun 	.volatile_reg = adau1977_register_volatile,
998*4882a593Smuzhiyun 
999*4882a593Smuzhiyun 	.cache_type = REGCACHE_RBTREE,
1000*4882a593Smuzhiyun 	.reg_defaults = adau1977_reg_defaults,
1001*4882a593Smuzhiyun 	.num_reg_defaults = ARRAY_SIZE(adau1977_reg_defaults),
1002*4882a593Smuzhiyun };
1003*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(adau1977_regmap_config);
1004*4882a593Smuzhiyun 
1005*4882a593Smuzhiyun MODULE_DESCRIPTION("ASoC ADAU1977/ADAU1978/ADAU1979 driver");
1006*4882a593Smuzhiyun MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
1007*4882a593Smuzhiyun MODULE_LICENSE("GPL");
1008