blob: 8afdfbec551b4574a4b9ecc880a7668d811e4eb9 [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) \
Steven Toth98c94822008-10-16 20:24:42 -030051 printk(KERN_INFO "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)
Steven Toth98c94822008-10-16 20:24:42 -030075
76/* configured fec (not tuned) or actual FEC (tuned) 1=1/2 2=2/3 etc */
77#define CX24116_REG_FECSTATUS (0x9c)
Darron Broad681faa02008-09-22 00:47:20 -030078
79/* FECSTATUS bits */
Steven Toth98c94822008-10-16 20:24:42 -030080/* mask to determine configured fec (not tuned) or actual fec (tuned) */
81#define CX24116_FEC_FECMASK (0x1f)
82
83/* Select DVB-S demodulator, else DVB-S2 */
84#define CX24116_FEC_DVBS (0x20)
Darron Broad681faa02008-09-22 00:47:20 -030085#define CX24116_FEC_UNKNOWN (0x40) /* Unknown/unused */
Steven Toth98c94822008-10-16 20:24:42 -030086
87/* Pilot mode requested when tuning else always reset when tuned */
88#define CX24116_FEC_PILOT (0x80)
Steven Toth0d467482008-09-04 01:14:43 -030089
90/* arg buffer size */
91#define CX24116_ARGLEN (0x1e)
92
Darron Broad490c8682008-09-13 19:42:16 -030093/* rolloff */
94#define CX24116_ROLLOFF_020 (0x00)
95#define CX24116_ROLLOFF_025 (0x01)
96#define CX24116_ROLLOFF_035 (0x02)
97
98/* pilot bit */
Darron Broad01a8f032008-10-03 11:47:46 -030099#define CX24116_PILOT_OFF (0x00)
100#define CX24116_PILOT_ON (0x40)
Darron Broad490c8682008-09-13 19:42:16 -0300101
102/* signal status */
103#define CX24116_HAS_SIGNAL (0x01)
104#define CX24116_HAS_CARRIER (0x02)
105#define CX24116_HAS_VITERBI (0x04)
106#define CX24116_HAS_SYNCLOCK (0x08)
107#define CX24116_HAS_UNKNOWN1 (0x10)
108#define CX24116_HAS_UNKNOWN2 (0x20)
109#define CX24116_STATUS_MASK (0x3f)
110#define CX24116_SIGNAL_MASK (0xc0)
111
112#define CX24116_DISEQC_TONEOFF (0) /* toneburst never sent */
113#define CX24116_DISEQC_TONECACHE (1) /* toneburst cached */
114#define CX24116_DISEQC_MESGCACHE (2) /* message cached */
115
Steven Toth0d467482008-09-04 01:14:43 -0300116/* arg offset for DiSEqC */
117#define CX24116_DISEQC_BURST (1)
118#define CX24116_DISEQC_ARG2_2 (2) /* unknown value=2 */
119#define CX24116_DISEQC_ARG3_0 (3) /* unknown value=0 */
120#define CX24116_DISEQC_ARG4_0 (4) /* unknown value=0 */
121#define CX24116_DISEQC_MSGLEN (5)
122#define CX24116_DISEQC_MSGOFS (6)
123
124/* DiSEqC burst */
125#define CX24116_DISEQC_MINI_A (0)
126#define CX24116_DISEQC_MINI_B (1)
127
Darron Broad490c8682008-09-13 19:42:16 -0300128/* DiSEqC tone burst */
129static int toneburst = 1;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300130module_param(toneburst, int, 0644);
Steven Toth98c94822008-10-16 20:24:42 -0300131MODULE_PARM_DESC(toneburst, "DiSEqC toneburst 0=OFF, 1=TONE CACHE, "\
132 "2=MESSAGE CACHE (default:1)");
Darron Broad490c8682008-09-13 19:42:16 -0300133
Steven Toth8953db72008-10-06 21:20:21 -0300134/* SNR measurements */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300135static int esno_snr;
136module_param(esno_snr, int, 0644);
Steven Toth98c94822008-10-16 20:24:42 -0300137MODULE_PARM_DESC(debug, "SNR return units, 0=PERCENTAGE 0-100, "\
138 "1=ESNO(db * 10) (default:0)");
Steven Toth8953db72008-10-06 21:20:21 -0300139
Steven Tothf11ec7d2008-10-16 20:22:01 -0300140enum cmds {
Darron Broad490c8682008-09-13 19:42:16 -0300141 CMD_SET_VCO = 0x10,
Steven Toth0d467482008-09-04 01:14:43 -0300142 CMD_TUNEREQUEST = 0x11,
Darron Broad490c8682008-09-13 19:42:16 -0300143 CMD_MPEGCONFIG = 0x13,
144 CMD_TUNERINIT = 0x14,
145 CMD_BANDWIDTH = 0x15,
146 CMD_GETAGC = 0x19,
147 CMD_LNBCONFIG = 0x20,
148 CMD_LNBSEND = 0x21, /* Formerly CMD_SEND_DISEQC */
Steven Toth0d467482008-09-04 01:14:43 -0300149 CMD_SET_TONEPRE = 0x22,
150 CMD_SET_TONE = 0x23,
Darron Broad490c8682008-09-13 19:42:16 -0300151 CMD_UPDFWVERS = 0x35,
152 CMD_TUNERSLEEP = 0x36,
153 CMD_AGCCONTROL = 0x3b, /* Unknown */
Steven Toth0d467482008-09-04 01:14:43 -0300154};
155
156/* The Demod/Tuner can't easily provide these, we cache them */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300157struct cx24116_tuning {
Steven Toth0d467482008-09-04 01:14:43 -0300158 u32 frequency;
159 u32 symbol_rate;
160 fe_spectral_inversion_t inversion;
161 fe_code_rate_t fec;
162
163 fe_modulation_t modulation;
Darron Broad490c8682008-09-13 19:42:16 -0300164 fe_pilot_t pilot;
165 fe_rolloff_t rolloff;
Steven Toth0d467482008-09-04 01:14:43 -0300166
167 /* Demod values */
168 u8 fec_val;
169 u8 fec_mask;
170 u8 inversion_val;
Darron Broad01a8f032008-10-03 11:47:46 -0300171 u8 pilot_val;
Darron Broad490c8682008-09-13 19:42:16 -0300172 u8 rolloff_val;
Steven Toth0d467482008-09-04 01:14:43 -0300173};
174
175/* Basic commands that are sent to the firmware */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300176struct cx24116_cmd {
Steven Toth0d467482008-09-04 01:14:43 -0300177 u8 len;
178 u8 args[CX24116_ARGLEN];
179};
180
Steven Tothf11ec7d2008-10-16 20:22:01 -0300181struct cx24116_state {
182 struct i2c_adapter *i2c;
183 const struct cx24116_config *config;
Steven Toth0d467482008-09-04 01:14:43 -0300184
185 struct dvb_frontend frontend;
186
187 struct cx24116_tuning dcur;
188 struct cx24116_tuning dnxt;
189
190 u8 skip_fw_load;
191 u8 burst;
Darron Broad490c8682008-09-13 19:42:16 -0300192 struct cx24116_cmd dsec_cmd;
Steven Toth0d467482008-09-04 01:14:43 -0300193};
194
Steven Tothf11ec7d2008-10-16 20:22:01 -0300195static int cx24116_writereg(struct cx24116_state *state, int reg, int data)
Steven Toth0d467482008-09-04 01:14:43 -0300196{
197 u8 buf[] = { reg, data };
198 struct i2c_msg msg = { .addr = state->config->demod_address,
199 .flags = 0, .buf = buf, .len = 2 };
200 int err;
201
Steven Tothf11ec7d2008-10-16 20:22:01 -0300202 if (debug > 1)
Steven Toth0d467482008-09-04 01:14:43 -0300203 printk("cx24116: %s: write reg 0x%02x, value 0x%02x\n",
Steven Tothf11ec7d2008-10-16 20:22:01 -0300204 __func__, reg, data);
Steven Toth0d467482008-09-04 01:14:43 -0300205
Steven Tothf11ec7d2008-10-16 20:22:01 -0300206 err = i2c_transfer(state->i2c, &msg, 1);
207 if (err != 1) {
Steven Toth98c94822008-10-16 20:24:42 -0300208 printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x,"
Steven Toth0d467482008-09-04 01:14:43 -0300209 " value == 0x%02x)\n", __func__, err, reg, data);
210 return -EREMOTEIO;
211 }
212
213 return 0;
214}
215
216/* Bulk byte writes to a single I2C address, for 32k firmware load */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300217static int cx24116_writeregN(struct cx24116_state *state, int reg,
218 u8 *data, u16 len)
Steven Toth0d467482008-09-04 01:14:43 -0300219{
220 int ret = -EREMOTEIO;
221 struct i2c_msg msg;
222 u8 *buf;
223
224 buf = kmalloc(len + 1, GFP_KERNEL);
225 if (buf == NULL) {
226 printk("Unable to kmalloc\n");
227 ret = -ENOMEM;
228 goto error;
229 }
230
231 *(buf) = reg;
232 memcpy(buf + 1, data, len);
233
234 msg.addr = state->config->demod_address;
235 msg.flags = 0;
236 msg.buf = buf;
237 msg.len = len + 1;
238
Steven Tothf11ec7d2008-10-16 20:22:01 -0300239 if (debug > 1)
Steven Toth98c94822008-10-16 20:24:42 -0300240 printk(KERN_INFO "cx24116: %s: write regN 0x%02x, len = %d\n",
Steven Tothf11ec7d2008-10-16 20:22:01 -0300241 __func__, reg, len);
Steven Toth0d467482008-09-04 01:14:43 -0300242
Steven Tothf11ec7d2008-10-16 20:22:01 -0300243 ret = i2c_transfer(state->i2c, &msg, 1);
244 if (ret != 1) {
Steven Toth98c94822008-10-16 20:24:42 -0300245 printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x\n",
Steven Toth0d467482008-09-04 01:14:43 -0300246 __func__, ret, reg);
247 ret = -EREMOTEIO;
248 }
249
250error:
251 kfree(buf);
252
253 return ret;
254}
255
Steven Tothf11ec7d2008-10-16 20:22:01 -0300256static int cx24116_readreg(struct cx24116_state *state, u8 reg)
Steven Toth0d467482008-09-04 01:14:43 -0300257{
258 int ret;
259 u8 b0[] = { reg };
260 u8 b1[] = { 0 };
261 struct i2c_msg msg[] = {
Steven Tothf11ec7d2008-10-16 20:22:01 -0300262 { .addr = state->config->demod_address, .flags = 0,
263 .buf = b0, .len = 1 },
264 { .addr = state->config->demod_address, .flags = I2C_M_RD,
265 .buf = b1, .len = 1 }
Steven Toth0d467482008-09-04 01:14:43 -0300266 };
267
268 ret = i2c_transfer(state->i2c, msg, 2);
269
270 if (ret != 2) {
Steven Toth98c94822008-10-16 20:24:42 -0300271 printk(KERN_ERR "%s: reg=0x%x (error=%d)\n",
272 __func__, reg, ret);
Steven Toth0d467482008-09-04 01:14:43 -0300273 return ret;
274 }
275
Steven Tothf11ec7d2008-10-16 20:22:01 -0300276 if (debug > 1)
Steven Toth98c94822008-10-16 20:24:42 -0300277 printk(KERN_INFO "cx24116: read reg 0x%02x, value 0x%02x\n",
Steven Tothf11ec7d2008-10-16 20:22:01 -0300278 reg, b1[0]);
Steven Toth0d467482008-09-04 01:14:43 -0300279
280 return b1[0];
281}
282
Steven Toth98c94822008-10-16 20:24:42 -0300283static int cx24116_set_inversion(struct cx24116_state *state,
284 fe_spectral_inversion_t inversion)
Steven Toth0d467482008-09-04 01:14:43 -0300285{
286 dprintk("%s(%d)\n", __func__, inversion);
287
288 switch (inversion) {
289 case INVERSION_OFF:
290 state->dnxt.inversion_val = 0x00;
291 break;
292 case INVERSION_ON:
293 state->dnxt.inversion_val = 0x04;
294 break;
295 case INVERSION_AUTO:
296 state->dnxt.inversion_val = 0x0C;
297 break;
298 default:
299 return -EINVAL;
300 }
301
302 state->dnxt.inversion = inversion;
303
304 return 0;
305}
306
Darron Broad490c8682008-09-13 19:42:16 -0300307/*
308 * modfec (modulation and FEC)
309 * ===========================
310 *
311 * MOD FEC mask/val standard
312 * ---- -------- ----------- --------
313 * QPSK FEC_1_2 0x02 0x02+X DVB-S
314 * QPSK FEC_2_3 0x04 0x02+X DVB-S
315 * QPSK FEC_3_4 0x08 0x02+X DVB-S
316 * QPSK FEC_4_5 0x10 0x02+X DVB-S (?)
317 * QPSK FEC_5_6 0x20 0x02+X DVB-S
318 * QPSK FEC_6_7 0x40 0x02+X DVB-S
319 * QPSK FEC_7_8 0x80 0x02+X DVB-S
320 * QPSK FEC_8_9 0x01 0x02+X DVB-S (?) (NOT SUPPORTED?)
321 * QPSK AUTO 0xff 0x02+X DVB-S
322 *
323 * For DVB-S high byte probably represents FEC
324 * and low byte selects the modulator. The high
325 * byte is search range mask. Bit 5 may turn
326 * on DVB-S and remaining bits represent some
327 * kind of calibration (how/what i do not know).
328 *
329 * Eg.(2/3) szap "Zone Horror"
330 *
331 * mask/val = 0x04, 0x20
Steven Toth98c94822008-10-16 20:24:42 -0300332 * status 1f | signal c3c0 | snr a333 | ber 00000098 | unc 0 | FE_HAS_LOCK
Darron Broad490c8682008-09-13 19:42:16 -0300333 *
334 * mask/val = 0x04, 0x30
Steven Toth98c94822008-10-16 20:24:42 -0300335 * status 1f | signal c3c0 | snr a333 | ber 00000000 | unc 0 | FE_HAS_LOCK
Darron Broad490c8682008-09-13 19:42:16 -0300336 *
337 * After tuning FECSTATUS contains actual FEC
338 * in use numbered 1 through to 8 for 1/2 .. 2/3 etc
339 *
340 * NBC=NOT/NON BACKWARD COMPATIBLE WITH DVB-S (DVB-S2 only)
341 *
342 * NBC-QPSK FEC_1_2 0x00, 0x04 DVB-S2
343 * NBC-QPSK FEC_3_5 0x00, 0x05 DVB-S2
344 * NBC-QPSK FEC_2_3 0x00, 0x06 DVB-S2
345 * NBC-QPSK FEC_3_4 0x00, 0x07 DVB-S2
346 * NBC-QPSK FEC_4_5 0x00, 0x08 DVB-S2
347 * NBC-QPSK FEC_5_6 0x00, 0x09 DVB-S2
348 * NBC-QPSK FEC_8_9 0x00, 0x0a DVB-S2
349 * NBC-QPSK FEC_9_10 0x00, 0x0b DVB-S2
350 *
351 * NBC-8PSK FEC_3_5 0x00, 0x0c DVB-S2
352 * NBC-8PSK FEC_2_3 0x00, 0x0d DVB-S2
353 * NBC-8PSK FEC_3_4 0x00, 0x0e DVB-S2
354 * NBC-8PSK FEC_5_6 0x00, 0x0f DVB-S2
355 * NBC-8PSK FEC_8_9 0x00, 0x10 DVB-S2
356 * NBC-8PSK FEC_9_10 0x00, 0x11 DVB-S2
357 *
358 * For DVB-S2 low bytes selects both modulator
359 * and FEC. High byte is meaningless here. To
360 * set pilot, bit 6 (0x40) is set. When inspecting
361 * FECSTATUS bit 7 (0x80) represents the pilot
362 * selection whilst not tuned. When tuned, actual FEC
363 * in use is found in FECSTATUS as per above. Pilot
364 * value is reset.
365 */
366
Steven Toth0d467482008-09-04 01:14:43 -0300367/* A table of modulation, fec and configuration bytes for the demod.
368 * Not all S2 mmodulation schemes are support and not all rates with
369 * a scheme are support. Especially, no auto detect when in S2 mode.
370 */
371struct cx24116_modfec {
Steven Toth0a6393a2008-10-06 21:06:48 -0300372 fe_delivery_system_t delivery_system;
Steven Toth0d467482008-09-04 01:14:43 -0300373 fe_modulation_t modulation;
374 fe_code_rate_t fec;
375 u8 mask; /* In DVBS mode this is used to autodetect */
376 u8 val; /* Passed to the firmware to indicate mode selection */
377} CX24116_MODFEC_MODES[] = {
378 /* QPSK. For unknown rates we set hardware to auto detect 0xfe 0x30 */
Darron Broad490c8682008-09-13 19:42:16 -0300379
380 /*mod fec mask val */
Steven Toth0a6393a2008-10-06 21:06:48 -0300381 { SYS_DVBS, QPSK, FEC_NONE, 0xfe, 0x30 },
382 { SYS_DVBS, QPSK, FEC_1_2, 0x02, 0x2e }, /* 00000010 00101110 */
383 { SYS_DVBS, QPSK, FEC_2_3, 0x04, 0x2f }, /* 00000100 00101111 */
384 { SYS_DVBS, QPSK, FEC_3_4, 0x08, 0x30 }, /* 00001000 00110000 */
385 { SYS_DVBS, QPSK, FEC_4_5, 0xfe, 0x30 }, /* 000?0000 ? */
386 { SYS_DVBS, QPSK, FEC_5_6, 0x20, 0x31 }, /* 00100000 00110001 */
387 { SYS_DVBS, QPSK, FEC_6_7, 0xfe, 0x30 }, /* 0?000000 ? */
388 { SYS_DVBS, QPSK, FEC_7_8, 0x80, 0x32 }, /* 10000000 00110010 */
389 { SYS_DVBS, QPSK, FEC_8_9, 0xfe, 0x30 }, /* 0000000? ? */
390 { SYS_DVBS, QPSK, FEC_AUTO, 0xfe, 0x30 },
Steven Toth0d467482008-09-04 01:14:43 -0300391 /* NBC-QPSK */
Steven Toth0a6393a2008-10-06 21:06:48 -0300392 { SYS_DVBS2, QPSK, FEC_1_2, 0x00, 0x04 },
393 { SYS_DVBS2, QPSK, FEC_3_5, 0x00, 0x05 },
394 { SYS_DVBS2, QPSK, FEC_2_3, 0x00, 0x06 },
395 { SYS_DVBS2, QPSK, FEC_3_4, 0x00, 0x07 },
396 { SYS_DVBS2, QPSK, FEC_4_5, 0x00, 0x08 },
397 { SYS_DVBS2, QPSK, FEC_5_6, 0x00, 0x09 },
398 { SYS_DVBS2, QPSK, FEC_8_9, 0x00, 0x0a },
399 { SYS_DVBS2, QPSK, FEC_9_10, 0x00, 0x0b },
Steven Toth0d467482008-09-04 01:14:43 -0300400 /* 8PSK */
Steven Toth0a6393a2008-10-06 21:06:48 -0300401 { SYS_DVBS2, PSK_8, FEC_3_5, 0x00, 0x0c },
402 { SYS_DVBS2, PSK_8, FEC_2_3, 0x00, 0x0d },
403 { SYS_DVBS2, PSK_8, FEC_3_4, 0x00, 0x0e },
404 { SYS_DVBS2, PSK_8, FEC_5_6, 0x00, 0x0f },
405 { SYS_DVBS2, PSK_8, FEC_8_9, 0x00, 0x10 },
406 { SYS_DVBS2, PSK_8, FEC_9_10, 0x00, 0x11 },
Darron Broad490c8682008-09-13 19:42:16 -0300407 /*
408 * `val' can be found in the FECSTATUS register when tuning.
409 * FECSTATUS will give the actual FEC in use if tuning was successful.
410 */
Steven Toth0d467482008-09-04 01:14:43 -0300411};
412
Steven Tothf11ec7d2008-10-16 20:22:01 -0300413static int cx24116_lookup_fecmod(struct cx24116_state *state,
Steven Toth0d467482008-09-04 01:14:43 -0300414 fe_modulation_t m, fe_code_rate_t f)
415{
416 int i, ret = -EOPNOTSUPP;
417
Darron Broad490c8682008-09-13 19:42:16 -0300418 dprintk("%s(0x%02x,0x%02x)\n", __func__, m, f);
419
Steven Tothf11ec7d2008-10-16 20:22:01 -0300420 for (i = 0; i < ARRAY_SIZE(CX24116_MODFEC_MODES); i++) {
421 if ((m == CX24116_MODFEC_MODES[i].modulation) &&
422 (f == CX24116_MODFEC_MODES[i].fec)) {
Steven Toth0d467482008-09-04 01:14:43 -0300423 ret = i;
424 break;
425 }
426 }
427
428 return ret;
429}
430
Steven Toth98c94822008-10-16 20:24:42 -0300431static int cx24116_set_fec(struct cx24116_state *state,
432 fe_modulation_t mod, fe_code_rate_t fec)
Steven Toth0d467482008-09-04 01:14:43 -0300433{
434 int ret = 0;
Darron Broad490c8682008-09-13 19:42:16 -0300435
436 dprintk("%s(0x%02x,0x%02x)\n", __func__, mod, fec);
Steven Toth0d467482008-09-04 01:14:43 -0300437
438 ret = cx24116_lookup_fecmod(state, mod, fec);
439
Steven Tothf11ec7d2008-10-16 20:22:01 -0300440 if (ret < 0)
Steven Toth0d467482008-09-04 01:14:43 -0300441 return ret;
442
Darron Broad490c8682008-09-13 19:42:16 -0300443 state->dnxt.fec = fec;
Steven Toth0d467482008-09-04 01:14:43 -0300444 state->dnxt.fec_val = CX24116_MODFEC_MODES[ret].val;
445 state->dnxt.fec_mask = CX24116_MODFEC_MODES[ret].mask;
Darron Broad490c8682008-09-13 19:42:16 -0300446 dprintk("%s() mask/val = 0x%02x/0x%02x\n", __func__,
447 state->dnxt.fec_mask, state->dnxt.fec_val);
Steven Toth0d467482008-09-04 01:14:43 -0300448
449 return 0;
450}
451
Steven Tothf11ec7d2008-10-16 20:22:01 -0300452static int cx24116_set_symbolrate(struct cx24116_state *state, u32 rate)
Steven Toth0d467482008-09-04 01:14:43 -0300453{
Darron Broad490c8682008-09-13 19:42:16 -0300454 dprintk("%s(%d)\n", __func__, rate);
Steven Toth0d467482008-09-04 01:14:43 -0300455
456 /* check if symbol rate is within limits */
Darron Broad490c8682008-09-13 19:42:16 -0300457 if ((rate > state->frontend.ops.info.symbol_rate_max) ||
458 (rate < state->frontend.ops.info.symbol_rate_min)) {
459 dprintk("%s() unsupported symbol_rate = %d\n", __func__, rate);
460 return -EOPNOTSUPP;
461 }
Steven Toth0d467482008-09-04 01:14:43 -0300462
Darron Broad490c8682008-09-13 19:42:16 -0300463 state->dnxt.symbol_rate = rate;
464 dprintk("%s() symbol_rate = %d\n", __func__, rate);
465
466 return 0;
Steven Toth0d467482008-09-04 01:14:43 -0300467}
468
Steven Tothf11ec7d2008-10-16 20:22:01 -0300469static int cx24116_load_firmware(struct dvb_frontend *fe,
470 const struct firmware *fw);
Steven Toth0d467482008-09-04 01:14:43 -0300471
Steven Tothf11ec7d2008-10-16 20:22:01 -0300472static int cx24116_firmware_ondemand(struct dvb_frontend *fe)
Steven Toth0d467482008-09-04 01:14:43 -0300473{
474 struct cx24116_state *state = fe->demodulator_priv;
475 const struct firmware *fw;
476 int ret = 0;
477
Steven Tothf11ec7d2008-10-16 20:22:01 -0300478 dprintk("%s()\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -0300479
Steven Tothf11ec7d2008-10-16 20:22:01 -0300480 if (cx24116_readreg(state, 0x20) > 0) {
Steven Toth0d467482008-09-04 01:14:43 -0300481
482 if (state->skip_fw_load)
483 return 0;
484
485 /* Load firmware */
Steven Toth98c94822008-10-16 20:24:42 -0300486 /* request the firmware, this will block until loaded */
487 printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n",
488 __func__, CX24116_DEFAULT_FIRMWARE);
489 ret = request_firmware(&fw, CX24116_DEFAULT_FIRMWARE,
490 &state->i2c->dev);
491 printk(KERN_INFO "%s: Waiting for firmware upload(2)...\n",
492 __func__);
Steven Toth0d467482008-09-04 01:14:43 -0300493 if (ret) {
Steven Toth98c94822008-10-16 20:24:42 -0300494 printk(KERN_ERR "%s: No firmware uploaded "
495 "(timeout or file not found?)\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -0300496 return ret;
497 }
498
Steven Toth98c94822008-10-16 20:24:42 -0300499 /* Make sure we don't recurse back through here
500 * during loading */
Steven Toth0d467482008-09-04 01:14:43 -0300501 state->skip_fw_load = 1;
502
503 ret = cx24116_load_firmware(fe, fw);
504 if (ret)
Steven Toth98c94822008-10-16 20:24:42 -0300505 printk(KERN_ERR "%s: Writing firmware to device failed\n",
506 __func__);
Steven Toth0d467482008-09-04 01:14:43 -0300507
508 release_firmware(fw);
509
Steven Toth98c94822008-10-16 20:24:42 -0300510 printk(KERN_INFO "%s: Firmware upload %s\n", __func__,
511 ret == 0 ? "complete" : "failed");
Steven Toth0d467482008-09-04 01:14:43 -0300512
513 /* Ensure firmware is always loaded if required */
514 state->skip_fw_load = 0;
515 }
516
517 return ret;
518}
519
Steven Toth98c94822008-10-16 20:24:42 -0300520/* Take a basic firmware command structure, format it
521 * and forward it for processing
522 */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300523static int cx24116_cmd_execute(struct dvb_frontend *fe, struct cx24116_cmd *cmd)
Steven Toth0d467482008-09-04 01:14:43 -0300524{
525 struct cx24116_state *state = fe->demodulator_priv;
526 int i, ret;
527
528 dprintk("%s()\n", __func__);
529
530 /* Load the firmware if required */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300531 ret = cx24116_firmware_ondemand(fe);
532 if (ret != 0) {
Steven Toth98c94822008-10-16 20:24:42 -0300533 printk(KERN_ERR "%s(): Unable initialise the firmware\n",
534 __func__);
Steven Toth0d467482008-09-04 01:14:43 -0300535 return ret;
536 }
537
538 /* Write the command */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300539 for (i = 0; i < cmd->len ; i++) {
Steven Toth0d467482008-09-04 01:14:43 -0300540 dprintk("%s: 0x%02x == 0x%02x\n", __func__, i, cmd->args[i]);
541 cx24116_writereg(state, i, cmd->args[i]);
542 }
543
544 /* Start execution and wait for cmd to terminate */
Darron Broad490c8682008-09-13 19:42:16 -0300545 cx24116_writereg(state, CX24116_REG_EXECUTE, 0x01);
Steven Tothf11ec7d2008-10-16 20:22:01 -0300546 while (cx24116_readreg(state, CX24116_REG_EXECUTE)) {
Steven Toth0d467482008-09-04 01:14:43 -0300547 msleep(10);
Steven Tothf11ec7d2008-10-16 20:22:01 -0300548 if (i++ > 64) {
Steven Toth98c94822008-10-16 20:24:42 -0300549 /* Avoid looping forever if the firmware does
550 not respond */
551 printk(KERN_WARNING "%s() Firmware not responding\n",
552 __func__);
Steven Toth0d467482008-09-04 01:14:43 -0300553 return -EREMOTEIO;
554 }
555 }
556 return 0;
557}
558
Steven Tothf11ec7d2008-10-16 20:22:01 -0300559static int cx24116_load_firmware(struct dvb_frontend *fe,
560 const struct firmware *fw)
Steven Toth0d467482008-09-04 01:14:43 -0300561{
Steven Tothf11ec7d2008-10-16 20:22:01 -0300562 struct cx24116_state *state = fe->demodulator_priv;
Steven Toth0d467482008-09-04 01:14:43 -0300563 struct cx24116_cmd cmd;
Darron Broad490c8682008-09-13 19:42:16 -0300564 int i, ret;
565 unsigned char vers[4];
Steven Toth0d467482008-09-04 01:14:43 -0300566
567 dprintk("%s\n", __func__);
Steven Tothf11ec7d2008-10-16 20:22:01 -0300568 dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n",
569 fw->size,
570 fw->data[0],
571 fw->data[1],
572 fw->data[fw->size-2],
573 fw->data[fw->size-1]);
Steven Toth0d467482008-09-04 01:14:43 -0300574
575 /* Toggle 88x SRST pin to reset demod */
576 if (state->config->reset_device)
577 state->config->reset_device(fe);
578
579 /* Begin the firmware load process */
580 /* Prepare the demod, load the firmware, cleanup after load */
Steven Toth0d467482008-09-04 01:14:43 -0300581
Darron Broad490c8682008-09-13 19:42:16 -0300582 /* Init PLL */
583 cx24116_writereg(state, 0xE5, 0x00);
584 cx24116_writereg(state, 0xF1, 0x08);
585 cx24116_writereg(state, 0xF2, 0x13);
586
587 /* Start PLL */
588 cx24116_writereg(state, 0xe0, 0x03);
589 cx24116_writereg(state, 0xe0, 0x00);
590
591 /* Unknown */
592 cx24116_writereg(state, CX24116_REG_CLKDIV, 0x46);
593 cx24116_writereg(state, CX24116_REG_RATEDIV, 0x00);
594
595 /* Unknown */
Steven Toth0d467482008-09-04 01:14:43 -0300596 cx24116_writereg(state, 0xF0, 0x03);
597 cx24116_writereg(state, 0xF4, 0x81);
598 cx24116_writereg(state, 0xF5, 0x00);
599 cx24116_writereg(state, 0xF6, 0x00);
600
601 /* write the entire firmware as one transaction */
602 cx24116_writeregN(state, 0xF7, fw->data, fw->size);
603
604 cx24116_writereg(state, 0xF4, 0x10);
605 cx24116_writereg(state, 0xF0, 0x00);
606 cx24116_writereg(state, 0xF8, 0x06);
607
Darron Broad490c8682008-09-13 19:42:16 -0300608 /* Firmware CMD 10: VCO config */
609 cmd.args[0x00] = CMD_SET_VCO;
Steven Toth0d467482008-09-04 01:14:43 -0300610 cmd.args[0x01] = 0x05;
611 cmd.args[0x02] = 0xdc;
612 cmd.args[0x03] = 0xda;
613 cmd.args[0x04] = 0xae;
614 cmd.args[0x05] = 0xaa;
615 cmd.args[0x06] = 0x04;
616 cmd.args[0x07] = 0x9d;
617 cmd.args[0x08] = 0xfc;
618 cmd.args[0x09] = 0x06;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300619 cmd.len = 0x0a;
Steven Toth0d467482008-09-04 01:14:43 -0300620 ret = cx24116_cmd_execute(fe, &cmd);
621 if (ret != 0)
622 return ret;
623
Darron Broad490c8682008-09-13 19:42:16 -0300624 cx24116_writereg(state, CX24116_REG_SSTATUS, 0x00);
Steven Toth0d467482008-09-04 01:14:43 -0300625
Darron Broad490c8682008-09-13 19:42:16 -0300626 /* Firmware CMD 14: Tuner config */
627 cmd.args[0x00] = CMD_TUNERINIT;
Steven Toth0d467482008-09-04 01:14:43 -0300628 cmd.args[0x01] = 0x00;
629 cmd.args[0x02] = 0x00;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300630 cmd.len = 0x03;
Steven Toth0d467482008-09-04 01:14:43 -0300631 ret = cx24116_cmd_execute(fe, &cmd);
632 if (ret != 0)
633 return ret;
634
635 cx24116_writereg(state, 0xe5, 0x00);
636
Darron Broad490c8682008-09-13 19:42:16 -0300637 /* Firmware CMD 13: MPEG config */
638 cmd.args[0x00] = CMD_MPEGCONFIG;
Steven Toth0d467482008-09-04 01:14:43 -0300639 cmd.args[0x01] = 0x01;
640 cmd.args[0x02] = 0x75;
641 cmd.args[0x03] = 0x00;
Igor M. Liplianincc8c4f32008-09-09 13:57:47 -0300642 if (state->config->mpg_clk_pos_pol)
643 cmd.args[0x04] = state->config->mpg_clk_pos_pol;
644 else
645 cmd.args[0x04] = 0x02;
Steven Toth0d467482008-09-04 01:14:43 -0300646 cmd.args[0x05] = 0x00;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300647 cmd.len = 0x06;
Steven Toth0d467482008-09-04 01:14:43 -0300648 ret = cx24116_cmd_execute(fe, &cmd);
649 if (ret != 0)
650 return ret;
651
Darron Broad490c8682008-09-13 19:42:16 -0300652 /* Firmware CMD 35: Get firmware version */
653 cmd.args[0x00] = CMD_UPDFWVERS;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300654 cmd.len = 0x02;
655 for (i = 0; i < 4; i++) {
Darron Broad490c8682008-09-13 19:42:16 -0300656 cmd.args[0x01] = i;
657 ret = cx24116_cmd_execute(fe, &cmd);
658 if (ret != 0)
659 return ret;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300660 vers[i] = cx24116_readreg(state, CX24116_REG_MAILBOX);
Darron Broad490c8682008-09-13 19:42:16 -0300661 }
Steven Toth98c94822008-10-16 20:24:42 -0300662 printk(KERN_INFO "%s: FW version %i.%i.%i.%i\n", __func__,
Darron Broad490c8682008-09-13 19:42:16 -0300663 vers[0], vers[1], vers[2], vers[3]);
664
Steven Toth0d467482008-09-04 01:14:43 -0300665 return 0;
666}
667
Steven Tothf11ec7d2008-10-16 20:22:01 -0300668static int cx24116_set_voltage(struct dvb_frontend *fe,
669 fe_sec_voltage_t voltage)
Steven Toth0d467482008-09-04 01:14:43 -0300670{
671 /* The isl6421 module will override this function in the fops. */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300672 dprintk("%s() This should never appear if the isl6421 module "
673 "is loaded correctly\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -0300674
675 return -EOPNOTSUPP;
676}
677
Steven Tothf11ec7d2008-10-16 20:22:01 -0300678static int cx24116_read_status(struct dvb_frontend *fe, fe_status_t *status)
Steven Toth0d467482008-09-04 01:14:43 -0300679{
680 struct cx24116_state *state = fe->demodulator_priv;
681
Darron Broad490c8682008-09-13 19:42:16 -0300682 int lock = cx24116_readreg(state, CX24116_REG_SSTATUS);
Steven Toth0d467482008-09-04 01:14:43 -0300683
684 dprintk("%s: status = 0x%02x\n", __func__, lock);
685
686 *status = 0;
687
Darron Broad490c8682008-09-13 19:42:16 -0300688 if (lock & CX24116_HAS_SIGNAL)
Steven Toth0d467482008-09-04 01:14:43 -0300689 *status |= FE_HAS_SIGNAL;
Darron Broad490c8682008-09-13 19:42:16 -0300690 if (lock & CX24116_HAS_CARRIER)
Steven Toth0d467482008-09-04 01:14:43 -0300691 *status |= FE_HAS_CARRIER;
Darron Broad490c8682008-09-13 19:42:16 -0300692 if (lock & CX24116_HAS_VITERBI)
Steven Toth0d467482008-09-04 01:14:43 -0300693 *status |= FE_HAS_VITERBI;
Darron Broad490c8682008-09-13 19:42:16 -0300694 if (lock & CX24116_HAS_SYNCLOCK)
Steven Toth0d467482008-09-04 01:14:43 -0300695 *status |= FE_HAS_SYNC | FE_HAS_LOCK;
696
697 return 0;
698}
699
Steven Tothf11ec7d2008-10-16 20:22:01 -0300700static int cx24116_read_ber(struct dvb_frontend *fe, u32 *ber)
Steven Toth0d467482008-09-04 01:14:43 -0300701{
Darron Broad490c8682008-09-13 19:42:16 -0300702 struct cx24116_state *state = fe->demodulator_priv;
703
Steven Toth0d467482008-09-04 01:14:43 -0300704 dprintk("%s()\n", __func__);
Darron Broad490c8682008-09-13 19:42:16 -0300705
Steven Tothf11ec7d2008-10-16 20:22:01 -0300706 *ber = (cx24116_readreg(state, CX24116_REG_BER24) << 24) |
707 (cx24116_readreg(state, CX24116_REG_BER16) << 16) |
708 (cx24116_readreg(state, CX24116_REG_BER8) << 8) |
709 cx24116_readreg(state, CX24116_REG_BER0);
Steven Toth0d467482008-09-04 01:14:43 -0300710
711 return 0;
712}
713
Darron Broad490c8682008-09-13 19:42:16 -0300714/* TODO Determine function and scale appropriately */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300715static int cx24116_read_signal_strength(struct dvb_frontend *fe,
716 u16 *signal_strength)
Steven Toth0d467482008-09-04 01:14:43 -0300717{
718 struct cx24116_state *state = fe->demodulator_priv;
Darron Broad490c8682008-09-13 19:42:16 -0300719 struct cx24116_cmd cmd;
720 int ret;
721 u16 sig_reading;
722
723 dprintk("%s()\n", __func__);
724
725 /* Firmware CMD 19: Get AGC */
726 cmd.args[0x00] = CMD_GETAGC;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300727 cmd.len = 0x01;
Darron Broad490c8682008-09-13 19:42:16 -0300728 ret = cx24116_cmd_execute(fe, &cmd);
729 if (ret != 0)
730 return ret;
731
Steven Tothf11ec7d2008-10-16 20:22:01 -0300732 sig_reading =
733 (cx24116_readreg(state,
734 CX24116_REG_SSTATUS) & CX24116_SIGNAL_MASK) |
735 (cx24116_readreg(state, CX24116_REG_SIGNAL) << 6);
736 *signal_strength = 0 - sig_reading;
Darron Broad490c8682008-09-13 19:42:16 -0300737
Steven Tothf11ec7d2008-10-16 20:22:01 -0300738 dprintk("%s: raw / cooked = 0x%04x / 0x%04x\n",
739 __func__, sig_reading, *signal_strength);
Darron Broad490c8682008-09-13 19:42:16 -0300740
741 return 0;
742}
743
744/* SNR (0..100)% = (sig & 0xf0) * 10 + (sig & 0x0f) * 10 / 16 */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300745static int cx24116_read_snr_pct(struct dvb_frontend *fe, u16 *snr)
Darron Broad490c8682008-09-13 19:42:16 -0300746{
747 struct cx24116_state *state = fe->demodulator_priv;
748 u8 snr_reading;
749 static const u32 snr_tab[] = { /* 10 x Table (rounded up) */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300750 0x00000, 0x0199A, 0x03333, 0x04ccD, 0x06667,
751 0x08000, 0x0999A, 0x0b333, 0x0cccD, 0x0e667,
752 0x10000, 0x1199A, 0x13333, 0x14ccD, 0x16667,
753 0x18000 };
Steven Toth0d467482008-09-04 01:14:43 -0300754
755 dprintk("%s()\n", __func__);
756
Steven Toth8953db72008-10-06 21:20:21 -0300757 snr_reading = cx24116_readreg(state, CX24116_REG_QUALITY0);
Steven Toth0d467482008-09-04 01:14:43 -0300758
Steven Tothf11ec7d2008-10-16 20:22:01 -0300759 if (snr_reading >= 0xa0 /* 100% */)
Darron Broad490c8682008-09-13 19:42:16 -0300760 *snr = 0xffff;
Steven Toth0d467482008-09-04 01:14:43 -0300761 else
Steven Tothf11ec7d2008-10-16 20:22:01 -0300762 *snr = snr_tab[(snr_reading & 0xf0) >> 4] +
763 (snr_tab[(snr_reading & 0x0f)] >> 4);
Steven Toth0d467482008-09-04 01:14:43 -0300764
Darron Broad490c8682008-09-13 19:42:16 -0300765 dprintk("%s: raw / cooked = 0x%02x / 0x%04x\n", __func__,
766 snr_reading, *snr);
Steven Toth0d467482008-09-04 01:14:43 -0300767
768 return 0;
769}
770
Steven Toth8953db72008-10-06 21:20:21 -0300771/* The reelbox patches show the value in the registers represents
772 * ESNO, from 0->30db (values 0->300). We provide this value by
773 * default.
774 */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300775static int cx24116_read_snr_esno(struct dvb_frontend *fe, u16 *snr)
Steven Toth8953db72008-10-06 21:20:21 -0300776{
777 struct cx24116_state *state = fe->demodulator_priv;
778
779 dprintk("%s()\n", __func__);
780
781 *snr = cx24116_readreg(state, CX24116_REG_QUALITY8) << 8 |
782 cx24116_readreg(state, CX24116_REG_QUALITY0);
783
784 dprintk("%s: raw 0x%04x\n", __func__, *snr);
785
786 return 0;
787}
788
Steven Tothf11ec7d2008-10-16 20:22:01 -0300789static int cx24116_read_snr(struct dvb_frontend *fe, u16 *snr)
Steven Toth8953db72008-10-06 21:20:21 -0300790{
791 if (esno_snr == 1)
792 return cx24116_read_snr_esno(fe, snr);
793 else
794 return cx24116_read_snr_pct(fe, snr);
795}
796
Steven Tothf11ec7d2008-10-16 20:22:01 -0300797static int cx24116_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
Steven Toth0d467482008-09-04 01:14:43 -0300798{
Darron Broad490c8682008-09-13 19:42:16 -0300799 struct cx24116_state *state = fe->demodulator_priv;
800
Steven Toth0d467482008-09-04 01:14:43 -0300801 dprintk("%s()\n", __func__);
Darron Broad490c8682008-09-13 19:42:16 -0300802
Steven Tothf11ec7d2008-10-16 20:22:01 -0300803 *ucblocks = (cx24116_readreg(state, CX24116_REG_UCB8) << 8) |
Darron Broad490c8682008-09-13 19:42:16 -0300804 cx24116_readreg(state, CX24116_REG_UCB0);
Steven Toth0d467482008-09-04 01:14:43 -0300805
806 return 0;
807}
808
809/* Overwrite the current tuning params, we are about to tune */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300810static void cx24116_clone_params(struct dvb_frontend *fe)
Steven Toth0d467482008-09-04 01:14:43 -0300811{
812 struct cx24116_state *state = fe->demodulator_priv;
813 memcpy(&state->dcur, &state->dnxt, sizeof(state->dcur));
814}
815
Darron Broad490c8682008-09-13 19:42:16 -0300816/* Wait for LNB */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300817static int cx24116_wait_for_lnb(struct dvb_frontend *fe)
Darron Broad490c8682008-09-13 19:42:16 -0300818{
819 struct cx24116_state *state = fe->demodulator_priv;
820 int i;
821
822 dprintk("%s() qstatus = 0x%02x\n", __func__,
823 cx24116_readreg(state, CX24116_REG_QSTATUS));
824
825 /* Wait for up to 300 ms */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300826 for (i = 0; i < 30 ; i++) {
Darron Broad490c8682008-09-13 19:42:16 -0300827 if (cx24116_readreg(state, CX24116_REG_QSTATUS) & 0x20)
828 return 0;
829 msleep(10);
830 }
831
832 dprintk("%s(): LNB not ready\n", __func__);
833
834 return -ETIMEDOUT; /* -EBUSY ? */
835}
836
Steven Tothf11ec7d2008-10-16 20:22:01 -0300837static int cx24116_set_tone(struct dvb_frontend *fe,
838 fe_sec_tone_mode_t tone)
Steven Toth0d467482008-09-04 01:14:43 -0300839{
840 struct cx24116_cmd cmd;
841 int ret;
842
843 dprintk("%s(%d)\n", __func__, tone);
Steven Tothf11ec7d2008-10-16 20:22:01 -0300844 if ((tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF)) {
Steven Toth98c94822008-10-16 20:24:42 -0300845 printk(KERN_ERR "%s: Invalid, tone=%d\n", __func__, tone);
Steven Toth0d467482008-09-04 01:14:43 -0300846 return -EINVAL;
847 }
848
Darron Broad490c8682008-09-13 19:42:16 -0300849 /* Wait for LNB ready */
850 ret = cx24116_wait_for_lnb(fe);
Steven Tothf11ec7d2008-10-16 20:22:01 -0300851 if (ret != 0)
Darron Broad490c8682008-09-13 19:42:16 -0300852 return ret;
853
854 /* Min delay time after DiSEqC send */
855 msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */
856
Steven Toth0d467482008-09-04 01:14:43 -0300857 /* This is always done before the tone is set */
858 cmd.args[0x00] = CMD_SET_TONEPRE;
859 cmd.args[0x01] = 0x00;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300860 cmd.len = 0x02;
Steven Toth0d467482008-09-04 01:14:43 -0300861 ret = cx24116_cmd_execute(fe, &cmd);
862 if (ret != 0)
863 return ret;
864
865 /* Now we set the tone */
866 cmd.args[0x00] = CMD_SET_TONE;
867 cmd.args[0x01] = 0x00;
868 cmd.args[0x02] = 0x00;
869
870 switch (tone) {
871 case SEC_TONE_ON:
872 dprintk("%s: setting tone on\n", __func__);
873 cmd.args[0x03] = 0x01;
874 break;
875 case SEC_TONE_OFF:
Steven Tothf11ec7d2008-10-16 20:22:01 -0300876 dprintk("%s: setting tone off\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -0300877 cmd.args[0x03] = 0x00;
878 break;
879 }
Steven Tothf11ec7d2008-10-16 20:22:01 -0300880 cmd.len = 0x04;
Steven Toth0d467482008-09-04 01:14:43 -0300881
Darron Broad490c8682008-09-13 19:42:16 -0300882 /* Min delay time before DiSEqC send */
883 msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */
884
Steven Toth0d467482008-09-04 01:14:43 -0300885 return cx24116_cmd_execute(fe, &cmd);
886}
887
888/* Initialise DiSEqC */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300889static int cx24116_diseqc_init(struct dvb_frontend *fe)
Steven Toth0d467482008-09-04 01:14:43 -0300890{
891 struct cx24116_state *state = fe->demodulator_priv;
Darron Broad490c8682008-09-13 19:42:16 -0300892 struct cx24116_cmd cmd;
893 int ret;
Steven Toth0d467482008-09-04 01:14:43 -0300894
Darron Broad490c8682008-09-13 19:42:16 -0300895 /* Firmware CMD 20: LNB/DiSEqC config */
896 cmd.args[0x00] = CMD_LNBCONFIG;
897 cmd.args[0x01] = 0x00;
898 cmd.args[0x02] = 0x10;
899 cmd.args[0x03] = 0x00;
900 cmd.args[0x04] = 0x8f;
901 cmd.args[0x05] = 0x28;
902 cmd.args[0x06] = (toneburst == CX24116_DISEQC_TONEOFF) ? 0x00 : 0x01;
903 cmd.args[0x07] = 0x01;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300904 cmd.len = 0x08;
Darron Broad490c8682008-09-13 19:42:16 -0300905 ret = cx24116_cmd_execute(fe, &cmd);
906 if (ret != 0)
907 return ret;
908
909 /* Prepare a DiSEqC command */
910 state->dsec_cmd.args[0x00] = CMD_LNBSEND;
911
912 /* DiSEqC burst */
913 state->dsec_cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_A;
914
915 /* Unknown */
916 state->dsec_cmd.args[CX24116_DISEQC_ARG2_2] = 0x02;
917 state->dsec_cmd.args[CX24116_DISEQC_ARG3_0] = 0x00;
Steven Toth98c94822008-10-16 20:24:42 -0300918 /* Continuation flag? */
919 state->dsec_cmd.args[CX24116_DISEQC_ARG4_0] = 0x00;
Darron Broad490c8682008-09-13 19:42:16 -0300920
921 /* DiSEqC message length */
922 state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = 0x00;
923
924 /* Command length */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300925 state->dsec_cmd.len = CX24116_DISEQC_MSGOFS;
Steven Toth0d467482008-09-04 01:14:43 -0300926
927 return 0;
928}
929
930/* Send DiSEqC message with derived burst (hack) || previous burst */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300931static int cx24116_send_diseqc_msg(struct dvb_frontend *fe,
932 struct dvb_diseqc_master_cmd *d)
Steven Toth0d467482008-09-04 01:14:43 -0300933{
934 struct cx24116_state *state = fe->demodulator_priv;
Steven Toth0d467482008-09-04 01:14:43 -0300935 int i, ret;
936
937 /* Dump DiSEqC message */
938 if (debug) {
Steven Toth98c94822008-10-16 20:24:42 -0300939 printk(KERN_INFO "cx24116: %s(", __func__);
Steven Tothf11ec7d2008-10-16 20:22:01 -0300940 for (i = 0 ; i < d->msg_len ;) {
Steven Toth98c94822008-10-16 20:24:42 -0300941 printk(KERN_INFO "0x%02x", d->msg[i]);
Steven Tothf11ec7d2008-10-16 20:22:01 -0300942 if (++i < d->msg_len)
Steven Toth98c94822008-10-16 20:24:42 -0300943 printk(KERN_INFO ", ");
Steven Tothf11ec7d2008-10-16 20:22:01 -0300944 }
Darron Broad490c8682008-09-13 19:42:16 -0300945 printk(") toneburst=%d\n", toneburst);
Steven Toth0d467482008-09-04 01:14:43 -0300946 }
947
Darron Broad490c8682008-09-13 19:42:16 -0300948 /* Validate length */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300949 if (d->msg_len > (CX24116_ARGLEN - CX24116_DISEQC_MSGOFS))
Steven Toth0d467482008-09-04 01:14:43 -0300950 return -EINVAL;
951
Steven Toth0d467482008-09-04 01:14:43 -0300952 /* DiSEqC message */
953 for (i = 0; i < d->msg_len; i++)
Darron Broad490c8682008-09-13 19:42:16 -0300954 state->dsec_cmd.args[CX24116_DISEQC_MSGOFS + i] = d->msg[i];
Steven Toth0d467482008-09-04 01:14:43 -0300955
Darron Broad490c8682008-09-13 19:42:16 -0300956 /* DiSEqC message length */
957 state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = d->msg_len;
Steven Toth0d467482008-09-04 01:14:43 -0300958
Darron Broad490c8682008-09-13 19:42:16 -0300959 /* Command length */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300960 state->dsec_cmd.len = CX24116_DISEQC_MSGOFS +
961 state->dsec_cmd.args[CX24116_DISEQC_MSGLEN];
Steven Toth0d467482008-09-04 01:14:43 -0300962
Darron Broad490c8682008-09-13 19:42:16 -0300963 /* DiSEqC toneburst */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300964 if (toneburst == CX24116_DISEQC_MESGCACHE)
Darron Broad490c8682008-09-13 19:42:16 -0300965 /* Message is cached */
966 return 0;
Steven Toth0d467482008-09-04 01:14:43 -0300967
Steven Tothf11ec7d2008-10-16 20:22:01 -0300968 else if (toneburst == CX24116_DISEQC_TONEOFF)
Darron Broad490c8682008-09-13 19:42:16 -0300969 /* Message is sent without burst */
970 state->dsec_cmd.args[CX24116_DISEQC_BURST] = 0;
971
Steven Tothf11ec7d2008-10-16 20:22:01 -0300972 else if (toneburst == CX24116_DISEQC_TONECACHE) {
Darron Broad490c8682008-09-13 19:42:16 -0300973 /*
974 * Message is sent with derived else cached burst
975 *
976 * WRITE PORT GROUP COMMAND 38
977 *
978 * 0/A/A: E0 10 38 F0..F3
979 * 1/B/B: E0 10 38 F4..F7
980 * 2/C/A: E0 10 38 F8..FB
981 * 3/D/B: E0 10 38 FC..FF
982 *
Darron Broad7396d3e2008-09-14 10:45:58 -0300983 * databyte[3]= 8421:8421
Darron Broad490c8682008-09-13 19:42:16 -0300984 * ABCD:WXYZ
985 * CLR :SET
986 *
987 * WX= PORT SELECT 0..3 (X=TONEBURST)
988 * Y = VOLTAGE (0=13V, 1=18V)
989 * Z = BAND (0=LOW, 1=HIGH(22K))
990 */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300991 if (d->msg_len >= 4 && d->msg[2] == 0x38)
992 state->dsec_cmd.args[CX24116_DISEQC_BURST] =
993 ((d->msg[3] & 4) >> 2);
994 if (debug)
995 dprintk("%s burst=%d\n", __func__,
996 state->dsec_cmd.args[CX24116_DISEQC_BURST]);
Darron Broad490c8682008-09-13 19:42:16 -0300997 }
998
999 /* Wait for LNB ready */
1000 ret = cx24116_wait_for_lnb(fe);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001001 if (ret != 0)
Darron Broad490c8682008-09-13 19:42:16 -03001002 return ret;
1003
1004 /* Wait for voltage/min repeat delay */
1005 msleep(100);
1006
1007 /* Command */
1008 ret = cx24116_cmd_execute(fe, &state->dsec_cmd);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001009 if (ret != 0)
Darron Broad490c8682008-09-13 19:42:16 -03001010 return ret;
1011 /*
1012 * Wait for send
Steven Toth0d467482008-09-04 01:14:43 -03001013 *
1014 * Eutelsat spec:
Darron Broad490c8682008-09-13 19:42:16 -03001015 * >15ms delay + (XXX determine if FW does this, see set_tone)
1016 * 13.5ms per byte +
1017 * >15ms delay +
1018 * 12.5ms burst +
1019 * >15ms delay (XXX determine if FW does this, see set_tone)
Steven Toth0d467482008-09-04 01:14:43 -03001020 */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001021 msleep((state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) +
1022 ((toneburst == CX24116_DISEQC_TONEOFF) ? 30 : 60));
Steven Toth0d467482008-09-04 01:14:43 -03001023
Darron Broad490c8682008-09-13 19:42:16 -03001024 return 0;
Steven Toth0d467482008-09-04 01:14:43 -03001025}
1026
1027/* Send DiSEqC burst */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001028static int cx24116_diseqc_send_burst(struct dvb_frontend *fe,
1029 fe_sec_mini_cmd_t burst)
Steven Toth0d467482008-09-04 01:14:43 -03001030{
1031 struct cx24116_state *state = fe->demodulator_priv;
Steven Toth0d467482008-09-04 01:14:43 -03001032 int ret;
1033
Steven Tothf11ec7d2008-10-16 20:22:01 -03001034 dprintk("%s(%d) toneburst=%d\n", __func__, burst, toneburst);
Steven Toth0d467482008-09-04 01:14:43 -03001035
Darron Broad490c8682008-09-13 19:42:16 -03001036 /* DiSEqC burst */
Steven Toth0d467482008-09-04 01:14:43 -03001037 if (burst == SEC_MINI_A)
Steven Tothf11ec7d2008-10-16 20:22:01 -03001038 state->dsec_cmd.args[CX24116_DISEQC_BURST] =
1039 CX24116_DISEQC_MINI_A;
1040 else if (burst == SEC_MINI_B)
1041 state->dsec_cmd.args[CX24116_DISEQC_BURST] =
1042 CX24116_DISEQC_MINI_B;
Steven Toth0d467482008-09-04 01:14:43 -03001043 else
1044 return -EINVAL;
1045
Darron Broad490c8682008-09-13 19:42:16 -03001046 /* DiSEqC toneburst */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001047 if (toneburst != CX24116_DISEQC_MESGCACHE)
Darron Broad490c8682008-09-13 19:42:16 -03001048 /* Burst is cached */
1049 return 0;
Steven Toth0d467482008-09-04 01:14:43 -03001050
Darron Broad490c8682008-09-13 19:42:16 -03001051 /* Burst is to be sent with cached message */
Steven Toth0d467482008-09-04 01:14:43 -03001052
Darron Broad490c8682008-09-13 19:42:16 -03001053 /* Wait for LNB ready */
1054 ret = cx24116_wait_for_lnb(fe);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001055 if (ret != 0)
Darron Broad490c8682008-09-13 19:42:16 -03001056 return ret;
Steven Toth0d467482008-09-04 01:14:43 -03001057
Darron Broad490c8682008-09-13 19:42:16 -03001058 /* Wait for voltage/min repeat delay */
1059 msleep(100);
Steven Toth0d467482008-09-04 01:14:43 -03001060
Darron Broad490c8682008-09-13 19:42:16 -03001061 /* Command */
1062 ret = cx24116_cmd_execute(fe, &state->dsec_cmd);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001063 if (ret != 0)
Darron Broad490c8682008-09-13 19:42:16 -03001064 return ret;
1065
1066 /*
1067 * Wait for send
1068 *
1069 * Eutelsat spec:
1070 * >15ms delay + (XXX determine if FW does this, see set_tone)
1071 * 13.5ms per byte +
1072 * >15ms delay +
1073 * 12.5ms burst +
1074 * >15ms delay (XXX determine if FW does this, see set_tone)
1075 */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001076 msleep((state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) + 60);
Darron Broad490c8682008-09-13 19:42:16 -03001077
1078 return 0;
Steven Toth0d467482008-09-04 01:14:43 -03001079}
1080
Steven Tothf11ec7d2008-10-16 20:22:01 -03001081static void cx24116_release(struct dvb_frontend *fe)
Steven Toth0d467482008-09-04 01:14:43 -03001082{
Steven Tothf11ec7d2008-10-16 20:22:01 -03001083 struct cx24116_state *state = fe->demodulator_priv;
1084 dprintk("%s\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -03001085 kfree(state);
1086}
1087
1088static struct dvb_frontend_ops cx24116_ops;
1089
Steven Tothf11ec7d2008-10-16 20:22:01 -03001090struct dvb_frontend *cx24116_attach(const struct cx24116_config *config,
1091 struct i2c_adapter *i2c)
Steven Toth0d467482008-09-04 01:14:43 -03001092{
Steven Tothf11ec7d2008-10-16 20:22:01 -03001093 struct cx24116_state *state = NULL;
Steven Toth0d467482008-09-04 01:14:43 -03001094 int ret;
1095
Steven Tothf11ec7d2008-10-16 20:22:01 -03001096 dprintk("%s\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -03001097
1098 /* allocate memory for the internal state */
1099 state = kmalloc(sizeof(struct cx24116_state), GFP_KERNEL);
Steven Toth98c94822008-10-16 20:24:42 -03001100 if (state == NULL)
Darron Broad7396d3e2008-09-14 10:45:58 -03001101 goto error1;
Steven Toth0d467482008-09-04 01:14:43 -03001102
1103 /* setup the state */
1104 memset(state, 0, sizeof(struct cx24116_state));
1105
1106 state->config = config;
1107 state->i2c = i2c;
1108
1109 /* check if the demod is present */
Steven Toth98c94822008-10-16 20:24:42 -03001110 ret = (cx24116_readreg(state, 0xFF) << 8) |
1111 cx24116_readreg(state, 0xFE);
Steven Toth0d467482008-09-04 01:14:43 -03001112 if (ret != 0x0501) {
Steven Toth98c94822008-10-16 20:24:42 -03001113 printk(KERN_INFO "Invalid probe, probably not a CX24116 device\n");
Darron Broad7396d3e2008-09-14 10:45:58 -03001114 goto error2;
Steven Toth0d467482008-09-04 01:14:43 -03001115 }
1116
1117 /* create dvb_frontend */
Steven Toth98c94822008-10-16 20:24:42 -03001118 memcpy(&state->frontend.ops, &cx24116_ops,
1119 sizeof(struct dvb_frontend_ops));
Steven Toth0d467482008-09-04 01:14:43 -03001120 state->frontend.demodulator_priv = state;
1121 return &state->frontend;
1122
Darron Broad7396d3e2008-09-14 10:45:58 -03001123error2: kfree(state);
Darron Broad490c8682008-09-13 19:42:16 -03001124error1: return NULL;
Steven Toth0d467482008-09-04 01:14:43 -03001125}
Steven Tothf11ec7d2008-10-16 20:22:01 -03001126EXPORT_SYMBOL(cx24116_attach);
1127
Darron Broad490c8682008-09-13 19:42:16 -03001128/*
1129 * Initialise or wake up device
1130 *
1131 * Power config will reset and load initial firmware if required
1132 */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001133static int cx24116_initfe(struct dvb_frontend *fe)
Steven Toth0d467482008-09-04 01:14:43 -03001134{
Steven Tothf11ec7d2008-10-16 20:22:01 -03001135 struct cx24116_state *state = fe->demodulator_priv;
Darron Broad490c8682008-09-13 19:42:16 -03001136 struct cx24116_cmd cmd;
1137 int ret;
1138
Steven Tothf11ec7d2008-10-16 20:22:01 -03001139 dprintk("%s()\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -03001140
Darron Broad490c8682008-09-13 19:42:16 -03001141 /* Power on */
1142 cx24116_writereg(state, 0xe0, 0);
1143 cx24116_writereg(state, 0xe1, 0);
1144 cx24116_writereg(state, 0xea, 0);
1145
1146 /* Firmware CMD 36: Power config */
1147 cmd.args[0x00] = CMD_TUNERSLEEP;
1148 cmd.args[0x01] = 0;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001149 cmd.len = 0x02;
Darron Broad490c8682008-09-13 19:42:16 -03001150 ret = cx24116_cmd_execute(fe, &cmd);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001151 if (ret != 0)
Darron Broad490c8682008-09-13 19:42:16 -03001152 return ret;
1153
Steven Toth0d467482008-09-04 01:14:43 -03001154 return cx24116_diseqc_init(fe);
1155}
1156
Darron Broad490c8682008-09-13 19:42:16 -03001157/*
1158 * Put device to sleep
1159 */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001160static int cx24116_sleep(struct dvb_frontend *fe)
Darron Broad490c8682008-09-13 19:42:16 -03001161{
Steven Tothf11ec7d2008-10-16 20:22:01 -03001162 struct cx24116_state *state = fe->demodulator_priv;
Darron Broad490c8682008-09-13 19:42:16 -03001163 struct cx24116_cmd cmd;
1164 int ret;
1165
Steven Tothf11ec7d2008-10-16 20:22:01 -03001166 dprintk("%s()\n", __func__);
Darron Broad490c8682008-09-13 19:42:16 -03001167
1168 /* Firmware CMD 36: Power config */
1169 cmd.args[0x00] = CMD_TUNERSLEEP;
1170 cmd.args[0x01] = 1;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001171 cmd.len = 0x02;
Darron Broad490c8682008-09-13 19:42:16 -03001172 ret = cx24116_cmd_execute(fe, &cmd);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001173 if (ret != 0)
Darron Broad490c8682008-09-13 19:42:16 -03001174 return ret;
1175
1176 /* Power off (Shutdown clocks) */
1177 cx24116_writereg(state, 0xea, 0xff);
1178 cx24116_writereg(state, 0xe1, 1);
1179 cx24116_writereg(state, 0xe0, 1);
1180
1181 return 0;
1182}
1183
Steven Tothf11ec7d2008-10-16 20:22:01 -03001184static int cx24116_set_property(struct dvb_frontend *fe,
1185 struct dtv_property *tvp)
Steven Toth0d467482008-09-04 01:14:43 -03001186{
1187 dprintk("%s(..)\n", __func__);
1188 return 0;
1189}
1190
Steven Tothf11ec7d2008-10-16 20:22:01 -03001191static int cx24116_get_property(struct dvb_frontend *fe,
1192 struct dtv_property *tvp)
Steven Toth0d467482008-09-04 01:14:43 -03001193{
Steven Tothbfbf2da2008-09-12 01:37:37 -03001194 dprintk("%s(..)\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -03001195 return 0;
1196}
1197
1198/* dvb-core told us to tune, the tv property cache will be complete,
1199 * it's safe for is to pull values and use them for tuning purposes.
1200 */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001201static int cx24116_set_frontend(struct dvb_frontend *fe,
1202 struct dvb_frontend_parameters *p)
Steven Toth0d467482008-09-04 01:14:43 -03001203{
1204 struct cx24116_state *state = fe->demodulator_priv;
Steven Toth56f06802008-09-11 10:19:27 -03001205 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
Steven Toth0d467482008-09-04 01:14:43 -03001206 struct cx24116_cmd cmd;
1207 fe_status_t tunerstat;
Darron Broad01a8f032008-10-03 11:47:46 -03001208 int i, status, ret, retune;
Steven Toth0d467482008-09-04 01:14:43 -03001209
Steven Tothf11ec7d2008-10-16 20:22:01 -03001210 dprintk("%s()\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -03001211
Steven Tothf11ec7d2008-10-16 20:22:01 -03001212 switch (c->delivery_system) {
1213 case SYS_DVBS:
1214 dprintk("%s: DVB-S delivery system selected\n", __func__);
Darron Broad01a8f032008-10-03 11:47:46 -03001215
Steven Tothf11ec7d2008-10-16 20:22:01 -03001216 /* Only QPSK is supported for DVB-S */
1217 if (c->modulation != QPSK) {
1218 dprintk("%s: unsupported modulation selected (%d)\n",
1219 __func__, c->modulation);
1220 return -EOPNOTSUPP;
1221 }
Darron Broad01a8f032008-10-03 11:47:46 -03001222
Steven Tothf11ec7d2008-10-16 20:22:01 -03001223 /* Pilot doesn't exist in DVB-S, turn bit off */
1224 state->dnxt.pilot_val = CX24116_PILOT_OFF;
1225 retune = 1;
1226
1227 /* DVB-S only supports 0.35 */
1228 if (c->rolloff != ROLLOFF_35) {
1229 dprintk("%s: unsupported rolloff selected (%d)\n",
1230 __func__, c->rolloff);
1231 return -EOPNOTSUPP;
1232 }
1233 state->dnxt.rolloff_val = CX24116_ROLLOFF_035;
1234 break;
1235
1236 case SYS_DVBS2:
1237 dprintk("%s: DVB-S2 delivery system selected\n", __func__);
1238
1239 /*
1240 * NBC 8PSK/QPSK with DVB-S is supported for DVB-S2,
1241 * but not hardware auto detection
1242 */
1243 if (c->modulation != PSK_8 && c->modulation != QPSK) {
1244 dprintk("%s: unsupported modulation selected (%d)\n",
1245 __func__, c->modulation);
1246 return -EOPNOTSUPP;
1247 }
1248
1249 switch (c->pilot) {
1250 case PILOT_AUTO: /* Not supported but emulated */
1251 retune = 2; /* Fall-through */
1252 case PILOT_OFF:
Darron Broad01a8f032008-10-03 11:47:46 -03001253 state->dnxt.pilot_val = CX24116_PILOT_OFF;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001254 break;
1255 case PILOT_ON:
1256 state->dnxt.pilot_val = CX24116_PILOT_ON;
1257 break;
1258 default:
1259 dprintk("%s: unsupported pilot mode selected (%d)\n",
1260 __func__, c->pilot);
1261 return -EOPNOTSUPP;
1262 }
Darron Broad01a8f032008-10-03 11:47:46 -03001263
Steven Tothf11ec7d2008-10-16 20:22:01 -03001264 switch (c->rolloff) {
1265 case ROLLOFF_20:
1266 state->dnxt.rolloff_val = CX24116_ROLLOFF_020;
1267 break;
1268 case ROLLOFF_25:
1269 state->dnxt.rolloff_val = CX24116_ROLLOFF_025;
1270 break;
1271 case ROLLOFF_35:
Darron Broad7396d3e2008-09-14 10:45:58 -03001272 state->dnxt.rolloff_val = CX24116_ROLLOFF_035;
Darron Broad490c8682008-09-13 19:42:16 -03001273 break;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001274 case ROLLOFF_AUTO: /* Rolloff must be explicit */
Darron Broad490c8682008-09-13 19:42:16 -03001275 default:
Steven Tothf11ec7d2008-10-16 20:22:01 -03001276 dprintk("%s: unsupported rolloff selected (%d)\n",
1277 __func__, c->rolloff);
Darron Broad490c8682008-09-13 19:42:16 -03001278 return -EOPNOTSUPP;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001279 }
1280 break;
1281
1282 default:
1283 dprintk("%s: unsupported delivery system selected (%d)\n",
1284 __func__, c->delivery_system);
1285 return -EOPNOTSUPP;
Darron Broad490c8682008-09-13 19:42:16 -03001286 }
Darron Broad01a8f032008-10-03 11:47:46 -03001287 state->dnxt.modulation = c->modulation;
1288 state->dnxt.frequency = c->frequency;
1289 state->dnxt.pilot = c->pilot;
1290 state->dnxt.rolloff = c->rolloff;
Darron Broad490c8682008-09-13 19:42:16 -03001291
Steven Tothf11ec7d2008-10-16 20:22:01 -03001292 ret = cx24116_set_inversion(state, c->inversion);
1293 if (ret != 0)
Steven Toth0d467482008-09-04 01:14:43 -03001294 return ret;
1295
Darron Broad01a8f032008-10-03 11:47:46 -03001296 /* FEC_NONE/AUTO for DVB-S2 is not supported and detected here */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001297 ret = cx24116_set_fec(state, c->modulation, c->fec_inner);
1298 if (ret != 0)
Steven Toth0d467482008-09-04 01:14:43 -03001299 return ret;
1300
Steven Tothf11ec7d2008-10-16 20:22:01 -03001301 ret = cx24116_set_symbolrate(state, c->symbol_rate);
1302 if (ret != 0)
Steven Toth0d467482008-09-04 01:14:43 -03001303 return ret;
1304
1305 /* discard the 'current' tuning parameters and prepare to tune */
1306 cx24116_clone_params(fe);
1307
Darron Broad01a8f032008-10-03 11:47:46 -03001308 dprintk("%s: modulation = %d\n", __func__, state->dcur.modulation);
Steven Toth0d467482008-09-04 01:14:43 -03001309 dprintk("%s: frequency = %d\n", __func__, state->dcur.frequency);
Darron Broad01a8f032008-10-03 11:47:46 -03001310 dprintk("%s: pilot = %d (val = 0x%02x)\n", __func__,
1311 state->dcur.pilot, state->dcur.pilot_val);
1312 dprintk("%s: retune = %d\n", __func__, retune);
1313 dprintk("%s: rolloff = %d (val = 0x%02x)\n", __func__,
1314 state->dcur.rolloff, state->dcur.rolloff_val);
Steven Toth0d467482008-09-04 01:14:43 -03001315 dprintk("%s: symbol_rate = %d\n", __func__, state->dcur.symbol_rate);
1316 dprintk("%s: FEC = %d (mask/val = 0x%02x/0x%02x)\n", __func__,
1317 state->dcur.fec, state->dcur.fec_mask, state->dcur.fec_val);
1318 dprintk("%s: Inversion = %d (val = 0x%02x)\n", __func__,
1319 state->dcur.inversion, state->dcur.inversion_val);
1320
Darron Broad490c8682008-09-13 19:42:16 -03001321 /* This is also done in advise/acquire on HVR4000 but not on LITE */
Steven Toth0d467482008-09-04 01:14:43 -03001322 if (state->config->set_ts_params)
1323 state->config->set_ts_params(fe, 0);
1324
Darron Broad490c8682008-09-13 19:42:16 -03001325 /* Set/Reset B/W */
1326 cmd.args[0x00] = CMD_BANDWIDTH;
1327 cmd.args[0x01] = 0x01;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001328 cmd.len = 0x02;
Darron Broad490c8682008-09-13 19:42:16 -03001329 ret = cx24116_cmd_execute(fe, &cmd);
1330 if (ret != 0)
1331 return ret;
Igor M. Liplianin3f8e51a2008-09-09 13:22:29 -03001332
Steven Toth0d467482008-09-04 01:14:43 -03001333 /* Prepare a tune request */
1334 cmd.args[0x00] = CMD_TUNEREQUEST;
1335
1336 /* Frequency */
1337 cmd.args[0x01] = (state->dcur.frequency & 0xff0000) >> 16;
1338 cmd.args[0x02] = (state->dcur.frequency & 0x00ff00) >> 8;
1339 cmd.args[0x03] = (state->dcur.frequency & 0x0000ff);
1340
1341 /* Symbol Rate */
1342 cmd.args[0x04] = ((state->dcur.symbol_rate / 1000) & 0xff00) >> 8;
1343 cmd.args[0x05] = ((state->dcur.symbol_rate / 1000) & 0x00ff);
1344
1345 /* Automatic Inversion */
1346 cmd.args[0x06] = state->dcur.inversion_val;
1347
Darron Broad01a8f032008-10-03 11:47:46 -03001348 /* Modulation / FEC / Pilot */
1349 cmd.args[0x07] = state->dcur.fec_val | state->dcur.pilot_val;
Steven Toth0d467482008-09-04 01:14:43 -03001350
1351 cmd.args[0x08] = CX24116_SEARCH_RANGE_KHZ >> 8;
1352 cmd.args[0x09] = CX24116_SEARCH_RANGE_KHZ & 0xff;
1353 cmd.args[0x0a] = 0x00;
1354 cmd.args[0x0b] = 0x00;
Darron Broad490c8682008-09-13 19:42:16 -03001355 cmd.args[0x0c] = state->dcur.rolloff_val;
Steven Toth0d467482008-09-04 01:14:43 -03001356 cmd.args[0x0d] = state->dcur.fec_mask;
Igor M. Liplianin3f8e51a2008-09-09 13:22:29 -03001357
Darron Broad490c8682008-09-13 19:42:16 -03001358 if (state->dcur.symbol_rate > 30000000) {
Igor M. Liplianin3f8e51a2008-09-09 13:22:29 -03001359 cmd.args[0x0e] = 0x04;
1360 cmd.args[0x0f] = 0x00;
1361 cmd.args[0x10] = 0x01;
1362 cmd.args[0x11] = 0x77;
1363 cmd.args[0x12] = 0x36;
Darron Broad490c8682008-09-13 19:42:16 -03001364 cx24116_writereg(state, CX24116_REG_CLKDIV, 0x44);
1365 cx24116_writereg(state, CX24116_REG_RATEDIV, 0x01);
Igor M. Liplianin3f8e51a2008-09-09 13:22:29 -03001366 } else {
1367 cmd.args[0x0e] = 0x06;
1368 cmd.args[0x0f] = 0x00;
1369 cmd.args[0x10] = 0x00;
1370 cmd.args[0x11] = 0xFA;
1371 cmd.args[0x12] = 0x24;
Darron Broad490c8682008-09-13 19:42:16 -03001372 cx24116_writereg(state, CX24116_REG_CLKDIV, 0x46);
1373 cx24116_writereg(state, CX24116_REG_RATEDIV, 0x00);
Igor M. Liplianin3f8e51a2008-09-09 13:22:29 -03001374 }
1375
Steven Tothf11ec7d2008-10-16 20:22:01 -03001376 cmd.len = 0x13;
Steven Toth0d467482008-09-04 01:14:43 -03001377
1378 /* We need to support pilot and non-pilot tuning in the
1379 * driver automatically. This is a workaround for because
1380 * the demod does not support autodetect.
1381 */
1382 do {
Darron Broad490c8682008-09-13 19:42:16 -03001383 /* Reset status register */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001384 status = cx24116_readreg(state, CX24116_REG_SSTATUS)
1385 & CX24116_SIGNAL_MASK;
Darron Broad490c8682008-09-13 19:42:16 -03001386 cx24116_writereg(state, CX24116_REG_SSTATUS, status);
Steven Toth0d467482008-09-04 01:14:43 -03001387
1388 /* Tune */
1389 ret = cx24116_cmd_execute(fe, &cmd);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001390 if (ret != 0)
Steven Toth0d467482008-09-04 01:14:43 -03001391 break;
1392
Darron Broad490c8682008-09-13 19:42:16 -03001393 /*
1394 * Wait for up to 500 ms before retrying
1395 *
1396 * If we are able to tune then generally it occurs within 100ms.
1397 * If it takes longer, try a different toneburst setting.
1398 */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001399 for (i = 0; i < 50 ; i++) {
Darron Broad490c8682008-09-13 19:42:16 -03001400 cx24116_read_status(fe, &tunerstat);
1401 status = tunerstat & (FE_HAS_SIGNAL | FE_HAS_SYNC);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001402 if (status == (FE_HAS_SIGNAL | FE_HAS_SYNC)) {
1403 dprintk("%s: Tuned\n", __func__);
Darron Broad490c8682008-09-13 19:42:16 -03001404 goto tuned;
1405 }
1406 msleep(10);
Steven Toth0d467482008-09-04 01:14:43 -03001407 }
Darron Broad490c8682008-09-13 19:42:16 -03001408
Steven Tothf11ec7d2008-10-16 20:22:01 -03001409 dprintk("%s: Not tuned\n", __func__);
Darron Broad490c8682008-09-13 19:42:16 -03001410
1411 /* Toggle pilot bit when in auto-pilot */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001412 if (state->dcur.pilot == PILOT_AUTO)
Darron Broad01a8f032008-10-03 11:47:46 -03001413 cmd.args[0x07] ^= CX24116_PILOT_ON;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001414 } while (--retune);
Steven Toth0d467482008-09-04 01:14:43 -03001415
Darron Broad490c8682008-09-13 19:42:16 -03001416tuned: /* Set/Reset B/W */
1417 cmd.args[0x00] = CMD_BANDWIDTH;
1418 cmd.args[0x01] = 0x00;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001419 cmd.len = 0x02;
Darron Broad490c8682008-09-13 19:42:16 -03001420 ret = cx24116_cmd_execute(fe, &cmd);
1421 if (ret != 0)
1422 return ret;
1423
Steven Toth0d467482008-09-04 01:14:43 -03001424 return ret;
1425}
1426
1427static struct dvb_frontend_ops cx24116_ops = {
1428
1429 .info = {
1430 .name = "Conexant CX24116/CX24118",
1431 .type = FE_QPSK,
1432 .frequency_min = 950000,
1433 .frequency_max = 2150000,
1434 .frequency_stepsize = 1011, /* kHz for QPSK frontends */
1435 .frequency_tolerance = 5000,
1436 .symbol_rate_min = 1000000,
1437 .symbol_rate_max = 45000000,
1438 .caps = FE_CAN_INVERSION_AUTO |
1439 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
1440 FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
1441 FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
1442 FE_CAN_QPSK | FE_CAN_RECOVER
1443 },
1444
1445 .release = cx24116_release,
1446
1447 .init = cx24116_initfe,
Darron Broad490c8682008-09-13 19:42:16 -03001448 .sleep = cx24116_sleep,
Steven Toth0d467482008-09-04 01:14:43 -03001449 .read_status = cx24116_read_status,
1450 .read_ber = cx24116_read_ber,
1451 .read_signal_strength = cx24116_read_signal_strength,
1452 .read_snr = cx24116_read_snr,
1453 .read_ucblocks = cx24116_read_ucblocks,
1454 .set_tone = cx24116_set_tone,
1455 .set_voltage = cx24116_set_voltage,
1456 .diseqc_send_master_cmd = cx24116_send_diseqc_msg,
1457 .diseqc_send_burst = cx24116_diseqc_send_burst,
1458
1459 .set_property = cx24116_set_property,
Steven Tothbfbf2da2008-09-12 01:37:37 -03001460 .get_property = cx24116_get_property,
Steven Toth0d467482008-09-04 01:14:43 -03001461 .set_frontend = cx24116_set_frontend,
1462};
1463
Steven Toth0d467482008-09-04 01:14:43 -03001464MODULE_DESCRIPTION("DVB Frontend module for Conexant cx24116/cx24118 hardware");
1465MODULE_AUTHOR("Steven Toth");
1466MODULE_LICENSE("GPL");
1467