aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAntti Palosaari <crope@iki.fi>2014-04-10 21:00:50 -0400
committerMauro Carvalho Chehab <m.chehab@samsung.com>2014-04-23 08:50:23 -0400
commit845f35052ea94661dd32d80fc95a93d0502345e2 (patch)
treed62879de0b6475480d0f31051b5f7587875265be
parent930a873081986393f6e7e0fb9275753c1485277b (diff)
[media] si2168: Silicon Labs Si2168 DVB-T/T2/C demod driver
Silicon Labs Si2168 DVB-T/T2/C demod driver. That driver version supports only DVB-T. Signed-off-by: Antti Palosaari <crope@iki.fi> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
-rw-r--r--drivers/media/dvb-frontends/Kconfig7
-rw-r--r--drivers/media/dvb-frontends/Makefile1
-rw-r--r--drivers/media/dvb-frontends/si2168.c708
-rw-r--r--drivers/media/dvb-frontends/si2168.h23
-rw-r--r--drivers/media/dvb-frontends/si2168_priv.h30
5 files changed, 769 insertions, 0 deletions
diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig
index 025fc5496bfc..1469d44acb22 100644
--- a/drivers/media/dvb-frontends/Kconfig
+++ b/drivers/media/dvb-frontends/Kconfig
@@ -446,6 +446,13 @@ config DVB_RTL2832
446 help 446 help
447 Say Y when you want to support this frontend. 447 Say Y when you want to support this frontend.
448 448
449config DVB_SI2168
450 tristate "Silicon Labs Si2168"
451 depends on DVB_CORE && I2C && I2C_MUX
452 default m if !MEDIA_SUBDRV_AUTOSELECT
453 help
454 Say Y when you want to support this frontend.
455
449comment "DVB-C (cable) frontends" 456comment "DVB-C (cable) frontends"
450 depends on DVB_CORE 457 depends on DVB_CORE
451 458
diff --git a/drivers/media/dvb-frontends/Makefile b/drivers/media/dvb-frontends/Makefile
index 282aba2fe8db..dda0bee36f29 100644
--- a/drivers/media/dvb-frontends/Makefile
+++ b/drivers/media/dvb-frontends/Makefile
@@ -78,6 +78,7 @@ obj-$(CONFIG_DVB_AF9013) += af9013.o
78obj-$(CONFIG_DVB_CX24116) += cx24116.o 78obj-$(CONFIG_DVB_CX24116) += cx24116.o
79obj-$(CONFIG_DVB_CX24117) += cx24117.o 79obj-$(CONFIG_DVB_CX24117) += cx24117.o
80obj-$(CONFIG_DVB_SI21XX) += si21xx.o 80obj-$(CONFIG_DVB_SI21XX) += si21xx.o
81obj-$(CONFIG_DVB_SI2168) += si2168.o
81obj-$(CONFIG_DVB_STV0288) += stv0288.o 82obj-$(CONFIG_DVB_STV0288) += stv0288.o
82obj-$(CONFIG_DVB_STB6000) += stb6000.o 83obj-$(CONFIG_DVB_STB6000) += stb6000.o
83obj-$(CONFIG_DVB_S921) += s921.o 84obj-$(CONFIG_DVB_S921) += s921.o
diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c
new file mode 100644
index 000000000000..eef4e456548d
--- /dev/null
+++ b/drivers/media/dvb-frontends/si2168.c
@@ -0,0 +1,708 @@
1#include "si2168_priv.h"
2
3static const struct dvb_frontend_ops si2168_ops;
4
5/* execute firmware command */
6static int si2168_cmd_execute(struct si2168 *s, struct si2168_cmd *cmd)
7{
8 int ret;
9 unsigned long timeout;
10
11 mutex_lock(&s->i2c_mutex);
12
13 if (cmd->wlen) {
14 /* write cmd and args for firmware */
15 ret = i2c_master_send(s->client, cmd->args, cmd->wlen);
16 if (ret < 0) {
17 goto err_mutex_unlock;
18 } else if (ret != cmd->wlen) {
19 ret = -EREMOTEIO;
20 goto err_mutex_unlock;
21 }
22 }
23
24 if (cmd->rlen) {
25 /* wait cmd execution terminate */
26 #define TIMEOUT 50
27 timeout = jiffies + msecs_to_jiffies(TIMEOUT);
28 while (!time_after(jiffies, timeout)) {
29 ret = i2c_master_recv(s->client, cmd->args, cmd->rlen);
30 if (ret < 0) {
31 goto err_mutex_unlock;
32 } else if (ret != cmd->rlen) {
33 ret = -EREMOTEIO;
34 goto err_mutex_unlock;
35 }
36
37 /* firmware ready? */
38 if ((cmd->args[0] >> 7) & 0x01)
39 break;
40 }
41
42 dev_dbg(&s->client->dev, "%s: cmd execution took %d ms\n",
43 __func__,
44 jiffies_to_msecs(jiffies) -
45 (jiffies_to_msecs(timeout) - TIMEOUT));
46
47 if (!(cmd->args[0] >> 7) & 0x01) {
48 ret = -ETIMEDOUT;
49 goto err_mutex_unlock;
50 }
51 }
52
53 ret = 0;
54
55err_mutex_unlock:
56 mutex_unlock(&s->i2c_mutex);
57 if (ret)
58 goto err;
59
60 return 0;
61err:
62 dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
63 return ret;
64}
65
66static int si2168_read_status(struct dvb_frontend *fe, fe_status_t *status)
67{
68 struct si2168 *s = fe->demodulator_priv;
69 int ret;
70 struct si2168_cmd cmd;
71
72 *status = 0;
73
74 if (!s->active) {
75 ret = -EAGAIN;
76 goto err;
77 }
78
79 cmd.args[0] = 0xa0;
80 cmd.args[1] = 0x01;
81 cmd.wlen = 2;
82 cmd.rlen = 13;
83 ret = si2168_cmd_execute(s, &cmd);
84 if (ret)
85 goto err;
86
87 /*
88 * Possible values seen, in order from strong signal to weak:
89 * 16 0001 0110 full lock
90 * 1e 0001 1110 partial lock
91 * 1a 0001 1010 partial lock
92 * 18 0001 1000 no lock
93 *
94 * [b3:b1] lock bits
95 * [b4] statistics ready? Set in a few secs after lock is gained.
96 */
97
98 switch ((cmd.args[2] >> 0) & 0x0f) {
99 case 0x0a:
100 *status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
101 break;
102 case 0x0e:
103 *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI;
104 break;
105 case 0x06:
106 *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI |
107 FE_HAS_SYNC | FE_HAS_LOCK;
108 break;
109 }
110
111 s->fe_status = *status;
112
113 dev_dbg(&s->client->dev, "%s: status=%02x args=%*ph\n",
114 __func__, *status, cmd.rlen, cmd.args);
115
116 return 0;
117err:
118 dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
119 return ret;
120}
121
122static int si2168_set_frontend(struct dvb_frontend *fe)
123{
124 struct si2168 *s = fe->demodulator_priv;
125 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
126 int ret;
127 struct si2168_cmd cmd;
128 u8 bandwidth;
129
130 dev_dbg(&s->client->dev,
131 "%s: delivery_system=%u modulation=%u frequency=%u bandwidth_hz=%u symbol_rate=%u inversion=%u\n",
132 __func__, c->delivery_system, c->modulation,
133 c->frequency, c->bandwidth_hz, c->symbol_rate,
134 c->inversion);
135
136 if (!s->active) {
137 ret = -EAGAIN;
138 goto err;
139 }
140
141 switch (c->bandwidth_hz) {
142 case 5000000:
143 bandwidth = 0x25;
144 break;
145 case 6000000:
146 bandwidth = 0x26;
147 break;
148 case 7000000:
149 bandwidth = 0x27;
150 break;
151 case 8000000:
152 bandwidth = 0x28;
153 break;
154 default:
155 ret = -EINVAL;
156 goto err;
157 }
158
159 /* program tuner */
160 if (fe->ops.tuner_ops.set_params) {
161 ret = fe->ops.tuner_ops.set_params(fe);
162 if (ret)
163 goto err;
164 }
165
166 memcpy(cmd.args, "\x88\x02\x02\x02\x02", 5);
167 cmd.wlen = 5;
168 cmd.rlen = 5;
169 ret = si2168_cmd_execute(s, &cmd);
170 if (ret)
171 goto err;
172
173 memcpy(cmd.args, "\x89\x21\x06\x11\xff\x98", 6);
174 cmd.wlen = 6;
175 cmd.rlen = 3;
176 ret = si2168_cmd_execute(s, &cmd);
177 if (ret)
178 goto err;
179
180 memcpy(cmd.args, "\x51\x03", 2);
181 cmd.wlen = 2;
182 cmd.rlen = 12;
183 ret = si2168_cmd_execute(s, &cmd);
184 if (ret)
185 goto err;
186
187 memcpy(cmd.args, "\x12\x08\x04", 3);
188 cmd.wlen = 3;
189 cmd.rlen = 3;
190 ret = si2168_cmd_execute(s, &cmd);
191 if (ret)
192 goto err;
193
194 memcpy(cmd.args, "\x14\x00\x01\x04\x00\x00", 6);
195 cmd.wlen = 6;
196 cmd.rlen = 1;
197 ret = si2168_cmd_execute(s, &cmd);
198 if (ret)
199 goto err;
200
201 memcpy(cmd.args, "\x14\x00\x03\x10\x17\x00", 6);
202 cmd.wlen = 6;
203 cmd.rlen = 1;
204 ret = si2168_cmd_execute(s, &cmd);
205 if (ret)
206 goto err;
207
208 memcpy(cmd.args, "\x14\x00\x02\x10\x15\x00", 6);
209 cmd.wlen = 6;
210 cmd.rlen = 1;
211 ret = si2168_cmd_execute(s, &cmd);
212 if (ret)
213 goto err;
214
215 memcpy(cmd.args, "\x14\x00\x0c\x10\x12\x00", 6);
216 cmd.wlen = 6;
217 cmd.rlen = 1;
218 ret = si2168_cmd_execute(s, &cmd);
219 if (ret)
220 goto err;
221
222 memcpy(cmd.args, "\x14\x00\x06\x10\x24\x00", 6);
223 cmd.wlen = 6;
224 cmd.rlen = 1;
225 ret = si2168_cmd_execute(s, &cmd);
226 if (ret)
227 goto err;
228
229 memcpy(cmd.args, "\x14\x00\x0b\x10\x88\x13", 6);
230 cmd.wlen = 6;
231 cmd.rlen = 1;
232 ret = si2168_cmd_execute(s, &cmd);
233 if (ret)
234 goto err;
235
236 memcpy(cmd.args, "\x14\x00\x07\x10\x00\x24", 6);
237 cmd.wlen = 6;
238 cmd.rlen = 1;
239 ret = si2168_cmd_execute(s, &cmd);
240 if (ret)
241 goto err;
242
243 memcpy(cmd.args, "\x14\x00\x0a\x10\x00\x00", 6);
244 cmd.args[4] = bandwidth;
245 cmd.wlen = 6;
246 cmd.rlen = 1;
247 ret = si2168_cmd_execute(s, &cmd);
248 if (ret)
249 goto err;
250
251 memcpy(cmd.args, "\x14\x00\x04\x10\x15\x00", 6);
252 cmd.wlen = 6;
253 cmd.rlen = 1;
254 ret = si2168_cmd_execute(s, &cmd);
255 if (ret)
256 goto err;
257
258 memcpy(cmd.args, "\x14\x00\x05\x10\xa1\x00", 6);
259 cmd.wlen = 6;
260 cmd.rlen = 1;
261 ret = si2168_cmd_execute(s, &cmd);
262 if (ret)
263 goto err;
264
265 memcpy(cmd.args, "\x14\x00\x0f\x10\x10\x00", 6);
266 cmd.wlen = 6;
267 cmd.rlen = 1;
268 ret = si2168_cmd_execute(s, &cmd);
269 if (ret)
270 goto err;
271
272 memcpy(cmd.args, "\x14\x00\x0d\x10\xd0\x02", 6);
273 cmd.wlen = 6;
274 cmd.rlen = 1;
275 ret = si2168_cmd_execute(s, &cmd);
276 if (ret)
277 goto err;
278
279 memcpy(cmd.args, "\x14\x00\x01\x10\x00\x00", 6);
280 cmd.wlen = 6;
281 cmd.rlen = 1;
282 ret = si2168_cmd_execute(s, &cmd);
283 if (ret)
284 goto err;
285
286 memcpy(cmd.args, "\x14\x00\x09\x10\xe3\x18", 6);
287 cmd.wlen = 6;
288 cmd.rlen = 1;
289 ret = si2168_cmd_execute(s, &cmd);
290 if (ret)
291 goto err;
292
293 memcpy(cmd.args, "\x14\x00\x08\x10\xd7\x15", 6);
294 cmd.wlen = 6;
295 cmd.rlen = 1;
296 ret = si2168_cmd_execute(s, &cmd);
297 if (ret)
298 goto err;
299
300 memcpy(cmd.args, "\x14\x00\x04\x03\x00\x00", 6);
301 cmd.wlen = 6;
302 cmd.rlen = 1;
303 ret = si2168_cmd_execute(s, &cmd);
304 if (ret)
305 goto err;
306
307 memcpy(cmd.args, "\x14\x00\x03\x03\x00\x00", 6);
308 cmd.wlen = 6;
309 cmd.rlen = 1;
310 ret = si2168_cmd_execute(s, &cmd);
311 if (ret)
312 goto err;
313
314 memcpy(cmd.args, "\x14\x00\x08\x03\x00\x00", 6);
315 cmd.wlen = 6;
316 cmd.rlen = 1;
317 ret = si2168_cmd_execute(s, &cmd);
318 if (ret)
319 goto err;
320
321 memcpy(cmd.args, "\x14\x00\x07\x03\x01\x02", 6);
322 cmd.wlen = 6;
323 cmd.rlen = 1;
324 ret = si2168_cmd_execute(s, &cmd);
325 if (ret)
326 goto err;
327
328 memcpy(cmd.args, "\x14\x00\x06\x03\x00\x00", 6);
329 cmd.wlen = 6;
330 cmd.rlen = 1;
331 ret = si2168_cmd_execute(s, &cmd);
332 if (ret)
333 goto err;
334
335 memcpy(cmd.args, "\x14\x00\x05\x03\x00\x00", 6);
336 cmd.wlen = 6;
337 cmd.rlen = 1;
338 ret = si2168_cmd_execute(s, &cmd);
339 if (ret)
340 goto err;
341
342 memcpy(cmd.args, "\x14\x00\x01\x03\x0c\x40", 6);
343 cmd.wlen = 6;
344 cmd.rlen = 1;
345 ret = si2168_cmd_execute(s, &cmd);
346 if (ret)
347 goto err;
348
349 memcpy(cmd.args, "\x14\x00\x01\x10\x16\x00", 6);
350 cmd.wlen = 6;
351 cmd.rlen = 1;
352 ret = si2168_cmd_execute(s, &cmd);
353 if (ret)
354 goto err;
355
356 memcpy(cmd.args, "\x14\x00\x01\x12\x00\x00", 6);
357 cmd.wlen = 6;
358 cmd.rlen = 1;
359 ret = si2168_cmd_execute(s, &cmd);
360 if (ret)
361 goto err;
362
363 cmd.args[0] = 0x85;
364 cmd.wlen = 1;
365 cmd.rlen = 1;
366 ret = si2168_cmd_execute(s, &cmd);
367 if (ret)
368 goto err;
369
370 s->delivery_system = c->delivery_system;
371
372 return 0;
373err:
374 dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
375 return ret;
376}
377
378static int si2168_init(struct dvb_frontend *fe)
379{
380 struct si2168 *s = fe->demodulator_priv;
381 int ret, len, remaining;
382 const struct firmware *fw = NULL;
383 u8 *fw_file = SI2168_FIRMWARE;
384 const unsigned int i2c_wr_max = 8;
385 struct si2168_cmd cmd;
386
387 dev_dbg(&s->client->dev, "%s:\n", __func__);
388
389 cmd.args[0] = 0x13;
390 cmd.wlen = 1;
391 cmd.rlen = 0;
392 ret = si2168_cmd_execute(s, &cmd);
393 if (ret)
394 goto err;
395
396 cmd.args[0] = 0xc0;
397 cmd.args[1] = 0x12;
398 cmd.args[2] = 0x00;
399 cmd.args[3] = 0x0c;
400 cmd.args[4] = 0x00;
401 cmd.args[5] = 0x0d;
402 cmd.args[6] = 0x16;
403 cmd.args[7] = 0x00;
404 cmd.args[8] = 0x00;
405 cmd.args[9] = 0x00;
406 cmd.args[10] = 0x00;
407 cmd.args[11] = 0x00;
408 cmd.args[12] = 0x00;
409 cmd.wlen = 13;
410 cmd.rlen = 0;
411 ret = si2168_cmd_execute(s, &cmd);
412 if (ret)
413 goto err;
414
415 cmd.args[0] = 0xc0;
416 cmd.args[1] = 0x06;
417 cmd.args[2] = 0x01;
418 cmd.args[3] = 0x0f;
419 cmd.args[4] = 0x00;
420 cmd.args[5] = 0x20;
421 cmd.args[6] = 0x20;
422 cmd.args[7] = 0x01;
423 cmd.wlen = 8;
424 cmd.rlen = 1;
425 ret = si2168_cmd_execute(s, &cmd);
426 if (ret)
427 goto err;
428
429 cmd.args[0] = 0x02;
430 cmd.wlen = 1;
431 cmd.rlen = 13;
432 ret = si2168_cmd_execute(s, &cmd);
433 if (ret)
434 goto err;
435
436 cmd.args[0] = 0x05;
437 cmd.args[1] = 0x00;
438 cmd.args[2] = 0xaa;
439 cmd.args[3] = 0x4d;
440 cmd.args[4] = 0x56;
441 cmd.args[5] = 0x40;
442 cmd.args[6] = 0x00;
443 cmd.args[7] = 0x00;
444 cmd.wlen = 8;
445 cmd.rlen = 1;
446 ret = si2168_cmd_execute(s, &cmd);
447 if (ret)
448 goto err;
449
450 /* cold state - try to download firmware */
451 dev_info(&s->client->dev, "%s: found a '%s' in cold state\n",
452 KBUILD_MODNAME, si2168_ops.info.name);
453
454 /* request the firmware, this will block and timeout */
455 ret = request_firmware(&fw, fw_file, &s->client->dev);
456 if (ret) {
457 dev_err(&s->client->dev, "%s: firmare file '%s' not found\n",
458 KBUILD_MODNAME, fw_file);
459 goto err;
460 }
461
462 dev_info(&s->client->dev, "%s: downloading firmware from file '%s'\n",
463 KBUILD_MODNAME, fw_file);
464
465 for (remaining = fw->size; remaining > 0; remaining -= i2c_wr_max) {
466 len = remaining;
467 if (len > i2c_wr_max)
468 len = i2c_wr_max;
469
470 memcpy(cmd.args, &fw->data[fw->size - remaining], len);
471 cmd.wlen = len;
472 cmd.rlen = 1;
473 ret = si2168_cmd_execute(s, &cmd);
474 if (ret) {
475 dev_err(&s->client->dev,
476 "%s: firmware download failed=%d\n",
477 KBUILD_MODNAME, ret);
478 goto err;
479 }
480 }
481
482 release_firmware(fw);
483 fw = NULL;
484
485 cmd.args[0] = 0x01;
486 cmd.args[1] = 0x01;
487 cmd.wlen = 2;
488 cmd.rlen = 1;
489 ret = si2168_cmd_execute(s, &cmd);
490 if (ret)
491 goto err;
492
493 dev_info(&s->client->dev, "%s: found a '%s' in warm state\n",
494 KBUILD_MODNAME, si2168_ops.info.name);
495
496 s->active = true;
497
498 return 0;
499err:
500 if (fw)
501 release_firmware(fw);
502
503 dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
504 return ret;
505}
506
507static int si2168_sleep(struct dvb_frontend *fe)
508{
509 struct si2168 *s = fe->demodulator_priv;
510
511 dev_dbg(&s->client->dev, "%s:\n", __func__);
512
513 s->active = false;
514
515 return 0;
516}
517
518static int si2168_get_tune_settings(struct dvb_frontend *fe,
519 struct dvb_frontend_tune_settings *s)
520{
521 s->min_delay_ms = 900;
522
523 return 0;
524}
525
526/*
527 * I2C gate logic
528 * We must use unlocked i2c_transfer() here because I2C lock is already taken
529 * by tuner driver.
530 */
531static int si2168_select(struct i2c_adapter *adap, void *mux_priv, u32 chan)
532{
533 struct si2168 *s = mux_priv;
534 int ret;
535 struct i2c_msg gate_open_msg = {
536 .addr = s->client->addr,
537 .flags = 0,
538 .len = 3,
539 .buf = "\xc0\x0d\x01",
540 };
541
542 mutex_lock(&s->i2c_mutex);
543
544 /* open tuner I2C gate */
545 ret = __i2c_transfer(s->client->adapter, &gate_open_msg, 1);
546 if (ret != 1) {
547 dev_warn(&s->client->dev, "%s: i2c write failed=%d\n",
548 KBUILD_MODNAME, ret);
549 if (ret >= 0)
550 ret = -EREMOTEIO;
551 } else {
552 ret = 0;
553 }
554
555 return ret;
556}
557
558static int si2168_deselect(struct i2c_adapter *adap, void *mux_priv, u32 chan)
559{
560 struct si2168 *s = mux_priv;
561 int ret;
562 struct i2c_msg gate_close_msg = {
563 .addr = s->client->addr,
564 .flags = 0,
565 .len = 3,
566 .buf = "\xc0\x0d\x00",
567 };
568
569 /* close tuner I2C gate */
570 ret = __i2c_transfer(s->client->adapter, &gate_close_msg, 1);
571 if (ret != 1) {
572 dev_warn(&s->client->dev, "%s: i2c write failed=%d\n",
573 KBUILD_MODNAME, ret);
574 if (ret >= 0)
575 ret = -EREMOTEIO;
576 } else {
577 ret = 0;
578 }
579
580 mutex_unlock(&s->i2c_mutex);
581
582 return ret;
583}
584
585static const struct dvb_frontend_ops si2168_ops = {
586 .delsys = {SYS_DVBT},
587 .info = {
588 .name = "Silicon Labs Si2168",
589 .caps = FE_CAN_FEC_1_2 |
590 FE_CAN_FEC_2_3 |
591 FE_CAN_FEC_3_4 |
592 FE_CAN_FEC_5_6 |
593 FE_CAN_FEC_7_8 |
594 FE_CAN_FEC_AUTO |
595 FE_CAN_QPSK |
596 FE_CAN_QAM_16 |
597 FE_CAN_QAM_32 |
598 FE_CAN_QAM_64 |
599 FE_CAN_QAM_128 |
600 FE_CAN_QAM_256 |
601 FE_CAN_QAM_AUTO |
602 FE_CAN_TRANSMISSION_MODE_AUTO |
603 FE_CAN_GUARD_INTERVAL_AUTO |
604 FE_CAN_HIERARCHY_AUTO |
605 FE_CAN_MUTE_TS |
606 FE_CAN_2G_MODULATION
607 },
608
609 .get_tune_settings = si2168_get_tune_settings,
610
611 .init = si2168_init,
612 .sleep = si2168_sleep,
613
614 .set_frontend = si2168_set_frontend,
615
616 .read_status = si2168_read_status,
617};
618
619static int si2168_probe(struct i2c_client *client,
620 const struct i2c_device_id *id)
621{
622 struct si2168_config *config = client->dev.platform_data;
623 struct si2168 *s;
624 int ret;
625 struct si2168_cmd cmd;
626
627 dev_dbg(&client->dev, "%s:\n", __func__);
628
629 s = kzalloc(sizeof(struct si2168), GFP_KERNEL);
630 if (!s) {
631 ret = -ENOMEM;
632 dev_err(&client->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME);
633 goto err;
634 }
635
636 s->client = client;
637 mutex_init(&s->i2c_mutex);
638
639 /* check if the demod is there */
640 cmd.wlen = 0;
641 cmd.rlen = 1;
642 ret = si2168_cmd_execute(s, &cmd);
643 if (ret)
644 goto err;
645
646 /* create mux i2c adapter for tuner */
647 s->adapter = i2c_add_mux_adapter(client->adapter, &client->dev, s,
648 0, 0, 0, si2168_select, si2168_deselect);
649 if (s->adapter == NULL)
650 goto err;
651
652 /* create dvb_frontend */
653 memcpy(&s->fe.ops, &si2168_ops, sizeof(struct dvb_frontend_ops));
654 s->fe.demodulator_priv = s;
655
656 *config->i2c_adapter = s->adapter;
657 *config->fe = &s->fe;
658
659 i2c_set_clientdata(client, s);
660
661 dev_info(&s->client->dev,
662 "%s: Silicon Labs Si2168 successfully attached\n",
663 KBUILD_MODNAME);
664 return 0;
665err:
666 kfree(s);
667 dev_dbg(&client->dev, "%s: failed=%d\n", __func__, ret);
668 return ret;
669}
670
671static int si2168_remove(struct i2c_client *client)
672{
673 struct si2168 *s = i2c_get_clientdata(client);
674
675 dev_dbg(&client->dev, "%s:\n", __func__);
676
677 i2c_del_mux_adapter(s->adapter);
678
679 s->fe.ops.release = NULL;
680 s->fe.demodulator_priv = NULL;
681
682 kfree(s);
683
684 return 0;
685}
686
687static const struct i2c_device_id si2168_id[] = {
688 {"si2168", 0},
689 {}
690};
691MODULE_DEVICE_TABLE(i2c, si2168_id);
692
693static struct i2c_driver si2168_driver = {
694 .driver = {
695 .owner = THIS_MODULE,
696 .name = "si2168",
697 },
698 .probe = si2168_probe,
699 .remove = si2168_remove,
700 .id_table = si2168_id,
701};
702
703module_i2c_driver(si2168_driver);
704
705MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
706MODULE_DESCRIPTION("Silicon Labs Si2168 DVB-T/T2/C demodulator driver");
707MODULE_LICENSE("GPL");
708MODULE_FIRMWARE(SI2168_FIRMWARE);
diff --git a/drivers/media/dvb-frontends/si2168.h b/drivers/media/dvb-frontends/si2168.h
new file mode 100644
index 000000000000..5a801aa382f7
--- /dev/null
+++ b/drivers/media/dvb-frontends/si2168.h
@@ -0,0 +1,23 @@
1#ifndef SI2168_H
2#define SI2168_H
3
4#include <linux/dvb/frontend.h>
5/*
6 * I2C address
7 * 0x64
8 */
9struct si2168_config {
10 /*
11 * frontend
12 * returned by driver
13 */
14 struct dvb_frontend **fe;
15
16 /*
17 * tuner I2C adapter
18 * returned by driver
19 */
20 struct i2c_adapter **i2c_adapter;
21};
22
23#endif
diff --git a/drivers/media/dvb-frontends/si2168_priv.h b/drivers/media/dvb-frontends/si2168_priv.h
new file mode 100644
index 000000000000..36463246c6a8
--- /dev/null
+++ b/drivers/media/dvb-frontends/si2168_priv.h
@@ -0,0 +1,30 @@
1#ifndef SI2168_PRIV_H
2#define SI2168_PRIV_H
3
4#include "si2168.h"
5#include "dvb_frontend.h"
6#include <linux/firmware.h>
7#include <linux/i2c-mux.h>
8
9#define SI2168_FIRMWARE "dvb-demod-si2168-01.fw"
10
11/* state struct */
12struct si2168 {
13 struct i2c_client *client;
14 struct i2c_adapter *adapter;
15 struct mutex i2c_mutex;
16 struct dvb_frontend fe;
17 fe_delivery_system_t delivery_system;
18 fe_status_t fe_status;
19 bool active;
20};
21
22/* firmare command struct */
23#define SI2157_ARGLEN 30
24struct si2168_cmd {
25 u8 args[SI2157_ARGLEN];
26 unsigned wlen;
27 unsigned rlen;
28};
29
30#endif