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 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
25 struct tda18212_priv
{
26 struct tda18212_config
*cfg
;
27 struct i2c_adapter
*i2c
;
32 #define dbg(fmt, arg...) \
35 pr_info("%s: " fmt, __func__, ##arg); \
39 module_param(debug
, int, 0644);
40 MODULE_PARM_DESC(debug
, "Turn on/off debugging (default:off).");
42 /* write multiple registers */
43 static int tda18212_wr_regs(struct tda18212_priv
*priv
, u8 reg
, u8
*val
,
48 struct i2c_msg msg
[1] = {
50 .addr
= priv
->cfg
->i2c_address
,
58 memcpy(&buf
[1], val
, len
);
60 ret
= i2c_transfer(priv
->i2c
, msg
, 1);
64 pr_warn("i2c wr failed ret:%d reg:%02x len:%d\n",
71 /* read multiple registers */
72 static int tda18212_rd_regs(struct tda18212_priv
*priv
, u8 reg
, u8
*val
,
77 struct i2c_msg msg
[2] = {
79 .addr
= priv
->cfg
->i2c_address
,
84 .addr
= priv
->cfg
->i2c_address
,
91 ret
= i2c_transfer(priv
->i2c
, msg
, 2);
93 memcpy(val
, buf
, len
);
96 pr_warn("i2c rd failed ret:%d reg:%02x len:%d\n",
104 /* write single register */
105 static int tda18212_wr_reg(struct tda18212_priv
*priv
, u8 reg
, u8 val
)
107 return tda18212_wr_regs(priv
, reg
, &val
, 1);
110 /* read single register */
111 static int tda18212_rd_reg(struct tda18212_priv
*priv
, u8 reg
, u8
*val
)
113 return tda18212_rd_regs(priv
, reg
, val
, 1);
116 #if 0 /* keep, useful when developing driver */
117 static void tda18212_dump_regs(struct tda18212_priv
*priv
)
122 #define TDA18212_RD_LEN 32
123 for (i
= 0; i
< sizeof(buf
); i
+= TDA18212_RD_LEN
)
124 tda18212_rd_regs(priv
, i
, &buf
[i
], TDA18212_RD_LEN
);
126 print_hex_dump(KERN_INFO
, "", DUMP_PREFIX_OFFSET
, 32, 1, buf
,
133 static int tda18212_set_params(struct dvb_frontend
*fe
)
135 struct tda18212_priv
*priv
= fe
->tuner_priv
;
136 struct dtv_frontend_properties
*c
= &fe
->dtv_property_cache
;
148 static const u8 bw_params
[][3] = {
150 [DVBT_6
] = { 0xb3, 0x20, 0x03 },
151 [DVBT_7
] = { 0xb3, 0x31, 0x01 },
152 [DVBT_8
] = { 0xb3, 0x22, 0x01 },
153 [DVBT2_6
] = { 0xbc, 0x20, 0x03 },
154 [DVBT2_7
] = { 0xbc, 0x72, 0x03 },
155 [DVBT2_8
] = { 0xbc, 0x22, 0x01 },
156 [DVBC_6
] = { 0x92, 0x50, 0x03 },
157 [DVBC_8
] = { 0x92, 0x53, 0x03 },
160 dbg("delsys=%d RF=%d BW=%d\n",
161 c
->delivery_system
, c
->frequency
, c
->bandwidth_hz
);
163 if (fe
->ops
.i2c_gate_ctrl
)
164 fe
->ops
.i2c_gate_ctrl(fe
, 1); /* open I2C-gate */
166 switch (c
->delivery_system
) {
168 switch (c
->bandwidth_hz
) {
170 if_khz
= priv
->cfg
->if_dvbt_6
;
174 if_khz
= priv
->cfg
->if_dvbt_7
;
178 if_khz
= priv
->cfg
->if_dvbt_8
;
187 switch (c
->bandwidth_hz
) {
189 if_khz
= priv
->cfg
->if_dvbt2_6
;
193 if_khz
= priv
->cfg
->if_dvbt2_7
;
197 if_khz
= priv
->cfg
->if_dvbt2_8
;
205 case SYS_DVBC_ANNEX_A
:
206 case SYS_DVBC_ANNEX_C
:
207 if_khz
= priv
->cfg
->if_dvbc
;
215 ret
= tda18212_wr_reg(priv
, 0x23, bw_params
[i
][2]);
219 ret
= tda18212_wr_reg(priv
, 0x06, 0x00);
223 ret
= tda18212_wr_reg(priv
, 0x0f, bw_params
[i
][0]);
228 buf
[1] = bw_params
[i
][1];
229 buf
[2] = 0x03; /* default value */
230 buf
[3] = DIV_ROUND_CLOSEST(if_khz
, 50);
231 buf
[4] = ((c
->frequency
/ 1000) >> 16) & 0xff;
232 buf
[5] = ((c
->frequency
/ 1000) >> 8) & 0xff;
233 buf
[6] = ((c
->frequency
/ 1000) >> 0) & 0xff;
236 ret
= tda18212_wr_regs(priv
, 0x12, buf
, sizeof(buf
));
240 /* actual IF rounded as it is on register */
241 priv
->if_frequency
= buf
[3] * 50 * 1000;
244 if (fe
->ops
.i2c_gate_ctrl
)
245 fe
->ops
.i2c_gate_ctrl(fe
, 0); /* close I2C-gate */
250 dbg("failed:%d\n", ret
);
254 static int tda18212_get_if_frequency(struct dvb_frontend
*fe
, u32
*frequency
)
256 struct tda18212_priv
*priv
= fe
->tuner_priv
;
258 *frequency
= priv
->if_frequency
;
263 static int tda18212_release(struct dvb_frontend
*fe
)
265 kfree(fe
->tuner_priv
);
266 fe
->tuner_priv
= NULL
;
270 static const struct dvb_tuner_ops tda18212_tuner_ops
= {
272 .name
= "NXP TDA18212",
274 .frequency_min
= 48000000,
275 .frequency_max
= 864000000,
276 .frequency_step
= 1000,
279 .release
= tda18212_release
,
281 .set_params
= tda18212_set_params
,
282 .get_if_frequency
= tda18212_get_if_frequency
,
285 struct dvb_frontend
*tda18212_attach(struct dvb_frontend
*fe
,
286 struct i2c_adapter
*i2c
, struct tda18212_config
*cfg
)
288 struct tda18212_priv
*priv
= NULL
;
292 priv
= kzalloc(sizeof(struct tda18212_priv
), GFP_KERNEL
);
298 fe
->tuner_priv
= priv
;
300 if (fe
->ops
.i2c_gate_ctrl
)
301 fe
->ops
.i2c_gate_ctrl(fe
, 1); /* open I2C-gate */
303 /* check if the tuner is there */
304 ret
= tda18212_rd_reg(priv
, 0x00, &val
);
306 if (fe
->ops
.i2c_gate_ctrl
)
307 fe
->ops
.i2c_gate_ctrl(fe
, 0); /* close I2C-gate */
309 dbg("ret:%d chip ID:%02x\n", ret
, val
);
310 if (ret
|| val
!= 0xc7) {
315 pr_info("NXP TDA18212HN successfully identified\n");
317 memcpy(&fe
->ops
.tuner_ops
, &tda18212_tuner_ops
,
318 sizeof(struct dvb_tuner_ops
));
322 EXPORT_SYMBOL(tda18212_attach
);
324 MODULE_DESCRIPTION("NXP TDA18212HN silicon tuner driver");
325 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
326 MODULE_LICENSE("GPL");