blob: 95c6465b87a12b71e39015f6bf896dd84c766db4 [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.
Igor M. Liplianinc7bdcd02009-01-17 10:16:36 -030018 January, 17th 2009
19 Fill set_voltage with actually control voltage code.
20 Correct set tone to not affect voltage.
Steven Toth0d467482008-09-04 01:14:43 -030021
22 This program is free software; you can redistribute it and/or modify
23 it under the terms of the GNU General Public License as published by
24 the Free Software Foundation; either version 2 of the License, or
25 (at your option) any later version.
26
27 This program is distributed in the hope that it will be useful,
28 but WITHOUT ANY WARRANTY; without even the implied warranty of
29 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 GNU General Public License for more details.
31
32 You should have received a copy of the GNU General Public License
33 along with this program; if not, write to the Free Software
34 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35*/
36
Steven Toth0d467482008-09-04 01:14:43 -030037#include <linux/slab.h>
38#include <linux/kernel.h>
39#include <linux/module.h>
40#include <linux/moduleparam.h>
41#include <linux/init.h>
42#include <linux/firmware.h>
43
44#include "dvb_frontend.h"
45#include "cx24116.h"
46
Steven Tothf11ec7d2008-10-16 20:22:01 -030047static int debug;
48module_param(debug, int, 0644);
49MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
50
Darron Broad490c8682008-09-13 19:42:16 -030051#define dprintk(args...) \
52 do { \
Steven Tothf11ec7d2008-10-16 20:22:01 -030053 if (debug) \
Steven Toth98c94822008-10-16 20:24:42 -030054 printk(KERN_INFO "cx24116: " args); \
Darron Broad490c8682008-09-13 19:42:16 -030055 } while (0)
56
Steven Toth0d467482008-09-04 01:14:43 -030057#define CX24116_DEFAULT_FIRMWARE "dvb-fe-cx24116.fw"
58#define CX24116_SEARCH_RANGE_KHZ 5000
59
Darron Broad490c8682008-09-13 19:42:16 -030060/* known registers */
61#define CX24116_REG_COMMAND (0x00) /* command args 0x00..0x1e */
62#define CX24116_REG_EXECUTE (0x1f) /* execute command */
63#define CX24116_REG_MAILBOX (0x96) /* FW or multipurpose mailbox? */
64#define CX24116_REG_RESET (0x20) /* reset status > 0 */
65#define CX24116_REG_SIGNAL (0x9e) /* signal low */
66#define CX24116_REG_SSTATUS (0x9d) /* signal high / status */
Steven Toth8953db72008-10-06 21:20:21 -030067#define CX24116_REG_QUALITY8 (0xa3)
Darron Broad490c8682008-09-13 19:42:16 -030068#define CX24116_REG_QSTATUS (0xbc)
Steven Toth8953db72008-10-06 21:20:21 -030069#define CX24116_REG_QUALITY0 (0xd5)
Darron Broad490c8682008-09-13 19:42:16 -030070#define CX24116_REG_BER0 (0xc9)
71#define CX24116_REG_BER8 (0xc8)
72#define CX24116_REG_BER16 (0xc7)
73#define CX24116_REG_BER24 (0xc6)
74#define CX24116_REG_UCB0 (0xcb)
75#define CX24116_REG_UCB8 (0xca)
76#define CX24116_REG_CLKDIV (0xf3)
77#define CX24116_REG_RATEDIV (0xf9)
Steven Toth98c94822008-10-16 20:24:42 -030078
79/* configured fec (not tuned) or actual FEC (tuned) 1=1/2 2=2/3 etc */
80#define CX24116_REG_FECSTATUS (0x9c)
Darron Broad681faa02008-09-22 00:47:20 -030081
82/* FECSTATUS bits */
Steven Toth98c94822008-10-16 20:24:42 -030083/* mask to determine configured fec (not tuned) or actual fec (tuned) */
84#define CX24116_FEC_FECMASK (0x1f)
85
86/* Select DVB-S demodulator, else DVB-S2 */
87#define CX24116_FEC_DVBS (0x20)
Darron Broad681faa02008-09-22 00:47:20 -030088#define CX24116_FEC_UNKNOWN (0x40) /* Unknown/unused */
Steven Toth98c94822008-10-16 20:24:42 -030089
90/* Pilot mode requested when tuning else always reset when tuned */
91#define CX24116_FEC_PILOT (0x80)
Steven Toth0d467482008-09-04 01:14:43 -030092
93/* arg buffer size */
94#define CX24116_ARGLEN (0x1e)
95
Darron Broad490c8682008-09-13 19:42:16 -030096/* rolloff */
97#define CX24116_ROLLOFF_020 (0x00)
98#define CX24116_ROLLOFF_025 (0x01)
99#define CX24116_ROLLOFF_035 (0x02)
100
101/* pilot bit */
Darron Broad01a8f032008-10-03 11:47:46 -0300102#define CX24116_PILOT_OFF (0x00)
103#define CX24116_PILOT_ON (0x40)
Darron Broad490c8682008-09-13 19:42:16 -0300104
105/* signal status */
106#define CX24116_HAS_SIGNAL (0x01)
107#define CX24116_HAS_CARRIER (0x02)
108#define CX24116_HAS_VITERBI (0x04)
109#define CX24116_HAS_SYNCLOCK (0x08)
110#define CX24116_HAS_UNKNOWN1 (0x10)
111#define CX24116_HAS_UNKNOWN2 (0x20)
Darron Broad6639f1e2008-12-18 06:28:18 -0300112#define CX24116_STATUS_MASK (0x0f)
Darron Broad490c8682008-09-13 19:42:16 -0300113#define CX24116_SIGNAL_MASK (0xc0)
114
115#define CX24116_DISEQC_TONEOFF (0) /* toneburst never sent */
116#define CX24116_DISEQC_TONECACHE (1) /* toneburst cached */
117#define CX24116_DISEQC_MESGCACHE (2) /* message cached */
118
Steven Toth0d467482008-09-04 01:14:43 -0300119/* arg offset for DiSEqC */
120#define CX24116_DISEQC_BURST (1)
121#define CX24116_DISEQC_ARG2_2 (2) /* unknown value=2 */
122#define CX24116_DISEQC_ARG3_0 (3) /* unknown value=0 */
123#define CX24116_DISEQC_ARG4_0 (4) /* unknown value=0 */
124#define CX24116_DISEQC_MSGLEN (5)
125#define CX24116_DISEQC_MSGOFS (6)
126
127/* DiSEqC burst */
128#define CX24116_DISEQC_MINI_A (0)
129#define CX24116_DISEQC_MINI_B (1)
130
Darron Broad490c8682008-09-13 19:42:16 -0300131/* DiSEqC tone burst */
132static int toneburst = 1;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300133module_param(toneburst, int, 0644);
Steven Toth98c94822008-10-16 20:24:42 -0300134MODULE_PARM_DESC(toneburst, "DiSEqC toneburst 0=OFF, 1=TONE CACHE, "\
135 "2=MESSAGE CACHE (default:1)");
Darron Broad490c8682008-09-13 19:42:16 -0300136
Steven Toth8953db72008-10-06 21:20:21 -0300137/* SNR measurements */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300138static int esno_snr;
139module_param(esno_snr, int, 0644);
Hans Petter Selasky53f1fe92011-03-28 14:37:36 -0300140MODULE_PARM_DESC(esno_snr, "SNR return units, 0=PERCENTAGE 0-100, "\
Steven Toth98c94822008-10-16 20:24:42 -0300141 "1=ESNO(db * 10) (default:0)");
Steven Toth8953db72008-10-06 21:20:21 -0300142
Steven Tothf11ec7d2008-10-16 20:22:01 -0300143enum cmds {
Darron Broad490c8682008-09-13 19:42:16 -0300144 CMD_SET_VCO = 0x10,
Steven Toth0d467482008-09-04 01:14:43 -0300145 CMD_TUNEREQUEST = 0x11,
Darron Broad490c8682008-09-13 19:42:16 -0300146 CMD_MPEGCONFIG = 0x13,
147 CMD_TUNERINIT = 0x14,
148 CMD_BANDWIDTH = 0x15,
149 CMD_GETAGC = 0x19,
150 CMD_LNBCONFIG = 0x20,
151 CMD_LNBSEND = 0x21, /* Formerly CMD_SEND_DISEQC */
Igor M. Liplianinc7bdcd02009-01-17 10:16:36 -0300152 CMD_LNBDCLEVEL = 0x22,
Steven Toth0d467482008-09-04 01:14:43 -0300153 CMD_SET_TONE = 0x23,
Darron Broad490c8682008-09-13 19:42:16 -0300154 CMD_UPDFWVERS = 0x35,
155 CMD_TUNERSLEEP = 0x36,
156 CMD_AGCCONTROL = 0x3b, /* Unknown */
Steven Toth0d467482008-09-04 01:14:43 -0300157};
158
159/* The Demod/Tuner can't easily provide these, we cache them */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300160struct cx24116_tuning {
Steven Toth0d467482008-09-04 01:14:43 -0300161 u32 frequency;
162 u32 symbol_rate;
163 fe_spectral_inversion_t inversion;
164 fe_code_rate_t fec;
165
Darron Broad35694762008-12-18 06:21:51 -0300166 fe_delivery_system_t delsys;
Steven Toth0d467482008-09-04 01:14:43 -0300167 fe_modulation_t modulation;
Darron Broad490c8682008-09-13 19:42:16 -0300168 fe_pilot_t pilot;
169 fe_rolloff_t rolloff;
Steven Toth0d467482008-09-04 01:14:43 -0300170
171 /* Demod values */
172 u8 fec_val;
173 u8 fec_mask;
174 u8 inversion_val;
Darron Broad01a8f032008-10-03 11:47:46 -0300175 u8 pilot_val;
Darron Broad490c8682008-09-13 19:42:16 -0300176 u8 rolloff_val;
Steven Toth0d467482008-09-04 01:14:43 -0300177};
178
179/* Basic commands that are sent to the firmware */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300180struct cx24116_cmd {
Steven Toth0d467482008-09-04 01:14:43 -0300181 u8 len;
182 u8 args[CX24116_ARGLEN];
183};
184
Steven Tothf11ec7d2008-10-16 20:22:01 -0300185struct cx24116_state {
186 struct i2c_adapter *i2c;
187 const struct cx24116_config *config;
Steven Toth0d467482008-09-04 01:14:43 -0300188
189 struct dvb_frontend frontend;
190
191 struct cx24116_tuning dcur;
192 struct cx24116_tuning dnxt;
193
194 u8 skip_fw_load;
195 u8 burst;
Darron Broad490c8682008-09-13 19:42:16 -0300196 struct cx24116_cmd dsec_cmd;
Steven Toth0d467482008-09-04 01:14:43 -0300197};
198
Steven Tothf11ec7d2008-10-16 20:22:01 -0300199static int cx24116_writereg(struct cx24116_state *state, int reg, int data)
Steven Toth0d467482008-09-04 01:14:43 -0300200{
201 u8 buf[] = { reg, data };
202 struct i2c_msg msg = { .addr = state->config->demod_address,
203 .flags = 0, .buf = buf, .len = 2 };
204 int err;
205
Steven Tothf11ec7d2008-10-16 20:22:01 -0300206 if (debug > 1)
Steven Toth0d467482008-09-04 01:14:43 -0300207 printk("cx24116: %s: write reg 0x%02x, value 0x%02x\n",
Steven Tothf11ec7d2008-10-16 20:22:01 -0300208 __func__, reg, data);
Steven Toth0d467482008-09-04 01:14:43 -0300209
Steven Tothf11ec7d2008-10-16 20:22:01 -0300210 err = i2c_transfer(state->i2c, &msg, 1);
211 if (err != 1) {
Steven Toth98c94822008-10-16 20:24:42 -0300212 printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x,"
Steven Toth0d467482008-09-04 01:14:43 -0300213 " value == 0x%02x)\n", __func__, err, reg, data);
214 return -EREMOTEIO;
215 }
216
217 return 0;
218}
219
220/* Bulk byte writes to a single I2C address, for 32k firmware load */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300221static int cx24116_writeregN(struct cx24116_state *state, int reg,
Geert Uytterhoeven64decbf2008-10-16 21:04:35 -0300222 const u8 *data, u16 len)
Steven Toth0d467482008-09-04 01:14:43 -0300223{
224 int ret = -EREMOTEIO;
225 struct i2c_msg msg;
226 u8 *buf;
227
228 buf = kmalloc(len + 1, GFP_KERNEL);
229 if (buf == NULL) {
230 printk("Unable to kmalloc\n");
231 ret = -ENOMEM;
232 goto error;
233 }
234
235 *(buf) = reg;
236 memcpy(buf + 1, data, len);
237
238 msg.addr = state->config->demod_address;
239 msg.flags = 0;
240 msg.buf = buf;
241 msg.len = len + 1;
242
Steven Tothf11ec7d2008-10-16 20:22:01 -0300243 if (debug > 1)
Steven Toth98c94822008-10-16 20:24:42 -0300244 printk(KERN_INFO "cx24116: %s: write regN 0x%02x, len = %d\n",
Steven Tothf11ec7d2008-10-16 20:22:01 -0300245 __func__, reg, len);
Steven Toth0d467482008-09-04 01:14:43 -0300246
Steven Tothf11ec7d2008-10-16 20:22:01 -0300247 ret = i2c_transfer(state->i2c, &msg, 1);
248 if (ret != 1) {
Steven Toth98c94822008-10-16 20:24:42 -0300249 printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x\n",
Steven Toth0d467482008-09-04 01:14:43 -0300250 __func__, ret, reg);
251 ret = -EREMOTEIO;
252 }
253
254error:
255 kfree(buf);
256
257 return ret;
258}
259
Steven Tothf11ec7d2008-10-16 20:22:01 -0300260static int cx24116_readreg(struct cx24116_state *state, u8 reg)
Steven Toth0d467482008-09-04 01:14:43 -0300261{
262 int ret;
263 u8 b0[] = { reg };
264 u8 b1[] = { 0 };
265 struct i2c_msg msg[] = {
Steven Tothf11ec7d2008-10-16 20:22:01 -0300266 { .addr = state->config->demod_address, .flags = 0,
267 .buf = b0, .len = 1 },
268 { .addr = state->config->demod_address, .flags = I2C_M_RD,
269 .buf = b1, .len = 1 }
Steven Toth0d467482008-09-04 01:14:43 -0300270 };
271
272 ret = i2c_transfer(state->i2c, msg, 2);
273
274 if (ret != 2) {
Steven Toth98c94822008-10-16 20:24:42 -0300275 printk(KERN_ERR "%s: reg=0x%x (error=%d)\n",
276 __func__, reg, ret);
Steven Toth0d467482008-09-04 01:14:43 -0300277 return ret;
278 }
279
Steven Tothf11ec7d2008-10-16 20:22:01 -0300280 if (debug > 1)
Steven Toth98c94822008-10-16 20:24:42 -0300281 printk(KERN_INFO "cx24116: read reg 0x%02x, value 0x%02x\n",
Steven Tothf11ec7d2008-10-16 20:22:01 -0300282 reg, b1[0]);
Steven Toth0d467482008-09-04 01:14:43 -0300283
284 return b1[0];
285}
286
Steven Toth98c94822008-10-16 20:24:42 -0300287static int cx24116_set_inversion(struct cx24116_state *state,
288 fe_spectral_inversion_t inversion)
Steven Toth0d467482008-09-04 01:14:43 -0300289{
290 dprintk("%s(%d)\n", __func__, inversion);
291
292 switch (inversion) {
293 case INVERSION_OFF:
294 state->dnxt.inversion_val = 0x00;
295 break;
296 case INVERSION_ON:
297 state->dnxt.inversion_val = 0x04;
298 break;
299 case INVERSION_AUTO:
300 state->dnxt.inversion_val = 0x0C;
301 break;
302 default:
303 return -EINVAL;
304 }
305
306 state->dnxt.inversion = inversion;
307
308 return 0;
309}
310
Darron Broad490c8682008-09-13 19:42:16 -0300311/*
312 * modfec (modulation and FEC)
313 * ===========================
314 *
315 * MOD FEC mask/val standard
316 * ---- -------- ----------- --------
317 * QPSK FEC_1_2 0x02 0x02+X DVB-S
318 * QPSK FEC_2_3 0x04 0x02+X DVB-S
319 * QPSK FEC_3_4 0x08 0x02+X DVB-S
320 * QPSK FEC_4_5 0x10 0x02+X DVB-S (?)
321 * QPSK FEC_5_6 0x20 0x02+X DVB-S
322 * QPSK FEC_6_7 0x40 0x02+X DVB-S
323 * QPSK FEC_7_8 0x80 0x02+X DVB-S
324 * QPSK FEC_8_9 0x01 0x02+X DVB-S (?) (NOT SUPPORTED?)
325 * QPSK AUTO 0xff 0x02+X DVB-S
326 *
327 * For DVB-S high byte probably represents FEC
328 * and low byte selects the modulator. The high
329 * byte is search range mask. Bit 5 may turn
330 * on DVB-S and remaining bits represent some
331 * kind of calibration (how/what i do not know).
332 *
333 * Eg.(2/3) szap "Zone Horror"
334 *
335 * mask/val = 0x04, 0x20
Steven Toth98c94822008-10-16 20:24:42 -0300336 * status 1f | signal c3c0 | snr a333 | ber 00000098 | unc 0 | FE_HAS_LOCK
Darron Broad490c8682008-09-13 19:42:16 -0300337 *
338 * mask/val = 0x04, 0x30
Steven Toth98c94822008-10-16 20:24:42 -0300339 * status 1f | signal c3c0 | snr a333 | ber 00000000 | unc 0 | FE_HAS_LOCK
Darron Broad490c8682008-09-13 19:42:16 -0300340 *
341 * After tuning FECSTATUS contains actual FEC
342 * in use numbered 1 through to 8 for 1/2 .. 2/3 etc
343 *
344 * NBC=NOT/NON BACKWARD COMPATIBLE WITH DVB-S (DVB-S2 only)
345 *
346 * NBC-QPSK FEC_1_2 0x00, 0x04 DVB-S2
347 * NBC-QPSK FEC_3_5 0x00, 0x05 DVB-S2
348 * NBC-QPSK FEC_2_3 0x00, 0x06 DVB-S2
349 * NBC-QPSK FEC_3_4 0x00, 0x07 DVB-S2
350 * NBC-QPSK FEC_4_5 0x00, 0x08 DVB-S2
351 * NBC-QPSK FEC_5_6 0x00, 0x09 DVB-S2
352 * NBC-QPSK FEC_8_9 0x00, 0x0a DVB-S2
353 * NBC-QPSK FEC_9_10 0x00, 0x0b DVB-S2
354 *
355 * NBC-8PSK FEC_3_5 0x00, 0x0c DVB-S2
356 * NBC-8PSK FEC_2_3 0x00, 0x0d DVB-S2
357 * NBC-8PSK FEC_3_4 0x00, 0x0e DVB-S2
358 * NBC-8PSK FEC_5_6 0x00, 0x0f DVB-S2
359 * NBC-8PSK FEC_8_9 0x00, 0x10 DVB-S2
360 * NBC-8PSK FEC_9_10 0x00, 0x11 DVB-S2
361 *
362 * For DVB-S2 low bytes selects both modulator
363 * and FEC. High byte is meaningless here. To
364 * set pilot, bit 6 (0x40) is set. When inspecting
365 * FECSTATUS bit 7 (0x80) represents the pilot
366 * selection whilst not tuned. When tuned, actual FEC
367 * in use is found in FECSTATUS as per above. Pilot
368 * value is reset.
369 */
370
Steven Toth0d467482008-09-04 01:14:43 -0300371/* A table of modulation, fec and configuration bytes for the demod.
372 * Not all S2 mmodulation schemes are support and not all rates with
373 * a scheme are support. Especially, no auto detect when in S2 mode.
374 */
Mauro Carvalho Chehabffbc5f82009-01-05 01:34:20 -0300375static struct cx24116_modfec {
Steven Toth0a6393a2008-10-06 21:06:48 -0300376 fe_delivery_system_t delivery_system;
Steven Toth0d467482008-09-04 01:14:43 -0300377 fe_modulation_t modulation;
378 fe_code_rate_t fec;
379 u8 mask; /* In DVBS mode this is used to autodetect */
380 u8 val; /* Passed to the firmware to indicate mode selection */
381} CX24116_MODFEC_MODES[] = {
382 /* QPSK. For unknown rates we set hardware to auto detect 0xfe 0x30 */
Darron Broad490c8682008-09-13 19:42:16 -0300383
384 /*mod fec mask val */
Steven Toth0a6393a2008-10-06 21:06:48 -0300385 { SYS_DVBS, QPSK, FEC_NONE, 0xfe, 0x30 },
386 { SYS_DVBS, QPSK, FEC_1_2, 0x02, 0x2e }, /* 00000010 00101110 */
387 { SYS_DVBS, QPSK, FEC_2_3, 0x04, 0x2f }, /* 00000100 00101111 */
388 { SYS_DVBS, QPSK, FEC_3_4, 0x08, 0x30 }, /* 00001000 00110000 */
389 { SYS_DVBS, QPSK, FEC_4_5, 0xfe, 0x30 }, /* 000?0000 ? */
390 { SYS_DVBS, QPSK, FEC_5_6, 0x20, 0x31 }, /* 00100000 00110001 */
391 { SYS_DVBS, QPSK, FEC_6_7, 0xfe, 0x30 }, /* 0?000000 ? */
392 { SYS_DVBS, QPSK, FEC_7_8, 0x80, 0x32 }, /* 10000000 00110010 */
393 { SYS_DVBS, QPSK, FEC_8_9, 0xfe, 0x30 }, /* 0000000? ? */
394 { SYS_DVBS, QPSK, FEC_AUTO, 0xfe, 0x30 },
Steven Toth0d467482008-09-04 01:14:43 -0300395 /* NBC-QPSK */
Steven Toth0a6393a2008-10-06 21:06:48 -0300396 { SYS_DVBS2, QPSK, FEC_1_2, 0x00, 0x04 },
397 { SYS_DVBS2, QPSK, FEC_3_5, 0x00, 0x05 },
398 { SYS_DVBS2, QPSK, FEC_2_3, 0x00, 0x06 },
399 { SYS_DVBS2, QPSK, FEC_3_4, 0x00, 0x07 },
400 { SYS_DVBS2, QPSK, FEC_4_5, 0x00, 0x08 },
401 { SYS_DVBS2, QPSK, FEC_5_6, 0x00, 0x09 },
402 { SYS_DVBS2, QPSK, FEC_8_9, 0x00, 0x0a },
403 { SYS_DVBS2, QPSK, FEC_9_10, 0x00, 0x0b },
Steven Toth0d467482008-09-04 01:14:43 -0300404 /* 8PSK */
Steven Toth0a6393a2008-10-06 21:06:48 -0300405 { SYS_DVBS2, PSK_8, FEC_3_5, 0x00, 0x0c },
406 { SYS_DVBS2, PSK_8, FEC_2_3, 0x00, 0x0d },
407 { SYS_DVBS2, PSK_8, FEC_3_4, 0x00, 0x0e },
408 { SYS_DVBS2, PSK_8, FEC_5_6, 0x00, 0x0f },
409 { SYS_DVBS2, PSK_8, FEC_8_9, 0x00, 0x10 },
410 { SYS_DVBS2, PSK_8, FEC_9_10, 0x00, 0x11 },
Darron Broad490c8682008-09-13 19:42:16 -0300411 /*
412 * `val' can be found in the FECSTATUS register when tuning.
413 * FECSTATUS will give the actual FEC in use if tuning was successful.
414 */
Steven Toth0d467482008-09-04 01:14:43 -0300415};
416
Steven Tothf11ec7d2008-10-16 20:22:01 -0300417static int cx24116_lookup_fecmod(struct cx24116_state *state,
Darron Broad35694762008-12-18 06:21:51 -0300418 fe_delivery_system_t d, fe_modulation_t m, fe_code_rate_t f)
Steven Toth0d467482008-09-04 01:14:43 -0300419{
420 int i, ret = -EOPNOTSUPP;
421
Darron Broad490c8682008-09-13 19:42:16 -0300422 dprintk("%s(0x%02x,0x%02x)\n", __func__, m, f);
423
Steven Tothf11ec7d2008-10-16 20:22:01 -0300424 for (i = 0; i < ARRAY_SIZE(CX24116_MODFEC_MODES); i++) {
Darron Broad35694762008-12-18 06:21:51 -0300425 if ((d == CX24116_MODFEC_MODES[i].delivery_system) &&
426 (m == CX24116_MODFEC_MODES[i].modulation) &&
Steven Tothf11ec7d2008-10-16 20:22:01 -0300427 (f == CX24116_MODFEC_MODES[i].fec)) {
Steven Toth0d467482008-09-04 01:14:43 -0300428 ret = i;
429 break;
430 }
431 }
432
433 return ret;
434}
435
Steven Toth98c94822008-10-16 20:24:42 -0300436static int cx24116_set_fec(struct cx24116_state *state,
Darron Broad35694762008-12-18 06:21:51 -0300437 fe_delivery_system_t delsys, fe_modulation_t mod, fe_code_rate_t fec)
Steven Toth0d467482008-09-04 01:14:43 -0300438{
439 int ret = 0;
Darron Broad490c8682008-09-13 19:42:16 -0300440
441 dprintk("%s(0x%02x,0x%02x)\n", __func__, mod, fec);
Steven Toth0d467482008-09-04 01:14:43 -0300442
Darron Broad35694762008-12-18 06:21:51 -0300443 ret = cx24116_lookup_fecmod(state, delsys, mod, fec);
Steven Toth0d467482008-09-04 01:14:43 -0300444
Steven Tothf11ec7d2008-10-16 20:22:01 -0300445 if (ret < 0)
Steven Toth0d467482008-09-04 01:14:43 -0300446 return ret;
447
Darron Broad490c8682008-09-13 19:42:16 -0300448 state->dnxt.fec = fec;
Steven Toth0d467482008-09-04 01:14:43 -0300449 state->dnxt.fec_val = CX24116_MODFEC_MODES[ret].val;
450 state->dnxt.fec_mask = CX24116_MODFEC_MODES[ret].mask;
Darron Broad490c8682008-09-13 19:42:16 -0300451 dprintk("%s() mask/val = 0x%02x/0x%02x\n", __func__,
452 state->dnxt.fec_mask, state->dnxt.fec_val);
Steven Toth0d467482008-09-04 01:14:43 -0300453
454 return 0;
455}
456
Steven Tothf11ec7d2008-10-16 20:22:01 -0300457static int cx24116_set_symbolrate(struct cx24116_state *state, u32 rate)
Steven Toth0d467482008-09-04 01:14:43 -0300458{
Darron Broad490c8682008-09-13 19:42:16 -0300459 dprintk("%s(%d)\n", __func__, rate);
Steven Toth0d467482008-09-04 01:14:43 -0300460
461 /* check if symbol rate is within limits */
Darron Broad490c8682008-09-13 19:42:16 -0300462 if ((rate > state->frontend.ops.info.symbol_rate_max) ||
463 (rate < state->frontend.ops.info.symbol_rate_min)) {
464 dprintk("%s() unsupported symbol_rate = %d\n", __func__, rate);
465 return -EOPNOTSUPP;
466 }
Steven Toth0d467482008-09-04 01:14:43 -0300467
Darron Broad490c8682008-09-13 19:42:16 -0300468 state->dnxt.symbol_rate = rate;
469 dprintk("%s() symbol_rate = %d\n", __func__, rate);
470
471 return 0;
Steven Toth0d467482008-09-04 01:14:43 -0300472}
473
Steven Tothf11ec7d2008-10-16 20:22:01 -0300474static int cx24116_load_firmware(struct dvb_frontend *fe,
475 const struct firmware *fw);
Steven Toth0d467482008-09-04 01:14:43 -0300476
Steven Tothf11ec7d2008-10-16 20:22:01 -0300477static int cx24116_firmware_ondemand(struct dvb_frontend *fe)
Steven Toth0d467482008-09-04 01:14:43 -0300478{
479 struct cx24116_state *state = fe->demodulator_priv;
480 const struct firmware *fw;
481 int ret = 0;
482
Steven Tothf11ec7d2008-10-16 20:22:01 -0300483 dprintk("%s()\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -0300484
Steven Tothf11ec7d2008-10-16 20:22:01 -0300485 if (cx24116_readreg(state, 0x20) > 0) {
Steven Toth0d467482008-09-04 01:14:43 -0300486
487 if (state->skip_fw_load)
488 return 0;
489
490 /* Load firmware */
Steven Toth98c94822008-10-16 20:24:42 -0300491 /* request the firmware, this will block until loaded */
492 printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n",
493 __func__, CX24116_DEFAULT_FIRMWARE);
494 ret = request_firmware(&fw, CX24116_DEFAULT_FIRMWARE,
Jean Delvaree9785252009-04-26 05:43:59 -0300495 state->i2c->dev.parent);
Steven Toth98c94822008-10-16 20:24:42 -0300496 printk(KERN_INFO "%s: Waiting for firmware upload(2)...\n",
497 __func__);
Steven Toth0d467482008-09-04 01:14:43 -0300498 if (ret) {
Steven Toth98c94822008-10-16 20:24:42 -0300499 printk(KERN_ERR "%s: No firmware uploaded "
500 "(timeout or file not found?)\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -0300501 return ret;
502 }
503
Steven Toth98c94822008-10-16 20:24:42 -0300504 /* Make sure we don't recurse back through here
505 * during loading */
Steven Toth0d467482008-09-04 01:14:43 -0300506 state->skip_fw_load = 1;
507
508 ret = cx24116_load_firmware(fe, fw);
509 if (ret)
Steven Toth98c94822008-10-16 20:24:42 -0300510 printk(KERN_ERR "%s: Writing firmware to device failed\n",
511 __func__);
Steven Toth0d467482008-09-04 01:14:43 -0300512
513 release_firmware(fw);
514
Steven Toth98c94822008-10-16 20:24:42 -0300515 printk(KERN_INFO "%s: Firmware upload %s\n", __func__,
516 ret == 0 ? "complete" : "failed");
Steven Toth0d467482008-09-04 01:14:43 -0300517
518 /* Ensure firmware is always loaded if required */
519 state->skip_fw_load = 0;
520 }
521
522 return ret;
523}
524
Steven Toth98c94822008-10-16 20:24:42 -0300525/* Take a basic firmware command structure, format it
526 * and forward it for processing
527 */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300528static int cx24116_cmd_execute(struct dvb_frontend *fe, struct cx24116_cmd *cmd)
Steven Toth0d467482008-09-04 01:14:43 -0300529{
530 struct cx24116_state *state = fe->demodulator_priv;
531 int i, ret;
532
533 dprintk("%s()\n", __func__);
534
535 /* Load the firmware if required */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300536 ret = cx24116_firmware_ondemand(fe);
537 if (ret != 0) {
Steven Toth98c94822008-10-16 20:24:42 -0300538 printk(KERN_ERR "%s(): Unable initialise the firmware\n",
539 __func__);
Steven Toth0d467482008-09-04 01:14:43 -0300540 return ret;
541 }
542
543 /* Write the command */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300544 for (i = 0; i < cmd->len ; i++) {
Steven Toth0d467482008-09-04 01:14:43 -0300545 dprintk("%s: 0x%02x == 0x%02x\n", __func__, i, cmd->args[i]);
546 cx24116_writereg(state, i, cmd->args[i]);
547 }
548
549 /* Start execution and wait for cmd to terminate */
Darron Broad490c8682008-09-13 19:42:16 -0300550 cx24116_writereg(state, CX24116_REG_EXECUTE, 0x01);
Steven Tothf11ec7d2008-10-16 20:22:01 -0300551 while (cx24116_readreg(state, CX24116_REG_EXECUTE)) {
Steven Toth0d467482008-09-04 01:14:43 -0300552 msleep(10);
Steven Tothf11ec7d2008-10-16 20:22:01 -0300553 if (i++ > 64) {
Steven Toth98c94822008-10-16 20:24:42 -0300554 /* Avoid looping forever if the firmware does
555 not respond */
556 printk(KERN_WARNING "%s() Firmware not responding\n",
557 __func__);
Steven Toth0d467482008-09-04 01:14:43 -0300558 return -EREMOTEIO;
559 }
560 }
561 return 0;
562}
563
Steven Tothf11ec7d2008-10-16 20:22:01 -0300564static int cx24116_load_firmware(struct dvb_frontend *fe,
565 const struct firmware *fw)
Steven Toth0d467482008-09-04 01:14:43 -0300566{
Steven Tothf11ec7d2008-10-16 20:22:01 -0300567 struct cx24116_state *state = fe->demodulator_priv;
Steven Toth0d467482008-09-04 01:14:43 -0300568 struct cx24116_cmd cmd;
Antti Palosaarie0bae9b2011-05-04 17:23:09 -0300569 int i, ret, len, max, remaining;
Darron Broad490c8682008-09-13 19:42:16 -0300570 unsigned char vers[4];
Steven Toth0d467482008-09-04 01:14:43 -0300571
572 dprintk("%s\n", __func__);
Steven Tothf11ec7d2008-10-16 20:22:01 -0300573 dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n",
574 fw->size,
575 fw->data[0],
576 fw->data[1],
577 fw->data[fw->size-2],
578 fw->data[fw->size-1]);
Steven Toth0d467482008-09-04 01:14:43 -0300579
580 /* Toggle 88x SRST pin to reset demod */
581 if (state->config->reset_device)
582 state->config->reset_device(fe);
583
584 /* Begin the firmware load process */
585 /* Prepare the demod, load the firmware, cleanup after load */
Steven Toth0d467482008-09-04 01:14:43 -0300586
Darron Broad490c8682008-09-13 19:42:16 -0300587 /* Init PLL */
588 cx24116_writereg(state, 0xE5, 0x00);
589 cx24116_writereg(state, 0xF1, 0x08);
590 cx24116_writereg(state, 0xF2, 0x13);
591
592 /* Start PLL */
593 cx24116_writereg(state, 0xe0, 0x03);
594 cx24116_writereg(state, 0xe0, 0x00);
595
596 /* Unknown */
597 cx24116_writereg(state, CX24116_REG_CLKDIV, 0x46);
598 cx24116_writereg(state, CX24116_REG_RATEDIV, 0x00);
599
600 /* Unknown */
Steven Toth0d467482008-09-04 01:14:43 -0300601 cx24116_writereg(state, 0xF0, 0x03);
602 cx24116_writereg(state, 0xF4, 0x81);
603 cx24116_writereg(state, 0xF5, 0x00);
604 cx24116_writereg(state, 0xF6, 0x00);
605
Antti Palosaari107d7b12011-04-27 21:03:07 -0300606 /* Split firmware to the max I2C write len and write.
Antti Palosaarie0bae9b2011-05-04 17:23:09 -0300607 * Writes whole firmware as one write when i2c_wr_max is set to 0. */
608 if (state->config->i2c_wr_max)
609 max = state->config->i2c_wr_max;
610 else
611 max = INT_MAX; /* enough for 32k firmware */
Antti Palosaari107d7b12011-04-27 21:03:07 -0300612
Antti Palosaarie0bae9b2011-05-04 17:23:09 -0300613 for (remaining = fw->size; remaining > 0; remaining -= max - 1) {
Antti Palosaari107d7b12011-04-27 21:03:07 -0300614 len = remaining;
Antti Palosaarie0bae9b2011-05-04 17:23:09 -0300615 if (len > max - 1)
616 len = max - 1;
Antti Palosaari107d7b12011-04-27 21:03:07 -0300617
618 cx24116_writeregN(state, 0xF7, &fw->data[fw->size - remaining],
619 len);
620 }
Steven Toth0d467482008-09-04 01:14:43 -0300621
622 cx24116_writereg(state, 0xF4, 0x10);
623 cx24116_writereg(state, 0xF0, 0x00);
624 cx24116_writereg(state, 0xF8, 0x06);
625
Darron Broad490c8682008-09-13 19:42:16 -0300626 /* Firmware CMD 10: VCO config */
627 cmd.args[0x00] = CMD_SET_VCO;
Steven Toth0d467482008-09-04 01:14:43 -0300628 cmd.args[0x01] = 0x05;
629 cmd.args[0x02] = 0xdc;
630 cmd.args[0x03] = 0xda;
631 cmd.args[0x04] = 0xae;
632 cmd.args[0x05] = 0xaa;
633 cmd.args[0x06] = 0x04;
634 cmd.args[0x07] = 0x9d;
635 cmd.args[0x08] = 0xfc;
636 cmd.args[0x09] = 0x06;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300637 cmd.len = 0x0a;
Steven Toth0d467482008-09-04 01:14:43 -0300638 ret = cx24116_cmd_execute(fe, &cmd);
639 if (ret != 0)
640 return ret;
641
Darron Broad490c8682008-09-13 19:42:16 -0300642 cx24116_writereg(state, CX24116_REG_SSTATUS, 0x00);
Steven Toth0d467482008-09-04 01:14:43 -0300643
Darron Broad490c8682008-09-13 19:42:16 -0300644 /* Firmware CMD 14: Tuner config */
645 cmd.args[0x00] = CMD_TUNERINIT;
Steven Toth0d467482008-09-04 01:14:43 -0300646 cmd.args[0x01] = 0x00;
647 cmd.args[0x02] = 0x00;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300648 cmd.len = 0x03;
Steven Toth0d467482008-09-04 01:14:43 -0300649 ret = cx24116_cmd_execute(fe, &cmd);
650 if (ret != 0)
651 return ret;
652
653 cx24116_writereg(state, 0xe5, 0x00);
654
Darron Broad490c8682008-09-13 19:42:16 -0300655 /* Firmware CMD 13: MPEG config */
656 cmd.args[0x00] = CMD_MPEGCONFIG;
Steven Toth0d467482008-09-04 01:14:43 -0300657 cmd.args[0x01] = 0x01;
658 cmd.args[0x02] = 0x75;
659 cmd.args[0x03] = 0x00;
Igor M. Liplianincc8c4f32008-09-09 13:57:47 -0300660 if (state->config->mpg_clk_pos_pol)
661 cmd.args[0x04] = state->config->mpg_clk_pos_pol;
662 else
663 cmd.args[0x04] = 0x02;
Steven Toth0d467482008-09-04 01:14:43 -0300664 cmd.args[0x05] = 0x00;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300665 cmd.len = 0x06;
Steven Toth0d467482008-09-04 01:14:43 -0300666 ret = cx24116_cmd_execute(fe, &cmd);
667 if (ret != 0)
668 return ret;
669
Darron Broad490c8682008-09-13 19:42:16 -0300670 /* Firmware CMD 35: Get firmware version */
671 cmd.args[0x00] = CMD_UPDFWVERS;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300672 cmd.len = 0x02;
673 for (i = 0; i < 4; i++) {
Darron Broad490c8682008-09-13 19:42:16 -0300674 cmd.args[0x01] = i;
675 ret = cx24116_cmd_execute(fe, &cmd);
676 if (ret != 0)
677 return ret;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300678 vers[i] = cx24116_readreg(state, CX24116_REG_MAILBOX);
Darron Broad490c8682008-09-13 19:42:16 -0300679 }
Steven Toth98c94822008-10-16 20:24:42 -0300680 printk(KERN_INFO "%s: FW version %i.%i.%i.%i\n", __func__,
Darron Broad490c8682008-09-13 19:42:16 -0300681 vers[0], vers[1], vers[2], vers[3]);
682
Steven Toth0d467482008-09-04 01:14:43 -0300683 return 0;
684}
685
Steven Tothf11ec7d2008-10-16 20:22:01 -0300686static int cx24116_read_status(struct dvb_frontend *fe, fe_status_t *status)
Steven Toth0d467482008-09-04 01:14:43 -0300687{
688 struct cx24116_state *state = fe->demodulator_priv;
689
Darron Broad6639f1e2008-12-18 06:28:18 -0300690 int lock = cx24116_readreg(state, CX24116_REG_SSTATUS) &
691 CX24116_STATUS_MASK;
Steven Toth0d467482008-09-04 01:14:43 -0300692
693 dprintk("%s: status = 0x%02x\n", __func__, lock);
694
695 *status = 0;
696
Darron Broad490c8682008-09-13 19:42:16 -0300697 if (lock & CX24116_HAS_SIGNAL)
Steven Toth0d467482008-09-04 01:14:43 -0300698 *status |= FE_HAS_SIGNAL;
Darron Broad490c8682008-09-13 19:42:16 -0300699 if (lock & CX24116_HAS_CARRIER)
Steven Toth0d467482008-09-04 01:14:43 -0300700 *status |= FE_HAS_CARRIER;
Darron Broad490c8682008-09-13 19:42:16 -0300701 if (lock & CX24116_HAS_VITERBI)
Steven Toth0d467482008-09-04 01:14:43 -0300702 *status |= FE_HAS_VITERBI;
Darron Broad490c8682008-09-13 19:42:16 -0300703 if (lock & CX24116_HAS_SYNCLOCK)
Steven Toth0d467482008-09-04 01:14:43 -0300704 *status |= FE_HAS_SYNC | FE_HAS_LOCK;
705
706 return 0;
707}
708
Steven Tothf11ec7d2008-10-16 20:22:01 -0300709static int cx24116_read_ber(struct dvb_frontend *fe, u32 *ber)
Steven Toth0d467482008-09-04 01:14:43 -0300710{
Darron Broad490c8682008-09-13 19:42:16 -0300711 struct cx24116_state *state = fe->demodulator_priv;
712
Steven Toth0d467482008-09-04 01:14:43 -0300713 dprintk("%s()\n", __func__);
Darron Broad490c8682008-09-13 19:42:16 -0300714
Steven Tothf11ec7d2008-10-16 20:22:01 -0300715 *ber = (cx24116_readreg(state, CX24116_REG_BER24) << 24) |
716 (cx24116_readreg(state, CX24116_REG_BER16) << 16) |
717 (cx24116_readreg(state, CX24116_REG_BER8) << 8) |
718 cx24116_readreg(state, CX24116_REG_BER0);
Steven Toth0d467482008-09-04 01:14:43 -0300719
720 return 0;
721}
722
Darron Broad490c8682008-09-13 19:42:16 -0300723/* TODO Determine function and scale appropriately */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300724static int cx24116_read_signal_strength(struct dvb_frontend *fe,
725 u16 *signal_strength)
Steven Toth0d467482008-09-04 01:14:43 -0300726{
727 struct cx24116_state *state = fe->demodulator_priv;
Darron Broad490c8682008-09-13 19:42:16 -0300728 struct cx24116_cmd cmd;
729 int ret;
730 u16 sig_reading;
731
732 dprintk("%s()\n", __func__);
733
734 /* Firmware CMD 19: Get AGC */
735 cmd.args[0x00] = CMD_GETAGC;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300736 cmd.len = 0x01;
Darron Broad490c8682008-09-13 19:42:16 -0300737 ret = cx24116_cmd_execute(fe, &cmd);
738 if (ret != 0)
739 return ret;
740
Steven Tothf11ec7d2008-10-16 20:22:01 -0300741 sig_reading =
742 (cx24116_readreg(state,
743 CX24116_REG_SSTATUS) & CX24116_SIGNAL_MASK) |
744 (cx24116_readreg(state, CX24116_REG_SIGNAL) << 6);
745 *signal_strength = 0 - sig_reading;
Darron Broad490c8682008-09-13 19:42:16 -0300746
Steven Tothf11ec7d2008-10-16 20:22:01 -0300747 dprintk("%s: raw / cooked = 0x%04x / 0x%04x\n",
748 __func__, sig_reading, *signal_strength);
Darron Broad490c8682008-09-13 19:42:16 -0300749
750 return 0;
751}
752
753/* SNR (0..100)% = (sig & 0xf0) * 10 + (sig & 0x0f) * 10 / 16 */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300754static int cx24116_read_snr_pct(struct dvb_frontend *fe, u16 *snr)
Darron Broad490c8682008-09-13 19:42:16 -0300755{
756 struct cx24116_state *state = fe->demodulator_priv;
757 u8 snr_reading;
758 static const u32 snr_tab[] = { /* 10 x Table (rounded up) */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300759 0x00000, 0x0199A, 0x03333, 0x04ccD, 0x06667,
760 0x08000, 0x0999A, 0x0b333, 0x0cccD, 0x0e667,
761 0x10000, 0x1199A, 0x13333, 0x14ccD, 0x16667,
762 0x18000 };
Steven Toth0d467482008-09-04 01:14:43 -0300763
764 dprintk("%s()\n", __func__);
765
Steven Toth8953db72008-10-06 21:20:21 -0300766 snr_reading = cx24116_readreg(state, CX24116_REG_QUALITY0);
Steven Toth0d467482008-09-04 01:14:43 -0300767
Steven Tothf11ec7d2008-10-16 20:22:01 -0300768 if (snr_reading >= 0xa0 /* 100% */)
Darron Broad490c8682008-09-13 19:42:16 -0300769 *snr = 0xffff;
Steven Toth0d467482008-09-04 01:14:43 -0300770 else
Steven Tothf11ec7d2008-10-16 20:22:01 -0300771 *snr = snr_tab[(snr_reading & 0xf0) >> 4] +
772 (snr_tab[(snr_reading & 0x0f)] >> 4);
Steven Toth0d467482008-09-04 01:14:43 -0300773
Darron Broad490c8682008-09-13 19:42:16 -0300774 dprintk("%s: raw / cooked = 0x%02x / 0x%04x\n", __func__,
775 snr_reading, *snr);
Steven Toth0d467482008-09-04 01:14:43 -0300776
777 return 0;
778}
779
Steven Toth8953db72008-10-06 21:20:21 -0300780/* The reelbox patches show the value in the registers represents
781 * ESNO, from 0->30db (values 0->300). We provide this value by
782 * default.
783 */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300784static int cx24116_read_snr_esno(struct dvb_frontend *fe, u16 *snr)
Steven Toth8953db72008-10-06 21:20:21 -0300785{
786 struct cx24116_state *state = fe->demodulator_priv;
787
788 dprintk("%s()\n", __func__);
789
790 *snr = cx24116_readreg(state, CX24116_REG_QUALITY8) << 8 |
791 cx24116_readreg(state, CX24116_REG_QUALITY0);
792
793 dprintk("%s: raw 0x%04x\n", __func__, *snr);
794
795 return 0;
796}
797
Steven Tothf11ec7d2008-10-16 20:22:01 -0300798static int cx24116_read_snr(struct dvb_frontend *fe, u16 *snr)
Steven Toth8953db72008-10-06 21:20:21 -0300799{
800 if (esno_snr == 1)
801 return cx24116_read_snr_esno(fe, snr);
802 else
803 return cx24116_read_snr_pct(fe, snr);
804}
805
Steven Tothf11ec7d2008-10-16 20:22:01 -0300806static int cx24116_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
Steven Toth0d467482008-09-04 01:14:43 -0300807{
Darron Broad490c8682008-09-13 19:42:16 -0300808 struct cx24116_state *state = fe->demodulator_priv;
809
Steven Toth0d467482008-09-04 01:14:43 -0300810 dprintk("%s()\n", __func__);
Darron Broad490c8682008-09-13 19:42:16 -0300811
Steven Tothf11ec7d2008-10-16 20:22:01 -0300812 *ucblocks = (cx24116_readreg(state, CX24116_REG_UCB8) << 8) |
Darron Broad490c8682008-09-13 19:42:16 -0300813 cx24116_readreg(state, CX24116_REG_UCB0);
Steven Toth0d467482008-09-04 01:14:43 -0300814
815 return 0;
816}
817
818/* Overwrite the current tuning params, we are about to tune */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300819static void cx24116_clone_params(struct dvb_frontend *fe)
Steven Toth0d467482008-09-04 01:14:43 -0300820{
821 struct cx24116_state *state = fe->demodulator_priv;
822 memcpy(&state->dcur, &state->dnxt, sizeof(state->dcur));
823}
824
Darron Broad490c8682008-09-13 19:42:16 -0300825/* Wait for LNB */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300826static int cx24116_wait_for_lnb(struct dvb_frontend *fe)
Darron Broad490c8682008-09-13 19:42:16 -0300827{
828 struct cx24116_state *state = fe->demodulator_priv;
829 int i;
830
831 dprintk("%s() qstatus = 0x%02x\n", __func__,
832 cx24116_readreg(state, CX24116_REG_QSTATUS));
833
834 /* Wait for up to 300 ms */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300835 for (i = 0; i < 30 ; i++) {
Darron Broad490c8682008-09-13 19:42:16 -0300836 if (cx24116_readreg(state, CX24116_REG_QSTATUS) & 0x20)
837 return 0;
838 msleep(10);
839 }
840
841 dprintk("%s(): LNB not ready\n", __func__);
842
843 return -ETIMEDOUT; /* -EBUSY ? */
844}
845
Igor M. Liplianinc7bdcd02009-01-17 10:16:36 -0300846static int cx24116_set_voltage(struct dvb_frontend *fe,
847 fe_sec_voltage_t voltage)
848{
849 struct cx24116_cmd cmd;
850 int ret;
851
852 dprintk("%s: %s\n", __func__,
853 voltage == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
854 voltage == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??");
855
856 /* Wait for LNB ready */
857 ret = cx24116_wait_for_lnb(fe);
858 if (ret != 0)
859 return ret;
860
861 /* Wait for voltage/min repeat delay */
862 msleep(100);
863
864 cmd.args[0x00] = CMD_LNBDCLEVEL;
865 cmd.args[0x01] = (voltage == SEC_VOLTAGE_18 ? 0x01 : 0x00);
866 cmd.len = 0x02;
867
868 /* Min delay time before DiSEqC send */
869 msleep(15);
870
871 return cx24116_cmd_execute(fe, &cmd);
872}
873
Steven Tothf11ec7d2008-10-16 20:22:01 -0300874static int cx24116_set_tone(struct dvb_frontend *fe,
875 fe_sec_tone_mode_t tone)
Steven Toth0d467482008-09-04 01:14:43 -0300876{
877 struct cx24116_cmd cmd;
878 int ret;
879
880 dprintk("%s(%d)\n", __func__, tone);
Steven Tothf11ec7d2008-10-16 20:22:01 -0300881 if ((tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF)) {
Steven Toth98c94822008-10-16 20:24:42 -0300882 printk(KERN_ERR "%s: Invalid, tone=%d\n", __func__, tone);
Steven Toth0d467482008-09-04 01:14:43 -0300883 return -EINVAL;
884 }
885
Darron Broad490c8682008-09-13 19:42:16 -0300886 /* Wait for LNB ready */
887 ret = cx24116_wait_for_lnb(fe);
Steven Tothf11ec7d2008-10-16 20:22:01 -0300888 if (ret != 0)
Darron Broad490c8682008-09-13 19:42:16 -0300889 return ret;
890
891 /* Min delay time after DiSEqC send */
892 msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */
893
Steven Toth0d467482008-09-04 01:14:43 -0300894 /* Now we set the tone */
895 cmd.args[0x00] = CMD_SET_TONE;
896 cmd.args[0x01] = 0x00;
897 cmd.args[0x02] = 0x00;
898
899 switch (tone) {
900 case SEC_TONE_ON:
901 dprintk("%s: setting tone on\n", __func__);
902 cmd.args[0x03] = 0x01;
903 break;
904 case SEC_TONE_OFF:
Steven Tothf11ec7d2008-10-16 20:22:01 -0300905 dprintk("%s: setting tone off\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -0300906 cmd.args[0x03] = 0x00;
907 break;
908 }
Steven Tothf11ec7d2008-10-16 20:22:01 -0300909 cmd.len = 0x04;
Steven Toth0d467482008-09-04 01:14:43 -0300910
Darron Broad490c8682008-09-13 19:42:16 -0300911 /* Min delay time before DiSEqC send */
912 msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */
913
Steven Toth0d467482008-09-04 01:14:43 -0300914 return cx24116_cmd_execute(fe, &cmd);
915}
916
917/* Initialise DiSEqC */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300918static int cx24116_diseqc_init(struct dvb_frontend *fe)
Steven Toth0d467482008-09-04 01:14:43 -0300919{
920 struct cx24116_state *state = fe->demodulator_priv;
Darron Broad490c8682008-09-13 19:42:16 -0300921 struct cx24116_cmd cmd;
922 int ret;
Steven Toth0d467482008-09-04 01:14:43 -0300923
Darron Broad490c8682008-09-13 19:42:16 -0300924 /* Firmware CMD 20: LNB/DiSEqC config */
925 cmd.args[0x00] = CMD_LNBCONFIG;
926 cmd.args[0x01] = 0x00;
927 cmd.args[0x02] = 0x10;
928 cmd.args[0x03] = 0x00;
929 cmd.args[0x04] = 0x8f;
930 cmd.args[0x05] = 0x28;
931 cmd.args[0x06] = (toneburst == CX24116_DISEQC_TONEOFF) ? 0x00 : 0x01;
932 cmd.args[0x07] = 0x01;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300933 cmd.len = 0x08;
Darron Broad490c8682008-09-13 19:42:16 -0300934 ret = cx24116_cmd_execute(fe, &cmd);
935 if (ret != 0)
936 return ret;
937
938 /* Prepare a DiSEqC command */
939 state->dsec_cmd.args[0x00] = CMD_LNBSEND;
940
941 /* DiSEqC burst */
942 state->dsec_cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_A;
943
944 /* Unknown */
945 state->dsec_cmd.args[CX24116_DISEQC_ARG2_2] = 0x02;
946 state->dsec_cmd.args[CX24116_DISEQC_ARG3_0] = 0x00;
Steven Toth98c94822008-10-16 20:24:42 -0300947 /* Continuation flag? */
948 state->dsec_cmd.args[CX24116_DISEQC_ARG4_0] = 0x00;
Darron Broad490c8682008-09-13 19:42:16 -0300949
950 /* DiSEqC message length */
951 state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = 0x00;
952
953 /* Command length */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300954 state->dsec_cmd.len = CX24116_DISEQC_MSGOFS;
Steven Toth0d467482008-09-04 01:14:43 -0300955
956 return 0;
957}
958
959/* Send DiSEqC message with derived burst (hack) || previous burst */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300960static int cx24116_send_diseqc_msg(struct dvb_frontend *fe,
961 struct dvb_diseqc_master_cmd *d)
Steven Toth0d467482008-09-04 01:14:43 -0300962{
963 struct cx24116_state *state = fe->demodulator_priv;
Steven Toth0d467482008-09-04 01:14:43 -0300964 int i, ret;
965
966 /* Dump DiSEqC message */
967 if (debug) {
Steven Toth98c94822008-10-16 20:24:42 -0300968 printk(KERN_INFO "cx24116: %s(", __func__);
Steven Tothf11ec7d2008-10-16 20:22:01 -0300969 for (i = 0 ; i < d->msg_len ;) {
Steven Toth98c94822008-10-16 20:24:42 -0300970 printk(KERN_INFO "0x%02x", d->msg[i]);
Steven Tothf11ec7d2008-10-16 20:22:01 -0300971 if (++i < d->msg_len)
Steven Toth98c94822008-10-16 20:24:42 -0300972 printk(KERN_INFO ", ");
Steven Tothf11ec7d2008-10-16 20:22:01 -0300973 }
Darron Broad490c8682008-09-13 19:42:16 -0300974 printk(") toneburst=%d\n", toneburst);
Steven Toth0d467482008-09-04 01:14:43 -0300975 }
976
Darron Broad490c8682008-09-13 19:42:16 -0300977 /* Validate length */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300978 if (d->msg_len > (CX24116_ARGLEN - CX24116_DISEQC_MSGOFS))
Steven Toth0d467482008-09-04 01:14:43 -0300979 return -EINVAL;
980
Steven Toth0d467482008-09-04 01:14:43 -0300981 /* DiSEqC message */
982 for (i = 0; i < d->msg_len; i++)
Darron Broad490c8682008-09-13 19:42:16 -0300983 state->dsec_cmd.args[CX24116_DISEQC_MSGOFS + i] = d->msg[i];
Steven Toth0d467482008-09-04 01:14:43 -0300984
Darron Broad490c8682008-09-13 19:42:16 -0300985 /* DiSEqC message length */
986 state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = d->msg_len;
Steven Toth0d467482008-09-04 01:14:43 -0300987
Darron Broad490c8682008-09-13 19:42:16 -0300988 /* Command length */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300989 state->dsec_cmd.len = CX24116_DISEQC_MSGOFS +
990 state->dsec_cmd.args[CX24116_DISEQC_MSGLEN];
Steven Toth0d467482008-09-04 01:14:43 -0300991
Darron Broad490c8682008-09-13 19:42:16 -0300992 /* DiSEqC toneburst */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300993 if (toneburst == CX24116_DISEQC_MESGCACHE)
Darron Broad490c8682008-09-13 19:42:16 -0300994 /* Message is cached */
995 return 0;
Steven Toth0d467482008-09-04 01:14:43 -0300996
Steven Tothf11ec7d2008-10-16 20:22:01 -0300997 else if (toneburst == CX24116_DISEQC_TONEOFF)
Darron Broad490c8682008-09-13 19:42:16 -0300998 /* Message is sent without burst */
999 state->dsec_cmd.args[CX24116_DISEQC_BURST] = 0;
1000
Steven Tothf11ec7d2008-10-16 20:22:01 -03001001 else if (toneburst == CX24116_DISEQC_TONECACHE) {
Darron Broad490c8682008-09-13 19:42:16 -03001002 /*
1003 * Message is sent with derived else cached burst
1004 *
1005 * WRITE PORT GROUP COMMAND 38
1006 *
1007 * 0/A/A: E0 10 38 F0..F3
1008 * 1/B/B: E0 10 38 F4..F7
1009 * 2/C/A: E0 10 38 F8..FB
1010 * 3/D/B: E0 10 38 FC..FF
1011 *
Darron Broad7396d3e2008-09-14 10:45:58 -03001012 * databyte[3]= 8421:8421
Darron Broad490c8682008-09-13 19:42:16 -03001013 * ABCD:WXYZ
1014 * CLR :SET
1015 *
1016 * WX= PORT SELECT 0..3 (X=TONEBURST)
1017 * Y = VOLTAGE (0=13V, 1=18V)
1018 * Z = BAND (0=LOW, 1=HIGH(22K))
1019 */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001020 if (d->msg_len >= 4 && d->msg[2] == 0x38)
1021 state->dsec_cmd.args[CX24116_DISEQC_BURST] =
1022 ((d->msg[3] & 4) >> 2);
1023 if (debug)
1024 dprintk("%s burst=%d\n", __func__,
1025 state->dsec_cmd.args[CX24116_DISEQC_BURST]);
Darron Broad490c8682008-09-13 19:42:16 -03001026 }
1027
1028 /* 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;
1032
1033 /* Wait for voltage/min repeat delay */
1034 msleep(100);
1035
1036 /* 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 * Wait for send
Steven Toth0d467482008-09-04 01:14:43 -03001042 *
1043 * Eutelsat spec:
Darron Broad490c8682008-09-13 19:42:16 -03001044 * >15ms delay + (XXX determine if FW does this, see set_tone)
1045 * 13.5ms per byte +
1046 * >15ms delay +
1047 * 12.5ms burst +
1048 * >15ms delay (XXX determine if FW does this, see set_tone)
Steven Toth0d467482008-09-04 01:14:43 -03001049 */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001050 msleep((state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) +
1051 ((toneburst == CX24116_DISEQC_TONEOFF) ? 30 : 60));
Steven Toth0d467482008-09-04 01:14:43 -03001052
Darron Broad490c8682008-09-13 19:42:16 -03001053 return 0;
Steven Toth0d467482008-09-04 01:14:43 -03001054}
1055
1056/* Send DiSEqC burst */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001057static int cx24116_diseqc_send_burst(struct dvb_frontend *fe,
1058 fe_sec_mini_cmd_t burst)
Steven Toth0d467482008-09-04 01:14:43 -03001059{
1060 struct cx24116_state *state = fe->demodulator_priv;
Steven Toth0d467482008-09-04 01:14:43 -03001061 int ret;
1062
Steven Tothf11ec7d2008-10-16 20:22:01 -03001063 dprintk("%s(%d) toneburst=%d\n", __func__, burst, toneburst);
Steven Toth0d467482008-09-04 01:14:43 -03001064
Darron Broad490c8682008-09-13 19:42:16 -03001065 /* DiSEqC burst */
Steven Toth0d467482008-09-04 01:14:43 -03001066 if (burst == SEC_MINI_A)
Steven Tothf11ec7d2008-10-16 20:22:01 -03001067 state->dsec_cmd.args[CX24116_DISEQC_BURST] =
1068 CX24116_DISEQC_MINI_A;
1069 else if (burst == SEC_MINI_B)
1070 state->dsec_cmd.args[CX24116_DISEQC_BURST] =
1071 CX24116_DISEQC_MINI_B;
Steven Toth0d467482008-09-04 01:14:43 -03001072 else
1073 return -EINVAL;
1074
Darron Broad490c8682008-09-13 19:42:16 -03001075 /* DiSEqC toneburst */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001076 if (toneburst != CX24116_DISEQC_MESGCACHE)
Darron Broad490c8682008-09-13 19:42:16 -03001077 /* Burst is cached */
1078 return 0;
Steven Toth0d467482008-09-04 01:14:43 -03001079
Darron Broad490c8682008-09-13 19:42:16 -03001080 /* Burst is to be sent with cached message */
Steven Toth0d467482008-09-04 01:14:43 -03001081
Darron Broad490c8682008-09-13 19:42:16 -03001082 /* Wait for LNB ready */
1083 ret = cx24116_wait_for_lnb(fe);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001084 if (ret != 0)
Darron Broad490c8682008-09-13 19:42:16 -03001085 return ret;
Steven Toth0d467482008-09-04 01:14:43 -03001086
Darron Broad490c8682008-09-13 19:42:16 -03001087 /* Wait for voltage/min repeat delay */
1088 msleep(100);
Steven Toth0d467482008-09-04 01:14:43 -03001089
Darron Broad490c8682008-09-13 19:42:16 -03001090 /* Command */
1091 ret = cx24116_cmd_execute(fe, &state->dsec_cmd);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001092 if (ret != 0)
Darron Broad490c8682008-09-13 19:42:16 -03001093 return ret;
1094
1095 /*
1096 * Wait for send
1097 *
1098 * Eutelsat spec:
1099 * >15ms delay + (XXX determine if FW does this, see set_tone)
1100 * 13.5ms per byte +
1101 * >15ms delay +
1102 * 12.5ms burst +
1103 * >15ms delay (XXX determine if FW does this, see set_tone)
1104 */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001105 msleep((state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) + 60);
Darron Broad490c8682008-09-13 19:42:16 -03001106
1107 return 0;
Steven Toth0d467482008-09-04 01:14:43 -03001108}
1109
Steven Tothf11ec7d2008-10-16 20:22:01 -03001110static void cx24116_release(struct dvb_frontend *fe)
Steven Toth0d467482008-09-04 01:14:43 -03001111{
Steven Tothf11ec7d2008-10-16 20:22:01 -03001112 struct cx24116_state *state = fe->demodulator_priv;
1113 dprintk("%s\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -03001114 kfree(state);
1115}
1116
1117static struct dvb_frontend_ops cx24116_ops;
1118
Steven Tothf11ec7d2008-10-16 20:22:01 -03001119struct dvb_frontend *cx24116_attach(const struct cx24116_config *config,
1120 struct i2c_adapter *i2c)
Steven Toth0d467482008-09-04 01:14:43 -03001121{
Steven Tothf11ec7d2008-10-16 20:22:01 -03001122 struct cx24116_state *state = NULL;
Steven Toth0d467482008-09-04 01:14:43 -03001123 int ret;
1124
Steven Tothf11ec7d2008-10-16 20:22:01 -03001125 dprintk("%s\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -03001126
1127 /* allocate memory for the internal state */
Matthias Schwarzott8420fa72009-02-23 12:26:38 -03001128 state = kzalloc(sizeof(struct cx24116_state), GFP_KERNEL);
Steven Toth98c94822008-10-16 20:24:42 -03001129 if (state == NULL)
Darron Broad7396d3e2008-09-14 10:45:58 -03001130 goto error1;
Steven Toth0d467482008-09-04 01:14:43 -03001131
Steven Toth0d467482008-09-04 01:14:43 -03001132 state->config = config;
1133 state->i2c = i2c;
1134
1135 /* check if the demod is present */
Steven Toth98c94822008-10-16 20:24:42 -03001136 ret = (cx24116_readreg(state, 0xFF) << 8) |
1137 cx24116_readreg(state, 0xFE);
Steven Toth0d467482008-09-04 01:14:43 -03001138 if (ret != 0x0501) {
Steven Toth98c94822008-10-16 20:24:42 -03001139 printk(KERN_INFO "Invalid probe, probably not a CX24116 device\n");
Darron Broad7396d3e2008-09-14 10:45:58 -03001140 goto error2;
Steven Toth0d467482008-09-04 01:14:43 -03001141 }
1142
1143 /* create dvb_frontend */
Steven Toth98c94822008-10-16 20:24:42 -03001144 memcpy(&state->frontend.ops, &cx24116_ops,
1145 sizeof(struct dvb_frontend_ops));
Steven Toth0d467482008-09-04 01:14:43 -03001146 state->frontend.demodulator_priv = state;
1147 return &state->frontend;
1148
Darron Broad7396d3e2008-09-14 10:45:58 -03001149error2: kfree(state);
Darron Broad490c8682008-09-13 19:42:16 -03001150error1: return NULL;
Steven Toth0d467482008-09-04 01:14:43 -03001151}
Steven Tothf11ec7d2008-10-16 20:22:01 -03001152EXPORT_SYMBOL(cx24116_attach);
1153
Darron Broad490c8682008-09-13 19:42:16 -03001154/*
1155 * Initialise or wake up device
1156 *
1157 * Power config will reset and load initial firmware if required
1158 */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001159static int cx24116_initfe(struct dvb_frontend *fe)
Steven Toth0d467482008-09-04 01:14:43 -03001160{
Steven Tothf11ec7d2008-10-16 20:22:01 -03001161 struct cx24116_state *state = fe->demodulator_priv;
Darron Broad490c8682008-09-13 19:42:16 -03001162 struct cx24116_cmd cmd;
1163 int ret;
1164
Steven Tothf11ec7d2008-10-16 20:22:01 -03001165 dprintk("%s()\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -03001166
Darron Broad490c8682008-09-13 19:42:16 -03001167 /* Power on */
1168 cx24116_writereg(state, 0xe0, 0);
1169 cx24116_writereg(state, 0xe1, 0);
1170 cx24116_writereg(state, 0xea, 0);
1171
1172 /* Firmware CMD 36: Power config */
1173 cmd.args[0x00] = CMD_TUNERSLEEP;
1174 cmd.args[0x01] = 0;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001175 cmd.len = 0x02;
Darron Broad490c8682008-09-13 19:42:16 -03001176 ret = cx24116_cmd_execute(fe, &cmd);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001177 if (ret != 0)
Darron Broad490c8682008-09-13 19:42:16 -03001178 return ret;
1179
Igor M. Liplianin8afe6ad2009-01-29 21:57:07 -03001180 ret = cx24116_diseqc_init(fe);
1181 if (ret != 0)
1182 return ret;
1183
1184 /* HVR-4000 needs this */
1185 return cx24116_set_voltage(fe, SEC_VOLTAGE_13);
Steven Toth0d467482008-09-04 01:14:43 -03001186}
1187
Darron Broad490c8682008-09-13 19:42:16 -03001188/*
1189 * Put device to sleep
1190 */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001191static int cx24116_sleep(struct dvb_frontend *fe)
Darron Broad490c8682008-09-13 19:42:16 -03001192{
Steven Tothf11ec7d2008-10-16 20:22:01 -03001193 struct cx24116_state *state = fe->demodulator_priv;
Darron Broad490c8682008-09-13 19:42:16 -03001194 struct cx24116_cmd cmd;
1195 int ret;
1196
Steven Tothf11ec7d2008-10-16 20:22:01 -03001197 dprintk("%s()\n", __func__);
Darron Broad490c8682008-09-13 19:42:16 -03001198
1199 /* Firmware CMD 36: Power config */
1200 cmd.args[0x00] = CMD_TUNERSLEEP;
1201 cmd.args[0x01] = 1;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001202 cmd.len = 0x02;
Darron Broad490c8682008-09-13 19:42:16 -03001203 ret = cx24116_cmd_execute(fe, &cmd);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001204 if (ret != 0)
Darron Broad490c8682008-09-13 19:42:16 -03001205 return ret;
1206
1207 /* Power off (Shutdown clocks) */
1208 cx24116_writereg(state, 0xea, 0xff);
1209 cx24116_writereg(state, 0xe1, 1);
1210 cx24116_writereg(state, 0xe0, 1);
1211
1212 return 0;
1213}
1214
Steven Tothf11ec7d2008-10-16 20:22:01 -03001215static int cx24116_set_property(struct dvb_frontend *fe,
1216 struct dtv_property *tvp)
Steven Toth0d467482008-09-04 01:14:43 -03001217{
1218 dprintk("%s(..)\n", __func__);
1219 return 0;
1220}
1221
Steven Tothf11ec7d2008-10-16 20:22:01 -03001222static int cx24116_get_property(struct dvb_frontend *fe,
1223 struct dtv_property *tvp)
Steven Toth0d467482008-09-04 01:14:43 -03001224{
Steven Tothbfbf2da2008-09-12 01:37:37 -03001225 dprintk("%s(..)\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -03001226 return 0;
1227}
1228
1229/* dvb-core told us to tune, the tv property cache will be complete,
1230 * it's safe for is to pull values and use them for tuning purposes.
1231 */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001232static int cx24116_set_frontend(struct dvb_frontend *fe,
1233 struct dvb_frontend_parameters *p)
Steven Toth0d467482008-09-04 01:14:43 -03001234{
1235 struct cx24116_state *state = fe->demodulator_priv;
Steven Toth56f06802008-09-11 10:19:27 -03001236 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
Steven Toth0d467482008-09-04 01:14:43 -03001237 struct cx24116_cmd cmd;
1238 fe_status_t tunerstat;
Darron Broad2fd93392008-12-18 06:27:23 -03001239 int i, status, ret, retune = 1;
Steven Toth0d467482008-09-04 01:14:43 -03001240
Steven Tothf11ec7d2008-10-16 20:22:01 -03001241 dprintk("%s()\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -03001242
Steven Tothf11ec7d2008-10-16 20:22:01 -03001243 switch (c->delivery_system) {
1244 case SYS_DVBS:
1245 dprintk("%s: DVB-S delivery system selected\n", __func__);
Darron Broad01a8f032008-10-03 11:47:46 -03001246
Steven Tothf11ec7d2008-10-16 20:22:01 -03001247 /* Only QPSK is supported for DVB-S */
1248 if (c->modulation != QPSK) {
1249 dprintk("%s: unsupported modulation selected (%d)\n",
1250 __func__, c->modulation);
1251 return -EOPNOTSUPP;
1252 }
Darron Broad01a8f032008-10-03 11:47:46 -03001253
Steven Tothf11ec7d2008-10-16 20:22:01 -03001254 /* Pilot doesn't exist in DVB-S, turn bit off */
1255 state->dnxt.pilot_val = CX24116_PILOT_OFF;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001256
1257 /* DVB-S only supports 0.35 */
1258 if (c->rolloff != ROLLOFF_35) {
1259 dprintk("%s: unsupported rolloff selected (%d)\n",
1260 __func__, c->rolloff);
1261 return -EOPNOTSUPP;
1262 }
1263 state->dnxt.rolloff_val = CX24116_ROLLOFF_035;
1264 break;
1265
1266 case SYS_DVBS2:
1267 dprintk("%s: DVB-S2 delivery system selected\n", __func__);
1268
1269 /*
1270 * NBC 8PSK/QPSK with DVB-S is supported for DVB-S2,
1271 * but not hardware auto detection
1272 */
1273 if (c->modulation != PSK_8 && c->modulation != QPSK) {
1274 dprintk("%s: unsupported modulation selected (%d)\n",
1275 __func__, c->modulation);
1276 return -EOPNOTSUPP;
1277 }
1278
1279 switch (c->pilot) {
1280 case PILOT_AUTO: /* Not supported but emulated */
Christophe Thommeret74563212008-10-15 20:01:32 -03001281 state->dnxt.pilot_val = (c->modulation == QPSK)
1282 ? CX24116_PILOT_OFF : CX24116_PILOT_ON;
Darron Broad2fd93392008-12-18 06:27:23 -03001283 retune++;
Christophe Thommeret74563212008-10-15 20:01:32 -03001284 break;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001285 case PILOT_OFF:
Darron Broad01a8f032008-10-03 11:47:46 -03001286 state->dnxt.pilot_val = CX24116_PILOT_OFF;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001287 break;
1288 case PILOT_ON:
1289 state->dnxt.pilot_val = CX24116_PILOT_ON;
1290 break;
1291 default:
1292 dprintk("%s: unsupported pilot mode selected (%d)\n",
1293 __func__, c->pilot);
1294 return -EOPNOTSUPP;
1295 }
Darron Broad01a8f032008-10-03 11:47:46 -03001296
Steven Tothf11ec7d2008-10-16 20:22:01 -03001297 switch (c->rolloff) {
1298 case ROLLOFF_20:
1299 state->dnxt.rolloff_val = CX24116_ROLLOFF_020;
1300 break;
1301 case ROLLOFF_25:
1302 state->dnxt.rolloff_val = CX24116_ROLLOFF_025;
1303 break;
1304 case ROLLOFF_35:
Darron Broad7396d3e2008-09-14 10:45:58 -03001305 state->dnxt.rolloff_val = CX24116_ROLLOFF_035;
Darron Broad490c8682008-09-13 19:42:16 -03001306 break;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001307 case ROLLOFF_AUTO: /* Rolloff must be explicit */
Darron Broad490c8682008-09-13 19:42:16 -03001308 default:
Steven Tothf11ec7d2008-10-16 20:22:01 -03001309 dprintk("%s: unsupported rolloff selected (%d)\n",
1310 __func__, c->rolloff);
Darron Broad490c8682008-09-13 19:42:16 -03001311 return -EOPNOTSUPP;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001312 }
1313 break;
1314
1315 default:
1316 dprintk("%s: unsupported delivery system selected (%d)\n",
1317 __func__, c->delivery_system);
1318 return -EOPNOTSUPP;
Darron Broad490c8682008-09-13 19:42:16 -03001319 }
Darron Broad35694762008-12-18 06:21:51 -03001320 state->dnxt.delsys = c->delivery_system;
Darron Broad01a8f032008-10-03 11:47:46 -03001321 state->dnxt.modulation = c->modulation;
1322 state->dnxt.frequency = c->frequency;
1323 state->dnxt.pilot = c->pilot;
1324 state->dnxt.rolloff = c->rolloff;
Darron Broad490c8682008-09-13 19:42:16 -03001325
Steven Tothf11ec7d2008-10-16 20:22:01 -03001326 ret = cx24116_set_inversion(state, c->inversion);
1327 if (ret != 0)
Steven Toth0d467482008-09-04 01:14:43 -03001328 return ret;
1329
Darron Broad01a8f032008-10-03 11:47:46 -03001330 /* FEC_NONE/AUTO for DVB-S2 is not supported and detected here */
Darron Broad35694762008-12-18 06:21:51 -03001331 ret = cx24116_set_fec(state, c->delivery_system, c->modulation, c->fec_inner);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001332 if (ret != 0)
Steven Toth0d467482008-09-04 01:14:43 -03001333 return ret;
1334
Steven Tothf11ec7d2008-10-16 20:22:01 -03001335 ret = cx24116_set_symbolrate(state, c->symbol_rate);
1336 if (ret != 0)
Steven Toth0d467482008-09-04 01:14:43 -03001337 return ret;
1338
1339 /* discard the 'current' tuning parameters and prepare to tune */
1340 cx24116_clone_params(fe);
1341
Darron Broad35694762008-12-18 06:21:51 -03001342 dprintk("%s: delsys = %d\n", __func__, state->dcur.delsys);
Darron Broad01a8f032008-10-03 11:47:46 -03001343 dprintk("%s: modulation = %d\n", __func__, state->dcur.modulation);
Steven Toth0d467482008-09-04 01:14:43 -03001344 dprintk("%s: frequency = %d\n", __func__, state->dcur.frequency);
Darron Broad01a8f032008-10-03 11:47:46 -03001345 dprintk("%s: pilot = %d (val = 0x%02x)\n", __func__,
1346 state->dcur.pilot, state->dcur.pilot_val);
1347 dprintk("%s: retune = %d\n", __func__, retune);
1348 dprintk("%s: rolloff = %d (val = 0x%02x)\n", __func__,
1349 state->dcur.rolloff, state->dcur.rolloff_val);
Steven Toth0d467482008-09-04 01:14:43 -03001350 dprintk("%s: symbol_rate = %d\n", __func__, state->dcur.symbol_rate);
1351 dprintk("%s: FEC = %d (mask/val = 0x%02x/0x%02x)\n", __func__,
1352 state->dcur.fec, state->dcur.fec_mask, state->dcur.fec_val);
1353 dprintk("%s: Inversion = %d (val = 0x%02x)\n", __func__,
1354 state->dcur.inversion, state->dcur.inversion_val);
1355
Darron Broad490c8682008-09-13 19:42:16 -03001356 /* This is also done in advise/acquire on HVR4000 but not on LITE */
Steven Toth0d467482008-09-04 01:14:43 -03001357 if (state->config->set_ts_params)
1358 state->config->set_ts_params(fe, 0);
1359
Darron Broad490c8682008-09-13 19:42:16 -03001360 /* Set/Reset B/W */
1361 cmd.args[0x00] = CMD_BANDWIDTH;
1362 cmd.args[0x01] = 0x01;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001363 cmd.len = 0x02;
Darron Broad490c8682008-09-13 19:42:16 -03001364 ret = cx24116_cmd_execute(fe, &cmd);
1365 if (ret != 0)
1366 return ret;
Igor M. Liplianin3f8e51a2008-09-09 13:22:29 -03001367
Steven Toth0d467482008-09-04 01:14:43 -03001368 /* Prepare a tune request */
1369 cmd.args[0x00] = CMD_TUNEREQUEST;
1370
1371 /* Frequency */
1372 cmd.args[0x01] = (state->dcur.frequency & 0xff0000) >> 16;
1373 cmd.args[0x02] = (state->dcur.frequency & 0x00ff00) >> 8;
1374 cmd.args[0x03] = (state->dcur.frequency & 0x0000ff);
1375
1376 /* Symbol Rate */
1377 cmd.args[0x04] = ((state->dcur.symbol_rate / 1000) & 0xff00) >> 8;
1378 cmd.args[0x05] = ((state->dcur.symbol_rate / 1000) & 0x00ff);
1379
1380 /* Automatic Inversion */
1381 cmd.args[0x06] = state->dcur.inversion_val;
1382
Darron Broad01a8f032008-10-03 11:47:46 -03001383 /* Modulation / FEC / Pilot */
1384 cmd.args[0x07] = state->dcur.fec_val | state->dcur.pilot_val;
Steven Toth0d467482008-09-04 01:14:43 -03001385
1386 cmd.args[0x08] = CX24116_SEARCH_RANGE_KHZ >> 8;
1387 cmd.args[0x09] = CX24116_SEARCH_RANGE_KHZ & 0xff;
1388 cmd.args[0x0a] = 0x00;
1389 cmd.args[0x0b] = 0x00;
Darron Broad490c8682008-09-13 19:42:16 -03001390 cmd.args[0x0c] = state->dcur.rolloff_val;
Steven Toth0d467482008-09-04 01:14:43 -03001391 cmd.args[0x0d] = state->dcur.fec_mask;
Igor M. Liplianin3f8e51a2008-09-09 13:22:29 -03001392
Darron Broad490c8682008-09-13 19:42:16 -03001393 if (state->dcur.symbol_rate > 30000000) {
Igor M. Liplianin3f8e51a2008-09-09 13:22:29 -03001394 cmd.args[0x0e] = 0x04;
1395 cmd.args[0x0f] = 0x00;
1396 cmd.args[0x10] = 0x01;
1397 cmd.args[0x11] = 0x77;
1398 cmd.args[0x12] = 0x36;
Darron Broad490c8682008-09-13 19:42:16 -03001399 cx24116_writereg(state, CX24116_REG_CLKDIV, 0x44);
1400 cx24116_writereg(state, CX24116_REG_RATEDIV, 0x01);
Igor M. Liplianin3f8e51a2008-09-09 13:22:29 -03001401 } else {
1402 cmd.args[0x0e] = 0x06;
1403 cmd.args[0x0f] = 0x00;
1404 cmd.args[0x10] = 0x00;
1405 cmd.args[0x11] = 0xFA;
1406 cmd.args[0x12] = 0x24;
Darron Broad490c8682008-09-13 19:42:16 -03001407 cx24116_writereg(state, CX24116_REG_CLKDIV, 0x46);
1408 cx24116_writereg(state, CX24116_REG_RATEDIV, 0x00);
Igor M. Liplianin3f8e51a2008-09-09 13:22:29 -03001409 }
1410
Steven Tothf11ec7d2008-10-16 20:22:01 -03001411 cmd.len = 0x13;
Steven Toth0d467482008-09-04 01:14:43 -03001412
1413 /* We need to support pilot and non-pilot tuning in the
1414 * driver automatically. This is a workaround for because
1415 * the demod does not support autodetect.
1416 */
1417 do {
Darron Broad490c8682008-09-13 19:42:16 -03001418 /* Reset status register */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001419 status = cx24116_readreg(state, CX24116_REG_SSTATUS)
1420 & CX24116_SIGNAL_MASK;
Darron Broad490c8682008-09-13 19:42:16 -03001421 cx24116_writereg(state, CX24116_REG_SSTATUS, status);
Steven Toth0d467482008-09-04 01:14:43 -03001422
1423 /* Tune */
1424 ret = cx24116_cmd_execute(fe, &cmd);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001425 if (ret != 0)
Steven Toth0d467482008-09-04 01:14:43 -03001426 break;
1427
Darron Broad490c8682008-09-13 19:42:16 -03001428 /*
1429 * Wait for up to 500 ms before retrying
1430 *
1431 * If we are able to tune then generally it occurs within 100ms.
1432 * If it takes longer, try a different toneburst setting.
1433 */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001434 for (i = 0; i < 50 ; i++) {
Darron Broad490c8682008-09-13 19:42:16 -03001435 cx24116_read_status(fe, &tunerstat);
1436 status = tunerstat & (FE_HAS_SIGNAL | FE_HAS_SYNC);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001437 if (status == (FE_HAS_SIGNAL | FE_HAS_SYNC)) {
1438 dprintk("%s: Tuned\n", __func__);
Darron Broad490c8682008-09-13 19:42:16 -03001439 goto tuned;
1440 }
1441 msleep(10);
Steven Toth0d467482008-09-04 01:14:43 -03001442 }
Darron Broad490c8682008-09-13 19:42:16 -03001443
Steven Tothf11ec7d2008-10-16 20:22:01 -03001444 dprintk("%s: Not tuned\n", __func__);
Darron Broad490c8682008-09-13 19:42:16 -03001445
1446 /* Toggle pilot bit when in auto-pilot */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001447 if (state->dcur.pilot == PILOT_AUTO)
Darron Broad01a8f032008-10-03 11:47:46 -03001448 cmd.args[0x07] ^= CX24116_PILOT_ON;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001449 } while (--retune);
Steven Toth0d467482008-09-04 01:14:43 -03001450
Darron Broad490c8682008-09-13 19:42:16 -03001451tuned: /* Set/Reset B/W */
1452 cmd.args[0x00] = CMD_BANDWIDTH;
1453 cmd.args[0x01] = 0x00;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001454 cmd.len = 0x02;
Darron Broad490c8682008-09-13 19:42:16 -03001455 ret = cx24116_cmd_execute(fe, &cmd);
1456 if (ret != 0)
1457 return ret;
1458
Steven Toth0d467482008-09-04 01:14:43 -03001459 return ret;
1460}
1461
Darron Broad6639f1e2008-12-18 06:28:18 -03001462static int cx24116_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters *params,
1463 unsigned int mode_flags, unsigned int *delay, fe_status_t *status)
1464{
1465 *delay = HZ / 5;
1466 if (params) {
1467 int ret = cx24116_set_frontend(fe, params);
1468 if (ret)
1469 return ret;
1470 }
1471 return cx24116_read_status(fe, status);
1472}
1473
1474static int cx24116_get_algo(struct dvb_frontend *fe)
1475{
1476 return DVBFE_ALGO_HW;
1477}
1478
Steven Toth0d467482008-09-04 01:14:43 -03001479static struct dvb_frontend_ops cx24116_ops = {
1480
1481 .info = {
1482 .name = "Conexant CX24116/CX24118",
1483 .type = FE_QPSK,
1484 .frequency_min = 950000,
1485 .frequency_max = 2150000,
1486 .frequency_stepsize = 1011, /* kHz for QPSK frontends */
1487 .frequency_tolerance = 5000,
1488 .symbol_rate_min = 1000000,
1489 .symbol_rate_max = 45000000,
1490 .caps = FE_CAN_INVERSION_AUTO |
1491 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
1492 FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
1493 FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
Klaus Schmidingerfaed4aa2008-12-31 14:13:56 -03001494 FE_CAN_2G_MODULATION |
Steven Toth0d467482008-09-04 01:14:43 -03001495 FE_CAN_QPSK | FE_CAN_RECOVER
1496 },
1497
1498 .release = cx24116_release,
1499
1500 .init = cx24116_initfe,
Darron Broad490c8682008-09-13 19:42:16 -03001501 .sleep = cx24116_sleep,
Steven Toth0d467482008-09-04 01:14:43 -03001502 .read_status = cx24116_read_status,
1503 .read_ber = cx24116_read_ber,
1504 .read_signal_strength = cx24116_read_signal_strength,
1505 .read_snr = cx24116_read_snr,
1506 .read_ucblocks = cx24116_read_ucblocks,
1507 .set_tone = cx24116_set_tone,
1508 .set_voltage = cx24116_set_voltage,
1509 .diseqc_send_master_cmd = cx24116_send_diseqc_msg,
1510 .diseqc_send_burst = cx24116_diseqc_send_burst,
Darron Broad6639f1e2008-12-18 06:28:18 -03001511 .get_frontend_algo = cx24116_get_algo,
1512 .tune = cx24116_tune,
Steven Toth0d467482008-09-04 01:14:43 -03001513
1514 .set_property = cx24116_set_property,
Steven Tothbfbf2da2008-09-12 01:37:37 -03001515 .get_property = cx24116_get_property,
Steven Toth0d467482008-09-04 01:14:43 -03001516 .set_frontend = cx24116_set_frontend,
1517};
1518
Steven Toth0d467482008-09-04 01:14:43 -03001519MODULE_DESCRIPTION("DVB Frontend module for Conexant cx24116/cx24118 hardware");
1520MODULE_AUTHOR("Steven Toth");
1521MODULE_LICENSE("GPL");
1522