Linux 2.6.34-rc3
[pohmelfs.git] / drivers / media / dvb / frontends / lgdt3304.c
blobe334b5d4e5785d1ad93a07f46d808cbea87edecd
1 /*
2 * Driver for LG ATSC lgdt3304 driver
4 * Copyright (C) 2008 Markus Rechberger <mrechberger@sundtek.de>
6 */
8 #include <linux/kernel.h>
9 #include <linux/module.h>
10 #include <linux/delay.h>
11 #include "dvb_frontend.h"
12 #include "lgdt3304.h"
14 static unsigned int debug = 0;
15 module_param(debug, int, 0644);
16 MODULE_PARM_DESC(debug,"lgdt3304 debugging (default off)");
18 #define dprintk(fmt, args...) if (debug) do {\
19 printk("lgdt3304 debug: " fmt, ##args); } while (0)
21 struct lgdt3304_state
23 struct dvb_frontend frontend;
24 fe_modulation_t current_modulation;
25 __u32 snr;
26 __u32 current_frequency;
27 __u8 addr;
28 struct i2c_adapter *i2c;
31 static int i2c_write_demod_bytes (struct dvb_frontend *fe, __u8 *buf, int len)
33 struct lgdt3304_state *state = fe->demodulator_priv;
34 struct i2c_msg i2cmsgs = {
35 .addr = state->addr,
36 .flags = 0,
37 .len = 3,
38 .buf = buf
40 int i;
41 int err;
43 for (i=0; i<len-1; i+=3){
44 if((err = i2c_transfer(state->i2c, &i2cmsgs, 1))<0) {
45 printk("%s i2c_transfer error %d\n", __func__, err);
46 if (err < 0)
47 return err;
48 else
49 return -EREMOTEIO;
51 i2cmsgs.buf += 3;
53 return 0;
56 static int lgdt3304_i2c_read_reg(struct dvb_frontend *fe, unsigned int reg)
58 struct lgdt3304_state *state = fe->demodulator_priv;
59 struct i2c_msg i2cmsgs[2];
60 int ret;
61 __u8 buf;
63 __u8 regbuf[2] = { reg>>8, reg&0xff };
65 i2cmsgs[0].addr = state->addr;
66 i2cmsgs[0].flags = 0;
67 i2cmsgs[0].len = 2;
68 i2cmsgs[0].buf = regbuf;
70 i2cmsgs[1].addr = state->addr;
71 i2cmsgs[1].flags = I2C_M_RD;
72 i2cmsgs[1].len = 1;
73 i2cmsgs[1].buf = &buf;
75 if((ret = i2c_transfer(state->i2c, i2cmsgs, 2))<0) {
76 printk("%s i2c_transfer error %d\n", __func__, ret);
77 return ret;
80 return buf;
83 static int lgdt3304_i2c_write_reg(struct dvb_frontend *fe, int reg, int val)
85 struct lgdt3304_state *state = fe->demodulator_priv;
86 char buffer[3] = { reg>>8, reg&0xff, val };
87 int ret;
89 struct i2c_msg i2cmsgs = {
90 .addr = state->addr,
91 .flags = 0,
92 .len = 3,
93 .buf=buffer
95 ret = i2c_transfer(state->i2c, &i2cmsgs, 1);
96 if (ret != 1) {
97 printk("%s i2c_transfer error %d\n", __func__, ret);
98 return ret;
101 return 0;
105 static int lgdt3304_soft_Reset(struct dvb_frontend *fe)
107 lgdt3304_i2c_write_reg(fe, 0x0002, 0x9a);
108 lgdt3304_i2c_write_reg(fe, 0x0002, 0x9b);
109 mdelay(200);
110 return 0;
113 static int lgdt3304_set_parameters(struct dvb_frontend *fe, struct dvb_frontend_parameters *param) {
114 int err = 0;
116 static __u8 lgdt3304_vsb8_data[] = {
117 /* 16bit , 8bit */
118 /* regs , val */
119 0x00, 0x00, 0x02,
120 0x00, 0x00, 0x13,
121 0x00, 0x0d, 0x02,
122 0x00, 0x0e, 0x02,
123 0x00, 0x12, 0x32,
124 0x00, 0x13, 0xc4,
125 0x01, 0x12, 0x17,
126 0x01, 0x13, 0x15,
127 0x01, 0x14, 0x18,
128 0x01, 0x15, 0xff,
129 0x01, 0x16, 0x2c,
130 0x02, 0x14, 0x67,
131 0x02, 0x24, 0x8d,
132 0x04, 0x27, 0x12,
133 0x04, 0x28, 0x4f,
134 0x03, 0x08, 0x80,
135 0x03, 0x09, 0x00,
136 0x03, 0x0d, 0x00,
137 0x03, 0x0e, 0x1c,
138 0x03, 0x14, 0xe1,
139 0x05, 0x0e, 0x5b,
142 /* not yet tested .. */
143 static __u8 lgdt3304_qam64_data[] = {
144 /* 16bit , 8bit */
145 /* regs , val */
146 0x00, 0x00, 0x18,
147 0x00, 0x0d, 0x02,
148 //0x00, 0x0e, 0x02,
149 0x00, 0x12, 0x2a,
150 0x00, 0x13, 0x00,
151 0x03, 0x14, 0xe3,
152 0x03, 0x0e, 0x1c,
153 0x03, 0x08, 0x66,
154 0x03, 0x09, 0x66,
155 0x03, 0x0a, 0x08,
156 0x03, 0x0b, 0x9b,
157 0x05, 0x0e, 0x5b,
161 /* tested with KWorld a340 */
162 static __u8 lgdt3304_qam256_data[] = {
163 /* 16bit , 8bit */
164 /* regs , val */
165 0x00, 0x00, 0x01, //0x19,
166 0x00, 0x12, 0x2a,
167 0x00, 0x13, 0x80,
168 0x00, 0x0d, 0x02,
169 0x03, 0x14, 0xe3,
171 0x03, 0x0e, 0x1c,
172 0x03, 0x08, 0x66,
173 0x03, 0x09, 0x66,
174 0x03, 0x0a, 0x08,
175 0x03, 0x0b, 0x9b,
177 0x03, 0x0d, 0x14,
178 //0x05, 0x0e, 0x5b,
179 0x01, 0x06, 0x4a,
180 0x01, 0x07, 0x3d,
181 0x01, 0x08, 0x70,
182 0x01, 0x09, 0xa3,
184 0x05, 0x04, 0xfd,
186 0x00, 0x0d, 0x82,
188 0x05, 0x0e, 0x5b,
190 0x05, 0x0e, 0x5b,
192 0x00, 0x02, 0x9a,
194 0x00, 0x02, 0x9b,
196 0x00, 0x00, 0x01,
197 0x00, 0x12, 0x2a,
198 0x00, 0x13, 0x80,
199 0x00, 0x0d, 0x02,
200 0x03, 0x14, 0xe3,
202 0x03, 0x0e, 0x1c,
203 0x03, 0x08, 0x66,
204 0x03, 0x09, 0x66,
205 0x03, 0x0a, 0x08,
206 0x03, 0x0b, 0x9b,
208 0x03, 0x0d, 0x14,
209 0x01, 0x06, 0x4a,
210 0x01, 0x07, 0x3d,
211 0x01, 0x08, 0x70,
212 0x01, 0x09, 0xa3,
214 0x05, 0x04, 0xfd,
216 0x00, 0x0d, 0x82,
218 0x05, 0x0e, 0x5b,
221 struct lgdt3304_state *state = fe->demodulator_priv;
222 if (state->current_modulation != param->u.vsb.modulation) {
223 switch(param->u.vsb.modulation) {
224 case VSB_8:
225 err = i2c_write_demod_bytes(fe, lgdt3304_vsb8_data,
226 sizeof(lgdt3304_vsb8_data));
227 break;
228 case QAM_64:
229 err = i2c_write_demod_bytes(fe, lgdt3304_qam64_data,
230 sizeof(lgdt3304_qam64_data));
231 break;
232 case QAM_256:
233 err = i2c_write_demod_bytes(fe, lgdt3304_qam256_data,
234 sizeof(lgdt3304_qam256_data));
235 break;
236 default:
237 break;
240 if (err) {
241 printk("%s error setting modulation\n", __func__);
242 } else {
243 state->current_modulation = param->u.vsb.modulation;
246 state->current_frequency = param->frequency;
248 lgdt3304_soft_Reset(fe);
251 if (fe->ops.tuner_ops.set_params)
252 fe->ops.tuner_ops.set_params(fe, param);
254 return 0;
257 static int lgdt3304_init(struct dvb_frontend *fe) {
258 return 0;
261 static int lgdt3304_sleep(struct dvb_frontend *fe) {
262 return 0;
266 static int lgdt3304_read_status(struct dvb_frontend *fe, fe_status_t *status)
268 struct lgdt3304_state *state = fe->demodulator_priv;
269 int r011d;
270 int qam_lck;
272 *status = 0;
273 dprintk("lgdt read status\n");
275 r011d = lgdt3304_i2c_read_reg(fe, 0x011d);
277 dprintk("%02x\n", r011d);
279 switch(state->current_modulation) {
280 case VSB_8:
281 if (r011d & 0x80) {
282 dprintk("VSB Locked\n");
283 *status |= FE_HAS_CARRIER;
284 *status |= FE_HAS_LOCK;
285 *status |= FE_HAS_SYNC;
286 *status |= FE_HAS_SIGNAL;
288 break;
289 case QAM_64:
290 case QAM_256:
291 qam_lck = r011d & 0x7;
292 switch(qam_lck) {
293 case 0x0: dprintk("Unlock\n");
294 break;
295 case 0x4: dprintk("1st Lock in acquisition state\n");
296 break;
297 case 0x6: dprintk("2nd Lock in acquisition state\n");
298 break;
299 case 0x7: dprintk("Final Lock in good reception state\n");
300 *status |= FE_HAS_CARRIER;
301 *status |= FE_HAS_LOCK;
302 *status |= FE_HAS_SYNC;
303 *status |= FE_HAS_SIGNAL;
304 break;
306 break;
307 default:
308 printk("%s unhandled modulation\n", __func__);
312 return 0;
315 static int lgdt3304_read_ber(struct dvb_frontend *fe, __u32 *ber)
317 dprintk("read ber\n");
318 return 0;
321 static int lgdt3304_read_snr(struct dvb_frontend *fe, __u16 *snr)
323 dprintk("read snr\n");
324 return 0;
327 static int lgdt3304_read_ucblocks(struct dvb_frontend *fe, __u32 *ucblocks)
329 dprintk("read ucblocks\n");
330 return 0;
333 static void lgdt3304_release(struct dvb_frontend *fe)
335 struct lgdt3304_state *state = (struct lgdt3304_state *)fe->demodulator_priv;
336 kfree(state);
339 static struct dvb_frontend_ops demod_lgdt3304={
340 .info = {
341 .name = "LG 3304",
342 .type = FE_ATSC,
343 .frequency_min = 54000000,
344 .frequency_max = 858000000,
345 .frequency_stepsize = 62500,
346 .symbol_rate_min = 5056941,
347 .symbol_rate_max = 10762000,
348 .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
350 .init = lgdt3304_init,
351 .sleep = lgdt3304_sleep,
352 .set_frontend = lgdt3304_set_parameters,
353 .read_snr = lgdt3304_read_snr,
354 .read_ber = lgdt3304_read_ber,
355 .read_status = lgdt3304_read_status,
356 .read_ucblocks = lgdt3304_read_ucblocks,
357 .release = lgdt3304_release,
360 struct dvb_frontend* lgdt3304_attach(const struct lgdt3304_config *config,
361 struct i2c_adapter *i2c)
364 struct lgdt3304_state *state;
365 state = kzalloc(sizeof(struct lgdt3304_state), GFP_KERNEL);
366 if (state == NULL)
367 return NULL;
368 state->addr = config->i2c_address;
369 state->i2c = i2c;
371 memcpy(&state->frontend.ops, &demod_lgdt3304, sizeof(struct dvb_frontend_ops));
372 state->frontend.demodulator_priv = state;
373 return &state->frontend;
376 EXPORT_SYMBOL_GPL(lgdt3304_attach);
377 MODULE_AUTHOR("Markus Rechberger <mrechberger@empiatech.com>");
378 MODULE_DESCRIPTION("LGE LGDT3304 DVB-T demodulator driver");
379 MODULE_LICENSE("GPL");