1/* 2 Conexant 22702 DVB OFDM demodulator driver 3 4 based on: 5 Alps TDMB7 DVB OFDM demodulator driver 6 7 Copyright (C) 2001-2002 Convergence Integrated Media GmbH 8 Holger Waechtler <holger@convergence.de> 9 10 Copyright (C) 2004 Steven Toth <stoth@linuxtv.org> 11 12 This program is free software; you can redistribute it and/or modify 13 it under the terms of the GNU General Public License as published by 14 the Free Software Foundation; either version 2 of the License, or 15 (at your option) any later version. 16 17 This program is distributed in the hope that it will be useful, 18 but WITHOUT ANY WARRANTY; without even the implied warranty of 19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 GNU General Public License for more details. 21 22 You should have received a copy of the GNU General Public License 23 along with this program; if not, write to the Free Software 24 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 25 26*/ 27 28#include <linux/kernel.h> 29#include <linux/init.h> 30#include <linux/module.h> 31#include <linux/string.h> 32#include <linux/slab.h> 33#include <linux/delay.h> 34#include "dvb_frontend.h" 35#include "cx22702.h" 36 37struct cx22702_state { 38 39 struct i2c_adapter *i2c; 40 41 /* configuration settings */ 42 const struct cx22702_config *config; 43 44 struct dvb_frontend frontend; 45 46 /* previous uncorrected block counter */ 47 u8 prevUCBlocks; 48}; 49 50static int debug; 51module_param(debug, int, 0644); 52MODULE_PARM_DESC(debug, "Enable verbose debug messages"); 53 54#define dprintk if (debug) printk 55 56/* Register values to initialise the demod */ 57static u8 init_tab[] = { 58 0x00, 0x00, /* Stop aquisition */ 59 0x0B, 0x06, 60 0x09, 0x01, 61 0x0D, 0x41, 62 0x16, 0x32, 63 0x20, 0x0A, 64 0x21, 0x17, 65 0x24, 0x3e, 66 0x26, 0xff, 67 0x27, 0x10, 68 0x28, 0x00, 69 0x29, 0x00, 70 0x2a, 0x10, 71 0x2b, 0x00, 72 0x2c, 0x10, 73 0x2d, 0x00, 74 0x48, 0xd4, 75 0x49, 0x56, 76 0x6b, 0x1e, 77 0xc8, 0x02, 78 0xf9, 0x00, 79 0xfa, 0x00, 80 0xfb, 0x00, 81 0xfc, 0x00, 82 0xfd, 0x00, 83}; 84 85static int cx22702_writereg(struct cx22702_state *state, u8 reg, u8 data) 86{ 87 int ret; 88 u8 buf[] = { reg, data }; 89 struct i2c_msg msg = { 90 .addr = state->config->demod_address, .flags = 0, 91 .buf = buf, .len = 2 }; 92 93 ret = i2c_transfer(state->i2c, &msg, 1); 94 95 if (ret != 1) 96 printk(KERN_ERR 97 "%s: error (reg == 0x%02x, val == 0x%02x, ret == %i)\n", 98 __func__, reg, data, ret); 99 100 return (ret != 1) ? -1 : 0; 101} 102 103static u8 cx22702_readreg(struct cx22702_state *state, u8 reg) 104{ 105 int ret; 106 u8 b0[] = { reg }; 107 u8 b1[] = { 0 }; 108 109 struct i2c_msg msg[] = { 110 { .addr = state->config->demod_address, .flags = 0, 111 .buf = b0, .len = 1 }, 112 { .addr = state->config->demod_address, .flags = I2C_M_RD, 113 .buf = b1, .len = 1 } }; 114 115 ret = i2c_transfer(state->i2c, msg, 2); 116 117 if (ret != 2) 118 printk(KERN_ERR "%s: readreg error (ret == %i)\n", 119 __func__, ret); 120 121 return b1[0]; 122} 123 124static int cx22702_set_inversion(struct cx22702_state *state, int inversion) 125{ 126 u8 val; 127 128 switch (inversion) { 129 case INVERSION_AUTO: 130 return -EOPNOTSUPP; 131 case INVERSION_ON: 132 val = cx22702_readreg(state, 0x0C); 133 return cx22702_writereg(state, 0x0C, val | 0x01); 134 case INVERSION_OFF: 135 val = cx22702_readreg(state, 0x0C); 136 return cx22702_writereg(state, 0x0C, val & 0xfe); 137 default: 138 return -EINVAL; 139 } 140 141} 142 143/* Retrieve the demod settings */ 144static int cx22702_get_tps(struct cx22702_state *state, 145 struct dvb_ofdm_parameters *p) 146{ 147 u8 val; 148 149 /* Make sure the TPS regs are valid */ 150 if (!(cx22702_readreg(state, 0x0A) & 0x20)) 151 return -EAGAIN; 152 153 val = cx22702_readreg(state, 0x01); 154 switch ((val & 0x18) >> 3) { 155 case 0: 156 p->constellation = QPSK; 157 break; 158 case 1: 159 p->constellation = QAM_16; 160 break; 161 case 2: 162 p->constellation = QAM_64; 163 break; 164 } 165 switch (val & 0x07) { 166 case 0: 167 p->hierarchy_information = HIERARCHY_NONE; 168 break; 169 case 1: 170 p->hierarchy_information = HIERARCHY_1; 171 break; 172 case 2: 173 p->hierarchy_information = HIERARCHY_2; 174 break; 175 case 3: 176 p->hierarchy_information = HIERARCHY_4; 177 break; 178 } 179 180 181 val = cx22702_readreg(state, 0x02); 182 switch ((val & 0x38) >> 3) { 183 case 0: 184 p->code_rate_HP = FEC_1_2; 185 break; 186 case 1: 187 p->code_rate_HP = FEC_2_3; 188 break; 189 case 2: 190 p->code_rate_HP = FEC_3_4; 191 break; 192 case 3: 193 p->code_rate_HP = FEC_5_6; 194 break; 195 case 4: 196 p->code_rate_HP = FEC_7_8; 197 break; 198 } 199 switch (val & 0x07) { 200 case 0: 201 p->code_rate_LP = FEC_1_2; 202 break; 203 case 1: 204 p->code_rate_LP = FEC_2_3; 205 break; 206 case 2: 207 p->code_rate_LP = FEC_3_4; 208 break; 209 case 3: 210 p->code_rate_LP = FEC_5_6; 211 break; 212 case 4: 213 p->code_rate_LP = FEC_7_8; 214 break; 215 } 216 217 val = cx22702_readreg(state, 0x03); 218 switch ((val & 0x0c) >> 2) { 219 case 0: 220 p->guard_interval = GUARD_INTERVAL_1_32; 221 break; 222 case 1: 223 p->guard_interval = GUARD_INTERVAL_1_16; 224 break; 225 case 2: 226 p->guard_interval = GUARD_INTERVAL_1_8; 227 break; 228 case 3: 229 p->guard_interval = GUARD_INTERVAL_1_4; 230 break; 231 } 232 switch (val & 0x03) { 233 case 0: 234 p->transmission_mode = TRANSMISSION_MODE_2K; 235 break; 236 case 1: 237 p->transmission_mode = TRANSMISSION_MODE_8K; 238 break; 239 } 240 241 return 0; 242} 243 244static int cx22702_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) 245{ 246 struct cx22702_state *state = fe->demodulator_priv; 247 dprintk("%s(%d)\n", __func__, enable); 248 if (enable) 249 return cx22702_writereg(state, 0x0D, 250 cx22702_readreg(state, 0x0D) & 0xfe); 251 else 252 return cx22702_writereg(state, 0x0D, 253 cx22702_readreg(state, 0x0D) | 1); 254} 255 256/* Talk to the demod, set the FEC, GUARD, QAM settings etc */ 257static int cx22702_set_tps(struct dvb_frontend *fe, 258 struct dvb_frontend_parameters *p) 259{ 260 u8 val; 261 struct cx22702_state *state = fe->demodulator_priv; 262 263 if (fe->ops.tuner_ops.set_params) { 264 fe->ops.tuner_ops.set_params(fe, p); 265 if (fe->ops.i2c_gate_ctrl) 266 fe->ops.i2c_gate_ctrl(fe, 0); 267 } 268 269 /* set inversion */ 270 cx22702_set_inversion(state, p->inversion); 271 272 /* set bandwidth */ 273 switch (p->u.ofdm.bandwidth) { 274 case BANDWIDTH_6_MHZ: 275 cx22702_writereg(state, 0x0C, 276 (cx22702_readreg(state, 0x0C) & 0xcf) | 0x20); 277 break; 278 case BANDWIDTH_7_MHZ: 279 cx22702_writereg(state, 0x0C, 280 (cx22702_readreg(state, 0x0C) & 0xcf) | 0x10); 281 break; 282 case BANDWIDTH_8_MHZ: 283 cx22702_writereg(state, 0x0C, 284 cx22702_readreg(state, 0x0C) & 0xcf); 285 break; 286 default: 287 dprintk("%s: invalid bandwidth\n", __func__); 288 return -EINVAL; 289 } 290 291 p->u.ofdm.code_rate_LP = FEC_AUTO; /* temp hack as manual not working */ 292 293 /* use auto configuration? */ 294 if ((p->u.ofdm.hierarchy_information == HIERARCHY_AUTO) || 295 (p->u.ofdm.constellation == QAM_AUTO) || 296 (p->u.ofdm.code_rate_HP == FEC_AUTO) || 297 (p->u.ofdm.code_rate_LP == FEC_AUTO) || 298 (p->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO) || 299 (p->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO)) { 300 301 /* TPS Source - use hardware driven values */ 302 cx22702_writereg(state, 0x06, 0x10); 303 cx22702_writereg(state, 0x07, 0x9); 304 cx22702_writereg(state, 0x08, 0xC1); 305 cx22702_writereg(state, 0x0B, cx22702_readreg(state, 0x0B) 306 & 0xfc); 307 cx22702_writereg(state, 0x0C, 308 (cx22702_readreg(state, 0x0C) & 0xBF) | 0x40); 309 cx22702_writereg(state, 0x00, 0x01); /* Begin aquisition */ 310 dprintk("%s: Autodetecting\n", __func__); 311 return 0; 312 } 313 314 /* manually programmed values */ 315 val = 0; 316 switch (p->u.ofdm.constellation) { 317 case QPSK: 318 val = (val & 0xe7); 319 break; 320 case QAM_16: 321 val = (val & 0xe7) | 0x08; 322 break; 323 case QAM_64: 324 val = (val & 0xe7) | 0x10; 325 break; 326 default: 327 dprintk("%s: invalid constellation\n", __func__); 328 return -EINVAL; 329 } 330 switch (p->u.ofdm.hierarchy_information) { 331 case HIERARCHY_NONE: 332 val = (val & 0xf8); 333 break; 334 case HIERARCHY_1: 335 val = (val & 0xf8) | 1; 336 break; 337 case HIERARCHY_2: 338 val = (val & 0xf8) | 2; 339 break; 340 case HIERARCHY_4: 341 val = (val & 0xf8) | 3; 342 break; 343 default: 344 dprintk("%s: invalid hierarchy\n", __func__); 345 return -EINVAL; 346 } 347 cx22702_writereg(state, 0x06, val); 348 349 val = 0; 350 switch (p->u.ofdm.code_rate_HP) { 351 case FEC_NONE: 352 case FEC_1_2: 353 val = (val & 0xc7); 354 break; 355 case FEC_2_3: 356 val = (val & 0xc7) | 0x08; 357 break; 358 case FEC_3_4: 359 val = (val & 0xc7) | 0x10; 360 break; 361 case FEC_5_6: 362 val = (val & 0xc7) | 0x18; 363 break; 364 case FEC_7_8: 365 val = (val & 0xc7) | 0x20; 366 break; 367 default: 368 dprintk("%s: invalid code_rate_HP\n", __func__); 369 return -EINVAL; 370 } 371 switch (p->u.ofdm.code_rate_LP) { 372 case FEC_NONE: 373 case FEC_1_2: 374 val = (val & 0xf8); 375 break; 376 case FEC_2_3: 377 val = (val & 0xf8) | 1; 378 break; 379 case FEC_3_4: 380 val = (val & 0xf8) | 2; 381 break; 382 case FEC_5_6: 383 val = (val & 0xf8) | 3; 384 break; 385 case FEC_7_8: 386 val = (val & 0xf8) | 4; 387 break; 388 default: 389 dprintk("%s: invalid code_rate_LP\n", __func__); 390 return -EINVAL; 391 } 392 cx22702_writereg(state, 0x07, val); 393 394 val = 0; 395 switch (p->u.ofdm.guard_interval) { 396 case GUARD_INTERVAL_1_32: 397 val = (val & 0xf3); 398 break; 399 case GUARD_INTERVAL_1_16: 400 val = (val & 0xf3) | 0x04; 401 break; 402 case GUARD_INTERVAL_1_8: 403 val = (val & 0xf3) | 0x08; 404 break; 405 case GUARD_INTERVAL_1_4: 406 val = (val & 0xf3) | 0x0c; 407 break; 408 default: 409 dprintk("%s: invalid guard_interval\n", __func__); 410 return -EINVAL; 411 } 412 switch (p->u.ofdm.transmission_mode) { 413 case TRANSMISSION_MODE_2K: 414 val = (val & 0xfc); 415 break; 416 case TRANSMISSION_MODE_8K: 417 val = (val & 0xfc) | 1; 418 break; 419 default: 420 dprintk("%s: invalid transmission_mode\n", __func__); 421 return -EINVAL; 422 } 423 cx22702_writereg(state, 0x08, val); 424 cx22702_writereg(state, 0x0B, 425 (cx22702_readreg(state, 0x0B) & 0xfc) | 0x02); 426 cx22702_writereg(state, 0x0C, 427 (cx22702_readreg(state, 0x0C) & 0xBF) | 0x40); 428 429 /* Begin channel aquisition */ 430 cx22702_writereg(state, 0x00, 0x01); 431 432 return 0; 433} 434 435/* Reset the demod hardware and reset all of the configuration registers 436 to a default state. */ 437static int cx22702_init(struct dvb_frontend *fe) 438{ 439 int i; 440 struct cx22702_state *state = fe->demodulator_priv; 441 442 cx22702_writereg(state, 0x00, 0x02); 443 444 msleep(10); 445 446 for (i = 0; i < ARRAY_SIZE(init_tab); i += 2) 447 cx22702_writereg(state, init_tab[i], init_tab[i + 1]); 448 449 cx22702_writereg(state, 0xf8, (state->config->output_mode << 1) 450 & 0x02); 451 452 cx22702_i2c_gate_ctrl(fe, 0); 453 454 return 0; 455} 456 457static int cx22702_read_status(struct dvb_frontend *fe, fe_status_t *status) 458{ 459 struct cx22702_state *state = fe->demodulator_priv; 460 u8 reg0A; 461 u8 reg23; 462 463 *status = 0; 464 465 reg0A = cx22702_readreg(state, 0x0A); 466 reg23 = cx22702_readreg(state, 0x23); 467 468 dprintk("%s: status demod=0x%02x agc=0x%02x\n" 469 , __func__, reg0A, reg23); 470 471 if (reg0A & 0x10) { 472 *status |= FE_HAS_LOCK; 473 *status |= FE_HAS_VITERBI; 474 *status |= FE_HAS_SYNC; 475 } 476 477 if (reg0A & 0x20) 478 *status |= FE_HAS_CARRIER; 479 480 if (reg23 < 0xf0) 481 *status |= FE_HAS_SIGNAL; 482 483 return 0; 484} 485 486static int cx22702_read_ber(struct dvb_frontend *fe, u32 *ber) 487{ 488 struct cx22702_state *state = fe->demodulator_priv; 489 490 if (cx22702_readreg(state, 0xE4) & 0x02) { 491 /* Realtime statistics */ 492 *ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 7 493 | (cx22702_readreg(state, 0xDF) & 0x7F); 494 } else { 495 /* Averagtine statistics */ 496 *ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 7 497 | cx22702_readreg(state, 0xDF); 498 } 499 500 return 0; 501} 502 503static int cx22702_read_signal_strength(struct dvb_frontend *fe, 504 u16 *signal_strength) 505{ 506 struct cx22702_state *state = fe->demodulator_priv; 507 508 u16 rs_ber = 0; 509 rs_ber = cx22702_readreg(state, 0x23); 510 *signal_strength = (rs_ber << 8) | rs_ber; 511 512 return 0; 513} 514 515static int cx22702_read_snr(struct dvb_frontend *fe, u16 *snr) 516{ 517 struct cx22702_state *state = fe->demodulator_priv; 518 519 u16 rs_ber = 0; 520 if (cx22702_readreg(state, 0xE4) & 0x02) { 521 /* Realtime statistics */ 522 rs_ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 7 523 | (cx22702_readreg(state, 0xDF) & 0x7F); 524 } else { 525 /* Averagine statistics */ 526 rs_ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 8 527 | cx22702_readreg(state, 0xDF); 528 } 529 *snr = ~rs_ber; 530 531 return 0; 532} 533 534static int cx22702_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) 535{ 536 struct cx22702_state *state = fe->demodulator_priv; 537 538 u8 _ucblocks; 539 540 /* RS Uncorrectable Packet Count then reset */ 541 _ucblocks = cx22702_readreg(state, 0xE3); 542 if (state->prevUCBlocks < _ucblocks) 543 *ucblocks = (_ucblocks - state->prevUCBlocks); 544 else 545 *ucblocks = state->prevUCBlocks - _ucblocks; 546 state->prevUCBlocks = _ucblocks; 547 548 return 0; 549} 550 551static int cx22702_get_frontend(struct dvb_frontend *fe, 552 struct dvb_frontend_parameters *p) 553{ 554 struct cx22702_state *state = fe->demodulator_priv; 555 556 u8 reg0C = cx22702_readreg(state, 0x0C); 557 558 p->inversion = reg0C & 0x1 ? INVERSION_ON : INVERSION_OFF; 559 return cx22702_get_tps(state, &p->u.ofdm); 560} 561 562static int cx22702_get_tune_settings(struct dvb_frontend *fe, 563 struct dvb_frontend_tune_settings *tune) 564{ 565 tune->min_delay_ms = 1000; 566 return 0; 567} 568 569static void cx22702_release(struct dvb_frontend *fe) 570{ 571 struct cx22702_state *state = fe->demodulator_priv; 572 kfree(state); 573} 574 575static struct dvb_frontend_ops cx22702_ops; 576 577struct dvb_frontend *cx22702_attach(const struct cx22702_config *config, 578 struct i2c_adapter *i2c) 579{ 580 struct cx22702_state *state = NULL; 581 582 /* allocate memory for the internal state */ 583 state = kzalloc(sizeof(struct cx22702_state), GFP_KERNEL); 584 if (state == NULL) 585 goto error; 586 587 /* setup the state */ 588 state->config = config; 589 state->i2c = i2c; 590 state->prevUCBlocks = 0; 591 592 /* check if the demod is there */ 593 if (cx22702_readreg(state, 0x1f) != 0x3) 594 goto error; 595 596 /* create dvb_frontend */ 597 memcpy(&state->frontend.ops, &cx22702_ops, 598 sizeof(struct dvb_frontend_ops)); 599 state->frontend.demodulator_priv = state; 600 return &state->frontend; 601 602error: 603 kfree(state); 604 return NULL; 605} 606EXPORT_SYMBOL(cx22702_attach); 607 608static struct dvb_frontend_ops cx22702_ops = { 609 610 .info = { 611 .name = "Conexant CX22702 DVB-T", 612 .type = FE_OFDM, 613 .frequency_min = 177000000, 614 .frequency_max = 858000000, 615 .frequency_stepsize = 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 639MODULE_DESCRIPTION("Conexant CX22702 DVB-T Demodulator driver"); 640MODULE_AUTHOR("Steven Toth"); 641MODULE_LICENSE("GPL"); 642