xref: /OK3568_Linux_fs/kernel/drivers/media/tuners/m88rs6000t.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Driver for the internal tuner of Montage M88RS6000
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2014 Max nibble <nibble.max@gmail.com>
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include "m88rs6000t.h"
9*4882a593Smuzhiyun #include <linux/regmap.h>
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun struct m88rs6000t_dev {
12*4882a593Smuzhiyun 	struct m88rs6000t_config cfg;
13*4882a593Smuzhiyun 	struct i2c_client *client;
14*4882a593Smuzhiyun 	struct regmap *regmap;
15*4882a593Smuzhiyun 	u32 frequency_khz;
16*4882a593Smuzhiyun };
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun struct m88rs6000t_reg_val {
19*4882a593Smuzhiyun 	u8 reg;
20*4882a593Smuzhiyun 	u8 val;
21*4882a593Smuzhiyun };
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun /* set demod main mclk and ts mclk */
m88rs6000t_set_demod_mclk(struct dvb_frontend * fe)24*4882a593Smuzhiyun static int m88rs6000t_set_demod_mclk(struct dvb_frontend *fe)
25*4882a593Smuzhiyun {
26*4882a593Smuzhiyun 	struct m88rs6000t_dev *dev = fe->tuner_priv;
27*4882a593Smuzhiyun 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
28*4882a593Smuzhiyun 	u8 reg11, reg15, reg16, reg1D, reg1E, reg1F;
29*4882a593Smuzhiyun 	u8 N, f0 = 0, f1 = 0, f2 = 0, f3 = 0;
30*4882a593Smuzhiyun 	u16 pll_div_fb;
31*4882a593Smuzhiyun 	u32 div, ts_mclk;
32*4882a593Smuzhiyun 	unsigned int utmp;
33*4882a593Smuzhiyun 	int ret;
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun 	/* select demod main mclk */
36*4882a593Smuzhiyun 	ret = regmap_read(dev->regmap, 0x15, &utmp);
37*4882a593Smuzhiyun 	if (ret)
38*4882a593Smuzhiyun 		goto err;
39*4882a593Smuzhiyun 	reg15 = utmp;
40*4882a593Smuzhiyun 	if (c->symbol_rate > 45010000) {
41*4882a593Smuzhiyun 		reg11 = 0x0E;
42*4882a593Smuzhiyun 		reg15 |= 0x02;
43*4882a593Smuzhiyun 		reg16 = 115; /* mclk = 110.25MHz */
44*4882a593Smuzhiyun 	} else {
45*4882a593Smuzhiyun 		reg11 = 0x0A;
46*4882a593Smuzhiyun 		reg15 &= ~0x02;
47*4882a593Smuzhiyun 		reg16 = 96; /* mclk = 96MHz */
48*4882a593Smuzhiyun 	}
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun 	/* set ts mclk */
51*4882a593Smuzhiyun 	if (c->delivery_system == SYS_DVBS)
52*4882a593Smuzhiyun 		ts_mclk = 96000;
53*4882a593Smuzhiyun 	else
54*4882a593Smuzhiyun 		ts_mclk = 144000;
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun 	pll_div_fb = (reg15 & 0x01) << 8;
57*4882a593Smuzhiyun 	pll_div_fb += reg16;
58*4882a593Smuzhiyun 	pll_div_fb += 32;
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun 	div = 36000 * pll_div_fb;
61*4882a593Smuzhiyun 	div /= ts_mclk;
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun 	if (div <= 32) {
64*4882a593Smuzhiyun 		N = 2;
65*4882a593Smuzhiyun 		f0 = 0;
66*4882a593Smuzhiyun 		f1 = div / 2;
67*4882a593Smuzhiyun 		f2 = div - f1;
68*4882a593Smuzhiyun 		f3 = 0;
69*4882a593Smuzhiyun 	} else if (div <= 48) {
70*4882a593Smuzhiyun 		N = 3;
71*4882a593Smuzhiyun 		f0 = div / 3;
72*4882a593Smuzhiyun 		f1 = (div - f0) / 2;
73*4882a593Smuzhiyun 		f2 = div - f0 - f1;
74*4882a593Smuzhiyun 		f3 = 0;
75*4882a593Smuzhiyun 	} else if (div <= 64) {
76*4882a593Smuzhiyun 		N = 4;
77*4882a593Smuzhiyun 		f0 = div / 4;
78*4882a593Smuzhiyun 		f1 = (div - f0) / 3;
79*4882a593Smuzhiyun 		f2 = (div - f0 - f1) / 2;
80*4882a593Smuzhiyun 		f3 = div - f0 - f1 - f2;
81*4882a593Smuzhiyun 	} else {
82*4882a593Smuzhiyun 		N = 4;
83*4882a593Smuzhiyun 		f0 = 16;
84*4882a593Smuzhiyun 		f1 = 16;
85*4882a593Smuzhiyun 		f2 = 16;
86*4882a593Smuzhiyun 		f3 = 16;
87*4882a593Smuzhiyun 	}
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun 	if (f0 == 16)
90*4882a593Smuzhiyun 		f0 = 0;
91*4882a593Smuzhiyun 	if (f1 == 16)
92*4882a593Smuzhiyun 		f1 = 0;
93*4882a593Smuzhiyun 	if (f2 == 16)
94*4882a593Smuzhiyun 		f2 = 0;
95*4882a593Smuzhiyun 	if (f3 == 16)
96*4882a593Smuzhiyun 		f3 = 0;
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	ret = regmap_read(dev->regmap, 0x1D, &utmp);
99*4882a593Smuzhiyun 	if (ret)
100*4882a593Smuzhiyun 		goto err;
101*4882a593Smuzhiyun 	reg1D = utmp;
102*4882a593Smuzhiyun 	reg1D &= ~0x03;
103*4882a593Smuzhiyun 	reg1D |= N - 1;
104*4882a593Smuzhiyun 	reg1E = ((f3 << 4) + f2) & 0xFF;
105*4882a593Smuzhiyun 	reg1F = ((f1 << 4) + f0) & 0xFF;
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 	/* program and recalibrate demod PLL */
108*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x05, 0x40);
109*4882a593Smuzhiyun 	if (ret)
110*4882a593Smuzhiyun 		goto err;
111*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x11, 0x08);
112*4882a593Smuzhiyun 	if (ret)
113*4882a593Smuzhiyun 		goto err;
114*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x15, reg15);
115*4882a593Smuzhiyun 	if (ret)
116*4882a593Smuzhiyun 		goto err;
117*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x16, reg16);
118*4882a593Smuzhiyun 	if (ret)
119*4882a593Smuzhiyun 		goto err;
120*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x1D, reg1D);
121*4882a593Smuzhiyun 	if (ret)
122*4882a593Smuzhiyun 		goto err;
123*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x1E, reg1E);
124*4882a593Smuzhiyun 	if (ret)
125*4882a593Smuzhiyun 		goto err;
126*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x1F, reg1F);
127*4882a593Smuzhiyun 	if (ret)
128*4882a593Smuzhiyun 		goto err;
129*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x17, 0xc1);
130*4882a593Smuzhiyun 	if (ret)
131*4882a593Smuzhiyun 		goto err;
132*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x17, 0x81);
133*4882a593Smuzhiyun 	if (ret)
134*4882a593Smuzhiyun 		goto err;
135*4882a593Smuzhiyun 	usleep_range(5000, 50000);
136*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x05, 0x00);
137*4882a593Smuzhiyun 	if (ret)
138*4882a593Smuzhiyun 		goto err;
139*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x11, reg11);
140*4882a593Smuzhiyun 	if (ret)
141*4882a593Smuzhiyun 		goto err;
142*4882a593Smuzhiyun 	usleep_range(5000, 50000);
143*4882a593Smuzhiyun err:
144*4882a593Smuzhiyun 	if (ret)
145*4882a593Smuzhiyun 		dev_dbg(&dev->client->dev, "failed=%d\n", ret);
146*4882a593Smuzhiyun 	return ret;
147*4882a593Smuzhiyun }
148*4882a593Smuzhiyun 
m88rs6000t_set_pll_freq(struct m88rs6000t_dev * dev,u32 tuner_freq_MHz)149*4882a593Smuzhiyun static int m88rs6000t_set_pll_freq(struct m88rs6000t_dev *dev,
150*4882a593Smuzhiyun 			u32 tuner_freq_MHz)
151*4882a593Smuzhiyun {
152*4882a593Smuzhiyun 	u32 fcry_KHz, ulNDiv1, ulNDiv2, ulNDiv;
153*4882a593Smuzhiyun 	u8 refDiv, ucLoDiv1, ucLomod1, ucLoDiv2, ucLomod2, ucLoDiv, ucLomod;
154*4882a593Smuzhiyun 	u8 reg27, reg29, reg42, reg42buf;
155*4882a593Smuzhiyun 	unsigned int utmp;
156*4882a593Smuzhiyun 	int ret;
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	fcry_KHz = 27000; /* in kHz */
159*4882a593Smuzhiyun 	refDiv = 27;
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x36, (refDiv - 8));
162*4882a593Smuzhiyun 	if (ret)
163*4882a593Smuzhiyun 		goto err;
164*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x31, 0x00);
165*4882a593Smuzhiyun 	if (ret)
166*4882a593Smuzhiyun 		goto err;
167*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x2c, 0x02);
168*4882a593Smuzhiyun 	if (ret)
169*4882a593Smuzhiyun 		goto err;
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 	if (tuner_freq_MHz >= 1550) {
172*4882a593Smuzhiyun 		ucLoDiv1 = 2;
173*4882a593Smuzhiyun 		ucLomod1 = 0;
174*4882a593Smuzhiyun 		ucLoDiv2 = 2;
175*4882a593Smuzhiyun 		ucLomod2 = 0;
176*4882a593Smuzhiyun 	} else if (tuner_freq_MHz >= 1380) {
177*4882a593Smuzhiyun 		ucLoDiv1 = 3;
178*4882a593Smuzhiyun 		ucLomod1 = 16;
179*4882a593Smuzhiyun 		ucLoDiv2 = 2;
180*4882a593Smuzhiyun 		ucLomod2 = 0;
181*4882a593Smuzhiyun 	} else if (tuner_freq_MHz >= 1070) {
182*4882a593Smuzhiyun 		ucLoDiv1 = 3;
183*4882a593Smuzhiyun 		ucLomod1 = 16;
184*4882a593Smuzhiyun 		ucLoDiv2 = 3;
185*4882a593Smuzhiyun 		ucLomod2 = 16;
186*4882a593Smuzhiyun 	} else if (tuner_freq_MHz >= 1000) {
187*4882a593Smuzhiyun 		ucLoDiv1 = 3;
188*4882a593Smuzhiyun 		ucLomod1 = 16;
189*4882a593Smuzhiyun 		ucLoDiv2 = 4;
190*4882a593Smuzhiyun 		ucLomod2 = 64;
191*4882a593Smuzhiyun 	} else if (tuner_freq_MHz >= 775) {
192*4882a593Smuzhiyun 		ucLoDiv1 = 4;
193*4882a593Smuzhiyun 		ucLomod1 = 64;
194*4882a593Smuzhiyun 		ucLoDiv2 = 4;
195*4882a593Smuzhiyun 		ucLomod2 = 64;
196*4882a593Smuzhiyun 	} else if (tuner_freq_MHz >= 700) {
197*4882a593Smuzhiyun 		ucLoDiv1 = 6;
198*4882a593Smuzhiyun 		ucLomod1 = 48;
199*4882a593Smuzhiyun 		ucLoDiv2 = 4;
200*4882a593Smuzhiyun 		ucLomod2 = 64;
201*4882a593Smuzhiyun 	} else if (tuner_freq_MHz >= 520) {
202*4882a593Smuzhiyun 		ucLoDiv1 = 6;
203*4882a593Smuzhiyun 		ucLomod1 = 48;
204*4882a593Smuzhiyun 		ucLoDiv2 = 6;
205*4882a593Smuzhiyun 		ucLomod2 = 48;
206*4882a593Smuzhiyun 	} else {
207*4882a593Smuzhiyun 		ucLoDiv1 = 8;
208*4882a593Smuzhiyun 		ucLomod1 = 96;
209*4882a593Smuzhiyun 		ucLoDiv2 = 8;
210*4882a593Smuzhiyun 		ucLomod2 = 96;
211*4882a593Smuzhiyun 	}
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	ulNDiv1 = ((tuner_freq_MHz * ucLoDiv1 * 1000) * refDiv
214*4882a593Smuzhiyun 			/ fcry_KHz - 1024) / 2;
215*4882a593Smuzhiyun 	ulNDiv2 = ((tuner_freq_MHz * ucLoDiv2 * 1000) * refDiv
216*4882a593Smuzhiyun 			/ fcry_KHz - 1024) / 2;
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 	reg27 = (((ulNDiv1 >> 8) & 0x0F) + ucLomod1) & 0x7F;
219*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x27, reg27);
220*4882a593Smuzhiyun 	if (ret)
221*4882a593Smuzhiyun 		goto err;
222*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x28, (u8)(ulNDiv1 & 0xFF));
223*4882a593Smuzhiyun 	if (ret)
224*4882a593Smuzhiyun 		goto err;
225*4882a593Smuzhiyun 	reg29 = (((ulNDiv2 >> 8) & 0x0F) + ucLomod2) & 0x7f;
226*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x29, reg29);
227*4882a593Smuzhiyun 	if (ret)
228*4882a593Smuzhiyun 		goto err;
229*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x2a, (u8)(ulNDiv2 & 0xFF));
230*4882a593Smuzhiyun 	if (ret)
231*4882a593Smuzhiyun 		goto err;
232*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x2F, 0xf5);
233*4882a593Smuzhiyun 	if (ret)
234*4882a593Smuzhiyun 		goto err;
235*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x30, 0x05);
236*4882a593Smuzhiyun 	if (ret)
237*4882a593Smuzhiyun 		goto err;
238*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x08, 0x1f);
239*4882a593Smuzhiyun 	if (ret)
240*4882a593Smuzhiyun 		goto err;
241*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x08, 0x3f);
242*4882a593Smuzhiyun 	if (ret)
243*4882a593Smuzhiyun 		goto err;
244*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x09, 0x20);
245*4882a593Smuzhiyun 	if (ret)
246*4882a593Smuzhiyun 		goto err;
247*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x09, 0x00);
248*4882a593Smuzhiyun 	if (ret)
249*4882a593Smuzhiyun 		goto err;
250*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x3e, 0x11);
251*4882a593Smuzhiyun 	if (ret)
252*4882a593Smuzhiyun 		goto err;
253*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x08, 0x2f);
254*4882a593Smuzhiyun 	if (ret)
255*4882a593Smuzhiyun 		goto err;
256*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x08, 0x3f);
257*4882a593Smuzhiyun 	if (ret)
258*4882a593Smuzhiyun 		goto err;
259*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x09, 0x10);
260*4882a593Smuzhiyun 	if (ret)
261*4882a593Smuzhiyun 		goto err;
262*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x09, 0x00);
263*4882a593Smuzhiyun 	if (ret)
264*4882a593Smuzhiyun 		goto err;
265*4882a593Smuzhiyun 	usleep_range(2000, 50000);
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 	ret = regmap_read(dev->regmap, 0x42, &utmp);
268*4882a593Smuzhiyun 	if (ret)
269*4882a593Smuzhiyun 		goto err;
270*4882a593Smuzhiyun 	reg42 = utmp;
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x3e, 0x10);
273*4882a593Smuzhiyun 	if (ret)
274*4882a593Smuzhiyun 		goto err;
275*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x08, 0x2f);
276*4882a593Smuzhiyun 	if (ret)
277*4882a593Smuzhiyun 		goto err;
278*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x08, 0x3f);
279*4882a593Smuzhiyun 	if (ret)
280*4882a593Smuzhiyun 		goto err;
281*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x09, 0x10);
282*4882a593Smuzhiyun 	if (ret)
283*4882a593Smuzhiyun 		goto err;
284*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x09, 0x00);
285*4882a593Smuzhiyun 	if (ret)
286*4882a593Smuzhiyun 		goto err;
287*4882a593Smuzhiyun 	usleep_range(2000, 50000);
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun 	ret = regmap_read(dev->regmap, 0x42, &utmp);
290*4882a593Smuzhiyun 	if (ret)
291*4882a593Smuzhiyun 		goto err;
292*4882a593Smuzhiyun 	reg42buf = utmp;
293*4882a593Smuzhiyun 	if (reg42buf < reg42) {
294*4882a593Smuzhiyun 		ret = regmap_write(dev->regmap, 0x3e, 0x11);
295*4882a593Smuzhiyun 		if (ret)
296*4882a593Smuzhiyun 			goto err;
297*4882a593Smuzhiyun 	}
298*4882a593Smuzhiyun 	usleep_range(5000, 50000);
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun 	ret = regmap_read(dev->regmap, 0x2d, &utmp);
301*4882a593Smuzhiyun 	if (ret)
302*4882a593Smuzhiyun 		goto err;
303*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x2d, utmp);
304*4882a593Smuzhiyun 	if (ret)
305*4882a593Smuzhiyun 		goto err;
306*4882a593Smuzhiyun 	ret = regmap_read(dev->regmap, 0x2e, &utmp);
307*4882a593Smuzhiyun 	if (ret)
308*4882a593Smuzhiyun 		goto err;
309*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x2e, utmp);
310*4882a593Smuzhiyun 	if (ret)
311*4882a593Smuzhiyun 		goto err;
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun 	ret = regmap_read(dev->regmap, 0x27, &utmp);
314*4882a593Smuzhiyun 	if (ret)
315*4882a593Smuzhiyun 		goto err;
316*4882a593Smuzhiyun 	reg27 = utmp & 0x70;
317*4882a593Smuzhiyun 	ret = regmap_read(dev->regmap, 0x83, &utmp);
318*4882a593Smuzhiyun 	if (ret)
319*4882a593Smuzhiyun 		goto err;
320*4882a593Smuzhiyun 	if (reg27 == (utmp & 0x70)) {
321*4882a593Smuzhiyun 		ucLoDiv	= ucLoDiv1;
322*4882a593Smuzhiyun 		ulNDiv = ulNDiv1;
323*4882a593Smuzhiyun 		ucLomod = ucLomod1 / 16;
324*4882a593Smuzhiyun 	} else {
325*4882a593Smuzhiyun 		ucLoDiv	= ucLoDiv2;
326*4882a593Smuzhiyun 		ulNDiv = ulNDiv2;
327*4882a593Smuzhiyun 		ucLomod = ucLomod2 / 16;
328*4882a593Smuzhiyun 	}
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	if ((ucLoDiv == 3) || (ucLoDiv == 6)) {
331*4882a593Smuzhiyun 		refDiv = 18;
332*4882a593Smuzhiyun 		ret = regmap_write(dev->regmap, 0x36, (refDiv - 8));
333*4882a593Smuzhiyun 		if (ret)
334*4882a593Smuzhiyun 			goto err;
335*4882a593Smuzhiyun 		ulNDiv = ((tuner_freq_MHz * ucLoDiv * 1000) * refDiv
336*4882a593Smuzhiyun 				/ fcry_KHz - 1024) / 2;
337*4882a593Smuzhiyun 	}
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 	reg27 = (0x80 + ((ucLomod << 4) & 0x70)
340*4882a593Smuzhiyun 			+ ((ulNDiv >> 8) & 0x0F)) & 0xFF;
341*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x27, reg27);
342*4882a593Smuzhiyun 	if (ret)
343*4882a593Smuzhiyun 		goto err;
344*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x28, (u8)(ulNDiv & 0xFF));
345*4882a593Smuzhiyun 	if (ret)
346*4882a593Smuzhiyun 		goto err;
347*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x29, 0x80);
348*4882a593Smuzhiyun 	if (ret)
349*4882a593Smuzhiyun 		goto err;
350*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x31, 0x03);
351*4882a593Smuzhiyun 	if (ret)
352*4882a593Smuzhiyun 		goto err;
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun 	if (ucLoDiv == 3)
355*4882a593Smuzhiyun 		utmp = 0xCE;
356*4882a593Smuzhiyun 	else
357*4882a593Smuzhiyun 		utmp = 0x8A;
358*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x3b, utmp);
359*4882a593Smuzhiyun 	if (ret)
360*4882a593Smuzhiyun 		goto err;
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun 	dev->frequency_khz = fcry_KHz * (ulNDiv * 2 + 1024) / refDiv / ucLoDiv;
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun 	dev_dbg(&dev->client->dev,
365*4882a593Smuzhiyun 		"actual tune frequency=%d\n", dev->frequency_khz);
366*4882a593Smuzhiyun err:
367*4882a593Smuzhiyun 	if (ret)
368*4882a593Smuzhiyun 		dev_dbg(&dev->client->dev, "failed=%d\n", ret);
369*4882a593Smuzhiyun 	return ret;
370*4882a593Smuzhiyun }
371*4882a593Smuzhiyun 
m88rs6000t_set_bb(struct m88rs6000t_dev * dev,u32 symbol_rate_KSs,s32 lpf_offset_KHz)372*4882a593Smuzhiyun static int m88rs6000t_set_bb(struct m88rs6000t_dev *dev,
373*4882a593Smuzhiyun 		u32 symbol_rate_KSs, s32 lpf_offset_KHz)
374*4882a593Smuzhiyun {
375*4882a593Smuzhiyun 	u32 f3dB;
376*4882a593Smuzhiyun 	u8  reg40;
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	f3dB = symbol_rate_KSs * 9 / 14 + 2000;
379*4882a593Smuzhiyun 	f3dB += lpf_offset_KHz;
380*4882a593Smuzhiyun 	f3dB = clamp_val(f3dB, 6000U, 43000U);
381*4882a593Smuzhiyun 	reg40 = f3dB / 1000;
382*4882a593Smuzhiyun 	return regmap_write(dev->regmap, 0x40, reg40);
383*4882a593Smuzhiyun }
384*4882a593Smuzhiyun 
m88rs6000t_set_params(struct dvb_frontend * fe)385*4882a593Smuzhiyun static int m88rs6000t_set_params(struct dvb_frontend *fe)
386*4882a593Smuzhiyun {
387*4882a593Smuzhiyun 	struct m88rs6000t_dev *dev = fe->tuner_priv;
388*4882a593Smuzhiyun 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
389*4882a593Smuzhiyun 	int ret;
390*4882a593Smuzhiyun 	s32 lpf_offset_KHz;
391*4882a593Smuzhiyun 	u32 realFreq, freq_MHz;
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun 	dev_dbg(&dev->client->dev,
394*4882a593Smuzhiyun 			"frequency=%d symbol_rate=%d\n",
395*4882a593Smuzhiyun 			c->frequency, c->symbol_rate);
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun 	if (c->symbol_rate < 5000000)
398*4882a593Smuzhiyun 		lpf_offset_KHz = 3000;
399*4882a593Smuzhiyun 	else
400*4882a593Smuzhiyun 		lpf_offset_KHz = 0;
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun 	realFreq = c->frequency + lpf_offset_KHz;
403*4882a593Smuzhiyun 	/* set tuner pll.*/
404*4882a593Smuzhiyun 	freq_MHz = (realFreq + 500) / 1000;
405*4882a593Smuzhiyun 	ret = m88rs6000t_set_pll_freq(dev, freq_MHz);
406*4882a593Smuzhiyun 	if (ret)
407*4882a593Smuzhiyun 		goto err;
408*4882a593Smuzhiyun 	ret = m88rs6000t_set_bb(dev, c->symbol_rate / 1000, lpf_offset_KHz);
409*4882a593Smuzhiyun 	if (ret)
410*4882a593Smuzhiyun 		goto err;
411*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x00, 0x01);
412*4882a593Smuzhiyun 	if (ret)
413*4882a593Smuzhiyun 		goto err;
414*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x00, 0x00);
415*4882a593Smuzhiyun 	if (ret)
416*4882a593Smuzhiyun 		goto err;
417*4882a593Smuzhiyun 	/* set demod mlck */
418*4882a593Smuzhiyun 	ret = m88rs6000t_set_demod_mclk(fe);
419*4882a593Smuzhiyun err:
420*4882a593Smuzhiyun 	if (ret)
421*4882a593Smuzhiyun 		dev_dbg(&dev->client->dev, "failed=%d\n", ret);
422*4882a593Smuzhiyun 	return ret;
423*4882a593Smuzhiyun }
424*4882a593Smuzhiyun 
m88rs6000t_init(struct dvb_frontend * fe)425*4882a593Smuzhiyun static int m88rs6000t_init(struct dvb_frontend *fe)
426*4882a593Smuzhiyun {
427*4882a593Smuzhiyun 	struct m88rs6000t_dev *dev = fe->tuner_priv;
428*4882a593Smuzhiyun 	int ret;
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun 	dev_dbg(&dev->client->dev, "%s:\n", __func__);
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun 	ret = regmap_update_bits(dev->regmap, 0x11, 0x08, 0x08);
433*4882a593Smuzhiyun 	if (ret)
434*4882a593Smuzhiyun 		goto err;
435*4882a593Smuzhiyun 	usleep_range(5000, 50000);
436*4882a593Smuzhiyun 	ret = regmap_update_bits(dev->regmap, 0x10, 0x01, 0x01);
437*4882a593Smuzhiyun 	if (ret)
438*4882a593Smuzhiyun 		goto err;
439*4882a593Smuzhiyun 	usleep_range(10000, 50000);
440*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x07, 0x7d);
441*4882a593Smuzhiyun err:
442*4882a593Smuzhiyun 	if (ret)
443*4882a593Smuzhiyun 		dev_dbg(&dev->client->dev, "failed=%d\n", ret);
444*4882a593Smuzhiyun 	return ret;
445*4882a593Smuzhiyun }
446*4882a593Smuzhiyun 
m88rs6000t_sleep(struct dvb_frontend * fe)447*4882a593Smuzhiyun static int m88rs6000t_sleep(struct dvb_frontend *fe)
448*4882a593Smuzhiyun {
449*4882a593Smuzhiyun 	struct m88rs6000t_dev *dev = fe->tuner_priv;
450*4882a593Smuzhiyun 	int ret;
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun 	dev_dbg(&dev->client->dev, "%s:\n", __func__);
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x07, 0x6d);
455*4882a593Smuzhiyun 	if (ret) {
456*4882a593Smuzhiyun 		dev_dbg(&dev->client->dev, "failed=%d\n", ret);
457*4882a593Smuzhiyun 		return ret;
458*4882a593Smuzhiyun 	}
459*4882a593Smuzhiyun 	usleep_range(5000, 10000);
460*4882a593Smuzhiyun 	return 0;
461*4882a593Smuzhiyun }
462*4882a593Smuzhiyun 
m88rs6000t_get_frequency(struct dvb_frontend * fe,u32 * frequency)463*4882a593Smuzhiyun static int m88rs6000t_get_frequency(struct dvb_frontend *fe, u32 *frequency)
464*4882a593Smuzhiyun {
465*4882a593Smuzhiyun 	struct m88rs6000t_dev *dev = fe->tuner_priv;
466*4882a593Smuzhiyun 
467*4882a593Smuzhiyun 	dev_dbg(&dev->client->dev, "\n");
468*4882a593Smuzhiyun 
469*4882a593Smuzhiyun 	*frequency = dev->frequency_khz;
470*4882a593Smuzhiyun 	return 0;
471*4882a593Smuzhiyun }
472*4882a593Smuzhiyun 
m88rs6000t_get_if_frequency(struct dvb_frontend * fe,u32 * frequency)473*4882a593Smuzhiyun static int m88rs6000t_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
474*4882a593Smuzhiyun {
475*4882a593Smuzhiyun 	struct m88rs6000t_dev *dev = fe->tuner_priv;
476*4882a593Smuzhiyun 
477*4882a593Smuzhiyun 	dev_dbg(&dev->client->dev, "\n");
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun 	*frequency = 0; /* Zero-IF */
480*4882a593Smuzhiyun 	return 0;
481*4882a593Smuzhiyun }
482*4882a593Smuzhiyun 
483*4882a593Smuzhiyun 
m88rs6000t_get_rf_strength(struct dvb_frontend * fe,u16 * strength)484*4882a593Smuzhiyun static int m88rs6000t_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
485*4882a593Smuzhiyun {
486*4882a593Smuzhiyun 	struct m88rs6000t_dev *dev = fe->tuner_priv;
487*4882a593Smuzhiyun 	unsigned int val, i;
488*4882a593Smuzhiyun 	int ret;
489*4882a593Smuzhiyun 	u16 gain;
490*4882a593Smuzhiyun 	u32 PGA2_cri_GS = 46, PGA2_crf_GS = 290, TIA_GS = 290;
491*4882a593Smuzhiyun 	u32 RF_GC = 1200, IF_GC = 1100, BB_GC = 300;
492*4882a593Smuzhiyun 	u32 PGA2_GC = 300, TIA_GC = 300, PGA2_cri = 0, PGA2_crf = 0;
493*4882a593Smuzhiyun 	u32 RFG = 0, IFG = 0, BBG = 0, PGA2G = 0, TIAG = 0;
494*4882a593Smuzhiyun 	u32 RFGS[13] = {0, 245, 266, 268, 270, 285,
495*4882a593Smuzhiyun 			298, 295, 283, 285, 285, 300, 300};
496*4882a593Smuzhiyun 	u32 IFGS[12] = {0, 300, 230, 270, 270, 285,
497*4882a593Smuzhiyun 			295, 285, 290, 295, 295, 310};
498*4882a593Smuzhiyun 	u32 BBGS[14] = {0, 286, 275, 290, 294, 300, 290,
499*4882a593Smuzhiyun 			290, 285, 283, 260, 295, 290, 260};
500*4882a593Smuzhiyun 
501*4882a593Smuzhiyun 	ret = regmap_read(dev->regmap, 0x5A, &val);
502*4882a593Smuzhiyun 	if (ret)
503*4882a593Smuzhiyun 		goto err;
504*4882a593Smuzhiyun 	RF_GC = val & 0x0f;
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun 	ret = regmap_read(dev->regmap, 0x5F, &val);
507*4882a593Smuzhiyun 	if (ret)
508*4882a593Smuzhiyun 		goto err;
509*4882a593Smuzhiyun 	IF_GC = val & 0x0f;
510*4882a593Smuzhiyun 
511*4882a593Smuzhiyun 	ret = regmap_read(dev->regmap, 0x3F, &val);
512*4882a593Smuzhiyun 	if (ret)
513*4882a593Smuzhiyun 		goto err;
514*4882a593Smuzhiyun 	TIA_GC = (val >> 4) & 0x07;
515*4882a593Smuzhiyun 
516*4882a593Smuzhiyun 	ret = regmap_read(dev->regmap, 0x77, &val);
517*4882a593Smuzhiyun 	if (ret)
518*4882a593Smuzhiyun 		goto err;
519*4882a593Smuzhiyun 	BB_GC = (val >> 4) & 0x0f;
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun 	ret = regmap_read(dev->regmap, 0x76, &val);
522*4882a593Smuzhiyun 	if (ret)
523*4882a593Smuzhiyun 		goto err;
524*4882a593Smuzhiyun 	PGA2_GC = val & 0x3f;
525*4882a593Smuzhiyun 	PGA2_cri = PGA2_GC >> 2;
526*4882a593Smuzhiyun 	PGA2_crf = PGA2_GC & 0x03;
527*4882a593Smuzhiyun 
528*4882a593Smuzhiyun 	for (i = 0; i <= RF_GC && i < ARRAY_SIZE(RFGS); i++)
529*4882a593Smuzhiyun 		RFG += RFGS[i];
530*4882a593Smuzhiyun 
531*4882a593Smuzhiyun 	if (RF_GC == 0)
532*4882a593Smuzhiyun 		RFG += 400;
533*4882a593Smuzhiyun 	if (RF_GC == 1)
534*4882a593Smuzhiyun 		RFG += 300;
535*4882a593Smuzhiyun 	if (RF_GC == 2)
536*4882a593Smuzhiyun 		RFG += 200;
537*4882a593Smuzhiyun 	if (RF_GC == 3)
538*4882a593Smuzhiyun 		RFG += 100;
539*4882a593Smuzhiyun 
540*4882a593Smuzhiyun 	for (i = 0; i <= IF_GC && i < ARRAY_SIZE(IFGS); i++)
541*4882a593Smuzhiyun 		IFG += IFGS[i];
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun 	TIAG = TIA_GC * TIA_GS;
544*4882a593Smuzhiyun 
545*4882a593Smuzhiyun 	for (i = 0; i <= BB_GC && i < ARRAY_SIZE(BBGS); i++)
546*4882a593Smuzhiyun 		BBG += BBGS[i];
547*4882a593Smuzhiyun 
548*4882a593Smuzhiyun 	PGA2G = PGA2_cri * PGA2_cri_GS + PGA2_crf * PGA2_crf_GS;
549*4882a593Smuzhiyun 
550*4882a593Smuzhiyun 	gain = RFG + IFG - TIAG + BBG + PGA2G;
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun 	/* scale value to 0x0000-0xffff */
553*4882a593Smuzhiyun 	gain = clamp_val(gain, 1000U, 10500U);
554*4882a593Smuzhiyun 	*strength = (10500 - gain) * 0xffff / (10500 - 1000);
555*4882a593Smuzhiyun err:
556*4882a593Smuzhiyun 	if (ret)
557*4882a593Smuzhiyun 		dev_dbg(&dev->client->dev, "failed=%d\n", ret);
558*4882a593Smuzhiyun 	return ret;
559*4882a593Smuzhiyun }
560*4882a593Smuzhiyun 
561*4882a593Smuzhiyun static const struct dvb_tuner_ops m88rs6000t_tuner_ops = {
562*4882a593Smuzhiyun 	.info = {
563*4882a593Smuzhiyun 		.name             = "Montage M88RS6000 Internal Tuner",
564*4882a593Smuzhiyun 		.frequency_min_hz =  950 * MHz,
565*4882a593Smuzhiyun 		.frequency_max_hz = 2150 * MHz,
566*4882a593Smuzhiyun 	},
567*4882a593Smuzhiyun 
568*4882a593Smuzhiyun 	.init = m88rs6000t_init,
569*4882a593Smuzhiyun 	.sleep = m88rs6000t_sleep,
570*4882a593Smuzhiyun 	.set_params = m88rs6000t_set_params,
571*4882a593Smuzhiyun 	.get_frequency = m88rs6000t_get_frequency,
572*4882a593Smuzhiyun 	.get_if_frequency = m88rs6000t_get_if_frequency,
573*4882a593Smuzhiyun 	.get_rf_strength = m88rs6000t_get_rf_strength,
574*4882a593Smuzhiyun };
575*4882a593Smuzhiyun 
m88rs6000t_probe(struct i2c_client * client,const struct i2c_device_id * id)576*4882a593Smuzhiyun static int m88rs6000t_probe(struct i2c_client *client,
577*4882a593Smuzhiyun 		const struct i2c_device_id *id)
578*4882a593Smuzhiyun {
579*4882a593Smuzhiyun 	struct m88rs6000t_config *cfg = client->dev.platform_data;
580*4882a593Smuzhiyun 	struct dvb_frontend *fe = cfg->fe;
581*4882a593Smuzhiyun 	struct m88rs6000t_dev *dev;
582*4882a593Smuzhiyun 	int ret, i;
583*4882a593Smuzhiyun 	unsigned int utmp;
584*4882a593Smuzhiyun 	static const struct regmap_config regmap_config = {
585*4882a593Smuzhiyun 		.reg_bits = 8,
586*4882a593Smuzhiyun 		.val_bits = 8,
587*4882a593Smuzhiyun 	};
588*4882a593Smuzhiyun 	static const struct m88rs6000t_reg_val reg_vals[] = {
589*4882a593Smuzhiyun 		{0x10, 0xfb},
590*4882a593Smuzhiyun 		{0x24, 0x38},
591*4882a593Smuzhiyun 		{0x11, 0x0a},
592*4882a593Smuzhiyun 		{0x12, 0x00},
593*4882a593Smuzhiyun 		{0x2b, 0x1c},
594*4882a593Smuzhiyun 		{0x44, 0x48},
595*4882a593Smuzhiyun 		{0x54, 0x24},
596*4882a593Smuzhiyun 		{0x55, 0x06},
597*4882a593Smuzhiyun 		{0x59, 0x00},
598*4882a593Smuzhiyun 		{0x5b, 0x4c},
599*4882a593Smuzhiyun 		{0x60, 0x8b},
600*4882a593Smuzhiyun 		{0x61, 0xf4},
601*4882a593Smuzhiyun 		{0x65, 0x07},
602*4882a593Smuzhiyun 		{0x6d, 0x6f},
603*4882a593Smuzhiyun 		{0x6e, 0x31},
604*4882a593Smuzhiyun 		{0x3c, 0xf3},
605*4882a593Smuzhiyun 		{0x37, 0x0f},
606*4882a593Smuzhiyun 		{0x48, 0x28},
607*4882a593Smuzhiyun 		{0x49, 0xd8},
608*4882a593Smuzhiyun 		{0x70, 0x66},
609*4882a593Smuzhiyun 		{0x71, 0xCF},
610*4882a593Smuzhiyun 		{0x72, 0x81},
611*4882a593Smuzhiyun 		{0x73, 0xA7},
612*4882a593Smuzhiyun 		{0x74, 0x4F},
613*4882a593Smuzhiyun 		{0x75, 0xFC},
614*4882a593Smuzhiyun 	};
615*4882a593Smuzhiyun 
616*4882a593Smuzhiyun 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
617*4882a593Smuzhiyun 	if (!dev) {
618*4882a593Smuzhiyun 		ret = -ENOMEM;
619*4882a593Smuzhiyun 		dev_err(&client->dev, "kzalloc() failed\n");
620*4882a593Smuzhiyun 		goto err;
621*4882a593Smuzhiyun 	}
622*4882a593Smuzhiyun 
623*4882a593Smuzhiyun 	memcpy(&dev->cfg, cfg, sizeof(struct m88rs6000t_config));
624*4882a593Smuzhiyun 	dev->client = client;
625*4882a593Smuzhiyun 	dev->regmap = devm_regmap_init_i2c(client, &regmap_config);
626*4882a593Smuzhiyun 	if (IS_ERR(dev->regmap)) {
627*4882a593Smuzhiyun 		ret = PTR_ERR(dev->regmap);
628*4882a593Smuzhiyun 		goto err;
629*4882a593Smuzhiyun 	}
630*4882a593Smuzhiyun 
631*4882a593Smuzhiyun 	ret = regmap_update_bits(dev->regmap, 0x11, 0x08, 0x08);
632*4882a593Smuzhiyun 	if (ret)
633*4882a593Smuzhiyun 		goto err;
634*4882a593Smuzhiyun 	usleep_range(5000, 50000);
635*4882a593Smuzhiyun 	ret = regmap_update_bits(dev->regmap, 0x10, 0x01, 0x01);
636*4882a593Smuzhiyun 	if (ret)
637*4882a593Smuzhiyun 		goto err;
638*4882a593Smuzhiyun 	usleep_range(10000, 50000);
639*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x07, 0x7d);
640*4882a593Smuzhiyun 	if (ret)
641*4882a593Smuzhiyun 		goto err;
642*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x04, 0x01);
643*4882a593Smuzhiyun 	if (ret)
644*4882a593Smuzhiyun 		goto err;
645*4882a593Smuzhiyun 
646*4882a593Smuzhiyun 	/* check tuner chip id */
647*4882a593Smuzhiyun 	ret = regmap_read(dev->regmap, 0x01, &utmp);
648*4882a593Smuzhiyun 	if (ret)
649*4882a593Smuzhiyun 		goto err;
650*4882a593Smuzhiyun 	dev_info(&dev->client->dev, "chip_id=%02x\n", utmp);
651*4882a593Smuzhiyun 	if (utmp != 0x64) {
652*4882a593Smuzhiyun 		ret = -ENODEV;
653*4882a593Smuzhiyun 		goto err;
654*4882a593Smuzhiyun 	}
655*4882a593Smuzhiyun 
656*4882a593Smuzhiyun 	/* tuner init. */
657*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x05, 0x40);
658*4882a593Smuzhiyun 	if (ret)
659*4882a593Smuzhiyun 		goto err;
660*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x11, 0x08);
661*4882a593Smuzhiyun 	if (ret)
662*4882a593Smuzhiyun 		goto err;
663*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x15, 0x6c);
664*4882a593Smuzhiyun 	if (ret)
665*4882a593Smuzhiyun 		goto err;
666*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x17, 0xc1);
667*4882a593Smuzhiyun 	if (ret)
668*4882a593Smuzhiyun 		goto err;
669*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x17, 0x81);
670*4882a593Smuzhiyun 	if (ret)
671*4882a593Smuzhiyun 		goto err;
672*4882a593Smuzhiyun 	usleep_range(10000, 50000);
673*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x05, 0x00);
674*4882a593Smuzhiyun 	if (ret)
675*4882a593Smuzhiyun 		goto err;
676*4882a593Smuzhiyun 	ret = regmap_write(dev->regmap, 0x11, 0x0a);
677*4882a593Smuzhiyun 	if (ret)
678*4882a593Smuzhiyun 		goto err;
679*4882a593Smuzhiyun 
680*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(reg_vals); i++) {
681*4882a593Smuzhiyun 		ret = regmap_write(dev->regmap,
682*4882a593Smuzhiyun 				reg_vals[i].reg, reg_vals[i].val);
683*4882a593Smuzhiyun 		if (ret)
684*4882a593Smuzhiyun 			goto err;
685*4882a593Smuzhiyun 	}
686*4882a593Smuzhiyun 
687*4882a593Smuzhiyun 	dev_info(&dev->client->dev, "Montage M88RS6000 internal tuner successfully identified\n");
688*4882a593Smuzhiyun 
689*4882a593Smuzhiyun 	fe->tuner_priv = dev;
690*4882a593Smuzhiyun 	memcpy(&fe->ops.tuner_ops, &m88rs6000t_tuner_ops,
691*4882a593Smuzhiyun 			sizeof(struct dvb_tuner_ops));
692*4882a593Smuzhiyun 	i2c_set_clientdata(client, dev);
693*4882a593Smuzhiyun 	return 0;
694*4882a593Smuzhiyun err:
695*4882a593Smuzhiyun 	dev_dbg(&client->dev, "failed=%d\n", ret);
696*4882a593Smuzhiyun 	kfree(dev);
697*4882a593Smuzhiyun 	return ret;
698*4882a593Smuzhiyun }
699*4882a593Smuzhiyun 
m88rs6000t_remove(struct i2c_client * client)700*4882a593Smuzhiyun static int m88rs6000t_remove(struct i2c_client *client)
701*4882a593Smuzhiyun {
702*4882a593Smuzhiyun 	struct m88rs6000t_dev *dev = i2c_get_clientdata(client);
703*4882a593Smuzhiyun 	struct dvb_frontend *fe = dev->cfg.fe;
704*4882a593Smuzhiyun 
705*4882a593Smuzhiyun 	dev_dbg(&client->dev, "\n");
706*4882a593Smuzhiyun 
707*4882a593Smuzhiyun 	memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
708*4882a593Smuzhiyun 	fe->tuner_priv = NULL;
709*4882a593Smuzhiyun 	kfree(dev);
710*4882a593Smuzhiyun 
711*4882a593Smuzhiyun 	return 0;
712*4882a593Smuzhiyun }
713*4882a593Smuzhiyun 
714*4882a593Smuzhiyun static const struct i2c_device_id m88rs6000t_id[] = {
715*4882a593Smuzhiyun 	{"m88rs6000t", 0},
716*4882a593Smuzhiyun 	{}
717*4882a593Smuzhiyun };
718*4882a593Smuzhiyun MODULE_DEVICE_TABLE(i2c, m88rs6000t_id);
719*4882a593Smuzhiyun 
720*4882a593Smuzhiyun static struct i2c_driver m88rs6000t_driver = {
721*4882a593Smuzhiyun 	.driver = {
722*4882a593Smuzhiyun 		.name	= "m88rs6000t",
723*4882a593Smuzhiyun 	},
724*4882a593Smuzhiyun 	.probe		= m88rs6000t_probe,
725*4882a593Smuzhiyun 	.remove		= m88rs6000t_remove,
726*4882a593Smuzhiyun 	.id_table	= m88rs6000t_id,
727*4882a593Smuzhiyun };
728*4882a593Smuzhiyun 
729*4882a593Smuzhiyun module_i2c_driver(m88rs6000t_driver);
730*4882a593Smuzhiyun 
731*4882a593Smuzhiyun MODULE_AUTHOR("Max nibble <nibble.max@gmail.com>");
732*4882a593Smuzhiyun MODULE_DESCRIPTION("Montage M88RS6000 internal tuner driver");
733*4882a593Smuzhiyun MODULE_LICENSE("GPL");
734