1/* 2 Auvitek AU8522 QAM/8VSB demodulator driver 3 4 Copyright (C) 2008 Steven Toth <stoth@linuxtv.org> 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software 18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 20*/ 21 22#include <linux/kernel.h> 23#include <linux/init.h> 24#include <linux/module.h> 25#include <linux/string.h> 26#include <linux/delay.h> 27#include "dvb_frontend.h" 28#include "au8522.h" 29#include "au8522_priv.h" 30 31static int debug; 32 33/* Despite the name "hybrid_tuner", the framework works just as well for 34 hybrid demodulators as well... */ 35static LIST_HEAD(hybrid_tuner_instance_list); 36static DEFINE_MUTEX(au8522_list_mutex); 37 38#define dprintk(arg...)\ 39 do { if (debug)\ 40 printk(arg);\ 41 } while (0) 42 43/* 16 bit registers, 8 bit values */ 44int au8522_writereg(struct au8522_state *state, u16 reg, u8 data) 45{ 46 int ret; 47 u8 buf[] = { (reg >> 8) | 0x80, reg & 0xff, data }; 48 49 struct i2c_msg msg = { .addr = state->config->demod_address, 50 .flags = 0, .buf = buf, .len = 3 }; 51 52 ret = i2c_transfer(state->i2c, &msg, 1); 53 54 if (ret != 1) 55 printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, " 56 "ret == %i)\n", __func__, reg, data, ret); 57 58 return (ret != 1) ? -1 : 0; 59} 60 61u8 au8522_readreg(struct au8522_state *state, u16 reg) 62{ 63 int ret; 64 u8 b0[] = { (reg >> 8) | 0x40, reg & 0xff }; 65 u8 b1[] = { 0 }; 66 67 struct i2c_msg msg[] = { 68 { .addr = state->config->demod_address, .flags = 0, 69 .buf = b0, .len = 2 }, 70 { .addr = state->config->demod_address, .flags = I2C_M_RD, 71 .buf = b1, .len = 1 } }; 72 73 ret = i2c_transfer(state->i2c, msg, 2); 74 75 if (ret != 2) 76 printk(KERN_ERR "%s: readreg error (ret == %i)\n", 77 __func__, ret); 78 return b1[0]; 79} 80 81static int au8522_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) 82{ 83 struct au8522_state *state = fe->demodulator_priv; 84 85 dprintk("%s(%d)\n", __func__, enable); 86 87 if (state->operational_mode == AU8522_ANALOG_MODE) { 88 /* We're being asked to manage the gate even though we're 89 not in digital mode. This can occur if we get switched 90 over to analog mode before the dvb_frontend kernel thread 91 has completely shutdown */ 92 return 0; 93 } 94 95 if (enable) 96 return au8522_writereg(state, 0x106, 1); 97 else 98 return au8522_writereg(state, 0x106, 0); 99} 100 101struct mse2snr_tab { 102 u16 val; 103 u16 data; 104}; 105 106/* VSB SNR lookup table */ 107static struct mse2snr_tab vsb_mse2snr_tab[] = { 108 { 0, 270 }, 109 { 2, 250 }, 110 { 3, 240 }, 111 { 5, 230 }, 112 { 7, 220 }, 113 { 9, 210 }, 114 { 12, 200 }, 115 { 13, 195 }, 116 { 15, 190 }, 117 { 17, 185 }, 118 { 19, 180 }, 119 { 21, 175 }, 120 { 24, 170 }, 121 { 27, 165 }, 122 { 31, 160 }, 123 { 32, 158 }, 124 { 33, 156 }, 125 { 36, 152 }, 126 { 37, 150 }, 127 { 39, 148 }, 128 { 40, 146 }, 129 { 41, 144 }, 130 { 43, 142 }, 131 { 44, 140 }, 132 { 48, 135 }, 133 { 50, 130 }, 134 { 43, 142 }, 135 { 53, 125 }, 136 { 56, 120 }, 137 { 256, 115 }, 138}; 139 140/* QAM64 SNR lookup table */ 141static struct mse2snr_tab qam64_mse2snr_tab[] = { 142 { 15, 0 }, 143 { 16, 290 }, 144 { 17, 288 }, 145 { 18, 286 }, 146 { 19, 284 }, 147 { 20, 282 }, 148 { 21, 281 }, 149 { 22, 279 }, 150 { 23, 277 }, 151 { 24, 275 }, 152 { 25, 273 }, 153 { 26, 271 }, 154 { 27, 269 }, 155 { 28, 268 }, 156 { 29, 266 }, 157 { 30, 264 }, 158 { 31, 262 }, 159 { 32, 260 }, 160 { 33, 259 }, 161 { 34, 258 }, 162 { 35, 256 }, 163 { 36, 255 }, 164 { 37, 254 }, 165 { 38, 252 }, 166 { 39, 251 }, 167 { 40, 250 }, 168 { 41, 249 }, 169 { 42, 248 }, 170 { 43, 246 }, 171 { 44, 245 }, 172 { 45, 244 }, 173 { 46, 242 }, 174 { 47, 241 }, 175 { 48, 240 }, 176 { 50, 239 }, 177 { 51, 238 }, 178 { 53, 237 }, 179 { 54, 236 }, 180 { 56, 235 }, 181 { 57, 234 }, 182 { 59, 233 }, 183 { 60, 232 }, 184 { 62, 231 }, 185 { 63, 230 }, 186 { 65, 229 }, 187 { 67, 228 }, 188 { 68, 227 }, 189 { 70, 226 }, 190 { 71, 225 }, 191 { 73, 224 }, 192 { 74, 223 }, 193 { 76, 222 }, 194 { 78, 221 }, 195 { 80, 220 }, 196 { 82, 219 }, 197 { 85, 218 }, 198 { 88, 217 }, 199 { 90, 216 }, 200 { 92, 215 }, 201 { 93, 214 }, 202 { 94, 212 }, 203 { 95, 211 }, 204 { 97, 210 }, 205 { 99, 209 }, 206 { 101, 208 }, 207 { 102, 207 }, 208 { 104, 206 }, 209 { 107, 205 }, 210 { 111, 204 }, 211 { 114, 203 }, 212 { 118, 202 }, 213 { 122, 201 }, 214 { 125, 200 }, 215 { 128, 199 }, 216 { 130, 198 }, 217 { 132, 197 }, 218 { 256, 190 }, 219}; 220 221/* QAM256 SNR lookup table */ 222static struct mse2snr_tab qam256_mse2snr_tab[] = { 223 { 16, 0 }, 224 { 17, 400 }, 225 { 18, 398 }, 226 { 19, 396 }, 227 { 20, 394 }, 228 { 21, 392 }, 229 { 22, 390 }, 230 { 23, 388 }, 231 { 24, 386 }, 232 { 25, 384 }, 233 { 26, 382 }, 234 { 27, 380 }, 235 { 28, 379 }, 236 { 29, 378 }, 237 { 30, 377 }, 238 { 31, 376 }, 239 { 32, 375 }, 240 { 33, 374 }, 241 { 34, 373 }, 242 { 35, 372 }, 243 { 36, 371 }, 244 { 37, 370 }, 245 { 38, 362 }, 246 { 39, 354 }, 247 { 40, 346 }, 248 { 41, 338 }, 249 { 42, 330 }, 250 { 43, 328 }, 251 { 44, 326 }, 252 { 45, 324 }, 253 { 46, 322 }, 254 { 47, 320 }, 255 { 48, 319 }, 256 { 49, 318 }, 257 { 50, 317 }, 258 { 51, 316 }, 259 { 52, 315 }, 260 { 53, 314 }, 261 { 54, 313 }, 262 { 55, 312 }, 263 { 56, 311 }, 264 { 57, 310 }, 265 { 58, 308 }, 266 { 59, 306 }, 267 { 60, 304 }, 268 { 61, 302 }, 269 { 62, 300 }, 270 { 63, 298 }, 271 { 65, 295 }, 272 { 68, 294 }, 273 { 70, 293 }, 274 { 73, 292 }, 275 { 76, 291 }, 276 { 78, 290 }, 277 { 79, 289 }, 278 { 81, 288 }, 279 { 82, 287 }, 280 { 83, 286 }, 281 { 84, 285 }, 282 { 85, 284 }, 283 { 86, 283 }, 284 { 88, 282 }, 285 { 89, 281 }, 286 { 256, 280 }, 287}; 288 289static int au8522_mse2snr_lookup(struct mse2snr_tab *tab, int sz, int mse, 290 u16 *snr) 291{ 292 int i, ret = -EINVAL; 293 dprintk("%s()\n", __func__); 294 295 for (i = 0; i < sz; i++) { 296 if (mse < tab[i].val) { 297 *snr = tab[i].data; 298 ret = 0; 299 break; 300 } 301 } 302 dprintk("%s() snr=%d\n", __func__, *snr); 303 return ret; 304} 305 306static int au8522_set_if(struct dvb_frontend *fe, enum au8522_if_freq if_freq) 307{ 308 struct au8522_state *state = fe->demodulator_priv; 309 u8 r0b5, r0b6, r0b7; 310 char *ifmhz; 311 312 switch (if_freq) { 313 case AU8522_IF_3_25MHZ: 314 ifmhz = "3.25"; 315 r0b5 = 0x00; 316 r0b6 = 0x3d; 317 r0b7 = 0xa0; 318 break; 319 case AU8522_IF_4MHZ: 320 ifmhz = "4.00"; 321 r0b5 = 0x00; 322 r0b6 = 0x4b; 323 r0b7 = 0xd9; 324 break; 325 case AU8522_IF_6MHZ: 326 ifmhz = "6.00"; 327 r0b5 = 0xfb; 328 r0b6 = 0x8e; 329 r0b7 = 0x39; 330 break; 331 default: 332 dprintk("%s() IF Frequency not supported\n", __func__); 333 return -EINVAL; 334 } 335 dprintk("%s() %s MHz\n", __func__, ifmhz); 336 au8522_writereg(state, 0x80b5, r0b5); 337 au8522_writereg(state, 0x80b6, r0b6); 338 au8522_writereg(state, 0x80b7, r0b7); 339 340 return 0; 341} 342 343/* VSB Modulation table */ 344static struct { 345 u16 reg; 346 u16 data; 347} VSB_mod_tab[] = { 348 { 0x8090, 0x84 }, 349 { 0x4092, 0x11 }, 350 { 0x2005, 0x00 }, 351 { 0x8091, 0x80 }, 352 { 0x80a3, 0x0c }, 353 { 0x80a4, 0xe8 }, 354 { 0x8081, 0xc4 }, 355 { 0x80a5, 0x40 }, 356 { 0x80a7, 0x40 }, 357 { 0x80a6, 0x67 }, 358 { 0x8262, 0x20 }, 359 { 0x821c, 0x30 }, 360 { 0x80d8, 0x1a }, 361 { 0x8227, 0xa0 }, 362 { 0x8121, 0xff }, 363 { 0x80a8, 0xf0 }, 364 { 0x80a9, 0x05 }, 365 { 0x80aa, 0x77 }, 366 { 0x80ab, 0xf0 }, 367 { 0x80ac, 0x05 }, 368 { 0x80ad, 0x77 }, 369 { 0x80ae, 0x41 }, 370 { 0x80af, 0x66 }, 371 { 0x821b, 0xcc }, 372 { 0x821d, 0x80 }, 373 { 0x80a4, 0xe8 }, 374 { 0x8231, 0x13 }, 375}; 376 377/* QAM64 Modulation table */ 378static struct { 379 u16 reg; 380 u16 data; 381} QAM64_mod_tab[] = { 382 { 0x00a3, 0x09 }, 383 { 0x00a4, 0x00 }, 384 { 0x0081, 0xc4 }, 385 { 0x00a5, 0x40 }, 386 { 0x00aa, 0x77 }, 387 { 0x00ad, 0x77 }, 388 { 0x00a6, 0x67 }, 389 { 0x0262, 0x20 }, 390 { 0x021c, 0x30 }, 391 { 0x00b8, 0x3e }, 392 { 0x00b9, 0xf0 }, 393 { 0x00ba, 0x01 }, 394 { 0x00bb, 0x18 }, 395 { 0x00bc, 0x50 }, 396 { 0x00bd, 0x00 }, 397 { 0x00be, 0xea }, 398 { 0x00bf, 0xef }, 399 { 0x00c0, 0xfc }, 400 { 0x00c1, 0xbd }, 401 { 0x00c2, 0x1f }, 402 { 0x00c3, 0xfc }, 403 { 0x00c4, 0xdd }, 404 { 0x00c5, 0xaf }, 405 { 0x00c6, 0x00 }, 406 { 0x00c7, 0x38 }, 407 { 0x00c8, 0x30 }, 408 { 0x00c9, 0x05 }, 409 { 0x00ca, 0x4a }, 410 { 0x00cb, 0xd0 }, 411 { 0x00cc, 0x01 }, 412 { 0x00cd, 0xd9 }, 413 { 0x00ce, 0x6f }, 414 { 0x00cf, 0xf9 }, 415 { 0x00d0, 0x70 }, 416 { 0x00d1, 0xdf }, 417 { 0x00d2, 0xf7 }, 418 { 0x00d3, 0xc2 }, 419 { 0x00d4, 0xdf }, 420 { 0x00d5, 0x02 }, 421 { 0x00d6, 0x9a }, 422 { 0x00d7, 0xd0 }, 423 { 0x0250, 0x0d }, 424 { 0x0251, 0xcd }, 425 { 0x0252, 0xe0 }, 426 { 0x0253, 0x05 }, 427 { 0x0254, 0xa7 }, 428 { 0x0255, 0xff }, 429 { 0x0256, 0xed }, 430 { 0x0257, 0x5b }, 431 { 0x0258, 0xae }, 432 { 0x0259, 0xe6 }, 433 { 0x025a, 0x3d }, 434 { 0x025b, 0x0f }, 435 { 0x025c, 0x0d }, 436 { 0x025d, 0xea }, 437 { 0x025e, 0xf2 }, 438 { 0x025f, 0x51 }, 439 { 0x0260, 0xf5 }, 440 { 0x0261, 0x06 }, 441 { 0x021a, 0x00 }, 442 { 0x0546, 0x40 }, 443 { 0x0210, 0xc7 }, 444 { 0x0211, 0xaa }, 445 { 0x0212, 0xab }, 446 { 0x0213, 0x02 }, 447 { 0x0502, 0x00 }, 448 { 0x0121, 0x04 }, 449 { 0x0122, 0x04 }, 450 { 0x052e, 0x10 }, 451 { 0x00a4, 0xca }, 452 { 0x00a7, 0x40 }, 453 { 0x0526, 0x01 }, 454}; 455 456/* QAM256 Modulation table */ 457static struct { 458 u16 reg; 459 u16 data; 460} QAM256_mod_tab[] = { 461 { 0x80a3, 0x09 }, 462 { 0x80a4, 0x00 }, 463 { 0x8081, 0xc4 }, 464 { 0x80a5, 0x40 }, 465 { 0x80aa, 0x77 }, 466 { 0x80ad, 0x77 }, 467 { 0x80a6, 0x67 }, 468 { 0x8262, 0x20 }, 469 { 0x821c, 0x30 }, 470 { 0x80b8, 0x3e }, 471 { 0x80b9, 0xf0 }, 472 { 0x80ba, 0x01 }, 473 { 0x80bb, 0x18 }, 474 { 0x80bc, 0x50 }, 475 { 0x80bd, 0x00 }, 476 { 0x80be, 0xea }, 477 { 0x80bf, 0xef }, 478 { 0x80c0, 0xfc }, 479 { 0x80c1, 0xbd }, 480 { 0x80c2, 0x1f }, 481 { 0x80c3, 0xfc }, 482 { 0x80c4, 0xdd }, 483 { 0x80c5, 0xaf }, 484 { 0x80c6, 0x00 }, 485 { 0x80c7, 0x38 }, 486 { 0x80c8, 0x30 }, 487 { 0x80c9, 0x05 }, 488 { 0x80ca, 0x4a }, 489 { 0x80cb, 0xd0 }, 490 { 0x80cc, 0x01 }, 491 { 0x80cd, 0xd9 }, 492 { 0x80ce, 0x6f }, 493 { 0x80cf, 0xf9 }, 494 { 0x80d0, 0x70 }, 495 { 0x80d1, 0xdf }, 496 { 0x80d2, 0xf7 }, 497 { 0x80d3, 0xc2 }, 498 { 0x80d4, 0xdf }, 499 { 0x80d5, 0x02 }, 500 { 0x80d6, 0x9a }, 501 { 0x80d7, 0xd0 }, 502 { 0x8250, 0x0d }, 503 { 0x8251, 0xcd }, 504 { 0x8252, 0xe0 }, 505 { 0x8253, 0x05 }, 506 { 0x8254, 0xa7 }, 507 { 0x8255, 0xff }, 508 { 0x8256, 0xed }, 509 { 0x8257, 0x5b }, 510 { 0x8258, 0xae }, 511 { 0x8259, 0xe6 }, 512 { 0x825a, 0x3d }, 513 { 0x825b, 0x0f }, 514 { 0x825c, 0x0d }, 515 { 0x825d, 0xea }, 516 { 0x825e, 0xf2 }, 517 { 0x825f, 0x51 }, 518 { 0x8260, 0xf5 }, 519 { 0x8261, 0x06 }, 520 { 0x821a, 0x00 }, 521 { 0x8546, 0x40 }, 522 { 0x8210, 0x26 }, 523 { 0x8211, 0xf6 }, 524 { 0x8212, 0x84 }, 525 { 0x8213, 0x02 }, 526 { 0x8502, 0x01 }, 527 { 0x8121, 0x04 }, 528 { 0x8122, 0x04 }, 529 { 0x852e, 0x10 }, 530 { 0x80a4, 0xca }, 531 { 0x80a7, 0x40 }, 532 { 0x8526, 0x01 }, 533}; 534 535static int au8522_enable_modulation(struct dvb_frontend *fe, 536 fe_modulation_t m) 537{ 538 struct au8522_state *state = fe->demodulator_priv; 539 int i; 540 541 dprintk("%s(0x%08x)\n", __func__, m); 542 543 switch (m) { 544 case VSB_8: 545 dprintk("%s() VSB_8\n", __func__); 546 for (i = 0; i < ARRAY_SIZE(VSB_mod_tab); i++) 547 au8522_writereg(state, 548 VSB_mod_tab[i].reg, 549 VSB_mod_tab[i].data); 550 au8522_set_if(fe, state->config->vsb_if); 551 break; 552 case QAM_64: 553 dprintk("%s() QAM 64\n", __func__); 554 for (i = 0; i < ARRAY_SIZE(QAM64_mod_tab); i++) 555 au8522_writereg(state, 556 QAM64_mod_tab[i].reg, 557 QAM64_mod_tab[i].data); 558 au8522_set_if(fe, state->config->qam_if); 559 break; 560 case QAM_256: 561 dprintk("%s() QAM 256\n", __func__); 562 for (i = 0; i < ARRAY_SIZE(QAM256_mod_tab); i++) 563 au8522_writereg(state, 564 QAM256_mod_tab[i].reg, 565 QAM256_mod_tab[i].data); 566 au8522_set_if(fe, state->config->qam_if); 567 break; 568 default: 569 dprintk("%s() Invalid modulation\n", __func__); 570 return -EINVAL; 571 } 572 573 state->current_modulation = m; 574 575 return 0; 576} 577 578/* Talk to the demod, set the FEC, GUARD, QAM settings etc */ 579static int au8522_set_frontend(struct dvb_frontend *fe, 580 struct dvb_frontend_parameters *p) 581{ 582 struct au8522_state *state = fe->demodulator_priv; 583 int ret = -EINVAL; 584 585 dprintk("%s(frequency=%d)\n", __func__, p->frequency); 586 587 if ((state->current_frequency == p->frequency) && 588 (state->current_modulation == p->u.vsb.modulation)) 589 return 0; 590 591 au8522_enable_modulation(fe, p->u.vsb.modulation); 592 593 /* Allow the demod to settle */ 594 msleep(100); 595 596 if (fe->ops.tuner_ops.set_params) { 597 if (fe->ops.i2c_gate_ctrl) 598 fe->ops.i2c_gate_ctrl(fe, 1); 599 ret = fe->ops.tuner_ops.set_params(fe, p); 600 if (fe->ops.i2c_gate_ctrl) 601 fe->ops.i2c_gate_ctrl(fe, 0); 602 } 603 604 if (ret < 0) 605 return ret; 606 607 state->current_frequency = p->frequency; 608 609 return 0; 610} 611 612/* Reset the demod hardware and reset all of the configuration registers 613 to a default state. */ 614int au8522_init(struct dvb_frontend *fe) 615{ 616 struct au8522_state *state = fe->demodulator_priv; 617 dprintk("%s()\n", __func__); 618 619 state->operational_mode = AU8522_DIGITAL_MODE; 620 621 /* Clear out any state associated with the digital side of the 622 chip, so that when it gets powered back up it won't think 623 that it is already tuned */ 624 state->current_frequency = 0; 625 626 au8522_writereg(state, 0xa4, 1 << 5); 627 628 au8522_i2c_gate_ctrl(fe, 1); 629 630 return 0; 631} 632 633static int au8522_led_gpio_enable(struct au8522_state *state, int onoff) 634{ 635 struct au8522_led_config *led_config = state->config->led_cfg; 636 u8 val; 637 638 /* bail out if we cant control an LED */ 639 if (!led_config || !led_config->gpio_output || 640 !led_config->gpio_output_enable || !led_config->gpio_output_disable) 641 return 0; 642 643 val = au8522_readreg(state, 0x4000 | 644 (led_config->gpio_output & ~0xc000)); 645 if (onoff) { 646 /* enable GPIO output */ 647 val &= ~((led_config->gpio_output_enable >> 8) & 0xff); 648 val |= (led_config->gpio_output_enable & 0xff); 649 } else { 650 /* disable GPIO output */ 651 val &= ~((led_config->gpio_output_disable >> 8) & 0xff); 652 val |= (led_config->gpio_output_disable & 0xff); 653 } 654 return au8522_writereg(state, 0x8000 | 655 (led_config->gpio_output & ~0xc000), val); 656} 657 658/* led = 0 | off 659 * led = 1 | signal ok 660 * led = 2 | signal strong 661 * led < 0 | only light led if leds are currently off 662 */ 663static int au8522_led_ctrl(struct au8522_state *state, int led) 664{ 665 struct au8522_led_config *led_config = state->config->led_cfg; 666 int i, ret = 0; 667 668 /* bail out if we cant control an LED */ 669 if (!led_config || !led_config->gpio_leds || 670 !led_config->num_led_states || !led_config->led_states) 671 return 0; 672 673 if (led < 0) { 674 /* if LED is already lit, then leave it as-is */ 675 if (state->led_state) 676 return 0; 677 else 678 led *= -1; 679 } 680 681 /* toggle LED if changing state */ 682 if (state->led_state != led) { 683 u8 val; 684 685 dprintk("%s: %d\n", __func__, led); 686 687 au8522_led_gpio_enable(state, 1); 688 689 val = au8522_readreg(state, 0x4000 | 690 (led_config->gpio_leds & ~0xc000)); 691 692 /* start with all leds off */ 693 for (i = 0; i < led_config->num_led_states; i++) 694 val &= ~led_config->led_states[i]; 695 696 /* set selected LED state */ 697 if (led < led_config->num_led_states) 698 val |= led_config->led_states[led]; 699 else if (led_config->num_led_states) 700 val |= 701 led_config->led_states[led_config->num_led_states - 1]; 702 703 ret = au8522_writereg(state, 0x8000 | 704 (led_config->gpio_leds & ~0xc000), val); 705 if (ret < 0) 706 return ret; 707 708 state->led_state = led; 709 710 if (led == 0) 711 au8522_led_gpio_enable(state, 0); 712 } 713 714 return 0; 715} 716 717int au8522_sleep(struct dvb_frontend *fe) 718{ 719 struct au8522_state *state = fe->demodulator_priv; 720 dprintk("%s()\n", __func__); 721 722 /* Only power down if the digital side is currently using the chip */ 723 if (state->operational_mode == AU8522_ANALOG_MODE) { 724 /* We're not in one of the expected power modes, which means 725 that the DVB thread is probably telling us to go to sleep 726 even though the analog frontend has already started using 727 the chip. So ignore the request */ 728 return 0; 729 } 730 731 /* turn off led */ 732 au8522_led_ctrl(state, 0); 733 734 /* Power down the chip */ 735 au8522_writereg(state, 0xa4, 1 << 5); 736 737 state->current_frequency = 0; 738 739 return 0; 740} 741 742static int au8522_read_status(struct dvb_frontend *fe, fe_status_t *status) 743{ 744 struct au8522_state *state = fe->demodulator_priv; 745 u8 reg; 746 u32 tuner_status = 0; 747 748 *status = 0; 749 750 if (state->current_modulation == VSB_8) { 751 dprintk("%s() Checking VSB_8\n", __func__); 752 reg = au8522_readreg(state, 0x4088); 753 if ((reg & 0x03) == 0x03) 754 *status |= FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI; 755 } else { 756 dprintk("%s() Checking QAM\n", __func__); 757 reg = au8522_readreg(state, 0x4541); 758 if (reg & 0x80) 759 *status |= FE_HAS_VITERBI; 760 if (reg & 0x20) 761 *status |= FE_HAS_LOCK | FE_HAS_SYNC; 762 } 763 764 switch (state->config->status_mode) { 765 case AU8522_DEMODLOCKING: 766 dprintk("%s() DEMODLOCKING\n", __func__); 767 if (*status & FE_HAS_VITERBI) 768 *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; 769 break; 770 case AU8522_TUNERLOCKING: 771 /* Get the tuner status */ 772 dprintk("%s() TUNERLOCKING\n", __func__); 773 if (fe->ops.tuner_ops.get_status) { 774 if (fe->ops.i2c_gate_ctrl) 775 fe->ops.i2c_gate_ctrl(fe, 1); 776 777 fe->ops.tuner_ops.get_status(fe, &tuner_status); 778 779 if (fe->ops.i2c_gate_ctrl) 780 fe->ops.i2c_gate_ctrl(fe, 0); 781 } 782 if (tuner_status) 783 *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; 784 break; 785 } 786 state->fe_status = *status; 787 788 if (*status & FE_HAS_LOCK) 789 /* turn on LED, if it isn't on already */ 790 au8522_led_ctrl(state, -1); 791 else 792 /* turn off LED */ 793 au8522_led_ctrl(state, 0); 794 795 dprintk("%s() status 0x%08x\n", __func__, *status); 796 797 return 0; 798} 799 800static int au8522_led_status(struct au8522_state *state, const u16 *snr) 801{ 802 struct au8522_led_config *led_config = state->config->led_cfg; 803 int led; 804 u16 strong; 805 806 /* bail out if we cant control an LED */ 807 if (!led_config) 808 return 0; 809 810 if (0 == (state->fe_status & FE_HAS_LOCK)) 811 return au8522_led_ctrl(state, 0); 812 else if (state->current_modulation == QAM_256) 813 strong = led_config->qam256_strong; 814 else if (state->current_modulation == QAM_64) 815 strong = led_config->qam64_strong; 816 else /* (state->current_modulation == VSB_8) */ 817 strong = led_config->vsb8_strong; 818 819 if (*snr >= strong) 820 led = 2; 821 else 822 led = 1; 823 824 if ((state->led_state) && 825 (((strong < *snr) ? (*snr - strong) : (strong - *snr)) <= 10)) 826 /* snr didn't change enough to bother 827 * changing the color of the led */ 828 return 0; 829 830 return au8522_led_ctrl(state, led); 831} 832 833static int au8522_read_snr(struct dvb_frontend *fe, u16 *snr) 834{ 835 struct au8522_state *state = fe->demodulator_priv; 836 int ret = -EINVAL; 837 838 dprintk("%s()\n", __func__); 839 840 if (state->current_modulation == QAM_256) 841 ret = au8522_mse2snr_lookup(qam256_mse2snr_tab, 842 ARRAY_SIZE(qam256_mse2snr_tab), 843 au8522_readreg(state, 0x4522), 844 snr); 845 else if (state->current_modulation == QAM_64) 846 ret = au8522_mse2snr_lookup(qam64_mse2snr_tab, 847 ARRAY_SIZE(qam64_mse2snr_tab), 848 au8522_readreg(state, 0x4522), 849 snr); 850 else /* VSB_8 */ 851 ret = au8522_mse2snr_lookup(vsb_mse2snr_tab, 852 ARRAY_SIZE(vsb_mse2snr_tab), 853 au8522_readreg(state, 0x4311), 854 snr); 855 856 if (state->config->led_cfg) 857 au8522_led_status(state, snr); 858 859 return ret; 860} 861 862static int au8522_read_signal_strength(struct dvb_frontend *fe, 863 u16 *signal_strength) 864{ 865 return au8522_read_snr(fe, signal_strength); 866} 867 868static int au8522_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) 869{ 870 struct au8522_state *state = fe->demodulator_priv; 871 872 if (state->current_modulation == VSB_8) 873 *ucblocks = au8522_readreg(state, 0x4087); 874 else 875 *ucblocks = au8522_readreg(state, 0x4543); 876 877 return 0; 878} 879 880static int au8522_read_ber(struct dvb_frontend *fe, u32 *ber) 881{ 882 return au8522_read_ucblocks(fe, ber); 883} 884 885static int au8522_get_frontend(struct dvb_frontend *fe, 886 struct dvb_frontend_parameters *p) 887{ 888 struct au8522_state *state = fe->demodulator_priv; 889 890 p->frequency = state->current_frequency; 891 p->u.vsb.modulation = state->current_modulation; 892 893 return 0; 894} 895 896static int au8522_get_tune_settings(struct dvb_frontend *fe, 897 struct dvb_frontend_tune_settings *tune) 898{ 899 tune->min_delay_ms = 1000; 900 return 0; 901} 902 903static struct dvb_frontend_ops au8522_ops; 904 905int au8522_get_state(struct au8522_state **state, struct i2c_adapter *i2c, 906 u8 client_address) 907{ 908 int ret; 909 910 mutex_lock(&au8522_list_mutex); 911 ret = hybrid_tuner_request_state(struct au8522_state, (*state), 912 hybrid_tuner_instance_list, 913 i2c, client_address, "au8522"); 914 mutex_unlock(&au8522_list_mutex); 915 916 return ret; 917} 918 919void au8522_release_state(struct au8522_state *state) 920{ 921 mutex_lock(&au8522_list_mutex); 922 if (state != NULL) 923 hybrid_tuner_release_state(state); 924 mutex_unlock(&au8522_list_mutex); 925} 926 927 928static void au8522_release(struct dvb_frontend *fe) 929{ 930 struct au8522_state *state = fe->demodulator_priv; 931 au8522_release_state(state); 932} 933 934struct dvb_frontend *au8522_attach(const struct au8522_config *config, 935 struct i2c_adapter *i2c) 936{ 937 struct au8522_state *state = NULL; 938 int instance; 939 940 /* allocate memory for the internal state */ 941 instance = au8522_get_state(&state, i2c, config->demod_address); 942 switch (instance) { 943 case 0: 944 dprintk("%s state allocation failed\n", __func__); 945 break; 946 case 1: 947 /* new demod instance */ 948 dprintk("%s using new instance\n", __func__); 949 break; 950 default: 951 /* existing demod instance */ 952 dprintk("%s using existing instance\n", __func__); 953 break; 954 } 955 956 /* setup the state */ 957 state->config = config; 958 state->i2c = i2c; 959 state->operational_mode = AU8522_DIGITAL_MODE; 960 961 /* create dvb_frontend */ 962 memcpy(&state->frontend.ops, &au8522_ops, 963 sizeof(struct dvb_frontend_ops)); 964 state->frontend.demodulator_priv = state; 965 966 if (au8522_init(&state->frontend) != 0) { 967 printk(KERN_ERR "%s: Failed to initialize correctly\n", 968 __func__); 969 goto error; 970 } 971 972 /* Note: Leaving the I2C gate open here. */ 973 au8522_i2c_gate_ctrl(&state->frontend, 1); 974 975 return &state->frontend; 976 977error: 978 au8522_release_state(state); 979 return NULL; 980} 981EXPORT_SYMBOL(au8522_attach); 982 983static struct dvb_frontend_ops au8522_ops = { 984 985 .info = { 986 .name = "Auvitek AU8522 QAM/8VSB Frontend", 987 .type = FE_ATSC, 988 .frequency_min = 54000000, 989 .frequency_max = 858000000, 990 .frequency_stepsize = 62500, 991 .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB 992 }, 993 994 .init = au8522_init, 995 .sleep = au8522_sleep, 996 .i2c_gate_ctrl = au8522_i2c_gate_ctrl, 997 .set_frontend = au8522_set_frontend, 998 .get_frontend = au8522_get_frontend, 999 .get_tune_settings = au8522_get_tune_settings, 1000 .read_status = au8522_read_status, 1001 .read_ber = au8522_read_ber, 1002 .read_signal_strength = au8522_read_signal_strength, 1003 .read_snr = au8522_read_snr, 1004 .read_ucblocks = au8522_read_ucblocks, 1005 .release = au8522_release, 1006}; 1007 1008module_param(debug, int, 0644); 1009MODULE_PARM_DESC(debug, "Enable verbose debug messages"); 1010 1011MODULE_DESCRIPTION("Auvitek AU8522 QAM-B/ATSC Demodulator driver"); 1012MODULE_AUTHOR("Steven Toth"); 1013MODULE_LICENSE("GPL"); 1014