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 return -EINVAL; 346 case 0: 347 if (vco_cal < 8) { 348 regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); 349 regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1; 350 err = fc0011_writereg(priv, FC11_REG_VCOSEL, 351 regs[FC11_REG_VCOSEL]); 352 if (err) 353 return err; 354 err = fc0011_vcocal_trigger(priv); 355 if (err) 356 return err; 357 } else { 358 regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); 359 err = fc0011_writereg(priv, FC11_REG_VCOSEL, 360 regs[FC11_REG_VCOSEL]); 361 if (err) 362 return err; 363 } 364 break; 365 case 1: 366 if (vco_cal < 5) { 367 regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); 368 regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_2; 369 err = fc0011_writereg(priv, FC11_REG_VCOSEL, 370 regs[FC11_REG_VCOSEL]); 371 if (err) 372 return err; 373 err = fc0011_vcocal_trigger(priv); 374 if (err) 375 return err; 376 } else if (vco_cal <= 48) { 377 regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); 378 regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1; 379 err = fc0011_writereg(priv, FC11_REG_VCOSEL, 380 regs[FC11_REG_VCOSEL]); 381 if (err) 382 return err; 383 } else { 384 regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); 385 err = fc0011_writereg(priv, FC11_REG_VCOSEL, 386 regs[FC11_REG_VCOSEL]); 387 if (err) 388 return err; 389 err = fc0011_vcocal_trigger(priv); 390 if (err) 391 return err; 392 } 393 break; 394 case 2: 395 if (vco_cal > 53) { 396 regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); 397 regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1; 398 err = fc0011_writereg(priv, FC11_REG_VCOSEL, 399 regs[FC11_REG_VCOSEL]); 400 if (err) 401 return err; 402 err = fc0011_vcocal_trigger(priv); 403 if (err) 404 return err; 405 } else { 406 regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); 407 regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_2; 408 err = fc0011_writereg(priv, FC11_REG_VCOSEL, 409 regs[FC11_REG_VCOSEL]); 410 if (err) 411 return err; 412 } 413 break; 414 } 415 err = fc0011_vcocal_read(priv, NULL); 416 if (err) 417 return err; 418 usleep_range(10000, 50000); 419 420 err = fc0011_readreg(priv, FC11_REG_RCCAL, ®s[FC11_REG_RCCAL]); 421 if (err) 422 return err; 423 regs[FC11_REG_RCCAL] |= FC11_RCCAL_FORCE; 424 err = fc0011_writereg(priv, FC11_REG_RCCAL, regs[FC11_REG_RCCAL]); 425 if (err) 426 return err; 427 regs[FC11_REG_16] = 0xB; 428 err = fc0011_writereg(priv, FC11_REG_16, regs[FC11_REG_16]); 429 if (err) 430 return err; 431 432 dev_dbg(&priv->i2c->dev, "Tuned to fa=%02X fp=%02X xin=%02X%02X vco=%02X vcosel=%02X vcocal=%02X(%u) bw=%u\n", 433 (unsigned int)regs[FC11_REG_FA], 434 (unsigned int)regs[FC11_REG_FP], 435 (unsigned int)regs[FC11_REG_XINHI], 436 (unsigned int)regs[FC11_REG_XINLO], 437 (unsigned int)regs[FC11_REG_VCO], 438 (unsigned int)regs[FC11_REG_VCOSEL], 439 (unsigned int)vco_cal, vco_retries, 440 (unsigned int)bandwidth); 441 442 priv->frequency = p->frequency; 443 priv->bandwidth = p->bandwidth_hz; 444 445 return 0; 446 } 447 448 static int fc0011_get_frequency(struct dvb_frontend *fe, u32 *frequency) 449 { 450 struct fc0011_priv *priv = fe->tuner_priv; 451 452 *frequency = priv->frequency; 453 454 return 0; 455 } 456 457 static int fc0011_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) 458 { 459 *frequency = 0; 460 461 return 0; 462 } 463 464 static int fc0011_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) 465 { 466 struct fc0011_priv *priv = fe->tuner_priv; 467 468 *bandwidth = priv->bandwidth; 469 470 return 0; 471 } 472 473 static const struct dvb_tuner_ops fc0011_tuner_ops = { 474 .info = { 475 .name = "Fitipower FC0011", 476 477 .frequency_min_hz = 45 * MHz, 478 .frequency_max_hz = 1000 * MHz, 479 }, 480 481 .release = fc0011_release, 482 .init = fc0011_init, 483 484 .set_params = fc0011_set_params, 485 486 .get_frequency = fc0011_get_frequency, 487 .get_if_frequency = fc0011_get_if_frequency, 488 .get_bandwidth = fc0011_get_bandwidth, 489 }; 490 491 struct dvb_frontend *fc0011_attach(struct dvb_frontend *fe, 492 struct i2c_adapter *i2c, 493 const struct fc0011_config *config) 494 { 495 struct fc0011_priv *priv; 496 497 priv = kzalloc(sizeof(struct fc0011_priv), GFP_KERNEL); 498 if (!priv) 499 return NULL; 500 501 priv->i2c = i2c; 502 priv->addr = config->i2c_address; 503 504 fe->tuner_priv = priv; 505 fe->ops.tuner_ops = fc0011_tuner_ops; 506 507 dev_info(&priv->i2c->dev, "Fitipower FC0011 tuner attached\n"); 508 509 return fe; 510 } 511 EXPORT_SYMBOL(fc0011_attach); 512 513 MODULE_DESCRIPTION("Fitipower FC0011 silicon tuner driver"); 514 MODULE_AUTHOR("Michael Buesch <m@bues.ch>"); 515 MODULE_LICENSE("GPL"); 516