2 * E3C EC100 demodulator driver
4 * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
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
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "dvb_frontend.h"
23 #include "ec100_priv.h"
27 module_param_named(debug
, ec100_debug
, int, 0644);
28 MODULE_PARM_DESC(debug
, "Turn on/off frontend debugging (default:off).");
31 struct i2c_adapter
*i2c
;
32 struct dvb_frontend frontend
;
33 struct ec100_config config
;
38 /* write single register */
39 static int ec100_write_reg(struct ec100_state
*state
, u8 reg
, u8 val
)
41 u8 buf
[2] = {reg
, val
};
42 struct i2c_msg msg
= {
43 .addr
= state
->config
.demod_address
,
48 if (i2c_transfer(state
->i2c
, &msg
, 1) != 1) {
49 warn("I2C write failed reg:%02x", reg
);
55 /* read single register */
56 static int ec100_read_reg(struct ec100_state
*state
, u8 reg
, u8
*val
)
58 struct i2c_msg msg
[2] = {
60 .addr
= state
->config
.demod_address
,
65 .addr
= state
->config
.demod_address
,
72 if (i2c_transfer(state
->i2c
, msg
, 2) != 2) {
73 warn("I2C read failed reg:%02x", reg
);
79 static int ec100_set_frontend(struct dvb_frontend
*fe
)
81 struct dtv_frontend_properties
*c
= &fe
->dtv_property_cache
;
82 struct ec100_state
*state
= fe
->demodulator_priv
;
86 deb_info("%s: freq:%d bw:%d\n", __func__
, c
->frequency
,
90 if (fe
->ops
.tuner_ops
.set_params
)
91 fe
->ops
.tuner_ops
.set_params(fe
);
93 ret
= ec100_write_reg(state
, 0x04, 0x06);
96 ret
= ec100_write_reg(state
, 0x67, 0x58);
99 ret
= ec100_write_reg(state
, 0x05, 0x18);
103 /* reg/bw | 6 | 7 | 8
104 -------+------+------+------
105 A 0x1b | 0xa1 | 0xe7 | 0x2c
106 A 0x1c | 0x55 | 0x63 | 0x72
107 -------+------+------+------
108 B 0x1b | 0xb7 | 0x00 | 0x49
109 B 0x1c | 0x55 | 0x64 | 0x72 */
111 switch (c
->bandwidth_hz
) {
126 ret
= ec100_write_reg(state
, 0x1b, tmp
);
129 ret
= ec100_write_reg(state
, 0x1c, tmp2
);
133 ret
= ec100_write_reg(state
, 0x0c, 0xbb); /* if freq */
136 ret
= ec100_write_reg(state
, 0x0d, 0x31); /* if freq */
140 ret
= ec100_write_reg(state
, 0x08, 0x24);
144 ret
= ec100_write_reg(state
, 0x00, 0x00); /* go */
147 ret
= ec100_write_reg(state
, 0x00, 0x20); /* go */
153 deb_info("%s: failed:%d\n", __func__
, ret
);
157 static int ec100_get_tune_settings(struct dvb_frontend
*fe
,
158 struct dvb_frontend_tune_settings
*fesettings
)
160 fesettings
->min_delay_ms
= 300;
161 fesettings
->step_size
= 0;
162 fesettings
->max_drift
= 0;
167 static int ec100_read_status(struct dvb_frontend
*fe
, fe_status_t
*status
)
169 struct ec100_state
*state
= fe
->demodulator_priv
;
174 ret
= ec100_read_reg(state
, 0x42, &tmp
);
179 /* bit7 set - have lock */
180 *status
|= FE_HAS_SIGNAL
| FE_HAS_CARRIER
| FE_HAS_VITERBI
|
181 FE_HAS_SYNC
| FE_HAS_LOCK
;
183 ret
= ec100_read_reg(state
, 0x01, &tmp
);
188 /* bit4 set - have signal */
189 *status
|= FE_HAS_SIGNAL
;
191 /* bit0 clear - have ~valid signal */
192 *status
|= FE_HAS_CARRIER
| FE_HAS_VITERBI
;
199 deb_info("%s: failed:%d\n", __func__
, ret
);
203 static int ec100_read_ber(struct dvb_frontend
*fe
, u32
*ber
)
205 struct ec100_state
*state
= fe
->demodulator_priv
;
212 ret
= ec100_read_reg(state
, 0x65, &tmp
);
215 ret
= ec100_read_reg(state
, 0x66, &tmp2
);
219 ber2
= (tmp2
<< 8) | tmp
;
221 /* if counter overflow or clear */
222 if (ber2
< state
->ber
)
225 *ber
= ber2
- state
->ber
;
231 deb_info("%s: failed:%d\n", __func__
, ret
);
235 static int ec100_read_signal_strength(struct dvb_frontend
*fe
, u16
*strength
)
237 struct ec100_state
*state
= fe
->demodulator_priv
;
241 ret
= ec100_read_reg(state
, 0x24, &tmp
);
247 *strength
= ((tmp
<< 8) | tmp
);
251 deb_info("%s: failed:%d\n", __func__
, ret
);
255 static int ec100_read_snr(struct dvb_frontend
*fe
, u16
*snr
)
261 static int ec100_read_ucblocks(struct dvb_frontend
*fe
, u32
*ucblocks
)
267 static void ec100_release(struct dvb_frontend
*fe
)
269 struct ec100_state
*state
= fe
->demodulator_priv
;
273 static struct dvb_frontend_ops ec100_ops
;
275 struct dvb_frontend
*ec100_attach(const struct ec100_config
*config
,
276 struct i2c_adapter
*i2c
)
279 struct ec100_state
*state
= NULL
;
282 /* allocate memory for the internal state */
283 state
= kzalloc(sizeof(struct ec100_state
), GFP_KERNEL
);
287 /* setup the state */
289 memcpy(&state
->config
, config
, sizeof(struct ec100_config
));
291 /* check if the demod is there */
292 ret
= ec100_read_reg(state
, 0x33, &tmp
);
293 if (ret
|| tmp
!= 0x0b)
296 /* create dvb_frontend */
297 memcpy(&state
->frontend
.ops
, &ec100_ops
,
298 sizeof(struct dvb_frontend_ops
));
299 state
->frontend
.demodulator_priv
= state
;
301 return &state
->frontend
;
306 EXPORT_SYMBOL(ec100_attach
);
308 static struct dvb_frontend_ops ec100_ops
= {
309 .delsys
= { SYS_DVBT
},
311 .name
= "E3C EC100 DVB-T",
313 FE_CAN_FEC_1_2
| FE_CAN_FEC_2_3
| FE_CAN_FEC_3_4
|
314 FE_CAN_FEC_5_6
| FE_CAN_FEC_7_8
| FE_CAN_FEC_AUTO
|
315 FE_CAN_QPSK
| FE_CAN_QAM_16
|
316 FE_CAN_QAM_64
| FE_CAN_QAM_AUTO
|
317 FE_CAN_TRANSMISSION_MODE_AUTO
|
318 FE_CAN_GUARD_INTERVAL_AUTO
|
319 FE_CAN_HIERARCHY_AUTO
|
323 .release
= ec100_release
,
324 .set_frontend
= ec100_set_frontend
,
325 .get_tune_settings
= ec100_get_tune_settings
,
326 .read_status
= ec100_read_status
,
327 .read_ber
= ec100_read_ber
,
328 .read_signal_strength
= ec100_read_signal_strength
,
329 .read_snr
= ec100_read_snr
,
330 .read_ucblocks
= ec100_read_ucblocks
,
333 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
334 MODULE_DESCRIPTION("E3C EC100 DVB-T demodulator driver");
335 MODULE_LICENSE("GPL");