1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Sharp QM1D1C0042 8PSK tuner driver
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2014 Akihiro Tsukada <tskd08@gmail.com>
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun /*
9*4882a593Smuzhiyun * NOTICE:
10*4882a593Smuzhiyun * As the disclosed information on the chip is very limited,
11*4882a593Smuzhiyun * this driver lacks some features, including chip config like IF freq.
12*4882a593Smuzhiyun * It assumes that users of this driver (such as a PCI bridge of
13*4882a593Smuzhiyun * DTV receiver cards) know the relevant info and
14*4882a593Smuzhiyun * configure the chip via I2C if necessary.
15*4882a593Smuzhiyun *
16*4882a593Smuzhiyun * Currently, PT3 driver is the only one that uses this driver,
17*4882a593Smuzhiyun * and contains init/config code in its firmware.
18*4882a593Smuzhiyun * Thus some part of the code might be dependent on PT3 specific config.
19*4882a593Smuzhiyun */
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun #include <linux/kernel.h>
22*4882a593Smuzhiyun #include <linux/math64.h>
23*4882a593Smuzhiyun #include "qm1d1c0042.h"
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun #define QM1D1C0042_NUM_REGS 0x20
26*4882a593Smuzhiyun #define QM1D1C0042_NUM_REG_ROWS 2
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun static const u8
29*4882a593Smuzhiyun reg_initval[QM1D1C0042_NUM_REG_ROWS][QM1D1C0042_NUM_REGS] = { {
30*4882a593Smuzhiyun 0x48, 0x1c, 0xa0, 0x10, 0xbc, 0xc5, 0x20, 0x33,
31*4882a593Smuzhiyun 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
32*4882a593Smuzhiyun 0x00, 0xff, 0xf3, 0x00, 0x2a, 0x64, 0xa6, 0x86,
33*4882a593Smuzhiyun 0x8c, 0xcf, 0xb8, 0xf1, 0xa8, 0xf2, 0x89, 0x00
34*4882a593Smuzhiyun }, {
35*4882a593Smuzhiyun 0x68, 0x1c, 0xc0, 0x10, 0xbc, 0xc1, 0x11, 0x33,
36*4882a593Smuzhiyun 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
37*4882a593Smuzhiyun 0x00, 0xff, 0xf3, 0x00, 0x3f, 0x25, 0x5c, 0xd6,
38*4882a593Smuzhiyun 0x55, 0xcf, 0x95, 0xf6, 0x36, 0xf2, 0x09, 0x00
39*4882a593Smuzhiyun }
40*4882a593Smuzhiyun };
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun static int reg_index;
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun static const struct qm1d1c0042_config default_cfg = {
45*4882a593Smuzhiyun .xtal_freq = 16000,
46*4882a593Smuzhiyun .lpf = 1,
47*4882a593Smuzhiyun .fast_srch = 0,
48*4882a593Smuzhiyun .lpf_wait = 20,
49*4882a593Smuzhiyun .fast_srch_wait = 4,
50*4882a593Smuzhiyun .normal_srch_wait = 15,
51*4882a593Smuzhiyun };
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun struct qm1d1c0042_state {
54*4882a593Smuzhiyun struct qm1d1c0042_config cfg;
55*4882a593Smuzhiyun struct i2c_client *i2c;
56*4882a593Smuzhiyun u8 regs[QM1D1C0042_NUM_REGS];
57*4882a593Smuzhiyun };
58*4882a593Smuzhiyun
cfg_to_state(struct qm1d1c0042_config * c)59*4882a593Smuzhiyun static struct qm1d1c0042_state *cfg_to_state(struct qm1d1c0042_config *c)
60*4882a593Smuzhiyun {
61*4882a593Smuzhiyun return container_of(c, struct qm1d1c0042_state, cfg);
62*4882a593Smuzhiyun }
63*4882a593Smuzhiyun
reg_write(struct qm1d1c0042_state * state,u8 reg,u8 val)64*4882a593Smuzhiyun static int reg_write(struct qm1d1c0042_state *state, u8 reg, u8 val)
65*4882a593Smuzhiyun {
66*4882a593Smuzhiyun u8 wbuf[2] = { reg, val };
67*4882a593Smuzhiyun int ret;
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun ret = i2c_master_send(state->i2c, wbuf, sizeof(wbuf));
70*4882a593Smuzhiyun if (ret >= 0 && ret < sizeof(wbuf))
71*4882a593Smuzhiyun ret = -EIO;
72*4882a593Smuzhiyun return (ret == sizeof(wbuf)) ? 0 : ret;
73*4882a593Smuzhiyun }
74*4882a593Smuzhiyun
reg_read(struct qm1d1c0042_state * state,u8 reg,u8 * val)75*4882a593Smuzhiyun static int reg_read(struct qm1d1c0042_state *state, u8 reg, u8 *val)
76*4882a593Smuzhiyun {
77*4882a593Smuzhiyun struct i2c_msg msgs[2] = {
78*4882a593Smuzhiyun {
79*4882a593Smuzhiyun .addr = state->i2c->addr,
80*4882a593Smuzhiyun .flags = 0,
81*4882a593Smuzhiyun .buf = ®,
82*4882a593Smuzhiyun .len = 1,
83*4882a593Smuzhiyun },
84*4882a593Smuzhiyun {
85*4882a593Smuzhiyun .addr = state->i2c->addr,
86*4882a593Smuzhiyun .flags = I2C_M_RD,
87*4882a593Smuzhiyun .buf = val,
88*4882a593Smuzhiyun .len = 1,
89*4882a593Smuzhiyun },
90*4882a593Smuzhiyun };
91*4882a593Smuzhiyun int ret;
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun ret = i2c_transfer(state->i2c->adapter, msgs, ARRAY_SIZE(msgs));
94*4882a593Smuzhiyun if (ret >= 0 && ret < ARRAY_SIZE(msgs))
95*4882a593Smuzhiyun ret = -EIO;
96*4882a593Smuzhiyun return (ret == ARRAY_SIZE(msgs)) ? 0 : ret;
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun
qm1d1c0042_set_srch_mode(struct qm1d1c0042_state * state,bool fast)100*4882a593Smuzhiyun static int qm1d1c0042_set_srch_mode(struct qm1d1c0042_state *state, bool fast)
101*4882a593Smuzhiyun {
102*4882a593Smuzhiyun if (fast)
103*4882a593Smuzhiyun state->regs[0x03] |= 0x01; /* set fast search mode */
104*4882a593Smuzhiyun else
105*4882a593Smuzhiyun state->regs[0x03] &= ~0x01 & 0xff;
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun return reg_write(state, 0x03, state->regs[0x03]);
108*4882a593Smuzhiyun }
109*4882a593Smuzhiyun
qm1d1c0042_wakeup(struct qm1d1c0042_state * state)110*4882a593Smuzhiyun static int qm1d1c0042_wakeup(struct qm1d1c0042_state *state)
111*4882a593Smuzhiyun {
112*4882a593Smuzhiyun int ret;
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun state->regs[0x01] |= 1 << 3; /* BB_Reg_enable */
115*4882a593Smuzhiyun state->regs[0x01] &= (~(1 << 0)) & 0xff; /* NORMAL (wake-up) */
116*4882a593Smuzhiyun state->regs[0x05] &= (~(1 << 3)) & 0xff; /* pfd_rst NORMAL */
117*4882a593Smuzhiyun ret = reg_write(state, 0x01, state->regs[0x01]);
118*4882a593Smuzhiyun if (ret == 0)
119*4882a593Smuzhiyun ret = reg_write(state, 0x05, state->regs[0x05]);
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun if (ret < 0)
122*4882a593Smuzhiyun dev_warn(&state->i2c->dev, "(%s) failed. [adap%d-fe%d]\n",
123*4882a593Smuzhiyun __func__, state->cfg.fe->dvb->num, state->cfg.fe->id);
124*4882a593Smuzhiyun return ret;
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun /* tuner_ops */
128*4882a593Smuzhiyun
qm1d1c0042_set_config(struct dvb_frontend * fe,void * priv_cfg)129*4882a593Smuzhiyun static int qm1d1c0042_set_config(struct dvb_frontend *fe, void *priv_cfg)
130*4882a593Smuzhiyun {
131*4882a593Smuzhiyun struct qm1d1c0042_state *state;
132*4882a593Smuzhiyun struct qm1d1c0042_config *cfg;
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun state = fe->tuner_priv;
135*4882a593Smuzhiyun cfg = priv_cfg;
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun if (cfg->fe)
138*4882a593Smuzhiyun state->cfg.fe = cfg->fe;
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun if (cfg->xtal_freq != QM1D1C0042_CFG_XTAL_DFLT)
141*4882a593Smuzhiyun dev_warn(&state->i2c->dev,
142*4882a593Smuzhiyun "(%s) changing xtal_freq not supported. ", __func__);
143*4882a593Smuzhiyun state->cfg.xtal_freq = default_cfg.xtal_freq;
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun state->cfg.lpf = cfg->lpf;
146*4882a593Smuzhiyun state->cfg.fast_srch = cfg->fast_srch;
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun if (cfg->lpf_wait != QM1D1C0042_CFG_WAIT_DFLT)
149*4882a593Smuzhiyun state->cfg.lpf_wait = cfg->lpf_wait;
150*4882a593Smuzhiyun else
151*4882a593Smuzhiyun state->cfg.lpf_wait = default_cfg.lpf_wait;
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun if (cfg->fast_srch_wait != QM1D1C0042_CFG_WAIT_DFLT)
154*4882a593Smuzhiyun state->cfg.fast_srch_wait = cfg->fast_srch_wait;
155*4882a593Smuzhiyun else
156*4882a593Smuzhiyun state->cfg.fast_srch_wait = default_cfg.fast_srch_wait;
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun if (cfg->normal_srch_wait != QM1D1C0042_CFG_WAIT_DFLT)
159*4882a593Smuzhiyun state->cfg.normal_srch_wait = cfg->normal_srch_wait;
160*4882a593Smuzhiyun else
161*4882a593Smuzhiyun state->cfg.normal_srch_wait = default_cfg.normal_srch_wait;
162*4882a593Smuzhiyun return 0;
163*4882a593Smuzhiyun }
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun /* divisor, vco_band parameters */
166*4882a593Smuzhiyun /* {maxfreq, param1(band?), param2(div?) */
167*4882a593Smuzhiyun static const u32 conv_table[9][3] = {
168*4882a593Smuzhiyun { 2151000, 1, 7 },
169*4882a593Smuzhiyun { 1950000, 1, 6 },
170*4882a593Smuzhiyun { 1800000, 1, 5 },
171*4882a593Smuzhiyun { 1600000, 1, 4 },
172*4882a593Smuzhiyun { 1450000, 1, 3 },
173*4882a593Smuzhiyun { 1250000, 1, 2 },
174*4882a593Smuzhiyun { 1200000, 0, 7 },
175*4882a593Smuzhiyun { 975000, 0, 6 },
176*4882a593Smuzhiyun { 950000, 0, 0 }
177*4882a593Smuzhiyun };
178*4882a593Smuzhiyun
qm1d1c0042_set_params(struct dvb_frontend * fe)179*4882a593Smuzhiyun static int qm1d1c0042_set_params(struct dvb_frontend *fe)
180*4882a593Smuzhiyun {
181*4882a593Smuzhiyun struct qm1d1c0042_state *state;
182*4882a593Smuzhiyun u32 freq;
183*4882a593Smuzhiyun int i, ret;
184*4882a593Smuzhiyun u8 val, mask;
185*4882a593Smuzhiyun u32 a, sd;
186*4882a593Smuzhiyun s32 b;
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun state = fe->tuner_priv;
189*4882a593Smuzhiyun freq = fe->dtv_property_cache.frequency;
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun state->regs[0x08] &= 0xf0;
192*4882a593Smuzhiyun state->regs[0x08] |= 0x09;
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun state->regs[0x13] &= 0x9f;
195*4882a593Smuzhiyun state->regs[0x13] |= 0x20;
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun /* div2/vco_band */
198*4882a593Smuzhiyun val = state->regs[0x02] & 0x0f;
199*4882a593Smuzhiyun for (i = 0; i < 8; i++)
200*4882a593Smuzhiyun if (freq < conv_table[i][0] && freq >= conv_table[i + 1][0]) {
201*4882a593Smuzhiyun val |= conv_table[i][1] << 7;
202*4882a593Smuzhiyun val |= conv_table[i][2] << 4;
203*4882a593Smuzhiyun break;
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun ret = reg_write(state, 0x02, val);
206*4882a593Smuzhiyun if (ret < 0)
207*4882a593Smuzhiyun return ret;
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun a = DIV_ROUND_CLOSEST(freq, state->cfg.xtal_freq);
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun state->regs[0x06] &= 0x40;
212*4882a593Smuzhiyun state->regs[0x06] |= (a - 12) / 4;
213*4882a593Smuzhiyun ret = reg_write(state, 0x06, state->regs[0x06]);
214*4882a593Smuzhiyun if (ret < 0)
215*4882a593Smuzhiyun return ret;
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun state->regs[0x07] &= 0xf0;
218*4882a593Smuzhiyun state->regs[0x07] |= (a - 4 * ((a - 12) / 4 + 1) - 5) & 0x0f;
219*4882a593Smuzhiyun ret = reg_write(state, 0x07, state->regs[0x07]);
220*4882a593Smuzhiyun if (ret < 0)
221*4882a593Smuzhiyun return ret;
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun /* LPF */
224*4882a593Smuzhiyun val = state->regs[0x08];
225*4882a593Smuzhiyun if (state->cfg.lpf) {
226*4882a593Smuzhiyun /* LPF_CLK, LPF_FC */
227*4882a593Smuzhiyun val &= 0xf0;
228*4882a593Smuzhiyun val |= 0x02;
229*4882a593Smuzhiyun }
230*4882a593Smuzhiyun ret = reg_write(state, 0x08, val);
231*4882a593Smuzhiyun if (ret < 0)
232*4882a593Smuzhiyun return ret;
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun /*
235*4882a593Smuzhiyun * b = (freq / state->cfg.xtal_freq - a) << 20;
236*4882a593Smuzhiyun * sd = b (b >= 0)
237*4882a593Smuzhiyun * 1<<22 + b (b < 0)
238*4882a593Smuzhiyun */
239*4882a593Smuzhiyun b = (s32)div64_s64(((s64) freq) << 20, state->cfg.xtal_freq)
240*4882a593Smuzhiyun - (((s64) a) << 20);
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun if (b >= 0)
243*4882a593Smuzhiyun sd = b;
244*4882a593Smuzhiyun else
245*4882a593Smuzhiyun sd = (1 << 22) + b;
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun state->regs[0x09] &= 0xc0;
248*4882a593Smuzhiyun state->regs[0x09] |= (sd >> 16) & 0x3f;
249*4882a593Smuzhiyun state->regs[0x0a] = (sd >> 8) & 0xff;
250*4882a593Smuzhiyun state->regs[0x0b] = sd & 0xff;
251*4882a593Smuzhiyun ret = reg_write(state, 0x09, state->regs[0x09]);
252*4882a593Smuzhiyun if (ret == 0)
253*4882a593Smuzhiyun ret = reg_write(state, 0x0a, state->regs[0x0a]);
254*4882a593Smuzhiyun if (ret == 0)
255*4882a593Smuzhiyun ret = reg_write(state, 0x0b, state->regs[0x0b]);
256*4882a593Smuzhiyun if (ret != 0)
257*4882a593Smuzhiyun return ret;
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun if (!state->cfg.lpf) {
260*4882a593Smuzhiyun /* CSEL_Offset */
261*4882a593Smuzhiyun ret = reg_write(state, 0x13, state->regs[0x13]);
262*4882a593Smuzhiyun if (ret < 0)
263*4882a593Smuzhiyun return ret;
264*4882a593Smuzhiyun }
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun /* VCO_TM, LPF_TM */
267*4882a593Smuzhiyun mask = state->cfg.lpf ? 0x3f : 0x7f;
268*4882a593Smuzhiyun val = state->regs[0x0c] & mask;
269*4882a593Smuzhiyun ret = reg_write(state, 0x0c, val);
270*4882a593Smuzhiyun if (ret < 0)
271*4882a593Smuzhiyun return ret;
272*4882a593Smuzhiyun usleep_range(2000, 3000);
273*4882a593Smuzhiyun val = state->regs[0x0c] | ~mask;
274*4882a593Smuzhiyun ret = reg_write(state, 0x0c, val);
275*4882a593Smuzhiyun if (ret < 0)
276*4882a593Smuzhiyun return ret;
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun if (state->cfg.lpf)
279*4882a593Smuzhiyun msleep(state->cfg.lpf_wait);
280*4882a593Smuzhiyun else if (state->regs[0x03] & 0x01)
281*4882a593Smuzhiyun msleep(state->cfg.fast_srch_wait);
282*4882a593Smuzhiyun else
283*4882a593Smuzhiyun msleep(state->cfg.normal_srch_wait);
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun if (state->cfg.lpf) {
286*4882a593Smuzhiyun /* LPF_FC */
287*4882a593Smuzhiyun ret = reg_write(state, 0x08, 0x09);
288*4882a593Smuzhiyun if (ret < 0)
289*4882a593Smuzhiyun return ret;
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun /* CSEL_Offset */
292*4882a593Smuzhiyun ret = reg_write(state, 0x13, state->regs[0x13]);
293*4882a593Smuzhiyun if (ret < 0)
294*4882a593Smuzhiyun return ret;
295*4882a593Smuzhiyun }
296*4882a593Smuzhiyun return 0;
297*4882a593Smuzhiyun }
298*4882a593Smuzhiyun
qm1d1c0042_sleep(struct dvb_frontend * fe)299*4882a593Smuzhiyun static int qm1d1c0042_sleep(struct dvb_frontend *fe)
300*4882a593Smuzhiyun {
301*4882a593Smuzhiyun struct qm1d1c0042_state *state;
302*4882a593Smuzhiyun int ret;
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun state = fe->tuner_priv;
305*4882a593Smuzhiyun state->regs[0x01] &= (~(1 << 3)) & 0xff; /* BB_Reg_disable */
306*4882a593Smuzhiyun state->regs[0x01] |= 1 << 0; /* STDBY */
307*4882a593Smuzhiyun state->regs[0x05] |= 1 << 3; /* pfd_rst STANDBY */
308*4882a593Smuzhiyun ret = reg_write(state, 0x05, state->regs[0x05]);
309*4882a593Smuzhiyun if (ret == 0)
310*4882a593Smuzhiyun ret = reg_write(state, 0x01, state->regs[0x01]);
311*4882a593Smuzhiyun if (ret < 0)
312*4882a593Smuzhiyun dev_warn(&state->i2c->dev, "(%s) failed. [adap%d-fe%d]\n",
313*4882a593Smuzhiyun __func__, fe->dvb->num, fe->id);
314*4882a593Smuzhiyun return ret;
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun
qm1d1c0042_init(struct dvb_frontend * fe)317*4882a593Smuzhiyun static int qm1d1c0042_init(struct dvb_frontend *fe)
318*4882a593Smuzhiyun {
319*4882a593Smuzhiyun struct qm1d1c0042_state *state;
320*4882a593Smuzhiyun u8 val;
321*4882a593Smuzhiyun int i, ret;
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun state = fe->tuner_priv;
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun reg_write(state, 0x01, 0x0c);
326*4882a593Smuzhiyun reg_write(state, 0x01, 0x0c);
327*4882a593Smuzhiyun
328*4882a593Smuzhiyun ret = reg_write(state, 0x01, 0x0c); /* soft reset on */
329*4882a593Smuzhiyun if (ret < 0)
330*4882a593Smuzhiyun goto failed;
331*4882a593Smuzhiyun usleep_range(2000, 3000);
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun ret = reg_write(state, 0x01, 0x1c); /* soft reset off */
334*4882a593Smuzhiyun if (ret < 0)
335*4882a593Smuzhiyun goto failed;
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun /* check ID and choose initial registers corresponding ID */
338*4882a593Smuzhiyun ret = reg_read(state, 0x00, &val);
339*4882a593Smuzhiyun if (ret < 0)
340*4882a593Smuzhiyun goto failed;
341*4882a593Smuzhiyun for (reg_index = 0; reg_index < QM1D1C0042_NUM_REG_ROWS;
342*4882a593Smuzhiyun reg_index++) {
343*4882a593Smuzhiyun if (val == reg_initval[reg_index][0x00])
344*4882a593Smuzhiyun break;
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun if (reg_index >= QM1D1C0042_NUM_REG_ROWS) {
347*4882a593Smuzhiyun ret = -EINVAL;
348*4882a593Smuzhiyun goto failed;
349*4882a593Smuzhiyun }
350*4882a593Smuzhiyun memcpy(state->regs, reg_initval[reg_index], QM1D1C0042_NUM_REGS);
351*4882a593Smuzhiyun usleep_range(2000, 3000);
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun state->regs[0x0c] |= 0x40;
354*4882a593Smuzhiyun ret = reg_write(state, 0x0c, state->regs[0x0c]);
355*4882a593Smuzhiyun if (ret < 0)
356*4882a593Smuzhiyun goto failed;
357*4882a593Smuzhiyun msleep(state->cfg.lpf_wait);
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun /* set all writable registers */
360*4882a593Smuzhiyun for (i = 1; i <= 0x0c ; i++) {
361*4882a593Smuzhiyun ret = reg_write(state, i, state->regs[i]);
362*4882a593Smuzhiyun if (ret < 0)
363*4882a593Smuzhiyun goto failed;
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun for (i = 0x11; i < QM1D1C0042_NUM_REGS; i++) {
366*4882a593Smuzhiyun ret = reg_write(state, i, state->regs[i]);
367*4882a593Smuzhiyun if (ret < 0)
368*4882a593Smuzhiyun goto failed;
369*4882a593Smuzhiyun }
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun ret = qm1d1c0042_wakeup(state);
372*4882a593Smuzhiyun if (ret < 0)
373*4882a593Smuzhiyun goto failed;
374*4882a593Smuzhiyun
375*4882a593Smuzhiyun ret = qm1d1c0042_set_srch_mode(state, state->cfg.fast_srch);
376*4882a593Smuzhiyun if (ret < 0)
377*4882a593Smuzhiyun goto failed;
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun return ret;
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun failed:
382*4882a593Smuzhiyun dev_warn(&state->i2c->dev, "(%s) failed. [adap%d-fe%d]\n",
383*4882a593Smuzhiyun __func__, fe->dvb->num, fe->id);
384*4882a593Smuzhiyun return ret;
385*4882a593Smuzhiyun }
386*4882a593Smuzhiyun
387*4882a593Smuzhiyun /* I2C driver functions */
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun static const struct dvb_tuner_ops qm1d1c0042_ops = {
390*4882a593Smuzhiyun .info = {
391*4882a593Smuzhiyun .name = "Sharp QM1D1C0042",
392*4882a593Smuzhiyun
393*4882a593Smuzhiyun .frequency_min_hz = 950 * MHz,
394*4882a593Smuzhiyun .frequency_max_hz = 2150 * MHz,
395*4882a593Smuzhiyun },
396*4882a593Smuzhiyun
397*4882a593Smuzhiyun .init = qm1d1c0042_init,
398*4882a593Smuzhiyun .sleep = qm1d1c0042_sleep,
399*4882a593Smuzhiyun .set_config = qm1d1c0042_set_config,
400*4882a593Smuzhiyun .set_params = qm1d1c0042_set_params,
401*4882a593Smuzhiyun };
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun
qm1d1c0042_probe(struct i2c_client * client,const struct i2c_device_id * id)404*4882a593Smuzhiyun static int qm1d1c0042_probe(struct i2c_client *client,
405*4882a593Smuzhiyun const struct i2c_device_id *id)
406*4882a593Smuzhiyun {
407*4882a593Smuzhiyun struct qm1d1c0042_state *state;
408*4882a593Smuzhiyun struct qm1d1c0042_config *cfg;
409*4882a593Smuzhiyun struct dvb_frontend *fe;
410*4882a593Smuzhiyun
411*4882a593Smuzhiyun state = kzalloc(sizeof(*state), GFP_KERNEL);
412*4882a593Smuzhiyun if (!state)
413*4882a593Smuzhiyun return -ENOMEM;
414*4882a593Smuzhiyun state->i2c = client;
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun cfg = client->dev.platform_data;
417*4882a593Smuzhiyun fe = cfg->fe;
418*4882a593Smuzhiyun fe->tuner_priv = state;
419*4882a593Smuzhiyun qm1d1c0042_set_config(fe, cfg);
420*4882a593Smuzhiyun memcpy(&fe->ops.tuner_ops, &qm1d1c0042_ops, sizeof(qm1d1c0042_ops));
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun i2c_set_clientdata(client, &state->cfg);
423*4882a593Smuzhiyun dev_info(&client->dev, "Sharp QM1D1C0042 attached.\n");
424*4882a593Smuzhiyun return 0;
425*4882a593Smuzhiyun }
426*4882a593Smuzhiyun
qm1d1c0042_remove(struct i2c_client * client)427*4882a593Smuzhiyun static int qm1d1c0042_remove(struct i2c_client *client)
428*4882a593Smuzhiyun {
429*4882a593Smuzhiyun struct qm1d1c0042_state *state;
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun state = cfg_to_state(i2c_get_clientdata(client));
432*4882a593Smuzhiyun state->cfg.fe->tuner_priv = NULL;
433*4882a593Smuzhiyun kfree(state);
434*4882a593Smuzhiyun return 0;
435*4882a593Smuzhiyun }
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun static const struct i2c_device_id qm1d1c0042_id[] = {
439*4882a593Smuzhiyun {"qm1d1c0042", 0},
440*4882a593Smuzhiyun {}
441*4882a593Smuzhiyun };
442*4882a593Smuzhiyun MODULE_DEVICE_TABLE(i2c, qm1d1c0042_id);
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun static struct i2c_driver qm1d1c0042_driver = {
445*4882a593Smuzhiyun .driver = {
446*4882a593Smuzhiyun .name = "qm1d1c0042",
447*4882a593Smuzhiyun },
448*4882a593Smuzhiyun .probe = qm1d1c0042_probe,
449*4882a593Smuzhiyun .remove = qm1d1c0042_remove,
450*4882a593Smuzhiyun .id_table = qm1d1c0042_id,
451*4882a593Smuzhiyun };
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun module_i2c_driver(qm1d1c0042_driver);
454*4882a593Smuzhiyun
455*4882a593Smuzhiyun MODULE_DESCRIPTION("Sharp QM1D1C0042 tuner");
456*4882a593Smuzhiyun MODULE_AUTHOR("Akihiro TSUKADA");
457*4882a593Smuzhiyun MODULE_LICENSE("GPL");
458