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