0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
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
0030 const struct cx22702_config *config;
0031
0032 struct dvb_frontend frontend;
0033
0034
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
0045 static const u8 init_tab[] = {
0046 0x00, 0x00,
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 = ®, .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
0136 static int cx22702_get_tps(struct cx22702_state *state,
0137 struct dtv_frontend_properties *p)
0138 {
0139 u8 val;
0140
0141
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
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
0264 cx22702_set_inversion(state, p->inversion);
0265
0266
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;
0284
0285
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
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);
0302 dprintk("%s: Autodetecting\n", __func__);
0303 return 0;
0304 }
0305
0306
0307 switch (p->modulation) {
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) {
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) {
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) {
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) {
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) {
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
0416 cx22702_writereg(state, 0x00, 0x01);
0417
0418 return 0;
0419 }
0420
0421
0422
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
0478 *ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 7
0479 | (cx22702_readreg(state, 0xDF) & 0x7F);
0480 } else {
0481
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
0497
0498
0499
0500
0501
0502
0503
0504
0505 reg23 = cx22702_readreg(state, 0x23);
0506 if (reg23 & 0x80) {
0507 *signal_strength = 0;
0508 } else {
0509 reg23 = ~reg23 & 0x7f;
0510
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
0524 rs_ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 7
0525 | (cx22702_readreg(state, 0xDF) & 0x7F);
0526 } else {
0527
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
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
0585 state = kzalloc(sizeof(struct cx22702_state), GFP_KERNEL);
0586 if (state == NULL)
0587 goto error;
0588
0589
0590 state->config = config;
0591 state->i2c = i2c;
0592
0593
0594 if (cx22702_readreg(state, 0x1f) != 0x3)
0595 goto error;
0596
0597
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");