blob: cfb265de5229a08c0c5a78311f72cb49b46f1f89 [file] [log] [blame]
Steven Toth0d467482008-09-04 01:14:43 -03001/*
2 Conexant cx24116/cx24118 - DVBS/S2 Satellite demod/tuner driver
3
4 Copyright (C) 2006-2008 Steven Toth <stoth@hauppauge.com>
Darron Broad490c8682008-09-13 19:42:16 -03005 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).
Steven Toth0d467482008-09-04 01:14:43 -030017
18 This program is free software; you can redistribute it and/or modify
19 it under the terms of the GNU General Public License as published by
20 the Free Software Foundation; either version 2 of the License, or
21 (at your option) any later version.
22
23 This program is distributed in the hope that it will be useful,
24 but WITHOUT ANY WARRANTY; without even the implied warranty of
25 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 GNU General Public License for more details.
27
28 You should have received a copy of the GNU General Public License
29 along with this program; if not, write to the Free Software
30 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31*/
32
Steven Toth0d467482008-09-04 01:14:43 -030033#include <linux/slab.h>
34#include <linux/kernel.h>
35#include <linux/module.h>
36#include <linux/moduleparam.h>
37#include <linux/init.h>
38#include <linux/firmware.h>
Darron Broad490c8682008-09-13 19:42:16 -030039#include <linux/sysctl.h>
Steven Toth0d467482008-09-04 01:14:43 -030040
41#include "dvb_frontend.h"
42#include "cx24116.h"
43
Darron Broad490c8682008-09-13 19:42:16 -030044static int debug = 0;
45#define dprintk(args...) \
46 do { \
47 if (debug) printk ("cx24116: " args); \
48 } while (0)
49
Steven Toth0d467482008-09-04 01:14:43 -030050#define CX24116_DEFAULT_FIRMWARE "dvb-fe-cx24116.fw"
51#define CX24116_SEARCH_RANGE_KHZ 5000
52
Darron Broad490c8682008-09-13 19:42:16 -030053/* 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_QSTATUS (0xbc)
61#define CX24116_REG_QUALITY (0xd5)
62#define CX24116_REG_BER0 (0xc9)
63#define CX24116_REG_BER8 (0xc8)
64#define CX24116_REG_BER16 (0xc7)
65#define CX24116_REG_BER24 (0xc6)
66#define CX24116_REG_UCB0 (0xcb)
67#define CX24116_REG_UCB8 (0xca)
68#define CX24116_REG_CLKDIV (0xf3)
69#define CX24116_REG_RATEDIV (0xf9)
Steven Toth0d467482008-09-04 01:14:43 -030070
71/* arg buffer size */
72#define CX24116_ARGLEN (0x1e)
73
Darron Broad490c8682008-09-13 19:42:16 -030074/* rolloff */
75#define CX24116_ROLLOFF_020 (0x00)
76#define CX24116_ROLLOFF_025 (0x01)
77#define CX24116_ROLLOFF_035 (0x02)
78
79/* pilot bit */
80#define CX24116_PILOT (0x40)
81
82/* signal status */
83#define CX24116_HAS_SIGNAL (0x01)
84#define CX24116_HAS_CARRIER (0x02)
85#define CX24116_HAS_VITERBI (0x04)
86#define CX24116_HAS_SYNCLOCK (0x08)
87#define CX24116_HAS_UNKNOWN1 (0x10)
88#define CX24116_HAS_UNKNOWN2 (0x20)
89#define CX24116_STATUS_MASK (0x3f)
90#define CX24116_SIGNAL_MASK (0xc0)
91
92#define CX24116_DISEQC_TONEOFF (0) /* toneburst never sent */
93#define CX24116_DISEQC_TONECACHE (1) /* toneburst cached */
94#define CX24116_DISEQC_MESGCACHE (2) /* message cached */
95
Steven Toth0d467482008-09-04 01:14:43 -030096/* arg offset for DiSEqC */
97#define CX24116_DISEQC_BURST (1)
98#define CX24116_DISEQC_ARG2_2 (2) /* unknown value=2 */
99#define CX24116_DISEQC_ARG3_0 (3) /* unknown value=0 */
100#define CX24116_DISEQC_ARG4_0 (4) /* unknown value=0 */
101#define CX24116_DISEQC_MSGLEN (5)
102#define CX24116_DISEQC_MSGOFS (6)
103
104/* DiSEqC burst */
105#define CX24116_DISEQC_MINI_A (0)
106#define CX24116_DISEQC_MINI_B (1)
107
Darron Broad490c8682008-09-13 19:42:16 -0300108/* DiSEqC tone burst */
109static int toneburst = 1;
110
111/* debug & toneburst sysctl */
112static struct ctl_table_header *kernel_table_header;
113static ctl_table toneburst_table[] = {
114{
115 .ctl_name = 0,
116 .procname = "toneburst",
117 .data = &toneburst,
118 .maxlen = sizeof(int),
119 .mode = 0666,
120 .child = NULL,
121 .parent = NULL,
122 .proc_handler = &proc_dointvec,
123 .strategy = NULL,
124 .extra1 = NULL,
125 .extra2 = NULL,
126},
127{
128 .ctl_name = 0,
129 .procname = "debug",
130 .data = &debug,
131 .maxlen = sizeof(int),
132 .mode = 0666,
133 .child = NULL,
134 .parent = NULL,
135 .proc_handler = &proc_dointvec,
136 .strategy = NULL,
137 .extra1 = NULL,
138 .extra2 = NULL,
139 },
140 {0},
141};
142static ctl_table cx24116_table[] = {
143{
144 .ctl_name = 0,
145 .procname = "cx24116",
146 .data = NULL,
147 .maxlen = 0,
148 .mode = 0555,
149 .child = toneburst_table,
150 .parent = NULL,
151 .proc_handler = NULL,
152 .strategy = NULL,
153 .extra1 = NULL,
154 .extra2 = NULL,
155 },
156 {0},
157};
158static ctl_table kernel_table[] = {
159{
160 .ctl_name = CTL_DEV,
161 .procname = "dev",
162 .data = NULL,
163 .maxlen = 0,
164 .mode = 0555,
165 .child = cx24116_table,
166 .parent = NULL,
167 .proc_handler = NULL,
168 .strategy = NULL,
169 .extra1 = NULL,
170 .extra2 = NULL,
171 },
172 {0},
173};
Steven Toth0d467482008-09-04 01:14:43 -0300174
175enum cmds
176{
Darron Broad490c8682008-09-13 19:42:16 -0300177 CMD_SET_VCO = 0x10,
Steven Toth0d467482008-09-04 01:14:43 -0300178 CMD_TUNEREQUEST = 0x11,
Darron Broad490c8682008-09-13 19:42:16 -0300179 CMD_MPEGCONFIG = 0x13,
180 CMD_TUNERINIT = 0x14,
181 CMD_BANDWIDTH = 0x15,
182 CMD_GETAGC = 0x19,
183 CMD_LNBCONFIG = 0x20,
184 CMD_LNBSEND = 0x21, /* Formerly CMD_SEND_DISEQC */
Steven Toth0d467482008-09-04 01:14:43 -0300185 CMD_SET_TONEPRE = 0x22,
186 CMD_SET_TONE = 0x23,
Darron Broad490c8682008-09-13 19:42:16 -0300187 CMD_UPDFWVERS = 0x35,
188 CMD_TUNERSLEEP = 0x36,
189 CMD_AGCCONTROL = 0x3b, /* Unknown */
Steven Toth0d467482008-09-04 01:14:43 -0300190};
191
192/* The Demod/Tuner can't easily provide these, we cache them */
193struct cx24116_tuning
194{
195 u32 frequency;
196 u32 symbol_rate;
197 fe_spectral_inversion_t inversion;
198 fe_code_rate_t fec;
199
200 fe_modulation_t modulation;
Darron Broad490c8682008-09-13 19:42:16 -0300201 fe_pilot_t pilot;
202 fe_rolloff_t rolloff;
Steven Toth0d467482008-09-04 01:14:43 -0300203
204 /* Demod values */
205 u8 fec_val;
206 u8 fec_mask;
207 u8 inversion_val;
Darron Broad490c8682008-09-13 19:42:16 -0300208 u8 rolloff_val;
Steven Toth0d467482008-09-04 01:14:43 -0300209};
210
211/* Basic commands that are sent to the firmware */
212struct cx24116_cmd
213{
214 u8 len;
215 u8 args[CX24116_ARGLEN];
216};
217
218struct cx24116_state
219{
220 struct i2c_adapter* i2c;
221 const struct cx24116_config* config;
222
223 struct dvb_frontend frontend;
224
225 struct cx24116_tuning dcur;
226 struct cx24116_tuning dnxt;
227
228 u8 skip_fw_load;
229 u8 burst;
Darron Broad490c8682008-09-13 19:42:16 -0300230 struct cx24116_cmd dsec_cmd;
Steven Toth0d467482008-09-04 01:14:43 -0300231};
232
233static int cx24116_writereg(struct cx24116_state* state, int reg, int data)
234{
235 u8 buf[] = { reg, data };
236 struct i2c_msg msg = { .addr = state->config->demod_address,
237 .flags = 0, .buf = buf, .len = 2 };
238 int err;
239
240 if (debug>1)
241 printk("cx24116: %s: write reg 0x%02x, value 0x%02x\n",
242 __func__,reg, data);
243
244 if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
245 printk("%s: writereg error(err == %i, reg == 0x%02x,"
246 " value == 0x%02x)\n", __func__, err, reg, data);
247 return -EREMOTEIO;
248 }
249
250 return 0;
251}
252
253/* Bulk byte writes to a single I2C address, for 32k firmware load */
254static int cx24116_writeregN(struct cx24116_state* state, int reg, u8 *data, u16 len)
255{
256 int ret = -EREMOTEIO;
257 struct i2c_msg msg;
258 u8 *buf;
259
260 buf = kmalloc(len + 1, GFP_KERNEL);
261 if (buf == NULL) {
262 printk("Unable to kmalloc\n");
263 ret = -ENOMEM;
264 goto error;
265 }
266
267 *(buf) = reg;
268 memcpy(buf + 1, data, len);
269
270 msg.addr = state->config->demod_address;
271 msg.flags = 0;
272 msg.buf = buf;
273 msg.len = len + 1;
274
275 if (debug>1)
276 printk("cx24116: %s: write regN 0x%02x, len = %d\n",
277 __func__,reg, len);
278
279 if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1) {
280 printk("%s: writereg error(err == %i, reg == 0x%02x\n",
281 __func__, ret, reg);
282 ret = -EREMOTEIO;
283 }
284
285error:
286 kfree(buf);
287
288 return ret;
289}
290
291static int cx24116_readreg(struct cx24116_state* state, u8 reg)
292{
293 int ret;
294 u8 b0[] = { reg };
295 u8 b1[] = { 0 };
296 struct i2c_msg msg[] = {
297 { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
298 { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 }
299 };
300
301 ret = i2c_transfer(state->i2c, msg, 2);
302
303 if (ret != 2) {
304 printk("%s: reg=0x%x (error=%d)\n", __func__, reg, ret);
305 return ret;
306 }
307
308 if (debug>1)
309 printk("cx24116: read reg 0x%02x, value 0x%02x\n",reg, b1[0]);
310
311 return b1[0];
312}
313
314static int cx24116_set_inversion(struct cx24116_state* state, fe_spectral_inversion_t inversion)
315{
316 dprintk("%s(%d)\n", __func__, inversion);
317
318 switch (inversion) {
319 case INVERSION_OFF:
320 state->dnxt.inversion_val = 0x00;
321 break;
322 case INVERSION_ON:
323 state->dnxt.inversion_val = 0x04;
324 break;
325 case INVERSION_AUTO:
326 state->dnxt.inversion_val = 0x0C;
327 break;
328 default:
329 return -EINVAL;
330 }
331
332 state->dnxt.inversion = inversion;
333
334 return 0;
335}
336
Darron Broad490c8682008-09-13 19:42:16 -0300337/*
338 * modfec (modulation and FEC)
339 * ===========================
340 *
341 * MOD FEC mask/val standard
342 * ---- -------- ----------- --------
343 * QPSK FEC_1_2 0x02 0x02+X DVB-S
344 * QPSK FEC_2_3 0x04 0x02+X DVB-S
345 * QPSK FEC_3_4 0x08 0x02+X DVB-S
346 * QPSK FEC_4_5 0x10 0x02+X DVB-S (?)
347 * QPSK FEC_5_6 0x20 0x02+X DVB-S
348 * QPSK FEC_6_7 0x40 0x02+X DVB-S
349 * QPSK FEC_7_8 0x80 0x02+X DVB-S
350 * QPSK FEC_8_9 0x01 0x02+X DVB-S (?) (NOT SUPPORTED?)
351 * QPSK AUTO 0xff 0x02+X DVB-S
352 *
353 * For DVB-S high byte probably represents FEC
354 * and low byte selects the modulator. The high
355 * byte is search range mask. Bit 5 may turn
356 * on DVB-S and remaining bits represent some
357 * kind of calibration (how/what i do not know).
358 *
359 * Eg.(2/3) szap "Zone Horror"
360 *
361 * mask/val = 0x04, 0x20
362 * status 1f | signal c3c0 | snr a333 | ber 00000098 | unc 00000000 | FE_HAS_LOCK
363 *
364 * mask/val = 0x04, 0x30
365 * status 1f | signal c3c0 | snr a333 | ber 00000000 | unc 00000000 | FE_HAS_LOCK
366 *
367 * After tuning FECSTATUS contains actual FEC
368 * in use numbered 1 through to 8 for 1/2 .. 2/3 etc
369 *
370 * NBC=NOT/NON BACKWARD COMPATIBLE WITH DVB-S (DVB-S2 only)
371 *
372 * NBC-QPSK FEC_1_2 0x00, 0x04 DVB-S2
373 * NBC-QPSK FEC_3_5 0x00, 0x05 DVB-S2
374 * NBC-QPSK FEC_2_3 0x00, 0x06 DVB-S2
375 * NBC-QPSK FEC_3_4 0x00, 0x07 DVB-S2
376 * NBC-QPSK FEC_4_5 0x00, 0x08 DVB-S2
377 * NBC-QPSK FEC_5_6 0x00, 0x09 DVB-S2
378 * NBC-QPSK FEC_8_9 0x00, 0x0a DVB-S2
379 * NBC-QPSK FEC_9_10 0x00, 0x0b DVB-S2
380 *
381 * NBC-8PSK FEC_3_5 0x00, 0x0c DVB-S2
382 * NBC-8PSK FEC_2_3 0x00, 0x0d DVB-S2
383 * NBC-8PSK FEC_3_4 0x00, 0x0e DVB-S2
384 * NBC-8PSK FEC_5_6 0x00, 0x0f DVB-S2
385 * NBC-8PSK FEC_8_9 0x00, 0x10 DVB-S2
386 * NBC-8PSK FEC_9_10 0x00, 0x11 DVB-S2
387 *
388 * For DVB-S2 low bytes selects both modulator
389 * and FEC. High byte is meaningless here. To
390 * set pilot, bit 6 (0x40) is set. When inspecting
391 * FECSTATUS bit 7 (0x80) represents the pilot
392 * selection whilst not tuned. When tuned, actual FEC
393 * in use is found in FECSTATUS as per above. Pilot
394 * value is reset.
395 */
396
Steven Toth0d467482008-09-04 01:14:43 -0300397/* A table of modulation, fec and configuration bytes for the demod.
398 * Not all S2 mmodulation schemes are support and not all rates with
399 * a scheme are support. Especially, no auto detect when in S2 mode.
400 */
401struct cx24116_modfec {
402 fe_modulation_t modulation;
403 fe_code_rate_t fec;
404 u8 mask; /* In DVBS mode this is used to autodetect */
405 u8 val; /* Passed to the firmware to indicate mode selection */
406} CX24116_MODFEC_MODES[] = {
407 /* QPSK. For unknown rates we set hardware to auto detect 0xfe 0x30 */
Darron Broad490c8682008-09-13 19:42:16 -0300408
409 /*mod fec mask val */
Steven Toth0d467482008-09-04 01:14:43 -0300410 { QPSK, FEC_NONE, 0xfe, 0x30 },
Darron Broad490c8682008-09-13 19:42:16 -0300411 { QPSK, FEC_1_2, 0x02, 0x2e }, /* 00000010 00101110 */
412 { QPSK, FEC_2_3, 0x04, 0x2f }, /* 00000100 00101111 */
413 { QPSK, FEC_3_4, 0x08, 0x30 }, /* 00001000 00110000 */
414 { QPSK, FEC_4_5, 0xfe, 0x30 }, /* 000?0000 ? */
415 { QPSK, FEC_5_6, 0x20, 0x31 }, /* 00100000 00110001 */
416 { QPSK, FEC_6_7, 0xfe, 0x30 }, /* 0?000000 ? */
417 { QPSK, FEC_7_8, 0x80, 0x32 }, /* 10000000 00110010 */
418 { QPSK, FEC_8_9, 0xfe, 0x30 }, /* 0000000? ? */
Steven Toth0d467482008-09-04 01:14:43 -0300419 { QPSK, FEC_AUTO, 0xfe, 0x30 },
420 /* NBC-QPSK */
421 { NBC_QPSK, FEC_1_2, 0x00, 0x04 },
422 { NBC_QPSK, FEC_3_5, 0x00, 0x05 },
423 { NBC_QPSK, FEC_2_3, 0x00, 0x06 },
424 { NBC_QPSK, FEC_3_4, 0x00, 0x07 },
425 { NBC_QPSK, FEC_4_5, 0x00, 0x08 },
426 { NBC_QPSK, FEC_5_6, 0x00, 0x09 },
427 { NBC_QPSK, FEC_8_9, 0x00, 0x0a },
428 { NBC_QPSK, FEC_9_10, 0x00, 0x0b },
429 /* 8PSK */
430 { _8PSK, FEC_3_5, 0x00, 0x0c },
431 { _8PSK, FEC_2_3, 0x00, 0x0d },
432 { _8PSK, FEC_3_4, 0x00, 0x0e },
433 { _8PSK, FEC_5_6, 0x00, 0x0f },
Darron Broad490c8682008-09-13 19:42:16 -0300434 { _8PSK, FEC_8_9, 0x00, 0x10 },
Steven Toth0d467482008-09-04 01:14:43 -0300435 { _8PSK, FEC_9_10, 0x00, 0x11 },
Darron Broad490c8682008-09-13 19:42:16 -0300436 /*
437 * `val' can be found in the FECSTATUS register when tuning.
438 * FECSTATUS will give the actual FEC in use if tuning was successful.
439 */
Steven Toth0d467482008-09-04 01:14:43 -0300440};
441
442static int cx24116_lookup_fecmod(struct cx24116_state* state,
443 fe_modulation_t m, fe_code_rate_t f)
444{
445 int i, ret = -EOPNOTSUPP;
446
Darron Broad490c8682008-09-13 19:42:16 -0300447 dprintk("%s(0x%02x,0x%02x)\n", __func__, m, f);
448
Steven Toth0d467482008-09-04 01:14:43 -0300449 for(i=0 ; i < sizeof(CX24116_MODFEC_MODES) / sizeof(struct cx24116_modfec) ; i++)
450 {
451 if( (m == CX24116_MODFEC_MODES[i].modulation) &&
452 (f == CX24116_MODFEC_MODES[i].fec) )
453 {
454 ret = i;
455 break;
456 }
457 }
458
459 return ret;
460}
461
462static int cx24116_set_fec(struct cx24116_state* state, fe_modulation_t mod, fe_code_rate_t fec)
463{
464 int ret = 0;
Darron Broad490c8682008-09-13 19:42:16 -0300465
466 dprintk("%s(0x%02x,0x%02x)\n", __func__, mod, fec);
Steven Toth0d467482008-09-04 01:14:43 -0300467
468 ret = cx24116_lookup_fecmod(state, mod, fec);
469
470 if(ret < 0)
471 return ret;
472
Darron Broad490c8682008-09-13 19:42:16 -0300473 state->dnxt.fec = fec;
Steven Toth0d467482008-09-04 01:14:43 -0300474 state->dnxt.fec_val = CX24116_MODFEC_MODES[ret].val;
475 state->dnxt.fec_mask = CX24116_MODFEC_MODES[ret].mask;
Darron Broad490c8682008-09-13 19:42:16 -0300476 dprintk("%s() mask/val = 0x%02x/0x%02x\n", __func__,
477 state->dnxt.fec_mask, state->dnxt.fec_val);
Steven Toth0d467482008-09-04 01:14:43 -0300478
479 return 0;
480}
481
482static int cx24116_set_symbolrate(struct cx24116_state* state, u32 rate)
483{
Darron Broad490c8682008-09-13 19:42:16 -0300484 dprintk("%s(%d)\n", __func__, rate);
Steven Toth0d467482008-09-04 01:14:43 -0300485
486 /* check if symbol rate is within limits */
Darron Broad490c8682008-09-13 19:42:16 -0300487 if ((rate > state->frontend.ops.info.symbol_rate_max) ||
488 (rate < state->frontend.ops.info.symbol_rate_min)) {
489 dprintk("%s() unsupported symbol_rate = %d\n", __func__, rate);
490 return -EOPNOTSUPP;
491 }
Steven Toth0d467482008-09-04 01:14:43 -0300492
Darron Broad490c8682008-09-13 19:42:16 -0300493 state->dnxt.symbol_rate = rate;
494 dprintk("%s() symbol_rate = %d\n", __func__, rate);
495
496 return 0;
Steven Toth0d467482008-09-04 01:14:43 -0300497}
498
499static int cx24116_load_firmware (struct dvb_frontend* fe, const struct firmware *fw);
500
501static int cx24116_firmware_ondemand(struct dvb_frontend* fe)
502{
503 struct cx24116_state *state = fe->demodulator_priv;
504 const struct firmware *fw;
505 int ret = 0;
506
507 dprintk("%s()\n",__func__);
508
509 if (cx24116_readreg(state, 0x20) > 0)
510 {
511
512 if (state->skip_fw_load)
513 return 0;
514
515 /* Load firmware */
516 /* request the firmware, this will block until someone uploads it */
517 printk("%s: Waiting for firmware upload (%s)...\n", __func__, CX24116_DEFAULT_FIRMWARE);
518 ret = request_firmware(&fw, CX24116_DEFAULT_FIRMWARE, &state->i2c->dev);
519 printk("%s: Waiting for firmware upload(2)...\n", __func__);
520 if (ret) {
521 printk("%s: No firmware uploaded (timeout or file not found?)\n", __func__);
522 return ret;
523 }
524
525 /* Make sure we don't recurse back through here during loading */
526 state->skip_fw_load = 1;
527
528 ret = cx24116_load_firmware(fe, fw);
529 if (ret)
530 printk("%s: Writing firmware to device failed\n", __func__);
531
532 release_firmware(fw);
533
534 printk("%s: Firmware upload %s\n", __func__, ret == 0 ? "complete" : "failed");
535
536 /* Ensure firmware is always loaded if required */
537 state->skip_fw_load = 0;
538 }
539
540 return ret;
541}
542
543/* Take a basic firmware command structure, format it and forward it for processing */
544static int cx24116_cmd_execute(struct dvb_frontend* fe, struct cx24116_cmd *cmd)
545{
546 struct cx24116_state *state = fe->demodulator_priv;
547 int i, ret;
548
549 dprintk("%s()\n", __func__);
550
551 /* Load the firmware if required */
552 if ( (ret = cx24116_firmware_ondemand(fe)) != 0)
553 {
554 printk("%s(): Unable initialise the firmware\n", __func__);
555 return ret;
556 }
557
558 /* Write the command */
559 for(i = 0; i < cmd->len ; i++)
560 {
561 dprintk("%s: 0x%02x == 0x%02x\n", __func__, i, cmd->args[i]);
562 cx24116_writereg(state, i, cmd->args[i]);
563 }
564
565 /* Start execution and wait for cmd to terminate */
Darron Broad490c8682008-09-13 19:42:16 -0300566 cx24116_writereg(state, CX24116_REG_EXECUTE, 0x01);
567 while( cx24116_readreg(state, CX24116_REG_EXECUTE) )
Steven Toth0d467482008-09-04 01:14:43 -0300568 {
569 msleep(10);
570 if(i++ > 64)
571 {
572 /* Avoid looping forever if the firmware does no respond */
573 printk("%s() Firmware not responding\n", __func__);
574 return -EREMOTEIO;
575 }
576 }
577 return 0;
578}
579
580static int cx24116_load_firmware (struct dvb_frontend* fe, const struct firmware *fw)
581{
582 struct cx24116_state* state = fe->demodulator_priv;
583 struct cx24116_cmd cmd;
Darron Broad490c8682008-09-13 19:42:16 -0300584 int i, ret;
585 unsigned char vers[4];
Steven Toth0d467482008-09-04 01:14:43 -0300586
587 dprintk("%s\n", __func__);
588 dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n"
589 ,fw->size
590 ,fw->data[0]
591 ,fw->data[1]
592 ,fw->data[ fw->size-2 ]
593 ,fw->data[ fw->size-1 ]
594 );
595
596 /* Toggle 88x SRST pin to reset demod */
597 if (state->config->reset_device)
598 state->config->reset_device(fe);
599
600 /* Begin the firmware load process */
601 /* Prepare the demod, load the firmware, cleanup after load */
Steven Toth0d467482008-09-04 01:14:43 -0300602
Darron Broad490c8682008-09-13 19:42:16 -0300603 /* Init PLL */
604 cx24116_writereg(state, 0xE5, 0x00);
605 cx24116_writereg(state, 0xF1, 0x08);
606 cx24116_writereg(state, 0xF2, 0x13);
607
608 /* Start PLL */
609 cx24116_writereg(state, 0xe0, 0x03);
610 cx24116_writereg(state, 0xe0, 0x00);
611
612 /* Unknown */
613 cx24116_writereg(state, CX24116_REG_CLKDIV, 0x46);
614 cx24116_writereg(state, CX24116_REG_RATEDIV, 0x00);
615
616 /* Unknown */
Steven Toth0d467482008-09-04 01:14:43 -0300617 cx24116_writereg(state, 0xF0, 0x03);
618 cx24116_writereg(state, 0xF4, 0x81);
619 cx24116_writereg(state, 0xF5, 0x00);
620 cx24116_writereg(state, 0xF6, 0x00);
621
622 /* write the entire firmware as one transaction */
623 cx24116_writeregN(state, 0xF7, fw->data, fw->size);
624
625 cx24116_writereg(state, 0xF4, 0x10);
626 cx24116_writereg(state, 0xF0, 0x00);
627 cx24116_writereg(state, 0xF8, 0x06);
628
Darron Broad490c8682008-09-13 19:42:16 -0300629 /* Firmware CMD 10: VCO config */
630 cmd.args[0x00] = CMD_SET_VCO;
Steven Toth0d467482008-09-04 01:14:43 -0300631 cmd.args[0x01] = 0x05;
632 cmd.args[0x02] = 0xdc;
633 cmd.args[0x03] = 0xda;
634 cmd.args[0x04] = 0xae;
635 cmd.args[0x05] = 0xaa;
636 cmd.args[0x06] = 0x04;
637 cmd.args[0x07] = 0x9d;
638 cmd.args[0x08] = 0xfc;
639 cmd.args[0x09] = 0x06;
640 cmd.len= 0x0a;
641 ret = cx24116_cmd_execute(fe, &cmd);
642 if (ret != 0)
643 return ret;
644
Darron Broad490c8682008-09-13 19:42:16 -0300645 cx24116_writereg(state, CX24116_REG_SSTATUS, 0x00);
Steven Toth0d467482008-09-04 01:14:43 -0300646
Darron Broad490c8682008-09-13 19:42:16 -0300647 /* Firmware CMD 14: Tuner config */
648 cmd.args[0x00] = CMD_TUNERINIT;
Steven Toth0d467482008-09-04 01:14:43 -0300649 cmd.args[0x01] = 0x00;
650 cmd.args[0x02] = 0x00;
651 cmd.len= 0x03;
652 ret = cx24116_cmd_execute(fe, &cmd);
653 if (ret != 0)
654 return ret;
655
656 cx24116_writereg(state, 0xe5, 0x00);
657
Darron Broad490c8682008-09-13 19:42:16 -0300658 /* Firmware CMD 13: MPEG config */
659 cmd.args[0x00] = CMD_MPEGCONFIG;
Steven Toth0d467482008-09-04 01:14:43 -0300660 cmd.args[0x01] = 0x01;
661 cmd.args[0x02] = 0x75;
662 cmd.args[0x03] = 0x00;
Igor M. Liplianincc8c4f32008-09-09 13:57:47 -0300663 if (state->config->mpg_clk_pos_pol)
664 cmd.args[0x04] = state->config->mpg_clk_pos_pol;
665 else
666 cmd.args[0x04] = 0x02;
Steven Toth0d467482008-09-04 01:14:43 -0300667 cmd.args[0x05] = 0x00;
668 cmd.len= 0x06;
669 ret = cx24116_cmd_execute(fe, &cmd);
670 if (ret != 0)
671 return ret;
672
Darron Broad490c8682008-09-13 19:42:16 -0300673 /* Firmware CMD 35: Get firmware version */
674 cmd.args[0x00] = CMD_UPDFWVERS;
675 cmd.len= 0x02;
676 for(i=0; i<4; i++) {
677 cmd.args[0x01] = i;
678 ret = cx24116_cmd_execute(fe, &cmd);
679 if (ret != 0)
680 return ret;
681 vers[i]= cx24116_readreg(state, CX24116_REG_MAILBOX);
682 }
683 printk("%s: FW version %i.%i.%i.%i\n", __func__,
684 vers[0], vers[1], vers[2], vers[3]);
685
Steven Toth0d467482008-09-04 01:14:43 -0300686 return 0;
687}
688
689static int cx24116_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
690{
691 /* The isl6421 module will override this function in the fops. */
692 dprintk("%s() This should never appear if the isl6421 module is loaded correctly\n",__func__);
693
694 return -EOPNOTSUPP;
695}
696
697static int cx24116_read_status(struct dvb_frontend* fe, fe_status_t* status)
698{
699 struct cx24116_state *state = fe->demodulator_priv;
700
Darron Broad490c8682008-09-13 19:42:16 -0300701 int lock = cx24116_readreg(state, CX24116_REG_SSTATUS);
Steven Toth0d467482008-09-04 01:14:43 -0300702
703 dprintk("%s: status = 0x%02x\n", __func__, lock);
704
705 *status = 0;
706
Darron Broad490c8682008-09-13 19:42:16 -0300707 if (lock & CX24116_HAS_SIGNAL)
Steven Toth0d467482008-09-04 01:14:43 -0300708 *status |= FE_HAS_SIGNAL;
Darron Broad490c8682008-09-13 19:42:16 -0300709 if (lock & CX24116_HAS_CARRIER)
Steven Toth0d467482008-09-04 01:14:43 -0300710 *status |= FE_HAS_CARRIER;
Darron Broad490c8682008-09-13 19:42:16 -0300711 if (lock & CX24116_HAS_VITERBI)
Steven Toth0d467482008-09-04 01:14:43 -0300712 *status |= FE_HAS_VITERBI;
Darron Broad490c8682008-09-13 19:42:16 -0300713 if (lock & CX24116_HAS_SYNCLOCK)
Steven Toth0d467482008-09-04 01:14:43 -0300714 *status |= FE_HAS_SYNC | FE_HAS_LOCK;
715
716 return 0;
717}
718
Steven Toth0d467482008-09-04 01:14:43 -0300719static int cx24116_read_ber(struct dvb_frontend* fe, u32* ber)
720{
Darron Broad490c8682008-09-13 19:42:16 -0300721 struct cx24116_state *state = fe->demodulator_priv;
722
Steven Toth0d467482008-09-04 01:14:43 -0300723 dprintk("%s()\n", __func__);
Darron Broad490c8682008-09-13 19:42:16 -0300724
725 *ber = ( cx24116_readreg(state, CX24116_REG_BER24) << 24 ) |
726 ( cx24116_readreg(state, CX24116_REG_BER16) << 16 ) |
727 ( cx24116_readreg(state, CX24116_REG_BER8 ) << 8 ) |
728 cx24116_readreg(state, CX24116_REG_BER0 );
Steven Toth0d467482008-09-04 01:14:43 -0300729
730 return 0;
731}
732
Darron Broad490c8682008-09-13 19:42:16 -0300733/* TODO Determine function and scale appropriately */
Steven Toth0d467482008-09-04 01:14:43 -0300734static int cx24116_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
735{
736 struct cx24116_state *state = fe->demodulator_priv;
Darron Broad490c8682008-09-13 19:42:16 -0300737 struct cx24116_cmd cmd;
738 int ret;
739 u16 sig_reading;
740
741 dprintk("%s()\n", __func__);
742
743 /* Firmware CMD 19: Get AGC */
744 cmd.args[0x00] = CMD_GETAGC;
745 cmd.len= 0x01;
746 ret = cx24116_cmd_execute(fe, &cmd);
747 if (ret != 0)
748 return ret;
749
750 sig_reading = ( cx24116_readreg(state, CX24116_REG_SSTATUS) & CX24116_SIGNAL_MASK ) |
751 ( cx24116_readreg(state, CX24116_REG_SIGNAL) << 6 );
752 *signal_strength= 0 - sig_reading;
753
754 dprintk("%s: raw / cooked = 0x%04x / 0x%04x\n", __func__, sig_reading, *signal_strength);
755
756 return 0;
757}
758
759/* SNR (0..100)% = (sig & 0xf0) * 10 + (sig & 0x0f) * 10 / 16 */
760static int cx24116_read_snr(struct dvb_frontend* fe, u16* snr)
761{
762 struct cx24116_state *state = fe->demodulator_priv;
763 u8 snr_reading;
764 static const u32 snr_tab[] = { /* 10 x Table (rounded up) */
765 0x00000,0x0199A,0x03333,0x04ccD,0x06667,
766 0x08000,0x0999A,0x0b333,0x0cccD,0x0e667,
Steven Toth0d467482008-09-04 01:14:43 -0300767 0x10000,0x1199A,0x13333,0x14ccD,0x16667,0x18000 };
768
769 dprintk("%s()\n", __func__);
770
Darron Broad490c8682008-09-13 19:42:16 -0300771 snr_reading = cx24116_readreg(state, CX24116_REG_QUALITY);
Steven Toth0d467482008-09-04 01:14:43 -0300772
Darron Broad490c8682008-09-13 19:42:16 -0300773 if(snr_reading >= 0xa0 /* 100% */)
774 *snr = 0xffff;
Steven Toth0d467482008-09-04 01:14:43 -0300775 else
Darron Broad490c8682008-09-13 19:42:16 -0300776 *snr = snr_tab [ ( snr_reading & 0xf0 ) >> 4 ] +
777 ( snr_tab [ ( snr_reading & 0x0f ) ] >> 4 );
Steven Toth0d467482008-09-04 01:14:43 -0300778
Darron Broad490c8682008-09-13 19:42:16 -0300779 dprintk("%s: raw / cooked = 0x%02x / 0x%04x\n", __func__,
780 snr_reading, *snr);
Steven Toth0d467482008-09-04 01:14:43 -0300781
782 return 0;
783}
784
Steven Toth0d467482008-09-04 01:14:43 -0300785static int cx24116_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
786{
Darron Broad490c8682008-09-13 19:42:16 -0300787 struct cx24116_state *state = fe->demodulator_priv;
788
Steven Toth0d467482008-09-04 01:14:43 -0300789 dprintk("%s()\n", __func__);
Darron Broad490c8682008-09-13 19:42:16 -0300790
791 *ucblocks = ( cx24116_readreg(state, CX24116_REG_UCB8) << 8 ) |
792 cx24116_readreg(state, CX24116_REG_UCB0);
Steven Toth0d467482008-09-04 01:14:43 -0300793
794 return 0;
795}
796
797/* Overwrite the current tuning params, we are about to tune */
798static void cx24116_clone_params(struct dvb_frontend* fe)
799{
800 struct cx24116_state *state = fe->demodulator_priv;
801 memcpy(&state->dcur, &state->dnxt, sizeof(state->dcur));
802}
803
Darron Broad490c8682008-09-13 19:42:16 -0300804/* Wait for LNB */
805static int cx24116_wait_for_lnb(struct dvb_frontend* fe)
806{
807 struct cx24116_state *state = fe->demodulator_priv;
808 int i;
809
810 dprintk("%s() qstatus = 0x%02x\n", __func__,
811 cx24116_readreg(state, CX24116_REG_QSTATUS));
812
813 /* Wait for up to 300 ms */
814 for(i = 0; i < 30 ; i++) {
815 if (cx24116_readreg(state, CX24116_REG_QSTATUS) & 0x20)
816 return 0;
817 msleep(10);
818 }
819
820 dprintk("%s(): LNB not ready\n", __func__);
821
822 return -ETIMEDOUT; /* -EBUSY ? */
823}
824
Steven Toth0d467482008-09-04 01:14:43 -0300825static int cx24116_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
826{
827 struct cx24116_cmd cmd;
828 int ret;
829
830 dprintk("%s(%d)\n", __func__, tone);
831 if ( (tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF) ) {
832 printk("%s: Invalid, tone=%d\n", __func__, tone);
833 return -EINVAL;
834 }
835
Darron Broad490c8682008-09-13 19:42:16 -0300836 /* Wait for LNB ready */
837 ret = cx24116_wait_for_lnb(fe);
838 if(ret != 0)
839 return ret;
840
841 /* Min delay time after DiSEqC send */
842 msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */
843
Steven Toth0d467482008-09-04 01:14:43 -0300844 /* This is always done before the tone is set */
845 cmd.args[0x00] = CMD_SET_TONEPRE;
846 cmd.args[0x01] = 0x00;
847 cmd.len= 0x02;
848 ret = cx24116_cmd_execute(fe, &cmd);
849 if (ret != 0)
850 return ret;
851
852 /* Now we set the tone */
853 cmd.args[0x00] = CMD_SET_TONE;
854 cmd.args[0x01] = 0x00;
855 cmd.args[0x02] = 0x00;
856
857 switch (tone) {
858 case SEC_TONE_ON:
859 dprintk("%s: setting tone on\n", __func__);
860 cmd.args[0x03] = 0x01;
861 break;
862 case SEC_TONE_OFF:
863 dprintk("%s: setting tone off\n",__func__);
864 cmd.args[0x03] = 0x00;
865 break;
866 }
867 cmd.len= 0x04;
868
Darron Broad490c8682008-09-13 19:42:16 -0300869 /* Min delay time before DiSEqC send */
870 msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */
871
Steven Toth0d467482008-09-04 01:14:43 -0300872 return cx24116_cmd_execute(fe, &cmd);
873}
874
875/* Initialise DiSEqC */
876static int cx24116_diseqc_init(struct dvb_frontend* fe)
877{
878 struct cx24116_state *state = fe->demodulator_priv;
Darron Broad490c8682008-09-13 19:42:16 -0300879 struct cx24116_cmd cmd;
880 int ret;
Steven Toth0d467482008-09-04 01:14:43 -0300881
Darron Broad490c8682008-09-13 19:42:16 -0300882 /* Firmware CMD 20: LNB/DiSEqC config */
883 cmd.args[0x00] = CMD_LNBCONFIG;
884 cmd.args[0x01] = 0x00;
885 cmd.args[0x02] = 0x10;
886 cmd.args[0x03] = 0x00;
887 cmd.args[0x04] = 0x8f;
888 cmd.args[0x05] = 0x28;
889 cmd.args[0x06] = (toneburst == CX24116_DISEQC_TONEOFF) ? 0x00 : 0x01;
890 cmd.args[0x07] = 0x01;
891 cmd.len= 0x08;
892 ret = cx24116_cmd_execute(fe, &cmd);
893 if (ret != 0)
894 return ret;
895
896 /* Prepare a DiSEqC command */
897 state->dsec_cmd.args[0x00] = CMD_LNBSEND;
898
899 /* DiSEqC burst */
900 state->dsec_cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_A;
901
902 /* Unknown */
903 state->dsec_cmd.args[CX24116_DISEQC_ARG2_2] = 0x02;
904 state->dsec_cmd.args[CX24116_DISEQC_ARG3_0] = 0x00;
905 state->dsec_cmd.args[CX24116_DISEQC_ARG4_0] = 0x00; /* Continuation flag? */
906
907 /* DiSEqC message length */
908 state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = 0x00;
909
910 /* Command length */
911 state->dsec_cmd.len= CX24116_DISEQC_MSGOFS;
Steven Toth0d467482008-09-04 01:14:43 -0300912
913 return 0;
914}
915
916/* Send DiSEqC message with derived burst (hack) || previous burst */
917static int cx24116_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *d)
918{
919 struct cx24116_state *state = fe->demodulator_priv;
Steven Toth0d467482008-09-04 01:14:43 -0300920 int i, ret;
921
922 /* Dump DiSEqC message */
923 if (debug) {
924 printk("cx24116: %s(", __func__);
925 for(i = 0 ; i < d->msg_len ;) {
926 printk("0x%02x", d->msg[i]);
927 if(++i < d->msg_len)
928 printk(", ");
Darron Broad490c8682008-09-13 19:42:16 -0300929 }
930 printk(") toneburst=%d\n", toneburst);
Steven Toth0d467482008-09-04 01:14:43 -0300931 }
932
Darron Broad490c8682008-09-13 19:42:16 -0300933 /* Validate length */
Steven Toth0d467482008-09-04 01:14:43 -0300934 if(d->msg_len > (CX24116_ARGLEN - CX24116_DISEQC_MSGOFS))
935 return -EINVAL;
936
Steven Toth0d467482008-09-04 01:14:43 -0300937 /* DiSEqC message */
938 for (i = 0; i < d->msg_len; i++)
Darron Broad490c8682008-09-13 19:42:16 -0300939 state->dsec_cmd.args[CX24116_DISEQC_MSGOFS + i] = d->msg[i];
Steven Toth0d467482008-09-04 01:14:43 -0300940
Darron Broad490c8682008-09-13 19:42:16 -0300941 /* DiSEqC message length */
942 state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = d->msg_len;
Steven Toth0d467482008-09-04 01:14:43 -0300943
Darron Broad490c8682008-09-13 19:42:16 -0300944 /* Command length */
945 state->dsec_cmd.len= CX24116_DISEQC_MSGOFS + state->dsec_cmd.args[CX24116_DISEQC_MSGLEN];
Steven Toth0d467482008-09-04 01:14:43 -0300946
Darron Broad490c8682008-09-13 19:42:16 -0300947 /* DiSEqC toneburst */
948 if(toneburst == CX24116_DISEQC_MESGCACHE)
949 /* Message is cached */
950 return 0;
Steven Toth0d467482008-09-04 01:14:43 -0300951
Darron Broad490c8682008-09-13 19:42:16 -0300952 else if(toneburst == CX24116_DISEQC_TONEOFF)
953 /* Message is sent without burst */
954 state->dsec_cmd.args[CX24116_DISEQC_BURST] = 0;
955
956 else if(toneburst == CX24116_DISEQC_TONECACHE) {
957 /*
958 * Message is sent with derived else cached burst
959 *
960 * WRITE PORT GROUP COMMAND 38
961 *
962 * 0/A/A: E0 10 38 F0..F3
963 * 1/B/B: E0 10 38 F4..F7
964 * 2/C/A: E0 10 38 F8..FB
965 * 3/D/B: E0 10 38 FC..FF
966 *
967 * datebyte[3]= 8421:8421
968 * ABCD:WXYZ
969 * CLR :SET
970 *
971 * WX= PORT SELECT 0..3 (X=TONEBURST)
972 * Y = VOLTAGE (0=13V, 1=18V)
973 * Z = BAND (0=LOW, 1=HIGH(22K))
974 */
975 if(d->msg_len >= 4 && d->msg[2] == 0x38)
976 state->dsec_cmd.args[CX24116_DISEQC_BURST] = ((d->msg[3] & 4) >> 2);
977 if(debug)
978 dprintk("%s burst=%d\n", __func__, state->dsec_cmd.args[CX24116_DISEQC_BURST]);
979 }
980
981 /* Wait for LNB ready */
982 ret = cx24116_wait_for_lnb(fe);
983 if(ret != 0)
984 return ret;
985
986 /* Wait for voltage/min repeat delay */
987 msleep(100);
988
989 /* Command */
990 ret = cx24116_cmd_execute(fe, &state->dsec_cmd);
991 if(ret != 0)
992 return ret;
993 /*
994 * Wait for send
Steven Toth0d467482008-09-04 01:14:43 -0300995 *
996 * Eutelsat spec:
Darron Broad490c8682008-09-13 19:42:16 -0300997 * >15ms delay + (XXX determine if FW does this, see set_tone)
998 * 13.5ms per byte +
999 * >15ms delay +
1000 * 12.5ms burst +
1001 * >15ms delay (XXX determine if FW does this, see set_tone)
Steven Toth0d467482008-09-04 01:14:43 -03001002 */
Darron Broad490c8682008-09-13 19:42:16 -03001003 msleep( (state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) + ((toneburst == CX24116_DISEQC_TONEOFF) ? 30 : 60) );
Steven Toth0d467482008-09-04 01:14:43 -03001004
Darron Broad490c8682008-09-13 19:42:16 -03001005 return 0;
Steven Toth0d467482008-09-04 01:14:43 -03001006}
1007
1008/* Send DiSEqC burst */
1009static int cx24116_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst)
1010{
1011 struct cx24116_state *state = fe->demodulator_priv;
Steven Toth0d467482008-09-04 01:14:43 -03001012 int ret;
1013
Darron Broad490c8682008-09-13 19:42:16 -03001014 dprintk("%s(%d) toneburst=%d\n",__func__, burst, toneburst);
Steven Toth0d467482008-09-04 01:14:43 -03001015
Darron Broad490c8682008-09-13 19:42:16 -03001016 /* DiSEqC burst */
Steven Toth0d467482008-09-04 01:14:43 -03001017 if (burst == SEC_MINI_A)
Darron Broad490c8682008-09-13 19:42:16 -03001018 state->dsec_cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_A;
Steven Toth0d467482008-09-04 01:14:43 -03001019 else if(burst == SEC_MINI_B)
Darron Broad490c8682008-09-13 19:42:16 -03001020 state->dsec_cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_B;
Steven Toth0d467482008-09-04 01:14:43 -03001021 else
1022 return -EINVAL;
1023
Darron Broad490c8682008-09-13 19:42:16 -03001024 /* DiSEqC toneburst */
1025 if(toneburst != CX24116_DISEQC_MESGCACHE)
1026 /* Burst is cached */
1027 return 0;
Steven Toth0d467482008-09-04 01:14:43 -03001028
Darron Broad490c8682008-09-13 19:42:16 -03001029 /* Burst is to be sent with cached message */
Steven Toth0d467482008-09-04 01:14:43 -03001030
Darron Broad490c8682008-09-13 19:42:16 -03001031 /* Wait for LNB ready */
1032 ret = cx24116_wait_for_lnb(fe);
1033 if(ret != 0)
1034 return ret;
Steven Toth0d467482008-09-04 01:14:43 -03001035
Darron Broad490c8682008-09-13 19:42:16 -03001036 /* Wait for voltage/min repeat delay */
1037 msleep(100);
Steven Toth0d467482008-09-04 01:14:43 -03001038
Darron Broad490c8682008-09-13 19:42:16 -03001039 /* Command */
1040 ret = cx24116_cmd_execute(fe, &state->dsec_cmd);
1041 if(ret != 0)
1042 return ret;
1043
1044 /*
1045 * Wait for send
1046 *
1047 * Eutelsat spec:
1048 * >15ms delay + (XXX determine if FW does this, see set_tone)
1049 * 13.5ms per byte +
1050 * >15ms delay +
1051 * 12.5ms burst +
1052 * >15ms delay (XXX determine if FW does this, see set_tone)
1053 */
1054 msleep( (state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) + 60 );
1055
1056 return 0;
Steven Toth0d467482008-09-04 01:14:43 -03001057}
1058
1059static void cx24116_release(struct dvb_frontend* fe)
1060{
1061 struct cx24116_state* state = fe->demodulator_priv;
1062 dprintk("%s\n",__func__);
1063 kfree(state);
Darron Broad490c8682008-09-13 19:42:16 -03001064 unregister_sysctl_table(kernel_table_header);
Steven Toth0d467482008-09-04 01:14:43 -03001065}
1066
1067static struct dvb_frontend_ops cx24116_ops;
1068
1069struct dvb_frontend* cx24116_attach(const struct cx24116_config* config,
1070 struct i2c_adapter* i2c)
1071{
1072 struct cx24116_state* state = NULL;
1073 int ret;
1074
1075 dprintk("%s\n",__func__);
1076
Darron Broad490c8682008-09-13 19:42:16 -03001077 kernel_table_header = register_sysctl_table(kernel_table);
1078 if(!kernel_table_header)
1079 goto error1;
1080
Steven Toth0d467482008-09-04 01:14:43 -03001081 /* allocate memory for the internal state */
1082 state = kmalloc(sizeof(struct cx24116_state), GFP_KERNEL);
1083 if (state == NULL) {
1084 printk("Unable to kmalloc\n");
Darron Broad490c8682008-09-13 19:42:16 -03001085 goto error2;
Steven Toth0d467482008-09-04 01:14:43 -03001086 }
1087
1088 /* setup the state */
1089 memset(state, 0, sizeof(struct cx24116_state));
1090
1091 state->config = config;
1092 state->i2c = i2c;
1093
1094 /* check if the demod is present */
1095 ret = (cx24116_readreg(state, 0xFF) << 8) | cx24116_readreg(state, 0xFE);
1096 if (ret != 0x0501) {
1097 printk("Invalid probe, probably not a CX24116 device\n");
Darron Broad490c8682008-09-13 19:42:16 -03001098 goto error3;
Steven Toth0d467482008-09-04 01:14:43 -03001099 }
1100
1101 /* create dvb_frontend */
1102 memcpy(&state->frontend.ops, &cx24116_ops, sizeof(struct dvb_frontend_ops));
1103 state->frontend.demodulator_priv = state;
1104 return &state->frontend;
1105
Darron Broad490c8682008-09-13 19:42:16 -03001106error3: kfree(state);
1107error2: unregister_sysctl_table(kernel_table_header);
1108error1: return NULL;
Steven Toth0d467482008-09-04 01:14:43 -03001109}
Darron Broad490c8682008-09-13 19:42:16 -03001110/*
1111 * Initialise or wake up device
1112 *
1113 * Power config will reset and load initial firmware if required
1114 */
Steven Toth0d467482008-09-04 01:14:43 -03001115static int cx24116_initfe(struct dvb_frontend* fe)
1116{
Darron Broad490c8682008-09-13 19:42:16 -03001117 struct cx24116_state* state = fe->demodulator_priv;
1118 struct cx24116_cmd cmd;
1119 int ret;
1120
Steven Toth0d467482008-09-04 01:14:43 -03001121 dprintk("%s()\n",__func__);
1122
Darron Broad490c8682008-09-13 19:42:16 -03001123 /* Power on */
1124 cx24116_writereg(state, 0xe0, 0);
1125 cx24116_writereg(state, 0xe1, 0);
1126 cx24116_writereg(state, 0xea, 0);
1127
1128 /* Firmware CMD 36: Power config */
1129 cmd.args[0x00] = CMD_TUNERSLEEP;
1130 cmd.args[0x01] = 0;
1131 cmd.len= 0x02;
1132 ret = cx24116_cmd_execute(fe, &cmd);
1133 if(ret != 0)
1134 return ret;
1135
Steven Toth0d467482008-09-04 01:14:43 -03001136 return cx24116_diseqc_init(fe);
1137}
1138
Darron Broad490c8682008-09-13 19:42:16 -03001139/*
1140 * Put device to sleep
1141 */
1142static int cx24116_sleep(struct dvb_frontend* fe)
1143{
1144 struct cx24116_state* state = fe->demodulator_priv;
1145 struct cx24116_cmd cmd;
1146 int ret;
1147
1148 dprintk("%s()\n",__func__);
1149
1150 /* Firmware CMD 36: Power config */
1151 cmd.args[0x00] = CMD_TUNERSLEEP;
1152 cmd.args[0x01] = 1;
1153 cmd.len= 0x02;
1154 ret = cx24116_cmd_execute(fe, &cmd);
1155 if(ret != 0)
1156 return ret;
1157
1158 /* Power off (Shutdown clocks) */
1159 cx24116_writereg(state, 0xea, 0xff);
1160 cx24116_writereg(state, 0xe1, 1);
1161 cx24116_writereg(state, 0xe0, 1);
1162
1163 return 0;
1164}
1165
Steven Tothe7fee0f32008-09-11 10:23:01 -03001166static int cx24116_set_property(struct dvb_frontend *fe, struct dtv_property* tvp)
Steven Toth0d467482008-09-04 01:14:43 -03001167{
1168 dprintk("%s(..)\n", __func__);
1169 return 0;
1170}
1171
Steven Tothbfbf2da2008-09-12 01:37:37 -03001172static int cx24116_get_property(struct dvb_frontend *fe, struct dtv_property* tvp)
Steven Toth0d467482008-09-04 01:14:43 -03001173{
Steven Tothbfbf2da2008-09-12 01:37:37 -03001174 dprintk("%s(..)\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -03001175 return 0;
1176}
1177
1178/* dvb-core told us to tune, the tv property cache will be complete,
1179 * it's safe for is to pull values and use them for tuning purposes.
1180 */
1181static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
1182{
1183 struct cx24116_state *state = fe->demodulator_priv;
Steven Toth56f06802008-09-11 10:19:27 -03001184 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
Steven Toth0d467482008-09-04 01:14:43 -03001185 struct cx24116_cmd cmd;
1186 fe_status_t tunerstat;
Darron Broad490c8682008-09-13 19:42:16 -03001187 int i, status, ret, retune = 1;
Steven Toth0d467482008-09-04 01:14:43 -03001188
1189 dprintk("%s()\n",__func__);
1190
1191 state->dnxt.modulation = c->modulation;
1192 state->dnxt.frequency = c->frequency;
1193
Darron Broad490c8682008-09-13 19:42:16 -03001194 switch(c->delivery_system) {
1195 case SYS_DVBS:
1196 dprintk("%s: DVB-S delivery system selected\n",__func__);
1197 state->dnxt.pilot = PILOT_OFF;
1198 state->dnxt.rolloff = CX24116_ROLLOFF_035;
1199 break;
1200 case SYS_DVBS2:
1201 dprintk("%s: DVB-S2 delivery system selected\n",__func__);
1202 if(c->pilot == PILOT_AUTO)
1203 retune++;
1204 state->dnxt.pilot = c->pilot;
1205 switch(c->rolloff) {
1206 case ROLLOFF_20:
1207 state->dnxt.rolloff_val= CX24116_ROLLOFF_020;
1208 break;
1209 case ROLLOFF_25:
1210 state->dnxt.rolloff_val= CX24116_ROLLOFF_025;
1211 break;
1212 case ROLLOFF_35:
1213 state->dnxt.rolloff_val= CX24116_ROLLOFF_035;
1214 break;
1215 case ROLLOFF_AUTO:
1216 return -EOPNOTSUPP;
1217 }
1218 state->dnxt.rolloff = c->rolloff;
1219 break;
1220 default:
1221 dprintk("%s: unsupported delivery system selected (%d)\n",
1222 __func__, c->delivery_system);
1223 return -EOPNOTSUPP;
1224 }
1225
Steven Toth0d467482008-09-04 01:14:43 -03001226 if ((ret = cx24116_set_inversion(state, c->inversion)) != 0)
1227 return ret;
1228
1229 if ((ret = cx24116_set_fec(state, c->modulation, c->fec_inner)) != 0)
1230 return ret;
1231
1232 if ((ret = cx24116_set_symbolrate(state, c->symbol_rate)) != 0)
1233 return ret;
1234
1235 /* discard the 'current' tuning parameters and prepare to tune */
1236 cx24116_clone_params(fe);
1237
Darron Broad490c8682008-09-13 19:42:16 -03001238 dprintk("%s: retune = %d\n", __func__, retune);
1239 dprintk("%s: rolloff = %d\n", __func__, state->dcur.rolloff);
1240 dprintk("%s: pilot = %d\n", __func__, state->dcur.pilot);
Steven Toth0d467482008-09-04 01:14:43 -03001241 dprintk("%s: frequency = %d\n", __func__, state->dcur.frequency);
1242 dprintk("%s: symbol_rate = %d\n", __func__, state->dcur.symbol_rate);
1243 dprintk("%s: FEC = %d (mask/val = 0x%02x/0x%02x)\n", __func__,
1244 state->dcur.fec, state->dcur.fec_mask, state->dcur.fec_val);
1245 dprintk("%s: Inversion = %d (val = 0x%02x)\n", __func__,
1246 state->dcur.inversion, state->dcur.inversion_val);
1247
Darron Broad490c8682008-09-13 19:42:16 -03001248 /* This is also done in advise/acquire on HVR4000 but not on LITE */
Steven Toth0d467482008-09-04 01:14:43 -03001249 if (state->config->set_ts_params)
1250 state->config->set_ts_params(fe, 0);
1251
Darron Broad490c8682008-09-13 19:42:16 -03001252 /* Set/Reset B/W */
1253 cmd.args[0x00] = CMD_BANDWIDTH;
1254 cmd.args[0x01] = 0x01;
1255 cmd.len= 0x02;
1256 ret = cx24116_cmd_execute(fe, &cmd);
1257 if (ret != 0)
1258 return ret;
Igor M. Liplianin3f8e51a2008-09-09 13:22:29 -03001259
Steven Toth0d467482008-09-04 01:14:43 -03001260 /* Prepare a tune request */
1261 cmd.args[0x00] = CMD_TUNEREQUEST;
1262
1263 /* Frequency */
1264 cmd.args[0x01] = (state->dcur.frequency & 0xff0000) >> 16;
1265 cmd.args[0x02] = (state->dcur.frequency & 0x00ff00) >> 8;
1266 cmd.args[0x03] = (state->dcur.frequency & 0x0000ff);
1267
1268 /* Symbol Rate */
1269 cmd.args[0x04] = ((state->dcur.symbol_rate / 1000) & 0xff00) >> 8;
1270 cmd.args[0x05] = ((state->dcur.symbol_rate / 1000) & 0x00ff);
1271
1272 /* Automatic Inversion */
1273 cmd.args[0x06] = state->dcur.inversion_val;
1274
1275 /* Modulation / FEC & Pilot Off */
1276 cmd.args[0x07] = state->dcur.fec_val;
1277
Darron Broad490c8682008-09-13 19:42:16 -03001278 if (state->dcur.pilot == PILOT_ON)
1279 cmd.args[0x07] |= CX24116_PILOT;
Steven Toth0d467482008-09-04 01:14:43 -03001280
1281 cmd.args[0x08] = CX24116_SEARCH_RANGE_KHZ >> 8;
1282 cmd.args[0x09] = CX24116_SEARCH_RANGE_KHZ & 0xff;
1283 cmd.args[0x0a] = 0x00;
1284 cmd.args[0x0b] = 0x00;
Darron Broad490c8682008-09-13 19:42:16 -03001285 cmd.args[0x0c] = state->dcur.rolloff_val;
Steven Toth0d467482008-09-04 01:14:43 -03001286 cmd.args[0x0d] = state->dcur.fec_mask;
Igor M. Liplianin3f8e51a2008-09-09 13:22:29 -03001287
Darron Broad490c8682008-09-13 19:42:16 -03001288 if (state->dcur.symbol_rate > 30000000) {
Igor M. Liplianin3f8e51a2008-09-09 13:22:29 -03001289 cmd.args[0x0e] = 0x04;
1290 cmd.args[0x0f] = 0x00;
1291 cmd.args[0x10] = 0x01;
1292 cmd.args[0x11] = 0x77;
1293 cmd.args[0x12] = 0x36;
Darron Broad490c8682008-09-13 19:42:16 -03001294 cx24116_writereg(state, CX24116_REG_CLKDIV, 0x44);
1295 cx24116_writereg(state, CX24116_REG_RATEDIV, 0x01);
Igor M. Liplianin3f8e51a2008-09-09 13:22:29 -03001296 } else {
1297 cmd.args[0x0e] = 0x06;
1298 cmd.args[0x0f] = 0x00;
1299 cmd.args[0x10] = 0x00;
1300 cmd.args[0x11] = 0xFA;
1301 cmd.args[0x12] = 0x24;
Darron Broad490c8682008-09-13 19:42:16 -03001302 cx24116_writereg(state, CX24116_REG_CLKDIV, 0x46);
1303 cx24116_writereg(state, CX24116_REG_RATEDIV, 0x00);
Igor M. Liplianin3f8e51a2008-09-09 13:22:29 -03001304 }
1305
Steven Toth0d467482008-09-04 01:14:43 -03001306 cmd.len= 0x13;
1307
1308 /* We need to support pilot and non-pilot tuning in the
1309 * driver automatically. This is a workaround for because
1310 * the demod does not support autodetect.
1311 */
1312 do {
Darron Broad490c8682008-09-13 19:42:16 -03001313 /* Reset status register */
1314 status = cx24116_readreg(state, CX24116_REG_SSTATUS) & CX24116_SIGNAL_MASK;
1315 cx24116_writereg(state, CX24116_REG_SSTATUS, status);
Steven Toth0d467482008-09-04 01:14:43 -03001316
1317 /* Tune */
1318 ret = cx24116_cmd_execute(fe, &cmd);
1319 if( ret != 0 )
1320 break;
1321
Darron Broad490c8682008-09-13 19:42:16 -03001322 /*
1323 * Wait for up to 500 ms before retrying
1324 *
1325 * If we are able to tune then generally it occurs within 100ms.
1326 * If it takes longer, try a different toneburst setting.
1327 */
1328 for(i = 0; i < 50 ; i++) {
1329 cx24116_read_status(fe, &tunerstat);
1330 status = tunerstat & (FE_HAS_SIGNAL | FE_HAS_SYNC);
1331 if(status == (FE_HAS_SIGNAL | FE_HAS_SYNC)) {
1332 dprintk("%s: Tuned\n",__func__);
1333 goto tuned;
1334 }
1335 msleep(10);
Steven Toth0d467482008-09-04 01:14:43 -03001336 }
Darron Broad490c8682008-09-13 19:42:16 -03001337
1338 dprintk("%s: Not tuned\n",__func__);
1339
1340 /* Toggle pilot bit when in auto-pilot */
1341 if(state->dcur.pilot == PILOT_AUTO)
1342 cmd.args[0x07] ^= CX24116_PILOT;
Steven Toth0d467482008-09-04 01:14:43 -03001343 }
1344 while(--retune);
1345
Darron Broad490c8682008-09-13 19:42:16 -03001346tuned: /* Set/Reset B/W */
1347 cmd.args[0x00] = CMD_BANDWIDTH;
1348 cmd.args[0x01] = 0x00;
1349 cmd.len= 0x02;
1350 ret = cx24116_cmd_execute(fe, &cmd);
1351 if (ret != 0)
1352 return ret;
1353
Steven Toth0d467482008-09-04 01:14:43 -03001354 return ret;
1355}
1356
1357static struct dvb_frontend_ops cx24116_ops = {
1358
1359 .info = {
1360 .name = "Conexant CX24116/CX24118",
1361 .type = FE_QPSK,
1362 .frequency_min = 950000,
1363 .frequency_max = 2150000,
1364 .frequency_stepsize = 1011, /* kHz for QPSK frontends */
1365 .frequency_tolerance = 5000,
1366 .symbol_rate_min = 1000000,
1367 .symbol_rate_max = 45000000,
1368 .caps = FE_CAN_INVERSION_AUTO |
1369 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
1370 FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
1371 FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
1372 FE_CAN_QPSK | FE_CAN_RECOVER
1373 },
1374
1375 .release = cx24116_release,
1376
1377 .init = cx24116_initfe,
Darron Broad490c8682008-09-13 19:42:16 -03001378 .sleep = cx24116_sleep,
Steven Toth0d467482008-09-04 01:14:43 -03001379 .read_status = cx24116_read_status,
1380 .read_ber = cx24116_read_ber,
1381 .read_signal_strength = cx24116_read_signal_strength,
1382 .read_snr = cx24116_read_snr,
1383 .read_ucblocks = cx24116_read_ucblocks,
1384 .set_tone = cx24116_set_tone,
1385 .set_voltage = cx24116_set_voltage,
1386 .diseqc_send_master_cmd = cx24116_send_diseqc_msg,
1387 .diseqc_send_burst = cx24116_diseqc_send_burst,
1388
1389 .set_property = cx24116_set_property,
Steven Tothbfbf2da2008-09-12 01:37:37 -03001390 .get_property = cx24116_get_property,
Steven Toth0d467482008-09-04 01:14:43 -03001391 .set_frontend = cx24116_set_frontend,
1392};
1393
1394module_param(debug, int, 0644);
1395MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
1396
Darron Broad490c8682008-09-13 19:42:16 -03001397module_param(toneburst, int, 0644);
1398MODULE_PARM_DESC(toneburst, "DiSEqC toneburst 0=OFF, 1=TONE CACHE, 2=MESSAGE CACHE (default:1)");
1399
Steven Toth0d467482008-09-04 01:14:43 -03001400MODULE_DESCRIPTION("DVB Frontend module for Conexant cx24116/cx24118 hardware");
1401MODULE_AUTHOR("Steven Toth");
1402MODULE_LICENSE("GPL");
1403
1404EXPORT_SYMBOL(cx24116_attach);