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