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