diff options
Diffstat (limited to 'drivers/media/dvb/frontends/cx24116.c')
-rw-r--r-- | drivers/media/dvb/frontends/cx24116.c | 1423 |
1 files changed, 1423 insertions, 0 deletions
diff --git a/drivers/media/dvb/frontends/cx24116.c b/drivers/media/dvb/frontends/cx24116.c new file mode 100644 index 000000000000..deb36f469ada --- /dev/null +++ b/drivers/media/dvb/frontends/cx24116.c | |||
@@ -0,0 +1,1423 @@ | |||
1 | /* | ||
2 | Conexant cx24116/cx24118 - DVBS/S2 Satellite demod/tuner driver | ||
3 | |||
4 | Copyright (C) 2006-2008 Steven Toth <stoth@hauppauge.com> | ||
5 | Copyright (C) 2006-2007 Georg Acher | ||
6 | Copyright (C) 2007-2008 Darron Broad | ||
7 | March 2007 | ||
8 | Fixed some bugs. | ||
9 | Added diseqc support. | ||
10 | Added corrected signal strength support. | ||
11 | August 2007 | ||
12 | Sync with legacy version. | ||
13 | Some clean ups. | ||
14 | Copyright (C) 2008 Igor Liplianin | ||
15 | September, 9th 2008 | ||
16 | Fixed locking on high symbol rates (>30000). | ||
17 | Implement MPEG initialization parameter. | ||
18 | |||
19 | This program is free software; you can redistribute it and/or modify | ||
20 | it under the terms of the GNU General Public License as published by | ||
21 | the Free Software Foundation; either version 2 of the License, or | ||
22 | (at your option) any later version. | ||
23 | |||
24 | This program is distributed in the hope that it will be useful, | ||
25 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
26 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
27 | GNU General Public License for more details. | ||
28 | |||
29 | You should have received a copy of the GNU General Public License | ||
30 | along with this program; if not, write to the Free Software | ||
31 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
32 | */ | ||
33 | |||
34 | #include <linux/slab.h> | ||
35 | #include <linux/kernel.h> | ||
36 | #include <linux/module.h> | ||
37 | #include <linux/moduleparam.h> | ||
38 | #include <linux/init.h> | ||
39 | #include <linux/firmware.h> | ||
40 | |||
41 | #include "dvb_frontend.h" | ||
42 | #include "cx24116.h" | ||
43 | |||
44 | static int debug = 0; | ||
45 | #define dprintk(args...) \ | ||
46 | do { \ | ||
47 | if (debug) printk ("cx24116: " args); \ | ||
48 | } while (0) | ||
49 | |||
50 | #define CX24116_DEFAULT_FIRMWARE "dvb-fe-cx24116.fw" | ||
51 | #define CX24116_SEARCH_RANGE_KHZ 5000 | ||
52 | |||
53 | /* known registers */ | ||
54 | #define CX24116_REG_COMMAND (0x00) /* command args 0x00..0x1e */ | ||
55 | #define CX24116_REG_EXECUTE (0x1f) /* execute command */ | ||
56 | #define CX24116_REG_MAILBOX (0x96) /* FW or multipurpose mailbox? */ | ||
57 | #define CX24116_REG_RESET (0x20) /* reset status > 0 */ | ||
58 | #define CX24116_REG_SIGNAL (0x9e) /* signal low */ | ||
59 | #define CX24116_REG_SSTATUS (0x9d) /* signal high / status */ | ||
60 | #define CX24116_REG_QUALITY8 (0xa3) | ||
61 | #define CX24116_REG_QSTATUS (0xbc) | ||
62 | #define CX24116_REG_QUALITY0 (0xd5) | ||
63 | #define CX24116_REG_BER0 (0xc9) | ||
64 | #define CX24116_REG_BER8 (0xc8) | ||
65 | #define CX24116_REG_BER16 (0xc7) | ||
66 | #define CX24116_REG_BER24 (0xc6) | ||
67 | #define CX24116_REG_UCB0 (0xcb) | ||
68 | #define CX24116_REG_UCB8 (0xca) | ||
69 | #define CX24116_REG_CLKDIV (0xf3) | ||
70 | #define CX24116_REG_RATEDIV (0xf9) | ||
71 | #define CX24116_REG_FECSTATUS (0x9c) /* configured fec (not tuned) or actual FEC (tuned) 1=1/2 2=2/3 etc */ | ||
72 | |||
73 | /* FECSTATUS bits */ | ||
74 | #define CX24116_FEC_FECMASK (0x1f) /* mask to determine configured fec (not tuned) or actual fec (tuned) */ | ||
75 | #define CX24116_FEC_DVBS (0x20) /* Select DVB-S demodulator, else DVB-S2 */ | ||
76 | #define CX24116_FEC_UNKNOWN (0x40) /* Unknown/unused */ | ||
77 | #define CX24116_FEC_PILOT (0x80) /* Pilot mode requested when tuning else always reset when tuned */ | ||
78 | |||
79 | /* arg buffer size */ | ||
80 | #define CX24116_ARGLEN (0x1e) | ||
81 | |||
82 | /* rolloff */ | ||
83 | #define CX24116_ROLLOFF_020 (0x00) | ||
84 | #define CX24116_ROLLOFF_025 (0x01) | ||
85 | #define CX24116_ROLLOFF_035 (0x02) | ||
86 | |||
87 | /* pilot bit */ | ||
88 | #define CX24116_PILOT_OFF (0x00) | ||
89 | #define CX24116_PILOT_ON (0x40) | ||
90 | |||
91 | /* signal status */ | ||
92 | #define CX24116_HAS_SIGNAL (0x01) | ||
93 | #define CX24116_HAS_CARRIER (0x02) | ||
94 | #define CX24116_HAS_VITERBI (0x04) | ||
95 | #define CX24116_HAS_SYNCLOCK (0x08) | ||
96 | #define CX24116_HAS_UNKNOWN1 (0x10) | ||
97 | #define CX24116_HAS_UNKNOWN2 (0x20) | ||
98 | #define CX24116_STATUS_MASK (0x3f) | ||
99 | #define CX24116_SIGNAL_MASK (0xc0) | ||
100 | |||
101 | #define CX24116_DISEQC_TONEOFF (0) /* toneburst never sent */ | ||
102 | #define CX24116_DISEQC_TONECACHE (1) /* toneburst cached */ | ||
103 | #define CX24116_DISEQC_MESGCACHE (2) /* message cached */ | ||
104 | |||
105 | /* arg offset for DiSEqC */ | ||
106 | #define CX24116_DISEQC_BURST (1) | ||
107 | #define CX24116_DISEQC_ARG2_2 (2) /* unknown value=2 */ | ||
108 | #define CX24116_DISEQC_ARG3_0 (3) /* unknown value=0 */ | ||
109 | #define CX24116_DISEQC_ARG4_0 (4) /* unknown value=0 */ | ||
110 | #define CX24116_DISEQC_MSGLEN (5) | ||
111 | #define CX24116_DISEQC_MSGOFS (6) | ||
112 | |||
113 | /* DiSEqC burst */ | ||
114 | #define CX24116_DISEQC_MINI_A (0) | ||
115 | #define CX24116_DISEQC_MINI_B (1) | ||
116 | |||
117 | /* DiSEqC tone burst */ | ||
118 | static int toneburst = 1; | ||
119 | |||
120 | /* SNR measurements */ | ||
121 | static int esno_snr = 0; | ||
122 | |||
123 | enum cmds | ||
124 | { | ||
125 | CMD_SET_VCO = 0x10, | ||
126 | CMD_TUNEREQUEST = 0x11, | ||
127 | CMD_MPEGCONFIG = 0x13, | ||
128 | CMD_TUNERINIT = 0x14, | ||
129 | CMD_BANDWIDTH = 0x15, | ||
130 | CMD_GETAGC = 0x19, | ||
131 | CMD_LNBCONFIG = 0x20, | ||
132 | CMD_LNBSEND = 0x21, /* Formerly CMD_SEND_DISEQC */ | ||
133 | CMD_SET_TONEPRE = 0x22, | ||
134 | CMD_SET_TONE = 0x23, | ||
135 | CMD_UPDFWVERS = 0x35, | ||
136 | CMD_TUNERSLEEP = 0x36, | ||
137 | CMD_AGCCONTROL = 0x3b, /* Unknown */ | ||
138 | }; | ||
139 | |||
140 | /* The Demod/Tuner can't easily provide these, we cache them */ | ||
141 | struct cx24116_tuning | ||
142 | { | ||
143 | u32 frequency; | ||
144 | u32 symbol_rate; | ||
145 | fe_spectral_inversion_t inversion; | ||
146 | fe_code_rate_t fec; | ||
147 | |||
148 | fe_modulation_t modulation; | ||
149 | fe_pilot_t pilot; | ||
150 | fe_rolloff_t rolloff; | ||
151 | |||
152 | /* Demod values */ | ||
153 | u8 fec_val; | ||
154 | u8 fec_mask; | ||
155 | u8 inversion_val; | ||
156 | u8 pilot_val; | ||
157 | u8 rolloff_val; | ||
158 | }; | ||
159 | |||
160 | /* Basic commands that are sent to the firmware */ | ||
161 | struct cx24116_cmd | ||
162 | { | ||
163 | u8 len; | ||
164 | u8 args[CX24116_ARGLEN]; | ||
165 | }; | ||
166 | |||
167 | struct cx24116_state | ||
168 | { | ||
169 | struct i2c_adapter* i2c; | ||
170 | const struct cx24116_config* config; | ||
171 | |||
172 | struct dvb_frontend frontend; | ||
173 | |||
174 | struct cx24116_tuning dcur; | ||
175 | struct cx24116_tuning dnxt; | ||
176 | |||
177 | u8 skip_fw_load; | ||
178 | u8 burst; | ||
179 | struct cx24116_cmd dsec_cmd; | ||
180 | }; | ||
181 | |||
182 | static int cx24116_writereg(struct cx24116_state* state, int reg, int data) | ||
183 | { | ||
184 | u8 buf[] = { reg, data }; | ||
185 | struct i2c_msg msg = { .addr = state->config->demod_address, | ||
186 | .flags = 0, .buf = buf, .len = 2 }; | ||
187 | int err; | ||
188 | |||
189 | if (debug>1) | ||
190 | printk("cx24116: %s: write reg 0x%02x, value 0x%02x\n", | ||
191 | __func__,reg, data); | ||
192 | |||
193 | if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { | ||
194 | printk("%s: writereg error(err == %i, reg == 0x%02x," | ||
195 | " value == 0x%02x)\n", __func__, err, reg, data); | ||
196 | return -EREMOTEIO; | ||
197 | } | ||
198 | |||
199 | return 0; | ||
200 | } | ||
201 | |||
202 | /* Bulk byte writes to a single I2C address, for 32k firmware load */ | ||
203 | static int cx24116_writeregN(struct cx24116_state* state, int reg, u8 *data, u16 len) | ||
204 | { | ||
205 | int ret = -EREMOTEIO; | ||
206 | struct i2c_msg msg; | ||
207 | u8 *buf; | ||
208 | |||
209 | buf = kmalloc(len + 1, GFP_KERNEL); | ||
210 | if (buf == NULL) { | ||
211 | printk("Unable to kmalloc\n"); | ||
212 | ret = -ENOMEM; | ||
213 | goto error; | ||
214 | } | ||
215 | |||
216 | *(buf) = reg; | ||
217 | memcpy(buf + 1, data, len); | ||
218 | |||
219 | msg.addr = state->config->demod_address; | ||
220 | msg.flags = 0; | ||
221 | msg.buf = buf; | ||
222 | msg.len = len + 1; | ||
223 | |||
224 | if (debug>1) | ||
225 | printk("cx24116: %s: write regN 0x%02x, len = %d\n", | ||
226 | __func__,reg, len); | ||
227 | |||
228 | if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1) { | ||
229 | printk("%s: writereg error(err == %i, reg == 0x%02x\n", | ||
230 | __func__, ret, reg); | ||
231 | ret = -EREMOTEIO; | ||
232 | } | ||
233 | |||
234 | error: | ||
235 | kfree(buf); | ||
236 | |||
237 | return ret; | ||
238 | } | ||
239 | |||
240 | static int cx24116_readreg(struct cx24116_state* state, u8 reg) | ||
241 | { | ||
242 | int ret; | ||
243 | u8 b0[] = { reg }; | ||
244 | u8 b1[] = { 0 }; | ||
245 | struct i2c_msg msg[] = { | ||
246 | { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 }, | ||
247 | { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } | ||
248 | }; | ||
249 | |||
250 | ret = i2c_transfer(state->i2c, msg, 2); | ||
251 | |||
252 | if (ret != 2) { | ||
253 | printk("%s: reg=0x%x (error=%d)\n", __func__, reg, ret); | ||
254 | return ret; | ||
255 | } | ||
256 | |||
257 | if (debug>1) | ||
258 | printk("cx24116: read reg 0x%02x, value 0x%02x\n",reg, b1[0]); | ||
259 | |||
260 | return b1[0]; | ||
261 | } | ||
262 | |||
263 | static int cx24116_set_inversion(struct cx24116_state* state, fe_spectral_inversion_t inversion) | ||
264 | { | ||
265 | dprintk("%s(%d)\n", __func__, inversion); | ||
266 | |||
267 | switch (inversion) { | ||
268 | case INVERSION_OFF: | ||
269 | state->dnxt.inversion_val = 0x00; | ||
270 | break; | ||
271 | case INVERSION_ON: | ||
272 | state->dnxt.inversion_val = 0x04; | ||
273 | break; | ||
274 | case INVERSION_AUTO: | ||
275 | state->dnxt.inversion_val = 0x0C; | ||
276 | break; | ||
277 | default: | ||
278 | return -EINVAL; | ||
279 | } | ||
280 | |||
281 | state->dnxt.inversion = inversion; | ||
282 | |||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | /* | ||
287 | * modfec (modulation and FEC) | ||
288 | * =========================== | ||
289 | * | ||
290 | * MOD FEC mask/val standard | ||
291 | * ---- -------- ----------- -------- | ||
292 | * QPSK FEC_1_2 0x02 0x02+X DVB-S | ||
293 | * QPSK FEC_2_3 0x04 0x02+X DVB-S | ||
294 | * QPSK FEC_3_4 0x08 0x02+X DVB-S | ||
295 | * QPSK FEC_4_5 0x10 0x02+X DVB-S (?) | ||
296 | * QPSK FEC_5_6 0x20 0x02+X DVB-S | ||
297 | * QPSK FEC_6_7 0x40 0x02+X DVB-S | ||
298 | * QPSK FEC_7_8 0x80 0x02+X DVB-S | ||
299 | * QPSK FEC_8_9 0x01 0x02+X DVB-S (?) (NOT SUPPORTED?) | ||
300 | * QPSK AUTO 0xff 0x02+X DVB-S | ||
301 | * | ||
302 | * For DVB-S high byte probably represents FEC | ||
303 | * and low byte selects the modulator. The high | ||
304 | * byte is search range mask. Bit 5 may turn | ||
305 | * on DVB-S and remaining bits represent some | ||
306 | * kind of calibration (how/what i do not know). | ||
307 | * | ||
308 | * Eg.(2/3) szap "Zone Horror" | ||
309 | * | ||
310 | * mask/val = 0x04, 0x20 | ||
311 | * status 1f | signal c3c0 | snr a333 | ber 00000098 | unc 00000000 | FE_HAS_LOCK | ||
312 | * | ||
313 | * mask/val = 0x04, 0x30 | ||
314 | * status 1f | signal c3c0 | snr a333 | ber 00000000 | unc 00000000 | FE_HAS_LOCK | ||
315 | * | ||
316 | * After tuning FECSTATUS contains actual FEC | ||
317 | * in use numbered 1 through to 8 for 1/2 .. 2/3 etc | ||
318 | * | ||
319 | * NBC=NOT/NON BACKWARD COMPATIBLE WITH DVB-S (DVB-S2 only) | ||
320 | * | ||
321 | * NBC-QPSK FEC_1_2 0x00, 0x04 DVB-S2 | ||
322 | * NBC-QPSK FEC_3_5 0x00, 0x05 DVB-S2 | ||
323 | * NBC-QPSK FEC_2_3 0x00, 0x06 DVB-S2 | ||
324 | * NBC-QPSK FEC_3_4 0x00, 0x07 DVB-S2 | ||
325 | * NBC-QPSK FEC_4_5 0x00, 0x08 DVB-S2 | ||
326 | * NBC-QPSK FEC_5_6 0x00, 0x09 DVB-S2 | ||
327 | * NBC-QPSK FEC_8_9 0x00, 0x0a DVB-S2 | ||
328 | * NBC-QPSK FEC_9_10 0x00, 0x0b DVB-S2 | ||
329 | * | ||
330 | * NBC-8PSK FEC_3_5 0x00, 0x0c DVB-S2 | ||
331 | * NBC-8PSK FEC_2_3 0x00, 0x0d DVB-S2 | ||
332 | * NBC-8PSK FEC_3_4 0x00, 0x0e DVB-S2 | ||
333 | * NBC-8PSK FEC_5_6 0x00, 0x0f DVB-S2 | ||
334 | * NBC-8PSK FEC_8_9 0x00, 0x10 DVB-S2 | ||
335 | * NBC-8PSK FEC_9_10 0x00, 0x11 DVB-S2 | ||
336 | * | ||
337 | * For DVB-S2 low bytes selects both modulator | ||
338 | * and FEC. High byte is meaningless here. To | ||
339 | * set pilot, bit 6 (0x40) is set. When inspecting | ||
340 | * FECSTATUS bit 7 (0x80) represents the pilot | ||
341 | * selection whilst not tuned. When tuned, actual FEC | ||
342 | * in use is found in FECSTATUS as per above. Pilot | ||
343 | * value is reset. | ||
344 | */ | ||
345 | |||
346 | /* A table of modulation, fec and configuration bytes for the demod. | ||
347 | * Not all S2 mmodulation schemes are support and not all rates with | ||
348 | * a scheme are support. Especially, no auto detect when in S2 mode. | ||
349 | */ | ||
350 | struct cx24116_modfec { | ||
351 | fe_delivery_system_t delivery_system; | ||
352 | fe_modulation_t modulation; | ||
353 | fe_code_rate_t fec; | ||
354 | u8 mask; /* In DVBS mode this is used to autodetect */ | ||
355 | u8 val; /* Passed to the firmware to indicate mode selection */ | ||
356 | } CX24116_MODFEC_MODES[] = { | ||
357 | /* QPSK. For unknown rates we set hardware to auto detect 0xfe 0x30 */ | ||
358 | |||
359 | /*mod fec mask val */ | ||
360 | { SYS_DVBS, QPSK, FEC_NONE, 0xfe, 0x30 }, | ||
361 | { SYS_DVBS, QPSK, FEC_1_2, 0x02, 0x2e }, /* 00000010 00101110 */ | ||
362 | { SYS_DVBS, QPSK, FEC_2_3, 0x04, 0x2f }, /* 00000100 00101111 */ | ||
363 | { SYS_DVBS, QPSK, FEC_3_4, 0x08, 0x30 }, /* 00001000 00110000 */ | ||
364 | { SYS_DVBS, QPSK, FEC_4_5, 0xfe, 0x30 }, /* 000?0000 ? */ | ||
365 | { SYS_DVBS, QPSK, FEC_5_6, 0x20, 0x31 }, /* 00100000 00110001 */ | ||
366 | { SYS_DVBS, QPSK, FEC_6_7, 0xfe, 0x30 }, /* 0?000000 ? */ | ||
367 | { SYS_DVBS, QPSK, FEC_7_8, 0x80, 0x32 }, /* 10000000 00110010 */ | ||
368 | { SYS_DVBS, QPSK, FEC_8_9, 0xfe, 0x30 }, /* 0000000? ? */ | ||
369 | { SYS_DVBS, QPSK, FEC_AUTO, 0xfe, 0x30 }, | ||
370 | /* NBC-QPSK */ | ||
371 | { SYS_DVBS2, QPSK, FEC_1_2, 0x00, 0x04 }, | ||
372 | { SYS_DVBS2, QPSK, FEC_3_5, 0x00, 0x05 }, | ||
373 | { SYS_DVBS2, QPSK, FEC_2_3, 0x00, 0x06 }, | ||
374 | { SYS_DVBS2, QPSK, FEC_3_4, 0x00, 0x07 }, | ||
375 | { SYS_DVBS2, QPSK, FEC_4_5, 0x00, 0x08 }, | ||
376 | { SYS_DVBS2, QPSK, FEC_5_6, 0x00, 0x09 }, | ||
377 | { SYS_DVBS2, QPSK, FEC_8_9, 0x00, 0x0a }, | ||
378 | { SYS_DVBS2, QPSK, FEC_9_10, 0x00, 0x0b }, | ||
379 | /* 8PSK */ | ||
380 | { SYS_DVBS2, PSK_8, FEC_3_5, 0x00, 0x0c }, | ||
381 | { SYS_DVBS2, PSK_8, FEC_2_3, 0x00, 0x0d }, | ||
382 | { SYS_DVBS2, PSK_8, FEC_3_4, 0x00, 0x0e }, | ||
383 | { SYS_DVBS2, PSK_8, FEC_5_6, 0x00, 0x0f }, | ||
384 | { SYS_DVBS2, PSK_8, FEC_8_9, 0x00, 0x10 }, | ||
385 | { SYS_DVBS2, PSK_8, FEC_9_10, 0x00, 0x11 }, | ||
386 | /* | ||
387 | * `val' can be found in the FECSTATUS register when tuning. | ||
388 | * FECSTATUS will give the actual FEC in use if tuning was successful. | ||
389 | */ | ||
390 | }; | ||
391 | |||
392 | static int cx24116_lookup_fecmod(struct cx24116_state* state, | ||
393 | fe_modulation_t m, fe_code_rate_t f) | ||
394 | { | ||
395 | int i, ret = -EOPNOTSUPP; | ||
396 | |||
397 | dprintk("%s(0x%02x,0x%02x)\n", __func__, m, f); | ||
398 | |||
399 | for(i=0 ; i < sizeof(CX24116_MODFEC_MODES) / sizeof(struct cx24116_modfec) ; i++) | ||
400 | { | ||
401 | if( (m == CX24116_MODFEC_MODES[i].modulation) && | ||
402 | (f == CX24116_MODFEC_MODES[i].fec) ) | ||
403 | { | ||
404 | ret = i; | ||
405 | break; | ||
406 | } | ||
407 | } | ||
408 | |||
409 | return ret; | ||
410 | } | ||
411 | |||
412 | static int cx24116_set_fec(struct cx24116_state* state, fe_modulation_t mod, fe_code_rate_t fec) | ||
413 | { | ||
414 | int ret = 0; | ||
415 | |||
416 | dprintk("%s(0x%02x,0x%02x)\n", __func__, mod, fec); | ||
417 | |||
418 | ret = cx24116_lookup_fecmod(state, mod, fec); | ||
419 | |||
420 | if(ret < 0) | ||
421 | return ret; | ||
422 | |||
423 | state->dnxt.fec = fec; | ||
424 | state->dnxt.fec_val = CX24116_MODFEC_MODES[ret].val; | ||
425 | state->dnxt.fec_mask = CX24116_MODFEC_MODES[ret].mask; | ||
426 | dprintk("%s() mask/val = 0x%02x/0x%02x\n", __func__, | ||
427 | state->dnxt.fec_mask, state->dnxt.fec_val); | ||
428 | |||
429 | return 0; | ||
430 | } | ||
431 | |||
432 | static int cx24116_set_symbolrate(struct cx24116_state* state, u32 rate) | ||
433 | { | ||
434 | dprintk("%s(%d)\n", __func__, rate); | ||
435 | |||
436 | /* check if symbol rate is within limits */ | ||
437 | if ((rate > state->frontend.ops.info.symbol_rate_max) || | ||
438 | (rate < state->frontend.ops.info.symbol_rate_min)) { | ||
439 | dprintk("%s() unsupported symbol_rate = %d\n", __func__, rate); | ||
440 | return -EOPNOTSUPP; | ||
441 | } | ||
442 | |||
443 | state->dnxt.symbol_rate = rate; | ||
444 | dprintk("%s() symbol_rate = %d\n", __func__, rate); | ||
445 | |||
446 | return 0; | ||
447 | } | ||
448 | |||
449 | static int cx24116_load_firmware (struct dvb_frontend* fe, const struct firmware *fw); | ||
450 | |||
451 | static int cx24116_firmware_ondemand(struct dvb_frontend* fe) | ||
452 | { | ||
453 | struct cx24116_state *state = fe->demodulator_priv; | ||
454 | const struct firmware *fw; | ||
455 | int ret = 0; | ||
456 | |||
457 | dprintk("%s()\n",__func__); | ||
458 | |||
459 | if (cx24116_readreg(state, 0x20) > 0) | ||
460 | { | ||
461 | |||
462 | if (state->skip_fw_load) | ||
463 | return 0; | ||
464 | |||
465 | /* Load firmware */ | ||
466 | /* request the firmware, this will block until someone uploads it */ | ||
467 | printk("%s: Waiting for firmware upload (%s)...\n", __func__, CX24116_DEFAULT_FIRMWARE); | ||
468 | ret = request_firmware(&fw, CX24116_DEFAULT_FIRMWARE, &state->i2c->dev); | ||
469 | printk("%s: Waiting for firmware upload(2)...\n", __func__); | ||
470 | if (ret) { | ||
471 | printk("%s: No firmware uploaded (timeout or file not found?)\n", __func__); | ||
472 | return ret; | ||
473 | } | ||
474 | |||
475 | /* Make sure we don't recurse back through here during loading */ | ||
476 | state->skip_fw_load = 1; | ||
477 | |||
478 | ret = cx24116_load_firmware(fe, fw); | ||
479 | if (ret) | ||
480 | printk("%s: Writing firmware to device failed\n", __func__); | ||
481 | |||
482 | release_firmware(fw); | ||
483 | |||
484 | printk("%s: Firmware upload %s\n", __func__, ret == 0 ? "complete" : "failed"); | ||
485 | |||
486 | /* Ensure firmware is always loaded if required */ | ||
487 | state->skip_fw_load = 0; | ||
488 | } | ||
489 | |||
490 | return ret; | ||
491 | } | ||
492 | |||
493 | /* Take a basic firmware command structure, format it and forward it for processing */ | ||
494 | static int cx24116_cmd_execute(struct dvb_frontend* fe, struct cx24116_cmd *cmd) | ||
495 | { | ||
496 | struct cx24116_state *state = fe->demodulator_priv; | ||
497 | int i, ret; | ||
498 | |||
499 | dprintk("%s()\n", __func__); | ||
500 | |||
501 | /* Load the firmware if required */ | ||
502 | if ( (ret = cx24116_firmware_ondemand(fe)) != 0) | ||
503 | { | ||
504 | printk("%s(): Unable initialise the firmware\n", __func__); | ||
505 | return ret; | ||
506 | } | ||
507 | |||
508 | /* Write the command */ | ||
509 | for(i = 0; i < cmd->len ; i++) | ||
510 | { | ||
511 | dprintk("%s: 0x%02x == 0x%02x\n", __func__, i, cmd->args[i]); | ||
512 | cx24116_writereg(state, i, cmd->args[i]); | ||
513 | } | ||
514 | |||
515 | /* Start execution and wait for cmd to terminate */ | ||
516 | cx24116_writereg(state, CX24116_REG_EXECUTE, 0x01); | ||
517 | while( cx24116_readreg(state, CX24116_REG_EXECUTE) ) | ||
518 | { | ||
519 | msleep(10); | ||
520 | if(i++ > 64) | ||
521 | { | ||
522 | /* Avoid looping forever if the firmware does no respond */ | ||
523 | printk("%s() Firmware not responding\n", __func__); | ||
524 | return -EREMOTEIO; | ||
525 | } | ||
526 | } | ||
527 | return 0; | ||
528 | } | ||
529 | |||
530 | static int cx24116_load_firmware (struct dvb_frontend* fe, const struct firmware *fw) | ||
531 | { | ||
532 | struct cx24116_state* state = fe->demodulator_priv; | ||
533 | struct cx24116_cmd cmd; | ||
534 | int i, ret; | ||
535 | unsigned char vers[4]; | ||
536 | |||
537 | dprintk("%s\n", __func__); | ||
538 | dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n" | ||
539 | ,fw->size | ||
540 | ,fw->data[0] | ||
541 | ,fw->data[1] | ||
542 | ,fw->data[ fw->size-2 ] | ||
543 | ,fw->data[ fw->size-1 ] | ||
544 | ); | ||
545 | |||
546 | /* Toggle 88x SRST pin to reset demod */ | ||
547 | if (state->config->reset_device) | ||
548 | state->config->reset_device(fe); | ||
549 | |||
550 | /* Begin the firmware load process */ | ||
551 | /* Prepare the demod, load the firmware, cleanup after load */ | ||
552 | |||
553 | /* Init PLL */ | ||
554 | cx24116_writereg(state, 0xE5, 0x00); | ||
555 | cx24116_writereg(state, 0xF1, 0x08); | ||
556 | cx24116_writereg(state, 0xF2, 0x13); | ||
557 | |||
558 | /* Start PLL */ | ||
559 | cx24116_writereg(state, 0xe0, 0x03); | ||
560 | cx24116_writereg(state, 0xe0, 0x00); | ||
561 | |||
562 | /* Unknown */ | ||
563 | cx24116_writereg(state, CX24116_REG_CLKDIV, 0x46); | ||
564 | cx24116_writereg(state, CX24116_REG_RATEDIV, 0x00); | ||
565 | |||
566 | /* Unknown */ | ||
567 | cx24116_writereg(state, 0xF0, 0x03); | ||
568 | cx24116_writereg(state, 0xF4, 0x81); | ||
569 | cx24116_writereg(state, 0xF5, 0x00); | ||
570 | cx24116_writereg(state, 0xF6, 0x00); | ||
571 | |||
572 | /* write the entire firmware as one transaction */ | ||
573 | cx24116_writeregN(state, 0xF7, fw->data, fw->size); | ||
574 | |||
575 | cx24116_writereg(state, 0xF4, 0x10); | ||
576 | cx24116_writereg(state, 0xF0, 0x00); | ||
577 | cx24116_writereg(state, 0xF8, 0x06); | ||
578 | |||
579 | /* Firmware CMD 10: VCO config */ | ||
580 | cmd.args[0x00] = CMD_SET_VCO; | ||
581 | cmd.args[0x01] = 0x05; | ||
582 | cmd.args[0x02] = 0xdc; | ||
583 | cmd.args[0x03] = 0xda; | ||
584 | cmd.args[0x04] = 0xae; | ||
585 | cmd.args[0x05] = 0xaa; | ||
586 | cmd.args[0x06] = 0x04; | ||
587 | cmd.args[0x07] = 0x9d; | ||
588 | cmd.args[0x08] = 0xfc; | ||
589 | cmd.args[0x09] = 0x06; | ||
590 | cmd.len= 0x0a; | ||
591 | ret = cx24116_cmd_execute(fe, &cmd); | ||
592 | if (ret != 0) | ||
593 | return ret; | ||
594 | |||
595 | cx24116_writereg(state, CX24116_REG_SSTATUS, 0x00); | ||
596 | |||
597 | /* Firmware CMD 14: Tuner config */ | ||
598 | cmd.args[0x00] = CMD_TUNERINIT; | ||
599 | cmd.args[0x01] = 0x00; | ||
600 | cmd.args[0x02] = 0x00; | ||
601 | cmd.len= 0x03; | ||
602 | ret = cx24116_cmd_execute(fe, &cmd); | ||
603 | if (ret != 0) | ||
604 | return ret; | ||
605 | |||
606 | cx24116_writereg(state, 0xe5, 0x00); | ||
607 | |||
608 | /* Firmware CMD 13: MPEG config */ | ||
609 | cmd.args[0x00] = CMD_MPEGCONFIG; | ||
610 | cmd.args[0x01] = 0x01; | ||
611 | cmd.args[0x02] = 0x75; | ||
612 | cmd.args[0x03] = 0x00; | ||
613 | if (state->config->mpg_clk_pos_pol) | ||
614 | cmd.args[0x04] = state->config->mpg_clk_pos_pol; | ||
615 | else | ||
616 | cmd.args[0x04] = 0x02; | ||
617 | cmd.args[0x05] = 0x00; | ||
618 | cmd.len= 0x06; | ||
619 | ret = cx24116_cmd_execute(fe, &cmd); | ||
620 | if (ret != 0) | ||
621 | return ret; | ||
622 | |||
623 | /* Firmware CMD 35: Get firmware version */ | ||
624 | cmd.args[0x00] = CMD_UPDFWVERS; | ||
625 | cmd.len= 0x02; | ||
626 | for(i=0; i<4; i++) { | ||
627 | cmd.args[0x01] = i; | ||
628 | ret = cx24116_cmd_execute(fe, &cmd); | ||
629 | if (ret != 0) | ||
630 | return ret; | ||
631 | vers[i]= cx24116_readreg(state, CX24116_REG_MAILBOX); | ||
632 | } | ||
633 | printk("%s: FW version %i.%i.%i.%i\n", __func__, | ||
634 | vers[0], vers[1], vers[2], vers[3]); | ||
635 | |||
636 | return 0; | ||
637 | } | ||
638 | |||
639 | static int cx24116_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) | ||
640 | { | ||
641 | /* The isl6421 module will override this function in the fops. */ | ||
642 | dprintk("%s() This should never appear if the isl6421 module is loaded correctly\n",__func__); | ||
643 | |||
644 | return -EOPNOTSUPP; | ||
645 | } | ||
646 | |||
647 | static int cx24116_read_status(struct dvb_frontend* fe, fe_status_t* status) | ||
648 | { | ||
649 | struct cx24116_state *state = fe->demodulator_priv; | ||
650 | |||
651 | int lock = cx24116_readreg(state, CX24116_REG_SSTATUS); | ||
652 | |||
653 | dprintk("%s: status = 0x%02x\n", __func__, lock); | ||
654 | |||
655 | *status = 0; | ||
656 | |||
657 | if (lock & CX24116_HAS_SIGNAL) | ||
658 | *status |= FE_HAS_SIGNAL; | ||
659 | if (lock & CX24116_HAS_CARRIER) | ||
660 | *status |= FE_HAS_CARRIER; | ||
661 | if (lock & CX24116_HAS_VITERBI) | ||
662 | *status |= FE_HAS_VITERBI; | ||
663 | if (lock & CX24116_HAS_SYNCLOCK) | ||
664 | *status |= FE_HAS_SYNC | FE_HAS_LOCK; | ||
665 | |||
666 | return 0; | ||
667 | } | ||
668 | |||
669 | static int cx24116_read_ber(struct dvb_frontend* fe, u32* ber) | ||
670 | { | ||
671 | struct cx24116_state *state = fe->demodulator_priv; | ||
672 | |||
673 | dprintk("%s()\n", __func__); | ||
674 | |||
675 | *ber = ( cx24116_readreg(state, CX24116_REG_BER24) << 24 ) | | ||
676 | ( cx24116_readreg(state, CX24116_REG_BER16) << 16 ) | | ||
677 | ( cx24116_readreg(state, CX24116_REG_BER8 ) << 8 ) | | ||
678 | cx24116_readreg(state, CX24116_REG_BER0 ); | ||
679 | |||
680 | return 0; | ||
681 | } | ||
682 | |||
683 | /* TODO Determine function and scale appropriately */ | ||
684 | static int cx24116_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength) | ||
685 | { | ||
686 | struct cx24116_state *state = fe->demodulator_priv; | ||
687 | struct cx24116_cmd cmd; | ||
688 | int ret; | ||
689 | u16 sig_reading; | ||
690 | |||
691 | dprintk("%s()\n", __func__); | ||
692 | |||
693 | /* Firmware CMD 19: Get AGC */ | ||
694 | cmd.args[0x00] = CMD_GETAGC; | ||
695 | cmd.len= 0x01; | ||
696 | ret = cx24116_cmd_execute(fe, &cmd); | ||
697 | if (ret != 0) | ||
698 | return ret; | ||
699 | |||
700 | sig_reading = ( cx24116_readreg(state, CX24116_REG_SSTATUS) & CX24116_SIGNAL_MASK ) | | ||
701 | ( cx24116_readreg(state, CX24116_REG_SIGNAL) << 6 ); | ||
702 | *signal_strength= 0 - sig_reading; | ||
703 | |||
704 | dprintk("%s: raw / cooked = 0x%04x / 0x%04x\n", __func__, sig_reading, *signal_strength); | ||
705 | |||
706 | return 0; | ||
707 | } | ||
708 | |||
709 | /* SNR (0..100)% = (sig & 0xf0) * 10 + (sig & 0x0f) * 10 / 16 */ | ||
710 | static int cx24116_read_snr_pct(struct dvb_frontend* fe, u16* snr) | ||
711 | { | ||
712 | struct cx24116_state *state = fe->demodulator_priv; | ||
713 | u8 snr_reading; | ||
714 | static const u32 snr_tab[] = { /* 10 x Table (rounded up) */ | ||
715 | 0x00000,0x0199A,0x03333,0x04ccD,0x06667, | ||
716 | 0x08000,0x0999A,0x0b333,0x0cccD,0x0e667, | ||
717 | 0x10000,0x1199A,0x13333,0x14ccD,0x16667,0x18000 }; | ||
718 | |||
719 | dprintk("%s()\n", __func__); | ||
720 | |||
721 | snr_reading = cx24116_readreg(state, CX24116_REG_QUALITY0); | ||
722 | |||
723 | if(snr_reading >= 0xa0 /* 100% */) | ||
724 | *snr = 0xffff; | ||
725 | else | ||
726 | *snr = snr_tab [ ( snr_reading & 0xf0 ) >> 4 ] + | ||
727 | ( snr_tab [ ( snr_reading & 0x0f ) ] >> 4 ); | ||
728 | |||
729 | dprintk("%s: raw / cooked = 0x%02x / 0x%04x\n", __func__, | ||
730 | snr_reading, *snr); | ||
731 | |||
732 | return 0; | ||
733 | } | ||
734 | |||
735 | /* The reelbox patches show the value in the registers represents | ||
736 | * ESNO, from 0->30db (values 0->300). We provide this value by | ||
737 | * default. | ||
738 | */ | ||
739 | static int cx24116_read_snr_esno(struct dvb_frontend* fe, u16* snr) | ||
740 | { | ||
741 | struct cx24116_state *state = fe->demodulator_priv; | ||
742 | |||
743 | dprintk("%s()\n", __func__); | ||
744 | |||
745 | *snr = cx24116_readreg(state, CX24116_REG_QUALITY8) << 8 | | ||
746 | cx24116_readreg(state, CX24116_REG_QUALITY0); | ||
747 | |||
748 | dprintk("%s: raw 0x%04x\n", __func__, *snr); | ||
749 | |||
750 | return 0; | ||
751 | } | ||
752 | |||
753 | static int cx24116_read_snr(struct dvb_frontend* fe, u16* snr) | ||
754 | { | ||
755 | if (esno_snr == 1) | ||
756 | return cx24116_read_snr_esno(fe, snr); | ||
757 | else | ||
758 | return cx24116_read_snr_pct(fe, snr); | ||
759 | } | ||
760 | |||
761 | static int cx24116_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) | ||
762 | { | ||
763 | struct cx24116_state *state = fe->demodulator_priv; | ||
764 | |||
765 | dprintk("%s()\n", __func__); | ||
766 | |||
767 | *ucblocks = ( cx24116_readreg(state, CX24116_REG_UCB8) << 8 ) | | ||
768 | cx24116_readreg(state, CX24116_REG_UCB0); | ||
769 | |||
770 | return 0; | ||
771 | } | ||
772 | |||
773 | /* Overwrite the current tuning params, we are about to tune */ | ||
774 | static void cx24116_clone_params(struct dvb_frontend* fe) | ||
775 | { | ||
776 | struct cx24116_state *state = fe->demodulator_priv; | ||
777 | memcpy(&state->dcur, &state->dnxt, sizeof(state->dcur)); | ||
778 | } | ||
779 | |||
780 | /* Wait for LNB */ | ||
781 | static int cx24116_wait_for_lnb(struct dvb_frontend* fe) | ||
782 | { | ||
783 | struct cx24116_state *state = fe->demodulator_priv; | ||
784 | int i; | ||
785 | |||
786 | dprintk("%s() qstatus = 0x%02x\n", __func__, | ||
787 | cx24116_readreg(state, CX24116_REG_QSTATUS)); | ||
788 | |||
789 | /* Wait for up to 300 ms */ | ||
790 | for(i = 0; i < 30 ; i++) { | ||
791 | if (cx24116_readreg(state, CX24116_REG_QSTATUS) & 0x20) | ||
792 | return 0; | ||
793 | msleep(10); | ||
794 | } | ||
795 | |||
796 | dprintk("%s(): LNB not ready\n", __func__); | ||
797 | |||
798 | return -ETIMEDOUT; /* -EBUSY ? */ | ||
799 | } | ||
800 | |||
801 | static int cx24116_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) | ||
802 | { | ||
803 | struct cx24116_cmd cmd; | ||
804 | int ret; | ||
805 | |||
806 | dprintk("%s(%d)\n", __func__, tone); | ||
807 | if ( (tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF) ) { | ||
808 | printk("%s: Invalid, tone=%d\n", __func__, tone); | ||
809 | return -EINVAL; | ||
810 | } | ||
811 | |||
812 | /* Wait for LNB ready */ | ||
813 | ret = cx24116_wait_for_lnb(fe); | ||
814 | if(ret != 0) | ||
815 | return ret; | ||
816 | |||
817 | /* Min delay time after DiSEqC send */ | ||
818 | msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */ | ||
819 | |||
820 | /* This is always done before the tone is set */ | ||
821 | cmd.args[0x00] = CMD_SET_TONEPRE; | ||
822 | cmd.args[0x01] = 0x00; | ||
823 | cmd.len= 0x02; | ||
824 | ret = cx24116_cmd_execute(fe, &cmd); | ||
825 | if (ret != 0) | ||
826 | return ret; | ||
827 | |||
828 | /* Now we set the tone */ | ||
829 | cmd.args[0x00] = CMD_SET_TONE; | ||
830 | cmd.args[0x01] = 0x00; | ||
831 | cmd.args[0x02] = 0x00; | ||
832 | |||
833 | switch (tone) { | ||
834 | case SEC_TONE_ON: | ||
835 | dprintk("%s: setting tone on\n", __func__); | ||
836 | cmd.args[0x03] = 0x01; | ||
837 | break; | ||
838 | case SEC_TONE_OFF: | ||
839 | dprintk("%s: setting tone off\n",__func__); | ||
840 | cmd.args[0x03] = 0x00; | ||
841 | break; | ||
842 | } | ||
843 | cmd.len= 0x04; | ||
844 | |||
845 | /* Min delay time before DiSEqC send */ | ||
846 | msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */ | ||
847 | |||
848 | return cx24116_cmd_execute(fe, &cmd); | ||
849 | } | ||
850 | |||
851 | /* Initialise DiSEqC */ | ||
852 | static int cx24116_diseqc_init(struct dvb_frontend* fe) | ||
853 | { | ||
854 | struct cx24116_state *state = fe->demodulator_priv; | ||
855 | struct cx24116_cmd cmd; | ||
856 | int ret; | ||
857 | |||
858 | /* Firmware CMD 20: LNB/DiSEqC config */ | ||
859 | cmd.args[0x00] = CMD_LNBCONFIG; | ||
860 | cmd.args[0x01] = 0x00; | ||
861 | cmd.args[0x02] = 0x10; | ||
862 | cmd.args[0x03] = 0x00; | ||
863 | cmd.args[0x04] = 0x8f; | ||
864 | cmd.args[0x05] = 0x28; | ||
865 | cmd.args[0x06] = (toneburst == CX24116_DISEQC_TONEOFF) ? 0x00 : 0x01; | ||
866 | cmd.args[0x07] = 0x01; | ||
867 | cmd.len= 0x08; | ||
868 | ret = cx24116_cmd_execute(fe, &cmd); | ||
869 | if (ret != 0) | ||
870 | return ret; | ||
871 | |||
872 | /* Prepare a DiSEqC command */ | ||
873 | state->dsec_cmd.args[0x00] = CMD_LNBSEND; | ||
874 | |||
875 | /* DiSEqC burst */ | ||
876 | state->dsec_cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_A; | ||
877 | |||
878 | /* Unknown */ | ||
879 | state->dsec_cmd.args[CX24116_DISEQC_ARG2_2] = 0x02; | ||
880 | state->dsec_cmd.args[CX24116_DISEQC_ARG3_0] = 0x00; | ||
881 | state->dsec_cmd.args[CX24116_DISEQC_ARG4_0] = 0x00; /* Continuation flag? */ | ||
882 | |||
883 | /* DiSEqC message length */ | ||
884 | state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = 0x00; | ||
885 | |||
886 | /* Command length */ | ||
887 | state->dsec_cmd.len= CX24116_DISEQC_MSGOFS; | ||
888 | |||
889 | return 0; | ||
890 | } | ||
891 | |||
892 | /* Send DiSEqC message with derived burst (hack) || previous burst */ | ||
893 | static int cx24116_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *d) | ||
894 | { | ||
895 | struct cx24116_state *state = fe->demodulator_priv; | ||
896 | int i, ret; | ||
897 | |||
898 | /* Dump DiSEqC message */ | ||
899 | if (debug) { | ||
900 | printk("cx24116: %s(", __func__); | ||
901 | for(i = 0 ; i < d->msg_len ;) { | ||
902 | printk("0x%02x", d->msg[i]); | ||
903 | if(++i < d->msg_len) | ||
904 | printk(", "); | ||
905 | } | ||
906 | printk(") toneburst=%d\n", toneburst); | ||
907 | } | ||
908 | |||
909 | /* Validate length */ | ||
910 | if(d->msg_len > (CX24116_ARGLEN - CX24116_DISEQC_MSGOFS)) | ||
911 | return -EINVAL; | ||
912 | |||
913 | /* DiSEqC message */ | ||
914 | for (i = 0; i < d->msg_len; i++) | ||
915 | state->dsec_cmd.args[CX24116_DISEQC_MSGOFS + i] = d->msg[i]; | ||
916 | |||
917 | /* DiSEqC message length */ | ||
918 | state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = d->msg_len; | ||
919 | |||
920 | /* Command length */ | ||
921 | state->dsec_cmd.len= CX24116_DISEQC_MSGOFS + state->dsec_cmd.args[CX24116_DISEQC_MSGLEN]; | ||
922 | |||
923 | /* DiSEqC toneburst */ | ||
924 | if(toneburst == CX24116_DISEQC_MESGCACHE) | ||
925 | /* Message is cached */ | ||
926 | return 0; | ||
927 | |||
928 | else if(toneburst == CX24116_DISEQC_TONEOFF) | ||
929 | /* Message is sent without burst */ | ||
930 | state->dsec_cmd.args[CX24116_DISEQC_BURST] = 0; | ||
931 | |||
932 | else if(toneburst == CX24116_DISEQC_TONECACHE) { | ||
933 | /* | ||
934 | * Message is sent with derived else cached burst | ||
935 | * | ||
936 | * WRITE PORT GROUP COMMAND 38 | ||
937 | * | ||
938 | * 0/A/A: E0 10 38 F0..F3 | ||
939 | * 1/B/B: E0 10 38 F4..F7 | ||
940 | * 2/C/A: E0 10 38 F8..FB | ||
941 | * 3/D/B: E0 10 38 FC..FF | ||
942 | * | ||
943 | * databyte[3]= 8421:8421 | ||
944 | * ABCD:WXYZ | ||
945 | * CLR :SET | ||
946 | * | ||
947 | * WX= PORT SELECT 0..3 (X=TONEBURST) | ||
948 | * Y = VOLTAGE (0=13V, 1=18V) | ||
949 | * Z = BAND (0=LOW, 1=HIGH(22K)) | ||
950 | */ | ||
951 | if(d->msg_len >= 4 && d->msg[2] == 0x38) | ||
952 | state->dsec_cmd.args[CX24116_DISEQC_BURST] = ((d->msg[3] & 4) >> 2); | ||
953 | if(debug) | ||
954 | dprintk("%s burst=%d\n", __func__, state->dsec_cmd.args[CX24116_DISEQC_BURST]); | ||
955 | } | ||
956 | |||
957 | /* Wait for LNB ready */ | ||
958 | ret = cx24116_wait_for_lnb(fe); | ||
959 | if(ret != 0) | ||
960 | return ret; | ||
961 | |||
962 | /* Wait for voltage/min repeat delay */ | ||
963 | msleep(100); | ||
964 | |||
965 | /* Command */ | ||
966 | ret = cx24116_cmd_execute(fe, &state->dsec_cmd); | ||
967 | if(ret != 0) | ||
968 | return ret; | ||
969 | /* | ||
970 | * Wait for send | ||
971 | * | ||
972 | * Eutelsat spec: | ||
973 | * >15ms delay + (XXX determine if FW does this, see set_tone) | ||
974 | * 13.5ms per byte + | ||
975 | * >15ms delay + | ||
976 | * 12.5ms burst + | ||
977 | * >15ms delay (XXX determine if FW does this, see set_tone) | ||
978 | */ | ||
979 | msleep( (state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) + ((toneburst == CX24116_DISEQC_TONEOFF) ? 30 : 60) ); | ||
980 | |||
981 | return 0; | ||
982 | } | ||
983 | |||
984 | /* Send DiSEqC burst */ | ||
985 | static int cx24116_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst) | ||
986 | { | ||
987 | struct cx24116_state *state = fe->demodulator_priv; | ||
988 | int ret; | ||
989 | |||
990 | dprintk("%s(%d) toneburst=%d\n",__func__, burst, toneburst); | ||
991 | |||
992 | /* DiSEqC burst */ | ||
993 | if (burst == SEC_MINI_A) | ||
994 | state->dsec_cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_A; | ||
995 | else if(burst == SEC_MINI_B) | ||
996 | state->dsec_cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_B; | ||
997 | else | ||
998 | return -EINVAL; | ||
999 | |||
1000 | /* DiSEqC toneburst */ | ||
1001 | if(toneburst != CX24116_DISEQC_MESGCACHE) | ||
1002 | /* Burst is cached */ | ||
1003 | return 0; | ||
1004 | |||
1005 | /* Burst is to be sent with cached message */ | ||
1006 | |||
1007 | /* Wait for LNB ready */ | ||
1008 | ret = cx24116_wait_for_lnb(fe); | ||
1009 | if(ret != 0) | ||
1010 | return ret; | ||
1011 | |||
1012 | /* Wait for voltage/min repeat delay */ | ||
1013 | msleep(100); | ||
1014 | |||
1015 | /* Command */ | ||
1016 | ret = cx24116_cmd_execute(fe, &state->dsec_cmd); | ||
1017 | if(ret != 0) | ||
1018 | return ret; | ||
1019 | |||
1020 | /* | ||
1021 | * Wait for send | ||
1022 | * | ||
1023 | * Eutelsat spec: | ||
1024 | * >15ms delay + (XXX determine if FW does this, see set_tone) | ||
1025 | * 13.5ms per byte + | ||
1026 | * >15ms delay + | ||
1027 | * 12.5ms burst + | ||
1028 | * >15ms delay (XXX determine if FW does this, see set_tone) | ||
1029 | */ | ||
1030 | msleep( (state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) + 60 ); | ||
1031 | |||
1032 | return 0; | ||
1033 | } | ||
1034 | |||
1035 | static void cx24116_release(struct dvb_frontend* fe) | ||
1036 | { | ||
1037 | struct cx24116_state* state = fe->demodulator_priv; | ||
1038 | dprintk("%s\n",__func__); | ||
1039 | kfree(state); | ||
1040 | } | ||
1041 | |||
1042 | static struct dvb_frontend_ops cx24116_ops; | ||
1043 | |||
1044 | struct dvb_frontend* cx24116_attach(const struct cx24116_config* config, | ||
1045 | struct i2c_adapter* i2c) | ||
1046 | { | ||
1047 | struct cx24116_state* state = NULL; | ||
1048 | int ret; | ||
1049 | |||
1050 | dprintk("%s\n",__func__); | ||
1051 | |||
1052 | /* allocate memory for the internal state */ | ||
1053 | state = kmalloc(sizeof(struct cx24116_state), GFP_KERNEL); | ||
1054 | if (state == NULL) { | ||
1055 | printk("Unable to kmalloc\n"); | ||
1056 | goto error1; | ||
1057 | } | ||
1058 | |||
1059 | /* setup the state */ | ||
1060 | memset(state, 0, sizeof(struct cx24116_state)); | ||
1061 | |||
1062 | state->config = config; | ||
1063 | state->i2c = i2c; | ||
1064 | |||
1065 | /* check if the demod is present */ | ||
1066 | ret = (cx24116_readreg(state, 0xFF) << 8) | cx24116_readreg(state, 0xFE); | ||
1067 | if (ret != 0x0501) { | ||
1068 | printk("Invalid probe, probably not a CX24116 device\n"); | ||
1069 | goto error2; | ||
1070 | } | ||
1071 | |||
1072 | /* create dvb_frontend */ | ||
1073 | memcpy(&state->frontend.ops, &cx24116_ops, sizeof(struct dvb_frontend_ops)); | ||
1074 | state->frontend.demodulator_priv = state; | ||
1075 | return &state->frontend; | ||
1076 | |||
1077 | error2: kfree(state); | ||
1078 | error1: return NULL; | ||
1079 | } | ||
1080 | /* | ||
1081 | * Initialise or wake up device | ||
1082 | * | ||
1083 | * Power config will reset and load initial firmware if required | ||
1084 | */ | ||
1085 | static int cx24116_initfe(struct dvb_frontend* fe) | ||
1086 | { | ||
1087 | struct cx24116_state* state = fe->demodulator_priv; | ||
1088 | struct cx24116_cmd cmd; | ||
1089 | int ret; | ||
1090 | |||
1091 | dprintk("%s()\n",__func__); | ||
1092 | |||
1093 | /* Power on */ | ||
1094 | cx24116_writereg(state, 0xe0, 0); | ||
1095 | cx24116_writereg(state, 0xe1, 0); | ||
1096 | cx24116_writereg(state, 0xea, 0); | ||
1097 | |||
1098 | /* Firmware CMD 36: Power config */ | ||
1099 | cmd.args[0x00] = CMD_TUNERSLEEP; | ||
1100 | cmd.args[0x01] = 0; | ||
1101 | cmd.len= 0x02; | ||
1102 | ret = cx24116_cmd_execute(fe, &cmd); | ||
1103 | if(ret != 0) | ||
1104 | return ret; | ||
1105 | |||
1106 | return cx24116_diseqc_init(fe); | ||
1107 | } | ||
1108 | |||
1109 | /* | ||
1110 | * Put device to sleep | ||
1111 | */ | ||
1112 | static int cx24116_sleep(struct dvb_frontend* fe) | ||
1113 | { | ||
1114 | struct cx24116_state* state = fe->demodulator_priv; | ||
1115 | struct cx24116_cmd cmd; | ||
1116 | int ret; | ||
1117 | |||
1118 | dprintk("%s()\n",__func__); | ||
1119 | |||
1120 | /* Firmware CMD 36: Power config */ | ||
1121 | cmd.args[0x00] = CMD_TUNERSLEEP; | ||
1122 | cmd.args[0x01] = 1; | ||
1123 | cmd.len= 0x02; | ||
1124 | ret = cx24116_cmd_execute(fe, &cmd); | ||
1125 | if(ret != 0) | ||
1126 | return ret; | ||
1127 | |||
1128 | /* Power off (Shutdown clocks) */ | ||
1129 | cx24116_writereg(state, 0xea, 0xff); | ||
1130 | cx24116_writereg(state, 0xe1, 1); | ||
1131 | cx24116_writereg(state, 0xe0, 1); | ||
1132 | |||
1133 | return 0; | ||
1134 | } | ||
1135 | |||
1136 | static int cx24116_set_property(struct dvb_frontend *fe, struct dtv_property* tvp) | ||
1137 | { | ||
1138 | dprintk("%s(..)\n", __func__); | ||
1139 | return 0; | ||
1140 | } | ||
1141 | |||
1142 | static int cx24116_get_property(struct dvb_frontend *fe, struct dtv_property* tvp) | ||
1143 | { | ||
1144 | dprintk("%s(..)\n", __func__); | ||
1145 | return 0; | ||
1146 | } | ||
1147 | |||
1148 | /* dvb-core told us to tune, the tv property cache will be complete, | ||
1149 | * it's safe for is to pull values and use them for tuning purposes. | ||
1150 | */ | ||
1151 | static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) | ||
1152 | { | ||
1153 | struct cx24116_state *state = fe->demodulator_priv; | ||
1154 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
1155 | struct cx24116_cmd cmd; | ||
1156 | fe_status_t tunerstat; | ||
1157 | int i, status, ret, retune; | ||
1158 | |||
1159 | dprintk("%s()\n",__func__); | ||
1160 | |||
1161 | switch(c->delivery_system) { | ||
1162 | case SYS_DVBS: | ||
1163 | dprintk("%s: DVB-S delivery system selected\n",__func__); | ||
1164 | |||
1165 | /* Only QPSK is supported for DVB-S */ | ||
1166 | if(c->modulation != QPSK) { | ||
1167 | dprintk("%s: unsupported modulation selected (%d)\n", | ||
1168 | __func__, c->modulation); | ||
1169 | return -EOPNOTSUPP; | ||
1170 | } | ||
1171 | |||
1172 | /* Pilot doesn't exist in DVB-S, turn bit off */ | ||
1173 | state->dnxt.pilot_val = CX24116_PILOT_OFF; | ||
1174 | retune = 1; | ||
1175 | |||
1176 | /* DVB-S only supports 0.35 */ | ||
1177 | if(c->rolloff != ROLLOFF_35) { | ||
1178 | dprintk("%s: unsupported rolloff selected (%d)\n", | ||
1179 | __func__, c->rolloff); | ||
1180 | return -EOPNOTSUPP; | ||
1181 | } | ||
1182 | state->dnxt.rolloff_val = CX24116_ROLLOFF_035; | ||
1183 | break; | ||
1184 | |||
1185 | case SYS_DVBS2: | ||
1186 | dprintk("%s: DVB-S2 delivery system selected\n",__func__); | ||
1187 | |||
1188 | /* | ||
1189 | * NBC 8PSK/QPSK with DVB-S is supported for DVB-S2, | ||
1190 | * but not hardware auto detection | ||
1191 | */ | ||
1192 | if(c->modulation != PSK_8 && c->modulation != QPSK) { | ||
1193 | dprintk("%s: unsupported modulation selected (%d)\n", | ||
1194 | __func__, c->modulation); | ||
1195 | return -EOPNOTSUPP; | ||
1196 | } | ||
1197 | |||
1198 | switch(c->pilot) { | ||
1199 | case PILOT_AUTO: /* Not supported but emulated */ | ||
1200 | retune = 2; /* Fall-through */ | ||
1201 | case PILOT_OFF: | ||
1202 | state->dnxt.pilot_val = CX24116_PILOT_OFF; | ||
1203 | break; | ||
1204 | case PILOT_ON: | ||
1205 | state->dnxt.pilot_val = CX24116_PILOT_ON; | ||
1206 | break; | ||
1207 | default: | ||
1208 | dprintk("%s: unsupported pilot mode selected (%d)\n", | ||
1209 | __func__, c->pilot); | ||
1210 | return -EOPNOTSUPP; | ||
1211 | } | ||
1212 | |||
1213 | switch(c->rolloff) { | ||
1214 | case ROLLOFF_20: | ||
1215 | state->dnxt.rolloff_val= CX24116_ROLLOFF_020; | ||
1216 | break; | ||
1217 | case ROLLOFF_25: | ||
1218 | state->dnxt.rolloff_val= CX24116_ROLLOFF_025; | ||
1219 | break; | ||
1220 | case ROLLOFF_35: | ||
1221 | state->dnxt.rolloff_val= CX24116_ROLLOFF_035; | ||
1222 | break; | ||
1223 | case ROLLOFF_AUTO: /* Rolloff must be explicit */ | ||
1224 | default: | ||
1225 | dprintk("%s: unsupported rolloff selected (%d)\n", | ||
1226 | __func__, c->rolloff); | ||
1227 | return -EOPNOTSUPP; | ||
1228 | } | ||
1229 | break; | ||
1230 | |||
1231 | default: | ||
1232 | dprintk("%s: unsupported delivery system selected (%d)\n", | ||
1233 | __func__, c->delivery_system); | ||
1234 | return -EOPNOTSUPP; | ||
1235 | } | ||
1236 | state->dnxt.modulation = c->modulation; | ||
1237 | state->dnxt.frequency = c->frequency; | ||
1238 | state->dnxt.pilot = c->pilot; | ||
1239 | state->dnxt.rolloff = c->rolloff; | ||
1240 | |||
1241 | if ((ret = cx24116_set_inversion(state, c->inversion)) != 0) | ||
1242 | return ret; | ||
1243 | |||
1244 | /* FEC_NONE/AUTO for DVB-S2 is not supported and detected here */ | ||
1245 | if ((ret = cx24116_set_fec(state, c->modulation, c->fec_inner)) != 0) | ||
1246 | return ret; | ||
1247 | |||
1248 | if ((ret = cx24116_set_symbolrate(state, c->symbol_rate)) != 0) | ||
1249 | return ret; | ||
1250 | |||
1251 | /* discard the 'current' tuning parameters and prepare to tune */ | ||
1252 | cx24116_clone_params(fe); | ||
1253 | |||
1254 | dprintk("%s: modulation = %d\n", __func__, state->dcur.modulation); | ||
1255 | dprintk("%s: frequency = %d\n", __func__, state->dcur.frequency); | ||
1256 | dprintk("%s: pilot = %d (val = 0x%02x)\n", __func__, | ||
1257 | state->dcur.pilot, state->dcur.pilot_val); | ||
1258 | dprintk("%s: retune = %d\n", __func__, retune); | ||
1259 | dprintk("%s: rolloff = %d (val = 0x%02x)\n", __func__, | ||
1260 | state->dcur.rolloff, state->dcur.rolloff_val); | ||
1261 | dprintk("%s: symbol_rate = %d\n", __func__, state->dcur.symbol_rate); | ||
1262 | dprintk("%s: FEC = %d (mask/val = 0x%02x/0x%02x)\n", __func__, | ||
1263 | state->dcur.fec, state->dcur.fec_mask, state->dcur.fec_val); | ||
1264 | dprintk("%s: Inversion = %d (val = 0x%02x)\n", __func__, | ||
1265 | state->dcur.inversion, state->dcur.inversion_val); | ||
1266 | |||
1267 | /* This is also done in advise/acquire on HVR4000 but not on LITE */ | ||
1268 | if (state->config->set_ts_params) | ||
1269 | state->config->set_ts_params(fe, 0); | ||
1270 | |||
1271 | /* Set/Reset B/W */ | ||
1272 | cmd.args[0x00] = CMD_BANDWIDTH; | ||
1273 | cmd.args[0x01] = 0x01; | ||
1274 | cmd.len= 0x02; | ||
1275 | ret = cx24116_cmd_execute(fe, &cmd); | ||
1276 | if (ret != 0) | ||
1277 | return ret; | ||
1278 | |||
1279 | /* Prepare a tune request */ | ||
1280 | cmd.args[0x00] = CMD_TUNEREQUEST; | ||
1281 | |||
1282 | /* Frequency */ | ||
1283 | cmd.args[0x01] = (state->dcur.frequency & 0xff0000) >> 16; | ||
1284 | cmd.args[0x02] = (state->dcur.frequency & 0x00ff00) >> 8; | ||
1285 | cmd.args[0x03] = (state->dcur.frequency & 0x0000ff); | ||
1286 | |||
1287 | /* Symbol Rate */ | ||
1288 | cmd.args[0x04] = ((state->dcur.symbol_rate / 1000) & 0xff00) >> 8; | ||
1289 | cmd.args[0x05] = ((state->dcur.symbol_rate / 1000) & 0x00ff); | ||
1290 | |||
1291 | /* Automatic Inversion */ | ||
1292 | cmd.args[0x06] = state->dcur.inversion_val; | ||
1293 | |||
1294 | /* Modulation / FEC / Pilot */ | ||
1295 | cmd.args[0x07] = state->dcur.fec_val | state->dcur.pilot_val; | ||
1296 | |||
1297 | cmd.args[0x08] = CX24116_SEARCH_RANGE_KHZ >> 8; | ||
1298 | cmd.args[0x09] = CX24116_SEARCH_RANGE_KHZ & 0xff; | ||
1299 | cmd.args[0x0a] = 0x00; | ||
1300 | cmd.args[0x0b] = 0x00; | ||
1301 | cmd.args[0x0c] = state->dcur.rolloff_val; | ||
1302 | cmd.args[0x0d] = state->dcur.fec_mask; | ||
1303 | |||
1304 | if (state->dcur.symbol_rate > 30000000) { | ||
1305 | cmd.args[0x0e] = 0x04; | ||
1306 | cmd.args[0x0f] = 0x00; | ||
1307 | cmd.args[0x10] = 0x01; | ||
1308 | cmd.args[0x11] = 0x77; | ||
1309 | cmd.args[0x12] = 0x36; | ||
1310 | cx24116_writereg(state, CX24116_REG_CLKDIV, 0x44); | ||
1311 | cx24116_writereg(state, CX24116_REG_RATEDIV, 0x01); | ||
1312 | } else { | ||
1313 | cmd.args[0x0e] = 0x06; | ||
1314 | cmd.args[0x0f] = 0x00; | ||
1315 | cmd.args[0x10] = 0x00; | ||
1316 | cmd.args[0x11] = 0xFA; | ||
1317 | cmd.args[0x12] = 0x24; | ||
1318 | cx24116_writereg(state, CX24116_REG_CLKDIV, 0x46); | ||
1319 | cx24116_writereg(state, CX24116_REG_RATEDIV, 0x00); | ||
1320 | } | ||
1321 | |||
1322 | cmd.len= 0x13; | ||
1323 | |||
1324 | /* We need to support pilot and non-pilot tuning in the | ||
1325 | * driver automatically. This is a workaround for because | ||
1326 | * the demod does not support autodetect. | ||
1327 | */ | ||
1328 | do { | ||
1329 | /* Reset status register */ | ||
1330 | status = cx24116_readreg(state, CX24116_REG_SSTATUS) & CX24116_SIGNAL_MASK; | ||
1331 | cx24116_writereg(state, CX24116_REG_SSTATUS, status); | ||
1332 | |||
1333 | /* Tune */ | ||
1334 | ret = cx24116_cmd_execute(fe, &cmd); | ||
1335 | if( ret != 0 ) | ||
1336 | break; | ||
1337 | |||
1338 | /* | ||
1339 | * Wait for up to 500 ms before retrying | ||
1340 | * | ||
1341 | * If we are able to tune then generally it occurs within 100ms. | ||
1342 | * If it takes longer, try a different toneburst setting. | ||
1343 | */ | ||
1344 | for(i = 0; i < 50 ; i++) { | ||
1345 | cx24116_read_status(fe, &tunerstat); | ||
1346 | status = tunerstat & (FE_HAS_SIGNAL | FE_HAS_SYNC); | ||
1347 | if(status == (FE_HAS_SIGNAL | FE_HAS_SYNC)) { | ||
1348 | dprintk("%s: Tuned\n",__func__); | ||
1349 | goto tuned; | ||
1350 | } | ||
1351 | msleep(10); | ||
1352 | } | ||
1353 | |||
1354 | dprintk("%s: Not tuned\n",__func__); | ||
1355 | |||
1356 | /* Toggle pilot bit when in auto-pilot */ | ||
1357 | if(state->dcur.pilot == PILOT_AUTO) | ||
1358 | cmd.args[0x07] ^= CX24116_PILOT_ON; | ||
1359 | } | ||
1360 | while(--retune); | ||
1361 | |||
1362 | tuned: /* Set/Reset B/W */ | ||
1363 | cmd.args[0x00] = CMD_BANDWIDTH; | ||
1364 | cmd.args[0x01] = 0x00; | ||
1365 | cmd.len= 0x02; | ||
1366 | ret = cx24116_cmd_execute(fe, &cmd); | ||
1367 | if (ret != 0) | ||
1368 | return ret; | ||
1369 | |||
1370 | return ret; | ||
1371 | } | ||
1372 | |||
1373 | static struct dvb_frontend_ops cx24116_ops = { | ||
1374 | |||
1375 | .info = { | ||
1376 | .name = "Conexant CX24116/CX24118", | ||
1377 | .type = FE_QPSK, | ||
1378 | .frequency_min = 950000, | ||
1379 | .frequency_max = 2150000, | ||
1380 | .frequency_stepsize = 1011, /* kHz for QPSK frontends */ | ||
1381 | .frequency_tolerance = 5000, | ||
1382 | .symbol_rate_min = 1000000, | ||
1383 | .symbol_rate_max = 45000000, | ||
1384 | .caps = FE_CAN_INVERSION_AUTO | | ||
1385 | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | | ||
1386 | FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | | ||
1387 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | | ||
1388 | FE_CAN_QPSK | FE_CAN_RECOVER | ||
1389 | }, | ||
1390 | |||
1391 | .release = cx24116_release, | ||
1392 | |||
1393 | .init = cx24116_initfe, | ||
1394 | .sleep = cx24116_sleep, | ||
1395 | .read_status = cx24116_read_status, | ||
1396 | .read_ber = cx24116_read_ber, | ||
1397 | .read_signal_strength = cx24116_read_signal_strength, | ||
1398 | .read_snr = cx24116_read_snr, | ||
1399 | .read_ucblocks = cx24116_read_ucblocks, | ||
1400 | .set_tone = cx24116_set_tone, | ||
1401 | .set_voltage = cx24116_set_voltage, | ||
1402 | .diseqc_send_master_cmd = cx24116_send_diseqc_msg, | ||
1403 | .diseqc_send_burst = cx24116_diseqc_send_burst, | ||
1404 | |||
1405 | .set_property = cx24116_set_property, | ||
1406 | .get_property = cx24116_get_property, | ||
1407 | .set_frontend = cx24116_set_frontend, | ||
1408 | }; | ||
1409 | |||
1410 | module_param(debug, int, 0644); | ||
1411 | MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)"); | ||
1412 | |||
1413 | module_param(toneburst, int, 0644); | ||
1414 | MODULE_PARM_DESC(toneburst, "DiSEqC toneburst 0=OFF, 1=TONE CACHE, 2=MESSAGE CACHE (default:1)"); | ||
1415 | |||
1416 | module_param(esno_snr, int, 0644); | ||
1417 | MODULE_PARM_DESC(debug, "SNR return units, 0=PERCENTAGE 0-100, 1=ESNO(db * 10) (default:0)"); | ||
1418 | |||
1419 | MODULE_DESCRIPTION("DVB Frontend module for Conexant cx24116/cx24118 hardware"); | ||
1420 | MODULE_AUTHOR("Steven Toth"); | ||
1421 | MODULE_LICENSE("GPL"); | ||
1422 | |||
1423 | EXPORT_SYMBOL(cx24116_attach); | ||