1 /*
2  * NXP TDA18218HN silicon tuner driver
3  *
4  * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
5  *
6  *    This program is free software; you can redistribute it and/or modify
7  *    it under the terms of the GNU General Public License as published by
8  *    the Free Software Foundation; either version 2 of the License, or
9  *    (at your option) any later version.
10  *
11  *    This program is distributed in the hope that it will be useful,
12  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *    GNU General Public License for more details.
15  *
16  *    You should have received a copy of the GNU General Public License
17  *    along with this program; if not, write to the Free Software
18  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20 
21 #include "tda18218.h"
22 #include "tda18218_priv.h"
23 
24 static int debug;
25 module_param(debug, int, 0644);
26 MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
27 
28 /* write multiple registers */
tda18218_wr_regs(struct tda18218_priv * priv,u8 reg,u8 * val,u8 len)29 static int tda18218_wr_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len)
30 {
31 	int ret = 0;
32 	u8 buf[1+len], quotient, remainder, i, msg_len, msg_len_max;
33 	struct i2c_msg msg[1] = {
34 		{
35 			.addr = priv->cfg->i2c_address,
36 			.flags = 0,
37 			.buf = buf,
38 		}
39 	};
40 
41 	msg_len_max = priv->cfg->i2c_wr_max - 1;
42 	quotient = len / msg_len_max;
43 	remainder = len % msg_len_max;
44 	msg_len = msg_len_max;
45 	for (i = 0; (i <= quotient && remainder); i++) {
46 		if (i == quotient)  /* set len of the last msg */
47 			msg_len = remainder;
48 
49 		msg[0].len = msg_len + 1;
50 		buf[0] = reg + i * msg_len_max;
51 		memcpy(&buf[1], &val[i * msg_len_max], msg_len);
52 
53 		ret = i2c_transfer(priv->i2c, msg, 1);
54 		if (ret != 1)
55 			break;
56 	}
57 
58 	if (ret == 1) {
59 		ret = 0;
60 	} else {
61 		warn("i2c wr failed ret:%d reg:%02x len:%d", ret, reg, len);
62 		ret = -EREMOTEIO;
63 	}
64 
65 	return ret;
66 }
67 
68 /* read multiple registers */
tda18218_rd_regs(struct tda18218_priv * priv,u8 reg,u8 * val,u8 len)69 static int tda18218_rd_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len)
70 {
71 	int ret;
72 	u8 buf[reg+len]; /* we must start read always from reg 0x00 */
73 	struct i2c_msg msg[2] = {
74 		{
75 			.addr = priv->cfg->i2c_address,
76 			.flags = 0,
77 			.len = 1,
78 			.buf = "\x00",
79 		}, {
80 			.addr = priv->cfg->i2c_address,
81 			.flags = I2C_M_RD,
82 			.len = sizeof(buf),
83 			.buf = buf,
84 		}
85 	};
86 
87 	ret = i2c_transfer(priv->i2c, msg, 2);
88 	if (ret == 2) {
89 		memcpy(val, &buf[reg], len);
90 		ret = 0;
91 	} else {
92 		warn("i2c rd failed ret:%d reg:%02x len:%d", ret, reg, len);
93 		ret = -EREMOTEIO;
94 	}
95 
96 	return ret;
97 }
98 
99 /* write single register */
tda18218_wr_reg(struct tda18218_priv * priv,u8 reg,u8 val)100 static int tda18218_wr_reg(struct tda18218_priv *priv, u8 reg, u8 val)
101 {
102 	return tda18218_wr_regs(priv, reg, &val, 1);
103 }
104 
105 /* read single register */
106 
tda18218_rd_reg(struct tda18218_priv * priv,u8 reg,u8 * val)107 static int tda18218_rd_reg(struct tda18218_priv *priv, u8 reg, u8 *val)
108 {
109 	return tda18218_rd_regs(priv, reg, val, 1);
110 }
111 
tda18218_set_params(struct dvb_frontend * fe)112 static int tda18218_set_params(struct dvb_frontend *fe)
113 {
114 	struct tda18218_priv *priv = fe->tuner_priv;
115 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
116 	u32 bw = c->bandwidth_hz;
117 	int ret;
118 	u8 buf[3], i, BP_Filter, LP_Fc;
119 	u32 LO_Frac;
120 	/* TODO: find out correct AGC algorithm */
121 	u8 agc[][2] = {
122 		{ R20_AGC11, 0x60 },
123 		{ R23_AGC21, 0x02 },
124 		{ R20_AGC11, 0xa0 },
125 		{ R23_AGC21, 0x09 },
126 		{ R20_AGC11, 0xe0 },
127 		{ R23_AGC21, 0x0c },
128 		{ R20_AGC11, 0x40 },
129 		{ R23_AGC21, 0x01 },
130 		{ R20_AGC11, 0x80 },
131 		{ R23_AGC21, 0x08 },
132 		{ R20_AGC11, 0xc0 },
133 		{ R23_AGC21, 0x0b },
134 		{ R24_AGC22, 0x1c },
135 		{ R24_AGC22, 0x0c },
136 	};
137 
138 	if (fe->ops.i2c_gate_ctrl)
139 		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
140 
141 	/* low-pass filter cut-off frequency */
142 	if (bw <= 6000000) {
143 		LP_Fc = 0;
144 		priv->if_frequency = 3000000;
145 	} else if (bw <= 7000000) {
146 		LP_Fc = 1;
147 		priv->if_frequency = 3500000;
148 	} else {
149 		LP_Fc = 2;
150 		priv->if_frequency = 4000000;
151 	}
152 
153 	LO_Frac = c->frequency + priv->if_frequency;
154 
155 	/* band-pass filter */
156 	if (LO_Frac < 188000000)
157 		BP_Filter = 3;
158 	else if (LO_Frac < 253000000)
159 		BP_Filter = 4;
160 	else if (LO_Frac < 343000000)
161 		BP_Filter = 5;
162 	else
163 		BP_Filter = 6;
164 
165 	buf[0] = (priv->regs[R1A_IF1] & ~7) | BP_Filter; /* BP_Filter */
166 	buf[1] = (priv->regs[R1B_IF2] & ~3) | LP_Fc; /* LP_Fc */
167 	buf[2] = priv->regs[R1C_AGC2B];
168 	ret = tda18218_wr_regs(priv, R1A_IF1, buf, 3);
169 	if (ret)
170 		goto error;
171 
172 	buf[0] = (LO_Frac / 1000) >> 12; /* LO_Frac_0 */
173 	buf[1] = (LO_Frac / 1000) >> 4; /* LO_Frac_1 */
174 	buf[2] = (LO_Frac / 1000) << 4 |
175 		(priv->regs[R0C_MD5] & 0x0f); /* LO_Frac_2 */
176 	ret = tda18218_wr_regs(priv, R0A_MD3, buf, 3);
177 	if (ret)
178 		goto error;
179 
180 	buf[0] = priv->regs[R0F_MD8] | (1 << 6); /* Freq_prog_Start */
181 	ret = tda18218_wr_regs(priv, R0F_MD8, buf, 1);
182 	if (ret)
183 		goto error;
184 
185 	buf[0] = priv->regs[R0F_MD8] & ~(1 << 6); /* Freq_prog_Start */
186 	ret = tda18218_wr_regs(priv, R0F_MD8, buf, 1);
187 	if (ret)
188 		goto error;
189 
190 	/* trigger AGC */
191 	for (i = 0; i < ARRAY_SIZE(agc); i++) {
192 		ret = tda18218_wr_reg(priv, agc[i][0], agc[i][1]);
193 		if (ret)
194 			goto error;
195 	}
196 
197 error:
198 	if (fe->ops.i2c_gate_ctrl)
199 		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
200 
201 	if (ret)
202 		dbg("%s: failed ret:%d", __func__, ret);
203 
204 	return ret;
205 }
206 
tda18218_get_if_frequency(struct dvb_frontend * fe,u32 * frequency)207 static int tda18218_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
208 {
209 	struct tda18218_priv *priv = fe->tuner_priv;
210 	*frequency = priv->if_frequency;
211 	dbg("%s: if=%d", __func__, *frequency);
212 	return 0;
213 }
214 
tda18218_sleep(struct dvb_frontend * fe)215 static int tda18218_sleep(struct dvb_frontend *fe)
216 {
217 	struct tda18218_priv *priv = fe->tuner_priv;
218 	int ret;
219 
220 	if (fe->ops.i2c_gate_ctrl)
221 		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
222 
223 	/* standby */
224 	ret = tda18218_wr_reg(priv, R17_PD1, priv->regs[R17_PD1] | (1 << 0));
225 
226 	if (fe->ops.i2c_gate_ctrl)
227 		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
228 
229 	if (ret)
230 		dbg("%s: failed ret:%d", __func__, ret);
231 
232 	return ret;
233 }
234 
tda18218_init(struct dvb_frontend * fe)235 static int tda18218_init(struct dvb_frontend *fe)
236 {
237 	struct tda18218_priv *priv = fe->tuner_priv;
238 	int ret;
239 
240 	/* TODO: calibrations */
241 
242 	if (fe->ops.i2c_gate_ctrl)
243 		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
244 
245 	ret = tda18218_wr_regs(priv, R00_ID, priv->regs, TDA18218_NUM_REGS);
246 
247 	if (fe->ops.i2c_gate_ctrl)
248 		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
249 
250 	if (ret)
251 		dbg("%s: failed ret:%d", __func__, ret);
252 
253 	return ret;
254 }
255 
tda18218_release(struct dvb_frontend * fe)256 static int tda18218_release(struct dvb_frontend *fe)
257 {
258 	kfree(fe->tuner_priv);
259 	fe->tuner_priv = NULL;
260 	return 0;
261 }
262 
263 static const struct dvb_tuner_ops tda18218_tuner_ops = {
264 	.info = {
265 		.name           = "NXP TDA18218",
266 
267 		.frequency_min  = 174000000,
268 		.frequency_max  = 864000000,
269 		.frequency_step =      1000,
270 	},
271 
272 	.release       = tda18218_release,
273 	.init          = tda18218_init,
274 	.sleep         = tda18218_sleep,
275 
276 	.set_params    = tda18218_set_params,
277 
278 	.get_if_frequency = tda18218_get_if_frequency,
279 };
280 
tda18218_attach(struct dvb_frontend * fe,struct i2c_adapter * i2c,struct tda18218_config * cfg)281 struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe,
282 	struct i2c_adapter *i2c, struct tda18218_config *cfg)
283 {
284 	struct tda18218_priv *priv = NULL;
285 	u8 val;
286 	int ret;
287 	/* chip default registers values */
288 	static u8 def_regs[] = {
289 		0xc0, 0x88, 0x00, 0x8e, 0x03, 0x00, 0x00, 0xd0, 0x00, 0x40,
290 		0x00, 0x00, 0x07, 0xff, 0x84, 0x09, 0x00, 0x13, 0x00, 0x00,
291 		0x01, 0x84, 0x09, 0xf0, 0x19, 0x0a, 0x8e, 0x69, 0x98, 0x01,
292 		0x00, 0x58, 0x10, 0x40, 0x8c, 0x00, 0x0c, 0x48, 0x85, 0xc9,
293 		0xa7, 0x00, 0x00, 0x00, 0x30, 0x81, 0x80, 0x00, 0x39, 0x00,
294 		0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xf6
295 	};
296 
297 	priv = kzalloc(sizeof(struct tda18218_priv), GFP_KERNEL);
298 	if (priv == NULL)
299 		return NULL;
300 
301 	priv->cfg = cfg;
302 	priv->i2c = i2c;
303 	fe->tuner_priv = priv;
304 
305 	if (fe->ops.i2c_gate_ctrl)
306 		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
307 
308 	/* check if the tuner is there */
309 	ret = tda18218_rd_reg(priv, R00_ID, &val);
310 	dbg("%s: ret:%d chip ID:%02x", __func__, ret, val);
311 	if (ret || val != def_regs[R00_ID]) {
312 		kfree(priv);
313 		return NULL;
314 	}
315 
316 	info("NXP TDA18218HN successfully identified.");
317 
318 	memcpy(&fe->ops.tuner_ops, &tda18218_tuner_ops,
319 		sizeof(struct dvb_tuner_ops));
320 	memcpy(priv->regs, def_regs, sizeof(def_regs));
321 
322 	/* loop-through enabled chip default register values */
323 	if (priv->cfg->loop_through) {
324 		priv->regs[R17_PD1] = 0xb0;
325 		priv->regs[R18_PD2] = 0x59;
326 	}
327 
328 	/* standby */
329 	ret = tda18218_wr_reg(priv, R17_PD1, priv->regs[R17_PD1] | (1 << 0));
330 	if (ret)
331 		dbg("%s: failed ret:%d", __func__, ret);
332 
333 	if (fe->ops.i2c_gate_ctrl)
334 		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
335 
336 	return fe;
337 }
338 EXPORT_SYMBOL(tda18218_attach);
339 
340 MODULE_DESCRIPTION("NXP TDA18218HN silicon tuner driver");
341 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
342 MODULE_LICENSE("GPL");
343