Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Driver for Microtune MT2266 "Direct conversion low power broadband tuner"
0004  *
0005  *  Copyright (c) 2007 Olivier DANET <odanet@caramail.com>
0006  */
0007 
0008 #include <linux/module.h>
0009 #include <linux/delay.h>
0010 #include <linux/dvb/frontend.h>
0011 #include <linux/i2c.h>
0012 #include <linux/slab.h>
0013 
0014 #include <media/dvb_frontend.h>
0015 #include "mt2266.h"
0016 
0017 #define I2C_ADDRESS 0x60
0018 
0019 #define REG_PART_REV   0
0020 #define REG_TUNE       1
0021 #define REG_BAND       6
0022 #define REG_BANDWIDTH  8
0023 #define REG_LOCK       0x12
0024 
0025 #define PART_REV 0x85
0026 
0027 struct mt2266_priv {
0028     struct mt2266_config *cfg;
0029     struct i2c_adapter   *i2c;
0030 
0031     u32 frequency;
0032     u32 bandwidth;
0033     u8 band;
0034 };
0035 
0036 #define MT2266_VHF 1
0037 #define MT2266_UHF 0
0038 
0039 /* Here, frequencies are expressed in kiloHertz to avoid 32 bits overflows */
0040 
0041 static int debug;
0042 module_param(debug, int, 0644);
0043 MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
0044 
0045 #define dprintk(args...) do { if (debug) {printk(KERN_DEBUG "MT2266: " args); printk("\n"); }} while (0)
0046 
0047 // Reads a single register
0048 static int mt2266_readreg(struct mt2266_priv *priv, u8 reg, u8 *val)
0049 {
0050     struct i2c_msg msg[2] = {
0051         { .addr = priv->cfg->i2c_address, .flags = 0,        .buf = &reg, .len = 1 },
0052         { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = val,  .len = 1 },
0053     };
0054     if (i2c_transfer(priv->i2c, msg, 2) != 2) {
0055         printk(KERN_WARNING "MT2266 I2C read failed\n");
0056         return -EREMOTEIO;
0057     }
0058     return 0;
0059 }
0060 
0061 // Writes a single register
0062 static int mt2266_writereg(struct mt2266_priv *priv, u8 reg, u8 val)
0063 {
0064     u8 buf[2] = { reg, val };
0065     struct i2c_msg msg = {
0066         .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2
0067     };
0068     if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
0069         printk(KERN_WARNING "MT2266 I2C write failed\n");
0070         return -EREMOTEIO;
0071     }
0072     return 0;
0073 }
0074 
0075 // Writes a set of consecutive registers
0076 static int mt2266_writeregs(struct mt2266_priv *priv,u8 *buf, u8 len)
0077 {
0078     struct i2c_msg msg = {
0079         .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = len
0080     };
0081     if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
0082         printk(KERN_WARNING "MT2266 I2C write failed (len=%i)\n",(int)len);
0083         return -EREMOTEIO;
0084     }
0085     return 0;
0086 }
0087 
0088 // Initialisation sequences
0089 static u8 mt2266_init1[] = { REG_TUNE, 0x00, 0x00, 0x28,
0090                  0x00, 0x52, 0x99, 0x3f };
0091 
0092 static u8 mt2266_init2[] = {
0093     0x17, 0x6d, 0x71, 0x61, 0xc0, 0xbf, 0xff, 0xdc, 0x00, 0x0a, 0xd4,
0094     0x03, 0x64, 0x64, 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14,
0095     0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x7f, 0x5e, 0x3f, 0xff, 0xff,
0096     0xff, 0x00, 0x77, 0x0f, 0x2d
0097 };
0098 
0099 static u8 mt2266_init_8mhz[] = { REG_BANDWIDTH, 0x22, 0x22, 0x22, 0x22,
0100                         0x22, 0x22, 0x22, 0x22 };
0101 
0102 static u8 mt2266_init_7mhz[] = { REG_BANDWIDTH, 0x32, 0x32, 0x32, 0x32,
0103                         0x32, 0x32, 0x32, 0x32 };
0104 
0105 static u8 mt2266_init_6mhz[] = { REG_BANDWIDTH, 0xa7, 0xa7, 0xa7, 0xa7,
0106                         0xa7, 0xa7, 0xa7, 0xa7 };
0107 
0108 static u8 mt2266_uhf[] = { 0x1d, 0xdc, 0x00, 0x0a, 0xd4, 0x03, 0x64, 0x64,
0109                0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14 };
0110 
0111 static u8 mt2266_vhf[] = { 0x1d, 0xfe, 0x00, 0x00, 0xb4, 0x03, 0xa5, 0xa5,
0112                0xa5, 0xa5, 0x82, 0xaa, 0xf1, 0x17, 0x80, 0x1f };
0113 
0114 #define FREF 30000       // Quartz oscillator 30 MHz
0115 
0116 static int mt2266_set_params(struct dvb_frontend *fe)
0117 {
0118     struct dtv_frontend_properties *c = &fe->dtv_property_cache;
0119     struct mt2266_priv *priv;
0120     int ret=0;
0121     u32 freq;
0122     u32 tune;
0123     u8  lnaband;
0124     u8  b[10];
0125     int i;
0126     u8 band;
0127 
0128     priv = fe->tuner_priv;
0129 
0130     freq = priv->frequency / 1000; /* Hz -> kHz */
0131     if (freq < 470000 && freq > 230000)
0132         return -EINVAL; /* Gap between VHF and UHF bands */
0133 
0134     priv->frequency = c->frequency;
0135     tune = 2 * freq * (8192/16) / (FREF/16);
0136     band = (freq < 300000) ? MT2266_VHF : MT2266_UHF;
0137     if (band == MT2266_VHF)
0138         tune *= 2;
0139 
0140     switch (c->bandwidth_hz) {
0141     case 6000000:
0142         mt2266_writeregs(priv, mt2266_init_6mhz,
0143                  sizeof(mt2266_init_6mhz));
0144         break;
0145     case 8000000:
0146         mt2266_writeregs(priv, mt2266_init_8mhz,
0147                  sizeof(mt2266_init_8mhz));
0148         break;
0149     case 7000000:
0150     default:
0151         mt2266_writeregs(priv, mt2266_init_7mhz,
0152                  sizeof(mt2266_init_7mhz));
0153         break;
0154     }
0155     priv->bandwidth = c->bandwidth_hz;
0156 
0157     if (band == MT2266_VHF && priv->band == MT2266_UHF) {
0158         dprintk("Switch from UHF to VHF");
0159         mt2266_writereg(priv, 0x05, 0x04);
0160         mt2266_writereg(priv, 0x19, 0x61);
0161         mt2266_writeregs(priv, mt2266_vhf, sizeof(mt2266_vhf));
0162     } else if (band == MT2266_UHF && priv->band == MT2266_VHF) {
0163         dprintk("Switch from VHF to UHF");
0164         mt2266_writereg(priv, 0x05, 0x52);
0165         mt2266_writereg(priv, 0x19, 0x61);
0166         mt2266_writeregs(priv, mt2266_uhf, sizeof(mt2266_uhf));
0167     }
0168     msleep(10);
0169 
0170     if (freq <= 495000)
0171         lnaband = 0xEE;
0172     else if (freq <= 525000)
0173         lnaband = 0xDD;
0174     else if (freq <= 550000)
0175         lnaband = 0xCC;
0176     else if (freq <= 580000)
0177         lnaband = 0xBB;
0178     else if (freq <= 605000)
0179         lnaband = 0xAA;
0180     else if (freq <= 630000)
0181         lnaband = 0x99;
0182     else if (freq <= 655000)
0183         lnaband = 0x88;
0184     else if (freq <= 685000)
0185         lnaband = 0x77;
0186     else if (freq <= 710000)
0187         lnaband = 0x66;
0188     else if (freq <= 735000)
0189         lnaband = 0x55;
0190     else if (freq <= 765000)
0191         lnaband = 0x44;
0192     else if (freq <= 802000)
0193         lnaband = 0x33;
0194     else if (freq <= 840000)
0195         lnaband = 0x22;
0196     else
0197         lnaband = 0x11;
0198 
0199     b[0] = REG_TUNE;
0200     b[1] = (tune >> 8) & 0x1F;
0201     b[2] = tune & 0xFF;
0202     b[3] = tune >> 13;
0203     mt2266_writeregs(priv,b,4);
0204 
0205     dprintk("set_parms: tune=%d band=%d %s",
0206         (int) tune, (int) lnaband,
0207         (band == MT2266_UHF) ? "UHF" : "VHF");
0208     dprintk("set_parms: [1..3]: %2x %2x %2x",
0209         (int) b[1], (int) b[2], (int)b[3]);
0210 
0211     if (band == MT2266_UHF) {
0212         b[0] = 0x05;
0213         b[1] = (priv->band == MT2266_VHF) ? 0x52 : 0x62;
0214         b[2] = lnaband;
0215         mt2266_writeregs(priv, b, 3);
0216     }
0217 
0218     /* Wait for pll lock or timeout */
0219     i = 0;
0220     do {
0221         mt2266_readreg(priv,REG_LOCK,b);
0222         if (b[0] & 0x40)
0223             break;
0224         msleep(10);
0225         i++;
0226     } while (i<10);
0227     dprintk("Lock when i=%i",(int)i);
0228 
0229     if (band == MT2266_UHF && priv->band == MT2266_VHF)
0230         mt2266_writereg(priv, 0x05, 0x62);
0231 
0232     priv->band = band;
0233 
0234     return ret;
0235 }
0236 
0237 static void mt2266_calibrate(struct mt2266_priv *priv)
0238 {
0239     mt2266_writereg(priv, 0x11, 0x03);
0240     mt2266_writereg(priv, 0x11, 0x01);
0241     mt2266_writeregs(priv, mt2266_init1, sizeof(mt2266_init1));
0242     mt2266_writeregs(priv, mt2266_init2, sizeof(mt2266_init2));
0243     mt2266_writereg(priv, 0x33, 0x5e);
0244     mt2266_writereg(priv, 0x10, 0x10);
0245     mt2266_writereg(priv, 0x10, 0x00);
0246     mt2266_writeregs(priv, mt2266_init_8mhz, sizeof(mt2266_init_8mhz));
0247     msleep(25);
0248     mt2266_writereg(priv, 0x17, 0x6d);
0249     mt2266_writereg(priv, 0x1c, 0x00);
0250     msleep(75);
0251     mt2266_writereg(priv, 0x17, 0x6d);
0252     mt2266_writereg(priv, 0x1c, 0xff);
0253 }
0254 
0255 static int mt2266_get_frequency(struct dvb_frontend *fe, u32 *frequency)
0256 {
0257     struct mt2266_priv *priv = fe->tuner_priv;
0258     *frequency = priv->frequency;
0259     return 0;
0260 }
0261 
0262 static int mt2266_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
0263 {
0264     struct mt2266_priv *priv = fe->tuner_priv;
0265     *bandwidth = priv->bandwidth;
0266     return 0;
0267 }
0268 
0269 static int mt2266_init(struct dvb_frontend *fe)
0270 {
0271     int ret;
0272     struct mt2266_priv *priv = fe->tuner_priv;
0273     ret = mt2266_writereg(priv, 0x17, 0x6d);
0274     if (ret < 0)
0275         return ret;
0276     ret = mt2266_writereg(priv, 0x1c, 0xff);
0277     if (ret < 0)
0278         return ret;
0279     return 0;
0280 }
0281 
0282 static int mt2266_sleep(struct dvb_frontend *fe)
0283 {
0284     struct mt2266_priv *priv = fe->tuner_priv;
0285     mt2266_writereg(priv, 0x17, 0x6d);
0286     mt2266_writereg(priv, 0x1c, 0x00);
0287     return 0;
0288 }
0289 
0290 static void mt2266_release(struct dvb_frontend *fe)
0291 {
0292     kfree(fe->tuner_priv);
0293     fe->tuner_priv = NULL;
0294 }
0295 
0296 static const struct dvb_tuner_ops mt2266_tuner_ops = {
0297     .info = {
0298         .name              = "Microtune MT2266",
0299         .frequency_min_hz  = 174 * MHz,
0300         .frequency_max_hz  = 862 * MHz,
0301         .frequency_step_hz =  50 * kHz,
0302     },
0303     .release       = mt2266_release,
0304     .init          = mt2266_init,
0305     .sleep         = mt2266_sleep,
0306     .set_params    = mt2266_set_params,
0307     .get_frequency = mt2266_get_frequency,
0308     .get_bandwidth = mt2266_get_bandwidth
0309 };
0310 
0311 struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg)
0312 {
0313     struct mt2266_priv *priv = NULL;
0314     u8 id = 0;
0315 
0316     priv = kzalloc(sizeof(struct mt2266_priv), GFP_KERNEL);
0317     if (priv == NULL)
0318         return NULL;
0319 
0320     priv->cfg      = cfg;
0321     priv->i2c      = i2c;
0322     priv->band     = MT2266_UHF;
0323 
0324     if (mt2266_readreg(priv, 0, &id)) {
0325         kfree(priv);
0326         return NULL;
0327     }
0328     if (id != PART_REV) {
0329         kfree(priv);
0330         return NULL;
0331     }
0332     printk(KERN_INFO "MT2266: successfully identified\n");
0333     memcpy(&fe->ops.tuner_ops, &mt2266_tuner_ops, sizeof(struct dvb_tuner_ops));
0334 
0335     fe->tuner_priv = priv;
0336     mt2266_calibrate(priv);
0337     return fe;
0338 }
0339 EXPORT_SYMBOL(mt2266_attach);
0340 
0341 MODULE_AUTHOR("Olivier DANET");
0342 MODULE_DESCRIPTION("Microtune MT2266 silicon tuner driver");
0343 MODULE_LICENSE("GPL");