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