blob: 414bec9b5b64b6584f9b7125757ab6a2e0cf0692 [file] [log] [blame]
Steven Toth0d467482008-09-04 01:14:43 -03001/*
2 Conexant cx24116/cx24118 - DVBS/S2 Satellite demod/tuner driver
3
4 Copyright (C) 2006-2008 Steven Toth <stoth@hauppauge.com>
Darron Broad490c8682008-09-13 19:42:16 -03005 Copyright (C) 2006-2007 Georg Acher
6 Copyright (C) 2007-2008 Darron Broad
7 March 2007
8 Fixed some bugs.
9 Added diseqc support.
10 Added corrected signal strength support.
11 August 2007
12 Sync with legacy version.
13 Some clean ups.
14 Copyright (C) 2008 Igor Liplianin
15 September, 9th 2008
Igor M. Liplianinc063a482008-09-14 07:43:53 -030016 Fixed locking on high symbol rates (>30000).
17 Implement MPEG initialization parameter.
Steven Toth0d467482008-09-04 01:14:43 -030018
19 This program is free software; you can redistribute it and/or modify
20 it under the terms of the GNU General Public License as published by
21 the Free Software Foundation; either version 2 of the License, or
22 (at your option) any later version.
23
24 This program is distributed in the hope that it will be useful,
25 but WITHOUT ANY WARRANTY; without even the implied warranty of
26 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 GNU General Public License for more details.
28
29 You should have received a copy of the GNU General Public License
30 along with this program; if not, write to the Free Software
31 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
32*/
33
Steven Toth0d467482008-09-04 01:14:43 -030034#include <linux/slab.h>
35#include <linux/kernel.h>
36#include <linux/module.h>
37#include <linux/moduleparam.h>
38#include <linux/init.h>
39#include <linux/firmware.h>
40
41#include "dvb_frontend.h"
42#include "cx24116.h"
43
Steven Tothf11ec7d2008-10-16 20:22:01 -030044static int debug;
45module_param(debug, int, 0644);
46MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
47
Darron Broad490c8682008-09-13 19:42:16 -030048#define dprintk(args...) \
49 do { \
Steven Tothf11ec7d2008-10-16 20:22:01 -030050 if (debug) \
Steven Toth98c94822008-10-16 20:24:42 -030051 printk(KERN_INFO "cx24116: " args); \
Darron Broad490c8682008-09-13 19:42:16 -030052 } while (0)
53
Steven Toth0d467482008-09-04 01:14:43 -030054#define CX24116_DEFAULT_FIRMWARE "dvb-fe-cx24116.fw"
55#define CX24116_SEARCH_RANGE_KHZ 5000
56
Darron Broad490c8682008-09-13 19:42:16 -030057/* known registers */
58#define CX24116_REG_COMMAND (0x00) /* command args 0x00..0x1e */
59#define CX24116_REG_EXECUTE (0x1f) /* execute command */
60#define CX24116_REG_MAILBOX (0x96) /* FW or multipurpose mailbox? */
61#define CX24116_REG_RESET (0x20) /* reset status > 0 */
62#define CX24116_REG_SIGNAL (0x9e) /* signal low */
63#define CX24116_REG_SSTATUS (0x9d) /* signal high / status */
Steven Toth8953db72008-10-06 21:20:21 -030064#define CX24116_REG_QUALITY8 (0xa3)
Darron Broad490c8682008-09-13 19:42:16 -030065#define CX24116_REG_QSTATUS (0xbc)
Steven Toth8953db72008-10-06 21:20:21 -030066#define CX24116_REG_QUALITY0 (0xd5)
Darron Broad490c8682008-09-13 19:42:16 -030067#define CX24116_REG_BER0 (0xc9)
68#define CX24116_REG_BER8 (0xc8)
69#define CX24116_REG_BER16 (0xc7)
70#define CX24116_REG_BER24 (0xc6)
71#define CX24116_REG_UCB0 (0xcb)
72#define CX24116_REG_UCB8 (0xca)
73#define CX24116_REG_CLKDIV (0xf3)
74#define CX24116_REG_RATEDIV (0xf9)
Steven Toth98c94822008-10-16 20:24:42 -030075
76/* configured fec (not tuned) or actual FEC (tuned) 1=1/2 2=2/3 etc */
77#define CX24116_REG_FECSTATUS (0x9c)
Darron Broad681faa02008-09-22 00:47:20 -030078
79/* FECSTATUS bits */
Steven Toth98c94822008-10-16 20:24:42 -030080/* mask to determine configured fec (not tuned) or actual fec (tuned) */
81#define CX24116_FEC_FECMASK (0x1f)
82
83/* Select DVB-S demodulator, else DVB-S2 */
84#define CX24116_FEC_DVBS (0x20)
Darron Broad681faa02008-09-22 00:47:20 -030085#define CX24116_FEC_UNKNOWN (0x40) /* Unknown/unused */
Steven Toth98c94822008-10-16 20:24:42 -030086
87/* Pilot mode requested when tuning else always reset when tuned */
88#define CX24116_FEC_PILOT (0x80)
Steven Toth0d467482008-09-04 01:14:43 -030089
90/* arg buffer size */
91#define CX24116_ARGLEN (0x1e)
92
Darron Broad490c8682008-09-13 19:42:16 -030093/* rolloff */
94#define CX24116_ROLLOFF_020 (0x00)
95#define CX24116_ROLLOFF_025 (0x01)
96#define CX24116_ROLLOFF_035 (0x02)
97
98/* pilot bit */
Darron Broad01a8f032008-10-03 11:47:46 -030099#define CX24116_PILOT_OFF (0x00)
100#define CX24116_PILOT_ON (0x40)
Darron Broad490c8682008-09-13 19:42:16 -0300101
102/* signal status */
103#define CX24116_HAS_SIGNAL (0x01)
104#define CX24116_HAS_CARRIER (0x02)
105#define CX24116_HAS_VITERBI (0x04)
106#define CX24116_HAS_SYNCLOCK (0x08)
107#define CX24116_HAS_UNKNOWN1 (0x10)
108#define CX24116_HAS_UNKNOWN2 (0x20)
109#define CX24116_STATUS_MASK (0x3f)
110#define CX24116_SIGNAL_MASK (0xc0)
111
112#define CX24116_DISEQC_TONEOFF (0) /* toneburst never sent */
113#define CX24116_DISEQC_TONECACHE (1) /* toneburst cached */
114#define CX24116_DISEQC_MESGCACHE (2) /* message cached */
115
Steven Toth0d467482008-09-04 01:14:43 -0300116/* arg offset for DiSEqC */
117#define CX24116_DISEQC_BURST (1)
118#define CX24116_DISEQC_ARG2_2 (2) /* unknown value=2 */
119#define CX24116_DISEQC_ARG3_0 (3) /* unknown value=0 */
120#define CX24116_DISEQC_ARG4_0 (4) /* unknown value=0 */
121#define CX24116_DISEQC_MSGLEN (5)
122#define CX24116_DISEQC_MSGOFS (6)
123
124/* DiSEqC burst */
125#define CX24116_DISEQC_MINI_A (0)
126#define CX24116_DISEQC_MINI_B (1)
127
Darron Broad490c8682008-09-13 19:42:16 -0300128/* DiSEqC tone burst */
129static int toneburst = 1;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300130module_param(toneburst, int, 0644);
Steven Toth98c94822008-10-16 20:24:42 -0300131MODULE_PARM_DESC(toneburst, "DiSEqC toneburst 0=OFF, 1=TONE CACHE, "\
132 "2=MESSAGE CACHE (default:1)");
Darron Broad490c8682008-09-13 19:42:16 -0300133
Steven Toth8953db72008-10-06 21:20:21 -0300134/* SNR measurements */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300135static int esno_snr;
136module_param(esno_snr, int, 0644);
Steven Toth98c94822008-10-16 20:24:42 -0300137MODULE_PARM_DESC(debug, "SNR return units, 0=PERCENTAGE 0-100, "\
138 "1=ESNO(db * 10) (default:0)");
Steven Toth8953db72008-10-06 21:20:21 -0300139
Steven Tothf11ec7d2008-10-16 20:22:01 -0300140enum cmds {
Darron Broad490c8682008-09-13 19:42:16 -0300141 CMD_SET_VCO = 0x10,
Steven Toth0d467482008-09-04 01:14:43 -0300142 CMD_TUNEREQUEST = 0x11,
Darron Broad490c8682008-09-13 19:42:16 -0300143 CMD_MPEGCONFIG = 0x13,
144 CMD_TUNERINIT = 0x14,
145 CMD_BANDWIDTH = 0x15,
146 CMD_GETAGC = 0x19,
147 CMD_LNBCONFIG = 0x20,
148 CMD_LNBSEND = 0x21, /* Formerly CMD_SEND_DISEQC */
Steven Toth0d467482008-09-04 01:14:43 -0300149 CMD_SET_TONEPRE = 0x22,
150 CMD_SET_TONE = 0x23,
Darron Broad490c8682008-09-13 19:42:16 -0300151 CMD_UPDFWVERS = 0x35,
152 CMD_TUNERSLEEP = 0x36,
153 CMD_AGCCONTROL = 0x3b, /* Unknown */
Steven Toth0d467482008-09-04 01:14:43 -0300154};
155
156/* The Demod/Tuner can't easily provide these, we cache them */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300157struct cx24116_tuning {
Steven Toth0d467482008-09-04 01:14:43 -0300158 u32 frequency;
159 u32 symbol_rate;
160 fe_spectral_inversion_t inversion;
161 fe_code_rate_t fec;
162
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 */
372struct 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 Broad490c8682008-09-13 19:42:16 -0300684 int lock = cx24116_readreg(state, CX24116_REG_SSTATUS);
Steven Toth0d467482008-09-04 01:14:43 -0300685
686 dprintk("%s: status = 0x%02x\n", __func__, lock);
687
688 *status = 0;
689
Darron Broad490c8682008-09-13 19:42:16 -0300690 if (lock & CX24116_HAS_SIGNAL)
Steven Toth0d467482008-09-04 01:14:43 -0300691 *status |= FE_HAS_SIGNAL;
Darron Broad490c8682008-09-13 19:42:16 -0300692 if (lock & CX24116_HAS_CARRIER)
Steven Toth0d467482008-09-04 01:14:43 -0300693 *status |= FE_HAS_CARRIER;
Darron Broad490c8682008-09-13 19:42:16 -0300694 if (lock & CX24116_HAS_VITERBI)
Steven Toth0d467482008-09-04 01:14:43 -0300695 *status |= FE_HAS_VITERBI;
Darron Broad490c8682008-09-13 19:42:16 -0300696 if (lock & CX24116_HAS_SYNCLOCK)
Steven Toth0d467482008-09-04 01:14:43 -0300697 *status |= FE_HAS_SYNC | FE_HAS_LOCK;
698
699 return 0;
700}
701
Steven Tothf11ec7d2008-10-16 20:22:01 -0300702static int cx24116_read_ber(struct dvb_frontend *fe, u32 *ber)
Steven Toth0d467482008-09-04 01:14:43 -0300703{
Darron Broad490c8682008-09-13 19:42:16 -0300704 struct cx24116_state *state = fe->demodulator_priv;
705
Steven Toth0d467482008-09-04 01:14:43 -0300706 dprintk("%s()\n", __func__);
Darron Broad490c8682008-09-13 19:42:16 -0300707
Steven Tothf11ec7d2008-10-16 20:22:01 -0300708 *ber = (cx24116_readreg(state, CX24116_REG_BER24) << 24) |
709 (cx24116_readreg(state, CX24116_REG_BER16) << 16) |
710 (cx24116_readreg(state, CX24116_REG_BER8) << 8) |
711 cx24116_readreg(state, CX24116_REG_BER0);
Steven Toth0d467482008-09-04 01:14:43 -0300712
713 return 0;
714}
715
Darron Broad490c8682008-09-13 19:42:16 -0300716/* TODO Determine function and scale appropriately */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300717static int cx24116_read_signal_strength(struct dvb_frontend *fe,
718 u16 *signal_strength)
Steven Toth0d467482008-09-04 01:14:43 -0300719{
720 struct cx24116_state *state = fe->demodulator_priv;
Darron Broad490c8682008-09-13 19:42:16 -0300721 struct cx24116_cmd cmd;
722 int ret;
723 u16 sig_reading;
724
725 dprintk("%s()\n", __func__);
726
727 /* Firmware CMD 19: Get AGC */
728 cmd.args[0x00] = CMD_GETAGC;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300729 cmd.len = 0x01;
Darron Broad490c8682008-09-13 19:42:16 -0300730 ret = cx24116_cmd_execute(fe, &cmd);
731 if (ret != 0)
732 return ret;
733
Steven Tothf11ec7d2008-10-16 20:22:01 -0300734 sig_reading =
735 (cx24116_readreg(state,
736 CX24116_REG_SSTATUS) & CX24116_SIGNAL_MASK) |
737 (cx24116_readreg(state, CX24116_REG_SIGNAL) << 6);
738 *signal_strength = 0 - sig_reading;
Darron Broad490c8682008-09-13 19:42:16 -0300739
Steven Tothf11ec7d2008-10-16 20:22:01 -0300740 dprintk("%s: raw / cooked = 0x%04x / 0x%04x\n",
741 __func__, sig_reading, *signal_strength);
Darron Broad490c8682008-09-13 19:42:16 -0300742
743 return 0;
744}
745
746/* SNR (0..100)% = (sig & 0xf0) * 10 + (sig & 0x0f) * 10 / 16 */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300747static int cx24116_read_snr_pct(struct dvb_frontend *fe, u16 *snr)
Darron Broad490c8682008-09-13 19:42:16 -0300748{
749 struct cx24116_state *state = fe->demodulator_priv;
750 u8 snr_reading;
751 static const u32 snr_tab[] = { /* 10 x Table (rounded up) */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300752 0x00000, 0x0199A, 0x03333, 0x04ccD, 0x06667,
753 0x08000, 0x0999A, 0x0b333, 0x0cccD, 0x0e667,
754 0x10000, 0x1199A, 0x13333, 0x14ccD, 0x16667,
755 0x18000 };
Steven Toth0d467482008-09-04 01:14:43 -0300756
757 dprintk("%s()\n", __func__);
758
Steven Toth8953db72008-10-06 21:20:21 -0300759 snr_reading = cx24116_readreg(state, CX24116_REG_QUALITY0);
Steven Toth0d467482008-09-04 01:14:43 -0300760
Steven Tothf11ec7d2008-10-16 20:22:01 -0300761 if (snr_reading >= 0xa0 /* 100% */)
Darron Broad490c8682008-09-13 19:42:16 -0300762 *snr = 0xffff;
Steven Toth0d467482008-09-04 01:14:43 -0300763 else
Steven Tothf11ec7d2008-10-16 20:22:01 -0300764 *snr = snr_tab[(snr_reading & 0xf0) >> 4] +
765 (snr_tab[(snr_reading & 0x0f)] >> 4);
Steven Toth0d467482008-09-04 01:14:43 -0300766
Darron Broad490c8682008-09-13 19:42:16 -0300767 dprintk("%s: raw / cooked = 0x%02x / 0x%04x\n", __func__,
768 snr_reading, *snr);
Steven Toth0d467482008-09-04 01:14:43 -0300769
770 return 0;
771}
772
Steven Toth8953db72008-10-06 21:20:21 -0300773/* The reelbox patches show the value in the registers represents
774 * ESNO, from 0->30db (values 0->300). We provide this value by
775 * default.
776 */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300777static int cx24116_read_snr_esno(struct dvb_frontend *fe, u16 *snr)
Steven Toth8953db72008-10-06 21:20:21 -0300778{
779 struct cx24116_state *state = fe->demodulator_priv;
780
781 dprintk("%s()\n", __func__);
782
783 *snr = cx24116_readreg(state, CX24116_REG_QUALITY8) << 8 |
784 cx24116_readreg(state, CX24116_REG_QUALITY0);
785
786 dprintk("%s: raw 0x%04x\n", __func__, *snr);
787
788 return 0;
789}
790
Steven Tothf11ec7d2008-10-16 20:22:01 -0300791static int cx24116_read_snr(struct dvb_frontend *fe, u16 *snr)
Steven Toth8953db72008-10-06 21:20:21 -0300792{
793 if (esno_snr == 1)
794 return cx24116_read_snr_esno(fe, snr);
795 else
796 return cx24116_read_snr_pct(fe, snr);
797}
798
Steven Tothf11ec7d2008-10-16 20:22:01 -0300799static int cx24116_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
Steven Toth0d467482008-09-04 01:14:43 -0300800{
Darron Broad490c8682008-09-13 19:42:16 -0300801 struct cx24116_state *state = fe->demodulator_priv;
802
Steven Toth0d467482008-09-04 01:14:43 -0300803 dprintk("%s()\n", __func__);
Darron Broad490c8682008-09-13 19:42:16 -0300804
Steven Tothf11ec7d2008-10-16 20:22:01 -0300805 *ucblocks = (cx24116_readreg(state, CX24116_REG_UCB8) << 8) |
Darron Broad490c8682008-09-13 19:42:16 -0300806 cx24116_readreg(state, CX24116_REG_UCB0);
Steven Toth0d467482008-09-04 01:14:43 -0300807
808 return 0;
809}
810
811/* Overwrite the current tuning params, we are about to tune */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300812static void cx24116_clone_params(struct dvb_frontend *fe)
Steven Toth0d467482008-09-04 01:14:43 -0300813{
814 struct cx24116_state *state = fe->demodulator_priv;
815 memcpy(&state->dcur, &state->dnxt, sizeof(state->dcur));
816}
817
Darron Broad490c8682008-09-13 19:42:16 -0300818/* Wait for LNB */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300819static int cx24116_wait_for_lnb(struct dvb_frontend *fe)
Darron Broad490c8682008-09-13 19:42:16 -0300820{
821 struct cx24116_state *state = fe->demodulator_priv;
822 int i;
823
824 dprintk("%s() qstatus = 0x%02x\n", __func__,
825 cx24116_readreg(state, CX24116_REG_QSTATUS));
826
827 /* Wait for up to 300 ms */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300828 for (i = 0; i < 30 ; i++) {
Darron Broad490c8682008-09-13 19:42:16 -0300829 if (cx24116_readreg(state, CX24116_REG_QSTATUS) & 0x20)
830 return 0;
831 msleep(10);
832 }
833
834 dprintk("%s(): LNB not ready\n", __func__);
835
836 return -ETIMEDOUT; /* -EBUSY ? */
837}
838
Steven Tothf11ec7d2008-10-16 20:22:01 -0300839static int cx24116_set_tone(struct dvb_frontend *fe,
840 fe_sec_tone_mode_t tone)
Steven Toth0d467482008-09-04 01:14:43 -0300841{
842 struct cx24116_cmd cmd;
843 int ret;
844
845 dprintk("%s(%d)\n", __func__, tone);
Steven Tothf11ec7d2008-10-16 20:22:01 -0300846 if ((tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF)) {
Steven Toth98c94822008-10-16 20:24:42 -0300847 printk(KERN_ERR "%s: Invalid, tone=%d\n", __func__, tone);
Steven Toth0d467482008-09-04 01:14:43 -0300848 return -EINVAL;
849 }
850
Darron Broad490c8682008-09-13 19:42:16 -0300851 /* Wait for LNB ready */
852 ret = cx24116_wait_for_lnb(fe);
Steven Tothf11ec7d2008-10-16 20:22:01 -0300853 if (ret != 0)
Darron Broad490c8682008-09-13 19:42:16 -0300854 return ret;
855
856 /* Min delay time after DiSEqC send */
857 msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */
858
Steven Toth0d467482008-09-04 01:14:43 -0300859 /* This is always done before the tone is set */
860 cmd.args[0x00] = CMD_SET_TONEPRE;
861 cmd.args[0x01] = 0x00;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300862 cmd.len = 0x02;
Steven Toth0d467482008-09-04 01:14:43 -0300863 ret = cx24116_cmd_execute(fe, &cmd);
864 if (ret != 0)
865 return ret;
866
867 /* Now we set the tone */
868 cmd.args[0x00] = CMD_SET_TONE;
869 cmd.args[0x01] = 0x00;
870 cmd.args[0x02] = 0x00;
871
872 switch (tone) {
873 case SEC_TONE_ON:
874 dprintk("%s: setting tone on\n", __func__);
875 cmd.args[0x03] = 0x01;
876 break;
877 case SEC_TONE_OFF:
Steven Tothf11ec7d2008-10-16 20:22:01 -0300878 dprintk("%s: setting tone off\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -0300879 cmd.args[0x03] = 0x00;
880 break;
881 }
Steven Tothf11ec7d2008-10-16 20:22:01 -0300882 cmd.len = 0x04;
Steven Toth0d467482008-09-04 01:14:43 -0300883
Darron Broad490c8682008-09-13 19:42:16 -0300884 /* Min delay time before DiSEqC send */
885 msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */
886
Steven Toth0d467482008-09-04 01:14:43 -0300887 return cx24116_cmd_execute(fe, &cmd);
888}
889
890/* Initialise DiSEqC */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300891static int cx24116_diseqc_init(struct dvb_frontend *fe)
Steven Toth0d467482008-09-04 01:14:43 -0300892{
893 struct cx24116_state *state = fe->demodulator_priv;
Darron Broad490c8682008-09-13 19:42:16 -0300894 struct cx24116_cmd cmd;
895 int ret;
Steven Toth0d467482008-09-04 01:14:43 -0300896
Darron Broad490c8682008-09-13 19:42:16 -0300897 /* Firmware CMD 20: LNB/DiSEqC config */
898 cmd.args[0x00] = CMD_LNBCONFIG;
899 cmd.args[0x01] = 0x00;
900 cmd.args[0x02] = 0x10;
901 cmd.args[0x03] = 0x00;
902 cmd.args[0x04] = 0x8f;
903 cmd.args[0x05] = 0x28;
904 cmd.args[0x06] = (toneburst == CX24116_DISEQC_TONEOFF) ? 0x00 : 0x01;
905 cmd.args[0x07] = 0x01;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300906 cmd.len = 0x08;
Darron Broad490c8682008-09-13 19:42:16 -0300907 ret = cx24116_cmd_execute(fe, &cmd);
908 if (ret != 0)
909 return ret;
910
911 /* Prepare a DiSEqC command */
912 state->dsec_cmd.args[0x00] = CMD_LNBSEND;
913
914 /* DiSEqC burst */
915 state->dsec_cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_A;
916
917 /* Unknown */
918 state->dsec_cmd.args[CX24116_DISEQC_ARG2_2] = 0x02;
919 state->dsec_cmd.args[CX24116_DISEQC_ARG3_0] = 0x00;
Steven Toth98c94822008-10-16 20:24:42 -0300920 /* Continuation flag? */
921 state->dsec_cmd.args[CX24116_DISEQC_ARG4_0] = 0x00;
Darron Broad490c8682008-09-13 19:42:16 -0300922
923 /* DiSEqC message length */
924 state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = 0x00;
925
926 /* Command length */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300927 state->dsec_cmd.len = CX24116_DISEQC_MSGOFS;
Steven Toth0d467482008-09-04 01:14:43 -0300928
929 return 0;
930}
931
932/* Send DiSEqC message with derived burst (hack) || previous burst */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300933static int cx24116_send_diseqc_msg(struct dvb_frontend *fe,
934 struct dvb_diseqc_master_cmd *d)
Steven Toth0d467482008-09-04 01:14:43 -0300935{
936 struct cx24116_state *state = fe->demodulator_priv;
Steven Toth0d467482008-09-04 01:14:43 -0300937 int i, ret;
938
939 /* Dump DiSEqC message */
940 if (debug) {
Steven Toth98c94822008-10-16 20:24:42 -0300941 printk(KERN_INFO "cx24116: %s(", __func__);
Steven Tothf11ec7d2008-10-16 20:22:01 -0300942 for (i = 0 ; i < d->msg_len ;) {
Steven Toth98c94822008-10-16 20:24:42 -0300943 printk(KERN_INFO "0x%02x", d->msg[i]);
Steven Tothf11ec7d2008-10-16 20:22:01 -0300944 if (++i < d->msg_len)
Steven Toth98c94822008-10-16 20:24:42 -0300945 printk(KERN_INFO ", ");
Steven Tothf11ec7d2008-10-16 20:22:01 -0300946 }
Darron Broad490c8682008-09-13 19:42:16 -0300947 printk(") toneburst=%d\n", toneburst);
Steven Toth0d467482008-09-04 01:14:43 -0300948 }
949
Darron Broad490c8682008-09-13 19:42:16 -0300950 /* Validate length */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300951 if (d->msg_len > (CX24116_ARGLEN - CX24116_DISEQC_MSGOFS))
Steven Toth0d467482008-09-04 01:14:43 -0300952 return -EINVAL;
953
Steven Toth0d467482008-09-04 01:14:43 -0300954 /* DiSEqC message */
955 for (i = 0; i < d->msg_len; i++)
Darron Broad490c8682008-09-13 19:42:16 -0300956 state->dsec_cmd.args[CX24116_DISEQC_MSGOFS + i] = d->msg[i];
Steven Toth0d467482008-09-04 01:14:43 -0300957
Darron Broad490c8682008-09-13 19:42:16 -0300958 /* DiSEqC message length */
959 state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = d->msg_len;
Steven Toth0d467482008-09-04 01:14:43 -0300960
Darron Broad490c8682008-09-13 19:42:16 -0300961 /* Command length */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300962 state->dsec_cmd.len = CX24116_DISEQC_MSGOFS +
963 state->dsec_cmd.args[CX24116_DISEQC_MSGLEN];
Steven Toth0d467482008-09-04 01:14:43 -0300964
Darron Broad490c8682008-09-13 19:42:16 -0300965 /* DiSEqC toneburst */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300966 if (toneburst == CX24116_DISEQC_MESGCACHE)
Darron Broad490c8682008-09-13 19:42:16 -0300967 /* Message is cached */
968 return 0;
Steven Toth0d467482008-09-04 01:14:43 -0300969
Steven Tothf11ec7d2008-10-16 20:22:01 -0300970 else if (toneburst == CX24116_DISEQC_TONEOFF)
Darron Broad490c8682008-09-13 19:42:16 -0300971 /* Message is sent without burst */
972 state->dsec_cmd.args[CX24116_DISEQC_BURST] = 0;
973
Steven Tothf11ec7d2008-10-16 20:22:01 -0300974 else if (toneburst == CX24116_DISEQC_TONECACHE) {
Darron Broad490c8682008-09-13 19:42:16 -0300975 /*
976 * Message is sent with derived else cached burst
977 *
978 * WRITE PORT GROUP COMMAND 38
979 *
980 * 0/A/A: E0 10 38 F0..F3
981 * 1/B/B: E0 10 38 F4..F7
982 * 2/C/A: E0 10 38 F8..FB
983 * 3/D/B: E0 10 38 FC..FF
984 *
Darron Broad7396d3e2008-09-14 10:45:58 -0300985 * databyte[3]= 8421:8421
Darron Broad490c8682008-09-13 19:42:16 -0300986 * ABCD:WXYZ
987 * CLR :SET
988 *
989 * WX= PORT SELECT 0..3 (X=TONEBURST)
990 * Y = VOLTAGE (0=13V, 1=18V)
991 * Z = BAND (0=LOW, 1=HIGH(22K))
992 */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300993 if (d->msg_len >= 4 && d->msg[2] == 0x38)
994 state->dsec_cmd.args[CX24116_DISEQC_BURST] =
995 ((d->msg[3] & 4) >> 2);
996 if (debug)
997 dprintk("%s burst=%d\n", __func__,
998 state->dsec_cmd.args[CX24116_DISEQC_BURST]);
Darron Broad490c8682008-09-13 19:42:16 -0300999 }
1000
1001 /* Wait for LNB ready */
1002 ret = cx24116_wait_for_lnb(fe);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001003 if (ret != 0)
Darron Broad490c8682008-09-13 19:42:16 -03001004 return ret;
1005
1006 /* Wait for voltage/min repeat delay */
1007 msleep(100);
1008
1009 /* Command */
1010 ret = cx24116_cmd_execute(fe, &state->dsec_cmd);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001011 if (ret != 0)
Darron Broad490c8682008-09-13 19:42:16 -03001012 return ret;
1013 /*
1014 * Wait for send
Steven Toth0d467482008-09-04 01:14:43 -03001015 *
1016 * Eutelsat spec:
Darron Broad490c8682008-09-13 19:42:16 -03001017 * >15ms delay + (XXX determine if FW does this, see set_tone)
1018 * 13.5ms per byte +
1019 * >15ms delay +
1020 * 12.5ms burst +
1021 * >15ms delay (XXX determine if FW does this, see set_tone)
Steven Toth0d467482008-09-04 01:14:43 -03001022 */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001023 msleep((state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) +
1024 ((toneburst == CX24116_DISEQC_TONEOFF) ? 30 : 60));
Steven Toth0d467482008-09-04 01:14:43 -03001025
Darron Broad490c8682008-09-13 19:42:16 -03001026 return 0;
Steven Toth0d467482008-09-04 01:14:43 -03001027}
1028
1029/* Send DiSEqC burst */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001030static int cx24116_diseqc_send_burst(struct dvb_frontend *fe,
1031 fe_sec_mini_cmd_t burst)
Steven Toth0d467482008-09-04 01:14:43 -03001032{
1033 struct cx24116_state *state = fe->demodulator_priv;
Steven Toth0d467482008-09-04 01:14:43 -03001034 int ret;
1035
Steven Tothf11ec7d2008-10-16 20:22:01 -03001036 dprintk("%s(%d) toneburst=%d\n", __func__, burst, toneburst);
Steven Toth0d467482008-09-04 01:14:43 -03001037
Darron Broad490c8682008-09-13 19:42:16 -03001038 /* DiSEqC burst */
Steven Toth0d467482008-09-04 01:14:43 -03001039 if (burst == SEC_MINI_A)
Steven Tothf11ec7d2008-10-16 20:22:01 -03001040 state->dsec_cmd.args[CX24116_DISEQC_BURST] =
1041 CX24116_DISEQC_MINI_A;
1042 else if (burst == SEC_MINI_B)
1043 state->dsec_cmd.args[CX24116_DISEQC_BURST] =
1044 CX24116_DISEQC_MINI_B;
Steven Toth0d467482008-09-04 01:14:43 -03001045 else
1046 return -EINVAL;
1047
Darron Broad490c8682008-09-13 19:42:16 -03001048 /* DiSEqC toneburst */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001049 if (toneburst != CX24116_DISEQC_MESGCACHE)
Darron Broad490c8682008-09-13 19:42:16 -03001050 /* Burst is cached */
1051 return 0;
Steven Toth0d467482008-09-04 01:14:43 -03001052
Darron Broad490c8682008-09-13 19:42:16 -03001053 /* Burst is to be sent with cached message */
Steven Toth0d467482008-09-04 01:14:43 -03001054
Darron Broad490c8682008-09-13 19:42:16 -03001055 /* Wait for LNB ready */
1056 ret = cx24116_wait_for_lnb(fe);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001057 if (ret != 0)
Darron Broad490c8682008-09-13 19:42:16 -03001058 return ret;
Steven Toth0d467482008-09-04 01:14:43 -03001059
Darron Broad490c8682008-09-13 19:42:16 -03001060 /* Wait for voltage/min repeat delay */
1061 msleep(100);
Steven Toth0d467482008-09-04 01:14:43 -03001062
Darron Broad490c8682008-09-13 19:42:16 -03001063 /* Command */
1064 ret = cx24116_cmd_execute(fe, &state->dsec_cmd);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001065 if (ret != 0)
Darron Broad490c8682008-09-13 19:42:16 -03001066 return ret;
1067
1068 /*
1069 * Wait for send
1070 *
1071 * Eutelsat spec:
1072 * >15ms delay + (XXX determine if FW does this, see set_tone)
1073 * 13.5ms per byte +
1074 * >15ms delay +
1075 * 12.5ms burst +
1076 * >15ms delay (XXX determine if FW does this, see set_tone)
1077 */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001078 msleep((state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) + 60);
Darron Broad490c8682008-09-13 19:42:16 -03001079
1080 return 0;
Steven Toth0d467482008-09-04 01:14:43 -03001081}
1082
Steven Tothf11ec7d2008-10-16 20:22:01 -03001083static void cx24116_release(struct dvb_frontend *fe)
Steven Toth0d467482008-09-04 01:14:43 -03001084{
Steven Tothf11ec7d2008-10-16 20:22:01 -03001085 struct cx24116_state *state = fe->demodulator_priv;
1086 dprintk("%s\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -03001087 kfree(state);
1088}
1089
1090static struct dvb_frontend_ops cx24116_ops;
1091
Steven Tothf11ec7d2008-10-16 20:22:01 -03001092struct dvb_frontend *cx24116_attach(const struct cx24116_config *config,
1093 struct i2c_adapter *i2c)
Steven Toth0d467482008-09-04 01:14:43 -03001094{
Steven Tothf11ec7d2008-10-16 20:22:01 -03001095 struct cx24116_state *state = NULL;
Steven Toth0d467482008-09-04 01:14:43 -03001096 int ret;
1097
Steven Tothf11ec7d2008-10-16 20:22:01 -03001098 dprintk("%s\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -03001099
1100 /* allocate memory for the internal state */
1101 state = kmalloc(sizeof(struct cx24116_state), GFP_KERNEL);
Steven Toth98c94822008-10-16 20:24:42 -03001102 if (state == NULL)
Darron Broad7396d3e2008-09-14 10:45:58 -03001103 goto error1;
Steven Toth0d467482008-09-04 01:14:43 -03001104
1105 /* setup the state */
1106 memset(state, 0, sizeof(struct cx24116_state));
1107
1108 state->config = config;
1109 state->i2c = i2c;
1110
1111 /* check if the demod is present */
Steven Toth98c94822008-10-16 20:24:42 -03001112 ret = (cx24116_readreg(state, 0xFF) << 8) |
1113 cx24116_readreg(state, 0xFE);
Steven Toth0d467482008-09-04 01:14:43 -03001114 if (ret != 0x0501) {
Steven Toth98c94822008-10-16 20:24:42 -03001115 printk(KERN_INFO "Invalid probe, probably not a CX24116 device\n");
Darron Broad7396d3e2008-09-14 10:45:58 -03001116 goto error2;
Steven Toth0d467482008-09-04 01:14:43 -03001117 }
1118
1119 /* create dvb_frontend */
Steven Toth98c94822008-10-16 20:24:42 -03001120 memcpy(&state->frontend.ops, &cx24116_ops,
1121 sizeof(struct dvb_frontend_ops));
Steven Toth0d467482008-09-04 01:14:43 -03001122 state->frontend.demodulator_priv = state;
1123 return &state->frontend;
1124
Darron Broad7396d3e2008-09-14 10:45:58 -03001125error2: kfree(state);
Darron Broad490c8682008-09-13 19:42:16 -03001126error1: return NULL;
Steven Toth0d467482008-09-04 01:14:43 -03001127}
Steven Tothf11ec7d2008-10-16 20:22:01 -03001128EXPORT_SYMBOL(cx24116_attach);
1129
Darron Broad490c8682008-09-13 19:42:16 -03001130/*
1131 * Initialise or wake up device
1132 *
1133 * Power config will reset and load initial firmware if required
1134 */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001135static int cx24116_initfe(struct dvb_frontend *fe)
Steven Toth0d467482008-09-04 01:14:43 -03001136{
Steven Tothf11ec7d2008-10-16 20:22:01 -03001137 struct cx24116_state *state = fe->demodulator_priv;
Darron Broad490c8682008-09-13 19:42:16 -03001138 struct cx24116_cmd cmd;
1139 int ret;
1140
Steven Tothf11ec7d2008-10-16 20:22:01 -03001141 dprintk("%s()\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -03001142
Darron Broad490c8682008-09-13 19:42:16 -03001143 /* Power on */
1144 cx24116_writereg(state, 0xe0, 0);
1145 cx24116_writereg(state, 0xe1, 0);
1146 cx24116_writereg(state, 0xea, 0);
1147
1148 /* Firmware CMD 36: Power config */
1149 cmd.args[0x00] = CMD_TUNERSLEEP;
1150 cmd.args[0x01] = 0;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001151 cmd.len = 0x02;
Darron Broad490c8682008-09-13 19:42:16 -03001152 ret = cx24116_cmd_execute(fe, &cmd);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001153 if (ret != 0)
Darron Broad490c8682008-09-13 19:42:16 -03001154 return ret;
1155
Steven Toth0d467482008-09-04 01:14:43 -03001156 return cx24116_diseqc_init(fe);
1157}
1158
Darron Broad490c8682008-09-13 19:42:16 -03001159/*
1160 * Put device to sleep
1161 */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001162static int cx24116_sleep(struct dvb_frontend *fe)
Darron Broad490c8682008-09-13 19:42:16 -03001163{
Steven Tothf11ec7d2008-10-16 20:22:01 -03001164 struct cx24116_state *state = fe->demodulator_priv;
Darron Broad490c8682008-09-13 19:42:16 -03001165 struct cx24116_cmd cmd;
1166 int ret;
1167
Steven Tothf11ec7d2008-10-16 20:22:01 -03001168 dprintk("%s()\n", __func__);
Darron Broad490c8682008-09-13 19:42:16 -03001169
1170 /* Firmware CMD 36: Power config */
1171 cmd.args[0x00] = CMD_TUNERSLEEP;
1172 cmd.args[0x01] = 1;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001173 cmd.len = 0x02;
Darron Broad490c8682008-09-13 19:42:16 -03001174 ret = cx24116_cmd_execute(fe, &cmd);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001175 if (ret != 0)
Darron Broad490c8682008-09-13 19:42:16 -03001176 return ret;
1177
1178 /* Power off (Shutdown clocks) */
1179 cx24116_writereg(state, 0xea, 0xff);
1180 cx24116_writereg(state, 0xe1, 1);
1181 cx24116_writereg(state, 0xe0, 1);
1182
1183 return 0;
1184}
1185
Steven Tothf11ec7d2008-10-16 20:22:01 -03001186static int cx24116_set_property(struct dvb_frontend *fe,
1187 struct dtv_property *tvp)
Steven Toth0d467482008-09-04 01:14:43 -03001188{
1189 dprintk("%s(..)\n", __func__);
1190 return 0;
1191}
1192
Steven Tothf11ec7d2008-10-16 20:22:01 -03001193static int cx24116_get_property(struct dvb_frontend *fe,
1194 struct dtv_property *tvp)
Steven Toth0d467482008-09-04 01:14:43 -03001195{
Steven Tothbfbf2da2008-09-12 01:37:37 -03001196 dprintk("%s(..)\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -03001197 return 0;
1198}
1199
1200/* dvb-core told us to tune, the tv property cache will be complete,
1201 * it's safe for is to pull values and use them for tuning purposes.
1202 */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001203static int cx24116_set_frontend(struct dvb_frontend *fe,
1204 struct dvb_frontend_parameters *p)
Steven Toth0d467482008-09-04 01:14:43 -03001205{
1206 struct cx24116_state *state = fe->demodulator_priv;
Steven Toth56f06802008-09-11 10:19:27 -03001207 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
Steven Toth0d467482008-09-04 01:14:43 -03001208 struct cx24116_cmd cmd;
1209 fe_status_t tunerstat;
Darron Broad01a8f032008-10-03 11:47:46 -03001210 int i, status, ret, retune;
Steven Toth0d467482008-09-04 01:14:43 -03001211
Steven Tothf11ec7d2008-10-16 20:22:01 -03001212 dprintk("%s()\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -03001213
Steven Tothf11ec7d2008-10-16 20:22:01 -03001214 switch (c->delivery_system) {
1215 case SYS_DVBS:
1216 dprintk("%s: DVB-S delivery system selected\n", __func__);
Darron Broad01a8f032008-10-03 11:47:46 -03001217
Steven Tothf11ec7d2008-10-16 20:22:01 -03001218 /* Only QPSK is supported for DVB-S */
1219 if (c->modulation != QPSK) {
1220 dprintk("%s: unsupported modulation selected (%d)\n",
1221 __func__, c->modulation);
1222 return -EOPNOTSUPP;
1223 }
Darron Broad01a8f032008-10-03 11:47:46 -03001224
Steven Tothf11ec7d2008-10-16 20:22:01 -03001225 /* Pilot doesn't exist in DVB-S, turn bit off */
1226 state->dnxt.pilot_val = CX24116_PILOT_OFF;
1227 retune = 1;
1228
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;
1255 retune = 2;
1256 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
1434static struct dvb_frontend_ops cx24116_ops = {
1435
1436 .info = {
1437 .name = "Conexant CX24116/CX24118",
1438 .type = FE_QPSK,
1439 .frequency_min = 950000,
1440 .frequency_max = 2150000,
1441 .frequency_stepsize = 1011, /* kHz for QPSK frontends */
1442 .frequency_tolerance = 5000,
1443 .symbol_rate_min = 1000000,
1444 .symbol_rate_max = 45000000,
1445 .caps = FE_CAN_INVERSION_AUTO |
1446 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
1447 FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
1448 FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
1449 FE_CAN_QPSK | FE_CAN_RECOVER
1450 },
1451
1452 .release = cx24116_release,
1453
1454 .init = cx24116_initfe,
Darron Broad490c8682008-09-13 19:42:16 -03001455 .sleep = cx24116_sleep,
Steven Toth0d467482008-09-04 01:14:43 -03001456 .read_status = cx24116_read_status,
1457 .read_ber = cx24116_read_ber,
1458 .read_signal_strength = cx24116_read_signal_strength,
1459 .read_snr = cx24116_read_snr,
1460 .read_ucblocks = cx24116_read_ucblocks,
1461 .set_tone = cx24116_set_tone,
1462 .set_voltage = cx24116_set_voltage,
1463 .diseqc_send_master_cmd = cx24116_send_diseqc_msg,
1464 .diseqc_send_burst = cx24116_diseqc_send_burst,
1465
1466 .set_property = cx24116_set_property,
Steven Tothbfbf2da2008-09-12 01:37:37 -03001467 .get_property = cx24116_get_property,
Steven Toth0d467482008-09-04 01:14:43 -03001468 .set_frontend = cx24116_set_frontend,
1469};
1470
Steven Toth0d467482008-09-04 01:14:43 -03001471MODULE_DESCRIPTION("DVB Frontend module for Conexant cx24116/cx24118 hardware");
1472MODULE_AUTHOR("Steven Toth");
1473MODULE_LICENSE("GPL");
1474