1 /* 2 * Fitipower FC0011 tuner driver 3 * 4 * Copyright (C) 2012 Michael Buesch <m@bues.ch> 5 * 6 * Derived from FC0012 tuner driver: 7 * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.net> 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 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 22 */ 23 24 #include "fc0011.h" 25 26 27 /* Tuner registers */ 28 enum { 29 FC11_REG_0, 30 FC11_REG_FA, /* FA */ 31 FC11_REG_FP, /* FP */ 32 FC11_REG_XINHI, /* XIN high 8 bit */ 33 FC11_REG_XINLO, /* XIN low 8 bit */ 34 FC11_REG_VCO, /* VCO */ 35 FC11_REG_VCOSEL, /* VCO select */ 36 FC11_REG_7, /* Unknown tuner reg 7 */ 37 FC11_REG_8, /* Unknown tuner reg 8 */ 38 FC11_REG_9, 39 FC11_REG_10, /* Unknown tuner reg 10 */ 40 FC11_REG_11, /* Unknown tuner reg 11 */ 41 FC11_REG_12, 42 FC11_REG_RCCAL, /* RC calibrate */ 43 FC11_REG_VCOCAL, /* VCO calibrate */ 44 FC11_REG_15, 45 FC11_REG_16, /* Unknown tuner reg 16 */ 46 FC11_REG_17, 47 48 FC11_NR_REGS, /* Number of registers */ 49 }; 50 51 enum FC11_REG_VCOSEL_bits { 52 FC11_VCOSEL_2 = 0x08, /* VCO select 2 */ 53 FC11_VCOSEL_1 = 0x10, /* VCO select 1 */ 54 FC11_VCOSEL_CLKOUT = 0x20, /* Fix clock out */ 55 FC11_VCOSEL_BW7M = 0x40, /* 7MHz bw */ 56 FC11_VCOSEL_BW6M = 0x80, /* 6MHz bw */ 57 }; 58 59 enum FC11_REG_RCCAL_bits { 60 FC11_RCCAL_FORCE = 0x10, /* force */ 61 }; 62 63 enum FC11_REG_VCOCAL_bits { 64 FC11_VCOCAL_RUN = 0, /* VCO calibration run */ 65 FC11_VCOCAL_VALUEMASK = 0x3F, /* VCO calibration value mask */ 66 FC11_VCOCAL_OK = 0x40, /* VCO calibration Ok */ 67 FC11_VCOCAL_RESET = 0x80, /* VCO calibration reset */ 68 }; 69 70 71 struct fc0011_priv { 72 struct i2c_adapter *i2c; 73 u8 addr; 74 75 u32 frequency; 76 u32 bandwidth; 77 }; 78 79 80 static int fc0011_writereg(struct fc0011_priv *priv, u8 reg, u8 val) 81 { 82 u8 buf[2] = { reg, val }; 83 struct i2c_msg msg = { .addr = priv->addr, 84 .flags = 0, .buf = buf, .len = 2 }; 85 86 if (i2c_transfer(priv->i2c, &msg, 1) != 1) { 87 dev_err(&priv->i2c->dev, 88 "I2C write reg failed, reg: %02x, val: %02x\n", 89 reg, val); 90 return -EIO; 91 } 92 93 return 0; 94 } 95 96 static int fc0011_readreg(struct fc0011_priv *priv, u8 reg, u8 *val) 97 { 98 u8 dummy; 99 struct i2c_msg msg[2] = { 100 { .addr = priv->addr, 101 .flags = 0, .buf = ®, .len = 1 }, 102 { .addr = priv->addr, 103 .flags = I2C_M_RD, .buf = val ? : &dummy, .len = 1 }, 104 }; 105 106 if (i2c_transfer(priv->i2c, msg, 2) != 2) { 107 dev_err(&priv->i2c->dev, 108 "I2C read failed, reg: %02x\n", reg); 109 return -EIO; 110 } 111 112 return 0; 113 } 114 115 static int fc0011_release(struct dvb_frontend *fe) 116 { 117 kfree(fe->tuner_priv); 118 fe->tuner_priv = NULL; 119 120 return 0; 121 } 122 123 static int fc0011_init(struct dvb_frontend *fe) 124 { 125 struct fc0011_priv *priv = fe->tuner_priv; 126 int err; 127 128 if (WARN_ON(!fe->callback)) 129 return -EINVAL; 130 131 err = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER, 132 FC0011_FE_CALLBACK_POWER, priv->addr); 133 if (err) { 134 dev_err(&priv->i2c->dev, "Power-on callback failed\n"); 135 return err; 136 } 137 err = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER, 138 FC0011_FE_CALLBACK_RESET, priv->addr); 139 if (err) { 140 dev_err(&priv->i2c->dev, "Reset callback failed\n"); 141 return err; 142 } 143 144 return 0; 145 } 146 147 /* Initiate VCO calibration */ 148 static int fc0011_vcocal_trigger(struct fc0011_priv *priv) 149 { 150 int err; 151 152 err = fc0011_writereg(priv, FC11_REG_VCOCAL, FC11_VCOCAL_RESET); 153 if (err) 154 return err; 155 err = fc0011_writereg(priv, FC11_REG_VCOCAL, FC11_VCOCAL_RUN); 156 if (err) 157 return err; 158 159 return 0; 160 } 161 162 /* Read VCO calibration value */ 163 static int fc0011_vcocal_read(struct fc0011_priv *priv, u8 *value) 164 { 165 int err; 166 167 err = fc0011_writereg(priv, FC11_REG_VCOCAL, FC11_VCOCAL_RUN); 168 if (err) 169 return err; 170 usleep_range(10000, 20000); 171 err = fc0011_readreg(priv, FC11_REG_VCOCAL, value); 172 if (err) 173 return err; 174 175 return 0; 176 } 177 178 static int fc0011_set_params(struct dvb_frontend *fe) 179 { 180 struct dtv_frontend_properties *p = &fe->dtv_property_cache; 181 struct fc0011_priv *priv = fe->tuner_priv; 182 int err; 183 unsigned int i, vco_retries; 184 u32 freq = p->frequency / 1000; 185 u32 bandwidth = p->bandwidth_hz / 1000; 186 u32 fvco, xin, xdiv, xdivr; 187 u16 frac; 188 u8 fa, fp, vco_sel, vco_cal; 189 u8 regs[FC11_NR_REGS] = { }; 190 191 regs[FC11_REG_7] = 0x0F; 192 regs[FC11_REG_8] = 0x3E; 193 regs[FC11_REG_10] = 0xB8; 194 regs[FC11_REG_11] = 0x80; 195 regs[FC11_REG_RCCAL] = 0x04; 196 err = fc0011_writereg(priv, FC11_REG_7, regs[FC11_REG_7]); 197 err |= fc0011_writereg(priv, FC11_REG_8, regs[FC11_REG_8]); 198 err |= fc0011_writereg(priv, FC11_REG_10, regs[FC11_REG_10]); 199 err |= fc0011_writereg(priv, FC11_REG_11, regs[FC11_REG_11]); 200 err |= fc0011_writereg(priv, FC11_REG_RCCAL, regs[FC11_REG_RCCAL]); 201 if (err) 202 return -EIO; 203 204 /* Set VCO freq and VCO div */ 205 if (freq < 54000) { 206 fvco = freq * 64; 207 regs[FC11_REG_VCO] = 0x82; 208 } else if (freq < 108000) { 209 fvco = freq * 32; 210 regs[FC11_REG_VCO] = 0x42; 211 } else if (freq < 216000) { 212 fvco = freq * 16; 213 regs[FC11_REG_VCO] = 0x22; 214 } else if (freq < 432000) { 215 fvco = freq * 8; 216 regs[FC11_REG_VCO] = 0x12; 217 } else { 218 fvco = freq * 4; 219 regs[FC11_REG_VCO] = 0x0A; 220 } 221 222 /* Calc XIN. The PLL reference frequency is 18 MHz. */ 223 xdiv = fvco / 18000; 224 frac = fvco - xdiv * 18000; 225 frac = (frac << 15) / 18000; 226 if (frac >= 16384) 227 frac += 32786; 228 if (!frac) 229 xin = 0; 230 else if (frac < 511) 231 xin = 512; 232 else if (frac < 65026) 233 xin = frac; 234 else 235 xin = 65024; 236 regs[FC11_REG_XINHI] = xin >> 8; 237 regs[FC11_REG_XINLO] = xin; 238 239 /* Calc FP and FA */ 240 xdivr = xdiv; 241 if (fvco - xdiv * 18000 >= 9000) 242 xdivr += 1; /* round */ 243 fp = xdivr / 8; 244 fa = xdivr - fp * 8; 245 if (fa < 2) { 246 fp -= 1; 247 fa += 8; 248 } 249 if (fp > 0x1F) { 250 fp &= 0x1F; 251 fa &= 0xF; 252 } 253 if (fa >= fp) { 254 dev_warn(&priv->i2c->dev, 255 "fa %02X >= fp %02X, but trying to continue\n", 256 (unsigned int)(u8)fa, (unsigned int)(u8)fp); 257 } 258 regs[FC11_REG_FA] = fa; 259 regs[FC11_REG_FP] = fp; 260 261 /* Select bandwidth */ 262 switch (bandwidth) { 263 case 8000: 264 break; 265 case 7000: 266 regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_BW7M; 267 break; 268 default: 269 dev_warn(&priv->i2c->dev, "Unsupported bandwidth %u kHz. " 270 "Using 6000 kHz.\n", 271 bandwidth); 272 bandwidth = 6000; 273 /* fallthrough */ 274 case 6000: 275 regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_BW6M; 276 break; 277 } 278 279 /* Pre VCO select */ 280 if (fvco < 2320000) { 281 vco_sel = 0; 282 regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); 283 } else if (fvco < 3080000) { 284 vco_sel = 1; 285 regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); 286 regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1; 287 } else { 288 vco_sel = 2; 289 regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); 290 regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_2; 291 } 292 293 /* Fix for low freqs */ 294 if (freq < 45000) { 295 regs[FC11_REG_FA] = 0x6; 296 regs[FC11_REG_FP] = 0x11; 297 } 298 299 /* Clock out fix */ 300 regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_CLKOUT; 301 302 /* Write the cached registers */ 303 for (i = FC11_REG_FA; i <= FC11_REG_VCOSEL; i++) { 304 err = fc0011_writereg(priv, i, regs[i]); 305 if (err) 306 return err; 307 } 308 309 /* VCO calibration */ 310 err = fc0011_vcocal_trigger(priv); 311 if (err) 312 return err; 313 err = fc0011_vcocal_read(priv, &vco_cal); 314 if (err) 315 return err; 316 vco_retries = 0; 317 while (!(vco_cal & FC11_VCOCAL_OK) && vco_retries < 3) { 318 /* Reset the tuner and try again */ 319 err = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER, 320 FC0011_FE_CALLBACK_RESET, priv->addr); 321 if (err) { 322 dev_err(&priv->i2c->dev, "Failed to reset tuner\n"); 323 return err; 324 } 325 /* Reinit tuner config */ 326 err = 0; 327 for (i = FC11_REG_FA; i <= FC11_REG_VCOSEL; i++) 328 err |= fc0011_writereg(priv, i, regs[i]); 329 err |= fc0011_writereg(priv, FC11_REG_7, regs[FC11_REG_7]); 330 err |= fc0011_writereg(priv, FC11_REG_8, regs[FC11_REG_8]); 331 err |= fc0011_writereg(priv, FC11_REG_10, regs[FC11_REG_10]); 332 err |= fc0011_writereg(priv, FC11_REG_11, regs[FC11_REG_11]); 333 err |= fc0011_writereg(priv, FC11_REG_RCCAL, regs[FC11_REG_RCCAL]); 334 if (err) 335 return -EIO; 336 /* VCO calibration */ 337 err = fc0011_vcocal_trigger(priv); 338 if (err) 339 return err; 340 err = fc0011_vcocal_read(priv, &vco_cal); 341 if (err) 342 return err; 343 vco_retries++; 344 } 345 if (!(vco_cal & FC11_VCOCAL_OK)) { 346 dev_err(&priv->i2c->dev, 347 "Failed to read VCO calibration value (got %02X)\n", 348 (unsigned int)vco_cal); 349 return -EIO; 350 } 351 vco_cal &= FC11_VCOCAL_VALUEMASK; 352 353 switch (vco_sel) { 354 case 0: 355 if (vco_cal < 8) { 356 regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); 357 regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1; 358 err = fc0011_writereg(priv, FC11_REG_VCOSEL, 359 regs[FC11_REG_VCOSEL]); 360 if (err) 361 return err; 362 err = fc0011_vcocal_trigger(priv); 363 if (err) 364 return err; 365 } else { 366 regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); 367 err = fc0011_writereg(priv, FC11_REG_VCOSEL, 368 regs[FC11_REG_VCOSEL]); 369 if (err) 370 return err; 371 } 372 break; 373 case 1: 374 if (vco_cal < 5) { 375 regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); 376 regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_2; 377 err = fc0011_writereg(priv, FC11_REG_VCOSEL, 378 regs[FC11_REG_VCOSEL]); 379 if (err) 380 return err; 381 err = fc0011_vcocal_trigger(priv); 382 if (err) 383 return err; 384 } else if (vco_cal <= 48) { 385 regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); 386 regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1; 387 err = fc0011_writereg(priv, FC11_REG_VCOSEL, 388 regs[FC11_REG_VCOSEL]); 389 if (err) 390 return err; 391 } else { 392 regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); 393 err = fc0011_writereg(priv, FC11_REG_VCOSEL, 394 regs[FC11_REG_VCOSEL]); 395 if (err) 396 return err; 397 err = fc0011_vcocal_trigger(priv); 398 if (err) 399 return err; 400 } 401 break; 402 case 2: 403 if (vco_cal > 53) { 404 regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); 405 regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1; 406 err = fc0011_writereg(priv, FC11_REG_VCOSEL, 407 regs[FC11_REG_VCOSEL]); 408 if (err) 409 return err; 410 err = fc0011_vcocal_trigger(priv); 411 if (err) 412 return err; 413 } else { 414 regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); 415 regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_2; 416 err = fc0011_writereg(priv, FC11_REG_VCOSEL, 417 regs[FC11_REG_VCOSEL]); 418 if (err) 419 return err; 420 } 421 break; 422 } 423 err = fc0011_vcocal_read(priv, NULL); 424 if (err) 425 return err; 426 usleep_range(10000, 50000); 427 428 err = fc0011_readreg(priv, FC11_REG_RCCAL, ®s[FC11_REG_RCCAL]); 429 if (err) 430 return err; 431 regs[FC11_REG_RCCAL] |= FC11_RCCAL_FORCE; 432 err = fc0011_writereg(priv, FC11_REG_RCCAL, regs[FC11_REG_RCCAL]); 433 if (err) 434 return err; 435 err = fc0011_writereg(priv, FC11_REG_16, 0xB); 436 if (err) 437 return err; 438 439 dev_dbg(&priv->i2c->dev, "Tuned to " 440 "fa=%02X fp=%02X xin=%02X%02X vco=%02X vcosel=%02X " 441 "vcocal=%02X(%u) bw=%u\n", 442 (unsigned int)regs[FC11_REG_FA], 443 (unsigned int)regs[FC11_REG_FP], 444 (unsigned int)regs[FC11_REG_XINHI], 445 (unsigned int)regs[FC11_REG_XINLO], 446 (unsigned int)regs[FC11_REG_VCO], 447 (unsigned int)regs[FC11_REG_VCOSEL], 448 (unsigned int)vco_cal, vco_retries, 449 (unsigned int)bandwidth); 450 451 priv->frequency = p->frequency; 452 priv->bandwidth = p->bandwidth_hz; 453 454 return 0; 455 } 456 457 static int fc0011_get_frequency(struct dvb_frontend *fe, u32 *frequency) 458 { 459 struct fc0011_priv *priv = fe->tuner_priv; 460 461 *frequency = priv->frequency; 462 463 return 0; 464 } 465 466 static int fc0011_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) 467 { 468 *frequency = 0; 469 470 return 0; 471 } 472 473 static int fc0011_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) 474 { 475 struct fc0011_priv *priv = fe->tuner_priv; 476 477 *bandwidth = priv->bandwidth; 478 479 return 0; 480 } 481 482 static const struct dvb_tuner_ops fc0011_tuner_ops = { 483 .info = { 484 .name = "Fitipower FC0011", 485 486 .frequency_min = 45000000, 487 .frequency_max = 1000000000, 488 }, 489 490 .release = fc0011_release, 491 .init = fc0011_init, 492 493 .set_params = fc0011_set_params, 494 495 .get_frequency = fc0011_get_frequency, 496 .get_if_frequency = fc0011_get_if_frequency, 497 .get_bandwidth = fc0011_get_bandwidth, 498 }; 499 500 struct dvb_frontend *fc0011_attach(struct dvb_frontend *fe, 501 struct i2c_adapter *i2c, 502 const struct fc0011_config *config) 503 { 504 struct fc0011_priv *priv; 505 506 priv = kzalloc(sizeof(struct fc0011_priv), GFP_KERNEL); 507 if (!priv) 508 return NULL; 509 510 priv->i2c = i2c; 511 priv->addr = config->i2c_address; 512 513 fe->tuner_priv = priv; 514 fe->ops.tuner_ops = fc0011_tuner_ops; 515 516 dev_info(&priv->i2c->dev, "Fitipower FC0011 tuner attached\n"); 517 518 return fe; 519 } 520 EXPORT_SYMBOL(fc0011_attach); 521 522 MODULE_DESCRIPTION("Fitipower FC0011 silicon tuner driver"); 523 MODULE_AUTHOR("Michael Buesch <m@bues.ch>"); 524 MODULE_LICENSE("GPL"); 525