1786baecfSMauro Carvalho Chehab /*
2786baecfSMauro Carvalho Chehab  * Afatech AF9035 DVB USB driver
3786baecfSMauro Carvalho Chehab  *
4786baecfSMauro Carvalho Chehab  * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
5786baecfSMauro Carvalho Chehab  * Copyright (C) 2012 Antti Palosaari <crope@iki.fi>
6786baecfSMauro Carvalho Chehab  *
7786baecfSMauro Carvalho Chehab  *    This program is free software; you can redistribute it and/or modify
8786baecfSMauro Carvalho Chehab  *    it under the terms of the GNU General Public License as published by
9786baecfSMauro Carvalho Chehab  *    the Free Software Foundation; either version 2 of the License, or
10786baecfSMauro Carvalho Chehab  *    (at your option) any later version.
11786baecfSMauro Carvalho Chehab  *
12786baecfSMauro Carvalho Chehab  *    This program is distributed in the hope that it will be useful,
13786baecfSMauro Carvalho Chehab  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
14786baecfSMauro Carvalho Chehab  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15786baecfSMauro Carvalho Chehab  *    GNU General Public License for more details.
16786baecfSMauro Carvalho Chehab  *
17786baecfSMauro Carvalho Chehab  *    You should have received a copy of the GNU General Public License along
18786baecfSMauro Carvalho Chehab  *    with this program; if not, write to the Free Software Foundation, Inc.,
19786baecfSMauro Carvalho Chehab  *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20786baecfSMauro Carvalho Chehab  */
21786baecfSMauro Carvalho Chehab 
22786baecfSMauro Carvalho Chehab #include "af9035.h"
23786baecfSMauro Carvalho Chehab 
24786baecfSMauro Carvalho Chehab DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
25786baecfSMauro Carvalho Chehab 
26786baecfSMauro Carvalho Chehab static u16 af9035_checksum(const u8 *buf, size_t len)
27786baecfSMauro Carvalho Chehab {
28786baecfSMauro Carvalho Chehab 	size_t i;
29786baecfSMauro Carvalho Chehab 	u16 checksum = 0;
30786baecfSMauro Carvalho Chehab 
31786baecfSMauro Carvalho Chehab 	for (i = 1; i < len; i++) {
32786baecfSMauro Carvalho Chehab 		if (i % 2)
33786baecfSMauro Carvalho Chehab 			checksum += buf[i] << 8;
34786baecfSMauro Carvalho Chehab 		else
35786baecfSMauro Carvalho Chehab 			checksum += buf[i];
36786baecfSMauro Carvalho Chehab 	}
37786baecfSMauro Carvalho Chehab 	checksum = ~checksum;
38786baecfSMauro Carvalho Chehab 
39786baecfSMauro Carvalho Chehab 	return checksum;
40786baecfSMauro Carvalho Chehab }
41786baecfSMauro Carvalho Chehab 
42786baecfSMauro Carvalho Chehab static int af9035_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req)
43786baecfSMauro Carvalho Chehab {
44786baecfSMauro Carvalho Chehab #define BUF_LEN 64
45786baecfSMauro Carvalho Chehab #define REQ_HDR_LEN 4 /* send header size */
46786baecfSMauro Carvalho Chehab #define ACK_HDR_LEN 3 /* rece header size */
47786baecfSMauro Carvalho Chehab #define CHECKSUM_LEN 2
48786baecfSMauro Carvalho Chehab #define USB_TIMEOUT 2000
49786baecfSMauro Carvalho Chehab 	struct state *state = d_to_priv(d);
50786baecfSMauro Carvalho Chehab 	int ret, wlen, rlen;
51786baecfSMauro Carvalho Chehab 	u8 buf[BUF_LEN];
52786baecfSMauro Carvalho Chehab 	u16 checksum, tmp_checksum;
53786baecfSMauro Carvalho Chehab 
54786baecfSMauro Carvalho Chehab 	/* buffer overflow check */
55786baecfSMauro Carvalho Chehab 	if (req->wlen > (BUF_LEN - REQ_HDR_LEN - CHECKSUM_LEN) ||
56786baecfSMauro Carvalho Chehab 			req->rlen > (BUF_LEN - ACK_HDR_LEN - CHECKSUM_LEN)) {
57119f7a8cSAntti Palosaari 		dev_err(&d->udev->dev, "%s: too much data wlen=%d rlen=%d\n",
58119f7a8cSAntti Palosaari 				__func__, req->wlen, req->rlen);
59786baecfSMauro Carvalho Chehab 		return -EINVAL;
60786baecfSMauro Carvalho Chehab 	}
61786baecfSMauro Carvalho Chehab 
62786baecfSMauro Carvalho Chehab 	buf[0] = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN - 1;
63786baecfSMauro Carvalho Chehab 	buf[1] = req->mbox;
64786baecfSMauro Carvalho Chehab 	buf[2] = req->cmd;
65786baecfSMauro Carvalho Chehab 	buf[3] = state->seq++;
66786baecfSMauro Carvalho Chehab 	memcpy(&buf[REQ_HDR_LEN], req->wbuf, req->wlen);
67786baecfSMauro Carvalho Chehab 
68786baecfSMauro Carvalho Chehab 	wlen = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN;
69786baecfSMauro Carvalho Chehab 	rlen = ACK_HDR_LEN + req->rlen + CHECKSUM_LEN;
70786baecfSMauro Carvalho Chehab 
71786baecfSMauro Carvalho Chehab 	/* calc and add checksum */
72786baecfSMauro Carvalho Chehab 	checksum = af9035_checksum(buf, buf[0] - 1);
73786baecfSMauro Carvalho Chehab 	buf[buf[0] - 1] = (checksum >> 8);
74786baecfSMauro Carvalho Chehab 	buf[buf[0] - 0] = (checksum & 0xff);
75786baecfSMauro Carvalho Chehab 
76786baecfSMauro Carvalho Chehab 	/* no ack for these packets */
77786baecfSMauro Carvalho Chehab 	if (req->cmd == CMD_FW_DL)
78786baecfSMauro Carvalho Chehab 		rlen = 0;
79786baecfSMauro Carvalho Chehab 
80786baecfSMauro Carvalho Chehab 	ret = dvb_usbv2_generic_rw(d, buf, wlen, buf, rlen);
81786baecfSMauro Carvalho Chehab 	if (ret)
82786baecfSMauro Carvalho Chehab 		goto err;
83786baecfSMauro Carvalho Chehab 
84786baecfSMauro Carvalho Chehab 	/* no ack for those packets */
85786baecfSMauro Carvalho Chehab 	if (req->cmd == CMD_FW_DL)
86786baecfSMauro Carvalho Chehab 		goto exit;
87786baecfSMauro Carvalho Chehab 
88786baecfSMauro Carvalho Chehab 	/* verify checksum */
89786baecfSMauro Carvalho Chehab 	checksum = af9035_checksum(buf, rlen - 2);
90786baecfSMauro Carvalho Chehab 	tmp_checksum = (buf[rlen - 2] << 8) | buf[rlen - 1];
91786baecfSMauro Carvalho Chehab 	if (tmp_checksum != checksum) {
92119f7a8cSAntti Palosaari 		dev_err(&d->udev->dev, "%s: command=%02x checksum mismatch " \
93119f7a8cSAntti Palosaari 				"(%04x != %04x)\n", KBUILD_MODNAME, req->cmd,
94119f7a8cSAntti Palosaari 				tmp_checksum, checksum);
95786baecfSMauro Carvalho Chehab 		ret = -EIO;
96786baecfSMauro Carvalho Chehab 		goto err;
97786baecfSMauro Carvalho Chehab 	}
98786baecfSMauro Carvalho Chehab 
99786baecfSMauro Carvalho Chehab 	/* check status */
100786baecfSMauro Carvalho Chehab 	if (buf[2]) {
101119f7a8cSAntti Palosaari 		dev_dbg(&d->udev->dev, "%s: command=%02x failed fw error=%d\n",
102119f7a8cSAntti Palosaari 				__func__, req->cmd, buf[2]);
103786baecfSMauro Carvalho Chehab 		ret = -EIO;
104786baecfSMauro Carvalho Chehab 		goto err;
105786baecfSMauro Carvalho Chehab 	}
106786baecfSMauro Carvalho Chehab 
107786baecfSMauro Carvalho Chehab 	/* read request, copy returned data to return buf */
108786baecfSMauro Carvalho Chehab 	if (req->rlen)
109786baecfSMauro Carvalho Chehab 		memcpy(req->rbuf, &buf[ACK_HDR_LEN], req->rlen);
110786baecfSMauro Carvalho Chehab 
111786baecfSMauro Carvalho Chehab exit:
112786baecfSMauro Carvalho Chehab 	return 0;
113786baecfSMauro Carvalho Chehab 
114786baecfSMauro Carvalho Chehab err:
115119f7a8cSAntti Palosaari 	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
116786baecfSMauro Carvalho Chehab 
117786baecfSMauro Carvalho Chehab 	return ret;
118786baecfSMauro Carvalho Chehab }
119786baecfSMauro Carvalho Chehab 
120786baecfSMauro Carvalho Chehab /* write multiple registers */
121786baecfSMauro Carvalho Chehab static int af9035_wr_regs(struct dvb_usb_device *d, u32 reg, u8 *val, int len)
122786baecfSMauro Carvalho Chehab {
123786baecfSMauro Carvalho Chehab 	u8 wbuf[6 + len];
124786baecfSMauro Carvalho Chehab 	u8 mbox = (reg >> 16) & 0xff;
125786baecfSMauro Carvalho Chehab 	struct usb_req req = { CMD_MEM_WR, mbox, sizeof(wbuf), wbuf, 0, NULL };
126786baecfSMauro Carvalho Chehab 
127786baecfSMauro Carvalho Chehab 	wbuf[0] = len;
128786baecfSMauro Carvalho Chehab 	wbuf[1] = 2;
129786baecfSMauro Carvalho Chehab 	wbuf[2] = 0;
130786baecfSMauro Carvalho Chehab 	wbuf[3] = 0;
131786baecfSMauro Carvalho Chehab 	wbuf[4] = (reg >> 8) & 0xff;
132786baecfSMauro Carvalho Chehab 	wbuf[5] = (reg >> 0) & 0xff;
133786baecfSMauro Carvalho Chehab 	memcpy(&wbuf[6], val, len);
134786baecfSMauro Carvalho Chehab 
135786baecfSMauro Carvalho Chehab 	return af9035_ctrl_msg(d, &req);
136786baecfSMauro Carvalho Chehab }
137786baecfSMauro Carvalho Chehab 
138786baecfSMauro Carvalho Chehab /* read multiple registers */
139786baecfSMauro Carvalho Chehab static int af9035_rd_regs(struct dvb_usb_device *d, u32 reg, u8 *val, int len)
140786baecfSMauro Carvalho Chehab {
141786baecfSMauro Carvalho Chehab 	u8 wbuf[] = { len, 2, 0, 0, (reg >> 8) & 0xff, reg & 0xff };
142786baecfSMauro Carvalho Chehab 	u8 mbox = (reg >> 16) & 0xff;
143786baecfSMauro Carvalho Chehab 	struct usb_req req = { CMD_MEM_RD, mbox, sizeof(wbuf), wbuf, len, val };
144786baecfSMauro Carvalho Chehab 
145786baecfSMauro Carvalho Chehab 	return af9035_ctrl_msg(d, &req);
146786baecfSMauro Carvalho Chehab }
147786baecfSMauro Carvalho Chehab 
148786baecfSMauro Carvalho Chehab /* write single register */
149786baecfSMauro Carvalho Chehab static int af9035_wr_reg(struct dvb_usb_device *d, u32 reg, u8 val)
150786baecfSMauro Carvalho Chehab {
151786baecfSMauro Carvalho Chehab 	return af9035_wr_regs(d, reg, &val, 1);
152786baecfSMauro Carvalho Chehab }
153786baecfSMauro Carvalho Chehab 
154786baecfSMauro Carvalho Chehab /* read single register */
155786baecfSMauro Carvalho Chehab static int af9035_rd_reg(struct dvb_usb_device *d, u32 reg, u8 *val)
156786baecfSMauro Carvalho Chehab {
157786baecfSMauro Carvalho Chehab 	return af9035_rd_regs(d, reg, val, 1);
158786baecfSMauro Carvalho Chehab }
159786baecfSMauro Carvalho Chehab 
160786baecfSMauro Carvalho Chehab /* write single register with mask */
161786baecfSMauro Carvalho Chehab static int af9035_wr_reg_mask(struct dvb_usb_device *d, u32 reg, u8 val,
162786baecfSMauro Carvalho Chehab 		u8 mask)
163786baecfSMauro Carvalho Chehab {
164786baecfSMauro Carvalho Chehab 	int ret;
165786baecfSMauro Carvalho Chehab 	u8 tmp;
166786baecfSMauro Carvalho Chehab 
167786baecfSMauro Carvalho Chehab 	/* no need for read if whole reg is written */
168786baecfSMauro Carvalho Chehab 	if (mask != 0xff) {
169786baecfSMauro Carvalho Chehab 		ret = af9035_rd_regs(d, reg, &tmp, 1);
170786baecfSMauro Carvalho Chehab 		if (ret)
171786baecfSMauro Carvalho Chehab 			return ret;
172786baecfSMauro Carvalho Chehab 
173786baecfSMauro Carvalho Chehab 		val &= mask;
174786baecfSMauro Carvalho Chehab 		tmp &= ~mask;
175786baecfSMauro Carvalho Chehab 		val |= tmp;
176786baecfSMauro Carvalho Chehab 	}
177786baecfSMauro Carvalho Chehab 
178786baecfSMauro Carvalho Chehab 	return af9035_wr_regs(d, reg, &val, 1);
179786baecfSMauro Carvalho Chehab }
180786baecfSMauro Carvalho Chehab 
181786baecfSMauro Carvalho Chehab static int af9035_i2c_master_xfer(struct i2c_adapter *adap,
182786baecfSMauro Carvalho Chehab 		struct i2c_msg msg[], int num)
183786baecfSMauro Carvalho Chehab {
184786baecfSMauro Carvalho Chehab 	struct dvb_usb_device *d = i2c_get_adapdata(adap);
185786baecfSMauro Carvalho Chehab 	struct state *state = d_to_priv(d);
186786baecfSMauro Carvalho Chehab 	int ret;
187786baecfSMauro Carvalho Chehab 
188786baecfSMauro Carvalho Chehab 	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
189786baecfSMauro Carvalho Chehab 		return -EAGAIN;
190786baecfSMauro Carvalho Chehab 
191786baecfSMauro Carvalho Chehab 	/*
192786baecfSMauro Carvalho Chehab 	 * I2C sub header is 5 bytes long. Meaning of those bytes are:
193786baecfSMauro Carvalho Chehab 	 * 0: data len
194786baecfSMauro Carvalho Chehab 	 * 1: I2C addr << 1
195786baecfSMauro Carvalho Chehab 	 * 2: reg addr len
196786baecfSMauro Carvalho Chehab 	 *    byte 3 and 4 can be used as reg addr
197786baecfSMauro Carvalho Chehab 	 * 3: reg addr MSB
198786baecfSMauro Carvalho Chehab 	 *    used when reg addr len is set to 2
199786baecfSMauro Carvalho Chehab 	 * 4: reg addr LSB
200786baecfSMauro Carvalho Chehab 	 *    used when reg addr len is set to 1 or 2
201786baecfSMauro Carvalho Chehab 	 *
202786baecfSMauro Carvalho Chehab 	 * For the simplify we do not use register addr at all.
203786baecfSMauro Carvalho Chehab 	 * NOTE: As a firmware knows tuner type there is very small possibility
204786baecfSMauro Carvalho Chehab 	 * there could be some tuner I2C hacks done by firmware and this may
205786baecfSMauro Carvalho Chehab 	 * lead problems if firmware expects those bytes are used.
206786baecfSMauro Carvalho Chehab 	 */
207786baecfSMauro Carvalho Chehab 	if (num == 2 && !(msg[0].flags & I2C_M_RD) &&
208786baecfSMauro Carvalho Chehab 			(msg[1].flags & I2C_M_RD)) {
209786baecfSMauro Carvalho Chehab 		if (msg[0].len > 40 || msg[1].len > 40) {
210786baecfSMauro Carvalho Chehab 			/* TODO: correct limits > 40 */
211786baecfSMauro Carvalho Chehab 			ret = -EOPNOTSUPP;
212786baecfSMauro Carvalho Chehab 		} else if (msg[0].addr == state->af9033_config[0].i2c_addr) {
213786baecfSMauro Carvalho Chehab 			/* integrated demod */
214786baecfSMauro Carvalho Chehab 			u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 |
215786baecfSMauro Carvalho Chehab 					msg[0].buf[2];
216786baecfSMauro Carvalho Chehab 			ret = af9035_rd_regs(d, reg, &msg[1].buf[0],
217786baecfSMauro Carvalho Chehab 					msg[1].len);
218786baecfSMauro Carvalho Chehab 		} else {
219786baecfSMauro Carvalho Chehab 			/* I2C */
220786baecfSMauro Carvalho Chehab 			u8 buf[5 + msg[0].len];
221786baecfSMauro Carvalho Chehab 			struct usb_req req = { CMD_I2C_RD, 0, sizeof(buf),
222786baecfSMauro Carvalho Chehab 					buf, msg[1].len, msg[1].buf };
223786baecfSMauro Carvalho Chehab 			buf[0] = msg[1].len;
224786baecfSMauro Carvalho Chehab 			buf[1] = msg[0].addr << 1;
225786baecfSMauro Carvalho Chehab 			buf[2] = 0x00; /* reg addr len */
226786baecfSMauro Carvalho Chehab 			buf[3] = 0x00; /* reg addr MSB */
227786baecfSMauro Carvalho Chehab 			buf[4] = 0x00; /* reg addr LSB */
228786baecfSMauro Carvalho Chehab 			memcpy(&buf[5], msg[0].buf, msg[0].len);
229786baecfSMauro Carvalho Chehab 			ret = af9035_ctrl_msg(d, &req);
230786baecfSMauro Carvalho Chehab 		}
231786baecfSMauro Carvalho Chehab 	} else if (num == 1 && !(msg[0].flags & I2C_M_RD)) {
232786baecfSMauro Carvalho Chehab 		if (msg[0].len > 40) {
233786baecfSMauro Carvalho Chehab 			/* TODO: correct limits > 40 */
234786baecfSMauro Carvalho Chehab 			ret = -EOPNOTSUPP;
235786baecfSMauro Carvalho Chehab 		} else if (msg[0].addr == state->af9033_config[0].i2c_addr) {
236786baecfSMauro Carvalho Chehab 			/* integrated demod */
237786baecfSMauro Carvalho Chehab 			u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 |
238786baecfSMauro Carvalho Chehab 					msg[0].buf[2];
239786baecfSMauro Carvalho Chehab 			ret = af9035_wr_regs(d, reg, &msg[0].buf[3],
240786baecfSMauro Carvalho Chehab 					msg[0].len - 3);
241786baecfSMauro Carvalho Chehab 		} else {
242786baecfSMauro Carvalho Chehab 			/* I2C */
243786baecfSMauro Carvalho Chehab 			u8 buf[5 + msg[0].len];
244786baecfSMauro Carvalho Chehab 			struct usb_req req = { CMD_I2C_WR, 0, sizeof(buf), buf,
245786baecfSMauro Carvalho Chehab 					0, NULL };
246786baecfSMauro Carvalho Chehab 			buf[0] = msg[0].len;
247786baecfSMauro Carvalho Chehab 			buf[1] = msg[0].addr << 1;
248786baecfSMauro Carvalho Chehab 			buf[2] = 0x00; /* reg addr len */
249786baecfSMauro Carvalho Chehab 			buf[3] = 0x00; /* reg addr MSB */
250786baecfSMauro Carvalho Chehab 			buf[4] = 0x00; /* reg addr LSB */
251786baecfSMauro Carvalho Chehab 			memcpy(&buf[5], msg[0].buf, msg[0].len);
252786baecfSMauro Carvalho Chehab 			ret = af9035_ctrl_msg(d, &req);
253786baecfSMauro Carvalho Chehab 		}
254786baecfSMauro Carvalho Chehab 	} else {
255786baecfSMauro Carvalho Chehab 		/*
256786baecfSMauro Carvalho Chehab 		 * We support only two kind of I2C transactions:
257786baecfSMauro Carvalho Chehab 		 * 1) 1 x read + 1 x write
258786baecfSMauro Carvalho Chehab 		 * 2) 1 x write
259786baecfSMauro Carvalho Chehab 		 */
260786baecfSMauro Carvalho Chehab 		ret = -EOPNOTSUPP;
261786baecfSMauro Carvalho Chehab 	}
262786baecfSMauro Carvalho Chehab 
263786baecfSMauro Carvalho Chehab 	mutex_unlock(&d->i2c_mutex);
264786baecfSMauro Carvalho Chehab 
265786baecfSMauro Carvalho Chehab 	if (ret < 0)
266786baecfSMauro Carvalho Chehab 		return ret;
267786baecfSMauro Carvalho Chehab 	else
268786baecfSMauro Carvalho Chehab 		return num;
269786baecfSMauro Carvalho Chehab }
270786baecfSMauro Carvalho Chehab 
271786baecfSMauro Carvalho Chehab static u32 af9035_i2c_functionality(struct i2c_adapter *adapter)
272786baecfSMauro Carvalho Chehab {
273786baecfSMauro Carvalho Chehab 	return I2C_FUNC_I2C;
274786baecfSMauro Carvalho Chehab }
275786baecfSMauro Carvalho Chehab 
276786baecfSMauro Carvalho Chehab static struct i2c_algorithm af9035_i2c_algo = {
277786baecfSMauro Carvalho Chehab 	.master_xfer = af9035_i2c_master_xfer,
278786baecfSMauro Carvalho Chehab 	.functionality = af9035_i2c_functionality,
279786baecfSMauro Carvalho Chehab };
280786baecfSMauro Carvalho Chehab 
281786baecfSMauro Carvalho Chehab static int af9035_identify_state(struct dvb_usb_device *d, const char **name)
282786baecfSMauro Carvalho Chehab {
283786baecfSMauro Carvalho Chehab 	int ret;
284786baecfSMauro Carvalho Chehab 	u8 wbuf[1] = { 1 };
285786baecfSMauro Carvalho Chehab 	u8 rbuf[4];
286786baecfSMauro Carvalho Chehab 	struct usb_req req = { CMD_FW_QUERYINFO, 0, sizeof(wbuf), wbuf,
287786baecfSMauro Carvalho Chehab 			sizeof(rbuf), rbuf };
288786baecfSMauro Carvalho Chehab 
289786baecfSMauro Carvalho Chehab 	ret = af9035_ctrl_msg(d, &req);
290786baecfSMauro Carvalho Chehab 	if (ret < 0)
291786baecfSMauro Carvalho Chehab 		goto err;
292786baecfSMauro Carvalho Chehab 
293119f7a8cSAntti Palosaari 	dev_dbg(&d->udev->dev, "%s: reply=%*ph\n", __func__, 4, rbuf);
294786baecfSMauro Carvalho Chehab 	if (rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])
295786baecfSMauro Carvalho Chehab 		ret = WARM;
296786baecfSMauro Carvalho Chehab 	else
297786baecfSMauro Carvalho Chehab 		ret = COLD;
298786baecfSMauro Carvalho Chehab 
299786baecfSMauro Carvalho Chehab 	return ret;
300786baecfSMauro Carvalho Chehab 
301786baecfSMauro Carvalho Chehab err:
302119f7a8cSAntti Palosaari 	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
303786baecfSMauro Carvalho Chehab 
304786baecfSMauro Carvalho Chehab 	return ret;
305786baecfSMauro Carvalho Chehab }
306786baecfSMauro Carvalho Chehab 
307786baecfSMauro Carvalho Chehab static int af9035_download_firmware(struct dvb_usb_device *d,
308786baecfSMauro Carvalho Chehab 		const struct firmware *fw)
309786baecfSMauro Carvalho Chehab {
310786baecfSMauro Carvalho Chehab 	int ret, i, j, len;
311786baecfSMauro Carvalho Chehab 	u8 wbuf[1];
312786baecfSMauro Carvalho Chehab 	u8 rbuf[4];
313786baecfSMauro Carvalho Chehab 	struct usb_req req = { 0, 0, 0, NULL, 0, NULL };
314786baecfSMauro Carvalho Chehab 	struct usb_req req_fw_dl = { CMD_FW_DL, 0, 0, wbuf, 0, NULL };
315786baecfSMauro Carvalho Chehab 	struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf } ;
316786baecfSMauro Carvalho Chehab 	u8 hdr_core;
317786baecfSMauro Carvalho Chehab 	u16 hdr_addr, hdr_data_len, hdr_checksum;
318786baecfSMauro Carvalho Chehab 	#define MAX_DATA 58
319786baecfSMauro Carvalho Chehab 	#define HDR_SIZE 7
320786baecfSMauro Carvalho Chehab 
321786baecfSMauro Carvalho Chehab 	/*
322786baecfSMauro Carvalho Chehab 	 * Thanks to Daniel Glöckner <daniel-gl@gmx.net> about that info!
323786baecfSMauro Carvalho Chehab 	 *
324786baecfSMauro Carvalho Chehab 	 * byte 0: MCS 51 core
325786baecfSMauro Carvalho Chehab 	 *  There are two inside the AF9035 (1=Link and 2=OFDM) with separate
326786baecfSMauro Carvalho Chehab 	 *  address spaces
327786baecfSMauro Carvalho Chehab 	 * byte 1-2: Big endian destination address
328786baecfSMauro Carvalho Chehab 	 * byte 3-4: Big endian number of data bytes following the header
329786baecfSMauro Carvalho Chehab 	 * byte 5-6: Big endian header checksum, apparently ignored by the chip
330786baecfSMauro Carvalho Chehab 	 *  Calculated as ~(h[0]*256+h[1]+h[2]*256+h[3]+h[4]*256)
331786baecfSMauro Carvalho Chehab 	 */
332786baecfSMauro Carvalho Chehab 
333786baecfSMauro Carvalho Chehab 	for (i = fw->size; i > HDR_SIZE;) {
334786baecfSMauro Carvalho Chehab 		hdr_core = fw->data[fw->size - i + 0];
335786baecfSMauro Carvalho Chehab 		hdr_addr = fw->data[fw->size - i + 1] << 8;
336786baecfSMauro Carvalho Chehab 		hdr_addr |= fw->data[fw->size - i + 2] << 0;
337786baecfSMauro Carvalho Chehab 		hdr_data_len = fw->data[fw->size - i + 3] << 8;
338786baecfSMauro Carvalho Chehab 		hdr_data_len |= fw->data[fw->size - i + 4] << 0;
339786baecfSMauro Carvalho Chehab 		hdr_checksum = fw->data[fw->size - i + 5] << 8;
340786baecfSMauro Carvalho Chehab 		hdr_checksum |= fw->data[fw->size - i + 6] << 0;
341786baecfSMauro Carvalho Chehab 
342119f7a8cSAntti Palosaari 		dev_dbg(&d->udev->dev, "%s: core=%d addr=%04x data_len=%d " \
343119f7a8cSAntti Palosaari 				"checksum=%04x\n", __func__, hdr_core, hdr_addr,
344119f7a8cSAntti Palosaari 				hdr_data_len, hdr_checksum);
345786baecfSMauro Carvalho Chehab 
346786baecfSMauro Carvalho Chehab 		if (((hdr_core != 1) && (hdr_core != 2)) ||
347786baecfSMauro Carvalho Chehab 				(hdr_data_len > i)) {
348119f7a8cSAntti Palosaari 			dev_dbg(&d->udev->dev, "%s: bad firmware\n", __func__);
349786baecfSMauro Carvalho Chehab 			break;
350786baecfSMauro Carvalho Chehab 		}
351786baecfSMauro Carvalho Chehab 
352786baecfSMauro Carvalho Chehab 		/* download begin packet */
353786baecfSMauro Carvalho Chehab 		req.cmd = CMD_FW_DL_BEGIN;
354786baecfSMauro Carvalho Chehab 		ret = af9035_ctrl_msg(d, &req);
355786baecfSMauro Carvalho Chehab 		if (ret < 0)
356786baecfSMauro Carvalho Chehab 			goto err;
357786baecfSMauro Carvalho Chehab 
358786baecfSMauro Carvalho Chehab 		/* download firmware packet(s) */
359786baecfSMauro Carvalho Chehab 		for (j = HDR_SIZE + hdr_data_len; j > 0; j -= MAX_DATA) {
360786baecfSMauro Carvalho Chehab 			len = j;
361786baecfSMauro Carvalho Chehab 			if (len > MAX_DATA)
362786baecfSMauro Carvalho Chehab 				len = MAX_DATA;
363786baecfSMauro Carvalho Chehab 			req_fw_dl.wlen = len;
364786baecfSMauro Carvalho Chehab 			req_fw_dl.wbuf = (u8 *) &fw->data[fw->size - i +
365786baecfSMauro Carvalho Chehab 					HDR_SIZE + hdr_data_len - j];
366786baecfSMauro Carvalho Chehab 			ret = af9035_ctrl_msg(d, &req_fw_dl);
367786baecfSMauro Carvalho Chehab 			if (ret < 0)
368786baecfSMauro Carvalho Chehab 				goto err;
369786baecfSMauro Carvalho Chehab 		}
370786baecfSMauro Carvalho Chehab 
371786baecfSMauro Carvalho Chehab 		/* download end packet */
372786baecfSMauro Carvalho Chehab 		req.cmd = CMD_FW_DL_END;
373786baecfSMauro Carvalho Chehab 		ret = af9035_ctrl_msg(d, &req);
374786baecfSMauro Carvalho Chehab 		if (ret < 0)
375786baecfSMauro Carvalho Chehab 			goto err;
376786baecfSMauro Carvalho Chehab 
377786baecfSMauro Carvalho Chehab 		i -= hdr_data_len + HDR_SIZE;
378786baecfSMauro Carvalho Chehab 
379119f7a8cSAntti Palosaari 		dev_dbg(&d->udev->dev, "%s: data uploaded=%zu\n",
380119f7a8cSAntti Palosaari 				__func__, fw->size - i);
381786baecfSMauro Carvalho Chehab 	}
382786baecfSMauro Carvalho Chehab 
383786baecfSMauro Carvalho Chehab 	/* firmware loaded, request boot */
384786baecfSMauro Carvalho Chehab 	req.cmd = CMD_FW_BOOT;
385786baecfSMauro Carvalho Chehab 	ret = af9035_ctrl_msg(d, &req);
386786baecfSMauro Carvalho Chehab 	if (ret < 0)
387786baecfSMauro Carvalho Chehab 		goto err;
388786baecfSMauro Carvalho Chehab 
389786baecfSMauro Carvalho Chehab 	/* ensure firmware starts */
390786baecfSMauro Carvalho Chehab 	wbuf[0] = 1;
391786baecfSMauro Carvalho Chehab 	ret = af9035_ctrl_msg(d, &req_fw_ver);
392786baecfSMauro Carvalho Chehab 	if (ret < 0)
393786baecfSMauro Carvalho Chehab 		goto err;
394786baecfSMauro Carvalho Chehab 
395786baecfSMauro Carvalho Chehab 	if (!(rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])) {
396119f7a8cSAntti Palosaari 		dev_err(&d->udev->dev, "%s: firmware did not run\n",
397119f7a8cSAntti Palosaari 				KBUILD_MODNAME);
398786baecfSMauro Carvalho Chehab 		ret = -ENODEV;
399786baecfSMauro Carvalho Chehab 		goto err;
400786baecfSMauro Carvalho Chehab 	}
401786baecfSMauro Carvalho Chehab 
402119f7a8cSAntti Palosaari 	dev_info(&d->udev->dev, "%s: firmware version=%d.%d.%d.%d",
403119f7a8cSAntti Palosaari 			KBUILD_MODNAME, rbuf[0], rbuf[1], rbuf[2], rbuf[3]);
404786baecfSMauro Carvalho Chehab 
405786baecfSMauro Carvalho Chehab 	return 0;
406786baecfSMauro Carvalho Chehab 
407786baecfSMauro Carvalho Chehab err:
408119f7a8cSAntti Palosaari 	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
409786baecfSMauro Carvalho Chehab 
410786baecfSMauro Carvalho Chehab 	return ret;
411786baecfSMauro Carvalho Chehab }
412786baecfSMauro Carvalho Chehab 
413786baecfSMauro Carvalho Chehab static int af9035_download_firmware_it9135(struct dvb_usb_device *d,
414786baecfSMauro Carvalho Chehab 		const struct firmware *fw)
415786baecfSMauro Carvalho Chehab {
416786baecfSMauro Carvalho Chehab 	int ret, i, i_prev;
417786baecfSMauro Carvalho Chehab 	u8 wbuf[1];
418786baecfSMauro Carvalho Chehab 	u8 rbuf[4];
419786baecfSMauro Carvalho Chehab 	struct usb_req req = { 0, 0, 0, NULL, 0, NULL };
420786baecfSMauro Carvalho Chehab 	struct usb_req req_fw_dl = { CMD_FW_SCATTER_WR, 0, 0, NULL, 0, NULL };
421786baecfSMauro Carvalho Chehab 	struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf } ;
422786baecfSMauro Carvalho Chehab 	#define HDR_SIZE 7
423786baecfSMauro Carvalho Chehab 
424786baecfSMauro Carvalho Chehab 	/*
425786baecfSMauro Carvalho Chehab 	 * There seems to be following firmware header. Meaning of bytes 0-3
426786baecfSMauro Carvalho Chehab 	 * is unknown.
427786baecfSMauro Carvalho Chehab 	 *
428786baecfSMauro Carvalho Chehab 	 * 0: 3
429786baecfSMauro Carvalho Chehab 	 * 1: 0, 1
430786baecfSMauro Carvalho Chehab 	 * 2: 0
431786baecfSMauro Carvalho Chehab 	 * 3: 1, 2, 3
432786baecfSMauro Carvalho Chehab 	 * 4: addr MSB
433786baecfSMauro Carvalho Chehab 	 * 5: addr LSB
434786baecfSMauro Carvalho Chehab 	 * 6: count of data bytes ?
435786baecfSMauro Carvalho Chehab 	 */
436786baecfSMauro Carvalho Chehab 
437786baecfSMauro Carvalho Chehab 	for (i = HDR_SIZE, i_prev = 0; i <= fw->size; i++) {
438786baecfSMauro Carvalho Chehab 		if (i == fw->size ||
439786baecfSMauro Carvalho Chehab 				(fw->data[i + 0] == 0x03 &&
440786baecfSMauro Carvalho Chehab 				(fw->data[i + 1] == 0x00 ||
441786baecfSMauro Carvalho Chehab 				fw->data[i + 1] == 0x01) &&
442786baecfSMauro Carvalho Chehab 				fw->data[i + 2] == 0x00)) {
443786baecfSMauro Carvalho Chehab 			req_fw_dl.wlen = i - i_prev;
444786baecfSMauro Carvalho Chehab 			req_fw_dl.wbuf = (u8 *) &fw->data[i_prev];
445786baecfSMauro Carvalho Chehab 			i_prev = i;
446786baecfSMauro Carvalho Chehab 			ret = af9035_ctrl_msg(d, &req_fw_dl);
447786baecfSMauro Carvalho Chehab 			if (ret < 0)
448786baecfSMauro Carvalho Chehab 				goto err;
449786baecfSMauro Carvalho Chehab 
450119f7a8cSAntti Palosaari 			dev_dbg(&d->udev->dev, "%s: data uploaded=%d\n",
451119f7a8cSAntti Palosaari 					__func__, i);
452786baecfSMauro Carvalho Chehab 		}
453786baecfSMauro Carvalho Chehab 	}
454786baecfSMauro Carvalho Chehab 
455786baecfSMauro Carvalho Chehab 	/* firmware loaded, request boot */
456786baecfSMauro Carvalho Chehab 	req.cmd = CMD_FW_BOOT;
457786baecfSMauro Carvalho Chehab 	ret = af9035_ctrl_msg(d, &req);
458786baecfSMauro Carvalho Chehab 	if (ret < 0)
459786baecfSMauro Carvalho Chehab 		goto err;
460786baecfSMauro Carvalho Chehab 
461786baecfSMauro Carvalho Chehab 	/* ensure firmware starts */
462786baecfSMauro Carvalho Chehab 	wbuf[0] = 1;
463786baecfSMauro Carvalho Chehab 	ret = af9035_ctrl_msg(d, &req_fw_ver);
464786baecfSMauro Carvalho Chehab 	if (ret < 0)
465786baecfSMauro Carvalho Chehab 		goto err;
466786baecfSMauro Carvalho Chehab 
467786baecfSMauro Carvalho Chehab 	if (!(rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])) {
468119f7a8cSAntti Palosaari 		dev_err(&d->udev->dev, "%s: firmware did not run\n",
469119f7a8cSAntti Palosaari 				KBUILD_MODNAME);
470786baecfSMauro Carvalho Chehab 		ret = -ENODEV;
471786baecfSMauro Carvalho Chehab 		goto err;
472786baecfSMauro Carvalho Chehab 	}
473786baecfSMauro Carvalho Chehab 
474119f7a8cSAntti Palosaari 	dev_info(&d->udev->dev, "%s: firmware version=%d.%d.%d.%d",
475119f7a8cSAntti Palosaari 			KBUILD_MODNAME, rbuf[0], rbuf[1], rbuf[2], rbuf[3]);
476786baecfSMauro Carvalho Chehab 
477786baecfSMauro Carvalho Chehab 	return 0;
478786baecfSMauro Carvalho Chehab 
479786baecfSMauro Carvalho Chehab err:
480119f7a8cSAntti Palosaari 	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
481786baecfSMauro Carvalho Chehab 
482786baecfSMauro Carvalho Chehab 	return ret;
483786baecfSMauro Carvalho Chehab }
484786baecfSMauro Carvalho Chehab 
485786baecfSMauro Carvalho Chehab static int af9035_read_config(struct dvb_usb_device *d)
486786baecfSMauro Carvalho Chehab {
487786baecfSMauro Carvalho Chehab 	struct state *state = d_to_priv(d);
488786baecfSMauro Carvalho Chehab 	int ret, i, eeprom_shift = 0;
489786baecfSMauro Carvalho Chehab 	u8 tmp;
490786baecfSMauro Carvalho Chehab 	u16 tmp16;
491786baecfSMauro Carvalho Chehab 
492786baecfSMauro Carvalho Chehab 	/* check if there is dual tuners */
493786baecfSMauro Carvalho Chehab 	ret = af9035_rd_reg(d, EEPROM_DUAL_MODE, &tmp);
494786baecfSMauro Carvalho Chehab 	if (ret < 0)
495786baecfSMauro Carvalho Chehab 		goto err;
496786baecfSMauro Carvalho Chehab 
497786baecfSMauro Carvalho Chehab 	state->dual_mode = tmp;
498119f7a8cSAntti Palosaari 	dev_dbg(&d->udev->dev, "%s: dual mode=%d\n",
499119f7a8cSAntti Palosaari 			__func__, state->dual_mode);
500786baecfSMauro Carvalho Chehab 
501786baecfSMauro Carvalho Chehab 	for (i = 0; i < state->dual_mode + 1; i++) {
502786baecfSMauro Carvalho Chehab 		/* tuner */
503786baecfSMauro Carvalho Chehab 		ret = af9035_rd_reg(d, EEPROM_1_TUNER_ID + eeprom_shift, &tmp);
504786baecfSMauro Carvalho Chehab 		if (ret < 0)
505786baecfSMauro Carvalho Chehab 			goto err;
506786baecfSMauro Carvalho Chehab 
507786baecfSMauro Carvalho Chehab 		state->af9033_config[i].tuner = tmp;
508119f7a8cSAntti Palosaari 		dev_dbg(&d->udev->dev, "%s: [%d]tuner=%02x\n",
509119f7a8cSAntti Palosaari 				__func__, i, tmp);
510786baecfSMauro Carvalho Chehab 
511786baecfSMauro Carvalho Chehab 		switch (tmp) {
512786baecfSMauro Carvalho Chehab 		case AF9033_TUNER_TUA9001:
513786baecfSMauro Carvalho Chehab 		case AF9033_TUNER_FC0011:
514786baecfSMauro Carvalho Chehab 		case AF9033_TUNER_MXL5007T:
515786baecfSMauro Carvalho Chehab 		case AF9033_TUNER_TDA18218:
516786baecfSMauro Carvalho Chehab 			state->af9033_config[i].spec_inv = 1;
517786baecfSMauro Carvalho Chehab 			break;
518786baecfSMauro Carvalho Chehab 		default:
519119f7a8cSAntti Palosaari 			dev_warn(&d->udev->dev, "%s: tuner id=%02x not " \
520119f7a8cSAntti Palosaari 					"supported, please report!",
521119f7a8cSAntti Palosaari 					KBUILD_MODNAME, tmp);
522786baecfSMauro Carvalho Chehab 		};
523786baecfSMauro Carvalho Chehab 
524786baecfSMauro Carvalho Chehab 		/* tuner IF frequency */
525786baecfSMauro Carvalho Chehab 		ret = af9035_rd_reg(d, EEPROM_1_IFFREQ_L + eeprom_shift, &tmp);
526786baecfSMauro Carvalho Chehab 		if (ret < 0)
527786baecfSMauro Carvalho Chehab 			goto err;
528786baecfSMauro Carvalho Chehab 
529786baecfSMauro Carvalho Chehab 		tmp16 = tmp;
530786baecfSMauro Carvalho Chehab 
531786baecfSMauro Carvalho Chehab 		ret = af9035_rd_reg(d, EEPROM_1_IFFREQ_H + eeprom_shift, &tmp);
532786baecfSMauro Carvalho Chehab 		if (ret < 0)
533786baecfSMauro Carvalho Chehab 			goto err;
534786baecfSMauro Carvalho Chehab 
535786baecfSMauro Carvalho Chehab 		tmp16 |= tmp << 8;
536786baecfSMauro Carvalho Chehab 
537119f7a8cSAntti Palosaari 		dev_dbg(&d->udev->dev, "%s: [%d]IF=%d\n", __func__, i, tmp16);
538786baecfSMauro Carvalho Chehab 
539786baecfSMauro Carvalho Chehab 		eeprom_shift = 0x10; /* shift for the 2nd tuner params */
540786baecfSMauro Carvalho Chehab 	}
541786baecfSMauro Carvalho Chehab 
542786baecfSMauro Carvalho Chehab 	/* get demod clock */
543786baecfSMauro Carvalho Chehab 	ret = af9035_rd_reg(d, 0x00d800, &tmp);
544786baecfSMauro Carvalho Chehab 	if (ret < 0)
545786baecfSMauro Carvalho Chehab 		goto err;
546786baecfSMauro Carvalho Chehab 
547786baecfSMauro Carvalho Chehab 	tmp = (tmp >> 0) & 0x0f;
548786baecfSMauro Carvalho Chehab 
549786baecfSMauro Carvalho Chehab 	for (i = 0; i < ARRAY_SIZE(state->af9033_config); i++)
550786baecfSMauro Carvalho Chehab 		state->af9033_config[i].clock = clock_lut[tmp];
551786baecfSMauro Carvalho Chehab 
552786baecfSMauro Carvalho Chehab 	return 0;
553786baecfSMauro Carvalho Chehab 
554786baecfSMauro Carvalho Chehab err:
555119f7a8cSAntti Palosaari 	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
556786baecfSMauro Carvalho Chehab 
557786baecfSMauro Carvalho Chehab 	return ret;
558786baecfSMauro Carvalho Chehab }
559786baecfSMauro Carvalho Chehab 
560786baecfSMauro Carvalho Chehab static int af9035_read_config_it9135(struct dvb_usb_device *d)
561786baecfSMauro Carvalho Chehab {
562786baecfSMauro Carvalho Chehab 	struct state *state = d_to_priv(d);
563786baecfSMauro Carvalho Chehab 	int ret, i;
564786baecfSMauro Carvalho Chehab 	u8 tmp;
565786baecfSMauro Carvalho Chehab 
566786baecfSMauro Carvalho Chehab 	state->dual_mode = false;
567786baecfSMauro Carvalho Chehab 
568786baecfSMauro Carvalho Chehab 	/* get demod clock */
569786baecfSMauro Carvalho Chehab 	ret = af9035_rd_reg(d, 0x00d800, &tmp);
570786baecfSMauro Carvalho Chehab 	if (ret < 0)
571786baecfSMauro Carvalho Chehab 		goto err;
572786baecfSMauro Carvalho Chehab 
573786baecfSMauro Carvalho Chehab 	tmp = (tmp >> 0) & 0x0f;
574786baecfSMauro Carvalho Chehab 
575786baecfSMauro Carvalho Chehab 	for (i = 0; i < ARRAY_SIZE(state->af9033_config); i++)
576786baecfSMauro Carvalho Chehab 		state->af9033_config[i].clock = clock_lut_it9135[tmp];
577786baecfSMauro Carvalho Chehab 
578786baecfSMauro Carvalho Chehab 	return 0;
579786baecfSMauro Carvalho Chehab 
580786baecfSMauro Carvalho Chehab err:
581119f7a8cSAntti Palosaari 	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
582786baecfSMauro Carvalho Chehab 
583786baecfSMauro Carvalho Chehab 	return ret;
584786baecfSMauro Carvalho Chehab }
585786baecfSMauro Carvalho Chehab 
58651639be3SAntti Palosaari static int af9035_tua9001_tuner_callback(struct dvb_usb_device *d,
58751639be3SAntti Palosaari 		int cmd, int arg)
58851639be3SAntti Palosaari {
58951639be3SAntti Palosaari 	int ret;
59051639be3SAntti Palosaari 	u8 val;
59151639be3SAntti Palosaari 
59251639be3SAntti Palosaari 	dev_dbg(&d->udev->dev, "%s: cmd=%d arg=%d\n", __func__, cmd, arg);
59351639be3SAntti Palosaari 
59451639be3SAntti Palosaari 	/*
59551639be3SAntti Palosaari 	 * CEN     always enabled by hardware wiring
59651639be3SAntti Palosaari 	 * RESETN  GPIOT3
59751639be3SAntti Palosaari 	 * RXEN    GPIOT2
59851639be3SAntti Palosaari 	 */
59951639be3SAntti Palosaari 
60051639be3SAntti Palosaari 	switch (cmd) {
60151639be3SAntti Palosaari 	case TUA9001_CMD_RESETN:
60251639be3SAntti Palosaari 		if (arg)
60351639be3SAntti Palosaari 			val = 0x00;
60451639be3SAntti Palosaari 		else
60551639be3SAntti Palosaari 			val = 0x01;
60651639be3SAntti Palosaari 
60751639be3SAntti Palosaari 		ret = af9035_wr_reg_mask(d, 0x00d8e7, val, 0x01);
60851639be3SAntti Palosaari 		if (ret < 0)
60951639be3SAntti Palosaari 			goto err;
61051639be3SAntti Palosaari 		break;
61151639be3SAntti Palosaari 	case TUA9001_CMD_RXEN:
61251639be3SAntti Palosaari 		if (arg)
61351639be3SAntti Palosaari 			val = 0x01;
61451639be3SAntti Palosaari 		else
61551639be3SAntti Palosaari 			val = 0x00;
61651639be3SAntti Palosaari 
61751639be3SAntti Palosaari 		ret = af9035_wr_reg_mask(d, 0x00d8eb, val, 0x01);
61851639be3SAntti Palosaari 		if (ret < 0)
61951639be3SAntti Palosaari 			goto err;
62051639be3SAntti Palosaari 		break;
62151639be3SAntti Palosaari 	}
62251639be3SAntti Palosaari 
62351639be3SAntti Palosaari 	return 0;
62451639be3SAntti Palosaari 
62551639be3SAntti Palosaari err:
62651639be3SAntti Palosaari 	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
62751639be3SAntti Palosaari 
62851639be3SAntti Palosaari 	return ret;
62951639be3SAntti Palosaari }
63051639be3SAntti Palosaari 
63151639be3SAntti Palosaari 
632786baecfSMauro Carvalho Chehab static int af9035_fc0011_tuner_callback(struct dvb_usb_device *d,
633786baecfSMauro Carvalho Chehab 		int cmd, int arg)
634786baecfSMauro Carvalho Chehab {
635786baecfSMauro Carvalho Chehab 	int ret;
636786baecfSMauro Carvalho Chehab 
637786baecfSMauro Carvalho Chehab 	switch (cmd) {
638786baecfSMauro Carvalho Chehab 	case FC0011_FE_CALLBACK_POWER:
639786baecfSMauro Carvalho Chehab 		/* Tuner enable */
640786baecfSMauro Carvalho Chehab 		ret = af9035_wr_reg_mask(d, 0xd8eb, 1, 1);
641786baecfSMauro Carvalho Chehab 		if (ret < 0)
642786baecfSMauro Carvalho Chehab 			goto err;
643786baecfSMauro Carvalho Chehab 
644786baecfSMauro Carvalho Chehab 		ret = af9035_wr_reg_mask(d, 0xd8ec, 1, 1);
645786baecfSMauro Carvalho Chehab 		if (ret < 0)
646786baecfSMauro Carvalho Chehab 			goto err;
647786baecfSMauro Carvalho Chehab 
648786baecfSMauro Carvalho Chehab 		ret = af9035_wr_reg_mask(d, 0xd8ed, 1, 1);
649786baecfSMauro Carvalho Chehab 		if (ret < 0)
650786baecfSMauro Carvalho Chehab 			goto err;
651786baecfSMauro Carvalho Chehab 
652786baecfSMauro Carvalho Chehab 		/* LED */
653786baecfSMauro Carvalho Chehab 		ret = af9035_wr_reg_mask(d, 0xd8d0, 1, 1);
654786baecfSMauro Carvalho Chehab 		if (ret < 0)
655786baecfSMauro Carvalho Chehab 			goto err;
656786baecfSMauro Carvalho Chehab 
657786baecfSMauro Carvalho Chehab 		ret = af9035_wr_reg_mask(d, 0xd8d1, 1, 1);
658786baecfSMauro Carvalho Chehab 		if (ret < 0)
659786baecfSMauro Carvalho Chehab 			goto err;
660786baecfSMauro Carvalho Chehab 
661786baecfSMauro Carvalho Chehab 		usleep_range(10000, 50000);
662786baecfSMauro Carvalho Chehab 		break;
663786baecfSMauro Carvalho Chehab 	case FC0011_FE_CALLBACK_RESET:
664786baecfSMauro Carvalho Chehab 		ret = af9035_wr_reg(d, 0xd8e9, 1);
665786baecfSMauro Carvalho Chehab 		if (ret < 0)
666786baecfSMauro Carvalho Chehab 			goto err;
667786baecfSMauro Carvalho Chehab 
668786baecfSMauro Carvalho Chehab 		ret = af9035_wr_reg(d, 0xd8e8, 1);
669786baecfSMauro Carvalho Chehab 		if (ret < 0)
670786baecfSMauro Carvalho Chehab 			goto err;
671786baecfSMauro Carvalho Chehab 
672786baecfSMauro Carvalho Chehab 		ret = af9035_wr_reg(d, 0xd8e7, 1);
673786baecfSMauro Carvalho Chehab 		if (ret < 0)
674786baecfSMauro Carvalho Chehab 			goto err;
675786baecfSMauro Carvalho Chehab 
676786baecfSMauro Carvalho Chehab 		usleep_range(10000, 20000);
677786baecfSMauro Carvalho Chehab 
678786baecfSMauro Carvalho Chehab 		ret = af9035_wr_reg(d, 0xd8e7, 0);
679786baecfSMauro Carvalho Chehab 		if (ret < 0)
680786baecfSMauro Carvalho Chehab 			goto err;
681786baecfSMauro Carvalho Chehab 
682786baecfSMauro Carvalho Chehab 		usleep_range(10000, 20000);
683786baecfSMauro Carvalho Chehab 		break;
684786baecfSMauro Carvalho Chehab 	default:
685786baecfSMauro Carvalho Chehab 		ret = -EINVAL;
686786baecfSMauro Carvalho Chehab 		goto err;
687786baecfSMauro Carvalho Chehab 	}
688786baecfSMauro Carvalho Chehab 
689786baecfSMauro Carvalho Chehab 	return 0;
690786baecfSMauro Carvalho Chehab 
691786baecfSMauro Carvalho Chehab err:
692119f7a8cSAntti Palosaari 	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
693786baecfSMauro Carvalho Chehab 
694786baecfSMauro Carvalho Chehab 	return ret;
695786baecfSMauro Carvalho Chehab }
696786baecfSMauro Carvalho Chehab 
697786baecfSMauro Carvalho Chehab static int af9035_tuner_callback(struct dvb_usb_device *d, int cmd, int arg)
698786baecfSMauro Carvalho Chehab {
699786baecfSMauro Carvalho Chehab 	struct state *state = d_to_priv(d);
700786baecfSMauro Carvalho Chehab 
701786baecfSMauro Carvalho Chehab 	switch (state->af9033_config[0].tuner) {
702786baecfSMauro Carvalho Chehab 	case AF9033_TUNER_FC0011:
703786baecfSMauro Carvalho Chehab 		return af9035_fc0011_tuner_callback(d, cmd, arg);
70451639be3SAntti Palosaari 	case AF9033_TUNER_TUA9001:
70551639be3SAntti Palosaari 		return af9035_tua9001_tuner_callback(d, cmd, arg);
706786baecfSMauro Carvalho Chehab 	default:
707786baecfSMauro Carvalho Chehab 		break;
708786baecfSMauro Carvalho Chehab 	}
709786baecfSMauro Carvalho Chehab 
7101835af10SAntti Palosaari 	return 0;
711786baecfSMauro Carvalho Chehab }
712786baecfSMauro Carvalho Chehab 
713786baecfSMauro Carvalho Chehab static int af9035_frontend_callback(void *adapter_priv, int component,
714786baecfSMauro Carvalho Chehab 				    int cmd, int arg)
715786baecfSMauro Carvalho Chehab {
716786baecfSMauro Carvalho Chehab 	struct i2c_adapter *adap = adapter_priv;
717786baecfSMauro Carvalho Chehab 	struct dvb_usb_device *d = i2c_get_adapdata(adap);
718786baecfSMauro Carvalho Chehab 
7191835af10SAntti Palosaari 	dev_dbg(&d->udev->dev, "%s: component=%d cmd=%d arg=%d\n",
7201835af10SAntti Palosaari 			__func__, component, cmd, arg);
7211835af10SAntti Palosaari 
722786baecfSMauro Carvalho Chehab 	switch (component) {
723786baecfSMauro Carvalho Chehab 	case DVB_FRONTEND_COMPONENT_TUNER:
724786baecfSMauro Carvalho Chehab 		return af9035_tuner_callback(d, cmd, arg);
725786baecfSMauro Carvalho Chehab 	default:
726786baecfSMauro Carvalho Chehab 		break;
727786baecfSMauro Carvalho Chehab 	}
728786baecfSMauro Carvalho Chehab 
7291835af10SAntti Palosaari 	return 0;
730786baecfSMauro Carvalho Chehab }
731786baecfSMauro Carvalho Chehab 
732786baecfSMauro Carvalho Chehab static int af9035_frontend_attach(struct dvb_usb_adapter *adap)
733786baecfSMauro Carvalho Chehab {
734786baecfSMauro Carvalho Chehab 	struct state *state = adap_to_priv(adap);
735786baecfSMauro Carvalho Chehab 	struct dvb_usb_device *d = adap_to_d(adap);
736786baecfSMauro Carvalho Chehab 	int ret;
737786baecfSMauro Carvalho Chehab 
738786baecfSMauro Carvalho Chehab 	if (!state->af9033_config[adap->id].tuner) {
739786baecfSMauro Carvalho Chehab 		/* unsupported tuner */
740786baecfSMauro Carvalho Chehab 		ret = -ENODEV;
741786baecfSMauro Carvalho Chehab 		goto err;
742786baecfSMauro Carvalho Chehab 	}
743786baecfSMauro Carvalho Chehab 
744786baecfSMauro Carvalho Chehab 	if (adap->id == 0) {
745786baecfSMauro Carvalho Chehab 		state->af9033_config[0].ts_mode = AF9033_TS_MODE_USB;
746786baecfSMauro Carvalho Chehab 		state->af9033_config[1].ts_mode = AF9033_TS_MODE_SERIAL;
747786baecfSMauro Carvalho Chehab 
748786baecfSMauro Carvalho Chehab 		ret = af9035_wr_reg(d, 0x00417f,
749786baecfSMauro Carvalho Chehab 				state->af9033_config[1].i2c_addr);
750786baecfSMauro Carvalho Chehab 		if (ret < 0)
751786baecfSMauro Carvalho Chehab 			goto err;
752786baecfSMauro Carvalho Chehab 
753786baecfSMauro Carvalho Chehab 		ret = af9035_wr_reg(d, 0x00d81a,
754786baecfSMauro Carvalho Chehab 				state->dual_mode);
755786baecfSMauro Carvalho Chehab 		if (ret < 0)
756786baecfSMauro Carvalho Chehab 			goto err;
757786baecfSMauro Carvalho Chehab 	}
758786baecfSMauro Carvalho Chehab 
759786baecfSMauro Carvalho Chehab 	/* attach demodulator */
760786baecfSMauro Carvalho Chehab 	adap->fe[0] = dvb_attach(af9033_attach,
761786baecfSMauro Carvalho Chehab 			&state->af9033_config[adap->id], &d->i2c_adap);
762786baecfSMauro Carvalho Chehab 	if (adap->fe[0] == NULL) {
763786baecfSMauro Carvalho Chehab 		ret = -ENODEV;
764786baecfSMauro Carvalho Chehab 		goto err;
765786baecfSMauro Carvalho Chehab 	}
766786baecfSMauro Carvalho Chehab 
767786baecfSMauro Carvalho Chehab 	/* disable I2C-gate */
768786baecfSMauro Carvalho Chehab 	adap->fe[0]->ops.i2c_gate_ctrl = NULL;
769786baecfSMauro Carvalho Chehab 	adap->fe[0]->callback = af9035_frontend_callback;
770786baecfSMauro Carvalho Chehab 
771786baecfSMauro Carvalho Chehab 	return 0;
772786baecfSMauro Carvalho Chehab 
773786baecfSMauro Carvalho Chehab err:
774119f7a8cSAntti Palosaari 	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
775786baecfSMauro Carvalho Chehab 
776786baecfSMauro Carvalho Chehab 	return ret;
777786baecfSMauro Carvalho Chehab }
778786baecfSMauro Carvalho Chehab 
779786baecfSMauro Carvalho Chehab static struct tua9001_config af9035_tua9001_config = {
780786baecfSMauro Carvalho Chehab 	.i2c_addr = 0x60,
781786baecfSMauro Carvalho Chehab };
782786baecfSMauro Carvalho Chehab 
783786baecfSMauro Carvalho Chehab static const struct fc0011_config af9035_fc0011_config = {
784786baecfSMauro Carvalho Chehab 	.i2c_address = 0x60,
785786baecfSMauro Carvalho Chehab };
786786baecfSMauro Carvalho Chehab 
787786baecfSMauro Carvalho Chehab static struct mxl5007t_config af9035_mxl5007t_config = {
788786baecfSMauro Carvalho Chehab 	.xtal_freq_hz = MxL_XTAL_24_MHZ,
789786baecfSMauro Carvalho Chehab 	.if_freq_hz = MxL_IF_4_57_MHZ,
790786baecfSMauro Carvalho Chehab 	.invert_if = 0,
791786baecfSMauro Carvalho Chehab 	.loop_thru_enable = 0,
792786baecfSMauro Carvalho Chehab 	.clk_out_enable = 0,
793786baecfSMauro Carvalho Chehab 	.clk_out_amp = MxL_CLKOUT_AMP_0_94V,
794786baecfSMauro Carvalho Chehab };
795786baecfSMauro Carvalho Chehab 
796786baecfSMauro Carvalho Chehab static struct tda18218_config af9035_tda18218_config = {
797786baecfSMauro Carvalho Chehab 	.i2c_address = 0x60,
798786baecfSMauro Carvalho Chehab 	.i2c_wr_max = 21,
799786baecfSMauro Carvalho Chehab };
800786baecfSMauro Carvalho Chehab 
801786baecfSMauro Carvalho Chehab static int af9035_tuner_attach(struct dvb_usb_adapter *adap)
802786baecfSMauro Carvalho Chehab {
803786baecfSMauro Carvalho Chehab 	struct state *state = adap_to_priv(adap);
804786baecfSMauro Carvalho Chehab 	struct dvb_usb_device *d = adap_to_d(adap);
805786baecfSMauro Carvalho Chehab 	int ret;
806786baecfSMauro Carvalho Chehab 	struct dvb_frontend *fe;
807786baecfSMauro Carvalho Chehab 
808786baecfSMauro Carvalho Chehab 	switch (state->af9033_config[adap->id].tuner) {
809786baecfSMauro Carvalho Chehab 	case AF9033_TUNER_TUA9001:
810786baecfSMauro Carvalho Chehab 		/* AF9035 gpiot3 = TUA9001 RESETN
811786baecfSMauro Carvalho Chehab 		   AF9035 gpiot2 = TUA9001 RXEN */
812786baecfSMauro Carvalho Chehab 
813786baecfSMauro Carvalho Chehab 		/* configure gpiot2 and gpiot2 as output */
814786baecfSMauro Carvalho Chehab 		ret = af9035_wr_reg_mask(d, 0x00d8ec, 0x01, 0x01);
815786baecfSMauro Carvalho Chehab 		if (ret < 0)
816786baecfSMauro Carvalho Chehab 			goto err;
817786baecfSMauro Carvalho Chehab 
818786baecfSMauro Carvalho Chehab 		ret = af9035_wr_reg_mask(d, 0x00d8ed, 0x01, 0x01);
819786baecfSMauro Carvalho Chehab 		if (ret < 0)
820786baecfSMauro Carvalho Chehab 			goto err;
821786baecfSMauro Carvalho Chehab 
822786baecfSMauro Carvalho Chehab 		ret = af9035_wr_reg_mask(d, 0x00d8e8, 0x01, 0x01);
823786baecfSMauro Carvalho Chehab 		if (ret < 0)
824786baecfSMauro Carvalho Chehab 			goto err;
825786baecfSMauro Carvalho Chehab 
826786baecfSMauro Carvalho Chehab 		ret = af9035_wr_reg_mask(d, 0x00d8e9, 0x01, 0x01);
827786baecfSMauro Carvalho Chehab 		if (ret < 0)
828786baecfSMauro Carvalho Chehab 			goto err;
829786baecfSMauro Carvalho Chehab 
830786baecfSMauro Carvalho Chehab 		/* attach tuner */
831786baecfSMauro Carvalho Chehab 		fe = dvb_attach(tua9001_attach, adap->fe[0],
832786baecfSMauro Carvalho Chehab 				&d->i2c_adap, &af9035_tua9001_config);
833786baecfSMauro Carvalho Chehab 		break;
834786baecfSMauro Carvalho Chehab 	case AF9033_TUNER_FC0011:
835786baecfSMauro Carvalho Chehab 		fe = dvb_attach(fc0011_attach, adap->fe[0],
836786baecfSMauro Carvalho Chehab 				&d->i2c_adap, &af9035_fc0011_config);
837786baecfSMauro Carvalho Chehab 		break;
838786baecfSMauro Carvalho Chehab 	case AF9033_TUNER_MXL5007T:
839786baecfSMauro Carvalho Chehab 		ret = af9035_wr_reg(d, 0x00d8e0, 1);
840786baecfSMauro Carvalho Chehab 		if (ret < 0)
841786baecfSMauro Carvalho Chehab 			goto err;
842786baecfSMauro Carvalho Chehab 		ret = af9035_wr_reg(d, 0x00d8e1, 1);
843786baecfSMauro Carvalho Chehab 		if (ret < 0)
844786baecfSMauro Carvalho Chehab 			goto err;
845786baecfSMauro Carvalho Chehab 		ret = af9035_wr_reg(d, 0x00d8df, 0);
846786baecfSMauro Carvalho Chehab 		if (ret < 0)
847786baecfSMauro Carvalho Chehab 			goto err;
848786baecfSMauro Carvalho Chehab 
849786baecfSMauro Carvalho Chehab 		msleep(30);
850786baecfSMauro Carvalho Chehab 
851786baecfSMauro Carvalho Chehab 		ret = af9035_wr_reg(d, 0x00d8df, 1);
852786baecfSMauro Carvalho Chehab 		if (ret < 0)
853786baecfSMauro Carvalho Chehab 			goto err;
854786baecfSMauro Carvalho Chehab 
855786baecfSMauro Carvalho Chehab 		msleep(300);
856786baecfSMauro Carvalho Chehab 
857786baecfSMauro Carvalho Chehab 		ret = af9035_wr_reg(d, 0x00d8c0, 1);
858786baecfSMauro Carvalho Chehab 		if (ret < 0)
859786baecfSMauro Carvalho Chehab 			goto err;
860786baecfSMauro Carvalho Chehab 		ret = af9035_wr_reg(d, 0x00d8c1, 1);
861786baecfSMauro Carvalho Chehab 		if (ret < 0)
862786baecfSMauro Carvalho Chehab 			goto err;
863786baecfSMauro Carvalho Chehab 		ret = af9035_wr_reg(d, 0x00d8bf, 0);
864786baecfSMauro Carvalho Chehab 		if (ret < 0)
865786baecfSMauro Carvalho Chehab 			goto err;
866786baecfSMauro Carvalho Chehab 		ret = af9035_wr_reg(d, 0x00d8b4, 1);
867786baecfSMauro Carvalho Chehab 		if (ret < 0)
868786baecfSMauro Carvalho Chehab 			goto err;
869786baecfSMauro Carvalho Chehab 		ret = af9035_wr_reg(d, 0x00d8b5, 1);
870786baecfSMauro Carvalho Chehab 		if (ret < 0)
871786baecfSMauro Carvalho Chehab 			goto err;
872786baecfSMauro Carvalho Chehab 		ret = af9035_wr_reg(d, 0x00d8b3, 1);
873786baecfSMauro Carvalho Chehab 		if (ret < 0)
874786baecfSMauro Carvalho Chehab 			goto err;
875786baecfSMauro Carvalho Chehab 
876786baecfSMauro Carvalho Chehab 		/* attach tuner */
877786baecfSMauro Carvalho Chehab 		fe = dvb_attach(mxl5007t_attach, adap->fe[0],
878786baecfSMauro Carvalho Chehab 				&d->i2c_adap, 0x60, &af9035_mxl5007t_config);
879786baecfSMauro Carvalho Chehab 		break;
880786baecfSMauro Carvalho Chehab 	case AF9033_TUNER_TDA18218:
881786baecfSMauro Carvalho Chehab 		/* attach tuner */
882786baecfSMauro Carvalho Chehab 		fe = dvb_attach(tda18218_attach, adap->fe[0],
883786baecfSMauro Carvalho Chehab 				&d->i2c_adap, &af9035_tda18218_config);
884786baecfSMauro Carvalho Chehab 		break;
885786baecfSMauro Carvalho Chehab 	default:
886786baecfSMauro Carvalho Chehab 		fe = NULL;
887786baecfSMauro Carvalho Chehab 	}
888786baecfSMauro Carvalho Chehab 
889786baecfSMauro Carvalho Chehab 	if (fe == NULL) {
890786baecfSMauro Carvalho Chehab 		ret = -ENODEV;
891786baecfSMauro Carvalho Chehab 		goto err;
892786baecfSMauro Carvalho Chehab 	}
893786baecfSMauro Carvalho Chehab 
894786baecfSMauro Carvalho Chehab 	return 0;
895786baecfSMauro Carvalho Chehab 
896786baecfSMauro Carvalho Chehab err:
897119f7a8cSAntti Palosaari 	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
898786baecfSMauro Carvalho Chehab 
899786baecfSMauro Carvalho Chehab 	return ret;
900786baecfSMauro Carvalho Chehab }
901786baecfSMauro Carvalho Chehab 
902786baecfSMauro Carvalho Chehab static int af9035_init(struct dvb_usb_device *d)
903786baecfSMauro Carvalho Chehab {
904786baecfSMauro Carvalho Chehab 	struct state *state = d_to_priv(d);
905786baecfSMauro Carvalho Chehab 	int ret, i;
906786baecfSMauro Carvalho Chehab 	u16 frame_size = 87 * 188 / 4;
907786baecfSMauro Carvalho Chehab 	u8  packet_size = 512 / 4;
908786baecfSMauro Carvalho Chehab 	struct reg_val_mask tab[] = {
909786baecfSMauro Carvalho Chehab 		{ 0x80f99d, 0x01, 0x01 },
910786baecfSMauro Carvalho Chehab 		{ 0x80f9a4, 0x01, 0x01 },
911786baecfSMauro Carvalho Chehab 		{ 0x00dd11, 0x00, 0x20 },
912786baecfSMauro Carvalho Chehab 		{ 0x00dd11, 0x00, 0x40 },
913786baecfSMauro Carvalho Chehab 		{ 0x00dd13, 0x00, 0x20 },
914786baecfSMauro Carvalho Chehab 		{ 0x00dd13, 0x00, 0x40 },
915786baecfSMauro Carvalho Chehab 		{ 0x00dd11, 0x20, 0x20 },
916786baecfSMauro Carvalho Chehab 		{ 0x00dd88, (frame_size >> 0) & 0xff, 0xff},
917786baecfSMauro Carvalho Chehab 		{ 0x00dd89, (frame_size >> 8) & 0xff, 0xff},
918786baecfSMauro Carvalho Chehab 		{ 0x00dd0c, packet_size, 0xff},
919786baecfSMauro Carvalho Chehab 		{ 0x00dd11, state->dual_mode << 6, 0x40 },
920786baecfSMauro Carvalho Chehab 		{ 0x00dd8a, (frame_size >> 0) & 0xff, 0xff},
921786baecfSMauro Carvalho Chehab 		{ 0x00dd8b, (frame_size >> 8) & 0xff, 0xff},
922786baecfSMauro Carvalho Chehab 		{ 0x00dd0d, packet_size, 0xff },
923786baecfSMauro Carvalho Chehab 		{ 0x80f9a3, 0x00, 0x01 },
924786baecfSMauro Carvalho Chehab 		{ 0x80f9cd, 0x00, 0x01 },
925786baecfSMauro Carvalho Chehab 		{ 0x80f99d, 0x00, 0x01 },
926786baecfSMauro Carvalho Chehab 		{ 0x80f9a4, 0x00, 0x01 },
927786baecfSMauro Carvalho Chehab 	};
928786baecfSMauro Carvalho Chehab 
929119f7a8cSAntti Palosaari 	dev_dbg(&d->udev->dev, "%s: USB speed=%d frame_size=%04x " \
930119f7a8cSAntti Palosaari 			"packet_size=%02x\n", __func__,
931119f7a8cSAntti Palosaari 			d->udev->speed, frame_size, packet_size);
932786baecfSMauro Carvalho Chehab 
933786baecfSMauro Carvalho Chehab 	/* init endpoints */
934786baecfSMauro Carvalho Chehab 	for (i = 0; i < ARRAY_SIZE(tab); i++) {
935786baecfSMauro Carvalho Chehab 		ret = af9035_wr_reg_mask(d, tab[i].reg, tab[i].val,
936786baecfSMauro Carvalho Chehab 				tab[i].mask);
937786baecfSMauro Carvalho Chehab 		if (ret < 0)
938786baecfSMauro Carvalho Chehab 			goto err;
939786baecfSMauro Carvalho Chehab 	}
940786baecfSMauro Carvalho Chehab 
941786baecfSMauro Carvalho Chehab 	return 0;
942786baecfSMauro Carvalho Chehab 
943786baecfSMauro Carvalho Chehab err:
944119f7a8cSAntti Palosaari 	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
945786baecfSMauro Carvalho Chehab 
946786baecfSMauro Carvalho Chehab 	return ret;
947786baecfSMauro Carvalho Chehab }
948786baecfSMauro Carvalho Chehab 
949786baecfSMauro Carvalho Chehab static int af9035_rc_query(struct dvb_usb_device *d)
950786baecfSMauro Carvalho Chehab {
951786baecfSMauro Carvalho Chehab 	unsigned int key;
952786baecfSMauro Carvalho Chehab 	unsigned char b[4];
953786baecfSMauro Carvalho Chehab 	int ret;
954786baecfSMauro Carvalho Chehab 	struct usb_req req = { CMD_IR_GET, 0, 0, NULL, 4, b };
955786baecfSMauro Carvalho Chehab 
956786baecfSMauro Carvalho Chehab 	ret = af9035_ctrl_msg(d, &req);
957786baecfSMauro Carvalho Chehab 	if (ret < 0)
958786baecfSMauro Carvalho Chehab 		goto err;
959786baecfSMauro Carvalho Chehab 
960786baecfSMauro Carvalho Chehab 	if ((b[2] + b[3]) == 0xff) {
961786baecfSMauro Carvalho Chehab 		if ((b[0] + b[1]) == 0xff) {
962786baecfSMauro Carvalho Chehab 			/* NEC */
963786baecfSMauro Carvalho Chehab 			key = b[0] << 8 | b[2];
964786baecfSMauro Carvalho Chehab 		} else {
965786baecfSMauro Carvalho Chehab 			/* ext. NEC */
966786baecfSMauro Carvalho Chehab 			key = b[0] << 16 | b[1] << 8 | b[2];
967786baecfSMauro Carvalho Chehab 		}
968786baecfSMauro Carvalho Chehab 	} else {
969786baecfSMauro Carvalho Chehab 		key = b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3];
970786baecfSMauro Carvalho Chehab 	}
971786baecfSMauro Carvalho Chehab 
972786baecfSMauro Carvalho Chehab 	rc_keydown(d->rc_dev, key, 0);
973786baecfSMauro Carvalho Chehab 
974786baecfSMauro Carvalho Chehab err:
975786baecfSMauro Carvalho Chehab 	/* ignore errors */
976786baecfSMauro Carvalho Chehab 	return 0;
977786baecfSMauro Carvalho Chehab }
978786baecfSMauro Carvalho Chehab 
979786baecfSMauro Carvalho Chehab static int af9035_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
980786baecfSMauro Carvalho Chehab {
981786baecfSMauro Carvalho Chehab 	int ret;
982786baecfSMauro Carvalho Chehab 	u8 tmp;
983786baecfSMauro Carvalho Chehab 
984786baecfSMauro Carvalho Chehab 	ret = af9035_rd_reg(d, EEPROM_IR_MODE, &tmp);
985786baecfSMauro Carvalho Chehab 	if (ret < 0)
986786baecfSMauro Carvalho Chehab 		goto err;
987786baecfSMauro Carvalho Chehab 
988119f7a8cSAntti Palosaari 	dev_dbg(&d->udev->dev, "%s: ir_mode=%02x\n", __func__, tmp);
989786baecfSMauro Carvalho Chehab 
990786baecfSMauro Carvalho Chehab 	/* don't activate rc if in HID mode or if not available */
991786baecfSMauro Carvalho Chehab 	if (tmp == 5) {
992786baecfSMauro Carvalho Chehab 		ret = af9035_rd_reg(d, EEPROM_IR_TYPE, &tmp);
993786baecfSMauro Carvalho Chehab 		if (ret < 0)
994786baecfSMauro Carvalho Chehab 			goto err;
995786baecfSMauro Carvalho Chehab 
996119f7a8cSAntti Palosaari 		dev_dbg(&d->udev->dev, "%s: ir_type=%02x\n", __func__, tmp);
997786baecfSMauro Carvalho Chehab 
998786baecfSMauro Carvalho Chehab 		switch (tmp) {
999786baecfSMauro Carvalho Chehab 		case 0: /* NEC */
1000786baecfSMauro Carvalho Chehab 		default:
1001786baecfSMauro Carvalho Chehab 			rc->allowed_protos = RC_TYPE_NEC;
1002786baecfSMauro Carvalho Chehab 			break;
1003786baecfSMauro Carvalho Chehab 		case 1: /* RC6 */
1004786baecfSMauro Carvalho Chehab 			rc->allowed_protos = RC_TYPE_RC6;
1005786baecfSMauro Carvalho Chehab 			break;
1006786baecfSMauro Carvalho Chehab 		}
1007786baecfSMauro Carvalho Chehab 
1008786baecfSMauro Carvalho Chehab 		rc->query = af9035_rc_query;
1009786baecfSMauro Carvalho Chehab 		rc->interval = 500;
1010786baecfSMauro Carvalho Chehab 
1011786baecfSMauro Carvalho Chehab 		/* load empty to enable rc */
1012786baecfSMauro Carvalho Chehab 		if (!rc->map_name)
1013786baecfSMauro Carvalho Chehab 			rc->map_name = RC_MAP_EMPTY;
1014786baecfSMauro Carvalho Chehab 	}
1015786baecfSMauro Carvalho Chehab 
1016786baecfSMauro Carvalho Chehab 	return 0;
1017786baecfSMauro Carvalho Chehab 
1018786baecfSMauro Carvalho Chehab err:
1019119f7a8cSAntti Palosaari 	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
1020786baecfSMauro Carvalho Chehab 
1021786baecfSMauro Carvalho Chehab 	return ret;
1022786baecfSMauro Carvalho Chehab }
1023786baecfSMauro Carvalho Chehab 
1024786baecfSMauro Carvalho Chehab /* interface 0 is used by DVB-T receiver and
1025786baecfSMauro Carvalho Chehab    interface 1 is for remote controller (HID) */
1026786baecfSMauro Carvalho Chehab static const struct dvb_usb_device_properties af9035_props = {
1027786baecfSMauro Carvalho Chehab 	.driver_name = KBUILD_MODNAME,
1028786baecfSMauro Carvalho Chehab 	.owner = THIS_MODULE,
1029786baecfSMauro Carvalho Chehab 	.adapter_nr = adapter_nr,
1030786baecfSMauro Carvalho Chehab 	.size_of_priv = sizeof(struct state),
1031786baecfSMauro Carvalho Chehab 
1032786baecfSMauro Carvalho Chehab 	.generic_bulk_ctrl_endpoint = 0x02,
1033786baecfSMauro Carvalho Chehab 	.generic_bulk_ctrl_endpoint_response = 0x81,
1034786baecfSMauro Carvalho Chehab 
1035786baecfSMauro Carvalho Chehab 	.identify_state = af9035_identify_state,
1036786baecfSMauro Carvalho Chehab 	.firmware = "dvb-usb-af9035-02.fw",
1037786baecfSMauro Carvalho Chehab 	.download_firmware = af9035_download_firmware,
1038786baecfSMauro Carvalho Chehab 
1039786baecfSMauro Carvalho Chehab 	.i2c_algo = &af9035_i2c_algo,
1040786baecfSMauro Carvalho Chehab 	.read_config = af9035_read_config,
1041786baecfSMauro Carvalho Chehab 	.frontend_attach = af9035_frontend_attach,
1042786baecfSMauro Carvalho Chehab 	.tuner_attach = af9035_tuner_attach,
1043786baecfSMauro Carvalho Chehab 	.init = af9035_init,
1044786baecfSMauro Carvalho Chehab 	.get_rc_config = af9035_get_rc_config,
1045786baecfSMauro Carvalho Chehab 
1046786baecfSMauro Carvalho Chehab 	.num_adapters = 1,
1047786baecfSMauro Carvalho Chehab 	.adapter = {
1048786baecfSMauro Carvalho Chehab 		{
1049786baecfSMauro Carvalho Chehab 			.stream = DVB_USB_STREAM_BULK(0x84, 6, 87 * 188),
1050786baecfSMauro Carvalho Chehab 		}, {
1051786baecfSMauro Carvalho Chehab 			.stream = DVB_USB_STREAM_BULK(0x85, 6, 87 * 188),
1052786baecfSMauro Carvalho Chehab 		},
1053786baecfSMauro Carvalho Chehab 	},
1054786baecfSMauro Carvalho Chehab };
1055786baecfSMauro Carvalho Chehab 
1056786baecfSMauro Carvalho Chehab static const struct dvb_usb_device_properties it9135_props = {
1057786baecfSMauro Carvalho Chehab 	.driver_name = KBUILD_MODNAME,
1058786baecfSMauro Carvalho Chehab 	.owner = THIS_MODULE,
1059786baecfSMauro Carvalho Chehab 	.adapter_nr = adapter_nr,
1060786baecfSMauro Carvalho Chehab 	.size_of_priv = sizeof(struct state),
1061786baecfSMauro Carvalho Chehab 
1062786baecfSMauro Carvalho Chehab 	.generic_bulk_ctrl_endpoint = 0x02,
1063786baecfSMauro Carvalho Chehab 	.generic_bulk_ctrl_endpoint_response = 0x81,
1064786baecfSMauro Carvalho Chehab 
1065786baecfSMauro Carvalho Chehab 	.identify_state = af9035_identify_state,
1066786baecfSMauro Carvalho Chehab 	.firmware = "dvb-usb-it9135-01.fw",
1067786baecfSMauro Carvalho Chehab 	.download_firmware = af9035_download_firmware_it9135,
1068786baecfSMauro Carvalho Chehab 
1069786baecfSMauro Carvalho Chehab 	.i2c_algo = &af9035_i2c_algo,
1070786baecfSMauro Carvalho Chehab 	.read_config = af9035_read_config_it9135,
1071786baecfSMauro Carvalho Chehab 	.frontend_attach = af9035_frontend_attach,
1072786baecfSMauro Carvalho Chehab 	.tuner_attach = af9035_tuner_attach,
1073786baecfSMauro Carvalho Chehab 	.init = af9035_init,
1074786baecfSMauro Carvalho Chehab 	.get_rc_config = af9035_get_rc_config,
1075786baecfSMauro Carvalho Chehab 
1076786baecfSMauro Carvalho Chehab 	.num_adapters = 1,
1077786baecfSMauro Carvalho Chehab 	.adapter = {
1078786baecfSMauro Carvalho Chehab 		{
1079786baecfSMauro Carvalho Chehab 			.stream = DVB_USB_STREAM_BULK(0x84, 6, 87 * 188),
1080786baecfSMauro Carvalho Chehab 		}, {
1081786baecfSMauro Carvalho Chehab 			.stream = DVB_USB_STREAM_BULK(0x85, 6, 87 * 188),
1082786baecfSMauro Carvalho Chehab 		},
1083786baecfSMauro Carvalho Chehab 	},
1084786baecfSMauro Carvalho Chehab };
1085786baecfSMauro Carvalho Chehab 
1086786baecfSMauro Carvalho Chehab static const struct usb_device_id af9035_id_table[] = {
1087786baecfSMauro Carvalho Chehab 	{ DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_9035,
1088786baecfSMauro Carvalho Chehab 		&af9035_props, "Afatech AF9035 reference design", NULL) },
1089786baecfSMauro Carvalho Chehab 	{ DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1000,
1090786baecfSMauro Carvalho Chehab 		&af9035_props, "Afatech AF9035 reference design", NULL) },
1091786baecfSMauro Carvalho Chehab 	{ DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1001,
1092786baecfSMauro Carvalho Chehab 		&af9035_props, "Afatech AF9035 reference design", NULL) },
1093786baecfSMauro Carvalho Chehab 	{ DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1002,
1094786baecfSMauro Carvalho Chehab 		&af9035_props, "Afatech AF9035 reference design", NULL) },
1095786baecfSMauro Carvalho Chehab 	{ DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1003,
1096786baecfSMauro Carvalho Chehab 		&af9035_props, "Afatech AF9035 reference design", NULL) },
1097786baecfSMauro Carvalho Chehab 	{ DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK,
1098786baecfSMauro Carvalho Chehab 		&af9035_props, "TerraTec Cinergy T Stick", NULL) },
1099786baecfSMauro Carvalho Chehab 	{ DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835,
1100786baecfSMauro Carvalho Chehab 		&af9035_props, "AVerMedia AVerTV Volar HD/PRO (A835)", NULL) },
1101786baecfSMauro Carvalho Chehab 	{ DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_B835,
1102786baecfSMauro Carvalho Chehab 		&af9035_props, "AVerMedia AVerTV Volar HD/PRO (A835)", NULL) },
1103786baecfSMauro Carvalho Chehab 	{ DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_1867,
1104786baecfSMauro Carvalho Chehab 		&af9035_props, "AVerMedia HD Volar (A867)", NULL) },
1105786baecfSMauro Carvalho Chehab 	{ DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A867,
1106786baecfSMauro Carvalho Chehab 		&af9035_props, "AVerMedia HD Volar (A867)", NULL) },
1107786baecfSMauro Carvalho Chehab 	{ DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_TWINSTAR,
1108786baecfSMauro Carvalho Chehab 		&af9035_props, "AVerMedia Twinstar (A825)", NULL) },
1109786baecfSMauro Carvalho Chehab 	{ }
1110786baecfSMauro Carvalho Chehab };
1111786baecfSMauro Carvalho Chehab MODULE_DEVICE_TABLE(usb, af9035_id_table);
1112786baecfSMauro Carvalho Chehab 
1113786baecfSMauro Carvalho Chehab static struct usb_driver af9035_usb_driver = {
1114786baecfSMauro Carvalho Chehab 	.name = KBUILD_MODNAME,
1115786baecfSMauro Carvalho Chehab 	.id_table = af9035_id_table,
1116786baecfSMauro Carvalho Chehab 	.probe = dvb_usbv2_probe,
1117786baecfSMauro Carvalho Chehab 	.disconnect = dvb_usbv2_disconnect,
1118786baecfSMauro Carvalho Chehab 	.suspend = dvb_usbv2_suspend,
1119786baecfSMauro Carvalho Chehab 	.resume = dvb_usbv2_resume,
112004966aa8SAntti Palosaari 	.reset_resume = dvb_usbv2_reset_resume,
1121786baecfSMauro Carvalho Chehab 	.no_dynamic_id = 1,
1122786baecfSMauro Carvalho Chehab 	.soft_unbind = 1,
1123786baecfSMauro Carvalho Chehab };
1124786baecfSMauro Carvalho Chehab 
1125786baecfSMauro Carvalho Chehab module_usb_driver(af9035_usb_driver);
1126786baecfSMauro Carvalho Chehab 
1127786baecfSMauro Carvalho Chehab MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
1128786baecfSMauro Carvalho Chehab MODULE_DESCRIPTION("Afatech AF9035 driver");
1129786baecfSMauro Carvalho Chehab MODULE_LICENSE("GPL");
1130