1 // SPDX-License-Identifier: GPL-2.0-or-later
3 Conexant 22702 DVB OFDM demodulator driver
6 Alps TDMB7 DVB OFDM demodulator driver
8 Copyright (C) 2001-2002 Convergence Integrated Media GmbH
9 Holger Waechtler <holger@convergence.de>
11 Copyright (C) 2004 Steven Toth <stoth@linuxtv.org>
16 #include <linux/kernel.h>
17 #include <linux/init.h>
18 #include <linux/module.h>
19 #include <linux/string.h>
20 #include <linux/slab.h>
21 #include <linux/delay.h>
22 #include <media/dvb_frontend.h>
25 struct cx22702_state
{
27 struct i2c_adapter
*i2c
;
29 /* configuration settings */
30 const struct cx22702_config
*config
;
32 struct dvb_frontend frontend
;
34 /* previous uncorrected block counter */
39 module_param(debug
, int, 0644);
40 MODULE_PARM_DESC(debug
, "Enable verbose debug messages");
42 #define dprintk if (debug) printk
44 /* Register values to initialise the demod */
45 static const u8 init_tab
[] = {
46 0x00, 0x00, /* Stop acquisition */
73 static int cx22702_writereg(struct cx22702_state
*state
, u8 reg
, u8 data
)
76 u8 buf
[] = { reg
, data
};
77 struct i2c_msg msg
= {
78 .addr
= state
->config
->demod_address
, .flags
= 0,
79 .buf
= buf
, .len
= 2 };
81 ret
= i2c_transfer(state
->i2c
, &msg
, 1);
83 if (unlikely(ret
!= 1)) {
85 "%s: error (reg == 0x%02x, val == 0x%02x, ret == %i)\n",
86 __func__
, reg
, data
, ret
);
93 static u8
cx22702_readreg(struct cx22702_state
*state
, u8 reg
)
98 struct i2c_msg msg
[] = {
99 { .addr
= state
->config
->demod_address
, .flags
= 0,
100 .buf
= ®
, .len
= 1 },
101 { .addr
= state
->config
->demod_address
, .flags
= I2C_M_RD
,
102 .buf
= &data
, .len
= 1 } };
104 ret
= i2c_transfer(state
->i2c
, msg
, 2);
106 if (unlikely(ret
!= 2)) {
107 printk(KERN_ERR
"%s: error (reg == 0x%02x, ret == %i)\n",
115 static int cx22702_set_inversion(struct cx22702_state
*state
, int inversion
)
119 val
= cx22702_readreg(state
, 0x0C);
132 return cx22702_writereg(state
, 0x0C, val
);
135 /* Retrieve the demod settings */
136 static int cx22702_get_tps(struct cx22702_state
*state
,
137 struct dtv_frontend_properties
*p
)
141 /* Make sure the TPS regs are valid */
142 if (!(cx22702_readreg(state
, 0x0A) & 0x20))
145 val
= cx22702_readreg(state
, 0x01);
146 switch ((val
& 0x18) >> 3) {
148 p
->modulation
= QPSK
;
151 p
->modulation
= QAM_16
;
154 p
->modulation
= QAM_64
;
157 switch (val
& 0x07) {
159 p
->hierarchy
= HIERARCHY_NONE
;
162 p
->hierarchy
= HIERARCHY_1
;
165 p
->hierarchy
= HIERARCHY_2
;
168 p
->hierarchy
= HIERARCHY_4
;
173 val
= cx22702_readreg(state
, 0x02);
174 switch ((val
& 0x38) >> 3) {
176 p
->code_rate_HP
= FEC_1_2
;
179 p
->code_rate_HP
= FEC_2_3
;
182 p
->code_rate_HP
= FEC_3_4
;
185 p
->code_rate_HP
= FEC_5_6
;
188 p
->code_rate_HP
= FEC_7_8
;
191 switch (val
& 0x07) {
193 p
->code_rate_LP
= FEC_1_2
;
196 p
->code_rate_LP
= FEC_2_3
;
199 p
->code_rate_LP
= FEC_3_4
;
202 p
->code_rate_LP
= FEC_5_6
;
205 p
->code_rate_LP
= FEC_7_8
;
209 val
= cx22702_readreg(state
, 0x03);
210 switch ((val
& 0x0c) >> 2) {
212 p
->guard_interval
= GUARD_INTERVAL_1_32
;
215 p
->guard_interval
= GUARD_INTERVAL_1_16
;
218 p
->guard_interval
= GUARD_INTERVAL_1_8
;
221 p
->guard_interval
= GUARD_INTERVAL_1_4
;
224 switch (val
& 0x03) {
226 p
->transmission_mode
= TRANSMISSION_MODE_2K
;
229 p
->transmission_mode
= TRANSMISSION_MODE_8K
;
236 static int cx22702_i2c_gate_ctrl(struct dvb_frontend
*fe
, int enable
)
238 struct cx22702_state
*state
= fe
->demodulator_priv
;
241 dprintk("%s(%d)\n", __func__
, enable
);
242 val
= cx22702_readreg(state
, 0x0D);
247 return cx22702_writereg(state
, 0x0D, val
);
250 /* Talk to the demod, set the FEC, GUARD, QAM settings etc */
251 static int cx22702_set_tps(struct dvb_frontend
*fe
)
253 struct dtv_frontend_properties
*p
= &fe
->dtv_property_cache
;
255 struct cx22702_state
*state
= fe
->demodulator_priv
;
257 if (fe
->ops
.tuner_ops
.set_params
) {
258 fe
->ops
.tuner_ops
.set_params(fe
);
259 if (fe
->ops
.i2c_gate_ctrl
)
260 fe
->ops
.i2c_gate_ctrl(fe
, 0);
264 cx22702_set_inversion(state
, p
->inversion
);
267 val
= cx22702_readreg(state
, 0x0C) & 0xcf;
268 switch (p
->bandwidth_hz
) {
278 dprintk("%s: invalid bandwidth\n", __func__
);
281 cx22702_writereg(state
, 0x0C, val
);
283 p
->code_rate_LP
= FEC_AUTO
; /* temp hack as manual not working */
285 /* use auto configuration? */
286 if ((p
->hierarchy
== HIERARCHY_AUTO
) ||
287 (p
->modulation
== QAM_AUTO
) ||
288 (p
->code_rate_HP
== FEC_AUTO
) ||
289 (p
->code_rate_LP
== FEC_AUTO
) ||
290 (p
->guard_interval
== GUARD_INTERVAL_AUTO
) ||
291 (p
->transmission_mode
== TRANSMISSION_MODE_AUTO
)) {
293 /* TPS Source - use hardware driven values */
294 cx22702_writereg(state
, 0x06, 0x10);
295 cx22702_writereg(state
, 0x07, 0x9);
296 cx22702_writereg(state
, 0x08, 0xC1);
297 cx22702_writereg(state
, 0x0B, cx22702_readreg(state
, 0x0B)
299 cx22702_writereg(state
, 0x0C,
300 (cx22702_readreg(state
, 0x0C) & 0xBF) | 0x40);
301 cx22702_writereg(state
, 0x00, 0x01); /* Begin acquisition */
302 dprintk("%s: Autodetecting\n", __func__
);
306 /* manually programmed values */
307 switch (p
->modulation
) { /* mask 0x18 */
318 dprintk("%s: invalid modulation\n", __func__
);
321 switch (p
->hierarchy
) { /* mask 0x07 */
334 dprintk("%s: invalid hierarchy\n", __func__
);
337 cx22702_writereg(state
, 0x06, val
);
339 switch (p
->code_rate_HP
) { /* mask 0x38 */
357 dprintk("%s: invalid code_rate_HP\n", __func__
);
360 switch (p
->code_rate_LP
) { /* mask 0x07 */
377 dprintk("%s: invalid code_rate_LP\n", __func__
);
380 cx22702_writereg(state
, 0x07, val
);
382 switch (p
->guard_interval
) { /* mask 0x0c */
383 case GUARD_INTERVAL_1_32
:
386 case GUARD_INTERVAL_1_16
:
389 case GUARD_INTERVAL_1_8
:
392 case GUARD_INTERVAL_1_4
:
396 dprintk("%s: invalid guard_interval\n", __func__
);
399 switch (p
->transmission_mode
) { /* mask 0x03 */
400 case TRANSMISSION_MODE_2K
:
402 case TRANSMISSION_MODE_8K
:
406 dprintk("%s: invalid transmission_mode\n", __func__
);
409 cx22702_writereg(state
, 0x08, val
);
410 cx22702_writereg(state
, 0x0B,
411 (cx22702_readreg(state
, 0x0B) & 0xfc) | 0x02);
412 cx22702_writereg(state
, 0x0C,
413 (cx22702_readreg(state
, 0x0C) & 0xBF) | 0x40);
415 /* Begin channel acquisition */
416 cx22702_writereg(state
, 0x00, 0x01);
421 /* Reset the demod hardware and reset all of the configuration registers
422 to a default state. */
423 static int cx22702_init(struct dvb_frontend
*fe
)
426 struct cx22702_state
*state
= fe
->demodulator_priv
;
428 cx22702_writereg(state
, 0x00, 0x02);
432 for (i
= 0; i
< ARRAY_SIZE(init_tab
); i
+= 2)
433 cx22702_writereg(state
, init_tab
[i
], init_tab
[i
+ 1]);
435 cx22702_writereg(state
, 0xf8, (state
->config
->output_mode
<< 1)
438 cx22702_i2c_gate_ctrl(fe
, 0);
443 static int cx22702_read_status(struct dvb_frontend
*fe
, enum fe_status
*status
)
445 struct cx22702_state
*state
= fe
->demodulator_priv
;
451 reg0A
= cx22702_readreg(state
, 0x0A);
452 reg23
= cx22702_readreg(state
, 0x23);
454 dprintk("%s: status demod=0x%02x agc=0x%02x\n"
455 , __func__
, reg0A
, reg23
);
458 *status
|= FE_HAS_LOCK
;
459 *status
|= FE_HAS_VITERBI
;
460 *status
|= FE_HAS_SYNC
;
464 *status
|= FE_HAS_CARRIER
;
467 *status
|= FE_HAS_SIGNAL
;
472 static int cx22702_read_ber(struct dvb_frontend
*fe
, u32
*ber
)
474 struct cx22702_state
*state
= fe
->demodulator_priv
;
476 if (cx22702_readreg(state
, 0xE4) & 0x02) {
477 /* Realtime statistics */
478 *ber
= (cx22702_readreg(state
, 0xDE) & 0x7F) << 7
479 | (cx22702_readreg(state
, 0xDF) & 0x7F);
481 /* Averagtine statistics */
482 *ber
= (cx22702_readreg(state
, 0xDE) & 0x7F) << 7
483 | cx22702_readreg(state
, 0xDF);
489 static int cx22702_read_signal_strength(struct dvb_frontend
*fe
,
490 u16
*signal_strength
)
492 struct cx22702_state
*state
= fe
->demodulator_priv
;
496 * Experience suggests that the strength signal register works as
498 * - In the absence of signal, value is 0xff.
499 * - In the presence of a weak signal, bit 7 is set, not sure what
500 * the lower 7 bits mean.
501 * - In the presence of a strong signal, the register holds a 7-bit
502 * value (bit 7 is cleared), with greater values standing for
505 reg23
= cx22702_readreg(state
, 0x23);
507 *signal_strength
= 0;
509 reg23
= ~reg23
& 0x7f;
510 /* Scale to 16 bit */
511 *signal_strength
= (reg23
<< 9) | (reg23
<< 2) | (reg23
>> 5);
517 static int cx22702_read_snr(struct dvb_frontend
*fe
, u16
*snr
)
519 struct cx22702_state
*state
= fe
->demodulator_priv
;
522 if (cx22702_readreg(state
, 0xE4) & 0x02) {
523 /* Realtime statistics */
524 rs_ber
= (cx22702_readreg(state
, 0xDE) & 0x7F) << 7
525 | (cx22702_readreg(state
, 0xDF) & 0x7F);
527 /* Averagine statistics */
528 rs_ber
= (cx22702_readreg(state
, 0xDE) & 0x7F) << 8
529 | cx22702_readreg(state
, 0xDF);
536 static int cx22702_read_ucblocks(struct dvb_frontend
*fe
, u32
*ucblocks
)
538 struct cx22702_state
*state
= fe
->demodulator_priv
;
542 /* RS Uncorrectable Packet Count then reset */
543 _ucblocks
= cx22702_readreg(state
, 0xE3);
544 if (state
->prevUCBlocks
< _ucblocks
)
545 *ucblocks
= (_ucblocks
- state
->prevUCBlocks
);
547 *ucblocks
= state
->prevUCBlocks
- _ucblocks
;
548 state
->prevUCBlocks
= _ucblocks
;
553 static int cx22702_get_frontend(struct dvb_frontend
*fe
,
554 struct dtv_frontend_properties
*c
)
556 struct cx22702_state
*state
= fe
->demodulator_priv
;
558 u8 reg0C
= cx22702_readreg(state
, 0x0C);
560 c
->inversion
= reg0C
& 0x1 ? INVERSION_ON
: INVERSION_OFF
;
561 return cx22702_get_tps(state
, c
);
564 static int cx22702_get_tune_settings(struct dvb_frontend
*fe
,
565 struct dvb_frontend_tune_settings
*tune
)
567 tune
->min_delay_ms
= 1000;
571 static void cx22702_release(struct dvb_frontend
*fe
)
573 struct cx22702_state
*state
= fe
->demodulator_priv
;
577 static const struct dvb_frontend_ops cx22702_ops
;
579 struct dvb_frontend
*cx22702_attach(const struct cx22702_config
*config
,
580 struct i2c_adapter
*i2c
)
582 struct cx22702_state
*state
= NULL
;
584 /* allocate memory for the internal state */
585 state
= kzalloc(sizeof(struct cx22702_state
), GFP_KERNEL
);
589 /* setup the state */
590 state
->config
= config
;
593 /* check if the demod is there */
594 if (cx22702_readreg(state
, 0x1f) != 0x3)
597 /* create dvb_frontend */
598 memcpy(&state
->frontend
.ops
, &cx22702_ops
,
599 sizeof(struct dvb_frontend_ops
));
600 state
->frontend
.demodulator_priv
= state
;
601 return &state
->frontend
;
607 EXPORT_SYMBOL(cx22702_attach
);
609 static const struct dvb_frontend_ops cx22702_ops
= {
610 .delsys
= { SYS_DVBT
},
612 .name
= "Conexant CX22702 DVB-T",
613 .frequency_min_hz
= 177 * MHz
,
614 .frequency_max_hz
= 858 * MHz
,
615 .frequency_stepsize_hz
= 166666,
616 .caps
= FE_CAN_FEC_1_2
| FE_CAN_FEC_2_3
| FE_CAN_FEC_3_4
|
617 FE_CAN_FEC_5_6
| FE_CAN_FEC_7_8
| FE_CAN_FEC_AUTO
|
618 FE_CAN_QPSK
| FE_CAN_QAM_16
| FE_CAN_QAM_64
| FE_CAN_QAM_AUTO
|
619 FE_CAN_HIERARCHY_AUTO
| FE_CAN_GUARD_INTERVAL_AUTO
|
620 FE_CAN_TRANSMISSION_MODE_AUTO
| FE_CAN_RECOVER
623 .release
= cx22702_release
,
625 .init
= cx22702_init
,
626 .i2c_gate_ctrl
= cx22702_i2c_gate_ctrl
,
628 .set_frontend
= cx22702_set_tps
,
629 .get_frontend
= cx22702_get_frontend
,
630 .get_tune_settings
= cx22702_get_tune_settings
,
632 .read_status
= cx22702_read_status
,
633 .read_ber
= cx22702_read_ber
,
634 .read_signal_strength
= cx22702_read_signal_strength
,
635 .read_snr
= cx22702_read_snr
,
636 .read_ucblocks
= cx22702_read_ucblocks
,
639 MODULE_DESCRIPTION("Conexant CX22702 DVB-T Demodulator driver");
640 MODULE_AUTHOR("Steven Toth");
641 MODULE_LICENSE("GPL");