xref: /OK3568_Linux_fs/kernel/drivers/media/dvb-frontends/si2168.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Silicon Labs Si2168 DVB-T/T2/C demodulator driver
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2014 Antti Palosaari <crope@iki.fi>
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <linux/delay.h>
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include "si2168_priv.h"
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun static const struct dvb_frontend_ops si2168_ops;
13*4882a593Smuzhiyun 
cmd_init(struct si2168_cmd * cmd,const u8 * buf,int wlen,int rlen)14*4882a593Smuzhiyun static void cmd_init(struct si2168_cmd *cmd, const u8 *buf, int wlen, int rlen)
15*4882a593Smuzhiyun {
16*4882a593Smuzhiyun 	memcpy(cmd->args, buf, wlen);
17*4882a593Smuzhiyun 	cmd->wlen = wlen;
18*4882a593Smuzhiyun 	cmd->rlen = rlen;
19*4882a593Smuzhiyun }
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun /* execute firmware command */
si2168_cmd_execute(struct i2c_client * client,struct si2168_cmd * cmd)22*4882a593Smuzhiyun static int si2168_cmd_execute(struct i2c_client *client, struct si2168_cmd *cmd)
23*4882a593Smuzhiyun {
24*4882a593Smuzhiyun 	struct si2168_dev *dev = i2c_get_clientdata(client);
25*4882a593Smuzhiyun 	int ret;
26*4882a593Smuzhiyun 	unsigned long timeout;
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun 	mutex_lock(&dev->i2c_mutex);
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun 	if (cmd->wlen) {
31*4882a593Smuzhiyun 		/* write cmd and args for firmware */
32*4882a593Smuzhiyun 		ret = i2c_master_send(client, cmd->args, cmd->wlen);
33*4882a593Smuzhiyun 		if (ret < 0) {
34*4882a593Smuzhiyun 			goto err_mutex_unlock;
35*4882a593Smuzhiyun 		} else if (ret != cmd->wlen) {
36*4882a593Smuzhiyun 			ret = -EREMOTEIO;
37*4882a593Smuzhiyun 			goto err_mutex_unlock;
38*4882a593Smuzhiyun 		}
39*4882a593Smuzhiyun 	}
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun 	if (cmd->rlen) {
42*4882a593Smuzhiyun 		/* wait cmd execution terminate */
43*4882a593Smuzhiyun 		#define TIMEOUT 70
44*4882a593Smuzhiyun 		timeout = jiffies + msecs_to_jiffies(TIMEOUT);
45*4882a593Smuzhiyun 		while (!time_after(jiffies, timeout)) {
46*4882a593Smuzhiyun 			ret = i2c_master_recv(client, cmd->args, cmd->rlen);
47*4882a593Smuzhiyun 			if (ret < 0) {
48*4882a593Smuzhiyun 				goto err_mutex_unlock;
49*4882a593Smuzhiyun 			} else if (ret != cmd->rlen) {
50*4882a593Smuzhiyun 				ret = -EREMOTEIO;
51*4882a593Smuzhiyun 				goto err_mutex_unlock;
52*4882a593Smuzhiyun 			}
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun 			/* firmware ready? */
55*4882a593Smuzhiyun 			if ((cmd->args[0] >> 7) & 0x01)
56*4882a593Smuzhiyun 				break;
57*4882a593Smuzhiyun 		}
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun 		dev_dbg(&client->dev, "cmd execution took %d ms\n",
60*4882a593Smuzhiyun 				jiffies_to_msecs(jiffies) -
61*4882a593Smuzhiyun 				(jiffies_to_msecs(timeout) - TIMEOUT));
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun 		/* error bit set? */
64*4882a593Smuzhiyun 		if ((cmd->args[0] >> 6) & 0x01) {
65*4882a593Smuzhiyun 			ret = -EREMOTEIO;
66*4882a593Smuzhiyun 			goto err_mutex_unlock;
67*4882a593Smuzhiyun 		}
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 		if (!((cmd->args[0] >> 7) & 0x01)) {
70*4882a593Smuzhiyun 			ret = -ETIMEDOUT;
71*4882a593Smuzhiyun 			goto err_mutex_unlock;
72*4882a593Smuzhiyun 		}
73*4882a593Smuzhiyun 	}
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun 	mutex_unlock(&dev->i2c_mutex);
76*4882a593Smuzhiyun 	return 0;
77*4882a593Smuzhiyun err_mutex_unlock:
78*4882a593Smuzhiyun 	mutex_unlock(&dev->i2c_mutex);
79*4882a593Smuzhiyun 	dev_dbg(&client->dev, "failed=%d\n", ret);
80*4882a593Smuzhiyun 	return ret;
81*4882a593Smuzhiyun }
82*4882a593Smuzhiyun 
si2168_ts_bus_ctrl(struct dvb_frontend * fe,int acquire)83*4882a593Smuzhiyun static int si2168_ts_bus_ctrl(struct dvb_frontend *fe, int acquire)
84*4882a593Smuzhiyun {
85*4882a593Smuzhiyun 	struct i2c_client *client = fe->demodulator_priv;
86*4882a593Smuzhiyun 	struct si2168_dev *dev = i2c_get_clientdata(client);
87*4882a593Smuzhiyun 	struct si2168_cmd cmd;
88*4882a593Smuzhiyun 	int ret = 0;
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	dev_dbg(&client->dev, "%s acquire: %d\n", __func__, acquire);
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun 	/* set manual value */
93*4882a593Smuzhiyun 	if (dev->ts_mode & SI2168_TS_CLK_MANUAL) {
94*4882a593Smuzhiyun 		cmd_init(&cmd, "\x14\x00\x0d\x10\xe8\x03", 6, 4);
95*4882a593Smuzhiyun 		ret = si2168_cmd_execute(client, &cmd);
96*4882a593Smuzhiyun 		if (ret)
97*4882a593Smuzhiyun 			return ret;
98*4882a593Smuzhiyun 	}
99*4882a593Smuzhiyun 	/* set TS_MODE property */
100*4882a593Smuzhiyun 	cmd_init(&cmd, "\x14\x00\x01\x10\x10\x00", 6, 4);
101*4882a593Smuzhiyun 	if (dev->ts_mode & SI2168_TS_CLK_MANUAL)
102*4882a593Smuzhiyun 		cmd.args[4] = SI2168_TS_CLK_MANUAL;
103*4882a593Smuzhiyun 	if (acquire)
104*4882a593Smuzhiyun 		cmd.args[4] |= dev->ts_mode;
105*4882a593Smuzhiyun 	else
106*4882a593Smuzhiyun 		cmd.args[4] |= SI2168_TS_TRISTATE;
107*4882a593Smuzhiyun 	if (dev->ts_clock_gapped)
108*4882a593Smuzhiyun 		cmd.args[4] |= 0x40;
109*4882a593Smuzhiyun 	ret = si2168_cmd_execute(client, &cmd);
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	return ret;
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun 
si2168_read_status(struct dvb_frontend * fe,enum fe_status * status)114*4882a593Smuzhiyun static int si2168_read_status(struct dvb_frontend *fe, enum fe_status *status)
115*4882a593Smuzhiyun {
116*4882a593Smuzhiyun 	struct i2c_client *client = fe->demodulator_priv;
117*4882a593Smuzhiyun 	struct si2168_dev *dev = i2c_get_clientdata(client);
118*4882a593Smuzhiyun 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
119*4882a593Smuzhiyun 	int ret, i;
120*4882a593Smuzhiyun 	unsigned int utmp, utmp1, utmp2;
121*4882a593Smuzhiyun 	struct si2168_cmd cmd;
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 	*status = 0;
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 	if (!dev->active) {
126*4882a593Smuzhiyun 		ret = -EAGAIN;
127*4882a593Smuzhiyun 		goto err;
128*4882a593Smuzhiyun 	}
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	switch (c->delivery_system) {
131*4882a593Smuzhiyun 	case SYS_DVBT:
132*4882a593Smuzhiyun 		cmd_init(&cmd, "\xa0\x01", 2, 13);
133*4882a593Smuzhiyun 		break;
134*4882a593Smuzhiyun 	case SYS_DVBC_ANNEX_A:
135*4882a593Smuzhiyun 		cmd_init(&cmd, "\x90\x01", 2, 9);
136*4882a593Smuzhiyun 		break;
137*4882a593Smuzhiyun 	case SYS_DVBT2:
138*4882a593Smuzhiyun 		cmd_init(&cmd, "\x50\x01", 2, 14);
139*4882a593Smuzhiyun 		break;
140*4882a593Smuzhiyun 	default:
141*4882a593Smuzhiyun 		ret = -EINVAL;
142*4882a593Smuzhiyun 		goto err;
143*4882a593Smuzhiyun 	}
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	ret = si2168_cmd_execute(client, &cmd);
146*4882a593Smuzhiyun 	if (ret)
147*4882a593Smuzhiyun 		goto err;
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	switch ((cmd.args[2] >> 1) & 0x03) {
150*4882a593Smuzhiyun 	case 0x01:
151*4882a593Smuzhiyun 		*status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
152*4882a593Smuzhiyun 		break;
153*4882a593Smuzhiyun 	case 0x03:
154*4882a593Smuzhiyun 		*status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI |
155*4882a593Smuzhiyun 				FE_HAS_SYNC | FE_HAS_LOCK;
156*4882a593Smuzhiyun 		break;
157*4882a593Smuzhiyun 	}
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	dev->fe_status = *status;
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 	if (*status & FE_HAS_LOCK) {
162*4882a593Smuzhiyun 		c->cnr.len = 1;
163*4882a593Smuzhiyun 		c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
164*4882a593Smuzhiyun 		c->cnr.stat[0].svalue = cmd.args[3] * 1000 / 4;
165*4882a593Smuzhiyun 	} else {
166*4882a593Smuzhiyun 		c->cnr.len = 1;
167*4882a593Smuzhiyun 		c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
168*4882a593Smuzhiyun 	}
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	dev_dbg(&client->dev, "status=%02x args=%*ph\n",
171*4882a593Smuzhiyun 			*status, cmd.rlen, cmd.args);
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 	/* BER */
174*4882a593Smuzhiyun 	if (*status & FE_HAS_VITERBI) {
175*4882a593Smuzhiyun 		cmd_init(&cmd, "\x82\x00", 2, 3);
176*4882a593Smuzhiyun 		ret = si2168_cmd_execute(client, &cmd);
177*4882a593Smuzhiyun 		if (ret)
178*4882a593Smuzhiyun 			goto err;
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 		/*
181*4882a593Smuzhiyun 		 * Firmware returns [0, 255] mantissa and [0, 8] exponent.
182*4882a593Smuzhiyun 		 * Convert to DVB API: mantissa * 10^(8 - exponent) / 10^8
183*4882a593Smuzhiyun 		 */
184*4882a593Smuzhiyun 		utmp = clamp(8 - cmd.args[1], 0, 8);
185*4882a593Smuzhiyun 		for (i = 0, utmp1 = 1; i < utmp; i++)
186*4882a593Smuzhiyun 			utmp1 = utmp1 * 10;
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 		utmp1 = cmd.args[2] * utmp1;
189*4882a593Smuzhiyun 		utmp2 = 100000000; /* 10^8 */
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 		dev_dbg(&client->dev,
192*4882a593Smuzhiyun 			"post_bit_error=%u post_bit_count=%u ber=%u*10^-%u\n",
193*4882a593Smuzhiyun 			utmp1, utmp2, cmd.args[2], cmd.args[1]);
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 		c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
196*4882a593Smuzhiyun 		c->post_bit_error.stat[0].uvalue += utmp1;
197*4882a593Smuzhiyun 		c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
198*4882a593Smuzhiyun 		c->post_bit_count.stat[0].uvalue += utmp2;
199*4882a593Smuzhiyun 	} else {
200*4882a593Smuzhiyun 		c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
201*4882a593Smuzhiyun 		c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
202*4882a593Smuzhiyun 	}
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 	/* UCB */
205*4882a593Smuzhiyun 	if (*status & FE_HAS_SYNC) {
206*4882a593Smuzhiyun 		cmd_init(&cmd, "\x84\x01", 2, 3);
207*4882a593Smuzhiyun 		ret = si2168_cmd_execute(client, &cmd);
208*4882a593Smuzhiyun 		if (ret)
209*4882a593Smuzhiyun 			goto err;
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 		utmp1 = cmd.args[2] << 8 | cmd.args[1] << 0;
212*4882a593Smuzhiyun 		dev_dbg(&client->dev, "block_error=%u\n", utmp1);
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun 		/* Sometimes firmware returns bogus value */
215*4882a593Smuzhiyun 		if (utmp1 == 0xffff)
216*4882a593Smuzhiyun 			utmp1 = 0;
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 		c->block_error.stat[0].scale = FE_SCALE_COUNTER;
219*4882a593Smuzhiyun 		c->block_error.stat[0].uvalue += utmp1;
220*4882a593Smuzhiyun 	} else {
221*4882a593Smuzhiyun 		c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
222*4882a593Smuzhiyun 	}
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun 	return 0;
225*4882a593Smuzhiyun err:
226*4882a593Smuzhiyun 	dev_dbg(&client->dev, "failed=%d\n", ret);
227*4882a593Smuzhiyun 	return ret;
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun 
si2168_set_frontend(struct dvb_frontend * fe)230*4882a593Smuzhiyun static int si2168_set_frontend(struct dvb_frontend *fe)
231*4882a593Smuzhiyun {
232*4882a593Smuzhiyun 	struct i2c_client *client = fe->demodulator_priv;
233*4882a593Smuzhiyun 	struct si2168_dev *dev = i2c_get_clientdata(client);
234*4882a593Smuzhiyun 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
235*4882a593Smuzhiyun 	int ret;
236*4882a593Smuzhiyun 	struct si2168_cmd cmd;
237*4882a593Smuzhiyun 	u8 bandwidth, delivery_system;
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	dev_dbg(&client->dev,
240*4882a593Smuzhiyun 			"delivery_system=%u modulation=%u frequency=%u bandwidth_hz=%u symbol_rate=%u inversion=%u stream_id=%u\n",
241*4882a593Smuzhiyun 			c->delivery_system, c->modulation, c->frequency,
242*4882a593Smuzhiyun 			c->bandwidth_hz, c->symbol_rate, c->inversion,
243*4882a593Smuzhiyun 			c->stream_id);
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	if (!dev->active) {
246*4882a593Smuzhiyun 		ret = -EAGAIN;
247*4882a593Smuzhiyun 		goto err;
248*4882a593Smuzhiyun 	}
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun 	switch (c->delivery_system) {
251*4882a593Smuzhiyun 	case SYS_DVBT:
252*4882a593Smuzhiyun 		delivery_system = 0x20;
253*4882a593Smuzhiyun 		break;
254*4882a593Smuzhiyun 	case SYS_DVBC_ANNEX_A:
255*4882a593Smuzhiyun 		delivery_system = 0x30;
256*4882a593Smuzhiyun 		break;
257*4882a593Smuzhiyun 	case SYS_DVBT2:
258*4882a593Smuzhiyun 		delivery_system = 0x70;
259*4882a593Smuzhiyun 		break;
260*4882a593Smuzhiyun 	default:
261*4882a593Smuzhiyun 		ret = -EINVAL;
262*4882a593Smuzhiyun 		goto err;
263*4882a593Smuzhiyun 	}
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	if (c->bandwidth_hz == 0) {
266*4882a593Smuzhiyun 		ret = -EINVAL;
267*4882a593Smuzhiyun 		goto err;
268*4882a593Smuzhiyun 	} else if (c->bandwidth_hz <= 2000000)
269*4882a593Smuzhiyun 		bandwidth = 0x02;
270*4882a593Smuzhiyun 	else if (c->bandwidth_hz <= 5000000)
271*4882a593Smuzhiyun 		bandwidth = 0x05;
272*4882a593Smuzhiyun 	else if (c->bandwidth_hz <= 6000000)
273*4882a593Smuzhiyun 		bandwidth = 0x06;
274*4882a593Smuzhiyun 	else if (c->bandwidth_hz <= 7000000)
275*4882a593Smuzhiyun 		bandwidth = 0x07;
276*4882a593Smuzhiyun 	else if (c->bandwidth_hz <= 8000000)
277*4882a593Smuzhiyun 		bandwidth = 0x08;
278*4882a593Smuzhiyun 	else if (c->bandwidth_hz <= 9000000)
279*4882a593Smuzhiyun 		bandwidth = 0x09;
280*4882a593Smuzhiyun 	else if (c->bandwidth_hz <= 10000000)
281*4882a593Smuzhiyun 		bandwidth = 0x0a;
282*4882a593Smuzhiyun 	else
283*4882a593Smuzhiyun 		bandwidth = 0x0f;
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun 	/* program tuner */
286*4882a593Smuzhiyun 	if (fe->ops.tuner_ops.set_params) {
287*4882a593Smuzhiyun 		ret = fe->ops.tuner_ops.set_params(fe);
288*4882a593Smuzhiyun 		if (ret)
289*4882a593Smuzhiyun 			goto err;
290*4882a593Smuzhiyun 	}
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun 	cmd_init(&cmd, "\x88\x02\x02\x02\x02", 5, 5);
293*4882a593Smuzhiyun 	ret = si2168_cmd_execute(client, &cmd);
294*4882a593Smuzhiyun 	if (ret)
295*4882a593Smuzhiyun 		goto err;
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 	/* that has no big effect */
298*4882a593Smuzhiyun 	if (c->delivery_system == SYS_DVBT)
299*4882a593Smuzhiyun 		cmd_init(&cmd, "\x89\x21\x06\x11\xff\x98", 6, 3);
300*4882a593Smuzhiyun 	else if (c->delivery_system == SYS_DVBC_ANNEX_A)
301*4882a593Smuzhiyun 		cmd_init(&cmd, "\x89\x21\x06\x11\x89\xf0", 6, 3);
302*4882a593Smuzhiyun 	else if (c->delivery_system == SYS_DVBT2)
303*4882a593Smuzhiyun 		cmd_init(&cmd, "\x89\x21\x06\x11\x89\x20", 6, 3);
304*4882a593Smuzhiyun 	ret = si2168_cmd_execute(client, &cmd);
305*4882a593Smuzhiyun 	if (ret)
306*4882a593Smuzhiyun 		goto err;
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	if (c->delivery_system == SYS_DVBT2) {
309*4882a593Smuzhiyun 		/* select PLP */
310*4882a593Smuzhiyun 		cmd.args[0] = 0x52;
311*4882a593Smuzhiyun 		cmd.args[1] = c->stream_id & 0xff;
312*4882a593Smuzhiyun 		cmd.args[2] = c->stream_id == NO_STREAM_ID_FILTER ? 0 : 1;
313*4882a593Smuzhiyun 		cmd.wlen = 3;
314*4882a593Smuzhiyun 		cmd.rlen = 1;
315*4882a593Smuzhiyun 		ret = si2168_cmd_execute(client, &cmd);
316*4882a593Smuzhiyun 		if (ret)
317*4882a593Smuzhiyun 			goto err;
318*4882a593Smuzhiyun 	}
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	cmd_init(&cmd, "\x51\x03", 2, 12);
321*4882a593Smuzhiyun 	ret = si2168_cmd_execute(client, &cmd);
322*4882a593Smuzhiyun 	if (ret)
323*4882a593Smuzhiyun 		goto err;
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun 	cmd_init(&cmd, "\x12\x08\x04", 3, 3);
326*4882a593Smuzhiyun 	ret = si2168_cmd_execute(client, &cmd);
327*4882a593Smuzhiyun 	if (ret)
328*4882a593Smuzhiyun 		goto err;
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	cmd_init(&cmd, "\x14\x00\x0c\x10\x12\x00", 6, 4);
331*4882a593Smuzhiyun 	ret = si2168_cmd_execute(client, &cmd);
332*4882a593Smuzhiyun 	if (ret)
333*4882a593Smuzhiyun 		goto err;
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	cmd_init(&cmd, "\x14\x00\x06\x10\x24\x00", 6, 4);
336*4882a593Smuzhiyun 	ret = si2168_cmd_execute(client, &cmd);
337*4882a593Smuzhiyun 	if (ret)
338*4882a593Smuzhiyun 		goto err;
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun 	cmd_init(&cmd, "\x14\x00\x07\x10\x00\x24", 6, 4);
341*4882a593Smuzhiyun 	ret = si2168_cmd_execute(client, &cmd);
342*4882a593Smuzhiyun 	if (ret)
343*4882a593Smuzhiyun 		goto err;
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun 	cmd_init(&cmd, "\x14\x00\x0a\x10\x00\x00", 6, 4);
346*4882a593Smuzhiyun 	cmd.args[4] = delivery_system | bandwidth;
347*4882a593Smuzhiyun 	if (dev->spectral_inversion)
348*4882a593Smuzhiyun 		cmd.args[5] |= 1;
349*4882a593Smuzhiyun 	ret = si2168_cmd_execute(client, &cmd);
350*4882a593Smuzhiyun 	if (ret)
351*4882a593Smuzhiyun 		goto err;
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 	/* set DVB-C symbol rate */
354*4882a593Smuzhiyun 	if (c->delivery_system == SYS_DVBC_ANNEX_A) {
355*4882a593Smuzhiyun 		cmd_init(&cmd, "\x14\x00\x02\x11\x00\x00", 6, 4);
356*4882a593Smuzhiyun 		cmd.args[4] = ((c->symbol_rate / 1000) >> 0) & 0xff;
357*4882a593Smuzhiyun 		cmd.args[5] = ((c->symbol_rate / 1000) >> 8) & 0xff;
358*4882a593Smuzhiyun 		ret = si2168_cmd_execute(client, &cmd);
359*4882a593Smuzhiyun 		if (ret)
360*4882a593Smuzhiyun 			goto err;
361*4882a593Smuzhiyun 	}
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun 	cmd_init(&cmd, "\x14\x00\x0f\x10\x10\x00", 6, 4);
364*4882a593Smuzhiyun 	ret = si2168_cmd_execute(client, &cmd);
365*4882a593Smuzhiyun 	if (ret)
366*4882a593Smuzhiyun 		goto err;
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun 	cmd_init(&cmd, "\x14\x00\x09\x10\xe3\x08", 6, 4);
369*4882a593Smuzhiyun 	cmd.args[5] |= dev->ts_clock_inv ? 0x00 : 0x10;
370*4882a593Smuzhiyun 	ret = si2168_cmd_execute(client, &cmd);
371*4882a593Smuzhiyun 	if (ret)
372*4882a593Smuzhiyun 		goto err;
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 	cmd_init(&cmd, "\x14\x00\x08\x10\xd7\x05", 6, 4);
375*4882a593Smuzhiyun 	cmd.args[5] |= dev->ts_clock_inv ? 0x00 : 0x10;
376*4882a593Smuzhiyun 	ret = si2168_cmd_execute(client, &cmd);
377*4882a593Smuzhiyun 	if (ret)
378*4882a593Smuzhiyun 		goto err;
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun 	cmd_init(&cmd, "\x14\x00\x01\x12\x00\x00", 6, 4);
381*4882a593Smuzhiyun 	ret = si2168_cmd_execute(client, &cmd);
382*4882a593Smuzhiyun 	if (ret)
383*4882a593Smuzhiyun 		goto err;
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun 	cmd_init(&cmd, "\x14\x00\x01\x03\x0c\x00", 6, 4);
386*4882a593Smuzhiyun 	ret = si2168_cmd_execute(client, &cmd);
387*4882a593Smuzhiyun 	if (ret)
388*4882a593Smuzhiyun 		goto err;
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun 	cmd_init(&cmd, "\x85", 1, 1);
391*4882a593Smuzhiyun 	ret = si2168_cmd_execute(client, &cmd);
392*4882a593Smuzhiyun 	if (ret)
393*4882a593Smuzhiyun 		goto err;
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 	dev->delivery_system = c->delivery_system;
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun 	/* enable ts bus */
398*4882a593Smuzhiyun 	ret = si2168_ts_bus_ctrl(fe, 1);
399*4882a593Smuzhiyun 	if (ret)
400*4882a593Smuzhiyun 		goto err;
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun 	return 0;
403*4882a593Smuzhiyun err:
404*4882a593Smuzhiyun 	dev_dbg(&client->dev, "failed=%d\n", ret);
405*4882a593Smuzhiyun 	return ret;
406*4882a593Smuzhiyun }
407*4882a593Smuzhiyun 
si2168_init(struct dvb_frontend * fe)408*4882a593Smuzhiyun static int si2168_init(struct dvb_frontend *fe)
409*4882a593Smuzhiyun {
410*4882a593Smuzhiyun 	struct i2c_client *client = fe->demodulator_priv;
411*4882a593Smuzhiyun 	struct si2168_dev *dev = i2c_get_clientdata(client);
412*4882a593Smuzhiyun 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
413*4882a593Smuzhiyun 	int ret, len, remaining;
414*4882a593Smuzhiyun 	const struct firmware *fw;
415*4882a593Smuzhiyun 	struct si2168_cmd cmd;
416*4882a593Smuzhiyun 
417*4882a593Smuzhiyun 	dev_dbg(&client->dev, "\n");
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun 	/* initialize */
420*4882a593Smuzhiyun 	cmd_init(&cmd, "\xc0\x12\x00\x0c\x00\x0d\x16\x00\x00\x00\x00\x00\x00",
421*4882a593Smuzhiyun 		 13, 0);
422*4882a593Smuzhiyun 	ret = si2168_cmd_execute(client, &cmd);
423*4882a593Smuzhiyun 	if (ret)
424*4882a593Smuzhiyun 		goto err;
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun 	if (dev->warm) {
427*4882a593Smuzhiyun 		/* resume */
428*4882a593Smuzhiyun 		cmd_init(&cmd, "\xc0\x06\x08\x0f\x00\x20\x21\x01", 8, 1);
429*4882a593Smuzhiyun 		ret = si2168_cmd_execute(client, &cmd);
430*4882a593Smuzhiyun 		if (ret)
431*4882a593Smuzhiyun 			goto err;
432*4882a593Smuzhiyun 
433*4882a593Smuzhiyun 		udelay(100);
434*4882a593Smuzhiyun 		cmd_init(&cmd, "\x85", 1, 1);
435*4882a593Smuzhiyun 		ret = si2168_cmd_execute(client, &cmd);
436*4882a593Smuzhiyun 		if (ret)
437*4882a593Smuzhiyun 			goto err;
438*4882a593Smuzhiyun 
439*4882a593Smuzhiyun 		goto warm;
440*4882a593Smuzhiyun 	}
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun 	/* power up */
443*4882a593Smuzhiyun 	cmd_init(&cmd, "\xc0\x06\x01\x0f\x00\x20\x20\x01", 8, 1);
444*4882a593Smuzhiyun 	ret = si2168_cmd_execute(client, &cmd);
445*4882a593Smuzhiyun 	if (ret)
446*4882a593Smuzhiyun 		goto err;
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun 	/* request the firmware, this will block and timeout */
449*4882a593Smuzhiyun 	ret = request_firmware(&fw, dev->firmware_name, &client->dev);
450*4882a593Smuzhiyun 	if (ret) {
451*4882a593Smuzhiyun 		/* fallback mechanism to handle old name for Si2168 B40 fw */
452*4882a593Smuzhiyun 		if (dev->chip_id == SI2168_CHIP_ID_B40) {
453*4882a593Smuzhiyun 			dev->firmware_name = SI2168_B40_FIRMWARE_FALLBACK;
454*4882a593Smuzhiyun 			ret = request_firmware(&fw, dev->firmware_name,
455*4882a593Smuzhiyun 					       &client->dev);
456*4882a593Smuzhiyun 		}
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun 		if (ret == 0) {
459*4882a593Smuzhiyun 			dev_notice(&client->dev,
460*4882a593Smuzhiyun 					"please install firmware file '%s'\n",
461*4882a593Smuzhiyun 					SI2168_B40_FIRMWARE);
462*4882a593Smuzhiyun 		} else {
463*4882a593Smuzhiyun 			dev_err(&client->dev,
464*4882a593Smuzhiyun 					"firmware file '%s' not found\n",
465*4882a593Smuzhiyun 					dev->firmware_name);
466*4882a593Smuzhiyun 			goto err_release_firmware;
467*4882a593Smuzhiyun 		}
468*4882a593Smuzhiyun 	}
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun 	dev_info(&client->dev, "downloading firmware from file '%s'\n",
471*4882a593Smuzhiyun 			dev->firmware_name);
472*4882a593Smuzhiyun 
473*4882a593Smuzhiyun 	if ((fw->size % 17 == 0) && (fw->data[0] > 5)) {
474*4882a593Smuzhiyun 		/* firmware is in the new format */
475*4882a593Smuzhiyun 		for (remaining = fw->size; remaining > 0; remaining -= 17) {
476*4882a593Smuzhiyun 			len = fw->data[fw->size - remaining];
477*4882a593Smuzhiyun 			if (len > SI2168_ARGLEN) {
478*4882a593Smuzhiyun 				ret = -EINVAL;
479*4882a593Smuzhiyun 				break;
480*4882a593Smuzhiyun 			}
481*4882a593Smuzhiyun 			cmd_init(&cmd, &fw->data[(fw->size - remaining) + 1],
482*4882a593Smuzhiyun 				 len, 1);
483*4882a593Smuzhiyun 			ret = si2168_cmd_execute(client, &cmd);
484*4882a593Smuzhiyun 			if (ret)
485*4882a593Smuzhiyun 				break;
486*4882a593Smuzhiyun 		}
487*4882a593Smuzhiyun 	} else if (fw->size % 8 == 0) {
488*4882a593Smuzhiyun 		/* firmware is in the old format */
489*4882a593Smuzhiyun 		for (remaining = fw->size; remaining > 0; remaining -= 8) {
490*4882a593Smuzhiyun 			cmd_init(&cmd, &fw->data[fw->size - remaining], 8, 1);
491*4882a593Smuzhiyun 			ret = si2168_cmd_execute(client, &cmd);
492*4882a593Smuzhiyun 			if (ret)
493*4882a593Smuzhiyun 				break;
494*4882a593Smuzhiyun 		}
495*4882a593Smuzhiyun 	} else {
496*4882a593Smuzhiyun 		/* bad or unknown firmware format */
497*4882a593Smuzhiyun 		ret = -EINVAL;
498*4882a593Smuzhiyun 	}
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun 	if (ret) {
501*4882a593Smuzhiyun 		dev_err(&client->dev, "firmware download failed %d\n", ret);
502*4882a593Smuzhiyun 		goto err_release_firmware;
503*4882a593Smuzhiyun 	}
504*4882a593Smuzhiyun 
505*4882a593Smuzhiyun 	release_firmware(fw);
506*4882a593Smuzhiyun 
507*4882a593Smuzhiyun 	cmd_init(&cmd, "\x01\x01", 2, 1);
508*4882a593Smuzhiyun 	ret = si2168_cmd_execute(client, &cmd);
509*4882a593Smuzhiyun 	if (ret)
510*4882a593Smuzhiyun 		goto err;
511*4882a593Smuzhiyun 
512*4882a593Smuzhiyun 	/* query firmware version */
513*4882a593Smuzhiyun 	cmd_init(&cmd, "\x11", 1, 10);
514*4882a593Smuzhiyun 	ret = si2168_cmd_execute(client, &cmd);
515*4882a593Smuzhiyun 	if (ret)
516*4882a593Smuzhiyun 		goto err;
517*4882a593Smuzhiyun 
518*4882a593Smuzhiyun 	dev->version = (cmd.args[9] + '@') << 24 | (cmd.args[6] - '0') << 16 |
519*4882a593Smuzhiyun 		       (cmd.args[7] - '0') << 8 | (cmd.args[8]) << 0;
520*4882a593Smuzhiyun 	dev_info(&client->dev, "firmware version: %c %d.%d.%d\n",
521*4882a593Smuzhiyun 		 dev->version >> 24 & 0xff, dev->version >> 16 & 0xff,
522*4882a593Smuzhiyun 		 dev->version >> 8 & 0xff, dev->version >> 0 & 0xff);
523*4882a593Smuzhiyun 
524*4882a593Smuzhiyun 	/* set ts mode */
525*4882a593Smuzhiyun 	ret = si2168_ts_bus_ctrl(fe, 1);
526*4882a593Smuzhiyun 	if (ret)
527*4882a593Smuzhiyun 		goto err;
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun 	dev->warm = true;
530*4882a593Smuzhiyun warm:
531*4882a593Smuzhiyun 	/* Init stats here to indicate which stats are supported */
532*4882a593Smuzhiyun 	c->cnr.len = 1;
533*4882a593Smuzhiyun 	c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
534*4882a593Smuzhiyun 	c->post_bit_error.len = 1;
535*4882a593Smuzhiyun 	c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
536*4882a593Smuzhiyun 	c->post_bit_count.len = 1;
537*4882a593Smuzhiyun 	c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
538*4882a593Smuzhiyun 	c->block_error.len = 1;
539*4882a593Smuzhiyun 	c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
540*4882a593Smuzhiyun 
541*4882a593Smuzhiyun 	dev->active = true;
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun 	return 0;
544*4882a593Smuzhiyun err_release_firmware:
545*4882a593Smuzhiyun 	release_firmware(fw);
546*4882a593Smuzhiyun err:
547*4882a593Smuzhiyun 	dev_dbg(&client->dev, "failed=%d\n", ret);
548*4882a593Smuzhiyun 	return ret;
549*4882a593Smuzhiyun }
550*4882a593Smuzhiyun 
si2168_sleep(struct dvb_frontend * fe)551*4882a593Smuzhiyun static int si2168_sleep(struct dvb_frontend *fe)
552*4882a593Smuzhiyun {
553*4882a593Smuzhiyun 	struct i2c_client *client = fe->demodulator_priv;
554*4882a593Smuzhiyun 	struct si2168_dev *dev = i2c_get_clientdata(client);
555*4882a593Smuzhiyun 	int ret;
556*4882a593Smuzhiyun 	struct si2168_cmd cmd;
557*4882a593Smuzhiyun 
558*4882a593Smuzhiyun 	dev_dbg(&client->dev, "\n");
559*4882a593Smuzhiyun 
560*4882a593Smuzhiyun 	dev->active = false;
561*4882a593Smuzhiyun 
562*4882a593Smuzhiyun 	/* tri-state data bus */
563*4882a593Smuzhiyun 	ret = si2168_ts_bus_ctrl(fe, 0);
564*4882a593Smuzhiyun 	if (ret)
565*4882a593Smuzhiyun 		goto err;
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun 	/* Firmware later than B 4.0-11 loses warm state during sleep */
568*4882a593Smuzhiyun 	if (dev->version > ('B' << 24 | 4 << 16 | 0 << 8 | 11 << 0))
569*4882a593Smuzhiyun 		dev->warm = false;
570*4882a593Smuzhiyun 
571*4882a593Smuzhiyun 	cmd_init(&cmd, "\x13", 1, 0);
572*4882a593Smuzhiyun 	ret = si2168_cmd_execute(client, &cmd);
573*4882a593Smuzhiyun 	if (ret)
574*4882a593Smuzhiyun 		goto err;
575*4882a593Smuzhiyun 
576*4882a593Smuzhiyun 	return 0;
577*4882a593Smuzhiyun err:
578*4882a593Smuzhiyun 	dev_dbg(&client->dev, "failed=%d\n", ret);
579*4882a593Smuzhiyun 	return ret;
580*4882a593Smuzhiyun }
581*4882a593Smuzhiyun 
si2168_get_tune_settings(struct dvb_frontend * fe,struct dvb_frontend_tune_settings * s)582*4882a593Smuzhiyun static int si2168_get_tune_settings(struct dvb_frontend *fe,
583*4882a593Smuzhiyun 	struct dvb_frontend_tune_settings *s)
584*4882a593Smuzhiyun {
585*4882a593Smuzhiyun 	s->min_delay_ms = 900;
586*4882a593Smuzhiyun 
587*4882a593Smuzhiyun 	return 0;
588*4882a593Smuzhiyun }
589*4882a593Smuzhiyun 
si2168_select(struct i2c_mux_core * muxc,u32 chan)590*4882a593Smuzhiyun static int si2168_select(struct i2c_mux_core *muxc, u32 chan)
591*4882a593Smuzhiyun {
592*4882a593Smuzhiyun 	struct i2c_client *client = i2c_mux_priv(muxc);
593*4882a593Smuzhiyun 	int ret;
594*4882a593Smuzhiyun 	struct si2168_cmd cmd;
595*4882a593Smuzhiyun 
596*4882a593Smuzhiyun 	/* open I2C gate */
597*4882a593Smuzhiyun 	cmd_init(&cmd, "\xc0\x0d\x01", 3, 0);
598*4882a593Smuzhiyun 	ret = si2168_cmd_execute(client, &cmd);
599*4882a593Smuzhiyun 	if (ret)
600*4882a593Smuzhiyun 		goto err;
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun 	return 0;
603*4882a593Smuzhiyun err:
604*4882a593Smuzhiyun 	dev_dbg(&client->dev, "failed=%d\n", ret);
605*4882a593Smuzhiyun 	return ret;
606*4882a593Smuzhiyun }
607*4882a593Smuzhiyun 
si2168_deselect(struct i2c_mux_core * muxc,u32 chan)608*4882a593Smuzhiyun static int si2168_deselect(struct i2c_mux_core *muxc, u32 chan)
609*4882a593Smuzhiyun {
610*4882a593Smuzhiyun 	struct i2c_client *client = i2c_mux_priv(muxc);
611*4882a593Smuzhiyun 	int ret;
612*4882a593Smuzhiyun 	struct si2168_cmd cmd;
613*4882a593Smuzhiyun 
614*4882a593Smuzhiyun 	/* close I2C gate */
615*4882a593Smuzhiyun 	cmd_init(&cmd, "\xc0\x0d\x00", 3, 0);
616*4882a593Smuzhiyun 	ret = si2168_cmd_execute(client, &cmd);
617*4882a593Smuzhiyun 	if (ret)
618*4882a593Smuzhiyun 		goto err;
619*4882a593Smuzhiyun 
620*4882a593Smuzhiyun 	return 0;
621*4882a593Smuzhiyun err:
622*4882a593Smuzhiyun 	dev_dbg(&client->dev, "failed=%d\n", ret);
623*4882a593Smuzhiyun 	return ret;
624*4882a593Smuzhiyun }
625*4882a593Smuzhiyun 
626*4882a593Smuzhiyun static const struct dvb_frontend_ops si2168_ops = {
627*4882a593Smuzhiyun 	.delsys = {SYS_DVBT, SYS_DVBT2, SYS_DVBC_ANNEX_A},
628*4882a593Smuzhiyun 	.info = {
629*4882a593Smuzhiyun 		.name = "Silicon Labs Si2168",
630*4882a593Smuzhiyun 		.frequency_min_hz      =  48 * MHz,
631*4882a593Smuzhiyun 		.frequency_max_hz      = 870 * MHz,
632*4882a593Smuzhiyun 		.frequency_stepsize_hz = 62500,
633*4882a593Smuzhiyun 		.symbol_rate_min       = 1000000,
634*4882a593Smuzhiyun 		.symbol_rate_max       = 7200000,
635*4882a593Smuzhiyun 		.caps =	FE_CAN_FEC_1_2 |
636*4882a593Smuzhiyun 			FE_CAN_FEC_2_3 |
637*4882a593Smuzhiyun 			FE_CAN_FEC_3_4 |
638*4882a593Smuzhiyun 			FE_CAN_FEC_5_6 |
639*4882a593Smuzhiyun 			FE_CAN_FEC_7_8 |
640*4882a593Smuzhiyun 			FE_CAN_FEC_AUTO |
641*4882a593Smuzhiyun 			FE_CAN_QPSK |
642*4882a593Smuzhiyun 			FE_CAN_QAM_16 |
643*4882a593Smuzhiyun 			FE_CAN_QAM_32 |
644*4882a593Smuzhiyun 			FE_CAN_QAM_64 |
645*4882a593Smuzhiyun 			FE_CAN_QAM_128 |
646*4882a593Smuzhiyun 			FE_CAN_QAM_256 |
647*4882a593Smuzhiyun 			FE_CAN_QAM_AUTO |
648*4882a593Smuzhiyun 			FE_CAN_TRANSMISSION_MODE_AUTO |
649*4882a593Smuzhiyun 			FE_CAN_GUARD_INTERVAL_AUTO |
650*4882a593Smuzhiyun 			FE_CAN_HIERARCHY_AUTO |
651*4882a593Smuzhiyun 			FE_CAN_MUTE_TS |
652*4882a593Smuzhiyun 			FE_CAN_2G_MODULATION |
653*4882a593Smuzhiyun 			FE_CAN_MULTISTREAM
654*4882a593Smuzhiyun 	},
655*4882a593Smuzhiyun 
656*4882a593Smuzhiyun 	.get_tune_settings = si2168_get_tune_settings,
657*4882a593Smuzhiyun 
658*4882a593Smuzhiyun 	.init = si2168_init,
659*4882a593Smuzhiyun 	.sleep = si2168_sleep,
660*4882a593Smuzhiyun 
661*4882a593Smuzhiyun 	.set_frontend = si2168_set_frontend,
662*4882a593Smuzhiyun 
663*4882a593Smuzhiyun 	.read_status = si2168_read_status,
664*4882a593Smuzhiyun };
665*4882a593Smuzhiyun 
si2168_probe(struct i2c_client * client,const struct i2c_device_id * id)666*4882a593Smuzhiyun static int si2168_probe(struct i2c_client *client,
667*4882a593Smuzhiyun 		const struct i2c_device_id *id)
668*4882a593Smuzhiyun {
669*4882a593Smuzhiyun 	struct si2168_config *config = client->dev.platform_data;
670*4882a593Smuzhiyun 	struct si2168_dev *dev;
671*4882a593Smuzhiyun 	int ret;
672*4882a593Smuzhiyun 	struct si2168_cmd cmd;
673*4882a593Smuzhiyun 
674*4882a593Smuzhiyun 	dev_dbg(&client->dev, "\n");
675*4882a593Smuzhiyun 
676*4882a593Smuzhiyun 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
677*4882a593Smuzhiyun 	if (!dev) {
678*4882a593Smuzhiyun 		ret = -ENOMEM;
679*4882a593Smuzhiyun 		goto err;
680*4882a593Smuzhiyun 	}
681*4882a593Smuzhiyun 
682*4882a593Smuzhiyun 	i2c_set_clientdata(client, dev);
683*4882a593Smuzhiyun 	mutex_init(&dev->i2c_mutex);
684*4882a593Smuzhiyun 
685*4882a593Smuzhiyun 	/* Initialize */
686*4882a593Smuzhiyun 	cmd_init(&cmd, "\xc0\x12\x00\x0c\x00\x0d\x16\x00\x00\x00\x00\x00\x00",
687*4882a593Smuzhiyun 		 13, 0);
688*4882a593Smuzhiyun 	ret = si2168_cmd_execute(client, &cmd);
689*4882a593Smuzhiyun 	if (ret)
690*4882a593Smuzhiyun 		goto err_kfree;
691*4882a593Smuzhiyun 
692*4882a593Smuzhiyun 	/* Power up */
693*4882a593Smuzhiyun 	cmd_init(&cmd, "\xc0\x06\x01\x0f\x00\x20\x20\x01", 8, 1);
694*4882a593Smuzhiyun 	ret = si2168_cmd_execute(client, &cmd);
695*4882a593Smuzhiyun 	if (ret)
696*4882a593Smuzhiyun 		goto err_kfree;
697*4882a593Smuzhiyun 
698*4882a593Smuzhiyun 	/* Query chip revision */
699*4882a593Smuzhiyun 	cmd_init(&cmd, "\x02", 1, 13);
700*4882a593Smuzhiyun 	ret = si2168_cmd_execute(client, &cmd);
701*4882a593Smuzhiyun 	if (ret)
702*4882a593Smuzhiyun 		goto err_kfree;
703*4882a593Smuzhiyun 
704*4882a593Smuzhiyun 	dev->chip_id = cmd.args[1] << 24 | cmd.args[2] << 16 |
705*4882a593Smuzhiyun 		       cmd.args[3] << 8 | cmd.args[4] << 0;
706*4882a593Smuzhiyun 
707*4882a593Smuzhiyun 	switch (dev->chip_id) {
708*4882a593Smuzhiyun 	case SI2168_CHIP_ID_A20:
709*4882a593Smuzhiyun 		dev->firmware_name = SI2168_A20_FIRMWARE;
710*4882a593Smuzhiyun 		break;
711*4882a593Smuzhiyun 	case SI2168_CHIP_ID_A30:
712*4882a593Smuzhiyun 		dev->firmware_name = SI2168_A30_FIRMWARE;
713*4882a593Smuzhiyun 		break;
714*4882a593Smuzhiyun 	case SI2168_CHIP_ID_B40:
715*4882a593Smuzhiyun 		dev->firmware_name = SI2168_B40_FIRMWARE;
716*4882a593Smuzhiyun 		break;
717*4882a593Smuzhiyun 	case SI2168_CHIP_ID_D60:
718*4882a593Smuzhiyun 		dev->firmware_name = SI2168_D60_FIRMWARE;
719*4882a593Smuzhiyun 		break;
720*4882a593Smuzhiyun 	default:
721*4882a593Smuzhiyun 		dev_dbg(&client->dev, "unknown chip version Si21%d-%c%c%c\n",
722*4882a593Smuzhiyun 			cmd.args[2], cmd.args[1], cmd.args[3], cmd.args[4]);
723*4882a593Smuzhiyun 		ret = -ENODEV;
724*4882a593Smuzhiyun 		goto err_kfree;
725*4882a593Smuzhiyun 	}
726*4882a593Smuzhiyun 
727*4882a593Smuzhiyun 	dev->version = (cmd.args[1]) << 24 | (cmd.args[3] - '0') << 16 |
728*4882a593Smuzhiyun 		       (cmd.args[4] - '0') << 8 | (cmd.args[5]) << 0;
729*4882a593Smuzhiyun 
730*4882a593Smuzhiyun 	/* create mux i2c adapter for tuner */
731*4882a593Smuzhiyun 	dev->muxc = i2c_mux_alloc(client->adapter, &client->dev,
732*4882a593Smuzhiyun 				  1, 0, I2C_MUX_LOCKED,
733*4882a593Smuzhiyun 				  si2168_select, si2168_deselect);
734*4882a593Smuzhiyun 	if (!dev->muxc) {
735*4882a593Smuzhiyun 		ret = -ENOMEM;
736*4882a593Smuzhiyun 		goto err_kfree;
737*4882a593Smuzhiyun 	}
738*4882a593Smuzhiyun 	dev->muxc->priv = client;
739*4882a593Smuzhiyun 	ret = i2c_mux_add_adapter(dev->muxc, 0, 0, 0);
740*4882a593Smuzhiyun 	if (ret)
741*4882a593Smuzhiyun 		goto err_kfree;
742*4882a593Smuzhiyun 
743*4882a593Smuzhiyun 	/* create dvb_frontend */
744*4882a593Smuzhiyun 	memcpy(&dev->fe.ops, &si2168_ops, sizeof(struct dvb_frontend_ops));
745*4882a593Smuzhiyun 	dev->fe.demodulator_priv = client;
746*4882a593Smuzhiyun 	*config->i2c_adapter = dev->muxc->adapter[0];
747*4882a593Smuzhiyun 	*config->fe = &dev->fe;
748*4882a593Smuzhiyun 	dev->ts_mode = config->ts_mode;
749*4882a593Smuzhiyun 	dev->ts_clock_inv = config->ts_clock_inv;
750*4882a593Smuzhiyun 	dev->ts_clock_gapped = config->ts_clock_gapped;
751*4882a593Smuzhiyun 	dev->spectral_inversion = config->spectral_inversion;
752*4882a593Smuzhiyun 
753*4882a593Smuzhiyun 	dev_info(&client->dev, "Silicon Labs Si2168-%c%d%d successfully identified\n",
754*4882a593Smuzhiyun 		 dev->version >> 24 & 0xff, dev->version >> 16 & 0xff,
755*4882a593Smuzhiyun 		 dev->version >> 8 & 0xff);
756*4882a593Smuzhiyun 	dev_info(&client->dev, "firmware version: %c %d.%d.%d\n",
757*4882a593Smuzhiyun 		 dev->version >> 24 & 0xff, dev->version >> 16 & 0xff,
758*4882a593Smuzhiyun 		 dev->version >> 8 & 0xff, dev->version >> 0 & 0xff);
759*4882a593Smuzhiyun 
760*4882a593Smuzhiyun 	return 0;
761*4882a593Smuzhiyun err_kfree:
762*4882a593Smuzhiyun 	kfree(dev);
763*4882a593Smuzhiyun err:
764*4882a593Smuzhiyun 	dev_warn(&client->dev, "probe failed = %d\n", ret);
765*4882a593Smuzhiyun 	return ret;
766*4882a593Smuzhiyun }
767*4882a593Smuzhiyun 
si2168_remove(struct i2c_client * client)768*4882a593Smuzhiyun static int si2168_remove(struct i2c_client *client)
769*4882a593Smuzhiyun {
770*4882a593Smuzhiyun 	struct si2168_dev *dev = i2c_get_clientdata(client);
771*4882a593Smuzhiyun 
772*4882a593Smuzhiyun 	dev_dbg(&client->dev, "\n");
773*4882a593Smuzhiyun 
774*4882a593Smuzhiyun 	i2c_mux_del_adapters(dev->muxc);
775*4882a593Smuzhiyun 
776*4882a593Smuzhiyun 	dev->fe.ops.release = NULL;
777*4882a593Smuzhiyun 	dev->fe.demodulator_priv = NULL;
778*4882a593Smuzhiyun 
779*4882a593Smuzhiyun 	kfree(dev);
780*4882a593Smuzhiyun 
781*4882a593Smuzhiyun 	return 0;
782*4882a593Smuzhiyun }
783*4882a593Smuzhiyun 
784*4882a593Smuzhiyun static const struct i2c_device_id si2168_id_table[] = {
785*4882a593Smuzhiyun 	{"si2168", 0},
786*4882a593Smuzhiyun 	{}
787*4882a593Smuzhiyun };
788*4882a593Smuzhiyun MODULE_DEVICE_TABLE(i2c, si2168_id_table);
789*4882a593Smuzhiyun 
790*4882a593Smuzhiyun static struct i2c_driver si2168_driver = {
791*4882a593Smuzhiyun 	.driver = {
792*4882a593Smuzhiyun 		.name                = "si2168",
793*4882a593Smuzhiyun 		.suppress_bind_attrs = true,
794*4882a593Smuzhiyun 	},
795*4882a593Smuzhiyun 	.probe		= si2168_probe,
796*4882a593Smuzhiyun 	.remove		= si2168_remove,
797*4882a593Smuzhiyun 	.id_table	= si2168_id_table,
798*4882a593Smuzhiyun };
799*4882a593Smuzhiyun 
800*4882a593Smuzhiyun module_i2c_driver(si2168_driver);
801*4882a593Smuzhiyun 
802*4882a593Smuzhiyun MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
803*4882a593Smuzhiyun MODULE_DESCRIPTION("Silicon Labs Si2168 DVB-T/T2/C demodulator driver");
804*4882a593Smuzhiyun MODULE_LICENSE("GPL");
805*4882a593Smuzhiyun MODULE_FIRMWARE(SI2168_A20_FIRMWARE);
806*4882a593Smuzhiyun MODULE_FIRMWARE(SI2168_A30_FIRMWARE);
807*4882a593Smuzhiyun MODULE_FIRMWARE(SI2168_B40_FIRMWARE);
808*4882a593Smuzhiyun MODULE_FIRMWARE(SI2168_D60_FIRMWARE);
809