2 Legend Silicon LGS-8GL5 DMB-TH OFDM demodulator driver
4 Copyright (C) 2008 Sirius International (Hong Kong) Limited
5 Timothy Lee <timothy.lee@siriushk.com>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 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.
23 #include <linux/kernel.h>
24 #include <linux/init.h>
25 #include <linux/module.h>
26 #include <linux/string.h>
27 #include <linux/slab.h>
28 #include "dvb_frontend.h"
32 #define REG_RESET 0x02
33 #define REG_RESET_OFF 0x01
42 #define REG_STRENGTH 0x4b
43 #define REG_STRENGTH_MASK 0x7f
44 #define REG_STRENGTH_CARRIER 0x80
45 #define REG_INVERSION 0x7c
46 #define REG_INVERSION_ON 0x80
50 #define REG_STATUS 0xa4
51 #define REG_STATUS_SYNC 0x04
52 #define REG_STATUS_LOCK 0x01
55 struct lgs8gl5_state
{
56 struct i2c_adapter
*i2c
;
57 const struct lgs8gl5_config
*config
;
58 struct dvb_frontend frontend
;
63 #define dprintk(args...) \
66 printk(KERN_DEBUG "lgs8gl5: " args); \
70 /* Writes into demod's register */
72 lgs8gl5_write_reg(struct lgs8gl5_state
*state
, u8 reg
, u8 data
)
75 u8 buf
[] = {reg
, data
};
76 struct i2c_msg msg
= {
77 .addr
= state
->config
->demod_address
,
83 ret
= i2c_transfer(state
->i2c
, &msg
, 1);
85 dprintk("%s: error (reg=0x%02x, val=0x%02x, ret=%i)\n",
86 __func__
, reg
, data
, ret
);
87 return (ret
!= 1) ? -1 : 0;
91 /* Reads from demod's register */
93 lgs8gl5_read_reg(struct lgs8gl5_state
*state
, u8 reg
)
98 struct i2c_msg msg
[2] = {
100 .addr
= state
->config
->demod_address
,
106 .addr
= state
->config
->demod_address
,
113 ret
= i2c_transfer(state
->i2c
, msg
, 2);
122 lgs8gl5_update_reg(struct lgs8gl5_state
*state
, u8 reg
, u8 data
)
124 lgs8gl5_read_reg(state
, reg
);
125 lgs8gl5_write_reg(state
, reg
, data
);
130 /* Writes into alternate device's register */
131 /* TODO: Find out what that device is for! */
133 lgs8gl5_update_alt_reg(struct lgs8gl5_state
*state
, u8 reg
, u8 data
)
138 u8 b2
[] = {reg
, data
};
139 struct i2c_msg msg
[3] = {
141 .addr
= state
->config
->demod_address
+ 2,
147 .addr
= state
->config
->demod_address
+ 2,
153 .addr
= state
->config
->demod_address
+ 2,
160 ret
= i2c_transfer(state
->i2c
, msg
, 3);
161 return (ret
!= 3) ? -1 : 0;
166 lgs8gl5_soft_reset(struct lgs8gl5_state
*state
)
170 dprintk("%s\n", __func__
);
172 val
= lgs8gl5_read_reg(state
, REG_RESET
);
173 lgs8gl5_write_reg(state
, REG_RESET
, val
& ~REG_RESET_OFF
);
174 lgs8gl5_write_reg(state
, REG_RESET
, val
| REG_RESET_OFF
);
180 lgs8gl5_set_inversion(struct lgs8gl5_state
*state
, int inversion
)
184 dprintk("%s\n", __func__
);
190 val
= lgs8gl5_read_reg(state
, REG_INVERSION
);
191 return lgs8gl5_write_reg(state
, REG_INVERSION
,
192 val
| REG_INVERSION_ON
);
194 val
= lgs8gl5_read_reg(state
, REG_INVERSION
);
195 return lgs8gl5_write_reg(state
, REG_INVERSION
,
196 val
& ~REG_INVERSION_ON
);
203 /* Starts demodulation */
205 lgs8gl5_start_demod(struct lgs8gl5_state
*state
)
210 dprintk("%s\n", __func__
);
212 lgs8gl5_update_alt_reg(state
, 0xc2, 0x28);
213 lgs8gl5_soft_reset(state
);
214 lgs8gl5_update_reg(state
, REG_07
, 0x10);
215 lgs8gl5_update_reg(state
, REG_07
, 0x10);
216 lgs8gl5_write_reg(state
, REG_09
, 0x0e);
217 lgs8gl5_write_reg(state
, REG_0A
, 0xe5);
218 lgs8gl5_write_reg(state
, REG_0B
, 0x35);
219 lgs8gl5_write_reg(state
, REG_0C
, 0x30);
221 lgs8gl5_update_reg(state
, REG_03
, 0x00);
222 lgs8gl5_update_reg(state
, REG_7E
, 0x01);
223 lgs8gl5_update_alt_reg(state
, 0xc5, 0x00);
224 lgs8gl5_update_reg(state
, REG_04
, 0x02);
225 lgs8gl5_update_reg(state
, REG_37
, 0x01);
226 lgs8gl5_soft_reset(state
);
228 /* Wait for carrier */
229 for (n
= 0; n
< 10; n
++) {
230 val
= lgs8gl5_read_reg(state
, REG_STRENGTH
);
231 dprintk("Wait for carrier[%d] 0x%02X\n", n
, val
);
232 if (val
& REG_STRENGTH_CARRIER
)
236 if (!(val
& REG_STRENGTH_CARRIER
))
240 for (n
= 0; n
< 20; n
++) {
241 val
= lgs8gl5_read_reg(state
, REG_STATUS
);
242 dprintk("Wait for lock[%d] 0x%02X\n", n
, val
);
243 if (val
& REG_STATUS_LOCK
)
247 if (!(val
& REG_STATUS_LOCK
))
250 lgs8gl5_write_reg(state
, REG_7D
, lgs8gl5_read_reg(state
, REG_A2
));
251 lgs8gl5_soft_reset(state
);
256 lgs8gl5_init(struct dvb_frontend
*fe
)
258 struct lgs8gl5_state
*state
= fe
->demodulator_priv
;
260 dprintk("%s\n", __func__
);
262 lgs8gl5_update_alt_reg(state
, 0xc2, 0x28);
263 lgs8gl5_soft_reset(state
);
264 lgs8gl5_update_reg(state
, REG_07
, 0x10);
265 lgs8gl5_update_reg(state
, REG_07
, 0x10);
266 lgs8gl5_write_reg(state
, REG_09
, 0x0e);
267 lgs8gl5_write_reg(state
, REG_0A
, 0xe5);
268 lgs8gl5_write_reg(state
, REG_0B
, 0x35);
269 lgs8gl5_write_reg(state
, REG_0C
, 0x30);
276 lgs8gl5_read_status(struct dvb_frontend
*fe
, fe_status_t
*status
)
278 struct lgs8gl5_state
*state
= fe
->demodulator_priv
;
279 u8 level
= lgs8gl5_read_reg(state
, REG_STRENGTH
);
280 u8 flags
= lgs8gl5_read_reg(state
, REG_STATUS
);
284 if ((level
& REG_STRENGTH_MASK
) > 0)
285 *status
|= FE_HAS_SIGNAL
;
286 if (level
& REG_STRENGTH_CARRIER
)
287 *status
|= FE_HAS_CARRIER
;
288 if (flags
& REG_STATUS_SYNC
)
289 *status
|= FE_HAS_SYNC
;
290 if (flags
& REG_STATUS_LOCK
)
291 *status
|= FE_HAS_LOCK
;
298 lgs8gl5_read_ber(struct dvb_frontend
*fe
, u32
*ber
)
300 struct lgs8gl5_state
*state
= fe
->demodulator_priv
;
308 lgs8gl5_read_signal_strength(struct dvb_frontend
*fe
, u16
*signal_strength
)
310 struct lgs8gl5_state
*state
= fe
->demodulator_priv
;
311 u8 level
= lgs8gl5_read_reg(state
, REG_STRENGTH
);
312 *signal_strength
= (level
& REG_STRENGTH_MASK
) << 8;
319 lgs8gl5_read_snr(struct dvb_frontend
*fe
, u16
*snr
)
321 struct lgs8gl5_state
*state
= fe
->demodulator_priv
;
322 u8 level
= lgs8gl5_read_reg(state
, REG_STRENGTH
);
323 *snr
= (level
& REG_STRENGTH_MASK
) << 8;
330 lgs8gl5_read_ucblocks(struct dvb_frontend
*fe
, u32
*ucblocks
)
332 struct lgs8gl5_state
*state
= fe
->demodulator_priv
;
340 lgs8gl5_set_frontend(struct dvb_frontend
*fe
,
341 struct dvb_frontend_parameters
*p
)
343 struct lgs8gl5_state
*state
= fe
->demodulator_priv
;
345 dprintk("%s\n", __func__
);
347 if (p
->u
.ofdm
.bandwidth
!= BANDWIDTH_8_MHZ
)
350 if (fe
->ops
.tuner_ops
.set_params
) {
351 fe
->ops
.tuner_ops
.set_params(fe
, p
);
352 if (fe
->ops
.i2c_gate_ctrl
)
353 fe
->ops
.i2c_gate_ctrl(fe
, 0);
356 /* lgs8gl5_set_inversion(state, p->inversion); */
358 lgs8gl5_start_demod(state
);
365 lgs8gl5_get_frontend(struct dvb_frontend
*fe
,
366 struct dvb_frontend_parameters
*p
)
368 struct lgs8gl5_state
*state
= fe
->demodulator_priv
;
369 u8 inv
= lgs8gl5_read_reg(state
, REG_INVERSION
);
370 struct dvb_ofdm_parameters
*o
= &p
->u
.ofdm
;
372 p
->inversion
= (inv
& REG_INVERSION_ON
) ? INVERSION_ON
: INVERSION_OFF
;
374 o
->code_rate_HP
= FEC_1_2
;
375 o
->code_rate_LP
= FEC_7_8
;
376 o
->guard_interval
= GUARD_INTERVAL_1_32
;
377 o
->transmission_mode
= TRANSMISSION_MODE_2K
;
378 o
->constellation
= QAM_64
;
379 o
->hierarchy_information
= HIERARCHY_NONE
;
380 o
->bandwidth
= BANDWIDTH_8_MHZ
;
387 lgs8gl5_get_tune_settings(struct dvb_frontend
*fe
,
388 struct dvb_frontend_tune_settings
*fesettings
)
390 fesettings
->min_delay_ms
= 240;
391 fesettings
->step_size
= 0;
392 fesettings
->max_drift
= 0;
398 lgs8gl5_release(struct dvb_frontend
*fe
)
400 struct lgs8gl5_state
*state
= fe
->demodulator_priv
;
405 static struct dvb_frontend_ops lgs8gl5_ops
;
409 lgs8gl5_attach(const struct lgs8gl5_config
*config
, struct i2c_adapter
*i2c
)
411 struct lgs8gl5_state
*state
= NULL
;
413 dprintk("%s\n", __func__
);
415 /* Allocate memory for the internal state */
416 state
= kmalloc(sizeof(struct lgs8gl5_state
), GFP_KERNEL
);
420 /* Setup the state */
421 state
->config
= config
;
424 /* Check if the demod is there */
425 if (lgs8gl5_read_reg(state
, REG_RESET
) < 0)
428 /* Create dvb_frontend */
429 memcpy(&state
->frontend
.ops
, &lgs8gl5_ops
,
430 sizeof(struct dvb_frontend_ops
));
431 state
->frontend
.demodulator_priv
= state
;
432 return &state
->frontend
;
438 EXPORT_SYMBOL(lgs8gl5_attach
);
441 static struct dvb_frontend_ops lgs8gl5_ops
= {
443 .name
= "Legend Silicon LGS-8GL5 DMB-TH",
445 .frequency_min
= 474000000,
446 .frequency_max
= 858000000,
447 .frequency_stepsize
= 10000,
448 .frequency_tolerance
= 0,
449 .caps
= FE_CAN_FEC_AUTO
|
450 FE_CAN_QPSK
| FE_CAN_QAM_16
| FE_CAN_QAM_32
|
451 FE_CAN_QAM_64
| FE_CAN_QAM_AUTO
|
452 FE_CAN_TRANSMISSION_MODE_AUTO
|
453 FE_CAN_BANDWIDTH_AUTO
|
454 FE_CAN_GUARD_INTERVAL_AUTO
|
455 FE_CAN_HIERARCHY_AUTO
|
459 .release
= lgs8gl5_release
,
461 .init
= lgs8gl5_init
,
463 .set_frontend
= lgs8gl5_set_frontend
,
464 .get_frontend
= lgs8gl5_get_frontend
,
465 .get_tune_settings
= lgs8gl5_get_tune_settings
,
467 .read_status
= lgs8gl5_read_status
,
468 .read_ber
= lgs8gl5_read_ber
,
469 .read_signal_strength
= lgs8gl5_read_signal_strength
,
470 .read_snr
= lgs8gl5_read_snr
,
471 .read_ucblocks
= lgs8gl5_read_ucblocks
,
475 module_param(debug
, int, 0644);
476 MODULE_PARM_DESC(debug
, "Turn on/off frontend debugging (default:off).");
478 MODULE_DESCRIPTION("Legend Silicon LGS-8GL5 DMB-TH Demodulator driver");
479 MODULE_AUTHOR("Timothy Lee");
480 MODULE_LICENSE("GPL");