xref: /linux/drivers/media/dvb-frontends/cx24117.c (revision 79790b6818e96c58fe2bffee1b418c16e64e7b80)
174ba9207SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
20d788680SLuis Alves /*
30d788680SLuis Alves     Conexant cx24117/cx24132 - Dual DVBS/S2 Satellite demod/tuner driver
40d788680SLuis Alves 
50d788680SLuis Alves     Copyright (C) 2013 Luis Alves <ljalvs@gmail.com>
60d788680SLuis Alves 	July, 6th 2013
70d788680SLuis Alves 	    First release based on cx24116 driver by:
80d788680SLuis Alves 	    Steven Toth and Georg Acher, Darron Broad, Igor Liplianin
90d788680SLuis Alves 	    Cards currently supported:
100d788680SLuis Alves 		TBS6980 - Dual DVBS/S2 PCIe card
110d788680SLuis Alves 		TBS6981 - Dual DVBS/S2 PCIe card
120d788680SLuis Alves 
130d788680SLuis Alves */
140d788680SLuis Alves 
150d788680SLuis Alves #include <linux/slab.h>
160d788680SLuis Alves #include <linux/kernel.h>
170d788680SLuis Alves #include <linux/module.h>
180d788680SLuis Alves #include <linux/moduleparam.h>
190d788680SLuis Alves #include <linux/init.h>
200d788680SLuis Alves #include <linux/firmware.h>
210d788680SLuis Alves 
22d10e8280SLuis Alves #include "tuner-i2c.h"
23fada1935SMauro Carvalho Chehab #include <media/dvb_frontend.h>
240d788680SLuis Alves #include "cx24117.h"
250d788680SLuis Alves 
260d788680SLuis Alves 
270d788680SLuis Alves #define CX24117_DEFAULT_FIRMWARE "dvb-fe-cx24117.fw"
280d788680SLuis Alves #define CX24117_SEARCH_RANGE_KHZ 5000
290d788680SLuis Alves 
300d788680SLuis Alves /* known registers */
310d788680SLuis Alves #define CX24117_REG_COMMAND      (0x00)      /* command buffer */
320d788680SLuis Alves #define CX24117_REG_EXECUTE      (0x1f)      /* execute command */
330d788680SLuis Alves 
340d788680SLuis Alves #define CX24117_REG_FREQ3_0      (0x34)      /* frequency */
350d788680SLuis Alves #define CX24117_REG_FREQ2_0      (0x35)
360d788680SLuis Alves #define CX24117_REG_FREQ1_0      (0x36)
370d788680SLuis Alves #define CX24117_REG_STATE0       (0x39)
380d788680SLuis Alves #define CX24117_REG_SSTATUS0     (0x3a)      /* demod0 signal high / status */
390d788680SLuis Alves #define CX24117_REG_SIGNAL0      (0x3b)
400d788680SLuis Alves #define CX24117_REG_FREQ5_0      (0x3c)      /* +-freq */
410d788680SLuis Alves #define CX24117_REG_FREQ6_0      (0x3d)
420d788680SLuis Alves #define CX24117_REG_SRATE2_0     (0x3e)      /* +- 1000 * srate */
430d788680SLuis Alves #define CX24117_REG_SRATE1_0     (0x3f)
440d788680SLuis Alves #define CX24117_REG_QUALITY2_0   (0x40)
450d788680SLuis Alves #define CX24117_REG_QUALITY1_0   (0x41)
460d788680SLuis Alves 
470d788680SLuis Alves #define CX24117_REG_BER4_0       (0x47)
480d788680SLuis Alves #define CX24117_REG_BER3_0       (0x48)
490d788680SLuis Alves #define CX24117_REG_BER2_0       (0x49)
500d788680SLuis Alves #define CX24117_REG_BER1_0       (0x4a)
510d788680SLuis Alves #define CX24117_REG_DVBS_UCB2_0  (0x4b)
520d788680SLuis Alves #define CX24117_REG_DVBS_UCB1_0  (0x4c)
530d788680SLuis Alves #define CX24117_REG_DVBS2_UCB2_0 (0x50)
540d788680SLuis Alves #define CX24117_REG_DVBS2_UCB1_0 (0x51)
550d788680SLuis Alves #define CX24117_REG_QSTATUS0     (0x93)
560d788680SLuis Alves #define CX24117_REG_CLKDIV0      (0xe6)
570d788680SLuis Alves #define CX24117_REG_RATEDIV0     (0xf0)
580d788680SLuis Alves 
590d788680SLuis Alves 
600d788680SLuis Alves #define CX24117_REG_FREQ3_1      (0x55)      /* frequency */
610d788680SLuis Alves #define CX24117_REG_FREQ2_1      (0x56)
620d788680SLuis Alves #define CX24117_REG_FREQ1_1      (0x57)
630d788680SLuis Alves #define CX24117_REG_STATE1       (0x5a)
640d788680SLuis Alves #define CX24117_REG_SSTATUS1     (0x5b)      /* demod1 signal high / status */
650d788680SLuis Alves #define CX24117_REG_SIGNAL1      (0x5c)
660d788680SLuis Alves #define CX24117_REG_FREQ5_1      (0x5d)      /* +- freq */
670d788680SLuis Alves #define CX24117_REG_FREQ4_1      (0x5e)
680d788680SLuis Alves #define CX24117_REG_SRATE2_1     (0x5f)
690d788680SLuis Alves #define CX24117_REG_SRATE1_1     (0x60)
700d788680SLuis Alves #define CX24117_REG_QUALITY2_1   (0x61)
710d788680SLuis Alves #define CX24117_REG_QUALITY1_1   (0x62)
720d788680SLuis Alves #define CX24117_REG_BER4_1       (0x68)
730d788680SLuis Alves #define CX24117_REG_BER3_1       (0x69)
740d788680SLuis Alves #define CX24117_REG_BER2_1       (0x6a)
750d788680SLuis Alves #define CX24117_REG_BER1_1       (0x6b)
760d788680SLuis Alves #define CX24117_REG_DVBS_UCB2_1  (0x6c)
770d788680SLuis Alves #define CX24117_REG_DVBS_UCB1_1  (0x6d)
780d788680SLuis Alves #define CX24117_REG_DVBS2_UCB2_1 (0x71)
790d788680SLuis Alves #define CX24117_REG_DVBS2_UCB1_1 (0x72)
800d788680SLuis Alves #define CX24117_REG_QSTATUS1     (0x9f)
810d788680SLuis Alves #define CX24117_REG_CLKDIV1      (0xe7)
820d788680SLuis Alves #define CX24117_REG_RATEDIV1     (0xf1)
830d788680SLuis Alves 
840d788680SLuis Alves 
850d788680SLuis Alves /* arg buffer size */
860d788680SLuis Alves #define CX24117_ARGLEN       (0x1e)
870d788680SLuis Alves 
880d788680SLuis Alves /* rolloff */
890d788680SLuis Alves #define CX24117_ROLLOFF_020  (0x00)
900d788680SLuis Alves #define CX24117_ROLLOFF_025  (0x01)
910d788680SLuis Alves #define CX24117_ROLLOFF_035  (0x02)
920d788680SLuis Alves 
930d788680SLuis Alves /* pilot bit */
940d788680SLuis Alves #define CX24117_PILOT_OFF    (0x00)
950d788680SLuis Alves #define CX24117_PILOT_ON     (0x40)
960d788680SLuis Alves #define CX24117_PILOT_AUTO   (0x80)
970d788680SLuis Alves 
980d788680SLuis Alves /* signal status */
990d788680SLuis Alves #define CX24117_HAS_SIGNAL   (0x01)
1000d788680SLuis Alves #define CX24117_HAS_CARRIER  (0x02)
1010d788680SLuis Alves #define CX24117_HAS_VITERBI  (0x04)
1020d788680SLuis Alves #define CX24117_HAS_SYNCLOCK (0x08)
1030d788680SLuis Alves #define CX24117_STATUS_MASK  (0x0f)
1040d788680SLuis Alves #define CX24117_SIGNAL_MASK  (0xc0)
1050d788680SLuis Alves 
1060d788680SLuis Alves 
1070d788680SLuis Alves /* arg offset for DiSEqC */
1080d788680SLuis Alves #define CX24117_DISEQC_DEMOD  (1)
1090d788680SLuis Alves #define CX24117_DISEQC_BURST  (2)
1100d788680SLuis Alves #define CX24117_DISEQC_ARG3_2 (3)   /* unknown value=2 */
1110d788680SLuis Alves #define CX24117_DISEQC_ARG4_0 (4)   /* unknown value=0 */
1120d788680SLuis Alves #define CX24117_DISEQC_ARG5_0 (5)   /* unknown value=0 */
1130d788680SLuis Alves #define CX24117_DISEQC_MSGLEN (6)
1140d788680SLuis Alves #define CX24117_DISEQC_MSGOFS (7)
1150d788680SLuis Alves 
1160d788680SLuis Alves /* DiSEqC burst */
1170d788680SLuis Alves #define CX24117_DISEQC_MINI_A (0)
1180d788680SLuis Alves #define CX24117_DISEQC_MINI_B (1)
1190d788680SLuis Alves 
1200d788680SLuis Alves 
1210d788680SLuis Alves #define CX24117_PNE	(0) /* 0 disabled / 2 enabled */
1220d788680SLuis Alves #define CX24117_OCC	(1) /* 0 disabled / 1 enabled */
1230d788680SLuis Alves 
1240d788680SLuis Alves 
1250d788680SLuis Alves enum cmds {
1269fa7c419SLuis Alves 	CMD_SET_VCOFREQ    = 0x10,
1270d788680SLuis Alves 	CMD_TUNEREQUEST    = 0x11,
1289fa7c419SLuis Alves 	CMD_GLOBAL_MPEGCFG = 0x13,
1299fa7c419SLuis Alves 	CMD_MPEGCFG        = 0x14,
1309fa7c419SLuis Alves 	CMD_TUNERINIT      = 0x15,
1319fa7c419SLuis Alves 	CMD_GET_SRATE      = 0x18,
1329fa7c419SLuis Alves 	CMD_SET_GOLDCODE   = 0x19,
1339fa7c419SLuis Alves 	CMD_GET_AGCACC     = 0x1a,
1349fa7c419SLuis Alves 	CMD_DEMODINIT      = 0x1b,
1359fa7c419SLuis Alves 	CMD_GETCTLACC      = 0x1c,
1369fa7c419SLuis Alves 
1379fa7c419SLuis Alves 	CMD_LNBCONFIG      = 0x20,
1389fa7c419SLuis Alves 	CMD_LNBSEND        = 0x21,
1390d788680SLuis Alves 	CMD_LNBDCLEVEL     = 0x22,
1409fa7c419SLuis Alves 	CMD_LNBPCBCONFIG   = 0x23,
1419fa7c419SLuis Alves 	CMD_LNBSENDTONEBST = 0x24,
1429fa7c419SLuis Alves 	CMD_LNBUPDREPLY    = 0x25,
1439fa7c419SLuis Alves 
1449fa7c419SLuis Alves 	CMD_SET_GPIOMODE   = 0x30,
1459fa7c419SLuis Alves 	CMD_SET_GPIOEN     = 0x31,
1469fa7c419SLuis Alves 	CMD_SET_GPIODIR    = 0x32,
1479fa7c419SLuis Alves 	CMD_SET_GPIOOUT    = 0x33,
1489fa7c419SLuis Alves 	CMD_ENABLERSCORR   = 0x34,
1499fa7c419SLuis Alves 	CMD_FWVERSION      = 0x35,
1509fa7c419SLuis Alves 	CMD_SET_SLEEPMODE  = 0x36,
1519fa7c419SLuis Alves 	CMD_BERCTRL        = 0x3c,
1529fa7c419SLuis Alves 	CMD_EVENTCTRL      = 0x3d,
1530d788680SLuis Alves };
1540d788680SLuis Alves 
155d10e8280SLuis Alves static LIST_HEAD(hybrid_tuner_instance_list);
156d10e8280SLuis Alves static DEFINE_MUTEX(cx24117_list_mutex);
157d10e8280SLuis Alves 
1580d788680SLuis Alves /* The Demod/Tuner can't easily provide these, we cache them */
1590d788680SLuis Alves struct cx24117_tuning {
1600d788680SLuis Alves 	u32 frequency;
1610d788680SLuis Alves 	u32 symbol_rate;
1620df289a2SMauro Carvalho Chehab 	enum fe_spectral_inversion inversion;
1630df289a2SMauro Carvalho Chehab 	enum fe_code_rate fec;
1640d788680SLuis Alves 
1650df289a2SMauro Carvalho Chehab 	enum fe_delivery_system delsys;
1660df289a2SMauro Carvalho Chehab 	enum fe_modulation modulation;
1670df289a2SMauro Carvalho Chehab 	enum fe_pilot pilot;
1680df289a2SMauro Carvalho Chehab 	enum fe_rolloff rolloff;
1690d788680SLuis Alves 
1700d788680SLuis Alves 	/* Demod values */
1710d788680SLuis Alves 	u8 fec_val;
1720d788680SLuis Alves 	u8 fec_mask;
1730d788680SLuis Alves 	u8 inversion_val;
1740d788680SLuis Alves 	u8 pilot_val;
1750d788680SLuis Alves 	u8 rolloff_val;
1760d788680SLuis Alves };
1770d788680SLuis Alves 
1780d788680SLuis Alves /* Basic commands that are sent to the firmware */
1790d788680SLuis Alves struct cx24117_cmd {
1800d788680SLuis Alves 	u8 len;
1810d788680SLuis Alves 	u8 args[CX24117_ARGLEN];
1820d788680SLuis Alves };
1830d788680SLuis Alves 
1840d788680SLuis Alves /* common to both fe's */
1850d788680SLuis Alves struct cx24117_priv {
1860d788680SLuis Alves 	u8 demod_address;
1870d788680SLuis Alves 	struct i2c_adapter *i2c;
1880d788680SLuis Alves 	u8 skip_fw_load;
1890d788680SLuis Alves 	struct mutex fe_lock;
190d10e8280SLuis Alves 
191d10e8280SLuis Alves 	/* Used for sharing this struct between demods */
192d10e8280SLuis Alves 	struct tuner_i2c_props i2c_props;
193d10e8280SLuis Alves 	struct list_head hybrid_tuner_instance_list;
1940d788680SLuis Alves };
1950d788680SLuis Alves 
1960d788680SLuis Alves /* one per each fe */
1970d788680SLuis Alves struct cx24117_state {
1980d788680SLuis Alves 	struct cx24117_priv *priv;
1990d788680SLuis Alves 	struct dvb_frontend frontend;
2000d788680SLuis Alves 
2010d788680SLuis Alves 	struct cx24117_tuning dcur;
2020d788680SLuis Alves 	struct cx24117_tuning dnxt;
2030d788680SLuis Alves 	struct cx24117_cmd dsec_cmd;
2040d788680SLuis Alves 
2050d788680SLuis Alves 	int demod;
2060d788680SLuis Alves };
2070d788680SLuis Alves 
2080d788680SLuis Alves /* modfec (modulation and FEC) lookup table */
2090d788680SLuis Alves /* Check cx24116.c for a detailed description of each field */
2100d788680SLuis Alves static struct cx24117_modfec {
2110df289a2SMauro Carvalho Chehab 	enum fe_delivery_system delivery_system;
2120df289a2SMauro Carvalho Chehab 	enum fe_modulation modulation;
2130df289a2SMauro Carvalho Chehab 	enum fe_code_rate fec;
2140d788680SLuis Alves 	u8 mask;	/* In DVBS mode this is used to autodetect */
2150d788680SLuis Alves 	u8 val;		/* Passed to the firmware to indicate mode selection */
2160d788680SLuis Alves } cx24117_modfec_modes[] = {
2170d788680SLuis Alves 	/* QPSK. For unknown rates we set hardware to auto detect 0xfe 0x30 */
2180d788680SLuis Alves 
2190d788680SLuis Alves 	/*mod   fec       mask  val */
2200d788680SLuis Alves 	{ SYS_DVBS, QPSK, FEC_NONE, 0xfe, 0x30 },
2210d788680SLuis Alves 	{ SYS_DVBS, QPSK, FEC_1_2,  0x02, 0x2e }, /* 00000010 00101110 */
2220d788680SLuis Alves 	{ SYS_DVBS, QPSK, FEC_2_3,  0x04, 0x2f }, /* 00000100 00101111 */
2230d788680SLuis Alves 	{ SYS_DVBS, QPSK, FEC_3_4,  0x08, 0x30 }, /* 00001000 00110000 */
2240d788680SLuis Alves 	{ SYS_DVBS, QPSK, FEC_4_5,  0xfe, 0x30 }, /* 000?0000 ?        */
2250d788680SLuis Alves 	{ SYS_DVBS, QPSK, FEC_5_6,  0x20, 0x31 }, /* 00100000 00110001 */
2260d788680SLuis Alves 	{ SYS_DVBS, QPSK, FEC_6_7,  0xfe, 0x30 }, /* 0?000000 ?        */
2270d788680SLuis Alves 	{ SYS_DVBS, QPSK, FEC_7_8,  0x80, 0x32 }, /* 10000000 00110010 */
2280d788680SLuis Alves 	{ SYS_DVBS, QPSK, FEC_8_9,  0xfe, 0x30 }, /* 0000000? ?        */
2290d788680SLuis Alves 	{ SYS_DVBS, QPSK, FEC_AUTO, 0xfe, 0x30 },
2300d788680SLuis Alves 	/* NBC-QPSK */
2310d788680SLuis Alves 	{ SYS_DVBS2, QPSK, FEC_NONE, 0x00, 0x00 },
2320d788680SLuis Alves 	{ SYS_DVBS2, QPSK, FEC_1_2,  0x00, 0x04 },
2330d788680SLuis Alves 	{ SYS_DVBS2, QPSK, FEC_3_5,  0x00, 0x05 },
2340d788680SLuis Alves 	{ SYS_DVBS2, QPSK, FEC_2_3,  0x00, 0x06 },
2350d788680SLuis Alves 	{ SYS_DVBS2, QPSK, FEC_3_4,  0x00, 0x07 },
2360d788680SLuis Alves 	{ SYS_DVBS2, QPSK, FEC_4_5,  0x00, 0x08 },
2370d788680SLuis Alves 	{ SYS_DVBS2, QPSK, FEC_5_6,  0x00, 0x09 },
2380d788680SLuis Alves 	{ SYS_DVBS2, QPSK, FEC_8_9,  0x00, 0x0a },
2390d788680SLuis Alves 	{ SYS_DVBS2, QPSK, FEC_9_10, 0x00, 0x0b },
2400d788680SLuis Alves 	{ SYS_DVBS2, QPSK, FEC_AUTO, 0x00, 0x00 },
2410d788680SLuis Alves 	/* 8PSK */
2420d788680SLuis Alves 	{ SYS_DVBS2, PSK_8, FEC_NONE, 0x00, 0x00 },
2430d788680SLuis Alves 	{ SYS_DVBS2, PSK_8, FEC_3_5,  0x00, 0x0c },
2440d788680SLuis Alves 	{ SYS_DVBS2, PSK_8, FEC_2_3,  0x00, 0x0d },
2450d788680SLuis Alves 	{ SYS_DVBS2, PSK_8, FEC_3_4,  0x00, 0x0e },
2460d788680SLuis Alves 	{ SYS_DVBS2, PSK_8, FEC_5_6,  0x00, 0x0f },
2470d788680SLuis Alves 	{ SYS_DVBS2, PSK_8, FEC_8_9,  0x00, 0x10 },
2480d788680SLuis Alves 	{ SYS_DVBS2, PSK_8, FEC_9_10, 0x00, 0x11 },
2490d788680SLuis Alves 	{ SYS_DVBS2, PSK_8, FEC_AUTO, 0x00, 0x00 },
2500d788680SLuis Alves 	/*
2510d788680SLuis Alves 	 * 'val' can be found in the FECSTATUS register when tuning.
2520d788680SLuis Alves 	 * FECSTATUS will give the actual FEC in use if tuning was successful.
2530d788680SLuis Alves 	 */
2540d788680SLuis Alves };
2550d788680SLuis Alves 
2560d788680SLuis Alves 
cx24117_writereg(struct cx24117_state * state,u8 reg,u8 data)2570d788680SLuis Alves static int cx24117_writereg(struct cx24117_state *state, u8 reg, u8 data)
2580d788680SLuis Alves {
2590d788680SLuis Alves 	u8 buf[] = { reg, data };
2600d788680SLuis Alves 	struct i2c_msg msg = { .addr = state->priv->demod_address,
2610d788680SLuis Alves 		.flags = 0, .buf = buf, .len = 2 };
2620d788680SLuis Alves 	int ret;
2630d788680SLuis Alves 
2640d788680SLuis Alves 	dev_dbg(&state->priv->i2c->dev,
2650d788680SLuis Alves 			"%s() demod%d i2c wr @0x%02x=0x%02x\n",
2660d788680SLuis Alves 			__func__, state->demod, reg, data);
2670d788680SLuis Alves 
2680d788680SLuis Alves 	ret = i2c_transfer(state->priv->i2c, &msg, 1);
2690d788680SLuis Alves 	if (ret < 0) {
2700d788680SLuis Alves 		dev_warn(&state->priv->i2c->dev,
2710d788680SLuis Alves 			"%s: demod%d i2c wr err(%i) @0x%02x=0x%02x\n",
2720d788680SLuis Alves 			KBUILD_MODNAME, state->demod, ret, reg, data);
2730d788680SLuis Alves 		return ret;
2740d788680SLuis Alves 	}
2750d788680SLuis Alves 	return 0;
2760d788680SLuis Alves }
2770d788680SLuis Alves 
cx24117_writecmd(struct cx24117_state * state,struct cx24117_cmd * cmd)2780d788680SLuis Alves static int cx24117_writecmd(struct cx24117_state *state,
2790d788680SLuis Alves 	struct cx24117_cmd *cmd)
2800d788680SLuis Alves {
2810d788680SLuis Alves 	struct i2c_msg msg;
2820d788680SLuis Alves 	u8 buf[CX24117_ARGLEN+1];
2830d788680SLuis Alves 	int ret;
2840d788680SLuis Alves 
2850d788680SLuis Alves 	dev_dbg(&state->priv->i2c->dev,
2860d788680SLuis Alves 			"%s() demod%d i2c wr cmd len=%d\n",
2870d788680SLuis Alves 			__func__, state->demod, cmd->len);
2880d788680SLuis Alves 
2890d788680SLuis Alves 	buf[0] = CX24117_REG_COMMAND;
2900d788680SLuis Alves 	memcpy(&buf[1], cmd->args, cmd->len);
2910d788680SLuis Alves 
2920d788680SLuis Alves 	msg.addr = state->priv->demod_address;
2930d788680SLuis Alves 	msg.flags = 0;
2940d788680SLuis Alves 	msg.len = cmd->len+1;
2950d788680SLuis Alves 	msg.buf = buf;
2960d788680SLuis Alves 	ret = i2c_transfer(state->priv->i2c, &msg, 1);
2970d788680SLuis Alves 	if (ret < 0) {
2980d788680SLuis Alves 		dev_warn(&state->priv->i2c->dev,
2990d788680SLuis Alves 			"%s: demod%d i2c wr cmd err(%i) len=%d\n",
3000d788680SLuis Alves 			KBUILD_MODNAME, state->demod, ret, cmd->len);
3010d788680SLuis Alves 		return ret;
3020d788680SLuis Alves 	}
3030d788680SLuis Alves 	return 0;
3040d788680SLuis Alves }
3050d788680SLuis Alves 
cx24117_readreg(struct cx24117_state * state,u8 reg)3060d788680SLuis Alves static int cx24117_readreg(struct cx24117_state *state, u8 reg)
3070d788680SLuis Alves {
3080d788680SLuis Alves 	int ret;
3090d788680SLuis Alves 	u8 recv = 0;
3100d788680SLuis Alves 	struct i2c_msg msg[] = {
3110d788680SLuis Alves 		{ .addr = state->priv->demod_address, .flags = 0,
3120d788680SLuis Alves 			.buf = &reg, .len = 1 },
3130d788680SLuis Alves 		{ .addr = state->priv->demod_address, .flags = I2C_M_RD,
3140d788680SLuis Alves 			.buf = &recv, .len = 1 }
3150d788680SLuis Alves 	};
3160d788680SLuis Alves 
3170d788680SLuis Alves 	ret = i2c_transfer(state->priv->i2c, msg, 2);
3180d788680SLuis Alves 	if (ret < 0) {
3190d788680SLuis Alves 		dev_warn(&state->priv->i2c->dev,
3200d788680SLuis Alves 			"%s: demod%d i2c rd err(%d) @0x%x\n",
3210d788680SLuis Alves 			KBUILD_MODNAME, state->demod, ret, reg);
3220d788680SLuis Alves 		return ret;
3230d788680SLuis Alves 	}
3240d788680SLuis Alves 
3250d788680SLuis Alves 	dev_dbg(&state->priv->i2c->dev, "%s() demod%d i2c rd @0x%02x=0x%02x\n",
3260d788680SLuis Alves 		__func__, state->demod, reg, recv);
3270d788680SLuis Alves 
3280d788680SLuis Alves 	return recv;
3290d788680SLuis Alves }
3300d788680SLuis Alves 
cx24117_readregN(struct cx24117_state * state,u8 reg,u8 * buf,int len)3310d788680SLuis Alves static int cx24117_readregN(struct cx24117_state *state,
3320d788680SLuis Alves 	u8 reg, u8 *buf, int len)
3330d788680SLuis Alves {
3340d788680SLuis Alves 	int ret;
3350d788680SLuis Alves 	struct i2c_msg msg[] = {
3360d788680SLuis Alves 		{ .addr = state->priv->demod_address, .flags = 0,
3370d788680SLuis Alves 			.buf = &reg, .len = 1 },
3380d788680SLuis Alves 		{ .addr = state->priv->demod_address, .flags = I2C_M_RD,
3390d788680SLuis Alves 			.buf = buf, .len = len }
3400d788680SLuis Alves 	};
3410d788680SLuis Alves 
3420d788680SLuis Alves 	ret = i2c_transfer(state->priv->i2c, msg, 2);
3430d788680SLuis Alves 	if (ret < 0) {
3440d788680SLuis Alves 		dev_warn(&state->priv->i2c->dev,
3450d788680SLuis Alves 			"%s: demod%d i2c rd err(%d) @0x%x\n",
3460d788680SLuis Alves 			KBUILD_MODNAME, state->demod, ret, reg);
3470d788680SLuis Alves 		return ret;
3480d788680SLuis Alves 	}
3490d788680SLuis Alves 	return 0;
3500d788680SLuis Alves }
3510d788680SLuis Alves 
cx24117_set_inversion(struct cx24117_state * state,enum fe_spectral_inversion inversion)3520d788680SLuis Alves static int cx24117_set_inversion(struct cx24117_state *state,
3530df289a2SMauro Carvalho Chehab 	enum fe_spectral_inversion inversion)
3540d788680SLuis Alves {
3550d788680SLuis Alves 	dev_dbg(&state->priv->i2c->dev, "%s(%d) demod%d\n",
3560d788680SLuis Alves 		__func__, inversion, state->demod);
3570d788680SLuis Alves 
3580d788680SLuis Alves 	switch (inversion) {
3590d788680SLuis Alves 	case INVERSION_OFF:
3600d788680SLuis Alves 		state->dnxt.inversion_val = 0x00;
3610d788680SLuis Alves 		break;
3620d788680SLuis Alves 	case INVERSION_ON:
3630d788680SLuis Alves 		state->dnxt.inversion_val = 0x04;
3640d788680SLuis Alves 		break;
3650d788680SLuis Alves 	case INVERSION_AUTO:
3660d788680SLuis Alves 		state->dnxt.inversion_val = 0x0C;
3670d788680SLuis Alves 		break;
3680d788680SLuis Alves 	default:
3690d788680SLuis Alves 		return -EINVAL;
3700d788680SLuis Alves 	}
3710d788680SLuis Alves 
3720d788680SLuis Alves 	state->dnxt.inversion = inversion;
3730d788680SLuis Alves 
3740d788680SLuis Alves 	return 0;
3750d788680SLuis Alves }
3760d788680SLuis Alves 
cx24117_lookup_fecmod(struct cx24117_state * state,enum fe_delivery_system d,enum fe_modulation m,enum fe_code_rate f)3770d788680SLuis Alves static int cx24117_lookup_fecmod(struct cx24117_state *state,
3780df289a2SMauro Carvalho Chehab 	enum fe_delivery_system d, enum fe_modulation m, enum fe_code_rate f)
3790d788680SLuis Alves {
3800d788680SLuis Alves 	int i, ret = -EINVAL;
3810d788680SLuis Alves 
3820d788680SLuis Alves 	dev_dbg(&state->priv->i2c->dev,
3830d788680SLuis Alves 		"%s(demod(0x%02x,0x%02x) demod%d\n",
3840d788680SLuis Alves 		__func__, m, f, state->demod);
3850d788680SLuis Alves 
3860d788680SLuis Alves 	for (i = 0; i < ARRAY_SIZE(cx24117_modfec_modes); i++) {
3870d788680SLuis Alves 		if ((d == cx24117_modfec_modes[i].delivery_system) &&
3880d788680SLuis Alves 			(m == cx24117_modfec_modes[i].modulation) &&
3890d788680SLuis Alves 			(f == cx24117_modfec_modes[i].fec)) {
3900d788680SLuis Alves 				ret = i;
3910d788680SLuis Alves 				break;
3920d788680SLuis Alves 			}
3930d788680SLuis Alves 	}
3940d788680SLuis Alves 
3950d788680SLuis Alves 	return ret;
3960d788680SLuis Alves }
3970d788680SLuis Alves 
cx24117_set_fec(struct cx24117_state * state,enum fe_delivery_system delsys,enum fe_modulation mod,enum fe_code_rate fec)3980d788680SLuis Alves static int cx24117_set_fec(struct cx24117_state *state,
3990df289a2SMauro Carvalho Chehab 			   enum fe_delivery_system delsys,
4000df289a2SMauro Carvalho Chehab 			   enum fe_modulation mod,
4010df289a2SMauro Carvalho Chehab 			   enum fe_code_rate fec)
4020d788680SLuis Alves {
4030d788680SLuis Alves 	int ret;
4040d788680SLuis Alves 
4050d788680SLuis Alves 	dev_dbg(&state->priv->i2c->dev,
4060d788680SLuis Alves 		"%s(0x%02x,0x%02x) demod%d\n",
4070d788680SLuis Alves 		__func__, mod, fec, state->demod);
4080d788680SLuis Alves 
4090d788680SLuis Alves 	ret = cx24117_lookup_fecmod(state, delsys, mod, fec);
4100d788680SLuis Alves 	if (ret < 0)
4110d788680SLuis Alves 		return ret;
4120d788680SLuis Alves 
4130d788680SLuis Alves 	state->dnxt.fec = fec;
4140d788680SLuis Alves 	state->dnxt.fec_val = cx24117_modfec_modes[ret].val;
4150d788680SLuis Alves 	state->dnxt.fec_mask = cx24117_modfec_modes[ret].mask;
4160d788680SLuis Alves 	dev_dbg(&state->priv->i2c->dev,
4170d788680SLuis Alves 		"%s() demod%d mask/val = 0x%02x/0x%02x\n", __func__,
4180d788680SLuis Alves 		state->demod, state->dnxt.fec_mask, state->dnxt.fec_val);
4190d788680SLuis Alves 
4200d788680SLuis Alves 	return 0;
4210d788680SLuis Alves }
4220d788680SLuis Alves 
cx24117_set_symbolrate(struct cx24117_state * state,u32 rate)4230d788680SLuis Alves static int cx24117_set_symbolrate(struct cx24117_state *state, u32 rate)
4240d788680SLuis Alves {
4250d788680SLuis Alves 	dev_dbg(&state->priv->i2c->dev, "%s(%d) demod%d\n",
4260d788680SLuis Alves 		__func__, rate, state->demod);
4270d788680SLuis Alves 
4280d788680SLuis Alves 	state->dnxt.symbol_rate = rate;
4290d788680SLuis Alves 
4300d788680SLuis Alves 	dev_dbg(&state->priv->i2c->dev,
4310d788680SLuis Alves 		"%s() demod%d symbol_rate = %d\n",
4320d788680SLuis Alves 		__func__, state->demod, rate);
4330d788680SLuis Alves 
4340d788680SLuis Alves 	return 0;
4350d788680SLuis Alves }
4360d788680SLuis Alves 
4370d788680SLuis Alves static int cx24117_load_firmware(struct dvb_frontend *fe,
4380d788680SLuis Alves 	const struct firmware *fw);
4390d788680SLuis Alves 
cx24117_firmware_ondemand(struct dvb_frontend * fe)4400d788680SLuis Alves static int cx24117_firmware_ondemand(struct dvb_frontend *fe)
4410d788680SLuis Alves {
4420d788680SLuis Alves 	struct cx24117_state *state = fe->demodulator_priv;
4430d788680SLuis Alves 	const struct firmware *fw;
4440d788680SLuis Alves 	int ret = 0;
4450d788680SLuis Alves 
4460d788680SLuis Alves 	dev_dbg(&state->priv->i2c->dev, "%s() demod%d skip_fw_load=%d\n",
4470d788680SLuis Alves 		__func__, state->demod, state->priv->skip_fw_load);
4480d788680SLuis Alves 
4490d788680SLuis Alves 	if (state->priv->skip_fw_load)
4500d788680SLuis Alves 		return 0;
4510d788680SLuis Alves 
452510cb39cSGeert Uytterhoeven 	/* check if firmware is already running */
4530d788680SLuis Alves 	if (cx24117_readreg(state, 0xeb) != 0xa) {
4540d788680SLuis Alves 		/* Load firmware */
4550d788680SLuis Alves 		/* request the firmware, this will block until loaded */
4560d788680SLuis Alves 		dev_dbg(&state->priv->i2c->dev,
4570d788680SLuis Alves 			"%s: Waiting for firmware upload (%s)...\n",
4580d788680SLuis Alves 			__func__, CX24117_DEFAULT_FIRMWARE);
4590d788680SLuis Alves 		ret = request_firmware(&fw, CX24117_DEFAULT_FIRMWARE,
4600d788680SLuis Alves 			state->priv->i2c->dev.parent);
4610d788680SLuis Alves 		dev_dbg(&state->priv->i2c->dev,
4620d788680SLuis Alves 			"%s: Waiting for firmware upload(2)...\n", __func__);
4630d788680SLuis Alves 		if (ret) {
4640d788680SLuis Alves 			dev_err(&state->priv->i2c->dev,
4654bd69e7bSMauro Carvalho Chehab 				"%s: No firmware uploaded (timeout or file not found?)\n",
4664bd69e7bSMauro Carvalho Chehab __func__);
4670d788680SLuis Alves 			return ret;
4680d788680SLuis Alves 		}
4690d788680SLuis Alves 
4700d788680SLuis Alves 		/* Make sure we don't recurse back through here
4710d788680SLuis Alves 		 * during loading */
4720d788680SLuis Alves 		state->priv->skip_fw_load = 1;
4730d788680SLuis Alves 
4740d788680SLuis Alves 		ret = cx24117_load_firmware(fe, fw);
4750d788680SLuis Alves 		if (ret)
4760d788680SLuis Alves 			dev_err(&state->priv->i2c->dev,
4770d788680SLuis Alves 				"%s: Writing firmware failed\n", __func__);
4780d788680SLuis Alves 		release_firmware(fw);
4790d788680SLuis Alves 
4800d788680SLuis Alves 		dev_info(&state->priv->i2c->dev,
4810d788680SLuis Alves 			"%s: Firmware upload %s\n", __func__,
4820d788680SLuis Alves 			ret == 0 ? "complete" : "failed");
4830d788680SLuis Alves 
4840d788680SLuis Alves 		/* Ensure firmware is always loaded if required */
4850d788680SLuis Alves 		state->priv->skip_fw_load = 0;
4860d788680SLuis Alves 	}
4870d788680SLuis Alves 
4880d788680SLuis Alves 	return ret;
4890d788680SLuis Alves }
4900d788680SLuis Alves 
4910d788680SLuis Alves /* Take a basic firmware command structure, format it
4920d788680SLuis Alves  * and forward it for processing
4930d788680SLuis Alves  */
cx24117_cmd_execute_nolock(struct dvb_frontend * fe,struct cx24117_cmd * cmd)4940d788680SLuis Alves static int cx24117_cmd_execute_nolock(struct dvb_frontend *fe,
4950d788680SLuis Alves 	struct cx24117_cmd *cmd)
4960d788680SLuis Alves {
4970d788680SLuis Alves 	struct cx24117_state *state = fe->demodulator_priv;
4980d788680SLuis Alves 	int i, ret;
4990d788680SLuis Alves 
5000d788680SLuis Alves 	dev_dbg(&state->priv->i2c->dev, "%s() demod%d\n",
5010d788680SLuis Alves 		__func__, state->demod);
5020d788680SLuis Alves 
5030d788680SLuis Alves 	/* Load the firmware if required */
5040d788680SLuis Alves 	ret = cx24117_firmware_ondemand(fe);
5050d788680SLuis Alves 	if (ret != 0)
5060d788680SLuis Alves 		return ret;
5070d788680SLuis Alves 
5080d788680SLuis Alves 	/* Write the command */
5090d788680SLuis Alves 	cx24117_writecmd(state, cmd);
5100d788680SLuis Alves 
5110d788680SLuis Alves 	/* Start execution and wait for cmd to terminate */
5120d788680SLuis Alves 	cx24117_writereg(state, CX24117_REG_EXECUTE, 0x01);
5130d788680SLuis Alves 	i = 0;
5140d788680SLuis Alves 	while (cx24117_readreg(state, CX24117_REG_EXECUTE)) {
5150d788680SLuis Alves 		msleep(20);
5160d788680SLuis Alves 		if (i++ > 40) {
5170d788680SLuis Alves 			/* Avoid looping forever if the firmware does
5180d788680SLuis Alves 				not respond */
5190d788680SLuis Alves 			dev_warn(&state->priv->i2c->dev,
5200d788680SLuis Alves 				"%s() Firmware not responding\n", __func__);
5210d788680SLuis Alves 			return -EIO;
5220d788680SLuis Alves 		}
5230d788680SLuis Alves 	}
5240d788680SLuis Alves 	return 0;
5250d788680SLuis Alves }
5260d788680SLuis Alves 
cx24117_cmd_execute(struct dvb_frontend * fe,struct cx24117_cmd * cmd)5270d788680SLuis Alves static int cx24117_cmd_execute(struct dvb_frontend *fe, struct cx24117_cmd *cmd)
5280d788680SLuis Alves {
5290d788680SLuis Alves 	struct cx24117_state *state = fe->demodulator_priv;
5300d788680SLuis Alves 	int ret;
5310d788680SLuis Alves 
5320d788680SLuis Alves 	mutex_lock(&state->priv->fe_lock);
5330d788680SLuis Alves 	ret = cx24117_cmd_execute_nolock(fe, cmd);
5340d788680SLuis Alves 	mutex_unlock(&state->priv->fe_lock);
5350d788680SLuis Alves 
5360d788680SLuis Alves 	return ret;
5370d788680SLuis Alves }
5380d788680SLuis Alves 
cx24117_load_firmware(struct dvb_frontend * fe,const struct firmware * fw)5390d788680SLuis Alves static int cx24117_load_firmware(struct dvb_frontend *fe,
5400d788680SLuis Alves 	const struct firmware *fw)
5410d788680SLuis Alves {
5420d788680SLuis Alves 	struct cx24117_state *state = fe->demodulator_priv;
5430d788680SLuis Alves 	struct cx24117_cmd cmd;
5440d788680SLuis Alves 	int i, ret;
5450d788680SLuis Alves 	unsigned char vers[4];
5460d788680SLuis Alves 
5470d788680SLuis Alves 	struct i2c_msg msg;
5480d788680SLuis Alves 	u8 *buf;
5490d788680SLuis Alves 
5500d788680SLuis Alves 	dev_dbg(&state->priv->i2c->dev,
5510d788680SLuis Alves 		"%s() demod%d FW is %zu bytes (%02x %02x .. %02x %02x)\n",
5520d788680SLuis Alves 		__func__, state->demod, fw->size, fw->data[0], fw->data[1],
5530d788680SLuis Alves 		fw->data[fw->size - 2], fw->data[fw->size - 1]);
5540d788680SLuis Alves 
5550d788680SLuis Alves 	cx24117_writereg(state, 0xea, 0x00);
5560d788680SLuis Alves 	cx24117_writereg(state, 0xea, 0x01);
5570d788680SLuis Alves 	cx24117_writereg(state, 0xea, 0x00);
5580d788680SLuis Alves 
5590d788680SLuis Alves 	cx24117_writereg(state, 0xce, 0x92);
5600d788680SLuis Alves 
5610d788680SLuis Alves 	cx24117_writereg(state, 0xfb, 0x00);
5620d788680SLuis Alves 	cx24117_writereg(state, 0xfc, 0x00);
5630d788680SLuis Alves 
5640d788680SLuis Alves 	cx24117_writereg(state, 0xc3, 0x04);
5650d788680SLuis Alves 	cx24117_writereg(state, 0xc4, 0x04);
5660d788680SLuis Alves 
5670d788680SLuis Alves 	cx24117_writereg(state, 0xce, 0x00);
5680d788680SLuis Alves 	cx24117_writereg(state, 0xcf, 0x00);
5690d788680SLuis Alves 
5700d788680SLuis Alves 	cx24117_writereg(state, 0xea, 0x00);
5710d788680SLuis Alves 	cx24117_writereg(state, 0xeb, 0x0c);
5720d788680SLuis Alves 	cx24117_writereg(state, 0xec, 0x06);
5730d788680SLuis Alves 	cx24117_writereg(state, 0xed, 0x05);
5740d788680SLuis Alves 	cx24117_writereg(state, 0xee, 0x03);
5750d788680SLuis Alves 	cx24117_writereg(state, 0xef, 0x05);
5760d788680SLuis Alves 
5770d788680SLuis Alves 	cx24117_writereg(state, 0xf3, 0x03);
5780d788680SLuis Alves 	cx24117_writereg(state, 0xf4, 0x44);
5790d788680SLuis Alves 
5800d788680SLuis Alves 	cx24117_writereg(state, CX24117_REG_RATEDIV0, 0x04);
5810d788680SLuis Alves 	cx24117_writereg(state, CX24117_REG_CLKDIV0, 0x02);
5820d788680SLuis Alves 
5830d788680SLuis Alves 	cx24117_writereg(state, CX24117_REG_RATEDIV1, 0x04);
5840d788680SLuis Alves 	cx24117_writereg(state, CX24117_REG_CLKDIV1, 0x02);
5850d788680SLuis Alves 
5860d788680SLuis Alves 	cx24117_writereg(state, 0xf2, 0x04);
5870d788680SLuis Alves 	cx24117_writereg(state, 0xe8, 0x02);
5880d788680SLuis Alves 	cx24117_writereg(state, 0xea, 0x01);
5890d788680SLuis Alves 	cx24117_writereg(state, 0xc8, 0x00);
5900d788680SLuis Alves 	cx24117_writereg(state, 0xc9, 0x00);
5910d788680SLuis Alves 	cx24117_writereg(state, 0xca, 0x00);
5920d788680SLuis Alves 	cx24117_writereg(state, 0xcb, 0x00);
5930d788680SLuis Alves 	cx24117_writereg(state, 0xcc, 0x00);
5940d788680SLuis Alves 	cx24117_writereg(state, 0xcd, 0x00);
5950d788680SLuis Alves 	cx24117_writereg(state, 0xe4, 0x03);
5960d788680SLuis Alves 	cx24117_writereg(state, 0xeb, 0x0a);
5970d788680SLuis Alves 
5980d788680SLuis Alves 	cx24117_writereg(state, 0xfb, 0x00);
5990d788680SLuis Alves 	cx24117_writereg(state, 0xe0, 0x76);
6000d788680SLuis Alves 	cx24117_writereg(state, 0xf7, 0x81);
6010d788680SLuis Alves 	cx24117_writereg(state, 0xf8, 0x00);
6020d788680SLuis Alves 	cx24117_writereg(state, 0xf9, 0x00);
6030d788680SLuis Alves 
6040d788680SLuis Alves 	buf = kmalloc(fw->size + 1, GFP_KERNEL);
6050d788680SLuis Alves 	if (buf == NULL) {
6060d788680SLuis Alves 		state->priv->skip_fw_load = 0;
6070d788680SLuis Alves 		return -ENOMEM;
6080d788680SLuis Alves 	}
6090d788680SLuis Alves 
6100d788680SLuis Alves 	/* fw upload reg */
6110d788680SLuis Alves 	buf[0] = 0xfa;
6120d788680SLuis Alves 	memcpy(&buf[1], fw->data, fw->size);
6130d788680SLuis Alves 
6140d788680SLuis Alves 	/* prepare i2c message to send */
6150d788680SLuis Alves 	msg.addr = state->priv->demod_address;
6160d788680SLuis Alves 	msg.flags = 0;
6170d788680SLuis Alves 	msg.len = fw->size + 1;
6180d788680SLuis Alves 	msg.buf = buf;
6190d788680SLuis Alves 
6200d788680SLuis Alves 	/* send fw */
6210d788680SLuis Alves 	ret = i2c_transfer(state->priv->i2c, &msg, 1);
6222f6451edSWenwen Wang 	if (ret < 0) {
6232f6451edSWenwen Wang 		kfree(buf);
6240d788680SLuis Alves 		return ret;
6252f6451edSWenwen Wang 	}
6260d788680SLuis Alves 
6270d788680SLuis Alves 	kfree(buf);
6280d788680SLuis Alves 
6290d788680SLuis Alves 	cx24117_writereg(state, 0xf7, 0x0c);
6300d788680SLuis Alves 	cx24117_writereg(state, 0xe0, 0x00);
6310d788680SLuis Alves 
6329fa7c419SLuis Alves 	/* Init demodulator */
6339fa7c419SLuis Alves 	cmd.args[0] = CMD_DEMODINIT;
6340d788680SLuis Alves 	cmd.args[1] = 0x00;
6350d788680SLuis Alves 	cmd.args[2] = 0x01;
6360d788680SLuis Alves 	cmd.args[3] = 0x00;
6370d788680SLuis Alves 	cmd.len = 4;
6380d788680SLuis Alves 	ret = cx24117_cmd_execute_nolock(fe, &cmd);
6390d788680SLuis Alves 	if (ret != 0)
6400d788680SLuis Alves 		goto error;
6410d788680SLuis Alves 
6429fa7c419SLuis Alves 	/* Set VCO frequency */
6439fa7c419SLuis Alves 	cmd.args[0] = CMD_SET_VCOFREQ;
6440d788680SLuis Alves 	cmd.args[1] = 0x06;
6450d788680SLuis Alves 	cmd.args[2] = 0x2b;
6460d788680SLuis Alves 	cmd.args[3] = 0xd8;
6470d788680SLuis Alves 	cmd.args[4] = 0xa5;
6480d788680SLuis Alves 	cmd.args[5] = 0xee;
6490d788680SLuis Alves 	cmd.args[6] = 0x03;
6500d788680SLuis Alves 	cmd.args[7] = 0x9d;
6510d788680SLuis Alves 	cmd.args[8] = 0xfc;
6520d788680SLuis Alves 	cmd.args[9] = 0x06;
6530d788680SLuis Alves 	cmd.args[10] = 0x02;
6540d788680SLuis Alves 	cmd.args[11] = 0x9d;
6550d788680SLuis Alves 	cmd.args[12] = 0xfc;
6560d788680SLuis Alves 	cmd.len = 13;
6570d788680SLuis Alves 	ret = cx24117_cmd_execute_nolock(fe, &cmd);
6580d788680SLuis Alves 	if (ret != 0)
6590d788680SLuis Alves 		goto error;
6600d788680SLuis Alves 
6619fa7c419SLuis Alves 	/* Tuner init */
6629fa7c419SLuis Alves 	cmd.args[0] = CMD_TUNERINIT;
6630d788680SLuis Alves 	cmd.args[1] = 0x00;
6640d788680SLuis Alves 	cmd.args[2] = 0x01;
6650d788680SLuis Alves 	cmd.args[3] = 0x00;
6660d788680SLuis Alves 	cmd.args[4] = 0x00;
6670d788680SLuis Alves 	cmd.args[5] = 0x01;
6680d788680SLuis Alves 	cmd.args[6] = 0x01;
6690d788680SLuis Alves 	cmd.args[7] = 0x01;
6700d788680SLuis Alves 	cmd.args[8] = 0x00;
6710d788680SLuis Alves 	cmd.args[9] = 0x05;
6720d788680SLuis Alves 	cmd.args[10] = 0x02;
6730d788680SLuis Alves 	cmd.args[11] = 0x02;
6740d788680SLuis Alves 	cmd.args[12] = 0x00;
6750d788680SLuis Alves 	cmd.len = 13;
6760d788680SLuis Alves 	ret = cx24117_cmd_execute_nolock(fe, &cmd);
6770d788680SLuis Alves 	if (ret != 0)
6780d788680SLuis Alves 		goto error;
6790d788680SLuis Alves 
6809fa7c419SLuis Alves 	/* Global MPEG config */
6819fa7c419SLuis Alves 	cmd.args[0] = CMD_GLOBAL_MPEGCFG;
6820d788680SLuis Alves 	cmd.args[1] = 0x00;
6830d788680SLuis Alves 	cmd.args[2] = 0x00;
6840d788680SLuis Alves 	cmd.args[3] = 0x00;
6850d788680SLuis Alves 	cmd.args[4] = 0x01;
6860d788680SLuis Alves 	cmd.args[5] = 0x00;
6870d788680SLuis Alves 	cmd.len = 6;
6880d788680SLuis Alves 	ret = cx24117_cmd_execute_nolock(fe, &cmd);
6890d788680SLuis Alves 	if (ret != 0)
6900d788680SLuis Alves 		goto error;
6910d788680SLuis Alves 
6929fa7c419SLuis Alves 	/* MPEG config for each demod */
6930d788680SLuis Alves 	for (i = 0; i < 2; i++) {
6949fa7c419SLuis Alves 		cmd.args[0] = CMD_MPEGCFG;
6950d788680SLuis Alves 		cmd.args[1] = (u8) i;
6960d788680SLuis Alves 		cmd.args[2] = 0x00;
6970d788680SLuis Alves 		cmd.args[3] = 0x05;
6980d788680SLuis Alves 		cmd.args[4] = 0x00;
6990d788680SLuis Alves 		cmd.args[5] = 0x00;
7000d788680SLuis Alves 		cmd.args[6] = 0x55;
7010d788680SLuis Alves 		cmd.args[7] = 0x00;
7020d788680SLuis Alves 		cmd.len = 8;
7030d788680SLuis Alves 		ret = cx24117_cmd_execute_nolock(fe, &cmd);
7040d788680SLuis Alves 		if (ret != 0)
7050d788680SLuis Alves 			goto error;
7060d788680SLuis Alves 	}
7070d788680SLuis Alves 
7080d788680SLuis Alves 	cx24117_writereg(state, 0xce, 0xc0);
7090d788680SLuis Alves 	cx24117_writereg(state, 0xcf, 0x00);
7100d788680SLuis Alves 	cx24117_writereg(state, 0xe5, 0x04);
7110d788680SLuis Alves 
7129fa7c419SLuis Alves 	/* Get firmware version */
7139fa7c419SLuis Alves 	cmd.args[0] = CMD_FWVERSION;
7140d788680SLuis Alves 	cmd.len = 2;
7150d788680SLuis Alves 	for (i = 0; i < 4; i++) {
7160d788680SLuis Alves 		cmd.args[1] = i;
7170d788680SLuis Alves 		ret = cx24117_cmd_execute_nolock(fe, &cmd);
7180d788680SLuis Alves 		if (ret != 0)
7190d788680SLuis Alves 			goto error;
7200d788680SLuis Alves 		vers[i] = cx24117_readreg(state, 0x33);
7210d788680SLuis Alves 	}
7220d788680SLuis Alves 	dev_info(&state->priv->i2c->dev,
7230d788680SLuis Alves 		"%s: FW version %i.%i.%i.%i\n", __func__,
7240d788680SLuis Alves 		vers[0], vers[1], vers[2], vers[3]);
7250d788680SLuis Alves 	return 0;
7260d788680SLuis Alves error:
7270d788680SLuis Alves 	state->priv->skip_fw_load = 0;
7280d788680SLuis Alves 	dev_err(&state->priv->i2c->dev, "%s() Error running FW.\n", __func__);
7290d788680SLuis Alves 	return ret;
7300d788680SLuis Alves }
7310d788680SLuis Alves 
cx24117_read_status(struct dvb_frontend * fe,enum fe_status * status)7320df289a2SMauro Carvalho Chehab static int cx24117_read_status(struct dvb_frontend *fe, enum fe_status *status)
7330d788680SLuis Alves {
7340d788680SLuis Alves 	struct cx24117_state *state = fe->demodulator_priv;
7350d788680SLuis Alves 	int lock;
7360d788680SLuis Alves 
7370d788680SLuis Alves 	lock = cx24117_readreg(state,
7380d788680SLuis Alves 		(state->demod == 0) ? CX24117_REG_SSTATUS0 :
7390d788680SLuis Alves 				      CX24117_REG_SSTATUS1) &
7400d788680SLuis Alves 		CX24117_STATUS_MASK;
7410d788680SLuis Alves 
7420d788680SLuis Alves 	dev_dbg(&state->priv->i2c->dev, "%s() demod%d status = 0x%02x\n",
7430d788680SLuis Alves 		__func__, state->demod, lock);
7440d788680SLuis Alves 
7450d788680SLuis Alves 	*status = 0;
7460d788680SLuis Alves 
7470d788680SLuis Alves 	if (lock & CX24117_HAS_SIGNAL)
7480d788680SLuis Alves 		*status |= FE_HAS_SIGNAL;
7490d788680SLuis Alves 	if (lock & CX24117_HAS_CARRIER)
7500d788680SLuis Alves 		*status |= FE_HAS_CARRIER;
7510d788680SLuis Alves 	if (lock & CX24117_HAS_VITERBI)
7520d788680SLuis Alves 		*status |= FE_HAS_VITERBI;
7530d788680SLuis Alves 	if (lock & CX24117_HAS_SYNCLOCK)
7540d788680SLuis Alves 		*status |= FE_HAS_SYNC | FE_HAS_LOCK;
7550d788680SLuis Alves 
7560d788680SLuis Alves 	return 0;
7570d788680SLuis Alves }
7580d788680SLuis Alves 
cx24117_read_ber(struct dvb_frontend * fe,u32 * ber)7590d788680SLuis Alves static int cx24117_read_ber(struct dvb_frontend *fe, u32 *ber)
7600d788680SLuis Alves {
7610d788680SLuis Alves 	struct cx24117_state *state = fe->demodulator_priv;
7620d788680SLuis Alves 	int ret;
7630d788680SLuis Alves 	u8 buf[4];
7640d788680SLuis Alves 	u8 base_reg = (state->demod == 0) ?
7650d788680SLuis Alves 			CX24117_REG_BER4_0 :
7660d788680SLuis Alves 			CX24117_REG_BER4_1;
7670d788680SLuis Alves 
7680d788680SLuis Alves 	ret = cx24117_readregN(state, base_reg, buf, 4);
7690d788680SLuis Alves 	if (ret != 0)
7700d788680SLuis Alves 		return ret;
7710d788680SLuis Alves 
7720d788680SLuis Alves 	*ber = (buf[0] << 24) | (buf[1] << 16) |
7730d788680SLuis Alves 		(buf[1] << 8) | buf[0];
7740d788680SLuis Alves 
7750d788680SLuis Alves 	dev_dbg(&state->priv->i2c->dev, "%s() demod%d ber=0x%04x\n",
7760d788680SLuis Alves 		__func__, state->demod, *ber);
7770d788680SLuis Alves 
7780d788680SLuis Alves 	return 0;
7790d788680SLuis Alves }
7800d788680SLuis Alves 
cx24117_read_signal_strength(struct dvb_frontend * fe,u16 * signal_strength)7810d788680SLuis Alves static int cx24117_read_signal_strength(struct dvb_frontend *fe,
7820d788680SLuis Alves 	u16 *signal_strength)
7830d788680SLuis Alves {
7840d788680SLuis Alves 	struct cx24117_state *state = fe->demodulator_priv;
7850d788680SLuis Alves 	struct cx24117_cmd cmd;
7860d788680SLuis Alves 	int ret;
7870d788680SLuis Alves 	u16 sig_reading;
7880d788680SLuis Alves 	u8 buf[2];
7890d788680SLuis Alves 	u8 reg = (state->demod == 0) ?
7900d788680SLuis Alves 		CX24117_REG_SSTATUS0 : CX24117_REG_SSTATUS1;
7910d788680SLuis Alves 
7929fa7c419SLuis Alves 	/* Read AGC accumulator register */
7939fa7c419SLuis Alves 	cmd.args[0] = CMD_GET_AGCACC;
7940d788680SLuis Alves 	cmd.args[1] = (u8) state->demod;
7950d788680SLuis Alves 	cmd.len = 2;
7960d788680SLuis Alves 	ret = cx24117_cmd_execute(fe, &cmd);
7970d788680SLuis Alves 	if (ret != 0)
7980d788680SLuis Alves 		return ret;
7990d788680SLuis Alves 
8000d788680SLuis Alves 	ret = cx24117_readregN(state, reg, buf, 2);
8010d788680SLuis Alves 	if (ret != 0)
8020d788680SLuis Alves 		return ret;
8030d788680SLuis Alves 	sig_reading = ((buf[0] & CX24117_SIGNAL_MASK) << 2) | buf[1];
8040d788680SLuis Alves 
8050d788680SLuis Alves 	*signal_strength = -100 * sig_reading + 94324;
8060d788680SLuis Alves 
8070d788680SLuis Alves 	dev_dbg(&state->priv->i2c->dev,
8080d788680SLuis Alves 		"%s() demod%d raw / cooked = 0x%04x / 0x%04x\n",
8090d788680SLuis Alves 		__func__, state->demod, sig_reading, *signal_strength);
8100d788680SLuis Alves 
8110d788680SLuis Alves 	return 0;
8120d788680SLuis Alves }
8130d788680SLuis Alves 
cx24117_read_snr(struct dvb_frontend * fe,u16 * snr)8140d788680SLuis Alves static int cx24117_read_snr(struct dvb_frontend *fe, u16 *snr)
8150d788680SLuis Alves {
8160d788680SLuis Alves 	struct cx24117_state *state = fe->demodulator_priv;
8170d788680SLuis Alves 	int ret;
8180d788680SLuis Alves 	u8 buf[2];
8190d788680SLuis Alves 	u8 reg = (state->demod == 0) ?
8200d788680SLuis Alves 		CX24117_REG_QUALITY2_0 : CX24117_REG_QUALITY2_1;
8210d788680SLuis Alves 
8220d788680SLuis Alves 	ret = cx24117_readregN(state, reg, buf, 2);
8230d788680SLuis Alves 	if (ret != 0)
8240d788680SLuis Alves 		return ret;
8250d788680SLuis Alves 
8260d788680SLuis Alves 	*snr = (buf[0] << 8) | buf[1];
8270d788680SLuis Alves 
8280d788680SLuis Alves 	dev_dbg(&state->priv->i2c->dev,
8290d788680SLuis Alves 		"%s() demod%d snr = 0x%04x\n",
8300d788680SLuis Alves 		__func__, state->demod, *snr);
8310d788680SLuis Alves 
8320d788680SLuis Alves 	return ret;
8330d788680SLuis Alves }
8340d788680SLuis Alves 
cx24117_read_ucblocks(struct dvb_frontend * fe,u32 * ucblocks)8350d788680SLuis Alves static int cx24117_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
8360d788680SLuis Alves {
8370d788680SLuis Alves 	struct cx24117_state *state = fe->demodulator_priv;
8380df289a2SMauro Carvalho Chehab 	enum fe_delivery_system delsys = fe->dtv_property_cache.delivery_system;
8390d788680SLuis Alves 	int ret;
8400d788680SLuis Alves 	u8 buf[2];
8410d788680SLuis Alves 	u8 reg = (state->demod == 0) ?
8420d788680SLuis Alves 		CX24117_REG_DVBS_UCB2_0 :
8430d788680SLuis Alves 		CX24117_REG_DVBS_UCB2_1;
8440d788680SLuis Alves 
8450d788680SLuis Alves 	switch (delsys) {
8460d788680SLuis Alves 	case SYS_DVBS:
8470d788680SLuis Alves 		break;
8480d788680SLuis Alves 	case SYS_DVBS2:
8490d788680SLuis Alves 		reg += (CX24117_REG_DVBS2_UCB2_0 - CX24117_REG_DVBS_UCB2_0);
8500d788680SLuis Alves 		break;
8510d788680SLuis Alves 	default:
8520d788680SLuis Alves 		return -EINVAL;
8530d788680SLuis Alves 	}
8540d788680SLuis Alves 
8550d788680SLuis Alves 	ret = cx24117_readregN(state, reg, buf, 2);
8560d788680SLuis Alves 	if (ret != 0)
8570d788680SLuis Alves 		return ret;
8580d788680SLuis Alves 	*ucblocks = (buf[0] << 8) | buf[1];
8590d788680SLuis Alves 
8600d788680SLuis Alves 	dev_dbg(&state->priv->i2c->dev, "%s() demod%d ucb=0x%04x\n",
8610d788680SLuis Alves 		__func__, state->demod, *ucblocks);
8620d788680SLuis Alves 
8630d788680SLuis Alves 	return 0;
8640d788680SLuis Alves }
8650d788680SLuis Alves 
8660d788680SLuis Alves /* Overwrite the current tuning params, we are about to tune */
cx24117_clone_params(struct dvb_frontend * fe)8670d788680SLuis Alves static void cx24117_clone_params(struct dvb_frontend *fe)
8680d788680SLuis Alves {
8690d788680SLuis Alves 	struct cx24117_state *state = fe->demodulator_priv;
8700d788680SLuis Alves 	state->dcur = state->dnxt;
8710d788680SLuis Alves }
8720d788680SLuis Alves 
8730d788680SLuis Alves /* Wait for LNB */
cx24117_wait_for_lnb(struct dvb_frontend * fe)8740d788680SLuis Alves static int cx24117_wait_for_lnb(struct dvb_frontend *fe)
8750d788680SLuis Alves {
8760d788680SLuis Alves 	struct cx24117_state *state = fe->demodulator_priv;
8770d788680SLuis Alves 	int i;
8780d788680SLuis Alves 	u8 val, reg = (state->demod == 0) ? CX24117_REG_QSTATUS0 :
8790d788680SLuis Alves 					    CX24117_REG_QSTATUS1;
8800d788680SLuis Alves 
8810d788680SLuis Alves 	dev_dbg(&state->priv->i2c->dev, "%s() demod%d qstatus = 0x%02x\n",
8820d788680SLuis Alves 		__func__, state->demod, cx24117_readreg(state, reg));
8830d788680SLuis Alves 
8840d788680SLuis Alves 	/* Wait for up to 300 ms */
8850d788680SLuis Alves 	for (i = 0; i < 10; i++) {
8860d788680SLuis Alves 		val = cx24117_readreg(state, reg) & 0x01;
8870d788680SLuis Alves 		if (val != 0)
8880d788680SLuis Alves 			return 0;
8890d788680SLuis Alves 		msleep(30);
8900d788680SLuis Alves 	}
8910d788680SLuis Alves 
8920d788680SLuis Alves 	dev_warn(&state->priv->i2c->dev, "%s: demod%d LNB not ready\n",
8930d788680SLuis Alves 		KBUILD_MODNAME, state->demod);
8940d788680SLuis Alves 
8950d788680SLuis Alves 	return -ETIMEDOUT; /* -EBUSY ? */
8960d788680SLuis Alves }
8970d788680SLuis Alves 
cx24117_set_voltage(struct dvb_frontend * fe,enum fe_sec_voltage voltage)8980d788680SLuis Alves static int cx24117_set_voltage(struct dvb_frontend *fe,
8990df289a2SMauro Carvalho Chehab 			       enum fe_sec_voltage voltage)
9000d788680SLuis Alves {
9010d788680SLuis Alves 	struct cx24117_state *state = fe->demodulator_priv;
9020d788680SLuis Alves 	struct cx24117_cmd cmd;
9030d788680SLuis Alves 	int ret;
9040d788680SLuis Alves 	u8 reg = (state->demod == 0) ? 0x10 : 0x20;
9050d788680SLuis Alves 
9060d788680SLuis Alves 	dev_dbg(&state->priv->i2c->dev, "%s() demod%d %s\n",
9070d788680SLuis Alves 		__func__, state->demod,
9080d788680SLuis Alves 		voltage == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
9090d788680SLuis Alves 		voltage == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" :
9100d788680SLuis Alves 		"SEC_VOLTAGE_OFF");
9110d788680SLuis Alves 
91271b6aaafSLuis Alves 	/* Prepare a set GPIO logic level CMD */
91371b6aaafSLuis Alves 	cmd.args[0] = CMD_SET_GPIOOUT;
91471b6aaafSLuis Alves 	cmd.args[2] = reg; /* mask */
9150d788680SLuis Alves 	cmd.len = 3;
9160d788680SLuis Alves 
9170d788680SLuis Alves 	if ((voltage == SEC_VOLTAGE_13) ||
9180d788680SLuis Alves 	    (voltage == SEC_VOLTAGE_18)) {
91971b6aaafSLuis Alves 		/* power on LNB */
9200d788680SLuis Alves 		cmd.args[1] = reg;
9210d788680SLuis Alves 		ret = cx24117_cmd_execute(fe, &cmd);
9220d788680SLuis Alves 		if (ret != 0)
9230d788680SLuis Alves 			return ret;
9240d788680SLuis Alves 
9250d788680SLuis Alves 		ret = cx24117_wait_for_lnb(fe);
9260d788680SLuis Alves 		if (ret != 0)
9270d788680SLuis Alves 			return ret;
9280d788680SLuis Alves 
9290d788680SLuis Alves 		/* Wait for voltage/min repeat delay */
9300d788680SLuis Alves 		msleep(100);
9310d788680SLuis Alves 
9329fa7c419SLuis Alves 		/* Set 13V/18V select pin */
9330d788680SLuis Alves 		cmd.args[0] = CMD_LNBDCLEVEL;
9340d788680SLuis Alves 		cmd.args[1] = state->demod ? 0 : 1;
9350d788680SLuis Alves 		cmd.args[2] = (voltage == SEC_VOLTAGE_18 ? 0x01 : 0x00);
9360d788680SLuis Alves 		cmd.len = 3;
93771b6aaafSLuis Alves 		ret = cx24117_cmd_execute(fe, &cmd);
9380d788680SLuis Alves 
9390d788680SLuis Alves 		/* Min delay time before DiSEqC send */
9400d788680SLuis Alves 		msleep(20);
9410d788680SLuis Alves 	} else {
94271b6aaafSLuis Alves 		/* power off LNB */
9430d788680SLuis Alves 		cmd.args[1] = 0x00;
94471b6aaafSLuis Alves 		ret = cx24117_cmd_execute(fe, &cmd);
9450d788680SLuis Alves 	}
9460d788680SLuis Alves 
94771b6aaafSLuis Alves 	return ret;
9480d788680SLuis Alves }
9490d788680SLuis Alves 
cx24117_set_tone(struct dvb_frontend * fe,enum fe_sec_tone_mode tone)9500d788680SLuis Alves static int cx24117_set_tone(struct dvb_frontend *fe,
9510df289a2SMauro Carvalho Chehab 			    enum fe_sec_tone_mode tone)
9520d788680SLuis Alves {
9530d788680SLuis Alves 	struct cx24117_state *state = fe->demodulator_priv;
9540d788680SLuis Alves 	struct cx24117_cmd cmd;
9550d788680SLuis Alves 	int ret;
9560d788680SLuis Alves 
9570d788680SLuis Alves 	dev_dbg(&state->priv->i2c->dev, "%s(%d) demod%d\n",
9580d788680SLuis Alves 		__func__, state->demod, tone);
9590d788680SLuis Alves 	if ((tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF)) {
9600d788680SLuis Alves 		dev_warn(&state->priv->i2c->dev, "%s: demod%d invalid tone=%d\n",
9610d788680SLuis Alves 			KBUILD_MODNAME, state->demod, tone);
9620d788680SLuis Alves 		return -EINVAL;
9630d788680SLuis Alves 	}
9640d788680SLuis Alves 
9650d788680SLuis Alves 	/* Wait for LNB ready */
9660d788680SLuis Alves 	ret = cx24117_wait_for_lnb(fe);
9670d788680SLuis Alves 	if (ret != 0)
9680d788680SLuis Alves 		return ret;
9690d788680SLuis Alves 
9700d788680SLuis Alves 	/* Min delay time after DiSEqC send */
9710d788680SLuis Alves 	msleep(20);
9720d788680SLuis Alves 
9730d788680SLuis Alves 	/* Set the tone */
9749fa7c419SLuis Alves 	cmd.args[0] = CMD_LNBPCBCONFIG;
9750d788680SLuis Alves 	cmd.args[1] = (state->demod ? 0 : 1);
9760d788680SLuis Alves 	cmd.args[2] = 0x00;
9770d788680SLuis Alves 	cmd.args[3] = 0x00;
9780d788680SLuis Alves 	cmd.len = 5;
9790d788680SLuis Alves 	switch (tone) {
9800d788680SLuis Alves 	case SEC_TONE_ON:
9810d788680SLuis Alves 		cmd.args[4] = 0x01;
9820d788680SLuis Alves 		break;
9830d788680SLuis Alves 	case SEC_TONE_OFF:
9840d788680SLuis Alves 		cmd.args[4] = 0x00;
9850d788680SLuis Alves 		break;
9860d788680SLuis Alves 	}
9870d788680SLuis Alves 
9880d788680SLuis Alves 	msleep(20);
9890d788680SLuis Alves 
9900d788680SLuis Alves 	return cx24117_cmd_execute(fe, &cmd);
9910d788680SLuis Alves }
9920d788680SLuis Alves 
9930d788680SLuis Alves /* Initialise DiSEqC */
cx24117_diseqc_init(struct dvb_frontend * fe)9940d788680SLuis Alves static int cx24117_diseqc_init(struct dvb_frontend *fe)
9950d788680SLuis Alves {
9960d788680SLuis Alves 	struct cx24117_state *state = fe->demodulator_priv;
9970d788680SLuis Alves 
9980d788680SLuis Alves 	/* Prepare a DiSEqC command */
9990d788680SLuis Alves 	state->dsec_cmd.args[0] = CMD_LNBSEND;
10000d788680SLuis Alves 
10010d788680SLuis Alves 	/* demod */
10020d788680SLuis Alves 	state->dsec_cmd.args[CX24117_DISEQC_DEMOD] = state->demod ? 0 : 1;
10030d788680SLuis Alves 
10040d788680SLuis Alves 	/* DiSEqC burst */
10050d788680SLuis Alves 	state->dsec_cmd.args[CX24117_DISEQC_BURST] = CX24117_DISEQC_MINI_A;
10060d788680SLuis Alves 
10070d788680SLuis Alves 	/* Unknown */
10080d788680SLuis Alves 	state->dsec_cmd.args[CX24117_DISEQC_ARG3_2] = 0x02;
10090d788680SLuis Alves 	state->dsec_cmd.args[CX24117_DISEQC_ARG4_0] = 0x00;
10100d788680SLuis Alves 
10110d788680SLuis Alves 	/* Continuation flag? */
10120d788680SLuis Alves 	state->dsec_cmd.args[CX24117_DISEQC_ARG5_0] = 0x00;
10130d788680SLuis Alves 
10140d788680SLuis Alves 	/* DiSEqC message length */
10150d788680SLuis Alves 	state->dsec_cmd.args[CX24117_DISEQC_MSGLEN] = 0x00;
10160d788680SLuis Alves 
10170d788680SLuis Alves 	/* Command length */
10180d788680SLuis Alves 	state->dsec_cmd.len = 7;
10190d788680SLuis Alves 
10200d788680SLuis Alves 	return 0;
10210d788680SLuis Alves }
10220d788680SLuis Alves 
10230d788680SLuis Alves /* Send DiSEqC message */
cx24117_send_diseqc_msg(struct dvb_frontend * fe,struct dvb_diseqc_master_cmd * d)10240d788680SLuis Alves static int cx24117_send_diseqc_msg(struct dvb_frontend *fe,
10250d788680SLuis Alves 	struct dvb_diseqc_master_cmd *d)
10260d788680SLuis Alves {
10270d788680SLuis Alves 	struct cx24117_state *state = fe->demodulator_priv;
10280d788680SLuis Alves 	int i, ret;
10290d788680SLuis Alves 
10300d788680SLuis Alves 	/* Dump DiSEqC message */
10310d788680SLuis Alves 	dev_dbg(&state->priv->i2c->dev, "%s: demod %d (",
10320d788680SLuis Alves 		__func__, state->demod);
10330d788680SLuis Alves 	for (i = 0; i < d->msg_len; i++)
10340d788680SLuis Alves 		dev_dbg(&state->priv->i2c->dev, "0x%02x ", d->msg[i]);
10350d788680SLuis Alves 	dev_dbg(&state->priv->i2c->dev, ")\n");
10360d788680SLuis Alves 
10370d788680SLuis Alves 	/* Validate length */
103882e3b88bSMauro Carvalho Chehab 	if (d->msg_len > sizeof(d->msg))
10390d788680SLuis Alves 		return -EINVAL;
10400d788680SLuis Alves 
10410d788680SLuis Alves 	/* DiSEqC message */
10420d788680SLuis Alves 	for (i = 0; i < d->msg_len; i++)
10430d788680SLuis Alves 		state->dsec_cmd.args[CX24117_DISEQC_MSGOFS + i] = d->msg[i];
10440d788680SLuis Alves 
10450d788680SLuis Alves 	/* DiSEqC message length */
10460d788680SLuis Alves 	state->dsec_cmd.args[CX24117_DISEQC_MSGLEN] = d->msg_len;
10470d788680SLuis Alves 
10480d788680SLuis Alves 	/* Command length */
10490d788680SLuis Alves 	state->dsec_cmd.len = CX24117_DISEQC_MSGOFS +
10500d788680SLuis Alves 		state->dsec_cmd.args[CX24117_DISEQC_MSGLEN];
10510d788680SLuis Alves 
10520d788680SLuis Alves 	/*
10530d788680SLuis Alves 	 * Message is sent with derived else cached burst
10540d788680SLuis Alves 	 *
10550d788680SLuis Alves 	 * WRITE PORT GROUP COMMAND 38
10560d788680SLuis Alves 	 *
10570d788680SLuis Alves 	 * 0/A/A: E0 10 38 F0..F3
10580d788680SLuis Alves 	 * 1/B/B: E0 10 38 F4..F7
10590d788680SLuis Alves 	 * 2/C/A: E0 10 38 F8..FB
10600d788680SLuis Alves 	 * 3/D/B: E0 10 38 FC..FF
10610d788680SLuis Alves 	 *
10620d788680SLuis Alves 	 * databyte[3]= 8421:8421
10630d788680SLuis Alves 	 *              ABCD:WXYZ
10640d788680SLuis Alves 	 *              CLR :SET
10650d788680SLuis Alves 	 *
10660d788680SLuis Alves 	 *              WX= PORT SELECT 0..3    (X=TONEBURST)
10670d788680SLuis Alves 	 *              Y = VOLTAGE             (0=13V, 1=18V)
10680d788680SLuis Alves 	 *              Z = BAND                (0=LOW, 1=HIGH(22K))
10690d788680SLuis Alves 	 */
10700d788680SLuis Alves 	if (d->msg_len >= 4 && d->msg[2] == 0x38)
10710d788680SLuis Alves 		state->dsec_cmd.args[CX24117_DISEQC_BURST] =
10720d788680SLuis Alves 			((d->msg[3] & 4) >> 2);
10730d788680SLuis Alves 
10740d788680SLuis Alves 	dev_dbg(&state->priv->i2c->dev, "%s() demod%d burst=%d\n",
10750d788680SLuis Alves 		__func__, state->demod,
10760d788680SLuis Alves 		state->dsec_cmd.args[CX24117_DISEQC_BURST]);
10770d788680SLuis Alves 
10780d788680SLuis Alves 	/* Wait for LNB ready */
10790d788680SLuis Alves 	ret = cx24117_wait_for_lnb(fe);
10800d788680SLuis Alves 	if (ret != 0)
10810d788680SLuis Alves 		return ret;
10820d788680SLuis Alves 
10830d788680SLuis Alves 	/* Wait for voltage/min repeat delay */
10840d788680SLuis Alves 	msleep(100);
10850d788680SLuis Alves 
10860d788680SLuis Alves 	/* Command */
10870d788680SLuis Alves 	ret = cx24117_cmd_execute(fe, &state->dsec_cmd);
10880d788680SLuis Alves 	if (ret != 0)
10890d788680SLuis Alves 		return ret;
10900d788680SLuis Alves 	/*
10910d788680SLuis Alves 	 * Wait for send
10920d788680SLuis Alves 	 *
10930d788680SLuis Alves 	 * Eutelsat spec:
10940d788680SLuis Alves 	 * >15ms delay          + (XXX determine if FW does this, see set_tone)
10950d788680SLuis Alves 	 *  13.5ms per byte     +
10960d788680SLuis Alves 	 * >15ms delay          +
10970d788680SLuis Alves 	 *  12.5ms burst        +
10980d788680SLuis Alves 	 * >15ms delay            (XXX determine if FW does this, see set_tone)
10990d788680SLuis Alves 	 */
11000d788680SLuis Alves 	msleep((state->dsec_cmd.args[CX24117_DISEQC_MSGLEN] << 4) + 60);
11010d788680SLuis Alves 
11020d788680SLuis Alves 	return 0;
11030d788680SLuis Alves }
11040d788680SLuis Alves 
11050d788680SLuis Alves /* Send DiSEqC burst */
cx24117_diseqc_send_burst(struct dvb_frontend * fe,enum fe_sec_mini_cmd burst)11060d788680SLuis Alves static int cx24117_diseqc_send_burst(struct dvb_frontend *fe,
11070df289a2SMauro Carvalho Chehab 	enum fe_sec_mini_cmd burst)
11080d788680SLuis Alves {
11090d788680SLuis Alves 	struct cx24117_state *state = fe->demodulator_priv;
11100d788680SLuis Alves 
11110d788680SLuis Alves 	dev_dbg(&state->priv->i2c->dev, "%s(%d) demod=%d\n",
11120d788680SLuis Alves 		__func__, burst, state->demod);
11130d788680SLuis Alves 
11140d788680SLuis Alves 	/* DiSEqC burst */
11150d788680SLuis Alves 	if (burst == SEC_MINI_A)
11160d788680SLuis Alves 		state->dsec_cmd.args[CX24117_DISEQC_BURST] =
11170d788680SLuis Alves 			CX24117_DISEQC_MINI_A;
11180d788680SLuis Alves 	else if (burst == SEC_MINI_B)
11190d788680SLuis Alves 		state->dsec_cmd.args[CX24117_DISEQC_BURST] =
11200d788680SLuis Alves 			CX24117_DISEQC_MINI_B;
11210d788680SLuis Alves 	else
11220d788680SLuis Alves 		return -EINVAL;
11230d788680SLuis Alves 
11240d788680SLuis Alves 	return 0;
11250d788680SLuis Alves }
11260d788680SLuis Alves 
cx24117_get_priv(struct cx24117_priv ** priv,struct i2c_adapter * i2c,u8 client_address)1127d10e8280SLuis Alves static int cx24117_get_priv(struct cx24117_priv **priv,
1128d10e8280SLuis Alves 	struct i2c_adapter *i2c, u8 client_address)
1129d10e8280SLuis Alves {
1130d10e8280SLuis Alves 	int ret;
1131d10e8280SLuis Alves 
1132d10e8280SLuis Alves 	mutex_lock(&cx24117_list_mutex);
1133d10e8280SLuis Alves 	ret = hybrid_tuner_request_state(struct cx24117_priv, (*priv),
1134d10e8280SLuis Alves 		hybrid_tuner_instance_list, i2c, client_address, "cx24117");
1135d10e8280SLuis Alves 	mutex_unlock(&cx24117_list_mutex);
1136d10e8280SLuis Alves 
1137d10e8280SLuis Alves 	return ret;
1138d10e8280SLuis Alves }
1139d10e8280SLuis Alves 
cx24117_release_priv(struct cx24117_priv * priv)1140d10e8280SLuis Alves static void cx24117_release_priv(struct cx24117_priv *priv)
1141d10e8280SLuis Alves {
1142d10e8280SLuis Alves 	mutex_lock(&cx24117_list_mutex);
1143d10e8280SLuis Alves 	if (priv != NULL)
1144d10e8280SLuis Alves 		hybrid_tuner_release_state(priv);
1145d10e8280SLuis Alves 	mutex_unlock(&cx24117_list_mutex);
1146d10e8280SLuis Alves }
1147d10e8280SLuis Alves 
cx24117_release(struct dvb_frontend * fe)11480d788680SLuis Alves static void cx24117_release(struct dvb_frontend *fe)
11490d788680SLuis Alves {
11500d788680SLuis Alves 	struct cx24117_state *state = fe->demodulator_priv;
11510d788680SLuis Alves 	dev_dbg(&state->priv->i2c->dev, "%s demod%d\n",
11520d788680SLuis Alves 		__func__, state->demod);
1153d10e8280SLuis Alves 	cx24117_release_priv(state->priv);
11540d788680SLuis Alves 	kfree(state);
11550d788680SLuis Alves }
11560d788680SLuis Alves 
1157bd336e63SMax Kellermann static const struct dvb_frontend_ops cx24117_ops;
11580d788680SLuis Alves 
cx24117_attach(const struct cx24117_config * config,struct i2c_adapter * i2c)11590d788680SLuis Alves struct dvb_frontend *cx24117_attach(const struct cx24117_config *config,
1160d10e8280SLuis Alves 	struct i2c_adapter *i2c)
11610d788680SLuis Alves {
11620d788680SLuis Alves 	struct cx24117_state *state = NULL;
11630d788680SLuis Alves 	struct cx24117_priv *priv = NULL;
11640d788680SLuis Alves 	int demod = 0;
11650d788680SLuis Alves 
1166d10e8280SLuis Alves 	/* get the common data struct for both demods */
1167d10e8280SLuis Alves 	demod = cx24117_get_priv(&priv, i2c, config->demod_address);
1168d10e8280SLuis Alves 
1169d10e8280SLuis Alves 	switch (demod) {
1170d10e8280SLuis Alves 	case 0:
1171a33dd517SAndi Shyti 		dev_err(&i2c->dev,
1172d10e8280SLuis Alves 			"%s: Error attaching frontend %d\n",
1173d10e8280SLuis Alves 			KBUILD_MODNAME, demod);
11740d788680SLuis Alves 		goto error1;
1175d10e8280SLuis Alves 	case 1:
1176d10e8280SLuis Alves 		/* new priv instance */
11770d788680SLuis Alves 		priv->i2c = i2c;
11780d788680SLuis Alves 		priv->demod_address = config->demod_address;
11790d788680SLuis Alves 		mutex_init(&priv->fe_lock);
1180d10e8280SLuis Alves 		break;
1181d10e8280SLuis Alves 	default:
1182d10e8280SLuis Alves 		/* existing priv instance */
1183d10e8280SLuis Alves 		break;
11840d788680SLuis Alves 	}
11850d788680SLuis Alves 
11860d788680SLuis Alves 	/* allocate memory for the internal state */
11870d788680SLuis Alves 	state = kzalloc(sizeof(struct cx24117_state), GFP_KERNEL);
11880d788680SLuis Alves 	if (state == NULL)
11890d788680SLuis Alves 		goto error2;
11900d788680SLuis Alves 
1191d10e8280SLuis Alves 	state->demod = demod - 1;
11920d788680SLuis Alves 	state->priv = priv;
11930d788680SLuis Alves 
11940d788680SLuis Alves 	dev_info(&state->priv->i2c->dev,
11950d788680SLuis Alves 		"%s: Attaching frontend %d\n",
1196d10e8280SLuis Alves 		KBUILD_MODNAME, state->demod);
11970d788680SLuis Alves 
11980d788680SLuis Alves 	/* create dvb_frontend */
11990d788680SLuis Alves 	memcpy(&state->frontend.ops, &cx24117_ops,
12000d788680SLuis Alves 		sizeof(struct dvb_frontend_ops));
12010d788680SLuis Alves 	state->frontend.demodulator_priv = state;
12020d788680SLuis Alves 	return &state->frontend;
12030d788680SLuis Alves 
12040d788680SLuis Alves error2:
1205d10e8280SLuis Alves 	cx24117_release_priv(priv);
12060d788680SLuis Alves error1:
12070d788680SLuis Alves 	return NULL;
12080d788680SLuis Alves }
12090d788680SLuis Alves EXPORT_SYMBOL_GPL(cx24117_attach);
12100d788680SLuis Alves 
12110d788680SLuis Alves /*
12120d788680SLuis Alves  * Initialise or wake up device
12130d788680SLuis Alves  *
12140d788680SLuis Alves  * Power config will reset and load initial firmware if required
12150d788680SLuis Alves  */
cx24117_initfe(struct dvb_frontend * fe)12160d788680SLuis Alves static int cx24117_initfe(struct dvb_frontend *fe)
12170d788680SLuis Alves {
12180d788680SLuis Alves 	struct cx24117_state *state = fe->demodulator_priv;
12190d788680SLuis Alves 	struct cx24117_cmd cmd;
12200d788680SLuis Alves 	int ret;
12210d788680SLuis Alves 
12220d788680SLuis Alves 	dev_dbg(&state->priv->i2c->dev, "%s() demod%d\n",
12230d788680SLuis Alves 		__func__, state->demod);
12240d788680SLuis Alves 
12250d788680SLuis Alves 	mutex_lock(&state->priv->fe_lock);
12260d788680SLuis Alves 
12279fa7c419SLuis Alves 	/* Set sleep mode off */
12289fa7c419SLuis Alves 	cmd.args[0] = CMD_SET_SLEEPMODE;
12290d788680SLuis Alves 	cmd.args[1] = (state->demod ? 1 : 0);
12300d788680SLuis Alves 	cmd.args[2] = 0;
12310d788680SLuis Alves 	cmd.len = 3;
12320d788680SLuis Alves 	ret = cx24117_cmd_execute_nolock(fe, &cmd);
12330d788680SLuis Alves 	if (ret != 0)
12344699b5f3SLuis Alves 		goto exit;
12350d788680SLuis Alves 
12360d788680SLuis Alves 	ret = cx24117_diseqc_init(fe);
12370d788680SLuis Alves 	if (ret != 0)
12384699b5f3SLuis Alves 		goto exit;
12390d788680SLuis Alves 
12409fa7c419SLuis Alves 	/* Set BER control */
12419fa7c419SLuis Alves 	cmd.args[0] = CMD_BERCTRL;
12420d788680SLuis Alves 	cmd.args[1] = (state->demod ? 1 : 0);
12430d788680SLuis Alves 	cmd.args[2] = 0x10;
12440d788680SLuis Alves 	cmd.args[3] = 0x10;
12450d788680SLuis Alves 	cmd.len = 4;
12460d788680SLuis Alves 	ret = cx24117_cmd_execute_nolock(fe, &cmd);
12470d788680SLuis Alves 	if (ret != 0)
12484699b5f3SLuis Alves 		goto exit;
12490d788680SLuis Alves 
12509fa7c419SLuis Alves 	/* Set RS correction (enable/disable) */
12519fa7c419SLuis Alves 	cmd.args[0] = CMD_ENABLERSCORR;
12520d788680SLuis Alves 	cmd.args[1] = (state->demod ? 1 : 0);
12530d788680SLuis Alves 	cmd.args[2] = CX24117_OCC;
12540d788680SLuis Alves 	cmd.len = 3;
12550d788680SLuis Alves 	ret = cx24117_cmd_execute_nolock(fe, &cmd);
125671b6aaafSLuis Alves 	if (ret != 0)
125771b6aaafSLuis Alves 		goto exit;
125871b6aaafSLuis Alves 
125971b6aaafSLuis Alves 	/* Set GPIO direction */
126071b6aaafSLuis Alves 	/* Set as output - controls LNB power on/off */
126171b6aaafSLuis Alves 	cmd.args[0] = CMD_SET_GPIODIR;
126271b6aaafSLuis Alves 	cmd.args[1] = 0x30;
126371b6aaafSLuis Alves 	cmd.args[2] = 0x30;
126471b6aaafSLuis Alves 	cmd.len = 3;
126571b6aaafSLuis Alves 	ret = cx24117_cmd_execute_nolock(fe, &cmd);
12660d788680SLuis Alves 
12674699b5f3SLuis Alves exit:
12680d788680SLuis Alves 	mutex_unlock(&state->priv->fe_lock);
12690d788680SLuis Alves 
12700d788680SLuis Alves 	return ret;
12710d788680SLuis Alves }
12720d788680SLuis Alves 
12730d788680SLuis Alves /*
12740d788680SLuis Alves  * Put device to sleep
12750d788680SLuis Alves  */
cx24117_sleep(struct dvb_frontend * fe)12760d788680SLuis Alves static int cx24117_sleep(struct dvb_frontend *fe)
12770d788680SLuis Alves {
12780d788680SLuis Alves 	struct cx24117_state *state = fe->demodulator_priv;
12790d788680SLuis Alves 	struct cx24117_cmd cmd;
12800d788680SLuis Alves 
12810d788680SLuis Alves 	dev_dbg(&state->priv->i2c->dev, "%s() demod%d\n",
12820d788680SLuis Alves 		__func__, state->demod);
12830d788680SLuis Alves 
12849fa7c419SLuis Alves 	/* Set sleep mode on */
12859fa7c419SLuis Alves 	cmd.args[0] = CMD_SET_SLEEPMODE;
12860d788680SLuis Alves 	cmd.args[1] = (state->demod ? 1 : 0);
12870d788680SLuis Alves 	cmd.args[2] = 1;
12880d788680SLuis Alves 	cmd.len = 3;
12890d788680SLuis Alves 	return cx24117_cmd_execute(fe, &cmd);
12900d788680SLuis Alves }
12910d788680SLuis Alves 
12920d788680SLuis Alves /* dvb-core told us to tune, the tv property cache will be complete,
12930d788680SLuis Alves  * it's safe for is to pull values and use them for tuning purposes.
12940d788680SLuis Alves  */
cx24117_set_frontend(struct dvb_frontend * fe)12950d788680SLuis Alves static int cx24117_set_frontend(struct dvb_frontend *fe)
12960d788680SLuis Alves {
12970d788680SLuis Alves 	struct cx24117_state *state = fe->demodulator_priv;
12980d788680SLuis Alves 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
12990d788680SLuis Alves 	struct cx24117_cmd cmd;
13000df289a2SMauro Carvalho Chehab 	enum fe_status tunerstat;
13010d788680SLuis Alves 	int i, status, ret, retune = 1;
13020d788680SLuis Alves 	u8 reg_clkdiv, reg_ratediv;
13030d788680SLuis Alves 
13040d788680SLuis Alves 	dev_dbg(&state->priv->i2c->dev, "%s() demod%d\n",
13050d788680SLuis Alves 		__func__, state->demod);
13060d788680SLuis Alves 
13070d788680SLuis Alves 	switch (c->delivery_system) {
13080d788680SLuis Alves 	case SYS_DVBS:
13090d788680SLuis Alves 		dev_dbg(&state->priv->i2c->dev, "%s() demod%d DVB-S\n",
13100d788680SLuis Alves 			__func__, state->demod);
13110d788680SLuis Alves 
13120d788680SLuis Alves 		/* Only QPSK is supported for DVB-S */
13130d788680SLuis Alves 		if (c->modulation != QPSK) {
13140d788680SLuis Alves 			dev_dbg(&state->priv->i2c->dev,
13150d788680SLuis Alves 				"%s() demod%d unsupported modulation (%d)\n",
13160d788680SLuis Alves 				__func__, state->demod, c->modulation);
13170d788680SLuis Alves 			return -EINVAL;
13180d788680SLuis Alves 		}
13190d788680SLuis Alves 
13200d788680SLuis Alves 		/* Pilot doesn't exist in DVB-S, turn bit off */
13210d788680SLuis Alves 		state->dnxt.pilot_val = CX24117_PILOT_OFF;
13220d788680SLuis Alves 
13230d788680SLuis Alves 		/* DVB-S only supports 0.35 */
13240d788680SLuis Alves 		state->dnxt.rolloff_val = CX24117_ROLLOFF_035;
13250d788680SLuis Alves 		break;
13260d788680SLuis Alves 
13270d788680SLuis Alves 	case SYS_DVBS2:
13280d788680SLuis Alves 		dev_dbg(&state->priv->i2c->dev, "%s() demod%d DVB-S2\n",
13290d788680SLuis Alves 			__func__, state->demod);
13300d788680SLuis Alves 
13310d788680SLuis Alves 		/*
13320d788680SLuis Alves 		 * NBC 8PSK/QPSK with DVB-S is supported for DVB-S2,
13330d788680SLuis Alves 		 * but not hardware auto detection
13340d788680SLuis Alves 		 */
13350d788680SLuis Alves 		if (c->modulation != PSK_8 && c->modulation != QPSK) {
13360d788680SLuis Alves 			dev_dbg(&state->priv->i2c->dev,
13370d788680SLuis Alves 				"%s() demod%d unsupported modulation (%d)\n",
13380d788680SLuis Alves 				__func__, state->demod, c->modulation);
13390d788680SLuis Alves 			return -EOPNOTSUPP;
13400d788680SLuis Alves 		}
13410d788680SLuis Alves 
13420d788680SLuis Alves 		switch (c->pilot) {
13430d788680SLuis Alves 		case PILOT_AUTO:
13440d788680SLuis Alves 			state->dnxt.pilot_val = CX24117_PILOT_AUTO;
13450d788680SLuis Alves 			break;
13460d788680SLuis Alves 		case PILOT_OFF:
13470d788680SLuis Alves 			state->dnxt.pilot_val = CX24117_PILOT_OFF;
13480d788680SLuis Alves 			break;
13490d788680SLuis Alves 		case PILOT_ON:
13500d788680SLuis Alves 			state->dnxt.pilot_val = CX24117_PILOT_ON;
13510d788680SLuis Alves 			break;
13520d788680SLuis Alves 		default:
13530d788680SLuis Alves 			dev_dbg(&state->priv->i2c->dev,
13540d788680SLuis Alves 				"%s() demod%d unsupported pilot mode (%d)\n",
13550d788680SLuis Alves 				__func__, state->demod, c->pilot);
13560d788680SLuis Alves 			return -EOPNOTSUPP;
13570d788680SLuis Alves 		}
13580d788680SLuis Alves 
13590d788680SLuis Alves 		switch (c->rolloff) {
13600d788680SLuis Alves 		case ROLLOFF_20:
13610d788680SLuis Alves 			state->dnxt.rolloff_val = CX24117_ROLLOFF_020;
13620d788680SLuis Alves 			break;
13630d788680SLuis Alves 		case ROLLOFF_25:
13640d788680SLuis Alves 			state->dnxt.rolloff_val = CX24117_ROLLOFF_025;
13650d788680SLuis Alves 			break;
13660d788680SLuis Alves 		case ROLLOFF_35:
13670d788680SLuis Alves 			state->dnxt.rolloff_val = CX24117_ROLLOFF_035;
13680d788680SLuis Alves 			break;
13690d788680SLuis Alves 		case ROLLOFF_AUTO:
13700d788680SLuis Alves 			state->dnxt.rolloff_val = CX24117_ROLLOFF_035;
13710d788680SLuis Alves 			/* soft-auto rolloff */
13720d788680SLuis Alves 			retune = 3;
13730d788680SLuis Alves 			break;
13740d788680SLuis Alves 		default:
13750d788680SLuis Alves 			dev_warn(&state->priv->i2c->dev,
13760d788680SLuis Alves 				"%s: demod%d unsupported rolloff (%d)\n",
13770d788680SLuis Alves 				KBUILD_MODNAME, state->demod, c->rolloff);
13780d788680SLuis Alves 			return -EOPNOTSUPP;
13790d788680SLuis Alves 		}
13800d788680SLuis Alves 		break;
13810d788680SLuis Alves 
13820d788680SLuis Alves 	default:
13830d788680SLuis Alves 		dev_warn(&state->priv->i2c->dev,
13840d788680SLuis Alves 			"%s: demod %d unsupported delivery system (%d)\n",
13850d788680SLuis Alves 			KBUILD_MODNAME, state->demod, c->delivery_system);
13860d788680SLuis Alves 		return -EINVAL;
13870d788680SLuis Alves 	}
13880d788680SLuis Alves 
13890d788680SLuis Alves 	state->dnxt.delsys = c->delivery_system;
13900d788680SLuis Alves 	state->dnxt.modulation = c->modulation;
13910d788680SLuis Alves 	state->dnxt.frequency = c->frequency;
13920d788680SLuis Alves 	state->dnxt.pilot = c->pilot;
13930d788680SLuis Alves 	state->dnxt.rolloff = c->rolloff;
13940d788680SLuis Alves 
13950d788680SLuis Alves 	ret = cx24117_set_inversion(state, c->inversion);
13960d788680SLuis Alves 	if (ret !=  0)
13970d788680SLuis Alves 		return ret;
13980d788680SLuis Alves 
13990d788680SLuis Alves 	ret = cx24117_set_fec(state,
14000d788680SLuis Alves 		c->delivery_system, c->modulation, c->fec_inner);
14010d788680SLuis Alves 	if (ret !=  0)
14020d788680SLuis Alves 		return ret;
14030d788680SLuis Alves 
14040d788680SLuis Alves 	ret = cx24117_set_symbolrate(state, c->symbol_rate);
14050d788680SLuis Alves 	if (ret !=  0)
14060d788680SLuis Alves 		return ret;
14070d788680SLuis Alves 
14080d788680SLuis Alves 	/* discard the 'current' tuning parameters and prepare to tune */
14090d788680SLuis Alves 	cx24117_clone_params(fe);
14100d788680SLuis Alves 
14110d788680SLuis Alves 	dev_dbg(&state->priv->i2c->dev,
14120d788680SLuis Alves 		"%s: delsys      = %d\n", __func__, state->dcur.delsys);
14130d788680SLuis Alves 	dev_dbg(&state->priv->i2c->dev,
14140d788680SLuis Alves 		"%s: modulation  = %d\n", __func__, state->dcur.modulation);
14150d788680SLuis Alves 	dev_dbg(&state->priv->i2c->dev,
14160d788680SLuis Alves 		"%s: frequency   = %d\n", __func__, state->dcur.frequency);
14170d788680SLuis Alves 	dev_dbg(&state->priv->i2c->dev,
14180d788680SLuis Alves 		"%s: pilot       = %d (val = 0x%02x)\n", __func__,
14190d788680SLuis Alves 		state->dcur.pilot, state->dcur.pilot_val);
14200d788680SLuis Alves 	dev_dbg(&state->priv->i2c->dev,
14210d788680SLuis Alves 		"%s: retune      = %d\n", __func__, retune);
14220d788680SLuis Alves 	dev_dbg(&state->priv->i2c->dev,
14230d788680SLuis Alves 		"%s: rolloff     = %d (val = 0x%02x)\n", __func__,
14240d788680SLuis Alves 		state->dcur.rolloff, state->dcur.rolloff_val);
14250d788680SLuis Alves 	dev_dbg(&state->priv->i2c->dev,
14260d788680SLuis Alves 		"%s: symbol_rate = %d\n", __func__, state->dcur.symbol_rate);
14270d788680SLuis Alves 	dev_dbg(&state->priv->i2c->dev,
14280d788680SLuis Alves 		"%s: FEC         = %d (mask/val = 0x%02x/0x%02x)\n", __func__,
14290d788680SLuis Alves 		state->dcur.fec, state->dcur.fec_mask, state->dcur.fec_val);
14300d788680SLuis Alves 	dev_dbg(&state->priv->i2c->dev,
14310d788680SLuis Alves 		"%s: Inversion   = %d (val = 0x%02x)\n", __func__,
14320d788680SLuis Alves 		state->dcur.inversion, state->dcur.inversion_val);
14330d788680SLuis Alves 
14340d788680SLuis Alves 	/* Prepare a tune request */
14350d788680SLuis Alves 	cmd.args[0] = CMD_TUNEREQUEST;
14360d788680SLuis Alves 
14370d788680SLuis Alves 	/* demod */
14380d788680SLuis Alves 	cmd.args[1] = state->demod;
14390d788680SLuis Alves 
14400d788680SLuis Alves 	/* Frequency */
14410d788680SLuis Alves 	cmd.args[2] = (state->dcur.frequency & 0xff0000) >> 16;
14420d788680SLuis Alves 	cmd.args[3] = (state->dcur.frequency & 0x00ff00) >> 8;
14430d788680SLuis Alves 	cmd.args[4] = (state->dcur.frequency & 0x0000ff);
14440d788680SLuis Alves 
14450d788680SLuis Alves 	/* Symbol Rate */
14460d788680SLuis Alves 	cmd.args[5] = ((state->dcur.symbol_rate / 1000) & 0xff00) >> 8;
14470d788680SLuis Alves 	cmd.args[6] = ((state->dcur.symbol_rate / 1000) & 0x00ff);
14480d788680SLuis Alves 
14490d788680SLuis Alves 	/* Automatic Inversion */
14500d788680SLuis Alves 	cmd.args[7] = state->dcur.inversion_val;
14510d788680SLuis Alves 
14520d788680SLuis Alves 	/* Modulation / FEC / Pilot */
14530d788680SLuis Alves 	cmd.args[8] = state->dcur.fec_val | state->dcur.pilot_val;
14540d788680SLuis Alves 
14550d788680SLuis Alves 	cmd.args[9] = CX24117_SEARCH_RANGE_KHZ >> 8;
14560d788680SLuis Alves 	cmd.args[10] = CX24117_SEARCH_RANGE_KHZ & 0xff;
14570d788680SLuis Alves 
14580d788680SLuis Alves 	cmd.args[11] = state->dcur.rolloff_val;
14590d788680SLuis Alves 	cmd.args[12] = state->dcur.fec_mask;
14600d788680SLuis Alves 
14610d788680SLuis Alves 	if (state->dcur.symbol_rate > 30000000) {
14620d788680SLuis Alves 		reg_ratediv = 0x04;
14630d788680SLuis Alves 		reg_clkdiv = 0x02;
14640d788680SLuis Alves 	} else if (state->dcur.symbol_rate > 10000000) {
14650d788680SLuis Alves 		reg_ratediv = 0x06;
14660d788680SLuis Alves 		reg_clkdiv = 0x03;
14670d788680SLuis Alves 	} else {
14680d788680SLuis Alves 		reg_ratediv = 0x0a;
14690d788680SLuis Alves 		reg_clkdiv = 0x05;
14700d788680SLuis Alves 	}
14710d788680SLuis Alves 
14720d788680SLuis Alves 	cmd.args[13] = reg_ratediv;
14730d788680SLuis Alves 	cmd.args[14] = reg_clkdiv;
14740d788680SLuis Alves 
14750d788680SLuis Alves 	cx24117_writereg(state, (state->demod == 0) ?
14760d788680SLuis Alves 		CX24117_REG_CLKDIV0 : CX24117_REG_CLKDIV1, reg_clkdiv);
14770d788680SLuis Alves 	cx24117_writereg(state, (state->demod == 0) ?
14780d788680SLuis Alves 		CX24117_REG_RATEDIV0 : CX24117_REG_RATEDIV1, reg_ratediv);
14790d788680SLuis Alves 
14800d788680SLuis Alves 	cmd.args[15] = CX24117_PNE;
14810d788680SLuis Alves 	cmd.len = 16;
14820d788680SLuis Alves 
14830d788680SLuis Alves 	do {
14840d788680SLuis Alves 		/* Reset status register */
14850d788680SLuis Alves 		status = cx24117_readreg(state, (state->demod == 0) ?
14860d788680SLuis Alves 			CX24117_REG_SSTATUS0 : CX24117_REG_SSTATUS1) &
14870d788680SLuis Alves 			CX24117_SIGNAL_MASK;
14880d788680SLuis Alves 
14890d788680SLuis Alves 		dev_dbg(&state->priv->i2c->dev,
14900d788680SLuis Alves 			"%s() demod%d status_setfe = %02x\n",
14910d788680SLuis Alves 			__func__, state->demod, status);
14920d788680SLuis Alves 
14930d788680SLuis Alves 		cx24117_writereg(state, (state->demod == 0) ?
14940d788680SLuis Alves 			CX24117_REG_SSTATUS0 : CX24117_REG_SSTATUS1, status);
14950d788680SLuis Alves 
14960d788680SLuis Alves 		/* Tune */
14970d788680SLuis Alves 		ret = cx24117_cmd_execute(fe, &cmd);
14980d788680SLuis Alves 		if (ret != 0)
14990d788680SLuis Alves 			break;
15000d788680SLuis Alves 
15010d788680SLuis Alves 		/*
15020d788680SLuis Alves 		 * Wait for up to 500 ms before retrying
15030d788680SLuis Alves 		 *
15040d788680SLuis Alves 		 * If we are able to tune then generally it occurs within 100ms.
15050d788680SLuis Alves 		 * If it takes longer, try a different rolloff setting.
15060d788680SLuis Alves 		 */
15070d788680SLuis Alves 		for (i = 0; i < 50; i++) {
15080d788680SLuis Alves 			cx24117_read_status(fe, &tunerstat);
15090d788680SLuis Alves 			status = tunerstat & (FE_HAS_SIGNAL | FE_HAS_SYNC);
15100d788680SLuis Alves 			if (status == (FE_HAS_SIGNAL | FE_HAS_SYNC)) {
15110d788680SLuis Alves 				dev_dbg(&state->priv->i2c->dev,
15120d788680SLuis Alves 					"%s() demod%d tuned\n",
15130d788680SLuis Alves 					__func__, state->demod);
15140d788680SLuis Alves 				return 0;
15150d788680SLuis Alves 			}
15160d788680SLuis Alves 			msleep(20);
15170d788680SLuis Alves 		}
15180d788680SLuis Alves 
15190d788680SLuis Alves 		dev_dbg(&state->priv->i2c->dev, "%s() demod%d not tuned\n",
15200d788680SLuis Alves 			__func__, state->demod);
15210d788680SLuis Alves 
15220d788680SLuis Alves 		/* try next rolloff value */
15230d788680SLuis Alves 		if (state->dcur.rolloff == 3)
15240d788680SLuis Alves 			cmd.args[11]--;
15250d788680SLuis Alves 
15260d788680SLuis Alves 	} while (--retune);
15270d788680SLuis Alves 	return -EINVAL;
15280d788680SLuis Alves }
15290d788680SLuis Alves 
cx24117_tune(struct dvb_frontend * fe,bool re_tune,unsigned int mode_flags,unsigned int * delay,enum fe_status * status)15300d788680SLuis Alves static int cx24117_tune(struct dvb_frontend *fe, bool re_tune,
15310df289a2SMauro Carvalho Chehab 	unsigned int mode_flags, unsigned int *delay, enum fe_status *status)
15320d788680SLuis Alves {
15330d788680SLuis Alves 	struct cx24117_state *state = fe->demodulator_priv;
15340d788680SLuis Alves 
15350d788680SLuis Alves 	dev_dbg(&state->priv->i2c->dev, "%s() demod%d\n",
15360d788680SLuis Alves 		__func__, state->demod);
15370d788680SLuis Alves 
15380d788680SLuis Alves 	*delay = HZ / 5;
15390d788680SLuis Alves 	if (re_tune) {
15400d788680SLuis Alves 		int ret = cx24117_set_frontend(fe);
15410d788680SLuis Alves 		if (ret)
15420d788680SLuis Alves 			return ret;
15430d788680SLuis Alves 	}
15440d788680SLuis Alves 	return cx24117_read_status(fe, status);
15450d788680SLuis Alves }
15460d788680SLuis Alves 
cx24117_get_algo(struct dvb_frontend * fe)15478d718e53SLuc Van Oostenryck static enum dvbfe_algo cx24117_get_algo(struct dvb_frontend *fe)
15480d788680SLuis Alves {
15490d788680SLuis Alves 	return DVBFE_ALGO_HW;
15500d788680SLuis Alves }
15510d788680SLuis Alves 
cx24117_get_frontend(struct dvb_frontend * fe,struct dtv_frontend_properties * c)15527e3e68bcSMauro Carvalho Chehab static int cx24117_get_frontend(struct dvb_frontend *fe,
15537e3e68bcSMauro Carvalho Chehab 				struct dtv_frontend_properties *c)
15540d788680SLuis Alves {
15550d788680SLuis Alves 	struct cx24117_state *state = fe->demodulator_priv;
15560d788680SLuis Alves 	struct cx24117_cmd cmd;
15570d788680SLuis Alves 	u8 reg, st, inv;
15580d788680SLuis Alves 	int ret, idx;
15590d788680SLuis Alves 	unsigned int freq;
15600d788680SLuis Alves 	short srate_os, freq_os;
15610d788680SLuis Alves 
15620d788680SLuis Alves 	u8 buf[0x1f-4];
15630d788680SLuis Alves 
15649fa7c419SLuis Alves 	/* Read current tune parameters */
15659fa7c419SLuis Alves 	cmd.args[0] = CMD_GETCTLACC;
15660d788680SLuis Alves 	cmd.args[1] = (u8) state->demod;
15670d788680SLuis Alves 	cmd.len = 2;
15680d788680SLuis Alves 	ret = cx24117_cmd_execute(fe, &cmd);
15690d788680SLuis Alves 	if (ret != 0)
15700d788680SLuis Alves 		return ret;
15710d788680SLuis Alves 
15720d788680SLuis Alves 	/* read all required regs at once */
15730d788680SLuis Alves 	reg = (state->demod == 0) ? CX24117_REG_FREQ3_0 : CX24117_REG_FREQ3_1;
15740d788680SLuis Alves 	ret = cx24117_readregN(state, reg, buf, 0x1f-4);
15750d788680SLuis Alves 	if (ret != 0)
15760d788680SLuis Alves 		return ret;
15770d788680SLuis Alves 
15780d788680SLuis Alves 	st = buf[5];
15790d788680SLuis Alves 
15800d788680SLuis Alves 	/* get spectral inversion */
15810d788680SLuis Alves 	inv = (((state->demod == 0) ? ~st : st) >> 6) & 1;
15820d788680SLuis Alves 	if (inv == 0)
15830d788680SLuis Alves 		c->inversion = INVERSION_OFF;
15840d788680SLuis Alves 	else
15850d788680SLuis Alves 		c->inversion = INVERSION_ON;
15860d788680SLuis Alves 
15870d788680SLuis Alves 	/* modulation and fec */
15880d788680SLuis Alves 	idx = st & 0x3f;
15890d788680SLuis Alves 	if (c->delivery_system == SYS_DVBS2) {
15900d788680SLuis Alves 		if (idx > 11)
15910d788680SLuis Alves 			idx += 9;
15920d788680SLuis Alves 		else
15930d788680SLuis Alves 			idx += 7;
15940d788680SLuis Alves 	}
15950d788680SLuis Alves 
15960d788680SLuis Alves 	c->modulation = cx24117_modfec_modes[idx].modulation;
15970d788680SLuis Alves 	c->fec_inner = cx24117_modfec_modes[idx].fec;
15980d788680SLuis Alves 
15990d788680SLuis Alves 	/* frequency */
16000d788680SLuis Alves 	freq = (buf[0] << 16) | (buf[1] << 8) | buf[2];
16010d788680SLuis Alves 	freq_os = (buf[8] << 8) | buf[9];
16020d788680SLuis Alves 	c->frequency = freq + freq_os;
16030d788680SLuis Alves 
16040d788680SLuis Alves 	/* symbol rate */
16050d788680SLuis Alves 	srate_os = (buf[10] << 8) | buf[11];
16060d788680SLuis Alves 	c->symbol_rate = -1000 * srate_os + state->dcur.symbol_rate;
16070d788680SLuis Alves 	return 0;
16080d788680SLuis Alves }
16090d788680SLuis Alves 
1610bd336e63SMax Kellermann static const struct dvb_frontend_ops cx24117_ops = {
16110d788680SLuis Alves 	.delsys = { SYS_DVBS, SYS_DVBS2 },
16120d788680SLuis Alves 	.info = {
16130d788680SLuis Alves 		.name = "Conexant CX24117/CX24132",
1614f1b1eabfSMauro Carvalho Chehab 		.frequency_min_hz =  950 * MHz,
1615f1b1eabfSMauro Carvalho Chehab 		.frequency_max_hz = 2150 * MHz,
1616f1b1eabfSMauro Carvalho Chehab 		.frequency_stepsize_hz = 1011 * kHz,
1617f1b1eabfSMauro Carvalho Chehab 		.frequency_tolerance_hz = 5 * MHz,
16180d788680SLuis Alves 		.symbol_rate_min = 1000000,
16190d788680SLuis Alves 		.symbol_rate_max = 45000000,
16200d788680SLuis Alves 		.caps = FE_CAN_INVERSION_AUTO |
16210d788680SLuis Alves 			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
16220d788680SLuis Alves 			FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
16230d788680SLuis Alves 			FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
16240d788680SLuis Alves 			FE_CAN_2G_MODULATION |
16250d788680SLuis Alves 			FE_CAN_QPSK | FE_CAN_RECOVER
16260d788680SLuis Alves 	},
16270d788680SLuis Alves 
16280d788680SLuis Alves 	.release = cx24117_release,
16290d788680SLuis Alves 
16300d788680SLuis Alves 	.init = cx24117_initfe,
16310d788680SLuis Alves 	.sleep = cx24117_sleep,
16320d788680SLuis Alves 	.read_status = cx24117_read_status,
16330d788680SLuis Alves 	.read_ber = cx24117_read_ber,
16340d788680SLuis Alves 	.read_signal_strength = cx24117_read_signal_strength,
16350d788680SLuis Alves 	.read_snr = cx24117_read_snr,
16360d788680SLuis Alves 	.read_ucblocks = cx24117_read_ucblocks,
16370d788680SLuis Alves 	.set_tone = cx24117_set_tone,
16380d788680SLuis Alves 	.set_voltage = cx24117_set_voltage,
16390d788680SLuis Alves 	.diseqc_send_master_cmd = cx24117_send_diseqc_msg,
16400d788680SLuis Alves 	.diseqc_send_burst = cx24117_diseqc_send_burst,
16410d788680SLuis Alves 	.get_frontend_algo = cx24117_get_algo,
16420d788680SLuis Alves 	.tune = cx24117_tune,
16430d788680SLuis Alves 
16440d788680SLuis Alves 	.set_frontend = cx24117_set_frontend,
16450d788680SLuis Alves 	.get_frontend = cx24117_get_frontend,
16460d788680SLuis Alves };
16470d788680SLuis Alves 
16480d788680SLuis Alves 
16490d788680SLuis Alves MODULE_DESCRIPTION("DVB Frontend module for Conexant cx24117/cx24132 hardware");
1650*6a57a219SAhelenia Ziemiańska MODULE_AUTHOR("Luis Alves <ljalvs@gmail.com>");
16510d788680SLuis Alves MODULE_LICENSE("GPL");
16520d788680SLuis Alves MODULE_VERSION("1.1");
16530d788680SLuis Alves MODULE_FIRMWARE(CX24117_DEFAULT_FIRMWARE);
16540d788680SLuis Alves 
1655