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