1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * E3C EC100 demodulator driver |
4 | * |
5 | * Copyright (C) 2009 Antti Palosaari <crope@iki.fi> |
6 | */ |
7 | |
8 | #include <media/dvb_frontend.h> |
9 | #include "ec100.h" |
10 | |
11 | struct ec100_state { |
12 | struct i2c_adapter *i2c; |
13 | struct dvb_frontend frontend; |
14 | struct ec100_config config; |
15 | |
16 | u16 ber; |
17 | }; |
18 | |
19 | /* write single register */ |
20 | static int ec100_write_reg(struct ec100_state *state, u8 reg, u8 val) |
21 | { |
22 | int ret; |
23 | u8 buf[2] = {reg, val}; |
24 | struct i2c_msg msg[1] = { |
25 | { |
26 | .addr = state->config.demod_address, |
27 | .flags = 0, |
28 | .len = sizeof(buf), |
29 | .buf = buf, |
30 | } |
31 | }; |
32 | |
33 | ret = i2c_transfer(adap: state->i2c, msgs: msg, num: 1); |
34 | if (ret == 1) { |
35 | ret = 0; |
36 | } else { |
37 | dev_warn(&state->i2c->dev, "%s: i2c wr failed=%d reg=%02x\n" , |
38 | KBUILD_MODNAME, ret, reg); |
39 | ret = -EREMOTEIO; |
40 | } |
41 | |
42 | return ret; |
43 | } |
44 | |
45 | /* read single register */ |
46 | static int ec100_read_reg(struct ec100_state *state, u8 reg, u8 *val) |
47 | { |
48 | int ret; |
49 | struct i2c_msg msg[2] = { |
50 | { |
51 | .addr = state->config.demod_address, |
52 | .flags = 0, |
53 | .len = 1, |
54 | .buf = ® |
55 | }, { |
56 | .addr = state->config.demod_address, |
57 | .flags = I2C_M_RD, |
58 | .len = 1, |
59 | .buf = val |
60 | } |
61 | }; |
62 | |
63 | ret = i2c_transfer(adap: state->i2c, msgs: msg, num: 2); |
64 | if (ret == 2) { |
65 | ret = 0; |
66 | } else { |
67 | dev_warn(&state->i2c->dev, "%s: i2c rd failed=%d reg=%02x\n" , |
68 | KBUILD_MODNAME, ret, reg); |
69 | ret = -EREMOTEIO; |
70 | } |
71 | |
72 | return ret; |
73 | } |
74 | |
75 | static int ec100_set_frontend(struct dvb_frontend *fe) |
76 | { |
77 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; |
78 | struct ec100_state *state = fe->demodulator_priv; |
79 | int ret; |
80 | u8 tmp, tmp2; |
81 | |
82 | dev_dbg(&state->i2c->dev, "%s: frequency=%d bandwidth_hz=%d\n" , |
83 | __func__, c->frequency, c->bandwidth_hz); |
84 | |
85 | /* program tuner */ |
86 | if (fe->ops.tuner_ops.set_params) |
87 | fe->ops.tuner_ops.set_params(fe); |
88 | |
89 | ret = ec100_write_reg(state, reg: 0x04, val: 0x06); |
90 | if (ret) |
91 | goto error; |
92 | ret = ec100_write_reg(state, reg: 0x67, val: 0x58); |
93 | if (ret) |
94 | goto error; |
95 | ret = ec100_write_reg(state, reg: 0x05, val: 0x18); |
96 | if (ret) |
97 | goto error; |
98 | |
99 | /* reg/bw | 6 | 7 | 8 |
100 | -------+------+------+------ |
101 | A 0x1b | 0xa1 | 0xe7 | 0x2c |
102 | A 0x1c | 0x55 | 0x63 | 0x72 |
103 | -------+------+------+------ |
104 | B 0x1b | 0xb7 | 0x00 | 0x49 |
105 | B 0x1c | 0x55 | 0x64 | 0x72 */ |
106 | |
107 | switch (c->bandwidth_hz) { |
108 | case 6000000: |
109 | tmp = 0xb7; |
110 | tmp2 = 0x55; |
111 | break; |
112 | case 7000000: |
113 | tmp = 0x00; |
114 | tmp2 = 0x64; |
115 | break; |
116 | case 8000000: |
117 | default: |
118 | tmp = 0x49; |
119 | tmp2 = 0x72; |
120 | } |
121 | |
122 | ret = ec100_write_reg(state, reg: 0x1b, val: tmp); |
123 | if (ret) |
124 | goto error; |
125 | ret = ec100_write_reg(state, reg: 0x1c, val: tmp2); |
126 | if (ret) |
127 | goto error; |
128 | |
129 | ret = ec100_write_reg(state, reg: 0x0c, val: 0xbb); /* if freq */ |
130 | if (ret) |
131 | goto error; |
132 | ret = ec100_write_reg(state, reg: 0x0d, val: 0x31); /* if freq */ |
133 | if (ret) |
134 | goto error; |
135 | |
136 | ret = ec100_write_reg(state, reg: 0x08, val: 0x24); |
137 | if (ret) |
138 | goto error; |
139 | |
140 | ret = ec100_write_reg(state, reg: 0x00, val: 0x00); /* go */ |
141 | if (ret) |
142 | goto error; |
143 | ret = ec100_write_reg(state, reg: 0x00, val: 0x20); /* go */ |
144 | if (ret) |
145 | goto error; |
146 | |
147 | return ret; |
148 | error: |
149 | dev_dbg(&state->i2c->dev, "%s: failed=%d\n" , __func__, ret); |
150 | return ret; |
151 | } |
152 | |
153 | static int ec100_get_tune_settings(struct dvb_frontend *fe, |
154 | struct dvb_frontend_tune_settings *fesettings) |
155 | { |
156 | fesettings->min_delay_ms = 300; |
157 | fesettings->step_size = 0; |
158 | fesettings->max_drift = 0; |
159 | |
160 | return 0; |
161 | } |
162 | |
163 | static int ec100_read_status(struct dvb_frontend *fe, enum fe_status *status) |
164 | { |
165 | struct ec100_state *state = fe->demodulator_priv; |
166 | int ret; |
167 | u8 tmp; |
168 | *status = 0; |
169 | |
170 | ret = ec100_read_reg(state, reg: 0x42, val: &tmp); |
171 | if (ret) |
172 | goto error; |
173 | |
174 | if (tmp & 0x80) { |
175 | /* bit7 set - have lock */ |
176 | *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | |
177 | FE_HAS_SYNC | FE_HAS_LOCK; |
178 | } else { |
179 | ret = ec100_read_reg(state, reg: 0x01, val: &tmp); |
180 | if (ret) |
181 | goto error; |
182 | |
183 | if (tmp & 0x10) { |
184 | /* bit4 set - have signal */ |
185 | *status |= FE_HAS_SIGNAL; |
186 | if (!(tmp & 0x01)) { |
187 | /* bit0 clear - have ~valid signal */ |
188 | *status |= FE_HAS_CARRIER | FE_HAS_VITERBI; |
189 | } |
190 | } |
191 | } |
192 | |
193 | return ret; |
194 | error: |
195 | dev_dbg(&state->i2c->dev, "%s: failed=%d\n" , __func__, ret); |
196 | return ret; |
197 | } |
198 | |
199 | static int ec100_read_ber(struct dvb_frontend *fe, u32 *ber) |
200 | { |
201 | struct ec100_state *state = fe->demodulator_priv; |
202 | int ret; |
203 | u8 tmp, tmp2; |
204 | u16 ber2; |
205 | |
206 | *ber = 0; |
207 | |
208 | ret = ec100_read_reg(state, reg: 0x65, val: &tmp); |
209 | if (ret) |
210 | goto error; |
211 | ret = ec100_read_reg(state, reg: 0x66, val: &tmp2); |
212 | if (ret) |
213 | goto error; |
214 | |
215 | ber2 = (tmp2 << 8) | tmp; |
216 | |
217 | /* if counter overflow or clear */ |
218 | if (ber2 < state->ber) |
219 | *ber = ber2; |
220 | else |
221 | *ber = ber2 - state->ber; |
222 | |
223 | state->ber = ber2; |
224 | |
225 | return ret; |
226 | error: |
227 | dev_dbg(&state->i2c->dev, "%s: failed=%d\n" , __func__, ret); |
228 | return ret; |
229 | } |
230 | |
231 | static int ec100_read_signal_strength(struct dvb_frontend *fe, u16 *strength) |
232 | { |
233 | struct ec100_state *state = fe->demodulator_priv; |
234 | int ret; |
235 | u8 tmp; |
236 | |
237 | ret = ec100_read_reg(state, reg: 0x24, val: &tmp); |
238 | if (ret) { |
239 | *strength = 0; |
240 | goto error; |
241 | } |
242 | |
243 | *strength = ((tmp << 8) | tmp); |
244 | |
245 | return ret; |
246 | error: |
247 | dev_dbg(&state->i2c->dev, "%s: failed=%d\n" , __func__, ret); |
248 | return ret; |
249 | } |
250 | |
251 | static int ec100_read_snr(struct dvb_frontend *fe, u16 *snr) |
252 | { |
253 | *snr = 0; |
254 | return 0; |
255 | } |
256 | |
257 | static int ec100_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) |
258 | { |
259 | *ucblocks = 0; |
260 | return 0; |
261 | } |
262 | |
263 | static void ec100_release(struct dvb_frontend *fe) |
264 | { |
265 | struct ec100_state *state = fe->demodulator_priv; |
266 | kfree(objp: state); |
267 | } |
268 | |
269 | static const struct dvb_frontend_ops ec100_ops; |
270 | |
271 | struct dvb_frontend *ec100_attach(const struct ec100_config *config, |
272 | struct i2c_adapter *i2c) |
273 | { |
274 | int ret; |
275 | struct ec100_state *state = NULL; |
276 | u8 tmp; |
277 | |
278 | /* allocate memory for the internal state */ |
279 | state = kzalloc(size: sizeof(struct ec100_state), GFP_KERNEL); |
280 | if (state == NULL) |
281 | goto error; |
282 | |
283 | /* setup the state */ |
284 | state->i2c = i2c; |
285 | memcpy(&state->config, config, sizeof(struct ec100_config)); |
286 | |
287 | /* check if the demod is there */ |
288 | ret = ec100_read_reg(state, reg: 0x33, val: &tmp); |
289 | if (ret || tmp != 0x0b) |
290 | goto error; |
291 | |
292 | /* create dvb_frontend */ |
293 | memcpy(&state->frontend.ops, &ec100_ops, |
294 | sizeof(struct dvb_frontend_ops)); |
295 | state->frontend.demodulator_priv = state; |
296 | |
297 | return &state->frontend; |
298 | error: |
299 | kfree(objp: state); |
300 | return NULL; |
301 | } |
302 | EXPORT_SYMBOL_GPL(ec100_attach); |
303 | |
304 | static const struct dvb_frontend_ops ec100_ops = { |
305 | .delsys = { SYS_DVBT }, |
306 | .info = { |
307 | .name = "E3C EC100 DVB-T" , |
308 | .caps = |
309 | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | |
310 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | |
311 | FE_CAN_QPSK | FE_CAN_QAM_16 | |
312 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | |
313 | FE_CAN_TRANSMISSION_MODE_AUTO | |
314 | FE_CAN_GUARD_INTERVAL_AUTO | |
315 | FE_CAN_HIERARCHY_AUTO | |
316 | FE_CAN_MUTE_TS |
317 | }, |
318 | |
319 | .release = ec100_release, |
320 | .set_frontend = ec100_set_frontend, |
321 | .get_tune_settings = ec100_get_tune_settings, |
322 | .read_status = ec100_read_status, |
323 | .read_ber = ec100_read_ber, |
324 | .read_signal_strength = ec100_read_signal_strength, |
325 | .read_snr = ec100_read_snr, |
326 | .read_ucblocks = ec100_read_ucblocks, |
327 | }; |
328 | |
329 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>" ); |
330 | MODULE_DESCRIPTION("E3C EC100 DVB-T demodulator driver" ); |
331 | MODULE_LICENSE("GPL" ); |
332 | |