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 void fc0011_release(struct dvb_frontend *fe) 116 { 117 kfree(fe->tuner_priv); 118 fe->tuner_priv = NULL; 119 } 120 121 static int fc0011_init(struct dvb_frontend *fe) 122 { 123 struct fc0011_priv *priv = fe->tuner_priv; 124 int err; 125 126 if (WARN_ON(!fe->callback)) 127 return -EINVAL; 128 129 err = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER, 130 FC0011_FE_CALLBACK_POWER, priv->addr); 131 if (err) { 132 dev_err(&priv->i2c->dev, "Power-on callback failed\n"); 133 return err; 134 } 135 err = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER, 136 FC0011_FE_CALLBACK_RESET, priv->addr); 137 if (err) { 138 dev_err(&priv->i2c->dev, "Reset callback failed\n"); 139 return err; 140 } 141 142 return 0; 143 } 144 145 /* Initiate VCO calibration */ 146 static int fc0011_vcocal_trigger(struct fc0011_priv *priv) 147 { 148 int err; 149 150 err = fc0011_writereg(priv, FC11_REG_VCOCAL, FC11_VCOCAL_RESET); 151 if (err) 152 return err; 153 err = fc0011_writereg(priv, FC11_REG_VCOCAL, FC11_VCOCAL_RUN); 154 if (err) 155 return err; 156 157 return 0; 158 } 159 160 /* Read VCO calibration value */ 161 static int fc0011_vcocal_read(struct fc0011_priv *priv, u8 *value) 162 { 163 int err; 164 165 err = fc0011_writereg(priv, FC11_REG_VCOCAL, FC11_VCOCAL_RUN); 166 if (err) 167 return err; 168 usleep_range(10000, 20000); 169 err = fc0011_readreg(priv, FC11_REG_VCOCAL, value); 170 if (err) 171 return err; 172 173 return 0; 174 } 175 176 static int fc0011_set_params(struct dvb_frontend *fe) 177 { 178 struct dtv_frontend_properties *p = &fe->dtv_property_cache; 179 struct fc0011_priv *priv = fe->tuner_priv; 180 int err; 181 unsigned int i, vco_retries; 182 u32 freq = p->frequency / 1000; 183 u32 bandwidth = p->bandwidth_hz / 1000; 184 u32 fvco, xin, frac, xdiv, xdivr; 185 u8 fa, fp, vco_sel, vco_cal; 186 u8 regs[FC11_NR_REGS] = { }; 187 188 regs[FC11_REG_7] = 0x0F; 189 regs[FC11_REG_8] = 0x3E; 190 regs[FC11_REG_10] = 0xB8; 191 regs[FC11_REG_11] = 0x80; 192 regs[FC11_REG_RCCAL] = 0x04; 193 err = fc0011_writereg(priv, FC11_REG_7, regs[FC11_REG_7]); 194 err |= fc0011_writereg(priv, FC11_REG_8, regs[FC11_REG_8]); 195 err |= fc0011_writereg(priv, FC11_REG_10, regs[FC11_REG_10]); 196 err |= fc0011_writereg(priv, FC11_REG_11, regs[FC11_REG_11]); 197 err |= fc0011_writereg(priv, FC11_REG_RCCAL, regs[FC11_REG_RCCAL]); 198 if (err) 199 return -EIO; 200 201 /* Set VCO freq and VCO div */ 202 if (freq < 54000) { 203 fvco = freq * 64; 204 regs[FC11_REG_VCO] = 0x82; 205 } else if (freq < 108000) { 206 fvco = freq * 32; 207 regs[FC11_REG_VCO] = 0x42; 208 } else if (freq < 216000) { 209 fvco = freq * 16; 210 regs[FC11_REG_VCO] = 0x22; 211 } else if (freq < 432000) { 212 fvco = freq * 8; 213 regs[FC11_REG_VCO] = 0x12; 214 } else { 215 fvco = freq * 4; 216 regs[FC11_REG_VCO] = 0x0A; 217 } 218 219 /* Calc XIN. The PLL reference frequency is 18 MHz. */ 220 xdiv = fvco / 18000; 221 WARN_ON(xdiv > 0xFF); 222 frac = fvco - xdiv * 18000; 223 frac = (frac << 15) / 18000; 224 if (frac >= 16384) 225 frac += 32786; 226 if (!frac) 227 xin = 0; 228 else 229 xin = clamp_t(u32, frac, 512, 65024); 230 regs[FC11_REG_XINHI] = xin >> 8; 231 regs[FC11_REG_XINLO] = xin; 232 233 /* Calc FP and FA */ 234 xdivr = xdiv; 235 if (fvco - xdiv * 18000 >= 9000) 236 xdivr += 1; /* round */ 237 fp = xdivr / 8; 238 fa = xdivr - fp * 8; 239 if (fa < 2) { 240 fp -= 1; 241 fa += 8; 242 } 243 if (fp > 0x1F) { 244 fp = 0x1F; 245 fa = 0xF; 246 } 247 if (fa >= fp) { 248 dev_warn(&priv->i2c->dev, 249 "fa %02X >= fp %02X, but trying to continue\n", 250 (unsigned int)(u8)fa, (unsigned int)(u8)fp); 251 } 252 regs[FC11_REG_FA] = fa; 253 regs[FC11_REG_FP] = fp; 254 255 /* Select bandwidth */ 256 switch (bandwidth) { 257 case 8000: 258 break; 259 case 7000: 260 regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_BW7M; 261 break; 262 default: 263 dev_warn(&priv->i2c->dev, "Unsupported bandwidth %u kHz. Using 6000 kHz.\n", 264 bandwidth); 265 bandwidth = 6000; 266 /* fallthrough */ 267 case 6000: 268 regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_BW6M; 269 break; 270 } 271 272 /* Pre VCO select */ 273 if (fvco < 2320000) { 274 vco_sel = 0; 275 regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); 276 } else if (fvco < 3080000) { 277 vco_sel = 1; 278 regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); 279 regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1; 280 } else { 281 vco_sel = 2; 282 regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); 283 regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_2; 284 } 285 286 /* Fix for low freqs */ 287 if (freq < 45000) { 288 regs[FC11_REG_FA] = 0x6; 289 regs[FC11_REG_FP] = 0x11; 290 } 291 292 /* Clock out fix */ 293 regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_CLKOUT; 294 295 /* Write the cached registers */ 296 for (i = FC11_REG_FA; i <= FC11_REG_VCOSEL; i++) { 297 err = fc0011_writereg(priv, i, regs[i]); 298 if (err) 299 return err; 300 } 301 302 /* VCO calibration */ 303 err = fc0011_vcocal_trigger(priv); 304 if (err) 305 return err; 306 err = fc0011_vcocal_read(priv, &vco_cal); 307 if (err) 308 return err; 309 vco_retries = 0; 310 while (!(vco_cal & FC11_VCOCAL_OK) && vco_retries < 3) { 311 /* Reset the tuner and try again */ 312 err = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER, 313 FC0011_FE_CALLBACK_RESET, priv->addr); 314 if (err) { 315 dev_err(&priv->i2c->dev, "Failed to reset tuner\n"); 316 return err; 317 } 318 /* Reinit tuner config */ 319 err = 0; 320 for (i = FC11_REG_FA; i <= FC11_REG_VCOSEL; i++) 321 err |= fc0011_writereg(priv, i, regs[i]); 322 err |= fc0011_writereg(priv, FC11_REG_7, regs[FC11_REG_7]); 323 err |= fc0011_writereg(priv, FC11_REG_8, regs[FC11_REG_8]); 324 err |= fc0011_writereg(priv, FC11_REG_10, regs[FC11_REG_10]); 325 err |= fc0011_writereg(priv, FC11_REG_11, regs[FC11_REG_11]); 326 err |= fc0011_writereg(priv, FC11_REG_RCCAL, regs[FC11_REG_RCCAL]); 327 if (err) 328 return -EIO; 329 /* VCO calibration */ 330 err = fc0011_vcocal_trigger(priv); 331 if (err) 332 return err; 333 err = fc0011_vcocal_read(priv, &vco_cal); 334 if (err) 335 return err; 336 vco_retries++; 337 } 338 if (!(vco_cal & FC11_VCOCAL_OK)) { 339 dev_err(&priv->i2c->dev, 340 "Failed to read VCO calibration value (got %02X)\n", 341 (unsigned int)vco_cal); 342 return -EIO; 343 } 344 vco_cal &= FC11_VCOCAL_VALUEMASK; 345 346 switch (vco_sel) { 347 default: 348 WARN_ON(1); 349 case 0: 350 if (vco_cal < 8) { 351 regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); 352 regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1; 353 err = fc0011_writereg(priv, FC11_REG_VCOSEL, 354 regs[FC11_REG_VCOSEL]); 355 if (err) 356 return err; 357 err = fc0011_vcocal_trigger(priv); 358 if (err) 359 return err; 360 } else { 361 regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); 362 err = fc0011_writereg(priv, FC11_REG_VCOSEL, 363 regs[FC11_REG_VCOSEL]); 364 if (err) 365 return err; 366 } 367 break; 368 case 1: 369 if (vco_cal < 5) { 370 regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); 371 regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_2; 372 err = fc0011_writereg(priv, FC11_REG_VCOSEL, 373 regs[FC11_REG_VCOSEL]); 374 if (err) 375 return err; 376 err = fc0011_vcocal_trigger(priv); 377 if (err) 378 return err; 379 } else if (vco_cal <= 48) { 380 regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); 381 regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1; 382 err = fc0011_writereg(priv, FC11_REG_VCOSEL, 383 regs[FC11_REG_VCOSEL]); 384 if (err) 385 return err; 386 } else { 387 regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); 388 err = fc0011_writereg(priv, FC11_REG_VCOSEL, 389 regs[FC11_REG_VCOSEL]); 390 if (err) 391 return err; 392 err = fc0011_vcocal_trigger(priv); 393 if (err) 394 return err; 395 } 396 break; 397 case 2: 398 if (vco_cal > 53) { 399 regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); 400 regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1; 401 err = fc0011_writereg(priv, FC11_REG_VCOSEL, 402 regs[FC11_REG_VCOSEL]); 403 if (err) 404 return err; 405 err = fc0011_vcocal_trigger(priv); 406 if (err) 407 return err; 408 } else { 409 regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); 410 regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_2; 411 err = fc0011_writereg(priv, FC11_REG_VCOSEL, 412 regs[FC11_REG_VCOSEL]); 413 if (err) 414 return err; 415 } 416 break; 417 } 418 err = fc0011_vcocal_read(priv, NULL); 419 if (err) 420 return err; 421 usleep_range(10000, 50000); 422 423 err = fc0011_readreg(priv, FC11_REG_RCCAL, ®s[FC11_REG_RCCAL]); 424 if (err) 425 return err; 426 regs[FC11_REG_RCCAL] |= FC11_RCCAL_FORCE; 427 err = fc0011_writereg(priv, FC11_REG_RCCAL, regs[FC11_REG_RCCAL]); 428 if (err) 429 return err; 430 regs[FC11_REG_16] = 0xB; 431 err = fc0011_writereg(priv, FC11_REG_16, regs[FC11_REG_16]); 432 if (err) 433 return err; 434 435 dev_dbg(&priv->i2c->dev, "Tuned to fa=%02X fp=%02X xin=%02X%02X vco=%02X vcosel=%02X vcocal=%02X(%u) bw=%u\n", 436 (unsigned int)regs[FC11_REG_FA], 437 (unsigned int)regs[FC11_REG_FP], 438 (unsigned int)regs[FC11_REG_XINHI], 439 (unsigned int)regs[FC11_REG_XINLO], 440 (unsigned int)regs[FC11_REG_VCO], 441 (unsigned int)regs[FC11_REG_VCOSEL], 442 (unsigned int)vco_cal, vco_retries, 443 (unsigned int)bandwidth); 444 445 priv->frequency = p->frequency; 446 priv->bandwidth = p->bandwidth_hz; 447 448 return 0; 449 } 450 451 static int fc0011_get_frequency(struct dvb_frontend *fe, u32 *frequency) 452 { 453 struct fc0011_priv *priv = fe->tuner_priv; 454 455 *frequency = priv->frequency; 456 457 return 0; 458 } 459 460 static int fc0011_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) 461 { 462 *frequency = 0; 463 464 return 0; 465 } 466 467 static int fc0011_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) 468 { 469 struct fc0011_priv *priv = fe->tuner_priv; 470 471 *bandwidth = priv->bandwidth; 472 473 return 0; 474 } 475 476 static const struct dvb_tuner_ops fc0011_tuner_ops = { 477 .info = { 478 .name = "Fitipower FC0011", 479 480 .frequency_min = 45000000, 481 .frequency_max = 1000000000, 482 }, 483 484 .release = fc0011_release, 485 .init = fc0011_init, 486 487 .set_params = fc0011_set_params, 488 489 .get_frequency = fc0011_get_frequency, 490 .get_if_frequency = fc0011_get_if_frequency, 491 .get_bandwidth = fc0011_get_bandwidth, 492 }; 493 494 struct dvb_frontend *fc0011_attach(struct dvb_frontend *fe, 495 struct i2c_adapter *i2c, 496 const struct fc0011_config *config) 497 { 498 struct fc0011_priv *priv; 499 500 priv = kzalloc(sizeof(struct fc0011_priv), GFP_KERNEL); 501 if (!priv) 502 return NULL; 503 504 priv->i2c = i2c; 505 priv->addr = config->i2c_address; 506 507 fe->tuner_priv = priv; 508 fe->ops.tuner_ops = fc0011_tuner_ops; 509 510 dev_info(&priv->i2c->dev, "Fitipower FC0011 tuner attached\n"); 511 512 return fe; 513 } 514 EXPORT_SYMBOL(fc0011_attach); 515 516 MODULE_DESCRIPTION("Fitipower FC0011 silicon tuner driver"); 517 MODULE_AUTHOR("Michael Buesch <m@bues.ch>"); 518 MODULE_LICENSE("GPL"); 519