blob: 28ad609e73f40e95c3b31555aef44a74cc93aa2a [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)
Darron Broad6639f1e2008-12-18 06:28:18 -0300109#define CX24116_STATUS_MASK (0x0f)
Darron Broad490c8682008-09-13 19:42:16 -0300110#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
Darron Broad35694762008-12-18 06:21:51 -0300163 fe_delivery_system_t delsys;
Steven Toth0d467482008-09-04 01:14:43 -0300164 fe_modulation_t modulation;
Darron Broad490c8682008-09-13 19:42:16 -0300165 fe_pilot_t pilot;
166 fe_rolloff_t rolloff;
Steven Toth0d467482008-09-04 01:14:43 -0300167
168 /* Demod values */
169 u8 fec_val;
170 u8 fec_mask;
171 u8 inversion_val;
Darron Broad01a8f032008-10-03 11:47:46 -0300172 u8 pilot_val;
Darron Broad490c8682008-09-13 19:42:16 -0300173 u8 rolloff_val;
Steven Toth0d467482008-09-04 01:14:43 -0300174};
175
176/* Basic commands that are sent to the firmware */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300177struct cx24116_cmd {
Steven Toth0d467482008-09-04 01:14:43 -0300178 u8 len;
179 u8 args[CX24116_ARGLEN];
180};
181
Steven Tothf11ec7d2008-10-16 20:22:01 -0300182struct cx24116_state {
183 struct i2c_adapter *i2c;
184 const struct cx24116_config *config;
Steven Toth0d467482008-09-04 01:14:43 -0300185
186 struct dvb_frontend frontend;
187
188 struct cx24116_tuning dcur;
189 struct cx24116_tuning dnxt;
190
191 u8 skip_fw_load;
192 u8 burst;
Darron Broad490c8682008-09-13 19:42:16 -0300193 struct cx24116_cmd dsec_cmd;
Steven Toth0d467482008-09-04 01:14:43 -0300194};
195
Steven Tothf11ec7d2008-10-16 20:22:01 -0300196static int cx24116_writereg(struct cx24116_state *state, int reg, int data)
Steven Toth0d467482008-09-04 01:14:43 -0300197{
198 u8 buf[] = { reg, data };
199 struct i2c_msg msg = { .addr = state->config->demod_address,
200 .flags = 0, .buf = buf, .len = 2 };
201 int err;
202
Steven Tothf11ec7d2008-10-16 20:22:01 -0300203 if (debug > 1)
Steven Toth0d467482008-09-04 01:14:43 -0300204 printk("cx24116: %s: write reg 0x%02x, value 0x%02x\n",
Steven Tothf11ec7d2008-10-16 20:22:01 -0300205 __func__, reg, data);
Steven Toth0d467482008-09-04 01:14:43 -0300206
Steven Tothf11ec7d2008-10-16 20:22:01 -0300207 err = i2c_transfer(state->i2c, &msg, 1);
208 if (err != 1) {
Steven Toth98c94822008-10-16 20:24:42 -0300209 printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x,"
Steven Toth0d467482008-09-04 01:14:43 -0300210 " value == 0x%02x)\n", __func__, err, reg, data);
211 return -EREMOTEIO;
212 }
213
214 return 0;
215}
216
217/* Bulk byte writes to a single I2C address, for 32k firmware load */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300218static int cx24116_writeregN(struct cx24116_state *state, int reg,
Geert Uytterhoeven64decbf2008-10-16 21:04:35 -0300219 const u8 *data, u16 len)
Steven Toth0d467482008-09-04 01:14:43 -0300220{
221 int ret = -EREMOTEIO;
222 struct i2c_msg msg;
223 u8 *buf;
224
225 buf = kmalloc(len + 1, GFP_KERNEL);
226 if (buf == NULL) {
227 printk("Unable to kmalloc\n");
228 ret = -ENOMEM;
229 goto error;
230 }
231
232 *(buf) = reg;
233 memcpy(buf + 1, data, len);
234
235 msg.addr = state->config->demod_address;
236 msg.flags = 0;
237 msg.buf = buf;
238 msg.len = len + 1;
239
Steven Tothf11ec7d2008-10-16 20:22:01 -0300240 if (debug > 1)
Steven Toth98c94822008-10-16 20:24:42 -0300241 printk(KERN_INFO "cx24116: %s: write regN 0x%02x, len = %d\n",
Steven Tothf11ec7d2008-10-16 20:22:01 -0300242 __func__, reg, len);
Steven Toth0d467482008-09-04 01:14:43 -0300243
Steven Tothf11ec7d2008-10-16 20:22:01 -0300244 ret = i2c_transfer(state->i2c, &msg, 1);
245 if (ret != 1) {
Steven Toth98c94822008-10-16 20:24:42 -0300246 printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x\n",
Steven Toth0d467482008-09-04 01:14:43 -0300247 __func__, ret, reg);
248 ret = -EREMOTEIO;
249 }
250
251error:
252 kfree(buf);
253
254 return ret;
255}
256
Steven Tothf11ec7d2008-10-16 20:22:01 -0300257static int cx24116_readreg(struct cx24116_state *state, u8 reg)
Steven Toth0d467482008-09-04 01:14:43 -0300258{
259 int ret;
260 u8 b0[] = { reg };
261 u8 b1[] = { 0 };
262 struct i2c_msg msg[] = {
Steven Tothf11ec7d2008-10-16 20:22:01 -0300263 { .addr = state->config->demod_address, .flags = 0,
264 .buf = b0, .len = 1 },
265 { .addr = state->config->demod_address, .flags = I2C_M_RD,
266 .buf = b1, .len = 1 }
Steven Toth0d467482008-09-04 01:14:43 -0300267 };
268
269 ret = i2c_transfer(state->i2c, msg, 2);
270
271 if (ret != 2) {
Steven Toth98c94822008-10-16 20:24:42 -0300272 printk(KERN_ERR "%s: reg=0x%x (error=%d)\n",
273 __func__, reg, ret);
Steven Toth0d467482008-09-04 01:14:43 -0300274 return ret;
275 }
276
Steven Tothf11ec7d2008-10-16 20:22:01 -0300277 if (debug > 1)
Steven Toth98c94822008-10-16 20:24:42 -0300278 printk(KERN_INFO "cx24116: read reg 0x%02x, value 0x%02x\n",
Steven Tothf11ec7d2008-10-16 20:22:01 -0300279 reg, b1[0]);
Steven Toth0d467482008-09-04 01:14:43 -0300280
281 return b1[0];
282}
283
Steven Toth98c94822008-10-16 20:24:42 -0300284static int cx24116_set_inversion(struct cx24116_state *state,
285 fe_spectral_inversion_t inversion)
Steven Toth0d467482008-09-04 01:14:43 -0300286{
287 dprintk("%s(%d)\n", __func__, inversion);
288
289 switch (inversion) {
290 case INVERSION_OFF:
291 state->dnxt.inversion_val = 0x00;
292 break;
293 case INVERSION_ON:
294 state->dnxt.inversion_val = 0x04;
295 break;
296 case INVERSION_AUTO:
297 state->dnxt.inversion_val = 0x0C;
298 break;
299 default:
300 return -EINVAL;
301 }
302
303 state->dnxt.inversion = inversion;
304
305 return 0;
306}
307
Darron Broad490c8682008-09-13 19:42:16 -0300308/*
309 * modfec (modulation and FEC)
310 * ===========================
311 *
312 * MOD FEC mask/val standard
313 * ---- -------- ----------- --------
314 * QPSK FEC_1_2 0x02 0x02+X DVB-S
315 * QPSK FEC_2_3 0x04 0x02+X DVB-S
316 * QPSK FEC_3_4 0x08 0x02+X DVB-S
317 * QPSK FEC_4_5 0x10 0x02+X DVB-S (?)
318 * QPSK FEC_5_6 0x20 0x02+X DVB-S
319 * QPSK FEC_6_7 0x40 0x02+X DVB-S
320 * QPSK FEC_7_8 0x80 0x02+X DVB-S
321 * QPSK FEC_8_9 0x01 0x02+X DVB-S (?) (NOT SUPPORTED?)
322 * QPSK AUTO 0xff 0x02+X DVB-S
323 *
324 * For DVB-S high byte probably represents FEC
325 * and low byte selects the modulator. The high
326 * byte is search range mask. Bit 5 may turn
327 * on DVB-S and remaining bits represent some
328 * kind of calibration (how/what i do not know).
329 *
330 * Eg.(2/3) szap "Zone Horror"
331 *
332 * mask/val = 0x04, 0x20
Steven Toth98c94822008-10-16 20:24:42 -0300333 * status 1f | signal c3c0 | snr a333 | ber 00000098 | unc 0 | FE_HAS_LOCK
Darron Broad490c8682008-09-13 19:42:16 -0300334 *
335 * mask/val = 0x04, 0x30
Steven Toth98c94822008-10-16 20:24:42 -0300336 * status 1f | signal c3c0 | snr a333 | ber 00000000 | unc 0 | FE_HAS_LOCK
Darron Broad490c8682008-09-13 19:42:16 -0300337 *
338 * After tuning FECSTATUS contains actual FEC
339 * in use numbered 1 through to 8 for 1/2 .. 2/3 etc
340 *
341 * NBC=NOT/NON BACKWARD COMPATIBLE WITH DVB-S (DVB-S2 only)
342 *
343 * NBC-QPSK FEC_1_2 0x00, 0x04 DVB-S2
344 * NBC-QPSK FEC_3_5 0x00, 0x05 DVB-S2
345 * NBC-QPSK FEC_2_3 0x00, 0x06 DVB-S2
346 * NBC-QPSK FEC_3_4 0x00, 0x07 DVB-S2
347 * NBC-QPSK FEC_4_5 0x00, 0x08 DVB-S2
348 * NBC-QPSK FEC_5_6 0x00, 0x09 DVB-S2
349 * NBC-QPSK FEC_8_9 0x00, 0x0a DVB-S2
350 * NBC-QPSK FEC_9_10 0x00, 0x0b DVB-S2
351 *
352 * NBC-8PSK FEC_3_5 0x00, 0x0c DVB-S2
353 * NBC-8PSK FEC_2_3 0x00, 0x0d DVB-S2
354 * NBC-8PSK FEC_3_4 0x00, 0x0e DVB-S2
355 * NBC-8PSK FEC_5_6 0x00, 0x0f DVB-S2
356 * NBC-8PSK FEC_8_9 0x00, 0x10 DVB-S2
357 * NBC-8PSK FEC_9_10 0x00, 0x11 DVB-S2
358 *
359 * For DVB-S2 low bytes selects both modulator
360 * and FEC. High byte is meaningless here. To
361 * set pilot, bit 6 (0x40) is set. When inspecting
362 * FECSTATUS bit 7 (0x80) represents the pilot
363 * selection whilst not tuned. When tuned, actual FEC
364 * in use is found in FECSTATUS as per above. Pilot
365 * value is reset.
366 */
367
Steven Toth0d467482008-09-04 01:14:43 -0300368/* A table of modulation, fec and configuration bytes for the demod.
369 * Not all S2 mmodulation schemes are support and not all rates with
370 * a scheme are support. Especially, no auto detect when in S2 mode.
371 */
Mauro Carvalho Chehabffbc5f82009-01-05 01:34:20 -0300372static struct cx24116_modfec {
Steven Toth0a6393a2008-10-06 21:06:48 -0300373 fe_delivery_system_t delivery_system;
Steven Toth0d467482008-09-04 01:14:43 -0300374 fe_modulation_t modulation;
375 fe_code_rate_t fec;
376 u8 mask; /* In DVBS mode this is used to autodetect */
377 u8 val; /* Passed to the firmware to indicate mode selection */
378} CX24116_MODFEC_MODES[] = {
379 /* QPSK. For unknown rates we set hardware to auto detect 0xfe 0x30 */
Darron Broad490c8682008-09-13 19:42:16 -0300380
381 /*mod fec mask val */
Steven Toth0a6393a2008-10-06 21:06:48 -0300382 { SYS_DVBS, QPSK, FEC_NONE, 0xfe, 0x30 },
383 { SYS_DVBS, QPSK, FEC_1_2, 0x02, 0x2e }, /* 00000010 00101110 */
384 { SYS_DVBS, QPSK, FEC_2_3, 0x04, 0x2f }, /* 00000100 00101111 */
385 { SYS_DVBS, QPSK, FEC_3_4, 0x08, 0x30 }, /* 00001000 00110000 */
386 { SYS_DVBS, QPSK, FEC_4_5, 0xfe, 0x30 }, /* 000?0000 ? */
387 { SYS_DVBS, QPSK, FEC_5_6, 0x20, 0x31 }, /* 00100000 00110001 */
388 { SYS_DVBS, QPSK, FEC_6_7, 0xfe, 0x30 }, /* 0?000000 ? */
389 { SYS_DVBS, QPSK, FEC_7_8, 0x80, 0x32 }, /* 10000000 00110010 */
390 { SYS_DVBS, QPSK, FEC_8_9, 0xfe, 0x30 }, /* 0000000? ? */
391 { SYS_DVBS, QPSK, FEC_AUTO, 0xfe, 0x30 },
Steven Toth0d467482008-09-04 01:14:43 -0300392 /* NBC-QPSK */
Steven Toth0a6393a2008-10-06 21:06:48 -0300393 { SYS_DVBS2, QPSK, FEC_1_2, 0x00, 0x04 },
394 { SYS_DVBS2, QPSK, FEC_3_5, 0x00, 0x05 },
395 { SYS_DVBS2, QPSK, FEC_2_3, 0x00, 0x06 },
396 { SYS_DVBS2, QPSK, FEC_3_4, 0x00, 0x07 },
397 { SYS_DVBS2, QPSK, FEC_4_5, 0x00, 0x08 },
398 { SYS_DVBS2, QPSK, FEC_5_6, 0x00, 0x09 },
399 { SYS_DVBS2, QPSK, FEC_8_9, 0x00, 0x0a },
400 { SYS_DVBS2, QPSK, FEC_9_10, 0x00, 0x0b },
Steven Toth0d467482008-09-04 01:14:43 -0300401 /* 8PSK */
Steven Toth0a6393a2008-10-06 21:06:48 -0300402 { SYS_DVBS2, PSK_8, FEC_3_5, 0x00, 0x0c },
403 { SYS_DVBS2, PSK_8, FEC_2_3, 0x00, 0x0d },
404 { SYS_DVBS2, PSK_8, FEC_3_4, 0x00, 0x0e },
405 { SYS_DVBS2, PSK_8, FEC_5_6, 0x00, 0x0f },
406 { SYS_DVBS2, PSK_8, FEC_8_9, 0x00, 0x10 },
407 { SYS_DVBS2, PSK_8, FEC_9_10, 0x00, 0x11 },
Darron Broad490c8682008-09-13 19:42:16 -0300408 /*
409 * `val' can be found in the FECSTATUS register when tuning.
410 * FECSTATUS will give the actual FEC in use if tuning was successful.
411 */
Steven Toth0d467482008-09-04 01:14:43 -0300412};
413
Steven Tothf11ec7d2008-10-16 20:22:01 -0300414static int cx24116_lookup_fecmod(struct cx24116_state *state,
Darron Broad35694762008-12-18 06:21:51 -0300415 fe_delivery_system_t d, fe_modulation_t m, fe_code_rate_t f)
Steven Toth0d467482008-09-04 01:14:43 -0300416{
417 int i, ret = -EOPNOTSUPP;
418
Darron Broad490c8682008-09-13 19:42:16 -0300419 dprintk("%s(0x%02x,0x%02x)\n", __func__, m, f);
420
Steven Tothf11ec7d2008-10-16 20:22:01 -0300421 for (i = 0; i < ARRAY_SIZE(CX24116_MODFEC_MODES); i++) {
Darron Broad35694762008-12-18 06:21:51 -0300422 if ((d == CX24116_MODFEC_MODES[i].delivery_system) &&
423 (m == CX24116_MODFEC_MODES[i].modulation) &&
Steven Tothf11ec7d2008-10-16 20:22:01 -0300424 (f == CX24116_MODFEC_MODES[i].fec)) {
Steven Toth0d467482008-09-04 01:14:43 -0300425 ret = i;
426 break;
427 }
428 }
429
430 return ret;
431}
432
Steven Toth98c94822008-10-16 20:24:42 -0300433static int cx24116_set_fec(struct cx24116_state *state,
Darron Broad35694762008-12-18 06:21:51 -0300434 fe_delivery_system_t delsys, fe_modulation_t mod, fe_code_rate_t fec)
Steven Toth0d467482008-09-04 01:14:43 -0300435{
436 int ret = 0;
Darron Broad490c8682008-09-13 19:42:16 -0300437
438 dprintk("%s(0x%02x,0x%02x)\n", __func__, mod, fec);
Steven Toth0d467482008-09-04 01:14:43 -0300439
Darron Broad35694762008-12-18 06:21:51 -0300440 ret = cx24116_lookup_fecmod(state, delsys, mod, fec);
Steven Toth0d467482008-09-04 01:14:43 -0300441
Steven Tothf11ec7d2008-10-16 20:22:01 -0300442 if (ret < 0)
Steven Toth0d467482008-09-04 01:14:43 -0300443 return ret;
444
Darron Broad490c8682008-09-13 19:42:16 -0300445 state->dnxt.fec = fec;
Steven Toth0d467482008-09-04 01:14:43 -0300446 state->dnxt.fec_val = CX24116_MODFEC_MODES[ret].val;
447 state->dnxt.fec_mask = CX24116_MODFEC_MODES[ret].mask;
Darron Broad490c8682008-09-13 19:42:16 -0300448 dprintk("%s() mask/val = 0x%02x/0x%02x\n", __func__,
449 state->dnxt.fec_mask, state->dnxt.fec_val);
Steven Toth0d467482008-09-04 01:14:43 -0300450
451 return 0;
452}
453
Steven Tothf11ec7d2008-10-16 20:22:01 -0300454static int cx24116_set_symbolrate(struct cx24116_state *state, u32 rate)
Steven Toth0d467482008-09-04 01:14:43 -0300455{
Darron Broad490c8682008-09-13 19:42:16 -0300456 dprintk("%s(%d)\n", __func__, rate);
Steven Toth0d467482008-09-04 01:14:43 -0300457
458 /* check if symbol rate is within limits */
Darron Broad490c8682008-09-13 19:42:16 -0300459 if ((rate > state->frontend.ops.info.symbol_rate_max) ||
460 (rate < state->frontend.ops.info.symbol_rate_min)) {
461 dprintk("%s() unsupported symbol_rate = %d\n", __func__, rate);
462 return -EOPNOTSUPP;
463 }
Steven Toth0d467482008-09-04 01:14:43 -0300464
Darron Broad490c8682008-09-13 19:42:16 -0300465 state->dnxt.symbol_rate = rate;
466 dprintk("%s() symbol_rate = %d\n", __func__, rate);
467
468 return 0;
Steven Toth0d467482008-09-04 01:14:43 -0300469}
470
Steven Tothf11ec7d2008-10-16 20:22:01 -0300471static int cx24116_load_firmware(struct dvb_frontend *fe,
472 const struct firmware *fw);
Steven Toth0d467482008-09-04 01:14:43 -0300473
Steven Tothf11ec7d2008-10-16 20:22:01 -0300474static int cx24116_firmware_ondemand(struct dvb_frontend *fe)
Steven Toth0d467482008-09-04 01:14:43 -0300475{
476 struct cx24116_state *state = fe->demodulator_priv;
477 const struct firmware *fw;
478 int ret = 0;
479
Steven Tothf11ec7d2008-10-16 20:22:01 -0300480 dprintk("%s()\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -0300481
Steven Tothf11ec7d2008-10-16 20:22:01 -0300482 if (cx24116_readreg(state, 0x20) > 0) {
Steven Toth0d467482008-09-04 01:14:43 -0300483
484 if (state->skip_fw_load)
485 return 0;
486
487 /* Load firmware */
Steven Toth98c94822008-10-16 20:24:42 -0300488 /* request the firmware, this will block until loaded */
489 printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n",
490 __func__, CX24116_DEFAULT_FIRMWARE);
491 ret = request_firmware(&fw, CX24116_DEFAULT_FIRMWARE,
492 &state->i2c->dev);
493 printk(KERN_INFO "%s: Waiting for firmware upload(2)...\n",
494 __func__);
Steven Toth0d467482008-09-04 01:14:43 -0300495 if (ret) {
Steven Toth98c94822008-10-16 20:24:42 -0300496 printk(KERN_ERR "%s: No firmware uploaded "
497 "(timeout or file not found?)\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -0300498 return ret;
499 }
500
Steven Toth98c94822008-10-16 20:24:42 -0300501 /* Make sure we don't recurse back through here
502 * during loading */
Steven Toth0d467482008-09-04 01:14:43 -0300503 state->skip_fw_load = 1;
504
505 ret = cx24116_load_firmware(fe, fw);
506 if (ret)
Steven Toth98c94822008-10-16 20:24:42 -0300507 printk(KERN_ERR "%s: Writing firmware to device failed\n",
508 __func__);
Steven Toth0d467482008-09-04 01:14:43 -0300509
510 release_firmware(fw);
511
Steven Toth98c94822008-10-16 20:24:42 -0300512 printk(KERN_INFO "%s: Firmware upload %s\n", __func__,
513 ret == 0 ? "complete" : "failed");
Steven Toth0d467482008-09-04 01:14:43 -0300514
515 /* Ensure firmware is always loaded if required */
516 state->skip_fw_load = 0;
517 }
518
519 return ret;
520}
521
Steven Toth98c94822008-10-16 20:24:42 -0300522/* Take a basic firmware command structure, format it
523 * and forward it for processing
524 */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300525static int cx24116_cmd_execute(struct dvb_frontend *fe, struct cx24116_cmd *cmd)
Steven Toth0d467482008-09-04 01:14:43 -0300526{
527 struct cx24116_state *state = fe->demodulator_priv;
528 int i, ret;
529
530 dprintk("%s()\n", __func__);
531
532 /* Load the firmware if required */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300533 ret = cx24116_firmware_ondemand(fe);
534 if (ret != 0) {
Steven Toth98c94822008-10-16 20:24:42 -0300535 printk(KERN_ERR "%s(): Unable initialise the firmware\n",
536 __func__);
Steven Toth0d467482008-09-04 01:14:43 -0300537 return ret;
538 }
539
540 /* Write the command */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300541 for (i = 0; i < cmd->len ; i++) {
Steven Toth0d467482008-09-04 01:14:43 -0300542 dprintk("%s: 0x%02x == 0x%02x\n", __func__, i, cmd->args[i]);
543 cx24116_writereg(state, i, cmd->args[i]);
544 }
545
546 /* Start execution and wait for cmd to terminate */
Darron Broad490c8682008-09-13 19:42:16 -0300547 cx24116_writereg(state, CX24116_REG_EXECUTE, 0x01);
Steven Tothf11ec7d2008-10-16 20:22:01 -0300548 while (cx24116_readreg(state, CX24116_REG_EXECUTE)) {
Steven Toth0d467482008-09-04 01:14:43 -0300549 msleep(10);
Steven Tothf11ec7d2008-10-16 20:22:01 -0300550 if (i++ > 64) {
Steven Toth98c94822008-10-16 20:24:42 -0300551 /* Avoid looping forever if the firmware does
552 not respond */
553 printk(KERN_WARNING "%s() Firmware not responding\n",
554 __func__);
Steven Toth0d467482008-09-04 01:14:43 -0300555 return -EREMOTEIO;
556 }
557 }
558 return 0;
559}
560
Steven Tothf11ec7d2008-10-16 20:22:01 -0300561static int cx24116_load_firmware(struct dvb_frontend *fe,
562 const struct firmware *fw)
Steven Toth0d467482008-09-04 01:14:43 -0300563{
Steven Tothf11ec7d2008-10-16 20:22:01 -0300564 struct cx24116_state *state = fe->demodulator_priv;
Steven Toth0d467482008-09-04 01:14:43 -0300565 struct cx24116_cmd cmd;
Darron Broad490c8682008-09-13 19:42:16 -0300566 int i, ret;
567 unsigned char vers[4];
Steven Toth0d467482008-09-04 01:14:43 -0300568
569 dprintk("%s\n", __func__);
Steven Tothf11ec7d2008-10-16 20:22:01 -0300570 dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n",
571 fw->size,
572 fw->data[0],
573 fw->data[1],
574 fw->data[fw->size-2],
575 fw->data[fw->size-1]);
Steven Toth0d467482008-09-04 01:14:43 -0300576
577 /* Toggle 88x SRST pin to reset demod */
578 if (state->config->reset_device)
579 state->config->reset_device(fe);
580
581 /* Begin the firmware load process */
582 /* Prepare the demod, load the firmware, cleanup after load */
Steven Toth0d467482008-09-04 01:14:43 -0300583
Darron Broad490c8682008-09-13 19:42:16 -0300584 /* Init PLL */
585 cx24116_writereg(state, 0xE5, 0x00);
586 cx24116_writereg(state, 0xF1, 0x08);
587 cx24116_writereg(state, 0xF2, 0x13);
588
589 /* Start PLL */
590 cx24116_writereg(state, 0xe0, 0x03);
591 cx24116_writereg(state, 0xe0, 0x00);
592
593 /* Unknown */
594 cx24116_writereg(state, CX24116_REG_CLKDIV, 0x46);
595 cx24116_writereg(state, CX24116_REG_RATEDIV, 0x00);
596
597 /* Unknown */
Steven Toth0d467482008-09-04 01:14:43 -0300598 cx24116_writereg(state, 0xF0, 0x03);
599 cx24116_writereg(state, 0xF4, 0x81);
600 cx24116_writereg(state, 0xF5, 0x00);
601 cx24116_writereg(state, 0xF6, 0x00);
602
603 /* write the entire firmware as one transaction */
604 cx24116_writeregN(state, 0xF7, fw->data, fw->size);
605
606 cx24116_writereg(state, 0xF4, 0x10);
607 cx24116_writereg(state, 0xF0, 0x00);
608 cx24116_writereg(state, 0xF8, 0x06);
609
Darron Broad490c8682008-09-13 19:42:16 -0300610 /* Firmware CMD 10: VCO config */
611 cmd.args[0x00] = CMD_SET_VCO;
Steven Toth0d467482008-09-04 01:14:43 -0300612 cmd.args[0x01] = 0x05;
613 cmd.args[0x02] = 0xdc;
614 cmd.args[0x03] = 0xda;
615 cmd.args[0x04] = 0xae;
616 cmd.args[0x05] = 0xaa;
617 cmd.args[0x06] = 0x04;
618 cmd.args[0x07] = 0x9d;
619 cmd.args[0x08] = 0xfc;
620 cmd.args[0x09] = 0x06;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300621 cmd.len = 0x0a;
Steven Toth0d467482008-09-04 01:14:43 -0300622 ret = cx24116_cmd_execute(fe, &cmd);
623 if (ret != 0)
624 return ret;
625
Darron Broad490c8682008-09-13 19:42:16 -0300626 cx24116_writereg(state, CX24116_REG_SSTATUS, 0x00);
Steven Toth0d467482008-09-04 01:14:43 -0300627
Darron Broad490c8682008-09-13 19:42:16 -0300628 /* Firmware CMD 14: Tuner config */
629 cmd.args[0x00] = CMD_TUNERINIT;
Steven Toth0d467482008-09-04 01:14:43 -0300630 cmd.args[0x01] = 0x00;
631 cmd.args[0x02] = 0x00;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300632 cmd.len = 0x03;
Steven Toth0d467482008-09-04 01:14:43 -0300633 ret = cx24116_cmd_execute(fe, &cmd);
634 if (ret != 0)
635 return ret;
636
637 cx24116_writereg(state, 0xe5, 0x00);
638
Darron Broad490c8682008-09-13 19:42:16 -0300639 /* Firmware CMD 13: MPEG config */
640 cmd.args[0x00] = CMD_MPEGCONFIG;
Steven Toth0d467482008-09-04 01:14:43 -0300641 cmd.args[0x01] = 0x01;
642 cmd.args[0x02] = 0x75;
643 cmd.args[0x03] = 0x00;
Igor M. Liplianincc8c4f32008-09-09 13:57:47 -0300644 if (state->config->mpg_clk_pos_pol)
645 cmd.args[0x04] = state->config->mpg_clk_pos_pol;
646 else
647 cmd.args[0x04] = 0x02;
Steven Toth0d467482008-09-04 01:14:43 -0300648 cmd.args[0x05] = 0x00;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300649 cmd.len = 0x06;
Steven Toth0d467482008-09-04 01:14:43 -0300650 ret = cx24116_cmd_execute(fe, &cmd);
651 if (ret != 0)
652 return ret;
653
Darron Broad490c8682008-09-13 19:42:16 -0300654 /* Firmware CMD 35: Get firmware version */
655 cmd.args[0x00] = CMD_UPDFWVERS;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300656 cmd.len = 0x02;
657 for (i = 0; i < 4; i++) {
Darron Broad490c8682008-09-13 19:42:16 -0300658 cmd.args[0x01] = i;
659 ret = cx24116_cmd_execute(fe, &cmd);
660 if (ret != 0)
661 return ret;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300662 vers[i] = cx24116_readreg(state, CX24116_REG_MAILBOX);
Darron Broad490c8682008-09-13 19:42:16 -0300663 }
Steven Toth98c94822008-10-16 20:24:42 -0300664 printk(KERN_INFO "%s: FW version %i.%i.%i.%i\n", __func__,
Darron Broad490c8682008-09-13 19:42:16 -0300665 vers[0], vers[1], vers[2], vers[3]);
666
Steven Toth0d467482008-09-04 01:14:43 -0300667 return 0;
668}
669
Steven Tothf11ec7d2008-10-16 20:22:01 -0300670static int cx24116_set_voltage(struct dvb_frontend *fe,
671 fe_sec_voltage_t voltage)
Steven Toth0d467482008-09-04 01:14:43 -0300672{
673 /* The isl6421 module will override this function in the fops. */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300674 dprintk("%s() This should never appear if the isl6421 module "
675 "is loaded correctly\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -0300676
677 return -EOPNOTSUPP;
678}
679
Steven Tothf11ec7d2008-10-16 20:22:01 -0300680static int cx24116_read_status(struct dvb_frontend *fe, fe_status_t *status)
Steven Toth0d467482008-09-04 01:14:43 -0300681{
682 struct cx24116_state *state = fe->demodulator_priv;
683
Darron Broad6639f1e2008-12-18 06:28:18 -0300684 int lock = cx24116_readreg(state, CX24116_REG_SSTATUS) &
685 CX24116_STATUS_MASK;
Steven Toth0d467482008-09-04 01:14:43 -0300686
687 dprintk("%s: status = 0x%02x\n", __func__, lock);
688
689 *status = 0;
690
Darron Broad490c8682008-09-13 19:42:16 -0300691 if (lock & CX24116_HAS_SIGNAL)
Steven Toth0d467482008-09-04 01:14:43 -0300692 *status |= FE_HAS_SIGNAL;
Darron Broad490c8682008-09-13 19:42:16 -0300693 if (lock & CX24116_HAS_CARRIER)
Steven Toth0d467482008-09-04 01:14:43 -0300694 *status |= FE_HAS_CARRIER;
Darron Broad490c8682008-09-13 19:42:16 -0300695 if (lock & CX24116_HAS_VITERBI)
Steven Toth0d467482008-09-04 01:14:43 -0300696 *status |= FE_HAS_VITERBI;
Darron Broad490c8682008-09-13 19:42:16 -0300697 if (lock & CX24116_HAS_SYNCLOCK)
Steven Toth0d467482008-09-04 01:14:43 -0300698 *status |= FE_HAS_SYNC | FE_HAS_LOCK;
699
700 return 0;
701}
702
Steven Tothf11ec7d2008-10-16 20:22:01 -0300703static int cx24116_read_ber(struct dvb_frontend *fe, u32 *ber)
Steven Toth0d467482008-09-04 01:14:43 -0300704{
Darron Broad490c8682008-09-13 19:42:16 -0300705 struct cx24116_state *state = fe->demodulator_priv;
706
Steven Toth0d467482008-09-04 01:14:43 -0300707 dprintk("%s()\n", __func__);
Darron Broad490c8682008-09-13 19:42:16 -0300708
Steven Tothf11ec7d2008-10-16 20:22:01 -0300709 *ber = (cx24116_readreg(state, CX24116_REG_BER24) << 24) |
710 (cx24116_readreg(state, CX24116_REG_BER16) << 16) |
711 (cx24116_readreg(state, CX24116_REG_BER8) << 8) |
712 cx24116_readreg(state, CX24116_REG_BER0);
Steven Toth0d467482008-09-04 01:14:43 -0300713
714 return 0;
715}
716
Darron Broad490c8682008-09-13 19:42:16 -0300717/* TODO Determine function and scale appropriately */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300718static int cx24116_read_signal_strength(struct dvb_frontend *fe,
719 u16 *signal_strength)
Steven Toth0d467482008-09-04 01:14:43 -0300720{
721 struct cx24116_state *state = fe->demodulator_priv;
Darron Broad490c8682008-09-13 19:42:16 -0300722 struct cx24116_cmd cmd;
723 int ret;
724 u16 sig_reading;
725
726 dprintk("%s()\n", __func__);
727
728 /* Firmware CMD 19: Get AGC */
729 cmd.args[0x00] = CMD_GETAGC;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300730 cmd.len = 0x01;
Darron Broad490c8682008-09-13 19:42:16 -0300731 ret = cx24116_cmd_execute(fe, &cmd);
732 if (ret != 0)
733 return ret;
734
Steven Tothf11ec7d2008-10-16 20:22:01 -0300735 sig_reading =
736 (cx24116_readreg(state,
737 CX24116_REG_SSTATUS) & CX24116_SIGNAL_MASK) |
738 (cx24116_readreg(state, CX24116_REG_SIGNAL) << 6);
739 *signal_strength = 0 - sig_reading;
Darron Broad490c8682008-09-13 19:42:16 -0300740
Steven Tothf11ec7d2008-10-16 20:22:01 -0300741 dprintk("%s: raw / cooked = 0x%04x / 0x%04x\n",
742 __func__, sig_reading, *signal_strength);
Darron Broad490c8682008-09-13 19:42:16 -0300743
744 return 0;
745}
746
747/* SNR (0..100)% = (sig & 0xf0) * 10 + (sig & 0x0f) * 10 / 16 */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300748static int cx24116_read_snr_pct(struct dvb_frontend *fe, u16 *snr)
Darron Broad490c8682008-09-13 19:42:16 -0300749{
750 struct cx24116_state *state = fe->demodulator_priv;
751 u8 snr_reading;
752 static const u32 snr_tab[] = { /* 10 x Table (rounded up) */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300753 0x00000, 0x0199A, 0x03333, 0x04ccD, 0x06667,
754 0x08000, 0x0999A, 0x0b333, 0x0cccD, 0x0e667,
755 0x10000, 0x1199A, 0x13333, 0x14ccD, 0x16667,
756 0x18000 };
Steven Toth0d467482008-09-04 01:14:43 -0300757
758 dprintk("%s()\n", __func__);
759
Steven Toth8953db72008-10-06 21:20:21 -0300760 snr_reading = cx24116_readreg(state, CX24116_REG_QUALITY0);
Steven Toth0d467482008-09-04 01:14:43 -0300761
Steven Tothf11ec7d2008-10-16 20:22:01 -0300762 if (snr_reading >= 0xa0 /* 100% */)
Darron Broad490c8682008-09-13 19:42:16 -0300763 *snr = 0xffff;
Steven Toth0d467482008-09-04 01:14:43 -0300764 else
Steven Tothf11ec7d2008-10-16 20:22:01 -0300765 *snr = snr_tab[(snr_reading & 0xf0) >> 4] +
766 (snr_tab[(snr_reading & 0x0f)] >> 4);
Steven Toth0d467482008-09-04 01:14:43 -0300767
Darron Broad490c8682008-09-13 19:42:16 -0300768 dprintk("%s: raw / cooked = 0x%02x / 0x%04x\n", __func__,
769 snr_reading, *snr);
Steven Toth0d467482008-09-04 01:14:43 -0300770
771 return 0;
772}
773
Steven Toth8953db72008-10-06 21:20:21 -0300774/* The reelbox patches show the value in the registers represents
775 * ESNO, from 0->30db (values 0->300). We provide this value by
776 * default.
777 */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300778static int cx24116_read_snr_esno(struct dvb_frontend *fe, u16 *snr)
Steven Toth8953db72008-10-06 21:20:21 -0300779{
780 struct cx24116_state *state = fe->demodulator_priv;
781
782 dprintk("%s()\n", __func__);
783
784 *snr = cx24116_readreg(state, CX24116_REG_QUALITY8) << 8 |
785 cx24116_readreg(state, CX24116_REG_QUALITY0);
786
787 dprintk("%s: raw 0x%04x\n", __func__, *snr);
788
789 return 0;
790}
791
Steven Tothf11ec7d2008-10-16 20:22:01 -0300792static int cx24116_read_snr(struct dvb_frontend *fe, u16 *snr)
Steven Toth8953db72008-10-06 21:20:21 -0300793{
794 if (esno_snr == 1)
795 return cx24116_read_snr_esno(fe, snr);
796 else
797 return cx24116_read_snr_pct(fe, snr);
798}
799
Steven Tothf11ec7d2008-10-16 20:22:01 -0300800static int cx24116_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
Steven Toth0d467482008-09-04 01:14:43 -0300801{
Darron Broad490c8682008-09-13 19:42:16 -0300802 struct cx24116_state *state = fe->demodulator_priv;
803
Steven Toth0d467482008-09-04 01:14:43 -0300804 dprintk("%s()\n", __func__);
Darron Broad490c8682008-09-13 19:42:16 -0300805
Steven Tothf11ec7d2008-10-16 20:22:01 -0300806 *ucblocks = (cx24116_readreg(state, CX24116_REG_UCB8) << 8) |
Darron Broad490c8682008-09-13 19:42:16 -0300807 cx24116_readreg(state, CX24116_REG_UCB0);
Steven Toth0d467482008-09-04 01:14:43 -0300808
809 return 0;
810}
811
812/* Overwrite the current tuning params, we are about to tune */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300813static void cx24116_clone_params(struct dvb_frontend *fe)
Steven Toth0d467482008-09-04 01:14:43 -0300814{
815 struct cx24116_state *state = fe->demodulator_priv;
816 memcpy(&state->dcur, &state->dnxt, sizeof(state->dcur));
817}
818
Darron Broad490c8682008-09-13 19:42:16 -0300819/* Wait for LNB */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300820static int cx24116_wait_for_lnb(struct dvb_frontend *fe)
Darron Broad490c8682008-09-13 19:42:16 -0300821{
822 struct cx24116_state *state = fe->demodulator_priv;
823 int i;
824
825 dprintk("%s() qstatus = 0x%02x\n", __func__,
826 cx24116_readreg(state, CX24116_REG_QSTATUS));
827
828 /* Wait for up to 300 ms */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300829 for (i = 0; i < 30 ; i++) {
Darron Broad490c8682008-09-13 19:42:16 -0300830 if (cx24116_readreg(state, CX24116_REG_QSTATUS) & 0x20)
831 return 0;
832 msleep(10);
833 }
834
835 dprintk("%s(): LNB not ready\n", __func__);
836
837 return -ETIMEDOUT; /* -EBUSY ? */
838}
839
Steven Tothf11ec7d2008-10-16 20:22:01 -0300840static int cx24116_set_tone(struct dvb_frontend *fe,
841 fe_sec_tone_mode_t tone)
Steven Toth0d467482008-09-04 01:14:43 -0300842{
843 struct cx24116_cmd cmd;
844 int ret;
845
846 dprintk("%s(%d)\n", __func__, tone);
Steven Tothf11ec7d2008-10-16 20:22:01 -0300847 if ((tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF)) {
Steven Toth98c94822008-10-16 20:24:42 -0300848 printk(KERN_ERR "%s: Invalid, tone=%d\n", __func__, tone);
Steven Toth0d467482008-09-04 01:14:43 -0300849 return -EINVAL;
850 }
851
Darron Broad490c8682008-09-13 19:42:16 -0300852 /* Wait for LNB ready */
853 ret = cx24116_wait_for_lnb(fe);
Steven Tothf11ec7d2008-10-16 20:22:01 -0300854 if (ret != 0)
Darron Broad490c8682008-09-13 19:42:16 -0300855 return ret;
856
857 /* Min delay time after DiSEqC send */
858 msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */
859
Steven Toth0d467482008-09-04 01:14:43 -0300860 /* This is always done before the tone is set */
861 cmd.args[0x00] = CMD_SET_TONEPRE;
862 cmd.args[0x01] = 0x00;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300863 cmd.len = 0x02;
Steven Toth0d467482008-09-04 01:14:43 -0300864 ret = cx24116_cmd_execute(fe, &cmd);
865 if (ret != 0)
866 return ret;
867
868 /* Now we set the tone */
869 cmd.args[0x00] = CMD_SET_TONE;
870 cmd.args[0x01] = 0x00;
871 cmd.args[0x02] = 0x00;
872
873 switch (tone) {
874 case SEC_TONE_ON:
875 dprintk("%s: setting tone on\n", __func__);
876 cmd.args[0x03] = 0x01;
877 break;
878 case SEC_TONE_OFF:
Steven Tothf11ec7d2008-10-16 20:22:01 -0300879 dprintk("%s: setting tone off\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -0300880 cmd.args[0x03] = 0x00;
881 break;
882 }
Steven Tothf11ec7d2008-10-16 20:22:01 -0300883 cmd.len = 0x04;
Steven Toth0d467482008-09-04 01:14:43 -0300884
Darron Broad490c8682008-09-13 19:42:16 -0300885 /* Min delay time before DiSEqC send */
886 msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */
887
Steven Toth0d467482008-09-04 01:14:43 -0300888 return cx24116_cmd_execute(fe, &cmd);
889}
890
891/* Initialise DiSEqC */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300892static int cx24116_diseqc_init(struct dvb_frontend *fe)
Steven Toth0d467482008-09-04 01:14:43 -0300893{
894 struct cx24116_state *state = fe->demodulator_priv;
Darron Broad490c8682008-09-13 19:42:16 -0300895 struct cx24116_cmd cmd;
896 int ret;
Steven Toth0d467482008-09-04 01:14:43 -0300897
Darron Broad490c8682008-09-13 19:42:16 -0300898 /* Firmware CMD 20: LNB/DiSEqC config */
899 cmd.args[0x00] = CMD_LNBCONFIG;
900 cmd.args[0x01] = 0x00;
901 cmd.args[0x02] = 0x10;
902 cmd.args[0x03] = 0x00;
903 cmd.args[0x04] = 0x8f;
904 cmd.args[0x05] = 0x28;
905 cmd.args[0x06] = (toneburst == CX24116_DISEQC_TONEOFF) ? 0x00 : 0x01;
906 cmd.args[0x07] = 0x01;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300907 cmd.len = 0x08;
Darron Broad490c8682008-09-13 19:42:16 -0300908 ret = cx24116_cmd_execute(fe, &cmd);
909 if (ret != 0)
910 return ret;
911
912 /* Prepare a DiSEqC command */
913 state->dsec_cmd.args[0x00] = CMD_LNBSEND;
914
915 /* DiSEqC burst */
916 state->dsec_cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_A;
917
918 /* Unknown */
919 state->dsec_cmd.args[CX24116_DISEQC_ARG2_2] = 0x02;
920 state->dsec_cmd.args[CX24116_DISEQC_ARG3_0] = 0x00;
Steven Toth98c94822008-10-16 20:24:42 -0300921 /* Continuation flag? */
922 state->dsec_cmd.args[CX24116_DISEQC_ARG4_0] = 0x00;
Darron Broad490c8682008-09-13 19:42:16 -0300923
924 /* DiSEqC message length */
925 state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = 0x00;
926
927 /* Command length */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300928 state->dsec_cmd.len = CX24116_DISEQC_MSGOFS;
Steven Toth0d467482008-09-04 01:14:43 -0300929
930 return 0;
931}
932
933/* Send DiSEqC message with derived burst (hack) || previous burst */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300934static int cx24116_send_diseqc_msg(struct dvb_frontend *fe,
935 struct dvb_diseqc_master_cmd *d)
Steven Toth0d467482008-09-04 01:14:43 -0300936{
937 struct cx24116_state *state = fe->demodulator_priv;
Steven Toth0d467482008-09-04 01:14:43 -0300938 int i, ret;
939
940 /* Dump DiSEqC message */
941 if (debug) {
Steven Toth98c94822008-10-16 20:24:42 -0300942 printk(KERN_INFO "cx24116: %s(", __func__);
Steven Tothf11ec7d2008-10-16 20:22:01 -0300943 for (i = 0 ; i < d->msg_len ;) {
Steven Toth98c94822008-10-16 20:24:42 -0300944 printk(KERN_INFO "0x%02x", d->msg[i]);
Steven Tothf11ec7d2008-10-16 20:22:01 -0300945 if (++i < d->msg_len)
Steven Toth98c94822008-10-16 20:24:42 -0300946 printk(KERN_INFO ", ");
Steven Tothf11ec7d2008-10-16 20:22:01 -0300947 }
Darron Broad490c8682008-09-13 19:42:16 -0300948 printk(") toneburst=%d\n", toneburst);
Steven Toth0d467482008-09-04 01:14:43 -0300949 }
950
Darron Broad490c8682008-09-13 19:42:16 -0300951 /* Validate length */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300952 if (d->msg_len > (CX24116_ARGLEN - CX24116_DISEQC_MSGOFS))
Steven Toth0d467482008-09-04 01:14:43 -0300953 return -EINVAL;
954
Steven Toth0d467482008-09-04 01:14:43 -0300955 /* DiSEqC message */
956 for (i = 0; i < d->msg_len; i++)
Darron Broad490c8682008-09-13 19:42:16 -0300957 state->dsec_cmd.args[CX24116_DISEQC_MSGOFS + i] = d->msg[i];
Steven Toth0d467482008-09-04 01:14:43 -0300958
Darron Broad490c8682008-09-13 19:42:16 -0300959 /* DiSEqC message length */
960 state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = d->msg_len;
Steven Toth0d467482008-09-04 01:14:43 -0300961
Darron Broad490c8682008-09-13 19:42:16 -0300962 /* Command length */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300963 state->dsec_cmd.len = CX24116_DISEQC_MSGOFS +
964 state->dsec_cmd.args[CX24116_DISEQC_MSGLEN];
Steven Toth0d467482008-09-04 01:14:43 -0300965
Darron Broad490c8682008-09-13 19:42:16 -0300966 /* DiSEqC toneburst */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300967 if (toneburst == CX24116_DISEQC_MESGCACHE)
Darron Broad490c8682008-09-13 19:42:16 -0300968 /* Message is cached */
969 return 0;
Steven Toth0d467482008-09-04 01:14:43 -0300970
Steven Tothf11ec7d2008-10-16 20:22:01 -0300971 else if (toneburst == CX24116_DISEQC_TONEOFF)
Darron Broad490c8682008-09-13 19:42:16 -0300972 /* Message is sent without burst */
973 state->dsec_cmd.args[CX24116_DISEQC_BURST] = 0;
974
Steven Tothf11ec7d2008-10-16 20:22:01 -0300975 else if (toneburst == CX24116_DISEQC_TONECACHE) {
Darron Broad490c8682008-09-13 19:42:16 -0300976 /*
977 * Message is sent with derived else cached burst
978 *
979 * WRITE PORT GROUP COMMAND 38
980 *
981 * 0/A/A: E0 10 38 F0..F3
982 * 1/B/B: E0 10 38 F4..F7
983 * 2/C/A: E0 10 38 F8..FB
984 * 3/D/B: E0 10 38 FC..FF
985 *
Darron Broad7396d3e2008-09-14 10:45:58 -0300986 * databyte[3]= 8421:8421
Darron Broad490c8682008-09-13 19:42:16 -0300987 * ABCD:WXYZ
988 * CLR :SET
989 *
990 * WX= PORT SELECT 0..3 (X=TONEBURST)
991 * Y = VOLTAGE (0=13V, 1=18V)
992 * Z = BAND (0=LOW, 1=HIGH(22K))
993 */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300994 if (d->msg_len >= 4 && d->msg[2] == 0x38)
995 state->dsec_cmd.args[CX24116_DISEQC_BURST] =
996 ((d->msg[3] & 4) >> 2);
997 if (debug)
998 dprintk("%s burst=%d\n", __func__,
999 state->dsec_cmd.args[CX24116_DISEQC_BURST]);
Darron Broad490c8682008-09-13 19:42:16 -03001000 }
1001
1002 /* Wait for LNB ready */
1003 ret = cx24116_wait_for_lnb(fe);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001004 if (ret != 0)
Darron Broad490c8682008-09-13 19:42:16 -03001005 return ret;
1006
1007 /* Wait for voltage/min repeat delay */
1008 msleep(100);
1009
1010 /* Command */
1011 ret = cx24116_cmd_execute(fe, &state->dsec_cmd);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001012 if (ret != 0)
Darron Broad490c8682008-09-13 19:42:16 -03001013 return ret;
1014 /*
1015 * Wait for send
Steven Toth0d467482008-09-04 01:14:43 -03001016 *
1017 * Eutelsat spec:
Darron Broad490c8682008-09-13 19:42:16 -03001018 * >15ms delay + (XXX determine if FW does this, see set_tone)
1019 * 13.5ms per byte +
1020 * >15ms delay +
1021 * 12.5ms burst +
1022 * >15ms delay (XXX determine if FW does this, see set_tone)
Steven Toth0d467482008-09-04 01:14:43 -03001023 */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001024 msleep((state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) +
1025 ((toneburst == CX24116_DISEQC_TONEOFF) ? 30 : 60));
Steven Toth0d467482008-09-04 01:14:43 -03001026
Darron Broad490c8682008-09-13 19:42:16 -03001027 return 0;
Steven Toth0d467482008-09-04 01:14:43 -03001028}
1029
1030/* Send DiSEqC burst */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001031static int cx24116_diseqc_send_burst(struct dvb_frontend *fe,
1032 fe_sec_mini_cmd_t burst)
Steven Toth0d467482008-09-04 01:14:43 -03001033{
1034 struct cx24116_state *state = fe->demodulator_priv;
Steven Toth0d467482008-09-04 01:14:43 -03001035 int ret;
1036
Steven Tothf11ec7d2008-10-16 20:22:01 -03001037 dprintk("%s(%d) toneburst=%d\n", __func__, burst, toneburst);
Steven Toth0d467482008-09-04 01:14:43 -03001038
Darron Broad490c8682008-09-13 19:42:16 -03001039 /* DiSEqC burst */
Steven Toth0d467482008-09-04 01:14:43 -03001040 if (burst == SEC_MINI_A)
Steven Tothf11ec7d2008-10-16 20:22:01 -03001041 state->dsec_cmd.args[CX24116_DISEQC_BURST] =
1042 CX24116_DISEQC_MINI_A;
1043 else if (burst == SEC_MINI_B)
1044 state->dsec_cmd.args[CX24116_DISEQC_BURST] =
1045 CX24116_DISEQC_MINI_B;
Steven Toth0d467482008-09-04 01:14:43 -03001046 else
1047 return -EINVAL;
1048
Darron Broad490c8682008-09-13 19:42:16 -03001049 /* DiSEqC toneburst */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001050 if (toneburst != CX24116_DISEQC_MESGCACHE)
Darron Broad490c8682008-09-13 19:42:16 -03001051 /* Burst is cached */
1052 return 0;
Steven Toth0d467482008-09-04 01:14:43 -03001053
Darron Broad490c8682008-09-13 19:42:16 -03001054 /* Burst is to be sent with cached message */
Steven Toth0d467482008-09-04 01:14:43 -03001055
Darron Broad490c8682008-09-13 19:42:16 -03001056 /* Wait for LNB ready */
1057 ret = cx24116_wait_for_lnb(fe);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001058 if (ret != 0)
Darron Broad490c8682008-09-13 19:42:16 -03001059 return ret;
Steven Toth0d467482008-09-04 01:14:43 -03001060
Darron Broad490c8682008-09-13 19:42:16 -03001061 /* Wait for voltage/min repeat delay */
1062 msleep(100);
Steven Toth0d467482008-09-04 01:14:43 -03001063
Darron Broad490c8682008-09-13 19:42:16 -03001064 /* Command */
1065 ret = cx24116_cmd_execute(fe, &state->dsec_cmd);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001066 if (ret != 0)
Darron Broad490c8682008-09-13 19:42:16 -03001067 return ret;
1068
1069 /*
1070 * Wait for send
1071 *
1072 * Eutelsat spec:
1073 * >15ms delay + (XXX determine if FW does this, see set_tone)
1074 * 13.5ms per byte +
1075 * >15ms delay +
1076 * 12.5ms burst +
1077 * >15ms delay (XXX determine if FW does this, see set_tone)
1078 */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001079 msleep((state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) + 60);
Darron Broad490c8682008-09-13 19:42:16 -03001080
1081 return 0;
Steven Toth0d467482008-09-04 01:14:43 -03001082}
1083
Steven Tothf11ec7d2008-10-16 20:22:01 -03001084static void cx24116_release(struct dvb_frontend *fe)
Steven Toth0d467482008-09-04 01:14:43 -03001085{
Steven Tothf11ec7d2008-10-16 20:22:01 -03001086 struct cx24116_state *state = fe->demodulator_priv;
1087 dprintk("%s\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -03001088 kfree(state);
1089}
1090
1091static struct dvb_frontend_ops cx24116_ops;
1092
Steven Tothf11ec7d2008-10-16 20:22:01 -03001093struct dvb_frontend *cx24116_attach(const struct cx24116_config *config,
1094 struct i2c_adapter *i2c)
Steven Toth0d467482008-09-04 01:14:43 -03001095{
Steven Tothf11ec7d2008-10-16 20:22:01 -03001096 struct cx24116_state *state = NULL;
Steven Toth0d467482008-09-04 01:14:43 -03001097 int ret;
1098
Steven Tothf11ec7d2008-10-16 20:22:01 -03001099 dprintk("%s\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -03001100
1101 /* allocate memory for the internal state */
1102 state = kmalloc(sizeof(struct cx24116_state), GFP_KERNEL);
Steven Toth98c94822008-10-16 20:24:42 -03001103 if (state == NULL)
Darron Broad7396d3e2008-09-14 10:45:58 -03001104 goto error1;
Steven Toth0d467482008-09-04 01:14:43 -03001105
1106 /* setup the state */
1107 memset(state, 0, sizeof(struct cx24116_state));
1108
1109 state->config = config;
1110 state->i2c = i2c;
1111
1112 /* check if the demod is present */
Steven Toth98c94822008-10-16 20:24:42 -03001113 ret = (cx24116_readreg(state, 0xFF) << 8) |
1114 cx24116_readreg(state, 0xFE);
Steven Toth0d467482008-09-04 01:14:43 -03001115 if (ret != 0x0501) {
Steven Toth98c94822008-10-16 20:24:42 -03001116 printk(KERN_INFO "Invalid probe, probably not a CX24116 device\n");
Darron Broad7396d3e2008-09-14 10:45:58 -03001117 goto error2;
Steven Toth0d467482008-09-04 01:14:43 -03001118 }
1119
1120 /* create dvb_frontend */
Steven Toth98c94822008-10-16 20:24:42 -03001121 memcpy(&state->frontend.ops, &cx24116_ops,
1122 sizeof(struct dvb_frontend_ops));
Steven Toth0d467482008-09-04 01:14:43 -03001123 state->frontend.demodulator_priv = state;
1124 return &state->frontend;
1125
Darron Broad7396d3e2008-09-14 10:45:58 -03001126error2: kfree(state);
Darron Broad490c8682008-09-13 19:42:16 -03001127error1: return NULL;
Steven Toth0d467482008-09-04 01:14:43 -03001128}
Steven Tothf11ec7d2008-10-16 20:22:01 -03001129EXPORT_SYMBOL(cx24116_attach);
1130
Darron Broad490c8682008-09-13 19:42:16 -03001131/*
1132 * Initialise or wake up device
1133 *
1134 * Power config will reset and load initial firmware if required
1135 */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001136static int cx24116_initfe(struct dvb_frontend *fe)
Steven Toth0d467482008-09-04 01:14:43 -03001137{
Steven Tothf11ec7d2008-10-16 20:22:01 -03001138 struct cx24116_state *state = fe->demodulator_priv;
Darron Broad490c8682008-09-13 19:42:16 -03001139 struct cx24116_cmd cmd;
1140 int ret;
1141
Steven Tothf11ec7d2008-10-16 20:22:01 -03001142 dprintk("%s()\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -03001143
Darron Broad490c8682008-09-13 19:42:16 -03001144 /* Power on */
1145 cx24116_writereg(state, 0xe0, 0);
1146 cx24116_writereg(state, 0xe1, 0);
1147 cx24116_writereg(state, 0xea, 0);
1148
1149 /* Firmware CMD 36: Power config */
1150 cmd.args[0x00] = CMD_TUNERSLEEP;
1151 cmd.args[0x01] = 0;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001152 cmd.len = 0x02;
Darron Broad490c8682008-09-13 19:42:16 -03001153 ret = cx24116_cmd_execute(fe, &cmd);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001154 if (ret != 0)
Darron Broad490c8682008-09-13 19:42:16 -03001155 return ret;
1156
Steven Toth0d467482008-09-04 01:14:43 -03001157 return cx24116_diseqc_init(fe);
1158}
1159
Darron Broad490c8682008-09-13 19:42:16 -03001160/*
1161 * Put device to sleep
1162 */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001163static int cx24116_sleep(struct dvb_frontend *fe)
Darron Broad490c8682008-09-13 19:42:16 -03001164{
Steven Tothf11ec7d2008-10-16 20:22:01 -03001165 struct cx24116_state *state = fe->demodulator_priv;
Darron Broad490c8682008-09-13 19:42:16 -03001166 struct cx24116_cmd cmd;
1167 int ret;
1168
Steven Tothf11ec7d2008-10-16 20:22:01 -03001169 dprintk("%s()\n", __func__);
Darron Broad490c8682008-09-13 19:42:16 -03001170
1171 /* Firmware CMD 36: Power config */
1172 cmd.args[0x00] = CMD_TUNERSLEEP;
1173 cmd.args[0x01] = 1;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001174 cmd.len = 0x02;
Darron Broad490c8682008-09-13 19:42:16 -03001175 ret = cx24116_cmd_execute(fe, &cmd);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001176 if (ret != 0)
Darron Broad490c8682008-09-13 19:42:16 -03001177 return ret;
1178
1179 /* Power off (Shutdown clocks) */
1180 cx24116_writereg(state, 0xea, 0xff);
1181 cx24116_writereg(state, 0xe1, 1);
1182 cx24116_writereg(state, 0xe0, 1);
1183
1184 return 0;
1185}
1186
Steven Tothf11ec7d2008-10-16 20:22:01 -03001187static int cx24116_set_property(struct dvb_frontend *fe,
1188 struct dtv_property *tvp)
Steven Toth0d467482008-09-04 01:14:43 -03001189{
1190 dprintk("%s(..)\n", __func__);
1191 return 0;
1192}
1193
Steven Tothf11ec7d2008-10-16 20:22:01 -03001194static int cx24116_get_property(struct dvb_frontend *fe,
1195 struct dtv_property *tvp)
Steven Toth0d467482008-09-04 01:14:43 -03001196{
Steven Tothbfbf2da2008-09-12 01:37:37 -03001197 dprintk("%s(..)\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -03001198 return 0;
1199}
1200
1201/* dvb-core told us to tune, the tv property cache will be complete,
1202 * it's safe for is to pull values and use them for tuning purposes.
1203 */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001204static int cx24116_set_frontend(struct dvb_frontend *fe,
1205 struct dvb_frontend_parameters *p)
Steven Toth0d467482008-09-04 01:14:43 -03001206{
1207 struct cx24116_state *state = fe->demodulator_priv;
Steven Toth56f06802008-09-11 10:19:27 -03001208 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
Steven Toth0d467482008-09-04 01:14:43 -03001209 struct cx24116_cmd cmd;
1210 fe_status_t tunerstat;
Darron Broad2fd93392008-12-18 06:27:23 -03001211 int i, status, ret, retune = 1;
Steven Toth0d467482008-09-04 01:14:43 -03001212
Steven Tothf11ec7d2008-10-16 20:22:01 -03001213 dprintk("%s()\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -03001214
Steven Tothf11ec7d2008-10-16 20:22:01 -03001215 switch (c->delivery_system) {
1216 case SYS_DVBS:
1217 dprintk("%s: DVB-S delivery system selected\n", __func__);
Darron Broad01a8f032008-10-03 11:47:46 -03001218
Steven Tothf11ec7d2008-10-16 20:22:01 -03001219 /* Only QPSK is supported for DVB-S */
1220 if (c->modulation != QPSK) {
1221 dprintk("%s: unsupported modulation selected (%d)\n",
1222 __func__, c->modulation);
1223 return -EOPNOTSUPP;
1224 }
Darron Broad01a8f032008-10-03 11:47:46 -03001225
Steven Tothf11ec7d2008-10-16 20:22:01 -03001226 /* Pilot doesn't exist in DVB-S, turn bit off */
1227 state->dnxt.pilot_val = CX24116_PILOT_OFF;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001228
1229 /* DVB-S only supports 0.35 */
1230 if (c->rolloff != ROLLOFF_35) {
1231 dprintk("%s: unsupported rolloff selected (%d)\n",
1232 __func__, c->rolloff);
1233 return -EOPNOTSUPP;
1234 }
1235 state->dnxt.rolloff_val = CX24116_ROLLOFF_035;
1236 break;
1237
1238 case SYS_DVBS2:
1239 dprintk("%s: DVB-S2 delivery system selected\n", __func__);
1240
1241 /*
1242 * NBC 8PSK/QPSK with DVB-S is supported for DVB-S2,
1243 * but not hardware auto detection
1244 */
1245 if (c->modulation != PSK_8 && c->modulation != QPSK) {
1246 dprintk("%s: unsupported modulation selected (%d)\n",
1247 __func__, c->modulation);
1248 return -EOPNOTSUPP;
1249 }
1250
1251 switch (c->pilot) {
1252 case PILOT_AUTO: /* Not supported but emulated */
Christophe Thommeret74563212008-10-15 20:01:32 -03001253 state->dnxt.pilot_val = (c->modulation == QPSK)
1254 ? CX24116_PILOT_OFF : CX24116_PILOT_ON;
Darron Broad2fd93392008-12-18 06:27:23 -03001255 retune++;
Christophe Thommeret74563212008-10-15 20:01:32 -03001256 break;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001257 case PILOT_OFF:
Darron Broad01a8f032008-10-03 11:47:46 -03001258 state->dnxt.pilot_val = CX24116_PILOT_OFF;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001259 break;
1260 case PILOT_ON:
1261 state->dnxt.pilot_val = CX24116_PILOT_ON;
1262 break;
1263 default:
1264 dprintk("%s: unsupported pilot mode selected (%d)\n",
1265 __func__, c->pilot);
1266 return -EOPNOTSUPP;
1267 }
Darron Broad01a8f032008-10-03 11:47:46 -03001268
Steven Tothf11ec7d2008-10-16 20:22:01 -03001269 switch (c->rolloff) {
1270 case ROLLOFF_20:
1271 state->dnxt.rolloff_val = CX24116_ROLLOFF_020;
1272 break;
1273 case ROLLOFF_25:
1274 state->dnxt.rolloff_val = CX24116_ROLLOFF_025;
1275 break;
1276 case ROLLOFF_35:
Darron Broad7396d3e2008-09-14 10:45:58 -03001277 state->dnxt.rolloff_val = CX24116_ROLLOFF_035;
Darron Broad490c8682008-09-13 19:42:16 -03001278 break;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001279 case ROLLOFF_AUTO: /* Rolloff must be explicit */
Darron Broad490c8682008-09-13 19:42:16 -03001280 default:
Steven Tothf11ec7d2008-10-16 20:22:01 -03001281 dprintk("%s: unsupported rolloff selected (%d)\n",
1282 __func__, c->rolloff);
Darron Broad490c8682008-09-13 19:42:16 -03001283 return -EOPNOTSUPP;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001284 }
1285 break;
1286
1287 default:
1288 dprintk("%s: unsupported delivery system selected (%d)\n",
1289 __func__, c->delivery_system);
1290 return -EOPNOTSUPP;
Darron Broad490c8682008-09-13 19:42:16 -03001291 }
Darron Broad35694762008-12-18 06:21:51 -03001292 state->dnxt.delsys = c->delivery_system;
Darron Broad01a8f032008-10-03 11:47:46 -03001293 state->dnxt.modulation = c->modulation;
1294 state->dnxt.frequency = c->frequency;
1295 state->dnxt.pilot = c->pilot;
1296 state->dnxt.rolloff = c->rolloff;
Darron Broad490c8682008-09-13 19:42:16 -03001297
Steven Tothf11ec7d2008-10-16 20:22:01 -03001298 ret = cx24116_set_inversion(state, c->inversion);
1299 if (ret != 0)
Steven Toth0d467482008-09-04 01:14:43 -03001300 return ret;
1301
Darron Broad01a8f032008-10-03 11:47:46 -03001302 /* FEC_NONE/AUTO for DVB-S2 is not supported and detected here */
Darron Broad35694762008-12-18 06:21:51 -03001303 ret = cx24116_set_fec(state, c->delivery_system, c->modulation, c->fec_inner);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001304 if (ret != 0)
Steven Toth0d467482008-09-04 01:14:43 -03001305 return ret;
1306
Steven Tothf11ec7d2008-10-16 20:22:01 -03001307 ret = cx24116_set_symbolrate(state, c->symbol_rate);
1308 if (ret != 0)
Steven Toth0d467482008-09-04 01:14:43 -03001309 return ret;
1310
1311 /* discard the 'current' tuning parameters and prepare to tune */
1312 cx24116_clone_params(fe);
1313
Darron Broad35694762008-12-18 06:21:51 -03001314 dprintk("%s: delsys = %d\n", __func__, state->dcur.delsys);
Darron Broad01a8f032008-10-03 11:47:46 -03001315 dprintk("%s: modulation = %d\n", __func__, state->dcur.modulation);
Steven Toth0d467482008-09-04 01:14:43 -03001316 dprintk("%s: frequency = %d\n", __func__, state->dcur.frequency);
Darron Broad01a8f032008-10-03 11:47:46 -03001317 dprintk("%s: pilot = %d (val = 0x%02x)\n", __func__,
1318 state->dcur.pilot, state->dcur.pilot_val);
1319 dprintk("%s: retune = %d\n", __func__, retune);
1320 dprintk("%s: rolloff = %d (val = 0x%02x)\n", __func__,
1321 state->dcur.rolloff, state->dcur.rolloff_val);
Steven Toth0d467482008-09-04 01:14:43 -03001322 dprintk("%s: symbol_rate = %d\n", __func__, state->dcur.symbol_rate);
1323 dprintk("%s: FEC = %d (mask/val = 0x%02x/0x%02x)\n", __func__,
1324 state->dcur.fec, state->dcur.fec_mask, state->dcur.fec_val);
1325 dprintk("%s: Inversion = %d (val = 0x%02x)\n", __func__,
1326 state->dcur.inversion, state->dcur.inversion_val);
1327
Darron Broad490c8682008-09-13 19:42:16 -03001328 /* This is also done in advise/acquire on HVR4000 but not on LITE */
Steven Toth0d467482008-09-04 01:14:43 -03001329 if (state->config->set_ts_params)
1330 state->config->set_ts_params(fe, 0);
1331
Darron Broad490c8682008-09-13 19:42:16 -03001332 /* Set/Reset B/W */
1333 cmd.args[0x00] = CMD_BANDWIDTH;
1334 cmd.args[0x01] = 0x01;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001335 cmd.len = 0x02;
Darron Broad490c8682008-09-13 19:42:16 -03001336 ret = cx24116_cmd_execute(fe, &cmd);
1337 if (ret != 0)
1338 return ret;
Igor M. Liplianin3f8e51a2008-09-09 13:22:29 -03001339
Steven Toth0d467482008-09-04 01:14:43 -03001340 /* Prepare a tune request */
1341 cmd.args[0x00] = CMD_TUNEREQUEST;
1342
1343 /* Frequency */
1344 cmd.args[0x01] = (state->dcur.frequency & 0xff0000) >> 16;
1345 cmd.args[0x02] = (state->dcur.frequency & 0x00ff00) >> 8;
1346 cmd.args[0x03] = (state->dcur.frequency & 0x0000ff);
1347
1348 /* Symbol Rate */
1349 cmd.args[0x04] = ((state->dcur.symbol_rate / 1000) & 0xff00) >> 8;
1350 cmd.args[0x05] = ((state->dcur.symbol_rate / 1000) & 0x00ff);
1351
1352 /* Automatic Inversion */
1353 cmd.args[0x06] = state->dcur.inversion_val;
1354
Darron Broad01a8f032008-10-03 11:47:46 -03001355 /* Modulation / FEC / Pilot */
1356 cmd.args[0x07] = state->dcur.fec_val | state->dcur.pilot_val;
Steven Toth0d467482008-09-04 01:14:43 -03001357
1358 cmd.args[0x08] = CX24116_SEARCH_RANGE_KHZ >> 8;
1359 cmd.args[0x09] = CX24116_SEARCH_RANGE_KHZ & 0xff;
1360 cmd.args[0x0a] = 0x00;
1361 cmd.args[0x0b] = 0x00;
Darron Broad490c8682008-09-13 19:42:16 -03001362 cmd.args[0x0c] = state->dcur.rolloff_val;
Steven Toth0d467482008-09-04 01:14:43 -03001363 cmd.args[0x0d] = state->dcur.fec_mask;
Igor M. Liplianin3f8e51a2008-09-09 13:22:29 -03001364
Darron Broad490c8682008-09-13 19:42:16 -03001365 if (state->dcur.symbol_rate > 30000000) {
Igor M. Liplianin3f8e51a2008-09-09 13:22:29 -03001366 cmd.args[0x0e] = 0x04;
1367 cmd.args[0x0f] = 0x00;
1368 cmd.args[0x10] = 0x01;
1369 cmd.args[0x11] = 0x77;
1370 cmd.args[0x12] = 0x36;
Darron Broad490c8682008-09-13 19:42:16 -03001371 cx24116_writereg(state, CX24116_REG_CLKDIV, 0x44);
1372 cx24116_writereg(state, CX24116_REG_RATEDIV, 0x01);
Igor M. Liplianin3f8e51a2008-09-09 13:22:29 -03001373 } else {
1374 cmd.args[0x0e] = 0x06;
1375 cmd.args[0x0f] = 0x00;
1376 cmd.args[0x10] = 0x00;
1377 cmd.args[0x11] = 0xFA;
1378 cmd.args[0x12] = 0x24;
Darron Broad490c8682008-09-13 19:42:16 -03001379 cx24116_writereg(state, CX24116_REG_CLKDIV, 0x46);
1380 cx24116_writereg(state, CX24116_REG_RATEDIV, 0x00);
Igor M. Liplianin3f8e51a2008-09-09 13:22:29 -03001381 }
1382
Steven Tothf11ec7d2008-10-16 20:22:01 -03001383 cmd.len = 0x13;
Steven Toth0d467482008-09-04 01:14:43 -03001384
1385 /* We need to support pilot and non-pilot tuning in the
1386 * driver automatically. This is a workaround for because
1387 * the demod does not support autodetect.
1388 */
1389 do {
Darron Broad490c8682008-09-13 19:42:16 -03001390 /* Reset status register */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001391 status = cx24116_readreg(state, CX24116_REG_SSTATUS)
1392 & CX24116_SIGNAL_MASK;
Darron Broad490c8682008-09-13 19:42:16 -03001393 cx24116_writereg(state, CX24116_REG_SSTATUS, status);
Steven Toth0d467482008-09-04 01:14:43 -03001394
1395 /* Tune */
1396 ret = cx24116_cmd_execute(fe, &cmd);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001397 if (ret != 0)
Steven Toth0d467482008-09-04 01:14:43 -03001398 break;
1399
Darron Broad490c8682008-09-13 19:42:16 -03001400 /*
1401 * Wait for up to 500 ms before retrying
1402 *
1403 * If we are able to tune then generally it occurs within 100ms.
1404 * If it takes longer, try a different toneburst setting.
1405 */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001406 for (i = 0; i < 50 ; i++) {
Darron Broad490c8682008-09-13 19:42:16 -03001407 cx24116_read_status(fe, &tunerstat);
1408 status = tunerstat & (FE_HAS_SIGNAL | FE_HAS_SYNC);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001409 if (status == (FE_HAS_SIGNAL | FE_HAS_SYNC)) {
1410 dprintk("%s: Tuned\n", __func__);
Darron Broad490c8682008-09-13 19:42:16 -03001411 goto tuned;
1412 }
1413 msleep(10);
Steven Toth0d467482008-09-04 01:14:43 -03001414 }
Darron Broad490c8682008-09-13 19:42:16 -03001415
Steven Tothf11ec7d2008-10-16 20:22:01 -03001416 dprintk("%s: Not tuned\n", __func__);
Darron Broad490c8682008-09-13 19:42:16 -03001417
1418 /* Toggle pilot bit when in auto-pilot */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001419 if (state->dcur.pilot == PILOT_AUTO)
Darron Broad01a8f032008-10-03 11:47:46 -03001420 cmd.args[0x07] ^= CX24116_PILOT_ON;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001421 } while (--retune);
Steven Toth0d467482008-09-04 01:14:43 -03001422
Darron Broad490c8682008-09-13 19:42:16 -03001423tuned: /* Set/Reset B/W */
1424 cmd.args[0x00] = CMD_BANDWIDTH;
1425 cmd.args[0x01] = 0x00;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001426 cmd.len = 0x02;
Darron Broad490c8682008-09-13 19:42:16 -03001427 ret = cx24116_cmd_execute(fe, &cmd);
1428 if (ret != 0)
1429 return ret;
1430
Steven Toth0d467482008-09-04 01:14:43 -03001431 return ret;
1432}
1433
Darron Broad6639f1e2008-12-18 06:28:18 -03001434static int cx24116_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters *params,
1435 unsigned int mode_flags, unsigned int *delay, fe_status_t *status)
1436{
1437 *delay = HZ / 5;
1438 if (params) {
1439 int ret = cx24116_set_frontend(fe, params);
1440 if (ret)
1441 return ret;
1442 }
1443 return cx24116_read_status(fe, status);
1444}
1445
1446static int cx24116_get_algo(struct dvb_frontend *fe)
1447{
1448 return DVBFE_ALGO_HW;
1449}
1450
Steven Toth0d467482008-09-04 01:14:43 -03001451static struct dvb_frontend_ops cx24116_ops = {
1452
1453 .info = {
1454 .name = "Conexant CX24116/CX24118",
1455 .type = FE_QPSK,
1456 .frequency_min = 950000,
1457 .frequency_max = 2150000,
1458 .frequency_stepsize = 1011, /* kHz for QPSK frontends */
1459 .frequency_tolerance = 5000,
1460 .symbol_rate_min = 1000000,
1461 .symbol_rate_max = 45000000,
1462 .caps = FE_CAN_INVERSION_AUTO |
1463 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
1464 FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
1465 FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
Klaus Schmidingerfaed4aa2008-12-31 14:13:56 -03001466 FE_CAN_2G_MODULATION |
Steven Toth0d467482008-09-04 01:14:43 -03001467 FE_CAN_QPSK | FE_CAN_RECOVER
1468 },
1469
1470 .release = cx24116_release,
1471
1472 .init = cx24116_initfe,
Darron Broad490c8682008-09-13 19:42:16 -03001473 .sleep = cx24116_sleep,
Steven Toth0d467482008-09-04 01:14:43 -03001474 .read_status = cx24116_read_status,
1475 .read_ber = cx24116_read_ber,
1476 .read_signal_strength = cx24116_read_signal_strength,
1477 .read_snr = cx24116_read_snr,
1478 .read_ucblocks = cx24116_read_ucblocks,
1479 .set_tone = cx24116_set_tone,
1480 .set_voltage = cx24116_set_voltage,
1481 .diseqc_send_master_cmd = cx24116_send_diseqc_msg,
1482 .diseqc_send_burst = cx24116_diseqc_send_burst,
Darron Broad6639f1e2008-12-18 06:28:18 -03001483 .get_frontend_algo = cx24116_get_algo,
1484 .tune = cx24116_tune,
Steven Toth0d467482008-09-04 01:14:43 -03001485
1486 .set_property = cx24116_set_property,
Steven Tothbfbf2da2008-09-12 01:37:37 -03001487 .get_property = cx24116_get_property,
Steven Toth0d467482008-09-04 01:14:43 -03001488 .set_frontend = cx24116_set_frontend,
1489};
1490
Steven Toth0d467482008-09-04 01:14:43 -03001491MODULE_DESCRIPTION("DVB Frontend module for Conexant cx24116/cx24118 hardware");
1492MODULE_AUTHOR("Steven Toth");
1493MODULE_LICENSE("GPL");
1494