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 + 3000000;
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");