Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

V4L/DVB (7568): Support for DVB-S demod PN1010 (clone of S5H1420) added

This device is a clone of the PN1010 used by SkyStar2 rev2.7 .

This patch adds support for the flexcop-device and makes the driver look a little bit nicer.

It needs to be checked whether the driver is still ok for the budget-cards.

Signed-off-by: Patrick Boettcher <pb@linuxtv.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

authored by

Patrick Boettcher and committed by
Mauro Carvalho Chehab
dbad108b 44dc733c

+470 -214
+331 -188
drivers/media/dvb/frontends/s5h1420.c
··· 1 1 /* 2 - Driver for Samsung S5H1420 QPSK Demodulator 3 - 4 - Copyright (C) 2005 Andrew de Quincey <adq_dvb@lidskialf.net> 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 - 15 - GNU General Public License for more details. 16 - 17 - You should have received a copy of the GNU General Public License 18 - along with this program; if not, write to the Free Software 19 - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 - 21 - */ 2 + * Driver for 3 + * Samsung S5H1420 and 4 + * PnpNetwork PN1010 QPSK Demodulator 5 + * 6 + * Copyright (C) 2005 Andrew de Quincey <adq_dvb@lidskialf.net> 7 + * Copyright (C) 2005-8 Patrick Boettcher <pb@linuxtv.org> 8 + * 9 + * This program is free software; you can redistribute it and/or modify 10 + * it under the terms of the GNU General Public License as published by 11 + * the Free Software Foundation; either version 2 of the License, or 12 + * (at your option) any later version. 13 + * 14 + * This program is distributed in the hope that it will be useful, 15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 + * 18 + * GNU General Public License for more details. 19 + * 20 + * You should have received a copy of the GNU General Public License 21 + * along with this program; if not, write to the Free Software 22 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 23 + */ 22 24 23 25 #include <linux/kernel.h> 24 26 #include <linux/module.h> ··· 31 29 #include <linux/jiffies.h> 32 30 #include <asm/div64.h> 33 31 32 + #include <linux/i2c.h> 33 + 34 + 34 35 #include "dvb_frontend.h" 35 36 #include "s5h1420.h" 36 - 37 - 37 + #include "s5h1420_priv.h" 38 38 39 39 #define TONE_FREQ 22000 40 40 41 41 struct s5h1420_state { 42 42 struct i2c_adapter* i2c; 43 43 const struct s5h1420_config* config; 44 + 44 45 struct dvb_frontend frontend; 46 + struct i2c_adapter tuner_i2c_adapter; 47 + 48 + u8 CON_1_val; 45 49 46 50 u8 postlocked:1; 47 51 u32 fclk; 48 52 u32 tunedfreq; 49 53 fe_code_rate_t fec_inner; 50 54 u32 symbol_rate; 55 + 56 + /* FIXME: ugly workaround for flexcop's incapable i2c-controller 57 + * it does not support repeated-start, workaround: write addr-1 58 + * and then read 59 + */ 60 + u8 shadow[255]; 51 61 }; 52 62 53 63 static u32 s5h1420_getsymbolrate(struct s5h1420_state* state); ··· 68 54 69 55 70 56 static int debug; 71 - #define dprintk if (debug) printk 57 + module_param(debug, int, 0644); 58 + MODULE_PARM_DESC(debug, "enable debugging"); 59 + 60 + #define dprintk(x...) do { \ 61 + if (debug) \ 62 + printk(KERN_DEBUG "S5H1420: " x); \ 63 + } while (0) 64 + 65 + static u8 s5h1420_readreg(struct s5h1420_state *state, u8 reg) 66 + { 67 + int ret; 68 + u8 b[2]; 69 + struct i2c_msg msg[] = { 70 + { .addr = state->config->demod_address, .flags = 0, .buf = b, .len = 2 }, 71 + { .addr = state->config->demod_address, .flags = 0, .buf = &reg, .len = 1 }, 72 + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b, .len = 1 }, 73 + }; 74 + 75 + b[0] = (reg - 1) & 0xff; 76 + b[1] = state->shadow[(reg - 1) & 0xff]; 77 + 78 + if (state->config->repeated_start_workaround) { 79 + ret = i2c_transfer(state->i2c, msg, 3); 80 + if (ret != 3) 81 + return ret; 82 + } else { 83 + ret = i2c_transfer(state->i2c, &msg[1], 2); 84 + if (ret != 2) 85 + return ret; 86 + } 87 + 88 + /* dprintk("rd(%02x): %02x %02x\n", state->config->demod_address, reg, b[0]); */ 89 + 90 + return b[0]; 91 + } 72 92 73 93 static int s5h1420_writereg (struct s5h1420_state* state, u8 reg, u8 data) 74 94 { 75 - u8 buf [] = { reg, data }; 95 + u8 buf[] = { reg, data }; 76 96 struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; 77 97 int err; 78 98 79 - if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { 80 - dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __func__, err, reg, data); 99 + /* dprintk("wr(%02x): %02x %02x\n", state->config->demod_address, reg, data); */ 100 + err = i2c_transfer(state->i2c, &msg, 1); 101 + if (err != 1) { 102 + dprintk("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __func__, err, reg, data); 81 103 return -EREMOTEIO; 82 104 } 105 + state->shadow[reg] = data; 83 106 84 107 return 0; 85 - } 86 - 87 - static u8 s5h1420_readreg (struct s5h1420_state* state, u8 reg) 88 - { 89 - int ret; 90 - u8 b0 [] = { reg }; 91 - u8 b1 [] = { 0 }; 92 - struct i2c_msg msg1 = { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }; 93 - struct i2c_msg msg2 = { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 }; 94 - 95 - if ((ret = i2c_transfer (state->i2c, &msg1, 1)) != 1) 96 - return ret; 97 - 98 - if ((ret = i2c_transfer (state->i2c, &msg2, 1)) != 1) 99 - return ret; 100 - 101 - return b1[0]; 102 108 } 103 109 104 110 static int s5h1420_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage) 105 111 { 106 112 struct s5h1420_state* state = fe->demodulator_priv; 113 + 114 + dprintk("enter %s\n", __func__); 107 115 108 116 switch(voltage) { 109 117 case SEC_VOLTAGE_13: ··· 142 106 break; 143 107 } 144 108 109 + dprintk("leave %s\n", __func__); 145 110 return 0; 146 111 } 147 112 ··· 150 113 { 151 114 struct s5h1420_state* state = fe->demodulator_priv; 152 115 116 + dprintk("enter %s\n", __func__); 153 117 switch(tone) { 154 118 case SEC_TONE_ON: 155 119 s5h1420_writereg(state, 0x3b, ··· 162 124 (s5h1420_readreg(state, 0x3b) & 0x74) | 0x01); 163 125 break; 164 126 } 127 + dprintk("leave %s\n", __func__); 165 128 166 129 return 0; 167 130 } ··· 176 137 unsigned long timeout; 177 138 int result = 0; 178 139 140 + dprintk("enter %s\n", __func__); 179 141 if (cmd->msg_len > 8) 180 142 return -EINVAL; 181 143 ··· 208 168 /* restore original settings */ 209 169 s5h1420_writereg(state, 0x3b, val); 210 170 msleep(15); 171 + dprintk("leave %s\n", __func__); 211 172 return result; 212 173 } 213 174 ··· 330 289 struct s5h1420_state* state = fe->demodulator_priv; 331 290 u8 val; 332 291 292 + dprintk("enter %s\n", __func__); 293 + 333 294 if (status == NULL) 334 295 return -EINVAL; 335 296 ··· 340 297 341 298 /* fix for FEC 5/6 inversion issue - if it doesn't quite lock, invert 342 299 the inversion, wait a bit and check again */ 343 - if (*status == (FE_HAS_SIGNAL|FE_HAS_CARRIER|FE_HAS_VITERBI)) { 344 - val = s5h1420_readreg(state, 0x32); 300 + if (*status == (FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI)) { 301 + val = s5h1420_readreg(state, Vit10); 345 302 if ((val & 0x07) == 0x03) { 346 303 if (val & 0x08) 347 - s5h1420_writereg(state, 0x31, 0x13); 304 + s5h1420_writereg(state, Vit09, 0x13); 348 305 else 349 - s5h1420_writereg(state, 0x31, 0x1b); 306 + s5h1420_writereg(state, Vit09, 0x1b); 350 307 351 308 /* wait a bit then update lock status */ 352 309 mdelay(200); ··· 355 312 } 356 313 357 314 /* perform post lock setup */ 358 - if ((*status & FE_HAS_LOCK) && (!state->postlocked)) { 315 + if ((*status & FE_HAS_LOCK) && !state->postlocked) { 359 316 360 317 /* calculate the data rate */ 361 318 u32 tmp = s5h1420_getsymbolrate(state); 362 - switch(s5h1420_readreg(state, 0x32) & 0x07) { 363 - case 0: 364 - tmp = (tmp * 2 * 1) / 2; 365 - break; 366 - 367 - case 1: 368 - tmp = (tmp * 2 * 2) / 3; 369 - break; 370 - 371 - case 2: 372 - tmp = (tmp * 2 * 3) / 4; 373 - break; 374 - 375 - case 3: 376 - tmp = (tmp * 2 * 5) / 6; 377 - break; 378 - 379 - case 4: 380 - tmp = (tmp * 2 * 6) / 7; 381 - break; 382 - 383 - case 5: 384 - tmp = (tmp * 2 * 7) / 8; 385 - break; 319 + switch (s5h1420_readreg(state, Vit10) & 0x07) { 320 + case 0: tmp = (tmp * 2 * 1) / 2; break; 321 + case 1: tmp = (tmp * 2 * 2) / 3; break; 322 + case 2: tmp = (tmp * 2 * 3) / 4; break; 323 + case 3: tmp = (tmp * 2 * 5) / 6; break; 324 + case 4: tmp = (tmp * 2 * 6) / 7; break; 325 + case 5: tmp = (tmp * 2 * 7) / 8; break; 386 326 } 327 + 387 328 if (tmp == 0) { 388 - printk("s5h1420: avoided division by 0\n"); 329 + printk(KERN_ERR "s5h1420: avoided division by 0\n"); 389 330 tmp = 1; 390 331 } 391 332 tmp = state->fclk / tmp; 392 333 334 + 393 335 /* set the MPEG_CLK_INTL for the calculated data rate */ 394 - if (tmp < 4) 336 + if (tmp < 2) 395 337 val = 0x00; 396 - else if (tmp < 8) 338 + else if (tmp < 5) 397 339 val = 0x01; 398 - else if (tmp < 12) 340 + else if (tmp < 9) 399 341 val = 0x02; 400 - else if (tmp < 16) 342 + else if (tmp < 13) 401 343 val = 0x03; 402 - else if (tmp < 24) 344 + else if (tmp < 17) 403 345 val = 0x04; 404 - else if (tmp < 32) 346 + else if (tmp < 25) 405 347 val = 0x05; 406 - else 348 + else if (tmp < 33) 407 349 val = 0x06; 408 - s5h1420_writereg(state, 0x22, val); 350 + else 351 + val = 0x07; 352 + dprintk("for MPEG_CLK_INTL %d %x\n", tmp, val); 409 353 410 - /* DC freeze */ 411 - s5h1420_writereg(state, 0x1f, s5h1420_readreg(state, 0x1f) | 0x01); 354 + s5h1420_writereg(state, FEC01, 0x18); 355 + s5h1420_writereg(state, FEC01, 0x10); 356 + s5h1420_writereg(state, FEC01, val); 412 357 413 - /* kicker disable + remove DC offset */ 414 - s5h1420_writereg(state, 0x05, s5h1420_readreg(state, 0x05) & 0x6f); 358 + /* Enable "MPEG_Out" */ 359 + val = s5h1420_readreg(state, Mpeg02); 360 + s5h1420_writereg(state, Mpeg02, val | (1 << 6)); 361 + 362 + /* kicker disable */ 363 + val = s5h1420_readreg(state, QPSK01) & 0x7f; 364 + s5h1420_writereg(state, QPSK01, val); 365 + 366 + /* DC freeze TODO it was never activated by default or it can stay activated */ 367 + 368 + if (s5h1420_getsymbolrate(state) >= 20000000) { 369 + s5h1420_writereg(state, Loop04, 0x8a); 370 + s5h1420_writereg(state, Loop05, 0x6a); 371 + } else { 372 + s5h1420_writereg(state, Loop04, 0x58); 373 + s5h1420_writereg(state, Loop05, 0x27); 374 + } 415 375 416 376 /* post-lock processing has been done! */ 417 377 state->postlocked = 1; 418 378 } 379 + 380 + dprintk("leave %s\n", __func__); 419 381 420 382 return 0; 421 383 } ··· 462 414 463 415 static void s5h1420_reset(struct s5h1420_state* state) 464 416 { 417 + dprintk("%s\n", __func__); 465 418 s5h1420_writereg (state, 0x01, 0x08); 466 419 s5h1420_writereg (state, 0x01, 0x00); 467 420 udelay(10); ··· 471 422 static void s5h1420_setsymbolrate(struct s5h1420_state* state, 472 423 struct dvb_frontend_parameters *p) 473 424 { 425 + u8 v; 474 426 u64 val; 475 427 428 + dprintk("enter %s\n", __func__); 429 + 476 430 val = ((u64) p->u.qpsk.symbol_rate / 1000ULL) * (1ULL<<24); 477 - if (p->u.qpsk.symbol_rate <= 21000000) { 431 + if (p->u.qpsk.symbol_rate < 29000000) 478 432 val *= 2; 479 - } 480 433 do_div(val, (state->fclk / 1000)); 481 434 482 - s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) & 0x7f); 483 - s5h1420_writereg(state, 0x11, val >> 16); 484 - s5h1420_writereg(state, 0x12, val >> 8); 485 - s5h1420_writereg(state, 0x13, val & 0xff); 486 - s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) | 0x80); 435 + dprintk("symbol rate register: %06llx\n", val); 436 + 437 + v = s5h1420_readreg(state, Loop01); 438 + s5h1420_writereg(state, Loop01, v & 0x7f); 439 + s5h1420_writereg(state, Tnco01, val >> 16); 440 + s5h1420_writereg(state, Tnco02, val >> 8); 441 + s5h1420_writereg(state, Tnco03, val & 0xff); 442 + s5h1420_writereg(state, Loop01, v | 0x80); 443 + dprintk("leave %s\n", __func__); 487 444 } 488 445 489 446 static u32 s5h1420_getsymbolrate(struct s5h1420_state* state) 490 447 { 491 - u64 val = 0; 492 - int sampling = 2; 493 - 494 - if (s5h1420_readreg(state, 0x05) & 0x2) 495 - sampling = 1; 496 - 497 - s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) | 0x08); 498 - val = s5h1420_readreg(state, 0x11) << 16; 499 - val |= s5h1420_readreg(state, 0x12) << 8; 500 - val |= s5h1420_readreg(state, 0x13); 501 - s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) & 0xf7); 502 - 503 - val *= (state->fclk / 1000ULL); 504 - do_div(val, ((1<<24) * sampling)); 505 - 506 - return (u32) (val * 1000ULL); 448 + return state->symbol_rate; 507 449 } 508 450 509 451 static void s5h1420_setfreqoffset(struct s5h1420_state* state, int freqoffset) 510 452 { 511 453 int val; 454 + u8 v; 455 + 456 + dprintk("enter %s\n", __func__); 512 457 513 458 /* remember freqoffset is in kHz, but the chip wants the offset in Hz, so 514 459 * divide fclk by 1000000 to get the correct value. */ 515 460 val = -(int) ((freqoffset * (1<<24)) / (state->fclk / 1000000)); 516 461 517 - s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) & 0xbf); 518 - s5h1420_writereg(state, 0x0e, val >> 16); 519 - s5h1420_writereg(state, 0x0f, val >> 8); 520 - s5h1420_writereg(state, 0x10, val & 0xff); 521 - s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) | 0x40); 462 + dprintk("phase rotator/freqoffset: %d %06x\n", freqoffset, val); 463 + 464 + v = s5h1420_readreg(state, Loop01); 465 + s5h1420_writereg(state, Loop01, v & 0xbf); 466 + s5h1420_writereg(state, Pnco01, val >> 16); 467 + s5h1420_writereg(state, Pnco02, val >> 8); 468 + s5h1420_writereg(state, Pnco03, val & 0xff); 469 + s5h1420_writereg(state, Loop01, v | 0x40); 470 + dprintk("leave %s\n", __func__); 522 471 } 523 472 524 473 static int s5h1420_getfreqoffset(struct s5h1420_state* state) ··· 543 496 struct dvb_frontend_parameters *p) 544 497 { 545 498 u8 inversion = 0; 499 + u8 vit08, vit09; 546 500 547 - if (p->inversion == INVERSION_OFF) { 501 + dprintk("enter %s\n", __func__); 502 + 503 + if (p->inversion == INVERSION_OFF) 548 504 inversion = state->config->invert ? 0x08 : 0; 549 - } else if (p->inversion == INVERSION_ON) { 505 + else if (p->inversion == INVERSION_ON) 550 506 inversion = state->config->invert ? 0 : 0x08; 551 - } 552 507 553 508 if ((p->u.qpsk.fec_inner == FEC_AUTO) || (p->inversion == INVERSION_AUTO)) { 554 - s5h1420_writereg(state, 0x30, 0x3f); 555 - s5h1420_writereg(state, 0x31, 0x00 | inversion); 509 + vit08 = 0x3f; 510 + vit09 = 0; 556 511 } else { 557 512 switch(p->u.qpsk.fec_inner) { 558 513 case FEC_1_2: 559 - s5h1420_writereg(state, 0x30, 0x01); 560 - s5h1420_writereg(state, 0x31, 0x10 | inversion); 514 + vit08 = 0x01; vit09 = 0x10; 561 515 break; 562 516 563 517 case FEC_2_3: 564 - s5h1420_writereg(state, 0x30, 0x02); 565 - s5h1420_writereg(state, 0x31, 0x11 | inversion); 518 + vit08 = 0x02; vit09 = 0x11; 566 519 break; 567 520 568 521 case FEC_3_4: 569 - s5h1420_writereg(state, 0x30, 0x04); 570 - s5h1420_writereg(state, 0x31, 0x12 | inversion); 522 + vit08 = 0x04; vit09 = 0x12; 571 523 break; 572 524 573 525 case FEC_5_6: 574 - s5h1420_writereg(state, 0x30, 0x08); 575 - s5h1420_writereg(state, 0x31, 0x13 | inversion); 526 + vit08 = 0x08; vit09 = 0x13; 576 527 break; 577 528 578 529 case FEC_6_7: 579 - s5h1420_writereg(state, 0x30, 0x10); 580 - s5h1420_writereg(state, 0x31, 0x14 | inversion); 530 + vit08 = 0x10; vit09 = 0x14; 581 531 break; 582 532 583 533 case FEC_7_8: 584 - s5h1420_writereg(state, 0x30, 0x20); 585 - s5h1420_writereg(state, 0x31, 0x15 | inversion); 534 + vit08 = 0x20; vit09 = 0x15; 586 535 break; 587 536 588 537 default: 589 538 return; 590 539 } 591 540 } 541 + vit09 |= inversion; 542 + dprintk("fec: %02x %02x\n", vit08, vit09); 543 + s5h1420_writereg(state, Vit08, vit08); 544 + s5h1420_writereg(state, Vit09, vit09); 545 + dprintk("leave %s\n", __func__); 592 546 } 593 547 594 548 static fe_code_rate_t s5h1420_getfec(struct s5h1420_state* state) ··· 631 583 struct s5h1420_state* state = fe->demodulator_priv; 632 584 int frequency_delta; 633 585 struct dvb_frontend_tune_settings fesettings; 586 + uint8_t clock_settting; 587 + 588 + dprintk("enter %s\n", __func__); 634 589 635 590 /* check if we should do a fast-tune */ 636 591 memcpy(&fesettings.parameters, p, sizeof(struct dvb_frontend_parameters)); 637 592 s5h1420_get_tune_settings(fe, &fesettings); 638 593 frequency_delta = p->frequency - state->tunedfreq; 639 594 if ((frequency_delta > -fesettings.max_drift) && 640 - (frequency_delta < fesettings.max_drift) && 641 - (frequency_delta != 0) && 642 - (state->fec_inner == p->u.qpsk.fec_inner) && 643 - (state->symbol_rate == p->u.qpsk.symbol_rate)) { 595 + (frequency_delta < fesettings.max_drift) && 596 + (frequency_delta != 0) && 597 + (state->fec_inner == p->u.qpsk.fec_inner) && 598 + (state->symbol_rate == p->u.qpsk.symbol_rate)) { 644 599 645 600 if (fe->ops.tuner_ops.set_params) { 646 601 fe->ops.tuner_ops.set_params(fe, p); ··· 657 606 } else { 658 607 s5h1420_setfreqoffset(state, 0); 659 608 } 609 + dprintk("simple tune\n"); 660 610 return 0; 661 611 } 612 + dprintk("tuning demod\n"); 662 613 663 614 /* first of all, software reset */ 664 615 s5h1420_reset(state); 665 616 666 617 /* set s5h1420 fclk PLL according to desired symbol rate */ 667 - if (p->u.qpsk.symbol_rate > 28000000) { 668 - state->fclk = 88000000; 669 - s5h1420_writereg(state, 0x03, 0x50); 670 - s5h1420_writereg(state, 0x04, 0x40); 671 - s5h1420_writereg(state, 0x05, 0xae); 672 - } else if (p->u.qpsk.symbol_rate > 21000000) { 618 + if (p->u.qpsk.symbol_rate > 33000000) 619 + state->fclk = 80000000; 620 + else if (p->u.qpsk.symbol_rate > 28500000) 673 621 state->fclk = 59000000; 674 - s5h1420_writereg(state, 0x03, 0x33); 675 - s5h1420_writereg(state, 0x04, 0x40); 676 - s5h1420_writereg(state, 0x05, 0xae); 677 - } else { 622 + else if (p->u.qpsk.symbol_rate > 25000000) 623 + state->fclk = 86000000; 624 + else if (p->u.qpsk.symbol_rate > 1900000) 678 625 state->fclk = 88000000; 679 - s5h1420_writereg(state, 0x03, 0x50); 680 - s5h1420_writereg(state, 0x04, 0x40); 681 - s5h1420_writereg(state, 0x05, 0xac); 626 + else 627 + state->fclk = 44000000; 628 + 629 + /* Clock */ 630 + switch (state->fclk) { 631 + default: 632 + case 88000000: 633 + clock_settting = 80; 634 + break; 635 + case 86000000: 636 + clock_settting = 78; 637 + break; 638 + case 80000000: 639 + clock_settting = 72; 640 + break; 641 + case 59000000: 642 + clock_settting = 51; 643 + break; 644 + case 44000000: 645 + clock_settting = 36; 646 + break; 682 647 } 648 + dprintk("pll01: %d, ToneFreq: %d\n", state->fclk/1000000 - 8, (state->fclk + (TONE_FREQ * 32) - 1) / (TONE_FREQ * 32)); 649 + s5h1420_writereg(state, PLL01, state->fclk/1000000 - 8); 650 + s5h1420_writereg(state, PLL02, 0x40); 651 + s5h1420_writereg(state, DiS01, (state->fclk + (TONE_FREQ * 32) - 1) / (TONE_FREQ * 32)); 652 + 653 + /* TODO DC offset removal, config parameter ? */ 654 + if (p->u.qpsk.symbol_rate > 29000000) 655 + s5h1420_writereg(state, QPSK01, 0xae | 0x10); 656 + else 657 + s5h1420_writereg(state, QPSK01, 0xac | 0x10); 683 658 684 659 /* set misc registers */ 685 - s5h1420_writereg(state, 0x02, 0x00); 686 - s5h1420_writereg(state, 0x06, 0x00); 687 - s5h1420_writereg(state, 0x07, 0xb0); 688 - s5h1420_writereg(state, 0x0a, 0xe7); 689 - s5h1420_writereg(state, 0x0b, 0x78); 690 - s5h1420_writereg(state, 0x0c, 0x48); 691 - s5h1420_writereg(state, 0x0d, 0x6b); 692 - s5h1420_writereg(state, 0x2e, 0x8e); 693 - s5h1420_writereg(state, 0x35, 0x33); 694 - s5h1420_writereg(state, 0x38, 0x01); 695 - s5h1420_writereg(state, 0x39, 0x7d); 696 - s5h1420_writereg(state, 0x3a, (state->fclk + (TONE_FREQ * 32) - 1) / (TONE_FREQ * 32)); 697 - s5h1420_writereg(state, 0x3c, 0x00); 698 - s5h1420_writereg(state, 0x45, 0x61); 699 - s5h1420_writereg(state, 0x46, 0x1d); 660 + s5h1420_writereg(state, CON_1, 0x00); 661 + s5h1420_writereg(state, QPSK02, 0x00); 662 + s5h1420_writereg(state, Pre01, 0xb0); 700 663 701 - /* start QPSK */ 702 - s5h1420_writereg(state, 0x05, s5h1420_readreg(state, 0x05) | 1); 664 + s5h1420_writereg(state, Loop01, 0xF0); 665 + s5h1420_writereg(state, Loop02, 0x2a); /* e7 for s5h1420 */ 666 + s5h1420_writereg(state, Loop03, 0x79); /* 78 for s5h1420 */ 667 + if (p->u.qpsk.symbol_rate > 20000000) 668 + s5h1420_writereg(state, Loop04, 0x79); 669 + else 670 + s5h1420_writereg(state, Loop04, 0x58); 671 + s5h1420_writereg(state, Loop05, 0x6b); 672 + 673 + if (p->u.qpsk.symbol_rate >= 8000000) 674 + s5h1420_writereg(state, Post01, (0 << 6) | 0x10); 675 + else if (p->u.qpsk.symbol_rate >= 4000000) 676 + s5h1420_writereg(state, Post01, (1 << 6) | 0x10); 677 + else 678 + s5h1420_writereg(state, Post01, (3 << 6) | 0x10); 679 + 680 + s5h1420_writereg(state, Monitor12, 0x00); /* unfreeze DC compensation */ 681 + 682 + s5h1420_writereg(state, Sync01, 0x33); 683 + s5h1420_writereg(state, Mpeg01, state->config->cdclk_polarity); 684 + s5h1420_writereg(state, Mpeg02, 0x3d); /* Parallel output more, disabled -> enabled later */ 685 + s5h1420_writereg(state, Err01, 0x03); /* 0x1d for s5h1420 */ 686 + 687 + s5h1420_writereg(state, Vit06, 0x6e); /* 0x8e for s5h1420 */ 688 + s5h1420_writereg(state, DiS03, 0x00); 689 + s5h1420_writereg(state, Rf01, 0x61); /* Tuner i2c address - for the gate controller */ 703 690 704 691 /* set tuner PLL */ 705 692 if (fe->ops.tuner_ops.set_params) { 706 693 fe->ops.tuner_ops.set_params(fe, p); 707 - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); 694 + if (fe->ops.i2c_gate_ctrl) 695 + fe->ops.i2c_gate_ctrl(fe, 0); 708 696 s5h1420_setfreqoffset(state, 0); 709 697 } 710 698 ··· 751 661 s5h1420_setsymbolrate(state, p); 752 662 s5h1420_setfec_inversion(state, p); 753 663 664 + /* start QPSK */ 665 + s5h1420_writereg(state, QPSK01, s5h1420_readreg(state, QPSK01) | 1); 666 + 754 667 state->fec_inner = p->u.qpsk.fec_inner; 755 668 state->symbol_rate = p->u.qpsk.symbol_rate; 756 669 state->postlocked = 0; 757 670 state->tunedfreq = p->frequency; 671 + 672 + dprintk("leave %s\n", __func__); 758 673 return 0; 759 674 } 760 675 ··· 812 717 { 813 718 struct s5h1420_state* state = fe->demodulator_priv; 814 719 815 - if (enable) { 816 - return s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1); 817 - } else { 818 - return s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) & 0xfe); 819 - } 720 + if (enable) 721 + return s5h1420_writereg(state, 0x02, state->CON_1_val | 1); 722 + else 723 + return s5h1420_writereg(state, 0x02, state->CON_1_val & 0xfe); 820 724 } 821 725 822 726 static int s5h1420_init (struct dvb_frontend* fe) ··· 823 729 struct s5h1420_state* state = fe->demodulator_priv; 824 730 825 731 /* disable power down and do reset */ 826 - s5h1420_writereg(state, 0x02, 0x10); 732 + state->CON_1_val = 0x10; 733 + s5h1420_writereg(state, 0x02, state->CON_1_val); 827 734 msleep(10); 828 735 s5h1420_reset(state); 829 736 ··· 834 739 static int s5h1420_sleep(struct dvb_frontend* fe) 835 740 { 836 741 struct s5h1420_state* state = fe->demodulator_priv; 837 - 838 - return s5h1420_writereg(state, 0x02, 0x12); 742 + state->CON_1_val = 0x12; 743 + return s5h1420_writereg(state, 0x02, state->CON_1_val); 839 744 } 840 745 841 746 static void s5h1420_release(struct dvb_frontend* fe) 842 747 { 843 748 struct s5h1420_state* state = fe->demodulator_priv; 749 + i2c_del_adapter(&state->tuner_i2c_adapter); 844 750 kfree(state); 845 751 } 846 752 753 + static u32 s5h1420_tuner_i2c_func(struct i2c_adapter *adapter) 754 + { 755 + return I2C_FUNC_I2C; 756 + } 757 + 758 + static int s5h1420_tuner_i2c_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) 759 + { 760 + struct s5h1420_state *state = i2c_get_adapdata(i2c_adap); 761 + struct i2c_msg m[1 + num]; 762 + u8 tx_open[2] = { CON_1, state->CON_1_val | 1 }; /* repeater stops once there was a stop condition */ 763 + 764 + memset(m, 0, sizeof(struct i2c_msg) * (1 + num)); 765 + 766 + m[0].addr = state->config->demod_address; 767 + m[0].buf = tx_open; 768 + m[0].len = 2; 769 + 770 + memcpy(&m[1], msg, sizeof(struct i2c_msg) * num); 771 + 772 + return i2c_transfer(state->i2c, m, 1+num) == 1 + num ? num : -EIO; 773 + } 774 + 775 + static struct i2c_algorithm s5h1420_tuner_i2c_algo = { 776 + .master_xfer = s5h1420_tuner_i2c_tuner_xfer, 777 + .functionality = s5h1420_tuner_i2c_func, 778 + }; 779 + 780 + struct i2c_adapter *s5h1420_get_tuner_i2c_adapter(struct dvb_frontend *fe) 781 + { 782 + struct s5h1420_state *state = fe->demodulator_priv; 783 + return &state->tuner_i2c_adapter; 784 + } 785 + EXPORT_SYMBOL(s5h1420_get_tuner_i2c_adapter); 786 + 847 787 static struct dvb_frontend_ops s5h1420_ops; 848 788 849 - struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config, 850 - struct i2c_adapter* i2c) 789 + struct dvb_frontend *s5h1420_attach(const struct s5h1420_config *config, 790 + struct i2c_adapter *i2c) 851 791 { 852 - struct s5h1420_state* state = NULL; 853 - u8 identity; 854 - 855 792 /* allocate memory for the internal state */ 856 - state = kmalloc(sizeof(struct s5h1420_state), GFP_KERNEL); 793 + struct s5h1420_state *state = kzalloc(sizeof(struct s5h1420_state), GFP_KERNEL); 794 + u8 i; 795 + 857 796 if (state == NULL) 858 797 goto error; 859 798 ··· 901 772 state->symbol_rate = 0; 902 773 903 774 /* check if the demod is there + identify it */ 904 - identity = s5h1420_readreg(state, 0x00); 905 - if (identity != 0x03) 775 + i = s5h1420_readreg(state, ID01); 776 + if (i != 0x03) 906 777 goto error; 778 + 779 + memset(state->shadow, 0xff, sizeof(state->shadow)); 780 + 781 + for (i = 0; i < 0x50; i++) 782 + state->shadow[i] = s5h1420_readreg(state, i); 907 783 908 784 /* create dvb_frontend */ 909 785 memcpy(&state->frontend.ops, &s5h1420_ops, sizeof(struct dvb_frontend_ops)); 910 786 state->frontend.demodulator_priv = state; 787 + 788 + /* create tuner i2c adapter */ 789 + strncpy(state->tuner_i2c_adapter.name, "S5H1420-PN1010 tuner I2C bus", I2C_NAME_SIZE); 790 + state->tuner_i2c_adapter.class = I2C_CLASS_TV_DIGITAL, 791 + state->tuner_i2c_adapter.algo = &s5h1420_tuner_i2c_algo; 792 + state->tuner_i2c_adapter.algo_data = NULL; 793 + i2c_set_adapdata(&state->tuner_i2c_adapter, state); 794 + if (i2c_add_adapter(&state->tuner_i2c_adapter) < 0) { 795 + printk(KERN_ERR "S5H1420/PN1010: tuner i2c bus could not be initialized\n"); 796 + goto error; 797 + } 798 + 911 799 return &state->frontend; 912 800 913 801 error: 914 802 kfree(state); 915 803 return NULL; 916 804 } 805 + EXPORT_SYMBOL(s5h1420_attach); 917 806 918 807 static struct dvb_frontend_ops s5h1420_ops = { 919 808 920 809 .info = { 921 - .name = "Samsung S5H1420 DVB-S", 810 + .name = "Samsung S5H1420/PnpNetwork PN1010 DVB-S", 922 811 .type = FE_QPSK, 923 812 .frequency_min = 950000, 924 813 .frequency_max = 2150000, ··· 973 826 .set_voltage = s5h1420_set_voltage, 974 827 }; 975 828 976 - module_param(debug, int, 0644); 977 - 978 - MODULE_DESCRIPTION("Samsung S5H1420 DVB-S Demodulator driver"); 979 - MODULE_AUTHOR("Andrew de Quincey"); 829 + MODULE_DESCRIPTION("Samsung S5H1420/PnpNetwork PN1010 DVB-S Demodulator driver"); 830 + MODULE_AUTHOR("Andrew de Quincey, Patrick Boettcher"); 980 831 MODULE_LICENSE("GPL"); 981 - 982 - EXPORT_SYMBOL(s5h1420_attach);
+36 -26
drivers/media/dvb/frontends/s5h1420.h
··· 1 1 /* 2 - Driver for S5H1420 QPSK Demodulators 3 - 4 - Copyright (C) 2005 Andrew de Quincey <adq_dvb@lidskialf.net> 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 - 15 - GNU General Public License for more details. 16 - 17 - You should have received a copy of the GNU General Public License 18 - along with this program; if not, write to the Free Software 19 - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 - 21 - */ 22 - 2 + * Driver for 3 + * Samsung S5H1420 and 4 + * PnpNetwork PN1010 QPSK Demodulator 5 + * 6 + * Copyright (C) 2005 Andrew de Quincey <adq_dvb@lidskialf.net> 7 + * Copyright (C) 2005-8 Patrick Boettcher <pb@linuxtv.org> 8 + * 9 + * This program is free software; you can redistribute it and/or modify 10 + * it under the terms of the GNU General Public License as published by 11 + * the Free Software Foundation; either version 2 of the License, or 12 + * (at your option) any later version. 13 + * 14 + * This program is distributed in the hope that it will be useful, 15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 + * 18 + * GNU General Public License for more details. 19 + * 20 + * You should have received a copy of the GNU General Public License 21 + * along with this program; if not, write to the Free Software 22 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 23 + */ 23 24 #ifndef S5H1420_H 24 25 #define S5H1420_H 25 26 ··· 32 31 u8 demod_address; 33 32 34 33 /* does the inversion require inversion? */ 35 - u8 invert:1; 34 + u8 invert : 1; 35 + 36 + u8 repeated_start_workaround : 1; 37 + u8 cdclk_polarity : 1; /* 1 == falling edge, 0 == raising edge */ 36 38 }; 37 39 38 40 #if defined(CONFIG_DVB_S5H1420) || (defined(CONFIG_DVB_S5H1420_MODULE) && defined(MODULE)) 39 - extern struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config, 40 - struct i2c_adapter* i2c); 41 + extern struct dvb_frontend *s5h1420_attach(const struct s5h1420_config *config, 42 + struct i2c_adapter *i2c); 43 + extern struct i2c_adapter *s5h1420_get_tuner_i2c_adapter(struct dvb_frontend *fe); 41 44 #else 42 - static inline struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config, 43 - struct i2c_adapter* i2c) 45 + static inline struct dvb_frontend *s5h1420_attach(const struct s5h1420_config *config, 46 + struct i2c_adapter *i2c) 44 47 { 45 48 printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); 49 + return NULL; 50 + } 51 + 52 + static inline struct i2c_adapter *s5h1420_get_tuner_i2c_adapter(struct dvb_frontend *fe) 53 + { 46 54 return NULL; 47 55 } 48 56 #endif // CONFIG_DVB_S5H1420
+102
drivers/media/dvb/frontends/s5h1420_priv.h
··· 1 + /* 2 + * Driver for 3 + * Samsung S5H1420 and 4 + * PnpNetwork PN1010 QPSK Demodulator 5 + * 6 + * Copyright (C) 2005 Andrew de Quincey <adq_dvb@lidskialf.net> 7 + * Copyright (C) 2005 Patrick Boettcher <pb@linuxtv.org> 8 + * 9 + * This program is free software; you can redistribute it and/or modify it 10 + * under the terms of the GNU General Public License as published by the Free 11 + * Software Foundation; either version 2 of the License, or (at your option) 12 + * any later version. 13 + * 14 + * This program is distributed in the hope that it will be useful, but WITHOUT 15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 16 + * FITNESS FOR A PARTICULAR PURPOSE. See the 17 + * 18 + * GNU General Public License for more details. 19 + * 20 + * You should have received a copy of the GNU General Public License along with 21 + * this program; if not, write to the Free Software Foundation, Inc., 675 Mass 22 + * Ave, Cambridge, MA 02139, USA. 23 + */ 24 + #ifndef S5H1420_PRIV 25 + #define S5H1420_PRIV 26 + 27 + #include <asm/types.h> 28 + 29 + enum s5h1420_register { 30 + ID01 = 0x00, 31 + CON_0 = 0x01, 32 + CON_1 = 0x02, 33 + PLL01 = 0x03, 34 + PLL02 = 0x04, 35 + QPSK01 = 0x05, 36 + QPSK02 = 0x06, 37 + Pre01 = 0x07, 38 + Post01 = 0x08, 39 + Loop01 = 0x09, 40 + Loop02 = 0x0a, 41 + Loop03 = 0x0b, 42 + Loop04 = 0x0c, 43 + Loop05 = 0x0d, 44 + Pnco01 = 0x0e, 45 + Pnco02 = 0x0f, 46 + Pnco03 = 0x10, 47 + Tnco01 = 0x11, 48 + Tnco02 = 0x12, 49 + Tnco03 = 0x13, 50 + Monitor01 = 0x14, 51 + Monitor02 = 0x15, 52 + Monitor03 = 0x16, 53 + Monitor04 = 0x17, 54 + Monitor05 = 0x18, 55 + Monitor06 = 0x19, 56 + Monitor07 = 0x1a, 57 + Monitor12 = 0x1f, 58 + 59 + FEC01 = 0x22, 60 + Soft01 = 0x23, 61 + Soft02 = 0x24, 62 + Soft03 = 0x25, 63 + Soft04 = 0x26, 64 + Soft05 = 0x27, 65 + Soft06 = 0x28, 66 + Vit01 = 0x29, 67 + Vit02 = 0x2a, 68 + Vit03 = 0x2b, 69 + Vit04 = 0x2c, 70 + Vit05 = 0x2d, 71 + Vit06 = 0x2e, 72 + Vit07 = 0x2f, 73 + Vit08 = 0x30, 74 + Vit09 = 0x31, 75 + Vit10 = 0x32, 76 + Vit11 = 0x33, 77 + Vit12 = 0x34, 78 + Sync01 = 0x35, 79 + Sync02 = 0x36, 80 + Rs01 = 0x37, 81 + Mpeg01 = 0x38, 82 + Mpeg02 = 0x39, 83 + DiS01 = 0x3a, 84 + DiS02 = 0x3b, 85 + DiS03 = 0x3c, 86 + DiS04 = 0x3d, 87 + DiS05 = 0x3e, 88 + DiS06 = 0x3f, 89 + DiS07 = 0x40, 90 + DiS08 = 0x41, 91 + DiS09 = 0x42, 92 + DiS10 = 0x43, 93 + DiS11 = 0x44, 94 + Rf01 = 0x45, 95 + Err01 = 0x46, 96 + Err02 = 0x47, 97 + Err03 = 0x48, 98 + Err04 = 0x49, 99 + }; 100 + 101 + 102 + #endif
+1
drivers/media/dvb/ttpci/budget.c
··· 358 358 static struct s5h1420_config s5h1420_config = { 359 359 .demod_address = 0x53, 360 360 .invert = 1, 361 + .cdclk_polarity = 1, 361 362 }; 362 363 363 364 static struct tda10086_config tda10086_config = {