Commit | Line | Data |
---|---|---|
c942fddf | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
1da177e4 LT |
2 | /* |
3 | * Support for OR51132 (pcHDTV HD-3000) - VSB/QAM | |
4 | * | |
d9e54324 TP |
5 | * Copyright (C) 2007 Trent Piepho <xyzzy@speakeasy.org> |
6 | * | |
1da177e4 LT |
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. | |
1da177e4 LT |
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> | |
1da177e4 LT |
24 | #include <linux/init.h> |
25 | #include <linux/delay.h> | |
4e57b681 TS |
26 | #include <linux/string.h> |
27 | #include <linux/slab.h> | |
1da177e4 LT |
28 | #include <asm/byteorder.h> |
29 | ||
fada1935 MCC |
30 | #include <media/dvb_math.h> |
31 | #include <media/dvb_frontend.h> | |
1da177e4 LT |
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; | |
1da177e4 LT |
44 | |
45 | /* Configuration settings */ | |
46 | const struct or51132_config* config; | |
47 | ||
48 | struct dvb_frontend frontend; | |
49 | ||
50 | /* Demodulator private data */ | |
0df289a2 | 51 | enum fe_modulation current_modulation; |
b2fb7f55 | 52 | u32 snr; /* Result of last SNR calculation */ |
1da177e4 LT |
53 | |
54 | /* Tuner private data */ | |
55 | u32 current_frequency; | |
56 | }; | |
57 | ||
d9e54324 TP |
58 | |
59 | /* Write buffer to demod */ | |
60 | static int or51132_writebuf(struct or51132_state *state, const u8 *buf, int len) | |
1da177e4 LT |
61 | { |
62 | int err; | |
d9e54324 TP |
63 | struct i2c_msg msg = { .addr = state->config->demod_address, |
64 | .flags = 0, .buf = (u8*)buf, .len = len }; | |
1da177e4 | 65 | |
d9e54324 | 66 | /* msleep(20); */ /* doesn't appear to be necessary */ |
1da177e4 | 67 | if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { |
d9e54324 TP |
68 | printk(KERN_WARNING "or51132: I2C write (addr 0x%02x len %d) error: %d\n", |
69 | msg.addr, msg.len, err); | |
1da177e4 LT |
70 | return -EREMOTEIO; |
71 | } | |
1da177e4 LT |
72 | return 0; |
73 | } | |
74 | ||
d9e54324 TP |
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...) \ | |
cbfa6f2a | 79 | ({ static const u8 _data[] = {data}; \ |
d9e54324 TP |
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) | |
1da177e4 LT |
84 | { |
85 | int err; | |
d9e54324 TP |
86 | struct i2c_msg msg = { .addr = state->config->demod_address, |
87 | .flags = I2C_M_RD, .buf = buf, .len = len }; | |
1da177e4 | 88 | |
d9e54324 | 89 | /* msleep(20); */ /* doesn't appear to be necessary */ |
1da177e4 | 90 | if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { |
d9e54324 TP |
91 | printk(KERN_WARNING "or51132: I2C read (addr 0x%02x len %d) error: %d\n", |
92 | msg.addr, msg.len, err); | |
1da177e4 LT |
93 | return -EREMOTEIO; |
94 | } | |
1da177e4 LT |
95 | return 0; |
96 | } | |
97 | ||
d9e54324 TP |
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 | } | |
18dcd55a | 114 | return buf[0] | (buf[1] << 8); |
d9e54324 TP |
115 | } |
116 | ||
1da177e4 LT |
117 | static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware *fw) |
118 | { | |
b8742700 | 119 | struct or51132_state* state = fe->demodulator_priv; |
cbfa6f2a | 120 | static const u8 run_buf[] = {0x7F,0x01}; |
0ead0918 | 121 | u8 rec_buf[8]; |
1da177e4 LT |
122 | u32 firmwareAsize, firmwareBsize; |
123 | int i,ret; | |
124 | ||
5b5e0928 | 125 | dprintk("Firmware is %zd bytes\n",fw->size); |
1da177e4 LT |
126 | |
127 | /* Get size of firmware A and B */ | |
18dcd55a | 128 | firmwareAsize = le32_to_cpu(*((__le32*)fw->data)); |
1da177e4 | 129 | dprintk("FirmwareA is %i bytes\n",firmwareAsize); |
18dcd55a | 130 | firmwareBsize = le32_to_cpu(*((__le32*)(fw->data+4))); |
1da177e4 LT |
131 | dprintk("FirmwareB is %i bytes\n",firmwareBsize); |
132 | ||
133 | /* Upload firmware */ | |
d9e54324 | 134 | if ((ret = or51132_writebuf(state, &fw->data[8], firmwareAsize))) { |
1da177e4 LT |
135 | printk(KERN_WARNING "or51132: load_firmware error 1\n"); |
136 | return ret; | |
137 | } | |
d9e54324 TP |
138 | if ((ret = or51132_writebuf(state, &fw->data[8+firmwareAsize], |
139 | firmwareBsize))) { | |
1da177e4 LT |
140 | printk(KERN_WARNING "or51132: load_firmware error 2\n"); |
141 | return ret; | |
142 | } | |
1da177e4 | 143 | |
d9e54324 | 144 | if ((ret = or51132_writebuf(state, run_buf, 2))) { |
1da177e4 LT |
145 | printk(KERN_WARNING "or51132: load_firmware error 3\n"); |
146 | return ret; | |
147 | } | |
d9e54324 | 148 | if ((ret = or51132_writebuf(state, run_buf, 2))) { |
1da177e4 LT |
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 */ | |
d9e54324 | 158 | if ((ret = or51132_writebytes(state, 0x10, 0x10, 0x00))) { |
1da177e4 LT |
159 | printk(KERN_WARNING "or51132: load_firmware error a\n"); |
160 | return ret; | |
161 | } | |
d9e54324 | 162 | if ((ret = or51132_writebytes(state, 0x04, 0x17))) { |
1da177e4 LT |
163 | printk(KERN_WARNING "or51132: load_firmware error b\n"); |
164 | return ret; | |
165 | } | |
d9e54324 | 166 | if ((ret = or51132_writebytes(state, 0x00, 0x00))) { |
1da177e4 LT |
167 | printk(KERN_WARNING "or51132: load_firmware error c\n"); |
168 | return ret; | |
169 | } | |
d9e54324 | 170 | for (i=0;i<4;i++) { |
d147ed2a | 171 | /* Once upon a time, this command might have had something |
0ead0918 TP |
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 */ | |
d9e54324 | 176 | if ((ret = or51132_readbuf(state, &rec_buf[i*2], 2))) { |
1da177e4 LT |
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 | ||
d9e54324 | 190 | if ((ret = or51132_writebytes(state, 0x10, 0x00, 0x00))) { |
1da177e4 LT |
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 | { | |
b8742700 | 221 | struct or51132_state* state = fe->demodulator_priv; |
d9e54324 TP |
222 | u8 cmd_buf1[3] = {0x04, 0x01, 0x5f}; |
223 | u8 cmd_buf2[3] = {0x1c, 0x00, 0 }; | |
1da177e4 LT |
224 | |
225 | dprintk("setmode %d\n",(int)state->current_modulation); | |
d9e54324 | 226 | |
1da177e4 | 227 | switch (state->current_modulation) { |
1da177e4 | 228 | case VSB_8: |
d9e54324 TP |
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; | |
1da177e4 | 235 | break; |
d9e54324 TP |
236 | /* All QAM modes are: |
237 | Auto-deinterleave; MPEGser, MPEG2tr, phase noise-high | |
238 | REC MODE Normal Carrier Lock */ | |
1da177e4 | 239 | case QAM_AUTO: |
1da177e4 | 240 | /* Channel MODE Auto QAM64/256 */ |
d9e54324 | 241 | cmd_buf2[2] = 0x4f; |
1da177e4 LT |
242 | break; |
243 | case QAM_256: | |
1da177e4 | 244 | /* Channel MODE QAM256 */ |
d9e54324 | 245 | cmd_buf2[2] = 0x45; |
1da177e4 LT |
246 | break; |
247 | case QAM_64: | |
1da177e4 | 248 | /* Channel MODE QAM64 */ |
d9e54324 | 249 | cmd_buf2[2] = 0x43; |
1da177e4 LT |
250 | break; |
251 | default: | |
d9e54324 TP |
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, 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]); | |
264 | ||
265 | /* Set operation mode in Receiver 6 register */ | |
266 | if (or51132_writebuf(state, cmd_buf2, 3)) { | |
1da177e4 | 267 | printk(KERN_WARNING "or51132: set_mode error 2\n"); |
d9e54324 | 268 | return -EREMOTEIO; |
1da177e4 | 269 | } |
d9e54324 | 270 | dprintk("set #6 to 0x%02x%02x\n", cmd_buf2[1], cmd_buf2[2]); |
1da177e4 LT |
271 | |
272 | return 0; | |
273 | } | |
274 | ||
87184554 TP |
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 | |
0df289a2 | 280 | static int modulation_fw_class(enum fe_modulation modulation) |
87184554 TP |
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 | ||
d8f7cc28 | 294 | static int or51132_set_parameters(struct dvb_frontend *fe) |
1da177e4 | 295 | { |
d8f7cc28 | 296 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; |
1da177e4 | 297 | int ret; |
b8742700 | 298 | struct or51132_state* state = fe->demodulator_priv; |
1da177e4 | 299 | const struct firmware *fw; |
87184554 TP |
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(state->current_modulation) != | |
d8f7cc28 MCC |
305 | modulation_fw_class(p->modulation)) { |
306 | switch (modulation_fw_class(p->modulation)) { | |
87184554 | 307 | case MOD_FWCLASS_VSB: |
1da177e4 | 308 | dprintk("set_parameters VSB MODE\n"); |
87184554 TP |
309 | fwname = OR51132_VSB_FIRMWARE; |
310 | ||
1da177e4 | 311 | /* Set non-punctured clock for VSB */ |
87184554 | 312 | clock_mode = 0; |
1da177e4 | 313 | break; |
87184554 | 314 | case MOD_FWCLASS_QAM: |
1da177e4 | 315 | dprintk("set_parameters QAM MODE\n"); |
87184554 TP |
316 | fwname = OR51132_QAM_FIRMWARE; |
317 | ||
1da177e4 | 318 | /* Set punctured clock for QAM */ |
87184554 | 319 | clock_mode = 1; |
1da177e4 LT |
320 | break; |
321 | default: | |
87184554 | 322 | printk("or51132: Modulation type(%d) UNSUPPORTED\n", |
d8f7cc28 | 323 | p->modulation); |
1da177e4 | 324 | return -1; |
87184554 TP |
325 | } |
326 | printk("or51132: Waiting for firmware upload(%s)...\n", | |
327 | fwname); | |
e9785250 | 328 | ret = request_firmware(&fw, fwname, state->i2c->dev.parent); |
87184554 | 329 | if (ret) { |
4bd69e7b | 330 | printk(KERN_WARNING "or51132: No firmware uploaded(timeout or file not found?)\n"); |
87184554 TP |
331 | return ret; |
332 | } | |
1da177e4 LT |
333 | ret = or51132_load_firmware(fe, fw); |
334 | release_firmware(fw); | |
335 | if (ret) { | |
4bd69e7b | 336 | printk(KERN_WARNING "or51132: Writing firmware to device failed!\n"); |
1da177e4 LT |
337 | return ret; |
338 | } | |
339 | printk("or51132: Firmware upload complete.\n"); | |
87184554 TP |
340 | state->config->set_ts_params(fe, clock_mode); |
341 | } | |
342 | /* Change only if we are actually changing the modulation */ | |
d8f7cc28 MCC |
343 | if (state->current_modulation != p->modulation) { |
344 | state->current_modulation = p->modulation; | |
1da177e4 LT |
345 | or51132_setmode(fe); |
346 | } | |
347 | ||
dea74869 | 348 | if (fe->ops.tuner_ops.set_params) { |
14d24d14 | 349 | fe->ops.tuner_ops.set_params(fe); |
dea74869 | 350 | if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); |
44d92aa7 | 351 | } |
80e27e20 MM |
352 | |
353 | /* Set to current mode */ | |
354 | or51132_setmode(fe); | |
355 | ||
356 | /* Update current frequency */ | |
d8f7cc28 | 357 | state->current_frequency = p->frequency; |
1da177e4 LT |
358 | return 0; |
359 | } | |
360 | ||
7e3e68bc MCC |
361 | static int or51132_get_parameters(struct dvb_frontend* fe, |
362 | struct dtv_frontend_properties *p) | |
0dbbc0a7 TP |
363 | { |
364 | struct or51132_state* state = fe->demodulator_priv; | |
d9e54324 TP |
365 | int status; |
366 | int retry = 1; | |
0dbbc0a7 | 367 | |
d9e54324 | 368 | start: |
0dbbc0a7 | 369 | /* Receiver Status */ |
d9e54324 TP |
370 | if ((status = or51132_readreg(state, 0x00)) < 0) { |
371 | printk(KERN_WARNING "or51132: get_parameters: error reading receiver status\n"); | |
0dbbc0a7 TP |
372 | return -EREMOTEIO; |
373 | } | |
d9e54324 | 374 | switch(status&0xff) { |
d8f7cc28 MCC |
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; | |
0dbbc0a7 TP |
390 | } |
391 | ||
392 | /* FIXME: Read frequency from frontend, take AFC into account */ | |
d8f7cc28 | 393 | p->frequency = state->current_frequency; |
0dbbc0a7 TP |
394 | |
395 | /* FIXME: How to read inversion setting? Receiver 6 register? */ | |
d8f7cc28 | 396 | p->inversion = INVERSION_AUTO; |
0dbbc0a7 TP |
397 | |
398 | return 0; | |
399 | } | |
400 | ||
0df289a2 | 401 | static int or51132_read_status(struct dvb_frontend *fe, enum fe_status *status) |
1da177e4 | 402 | { |
b8742700 | 403 | struct or51132_state* state = fe->demodulator_priv; |
d9e54324 | 404 | int reg; |
1da177e4 LT |
405 | |
406 | /* Receiver Status */ | |
d9e54324 TP |
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; | |
1da177e4 | 411 | } |
271ddbf7 | 412 | dprintk("%s: read_status %04x\n", __func__, reg); |
d9e54324 TP |
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; | |
1da177e4 LT |
419 | return 0; |
420 | } | |
421 | ||
b2fb7f55 | 422 | /* Calculate SNR estimation (scaled by 2^24) |
1da177e4 | 423 | |
b2fb7f55 | 424 | 8-VSB SNR and QAM equations from Oren datasheets |
1da177e4 | 425 | |
b2fb7f55 RS |
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 ) | |
1da177e4 | 434 | |
b2fb7f55 RS |
435 | For QAM256: |
436 | SNR[dB] = 10 * log10(907832426.314266 / MSE^2 ) | |
1da177e4 | 437 | |
b2fb7f55 RS |
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 */ | |
1da177e4 | 442 | |
b2fb7f55 RS |
443 | static u32 calculate_snr(u32 mse, u32 c) |
444 | { | |
445 | if (mse == 0) /* No signal */ | |
446 | return 0; | |
447 | ||
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; | |
454 | } | |
455 | return 10*(c - mse); | |
1da177e4 LT |
456 | } |
457 | ||
b2fb7f55 | 458 | static int or51132_read_snr(struct dvb_frontend* fe, u16* snr) |
1da177e4 | 459 | { |
b8742700 | 460 | struct or51132_state* state = fe->demodulator_priv; |
d9e54324 TP |
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, 0x02); | |
468 | if (noise < 0) { | |
469 | printk(KERN_WARNING "or51132: read_snr: error reading equalizer\n"); | |
b2fb7f55 | 470 | return -EREMOTEIO; |
1da177e4 | 471 | } |
d9e54324 | 472 | dprintk("read_snr noise (%d)\n", noise); |
1da177e4 | 473 | |
b2fb7f55 RS |
474 | /* Read status, contains modulation type for QAM_AUTO and |
475 | NTSC filter for VSB */ | |
d9e54324 TP |
476 | reg = or51132_readreg(state, 0x00); |
477 | if (reg < 0) { | |
478 | printk(KERN_WARNING "or51132: read_snr: error reading receiver status\n"); | |
b2fb7f55 | 479 | return -EREMOTEIO; |
1da177e4 | 480 | } |
1da177e4 | 481 | |
d9e54324 | 482 | switch (reg&0xff) { |
b2fb7f55 | 483 | case 0x06: |
d9e54324 | 484 | if (reg & 0x1000) usK = 3 << 24; |
06eeefe8 MCC |
485 | /* fall through */ |
486 | case 0x43: /* QAM64 */ | |
b2fb7f55 RS |
487 | c = 150204167; |
488 | break; | |
489 | case 0x45: | |
490 | c = 150290396; | |
491 | break; | |
492 | default: | |
d9e54324 TP |
493 | printk(KERN_WARNING "or51132: unknown status 0x%02x\n", reg&0xff); |
494 | if (retry--) goto start; | |
b2fb7f55 RS |
495 | return -EREMOTEIO; |
496 | } | |
271ddbf7 | 497 | dprintk("%s: modulation %02x, NTSC rej O%s\n", __func__, |
d9e54324 | 498 | reg&0xff, reg&0x1000?"n":"ff"); |
b2fb7f55 RS |
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 | ||
271ddbf7 | 504 | dprintk("%s: noise = 0x%08x, snr = %d.%02d dB\n", __func__, noise, |
b2fb7f55 | 505 | state->snr >> 24, (((state->snr>>8) & 0xffff) * 100) >> 16); |
1da177e4 LT |
506 | |
507 | return 0; | |
508 | } | |
509 | ||
b2fb7f55 | 510 | static int or51132_read_signal_strength(struct dvb_frontend* fe, u16* strength) |
1da177e4 | 511 | { |
b2fb7f55 RS |
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; | |
1da177e4 | 518 | |
b2fb7f55 RS |
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; | |
1da177e4 LT |
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 | { | |
b8742700 | 543 | struct or51132_state* state = fe->demodulator_priv; |
1da177e4 LT |
544 | kfree(state); |
545 | } | |
546 | ||
bd336e63 | 547 | static const struct dvb_frontend_ops or51132_ops; |
1da177e4 LT |
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 */ | |
084e24ac | 555 | state = kzalloc(sizeof(struct or51132_state), GFP_KERNEL); |
1da177e4 | 556 | if (state == NULL) |
3473e342 | 557 | return NULL; |
1da177e4 LT |
558 | |
559 | /* Setup the state */ | |
560 | state->config = config; | |
561 | state->i2c = i2c; | |
1da177e4 LT |
562 | state->current_frequency = -1; |
563 | state->current_modulation = -1; | |
564 | ||
565 | /* Create dvb_frontend */ | |
dea74869 | 566 | memcpy(&state->frontend.ops, &or51132_ops, sizeof(struct dvb_frontend_ops)); |
1da177e4 LT |
567 | state->frontend.demodulator_priv = state; |
568 | return &state->frontend; | |
1da177e4 LT |
569 | } |
570 | ||
bd336e63 | 571 | static const struct dvb_frontend_ops or51132_ops = { |
d8f7cc28 | 572 | .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, |
1da177e4 LT |
573 | .info = { |
574 | .name = "Oren OR51132 VSB/QAM Frontend", | |
f1b1eabf MCC |
575 | .frequency_min_hz = 44 * MHz, |
576 | .frequency_max_hz = 958 * MHz, | |
577 | .frequency_stepsize_hz = 166666, | |
1da177e4 LT |
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 | ||
d8f7cc28 MCC |
589 | .set_frontend = or51132_set_parameters, |
590 | .get_frontend = or51132_get_parameters, | |
1da177e4 LT |
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"); | |
d9e54324 | 605 | MODULE_AUTHOR("Trent Piepho"); |
1da177e4 LT |
606 | MODULE_LICENSE("GPL"); |
607 | ||
608 | EXPORT_SYMBOL(or51132_attach); |