xref: /openbmc/linux/drivers/media/tuners/xc2028.c (revision 85030415)
1d76231e4SMauro Carvalho Chehab // SPDX-License-Identifier: GPL-2.0
2d76231e4SMauro Carvalho Chehab // xc2028
3d76231e4SMauro Carvalho Chehab //
4d76231e4SMauro Carvalho Chehab // Copyright (c) 2007-2008 Mauro Carvalho Chehab <mchehab@kernel.org>
5d76231e4SMauro Carvalho Chehab //
6d76231e4SMauro Carvalho Chehab // Copyright (c) 2007 Michel Ludwig (michel.ludwig@gmail.com)
7d76231e4SMauro Carvalho Chehab //       - frontend interface
8d76231e4SMauro Carvalho Chehab 
9d76231e4SMauro Carvalho Chehab #include <linux/i2c.h>
10d76231e4SMauro Carvalho Chehab #include <asm/div64.h>
11d76231e4SMauro Carvalho Chehab #include <linux/firmware.h>
12d76231e4SMauro Carvalho Chehab #include <linux/videodev2.h>
13d76231e4SMauro Carvalho Chehab #include <linux/delay.h>
14d76231e4SMauro Carvalho Chehab #include <media/tuner.h>
15d76231e4SMauro Carvalho Chehab #include <linux/mutex.h>
16d76231e4SMauro Carvalho Chehab #include <linux/slab.h>
17d76231e4SMauro Carvalho Chehab #include <asm/unaligned.h>
18d76231e4SMauro Carvalho Chehab #include "tuner-i2c.h"
19d76231e4SMauro Carvalho Chehab #include "xc2028.h"
20d76231e4SMauro Carvalho Chehab #include "xc2028-types.h"
21d76231e4SMauro Carvalho Chehab 
22d76231e4SMauro Carvalho Chehab #include <linux/dvb/frontend.h>
23d76231e4SMauro Carvalho Chehab #include <media/dvb_frontend.h>
24d76231e4SMauro Carvalho Chehab 
25d76231e4SMauro Carvalho Chehab /* Max transfer size done by I2C transfer functions */
26d76231e4SMauro Carvalho Chehab #define MAX_XFER_SIZE  80
27d76231e4SMauro Carvalho Chehab 
28d76231e4SMauro Carvalho Chehab /* Registers (Write-only) */
29d76231e4SMauro Carvalho Chehab #define XREG_INIT         0x00
30d76231e4SMauro Carvalho Chehab #define XREG_RF_FREQ      0x02
31d76231e4SMauro Carvalho Chehab #define XREG_POWER_DOWN   0x08
32d76231e4SMauro Carvalho Chehab 
33d76231e4SMauro Carvalho Chehab /* Registers (Read-only) */
34d76231e4SMauro Carvalho Chehab #define XREG_FREQ_ERROR   0x01
35d76231e4SMauro Carvalho Chehab #define XREG_LOCK         0x02
36d76231e4SMauro Carvalho Chehab #define XREG_VERSION      0x04
37d76231e4SMauro Carvalho Chehab #define XREG_PRODUCT_ID   0x08
38d76231e4SMauro Carvalho Chehab #define XREG_HSYNC_FREQ   0x10
39d76231e4SMauro Carvalho Chehab #define XREG_FRAME_LINES  0x20
40d76231e4SMauro Carvalho Chehab #define XREG_SNR          0x40
41d76231e4SMauro Carvalho Chehab 
42d76231e4SMauro Carvalho Chehab #define XREG_ADC_ENV      0x0100
43d76231e4SMauro Carvalho Chehab 
44d76231e4SMauro Carvalho Chehab static int debug;
45d76231e4SMauro Carvalho Chehab module_param(debug, int, 0644);
46d76231e4SMauro Carvalho Chehab MODULE_PARM_DESC(debug, "enable verbose debug messages");
47d76231e4SMauro Carvalho Chehab 
48d76231e4SMauro Carvalho Chehab static int no_poweroff;
49d76231e4SMauro Carvalho Chehab module_param(no_poweroff, int, 0644);
50d76231e4SMauro Carvalho Chehab MODULE_PARM_DESC(no_poweroff, "0 (default) powers device off when not used.\n"
51d76231e4SMauro Carvalho Chehab 	"1 keep device energized and with tuner ready all the times.\n"
52d76231e4SMauro Carvalho Chehab 	"  Faster, but consumes more power and keeps the device hotter\n");
53d76231e4SMauro Carvalho Chehab 
54d76231e4SMauro Carvalho Chehab static char audio_std[8];
55d76231e4SMauro Carvalho Chehab module_param_string(audio_std, audio_std, sizeof(audio_std), 0);
56d76231e4SMauro Carvalho Chehab MODULE_PARM_DESC(audio_std,
57d76231e4SMauro Carvalho Chehab 	"Audio standard. XC3028 audio decoder explicitly needs to know what audio\n"
58d76231e4SMauro Carvalho Chehab 	"standard is needed for some video standards with audio A2 or NICAM.\n"
59d76231e4SMauro Carvalho Chehab 	"The valid values are:\n"
60d76231e4SMauro Carvalho Chehab 	"A2\n"
61d76231e4SMauro Carvalho Chehab 	"A2/A\n"
62d76231e4SMauro Carvalho Chehab 	"A2/B\n"
63d76231e4SMauro Carvalho Chehab 	"NICAM\n"
64d76231e4SMauro Carvalho Chehab 	"NICAM/A\n"
65d76231e4SMauro Carvalho Chehab 	"NICAM/B\n");
66d76231e4SMauro Carvalho Chehab 
67d76231e4SMauro Carvalho Chehab static char firmware_name[30];
68d76231e4SMauro Carvalho Chehab module_param_string(firmware_name, firmware_name, sizeof(firmware_name), 0);
69d76231e4SMauro Carvalho Chehab MODULE_PARM_DESC(firmware_name,
70d76231e4SMauro Carvalho Chehab 		 "Firmware file name. Allows overriding the default firmware name\n");
71d76231e4SMauro Carvalho Chehab 
72d76231e4SMauro Carvalho Chehab static LIST_HEAD(hybrid_tuner_instance_list);
73d76231e4SMauro Carvalho Chehab static DEFINE_MUTEX(xc2028_list_mutex);
74d76231e4SMauro Carvalho Chehab 
75d76231e4SMauro Carvalho Chehab /* struct for storing firmware table */
76d76231e4SMauro Carvalho Chehab struct firmware_description {
77d76231e4SMauro Carvalho Chehab 	unsigned int  type;
78d76231e4SMauro Carvalho Chehab 	v4l2_std_id   id;
79d76231e4SMauro Carvalho Chehab 	__u16         int_freq;
80d76231e4SMauro Carvalho Chehab 	unsigned char *ptr;
81d76231e4SMauro Carvalho Chehab 	unsigned int  size;
82d76231e4SMauro Carvalho Chehab };
83d76231e4SMauro Carvalho Chehab 
84d76231e4SMauro Carvalho Chehab struct firmware_properties {
85d76231e4SMauro Carvalho Chehab 	unsigned int	type;
86d76231e4SMauro Carvalho Chehab 	v4l2_std_id	id;
87d76231e4SMauro Carvalho Chehab 	v4l2_std_id	std_req;
88d76231e4SMauro Carvalho Chehab 	__u16		int_freq;
89d76231e4SMauro Carvalho Chehab 	unsigned int	scode_table;
90d76231e4SMauro Carvalho Chehab 	int		scode_nr;
91d76231e4SMauro Carvalho Chehab };
92d76231e4SMauro Carvalho Chehab 
93d76231e4SMauro Carvalho Chehab enum xc2028_state {
94d76231e4SMauro Carvalho Chehab 	XC2028_NO_FIRMWARE = 0,
95d76231e4SMauro Carvalho Chehab 	XC2028_WAITING_FIRMWARE,
96d76231e4SMauro Carvalho Chehab 	XC2028_ACTIVE,
97d76231e4SMauro Carvalho Chehab 	XC2028_SLEEP,
98d76231e4SMauro Carvalho Chehab 	XC2028_NODEV,
99d76231e4SMauro Carvalho Chehab };
100d76231e4SMauro Carvalho Chehab 
101d76231e4SMauro Carvalho Chehab struct xc2028_data {
102d76231e4SMauro Carvalho Chehab 	struct list_head        hybrid_tuner_instance_list;
103d76231e4SMauro Carvalho Chehab 	struct tuner_i2c_props  i2c_props;
104d76231e4SMauro Carvalho Chehab 	__u32			frequency;
105d76231e4SMauro Carvalho Chehab 
106d76231e4SMauro Carvalho Chehab 	enum xc2028_state	state;
107d76231e4SMauro Carvalho Chehab 	const char		*fname;
108d76231e4SMauro Carvalho Chehab 
109d76231e4SMauro Carvalho Chehab 	struct firmware_description *firm;
110d76231e4SMauro Carvalho Chehab 	int			firm_size;
111d76231e4SMauro Carvalho Chehab 	__u16			firm_version;
112d76231e4SMauro Carvalho Chehab 
113d76231e4SMauro Carvalho Chehab 	__u16			hwmodel;
114d76231e4SMauro Carvalho Chehab 	__u16			hwvers;
115d76231e4SMauro Carvalho Chehab 
116d76231e4SMauro Carvalho Chehab 	struct xc2028_ctrl	ctrl;
117d76231e4SMauro Carvalho Chehab 
118d76231e4SMauro Carvalho Chehab 	struct firmware_properties cur_fw;
119d76231e4SMauro Carvalho Chehab 
120d76231e4SMauro Carvalho Chehab 	struct mutex lock;
121d76231e4SMauro Carvalho Chehab };
122d76231e4SMauro Carvalho Chehab 
123d76231e4SMauro Carvalho Chehab #define i2c_send(priv, buf, size) ({					\
124d76231e4SMauro Carvalho Chehab 	int _rc;							\
125d76231e4SMauro Carvalho Chehab 	_rc = tuner_i2c_xfer_send(&priv->i2c_props, buf, size);		\
126d76231e4SMauro Carvalho Chehab 	if (size != _rc)						\
127d76231e4SMauro Carvalho Chehab 		tuner_info("i2c output error: rc = %d (should be %d)\n",\
128d76231e4SMauro Carvalho Chehab 			   _rc, (int)size);				\
129d76231e4SMauro Carvalho Chehab 	if (priv->ctrl.msleep)						\
130d76231e4SMauro Carvalho Chehab 		msleep(priv->ctrl.msleep);				\
131d76231e4SMauro Carvalho Chehab 	_rc;								\
132d76231e4SMauro Carvalho Chehab })
133d76231e4SMauro Carvalho Chehab 
134d76231e4SMauro Carvalho Chehab #define i2c_send_recv(priv, obuf, osize, ibuf, isize) ({		\
135d76231e4SMauro Carvalho Chehab 	int _rc;							\
136d76231e4SMauro Carvalho Chehab 	_rc = tuner_i2c_xfer_send_recv(&priv->i2c_props, obuf, osize,	\
137d76231e4SMauro Carvalho Chehab 				       ibuf, isize);			\
138d76231e4SMauro Carvalho Chehab 	if (isize != _rc)						\
139d76231e4SMauro Carvalho Chehab 		tuner_err("i2c input error: rc = %d (should be %d)\n",	\
140d76231e4SMauro Carvalho Chehab 			   _rc, (int)isize);				\
141d76231e4SMauro Carvalho Chehab 	if (priv->ctrl.msleep)						\
142d76231e4SMauro Carvalho Chehab 		msleep(priv->ctrl.msleep);				\
143d76231e4SMauro Carvalho Chehab 	_rc;								\
144d76231e4SMauro Carvalho Chehab })
145d76231e4SMauro Carvalho Chehab 
146d76231e4SMauro Carvalho Chehab #define send_seq(priv, data...)	({					\
147d76231e4SMauro Carvalho Chehab 	static u8 _val[] = data;					\
148d76231e4SMauro Carvalho Chehab 	int _rc;							\
149d76231e4SMauro Carvalho Chehab 	if (sizeof(_val) !=						\
150d76231e4SMauro Carvalho Chehab 			(_rc = tuner_i2c_xfer_send(&priv->i2c_props,	\
151d76231e4SMauro Carvalho Chehab 						_val, sizeof(_val)))) {	\
152d76231e4SMauro Carvalho Chehab 		tuner_err("Error on line %d: %d\n", __LINE__, _rc);	\
153d76231e4SMauro Carvalho Chehab 	} else if (priv->ctrl.msleep)					\
154d76231e4SMauro Carvalho Chehab 		msleep(priv->ctrl.msleep);				\
155d76231e4SMauro Carvalho Chehab 	_rc;								\
156d76231e4SMauro Carvalho Chehab })
157d76231e4SMauro Carvalho Chehab 
xc2028_get_reg(struct xc2028_data * priv,u16 reg,u16 * val)158d76231e4SMauro Carvalho Chehab static int xc2028_get_reg(struct xc2028_data *priv, u16 reg, u16 *val)
159d76231e4SMauro Carvalho Chehab {
160d76231e4SMauro Carvalho Chehab 	unsigned char buf[2];
161d76231e4SMauro Carvalho Chehab 	unsigned char ibuf[2];
162d76231e4SMauro Carvalho Chehab 
163d76231e4SMauro Carvalho Chehab 	tuner_dbg("%s %04x called\n", __func__, reg);
164d76231e4SMauro Carvalho Chehab 
165d76231e4SMauro Carvalho Chehab 	buf[0] = reg >> 8;
166d76231e4SMauro Carvalho Chehab 	buf[1] = (unsigned char) reg;
167d76231e4SMauro Carvalho Chehab 
168d76231e4SMauro Carvalho Chehab 	if (i2c_send_recv(priv, buf, 2, ibuf, 2) != 2)
169d76231e4SMauro Carvalho Chehab 		return -EIO;
170d76231e4SMauro Carvalho Chehab 
171d76231e4SMauro Carvalho Chehab 	*val = (ibuf[1]) | (ibuf[0] << 8);
172d76231e4SMauro Carvalho Chehab 	return 0;
173d76231e4SMauro Carvalho Chehab }
174d76231e4SMauro Carvalho Chehab 
175d76231e4SMauro Carvalho Chehab #define dump_firm_type(t)	dump_firm_type_and_int_freq(t, 0)
dump_firm_type_and_int_freq(unsigned int type,u16 int_freq)176d76231e4SMauro Carvalho Chehab static void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq)
177d76231e4SMauro Carvalho Chehab {
178d76231e4SMauro Carvalho Chehab 	if (type & BASE)
179d76231e4SMauro Carvalho Chehab 		printk(KERN_CONT "BASE ");
180d76231e4SMauro Carvalho Chehab 	if (type & INIT1)
181d76231e4SMauro Carvalho Chehab 		printk(KERN_CONT "INIT1 ");
182d76231e4SMauro Carvalho Chehab 	if (type & F8MHZ)
183d76231e4SMauro Carvalho Chehab 		printk(KERN_CONT "F8MHZ ");
184d76231e4SMauro Carvalho Chehab 	if (type & MTS)
185d76231e4SMauro Carvalho Chehab 		printk(KERN_CONT "MTS ");
186d76231e4SMauro Carvalho Chehab 	if (type & D2620)
187d76231e4SMauro Carvalho Chehab 		printk(KERN_CONT "D2620 ");
188d76231e4SMauro Carvalho Chehab 	if (type & D2633)
189d76231e4SMauro Carvalho Chehab 		printk(KERN_CONT "D2633 ");
190d76231e4SMauro Carvalho Chehab 	if (type & DTV6)
191d76231e4SMauro Carvalho Chehab 		printk(KERN_CONT "DTV6 ");
192d76231e4SMauro Carvalho Chehab 	if (type & QAM)
193d76231e4SMauro Carvalho Chehab 		printk(KERN_CONT "QAM ");
194d76231e4SMauro Carvalho Chehab 	if (type & DTV7)
195d76231e4SMauro Carvalho Chehab 		printk(KERN_CONT "DTV7 ");
196d76231e4SMauro Carvalho Chehab 	if (type & DTV78)
197d76231e4SMauro Carvalho Chehab 		printk(KERN_CONT "DTV78 ");
198d76231e4SMauro Carvalho Chehab 	if (type & DTV8)
199d76231e4SMauro Carvalho Chehab 		printk(KERN_CONT "DTV8 ");
200d76231e4SMauro Carvalho Chehab 	if (type & FM)
201d76231e4SMauro Carvalho Chehab 		printk(KERN_CONT "FM ");
202d76231e4SMauro Carvalho Chehab 	if (type & INPUT1)
203d76231e4SMauro Carvalho Chehab 		printk(KERN_CONT "INPUT1 ");
204d76231e4SMauro Carvalho Chehab 	if (type & LCD)
205d76231e4SMauro Carvalho Chehab 		printk(KERN_CONT "LCD ");
206d76231e4SMauro Carvalho Chehab 	if (type & NOGD)
207d76231e4SMauro Carvalho Chehab 		printk(KERN_CONT "NOGD ");
208d76231e4SMauro Carvalho Chehab 	if (type & MONO)
209d76231e4SMauro Carvalho Chehab 		printk(KERN_CONT "MONO ");
210d76231e4SMauro Carvalho Chehab 	if (type & ATSC)
211d76231e4SMauro Carvalho Chehab 		printk(KERN_CONT "ATSC ");
212d76231e4SMauro Carvalho Chehab 	if (type & IF)
213d76231e4SMauro Carvalho Chehab 		printk(KERN_CONT "IF ");
214d76231e4SMauro Carvalho Chehab 	if (type & LG60)
215d76231e4SMauro Carvalho Chehab 		printk(KERN_CONT "LG60 ");
216d76231e4SMauro Carvalho Chehab 	if (type & ATI638)
217d76231e4SMauro Carvalho Chehab 		printk(KERN_CONT "ATI638 ");
218d76231e4SMauro Carvalho Chehab 	if (type & OREN538)
219d76231e4SMauro Carvalho Chehab 		printk(KERN_CONT "OREN538 ");
220d76231e4SMauro Carvalho Chehab 	if (type & OREN36)
221d76231e4SMauro Carvalho Chehab 		printk(KERN_CONT "OREN36 ");
222d76231e4SMauro Carvalho Chehab 	if (type & TOYOTA388)
223d76231e4SMauro Carvalho Chehab 		printk(KERN_CONT "TOYOTA388 ");
224d76231e4SMauro Carvalho Chehab 	if (type & TOYOTA794)
225d76231e4SMauro Carvalho Chehab 		printk(KERN_CONT "TOYOTA794 ");
226d76231e4SMauro Carvalho Chehab 	if (type & DIBCOM52)
227d76231e4SMauro Carvalho Chehab 		printk(KERN_CONT "DIBCOM52 ");
228d76231e4SMauro Carvalho Chehab 	if (type & ZARLINK456)
229d76231e4SMauro Carvalho Chehab 		printk(KERN_CONT "ZARLINK456 ");
230d76231e4SMauro Carvalho Chehab 	if (type & CHINA)
231d76231e4SMauro Carvalho Chehab 		printk(KERN_CONT "CHINA ");
232d76231e4SMauro Carvalho Chehab 	if (type & F6MHZ)
233d76231e4SMauro Carvalho Chehab 		printk(KERN_CONT "F6MHZ ");
234d76231e4SMauro Carvalho Chehab 	if (type & INPUT2)
235d76231e4SMauro Carvalho Chehab 		printk(KERN_CONT "INPUT2 ");
236d76231e4SMauro Carvalho Chehab 	if (type & SCODE)
237d76231e4SMauro Carvalho Chehab 		printk(KERN_CONT "SCODE ");
238d76231e4SMauro Carvalho Chehab 	if (type & HAS_IF)
239d76231e4SMauro Carvalho Chehab 		printk(KERN_CONT "HAS_IF_%d ", int_freq);
240d76231e4SMauro Carvalho Chehab }
241d76231e4SMauro Carvalho Chehab 
parse_audio_std_option(void)242d76231e4SMauro Carvalho Chehab static  v4l2_std_id parse_audio_std_option(void)
243d76231e4SMauro Carvalho Chehab {
244d76231e4SMauro Carvalho Chehab 	if (strcasecmp(audio_std, "A2") == 0)
245d76231e4SMauro Carvalho Chehab 		return V4L2_STD_A2;
246d76231e4SMauro Carvalho Chehab 	if (strcasecmp(audio_std, "A2/A") == 0)
247d76231e4SMauro Carvalho Chehab 		return V4L2_STD_A2_A;
248d76231e4SMauro Carvalho Chehab 	if (strcasecmp(audio_std, "A2/B") == 0)
249d76231e4SMauro Carvalho Chehab 		return V4L2_STD_A2_B;
250d76231e4SMauro Carvalho Chehab 	if (strcasecmp(audio_std, "NICAM") == 0)
251d76231e4SMauro Carvalho Chehab 		return V4L2_STD_NICAM;
252d76231e4SMauro Carvalho Chehab 	if (strcasecmp(audio_std, "NICAM/A") == 0)
253d76231e4SMauro Carvalho Chehab 		return V4L2_STD_NICAM_A;
254d76231e4SMauro Carvalho Chehab 	if (strcasecmp(audio_std, "NICAM/B") == 0)
255d76231e4SMauro Carvalho Chehab 		return V4L2_STD_NICAM_B;
256d76231e4SMauro Carvalho Chehab 
257d76231e4SMauro Carvalho Chehab 	return 0;
258d76231e4SMauro Carvalho Chehab }
259d76231e4SMauro Carvalho Chehab 
check_device_status(struct xc2028_data * priv)260d76231e4SMauro Carvalho Chehab static int check_device_status(struct xc2028_data *priv)
261d76231e4SMauro Carvalho Chehab {
262d76231e4SMauro Carvalho Chehab 	switch (priv->state) {
263d76231e4SMauro Carvalho Chehab 	case XC2028_NO_FIRMWARE:
264d76231e4SMauro Carvalho Chehab 	case XC2028_WAITING_FIRMWARE:
265d76231e4SMauro Carvalho Chehab 		return -EAGAIN;
266d76231e4SMauro Carvalho Chehab 	case XC2028_ACTIVE:
267d76231e4SMauro Carvalho Chehab 		return 1;
268d76231e4SMauro Carvalho Chehab 	case XC2028_SLEEP:
269d76231e4SMauro Carvalho Chehab 		return 0;
270d76231e4SMauro Carvalho Chehab 	case XC2028_NODEV:
271d76231e4SMauro Carvalho Chehab 		return -ENODEV;
272d76231e4SMauro Carvalho Chehab 	}
273d76231e4SMauro Carvalho Chehab 	return 0;
274d76231e4SMauro Carvalho Chehab }
275d76231e4SMauro Carvalho Chehab 
free_firmware(struct xc2028_data * priv)276d76231e4SMauro Carvalho Chehab static void free_firmware(struct xc2028_data *priv)
277d76231e4SMauro Carvalho Chehab {
278d76231e4SMauro Carvalho Chehab 	int i;
279d76231e4SMauro Carvalho Chehab 	tuner_dbg("%s called\n", __func__);
280d76231e4SMauro Carvalho Chehab 
281d76231e4SMauro Carvalho Chehab 	/* free allocated f/w string */
282d76231e4SMauro Carvalho Chehab 	if (priv->fname != firmware_name)
283d76231e4SMauro Carvalho Chehab 		kfree(priv->fname);
284d76231e4SMauro Carvalho Chehab 	priv->fname = NULL;
285d76231e4SMauro Carvalho Chehab 
286d76231e4SMauro Carvalho Chehab 	priv->state = XC2028_NO_FIRMWARE;
287d76231e4SMauro Carvalho Chehab 	memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
288d76231e4SMauro Carvalho Chehab 
289d76231e4SMauro Carvalho Chehab 	if (!priv->firm)
290d76231e4SMauro Carvalho Chehab 		return;
291d76231e4SMauro Carvalho Chehab 
292d76231e4SMauro Carvalho Chehab 	for (i = 0; i < priv->firm_size; i++)
293d76231e4SMauro Carvalho Chehab 		kfree(priv->firm[i].ptr);
294d76231e4SMauro Carvalho Chehab 
295d76231e4SMauro Carvalho Chehab 	kfree(priv->firm);
296d76231e4SMauro Carvalho Chehab 
297d76231e4SMauro Carvalho Chehab 	priv->firm = NULL;
298d76231e4SMauro Carvalho Chehab 	priv->firm_size = 0;
299d76231e4SMauro Carvalho Chehab }
300d76231e4SMauro Carvalho Chehab 
load_all_firmwares(struct dvb_frontend * fe,const struct firmware * fw)301d76231e4SMauro Carvalho Chehab static int load_all_firmwares(struct dvb_frontend *fe,
302d76231e4SMauro Carvalho Chehab 			      const struct firmware *fw)
303d76231e4SMauro Carvalho Chehab {
304d76231e4SMauro Carvalho Chehab 	struct xc2028_data    *priv = fe->tuner_priv;
305d76231e4SMauro Carvalho Chehab 	const unsigned char   *p, *endp;
306d76231e4SMauro Carvalho Chehab 	int                   rc = 0;
307d76231e4SMauro Carvalho Chehab 	int		      n, n_array;
308d76231e4SMauro Carvalho Chehab 	char		      name[33];
309d76231e4SMauro Carvalho Chehab 
310d76231e4SMauro Carvalho Chehab 	tuner_dbg("%s called\n", __func__);
311d76231e4SMauro Carvalho Chehab 
312d76231e4SMauro Carvalho Chehab 	p = fw->data;
313d76231e4SMauro Carvalho Chehab 	endp = p + fw->size;
314d76231e4SMauro Carvalho Chehab 
315d76231e4SMauro Carvalho Chehab 	if (fw->size < sizeof(name) - 1 + 2 + 2) {
316d76231e4SMauro Carvalho Chehab 		tuner_err("Error: firmware file %s has invalid size!\n",
317d76231e4SMauro Carvalho Chehab 			  priv->fname);
318d76231e4SMauro Carvalho Chehab 		goto corrupt;
319d76231e4SMauro Carvalho Chehab 	}
320d76231e4SMauro Carvalho Chehab 
321d76231e4SMauro Carvalho Chehab 	memcpy(name, p, sizeof(name) - 1);
322d76231e4SMauro Carvalho Chehab 	name[sizeof(name) - 1] = 0;
323d76231e4SMauro Carvalho Chehab 	p += sizeof(name) - 1;
324d76231e4SMauro Carvalho Chehab 
325d76231e4SMauro Carvalho Chehab 	priv->firm_version = get_unaligned_le16(p);
326d76231e4SMauro Carvalho Chehab 	p += 2;
327d76231e4SMauro Carvalho Chehab 
328d76231e4SMauro Carvalho Chehab 	n_array = get_unaligned_le16(p);
329d76231e4SMauro Carvalho Chehab 	p += 2;
330d76231e4SMauro Carvalho Chehab 
331d76231e4SMauro Carvalho Chehab 	tuner_info("Loading %d firmware images from %s, type: %s, ver %d.%d\n",
332d76231e4SMauro Carvalho Chehab 		   n_array, priv->fname, name,
333d76231e4SMauro Carvalho Chehab 		   priv->firm_version >> 8, priv->firm_version & 0xff);
334d76231e4SMauro Carvalho Chehab 
335d76231e4SMauro Carvalho Chehab 	priv->firm = kcalloc(n_array, sizeof(*priv->firm), GFP_KERNEL);
336d76231e4SMauro Carvalho Chehab 	if (priv->firm == NULL) {
337d76231e4SMauro Carvalho Chehab 		tuner_err("Not enough memory to load firmware file.\n");
338d76231e4SMauro Carvalho Chehab 		rc = -ENOMEM;
339d76231e4SMauro Carvalho Chehab 		goto err;
340d76231e4SMauro Carvalho Chehab 	}
341d76231e4SMauro Carvalho Chehab 	priv->firm_size = n_array;
342d76231e4SMauro Carvalho Chehab 
343d76231e4SMauro Carvalho Chehab 	n = -1;
344d76231e4SMauro Carvalho Chehab 	while (p < endp) {
345d76231e4SMauro Carvalho Chehab 		__u32 type, size;
346d76231e4SMauro Carvalho Chehab 		v4l2_std_id id;
347d76231e4SMauro Carvalho Chehab 		__u16 int_freq = 0;
348d76231e4SMauro Carvalho Chehab 
349d76231e4SMauro Carvalho Chehab 		n++;
350d76231e4SMauro Carvalho Chehab 		if (n >= n_array) {
351d76231e4SMauro Carvalho Chehab 			tuner_err("More firmware images in file than were expected!\n");
352d76231e4SMauro Carvalho Chehab 			goto corrupt;
353d76231e4SMauro Carvalho Chehab 		}
354d76231e4SMauro Carvalho Chehab 
355d76231e4SMauro Carvalho Chehab 		/* Checks if there's enough bytes to read */
356d76231e4SMauro Carvalho Chehab 		if (endp - p < sizeof(type) + sizeof(id) + sizeof(size))
357d76231e4SMauro Carvalho Chehab 			goto header;
358d76231e4SMauro Carvalho Chehab 
359d76231e4SMauro Carvalho Chehab 		type = get_unaligned_le32(p);
360d76231e4SMauro Carvalho Chehab 		p += sizeof(type);
361d76231e4SMauro Carvalho Chehab 
362d76231e4SMauro Carvalho Chehab 		id = get_unaligned_le64(p);
363d76231e4SMauro Carvalho Chehab 		p += sizeof(id);
364d76231e4SMauro Carvalho Chehab 
365d76231e4SMauro Carvalho Chehab 		if (type & HAS_IF) {
366d76231e4SMauro Carvalho Chehab 			int_freq = get_unaligned_le16(p);
367d76231e4SMauro Carvalho Chehab 			p += sizeof(int_freq);
368d76231e4SMauro Carvalho Chehab 			if (endp - p < sizeof(size))
369d76231e4SMauro Carvalho Chehab 				goto header;
370d76231e4SMauro Carvalho Chehab 		}
371d76231e4SMauro Carvalho Chehab 
372d76231e4SMauro Carvalho Chehab 		size = get_unaligned_le32(p);
373d76231e4SMauro Carvalho Chehab 		p += sizeof(size);
374d76231e4SMauro Carvalho Chehab 
375d76231e4SMauro Carvalho Chehab 		if (!size || size > endp - p) {
376d76231e4SMauro Carvalho Chehab 			tuner_err("Firmware type ");
377d76231e4SMauro Carvalho Chehab 			dump_firm_type(type);
378d76231e4SMauro Carvalho Chehab 			printk(KERN_CONT
379d76231e4SMauro Carvalho Chehab 			       "(%x), id %llx is corrupted (size=%zd, expected %d)\n",
380d76231e4SMauro Carvalho Chehab 			       type, (unsigned long long)id, (endp - p), size);
381d76231e4SMauro Carvalho Chehab 			goto corrupt;
382d76231e4SMauro Carvalho Chehab 		}
383d76231e4SMauro Carvalho Chehab 
384d76231e4SMauro Carvalho Chehab 		priv->firm[n].ptr = kmemdup(p, size, GFP_KERNEL);
385d76231e4SMauro Carvalho Chehab 		if (priv->firm[n].ptr == NULL) {
386d76231e4SMauro Carvalho Chehab 			tuner_err("Not enough memory to load firmware file.\n");
387d76231e4SMauro Carvalho Chehab 			rc = -ENOMEM;
388d76231e4SMauro Carvalho Chehab 			goto err;
389d76231e4SMauro Carvalho Chehab 		}
390d76231e4SMauro Carvalho Chehab 		tuner_dbg("Reading firmware type ");
391d76231e4SMauro Carvalho Chehab 		if (debug) {
392d76231e4SMauro Carvalho Chehab 			dump_firm_type_and_int_freq(type, int_freq);
393d76231e4SMauro Carvalho Chehab 			printk(KERN_CONT "(%x), id %llx, size=%d.\n",
394d76231e4SMauro Carvalho Chehab 			       type, (unsigned long long)id, size);
395d76231e4SMauro Carvalho Chehab 		}
396d76231e4SMauro Carvalho Chehab 
397d76231e4SMauro Carvalho Chehab 		priv->firm[n].type = type;
398d76231e4SMauro Carvalho Chehab 		priv->firm[n].id   = id;
399d76231e4SMauro Carvalho Chehab 		priv->firm[n].size = size;
400d76231e4SMauro Carvalho Chehab 		priv->firm[n].int_freq = int_freq;
401d76231e4SMauro Carvalho Chehab 
402d76231e4SMauro Carvalho Chehab 		p += size;
403d76231e4SMauro Carvalho Chehab 	}
404d76231e4SMauro Carvalho Chehab 
405d76231e4SMauro Carvalho Chehab 	if (n + 1 != priv->firm_size) {
406d76231e4SMauro Carvalho Chehab 		tuner_err("Firmware file is incomplete!\n");
407d76231e4SMauro Carvalho Chehab 		goto corrupt;
408d76231e4SMauro Carvalho Chehab 	}
409d76231e4SMauro Carvalho Chehab 
410d76231e4SMauro Carvalho Chehab 	goto done;
411d76231e4SMauro Carvalho Chehab 
412d76231e4SMauro Carvalho Chehab header:
413d76231e4SMauro Carvalho Chehab 	tuner_err("Firmware header is incomplete!\n");
414d76231e4SMauro Carvalho Chehab corrupt:
415d76231e4SMauro Carvalho Chehab 	rc = -EINVAL;
416d76231e4SMauro Carvalho Chehab 	tuner_err("Error: firmware file is corrupted!\n");
417d76231e4SMauro Carvalho Chehab 
418d76231e4SMauro Carvalho Chehab err:
419d76231e4SMauro Carvalho Chehab 	tuner_info("Releasing partially loaded firmware file.\n");
420d76231e4SMauro Carvalho Chehab 	free_firmware(priv);
421d76231e4SMauro Carvalho Chehab 
422d76231e4SMauro Carvalho Chehab done:
423d76231e4SMauro Carvalho Chehab 	if (rc == 0)
424d76231e4SMauro Carvalho Chehab 		tuner_dbg("Firmware files loaded.\n");
425d76231e4SMauro Carvalho Chehab 	else
426d76231e4SMauro Carvalho Chehab 		priv->state = XC2028_NODEV;
427d76231e4SMauro Carvalho Chehab 
428d76231e4SMauro Carvalho Chehab 	return rc;
429d76231e4SMauro Carvalho Chehab }
430d76231e4SMauro Carvalho Chehab 
seek_firmware(struct dvb_frontend * fe,unsigned int type,v4l2_std_id * id)431d76231e4SMauro Carvalho Chehab static int seek_firmware(struct dvb_frontend *fe, unsigned int type,
432d76231e4SMauro Carvalho Chehab 			 v4l2_std_id *id)
433d76231e4SMauro Carvalho Chehab {
434d76231e4SMauro Carvalho Chehab 	struct xc2028_data *priv = fe->tuner_priv;
435d76231e4SMauro Carvalho Chehab 	int                 i, best_i = -1, best_nr_matches = 0;
436d76231e4SMauro Carvalho Chehab 	unsigned int        type_mask = 0;
437d76231e4SMauro Carvalho Chehab 
438d76231e4SMauro Carvalho Chehab 	tuner_dbg("%s called, want type=", __func__);
439d76231e4SMauro Carvalho Chehab 	if (debug) {
440d76231e4SMauro Carvalho Chehab 		dump_firm_type(type);
441d76231e4SMauro Carvalho Chehab 		printk(KERN_CONT "(%x), id %016llx.\n",
442d76231e4SMauro Carvalho Chehab 		       type, (unsigned long long)*id);
443d76231e4SMauro Carvalho Chehab 	}
444d76231e4SMauro Carvalho Chehab 
445d76231e4SMauro Carvalho Chehab 	if (!priv->firm) {
446d76231e4SMauro Carvalho Chehab 		tuner_err("Error! firmware not loaded\n");
447d76231e4SMauro Carvalho Chehab 		return -EINVAL;
448d76231e4SMauro Carvalho Chehab 	}
449d76231e4SMauro Carvalho Chehab 
450d76231e4SMauro Carvalho Chehab 	if (((type & ~SCODE) == 0) && (*id == 0))
451d76231e4SMauro Carvalho Chehab 		*id = V4L2_STD_PAL;
452d76231e4SMauro Carvalho Chehab 
453d76231e4SMauro Carvalho Chehab 	if (type & BASE)
454d76231e4SMauro Carvalho Chehab 		type_mask = BASE_TYPES;
455d76231e4SMauro Carvalho Chehab 	else if (type & SCODE) {
456d76231e4SMauro Carvalho Chehab 		type &= SCODE_TYPES;
457d76231e4SMauro Carvalho Chehab 		type_mask = SCODE_TYPES & ~HAS_IF;
458d76231e4SMauro Carvalho Chehab 	} else if (type & DTV_TYPES)
459d76231e4SMauro Carvalho Chehab 		type_mask = DTV_TYPES;
460d76231e4SMauro Carvalho Chehab 	else if (type & STD_SPECIFIC_TYPES)
461d76231e4SMauro Carvalho Chehab 		type_mask = STD_SPECIFIC_TYPES;
462d76231e4SMauro Carvalho Chehab 
463d76231e4SMauro Carvalho Chehab 	type &= type_mask;
464d76231e4SMauro Carvalho Chehab 
465d76231e4SMauro Carvalho Chehab 	if (!(type & SCODE))
466d76231e4SMauro Carvalho Chehab 		type_mask = ~0;
467d76231e4SMauro Carvalho Chehab 
468d76231e4SMauro Carvalho Chehab 	/* Seek for exact match */
469d76231e4SMauro Carvalho Chehab 	for (i = 0; i < priv->firm_size; i++) {
470d76231e4SMauro Carvalho Chehab 		if ((type == (priv->firm[i].type & type_mask)) &&
471d76231e4SMauro Carvalho Chehab 		    (*id == priv->firm[i].id))
472d76231e4SMauro Carvalho Chehab 			goto found;
473d76231e4SMauro Carvalho Chehab 	}
474d76231e4SMauro Carvalho Chehab 
475d76231e4SMauro Carvalho Chehab 	/* Seek for generic video standard match */
476d76231e4SMauro Carvalho Chehab 	for (i = 0; i < priv->firm_size; i++) {
477d76231e4SMauro Carvalho Chehab 		v4l2_std_id match_mask;
478d76231e4SMauro Carvalho Chehab 		int nr_matches;
479d76231e4SMauro Carvalho Chehab 
480d76231e4SMauro Carvalho Chehab 		if (type != (priv->firm[i].type & type_mask))
481d76231e4SMauro Carvalho Chehab 			continue;
482d76231e4SMauro Carvalho Chehab 
483d76231e4SMauro Carvalho Chehab 		match_mask = *id & priv->firm[i].id;
484d76231e4SMauro Carvalho Chehab 		if (!match_mask)
485d76231e4SMauro Carvalho Chehab 			continue;
486d76231e4SMauro Carvalho Chehab 
487d76231e4SMauro Carvalho Chehab 		if ((*id & match_mask) == *id)
488d76231e4SMauro Carvalho Chehab 			goto found; /* Supports all the requested standards */
489d76231e4SMauro Carvalho Chehab 
490d76231e4SMauro Carvalho Chehab 		nr_matches = hweight64(match_mask);
491d76231e4SMauro Carvalho Chehab 		if (nr_matches > best_nr_matches) {
492d76231e4SMauro Carvalho Chehab 			best_nr_matches = nr_matches;
493d76231e4SMauro Carvalho Chehab 			best_i = i;
494d76231e4SMauro Carvalho Chehab 		}
495d76231e4SMauro Carvalho Chehab 	}
496d76231e4SMauro Carvalho Chehab 
497d76231e4SMauro Carvalho Chehab 	if (best_nr_matches > 0) {
498d76231e4SMauro Carvalho Chehab 		tuner_dbg("Selecting best matching firmware (%d bits) for type=",
499d76231e4SMauro Carvalho Chehab 			  best_nr_matches);
500d76231e4SMauro Carvalho Chehab 		dump_firm_type(type);
501d76231e4SMauro Carvalho Chehab 		printk(KERN_CONT
502d76231e4SMauro Carvalho Chehab 		       "(%x), id %016llx:\n", type, (unsigned long long)*id);
503d76231e4SMauro Carvalho Chehab 		i = best_i;
504d76231e4SMauro Carvalho Chehab 		goto found;
505d76231e4SMauro Carvalho Chehab 	}
506d76231e4SMauro Carvalho Chehab 
507d76231e4SMauro Carvalho Chehab 	/*FIXME: Would make sense to seek for type "hint" match ? */
508d76231e4SMauro Carvalho Chehab 
509d76231e4SMauro Carvalho Chehab 	i = -ENOENT;
510d76231e4SMauro Carvalho Chehab 	goto ret;
511d76231e4SMauro Carvalho Chehab 
512d76231e4SMauro Carvalho Chehab found:
513d76231e4SMauro Carvalho Chehab 	*id = priv->firm[i].id;
514d76231e4SMauro Carvalho Chehab 
515d76231e4SMauro Carvalho Chehab ret:
516d76231e4SMauro Carvalho Chehab 	tuner_dbg("%s firmware for type=", (i < 0) ? "Can't find" : "Found");
517d76231e4SMauro Carvalho Chehab 	if (debug) {
518d76231e4SMauro Carvalho Chehab 		dump_firm_type(type);
519d76231e4SMauro Carvalho Chehab 		printk(KERN_CONT "(%x), id %016llx.\n",
520d76231e4SMauro Carvalho Chehab 		       type, (unsigned long long)*id);
521d76231e4SMauro Carvalho Chehab 	}
522d76231e4SMauro Carvalho Chehab 	return i;
523d76231e4SMauro Carvalho Chehab }
524d76231e4SMauro Carvalho Chehab 
do_tuner_callback(struct dvb_frontend * fe,int cmd,int arg)525d76231e4SMauro Carvalho Chehab static inline int do_tuner_callback(struct dvb_frontend *fe, int cmd, int arg)
526d76231e4SMauro Carvalho Chehab {
527d76231e4SMauro Carvalho Chehab 	struct xc2028_data *priv = fe->tuner_priv;
528d76231e4SMauro Carvalho Chehab 
529d76231e4SMauro Carvalho Chehab 	/* analog side (tuner-core) uses i2c_adap->algo_data.
530d76231e4SMauro Carvalho Chehab 	 * digital side is not guaranteed to have algo_data defined.
531d76231e4SMauro Carvalho Chehab 	 *
532d76231e4SMauro Carvalho Chehab 	 * digital side will always have fe->dvb defined.
533d76231e4SMauro Carvalho Chehab 	 * analog side (tuner-core) doesn't (yet) define fe->dvb.
534d76231e4SMauro Carvalho Chehab 	 */
535d76231e4SMauro Carvalho Chehab 
536d76231e4SMauro Carvalho Chehab 	return (!fe->callback) ? -EINVAL :
537d76231e4SMauro Carvalho Chehab 		fe->callback(((fe->dvb) && (fe->dvb->priv)) ?
538d76231e4SMauro Carvalho Chehab 				fe->dvb->priv : priv->i2c_props.adap->algo_data,
539d76231e4SMauro Carvalho Chehab 			     DVB_FRONTEND_COMPONENT_TUNER, cmd, arg);
540d76231e4SMauro Carvalho Chehab }
541d76231e4SMauro Carvalho Chehab 
load_firmware(struct dvb_frontend * fe,unsigned int type,v4l2_std_id * id)542d76231e4SMauro Carvalho Chehab static int load_firmware(struct dvb_frontend *fe, unsigned int type,
543d76231e4SMauro Carvalho Chehab 			 v4l2_std_id *id)
544d76231e4SMauro Carvalho Chehab {
545d76231e4SMauro Carvalho Chehab 	struct xc2028_data *priv = fe->tuner_priv;
546d76231e4SMauro Carvalho Chehab 	int                pos, rc;
547d76231e4SMauro Carvalho Chehab 	unsigned char      *p, *endp, buf[MAX_XFER_SIZE];
548d76231e4SMauro Carvalho Chehab 
549d76231e4SMauro Carvalho Chehab 	if (priv->ctrl.max_len > sizeof(buf))
550d76231e4SMauro Carvalho Chehab 		priv->ctrl.max_len = sizeof(buf);
551d76231e4SMauro Carvalho Chehab 
552d76231e4SMauro Carvalho Chehab 	tuner_dbg("%s called\n", __func__);
553d76231e4SMauro Carvalho Chehab 
554d76231e4SMauro Carvalho Chehab 	pos = seek_firmware(fe, type, id);
555d76231e4SMauro Carvalho Chehab 	if (pos < 0)
556d76231e4SMauro Carvalho Chehab 		return pos;
557d76231e4SMauro Carvalho Chehab 
558d76231e4SMauro Carvalho Chehab 	tuner_info("Loading firmware for type=");
559d76231e4SMauro Carvalho Chehab 	dump_firm_type(priv->firm[pos].type);
560d76231e4SMauro Carvalho Chehab 	printk(KERN_CONT "(%x), id %016llx.\n",
561d76231e4SMauro Carvalho Chehab 	       priv->firm[pos].type, (unsigned long long)*id);
562d76231e4SMauro Carvalho Chehab 
563d76231e4SMauro Carvalho Chehab 	p = priv->firm[pos].ptr;
564d76231e4SMauro Carvalho Chehab 	endp = p + priv->firm[pos].size;
565d76231e4SMauro Carvalho Chehab 
566d76231e4SMauro Carvalho Chehab 	while (p < endp) {
567d76231e4SMauro Carvalho Chehab 		__u16 size;
568d76231e4SMauro Carvalho Chehab 
569d76231e4SMauro Carvalho Chehab 		/* Checks if there's enough bytes to read */
570d76231e4SMauro Carvalho Chehab 		if (p + sizeof(size) > endp) {
571d76231e4SMauro Carvalho Chehab 			tuner_err("Firmware chunk size is wrong\n");
572d76231e4SMauro Carvalho Chehab 			return -EINVAL;
573d76231e4SMauro Carvalho Chehab 		}
574d76231e4SMauro Carvalho Chehab 
575d76231e4SMauro Carvalho Chehab 		size = le16_to_cpu(*(__le16 *) p);
576d76231e4SMauro Carvalho Chehab 		p += sizeof(size);
577d76231e4SMauro Carvalho Chehab 
578d76231e4SMauro Carvalho Chehab 		if (size == 0xffff)
579d76231e4SMauro Carvalho Chehab 			return 0;
580d76231e4SMauro Carvalho Chehab 
581d76231e4SMauro Carvalho Chehab 		if (!size) {
582d76231e4SMauro Carvalho Chehab 			/* Special callback command received */
583d76231e4SMauro Carvalho Chehab 			rc = do_tuner_callback(fe, XC2028_TUNER_RESET, 0);
584d76231e4SMauro Carvalho Chehab 			if (rc < 0) {
585d76231e4SMauro Carvalho Chehab 				tuner_err("Error at RESET code %d\n",
586d76231e4SMauro Carvalho Chehab 					   (*p) & 0x7f);
587d76231e4SMauro Carvalho Chehab 				return -EINVAL;
588d76231e4SMauro Carvalho Chehab 			}
589d76231e4SMauro Carvalho Chehab 			continue;
590d76231e4SMauro Carvalho Chehab 		}
591d76231e4SMauro Carvalho Chehab 		if (size >= 0xff00) {
592d76231e4SMauro Carvalho Chehab 			switch (size) {
593d76231e4SMauro Carvalho Chehab 			case 0xff00:
594d76231e4SMauro Carvalho Chehab 				rc = do_tuner_callback(fe, XC2028_RESET_CLK, 0);
595d76231e4SMauro Carvalho Chehab 				if (rc < 0) {
596d76231e4SMauro Carvalho Chehab 					tuner_err("Error at RESET code %d\n",
597d76231e4SMauro Carvalho Chehab 						  (*p) & 0x7f);
598d76231e4SMauro Carvalho Chehab 					return -EINVAL;
599d76231e4SMauro Carvalho Chehab 				}
600d76231e4SMauro Carvalho Chehab 				break;
601d76231e4SMauro Carvalho Chehab 			default:
602d76231e4SMauro Carvalho Chehab 				tuner_info("Invalid RESET code %d\n",
603d76231e4SMauro Carvalho Chehab 					   size & 0x7f);
604d76231e4SMauro Carvalho Chehab 				return -EINVAL;
605d76231e4SMauro Carvalho Chehab 
606d76231e4SMauro Carvalho Chehab 			}
607d76231e4SMauro Carvalho Chehab 			continue;
608d76231e4SMauro Carvalho Chehab 		}
609d76231e4SMauro Carvalho Chehab 
610d76231e4SMauro Carvalho Chehab 		/* Checks for a sleep command */
611d76231e4SMauro Carvalho Chehab 		if (size & 0x8000) {
612d76231e4SMauro Carvalho Chehab 			msleep(size & 0x7fff);
613d76231e4SMauro Carvalho Chehab 			continue;
614d76231e4SMauro Carvalho Chehab 		}
615d76231e4SMauro Carvalho Chehab 
616d76231e4SMauro Carvalho Chehab 		if ((size + p > endp)) {
617d76231e4SMauro Carvalho Chehab 			tuner_err("missing bytes: need %d, have %zd\n",
618d76231e4SMauro Carvalho Chehab 				   size, (endp - p));
619d76231e4SMauro Carvalho Chehab 			return -EINVAL;
620d76231e4SMauro Carvalho Chehab 		}
621d76231e4SMauro Carvalho Chehab 
622d76231e4SMauro Carvalho Chehab 		buf[0] = *p;
623d76231e4SMauro Carvalho Chehab 		p++;
624d76231e4SMauro Carvalho Chehab 		size--;
625d76231e4SMauro Carvalho Chehab 
626d76231e4SMauro Carvalho Chehab 		/* Sends message chunks */
627d76231e4SMauro Carvalho Chehab 		while (size > 0) {
628d76231e4SMauro Carvalho Chehab 			int len = (size < priv->ctrl.max_len - 1) ?
629d76231e4SMauro Carvalho Chehab 				   size : priv->ctrl.max_len - 1;
630d76231e4SMauro Carvalho Chehab 
631d76231e4SMauro Carvalho Chehab 			memcpy(buf + 1, p, len);
632d76231e4SMauro Carvalho Chehab 
633d76231e4SMauro Carvalho Chehab 			rc = i2c_send(priv, buf, len + 1);
634d76231e4SMauro Carvalho Chehab 			if (rc < 0) {
635d76231e4SMauro Carvalho Chehab 				tuner_err("%d returned from send\n", rc);
636d76231e4SMauro Carvalho Chehab 				return -EINVAL;
637d76231e4SMauro Carvalho Chehab 			}
638d76231e4SMauro Carvalho Chehab 
639d76231e4SMauro Carvalho Chehab 			p += len;
640d76231e4SMauro Carvalho Chehab 			size -= len;
641d76231e4SMauro Carvalho Chehab 		}
642d76231e4SMauro Carvalho Chehab 
643d76231e4SMauro Carvalho Chehab 		/* silently fail if the frontend doesn't support I2C flush */
644d76231e4SMauro Carvalho Chehab 		rc = do_tuner_callback(fe, XC2028_I2C_FLUSH, 0);
645d76231e4SMauro Carvalho Chehab 		if ((rc < 0) && (rc != -EINVAL)) {
646d76231e4SMauro Carvalho Chehab 			tuner_err("error executing flush: %d\n", rc);
647d76231e4SMauro Carvalho Chehab 			return rc;
648d76231e4SMauro Carvalho Chehab 		}
649d76231e4SMauro Carvalho Chehab 	}
650d76231e4SMauro Carvalho Chehab 	return 0;
651d76231e4SMauro Carvalho Chehab }
652d76231e4SMauro Carvalho Chehab 
load_scode(struct dvb_frontend * fe,unsigned int type,v4l2_std_id * id,__u16 int_freq,int scode)653d76231e4SMauro Carvalho Chehab static int load_scode(struct dvb_frontend *fe, unsigned int type,
654d76231e4SMauro Carvalho Chehab 			 v4l2_std_id *id, __u16 int_freq, int scode)
655d76231e4SMauro Carvalho Chehab {
656d76231e4SMauro Carvalho Chehab 	struct xc2028_data *priv = fe->tuner_priv;
657d76231e4SMauro Carvalho Chehab 	int                pos, rc;
658d76231e4SMauro Carvalho Chehab 	unsigned char	   *p;
659d76231e4SMauro Carvalho Chehab 
660d76231e4SMauro Carvalho Chehab 	tuner_dbg("%s called\n", __func__);
661d76231e4SMauro Carvalho Chehab 
662d76231e4SMauro Carvalho Chehab 	if (!int_freq) {
663d76231e4SMauro Carvalho Chehab 		pos = seek_firmware(fe, type, id);
664d76231e4SMauro Carvalho Chehab 		if (pos < 0)
665d76231e4SMauro Carvalho Chehab 			return pos;
666d76231e4SMauro Carvalho Chehab 	} else {
667d76231e4SMauro Carvalho Chehab 		for (pos = 0; pos < priv->firm_size; pos++) {
668d76231e4SMauro Carvalho Chehab 			if ((priv->firm[pos].int_freq == int_freq) &&
669d76231e4SMauro Carvalho Chehab 			    (priv->firm[pos].type & HAS_IF))
670d76231e4SMauro Carvalho Chehab 				break;
671d76231e4SMauro Carvalho Chehab 		}
672d76231e4SMauro Carvalho Chehab 		if (pos == priv->firm_size)
673d76231e4SMauro Carvalho Chehab 			return -ENOENT;
674d76231e4SMauro Carvalho Chehab 	}
675d76231e4SMauro Carvalho Chehab 
676d76231e4SMauro Carvalho Chehab 	p = priv->firm[pos].ptr;
677d76231e4SMauro Carvalho Chehab 
678d76231e4SMauro Carvalho Chehab 	if (priv->firm[pos].type & HAS_IF) {
679d76231e4SMauro Carvalho Chehab 		if (priv->firm[pos].size != 12 * 16 || scode >= 16)
680d76231e4SMauro Carvalho Chehab 			return -EINVAL;
681d76231e4SMauro Carvalho Chehab 		p += 12 * scode;
682d76231e4SMauro Carvalho Chehab 	} else {
683d76231e4SMauro Carvalho Chehab 		/* 16 SCODE entries per file; each SCODE entry is 12 bytes and
684d76231e4SMauro Carvalho Chehab 		 * has a 2-byte size header in the firmware format. */
685d76231e4SMauro Carvalho Chehab 		if (priv->firm[pos].size != 14 * 16 || scode >= 16 ||
686d76231e4SMauro Carvalho Chehab 		    le16_to_cpu(*(__le16 *)(p + 14 * scode)) != 12)
687d76231e4SMauro Carvalho Chehab 			return -EINVAL;
688d76231e4SMauro Carvalho Chehab 		p += 14 * scode + 2;
689d76231e4SMauro Carvalho Chehab 	}
690d76231e4SMauro Carvalho Chehab 
691d76231e4SMauro Carvalho Chehab 	tuner_info("Loading SCODE for type=");
692d76231e4SMauro Carvalho Chehab 	dump_firm_type_and_int_freq(priv->firm[pos].type,
693d76231e4SMauro Carvalho Chehab 				    priv->firm[pos].int_freq);
694d76231e4SMauro Carvalho Chehab 	printk(KERN_CONT "(%x), id %016llx.\n", priv->firm[pos].type,
695d76231e4SMauro Carvalho Chehab 	       (unsigned long long)*id);
696d76231e4SMauro Carvalho Chehab 
697d76231e4SMauro Carvalho Chehab 	if (priv->firm_version < 0x0202)
698d76231e4SMauro Carvalho Chehab 		rc = send_seq(priv, {0x20, 0x00, 0x00, 0x00});
699d76231e4SMauro Carvalho Chehab 	else
700d76231e4SMauro Carvalho Chehab 		rc = send_seq(priv, {0xa0, 0x00, 0x00, 0x00});
701d76231e4SMauro Carvalho Chehab 	if (rc < 0)
702d76231e4SMauro Carvalho Chehab 		return -EIO;
703d76231e4SMauro Carvalho Chehab 
704d76231e4SMauro Carvalho Chehab 	rc = i2c_send(priv, p, 12);
705d76231e4SMauro Carvalho Chehab 	if (rc < 0)
706d76231e4SMauro Carvalho Chehab 		return -EIO;
707d76231e4SMauro Carvalho Chehab 
708d76231e4SMauro Carvalho Chehab 	rc = send_seq(priv, {0x00, 0x8c});
709d76231e4SMauro Carvalho Chehab 	if (rc < 0)
710d76231e4SMauro Carvalho Chehab 		return -EIO;
711d76231e4SMauro Carvalho Chehab 
712d76231e4SMauro Carvalho Chehab 	return 0;
713d76231e4SMauro Carvalho Chehab }
714d76231e4SMauro Carvalho Chehab 
715d76231e4SMauro Carvalho Chehab static int xc2028_sleep(struct dvb_frontend *fe);
716d76231e4SMauro Carvalho Chehab 
check_firmware(struct dvb_frontend * fe,unsigned int type,v4l2_std_id std,__u16 int_freq)717d76231e4SMauro Carvalho Chehab static int check_firmware(struct dvb_frontend *fe, unsigned int type,
718d76231e4SMauro Carvalho Chehab 			  v4l2_std_id std, __u16 int_freq)
719d76231e4SMauro Carvalho Chehab {
720d76231e4SMauro Carvalho Chehab 	struct xc2028_data         *priv = fe->tuner_priv;
721d76231e4SMauro Carvalho Chehab 	struct firmware_properties new_fw;
722d76231e4SMauro Carvalho Chehab 	int			   rc, retry_count = 0;
723d76231e4SMauro Carvalho Chehab 	u16			   version, hwmodel;
724d76231e4SMauro Carvalho Chehab 	v4l2_std_id		   std0;
725d76231e4SMauro Carvalho Chehab 
726d76231e4SMauro Carvalho Chehab 	tuner_dbg("%s called\n", __func__);
727d76231e4SMauro Carvalho Chehab 
728d76231e4SMauro Carvalho Chehab 	rc = check_device_status(priv);
729d76231e4SMauro Carvalho Chehab 	if (rc < 0)
730d76231e4SMauro Carvalho Chehab 		return rc;
731d76231e4SMauro Carvalho Chehab 
732d76231e4SMauro Carvalho Chehab 	if (priv->ctrl.mts && !(type & FM))
733d76231e4SMauro Carvalho Chehab 		type |= MTS;
734d76231e4SMauro Carvalho Chehab 
735d76231e4SMauro Carvalho Chehab retry:
736d76231e4SMauro Carvalho Chehab 	new_fw.type = type;
737d76231e4SMauro Carvalho Chehab 	new_fw.id = std;
738d76231e4SMauro Carvalho Chehab 	new_fw.std_req = std;
739d76231e4SMauro Carvalho Chehab 	new_fw.scode_table = SCODE | priv->ctrl.scode_table;
740d76231e4SMauro Carvalho Chehab 	new_fw.scode_nr = 0;
741d76231e4SMauro Carvalho Chehab 	new_fw.int_freq = int_freq;
742d76231e4SMauro Carvalho Chehab 
743d76231e4SMauro Carvalho Chehab 	tuner_dbg("checking firmware, user requested type=");
744d76231e4SMauro Carvalho Chehab 	if (debug) {
745d76231e4SMauro Carvalho Chehab 		dump_firm_type(new_fw.type);
746d76231e4SMauro Carvalho Chehab 		printk(KERN_CONT "(%x), id %016llx, ", new_fw.type,
747d76231e4SMauro Carvalho Chehab 		       (unsigned long long)new_fw.std_req);
748d76231e4SMauro Carvalho Chehab 		if (!int_freq) {
749d76231e4SMauro Carvalho Chehab 			printk(KERN_CONT "scode_tbl ");
750d76231e4SMauro Carvalho Chehab 			dump_firm_type(priv->ctrl.scode_table);
751d76231e4SMauro Carvalho Chehab 			printk(KERN_CONT "(%x), ", priv->ctrl.scode_table);
752d76231e4SMauro Carvalho Chehab 		} else
753d76231e4SMauro Carvalho Chehab 			printk(KERN_CONT "int_freq %d, ", new_fw.int_freq);
754d76231e4SMauro Carvalho Chehab 		printk(KERN_CONT "scode_nr %d\n", new_fw.scode_nr);
755d76231e4SMauro Carvalho Chehab 	}
756d76231e4SMauro Carvalho Chehab 
757d76231e4SMauro Carvalho Chehab 	/*
758d76231e4SMauro Carvalho Chehab 	 * No need to reload base firmware if it matches and if the tuner
759d76231e4SMauro Carvalho Chehab 	 * is not at sleep mode
760d76231e4SMauro Carvalho Chehab 	 */
761d76231e4SMauro Carvalho Chehab 	if ((priv->state == XC2028_ACTIVE) &&
762d76231e4SMauro Carvalho Chehab 	    (((BASE | new_fw.type) & BASE_TYPES) ==
763d76231e4SMauro Carvalho Chehab 	    (priv->cur_fw.type & BASE_TYPES))) {
764d76231e4SMauro Carvalho Chehab 		tuner_dbg("BASE firmware not changed.\n");
765d76231e4SMauro Carvalho Chehab 		goto skip_base;
766d76231e4SMauro Carvalho Chehab 	}
767d76231e4SMauro Carvalho Chehab 
768d76231e4SMauro Carvalho Chehab 	/* Updating BASE - forget about all currently loaded firmware */
769d76231e4SMauro Carvalho Chehab 	memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
770d76231e4SMauro Carvalho Chehab 
771d76231e4SMauro Carvalho Chehab 	/* Reset is needed before loading firmware */
772d76231e4SMauro Carvalho Chehab 	rc = do_tuner_callback(fe, XC2028_TUNER_RESET, 0);
773d76231e4SMauro Carvalho Chehab 	if (rc < 0)
774d76231e4SMauro Carvalho Chehab 		goto fail;
775d76231e4SMauro Carvalho Chehab 
776d76231e4SMauro Carvalho Chehab 	/* BASE firmwares are all std0 */
777d76231e4SMauro Carvalho Chehab 	std0 = 0;
778d76231e4SMauro Carvalho Chehab 	rc = load_firmware(fe, BASE | new_fw.type, &std0);
779d76231e4SMauro Carvalho Chehab 	if (rc < 0) {
780d76231e4SMauro Carvalho Chehab 		tuner_err("Error %d while loading base firmware\n",
781d76231e4SMauro Carvalho Chehab 			  rc);
782d76231e4SMauro Carvalho Chehab 		goto fail;
783d76231e4SMauro Carvalho Chehab 	}
784d76231e4SMauro Carvalho Chehab 
785d76231e4SMauro Carvalho Chehab 	/* Load INIT1, if needed */
786d76231e4SMauro Carvalho Chehab 	tuner_dbg("Load init1 firmware, if exists\n");
787d76231e4SMauro Carvalho Chehab 
788d76231e4SMauro Carvalho Chehab 	rc = load_firmware(fe, BASE | INIT1 | new_fw.type, &std0);
789d76231e4SMauro Carvalho Chehab 	if (rc == -ENOENT)
790d76231e4SMauro Carvalho Chehab 		rc = load_firmware(fe, (BASE | INIT1 | new_fw.type) & ~F8MHZ,
791d76231e4SMauro Carvalho Chehab 				   &std0);
792d76231e4SMauro Carvalho Chehab 	if (rc < 0 && rc != -ENOENT) {
793d76231e4SMauro Carvalho Chehab 		tuner_err("Error %d while loading init1 firmware\n",
794d76231e4SMauro Carvalho Chehab 			  rc);
795d76231e4SMauro Carvalho Chehab 		goto fail;
796d76231e4SMauro Carvalho Chehab 	}
797d76231e4SMauro Carvalho Chehab 
798d76231e4SMauro Carvalho Chehab skip_base:
799d76231e4SMauro Carvalho Chehab 	/*
800d76231e4SMauro Carvalho Chehab 	 * No need to reload standard specific firmware if base firmware
801d76231e4SMauro Carvalho Chehab 	 * was not reloaded and requested video standards have not changed.
802d76231e4SMauro Carvalho Chehab 	 */
803d76231e4SMauro Carvalho Chehab 	if (priv->cur_fw.type == (BASE | new_fw.type) &&
804d76231e4SMauro Carvalho Chehab 	    priv->cur_fw.std_req == std) {
805d76231e4SMauro Carvalho Chehab 		tuner_dbg("Std-specific firmware already loaded.\n");
806d76231e4SMauro Carvalho Chehab 		goto skip_std_specific;
807d76231e4SMauro Carvalho Chehab 	}
808d76231e4SMauro Carvalho Chehab 
809d76231e4SMauro Carvalho Chehab 	/* Reloading std-specific firmware forces a SCODE update */
810d76231e4SMauro Carvalho Chehab 	priv->cur_fw.scode_table = 0;
811d76231e4SMauro Carvalho Chehab 
812d76231e4SMauro Carvalho Chehab 	rc = load_firmware(fe, new_fw.type, &new_fw.id);
813d76231e4SMauro Carvalho Chehab 	if (rc == -ENOENT)
814d76231e4SMauro Carvalho Chehab 		rc = load_firmware(fe, new_fw.type & ~F8MHZ, &new_fw.id);
815d76231e4SMauro Carvalho Chehab 
816d76231e4SMauro Carvalho Chehab 	if (rc < 0)
817d76231e4SMauro Carvalho Chehab 		goto fail;
818d76231e4SMauro Carvalho Chehab 
819d76231e4SMauro Carvalho Chehab skip_std_specific:
820d76231e4SMauro Carvalho Chehab 	if (priv->cur_fw.scode_table == new_fw.scode_table &&
821d76231e4SMauro Carvalho Chehab 	    priv->cur_fw.scode_nr == new_fw.scode_nr) {
822d76231e4SMauro Carvalho Chehab 		tuner_dbg("SCODE firmware already loaded.\n");
823d76231e4SMauro Carvalho Chehab 		goto check_device;
824d76231e4SMauro Carvalho Chehab 	}
825d76231e4SMauro Carvalho Chehab 
826d76231e4SMauro Carvalho Chehab 	if (new_fw.type & FM)
827d76231e4SMauro Carvalho Chehab 		goto check_device;
828d76231e4SMauro Carvalho Chehab 
829d76231e4SMauro Carvalho Chehab 	/* Load SCODE firmware, if exists */
830d76231e4SMauro Carvalho Chehab 	tuner_dbg("Trying to load scode %d\n", new_fw.scode_nr);
831d76231e4SMauro Carvalho Chehab 
832d76231e4SMauro Carvalho Chehab 	rc = load_scode(fe, new_fw.type | new_fw.scode_table, &new_fw.id,
833d76231e4SMauro Carvalho Chehab 			new_fw.int_freq, new_fw.scode_nr);
834d76231e4SMauro Carvalho Chehab 
835d76231e4SMauro Carvalho Chehab check_device:
836d76231e4SMauro Carvalho Chehab 	if (xc2028_get_reg(priv, 0x0004, &version) < 0 ||
837d76231e4SMauro Carvalho Chehab 	    xc2028_get_reg(priv, 0x0008, &hwmodel) < 0) {
838d76231e4SMauro Carvalho Chehab 		tuner_err("Unable to read tuner registers.\n");
839d76231e4SMauro Carvalho Chehab 		goto fail;
840d76231e4SMauro Carvalho Chehab 	}
841d76231e4SMauro Carvalho Chehab 
842d76231e4SMauro Carvalho Chehab 	tuner_dbg("Device is Xceive %d version %d.%d, firmware version %d.%d\n",
843d76231e4SMauro Carvalho Chehab 		  hwmodel, (version & 0xf000) >> 12, (version & 0xf00) >> 8,
844d76231e4SMauro Carvalho Chehab 		  (version & 0xf0) >> 4, version & 0xf);
845d76231e4SMauro Carvalho Chehab 
846d76231e4SMauro Carvalho Chehab 
847d76231e4SMauro Carvalho Chehab 	if (priv->ctrl.read_not_reliable)
848d76231e4SMauro Carvalho Chehab 		goto read_not_reliable;
849d76231e4SMauro Carvalho Chehab 
850d76231e4SMauro Carvalho Chehab 	/* Check firmware version against what we downloaded. */
851d76231e4SMauro Carvalho Chehab 	if (priv->firm_version != ((version & 0xf0) << 4 | (version & 0x0f))) {
852d76231e4SMauro Carvalho Chehab 		if (!priv->ctrl.read_not_reliable) {
853d76231e4SMauro Carvalho Chehab 			tuner_err("Incorrect readback of firmware version.\n");
854d76231e4SMauro Carvalho Chehab 			goto fail;
855d76231e4SMauro Carvalho Chehab 		} else {
856d76231e4SMauro Carvalho Chehab 			tuner_err("Returned an incorrect version. However, read is not reliable enough. Ignoring it.\n");
857d76231e4SMauro Carvalho Chehab 			hwmodel = 3028;
858d76231e4SMauro Carvalho Chehab 		}
859d76231e4SMauro Carvalho Chehab 	}
860d76231e4SMauro Carvalho Chehab 
861d76231e4SMauro Carvalho Chehab 	/* Check that the tuner hardware model remains consistent over time. */
862d76231e4SMauro Carvalho Chehab 	if (priv->hwmodel == 0 && (hwmodel == 2028 || hwmodel == 3028)) {
863d76231e4SMauro Carvalho Chehab 		priv->hwmodel = hwmodel;
864d76231e4SMauro Carvalho Chehab 		priv->hwvers  = version & 0xff00;
865d76231e4SMauro Carvalho Chehab 	} else if (priv->hwmodel == 0 || priv->hwmodel != hwmodel ||
866d76231e4SMauro Carvalho Chehab 		   priv->hwvers != (version & 0xff00)) {
867d76231e4SMauro Carvalho Chehab 		tuner_err("Read invalid device hardware information - tuner hung?\n");
868d76231e4SMauro Carvalho Chehab 		goto fail;
869d76231e4SMauro Carvalho Chehab 	}
870d76231e4SMauro Carvalho Chehab 
871d76231e4SMauro Carvalho Chehab read_not_reliable:
872d76231e4SMauro Carvalho Chehab 	priv->cur_fw = new_fw;
873d76231e4SMauro Carvalho Chehab 
874d76231e4SMauro Carvalho Chehab 	/*
875d76231e4SMauro Carvalho Chehab 	 * By setting BASE in cur_fw.type only after successfully loading all
876d76231e4SMauro Carvalho Chehab 	 * firmwares, we can:
877d76231e4SMauro Carvalho Chehab 	 * 1. Identify that BASE firmware with type=0 has been loaded;
878d76231e4SMauro Carvalho Chehab 	 * 2. Tell whether BASE firmware was just changed the next time through.
879d76231e4SMauro Carvalho Chehab 	 */
880d76231e4SMauro Carvalho Chehab 	priv->cur_fw.type |= BASE;
881d76231e4SMauro Carvalho Chehab 	priv->state = XC2028_ACTIVE;
882d76231e4SMauro Carvalho Chehab 
883d76231e4SMauro Carvalho Chehab 	return 0;
884d76231e4SMauro Carvalho Chehab 
885d76231e4SMauro Carvalho Chehab fail:
886d76231e4SMauro Carvalho Chehab 	free_firmware(priv);
887d76231e4SMauro Carvalho Chehab 
888d76231e4SMauro Carvalho Chehab 	if (retry_count < 8) {
889d76231e4SMauro Carvalho Chehab 		msleep(50);
890d76231e4SMauro Carvalho Chehab 		retry_count++;
891d76231e4SMauro Carvalho Chehab 		tuner_dbg("Retrying firmware load\n");
892d76231e4SMauro Carvalho Chehab 		goto retry;
893d76231e4SMauro Carvalho Chehab 	}
894d76231e4SMauro Carvalho Chehab 
895d76231e4SMauro Carvalho Chehab 	/* Firmware didn't load. Put the device to sleep */
896d76231e4SMauro Carvalho Chehab 	xc2028_sleep(fe);
897d76231e4SMauro Carvalho Chehab 
898d76231e4SMauro Carvalho Chehab 	if (rc == -ENOENT)
899d76231e4SMauro Carvalho Chehab 		rc = -EINVAL;
900d76231e4SMauro Carvalho Chehab 	return rc;
901d76231e4SMauro Carvalho Chehab }
902d76231e4SMauro Carvalho Chehab 
xc2028_signal(struct dvb_frontend * fe,u16 * strength)903d76231e4SMauro Carvalho Chehab static int xc2028_signal(struct dvb_frontend *fe, u16 *strength)
904d76231e4SMauro Carvalho Chehab {
905d76231e4SMauro Carvalho Chehab 	struct xc2028_data *priv = fe->tuner_priv;
906d76231e4SMauro Carvalho Chehab 	u16                 frq_lock, signal = 0;
907d76231e4SMauro Carvalho Chehab 	int                 rc, i;
908d76231e4SMauro Carvalho Chehab 
909d76231e4SMauro Carvalho Chehab 	tuner_dbg("%s called\n", __func__);
910d76231e4SMauro Carvalho Chehab 
911d76231e4SMauro Carvalho Chehab 	rc = check_device_status(priv);
912d76231e4SMauro Carvalho Chehab 	if (rc < 0)
913d76231e4SMauro Carvalho Chehab 		return rc;
914d76231e4SMauro Carvalho Chehab 
915d76231e4SMauro Carvalho Chehab 	/* If the device is sleeping, no channel is tuned */
916d76231e4SMauro Carvalho Chehab 	if (!rc) {
917d76231e4SMauro Carvalho Chehab 		*strength = 0;
918d76231e4SMauro Carvalho Chehab 		return 0;
919d76231e4SMauro Carvalho Chehab 	}
920d76231e4SMauro Carvalho Chehab 
921d76231e4SMauro Carvalho Chehab 	mutex_lock(&priv->lock);
922d76231e4SMauro Carvalho Chehab 
923d76231e4SMauro Carvalho Chehab 	/* Sync Lock Indicator */
924d76231e4SMauro Carvalho Chehab 	for (i = 0; i < 3; i++) {
925d76231e4SMauro Carvalho Chehab 		rc = xc2028_get_reg(priv, XREG_LOCK, &frq_lock);
926d76231e4SMauro Carvalho Chehab 		if (rc < 0)
927d76231e4SMauro Carvalho Chehab 			goto ret;
928d76231e4SMauro Carvalho Chehab 
929d76231e4SMauro Carvalho Chehab 		if (frq_lock)
930d76231e4SMauro Carvalho Chehab 			break;
931d76231e4SMauro Carvalho Chehab 		msleep(6);
932d76231e4SMauro Carvalho Chehab 	}
933d76231e4SMauro Carvalho Chehab 
934d76231e4SMauro Carvalho Chehab 	/* Frequency didn't lock */
935d76231e4SMauro Carvalho Chehab 	if (frq_lock == 2)
936d76231e4SMauro Carvalho Chehab 		goto ret;
937d76231e4SMauro Carvalho Chehab 
938d76231e4SMauro Carvalho Chehab 	/* Get SNR of the video signal */
939d76231e4SMauro Carvalho Chehab 	rc = xc2028_get_reg(priv, XREG_SNR, &signal);
940d76231e4SMauro Carvalho Chehab 	if (rc < 0)
941d76231e4SMauro Carvalho Chehab 		goto ret;
942d76231e4SMauro Carvalho Chehab 
943d76231e4SMauro Carvalho Chehab 	/* Signal level is 3 bits only */
944d76231e4SMauro Carvalho Chehab 
945d76231e4SMauro Carvalho Chehab 	signal = ((1 << 12) - 1) | ((signal & 0x07) << 12);
946d76231e4SMauro Carvalho Chehab 
947d76231e4SMauro Carvalho Chehab ret:
948d76231e4SMauro Carvalho Chehab 	mutex_unlock(&priv->lock);
949d76231e4SMauro Carvalho Chehab 
950d76231e4SMauro Carvalho Chehab 	*strength = signal;
951d76231e4SMauro Carvalho Chehab 
952d76231e4SMauro Carvalho Chehab 	tuner_dbg("signal strength is %d\n", signal);
953d76231e4SMauro Carvalho Chehab 
954d76231e4SMauro Carvalho Chehab 	return rc;
955d76231e4SMauro Carvalho Chehab }
956d76231e4SMauro Carvalho Chehab 
xc2028_get_afc(struct dvb_frontend * fe,s32 * afc)957d76231e4SMauro Carvalho Chehab static int xc2028_get_afc(struct dvb_frontend *fe, s32 *afc)
958d76231e4SMauro Carvalho Chehab {
959d76231e4SMauro Carvalho Chehab 	struct xc2028_data *priv = fe->tuner_priv;
960d76231e4SMauro Carvalho Chehab 	int i, rc;
961d76231e4SMauro Carvalho Chehab 	u16 frq_lock = 0;
962d76231e4SMauro Carvalho Chehab 	s16 afc_reg = 0;
963d76231e4SMauro Carvalho Chehab 
964d76231e4SMauro Carvalho Chehab 	rc = check_device_status(priv);
965d76231e4SMauro Carvalho Chehab 	if (rc < 0)
966d76231e4SMauro Carvalho Chehab 		return rc;
967d76231e4SMauro Carvalho Chehab 
968d76231e4SMauro Carvalho Chehab 	/* If the device is sleeping, no channel is tuned */
969d76231e4SMauro Carvalho Chehab 	if (!rc) {
970d76231e4SMauro Carvalho Chehab 		*afc = 0;
971d76231e4SMauro Carvalho Chehab 		return 0;
972d76231e4SMauro Carvalho Chehab 	}
973d76231e4SMauro Carvalho Chehab 
974d76231e4SMauro Carvalho Chehab 	mutex_lock(&priv->lock);
975d76231e4SMauro Carvalho Chehab 
976d76231e4SMauro Carvalho Chehab 	/* Sync Lock Indicator */
977d76231e4SMauro Carvalho Chehab 	for (i = 0; i < 3; i++) {
978d76231e4SMauro Carvalho Chehab 		rc = xc2028_get_reg(priv, XREG_LOCK, &frq_lock);
979d76231e4SMauro Carvalho Chehab 		if (rc < 0)
980d76231e4SMauro Carvalho Chehab 			goto ret;
981d76231e4SMauro Carvalho Chehab 
982d76231e4SMauro Carvalho Chehab 		if (frq_lock)
983d76231e4SMauro Carvalho Chehab 			break;
984d76231e4SMauro Carvalho Chehab 		msleep(6);
985d76231e4SMauro Carvalho Chehab 	}
986d76231e4SMauro Carvalho Chehab 
987d76231e4SMauro Carvalho Chehab 	/* Frequency didn't lock */
988d76231e4SMauro Carvalho Chehab 	if (frq_lock == 2)
989d76231e4SMauro Carvalho Chehab 		goto ret;
990d76231e4SMauro Carvalho Chehab 
991d76231e4SMauro Carvalho Chehab 	/* Get AFC */
992d76231e4SMauro Carvalho Chehab 	rc = xc2028_get_reg(priv, XREG_FREQ_ERROR, &afc_reg);
993d76231e4SMauro Carvalho Chehab 	if (rc < 0)
994d76231e4SMauro Carvalho Chehab 		goto ret;
995d76231e4SMauro Carvalho Chehab 
996d76231e4SMauro Carvalho Chehab 	*afc = afc_reg * 15625; /* Hz */
997d76231e4SMauro Carvalho Chehab 
998d76231e4SMauro Carvalho Chehab 	tuner_dbg("AFC is %d Hz\n", *afc);
999d76231e4SMauro Carvalho Chehab 
1000d76231e4SMauro Carvalho Chehab ret:
1001d76231e4SMauro Carvalho Chehab 	mutex_unlock(&priv->lock);
1002d76231e4SMauro Carvalho Chehab 
1003d76231e4SMauro Carvalho Chehab 	return rc;
1004d76231e4SMauro Carvalho Chehab }
1005d76231e4SMauro Carvalho Chehab 
1006d76231e4SMauro Carvalho Chehab #define DIV 15625
1007d76231e4SMauro Carvalho Chehab 
generic_set_freq(struct dvb_frontend * fe,u32 freq,enum v4l2_tuner_type new_type,unsigned int type,v4l2_std_id std,u16 int_freq)1008d76231e4SMauro Carvalho Chehab static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
1009d76231e4SMauro Carvalho Chehab 			    enum v4l2_tuner_type new_type,
1010d76231e4SMauro Carvalho Chehab 			    unsigned int type,
1011d76231e4SMauro Carvalho Chehab 			    v4l2_std_id std,
1012d76231e4SMauro Carvalho Chehab 			    u16 int_freq)
1013d76231e4SMauro Carvalho Chehab {
1014d76231e4SMauro Carvalho Chehab 	struct xc2028_data *priv = fe->tuner_priv;
1015d76231e4SMauro Carvalho Chehab 	int		   rc = -EINVAL;
1016d76231e4SMauro Carvalho Chehab 	unsigned char	   buf[4];
1017d76231e4SMauro Carvalho Chehab 	u32		   div, offset = 0;
1018d76231e4SMauro Carvalho Chehab 
1019d76231e4SMauro Carvalho Chehab 	tuner_dbg("%s called\n", __func__);
1020d76231e4SMauro Carvalho Chehab 
1021d76231e4SMauro Carvalho Chehab 	mutex_lock(&priv->lock);
1022d76231e4SMauro Carvalho Chehab 
1023d76231e4SMauro Carvalho Chehab 	tuner_dbg("should set frequency %d kHz\n", freq / 1000);
1024d76231e4SMauro Carvalho Chehab 
1025d76231e4SMauro Carvalho Chehab 	if (check_firmware(fe, type, std, int_freq) < 0)
1026d76231e4SMauro Carvalho Chehab 		goto ret;
1027d76231e4SMauro Carvalho Chehab 
1028d76231e4SMauro Carvalho Chehab 	/* On some cases xc2028 can disable video output, if
1029d76231e4SMauro Carvalho Chehab 	 * very weak signals are received. By sending a soft
1030d76231e4SMauro Carvalho Chehab 	 * reset, this is re-enabled. So, it is better to always
1031d76231e4SMauro Carvalho Chehab 	 * send a soft reset before changing channels, to be sure
1032d76231e4SMauro Carvalho Chehab 	 * that xc2028 will be in a safe state.
1033d76231e4SMauro Carvalho Chehab 	 * Maybe this might also be needed for DTV.
1034d76231e4SMauro Carvalho Chehab 	 */
1035d76231e4SMauro Carvalho Chehab 	switch (new_type) {
1036d76231e4SMauro Carvalho Chehab 	case V4L2_TUNER_ANALOG_TV:
1037d76231e4SMauro Carvalho Chehab 		rc = send_seq(priv, {0x00, 0x00});
1038d76231e4SMauro Carvalho Chehab 
1039d76231e4SMauro Carvalho Chehab 		/* Analog mode requires offset = 0 */
1040d76231e4SMauro Carvalho Chehab 		break;
1041d76231e4SMauro Carvalho Chehab 	case V4L2_TUNER_RADIO:
1042d76231e4SMauro Carvalho Chehab 		/* Radio mode requires offset = 0 */
1043d76231e4SMauro Carvalho Chehab 		break;
1044d76231e4SMauro Carvalho Chehab 	case V4L2_TUNER_DIGITAL_TV:
1045d76231e4SMauro Carvalho Chehab 		/*
1046d76231e4SMauro Carvalho Chehab 		 * Digital modes require an offset to adjust to the
1047d76231e4SMauro Carvalho Chehab 		 * proper frequency. The offset depends on what
1048d76231e4SMauro Carvalho Chehab 		 * firmware version is used.
1049d76231e4SMauro Carvalho Chehab 		 */
1050d76231e4SMauro Carvalho Chehab 
1051d76231e4SMauro Carvalho Chehab 		/*
1052d76231e4SMauro Carvalho Chehab 		 * Adjust to the center frequency. This is calculated by the
1053d76231e4SMauro Carvalho Chehab 		 * formula: offset = 1.25MHz - BW/2
1054d76231e4SMauro Carvalho Chehab 		 * For DTV 7/8, the firmware uses BW = 8000, so it needs a
1055d76231e4SMauro Carvalho Chehab 		 * further adjustment to get the frequency center on VHF
1056d76231e4SMauro Carvalho Chehab 		 */
1057d76231e4SMauro Carvalho Chehab 
1058d76231e4SMauro Carvalho Chehab 		/*
1059d76231e4SMauro Carvalho Chehab 		 * The firmware DTV78 used to work fine in UHF band (8 MHz
1060d76231e4SMauro Carvalho Chehab 		 * bandwidth) but not at all in VHF band (7 MHz bandwidth).
1061d76231e4SMauro Carvalho Chehab 		 * The real problem was connected to the formula used to
1062d76231e4SMauro Carvalho Chehab 		 * calculate the center frequency offset in VHF band.
1063d76231e4SMauro Carvalho Chehab 		 * In fact, removing the 500KHz adjustment fixed the problem.
1064d76231e4SMauro Carvalho Chehab 		 * This is coherent to what was implemented for the DTV7
1065d76231e4SMauro Carvalho Chehab 		 * firmware.
1066d76231e4SMauro Carvalho Chehab 		 * In the end, now the center frequency is the same for all 3
1067d76231e4SMauro Carvalho Chehab 		 * firmwares (DTV7, DTV8, DTV78) and doesn't depend on channel
1068d76231e4SMauro Carvalho Chehab 		 * bandwidth.
1069d76231e4SMauro Carvalho Chehab 		 */
1070d76231e4SMauro Carvalho Chehab 
1071d76231e4SMauro Carvalho Chehab 		if (priv->cur_fw.type & DTV6)
1072d76231e4SMauro Carvalho Chehab 			offset = 1750000;
1073d76231e4SMauro Carvalho Chehab 		else	/* DTV7 or DTV8 or DTV78 */
1074d76231e4SMauro Carvalho Chehab 			offset = 2750000;
1075d76231e4SMauro Carvalho Chehab 
1076d76231e4SMauro Carvalho Chehab 		/*
1077d76231e4SMauro Carvalho Chehab 		 * xc3028 additional "magic"
1078d76231e4SMauro Carvalho Chehab 		 * Depending on the firmware version, it needs some adjustments
1079d76231e4SMauro Carvalho Chehab 		 * to properly centralize the frequency. This seems to be
1080d76231e4SMauro Carvalho Chehab 		 * needed to compensate the SCODE table adjustments made by
1081d76231e4SMauro Carvalho Chehab 		 * newer firmwares
1082d76231e4SMauro Carvalho Chehab 		 */
1083d76231e4SMauro Carvalho Chehab 
1084d76231e4SMauro Carvalho Chehab 		/*
1085d76231e4SMauro Carvalho Chehab 		 * The proper adjustment would be to do it at s-code table.
1086d76231e4SMauro Carvalho Chehab 		 * However, this didn't work, as reported by
1087d76231e4SMauro Carvalho Chehab 		 * Robert Lowery <rglowery@exemail.com.au>
1088d76231e4SMauro Carvalho Chehab 		 */
1089d76231e4SMauro Carvalho Chehab 
1090d76231e4SMauro Carvalho Chehab #if 0
1091d76231e4SMauro Carvalho Chehab 		/*
1092d76231e4SMauro Carvalho Chehab 		 * Still need tests for XC3028L (firmware 3.2 or upper)
1093d76231e4SMauro Carvalho Chehab 		 * So, for now, let's just comment the per-firmware
1094d76231e4SMauro Carvalho Chehab 		 * version of this change. Reports with xc3028l working
1095d76231e4SMauro Carvalho Chehab 		 * with and without the lines below are welcome
1096d76231e4SMauro Carvalho Chehab 		 */
1097d76231e4SMauro Carvalho Chehab 
1098d76231e4SMauro Carvalho Chehab 		if (priv->firm_version < 0x0302) {
1099d76231e4SMauro Carvalho Chehab 			if (priv->cur_fw.type & DTV7)
1100d76231e4SMauro Carvalho Chehab 				offset += 500000;
1101d76231e4SMauro Carvalho Chehab 		} else {
1102d76231e4SMauro Carvalho Chehab 			if (priv->cur_fw.type & DTV7)
1103d76231e4SMauro Carvalho Chehab 				offset -= 300000;
1104d76231e4SMauro Carvalho Chehab 			else if (type != ATSC) /* DVB @6MHz, DTV 8 and DTV 7/8 */
1105d76231e4SMauro Carvalho Chehab 				offset += 200000;
1106d76231e4SMauro Carvalho Chehab 		}
1107d76231e4SMauro Carvalho Chehab #endif
1108d76231e4SMauro Carvalho Chehab 		break;
1109d76231e4SMauro Carvalho Chehab 	default:
1110d76231e4SMauro Carvalho Chehab 		tuner_err("Unsupported tuner type %d.\n", new_type);
1111d76231e4SMauro Carvalho Chehab 		break;
1112d76231e4SMauro Carvalho Chehab 	}
1113d76231e4SMauro Carvalho Chehab 
1114d76231e4SMauro Carvalho Chehab 	div = (freq - offset + DIV / 2) / DIV;
1115d76231e4SMauro Carvalho Chehab 
1116d76231e4SMauro Carvalho Chehab 	/* CMD= Set frequency */
1117d76231e4SMauro Carvalho Chehab 	if (priv->firm_version < 0x0202)
1118d76231e4SMauro Carvalho Chehab 		rc = send_seq(priv, {0x00, XREG_RF_FREQ, 0x00, 0x00});
1119d76231e4SMauro Carvalho Chehab 	else
1120d76231e4SMauro Carvalho Chehab 		rc = send_seq(priv, {0x80, XREG_RF_FREQ, 0x00, 0x00});
1121d76231e4SMauro Carvalho Chehab 	if (rc < 0)
1122d76231e4SMauro Carvalho Chehab 		goto ret;
1123d76231e4SMauro Carvalho Chehab 
1124d76231e4SMauro Carvalho Chehab 	/* Return code shouldn't be checked.
1125d76231e4SMauro Carvalho Chehab 	   The reset CLK is needed only with tm6000.
1126d76231e4SMauro Carvalho Chehab 	   Driver should work fine even if this fails.
1127d76231e4SMauro Carvalho Chehab 	 */
1128d76231e4SMauro Carvalho Chehab 	if (priv->ctrl.msleep)
1129d76231e4SMauro Carvalho Chehab 		msleep(priv->ctrl.msleep);
1130d76231e4SMauro Carvalho Chehab 	do_tuner_callback(fe, XC2028_RESET_CLK, 1);
1131d76231e4SMauro Carvalho Chehab 
1132d76231e4SMauro Carvalho Chehab 	msleep(10);
1133d76231e4SMauro Carvalho Chehab 
1134d76231e4SMauro Carvalho Chehab 	buf[0] = 0xff & (div >> 24);
1135d76231e4SMauro Carvalho Chehab 	buf[1] = 0xff & (div >> 16);
1136d76231e4SMauro Carvalho Chehab 	buf[2] = 0xff & (div >> 8);
1137d76231e4SMauro Carvalho Chehab 	buf[3] = 0xff & (div);
1138d76231e4SMauro Carvalho Chehab 
1139d76231e4SMauro Carvalho Chehab 	rc = i2c_send(priv, buf, sizeof(buf));
1140d76231e4SMauro Carvalho Chehab 	if (rc < 0)
1141d76231e4SMauro Carvalho Chehab 		goto ret;
1142d76231e4SMauro Carvalho Chehab 	msleep(100);
1143d76231e4SMauro Carvalho Chehab 
1144d76231e4SMauro Carvalho Chehab 	priv->frequency = freq;
1145d76231e4SMauro Carvalho Chehab 
1146d76231e4SMauro Carvalho Chehab 	tuner_dbg("divisor= %*ph (freq=%d.%03d)\n", 4, buf,
1147d76231e4SMauro Carvalho Chehab 	       freq / 1000000, (freq % 1000000) / 1000);
1148d76231e4SMauro Carvalho Chehab 
1149d76231e4SMauro Carvalho Chehab 	rc = 0;
1150d76231e4SMauro Carvalho Chehab 
1151d76231e4SMauro Carvalho Chehab ret:
1152d76231e4SMauro Carvalho Chehab 	mutex_unlock(&priv->lock);
1153d76231e4SMauro Carvalho Chehab 
1154d76231e4SMauro Carvalho Chehab 	return rc;
1155d76231e4SMauro Carvalho Chehab }
1156d76231e4SMauro Carvalho Chehab 
xc2028_set_analog_freq(struct dvb_frontend * fe,struct analog_parameters * p)1157d76231e4SMauro Carvalho Chehab static int xc2028_set_analog_freq(struct dvb_frontend *fe,
1158d76231e4SMauro Carvalho Chehab 			      struct analog_parameters *p)
1159d76231e4SMauro Carvalho Chehab {
1160d76231e4SMauro Carvalho Chehab 	struct xc2028_data *priv = fe->tuner_priv;
1161d76231e4SMauro Carvalho Chehab 	unsigned int       type=0;
1162d76231e4SMauro Carvalho Chehab 
1163d76231e4SMauro Carvalho Chehab 	tuner_dbg("%s called\n", __func__);
1164d76231e4SMauro Carvalho Chehab 
1165d76231e4SMauro Carvalho Chehab 	if (p->mode == V4L2_TUNER_RADIO) {
1166d76231e4SMauro Carvalho Chehab 		type |= FM;
1167d76231e4SMauro Carvalho Chehab 		if (priv->ctrl.input1)
1168d76231e4SMauro Carvalho Chehab 			type |= INPUT1;
1169d76231e4SMauro Carvalho Chehab 		return generic_set_freq(fe, (625l * p->frequency) / 10,
1170d76231e4SMauro Carvalho Chehab 				V4L2_TUNER_RADIO, type, 0, 0);
1171d76231e4SMauro Carvalho Chehab 	}
1172d76231e4SMauro Carvalho Chehab 
1173d76231e4SMauro Carvalho Chehab 	/* if std is not defined, choose one */
1174d76231e4SMauro Carvalho Chehab 	if (!p->std)
1175d76231e4SMauro Carvalho Chehab 		p->std = V4L2_STD_MN;
1176d76231e4SMauro Carvalho Chehab 
1177d76231e4SMauro Carvalho Chehab 	/* PAL/M, PAL/N, PAL/Nc and NTSC variants should use 6MHz firmware */
1178d76231e4SMauro Carvalho Chehab 	if (!(p->std & V4L2_STD_MN))
1179d76231e4SMauro Carvalho Chehab 		type |= F8MHZ;
1180d76231e4SMauro Carvalho Chehab 
1181d76231e4SMauro Carvalho Chehab 	/* Add audio hack to std mask */
1182d76231e4SMauro Carvalho Chehab 	p->std |= parse_audio_std_option();
1183d76231e4SMauro Carvalho Chehab 
1184d76231e4SMauro Carvalho Chehab 	return generic_set_freq(fe, 62500l * p->frequency,
1185d76231e4SMauro Carvalho Chehab 				V4L2_TUNER_ANALOG_TV, type, p->std, 0);
1186d76231e4SMauro Carvalho Chehab }
1187d76231e4SMauro Carvalho Chehab 
xc2028_set_params(struct dvb_frontend * fe)1188d76231e4SMauro Carvalho Chehab static int xc2028_set_params(struct dvb_frontend *fe)
1189d76231e4SMauro Carvalho Chehab {
1190d76231e4SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
1191d76231e4SMauro Carvalho Chehab 	u32 delsys = c->delivery_system;
1192d76231e4SMauro Carvalho Chehab 	u32 bw = c->bandwidth_hz;
1193d76231e4SMauro Carvalho Chehab 	struct xc2028_data *priv = fe->tuner_priv;
1194d76231e4SMauro Carvalho Chehab 	int rc;
1195d76231e4SMauro Carvalho Chehab 	unsigned int       type = 0;
1196d76231e4SMauro Carvalho Chehab 	u16                demod = 0;
1197d76231e4SMauro Carvalho Chehab 
1198d76231e4SMauro Carvalho Chehab 	tuner_dbg("%s called\n", __func__);
1199d76231e4SMauro Carvalho Chehab 
1200d76231e4SMauro Carvalho Chehab 	rc = check_device_status(priv);
1201d76231e4SMauro Carvalho Chehab 	if (rc < 0)
1202d76231e4SMauro Carvalho Chehab 		return rc;
1203d76231e4SMauro Carvalho Chehab 
1204d76231e4SMauro Carvalho Chehab 	switch (delsys) {
1205d76231e4SMauro Carvalho Chehab 	case SYS_DVBT:
1206d76231e4SMauro Carvalho Chehab 	case SYS_DVBT2:
1207d76231e4SMauro Carvalho Chehab 		/*
1208d76231e4SMauro Carvalho Chehab 		 * The only countries with 6MHz seem to be Taiwan/Uruguay.
1209d76231e4SMauro Carvalho Chehab 		 * Both seem to require QAM firmware for OFDM decoding
1210d76231e4SMauro Carvalho Chehab 		 * Tested in Taiwan by Terry Wu <terrywu2009@gmail.com>
1211d76231e4SMauro Carvalho Chehab 		 */
1212d76231e4SMauro Carvalho Chehab 		if (bw <= 6000000)
1213d76231e4SMauro Carvalho Chehab 			type |= QAM;
1214d76231e4SMauro Carvalho Chehab 
1215d76231e4SMauro Carvalho Chehab 		switch (priv->ctrl.type) {
1216d76231e4SMauro Carvalho Chehab 		case XC2028_D2633:
1217d76231e4SMauro Carvalho Chehab 			type |= D2633;
1218d76231e4SMauro Carvalho Chehab 			break;
1219d76231e4SMauro Carvalho Chehab 		case XC2028_D2620:
1220d76231e4SMauro Carvalho Chehab 			type |= D2620;
1221d76231e4SMauro Carvalho Chehab 			break;
1222d76231e4SMauro Carvalho Chehab 		case XC2028_AUTO:
1223d76231e4SMauro Carvalho Chehab 		default:
1224d76231e4SMauro Carvalho Chehab 			/* Zarlink seems to need D2633 */
1225d76231e4SMauro Carvalho Chehab 			if (priv->ctrl.demod == XC3028_FE_ZARLINK456)
1226d76231e4SMauro Carvalho Chehab 				type |= D2633;
1227d76231e4SMauro Carvalho Chehab 			else
1228d76231e4SMauro Carvalho Chehab 				type |= D2620;
1229d76231e4SMauro Carvalho Chehab 		}
1230d76231e4SMauro Carvalho Chehab 		break;
1231d76231e4SMauro Carvalho Chehab 	case SYS_ATSC:
1232d76231e4SMauro Carvalho Chehab 		/* The only ATSC firmware (at least on v2.7) is D2633 */
1233d76231e4SMauro Carvalho Chehab 		type |= ATSC | D2633;
1234d76231e4SMauro Carvalho Chehab 		break;
1235d76231e4SMauro Carvalho Chehab 	/* DVB-S and pure QAM (FE_QAM) are not supported */
1236d76231e4SMauro Carvalho Chehab 	default:
1237d76231e4SMauro Carvalho Chehab 		return -EINVAL;
1238d76231e4SMauro Carvalho Chehab 	}
1239d76231e4SMauro Carvalho Chehab 
1240d76231e4SMauro Carvalho Chehab 	if (bw <= 6000000) {
1241d76231e4SMauro Carvalho Chehab 		type |= DTV6;
1242d76231e4SMauro Carvalho Chehab 		priv->ctrl.vhfbw7 = 0;
1243d76231e4SMauro Carvalho Chehab 		priv->ctrl.uhfbw8 = 0;
1244d76231e4SMauro Carvalho Chehab 	} else if (bw <= 7000000) {
1245d76231e4SMauro Carvalho Chehab 		if (c->frequency < 470000000)
1246d76231e4SMauro Carvalho Chehab 			priv->ctrl.vhfbw7 = 1;
1247d76231e4SMauro Carvalho Chehab 		else
1248d76231e4SMauro Carvalho Chehab 			priv->ctrl.uhfbw8 = 0;
1249d76231e4SMauro Carvalho Chehab 		type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV7;
1250d76231e4SMauro Carvalho Chehab 		type |= F8MHZ;
1251d76231e4SMauro Carvalho Chehab 	} else {
1252d76231e4SMauro Carvalho Chehab 		if (c->frequency < 470000000)
1253d76231e4SMauro Carvalho Chehab 			priv->ctrl.vhfbw7 = 0;
1254d76231e4SMauro Carvalho Chehab 		else
1255d76231e4SMauro Carvalho Chehab 			priv->ctrl.uhfbw8 = 1;
1256d76231e4SMauro Carvalho Chehab 		type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV8;
1257d76231e4SMauro Carvalho Chehab 		type |= F8MHZ;
1258d76231e4SMauro Carvalho Chehab 	}
1259d76231e4SMauro Carvalho Chehab 
1260d76231e4SMauro Carvalho Chehab 	/* All S-code tables need a 200kHz shift */
1261d76231e4SMauro Carvalho Chehab 	if (priv->ctrl.demod) {
1262d76231e4SMauro Carvalho Chehab 		demod = priv->ctrl.demod;
1263d76231e4SMauro Carvalho Chehab 
1264d76231e4SMauro Carvalho Chehab 		/*
1265d76231e4SMauro Carvalho Chehab 		 * Newer firmwares require a 200 kHz offset only for ATSC
1266d76231e4SMauro Carvalho Chehab 		 */
1267d76231e4SMauro Carvalho Chehab 		if (type == ATSC || priv->firm_version < 0x0302)
1268d76231e4SMauro Carvalho Chehab 			demod += 200;
1269d76231e4SMauro Carvalho Chehab 		/*
1270d76231e4SMauro Carvalho Chehab 		 * The DTV7 S-code table needs a 700 kHz shift.
1271d76231e4SMauro Carvalho Chehab 		 *
1272d76231e4SMauro Carvalho Chehab 		 * DTV7 is only used in Australia.  Germany or Italy may also
1273d76231e4SMauro Carvalho Chehab 		 * use this firmware after initialization, but a tune to a UHF
1274d76231e4SMauro Carvalho Chehab 		 * channel should then cause DTV78 to be used.
1275d76231e4SMauro Carvalho Chehab 		 *
1276d76231e4SMauro Carvalho Chehab 		 * Unfortunately, on real-field tests, the s-code offset
1277d76231e4SMauro Carvalho Chehab 		 * didn't work as expected, as reported by
1278d76231e4SMauro Carvalho Chehab 		 * Robert Lowery <rglowery@exemail.com.au>
1279d76231e4SMauro Carvalho Chehab 		 */
1280d76231e4SMauro Carvalho Chehab 	}
1281d76231e4SMauro Carvalho Chehab 
1282d76231e4SMauro Carvalho Chehab 	return generic_set_freq(fe, c->frequency,
1283d76231e4SMauro Carvalho Chehab 				V4L2_TUNER_DIGITAL_TV, type, 0, demod);
1284d76231e4SMauro Carvalho Chehab }
1285d76231e4SMauro Carvalho Chehab 
xc2028_sleep(struct dvb_frontend * fe)1286d76231e4SMauro Carvalho Chehab static int xc2028_sleep(struct dvb_frontend *fe)
1287d76231e4SMauro Carvalho Chehab {
1288d76231e4SMauro Carvalho Chehab 	struct xc2028_data *priv = fe->tuner_priv;
1289d76231e4SMauro Carvalho Chehab 	int rc;
1290d76231e4SMauro Carvalho Chehab 
1291d76231e4SMauro Carvalho Chehab 	rc = check_device_status(priv);
1292d76231e4SMauro Carvalho Chehab 	if (rc < 0)
1293d76231e4SMauro Carvalho Chehab 		return rc;
1294d76231e4SMauro Carvalho Chehab 
1295d76231e4SMauro Carvalho Chehab 	/* Device is already in sleep mode */
1296d76231e4SMauro Carvalho Chehab 	if (!rc)
1297d76231e4SMauro Carvalho Chehab 		return 0;
1298d76231e4SMauro Carvalho Chehab 
1299d76231e4SMauro Carvalho Chehab 	/* Avoid firmware reload on slow devices or if PM disabled */
1300d76231e4SMauro Carvalho Chehab 	if (no_poweroff || priv->ctrl.disable_power_mgmt)
1301d76231e4SMauro Carvalho Chehab 		return 0;
1302d76231e4SMauro Carvalho Chehab 
1303d76231e4SMauro Carvalho Chehab 	tuner_dbg("Putting xc2028/3028 into poweroff mode.\n");
1304d76231e4SMauro Carvalho Chehab 	if (debug > 1) {
1305d76231e4SMauro Carvalho Chehab 		tuner_dbg("Printing sleep stack trace:\n");
1306d76231e4SMauro Carvalho Chehab 		dump_stack();
1307d76231e4SMauro Carvalho Chehab 	}
1308d76231e4SMauro Carvalho Chehab 
1309d76231e4SMauro Carvalho Chehab 	mutex_lock(&priv->lock);
1310d76231e4SMauro Carvalho Chehab 
1311d76231e4SMauro Carvalho Chehab 	if (priv->firm_version < 0x0202)
1312d76231e4SMauro Carvalho Chehab 		rc = send_seq(priv, {0x00, XREG_POWER_DOWN, 0x00, 0x00});
1313d76231e4SMauro Carvalho Chehab 	else
1314d76231e4SMauro Carvalho Chehab 		rc = send_seq(priv, {0x80, XREG_POWER_DOWN, 0x00, 0x00});
1315d76231e4SMauro Carvalho Chehab 
1316d76231e4SMauro Carvalho Chehab 	if (rc >= 0)
1317d76231e4SMauro Carvalho Chehab 		priv->state = XC2028_SLEEP;
1318d76231e4SMauro Carvalho Chehab 
1319d76231e4SMauro Carvalho Chehab 	mutex_unlock(&priv->lock);
1320d76231e4SMauro Carvalho Chehab 
1321d76231e4SMauro Carvalho Chehab 	return rc;
1322d76231e4SMauro Carvalho Chehab }
1323d76231e4SMauro Carvalho Chehab 
xc2028_dvb_release(struct dvb_frontend * fe)1324d76231e4SMauro Carvalho Chehab static void xc2028_dvb_release(struct dvb_frontend *fe)
1325d76231e4SMauro Carvalho Chehab {
1326d76231e4SMauro Carvalho Chehab 	struct xc2028_data *priv = fe->tuner_priv;
1327d76231e4SMauro Carvalho Chehab 
1328d76231e4SMauro Carvalho Chehab 	tuner_dbg("%s called\n", __func__);
1329d76231e4SMauro Carvalho Chehab 
1330d76231e4SMauro Carvalho Chehab 	mutex_lock(&xc2028_list_mutex);
1331d76231e4SMauro Carvalho Chehab 
1332d76231e4SMauro Carvalho Chehab 	/* only perform final cleanup if this is the last instance */
1333d76231e4SMauro Carvalho Chehab 	if (hybrid_tuner_report_instance_count(priv) == 1)
1334d76231e4SMauro Carvalho Chehab 		free_firmware(priv);
1335d76231e4SMauro Carvalho Chehab 
1336d76231e4SMauro Carvalho Chehab 	if (priv)
1337d76231e4SMauro Carvalho Chehab 		hybrid_tuner_release_state(priv);
1338d76231e4SMauro Carvalho Chehab 
1339d76231e4SMauro Carvalho Chehab 	mutex_unlock(&xc2028_list_mutex);
1340d76231e4SMauro Carvalho Chehab 
1341d76231e4SMauro Carvalho Chehab 	fe->tuner_priv = NULL;
1342d76231e4SMauro Carvalho Chehab }
1343d76231e4SMauro Carvalho Chehab 
xc2028_get_frequency(struct dvb_frontend * fe,u32 * frequency)1344d76231e4SMauro Carvalho Chehab static int xc2028_get_frequency(struct dvb_frontend *fe, u32 *frequency)
1345d76231e4SMauro Carvalho Chehab {
1346d76231e4SMauro Carvalho Chehab 	struct xc2028_data *priv = fe->tuner_priv;
1347d76231e4SMauro Carvalho Chehab 	int rc;
1348d76231e4SMauro Carvalho Chehab 
1349d76231e4SMauro Carvalho Chehab 	tuner_dbg("%s called\n", __func__);
1350d76231e4SMauro Carvalho Chehab 
1351d76231e4SMauro Carvalho Chehab 	rc = check_device_status(priv);
1352d76231e4SMauro Carvalho Chehab 	if (rc < 0)
1353d76231e4SMauro Carvalho Chehab 		return rc;
1354d76231e4SMauro Carvalho Chehab 
1355d76231e4SMauro Carvalho Chehab 	*frequency = priv->frequency;
1356d76231e4SMauro Carvalho Chehab 
1357d76231e4SMauro Carvalho Chehab 	return 0;
1358d76231e4SMauro Carvalho Chehab }
1359d76231e4SMauro Carvalho Chehab 
load_firmware_cb(const struct firmware * fw,void * context)1360d76231e4SMauro Carvalho Chehab static void load_firmware_cb(const struct firmware *fw,
1361d76231e4SMauro Carvalho Chehab 			     void *context)
1362d76231e4SMauro Carvalho Chehab {
1363d76231e4SMauro Carvalho Chehab 	struct dvb_frontend *fe = context;
1364*85030415SChi Zhiling 	struct xc2028_data *priv;
1365d76231e4SMauro Carvalho Chehab 	int rc;
1366d76231e4SMauro Carvalho Chehab 
1367*85030415SChi Zhiling 	if (!fe) {
1368*85030415SChi Zhiling 		pr_warn("xc2028: No frontend in %s\n", __func__);
1369*85030415SChi Zhiling 		return;
1370*85030415SChi Zhiling 	}
1371*85030415SChi Zhiling 
1372*85030415SChi Zhiling 	priv = fe->tuner_priv;
1373*85030415SChi Zhiling 
1374d76231e4SMauro Carvalho Chehab 	tuner_dbg("request_firmware_nowait(): %s\n", fw ? "OK" : "error");
1375d76231e4SMauro Carvalho Chehab 	if (!fw) {
1376d76231e4SMauro Carvalho Chehab 		tuner_err("Could not load firmware %s.\n", priv->fname);
1377d76231e4SMauro Carvalho Chehab 		priv->state = XC2028_NODEV;
1378d76231e4SMauro Carvalho Chehab 		return;
1379d76231e4SMauro Carvalho Chehab 	}
1380d76231e4SMauro Carvalho Chehab 
1381d76231e4SMauro Carvalho Chehab 	rc = load_all_firmwares(fe, fw);
1382d76231e4SMauro Carvalho Chehab 
1383d76231e4SMauro Carvalho Chehab 	release_firmware(fw);
1384d76231e4SMauro Carvalho Chehab 
1385d76231e4SMauro Carvalho Chehab 	if (rc < 0)
1386d76231e4SMauro Carvalho Chehab 		return;
1387d76231e4SMauro Carvalho Chehab 	priv->state = XC2028_ACTIVE;
1388d76231e4SMauro Carvalho Chehab }
1389d76231e4SMauro Carvalho Chehab 
xc2028_set_config(struct dvb_frontend * fe,void * priv_cfg)1390d76231e4SMauro Carvalho Chehab static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg)
1391d76231e4SMauro Carvalho Chehab {
1392d76231e4SMauro Carvalho Chehab 	struct xc2028_data *priv = fe->tuner_priv;
1393d76231e4SMauro Carvalho Chehab 	struct xc2028_ctrl *p    = priv_cfg;
1394d76231e4SMauro Carvalho Chehab 	int                 rc   = 0;
1395d76231e4SMauro Carvalho Chehab 
1396d76231e4SMauro Carvalho Chehab 	tuner_dbg("%s called\n", __func__);
1397d76231e4SMauro Carvalho Chehab 
1398d76231e4SMauro Carvalho Chehab 	mutex_lock(&priv->lock);
1399d76231e4SMauro Carvalho Chehab 
1400d76231e4SMauro Carvalho Chehab 	/*
1401d76231e4SMauro Carvalho Chehab 	 * Copy the config data.
1402d76231e4SMauro Carvalho Chehab 	 */
1403d76231e4SMauro Carvalho Chehab 	memcpy(&priv->ctrl, p, sizeof(priv->ctrl));
1404d76231e4SMauro Carvalho Chehab 
1405d76231e4SMauro Carvalho Chehab 	/*
1406d76231e4SMauro Carvalho Chehab 	 * If firmware name changed, frees firmware. As free_firmware will
1407d76231e4SMauro Carvalho Chehab 	 * reset the status to NO_FIRMWARE, this forces a new request_firmware
1408d76231e4SMauro Carvalho Chehab 	 */
1409d76231e4SMauro Carvalho Chehab 	if (!firmware_name[0] && p->fname &&
1410d76231e4SMauro Carvalho Chehab 	    priv->fname && strcmp(p->fname, priv->fname))
1411d76231e4SMauro Carvalho Chehab 		free_firmware(priv);
1412d76231e4SMauro Carvalho Chehab 
1413d76231e4SMauro Carvalho Chehab 	if (priv->ctrl.max_len < 9)
1414d76231e4SMauro Carvalho Chehab 		priv->ctrl.max_len = 13;
1415d76231e4SMauro Carvalho Chehab 
1416d76231e4SMauro Carvalho Chehab 	if (priv->state == XC2028_NO_FIRMWARE) {
1417d76231e4SMauro Carvalho Chehab 		if (!firmware_name[0])
1418d76231e4SMauro Carvalho Chehab 			priv->fname = kstrdup(p->fname, GFP_KERNEL);
1419d76231e4SMauro Carvalho Chehab 		else
1420d76231e4SMauro Carvalho Chehab 			priv->fname = firmware_name;
1421d76231e4SMauro Carvalho Chehab 
1422d76231e4SMauro Carvalho Chehab 		if (!priv->fname) {
1423d76231e4SMauro Carvalho Chehab 			rc = -ENOMEM;
1424d76231e4SMauro Carvalho Chehab 			goto unlock;
1425d76231e4SMauro Carvalho Chehab 		}
1426d76231e4SMauro Carvalho Chehab 
1427d76231e4SMauro Carvalho Chehab 		rc = request_firmware_nowait(THIS_MODULE, 1,
1428d76231e4SMauro Carvalho Chehab 					     priv->fname,
1429d76231e4SMauro Carvalho Chehab 					     priv->i2c_props.adap->dev.parent,
1430d76231e4SMauro Carvalho Chehab 					     GFP_KERNEL,
1431d76231e4SMauro Carvalho Chehab 					     fe, load_firmware_cb);
1432d76231e4SMauro Carvalho Chehab 		if (rc < 0) {
1433d76231e4SMauro Carvalho Chehab 			tuner_err("Failed to request firmware %s\n",
1434d76231e4SMauro Carvalho Chehab 				  priv->fname);
1435d76231e4SMauro Carvalho Chehab 			priv->state = XC2028_NODEV;
1436d76231e4SMauro Carvalho Chehab 		} else
1437d76231e4SMauro Carvalho Chehab 			priv->state = XC2028_WAITING_FIRMWARE;
1438d76231e4SMauro Carvalho Chehab 	}
1439d76231e4SMauro Carvalho Chehab unlock:
1440d76231e4SMauro Carvalho Chehab 	mutex_unlock(&priv->lock);
1441d76231e4SMauro Carvalho Chehab 
1442d76231e4SMauro Carvalho Chehab 	return rc;
1443d76231e4SMauro Carvalho Chehab }
1444d76231e4SMauro Carvalho Chehab 
1445d76231e4SMauro Carvalho Chehab static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = {
1446d76231e4SMauro Carvalho Chehab 	.info = {
1447d76231e4SMauro Carvalho Chehab 		 .name = "Xceive XC3028",
1448d76231e4SMauro Carvalho Chehab 		 .frequency_min_hz  =  42 * MHz,
1449d76231e4SMauro Carvalho Chehab 		 .frequency_max_hz  = 864 * MHz,
1450d76231e4SMauro Carvalho Chehab 		 .frequency_step_hz =  50 * kHz,
1451d76231e4SMauro Carvalho Chehab 		 },
1452d76231e4SMauro Carvalho Chehab 
1453d76231e4SMauro Carvalho Chehab 	.set_config	   = xc2028_set_config,
1454d76231e4SMauro Carvalho Chehab 	.set_analog_params = xc2028_set_analog_freq,
1455d76231e4SMauro Carvalho Chehab 	.release           = xc2028_dvb_release,
1456d76231e4SMauro Carvalho Chehab 	.get_frequency     = xc2028_get_frequency,
1457d76231e4SMauro Carvalho Chehab 	.get_rf_strength   = xc2028_signal,
1458d76231e4SMauro Carvalho Chehab 	.get_afc           = xc2028_get_afc,
1459d76231e4SMauro Carvalho Chehab 	.set_params        = xc2028_set_params,
1460d76231e4SMauro Carvalho Chehab 	.sleep             = xc2028_sleep,
1461d76231e4SMauro Carvalho Chehab };
1462d76231e4SMauro Carvalho Chehab 
xc2028_attach(struct dvb_frontend * fe,struct xc2028_config * cfg)1463d76231e4SMauro Carvalho Chehab struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
1464d76231e4SMauro Carvalho Chehab 				   struct xc2028_config *cfg)
1465d76231e4SMauro Carvalho Chehab {
1466d76231e4SMauro Carvalho Chehab 	struct xc2028_data *priv;
1467d76231e4SMauro Carvalho Chehab 	int instance;
1468d76231e4SMauro Carvalho Chehab 
1469d76231e4SMauro Carvalho Chehab 	if (debug)
1470d76231e4SMauro Carvalho Chehab 		printk(KERN_DEBUG "xc2028: Xcv2028/3028 init called!\n");
1471d76231e4SMauro Carvalho Chehab 
1472d76231e4SMauro Carvalho Chehab 	if (NULL == cfg)
1473d76231e4SMauro Carvalho Chehab 		return NULL;
1474d76231e4SMauro Carvalho Chehab 
1475d76231e4SMauro Carvalho Chehab 	if (!fe) {
1476d76231e4SMauro Carvalho Chehab 		printk(KERN_ERR "xc2028: No frontend!\n");
1477d76231e4SMauro Carvalho Chehab 		return NULL;
1478d76231e4SMauro Carvalho Chehab 	}
1479d76231e4SMauro Carvalho Chehab 
1480d76231e4SMauro Carvalho Chehab 	mutex_lock(&xc2028_list_mutex);
1481d76231e4SMauro Carvalho Chehab 
1482d76231e4SMauro Carvalho Chehab 	instance = hybrid_tuner_request_state(struct xc2028_data, priv,
1483d76231e4SMauro Carvalho Chehab 					      hybrid_tuner_instance_list,
1484d76231e4SMauro Carvalho Chehab 					      cfg->i2c_adap, cfg->i2c_addr,
1485d76231e4SMauro Carvalho Chehab 					      "xc2028");
1486d76231e4SMauro Carvalho Chehab 	switch (instance) {
1487d76231e4SMauro Carvalho Chehab 	case 0:
1488d76231e4SMauro Carvalho Chehab 		/* memory allocation failure */
1489d76231e4SMauro Carvalho Chehab 		goto fail;
1490d76231e4SMauro Carvalho Chehab 	case 1:
1491d76231e4SMauro Carvalho Chehab 		/* new tuner instance */
1492d76231e4SMauro Carvalho Chehab 		priv->ctrl.max_len = 13;
1493d76231e4SMauro Carvalho Chehab 
1494d76231e4SMauro Carvalho Chehab 		mutex_init(&priv->lock);
1495d76231e4SMauro Carvalho Chehab 
1496d76231e4SMauro Carvalho Chehab 		fe->tuner_priv = priv;
1497d76231e4SMauro Carvalho Chehab 		break;
1498d76231e4SMauro Carvalho Chehab 	case 2:
1499d76231e4SMauro Carvalho Chehab 		/* existing tuner instance */
1500d76231e4SMauro Carvalho Chehab 		fe->tuner_priv = priv;
1501d76231e4SMauro Carvalho Chehab 		break;
1502d76231e4SMauro Carvalho Chehab 	}
1503d76231e4SMauro Carvalho Chehab 
1504d76231e4SMauro Carvalho Chehab 	memcpy(&fe->ops.tuner_ops, &xc2028_dvb_tuner_ops,
1505d76231e4SMauro Carvalho Chehab 	       sizeof(xc2028_dvb_tuner_ops));
1506d76231e4SMauro Carvalho Chehab 
1507d76231e4SMauro Carvalho Chehab 	tuner_info("type set to %s\n", "XCeive xc2028/xc3028 tuner");
1508d76231e4SMauro Carvalho Chehab 
1509d76231e4SMauro Carvalho Chehab 	if (cfg->ctrl)
1510d76231e4SMauro Carvalho Chehab 		xc2028_set_config(fe, cfg->ctrl);
1511d76231e4SMauro Carvalho Chehab 
1512d76231e4SMauro Carvalho Chehab 	mutex_unlock(&xc2028_list_mutex);
1513d76231e4SMauro Carvalho Chehab 
1514d76231e4SMauro Carvalho Chehab 	return fe;
1515d76231e4SMauro Carvalho Chehab fail:
1516d76231e4SMauro Carvalho Chehab 	mutex_unlock(&xc2028_list_mutex);
1517d76231e4SMauro Carvalho Chehab 
1518d76231e4SMauro Carvalho Chehab 	xc2028_dvb_release(fe);
1519d76231e4SMauro Carvalho Chehab 	return NULL;
1520d76231e4SMauro Carvalho Chehab }
1521d76231e4SMauro Carvalho Chehab 
152286495af1SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(xc2028_attach);
1523d76231e4SMauro Carvalho Chehab 
1524d76231e4SMauro Carvalho Chehab MODULE_DESCRIPTION("Xceive xc2028/xc3028 tuner driver");
1525d76231e4SMauro Carvalho Chehab MODULE_AUTHOR("Michel Ludwig <michel.ludwig@gmail.com>");
1526d76231e4SMauro Carvalho Chehab MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@kernel.org>");
1527d76231e4SMauro Carvalho Chehab MODULE_LICENSE("GPL v2");
1528d76231e4SMauro Carvalho Chehab MODULE_FIRMWARE(XC2028_DEFAULT_FIRMWARE);
1529d76231e4SMauro Carvalho Chehab MODULE_FIRMWARE(XC3028L_DEFAULT_FIRMWARE);
1530