diff options
author | Michael Krufky <mkrufky@hauppauge.com> | 2011-09-08 02:44:15 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2011-11-03 05:42:30 -0400 |
commit | e92f9a56815d8566dcb6f98aa0ed118d66881a59 (patch) | |
tree | da5d3c5c6fd4f5fe81fb391d737a9dab80a7318a /drivers | |
parent | c8c741b6eeb7c5c514a3177fd28225bff454b08f (diff) |
[media] DVB: add MaxLinear MxL111SF DVB-T demodulator driver
Signed-off-by: Michael Krufky <mkrufky@kernellabs.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/dvb/dvb-usb/Makefile | 1 | ||||
-rw-r--r-- | drivers/media/dvb/dvb-usb/mxl111sf-demod.c | 604 | ||||
-rw-r--r-- | drivers/media/dvb/dvb-usb/mxl111sf-demod.h | 55 | ||||
-rw-r--r-- | drivers/media/dvb/dvb-usb/mxl111sf.h | 2 |
4 files changed, 661 insertions, 1 deletions
diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile index 7d0710bb1978..26c8b9e57050 100644 --- a/drivers/media/dvb/dvb-usb/Makefile +++ b/drivers/media/dvb/dvb-usb/Makefile | |||
@@ -102,6 +102,7 @@ obj-$(CONFIG_DVB_USB_IT913X) += dvb-usb-it913x.o | |||
102 | 102 | ||
103 | dvb-usb-mxl111sf-objs = mxl111sf.o mxl111sf-phy.o mxl111sf-i2c.o mxl111sf-gpio.o | 103 | dvb-usb-mxl111sf-objs = mxl111sf.o mxl111sf-phy.o mxl111sf-i2c.o mxl111sf-gpio.o |
104 | obj-$(CONFIG_DVB_USB_MXL111SF) += dvb-usb-mxl111sf.o | 104 | obj-$(CONFIG_DVB_USB_MXL111SF) += dvb-usb-mxl111sf.o |
105 | obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-demod.o | ||
105 | obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-tuner.o | 106 | obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-tuner.o |
106 | 107 | ||
107 | ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ | 108 | ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ |
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-demod.c b/drivers/media/dvb/dvb-usb/mxl111sf-demod.c new file mode 100644 index 000000000000..330774e346ab --- /dev/null +++ b/drivers/media/dvb/dvb-usb/mxl111sf-demod.c | |||
@@ -0,0 +1,604 @@ | |||
1 | /* | ||
2 | * mxl111sf-demod.c - driver for the MaxLinear MXL111SF DVB-T demodulator | ||
3 | * | ||
4 | * Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com> | ||
5 | * | ||
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. | ||
10 | * | ||
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. | ||
15 | * | ||
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. | ||
19 | */ | ||
20 | |||
21 | #include "mxl111sf-demod.h" | ||
22 | #include "mxl111sf-reg.h" | ||
23 | |||
24 | /* debug */ | ||
25 | static int mxl111sf_demod_debug; | ||
26 | module_param_named(debug, mxl111sf_demod_debug, int, 0644); | ||
27 | MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))."); | ||
28 | |||
29 | #define mxl_dbg(fmt, arg...) \ | ||
30 | if (mxl111sf_demod_debug) \ | ||
31 | mxl_printk(KERN_DEBUG, fmt, ##arg) | ||
32 | |||
33 | /* ------------------------------------------------------------------------ */ | ||
34 | |||
35 | struct mxl111sf_demod_state { | ||
36 | struct mxl111sf_state *mxl_state; | ||
37 | |||
38 | struct mxl111sf_demod_config *cfg; | ||
39 | |||
40 | struct dvb_frontend fe; | ||
41 | }; | ||
42 | |||
43 | /* ------------------------------------------------------------------------ */ | ||
44 | |||
45 | static int mxl111sf_demod_read_reg(struct mxl111sf_demod_state *state, | ||
46 | u8 addr, u8 *data) | ||
47 | { | ||
48 | return (state->cfg->read_reg) ? | ||
49 | state->cfg->read_reg(state->mxl_state, addr, data) : | ||
50 | -EINVAL; | ||
51 | } | ||
52 | |||
53 | static int mxl111sf_demod_write_reg(struct mxl111sf_demod_state *state, | ||
54 | u8 addr, u8 data) | ||
55 | { | ||
56 | return (state->cfg->write_reg) ? | ||
57 | state->cfg->write_reg(state->mxl_state, addr, data) : | ||
58 | -EINVAL; | ||
59 | } | ||
60 | |||
61 | static | ||
62 | int mxl111sf_demod_program_regs(struct mxl111sf_demod_state *state, | ||
63 | struct mxl111sf_reg_ctrl_info *ctrl_reg_info) | ||
64 | { | ||
65 | return (state->cfg->program_regs) ? | ||
66 | state->cfg->program_regs(state->mxl_state, ctrl_reg_info) : | ||
67 | -EINVAL; | ||
68 | } | ||
69 | |||
70 | /* ------------------------------------------------------------------------ */ | ||
71 | /* TPS */ | ||
72 | |||
73 | static | ||
74 | int mxl1x1sf_demod_get_tps_code_rate(struct mxl111sf_demod_state *state, | ||
75 | fe_code_rate_t *code_rate) | ||
76 | { | ||
77 | u8 val; | ||
78 | int ret = mxl111sf_demod_read_reg(state, V6_CODE_RATE_TPS_REG, &val); | ||
79 | /* bit<2:0> - 000:1/2, 001:2/3, 010:3/4, 011:5/6, 100:7/8 */ | ||
80 | if (mxl_fail(ret)) | ||
81 | goto fail; | ||
82 | |||
83 | switch (val & V6_CODE_RATE_TPS_MASK) { | ||
84 | case 0: | ||
85 | *code_rate = FEC_1_2; | ||
86 | break; | ||
87 | case 1: | ||
88 | *code_rate = FEC_2_3; | ||
89 | break; | ||
90 | case 2: | ||
91 | *code_rate = FEC_3_4; | ||
92 | break; | ||
93 | case 3: | ||
94 | *code_rate = FEC_5_6; | ||
95 | break; | ||
96 | case 4: | ||
97 | *code_rate = FEC_7_8; | ||
98 | break; | ||
99 | } | ||
100 | fail: | ||
101 | return ret; | ||
102 | } | ||
103 | |||
104 | static | ||
105 | int mxl1x1sf_demod_get_tps_constellation(struct mxl111sf_demod_state *state, | ||
106 | fe_modulation_t *constellation) | ||
107 | { | ||
108 | u8 val; | ||
109 | int ret = mxl111sf_demod_read_reg(state, V6_MODORDER_TPS_REG, &val); | ||
110 | /* Constellation, 00 : QPSK, 01 : 16QAM, 10:64QAM */ | ||
111 | if (mxl_fail(ret)) | ||
112 | goto fail; | ||
113 | |||
114 | switch ((val & V6_PARAM_CONSTELLATION_MASK) >> 4) { | ||
115 | case 0: | ||
116 | *constellation = QPSK; | ||
117 | break; | ||
118 | case 1: | ||
119 | *constellation = QAM_16; | ||
120 | break; | ||
121 | case 2: | ||
122 | *constellation = QAM_64; | ||
123 | break; | ||
124 | } | ||
125 | fail: | ||
126 | return ret; | ||
127 | } | ||
128 | |||
129 | static | ||
130 | int mxl1x1sf_demod_get_tps_guard_fft_mode(struct mxl111sf_demod_state *state, | ||
131 | fe_transmit_mode_t *fft_mode) | ||
132 | { | ||
133 | u8 val; | ||
134 | int ret = mxl111sf_demod_read_reg(state, V6_MODE_TPS_REG, &val); | ||
135 | /* FFT Mode, 00:2K, 01:8K, 10:4K */ | ||
136 | if (mxl_fail(ret)) | ||
137 | goto fail; | ||
138 | |||
139 | switch ((val & V6_PARAM_FFT_MODE_MASK) >> 2) { | ||
140 | case 0: | ||
141 | *fft_mode = TRANSMISSION_MODE_2K; | ||
142 | break; | ||
143 | case 1: | ||
144 | *fft_mode = TRANSMISSION_MODE_8K; | ||
145 | break; | ||
146 | case 2: | ||
147 | *fft_mode = TRANSMISSION_MODE_4K; | ||
148 | break; | ||
149 | } | ||
150 | fail: | ||
151 | return ret; | ||
152 | } | ||
153 | |||
154 | static | ||
155 | int mxl1x1sf_demod_get_tps_guard_interval(struct mxl111sf_demod_state *state, | ||
156 | fe_guard_interval_t *guard) | ||
157 | { | ||
158 | u8 val; | ||
159 | int ret = mxl111sf_demod_read_reg(state, V6_CP_TPS_REG, &val); | ||
160 | /* 00:1/32, 01:1/16, 10:1/8, 11:1/4 */ | ||
161 | if (mxl_fail(ret)) | ||
162 | goto fail; | ||
163 | |||
164 | switch ((val & V6_PARAM_GI_MASK) >> 4) { | ||
165 | case 0: | ||
166 | *guard = GUARD_INTERVAL_1_32; | ||
167 | break; | ||
168 | case 1: | ||
169 | *guard = GUARD_INTERVAL_1_16; | ||
170 | break; | ||
171 | case 2: | ||
172 | *guard = GUARD_INTERVAL_1_8; | ||
173 | break; | ||
174 | case 3: | ||
175 | *guard = GUARD_INTERVAL_1_4; | ||
176 | break; | ||
177 | } | ||
178 | fail: | ||
179 | return ret; | ||
180 | } | ||
181 | |||
182 | static | ||
183 | int mxl1x1sf_demod_get_tps_hierarchy(struct mxl111sf_demod_state *state, | ||
184 | fe_hierarchy_t *hierarchy) | ||
185 | { | ||
186 | u8 val; | ||
187 | int ret = mxl111sf_demod_read_reg(state, V6_TPS_HIERACHY_REG, &val); | ||
188 | /* bit<6:4> - 000:Non hierarchy, 001:1, 010:2, 011:4 */ | ||
189 | if (mxl_fail(ret)) | ||
190 | goto fail; | ||
191 | |||
192 | switch ((val & V6_TPS_HIERARCHY_INFO_MASK) >> 6) { | ||
193 | case 0: | ||
194 | *hierarchy = HIERARCHY_NONE; | ||
195 | break; | ||
196 | case 1: | ||
197 | *hierarchy = HIERARCHY_1; | ||
198 | break; | ||
199 | case 2: | ||
200 | *hierarchy = HIERARCHY_2; | ||
201 | break; | ||
202 | case 3: | ||
203 | *hierarchy = HIERARCHY_4; | ||
204 | break; | ||
205 | } | ||
206 | fail: | ||
207 | return ret; | ||
208 | } | ||
209 | |||
210 | /* ------------------------------------------------------------------------ */ | ||
211 | /* LOCKS */ | ||
212 | |||
213 | static | ||
214 | int mxl1x1sf_demod_get_sync_lock_status(struct mxl111sf_demod_state *state, | ||
215 | int *sync_lock) | ||
216 | { | ||
217 | u8 val = 0; | ||
218 | int ret = mxl111sf_demod_read_reg(state, V6_SYNC_LOCK_REG, &val); | ||
219 | if (mxl_fail(ret)) | ||
220 | goto fail; | ||
221 | *sync_lock = (val & SYNC_LOCK_MASK) >> 4; | ||
222 | fail: | ||
223 | return ret; | ||
224 | } | ||
225 | |||
226 | static | ||
227 | int mxl1x1sf_demod_get_rs_lock_status(struct mxl111sf_demod_state *state, | ||
228 | int *rs_lock) | ||
229 | { | ||
230 | u8 val = 0; | ||
231 | int ret = mxl111sf_demod_read_reg(state, V6_RS_LOCK_DET_REG, &val); | ||
232 | if (mxl_fail(ret)) | ||
233 | goto fail; | ||
234 | *rs_lock = (val & RS_LOCK_DET_MASK) >> 3; | ||
235 | fail: | ||
236 | return ret; | ||
237 | } | ||
238 | |||
239 | static | ||
240 | int mxl1x1sf_demod_get_tps_lock_status(struct mxl111sf_demod_state *state, | ||
241 | int *tps_lock) | ||
242 | { | ||
243 | u8 val = 0; | ||
244 | int ret = mxl111sf_demod_read_reg(state, V6_TPS_LOCK_REG, &val); | ||
245 | if (mxl_fail(ret)) | ||
246 | goto fail; | ||
247 | *tps_lock = (val & V6_PARAM_TPS_LOCK_MASK) >> 6; | ||
248 | fail: | ||
249 | return ret; | ||
250 | } | ||
251 | |||
252 | static | ||
253 | int mxl1x1sf_demod_get_fec_lock_status(struct mxl111sf_demod_state *state, | ||
254 | int *fec_lock) | ||
255 | { | ||
256 | u8 val = 0; | ||
257 | int ret = mxl111sf_demod_read_reg(state, V6_IRQ_STATUS_REG, &val); | ||
258 | if (mxl_fail(ret)) | ||
259 | goto fail; | ||
260 | *fec_lock = (val & IRQ_MASK_FEC_LOCK) >> 4; | ||
261 | fail: | ||
262 | return ret; | ||
263 | } | ||
264 | |||
265 | #if 0 | ||
266 | static | ||
267 | int mxl1x1sf_demod_get_cp_lock_status(struct mxl111sf_demod_state *state, | ||
268 | int *cp_lock) | ||
269 | { | ||
270 | u8 val = 0; | ||
271 | int ret = mxl111sf_demod_read_reg(state, V6_CP_LOCK_DET_REG, &val); | ||
272 | if (mxl_fail(ret)) | ||
273 | goto fail; | ||
274 | *cp_lock = (val & V6_CP_LOCK_DET_MASK) >> 2; | ||
275 | fail: | ||
276 | return ret; | ||
277 | } | ||
278 | #endif | ||
279 | |||
280 | static int mxl1x1sf_demod_reset_irq_status(struct mxl111sf_demod_state *state) | ||
281 | { | ||
282 | return mxl111sf_demod_write_reg(state, 0x0e, 0xff); | ||
283 | } | ||
284 | |||
285 | /* ------------------------------------------------------------------------ */ | ||
286 | |||
287 | static int mxl111sf_demod_set_frontend(struct dvb_frontend *fe, | ||
288 | struct dvb_frontend_parameters *param) | ||
289 | { | ||
290 | struct mxl111sf_demod_state *state = fe->demodulator_priv; | ||
291 | int ret = 0; | ||
292 | |||
293 | struct mxl111sf_reg_ctrl_info phy_pll_patch[] = { | ||
294 | {0x00, 0xff, 0x01}, /* change page to 1 */ | ||
295 | {0x40, 0xff, 0x05}, | ||
296 | {0x40, 0xff, 0x01}, | ||
297 | {0x41, 0xff, 0xca}, | ||
298 | {0x41, 0xff, 0xc0}, | ||
299 | {0x00, 0xff, 0x00}, /* change page to 0 */ | ||
300 | {0, 0, 0} | ||
301 | }; | ||
302 | |||
303 | mxl_dbg("()"); | ||
304 | |||
305 | if (fe->ops.tuner_ops.set_params) { | ||
306 | ret = fe->ops.tuner_ops.set_params(fe, param); | ||
307 | if (mxl_fail(ret)) | ||
308 | goto fail; | ||
309 | msleep(50); | ||
310 | } | ||
311 | ret = mxl111sf_demod_program_regs(state, phy_pll_patch); | ||
312 | mxl_fail(ret); | ||
313 | msleep(50); | ||
314 | ret = mxl1x1sf_demod_reset_irq_status(state); | ||
315 | mxl_fail(ret); | ||
316 | msleep(100); | ||
317 | fail: | ||
318 | return ret; | ||
319 | } | ||
320 | |||
321 | /* ------------------------------------------------------------------------ */ | ||
322 | |||
323 | #if 0 | ||
324 | /* resets TS Packet error count */ | ||
325 | /* After setting 7th bit of V5_PER_COUNT_RESET_REG, it should be reset to 0. */ | ||
326 | static | ||
327 | int mxl1x1sf_demod_reset_packet_error_count(struct mxl111sf_demod_state *state) | ||
328 | { | ||
329 | struct mxl111sf_reg_ctrl_info reset_per_count[] = { | ||
330 | {0x20, 0x01, 0x01}, | ||
331 | {0x20, 0x01, 0x00}, | ||
332 | {0, 0, 0} | ||
333 | }; | ||
334 | return mxl111sf_demod_program_regs(state, reset_per_count); | ||
335 | } | ||
336 | #endif | ||
337 | |||
338 | /* returns TS Packet error count */ | ||
339 | /* PER Count = FEC_PER_COUNT * (2 ** (FEC_PER_SCALE * 4)) */ | ||
340 | static int mxl111sf_demod_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) | ||
341 | { | ||
342 | struct mxl111sf_demod_state *state = fe->demodulator_priv; | ||
343 | u32 fec_per_count, fec_per_scale; | ||
344 | u8 val; | ||
345 | int ret; | ||
346 | |||
347 | *ucblocks = 0; | ||
348 | |||
349 | /* FEC_PER_COUNT Register */ | ||
350 | ret = mxl111sf_demod_read_reg(state, V6_FEC_PER_COUNT_REG, &val); | ||
351 | if (mxl_fail(ret)) | ||
352 | goto fail; | ||
353 | |||
354 | fec_per_count = val; | ||
355 | |||
356 | /* FEC_PER_SCALE Register */ | ||
357 | ret = mxl111sf_demod_read_reg(state, V6_FEC_PER_SCALE_REG, &val); | ||
358 | if (mxl_fail(ret)) | ||
359 | goto fail; | ||
360 | |||
361 | val &= V6_FEC_PER_SCALE_MASK; | ||
362 | val *= 4; | ||
363 | |||
364 | fec_per_scale = 1 << val; | ||
365 | |||
366 | fec_per_count *= fec_per_scale; | ||
367 | |||
368 | *ucblocks = fec_per_count; | ||
369 | fail: | ||
370 | return ret; | ||
371 | } | ||
372 | |||
373 | #define CALCULATE_BER(avg_errors, count) \ | ||
374 | ((u32)(avg_errors * 4)/(count*64*188*8)) | ||
375 | #define CALCULATE_SNR(data) \ | ||
376 | ((u32)((10 * (u32)data / 64) - 2.5)) | ||
377 | |||
378 | static int mxl111sf_demod_read_ber(struct dvb_frontend *fe, u32 *ber) | ||
379 | { | ||
380 | struct mxl111sf_demod_state *state = fe->demodulator_priv; | ||
381 | u8 val1, val2, val3; | ||
382 | int ret; | ||
383 | |||
384 | *ber = 0; | ||
385 | |||
386 | ret = mxl111sf_demod_read_reg(state, V6_RS_AVG_ERRORS_LSB_REG, &val1); | ||
387 | if (mxl_fail(ret)) | ||
388 | goto fail; | ||
389 | ret = mxl111sf_demod_read_reg(state, V6_RS_AVG_ERRORS_MSB_REG, &val2); | ||
390 | if (mxl_fail(ret)) | ||
391 | goto fail; | ||
392 | ret = mxl111sf_demod_read_reg(state, V6_N_ACCUMULATE_REG, &val3); | ||
393 | if (mxl_fail(ret)) | ||
394 | goto fail; | ||
395 | |||
396 | *ber = CALCULATE_BER((val1 | (val2 << 8)), val3); | ||
397 | fail: | ||
398 | return ret; | ||
399 | } | ||
400 | |||
401 | static int mxl111sf_demod_calc_snr(struct mxl111sf_demod_state *state, | ||
402 | u16 *snr) | ||
403 | { | ||
404 | u8 val1, val2; | ||
405 | int ret; | ||
406 | |||
407 | *snr = 0; | ||
408 | |||
409 | ret = mxl111sf_demod_read_reg(state, V6_SNR_RB_LSB_REG, &val1); | ||
410 | if (mxl_fail(ret)) | ||
411 | goto fail; | ||
412 | ret = mxl111sf_demod_read_reg(state, V6_SNR_RB_MSB_REG, &val2); | ||
413 | if (mxl_fail(ret)) | ||
414 | goto fail; | ||
415 | |||
416 | *snr = CALCULATE_SNR(val1 | ((val2 & 0x03) << 8)); | ||
417 | fail: | ||
418 | return ret; | ||
419 | } | ||
420 | |||
421 | static int mxl111sf_demod_read_snr(struct dvb_frontend *fe, u16 *snr) | ||
422 | { | ||
423 | struct mxl111sf_demod_state *state = fe->demodulator_priv; | ||
424 | |||
425 | int ret = mxl111sf_demod_calc_snr(state, snr); | ||
426 | if (mxl_fail(ret)) | ||
427 | goto fail; | ||
428 | |||
429 | *snr /= 10; /* 0.1 dB */ | ||
430 | fail: | ||
431 | return ret; | ||
432 | } | ||
433 | |||
434 | static int mxl111sf_demod_read_status(struct dvb_frontend *fe, | ||
435 | fe_status_t *status) | ||
436 | { | ||
437 | struct mxl111sf_demod_state *state = fe->demodulator_priv; | ||
438 | int ret, locked, cr_lock, sync_lock, fec_lock; | ||
439 | |||
440 | *status = 0; | ||
441 | |||
442 | ret = mxl1x1sf_demod_get_rs_lock_status(state, &locked); | ||
443 | if (mxl_fail(ret)) | ||
444 | goto fail; | ||
445 | ret = mxl1x1sf_demod_get_tps_lock_status(state, &cr_lock); | ||
446 | if (mxl_fail(ret)) | ||
447 | goto fail; | ||
448 | ret = mxl1x1sf_demod_get_sync_lock_status(state, &sync_lock); | ||
449 | if (mxl_fail(ret)) | ||
450 | goto fail; | ||
451 | ret = mxl1x1sf_demod_get_fec_lock_status(state, &fec_lock); | ||
452 | if (mxl_fail(ret)) | ||
453 | goto fail; | ||
454 | |||
455 | if (locked) | ||
456 | *status |= FE_HAS_SIGNAL; | ||
457 | if (cr_lock) | ||
458 | *status |= FE_HAS_CARRIER; | ||
459 | if (sync_lock) | ||
460 | *status |= FE_HAS_SYNC; | ||
461 | if (fec_lock) /* false positives? */ | ||
462 | *status |= FE_HAS_VITERBI; | ||
463 | |||
464 | if ((locked) && (cr_lock) && (sync_lock)) | ||
465 | *status |= FE_HAS_LOCK; | ||
466 | fail: | ||
467 | return ret; | ||
468 | } | ||
469 | |||
470 | static int mxl111sf_demod_read_signal_strength(struct dvb_frontend *fe, | ||
471 | u16 *signal_strength) | ||
472 | { | ||
473 | struct mxl111sf_demod_state *state = fe->demodulator_priv; | ||
474 | fe_modulation_t constellation; | ||
475 | u16 snr; | ||
476 | |||
477 | mxl111sf_demod_calc_snr(state, &snr); | ||
478 | mxl1x1sf_demod_get_tps_constellation(state, &constellation); | ||
479 | |||
480 | switch (constellation) { | ||
481 | case QPSK: | ||
482 | *signal_strength = (snr >= 1300) ? | ||
483 | min(65535, snr * 44) : snr * 38; | ||
484 | break; | ||
485 | case QAM_16: | ||
486 | *signal_strength = (snr >= 1500) ? | ||
487 | min(65535, snr * 38) : snr * 33; | ||
488 | break; | ||
489 | case QAM_64: | ||
490 | *signal_strength = (snr >= 2000) ? | ||
491 | min(65535, snr * 29) : snr * 25; | ||
492 | break; | ||
493 | default: | ||
494 | *signal_strength = 0; | ||
495 | return -EINVAL; | ||
496 | } | ||
497 | |||
498 | return 0; | ||
499 | } | ||
500 | |||
501 | static int mxl111sf_demod_get_frontend(struct dvb_frontend *fe, | ||
502 | struct dvb_frontend_parameters *p) | ||
503 | { | ||
504 | struct mxl111sf_demod_state *state = fe->demodulator_priv; | ||
505 | |||
506 | mxl_dbg("()"); | ||
507 | #if 0 | ||
508 | p->inversion = /* FIXME */ ? INVERSION_ON : INVERSION_OFF; | ||
509 | #endif | ||
510 | if (fe->ops.tuner_ops.get_bandwidth) | ||
511 | fe->ops.tuner_ops.get_bandwidth(fe, &p->u.ofdm.bandwidth); | ||
512 | if (fe->ops.tuner_ops.get_frequency) | ||
513 | fe->ops.tuner_ops.get_frequency(fe, &p->frequency); | ||
514 | mxl1x1sf_demod_get_tps_code_rate(state, &p->u.ofdm.code_rate_HP); | ||
515 | mxl1x1sf_demod_get_tps_code_rate(state, &p->u.ofdm.code_rate_LP); | ||
516 | mxl1x1sf_demod_get_tps_constellation(state, &p->u.ofdm.constellation); | ||
517 | mxl1x1sf_demod_get_tps_guard_fft_mode(state, | ||
518 | &p->u.ofdm.transmission_mode); | ||
519 | mxl1x1sf_demod_get_tps_guard_interval(state, | ||
520 | &p->u.ofdm.guard_interval); | ||
521 | mxl1x1sf_demod_get_tps_hierarchy(state, | ||
522 | &p->u.ofdm.hierarchy_information); | ||
523 | |||
524 | return 0; | ||
525 | } | ||
526 | |||
527 | static | ||
528 | int mxl111sf_demod_get_tune_settings(struct dvb_frontend *fe, | ||
529 | struct dvb_frontend_tune_settings *tune) | ||
530 | { | ||
531 | tune->min_delay_ms = 1000; | ||
532 | return 0; | ||
533 | } | ||
534 | |||
535 | static void mxl111sf_demod_release(struct dvb_frontend *fe) | ||
536 | { | ||
537 | struct mxl111sf_demod_state *state = fe->demodulator_priv; | ||
538 | mxl_dbg("()"); | ||
539 | kfree(state); | ||
540 | fe->demodulator_priv = NULL; | ||
541 | } | ||
542 | |||
543 | static struct dvb_frontend_ops mxl111sf_demod_ops = { | ||
544 | |||
545 | .info = { | ||
546 | .name = "MxL111SF DVB-T", | ||
547 | .type = FE_OFDM, | ||
548 | .frequency_min = 177000000, | ||
549 | .frequency_max = 858000000, | ||
550 | .frequency_stepsize = 166666, | ||
551 | .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | | ||
552 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | | ||
553 | FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | | ||
554 | FE_CAN_QAM_AUTO | | ||
555 | FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | | ||
556 | FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER | ||
557 | }, | ||
558 | .release = mxl111sf_demod_release, | ||
559 | #if 0 | ||
560 | .init = mxl111sf_init, | ||
561 | .i2c_gate_ctrl = mxl111sf_i2c_gate_ctrl, | ||
562 | #endif | ||
563 | .set_frontend = mxl111sf_demod_set_frontend, | ||
564 | .get_frontend = mxl111sf_demod_get_frontend, | ||
565 | .get_tune_settings = mxl111sf_demod_get_tune_settings, | ||
566 | .read_status = mxl111sf_demod_read_status, | ||
567 | .read_signal_strength = mxl111sf_demod_read_signal_strength, | ||
568 | .read_ber = mxl111sf_demod_read_ber, | ||
569 | .read_snr = mxl111sf_demod_read_snr, | ||
570 | .read_ucblocks = mxl111sf_demod_read_ucblocks, | ||
571 | }; | ||
572 | |||
573 | struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state, | ||
574 | struct mxl111sf_demod_config *cfg) | ||
575 | { | ||
576 | struct mxl111sf_demod_state *state = NULL; | ||
577 | |||
578 | mxl_dbg("()"); | ||
579 | |||
580 | state = kzalloc(sizeof(struct mxl111sf_demod_state), GFP_KERNEL); | ||
581 | if (state == NULL) | ||
582 | return NULL; | ||
583 | |||
584 | state->mxl_state = mxl_state; | ||
585 | state->cfg = cfg; | ||
586 | |||
587 | memcpy(&state->fe.ops, &mxl111sf_demod_ops, | ||
588 | sizeof(struct dvb_frontend_ops)); | ||
589 | |||
590 | state->fe.demodulator_priv = state; | ||
591 | return &state->fe; | ||
592 | } | ||
593 | EXPORT_SYMBOL_GPL(mxl111sf_demod_attach); | ||
594 | |||
595 | MODULE_DESCRIPTION("MaxLinear MxL111SF DVB-T demodulator driver"); | ||
596 | MODULE_AUTHOR("Michael Krufky <mkrufky@kernellabs.com>"); | ||
597 | MODULE_LICENSE("GPL"); | ||
598 | MODULE_VERSION("0.1"); | ||
599 | |||
600 | /* | ||
601 | * Local variables: | ||
602 | * c-basic-offset: 8 | ||
603 | * End: | ||
604 | */ | ||
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-demod.h b/drivers/media/dvb/dvb-usb/mxl111sf-demod.h new file mode 100644 index 000000000000..432706ae5274 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/mxl111sf-demod.h | |||
@@ -0,0 +1,55 @@ | |||
1 | /* | ||
2 | * mxl111sf-demod.h - driver for the MaxLinear MXL111SF DVB-T demodulator | ||
3 | * | ||
4 | * Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com> | ||
5 | * | ||
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. | ||
10 | * | ||
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. | ||
15 | * | ||
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. | ||
19 | */ | ||
20 | |||
21 | #ifndef __MXL111SF_DEMOD_H__ | ||
22 | #define __MXL111SF_DEMOD_H__ | ||
23 | |||
24 | #include "dvb_frontend.h" | ||
25 | #include "mxl111sf.h" | ||
26 | |||
27 | struct mxl111sf_demod_config { | ||
28 | int (*read_reg)(struct mxl111sf_state *state, u8 addr, u8 *data); | ||
29 | int (*write_reg)(struct mxl111sf_state *state, u8 addr, u8 data); | ||
30 | int (*program_regs)(struct mxl111sf_state *state, | ||
31 | struct mxl111sf_reg_ctrl_info *ctrl_reg_info); | ||
32 | }; | ||
33 | |||
34 | #if defined(CONFIG_DVB_USB_MXL111SF) || \ | ||
35 | (defined(CONFIG_DVB_USB_MXL111SF_MODULE) && defined(MODULE)) | ||
36 | extern | ||
37 | struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state, | ||
38 | struct mxl111sf_demod_config *cfg); | ||
39 | #else | ||
40 | static inline | ||
41 | struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state, | ||
42 | struct mxl111sf_demod_config *cfg) | ||
43 | { | ||
44 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
45 | return NULL; | ||
46 | } | ||
47 | #endif /* CONFIG_DVB_USB_MXL111SF */ | ||
48 | |||
49 | #endif /* __MXL111SF_DEMOD_H__ */ | ||
50 | |||
51 | /* | ||
52 | * Local variables: | ||
53 | * c-basic-offset: 8 | ||
54 | * End: | ||
55 | */ | ||
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf.h b/drivers/media/dvb/dvb-usb/mxl111sf.h index 5a2c7bb386cd..364d89f826bd 100644 --- a/drivers/media/dvb/dvb-usb/mxl111sf.h +++ b/drivers/media/dvb/dvb-usb/mxl111sf.h | |||
@@ -133,7 +133,7 @@ extern int dvb_usb_mxl111sf_debug; | |||
133 | /* The following allows the mxl_fail() macro defined below to work | 133 | /* The following allows the mxl_fail() macro defined below to work |
134 | * in externel modules, such as mxl111sf-tuner.ko, even though | 134 | * in externel modules, such as mxl111sf-tuner.ko, even though |
135 | * dvb_usb_mxl111sf_debug is not defined within those modules */ | 135 | * dvb_usb_mxl111sf_debug is not defined within those modules */ |
136 | #ifdef __MXL111SF_TUNER_H__ | 136 | #if (defined(__MXL111SF_TUNER_H__)) || (defined(__MXL111SF_DEMOD_H__)) |
137 | #define MXL_ADV_DEBUG_ENABLED MXL_ADV_DBG | 137 | #define MXL_ADV_DEBUG_ENABLED MXL_ADV_DBG |
138 | #else | 138 | #else |
139 | #define MXL_ADV_DEBUG_ENABLED dvb_usb_mxl111sf_debug | 139 | #define MXL_ADV_DEBUG_ENABLED dvb_usb_mxl111sf_debug |