xref: /OK3568_Linux_fs/kernel/drivers/media/tuners/si2157.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Silicon Labs Si2146/2147/2148/2157/2158 silicon tuner driver
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2014 Antti Palosaari <crope@iki.fi>
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include "si2157_priv.h"
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun static const struct dvb_tuner_ops si2157_ops;
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun static int tuner_lock_debug;
13*4882a593Smuzhiyun module_param(tuner_lock_debug, int, 0644);
14*4882a593Smuzhiyun MODULE_PARM_DESC(tuner_lock_debug, "if set, signal lock is briefly waited on after setting params");
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun /* execute firmware command */
si2157_cmd_execute(struct i2c_client * client,struct si2157_cmd * cmd)17*4882a593Smuzhiyun static int si2157_cmd_execute(struct i2c_client *client, struct si2157_cmd *cmd)
18*4882a593Smuzhiyun {
19*4882a593Smuzhiyun 	struct si2157_dev *dev = i2c_get_clientdata(client);
20*4882a593Smuzhiyun 	int ret;
21*4882a593Smuzhiyun 	unsigned long timeout;
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun 	mutex_lock(&dev->i2c_mutex);
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun 	if (cmd->wlen) {
26*4882a593Smuzhiyun 		/* write cmd and args for firmware */
27*4882a593Smuzhiyun 		ret = i2c_master_send(client, cmd->args, cmd->wlen);
28*4882a593Smuzhiyun 		if (ret < 0) {
29*4882a593Smuzhiyun 			goto err_mutex_unlock;
30*4882a593Smuzhiyun 		} else if (ret != cmd->wlen) {
31*4882a593Smuzhiyun 			ret = -EREMOTEIO;
32*4882a593Smuzhiyun 			goto err_mutex_unlock;
33*4882a593Smuzhiyun 		}
34*4882a593Smuzhiyun 	}
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun 	if (cmd->rlen) {
37*4882a593Smuzhiyun 		/* wait cmd execution terminate */
38*4882a593Smuzhiyun 		#define TIMEOUT 80
39*4882a593Smuzhiyun 		timeout = jiffies + msecs_to_jiffies(TIMEOUT);
40*4882a593Smuzhiyun 		while (!time_after(jiffies, timeout)) {
41*4882a593Smuzhiyun 			ret = i2c_master_recv(client, cmd->args, cmd->rlen);
42*4882a593Smuzhiyun 			if (ret < 0) {
43*4882a593Smuzhiyun 				goto err_mutex_unlock;
44*4882a593Smuzhiyun 			} else if (ret != cmd->rlen) {
45*4882a593Smuzhiyun 				ret = -EREMOTEIO;
46*4882a593Smuzhiyun 				goto err_mutex_unlock;
47*4882a593Smuzhiyun 			}
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun 			/* firmware ready? */
50*4882a593Smuzhiyun 			if ((cmd->args[0] >> 7) & 0x01)
51*4882a593Smuzhiyun 				break;
52*4882a593Smuzhiyun 		}
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun 		dev_dbg(&client->dev, "cmd execution took %d ms, status=%x\n",
55*4882a593Smuzhiyun 			jiffies_to_msecs(jiffies) -
56*4882a593Smuzhiyun 			(jiffies_to_msecs(timeout) - TIMEOUT),
57*4882a593Smuzhiyun 			cmd->args[0]);
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun 		if (!((cmd->args[0] >> 7) & 0x01)) {
60*4882a593Smuzhiyun 			ret = -ETIMEDOUT;
61*4882a593Smuzhiyun 			goto err_mutex_unlock;
62*4882a593Smuzhiyun 		}
63*4882a593Smuzhiyun 		/* check error status bit */
64*4882a593Smuzhiyun 		if (cmd->args[0] & 0x40) {
65*4882a593Smuzhiyun 			ret = -EAGAIN;
66*4882a593Smuzhiyun 			goto err_mutex_unlock;
67*4882a593Smuzhiyun 		}
68*4882a593Smuzhiyun 	}
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 	mutex_unlock(&dev->i2c_mutex);
71*4882a593Smuzhiyun 	return 0;
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun err_mutex_unlock:
74*4882a593Smuzhiyun 	mutex_unlock(&dev->i2c_mutex);
75*4882a593Smuzhiyun 	dev_dbg(&client->dev, "failed=%d\n", ret);
76*4882a593Smuzhiyun 	return ret;
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun 
si2157_init(struct dvb_frontend * fe)79*4882a593Smuzhiyun static int si2157_init(struct dvb_frontend *fe)
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun 	struct i2c_client *client = fe->tuner_priv;
82*4882a593Smuzhiyun 	struct si2157_dev *dev = i2c_get_clientdata(client);
83*4882a593Smuzhiyun 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
84*4882a593Smuzhiyun 	int ret, len, remaining;
85*4882a593Smuzhiyun 	struct si2157_cmd cmd;
86*4882a593Smuzhiyun 	const struct firmware *fw;
87*4882a593Smuzhiyun 	const char *fw_name;
88*4882a593Smuzhiyun 	unsigned int chip_id, xtal_trim;
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	dev_dbg(&client->dev, "\n");
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun 	/* Try to get Xtal trim property, to verify tuner still running */
93*4882a593Smuzhiyun 	memcpy(cmd.args, "\x15\x00\x02\x04", 4);
94*4882a593Smuzhiyun 	cmd.wlen = 4;
95*4882a593Smuzhiyun 	cmd.rlen = 4;
96*4882a593Smuzhiyun 	ret = si2157_cmd_execute(client, &cmd);
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	xtal_trim = cmd.args[2] | (cmd.args[3] << 8);
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 	if (ret == 0 && xtal_trim < 16)
101*4882a593Smuzhiyun 		goto warm;
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 	dev->if_frequency = 0; /* we no longer know current tuner state */
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	/* power up */
106*4882a593Smuzhiyun 	if (dev->chiptype == SI2157_CHIPTYPE_SI2146) {
107*4882a593Smuzhiyun 		memcpy(cmd.args, "\xc0\x05\x01\x00\x00\x0b\x00\x00\x01", 9);
108*4882a593Smuzhiyun 		cmd.wlen = 9;
109*4882a593Smuzhiyun 	} else if (dev->chiptype == SI2157_CHIPTYPE_SI2141) {
110*4882a593Smuzhiyun 		memcpy(cmd.args, "\xc0\x00\x0d\x0e\x00\x01\x01\x01\x01\x03", 10);
111*4882a593Smuzhiyun 		cmd.wlen = 10;
112*4882a593Smuzhiyun 	} else {
113*4882a593Smuzhiyun 		memcpy(cmd.args, "\xc0\x00\x0c\x00\x00\x01\x01\x01\x01\x01\x01\x02\x00\x00\x01", 15);
114*4882a593Smuzhiyun 		cmd.wlen = 15;
115*4882a593Smuzhiyun 	}
116*4882a593Smuzhiyun 	cmd.rlen = 1;
117*4882a593Smuzhiyun 	ret = si2157_cmd_execute(client, &cmd);
118*4882a593Smuzhiyun 	if (ret && (dev->chiptype != SI2157_CHIPTYPE_SI2141 || ret != -EAGAIN))
119*4882a593Smuzhiyun 		goto err;
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	/* Si2141 needs a second command before it answers the revision query */
122*4882a593Smuzhiyun 	if (dev->chiptype == SI2157_CHIPTYPE_SI2141) {
123*4882a593Smuzhiyun 		memcpy(cmd.args, "\xc0\x08\x01\x02\x00\x00\x01", 7);
124*4882a593Smuzhiyun 		cmd.wlen = 7;
125*4882a593Smuzhiyun 		ret = si2157_cmd_execute(client, &cmd);
126*4882a593Smuzhiyun 		if (ret)
127*4882a593Smuzhiyun 			goto err;
128*4882a593Smuzhiyun 	}
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	if (dev->dont_load_firmware) {
131*4882a593Smuzhiyun 		dev_info(&client->dev, "device is buggy, skipping firmware download\n");
132*4882a593Smuzhiyun 		goto skip_fw_download;
133*4882a593Smuzhiyun 	}
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	/* query chip revision */
136*4882a593Smuzhiyun 	memcpy(cmd.args, "\x02", 1);
137*4882a593Smuzhiyun 	cmd.wlen = 1;
138*4882a593Smuzhiyun 	cmd.rlen = 13;
139*4882a593Smuzhiyun 	ret = si2157_cmd_execute(client, &cmd);
140*4882a593Smuzhiyun 	if (ret)
141*4882a593Smuzhiyun 		goto err;
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	chip_id = cmd.args[1] << 24 | cmd.args[2] << 16 | cmd.args[3] << 8 |
144*4882a593Smuzhiyun 			cmd.args[4] << 0;
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 	#define SI2177_A30 ('A' << 24 | 77 << 16 | '3' << 8 | '0' << 0)
147*4882a593Smuzhiyun 	#define SI2158_A20 ('A' << 24 | 58 << 16 | '2' << 8 | '0' << 0)
148*4882a593Smuzhiyun 	#define SI2148_A20 ('A' << 24 | 48 << 16 | '2' << 8 | '0' << 0)
149*4882a593Smuzhiyun 	#define SI2157_A30 ('A' << 24 | 57 << 16 | '3' << 8 | '0' << 0)
150*4882a593Smuzhiyun 	#define SI2147_A30 ('A' << 24 | 47 << 16 | '3' << 8 | '0' << 0)
151*4882a593Smuzhiyun 	#define SI2146_A10 ('A' << 24 | 46 << 16 | '1' << 8 | '0' << 0)
152*4882a593Smuzhiyun 	#define SI2141_A10 ('A' << 24 | 41 << 16 | '1' << 8 | '0' << 0)
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 	switch (chip_id) {
155*4882a593Smuzhiyun 	case SI2158_A20:
156*4882a593Smuzhiyun 	case SI2148_A20:
157*4882a593Smuzhiyun 		fw_name = SI2158_A20_FIRMWARE;
158*4882a593Smuzhiyun 		break;
159*4882a593Smuzhiyun 	case SI2141_A10:
160*4882a593Smuzhiyun 		fw_name = SI2141_A10_FIRMWARE;
161*4882a593Smuzhiyun 		break;
162*4882a593Smuzhiyun 	case SI2177_A30:
163*4882a593Smuzhiyun 		fw_name = SI2157_A30_FIRMWARE;
164*4882a593Smuzhiyun 		break;
165*4882a593Smuzhiyun 	case SI2157_A30:
166*4882a593Smuzhiyun 	case SI2147_A30:
167*4882a593Smuzhiyun 	case SI2146_A10:
168*4882a593Smuzhiyun 		fw_name = NULL;
169*4882a593Smuzhiyun 		break;
170*4882a593Smuzhiyun 	default:
171*4882a593Smuzhiyun 		dev_err(&client->dev, "unknown chip version Si21%d-%c%c%c\n",
172*4882a593Smuzhiyun 				cmd.args[2], cmd.args[1],
173*4882a593Smuzhiyun 				cmd.args[3], cmd.args[4]);
174*4882a593Smuzhiyun 		ret = -EINVAL;
175*4882a593Smuzhiyun 		goto err;
176*4882a593Smuzhiyun 	}
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	dev_info(&client->dev, "found a 'Silicon Labs Si21%d-%c%c%c'\n",
179*4882a593Smuzhiyun 			cmd.args[2], cmd.args[1], cmd.args[3], cmd.args[4]);
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	if (fw_name == NULL)
182*4882a593Smuzhiyun 		goto skip_fw_download;
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	/* request the firmware, this will block and timeout */
185*4882a593Smuzhiyun 	ret = request_firmware(&fw, fw_name, &client->dev);
186*4882a593Smuzhiyun 	if (ret) {
187*4882a593Smuzhiyun 		dev_err(&client->dev, "firmware file '%s' not found\n",
188*4882a593Smuzhiyun 				fw_name);
189*4882a593Smuzhiyun 		goto err;
190*4882a593Smuzhiyun 	}
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 	/* firmware should be n chunks of 17 bytes */
193*4882a593Smuzhiyun 	if (fw->size % 17 != 0) {
194*4882a593Smuzhiyun 		dev_err(&client->dev, "firmware file '%s' is invalid\n",
195*4882a593Smuzhiyun 				fw_name);
196*4882a593Smuzhiyun 		ret = -EINVAL;
197*4882a593Smuzhiyun 		goto err_release_firmware;
198*4882a593Smuzhiyun 	}
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun 	dev_info(&client->dev, "downloading firmware from file '%s'\n",
201*4882a593Smuzhiyun 			fw_name);
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	for (remaining = fw->size; remaining > 0; remaining -= 17) {
204*4882a593Smuzhiyun 		len = fw->data[fw->size - remaining];
205*4882a593Smuzhiyun 		if (len > SI2157_ARGLEN) {
206*4882a593Smuzhiyun 			dev_err(&client->dev, "Bad firmware length\n");
207*4882a593Smuzhiyun 			ret = -EINVAL;
208*4882a593Smuzhiyun 			goto err_release_firmware;
209*4882a593Smuzhiyun 		}
210*4882a593Smuzhiyun 		memcpy(cmd.args, &fw->data[(fw->size - remaining) + 1], len);
211*4882a593Smuzhiyun 		cmd.wlen = len;
212*4882a593Smuzhiyun 		cmd.rlen = 1;
213*4882a593Smuzhiyun 		ret = si2157_cmd_execute(client, &cmd);
214*4882a593Smuzhiyun 		if (ret) {
215*4882a593Smuzhiyun 			dev_err(&client->dev, "firmware download failed %d\n",
216*4882a593Smuzhiyun 					ret);
217*4882a593Smuzhiyun 			goto err_release_firmware;
218*4882a593Smuzhiyun 		}
219*4882a593Smuzhiyun 	}
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun 	release_firmware(fw);
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun skip_fw_download:
224*4882a593Smuzhiyun 	/* reboot the tuner with new firmware? */
225*4882a593Smuzhiyun 	memcpy(cmd.args, "\x01\x01", 2);
226*4882a593Smuzhiyun 	cmd.wlen = 2;
227*4882a593Smuzhiyun 	cmd.rlen = 1;
228*4882a593Smuzhiyun 	ret = si2157_cmd_execute(client, &cmd);
229*4882a593Smuzhiyun 	if (ret)
230*4882a593Smuzhiyun 		goto err;
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 	/* query firmware version */
233*4882a593Smuzhiyun 	memcpy(cmd.args, "\x11", 1);
234*4882a593Smuzhiyun 	cmd.wlen = 1;
235*4882a593Smuzhiyun 	cmd.rlen = 10;
236*4882a593Smuzhiyun 	ret = si2157_cmd_execute(client, &cmd);
237*4882a593Smuzhiyun 	if (ret)
238*4882a593Smuzhiyun 		goto err;
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun 	dev_info(&client->dev, "firmware version: %c.%c.%d\n",
241*4882a593Smuzhiyun 			cmd.args[6], cmd.args[7], cmd.args[8]);
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	/* enable tuner status flags */
244*4882a593Smuzhiyun 	memcpy(cmd.args, "\x14\x00\x01\x05\x01\x00", 6);
245*4882a593Smuzhiyun 	cmd.wlen = 6;
246*4882a593Smuzhiyun 	cmd.rlen = 1;
247*4882a593Smuzhiyun 	ret = si2157_cmd_execute(client, &cmd);
248*4882a593Smuzhiyun 	if (ret)
249*4882a593Smuzhiyun 		goto err;
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	memcpy(cmd.args, "\x14\x00\x01\x06\x01\x00", 6);
252*4882a593Smuzhiyun 	cmd.wlen = 6;
253*4882a593Smuzhiyun 	cmd.rlen = 1;
254*4882a593Smuzhiyun 	ret = si2157_cmd_execute(client, &cmd);
255*4882a593Smuzhiyun 	if (ret)
256*4882a593Smuzhiyun 		goto err;
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun 	memcpy(cmd.args, "\x14\x00\x01\x07\x01\x00", 6);
259*4882a593Smuzhiyun 	cmd.wlen = 6;
260*4882a593Smuzhiyun 	cmd.rlen = 1;
261*4882a593Smuzhiyun 	ret = si2157_cmd_execute(client, &cmd);
262*4882a593Smuzhiyun 	if (ret)
263*4882a593Smuzhiyun 		goto err;
264*4882a593Smuzhiyun warm:
265*4882a593Smuzhiyun 	/* init statistics in order signal app which are supported */
266*4882a593Smuzhiyun 	c->strength.len = 1;
267*4882a593Smuzhiyun 	c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
268*4882a593Smuzhiyun 	/* start statistics polling */
269*4882a593Smuzhiyun 	schedule_delayed_work(&dev->stat_work, msecs_to_jiffies(1000));
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 	dev->active = true;
272*4882a593Smuzhiyun 	return 0;
273*4882a593Smuzhiyun err_release_firmware:
274*4882a593Smuzhiyun 	release_firmware(fw);
275*4882a593Smuzhiyun err:
276*4882a593Smuzhiyun 	dev_dbg(&client->dev, "failed=%d\n", ret);
277*4882a593Smuzhiyun 	return ret;
278*4882a593Smuzhiyun }
279*4882a593Smuzhiyun 
si2157_sleep(struct dvb_frontend * fe)280*4882a593Smuzhiyun static int si2157_sleep(struct dvb_frontend *fe)
281*4882a593Smuzhiyun {
282*4882a593Smuzhiyun 	struct i2c_client *client = fe->tuner_priv;
283*4882a593Smuzhiyun 	struct si2157_dev *dev = i2c_get_clientdata(client);
284*4882a593Smuzhiyun 	int ret;
285*4882a593Smuzhiyun 	struct si2157_cmd cmd;
286*4882a593Smuzhiyun 
287*4882a593Smuzhiyun 	dev_dbg(&client->dev, "\n");
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun 	dev->active = false;
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 	/* stop statistics polling */
292*4882a593Smuzhiyun 	cancel_delayed_work_sync(&dev->stat_work);
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 	/* standby */
295*4882a593Smuzhiyun 	memcpy(cmd.args, "\x16\x00", 2);
296*4882a593Smuzhiyun 	cmd.wlen = 2;
297*4882a593Smuzhiyun 	cmd.rlen = 1;
298*4882a593Smuzhiyun 	ret = si2157_cmd_execute(client, &cmd);
299*4882a593Smuzhiyun 	if (ret)
300*4882a593Smuzhiyun 		goto err;
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 	return 0;
303*4882a593Smuzhiyun err:
304*4882a593Smuzhiyun 	dev_dbg(&client->dev, "failed=%d\n", ret);
305*4882a593Smuzhiyun 	return ret;
306*4882a593Smuzhiyun }
307*4882a593Smuzhiyun 
si2157_tune_wait(struct i2c_client * client,u8 is_digital)308*4882a593Smuzhiyun static int si2157_tune_wait(struct i2c_client *client, u8 is_digital)
309*4882a593Smuzhiyun {
310*4882a593Smuzhiyun #define TUN_TIMEOUT 40
311*4882a593Smuzhiyun #define DIG_TIMEOUT 30
312*4882a593Smuzhiyun #define ANALOG_TIMEOUT 150
313*4882a593Smuzhiyun 	struct si2157_dev *dev = i2c_get_clientdata(client);
314*4882a593Smuzhiyun 	int ret;
315*4882a593Smuzhiyun 	unsigned long timeout;
316*4882a593Smuzhiyun 	unsigned long start_time;
317*4882a593Smuzhiyun 	u8 wait_status;
318*4882a593Smuzhiyun 	u8  tune_lock_mask;
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	if (is_digital)
321*4882a593Smuzhiyun 		tune_lock_mask = 0x04;
322*4882a593Smuzhiyun 	else
323*4882a593Smuzhiyun 		tune_lock_mask = 0x02;
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun 	mutex_lock(&dev->i2c_mutex);
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 	/* wait tuner command complete */
328*4882a593Smuzhiyun 	start_time = jiffies;
329*4882a593Smuzhiyun 	timeout = start_time + msecs_to_jiffies(TUN_TIMEOUT);
330*4882a593Smuzhiyun 	while (1) {
331*4882a593Smuzhiyun 		ret = i2c_master_recv(client, &wait_status,
332*4882a593Smuzhiyun 				      sizeof(wait_status));
333*4882a593Smuzhiyun 		if (ret < 0) {
334*4882a593Smuzhiyun 			goto err_mutex_unlock;
335*4882a593Smuzhiyun 		} else if (ret != sizeof(wait_status)) {
336*4882a593Smuzhiyun 			ret = -EREMOTEIO;
337*4882a593Smuzhiyun 			goto err_mutex_unlock;
338*4882a593Smuzhiyun 		}
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun 		if (time_after(jiffies, timeout))
341*4882a593Smuzhiyun 			break;
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun 		/* tuner done? */
344*4882a593Smuzhiyun 		if ((wait_status & 0x81) == 0x81)
345*4882a593Smuzhiyun 			break;
346*4882a593Smuzhiyun 		usleep_range(5000, 10000);
347*4882a593Smuzhiyun 	}
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun 	dev_dbg(&client->dev, "tuning took %d ms, status=0x%x\n",
350*4882a593Smuzhiyun 		jiffies_to_msecs(jiffies) - jiffies_to_msecs(start_time),
351*4882a593Smuzhiyun 		wait_status);
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 	/* if we tuned ok, wait a bit for tuner lock */
354*4882a593Smuzhiyun 	if (tuner_lock_debug && (wait_status & 0x81) == 0x81) {
355*4882a593Smuzhiyun 		if (is_digital)
356*4882a593Smuzhiyun 			timeout = jiffies + msecs_to_jiffies(DIG_TIMEOUT);
357*4882a593Smuzhiyun 		else
358*4882a593Smuzhiyun 			timeout = jiffies + msecs_to_jiffies(ANALOG_TIMEOUT);
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun 		while (!time_after(jiffies, timeout)) {
361*4882a593Smuzhiyun 			ret = i2c_master_recv(client, &wait_status,
362*4882a593Smuzhiyun 					      sizeof(wait_status));
363*4882a593Smuzhiyun 			if (ret < 0) {
364*4882a593Smuzhiyun 				goto err_mutex_unlock;
365*4882a593Smuzhiyun 			} else if (ret != sizeof(wait_status)) {
366*4882a593Smuzhiyun 				ret = -EREMOTEIO;
367*4882a593Smuzhiyun 				goto err_mutex_unlock;
368*4882a593Smuzhiyun 			}
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun 			/* tuner locked? */
371*4882a593Smuzhiyun 			if (wait_status & tune_lock_mask)
372*4882a593Smuzhiyun 				break;
373*4882a593Smuzhiyun 			usleep_range(5000, 10000);
374*4882a593Smuzhiyun 		}
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun 		dev_dbg(&client->dev, "tuning+lock took %d ms, status=0x%x\n",
377*4882a593Smuzhiyun 			jiffies_to_msecs(jiffies) - jiffies_to_msecs(start_time),
378*4882a593Smuzhiyun 			wait_status);
379*4882a593Smuzhiyun 	}
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 	if ((wait_status & 0xc0) != 0x80) {
382*4882a593Smuzhiyun 		ret = -ETIMEDOUT;
383*4882a593Smuzhiyun 		goto err_mutex_unlock;
384*4882a593Smuzhiyun 	}
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun 	mutex_unlock(&dev->i2c_mutex);
387*4882a593Smuzhiyun 	return 0;
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun err_mutex_unlock:
390*4882a593Smuzhiyun 	mutex_unlock(&dev->i2c_mutex);
391*4882a593Smuzhiyun 	dev_err(&client->dev, "failed=%d\n", ret);
392*4882a593Smuzhiyun 	return ret;
393*4882a593Smuzhiyun }
394*4882a593Smuzhiyun 
si2157_set_params(struct dvb_frontend * fe)395*4882a593Smuzhiyun static int si2157_set_params(struct dvb_frontend *fe)
396*4882a593Smuzhiyun {
397*4882a593Smuzhiyun 	struct i2c_client *client = fe->tuner_priv;
398*4882a593Smuzhiyun 	struct si2157_dev *dev = i2c_get_clientdata(client);
399*4882a593Smuzhiyun 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
400*4882a593Smuzhiyun 	int ret;
401*4882a593Smuzhiyun 	struct si2157_cmd cmd;
402*4882a593Smuzhiyun 	u8 bandwidth, delivery_system;
403*4882a593Smuzhiyun 	u32 if_frequency = 5000000;
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun 	dev_dbg(&client->dev,
406*4882a593Smuzhiyun 			"delivery_system=%d frequency=%u bandwidth_hz=%u\n",
407*4882a593Smuzhiyun 			c->delivery_system, c->frequency, c->bandwidth_hz);
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun 	if (!dev->active) {
410*4882a593Smuzhiyun 		ret = -EAGAIN;
411*4882a593Smuzhiyun 		goto err;
412*4882a593Smuzhiyun 	}
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 	if (c->bandwidth_hz <= 6000000)
415*4882a593Smuzhiyun 		bandwidth = 0x06;
416*4882a593Smuzhiyun 	else if (c->bandwidth_hz <= 7000000)
417*4882a593Smuzhiyun 		bandwidth = 0x07;
418*4882a593Smuzhiyun 	else if (c->bandwidth_hz <= 8000000)
419*4882a593Smuzhiyun 		bandwidth = 0x08;
420*4882a593Smuzhiyun 	else
421*4882a593Smuzhiyun 		bandwidth = 0x0f;
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun 	switch (c->delivery_system) {
424*4882a593Smuzhiyun 	case SYS_ATSC:
425*4882a593Smuzhiyun 			delivery_system = 0x00;
426*4882a593Smuzhiyun 			if_frequency = 3250000;
427*4882a593Smuzhiyun 			break;
428*4882a593Smuzhiyun 	case SYS_DVBC_ANNEX_B:
429*4882a593Smuzhiyun 			delivery_system = 0x10;
430*4882a593Smuzhiyun 			if_frequency = 4000000;
431*4882a593Smuzhiyun 			break;
432*4882a593Smuzhiyun 	case SYS_DVBT:
433*4882a593Smuzhiyun 	case SYS_DVBT2: /* it seems DVB-T and DVB-T2 both are 0x20 here */
434*4882a593Smuzhiyun 			delivery_system = 0x20;
435*4882a593Smuzhiyun 			break;
436*4882a593Smuzhiyun 	case SYS_DVBC_ANNEX_A:
437*4882a593Smuzhiyun 			delivery_system = 0x30;
438*4882a593Smuzhiyun 			break;
439*4882a593Smuzhiyun 	default:
440*4882a593Smuzhiyun 			ret = -EINVAL;
441*4882a593Smuzhiyun 			goto err;
442*4882a593Smuzhiyun 	}
443*4882a593Smuzhiyun 
444*4882a593Smuzhiyun 	memcpy(cmd.args, "\x14\x00\x03\x07\x00\x00", 6);
445*4882a593Smuzhiyun 	cmd.args[4] = delivery_system | bandwidth;
446*4882a593Smuzhiyun 	if (dev->inversion)
447*4882a593Smuzhiyun 		cmd.args[5] = 0x01;
448*4882a593Smuzhiyun 	cmd.wlen = 6;
449*4882a593Smuzhiyun 	cmd.rlen = 4;
450*4882a593Smuzhiyun 	ret = si2157_cmd_execute(client, &cmd);
451*4882a593Smuzhiyun 	if (ret)
452*4882a593Smuzhiyun 		goto err;
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 	if (dev->chiptype == SI2157_CHIPTYPE_SI2146)
455*4882a593Smuzhiyun 		memcpy(cmd.args, "\x14\x00\x02\x07\x00\x01", 6);
456*4882a593Smuzhiyun 	else
457*4882a593Smuzhiyun 		memcpy(cmd.args, "\x14\x00\x02\x07\x00\x00", 6);
458*4882a593Smuzhiyun 	cmd.args[4] = dev->if_port;
459*4882a593Smuzhiyun 	cmd.wlen = 6;
460*4882a593Smuzhiyun 	cmd.rlen = 4;
461*4882a593Smuzhiyun 	ret = si2157_cmd_execute(client, &cmd);
462*4882a593Smuzhiyun 	if (ret)
463*4882a593Smuzhiyun 		goto err;
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun 	/* set digital if frequency if needed */
466*4882a593Smuzhiyun 	if (if_frequency != dev->if_frequency) {
467*4882a593Smuzhiyun 		memcpy(cmd.args, "\x14\x00\x06\x07", 4);
468*4882a593Smuzhiyun 		cmd.args[4] = (if_frequency / 1000) & 0xff;
469*4882a593Smuzhiyun 		cmd.args[5] = ((if_frequency / 1000) >> 8) & 0xff;
470*4882a593Smuzhiyun 		cmd.wlen = 6;
471*4882a593Smuzhiyun 		cmd.rlen = 4;
472*4882a593Smuzhiyun 		ret = si2157_cmd_execute(client, &cmd);
473*4882a593Smuzhiyun 		if (ret)
474*4882a593Smuzhiyun 			goto err;
475*4882a593Smuzhiyun 
476*4882a593Smuzhiyun 		dev->if_frequency = if_frequency;
477*4882a593Smuzhiyun 	}
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun 	/* set digital frequency */
480*4882a593Smuzhiyun 	memcpy(cmd.args, "\x41\x00\x00\x00\x00\x00\x00\x00", 8);
481*4882a593Smuzhiyun 	cmd.args[4] = (c->frequency >>  0) & 0xff;
482*4882a593Smuzhiyun 	cmd.args[5] = (c->frequency >>  8) & 0xff;
483*4882a593Smuzhiyun 	cmd.args[6] = (c->frequency >> 16) & 0xff;
484*4882a593Smuzhiyun 	cmd.args[7] = (c->frequency >> 24) & 0xff;
485*4882a593Smuzhiyun 	cmd.wlen = 8;
486*4882a593Smuzhiyun 	cmd.rlen = 1;
487*4882a593Smuzhiyun 	ret = si2157_cmd_execute(client, &cmd);
488*4882a593Smuzhiyun 	if (ret)
489*4882a593Smuzhiyun 		goto err;
490*4882a593Smuzhiyun 
491*4882a593Smuzhiyun 	dev->bandwidth = bandwidth;
492*4882a593Smuzhiyun 	dev->frequency = c->frequency;
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun 	si2157_tune_wait(client, 1); /* wait to complete, ignore any errors */
495*4882a593Smuzhiyun 
496*4882a593Smuzhiyun 	return 0;
497*4882a593Smuzhiyun err:
498*4882a593Smuzhiyun 	dev->bandwidth = 0;
499*4882a593Smuzhiyun 	dev->frequency = 0;
500*4882a593Smuzhiyun 	dev->if_frequency = 0;
501*4882a593Smuzhiyun 	dev_dbg(&client->dev, "failed=%d\n", ret);
502*4882a593Smuzhiyun 	return ret;
503*4882a593Smuzhiyun }
504*4882a593Smuzhiyun 
si2157_set_analog_params(struct dvb_frontend * fe,struct analog_parameters * params)505*4882a593Smuzhiyun static int si2157_set_analog_params(struct dvb_frontend *fe,
506*4882a593Smuzhiyun 				    struct analog_parameters *params)
507*4882a593Smuzhiyun {
508*4882a593Smuzhiyun 	struct i2c_client *client = fe->tuner_priv;
509*4882a593Smuzhiyun 	struct si2157_dev *dev = i2c_get_clientdata(client);
510*4882a593Smuzhiyun 	char *std; /* for debugging */
511*4882a593Smuzhiyun 	int ret;
512*4882a593Smuzhiyun 	struct si2157_cmd cmd;
513*4882a593Smuzhiyun 	u32 bandwidth = 0;
514*4882a593Smuzhiyun 	u32 if_frequency = 0;
515*4882a593Smuzhiyun 	u32 freq = 0;
516*4882a593Smuzhiyun 	u64 tmp_lval = 0;
517*4882a593Smuzhiyun 	u8 system = 0;
518*4882a593Smuzhiyun 	u8 color = 0;    /* 0=NTSC/PAL, 0x10=SECAM */
519*4882a593Smuzhiyun 	u8 invert_analog = 1; /* analog tuner spectrum; 0=normal, 1=inverted */
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun 	if (dev->chiptype != SI2157_CHIPTYPE_SI2157) {
522*4882a593Smuzhiyun 		dev_info(&client->dev, "Analog tuning not supported for chiptype=%u\n",
523*4882a593Smuzhiyun 			 dev->chiptype);
524*4882a593Smuzhiyun 		ret = -EINVAL;
525*4882a593Smuzhiyun 		goto err;
526*4882a593Smuzhiyun 	}
527*4882a593Smuzhiyun 
528*4882a593Smuzhiyun 	if (!dev->active)
529*4882a593Smuzhiyun 		si2157_init(fe);
530*4882a593Smuzhiyun 
531*4882a593Smuzhiyun 	if (!dev->active) {
532*4882a593Smuzhiyun 		ret = -EAGAIN;
533*4882a593Smuzhiyun 		goto err;
534*4882a593Smuzhiyun 	}
535*4882a593Smuzhiyun 	if (params->mode == V4L2_TUNER_RADIO) {
536*4882a593Smuzhiyun 	/*
537*4882a593Smuzhiyun 	 * std = "fm";
538*4882a593Smuzhiyun 	 * bandwidth = 1700000; //best can do for FM, AGC will be a mess though
539*4882a593Smuzhiyun 	 * if_frequency = 1250000;  //HVR-225x(saa7164), HVR-12xx(cx23885)
540*4882a593Smuzhiyun 	 * if_frequency = 6600000;  //HVR-9xx(cx231xx)
541*4882a593Smuzhiyun 	 * if_frequency = 5500000;  //HVR-19xx(pvrusb2)
542*4882a593Smuzhiyun 	 */
543*4882a593Smuzhiyun 		dev_err(&client->dev, "si2157 does not currently support FM radio\n");
544*4882a593Smuzhiyun 		ret = -EINVAL;
545*4882a593Smuzhiyun 		goto err;
546*4882a593Smuzhiyun 	}
547*4882a593Smuzhiyun 	tmp_lval = params->frequency * 625LL;
548*4882a593Smuzhiyun 	do_div(tmp_lval, 10); /* convert to HZ */
549*4882a593Smuzhiyun 	freq = (u32)tmp_lval;
550*4882a593Smuzhiyun 
551*4882a593Smuzhiyun 	if (freq < 1000000) /* is freq in KHz */
552*4882a593Smuzhiyun 		freq = freq * 1000;
553*4882a593Smuzhiyun 	dev->frequency = freq;
554*4882a593Smuzhiyun 
555*4882a593Smuzhiyun 	/* if_frequency values based on tda187271C2 */
556*4882a593Smuzhiyun 	if (params->std & (V4L2_STD_B | V4L2_STD_GH)) {
557*4882a593Smuzhiyun 		if (freq >= 470000000) {
558*4882a593Smuzhiyun 			std = "palGH";
559*4882a593Smuzhiyun 			bandwidth = 8000000;
560*4882a593Smuzhiyun 			if_frequency = 6000000;
561*4882a593Smuzhiyun 			system = 1;
562*4882a593Smuzhiyun 			if (params->std &
563*4882a593Smuzhiyun 			    (V4L2_STD_SECAM_G | V4L2_STD_SECAM_H)) {
564*4882a593Smuzhiyun 				std = "secamGH";
565*4882a593Smuzhiyun 				color = 0x10;
566*4882a593Smuzhiyun 			}
567*4882a593Smuzhiyun 		} else {
568*4882a593Smuzhiyun 			std = "palB";
569*4882a593Smuzhiyun 			bandwidth = 7000000;
570*4882a593Smuzhiyun 			if_frequency = 6000000;
571*4882a593Smuzhiyun 			system = 0;
572*4882a593Smuzhiyun 			if (params->std & V4L2_STD_SECAM_B) {
573*4882a593Smuzhiyun 				std = "secamB";
574*4882a593Smuzhiyun 				color = 0x10;
575*4882a593Smuzhiyun 			}
576*4882a593Smuzhiyun 		}
577*4882a593Smuzhiyun 	} else if (params->std & V4L2_STD_MN) {
578*4882a593Smuzhiyun 		std = "MN";
579*4882a593Smuzhiyun 		bandwidth = 6000000;
580*4882a593Smuzhiyun 		if_frequency = 5400000;
581*4882a593Smuzhiyun 		system = 2;
582*4882a593Smuzhiyun 	} else if (params->std & V4L2_STD_PAL_I) {
583*4882a593Smuzhiyun 		std = "palI";
584*4882a593Smuzhiyun 		bandwidth = 8000000;
585*4882a593Smuzhiyun 		if_frequency = 7250000; /* TODO: does not work yet */
586*4882a593Smuzhiyun 		system = 4;
587*4882a593Smuzhiyun 	} else if (params->std & V4L2_STD_DK) {
588*4882a593Smuzhiyun 		std = "palDK";
589*4882a593Smuzhiyun 		bandwidth = 8000000;
590*4882a593Smuzhiyun 		if_frequency = 6900000; /* TODO: does not work yet */
591*4882a593Smuzhiyun 		system = 5;
592*4882a593Smuzhiyun 		if (params->std & V4L2_STD_SECAM_DK) {
593*4882a593Smuzhiyun 			std = "secamDK";
594*4882a593Smuzhiyun 			color = 0x10;
595*4882a593Smuzhiyun 		}
596*4882a593Smuzhiyun 	} else if (params->std & V4L2_STD_SECAM_L) {
597*4882a593Smuzhiyun 		std = "secamL";
598*4882a593Smuzhiyun 		bandwidth = 8000000;
599*4882a593Smuzhiyun 		if_frequency = 6750000; /* TODO: untested */
600*4882a593Smuzhiyun 		system = 6;
601*4882a593Smuzhiyun 		color = 0x10;
602*4882a593Smuzhiyun 	} else if (params->std & V4L2_STD_SECAM_LC) {
603*4882a593Smuzhiyun 		std = "secamL'";
604*4882a593Smuzhiyun 		bandwidth = 7000000;
605*4882a593Smuzhiyun 		if_frequency = 1250000; /* TODO: untested */
606*4882a593Smuzhiyun 		system = 7;
607*4882a593Smuzhiyun 		color = 0x10;
608*4882a593Smuzhiyun 	} else {
609*4882a593Smuzhiyun 		std = "unknown";
610*4882a593Smuzhiyun 	}
611*4882a593Smuzhiyun 	/* calc channel center freq */
612*4882a593Smuzhiyun 	freq = freq - 1250000 + (bandwidth / 2);
613*4882a593Smuzhiyun 
614*4882a593Smuzhiyun 	dev_dbg(&client->dev,
615*4882a593Smuzhiyun 		"mode=%d system=%u std='%s' params->frequency=%u center freq=%u if=%u bandwidth=%u\n",
616*4882a593Smuzhiyun 		params->mode, system, std, params->frequency,
617*4882a593Smuzhiyun 		freq, if_frequency, bandwidth);
618*4882a593Smuzhiyun 
619*4882a593Smuzhiyun 	/* set analog IF port */
620*4882a593Smuzhiyun 	memcpy(cmd.args, "\x14\x00\x03\x06\x08\x02", 6);
621*4882a593Smuzhiyun 	/* in using dev->if_port, we assume analog and digital IF's */
622*4882a593Smuzhiyun 	/*   are always on different ports */
623*4882a593Smuzhiyun 	/* assumes if_port definition is 0 or 1 for digital out */
624*4882a593Smuzhiyun 	cmd.args[4] = (dev->if_port == 1) ? 8 : 10;
625*4882a593Smuzhiyun 	/* Analog AGC assumed external */
626*4882a593Smuzhiyun 	cmd.args[5] = (dev->if_port == 1) ? 2 : 1;
627*4882a593Smuzhiyun 	cmd.wlen = 6;
628*4882a593Smuzhiyun 	cmd.rlen = 4;
629*4882a593Smuzhiyun 	ret = si2157_cmd_execute(client, &cmd);
630*4882a593Smuzhiyun 	if (ret)
631*4882a593Smuzhiyun 		goto err;
632*4882a593Smuzhiyun 
633*4882a593Smuzhiyun 	/* set analog IF output config */
634*4882a593Smuzhiyun 	memcpy(cmd.args, "\x14\x00\x0d\x06\x94\x64", 6);
635*4882a593Smuzhiyun 	cmd.wlen = 6;
636*4882a593Smuzhiyun 	cmd.rlen = 4;
637*4882a593Smuzhiyun 	ret = si2157_cmd_execute(client, &cmd);
638*4882a593Smuzhiyun 	if (ret)
639*4882a593Smuzhiyun 		goto err;
640*4882a593Smuzhiyun 
641*4882a593Smuzhiyun 	/* make this distinct from a digital IF */
642*4882a593Smuzhiyun 	dev->if_frequency = if_frequency | 1;
643*4882a593Smuzhiyun 
644*4882a593Smuzhiyun 	/* calc and set tuner analog if center frequency */
645*4882a593Smuzhiyun 	if_frequency = if_frequency + 1250000 - (bandwidth / 2);
646*4882a593Smuzhiyun 	dev_dbg(&client->dev, "IF Ctr freq=%d\n", if_frequency);
647*4882a593Smuzhiyun 
648*4882a593Smuzhiyun 	memcpy(cmd.args, "\x14\x00\x0C\x06", 4);
649*4882a593Smuzhiyun 	cmd.args[4] = (if_frequency / 1000) & 0xff;
650*4882a593Smuzhiyun 	cmd.args[5] = ((if_frequency / 1000) >> 8) & 0xff;
651*4882a593Smuzhiyun 	cmd.wlen = 6;
652*4882a593Smuzhiyun 	cmd.rlen = 4;
653*4882a593Smuzhiyun 	ret = si2157_cmd_execute(client, &cmd);
654*4882a593Smuzhiyun 	if (ret)
655*4882a593Smuzhiyun 		goto err;
656*4882a593Smuzhiyun 
657*4882a593Smuzhiyun 	/* set analog AGC config */
658*4882a593Smuzhiyun 	memcpy(cmd.args, "\x14\x00\x07\x06\x32\xc8", 6);
659*4882a593Smuzhiyun 	cmd.wlen = 6;
660*4882a593Smuzhiyun 	cmd.rlen = 4;
661*4882a593Smuzhiyun 	ret = si2157_cmd_execute(client, &cmd);
662*4882a593Smuzhiyun 	if (ret)
663*4882a593Smuzhiyun 		goto err;
664*4882a593Smuzhiyun 
665*4882a593Smuzhiyun 	/* set analog video mode */
666*4882a593Smuzhiyun 	memcpy(cmd.args, "\x14\x00\x04\x06\x00\x00", 6);
667*4882a593Smuzhiyun 	cmd.args[4] = system | color;
668*4882a593Smuzhiyun 	/* can use dev->inversion if assumed applies to both digital/analog */
669*4882a593Smuzhiyun 	if (invert_analog)
670*4882a593Smuzhiyun 		cmd.args[5] |= 0x02;
671*4882a593Smuzhiyun 	cmd.wlen = 6;
672*4882a593Smuzhiyun 	cmd.rlen = 1;
673*4882a593Smuzhiyun 	ret = si2157_cmd_execute(client, &cmd);
674*4882a593Smuzhiyun 	if (ret)
675*4882a593Smuzhiyun 		goto err;
676*4882a593Smuzhiyun 
677*4882a593Smuzhiyun 	/* set analog frequency */
678*4882a593Smuzhiyun 	memcpy(cmd.args, "\x41\x01\x00\x00\x00\x00\x00\x00", 8);
679*4882a593Smuzhiyun 	cmd.args[4] = (freq >>  0) & 0xff;
680*4882a593Smuzhiyun 	cmd.args[5] = (freq >>  8) & 0xff;
681*4882a593Smuzhiyun 	cmd.args[6] = (freq >> 16) & 0xff;
682*4882a593Smuzhiyun 	cmd.args[7] = (freq >> 24) & 0xff;
683*4882a593Smuzhiyun 	cmd.wlen = 8;
684*4882a593Smuzhiyun 	cmd.rlen = 1;
685*4882a593Smuzhiyun 	ret = si2157_cmd_execute(client, &cmd);
686*4882a593Smuzhiyun 	if (ret)
687*4882a593Smuzhiyun 		goto err;
688*4882a593Smuzhiyun 
689*4882a593Smuzhiyun 	dev->bandwidth = bandwidth;
690*4882a593Smuzhiyun 
691*4882a593Smuzhiyun 	si2157_tune_wait(client, 0); /* wait to complete, ignore any errors */
692*4882a593Smuzhiyun 
693*4882a593Smuzhiyun 	return 0;
694*4882a593Smuzhiyun err:
695*4882a593Smuzhiyun 	dev->bandwidth = 0;
696*4882a593Smuzhiyun 	dev->frequency = 0;
697*4882a593Smuzhiyun 	dev->if_frequency = 0;
698*4882a593Smuzhiyun 	dev_dbg(&client->dev, "failed=%d\n", ret);
699*4882a593Smuzhiyun 	return ret;
700*4882a593Smuzhiyun }
701*4882a593Smuzhiyun 
si2157_get_frequency(struct dvb_frontend * fe,u32 * frequency)702*4882a593Smuzhiyun static int si2157_get_frequency(struct dvb_frontend *fe, u32 *frequency)
703*4882a593Smuzhiyun {
704*4882a593Smuzhiyun 	struct i2c_client *client = fe->tuner_priv;
705*4882a593Smuzhiyun 	struct si2157_dev *dev = i2c_get_clientdata(client);
706*4882a593Smuzhiyun 
707*4882a593Smuzhiyun 	*frequency = dev->frequency;
708*4882a593Smuzhiyun 	dev_dbg(&client->dev, "freq=%u\n", dev->frequency);
709*4882a593Smuzhiyun 	return 0;
710*4882a593Smuzhiyun }
711*4882a593Smuzhiyun 
si2157_get_bandwidth(struct dvb_frontend * fe,u32 * bandwidth)712*4882a593Smuzhiyun static int si2157_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
713*4882a593Smuzhiyun {
714*4882a593Smuzhiyun 	struct i2c_client *client = fe->tuner_priv;
715*4882a593Smuzhiyun 	struct si2157_dev *dev = i2c_get_clientdata(client);
716*4882a593Smuzhiyun 
717*4882a593Smuzhiyun 	*bandwidth = dev->bandwidth;
718*4882a593Smuzhiyun 	dev_dbg(&client->dev, "bandwidth=%u\n", dev->bandwidth);
719*4882a593Smuzhiyun 	return 0;
720*4882a593Smuzhiyun }
721*4882a593Smuzhiyun 
si2157_get_if_frequency(struct dvb_frontend * fe,u32 * frequency)722*4882a593Smuzhiyun static int si2157_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
723*4882a593Smuzhiyun {
724*4882a593Smuzhiyun 	struct i2c_client *client = fe->tuner_priv;
725*4882a593Smuzhiyun 	struct si2157_dev *dev = i2c_get_clientdata(client);
726*4882a593Smuzhiyun 
727*4882a593Smuzhiyun 	*frequency = dev->if_frequency & ~1; /* strip analog IF indicator bit */
728*4882a593Smuzhiyun 	dev_dbg(&client->dev, "if_frequency=%u\n", *frequency);
729*4882a593Smuzhiyun 	return 0;
730*4882a593Smuzhiyun }
731*4882a593Smuzhiyun 
si2157_get_rf_strength(struct dvb_frontend * fe,u16 * rssi)732*4882a593Smuzhiyun static int si2157_get_rf_strength(struct dvb_frontend *fe, u16 *rssi)
733*4882a593Smuzhiyun {
734*4882a593Smuzhiyun 	struct i2c_client *client = fe->tuner_priv;
735*4882a593Smuzhiyun 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
736*4882a593Smuzhiyun 	struct si2157_cmd cmd;
737*4882a593Smuzhiyun 	int ret;
738*4882a593Smuzhiyun 	int strength;
739*4882a593Smuzhiyun 
740*4882a593Smuzhiyun 	dev_dbg(&client->dev, "\n");
741*4882a593Smuzhiyun 
742*4882a593Smuzhiyun 	memcpy(cmd.args, "\x42\x00", 2);
743*4882a593Smuzhiyun 	cmd.wlen = 2;
744*4882a593Smuzhiyun 	cmd.rlen = 12;
745*4882a593Smuzhiyun 	ret = si2157_cmd_execute(client, &cmd);
746*4882a593Smuzhiyun 	if (ret)
747*4882a593Smuzhiyun 		goto err;
748*4882a593Smuzhiyun 
749*4882a593Smuzhiyun 	c->strength.stat[0].scale = FE_SCALE_DECIBEL;
750*4882a593Smuzhiyun 	c->strength.stat[0].svalue = (s8)cmd.args[3] * 1000;
751*4882a593Smuzhiyun 
752*4882a593Smuzhiyun 	/* normalize values based on Silicon Labs reference
753*4882a593Smuzhiyun 	 * add 100, then anything > 80 is 100% signal
754*4882a593Smuzhiyun 	 */
755*4882a593Smuzhiyun 	strength = (s8)cmd.args[3] + 100;
756*4882a593Smuzhiyun 	strength = clamp_val(strength, 0, 80);
757*4882a593Smuzhiyun 	*rssi = (u16)(strength * 0xffff / 80);
758*4882a593Smuzhiyun 
759*4882a593Smuzhiyun 	dev_dbg(&client->dev, "strength=%d rssi=%u\n",
760*4882a593Smuzhiyun 		(s8)cmd.args[3], *rssi);
761*4882a593Smuzhiyun 
762*4882a593Smuzhiyun 	return 0;
763*4882a593Smuzhiyun err:
764*4882a593Smuzhiyun 	dev_dbg(&client->dev, "failed=%d\n", ret);
765*4882a593Smuzhiyun 	return ret;
766*4882a593Smuzhiyun }
767*4882a593Smuzhiyun 
768*4882a593Smuzhiyun static const struct dvb_tuner_ops si2157_ops = {
769*4882a593Smuzhiyun 	.info = {
770*4882a593Smuzhiyun 		.name             = "Silicon Labs Si2141/Si2146/2147/2148/2157/2158",
771*4882a593Smuzhiyun 		.frequency_min_hz =  42 * MHz,
772*4882a593Smuzhiyun 		.frequency_max_hz = 870 * MHz,
773*4882a593Smuzhiyun 	},
774*4882a593Smuzhiyun 
775*4882a593Smuzhiyun 	.init = si2157_init,
776*4882a593Smuzhiyun 	.sleep = si2157_sleep,
777*4882a593Smuzhiyun 	.set_params = si2157_set_params,
778*4882a593Smuzhiyun 	.set_analog_params = si2157_set_analog_params,
779*4882a593Smuzhiyun 	.get_frequency     = si2157_get_frequency,
780*4882a593Smuzhiyun 	.get_bandwidth     = si2157_get_bandwidth,
781*4882a593Smuzhiyun 	.get_if_frequency  = si2157_get_if_frequency,
782*4882a593Smuzhiyun 
783*4882a593Smuzhiyun 	.get_rf_strength   = si2157_get_rf_strength,
784*4882a593Smuzhiyun };
785*4882a593Smuzhiyun 
si2157_stat_work(struct work_struct * work)786*4882a593Smuzhiyun static void si2157_stat_work(struct work_struct *work)
787*4882a593Smuzhiyun {
788*4882a593Smuzhiyun 	struct si2157_dev *dev = container_of(work, struct si2157_dev, stat_work.work);
789*4882a593Smuzhiyun 	struct dvb_frontend *fe = dev->fe;
790*4882a593Smuzhiyun 	struct i2c_client *client = fe->tuner_priv;
791*4882a593Smuzhiyun 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
792*4882a593Smuzhiyun 	struct si2157_cmd cmd;
793*4882a593Smuzhiyun 	int ret;
794*4882a593Smuzhiyun 
795*4882a593Smuzhiyun 	dev_dbg(&client->dev, "\n");
796*4882a593Smuzhiyun 
797*4882a593Smuzhiyun 	memcpy(cmd.args, "\x42\x00", 2);
798*4882a593Smuzhiyun 	cmd.wlen = 2;
799*4882a593Smuzhiyun 	cmd.rlen = 12;
800*4882a593Smuzhiyun 	ret = si2157_cmd_execute(client, &cmd);
801*4882a593Smuzhiyun 	if (ret)
802*4882a593Smuzhiyun 		goto err;
803*4882a593Smuzhiyun 
804*4882a593Smuzhiyun 	c->strength.stat[0].scale = FE_SCALE_DECIBEL;
805*4882a593Smuzhiyun 	c->strength.stat[0].svalue = (s8) cmd.args[3] * 1000;
806*4882a593Smuzhiyun 
807*4882a593Smuzhiyun 	schedule_delayed_work(&dev->stat_work, msecs_to_jiffies(2000));
808*4882a593Smuzhiyun 	return;
809*4882a593Smuzhiyun err:
810*4882a593Smuzhiyun 	c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
811*4882a593Smuzhiyun 	dev_dbg(&client->dev, "failed=%d\n", ret);
812*4882a593Smuzhiyun }
813*4882a593Smuzhiyun 
si2157_probe(struct i2c_client * client,const struct i2c_device_id * id)814*4882a593Smuzhiyun static int si2157_probe(struct i2c_client *client,
815*4882a593Smuzhiyun 			const struct i2c_device_id *id)
816*4882a593Smuzhiyun {
817*4882a593Smuzhiyun 	struct si2157_config *cfg = client->dev.platform_data;
818*4882a593Smuzhiyun 	struct dvb_frontend *fe = cfg->fe;
819*4882a593Smuzhiyun 	struct si2157_dev *dev;
820*4882a593Smuzhiyun 	struct si2157_cmd cmd;
821*4882a593Smuzhiyun 	int ret;
822*4882a593Smuzhiyun 
823*4882a593Smuzhiyun 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
824*4882a593Smuzhiyun 	if (!dev) {
825*4882a593Smuzhiyun 		ret = -ENOMEM;
826*4882a593Smuzhiyun 		dev_err(&client->dev, "kzalloc() failed\n");
827*4882a593Smuzhiyun 		goto err;
828*4882a593Smuzhiyun 	}
829*4882a593Smuzhiyun 
830*4882a593Smuzhiyun 	i2c_set_clientdata(client, dev);
831*4882a593Smuzhiyun 	dev->fe = cfg->fe;
832*4882a593Smuzhiyun 	dev->inversion = cfg->inversion;
833*4882a593Smuzhiyun 	dev->dont_load_firmware = cfg->dont_load_firmware;
834*4882a593Smuzhiyun 	dev->if_port = cfg->if_port;
835*4882a593Smuzhiyun 	dev->chiptype = (u8)id->driver_data;
836*4882a593Smuzhiyun 	dev->if_frequency = 5000000; /* default value of property 0x0706 */
837*4882a593Smuzhiyun 	mutex_init(&dev->i2c_mutex);
838*4882a593Smuzhiyun 	INIT_DELAYED_WORK(&dev->stat_work, si2157_stat_work);
839*4882a593Smuzhiyun 
840*4882a593Smuzhiyun 	/* check if the tuner is there */
841*4882a593Smuzhiyun 	cmd.wlen = 0;
842*4882a593Smuzhiyun 	cmd.rlen = 1;
843*4882a593Smuzhiyun 	ret = si2157_cmd_execute(client, &cmd);
844*4882a593Smuzhiyun 	if (ret && ret != -EAGAIN)
845*4882a593Smuzhiyun 		goto err_kfree;
846*4882a593Smuzhiyun 
847*4882a593Smuzhiyun 	memcpy(&fe->ops.tuner_ops, &si2157_ops, sizeof(struct dvb_tuner_ops));
848*4882a593Smuzhiyun 	fe->tuner_priv = client;
849*4882a593Smuzhiyun 
850*4882a593Smuzhiyun #ifdef CONFIG_MEDIA_CONTROLLER
851*4882a593Smuzhiyun 	if (cfg->mdev) {
852*4882a593Smuzhiyun 		dev->mdev = cfg->mdev;
853*4882a593Smuzhiyun 
854*4882a593Smuzhiyun 		dev->ent.name = KBUILD_MODNAME;
855*4882a593Smuzhiyun 		dev->ent.function = MEDIA_ENT_F_TUNER;
856*4882a593Smuzhiyun 
857*4882a593Smuzhiyun 		dev->pad[SI2157_PAD_RF_INPUT].flags = MEDIA_PAD_FL_SINK;
858*4882a593Smuzhiyun 		dev->pad[SI2157_PAD_RF_INPUT].sig_type = PAD_SIGNAL_ANALOG;
859*4882a593Smuzhiyun 		dev->pad[SI2157_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE;
860*4882a593Smuzhiyun 		dev->pad[SI2157_PAD_VID_OUT].sig_type = PAD_SIGNAL_ANALOG;
861*4882a593Smuzhiyun 		dev->pad[SI2157_PAD_AUD_OUT].flags = MEDIA_PAD_FL_SOURCE;
862*4882a593Smuzhiyun 		dev->pad[SI2157_PAD_AUD_OUT].sig_type = PAD_SIGNAL_AUDIO;
863*4882a593Smuzhiyun 
864*4882a593Smuzhiyun 		ret = media_entity_pads_init(&dev->ent, SI2157_NUM_PADS,
865*4882a593Smuzhiyun 					     &dev->pad[0]);
866*4882a593Smuzhiyun 
867*4882a593Smuzhiyun 		if (ret)
868*4882a593Smuzhiyun 			goto err_kfree;
869*4882a593Smuzhiyun 
870*4882a593Smuzhiyun 		ret = media_device_register_entity(cfg->mdev, &dev->ent);
871*4882a593Smuzhiyun 		if (ret) {
872*4882a593Smuzhiyun 			media_entity_cleanup(&dev->ent);
873*4882a593Smuzhiyun 			goto err_kfree;
874*4882a593Smuzhiyun 		}
875*4882a593Smuzhiyun 	}
876*4882a593Smuzhiyun #endif
877*4882a593Smuzhiyun 
878*4882a593Smuzhiyun 	dev_info(&client->dev, "Silicon Labs %s successfully attached\n",
879*4882a593Smuzhiyun 			dev->chiptype == SI2157_CHIPTYPE_SI2141 ?  "Si2141" :
880*4882a593Smuzhiyun 			dev->chiptype == SI2157_CHIPTYPE_SI2146 ?
881*4882a593Smuzhiyun 			"Si2146" : "Si2147/2148/2157/2158");
882*4882a593Smuzhiyun 
883*4882a593Smuzhiyun 	return 0;
884*4882a593Smuzhiyun 
885*4882a593Smuzhiyun err_kfree:
886*4882a593Smuzhiyun 	kfree(dev);
887*4882a593Smuzhiyun err:
888*4882a593Smuzhiyun 	dev_dbg(&client->dev, "failed=%d\n", ret);
889*4882a593Smuzhiyun 	return ret;
890*4882a593Smuzhiyun }
891*4882a593Smuzhiyun 
si2157_remove(struct i2c_client * client)892*4882a593Smuzhiyun static int si2157_remove(struct i2c_client *client)
893*4882a593Smuzhiyun {
894*4882a593Smuzhiyun 	struct si2157_dev *dev = i2c_get_clientdata(client);
895*4882a593Smuzhiyun 	struct dvb_frontend *fe = dev->fe;
896*4882a593Smuzhiyun 
897*4882a593Smuzhiyun 	dev_dbg(&client->dev, "\n");
898*4882a593Smuzhiyun 
899*4882a593Smuzhiyun 	/* stop statistics polling */
900*4882a593Smuzhiyun 	cancel_delayed_work_sync(&dev->stat_work);
901*4882a593Smuzhiyun 
902*4882a593Smuzhiyun #ifdef CONFIG_MEDIA_CONTROLLER_DVB
903*4882a593Smuzhiyun 	if (dev->mdev)
904*4882a593Smuzhiyun 		media_device_unregister_entity(&dev->ent);
905*4882a593Smuzhiyun #endif
906*4882a593Smuzhiyun 
907*4882a593Smuzhiyun 	memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
908*4882a593Smuzhiyun 	fe->tuner_priv = NULL;
909*4882a593Smuzhiyun 	kfree(dev);
910*4882a593Smuzhiyun 
911*4882a593Smuzhiyun 	return 0;
912*4882a593Smuzhiyun }
913*4882a593Smuzhiyun 
914*4882a593Smuzhiyun static const struct i2c_device_id si2157_id_table[] = {
915*4882a593Smuzhiyun 	{"si2157", SI2157_CHIPTYPE_SI2157},
916*4882a593Smuzhiyun 	{"si2146", SI2157_CHIPTYPE_SI2146},
917*4882a593Smuzhiyun 	{"si2141", SI2157_CHIPTYPE_SI2141},
918*4882a593Smuzhiyun 	{"si2177", SI2157_CHIPTYPE_SI2177},
919*4882a593Smuzhiyun 	{}
920*4882a593Smuzhiyun };
921*4882a593Smuzhiyun MODULE_DEVICE_TABLE(i2c, si2157_id_table);
922*4882a593Smuzhiyun 
923*4882a593Smuzhiyun static struct i2c_driver si2157_driver = {
924*4882a593Smuzhiyun 	.driver = {
925*4882a593Smuzhiyun 		.name		     = "si2157",
926*4882a593Smuzhiyun 		.suppress_bind_attrs = true,
927*4882a593Smuzhiyun 	},
928*4882a593Smuzhiyun 	.probe		= si2157_probe,
929*4882a593Smuzhiyun 	.remove		= si2157_remove,
930*4882a593Smuzhiyun 	.id_table	= si2157_id_table,
931*4882a593Smuzhiyun };
932*4882a593Smuzhiyun 
933*4882a593Smuzhiyun module_i2c_driver(si2157_driver);
934*4882a593Smuzhiyun 
935*4882a593Smuzhiyun MODULE_DESCRIPTION("Silicon Labs Si2141/Si2146/2147/2148/2157/2158 silicon tuner driver");
936*4882a593Smuzhiyun MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
937*4882a593Smuzhiyun MODULE_LICENSE("GPL");
938*4882a593Smuzhiyun MODULE_FIRMWARE(SI2158_A20_FIRMWARE);
939*4882a593Smuzhiyun MODULE_FIRMWARE(SI2141_A10_FIRMWARE);
940*4882a593Smuzhiyun MODULE_FIRMWARE(SI2157_A30_FIRMWARE);
941