xref: /linux/drivers/media/tuners/tda18218.c (revision 03c11eb3b16dc0058589751dfd91f254be2be613)
1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2ccae7af2SMauro Carvalho Chehab /*
3ccae7af2SMauro Carvalho Chehab  * NXP TDA18218HN silicon tuner driver
4ccae7af2SMauro Carvalho Chehab  *
5ccae7af2SMauro Carvalho Chehab  * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
6ccae7af2SMauro Carvalho Chehab  */
7ccae7af2SMauro Carvalho Chehab 
8ccae7af2SMauro Carvalho Chehab #include "tda18218_priv.h"
9ccae7af2SMauro Carvalho Chehab 
10f1baab87SMauro Carvalho Chehab /* Max transfer size done by I2C transfer functions */
11f1baab87SMauro Carvalho Chehab #define MAX_XFER_SIZE  64
12f1baab87SMauro Carvalho Chehab 
13ccae7af2SMauro Carvalho Chehab /* write multiple registers */
tda18218_wr_regs(struct tda18218_priv * priv,u8 reg,u8 * val,u8 len)14ccae7af2SMauro Carvalho Chehab static int tda18218_wr_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len)
15ccae7af2SMauro Carvalho Chehab {
16af3a07acSAntti Palosaari 	int ret = 0, len2, remaining;
17f1baab87SMauro Carvalho Chehab 	u8 buf[MAX_XFER_SIZE];
18ccae7af2SMauro Carvalho Chehab 	struct i2c_msg msg[1] = {
19ccae7af2SMauro Carvalho Chehab 		{
20ccae7af2SMauro Carvalho Chehab 			.addr = priv->cfg->i2c_address,
21ccae7af2SMauro Carvalho Chehab 			.flags = 0,
22ccae7af2SMauro Carvalho Chehab 			.buf = buf,
23ccae7af2SMauro Carvalho Chehab 		}
24ccae7af2SMauro Carvalho Chehab 	};
25ccae7af2SMauro Carvalho Chehab 
26f1baab87SMauro Carvalho Chehab 	if (1 + len > sizeof(buf)) {
27f1baab87SMauro Carvalho Chehab 		dev_warn(&priv->i2c->dev,
28f1baab87SMauro Carvalho Chehab 			 "%s: i2c wr reg=%04x: len=%d is too big!\n",
29f1baab87SMauro Carvalho Chehab 			 KBUILD_MODNAME, reg, len);
30f1baab87SMauro Carvalho Chehab 		return -EINVAL;
31f1baab87SMauro Carvalho Chehab 	}
32f1baab87SMauro Carvalho Chehab 
33af3a07acSAntti Palosaari 	for (remaining = len; remaining > 0;
34af3a07acSAntti Palosaari 			remaining -= (priv->cfg->i2c_wr_max - 1)) {
35af3a07acSAntti Palosaari 		len2 = remaining;
36af3a07acSAntti Palosaari 		if (len2 > (priv->cfg->i2c_wr_max - 1))
37af3a07acSAntti Palosaari 			len2 = (priv->cfg->i2c_wr_max - 1);
38ccae7af2SMauro Carvalho Chehab 
39af3a07acSAntti Palosaari 		msg[0].len = 1 + len2;
40af3a07acSAntti Palosaari 		buf[0] = reg + len - remaining;
41af3a07acSAntti Palosaari 		memcpy(&buf[1], &val[len - remaining], len2);
42ccae7af2SMauro Carvalho Chehab 
43ccae7af2SMauro Carvalho Chehab 		ret = i2c_transfer(priv->i2c, msg, 1);
44ccae7af2SMauro Carvalho Chehab 		if (ret != 1)
45ccae7af2SMauro Carvalho Chehab 			break;
46ccae7af2SMauro Carvalho Chehab 	}
47ccae7af2SMauro Carvalho Chehab 
48ccae7af2SMauro Carvalho Chehab 	if (ret == 1) {
49ccae7af2SMauro Carvalho Chehab 		ret = 0;
50ccae7af2SMauro Carvalho Chehab 	} else {
519edd6987SAntti Palosaari 		dev_warn(&priv->i2c->dev, "%s: i2c wr failed=%d reg=%02x " \
529edd6987SAntti Palosaari 				"len=%d\n", KBUILD_MODNAME, ret, reg, len);
53ccae7af2SMauro Carvalho Chehab 		ret = -EREMOTEIO;
54ccae7af2SMauro Carvalho Chehab 	}
55ccae7af2SMauro Carvalho Chehab 
56ccae7af2SMauro Carvalho Chehab 	return ret;
57ccae7af2SMauro Carvalho Chehab }
58ccae7af2SMauro Carvalho Chehab 
59ccae7af2SMauro Carvalho Chehab /* read multiple registers */
tda18218_rd_regs(struct tda18218_priv * priv,u8 reg,u8 * val,u8 len)60ccae7af2SMauro Carvalho Chehab static int tda18218_rd_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len)
61ccae7af2SMauro Carvalho Chehab {
62ccae7af2SMauro Carvalho Chehab 	int ret;
63f1baab87SMauro Carvalho Chehab 	u8 buf[MAX_XFER_SIZE]; /* we must start read always from reg 0x00 */
64ccae7af2SMauro Carvalho Chehab 	struct i2c_msg msg[2] = {
65ccae7af2SMauro Carvalho Chehab 		{
66ccae7af2SMauro Carvalho Chehab 			.addr = priv->cfg->i2c_address,
67ccae7af2SMauro Carvalho Chehab 			.flags = 0,
68ccae7af2SMauro Carvalho Chehab 			.len = 1,
69ccae7af2SMauro Carvalho Chehab 			.buf = "\x00",
70ccae7af2SMauro Carvalho Chehab 		}, {
71ccae7af2SMauro Carvalho Chehab 			.addr = priv->cfg->i2c_address,
72ccae7af2SMauro Carvalho Chehab 			.flags = I2C_M_RD,
73f1baab87SMauro Carvalho Chehab 			.len = reg + len,
74ccae7af2SMauro Carvalho Chehab 			.buf = buf,
75ccae7af2SMauro Carvalho Chehab 		}
76ccae7af2SMauro Carvalho Chehab 	};
77ccae7af2SMauro Carvalho Chehab 
78f1baab87SMauro Carvalho Chehab 	if (reg + len > sizeof(buf)) {
79f1baab87SMauro Carvalho Chehab 		dev_warn(&priv->i2c->dev,
80f1baab87SMauro Carvalho Chehab 			 "%s: i2c wr reg=%04x: len=%d is too big!\n",
81f1baab87SMauro Carvalho Chehab 			 KBUILD_MODNAME, reg, len);
82f1baab87SMauro Carvalho Chehab 		return -EINVAL;
83f1baab87SMauro Carvalho Chehab 	}
84f1baab87SMauro Carvalho Chehab 
85ccae7af2SMauro Carvalho Chehab 	ret = i2c_transfer(priv->i2c, msg, 2);
86ccae7af2SMauro Carvalho Chehab 	if (ret == 2) {
87ccae7af2SMauro Carvalho Chehab 		memcpy(val, &buf[reg], len);
88ccae7af2SMauro Carvalho Chehab 		ret = 0;
89ccae7af2SMauro Carvalho Chehab 	} else {
909edd6987SAntti Palosaari 		dev_warn(&priv->i2c->dev, "%s: i2c rd failed=%d reg=%02x " \
919edd6987SAntti Palosaari 				"len=%d\n", KBUILD_MODNAME, ret, reg, len);
92ccae7af2SMauro Carvalho Chehab 		ret = -EREMOTEIO;
93ccae7af2SMauro Carvalho Chehab 	}
94ccae7af2SMauro Carvalho Chehab 
95ccae7af2SMauro Carvalho Chehab 	return ret;
96ccae7af2SMauro Carvalho Chehab }
97ccae7af2SMauro Carvalho Chehab 
98ccae7af2SMauro Carvalho Chehab /* write single register */
tda18218_wr_reg(struct tda18218_priv * priv,u8 reg,u8 val)99ccae7af2SMauro Carvalho Chehab static int tda18218_wr_reg(struct tda18218_priv *priv, u8 reg, u8 val)
100ccae7af2SMauro Carvalho Chehab {
101ccae7af2SMauro Carvalho Chehab 	return tda18218_wr_regs(priv, reg, &val, 1);
102ccae7af2SMauro Carvalho Chehab }
103ccae7af2SMauro Carvalho Chehab 
104ccae7af2SMauro Carvalho Chehab /* read single register */
105ccae7af2SMauro Carvalho Chehab 
tda18218_rd_reg(struct tda18218_priv * priv,u8 reg,u8 * val)106ccae7af2SMauro Carvalho Chehab static int tda18218_rd_reg(struct tda18218_priv *priv, u8 reg, u8 *val)
107ccae7af2SMauro Carvalho Chehab {
108ccae7af2SMauro Carvalho Chehab 	return tda18218_rd_regs(priv, reg, val, 1);
109ccae7af2SMauro Carvalho Chehab }
110ccae7af2SMauro Carvalho Chehab 
tda18218_set_params(struct dvb_frontend * fe)111ccae7af2SMauro Carvalho Chehab static int tda18218_set_params(struct dvb_frontend *fe)
112ccae7af2SMauro Carvalho Chehab {
113ccae7af2SMauro Carvalho Chehab 	struct tda18218_priv *priv = fe->tuner_priv;
114ccae7af2SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
115ccae7af2SMauro Carvalho Chehab 	u32 bw = c->bandwidth_hz;
116ccae7af2SMauro Carvalho Chehab 	int ret;
117ccae7af2SMauro Carvalho Chehab 	u8 buf[3], i, BP_Filter, LP_Fc;
118ccae7af2SMauro Carvalho Chehab 	u32 LO_Frac;
119ccae7af2SMauro Carvalho Chehab 	/* TODO: find out correct AGC algorithm */
120ccae7af2SMauro Carvalho Chehab 	u8 agc[][2] = {
121ccae7af2SMauro Carvalho Chehab 		{ R20_AGC11, 0x60 },
122ccae7af2SMauro Carvalho Chehab 		{ R23_AGC21, 0x02 },
123ccae7af2SMauro Carvalho Chehab 		{ R20_AGC11, 0xa0 },
124ccae7af2SMauro Carvalho Chehab 		{ R23_AGC21, 0x09 },
125ccae7af2SMauro Carvalho Chehab 		{ R20_AGC11, 0xe0 },
126ccae7af2SMauro Carvalho Chehab 		{ R23_AGC21, 0x0c },
127ccae7af2SMauro Carvalho Chehab 		{ R20_AGC11, 0x40 },
128ccae7af2SMauro Carvalho Chehab 		{ R23_AGC21, 0x01 },
129ccae7af2SMauro Carvalho Chehab 		{ R20_AGC11, 0x80 },
130ccae7af2SMauro Carvalho Chehab 		{ R23_AGC21, 0x08 },
131ccae7af2SMauro Carvalho Chehab 		{ R20_AGC11, 0xc0 },
132ccae7af2SMauro Carvalho Chehab 		{ R23_AGC21, 0x0b },
133ccae7af2SMauro Carvalho Chehab 		{ R24_AGC22, 0x1c },
134ccae7af2SMauro Carvalho Chehab 		{ R24_AGC22, 0x0c },
135ccae7af2SMauro Carvalho Chehab 	};
136ccae7af2SMauro Carvalho Chehab 
137ccae7af2SMauro Carvalho Chehab 	if (fe->ops.i2c_gate_ctrl)
138ccae7af2SMauro Carvalho Chehab 		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
139ccae7af2SMauro Carvalho Chehab 
140ccae7af2SMauro Carvalho Chehab 	/* low-pass filter cut-off frequency */
141ccae7af2SMauro Carvalho Chehab 	if (bw <= 6000000) {
142ccae7af2SMauro Carvalho Chehab 		LP_Fc = 0;
143ccae7af2SMauro Carvalho Chehab 		priv->if_frequency = 3000000;
144ccae7af2SMauro Carvalho Chehab 	} else if (bw <= 7000000) {
145ccae7af2SMauro Carvalho Chehab 		LP_Fc = 1;
146ccae7af2SMauro Carvalho Chehab 		priv->if_frequency = 3500000;
147ccae7af2SMauro Carvalho Chehab 	} else {
148ccae7af2SMauro Carvalho Chehab 		LP_Fc = 2;
149ccae7af2SMauro Carvalho Chehab 		priv->if_frequency = 4000000;
150ccae7af2SMauro Carvalho Chehab 	}
151ccae7af2SMauro Carvalho Chehab 
152ccae7af2SMauro Carvalho Chehab 	LO_Frac = c->frequency + priv->if_frequency;
153ccae7af2SMauro Carvalho Chehab 
154ccae7af2SMauro Carvalho Chehab 	/* band-pass filter */
155ccae7af2SMauro Carvalho Chehab 	if (LO_Frac < 188000000)
156ccae7af2SMauro Carvalho Chehab 		BP_Filter = 3;
157ccae7af2SMauro Carvalho Chehab 	else if (LO_Frac < 253000000)
158ccae7af2SMauro Carvalho Chehab 		BP_Filter = 4;
159ccae7af2SMauro Carvalho Chehab 	else if (LO_Frac < 343000000)
160ccae7af2SMauro Carvalho Chehab 		BP_Filter = 5;
161ccae7af2SMauro Carvalho Chehab 	else
162ccae7af2SMauro Carvalho Chehab 		BP_Filter = 6;
163ccae7af2SMauro Carvalho Chehab 
164ccae7af2SMauro Carvalho Chehab 	buf[0] = (priv->regs[R1A_IF1] & ~7) | BP_Filter; /* BP_Filter */
165ccae7af2SMauro Carvalho Chehab 	buf[1] = (priv->regs[R1B_IF2] & ~3) | LP_Fc; /* LP_Fc */
166ccae7af2SMauro Carvalho Chehab 	buf[2] = priv->regs[R1C_AGC2B];
167ccae7af2SMauro Carvalho Chehab 	ret = tda18218_wr_regs(priv, R1A_IF1, buf, 3);
168ccae7af2SMauro Carvalho Chehab 	if (ret)
169ccae7af2SMauro Carvalho Chehab 		goto error;
170ccae7af2SMauro Carvalho Chehab 
171ccae7af2SMauro Carvalho Chehab 	buf[0] = (LO_Frac / 1000) >> 12; /* LO_Frac_0 */
172ccae7af2SMauro Carvalho Chehab 	buf[1] = (LO_Frac / 1000) >> 4; /* LO_Frac_1 */
173ccae7af2SMauro Carvalho Chehab 	buf[2] = (LO_Frac / 1000) << 4 |
174ccae7af2SMauro Carvalho Chehab 		(priv->regs[R0C_MD5] & 0x0f); /* LO_Frac_2 */
175ccae7af2SMauro Carvalho Chehab 	ret = tda18218_wr_regs(priv, R0A_MD3, buf, 3);
176ccae7af2SMauro Carvalho Chehab 	if (ret)
177ccae7af2SMauro Carvalho Chehab 		goto error;
178ccae7af2SMauro Carvalho Chehab 
179ccae7af2SMauro Carvalho Chehab 	buf[0] = priv->regs[R0F_MD8] | (1 << 6); /* Freq_prog_Start */
180ccae7af2SMauro Carvalho Chehab 	ret = tda18218_wr_regs(priv, R0F_MD8, buf, 1);
181ccae7af2SMauro Carvalho Chehab 	if (ret)
182ccae7af2SMauro Carvalho Chehab 		goto error;
183ccae7af2SMauro Carvalho Chehab 
184ccae7af2SMauro Carvalho Chehab 	buf[0] = priv->regs[R0F_MD8] & ~(1 << 6); /* Freq_prog_Start */
185ccae7af2SMauro Carvalho Chehab 	ret = tda18218_wr_regs(priv, R0F_MD8, buf, 1);
186ccae7af2SMauro Carvalho Chehab 	if (ret)
187ccae7af2SMauro Carvalho Chehab 		goto error;
188ccae7af2SMauro Carvalho Chehab 
189ccae7af2SMauro Carvalho Chehab 	/* trigger AGC */
190ccae7af2SMauro Carvalho Chehab 	for (i = 0; i < ARRAY_SIZE(agc); i++) {
191ccae7af2SMauro Carvalho Chehab 		ret = tda18218_wr_reg(priv, agc[i][0], agc[i][1]);
192ccae7af2SMauro Carvalho Chehab 		if (ret)
193ccae7af2SMauro Carvalho Chehab 			goto error;
194ccae7af2SMauro Carvalho Chehab 	}
195ccae7af2SMauro Carvalho Chehab 
196ccae7af2SMauro Carvalho Chehab error:
197ccae7af2SMauro Carvalho Chehab 	if (fe->ops.i2c_gate_ctrl)
198ccae7af2SMauro Carvalho Chehab 		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
199ccae7af2SMauro Carvalho Chehab 
200ccae7af2SMauro Carvalho Chehab 	if (ret)
2019edd6987SAntti Palosaari 		dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
202ccae7af2SMauro Carvalho Chehab 
203ccae7af2SMauro Carvalho Chehab 	return ret;
204ccae7af2SMauro Carvalho Chehab }
205ccae7af2SMauro Carvalho Chehab 
tda18218_get_if_frequency(struct dvb_frontend * fe,u32 * frequency)206ccae7af2SMauro Carvalho Chehab static int tda18218_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
207ccae7af2SMauro Carvalho Chehab {
208ccae7af2SMauro Carvalho Chehab 	struct tda18218_priv *priv = fe->tuner_priv;
209ccae7af2SMauro Carvalho Chehab 	*frequency = priv->if_frequency;
2109edd6987SAntti Palosaari 	dev_dbg(&priv->i2c->dev, "%s: if_frequency=%d\n", __func__, *frequency);
211ccae7af2SMauro Carvalho Chehab 	return 0;
212ccae7af2SMauro Carvalho Chehab }
213ccae7af2SMauro Carvalho Chehab 
tda18218_sleep(struct dvb_frontend * fe)214ccae7af2SMauro Carvalho Chehab static int tda18218_sleep(struct dvb_frontend *fe)
215ccae7af2SMauro Carvalho Chehab {
216ccae7af2SMauro Carvalho Chehab 	struct tda18218_priv *priv = fe->tuner_priv;
217ccae7af2SMauro Carvalho Chehab 	int ret;
218ccae7af2SMauro Carvalho Chehab 
219ccae7af2SMauro Carvalho Chehab 	if (fe->ops.i2c_gate_ctrl)
220ccae7af2SMauro Carvalho Chehab 		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
221ccae7af2SMauro Carvalho Chehab 
222ccae7af2SMauro Carvalho Chehab 	/* standby */
223ccae7af2SMauro Carvalho Chehab 	ret = tda18218_wr_reg(priv, R17_PD1, priv->regs[R17_PD1] | (1 << 0));
224ccae7af2SMauro Carvalho Chehab 
225ccae7af2SMauro Carvalho Chehab 	if (fe->ops.i2c_gate_ctrl)
226ccae7af2SMauro Carvalho Chehab 		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
227ccae7af2SMauro Carvalho Chehab 
228ccae7af2SMauro Carvalho Chehab 	if (ret)
2299edd6987SAntti Palosaari 		dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
230ccae7af2SMauro Carvalho Chehab 
231ccae7af2SMauro Carvalho Chehab 	return ret;
232ccae7af2SMauro Carvalho Chehab }
233ccae7af2SMauro Carvalho Chehab 
tda18218_init(struct dvb_frontend * fe)234ccae7af2SMauro Carvalho Chehab static int tda18218_init(struct dvb_frontend *fe)
235ccae7af2SMauro Carvalho Chehab {
236ccae7af2SMauro Carvalho Chehab 	struct tda18218_priv *priv = fe->tuner_priv;
237ccae7af2SMauro Carvalho Chehab 	int ret;
238ccae7af2SMauro Carvalho Chehab 
239ccae7af2SMauro Carvalho Chehab 	/* TODO: calibrations */
240ccae7af2SMauro Carvalho Chehab 
241ccae7af2SMauro Carvalho Chehab 	if (fe->ops.i2c_gate_ctrl)
242ccae7af2SMauro Carvalho Chehab 		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
243ccae7af2SMauro Carvalho Chehab 
244ccae7af2SMauro Carvalho Chehab 	ret = tda18218_wr_regs(priv, R00_ID, priv->regs, TDA18218_NUM_REGS);
245ccae7af2SMauro Carvalho Chehab 
246ccae7af2SMauro Carvalho Chehab 	if (fe->ops.i2c_gate_ctrl)
247ccae7af2SMauro Carvalho Chehab 		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
248ccae7af2SMauro Carvalho Chehab 
249ccae7af2SMauro Carvalho Chehab 	if (ret)
2509edd6987SAntti Palosaari 		dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
251ccae7af2SMauro Carvalho Chehab 
252ccae7af2SMauro Carvalho Chehab 	return ret;
253ccae7af2SMauro Carvalho Chehab }
254ccae7af2SMauro Carvalho Chehab 
tda18218_release(struct dvb_frontend * fe)255f2709c20SMauro Carvalho Chehab static void tda18218_release(struct dvb_frontend *fe)
256f2709c20SMauro Carvalho Chehab {
257f2709c20SMauro Carvalho Chehab 	kfree(fe->tuner_priv);
258f2709c20SMauro Carvalho Chehab 	fe->tuner_priv = NULL;
259f2709c20SMauro Carvalho Chehab }
260f2709c20SMauro Carvalho Chehab 
261ccae7af2SMauro Carvalho Chehab static const struct dvb_tuner_ops tda18218_tuner_ops = {
262ccae7af2SMauro Carvalho Chehab 	.info = {
263ccae7af2SMauro Carvalho Chehab 		.name              = "NXP TDA18218",
264ccae7af2SMauro Carvalho Chehab 
265a3f90c75SMauro Carvalho Chehab 		.frequency_min_hz  = 174 * MHz,
266a3f90c75SMauro Carvalho Chehab 		.frequency_max_hz  = 864 * MHz,
267a3f90c75SMauro Carvalho Chehab 		.frequency_step_hz =   1 * kHz,
268ccae7af2SMauro Carvalho Chehab 	},
269ccae7af2SMauro Carvalho Chehab 
270f2709c20SMauro Carvalho Chehab 	.release       = tda18218_release,
271ccae7af2SMauro Carvalho Chehab 	.init          = tda18218_init,
272ccae7af2SMauro Carvalho Chehab 	.sleep         = tda18218_sleep,
273ccae7af2SMauro Carvalho Chehab 
274ccae7af2SMauro Carvalho Chehab 	.set_params    = tda18218_set_params,
275ccae7af2SMauro Carvalho Chehab 
276ccae7af2SMauro Carvalho Chehab 	.get_if_frequency = tda18218_get_if_frequency,
277ccae7af2SMauro Carvalho Chehab };
278ccae7af2SMauro Carvalho Chehab 
tda18218_attach(struct dvb_frontend * fe,struct i2c_adapter * i2c,struct tda18218_config * cfg)279ccae7af2SMauro Carvalho Chehab struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe,
280ccae7af2SMauro Carvalho Chehab 	struct i2c_adapter *i2c, struct tda18218_config *cfg)
281ccae7af2SMauro Carvalho Chehab {
282ccae7af2SMauro Carvalho Chehab 	struct tda18218_priv *priv = NULL;
283ed2e3301SPaul Bolle 	u8 val;
284ccae7af2SMauro Carvalho Chehab 	int ret;
285ccae7af2SMauro Carvalho Chehab 	/* chip default registers values */
286ccae7af2SMauro Carvalho Chehab 	static u8 def_regs[] = {
287ccae7af2SMauro Carvalho Chehab 		0xc0, 0x88, 0x00, 0x8e, 0x03, 0x00, 0x00, 0xd0, 0x00, 0x40,
288ccae7af2SMauro Carvalho Chehab 		0x00, 0x00, 0x07, 0xff, 0x84, 0x09, 0x00, 0x13, 0x00, 0x00,
289ccae7af2SMauro Carvalho Chehab 		0x01, 0x84, 0x09, 0xf0, 0x19, 0x0a, 0x8e, 0x69, 0x98, 0x01,
290ccae7af2SMauro Carvalho Chehab 		0x00, 0x58, 0x10, 0x40, 0x8c, 0x00, 0x0c, 0x48, 0x85, 0xc9,
291ccae7af2SMauro Carvalho Chehab 		0xa7, 0x00, 0x00, 0x00, 0x30, 0x81, 0x80, 0x00, 0x39, 0x00,
292ccae7af2SMauro Carvalho Chehab 		0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xf6
293ccae7af2SMauro Carvalho Chehab 	};
294ccae7af2SMauro Carvalho Chehab 
295ccae7af2SMauro Carvalho Chehab 	priv = kzalloc(sizeof(struct tda18218_priv), GFP_KERNEL);
296ccae7af2SMauro Carvalho Chehab 	if (priv == NULL)
297ccae7af2SMauro Carvalho Chehab 		return NULL;
298ccae7af2SMauro Carvalho Chehab 
299ccae7af2SMauro Carvalho Chehab 	priv->cfg = cfg;
300ccae7af2SMauro Carvalho Chehab 	priv->i2c = i2c;
301ccae7af2SMauro Carvalho Chehab 	fe->tuner_priv = priv;
302ccae7af2SMauro Carvalho Chehab 
303ccae7af2SMauro Carvalho Chehab 	if (fe->ops.i2c_gate_ctrl)
304ccae7af2SMauro Carvalho Chehab 		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
305ccae7af2SMauro Carvalho Chehab 
306ccae7af2SMauro Carvalho Chehab 	/* check if the tuner is there */
307ccae7af2SMauro Carvalho Chehab 	ret = tda18218_rd_reg(priv, R00_ID, &val);
308ed2e3301SPaul Bolle 	if (!ret)
309ed2e3301SPaul Bolle 		dev_dbg(&priv->i2c->dev, "%s: chip id=%02x\n", __func__, val);
310ccae7af2SMauro Carvalho Chehab 	if (ret || val != def_regs[R00_ID]) {
311ccae7af2SMauro Carvalho Chehab 		kfree(priv);
312ccae7af2SMauro Carvalho Chehab 		return NULL;
313ccae7af2SMauro Carvalho Chehab 	}
314ccae7af2SMauro Carvalho Chehab 
3159edd6987SAntti Palosaari 	dev_info(&priv->i2c->dev,
3169edd6987SAntti Palosaari 			"%s: NXP TDA18218HN successfully identified\n",
3179edd6987SAntti Palosaari 			KBUILD_MODNAME);
318ccae7af2SMauro Carvalho Chehab 
319ccae7af2SMauro Carvalho Chehab 	memcpy(&fe->ops.tuner_ops, &tda18218_tuner_ops,
320ccae7af2SMauro Carvalho Chehab 		sizeof(struct dvb_tuner_ops));
321ccae7af2SMauro Carvalho Chehab 	memcpy(priv->regs, def_regs, sizeof(def_regs));
322ccae7af2SMauro Carvalho Chehab 
323ccae7af2SMauro Carvalho Chehab 	/* loop-through enabled chip default register values */
324ccae7af2SMauro Carvalho Chehab 	if (priv->cfg->loop_through) {
325ccae7af2SMauro Carvalho Chehab 		priv->regs[R17_PD1] = 0xb0;
326ccae7af2SMauro Carvalho Chehab 		priv->regs[R18_PD2] = 0x59;
327ccae7af2SMauro Carvalho Chehab 	}
328ccae7af2SMauro Carvalho Chehab 
329ccae7af2SMauro Carvalho Chehab 	/* standby */
330ccae7af2SMauro Carvalho Chehab 	ret = tda18218_wr_reg(priv, R17_PD1, priv->regs[R17_PD1] | (1 << 0));
331ccae7af2SMauro Carvalho Chehab 	if (ret)
3329edd6987SAntti Palosaari 		dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
333ccae7af2SMauro Carvalho Chehab 
334ccae7af2SMauro Carvalho Chehab 	if (fe->ops.i2c_gate_ctrl)
335ccae7af2SMauro Carvalho Chehab 		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
336ccae7af2SMauro Carvalho Chehab 
337ccae7af2SMauro Carvalho Chehab 	return fe;
338ccae7af2SMauro Carvalho Chehab }
339*86495af1SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(tda18218_attach);
340ccae7af2SMauro Carvalho Chehab 
341ccae7af2SMauro Carvalho Chehab MODULE_DESCRIPTION("NXP TDA18218HN silicon tuner driver");
342ccae7af2SMauro Carvalho Chehab MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
343ccae7af2SMauro Carvalho Chehab MODULE_LICENSE("GPL");
344