Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Fitipower FC0011 tuner driver
0004  *
0005  * Copyright (C) 2012 Michael Buesch <m@bues.ch>
0006  *
0007  * Derived from FC0012 tuner driver:
0008  * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.net>
0009  */
0010 
0011 #include "fc0011.h"
0012 
0013 
0014 /* Tuner registers */
0015 enum {
0016     FC11_REG_0,
0017     FC11_REG_FA,        /* FA */
0018     FC11_REG_FP,        /* FP */
0019     FC11_REG_XINHI,     /* XIN high 8 bit */
0020     FC11_REG_XINLO,     /* XIN low 8 bit */
0021     FC11_REG_VCO,       /* VCO */
0022     FC11_REG_VCOSEL,    /* VCO select */
0023     FC11_REG_7,     /* Unknown tuner reg 7 */
0024     FC11_REG_8,     /* Unknown tuner reg 8 */
0025     FC11_REG_9,
0026     FC11_REG_10,        /* Unknown tuner reg 10 */
0027     FC11_REG_11,        /* Unknown tuner reg 11 */
0028     FC11_REG_12,
0029     FC11_REG_RCCAL,     /* RC calibrate */
0030     FC11_REG_VCOCAL,    /* VCO calibrate */
0031     FC11_REG_15,
0032     FC11_REG_16,        /* Unknown tuner reg 16 */
0033     FC11_REG_17,
0034 
0035     FC11_NR_REGS,       /* Number of registers */
0036 };
0037 
0038 enum FC11_REG_VCOSEL_bits {
0039     FC11_VCOSEL_2       = 0x08, /* VCO select 2 */
0040     FC11_VCOSEL_1       = 0x10, /* VCO select 1 */
0041     FC11_VCOSEL_CLKOUT  = 0x20, /* Fix clock out */
0042     FC11_VCOSEL_BW7M    = 0x40, /* 7MHz bw */
0043     FC11_VCOSEL_BW6M    = 0x80, /* 6MHz bw */
0044 };
0045 
0046 enum FC11_REG_RCCAL_bits {
0047     FC11_RCCAL_FORCE    = 0x10, /* force */
0048 };
0049 
0050 enum FC11_REG_VCOCAL_bits {
0051     FC11_VCOCAL_RUN     = 0,    /* VCO calibration run */
0052     FC11_VCOCAL_VALUEMASK   = 0x3F, /* VCO calibration value mask */
0053     FC11_VCOCAL_OK      = 0x40, /* VCO calibration Ok */
0054     FC11_VCOCAL_RESET   = 0x80, /* VCO calibration reset */
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 = &reg, .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 /* Initiate VCO calibration */
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 /* Read VCO calibration value */
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     /* Set VCO freq and VCO div */
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     /* Calc XIN. The PLL reference frequency is 18 MHz. */
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     /* Calc FP and FA */
0221     xdivr = xdiv;
0222     if (fvco - xdiv * 18000 >= 9000)
0223         xdivr += 1; /* round */
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     /* Select bandwidth */
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     /* Pre VCO select */
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     /* Fix for low freqs */
0274     if (freq < 45000) {
0275         regs[FC11_REG_FA] = 0x6;
0276         regs[FC11_REG_FP] = 0x11;
0277     }
0278 
0279     /* Clock out fix */
0280     regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_CLKOUT;
0281 
0282     /* Write the cached registers */
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     /* VCO calibration */
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         /* Reset the tuner and try again */
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         /* Reinit tuner config */
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         /* VCO calibration */
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, &regs[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");