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