fc0013.c (13944B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Fitipower FC0013 tuner driver 4 * 5 * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.net> 6 * partially based on driver code from Fitipower 7 * Copyright (C) 2010 Fitipower Integrated Technology Inc 8 */ 9 10#include "fc0013.h" 11#include "fc0013-priv.h" 12 13static int fc0013_writereg(struct fc0013_priv *priv, u8 reg, u8 val) 14{ 15 u8 buf[2] = {reg, val}; 16 struct i2c_msg msg = { 17 .addr = priv->addr, .flags = 0, .buf = buf, .len = 2 18 }; 19 20 if (i2c_transfer(priv->i2c, &msg, 1) != 1) { 21 err("I2C write reg failed, reg: %02x, val: %02x", reg, val); 22 return -EREMOTEIO; 23 } 24 return 0; 25} 26 27static int fc0013_readreg(struct fc0013_priv *priv, u8 reg, u8 *val) 28{ 29 struct i2c_msg msg[2] = { 30 { .addr = priv->addr, .flags = 0, .buf = ®, .len = 1 }, 31 { .addr = priv->addr, .flags = I2C_M_RD, .buf = val, .len = 1 }, 32 }; 33 34 if (i2c_transfer(priv->i2c, msg, 2) != 2) { 35 err("I2C read reg failed, reg: %02x", reg); 36 return -EREMOTEIO; 37 } 38 return 0; 39} 40 41static void fc0013_release(struct dvb_frontend *fe) 42{ 43 kfree(fe->tuner_priv); 44 fe->tuner_priv = NULL; 45} 46 47static int fc0013_init(struct dvb_frontend *fe) 48{ 49 struct fc0013_priv *priv = fe->tuner_priv; 50 int i, ret = 0; 51 unsigned char reg[] = { 52 0x00, /* reg. 0x00: dummy */ 53 0x09, /* reg. 0x01 */ 54 0x16, /* reg. 0x02 */ 55 0x00, /* reg. 0x03 */ 56 0x00, /* reg. 0x04 */ 57 0x17, /* reg. 0x05 */ 58 0x02, /* reg. 0x06 */ 59 0x0a, /* reg. 0x07: CHECK */ 60 0xff, /* reg. 0x08: AGC Clock divide by 256, AGC gain 1/256, 61 Loop Bw 1/8 */ 62 0x6f, /* reg. 0x09: enable LoopThrough */ 63 0xb8, /* reg. 0x0a: Disable LO Test Buffer */ 64 0x82, /* reg. 0x0b: CHECK */ 65 0xfc, /* reg. 0x0c: depending on AGC Up-Down mode, may need 0xf8 */ 66 0x01, /* reg. 0x0d: AGC Not Forcing & LNA Forcing, may need 0x02 */ 67 0x00, /* reg. 0x0e */ 68 0x00, /* reg. 0x0f */ 69 0x00, /* reg. 0x10 */ 70 0x00, /* reg. 0x11 */ 71 0x00, /* reg. 0x12 */ 72 0x00, /* reg. 0x13 */ 73 0x50, /* reg. 0x14: DVB-t High Gain, UHF. 74 Middle Gain: 0x48, Low Gain: 0x40 */ 75 0x01, /* reg. 0x15 */ 76 }; 77 78 switch (priv->xtal_freq) { 79 case FC_XTAL_27_MHZ: 80 case FC_XTAL_28_8_MHZ: 81 reg[0x07] |= 0x20; 82 break; 83 case FC_XTAL_36_MHZ: 84 default: 85 break; 86 } 87 88 if (priv->dual_master) 89 reg[0x0c] |= 0x02; 90 91 if (fe->ops.i2c_gate_ctrl) 92 fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ 93 94 for (i = 1; i < sizeof(reg); i++) { 95 ret = fc0013_writereg(priv, i, reg[i]); 96 if (ret) 97 break; 98 } 99 100 if (fe->ops.i2c_gate_ctrl) 101 fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ 102 103 if (ret) 104 err("fc0013_writereg failed: %d", ret); 105 106 return ret; 107} 108 109static int fc0013_sleep(struct dvb_frontend *fe) 110{ 111 /* nothing to do here */ 112 return 0; 113} 114 115int fc0013_rc_cal_add(struct dvb_frontend *fe, int rc_val) 116{ 117 struct fc0013_priv *priv = fe->tuner_priv; 118 int ret; 119 u8 rc_cal; 120 int val; 121 122 if (fe->ops.i2c_gate_ctrl) 123 fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ 124 125 /* push rc_cal value, get rc_cal value */ 126 ret = fc0013_writereg(priv, 0x10, 0x00); 127 if (ret) 128 goto error_out; 129 130 /* get rc_cal value */ 131 ret = fc0013_readreg(priv, 0x10, &rc_cal); 132 if (ret) 133 goto error_out; 134 135 rc_cal &= 0x0f; 136 137 val = (int)rc_cal + rc_val; 138 139 /* forcing rc_cal */ 140 ret = fc0013_writereg(priv, 0x0d, 0x11); 141 if (ret) 142 goto error_out; 143 144 /* modify rc_cal value */ 145 if (val > 15) 146 ret = fc0013_writereg(priv, 0x10, 0x0f); 147 else if (val < 0) 148 ret = fc0013_writereg(priv, 0x10, 0x00); 149 else 150 ret = fc0013_writereg(priv, 0x10, (u8)val); 151 152error_out: 153 if (fe->ops.i2c_gate_ctrl) 154 fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ 155 156 return ret; 157} 158EXPORT_SYMBOL(fc0013_rc_cal_add); 159 160int fc0013_rc_cal_reset(struct dvb_frontend *fe) 161{ 162 struct fc0013_priv *priv = fe->tuner_priv; 163 int ret; 164 165 if (fe->ops.i2c_gate_ctrl) 166 fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ 167 168 ret = fc0013_writereg(priv, 0x0d, 0x01); 169 if (!ret) 170 ret = fc0013_writereg(priv, 0x10, 0x00); 171 172 if (fe->ops.i2c_gate_ctrl) 173 fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ 174 175 return ret; 176} 177EXPORT_SYMBOL(fc0013_rc_cal_reset); 178 179static int fc0013_set_vhf_track(struct fc0013_priv *priv, u32 freq) 180{ 181 int ret; 182 u8 tmp; 183 184 ret = fc0013_readreg(priv, 0x1d, &tmp); 185 if (ret) 186 goto error_out; 187 tmp &= 0xe3; 188 if (freq <= 177500) { /* VHF Track: 7 */ 189 ret = fc0013_writereg(priv, 0x1d, tmp | 0x1c); 190 } else if (freq <= 184500) { /* VHF Track: 6 */ 191 ret = fc0013_writereg(priv, 0x1d, tmp | 0x18); 192 } else if (freq <= 191500) { /* VHF Track: 5 */ 193 ret = fc0013_writereg(priv, 0x1d, tmp | 0x14); 194 } else if (freq <= 198500) { /* VHF Track: 4 */ 195 ret = fc0013_writereg(priv, 0x1d, tmp | 0x10); 196 } else if (freq <= 205500) { /* VHF Track: 3 */ 197 ret = fc0013_writereg(priv, 0x1d, tmp | 0x0c); 198 } else if (freq <= 219500) { /* VHF Track: 2 */ 199 ret = fc0013_writereg(priv, 0x1d, tmp | 0x08); 200 } else if (freq < 300000) { /* VHF Track: 1 */ 201 ret = fc0013_writereg(priv, 0x1d, tmp | 0x04); 202 } else { /* UHF and GPS */ 203 ret = fc0013_writereg(priv, 0x1d, tmp | 0x1c); 204 } 205error_out: 206 return ret; 207} 208 209static int fc0013_set_params(struct dvb_frontend *fe) 210{ 211 struct fc0013_priv *priv = fe->tuner_priv; 212 int i, ret = 0; 213 struct dtv_frontend_properties *p = &fe->dtv_property_cache; 214 u32 freq = p->frequency / 1000; 215 u32 delsys = p->delivery_system; 216 unsigned char reg[7], am, pm, multi, tmp; 217 unsigned long f_vco; 218 unsigned short xtal_freq_khz_2, xin, xdiv; 219 bool vco_select = false; 220 221 if (fe->callback) { 222 ret = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER, 223 FC_FE_CALLBACK_VHF_ENABLE, (freq > 300000 ? 0 : 1)); 224 if (ret) 225 goto exit; 226 } 227 228 switch (priv->xtal_freq) { 229 case FC_XTAL_27_MHZ: 230 xtal_freq_khz_2 = 27000 / 2; 231 break; 232 case FC_XTAL_36_MHZ: 233 xtal_freq_khz_2 = 36000 / 2; 234 break; 235 case FC_XTAL_28_8_MHZ: 236 default: 237 xtal_freq_khz_2 = 28800 / 2; 238 break; 239 } 240 241 if (fe->ops.i2c_gate_ctrl) 242 fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ 243 244 /* set VHF track */ 245 ret = fc0013_set_vhf_track(priv, freq); 246 if (ret) 247 goto exit; 248 249 if (freq < 300000) { 250 /* enable VHF filter */ 251 ret = fc0013_readreg(priv, 0x07, &tmp); 252 if (ret) 253 goto exit; 254 ret = fc0013_writereg(priv, 0x07, tmp | 0x10); 255 if (ret) 256 goto exit; 257 258 /* disable UHF & disable GPS */ 259 ret = fc0013_readreg(priv, 0x14, &tmp); 260 if (ret) 261 goto exit; 262 ret = fc0013_writereg(priv, 0x14, tmp & 0x1f); 263 if (ret) 264 goto exit; 265 } else if (freq <= 862000) { 266 /* disable VHF filter */ 267 ret = fc0013_readreg(priv, 0x07, &tmp); 268 if (ret) 269 goto exit; 270 ret = fc0013_writereg(priv, 0x07, tmp & 0xef); 271 if (ret) 272 goto exit; 273 274 /* enable UHF & disable GPS */ 275 ret = fc0013_readreg(priv, 0x14, &tmp); 276 if (ret) 277 goto exit; 278 ret = fc0013_writereg(priv, 0x14, (tmp & 0x1f) | 0x40); 279 if (ret) 280 goto exit; 281 } else { 282 /* disable VHF filter */ 283 ret = fc0013_readreg(priv, 0x07, &tmp); 284 if (ret) 285 goto exit; 286 ret = fc0013_writereg(priv, 0x07, tmp & 0xef); 287 if (ret) 288 goto exit; 289 290 /* disable UHF & enable GPS */ 291 ret = fc0013_readreg(priv, 0x14, &tmp); 292 if (ret) 293 goto exit; 294 ret = fc0013_writereg(priv, 0x14, (tmp & 0x1f) | 0x20); 295 if (ret) 296 goto exit; 297 } 298 299 /* select frequency divider and the frequency of VCO */ 300 if (freq < 37084) { /* freq * 96 < 3560000 */ 301 multi = 96; 302 reg[5] = 0x82; 303 reg[6] = 0x00; 304 } else if (freq < 55625) { /* freq * 64 < 3560000 */ 305 multi = 64; 306 reg[5] = 0x02; 307 reg[6] = 0x02; 308 } else if (freq < 74167) { /* freq * 48 < 3560000 */ 309 multi = 48; 310 reg[5] = 0x42; 311 reg[6] = 0x00; 312 } else if (freq < 111250) { /* freq * 32 < 3560000 */ 313 multi = 32; 314 reg[5] = 0x82; 315 reg[6] = 0x02; 316 } else if (freq < 148334) { /* freq * 24 < 3560000 */ 317 multi = 24; 318 reg[5] = 0x22; 319 reg[6] = 0x00; 320 } else if (freq < 222500) { /* freq * 16 < 3560000 */ 321 multi = 16; 322 reg[5] = 0x42; 323 reg[6] = 0x02; 324 } else if (freq < 296667) { /* freq * 12 < 3560000 */ 325 multi = 12; 326 reg[5] = 0x12; 327 reg[6] = 0x00; 328 } else if (freq < 445000) { /* freq * 8 < 3560000 */ 329 multi = 8; 330 reg[5] = 0x22; 331 reg[6] = 0x02; 332 } else if (freq < 593334) { /* freq * 6 < 3560000 */ 333 multi = 6; 334 reg[5] = 0x0a; 335 reg[6] = 0x00; 336 } else if (freq < 950000) { /* freq * 4 < 3800000 */ 337 multi = 4; 338 reg[5] = 0x12; 339 reg[6] = 0x02; 340 } else { 341 multi = 2; 342 reg[5] = 0x0a; 343 reg[6] = 0x02; 344 } 345 346 f_vco = freq * multi; 347 348 if (f_vco >= 3060000) { 349 reg[6] |= 0x08; 350 vco_select = true; 351 } 352 353 if (freq >= 45000) { 354 /* From divided value (XDIV) determined the FA and FP value */ 355 xdiv = (unsigned short)(f_vco / xtal_freq_khz_2); 356 if ((f_vco - xdiv * xtal_freq_khz_2) >= (xtal_freq_khz_2 / 2)) 357 xdiv++; 358 359 pm = (unsigned char)(xdiv / 8); 360 am = (unsigned char)(xdiv - (8 * pm)); 361 362 if (am < 2) { 363 reg[1] = am + 8; 364 reg[2] = pm - 1; 365 } else { 366 reg[1] = am; 367 reg[2] = pm; 368 } 369 } else { 370 /* fix for frequency less than 45 MHz */ 371 reg[1] = 0x06; 372 reg[2] = 0x11; 373 } 374 375 /* fix clock out */ 376 reg[6] |= 0x20; 377 378 /* From VCO frequency determines the XIN ( fractional part of Delta 379 Sigma PLL) and divided value (XDIV) */ 380 xin = (unsigned short)(f_vco - (f_vco / xtal_freq_khz_2) * xtal_freq_khz_2); 381 xin = (xin << 15) / xtal_freq_khz_2; 382 if (xin >= 16384) 383 xin += 32768; 384 385 reg[3] = xin >> 8; 386 reg[4] = xin & 0xff; 387 388 if (delsys == SYS_DVBT) { 389 reg[6] &= 0x3f; /* bits 6 and 7 describe the bandwidth */ 390 switch (p->bandwidth_hz) { 391 case 6000000: 392 reg[6] |= 0x80; 393 break; 394 case 7000000: 395 reg[6] |= 0x40; 396 break; 397 case 8000000: 398 default: 399 break; 400 } 401 } else { 402 err("%s: modulation type not supported!", __func__); 403 return -EINVAL; 404 } 405 406 /* modified for Realtek demod */ 407 reg[5] |= 0x07; 408 409 for (i = 1; i <= 6; i++) { 410 ret = fc0013_writereg(priv, i, reg[i]); 411 if (ret) 412 goto exit; 413 } 414 415 ret = fc0013_readreg(priv, 0x11, &tmp); 416 if (ret) 417 goto exit; 418 if (multi == 64) 419 ret = fc0013_writereg(priv, 0x11, tmp | 0x04); 420 else 421 ret = fc0013_writereg(priv, 0x11, tmp & 0xfb); 422 if (ret) 423 goto exit; 424 425 /* VCO Calibration */ 426 ret = fc0013_writereg(priv, 0x0e, 0x80); 427 if (!ret) 428 ret = fc0013_writereg(priv, 0x0e, 0x00); 429 430 /* VCO Re-Calibration if needed */ 431 if (!ret) 432 ret = fc0013_writereg(priv, 0x0e, 0x00); 433 434 if (!ret) { 435 msleep(10); 436 ret = fc0013_readreg(priv, 0x0e, &tmp); 437 } 438 if (ret) 439 goto exit; 440 441 /* vco selection */ 442 tmp &= 0x3f; 443 444 if (vco_select) { 445 if (tmp > 0x3c) { 446 reg[6] &= ~0x08; 447 ret = fc0013_writereg(priv, 0x06, reg[6]); 448 if (!ret) 449 ret = fc0013_writereg(priv, 0x0e, 0x80); 450 if (!ret) 451 ret = fc0013_writereg(priv, 0x0e, 0x00); 452 } 453 } else { 454 if (tmp < 0x02) { 455 reg[6] |= 0x08; 456 ret = fc0013_writereg(priv, 0x06, reg[6]); 457 if (!ret) 458 ret = fc0013_writereg(priv, 0x0e, 0x80); 459 if (!ret) 460 ret = fc0013_writereg(priv, 0x0e, 0x00); 461 } 462 } 463 464 priv->frequency = p->frequency; 465 priv->bandwidth = p->bandwidth_hz; 466 467exit: 468 if (fe->ops.i2c_gate_ctrl) 469 fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ 470 if (ret) 471 warn("%s: failed: %d", __func__, ret); 472 return ret; 473} 474 475static int fc0013_get_frequency(struct dvb_frontend *fe, u32 *frequency) 476{ 477 struct fc0013_priv *priv = fe->tuner_priv; 478 *frequency = priv->frequency; 479 return 0; 480} 481 482static int fc0013_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) 483{ 484 /* always ? */ 485 *frequency = 0; 486 return 0; 487} 488 489static int fc0013_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) 490{ 491 struct fc0013_priv *priv = fe->tuner_priv; 492 *bandwidth = priv->bandwidth; 493 return 0; 494} 495 496#define INPUT_ADC_LEVEL -8 497 498static int fc0013_get_rf_strength(struct dvb_frontend *fe, u16 *strength) 499{ 500 struct fc0013_priv *priv = fe->tuner_priv; 501 int ret; 502 unsigned char tmp; 503 int int_temp, lna_gain, int_lna, tot_agc_gain, power; 504 static const int fc0013_lna_gain_table[] = { 505 /* low gain */ 506 -63, -58, -99, -73, 507 -63, -65, -54, -60, 508 /* middle gain */ 509 71, 70, 68, 67, 510 65, 63, 61, 58, 511 /* high gain */ 512 197, 191, 188, 186, 513 184, 182, 181, 179, 514 }; 515 516 if (fe->ops.i2c_gate_ctrl) 517 fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ 518 519 ret = fc0013_writereg(priv, 0x13, 0x00); 520 if (ret) 521 goto err; 522 523 ret = fc0013_readreg(priv, 0x13, &tmp); 524 if (ret) 525 goto err; 526 int_temp = tmp; 527 528 ret = fc0013_readreg(priv, 0x14, &tmp); 529 if (ret) 530 goto err; 531 lna_gain = tmp & 0x1f; 532 533 if (fe->ops.i2c_gate_ctrl) 534 fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ 535 536 if (lna_gain < ARRAY_SIZE(fc0013_lna_gain_table)) { 537 int_lna = fc0013_lna_gain_table[lna_gain]; 538 tot_agc_gain = (abs((int_temp >> 5) - 7) - 2 + 539 (int_temp & 0x1f)) * 2; 540 power = INPUT_ADC_LEVEL - tot_agc_gain - int_lna / 10; 541 542 if (power >= 45) 543 *strength = 255; /* 100% */ 544 else if (power < -95) 545 *strength = 0; 546 else 547 *strength = (power + 95) * 255 / 140; 548 549 *strength |= *strength << 8; 550 } else { 551 ret = -1; 552 } 553 554 goto exit; 555 556err: 557 if (fe->ops.i2c_gate_ctrl) 558 fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ 559exit: 560 if (ret) 561 warn("%s: failed: %d", __func__, ret); 562 return ret; 563} 564 565static const struct dvb_tuner_ops fc0013_tuner_ops = { 566 .info = { 567 .name = "Fitipower FC0013", 568 569 .frequency_min_hz = 37 * MHz, /* estimate */ 570 .frequency_max_hz = 1680 * MHz, /* CHECK */ 571 }, 572 573 .release = fc0013_release, 574 575 .init = fc0013_init, 576 .sleep = fc0013_sleep, 577 578 .set_params = fc0013_set_params, 579 580 .get_frequency = fc0013_get_frequency, 581 .get_if_frequency = fc0013_get_if_frequency, 582 .get_bandwidth = fc0013_get_bandwidth, 583 584 .get_rf_strength = fc0013_get_rf_strength, 585}; 586 587struct dvb_frontend *fc0013_attach(struct dvb_frontend *fe, 588 struct i2c_adapter *i2c, u8 i2c_address, int dual_master, 589 enum fc001x_xtal_freq xtal_freq) 590{ 591 struct fc0013_priv *priv = NULL; 592 593 priv = kzalloc(sizeof(struct fc0013_priv), GFP_KERNEL); 594 if (priv == NULL) 595 return NULL; 596 597 priv->i2c = i2c; 598 priv->dual_master = dual_master; 599 priv->addr = i2c_address; 600 priv->xtal_freq = xtal_freq; 601 602 info("Fitipower FC0013 successfully attached."); 603 604 fe->tuner_priv = priv; 605 606 memcpy(&fe->ops.tuner_ops, &fc0013_tuner_ops, 607 sizeof(struct dvb_tuner_ops)); 608 609 return fe; 610} 611EXPORT_SYMBOL(fc0013_attach); 612 613MODULE_DESCRIPTION("Fitipower FC0013 silicon tuner driver"); 614MODULE_AUTHOR("Hans-Frieder Vogt <hfvogt@gmx.net>"); 615MODULE_LICENSE("GPL"); 616MODULE_VERSION("0.2");