V4L/DVB (10452): Add Freescale MC44S803 tuner driver
[linux-2.6/libata-dev.git] / drivers / media / common / tuners / mc44s803.c
blob20c4485ce16a642a9724af9efb1cfed2667e64b3
1 /*
2 * Driver for Freescale MC44S803 Low Power CMOS Broadband Tuner
4 * Copyright (c) 2009 Jochen Friedrich <jochen@scram.de>
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.
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
15 * GNU General Public License for more details.
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.=
22 #include <linux/module.h>
23 #include <linux/delay.h>
24 #include <linux/dvb/frontend.h>
25 #include <linux/i2c.h>
27 #include "dvb_frontend.h"
29 #include "mc44s803.h"
30 #include "mc44s803_priv.h"
32 #define mc_printk(level, format, arg...) \
33 printk(level "mc44s803: " format , ## arg)
35 /* Writes a single register */
36 static int mc44s803_writereg(struct mc44s803_priv *priv, u32 val)
38 u8 buf[3];
39 struct i2c_msg msg = {
40 .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 3
43 buf[0] = (val & 0xff0000) >> 16;
44 buf[1] = (val & 0xff00) >> 8;
45 buf[2] = (val & 0xff);
47 if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
48 mc_printk(KERN_WARNING, "I2C write failed\n");
49 return -EREMOTEIO;
51 return 0;
54 /* Reads a single register */
55 static int mc44s803_readreg(struct mc44s803_priv *priv, u8 reg, u32 *val)
57 u32 wval;
58 u8 buf[3];
59 int ret;
60 struct i2c_msg msg[] = {
61 { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD,
62 .buf = buf, .len = 3 },
65 wval = MC44S803_REG_SM(MC44S803_REG_DATAREG, MC44S803_ADDR) |
66 MC44S803_REG_SM(reg, MC44S803_D);
68 ret = mc44s803_writereg(priv, wval);
69 if (ret)
70 return ret;
72 if (i2c_transfer(priv->i2c, msg, 1) != 1) {
73 mc_printk(KERN_WARNING, "I2C read failed\n");
74 return -EREMOTEIO;
77 *val = (buf[0] << 16) | (buf[1] << 8) | buf[2];
79 return 0;
82 static int mc44s803_release(struct dvb_frontend *fe)
84 struct mc44s803_priv *priv = fe->tuner_priv;
86 fe->tuner_priv = NULL;
87 kfree(priv);
89 return 0;
92 static int mc44s803_init(struct dvb_frontend *fe)
94 struct mc44s803_priv *priv = fe->tuner_priv;
95 u32 val;
96 int err;
98 if (fe->ops.i2c_gate_ctrl)
99 fe->ops.i2c_gate_ctrl(fe, 1);
101 /* Reset chip */
102 val = MC44S803_REG_SM(MC44S803_REG_RESET, MC44S803_ADDR) |
103 MC44S803_REG_SM(1, MC44S803_RS);
105 err = mc44s803_writereg(priv, val);
106 if (err)
107 goto exit;
109 val = MC44S803_REG_SM(MC44S803_REG_RESET, MC44S803_ADDR);
111 err = mc44s803_writereg(priv, val);
112 if (err)
113 goto exit;
115 /* Power Up and Start Osc */
117 val = MC44S803_REG_SM(MC44S803_REG_REFOSC, MC44S803_ADDR) |
118 MC44S803_REG_SM(0xC0, MC44S803_REFOSC) |
119 MC44S803_REG_SM(1, MC44S803_OSCSEL);
121 err = mc44s803_writereg(priv, val);
122 if (err)
123 goto exit;
125 val = MC44S803_REG_SM(MC44S803_REG_POWER, MC44S803_ADDR) |
126 MC44S803_REG_SM(0x200, MC44S803_POWER);
128 err = mc44s803_writereg(priv, val);
129 if (err)
130 goto exit;
132 msleep(10);
134 val = MC44S803_REG_SM(MC44S803_REG_REFOSC, MC44S803_ADDR) |
135 MC44S803_REG_SM(0x40, MC44S803_REFOSC) |
136 MC44S803_REG_SM(1, MC44S803_OSCSEL);
138 err = mc44s803_writereg(priv, val);
139 if (err)
140 goto exit;
142 msleep(20);
144 /* Setup Mixer */
146 val = MC44S803_REG_SM(MC44S803_REG_MIXER, MC44S803_ADDR) |
147 MC44S803_REG_SM(1, MC44S803_TRI_STATE) |
148 MC44S803_REG_SM(0x7F, MC44S803_MIXER_RES);
150 err = mc44s803_writereg(priv, val);
151 if (err)
152 goto exit;
154 /* Setup Cirquit Adjust */
156 val = MC44S803_REG_SM(MC44S803_REG_CIRCADJ, MC44S803_ADDR) |
157 MC44S803_REG_SM(1, MC44S803_G1) |
158 MC44S803_REG_SM(1, MC44S803_G3) |
159 MC44S803_REG_SM(0x3, MC44S803_CIRCADJ_RES) |
160 MC44S803_REG_SM(1, MC44S803_G6) |
161 MC44S803_REG_SM(priv->cfg->dig_out, MC44S803_S1) |
162 MC44S803_REG_SM(0x3, MC44S803_LP) |
163 MC44S803_REG_SM(1, MC44S803_CLRF) |
164 MC44S803_REG_SM(1, MC44S803_CLIF);
166 err = mc44s803_writereg(priv, val);
167 if (err)
168 goto exit;
170 val = MC44S803_REG_SM(MC44S803_REG_CIRCADJ, MC44S803_ADDR) |
171 MC44S803_REG_SM(1, MC44S803_G1) |
172 MC44S803_REG_SM(1, MC44S803_G3) |
173 MC44S803_REG_SM(0x3, MC44S803_CIRCADJ_RES) |
174 MC44S803_REG_SM(1, MC44S803_G6) |
175 MC44S803_REG_SM(priv->cfg->dig_out, MC44S803_S1) |
176 MC44S803_REG_SM(0x3, MC44S803_LP);
178 err = mc44s803_writereg(priv, val);
179 if (err)
180 goto exit;
182 /* Setup Digtune */
184 val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) |
185 MC44S803_REG_SM(3, MC44S803_XOD);
187 err = mc44s803_writereg(priv, val);
188 if (err)
189 goto exit;
191 /* Setup AGC */
193 val = MC44S803_REG_SM(MC44S803_REG_LNAAGC, MC44S803_ADDR) |
194 MC44S803_REG_SM(1, MC44S803_AT1) |
195 MC44S803_REG_SM(1, MC44S803_AT2) |
196 MC44S803_REG_SM(1, MC44S803_AGC_AN_DIG) |
197 MC44S803_REG_SM(1, MC44S803_AGC_READ_EN) |
198 MC44S803_REG_SM(1, MC44S803_LNA0);
200 err = mc44s803_writereg(priv, val);
201 if (err)
202 goto exit;
204 if (fe->ops.i2c_gate_ctrl)
205 fe->ops.i2c_gate_ctrl(fe, 0);
206 return 0;
208 exit:
209 if (fe->ops.i2c_gate_ctrl)
210 fe->ops.i2c_gate_ctrl(fe, 0);
212 mc_printk(KERN_WARNING, "I/O Error\n");
213 return err;
216 static int mc44s803_set_params(struct dvb_frontend *fe,
217 struct dvb_frontend_parameters *params)
219 struct mc44s803_priv *priv = fe->tuner_priv;
220 u32 r1, r2, n1, n2, lo1, lo2, freq, val;
221 int err;
223 priv->frequency = params->frequency;
225 r1 = MC44S803_OSC / 1000000;
226 r2 = MC44S803_OSC / 100000;
228 n1 = (params->frequency + MC44S803_IF1 + 500000) / 1000000;
229 freq = MC44S803_OSC / r1 * n1;
230 lo1 = ((60 * n1) + (r1 / 2)) / r1;
231 freq = freq - params->frequency;
233 n2 = (freq - MC44S803_IF2 + 50000) / 100000;
234 lo2 = ((60 * n2) + (r2 / 2)) / r2;
236 if (fe->ops.i2c_gate_ctrl)
237 fe->ops.i2c_gate_ctrl(fe, 1);
239 val = MC44S803_REG_SM(MC44S803_REG_REFDIV, MC44S803_ADDR) |
240 MC44S803_REG_SM(r1-1, MC44S803_R1) |
241 MC44S803_REG_SM(r2-1, MC44S803_R2) |
242 MC44S803_REG_SM(1, MC44S803_REFBUF_EN);
244 err = mc44s803_writereg(priv, val);
245 if (err)
246 goto exit;
248 val = MC44S803_REG_SM(MC44S803_REG_LO1, MC44S803_ADDR) |
249 MC44S803_REG_SM(n1-2, MC44S803_LO1);
251 err = mc44s803_writereg(priv, val);
252 if (err)
253 goto exit;
255 val = MC44S803_REG_SM(MC44S803_REG_LO2, MC44S803_ADDR) |
256 MC44S803_REG_SM(n2-2, MC44S803_LO2);
258 err = mc44s803_writereg(priv, val);
259 if (err)
260 goto exit;
262 val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) |
263 MC44S803_REG_SM(1, MC44S803_DA) |
264 MC44S803_REG_SM(lo1, MC44S803_LO_REF) |
265 MC44S803_REG_SM(1, MC44S803_AT);
267 err = mc44s803_writereg(priv, val);
268 if (err)
269 goto exit;
271 val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) |
272 MC44S803_REG_SM(2, MC44S803_DA) |
273 MC44S803_REG_SM(lo2, MC44S803_LO_REF) |
274 MC44S803_REG_SM(1, MC44S803_AT);
276 err = mc44s803_writereg(priv, val);
277 if (err)
278 goto exit;
280 if (fe->ops.i2c_gate_ctrl)
281 fe->ops.i2c_gate_ctrl(fe, 0);
283 return 0;
285 exit:
286 if (fe->ops.i2c_gate_ctrl)
287 fe->ops.i2c_gate_ctrl(fe, 0);
289 mc_printk(KERN_WARNING, "I/O Error\n");
290 return err;
293 static int mc44s803_get_frequency(struct dvb_frontend *fe, u32 *frequency)
295 struct mc44s803_priv *priv = fe->tuner_priv;
296 *frequency = priv->frequency;
297 return 0;
300 static const struct dvb_tuner_ops mc44s803_tuner_ops = {
301 .info = {
302 .name = "Freescale MC44S803",
303 .frequency_min = 48000000,
304 .frequency_max = 1000000000,
305 .frequency_step = 100000,
308 .release = mc44s803_release,
309 .init = mc44s803_init,
310 .set_params = mc44s803_set_params,
311 .get_frequency = mc44s803_get_frequency
314 /* This functions tries to identify a MC44S803 tuner by reading the ID
315 register. This is hasty. */
316 struct dvb_frontend *mc44s803_attach(struct dvb_frontend *fe,
317 struct i2c_adapter *i2c, struct mc44s803_config *cfg)
319 struct mc44s803_priv *priv;
320 u32 reg;
321 u8 id;
322 int ret;
324 reg = 0;
326 priv = kzalloc(sizeof(struct mc44s803_priv), GFP_KERNEL);
327 if (priv == NULL)
328 return NULL;
330 priv->cfg = cfg;
331 priv->i2c = i2c;
332 priv->fe = fe;
334 if (fe->ops.i2c_gate_ctrl)
335 fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
337 ret = mc44s803_readreg(priv, MC44S803_REG_ID, &reg);
338 if (ret)
339 goto error;
341 id = MC44S803_REG_MS(reg, MC44S803_ID);
343 if (id != 0x14) {
344 mc_printk(KERN_ERR, "unsupported ID "
345 "(%x should be 0x14)\n", id);
346 goto error;
349 mc_printk(KERN_INFO, "successfully identified (ID = %x)\n", id);
350 memcpy(&fe->ops.tuner_ops, &mc44s803_tuner_ops,
351 sizeof(struct dvb_tuner_ops));
353 fe->tuner_priv = priv;
355 if (fe->ops.i2c_gate_ctrl)
356 fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
358 return fe;
360 error:
361 if (fe->ops.i2c_gate_ctrl)
362 fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
364 kfree(priv);
365 return NULL;
367 EXPORT_SYMBOL(mc44s803_attach);
369 MODULE_AUTHOR("Jochen Friedrich");
370 MODULE_DESCRIPTION("Freescale MC44S803 silicon tuner driver");
371 MODULE_LICENSE("GPL");