0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include "fc0011.h"
0012
0013
0014
0015 enum {
0016 FC11_REG_0,
0017 FC11_REG_FA,
0018 FC11_REG_FP,
0019 FC11_REG_XINHI,
0020 FC11_REG_XINLO,
0021 FC11_REG_VCO,
0022 FC11_REG_VCOSEL,
0023 FC11_REG_7,
0024 FC11_REG_8,
0025 FC11_REG_9,
0026 FC11_REG_10,
0027 FC11_REG_11,
0028 FC11_REG_12,
0029 FC11_REG_RCCAL,
0030 FC11_REG_VCOCAL,
0031 FC11_REG_15,
0032 FC11_REG_16,
0033 FC11_REG_17,
0034
0035 FC11_NR_REGS,
0036 };
0037
0038 enum FC11_REG_VCOSEL_bits {
0039 FC11_VCOSEL_2 = 0x08,
0040 FC11_VCOSEL_1 = 0x10,
0041 FC11_VCOSEL_CLKOUT = 0x20,
0042 FC11_VCOSEL_BW7M = 0x40,
0043 FC11_VCOSEL_BW6M = 0x80,
0044 };
0045
0046 enum FC11_REG_RCCAL_bits {
0047 FC11_RCCAL_FORCE = 0x10,
0048 };
0049
0050 enum FC11_REG_VCOCAL_bits {
0051 FC11_VCOCAL_RUN = 0,
0052 FC11_VCOCAL_VALUEMASK = 0x3F,
0053 FC11_VCOCAL_OK = 0x40,
0054 FC11_VCOCAL_RESET = 0x80,
0055 };
0056
0057
0058 struct fc0011_priv {
0059 struct i2c_adapter *i2c;
0060 u8 addr;
0061
0062 u32 frequency;
0063 u32 bandwidth;
0064 };
0065
0066
0067 static int fc0011_writereg(struct fc0011_priv *priv, u8 reg, u8 val)
0068 {
0069 u8 buf[2] = { reg, val };
0070 struct i2c_msg msg = { .addr = priv->addr,
0071 .flags = 0, .buf = buf, .len = 2 };
0072
0073 if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
0074 dev_err(&priv->i2c->dev,
0075 "I2C write reg failed, reg: %02x, val: %02x\n",
0076 reg, val);
0077 return -EIO;
0078 }
0079
0080 return 0;
0081 }
0082
0083 static int fc0011_readreg(struct fc0011_priv *priv, u8 reg, u8 *val)
0084 {
0085 u8 dummy;
0086 struct i2c_msg msg[2] = {
0087 { .addr = priv->addr,
0088 .flags = 0, .buf = ®, .len = 1 },
0089 { .addr = priv->addr,
0090 .flags = I2C_M_RD, .buf = val ? : &dummy, .len = 1 },
0091 };
0092
0093 if (i2c_transfer(priv->i2c, msg, 2) != 2) {
0094 dev_err(&priv->i2c->dev,
0095 "I2C read failed, reg: %02x\n", reg);
0096 return -EIO;
0097 }
0098
0099 return 0;
0100 }
0101
0102 static void fc0011_release(struct dvb_frontend *fe)
0103 {
0104 kfree(fe->tuner_priv);
0105 fe->tuner_priv = NULL;
0106 }
0107
0108 static int fc0011_init(struct dvb_frontend *fe)
0109 {
0110 struct fc0011_priv *priv = fe->tuner_priv;
0111 int err;
0112
0113 if (WARN_ON(!fe->callback))
0114 return -EINVAL;
0115
0116 err = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER,
0117 FC0011_FE_CALLBACK_POWER, priv->addr);
0118 if (err) {
0119 dev_err(&priv->i2c->dev, "Power-on callback failed\n");
0120 return err;
0121 }
0122 err = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER,
0123 FC0011_FE_CALLBACK_RESET, priv->addr);
0124 if (err) {
0125 dev_err(&priv->i2c->dev, "Reset callback failed\n");
0126 return err;
0127 }
0128
0129 return 0;
0130 }
0131
0132
0133 static int fc0011_vcocal_trigger(struct fc0011_priv *priv)
0134 {
0135 int err;
0136
0137 err = fc0011_writereg(priv, FC11_REG_VCOCAL, FC11_VCOCAL_RESET);
0138 if (err)
0139 return err;
0140 err = fc0011_writereg(priv, FC11_REG_VCOCAL, FC11_VCOCAL_RUN);
0141 if (err)
0142 return err;
0143
0144 return 0;
0145 }
0146
0147
0148 static int fc0011_vcocal_read(struct fc0011_priv *priv, u8 *value)
0149 {
0150 int err;
0151
0152 err = fc0011_writereg(priv, FC11_REG_VCOCAL, FC11_VCOCAL_RUN);
0153 if (err)
0154 return err;
0155 usleep_range(10000, 20000);
0156 err = fc0011_readreg(priv, FC11_REG_VCOCAL, value);
0157 if (err)
0158 return err;
0159
0160 return 0;
0161 }
0162
0163 static int fc0011_set_params(struct dvb_frontend *fe)
0164 {
0165 struct dtv_frontend_properties *p = &fe->dtv_property_cache;
0166 struct fc0011_priv *priv = fe->tuner_priv;
0167 int err;
0168 unsigned int i, vco_retries;
0169 u32 freq = p->frequency / 1000;
0170 u32 bandwidth = p->bandwidth_hz / 1000;
0171 u32 fvco, xin, frac, xdiv, xdivr;
0172 u8 fa, fp, vco_sel, vco_cal;
0173 u8 regs[FC11_NR_REGS] = { };
0174
0175 regs[FC11_REG_7] = 0x0F;
0176 regs[FC11_REG_8] = 0x3E;
0177 regs[FC11_REG_10] = 0xB8;
0178 regs[FC11_REG_11] = 0x80;
0179 regs[FC11_REG_RCCAL] = 0x04;
0180 err = fc0011_writereg(priv, FC11_REG_7, regs[FC11_REG_7]);
0181 err |= fc0011_writereg(priv, FC11_REG_8, regs[FC11_REG_8]);
0182 err |= fc0011_writereg(priv, FC11_REG_10, regs[FC11_REG_10]);
0183 err |= fc0011_writereg(priv, FC11_REG_11, regs[FC11_REG_11]);
0184 err |= fc0011_writereg(priv, FC11_REG_RCCAL, regs[FC11_REG_RCCAL]);
0185 if (err)
0186 return -EIO;
0187
0188
0189 if (freq < 54000) {
0190 fvco = freq * 64;
0191 regs[FC11_REG_VCO] = 0x82;
0192 } else if (freq < 108000) {
0193 fvco = freq * 32;
0194 regs[FC11_REG_VCO] = 0x42;
0195 } else if (freq < 216000) {
0196 fvco = freq * 16;
0197 regs[FC11_REG_VCO] = 0x22;
0198 } else if (freq < 432000) {
0199 fvco = freq * 8;
0200 regs[FC11_REG_VCO] = 0x12;
0201 } else {
0202 fvco = freq * 4;
0203 regs[FC11_REG_VCO] = 0x0A;
0204 }
0205
0206
0207 xdiv = fvco / 18000;
0208 WARN_ON(xdiv > 0xFF);
0209 frac = fvco - xdiv * 18000;
0210 frac = (frac << 15) / 18000;
0211 if (frac >= 16384)
0212 frac += 32786;
0213 if (!frac)
0214 xin = 0;
0215 else
0216 xin = clamp_t(u32, frac, 512, 65024);
0217 regs[FC11_REG_XINHI] = xin >> 8;
0218 regs[FC11_REG_XINLO] = xin;
0219
0220
0221 xdivr = xdiv;
0222 if (fvco - xdiv * 18000 >= 9000)
0223 xdivr += 1;
0224 fp = xdivr / 8;
0225 fa = xdivr - fp * 8;
0226 if (fa < 2) {
0227 fp -= 1;
0228 fa += 8;
0229 }
0230 if (fp > 0x1F) {
0231 fp = 0x1F;
0232 fa = 0xF;
0233 }
0234 if (fa >= fp) {
0235 dev_warn(&priv->i2c->dev,
0236 "fa %02X >= fp %02X, but trying to continue\n",
0237 (unsigned int)(u8)fa, (unsigned int)(u8)fp);
0238 }
0239 regs[FC11_REG_FA] = fa;
0240 regs[FC11_REG_FP] = fp;
0241
0242
0243 switch (bandwidth) {
0244 case 8000:
0245 break;
0246 case 7000:
0247 regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_BW7M;
0248 break;
0249 default:
0250 dev_warn(&priv->i2c->dev, "Unsupported bandwidth %u kHz. Using 6000 kHz.\n",
0251 bandwidth);
0252 bandwidth = 6000;
0253 fallthrough;
0254 case 6000:
0255 regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_BW6M;
0256 break;
0257 }
0258
0259
0260 if (fvco < 2320000) {
0261 vco_sel = 0;
0262 regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
0263 } else if (fvco < 3080000) {
0264 vco_sel = 1;
0265 regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
0266 regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1;
0267 } else {
0268 vco_sel = 2;
0269 regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
0270 regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_2;
0271 }
0272
0273
0274 if (freq < 45000) {
0275 regs[FC11_REG_FA] = 0x6;
0276 regs[FC11_REG_FP] = 0x11;
0277 }
0278
0279
0280 regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_CLKOUT;
0281
0282
0283 for (i = FC11_REG_FA; i <= FC11_REG_VCOSEL; i++) {
0284 err = fc0011_writereg(priv, i, regs[i]);
0285 if (err)
0286 return err;
0287 }
0288
0289
0290 err = fc0011_vcocal_trigger(priv);
0291 if (err)
0292 return err;
0293 err = fc0011_vcocal_read(priv, &vco_cal);
0294 if (err)
0295 return err;
0296 vco_retries = 0;
0297 while (!(vco_cal & FC11_VCOCAL_OK) && vco_retries < 3) {
0298
0299 err = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER,
0300 FC0011_FE_CALLBACK_RESET, priv->addr);
0301 if (err) {
0302 dev_err(&priv->i2c->dev, "Failed to reset tuner\n");
0303 return err;
0304 }
0305
0306 err = 0;
0307 for (i = FC11_REG_FA; i <= FC11_REG_VCOSEL; i++)
0308 err |= fc0011_writereg(priv, i, regs[i]);
0309 err |= fc0011_writereg(priv, FC11_REG_7, regs[FC11_REG_7]);
0310 err |= fc0011_writereg(priv, FC11_REG_8, regs[FC11_REG_8]);
0311 err |= fc0011_writereg(priv, FC11_REG_10, regs[FC11_REG_10]);
0312 err |= fc0011_writereg(priv, FC11_REG_11, regs[FC11_REG_11]);
0313 err |= fc0011_writereg(priv, FC11_REG_RCCAL, regs[FC11_REG_RCCAL]);
0314 if (err)
0315 return -EIO;
0316
0317 err = fc0011_vcocal_trigger(priv);
0318 if (err)
0319 return err;
0320 err = fc0011_vcocal_read(priv, &vco_cal);
0321 if (err)
0322 return err;
0323 vco_retries++;
0324 }
0325 if (!(vco_cal & FC11_VCOCAL_OK)) {
0326 dev_err(&priv->i2c->dev,
0327 "Failed to read VCO calibration value (got %02X)\n",
0328 (unsigned int)vco_cal);
0329 return -EIO;
0330 }
0331 vco_cal &= FC11_VCOCAL_VALUEMASK;
0332
0333 switch (vco_sel) {
0334 default:
0335 WARN_ON(1);
0336 return -EINVAL;
0337 case 0:
0338 if (vco_cal < 8) {
0339 regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
0340 regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1;
0341 err = fc0011_writereg(priv, FC11_REG_VCOSEL,
0342 regs[FC11_REG_VCOSEL]);
0343 if (err)
0344 return err;
0345 err = fc0011_vcocal_trigger(priv);
0346 if (err)
0347 return err;
0348 } else {
0349 regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
0350 err = fc0011_writereg(priv, FC11_REG_VCOSEL,
0351 regs[FC11_REG_VCOSEL]);
0352 if (err)
0353 return err;
0354 }
0355 break;
0356 case 1:
0357 if (vco_cal < 5) {
0358 regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
0359 regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_2;
0360 err = fc0011_writereg(priv, FC11_REG_VCOSEL,
0361 regs[FC11_REG_VCOSEL]);
0362 if (err)
0363 return err;
0364 err = fc0011_vcocal_trigger(priv);
0365 if (err)
0366 return err;
0367 } else if (vco_cal <= 48) {
0368 regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
0369 regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1;
0370 err = fc0011_writereg(priv, FC11_REG_VCOSEL,
0371 regs[FC11_REG_VCOSEL]);
0372 if (err)
0373 return err;
0374 } else {
0375 regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
0376 err = fc0011_writereg(priv, FC11_REG_VCOSEL,
0377 regs[FC11_REG_VCOSEL]);
0378 if (err)
0379 return err;
0380 err = fc0011_vcocal_trigger(priv);
0381 if (err)
0382 return err;
0383 }
0384 break;
0385 case 2:
0386 if (vco_cal > 53) {
0387 regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
0388 regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1;
0389 err = fc0011_writereg(priv, FC11_REG_VCOSEL,
0390 regs[FC11_REG_VCOSEL]);
0391 if (err)
0392 return err;
0393 err = fc0011_vcocal_trigger(priv);
0394 if (err)
0395 return err;
0396 } else {
0397 regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
0398 regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_2;
0399 err = fc0011_writereg(priv, FC11_REG_VCOSEL,
0400 regs[FC11_REG_VCOSEL]);
0401 if (err)
0402 return err;
0403 }
0404 break;
0405 }
0406 err = fc0011_vcocal_read(priv, NULL);
0407 if (err)
0408 return err;
0409 usleep_range(10000, 50000);
0410
0411 err = fc0011_readreg(priv, FC11_REG_RCCAL, ®s[FC11_REG_RCCAL]);
0412 if (err)
0413 return err;
0414 regs[FC11_REG_RCCAL] |= FC11_RCCAL_FORCE;
0415 err = fc0011_writereg(priv, FC11_REG_RCCAL, regs[FC11_REG_RCCAL]);
0416 if (err)
0417 return err;
0418 regs[FC11_REG_16] = 0xB;
0419 err = fc0011_writereg(priv, FC11_REG_16, regs[FC11_REG_16]);
0420 if (err)
0421 return err;
0422
0423 dev_dbg(&priv->i2c->dev, "Tuned to fa=%02X fp=%02X xin=%02X%02X vco=%02X vcosel=%02X vcocal=%02X(%u) bw=%u\n",
0424 (unsigned int)regs[FC11_REG_FA],
0425 (unsigned int)regs[FC11_REG_FP],
0426 (unsigned int)regs[FC11_REG_XINHI],
0427 (unsigned int)regs[FC11_REG_XINLO],
0428 (unsigned int)regs[FC11_REG_VCO],
0429 (unsigned int)regs[FC11_REG_VCOSEL],
0430 (unsigned int)vco_cal, vco_retries,
0431 (unsigned int)bandwidth);
0432
0433 priv->frequency = p->frequency;
0434 priv->bandwidth = p->bandwidth_hz;
0435
0436 return 0;
0437 }
0438
0439 static int fc0011_get_frequency(struct dvb_frontend *fe, u32 *frequency)
0440 {
0441 struct fc0011_priv *priv = fe->tuner_priv;
0442
0443 *frequency = priv->frequency;
0444
0445 return 0;
0446 }
0447
0448 static int fc0011_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
0449 {
0450 *frequency = 0;
0451
0452 return 0;
0453 }
0454
0455 static int fc0011_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
0456 {
0457 struct fc0011_priv *priv = fe->tuner_priv;
0458
0459 *bandwidth = priv->bandwidth;
0460
0461 return 0;
0462 }
0463
0464 static const struct dvb_tuner_ops fc0011_tuner_ops = {
0465 .info = {
0466 .name = "Fitipower FC0011",
0467
0468 .frequency_min_hz = 45 * MHz,
0469 .frequency_max_hz = 1000 * MHz,
0470 },
0471
0472 .release = fc0011_release,
0473 .init = fc0011_init,
0474
0475 .set_params = fc0011_set_params,
0476
0477 .get_frequency = fc0011_get_frequency,
0478 .get_if_frequency = fc0011_get_if_frequency,
0479 .get_bandwidth = fc0011_get_bandwidth,
0480 };
0481
0482 struct dvb_frontend *fc0011_attach(struct dvb_frontend *fe,
0483 struct i2c_adapter *i2c,
0484 const struct fc0011_config *config)
0485 {
0486 struct fc0011_priv *priv;
0487
0488 priv = kzalloc(sizeof(struct fc0011_priv), GFP_KERNEL);
0489 if (!priv)
0490 return NULL;
0491
0492 priv->i2c = i2c;
0493 priv->addr = config->i2c_address;
0494
0495 fe->tuner_priv = priv;
0496 fe->ops.tuner_ops = fc0011_tuner_ops;
0497
0498 dev_info(&priv->i2c->dev, "Fitipower FC0011 tuner attached\n");
0499
0500 return fe;
0501 }
0502 EXPORT_SYMBOL(fc0011_attach);
0503
0504 MODULE_DESCRIPTION("Fitipower FC0011 silicon tuner driver");
0505 MODULE_AUTHOR("Michael Buesch <m@bues.ch>");
0506 MODULE_LICENSE("GPL");