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