xref: /linux/drivers/media/tuners/tda18218.c (revision ca55b2fef3a9373fcfc30f82fd26bc7fccbda732)
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_priv.h"
22 
23 /* Max transfer size done by I2C transfer functions */
24 #define MAX_XFER_SIZE  64
25 
26 /* write multiple registers */
27 static int tda18218_wr_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len)
28 {
29 	int ret = 0, len2, remaining;
30 	u8 buf[MAX_XFER_SIZE];
31 	struct i2c_msg msg[1] = {
32 		{
33 			.addr = priv->cfg->i2c_address,
34 			.flags = 0,
35 			.buf = buf,
36 		}
37 	};
38 
39 	if (1 + len > sizeof(buf)) {
40 		dev_warn(&priv->i2c->dev,
41 			 "%s: i2c wr reg=%04x: len=%d is too big!\n",
42 			 KBUILD_MODNAME, reg, len);
43 		return -EINVAL;
44 	}
45 
46 	for (remaining = len; remaining > 0;
47 			remaining -= (priv->cfg->i2c_wr_max - 1)) {
48 		len2 = remaining;
49 		if (len2 > (priv->cfg->i2c_wr_max - 1))
50 			len2 = (priv->cfg->i2c_wr_max - 1);
51 
52 		msg[0].len = 1 + len2;
53 		buf[0] = reg + len - remaining;
54 		memcpy(&buf[1], &val[len - remaining], len2);
55 
56 		ret = i2c_transfer(priv->i2c, msg, 1);
57 		if (ret != 1)
58 			break;
59 	}
60 
61 	if (ret == 1) {
62 		ret = 0;
63 	} else {
64 		dev_warn(&priv->i2c->dev, "%s: i2c wr failed=%d reg=%02x " \
65 				"len=%d\n", KBUILD_MODNAME, ret, reg, len);
66 		ret = -EREMOTEIO;
67 	}
68 
69 	return ret;
70 }
71 
72 /* read multiple registers */
73 static int tda18218_rd_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len)
74 {
75 	int ret;
76 	u8 buf[MAX_XFER_SIZE]; /* we must start read always from reg 0x00 */
77 	struct i2c_msg msg[2] = {
78 		{
79 			.addr = priv->cfg->i2c_address,
80 			.flags = 0,
81 			.len = 1,
82 			.buf = "\x00",
83 		}, {
84 			.addr = priv->cfg->i2c_address,
85 			.flags = I2C_M_RD,
86 			.len = reg + len,
87 			.buf = buf,
88 		}
89 	};
90 
91 	if (reg + len > sizeof(buf)) {
92 		dev_warn(&priv->i2c->dev,
93 			 "%s: i2c wr reg=%04x: len=%d is too big!\n",
94 			 KBUILD_MODNAME, reg, len);
95 		return -EINVAL;
96 	}
97 
98 	ret = i2c_transfer(priv->i2c, msg, 2);
99 	if (ret == 2) {
100 		memcpy(val, &buf[reg], len);
101 		ret = 0;
102 	} else {
103 		dev_warn(&priv->i2c->dev, "%s: i2c rd failed=%d reg=%02x " \
104 				"len=%d\n", KBUILD_MODNAME, ret, reg, len);
105 		ret = -EREMOTEIO;
106 	}
107 
108 	return ret;
109 }
110 
111 /* write single register */
112 static int tda18218_wr_reg(struct tda18218_priv *priv, u8 reg, u8 val)
113 {
114 	return tda18218_wr_regs(priv, reg, &val, 1);
115 }
116 
117 /* read single register */
118 
119 static int tda18218_rd_reg(struct tda18218_priv *priv, u8 reg, u8 *val)
120 {
121 	return tda18218_rd_regs(priv, reg, val, 1);
122 }
123 
124 static int tda18218_set_params(struct dvb_frontend *fe)
125 {
126 	struct tda18218_priv *priv = fe->tuner_priv;
127 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
128 	u32 bw = c->bandwidth_hz;
129 	int ret;
130 	u8 buf[3], i, BP_Filter, LP_Fc;
131 	u32 LO_Frac;
132 	/* TODO: find out correct AGC algorithm */
133 	u8 agc[][2] = {
134 		{ R20_AGC11, 0x60 },
135 		{ R23_AGC21, 0x02 },
136 		{ R20_AGC11, 0xa0 },
137 		{ R23_AGC21, 0x09 },
138 		{ R20_AGC11, 0xe0 },
139 		{ R23_AGC21, 0x0c },
140 		{ R20_AGC11, 0x40 },
141 		{ R23_AGC21, 0x01 },
142 		{ R20_AGC11, 0x80 },
143 		{ R23_AGC21, 0x08 },
144 		{ R20_AGC11, 0xc0 },
145 		{ R23_AGC21, 0x0b },
146 		{ R24_AGC22, 0x1c },
147 		{ R24_AGC22, 0x0c },
148 	};
149 
150 	if (fe->ops.i2c_gate_ctrl)
151 		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
152 
153 	/* low-pass filter cut-off frequency */
154 	if (bw <= 6000000) {
155 		LP_Fc = 0;
156 		priv->if_frequency = 3000000;
157 	} else if (bw <= 7000000) {
158 		LP_Fc = 1;
159 		priv->if_frequency = 3500000;
160 	} else {
161 		LP_Fc = 2;
162 		priv->if_frequency = 4000000;
163 	}
164 
165 	LO_Frac = c->frequency + priv->if_frequency;
166 
167 	/* band-pass filter */
168 	if (LO_Frac < 188000000)
169 		BP_Filter = 3;
170 	else if (LO_Frac < 253000000)
171 		BP_Filter = 4;
172 	else if (LO_Frac < 343000000)
173 		BP_Filter = 5;
174 	else
175 		BP_Filter = 6;
176 
177 	buf[0] = (priv->regs[R1A_IF1] & ~7) | BP_Filter; /* BP_Filter */
178 	buf[1] = (priv->regs[R1B_IF2] & ~3) | LP_Fc; /* LP_Fc */
179 	buf[2] = priv->regs[R1C_AGC2B];
180 	ret = tda18218_wr_regs(priv, R1A_IF1, buf, 3);
181 	if (ret)
182 		goto error;
183 
184 	buf[0] = (LO_Frac / 1000) >> 12; /* LO_Frac_0 */
185 	buf[1] = (LO_Frac / 1000) >> 4; /* LO_Frac_1 */
186 	buf[2] = (LO_Frac / 1000) << 4 |
187 		(priv->regs[R0C_MD5] & 0x0f); /* LO_Frac_2 */
188 	ret = tda18218_wr_regs(priv, R0A_MD3, buf, 3);
189 	if (ret)
190 		goto error;
191 
192 	buf[0] = priv->regs[R0F_MD8] | (1 << 6); /* Freq_prog_Start */
193 	ret = tda18218_wr_regs(priv, R0F_MD8, buf, 1);
194 	if (ret)
195 		goto error;
196 
197 	buf[0] = priv->regs[R0F_MD8] & ~(1 << 6); /* Freq_prog_Start */
198 	ret = tda18218_wr_regs(priv, R0F_MD8, buf, 1);
199 	if (ret)
200 		goto error;
201 
202 	/* trigger AGC */
203 	for (i = 0; i < ARRAY_SIZE(agc); i++) {
204 		ret = tda18218_wr_reg(priv, agc[i][0], agc[i][1]);
205 		if (ret)
206 			goto error;
207 	}
208 
209 error:
210 	if (fe->ops.i2c_gate_ctrl)
211 		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
212 
213 	if (ret)
214 		dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
215 
216 	return ret;
217 }
218 
219 static int tda18218_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
220 {
221 	struct tda18218_priv *priv = fe->tuner_priv;
222 	*frequency = priv->if_frequency;
223 	dev_dbg(&priv->i2c->dev, "%s: if_frequency=%d\n", __func__, *frequency);
224 	return 0;
225 }
226 
227 static int tda18218_sleep(struct dvb_frontend *fe)
228 {
229 	struct tda18218_priv *priv = fe->tuner_priv;
230 	int ret;
231 
232 	if (fe->ops.i2c_gate_ctrl)
233 		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
234 
235 	/* standby */
236 	ret = tda18218_wr_reg(priv, R17_PD1, priv->regs[R17_PD1] | (1 << 0));
237 
238 	if (fe->ops.i2c_gate_ctrl)
239 		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
240 
241 	if (ret)
242 		dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
243 
244 	return ret;
245 }
246 
247 static int tda18218_init(struct dvb_frontend *fe)
248 {
249 	struct tda18218_priv *priv = fe->tuner_priv;
250 	int ret;
251 
252 	/* TODO: calibrations */
253 
254 	if (fe->ops.i2c_gate_ctrl)
255 		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
256 
257 	ret = tda18218_wr_regs(priv, R00_ID, priv->regs, TDA18218_NUM_REGS);
258 
259 	if (fe->ops.i2c_gate_ctrl)
260 		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
261 
262 	if (ret)
263 		dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
264 
265 	return ret;
266 }
267 
268 static int tda18218_release(struct dvb_frontend *fe)
269 {
270 	kfree(fe->tuner_priv);
271 	fe->tuner_priv = NULL;
272 	return 0;
273 }
274 
275 static const struct dvb_tuner_ops tda18218_tuner_ops = {
276 	.info = {
277 		.name           = "NXP TDA18218",
278 
279 		.frequency_min  = 174000000,
280 		.frequency_max  = 864000000,
281 		.frequency_step =      1000,
282 	},
283 
284 	.release       = tda18218_release,
285 	.init          = tda18218_init,
286 	.sleep         = tda18218_sleep,
287 
288 	.set_params    = tda18218_set_params,
289 
290 	.get_if_frequency = tda18218_get_if_frequency,
291 };
292 
293 struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe,
294 	struct i2c_adapter *i2c, struct tda18218_config *cfg)
295 {
296 	struct tda18218_priv *priv = NULL;
297 	u8 val;
298 	int ret;
299 	/* chip default registers values */
300 	static u8 def_regs[] = {
301 		0xc0, 0x88, 0x00, 0x8e, 0x03, 0x00, 0x00, 0xd0, 0x00, 0x40,
302 		0x00, 0x00, 0x07, 0xff, 0x84, 0x09, 0x00, 0x13, 0x00, 0x00,
303 		0x01, 0x84, 0x09, 0xf0, 0x19, 0x0a, 0x8e, 0x69, 0x98, 0x01,
304 		0x00, 0x58, 0x10, 0x40, 0x8c, 0x00, 0x0c, 0x48, 0x85, 0xc9,
305 		0xa7, 0x00, 0x00, 0x00, 0x30, 0x81, 0x80, 0x00, 0x39, 0x00,
306 		0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xf6
307 	};
308 
309 	priv = kzalloc(sizeof(struct tda18218_priv), GFP_KERNEL);
310 	if (priv == NULL)
311 		return NULL;
312 
313 	priv->cfg = cfg;
314 	priv->i2c = i2c;
315 	fe->tuner_priv = priv;
316 
317 	if (fe->ops.i2c_gate_ctrl)
318 		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
319 
320 	/* check if the tuner is there */
321 	ret = tda18218_rd_reg(priv, R00_ID, &val);
322 	if (!ret)
323 		dev_dbg(&priv->i2c->dev, "%s: chip id=%02x\n", __func__, val);
324 	if (ret || val != def_regs[R00_ID]) {
325 		kfree(priv);
326 		return NULL;
327 	}
328 
329 	dev_info(&priv->i2c->dev,
330 			"%s: NXP TDA18218HN successfully identified\n",
331 			KBUILD_MODNAME);
332 
333 	memcpy(&fe->ops.tuner_ops, &tda18218_tuner_ops,
334 		sizeof(struct dvb_tuner_ops));
335 	memcpy(priv->regs, def_regs, sizeof(def_regs));
336 
337 	/* loop-through enabled chip default register values */
338 	if (priv->cfg->loop_through) {
339 		priv->regs[R17_PD1] = 0xb0;
340 		priv->regs[R18_PD2] = 0x59;
341 	}
342 
343 	/* standby */
344 	ret = tda18218_wr_reg(priv, R17_PD1, priv->regs[R17_PD1] | (1 << 0));
345 	if (ret)
346 		dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
347 
348 	if (fe->ops.i2c_gate_ctrl)
349 		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
350 
351 	return fe;
352 }
353 EXPORT_SYMBOL(tda18218_attach);
354 
355 MODULE_DESCRIPTION("NXP TDA18218HN silicon tuner driver");
356 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
357 MODULE_LICENSE("GPL");
358