Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003     Conexant 22702 DVB OFDM demodulator driver
0004 
0005     based on:
0006     Alps TDMB7 DVB OFDM demodulator driver
0007 
0008     Copyright (C) 2001-2002 Convergence Integrated Media GmbH
0009       Holger Waechtler <holger@convergence.de>
0010 
0011     Copyright (C) 2004 Steven Toth <stoth@linuxtv.org>
0012 
0013 
0014 */
0015 
0016 #include <linux/kernel.h>
0017 #include <linux/init.h>
0018 #include <linux/module.h>
0019 #include <linux/string.h>
0020 #include <linux/slab.h>
0021 #include <linux/delay.h>
0022 #include <media/dvb_frontend.h>
0023 #include "cx22702.h"
0024 
0025 struct cx22702_state {
0026 
0027     struct i2c_adapter *i2c;
0028 
0029     /* configuration settings */
0030     const struct cx22702_config *config;
0031 
0032     struct dvb_frontend frontend;
0033 
0034     /* previous uncorrected block counter */
0035     u8 prevUCBlocks;
0036 };
0037 
0038 static int debug;
0039 module_param(debug, int, 0644);
0040 MODULE_PARM_DESC(debug, "Enable verbose debug messages");
0041 
0042 #define dprintk if (debug) printk
0043 
0044 /* Register values to initialise the demod */
0045 static const u8 init_tab[] = {
0046     0x00, 0x00, /* Stop acquisition */
0047     0x0B, 0x06,
0048     0x09, 0x01,
0049     0x0D, 0x41,
0050     0x16, 0x32,
0051     0x20, 0x0A,
0052     0x21, 0x17,
0053     0x24, 0x3e,
0054     0x26, 0xff,
0055     0x27, 0x10,
0056     0x28, 0x00,
0057     0x29, 0x00,
0058     0x2a, 0x10,
0059     0x2b, 0x00,
0060     0x2c, 0x10,
0061     0x2d, 0x00,
0062     0x48, 0xd4,
0063     0x49, 0x56,
0064     0x6b, 0x1e,
0065     0xc8, 0x02,
0066     0xf9, 0x00,
0067     0xfa, 0x00,
0068     0xfb, 0x00,
0069     0xfc, 0x00,
0070     0xfd, 0x00,
0071 };
0072 
0073 static int cx22702_writereg(struct cx22702_state *state, u8 reg, u8 data)
0074 {
0075     int ret;
0076     u8 buf[] = { reg, data };
0077     struct i2c_msg msg = {
0078         .addr = state->config->demod_address, .flags = 0,
0079             .buf = buf, .len = 2 };
0080 
0081     ret = i2c_transfer(state->i2c, &msg, 1);
0082 
0083     if (unlikely(ret != 1)) {
0084         printk(KERN_ERR
0085             "%s: error (reg == 0x%02x, val == 0x%02x, ret == %i)\n",
0086             __func__, reg, data, ret);
0087         return -1;
0088     }
0089 
0090     return 0;
0091 }
0092 
0093 static u8 cx22702_readreg(struct cx22702_state *state, u8 reg)
0094 {
0095     int ret;
0096     u8 data;
0097 
0098     struct i2c_msg msg[] = {
0099         { .addr = state->config->demod_address, .flags = 0,
0100             .buf = &reg, .len = 1 },
0101         { .addr = state->config->demod_address, .flags = I2C_M_RD,
0102             .buf = &data, .len = 1 } };
0103 
0104     ret = i2c_transfer(state->i2c, msg, 2);
0105 
0106     if (unlikely(ret != 2)) {
0107         printk(KERN_ERR "%s: error (reg == 0x%02x, ret == %i)\n",
0108             __func__, reg, ret);
0109         return 0;
0110     }
0111 
0112     return data;
0113 }
0114 
0115 static int cx22702_set_inversion(struct cx22702_state *state, int inversion)
0116 {
0117     u8 val;
0118 
0119     val = cx22702_readreg(state, 0x0C);
0120     switch (inversion) {
0121     case INVERSION_AUTO:
0122         return -EOPNOTSUPP;
0123     case INVERSION_ON:
0124         val |= 0x01;
0125         break;
0126     case INVERSION_OFF:
0127         val &= 0xfe;
0128         break;
0129     default:
0130         return -EINVAL;
0131     }
0132     return cx22702_writereg(state, 0x0C, val);
0133 }
0134 
0135 /* Retrieve the demod settings */
0136 static int cx22702_get_tps(struct cx22702_state *state,
0137                struct dtv_frontend_properties *p)
0138 {
0139     u8 val;
0140 
0141     /* Make sure the TPS regs are valid */
0142     if (!(cx22702_readreg(state, 0x0A) & 0x20))
0143         return -EAGAIN;
0144 
0145     val = cx22702_readreg(state, 0x01);
0146     switch ((val & 0x18) >> 3) {
0147     case 0:
0148         p->modulation = QPSK;
0149         break;
0150     case 1:
0151         p->modulation = QAM_16;
0152         break;
0153     case 2:
0154         p->modulation = QAM_64;
0155         break;
0156     }
0157     switch (val & 0x07) {
0158     case 0:
0159         p->hierarchy = HIERARCHY_NONE;
0160         break;
0161     case 1:
0162         p->hierarchy = HIERARCHY_1;
0163         break;
0164     case 2:
0165         p->hierarchy = HIERARCHY_2;
0166         break;
0167     case 3:
0168         p->hierarchy = HIERARCHY_4;
0169         break;
0170     }
0171 
0172 
0173     val = cx22702_readreg(state, 0x02);
0174     switch ((val & 0x38) >> 3) {
0175     case 0:
0176         p->code_rate_HP = FEC_1_2;
0177         break;
0178     case 1:
0179         p->code_rate_HP = FEC_2_3;
0180         break;
0181     case 2:
0182         p->code_rate_HP = FEC_3_4;
0183         break;
0184     case 3:
0185         p->code_rate_HP = FEC_5_6;
0186         break;
0187     case 4:
0188         p->code_rate_HP = FEC_7_8;
0189         break;
0190     }
0191     switch (val & 0x07) {
0192     case 0:
0193         p->code_rate_LP = FEC_1_2;
0194         break;
0195     case 1:
0196         p->code_rate_LP = FEC_2_3;
0197         break;
0198     case 2:
0199         p->code_rate_LP = FEC_3_4;
0200         break;
0201     case 3:
0202         p->code_rate_LP = FEC_5_6;
0203         break;
0204     case 4:
0205         p->code_rate_LP = FEC_7_8;
0206         break;
0207     }
0208 
0209     val = cx22702_readreg(state, 0x03);
0210     switch ((val & 0x0c) >> 2) {
0211     case 0:
0212         p->guard_interval = GUARD_INTERVAL_1_32;
0213         break;
0214     case 1:
0215         p->guard_interval = GUARD_INTERVAL_1_16;
0216         break;
0217     case 2:
0218         p->guard_interval = GUARD_INTERVAL_1_8;
0219         break;
0220     case 3:
0221         p->guard_interval = GUARD_INTERVAL_1_4;
0222         break;
0223     }
0224     switch (val & 0x03) {
0225     case 0:
0226         p->transmission_mode = TRANSMISSION_MODE_2K;
0227         break;
0228     case 1:
0229         p->transmission_mode = TRANSMISSION_MODE_8K;
0230         break;
0231     }
0232 
0233     return 0;
0234 }
0235 
0236 static int cx22702_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
0237 {
0238     struct cx22702_state *state = fe->demodulator_priv;
0239     u8 val;
0240 
0241     dprintk("%s(%d)\n", __func__, enable);
0242     val = cx22702_readreg(state, 0x0D);
0243     if (enable)
0244         val &= 0xfe;
0245     else
0246         val |= 0x01;
0247     return cx22702_writereg(state, 0x0D, val);
0248 }
0249 
0250 /* Talk to the demod, set the FEC, GUARD, QAM settings etc */
0251 static int cx22702_set_tps(struct dvb_frontend *fe)
0252 {
0253     struct dtv_frontend_properties *p = &fe->dtv_property_cache;
0254     u8 val;
0255     struct cx22702_state *state = fe->demodulator_priv;
0256 
0257     if (fe->ops.tuner_ops.set_params) {
0258         fe->ops.tuner_ops.set_params(fe);
0259         if (fe->ops.i2c_gate_ctrl)
0260             fe->ops.i2c_gate_ctrl(fe, 0);
0261     }
0262 
0263     /* set inversion */
0264     cx22702_set_inversion(state, p->inversion);
0265 
0266     /* set bandwidth */
0267     val = cx22702_readreg(state, 0x0C) & 0xcf;
0268     switch (p->bandwidth_hz) {
0269     case 6000000:
0270         val |= 0x20;
0271         break;
0272     case 7000000:
0273         val |= 0x10;
0274         break;
0275     case 8000000:
0276         break;
0277     default:
0278         dprintk("%s: invalid bandwidth\n", __func__);
0279         return -EINVAL;
0280     }
0281     cx22702_writereg(state, 0x0C, val);
0282 
0283     p->code_rate_LP = FEC_AUTO; /* temp hack as manual not working */
0284 
0285     /* use auto configuration? */
0286     if ((p->hierarchy == HIERARCHY_AUTO) ||
0287        (p->modulation == QAM_AUTO) ||
0288        (p->code_rate_HP == FEC_AUTO) ||
0289        (p->code_rate_LP == FEC_AUTO) ||
0290        (p->guard_interval == GUARD_INTERVAL_AUTO) ||
0291        (p->transmission_mode == TRANSMISSION_MODE_AUTO)) {
0292 
0293         /* TPS Source - use hardware driven values */
0294         cx22702_writereg(state, 0x06, 0x10);
0295         cx22702_writereg(state, 0x07, 0x9);
0296         cx22702_writereg(state, 0x08, 0xC1);
0297         cx22702_writereg(state, 0x0B, cx22702_readreg(state, 0x0B)
0298             & 0xfc);
0299         cx22702_writereg(state, 0x0C,
0300             (cx22702_readreg(state, 0x0C) & 0xBF) | 0x40);
0301         cx22702_writereg(state, 0x00, 0x01); /* Begin acquisition */
0302         dprintk("%s: Autodetecting\n", __func__);
0303         return 0;
0304     }
0305 
0306     /* manually programmed values */
0307     switch (p->modulation) {        /* mask 0x18 */
0308     case QPSK:
0309         val = 0x00;
0310         break;
0311     case QAM_16:
0312         val = 0x08;
0313         break;
0314     case QAM_64:
0315         val = 0x10;
0316         break;
0317     default:
0318         dprintk("%s: invalid modulation\n", __func__);
0319         return -EINVAL;
0320     }
0321     switch (p->hierarchy) { /* mask 0x07 */
0322     case HIERARCHY_NONE:
0323         break;
0324     case HIERARCHY_1:
0325         val |= 0x01;
0326         break;
0327     case HIERARCHY_2:
0328         val |= 0x02;
0329         break;
0330     case HIERARCHY_4:
0331         val |= 0x03;
0332         break;
0333     default:
0334         dprintk("%s: invalid hierarchy\n", __func__);
0335         return -EINVAL;
0336     }
0337     cx22702_writereg(state, 0x06, val);
0338 
0339     switch (p->code_rate_HP) {      /* mask 0x38 */
0340     case FEC_NONE:
0341     case FEC_1_2:
0342         val = 0x00;
0343         break;
0344     case FEC_2_3:
0345         val = 0x08;
0346         break;
0347     case FEC_3_4:
0348         val = 0x10;
0349         break;
0350     case FEC_5_6:
0351         val = 0x18;
0352         break;
0353     case FEC_7_8:
0354         val = 0x20;
0355         break;
0356     default:
0357         dprintk("%s: invalid code_rate_HP\n", __func__);
0358         return -EINVAL;
0359     }
0360     switch (p->code_rate_LP) {      /* mask 0x07 */
0361     case FEC_NONE:
0362     case FEC_1_2:
0363         break;
0364     case FEC_2_3:
0365         val |= 0x01;
0366         break;
0367     case FEC_3_4:
0368         val |= 0x02;
0369         break;
0370     case FEC_5_6:
0371         val |= 0x03;
0372         break;
0373     case FEC_7_8:
0374         val |= 0x04;
0375         break;
0376     default:
0377         dprintk("%s: invalid code_rate_LP\n", __func__);
0378         return -EINVAL;
0379     }
0380     cx22702_writereg(state, 0x07, val);
0381 
0382     switch (p->guard_interval) {        /* mask 0x0c */
0383     case GUARD_INTERVAL_1_32:
0384         val = 0x00;
0385         break;
0386     case GUARD_INTERVAL_1_16:
0387         val = 0x04;
0388         break;
0389     case GUARD_INTERVAL_1_8:
0390         val = 0x08;
0391         break;
0392     case GUARD_INTERVAL_1_4:
0393         val = 0x0c;
0394         break;
0395     default:
0396         dprintk("%s: invalid guard_interval\n", __func__);
0397         return -EINVAL;
0398     }
0399     switch (p->transmission_mode) {     /* mask 0x03 */
0400     case TRANSMISSION_MODE_2K:
0401         break;
0402     case TRANSMISSION_MODE_8K:
0403         val |= 0x1;
0404         break;
0405     default:
0406         dprintk("%s: invalid transmission_mode\n", __func__);
0407         return -EINVAL;
0408     }
0409     cx22702_writereg(state, 0x08, val);
0410     cx22702_writereg(state, 0x0B,
0411         (cx22702_readreg(state, 0x0B) & 0xfc) | 0x02);
0412     cx22702_writereg(state, 0x0C,
0413         (cx22702_readreg(state, 0x0C) & 0xBF) | 0x40);
0414 
0415     /* Begin channel acquisition */
0416     cx22702_writereg(state, 0x00, 0x01);
0417 
0418     return 0;
0419 }
0420 
0421 /* Reset the demod hardware and reset all of the configuration registers
0422    to a default state. */
0423 static int cx22702_init(struct dvb_frontend *fe)
0424 {
0425     int i;
0426     struct cx22702_state *state = fe->demodulator_priv;
0427 
0428     cx22702_writereg(state, 0x00, 0x02);
0429 
0430     msleep(10);
0431 
0432     for (i = 0; i < ARRAY_SIZE(init_tab); i += 2)
0433         cx22702_writereg(state, init_tab[i], init_tab[i + 1]);
0434 
0435     cx22702_writereg(state, 0xf8, (state->config->output_mode << 1)
0436         & 0x02);
0437 
0438     cx22702_i2c_gate_ctrl(fe, 0);
0439 
0440     return 0;
0441 }
0442 
0443 static int cx22702_read_status(struct dvb_frontend *fe, enum fe_status *status)
0444 {
0445     struct cx22702_state *state = fe->demodulator_priv;
0446     u8 reg0A;
0447     u8 reg23;
0448 
0449     *status = 0;
0450 
0451     reg0A = cx22702_readreg(state, 0x0A);
0452     reg23 = cx22702_readreg(state, 0x23);
0453 
0454     dprintk("%s: status demod=0x%02x agc=0x%02x\n"
0455         , __func__, reg0A, reg23);
0456 
0457     if (reg0A & 0x10) {
0458         *status |= FE_HAS_LOCK;
0459         *status |= FE_HAS_VITERBI;
0460         *status |= FE_HAS_SYNC;
0461     }
0462 
0463     if (reg0A & 0x20)
0464         *status |= FE_HAS_CARRIER;
0465 
0466     if (reg23 < 0xf0)
0467         *status |= FE_HAS_SIGNAL;
0468 
0469     return 0;
0470 }
0471 
0472 static int cx22702_read_ber(struct dvb_frontend *fe, u32 *ber)
0473 {
0474     struct cx22702_state *state = fe->demodulator_priv;
0475 
0476     if (cx22702_readreg(state, 0xE4) & 0x02) {
0477         /* Realtime statistics */
0478         *ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 7
0479             | (cx22702_readreg(state, 0xDF) & 0x7F);
0480     } else {
0481         /* Averagtine statistics */
0482         *ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 7
0483             | cx22702_readreg(state, 0xDF);
0484     }
0485 
0486     return 0;
0487 }
0488 
0489 static int cx22702_read_signal_strength(struct dvb_frontend *fe,
0490     u16 *signal_strength)
0491 {
0492     struct cx22702_state *state = fe->demodulator_priv;
0493     u8 reg23;
0494 
0495     /*
0496      * Experience suggests that the strength signal register works as
0497      * follows:
0498      * - In the absence of signal, value is 0xff.
0499      * - In the presence of a weak signal, bit 7 is set, not sure what
0500      *   the lower 7 bits mean.
0501      * - In the presence of a strong signal, the register holds a 7-bit
0502      *   value (bit 7 is cleared), with greater values standing for
0503      *   weaker signals.
0504      */
0505     reg23 = cx22702_readreg(state, 0x23);
0506     if (reg23 & 0x80) {
0507         *signal_strength = 0;
0508     } else {
0509         reg23 = ~reg23 & 0x7f;
0510         /* Scale to 16 bit */
0511         *signal_strength = (reg23 << 9) | (reg23 << 2) | (reg23 >> 5);
0512     }
0513 
0514     return 0;
0515 }
0516 
0517 static int cx22702_read_snr(struct dvb_frontend *fe, u16 *snr)
0518 {
0519     struct cx22702_state *state = fe->demodulator_priv;
0520 
0521     u16 rs_ber;
0522     if (cx22702_readreg(state, 0xE4) & 0x02) {
0523         /* Realtime statistics */
0524         rs_ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 7
0525             | (cx22702_readreg(state, 0xDF) & 0x7F);
0526     } else {
0527         /* Averagine statistics */
0528         rs_ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 8
0529             | cx22702_readreg(state, 0xDF);
0530     }
0531     *snr = ~rs_ber;
0532 
0533     return 0;
0534 }
0535 
0536 static int cx22702_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
0537 {
0538     struct cx22702_state *state = fe->demodulator_priv;
0539 
0540     u8 _ucblocks;
0541 
0542     /* RS Uncorrectable Packet Count then reset */
0543     _ucblocks = cx22702_readreg(state, 0xE3);
0544     if (state->prevUCBlocks < _ucblocks)
0545         *ucblocks = (_ucblocks - state->prevUCBlocks);
0546     else
0547         *ucblocks = state->prevUCBlocks - _ucblocks;
0548     state->prevUCBlocks = _ucblocks;
0549 
0550     return 0;
0551 }
0552 
0553 static int cx22702_get_frontend(struct dvb_frontend *fe,
0554                 struct dtv_frontend_properties *c)
0555 {
0556     struct cx22702_state *state = fe->demodulator_priv;
0557 
0558     u8 reg0C = cx22702_readreg(state, 0x0C);
0559 
0560     c->inversion = reg0C & 0x1 ? INVERSION_ON : INVERSION_OFF;
0561     return cx22702_get_tps(state, c);
0562 }
0563 
0564 static int cx22702_get_tune_settings(struct dvb_frontend *fe,
0565     struct dvb_frontend_tune_settings *tune)
0566 {
0567     tune->min_delay_ms = 1000;
0568     return 0;
0569 }
0570 
0571 static void cx22702_release(struct dvb_frontend *fe)
0572 {
0573     struct cx22702_state *state = fe->demodulator_priv;
0574     kfree(state);
0575 }
0576 
0577 static const struct dvb_frontend_ops cx22702_ops;
0578 
0579 struct dvb_frontend *cx22702_attach(const struct cx22702_config *config,
0580     struct i2c_adapter *i2c)
0581 {
0582     struct cx22702_state *state = NULL;
0583 
0584     /* allocate memory for the internal state */
0585     state = kzalloc(sizeof(struct cx22702_state), GFP_KERNEL);
0586     if (state == NULL)
0587         goto error;
0588 
0589     /* setup the state */
0590     state->config = config;
0591     state->i2c = i2c;
0592 
0593     /* check if the demod is there */
0594     if (cx22702_readreg(state, 0x1f) != 0x3)
0595         goto error;
0596 
0597     /* create dvb_frontend */
0598     memcpy(&state->frontend.ops, &cx22702_ops,
0599         sizeof(struct dvb_frontend_ops));
0600     state->frontend.demodulator_priv = state;
0601     return &state->frontend;
0602 
0603 error:
0604     kfree(state);
0605     return NULL;
0606 }
0607 EXPORT_SYMBOL(cx22702_attach);
0608 
0609 static const struct dvb_frontend_ops cx22702_ops = {
0610     .delsys = { SYS_DVBT },
0611     .info = {
0612         .name           = "Conexant CX22702 DVB-T",
0613         .frequency_min_hz   = 177 * MHz,
0614         .frequency_max_hz   = 858 * MHz,
0615         .frequency_stepsize_hz  = 166666,
0616         .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
0617         FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
0618         FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
0619         FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
0620         FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER
0621     },
0622 
0623     .release = cx22702_release,
0624 
0625     .init = cx22702_init,
0626     .i2c_gate_ctrl = cx22702_i2c_gate_ctrl,
0627 
0628     .set_frontend = cx22702_set_tps,
0629     .get_frontend = cx22702_get_frontend,
0630     .get_tune_settings = cx22702_get_tune_settings,
0631 
0632     .read_status = cx22702_read_status,
0633     .read_ber = cx22702_read_ber,
0634     .read_signal_strength = cx22702_read_signal_strength,
0635     .read_snr = cx22702_read_snr,
0636     .read_ucblocks = cx22702_read_ucblocks,
0637 };
0638 
0639 MODULE_DESCRIPTION("Conexant CX22702 DVB-T Demodulator driver");
0640 MODULE_AUTHOR("Steven Toth");
0641 MODULE_LICENSE("GPL");