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