aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Toth <stoth@hauppauge.com>2007-07-28 18:17:39 -0400
committerMauro Carvalho Chehab <mchehab@infradead.org>2007-10-09 21:03:35 -0400
commitf47623a04dab402fb2c18fe516a174bc02005629 (patch)
tree5d261f2802f9fe5390a19e2e9df14fcdf237b390
parent03b7612336560c6799852acaaaeac70e1f00e483 (diff)
V4L/DVB (5947): Adding support for the MT2131 tuner.
This adds support for the Microtune MT2131 tuner. 8VSB mode has been tested but QAM support will likely require more register work. Hauppauge have not announced any QAM devices using the MT2131 so QAM remains undone. For legal reasons, Microtune allowed us to write a GPL driver providing we did not document in significant detail any of the registers. This explains the lack of comments or defined on register names. Signed-off-by: Steven Toth <stoth@hauppauge.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
-rw-r--r--drivers/media/dvb/frontends/Kconfig7
-rw-r--r--drivers/media/dvb/frontends/Makefile1
-rw-r--r--drivers/media/dvb/frontends/mt2131.c308
-rw-r--r--drivers/media/dvb/frontends/mt2131.h49
-rw-r--r--drivers/media/dvb/frontends/mt2131_priv.h44
5 files changed, 409 insertions, 0 deletions
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index ba70ad0c3f05..c3c8af771f80 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -329,6 +329,13 @@ config DVB_TUNER_MT2266
329 help 329 help
330 A driver for the silicon baseband tuner MT2266 from Microtune. 330 A driver for the silicon baseband tuner MT2266 from Microtune.
331 331
332config DVB_TUNER_MT2131
333 tristate "Microtune MT2131 silicon tuner"
334 depends on I2C
335 default m if DVB_FE_CUSTOMISE
336 help
337 A driver for the silicon baseband tuner MT2131 from Microtune.
338
332comment "Miscellaneous devices" 339comment "Miscellaneous devices"
333 depends on DVB_CORE 340 depends on DVB_CORE
334 341
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 217265ca2849..a8cfa03b273c 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -43,3 +43,4 @@ obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o
43obj-$(CONFIG_DVB_TUNER_MT2266) += mt2266.o 43obj-$(CONFIG_DVB_TUNER_MT2266) += mt2266.o
44obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o 44obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o
45obj-$(CONFIG_DVB_TUA6100) += tua6100.o 45obj-$(CONFIG_DVB_TUA6100) += tua6100.o
46obj-$(CONFIG_DVB_TUNER_MT2131) += mt2131.o
diff --git a/drivers/media/dvb/frontends/mt2131.c b/drivers/media/dvb/frontends/mt2131.c
new file mode 100644
index 000000000000..4fe1e62c9f06
--- /dev/null
+++ b/drivers/media/dvb/frontends/mt2131.c
@@ -0,0 +1,308 @@
1/*
2 * Driver for Microtune MT2131 "QAM/8VSB single chip tuner"
3 *
4 * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
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 *
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#include <linux/module.h>
23#include <linux/moduleparam.h>
24#include <linux/delay.h>
25#include <linux/dvb/frontend.h>
26#include <linux/i2c.h>
27
28#include "dvb_frontend.h"
29
30#include "mt2131.h"
31#include "mt2131_priv.h"
32
33static int debug;
34module_param(debug, int, 0644);
35MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
36
37#define dprintk(level,fmt, arg...) if (debug >= level) \
38 printk(KERN_INFO "%s: " fmt, "mt2131", ## arg)
39
40static u8 mt2131_config1[] = {
41 0x01,
42 0x50, 0x00, 0x50, 0x80, 0x00, 0x49, 0xfa, 0x88,
43 0x08, 0x77, 0x41, 0x04, 0x00, 0x00, 0x00, 0x32,
44 0x7f, 0xda, 0x4c, 0x00, 0x10, 0xaa, 0x78, 0x80,
45 0xff, 0x68, 0xa0, 0xff, 0xdd, 0x00, 0x00
46};
47
48static u8 mt2131_config2[] = {
49 0x10,
50 0x7f, 0xc8, 0x0a, 0x5f, 0x00, 0x04
51};
52
53static int mt2131_readreg(struct mt2131_priv *priv, u8 reg, u8 *val)
54{
55 struct i2c_msg msg[2] = {
56 { .addr = priv->cfg->i2c_address, .flags = 0, .buf = &reg, .len = 1 },
57 { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = val, .len = 1 },
58 };
59
60 if (i2c_transfer(priv->i2c, msg, 2) != 2) {
61 printk(KERN_WARNING "mt2131 I2C read failed\n");
62 return -EREMOTEIO;
63 }
64 return 0;
65}
66
67static int mt2131_writereg(struct mt2131_priv *priv, u8 reg, u8 val)
68{
69 u8 buf[2] = { reg, val };
70 struct i2c_msg msg = { .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2 };
71
72 if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
73 printk(KERN_WARNING "mt2131 I2C write failed\n");
74 return -EREMOTEIO;
75 }
76 return 0;
77}
78
79static int mt2131_writeregs(struct mt2131_priv *priv,u8 *buf, u8 len)
80{
81 struct i2c_msg msg = { .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = len };
82
83 if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
84 printk(KERN_WARNING "mt2131 I2C write failed (len=%i)\n",(int)len);
85 return -EREMOTEIO;
86 }
87 return 0;
88}
89
90static int mt2131_set_gpo(struct dvb_frontend *fe, u8 val)
91{
92 struct mt2131_priv *priv = fe->tuner_priv;
93 u8 v;
94
95 mt2131_readreg(priv, 0x07, &v);
96 mt2131_writereg(priv, 0x07, (v & 0xfe) | (val & 0x01));
97
98 return 0;
99}
100
101static int mt2131_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
102{
103 struct mt2131_priv *priv;
104 int ret=0, i;
105 u32 freq;
106 u8 if_band_center;
107 u32 f_lo1,f_lo2;
108 u32 div1,num1,div2,num2;
109 u8 b[8];
110 u8 lockval = 0;
111
112 priv = fe->tuner_priv;
113 if (fe->ops.info.type == FE_OFDM)
114 priv->bandwidth = params->u.ofdm.bandwidth;
115 else
116 priv->bandwidth = 0;
117
118 freq = params->frequency / 1000; // Hz -> kHz
119 dprintk(1, "%s() freq=%d\n", __FUNCTION__, freq);
120
121 f_lo1 = freq + MT2131_IF1 * 1000;
122 f_lo1 = (f_lo1 / 250) * 250;
123 f_lo2 = f_lo1 - freq - MT2131_IF2;
124
125 priv->frequency = (f_lo1 - f_lo2 - MT2131_IF2) * 1000,
126
127 /* Frequency LO1 = 16MHz * (DIV1 + NUM1/8192 ) */
128 num1 = f_lo1 * 64 / (MT2131_FREF / 128);
129 div1 = num1 / 8192;
130 num1 &= 0x1fff;
131
132 /* Frequency LO2 = 16MHz * (DIV2 + NUM2/8192 ) */
133 num2 = f_lo2 * 64 / (MT2131_FREF / 128);
134 div2 = num2 / 8192;
135 num2 &= 0x1fff;
136
137 if (freq <= 82500) if_band_center = 0x00; else
138 if (freq <= 137500) if_band_center = 0x01; else
139 if (freq <= 192500) if_band_center = 0x02; else
140 if (freq <= 247500) if_band_center = 0x03; else
141 if (freq <= 302500) if_band_center = 0x04; else
142 if (freq <= 357500) if_band_center = 0x05; else
143 if (freq <= 412500) if_band_center = 0x06; else
144 if (freq <= 467500) if_band_center = 0x07; else
145 if (freq <= 522500) if_band_center = 0x08; else
146 if (freq <= 577500) if_band_center = 0x09; else
147 if (freq <= 632500) if_band_center = 0x0A; else
148 if (freq <= 687500) if_band_center = 0x0B; else
149 if (freq <= 742500) if_band_center = 0x0C; else
150 if (freq <= 797500) if_band_center = 0x0D; else
151 if (freq <= 852500) if_band_center = 0x0E; else
152 if (freq <= 907500) if_band_center = 0x0F; else
153 if (freq <= 962500) if_band_center = 0x10; else
154 if (freq <= 1017500) if_band_center = 0x11; else
155 if (freq <= 1072500) if_band_center = 0x12; else if_band_center = 0x13;
156
157 b[0] = 1;
158 b[1] = (num1 >> 5) & 0xFF;
159 b[2] = (num1 & 0x1F);
160 b[3] = div1;
161 b[4] = (num2 >> 5) & 0xFF;
162 b[5] = num2 & 0x1F;
163 b[6] = div2;
164
165 dprintk(1, "IF1: %dMHz IF2: %dMHz\n", MT2131_IF1, MT2131_IF2);
166 dprintk(1, "PLL freq=%dkHz band=%d\n", (int)freq, (int)if_band_center);
167 dprintk(1, "PLL f_lo1=%dkHz f_lo2=%dkHz\n", (int)f_lo1, (int)f_lo2);
168 dprintk(1, "PLL div1=%d num1=%d div2=%d num2=%d\n",
169 (int)div1, (int)num1, (int)div2, (int)num2);
170 dprintk(1, "PLL [1..6]: %2x %2x %2x %2x %2x %2x\n",
171 (int)b[1], (int)b[2], (int)b[3], (int)b[4], (int)b[5],
172 (int)b[6]);
173
174 ret = mt2131_writeregs(priv,b,7);
175 if (ret < 0)
176 return ret;
177
178 mt2131_writereg(priv, 0x0b, if_band_center);
179
180 /* Wait for lock */
181 i = 0;
182 do {
183 mt2131_readreg(priv, 0x08, &lockval);
184 if ((lockval & 0x88) == 0x88)
185 break;
186 msleep(4);
187 i++;
188 } while (i < 10);
189
190 return ret;
191}
192
193static int mt2131_get_frequency(struct dvb_frontend *fe, u32 *frequency)
194{
195 struct mt2131_priv *priv = fe->tuner_priv;
196 dprintk(1, "%s()\n", __FUNCTION__);
197 *frequency = priv->frequency;
198 return 0;
199}
200
201static int mt2131_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
202{
203 struct mt2131_priv *priv = fe->tuner_priv;
204 dprintk(1, "%s()\n", __FUNCTION__);
205 *bandwidth = priv->bandwidth;
206 return 0;
207}
208
209static int mt2131_get_status(struct dvb_frontend *fe, u32 *status)
210{
211 struct mt2131_priv *priv = fe->tuner_priv;
212 u8 lock_status = 0;
213 u8 afc_status = 0;
214
215 *status = 0;
216
217 mt2131_readreg(priv, 0x08, &lock_status);
218 if ((lock_status & 0x88) == 0x88)
219 *status = TUNER_STATUS_LOCKED;
220
221 mt2131_readreg(priv, 0x09, &afc_status);
222 dprintk(1, "%s() - LO Status = 0x%x, AFC Status = 0x%x\n",
223 __FUNCTION__, lock_status, afc_status);
224
225 return 0;
226}
227
228static int mt2131_init(struct dvb_frontend *fe)
229{
230 struct mt2131_priv *priv = fe->tuner_priv;
231 int ret;
232 dprintk(1, "%s()\n", __FUNCTION__);
233
234 if ((ret = mt2131_writeregs(priv, mt2131_config1, sizeof(mt2131_config1))) < 0)
235 return ret;
236
237 mt2131_writereg(priv, 0x0b, 0x09);
238 mt2131_writereg(priv, 0x15, 0x47);
239 mt2131_writereg(priv, 0x07, 0xf2);
240 mt2131_writereg(priv, 0x0b, 0x01);
241
242 if ((ret = mt2131_writeregs(priv, mt2131_config2, sizeof(mt2131_config2))) < 0)
243 return ret;
244
245 return ret;
246}
247
248static int mt2131_release(struct dvb_frontend *fe)
249{
250 dprintk(1, "%s()\n", __FUNCTION__);
251 kfree(fe->tuner_priv);
252 fe->tuner_priv = NULL;
253 return 0;
254}
255
256static const struct dvb_tuner_ops mt2131_tuner_ops = {
257 .info = {
258 .name = "Microtune MT2131",
259 .frequency_min = 48000000,
260 .frequency_max = 860000000,
261 .frequency_step = 50000,
262 },
263
264 .release = mt2131_release,
265 .init = mt2131_init,
266
267 .set_params = mt2131_set_params,
268 .get_frequency = mt2131_get_frequency,
269 .get_bandwidth = mt2131_get_bandwidth,
270 .get_status = mt2131_get_status
271};
272
273struct dvb_frontend * mt2131_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2131_config *cfg, u16 if1)
274{
275 struct mt2131_priv *priv = NULL;
276 u8 id = 0;
277
278 dprintk(1, "%s()\n", __FUNCTION__);
279
280 priv = kzalloc(sizeof(struct mt2131_priv), GFP_KERNEL);
281 if (priv == NULL)
282 return NULL;
283
284 priv->cfg = cfg;
285 priv->bandwidth = 6000000; /* 6MHz */
286 priv->i2c = i2c;
287
288 if (mt2131_readreg(priv, 0, &id) != 0) {
289 kfree(priv);
290 return NULL;
291 }
292 if ( (id != 0x3E) && (id != 0x3F) ) {
293 printk(KERN_ERR "MT2131: Device not found at addr 0x%02x\n", cfg->i2c_address);
294 kfree(priv);
295 return NULL;
296 }
297
298 printk(KERN_INFO "MT2131: successfully identified at address 0x%02x\n", cfg->i2c_address);
299 memcpy(&fe->ops.tuner_ops, &mt2131_tuner_ops, sizeof(struct dvb_tuner_ops));
300
301 fe->tuner_priv = priv;
302 return fe;
303}
304EXPORT_SYMBOL(mt2131_attach);
305
306MODULE_AUTHOR("Steven Toth");
307MODULE_DESCRIPTION("Microtune MT2131 silicon tuner driver");
308MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/mt2131.h b/drivers/media/dvb/frontends/mt2131.h
new file mode 100644
index 000000000000..5d1f281d87b2
--- /dev/null
+++ b/drivers/media/dvb/frontends/mt2131.h
@@ -0,0 +1,49 @@
1/*
2 * Driver for Microtune MT2131 "QAM/8VSB single chip tuner"
3 *
4 * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
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 *
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#ifndef __MT2131_H__
23#define __MT2131_H__
24
25struct dvb_frontend;
26struct i2c_adapter;
27
28struct mt2131_config {
29 u8 i2c_address;
30 u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */
31};
32
33#if defined(CONFIG_DVB_TUNER_MT2131) || defined(CONFIG_DVB_TUNER_MT2131_MODULE)
34extern struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe,
35 struct i2c_adapter *i2c,
36 struct mt2131_config *cfg,
37 u16 if1);
38#else
39static inline struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe,
40 struct i2c_adapter *i2c,
41 struct mt2131_config *cfg,
42 u16 if1)
43{
44 printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
45 return NULL;
46}
47#endif // CONFIG_DVB_TUNER_MT2131
48
49#endif // __MT2131_H__
diff --git a/drivers/media/dvb/frontends/mt2131_priv.h b/drivers/media/dvb/frontends/mt2131_priv.h
new file mode 100644
index 000000000000..fe6333b49c93
--- /dev/null
+++ b/drivers/media/dvb/frontends/mt2131_priv.h
@@ -0,0 +1,44 @@
1/*
2 * Driver for Microtune MT2131 "QAM/8VSB single chip tuner"
3 *
4 * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
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 *
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#ifndef MT2131_PRIV_H
23#define MT2131_PRIV_H
24
25/* Regs */
26#define MT2131_PWR 0x07
27#define MT2131_UPC_1 0x0b
28#define MT2131_AGC_RL 0x10
29#define MT2131_MISC_2 0x15
30
31/* frequency values in KHz */
32#define MT2131_IF1 1220
33#define MT2131_IF2 44000
34#define MT2131_FREF 16000
35
36struct mt2131_priv {
37 struct mt2131_config *cfg;
38 struct i2c_adapter *i2c;
39
40 u32 frequency;
41 u32 bandwidth;
42};
43
44#endif