blob: 751792a092e2287c12c715cd3d6385fb94a4149e [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
Steven Tothf11ec7d2008-10-16 20:22:01 -030044static int debug;
45module_param(debug, int, 0644);
46MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
47
Darron Broad490c8682008-09-13 19:42:16 -030048#define dprintk(args...) \
49 do { \
Steven Tothf11ec7d2008-10-16 20:22:01 -030050 if (debug) \
51 printk("cx24116: " args); \
Darron Broad490c8682008-09-13 19:42:16 -030052 } while (0)
53
Steven Toth0d467482008-09-04 01:14:43 -030054#define CX24116_DEFAULT_FIRMWARE "dvb-fe-cx24116.fw"
55#define CX24116_SEARCH_RANGE_KHZ 5000
56
Darron Broad490c8682008-09-13 19:42:16 -030057/* known registers */
58#define CX24116_REG_COMMAND (0x00) /* command args 0x00..0x1e */
59#define CX24116_REG_EXECUTE (0x1f) /* execute command */
60#define CX24116_REG_MAILBOX (0x96) /* FW or multipurpose mailbox? */
61#define CX24116_REG_RESET (0x20) /* reset status > 0 */
62#define CX24116_REG_SIGNAL (0x9e) /* signal low */
63#define CX24116_REG_SSTATUS (0x9d) /* signal high / status */
Steven Toth8953db72008-10-06 21:20:21 -030064#define CX24116_REG_QUALITY8 (0xa3)
Darron Broad490c8682008-09-13 19:42:16 -030065#define CX24116_REG_QSTATUS (0xbc)
Steven Toth8953db72008-10-06 21:20:21 -030066#define CX24116_REG_QUALITY0 (0xd5)
Darron Broad490c8682008-09-13 19:42:16 -030067#define CX24116_REG_BER0 (0xc9)
68#define CX24116_REG_BER8 (0xc8)
69#define CX24116_REG_BER16 (0xc7)
70#define CX24116_REG_BER24 (0xc6)
71#define CX24116_REG_UCB0 (0xcb)
72#define CX24116_REG_UCB8 (0xca)
73#define CX24116_REG_CLKDIV (0xf3)
74#define CX24116_REG_RATEDIV (0xf9)
Darron Broad681faa02008-09-22 00:47:20 -030075#define CX24116_REG_FECSTATUS (0x9c) /* configured fec (not tuned) or actual FEC (tuned) 1=1/2 2=2/3 etc */
76
77/* FECSTATUS bits */
78#define CX24116_FEC_FECMASK (0x1f) /* mask to determine configured fec (not tuned) or actual fec (tuned) */
79#define CX24116_FEC_DVBS (0x20) /* Select DVB-S demodulator, else DVB-S2 */
80#define CX24116_FEC_UNKNOWN (0x40) /* Unknown/unused */
81#define CX24116_FEC_PILOT (0x80) /* Pilot mode requested when tuning else always reset when tuned */
Steven Toth0d467482008-09-04 01:14:43 -030082
83/* arg buffer size */
84#define CX24116_ARGLEN (0x1e)
85
Darron Broad490c8682008-09-13 19:42:16 -030086/* rolloff */
87#define CX24116_ROLLOFF_020 (0x00)
88#define CX24116_ROLLOFF_025 (0x01)
89#define CX24116_ROLLOFF_035 (0x02)
90
91/* pilot bit */
Darron Broad01a8f032008-10-03 11:47:46 -030092#define CX24116_PILOT_OFF (0x00)
93#define CX24116_PILOT_ON (0x40)
Darron Broad490c8682008-09-13 19:42:16 -030094
95/* signal status */
96#define CX24116_HAS_SIGNAL (0x01)
97#define CX24116_HAS_CARRIER (0x02)
98#define CX24116_HAS_VITERBI (0x04)
99#define CX24116_HAS_SYNCLOCK (0x08)
100#define CX24116_HAS_UNKNOWN1 (0x10)
101#define CX24116_HAS_UNKNOWN2 (0x20)
102#define CX24116_STATUS_MASK (0x3f)
103#define CX24116_SIGNAL_MASK (0xc0)
104
105#define CX24116_DISEQC_TONEOFF (0) /* toneburst never sent */
106#define CX24116_DISEQC_TONECACHE (1) /* toneburst cached */
107#define CX24116_DISEQC_MESGCACHE (2) /* message cached */
108
Steven Toth0d467482008-09-04 01:14:43 -0300109/* arg offset for DiSEqC */
110#define CX24116_DISEQC_BURST (1)
111#define CX24116_DISEQC_ARG2_2 (2) /* unknown value=2 */
112#define CX24116_DISEQC_ARG3_0 (3) /* unknown value=0 */
113#define CX24116_DISEQC_ARG4_0 (4) /* unknown value=0 */
114#define CX24116_DISEQC_MSGLEN (5)
115#define CX24116_DISEQC_MSGOFS (6)
116
117/* DiSEqC burst */
118#define CX24116_DISEQC_MINI_A (0)
119#define CX24116_DISEQC_MINI_B (1)
120
Darron Broad490c8682008-09-13 19:42:16 -0300121/* DiSEqC tone burst */
122static int toneburst = 1;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300123module_param(toneburst, int, 0644);
124MODULE_PARM_DESC(toneburst, "DiSEqC toneburst 0=OFF, 1=TONE CACHE, 2=MESSAGE CACHE (default:1)");
Darron Broad490c8682008-09-13 19:42:16 -0300125
Steven Toth8953db72008-10-06 21:20:21 -0300126/* SNR measurements */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300127static int esno_snr;
128module_param(esno_snr, int, 0644);
129MODULE_PARM_DESC(debug, "SNR return units, 0=PERCENTAGE 0-100, 1=ESNO(db * 10) (default:0)");
Steven Toth8953db72008-10-06 21:20:21 -0300130
Steven Tothf11ec7d2008-10-16 20:22:01 -0300131enum cmds {
Darron Broad490c8682008-09-13 19:42:16 -0300132 CMD_SET_VCO = 0x10,
Steven Toth0d467482008-09-04 01:14:43 -0300133 CMD_TUNEREQUEST = 0x11,
Darron Broad490c8682008-09-13 19:42:16 -0300134 CMD_MPEGCONFIG = 0x13,
135 CMD_TUNERINIT = 0x14,
136 CMD_BANDWIDTH = 0x15,
137 CMD_GETAGC = 0x19,
138 CMD_LNBCONFIG = 0x20,
139 CMD_LNBSEND = 0x21, /* Formerly CMD_SEND_DISEQC */
Steven Toth0d467482008-09-04 01:14:43 -0300140 CMD_SET_TONEPRE = 0x22,
141 CMD_SET_TONE = 0x23,
Darron Broad490c8682008-09-13 19:42:16 -0300142 CMD_UPDFWVERS = 0x35,
143 CMD_TUNERSLEEP = 0x36,
144 CMD_AGCCONTROL = 0x3b, /* Unknown */
Steven Toth0d467482008-09-04 01:14:43 -0300145};
146
147/* The Demod/Tuner can't easily provide these, we cache them */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300148struct cx24116_tuning {
Steven Toth0d467482008-09-04 01:14:43 -0300149 u32 frequency;
150 u32 symbol_rate;
151 fe_spectral_inversion_t inversion;
152 fe_code_rate_t fec;
153
154 fe_modulation_t modulation;
Darron Broad490c8682008-09-13 19:42:16 -0300155 fe_pilot_t pilot;
156 fe_rolloff_t rolloff;
Steven Toth0d467482008-09-04 01:14:43 -0300157
158 /* Demod values */
159 u8 fec_val;
160 u8 fec_mask;
161 u8 inversion_val;
Darron Broad01a8f032008-10-03 11:47:46 -0300162 u8 pilot_val;
Darron Broad490c8682008-09-13 19:42:16 -0300163 u8 rolloff_val;
Steven Toth0d467482008-09-04 01:14:43 -0300164};
165
166/* Basic commands that are sent to the firmware */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300167struct cx24116_cmd {
Steven Toth0d467482008-09-04 01:14:43 -0300168 u8 len;
169 u8 args[CX24116_ARGLEN];
170};
171
Steven Tothf11ec7d2008-10-16 20:22:01 -0300172struct cx24116_state {
173 struct i2c_adapter *i2c;
174 const struct cx24116_config *config;
Steven Toth0d467482008-09-04 01:14:43 -0300175
176 struct dvb_frontend frontend;
177
178 struct cx24116_tuning dcur;
179 struct cx24116_tuning dnxt;
180
181 u8 skip_fw_load;
182 u8 burst;
Darron Broad490c8682008-09-13 19:42:16 -0300183 struct cx24116_cmd dsec_cmd;
Steven Toth0d467482008-09-04 01:14:43 -0300184};
185
Steven Tothf11ec7d2008-10-16 20:22:01 -0300186static int cx24116_writereg(struct cx24116_state *state, int reg, int data)
Steven Toth0d467482008-09-04 01:14:43 -0300187{
188 u8 buf[] = { reg, data };
189 struct i2c_msg msg = { .addr = state->config->demod_address,
190 .flags = 0, .buf = buf, .len = 2 };
191 int err;
192
Steven Tothf11ec7d2008-10-16 20:22:01 -0300193 if (debug > 1)
Steven Toth0d467482008-09-04 01:14:43 -0300194 printk("cx24116: %s: write reg 0x%02x, value 0x%02x\n",
Steven Tothf11ec7d2008-10-16 20:22:01 -0300195 __func__, reg, data);
Steven Toth0d467482008-09-04 01:14:43 -0300196
Steven Tothf11ec7d2008-10-16 20:22:01 -0300197 err = i2c_transfer(state->i2c, &msg, 1);
198 if (err != 1) {
Steven Toth0d467482008-09-04 01:14:43 -0300199 printk("%s: writereg error(err == %i, reg == 0x%02x,"
200 " value == 0x%02x)\n", __func__, err, reg, data);
201 return -EREMOTEIO;
202 }
203
204 return 0;
205}
206
207/* Bulk byte writes to a single I2C address, for 32k firmware load */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300208static int cx24116_writeregN(struct cx24116_state *state, int reg,
209 u8 *data, u16 len)
Steven Toth0d467482008-09-04 01:14:43 -0300210{
211 int ret = -EREMOTEIO;
212 struct i2c_msg msg;
213 u8 *buf;
214
215 buf = kmalloc(len + 1, GFP_KERNEL);
216 if (buf == NULL) {
217 printk("Unable to kmalloc\n");
218 ret = -ENOMEM;
219 goto error;
220 }
221
222 *(buf) = reg;
223 memcpy(buf + 1, data, len);
224
225 msg.addr = state->config->demod_address;
226 msg.flags = 0;
227 msg.buf = buf;
228 msg.len = len + 1;
229
Steven Tothf11ec7d2008-10-16 20:22:01 -0300230 if (debug > 1)
Steven Toth0d467482008-09-04 01:14:43 -0300231 printk("cx24116: %s: write regN 0x%02x, len = %d\n",
Steven Tothf11ec7d2008-10-16 20:22:01 -0300232 __func__, reg, len);
Steven Toth0d467482008-09-04 01:14:43 -0300233
Steven Tothf11ec7d2008-10-16 20:22:01 -0300234 ret = i2c_transfer(state->i2c, &msg, 1);
235 if (ret != 1) {
Steven Toth0d467482008-09-04 01:14:43 -0300236 printk("%s: writereg error(err == %i, reg == 0x%02x\n",
237 __func__, ret, reg);
238 ret = -EREMOTEIO;
239 }
240
241error:
242 kfree(buf);
243
244 return ret;
245}
246
Steven Tothf11ec7d2008-10-16 20:22:01 -0300247static int cx24116_readreg(struct cx24116_state *state, u8 reg)
Steven Toth0d467482008-09-04 01:14:43 -0300248{
249 int ret;
250 u8 b0[] = { reg };
251 u8 b1[] = { 0 };
252 struct i2c_msg msg[] = {
Steven Tothf11ec7d2008-10-16 20:22:01 -0300253 { .addr = state->config->demod_address, .flags = 0,
254 .buf = b0, .len = 1 },
255 { .addr = state->config->demod_address, .flags = I2C_M_RD,
256 .buf = b1, .len = 1 }
Steven Toth0d467482008-09-04 01:14:43 -0300257 };
258
259 ret = i2c_transfer(state->i2c, msg, 2);
260
261 if (ret != 2) {
262 printk("%s: reg=0x%x (error=%d)\n", __func__, reg, ret);
263 return ret;
264 }
265
Steven Tothf11ec7d2008-10-16 20:22:01 -0300266 if (debug > 1)
267 printk("cx24116: read reg 0x%02x, value 0x%02x\n",
268 reg, b1[0]);
Steven Toth0d467482008-09-04 01:14:43 -0300269
270 return b1[0];
271}
272
Steven Tothf11ec7d2008-10-16 20:22:01 -0300273static int cx24116_set_inversion(struct cx24116_state *state, fe_spectral_inversion_t inversion)
Steven Toth0d467482008-09-04 01:14:43 -0300274{
275 dprintk("%s(%d)\n", __func__, inversion);
276
277 switch (inversion) {
278 case INVERSION_OFF:
279 state->dnxt.inversion_val = 0x00;
280 break;
281 case INVERSION_ON:
282 state->dnxt.inversion_val = 0x04;
283 break;
284 case INVERSION_AUTO:
285 state->dnxt.inversion_val = 0x0C;
286 break;
287 default:
288 return -EINVAL;
289 }
290
291 state->dnxt.inversion = inversion;
292
293 return 0;
294}
295
Darron Broad490c8682008-09-13 19:42:16 -0300296/*
297 * modfec (modulation and FEC)
298 * ===========================
299 *
300 * MOD FEC mask/val standard
301 * ---- -------- ----------- --------
302 * QPSK FEC_1_2 0x02 0x02+X DVB-S
303 * QPSK FEC_2_3 0x04 0x02+X DVB-S
304 * QPSK FEC_3_4 0x08 0x02+X DVB-S
305 * QPSK FEC_4_5 0x10 0x02+X DVB-S (?)
306 * QPSK FEC_5_6 0x20 0x02+X DVB-S
307 * QPSK FEC_6_7 0x40 0x02+X DVB-S
308 * QPSK FEC_7_8 0x80 0x02+X DVB-S
309 * QPSK FEC_8_9 0x01 0x02+X DVB-S (?) (NOT SUPPORTED?)
310 * QPSK AUTO 0xff 0x02+X DVB-S
311 *
312 * For DVB-S high byte probably represents FEC
313 * and low byte selects the modulator. The high
314 * byte is search range mask. Bit 5 may turn
315 * on DVB-S and remaining bits represent some
316 * kind of calibration (how/what i do not know).
317 *
318 * Eg.(2/3) szap "Zone Horror"
319 *
320 * mask/val = 0x04, 0x20
321 * status 1f | signal c3c0 | snr a333 | ber 00000098 | unc 00000000 | FE_HAS_LOCK
322 *
323 * mask/val = 0x04, 0x30
324 * status 1f | signal c3c0 | snr a333 | ber 00000000 | unc 00000000 | FE_HAS_LOCK
325 *
326 * After tuning FECSTATUS contains actual FEC
327 * in use numbered 1 through to 8 for 1/2 .. 2/3 etc
328 *
329 * NBC=NOT/NON BACKWARD COMPATIBLE WITH DVB-S (DVB-S2 only)
330 *
331 * NBC-QPSK FEC_1_2 0x00, 0x04 DVB-S2
332 * NBC-QPSK FEC_3_5 0x00, 0x05 DVB-S2
333 * NBC-QPSK FEC_2_3 0x00, 0x06 DVB-S2
334 * NBC-QPSK FEC_3_4 0x00, 0x07 DVB-S2
335 * NBC-QPSK FEC_4_5 0x00, 0x08 DVB-S2
336 * NBC-QPSK FEC_5_6 0x00, 0x09 DVB-S2
337 * NBC-QPSK FEC_8_9 0x00, 0x0a DVB-S2
338 * NBC-QPSK FEC_9_10 0x00, 0x0b DVB-S2
339 *
340 * NBC-8PSK FEC_3_5 0x00, 0x0c DVB-S2
341 * NBC-8PSK FEC_2_3 0x00, 0x0d DVB-S2
342 * NBC-8PSK FEC_3_4 0x00, 0x0e DVB-S2
343 * NBC-8PSK FEC_5_6 0x00, 0x0f DVB-S2
344 * NBC-8PSK FEC_8_9 0x00, 0x10 DVB-S2
345 * NBC-8PSK FEC_9_10 0x00, 0x11 DVB-S2
346 *
347 * For DVB-S2 low bytes selects both modulator
348 * and FEC. High byte is meaningless here. To
349 * set pilot, bit 6 (0x40) is set. When inspecting
350 * FECSTATUS bit 7 (0x80) represents the pilot
351 * selection whilst not tuned. When tuned, actual FEC
352 * in use is found in FECSTATUS as per above. Pilot
353 * value is reset.
354 */
355
Steven Toth0d467482008-09-04 01:14:43 -0300356/* A table of modulation, fec and configuration bytes for the demod.
357 * Not all S2 mmodulation schemes are support and not all rates with
358 * a scheme are support. Especially, no auto detect when in S2 mode.
359 */
360struct cx24116_modfec {
Steven Toth0a6393a2008-10-06 21:06:48 -0300361 fe_delivery_system_t delivery_system;
Steven Toth0d467482008-09-04 01:14:43 -0300362 fe_modulation_t modulation;
363 fe_code_rate_t fec;
364 u8 mask; /* In DVBS mode this is used to autodetect */
365 u8 val; /* Passed to the firmware to indicate mode selection */
366} CX24116_MODFEC_MODES[] = {
367 /* QPSK. For unknown rates we set hardware to auto detect 0xfe 0x30 */
Darron Broad490c8682008-09-13 19:42:16 -0300368
369 /*mod fec mask val */
Steven Toth0a6393a2008-10-06 21:06:48 -0300370 { SYS_DVBS, QPSK, FEC_NONE, 0xfe, 0x30 },
371 { SYS_DVBS, QPSK, FEC_1_2, 0x02, 0x2e }, /* 00000010 00101110 */
372 { SYS_DVBS, QPSK, FEC_2_3, 0x04, 0x2f }, /* 00000100 00101111 */
373 { SYS_DVBS, QPSK, FEC_3_4, 0x08, 0x30 }, /* 00001000 00110000 */
374 { SYS_DVBS, QPSK, FEC_4_5, 0xfe, 0x30 }, /* 000?0000 ? */
375 { SYS_DVBS, QPSK, FEC_5_6, 0x20, 0x31 }, /* 00100000 00110001 */
376 { SYS_DVBS, QPSK, FEC_6_7, 0xfe, 0x30 }, /* 0?000000 ? */
377 { SYS_DVBS, QPSK, FEC_7_8, 0x80, 0x32 }, /* 10000000 00110010 */
378 { SYS_DVBS, QPSK, FEC_8_9, 0xfe, 0x30 }, /* 0000000? ? */
379 { SYS_DVBS, QPSK, FEC_AUTO, 0xfe, 0x30 },
Steven Toth0d467482008-09-04 01:14:43 -0300380 /* NBC-QPSK */
Steven Toth0a6393a2008-10-06 21:06:48 -0300381 { SYS_DVBS2, QPSK, FEC_1_2, 0x00, 0x04 },
382 { SYS_DVBS2, QPSK, FEC_3_5, 0x00, 0x05 },
383 { SYS_DVBS2, QPSK, FEC_2_3, 0x00, 0x06 },
384 { SYS_DVBS2, QPSK, FEC_3_4, 0x00, 0x07 },
385 { SYS_DVBS2, QPSK, FEC_4_5, 0x00, 0x08 },
386 { SYS_DVBS2, QPSK, FEC_5_6, 0x00, 0x09 },
387 { SYS_DVBS2, QPSK, FEC_8_9, 0x00, 0x0a },
388 { SYS_DVBS2, QPSK, FEC_9_10, 0x00, 0x0b },
Steven Toth0d467482008-09-04 01:14:43 -0300389 /* 8PSK */
Steven Toth0a6393a2008-10-06 21:06:48 -0300390 { SYS_DVBS2, PSK_8, FEC_3_5, 0x00, 0x0c },
391 { SYS_DVBS2, PSK_8, FEC_2_3, 0x00, 0x0d },
392 { SYS_DVBS2, PSK_8, FEC_3_4, 0x00, 0x0e },
393 { SYS_DVBS2, PSK_8, FEC_5_6, 0x00, 0x0f },
394 { SYS_DVBS2, PSK_8, FEC_8_9, 0x00, 0x10 },
395 { SYS_DVBS2, PSK_8, FEC_9_10, 0x00, 0x11 },
Darron Broad490c8682008-09-13 19:42:16 -0300396 /*
397 * `val' can be found in the FECSTATUS register when tuning.
398 * FECSTATUS will give the actual FEC in use if tuning was successful.
399 */
Steven Toth0d467482008-09-04 01:14:43 -0300400};
401
Steven Tothf11ec7d2008-10-16 20:22:01 -0300402static int cx24116_lookup_fecmod(struct cx24116_state *state,
Steven Toth0d467482008-09-04 01:14:43 -0300403 fe_modulation_t m, fe_code_rate_t f)
404{
405 int i, ret = -EOPNOTSUPP;
406
Darron Broad490c8682008-09-13 19:42:16 -0300407 dprintk("%s(0x%02x,0x%02x)\n", __func__, m, f);
408
Steven Tothf11ec7d2008-10-16 20:22:01 -0300409 for (i = 0; i < ARRAY_SIZE(CX24116_MODFEC_MODES); i++) {
410 if ((m == CX24116_MODFEC_MODES[i].modulation) &&
411 (f == CX24116_MODFEC_MODES[i].fec)) {
Steven Toth0d467482008-09-04 01:14:43 -0300412 ret = i;
413 break;
414 }
415 }
416
417 return ret;
418}
419
Steven Tothf11ec7d2008-10-16 20:22:01 -0300420static int cx24116_set_fec(struct cx24116_state *state, fe_modulation_t mod, fe_code_rate_t fec)
Steven Toth0d467482008-09-04 01:14:43 -0300421{
422 int ret = 0;
Darron Broad490c8682008-09-13 19:42:16 -0300423
424 dprintk("%s(0x%02x,0x%02x)\n", __func__, mod, fec);
Steven Toth0d467482008-09-04 01:14:43 -0300425
426 ret = cx24116_lookup_fecmod(state, mod, fec);
427
Steven Tothf11ec7d2008-10-16 20:22:01 -0300428 if (ret < 0)
Steven Toth0d467482008-09-04 01:14:43 -0300429 return ret;
430
Darron Broad490c8682008-09-13 19:42:16 -0300431 state->dnxt.fec = fec;
Steven Toth0d467482008-09-04 01:14:43 -0300432 state->dnxt.fec_val = CX24116_MODFEC_MODES[ret].val;
433 state->dnxt.fec_mask = CX24116_MODFEC_MODES[ret].mask;
Darron Broad490c8682008-09-13 19:42:16 -0300434 dprintk("%s() mask/val = 0x%02x/0x%02x\n", __func__,
435 state->dnxt.fec_mask, state->dnxt.fec_val);
Steven Toth0d467482008-09-04 01:14:43 -0300436
437 return 0;
438}
439
Steven Tothf11ec7d2008-10-16 20:22:01 -0300440static int cx24116_set_symbolrate(struct cx24116_state *state, u32 rate)
Steven Toth0d467482008-09-04 01:14:43 -0300441{
Darron Broad490c8682008-09-13 19:42:16 -0300442 dprintk("%s(%d)\n", __func__, rate);
Steven Toth0d467482008-09-04 01:14:43 -0300443
444 /* check if symbol rate is within limits */
Darron Broad490c8682008-09-13 19:42:16 -0300445 if ((rate > state->frontend.ops.info.symbol_rate_max) ||
446 (rate < state->frontend.ops.info.symbol_rate_min)) {
447 dprintk("%s() unsupported symbol_rate = %d\n", __func__, rate);
448 return -EOPNOTSUPP;
449 }
Steven Toth0d467482008-09-04 01:14:43 -0300450
Darron Broad490c8682008-09-13 19:42:16 -0300451 state->dnxt.symbol_rate = rate;
452 dprintk("%s() symbol_rate = %d\n", __func__, rate);
453
454 return 0;
Steven Toth0d467482008-09-04 01:14:43 -0300455}
456
Steven Tothf11ec7d2008-10-16 20:22:01 -0300457static int cx24116_load_firmware(struct dvb_frontend *fe,
458 const struct firmware *fw);
Steven Toth0d467482008-09-04 01:14:43 -0300459
Steven Tothf11ec7d2008-10-16 20:22:01 -0300460static int cx24116_firmware_ondemand(struct dvb_frontend *fe)
Steven Toth0d467482008-09-04 01:14:43 -0300461{
462 struct cx24116_state *state = fe->demodulator_priv;
463 const struct firmware *fw;
464 int ret = 0;
465
Steven Tothf11ec7d2008-10-16 20:22:01 -0300466 dprintk("%s()\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -0300467
Steven Tothf11ec7d2008-10-16 20:22:01 -0300468 if (cx24116_readreg(state, 0x20) > 0) {
Steven Toth0d467482008-09-04 01:14:43 -0300469
470 if (state->skip_fw_load)
471 return 0;
472
473 /* Load firmware */
474 /* request the firmware, this will block until someone uploads it */
475 printk("%s: Waiting for firmware upload (%s)...\n", __func__, CX24116_DEFAULT_FIRMWARE);
476 ret = request_firmware(&fw, CX24116_DEFAULT_FIRMWARE, &state->i2c->dev);
477 printk("%s: Waiting for firmware upload(2)...\n", __func__);
478 if (ret) {
479 printk("%s: No firmware uploaded (timeout or file not found?)\n", __func__);
480 return ret;
481 }
482
483 /* Make sure we don't recurse back through here during loading */
484 state->skip_fw_load = 1;
485
486 ret = cx24116_load_firmware(fe, fw);
487 if (ret)
488 printk("%s: Writing firmware to device failed\n", __func__);
489
490 release_firmware(fw);
491
492 printk("%s: Firmware upload %s\n", __func__, ret == 0 ? "complete" : "failed");
493
494 /* Ensure firmware is always loaded if required */
495 state->skip_fw_load = 0;
496 }
497
498 return ret;
499}
500
501/* Take a basic firmware command structure, format it and forward it for processing */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300502static int cx24116_cmd_execute(struct dvb_frontend *fe, struct cx24116_cmd *cmd)
Steven Toth0d467482008-09-04 01:14:43 -0300503{
504 struct cx24116_state *state = fe->demodulator_priv;
505 int i, ret;
506
507 dprintk("%s()\n", __func__);
508
509 /* Load the firmware if required */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300510 ret = cx24116_firmware_ondemand(fe);
511 if (ret != 0) {
Steven Toth0d467482008-09-04 01:14:43 -0300512 printk("%s(): Unable initialise the firmware\n", __func__);
513 return ret;
514 }
515
516 /* Write the command */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300517 for (i = 0; i < cmd->len ; i++) {
Steven Toth0d467482008-09-04 01:14:43 -0300518 dprintk("%s: 0x%02x == 0x%02x\n", __func__, i, cmd->args[i]);
519 cx24116_writereg(state, i, cmd->args[i]);
520 }
521
522 /* Start execution and wait for cmd to terminate */
Darron Broad490c8682008-09-13 19:42:16 -0300523 cx24116_writereg(state, CX24116_REG_EXECUTE, 0x01);
Steven Tothf11ec7d2008-10-16 20:22:01 -0300524 while (cx24116_readreg(state, CX24116_REG_EXECUTE)) {
Steven Toth0d467482008-09-04 01:14:43 -0300525 msleep(10);
Steven Tothf11ec7d2008-10-16 20:22:01 -0300526 if (i++ > 64) {
Steven Toth0d467482008-09-04 01:14:43 -0300527 /* Avoid looping forever if the firmware does no respond */
528 printk("%s() Firmware not responding\n", __func__);
529 return -EREMOTEIO;
530 }
531 }
532 return 0;
533}
534
Steven Tothf11ec7d2008-10-16 20:22:01 -0300535static int cx24116_load_firmware(struct dvb_frontend *fe,
536 const struct firmware *fw)
Steven Toth0d467482008-09-04 01:14:43 -0300537{
Steven Tothf11ec7d2008-10-16 20:22:01 -0300538 struct cx24116_state *state = fe->demodulator_priv;
Steven Toth0d467482008-09-04 01:14:43 -0300539 struct cx24116_cmd cmd;
Darron Broad490c8682008-09-13 19:42:16 -0300540 int i, ret;
541 unsigned char vers[4];
Steven Toth0d467482008-09-04 01:14:43 -0300542
543 dprintk("%s\n", __func__);
Steven Tothf11ec7d2008-10-16 20:22:01 -0300544 dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n",
545 fw->size,
546 fw->data[0],
547 fw->data[1],
548 fw->data[fw->size-2],
549 fw->data[fw->size-1]);
Steven Toth0d467482008-09-04 01:14:43 -0300550
551 /* Toggle 88x SRST pin to reset demod */
552 if (state->config->reset_device)
553 state->config->reset_device(fe);
554
555 /* Begin the firmware load process */
556 /* Prepare the demod, load the firmware, cleanup after load */
Steven Toth0d467482008-09-04 01:14:43 -0300557
Darron Broad490c8682008-09-13 19:42:16 -0300558 /* Init PLL */
559 cx24116_writereg(state, 0xE5, 0x00);
560 cx24116_writereg(state, 0xF1, 0x08);
561 cx24116_writereg(state, 0xF2, 0x13);
562
563 /* Start PLL */
564 cx24116_writereg(state, 0xe0, 0x03);
565 cx24116_writereg(state, 0xe0, 0x00);
566
567 /* Unknown */
568 cx24116_writereg(state, CX24116_REG_CLKDIV, 0x46);
569 cx24116_writereg(state, CX24116_REG_RATEDIV, 0x00);
570
571 /* Unknown */
Steven Toth0d467482008-09-04 01:14:43 -0300572 cx24116_writereg(state, 0xF0, 0x03);
573 cx24116_writereg(state, 0xF4, 0x81);
574 cx24116_writereg(state, 0xF5, 0x00);
575 cx24116_writereg(state, 0xF6, 0x00);
576
577 /* write the entire firmware as one transaction */
578 cx24116_writeregN(state, 0xF7, fw->data, fw->size);
579
580 cx24116_writereg(state, 0xF4, 0x10);
581 cx24116_writereg(state, 0xF0, 0x00);
582 cx24116_writereg(state, 0xF8, 0x06);
583
Darron Broad490c8682008-09-13 19:42:16 -0300584 /* Firmware CMD 10: VCO config */
585 cmd.args[0x00] = CMD_SET_VCO;
Steven Toth0d467482008-09-04 01:14:43 -0300586 cmd.args[0x01] = 0x05;
587 cmd.args[0x02] = 0xdc;
588 cmd.args[0x03] = 0xda;
589 cmd.args[0x04] = 0xae;
590 cmd.args[0x05] = 0xaa;
591 cmd.args[0x06] = 0x04;
592 cmd.args[0x07] = 0x9d;
593 cmd.args[0x08] = 0xfc;
594 cmd.args[0x09] = 0x06;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300595 cmd.len = 0x0a;
Steven Toth0d467482008-09-04 01:14:43 -0300596 ret = cx24116_cmd_execute(fe, &cmd);
597 if (ret != 0)
598 return ret;
599
Darron Broad490c8682008-09-13 19:42:16 -0300600 cx24116_writereg(state, CX24116_REG_SSTATUS, 0x00);
Steven Toth0d467482008-09-04 01:14:43 -0300601
Darron Broad490c8682008-09-13 19:42:16 -0300602 /* Firmware CMD 14: Tuner config */
603 cmd.args[0x00] = CMD_TUNERINIT;
Steven Toth0d467482008-09-04 01:14:43 -0300604 cmd.args[0x01] = 0x00;
605 cmd.args[0x02] = 0x00;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300606 cmd.len = 0x03;
Steven Toth0d467482008-09-04 01:14:43 -0300607 ret = cx24116_cmd_execute(fe, &cmd);
608 if (ret != 0)
609 return ret;
610
611 cx24116_writereg(state, 0xe5, 0x00);
612
Darron Broad490c8682008-09-13 19:42:16 -0300613 /* Firmware CMD 13: MPEG config */
614 cmd.args[0x00] = CMD_MPEGCONFIG;
Steven Toth0d467482008-09-04 01:14:43 -0300615 cmd.args[0x01] = 0x01;
616 cmd.args[0x02] = 0x75;
617 cmd.args[0x03] = 0x00;
Igor M. Liplianincc8c4f32008-09-09 13:57:47 -0300618 if (state->config->mpg_clk_pos_pol)
619 cmd.args[0x04] = state->config->mpg_clk_pos_pol;
620 else
621 cmd.args[0x04] = 0x02;
Steven Toth0d467482008-09-04 01:14:43 -0300622 cmd.args[0x05] = 0x00;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300623 cmd.len = 0x06;
Steven Toth0d467482008-09-04 01:14:43 -0300624 ret = cx24116_cmd_execute(fe, &cmd);
625 if (ret != 0)
626 return ret;
627
Darron Broad490c8682008-09-13 19:42:16 -0300628 /* Firmware CMD 35: Get firmware version */
629 cmd.args[0x00] = CMD_UPDFWVERS;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300630 cmd.len = 0x02;
631 for (i = 0; i < 4; i++) {
Darron Broad490c8682008-09-13 19:42:16 -0300632 cmd.args[0x01] = i;
633 ret = cx24116_cmd_execute(fe, &cmd);
634 if (ret != 0)
635 return ret;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300636 vers[i] = cx24116_readreg(state, CX24116_REG_MAILBOX);
Darron Broad490c8682008-09-13 19:42:16 -0300637 }
638 printk("%s: FW version %i.%i.%i.%i\n", __func__,
639 vers[0], vers[1], vers[2], vers[3]);
640
Steven Toth0d467482008-09-04 01:14:43 -0300641 return 0;
642}
643
Steven Tothf11ec7d2008-10-16 20:22:01 -0300644static int cx24116_set_voltage(struct dvb_frontend *fe,
645 fe_sec_voltage_t voltage)
Steven Toth0d467482008-09-04 01:14:43 -0300646{
647 /* The isl6421 module will override this function in the fops. */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300648 dprintk("%s() This should never appear if the isl6421 module "
649 "is loaded correctly\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -0300650
651 return -EOPNOTSUPP;
652}
653
Steven Tothf11ec7d2008-10-16 20:22:01 -0300654static int cx24116_read_status(struct dvb_frontend *fe, fe_status_t *status)
Steven Toth0d467482008-09-04 01:14:43 -0300655{
656 struct cx24116_state *state = fe->demodulator_priv;
657
Darron Broad490c8682008-09-13 19:42:16 -0300658 int lock = cx24116_readreg(state, CX24116_REG_SSTATUS);
Steven Toth0d467482008-09-04 01:14:43 -0300659
660 dprintk("%s: status = 0x%02x\n", __func__, lock);
661
662 *status = 0;
663
Darron Broad490c8682008-09-13 19:42:16 -0300664 if (lock & CX24116_HAS_SIGNAL)
Steven Toth0d467482008-09-04 01:14:43 -0300665 *status |= FE_HAS_SIGNAL;
Darron Broad490c8682008-09-13 19:42:16 -0300666 if (lock & CX24116_HAS_CARRIER)
Steven Toth0d467482008-09-04 01:14:43 -0300667 *status |= FE_HAS_CARRIER;
Darron Broad490c8682008-09-13 19:42:16 -0300668 if (lock & CX24116_HAS_VITERBI)
Steven Toth0d467482008-09-04 01:14:43 -0300669 *status |= FE_HAS_VITERBI;
Darron Broad490c8682008-09-13 19:42:16 -0300670 if (lock & CX24116_HAS_SYNCLOCK)
Steven Toth0d467482008-09-04 01:14:43 -0300671 *status |= FE_HAS_SYNC | FE_HAS_LOCK;
672
673 return 0;
674}
675
Steven Tothf11ec7d2008-10-16 20:22:01 -0300676static int cx24116_read_ber(struct dvb_frontend *fe, u32 *ber)
Steven Toth0d467482008-09-04 01:14:43 -0300677{
Darron Broad490c8682008-09-13 19:42:16 -0300678 struct cx24116_state *state = fe->demodulator_priv;
679
Steven Toth0d467482008-09-04 01:14:43 -0300680 dprintk("%s()\n", __func__);
Darron Broad490c8682008-09-13 19:42:16 -0300681
Steven Tothf11ec7d2008-10-16 20:22:01 -0300682 *ber = (cx24116_readreg(state, CX24116_REG_BER24) << 24) |
683 (cx24116_readreg(state, CX24116_REG_BER16) << 16) |
684 (cx24116_readreg(state, CX24116_REG_BER8) << 8) |
685 cx24116_readreg(state, CX24116_REG_BER0);
Steven Toth0d467482008-09-04 01:14:43 -0300686
687 return 0;
688}
689
Darron Broad490c8682008-09-13 19:42:16 -0300690/* TODO Determine function and scale appropriately */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300691static int cx24116_read_signal_strength(struct dvb_frontend *fe,
692 u16 *signal_strength)
Steven Toth0d467482008-09-04 01:14:43 -0300693{
694 struct cx24116_state *state = fe->demodulator_priv;
Darron Broad490c8682008-09-13 19:42:16 -0300695 struct cx24116_cmd cmd;
696 int ret;
697 u16 sig_reading;
698
699 dprintk("%s()\n", __func__);
700
701 /* Firmware CMD 19: Get AGC */
702 cmd.args[0x00] = CMD_GETAGC;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300703 cmd.len = 0x01;
Darron Broad490c8682008-09-13 19:42:16 -0300704 ret = cx24116_cmd_execute(fe, &cmd);
705 if (ret != 0)
706 return ret;
707
Steven Tothf11ec7d2008-10-16 20:22:01 -0300708 sig_reading =
709 (cx24116_readreg(state,
710 CX24116_REG_SSTATUS) & CX24116_SIGNAL_MASK) |
711 (cx24116_readreg(state, CX24116_REG_SIGNAL) << 6);
712 *signal_strength = 0 - sig_reading;
Darron Broad490c8682008-09-13 19:42:16 -0300713
Steven Tothf11ec7d2008-10-16 20:22:01 -0300714 dprintk("%s: raw / cooked = 0x%04x / 0x%04x\n",
715 __func__, sig_reading, *signal_strength);
Darron Broad490c8682008-09-13 19:42:16 -0300716
717 return 0;
718}
719
720/* SNR (0..100)% = (sig & 0xf0) * 10 + (sig & 0x0f) * 10 / 16 */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300721static int cx24116_read_snr_pct(struct dvb_frontend *fe, u16 *snr)
Darron Broad490c8682008-09-13 19:42:16 -0300722{
723 struct cx24116_state *state = fe->demodulator_priv;
724 u8 snr_reading;
725 static const u32 snr_tab[] = { /* 10 x Table (rounded up) */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300726 0x00000, 0x0199A, 0x03333, 0x04ccD, 0x06667,
727 0x08000, 0x0999A, 0x0b333, 0x0cccD, 0x0e667,
728 0x10000, 0x1199A, 0x13333, 0x14ccD, 0x16667,
729 0x18000 };
Steven Toth0d467482008-09-04 01:14:43 -0300730
731 dprintk("%s()\n", __func__);
732
Steven Toth8953db72008-10-06 21:20:21 -0300733 snr_reading = cx24116_readreg(state, CX24116_REG_QUALITY0);
Steven Toth0d467482008-09-04 01:14:43 -0300734
Steven Tothf11ec7d2008-10-16 20:22:01 -0300735 if (snr_reading >= 0xa0 /* 100% */)
Darron Broad490c8682008-09-13 19:42:16 -0300736 *snr = 0xffff;
Steven Toth0d467482008-09-04 01:14:43 -0300737 else
Steven Tothf11ec7d2008-10-16 20:22:01 -0300738 *snr = snr_tab[(snr_reading & 0xf0) >> 4] +
739 (snr_tab[(snr_reading & 0x0f)] >> 4);
Steven Toth0d467482008-09-04 01:14:43 -0300740
Darron Broad490c8682008-09-13 19:42:16 -0300741 dprintk("%s: raw / cooked = 0x%02x / 0x%04x\n", __func__,
742 snr_reading, *snr);
Steven Toth0d467482008-09-04 01:14:43 -0300743
744 return 0;
745}
746
Steven Toth8953db72008-10-06 21:20:21 -0300747/* The reelbox patches show the value in the registers represents
748 * ESNO, from 0->30db (values 0->300). We provide this value by
749 * default.
750 */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300751static int cx24116_read_snr_esno(struct dvb_frontend *fe, u16 *snr)
Steven Toth8953db72008-10-06 21:20:21 -0300752{
753 struct cx24116_state *state = fe->demodulator_priv;
754
755 dprintk("%s()\n", __func__);
756
757 *snr = cx24116_readreg(state, CX24116_REG_QUALITY8) << 8 |
758 cx24116_readreg(state, CX24116_REG_QUALITY0);
759
760 dprintk("%s: raw 0x%04x\n", __func__, *snr);
761
762 return 0;
763}
764
Steven Tothf11ec7d2008-10-16 20:22:01 -0300765static int cx24116_read_snr(struct dvb_frontend *fe, u16 *snr)
Steven Toth8953db72008-10-06 21:20:21 -0300766{
767 if (esno_snr == 1)
768 return cx24116_read_snr_esno(fe, snr);
769 else
770 return cx24116_read_snr_pct(fe, snr);
771}
772
Steven Tothf11ec7d2008-10-16 20:22:01 -0300773static int cx24116_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
Steven Toth0d467482008-09-04 01:14:43 -0300774{
Darron Broad490c8682008-09-13 19:42:16 -0300775 struct cx24116_state *state = fe->demodulator_priv;
776
Steven Toth0d467482008-09-04 01:14:43 -0300777 dprintk("%s()\n", __func__);
Darron Broad490c8682008-09-13 19:42:16 -0300778
Steven Tothf11ec7d2008-10-16 20:22:01 -0300779 *ucblocks = (cx24116_readreg(state, CX24116_REG_UCB8) << 8) |
Darron Broad490c8682008-09-13 19:42:16 -0300780 cx24116_readreg(state, CX24116_REG_UCB0);
Steven Toth0d467482008-09-04 01:14:43 -0300781
782 return 0;
783}
784
785/* Overwrite the current tuning params, we are about to tune */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300786static void cx24116_clone_params(struct dvb_frontend *fe)
Steven Toth0d467482008-09-04 01:14:43 -0300787{
788 struct cx24116_state *state = fe->demodulator_priv;
789 memcpy(&state->dcur, &state->dnxt, sizeof(state->dcur));
790}
791
Darron Broad490c8682008-09-13 19:42:16 -0300792/* Wait for LNB */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300793static int cx24116_wait_for_lnb(struct dvb_frontend *fe)
Darron Broad490c8682008-09-13 19:42:16 -0300794{
795 struct cx24116_state *state = fe->demodulator_priv;
796 int i;
797
798 dprintk("%s() qstatus = 0x%02x\n", __func__,
799 cx24116_readreg(state, CX24116_REG_QSTATUS));
800
801 /* Wait for up to 300 ms */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300802 for (i = 0; i < 30 ; i++) {
Darron Broad490c8682008-09-13 19:42:16 -0300803 if (cx24116_readreg(state, CX24116_REG_QSTATUS) & 0x20)
804 return 0;
805 msleep(10);
806 }
807
808 dprintk("%s(): LNB not ready\n", __func__);
809
810 return -ETIMEDOUT; /* -EBUSY ? */
811}
812
Steven Tothf11ec7d2008-10-16 20:22:01 -0300813static int cx24116_set_tone(struct dvb_frontend *fe,
814 fe_sec_tone_mode_t tone)
Steven Toth0d467482008-09-04 01:14:43 -0300815{
816 struct cx24116_cmd cmd;
817 int ret;
818
819 dprintk("%s(%d)\n", __func__, tone);
Steven Tothf11ec7d2008-10-16 20:22:01 -0300820 if ((tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF)) {
Steven Toth0d467482008-09-04 01:14:43 -0300821 printk("%s: Invalid, tone=%d\n", __func__, tone);
822 return -EINVAL;
823 }
824
Darron Broad490c8682008-09-13 19:42:16 -0300825 /* Wait for LNB ready */
826 ret = cx24116_wait_for_lnb(fe);
Steven Tothf11ec7d2008-10-16 20:22:01 -0300827 if (ret != 0)
Darron Broad490c8682008-09-13 19:42:16 -0300828 return ret;
829
830 /* Min delay time after DiSEqC send */
831 msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */
832
Steven Toth0d467482008-09-04 01:14:43 -0300833 /* This is always done before the tone is set */
834 cmd.args[0x00] = CMD_SET_TONEPRE;
835 cmd.args[0x01] = 0x00;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300836 cmd.len = 0x02;
Steven Toth0d467482008-09-04 01:14:43 -0300837 ret = cx24116_cmd_execute(fe, &cmd);
838 if (ret != 0)
839 return ret;
840
841 /* Now we set the tone */
842 cmd.args[0x00] = CMD_SET_TONE;
843 cmd.args[0x01] = 0x00;
844 cmd.args[0x02] = 0x00;
845
846 switch (tone) {
847 case SEC_TONE_ON:
848 dprintk("%s: setting tone on\n", __func__);
849 cmd.args[0x03] = 0x01;
850 break;
851 case SEC_TONE_OFF:
Steven Tothf11ec7d2008-10-16 20:22:01 -0300852 dprintk("%s: setting tone off\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -0300853 cmd.args[0x03] = 0x00;
854 break;
855 }
Steven Tothf11ec7d2008-10-16 20:22:01 -0300856 cmd.len = 0x04;
Steven Toth0d467482008-09-04 01:14:43 -0300857
Darron Broad490c8682008-09-13 19:42:16 -0300858 /* Min delay time before DiSEqC send */
859 msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */
860
Steven Toth0d467482008-09-04 01:14:43 -0300861 return cx24116_cmd_execute(fe, &cmd);
862}
863
864/* Initialise DiSEqC */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300865static int cx24116_diseqc_init(struct dvb_frontend *fe)
Steven Toth0d467482008-09-04 01:14:43 -0300866{
867 struct cx24116_state *state = fe->demodulator_priv;
Darron Broad490c8682008-09-13 19:42:16 -0300868 struct cx24116_cmd cmd;
869 int ret;
Steven Toth0d467482008-09-04 01:14:43 -0300870
Darron Broad490c8682008-09-13 19:42:16 -0300871 /* Firmware CMD 20: LNB/DiSEqC config */
872 cmd.args[0x00] = CMD_LNBCONFIG;
873 cmd.args[0x01] = 0x00;
874 cmd.args[0x02] = 0x10;
875 cmd.args[0x03] = 0x00;
876 cmd.args[0x04] = 0x8f;
877 cmd.args[0x05] = 0x28;
878 cmd.args[0x06] = (toneburst == CX24116_DISEQC_TONEOFF) ? 0x00 : 0x01;
879 cmd.args[0x07] = 0x01;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300880 cmd.len = 0x08;
Darron Broad490c8682008-09-13 19:42:16 -0300881 ret = cx24116_cmd_execute(fe, &cmd);
882 if (ret != 0)
883 return ret;
884
885 /* Prepare a DiSEqC command */
886 state->dsec_cmd.args[0x00] = CMD_LNBSEND;
887
888 /* DiSEqC burst */
889 state->dsec_cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_A;
890
891 /* Unknown */
892 state->dsec_cmd.args[CX24116_DISEQC_ARG2_2] = 0x02;
893 state->dsec_cmd.args[CX24116_DISEQC_ARG3_0] = 0x00;
894 state->dsec_cmd.args[CX24116_DISEQC_ARG4_0] = 0x00; /* Continuation flag? */
895
896 /* DiSEqC message length */
897 state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = 0x00;
898
899 /* Command length */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300900 state->dsec_cmd.len = CX24116_DISEQC_MSGOFS;
Steven Toth0d467482008-09-04 01:14:43 -0300901
902 return 0;
903}
904
905/* Send DiSEqC message with derived burst (hack) || previous burst */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300906static int cx24116_send_diseqc_msg(struct dvb_frontend *fe,
907 struct dvb_diseqc_master_cmd *d)
Steven Toth0d467482008-09-04 01:14:43 -0300908{
909 struct cx24116_state *state = fe->demodulator_priv;
Steven Toth0d467482008-09-04 01:14:43 -0300910 int i, ret;
911
912 /* Dump DiSEqC message */
913 if (debug) {
914 printk("cx24116: %s(", __func__);
Steven Tothf11ec7d2008-10-16 20:22:01 -0300915 for (i = 0 ; i < d->msg_len ;) {
Steven Toth0d467482008-09-04 01:14:43 -0300916 printk("0x%02x", d->msg[i]);
Steven Tothf11ec7d2008-10-16 20:22:01 -0300917 if (++i < d->msg_len)
Steven Toth0d467482008-09-04 01:14:43 -0300918 printk(", ");
Steven Tothf11ec7d2008-10-16 20:22:01 -0300919 }
Darron Broad490c8682008-09-13 19:42:16 -0300920 printk(") toneburst=%d\n", toneburst);
Steven Toth0d467482008-09-04 01:14:43 -0300921 }
922
Darron Broad490c8682008-09-13 19:42:16 -0300923 /* Validate length */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300924 if (d->msg_len > (CX24116_ARGLEN - CX24116_DISEQC_MSGOFS))
Steven Toth0d467482008-09-04 01:14:43 -0300925 return -EINVAL;
926
Steven Toth0d467482008-09-04 01:14:43 -0300927 /* DiSEqC message */
928 for (i = 0; i < d->msg_len; i++)
Darron Broad490c8682008-09-13 19:42:16 -0300929 state->dsec_cmd.args[CX24116_DISEQC_MSGOFS + i] = d->msg[i];
Steven Toth0d467482008-09-04 01:14:43 -0300930
Darron Broad490c8682008-09-13 19:42:16 -0300931 /* DiSEqC message length */
932 state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = d->msg_len;
Steven Toth0d467482008-09-04 01:14:43 -0300933
Darron Broad490c8682008-09-13 19:42:16 -0300934 /* Command length */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300935 state->dsec_cmd.len = CX24116_DISEQC_MSGOFS +
936 state->dsec_cmd.args[CX24116_DISEQC_MSGLEN];
Steven Toth0d467482008-09-04 01:14:43 -0300937
Darron Broad490c8682008-09-13 19:42:16 -0300938 /* DiSEqC toneburst */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300939 if (toneburst == CX24116_DISEQC_MESGCACHE)
Darron Broad490c8682008-09-13 19:42:16 -0300940 /* Message is cached */
941 return 0;
Steven Toth0d467482008-09-04 01:14:43 -0300942
Steven Tothf11ec7d2008-10-16 20:22:01 -0300943 else if (toneburst == CX24116_DISEQC_TONEOFF)
Darron Broad490c8682008-09-13 19:42:16 -0300944 /* Message is sent without burst */
945 state->dsec_cmd.args[CX24116_DISEQC_BURST] = 0;
946
Steven Tothf11ec7d2008-10-16 20:22:01 -0300947 else if (toneburst == CX24116_DISEQC_TONECACHE) {
Darron Broad490c8682008-09-13 19:42:16 -0300948 /*
949 * Message is sent with derived else cached burst
950 *
951 * WRITE PORT GROUP COMMAND 38
952 *
953 * 0/A/A: E0 10 38 F0..F3
954 * 1/B/B: E0 10 38 F4..F7
955 * 2/C/A: E0 10 38 F8..FB
956 * 3/D/B: E0 10 38 FC..FF
957 *
Darron Broad7396d3e2008-09-14 10:45:58 -0300958 * databyte[3]= 8421:8421
Darron Broad490c8682008-09-13 19:42:16 -0300959 * ABCD:WXYZ
960 * CLR :SET
961 *
962 * WX= PORT SELECT 0..3 (X=TONEBURST)
963 * Y = VOLTAGE (0=13V, 1=18V)
964 * Z = BAND (0=LOW, 1=HIGH(22K))
965 */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300966 if (d->msg_len >= 4 && d->msg[2] == 0x38)
967 state->dsec_cmd.args[CX24116_DISEQC_BURST] =
968 ((d->msg[3] & 4) >> 2);
969 if (debug)
970 dprintk("%s burst=%d\n", __func__,
971 state->dsec_cmd.args[CX24116_DISEQC_BURST]);
Darron Broad490c8682008-09-13 19:42:16 -0300972 }
973
974 /* Wait for LNB ready */
975 ret = cx24116_wait_for_lnb(fe);
Steven Tothf11ec7d2008-10-16 20:22:01 -0300976 if (ret != 0)
Darron Broad490c8682008-09-13 19:42:16 -0300977 return ret;
978
979 /* Wait for voltage/min repeat delay */
980 msleep(100);
981
982 /* Command */
983 ret = cx24116_cmd_execute(fe, &state->dsec_cmd);
Steven Tothf11ec7d2008-10-16 20:22:01 -0300984 if (ret != 0)
Darron Broad490c8682008-09-13 19:42:16 -0300985 return ret;
986 /*
987 * Wait for send
Steven Toth0d467482008-09-04 01:14:43 -0300988 *
989 * Eutelsat spec:
Darron Broad490c8682008-09-13 19:42:16 -0300990 * >15ms delay + (XXX determine if FW does this, see set_tone)
991 * 13.5ms per byte +
992 * >15ms delay +
993 * 12.5ms burst +
994 * >15ms delay (XXX determine if FW does this, see set_tone)
Steven Toth0d467482008-09-04 01:14:43 -0300995 */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300996 msleep((state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) +
997 ((toneburst == CX24116_DISEQC_TONEOFF) ? 30 : 60));
Steven Toth0d467482008-09-04 01:14:43 -0300998
Darron Broad490c8682008-09-13 19:42:16 -0300999 return 0;
Steven Toth0d467482008-09-04 01:14:43 -03001000}
1001
1002/* Send DiSEqC burst */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001003static int cx24116_diseqc_send_burst(struct dvb_frontend *fe,
1004 fe_sec_mini_cmd_t burst)
Steven Toth0d467482008-09-04 01:14:43 -03001005{
1006 struct cx24116_state *state = fe->demodulator_priv;
Steven Toth0d467482008-09-04 01:14:43 -03001007 int ret;
1008
Steven Tothf11ec7d2008-10-16 20:22:01 -03001009 dprintk("%s(%d) toneburst=%d\n", __func__, burst, toneburst);
Steven Toth0d467482008-09-04 01:14:43 -03001010
Darron Broad490c8682008-09-13 19:42:16 -03001011 /* DiSEqC burst */
Steven Toth0d467482008-09-04 01:14:43 -03001012 if (burst == SEC_MINI_A)
Steven Tothf11ec7d2008-10-16 20:22:01 -03001013 state->dsec_cmd.args[CX24116_DISEQC_BURST] =
1014 CX24116_DISEQC_MINI_A;
1015 else if (burst == SEC_MINI_B)
1016 state->dsec_cmd.args[CX24116_DISEQC_BURST] =
1017 CX24116_DISEQC_MINI_B;
Steven Toth0d467482008-09-04 01:14:43 -03001018 else
1019 return -EINVAL;
1020
Darron Broad490c8682008-09-13 19:42:16 -03001021 /* DiSEqC toneburst */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001022 if (toneburst != CX24116_DISEQC_MESGCACHE)
Darron Broad490c8682008-09-13 19:42:16 -03001023 /* Burst is cached */
1024 return 0;
Steven Toth0d467482008-09-04 01:14:43 -03001025
Darron Broad490c8682008-09-13 19:42:16 -03001026 /* Burst is to be sent with cached message */
Steven Toth0d467482008-09-04 01:14:43 -03001027
Darron Broad490c8682008-09-13 19:42:16 -03001028 /* Wait for LNB ready */
1029 ret = cx24116_wait_for_lnb(fe);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001030 if (ret != 0)
Darron Broad490c8682008-09-13 19:42:16 -03001031 return ret;
Steven Toth0d467482008-09-04 01:14:43 -03001032
Darron Broad490c8682008-09-13 19:42:16 -03001033 /* Wait for voltage/min repeat delay */
1034 msleep(100);
Steven Toth0d467482008-09-04 01:14:43 -03001035
Darron Broad490c8682008-09-13 19:42:16 -03001036 /* Command */
1037 ret = cx24116_cmd_execute(fe, &state->dsec_cmd);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001038 if (ret != 0)
Darron Broad490c8682008-09-13 19:42:16 -03001039 return ret;
1040
1041 /*
1042 * Wait for send
1043 *
1044 * Eutelsat spec:
1045 * >15ms delay + (XXX determine if FW does this, see set_tone)
1046 * 13.5ms per byte +
1047 * >15ms delay +
1048 * 12.5ms burst +
1049 * >15ms delay (XXX determine if FW does this, see set_tone)
1050 */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001051 msleep((state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) + 60);
Darron Broad490c8682008-09-13 19:42:16 -03001052
1053 return 0;
Steven Toth0d467482008-09-04 01:14:43 -03001054}
1055
Steven Tothf11ec7d2008-10-16 20:22:01 -03001056static void cx24116_release(struct dvb_frontend *fe)
Steven Toth0d467482008-09-04 01:14:43 -03001057{
Steven Tothf11ec7d2008-10-16 20:22:01 -03001058 struct cx24116_state *state = fe->demodulator_priv;
1059 dprintk("%s\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -03001060 kfree(state);
1061}
1062
1063static struct dvb_frontend_ops cx24116_ops;
1064
Steven Tothf11ec7d2008-10-16 20:22:01 -03001065struct dvb_frontend *cx24116_attach(const struct cx24116_config *config,
1066 struct i2c_adapter *i2c)
Steven Toth0d467482008-09-04 01:14:43 -03001067{
Steven Tothf11ec7d2008-10-16 20:22:01 -03001068 struct cx24116_state *state = NULL;
Steven Toth0d467482008-09-04 01:14:43 -03001069 int ret;
1070
Steven Tothf11ec7d2008-10-16 20:22:01 -03001071 dprintk("%s\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -03001072
1073 /* allocate memory for the internal state */
1074 state = kmalloc(sizeof(struct cx24116_state), GFP_KERNEL);
1075 if (state == NULL) {
1076 printk("Unable to kmalloc\n");
Darron Broad7396d3e2008-09-14 10:45:58 -03001077 goto error1;
Steven Toth0d467482008-09-04 01:14:43 -03001078 }
1079
1080 /* setup the state */
1081 memset(state, 0, sizeof(struct cx24116_state));
1082
1083 state->config = config;
1084 state->i2c = i2c;
1085
1086 /* check if the demod is present */
1087 ret = (cx24116_readreg(state, 0xFF) << 8) | cx24116_readreg(state, 0xFE);
1088 if (ret != 0x0501) {
1089 printk("Invalid probe, probably not a CX24116 device\n");
Darron Broad7396d3e2008-09-14 10:45:58 -03001090 goto error2;
Steven Toth0d467482008-09-04 01:14:43 -03001091 }
1092
1093 /* create dvb_frontend */
1094 memcpy(&state->frontend.ops, &cx24116_ops, sizeof(struct dvb_frontend_ops));
1095 state->frontend.demodulator_priv = state;
1096 return &state->frontend;
1097
Darron Broad7396d3e2008-09-14 10:45:58 -03001098error2: kfree(state);
Darron Broad490c8682008-09-13 19:42:16 -03001099error1: return NULL;
Steven Toth0d467482008-09-04 01:14:43 -03001100}
Steven Tothf11ec7d2008-10-16 20:22:01 -03001101EXPORT_SYMBOL(cx24116_attach);
1102
Darron Broad490c8682008-09-13 19:42:16 -03001103/*
1104 * Initialise or wake up device
1105 *
1106 * Power config will reset and load initial firmware if required
1107 */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001108static int cx24116_initfe(struct dvb_frontend *fe)
Steven Toth0d467482008-09-04 01:14:43 -03001109{
Steven Tothf11ec7d2008-10-16 20:22:01 -03001110 struct cx24116_state *state = fe->demodulator_priv;
Darron Broad490c8682008-09-13 19:42:16 -03001111 struct cx24116_cmd cmd;
1112 int ret;
1113
Steven Tothf11ec7d2008-10-16 20:22:01 -03001114 dprintk("%s()\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -03001115
Darron Broad490c8682008-09-13 19:42:16 -03001116 /* Power on */
1117 cx24116_writereg(state, 0xe0, 0);
1118 cx24116_writereg(state, 0xe1, 0);
1119 cx24116_writereg(state, 0xea, 0);
1120
1121 /* Firmware CMD 36: Power config */
1122 cmd.args[0x00] = CMD_TUNERSLEEP;
1123 cmd.args[0x01] = 0;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001124 cmd.len = 0x02;
Darron Broad490c8682008-09-13 19:42:16 -03001125 ret = cx24116_cmd_execute(fe, &cmd);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001126 if (ret != 0)
Darron Broad490c8682008-09-13 19:42:16 -03001127 return ret;
1128
Steven Toth0d467482008-09-04 01:14:43 -03001129 return cx24116_diseqc_init(fe);
1130}
1131
Darron Broad490c8682008-09-13 19:42:16 -03001132/*
1133 * Put device to sleep
1134 */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001135static int cx24116_sleep(struct dvb_frontend *fe)
Darron Broad490c8682008-09-13 19:42:16 -03001136{
Steven Tothf11ec7d2008-10-16 20:22:01 -03001137 struct cx24116_state *state = fe->demodulator_priv;
Darron Broad490c8682008-09-13 19:42:16 -03001138 struct cx24116_cmd cmd;
1139 int ret;
1140
Steven Tothf11ec7d2008-10-16 20:22:01 -03001141 dprintk("%s()\n", __func__);
Darron Broad490c8682008-09-13 19:42:16 -03001142
1143 /* Firmware CMD 36: Power config */
1144 cmd.args[0x00] = CMD_TUNERSLEEP;
1145 cmd.args[0x01] = 1;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001146 cmd.len = 0x02;
Darron Broad490c8682008-09-13 19:42:16 -03001147 ret = cx24116_cmd_execute(fe, &cmd);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001148 if (ret != 0)
Darron Broad490c8682008-09-13 19:42:16 -03001149 return ret;
1150
1151 /* Power off (Shutdown clocks) */
1152 cx24116_writereg(state, 0xea, 0xff);
1153 cx24116_writereg(state, 0xe1, 1);
1154 cx24116_writereg(state, 0xe0, 1);
1155
1156 return 0;
1157}
1158
Steven Tothf11ec7d2008-10-16 20:22:01 -03001159static int cx24116_set_property(struct dvb_frontend *fe,
1160 struct dtv_property *tvp)
Steven Toth0d467482008-09-04 01:14:43 -03001161{
1162 dprintk("%s(..)\n", __func__);
1163 return 0;
1164}
1165
Steven Tothf11ec7d2008-10-16 20:22:01 -03001166static int cx24116_get_property(struct dvb_frontend *fe,
1167 struct dtv_property *tvp)
Steven Toth0d467482008-09-04 01:14:43 -03001168{
Steven Tothbfbf2da2008-09-12 01:37:37 -03001169 dprintk("%s(..)\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -03001170 return 0;
1171}
1172
1173/* dvb-core told us to tune, the tv property cache will be complete,
1174 * it's safe for is to pull values and use them for tuning purposes.
1175 */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001176static int cx24116_set_frontend(struct dvb_frontend *fe,
1177 struct dvb_frontend_parameters *p)
Steven Toth0d467482008-09-04 01:14:43 -03001178{
1179 struct cx24116_state *state = fe->demodulator_priv;
Steven Toth56f06802008-09-11 10:19:27 -03001180 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
Steven Toth0d467482008-09-04 01:14:43 -03001181 struct cx24116_cmd cmd;
1182 fe_status_t tunerstat;
Darron Broad01a8f032008-10-03 11:47:46 -03001183 int i, status, ret, retune;
Steven Toth0d467482008-09-04 01:14:43 -03001184
Steven Tothf11ec7d2008-10-16 20:22:01 -03001185 dprintk("%s()\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -03001186
Steven Tothf11ec7d2008-10-16 20:22:01 -03001187 switch (c->delivery_system) {
1188 case SYS_DVBS:
1189 dprintk("%s: DVB-S delivery system selected\n", __func__);
Darron Broad01a8f032008-10-03 11:47:46 -03001190
Steven Tothf11ec7d2008-10-16 20:22:01 -03001191 /* Only QPSK is supported for DVB-S */
1192 if (c->modulation != QPSK) {
1193 dprintk("%s: unsupported modulation selected (%d)\n",
1194 __func__, c->modulation);
1195 return -EOPNOTSUPP;
1196 }
Darron Broad01a8f032008-10-03 11:47:46 -03001197
Steven Tothf11ec7d2008-10-16 20:22:01 -03001198 /* Pilot doesn't exist in DVB-S, turn bit off */
1199 state->dnxt.pilot_val = CX24116_PILOT_OFF;
1200 retune = 1;
1201
1202 /* DVB-S only supports 0.35 */
1203 if (c->rolloff != ROLLOFF_35) {
1204 dprintk("%s: unsupported rolloff selected (%d)\n",
1205 __func__, c->rolloff);
1206 return -EOPNOTSUPP;
1207 }
1208 state->dnxt.rolloff_val = CX24116_ROLLOFF_035;
1209 break;
1210
1211 case SYS_DVBS2:
1212 dprintk("%s: DVB-S2 delivery system selected\n", __func__);
1213
1214 /*
1215 * NBC 8PSK/QPSK with DVB-S is supported for DVB-S2,
1216 * but not hardware auto detection
1217 */
1218 if (c->modulation != PSK_8 && c->modulation != QPSK) {
1219 dprintk("%s: unsupported modulation selected (%d)\n",
1220 __func__, c->modulation);
1221 return -EOPNOTSUPP;
1222 }
1223
1224 switch (c->pilot) {
1225 case PILOT_AUTO: /* Not supported but emulated */
1226 retune = 2; /* Fall-through */
1227 case PILOT_OFF:
Darron Broad01a8f032008-10-03 11:47:46 -03001228 state->dnxt.pilot_val = CX24116_PILOT_OFF;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001229 break;
1230 case PILOT_ON:
1231 state->dnxt.pilot_val = CX24116_PILOT_ON;
1232 break;
1233 default:
1234 dprintk("%s: unsupported pilot mode selected (%d)\n",
1235 __func__, c->pilot);
1236 return -EOPNOTSUPP;
1237 }
Darron Broad01a8f032008-10-03 11:47:46 -03001238
Steven Tothf11ec7d2008-10-16 20:22:01 -03001239 switch (c->rolloff) {
1240 case ROLLOFF_20:
1241 state->dnxt.rolloff_val = CX24116_ROLLOFF_020;
1242 break;
1243 case ROLLOFF_25:
1244 state->dnxt.rolloff_val = CX24116_ROLLOFF_025;
1245 break;
1246 case ROLLOFF_35:
Darron Broad7396d3e2008-09-14 10:45:58 -03001247 state->dnxt.rolloff_val = CX24116_ROLLOFF_035;
Darron Broad490c8682008-09-13 19:42:16 -03001248 break;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001249 case ROLLOFF_AUTO: /* Rolloff must be explicit */
Darron Broad490c8682008-09-13 19:42:16 -03001250 default:
Steven Tothf11ec7d2008-10-16 20:22:01 -03001251 dprintk("%s: unsupported rolloff selected (%d)\n",
1252 __func__, c->rolloff);
Darron Broad490c8682008-09-13 19:42:16 -03001253 return -EOPNOTSUPP;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001254 }
1255 break;
1256
1257 default:
1258 dprintk("%s: unsupported delivery system selected (%d)\n",
1259 __func__, c->delivery_system);
1260 return -EOPNOTSUPP;
Darron Broad490c8682008-09-13 19:42:16 -03001261 }
Darron Broad01a8f032008-10-03 11:47:46 -03001262 state->dnxt.modulation = c->modulation;
1263 state->dnxt.frequency = c->frequency;
1264 state->dnxt.pilot = c->pilot;
1265 state->dnxt.rolloff = c->rolloff;
Darron Broad490c8682008-09-13 19:42:16 -03001266
Steven Tothf11ec7d2008-10-16 20:22:01 -03001267 ret = cx24116_set_inversion(state, c->inversion);
1268 if (ret != 0)
Steven Toth0d467482008-09-04 01:14:43 -03001269 return ret;
1270
Darron Broad01a8f032008-10-03 11:47:46 -03001271 /* FEC_NONE/AUTO for DVB-S2 is not supported and detected here */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001272 ret = cx24116_set_fec(state, c->modulation, c->fec_inner);
1273 if (ret != 0)
Steven Toth0d467482008-09-04 01:14:43 -03001274 return ret;
1275
Steven Tothf11ec7d2008-10-16 20:22:01 -03001276 ret = cx24116_set_symbolrate(state, c->symbol_rate);
1277 if (ret != 0)
Steven Toth0d467482008-09-04 01:14:43 -03001278 return ret;
1279
1280 /* discard the 'current' tuning parameters and prepare to tune */
1281 cx24116_clone_params(fe);
1282
Darron Broad01a8f032008-10-03 11:47:46 -03001283 dprintk("%s: modulation = %d\n", __func__, state->dcur.modulation);
Steven Toth0d467482008-09-04 01:14:43 -03001284 dprintk("%s: frequency = %d\n", __func__, state->dcur.frequency);
Darron Broad01a8f032008-10-03 11:47:46 -03001285 dprintk("%s: pilot = %d (val = 0x%02x)\n", __func__,
1286 state->dcur.pilot, state->dcur.pilot_val);
1287 dprintk("%s: retune = %d\n", __func__, retune);
1288 dprintk("%s: rolloff = %d (val = 0x%02x)\n", __func__,
1289 state->dcur.rolloff, state->dcur.rolloff_val);
Steven Toth0d467482008-09-04 01:14:43 -03001290 dprintk("%s: symbol_rate = %d\n", __func__, state->dcur.symbol_rate);
1291 dprintk("%s: FEC = %d (mask/val = 0x%02x/0x%02x)\n", __func__,
1292 state->dcur.fec, state->dcur.fec_mask, state->dcur.fec_val);
1293 dprintk("%s: Inversion = %d (val = 0x%02x)\n", __func__,
1294 state->dcur.inversion, state->dcur.inversion_val);
1295
Darron Broad490c8682008-09-13 19:42:16 -03001296 /* This is also done in advise/acquire on HVR4000 but not on LITE */
Steven Toth0d467482008-09-04 01:14:43 -03001297 if (state->config->set_ts_params)
1298 state->config->set_ts_params(fe, 0);
1299
Darron Broad490c8682008-09-13 19:42:16 -03001300 /* Set/Reset B/W */
1301 cmd.args[0x00] = CMD_BANDWIDTH;
1302 cmd.args[0x01] = 0x01;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001303 cmd.len = 0x02;
Darron Broad490c8682008-09-13 19:42:16 -03001304 ret = cx24116_cmd_execute(fe, &cmd);
1305 if (ret != 0)
1306 return ret;
Igor M. Liplianin3f8e51a2008-09-09 13:22:29 -03001307
Steven Toth0d467482008-09-04 01:14:43 -03001308 /* Prepare a tune request */
1309 cmd.args[0x00] = CMD_TUNEREQUEST;
1310
1311 /* Frequency */
1312 cmd.args[0x01] = (state->dcur.frequency & 0xff0000) >> 16;
1313 cmd.args[0x02] = (state->dcur.frequency & 0x00ff00) >> 8;
1314 cmd.args[0x03] = (state->dcur.frequency & 0x0000ff);
1315
1316 /* Symbol Rate */
1317 cmd.args[0x04] = ((state->dcur.symbol_rate / 1000) & 0xff00) >> 8;
1318 cmd.args[0x05] = ((state->dcur.symbol_rate / 1000) & 0x00ff);
1319
1320 /* Automatic Inversion */
1321 cmd.args[0x06] = state->dcur.inversion_val;
1322
Darron Broad01a8f032008-10-03 11:47:46 -03001323 /* Modulation / FEC / Pilot */
1324 cmd.args[0x07] = state->dcur.fec_val | state->dcur.pilot_val;
Steven Toth0d467482008-09-04 01:14:43 -03001325
1326 cmd.args[0x08] = CX24116_SEARCH_RANGE_KHZ >> 8;
1327 cmd.args[0x09] = CX24116_SEARCH_RANGE_KHZ & 0xff;
1328 cmd.args[0x0a] = 0x00;
1329 cmd.args[0x0b] = 0x00;
Darron Broad490c8682008-09-13 19:42:16 -03001330 cmd.args[0x0c] = state->dcur.rolloff_val;
Steven Toth0d467482008-09-04 01:14:43 -03001331 cmd.args[0x0d] = state->dcur.fec_mask;
Igor M. Liplianin3f8e51a2008-09-09 13:22:29 -03001332
Darron Broad490c8682008-09-13 19:42:16 -03001333 if (state->dcur.symbol_rate > 30000000) {
Igor M. Liplianin3f8e51a2008-09-09 13:22:29 -03001334 cmd.args[0x0e] = 0x04;
1335 cmd.args[0x0f] = 0x00;
1336 cmd.args[0x10] = 0x01;
1337 cmd.args[0x11] = 0x77;
1338 cmd.args[0x12] = 0x36;
Darron Broad490c8682008-09-13 19:42:16 -03001339 cx24116_writereg(state, CX24116_REG_CLKDIV, 0x44);
1340 cx24116_writereg(state, CX24116_REG_RATEDIV, 0x01);
Igor M. Liplianin3f8e51a2008-09-09 13:22:29 -03001341 } else {
1342 cmd.args[0x0e] = 0x06;
1343 cmd.args[0x0f] = 0x00;
1344 cmd.args[0x10] = 0x00;
1345 cmd.args[0x11] = 0xFA;
1346 cmd.args[0x12] = 0x24;
Darron Broad490c8682008-09-13 19:42:16 -03001347 cx24116_writereg(state, CX24116_REG_CLKDIV, 0x46);
1348 cx24116_writereg(state, CX24116_REG_RATEDIV, 0x00);
Igor M. Liplianin3f8e51a2008-09-09 13:22:29 -03001349 }
1350
Steven Tothf11ec7d2008-10-16 20:22:01 -03001351 cmd.len = 0x13;
Steven Toth0d467482008-09-04 01:14:43 -03001352
1353 /* We need to support pilot and non-pilot tuning in the
1354 * driver automatically. This is a workaround for because
1355 * the demod does not support autodetect.
1356 */
1357 do {
Darron Broad490c8682008-09-13 19:42:16 -03001358 /* Reset status register */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001359 status = cx24116_readreg(state, CX24116_REG_SSTATUS)
1360 & CX24116_SIGNAL_MASK;
Darron Broad490c8682008-09-13 19:42:16 -03001361 cx24116_writereg(state, CX24116_REG_SSTATUS, status);
Steven Toth0d467482008-09-04 01:14:43 -03001362
1363 /* Tune */
1364 ret = cx24116_cmd_execute(fe, &cmd);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001365 if (ret != 0)
Steven Toth0d467482008-09-04 01:14:43 -03001366 break;
1367
Darron Broad490c8682008-09-13 19:42:16 -03001368 /*
1369 * Wait for up to 500 ms before retrying
1370 *
1371 * If we are able to tune then generally it occurs within 100ms.
1372 * If it takes longer, try a different toneburst setting.
1373 */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001374 for (i = 0; i < 50 ; i++) {
Darron Broad490c8682008-09-13 19:42:16 -03001375 cx24116_read_status(fe, &tunerstat);
1376 status = tunerstat & (FE_HAS_SIGNAL | FE_HAS_SYNC);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001377 if (status == (FE_HAS_SIGNAL | FE_HAS_SYNC)) {
1378 dprintk("%s: Tuned\n", __func__);
Darron Broad490c8682008-09-13 19:42:16 -03001379 goto tuned;
1380 }
1381 msleep(10);
Steven Toth0d467482008-09-04 01:14:43 -03001382 }
Darron Broad490c8682008-09-13 19:42:16 -03001383
Steven Tothf11ec7d2008-10-16 20:22:01 -03001384 dprintk("%s: Not tuned\n", __func__);
Darron Broad490c8682008-09-13 19:42:16 -03001385
1386 /* Toggle pilot bit when in auto-pilot */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001387 if (state->dcur.pilot == PILOT_AUTO)
Darron Broad01a8f032008-10-03 11:47:46 -03001388 cmd.args[0x07] ^= CX24116_PILOT_ON;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001389 } while (--retune);
Steven Toth0d467482008-09-04 01:14:43 -03001390
Darron Broad490c8682008-09-13 19:42:16 -03001391tuned: /* Set/Reset B/W */
1392 cmd.args[0x00] = CMD_BANDWIDTH;
1393 cmd.args[0x01] = 0x00;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001394 cmd.len = 0x02;
Darron Broad490c8682008-09-13 19:42:16 -03001395 ret = cx24116_cmd_execute(fe, &cmd);
1396 if (ret != 0)
1397 return ret;
1398
Steven Toth0d467482008-09-04 01:14:43 -03001399 return ret;
1400}
1401
1402static struct dvb_frontend_ops cx24116_ops = {
1403
1404 .info = {
1405 .name = "Conexant CX24116/CX24118",
1406 .type = FE_QPSK,
1407 .frequency_min = 950000,
1408 .frequency_max = 2150000,
1409 .frequency_stepsize = 1011, /* kHz for QPSK frontends */
1410 .frequency_tolerance = 5000,
1411 .symbol_rate_min = 1000000,
1412 .symbol_rate_max = 45000000,
1413 .caps = FE_CAN_INVERSION_AUTO |
1414 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
1415 FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
1416 FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
1417 FE_CAN_QPSK | FE_CAN_RECOVER
1418 },
1419
1420 .release = cx24116_release,
1421
1422 .init = cx24116_initfe,
Darron Broad490c8682008-09-13 19:42:16 -03001423 .sleep = cx24116_sleep,
Steven Toth0d467482008-09-04 01:14:43 -03001424 .read_status = cx24116_read_status,
1425 .read_ber = cx24116_read_ber,
1426 .read_signal_strength = cx24116_read_signal_strength,
1427 .read_snr = cx24116_read_snr,
1428 .read_ucblocks = cx24116_read_ucblocks,
1429 .set_tone = cx24116_set_tone,
1430 .set_voltage = cx24116_set_voltage,
1431 .diseqc_send_master_cmd = cx24116_send_diseqc_msg,
1432 .diseqc_send_burst = cx24116_diseqc_send_burst,
1433
1434 .set_property = cx24116_set_property,
Steven Tothbfbf2da2008-09-12 01:37:37 -03001435 .get_property = cx24116_get_property,
Steven Toth0d467482008-09-04 01:14:43 -03001436 .set_frontend = cx24116_set_frontend,
1437};
1438
Steven Toth0d467482008-09-04 01:14:43 -03001439MODULE_DESCRIPTION("DVB Frontend module for Conexant cx24116/cx24118 hardware");
1440MODULE_AUTHOR("Steven Toth");
1441MODULE_LICENSE("GPL");
1442