2 * NXP TDA18218HN silicon tuner driver
4 * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
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.
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.
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.
22 #include "tda18218_priv.h"
25 module_param(debug
, int, 0644);
26 MODULE_PARM_DESC(debug
, "Turn on/off debugging (default:off).");
28 /* write multiple registers */
29 static int tda18218_wr_regs(struct tda18218_priv
*priv
, u8 reg
, u8
*val
, u8 len
)
32 u8 buf
[1+len
], quotient
, remainder
, i
, msg_len
, msg_len_max
;
33 struct i2c_msg msg
[1] = {
35 .addr
= priv
->cfg
->i2c_address
,
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 */
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
);
53 ret
= i2c_transfer(priv
->i2c
, msg
, 1);
61 warn("i2c wr failed ret:%d reg:%02x len:%d", ret
, reg
, len
);
68 /* read multiple registers */
69 static int tda18218_rd_regs(struct tda18218_priv
*priv
, u8 reg
, u8
*val
, u8 len
)
72 u8 buf
[reg
+len
]; /* we must start read always from reg 0x00 */
73 struct i2c_msg msg
[2] = {
75 .addr
= priv
->cfg
->i2c_address
,
80 .addr
= priv
->cfg
->i2c_address
,
87 ret
= i2c_transfer(priv
->i2c
, msg
, 2);
89 memcpy(val
, &buf
[reg
], len
);
92 warn("i2c rd failed ret:%d reg:%02x len:%d", ret
, reg
, len
);
99 /* write single register */
100 static int tda18218_wr_reg(struct tda18218_priv
*priv
, u8 reg
, u8 val
)
102 return tda18218_wr_regs(priv
, reg
, &val
, 1);
105 /* read single register */
107 static int tda18218_rd_reg(struct tda18218_priv
*priv
, u8 reg
, u8
*val
)
109 return tda18218_rd_regs(priv
, reg
, val
, 1);
112 static int tda18218_set_params(struct dvb_frontend
*fe
,
113 struct dvb_frontend_parameters
*params
)
115 struct tda18218_priv
*priv
= fe
->tuner_priv
;
117 u8 buf
[3], i
, BP_Filter
, LP_Fc
;
119 /* TODO: find out correct AGC algorithm */
137 if (fe
->ops
.i2c_gate_ctrl
)
138 fe
->ops
.i2c_gate_ctrl(fe
, 1); /* open I2C-gate */
140 /* low-pass filter cut-off frequency */
141 switch (params
->u
.ofdm
.bandwidth
) {
142 case BANDWIDTH_6_MHZ
:
144 LO_Frac
= params
->frequency
+ 4000000;
146 case BANDWIDTH_7_MHZ
:
148 LO_Frac
= params
->frequency
+ 3500000;
150 case BANDWIDTH_8_MHZ
:
153 LO_Frac
= params
->frequency
+ 4000000;
157 /* band-pass filter */
158 if (LO_Frac
< 188000000)
160 else if (LO_Frac
< 253000000)
162 else if (LO_Frac
< 343000000)
167 buf
[0] = (priv
->regs
[R1A_IF1
] & ~7) | BP_Filter
; /* BP_Filter */
168 buf
[1] = (priv
->regs
[R1B_IF2
] & ~3) | LP_Fc
; /* LP_Fc */
169 buf
[2] = priv
->regs
[R1C_AGC2B
];
170 ret
= tda18218_wr_regs(priv
, R1A_IF1
, buf
, 3);
174 buf
[0] = (LO_Frac
/ 1000) >> 12; /* LO_Frac_0 */
175 buf
[1] = (LO_Frac
/ 1000) >> 4; /* LO_Frac_1 */
176 buf
[2] = (LO_Frac
/ 1000) << 4 |
177 (priv
->regs
[R0C_MD5
] & 0x0f); /* LO_Frac_2 */
178 ret
= tda18218_wr_regs(priv
, R0A_MD3
, buf
, 3);
182 buf
[0] = priv
->regs
[R0F_MD8
] | (1 << 6); /* Freq_prog_Start */
183 ret
= tda18218_wr_regs(priv
, R0F_MD8
, buf
, 1);
187 buf
[0] = priv
->regs
[R0F_MD8
] & ~(1 << 6); /* Freq_prog_Start */
188 ret
= tda18218_wr_regs(priv
, R0F_MD8
, buf
, 1);
193 for (i
= 0; i
< ARRAY_SIZE(agc
); i
++) {
194 ret
= tda18218_wr_reg(priv
, agc
[i
][0], agc
[i
][1]);
200 if (fe
->ops
.i2c_gate_ctrl
)
201 fe
->ops
.i2c_gate_ctrl(fe
, 0); /* close I2C-gate */
204 dbg("%s: failed ret:%d", __func__
, ret
);
209 static int tda18218_sleep(struct dvb_frontend
*fe
)
211 struct tda18218_priv
*priv
= fe
->tuner_priv
;
214 if (fe
->ops
.i2c_gate_ctrl
)
215 fe
->ops
.i2c_gate_ctrl(fe
, 1); /* open I2C-gate */
218 ret
= tda18218_wr_reg(priv
, R17_PD1
, priv
->regs
[R17_PD1
] | (1 << 0));
220 if (fe
->ops
.i2c_gate_ctrl
)
221 fe
->ops
.i2c_gate_ctrl(fe
, 0); /* close I2C-gate */
224 dbg("%s: failed ret:%d", __func__
, ret
);
229 static int tda18218_init(struct dvb_frontend
*fe
)
231 struct tda18218_priv
*priv
= fe
->tuner_priv
;
234 /* TODO: calibrations */
236 if (fe
->ops
.i2c_gate_ctrl
)
237 fe
->ops
.i2c_gate_ctrl(fe
, 1); /* open I2C-gate */
239 ret
= tda18218_wr_regs(priv
, R00_ID
, priv
->regs
, TDA18218_NUM_REGS
);
241 if (fe
->ops
.i2c_gate_ctrl
)
242 fe
->ops
.i2c_gate_ctrl(fe
, 0); /* close I2C-gate */
245 dbg("%s: failed ret:%d", __func__
, ret
);
250 static int tda18218_release(struct dvb_frontend
*fe
)
252 kfree(fe
->tuner_priv
);
253 fe
->tuner_priv
= NULL
;
257 static const struct dvb_tuner_ops tda18218_tuner_ops
= {
259 .name
= "NXP TDA18218",
261 .frequency_min
= 174000000,
262 .frequency_max
= 864000000,
263 .frequency_step
= 1000,
266 .release
= tda18218_release
,
267 .init
= tda18218_init
,
268 .sleep
= tda18218_sleep
,
270 .set_params
= tda18218_set_params
,
273 struct dvb_frontend
*tda18218_attach(struct dvb_frontend
*fe
,
274 struct i2c_adapter
*i2c
, struct tda18218_config
*cfg
)
276 struct tda18218_priv
*priv
= NULL
;
279 /* chip default registers values */
280 static u8 def_regs
[] = {
281 0xc0, 0x88, 0x00, 0x8e, 0x03, 0x00, 0x00, 0xd0, 0x00, 0x40,
282 0x00, 0x00, 0x07, 0xff, 0x84, 0x09, 0x00, 0x13, 0x00, 0x00,
283 0x01, 0x84, 0x09, 0xf0, 0x19, 0x0a, 0x8e, 0x69, 0x98, 0x01,
284 0x00, 0x58, 0x10, 0x40, 0x8c, 0x00, 0x0c, 0x48, 0x85, 0xc9,
285 0xa7, 0x00, 0x00, 0x00, 0x30, 0x81, 0x80, 0x00, 0x39, 0x00,
286 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xf6
289 priv
= kzalloc(sizeof(struct tda18218_priv
), GFP_KERNEL
);
295 fe
->tuner_priv
= priv
;
297 if (fe
->ops
.i2c_gate_ctrl
)
298 fe
->ops
.i2c_gate_ctrl(fe
, 1); /* open I2C-gate */
300 /* check if the tuner is there */
301 ret
= tda18218_rd_reg(priv
, R00_ID
, &val
);
302 dbg("%s: ret:%d chip ID:%02x", __func__
, ret
, val
);
303 if (ret
|| val
!= def_regs
[R00_ID
]) {
308 info("NXP TDA18218HN successfully identified.");
310 memcpy(&fe
->ops
.tuner_ops
, &tda18218_tuner_ops
,
311 sizeof(struct dvb_tuner_ops
));
312 memcpy(priv
->regs
, def_regs
, sizeof(def_regs
));
314 /* loop-through enabled chip default register values */
315 if (priv
->cfg
->loop_through
) {
316 priv
->regs
[R17_PD1
] = 0xb0;
317 priv
->regs
[R18_PD2
] = 0x59;
321 ret
= tda18218_wr_reg(priv
, R17_PD1
, priv
->regs
[R17_PD1
] | (1 << 0));
323 dbg("%s: failed ret:%d", __func__
, ret
);
325 if (fe
->ops
.i2c_gate_ctrl
)
326 fe
->ops
.i2c_gate_ctrl(fe
, 0); /* close I2C-gate */
330 EXPORT_SYMBOL(tda18218_attach
);
332 MODULE_DESCRIPTION("NXP TDA18218HN silicon tuner driver");
333 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
334 MODULE_LICENSE("GPL");