blob: 8814f36d53fb8e33ca70aa995943381ac7e7b5d1 [file] [log] [blame]
Steven Toth0d467482008-09-04 01:14:43 -03001/*
2 Conexant cx24116/cx24118 - DVBS/S2 Satellite demod/tuner driver
3
4 Copyright (C) 2006-2008 Steven Toth <stoth@hauppauge.com>
Darron Broad490c8682008-09-13 19:42:16 -03005 Copyright (C) 2006-2007 Georg Acher
6 Copyright (C) 2007-2008 Darron Broad
7 March 2007
8 Fixed some bugs.
9 Added diseqc support.
10 Added corrected signal strength support.
11 August 2007
12 Sync with legacy version.
13 Some clean ups.
14 Copyright (C) 2008 Igor Liplianin
15 September, 9th 2008
Igor M. Liplianinc063a482008-09-14 07:43:53 -030016 Fixed locking on high symbol rates (>30000).
17 Implement MPEG initialization parameter.
Igor M. Liplianinc7bdcd02009-01-17 10:16:36 -030018 January, 17th 2009
19 Fill set_voltage with actually control voltage code.
20 Correct set tone to not affect voltage.
Steven Toth0d467482008-09-04 01:14:43 -030021
22 This program is free software; you can redistribute it and/or modify
23 it under the terms of the GNU General Public License as published by
24 the Free Software Foundation; either version 2 of the License, or
25 (at your option) any later version.
26
27 This program is distributed in the hope that it will be useful,
28 but WITHOUT ANY WARRANTY; without even the implied warranty of
29 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 GNU General Public License for more details.
31
32 You should have received a copy of the GNU General Public License
33 along with this program; if not, write to the Free Software
34 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35*/
36
Steven Toth0d467482008-09-04 01:14:43 -030037#include <linux/slab.h>
38#include <linux/kernel.h>
39#include <linux/module.h>
40#include <linux/moduleparam.h>
41#include <linux/init.h>
42#include <linux/firmware.h>
43
44#include "dvb_frontend.h"
45#include "cx24116.h"
46
Steven Tothf11ec7d2008-10-16 20:22:01 -030047static int debug;
48module_param(debug, int, 0644);
49MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
50
Darron Broad490c8682008-09-13 19:42:16 -030051#define dprintk(args...) \
52 do { \
Steven Tothf11ec7d2008-10-16 20:22:01 -030053 if (debug) \
Steven Toth98c94822008-10-16 20:24:42 -030054 printk(KERN_INFO "cx24116: " args); \
Darron Broad490c8682008-09-13 19:42:16 -030055 } while (0)
56
Steven Toth0d467482008-09-04 01:14:43 -030057#define CX24116_DEFAULT_FIRMWARE "dvb-fe-cx24116.fw"
58#define CX24116_SEARCH_RANGE_KHZ 5000
59
Darron Broad490c8682008-09-13 19:42:16 -030060/* known registers */
61#define CX24116_REG_COMMAND (0x00) /* command args 0x00..0x1e */
62#define CX24116_REG_EXECUTE (0x1f) /* execute command */
63#define CX24116_REG_MAILBOX (0x96) /* FW or multipurpose mailbox? */
64#define CX24116_REG_RESET (0x20) /* reset status > 0 */
65#define CX24116_REG_SIGNAL (0x9e) /* signal low */
66#define CX24116_REG_SSTATUS (0x9d) /* signal high / status */
Steven Toth8953db72008-10-06 21:20:21 -030067#define CX24116_REG_QUALITY8 (0xa3)
Darron Broad490c8682008-09-13 19:42:16 -030068#define CX24116_REG_QSTATUS (0xbc)
Steven Toth8953db72008-10-06 21:20:21 -030069#define CX24116_REG_QUALITY0 (0xd5)
Darron Broad490c8682008-09-13 19:42:16 -030070#define CX24116_REG_BER0 (0xc9)
71#define CX24116_REG_BER8 (0xc8)
72#define CX24116_REG_BER16 (0xc7)
73#define CX24116_REG_BER24 (0xc6)
74#define CX24116_REG_UCB0 (0xcb)
75#define CX24116_REG_UCB8 (0xca)
76#define CX24116_REG_CLKDIV (0xf3)
77#define CX24116_REG_RATEDIV (0xf9)
Steven Toth98c94822008-10-16 20:24:42 -030078
79/* configured fec (not tuned) or actual FEC (tuned) 1=1/2 2=2/3 etc */
80#define CX24116_REG_FECSTATUS (0x9c)
Darron Broad681faa02008-09-22 00:47:20 -030081
82/* FECSTATUS bits */
Steven Toth98c94822008-10-16 20:24:42 -030083/* mask to determine configured fec (not tuned) or actual fec (tuned) */
84#define CX24116_FEC_FECMASK (0x1f)
85
86/* Select DVB-S demodulator, else DVB-S2 */
87#define CX24116_FEC_DVBS (0x20)
Darron Broad681faa02008-09-22 00:47:20 -030088#define CX24116_FEC_UNKNOWN (0x40) /* Unknown/unused */
Steven Toth98c94822008-10-16 20:24:42 -030089
90/* Pilot mode requested when tuning else always reset when tuned */
91#define CX24116_FEC_PILOT (0x80)
Steven Toth0d467482008-09-04 01:14:43 -030092
93/* arg buffer size */
94#define CX24116_ARGLEN (0x1e)
95
Darron Broad490c8682008-09-13 19:42:16 -030096/* rolloff */
97#define CX24116_ROLLOFF_020 (0x00)
98#define CX24116_ROLLOFF_025 (0x01)
99#define CX24116_ROLLOFF_035 (0x02)
100
101/* pilot bit */
Darron Broad01a8f032008-10-03 11:47:46 -0300102#define CX24116_PILOT_OFF (0x00)
103#define CX24116_PILOT_ON (0x40)
Darron Broad490c8682008-09-13 19:42:16 -0300104
105/* signal status */
106#define CX24116_HAS_SIGNAL (0x01)
107#define CX24116_HAS_CARRIER (0x02)
108#define CX24116_HAS_VITERBI (0x04)
109#define CX24116_HAS_SYNCLOCK (0x08)
110#define CX24116_HAS_UNKNOWN1 (0x10)
111#define CX24116_HAS_UNKNOWN2 (0x20)
Darron Broad6639f1e2008-12-18 06:28:18 -0300112#define CX24116_STATUS_MASK (0x0f)
Darron Broad490c8682008-09-13 19:42:16 -0300113#define CX24116_SIGNAL_MASK (0xc0)
114
115#define CX24116_DISEQC_TONEOFF (0) /* toneburst never sent */
116#define CX24116_DISEQC_TONECACHE (1) /* toneburst cached */
117#define CX24116_DISEQC_MESGCACHE (2) /* message cached */
118
Steven Toth0d467482008-09-04 01:14:43 -0300119/* arg offset for DiSEqC */
120#define CX24116_DISEQC_BURST (1)
121#define CX24116_DISEQC_ARG2_2 (2) /* unknown value=2 */
122#define CX24116_DISEQC_ARG3_0 (3) /* unknown value=0 */
123#define CX24116_DISEQC_ARG4_0 (4) /* unknown value=0 */
124#define CX24116_DISEQC_MSGLEN (5)
125#define CX24116_DISEQC_MSGOFS (6)
126
127/* DiSEqC burst */
128#define CX24116_DISEQC_MINI_A (0)
129#define CX24116_DISEQC_MINI_B (1)
130
Darron Broad490c8682008-09-13 19:42:16 -0300131/* DiSEqC tone burst */
132static int toneburst = 1;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300133module_param(toneburst, int, 0644);
Steven Toth98c94822008-10-16 20:24:42 -0300134MODULE_PARM_DESC(toneburst, "DiSEqC toneburst 0=OFF, 1=TONE CACHE, "\
135 "2=MESSAGE CACHE (default:1)");
Darron Broad490c8682008-09-13 19:42:16 -0300136
Steven Toth8953db72008-10-06 21:20:21 -0300137/* SNR measurements */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300138static int esno_snr;
139module_param(esno_snr, int, 0644);
Hans Petter Selasky53f1fe92011-03-28 14:37:36 -0300140MODULE_PARM_DESC(esno_snr, "SNR return units, 0=PERCENTAGE 0-100, "\
Steven Toth98c94822008-10-16 20:24:42 -0300141 "1=ESNO(db * 10) (default:0)");
Steven Toth8953db72008-10-06 21:20:21 -0300142
Steven Tothf11ec7d2008-10-16 20:22:01 -0300143enum cmds {
Darron Broad490c8682008-09-13 19:42:16 -0300144 CMD_SET_VCO = 0x10,
Steven Toth0d467482008-09-04 01:14:43 -0300145 CMD_TUNEREQUEST = 0x11,
Darron Broad490c8682008-09-13 19:42:16 -0300146 CMD_MPEGCONFIG = 0x13,
147 CMD_TUNERINIT = 0x14,
148 CMD_BANDWIDTH = 0x15,
149 CMD_GETAGC = 0x19,
150 CMD_LNBCONFIG = 0x20,
151 CMD_LNBSEND = 0x21, /* Formerly CMD_SEND_DISEQC */
Igor M. Liplianinc7bdcd02009-01-17 10:16:36 -0300152 CMD_LNBDCLEVEL = 0x22,
Steven Toth0d467482008-09-04 01:14:43 -0300153 CMD_SET_TONE = 0x23,
Darron Broad490c8682008-09-13 19:42:16 -0300154 CMD_UPDFWVERS = 0x35,
155 CMD_TUNERSLEEP = 0x36,
156 CMD_AGCCONTROL = 0x3b, /* Unknown */
Steven Toth0d467482008-09-04 01:14:43 -0300157};
158
159/* The Demod/Tuner can't easily provide these, we cache them */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300160struct cx24116_tuning {
Steven Toth0d467482008-09-04 01:14:43 -0300161 u32 frequency;
162 u32 symbol_rate;
Mauro Carvalho Chehab0df289a2015-06-07 14:53:52 -0300163 enum fe_spectral_inversion inversion;
164 enum fe_code_rate fec;
Steven Toth0d467482008-09-04 01:14:43 -0300165
Mauro Carvalho Chehab0df289a2015-06-07 14:53:52 -0300166 enum fe_delivery_system delsys;
167 enum fe_modulation modulation;
168 enum fe_pilot pilot;
169 enum fe_rolloff rolloff;
Steven Toth0d467482008-09-04 01:14:43 -0300170
171 /* Demod values */
172 u8 fec_val;
173 u8 fec_mask;
174 u8 inversion_val;
Darron Broad01a8f032008-10-03 11:47:46 -0300175 u8 pilot_val;
Darron Broad490c8682008-09-13 19:42:16 -0300176 u8 rolloff_val;
Steven Toth0d467482008-09-04 01:14:43 -0300177};
178
179/* Basic commands that are sent to the firmware */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300180struct cx24116_cmd {
Steven Toth0d467482008-09-04 01:14:43 -0300181 u8 len;
182 u8 args[CX24116_ARGLEN];
183};
184
Steven Tothf11ec7d2008-10-16 20:22:01 -0300185struct cx24116_state {
186 struct i2c_adapter *i2c;
187 const struct cx24116_config *config;
Steven Toth0d467482008-09-04 01:14:43 -0300188
189 struct dvb_frontend frontend;
190
191 struct cx24116_tuning dcur;
192 struct cx24116_tuning dnxt;
193
194 u8 skip_fw_load;
195 u8 burst;
Darron Broad490c8682008-09-13 19:42:16 -0300196 struct cx24116_cmd dsec_cmd;
Steven Toth0d467482008-09-04 01:14:43 -0300197};
198
Steven Tothf11ec7d2008-10-16 20:22:01 -0300199static int cx24116_writereg(struct cx24116_state *state, int reg, int data)
Steven Toth0d467482008-09-04 01:14:43 -0300200{
201 u8 buf[] = { reg, data };
202 struct i2c_msg msg = { .addr = state->config->demod_address,
203 .flags = 0, .buf = buf, .len = 2 };
204 int err;
205
Steven Tothf11ec7d2008-10-16 20:22:01 -0300206 if (debug > 1)
Steven Toth0d467482008-09-04 01:14:43 -0300207 printk("cx24116: %s: write reg 0x%02x, value 0x%02x\n",
Steven Tothf11ec7d2008-10-16 20:22:01 -0300208 __func__, reg, data);
Steven Toth0d467482008-09-04 01:14:43 -0300209
Steven Tothf11ec7d2008-10-16 20:22:01 -0300210 err = i2c_transfer(state->i2c, &msg, 1);
211 if (err != 1) {
Steven Toth98c94822008-10-16 20:24:42 -0300212 printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x,"
Steven Toth0d467482008-09-04 01:14:43 -0300213 " value == 0x%02x)\n", __func__, err, reg, data);
214 return -EREMOTEIO;
215 }
216
217 return 0;
218}
219
220/* Bulk byte writes to a single I2C address, for 32k firmware load */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300221static int cx24116_writeregN(struct cx24116_state *state, int reg,
Geert Uytterhoeven64decbf2008-10-16 21:04:35 -0300222 const u8 *data, u16 len)
Steven Toth0d467482008-09-04 01:14:43 -0300223{
224 int ret = -EREMOTEIO;
225 struct i2c_msg msg;
226 u8 *buf;
227
228 buf = kmalloc(len + 1, GFP_KERNEL);
229 if (buf == NULL) {
230 printk("Unable to kmalloc\n");
231 ret = -ENOMEM;
232 goto error;
233 }
234
235 *(buf) = reg;
236 memcpy(buf + 1, data, len);
237
238 msg.addr = state->config->demod_address;
239 msg.flags = 0;
240 msg.buf = buf;
241 msg.len = len + 1;
242
Steven Tothf11ec7d2008-10-16 20:22:01 -0300243 if (debug > 1)
Steven Toth98c94822008-10-16 20:24:42 -0300244 printk(KERN_INFO "cx24116: %s: write regN 0x%02x, len = %d\n",
Steven Tothf11ec7d2008-10-16 20:22:01 -0300245 __func__, reg, len);
Steven Toth0d467482008-09-04 01:14:43 -0300246
Steven Tothf11ec7d2008-10-16 20:22:01 -0300247 ret = i2c_transfer(state->i2c, &msg, 1);
248 if (ret != 1) {
Steven Toth98c94822008-10-16 20:24:42 -0300249 printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x\n",
Steven Toth0d467482008-09-04 01:14:43 -0300250 __func__, ret, reg);
251 ret = -EREMOTEIO;
252 }
253
254error:
255 kfree(buf);
256
257 return ret;
258}
259
Steven Tothf11ec7d2008-10-16 20:22:01 -0300260static int cx24116_readreg(struct cx24116_state *state, u8 reg)
Steven Toth0d467482008-09-04 01:14:43 -0300261{
262 int ret;
263 u8 b0[] = { reg };
264 u8 b1[] = { 0 };
265 struct i2c_msg msg[] = {
Steven Tothf11ec7d2008-10-16 20:22:01 -0300266 { .addr = state->config->demod_address, .flags = 0,
267 .buf = b0, .len = 1 },
268 { .addr = state->config->demod_address, .flags = I2C_M_RD,
269 .buf = b1, .len = 1 }
Steven Toth0d467482008-09-04 01:14:43 -0300270 };
271
272 ret = i2c_transfer(state->i2c, msg, 2);
273
274 if (ret != 2) {
Steven Toth98c94822008-10-16 20:24:42 -0300275 printk(KERN_ERR "%s: reg=0x%x (error=%d)\n",
276 __func__, reg, ret);
Steven Toth0d467482008-09-04 01:14:43 -0300277 return ret;
278 }
279
Steven Tothf11ec7d2008-10-16 20:22:01 -0300280 if (debug > 1)
Steven Toth98c94822008-10-16 20:24:42 -0300281 printk(KERN_INFO "cx24116: read reg 0x%02x, value 0x%02x\n",
Steven Tothf11ec7d2008-10-16 20:22:01 -0300282 reg, b1[0]);
Steven Toth0d467482008-09-04 01:14:43 -0300283
284 return b1[0];
285}
286
Steven Toth98c94822008-10-16 20:24:42 -0300287static int cx24116_set_inversion(struct cx24116_state *state,
Mauro Carvalho Chehab0df289a2015-06-07 14:53:52 -0300288 enum fe_spectral_inversion inversion)
Steven Toth0d467482008-09-04 01:14:43 -0300289{
290 dprintk("%s(%d)\n", __func__, inversion);
291
292 switch (inversion) {
293 case INVERSION_OFF:
294 state->dnxt.inversion_val = 0x00;
295 break;
296 case INVERSION_ON:
297 state->dnxt.inversion_val = 0x04;
298 break;
299 case INVERSION_AUTO:
300 state->dnxt.inversion_val = 0x0C;
301 break;
302 default:
303 return -EINVAL;
304 }
305
306 state->dnxt.inversion = inversion;
307
308 return 0;
309}
310
Darron Broad490c8682008-09-13 19:42:16 -0300311/*
312 * modfec (modulation and FEC)
313 * ===========================
314 *
315 * MOD FEC mask/val standard
316 * ---- -------- ----------- --------
317 * QPSK FEC_1_2 0x02 0x02+X DVB-S
318 * QPSK FEC_2_3 0x04 0x02+X DVB-S
319 * QPSK FEC_3_4 0x08 0x02+X DVB-S
320 * QPSK FEC_4_5 0x10 0x02+X DVB-S (?)
321 * QPSK FEC_5_6 0x20 0x02+X DVB-S
322 * QPSK FEC_6_7 0x40 0x02+X DVB-S
323 * QPSK FEC_7_8 0x80 0x02+X DVB-S
324 * QPSK FEC_8_9 0x01 0x02+X DVB-S (?) (NOT SUPPORTED?)
325 * QPSK AUTO 0xff 0x02+X DVB-S
326 *
327 * For DVB-S high byte probably represents FEC
328 * and low byte selects the modulator. The high
329 * byte is search range mask. Bit 5 may turn
330 * on DVB-S and remaining bits represent some
331 * kind of calibration (how/what i do not know).
332 *
333 * Eg.(2/3) szap "Zone Horror"
334 *
335 * mask/val = 0x04, 0x20
Steven Toth98c94822008-10-16 20:24:42 -0300336 * status 1f | signal c3c0 | snr a333 | ber 00000098 | unc 0 | FE_HAS_LOCK
Darron Broad490c8682008-09-13 19:42:16 -0300337 *
338 * mask/val = 0x04, 0x30
Steven Toth98c94822008-10-16 20:24:42 -0300339 * status 1f | signal c3c0 | snr a333 | ber 00000000 | unc 0 | FE_HAS_LOCK
Darron Broad490c8682008-09-13 19:42:16 -0300340 *
341 * After tuning FECSTATUS contains actual FEC
342 * in use numbered 1 through to 8 for 1/2 .. 2/3 etc
343 *
344 * NBC=NOT/NON BACKWARD COMPATIBLE WITH DVB-S (DVB-S2 only)
345 *
346 * NBC-QPSK FEC_1_2 0x00, 0x04 DVB-S2
347 * NBC-QPSK FEC_3_5 0x00, 0x05 DVB-S2
348 * NBC-QPSK FEC_2_3 0x00, 0x06 DVB-S2
349 * NBC-QPSK FEC_3_4 0x00, 0x07 DVB-S2
350 * NBC-QPSK FEC_4_5 0x00, 0x08 DVB-S2
351 * NBC-QPSK FEC_5_6 0x00, 0x09 DVB-S2
352 * NBC-QPSK FEC_8_9 0x00, 0x0a DVB-S2
353 * NBC-QPSK FEC_9_10 0x00, 0x0b DVB-S2
354 *
355 * NBC-8PSK FEC_3_5 0x00, 0x0c DVB-S2
356 * NBC-8PSK FEC_2_3 0x00, 0x0d DVB-S2
357 * NBC-8PSK FEC_3_4 0x00, 0x0e DVB-S2
358 * NBC-8PSK FEC_5_6 0x00, 0x0f DVB-S2
359 * NBC-8PSK FEC_8_9 0x00, 0x10 DVB-S2
360 * NBC-8PSK FEC_9_10 0x00, 0x11 DVB-S2
361 *
362 * For DVB-S2 low bytes selects both modulator
363 * and FEC. High byte is meaningless here. To
364 * set pilot, bit 6 (0x40) is set. When inspecting
365 * FECSTATUS bit 7 (0x80) represents the pilot
366 * selection whilst not tuned. When tuned, actual FEC
367 * in use is found in FECSTATUS as per above. Pilot
368 * value is reset.
369 */
370
Steven Toth0d467482008-09-04 01:14:43 -0300371/* A table of modulation, fec and configuration bytes for the demod.
372 * Not all S2 mmodulation schemes are support and not all rates with
373 * a scheme are support. Especially, no auto detect when in S2 mode.
374 */
Mauro Carvalho Chehabffbc5f82009-01-05 01:34:20 -0300375static struct cx24116_modfec {
Mauro Carvalho Chehab0df289a2015-06-07 14:53:52 -0300376 enum fe_delivery_system delivery_system;
377 enum fe_modulation modulation;
378 enum fe_code_rate fec;
Steven Toth0d467482008-09-04 01:14:43 -0300379 u8 mask; /* In DVBS mode this is used to autodetect */
380 u8 val; /* Passed to the firmware to indicate mode selection */
381} CX24116_MODFEC_MODES[] = {
382 /* QPSK. For unknown rates we set hardware to auto detect 0xfe 0x30 */
Darron Broad490c8682008-09-13 19:42:16 -0300383
384 /*mod fec mask val */
Steven Toth0a6393a2008-10-06 21:06:48 -0300385 { SYS_DVBS, QPSK, FEC_NONE, 0xfe, 0x30 },
386 { SYS_DVBS, QPSK, FEC_1_2, 0x02, 0x2e }, /* 00000010 00101110 */
387 { SYS_DVBS, QPSK, FEC_2_3, 0x04, 0x2f }, /* 00000100 00101111 */
388 { SYS_DVBS, QPSK, FEC_3_4, 0x08, 0x30 }, /* 00001000 00110000 */
389 { SYS_DVBS, QPSK, FEC_4_5, 0xfe, 0x30 }, /* 000?0000 ? */
390 { SYS_DVBS, QPSK, FEC_5_6, 0x20, 0x31 }, /* 00100000 00110001 */
391 { SYS_DVBS, QPSK, FEC_6_7, 0xfe, 0x30 }, /* 0?000000 ? */
392 { SYS_DVBS, QPSK, FEC_7_8, 0x80, 0x32 }, /* 10000000 00110010 */
393 { SYS_DVBS, QPSK, FEC_8_9, 0xfe, 0x30 }, /* 0000000? ? */
394 { SYS_DVBS, QPSK, FEC_AUTO, 0xfe, 0x30 },
Steven Toth0d467482008-09-04 01:14:43 -0300395 /* NBC-QPSK */
Steven Toth0a6393a2008-10-06 21:06:48 -0300396 { SYS_DVBS2, QPSK, FEC_1_2, 0x00, 0x04 },
397 { SYS_DVBS2, QPSK, FEC_3_5, 0x00, 0x05 },
398 { SYS_DVBS2, QPSK, FEC_2_3, 0x00, 0x06 },
399 { SYS_DVBS2, QPSK, FEC_3_4, 0x00, 0x07 },
400 { SYS_DVBS2, QPSK, FEC_4_5, 0x00, 0x08 },
401 { SYS_DVBS2, QPSK, FEC_5_6, 0x00, 0x09 },
402 { SYS_DVBS2, QPSK, FEC_8_9, 0x00, 0x0a },
403 { SYS_DVBS2, QPSK, FEC_9_10, 0x00, 0x0b },
Steven Toth0d467482008-09-04 01:14:43 -0300404 /* 8PSK */
Steven Toth0a6393a2008-10-06 21:06:48 -0300405 { SYS_DVBS2, PSK_8, FEC_3_5, 0x00, 0x0c },
406 { SYS_DVBS2, PSK_8, FEC_2_3, 0x00, 0x0d },
407 { SYS_DVBS2, PSK_8, FEC_3_4, 0x00, 0x0e },
408 { SYS_DVBS2, PSK_8, FEC_5_6, 0x00, 0x0f },
409 { SYS_DVBS2, PSK_8, FEC_8_9, 0x00, 0x10 },
410 { SYS_DVBS2, PSK_8, FEC_9_10, 0x00, 0x11 },
Darron Broad490c8682008-09-13 19:42:16 -0300411 /*
412 * `val' can be found in the FECSTATUS register when tuning.
413 * FECSTATUS will give the actual FEC in use if tuning was successful.
414 */
Steven Toth0d467482008-09-04 01:14:43 -0300415};
416
Steven Tothf11ec7d2008-10-16 20:22:01 -0300417static int cx24116_lookup_fecmod(struct cx24116_state *state,
Mauro Carvalho Chehab0df289a2015-06-07 14:53:52 -0300418 enum fe_delivery_system d, enum fe_modulation m, enum fe_code_rate f)
Steven Toth0d467482008-09-04 01:14:43 -0300419{
420 int i, ret = -EOPNOTSUPP;
421
Darron Broad490c8682008-09-13 19:42:16 -0300422 dprintk("%s(0x%02x,0x%02x)\n", __func__, m, f);
423
Steven Tothf11ec7d2008-10-16 20:22:01 -0300424 for (i = 0; i < ARRAY_SIZE(CX24116_MODFEC_MODES); i++) {
Darron Broad35694762008-12-18 06:21:51 -0300425 if ((d == CX24116_MODFEC_MODES[i].delivery_system) &&
426 (m == CX24116_MODFEC_MODES[i].modulation) &&
Steven Tothf11ec7d2008-10-16 20:22:01 -0300427 (f == CX24116_MODFEC_MODES[i].fec)) {
Steven Toth0d467482008-09-04 01:14:43 -0300428 ret = i;
429 break;
430 }
431 }
432
433 return ret;
434}
435
Steven Toth98c94822008-10-16 20:24:42 -0300436static int cx24116_set_fec(struct cx24116_state *state,
Mauro Carvalho Chehab0df289a2015-06-07 14:53:52 -0300437 enum fe_delivery_system delsys,
438 enum fe_modulation mod,
439 enum fe_code_rate fec)
Steven Toth0d467482008-09-04 01:14:43 -0300440{
441 int ret = 0;
Darron Broad490c8682008-09-13 19:42:16 -0300442
443 dprintk("%s(0x%02x,0x%02x)\n", __func__, mod, fec);
Steven Toth0d467482008-09-04 01:14:43 -0300444
Darron Broad35694762008-12-18 06:21:51 -0300445 ret = cx24116_lookup_fecmod(state, delsys, mod, fec);
Steven Toth0d467482008-09-04 01:14:43 -0300446
Steven Tothf11ec7d2008-10-16 20:22:01 -0300447 if (ret < 0)
Steven Toth0d467482008-09-04 01:14:43 -0300448 return ret;
449
Darron Broad490c8682008-09-13 19:42:16 -0300450 state->dnxt.fec = fec;
Steven Toth0d467482008-09-04 01:14:43 -0300451 state->dnxt.fec_val = CX24116_MODFEC_MODES[ret].val;
452 state->dnxt.fec_mask = CX24116_MODFEC_MODES[ret].mask;
Darron Broad490c8682008-09-13 19:42:16 -0300453 dprintk("%s() mask/val = 0x%02x/0x%02x\n", __func__,
454 state->dnxt.fec_mask, state->dnxt.fec_val);
Steven Toth0d467482008-09-04 01:14:43 -0300455
456 return 0;
457}
458
Steven Tothf11ec7d2008-10-16 20:22:01 -0300459static int cx24116_set_symbolrate(struct cx24116_state *state, u32 rate)
Steven Toth0d467482008-09-04 01:14:43 -0300460{
Darron Broad490c8682008-09-13 19:42:16 -0300461 dprintk("%s(%d)\n", __func__, rate);
Steven Toth0d467482008-09-04 01:14:43 -0300462
463 /* check if symbol rate is within limits */
Darron Broad490c8682008-09-13 19:42:16 -0300464 if ((rate > state->frontend.ops.info.symbol_rate_max) ||
465 (rate < state->frontend.ops.info.symbol_rate_min)) {
466 dprintk("%s() unsupported symbol_rate = %d\n", __func__, rate);
467 return -EOPNOTSUPP;
468 }
Steven Toth0d467482008-09-04 01:14:43 -0300469
Darron Broad490c8682008-09-13 19:42:16 -0300470 state->dnxt.symbol_rate = rate;
471 dprintk("%s() symbol_rate = %d\n", __func__, rate);
472
473 return 0;
Steven Toth0d467482008-09-04 01:14:43 -0300474}
475
Steven Tothf11ec7d2008-10-16 20:22:01 -0300476static int cx24116_load_firmware(struct dvb_frontend *fe,
477 const struct firmware *fw);
Steven Toth0d467482008-09-04 01:14:43 -0300478
Steven Tothf11ec7d2008-10-16 20:22:01 -0300479static int cx24116_firmware_ondemand(struct dvb_frontend *fe)
Steven Toth0d467482008-09-04 01:14:43 -0300480{
481 struct cx24116_state *state = fe->demodulator_priv;
482 const struct firmware *fw;
483 int ret = 0;
484
Steven Tothf11ec7d2008-10-16 20:22:01 -0300485 dprintk("%s()\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -0300486
Steven Tothf11ec7d2008-10-16 20:22:01 -0300487 if (cx24116_readreg(state, 0x20) > 0) {
Steven Toth0d467482008-09-04 01:14:43 -0300488
489 if (state->skip_fw_load)
490 return 0;
491
492 /* Load firmware */
Steven Toth98c94822008-10-16 20:24:42 -0300493 /* request the firmware, this will block until loaded */
494 printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n",
495 __func__, CX24116_DEFAULT_FIRMWARE);
496 ret = request_firmware(&fw, CX24116_DEFAULT_FIRMWARE,
Jean Delvaree9785252009-04-26 05:43:59 -0300497 state->i2c->dev.parent);
Steven Toth98c94822008-10-16 20:24:42 -0300498 printk(KERN_INFO "%s: Waiting for firmware upload(2)...\n",
499 __func__);
Steven Toth0d467482008-09-04 01:14:43 -0300500 if (ret) {
Steven Toth98c94822008-10-16 20:24:42 -0300501 printk(KERN_ERR "%s: No firmware uploaded "
502 "(timeout or file not found?)\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -0300503 return ret;
504 }
505
Steven Toth98c94822008-10-16 20:24:42 -0300506 /* Make sure we don't recurse back through here
507 * during loading */
Steven Toth0d467482008-09-04 01:14:43 -0300508 state->skip_fw_load = 1;
509
510 ret = cx24116_load_firmware(fe, fw);
511 if (ret)
Steven Toth98c94822008-10-16 20:24:42 -0300512 printk(KERN_ERR "%s: Writing firmware to device failed\n",
513 __func__);
Steven Toth0d467482008-09-04 01:14:43 -0300514
515 release_firmware(fw);
516
Steven Toth98c94822008-10-16 20:24:42 -0300517 printk(KERN_INFO "%s: Firmware upload %s\n", __func__,
518 ret == 0 ? "complete" : "failed");
Steven Toth0d467482008-09-04 01:14:43 -0300519
520 /* Ensure firmware is always loaded if required */
521 state->skip_fw_load = 0;
522 }
523
524 return ret;
525}
526
Steven Toth98c94822008-10-16 20:24:42 -0300527/* Take a basic firmware command structure, format it
528 * and forward it for processing
529 */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300530static int cx24116_cmd_execute(struct dvb_frontend *fe, struct cx24116_cmd *cmd)
Steven Toth0d467482008-09-04 01:14:43 -0300531{
532 struct cx24116_state *state = fe->demodulator_priv;
533 int i, ret;
534
535 dprintk("%s()\n", __func__);
536
537 /* Load the firmware if required */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300538 ret = cx24116_firmware_ondemand(fe);
539 if (ret != 0) {
Steven Toth98c94822008-10-16 20:24:42 -0300540 printk(KERN_ERR "%s(): Unable initialise the firmware\n",
541 __func__);
Steven Toth0d467482008-09-04 01:14:43 -0300542 return ret;
543 }
544
545 /* Write the command */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300546 for (i = 0; i < cmd->len ; i++) {
Steven Toth0d467482008-09-04 01:14:43 -0300547 dprintk("%s: 0x%02x == 0x%02x\n", __func__, i, cmd->args[i]);
548 cx24116_writereg(state, i, cmd->args[i]);
549 }
550
551 /* Start execution and wait for cmd to terminate */
Darron Broad490c8682008-09-13 19:42:16 -0300552 cx24116_writereg(state, CX24116_REG_EXECUTE, 0x01);
Steven Tothf11ec7d2008-10-16 20:22:01 -0300553 while (cx24116_readreg(state, CX24116_REG_EXECUTE)) {
Steven Toth0d467482008-09-04 01:14:43 -0300554 msleep(10);
Steven Tothf11ec7d2008-10-16 20:22:01 -0300555 if (i++ > 64) {
Steven Toth98c94822008-10-16 20:24:42 -0300556 /* Avoid looping forever if the firmware does
557 not respond */
558 printk(KERN_WARNING "%s() Firmware not responding\n",
559 __func__);
Steven Toth0d467482008-09-04 01:14:43 -0300560 return -EREMOTEIO;
561 }
562 }
563 return 0;
564}
565
Steven Tothf11ec7d2008-10-16 20:22:01 -0300566static int cx24116_load_firmware(struct dvb_frontend *fe,
567 const struct firmware *fw)
Steven Toth0d467482008-09-04 01:14:43 -0300568{
Steven Tothf11ec7d2008-10-16 20:22:01 -0300569 struct cx24116_state *state = fe->demodulator_priv;
Steven Toth0d467482008-09-04 01:14:43 -0300570 struct cx24116_cmd cmd;
Antti Palosaarie0bae9b2011-05-04 17:23:09 -0300571 int i, ret, len, max, remaining;
Darron Broad490c8682008-09-13 19:42:16 -0300572 unsigned char vers[4];
Steven Toth0d467482008-09-04 01:14:43 -0300573
574 dprintk("%s\n", __func__);
Steven Tothf11ec7d2008-10-16 20:22:01 -0300575 dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n",
576 fw->size,
577 fw->data[0],
578 fw->data[1],
579 fw->data[fw->size-2],
580 fw->data[fw->size-1]);
Steven Toth0d467482008-09-04 01:14:43 -0300581
582 /* Toggle 88x SRST pin to reset demod */
583 if (state->config->reset_device)
584 state->config->reset_device(fe);
585
586 /* Begin the firmware load process */
587 /* Prepare the demod, load the firmware, cleanup after load */
Steven Toth0d467482008-09-04 01:14:43 -0300588
Darron Broad490c8682008-09-13 19:42:16 -0300589 /* Init PLL */
590 cx24116_writereg(state, 0xE5, 0x00);
591 cx24116_writereg(state, 0xF1, 0x08);
592 cx24116_writereg(state, 0xF2, 0x13);
593
594 /* Start PLL */
595 cx24116_writereg(state, 0xe0, 0x03);
596 cx24116_writereg(state, 0xe0, 0x00);
597
598 /* Unknown */
599 cx24116_writereg(state, CX24116_REG_CLKDIV, 0x46);
600 cx24116_writereg(state, CX24116_REG_RATEDIV, 0x00);
601
602 /* Unknown */
Steven Toth0d467482008-09-04 01:14:43 -0300603 cx24116_writereg(state, 0xF0, 0x03);
604 cx24116_writereg(state, 0xF4, 0x81);
605 cx24116_writereg(state, 0xF5, 0x00);
606 cx24116_writereg(state, 0xF6, 0x00);
607
Antti Palosaari107d7b12011-04-27 21:03:07 -0300608 /* Split firmware to the max I2C write len and write.
Antti Palosaarie0bae9b2011-05-04 17:23:09 -0300609 * Writes whole firmware as one write when i2c_wr_max is set to 0. */
610 if (state->config->i2c_wr_max)
611 max = state->config->i2c_wr_max;
612 else
613 max = INT_MAX; /* enough for 32k firmware */
Antti Palosaari107d7b12011-04-27 21:03:07 -0300614
Antti Palosaarie0bae9b2011-05-04 17:23:09 -0300615 for (remaining = fw->size; remaining > 0; remaining -= max - 1) {
Antti Palosaari107d7b12011-04-27 21:03:07 -0300616 len = remaining;
Antti Palosaarie0bae9b2011-05-04 17:23:09 -0300617 if (len > max - 1)
618 len = max - 1;
Antti Palosaari107d7b12011-04-27 21:03:07 -0300619
620 cx24116_writeregN(state, 0xF7, &fw->data[fw->size - remaining],
621 len);
622 }
Steven Toth0d467482008-09-04 01:14:43 -0300623
624 cx24116_writereg(state, 0xF4, 0x10);
625 cx24116_writereg(state, 0xF0, 0x00);
626 cx24116_writereg(state, 0xF8, 0x06);
627
Darron Broad490c8682008-09-13 19:42:16 -0300628 /* Firmware CMD 10: VCO config */
629 cmd.args[0x00] = CMD_SET_VCO;
Steven Toth0d467482008-09-04 01:14:43 -0300630 cmd.args[0x01] = 0x05;
631 cmd.args[0x02] = 0xdc;
632 cmd.args[0x03] = 0xda;
633 cmd.args[0x04] = 0xae;
634 cmd.args[0x05] = 0xaa;
635 cmd.args[0x06] = 0x04;
636 cmd.args[0x07] = 0x9d;
637 cmd.args[0x08] = 0xfc;
638 cmd.args[0x09] = 0x06;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300639 cmd.len = 0x0a;
Steven Toth0d467482008-09-04 01:14:43 -0300640 ret = cx24116_cmd_execute(fe, &cmd);
641 if (ret != 0)
642 return ret;
643
Darron Broad490c8682008-09-13 19:42:16 -0300644 cx24116_writereg(state, CX24116_REG_SSTATUS, 0x00);
Steven Toth0d467482008-09-04 01:14:43 -0300645
Darron Broad490c8682008-09-13 19:42:16 -0300646 /* Firmware CMD 14: Tuner config */
647 cmd.args[0x00] = CMD_TUNERINIT;
Steven Toth0d467482008-09-04 01:14:43 -0300648 cmd.args[0x01] = 0x00;
649 cmd.args[0x02] = 0x00;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300650 cmd.len = 0x03;
Steven Toth0d467482008-09-04 01:14:43 -0300651 ret = cx24116_cmd_execute(fe, &cmd);
652 if (ret != 0)
653 return ret;
654
655 cx24116_writereg(state, 0xe5, 0x00);
656
Darron Broad490c8682008-09-13 19:42:16 -0300657 /* Firmware CMD 13: MPEG config */
658 cmd.args[0x00] = CMD_MPEGCONFIG;
Steven Toth0d467482008-09-04 01:14:43 -0300659 cmd.args[0x01] = 0x01;
660 cmd.args[0x02] = 0x75;
661 cmd.args[0x03] = 0x00;
Igor M. Liplianincc8c4f32008-09-09 13:57:47 -0300662 if (state->config->mpg_clk_pos_pol)
663 cmd.args[0x04] = state->config->mpg_clk_pos_pol;
664 else
665 cmd.args[0x04] = 0x02;
Steven Toth0d467482008-09-04 01:14:43 -0300666 cmd.args[0x05] = 0x00;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300667 cmd.len = 0x06;
Steven Toth0d467482008-09-04 01:14:43 -0300668 ret = cx24116_cmd_execute(fe, &cmd);
669 if (ret != 0)
670 return ret;
671
Darron Broad490c8682008-09-13 19:42:16 -0300672 /* Firmware CMD 35: Get firmware version */
673 cmd.args[0x00] = CMD_UPDFWVERS;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300674 cmd.len = 0x02;
675 for (i = 0; i < 4; i++) {
Darron Broad490c8682008-09-13 19:42:16 -0300676 cmd.args[0x01] = i;
677 ret = cx24116_cmd_execute(fe, &cmd);
678 if (ret != 0)
679 return ret;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300680 vers[i] = cx24116_readreg(state, CX24116_REG_MAILBOX);
Darron Broad490c8682008-09-13 19:42:16 -0300681 }
Steven Toth98c94822008-10-16 20:24:42 -0300682 printk(KERN_INFO "%s: FW version %i.%i.%i.%i\n", __func__,
Darron Broad490c8682008-09-13 19:42:16 -0300683 vers[0], vers[1], vers[2], vers[3]);
684
Steven Toth0d467482008-09-04 01:14:43 -0300685 return 0;
686}
687
Mauro Carvalho Chehab0df289a2015-06-07 14:53:52 -0300688static int cx24116_read_status(struct dvb_frontend *fe, enum fe_status *status)
Steven Toth0d467482008-09-04 01:14:43 -0300689{
690 struct cx24116_state *state = fe->demodulator_priv;
691
Darron Broad6639f1e2008-12-18 06:28:18 -0300692 int lock = cx24116_readreg(state, CX24116_REG_SSTATUS) &
693 CX24116_STATUS_MASK;
Steven Toth0d467482008-09-04 01:14:43 -0300694
695 dprintk("%s: status = 0x%02x\n", __func__, lock);
696
697 *status = 0;
698
Darron Broad490c8682008-09-13 19:42:16 -0300699 if (lock & CX24116_HAS_SIGNAL)
Steven Toth0d467482008-09-04 01:14:43 -0300700 *status |= FE_HAS_SIGNAL;
Darron Broad490c8682008-09-13 19:42:16 -0300701 if (lock & CX24116_HAS_CARRIER)
Steven Toth0d467482008-09-04 01:14:43 -0300702 *status |= FE_HAS_CARRIER;
Darron Broad490c8682008-09-13 19:42:16 -0300703 if (lock & CX24116_HAS_VITERBI)
Steven Toth0d467482008-09-04 01:14:43 -0300704 *status |= FE_HAS_VITERBI;
Darron Broad490c8682008-09-13 19:42:16 -0300705 if (lock & CX24116_HAS_SYNCLOCK)
Steven Toth0d467482008-09-04 01:14:43 -0300706 *status |= FE_HAS_SYNC | FE_HAS_LOCK;
707
708 return 0;
709}
710
Steven Tothf11ec7d2008-10-16 20:22:01 -0300711static int cx24116_read_ber(struct dvb_frontend *fe, u32 *ber)
Steven Toth0d467482008-09-04 01:14:43 -0300712{
Darron Broad490c8682008-09-13 19:42:16 -0300713 struct cx24116_state *state = fe->demodulator_priv;
714
Steven Toth0d467482008-09-04 01:14:43 -0300715 dprintk("%s()\n", __func__);
Darron Broad490c8682008-09-13 19:42:16 -0300716
Steven Tothf11ec7d2008-10-16 20:22:01 -0300717 *ber = (cx24116_readreg(state, CX24116_REG_BER24) << 24) |
718 (cx24116_readreg(state, CX24116_REG_BER16) << 16) |
719 (cx24116_readreg(state, CX24116_REG_BER8) << 8) |
720 cx24116_readreg(state, CX24116_REG_BER0);
Steven Toth0d467482008-09-04 01:14:43 -0300721
722 return 0;
723}
724
Darron Broad490c8682008-09-13 19:42:16 -0300725/* TODO Determine function and scale appropriately */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300726static int cx24116_read_signal_strength(struct dvb_frontend *fe,
727 u16 *signal_strength)
Steven Toth0d467482008-09-04 01:14:43 -0300728{
729 struct cx24116_state *state = fe->demodulator_priv;
Darron Broad490c8682008-09-13 19:42:16 -0300730 struct cx24116_cmd cmd;
731 int ret;
732 u16 sig_reading;
733
734 dprintk("%s()\n", __func__);
735
736 /* Firmware CMD 19: Get AGC */
737 cmd.args[0x00] = CMD_GETAGC;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300738 cmd.len = 0x01;
Darron Broad490c8682008-09-13 19:42:16 -0300739 ret = cx24116_cmd_execute(fe, &cmd);
740 if (ret != 0)
741 return ret;
742
Steven Tothf11ec7d2008-10-16 20:22:01 -0300743 sig_reading =
744 (cx24116_readreg(state,
745 CX24116_REG_SSTATUS) & CX24116_SIGNAL_MASK) |
746 (cx24116_readreg(state, CX24116_REG_SIGNAL) << 6);
747 *signal_strength = 0 - sig_reading;
Darron Broad490c8682008-09-13 19:42:16 -0300748
Steven Tothf11ec7d2008-10-16 20:22:01 -0300749 dprintk("%s: raw / cooked = 0x%04x / 0x%04x\n",
750 __func__, sig_reading, *signal_strength);
Darron Broad490c8682008-09-13 19:42:16 -0300751
752 return 0;
753}
754
755/* SNR (0..100)% = (sig & 0xf0) * 10 + (sig & 0x0f) * 10 / 16 */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300756static int cx24116_read_snr_pct(struct dvb_frontend *fe, u16 *snr)
Darron Broad490c8682008-09-13 19:42:16 -0300757{
758 struct cx24116_state *state = fe->demodulator_priv;
759 u8 snr_reading;
760 static const u32 snr_tab[] = { /* 10 x Table (rounded up) */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300761 0x00000, 0x0199A, 0x03333, 0x04ccD, 0x06667,
762 0x08000, 0x0999A, 0x0b333, 0x0cccD, 0x0e667,
763 0x10000, 0x1199A, 0x13333, 0x14ccD, 0x16667,
764 0x18000 };
Steven Toth0d467482008-09-04 01:14:43 -0300765
766 dprintk("%s()\n", __func__);
767
Steven Toth8953db72008-10-06 21:20:21 -0300768 snr_reading = cx24116_readreg(state, CX24116_REG_QUALITY0);
Steven Toth0d467482008-09-04 01:14:43 -0300769
Steven Tothf11ec7d2008-10-16 20:22:01 -0300770 if (snr_reading >= 0xa0 /* 100% */)
Darron Broad490c8682008-09-13 19:42:16 -0300771 *snr = 0xffff;
Steven Toth0d467482008-09-04 01:14:43 -0300772 else
Steven Tothf11ec7d2008-10-16 20:22:01 -0300773 *snr = snr_tab[(snr_reading & 0xf0) >> 4] +
774 (snr_tab[(snr_reading & 0x0f)] >> 4);
Steven Toth0d467482008-09-04 01:14:43 -0300775
Darron Broad490c8682008-09-13 19:42:16 -0300776 dprintk("%s: raw / cooked = 0x%02x / 0x%04x\n", __func__,
777 snr_reading, *snr);
Steven Toth0d467482008-09-04 01:14:43 -0300778
779 return 0;
780}
781
Steven Toth8953db72008-10-06 21:20:21 -0300782/* The reelbox patches show the value in the registers represents
783 * ESNO, from 0->30db (values 0->300). We provide this value by
784 * default.
785 */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300786static int cx24116_read_snr_esno(struct dvb_frontend *fe, u16 *snr)
Steven Toth8953db72008-10-06 21:20:21 -0300787{
788 struct cx24116_state *state = fe->demodulator_priv;
789
790 dprintk("%s()\n", __func__);
791
792 *snr = cx24116_readreg(state, CX24116_REG_QUALITY8) << 8 |
793 cx24116_readreg(state, CX24116_REG_QUALITY0);
794
795 dprintk("%s: raw 0x%04x\n", __func__, *snr);
796
797 return 0;
798}
799
Steven Tothf11ec7d2008-10-16 20:22:01 -0300800static int cx24116_read_snr(struct dvb_frontend *fe, u16 *snr)
Steven Toth8953db72008-10-06 21:20:21 -0300801{
802 if (esno_snr == 1)
803 return cx24116_read_snr_esno(fe, snr);
804 else
805 return cx24116_read_snr_pct(fe, snr);
806}
807
Steven Tothf11ec7d2008-10-16 20:22:01 -0300808static int cx24116_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
Steven Toth0d467482008-09-04 01:14:43 -0300809{
Darron Broad490c8682008-09-13 19:42:16 -0300810 struct cx24116_state *state = fe->demodulator_priv;
811
Steven Toth0d467482008-09-04 01:14:43 -0300812 dprintk("%s()\n", __func__);
Darron Broad490c8682008-09-13 19:42:16 -0300813
Steven Tothf11ec7d2008-10-16 20:22:01 -0300814 *ucblocks = (cx24116_readreg(state, CX24116_REG_UCB8) << 8) |
Darron Broad490c8682008-09-13 19:42:16 -0300815 cx24116_readreg(state, CX24116_REG_UCB0);
Steven Toth0d467482008-09-04 01:14:43 -0300816
817 return 0;
818}
819
820/* Overwrite the current tuning params, we are about to tune */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300821static void cx24116_clone_params(struct dvb_frontend *fe)
Steven Toth0d467482008-09-04 01:14:43 -0300822{
823 struct cx24116_state *state = fe->demodulator_priv;
Ezequiel Garciaee45ddc2012-10-23 15:57:24 -0300824 state->dcur = state->dnxt;
Steven Toth0d467482008-09-04 01:14:43 -0300825}
826
Darron Broad490c8682008-09-13 19:42:16 -0300827/* Wait for LNB */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300828static int cx24116_wait_for_lnb(struct dvb_frontend *fe)
Darron Broad490c8682008-09-13 19:42:16 -0300829{
830 struct cx24116_state *state = fe->demodulator_priv;
831 int i;
832
833 dprintk("%s() qstatus = 0x%02x\n", __func__,
834 cx24116_readreg(state, CX24116_REG_QSTATUS));
835
836 /* Wait for up to 300 ms */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300837 for (i = 0; i < 30 ; i++) {
Darron Broad490c8682008-09-13 19:42:16 -0300838 if (cx24116_readreg(state, CX24116_REG_QSTATUS) & 0x20)
839 return 0;
840 msleep(10);
841 }
842
843 dprintk("%s(): LNB not ready\n", __func__);
844
845 return -ETIMEDOUT; /* -EBUSY ? */
846}
847
Igor M. Liplianinc7bdcd02009-01-17 10:16:36 -0300848static int cx24116_set_voltage(struct dvb_frontend *fe,
Mauro Carvalho Chehab0df289a2015-06-07 14:53:52 -0300849 enum fe_sec_voltage voltage)
Igor M. Liplianinc7bdcd02009-01-17 10:16:36 -0300850{
851 struct cx24116_cmd cmd;
852 int ret;
853
854 dprintk("%s: %s\n", __func__,
855 voltage == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
856 voltage == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??");
857
858 /* Wait for LNB ready */
859 ret = cx24116_wait_for_lnb(fe);
860 if (ret != 0)
861 return ret;
862
863 /* Wait for voltage/min repeat delay */
864 msleep(100);
865
866 cmd.args[0x00] = CMD_LNBDCLEVEL;
867 cmd.args[0x01] = (voltage == SEC_VOLTAGE_18 ? 0x01 : 0x00);
868 cmd.len = 0x02;
869
870 /* Min delay time before DiSEqC send */
871 msleep(15);
872
873 return cx24116_cmd_execute(fe, &cmd);
874}
875
Steven Tothf11ec7d2008-10-16 20:22:01 -0300876static int cx24116_set_tone(struct dvb_frontend *fe,
Mauro Carvalho Chehab0df289a2015-06-07 14:53:52 -0300877 enum fe_sec_tone_mode tone)
Steven Toth0d467482008-09-04 01:14:43 -0300878{
879 struct cx24116_cmd cmd;
880 int ret;
881
882 dprintk("%s(%d)\n", __func__, tone);
Steven Tothf11ec7d2008-10-16 20:22:01 -0300883 if ((tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF)) {
Steven Toth98c94822008-10-16 20:24:42 -0300884 printk(KERN_ERR "%s: Invalid, tone=%d\n", __func__, tone);
Steven Toth0d467482008-09-04 01:14:43 -0300885 return -EINVAL;
886 }
887
Darron Broad490c8682008-09-13 19:42:16 -0300888 /* Wait for LNB ready */
889 ret = cx24116_wait_for_lnb(fe);
Steven Tothf11ec7d2008-10-16 20:22:01 -0300890 if (ret != 0)
Darron Broad490c8682008-09-13 19:42:16 -0300891 return ret;
892
893 /* Min delay time after DiSEqC send */
894 msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */
895
Steven Toth0d467482008-09-04 01:14:43 -0300896 /* Now we set the tone */
897 cmd.args[0x00] = CMD_SET_TONE;
898 cmd.args[0x01] = 0x00;
899 cmd.args[0x02] = 0x00;
900
901 switch (tone) {
902 case SEC_TONE_ON:
903 dprintk("%s: setting tone on\n", __func__);
904 cmd.args[0x03] = 0x01;
905 break;
906 case SEC_TONE_OFF:
Steven Tothf11ec7d2008-10-16 20:22:01 -0300907 dprintk("%s: setting tone off\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -0300908 cmd.args[0x03] = 0x00;
909 break;
910 }
Steven Tothf11ec7d2008-10-16 20:22:01 -0300911 cmd.len = 0x04;
Steven Toth0d467482008-09-04 01:14:43 -0300912
Darron Broad490c8682008-09-13 19:42:16 -0300913 /* Min delay time before DiSEqC send */
914 msleep(15); /* XXX determine is FW does this, see send_diseqc/burst */
915
Steven Toth0d467482008-09-04 01:14:43 -0300916 return cx24116_cmd_execute(fe, &cmd);
917}
918
919/* Initialise DiSEqC */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300920static int cx24116_diseqc_init(struct dvb_frontend *fe)
Steven Toth0d467482008-09-04 01:14:43 -0300921{
922 struct cx24116_state *state = fe->demodulator_priv;
Darron Broad490c8682008-09-13 19:42:16 -0300923 struct cx24116_cmd cmd;
924 int ret;
Steven Toth0d467482008-09-04 01:14:43 -0300925
Darron Broad490c8682008-09-13 19:42:16 -0300926 /* Firmware CMD 20: LNB/DiSEqC config */
927 cmd.args[0x00] = CMD_LNBCONFIG;
928 cmd.args[0x01] = 0x00;
929 cmd.args[0x02] = 0x10;
930 cmd.args[0x03] = 0x00;
931 cmd.args[0x04] = 0x8f;
932 cmd.args[0x05] = 0x28;
933 cmd.args[0x06] = (toneburst == CX24116_DISEQC_TONEOFF) ? 0x00 : 0x01;
934 cmd.args[0x07] = 0x01;
Steven Tothf11ec7d2008-10-16 20:22:01 -0300935 cmd.len = 0x08;
Darron Broad490c8682008-09-13 19:42:16 -0300936 ret = cx24116_cmd_execute(fe, &cmd);
937 if (ret != 0)
938 return ret;
939
940 /* Prepare a DiSEqC command */
941 state->dsec_cmd.args[0x00] = CMD_LNBSEND;
942
943 /* DiSEqC burst */
944 state->dsec_cmd.args[CX24116_DISEQC_BURST] = CX24116_DISEQC_MINI_A;
945
946 /* Unknown */
947 state->dsec_cmd.args[CX24116_DISEQC_ARG2_2] = 0x02;
948 state->dsec_cmd.args[CX24116_DISEQC_ARG3_0] = 0x00;
Steven Toth98c94822008-10-16 20:24:42 -0300949 /* Continuation flag? */
950 state->dsec_cmd.args[CX24116_DISEQC_ARG4_0] = 0x00;
Darron Broad490c8682008-09-13 19:42:16 -0300951
952 /* DiSEqC message length */
953 state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = 0x00;
954
955 /* Command length */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300956 state->dsec_cmd.len = CX24116_DISEQC_MSGOFS;
Steven Toth0d467482008-09-04 01:14:43 -0300957
958 return 0;
959}
960
961/* Send DiSEqC message with derived burst (hack) || previous burst */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300962static int cx24116_send_diseqc_msg(struct dvb_frontend *fe,
963 struct dvb_diseqc_master_cmd *d)
Steven Toth0d467482008-09-04 01:14:43 -0300964{
965 struct cx24116_state *state = fe->demodulator_priv;
Steven Toth0d467482008-09-04 01:14:43 -0300966 int i, ret;
967
Mauro Carvalho Chehab1fa2337a2015-04-28 18:51:17 -0300968 /* Validate length */
969 if (d->msg_len > sizeof(d->msg))
970 return -EINVAL;
971
Steven Toth0d467482008-09-04 01:14:43 -0300972 /* Dump DiSEqC message */
973 if (debug) {
Steven Toth98c94822008-10-16 20:24:42 -0300974 printk(KERN_INFO "cx24116: %s(", __func__);
Steven Tothf11ec7d2008-10-16 20:22:01 -0300975 for (i = 0 ; i < d->msg_len ;) {
Steven Toth98c94822008-10-16 20:24:42 -0300976 printk(KERN_INFO "0x%02x", d->msg[i]);
Steven Tothf11ec7d2008-10-16 20:22:01 -0300977 if (++i < d->msg_len)
Steven Toth98c94822008-10-16 20:24:42 -0300978 printk(KERN_INFO ", ");
Steven Tothf11ec7d2008-10-16 20:22:01 -0300979 }
Darron Broad490c8682008-09-13 19:42:16 -0300980 printk(") toneburst=%d\n", toneburst);
Steven Toth0d467482008-09-04 01:14:43 -0300981 }
982
Steven Toth0d467482008-09-04 01:14:43 -0300983 /* DiSEqC message */
984 for (i = 0; i < d->msg_len; i++)
Darron Broad490c8682008-09-13 19:42:16 -0300985 state->dsec_cmd.args[CX24116_DISEQC_MSGOFS + i] = d->msg[i];
Steven Toth0d467482008-09-04 01:14:43 -0300986
Darron Broad490c8682008-09-13 19:42:16 -0300987 /* DiSEqC message length */
988 state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] = d->msg_len;
Steven Toth0d467482008-09-04 01:14:43 -0300989
Darron Broad490c8682008-09-13 19:42:16 -0300990 /* Command length */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300991 state->dsec_cmd.len = CX24116_DISEQC_MSGOFS +
992 state->dsec_cmd.args[CX24116_DISEQC_MSGLEN];
Steven Toth0d467482008-09-04 01:14:43 -0300993
Darron Broad490c8682008-09-13 19:42:16 -0300994 /* DiSEqC toneburst */
Steven Tothf11ec7d2008-10-16 20:22:01 -0300995 if (toneburst == CX24116_DISEQC_MESGCACHE)
Darron Broad490c8682008-09-13 19:42:16 -0300996 /* Message is cached */
997 return 0;
Steven Toth0d467482008-09-04 01:14:43 -0300998
Steven Tothf11ec7d2008-10-16 20:22:01 -0300999 else if (toneburst == CX24116_DISEQC_TONEOFF)
Darron Broad490c8682008-09-13 19:42:16 -03001000 /* Message is sent without burst */
1001 state->dsec_cmd.args[CX24116_DISEQC_BURST] = 0;
1002
Steven Tothf11ec7d2008-10-16 20:22:01 -03001003 else if (toneburst == CX24116_DISEQC_TONECACHE) {
Darron Broad490c8682008-09-13 19:42:16 -03001004 /*
1005 * Message is sent with derived else cached burst
1006 *
1007 * WRITE PORT GROUP COMMAND 38
1008 *
1009 * 0/A/A: E0 10 38 F0..F3
1010 * 1/B/B: E0 10 38 F4..F7
1011 * 2/C/A: E0 10 38 F8..FB
1012 * 3/D/B: E0 10 38 FC..FF
1013 *
Darron Broad7396d3e2008-09-14 10:45:58 -03001014 * databyte[3]= 8421:8421
Darron Broad490c8682008-09-13 19:42:16 -03001015 * ABCD:WXYZ
1016 * CLR :SET
1017 *
1018 * WX= PORT SELECT 0..3 (X=TONEBURST)
1019 * Y = VOLTAGE (0=13V, 1=18V)
1020 * Z = BAND (0=LOW, 1=HIGH(22K))
1021 */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001022 if (d->msg_len >= 4 && d->msg[2] == 0x38)
1023 state->dsec_cmd.args[CX24116_DISEQC_BURST] =
1024 ((d->msg[3] & 4) >> 2);
1025 if (debug)
1026 dprintk("%s burst=%d\n", __func__,
1027 state->dsec_cmd.args[CX24116_DISEQC_BURST]);
Darron Broad490c8682008-09-13 19:42:16 -03001028 }
1029
1030 /* Wait for LNB ready */
1031 ret = cx24116_wait_for_lnb(fe);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001032 if (ret != 0)
Darron Broad490c8682008-09-13 19:42:16 -03001033 return ret;
1034
1035 /* Wait for voltage/min repeat delay */
1036 msleep(100);
1037
1038 /* Command */
1039 ret = cx24116_cmd_execute(fe, &state->dsec_cmd);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001040 if (ret != 0)
Darron Broad490c8682008-09-13 19:42:16 -03001041 return ret;
1042 /*
1043 * Wait for send
Steven Toth0d467482008-09-04 01:14:43 -03001044 *
1045 * Eutelsat spec:
Darron Broad490c8682008-09-13 19:42:16 -03001046 * >15ms delay + (XXX determine if FW does this, see set_tone)
1047 * 13.5ms per byte +
1048 * >15ms delay +
1049 * 12.5ms burst +
1050 * >15ms delay (XXX determine if FW does this, see set_tone)
Steven Toth0d467482008-09-04 01:14:43 -03001051 */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001052 msleep((state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) +
1053 ((toneburst == CX24116_DISEQC_TONEOFF) ? 30 : 60));
Steven Toth0d467482008-09-04 01:14:43 -03001054
Darron Broad490c8682008-09-13 19:42:16 -03001055 return 0;
Steven Toth0d467482008-09-04 01:14:43 -03001056}
1057
1058/* Send DiSEqC burst */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001059static int cx24116_diseqc_send_burst(struct dvb_frontend *fe,
Mauro Carvalho Chehab0df289a2015-06-07 14:53:52 -03001060 enum fe_sec_mini_cmd burst)
Steven Toth0d467482008-09-04 01:14:43 -03001061{
1062 struct cx24116_state *state = fe->demodulator_priv;
Steven Toth0d467482008-09-04 01:14:43 -03001063 int ret;
1064
Steven Tothf11ec7d2008-10-16 20:22:01 -03001065 dprintk("%s(%d) toneburst=%d\n", __func__, burst, toneburst);
Steven Toth0d467482008-09-04 01:14:43 -03001066
Darron Broad490c8682008-09-13 19:42:16 -03001067 /* DiSEqC burst */
Steven Toth0d467482008-09-04 01:14:43 -03001068 if (burst == SEC_MINI_A)
Steven Tothf11ec7d2008-10-16 20:22:01 -03001069 state->dsec_cmd.args[CX24116_DISEQC_BURST] =
1070 CX24116_DISEQC_MINI_A;
1071 else if (burst == SEC_MINI_B)
1072 state->dsec_cmd.args[CX24116_DISEQC_BURST] =
1073 CX24116_DISEQC_MINI_B;
Steven Toth0d467482008-09-04 01:14:43 -03001074 else
1075 return -EINVAL;
1076
Darron Broad490c8682008-09-13 19:42:16 -03001077 /* DiSEqC toneburst */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001078 if (toneburst != CX24116_DISEQC_MESGCACHE)
Darron Broad490c8682008-09-13 19:42:16 -03001079 /* Burst is cached */
1080 return 0;
Steven Toth0d467482008-09-04 01:14:43 -03001081
Darron Broad490c8682008-09-13 19:42:16 -03001082 /* Burst is to be sent with cached message */
Steven Toth0d467482008-09-04 01:14:43 -03001083
Darron Broad490c8682008-09-13 19:42:16 -03001084 /* Wait for LNB ready */
1085 ret = cx24116_wait_for_lnb(fe);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001086 if (ret != 0)
Darron Broad490c8682008-09-13 19:42:16 -03001087 return ret;
Steven Toth0d467482008-09-04 01:14:43 -03001088
Darron Broad490c8682008-09-13 19:42:16 -03001089 /* Wait for voltage/min repeat delay */
1090 msleep(100);
Steven Toth0d467482008-09-04 01:14:43 -03001091
Darron Broad490c8682008-09-13 19:42:16 -03001092 /* Command */
1093 ret = cx24116_cmd_execute(fe, &state->dsec_cmd);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001094 if (ret != 0)
Darron Broad490c8682008-09-13 19:42:16 -03001095 return ret;
1096
1097 /*
1098 * Wait for send
1099 *
1100 * Eutelsat spec:
1101 * >15ms delay + (XXX determine if FW does this, see set_tone)
1102 * 13.5ms per byte +
1103 * >15ms delay +
1104 * 12.5ms burst +
1105 * >15ms delay (XXX determine if FW does this, see set_tone)
1106 */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001107 msleep((state->dsec_cmd.args[CX24116_DISEQC_MSGLEN] << 4) + 60);
Darron Broad490c8682008-09-13 19:42:16 -03001108
1109 return 0;
Steven Toth0d467482008-09-04 01:14:43 -03001110}
1111
Steven Tothf11ec7d2008-10-16 20:22:01 -03001112static void cx24116_release(struct dvb_frontend *fe)
Steven Toth0d467482008-09-04 01:14:43 -03001113{
Steven Tothf11ec7d2008-10-16 20:22:01 -03001114 struct cx24116_state *state = fe->demodulator_priv;
1115 dprintk("%s\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -03001116 kfree(state);
1117}
1118
1119static struct dvb_frontend_ops cx24116_ops;
1120
Steven Tothf11ec7d2008-10-16 20:22:01 -03001121struct dvb_frontend *cx24116_attach(const struct cx24116_config *config,
1122 struct i2c_adapter *i2c)
Steven Toth0d467482008-09-04 01:14:43 -03001123{
Steven Tothf11ec7d2008-10-16 20:22:01 -03001124 struct cx24116_state *state = NULL;
Steven Toth0d467482008-09-04 01:14:43 -03001125 int ret;
1126
Steven Tothf11ec7d2008-10-16 20:22:01 -03001127 dprintk("%s\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -03001128
1129 /* allocate memory for the internal state */
Matthias Schwarzott8420fa72009-02-23 12:26:38 -03001130 state = kzalloc(sizeof(struct cx24116_state), GFP_KERNEL);
Steven Toth98c94822008-10-16 20:24:42 -03001131 if (state == NULL)
Darron Broad7396d3e2008-09-14 10:45:58 -03001132 goto error1;
Steven Toth0d467482008-09-04 01:14:43 -03001133
Steven Toth0d467482008-09-04 01:14:43 -03001134 state->config = config;
1135 state->i2c = i2c;
1136
1137 /* check if the demod is present */
Steven Toth98c94822008-10-16 20:24:42 -03001138 ret = (cx24116_readreg(state, 0xFF) << 8) |
1139 cx24116_readreg(state, 0xFE);
Steven Toth0d467482008-09-04 01:14:43 -03001140 if (ret != 0x0501) {
Steven Toth98c94822008-10-16 20:24:42 -03001141 printk(KERN_INFO "Invalid probe, probably not a CX24116 device\n");
Darron Broad7396d3e2008-09-14 10:45:58 -03001142 goto error2;
Steven Toth0d467482008-09-04 01:14:43 -03001143 }
1144
1145 /* create dvb_frontend */
Steven Toth98c94822008-10-16 20:24:42 -03001146 memcpy(&state->frontend.ops, &cx24116_ops,
1147 sizeof(struct dvb_frontend_ops));
Steven Toth0d467482008-09-04 01:14:43 -03001148 state->frontend.demodulator_priv = state;
1149 return &state->frontend;
1150
Darron Broad7396d3e2008-09-14 10:45:58 -03001151error2: kfree(state);
Darron Broad490c8682008-09-13 19:42:16 -03001152error1: return NULL;
Steven Toth0d467482008-09-04 01:14:43 -03001153}
Steven Tothf11ec7d2008-10-16 20:22:01 -03001154EXPORT_SYMBOL(cx24116_attach);
1155
Darron Broad490c8682008-09-13 19:42:16 -03001156/*
1157 * Initialise or wake up device
1158 *
1159 * Power config will reset and load initial firmware if required
1160 */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001161static int cx24116_initfe(struct dvb_frontend *fe)
Steven Toth0d467482008-09-04 01:14:43 -03001162{
Steven Tothf11ec7d2008-10-16 20:22:01 -03001163 struct cx24116_state *state = fe->demodulator_priv;
Darron Broad490c8682008-09-13 19:42:16 -03001164 struct cx24116_cmd cmd;
1165 int ret;
1166
Steven Tothf11ec7d2008-10-16 20:22:01 -03001167 dprintk("%s()\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -03001168
Darron Broad490c8682008-09-13 19:42:16 -03001169 /* Power on */
1170 cx24116_writereg(state, 0xe0, 0);
1171 cx24116_writereg(state, 0xe1, 0);
1172 cx24116_writereg(state, 0xea, 0);
1173
1174 /* Firmware CMD 36: Power config */
1175 cmd.args[0x00] = CMD_TUNERSLEEP;
1176 cmd.args[0x01] = 0;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001177 cmd.len = 0x02;
Darron Broad490c8682008-09-13 19:42:16 -03001178 ret = cx24116_cmd_execute(fe, &cmd);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001179 if (ret != 0)
Darron Broad490c8682008-09-13 19:42:16 -03001180 return ret;
1181
Igor M. Liplianin8afe6ad2009-01-29 21:57:07 -03001182 ret = cx24116_diseqc_init(fe);
1183 if (ret != 0)
1184 return ret;
1185
1186 /* HVR-4000 needs this */
1187 return cx24116_set_voltage(fe, SEC_VOLTAGE_13);
Steven Toth0d467482008-09-04 01:14:43 -03001188}
1189
Darron Broad490c8682008-09-13 19:42:16 -03001190/*
1191 * Put device to sleep
1192 */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001193static int cx24116_sleep(struct dvb_frontend *fe)
Darron Broad490c8682008-09-13 19:42:16 -03001194{
Steven Tothf11ec7d2008-10-16 20:22:01 -03001195 struct cx24116_state *state = fe->demodulator_priv;
Darron Broad490c8682008-09-13 19:42:16 -03001196 struct cx24116_cmd cmd;
1197 int ret;
1198
Steven Tothf11ec7d2008-10-16 20:22:01 -03001199 dprintk("%s()\n", __func__);
Darron Broad490c8682008-09-13 19:42:16 -03001200
1201 /* Firmware CMD 36: Power config */
1202 cmd.args[0x00] = CMD_TUNERSLEEP;
1203 cmd.args[0x01] = 1;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001204 cmd.len = 0x02;
Darron Broad490c8682008-09-13 19:42:16 -03001205 ret = cx24116_cmd_execute(fe, &cmd);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001206 if (ret != 0)
Darron Broad490c8682008-09-13 19:42:16 -03001207 return ret;
1208
1209 /* Power off (Shutdown clocks) */
1210 cx24116_writereg(state, 0xea, 0xff);
1211 cx24116_writereg(state, 0xe1, 1);
1212 cx24116_writereg(state, 0xe0, 1);
1213
1214 return 0;
1215}
1216
Steven Toth0d467482008-09-04 01:14:43 -03001217/* dvb-core told us to tune, the tv property cache will be complete,
1218 * it's safe for is to pull values and use them for tuning purposes.
1219 */
Mauro Carvalho Chehab1ac6a852011-12-22 17:28:11 -03001220static int cx24116_set_frontend(struct dvb_frontend *fe)
Steven Toth0d467482008-09-04 01:14:43 -03001221{
1222 struct cx24116_state *state = fe->demodulator_priv;
Steven Toth56f06802008-09-11 10:19:27 -03001223 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
Steven Toth0d467482008-09-04 01:14:43 -03001224 struct cx24116_cmd cmd;
Mauro Carvalho Chehab0df289a2015-06-07 14:53:52 -03001225 enum fe_status tunerstat;
Darron Broad2fd93392008-12-18 06:27:23 -03001226 int i, status, ret, retune = 1;
Steven Toth0d467482008-09-04 01:14:43 -03001227
Steven Tothf11ec7d2008-10-16 20:22:01 -03001228 dprintk("%s()\n", __func__);
Steven Toth0d467482008-09-04 01:14:43 -03001229
Steven Tothf11ec7d2008-10-16 20:22:01 -03001230 switch (c->delivery_system) {
1231 case SYS_DVBS:
1232 dprintk("%s: DVB-S delivery system selected\n", __func__);
Darron Broad01a8f032008-10-03 11:47:46 -03001233
Steven Tothf11ec7d2008-10-16 20:22:01 -03001234 /* Only QPSK is supported for DVB-S */
1235 if (c->modulation != QPSK) {
1236 dprintk("%s: unsupported modulation selected (%d)\n",
1237 __func__, c->modulation);
1238 return -EOPNOTSUPP;
1239 }
Darron Broad01a8f032008-10-03 11:47:46 -03001240
Steven Tothf11ec7d2008-10-16 20:22:01 -03001241 /* Pilot doesn't exist in DVB-S, turn bit off */
1242 state->dnxt.pilot_val = CX24116_PILOT_OFF;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001243
1244 /* DVB-S only supports 0.35 */
1245 if (c->rolloff != ROLLOFF_35) {
1246 dprintk("%s: unsupported rolloff selected (%d)\n",
1247 __func__, c->rolloff);
1248 return -EOPNOTSUPP;
1249 }
1250 state->dnxt.rolloff_val = CX24116_ROLLOFF_035;
1251 break;
1252
1253 case SYS_DVBS2:
1254 dprintk("%s: DVB-S2 delivery system selected\n", __func__);
1255
1256 /*
1257 * NBC 8PSK/QPSK with DVB-S is supported for DVB-S2,
1258 * but not hardware auto detection
1259 */
1260 if (c->modulation != PSK_8 && c->modulation != QPSK) {
1261 dprintk("%s: unsupported modulation selected (%d)\n",
1262 __func__, c->modulation);
1263 return -EOPNOTSUPP;
1264 }
1265
1266 switch (c->pilot) {
1267 case PILOT_AUTO: /* Not supported but emulated */
Christophe Thommeret74563212008-10-15 20:01:32 -03001268 state->dnxt.pilot_val = (c->modulation == QPSK)
1269 ? CX24116_PILOT_OFF : CX24116_PILOT_ON;
Darron Broad2fd93392008-12-18 06:27:23 -03001270 retune++;
Christophe Thommeret74563212008-10-15 20:01:32 -03001271 break;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001272 case PILOT_OFF:
Darron Broad01a8f032008-10-03 11:47:46 -03001273 state->dnxt.pilot_val = CX24116_PILOT_OFF;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001274 break;
1275 case PILOT_ON:
1276 state->dnxt.pilot_val = CX24116_PILOT_ON;
1277 break;
1278 default:
1279 dprintk("%s: unsupported pilot mode selected (%d)\n",
1280 __func__, c->pilot);
1281 return -EOPNOTSUPP;
1282 }
Darron Broad01a8f032008-10-03 11:47:46 -03001283
Steven Tothf11ec7d2008-10-16 20:22:01 -03001284 switch (c->rolloff) {
1285 case ROLLOFF_20:
1286 state->dnxt.rolloff_val = CX24116_ROLLOFF_020;
1287 break;
1288 case ROLLOFF_25:
1289 state->dnxt.rolloff_val = CX24116_ROLLOFF_025;
1290 break;
1291 case ROLLOFF_35:
Darron Broad7396d3e2008-09-14 10:45:58 -03001292 state->dnxt.rolloff_val = CX24116_ROLLOFF_035;
Darron Broad490c8682008-09-13 19:42:16 -03001293 break;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001294 case ROLLOFF_AUTO: /* Rolloff must be explicit */
Darron Broad490c8682008-09-13 19:42:16 -03001295 default:
Steven Tothf11ec7d2008-10-16 20:22:01 -03001296 dprintk("%s: unsupported rolloff selected (%d)\n",
1297 __func__, c->rolloff);
Darron Broad490c8682008-09-13 19:42:16 -03001298 return -EOPNOTSUPP;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001299 }
1300 break;
1301
1302 default:
1303 dprintk("%s: unsupported delivery system selected (%d)\n",
1304 __func__, c->delivery_system);
1305 return -EOPNOTSUPP;
Darron Broad490c8682008-09-13 19:42:16 -03001306 }
Darron Broad35694762008-12-18 06:21:51 -03001307 state->dnxt.delsys = c->delivery_system;
Darron Broad01a8f032008-10-03 11:47:46 -03001308 state->dnxt.modulation = c->modulation;
1309 state->dnxt.frequency = c->frequency;
1310 state->dnxt.pilot = c->pilot;
1311 state->dnxt.rolloff = c->rolloff;
Darron Broad490c8682008-09-13 19:42:16 -03001312
Steven Tothf11ec7d2008-10-16 20:22:01 -03001313 ret = cx24116_set_inversion(state, c->inversion);
1314 if (ret != 0)
Steven Toth0d467482008-09-04 01:14:43 -03001315 return ret;
1316
Darron Broad01a8f032008-10-03 11:47:46 -03001317 /* FEC_NONE/AUTO for DVB-S2 is not supported and detected here */
Darron Broad35694762008-12-18 06:21:51 -03001318 ret = cx24116_set_fec(state, c->delivery_system, c->modulation, c->fec_inner);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001319 if (ret != 0)
Steven Toth0d467482008-09-04 01:14:43 -03001320 return ret;
1321
Steven Tothf11ec7d2008-10-16 20:22:01 -03001322 ret = cx24116_set_symbolrate(state, c->symbol_rate);
1323 if (ret != 0)
Steven Toth0d467482008-09-04 01:14:43 -03001324 return ret;
1325
1326 /* discard the 'current' tuning parameters and prepare to tune */
1327 cx24116_clone_params(fe);
1328
Darron Broad35694762008-12-18 06:21:51 -03001329 dprintk("%s: delsys = %d\n", __func__, state->dcur.delsys);
Darron Broad01a8f032008-10-03 11:47:46 -03001330 dprintk("%s: modulation = %d\n", __func__, state->dcur.modulation);
Steven Toth0d467482008-09-04 01:14:43 -03001331 dprintk("%s: frequency = %d\n", __func__, state->dcur.frequency);
Darron Broad01a8f032008-10-03 11:47:46 -03001332 dprintk("%s: pilot = %d (val = 0x%02x)\n", __func__,
1333 state->dcur.pilot, state->dcur.pilot_val);
1334 dprintk("%s: retune = %d\n", __func__, retune);
1335 dprintk("%s: rolloff = %d (val = 0x%02x)\n", __func__,
1336 state->dcur.rolloff, state->dcur.rolloff_val);
Steven Toth0d467482008-09-04 01:14:43 -03001337 dprintk("%s: symbol_rate = %d\n", __func__, state->dcur.symbol_rate);
1338 dprintk("%s: FEC = %d (mask/val = 0x%02x/0x%02x)\n", __func__,
1339 state->dcur.fec, state->dcur.fec_mask, state->dcur.fec_val);
1340 dprintk("%s: Inversion = %d (val = 0x%02x)\n", __func__,
1341 state->dcur.inversion, state->dcur.inversion_val);
1342
Darron Broad490c8682008-09-13 19:42:16 -03001343 /* This is also done in advise/acquire on HVR4000 but not on LITE */
Steven Toth0d467482008-09-04 01:14:43 -03001344 if (state->config->set_ts_params)
1345 state->config->set_ts_params(fe, 0);
1346
Darron Broad490c8682008-09-13 19:42:16 -03001347 /* Set/Reset B/W */
1348 cmd.args[0x00] = CMD_BANDWIDTH;
1349 cmd.args[0x01] = 0x01;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001350 cmd.len = 0x02;
Darron Broad490c8682008-09-13 19:42:16 -03001351 ret = cx24116_cmd_execute(fe, &cmd);
1352 if (ret != 0)
1353 return ret;
Igor M. Liplianin3f8e51a2008-09-09 13:22:29 -03001354
Steven Toth0d467482008-09-04 01:14:43 -03001355 /* Prepare a tune request */
1356 cmd.args[0x00] = CMD_TUNEREQUEST;
1357
1358 /* Frequency */
1359 cmd.args[0x01] = (state->dcur.frequency & 0xff0000) >> 16;
1360 cmd.args[0x02] = (state->dcur.frequency & 0x00ff00) >> 8;
1361 cmd.args[0x03] = (state->dcur.frequency & 0x0000ff);
1362
1363 /* Symbol Rate */
1364 cmd.args[0x04] = ((state->dcur.symbol_rate / 1000) & 0xff00) >> 8;
1365 cmd.args[0x05] = ((state->dcur.symbol_rate / 1000) & 0x00ff);
1366
1367 /* Automatic Inversion */
1368 cmd.args[0x06] = state->dcur.inversion_val;
1369
Darron Broad01a8f032008-10-03 11:47:46 -03001370 /* Modulation / FEC / Pilot */
1371 cmd.args[0x07] = state->dcur.fec_val | state->dcur.pilot_val;
Steven Toth0d467482008-09-04 01:14:43 -03001372
1373 cmd.args[0x08] = CX24116_SEARCH_RANGE_KHZ >> 8;
1374 cmd.args[0x09] = CX24116_SEARCH_RANGE_KHZ & 0xff;
1375 cmd.args[0x0a] = 0x00;
1376 cmd.args[0x0b] = 0x00;
Darron Broad490c8682008-09-13 19:42:16 -03001377 cmd.args[0x0c] = state->dcur.rolloff_val;
Steven Toth0d467482008-09-04 01:14:43 -03001378 cmd.args[0x0d] = state->dcur.fec_mask;
Igor M. Liplianin3f8e51a2008-09-09 13:22:29 -03001379
Darron Broad490c8682008-09-13 19:42:16 -03001380 if (state->dcur.symbol_rate > 30000000) {
Igor M. Liplianin3f8e51a2008-09-09 13:22:29 -03001381 cmd.args[0x0e] = 0x04;
1382 cmd.args[0x0f] = 0x00;
1383 cmd.args[0x10] = 0x01;
1384 cmd.args[0x11] = 0x77;
1385 cmd.args[0x12] = 0x36;
Darron Broad490c8682008-09-13 19:42:16 -03001386 cx24116_writereg(state, CX24116_REG_CLKDIV, 0x44);
1387 cx24116_writereg(state, CX24116_REG_RATEDIV, 0x01);
Igor M. Liplianin3f8e51a2008-09-09 13:22:29 -03001388 } else {
1389 cmd.args[0x0e] = 0x06;
1390 cmd.args[0x0f] = 0x00;
1391 cmd.args[0x10] = 0x00;
1392 cmd.args[0x11] = 0xFA;
1393 cmd.args[0x12] = 0x24;
Darron Broad490c8682008-09-13 19:42:16 -03001394 cx24116_writereg(state, CX24116_REG_CLKDIV, 0x46);
1395 cx24116_writereg(state, CX24116_REG_RATEDIV, 0x00);
Igor M. Liplianin3f8e51a2008-09-09 13:22:29 -03001396 }
1397
Steven Tothf11ec7d2008-10-16 20:22:01 -03001398 cmd.len = 0x13;
Steven Toth0d467482008-09-04 01:14:43 -03001399
1400 /* We need to support pilot and non-pilot tuning in the
1401 * driver automatically. This is a workaround for because
1402 * the demod does not support autodetect.
1403 */
1404 do {
Darron Broad490c8682008-09-13 19:42:16 -03001405 /* Reset status register */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001406 status = cx24116_readreg(state, CX24116_REG_SSTATUS)
1407 & CX24116_SIGNAL_MASK;
Darron Broad490c8682008-09-13 19:42:16 -03001408 cx24116_writereg(state, CX24116_REG_SSTATUS, status);
Steven Toth0d467482008-09-04 01:14:43 -03001409
1410 /* Tune */
1411 ret = cx24116_cmd_execute(fe, &cmd);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001412 if (ret != 0)
Steven Toth0d467482008-09-04 01:14:43 -03001413 break;
1414
Darron Broad490c8682008-09-13 19:42:16 -03001415 /*
1416 * Wait for up to 500 ms before retrying
1417 *
1418 * If we are able to tune then generally it occurs within 100ms.
1419 * If it takes longer, try a different toneburst setting.
1420 */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001421 for (i = 0; i < 50 ; i++) {
Darron Broad490c8682008-09-13 19:42:16 -03001422 cx24116_read_status(fe, &tunerstat);
1423 status = tunerstat & (FE_HAS_SIGNAL | FE_HAS_SYNC);
Steven Tothf11ec7d2008-10-16 20:22:01 -03001424 if (status == (FE_HAS_SIGNAL | FE_HAS_SYNC)) {
1425 dprintk("%s: Tuned\n", __func__);
Darron Broad490c8682008-09-13 19:42:16 -03001426 goto tuned;
1427 }
1428 msleep(10);
Steven Toth0d467482008-09-04 01:14:43 -03001429 }
Darron Broad490c8682008-09-13 19:42:16 -03001430
Steven Tothf11ec7d2008-10-16 20:22:01 -03001431 dprintk("%s: Not tuned\n", __func__);
Darron Broad490c8682008-09-13 19:42:16 -03001432
1433 /* Toggle pilot bit when in auto-pilot */
Steven Tothf11ec7d2008-10-16 20:22:01 -03001434 if (state->dcur.pilot == PILOT_AUTO)
Darron Broad01a8f032008-10-03 11:47:46 -03001435 cmd.args[0x07] ^= CX24116_PILOT_ON;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001436 } while (--retune);
Steven Toth0d467482008-09-04 01:14:43 -03001437
Darron Broad490c8682008-09-13 19:42:16 -03001438tuned: /* Set/Reset B/W */
1439 cmd.args[0x00] = CMD_BANDWIDTH;
1440 cmd.args[0x01] = 0x00;
Steven Tothf11ec7d2008-10-16 20:22:01 -03001441 cmd.len = 0x02;
Greg Dietsche3735edf2011-06-16 13:33:35 -03001442 return cx24116_cmd_execute(fe, &cmd);
Steven Toth0d467482008-09-04 01:14:43 -03001443}
1444
Mauro Carvalho Chehab7e072222011-12-26 17:48:33 -03001445static int cx24116_tune(struct dvb_frontend *fe, bool re_tune,
Mauro Carvalho Chehab0df289a2015-06-07 14:53:52 -03001446 unsigned int mode_flags, unsigned int *delay, enum fe_status *status)
Darron Broad6639f1e2008-12-18 06:28:18 -03001447{
Mauro Carvalho Chehab1ac6a852011-12-22 17:28:11 -03001448 /*
1449 * It is safe to discard "params" here, as the DVB core will sync
1450 * fe->dtv_property_cache with fepriv->parameters_in, where the
1451 * DVBv3 params are stored. The only practical usage for it indicate
1452 * that re-tuning is needed, e. g. (fepriv->state & FESTATE_RETUNE) is
1453 * true.
1454 */
1455
Darron Broad6639f1e2008-12-18 06:28:18 -03001456 *delay = HZ / 5;
Mauro Carvalho Chehab7e072222011-12-26 17:48:33 -03001457 if (re_tune) {
Mauro Carvalho Chehab1ac6a852011-12-22 17:28:11 -03001458 int ret = cx24116_set_frontend(fe);
Darron Broad6639f1e2008-12-18 06:28:18 -03001459 if (ret)
1460 return ret;
1461 }
1462 return cx24116_read_status(fe, status);
1463}
1464
1465static int cx24116_get_algo(struct dvb_frontend *fe)
1466{
1467 return DVBFE_ALGO_HW;
1468}
1469
Steven Toth0d467482008-09-04 01:14:43 -03001470static struct dvb_frontend_ops cx24116_ops = {
Mauro Carvalho Chehab1ac6a852011-12-22 17:28:11 -03001471 .delsys = { SYS_DVBS, SYS_DVBS2 },
Steven Toth0d467482008-09-04 01:14:43 -03001472 .info = {
1473 .name = "Conexant CX24116/CX24118",
Steven Toth0d467482008-09-04 01:14:43 -03001474 .frequency_min = 950000,
1475 .frequency_max = 2150000,
1476 .frequency_stepsize = 1011, /* kHz for QPSK frontends */
1477 .frequency_tolerance = 5000,
1478 .symbol_rate_min = 1000000,
1479 .symbol_rate_max = 45000000,
1480 .caps = FE_CAN_INVERSION_AUTO |
1481 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
1482 FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
1483 FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
Klaus Schmidingerfaed4aa2008-12-31 14:13:56 -03001484 FE_CAN_2G_MODULATION |
Steven Toth0d467482008-09-04 01:14:43 -03001485 FE_CAN_QPSK | FE_CAN_RECOVER
1486 },
1487
1488 .release = cx24116_release,
1489
1490 .init = cx24116_initfe,
Darron Broad490c8682008-09-13 19:42:16 -03001491 .sleep = cx24116_sleep,
Steven Toth0d467482008-09-04 01:14:43 -03001492 .read_status = cx24116_read_status,
1493 .read_ber = cx24116_read_ber,
1494 .read_signal_strength = cx24116_read_signal_strength,
1495 .read_snr = cx24116_read_snr,
1496 .read_ucblocks = cx24116_read_ucblocks,
1497 .set_tone = cx24116_set_tone,
1498 .set_voltage = cx24116_set_voltage,
1499 .diseqc_send_master_cmd = cx24116_send_diseqc_msg,
1500 .diseqc_send_burst = cx24116_diseqc_send_burst,
Darron Broad6639f1e2008-12-18 06:28:18 -03001501 .get_frontend_algo = cx24116_get_algo,
1502 .tune = cx24116_tune,
Steven Toth0d467482008-09-04 01:14:43 -03001503
Mauro Carvalho Chehab1ac6a852011-12-22 17:28:11 -03001504 .set_frontend = cx24116_set_frontend,
Steven Toth0d467482008-09-04 01:14:43 -03001505};
1506
Steven Toth0d467482008-09-04 01:14:43 -03001507MODULE_DESCRIPTION("DVB Frontend module for Conexant cx24116/cx24118 hardware");
1508MODULE_AUTHOR("Steven Toth");
1509MODULE_LICENSE("GPL");
1510