diff options
Diffstat (limited to 'drivers/media/dvb-frontends/or51132.c')
-rw-r--r-- | drivers/media/dvb-frontends/or51132.c | 631 |
1 files changed, 631 insertions, 0 deletions
diff --git a/drivers/media/dvb-frontends/or51132.c b/drivers/media/dvb-frontends/or51132.c new file mode 100644 index 000000000000..5ef921823c15 --- /dev/null +++ b/drivers/media/dvb-frontends/or51132.c | |||
@@ -0,0 +1,631 @@ | |||
1 | /* | ||
2 | * Support for OR51132 (pcHDTV HD-3000) - VSB/QAM | ||
3 | * | ||
4 | * | ||
5 | * Copyright (C) 2007 Trent Piepho <xyzzy@speakeasy.org> | ||
6 | * | ||
7 | * Copyright (C) 2005 Kirk Lapray <kirk_lapray@bigfoot.com> | ||
8 | * | ||
9 | * Based on code from Jack Kelliher (kelliher@xmission.com) | ||
10 | * Copyright (C) 2002 & pcHDTV, inc. | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
25 | * | ||
26 | */ | ||
27 | |||
28 | /* | ||
29 | * This driver needs two external firmware files. Please copy | ||
30 | * "dvb-fe-or51132-vsb.fw" and "dvb-fe-or51132-qam.fw" to | ||
31 | * /usr/lib/hotplug/firmware/ or /lib/firmware/ | ||
32 | * (depending on configuration of firmware hotplug). | ||
33 | */ | ||
34 | #define OR51132_VSB_FIRMWARE "dvb-fe-or51132-vsb.fw" | ||
35 | #define OR51132_QAM_FIRMWARE "dvb-fe-or51132-qam.fw" | ||
36 | |||
37 | #include <linux/kernel.h> | ||
38 | #include <linux/module.h> | ||
39 | #include <linux/init.h> | ||
40 | #include <linux/delay.h> | ||
41 | #include <linux/string.h> | ||
42 | #include <linux/slab.h> | ||
43 | #include <asm/byteorder.h> | ||
44 | |||
45 | #include "dvb_math.h" | ||
46 | #include "dvb_frontend.h" | ||
47 | #include "or51132.h" | ||
48 | |||
49 | static int debug; | ||
50 | #define dprintk(args...) \ | ||
51 | do { \ | ||
52 | if (debug) printk(KERN_DEBUG "or51132: " args); \ | ||
53 | } while (0) | ||
54 | |||
55 | |||
56 | struct or51132_state | ||
57 | { | ||
58 | struct i2c_adapter* i2c; | ||
59 | |||
60 | /* Configuration settings */ | ||
61 | const struct or51132_config* config; | ||
62 | |||
63 | struct dvb_frontend frontend; | ||
64 | |||
65 | /* Demodulator private data */ | ||
66 | fe_modulation_t current_modulation; | ||
67 | u32 snr; /* Result of last SNR calculation */ | ||
68 | |||
69 | /* Tuner private data */ | ||
70 | u32 current_frequency; | ||
71 | }; | ||
72 | |||
73 | |||
74 | /* Write buffer to demod */ | ||
75 | static int or51132_writebuf(struct or51132_state *state, const u8 *buf, int len) | ||
76 | { | ||
77 | int err; | ||
78 | struct i2c_msg msg = { .addr = state->config->demod_address, | ||
79 | .flags = 0, .buf = (u8*)buf, .len = len }; | ||
80 | |||
81 | /* msleep(20); */ /* doesn't appear to be necessary */ | ||
82 | if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { | ||
83 | printk(KERN_WARNING "or51132: I2C write (addr 0x%02x len %d) error: %d\n", | ||
84 | msg.addr, msg.len, err); | ||
85 | return -EREMOTEIO; | ||
86 | } | ||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | /* Write constant bytes, e.g. or51132_writebytes(state, 0x04, 0x42, 0x00); | ||
91 | Less code and more efficient that loading a buffer on the stack with | ||
92 | the bytes to send and then calling or51132_writebuf() on that. */ | ||
93 | #define or51132_writebytes(state, data...) \ | ||
94 | ({ static const u8 _data[] = {data}; \ | ||
95 | or51132_writebuf(state, _data, sizeof(_data)); }) | ||
96 | |||
97 | /* Read data from demod into buffer. Returns 0 on success. */ | ||
98 | static int or51132_readbuf(struct or51132_state *state, u8 *buf, int len) | ||
99 | { | ||
100 | int err; | ||
101 | struct i2c_msg msg = { .addr = state->config->demod_address, | ||
102 | .flags = I2C_M_RD, .buf = buf, .len = len }; | ||
103 | |||
104 | /* msleep(20); */ /* doesn't appear to be necessary */ | ||
105 | if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { | ||
106 | printk(KERN_WARNING "or51132: I2C read (addr 0x%02x len %d) error: %d\n", | ||
107 | msg.addr, msg.len, err); | ||
108 | return -EREMOTEIO; | ||
109 | } | ||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | /* Reads a 16-bit demod register. Returns <0 on error. */ | ||
114 | static int or51132_readreg(struct or51132_state *state, u8 reg) | ||
115 | { | ||
116 | u8 buf[2] = { 0x04, reg }; | ||
117 | struct i2c_msg msg[2] = { | ||
118 | {.addr = state->config->demod_address, .flags = 0, | ||
119 | .buf = buf, .len = 2 }, | ||
120 | {.addr = state->config->demod_address, .flags = I2C_M_RD, | ||
121 | .buf = buf, .len = 2 }}; | ||
122 | int err; | ||
123 | |||
124 | if ((err = i2c_transfer(state->i2c, msg, 2)) != 2) { | ||
125 | printk(KERN_WARNING "or51132: I2C error reading register %d: %d\n", | ||
126 | reg, err); | ||
127 | return -EREMOTEIO; | ||
128 | } | ||
129 | return buf[0] | (buf[1] << 8); | ||
130 | } | ||
131 | |||
132 | static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware *fw) | ||
133 | { | ||
134 | struct or51132_state* state = fe->demodulator_priv; | ||
135 | static const u8 run_buf[] = {0x7F,0x01}; | ||
136 | u8 rec_buf[8]; | ||
137 | u32 firmwareAsize, firmwareBsize; | ||
138 | int i,ret; | ||
139 | |||
140 | dprintk("Firmware is %Zd bytes\n",fw->size); | ||
141 | |||
142 | /* Get size of firmware A and B */ | ||
143 | firmwareAsize = le32_to_cpu(*((__le32*)fw->data)); | ||
144 | dprintk("FirmwareA is %i bytes\n",firmwareAsize); | ||
145 | firmwareBsize = le32_to_cpu(*((__le32*)(fw->data+4))); | ||
146 | dprintk("FirmwareB is %i bytes\n",firmwareBsize); | ||
147 | |||
148 | /* Upload firmware */ | ||
149 | if ((ret = or51132_writebuf(state, &fw->data[8], firmwareAsize))) { | ||
150 | printk(KERN_WARNING "or51132: load_firmware error 1\n"); | ||
151 | return ret; | ||
152 | } | ||
153 | if ((ret = or51132_writebuf(state, &fw->data[8+firmwareAsize], | ||
154 | firmwareBsize))) { | ||
155 | printk(KERN_WARNING "or51132: load_firmware error 2\n"); | ||
156 | return ret; | ||
157 | } | ||
158 | |||
159 | if ((ret = or51132_writebuf(state, run_buf, 2))) { | ||
160 | printk(KERN_WARNING "or51132: load_firmware error 3\n"); | ||
161 | return ret; | ||
162 | } | ||
163 | if ((ret = or51132_writebuf(state, run_buf, 2))) { | ||
164 | printk(KERN_WARNING "or51132: load_firmware error 4\n"); | ||
165 | return ret; | ||
166 | } | ||
167 | |||
168 | /* 50ms for operation to begin */ | ||
169 | msleep(50); | ||
170 | |||
171 | /* Read back ucode version to besure we loaded correctly and are really up and running */ | ||
172 | /* Get uCode version */ | ||
173 | if ((ret = or51132_writebytes(state, 0x10, 0x10, 0x00))) { | ||
174 | printk(KERN_WARNING "or51132: load_firmware error a\n"); | ||
175 | return ret; | ||
176 | } | ||
177 | if ((ret = or51132_writebytes(state, 0x04, 0x17))) { | ||
178 | printk(KERN_WARNING "or51132: load_firmware error b\n"); | ||
179 | return ret; | ||
180 | } | ||
181 | if ((ret = or51132_writebytes(state, 0x00, 0x00))) { | ||
182 | printk(KERN_WARNING "or51132: load_firmware error c\n"); | ||
183 | return ret; | ||
184 | } | ||
185 | for (i=0;i<4;i++) { | ||
186 | /* Once upon a time, this command might have had something | ||
187 | to do with getting the firmware version, but it's | ||
188 | not used anymore: | ||
189 | {0x04,0x00,0x30,0x00,i+1} */ | ||
190 | /* Read 8 bytes, two bytes at a time */ | ||
191 | if ((ret = or51132_readbuf(state, &rec_buf[i*2], 2))) { | ||
192 | printk(KERN_WARNING | ||
193 | "or51132: load_firmware error d - %d\n",i); | ||
194 | return ret; | ||
195 | } | ||
196 | } | ||
197 | |||
198 | printk(KERN_WARNING | ||
199 | "or51132: Version: %02X%02X%02X%02X-%02X%02X%02X%02X (%02X%01X-%01X-%02X%01X-%01X)\n", | ||
200 | rec_buf[1],rec_buf[0],rec_buf[3],rec_buf[2], | ||
201 | rec_buf[5],rec_buf[4],rec_buf[7],rec_buf[6], | ||
202 | rec_buf[3],rec_buf[2]>>4,rec_buf[2]&0x0f, | ||
203 | rec_buf[5],rec_buf[4]>>4,rec_buf[4]&0x0f); | ||
204 | |||
205 | if ((ret = or51132_writebytes(state, 0x10, 0x00, 0x00))) { | ||
206 | printk(KERN_WARNING "or51132: load_firmware error e\n"); | ||
207 | return ret; | ||
208 | } | ||
209 | return 0; | ||
210 | }; | ||
211 | |||
212 | static int or51132_init(struct dvb_frontend* fe) | ||
213 | { | ||
214 | return 0; | ||
215 | } | ||
216 | |||
217 | static int or51132_read_ber(struct dvb_frontend* fe, u32* ber) | ||
218 | { | ||
219 | *ber = 0; | ||
220 | return 0; | ||
221 | } | ||
222 | |||
223 | static int or51132_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) | ||
224 | { | ||
225 | *ucblocks = 0; | ||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | static int or51132_sleep(struct dvb_frontend* fe) | ||
230 | { | ||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | static int or51132_setmode(struct dvb_frontend* fe) | ||
235 | { | ||
236 | struct or51132_state* state = fe->demodulator_priv; | ||
237 | u8 cmd_buf1[3] = {0x04, 0x01, 0x5f}; | ||
238 | u8 cmd_buf2[3] = {0x1c, 0x00, 0 }; | ||
239 | |||
240 | dprintk("setmode %d\n",(int)state->current_modulation); | ||
241 | |||
242 | switch (state->current_modulation) { | ||
243 | case VSB_8: | ||
244 | /* Auto CH, Auto NTSC rej, MPEGser, MPEG2tr, phase noise-high */ | ||
245 | cmd_buf1[2] = 0x50; | ||
246 | /* REC MODE inv IF spectrum, Normal */ | ||
247 | cmd_buf2[1] = 0x03; | ||
248 | /* Channel MODE ATSC/VSB8 */ | ||
249 | cmd_buf2[2] = 0x06; | ||
250 | break; | ||
251 | /* All QAM modes are: | ||
252 | Auto-deinterleave; MPEGser, MPEG2tr, phase noise-high | ||
253 | REC MODE Normal Carrier Lock */ | ||
254 | case QAM_AUTO: | ||
255 | /* Channel MODE Auto QAM64/256 */ | ||
256 | cmd_buf2[2] = 0x4f; | ||
257 | break; | ||
258 | case QAM_256: | ||
259 | /* Channel MODE QAM256 */ | ||
260 | cmd_buf2[2] = 0x45; | ||
261 | break; | ||
262 | case QAM_64: | ||
263 | /* Channel MODE QAM64 */ | ||
264 | cmd_buf2[2] = 0x43; | ||
265 | break; | ||
266 | default: | ||
267 | printk(KERN_WARNING | ||
268 | "or51132: setmode: Modulation set to unsupported value (%d)\n", | ||
269 | state->current_modulation); | ||
270 | return -EINVAL; | ||
271 | } | ||
272 | |||
273 | /* Set Receiver 1 register */ | ||
274 | if (or51132_writebuf(state, cmd_buf1, 3)) { | ||
275 | printk(KERN_WARNING "or51132: set_mode error 1\n"); | ||
276 | return -EREMOTEIO; | ||
277 | } | ||
278 | dprintk("set #1 to %02x\n", cmd_buf1[2]); | ||
279 | |||
280 | /* Set operation mode in Receiver 6 register */ | ||
281 | if (or51132_writebuf(state, cmd_buf2, 3)) { | ||
282 | printk(KERN_WARNING "or51132: set_mode error 2\n"); | ||
283 | return -EREMOTEIO; | ||
284 | } | ||
285 | dprintk("set #6 to 0x%02x%02x\n", cmd_buf2[1], cmd_buf2[2]); | ||
286 | |||
287 | return 0; | ||
288 | } | ||
289 | |||
290 | /* Some modulations use the same firmware. This classifies modulations | ||
291 | by the firmware they use. */ | ||
292 | #define MOD_FWCLASS_UNKNOWN 0 | ||
293 | #define MOD_FWCLASS_VSB 1 | ||
294 | #define MOD_FWCLASS_QAM 2 | ||
295 | static int modulation_fw_class(fe_modulation_t modulation) | ||
296 | { | ||
297 | switch(modulation) { | ||
298 | case VSB_8: | ||
299 | return MOD_FWCLASS_VSB; | ||
300 | case QAM_AUTO: | ||
301 | case QAM_64: | ||
302 | case QAM_256: | ||
303 | return MOD_FWCLASS_QAM; | ||
304 | default: | ||
305 | return MOD_FWCLASS_UNKNOWN; | ||
306 | } | ||
307 | } | ||
308 | |||
309 | static int or51132_set_parameters(struct dvb_frontend *fe) | ||
310 | { | ||
311 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; | ||
312 | int ret; | ||
313 | struct or51132_state* state = fe->demodulator_priv; | ||
314 | const struct firmware *fw; | ||
315 | const char *fwname; | ||
316 | int clock_mode; | ||
317 | |||
318 | /* Upload new firmware only if we need a different one */ | ||
319 | if (modulation_fw_class(state->current_modulation) != | ||
320 | modulation_fw_class(p->modulation)) { | ||
321 | switch (modulation_fw_class(p->modulation)) { | ||
322 | case MOD_FWCLASS_VSB: | ||
323 | dprintk("set_parameters VSB MODE\n"); | ||
324 | fwname = OR51132_VSB_FIRMWARE; | ||
325 | |||
326 | /* Set non-punctured clock for VSB */ | ||
327 | clock_mode = 0; | ||
328 | break; | ||
329 | case MOD_FWCLASS_QAM: | ||
330 | dprintk("set_parameters QAM MODE\n"); | ||
331 | fwname = OR51132_QAM_FIRMWARE; | ||
332 | |||
333 | /* Set punctured clock for QAM */ | ||
334 | clock_mode = 1; | ||
335 | break; | ||
336 | default: | ||
337 | printk("or51132: Modulation type(%d) UNSUPPORTED\n", | ||
338 | p->modulation); | ||
339 | return -1; | ||
340 | } | ||
341 | printk("or51132: Waiting for firmware upload(%s)...\n", | ||
342 | fwname); | ||
343 | ret = request_firmware(&fw, fwname, state->i2c->dev.parent); | ||
344 | if (ret) { | ||
345 | printk(KERN_WARNING "or51132: No firmware up" | ||
346 | "loaded(timeout or file not found?)\n"); | ||
347 | return ret; | ||
348 | } | ||
349 | ret = or51132_load_firmware(fe, fw); | ||
350 | release_firmware(fw); | ||
351 | if (ret) { | ||
352 | printk(KERN_WARNING "or51132: Writing firmware to " | ||
353 | "device failed!\n"); | ||
354 | return ret; | ||
355 | } | ||
356 | printk("or51132: Firmware upload complete.\n"); | ||
357 | state->config->set_ts_params(fe, clock_mode); | ||
358 | } | ||
359 | /* Change only if we are actually changing the modulation */ | ||
360 | if (state->current_modulation != p->modulation) { | ||
361 | state->current_modulation = p->modulation; | ||
362 | or51132_setmode(fe); | ||
363 | } | ||
364 | |||
365 | if (fe->ops.tuner_ops.set_params) { | ||
366 | fe->ops.tuner_ops.set_params(fe); | ||
367 | if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); | ||
368 | } | ||
369 | |||
370 | /* Set to current mode */ | ||
371 | or51132_setmode(fe); | ||
372 | |||
373 | /* Update current frequency */ | ||
374 | state->current_frequency = p->frequency; | ||
375 | return 0; | ||
376 | } | ||
377 | |||
378 | static int or51132_get_parameters(struct dvb_frontend* fe) | ||
379 | { | ||
380 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; | ||
381 | struct or51132_state* state = fe->demodulator_priv; | ||
382 | int status; | ||
383 | int retry = 1; | ||
384 | |||
385 | start: | ||
386 | /* Receiver Status */ | ||
387 | if ((status = or51132_readreg(state, 0x00)) < 0) { | ||
388 | printk(KERN_WARNING "or51132: get_parameters: error reading receiver status\n"); | ||
389 | return -EREMOTEIO; | ||
390 | } | ||
391 | switch(status&0xff) { | ||
392 | case 0x06: | ||
393 | p->modulation = VSB_8; | ||
394 | break; | ||
395 | case 0x43: | ||
396 | p->modulation = QAM_64; | ||
397 | break; | ||
398 | case 0x45: | ||
399 | p->modulation = QAM_256; | ||
400 | break; | ||
401 | default: | ||
402 | if (retry--) | ||
403 | goto start; | ||
404 | printk(KERN_WARNING "or51132: unknown status 0x%02x\n", | ||
405 | status&0xff); | ||
406 | return -EREMOTEIO; | ||
407 | } | ||
408 | |||
409 | /* FIXME: Read frequency from frontend, take AFC into account */ | ||
410 | p->frequency = state->current_frequency; | ||
411 | |||
412 | /* FIXME: How to read inversion setting? Receiver 6 register? */ | ||
413 | p->inversion = INVERSION_AUTO; | ||
414 | |||
415 | return 0; | ||
416 | } | ||
417 | |||
418 | static int or51132_read_status(struct dvb_frontend* fe, fe_status_t* status) | ||
419 | { | ||
420 | struct or51132_state* state = fe->demodulator_priv; | ||
421 | int reg; | ||
422 | |||
423 | /* Receiver Status */ | ||
424 | if ((reg = or51132_readreg(state, 0x00)) < 0) { | ||
425 | printk(KERN_WARNING "or51132: read_status: error reading receiver status: %d\n", reg); | ||
426 | *status = 0; | ||
427 | return -EREMOTEIO; | ||
428 | } | ||
429 | dprintk("%s: read_status %04x\n", __func__, reg); | ||
430 | |||
431 | if (reg & 0x0100) /* Receiver Lock */ | ||
432 | *status = FE_HAS_SIGNAL|FE_HAS_CARRIER|FE_HAS_VITERBI| | ||
433 | FE_HAS_SYNC|FE_HAS_LOCK; | ||
434 | else | ||
435 | *status = 0; | ||
436 | return 0; | ||
437 | } | ||
438 | |||
439 | /* Calculate SNR estimation (scaled by 2^24) | ||
440 | |||
441 | 8-VSB SNR and QAM equations from Oren datasheets | ||
442 | |||
443 | For 8-VSB: | ||
444 | SNR[dB] = 10 * log10(897152044.8282 / MSE^2 ) - K | ||
445 | |||
446 | Where K = 0 if NTSC rejection filter is OFF; and | ||
447 | K = 3 if NTSC rejection filter is ON | ||
448 | |||
449 | For QAM64: | ||
450 | SNR[dB] = 10 * log10(897152044.8282 / MSE^2 ) | ||
451 | |||
452 | For QAM256: | ||
453 | SNR[dB] = 10 * log10(907832426.314266 / MSE^2 ) | ||
454 | |||
455 | We re-write the snr equation as: | ||
456 | SNR * 2^24 = 10*(c - 2*intlog10(MSE)) | ||
457 | Where for QAM256, c = log10(907832426.314266) * 2^24 | ||
458 | and for 8-VSB and QAM64, c = log10(897152044.8282) * 2^24 */ | ||
459 | |||
460 | static u32 calculate_snr(u32 mse, u32 c) | ||
461 | { | ||
462 | if (mse == 0) /* No signal */ | ||
463 | return 0; | ||
464 | |||
465 | mse = 2*intlog10(mse); | ||
466 | if (mse > c) { | ||
467 | /* Negative SNR, which is possible, but realisticly the | ||
468 | demod will lose lock before the signal gets this bad. The | ||
469 | API only allows for unsigned values, so just return 0 */ | ||
470 | return 0; | ||
471 | } | ||
472 | return 10*(c - mse); | ||
473 | } | ||
474 | |||
475 | static int or51132_read_snr(struct dvb_frontend* fe, u16* snr) | ||
476 | { | ||
477 | struct or51132_state* state = fe->demodulator_priv; | ||
478 | int noise, reg; | ||
479 | u32 c, usK = 0; | ||
480 | int retry = 1; | ||
481 | |||
482 | start: | ||
483 | /* SNR after Equalizer */ | ||
484 | noise = or51132_readreg(state, 0x02); | ||
485 | if (noise < 0) { | ||
486 | printk(KERN_WARNING "or51132: read_snr: error reading equalizer\n"); | ||
487 | return -EREMOTEIO; | ||
488 | } | ||
489 | dprintk("read_snr noise (%d)\n", noise); | ||
490 | |||
491 | /* Read status, contains modulation type for QAM_AUTO and | ||
492 | NTSC filter for VSB */ | ||
493 | reg = or51132_readreg(state, 0x00); | ||
494 | if (reg < 0) { | ||
495 | printk(KERN_WARNING "or51132: read_snr: error reading receiver status\n"); | ||
496 | return -EREMOTEIO; | ||
497 | } | ||
498 | |||
499 | switch (reg&0xff) { | ||
500 | case 0x06: | ||
501 | if (reg & 0x1000) usK = 3 << 24; | ||
502 | /* Fall through to QAM64 case */ | ||
503 | case 0x43: | ||
504 | c = 150204167; | ||
505 | break; | ||
506 | case 0x45: | ||
507 | c = 150290396; | ||
508 | break; | ||
509 | default: | ||
510 | printk(KERN_WARNING "or51132: unknown status 0x%02x\n", reg&0xff); | ||
511 | if (retry--) goto start; | ||
512 | return -EREMOTEIO; | ||
513 | } | ||
514 | dprintk("%s: modulation %02x, NTSC rej O%s\n", __func__, | ||
515 | reg&0xff, reg&0x1000?"n":"ff"); | ||
516 | |||
517 | /* Calculate SNR using noise, c, and NTSC rejection correction */ | ||
518 | state->snr = calculate_snr(noise, c) - usK; | ||
519 | *snr = (state->snr) >> 16; | ||
520 | |||
521 | dprintk("%s: noise = 0x%08x, snr = %d.%02d dB\n", __func__, noise, | ||
522 | state->snr >> 24, (((state->snr>>8) & 0xffff) * 100) >> 16); | ||
523 | |||
524 | return 0; | ||
525 | } | ||
526 | |||
527 | static int or51132_read_signal_strength(struct dvb_frontend* fe, u16* strength) | ||
528 | { | ||
529 | /* Calculate Strength from SNR up to 35dB */ | ||
530 | /* Even though the SNR can go higher than 35dB, there is some comfort */ | ||
531 | /* factor in having a range of strong signals that can show at 100% */ | ||
532 | struct or51132_state* state = (struct or51132_state*) fe->demodulator_priv; | ||
533 | u16 snr; | ||
534 | int ret; | ||
535 | |||
536 | ret = fe->ops.read_snr(fe, &snr); | ||
537 | if (ret != 0) | ||
538 | return ret; | ||
539 | /* Rather than use the 8.8 value snr, use state->snr which is 8.24 */ | ||
540 | /* scale the range 0 - 35*2^24 into 0 - 65535 */ | ||
541 | if (state->snr >= 8960 * 0x10000) | ||
542 | *strength = 0xffff; | ||
543 | else | ||
544 | *strength = state->snr / 8960; | ||
545 | |||
546 | return 0; | ||
547 | } | ||
548 | |||
549 | static int or51132_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fe_tune_settings) | ||
550 | { | ||
551 | fe_tune_settings->min_delay_ms = 500; | ||
552 | fe_tune_settings->step_size = 0; | ||
553 | fe_tune_settings->max_drift = 0; | ||
554 | |||
555 | return 0; | ||
556 | } | ||
557 | |||
558 | static void or51132_release(struct dvb_frontend* fe) | ||
559 | { | ||
560 | struct or51132_state* state = fe->demodulator_priv; | ||
561 | kfree(state); | ||
562 | } | ||
563 | |||
564 | static struct dvb_frontend_ops or51132_ops; | ||
565 | |||
566 | struct dvb_frontend* or51132_attach(const struct or51132_config* config, | ||
567 | struct i2c_adapter* i2c) | ||
568 | { | ||
569 | struct or51132_state* state = NULL; | ||
570 | |||
571 | /* Allocate memory for the internal state */ | ||
572 | state = kzalloc(sizeof(struct or51132_state), GFP_KERNEL); | ||
573 | if (state == NULL) | ||
574 | return NULL; | ||
575 | |||
576 | /* Setup the state */ | ||
577 | state->config = config; | ||
578 | state->i2c = i2c; | ||
579 | state->current_frequency = -1; | ||
580 | state->current_modulation = -1; | ||
581 | |||
582 | /* Create dvb_frontend */ | ||
583 | memcpy(&state->frontend.ops, &or51132_ops, sizeof(struct dvb_frontend_ops)); | ||
584 | state->frontend.demodulator_priv = state; | ||
585 | return &state->frontend; | ||
586 | } | ||
587 | |||
588 | static struct dvb_frontend_ops or51132_ops = { | ||
589 | .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, | ||
590 | .info = { | ||
591 | .name = "Oren OR51132 VSB/QAM Frontend", | ||
592 | .frequency_min = 44000000, | ||
593 | .frequency_max = 958000000, | ||
594 | .frequency_stepsize = 166666, | ||
595 | .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | | ||
596 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | | ||
597 | FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_QAM_AUTO | | ||
598 | FE_CAN_8VSB | ||
599 | }, | ||
600 | |||
601 | .release = or51132_release, | ||
602 | |||
603 | .init = or51132_init, | ||
604 | .sleep = or51132_sleep, | ||
605 | |||
606 | .set_frontend = or51132_set_parameters, | ||
607 | .get_frontend = or51132_get_parameters, | ||
608 | .get_tune_settings = or51132_get_tune_settings, | ||
609 | |||
610 | .read_status = or51132_read_status, | ||
611 | .read_ber = or51132_read_ber, | ||
612 | .read_signal_strength = or51132_read_signal_strength, | ||
613 | .read_snr = or51132_read_snr, | ||
614 | .read_ucblocks = or51132_read_ucblocks, | ||
615 | }; | ||
616 | |||
617 | module_param(debug, int, 0644); | ||
618 | MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); | ||
619 | |||
620 | MODULE_DESCRIPTION("OR51132 ATSC [pcHDTV HD-3000] (8VSB & ITU J83 AnnexB FEC QAM64/256) Demodulator Driver"); | ||
621 | MODULE_AUTHOR("Kirk Lapray"); | ||
622 | MODULE_AUTHOR("Trent Piepho"); | ||
623 | MODULE_LICENSE("GPL"); | ||
624 | |||
625 | EXPORT_SYMBOL(or51132_attach); | ||
626 | |||
627 | /* | ||
628 | * Local variables: | ||
629 | * c-basic-offset: 8 | ||
630 | * End: | ||
631 | */ | ||