Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v2.6.21 565 lines 15 kB view raw
1/* 2 * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III 3 * 4 * flexcop-fe-tuner.c - methods for attaching a frontend and controlling DiSEqC. 5 * 6 * see flexcop.c for copyright information. 7 */ 8#include "flexcop.h" 9 10#include "stv0299.h" 11#include "mt352.h" 12#include "nxt200x.h" 13#include "bcm3510.h" 14#include "stv0297.h" 15#include "mt312.h" 16#include "lgdt330x.h" 17#include "lgh06xf.h" 18#include "dvb-pll.h" 19 20/* lnb control */ 21 22static int flexcop_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) 23{ 24 struct flexcop_device *fc = fe->dvb->priv; 25 flexcop_ibi_value v; 26 deb_tuner("polarity/voltage = %u\n", voltage); 27 28 v = fc->read_ibi_reg(fc, misc_204); 29 switch (voltage) { 30 case SEC_VOLTAGE_OFF: 31 v.misc_204.ACPI1_sig = 1; 32 break; 33 case SEC_VOLTAGE_13: 34 v.misc_204.ACPI1_sig = 0; 35 v.misc_204.LNB_L_H_sig = 0; 36 break; 37 case SEC_VOLTAGE_18: 38 v.misc_204.ACPI1_sig = 0; 39 v.misc_204.LNB_L_H_sig = 1; 40 break; 41 default: 42 err("unknown SEC_VOLTAGE value"); 43 return -EINVAL; 44 } 45 return fc->write_ibi_reg(fc, misc_204, v); 46} 47 48static int flexcop_sleep(struct dvb_frontend* fe) 49{ 50 struct flexcop_device *fc = fe->dvb->priv; 51/* flexcop_ibi_value v = fc->read_ibi_reg(fc,misc_204); */ 52 53 if (fc->fe_sleep) 54 return fc->fe_sleep(fe); 55 56/* v.misc_204.ACPI3_sig = 1; 57 fc->write_ibi_reg(fc,misc_204,v);*/ 58 59 return 0; 60} 61 62static int flexcop_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) 63{ 64 /* u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc }; */ 65 struct flexcop_device *fc = fe->dvb->priv; 66 flexcop_ibi_value v; 67 u16 ax; 68 v.raw = 0; 69 70 deb_tuner("tone = %u\n",tone); 71 72 switch (tone) { 73 case SEC_TONE_ON: 74 ax = 0x01ff; 75 break; 76 case SEC_TONE_OFF: 77 ax = 0; 78 break; 79 default: 80 err("unknown SEC_TONE value"); 81 return -EINVAL; 82 } 83 84 v.lnb_switch_freq_200.LNB_CTLPrescaler_sig = 1; /* divide by 2 */ 85 86 v.lnb_switch_freq_200.LNB_CTLHighCount_sig = ax; 87 v.lnb_switch_freq_200.LNB_CTLLowCount_sig = ax == 0 ? 0x1ff : ax; 88 89 return fc->write_ibi_reg(fc,lnb_switch_freq_200,v); 90} 91 92static void flexcop_diseqc_send_bit(struct dvb_frontend* fe, int data) 93{ 94 flexcop_set_tone(fe, SEC_TONE_ON); 95 udelay(data ? 500 : 1000); 96 flexcop_set_tone(fe, SEC_TONE_OFF); 97 udelay(data ? 1000 : 500); 98} 99 100static void flexcop_diseqc_send_byte(struct dvb_frontend* fe, int data) 101{ 102 int i, par = 1, d; 103 104 for (i = 7; i >= 0; i--) { 105 d = (data >> i) & 1; 106 par ^= d; 107 flexcop_diseqc_send_bit(fe, d); 108 } 109 110 flexcop_diseqc_send_bit(fe, par); 111} 112 113static int flexcop_send_diseqc_msg(struct dvb_frontend* fe, int len, u8 *msg, unsigned long burst) 114{ 115 int i; 116 117 flexcop_set_tone(fe, SEC_TONE_OFF); 118 mdelay(16); 119 120 for (i = 0; i < len; i++) 121 flexcop_diseqc_send_byte(fe,msg[i]); 122 123 mdelay(16); 124 125 if (burst != -1) { 126 if (burst) 127 flexcop_diseqc_send_byte(fe, 0xff); 128 else { 129 flexcop_set_tone(fe, SEC_TONE_ON); 130 udelay(12500); 131 flexcop_set_tone(fe, SEC_TONE_OFF); 132 } 133 msleep(20); 134 } 135 return 0; 136} 137 138static int flexcop_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd) 139{ 140 return flexcop_send_diseqc_msg(fe, cmd->msg_len, cmd->msg, 0); 141} 142 143static int flexcop_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) 144{ 145 return flexcop_send_diseqc_msg(fe, 0, NULL, minicmd); 146} 147 148/* dvb-s stv0299 */ 149static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio) 150{ 151 u8 aclk = 0; 152 u8 bclk = 0; 153 154 if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; } 155 else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; } 156 else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; } 157 else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; } 158 else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; } 159 else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; } 160 161 stv0299_writereg (fe, 0x13, aclk); 162 stv0299_writereg (fe, 0x14, bclk); 163 stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff); 164 stv0299_writereg (fe, 0x20, (ratio >> 8) & 0xff); 165 stv0299_writereg (fe, 0x21, (ratio ) & 0xf0); 166 167 return 0; 168} 169 170static int samsung_tbmu24112_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) 171{ 172 u8 buf[4]; 173 u32 div; 174 struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; 175 struct flexcop_device *fc = fe->dvb->priv; 176 177 div = params->frequency / 125; 178 179 buf[0] = (div >> 8) & 0x7f; 180 buf[1] = div & 0xff; 181 buf[2] = 0x84; /* 0xC4 */ 182 buf[3] = 0x08; 183 184 if (params->frequency < 1500000) buf[3] |= 0x10; 185 186 if (fe->ops.i2c_gate_ctrl) 187 fe->ops.i2c_gate_ctrl(fe, 1); 188 if (i2c_transfer(&fc->i2c_adap, &msg, 1) != 1) { 189 return -EIO; 190 } 191 return 0; 192} 193 194static u8 samsung_tbmu24112_inittab[] = { 195 0x01, 0x15, 196 0x02, 0x30, 197 0x03, 0x00, 198 0x04, 0x7D, 199 0x05, 0x35, 200 0x06, 0x02, 201 0x07, 0x00, 202 0x08, 0xC3, 203 0x0C, 0x00, 204 0x0D, 0x81, 205 0x0E, 0x23, 206 0x0F, 0x12, 207 0x10, 0x7E, 208 0x11, 0x84, 209 0x12, 0xB9, 210 0x13, 0x88, 211 0x14, 0x89, 212 0x15, 0xC9, 213 0x16, 0x00, 214 0x17, 0x5C, 215 0x18, 0x00, 216 0x19, 0x00, 217 0x1A, 0x00, 218 0x1C, 0x00, 219 0x1D, 0x00, 220 0x1E, 0x00, 221 0x1F, 0x3A, 222 0x20, 0x2E, 223 0x21, 0x80, 224 0x22, 0xFF, 225 0x23, 0xC1, 226 0x28, 0x00, 227 0x29, 0x1E, 228 0x2A, 0x14, 229 0x2B, 0x0F, 230 0x2C, 0x09, 231 0x2D, 0x05, 232 0x31, 0x1F, 233 0x32, 0x19, 234 0x33, 0xFE, 235 0x34, 0x93, 236 0xff, 0xff, 237}; 238 239static struct stv0299_config samsung_tbmu24112_config = { 240 .demod_address = 0x68, 241 .inittab = samsung_tbmu24112_inittab, 242 .mclk = 88000000UL, 243 .invert = 0, 244 .skip_reinit = 0, 245 .lock_output = STV0229_LOCKOUTPUT_LK, 246 .volt13_op0_op1 = STV0299_VOLT13_OP1, 247 .min_delay_ms = 100, 248 .set_symbol_rate = samsung_tbmu24112_set_symbol_rate, 249}; 250 251/* dvb-t mt352 */ 252static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe) 253{ 254 static u8 mt352_clock_config [] = { 0x89, 0x18, 0x2d }; 255 static u8 mt352_reset [] = { 0x50, 0x80 }; 256 static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 }; 257 static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0xa1 }; 258 static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; 259 260 mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); 261 udelay(2000); 262 mt352_write(fe, mt352_reset, sizeof(mt352_reset)); 263 mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); 264 265 mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg)); 266 mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); 267 268 return 0; 269} 270 271static int samsung_tdtc9251dh0_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters *params, u8* pllbuf, int buf_len) 272{ 273 u32 div; 274 unsigned char bs = 0; 275 276 if (buf_len < 5) 277 return -EINVAL; 278 279 #define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ 280 div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; 281 282 if (params->frequency >= 48000000 && params->frequency <= 154000000) bs = 0x09; 283 if (params->frequency >= 161000000 && params->frequency <= 439000000) bs = 0x0a; 284 if (params->frequency >= 447000000 && params->frequency <= 863000000) bs = 0x08; 285 286 pllbuf[0] = 0x61; 287 pllbuf[1] = div >> 8; 288 pllbuf[2] = div & 0xff; 289 pllbuf[3] = 0xcc; 290 pllbuf[4] = bs; 291 292 return 5; 293} 294 295static struct mt352_config samsung_tdtc9251dh0_config = { 296 .demod_address = 0x0f, 297 .demod_init = samsung_tdtc9251dh0_demod_init, 298}; 299 300static int flexcop_fe_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name) 301{ 302 struct flexcop_device *fc = fe->dvb->priv; 303 return request_firmware(fw, name, fc->dev); 304} 305 306static struct lgdt330x_config air2pc_atsc_hd5000_config = { 307 .demod_address = 0x59, 308 .demod_chip = LGDT3303, 309 .serial_mpeg = 0x04, 310 .clock_polarity_flip = 1, 311}; 312 313static struct nxt200x_config samsung_tbmv_config = { 314 .demod_address = 0x0a, 315}; 316 317static struct bcm3510_config air2pc_atsc_first_gen_config = { 318 .demod_address = 0x0f, 319 .request_firmware = flexcop_fe_request_firmware, 320}; 321 322static int skystar23_samsung_tbdu18132_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) 323{ 324 u8 buf[4]; 325 u32 div; 326 struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; 327 struct flexcop_device *fc = fe->dvb->priv; 328 329 div = (params->frequency + (125/2)) / 125; 330 331 buf[0] = (div >> 8) & 0x7f; 332 buf[1] = (div >> 0) & 0xff; 333 buf[2] = 0x84 | ((div >> 10) & 0x60); 334 buf[3] = 0x80; 335 336 if (params->frequency < 1550000) 337 buf[3] |= 0x02; 338 339 if (fe->ops.i2c_gate_ctrl) 340 fe->ops.i2c_gate_ctrl(fe, 1); 341 if (i2c_transfer(&fc->i2c_adap, &msg, 1) != 1) 342 return -EIO; 343 return 0; 344} 345 346static struct mt312_config skystar23_samsung_tbdu18132_config = { 347 348 .demod_address = 0x0e, 349}; 350 351static int alps_tdee4_stv0297_tuner_set_params(struct dvb_frontend* fe, 352 struct dvb_frontend_parameters *fep) 353{ 354 struct flexcop_device *fc = fe->dvb->priv; 355 u8 buf[4]; 356 u16 div; 357 int ret; 358 359/* 62.5 kHz * 10 */ 360#define REF_FREQ 625 361#define FREQ_OFFSET 36125 362 363 div = ((fep->frequency/1000 + FREQ_OFFSET ) * 10) / REF_FREQ; // 4 MHz = 4000 KHz 364 365 buf[0] = (u8)( div >> 8) & 0x7f; 366 buf[1] = (u8) div & 0xff; 367 368/* F(osc) = N * Reference Freq. (62.5 kHz) 369 * byte 2 : 0 N14 N13 N12 N11 N10 N9 N8 370 * byte 3 : N7 N6 N5 N4 N3 N2 N1 N0 371 * byte 4 : 1 * * AGD R3 R2 R1 R0 372 * byte 5 : C1 * RE RTS BS4 BS3 BS2 BS1 373 * AGD = 1, R3 R2 R1 R0 = 0 1 0 1 => byte 4 = 1**10101 = 0x95 */ 374 buf[2] = 0x95; 375 376// Range(MHz) C1 * RE RTS BS4 BS3 BS2 BS1 Byte 5 377// 47 - 153 0 * 0 0 0 0 0 1 0x01 378// 153 - 430 0 * 0 0 0 0 1 0 0x02 379// 430 - 822 0 * 0 0 1 0 0 0 0x08 380// 822 - 862 1 * 0 0 1 0 0 0 0x88 381 382 if (fep->frequency <= 153000000) buf[3] = 0x01; 383 else if (fep->frequency <= 430000000) buf[3] = 0x02; 384 else if (fep->frequency <= 822000000) buf[3] = 0x08; 385 else buf[3] = 0x88; 386 387 if (fe->ops.i2c_gate_ctrl) 388 fe->ops.i2c_gate_ctrl(fe, 0); 389 deb_tuner("tuner buffer for %d Hz: %x %x %x %x\n",fep->frequency, buf[0],buf[1],buf[2],buf[3]); 390 ret = fc->i2c_request(fc, FC_WRITE, FC_I2C_PORT_TUNER, 0x61, buf[0], &buf[1], 3); 391 deb_tuner("tuner write returned: %d\n",ret); 392 393 return 0; 394} 395 396static u8 alps_tdee4_stv0297_inittab[] = { 397 0x80, 0x01, 398 0x80, 0x00, 399 0x81, 0x01, 400 0x81, 0x00, 401 0x00, 0x48, 402 0x01, 0x58, 403 0x03, 0x00, 404 0x04, 0x00, 405 0x07, 0x00, 406 0x08, 0x00, 407 0x30, 0xff, 408 0x31, 0x9d, 409 0x32, 0xff, 410 0x33, 0x00, 411 0x34, 0x29, 412 0x35, 0x55, 413 0x36, 0x80, 414 0x37, 0x6e, 415 0x38, 0x9c, 416 0x40, 0x1a, 417 0x41, 0xfe, 418 0x42, 0x33, 419 0x43, 0x00, 420 0x44, 0xff, 421 0x45, 0x00, 422 0x46, 0x00, 423 0x49, 0x04, 424 0x4a, 0x51, 425 0x4b, 0xf8, 426 0x52, 0x30, 427 0x53, 0x06, 428 0x59, 0x06, 429 0x5a, 0x5e, 430 0x5b, 0x04, 431 0x61, 0x49, 432 0x62, 0x0a, 433 0x70, 0xff, 434 0x71, 0x04, 435 0x72, 0x00, 436 0x73, 0x00, 437 0x74, 0x0c, 438 0x80, 0x20, 439 0x81, 0x00, 440 0x82, 0x30, 441 0x83, 0x00, 442 0x84, 0x04, 443 0x85, 0x22, 444 0x86, 0x08, 445 0x87, 0x1b, 446 0x88, 0x00, 447 0x89, 0x00, 448 0x90, 0x00, 449 0x91, 0x04, 450 0xa0, 0x86, 451 0xa1, 0x00, 452 0xa2, 0x00, 453 0xb0, 0x91, 454 0xb1, 0x0b, 455 0xc0, 0x5b, 456 0xc1, 0x10, 457 0xc2, 0x12, 458 0xd0, 0x02, 459 0xd1, 0x00, 460 0xd2, 0x00, 461 0xd3, 0x00, 462 0xd4, 0x02, 463 0xd5, 0x00, 464 0xde, 0x00, 465 0xdf, 0x01, 466 0xff, 0xff, 467}; 468 469static struct stv0297_config alps_tdee4_stv0297_config = { 470 .demod_address = 0x1c, 471 .inittab = alps_tdee4_stv0297_inittab, 472// .invert = 1, 473// .pll_set = alps_tdee4_stv0297_pll_set, 474}; 475 476/* try to figure out the frontend, each card/box can have on of the following list */ 477int flexcop_frontend_init(struct flexcop_device *fc) 478{ 479 struct dvb_frontend_ops *ops; 480 481 /* try the sky v2.6 (stv0299/Samsung tbmu24112(sl1935)) */ 482 if ((fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, &fc->i2c_adap)) != NULL) { 483 ops = &fc->fe->ops; 484 485 ops->tuner_ops.set_params = samsung_tbmu24112_tuner_set_params; 486 487 ops->set_voltage = flexcop_set_voltage; 488 489 fc->fe_sleep = ops->sleep; 490 ops->sleep = flexcop_sleep; 491 492 fc->dev_type = FC_SKY; 493 info("found the stv0299 at i2c address: 0x%02x",samsung_tbmu24112_config.demod_address); 494 } else 495 /* try the air dvb-t (mt352/Samsung tdtc9251dh0(??)) */ 496 if ((fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, &fc->i2c_adap)) != NULL ) { 497 fc->dev_type = FC_AIR_DVB; 498 fc->fe->ops.tuner_ops.calc_regs = samsung_tdtc9251dh0_calc_regs; 499 info("found the mt352 at i2c address: 0x%02x",samsung_tdtc9251dh0_config.demod_address); 500 } else 501 /* try the air atsc 2nd generation (nxt2002) */ 502 if ((fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, &fc->i2c_adap)) != NULL) { 503 fc->dev_type = FC_AIR_ATSC2; 504 dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, &dvb_pll_samsung_tbmv); 505 info("found the nxt2002 at i2c address: 0x%02x",samsung_tbmv_config.demod_address); 506 } else 507 /* try the air atsc 3nd generation (lgdt3303) */ 508 if ((fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, &fc->i2c_adap)) != NULL) { 509 fc->dev_type = FC_AIR_ATSC3; 510 dvb_attach(lgh06xf_attach, fc->fe, &fc->i2c_adap); 511 info("found the lgdt3303 at i2c address: 0x%02x",air2pc_atsc_hd5000_config.demod_address); 512 } else 513 /* try the air atsc 1nd generation (bcm3510)/panasonic ct10s */ 514 if ((fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, &fc->i2c_adap)) != NULL) { 515 fc->dev_type = FC_AIR_ATSC1; 516 info("found the bcm3510 at i2c address: 0x%02x",air2pc_atsc_first_gen_config.demod_address); 517 } else 518 /* try the cable dvb (stv0297) */ 519 if ((fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, &fc->i2c_adap)) != NULL) { 520 fc->dev_type = FC_CABLE; 521 fc->fe->ops.tuner_ops.set_params = alps_tdee4_stv0297_tuner_set_params; 522 info("found the stv0297 at i2c address: 0x%02x",alps_tdee4_stv0297_config.demod_address); 523 } else 524 /* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */ 525 if ((fc->fe = dvb_attach(vp310_mt312_attach, &skystar23_samsung_tbdu18132_config, &fc->i2c_adap)) != NULL) { 526 ops = &fc->fe->ops; 527 528 ops->tuner_ops.set_params = skystar23_samsung_tbdu18132_tuner_set_params; 529 530 ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd; 531 ops->diseqc_send_burst = flexcop_diseqc_send_burst; 532 ops->set_tone = flexcop_set_tone; 533 ops->set_voltage = flexcop_set_voltage; 534 535 fc->fe_sleep = ops->sleep; 536 ops->sleep = flexcop_sleep; 537 538 fc->dev_type = FC_SKY_OLD; 539 info("found the vp310 (aka mt312) at i2c address: 0x%02x",skystar23_samsung_tbdu18132_config.demod_address); 540 } 541 542 if (fc->fe == NULL) { 543 err("no frontend driver found for this B2C2/FlexCop adapter"); 544 return -ENODEV; 545 } else { 546 if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) { 547 err("frontend registration failed!"); 548 dvb_frontend_detach(fc->fe); 549 fc->fe = NULL; 550 return -EINVAL; 551 } 552 } 553 fc->init_state |= FC_STATE_FE_INIT; 554 return 0; 555} 556 557void flexcop_frontend_exit(struct flexcop_device *fc) 558{ 559 if (fc->init_state & FC_STATE_FE_INIT) { 560 dvb_unregister_frontend(fc->fe); 561 dvb_frontend_detach(fc->fe); 562 } 563 564 fc->init_state &= ~FC_STATE_FE_INIT; 565}