blob: fdc741e7e7695871fb0bbe57f4cf0f9f483504b7 [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>
39
40#include "dvb_frontend.h"
41#include "cx24116.h"
42
Darron Broad490c8682008-09-13 19:42:16 -030043static int debug = 0;
44#define dprintk(args...) \
45 do { \
46 if (debug) printk ("cx24116: " args); \
47 } while (0)
48
Steven Toth0d467482008-09-04 01:14:43 -030049#define CX24116_DEFAULT_FIRMWARE "dvb-fe-cx24116.fw"
50#define CX24116_SEARCH_RANGE_KHZ 5000
51
Darron Broad490c8682008-09-13 19:42:16 -030052/* known registers */
53#define CX24116_REG_COMMAND (0x00) /* command args 0x00..0x1e */
54#define CX24116_REG_EXECUTE (0x1f) /* execute command */
55#define CX24116_REG_MAILBOX (0x96) /* FW or multipurpose mailbox? */
56#define CX24116_REG_RESET (0x20) /* reset status > 0 */
57#define CX24116_REG_SIGNAL (0x9e) /* signal low */
58#define CX24116_REG_SSTATUS (0x9d) /* signal high / status */
59#define CX24116_REG_QSTATUS (0xbc)
60#define CX24116_REG_QUALITY (0xd5)
61#define CX24116_REG_BER0 (0xc9)
62#define CX24116_REG_BER8 (0xc8)
63#define CX24116_REG_BER16 (0xc7)
64#define CX24116_REG_BER24 (0xc6)
65#define CX24116_REG_UCB0 (0xcb)
66#define CX24116_REG_UCB8 (0xca)
67#define CX24116_REG_CLKDIV (0xf3)
68#define CX24116_REG_RATEDIV (0xf9)
Steven Toth0d467482008-09-04 01:14:43 -030069
70/* arg buffer size */
71#define CX24116_ARGLEN (0x1e)
72
Darron Broad490c8682008-09-13 19:42:16 -030073/* rolloff */
74#define CX24116_ROLLOFF_020 (0x00)
75#define CX24116_ROLLOFF_025 (0x01)
76#define CX24116_ROLLOFF_035 (0x02)
77
78/* pilot bit */
79#define CX24116_PILOT (0x40)
80
81/* signal status */
82#define CX24116_HAS_SIGNAL (0x01)
83#define CX24116_HAS_CARRIER (0x02)
84#define CX24116_HAS_VITERBI (0x04)
85#define CX24116_HAS_SYNCLOCK (0x08)
86#define CX24116_HAS_UNKNOWN1 (0x10)
87#define CX24116_HAS_UNKNOWN2 (0x20)
88#define CX24116_STATUS_MASK (0x3f)
89#define CX24116_SIGNAL_MASK (0xc0)
90
91#define CX24116_DISEQC_TONEOFF (0) /* toneburst never sent */
92#define CX24116_DISEQC_TONECACHE (1) /* toneburst cached */
93#define CX24116_DISEQC_MESGCACHE (2) /* message cached */
94
Steven Toth0d467482008-09-04 01:14:43 -030095/* arg offset for DiSEqC */
96#define CX24116_DISEQC_BURST (1)
97#define CX24116_DISEQC_ARG2_2 (2) /* unknown value=2 */
98#define CX24116_DISEQC_ARG3_0 (3) /* unknown value=0 */
99#define CX24116_DISEQC_ARG4_0 (4) /* unknown value=0 */
100#define CX24116_DISEQC_MSGLEN (5)
101#define CX24116_DISEQC_MSGOFS (6)
102
103/* DiSEqC burst */
104#define CX24116_DISEQC_MINI_A (0)
105#define CX24116_DISEQC_MINI_B (1)
106
Darron Broad490c8682008-09-13 19:42:16 -0300107/* DiSEqC tone burst */
108static int toneburst = 1;
109
Steven Toth0d467482008-09-04 01:14:43 -0300110enum cmds
111{
Darron Broad490c8682008-09-13 19:42:16 -0300112 CMD_SET_VCO = 0x10,
Steven Toth0d467482008-09-04 01:14:43 -0300113 CMD_TUNEREQUEST = 0x11,
Darron Broad490c8682008-09-13 19:42:16 -0300114 CMD_MPEGCONFIG = 0x13,
115 CMD_TUNERINIT = 0x14,
116 CMD_BANDWIDTH = 0x15,
117 CMD_GETAGC = 0x19,
118 CMD_LNBCONFIG = 0x20,
119 CMD_LNBSEND = 0x21, /* Formerly CMD_SEND_DISEQC */
Steven Toth0d467482008-09-04 01:14:43 -0300120 CMD_SET_TONEPRE = 0x22,
121 CMD_SET_TONE = 0x23,
Darron Broad490c8682008-09-13 19:42:16 -0300122 CMD_UPDFWVERS = 0x35,
123 CMD_TUNERSLEEP = 0x36,
124 CMD_AGCCONTROL = 0x3b, /* Unknown */
Steven Toth0d467482008-09-04 01:14:43 -0300125};
126
127/* The Demod/Tuner can't easily provide these, we cache them */
128struct cx24116_tuning
129{
130 u32 frequency;
131 u32 symbol_rate;
132 fe_spectral_inversion_t inversion;
133 fe_code_rate_t fec;
134
135 fe_modulation_t modulation;
Darron Broad490c8682008-09-13 19:42:16 -0300136 fe_pilot_t pilot;
137 fe_rolloff_t rolloff;
Steven Toth0d467482008-09-04 01:14:43 -0300138
139 /* Demod values */
140 u8 fec_val;
141 u8 fec_mask;
142 u8 inversion_val;
Darron Broad490c8682008-09-13 19:42:16 -0300143 u8 rolloff_val;
Steven Toth0d467482008-09-04 01:14:43 -0300144};
145
146/* Basic commands that are sent to the firmware */
147struct cx24116_cmd
148{
149 u8 len;
150 u8 args[CX24116_ARGLEN];
151};
152
153struct cx24116_state
154{
155 struct i2c_adapter* i2c;
156 const struct cx24116_config* config;
157
158 struct dvb_frontend frontend;
159
160 struct cx24116_tuning dcur;
161 struct cx24116_tuning dnxt;
162
163 u8 skip_fw_load;
164 u8 burst;
Darron Broad490c8682008-09-13 19:42:16 -0300165 struct cx24116_cmd dsec_cmd;
Steven Toth0d467482008-09-04 01:14:43 -0300166};
167
168static int cx24116_writereg(struct cx24116_state* state, int reg, int data)
169{
170 u8 buf[] = { reg, data };
171 struct i2c_msg msg = { .addr = state->config->demod_address,
172 .flags = 0, .buf = buf, .len = 2 };
173 int err;
174
175 if (debug>1)
176 printk("cx24116: %s: write reg 0x%02x, value 0x%02x\n",
177 __func__,reg, data);
178
179 if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
180 printk("%s: writereg error(err == %i, reg == 0x%02x,"
181 " value == 0x%02x)\n", __func__, err, reg, data);
182 return -EREMOTEIO;
183 }
184
185 return 0;
186}
187
188/* Bulk byte writes to a single I2C address, for 32k firmware load */
189static int cx24116_writeregN(struct cx24116_state* state, int reg, u8 *data, u16 len)
190{
191 int ret = -EREMOTEIO;
192 struct i2c_msg msg;
193 u8 *buf;
194
195 buf = kmalloc(len + 1, GFP_KERNEL);
196 if (buf == NULL) {
197 printk("Unable to kmalloc\n");
198 ret = -ENOMEM;
199 goto error;
200 }
201
202 *(buf) = reg;
203 memcpy(buf + 1, data, len);
204
205 msg.addr = state->config->demod_address;
206 msg.flags = 0;
207 msg.buf = buf;
208 msg.len = len + 1;
209
210 if (debug>1)
211 printk("cx24116: %s: write regN 0x%02x, len = %d\n",
212 __func__,reg, len);
213
214 if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1) {
215 printk("%s: writereg error(err == %i, reg == 0x%02x\n",
216 __func__, ret, reg);
217 ret = -EREMOTEIO;
218 }
219
220error:
221 kfree(buf);
222
223 return ret;
224}
225
226static int cx24116_readreg(struct cx24116_state* state, u8 reg)
227{
228 int ret;
229 u8 b0[] = { reg };
230 u8 b1[] = { 0 };
231 struct i2c_msg msg[] = {
232 { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
233 { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 }
234 };
235
236 ret = i2c_transfer(state->i2c, msg, 2);
237
238 if (ret != 2) {
239 printk("%s: reg=0x%x (error=%d)\n", __func__, reg, ret);
240 return ret;
241 }
242
243 if (debug>1)
244 printk("cx24116: read reg 0x%02x, value 0x%02x\n",reg, b1[0]);
245
246 return b1[0];
247}
248
249static int cx24116_set_inversion(struct cx24116_state* state, fe_spectral_inversion_t inversion)
250{
251 dprintk("%s(%d)\n", __func__, inversion);
252
253 switch (inversion) {
254 case INVERSION_OFF:
255 state->dnxt.inversion_val = 0x00;
256 break;
257 case INVERSION_ON:
258 state->dnxt.inversion_val = 0x04;
259 break;
260 case INVERSION_AUTO:
261 state->dnxt.inversion_val = 0x0C;
262 break;
263 default:
264 return -EINVAL;
265 }
266
267 state->dnxt.inversion = inversion;
268
269 return 0;
270}
271
Darron Broad490c8682008-09-13 19:42:16 -0300272/*
273 * modfec (modulation and FEC)
274 * ===========================
275 *
276 * MOD FEC mask/val standard
277 * ---- -------- ----------- --------
278 * QPSK FEC_1_2 0x02 0x02+X DVB-S
279 * QPSK FEC_2_3 0x04 0x02+X DVB-S
280 * QPSK FEC_3_4 0x08 0x02+X DVB-S
281 * QPSK FEC_4_5 0x10 0x02+X DVB-S (?)
282 * QPSK FEC_5_6 0x20 0x02+X DVB-S
283 * QPSK FEC_6_7 0x40 0x02+X DVB-S
284 * QPSK FEC_7_8 0x80 0x02+X DVB-S
285 * QPSK FEC_8_9 0x01 0x02+X DVB-S (?) (NOT SUPPORTED?)
286 * QPSK AUTO 0xff 0x02+X DVB-S
287 *
288 * For DVB-S high byte probably represents FEC
289 * and low byte selects the modulator. The high
290 * byte is search range mask. Bit 5 may turn
291 * on DVB-S and remaining bits represent some
292 * kind of calibration (how/what i do not know).
293 *
294 * Eg.(2/3) szap "Zone Horror"
295 *
296 * mask/val = 0x04, 0x20
297 * status 1f | signal c3c0 | snr a333 | ber 00000098 | unc 00000000 | FE_HAS_LOCK
298 *
299 * mask/val = 0x04, 0x30
300 * status 1f | signal c3c0 | snr a333 | ber 00000000 | unc 00000000 | FE_HAS_LOCK
301 *
302 * After tuning FECSTATUS contains actual FEC
303 * in use numbered 1 through to 8 for 1/2 .. 2/3 etc
304 *
305 * NBC=NOT/NON BACKWARD COMPATIBLE WITH DVB-S (DVB-S2 only)
306 *
307 * NBC-QPSK FEC_1_2 0x00, 0x04 DVB-S2
308 * NBC-QPSK FEC_3_5 0x00, 0x05 DVB-S2
309 * NBC-QPSK FEC_2_3 0x00, 0x06 DVB-S2
310 * NBC-QPSK FEC_3_4 0x00, 0x07 DVB-S2
311 * NBC-QPSK FEC_4_5 0x00, 0x08 DVB-S2
312 * NBC-QPSK FEC_5_6 0x00, 0x09 DVB-S2
313 * NBC-QPSK FEC_8_9 0x00, 0x0a DVB-S2
314 * NBC-QPSK FEC_9_10 0x00, 0x0b DVB-S2
315 *
316 * NBC-8PSK FEC_3_5 0x00, 0x0c DVB-S2
317 * NBC-8PSK FEC_2_3 0x00, 0x0d DVB-S2
318 * NBC-8PSK FEC_3_4 0x00, 0x0e DVB-S2
319 * NBC-8PSK FEC_5_6 0x00, 0x0f DVB-S2
320 * NBC-8PSK FEC_8_9 0x00, 0x10 DVB-S2
321 * NBC-8PSK FEC_9_10 0x00, 0x11 DVB-S2
322 *
323 * For DVB-S2 low bytes selects both modulator
324 * and FEC. High byte is meaningless here. To
325 * set pilot, bit 6 (0x40) is set. When inspecting
326 * FECSTATUS bit 7 (0x80) represents the pilot
327 * selection whilst not tuned. When tuned, actual FEC
328 * in use is found in FECSTATUS as per above. Pilot
329 * value is reset.
330 */
331
Steven Toth0d467482008-09-04 01:14:43 -0300332/* A table of modulation, fec and configuration bytes for the demod.
333 * Not all S2 mmodulation schemes are support and not all rates with
334 * a scheme are support. Especially, no auto detect when in S2 mode.
335 */
336struct cx24116_modfec {
337 fe_modulation_t modulation;
338 fe_code_rate_t fec;
339 u8 mask; /* In DVBS mode this is used to autodetect */
340 u8 val; /* Passed to the firmware to indicate mode selection */
341} CX24116_MODFEC_MODES[] = {
342 /* QPSK. For unknown rates we set hardware to auto detect 0xfe 0x30 */
Darron Broad490c8682008-09-13 19:42:16 -0300343
344 /*mod fec mask val */
Steven Toth0d467482008-09-04 01:14:43 -0300345 { QPSK, FEC_NONE, 0xfe, 0x30 },
Darron Broad490c8682008-09-13 19:42:16 -0300346 { QPSK, FEC_1_2, 0x02, 0x2e }, /* 00000010 00101110 */
347 { QPSK, FEC_2_3, 0x04, 0x2f }, /* 00000100 00101111 */
348 { QPSK, FEC_3_4, 0x08, 0x30 }, /* 00001000 00110000 */
349 { QPSK, FEC_4_5, 0xfe, 0x30 }, /* 000?0000 ? */
350 { QPSK, FEC_5_6, 0x20, 0x31 }, /* 00100000 00110001 */
351 { QPSK, FEC_6_7, 0xfe, 0x30 }, /* 0?000000 ? */
352 { QPSK, FEC_7_8, 0x80, 0x32 }, /* 10000000 00110010 */
353 { QPSK, FEC_8_9, 0xfe, 0x30 }, /* 0000000? ? */
Steven Toth0d467482008-09-04 01:14:43 -0300354 { QPSK, FEC_AUTO, 0xfe, 0x30 },
355 /* NBC-QPSK */
356 { NBC_QPSK, FEC_1_2, 0x00, 0x04 },
357 { NBC_QPSK, FEC_3_5, 0x00, 0x05 },
358 { NBC_QPSK, FEC_2_3, 0x00, 0x06 },
359 { NBC_QPSK, FEC_3_4, 0x00, 0x07 },
360 { NBC_QPSK, FEC_4_5, 0x00, 0x08 },
361 { NBC_QPSK, FEC_5_6, 0x00, 0x09 },
362 { NBC_QPSK, FEC_8_9, 0x00, 0x0a },
363 { NBC_QPSK, FEC_9_10, 0x00, 0x0b },
364 /* 8PSK */
365 { _8PSK, FEC_3_5, 0x00, 0x0c },
366 { _8PSK, FEC_2_3, 0x00, 0x0d },
367 { _8PSK, FEC_3_4, 0x00, 0x0e },
368 { _8PSK, FEC_5_6, 0x00, 0x0f },
Darron Broad490c8682008-09-13 19:42:16 -0300369 { _8PSK, FEC_8_9, 0x00, 0x10 },
Steven Toth0d467482008-09-04 01:14:43 -0300370 { _8PSK, FEC_9_10, 0x00, 0x11 },
Darron Broad490c8682008-09-13 19:42:16 -0300371 /*
372 * `val' can be found in the FECSTATUS register when tuning.
373 * FECSTATUS will give the actual FEC in use if tuning was successful.
374 */
Steven Toth0d467482008-09-04 01:14:43 -0300375};
376
377static int cx24116_lookup_fecmod(struct cx24116_state* state,
378 fe_modulation_t m, fe_code_rate_t f)
379{
380 int i, ret = -EOPNOTSUPP;
381
Darron Broad490c8682008-09-13 19:42:16 -0300382 dprintk("%s(0x%02x,0x%02x)\n", __func__, m, f);
383
Steven Toth0d467482008-09-04 01:14:43 -0300384 for(i=0 ; i < sizeof(CX24116_MODFEC_MODES) / sizeof(struct cx24116_modfec) ; i++)
385 {
386 if( (m == CX24116_MODFEC_MODES[i].modulation) &&
387 (f == CX24116_MODFEC_MODES[i].fec) )
388 {
389 ret = i;
390 break;
391 }
392 }
393
394 return ret;
395}
396
397static int cx24116_set_fec(struct cx24116_state* state, fe_modulation_t mod, fe_code_rate_t fec)
398{
399 int ret = 0;
Darron Broad490c8682008-09-13 19:42:16 -0300400
401 dprintk("%s(0x%02x,0x%02x)\n", __func__, mod, fec);
Steven Toth0d467482008-09-04 01:14:43 -0300402
403 ret = cx24116_lookup_fecmod(state, mod, fec);
404
405 if(ret < 0)
406 return ret;
407
Darron Broad490c8682008-09-13 19:42:16 -0300408 state->dnxt.fec = fec;
Steven Toth0d467482008-09-04 01:14:43 -0300409 state->dnxt.fec_val = CX24116_MODFEC_MODES[ret].val;
410 state->dnxt.fec_mask = CX24116_MODFEC_MODES[ret].mask;
Darron Broad490c8682008-09-13 19:42:16 -0300411 dprintk("%s() mask/val = 0x%02x/0x%02x\n", __func__,
412 state->dnxt.fec_mask, state->dnxt.fec_val);
Steven Toth0d467482008-09-04 01:14:43 -0300413
414 return 0;
415}
416
417static int cx24116_set_symbolrate(struct cx24116_state* state, u32 rate)
418{
Darron Broad490c8682008-09-13 19:42:16 -0300419 dprintk("%s(%d)\n", __func__, rate);
Steven Toth0d467482008-09-04 01:14:43 -0300420
421 /* check if symbol rate is within limits */
Darron Broad490c8682008-09-13 19:42:16 -0300422 if ((rate > state->frontend.ops.info.symbol_rate_max) ||
423 (rate < state->frontend.ops.info.symbol_rate_min)) {
424 dprintk("%s() unsupported symbol_rate = %d\n", __func__, rate);
425 return -EOPNOTSUPP;
426 }
Steven Toth0d467482008-09-04 01:14:43 -0300427
Darron Broad490c8682008-09-13 19:42:16 -0300428 state->dnxt.symbol_rate = rate;
429 dprintk("%s() symbol_rate = %d\n", __func__, rate);
430
431 return 0;
Steven Toth0d467482008-09-04 01:14:43 -0300432}
433
434static int cx24116_load_firmware (struct dvb_frontend* fe, const struct firmware *fw);
435
436static int cx24116_firmware_ondemand(struct dvb_frontend* fe)
437{
438 struct cx24116_state *state = fe->demodulator_priv;
439 const struct firmware *fw;
440 int ret = 0;
441
442 dprintk("%s()\n",__func__);
443
444 if (cx24116_readreg(state, 0x20) > 0)
445 {
446
447 if (state->skip_fw_load)
448 return 0;
449
450 /* Load firmware */
451 /* request the firmware, this will block until someone uploads it */
452 printk("%s: Waiting for firmware upload (%s)...\n", __func__, CX24116_DEFAULT_FIRMWARE);
453 ret = request_firmware(&fw, CX24116_DEFAULT_FIRMWARE, &state->i2c->dev);
454 printk("%s: Waiting for firmware upload(2)...\n", __func__);
455 if (ret) {
456 printk("%s: No firmware uploaded (timeout or file not found?)\n", __func__);
457 return ret;
458 }
459
460 /* Make sure we don't recurse back through here during loading */
461 state->skip_fw_load = 1;
462
463 ret = cx24116_load_firmware(fe, fw);
464 if (ret)
465 printk("%s: Writing firmware to device failed\n", __func__);
466
467 release_firmware(fw);
468
469 printk("%s: Firmware upload %s\n", __func__, ret == 0 ? "complete" : "failed");
470
471 /* Ensure firmware is always loaded if required */
472 state->skip_fw_load = 0;
473 }
474
475 return ret;
476}
477
478/* Take a basic firmware command structure, format it and forward it for processing */
479static int cx24116_cmd_execute(struct dvb_frontend* fe, struct cx24116_cmd *cmd)
480{
481 struct cx24116_state *state = fe->demodulator_priv;
482 int i, ret;
483
484 dprintk("%s()\n", __func__);
485
486 /* Load the firmware if required */
487 if ( (ret = cx24116_firmware_ondemand(fe)) != 0)
488 {
489 printk("%s(): Unable initialise the firmware\n", __func__);
490 return ret;
491 }
492
493 /* Write the command */
494 for(i = 0; i < cmd->len ; i++)
495 {
496 dprintk("%s: 0x%02x == 0x%02x\n", __func__, i, cmd->args[i]);
497 cx24116_writereg(state, i, cmd->args[i]);
498 }
499
500 /* Start execution and wait for cmd to terminate */
Darron Broad490c8682008-09-13 19:42:16 -0300501 cx24116_writereg(state, CX24116_REG_EXECUTE, 0x01);
502 while( cx24116_readreg(state, CX24116_REG_EXECUTE) )
Steven Toth0d467482008-09-04 01:14:43 -0300503 {
504 msleep(10);
505 if(i++ > 64)
506 {
507 /* Avoid looping forever if the firmware does no respond */
508 printk("%s() Firmware not responding\n", __func__);
509 return -EREMOTEIO;
510 }
511 }
512 return 0;
513}
514
515static int cx24116_load_firmware (struct dvb_frontend* fe, const struct firmware *fw)
516{
517 struct cx24116_state* state = fe->demodulator_priv;
518 struct cx24116_cmd cmd;
Darron Broad490c8682008-09-13 19:42:16 -0300519 int i, ret;
520 unsigned char vers[4];
Steven Toth0d467482008-09-04 01:14:43 -0300521
522 dprintk("%s\n", __func__);
523 dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n"
524 ,fw->size
525 ,fw->data[0]
526 ,fw->data[1]
527 ,fw->data[ fw->size-2 ]
528 ,fw->data[ fw->size-1 ]
529 );
530
531 /* Toggle 88x SRST pin to reset demod */
532 if (state->config->reset_device)
533 state->config->reset_device(fe);
534
535 /* Begin the firmware load process */
536 /* Prepare the demod, load the firmware, cleanup after load */
Steven Toth0d467482008-09-04 01:14:43 -0300537
Darron Broad490c8682008-09-13 19:42:16 -0300538 /* Init PLL */
539 cx24116_writereg(state, 0xE5, 0x00);
540 cx24116_writereg(state, 0xF1, 0x08);
541 cx24116_writereg(state, 0xF2, 0x13);
542
543 /* Start PLL */
544 cx24116_writereg(state, 0xe0, 0x03);
545 cx24116_writereg(state, 0xe0, 0x00);
546
547 /* Unknown */
548 cx24116_writereg(state, CX24116_REG_CLKDIV, 0x46);
549 cx24116_writereg(state, CX24116_REG_RATEDIV, 0x00);
550
551 /* Unknown */
Steven Toth0d467482008-09-04 01:14:43 -0300552 cx24116_writereg(state, 0xF0, 0x03);
553 cx24116_writereg(state, 0xF4, 0x81);
554 cx24116_writereg(state, 0xF5, 0x00);
555 cx24116_writereg(state, 0xF6, 0x00);
556
557 /* write the entire firmware as one transaction */
558 cx24116_writeregN(state, 0xF7, fw->data, fw->size);
559
560 cx24116_writereg(state, 0xF4, 0x10);
561 cx24116_writereg(state, 0xF0, 0x00);
562 cx24116_writereg(state, 0xF8, 0x06);
563
Darron Broad490c8682008-09-13 19:42:16 -0300564 /* Firmware CMD 10: VCO config */
565 cmd.args[0x00] = CMD_SET_VCO;
Steven Toth0d467482008-09-04 01:14:43 -0300566 cmd.args[0x01] = 0x05;
567 cmd.args[0x02] = 0xdc;
568 cmd.args[0x03] = 0xda;
569 cmd.args[0x04] = 0xae;
570 cmd.args[0x05] = 0xaa;
571 cmd.args[0x06] = 0x04;
572 cmd.args[0x07] = 0x9d;
573 cmd.args[0x08] = 0xfc;
574 cmd.args[0x09] = 0x06;
575 cmd.len= 0x0a;
576 ret = cx24116_cmd_execute(fe, &cmd);
577 if (ret != 0)
578 return ret;
579
Darron Broad490c8682008-09-13 19:42:16 -0300580 cx24116_writereg(state, CX24116_REG_SSTATUS, 0x00);
Steven Toth0d467482008-09-04 01:14:43 -0300581
Darron Broad490c8682008-09-13 19:42:16 -0300582 /* Firmware CMD 14: Tuner config */
583 cmd.args[0x00] = CMD_TUNERINIT;
Steven Toth0d467482008-09-04 01:14:43 -0300584 cmd.args[0x01] = 0x00;
585 cmd.args[0x02] = 0x00;
586 cmd.len= 0x03;
587 ret = cx24116_cmd_execute(fe, &cmd);
588 if (ret != 0)
589 return ret;
590
591 cx24116_writereg(state, 0xe5, 0x00);
592
Darron Broad490c8682008-09-13 19:42:16 -0300593 /* Firmware CMD 13: MPEG config */
594 cmd.args[0x00] = CMD_MPEGCONFIG;
Steven Toth0d467482008-09-04 01:14:43 -0300595 cmd.args[0x01] = 0x01;
596 cmd.args[0x02] = 0x75;
597 cmd.args[0x03] = 0x00;
Igor M. Liplianincc8c4f32008-09-09 13:57:47 -0300598 if (state->config->mpg_clk_pos_pol)
599 cmd.args[0x04] = state->config->mpg_clk_pos_pol;
600 else
601 cmd.args[0x04] = 0x02;
Steven Toth0d467482008-09-04 01:14:43 -0300602 cmd.args[0x05] = 0x00;
603 cmd.len= 0x06;
604 ret = cx24116_cmd_execute(fe, &cmd);
605 if (ret != 0)
606 return ret;
607
Darron Broad490c8682008-09-13 19:42:16 -0300608 /* Firmware CMD 35: Get firmware version */
609 cmd.args[0x00] = CMD_UPDFWVERS;
610 cmd.len= 0x02;
611 for(i=0; i<4; i++) {
612 cmd.args[0x01] = i;
613 ret = cx24116_cmd_execute(fe, &cmd);
614 if (ret != 0)
615 return ret;
616 vers[i]= cx24116_readreg(state, CX24116_REG_MAILBOX);
617 }
618 printk("%s: FW version %i.%i.%i.%i\n", __func__,
619 vers[0], vers[1], vers[2], vers[3]);
620
Steven Toth0d467482008-09-04 01:14:43 -0300621 return 0;
622}
623
624static int cx24116_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
625{
626 /* The isl6421 module will override this function in the fops. */
627 dprintk("%s() This should never appear if the isl6421 module is loaded correctly\n",__func__);
628
629 return -EOPNOTSUPP;
630}
631
632static int cx24116_read_status(struct dvb_frontend* fe, fe_status_t* status)
633{
634 struct cx24116_state *state = fe->demodulator_priv;
635
Darron Broad490c8682008-09-13 19:42:16 -0300636 int lock = cx24116_readreg(state, CX24116_REG_SSTATUS);
Steven Toth0d467482008-09-04 01:14:43 -0300637
638 dprintk("%s: status = 0x%02x\n", __func__, lock);
639
640 *status = 0;
641
Darron Broad490c8682008-09-13 19:42:16 -0300642 if (lock & CX24116_HAS_SIGNAL)
Steven Toth0d467482008-09-04 01:14:43 -0300643 *status |= FE_HAS_SIGNAL;
Darron Broad490c8682008-09-13 19:42:16 -0300644 if (lock & CX24116_HAS_CARRIER)
Steven Toth0d467482008-09-04 01:14:43 -0300645 *status |= FE_HAS_CARRIER;
Darron Broad490c8682008-09-13 19:42:16 -0300646 if (lock & CX24116_HAS_VITERBI)
Steven Toth0d467482008-09-04 01:14:43 -0300647 *status |= FE_HAS_VITERBI;
Darron Broad490c8682008-09-13 19:42:16 -0300648 if (lock & CX24116_HAS_SYNCLOCK)
Steven Toth0d467482008-09-04 01:14:43 -0300649 *status |= FE_HAS_SYNC | FE_HAS_LOCK;
650
651 return 0;
652}
653
Steven Toth0d467482008-09-04 01:14:43 -0300654static int cx24116_read_ber(struct dvb_frontend* fe, u32* ber)
655{
Darron Broad490c8682008-09-13 19:42:16 -0300656 struct cx24116_state *state = fe->demodulator_priv;
657
Steven Toth0d467482008-09-04 01:14:43 -0300658 dprintk("%s()\n", __func__);
Darron Broad490c8682008-09-13 19:42:16 -0300659
660 *ber = ( cx24116_readreg(state, CX24116_REG_BER24) << 24 ) |
661 ( cx24116_readreg(state, CX24116_REG_BER16) << 16 ) |
662 ( cx24116_readreg(state, CX24116_REG_BER8 ) << 8 ) |
663 cx24116_readreg(state, CX24116_REG_BER0 );
Steven Toth0d467482008-09-04 01:14:43 -0300664
665 return 0;
666}
667
Darron Broad490c8682008-09-13 19:42:16 -0300668/* TODO Determine function and scale appropriately */
Steven Toth0d467482008-09-04 01:14:43 -0300669static int cx24116_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
670{
671 struct cx24116_state *state = fe->demodulator_priv;
Darron Broad490c8682008-09-13 19:42:16 -0300672 struct cx24116_cmd cmd;
673 int ret;
674 u16 sig_reading;
675
676 dprintk("%s()\n", __func__);
677
678 /* Firmware CMD 19: Get AGC */
679 cmd.args[0x00] = CMD_GETAGC;
680 cmd.len= 0x01;
681 ret = cx24116_cmd_execute(fe, &cmd);
682 if (ret != 0)
683 return ret;
684
685 sig_reading = ( cx24116_readreg(state, CX24116_REG_SSTATUS) & CX24116_SIGNAL_MASK ) |
686 ( cx24116_readreg(state, CX24116_REG_SIGNAL) << 6 );
687 *signal_strength= 0 - sig_reading;
688
689 dprintk("%s: raw / cooked = 0x%04x / 0x%04x\n", __func__, sig_reading, *signal_strength);
690
691 return 0;
692}
693
694/* SNR (0..100)% = (sig & 0xf0) * 10 + (sig & 0x0f) * 10 / 16 */
695static int cx24116_read_snr(struct dvb_frontend* fe, u16* snr)
696{
697 struct cx24116_state *state = fe->demodulator_priv;
698 u8 snr_reading;
699 static const u32 snr_tab[] = { /* 10 x Table (rounded up) */
700 0x00000,0x0199A,0x03333,0x04ccD,0x06667,
701 0x08000,0x0999A,0x0b333,0x0cccD,0x0e667,
Steven Toth0d467482008-09-04 01:14:43 -0300702 0x10000,0x1199A,0x13333,0x14ccD,0x16667,0x18000 };
703
704 dprintk("%s()\n", __func__);
705
Darron Broad490c8682008-09-13 19:42:16 -0300706 snr_reading = cx24116_readreg(state, CX24116_REG_QUALITY);
Steven Toth0d467482008-09-04 01:14:43 -0300707
Darron Broad490c8682008-09-13 19:42:16 -0300708 if(snr_reading >= 0xa0 /* 100% */)
709 *snr = 0xffff;
Steven Toth0d467482008-09-04 01:14:43 -0300710 else
Darron Broad490c8682008-09-13 19:42:16 -0300711 *snr = snr_tab [ ( snr_reading & 0xf0 ) >> 4 ] +
712 ( snr_tab [ ( snr_reading & 0x0f ) ] >> 4 );
Steven Toth0d467482008-09-04 01:14:43 -0300713
Darron Broad490c8682008-09-13 19:42:16 -0300714 dprintk("%s: raw / cooked = 0x%02x / 0x%04x\n", __func__,
715 snr_reading, *snr);
Steven Toth0d467482008-09-04 01:14:43 -0300716
717 return 0;
718}
719
Steven Toth0d467482008-09-04 01:14:43 -0300720static int cx24116_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
721{
Darron Broad490c8682008-09-13 19:42:16 -0300722 struct cx24116_state *state = fe->demodulator_priv;
723
Steven Toth0d467482008-09-04 01:14:43 -0300724 dprintk("%s()\n", __func__);
Darron Broad490c8682008-09-13 19:42:16 -0300725
726 *ucblocks = ( cx24116_readreg(state, CX24116_REG_UCB8) << 8 ) |
727 cx24116_readreg(state, CX24116_REG_UCB0);
Steven Toth0d467482008-09-04 01:14:43 -0300728
729 return 0;
730}
731
732/* Overwrite the current tuning params, we are about to tune */
733static void cx24116_clone_params(struct dvb_frontend* fe)
734{
735 struct cx24116_state *state = fe->demodulator_priv;
736 memcpy(&state->dcur, &state->dnxt, sizeof(state->dcur));
737}
738
Darron Broad490c8682008-09-13 19:42:16 -0300739/* Wait for LNB */
740static int cx24116_wait_for_lnb(struct dvb_frontend* fe)
741{
742 struct cx24116_state *state = fe->demodulator_priv;
743 int i;
744
745 dprintk("%s() qstatus = 0x%02x\n", __func__,
746 cx24116_readreg(state, CX24116_REG_QSTATUS));
747
748 /* Wait for up to 300 ms */
749 for(i = 0; i < 30 ; i++) {
750 if (cx24116_readreg(state, CX24116_REG_QSTATUS) & 0x20)
751 return 0;
752 msleep(10);
753 }
754
755 dprintk("%s(): LNB not ready\n", __func__);
756
757 return -ETIMEDOUT; /* -EBUSY ? */
758}
759
Steven Toth0d467482008-09-04 01:14:43 -0300760static int cx24116_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
761{
762 struct cx24116_cmd cmd;
763 int ret;
764
765 dprintk("%s(%d)\n", __func__, tone);
766 if ( (tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF) ) {
767 printk("%s: Invalid, tone=%d\n", __func__, tone);
768 return -EINVAL;
769 }
770
Darron Broad490c8682008-09-13 19:42:16 -0300771 /* Wait for LNB ready */
772 ret = cx24116_wait_for_lnb(fe);
773 if(ret != 0)
774 return ret;
775
776 /* Min delay time after DiSEqC send */
777 msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */
778
Steven Toth0d467482008-09-04 01:14:43 -0300779 /* This is always done before the tone is set */
780 cmd.args[0x00] = CMD_SET_TONEPRE;
781 cmd.args[0x01] = 0x00;
782 cmd.len= 0x02;
783 ret = cx24116_cmd_execute(fe, &cmd);
784 if (ret != 0)
785 return ret;
786
787 /* Now we set the tone */
788 cmd.args[0x00] = CMD_SET_TONE;
789 cmd.args[0x01] = 0x00;
790 cmd.args[0x02] = 0x00;
791
792 switch (tone) {
793 case SEC_TONE_ON:
794 dprintk("%s: setting tone on\n", __func__);
795 cmd.args[0x03] = 0x01;
796 break;
797 case SEC_TONE_OFF:
798 dprintk("%s: setting tone off\n",__func__);
799 cmd.args[0x03] = 0x00;
800 break;
801 }
802 cmd.len= 0x04;
803
Darron Broad490c8682008-09-13 19:42:16 -0300804 /* Min delay time before DiSEqC send */
805 msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */
806
Steven Toth0d467482008-09-04 01:14:43 -0300807 return cx24116_cmd_execute(fe, &cmd);
808}
809
810/* Initialise DiSEqC */
811static int cx24116_diseqc_init(struct dvb_frontend* fe)
812{
813 struct cx24116_state *state = fe->demodulator_priv;
Darron Broad490c8682008-09-13 19:42:16 -0300814 struct cx24116_cmd cmd;
815 int ret;
Steven Toth0d467482008-09-04 01:14:43 -0300816
Darron Broad490c8682008-09-13 19:42:16 -0300817 /* Firmware CMD 20: LNB/DiSEqC config */
818 cmd.args[0x00] = CMD_LNBCONFIG;
819 cmd.args[0x01] = 0x00;
820 cmd.args[0x02] = 0x10;
821 cmd.args[0x03] = 0x00;
822 cmd.args[0x04] = 0x8f;
823 cmd.args[0x05] = 0x28;
824 cmd.args[0x06] = (toneburst == CX24116_DISEQC_TONEOFF) ? 0x00 : 0x01;
825 cmd.args[0x07] = 0x01;
826 cmd.len= 0x08;
827 ret = cx24116_cmd_execute(fe, &cmd);
828 if (ret != 0)
829 return ret;
830
831 /* Prepare a DiSEqC command */
832 state->dsec_cmd.args[0x00] = CMD_LNBSEND;
833
834 /* DiSEqC burst */
835 state->dsec_cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_A;
836
837 /* Unknown */
838 state->dsec_cmd.args[CX24116_DISEQC_ARG2_2] = 0x02;
839 state->dsec_cmd.args[CX24116_DISEQC_ARG3_0] = 0x00;
840 state->dsec_cmd.args[CX24116_DISEQC_ARG4_0] = 0x00; /* Continuation flag? */
841
842 /* DiSEqC message length */
843 state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = 0x00;
844
845 /* Command length */
846 state->dsec_cmd.len= CX24116_DISEQC_MSGOFS;
Steven Toth0d467482008-09-04 01:14:43 -0300847
848 return 0;
849}
850
851/* Send DiSEqC message with derived burst (hack) || previous burst */
852static int cx24116_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *d)
853{
854 struct cx24116_state *state = fe->demodulator_priv;
Steven Toth0d467482008-09-04 01:14:43 -0300855 int i, ret;
856
857 /* Dump DiSEqC message */
858 if (debug) {
859 printk("cx24116: %s(", __func__);
860 for(i = 0 ; i < d->msg_len ;) {
861 printk("0x%02x", d->msg[i]);
862 if(++i < d->msg_len)
863 printk(", ");
Darron Broad490c8682008-09-13 19:42:16 -0300864 }
865 printk(") toneburst=%d\n", toneburst);
Steven Toth0d467482008-09-04 01:14:43 -0300866 }
867
Darron Broad490c8682008-09-13 19:42:16 -0300868 /* Validate length */
Steven Toth0d467482008-09-04 01:14:43 -0300869 if(d->msg_len > (CX24116_ARGLEN - CX24116_DISEQC_MSGOFS))
870 return -EINVAL;
871
Steven Toth0d467482008-09-04 01:14:43 -0300872 /* DiSEqC message */
873 for (i = 0; i < d->msg_len; i++)
Darron Broad490c8682008-09-13 19:42:16 -0300874 state->dsec_cmd.args[CX24116_DISEQC_MSGOFS + i] = d->msg[i];
Steven Toth0d467482008-09-04 01:14:43 -0300875
Darron Broad490c8682008-09-13 19:42:16 -0300876 /* DiSEqC message length */
877 state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = d->msg_len;
Steven Toth0d467482008-09-04 01:14:43 -0300878
Darron Broad490c8682008-09-13 19:42:16 -0300879 /* Command length */
880 state->dsec_cmd.len= CX24116_DISEQC_MSGOFS + state->dsec_cmd.args[CX24116_DISEQC_MSGLEN];
Steven Toth0d467482008-09-04 01:14:43 -0300881
Darron Broad490c8682008-09-13 19:42:16 -0300882 /* DiSEqC toneburst */
883 if(toneburst == CX24116_DISEQC_MESGCACHE)
884 /* Message is cached */
885 return 0;
Steven Toth0d467482008-09-04 01:14:43 -0300886
Darron Broad490c8682008-09-13 19:42:16 -0300887 else if(toneburst == CX24116_DISEQC_TONEOFF)
888 /* Message is sent without burst */
889 state->dsec_cmd.args[CX24116_DISEQC_BURST] = 0;
890
891 else if(toneburst == CX24116_DISEQC_TONECACHE) {
892 /*
893 * Message is sent with derived else cached burst
894 *
895 * WRITE PORT GROUP COMMAND 38
896 *
897 * 0/A/A: E0 10 38 F0..F3
898 * 1/B/B: E0 10 38 F4..F7
899 * 2/C/A: E0 10 38 F8..FB
900 * 3/D/B: E0 10 38 FC..FF
901 *
Darron Broad7396d3e2008-09-14 10:45:58 -0300902 * databyte[3]= 8421:8421
Darron Broad490c8682008-09-13 19:42:16 -0300903 * ABCD:WXYZ
904 * CLR :SET
905 *
906 * WX= PORT SELECT 0..3 (X=TONEBURST)
907 * Y = VOLTAGE (0=13V, 1=18V)
908 * Z = BAND (0=LOW, 1=HIGH(22K))
909 */
910 if(d->msg_len >= 4 && d->msg[2] == 0x38)
911 state->dsec_cmd.args[CX24116_DISEQC_BURST] = ((d->msg[3] & 4) >> 2);
912 if(debug)
913 dprintk("%s burst=%d\n", __func__, state->dsec_cmd.args[CX24116_DISEQC_BURST]);
914 }
915
916 /* Wait for LNB ready */
917 ret = cx24116_wait_for_lnb(fe);
918 if(ret != 0)
919 return ret;
920
921 /* Wait for voltage/min repeat delay */
922 msleep(100);
923
924 /* Command */
925 ret = cx24116_cmd_execute(fe, &state->dsec_cmd);
926 if(ret != 0)
927 return ret;
928 /*
929 * Wait for send
Steven Toth0d467482008-09-04 01:14:43 -0300930 *
931 * Eutelsat spec:
Darron Broad490c8682008-09-13 19:42:16 -0300932 * >15ms delay + (XXX determine if FW does this, see set_tone)
933 * 13.5ms per byte +
934 * >15ms delay +
935 * 12.5ms burst +
936 * >15ms delay (XXX determine if FW does this, see set_tone)
Steven Toth0d467482008-09-04 01:14:43 -0300937 */
Darron Broad490c8682008-09-13 19:42:16 -0300938 msleep( (state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) + ((toneburst == CX24116_DISEQC_TONEOFF) ? 30 : 60) );
Steven Toth0d467482008-09-04 01:14:43 -0300939
Darron Broad490c8682008-09-13 19:42:16 -0300940 return 0;
Steven Toth0d467482008-09-04 01:14:43 -0300941}
942
943/* Send DiSEqC burst */
944static int cx24116_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst)
945{
946 struct cx24116_state *state = fe->demodulator_priv;
Steven Toth0d467482008-09-04 01:14:43 -0300947 int ret;
948
Darron Broad490c8682008-09-13 19:42:16 -0300949 dprintk("%s(%d) toneburst=%d\n",__func__, burst, toneburst);
Steven Toth0d467482008-09-04 01:14:43 -0300950
Darron Broad490c8682008-09-13 19:42:16 -0300951 /* DiSEqC burst */
Steven Toth0d467482008-09-04 01:14:43 -0300952 if (burst == SEC_MINI_A)
Darron Broad490c8682008-09-13 19:42:16 -0300953 state->dsec_cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_A;
Steven Toth0d467482008-09-04 01:14:43 -0300954 else if(burst == SEC_MINI_B)
Darron Broad490c8682008-09-13 19:42:16 -0300955 state->dsec_cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_B;
Steven Toth0d467482008-09-04 01:14:43 -0300956 else
957 return -EINVAL;
958
Darron Broad490c8682008-09-13 19:42:16 -0300959 /* DiSEqC toneburst */
960 if(toneburst != CX24116_DISEQC_MESGCACHE)
961 /* Burst is cached */
962 return 0;
Steven Toth0d467482008-09-04 01:14:43 -0300963
Darron Broad490c8682008-09-13 19:42:16 -0300964 /* Burst is to be sent with cached message */
Steven Toth0d467482008-09-04 01:14:43 -0300965
Darron Broad490c8682008-09-13 19:42:16 -0300966 /* Wait for LNB ready */
967 ret = cx24116_wait_for_lnb(fe);
968 if(ret != 0)
969 return ret;
Steven Toth0d467482008-09-04 01:14:43 -0300970
Darron Broad490c8682008-09-13 19:42:16 -0300971 /* Wait for voltage/min repeat delay */
972 msleep(100);
Steven Toth0d467482008-09-04 01:14:43 -0300973
Darron Broad490c8682008-09-13 19:42:16 -0300974 /* Command */
975 ret = cx24116_cmd_execute(fe, &state->dsec_cmd);
976 if(ret != 0)
977 return ret;
978
979 /*
980 * Wait for send
981 *
982 * Eutelsat spec:
983 * >15ms delay + (XXX determine if FW does this, see set_tone)
984 * 13.5ms per byte +
985 * >15ms delay +
986 * 12.5ms burst +
987 * >15ms delay (XXX determine if FW does this, see set_tone)
988 */
989 msleep( (state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) + 60 );
990
991 return 0;
Steven Toth0d467482008-09-04 01:14:43 -0300992}
993
994static void cx24116_release(struct dvb_frontend* fe)
995{
996 struct cx24116_state* state = fe->demodulator_priv;
997 dprintk("%s\n",__func__);
998 kfree(state);
999}
1000
1001static struct dvb_frontend_ops cx24116_ops;
1002
1003struct dvb_frontend* cx24116_attach(const struct cx24116_config* config,
1004 struct i2c_adapter* i2c)
1005{
1006 struct cx24116_state* state = NULL;
1007 int ret;
1008
1009 dprintk("%s\n",__func__);
1010
1011 /* allocate memory for the internal state */
1012 state = kmalloc(sizeof(struct cx24116_state), GFP_KERNEL);
1013 if (state == NULL) {
1014 printk("Unable to kmalloc\n");
Darron Broad7396d3e2008-09-14 10:45:58 -03001015 goto error1;
Steven Toth0d467482008-09-04 01:14:43 -03001016 }
1017
1018 /* setup the state */
1019 memset(state, 0, sizeof(struct cx24116_state));
1020
1021 state->config = config;
1022 state->i2c = i2c;
1023
1024 /* check if the demod is present */
1025 ret = (cx24116_readreg(state, 0xFF) << 8) | cx24116_readreg(state, 0xFE);
1026 if (ret != 0x0501) {
1027 printk("Invalid probe, probably not a CX24116 device\n");
Darron Broad7396d3e2008-09-14 10:45:58 -03001028 goto error2;
Steven Toth0d467482008-09-04 01:14:43 -03001029 }
1030
1031 /* create dvb_frontend */
1032 memcpy(&state->frontend.ops, &cx24116_ops, sizeof(struct dvb_frontend_ops));
1033 state->frontend.demodulator_priv = state;
1034 return &state->frontend;
1035
Darron Broad7396d3e2008-09-14 10:45:58 -03001036error2: kfree(state);
Darron Broad490c8682008-09-13 19:42:16 -03001037error1: return NULL;
Steven Toth0d467482008-09-04 01:14:43 -03001038}
Darron Broad490c8682008-09-13 19:42:16 -03001039/*
1040 * Initialise or wake up device
1041 *
1042 * Power config will reset and load initial firmware if required
1043 */
Steven Toth0d467482008-09-04 01:14:43 -03001044static int cx24116_initfe(struct dvb_frontend* fe)
1045{
Darron Broad490c8682008-09-13 19:42:16 -03001046 struct cx24116_state* state = fe->demodulator_priv;
1047 struct cx24116_cmd cmd;
1048 int ret;
1049
Steven Toth0d467482008-09-04 01:14:43 -03001050 dprintk("%s()\n",__func__);
1051
Darron Broad490c8682008-09-13 19:42:16 -03001052 /* Power on */
1053 cx24116_writereg(state, 0xe0, 0);
1054 cx24116_writereg(state, 0xe1, 0);
1055 cx24116_writereg(state, 0xea, 0);
1056
1057 /* Firmware CMD 36: Power config */
1058 cmd.args[0x00] = CMD_TUNERSLEEP;
1059 cmd.args[0x01] = 0;
1060 cmd.len= 0x02;
1061 ret = cx24116_cmd_execute(fe, &cmd);
1062 if(ret != 0)
1063 return ret;
1064
Steven Toth0d467482008-09-04 01:14:43 -03001065 return cx24116_diseqc_init(fe);
1066}
1067
Darron Broad490c8682008-09-13 19:42:16 -03001068/*
1069 * Put device to sleep
1070 */
1071static int cx24116_sleep(struct dvb_frontend* fe)
1072{
1073 struct cx24116_state* state = fe->demodulator_priv;
1074 struct cx24116_cmd cmd;
1075 int ret;
1076
1077 dprintk("%s()\n",__func__);
1078
1079 /* Firmware CMD 36: Power config */
1080 cmd.args[0x00] = CMD_TUNERSLEEP;
1081 cmd.args[0x01] = 1;
1082 cmd.len= 0x02;
1083 ret = cx24116_cmd_execute(fe, &cmd);
1084 if(ret != 0)
1085 return ret;
1086
1087 /* Power off (Shutdown clocks) */
1088 cx24116_writereg(state, 0xea, 0xff);
1089 cx24116_writereg(state, 0xe1, 1);
1090 cx24116_writereg(state, 0xe0, 1);
1091
1092 return 0;
1093}
1094
Steven Tothe7fee0f32008-09-11 10:23:01 -03001095static int cx24116_set_property(struct dvb_frontend *fe, struct dtv_property* tvp)
Steven Toth0d467482008-09-04 01:14:43 -03001096{
1097 dprintk("%s(..)\n", __func__);
1098 return 0;
1099}
1100
Steven Tothbfbf2da2008-09-12 01:37:37 -03001101static int cx24116_get_property(struct dvb_frontend *fe, struct dtv_property* tvp)
Steven Toth0d467482008-09-04 01:14:43 -03001102{
Steven Tothbfbf2da2008-09-12 01:37:37 -03001103 dprintk("%s(..)\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -03001104 return 0;
1105}
1106
1107/* dvb-core told us to tune, the tv property cache will be complete,
1108 * it's safe for is to pull values and use them for tuning purposes.
1109 */
1110static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
1111{
1112 struct cx24116_state *state = fe->demodulator_priv;
Steven Toth56f06802008-09-11 10:19:27 -03001113 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
Steven Toth0d467482008-09-04 01:14:43 -03001114 struct cx24116_cmd cmd;
1115 fe_status_t tunerstat;
Darron Broad490c8682008-09-13 19:42:16 -03001116 int i, status, ret, retune = 1;
Steven Toth0d467482008-09-04 01:14:43 -03001117
1118 dprintk("%s()\n",__func__);
1119
1120 state->dnxt.modulation = c->modulation;
1121 state->dnxt.frequency = c->frequency;
1122
Darron Broad490c8682008-09-13 19:42:16 -03001123 switch(c->delivery_system) {
1124 case SYS_DVBS:
1125 dprintk("%s: DVB-S delivery system selected\n",__func__);
1126 state->dnxt.pilot = PILOT_OFF;
Darron Broad7396d3e2008-09-14 10:45:58 -03001127 state->dnxt.rolloff_val = CX24116_ROLLOFF_035;
1128 state->dnxt.rolloff = c->rolloff;
Darron Broad490c8682008-09-13 19:42:16 -03001129 break;
1130 case SYS_DVBS2:
1131 dprintk("%s: DVB-S2 delivery system selected\n",__func__);
1132 if(c->pilot == PILOT_AUTO)
1133 retune++;
1134 state->dnxt.pilot = c->pilot;
1135 switch(c->rolloff) {
1136 case ROLLOFF_20:
1137 state->dnxt.rolloff_val= CX24116_ROLLOFF_020;
1138 break;
1139 case ROLLOFF_25:
1140 state->dnxt.rolloff_val= CX24116_ROLLOFF_025;
1141 break;
1142 case ROLLOFF_35:
1143 state->dnxt.rolloff_val= CX24116_ROLLOFF_035;
1144 break;
1145 case ROLLOFF_AUTO:
1146 return -EOPNOTSUPP;
1147 }
1148 state->dnxt.rolloff = c->rolloff;
1149 break;
1150 default:
1151 dprintk("%s: unsupported delivery system selected (%d)\n",
1152 __func__, c->delivery_system);
1153 return -EOPNOTSUPP;
1154 }
1155
Steven Toth0d467482008-09-04 01:14:43 -03001156 if ((ret = cx24116_set_inversion(state, c->inversion)) != 0)
1157 return ret;
1158
1159 if ((ret = cx24116_set_fec(state, c->modulation, c->fec_inner)) != 0)
1160 return ret;
1161
1162 if ((ret = cx24116_set_symbolrate(state, c->symbol_rate)) != 0)
1163 return ret;
1164
1165 /* discard the 'current' tuning parameters and prepare to tune */
1166 cx24116_clone_params(fe);
1167
Darron Broad490c8682008-09-13 19:42:16 -03001168 dprintk("%s: retune = %d\n", __func__, retune);
1169 dprintk("%s: rolloff = %d\n", __func__, state->dcur.rolloff);
1170 dprintk("%s: pilot = %d\n", __func__, state->dcur.pilot);
Steven Toth0d467482008-09-04 01:14:43 -03001171 dprintk("%s: frequency = %d\n", __func__, state->dcur.frequency);
1172 dprintk("%s: symbol_rate = %d\n", __func__, state->dcur.symbol_rate);
1173 dprintk("%s: FEC = %d (mask/val = 0x%02x/0x%02x)\n", __func__,
1174 state->dcur.fec, state->dcur.fec_mask, state->dcur.fec_val);
1175 dprintk("%s: Inversion = %d (val = 0x%02x)\n", __func__,
1176 state->dcur.inversion, state->dcur.inversion_val);
1177
Darron Broad490c8682008-09-13 19:42:16 -03001178 /* This is also done in advise/acquire on HVR4000 but not on LITE */
Steven Toth0d467482008-09-04 01:14:43 -03001179 if (state->config->set_ts_params)
1180 state->config->set_ts_params(fe, 0);
1181
Darron Broad490c8682008-09-13 19:42:16 -03001182 /* Set/Reset B/W */
1183 cmd.args[0x00] = CMD_BANDWIDTH;
1184 cmd.args[0x01] = 0x01;
1185 cmd.len= 0x02;
1186 ret = cx24116_cmd_execute(fe, &cmd);
1187 if (ret != 0)
1188 return ret;
Igor M. Liplianin3f8e51a2008-09-09 13:22:29 -03001189
Steven Toth0d467482008-09-04 01:14:43 -03001190 /* Prepare a tune request */
1191 cmd.args[0x00] = CMD_TUNEREQUEST;
1192
1193 /* Frequency */
1194 cmd.args[0x01] = (state->dcur.frequency & 0xff0000) >> 16;
1195 cmd.args[0x02] = (state->dcur.frequency & 0x00ff00) >> 8;
1196 cmd.args[0x03] = (state->dcur.frequency & 0x0000ff);
1197
1198 /* Symbol Rate */
1199 cmd.args[0x04] = ((state->dcur.symbol_rate / 1000) & 0xff00) >> 8;
1200 cmd.args[0x05] = ((state->dcur.symbol_rate / 1000) & 0x00ff);
1201
1202 /* Automatic Inversion */
1203 cmd.args[0x06] = state->dcur.inversion_val;
1204
1205 /* Modulation / FEC & Pilot Off */
1206 cmd.args[0x07] = state->dcur.fec_val;
1207
Darron Broad490c8682008-09-13 19:42:16 -03001208 if (state->dcur.pilot == PILOT_ON)
1209 cmd.args[0x07] |= CX24116_PILOT;
Steven Toth0d467482008-09-04 01:14:43 -03001210
1211 cmd.args[0x08] = CX24116_SEARCH_RANGE_KHZ >> 8;
1212 cmd.args[0x09] = CX24116_SEARCH_RANGE_KHZ & 0xff;
1213 cmd.args[0x0a] = 0x00;
1214 cmd.args[0x0b] = 0x00;
Darron Broad490c8682008-09-13 19:42:16 -03001215 cmd.args[0x0c] = state->dcur.rolloff_val;
Steven Toth0d467482008-09-04 01:14:43 -03001216 cmd.args[0x0d] = state->dcur.fec_mask;
Igor M. Liplianin3f8e51a2008-09-09 13:22:29 -03001217
Darron Broad490c8682008-09-13 19:42:16 -03001218 if (state->dcur.symbol_rate > 30000000) {
Igor M. Liplianin3f8e51a2008-09-09 13:22:29 -03001219 cmd.args[0x0e] = 0x04;
1220 cmd.args[0x0f] = 0x00;
1221 cmd.args[0x10] = 0x01;
1222 cmd.args[0x11] = 0x77;
1223 cmd.args[0x12] = 0x36;
Darron Broad490c8682008-09-13 19:42:16 -03001224 cx24116_writereg(state, CX24116_REG_CLKDIV, 0x44);
1225 cx24116_writereg(state, CX24116_REG_RATEDIV, 0x01);
Igor M. Liplianin3f8e51a2008-09-09 13:22:29 -03001226 } else {
1227 cmd.args[0x0e] = 0x06;
1228 cmd.args[0x0f] = 0x00;
1229 cmd.args[0x10] = 0x00;
1230 cmd.args[0x11] = 0xFA;
1231 cmd.args[0x12] = 0x24;
Darron Broad490c8682008-09-13 19:42:16 -03001232 cx24116_writereg(state, CX24116_REG_CLKDIV, 0x46);
1233 cx24116_writereg(state, CX24116_REG_RATEDIV, 0x00);
Igor M. Liplianin3f8e51a2008-09-09 13:22:29 -03001234 }
1235
Steven Toth0d467482008-09-04 01:14:43 -03001236 cmd.len= 0x13;
1237
1238 /* We need to support pilot and non-pilot tuning in the
1239 * driver automatically. This is a workaround for because
1240 * the demod does not support autodetect.
1241 */
1242 do {
Darron Broad490c8682008-09-13 19:42:16 -03001243 /* Reset status register */
1244 status = cx24116_readreg(state, CX24116_REG_SSTATUS) & CX24116_SIGNAL_MASK;
1245 cx24116_writereg(state, CX24116_REG_SSTATUS, status);
Steven Toth0d467482008-09-04 01:14:43 -03001246
1247 /* Tune */
1248 ret = cx24116_cmd_execute(fe, &cmd);
1249 if( ret != 0 )
1250 break;
1251
Darron Broad490c8682008-09-13 19:42:16 -03001252 /*
1253 * Wait for up to 500 ms before retrying
1254 *
1255 * If we are able to tune then generally it occurs within 100ms.
1256 * If it takes longer, try a different toneburst setting.
1257 */
1258 for(i = 0; i < 50 ; i++) {
1259 cx24116_read_status(fe, &tunerstat);
1260 status = tunerstat & (FE_HAS_SIGNAL | FE_HAS_SYNC);
1261 if(status == (FE_HAS_SIGNAL | FE_HAS_SYNC)) {
1262 dprintk("%s: Tuned\n",__func__);
1263 goto tuned;
1264 }
1265 msleep(10);
Steven Toth0d467482008-09-04 01:14:43 -03001266 }
Darron Broad490c8682008-09-13 19:42:16 -03001267
1268 dprintk("%s: Not tuned\n",__func__);
1269
1270 /* Toggle pilot bit when in auto-pilot */
1271 if(state->dcur.pilot == PILOT_AUTO)
1272 cmd.args[0x07] ^= CX24116_PILOT;
Steven Toth0d467482008-09-04 01:14:43 -03001273 }
1274 while(--retune);
1275
Darron Broad490c8682008-09-13 19:42:16 -03001276tuned: /* Set/Reset B/W */
1277 cmd.args[0x00] = CMD_BANDWIDTH;
1278 cmd.args[0x01] = 0x00;
1279 cmd.len= 0x02;
1280 ret = cx24116_cmd_execute(fe, &cmd);
1281 if (ret != 0)
1282 return ret;
1283
Steven Toth0d467482008-09-04 01:14:43 -03001284 return ret;
1285}
1286
1287static struct dvb_frontend_ops cx24116_ops = {
1288
1289 .info = {
1290 .name = "Conexant CX24116/CX24118",
1291 .type = FE_QPSK,
1292 .frequency_min = 950000,
1293 .frequency_max = 2150000,
1294 .frequency_stepsize = 1011, /* kHz for QPSK frontends */
1295 .frequency_tolerance = 5000,
1296 .symbol_rate_min = 1000000,
1297 .symbol_rate_max = 45000000,
1298 .caps = FE_CAN_INVERSION_AUTO |
1299 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
1300 FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
1301 FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
1302 FE_CAN_QPSK | FE_CAN_RECOVER
1303 },
1304
1305 .release = cx24116_release,
1306
1307 .init = cx24116_initfe,
Darron Broad490c8682008-09-13 19:42:16 -03001308 .sleep = cx24116_sleep,
Steven Toth0d467482008-09-04 01:14:43 -03001309 .read_status = cx24116_read_status,
1310 .read_ber = cx24116_read_ber,
1311 .read_signal_strength = cx24116_read_signal_strength,
1312 .read_snr = cx24116_read_snr,
1313 .read_ucblocks = cx24116_read_ucblocks,
1314 .set_tone = cx24116_set_tone,
1315 .set_voltage = cx24116_set_voltage,
1316 .diseqc_send_master_cmd = cx24116_send_diseqc_msg,
1317 .diseqc_send_burst = cx24116_diseqc_send_burst,
1318
1319 .set_property = cx24116_set_property,
Steven Tothbfbf2da2008-09-12 01:37:37 -03001320 .get_property = cx24116_get_property,
Steven Toth0d467482008-09-04 01:14:43 -03001321 .set_frontend = cx24116_set_frontend,
1322};
1323
1324module_param(debug, int, 0644);
1325MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
1326
Darron Broad490c8682008-09-13 19:42:16 -03001327module_param(toneburst, int, 0644);
1328MODULE_PARM_DESC(toneburst, "DiSEqC toneburst 0=OFF, 1=TONE CACHE, 2=MESSAGE CACHE (default:1)");
1329
Steven Toth0d467482008-09-04 01:14:43 -03001330MODULE_DESCRIPTION("DVB Frontend module for Conexant cx24116/cx24118 hardware");
1331MODULE_AUTHOR("Steven Toth");
1332MODULE_LICENSE("GPL");
1333
1334EXPORT_SYMBOL(cx24116_attach);