1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 Conexant 22702 DVB OFDM demodulator driver 4 5 based on: 6 Alps TDMB7 DVB OFDM demodulator driver 7 8 Copyright (C) 2001-2002 Convergence Integrated Media GmbH 9 Holger Waechtler <holger@convergence.de> 10 11 Copyright (C) 2004 Steven Toth <stoth@linuxtv.org> 12 13 14 */ 15 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> 23 #include "cx22702.h" 24 25 struct cx22702_state { 26 27 struct i2c_adapter *i2c; 28 29 /* configuration settings */ 30 const struct cx22702_config *config; 31 32 struct dvb_frontend frontend; 33 34 /* previous uncorrected block counter */ 35 u8 prevUCBlocks; 36 }; 37 38 static int debug; 39 module_param(debug, int, 0644); 40 MODULE_PARM_DESC(debug, "Enable verbose debug messages"); 41 42 #define dprintk if (debug) printk 43 44 /* Register values to initialise the demod */ 45 static const u8 init_tab[] = { 46 0x00, 0x00, /* Stop acquisition */ 47 0x0B, 0x06, 48 0x09, 0x01, 49 0x0D, 0x41, 50 0x16, 0x32, 51 0x20, 0x0A, 52 0x21, 0x17, 53 0x24, 0x3e, 54 0x26, 0xff, 55 0x27, 0x10, 56 0x28, 0x00, 57 0x29, 0x00, 58 0x2a, 0x10, 59 0x2b, 0x00, 60 0x2c, 0x10, 61 0x2d, 0x00, 62 0x48, 0xd4, 63 0x49, 0x56, 64 0x6b, 0x1e, 65 0xc8, 0x02, 66 0xf9, 0x00, 67 0xfa, 0x00, 68 0xfb, 0x00, 69 0xfc, 0x00, 70 0xfd, 0x00, 71 }; 72 73 static int cx22702_writereg(struct cx22702_state *state, u8 reg, u8 data) 74 { 75 int ret; 76 u8 buf[] = { reg, data }; 77 struct i2c_msg msg = { 78 .addr = state->config->demod_address, .flags = 0, 79 .buf = buf, .len = 2 }; 80 81 ret = i2c_transfer(state->i2c, &msg, 1); 82 83 if (unlikely(ret != 1)) { 84 printk(KERN_ERR 85 "%s: error (reg == 0x%02x, val == 0x%02x, ret == %i)\n", 86 __func__, reg, data, ret); 87 return -1; 88 } 89 90 return 0; 91 } 92 93 static u8 cx22702_readreg(struct cx22702_state *state, u8 reg) 94 { 95 int ret; 96 u8 data; 97 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 } }; 103 104 ret = i2c_transfer(state->i2c, msg, 2); 105 106 if (unlikely(ret != 2)) { 107 printk(KERN_ERR "%s: error (reg == 0x%02x, ret == %i)\n", 108 __func__, reg, ret); 109 return 0; 110 } 111 112 return data; 113 } 114 115 static int cx22702_set_inversion(struct cx22702_state *state, int inversion) 116 { 117 u8 val; 118 119 val = cx22702_readreg(state, 0x0C); 120 switch (inversion) { 121 case INVERSION_AUTO: 122 return -EOPNOTSUPP; 123 case INVERSION_ON: 124 val |= 0x01; 125 break; 126 case INVERSION_OFF: 127 val &= 0xfe; 128 break; 129 default: 130 return -EINVAL; 131 } 132 return cx22702_writereg(state, 0x0C, val); 133 } 134 135 /* Retrieve the demod settings */ 136 static int cx22702_get_tps(struct cx22702_state *state, 137 struct dtv_frontend_properties *p) 138 { 139 u8 val; 140 141 /* Make sure the TPS regs are valid */ 142 if (!(cx22702_readreg(state, 0x0A) & 0x20)) 143 return -EAGAIN; 144 145 val = cx22702_readreg(state, 0x01); 146 switch ((val & 0x18) >> 3) { 147 case 0: 148 p->modulation = QPSK; 149 break; 150 case 1: 151 p->modulation = QAM_16; 152 break; 153 case 2: 154 p->modulation = QAM_64; 155 break; 156 } 157 switch (val & 0x07) { 158 case 0: 159 p->hierarchy = HIERARCHY_NONE; 160 break; 161 case 1: 162 p->hierarchy = HIERARCHY_1; 163 break; 164 case 2: 165 p->hierarchy = HIERARCHY_2; 166 break; 167 case 3: 168 p->hierarchy = HIERARCHY_4; 169 break; 170 } 171 172 173 val = cx22702_readreg(state, 0x02); 174 switch ((val & 0x38) >> 3) { 175 case 0: 176 p->code_rate_HP = FEC_1_2; 177 break; 178 case 1: 179 p->code_rate_HP = FEC_2_3; 180 break; 181 case 2: 182 p->code_rate_HP = FEC_3_4; 183 break; 184 case 3: 185 p->code_rate_HP = FEC_5_6; 186 break; 187 case 4: 188 p->code_rate_HP = FEC_7_8; 189 break; 190 } 191 switch (val & 0x07) { 192 case 0: 193 p->code_rate_LP = FEC_1_2; 194 break; 195 case 1: 196 p->code_rate_LP = FEC_2_3; 197 break; 198 case 2: 199 p->code_rate_LP = FEC_3_4; 200 break; 201 case 3: 202 p->code_rate_LP = FEC_5_6; 203 break; 204 case 4: 205 p->code_rate_LP = FEC_7_8; 206 break; 207 } 208 209 val = cx22702_readreg(state, 0x03); 210 switch ((val & 0x0c) >> 2) { 211 case 0: 212 p->guard_interval = GUARD_INTERVAL_1_32; 213 break; 214 case 1: 215 p->guard_interval = GUARD_INTERVAL_1_16; 216 break; 217 case 2: 218 p->guard_interval = GUARD_INTERVAL_1_8; 219 break; 220 case 3: 221 p->guard_interval = GUARD_INTERVAL_1_4; 222 break; 223 } 224 switch (val & 0x03) { 225 case 0: 226 p->transmission_mode = TRANSMISSION_MODE_2K; 227 break; 228 case 1: 229 p->transmission_mode = TRANSMISSION_MODE_8K; 230 break; 231 } 232 233 return 0; 234 } 235 236 static int cx22702_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) 237 { 238 struct cx22702_state *state = fe->demodulator_priv; 239 u8 val; 240 241 dprintk("%s(%d)\n", __func__, enable); 242 val = cx22702_readreg(state, 0x0D); 243 if (enable) 244 val &= 0xfe; 245 else 246 val |= 0x01; 247 return cx22702_writereg(state, 0x0D, val); 248 } 249 250 /* Talk to the demod, set the FEC, GUARD, QAM settings etc */ 251 static int cx22702_set_tps(struct dvb_frontend *fe) 252 { 253 struct dtv_frontend_properties *p = &fe->dtv_property_cache; 254 u8 val; 255 struct cx22702_state *state = fe->demodulator_priv; 256 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); 261 } 262 263 /* set inversion */ 264 cx22702_set_inversion(state, p->inversion); 265 266 /* set bandwidth */ 267 val = cx22702_readreg(state, 0x0C) & 0xcf; 268 switch (p->bandwidth_hz) { 269 case 6000000: 270 val |= 0x20; 271 break; 272 case 7000000: 273 val |= 0x10; 274 break; 275 case 8000000: 276 break; 277 default: 278 dprintk("%s: invalid bandwidth\n", __func__); 279 return -EINVAL; 280 } 281 cx22702_writereg(state, 0x0C, val); 282 283 p->code_rate_LP = FEC_AUTO; /* temp hack as manual not working */ 284 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)) { 292 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) 298 & 0xfc); 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__); 303 return 0; 304 } 305 306 /* manually programmed values */ 307 switch (p->modulation) { /* mask 0x18 */ 308 case QPSK: 309 val = 0x00; 310 break; 311 case QAM_16: 312 val = 0x08; 313 break; 314 case QAM_64: 315 val = 0x10; 316 break; 317 default: 318 dprintk("%s: invalid modulation\n", __func__); 319 return -EINVAL; 320 } 321 switch (p->hierarchy) { /* mask 0x07 */ 322 case HIERARCHY_NONE: 323 break; 324 case HIERARCHY_1: 325 val |= 0x01; 326 break; 327 case HIERARCHY_2: 328 val |= 0x02; 329 break; 330 case HIERARCHY_4: 331 val |= 0x03; 332 break; 333 default: 334 dprintk("%s: invalid hierarchy\n", __func__); 335 return -EINVAL; 336 } 337 cx22702_writereg(state, 0x06, val); 338 339 switch (p->code_rate_HP) { /* mask 0x38 */ 340 case FEC_NONE: 341 case FEC_1_2: 342 val = 0x00; 343 break; 344 case FEC_2_3: 345 val = 0x08; 346 break; 347 case FEC_3_4: 348 val = 0x10; 349 break; 350 case FEC_5_6: 351 val = 0x18; 352 break; 353 case FEC_7_8: 354 val = 0x20; 355 break; 356 default: 357 dprintk("%s: invalid code_rate_HP\n", __func__); 358 return -EINVAL; 359 } 360 switch (p->code_rate_LP) { /* mask 0x07 */ 361 case FEC_NONE: 362 case FEC_1_2: 363 break; 364 case FEC_2_3: 365 val |= 0x01; 366 break; 367 case FEC_3_4: 368 val |= 0x02; 369 break; 370 case FEC_5_6: 371 val |= 0x03; 372 break; 373 case FEC_7_8: 374 val |= 0x04; 375 break; 376 default: 377 dprintk("%s: invalid code_rate_LP\n", __func__); 378 return -EINVAL; 379 } 380 cx22702_writereg(state, 0x07, val); 381 382 switch (p->guard_interval) { /* mask 0x0c */ 383 case GUARD_INTERVAL_1_32: 384 val = 0x00; 385 break; 386 case GUARD_INTERVAL_1_16: 387 val = 0x04; 388 break; 389 case GUARD_INTERVAL_1_8: 390 val = 0x08; 391 break; 392 case GUARD_INTERVAL_1_4: 393 val = 0x0c; 394 break; 395 default: 396 dprintk("%s: invalid guard_interval\n", __func__); 397 return -EINVAL; 398 } 399 switch (p->transmission_mode) { /* mask 0x03 */ 400 case TRANSMISSION_MODE_2K: 401 break; 402 case TRANSMISSION_MODE_8K: 403 val |= 0x1; 404 break; 405 default: 406 dprintk("%s: invalid transmission_mode\n", __func__); 407 return -EINVAL; 408 } 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); 414 415 /* Begin channel acquisition */ 416 cx22702_writereg(state, 0x00, 0x01); 417 418 return 0; 419 } 420 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) 424 { 425 int i; 426 struct cx22702_state *state = fe->demodulator_priv; 427 428 cx22702_writereg(state, 0x00, 0x02); 429 430 msleep(10); 431 432 for (i = 0; i < ARRAY_SIZE(init_tab); i += 2) 433 cx22702_writereg(state, init_tab[i], init_tab[i + 1]); 434 435 cx22702_writereg(state, 0xf8, (state->config->output_mode << 1) 436 & 0x02); 437 438 cx22702_i2c_gate_ctrl(fe, 0); 439 440 return 0; 441 } 442 443 static int cx22702_read_status(struct dvb_frontend *fe, enum fe_status *status) 444 { 445 struct cx22702_state *state = fe->demodulator_priv; 446 u8 reg0A; 447 u8 reg23; 448 449 *status = 0; 450 451 reg0A = cx22702_readreg(state, 0x0A); 452 reg23 = cx22702_readreg(state, 0x23); 453 454 dprintk("%s: status demod=0x%02x agc=0x%02x\n" 455 , __func__, reg0A, reg23); 456 457 if (reg0A & 0x10) { 458 *status |= FE_HAS_LOCK; 459 *status |= FE_HAS_VITERBI; 460 *status |= FE_HAS_SYNC; 461 } 462 463 if (reg0A & 0x20) 464 *status |= FE_HAS_CARRIER; 465 466 if (reg23 < 0xf0) 467 *status |= FE_HAS_SIGNAL; 468 469 return 0; 470 } 471 472 static int cx22702_read_ber(struct dvb_frontend *fe, u32 *ber) 473 { 474 struct cx22702_state *state = fe->demodulator_priv; 475 476 if (cx22702_readreg(state, 0xE4) & 0x02) { 477 /* Realtime statistics */ 478 *ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 7 479 | (cx22702_readreg(state, 0xDF) & 0x7F); 480 } else { 481 /* Averagtine statistics */ 482 *ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 7 483 | cx22702_readreg(state, 0xDF); 484 } 485 486 return 0; 487 } 488 489 static int cx22702_read_signal_strength(struct dvb_frontend *fe, 490 u16 *signal_strength) 491 { 492 struct cx22702_state *state = fe->demodulator_priv; 493 u8 reg23; 494 495 /* 496 * Experience suggests that the strength signal register works as 497 * follows: 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 503 * weaker signals. 504 */ 505 reg23 = cx22702_readreg(state, 0x23); 506 if (reg23 & 0x80) { 507 *signal_strength = 0; 508 } else { 509 reg23 = ~reg23 & 0x7f; 510 /* Scale to 16 bit */ 511 *signal_strength = (reg23 << 9) | (reg23 << 2) | (reg23 >> 5); 512 } 513 514 return 0; 515 } 516 517 static int cx22702_read_snr(struct dvb_frontend *fe, u16 *snr) 518 { 519 struct cx22702_state *state = fe->demodulator_priv; 520 521 u16 rs_ber; 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); 526 } else { 527 /* Averagine statistics */ 528 rs_ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 8 529 | cx22702_readreg(state, 0xDF); 530 } 531 *snr = ~rs_ber; 532 533 return 0; 534 } 535 536 static int cx22702_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) 537 { 538 struct cx22702_state *state = fe->demodulator_priv; 539 540 u8 _ucblocks; 541 542 /* RS Uncorrectable Packet Count then reset */ 543 _ucblocks = cx22702_readreg(state, 0xE3); 544 if (state->prevUCBlocks < _ucblocks) 545 *ucblocks = (_ucblocks - state->prevUCBlocks); 546 else 547 *ucblocks = state->prevUCBlocks - _ucblocks; 548 state->prevUCBlocks = _ucblocks; 549 550 return 0; 551 } 552 553 static int cx22702_get_frontend(struct dvb_frontend *fe, 554 struct dtv_frontend_properties *c) 555 { 556 struct cx22702_state *state = fe->demodulator_priv; 557 558 u8 reg0C = cx22702_readreg(state, 0x0C); 559 560 c->inversion = reg0C & 0x1 ? INVERSION_ON : INVERSION_OFF; 561 return cx22702_get_tps(state, c); 562 } 563 564 static int cx22702_get_tune_settings(struct dvb_frontend *fe, 565 struct dvb_frontend_tune_settings *tune) 566 { 567 tune->min_delay_ms = 1000; 568 return 0; 569 } 570 571 static void cx22702_release(struct dvb_frontend *fe) 572 { 573 struct cx22702_state *state = fe->demodulator_priv; 574 kfree(state); 575 } 576 577 static const struct dvb_frontend_ops cx22702_ops; 578 579 struct dvb_frontend *cx22702_attach(const struct cx22702_config *config, 580 struct i2c_adapter *i2c) 581 { 582 struct cx22702_state *state = NULL; 583 584 /* allocate memory for the internal state */ 585 state = kzalloc(sizeof(struct cx22702_state), GFP_KERNEL); 586 if (state == NULL) 587 goto error; 588 589 /* setup the state */ 590 state->config = config; 591 state->i2c = i2c; 592 593 /* check if the demod is there */ 594 if (cx22702_readreg(state, 0x1f) != 0x3) 595 goto error; 596 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; 602 603 error: 604 kfree(state); 605 return NULL; 606 } 607 EXPORT_SYMBOL_GPL(cx22702_attach); 608 609 static const struct dvb_frontend_ops cx22702_ops = { 610 .delsys = { SYS_DVBT }, 611 .info = { 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 621 }, 622 623 .release = cx22702_release, 624 625 .init = cx22702_init, 626 .i2c_gate_ctrl = cx22702_i2c_gate_ctrl, 627 628 .set_frontend = cx22702_set_tps, 629 .get_frontend = cx22702_get_frontend, 630 .get_tune_settings = cx22702_get_tune_settings, 631 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, 637 }; 638 639 MODULE_DESCRIPTION("Conexant CX22702 DVB-T Demodulator driver"); 640 MODULE_AUTHOR("Steven Toth"); 641 MODULE_LICENSE("GPL"); 642