2 * NXP TDA18212HN silicon tuner driver
4 * Copyright (C) 2011 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 along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include "tda18212_priv.h"
24 module_param(debug
, int, 0644);
25 MODULE_PARM_DESC(debug
, "Turn on/off debugging (default:off).");
27 /* write multiple registers */
28 static int tda18212_wr_regs(struct tda18212_priv
*priv
, u8 reg
, u8
*val
,
33 struct i2c_msg msg
[1] = {
35 .addr
= priv
->cfg
->i2c_address
,
43 memcpy(&buf
[1], val
, len
);
45 ret
= i2c_transfer(priv
->i2c
, msg
, 1);
49 warn("i2c wr failed ret:%d reg:%02x len:%d", ret
, reg
, len
);
55 /* read multiple registers */
56 static int tda18212_rd_regs(struct tda18212_priv
*priv
, u8 reg
, u8
*val
,
61 struct i2c_msg msg
[2] = {
63 .addr
= priv
->cfg
->i2c_address
,
68 .addr
= priv
->cfg
->i2c_address
,
75 ret
= i2c_transfer(priv
->i2c
, msg
, 2);
77 memcpy(val
, buf
, len
);
80 warn("i2c rd failed ret:%d reg:%02x len:%d", ret
, reg
, len
);
87 /* write single register */
88 static int tda18212_wr_reg(struct tda18212_priv
*priv
, u8 reg
, u8 val
)
90 return tda18212_wr_regs(priv
, reg
, &val
, 1);
93 /* read single register */
94 static int tda18212_rd_reg(struct tda18212_priv
*priv
, u8 reg
, u8
*val
)
96 return tda18212_rd_regs(priv
, reg
, val
, 1);
99 #if 0 /* keep, useful when developing driver */
100 static void tda18212_dump_regs(struct tda18212_priv
*priv
)
105 #define TDA18212_RD_LEN 32
106 for (i
= 0; i
< sizeof(buf
); i
+= TDA18212_RD_LEN
)
107 tda18212_rd_regs(priv
, i
, &buf
[i
], TDA18212_RD_LEN
);
109 print_hex_dump(KERN_INFO
, "", DUMP_PREFIX_OFFSET
, 32, 1, buf
,
116 static int tda18212_set_params(struct dvb_frontend
*fe
,
117 struct dvb_frontend_parameters
*p
)
119 struct tda18212_priv
*priv
= fe
->tuner_priv
;
120 struct dtv_frontend_properties
*c
= &fe
->dtv_property_cache
;
124 static const u8 bw_params
[][3] = {
126 { 0xb3, 0x20, 0x03 }, /* DVB-T 6 MHz */
127 { 0xb3, 0x31, 0x01 }, /* DVB-T 7 MHz */
128 { 0xb3, 0x22, 0x01 }, /* DVB-T 8 MHz */
129 { 0x92, 0x53, 0x03 }, /* DVB-C */
132 dbg("%s: delsys=%d RF=%d BW=%d", __func__
,
133 c
->delivery_system
, c
->frequency
, c
->bandwidth_hz
);
135 if (fe
->ops
.i2c_gate_ctrl
)
136 fe
->ops
.i2c_gate_ctrl(fe
, 1); /* open I2C-gate */
138 switch (c
->delivery_system
) {
140 switch (c
->bandwidth_hz
) {
142 if_khz
= priv
->cfg
->if_dvbt_6
;
146 if_khz
= priv
->cfg
->if_dvbt_7
;
150 if_khz
= priv
->cfg
->if_dvbt_8
;
158 case SYS_DVBC_ANNEX_AC
:
159 if_khz
= priv
->cfg
->if_dvbc
;
167 ret
= tda18212_wr_reg(priv
, 0x23, bw_params
[i
][2]);
171 ret
= tda18212_wr_reg(priv
, 0x06, 0x00);
175 ret
= tda18212_wr_reg(priv
, 0x0f, bw_params
[i
][0]);
180 buf
[1] = bw_params
[i
][1];
181 buf
[2] = 0x03; /* default value */
182 buf
[3] = if_khz
/ 50;
183 buf
[4] = ((c
->frequency
/ 1000) >> 16) & 0xff;
184 buf
[5] = ((c
->frequency
/ 1000) >> 8) & 0xff;
185 buf
[6] = ((c
->frequency
/ 1000) >> 0) & 0xff;
188 ret
= tda18212_wr_regs(priv
, 0x12, buf
, sizeof(buf
));
193 if (fe
->ops
.i2c_gate_ctrl
)
194 fe
->ops
.i2c_gate_ctrl(fe
, 0); /* close I2C-gate */
199 dbg("%s: failed:%d", __func__
, ret
);
203 static int tda18212_release(struct dvb_frontend
*fe
)
205 kfree(fe
->tuner_priv
);
206 fe
->tuner_priv
= NULL
;
210 static const struct dvb_tuner_ops tda18212_tuner_ops
= {
212 .name
= "NXP TDA18212",
214 .frequency_min
= 48000000,
215 .frequency_max
= 864000000,
216 .frequency_step
= 1000,
219 .release
= tda18212_release
,
221 .set_params
= tda18212_set_params
,
224 struct dvb_frontend
*tda18212_attach(struct dvb_frontend
*fe
,
225 struct i2c_adapter
*i2c
, struct tda18212_config
*cfg
)
227 struct tda18212_priv
*priv
= NULL
;
231 priv
= kzalloc(sizeof(struct tda18212_priv
), GFP_KERNEL
);
237 fe
->tuner_priv
= priv
;
239 if (fe
->ops
.i2c_gate_ctrl
)
240 fe
->ops
.i2c_gate_ctrl(fe
, 1); /* open I2C-gate */
242 /* check if the tuner is there */
243 ret
= tda18212_rd_reg(priv
, 0x00, &val
);
245 if (fe
->ops
.i2c_gate_ctrl
)
246 fe
->ops
.i2c_gate_ctrl(fe
, 0); /* close I2C-gate */
248 dbg("%s: ret:%d chip ID:%02x", __func__
, ret
, val
);
249 if (ret
|| val
!= 0xc7) {
254 info("NXP TDA18212HN successfully identified.");
256 memcpy(&fe
->ops
.tuner_ops
, &tda18212_tuner_ops
,
257 sizeof(struct dvb_tuner_ops
));
261 EXPORT_SYMBOL(tda18212_attach
);
263 MODULE_DESCRIPTION("NXP TDA18212HN silicon tuner driver");
264 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
265 MODULE_LICENSE("GPL");