Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Driver for Quantek QT1010 silicon tuner
0004  *
0005  *  Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
0006  *                     Aapo Tahkola <aet@rasterburn.org>
0007  */
0008 #include "qt1010.h"
0009 #include "qt1010_priv.h"
0010 
0011 /* read single register */
0012 static int qt1010_readreg(struct qt1010_priv *priv, u8 reg, u8 *val)
0013 {
0014     struct i2c_msg msg[2] = {
0015         { .addr = priv->cfg->i2c_address,
0016           .flags = 0, .buf = &reg, .len = 1 },
0017         { .addr = priv->cfg->i2c_address,
0018           .flags = I2C_M_RD, .buf = val, .len = 1 },
0019     };
0020 
0021     if (i2c_transfer(priv->i2c, msg, 2) != 2) {
0022         dev_warn(&priv->i2c->dev, "%s: i2c rd failed reg=%02x\n",
0023                 KBUILD_MODNAME, reg);
0024         return -EREMOTEIO;
0025     }
0026     return 0;
0027 }
0028 
0029 /* write single register */
0030 static int qt1010_writereg(struct qt1010_priv *priv, u8 reg, u8 val)
0031 {
0032     u8 buf[2] = { reg, val };
0033     struct i2c_msg msg = { .addr = priv->cfg->i2c_address,
0034                    .flags = 0, .buf = buf, .len = 2 };
0035 
0036     if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
0037         dev_warn(&priv->i2c->dev, "%s: i2c wr failed reg=%02x\n",
0038                 KBUILD_MODNAME, reg);
0039         return -EREMOTEIO;
0040     }
0041     return 0;
0042 }
0043 
0044 static int qt1010_set_params(struct dvb_frontend *fe)
0045 {
0046     struct dtv_frontend_properties *c = &fe->dtv_property_cache;
0047     struct qt1010_priv *priv;
0048     int err;
0049     u32 freq, div, mod1, mod2;
0050     u8 i, tmpval, reg05;
0051     qt1010_i2c_oper_t rd[48] = {
0052         { QT1010_WR, 0x01, 0x80 },
0053         { QT1010_WR, 0x02, 0x3f },
0054         { QT1010_WR, 0x05, 0xff }, /* 02 c write */
0055         { QT1010_WR, 0x06, 0x44 },
0056         { QT1010_WR, 0x07, 0xff }, /* 04 c write */
0057         { QT1010_WR, 0x08, 0x08 },
0058         { QT1010_WR, 0x09, 0xff }, /* 06 c write */
0059         { QT1010_WR, 0x0a, 0xff }, /* 07 c write */
0060         { QT1010_WR, 0x0b, 0xff }, /* 08 c write */
0061         { QT1010_WR, 0x0c, 0xe1 },
0062         { QT1010_WR, 0x1a, 0xff }, /* 10 c write */
0063         { QT1010_WR, 0x1b, 0x00 },
0064         { QT1010_WR, 0x1c, 0x89 },
0065         { QT1010_WR, 0x11, 0xff }, /* 13 c write */
0066         { QT1010_WR, 0x12, 0xff }, /* 14 c write */
0067         { QT1010_WR, 0x22, 0xff }, /* 15 c write */
0068         { QT1010_WR, 0x1e, 0x00 },
0069         { QT1010_WR, 0x1e, 0xd0 },
0070         { QT1010_RD, 0x22, 0xff }, /* 16 c read */
0071         { QT1010_WR, 0x1e, 0x00 },
0072         { QT1010_RD, 0x05, 0xff }, /* 20 c read */
0073         { QT1010_RD, 0x22, 0xff }, /* 21 c read */
0074         { QT1010_WR, 0x23, 0xd0 },
0075         { QT1010_WR, 0x1e, 0x00 },
0076         { QT1010_WR, 0x1e, 0xe0 },
0077         { QT1010_RD, 0x23, 0xff }, /* 25 c read */
0078         { QT1010_RD, 0x23, 0xff }, /* 26 c read */
0079         { QT1010_WR, 0x1e, 0x00 },
0080         { QT1010_WR, 0x24, 0xd0 },
0081         { QT1010_WR, 0x1e, 0x00 },
0082         { QT1010_WR, 0x1e, 0xf0 },
0083         { QT1010_RD, 0x24, 0xff }, /* 31 c read */
0084         { QT1010_WR, 0x1e, 0x00 },
0085         { QT1010_WR, 0x14, 0x7f },
0086         { QT1010_WR, 0x15, 0x7f },
0087         { QT1010_WR, 0x05, 0xff }, /* 35 c write */
0088         { QT1010_WR, 0x06, 0x00 },
0089         { QT1010_WR, 0x15, 0x1f },
0090         { QT1010_WR, 0x16, 0xff },
0091         { QT1010_WR, 0x18, 0xff },
0092         { QT1010_WR, 0x1f, 0xff }, /* 40 c write */
0093         { QT1010_WR, 0x20, 0xff }, /* 41 c write */
0094         { QT1010_WR, 0x21, 0x53 },
0095         { QT1010_WR, 0x25, 0xff }, /* 43 c write */
0096         { QT1010_WR, 0x26, 0x15 },
0097         { QT1010_WR, 0x00, 0xff }, /* 45 c write */
0098         { QT1010_WR, 0x02, 0x00 },
0099         { QT1010_WR, 0x01, 0x00 }
0100     };
0101 
0102 #define FREQ1 32000000 /* 32 MHz */
0103 #define FREQ2  4000000 /* 4 MHz Quartz oscillator in the stick? */
0104 
0105     priv = fe->tuner_priv;
0106     freq = c->frequency;
0107     div = (freq + QT1010_OFFSET) / QT1010_STEP;
0108     freq = (div * QT1010_STEP) - QT1010_OFFSET;
0109     mod1 = (freq + QT1010_OFFSET) % FREQ1;
0110     mod2 = (freq + QT1010_OFFSET) % FREQ2;
0111     priv->frequency = freq;
0112 
0113     if (fe->ops.i2c_gate_ctrl)
0114         fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
0115 
0116     /* reg 05 base value */
0117     if      (freq < 290000000) reg05 = 0x14; /* 290 MHz */
0118     else if (freq < 610000000) reg05 = 0x34; /* 610 MHz */
0119     else if (freq < 802000000) reg05 = 0x54; /* 802 MHz */
0120     else                       reg05 = 0x74;
0121 
0122     /* 0x5 */
0123     rd[2].val = reg05;
0124 
0125     /* 07 - set frequency: 32 MHz scale */
0126     rd[4].val = (freq + QT1010_OFFSET) / FREQ1;
0127 
0128     /* 09 - changes every 8/24 MHz */
0129     if (mod1 < 8000000) rd[6].val = 0x1d;
0130     else                rd[6].val = 0x1c;
0131 
0132     /* 0a - set frequency: 4 MHz scale (max 28 MHz) */
0133     if      (mod1 < 1*FREQ2) rd[7].val = 0x09; /*  +0 MHz */
0134     else if (mod1 < 2*FREQ2) rd[7].val = 0x08; /*  +4 MHz */
0135     else if (mod1 < 3*FREQ2) rd[7].val = 0x0f; /*  +8 MHz */
0136     else if (mod1 < 4*FREQ2) rd[7].val = 0x0e; /* +12 MHz */
0137     else if (mod1 < 5*FREQ2) rd[7].val = 0x0d; /* +16 MHz */
0138     else if (mod1 < 6*FREQ2) rd[7].val = 0x0c; /* +20 MHz */
0139     else if (mod1 < 7*FREQ2) rd[7].val = 0x0b; /* +24 MHz */
0140     else                     rd[7].val = 0x0a; /* +28 MHz */
0141 
0142     /* 0b - changes every 2/2 MHz */
0143     if (mod2 < 2000000) rd[8].val = 0x45;
0144     else                rd[8].val = 0x44;
0145 
0146     /* 1a - set frequency: 125 kHz scale (max 3875 kHz)*/
0147     tmpval = 0x78; /* byte, overflows intentionally */
0148     rd[10].val = tmpval-((mod2/QT1010_STEP)*0x08);
0149 
0150     /* 11 */
0151     rd[13].val = 0xfd; /* TODO: correct value calculation */
0152 
0153     /* 12 */
0154     rd[14].val = 0x91; /* TODO: correct value calculation */
0155 
0156     /* 22 */
0157     if      (freq < 450000000) rd[15].val = 0xd0; /* 450 MHz */
0158     else if (freq < 482000000) rd[15].val = 0xd1; /* 482 MHz */
0159     else if (freq < 514000000) rd[15].val = 0xd4; /* 514 MHz */
0160     else if (freq < 546000000) rd[15].val = 0xd7; /* 546 MHz */
0161     else if (freq < 610000000) rd[15].val = 0xda; /* 610 MHz */
0162     else                       rd[15].val = 0xd0;
0163 
0164     /* 05 */
0165     rd[35].val = (reg05 & 0xf0);
0166 
0167     /* 1f */
0168     if      (mod1 <  8000000) tmpval = 0x00;
0169     else if (mod1 < 12000000) tmpval = 0x01;
0170     else if (mod1 < 16000000) tmpval = 0x02;
0171     else if (mod1 < 24000000) tmpval = 0x03;
0172     else if (mod1 < 28000000) tmpval = 0x04;
0173     else                      tmpval = 0x05;
0174     rd[40].val = (priv->reg1f_init_val + 0x0e + tmpval);
0175 
0176     /* 20 */
0177     if      (mod1 <  8000000) tmpval = 0x00;
0178     else if (mod1 < 12000000) tmpval = 0x01;
0179     else if (mod1 < 20000000) tmpval = 0x02;
0180     else if (mod1 < 24000000) tmpval = 0x03;
0181     else if (mod1 < 28000000) tmpval = 0x04;
0182     else                      tmpval = 0x05;
0183     rd[41].val = (priv->reg20_init_val + 0x0d + tmpval);
0184 
0185     /* 25 */
0186     rd[43].val = priv->reg25_init_val;
0187 
0188     /* 00 */
0189     rd[45].val = 0x92; /* TODO: correct value calculation */
0190 
0191     dev_dbg(&priv->i2c->dev,
0192             "%s: freq:%u 05:%02x 07:%02x 09:%02x 0a:%02x 0b:%02x " \
0193             "1a:%02x 11:%02x 12:%02x 22:%02x 05:%02x 1f:%02x " \
0194             "20:%02x 25:%02x 00:%02x\n", __func__, \
0195             freq, rd[2].val, rd[4].val, rd[6].val, rd[7].val, \
0196             rd[8].val, rd[10].val, rd[13].val, rd[14].val, \
0197             rd[15].val, rd[35].val, rd[40].val, rd[41].val, \
0198             rd[43].val, rd[45].val);
0199 
0200     for (i = 0; i < ARRAY_SIZE(rd); i++) {
0201         if (rd[i].oper == QT1010_WR) {
0202             err = qt1010_writereg(priv, rd[i].reg, rd[i].val);
0203         } else { /* read is required to proper locking */
0204             err = qt1010_readreg(priv, rd[i].reg, &tmpval);
0205         }
0206         if (err) return err;
0207     }
0208 
0209     if (fe->ops.i2c_gate_ctrl)
0210         fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
0211 
0212     return 0;
0213 }
0214 
0215 static int qt1010_init_meas1(struct qt1010_priv *priv,
0216                  u8 oper, u8 reg, u8 reg_init_val, u8 *retval)
0217 {
0218     u8 i, val1, val2;
0219     int err;
0220 
0221     qt1010_i2c_oper_t i2c_data[] = {
0222         { QT1010_WR, reg, reg_init_val },
0223         { QT1010_WR, 0x1e, 0x00 },
0224         { QT1010_WR, 0x1e, oper },
0225     };
0226 
0227     for (i = 0; i < ARRAY_SIZE(i2c_data); i++) {
0228         err = qt1010_writereg(priv, i2c_data[i].reg,
0229                       i2c_data[i].val);
0230         if (err)
0231             return err;
0232     }
0233 
0234     err = qt1010_readreg(priv, reg, &val2);
0235     if (err)
0236         return err;
0237     do {
0238         val1 = val2;
0239         err = qt1010_readreg(priv, reg, &val2);
0240         if (err)
0241             return err;
0242 
0243         dev_dbg(&priv->i2c->dev, "%s: compare reg:%02x %02x %02x\n",
0244                 __func__, reg, val1, val2);
0245     } while (val1 != val2);
0246     *retval = val1;
0247 
0248     return qt1010_writereg(priv, 0x1e, 0x00);
0249 }
0250 
0251 static int qt1010_init_meas2(struct qt1010_priv *priv,
0252                 u8 reg_init_val, u8 *retval)
0253 {
0254     u8 i, val = 0xff;
0255     int err;
0256     qt1010_i2c_oper_t i2c_data[] = {
0257         { QT1010_WR, 0x07, reg_init_val },
0258         { QT1010_WR, 0x22, 0xd0 },
0259         { QT1010_WR, 0x1e, 0x00 },
0260         { QT1010_WR, 0x1e, 0xd0 },
0261         { QT1010_RD, 0x22, 0xff },
0262         { QT1010_WR, 0x1e, 0x00 },
0263         { QT1010_WR, 0x22, 0xff }
0264     };
0265 
0266     for (i = 0; i < ARRAY_SIZE(i2c_data); i++) {
0267         if (i2c_data[i].oper == QT1010_WR) {
0268             err = qt1010_writereg(priv, i2c_data[i].reg,
0269                           i2c_data[i].val);
0270         } else {
0271             err = qt1010_readreg(priv, i2c_data[i].reg, &val);
0272         }
0273         if (err)
0274             return err;
0275     }
0276     *retval = val;
0277     return 0;
0278 }
0279 
0280 static int qt1010_init(struct dvb_frontend *fe)
0281 {
0282     struct qt1010_priv *priv = fe->tuner_priv;
0283     struct dtv_frontend_properties *c = &fe->dtv_property_cache;
0284     int err = 0;
0285     u8 i, tmpval, *valptr = NULL;
0286 
0287     static const qt1010_i2c_oper_t i2c_data[] = {
0288         { QT1010_WR, 0x01, 0x80 },
0289         { QT1010_WR, 0x0d, 0x84 },
0290         { QT1010_WR, 0x0e, 0xb7 },
0291         { QT1010_WR, 0x2a, 0x23 },
0292         { QT1010_WR, 0x2c, 0xdc },
0293         { QT1010_M1, 0x25, 0x40 }, /* get reg 25 init value */
0294         { QT1010_M1, 0x81, 0xff }, /* get reg 25 init value */
0295         { QT1010_WR, 0x2b, 0x70 },
0296         { QT1010_WR, 0x2a, 0x23 },
0297         { QT1010_M1, 0x26, 0x08 },
0298         { QT1010_M1, 0x82, 0xff },
0299         { QT1010_WR, 0x05, 0x14 },
0300         { QT1010_WR, 0x06, 0x44 },
0301         { QT1010_WR, 0x07, 0x28 },
0302         { QT1010_WR, 0x08, 0x0b },
0303         { QT1010_WR, 0x11, 0xfd },
0304         { QT1010_M1, 0x22, 0x0d },
0305         { QT1010_M1, 0xd0, 0xff },
0306         { QT1010_WR, 0x06, 0x40 },
0307         { QT1010_WR, 0x16, 0xf0 },
0308         { QT1010_WR, 0x02, 0x38 },
0309         { QT1010_WR, 0x03, 0x18 },
0310         { QT1010_WR, 0x20, 0xe0 },
0311         { QT1010_M1, 0x1f, 0x20 }, /* get reg 1f init value */
0312         { QT1010_M1, 0x84, 0xff }, /* get reg 1f init value */
0313         { QT1010_RD, 0x20, 0x20 }, /* get reg 20 init value */
0314         { QT1010_WR, 0x03, 0x19 },
0315         { QT1010_WR, 0x02, 0x3f },
0316         { QT1010_WR, 0x21, 0x53 },
0317         { QT1010_RD, 0x21, 0xff },
0318         { QT1010_WR, 0x11, 0xfd },
0319         { QT1010_WR, 0x05, 0x34 },
0320         { QT1010_WR, 0x06, 0x44 },
0321         { QT1010_WR, 0x08, 0x08 }
0322     };
0323 
0324     if (fe->ops.i2c_gate_ctrl)
0325         fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
0326 
0327     for (i = 0; i < ARRAY_SIZE(i2c_data); i++) {
0328         switch (i2c_data[i].oper) {
0329         case QT1010_WR:
0330             err = qt1010_writereg(priv, i2c_data[i].reg,
0331                           i2c_data[i].val);
0332             break;
0333         case QT1010_RD:
0334             if (i2c_data[i].val == 0x20)
0335                 valptr = &priv->reg20_init_val;
0336             else
0337                 valptr = &tmpval;
0338             err = qt1010_readreg(priv, i2c_data[i].reg, valptr);
0339             break;
0340         case QT1010_M1:
0341             if (i2c_data[i].val == 0x25)
0342                 valptr = &priv->reg25_init_val;
0343             else if (i2c_data[i].val == 0x1f)
0344                 valptr = &priv->reg1f_init_val;
0345             else
0346                 valptr = &tmpval;
0347 
0348             BUG_ON(i >= ARRAY_SIZE(i2c_data) - 1);
0349 
0350             err = qt1010_init_meas1(priv, i2c_data[i+1].reg,
0351                         i2c_data[i].reg,
0352                         i2c_data[i].val, valptr);
0353             i++;
0354             break;
0355         }
0356         if (err)
0357             return err;
0358     }
0359 
0360     for (i = 0x31; i < 0x3a; i++) /* 0x31 - 0x39 */
0361         if ((err = qt1010_init_meas2(priv, i, &tmpval)))
0362             return err;
0363 
0364     if (!c->frequency)
0365         c->frequency = 545000000; /* Sigmatek DVB-110 545000000 */
0366                       /* MSI Megasky 580 GL861 533000000 */
0367     return qt1010_set_params(fe);
0368 }
0369 
0370 static void qt1010_release(struct dvb_frontend *fe)
0371 {
0372     kfree(fe->tuner_priv);
0373     fe->tuner_priv = NULL;
0374 }
0375 
0376 static int qt1010_get_frequency(struct dvb_frontend *fe, u32 *frequency)
0377 {
0378     struct qt1010_priv *priv = fe->tuner_priv;
0379     *frequency = priv->frequency;
0380     return 0;
0381 }
0382 
0383 static int qt1010_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
0384 {
0385     *frequency = 36125000;
0386     return 0;
0387 }
0388 
0389 static const struct dvb_tuner_ops qt1010_tuner_ops = {
0390     .info = {
0391         .name              = "Quantek QT1010",
0392         .frequency_min_hz  = QT1010_MIN_FREQ,
0393         .frequency_max_hz  = QT1010_MAX_FREQ,
0394         .frequency_step_hz = QT1010_STEP,
0395     },
0396 
0397     .release       = qt1010_release,
0398     .init          = qt1010_init,
0399     /* TODO: implement sleep */
0400 
0401     .set_params    = qt1010_set_params,
0402     .get_frequency = qt1010_get_frequency,
0403     .get_if_frequency = qt1010_get_if_frequency,
0404 };
0405 
0406 struct dvb_frontend * qt1010_attach(struct dvb_frontend *fe,
0407                     struct i2c_adapter *i2c,
0408                     struct qt1010_config *cfg)
0409 {
0410     struct qt1010_priv *priv = NULL;
0411     u8 id;
0412 
0413     priv = kzalloc(sizeof(struct qt1010_priv), GFP_KERNEL);
0414     if (priv == NULL)
0415         return NULL;
0416 
0417     priv->cfg = cfg;
0418     priv->i2c = i2c;
0419 
0420     if (fe->ops.i2c_gate_ctrl)
0421         fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
0422 
0423 
0424     /* Try to detect tuner chip. Probably this is not correct register. */
0425     if (qt1010_readreg(priv, 0x29, &id) != 0 || (id != 0x39)) {
0426         kfree(priv);
0427         return NULL;
0428     }
0429 
0430     if (fe->ops.i2c_gate_ctrl)
0431         fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
0432 
0433     dev_info(&priv->i2c->dev,
0434             "%s: Quantek QT1010 successfully identified\n",
0435             KBUILD_MODNAME);
0436 
0437     memcpy(&fe->ops.tuner_ops, &qt1010_tuner_ops,
0438            sizeof(struct dvb_tuner_ops));
0439 
0440     fe->tuner_priv = priv;
0441     return fe;
0442 }
0443 EXPORT_SYMBOL(qt1010_attach);
0444 
0445 MODULE_DESCRIPTION("Quantek QT1010 silicon tuner driver");
0446 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
0447 MODULE_AUTHOR("Aapo Tahkola <aet@rasterburn.org>");
0448 MODULE_VERSION("0.1");
0449 MODULE_LICENSE("GPL");