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