Thomas Gleixner | c942fdd | 2019-05-27 08:55:06 +0200 | [diff] [blame^] | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2 | /* |
| 3 | * Support for OR51132 (pcHDTV HD-3000) - VSB/QAM |
| 4 | * |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 5 | * Copyright (C) 2007 Trent Piepho <xyzzy@speakeasy.org> |
| 6 | * |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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. |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 24 | #include <linux/init.h> |
| 25 | #include <linux/delay.h> |
Tim Schmielau | 4e57b68 | 2005-10-30 15:03:48 -0800 | [diff] [blame] | 26 | #include <linux/string.h> |
| 27 | #include <linux/slab.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 28 | #include <asm/byteorder.h> |
| 29 | |
Mauro Carvalho Chehab | fada193 | 2017-12-28 13:03:51 -0500 | [diff] [blame] | 30 | #include <media/dvb_math.h> |
| 31 | #include <media/dvb_frontend.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 44 | |
| 45 | /* Configuration settings */ |
| 46 | const struct or51132_config* config; |
| 47 | |
| 48 | struct dvb_frontend frontend; |
| 49 | |
| 50 | /* Demodulator private data */ |
Mauro Carvalho Chehab | 0df289a | 2015-06-07 14:53:52 -0300 | [diff] [blame] | 51 | enum fe_modulation current_modulation; |
Rusty Scott | b2fb7f5 | 2006-12-04 18:04:15 -0300 | [diff] [blame] | 52 | u32 snr; /* Result of last SNR calculation */ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 53 | |
| 54 | /* Tuner private data */ |
| 55 | u32 current_frequency; |
| 56 | }; |
| 57 | |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 58 | |
| 59 | /* Write buffer to demod */ |
| 60 | static int or51132_writebuf(struct or51132_state *state, const u8 *buf, int len) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 61 | { |
| 62 | int err; |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 63 | struct i2c_msg msg = { .addr = state->config->demod_address, |
| 64 | .flags = 0, .buf = (u8*)buf, .len = len }; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 65 | |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 66 | /* msleep(20); */ /* doesn't appear to be necessary */ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 67 | if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 68 | printk(KERN_WARNING "or51132: I2C write (addr 0x%02x len %d) error: %d\n", |
| 69 | msg.addr, msg.len, err); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 70 | return -EREMOTEIO; |
| 71 | } |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 72 | return 0; |
| 73 | } |
| 74 | |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 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...) \ |
Tobias Klauser | cbfa6f2 | 2008-04-21 22:27:50 +0000 | [diff] [blame] | 79 | ({ static const u8 _data[] = {data}; \ |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 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) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 84 | { |
| 85 | int err; |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 86 | struct i2c_msg msg = { .addr = state->config->demod_address, |
| 87 | .flags = I2C_M_RD, .buf = buf, .len = len }; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 88 | |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 89 | /* msleep(20); */ /* doesn't appear to be necessary */ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 90 | if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 91 | printk(KERN_WARNING "or51132: I2C read (addr 0x%02x len %d) error: %d\n", |
| 92 | msg.addr, msg.len, err); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 93 | return -EREMOTEIO; |
| 94 | } |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 95 | return 0; |
| 96 | } |
| 97 | |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 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(state->i2c, msg, 2)) != 2) { |
| 110 | printk(KERN_WARNING "or51132: I2C error reading register %d: %d\n", |
| 111 | reg, err); |
| 112 | return -EREMOTEIO; |
| 113 | } |
Al Viro | 18dcd55 | 2008-05-21 00:33:11 -0300 | [diff] [blame] | 114 | return buf[0] | (buf[1] << 8); |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 115 | } |
| 116 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 117 | static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware *fw) |
| 118 | { |
Johannes Stezenbach | b874270 | 2005-05-16 21:54:31 -0700 | [diff] [blame] | 119 | struct or51132_state* state = fe->demodulator_priv; |
Tobias Klauser | cbfa6f2 | 2008-04-21 22:27:50 +0000 | [diff] [blame] | 120 | static const u8 run_buf[] = {0x7F,0x01}; |
Trent Piepho | 0ead091 | 2006-04-02 20:40:33 -0300 | [diff] [blame] | 121 | u8 rec_buf[8]; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 122 | u32 firmwareAsize, firmwareBsize; |
| 123 | int i,ret; |
| 124 | |
Alexey Dobriyan | 5b5e092 | 2017-02-27 14:30:02 -0800 | [diff] [blame] | 125 | dprintk("Firmware is %zd bytes\n",fw->size); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 126 | |
| 127 | /* Get size of firmware A and B */ |
Al Viro | 18dcd55 | 2008-05-21 00:33:11 -0300 | [diff] [blame] | 128 | firmwareAsize = le32_to_cpu(*((__le32*)fw->data)); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 129 | dprintk("FirmwareA is %i bytes\n",firmwareAsize); |
Al Viro | 18dcd55 | 2008-05-21 00:33:11 -0300 | [diff] [blame] | 130 | firmwareBsize = le32_to_cpu(*((__le32*)(fw->data+4))); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 131 | dprintk("FirmwareB is %i bytes\n",firmwareBsize); |
| 132 | |
| 133 | /* Upload firmware */ |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 134 | if ((ret = or51132_writebuf(state, &fw->data[8], firmwareAsize))) { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 135 | printk(KERN_WARNING "or51132: load_firmware error 1\n"); |
| 136 | return ret; |
| 137 | } |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 138 | if ((ret = or51132_writebuf(state, &fw->data[8+firmwareAsize], |
| 139 | firmwareBsize))) { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 140 | printk(KERN_WARNING "or51132: load_firmware error 2\n"); |
| 141 | return ret; |
| 142 | } |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 143 | |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 144 | if ((ret = or51132_writebuf(state, run_buf, 2))) { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 145 | printk(KERN_WARNING "or51132: load_firmware error 3\n"); |
| 146 | return ret; |
| 147 | } |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 148 | if ((ret = or51132_writebuf(state, run_buf, 2))) { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 149 | printk(KERN_WARNING "or51132: load_firmware error 4\n"); |
| 150 | return ret; |
| 151 | } |
| 152 | |
| 153 | /* 50ms for operation to begin */ |
| 154 | msleep(50); |
| 155 | |
| 156 | /* Read back ucode version to besure we loaded correctly and are really up and running */ |
| 157 | /* Get uCode version */ |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 158 | if ((ret = or51132_writebytes(state, 0x10, 0x10, 0x00))) { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 159 | printk(KERN_WARNING "or51132: load_firmware error a\n"); |
| 160 | return ret; |
| 161 | } |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 162 | if ((ret = or51132_writebytes(state, 0x04, 0x17))) { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 163 | printk(KERN_WARNING "or51132: load_firmware error b\n"); |
| 164 | return ret; |
| 165 | } |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 166 | if ((ret = or51132_writebytes(state, 0x00, 0x00))) { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 167 | printk(KERN_WARNING "or51132: load_firmware error c\n"); |
| 168 | return ret; |
| 169 | } |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 170 | for (i=0;i<4;i++) { |
Michael Krufky | d147ed2a | 2006-04-03 01:29:09 -0300 | [diff] [blame] | 171 | /* Once upon a time, this command might have had something |
Trent Piepho | 0ead091 | 2006-04-02 20:40:33 -0300 | [diff] [blame] | 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 */ |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 176 | if ((ret = or51132_readbuf(state, &rec_buf[i*2], 2))) { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 | |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 190 | if ((ret = or51132_writebytes(state, 0x10, 0x00, 0x00))) { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 | { |
Johannes Stezenbach | b874270 | 2005-05-16 21:54:31 -0700 | [diff] [blame] | 221 | struct or51132_state* state = fe->demodulator_priv; |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 222 | u8 cmd_buf1[3] = {0x04, 0x01, 0x5f}; |
| 223 | u8 cmd_buf2[3] = {0x1c, 0x00, 0 }; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 224 | |
| 225 | dprintk("setmode %d\n",(int)state->current_modulation); |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 226 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 227 | switch (state->current_modulation) { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 228 | case VSB_8: |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 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; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 250 | break; |
| 251 | default: |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 252 | printk(KERN_WARNING |
| 253 | "or51132: setmode: Modulation set to unsupported value (%d)\n", |
| 254 | state->current_modulation); |
| 255 | return -EINVAL; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 256 | } |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 257 | |
| 258 | /* Set Receiver 1 register */ |
| 259 | if (or51132_writebuf(state, cmd_buf1, 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]); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 264 | |
| 265 | /* Set operation mode in Receiver 6 register */ |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 266 | if (or51132_writebuf(state, cmd_buf2, 3)) { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 267 | printk(KERN_WARNING "or51132: set_mode error 2\n"); |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 268 | return -EREMOTEIO; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 269 | } |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 270 | dprintk("set #6 to 0x%02x%02x\n", cmd_buf2[1], cmd_buf2[2]); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 271 | |
| 272 | return 0; |
| 273 | } |
| 274 | |
Trent Piepho | 8718455 | 2006-04-04 09:30:29 -0300 | [diff] [blame] | 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 |
Mauro Carvalho Chehab | 0df289a | 2015-06-07 14:53:52 -0300 | [diff] [blame] | 280 | static int modulation_fw_class(enum fe_modulation modulation) |
Trent Piepho | 8718455 | 2006-04-04 09:30:29 -0300 | [diff] [blame] | 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 | |
Mauro Carvalho Chehab | d8f7cc2 | 2011-12-26 15:01:57 -0300 | [diff] [blame] | 294 | static int or51132_set_parameters(struct dvb_frontend *fe) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 295 | { |
Mauro Carvalho Chehab | d8f7cc2 | 2011-12-26 15:01:57 -0300 | [diff] [blame] | 296 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 297 | int ret; |
Johannes Stezenbach | b874270 | 2005-05-16 21:54:31 -0700 | [diff] [blame] | 298 | struct or51132_state* state = fe->demodulator_priv; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 299 | const struct firmware *fw; |
Trent Piepho | 8718455 | 2006-04-04 09:30:29 -0300 | [diff] [blame] | 300 | const char *fwname; |
| 301 | int clock_mode; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 302 | |
Trent Piepho | 8718455 | 2006-04-04 09:30:29 -0300 | [diff] [blame] | 303 | /* Upload new firmware only if we need a different one */ |
| 304 | if (modulation_fw_class(state->current_modulation) != |
Mauro Carvalho Chehab | d8f7cc2 | 2011-12-26 15:01:57 -0300 | [diff] [blame] | 305 | modulation_fw_class(p->modulation)) { |
| 306 | switch (modulation_fw_class(p->modulation)) { |
Trent Piepho | 8718455 | 2006-04-04 09:30:29 -0300 | [diff] [blame] | 307 | case MOD_FWCLASS_VSB: |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 308 | dprintk("set_parameters VSB MODE\n"); |
Trent Piepho | 8718455 | 2006-04-04 09:30:29 -0300 | [diff] [blame] | 309 | fwname = OR51132_VSB_FIRMWARE; |
| 310 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 311 | /* Set non-punctured clock for VSB */ |
Trent Piepho | 8718455 | 2006-04-04 09:30:29 -0300 | [diff] [blame] | 312 | clock_mode = 0; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 313 | break; |
Trent Piepho | 8718455 | 2006-04-04 09:30:29 -0300 | [diff] [blame] | 314 | case MOD_FWCLASS_QAM: |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 315 | dprintk("set_parameters QAM MODE\n"); |
Trent Piepho | 8718455 | 2006-04-04 09:30:29 -0300 | [diff] [blame] | 316 | fwname = OR51132_QAM_FIRMWARE; |
| 317 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 318 | /* Set punctured clock for QAM */ |
Trent Piepho | 8718455 | 2006-04-04 09:30:29 -0300 | [diff] [blame] | 319 | clock_mode = 1; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 320 | break; |
| 321 | default: |
Trent Piepho | 8718455 | 2006-04-04 09:30:29 -0300 | [diff] [blame] | 322 | printk("or51132: Modulation type(%d) UNSUPPORTED\n", |
Mauro Carvalho Chehab | d8f7cc2 | 2011-12-26 15:01:57 -0300 | [diff] [blame] | 323 | p->modulation); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 324 | return -1; |
Trent Piepho | 8718455 | 2006-04-04 09:30:29 -0300 | [diff] [blame] | 325 | } |
| 326 | printk("or51132: Waiting for firmware upload(%s)...\n", |
| 327 | fwname); |
Jean Delvare | e978525 | 2009-04-26 05:43:59 -0300 | [diff] [blame] | 328 | ret = request_firmware(&fw, fwname, state->i2c->dev.parent); |
Trent Piepho | 8718455 | 2006-04-04 09:30:29 -0300 | [diff] [blame] | 329 | if (ret) { |
Mauro Carvalho Chehab | 4bd69e7 | 2016-10-18 17:44:22 -0200 | [diff] [blame] | 330 | printk(KERN_WARNING "or51132: No firmware uploaded(timeout or file not found?)\n"); |
Trent Piepho | 8718455 | 2006-04-04 09:30:29 -0300 | [diff] [blame] | 331 | return ret; |
| 332 | } |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 333 | ret = or51132_load_firmware(fe, fw); |
| 334 | release_firmware(fw); |
| 335 | if (ret) { |
Mauro Carvalho Chehab | 4bd69e7 | 2016-10-18 17:44:22 -0200 | [diff] [blame] | 336 | printk(KERN_WARNING "or51132: Writing firmware to device failed!\n"); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 337 | return ret; |
| 338 | } |
| 339 | printk("or51132: Firmware upload complete.\n"); |
Trent Piepho | 8718455 | 2006-04-04 09:30:29 -0300 | [diff] [blame] | 340 | state->config->set_ts_params(fe, clock_mode); |
| 341 | } |
| 342 | /* Change only if we are actually changing the modulation */ |
Mauro Carvalho Chehab | d8f7cc2 | 2011-12-26 15:01:57 -0300 | [diff] [blame] | 343 | if (state->current_modulation != p->modulation) { |
| 344 | state->current_modulation = p->modulation; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 345 | or51132_setmode(fe); |
| 346 | } |
| 347 | |
Patrick Boettcher | dea7486 | 2006-05-14 05:01:31 -0300 | [diff] [blame] | 348 | if (fe->ops.tuner_ops.set_params) { |
Mauro Carvalho Chehab | 14d24d1 | 2011-12-24 12:24:33 -0300 | [diff] [blame] | 349 | fe->ops.tuner_ops.set_params(fe); |
Patrick Boettcher | dea7486 | 2006-05-14 05:01:31 -0300 | [diff] [blame] | 350 | if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); |
Andrew de Quincey | 44d92aa | 2006-04-18 17:47:10 -0300 | [diff] [blame] | 351 | } |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 352 | |
Mac Michaels | 80e27e2 | 2005-09-09 13:02:40 -0700 | [diff] [blame] | 353 | /* Set to current mode */ |
| 354 | or51132_setmode(fe); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 355 | |
Mac Michaels | 80e27e2 | 2005-09-09 13:02:40 -0700 | [diff] [blame] | 356 | /* Update current frequency */ |
Mauro Carvalho Chehab | d8f7cc2 | 2011-12-26 15:01:57 -0300 | [diff] [blame] | 357 | state->current_frequency = p->frequency; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 358 | return 0; |
| 359 | } |
| 360 | |
Mauro Carvalho Chehab | 7e3e68b | 2016-02-04 12:58:30 -0200 | [diff] [blame] | 361 | static int or51132_get_parameters(struct dvb_frontend* fe, |
| 362 | struct dtv_frontend_properties *p) |
Trent Piepho | 0dbbc0a | 2006-04-06 06:03:09 -0300 | [diff] [blame] | 363 | { |
| 364 | struct or51132_state* state = fe->demodulator_priv; |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 365 | int status; |
| 366 | int retry = 1; |
Trent Piepho | 0dbbc0a | 2006-04-06 06:03:09 -0300 | [diff] [blame] | 367 | |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 368 | start: |
Trent Piepho | 0dbbc0a | 2006-04-06 06:03:09 -0300 | [diff] [blame] | 369 | /* Receiver Status */ |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 370 | if ((status = or51132_readreg(state, 0x00)) < 0) { |
| 371 | printk(KERN_WARNING "or51132: get_parameters: error reading receiver status\n"); |
Trent Piepho | 0dbbc0a | 2006-04-06 06:03:09 -0300 | [diff] [blame] | 372 | return -EREMOTEIO; |
| 373 | } |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 374 | switch(status&0xff) { |
Mauro Carvalho Chehab | d8f7cc2 | 2011-12-26 15:01:57 -0300 | [diff] [blame] | 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; |
Trent Piepho | 0dbbc0a | 2006-04-06 06:03:09 -0300 | [diff] [blame] | 390 | } |
| 391 | |
| 392 | /* FIXME: Read frequency from frontend, take AFC into account */ |
Mauro Carvalho Chehab | d8f7cc2 | 2011-12-26 15:01:57 -0300 | [diff] [blame] | 393 | p->frequency = state->current_frequency; |
Trent Piepho | 0dbbc0a | 2006-04-06 06:03:09 -0300 | [diff] [blame] | 394 | |
| 395 | /* FIXME: How to read inversion setting? Receiver 6 register? */ |
Mauro Carvalho Chehab | d8f7cc2 | 2011-12-26 15:01:57 -0300 | [diff] [blame] | 396 | p->inversion = INVERSION_AUTO; |
Trent Piepho | 0dbbc0a | 2006-04-06 06:03:09 -0300 | [diff] [blame] | 397 | |
| 398 | return 0; |
| 399 | } |
| 400 | |
Mauro Carvalho Chehab | 0df289a | 2015-06-07 14:53:52 -0300 | [diff] [blame] | 401 | static int or51132_read_status(struct dvb_frontend *fe, enum fe_status *status) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 402 | { |
Johannes Stezenbach | b874270 | 2005-05-16 21:54:31 -0700 | [diff] [blame] | 403 | struct or51132_state* state = fe->demodulator_priv; |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 404 | int reg; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 405 | |
| 406 | /* Receiver Status */ |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 407 | if ((reg = or51132_readreg(state, 0x00)) < 0) { |
| 408 | printk(KERN_WARNING "or51132: read_status: error reading receiver status: %d\n", reg); |
| 409 | *status = 0; |
| 410 | return -EREMOTEIO; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 411 | } |
Harvey Harrison | 271ddbf | 2008-04-08 23:20:00 -0300 | [diff] [blame] | 412 | dprintk("%s: read_status %04x\n", __func__, reg); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 413 | |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 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; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 419 | return 0; |
| 420 | } |
| 421 | |
Rusty Scott | b2fb7f5 | 2006-12-04 18:04:15 -0300 | [diff] [blame] | 422 | /* Calculate SNR estimation (scaled by 2^24) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 423 | |
Rusty Scott | b2fb7f5 | 2006-12-04 18:04:15 -0300 | [diff] [blame] | 424 | 8-VSB SNR and QAM equations from Oren datasheets |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 425 | |
Rusty Scott | b2fb7f5 | 2006-12-04 18:04:15 -0300 | [diff] [blame] | 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) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 444 | { |
Rusty Scott | b2fb7f5 | 2006-12-04 18:04:15 -0300 | [diff] [blame] | 445 | if (mse == 0) /* No signal */ |
| 446 | return 0; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 447 | |
Rusty Scott | b2fb7f5 | 2006-12-04 18:04:15 -0300 | [diff] [blame] | 448 | mse = 2*intlog10(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; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 454 | } |
Rusty Scott | b2fb7f5 | 2006-12-04 18:04:15 -0300 | [diff] [blame] | 455 | return 10*(c - mse); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 456 | } |
| 457 | |
| 458 | static int or51132_read_snr(struct dvb_frontend* fe, u16* snr) |
| 459 | { |
Johannes Stezenbach | b874270 | 2005-05-16 21:54:31 -0700 | [diff] [blame] | 460 | struct or51132_state* state = fe->demodulator_priv; |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 461 | int noise, reg; |
| 462 | u32 c, usK = 0; |
| 463 | int retry = 1; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 464 | |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 465 | start: |
| 466 | /* SNR after Equalizer */ |
| 467 | noise = or51132_readreg(state, 0x02); |
| 468 | if (noise < 0) { |
| 469 | printk(KERN_WARNING "or51132: read_snr: error reading equalizer\n"); |
Rusty Scott | b2fb7f5 | 2006-12-04 18:04:15 -0300 | [diff] [blame] | 470 | return -EREMOTEIO; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 471 | } |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 472 | dprintk("read_snr noise (%d)\n", noise); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 473 | |
Rusty Scott | b2fb7f5 | 2006-12-04 18:04:15 -0300 | [diff] [blame] | 474 | /* Read status, contains modulation type for QAM_AUTO and |
| 475 | NTSC filter for VSB */ |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 476 | reg = or51132_readreg(state, 0x00); |
| 477 | if (reg < 0) { |
| 478 | printk(KERN_WARNING "or51132: read_snr: error reading receiver status\n"); |
Rusty Scott | b2fb7f5 | 2006-12-04 18:04:15 -0300 | [diff] [blame] | 479 | return -EREMOTEIO; |
| 480 | } |
| 481 | |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 482 | switch (reg&0xff) { |
Rusty Scott | b2fb7f5 | 2006-12-04 18:04:15 -0300 | [diff] [blame] | 483 | case 0x06: |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 484 | if (reg & 0x1000) usK = 3 << 24; |
Mauro Carvalho Chehab | 06eeefe | 2017-05-18 08:13:28 -0300 | [diff] [blame] | 485 | /* fall through */ |
| 486 | case 0x43: /* QAM64 */ |
Rusty Scott | b2fb7f5 | 2006-12-04 18:04:15 -0300 | [diff] [blame] | 487 | c = 150204167; |
| 488 | break; |
| 489 | case 0x45: |
| 490 | c = 150290396; |
| 491 | break; |
| 492 | default: |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 493 | printk(KERN_WARNING "or51132: unknown status 0x%02x\n", reg&0xff); |
| 494 | if (retry--) goto start; |
Rusty Scott | b2fb7f5 | 2006-12-04 18:04:15 -0300 | [diff] [blame] | 495 | return -EREMOTEIO; |
| 496 | } |
Harvey Harrison | 271ddbf | 2008-04-08 23:20:00 -0300 | [diff] [blame] | 497 | dprintk("%s: modulation %02x, NTSC rej O%s\n", __func__, |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 498 | reg&0xff, reg&0x1000?"n":"ff"); |
Rusty Scott | b2fb7f5 | 2006-12-04 18:04:15 -0300 | [diff] [blame] | 499 | |
| 500 | /* Calculate SNR using noise, c, and NTSC rejection correction */ |
| 501 | state->snr = calculate_snr(noise, c) - usK; |
| 502 | *snr = (state->snr) >> 16; |
| 503 | |
Harvey Harrison | 271ddbf | 2008-04-08 23:20:00 -0300 | [diff] [blame] | 504 | dprintk("%s: noise = 0x%08x, snr = %d.%02d dB\n", __func__, noise, |
Rusty Scott | b2fb7f5 | 2006-12-04 18:04:15 -0300 | [diff] [blame] | 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; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 | { |
Johannes Stezenbach | b874270 | 2005-05-16 21:54:31 -0700 | [diff] [blame] | 543 | struct or51132_state* state = fe->demodulator_priv; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 544 | kfree(state); |
| 545 | } |
| 546 | |
Max Kellermann | bd336e6 | 2016-08-09 18:32:21 -0300 | [diff] [blame] | 547 | static const struct dvb_frontend_ops or51132_ops; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 */ |
Matthias Schwarzott | 084e24a | 2009-08-10 22:51:01 -0300 | [diff] [blame] | 555 | state = kzalloc(sizeof(struct or51132_state), GFP_KERNEL); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 556 | if (state == NULL) |
Mauro Carvalho Chehab | 3473e34 | 2008-01-07 10:45:47 -0300 | [diff] [blame] | 557 | return NULL; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 558 | |
| 559 | /* Setup the state */ |
| 560 | state->config = config; |
| 561 | state->i2c = i2c; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 562 | state->current_frequency = -1; |
| 563 | state->current_modulation = -1; |
| 564 | |
| 565 | /* Create dvb_frontend */ |
Patrick Boettcher | dea7486 | 2006-05-14 05:01:31 -0300 | [diff] [blame] | 566 | memcpy(&state->frontend.ops, &or51132_ops, sizeof(struct dvb_frontend_ops)); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 567 | state->frontend.demodulator_priv = state; |
| 568 | return &state->frontend; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 569 | } |
| 570 | |
Max Kellermann | bd336e6 | 2016-08-09 18:32:21 -0300 | [diff] [blame] | 571 | static const struct dvb_frontend_ops or51132_ops = { |
Mauro Carvalho Chehab | d8f7cc2 | 2011-12-26 15:01:57 -0300 | [diff] [blame] | 572 | .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 573 | .info = { |
| 574 | .name = "Oren OR51132 VSB/QAM Frontend", |
Mauro Carvalho Chehab | f1b1eab | 2018-07-05 18:59:36 -0400 | [diff] [blame] | 575 | .frequency_min_hz = 44 * MHz, |
| 576 | .frequency_max_hz = 958 * MHz, |
| 577 | .frequency_stepsize_hz = 166666, |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 | |
Mauro Carvalho Chehab | d8f7cc2 | 2011-12-26 15:01:57 -0300 | [diff] [blame] | 589 | .set_frontend = or51132_set_parameters, |
| 590 | .get_frontend = or51132_get_parameters, |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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"); |
Trent Piepho | d9e5432 | 2007-03-02 19:42:21 -0300 | [diff] [blame] | 605 | MODULE_AUTHOR("Trent Piepho"); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 606 | MODULE_LICENSE("GPL"); |
| 607 | |
| 608 | EXPORT_SYMBOL(or51132_attach); |