xref: /OK3568_Linux_fs/kernel/sound/soc/codecs/rt711.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun //
3*4882a593Smuzhiyun // rt711.c -- rt711 ALSA SoC audio driver
4*4882a593Smuzhiyun //
5*4882a593Smuzhiyun // Copyright(c) 2019 Realtek Semiconductor Corp.
6*4882a593Smuzhiyun //
7*4882a593Smuzhiyun //
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <linux/module.h>
10*4882a593Smuzhiyun #include <linux/moduleparam.h>
11*4882a593Smuzhiyun #include <linux/kernel.h>
12*4882a593Smuzhiyun #include <linux/init.h>
13*4882a593Smuzhiyun #include <linux/delay.h>
14*4882a593Smuzhiyun #include <linux/pm_runtime.h>
15*4882a593Smuzhiyun #include <linux/pm.h>
16*4882a593Smuzhiyun #include <linux/soundwire/sdw.h>
17*4882a593Smuzhiyun #include <linux/regmap.h>
18*4882a593Smuzhiyun #include <linux/slab.h>
19*4882a593Smuzhiyun #include <sound/core.h>
20*4882a593Smuzhiyun #include <sound/pcm.h>
21*4882a593Smuzhiyun #include <sound/pcm_params.h>
22*4882a593Smuzhiyun #include <sound/soc.h>
23*4882a593Smuzhiyun #include <sound/soc-dapm.h>
24*4882a593Smuzhiyun #include <sound/initval.h>
25*4882a593Smuzhiyun #include <sound/tlv.h>
26*4882a593Smuzhiyun #include <sound/hda_verbs.h>
27*4882a593Smuzhiyun #include <sound/jack.h>
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun #include "rt711.h"
30*4882a593Smuzhiyun 
rt711_index_write(struct regmap * regmap,unsigned int nid,unsigned int reg,unsigned int value)31*4882a593Smuzhiyun static int rt711_index_write(struct regmap *regmap,
32*4882a593Smuzhiyun 		unsigned int nid, unsigned int reg, unsigned int value)
33*4882a593Smuzhiyun {
34*4882a593Smuzhiyun 	int ret;
35*4882a593Smuzhiyun 	unsigned int addr = ((RT711_PRIV_INDEX_W_H | nid) << 8) | reg;
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun 	ret = regmap_write(regmap, addr, value);
38*4882a593Smuzhiyun 	if (ret < 0)
39*4882a593Smuzhiyun 		pr_err("Failed to set private value: %06x <= %04x ret=%d\n",
40*4882a593Smuzhiyun 			addr, value, ret);
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun 	return ret;
43*4882a593Smuzhiyun }
44*4882a593Smuzhiyun 
rt711_index_read(struct regmap * regmap,unsigned int nid,unsigned int reg,unsigned int * value)45*4882a593Smuzhiyun static int rt711_index_read(struct regmap *regmap,
46*4882a593Smuzhiyun 		unsigned int nid, unsigned int reg, unsigned int *value)
47*4882a593Smuzhiyun {
48*4882a593Smuzhiyun 	int ret;
49*4882a593Smuzhiyun 	unsigned int addr = ((RT711_PRIV_INDEX_W_H | nid) << 8) | reg;
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun 	*value = 0;
52*4882a593Smuzhiyun 	ret = regmap_read(regmap, addr, value);
53*4882a593Smuzhiyun 	if (ret < 0)
54*4882a593Smuzhiyun 		pr_err("Failed to get private value: %06x => %04x ret=%d\n",
55*4882a593Smuzhiyun 			addr, *value, ret);
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun 	return ret;
58*4882a593Smuzhiyun }
59*4882a593Smuzhiyun 
rt711_index_update_bits(struct regmap * regmap,unsigned int nid,unsigned int reg,unsigned int mask,unsigned int val)60*4882a593Smuzhiyun static int rt711_index_update_bits(struct regmap *regmap, unsigned int nid,
61*4882a593Smuzhiyun 			unsigned int reg, unsigned int mask, unsigned int val)
62*4882a593Smuzhiyun {
63*4882a593Smuzhiyun 	unsigned int tmp, orig;
64*4882a593Smuzhiyun 	int ret;
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 	ret = rt711_index_read(regmap, nid, reg, &orig);
67*4882a593Smuzhiyun 	if (ret < 0)
68*4882a593Smuzhiyun 		return ret;
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 	tmp = orig & ~mask;
71*4882a593Smuzhiyun 	tmp |= val & mask;
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun 	return rt711_index_write(regmap, nid, reg, tmp);
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun 
rt711_reset(struct regmap * regmap)76*4882a593Smuzhiyun static void rt711_reset(struct regmap *regmap)
77*4882a593Smuzhiyun {
78*4882a593Smuzhiyun 	regmap_write(regmap, RT711_FUNC_RESET, 0);
79*4882a593Smuzhiyun 	rt711_index_update_bits(regmap, RT711_VENDOR_REG,
80*4882a593Smuzhiyun 		RT711_PARA_VERB_CTL, RT711_HIDDEN_REG_SW_RESET,
81*4882a593Smuzhiyun 		RT711_HIDDEN_REG_SW_RESET);
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun 
rt711_calibration(struct rt711_priv * rt711)84*4882a593Smuzhiyun static int rt711_calibration(struct rt711_priv *rt711)
85*4882a593Smuzhiyun {
86*4882a593Smuzhiyun 	unsigned int val, loop = 0;
87*4882a593Smuzhiyun 	struct device *dev;
88*4882a593Smuzhiyun 	struct regmap *regmap = rt711->regmap;
89*4882a593Smuzhiyun 	int ret = 0;
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 	mutex_lock(&rt711->calibrate_mutex);
92*4882a593Smuzhiyun 	regmap_write(rt711->regmap,
93*4882a593Smuzhiyun 		RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D0);
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun 	dev = regmap_get_device(regmap);
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 	/* Calibration manual mode */
98*4882a593Smuzhiyun 	rt711_index_update_bits(regmap, RT711_VENDOR_REG, RT711_FSM_CTL,
99*4882a593Smuzhiyun 		0xf, 0x0);
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 	/* trigger */
102*4882a593Smuzhiyun 	rt711_index_update_bits(regmap, RT711_VENDOR_CALI,
103*4882a593Smuzhiyun 		RT711_DAC_DC_CALI_CTL1, RT711_DAC_DC_CALI_TRIGGER,
104*4882a593Smuzhiyun 		RT711_DAC_DC_CALI_TRIGGER);
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun 	/* wait for calibration process */
107*4882a593Smuzhiyun 	rt711_index_read(regmap, RT711_VENDOR_CALI,
108*4882a593Smuzhiyun 		RT711_DAC_DC_CALI_CTL1, &val);
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun 	while (val & RT711_DAC_DC_CALI_TRIGGER) {
111*4882a593Smuzhiyun 		if (loop >= 500) {
112*4882a593Smuzhiyun 			pr_err("%s, calibration time-out!\n",
113*4882a593Smuzhiyun 							__func__);
114*4882a593Smuzhiyun 			ret = -ETIMEDOUT;
115*4882a593Smuzhiyun 			break;
116*4882a593Smuzhiyun 		}
117*4882a593Smuzhiyun 		loop++;
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 		usleep_range(10000, 11000);
120*4882a593Smuzhiyun 		rt711_index_read(regmap, RT711_VENDOR_CALI,
121*4882a593Smuzhiyun 			RT711_DAC_DC_CALI_CTL1, &val);
122*4882a593Smuzhiyun 	}
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	/* depop mode */
125*4882a593Smuzhiyun 	rt711_index_update_bits(regmap, RT711_VENDOR_REG,
126*4882a593Smuzhiyun 		RT711_FSM_CTL, 0xf, RT711_DEPOP_CTL);
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 	regmap_write(rt711->regmap,
129*4882a593Smuzhiyun 		RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3);
130*4882a593Smuzhiyun 	mutex_unlock(&rt711->calibrate_mutex);
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 	dev_dbg(dev, "%s calibration complete, ret=%d\n", __func__, ret);
133*4882a593Smuzhiyun 	return ret;
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun 
rt711_button_detect(struct rt711_priv * rt711)136*4882a593Smuzhiyun static unsigned int rt711_button_detect(struct rt711_priv *rt711)
137*4882a593Smuzhiyun {
138*4882a593Smuzhiyun 	unsigned int btn_type = 0, val80, val81;
139*4882a593Smuzhiyun 	int ret;
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	ret = rt711_index_read(rt711->regmap, RT711_VENDOR_REG,
142*4882a593Smuzhiyun 				RT711_IRQ_FLAG_TABLE1, &val80);
143*4882a593Smuzhiyun 	if (ret < 0)
144*4882a593Smuzhiyun 		goto read_error;
145*4882a593Smuzhiyun 	ret = rt711_index_read(rt711->regmap, RT711_VENDOR_REG,
146*4882a593Smuzhiyun 					RT711_IRQ_FLAG_TABLE2, &val81);
147*4882a593Smuzhiyun 	if (ret < 0)
148*4882a593Smuzhiyun 		goto read_error;
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	val80 &= 0x0381;
151*4882a593Smuzhiyun 	val81 &= 0xff00;
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	switch (val80) {
154*4882a593Smuzhiyun 	case 0x0200:
155*4882a593Smuzhiyun 	case 0x0100:
156*4882a593Smuzhiyun 	case 0x0080:
157*4882a593Smuzhiyun 		btn_type |= SND_JACK_BTN_0;
158*4882a593Smuzhiyun 		break;
159*4882a593Smuzhiyun 	case 0x0001:
160*4882a593Smuzhiyun 		btn_type |= SND_JACK_BTN_3;
161*4882a593Smuzhiyun 		break;
162*4882a593Smuzhiyun 	}
163*4882a593Smuzhiyun 	switch (val81) {
164*4882a593Smuzhiyun 	case 0x8000:
165*4882a593Smuzhiyun 	case 0x4000:
166*4882a593Smuzhiyun 	case 0x2000:
167*4882a593Smuzhiyun 		btn_type |= SND_JACK_BTN_1;
168*4882a593Smuzhiyun 		break;
169*4882a593Smuzhiyun 	case 0x1000:
170*4882a593Smuzhiyun 	case 0x0800:
171*4882a593Smuzhiyun 	case 0x0400:
172*4882a593Smuzhiyun 		btn_type |= SND_JACK_BTN_2;
173*4882a593Smuzhiyun 		break;
174*4882a593Smuzhiyun 	case 0x0200:
175*4882a593Smuzhiyun 	case 0x0100:
176*4882a593Smuzhiyun 		btn_type |= SND_JACK_BTN_3;
177*4882a593Smuzhiyun 		break;
178*4882a593Smuzhiyun 	}
179*4882a593Smuzhiyun read_error:
180*4882a593Smuzhiyun 	return btn_type;
181*4882a593Smuzhiyun }
182*4882a593Smuzhiyun 
rt711_headset_detect(struct rt711_priv * rt711)183*4882a593Smuzhiyun static int rt711_headset_detect(struct rt711_priv *rt711)
184*4882a593Smuzhiyun {
185*4882a593Smuzhiyun 	unsigned int buf, loop = 0;
186*4882a593Smuzhiyun 	int ret;
187*4882a593Smuzhiyun 	unsigned int jack_status = 0, reg;
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 	ret = rt711_index_read(rt711->regmap, RT711_VENDOR_REG,
190*4882a593Smuzhiyun 				RT711_COMBO_JACK_AUTO_CTL2, &buf);
191*4882a593Smuzhiyun 	if (ret < 0)
192*4882a593Smuzhiyun 		goto io_error;
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	while (loop < 500 &&
195*4882a593Smuzhiyun 		(buf & RT711_COMBOJACK_AUTO_DET_STATUS) == 0) {
196*4882a593Smuzhiyun 		loop++;
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 		usleep_range(9000, 10000);
199*4882a593Smuzhiyun 		ret = rt711_index_read(rt711->regmap, RT711_VENDOR_REG,
200*4882a593Smuzhiyun 					RT711_COMBO_JACK_AUTO_CTL2, &buf);
201*4882a593Smuzhiyun 		if (ret < 0)
202*4882a593Smuzhiyun 			goto io_error;
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 		reg = RT711_VERB_GET_PIN_SENSE | RT711_HP_OUT;
205*4882a593Smuzhiyun 		ret = regmap_read(rt711->regmap, reg, &jack_status);
206*4882a593Smuzhiyun 		if (ret < 0)
207*4882a593Smuzhiyun 			goto io_error;
208*4882a593Smuzhiyun 		if ((jack_status & (1 << 31)) == 0)
209*4882a593Smuzhiyun 			goto remove_error;
210*4882a593Smuzhiyun 	}
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 	if (loop >= 500)
213*4882a593Smuzhiyun 		goto to_error;
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	if (buf & RT711_COMBOJACK_AUTO_DET_TRS)
216*4882a593Smuzhiyun 		rt711->jack_type = SND_JACK_HEADPHONE;
217*4882a593Smuzhiyun 	else if ((buf & RT711_COMBOJACK_AUTO_DET_CTIA) ||
218*4882a593Smuzhiyun 		(buf & RT711_COMBOJACK_AUTO_DET_OMTP))
219*4882a593Smuzhiyun 		rt711->jack_type = SND_JACK_HEADSET;
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun 	return 0;
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun to_error:
224*4882a593Smuzhiyun 	ret = -ETIMEDOUT;
225*4882a593Smuzhiyun 	pr_err_ratelimited("Time-out error in %s\n", __func__);
226*4882a593Smuzhiyun 	return ret;
227*4882a593Smuzhiyun io_error:
228*4882a593Smuzhiyun 	pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret);
229*4882a593Smuzhiyun 	return ret;
230*4882a593Smuzhiyun remove_error:
231*4882a593Smuzhiyun 	pr_err_ratelimited("Jack removal in %s\n", __func__);
232*4882a593Smuzhiyun 	return -ENODEV;
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun 
rt711_jack_detect_handler(struct work_struct * work)235*4882a593Smuzhiyun static void rt711_jack_detect_handler(struct work_struct *work)
236*4882a593Smuzhiyun {
237*4882a593Smuzhiyun 	struct rt711_priv *rt711 =
238*4882a593Smuzhiyun 		container_of(work, struct rt711_priv, jack_detect_work.work);
239*4882a593Smuzhiyun 	int btn_type = 0, ret;
240*4882a593Smuzhiyun 	unsigned int jack_status = 0, reg;
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 	if (!rt711->hs_jack)
243*4882a593Smuzhiyun 		return;
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	if (!rt711->component->card->instantiated)
246*4882a593Smuzhiyun 		return;
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 	reg = RT711_VERB_GET_PIN_SENSE | RT711_HP_OUT;
249*4882a593Smuzhiyun 	ret = regmap_read(rt711->regmap, reg, &jack_status);
250*4882a593Smuzhiyun 	if (ret < 0)
251*4882a593Smuzhiyun 		goto io_error;
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	/* pin attached */
254*4882a593Smuzhiyun 	if (jack_status & (1 << 31)) {
255*4882a593Smuzhiyun 		/* jack in */
256*4882a593Smuzhiyun 		if (rt711->jack_type == 0) {
257*4882a593Smuzhiyun 			ret = rt711_headset_detect(rt711);
258*4882a593Smuzhiyun 			if (ret < 0)
259*4882a593Smuzhiyun 				return;
260*4882a593Smuzhiyun 			if (rt711->jack_type == SND_JACK_HEADSET)
261*4882a593Smuzhiyun 				btn_type = rt711_button_detect(rt711);
262*4882a593Smuzhiyun 		} else if (rt711->jack_type == SND_JACK_HEADSET) {
263*4882a593Smuzhiyun 			/* jack is already in, report button event */
264*4882a593Smuzhiyun 			btn_type = rt711_button_detect(rt711);
265*4882a593Smuzhiyun 		}
266*4882a593Smuzhiyun 	} else {
267*4882a593Smuzhiyun 		/* jack out */
268*4882a593Smuzhiyun 		rt711->jack_type = 0;
269*4882a593Smuzhiyun 	}
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 	dev_dbg(&rt711->slave->dev,
272*4882a593Smuzhiyun 		"in %s, jack_type=0x%x\n", __func__, rt711->jack_type);
273*4882a593Smuzhiyun 	dev_dbg(&rt711->slave->dev,
274*4882a593Smuzhiyun 		"in %s, btn_type=0x%x\n", __func__, btn_type);
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun 	snd_soc_jack_report(rt711->hs_jack, rt711->jack_type | btn_type,
277*4882a593Smuzhiyun 			SND_JACK_HEADSET |
278*4882a593Smuzhiyun 			SND_JACK_BTN_0 | SND_JACK_BTN_1 |
279*4882a593Smuzhiyun 			SND_JACK_BTN_2 | SND_JACK_BTN_3);
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun 	if (btn_type) {
282*4882a593Smuzhiyun 		/* button released */
283*4882a593Smuzhiyun 		snd_soc_jack_report(rt711->hs_jack, rt711->jack_type,
284*4882a593Smuzhiyun 			SND_JACK_HEADSET |
285*4882a593Smuzhiyun 			SND_JACK_BTN_0 | SND_JACK_BTN_1 |
286*4882a593Smuzhiyun 			SND_JACK_BTN_2 | SND_JACK_BTN_3);
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 		mod_delayed_work(system_power_efficient_wq,
289*4882a593Smuzhiyun 			&rt711->jack_btn_check_work, msecs_to_jiffies(200));
290*4882a593Smuzhiyun 	}
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun 	return;
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun io_error:
295*4882a593Smuzhiyun 	pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret);
296*4882a593Smuzhiyun }
297*4882a593Smuzhiyun 
rt711_btn_check_handler(struct work_struct * work)298*4882a593Smuzhiyun static void rt711_btn_check_handler(struct work_struct *work)
299*4882a593Smuzhiyun {
300*4882a593Smuzhiyun 	struct rt711_priv *rt711 = container_of(work, struct rt711_priv,
301*4882a593Smuzhiyun 		jack_btn_check_work.work);
302*4882a593Smuzhiyun 	int btn_type = 0, ret;
303*4882a593Smuzhiyun 	unsigned int jack_status = 0, reg;
304*4882a593Smuzhiyun 
305*4882a593Smuzhiyun 	reg = RT711_VERB_GET_PIN_SENSE | RT711_HP_OUT;
306*4882a593Smuzhiyun 	ret = regmap_read(rt711->regmap, reg, &jack_status);
307*4882a593Smuzhiyun 	if (ret < 0)
308*4882a593Smuzhiyun 		goto io_error;
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 	/* pin attached */
311*4882a593Smuzhiyun 	if (jack_status & (1 << 31)) {
312*4882a593Smuzhiyun 		if (rt711->jack_type == SND_JACK_HEADSET) {
313*4882a593Smuzhiyun 			/* jack is already in, report button event */
314*4882a593Smuzhiyun 			btn_type = rt711_button_detect(rt711);
315*4882a593Smuzhiyun 		}
316*4882a593Smuzhiyun 	} else {
317*4882a593Smuzhiyun 		rt711->jack_type = 0;
318*4882a593Smuzhiyun 	}
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	/* cbj comparator */
321*4882a593Smuzhiyun 	ret = rt711_index_read(rt711->regmap, RT711_VENDOR_REG,
322*4882a593Smuzhiyun 		RT711_COMBO_JACK_AUTO_CTL2, &reg);
323*4882a593Smuzhiyun 	if (ret < 0)
324*4882a593Smuzhiyun 		goto io_error;
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	if ((reg & 0xf0) == 0xf0)
327*4882a593Smuzhiyun 		btn_type = 0;
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun 	dev_dbg(&rt711->slave->dev,
330*4882a593Smuzhiyun 		"%s, btn_type=0x%x\n",	__func__, btn_type);
331*4882a593Smuzhiyun 	snd_soc_jack_report(rt711->hs_jack, rt711->jack_type | btn_type,
332*4882a593Smuzhiyun 			SND_JACK_HEADSET |
333*4882a593Smuzhiyun 			SND_JACK_BTN_0 | SND_JACK_BTN_1 |
334*4882a593Smuzhiyun 			SND_JACK_BTN_2 | SND_JACK_BTN_3);
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 	if (btn_type) {
337*4882a593Smuzhiyun 		/* button released */
338*4882a593Smuzhiyun 		snd_soc_jack_report(rt711->hs_jack, rt711->jack_type,
339*4882a593Smuzhiyun 			SND_JACK_HEADSET |
340*4882a593Smuzhiyun 			SND_JACK_BTN_0 | SND_JACK_BTN_1 |
341*4882a593Smuzhiyun 			SND_JACK_BTN_2 | SND_JACK_BTN_3);
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun 		mod_delayed_work(system_power_efficient_wq,
344*4882a593Smuzhiyun 			&rt711->jack_btn_check_work, msecs_to_jiffies(200));
345*4882a593Smuzhiyun 	}
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	return;
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun io_error:
350*4882a593Smuzhiyun 	pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret);
351*4882a593Smuzhiyun }
352*4882a593Smuzhiyun 
rt711_jack_init(struct rt711_priv * rt711)353*4882a593Smuzhiyun static void rt711_jack_init(struct rt711_priv *rt711)
354*4882a593Smuzhiyun {
355*4882a593Smuzhiyun 	struct snd_soc_dapm_context *dapm =
356*4882a593Smuzhiyun 		snd_soc_component_get_dapm(rt711->component);
357*4882a593Smuzhiyun 
358*4882a593Smuzhiyun 	mutex_lock(&rt711->calibrate_mutex);
359*4882a593Smuzhiyun 	/* power on */
360*4882a593Smuzhiyun 	if (dapm->bias_level <= SND_SOC_BIAS_STANDBY)
361*4882a593Smuzhiyun 		regmap_write(rt711->regmap,
362*4882a593Smuzhiyun 			RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D0);
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun 	if (rt711->hs_jack) {
365*4882a593Smuzhiyun 		/* unsolicited response & IRQ control */
366*4882a593Smuzhiyun 		regmap_write(rt711->regmap,
367*4882a593Smuzhiyun 			RT711_SET_MIC2_UNSOLICITED_ENABLE, 0x82);
368*4882a593Smuzhiyun 		regmap_write(rt711->regmap,
369*4882a593Smuzhiyun 			RT711_SET_HP_UNSOLICITED_ENABLE, 0x81);
370*4882a593Smuzhiyun 		regmap_write(rt711->regmap,
371*4882a593Smuzhiyun 			RT711_SET_INLINE_UNSOLICITED_ENABLE, 0x83);
372*4882a593Smuzhiyun 		rt711_index_write(rt711->regmap, RT711_VENDOR_REG,
373*4882a593Smuzhiyun 			0x10, 0x2420);
374*4882a593Smuzhiyun 		rt711_index_write(rt711->regmap, RT711_VENDOR_REG,
375*4882a593Smuzhiyun 			0x19, 0x2e11);
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun 		switch (rt711->jd_src) {
378*4882a593Smuzhiyun 		case RT711_JD1:
379*4882a593Smuzhiyun 			/* default settings was already for JD1 */
380*4882a593Smuzhiyun 			break;
381*4882a593Smuzhiyun 		case RT711_JD2:
382*4882a593Smuzhiyun 			rt711_index_update_bits(rt711->regmap, RT711_VENDOR_REG,
383*4882a593Smuzhiyun 				RT711_JD_CTL2, RT711_JD2_2PORT_200K_DECODE_HP |
384*4882a593Smuzhiyun 				RT711_HP_JD_SEL_JD2,
385*4882a593Smuzhiyun 				RT711_JD2_2PORT_200K_DECODE_HP |
386*4882a593Smuzhiyun 				RT711_HP_JD_SEL_JD2);
387*4882a593Smuzhiyun 			rt711_index_update_bits(rt711->regmap, RT711_VENDOR_REG,
388*4882a593Smuzhiyun 				RT711_CC_DET1,
389*4882a593Smuzhiyun 				RT711_HP_JD_FINAL_RESULT_CTL_JD12,
390*4882a593Smuzhiyun 				RT711_HP_JD_FINAL_RESULT_CTL_JD12);
391*4882a593Smuzhiyun 			break;
392*4882a593Smuzhiyun 		default:
393*4882a593Smuzhiyun 			dev_warn(rt711->component->dev, "Wrong JD source\n");
394*4882a593Smuzhiyun 			break;
395*4882a593Smuzhiyun 		}
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun 		dev_dbg(&rt711->slave->dev, "in %s enable\n", __func__);
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun 		mod_delayed_work(system_power_efficient_wq,
400*4882a593Smuzhiyun 			&rt711->jack_detect_work, msecs_to_jiffies(250));
401*4882a593Smuzhiyun 	} else {
402*4882a593Smuzhiyun 		regmap_write(rt711->regmap,
403*4882a593Smuzhiyun 			RT711_SET_MIC2_UNSOLICITED_ENABLE, 0x00);
404*4882a593Smuzhiyun 		regmap_write(rt711->regmap,
405*4882a593Smuzhiyun 			RT711_SET_HP_UNSOLICITED_ENABLE, 0x00);
406*4882a593Smuzhiyun 		regmap_write(rt711->regmap,
407*4882a593Smuzhiyun 			RT711_SET_INLINE_UNSOLICITED_ENABLE, 0x00);
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun 		dev_dbg(&rt711->slave->dev, "in %s disable\n", __func__);
410*4882a593Smuzhiyun 	}
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun 	/* power off */
413*4882a593Smuzhiyun 	if (dapm->bias_level <= SND_SOC_BIAS_STANDBY)
414*4882a593Smuzhiyun 		regmap_write(rt711->regmap,
415*4882a593Smuzhiyun 			RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3);
416*4882a593Smuzhiyun 	mutex_unlock(&rt711->calibrate_mutex);
417*4882a593Smuzhiyun }
418*4882a593Smuzhiyun 
rt711_set_jack_detect(struct snd_soc_component * component,struct snd_soc_jack * hs_jack,void * data)419*4882a593Smuzhiyun static int rt711_set_jack_detect(struct snd_soc_component *component,
420*4882a593Smuzhiyun 	struct snd_soc_jack *hs_jack, void *data)
421*4882a593Smuzhiyun {
422*4882a593Smuzhiyun 	struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component);
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun 	rt711->hs_jack = hs_jack;
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun 	if (!rt711->hw_init) {
427*4882a593Smuzhiyun 		dev_dbg(&rt711->slave->dev,
428*4882a593Smuzhiyun 			"%s hw_init not ready yet\n", __func__);
429*4882a593Smuzhiyun 		return 0;
430*4882a593Smuzhiyun 	}
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun 	rt711_jack_init(rt711);
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 	return 0;
435*4882a593Smuzhiyun }
436*4882a593Smuzhiyun 
rt711_get_gain(struct rt711_priv * rt711,unsigned int addr_h,unsigned int addr_l,unsigned int val_h,unsigned int * r_val,unsigned int * l_val)437*4882a593Smuzhiyun static void rt711_get_gain(struct rt711_priv *rt711, unsigned int addr_h,
438*4882a593Smuzhiyun 				unsigned int addr_l, unsigned int val_h,
439*4882a593Smuzhiyun 				unsigned int *r_val, unsigned int *l_val)
440*4882a593Smuzhiyun {
441*4882a593Smuzhiyun 	/* R Channel */
442*4882a593Smuzhiyun 	*r_val = (val_h << 8);
443*4882a593Smuzhiyun 	regmap_read(rt711->regmap, addr_l, r_val);
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun 	/* L Channel */
446*4882a593Smuzhiyun 	val_h |= 0x20;
447*4882a593Smuzhiyun 	*l_val = (val_h << 8);
448*4882a593Smuzhiyun 	regmap_read(rt711->regmap, addr_h, l_val);
449*4882a593Smuzhiyun }
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun /* For Verb-Set Amplifier Gain (Verb ID = 3h) */
rt711_set_amp_gain_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)452*4882a593Smuzhiyun static int rt711_set_amp_gain_put(struct snd_kcontrol *kcontrol,
453*4882a593Smuzhiyun 		struct snd_ctl_elem_value *ucontrol)
454*4882a593Smuzhiyun {
455*4882a593Smuzhiyun 	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
456*4882a593Smuzhiyun 	struct snd_soc_dapm_context *dapm =
457*4882a593Smuzhiyun 		snd_soc_component_get_dapm(component);
458*4882a593Smuzhiyun 	struct soc_mixer_control *mc =
459*4882a593Smuzhiyun 		(struct soc_mixer_control *)kcontrol->private_value;
460*4882a593Smuzhiyun 	struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component);
461*4882a593Smuzhiyun 	unsigned int addr_h, addr_l, val_h, val_ll, val_lr;
462*4882a593Smuzhiyun 	unsigned int read_ll, read_rl;
463*4882a593Smuzhiyun 	int i;
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun 	mutex_lock(&rt711->calibrate_mutex);
466*4882a593Smuzhiyun 
467*4882a593Smuzhiyun 	/* Can't use update bit function, so read the original value first */
468*4882a593Smuzhiyun 	addr_h = mc->reg;
469*4882a593Smuzhiyun 	addr_l = mc->rreg;
470*4882a593Smuzhiyun 	if (mc->shift == RT711_DIR_OUT_SFT) /* output */
471*4882a593Smuzhiyun 		val_h = 0x80;
472*4882a593Smuzhiyun 	else /* input */
473*4882a593Smuzhiyun 		val_h = 0x0;
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun 	rt711_get_gain(rt711, addr_h, addr_l, val_h, &read_rl, &read_ll);
476*4882a593Smuzhiyun 
477*4882a593Smuzhiyun 	/* L Channel */
478*4882a593Smuzhiyun 	if (mc->invert) {
479*4882a593Smuzhiyun 		/* for mute/unmute */
480*4882a593Smuzhiyun 		val_ll = (mc->max - ucontrol->value.integer.value[0])
481*4882a593Smuzhiyun 					<< RT711_MUTE_SFT;
482*4882a593Smuzhiyun 		/* keep gain */
483*4882a593Smuzhiyun 		read_ll = read_ll & 0x7f;
484*4882a593Smuzhiyun 		val_ll |= read_ll;
485*4882a593Smuzhiyun 	} else {
486*4882a593Smuzhiyun 		/* for gain */
487*4882a593Smuzhiyun 		val_ll = ((ucontrol->value.integer.value[0]) & 0x7f);
488*4882a593Smuzhiyun 		if (val_ll > mc->max)
489*4882a593Smuzhiyun 			val_ll = mc->max;
490*4882a593Smuzhiyun 		/* keep mute status */
491*4882a593Smuzhiyun 		read_ll = read_ll & (1 << RT711_MUTE_SFT);
492*4882a593Smuzhiyun 		val_ll |= read_ll;
493*4882a593Smuzhiyun 	}
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun 	if (dapm->bias_level <= SND_SOC_BIAS_STANDBY)
496*4882a593Smuzhiyun 		regmap_write(rt711->regmap,
497*4882a593Smuzhiyun 				RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D0);
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun 	/* R Channel */
500*4882a593Smuzhiyun 	if (mc->invert) {
501*4882a593Smuzhiyun 		/* for mute/unmute */
502*4882a593Smuzhiyun 		val_lr = (mc->max - ucontrol->value.integer.value[1])
503*4882a593Smuzhiyun 					<< RT711_MUTE_SFT;
504*4882a593Smuzhiyun 		/* keep gain */
505*4882a593Smuzhiyun 		read_rl = read_rl & 0x7f;
506*4882a593Smuzhiyun 		val_lr |= read_rl;
507*4882a593Smuzhiyun 	} else {
508*4882a593Smuzhiyun 		/* for gain */
509*4882a593Smuzhiyun 		val_lr = ((ucontrol->value.integer.value[1]) & 0x7f);
510*4882a593Smuzhiyun 		if (val_lr > mc->max)
511*4882a593Smuzhiyun 			val_lr = mc->max;
512*4882a593Smuzhiyun 		/* keep mute status */
513*4882a593Smuzhiyun 		read_rl = read_rl & (1 << RT711_MUTE_SFT);
514*4882a593Smuzhiyun 		val_lr |= read_rl;
515*4882a593Smuzhiyun 	}
516*4882a593Smuzhiyun 
517*4882a593Smuzhiyun 	for (i = 0; i < 3; i++) { /* retry 3 times at most */
518*4882a593Smuzhiyun 
519*4882a593Smuzhiyun 		if (val_ll == val_lr) {
520*4882a593Smuzhiyun 			/* Set both L/R channels at the same time */
521*4882a593Smuzhiyun 			val_h = (1 << mc->shift) | (3 << 4);
522*4882a593Smuzhiyun 			regmap_write(rt711->regmap,
523*4882a593Smuzhiyun 				addr_h, (val_h << 8 | val_ll));
524*4882a593Smuzhiyun 			regmap_write(rt711->regmap,
525*4882a593Smuzhiyun 				addr_l, (val_h << 8 | val_ll));
526*4882a593Smuzhiyun 		} else {
527*4882a593Smuzhiyun 			/* Lch*/
528*4882a593Smuzhiyun 			val_h = (1 << mc->shift) | (1 << 5);
529*4882a593Smuzhiyun 			regmap_write(rt711->regmap,
530*4882a593Smuzhiyun 				addr_h, (val_h << 8 | val_ll));
531*4882a593Smuzhiyun 
532*4882a593Smuzhiyun 			/* Rch */
533*4882a593Smuzhiyun 			val_h = (1 << mc->shift) | (1 << 4);
534*4882a593Smuzhiyun 			regmap_write(rt711->regmap,
535*4882a593Smuzhiyun 				addr_l, (val_h << 8 | val_lr));
536*4882a593Smuzhiyun 		}
537*4882a593Smuzhiyun 		/* check result */
538*4882a593Smuzhiyun 		if (mc->shift == RT711_DIR_OUT_SFT) /* output */
539*4882a593Smuzhiyun 			val_h = 0x80;
540*4882a593Smuzhiyun 		else /* input */
541*4882a593Smuzhiyun 			val_h = 0x0;
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun 		rt711_get_gain(rt711, addr_h, addr_l, val_h,
544*4882a593Smuzhiyun 					&read_rl, &read_ll);
545*4882a593Smuzhiyun 		if (read_rl == val_lr && read_ll == val_ll)
546*4882a593Smuzhiyun 			break;
547*4882a593Smuzhiyun 	}
548*4882a593Smuzhiyun 
549*4882a593Smuzhiyun 	if (dapm->bias_level <= SND_SOC_BIAS_STANDBY)
550*4882a593Smuzhiyun 		regmap_write(rt711->regmap,
551*4882a593Smuzhiyun 				RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3);
552*4882a593Smuzhiyun 
553*4882a593Smuzhiyun 	mutex_unlock(&rt711->calibrate_mutex);
554*4882a593Smuzhiyun 	return 0;
555*4882a593Smuzhiyun }
556*4882a593Smuzhiyun 
rt711_set_amp_gain_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)557*4882a593Smuzhiyun static int rt711_set_amp_gain_get(struct snd_kcontrol *kcontrol,
558*4882a593Smuzhiyun 		struct snd_ctl_elem_value *ucontrol)
559*4882a593Smuzhiyun {
560*4882a593Smuzhiyun 	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
561*4882a593Smuzhiyun 	struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component);
562*4882a593Smuzhiyun 	struct soc_mixer_control *mc =
563*4882a593Smuzhiyun 		(struct soc_mixer_control *)kcontrol->private_value;
564*4882a593Smuzhiyun 	unsigned int addr_h, addr_l, val_h;
565*4882a593Smuzhiyun 	unsigned int read_ll, read_rl;
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun 	/* switch to get command */
568*4882a593Smuzhiyun 	addr_h = mc->reg;
569*4882a593Smuzhiyun 	addr_l = mc->rreg;
570*4882a593Smuzhiyun 	if (mc->shift == RT711_DIR_OUT_SFT) /* output */
571*4882a593Smuzhiyun 		val_h = 0x80;
572*4882a593Smuzhiyun 	else /* input */
573*4882a593Smuzhiyun 		val_h = 0x0;
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun 	rt711_get_gain(rt711, addr_h, addr_l, val_h, &read_rl, &read_ll);
576*4882a593Smuzhiyun 
577*4882a593Smuzhiyun 	if (mc->invert) {
578*4882a593Smuzhiyun 		/* mute/unmute for switch controls */
579*4882a593Smuzhiyun 		read_ll = !((read_ll & 0x80) >> RT711_MUTE_SFT);
580*4882a593Smuzhiyun 		read_rl = !((read_rl & 0x80) >> RT711_MUTE_SFT);
581*4882a593Smuzhiyun 	} else {
582*4882a593Smuzhiyun 		/* for gain volume controls */
583*4882a593Smuzhiyun 		read_ll = read_ll & 0x7f;
584*4882a593Smuzhiyun 		read_rl = read_rl & 0x7f;
585*4882a593Smuzhiyun 	}
586*4882a593Smuzhiyun 	ucontrol->value.integer.value[0] = read_ll;
587*4882a593Smuzhiyun 	ucontrol->value.integer.value[1] = read_rl;
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun 	return 0;
590*4882a593Smuzhiyun }
591*4882a593Smuzhiyun 
592*4882a593Smuzhiyun static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6525, 75, 0);
593*4882a593Smuzhiyun static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1725, 75, 0);
594*4882a593Smuzhiyun static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0);
595*4882a593Smuzhiyun 
596*4882a593Smuzhiyun static const struct snd_kcontrol_new rt711_snd_controls[] = {
597*4882a593Smuzhiyun 	SOC_DOUBLE_R_EXT_TLV("DAC Surr Playback Volume",
598*4882a593Smuzhiyun 		RT711_SET_GAIN_DAC2_H, RT711_SET_GAIN_DAC2_L,
599*4882a593Smuzhiyun 		RT711_DIR_OUT_SFT, 0x57, 0,
600*4882a593Smuzhiyun 		rt711_set_amp_gain_get, rt711_set_amp_gain_put, out_vol_tlv),
601*4882a593Smuzhiyun 	SOC_DOUBLE_R_EXT("ADC 08 Capture Switch",
602*4882a593Smuzhiyun 		RT711_SET_GAIN_ADC2_H, RT711_SET_GAIN_ADC2_L,
603*4882a593Smuzhiyun 		RT711_DIR_IN_SFT, 1, 1,
604*4882a593Smuzhiyun 		rt711_set_amp_gain_get, rt711_set_amp_gain_put),
605*4882a593Smuzhiyun 	SOC_DOUBLE_R_EXT("ADC 09 Capture Switch",
606*4882a593Smuzhiyun 		RT711_SET_GAIN_ADC1_H, RT711_SET_GAIN_ADC1_L,
607*4882a593Smuzhiyun 		RT711_DIR_IN_SFT, 1, 1,
608*4882a593Smuzhiyun 		rt711_set_amp_gain_get, rt711_set_amp_gain_put),
609*4882a593Smuzhiyun 	SOC_DOUBLE_R_EXT_TLV("ADC 08 Capture Volume",
610*4882a593Smuzhiyun 		RT711_SET_GAIN_ADC2_H, RT711_SET_GAIN_ADC2_L,
611*4882a593Smuzhiyun 		RT711_DIR_IN_SFT, 0x3f, 0,
612*4882a593Smuzhiyun 		rt711_set_amp_gain_get, rt711_set_amp_gain_put, in_vol_tlv),
613*4882a593Smuzhiyun 	SOC_DOUBLE_R_EXT_TLV("ADC 09 Capture Volume",
614*4882a593Smuzhiyun 		RT711_SET_GAIN_ADC1_H, RT711_SET_GAIN_ADC1_L,
615*4882a593Smuzhiyun 		RT711_DIR_IN_SFT, 0x3f, 0,
616*4882a593Smuzhiyun 		rt711_set_amp_gain_get, rt711_set_amp_gain_put, in_vol_tlv),
617*4882a593Smuzhiyun 	SOC_DOUBLE_R_EXT_TLV("AMIC Volume",
618*4882a593Smuzhiyun 		RT711_SET_GAIN_AMIC_H, RT711_SET_GAIN_AMIC_L,
619*4882a593Smuzhiyun 		RT711_DIR_IN_SFT, 3, 0,
620*4882a593Smuzhiyun 		rt711_set_amp_gain_get, rt711_set_amp_gain_put, mic_vol_tlv),
621*4882a593Smuzhiyun 	SOC_DOUBLE_R_EXT_TLV("DMIC1 Volume",
622*4882a593Smuzhiyun 		RT711_SET_GAIN_DMIC1_H, RT711_SET_GAIN_DMIC1_L,
623*4882a593Smuzhiyun 		RT711_DIR_IN_SFT, 3, 0,
624*4882a593Smuzhiyun 		rt711_set_amp_gain_get, rt711_set_amp_gain_put, mic_vol_tlv),
625*4882a593Smuzhiyun 	SOC_DOUBLE_R_EXT_TLV("DMIC2 Volume",
626*4882a593Smuzhiyun 		RT711_SET_GAIN_DMIC2_H, RT711_SET_GAIN_DMIC2_L,
627*4882a593Smuzhiyun 		RT711_DIR_IN_SFT, 3, 0,
628*4882a593Smuzhiyun 		rt711_set_amp_gain_get, rt711_set_amp_gain_put, mic_vol_tlv),
629*4882a593Smuzhiyun };
630*4882a593Smuzhiyun 
rt711_mux_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)631*4882a593Smuzhiyun static int rt711_mux_get(struct snd_kcontrol *kcontrol,
632*4882a593Smuzhiyun 			struct snd_ctl_elem_value *ucontrol)
633*4882a593Smuzhiyun {
634*4882a593Smuzhiyun 	struct snd_soc_component *component =
635*4882a593Smuzhiyun 		snd_soc_dapm_kcontrol_component(kcontrol);
636*4882a593Smuzhiyun 	struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component);
637*4882a593Smuzhiyun 	unsigned int reg, val = 0, nid;
638*4882a593Smuzhiyun 	int ret;
639*4882a593Smuzhiyun 
640*4882a593Smuzhiyun 	if (strstr(ucontrol->id.name, "ADC 22 Mux"))
641*4882a593Smuzhiyun 		nid = RT711_MIXER_IN1;
642*4882a593Smuzhiyun 	else if (strstr(ucontrol->id.name, "ADC 23 Mux"))
643*4882a593Smuzhiyun 		nid = RT711_MIXER_IN2;
644*4882a593Smuzhiyun 	else
645*4882a593Smuzhiyun 		return -EINVAL;
646*4882a593Smuzhiyun 
647*4882a593Smuzhiyun 	/* vid = 0xf01 */
648*4882a593Smuzhiyun 	reg = RT711_VERB_SET_CONNECT_SEL | nid;
649*4882a593Smuzhiyun 	ret = regmap_read(rt711->regmap, reg, &val);
650*4882a593Smuzhiyun 	if (ret < 0) {
651*4882a593Smuzhiyun 		dev_err(component->dev, "%s: sdw read failed: %d\n",
652*4882a593Smuzhiyun 			__func__, ret);
653*4882a593Smuzhiyun 		return ret;
654*4882a593Smuzhiyun 	}
655*4882a593Smuzhiyun 
656*4882a593Smuzhiyun 	ucontrol->value.enumerated.item[0] = val;
657*4882a593Smuzhiyun 
658*4882a593Smuzhiyun 	return 0;
659*4882a593Smuzhiyun }
660*4882a593Smuzhiyun 
rt711_mux_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)661*4882a593Smuzhiyun static int rt711_mux_put(struct snd_kcontrol *kcontrol,
662*4882a593Smuzhiyun 			struct snd_ctl_elem_value *ucontrol)
663*4882a593Smuzhiyun {
664*4882a593Smuzhiyun 	struct snd_soc_component *component =
665*4882a593Smuzhiyun 		snd_soc_dapm_kcontrol_component(kcontrol);
666*4882a593Smuzhiyun 	struct snd_soc_dapm_context *dapm =
667*4882a593Smuzhiyun 		snd_soc_dapm_kcontrol_dapm(kcontrol);
668*4882a593Smuzhiyun 	struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component);
669*4882a593Smuzhiyun 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
670*4882a593Smuzhiyun 	unsigned int *item = ucontrol->value.enumerated.item;
671*4882a593Smuzhiyun 	unsigned int val, val2 = 0, change, reg, nid;
672*4882a593Smuzhiyun 	int ret;
673*4882a593Smuzhiyun 
674*4882a593Smuzhiyun 	if (item[0] >= e->items)
675*4882a593Smuzhiyun 		return -EINVAL;
676*4882a593Smuzhiyun 
677*4882a593Smuzhiyun 	if (strstr(ucontrol->id.name, "ADC 22 Mux"))
678*4882a593Smuzhiyun 		nid = RT711_MIXER_IN1;
679*4882a593Smuzhiyun 	else if (strstr(ucontrol->id.name, "ADC 23 Mux"))
680*4882a593Smuzhiyun 		nid = RT711_MIXER_IN2;
681*4882a593Smuzhiyun 	else
682*4882a593Smuzhiyun 		return -EINVAL;
683*4882a593Smuzhiyun 
684*4882a593Smuzhiyun 	/* Verb ID = 0x701h */
685*4882a593Smuzhiyun 	val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
686*4882a593Smuzhiyun 
687*4882a593Smuzhiyun 	reg = RT711_VERB_SET_CONNECT_SEL | nid;
688*4882a593Smuzhiyun 	ret = regmap_read(rt711->regmap, reg, &val2);
689*4882a593Smuzhiyun 	if (ret < 0) {
690*4882a593Smuzhiyun 		dev_err(component->dev, "%s: sdw read failed: %d\n",
691*4882a593Smuzhiyun 			__func__, ret);
692*4882a593Smuzhiyun 		return ret;
693*4882a593Smuzhiyun 	}
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun 	if (val == val2)
696*4882a593Smuzhiyun 		change = 0;
697*4882a593Smuzhiyun 	else
698*4882a593Smuzhiyun 		change = 1;
699*4882a593Smuzhiyun 
700*4882a593Smuzhiyun 	if (change) {
701*4882a593Smuzhiyun 		reg = RT711_VERB_SET_CONNECT_SEL | nid;
702*4882a593Smuzhiyun 		regmap_write(rt711->regmap, reg, val);
703*4882a593Smuzhiyun 	}
704*4882a593Smuzhiyun 
705*4882a593Smuzhiyun 	snd_soc_dapm_mux_update_power(dapm, kcontrol,
706*4882a593Smuzhiyun 						item[0], e, NULL);
707*4882a593Smuzhiyun 
708*4882a593Smuzhiyun 	return change;
709*4882a593Smuzhiyun }
710*4882a593Smuzhiyun 
711*4882a593Smuzhiyun static const char * const adc_mux_text[] = {
712*4882a593Smuzhiyun 	"MIC2",
713*4882a593Smuzhiyun 	"LINE1",
714*4882a593Smuzhiyun 	"LINE2",
715*4882a593Smuzhiyun 	"DMIC",
716*4882a593Smuzhiyun };
717*4882a593Smuzhiyun 
718*4882a593Smuzhiyun static SOC_ENUM_SINGLE_DECL(
719*4882a593Smuzhiyun 	rt711_adc22_enum, SND_SOC_NOPM, 0, adc_mux_text);
720*4882a593Smuzhiyun 
721*4882a593Smuzhiyun static SOC_ENUM_SINGLE_DECL(
722*4882a593Smuzhiyun 	rt711_adc23_enum, SND_SOC_NOPM, 0, adc_mux_text);
723*4882a593Smuzhiyun 
724*4882a593Smuzhiyun static const struct snd_kcontrol_new rt711_adc22_mux =
725*4882a593Smuzhiyun 	SOC_DAPM_ENUM_EXT("ADC 22 Mux", rt711_adc22_enum,
726*4882a593Smuzhiyun 			rt711_mux_get, rt711_mux_put);
727*4882a593Smuzhiyun 
728*4882a593Smuzhiyun static const struct snd_kcontrol_new rt711_adc23_mux =
729*4882a593Smuzhiyun 	SOC_DAPM_ENUM_EXT("ADC 23 Mux", rt711_adc23_enum,
730*4882a593Smuzhiyun 			rt711_mux_get, rt711_mux_put);
731*4882a593Smuzhiyun 
rt711_dac_surround_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)732*4882a593Smuzhiyun static int rt711_dac_surround_event(struct snd_soc_dapm_widget *w,
733*4882a593Smuzhiyun 	struct snd_kcontrol *kcontrol, int event)
734*4882a593Smuzhiyun {
735*4882a593Smuzhiyun 	struct snd_soc_component *component =
736*4882a593Smuzhiyun 		snd_soc_dapm_to_component(w->dapm);
737*4882a593Smuzhiyun 	struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component);
738*4882a593Smuzhiyun 	unsigned int val_h = (1 << RT711_DIR_OUT_SFT) | (0x3 << 4);
739*4882a593Smuzhiyun 	unsigned int val_l;
740*4882a593Smuzhiyun 
741*4882a593Smuzhiyun 	switch (event) {
742*4882a593Smuzhiyun 	case SND_SOC_DAPM_POST_PMU:
743*4882a593Smuzhiyun 		regmap_write(rt711->regmap,
744*4882a593Smuzhiyun 			RT711_SET_STREAMID_DAC2, 0x10);
745*4882a593Smuzhiyun 
746*4882a593Smuzhiyun 		val_l = 0x00;
747*4882a593Smuzhiyun 		regmap_write(rt711->regmap,
748*4882a593Smuzhiyun 			RT711_SET_GAIN_HP_H, (val_h << 8 | val_l));
749*4882a593Smuzhiyun 		break;
750*4882a593Smuzhiyun 	case SND_SOC_DAPM_PRE_PMD:
751*4882a593Smuzhiyun 		val_l = (1 << RT711_MUTE_SFT);
752*4882a593Smuzhiyun 		regmap_write(rt711->regmap,
753*4882a593Smuzhiyun 			RT711_SET_GAIN_HP_H, (val_h << 8 | val_l));
754*4882a593Smuzhiyun 		usleep_range(50000, 55000);
755*4882a593Smuzhiyun 
756*4882a593Smuzhiyun 		regmap_write(rt711->regmap,
757*4882a593Smuzhiyun 			RT711_SET_STREAMID_DAC2, 0x00);
758*4882a593Smuzhiyun 		break;
759*4882a593Smuzhiyun 	}
760*4882a593Smuzhiyun 	return 0;
761*4882a593Smuzhiyun }
762*4882a593Smuzhiyun 
rt711_adc_09_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)763*4882a593Smuzhiyun static int rt711_adc_09_event(struct snd_soc_dapm_widget *w,
764*4882a593Smuzhiyun 	struct snd_kcontrol *kcontrol, int event)
765*4882a593Smuzhiyun {
766*4882a593Smuzhiyun 	struct snd_soc_component *component =
767*4882a593Smuzhiyun 		snd_soc_dapm_to_component(w->dapm);
768*4882a593Smuzhiyun 	struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component);
769*4882a593Smuzhiyun 
770*4882a593Smuzhiyun 	switch (event) {
771*4882a593Smuzhiyun 	case SND_SOC_DAPM_POST_PMU:
772*4882a593Smuzhiyun 		regmap_write(rt711->regmap,
773*4882a593Smuzhiyun 			RT711_SET_STREAMID_ADC1, 0x10);
774*4882a593Smuzhiyun 		break;
775*4882a593Smuzhiyun 	case SND_SOC_DAPM_PRE_PMD:
776*4882a593Smuzhiyun 		regmap_write(rt711->regmap,
777*4882a593Smuzhiyun 			RT711_SET_STREAMID_ADC1, 0x00);
778*4882a593Smuzhiyun 		break;
779*4882a593Smuzhiyun 	}
780*4882a593Smuzhiyun 	return 0;
781*4882a593Smuzhiyun }
782*4882a593Smuzhiyun 
rt711_adc_08_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)783*4882a593Smuzhiyun static int rt711_adc_08_event(struct snd_soc_dapm_widget *w,
784*4882a593Smuzhiyun 	struct snd_kcontrol *kcontrol, int event)
785*4882a593Smuzhiyun {
786*4882a593Smuzhiyun 	struct snd_soc_component *component =
787*4882a593Smuzhiyun 		snd_soc_dapm_to_component(w->dapm);
788*4882a593Smuzhiyun 	struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component);
789*4882a593Smuzhiyun 
790*4882a593Smuzhiyun 	switch (event) {
791*4882a593Smuzhiyun 	case SND_SOC_DAPM_POST_PMU:
792*4882a593Smuzhiyun 		regmap_write(rt711->regmap,
793*4882a593Smuzhiyun 			RT711_SET_STREAMID_ADC2, 0x10);
794*4882a593Smuzhiyun 		break;
795*4882a593Smuzhiyun 	case SND_SOC_DAPM_PRE_PMD:
796*4882a593Smuzhiyun 		regmap_write(rt711->regmap,
797*4882a593Smuzhiyun 			RT711_SET_STREAMID_ADC2, 0x00);
798*4882a593Smuzhiyun 		break;
799*4882a593Smuzhiyun 	}
800*4882a593Smuzhiyun 	return 0;
801*4882a593Smuzhiyun }
802*4882a593Smuzhiyun 
803*4882a593Smuzhiyun static const struct snd_soc_dapm_widget rt711_dapm_widgets[] = {
804*4882a593Smuzhiyun 	SND_SOC_DAPM_OUTPUT("HP"),
805*4882a593Smuzhiyun 	SND_SOC_DAPM_INPUT("MIC2"),
806*4882a593Smuzhiyun 	SND_SOC_DAPM_INPUT("DMIC1"),
807*4882a593Smuzhiyun 	SND_SOC_DAPM_INPUT("DMIC2"),
808*4882a593Smuzhiyun 	SND_SOC_DAPM_INPUT("LINE1"),
809*4882a593Smuzhiyun 	SND_SOC_DAPM_INPUT("LINE2"),
810*4882a593Smuzhiyun 
811*4882a593Smuzhiyun 	SND_SOC_DAPM_DAC_E("DAC Surround", NULL, SND_SOC_NOPM, 0, 0,
812*4882a593Smuzhiyun 		rt711_dac_surround_event,
813*4882a593Smuzhiyun 		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
814*4882a593Smuzhiyun 	SND_SOC_DAPM_ADC_E("ADC 09", NULL, SND_SOC_NOPM, 0, 0,
815*4882a593Smuzhiyun 		rt711_adc_09_event,
816*4882a593Smuzhiyun 		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
817*4882a593Smuzhiyun 	SND_SOC_DAPM_ADC_E("ADC 08", NULL, SND_SOC_NOPM, 0, 0,
818*4882a593Smuzhiyun 		rt711_adc_08_event,
819*4882a593Smuzhiyun 		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
820*4882a593Smuzhiyun 	SND_SOC_DAPM_MUX("ADC 22 Mux", SND_SOC_NOPM, 0, 0,
821*4882a593Smuzhiyun 		&rt711_adc22_mux),
822*4882a593Smuzhiyun 	SND_SOC_DAPM_MUX("ADC 23 Mux", SND_SOC_NOPM, 0, 0,
823*4882a593Smuzhiyun 		&rt711_adc23_mux),
824*4882a593Smuzhiyun 
825*4882a593Smuzhiyun 	SND_SOC_DAPM_AIF_IN("DP3RX", "DP3 Playback", 0, SND_SOC_NOPM, 0, 0),
826*4882a593Smuzhiyun 	SND_SOC_DAPM_AIF_OUT("DP2TX", "DP2 Capture", 0, SND_SOC_NOPM, 0, 0),
827*4882a593Smuzhiyun 	SND_SOC_DAPM_AIF_OUT("DP4TX", "DP4 Capture", 0, SND_SOC_NOPM, 0, 0),
828*4882a593Smuzhiyun };
829*4882a593Smuzhiyun 
830*4882a593Smuzhiyun static const struct snd_soc_dapm_route rt711_audio_map[] = {
831*4882a593Smuzhiyun 	{"DAC Surround", NULL, "DP3RX"},
832*4882a593Smuzhiyun 	{"DP2TX", NULL, "ADC 09"},
833*4882a593Smuzhiyun 	{"DP4TX", NULL, "ADC 08"},
834*4882a593Smuzhiyun 
835*4882a593Smuzhiyun 	{"ADC 09", NULL, "ADC 22 Mux"},
836*4882a593Smuzhiyun 	{"ADC 08", NULL, "ADC 23 Mux"},
837*4882a593Smuzhiyun 	{"ADC 22 Mux", "DMIC", "DMIC1"},
838*4882a593Smuzhiyun 	{"ADC 22 Mux", "LINE1", "LINE1"},
839*4882a593Smuzhiyun 	{"ADC 22 Mux", "LINE2", "LINE2"},
840*4882a593Smuzhiyun 	{"ADC 22 Mux", "MIC2", "MIC2"},
841*4882a593Smuzhiyun 	{"ADC 23 Mux", "DMIC", "DMIC2"},
842*4882a593Smuzhiyun 	{"ADC 23 Mux", "LINE1", "LINE1"},
843*4882a593Smuzhiyun 	{"ADC 23 Mux", "LINE2", "LINE2"},
844*4882a593Smuzhiyun 	{"ADC 23 Mux", "MIC2", "MIC2"},
845*4882a593Smuzhiyun 
846*4882a593Smuzhiyun 	{"HP", NULL, "DAC Surround"},
847*4882a593Smuzhiyun };
848*4882a593Smuzhiyun 
rt711_set_bias_level(struct snd_soc_component * component,enum snd_soc_bias_level level)849*4882a593Smuzhiyun static int rt711_set_bias_level(struct snd_soc_component *component,
850*4882a593Smuzhiyun 				enum snd_soc_bias_level level)
851*4882a593Smuzhiyun {
852*4882a593Smuzhiyun 	struct snd_soc_dapm_context *dapm =
853*4882a593Smuzhiyun 		snd_soc_component_get_dapm(component);
854*4882a593Smuzhiyun 	struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component);
855*4882a593Smuzhiyun 
856*4882a593Smuzhiyun 	switch (level) {
857*4882a593Smuzhiyun 	case SND_SOC_BIAS_PREPARE:
858*4882a593Smuzhiyun 		if (dapm->bias_level == SND_SOC_BIAS_STANDBY) {
859*4882a593Smuzhiyun 			regmap_write(rt711->regmap,
860*4882a593Smuzhiyun 				RT711_SET_AUDIO_POWER_STATE,
861*4882a593Smuzhiyun 				AC_PWRST_D0);
862*4882a593Smuzhiyun 		}
863*4882a593Smuzhiyun 		break;
864*4882a593Smuzhiyun 
865*4882a593Smuzhiyun 	case SND_SOC_BIAS_STANDBY:
866*4882a593Smuzhiyun 		mutex_lock(&rt711->calibrate_mutex);
867*4882a593Smuzhiyun 		regmap_write(rt711->regmap,
868*4882a593Smuzhiyun 			RT711_SET_AUDIO_POWER_STATE,
869*4882a593Smuzhiyun 			AC_PWRST_D3);
870*4882a593Smuzhiyun 		mutex_unlock(&rt711->calibrate_mutex);
871*4882a593Smuzhiyun 		break;
872*4882a593Smuzhiyun 
873*4882a593Smuzhiyun 	default:
874*4882a593Smuzhiyun 		break;
875*4882a593Smuzhiyun 	}
876*4882a593Smuzhiyun 
877*4882a593Smuzhiyun 	return 0;
878*4882a593Smuzhiyun }
879*4882a593Smuzhiyun 
rt711_parse_dt(struct rt711_priv * rt711,struct device * dev)880*4882a593Smuzhiyun static int rt711_parse_dt(struct rt711_priv *rt711, struct device *dev)
881*4882a593Smuzhiyun {
882*4882a593Smuzhiyun 	device_property_read_u32(dev, "realtek,jd-src",
883*4882a593Smuzhiyun 		&rt711->jd_src);
884*4882a593Smuzhiyun 
885*4882a593Smuzhiyun 	return 0;
886*4882a593Smuzhiyun }
887*4882a593Smuzhiyun 
rt711_probe(struct snd_soc_component * component)888*4882a593Smuzhiyun static int rt711_probe(struct snd_soc_component *component)
889*4882a593Smuzhiyun {
890*4882a593Smuzhiyun 	struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component);
891*4882a593Smuzhiyun 
892*4882a593Smuzhiyun 	rt711_parse_dt(rt711, &rt711->slave->dev);
893*4882a593Smuzhiyun 	rt711->component = component;
894*4882a593Smuzhiyun 
895*4882a593Smuzhiyun 	return 0;
896*4882a593Smuzhiyun }
897*4882a593Smuzhiyun 
rt711_remove(struct snd_soc_component * component)898*4882a593Smuzhiyun static void rt711_remove(struct snd_soc_component *component)
899*4882a593Smuzhiyun {
900*4882a593Smuzhiyun 	struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component);
901*4882a593Smuzhiyun 
902*4882a593Smuzhiyun 	regcache_cache_only(rt711->regmap, true);
903*4882a593Smuzhiyun }
904*4882a593Smuzhiyun 
905*4882a593Smuzhiyun static const struct snd_soc_component_driver soc_codec_dev_rt711 = {
906*4882a593Smuzhiyun 	.probe = rt711_probe,
907*4882a593Smuzhiyun 	.set_bias_level = rt711_set_bias_level,
908*4882a593Smuzhiyun 	.controls = rt711_snd_controls,
909*4882a593Smuzhiyun 	.num_controls = ARRAY_SIZE(rt711_snd_controls),
910*4882a593Smuzhiyun 	.dapm_widgets = rt711_dapm_widgets,
911*4882a593Smuzhiyun 	.num_dapm_widgets = ARRAY_SIZE(rt711_dapm_widgets),
912*4882a593Smuzhiyun 	.dapm_routes = rt711_audio_map,
913*4882a593Smuzhiyun 	.num_dapm_routes = ARRAY_SIZE(rt711_audio_map),
914*4882a593Smuzhiyun 	.set_jack = rt711_set_jack_detect,
915*4882a593Smuzhiyun 	.remove = rt711_remove,
916*4882a593Smuzhiyun };
917*4882a593Smuzhiyun 
rt711_set_sdw_stream(struct snd_soc_dai * dai,void * sdw_stream,int direction)918*4882a593Smuzhiyun static int rt711_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
919*4882a593Smuzhiyun 				int direction)
920*4882a593Smuzhiyun {
921*4882a593Smuzhiyun 	struct sdw_stream_data *stream;
922*4882a593Smuzhiyun 
923*4882a593Smuzhiyun 	if (!sdw_stream)
924*4882a593Smuzhiyun 		return 0;
925*4882a593Smuzhiyun 
926*4882a593Smuzhiyun 	stream = kzalloc(sizeof(*stream), GFP_KERNEL);
927*4882a593Smuzhiyun 	if (!stream)
928*4882a593Smuzhiyun 		return -ENOMEM;
929*4882a593Smuzhiyun 
930*4882a593Smuzhiyun 	stream->sdw_stream = (struct sdw_stream_runtime *)sdw_stream;
931*4882a593Smuzhiyun 
932*4882a593Smuzhiyun 	/* Use tx_mask or rx_mask to configure stream tag and set dma_data */
933*4882a593Smuzhiyun 	if (direction == SNDRV_PCM_STREAM_PLAYBACK)
934*4882a593Smuzhiyun 		dai->playback_dma_data = stream;
935*4882a593Smuzhiyun 	else
936*4882a593Smuzhiyun 		dai->capture_dma_data = stream;
937*4882a593Smuzhiyun 
938*4882a593Smuzhiyun 	return 0;
939*4882a593Smuzhiyun }
940*4882a593Smuzhiyun 
rt711_shutdown(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)941*4882a593Smuzhiyun static void rt711_shutdown(struct snd_pcm_substream *substream,
942*4882a593Smuzhiyun 				struct snd_soc_dai *dai)
943*4882a593Smuzhiyun {
944*4882a593Smuzhiyun 	struct sdw_stream_data *stream;
945*4882a593Smuzhiyun 
946*4882a593Smuzhiyun 	stream = snd_soc_dai_get_dma_data(dai, substream);
947*4882a593Smuzhiyun 	snd_soc_dai_set_dma_data(dai, substream, NULL);
948*4882a593Smuzhiyun 	kfree(stream);
949*4882a593Smuzhiyun }
950*4882a593Smuzhiyun 
rt711_pcm_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)951*4882a593Smuzhiyun static int rt711_pcm_hw_params(struct snd_pcm_substream *substream,
952*4882a593Smuzhiyun 				struct snd_pcm_hw_params *params,
953*4882a593Smuzhiyun 				struct snd_soc_dai *dai)
954*4882a593Smuzhiyun {
955*4882a593Smuzhiyun 	struct snd_soc_component *component = dai->component;
956*4882a593Smuzhiyun 	struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component);
957*4882a593Smuzhiyun 	struct sdw_stream_config stream_config;
958*4882a593Smuzhiyun 	struct sdw_port_config port_config;
959*4882a593Smuzhiyun 	enum sdw_data_direction direction;
960*4882a593Smuzhiyun 	struct sdw_stream_data *stream;
961*4882a593Smuzhiyun 	int retval, port, num_channels;
962*4882a593Smuzhiyun 	unsigned int val = 0;
963*4882a593Smuzhiyun 
964*4882a593Smuzhiyun 	dev_dbg(dai->dev, "%s %s", __func__, dai->name);
965*4882a593Smuzhiyun 	stream = snd_soc_dai_get_dma_data(dai, substream);
966*4882a593Smuzhiyun 
967*4882a593Smuzhiyun 	if (!stream)
968*4882a593Smuzhiyun 		return -EINVAL;
969*4882a593Smuzhiyun 
970*4882a593Smuzhiyun 	if (!rt711->slave)
971*4882a593Smuzhiyun 		return -EINVAL;
972*4882a593Smuzhiyun 
973*4882a593Smuzhiyun 	/* SoundWire specific configuration */
974*4882a593Smuzhiyun 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
975*4882a593Smuzhiyun 		direction = SDW_DATA_DIR_RX;
976*4882a593Smuzhiyun 		port = 3;
977*4882a593Smuzhiyun 	} else {
978*4882a593Smuzhiyun 		direction = SDW_DATA_DIR_TX;
979*4882a593Smuzhiyun 		if (dai->id == RT711_AIF1)
980*4882a593Smuzhiyun 			port = 4;
981*4882a593Smuzhiyun 		else if (dai->id == RT711_AIF2)
982*4882a593Smuzhiyun 			port = 2;
983*4882a593Smuzhiyun 		else
984*4882a593Smuzhiyun 			return -EINVAL;
985*4882a593Smuzhiyun 	}
986*4882a593Smuzhiyun 
987*4882a593Smuzhiyun 	stream_config.frame_rate = params_rate(params);
988*4882a593Smuzhiyun 	stream_config.ch_count = params_channels(params);
989*4882a593Smuzhiyun 	stream_config.bps = snd_pcm_format_width(params_format(params));
990*4882a593Smuzhiyun 	stream_config.direction = direction;
991*4882a593Smuzhiyun 
992*4882a593Smuzhiyun 	num_channels = params_channels(params);
993*4882a593Smuzhiyun 	port_config.ch_mask = (1 << (num_channels)) - 1;
994*4882a593Smuzhiyun 	port_config.num = port;
995*4882a593Smuzhiyun 
996*4882a593Smuzhiyun 	retval = sdw_stream_add_slave(rt711->slave, &stream_config,
997*4882a593Smuzhiyun 					&port_config, 1, stream->sdw_stream);
998*4882a593Smuzhiyun 	if (retval) {
999*4882a593Smuzhiyun 		dev_err(dai->dev, "Unable to configure port\n");
1000*4882a593Smuzhiyun 		return retval;
1001*4882a593Smuzhiyun 	}
1002*4882a593Smuzhiyun 
1003*4882a593Smuzhiyun 	if (params_channels(params) <= 16) {
1004*4882a593Smuzhiyun 		/* bit 3:0 Number of Channel */
1005*4882a593Smuzhiyun 		val |= (params_channels(params) - 1);
1006*4882a593Smuzhiyun 	} else {
1007*4882a593Smuzhiyun 		dev_err(component->dev, "Unsupported channels %d\n",
1008*4882a593Smuzhiyun 			params_channels(params));
1009*4882a593Smuzhiyun 		return -EINVAL;
1010*4882a593Smuzhiyun 	}
1011*4882a593Smuzhiyun 
1012*4882a593Smuzhiyun 	switch (params_width(params)) {
1013*4882a593Smuzhiyun 	/* bit 6:4 Bits per Sample */
1014*4882a593Smuzhiyun 	case 8:
1015*4882a593Smuzhiyun 		break;
1016*4882a593Smuzhiyun 	case 16:
1017*4882a593Smuzhiyun 		val |= (0x1 << 4);
1018*4882a593Smuzhiyun 		break;
1019*4882a593Smuzhiyun 	case 20:
1020*4882a593Smuzhiyun 		val |= (0x2 << 4);
1021*4882a593Smuzhiyun 		break;
1022*4882a593Smuzhiyun 	case 24:
1023*4882a593Smuzhiyun 		val |= (0x3 << 4);
1024*4882a593Smuzhiyun 		break;
1025*4882a593Smuzhiyun 	case 32:
1026*4882a593Smuzhiyun 		val |= (0x4 << 4);
1027*4882a593Smuzhiyun 		break;
1028*4882a593Smuzhiyun 	default:
1029*4882a593Smuzhiyun 		return -EINVAL;
1030*4882a593Smuzhiyun 	}
1031*4882a593Smuzhiyun 
1032*4882a593Smuzhiyun 	/* 48Khz */
1033*4882a593Smuzhiyun 	regmap_write(rt711->regmap, RT711_DAC_FORMAT_H, val);
1034*4882a593Smuzhiyun 	regmap_write(rt711->regmap, RT711_ADC1_FORMAT_H, val);
1035*4882a593Smuzhiyun 	regmap_write(rt711->regmap, RT711_ADC2_FORMAT_H, val);
1036*4882a593Smuzhiyun 
1037*4882a593Smuzhiyun 	return retval;
1038*4882a593Smuzhiyun }
1039*4882a593Smuzhiyun 
rt711_pcm_hw_free(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)1040*4882a593Smuzhiyun static int rt711_pcm_hw_free(struct snd_pcm_substream *substream,
1041*4882a593Smuzhiyun 				struct snd_soc_dai *dai)
1042*4882a593Smuzhiyun {
1043*4882a593Smuzhiyun 	struct snd_soc_component *component = dai->component;
1044*4882a593Smuzhiyun 	struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component);
1045*4882a593Smuzhiyun 	struct sdw_stream_data *stream =
1046*4882a593Smuzhiyun 		snd_soc_dai_get_dma_data(dai, substream);
1047*4882a593Smuzhiyun 
1048*4882a593Smuzhiyun 	if (!rt711->slave)
1049*4882a593Smuzhiyun 		return -EINVAL;
1050*4882a593Smuzhiyun 
1051*4882a593Smuzhiyun 	sdw_stream_remove_slave(rt711->slave, stream->sdw_stream);
1052*4882a593Smuzhiyun 	return 0;
1053*4882a593Smuzhiyun }
1054*4882a593Smuzhiyun 
1055*4882a593Smuzhiyun #define RT711_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
1056*4882a593Smuzhiyun #define RT711_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
1057*4882a593Smuzhiyun 			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
1058*4882a593Smuzhiyun 
1059*4882a593Smuzhiyun static struct snd_soc_dai_ops rt711_ops = {
1060*4882a593Smuzhiyun 	.hw_params	= rt711_pcm_hw_params,
1061*4882a593Smuzhiyun 	.hw_free	= rt711_pcm_hw_free,
1062*4882a593Smuzhiyun 	.set_sdw_stream	= rt711_set_sdw_stream,
1063*4882a593Smuzhiyun 	.shutdown	= rt711_shutdown,
1064*4882a593Smuzhiyun };
1065*4882a593Smuzhiyun 
1066*4882a593Smuzhiyun static struct snd_soc_dai_driver rt711_dai[] = {
1067*4882a593Smuzhiyun 	{
1068*4882a593Smuzhiyun 		.name = "rt711-aif1",
1069*4882a593Smuzhiyun 		.id = RT711_AIF1,
1070*4882a593Smuzhiyun 		.playback = {
1071*4882a593Smuzhiyun 			.stream_name = "DP3 Playback",
1072*4882a593Smuzhiyun 			.channels_min = 1,
1073*4882a593Smuzhiyun 			.channels_max = 2,
1074*4882a593Smuzhiyun 			.rates = RT711_STEREO_RATES,
1075*4882a593Smuzhiyun 			.formats = RT711_FORMATS,
1076*4882a593Smuzhiyun 		},
1077*4882a593Smuzhiyun 		.capture = {
1078*4882a593Smuzhiyun 			.stream_name = "DP4 Capture",
1079*4882a593Smuzhiyun 			.channels_min = 1,
1080*4882a593Smuzhiyun 			.channels_max = 2,
1081*4882a593Smuzhiyun 			.rates = RT711_STEREO_RATES,
1082*4882a593Smuzhiyun 			.formats = RT711_FORMATS,
1083*4882a593Smuzhiyun 		},
1084*4882a593Smuzhiyun 		.ops = &rt711_ops,
1085*4882a593Smuzhiyun 	},
1086*4882a593Smuzhiyun 	{
1087*4882a593Smuzhiyun 		.name = "rt711-aif2",
1088*4882a593Smuzhiyun 		.id = RT711_AIF2,
1089*4882a593Smuzhiyun 		.capture = {
1090*4882a593Smuzhiyun 			.stream_name = "DP2 Capture",
1091*4882a593Smuzhiyun 			.channels_min = 1,
1092*4882a593Smuzhiyun 			.channels_max = 2,
1093*4882a593Smuzhiyun 			.rates = RT711_STEREO_RATES,
1094*4882a593Smuzhiyun 			.formats = RT711_FORMATS,
1095*4882a593Smuzhiyun 		},
1096*4882a593Smuzhiyun 		.ops = &rt711_ops,
1097*4882a593Smuzhiyun 	}
1098*4882a593Smuzhiyun };
1099*4882a593Smuzhiyun 
1100*4882a593Smuzhiyun /* Bus clock frequency */
1101*4882a593Smuzhiyun #define RT711_CLK_FREQ_9600000HZ 9600000
1102*4882a593Smuzhiyun #define RT711_CLK_FREQ_12000000HZ 12000000
1103*4882a593Smuzhiyun #define RT711_CLK_FREQ_6000000HZ 6000000
1104*4882a593Smuzhiyun #define RT711_CLK_FREQ_4800000HZ 4800000
1105*4882a593Smuzhiyun #define RT711_CLK_FREQ_2400000HZ 2400000
1106*4882a593Smuzhiyun #define RT711_CLK_FREQ_12288000HZ 12288000
1107*4882a593Smuzhiyun 
rt711_clock_config(struct device * dev)1108*4882a593Smuzhiyun int rt711_clock_config(struct device *dev)
1109*4882a593Smuzhiyun {
1110*4882a593Smuzhiyun 	struct rt711_priv *rt711 = dev_get_drvdata(dev);
1111*4882a593Smuzhiyun 	unsigned int clk_freq, value;
1112*4882a593Smuzhiyun 
1113*4882a593Smuzhiyun 	clk_freq = (rt711->params.curr_dr_freq >> 1);
1114*4882a593Smuzhiyun 
1115*4882a593Smuzhiyun 	switch (clk_freq) {
1116*4882a593Smuzhiyun 	case RT711_CLK_FREQ_12000000HZ:
1117*4882a593Smuzhiyun 		value = 0x0;
1118*4882a593Smuzhiyun 		break;
1119*4882a593Smuzhiyun 	case RT711_CLK_FREQ_6000000HZ:
1120*4882a593Smuzhiyun 		value = 0x1;
1121*4882a593Smuzhiyun 		break;
1122*4882a593Smuzhiyun 	case RT711_CLK_FREQ_9600000HZ:
1123*4882a593Smuzhiyun 		value = 0x2;
1124*4882a593Smuzhiyun 		break;
1125*4882a593Smuzhiyun 	case RT711_CLK_FREQ_4800000HZ:
1126*4882a593Smuzhiyun 		value = 0x3;
1127*4882a593Smuzhiyun 		break;
1128*4882a593Smuzhiyun 	case RT711_CLK_FREQ_2400000HZ:
1129*4882a593Smuzhiyun 		value = 0x4;
1130*4882a593Smuzhiyun 		break;
1131*4882a593Smuzhiyun 	case RT711_CLK_FREQ_12288000HZ:
1132*4882a593Smuzhiyun 		value = 0x5;
1133*4882a593Smuzhiyun 		break;
1134*4882a593Smuzhiyun 	default:
1135*4882a593Smuzhiyun 		return -EINVAL;
1136*4882a593Smuzhiyun 	}
1137*4882a593Smuzhiyun 
1138*4882a593Smuzhiyun 	regmap_write(rt711->regmap, 0xe0, value);
1139*4882a593Smuzhiyun 	regmap_write(rt711->regmap, 0xf0, value);
1140*4882a593Smuzhiyun 
1141*4882a593Smuzhiyun 	dev_dbg(dev, "%s complete, clk_freq=%d\n", __func__, clk_freq);
1142*4882a593Smuzhiyun 
1143*4882a593Smuzhiyun 	return 0;
1144*4882a593Smuzhiyun }
1145*4882a593Smuzhiyun 
rt711_calibration_work(struct work_struct * work)1146*4882a593Smuzhiyun static void rt711_calibration_work(struct work_struct *work)
1147*4882a593Smuzhiyun {
1148*4882a593Smuzhiyun 	struct rt711_priv *rt711 =
1149*4882a593Smuzhiyun 		container_of(work, struct rt711_priv, calibration_work);
1150*4882a593Smuzhiyun 
1151*4882a593Smuzhiyun 	rt711_calibration(rt711);
1152*4882a593Smuzhiyun }
1153*4882a593Smuzhiyun 
rt711_init(struct device * dev,struct regmap * sdw_regmap,struct regmap * regmap,struct sdw_slave * slave)1154*4882a593Smuzhiyun int rt711_init(struct device *dev, struct regmap *sdw_regmap,
1155*4882a593Smuzhiyun 			struct regmap *regmap, struct sdw_slave *slave)
1156*4882a593Smuzhiyun {
1157*4882a593Smuzhiyun 	struct rt711_priv *rt711;
1158*4882a593Smuzhiyun 	int ret;
1159*4882a593Smuzhiyun 
1160*4882a593Smuzhiyun 	rt711 = devm_kzalloc(dev, sizeof(*rt711), GFP_KERNEL);
1161*4882a593Smuzhiyun 	if (!rt711)
1162*4882a593Smuzhiyun 		return -ENOMEM;
1163*4882a593Smuzhiyun 
1164*4882a593Smuzhiyun 	dev_set_drvdata(dev, rt711);
1165*4882a593Smuzhiyun 	rt711->slave = slave;
1166*4882a593Smuzhiyun 	rt711->sdw_regmap = sdw_regmap;
1167*4882a593Smuzhiyun 	rt711->regmap = regmap;
1168*4882a593Smuzhiyun 
1169*4882a593Smuzhiyun 	/*
1170*4882a593Smuzhiyun 	 * Mark hw_init to false
1171*4882a593Smuzhiyun 	 * HW init will be performed when device reports present
1172*4882a593Smuzhiyun 	 */
1173*4882a593Smuzhiyun 	rt711->hw_init = false;
1174*4882a593Smuzhiyun 	rt711->first_hw_init = false;
1175*4882a593Smuzhiyun 
1176*4882a593Smuzhiyun 	/* JD source uses JD2 in default */
1177*4882a593Smuzhiyun 	rt711->jd_src = RT711_JD2;
1178*4882a593Smuzhiyun 
1179*4882a593Smuzhiyun 	ret =  devm_snd_soc_register_component(dev,
1180*4882a593Smuzhiyun 				&soc_codec_dev_rt711,
1181*4882a593Smuzhiyun 				rt711_dai,
1182*4882a593Smuzhiyun 				ARRAY_SIZE(rt711_dai));
1183*4882a593Smuzhiyun 
1184*4882a593Smuzhiyun 	dev_dbg(&slave->dev, "%s\n", __func__);
1185*4882a593Smuzhiyun 
1186*4882a593Smuzhiyun 	return ret;
1187*4882a593Smuzhiyun }
1188*4882a593Smuzhiyun 
rt711_io_init(struct device * dev,struct sdw_slave * slave)1189*4882a593Smuzhiyun int rt711_io_init(struct device *dev, struct sdw_slave *slave)
1190*4882a593Smuzhiyun {
1191*4882a593Smuzhiyun 	struct rt711_priv *rt711 = dev_get_drvdata(dev);
1192*4882a593Smuzhiyun 
1193*4882a593Smuzhiyun 	if (rt711->hw_init)
1194*4882a593Smuzhiyun 		return 0;
1195*4882a593Smuzhiyun 
1196*4882a593Smuzhiyun 	if (rt711->first_hw_init) {
1197*4882a593Smuzhiyun 		regcache_cache_only(rt711->regmap, false);
1198*4882a593Smuzhiyun 		regcache_cache_bypass(rt711->regmap, true);
1199*4882a593Smuzhiyun 	}
1200*4882a593Smuzhiyun 
1201*4882a593Smuzhiyun 	/*
1202*4882a593Smuzhiyun 	 * PM runtime is only enabled when a Slave reports as Attached
1203*4882a593Smuzhiyun 	 */
1204*4882a593Smuzhiyun 	if (!rt711->first_hw_init) {
1205*4882a593Smuzhiyun 		/* set autosuspend parameters */
1206*4882a593Smuzhiyun 		pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
1207*4882a593Smuzhiyun 		pm_runtime_use_autosuspend(&slave->dev);
1208*4882a593Smuzhiyun 
1209*4882a593Smuzhiyun 		/* update count of parent 'active' children */
1210*4882a593Smuzhiyun 		pm_runtime_set_active(&slave->dev);
1211*4882a593Smuzhiyun 
1212*4882a593Smuzhiyun 		/* make sure the device does not suspend immediately */
1213*4882a593Smuzhiyun 		pm_runtime_mark_last_busy(&slave->dev);
1214*4882a593Smuzhiyun 
1215*4882a593Smuzhiyun 		pm_runtime_enable(&slave->dev);
1216*4882a593Smuzhiyun 	}
1217*4882a593Smuzhiyun 
1218*4882a593Smuzhiyun 	pm_runtime_get_noresume(&slave->dev);
1219*4882a593Smuzhiyun 
1220*4882a593Smuzhiyun 	rt711_reset(rt711->regmap);
1221*4882a593Smuzhiyun 
1222*4882a593Smuzhiyun 	/* power on */
1223*4882a593Smuzhiyun 	regmap_write(rt711->regmap, RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D0);
1224*4882a593Smuzhiyun 
1225*4882a593Smuzhiyun 	/* Set Pin Widget */
1226*4882a593Smuzhiyun 	regmap_write(rt711->regmap, RT711_SET_PIN_MIC2, 0x25);
1227*4882a593Smuzhiyun 	regmap_write(rt711->regmap, RT711_SET_PIN_HP, 0xc0);
1228*4882a593Smuzhiyun 	regmap_write(rt711->regmap, RT711_SET_PIN_DMIC1, 0x20);
1229*4882a593Smuzhiyun 	regmap_write(rt711->regmap, RT711_SET_PIN_DMIC2, 0x20);
1230*4882a593Smuzhiyun 	regmap_write(rt711->regmap, RT711_SET_PIN_LINE1, 0x20);
1231*4882a593Smuzhiyun 	regmap_write(rt711->regmap, RT711_SET_PIN_LINE2, 0x20);
1232*4882a593Smuzhiyun 
1233*4882a593Smuzhiyun 	/* Mute HP/ADC1/ADC2 */
1234*4882a593Smuzhiyun 	regmap_write(rt711->regmap, RT711_SET_GAIN_HP_H, 0xa080);
1235*4882a593Smuzhiyun 	regmap_write(rt711->regmap, RT711_SET_GAIN_HP_H, 0x9080);
1236*4882a593Smuzhiyun 	regmap_write(rt711->regmap, RT711_SET_GAIN_ADC2_H, 0x6080);
1237*4882a593Smuzhiyun 	regmap_write(rt711->regmap, RT711_SET_GAIN_ADC2_H, 0x5080);
1238*4882a593Smuzhiyun 	regmap_write(rt711->regmap, RT711_SET_GAIN_ADC1_H, 0x6080);
1239*4882a593Smuzhiyun 	regmap_write(rt711->regmap, RT711_SET_GAIN_ADC1_H, 0x5080);
1240*4882a593Smuzhiyun 
1241*4882a593Smuzhiyun 	/* Set Configuration Default */
1242*4882a593Smuzhiyun 	regmap_write(rt711->regmap, 0x4f12, 0x91);
1243*4882a593Smuzhiyun 	regmap_write(rt711->regmap, 0x4e12, 0xd6);
1244*4882a593Smuzhiyun 	regmap_write(rt711->regmap, 0x4d12, 0x11);
1245*4882a593Smuzhiyun 	regmap_write(rt711->regmap, 0x4c12, 0x20);
1246*4882a593Smuzhiyun 	regmap_write(rt711->regmap, 0x4f13, 0x91);
1247*4882a593Smuzhiyun 	regmap_write(rt711->regmap, 0x4e13, 0xd6);
1248*4882a593Smuzhiyun 	regmap_write(rt711->regmap, 0x4d13, 0x11);
1249*4882a593Smuzhiyun 	regmap_write(rt711->regmap, 0x4c13, 0x21);
1250*4882a593Smuzhiyun 	regmap_write(rt711->regmap, 0x4c21, 0xf0);
1251*4882a593Smuzhiyun 	regmap_write(rt711->regmap, 0x4d21, 0x11);
1252*4882a593Smuzhiyun 	regmap_write(rt711->regmap, 0x4e21, 0x11);
1253*4882a593Smuzhiyun 	regmap_write(rt711->regmap, 0x4f21, 0x01);
1254*4882a593Smuzhiyun 
1255*4882a593Smuzhiyun 	/* Data port arrangement */
1256*4882a593Smuzhiyun 	rt711_index_write(rt711->regmap, RT711_VENDOR_REG,
1257*4882a593Smuzhiyun 		RT711_TX_RX_MUX_CTL, 0x0154);
1258*4882a593Smuzhiyun 
1259*4882a593Smuzhiyun 	/* Set index */
1260*4882a593Smuzhiyun 	rt711_index_write(rt711->regmap, RT711_VENDOR_REG,
1261*4882a593Smuzhiyun 		RT711_DIGITAL_MISC_CTRL4, 0x201b);
1262*4882a593Smuzhiyun 	rt711_index_write(rt711->regmap, RT711_VENDOR_REG,
1263*4882a593Smuzhiyun 		RT711_COMBO_JACK_AUTO_CTL1, 0x5089);
1264*4882a593Smuzhiyun 	rt711_index_write(rt711->regmap, RT711_VENDOR_REG,
1265*4882a593Smuzhiyun 		RT711_VREFOUT_CTL, 0x5064);
1266*4882a593Smuzhiyun 	rt711_index_write(rt711->regmap, RT711_VENDOR_REG,
1267*4882a593Smuzhiyun 		RT711_INLINE_CMD_CTL, 0xd249);
1268*4882a593Smuzhiyun 
1269*4882a593Smuzhiyun 	/* Finish Initial Settings, set power to D3 */
1270*4882a593Smuzhiyun 	regmap_write(rt711->regmap, RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3);
1271*4882a593Smuzhiyun 
1272*4882a593Smuzhiyun 	if (rt711->first_hw_init)
1273*4882a593Smuzhiyun 		rt711_calibration(rt711);
1274*4882a593Smuzhiyun 	else {
1275*4882a593Smuzhiyun 		INIT_DELAYED_WORK(&rt711->jack_detect_work,
1276*4882a593Smuzhiyun 			rt711_jack_detect_handler);
1277*4882a593Smuzhiyun 		INIT_DELAYED_WORK(&rt711->jack_btn_check_work,
1278*4882a593Smuzhiyun 			rt711_btn_check_handler);
1279*4882a593Smuzhiyun 		mutex_init(&rt711->calibrate_mutex);
1280*4882a593Smuzhiyun 		INIT_WORK(&rt711->calibration_work, rt711_calibration_work);
1281*4882a593Smuzhiyun 		schedule_work(&rt711->calibration_work);
1282*4882a593Smuzhiyun 	}
1283*4882a593Smuzhiyun 
1284*4882a593Smuzhiyun 	/*
1285*4882a593Smuzhiyun 	 * if set_jack callback occurred early than io_init,
1286*4882a593Smuzhiyun 	 * we set up the jack detection function now
1287*4882a593Smuzhiyun 	 */
1288*4882a593Smuzhiyun 	if (rt711->hs_jack)
1289*4882a593Smuzhiyun 		rt711_jack_init(rt711);
1290*4882a593Smuzhiyun 
1291*4882a593Smuzhiyun 	if (rt711->first_hw_init) {
1292*4882a593Smuzhiyun 		regcache_cache_bypass(rt711->regmap, false);
1293*4882a593Smuzhiyun 		regcache_mark_dirty(rt711->regmap);
1294*4882a593Smuzhiyun 	} else
1295*4882a593Smuzhiyun 		rt711->first_hw_init = true;
1296*4882a593Smuzhiyun 
1297*4882a593Smuzhiyun 	/* Mark Slave initialization complete */
1298*4882a593Smuzhiyun 	rt711->hw_init = true;
1299*4882a593Smuzhiyun 
1300*4882a593Smuzhiyun 	pm_runtime_mark_last_busy(&slave->dev);
1301*4882a593Smuzhiyun 	pm_runtime_put_autosuspend(&slave->dev);
1302*4882a593Smuzhiyun 
1303*4882a593Smuzhiyun 	dev_dbg(&slave->dev, "%s hw_init complete\n", __func__);
1304*4882a593Smuzhiyun 	return 0;
1305*4882a593Smuzhiyun }
1306*4882a593Smuzhiyun 
1307*4882a593Smuzhiyun MODULE_DESCRIPTION("ASoC RT711 SDW driver");
1308*4882a593Smuzhiyun MODULE_AUTHOR("Shuming Fan <shumingf@realtek.com>");
1309*4882a593Smuzhiyun MODULE_LICENSE("GPL");
1310