aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/media/dvb/frontends/Kconfig7
-rw-r--r--drivers/media/dvb/frontends/Makefile2
-rw-r--r--drivers/media/dvb/frontends/cxd2820r.c886
-rw-r--r--drivers/media/dvb/frontends/cxd2820r.h118
-rw-r--r--drivers/media/dvb/frontends/cxd2820r_c.c336
-rw-r--r--drivers/media/dvb/frontends/cxd2820r_priv.h77
-rw-r--r--drivers/media/dvb/frontends/cxd2820r_t.c447
-rw-r--r--drivers/media/dvb/frontends/cxd2820r_t2.c421
8 files changed, 2294 insertions, 0 deletions
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index 7ceb02d95ecf..44b816f2601e 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -383,6 +383,13 @@ config DVB_STV0367
383 help 383 help
384 A DVB-T/C tuner module. Say Y when you want to support this frontend. 384 A DVB-T/C tuner module. Say Y when you want to support this frontend.
385 385
386config DVB_CXD2820R
387 tristate "Sony CXD2820R"
388 depends on DVB_CORE && I2C
389 default m if DVB_FE_CUSTOMISE
390 help
391 Say Y when you want to support this frontend.
392
386comment "DVB-C (cable) frontends" 393comment "DVB-C (cable) frontends"
387 depends on DVB_CORE 394 depends on DVB_CORE
388 395
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 6d5192935889..adec1a3f6291 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -86,3 +86,5 @@ obj-$(CONFIG_DVB_MB86A16) += mb86a16.o
86obj-$(CONFIG_DVB_MB86A20S) += mb86a20s.o 86obj-$(CONFIG_DVB_MB86A20S) += mb86a20s.o
87obj-$(CONFIG_DVB_IX2505V) += ix2505v.o 87obj-$(CONFIG_DVB_IX2505V) += ix2505v.o
88obj-$(CONFIG_DVB_STV0367) += stv0367.o 88obj-$(CONFIG_DVB_STV0367) += stv0367.o
89obj-$(CONFIG_DVB_CXD2820R) += cxd2820r.o
90
diff --git a/drivers/media/dvb/frontends/cxd2820r.c b/drivers/media/dvb/frontends/cxd2820r.c
new file mode 100644
index 000000000000..b58f92c75116
--- /dev/null
+++ b/drivers/media/dvb/frontends/cxd2820r.c
@@ -0,0 +1,886 @@
1/*
2 * Sony CXD2820R demodulator driver
3 *
4 * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21
22#include "cxd2820r_priv.h"
23
24int cxd2820r_debug;
25module_param_named(debug, cxd2820r_debug, int, 0644);
26MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
27
28/* TODO: temporary hack, will be removed later when there is app support */
29unsigned int cxd2820r_dvbt2_freq[5];
30int cxd2820r_dvbt2_count;
31module_param_array_named(dvbt2_freq, cxd2820r_dvbt2_freq, int,
32 &cxd2820r_dvbt2_count, 0644);
33MODULE_PARM_DESC(dvbt2_freq, "RF frequencies forced to DVB-T2 (unit Hz)");
34
35/* write multiple registers */
36static int cxd2820r_wr_regs_i2c(struct cxd2820r_priv *priv, u8 i2c, u8 reg,
37 u8 *val, int len)
38{
39 int ret;
40 u8 buf[len+1];
41 struct i2c_msg msg[1] = {
42 {
43 .addr = i2c,
44 .flags = 0,
45 .len = sizeof(buf),
46 .buf = buf,
47 }
48 };
49
50 buf[0] = reg;
51 memcpy(&buf[1], val, len);
52
53 ret = i2c_transfer(priv->i2c, msg, 1);
54 if (ret == 1) {
55 ret = 0;
56 } else {
57 warn("i2c wr failed ret:%d reg:%02x len:%d", ret, reg, len);
58 ret = -EREMOTEIO;
59 }
60 return ret;
61}
62
63/* read multiple registers */
64static int cxd2820r_rd_regs_i2c(struct cxd2820r_priv *priv, u8 i2c, u8 reg,
65 u8 *val, int len)
66{
67 int ret;
68 u8 buf[len];
69 struct i2c_msg msg[2] = {
70 {
71 .addr = i2c,
72 .flags = 0,
73 .len = 1,
74 .buf = &reg,
75 }, {
76 .addr = i2c,
77 .flags = I2C_M_RD,
78 .len = sizeof(buf),
79 .buf = buf,
80 }
81 };
82
83 ret = i2c_transfer(priv->i2c, msg, 2);
84 if (ret == 2) {
85 memcpy(val, buf, len);
86 ret = 0;
87 } else {
88 warn("i2c rd failed ret:%d reg:%02x len:%d", ret, reg, len);
89 ret = -EREMOTEIO;
90 }
91
92 return ret;
93}
94
95/* write multiple registers */
96static int cxd2820r_wr_regs(struct cxd2820r_priv *priv, u32 reginfo, u8 *val,
97 int len)
98{
99 int ret;
100 u8 i2c_addr;
101 u8 reg = (reginfo >> 0) & 0xff;
102 u8 bank = (reginfo >> 8) & 0xff;
103 u8 i2c = (reginfo >> 16) & 0x01;
104
105 /* select I2C */
106 if (i2c)
107 i2c_addr = priv->cfg.i2c_address | (1 << 1); /* DVB-C */
108 else
109 i2c_addr = priv->cfg.i2c_address; /* DVB-T/T2 */
110
111 /* switch bank if needed */
112 if (bank != priv->bank[i2c]) {
113 ret = cxd2820r_wr_regs_i2c(priv, i2c_addr, 0x00, &bank, 1);
114 if (ret)
115 return ret;
116 priv->bank[i2c] = bank;
117 }
118 return cxd2820r_wr_regs_i2c(priv, i2c_addr, reg, val, len);
119}
120
121/* read multiple registers */
122static int cxd2820r_rd_regs(struct cxd2820r_priv *priv, u32 reginfo, u8 *val,
123 int len)
124{
125 int ret;
126 u8 i2c_addr;
127 u8 reg = (reginfo >> 0) & 0xff;
128 u8 bank = (reginfo >> 8) & 0xff;
129 u8 i2c = (reginfo >> 16) & 0x01;
130
131 /* select I2C */
132 if (i2c)
133 i2c_addr = priv->cfg.i2c_address | (1 << 1); /* DVB-C */
134 else
135 i2c_addr = priv->cfg.i2c_address; /* DVB-T/T2 */
136
137 /* switch bank if needed */
138 if (bank != priv->bank[i2c]) {
139 ret = cxd2820r_wr_regs_i2c(priv, i2c_addr, 0x00, &bank, 1);
140 if (ret)
141 return ret;
142 priv->bank[i2c] = bank;
143 }
144 return cxd2820r_rd_regs_i2c(priv, i2c_addr, reg, val, len);
145}
146
147/* write single register */
148static int cxd2820r_wr_reg(struct cxd2820r_priv *priv, u32 reg, u8 val)
149{
150 return cxd2820r_wr_regs(priv, reg, &val, 1);
151}
152
153/* read single register */
154static int cxd2820r_rd_reg(struct cxd2820r_priv *priv, u32 reg, u8 *val)
155{
156 return cxd2820r_rd_regs(priv, reg, val, 1);
157}
158
159/* write single register with mask */
160static int cxd2820r_wr_reg_mask(struct cxd2820r_priv *priv, u32 reg, u8 val,
161 u8 mask)
162{
163 int ret;
164 u8 tmp;
165
166 /* no need for read if whole reg is written */
167 if (mask != 0xff) {
168 ret = cxd2820r_rd_reg(priv, reg, &tmp);
169 if (ret)
170 return ret;
171
172 val &= mask;
173 tmp &= ~mask;
174 val |= tmp;
175 }
176
177 return cxd2820r_wr_reg(priv, reg, val);
178}
179
180static int cxd2820r_gpio(struct dvb_frontend *fe)
181{
182 struct cxd2820r_priv *priv = fe->demodulator_priv;
183 int ret, i;
184 u8 *gpio, tmp0, tmp1;
185 dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
186
187 switch (fe->dtv_property_cache.delivery_system) {
188 case SYS_DVBT:
189 gpio = priv->cfg.gpio_dvbt;
190 break;
191 case SYS_DVBT2:
192 gpio = priv->cfg.gpio_dvbt2;
193 break;
194 case SYS_DVBC_ANNEX_AC:
195 gpio = priv->cfg.gpio_dvbc;
196 break;
197 default:
198 ret = -EINVAL;
199 goto error;
200 }
201
202 /* update GPIOs only when needed */
203 if (!memcmp(gpio, priv->gpio, sizeof(priv->gpio)))
204 return 0;
205
206 tmp0 = 0x00;
207 tmp1 = 0x00;
208 for (i = 0; i < sizeof(priv->gpio); i++) {
209 /* enable / disable */
210 if (gpio[i] & CXD2820R_GPIO_E)
211 tmp0 |= (2 << 6) >> (2 * i);
212 else
213 tmp0 |= (1 << 6) >> (2 * i);
214
215 /* input / output */
216 if (gpio[i] & CXD2820R_GPIO_I)
217 tmp1 |= (1 << (3 + i));
218 else
219 tmp1 |= (0 << (3 + i));
220
221 /* high / low */
222 if (gpio[i] & CXD2820R_GPIO_H)
223 tmp1 |= (1 << (0 + i));
224 else
225 tmp1 |= (0 << (0 + i));
226
227 dbg("%s: GPIO i=%d %02x %02x", __func__, i, tmp0, tmp1);
228 }
229
230 dbg("%s: wr gpio=%02x %02x", __func__, tmp0, tmp1);
231
232 /* write bits [7:2] */
233 ret = cxd2820r_wr_reg_mask(priv, 0x00089, tmp0, 0xfc);
234 if (ret)
235 goto error;
236
237 /* write bits [5:0] */
238 ret = cxd2820r_wr_reg_mask(priv, 0x0008e, tmp1, 0x3f);
239 if (ret)
240 goto error;
241
242 memcpy(priv->gpio, gpio, sizeof(priv->gpio));
243
244 return ret;
245error:
246 dbg("%s: failed:%d", __func__, ret);
247 return ret;
248}
249
250/* lock FE */
251static int cxd2820r_lock(struct cxd2820r_priv *priv, int active_fe)
252{
253 int ret = 0;
254 dbg("%s: active_fe=%d", __func__, active_fe);
255
256 mutex_lock(&priv->fe_lock);
257
258 /* -1=NONE, 0=DVB-T/T2, 1=DVB-C */
259 if (priv->active_fe == active_fe)
260 ;
261 else if (priv->active_fe == -1)
262 priv->active_fe = active_fe;
263 else
264 ret = -EBUSY;
265
266 mutex_unlock(&priv->fe_lock);
267
268 return ret;
269}
270
271/* unlock FE */
272static void cxd2820r_unlock(struct cxd2820r_priv *priv, int active_fe)
273{
274 dbg("%s: active_fe=%d", __func__, active_fe);
275
276 mutex_lock(&priv->fe_lock);
277
278 /* -1=NONE, 0=DVB-T/T2, 1=DVB-C */
279 if (priv->active_fe == active_fe)
280 priv->active_fe = -1;
281
282 mutex_unlock(&priv->fe_lock);
283
284 return;
285}
286
287/* 64 bit div with round closest, like DIV_ROUND_CLOSEST but 64 bit */
288static u32 cxd2820r_div_u64_round_closest(u64 dividend, u32 divisor)
289{
290 return div_u64(dividend + (divisor / 2), divisor);
291}
292
293/* TODO: ... */
294#include "cxd2820r_t.c"
295#include "cxd2820r_c.c"
296#include "cxd2820r_t2.c"
297
298static int cxd2820r_set_frontend(struct dvb_frontend *fe,
299 struct dvb_frontend_parameters *p)
300{
301 struct cxd2820r_priv *priv = fe->demodulator_priv;
302 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
303 int ret;
304 dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
305
306 if (fe->ops.info.type == FE_OFDM) {
307 /* DVB-T/T2 */
308 ret = cxd2820r_lock(priv, 0);
309 if (ret)
310 return ret;
311
312 switch (priv->delivery_system) {
313 case SYS_UNDEFINED:
314 if (c->delivery_system == SYS_DVBT) {
315 /* SLEEP => DVB-T */
316 ret = cxd2820r_set_frontend_t(fe, p);
317 } else {
318 /* SLEEP => DVB-T2 */
319 ret = cxd2820r_set_frontend_t2(fe, p);
320 }
321 break;
322 case SYS_DVBT:
323 if (c->delivery_system == SYS_DVBT) {
324 /* DVB-T => DVB-T */
325 ret = cxd2820r_set_frontend_t(fe, p);
326 } else if (c->delivery_system == SYS_DVBT2) {
327 /* DVB-T => DVB-T2 */
328 ret = cxd2820r_sleep_t(fe);
329 ret = cxd2820r_set_frontend_t2(fe, p);
330 }
331 break;
332 case SYS_DVBT2:
333 if (c->delivery_system == SYS_DVBT2) {
334 /* DVB-T2 => DVB-T2 */
335 ret = cxd2820r_set_frontend_t2(fe, p);
336 } else if (c->delivery_system == SYS_DVBT) {
337 /* DVB-T2 => DVB-T */
338 ret = cxd2820r_sleep_t2(fe);
339 ret = cxd2820r_set_frontend_t(fe, p);
340 }
341 break;
342 default:
343 dbg("%s: error state=%d", __func__,
344 priv->delivery_system);
345 ret = -EINVAL;
346 }
347 } else {
348 /* DVB-C */
349 ret = cxd2820r_lock(priv, 1);
350 if (ret)
351 return ret;
352
353 ret = cxd2820r_set_frontend_c(fe, p);
354 }
355
356 return ret;
357}
358
359static int cxd2820r_read_status(struct dvb_frontend *fe, fe_status_t *status)
360{
361 struct cxd2820r_priv *priv = fe->demodulator_priv;
362 int ret;
363 dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
364
365 if (fe->ops.info.type == FE_OFDM) {
366 /* DVB-T/T2 */
367 ret = cxd2820r_lock(priv, 0);
368 if (ret)
369 return ret;
370
371 switch (fe->dtv_property_cache.delivery_system) {
372 case SYS_DVBT:
373 ret = cxd2820r_read_status_t(fe, status);
374 break;
375 case SYS_DVBT2:
376 ret = cxd2820r_read_status_t2(fe, status);
377 break;
378 default:
379 ret = -EINVAL;
380 }
381 } else {
382 /* DVB-C */
383 ret = cxd2820r_lock(priv, 1);
384 if (ret)
385 return ret;
386
387 ret = cxd2820r_read_status_c(fe, status);
388 }
389
390 return ret;
391}
392
393static int cxd2820r_get_frontend(struct dvb_frontend *fe,
394 struct dvb_frontend_parameters *p)
395{
396 struct cxd2820r_priv *priv = fe->demodulator_priv;
397 int ret;
398 dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
399
400 if (fe->ops.info.type == FE_OFDM) {
401 /* DVB-T/T2 */
402 ret = cxd2820r_lock(priv, 0);
403 if (ret)
404 return ret;
405
406 switch (fe->dtv_property_cache.delivery_system) {
407 case SYS_DVBT:
408 ret = cxd2820r_get_frontend_t(fe, p);
409 break;
410 case SYS_DVBT2:
411 ret = cxd2820r_get_frontend_t2(fe, p);
412 break;
413 default:
414 ret = -EINVAL;
415 }
416 } else {
417 /* DVB-C */
418 ret = cxd2820r_lock(priv, 1);
419 if (ret)
420 return ret;
421
422 ret = cxd2820r_get_frontend_c(fe, p);
423 }
424
425 return ret;
426}
427
428static int cxd2820r_read_ber(struct dvb_frontend *fe, u32 *ber)
429{
430 struct cxd2820r_priv *priv = fe->demodulator_priv;
431 int ret;
432 dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
433
434 if (fe->ops.info.type == FE_OFDM) {
435 /* DVB-T/T2 */
436 ret = cxd2820r_lock(priv, 0);
437 if (ret)
438 return ret;
439
440 switch (fe->dtv_property_cache.delivery_system) {
441 case SYS_DVBT:
442 ret = cxd2820r_read_ber_t(fe, ber);
443 break;
444 case SYS_DVBT2:
445 ret = cxd2820r_read_ber_t2(fe, ber);
446 break;
447 default:
448 ret = -EINVAL;
449 }
450 } else {
451 /* DVB-C */
452 ret = cxd2820r_lock(priv, 1);
453 if (ret)
454 return ret;
455
456 ret = cxd2820r_read_ber_c(fe, ber);
457 }
458
459 return ret;
460}
461
462static int cxd2820r_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
463{
464 struct cxd2820r_priv *priv = fe->demodulator_priv;
465 int ret;
466 dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
467
468 if (fe->ops.info.type == FE_OFDM) {
469 /* DVB-T/T2 */
470 ret = cxd2820r_lock(priv, 0);
471 if (ret)
472 return ret;
473
474 switch (fe->dtv_property_cache.delivery_system) {
475 case SYS_DVBT:
476 ret = cxd2820r_read_signal_strength_t(fe, strength);
477 break;
478 case SYS_DVBT2:
479 ret = cxd2820r_read_signal_strength_t2(fe, strength);
480 break;
481 default:
482 ret = -EINVAL;
483 }
484 } else {
485 /* DVB-C */
486 ret = cxd2820r_lock(priv, 1);
487 if (ret)
488 return ret;
489
490 ret = cxd2820r_read_signal_strength_c(fe, strength);
491 }
492
493 return ret;
494}
495
496static int cxd2820r_read_snr(struct dvb_frontend *fe, u16 *snr)
497{
498 struct cxd2820r_priv *priv = fe->demodulator_priv;
499 int ret;
500 dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
501
502 if (fe->ops.info.type == FE_OFDM) {
503 /* DVB-T/T2 */
504 ret = cxd2820r_lock(priv, 0);
505 if (ret)
506 return ret;
507
508 switch (fe->dtv_property_cache.delivery_system) {
509 case SYS_DVBT:
510 ret = cxd2820r_read_snr_t(fe, snr);
511 break;
512 case SYS_DVBT2:
513 ret = cxd2820r_read_snr_t2(fe, snr);
514 break;
515 default:
516 ret = -EINVAL;
517 }
518 } else {
519 /* DVB-C */
520 ret = cxd2820r_lock(priv, 1);
521 if (ret)
522 return ret;
523
524 ret = cxd2820r_read_snr_c(fe, snr);
525 }
526
527 return ret;
528}
529
530static int cxd2820r_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
531{
532 struct cxd2820r_priv *priv = fe->demodulator_priv;
533 int ret;
534 dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
535
536 if (fe->ops.info.type == FE_OFDM) {
537 /* DVB-T/T2 */
538 ret = cxd2820r_lock(priv, 0);
539 if (ret)
540 return ret;
541
542 switch (fe->dtv_property_cache.delivery_system) {
543 case SYS_DVBT:
544 ret = cxd2820r_read_ucblocks_t(fe, ucblocks);
545 break;
546 case SYS_DVBT2:
547 ret = cxd2820r_read_ucblocks_t2(fe, ucblocks);
548 break;
549 default:
550 ret = -EINVAL;
551 }
552 } else {
553 /* DVB-C */
554 ret = cxd2820r_lock(priv, 1);
555 if (ret)
556 return ret;
557
558 ret = cxd2820r_read_ucblocks_c(fe, ucblocks);
559 }
560
561 return ret;
562}
563
564static int cxd2820r_init(struct dvb_frontend *fe)
565{
566 struct cxd2820r_priv *priv = fe->demodulator_priv;
567 int ret;
568 dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
569
570 priv->delivery_system = SYS_UNDEFINED;
571 /* delivery system is unknown at that (init) phase */
572
573 if (fe->ops.info.type == FE_OFDM) {
574 /* DVB-T/T2 */
575 ret = cxd2820r_lock(priv, 0);
576 if (ret)
577 return ret;
578
579 ret = cxd2820r_init_t(fe);
580 } else {
581 /* DVB-C */
582 ret = cxd2820r_lock(priv, 1);
583 if (ret)
584 return ret;
585
586 ret = cxd2820r_init_c(fe);
587 }
588
589 return ret;
590}
591
592static int cxd2820r_sleep(struct dvb_frontend *fe)
593{
594 struct cxd2820r_priv *priv = fe->demodulator_priv;
595 int ret;
596 dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
597
598 if (fe->ops.info.type == FE_OFDM) {
599 /* DVB-T/T2 */
600 ret = cxd2820r_lock(priv, 0);
601 if (ret)
602 return ret;
603
604 switch (fe->dtv_property_cache.delivery_system) {
605 case SYS_DVBT:
606 ret = cxd2820r_sleep_t(fe);
607 break;
608 case SYS_DVBT2:
609 ret = cxd2820r_sleep_t2(fe);
610 break;
611 default:
612 ret = -EINVAL;
613 }
614
615 cxd2820r_unlock(priv, 0);
616 } else {
617 /* DVB-C */
618 ret = cxd2820r_lock(priv, 1);
619 if (ret)
620 return ret;
621
622 ret = cxd2820r_sleep_c(fe);
623
624 cxd2820r_unlock(priv, 1);
625 }
626
627 return ret;
628}
629
630static int cxd2820r_get_tune_settings(struct dvb_frontend *fe,
631 struct dvb_frontend_tune_settings *s)
632{
633 struct cxd2820r_priv *priv = fe->demodulator_priv;
634 int ret, i;
635 unsigned int rf1, rf2;
636 dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
637
638 if (fe->ops.info.type == FE_OFDM) {
639 /* DVB-T/T2 */
640 ret = cxd2820r_lock(priv, 0);
641 if (ret)
642 return ret;
643
644 /* TODO: hack! This will be removed later when there is better
645 * app support for DVB-T2... */
646
647 /* Hz => MHz */
648 rf1 = DIV_ROUND_CLOSEST(fe->dtv_property_cache.frequency,
649 1000000);
650 for (i = 0; i < cxd2820r_dvbt2_count; i++) {
651 if (cxd2820r_dvbt2_freq[i] > 100000000) {
652 /* Hz => MHz */
653 rf2 = DIV_ROUND_CLOSEST(cxd2820r_dvbt2_freq[i],
654 1000000);
655 } else if (cxd2820r_dvbt2_freq[i] > 100000) {
656 /* kHz => MHz */
657 rf2 = DIV_ROUND_CLOSEST(cxd2820r_dvbt2_freq[i],
658 1000);
659 } else {
660 rf2 = cxd2820r_dvbt2_freq[i];
661 }
662
663 dbg("%s: rf1=%d rf2=%d", __func__, rf1, rf2);
664
665 if (rf1 == rf2) {
666 dbg("%s: forcing DVB-T2, frequency=%d",
667 __func__, fe->dtv_property_cache.frequency);
668 fe->dtv_property_cache.delivery_system =
669 SYS_DVBT2;
670 }
671 }
672
673 switch (fe->dtv_property_cache.delivery_system) {
674 case SYS_DVBT:
675 ret = cxd2820r_get_tune_settings_t(fe, s);
676 break;
677 case SYS_DVBT2:
678 ret = cxd2820r_get_tune_settings_t2(fe, s);
679 break;
680 default:
681 ret = -EINVAL;
682 }
683 } else {
684 /* DVB-C */
685 ret = cxd2820r_lock(priv, 1);
686 if (ret)
687 return ret;
688
689 ret = cxd2820r_get_tune_settings_c(fe, s);
690 }
691
692 return ret;
693}
694
695static void cxd2820r_release(struct dvb_frontend *fe)
696{
697 struct cxd2820r_priv *priv = fe->demodulator_priv;
698 dbg("%s", __func__);
699
700 if (fe->ops.info.type == FE_OFDM) {
701 i2c_del_adapter(&priv->tuner_i2c_adapter);
702 kfree(priv);
703 }
704
705 return;
706}
707
708static u32 cxd2820r_tuner_i2c_func(struct i2c_adapter *adapter)
709{
710 return I2C_FUNC_I2C;
711}
712
713static int cxd2820r_tuner_i2c_xfer(struct i2c_adapter *i2c_adap,
714 struct i2c_msg msg[], int num)
715{
716 struct cxd2820r_priv *priv = i2c_get_adapdata(i2c_adap);
717 u8 obuf[msg[0].len + 2];
718 struct i2c_msg msg2[2] = {
719 {
720 .addr = priv->cfg.i2c_address,
721 .flags = 0,
722 .len = sizeof(obuf),
723 .buf = obuf,
724 }, {
725 .addr = priv->cfg.i2c_address,
726 .flags = I2C_M_RD,
727 .len = msg[1].len,
728 .buf = msg[1].buf,
729 }
730 };
731
732 obuf[0] = 0x09;
733 obuf[1] = (msg[0].addr << 1);
734 if (num == 2) { /* I2C read */
735 obuf[1] = (msg[0].addr << 1) | I2C_M_RD; /* I2C RD flag */
736 msg2[0].len = sizeof(obuf) - 1; /* maybe HW bug ? */
737 }
738 memcpy(&obuf[2], msg[0].buf, msg[0].len);
739
740 return i2c_transfer(priv->i2c, msg2, num);
741}
742
743static struct i2c_algorithm cxd2820r_tuner_i2c_algo = {
744 .master_xfer = cxd2820r_tuner_i2c_xfer,
745 .functionality = cxd2820r_tuner_i2c_func,
746};
747
748struct i2c_adapter *cxd2820r_get_tuner_i2c_adapter(struct dvb_frontend *fe)
749{
750 struct cxd2820r_priv *priv = fe->demodulator_priv;
751 return &priv->tuner_i2c_adapter;
752}
753EXPORT_SYMBOL(cxd2820r_get_tuner_i2c_adapter);
754
755static struct dvb_frontend_ops cxd2820r_ops[2];
756
757struct dvb_frontend *cxd2820r_attach(const struct cxd2820r_config *cfg,
758 struct i2c_adapter *i2c, struct dvb_frontend *fe)
759{
760 int ret;
761 struct cxd2820r_priv *priv = NULL;
762 u8 tmp;
763
764 if (fe == NULL) {
765 /* FE0 */
766 /* allocate memory for the internal priv */
767 priv = kzalloc(sizeof(struct cxd2820r_priv), GFP_KERNEL);
768 if (priv == NULL)
769 goto error;
770
771 /* setup the priv */
772 priv->i2c = i2c;
773 memcpy(&priv->cfg, cfg, sizeof(struct cxd2820r_config));
774 mutex_init(&priv->fe_lock);
775
776 priv->active_fe = -1; /* NONE */
777
778 /* check if the demod is there */
779 priv->bank[0] = priv->bank[1] = 0xff;
780 ret = cxd2820r_rd_reg(priv, 0x000fd, &tmp);
781 dbg("%s: chip id=%02x", __func__, tmp);
782 if (ret || tmp != 0xe1)
783 goto error;
784
785 /* create frontends */
786 memcpy(&priv->fe[0].ops, &cxd2820r_ops[0],
787 sizeof(struct dvb_frontend_ops));
788 memcpy(&priv->fe[1].ops, &cxd2820r_ops[1],
789 sizeof(struct dvb_frontend_ops));
790
791 priv->fe[0].demodulator_priv = priv;
792 priv->fe[1].demodulator_priv = priv;
793
794 /* create tuner i2c adapter */
795 strlcpy(priv->tuner_i2c_adapter.name,
796 "CXD2820R tuner I2C adapter",
797 sizeof(priv->tuner_i2c_adapter.name));
798 priv->tuner_i2c_adapter.algo = &cxd2820r_tuner_i2c_algo;
799 priv->tuner_i2c_adapter.algo_data = NULL;
800 i2c_set_adapdata(&priv->tuner_i2c_adapter, priv);
801 if (i2c_add_adapter(&priv->tuner_i2c_adapter) < 0) {
802 err("tuner I2C bus could not be initialized");
803 goto error;
804 }
805
806 return &priv->fe[0];
807
808 } else {
809 /* FE1: FE0 given as pointer, just return FE1 we have
810 * already created */
811 priv = fe->demodulator_priv;
812 return &priv->fe[1];
813 }
814
815error:
816 kfree(priv);
817 return NULL;
818}
819EXPORT_SYMBOL(cxd2820r_attach);
820
821static struct dvb_frontend_ops cxd2820r_ops[2] = {
822 {
823 /* DVB-T/T2 */
824 .info = {
825 .name = "Sony CXD2820R (DVB-T/T2)",
826 .type = FE_OFDM,
827 .caps =
828 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
829 FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 |
830 FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
831 FE_CAN_QPSK | FE_CAN_QAM_16 |
832 FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
833 FE_CAN_TRANSMISSION_MODE_AUTO |
834 FE_CAN_GUARD_INTERVAL_AUTO |
835 FE_CAN_HIERARCHY_AUTO |
836 FE_CAN_MUTE_TS |
837 FE_CAN_2G_MODULATION
838 },
839
840 .release = cxd2820r_release,
841 .init = cxd2820r_init,
842 .sleep = cxd2820r_sleep,
843
844 .get_tune_settings = cxd2820r_get_tune_settings,
845
846 .set_frontend = cxd2820r_set_frontend,
847 .get_frontend = cxd2820r_get_frontend,
848
849 .read_status = cxd2820r_read_status,
850 .read_snr = cxd2820r_read_snr,
851 .read_ber = cxd2820r_read_ber,
852 .read_ucblocks = cxd2820r_read_ucblocks,
853 .read_signal_strength = cxd2820r_read_signal_strength,
854 },
855 {
856 /* DVB-C */
857 .info = {
858 .name = "Sony CXD2820R (DVB-C)",
859 .type = FE_QAM,
860 .caps =
861 FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
862 FE_CAN_QAM_128 | FE_CAN_QAM_256 |
863 FE_CAN_FEC_AUTO
864 },
865
866 .release = cxd2820r_release,
867 .init = cxd2820r_init,
868 .sleep = cxd2820r_sleep,
869
870 .get_tune_settings = cxd2820r_get_tune_settings,
871
872 .set_frontend = cxd2820r_set_frontend,
873 .get_frontend = cxd2820r_get_frontend,
874
875 .read_status = cxd2820r_read_status,
876 .read_snr = cxd2820r_read_snr,
877 .read_ber = cxd2820r_read_ber,
878 .read_ucblocks = cxd2820r_read_ucblocks,
879 .read_signal_strength = cxd2820r_read_signal_strength,
880 },
881};
882
883
884MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
885MODULE_DESCRIPTION("Sony CXD2820R demodulator driver");
886MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/cxd2820r.h b/drivers/media/dvb/frontends/cxd2820r.h
new file mode 100644
index 000000000000..ad17845123d9
--- /dev/null
+++ b/drivers/media/dvb/frontends/cxd2820r.h
@@ -0,0 +1,118 @@
1/*
2 * Sony CXD2820R demodulator driver
3 *
4 * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21
22#ifndef CXD2820R_H
23#define CXD2820R_H
24
25#include <linux/dvb/frontend.h>
26
27#define CXD2820R_GPIO_D (0 << 0) /* disable */
28#define CXD2820R_GPIO_E (1 << 0) /* enable */
29#define CXD2820R_GPIO_O (0 << 1) /* output */
30#define CXD2820R_GPIO_I (1 << 1) /* input */
31#define CXD2820R_GPIO_L (0 << 2) /* output low */
32#define CXD2820R_GPIO_H (1 << 2) /* output high */
33
34#define CXD2820R_TS_SERIAL 0x08
35#define CXD2820R_TS_SERIAL_MSB 0x28
36#define CXD2820R_TS_PARALLEL 0x30
37#define CXD2820R_TS_PARALLEL_MSB 0x70
38
39struct cxd2820r_config {
40 /* Demodulator I2C address.
41 * Driver determines DVB-C slave I2C address automatically from master
42 * address.
43 * Default: none, must set
44 * Values: 0x6c, 0x6d
45 */
46 u8 i2c_address;
47
48 /* TS output mode.
49 * Default: none, must set.
50 * Values:
51 */
52 u8 ts_mode;
53
54 /* IF AGC polarity.
55 * Default: 0
56 * Values: 0, 1
57 */
58 int if_agc_polarity:1;
59
60 /* Spectrum inversion.
61 * Default: 0
62 * Values: 0, 1
63 */
64 int spec_inv:1;
65
66 /* IFs for all used modes.
67 * Default: none, must set
68 * Values: <kHz>
69 */
70 u16 if_dvbt_6;
71 u16 if_dvbt_7;
72 u16 if_dvbt_8;
73 u16 if_dvbt2_5;
74 u16 if_dvbt2_6;
75 u16 if_dvbt2_7;
76 u16 if_dvbt2_8;
77 u16 if_dvbc;
78
79 /* GPIOs for all used modes.
80 * Default: none, disabled
81 * Values: <see above>
82 */
83 u8 gpio_dvbt[3];
84 u8 gpio_dvbt2[3];
85 u8 gpio_dvbc[3];
86};
87
88
89#if defined(CONFIG_DVB_CXD2820R) || \
90 (defined(CONFIG_DVB_CXD2820R_MODULE) && defined(MODULE))
91extern struct dvb_frontend *cxd2820r_attach(
92 const struct cxd2820r_config *config,
93 struct i2c_adapter *i2c,
94 struct dvb_frontend *fe
95);
96extern struct i2c_adapter *cxd2820r_get_tuner_i2c_adapter(
97 struct dvb_frontend *fe
98);
99#else
100static inline struct dvb_frontend *cxd2820r_attach(
101 const struct cxd2820r_config *config,
102 struct i2c_adapter *i2c,
103 struct dvb_frontend *fe
104)
105{
106 printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
107 return NULL;
108}
109static inline struct i2c_adapter *cxd2820r_get_tuner_i2c_adapter(
110 struct dvb_frontend *fe
111)
112{
113 return NULL;
114}
115
116#endif
117
118#endif /* CXD2820R_H */
diff --git a/drivers/media/dvb/frontends/cxd2820r_c.c b/drivers/media/dvb/frontends/cxd2820r_c.c
new file mode 100644
index 000000000000..a94bff944722
--- /dev/null
+++ b/drivers/media/dvb/frontends/cxd2820r_c.c
@@ -0,0 +1,336 @@
1/*
2 * Sony CXD2820R demodulator driver
3 *
4 * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21
22static int cxd2820r_set_frontend_c(struct dvb_frontend *fe,
23 struct dvb_frontend_parameters *params)
24{
25 struct cxd2820r_priv *priv = fe->demodulator_priv;
26 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
27 int ret, i;
28 u8 buf[2];
29 u16 if_ctl;
30 u64 num;
31 struct reg_val_mask tab[] = {
32 { 0x00080, 0x01, 0xff },
33 { 0x00081, 0x05, 0xff },
34 { 0x00085, 0x07, 0xff },
35 { 0x00088, 0x01, 0xff },
36
37 { 0x00082, 0x20, 0x60 },
38 { 0x1016a, 0x48, 0xff },
39 { 0x100a5, 0x00, 0x01 },
40 { 0x10020, 0x06, 0x07 },
41 { 0x10059, 0x50, 0xff },
42 { 0x10087, 0x0c, 0x3c },
43 { 0x1008b, 0x07, 0xff },
44 { 0x1001f, priv->cfg.if_agc_polarity << 7, 0x80 },
45 { 0x10070, priv->cfg.ts_mode, 0xff },
46 };
47
48 dbg("%s: RF=%d SR=%d", __func__, c->frequency, c->symbol_rate);
49
50 /* update GPIOs */
51 ret = cxd2820r_gpio(fe);
52 if (ret)
53 goto error;
54
55 /* program tuner */
56 if (fe->ops.tuner_ops.set_params)
57 fe->ops.tuner_ops.set_params(fe, params);
58
59 if (priv->delivery_system != SYS_DVBC_ANNEX_AC) {
60 for (i = 0; i < ARRAY_SIZE(tab); i++) {
61 ret = cxd2820r_wr_reg_mask(priv, tab[i].reg,
62 tab[i].val, tab[i].mask);
63 if (ret)
64 goto error;
65 }
66 }
67
68 priv->delivery_system = SYS_DVBC_ANNEX_AC;
69 priv->ber_running = 0; /* tune stops BER counter */
70
71 num = priv->cfg.if_dvbc;
72 num *= 0x4000;
73 if_ctl = cxd2820r_div_u64_round_closest(num, 41000);
74 buf[0] = (if_ctl >> 8) & 0x3f;
75 buf[1] = (if_ctl >> 0) & 0xff;
76
77 ret = cxd2820r_wr_regs(priv, 0x10042, buf, 2);
78 if (ret)
79 goto error;
80
81 ret = cxd2820r_wr_reg(priv, 0x000ff, 0x08);
82 if (ret)
83 goto error;
84
85 ret = cxd2820r_wr_reg(priv, 0x000fe, 0x01);
86 if (ret)
87 goto error;
88
89 return ret;
90error:
91 dbg("%s: failed:%d", __func__, ret);
92 return ret;
93}
94
95static int cxd2820r_get_frontend_c(struct dvb_frontend *fe,
96 struct dvb_frontend_parameters *p)
97{
98 struct cxd2820r_priv *priv = fe->demodulator_priv;
99 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
100 int ret;
101 u8 buf[2];
102
103 ret = cxd2820r_rd_regs(priv, 0x1001a, buf, 2);
104 if (ret)
105 goto error;
106
107 c->symbol_rate = 2500 * ((buf[0] & 0x0f) << 8 | buf[1]);
108
109 ret = cxd2820r_rd_reg(priv, 0x10019, &buf[0]);
110 if (ret)
111 goto error;
112
113 switch ((buf[0] >> 0) & 0x03) {
114 case 0:
115 c->modulation = QAM_16;
116 break;
117 case 1:
118 c->modulation = QAM_32;
119 break;
120 case 2:
121 c->modulation = QAM_64;
122 break;
123 case 3:
124 c->modulation = QAM_128;
125 break;
126 case 4:
127 c->modulation = QAM_256;
128 break;
129 }
130
131 switch ((buf[0] >> 7) & 0x01) {
132 case 0:
133 c->inversion = INVERSION_OFF;
134 break;
135 case 1:
136 c->inversion = INVERSION_ON;
137 break;
138 }
139
140 return ret;
141error:
142 dbg("%s: failed:%d", __func__, ret);
143 return ret;
144}
145
146static int cxd2820r_read_ber_c(struct dvb_frontend *fe, u32 *ber)
147{
148 struct cxd2820r_priv *priv = fe->demodulator_priv;
149 int ret;
150 u8 buf[3], start_ber = 0;
151 *ber = 0;
152
153 if (priv->ber_running) {
154 ret = cxd2820r_rd_regs(priv, 0x10076, buf, sizeof(buf));
155 if (ret)
156 goto error;
157
158 if ((buf[2] >> 7) & 0x01 || (buf[2] >> 4) & 0x01) {
159 *ber = (buf[2] & 0x0f) << 16 | buf[1] << 8 | buf[0];
160 start_ber = 1;
161 }
162 } else {
163 priv->ber_running = 1;
164 start_ber = 1;
165 }
166
167 if (start_ber) {
168 /* (re)start BER */
169 ret = cxd2820r_wr_reg(priv, 0x10079, 0x01);
170 if (ret)
171 goto error;
172 }
173
174 return ret;
175error:
176 dbg("%s: failed:%d", __func__, ret);
177 return ret;
178}
179
180static int cxd2820r_read_signal_strength_c(struct dvb_frontend *fe,
181 u16 *strength)
182{
183 struct cxd2820r_priv *priv = fe->demodulator_priv;
184 int ret;
185 u8 buf[2];
186 u16 tmp;
187
188 ret = cxd2820r_rd_regs(priv, 0x10049, buf, sizeof(buf));
189 if (ret)
190 goto error;
191
192 tmp = (buf[0] & 0x03) << 8 | buf[1];
193 tmp = (~tmp & 0x03ff);
194
195 if (tmp == 512)
196 /* ~no signal */
197 tmp = 0;
198 else if (tmp > 350)
199 tmp = 350;
200
201 /* scale value to 0x0000-0xffff */
202 *strength = tmp * 0xffff / (350-0);
203
204 return ret;
205error:
206 dbg("%s: failed:%d", __func__, ret);
207 return ret;
208}
209
210static int cxd2820r_read_snr_c(struct dvb_frontend *fe, u16 *snr)
211{
212 struct cxd2820r_priv *priv = fe->demodulator_priv;
213 int ret;
214 u8 tmp;
215 unsigned int A, B;
216 /* report SNR in dB * 10 */
217
218 ret = cxd2820r_rd_reg(priv, 0x10019, &tmp);
219 if (ret)
220 goto error;
221
222 if (((tmp >> 0) & 0x03) % 2) {
223 A = 875;
224 B = 650;
225 } else {
226 A = 950;
227 B = 760;
228 }
229
230 ret = cxd2820r_rd_reg(priv, 0x1004d, &tmp);
231 if (ret)
232 goto error;
233
234 #define CXD2820R_LOG2_E_24 24204406 /* log2(e) << 24 */
235 if (tmp)
236 *snr = A * (intlog2(B / tmp) >> 5) / (CXD2820R_LOG2_E_24 >> 5)
237 / 10;
238 else
239 *snr = 0;
240
241 return ret;
242error:
243 dbg("%s: failed:%d", __func__, ret);
244 return ret;
245}
246
247static int cxd2820r_read_ucblocks_c(struct dvb_frontend *fe, u32 *ucblocks)
248{
249 *ucblocks = 0;
250 /* no way to read ? */
251 return 0;
252}
253
254static int cxd2820r_read_status_c(struct dvb_frontend *fe, fe_status_t *status)
255{
256 struct cxd2820r_priv *priv = fe->demodulator_priv;
257 int ret;
258 u8 buf[2];
259 *status = 0;
260
261 ret = cxd2820r_rd_regs(priv, 0x10088, buf, sizeof(buf));
262 if (ret)
263 goto error;
264
265 if (((buf[0] >> 0) & 0x01) == 1) {
266 *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
267 FE_HAS_VITERBI | FE_HAS_SYNC;
268
269 if (((buf[1] >> 3) & 0x01) == 1) {
270 *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
271 FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
272 }
273 }
274
275 dbg("%s: lock=%02x %02x", __func__, buf[0], buf[1]);
276
277 return ret;
278error:
279 dbg("%s: failed:%d", __func__, ret);
280 return ret;
281}
282
283static int cxd2820r_init_c(struct dvb_frontend *fe)
284{
285 struct cxd2820r_priv *priv = fe->demodulator_priv;
286 int ret;
287
288 ret = cxd2820r_wr_reg(priv, 0x00085, 0x07);
289 if (ret)
290 goto error;
291
292 return ret;
293error:
294 dbg("%s: failed:%d", __func__, ret);
295 return ret;
296}
297
298static int cxd2820r_sleep_c(struct dvb_frontend *fe)
299{
300 struct cxd2820r_priv *priv = fe->demodulator_priv;
301 int ret, i;
302 struct reg_val_mask tab[] = {
303 { 0x000ff, 0x1f, 0xff },
304 { 0x00085, 0x00, 0xff },
305 { 0x00088, 0x01, 0xff },
306 { 0x00081, 0x00, 0xff },
307 { 0x00080, 0x00, 0xff },
308 };
309
310 dbg("%s", __func__);
311
312 priv->delivery_system = SYS_UNDEFINED;
313
314 for (i = 0; i < ARRAY_SIZE(tab); i++) {
315 ret = cxd2820r_wr_reg_mask(priv, tab[i].reg, tab[i].val,
316 tab[i].mask);
317 if (ret)
318 goto error;
319 }
320
321 return ret;
322error:
323 dbg("%s: failed:%d", __func__, ret);
324 return ret;
325}
326
327static int cxd2820r_get_tune_settings_c(struct dvb_frontend *fe,
328 struct dvb_frontend_tune_settings *s)
329{
330 s->min_delay_ms = 500;
331 s->step_size = 0; /* no zigzag */
332 s->max_drift = 0;
333
334 return 0;
335}
336
diff --git a/drivers/media/dvb/frontends/cxd2820r_priv.h b/drivers/media/dvb/frontends/cxd2820r_priv.h
new file mode 100644
index 000000000000..4d2d79969d91
--- /dev/null
+++ b/drivers/media/dvb/frontends/cxd2820r_priv.h
@@ -0,0 +1,77 @@
1/*
2 * Sony CXD2820R demodulator driver
3 *
4 * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21
22#ifndef CXD2820R_PRIV_H
23#define CXD2820R_PRIV_H
24
25#include "dvb_frontend.h"
26#include "dvb_math.h"
27#include "cxd2820r.h"
28
29#define LOG_PREFIX "cxd2820r"
30
31#undef dbg
32#define dbg(f, arg...) \
33 if (cxd2820r_debug) \
34 printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg)
35#undef err
36#define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg)
37#undef info
38#define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg)
39#undef warn
40#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
41
42/*
43 * FIXME: These are totally wrong and must be added properly to the API.
44 * Only temporary solution in order to get driver compile.
45 */
46#define SYS_DVBT2 SYS_DAB
47#define TRANSMISSION_MODE_1K 0
48#define TRANSMISSION_MODE_16K 0
49#define TRANSMISSION_MODE_32K 0
50#define GUARD_INTERVAL_1_128 0
51#define GUARD_INTERVAL_19_128 0
52#define GUARD_INTERVAL_19_256 0
53
54struct reg_val_mask {
55 u32 reg;
56 u8 val;
57 u8 mask;
58};
59
60struct cxd2820r_priv {
61 struct i2c_adapter *i2c;
62 struct dvb_frontend fe[2];
63 struct cxd2820r_config cfg;
64 struct i2c_adapter tuner_i2c_adapter;
65
66 struct mutex fe_lock; /* FE lock */
67 int active_fe:2; /* FE lock, -1=NONE, 0=DVB-T/T2, 1=DVB-C */
68
69 int ber_running:1;
70
71 u8 bank[2];
72 u8 gpio[3];
73
74 fe_delivery_system_t delivery_system;
75};
76
77#endif /* CXD2820R_PRIV_H */
diff --git a/drivers/media/dvb/frontends/cxd2820r_t.c b/drivers/media/dvb/frontends/cxd2820r_t.c
new file mode 100644
index 000000000000..6732a9843f13
--- /dev/null
+++ b/drivers/media/dvb/frontends/cxd2820r_t.c
@@ -0,0 +1,447 @@
1/*
2 * Sony CXD2820R demodulator driver
3 *
4 * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21
22static int cxd2820r_set_frontend_t(struct dvb_frontend *fe,
23 struct dvb_frontend_parameters *p)
24{
25 struct cxd2820r_priv *priv = fe->demodulator_priv;
26 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
27 int ret, i;
28 u32 if_khz, if_ctl;
29 u64 num;
30 u8 buf[3], bw_param;
31 u8 bw_params1[][5] = {
32 { 0x17, 0xea, 0xaa, 0xaa, 0xaa }, /* 6 MHz */
33 { 0x14, 0x80, 0x00, 0x00, 0x00 }, /* 7 MHz */
34 { 0x11, 0xf0, 0x00, 0x00, 0x00 }, /* 8 MHz */
35 };
36 u8 bw_params2[][2] = {
37 { 0x1f, 0xdc }, /* 6 MHz */
38 { 0x12, 0xf8 }, /* 7 MHz */
39 { 0x01, 0xe0 }, /* 8 MHz */
40 };
41 struct reg_val_mask tab[] = {
42 { 0x00080, 0x00, 0xff },
43 { 0x00081, 0x03, 0xff },
44 { 0x00085, 0x07, 0xff },
45 { 0x00088, 0x01, 0xff },
46
47 { 0x00070, priv->cfg.ts_mode, 0xff },
48 { 0x000cb, priv->cfg.if_agc_polarity << 6, 0x40 },
49 { 0x000a5, 0x00, 0x01 },
50 { 0x00082, 0x20, 0x60 },
51 { 0x000c2, 0xc3, 0xff },
52 { 0x0016a, 0x50, 0xff },
53 { 0x00427, 0x41, 0xff },
54 };
55
56 dbg("%s: RF=%d BW=%d", __func__, c->frequency, c->bandwidth_hz);
57
58 /* update GPIOs */
59 ret = cxd2820r_gpio(fe);
60 if (ret)
61 goto error;
62
63 /* program tuner */
64 if (fe->ops.tuner_ops.set_params)
65 fe->ops.tuner_ops.set_params(fe, p);
66
67 if (priv->delivery_system != SYS_DVBT) {
68 for (i = 0; i < ARRAY_SIZE(tab); i++) {
69 ret = cxd2820r_wr_reg_mask(priv, tab[i].reg,
70 tab[i].val, tab[i].mask);
71 if (ret)
72 goto error;
73 }
74 }
75
76 priv->delivery_system = SYS_DVBT;
77 priv->ber_running = 0; /* tune stops BER counter */
78
79 switch (c->bandwidth_hz) {
80 case 6000000:
81 if_khz = priv->cfg.if_dvbt_6;
82 i = 0;
83 bw_param = 2;
84 break;
85 case 7000000:
86 if_khz = priv->cfg.if_dvbt_7;
87 i = 1;
88 bw_param = 1;
89 break;
90 case 8000000:
91 if_khz = priv->cfg.if_dvbt_8;
92 i = 2;
93 bw_param = 0;
94 break;
95 default:
96 return -EINVAL;
97 }
98
99 num = if_khz;
100 num *= 0x1000000;
101 if_ctl = cxd2820r_div_u64_round_closest(num, 41000);
102 buf[0] = ((if_ctl >> 16) & 0xff);
103 buf[1] = ((if_ctl >> 8) & 0xff);
104 buf[2] = ((if_ctl >> 0) & 0xff);
105
106 ret = cxd2820r_wr_regs(priv, 0x000b6, buf, 3);
107 if (ret)
108 goto error;
109
110 ret = cxd2820r_wr_regs(priv, 0x0009f, bw_params1[i], 5);
111 if (ret)
112 goto error;
113
114 ret = cxd2820r_wr_reg_mask(priv, 0x000d7, bw_param << 6, 0xc0);
115 if (ret)
116 goto error;
117
118 ret = cxd2820r_wr_regs(priv, 0x000d9, bw_params2[i], 2);
119 if (ret)
120 goto error;
121
122 ret = cxd2820r_wr_reg(priv, 0x000ff, 0x08);
123 if (ret)
124 goto error;
125
126 ret = cxd2820r_wr_reg(priv, 0x000fe, 0x01);
127 if (ret)
128 goto error;
129
130 return ret;
131error:
132 dbg("%s: failed:%d", __func__, ret);
133 return ret;
134}
135
136static int cxd2820r_get_frontend_t(struct dvb_frontend *fe,
137 struct dvb_frontend_parameters *p)
138{
139 struct cxd2820r_priv *priv = fe->demodulator_priv;
140 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
141 int ret;
142 u8 buf[2];
143
144 ret = cxd2820r_rd_regs(priv, 0x0002f, buf, sizeof(buf));
145 if (ret)
146 goto error;
147
148 switch ((buf[0] >> 6) & 0x03) {
149 case 0:
150 c->modulation = QPSK;
151 break;
152 case 1:
153 c->modulation = QAM_16;
154 break;
155 case 2:
156 c->modulation = QAM_64;
157 break;
158 }
159
160 switch ((buf[1] >> 1) & 0x03) {
161 case 0:
162 c->transmission_mode = TRANSMISSION_MODE_2K;
163 break;
164 case 1:
165 c->transmission_mode = TRANSMISSION_MODE_8K;
166 break;
167 }
168
169 switch ((buf[1] >> 3) & 0x03) {
170 case 0:
171 c->guard_interval = GUARD_INTERVAL_1_32;
172 break;
173 case 1:
174 c->guard_interval = GUARD_INTERVAL_1_16;
175 break;
176 case 2:
177 c->guard_interval = GUARD_INTERVAL_1_8;
178 break;
179 case 3:
180 c->guard_interval = GUARD_INTERVAL_1_4;
181 break;
182 }
183
184 switch ((buf[0] >> 3) & 0x07) {
185 case 0:
186 c->hierarchy = HIERARCHY_NONE;
187 break;
188 case 1:
189 c->hierarchy = HIERARCHY_1;
190 break;
191 case 2:
192 c->hierarchy = HIERARCHY_2;
193 break;
194 case 3:
195 c->hierarchy = HIERARCHY_4;
196 break;
197 }
198
199 switch ((buf[0] >> 0) & 0x07) {
200 case 0:
201 c->code_rate_HP = FEC_1_2;
202 break;
203 case 1:
204 c->code_rate_HP = FEC_2_3;
205 break;
206 case 2:
207 c->code_rate_HP = FEC_3_4;
208 break;
209 case 3:
210 c->code_rate_HP = FEC_5_6;
211 break;
212 case 4:
213 c->code_rate_HP = FEC_7_8;
214 break;
215 }
216
217 switch ((buf[1] >> 5) & 0x07) {
218 case 0:
219 c->code_rate_LP = FEC_1_2;
220 break;
221 case 1:
222 c->code_rate_LP = FEC_2_3;
223 break;
224 case 2:
225 c->code_rate_LP = FEC_3_4;
226 break;
227 case 3:
228 c->code_rate_LP = FEC_5_6;
229 break;
230 case 4:
231 c->code_rate_LP = FEC_7_8;
232 break;
233 }
234
235 ret = cxd2820r_rd_reg(priv, 0x007c6, &buf[0]);
236 if (ret)
237 goto error;
238
239 switch ((buf[0] >> 0) & 0x01) {
240 case 0:
241 c->inversion = INVERSION_OFF;
242 break;
243 case 1:
244 c->inversion = INVERSION_ON;
245 break;
246 }
247
248 return ret;
249error:
250 dbg("%s: failed:%d", __func__, ret);
251 return ret;
252}
253
254static int cxd2820r_read_ber_t(struct dvb_frontend *fe, u32 *ber)
255{
256 struct cxd2820r_priv *priv = fe->demodulator_priv;
257 int ret;
258 u8 buf[3], start_ber = 0;
259 *ber = 0;
260
261 if (priv->ber_running) {
262 ret = cxd2820r_rd_regs(priv, 0x00076, buf, sizeof(buf));
263 if (ret)
264 goto error;
265
266 if ((buf[2] >> 7) & 0x01 || (buf[2] >> 4) & 0x01) {
267 *ber = (buf[2] & 0x0f) << 16 | buf[1] << 8 | buf[0];
268 start_ber = 1;
269 }
270 } else {
271 priv->ber_running = 1;
272 start_ber = 1;
273 }
274
275 if (start_ber) {
276 /* (re)start BER */
277 ret = cxd2820r_wr_reg(priv, 0x00079, 0x01);
278 if (ret)
279 goto error;
280 }
281
282 return ret;
283error:
284 dbg("%s: failed:%d", __func__, ret);
285 return ret;
286}
287
288static int cxd2820r_read_signal_strength_t(struct dvb_frontend *fe,
289 u16 *strength)
290{
291 struct cxd2820r_priv *priv = fe->demodulator_priv;
292 int ret;
293 u8 buf[2];
294 u16 tmp;
295
296 ret = cxd2820r_rd_regs(priv, 0x00026, buf, sizeof(buf));
297 if (ret)
298 goto error;
299
300 tmp = (buf[0] & 0x0f) << 8 | buf[1];
301 tmp = ~tmp & 0x0fff;
302
303 /* scale value to 0x0000-0xffff from 0x0000-0x0fff */
304 *strength = tmp * 0xffff / 0x0fff;
305
306 return ret;
307error:
308 dbg("%s: failed:%d", __func__, ret);
309 return ret;
310}
311
312static int cxd2820r_read_snr_t(struct dvb_frontend *fe, u16 *snr)
313{
314 struct cxd2820r_priv *priv = fe->demodulator_priv;
315 int ret;
316 u8 buf[2];
317 u16 tmp;
318 /* report SNR in dB * 10 */
319
320 ret = cxd2820r_rd_regs(priv, 0x00028, buf, sizeof(buf));
321 if (ret)
322 goto error;
323
324 tmp = (buf[0] & 0x1f) << 8 | buf[1];
325 #define CXD2820R_LOG10_8_24 15151336 /* log10(8) << 24 */
326 if (tmp)
327 *snr = (intlog10(tmp) - CXD2820R_LOG10_8_24) / ((1 << 24)
328 / 100);
329 else
330 *snr = 0;
331
332 dbg("%s: dBx10=%d val=%04x", __func__, *snr, tmp);
333
334 return ret;
335error:
336 dbg("%s: failed:%d", __func__, ret);
337 return ret;
338}
339
340static int cxd2820r_read_ucblocks_t(struct dvb_frontend *fe, u32 *ucblocks)
341{
342 *ucblocks = 0;
343 /* no way to read ? */
344 return 0;
345}
346
347static int cxd2820r_read_status_t(struct dvb_frontend *fe, fe_status_t *status)
348{
349 struct cxd2820r_priv *priv = fe->demodulator_priv;
350 int ret;
351 u8 buf[4];
352 *status = 0;
353
354 ret = cxd2820r_rd_reg(priv, 0x00010, &buf[0]);
355 if (ret)
356 goto error;
357
358 if ((buf[0] & 0x07) == 6) {
359 ret = cxd2820r_rd_reg(priv, 0x00073, &buf[1]);
360 if (ret)
361 goto error;
362
363 if (((buf[1] >> 3) & 0x01) == 1) {
364 *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
365 FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
366 } else {
367 *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
368 FE_HAS_VITERBI | FE_HAS_SYNC;
369 }
370 } else {
371 ret = cxd2820r_rd_reg(priv, 0x00014, &buf[2]);
372 if (ret)
373 goto error;
374
375 if ((buf[2] & 0x0f) >= 4) {
376 ret = cxd2820r_rd_reg(priv, 0x00a14, &buf[3]);
377 if (ret)
378 goto error;
379
380 if (((buf[3] >> 4) & 0x01) == 1)
381 *status |= FE_HAS_SIGNAL;
382 }
383 }
384
385 dbg("%s: lock=%02x %02x %02x %02x", __func__,
386 buf[0], buf[1], buf[2], buf[3]);
387
388 return ret;
389error:
390 dbg("%s: failed:%d", __func__, ret);
391 return ret;
392}
393
394static int cxd2820r_init_t(struct dvb_frontend *fe)
395{
396 struct cxd2820r_priv *priv = fe->demodulator_priv;
397 int ret;
398
399 ret = cxd2820r_wr_reg(priv, 0x00085, 0x07);
400 if (ret)
401 goto error;
402
403 return ret;
404error:
405 dbg("%s: failed:%d", __func__, ret);
406 return ret;
407}
408
409static int cxd2820r_sleep_t(struct dvb_frontend *fe)
410{
411 struct cxd2820r_priv *priv = fe->demodulator_priv;
412 int ret, i;
413 struct reg_val_mask tab[] = {
414 { 0x000ff, 0x1f, 0xff },
415 { 0x00085, 0x00, 0xff },
416 { 0x00088, 0x01, 0xff },
417 { 0x00081, 0x00, 0xff },
418 { 0x00080, 0x00, 0xff },
419 };
420
421 dbg("%s", __func__);
422
423 priv->delivery_system = SYS_UNDEFINED;
424
425 for (i = 0; i < ARRAY_SIZE(tab); i++) {
426 ret = cxd2820r_wr_reg_mask(priv, tab[i].reg, tab[i].val,
427 tab[i].mask);
428 if (ret)
429 goto error;
430 }
431
432 return ret;
433error:
434 dbg("%s: failed:%d", __func__, ret);
435 return ret;
436}
437
438static int cxd2820r_get_tune_settings_t(struct dvb_frontend *fe,
439 struct dvb_frontend_tune_settings *s)
440{
441 s->min_delay_ms = 500;
442 s->step_size = fe->ops.info.frequency_stepsize * 2;
443 s->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
444
445 return 0;
446}
447
diff --git a/drivers/media/dvb/frontends/cxd2820r_t2.c b/drivers/media/dvb/frontends/cxd2820r_t2.c
new file mode 100644
index 000000000000..6ec94ea77f15
--- /dev/null
+++ b/drivers/media/dvb/frontends/cxd2820r_t2.c
@@ -0,0 +1,421 @@
1/*
2 * Sony CXD2820R demodulator driver
3 *
4 * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21
22static int cxd2820r_set_frontend_t2(struct dvb_frontend *fe,
23 struct dvb_frontend_parameters *params)
24{
25 struct cxd2820r_priv *priv = fe->demodulator_priv;
26 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
27 int ret, i;
28 u32 if_khz, if_ctl;
29 u64 num;
30 u8 buf[3], bw_param;
31 u8 bw_params1[][5] = {
32 { 0x1c, 0xb3, 0x33, 0x33, 0x33 }, /* 5 MHz */
33 { 0x17, 0xea, 0xaa, 0xaa, 0xaa }, /* 6 MHz */
34 { 0x14, 0x80, 0x00, 0x00, 0x00 }, /* 7 MHz */
35 { 0x11, 0xf0, 0x00, 0x00, 0x00 }, /* 8 MHz */
36 };
37 struct reg_val_mask tab[] = {
38 { 0x00080, 0x02, 0xff },
39 { 0x00081, 0x20, 0xff },
40 { 0x00085, 0x07, 0xff },
41 { 0x00088, 0x01, 0xff },
42 { 0x02069, 0x01, 0xff },
43
44 { 0x0207f, 0x2a, 0xff },
45 { 0x02082, 0x0a, 0xff },
46 { 0x02083, 0x0a, 0xff },
47 { 0x020cb, priv->cfg.if_agc_polarity << 6, 0x40 },
48 { 0x02070, priv->cfg.ts_mode, 0xff },
49 { 0x020b5, priv->cfg.spec_inv << 4, 0x10 },
50 { 0x02567, 0x07, 0x0f },
51 { 0x02569, 0x03, 0x03 },
52 { 0x02595, 0x1a, 0xff },
53 { 0x02596, 0x50, 0xff },
54 { 0x02a8c, 0x00, 0xff },
55 { 0x02a8d, 0x34, 0xff },
56 { 0x02a45, 0x06, 0x07 },
57 { 0x03f10, 0x0d, 0xff },
58 { 0x03f11, 0x02, 0xff },
59 { 0x03f12, 0x01, 0xff },
60 { 0x03f23, 0x2c, 0xff },
61 { 0x03f51, 0x13, 0xff },
62 { 0x03f52, 0x01, 0xff },
63 { 0x03f53, 0x00, 0xff },
64 { 0x027e6, 0x14, 0xff },
65 { 0x02786, 0x02, 0x07 },
66 { 0x02787, 0x40, 0xe0 },
67 { 0x027ef, 0x10, 0x18 },
68 };
69
70 dbg("%s: RF=%d BW=%d", __func__, c->frequency, c->bandwidth_hz);
71
72 /* update GPIOs */
73 ret = cxd2820r_gpio(fe);
74 if (ret)
75 goto error;
76
77 /* program tuner */
78 if (fe->ops.tuner_ops.set_params)
79 fe->ops.tuner_ops.set_params(fe, params);
80
81 if (priv->delivery_system != SYS_DVBT2) {
82 for (i = 0; i < ARRAY_SIZE(tab); i++) {
83 ret = cxd2820r_wr_reg_mask(priv, tab[i].reg,
84 tab[i].val, tab[i].mask);
85 if (ret)
86 goto error;
87 }
88 }
89
90 priv->delivery_system = SYS_DVBT2;
91
92 switch (c->bandwidth_hz) {
93 case 5000000:
94 if_khz = priv->cfg.if_dvbt2_5;
95 i = 0;
96 bw_param = 3;
97 break;
98 case 6000000:
99 if_khz = priv->cfg.if_dvbt2_6;
100 i = 1;
101 bw_param = 2;
102 break;
103 case 7000000:
104 if_khz = priv->cfg.if_dvbt2_7;
105 i = 2;
106 bw_param = 1;
107 break;
108 case 8000000:
109 if_khz = priv->cfg.if_dvbt2_8;
110 i = 3;
111 bw_param = 0;
112 break;
113 default:
114 return -EINVAL;
115 }
116
117 num = if_khz;
118 num *= 0x1000000;
119 if_ctl = cxd2820r_div_u64_round_closest(num, 41000);
120 buf[0] = ((if_ctl >> 16) & 0xff);
121 buf[1] = ((if_ctl >> 8) & 0xff);
122 buf[2] = ((if_ctl >> 0) & 0xff);
123
124 ret = cxd2820r_wr_regs(priv, 0x020b6, buf, 3);
125 if (ret)
126 goto error;
127
128 ret = cxd2820r_wr_regs(priv, 0x0209f, bw_params1[i], 5);
129 if (ret)
130 goto error;
131
132 ret = cxd2820r_wr_reg_mask(priv, 0x020d7, bw_param << 6, 0xc0);
133 if (ret)
134 goto error;
135
136 ret = cxd2820r_wr_reg(priv, 0x000ff, 0x08);
137 if (ret)
138 goto error;
139
140 ret = cxd2820r_wr_reg(priv, 0x000fe, 0x01);
141 if (ret)
142 goto error;
143
144 return ret;
145error:
146 dbg("%s: failed:%d", __func__, ret);
147 return ret;
148
149}
150
151static int cxd2820r_get_frontend_t2(struct dvb_frontend *fe,
152 struct dvb_frontend_parameters *p)
153{
154 struct cxd2820r_priv *priv = fe->demodulator_priv;
155 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
156 int ret;
157 u8 buf[2];
158
159 ret = cxd2820r_rd_regs(priv, 0x0205c, buf, 2);
160 if (ret)
161 goto error;
162
163 switch ((buf[0] >> 0) & 0x07) {
164 case 0:
165 c->transmission_mode = TRANSMISSION_MODE_2K;
166 break;
167 case 1:
168 c->transmission_mode = TRANSMISSION_MODE_8K;
169 break;
170 case 2:
171 c->transmission_mode = TRANSMISSION_MODE_4K;
172 break;
173 case 3:
174 c->transmission_mode = TRANSMISSION_MODE_1K;
175 break;
176 case 4:
177 c->transmission_mode = TRANSMISSION_MODE_16K;
178 break;
179 case 5:
180 c->transmission_mode = TRANSMISSION_MODE_32K;
181 break;
182 }
183
184 switch ((buf[1] >> 4) & 0x07) {
185 case 0:
186 c->guard_interval = GUARD_INTERVAL_1_32;
187 break;
188 case 1:
189 c->guard_interval = GUARD_INTERVAL_1_16;
190 break;
191 case 2:
192 c->guard_interval = GUARD_INTERVAL_1_8;
193 break;
194 case 3:
195 c->guard_interval = GUARD_INTERVAL_1_4;
196 break;
197 case 4:
198 c->guard_interval = GUARD_INTERVAL_1_128;
199 break;
200 case 5:
201 c->guard_interval = GUARD_INTERVAL_19_128;
202 break;
203 case 6:
204 c->guard_interval = GUARD_INTERVAL_19_256;
205 break;
206 }
207
208 ret = cxd2820r_rd_regs(priv, 0x0225b, buf, 2);
209 if (ret)
210 goto error;
211
212 switch ((buf[0] >> 0) & 0x07) {
213 case 0:
214 c->fec_inner = FEC_1_2;
215 break;
216 case 1:
217 c->fec_inner = FEC_3_5;
218 break;
219 case 2:
220 c->fec_inner = FEC_2_3;
221 break;
222 case 3:
223 c->fec_inner = FEC_3_4;
224 break;
225 case 4:
226 c->fec_inner = FEC_4_5;
227 break;
228 case 5:
229 c->fec_inner = FEC_5_6;
230 break;
231 }
232
233 switch ((buf[1] >> 0) & 0x07) {
234 case 0:
235 c->modulation = QPSK;
236 break;
237 case 1:
238 c->modulation = QAM_16;
239 break;
240 case 2:
241 c->modulation = QAM_64;
242 break;
243 case 3:
244 c->modulation = QAM_256;
245 break;
246 }
247
248 ret = cxd2820r_rd_reg(priv, 0x020b5, &buf[0]);
249 if (ret)
250 goto error;
251
252 switch ((buf[0] >> 4) & 0x01) {
253 case 0:
254 c->inversion = INVERSION_OFF;
255 break;
256 case 1:
257 c->inversion = INVERSION_ON;
258 break;
259 }
260
261 return ret;
262error:
263 dbg("%s: failed:%d", __func__, ret);
264 return ret;
265}
266
267static int cxd2820r_read_status_t2(struct dvb_frontend *fe, fe_status_t *status)
268{
269 struct cxd2820r_priv *priv = fe->demodulator_priv;
270 int ret;
271 u8 buf[1];
272 *status = 0;
273
274 ret = cxd2820r_rd_reg(priv, 0x02010 , &buf[0]);
275 if (ret)
276 goto error;
277
278 if ((buf[0] & 0x07) == 6) {
279 if (((buf[0] >> 5) & 0x01) == 1) {
280 *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
281 FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
282 } else {
283 *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
284 FE_HAS_VITERBI | FE_HAS_SYNC;
285 }
286 }
287
288 dbg("%s: lock=%02x", __func__, buf[0]);
289
290 return ret;
291error:
292 dbg("%s: failed:%d", __func__, ret);
293 return ret;
294}
295
296static int cxd2820r_read_ber_t2(struct dvb_frontend *fe, u32 *ber)
297{
298 struct cxd2820r_priv *priv = fe->demodulator_priv;
299 int ret;
300 u8 buf[4];
301 unsigned int errbits;
302 *ber = 0;
303 /* FIXME: correct calculation */
304
305 ret = cxd2820r_rd_regs(priv, 0x02039, buf, sizeof(buf));
306 if (ret)
307 goto error;
308
309 if ((buf[0] >> 4) & 0x01) {
310 errbits = (buf[0] & 0x0f) << 24 | buf[1] << 16 |
311 buf[2] << 8 | buf[3];
312
313 if (errbits)
314 *ber = errbits * 64 / 16588800;
315 }
316
317 return ret;
318error:
319 dbg("%s: failed:%d", __func__, ret);
320 return ret;
321}
322
323static int cxd2820r_read_signal_strength_t2(struct dvb_frontend *fe,
324 u16 *strength)
325{
326 struct cxd2820r_priv *priv = fe->demodulator_priv;
327 int ret;
328 u8 buf[2];
329 u16 tmp;
330
331 ret = cxd2820r_rd_regs(priv, 0x02026, buf, sizeof(buf));
332 if (ret)
333 goto error;
334
335 tmp = (buf[0] & 0x0f) << 8 | buf[1];
336 tmp = ~tmp & 0x0fff;
337
338 /* scale value to 0x0000-0xffff from 0x0000-0x0fff */
339 *strength = tmp * 0xffff / 0x0fff;
340
341 return ret;
342error:
343 dbg("%s: failed:%d", __func__, ret);
344 return ret;
345}
346
347static int cxd2820r_read_snr_t2(struct dvb_frontend *fe, u16 *snr)
348{
349 struct cxd2820r_priv *priv = fe->demodulator_priv;
350 int ret;
351 u8 buf[2];
352 u16 tmp;
353 /* report SNR in dB * 10 */
354
355 ret = cxd2820r_rd_regs(priv, 0x02028, buf, sizeof(buf));
356 if (ret)
357 goto error;
358
359 tmp = (buf[0] & 0x0f) << 8 | buf[1];
360 #define CXD2820R_LOG10_8_24 15151336 /* log10(8) << 24 */
361 if (tmp)
362 *snr = (intlog10(tmp) - CXD2820R_LOG10_8_24) / ((1 << 24)
363 / 100);
364 else
365 *snr = 0;
366
367 dbg("%s: dBx10=%d val=%04x", __func__, *snr, tmp);
368
369 return ret;
370error:
371 dbg("%s: failed:%d", __func__, ret);
372 return ret;
373}
374
375static int cxd2820r_read_ucblocks_t2(struct dvb_frontend *fe, u32 *ucblocks)
376{
377 *ucblocks = 0;
378 /* no way to read ? */
379 return 0;
380}
381
382static int cxd2820r_sleep_t2(struct dvb_frontend *fe)
383{
384 struct cxd2820r_priv *priv = fe->demodulator_priv;
385 int ret, i;
386 struct reg_val_mask tab[] = {
387 { 0x000ff, 0x1f, 0xff },
388 { 0x00085, 0x00, 0xff },
389 { 0x00088, 0x01, 0xff },
390 { 0x02069, 0x00, 0xff },
391 { 0x00081, 0x00, 0xff },
392 { 0x00080, 0x00, 0xff },
393 };
394
395 dbg("%s", __func__);
396
397 for (i = 0; i < ARRAY_SIZE(tab); i++) {
398 ret = cxd2820r_wr_reg_mask(priv, tab[i].reg, tab[i].val,
399 tab[i].mask);
400 if (ret)
401 goto error;
402 }
403
404 priv->delivery_system = SYS_UNDEFINED;
405
406 return ret;
407error:
408 dbg("%s: failed:%d", __func__, ret);
409 return ret;
410}
411
412static int cxd2820r_get_tune_settings_t2(struct dvb_frontend *fe,
413 struct dvb_frontend_tune_settings *s)
414{
415 s->min_delay_ms = 1500;
416 s->step_size = fe->ops.info.frequency_stepsize * 2;
417 s->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
418
419 return 0;
420}
421