blob: d099501566a105cf297ada07f9b144920166f751 [file] [log] [blame]
Antti Palosaari51ff2e22010-08-13 03:41:02 -03001/*
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
24static int debug;
25module_param(debug, int, 0644);
26MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
27
28/* write multiple registers */
29static int tda18218_wr_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len)
30{
Hans Verkuil0c8fc772010-12-31 12:26:53 -030031 int ret = 0;
Antti Palosaari51ff2e22010-08-13 03:41:02 -030032 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 */
69static 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 */
100static 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
107static int tda18218_rd_reg(struct tda18218_priv *priv, u8 reg, u8 *val)
108{
109 return tda18218_rd_regs(priv, reg, val, 1);
110}
111
112static int tda18218_set_params(struct dvb_frontend *fe,
113 struct dvb_frontend_parameters *params)
114{
115 struct tda18218_priv *priv = fe->tuner_priv;
116 int ret;
117 u8 buf[3], i, BP_Filter, LP_Fc;
118 u32 LO_Frac;
119 /* TODO: find out correct AGC algorithm */
120 u8 agc[][2] = {
121 { R20_AGC11, 0x60 },
122 { R23_AGC21, 0x02 },
123 { R20_AGC11, 0xa0 },
124 { R23_AGC21, 0x09 },
125 { R20_AGC11, 0xe0 },
126 { R23_AGC21, 0x0c },
127 { R20_AGC11, 0x40 },
128 { R23_AGC21, 0x01 },
129 { R20_AGC11, 0x80 },
130 { R23_AGC21, 0x08 },
131 { R20_AGC11, 0xc0 },
132 { R23_AGC21, 0x0b },
133 { R24_AGC22, 0x1c },
134 { R24_AGC22, 0x0c },
135 };
136
137 if (fe->ops.i2c_gate_ctrl)
138 fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
139
140 /* low-pass filter cut-off frequency */
141 switch (params->u.ofdm.bandwidth) {
142 case BANDWIDTH_6_MHZ:
143 LP_Fc = 0;
Mauro Carvalho Chehabb4d48c92011-12-30 13:59:37 -0200144 priv->if_frequency = 3000000;
Antti Palosaari51ff2e22010-08-13 03:41:02 -0300145 break;
146 case BANDWIDTH_7_MHZ:
147 LP_Fc = 1;
Antti Palosaari522fdf72011-11-13 00:19:56 -0300148 priv->if_frequency = 3500000;
Antti Palosaari51ff2e22010-08-13 03:41:02 -0300149 break;
150 case BANDWIDTH_8_MHZ:
151 default:
152 LP_Fc = 2;
Antti Palosaari522fdf72011-11-13 00:19:56 -0300153 priv->if_frequency = 4000000;
Antti Palosaari51ff2e22010-08-13 03:41:02 -0300154 break;
155 }
156
Antti Palosaari522fdf72011-11-13 00:19:56 -0300157 LO_Frac = params->frequency + priv->if_frequency;
158
Antti Palosaari51ff2e22010-08-13 03:41:02 -0300159 /* band-pass filter */
160 if (LO_Frac < 188000000)
161 BP_Filter = 3;
162 else if (LO_Frac < 253000000)
163 BP_Filter = 4;
164 else if (LO_Frac < 343000000)
165 BP_Filter = 5;
166 else
167 BP_Filter = 6;
168
169 buf[0] = (priv->regs[R1A_IF1] & ~7) | BP_Filter; /* BP_Filter */
170 buf[1] = (priv->regs[R1B_IF2] & ~3) | LP_Fc; /* LP_Fc */
171 buf[2] = priv->regs[R1C_AGC2B];
172 ret = tda18218_wr_regs(priv, R1A_IF1, buf, 3);
173 if (ret)
174 goto error;
175
176 buf[0] = (LO_Frac / 1000) >> 12; /* LO_Frac_0 */
177 buf[1] = (LO_Frac / 1000) >> 4; /* LO_Frac_1 */
178 buf[2] = (LO_Frac / 1000) << 4 |
179 (priv->regs[R0C_MD5] & 0x0f); /* LO_Frac_2 */
180 ret = tda18218_wr_regs(priv, R0A_MD3, buf, 3);
181 if (ret)
182 goto error;
183
184 buf[0] = priv->regs[R0F_MD8] | (1 << 6); /* Freq_prog_Start */
185 ret = tda18218_wr_regs(priv, R0F_MD8, buf, 1);
186 if (ret)
187 goto error;
188
189 buf[0] = priv->regs[R0F_MD8] & ~(1 << 6); /* Freq_prog_Start */
190 ret = tda18218_wr_regs(priv, R0F_MD8, buf, 1);
191 if (ret)
192 goto error;
193
194 /* trigger AGC */
195 for (i = 0; i < ARRAY_SIZE(agc); i++) {
196 ret = tda18218_wr_reg(priv, agc[i][0], agc[i][1]);
197 if (ret)
198 goto error;
199 }
200
201error:
202 if (fe->ops.i2c_gate_ctrl)
203 fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
204
205 if (ret)
206 dbg("%s: failed ret:%d", __func__, ret);
207
208 return ret;
209}
210
Antti Palosaari522fdf72011-11-13 00:19:56 -0300211static int tda18218_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
212{
213 struct tda18218_priv *priv = fe->tuner_priv;
214 *frequency = priv->if_frequency;
215 dbg("%s: if=%d", __func__, *frequency);
216 return 0;
217}
218
Antti Palosaari51ff2e22010-08-13 03:41:02 -0300219static int tda18218_sleep(struct dvb_frontend *fe)
220{
221 struct tda18218_priv *priv = fe->tuner_priv;
222 int ret;
223
224 if (fe->ops.i2c_gate_ctrl)
225 fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
226
227 /* standby */
228 ret = tda18218_wr_reg(priv, R17_PD1, priv->regs[R17_PD1] | (1 << 0));
229
230 if (fe->ops.i2c_gate_ctrl)
231 fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
232
233 if (ret)
234 dbg("%s: failed ret:%d", __func__, ret);
235
236 return ret;
237}
238
239static int tda18218_init(struct dvb_frontend *fe)
240{
241 struct tda18218_priv *priv = fe->tuner_priv;
242 int ret;
243
244 /* TODO: calibrations */
245
246 if (fe->ops.i2c_gate_ctrl)
247 fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
248
249 ret = tda18218_wr_regs(priv, R00_ID, priv->regs, TDA18218_NUM_REGS);
250
251 if (fe->ops.i2c_gate_ctrl)
252 fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
253
254 if (ret)
255 dbg("%s: failed ret:%d", __func__, ret);
256
257 return ret;
258}
259
260static int tda18218_release(struct dvb_frontend *fe)
261{
262 kfree(fe->tuner_priv);
263 fe->tuner_priv = NULL;
264 return 0;
265}
266
267static const struct dvb_tuner_ops tda18218_tuner_ops = {
268 .info = {
269 .name = "NXP TDA18218",
270
271 .frequency_min = 174000000,
272 .frequency_max = 864000000,
273 .frequency_step = 1000,
274 },
275
276 .release = tda18218_release,
277 .init = tda18218_init,
278 .sleep = tda18218_sleep,
279
280 .set_params = tda18218_set_params,
Antti Palosaari522fdf72011-11-13 00:19:56 -0300281
282 .get_if_frequency = tda18218_get_if_frequency,
Antti Palosaari51ff2e22010-08-13 03:41:02 -0300283};
284
285struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe,
286 struct i2c_adapter *i2c, struct tda18218_config *cfg)
287{
288 struct tda18218_priv *priv = NULL;
289 u8 val;
290 int ret;
291 /* chip default registers values */
292 static u8 def_regs[] = {
293 0xc0, 0x88, 0x00, 0x8e, 0x03, 0x00, 0x00, 0xd0, 0x00, 0x40,
294 0x00, 0x00, 0x07, 0xff, 0x84, 0x09, 0x00, 0x13, 0x00, 0x00,
295 0x01, 0x84, 0x09, 0xf0, 0x19, 0x0a, 0x8e, 0x69, 0x98, 0x01,
296 0x00, 0x58, 0x10, 0x40, 0x8c, 0x00, 0x0c, 0x48, 0x85, 0xc9,
297 0xa7, 0x00, 0x00, 0x00, 0x30, 0x81, 0x80, 0x00, 0x39, 0x00,
298 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xf6
299 };
300
301 priv = kzalloc(sizeof(struct tda18218_priv), GFP_KERNEL);
302 if (priv == NULL)
303 return NULL;
304
305 priv->cfg = cfg;
306 priv->i2c = i2c;
307 fe->tuner_priv = priv;
308
309 if (fe->ops.i2c_gate_ctrl)
310 fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
311
312 /* check if the tuner is there */
313 ret = tda18218_rd_reg(priv, R00_ID, &val);
314 dbg("%s: ret:%d chip ID:%02x", __func__, ret, val);
315 if (ret || val != def_regs[R00_ID]) {
316 kfree(priv);
317 return NULL;
318 }
319
320 info("NXP TDA18218HN successfully identified.");
321
322 memcpy(&fe->ops.tuner_ops, &tda18218_tuner_ops,
323 sizeof(struct dvb_tuner_ops));
324 memcpy(priv->regs, def_regs, sizeof(def_regs));
325
326 /* loop-through enabled chip default register values */
327 if (priv->cfg->loop_through) {
328 priv->regs[R17_PD1] = 0xb0;
329 priv->regs[R18_PD2] = 0x59;
330 }
331
332 /* standby */
333 ret = tda18218_wr_reg(priv, R17_PD1, priv->regs[R17_PD1] | (1 << 0));
334 if (ret)
335 dbg("%s: failed ret:%d", __func__, ret);
336
337 if (fe->ops.i2c_gate_ctrl)
338 fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
339
340 return fe;
341}
342EXPORT_SYMBOL(tda18218_attach);
343
344MODULE_DESCRIPTION("NXP TDA18218HN silicon tuner driver");
345MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
346MODULE_LICENSE("GPL");