blob: 02ed4ef79c6733ed005edfeaf3e792285a2434df [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
Igor M. Liplianinc063a482008-09-14 07:43:53 -030016 Fixed locking on high symbol rates (>30000).
17 Implement MPEG initialization parameter.
Steven Toth0d467482008-09-04 01:14:43 -030018
19 This program is free software; you can redistribute it and/or modify
20 it under the terms of the GNU General Public License as published by
21 the Free Software Foundation; either version 2 of the License, or
22 (at your option) any later version.
23
24 This program is distributed in the hope that it will be useful,
25 but WITHOUT ANY WARRANTY; without even the implied warranty of
26 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 GNU General Public License for more details.
28
29 You should have received a copy of the GNU General Public License
30 along with this program; if not, write to the Free Software
31 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
32*/
33
Steven Toth0d467482008-09-04 01:14:43 -030034#include <linux/slab.h>
35#include <linux/kernel.h>
36#include <linux/module.h>
37#include <linux/moduleparam.h>
38#include <linux/init.h>
39#include <linux/firmware.h>
40
41#include "dvb_frontend.h"
42#include "cx24116.h"
43
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)
Darron Broad681faa02008-09-22 00:47:20 -030070#define CX24116_REG_FECSTATUS (0x9c) /* configured fec (not tuned) or actual FEC (tuned) 1=1/2 2=2/3 etc */
71
72/* FECSTATUS bits */
73#define CX24116_FEC_FECMASK (0x1f) /* mask to determine configured fec (not tuned) or actual fec (tuned) */
74#define CX24116_FEC_DVBS (0x20) /* Select DVB-S demodulator, else DVB-S2 */
75#define CX24116_FEC_UNKNOWN (0x40) /* Unknown/unused */
76#define CX24116_FEC_PILOT (0x80) /* Pilot mode requested when tuning else always reset when tuned */
Steven Toth0d467482008-09-04 01:14:43 -030077
78/* arg buffer size */
79#define CX24116_ARGLEN (0x1e)
80
Darron Broad490c8682008-09-13 19:42:16 -030081/* rolloff */
82#define CX24116_ROLLOFF_020 (0x00)
83#define CX24116_ROLLOFF_025 (0x01)
84#define CX24116_ROLLOFF_035 (0x02)
85
86/* pilot bit */
87#define CX24116_PILOT (0x40)
88
89/* signal status */
90#define CX24116_HAS_SIGNAL (0x01)
91#define CX24116_HAS_CARRIER (0x02)
92#define CX24116_HAS_VITERBI (0x04)
93#define CX24116_HAS_SYNCLOCK (0x08)
94#define CX24116_HAS_UNKNOWN1 (0x10)
95#define CX24116_HAS_UNKNOWN2 (0x20)
96#define CX24116_STATUS_MASK (0x3f)
97#define CX24116_SIGNAL_MASK (0xc0)
98
99#define CX24116_DISEQC_TONEOFF (0) /* toneburst never sent */
100#define CX24116_DISEQC_TONECACHE (1) /* toneburst cached */
101#define CX24116_DISEQC_MESGCACHE (2) /* message cached */
102
Steven Toth0d467482008-09-04 01:14:43 -0300103/* arg offset for DiSEqC */
104#define CX24116_DISEQC_BURST (1)
105#define CX24116_DISEQC_ARG2_2 (2) /* unknown value=2 */
106#define CX24116_DISEQC_ARG3_0 (3) /* unknown value=0 */
107#define CX24116_DISEQC_ARG4_0 (4) /* unknown value=0 */
108#define CX24116_DISEQC_MSGLEN (5)
109#define CX24116_DISEQC_MSGOFS (6)
110
111/* DiSEqC burst */
112#define CX24116_DISEQC_MINI_A (0)
113#define CX24116_DISEQC_MINI_B (1)
114
Darron Broad490c8682008-09-13 19:42:16 -0300115/* DiSEqC tone burst */
116static int toneburst = 1;
117
Steven Toth0d467482008-09-04 01:14:43 -0300118enum cmds
119{
Darron Broad490c8682008-09-13 19:42:16 -0300120 CMD_SET_VCO = 0x10,
Steven Toth0d467482008-09-04 01:14:43 -0300121 CMD_TUNEREQUEST = 0x11,
Darron Broad490c8682008-09-13 19:42:16 -0300122 CMD_MPEGCONFIG = 0x13,
123 CMD_TUNERINIT = 0x14,
124 CMD_BANDWIDTH = 0x15,
125 CMD_GETAGC = 0x19,
126 CMD_LNBCONFIG = 0x20,
127 CMD_LNBSEND = 0x21, /* Formerly CMD_SEND_DISEQC */
Steven Toth0d467482008-09-04 01:14:43 -0300128 CMD_SET_TONEPRE = 0x22,
129 CMD_SET_TONE = 0x23,
Darron Broad490c8682008-09-13 19:42:16 -0300130 CMD_UPDFWVERS = 0x35,
131 CMD_TUNERSLEEP = 0x36,
132 CMD_AGCCONTROL = 0x3b, /* Unknown */
Steven Toth0d467482008-09-04 01:14:43 -0300133};
134
135/* The Demod/Tuner can't easily provide these, we cache them */
136struct cx24116_tuning
137{
138 u32 frequency;
139 u32 symbol_rate;
140 fe_spectral_inversion_t inversion;
141 fe_code_rate_t fec;
142
143 fe_modulation_t modulation;
Darron Broad490c8682008-09-13 19:42:16 -0300144 fe_pilot_t pilot;
145 fe_rolloff_t rolloff;
Steven Toth0d467482008-09-04 01:14:43 -0300146
147 /* Demod values */
148 u8 fec_val;
149 u8 fec_mask;
150 u8 inversion_val;
Darron Broad490c8682008-09-13 19:42:16 -0300151 u8 rolloff_val;
Steven Toth0d467482008-09-04 01:14:43 -0300152};
153
154/* Basic commands that are sent to the firmware */
155struct cx24116_cmd
156{
157 u8 len;
158 u8 args[CX24116_ARGLEN];
159};
160
161struct cx24116_state
162{
163 struct i2c_adapter* i2c;
164 const struct cx24116_config* config;
165
166 struct dvb_frontend frontend;
167
168 struct cx24116_tuning dcur;
169 struct cx24116_tuning dnxt;
170
171 u8 skip_fw_load;
172 u8 burst;
Darron Broad490c8682008-09-13 19:42:16 -0300173 struct cx24116_cmd dsec_cmd;
Steven Toth0d467482008-09-04 01:14:43 -0300174};
175
176static int cx24116_writereg(struct cx24116_state* state, int reg, int data)
177{
178 u8 buf[] = { reg, data };
179 struct i2c_msg msg = { .addr = state->config->demod_address,
180 .flags = 0, .buf = buf, .len = 2 };
181 int err;
182
183 if (debug>1)
184 printk("cx24116: %s: write reg 0x%02x, value 0x%02x\n",
185 __func__,reg, data);
186
187 if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
188 printk("%s: writereg error(err == %i, reg == 0x%02x,"
189 " value == 0x%02x)\n", __func__, err, reg, data);
190 return -EREMOTEIO;
191 }
192
193 return 0;
194}
195
196/* Bulk byte writes to a single I2C address, for 32k firmware load */
197static int cx24116_writeregN(struct cx24116_state* state, int reg, u8 *data, u16 len)
198{
199 int ret = -EREMOTEIO;
200 struct i2c_msg msg;
201 u8 *buf;
202
203 buf = kmalloc(len + 1, GFP_KERNEL);
204 if (buf == NULL) {
205 printk("Unable to kmalloc\n");
206 ret = -ENOMEM;
207 goto error;
208 }
209
210 *(buf) = reg;
211 memcpy(buf + 1, data, len);
212
213 msg.addr = state->config->demod_address;
214 msg.flags = 0;
215 msg.buf = buf;
216 msg.len = len + 1;
217
218 if (debug>1)
219 printk("cx24116: %s: write regN 0x%02x, len = %d\n",
220 __func__,reg, len);
221
222 if ((ret = i2c_transfer(state->i2c, &msg, 1)) != 1) {
223 printk("%s: writereg error(err == %i, reg == 0x%02x\n",
224 __func__, ret, reg);
225 ret = -EREMOTEIO;
226 }
227
228error:
229 kfree(buf);
230
231 return ret;
232}
233
234static int cx24116_readreg(struct cx24116_state* state, u8 reg)
235{
236 int ret;
237 u8 b0[] = { reg };
238 u8 b1[] = { 0 };
239 struct i2c_msg msg[] = {
240 { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
241 { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 }
242 };
243
244 ret = i2c_transfer(state->i2c, msg, 2);
245
246 if (ret != 2) {
247 printk("%s: reg=0x%x (error=%d)\n", __func__, reg, ret);
248 return ret;
249 }
250
251 if (debug>1)
252 printk("cx24116: read reg 0x%02x, value 0x%02x\n",reg, b1[0]);
253
254 return b1[0];
255}
256
257static int cx24116_set_inversion(struct cx24116_state* state, fe_spectral_inversion_t inversion)
258{
259 dprintk("%s(%d)\n", __func__, inversion);
260
261 switch (inversion) {
262 case INVERSION_OFF:
263 state->dnxt.inversion_val = 0x00;
264 break;
265 case INVERSION_ON:
266 state->dnxt.inversion_val = 0x04;
267 break;
268 case INVERSION_AUTO:
269 state->dnxt.inversion_val = 0x0C;
270 break;
271 default:
272 return -EINVAL;
273 }
274
275 state->dnxt.inversion = inversion;
276
277 return 0;
278}
279
Darron Broad490c8682008-09-13 19:42:16 -0300280/*
281 * modfec (modulation and FEC)
282 * ===========================
283 *
284 * MOD FEC mask/val standard
285 * ---- -------- ----------- --------
286 * QPSK FEC_1_2 0x02 0x02+X DVB-S
287 * QPSK FEC_2_3 0x04 0x02+X DVB-S
288 * QPSK FEC_3_4 0x08 0x02+X DVB-S
289 * QPSK FEC_4_5 0x10 0x02+X DVB-S (?)
290 * QPSK FEC_5_6 0x20 0x02+X DVB-S
291 * QPSK FEC_6_7 0x40 0x02+X DVB-S
292 * QPSK FEC_7_8 0x80 0x02+X DVB-S
293 * QPSK FEC_8_9 0x01 0x02+X DVB-S (?) (NOT SUPPORTED?)
294 * QPSK AUTO 0xff 0x02+X DVB-S
295 *
296 * For DVB-S high byte probably represents FEC
297 * and low byte selects the modulator. The high
298 * byte is search range mask. Bit 5 may turn
299 * on DVB-S and remaining bits represent some
300 * kind of calibration (how/what i do not know).
301 *
302 * Eg.(2/3) szap "Zone Horror"
303 *
304 * mask/val = 0x04, 0x20
305 * status 1f | signal c3c0 | snr a333 | ber 00000098 | unc 00000000 | FE_HAS_LOCK
306 *
307 * mask/val = 0x04, 0x30
308 * status 1f | signal c3c0 | snr a333 | ber 00000000 | unc 00000000 | FE_HAS_LOCK
309 *
310 * After tuning FECSTATUS contains actual FEC
311 * in use numbered 1 through to 8 for 1/2 .. 2/3 etc
312 *
313 * NBC=NOT/NON BACKWARD COMPATIBLE WITH DVB-S (DVB-S2 only)
314 *
315 * NBC-QPSK FEC_1_2 0x00, 0x04 DVB-S2
316 * NBC-QPSK FEC_3_5 0x00, 0x05 DVB-S2
317 * NBC-QPSK FEC_2_3 0x00, 0x06 DVB-S2
318 * NBC-QPSK FEC_3_4 0x00, 0x07 DVB-S2
319 * NBC-QPSK FEC_4_5 0x00, 0x08 DVB-S2
320 * NBC-QPSK FEC_5_6 0x00, 0x09 DVB-S2
321 * NBC-QPSK FEC_8_9 0x00, 0x0a DVB-S2
322 * NBC-QPSK FEC_9_10 0x00, 0x0b DVB-S2
323 *
324 * NBC-8PSK FEC_3_5 0x00, 0x0c DVB-S2
325 * NBC-8PSK FEC_2_3 0x00, 0x0d DVB-S2
326 * NBC-8PSK FEC_3_4 0x00, 0x0e DVB-S2
327 * NBC-8PSK FEC_5_6 0x00, 0x0f DVB-S2
328 * NBC-8PSK FEC_8_9 0x00, 0x10 DVB-S2
329 * NBC-8PSK FEC_9_10 0x00, 0x11 DVB-S2
330 *
331 * For DVB-S2 low bytes selects both modulator
332 * and FEC. High byte is meaningless here. To
333 * set pilot, bit 6 (0x40) is set. When inspecting
334 * FECSTATUS bit 7 (0x80) represents the pilot
335 * selection whilst not tuned. When tuned, actual FEC
336 * in use is found in FECSTATUS as per above. Pilot
337 * value is reset.
338 */
339
Steven Toth0d467482008-09-04 01:14:43 -0300340/* A table of modulation, fec and configuration bytes for the demod.
341 * Not all S2 mmodulation schemes are support and not all rates with
342 * a scheme are support. Especially, no auto detect when in S2 mode.
343 */
344struct cx24116_modfec {
345 fe_modulation_t modulation;
346 fe_code_rate_t fec;
347 u8 mask; /* In DVBS mode this is used to autodetect */
348 u8 val; /* Passed to the firmware to indicate mode selection */
349} CX24116_MODFEC_MODES[] = {
350 /* QPSK. For unknown rates we set hardware to auto detect 0xfe 0x30 */
Darron Broad490c8682008-09-13 19:42:16 -0300351
352 /*mod fec mask val */
Steven Toth0d467482008-09-04 01:14:43 -0300353 { QPSK, FEC_NONE, 0xfe, 0x30 },
Darron Broad490c8682008-09-13 19:42:16 -0300354 { QPSK, FEC_1_2, 0x02, 0x2e }, /* 00000010 00101110 */
355 { QPSK, FEC_2_3, 0x04, 0x2f }, /* 00000100 00101111 */
356 { QPSK, FEC_3_4, 0x08, 0x30 }, /* 00001000 00110000 */
357 { QPSK, FEC_4_5, 0xfe, 0x30 }, /* 000?0000 ? */
358 { QPSK, FEC_5_6, 0x20, 0x31 }, /* 00100000 00110001 */
359 { QPSK, FEC_6_7, 0xfe, 0x30 }, /* 0?000000 ? */
360 { QPSK, FEC_7_8, 0x80, 0x32 }, /* 10000000 00110010 */
361 { QPSK, FEC_8_9, 0xfe, 0x30 }, /* 0000000? ? */
Steven Toth0d467482008-09-04 01:14:43 -0300362 { QPSK, FEC_AUTO, 0xfe, 0x30 },
363 /* NBC-QPSK */
364 { NBC_QPSK, FEC_1_2, 0x00, 0x04 },
365 { NBC_QPSK, FEC_3_5, 0x00, 0x05 },
366 { NBC_QPSK, FEC_2_3, 0x00, 0x06 },
367 { NBC_QPSK, FEC_3_4, 0x00, 0x07 },
368 { NBC_QPSK, FEC_4_5, 0x00, 0x08 },
369 { NBC_QPSK, FEC_5_6, 0x00, 0x09 },
370 { NBC_QPSK, FEC_8_9, 0x00, 0x0a },
371 { NBC_QPSK, FEC_9_10, 0x00, 0x0b },
372 /* 8PSK */
373 { _8PSK, FEC_3_5, 0x00, 0x0c },
374 { _8PSK, FEC_2_3, 0x00, 0x0d },
375 { _8PSK, FEC_3_4, 0x00, 0x0e },
376 { _8PSK, FEC_5_6, 0x00, 0x0f },
Darron Broad490c8682008-09-13 19:42:16 -0300377 { _8PSK, FEC_8_9, 0x00, 0x10 },
Steven Toth0d467482008-09-04 01:14:43 -0300378 { _8PSK, FEC_9_10, 0x00, 0x11 },
Darron Broad490c8682008-09-13 19:42:16 -0300379 /*
380 * `val' can be found in the FECSTATUS register when tuning.
381 * FECSTATUS will give the actual FEC in use if tuning was successful.
382 */
Steven Toth0d467482008-09-04 01:14:43 -0300383};
384
385static int cx24116_lookup_fecmod(struct cx24116_state* state,
386 fe_modulation_t m, fe_code_rate_t f)
387{
388 int i, ret = -EOPNOTSUPP;
389
Darron Broad490c8682008-09-13 19:42:16 -0300390 dprintk("%s(0x%02x,0x%02x)\n", __func__, m, f);
391
Steven Toth0d467482008-09-04 01:14:43 -0300392 for(i=0 ; i < sizeof(CX24116_MODFEC_MODES) / sizeof(struct cx24116_modfec) ; i++)
393 {
394 if( (m == CX24116_MODFEC_MODES[i].modulation) &&
395 (f == CX24116_MODFEC_MODES[i].fec) )
396 {
397 ret = i;
398 break;
399 }
400 }
401
402 return ret;
403}
404
405static int cx24116_set_fec(struct cx24116_state* state, fe_modulation_t mod, fe_code_rate_t fec)
406{
407 int ret = 0;
Darron Broad490c8682008-09-13 19:42:16 -0300408
409 dprintk("%s(0x%02x,0x%02x)\n", __func__, mod, fec);
Steven Toth0d467482008-09-04 01:14:43 -0300410
411 ret = cx24116_lookup_fecmod(state, mod, fec);
412
413 if(ret < 0)
414 return ret;
415
Darron Broad490c8682008-09-13 19:42:16 -0300416 state->dnxt.fec = fec;
Steven Toth0d467482008-09-04 01:14:43 -0300417 state->dnxt.fec_val = CX24116_MODFEC_MODES[ret].val;
418 state->dnxt.fec_mask = CX24116_MODFEC_MODES[ret].mask;
Darron Broad490c8682008-09-13 19:42:16 -0300419 dprintk("%s() mask/val = 0x%02x/0x%02x\n", __func__,
420 state->dnxt.fec_mask, state->dnxt.fec_val);
Steven Toth0d467482008-09-04 01:14:43 -0300421
422 return 0;
423}
424
425static int cx24116_set_symbolrate(struct cx24116_state* state, u32 rate)
426{
Darron Broad490c8682008-09-13 19:42:16 -0300427 dprintk("%s(%d)\n", __func__, rate);
Steven Toth0d467482008-09-04 01:14:43 -0300428
429 /* check if symbol rate is within limits */
Darron Broad490c8682008-09-13 19:42:16 -0300430 if ((rate > state->frontend.ops.info.symbol_rate_max) ||
431 (rate < state->frontend.ops.info.symbol_rate_min)) {
432 dprintk("%s() unsupported symbol_rate = %d\n", __func__, rate);
433 return -EOPNOTSUPP;
434 }
Steven Toth0d467482008-09-04 01:14:43 -0300435
Darron Broad490c8682008-09-13 19:42:16 -0300436 state->dnxt.symbol_rate = rate;
437 dprintk("%s() symbol_rate = %d\n", __func__, rate);
438
439 return 0;
Steven Toth0d467482008-09-04 01:14:43 -0300440}
441
442static int cx24116_load_firmware (struct dvb_frontend* fe, const struct firmware *fw);
443
444static int cx24116_firmware_ondemand(struct dvb_frontend* fe)
445{
446 struct cx24116_state *state = fe->demodulator_priv;
447 const struct firmware *fw;
448 int ret = 0;
449
450 dprintk("%s()\n",__func__);
451
452 if (cx24116_readreg(state, 0x20) > 0)
453 {
454
455 if (state->skip_fw_load)
456 return 0;
457
458 /* Load firmware */
459 /* request the firmware, this will block until someone uploads it */
460 printk("%s: Waiting for firmware upload (%s)...\n", __func__, CX24116_DEFAULT_FIRMWARE);
461 ret = request_firmware(&fw, CX24116_DEFAULT_FIRMWARE, &state->i2c->dev);
462 printk("%s: Waiting for firmware upload(2)...\n", __func__);
463 if (ret) {
464 printk("%s: No firmware uploaded (timeout or file not found?)\n", __func__);
465 return ret;
466 }
467
468 /* Make sure we don't recurse back through here during loading */
469 state->skip_fw_load = 1;
470
471 ret = cx24116_load_firmware(fe, fw);
472 if (ret)
473 printk("%s: Writing firmware to device failed\n", __func__);
474
475 release_firmware(fw);
476
477 printk("%s: Firmware upload %s\n", __func__, ret == 0 ? "complete" : "failed");
478
479 /* Ensure firmware is always loaded if required */
480 state->skip_fw_load = 0;
481 }
482
483 return ret;
484}
485
486/* Take a basic firmware command structure, format it and forward it for processing */
487static int cx24116_cmd_execute(struct dvb_frontend* fe, struct cx24116_cmd *cmd)
488{
489 struct cx24116_state *state = fe->demodulator_priv;
490 int i, ret;
491
492 dprintk("%s()\n", __func__);
493
494 /* Load the firmware if required */
495 if ( (ret = cx24116_firmware_ondemand(fe)) != 0)
496 {
497 printk("%s(): Unable initialise the firmware\n", __func__);
498 return ret;
499 }
500
501 /* Write the command */
502 for(i = 0; i < cmd->len ; i++)
503 {
504 dprintk("%s: 0x%02x == 0x%02x\n", __func__, i, cmd->args[i]);
505 cx24116_writereg(state, i, cmd->args[i]);
506 }
507
508 /* Start execution and wait for cmd to terminate */
Darron Broad490c8682008-09-13 19:42:16 -0300509 cx24116_writereg(state, CX24116_REG_EXECUTE, 0x01);
510 while( cx24116_readreg(state, CX24116_REG_EXECUTE) )
Steven Toth0d467482008-09-04 01:14:43 -0300511 {
512 msleep(10);
513 if(i++ > 64)
514 {
515 /* Avoid looping forever if the firmware does no respond */
516 printk("%s() Firmware not responding\n", __func__);
517 return -EREMOTEIO;
518 }
519 }
520 return 0;
521}
522
523static int cx24116_load_firmware (struct dvb_frontend* fe, const struct firmware *fw)
524{
525 struct cx24116_state* state = fe->demodulator_priv;
526 struct cx24116_cmd cmd;
Darron Broad490c8682008-09-13 19:42:16 -0300527 int i, ret;
528 unsigned char vers[4];
Steven Toth0d467482008-09-04 01:14:43 -0300529
530 dprintk("%s\n", __func__);
531 dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n"
532 ,fw->size
533 ,fw->data[0]
534 ,fw->data[1]
535 ,fw->data[ fw->size-2 ]
536 ,fw->data[ fw->size-1 ]
537 );
538
539 /* Toggle 88x SRST pin to reset demod */
540 if (state->config->reset_device)
541 state->config->reset_device(fe);
542
543 /* Begin the firmware load process */
544 /* Prepare the demod, load the firmware, cleanup after load */
Steven Toth0d467482008-09-04 01:14:43 -0300545
Darron Broad490c8682008-09-13 19:42:16 -0300546 /* Init PLL */
547 cx24116_writereg(state, 0xE5, 0x00);
548 cx24116_writereg(state, 0xF1, 0x08);
549 cx24116_writereg(state, 0xF2, 0x13);
550
551 /* Start PLL */
552 cx24116_writereg(state, 0xe0, 0x03);
553 cx24116_writereg(state, 0xe0, 0x00);
554
555 /* Unknown */
556 cx24116_writereg(state, CX24116_REG_CLKDIV, 0x46);
557 cx24116_writereg(state, CX24116_REG_RATEDIV, 0x00);
558
559 /* Unknown */
Steven Toth0d467482008-09-04 01:14:43 -0300560 cx24116_writereg(state, 0xF0, 0x03);
561 cx24116_writereg(state, 0xF4, 0x81);
562 cx24116_writereg(state, 0xF5, 0x00);
563 cx24116_writereg(state, 0xF6, 0x00);
564
565 /* write the entire firmware as one transaction */
566 cx24116_writeregN(state, 0xF7, fw->data, fw->size);
567
568 cx24116_writereg(state, 0xF4, 0x10);
569 cx24116_writereg(state, 0xF0, 0x00);
570 cx24116_writereg(state, 0xF8, 0x06);
571
Darron Broad490c8682008-09-13 19:42:16 -0300572 /* Firmware CMD 10: VCO config */
573 cmd.args[0x00] = CMD_SET_VCO;
Steven Toth0d467482008-09-04 01:14:43 -0300574 cmd.args[0x01] = 0x05;
575 cmd.args[0x02] = 0xdc;
576 cmd.args[0x03] = 0xda;
577 cmd.args[0x04] = 0xae;
578 cmd.args[0x05] = 0xaa;
579 cmd.args[0x06] = 0x04;
580 cmd.args[0x07] = 0x9d;
581 cmd.args[0x08] = 0xfc;
582 cmd.args[0x09] = 0x06;
583 cmd.len= 0x0a;
584 ret = cx24116_cmd_execute(fe, &cmd);
585 if (ret != 0)
586 return ret;
587
Darron Broad490c8682008-09-13 19:42:16 -0300588 cx24116_writereg(state, CX24116_REG_SSTATUS, 0x00);
Steven Toth0d467482008-09-04 01:14:43 -0300589
Darron Broad490c8682008-09-13 19:42:16 -0300590 /* Firmware CMD 14: Tuner config */
591 cmd.args[0x00] = CMD_TUNERINIT;
Steven Toth0d467482008-09-04 01:14:43 -0300592 cmd.args[0x01] = 0x00;
593 cmd.args[0x02] = 0x00;
594 cmd.len= 0x03;
595 ret = cx24116_cmd_execute(fe, &cmd);
596 if (ret != 0)
597 return ret;
598
599 cx24116_writereg(state, 0xe5, 0x00);
600
Darron Broad490c8682008-09-13 19:42:16 -0300601 /* Firmware CMD 13: MPEG config */
602 cmd.args[0x00] = CMD_MPEGCONFIG;
Steven Toth0d467482008-09-04 01:14:43 -0300603 cmd.args[0x01] = 0x01;
604 cmd.args[0x02] = 0x75;
605 cmd.args[0x03] = 0x00;
Igor M. Liplianincc8c4f32008-09-09 13:57:47 -0300606 if (state->config->mpg_clk_pos_pol)
607 cmd.args[0x04] = state->config->mpg_clk_pos_pol;
608 else
609 cmd.args[0x04] = 0x02;
Steven Toth0d467482008-09-04 01:14:43 -0300610 cmd.args[0x05] = 0x00;
611 cmd.len= 0x06;
612 ret = cx24116_cmd_execute(fe, &cmd);
613 if (ret != 0)
614 return ret;
615
Darron Broad490c8682008-09-13 19:42:16 -0300616 /* Firmware CMD 35: Get firmware version */
617 cmd.args[0x00] = CMD_UPDFWVERS;
618 cmd.len= 0x02;
619 for(i=0; i<4; i++) {
620 cmd.args[0x01] = i;
621 ret = cx24116_cmd_execute(fe, &cmd);
622 if (ret != 0)
623 return ret;
624 vers[i]= cx24116_readreg(state, CX24116_REG_MAILBOX);
625 }
626 printk("%s: FW version %i.%i.%i.%i\n", __func__,
627 vers[0], vers[1], vers[2], vers[3]);
628
Steven Toth0d467482008-09-04 01:14:43 -0300629 return 0;
630}
631
632static int cx24116_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
633{
634 /* The isl6421 module will override this function in the fops. */
635 dprintk("%s() This should never appear if the isl6421 module is loaded correctly\n",__func__);
636
637 return -EOPNOTSUPP;
638}
639
640static int cx24116_read_status(struct dvb_frontend* fe, fe_status_t* status)
641{
642 struct cx24116_state *state = fe->demodulator_priv;
643
Darron Broad490c8682008-09-13 19:42:16 -0300644 int lock = cx24116_readreg(state, CX24116_REG_SSTATUS);
Steven Toth0d467482008-09-04 01:14:43 -0300645
646 dprintk("%s: status = 0x%02x\n", __func__, lock);
647
648 *status = 0;
649
Darron Broad490c8682008-09-13 19:42:16 -0300650 if (lock & CX24116_HAS_SIGNAL)
Steven Toth0d467482008-09-04 01:14:43 -0300651 *status |= FE_HAS_SIGNAL;
Darron Broad490c8682008-09-13 19:42:16 -0300652 if (lock & CX24116_HAS_CARRIER)
Steven Toth0d467482008-09-04 01:14:43 -0300653 *status |= FE_HAS_CARRIER;
Darron Broad490c8682008-09-13 19:42:16 -0300654 if (lock & CX24116_HAS_VITERBI)
Steven Toth0d467482008-09-04 01:14:43 -0300655 *status |= FE_HAS_VITERBI;
Darron Broad490c8682008-09-13 19:42:16 -0300656 if (lock & CX24116_HAS_SYNCLOCK)
Steven Toth0d467482008-09-04 01:14:43 -0300657 *status |= FE_HAS_SYNC | FE_HAS_LOCK;
658
659 return 0;
660}
661
Steven Toth0d467482008-09-04 01:14:43 -0300662static int cx24116_read_ber(struct dvb_frontend* fe, u32* ber)
663{
Darron Broad490c8682008-09-13 19:42:16 -0300664 struct cx24116_state *state = fe->demodulator_priv;
665
Steven Toth0d467482008-09-04 01:14:43 -0300666 dprintk("%s()\n", __func__);
Darron Broad490c8682008-09-13 19:42:16 -0300667
668 *ber = ( cx24116_readreg(state, CX24116_REG_BER24) << 24 ) |
669 ( cx24116_readreg(state, CX24116_REG_BER16) << 16 ) |
670 ( cx24116_readreg(state, CX24116_REG_BER8 ) << 8 ) |
671 cx24116_readreg(state, CX24116_REG_BER0 );
Steven Toth0d467482008-09-04 01:14:43 -0300672
673 return 0;
674}
675
Darron Broad490c8682008-09-13 19:42:16 -0300676/* TODO Determine function and scale appropriately */
Steven Toth0d467482008-09-04 01:14:43 -0300677static int cx24116_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
678{
679 struct cx24116_state *state = fe->demodulator_priv;
Darron Broad490c8682008-09-13 19:42:16 -0300680 struct cx24116_cmd cmd;
681 int ret;
682 u16 sig_reading;
683
684 dprintk("%s()\n", __func__);
685
686 /* Firmware CMD 19: Get AGC */
687 cmd.args[0x00] = CMD_GETAGC;
688 cmd.len= 0x01;
689 ret = cx24116_cmd_execute(fe, &cmd);
690 if (ret != 0)
691 return ret;
692
693 sig_reading = ( cx24116_readreg(state, CX24116_REG_SSTATUS) & CX24116_SIGNAL_MASK ) |
694 ( cx24116_readreg(state, CX24116_REG_SIGNAL) << 6 );
695 *signal_strength= 0 - sig_reading;
696
697 dprintk("%s: raw / cooked = 0x%04x / 0x%04x\n", __func__, sig_reading, *signal_strength);
698
699 return 0;
700}
701
702/* SNR (0..100)% = (sig & 0xf0) * 10 + (sig & 0x0f) * 10 / 16 */
703static int cx24116_read_snr(struct dvb_frontend* fe, u16* snr)
704{
705 struct cx24116_state *state = fe->demodulator_priv;
706 u8 snr_reading;
707 static const u32 snr_tab[] = { /* 10 x Table (rounded up) */
708 0x00000,0x0199A,0x03333,0x04ccD,0x06667,
709 0x08000,0x0999A,0x0b333,0x0cccD,0x0e667,
Steven Toth0d467482008-09-04 01:14:43 -0300710 0x10000,0x1199A,0x13333,0x14ccD,0x16667,0x18000 };
711
712 dprintk("%s()\n", __func__);
713
Darron Broad490c8682008-09-13 19:42:16 -0300714 snr_reading = cx24116_readreg(state, CX24116_REG_QUALITY);
Steven Toth0d467482008-09-04 01:14:43 -0300715
Darron Broad490c8682008-09-13 19:42:16 -0300716 if(snr_reading >= 0xa0 /* 100% */)
717 *snr = 0xffff;
Steven Toth0d467482008-09-04 01:14:43 -0300718 else
Darron Broad490c8682008-09-13 19:42:16 -0300719 *snr = snr_tab [ ( snr_reading & 0xf0 ) >> 4 ] +
720 ( snr_tab [ ( snr_reading & 0x0f ) ] >> 4 );
Steven Toth0d467482008-09-04 01:14:43 -0300721
Darron Broad490c8682008-09-13 19:42:16 -0300722 dprintk("%s: raw / cooked = 0x%02x / 0x%04x\n", __func__,
723 snr_reading, *snr);
Steven Toth0d467482008-09-04 01:14:43 -0300724
725 return 0;
726}
727
Steven Toth0d467482008-09-04 01:14:43 -0300728static int cx24116_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
729{
Darron Broad490c8682008-09-13 19:42:16 -0300730 struct cx24116_state *state = fe->demodulator_priv;
731
Steven Toth0d467482008-09-04 01:14:43 -0300732 dprintk("%s()\n", __func__);
Darron Broad490c8682008-09-13 19:42:16 -0300733
734 *ucblocks = ( cx24116_readreg(state, CX24116_REG_UCB8) << 8 ) |
735 cx24116_readreg(state, CX24116_REG_UCB0);
Steven Toth0d467482008-09-04 01:14:43 -0300736
737 return 0;
738}
739
740/* Overwrite the current tuning params, we are about to tune */
741static void cx24116_clone_params(struct dvb_frontend* fe)
742{
743 struct cx24116_state *state = fe->demodulator_priv;
744 memcpy(&state->dcur, &state->dnxt, sizeof(state->dcur));
745}
746
Darron Broad490c8682008-09-13 19:42:16 -0300747/* Wait for LNB */
748static int cx24116_wait_for_lnb(struct dvb_frontend* fe)
749{
750 struct cx24116_state *state = fe->demodulator_priv;
751 int i;
752
753 dprintk("%s() qstatus = 0x%02x\n", __func__,
754 cx24116_readreg(state, CX24116_REG_QSTATUS));
755
756 /* Wait for up to 300 ms */
757 for(i = 0; i < 30 ; i++) {
758 if (cx24116_readreg(state, CX24116_REG_QSTATUS) & 0x20)
759 return 0;
760 msleep(10);
761 }
762
763 dprintk("%s(): LNB not ready\n", __func__);
764
765 return -ETIMEDOUT; /* -EBUSY ? */
766}
767
Steven Toth0d467482008-09-04 01:14:43 -0300768static int cx24116_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
769{
770 struct cx24116_cmd cmd;
771 int ret;
772
773 dprintk("%s(%d)\n", __func__, tone);
774 if ( (tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF) ) {
775 printk("%s: Invalid, tone=%d\n", __func__, tone);
776 return -EINVAL;
777 }
778
Darron Broad490c8682008-09-13 19:42:16 -0300779 /* Wait for LNB ready */
780 ret = cx24116_wait_for_lnb(fe);
781 if(ret != 0)
782 return ret;
783
784 /* Min delay time after DiSEqC send */
785 msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */
786
Steven Toth0d467482008-09-04 01:14:43 -0300787 /* This is always done before the tone is set */
788 cmd.args[0x00] = CMD_SET_TONEPRE;
789 cmd.args[0x01] = 0x00;
790 cmd.len= 0x02;
791 ret = cx24116_cmd_execute(fe, &cmd);
792 if (ret != 0)
793 return ret;
794
795 /* Now we set the tone */
796 cmd.args[0x00] = CMD_SET_TONE;
797 cmd.args[0x01] = 0x00;
798 cmd.args[0x02] = 0x00;
799
800 switch (tone) {
801 case SEC_TONE_ON:
802 dprintk("%s: setting tone on\n", __func__);
803 cmd.args[0x03] = 0x01;
804 break;
805 case SEC_TONE_OFF:
806 dprintk("%s: setting tone off\n",__func__);
807 cmd.args[0x03] = 0x00;
808 break;
809 }
810 cmd.len= 0x04;
811
Darron Broad490c8682008-09-13 19:42:16 -0300812 /* Min delay time before DiSEqC send */
813 msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */
814
Steven Toth0d467482008-09-04 01:14:43 -0300815 return cx24116_cmd_execute(fe, &cmd);
816}
817
818/* Initialise DiSEqC */
819static int cx24116_diseqc_init(struct dvb_frontend* fe)
820{
821 struct cx24116_state *state = fe->demodulator_priv;
Darron Broad490c8682008-09-13 19:42:16 -0300822 struct cx24116_cmd cmd;
823 int ret;
Steven Toth0d467482008-09-04 01:14:43 -0300824
Darron Broad490c8682008-09-13 19:42:16 -0300825 /* Firmware CMD 20: LNB/DiSEqC config */
826 cmd.args[0x00] = CMD_LNBCONFIG;
827 cmd.args[0x01] = 0x00;
828 cmd.args[0x02] = 0x10;
829 cmd.args[0x03] = 0x00;
830 cmd.args[0x04] = 0x8f;
831 cmd.args[0x05] = 0x28;
832 cmd.args[0x06] = (toneburst == CX24116_DISEQC_TONEOFF) ? 0x00 : 0x01;
833 cmd.args[0x07] = 0x01;
834 cmd.len= 0x08;
835 ret = cx24116_cmd_execute(fe, &cmd);
836 if (ret != 0)
837 return ret;
838
839 /* Prepare a DiSEqC command */
840 state->dsec_cmd.args[0x00] = CMD_LNBSEND;
841
842 /* DiSEqC burst */
843 state->dsec_cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_A;
844
845 /* Unknown */
846 state->dsec_cmd.args[CX24116_DISEQC_ARG2_2] = 0x02;
847 state->dsec_cmd.args[CX24116_DISEQC_ARG3_0] = 0x00;
848 state->dsec_cmd.args[CX24116_DISEQC_ARG4_0] = 0x00; /* Continuation flag? */
849
850 /* DiSEqC message length */
851 state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = 0x00;
852
853 /* Command length */
854 state->dsec_cmd.len= CX24116_DISEQC_MSGOFS;
Steven Toth0d467482008-09-04 01:14:43 -0300855
856 return 0;
857}
858
859/* Send DiSEqC message with derived burst (hack) || previous burst */
860static int cx24116_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *d)
861{
862 struct cx24116_state *state = fe->demodulator_priv;
Steven Toth0d467482008-09-04 01:14:43 -0300863 int i, ret;
864
865 /* Dump DiSEqC message */
866 if (debug) {
867 printk("cx24116: %s(", __func__);
868 for(i = 0 ; i < d->msg_len ;) {
869 printk("0x%02x", d->msg[i]);
870 if(++i < d->msg_len)
871 printk(", ");
Darron Broad490c8682008-09-13 19:42:16 -0300872 }
873 printk(") toneburst=%d\n", toneburst);
Steven Toth0d467482008-09-04 01:14:43 -0300874 }
875
Darron Broad490c8682008-09-13 19:42:16 -0300876 /* Validate length */
Steven Toth0d467482008-09-04 01:14:43 -0300877 if(d->msg_len > (CX24116_ARGLEN - CX24116_DISEQC_MSGOFS))
878 return -EINVAL;
879
Steven Toth0d467482008-09-04 01:14:43 -0300880 /* DiSEqC message */
881 for (i = 0; i < d->msg_len; i++)
Darron Broad490c8682008-09-13 19:42:16 -0300882 state->dsec_cmd.args[CX24116_DISEQC_MSGOFS + i] = d->msg[i];
Steven Toth0d467482008-09-04 01:14:43 -0300883
Darron Broad490c8682008-09-13 19:42:16 -0300884 /* DiSEqC message length */
885 state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = d->msg_len;
Steven Toth0d467482008-09-04 01:14:43 -0300886
Darron Broad490c8682008-09-13 19:42:16 -0300887 /* Command length */
888 state->dsec_cmd.len= CX24116_DISEQC_MSGOFS + state->dsec_cmd.args[CX24116_DISEQC_MSGLEN];
Steven Toth0d467482008-09-04 01:14:43 -0300889
Darron Broad490c8682008-09-13 19:42:16 -0300890 /* DiSEqC toneburst */
891 if(toneburst == CX24116_DISEQC_MESGCACHE)
892 /* Message is cached */
893 return 0;
Steven Toth0d467482008-09-04 01:14:43 -0300894
Darron Broad490c8682008-09-13 19:42:16 -0300895 else if(toneburst == CX24116_DISEQC_TONEOFF)
896 /* Message is sent without burst */
897 state->dsec_cmd.args[CX24116_DISEQC_BURST] = 0;
898
899 else if(toneburst == CX24116_DISEQC_TONECACHE) {
900 /*
901 * Message is sent with derived else cached burst
902 *
903 * WRITE PORT GROUP COMMAND 38
904 *
905 * 0/A/A: E0 10 38 F0..F3
906 * 1/B/B: E0 10 38 F4..F7
907 * 2/C/A: E0 10 38 F8..FB
908 * 3/D/B: E0 10 38 FC..FF
909 *
Darron Broad7396d3e2008-09-14 10:45:58 -0300910 * databyte[3]= 8421:8421
Darron Broad490c8682008-09-13 19:42:16 -0300911 * ABCD:WXYZ
912 * CLR :SET
913 *
914 * WX= PORT SELECT 0..3 (X=TONEBURST)
915 * Y = VOLTAGE (0=13V, 1=18V)
916 * Z = BAND (0=LOW, 1=HIGH(22K))
917 */
918 if(d->msg_len >= 4 && d->msg[2] == 0x38)
919 state->dsec_cmd.args[CX24116_DISEQC_BURST] = ((d->msg[3] & 4) >> 2);
920 if(debug)
921 dprintk("%s burst=%d\n", __func__, state->dsec_cmd.args[CX24116_DISEQC_BURST]);
922 }
923
924 /* Wait for LNB ready */
925 ret = cx24116_wait_for_lnb(fe);
926 if(ret != 0)
927 return ret;
928
929 /* Wait for voltage/min repeat delay */
930 msleep(100);
931
932 /* Command */
933 ret = cx24116_cmd_execute(fe, &state->dsec_cmd);
934 if(ret != 0)
935 return ret;
936 /*
937 * Wait for send
Steven Toth0d467482008-09-04 01:14:43 -0300938 *
939 * Eutelsat spec:
Darron Broad490c8682008-09-13 19:42:16 -0300940 * >15ms delay + (XXX determine if FW does this, see set_tone)
941 * 13.5ms per byte +
942 * >15ms delay +
943 * 12.5ms burst +
944 * >15ms delay (XXX determine if FW does this, see set_tone)
Steven Toth0d467482008-09-04 01:14:43 -0300945 */
Darron Broad490c8682008-09-13 19:42:16 -0300946 msleep( (state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) + ((toneburst == CX24116_DISEQC_TONEOFF) ? 30 : 60) );
Steven Toth0d467482008-09-04 01:14:43 -0300947
Darron Broad490c8682008-09-13 19:42:16 -0300948 return 0;
Steven Toth0d467482008-09-04 01:14:43 -0300949}
950
951/* Send DiSEqC burst */
952static int cx24116_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst)
953{
954 struct cx24116_state *state = fe->demodulator_priv;
Steven Toth0d467482008-09-04 01:14:43 -0300955 int ret;
956
Darron Broad490c8682008-09-13 19:42:16 -0300957 dprintk("%s(%d) toneburst=%d\n",__func__, burst, toneburst);
Steven Toth0d467482008-09-04 01:14:43 -0300958
Darron Broad490c8682008-09-13 19:42:16 -0300959 /* DiSEqC burst */
Steven Toth0d467482008-09-04 01:14:43 -0300960 if (burst == SEC_MINI_A)
Darron Broad490c8682008-09-13 19:42:16 -0300961 state->dsec_cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_A;
Steven Toth0d467482008-09-04 01:14:43 -0300962 else if(burst == SEC_MINI_B)
Darron Broad490c8682008-09-13 19:42:16 -0300963 state->dsec_cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_B;
Steven Toth0d467482008-09-04 01:14:43 -0300964 else
965 return -EINVAL;
966
Darron Broad490c8682008-09-13 19:42:16 -0300967 /* DiSEqC toneburst */
968 if(toneburst != CX24116_DISEQC_MESGCACHE)
969 /* Burst is cached */
970 return 0;
Steven Toth0d467482008-09-04 01:14:43 -0300971
Darron Broad490c8682008-09-13 19:42:16 -0300972 /* Burst is to be sent with cached message */
Steven Toth0d467482008-09-04 01:14:43 -0300973
Darron Broad490c8682008-09-13 19:42:16 -0300974 /* Wait for LNB ready */
975 ret = cx24116_wait_for_lnb(fe);
976 if(ret != 0)
977 return ret;
Steven Toth0d467482008-09-04 01:14:43 -0300978
Darron Broad490c8682008-09-13 19:42:16 -0300979 /* Wait for voltage/min repeat delay */
980 msleep(100);
Steven Toth0d467482008-09-04 01:14:43 -0300981
Darron Broad490c8682008-09-13 19:42:16 -0300982 /* Command */
983 ret = cx24116_cmd_execute(fe, &state->dsec_cmd);
984 if(ret != 0)
985 return ret;
986
987 /*
988 * Wait for send
989 *
990 * Eutelsat spec:
991 * >15ms delay + (XXX determine if FW does this, see set_tone)
992 * 13.5ms per byte +
993 * >15ms delay +
994 * 12.5ms burst +
995 * >15ms delay (XXX determine if FW does this, see set_tone)
996 */
997 msleep( (state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) + 60 );
998
999 return 0;
Steven Toth0d467482008-09-04 01:14:43 -03001000}
1001
1002static void cx24116_release(struct dvb_frontend* fe)
1003{
1004 struct cx24116_state* state = fe->demodulator_priv;
1005 dprintk("%s\n",__func__);
1006 kfree(state);
1007}
1008
1009static struct dvb_frontend_ops cx24116_ops;
1010
1011struct dvb_frontend* cx24116_attach(const struct cx24116_config* config,
1012 struct i2c_adapter* i2c)
1013{
1014 struct cx24116_state* state = NULL;
1015 int ret;
1016
1017 dprintk("%s\n",__func__);
1018
1019 /* allocate memory for the internal state */
1020 state = kmalloc(sizeof(struct cx24116_state), GFP_KERNEL);
1021 if (state == NULL) {
1022 printk("Unable to kmalloc\n");
Darron Broad7396d3e2008-09-14 10:45:58 -03001023 goto error1;
Steven Toth0d467482008-09-04 01:14:43 -03001024 }
1025
1026 /* setup the state */
1027 memset(state, 0, sizeof(struct cx24116_state));
1028
1029 state->config = config;
1030 state->i2c = i2c;
1031
1032 /* check if the demod is present */
1033 ret = (cx24116_readreg(state, 0xFF) << 8) | cx24116_readreg(state, 0xFE);
1034 if (ret != 0x0501) {
1035 printk("Invalid probe, probably not a CX24116 device\n");
Darron Broad7396d3e2008-09-14 10:45:58 -03001036 goto error2;
Steven Toth0d467482008-09-04 01:14:43 -03001037 }
1038
1039 /* create dvb_frontend */
1040 memcpy(&state->frontend.ops, &cx24116_ops, sizeof(struct dvb_frontend_ops));
1041 state->frontend.demodulator_priv = state;
1042 return &state->frontend;
1043
Darron Broad7396d3e2008-09-14 10:45:58 -03001044error2: kfree(state);
Darron Broad490c8682008-09-13 19:42:16 -03001045error1: return NULL;
Steven Toth0d467482008-09-04 01:14:43 -03001046}
Darron Broad490c8682008-09-13 19:42:16 -03001047/*
1048 * Initialise or wake up device
1049 *
1050 * Power config will reset and load initial firmware if required
1051 */
Steven Toth0d467482008-09-04 01:14:43 -03001052static int cx24116_initfe(struct dvb_frontend* fe)
1053{
Darron Broad490c8682008-09-13 19:42:16 -03001054 struct cx24116_state* state = fe->demodulator_priv;
1055 struct cx24116_cmd cmd;
1056 int ret;
1057
Steven Toth0d467482008-09-04 01:14:43 -03001058 dprintk("%s()\n",__func__);
1059
Darron Broad490c8682008-09-13 19:42:16 -03001060 /* Power on */
1061 cx24116_writereg(state, 0xe0, 0);
1062 cx24116_writereg(state, 0xe1, 0);
1063 cx24116_writereg(state, 0xea, 0);
1064
1065 /* Firmware CMD 36: Power config */
1066 cmd.args[0x00] = CMD_TUNERSLEEP;
1067 cmd.args[0x01] = 0;
1068 cmd.len= 0x02;
1069 ret = cx24116_cmd_execute(fe, &cmd);
1070 if(ret != 0)
1071 return ret;
1072
Steven Toth0d467482008-09-04 01:14:43 -03001073 return cx24116_diseqc_init(fe);
1074}
1075
Darron Broad490c8682008-09-13 19:42:16 -03001076/*
1077 * Put device to sleep
1078 */
1079static int cx24116_sleep(struct dvb_frontend* fe)
1080{
1081 struct cx24116_state* state = fe->demodulator_priv;
1082 struct cx24116_cmd cmd;
1083 int ret;
1084
1085 dprintk("%s()\n",__func__);
1086
1087 /* Firmware CMD 36: Power config */
1088 cmd.args[0x00] = CMD_TUNERSLEEP;
1089 cmd.args[0x01] = 1;
1090 cmd.len= 0x02;
1091 ret = cx24116_cmd_execute(fe, &cmd);
1092 if(ret != 0)
1093 return ret;
1094
1095 /* Power off (Shutdown clocks) */
1096 cx24116_writereg(state, 0xea, 0xff);
1097 cx24116_writereg(state, 0xe1, 1);
1098 cx24116_writereg(state, 0xe0, 1);
1099
1100 return 0;
1101}
1102
Steven Tothe7fee0f32008-09-11 10:23:01 -03001103static int cx24116_set_property(struct dvb_frontend *fe, struct dtv_property* tvp)
Steven Toth0d467482008-09-04 01:14:43 -03001104{
1105 dprintk("%s(..)\n", __func__);
1106 return 0;
1107}
1108
Steven Tothbfbf2da2008-09-12 01:37:37 -03001109static int cx24116_get_property(struct dvb_frontend *fe, struct dtv_property* tvp)
Steven Toth0d467482008-09-04 01:14:43 -03001110{
Steven Tothbfbf2da2008-09-12 01:37:37 -03001111 dprintk("%s(..)\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -03001112 return 0;
1113}
1114
1115/* dvb-core told us to tune, the tv property cache will be complete,
1116 * it's safe for is to pull values and use them for tuning purposes.
1117 */
1118static int cx24116_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
1119{
1120 struct cx24116_state *state = fe->demodulator_priv;
Steven Toth56f06802008-09-11 10:19:27 -03001121 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
Steven Toth0d467482008-09-04 01:14:43 -03001122 struct cx24116_cmd cmd;
1123 fe_status_t tunerstat;
Darron Broad490c8682008-09-13 19:42:16 -03001124 int i, status, ret, retune = 1;
Steven Toth0d467482008-09-04 01:14:43 -03001125
1126 dprintk("%s()\n",__func__);
1127
1128 state->dnxt.modulation = c->modulation;
1129 state->dnxt.frequency = c->frequency;
1130
Darron Broad490c8682008-09-13 19:42:16 -03001131 switch(c->delivery_system) {
1132 case SYS_DVBS:
1133 dprintk("%s: DVB-S delivery system selected\n",__func__);
1134 state->dnxt.pilot = PILOT_OFF;
Darron Broad7396d3e2008-09-14 10:45:58 -03001135 state->dnxt.rolloff_val = CX24116_ROLLOFF_035;
1136 state->dnxt.rolloff = c->rolloff;
Darron Broad490c8682008-09-13 19:42:16 -03001137 break;
1138 case SYS_DVBS2:
1139 dprintk("%s: DVB-S2 delivery system selected\n",__func__);
1140 if(c->pilot == PILOT_AUTO)
1141 retune++;
1142 state->dnxt.pilot = c->pilot;
1143 switch(c->rolloff) {
1144 case ROLLOFF_20:
1145 state->dnxt.rolloff_val= CX24116_ROLLOFF_020;
1146 break;
1147 case ROLLOFF_25:
1148 state->dnxt.rolloff_val= CX24116_ROLLOFF_025;
1149 break;
1150 case ROLLOFF_35:
1151 state->dnxt.rolloff_val= CX24116_ROLLOFF_035;
1152 break;
1153 case ROLLOFF_AUTO:
1154 return -EOPNOTSUPP;
1155 }
1156 state->dnxt.rolloff = c->rolloff;
1157 break;
1158 default:
1159 dprintk("%s: unsupported delivery system selected (%d)\n",
1160 __func__, c->delivery_system);
1161 return -EOPNOTSUPP;
1162 }
1163
Steven Toth0d467482008-09-04 01:14:43 -03001164 if ((ret = cx24116_set_inversion(state, c->inversion)) != 0)
1165 return ret;
1166
1167 if ((ret = cx24116_set_fec(state, c->modulation, c->fec_inner)) != 0)
1168 return ret;
1169
1170 if ((ret = cx24116_set_symbolrate(state, c->symbol_rate)) != 0)
1171 return ret;
1172
1173 /* discard the 'current' tuning parameters and prepare to tune */
1174 cx24116_clone_params(fe);
1175
Darron Broad490c8682008-09-13 19:42:16 -03001176 dprintk("%s: retune = %d\n", __func__, retune);
1177 dprintk("%s: rolloff = %d\n", __func__, state->dcur.rolloff);
1178 dprintk("%s: pilot = %d\n", __func__, state->dcur.pilot);
Steven Toth0d467482008-09-04 01:14:43 -03001179 dprintk("%s: frequency = %d\n", __func__, state->dcur.frequency);
1180 dprintk("%s: symbol_rate = %d\n", __func__, state->dcur.symbol_rate);
1181 dprintk("%s: FEC = %d (mask/val = 0x%02x/0x%02x)\n", __func__,
1182 state->dcur.fec, state->dcur.fec_mask, state->dcur.fec_val);
1183 dprintk("%s: Inversion = %d (val = 0x%02x)\n", __func__,
1184 state->dcur.inversion, state->dcur.inversion_val);
1185
Darron Broad490c8682008-09-13 19:42:16 -03001186 /* This is also done in advise/acquire on HVR4000 but not on LITE */
Steven Toth0d467482008-09-04 01:14:43 -03001187 if (state->config->set_ts_params)
1188 state->config->set_ts_params(fe, 0);
1189
Darron Broad490c8682008-09-13 19:42:16 -03001190 /* Set/Reset B/W */
1191 cmd.args[0x00] = CMD_BANDWIDTH;
1192 cmd.args[0x01] = 0x01;
1193 cmd.len= 0x02;
1194 ret = cx24116_cmd_execute(fe, &cmd);
1195 if (ret != 0)
1196 return ret;
Igor M. Liplianin3f8e51a2008-09-09 13:22:29 -03001197
Steven Toth0d467482008-09-04 01:14:43 -03001198 /* Prepare a tune request */
1199 cmd.args[0x00] = CMD_TUNEREQUEST;
1200
1201 /* Frequency */
1202 cmd.args[0x01] = (state->dcur.frequency & 0xff0000) >> 16;
1203 cmd.args[0x02] = (state->dcur.frequency & 0x00ff00) >> 8;
1204 cmd.args[0x03] = (state->dcur.frequency & 0x0000ff);
1205
1206 /* Symbol Rate */
1207 cmd.args[0x04] = ((state->dcur.symbol_rate / 1000) & 0xff00) >> 8;
1208 cmd.args[0x05] = ((state->dcur.symbol_rate / 1000) & 0x00ff);
1209
1210 /* Automatic Inversion */
1211 cmd.args[0x06] = state->dcur.inversion_val;
1212
1213 /* Modulation / FEC & Pilot Off */
1214 cmd.args[0x07] = state->dcur.fec_val;
1215
Darron Broad490c8682008-09-13 19:42:16 -03001216 if (state->dcur.pilot == PILOT_ON)
1217 cmd.args[0x07] |= CX24116_PILOT;
Steven Toth0d467482008-09-04 01:14:43 -03001218
1219 cmd.args[0x08] = CX24116_SEARCH_RANGE_KHZ >> 8;
1220 cmd.args[0x09] = CX24116_SEARCH_RANGE_KHZ & 0xff;
1221 cmd.args[0x0a] = 0x00;
1222 cmd.args[0x0b] = 0x00;
Darron Broad490c8682008-09-13 19:42:16 -03001223 cmd.args[0x0c] = state->dcur.rolloff_val;
Steven Toth0d467482008-09-04 01:14:43 -03001224 cmd.args[0x0d] = state->dcur.fec_mask;
Igor M. Liplianin3f8e51a2008-09-09 13:22:29 -03001225
Darron Broad490c8682008-09-13 19:42:16 -03001226 if (state->dcur.symbol_rate > 30000000) {
Igor M. Liplianin3f8e51a2008-09-09 13:22:29 -03001227 cmd.args[0x0e] = 0x04;
1228 cmd.args[0x0f] = 0x00;
1229 cmd.args[0x10] = 0x01;
1230 cmd.args[0x11] = 0x77;
1231 cmd.args[0x12] = 0x36;
Darron Broad490c8682008-09-13 19:42:16 -03001232 cx24116_writereg(state, CX24116_REG_CLKDIV, 0x44);
1233 cx24116_writereg(state, CX24116_REG_RATEDIV, 0x01);
Igor M. Liplianin3f8e51a2008-09-09 13:22:29 -03001234 } else {
1235 cmd.args[0x0e] = 0x06;
1236 cmd.args[0x0f] = 0x00;
1237 cmd.args[0x10] = 0x00;
1238 cmd.args[0x11] = 0xFA;
1239 cmd.args[0x12] = 0x24;
Darron Broad490c8682008-09-13 19:42:16 -03001240 cx24116_writereg(state, CX24116_REG_CLKDIV, 0x46);
1241 cx24116_writereg(state, CX24116_REG_RATEDIV, 0x00);
Igor M. Liplianin3f8e51a2008-09-09 13:22:29 -03001242 }
1243
Steven Toth0d467482008-09-04 01:14:43 -03001244 cmd.len= 0x13;
1245
1246 /* We need to support pilot and non-pilot tuning in the
1247 * driver automatically. This is a workaround for because
1248 * the demod does not support autodetect.
1249 */
1250 do {
Darron Broad490c8682008-09-13 19:42:16 -03001251 /* Reset status register */
1252 status = cx24116_readreg(state, CX24116_REG_SSTATUS) & CX24116_SIGNAL_MASK;
1253 cx24116_writereg(state, CX24116_REG_SSTATUS, status);
Steven Toth0d467482008-09-04 01:14:43 -03001254
1255 /* Tune */
1256 ret = cx24116_cmd_execute(fe, &cmd);
1257 if( ret != 0 )
1258 break;
1259
Darron Broad490c8682008-09-13 19:42:16 -03001260 /*
1261 * Wait for up to 500 ms before retrying
1262 *
1263 * If we are able to tune then generally it occurs within 100ms.
1264 * If it takes longer, try a different toneburst setting.
1265 */
1266 for(i = 0; i < 50 ; i++) {
1267 cx24116_read_status(fe, &tunerstat);
1268 status = tunerstat & (FE_HAS_SIGNAL | FE_HAS_SYNC);
1269 if(status == (FE_HAS_SIGNAL | FE_HAS_SYNC)) {
1270 dprintk("%s: Tuned\n",__func__);
1271 goto tuned;
1272 }
1273 msleep(10);
Steven Toth0d467482008-09-04 01:14:43 -03001274 }
Darron Broad490c8682008-09-13 19:42:16 -03001275
1276 dprintk("%s: Not tuned\n",__func__);
1277
1278 /* Toggle pilot bit when in auto-pilot */
1279 if(state->dcur.pilot == PILOT_AUTO)
1280 cmd.args[0x07] ^= CX24116_PILOT;
Steven Toth0d467482008-09-04 01:14:43 -03001281 }
1282 while(--retune);
1283
Darron Broad490c8682008-09-13 19:42:16 -03001284tuned: /* Set/Reset B/W */
1285 cmd.args[0x00] = CMD_BANDWIDTH;
1286 cmd.args[0x01] = 0x00;
1287 cmd.len= 0x02;
1288 ret = cx24116_cmd_execute(fe, &cmd);
1289 if (ret != 0)
1290 return ret;
1291
Steven Toth0d467482008-09-04 01:14:43 -03001292 return ret;
1293}
1294
1295static struct dvb_frontend_ops cx24116_ops = {
1296
1297 .info = {
1298 .name = "Conexant CX24116/CX24118",
1299 .type = FE_QPSK,
1300 .frequency_min = 950000,
1301 .frequency_max = 2150000,
1302 .frequency_stepsize = 1011, /* kHz for QPSK frontends */
1303 .frequency_tolerance = 5000,
1304 .symbol_rate_min = 1000000,
1305 .symbol_rate_max = 45000000,
1306 .caps = FE_CAN_INVERSION_AUTO |
1307 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
1308 FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
1309 FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
1310 FE_CAN_QPSK | FE_CAN_RECOVER
1311 },
1312
1313 .release = cx24116_release,
1314
1315 .init = cx24116_initfe,
Darron Broad490c8682008-09-13 19:42:16 -03001316 .sleep = cx24116_sleep,
Steven Toth0d467482008-09-04 01:14:43 -03001317 .read_status = cx24116_read_status,
1318 .read_ber = cx24116_read_ber,
1319 .read_signal_strength = cx24116_read_signal_strength,
1320 .read_snr = cx24116_read_snr,
1321 .read_ucblocks = cx24116_read_ucblocks,
1322 .set_tone = cx24116_set_tone,
1323 .set_voltage = cx24116_set_voltage,
1324 .diseqc_send_master_cmd = cx24116_send_diseqc_msg,
1325 .diseqc_send_burst = cx24116_diseqc_send_burst,
1326
1327 .set_property = cx24116_set_property,
Steven Tothbfbf2da2008-09-12 01:37:37 -03001328 .get_property = cx24116_get_property,
Steven Toth0d467482008-09-04 01:14:43 -03001329 .set_frontend = cx24116_set_frontend,
1330};
1331
1332module_param(debug, int, 0644);
1333MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
1334
Darron Broad490c8682008-09-13 19:42:16 -03001335module_param(toneburst, int, 0644);
1336MODULE_PARM_DESC(toneburst, "DiSEqC toneburst 0=OFF, 1=TONE CACHE, 2=MESSAGE CACHE (default:1)");
1337
Steven Toth0d467482008-09-04 01:14:43 -03001338MODULE_DESCRIPTION("DVB Frontend module for Conexant cx24116/cx24118 hardware");
1339MODULE_AUTHOR("Steven Toth");
1340MODULE_LICENSE("GPL");
1341
1342EXPORT_SYMBOL(cx24116_attach);