1/* 2Driver for Samsung S5H1420 QPSK Demodulator 3 4Copyright (C) 2005 Andrew de Quincey <adq_dvb@lidskialf.net> 5 6This program is free software; you can redistribute it and/or modify 7it under the terms of the GNU General Public License as published by 8the Free Software Foundation; either version 2 of the License, or 9(at your option) any later version. 10 11This program is distributed in the hope that it will be useful, 12but WITHOUT ANY WARRANTY; without even the implied warranty of 13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 15GNU General Public License for more details. 16 17You should have received a copy of the GNU General Public License 18along with this program; if not, write to the Free Software 19Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 21*/ 22 23#include <linux/kernel.h> 24#include <linux/module.h> 25#include <linux/init.h> 26#include <linux/string.h> 27#include <linux/slab.h> 28#include <linux/delay.h> 29#include <linux/jiffies.h> 30#include <asm/div64.h> 31 32#include "dvb_frontend.h" 33#include "s5h1420.h" 34 35 36 37#define TONE_FREQ 22000 38 39struct s5h1420_state { 40 struct i2c_adapter* i2c; 41 const struct s5h1420_config* config; 42 struct dvb_frontend frontend; 43 44 u8 postlocked:1; 45 u32 fclk; 46 u32 tunedfreq; 47 fe_code_rate_t fec_inner; 48 u32 symbol_rate; 49}; 50 51static u32 s5h1420_getsymbolrate(struct s5h1420_state* state); 52static int s5h1420_get_tune_settings(struct dvb_frontend* fe, 53 struct dvb_frontend_tune_settings* fesettings); 54 55 56static int debug = 0; 57#define dprintk if (debug) printk 58 59static int s5h1420_writereg (struct s5h1420_state* state, u8 reg, u8 data) 60{ 61 u8 buf [] = { reg, data }; 62 struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 }; 63 int err; 64 65 if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { 66 dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __FUNCTION__, err, reg, data); 67 return -EREMOTEIO; 68 } 69 70 return 0; 71} 72 73static u8 s5h1420_readreg (struct s5h1420_state* state, u8 reg) 74{ 75 int ret; 76 u8 b0 [] = { reg }; 77 u8 b1 [] = { 0 }; 78 struct i2c_msg msg1 = { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }; 79 struct i2c_msg msg2 = { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 }; 80 81 if ((ret = i2c_transfer (state->i2c, &msg1, 1)) != 1) 82 return ret; 83 84 if ((ret = i2c_transfer (state->i2c, &msg2, 1)) != 1) 85 return ret; 86 87 return b1[0]; 88} 89 90static int s5h1420_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage) 91{ 92 struct s5h1420_state* state = fe->demodulator_priv; 93 94 switch(voltage) { 95 case SEC_VOLTAGE_13: 96 s5h1420_writereg(state, 0x3c, 97 (s5h1420_readreg(state, 0x3c) & 0xfe) | 0x02); 98 break; 99 100 case SEC_VOLTAGE_18: 101 s5h1420_writereg(state, 0x3c, s5h1420_readreg(state, 0x3c) | 0x03); 102 break; 103 104 case SEC_VOLTAGE_OFF: 105 s5h1420_writereg(state, 0x3c, s5h1420_readreg(state, 0x3c) & 0xfd); 106 break; 107 } 108 109 return 0; 110} 111 112static int s5h1420_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone) 113{ 114 struct s5h1420_state* state = fe->demodulator_priv; 115 116 switch(tone) { 117 case SEC_TONE_ON: 118 s5h1420_writereg(state, 0x3b, 119 (s5h1420_readreg(state, 0x3b) & 0x74) | 0x08); 120 break; 121 122 case SEC_TONE_OFF: 123 s5h1420_writereg(state, 0x3b, 124 (s5h1420_readreg(state, 0x3b) & 0x74) | 0x01); 125 break; 126 } 127 128 return 0; 129} 130 131static int s5h1420_send_master_cmd (struct dvb_frontend* fe, 132 struct dvb_diseqc_master_cmd* cmd) 133{ 134 struct s5h1420_state* state = fe->demodulator_priv; 135 u8 val; 136 int i; 137 unsigned long timeout; 138 int result = 0; 139 140 if (cmd->msg_len > 8) 141 return -EINVAL; 142 143 /* setup for DISEQC */ 144 val = s5h1420_readreg(state, 0x3b); 145 s5h1420_writereg(state, 0x3b, 0x02); 146 msleep(15); 147 148 /* write the DISEQC command bytes */ 149 for(i=0; i< cmd->msg_len; i++) { 150 s5h1420_writereg(state, 0x3d + i, cmd->msg[i]); 151 } 152 153 /* kick off transmission */ 154 s5h1420_writereg(state, 0x3b, s5h1420_readreg(state, 0x3b) | 155 ((cmd->msg_len-1) << 4) | 0x08); 156 157 /* wait for transmission to complete */ 158 timeout = jiffies + ((100*HZ) / 1000); 159 while(time_before(jiffies, timeout)) { 160 if (!(s5h1420_readreg(state, 0x3b) & 0x08)) 161 break; 162 163 msleep(5); 164 } 165 if (time_after(jiffies, timeout)) 166 result = -ETIMEDOUT; 167 168 /* restore original settings */ 169 s5h1420_writereg(state, 0x3b, val); 170 msleep(15); 171 return result; 172} 173 174static int s5h1420_recv_slave_reply (struct dvb_frontend* fe, 175 struct dvb_diseqc_slave_reply* reply) 176{ 177 struct s5h1420_state* state = fe->demodulator_priv; 178 u8 val; 179 int i; 180 int length; 181 unsigned long timeout; 182 int result = 0; 183 184 /* setup for DISEQC recieve */ 185 val = s5h1420_readreg(state, 0x3b); 186 s5h1420_writereg(state, 0x3b, 0x82); 187 msleep(15); 188 189 /* wait for reception to complete */ 190 timeout = jiffies + ((reply->timeout*HZ) / 1000); 191 while(time_before(jiffies, timeout)) { 192 if (!(s5h1420_readreg(state, 0x3b) & 0x80)) 193 break; 194 195 msleep(5); 196 } 197 if (time_after(jiffies, timeout)) { 198 result = -ETIMEDOUT; 199 goto exit; 200 } 201 202 if (s5h1420_readreg(state, 0x49)) { 203 result = -EIO; 204 goto exit; 205 } 206 207 /* check length */ 208 length = (s5h1420_readreg(state, 0x3b) & 0x70) >> 4; 209 if (length > sizeof(reply->msg)) { 210 result = -EOVERFLOW; 211 goto exit; 212 } 213 reply->msg_len = length; 214 215 /* extract data */ 216 for(i=0; i< length; i++) { 217 reply->msg[i] = s5h1420_readreg(state, 0x3d + i); 218 } 219 220exit: 221 /* restore original settings */ 222 s5h1420_writereg(state, 0x3b, val); 223 msleep(15); 224 return result; 225} 226 227static int s5h1420_send_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) 228{ 229 struct s5h1420_state* state = fe->demodulator_priv; 230 u8 val; 231 int result = 0; 232 unsigned long timeout; 233 234 /* setup for tone burst */ 235 val = s5h1420_readreg(state, 0x3b); 236 s5h1420_writereg(state, 0x3b, (s5h1420_readreg(state, 0x3b) & 0x70) | 0x01); 237 238 /* set value for B position if requested */ 239 if (minicmd == SEC_MINI_B) { 240 s5h1420_writereg(state, 0x3b, s5h1420_readreg(state, 0x3b) | 0x04); 241 } 242 msleep(15); 243 244 /* start transmission */ 245 s5h1420_writereg(state, 0x3b, s5h1420_readreg(state, 0x3b) | 0x08); 246 247 /* wait for transmission to complete */ 248 timeout = jiffies + ((100*HZ) / 1000); 249 while(time_before(jiffies, timeout)) { 250 if (!(s5h1420_readreg(state, 0x3b) & 0x08)) 251 break; 252 253 msleep(5); 254 } 255 if (time_after(jiffies, timeout)) 256 result = -ETIMEDOUT; 257 258 /* restore original settings */ 259 s5h1420_writereg(state, 0x3b, val); 260 msleep(15); 261 return result; 262} 263 264static fe_status_t s5h1420_get_status_bits(struct s5h1420_state* state) 265{ 266 u8 val; 267 fe_status_t status = 0; 268 269 val = s5h1420_readreg(state, 0x14); 270 if (val & 0x02) 271 status |= FE_HAS_SIGNAL; 272 if (val & 0x01) 273 status |= FE_HAS_CARRIER; 274 val = s5h1420_readreg(state, 0x36); 275 if (val & 0x01) 276 status |= FE_HAS_VITERBI; 277 if (val & 0x20) 278 status |= FE_HAS_SYNC; 279 if (status == (FE_HAS_SIGNAL|FE_HAS_CARRIER|FE_HAS_VITERBI|FE_HAS_SYNC)) 280 status |= FE_HAS_LOCK; 281 282 return status; 283} 284 285static int s5h1420_read_status(struct dvb_frontend* fe, fe_status_t* status) 286{ 287 struct s5h1420_state* state = fe->demodulator_priv; 288 u8 val; 289 290 if (status == NULL) 291 return -EINVAL; 292 293 /* determine lock state */ 294 *status = s5h1420_get_status_bits(state); 295 296 /* fix for FEC 5/6 inversion issue - if it doesn't quite lock, invert 297 the inversion, wait a bit and check again */ 298 if (*status == (FE_HAS_SIGNAL|FE_HAS_CARRIER|FE_HAS_VITERBI)) { 299 val = s5h1420_readreg(state, 0x32); 300 if ((val & 0x07) == 0x03) { 301 if (val & 0x08) 302 s5h1420_writereg(state, 0x31, 0x13); 303 else 304 s5h1420_writereg(state, 0x31, 0x1b); 305 306 /* wait a bit then update lock status */ 307 mdelay(200); 308 *status = s5h1420_get_status_bits(state); 309 } 310 } 311 312 /* perform post lock setup */ 313 if ((*status & FE_HAS_LOCK) && (!state->postlocked)) { 314 315 /* calculate the data rate */ 316 u32 tmp = s5h1420_getsymbolrate(state); 317 switch(s5h1420_readreg(state, 0x32) & 0x07) { 318 case 0: 319 tmp = (tmp * 2 * 1) / 2; 320 break; 321 322 case 1: 323 tmp = (tmp * 2 * 2) / 3; 324 break; 325 326 case 2: 327 tmp = (tmp * 2 * 3) / 4; 328 break; 329 330 case 3: 331 tmp = (tmp * 2 * 5) / 6; 332 break; 333 334 case 4: 335 tmp = (tmp * 2 * 6) / 7; 336 break; 337 338 case 5: 339 tmp = (tmp * 2 * 7) / 8; 340 break; 341 } 342 if (tmp == 0) { 343 printk("s5h1420: avoided division by 0\n"); 344 tmp = 1; 345 } 346 tmp = state->fclk / tmp; 347 348 /* set the MPEG_CLK_INTL for the calculated data rate */ 349 if (tmp < 4) 350 val = 0x00; 351 else if (tmp < 8) 352 val = 0x01; 353 else if (tmp < 12) 354 val = 0x02; 355 else if (tmp < 16) 356 val = 0x03; 357 else if (tmp < 24) 358 val = 0x04; 359 else if (tmp < 32) 360 val = 0x05; 361 else 362 val = 0x06; 363 s5h1420_writereg(state, 0x22, val); 364 365 /* DC freeze */ 366 s5h1420_writereg(state, 0x1f, s5h1420_readreg(state, 0x1f) | 0x01); 367 368 /* kicker disable + remove DC offset */ 369 s5h1420_writereg(state, 0x05, s5h1420_readreg(state, 0x05) & 0x6f); 370 371 /* post-lock processing has been done! */ 372 state->postlocked = 1; 373 } 374 375 return 0; 376} 377 378static int s5h1420_read_ber(struct dvb_frontend* fe, u32* ber) 379{ 380 struct s5h1420_state* state = fe->demodulator_priv; 381 382 s5h1420_writereg(state, 0x46, 0x1d); 383 mdelay(25); 384 385 *ber = (s5h1420_readreg(state, 0x48) << 8) | s5h1420_readreg(state, 0x47); 386 387 return 0; 388} 389 390static int s5h1420_read_signal_strength(struct dvb_frontend* fe, u16* strength) 391{ 392 struct s5h1420_state* state = fe->demodulator_priv; 393 394 u8 val = s5h1420_readreg(state, 0x15); 395 396 *strength = (u16) ((val << 8) | val); 397 398 return 0; 399} 400 401static int s5h1420_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) 402{ 403 struct s5h1420_state* state = fe->demodulator_priv; 404 405 s5h1420_writereg(state, 0x46, 0x1f); 406 mdelay(25); 407 408 *ucblocks = (s5h1420_readreg(state, 0x48) << 8) | s5h1420_readreg(state, 0x47); 409 410 return 0; 411} 412 413static void s5h1420_reset(struct s5h1420_state* state) 414{ 415 s5h1420_writereg (state, 0x01, 0x08); 416 s5h1420_writereg (state, 0x01, 0x00); 417 udelay(10); 418} 419 420static void s5h1420_setsymbolrate(struct s5h1420_state* state, 421 struct dvb_frontend_parameters *p) 422{ 423 u64 val; 424 425 val = ((u64) p->u.qpsk.symbol_rate / 1000ULL) * (1ULL<<24); 426 if (p->u.qpsk.symbol_rate <= 21000000) { 427 val *= 2; 428 } 429 do_div(val, (state->fclk / 1000)); 430 431 s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) & 0x7f); 432 s5h1420_writereg(state, 0x11, val >> 16); 433 s5h1420_writereg(state, 0x12, val >> 8); 434 s5h1420_writereg(state, 0x13, val & 0xff); 435 s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) | 0x80); 436} 437 438static u32 s5h1420_getsymbolrate(struct s5h1420_state* state) 439{ 440 u64 val = 0; 441 int sampling = 2; 442 443 if (s5h1420_readreg(state, 0x05) & 0x2) 444 sampling = 1; 445 446 s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) | 0x08); 447 val = s5h1420_readreg(state, 0x11) << 16; 448 val |= s5h1420_readreg(state, 0x12) << 8; 449 val |= s5h1420_readreg(state, 0x13); 450 s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) & 0xf7); 451 452 val *= (state->fclk / 1000ULL); 453 do_div(val, ((1<<24) * sampling)); 454 455 return (u32) (val * 1000ULL); 456} 457 458static void s5h1420_setfreqoffset(struct s5h1420_state* state, int freqoffset) 459{ 460 int val; 461 462 /* remember freqoffset is in kHz, but the chip wants the offset in Hz, so 463 * divide fclk by 1000000 to get the correct value. */ 464 val = -(int) ((freqoffset * (1<<24)) / (state->fclk / 1000000)); 465 466 s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) & 0xbf); 467 s5h1420_writereg(state, 0x0e, val >> 16); 468 s5h1420_writereg(state, 0x0f, val >> 8); 469 s5h1420_writereg(state, 0x10, val & 0xff); 470 s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) | 0x40); 471} 472 473static int s5h1420_getfreqoffset(struct s5h1420_state* state) 474{ 475 int val; 476 477 s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) | 0x08); 478 val = s5h1420_readreg(state, 0x0e) << 16; 479 val |= s5h1420_readreg(state, 0x0f) << 8; 480 val |= s5h1420_readreg(state, 0x10); 481 s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) & 0xf7); 482 483 if (val & 0x800000) 484 val |= 0xff000000; 485 486 /* remember freqoffset is in kHz, but the chip wants the offset in Hz, so 487 * divide fclk by 1000000 to get the correct value. */ 488 val = (((-val) * (state->fclk/1000000)) / (1<<24)); 489 490 return val; 491} 492 493static void s5h1420_setfec_inversion(struct s5h1420_state* state, 494 struct dvb_frontend_parameters *p) 495{ 496 u8 inversion = 0; 497 498 if (p->inversion == INVERSION_OFF) { 499 inversion = state->config->invert ? 0x08 : 0; 500 } else if (p->inversion == INVERSION_ON) { 501 inversion = state->config->invert ? 0 : 0x08; 502 } 503 504 if ((p->u.qpsk.fec_inner == FEC_AUTO) || (p->inversion == INVERSION_AUTO)) { 505 s5h1420_writereg(state, 0x30, 0x3f); 506 s5h1420_writereg(state, 0x31, 0x00 | inversion); 507 } else { 508 switch(p->u.qpsk.fec_inner) { 509 case FEC_1_2: 510 s5h1420_writereg(state, 0x30, 0x01); 511 s5h1420_writereg(state, 0x31, 0x10 | inversion); 512 break; 513 514 case FEC_2_3: 515 s5h1420_writereg(state, 0x30, 0x02); 516 s5h1420_writereg(state, 0x31, 0x11 | inversion); 517 break; 518 519 case FEC_3_4: 520 s5h1420_writereg(state, 0x30, 0x04); 521 s5h1420_writereg(state, 0x31, 0x12 | inversion); 522 break; 523 524 case FEC_5_6: 525 s5h1420_writereg(state, 0x30, 0x08); 526 s5h1420_writereg(state, 0x31, 0x13 | inversion); 527 break; 528 529 case FEC_6_7: 530 s5h1420_writereg(state, 0x30, 0x10); 531 s5h1420_writereg(state, 0x31, 0x14 | inversion); 532 break; 533 534 case FEC_7_8: 535 s5h1420_writereg(state, 0x30, 0x20); 536 s5h1420_writereg(state, 0x31, 0x15 | inversion); 537 break; 538 539 default: 540 return; 541 } 542 } 543} 544 545static fe_code_rate_t s5h1420_getfec(struct s5h1420_state* state) 546{ 547 switch(s5h1420_readreg(state, 0x32) & 0x07) { 548 case 0: 549 return FEC_1_2; 550 551 case 1: 552 return FEC_2_3; 553 554 case 2: 555 return FEC_3_4; 556 557 case 3: 558 return FEC_5_6; 559 560 case 4: 561 return FEC_6_7; 562 563 case 5: 564 return FEC_7_8; 565 } 566 567 return FEC_NONE; 568} 569 570static fe_spectral_inversion_t s5h1420_getinversion(struct s5h1420_state* state) 571{ 572 if (s5h1420_readreg(state, 0x32) & 0x08) 573 return INVERSION_ON; 574 575 return INVERSION_OFF; 576} 577 578static int s5h1420_set_frontend(struct dvb_frontend* fe, 579 struct dvb_frontend_parameters *p) 580{ 581 struct s5h1420_state* state = fe->demodulator_priv; 582 int frequency_delta; 583 struct dvb_frontend_tune_settings fesettings; 584 585 /* check if we should do a fast-tune */ 586 memcpy(&fesettings.parameters, p, sizeof(struct dvb_frontend_parameters)); 587 s5h1420_get_tune_settings(fe, &fesettings); 588 frequency_delta = p->frequency - state->tunedfreq; 589 if ((frequency_delta > -fesettings.max_drift) && 590 (frequency_delta < fesettings.max_drift) && 591 (frequency_delta != 0) && 592 (state->fec_inner == p->u.qpsk.fec_inner) && 593 (state->symbol_rate == p->u.qpsk.symbol_rate)) { 594 595 if (fe->ops.tuner_ops.set_params) { 596 fe->ops.tuner_ops.set_params(fe, p); 597 if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); 598 } 599 if (fe->ops.tuner_ops.get_frequency) { 600 u32 tmp; 601 fe->ops.tuner_ops.get_frequency(fe, &tmp); 602 if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); 603 s5h1420_setfreqoffset(state, p->frequency - tmp); 604 } else { 605 s5h1420_setfreqoffset(state, 0); 606 } 607 return 0; 608 } 609 610 /* first of all, software reset */ 611 s5h1420_reset(state); 612 613 /* set s5h1420 fclk PLL according to desired symbol rate */ 614 if (p->u.qpsk.symbol_rate > 28000000) { 615 state->fclk = 88000000; 616 s5h1420_writereg(state, 0x03, 0x50); 617 s5h1420_writereg(state, 0x04, 0x40); 618 s5h1420_writereg(state, 0x05, 0xae); 619 } else if (p->u.qpsk.symbol_rate > 21000000) { 620 state->fclk = 59000000; 621 s5h1420_writereg(state, 0x03, 0x33); 622 s5h1420_writereg(state, 0x04, 0x40); 623 s5h1420_writereg(state, 0x05, 0xae); 624 } else { 625 state->fclk = 88000000; 626 s5h1420_writereg(state, 0x03, 0x50); 627 s5h1420_writereg(state, 0x04, 0x40); 628 s5h1420_writereg(state, 0x05, 0xac); 629 } 630 631 /* set misc registers */ 632 s5h1420_writereg(state, 0x02, 0x00); 633 s5h1420_writereg(state, 0x06, 0x00); 634 s5h1420_writereg(state, 0x07, 0xb0); 635 s5h1420_writereg(state, 0x0a, 0xe7); 636 s5h1420_writereg(state, 0x0b, 0x78); 637 s5h1420_writereg(state, 0x0c, 0x48); 638 s5h1420_writereg(state, 0x0d, 0x6b); 639 s5h1420_writereg(state, 0x2e, 0x8e); 640 s5h1420_writereg(state, 0x35, 0x33); 641 s5h1420_writereg(state, 0x38, 0x01); 642 s5h1420_writereg(state, 0x39, 0x7d); 643 s5h1420_writereg(state, 0x3a, (state->fclk + (TONE_FREQ * 32) - 1) / (TONE_FREQ * 32)); 644 s5h1420_writereg(state, 0x3c, 0x00); 645 s5h1420_writereg(state, 0x45, 0x61); 646 s5h1420_writereg(state, 0x46, 0x1d); 647 648 /* start QPSK */ 649 s5h1420_writereg(state, 0x05, s5h1420_readreg(state, 0x05) | 1); 650 651 /* set tuner PLL */ 652 if (fe->ops.tuner_ops.set_params) { 653 fe->ops.tuner_ops.set_params(fe, p); 654 if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); 655 s5h1420_setfreqoffset(state, 0); 656 } 657 658 /* set the reset of the parameters */ 659 s5h1420_setsymbolrate(state, p); 660 s5h1420_setfec_inversion(state, p); 661 662 state->fec_inner = p->u.qpsk.fec_inner; 663 state->symbol_rate = p->u.qpsk.symbol_rate; 664 state->postlocked = 0; 665 state->tunedfreq = p->frequency; 666 return 0; 667} 668 669static int s5h1420_get_frontend(struct dvb_frontend* fe, 670 struct dvb_frontend_parameters *p) 671{ 672 struct s5h1420_state* state = fe->demodulator_priv; 673 674 p->frequency = state->tunedfreq + s5h1420_getfreqoffset(state); 675 p->inversion = s5h1420_getinversion(state); 676 p->u.qpsk.symbol_rate = s5h1420_getsymbolrate(state); 677 p->u.qpsk.fec_inner = s5h1420_getfec(state); 678 679 return 0; 680} 681 682static int s5h1420_get_tune_settings(struct dvb_frontend* fe, 683 struct dvb_frontend_tune_settings* fesettings) 684{ 685 if (fesettings->parameters.u.qpsk.symbol_rate > 20000000) { 686 fesettings->min_delay_ms = 50; 687 fesettings->step_size = 2000; 688 fesettings->max_drift = 8000; 689 } else if (fesettings->parameters.u.qpsk.symbol_rate > 12000000) { 690 fesettings->min_delay_ms = 100; 691 fesettings->step_size = 1500; 692 fesettings->max_drift = 9000; 693 } else if (fesettings->parameters.u.qpsk.symbol_rate > 8000000) { 694 fesettings->min_delay_ms = 100; 695 fesettings->step_size = 1000; 696 fesettings->max_drift = 8000; 697 } else if (fesettings->parameters.u.qpsk.symbol_rate > 4000000) { 698 fesettings->min_delay_ms = 100; 699 fesettings->step_size = 500; 700 fesettings->max_drift = 7000; 701 } else if (fesettings->parameters.u.qpsk.symbol_rate > 2000000) { 702 fesettings->min_delay_ms = 200; 703 fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000); 704 fesettings->max_drift = 14 * fesettings->step_size; 705 } else { 706 fesettings->min_delay_ms = 200; 707 fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000); 708 fesettings->max_drift = 18 * fesettings->step_size; 709 } 710 711 return 0; 712} 713 714static int s5h1420_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) 715{ 716 struct s5h1420_state* state = fe->demodulator_priv; 717 718 if (enable) { 719 return s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1); 720 } else { 721 return s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) & 0xfe); 722 } 723} 724 725static int s5h1420_init (struct dvb_frontend* fe) 726{ 727 struct s5h1420_state* state = fe->demodulator_priv; 728 729 /* disable power down and do reset */ 730 s5h1420_writereg(state, 0x02, 0x10); 731 msleep(10); 732 s5h1420_reset(state); 733 734 return 0; 735} 736 737static int s5h1420_sleep(struct dvb_frontend* fe) 738{ 739 struct s5h1420_state* state = fe->demodulator_priv; 740 741 return s5h1420_writereg(state, 0x02, 0x12); 742} 743 744static void s5h1420_release(struct dvb_frontend* fe) 745{ 746 struct s5h1420_state* state = fe->demodulator_priv; 747 kfree(state); 748} 749 750static struct dvb_frontend_ops s5h1420_ops; 751 752struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config, 753 struct i2c_adapter* i2c) 754{ 755 struct s5h1420_state* state = NULL; 756 u8 identity; 757 758 /* allocate memory for the internal state */ 759 state = kmalloc(sizeof(struct s5h1420_state), GFP_KERNEL); 760 if (state == NULL) 761 goto error; 762 763 /* setup the state */ 764 state->config = config; 765 state->i2c = i2c; 766 state->postlocked = 0; 767 state->fclk = 88000000; 768 state->tunedfreq = 0; 769 state->fec_inner = FEC_NONE; 770 state->symbol_rate = 0; 771 772 /* check if the demod is there + identify it */ 773 identity = s5h1420_readreg(state, 0x00); 774 if (identity != 0x03) 775 goto error; 776 777 /* create dvb_frontend */ 778 memcpy(&state->frontend.ops, &s5h1420_ops, sizeof(struct dvb_frontend_ops)); 779 state->frontend.demodulator_priv = state; 780 return &state->frontend; 781 782error: 783 kfree(state); 784 return NULL; 785} 786 787static struct dvb_frontend_ops s5h1420_ops = { 788 789 .info = { 790 .name = "Samsung S5H1420 DVB-S", 791 .type = FE_QPSK, 792 .frequency_min = 950000, 793 .frequency_max = 2150000, 794 .frequency_stepsize = 125, /* kHz for QPSK frontends */ 795 .frequency_tolerance = 29500, 796 .symbol_rate_min = 1000000, 797 .symbol_rate_max = 45000000, 798 /* .symbol_rate_tolerance = ???,*/ 799 .caps = FE_CAN_INVERSION_AUTO | 800 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | 801 FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | 802 FE_CAN_QPSK 803 }, 804 805 .release = s5h1420_release, 806 807 .init = s5h1420_init, 808 .sleep = s5h1420_sleep, 809 .i2c_gate_ctrl = s5h1420_i2c_gate_ctrl, 810 811 .set_frontend = s5h1420_set_frontend, 812 .get_frontend = s5h1420_get_frontend, 813 .get_tune_settings = s5h1420_get_tune_settings, 814 815 .read_status = s5h1420_read_status, 816 .read_ber = s5h1420_read_ber, 817 .read_signal_strength = s5h1420_read_signal_strength, 818 .read_ucblocks = s5h1420_read_ucblocks, 819 820 .diseqc_send_master_cmd = s5h1420_send_master_cmd, 821 .diseqc_recv_slave_reply = s5h1420_recv_slave_reply, 822 .diseqc_send_burst = s5h1420_send_burst, 823 .set_tone = s5h1420_set_tone, 824 .set_voltage = s5h1420_set_voltage, 825}; 826 827module_param(debug, int, 0644); 828 829MODULE_DESCRIPTION("Samsung S5H1420 DVB-S Demodulator driver"); 830MODULE_AUTHOR("Andrew de Quincey"); 831MODULE_LICENSE("GPL"); 832 833EXPORT_SYMBOL(s5h1420_attach); 834