root/drivers/media/tuners/mt2266.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mt2266_readreg
  2. mt2266_writereg
  3. mt2266_writeregs
  4. mt2266_set_params
  5. mt2266_calibrate
  6. mt2266_get_frequency
  7. mt2266_get_bandwidth
  8. mt2266_init
  9. mt2266_sleep
  10. mt2266_release
  11. mt2266_attach

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  *  Driver for Microtune MT2266 "Direct conversion low power broadband tuner"
   4  *
   5  *  Copyright (c) 2007 Olivier DANET <odanet@caramail.com>
   6  */
   7 
   8 #include <linux/module.h>
   9 #include <linux/delay.h>
  10 #include <linux/dvb/frontend.h>
  11 #include <linux/i2c.h>
  12 #include <linux/slab.h>
  13 
  14 #include <media/dvb_frontend.h>
  15 #include "mt2266.h"
  16 
  17 #define I2C_ADDRESS 0x60
  18 
  19 #define REG_PART_REV   0
  20 #define REG_TUNE       1
  21 #define REG_BAND       6
  22 #define REG_BANDWIDTH  8
  23 #define REG_LOCK       0x12
  24 
  25 #define PART_REV 0x85
  26 
  27 struct mt2266_priv {
  28         struct mt2266_config *cfg;
  29         struct i2c_adapter   *i2c;
  30 
  31         u32 frequency;
  32         u32 bandwidth;
  33         u8 band;
  34 };
  35 
  36 #define MT2266_VHF 1
  37 #define MT2266_UHF 0
  38 
  39 /* Here, frequencies are expressed in kiloHertz to avoid 32 bits overflows */
  40 
  41 static int debug;
  42 module_param(debug, int, 0644);
  43 MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
  44 
  45 #define dprintk(args...) do { if (debug) {printk(KERN_DEBUG "MT2266: " args); printk("\n"); }} while (0)
  46 
  47 // Reads a single register
  48 static int mt2266_readreg(struct mt2266_priv *priv, u8 reg, u8 *val)
  49 {
  50         struct i2c_msg msg[2] = {
  51                 { .addr = priv->cfg->i2c_address, .flags = 0,        .buf = &reg, .len = 1 },
  52                 { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = val,  .len = 1 },
  53         };
  54         if (i2c_transfer(priv->i2c, msg, 2) != 2) {
  55                 printk(KERN_WARNING "MT2266 I2C read failed\n");
  56                 return -EREMOTEIO;
  57         }
  58         return 0;
  59 }
  60 
  61 // Writes a single register
  62 static int mt2266_writereg(struct mt2266_priv *priv, u8 reg, u8 val)
  63 {
  64         u8 buf[2] = { reg, val };
  65         struct i2c_msg msg = {
  66                 .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2
  67         };
  68         if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
  69                 printk(KERN_WARNING "MT2266 I2C write failed\n");
  70                 return -EREMOTEIO;
  71         }
  72         return 0;
  73 }
  74 
  75 // Writes a set of consecutive registers
  76 static int mt2266_writeregs(struct mt2266_priv *priv,u8 *buf, u8 len)
  77 {
  78         struct i2c_msg msg = {
  79                 .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = len
  80         };
  81         if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
  82                 printk(KERN_WARNING "MT2266 I2C write failed (len=%i)\n",(int)len);
  83                 return -EREMOTEIO;
  84         }
  85         return 0;
  86 }
  87 
  88 // Initialisation sequences
  89 static u8 mt2266_init1[] = { REG_TUNE, 0x00, 0x00, 0x28,
  90                                  0x00, 0x52, 0x99, 0x3f };
  91 
  92 static u8 mt2266_init2[] = {
  93     0x17, 0x6d, 0x71, 0x61, 0xc0, 0xbf, 0xff, 0xdc, 0x00, 0x0a, 0xd4,
  94     0x03, 0x64, 0x64, 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14,
  95     0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x7f, 0x5e, 0x3f, 0xff, 0xff,
  96     0xff, 0x00, 0x77, 0x0f, 0x2d
  97 };
  98 
  99 static u8 mt2266_init_8mhz[] = { REG_BANDWIDTH, 0x22, 0x22, 0x22, 0x22,
 100                                                 0x22, 0x22, 0x22, 0x22 };
 101 
 102 static u8 mt2266_init_7mhz[] = { REG_BANDWIDTH, 0x32, 0x32, 0x32, 0x32,
 103                                                 0x32, 0x32, 0x32, 0x32 };
 104 
 105 static u8 mt2266_init_6mhz[] = { REG_BANDWIDTH, 0xa7, 0xa7, 0xa7, 0xa7,
 106                                                 0xa7, 0xa7, 0xa7, 0xa7 };
 107 
 108 static u8 mt2266_uhf[] = { 0x1d, 0xdc, 0x00, 0x0a, 0xd4, 0x03, 0x64, 0x64,
 109                            0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14 };
 110 
 111 static u8 mt2266_vhf[] = { 0x1d, 0xfe, 0x00, 0x00, 0xb4, 0x03, 0xa5, 0xa5,
 112                            0xa5, 0xa5, 0x82, 0xaa, 0xf1, 0x17, 0x80, 0x1f };
 113 
 114 #define FREF 30000       // Quartz oscillator 30 MHz
 115 
 116 static int mt2266_set_params(struct dvb_frontend *fe)
 117 {
 118         struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 119         struct mt2266_priv *priv;
 120         int ret=0;
 121         u32 freq;
 122         u32 tune;
 123         u8  lnaband;
 124         u8  b[10];
 125         int i;
 126         u8 band;
 127 
 128         priv = fe->tuner_priv;
 129 
 130         freq = priv->frequency / 1000; /* Hz -> kHz */
 131         if (freq < 470000 && freq > 230000)
 132                 return -EINVAL; /* Gap between VHF and UHF bands */
 133 
 134         priv->frequency = c->frequency;
 135         tune = 2 * freq * (8192/16) / (FREF/16);
 136         band = (freq < 300000) ? MT2266_VHF : MT2266_UHF;
 137         if (band == MT2266_VHF)
 138                 tune *= 2;
 139 
 140         switch (c->bandwidth_hz) {
 141         case 6000000:
 142                 mt2266_writeregs(priv, mt2266_init_6mhz,
 143                                  sizeof(mt2266_init_6mhz));
 144                 break;
 145         case 8000000:
 146                 mt2266_writeregs(priv, mt2266_init_8mhz,
 147                                  sizeof(mt2266_init_8mhz));
 148                 break;
 149         case 7000000:
 150         default:
 151                 mt2266_writeregs(priv, mt2266_init_7mhz,
 152                                  sizeof(mt2266_init_7mhz));
 153                 break;
 154         }
 155         priv->bandwidth = c->bandwidth_hz;
 156 
 157         if (band == MT2266_VHF && priv->band == MT2266_UHF) {
 158                 dprintk("Switch from UHF to VHF");
 159                 mt2266_writereg(priv, 0x05, 0x04);
 160                 mt2266_writereg(priv, 0x19, 0x61);
 161                 mt2266_writeregs(priv, mt2266_vhf, sizeof(mt2266_vhf));
 162         } else if (band == MT2266_UHF && priv->band == MT2266_VHF) {
 163                 dprintk("Switch from VHF to UHF");
 164                 mt2266_writereg(priv, 0x05, 0x52);
 165                 mt2266_writereg(priv, 0x19, 0x61);
 166                 mt2266_writeregs(priv, mt2266_uhf, sizeof(mt2266_uhf));
 167         }
 168         msleep(10);
 169 
 170         if (freq <= 495000)
 171                 lnaband = 0xEE;
 172         else if (freq <= 525000)
 173                 lnaband = 0xDD;
 174         else if (freq <= 550000)
 175                 lnaband = 0xCC;
 176         else if (freq <= 580000)
 177                 lnaband = 0xBB;
 178         else if (freq <= 605000)
 179                 lnaband = 0xAA;
 180         else if (freq <= 630000)
 181                 lnaband = 0x99;
 182         else if (freq <= 655000)
 183                 lnaband = 0x88;
 184         else if (freq <= 685000)
 185                 lnaband = 0x77;
 186         else if (freq <= 710000)
 187                 lnaband = 0x66;
 188         else if (freq <= 735000)
 189                 lnaband = 0x55;
 190         else if (freq <= 765000)
 191                 lnaband = 0x44;
 192         else if (freq <= 802000)
 193                 lnaband = 0x33;
 194         else if (freq <= 840000)
 195                 lnaband = 0x22;
 196         else
 197                 lnaband = 0x11;
 198 
 199         b[0] = REG_TUNE;
 200         b[1] = (tune >> 8) & 0x1F;
 201         b[2] = tune & 0xFF;
 202         b[3] = tune >> 13;
 203         mt2266_writeregs(priv,b,4);
 204 
 205         dprintk("set_parms: tune=%d band=%d %s",
 206                 (int) tune, (int) lnaband,
 207                 (band == MT2266_UHF) ? "UHF" : "VHF");
 208         dprintk("set_parms: [1..3]: %2x %2x %2x",
 209                 (int) b[1], (int) b[2], (int)b[3]);
 210 
 211         if (band == MT2266_UHF) {
 212                 b[0] = 0x05;
 213                 b[1] = (priv->band == MT2266_VHF) ? 0x52 : 0x62;
 214                 b[2] = lnaband;
 215                 mt2266_writeregs(priv, b, 3);
 216         }
 217 
 218         /* Wait for pll lock or timeout */
 219         i = 0;
 220         do {
 221                 mt2266_readreg(priv,REG_LOCK,b);
 222                 if (b[0] & 0x40)
 223                         break;
 224                 msleep(10);
 225                 i++;
 226         } while (i<10);
 227         dprintk("Lock when i=%i",(int)i);
 228 
 229         if (band == MT2266_UHF && priv->band == MT2266_VHF)
 230                 mt2266_writereg(priv, 0x05, 0x62);
 231 
 232         priv->band = band;
 233 
 234         return ret;
 235 }
 236 
 237 static void mt2266_calibrate(struct mt2266_priv *priv)
 238 {
 239         mt2266_writereg(priv, 0x11, 0x03);
 240         mt2266_writereg(priv, 0x11, 0x01);
 241         mt2266_writeregs(priv, mt2266_init1, sizeof(mt2266_init1));
 242         mt2266_writeregs(priv, mt2266_init2, sizeof(mt2266_init2));
 243         mt2266_writereg(priv, 0x33, 0x5e);
 244         mt2266_writereg(priv, 0x10, 0x10);
 245         mt2266_writereg(priv, 0x10, 0x00);
 246         mt2266_writeregs(priv, mt2266_init_8mhz, sizeof(mt2266_init_8mhz));
 247         msleep(25);
 248         mt2266_writereg(priv, 0x17, 0x6d);
 249         mt2266_writereg(priv, 0x1c, 0x00);
 250         msleep(75);
 251         mt2266_writereg(priv, 0x17, 0x6d);
 252         mt2266_writereg(priv, 0x1c, 0xff);
 253 }
 254 
 255 static int mt2266_get_frequency(struct dvb_frontend *fe, u32 *frequency)
 256 {
 257         struct mt2266_priv *priv = fe->tuner_priv;
 258         *frequency = priv->frequency;
 259         return 0;
 260 }
 261 
 262 static int mt2266_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
 263 {
 264         struct mt2266_priv *priv = fe->tuner_priv;
 265         *bandwidth = priv->bandwidth;
 266         return 0;
 267 }
 268 
 269 static int mt2266_init(struct dvb_frontend *fe)
 270 {
 271         int ret;
 272         struct mt2266_priv *priv = fe->tuner_priv;
 273         ret = mt2266_writereg(priv, 0x17, 0x6d);
 274         if (ret < 0)
 275                 return ret;
 276         ret = mt2266_writereg(priv, 0x1c, 0xff);
 277         if (ret < 0)
 278                 return ret;
 279         return 0;
 280 }
 281 
 282 static int mt2266_sleep(struct dvb_frontend *fe)
 283 {
 284         struct mt2266_priv *priv = fe->tuner_priv;
 285         mt2266_writereg(priv, 0x17, 0x6d);
 286         mt2266_writereg(priv, 0x1c, 0x00);
 287         return 0;
 288 }
 289 
 290 static void mt2266_release(struct dvb_frontend *fe)
 291 {
 292         kfree(fe->tuner_priv);
 293         fe->tuner_priv = NULL;
 294 }
 295 
 296 static const struct dvb_tuner_ops mt2266_tuner_ops = {
 297         .info = {
 298                 .name              = "Microtune MT2266",
 299                 .frequency_min_hz  = 174 * MHz,
 300                 .frequency_max_hz  = 862 * MHz,
 301                 .frequency_step_hz =  50 * kHz,
 302         },
 303         .release       = mt2266_release,
 304         .init          = mt2266_init,
 305         .sleep         = mt2266_sleep,
 306         .set_params    = mt2266_set_params,
 307         .get_frequency = mt2266_get_frequency,
 308         .get_bandwidth = mt2266_get_bandwidth
 309 };
 310 
 311 struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg)
 312 {
 313         struct mt2266_priv *priv = NULL;
 314         u8 id = 0;
 315 
 316         priv = kzalloc(sizeof(struct mt2266_priv), GFP_KERNEL);
 317         if (priv == NULL)
 318                 return NULL;
 319 
 320         priv->cfg      = cfg;
 321         priv->i2c      = i2c;
 322         priv->band     = MT2266_UHF;
 323 
 324         if (mt2266_readreg(priv, 0, &id)) {
 325                 kfree(priv);
 326                 return NULL;
 327         }
 328         if (id != PART_REV) {
 329                 kfree(priv);
 330                 return NULL;
 331         }
 332         printk(KERN_INFO "MT2266: successfully identified\n");
 333         memcpy(&fe->ops.tuner_ops, &mt2266_tuner_ops, sizeof(struct dvb_tuner_ops));
 334 
 335         fe->tuner_priv = priv;
 336         mt2266_calibrate(priv);
 337         return fe;
 338 }
 339 EXPORT_SYMBOL(mt2266_attach);
 340 
 341 MODULE_AUTHOR("Olivier DANET");
 342 MODULE_DESCRIPTION("Microtune MT2266 silicon tuner driver");
 343 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */