xref: /openbmc/linux/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c (revision 786baecfe78f8e25547c628b48a60fc8e5636056)
1*786baecfSMauro Carvalho Chehab /*
2*786baecfSMauro Carvalho Chehab  *  mxl111sf-i2c.c - driver for the MaxLinear MXL111SF
3*786baecfSMauro Carvalho Chehab  *
4*786baecfSMauro Carvalho Chehab  *  Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com>
5*786baecfSMauro Carvalho Chehab  *
6*786baecfSMauro Carvalho Chehab  *  This program is free software; you can redistribute it and/or modify
7*786baecfSMauro Carvalho Chehab  *  it under the terms of the GNU General Public License as published by
8*786baecfSMauro Carvalho Chehab  *  the Free Software Foundation; either version 2 of the License, or
9*786baecfSMauro Carvalho Chehab  *  (at your option) any later version.
10*786baecfSMauro Carvalho Chehab  *
11*786baecfSMauro Carvalho Chehab  *  This program is distributed in the hope that it will be useful,
12*786baecfSMauro Carvalho Chehab  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13*786baecfSMauro Carvalho Chehab  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14*786baecfSMauro Carvalho Chehab  *  GNU General Public License for more details.
15*786baecfSMauro Carvalho Chehab  *
16*786baecfSMauro Carvalho Chehab  *  You should have received a copy of the GNU General Public License
17*786baecfSMauro Carvalho Chehab  *  along with this program; if not, write to the Free Software
18*786baecfSMauro Carvalho Chehab  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19*786baecfSMauro Carvalho Chehab  */
20*786baecfSMauro Carvalho Chehab 
21*786baecfSMauro Carvalho Chehab #include "mxl111sf-i2c.h"
22*786baecfSMauro Carvalho Chehab #include "mxl111sf.h"
23*786baecfSMauro Carvalho Chehab 
24*786baecfSMauro Carvalho Chehab /* SW-I2C ----------------------------------------------------------------- */
25*786baecfSMauro Carvalho Chehab 
26*786baecfSMauro Carvalho Chehab #define SW_I2C_ADDR		0x1a
27*786baecfSMauro Carvalho Chehab #define SW_I2C_EN		0x02
28*786baecfSMauro Carvalho Chehab #define SW_SCL_OUT		0x04
29*786baecfSMauro Carvalho Chehab #define SW_SDA_OUT		0x08
30*786baecfSMauro Carvalho Chehab #define SW_SDA_IN		0x04
31*786baecfSMauro Carvalho Chehab 
32*786baecfSMauro Carvalho Chehab #define SW_I2C_BUSY_ADDR	0x2f
33*786baecfSMauro Carvalho Chehab #define SW_I2C_BUSY		0x02
34*786baecfSMauro Carvalho Chehab 
35*786baecfSMauro Carvalho Chehab static int mxl111sf_i2c_bitbang_sendbyte(struct mxl111sf_state *state,
36*786baecfSMauro Carvalho Chehab 					 u8 byte)
37*786baecfSMauro Carvalho Chehab {
38*786baecfSMauro Carvalho Chehab 	int i, ret;
39*786baecfSMauro Carvalho Chehab 	u8 data = 0;
40*786baecfSMauro Carvalho Chehab 
41*786baecfSMauro Carvalho Chehab 	mxl_i2c("(0x%02x)", byte);
42*786baecfSMauro Carvalho Chehab 
43*786baecfSMauro Carvalho Chehab 	ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &data);
44*786baecfSMauro Carvalho Chehab 	if (mxl_fail(ret))
45*786baecfSMauro Carvalho Chehab 		goto fail;
46*786baecfSMauro Carvalho Chehab 
47*786baecfSMauro Carvalho Chehab 	for (i = 0; i < 8; i++) {
48*786baecfSMauro Carvalho Chehab 
49*786baecfSMauro Carvalho Chehab 		data = (byte & (0x80 >> i)) ? SW_SDA_OUT : 0;
50*786baecfSMauro Carvalho Chehab 
51*786baecfSMauro Carvalho Chehab 		ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
52*786baecfSMauro Carvalho Chehab 					 0x10 | SW_I2C_EN | data);
53*786baecfSMauro Carvalho Chehab 		if (mxl_fail(ret))
54*786baecfSMauro Carvalho Chehab 			goto fail;
55*786baecfSMauro Carvalho Chehab 
56*786baecfSMauro Carvalho Chehab 		ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
57*786baecfSMauro Carvalho Chehab 					 0x10 | SW_I2C_EN | data | SW_SCL_OUT);
58*786baecfSMauro Carvalho Chehab 		if (mxl_fail(ret))
59*786baecfSMauro Carvalho Chehab 			goto fail;
60*786baecfSMauro Carvalho Chehab 
61*786baecfSMauro Carvalho Chehab 		ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
62*786baecfSMauro Carvalho Chehab 					 0x10 | SW_I2C_EN | data);
63*786baecfSMauro Carvalho Chehab 		if (mxl_fail(ret))
64*786baecfSMauro Carvalho Chehab 			goto fail;
65*786baecfSMauro Carvalho Chehab 	}
66*786baecfSMauro Carvalho Chehab 
67*786baecfSMauro Carvalho Chehab 	/* last bit was 0 so we need to release SDA */
68*786baecfSMauro Carvalho Chehab 	if (!(byte & 1)) {
69*786baecfSMauro Carvalho Chehab 		ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
70*786baecfSMauro Carvalho Chehab 					 0x10 | SW_I2C_EN | SW_SDA_OUT);
71*786baecfSMauro Carvalho Chehab 		if (mxl_fail(ret))
72*786baecfSMauro Carvalho Chehab 			goto fail;
73*786baecfSMauro Carvalho Chehab 	}
74*786baecfSMauro Carvalho Chehab 
75*786baecfSMauro Carvalho Chehab 	/* CLK high for ACK readback */
76*786baecfSMauro Carvalho Chehab 	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
77*786baecfSMauro Carvalho Chehab 				 0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT);
78*786baecfSMauro Carvalho Chehab 	if (mxl_fail(ret))
79*786baecfSMauro Carvalho Chehab 		goto fail;
80*786baecfSMauro Carvalho Chehab 
81*786baecfSMauro Carvalho Chehab 	ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &data);
82*786baecfSMauro Carvalho Chehab 	if (mxl_fail(ret))
83*786baecfSMauro Carvalho Chehab 		goto fail;
84*786baecfSMauro Carvalho Chehab 
85*786baecfSMauro Carvalho Chehab 	/* drop the CLK after getting ACK, SDA will go high right away */
86*786baecfSMauro Carvalho Chehab 	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
87*786baecfSMauro Carvalho Chehab 				 0x10 | SW_I2C_EN | SW_SDA_OUT);
88*786baecfSMauro Carvalho Chehab 	if (mxl_fail(ret))
89*786baecfSMauro Carvalho Chehab 		goto fail;
90*786baecfSMauro Carvalho Chehab 
91*786baecfSMauro Carvalho Chehab 	if (data & SW_SDA_IN)
92*786baecfSMauro Carvalho Chehab 		ret = -EIO;
93*786baecfSMauro Carvalho Chehab fail:
94*786baecfSMauro Carvalho Chehab 	return ret;
95*786baecfSMauro Carvalho Chehab }
96*786baecfSMauro Carvalho Chehab 
97*786baecfSMauro Carvalho Chehab static int mxl111sf_i2c_bitbang_recvbyte(struct mxl111sf_state *state,
98*786baecfSMauro Carvalho Chehab 					 u8 *pbyte)
99*786baecfSMauro Carvalho Chehab {
100*786baecfSMauro Carvalho Chehab 	int i, ret;
101*786baecfSMauro Carvalho Chehab 	u8 byte = 0;
102*786baecfSMauro Carvalho Chehab 	u8 data = 0;
103*786baecfSMauro Carvalho Chehab 
104*786baecfSMauro Carvalho Chehab 	mxl_i2c("()");
105*786baecfSMauro Carvalho Chehab 
106*786baecfSMauro Carvalho Chehab 	*pbyte = 0;
107*786baecfSMauro Carvalho Chehab 
108*786baecfSMauro Carvalho Chehab 	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
109*786baecfSMauro Carvalho Chehab 				 0x10 | SW_I2C_EN | SW_SDA_OUT);
110*786baecfSMauro Carvalho Chehab 	if (mxl_fail(ret))
111*786baecfSMauro Carvalho Chehab 		goto fail;
112*786baecfSMauro Carvalho Chehab 
113*786baecfSMauro Carvalho Chehab 	for (i = 0; i < 8; i++) {
114*786baecfSMauro Carvalho Chehab 		ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
115*786baecfSMauro Carvalho Chehab 					 0x10 | SW_I2C_EN |
116*786baecfSMauro Carvalho Chehab 					 SW_SCL_OUT | SW_SDA_OUT);
117*786baecfSMauro Carvalho Chehab 		if (mxl_fail(ret))
118*786baecfSMauro Carvalho Chehab 			goto fail;
119*786baecfSMauro Carvalho Chehab 
120*786baecfSMauro Carvalho Chehab 		ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &data);
121*786baecfSMauro Carvalho Chehab 		if (mxl_fail(ret))
122*786baecfSMauro Carvalho Chehab 			goto fail;
123*786baecfSMauro Carvalho Chehab 
124*786baecfSMauro Carvalho Chehab 		if (data & SW_SDA_IN)
125*786baecfSMauro Carvalho Chehab 			byte |= (0x80 >> i);
126*786baecfSMauro Carvalho Chehab 
127*786baecfSMauro Carvalho Chehab 		ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
128*786baecfSMauro Carvalho Chehab 					 0x10 | SW_I2C_EN | SW_SDA_OUT);
129*786baecfSMauro Carvalho Chehab 		if (mxl_fail(ret))
130*786baecfSMauro Carvalho Chehab 			goto fail;
131*786baecfSMauro Carvalho Chehab 	}
132*786baecfSMauro Carvalho Chehab 	*pbyte = byte;
133*786baecfSMauro Carvalho Chehab fail:
134*786baecfSMauro Carvalho Chehab 	return ret;
135*786baecfSMauro Carvalho Chehab }
136*786baecfSMauro Carvalho Chehab 
137*786baecfSMauro Carvalho Chehab static int mxl111sf_i2c_start(struct mxl111sf_state *state)
138*786baecfSMauro Carvalho Chehab {
139*786baecfSMauro Carvalho Chehab 	int ret;
140*786baecfSMauro Carvalho Chehab 
141*786baecfSMauro Carvalho Chehab 	mxl_i2c("()");
142*786baecfSMauro Carvalho Chehab 
143*786baecfSMauro Carvalho Chehab 	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
144*786baecfSMauro Carvalho Chehab 				 0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT);
145*786baecfSMauro Carvalho Chehab 	if (mxl_fail(ret))
146*786baecfSMauro Carvalho Chehab 		goto fail;
147*786baecfSMauro Carvalho Chehab 
148*786baecfSMauro Carvalho Chehab 	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
149*786baecfSMauro Carvalho Chehab 				 0x10 | SW_I2C_EN | SW_SCL_OUT);
150*786baecfSMauro Carvalho Chehab 	if (mxl_fail(ret))
151*786baecfSMauro Carvalho Chehab 		goto fail;
152*786baecfSMauro Carvalho Chehab 
153*786baecfSMauro Carvalho Chehab 	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
154*786baecfSMauro Carvalho Chehab 				 0x10 | SW_I2C_EN); /* start */
155*786baecfSMauro Carvalho Chehab 	mxl_fail(ret);
156*786baecfSMauro Carvalho Chehab fail:
157*786baecfSMauro Carvalho Chehab 	return ret;
158*786baecfSMauro Carvalho Chehab }
159*786baecfSMauro Carvalho Chehab 
160*786baecfSMauro Carvalho Chehab static int mxl111sf_i2c_stop(struct mxl111sf_state *state)
161*786baecfSMauro Carvalho Chehab {
162*786baecfSMauro Carvalho Chehab 	int ret;
163*786baecfSMauro Carvalho Chehab 
164*786baecfSMauro Carvalho Chehab 	mxl_i2c("()");
165*786baecfSMauro Carvalho Chehab 
166*786baecfSMauro Carvalho Chehab 	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
167*786baecfSMauro Carvalho Chehab 				 0x10 | SW_I2C_EN); /* stop */
168*786baecfSMauro Carvalho Chehab 	if (mxl_fail(ret))
169*786baecfSMauro Carvalho Chehab 		goto fail;
170*786baecfSMauro Carvalho Chehab 
171*786baecfSMauro Carvalho Chehab 	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
172*786baecfSMauro Carvalho Chehab 				 0x10 | SW_I2C_EN | SW_SCL_OUT);
173*786baecfSMauro Carvalho Chehab 	if (mxl_fail(ret))
174*786baecfSMauro Carvalho Chehab 		goto fail;
175*786baecfSMauro Carvalho Chehab 
176*786baecfSMauro Carvalho Chehab 	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
177*786baecfSMauro Carvalho Chehab 				 0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT);
178*786baecfSMauro Carvalho Chehab 	if (mxl_fail(ret))
179*786baecfSMauro Carvalho Chehab 		goto fail;
180*786baecfSMauro Carvalho Chehab 
181*786baecfSMauro Carvalho Chehab 	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
182*786baecfSMauro Carvalho Chehab 				 0x10 | SW_SCL_OUT | SW_SDA_OUT);
183*786baecfSMauro Carvalho Chehab 	mxl_fail(ret);
184*786baecfSMauro Carvalho Chehab fail:
185*786baecfSMauro Carvalho Chehab 	return ret;
186*786baecfSMauro Carvalho Chehab }
187*786baecfSMauro Carvalho Chehab 
188*786baecfSMauro Carvalho Chehab static int mxl111sf_i2c_ack(struct mxl111sf_state *state)
189*786baecfSMauro Carvalho Chehab {
190*786baecfSMauro Carvalho Chehab 	int ret;
191*786baecfSMauro Carvalho Chehab 	u8 b = 0;
192*786baecfSMauro Carvalho Chehab 
193*786baecfSMauro Carvalho Chehab 	mxl_i2c("()");
194*786baecfSMauro Carvalho Chehab 
195*786baecfSMauro Carvalho Chehab 	ret = mxl111sf_read_reg(state, SW_I2C_BUSY_ADDR, &b);
196*786baecfSMauro Carvalho Chehab 	if (mxl_fail(ret))
197*786baecfSMauro Carvalho Chehab 		goto fail;
198*786baecfSMauro Carvalho Chehab 
199*786baecfSMauro Carvalho Chehab 	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
200*786baecfSMauro Carvalho Chehab 				 0x10 | SW_I2C_EN);
201*786baecfSMauro Carvalho Chehab 	if (mxl_fail(ret))
202*786baecfSMauro Carvalho Chehab 		goto fail;
203*786baecfSMauro Carvalho Chehab 
204*786baecfSMauro Carvalho Chehab 	/* pull SDA low */
205*786baecfSMauro Carvalho Chehab 	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
206*786baecfSMauro Carvalho Chehab 				 0x10 | SW_I2C_EN | SW_SCL_OUT);
207*786baecfSMauro Carvalho Chehab 	if (mxl_fail(ret))
208*786baecfSMauro Carvalho Chehab 		goto fail;
209*786baecfSMauro Carvalho Chehab 
210*786baecfSMauro Carvalho Chehab 	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
211*786baecfSMauro Carvalho Chehab 				 0x10 | SW_I2C_EN | SW_SDA_OUT);
212*786baecfSMauro Carvalho Chehab 	mxl_fail(ret);
213*786baecfSMauro Carvalho Chehab fail:
214*786baecfSMauro Carvalho Chehab 	return ret;
215*786baecfSMauro Carvalho Chehab }
216*786baecfSMauro Carvalho Chehab 
217*786baecfSMauro Carvalho Chehab static int mxl111sf_i2c_nack(struct mxl111sf_state *state)
218*786baecfSMauro Carvalho Chehab {
219*786baecfSMauro Carvalho Chehab 	int ret;
220*786baecfSMauro Carvalho Chehab 
221*786baecfSMauro Carvalho Chehab 	mxl_i2c("()");
222*786baecfSMauro Carvalho Chehab 
223*786baecfSMauro Carvalho Chehab 	/* SDA high to signal last byte read from slave */
224*786baecfSMauro Carvalho Chehab 	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
225*786baecfSMauro Carvalho Chehab 				 0x10 | SW_I2C_EN | SW_SCL_OUT | SW_SDA_OUT);
226*786baecfSMauro Carvalho Chehab 	if (mxl_fail(ret))
227*786baecfSMauro Carvalho Chehab 		goto fail;
228*786baecfSMauro Carvalho Chehab 
229*786baecfSMauro Carvalho Chehab 	ret = mxl111sf_write_reg(state, SW_I2C_ADDR,
230*786baecfSMauro Carvalho Chehab 				 0x10 | SW_I2C_EN | SW_SDA_OUT);
231*786baecfSMauro Carvalho Chehab 	mxl_fail(ret);
232*786baecfSMauro Carvalho Chehab fail:
233*786baecfSMauro Carvalho Chehab 	return ret;
234*786baecfSMauro Carvalho Chehab }
235*786baecfSMauro Carvalho Chehab 
236*786baecfSMauro Carvalho Chehab /* ------------------------------------------------------------------------ */
237*786baecfSMauro Carvalho Chehab 
238*786baecfSMauro Carvalho Chehab static int mxl111sf_i2c_sw_xfer_msg(struct mxl111sf_state *state,
239*786baecfSMauro Carvalho Chehab 				    struct i2c_msg *msg)
240*786baecfSMauro Carvalho Chehab {
241*786baecfSMauro Carvalho Chehab 	int i, ret;
242*786baecfSMauro Carvalho Chehab 
243*786baecfSMauro Carvalho Chehab 	mxl_i2c("()");
244*786baecfSMauro Carvalho Chehab 
245*786baecfSMauro Carvalho Chehab 	if (msg->flags & I2C_M_RD) {
246*786baecfSMauro Carvalho Chehab 
247*786baecfSMauro Carvalho Chehab 		ret = mxl111sf_i2c_start(state);
248*786baecfSMauro Carvalho Chehab 		if (mxl_fail(ret))
249*786baecfSMauro Carvalho Chehab 			goto fail;
250*786baecfSMauro Carvalho Chehab 
251*786baecfSMauro Carvalho Chehab 		ret = mxl111sf_i2c_bitbang_sendbyte(state,
252*786baecfSMauro Carvalho Chehab 						    (msg->addr << 1) | 0x01);
253*786baecfSMauro Carvalho Chehab 		if (mxl_fail(ret)) {
254*786baecfSMauro Carvalho Chehab 			mxl111sf_i2c_stop(state);
255*786baecfSMauro Carvalho Chehab 			goto fail;
256*786baecfSMauro Carvalho Chehab 		}
257*786baecfSMauro Carvalho Chehab 
258*786baecfSMauro Carvalho Chehab 		for (i = 0; i < msg->len; i++) {
259*786baecfSMauro Carvalho Chehab 			ret = mxl111sf_i2c_bitbang_recvbyte(state,
260*786baecfSMauro Carvalho Chehab 							    &msg->buf[i]);
261*786baecfSMauro Carvalho Chehab 			if (mxl_fail(ret)) {
262*786baecfSMauro Carvalho Chehab 				mxl111sf_i2c_stop(state);
263*786baecfSMauro Carvalho Chehab 				goto fail;
264*786baecfSMauro Carvalho Chehab 			}
265*786baecfSMauro Carvalho Chehab 
266*786baecfSMauro Carvalho Chehab 			if (i < msg->len - 1)
267*786baecfSMauro Carvalho Chehab 				mxl111sf_i2c_ack(state);
268*786baecfSMauro Carvalho Chehab 		}
269*786baecfSMauro Carvalho Chehab 
270*786baecfSMauro Carvalho Chehab 		mxl111sf_i2c_nack(state);
271*786baecfSMauro Carvalho Chehab 
272*786baecfSMauro Carvalho Chehab 		ret = mxl111sf_i2c_stop(state);
273*786baecfSMauro Carvalho Chehab 		if (mxl_fail(ret))
274*786baecfSMauro Carvalho Chehab 			goto fail;
275*786baecfSMauro Carvalho Chehab 
276*786baecfSMauro Carvalho Chehab 	} else {
277*786baecfSMauro Carvalho Chehab 
278*786baecfSMauro Carvalho Chehab 		ret = mxl111sf_i2c_start(state);
279*786baecfSMauro Carvalho Chehab 		if (mxl_fail(ret))
280*786baecfSMauro Carvalho Chehab 			goto fail;
281*786baecfSMauro Carvalho Chehab 
282*786baecfSMauro Carvalho Chehab 		ret = mxl111sf_i2c_bitbang_sendbyte(state,
283*786baecfSMauro Carvalho Chehab 						    (msg->addr << 1) & 0xfe);
284*786baecfSMauro Carvalho Chehab 		if (mxl_fail(ret)) {
285*786baecfSMauro Carvalho Chehab 			mxl111sf_i2c_stop(state);
286*786baecfSMauro Carvalho Chehab 			goto fail;
287*786baecfSMauro Carvalho Chehab 		}
288*786baecfSMauro Carvalho Chehab 
289*786baecfSMauro Carvalho Chehab 		for (i = 0; i < msg->len; i++) {
290*786baecfSMauro Carvalho Chehab 			ret = mxl111sf_i2c_bitbang_sendbyte(state,
291*786baecfSMauro Carvalho Chehab 							    msg->buf[i]);
292*786baecfSMauro Carvalho Chehab 			if (mxl_fail(ret)) {
293*786baecfSMauro Carvalho Chehab 				mxl111sf_i2c_stop(state);
294*786baecfSMauro Carvalho Chehab 				goto fail;
295*786baecfSMauro Carvalho Chehab 			}
296*786baecfSMauro Carvalho Chehab 		}
297*786baecfSMauro Carvalho Chehab 
298*786baecfSMauro Carvalho Chehab 		/* FIXME: we only want to do this on the last transaction */
299*786baecfSMauro Carvalho Chehab 		mxl111sf_i2c_stop(state);
300*786baecfSMauro Carvalho Chehab 	}
301*786baecfSMauro Carvalho Chehab fail:
302*786baecfSMauro Carvalho Chehab 	return ret;
303*786baecfSMauro Carvalho Chehab }
304*786baecfSMauro Carvalho Chehab 
305*786baecfSMauro Carvalho Chehab /* HW-I2C ----------------------------------------------------------------- */
306*786baecfSMauro Carvalho Chehab 
307*786baecfSMauro Carvalho Chehab #define USB_WRITE_I2C_CMD     0x99
308*786baecfSMauro Carvalho Chehab #define USB_READ_I2C_CMD      0xdd
309*786baecfSMauro Carvalho Chehab #define USB_END_I2C_CMD       0xfe
310*786baecfSMauro Carvalho Chehab 
311*786baecfSMauro Carvalho Chehab #define USB_WRITE_I2C_CMD_LEN   26
312*786baecfSMauro Carvalho Chehab #define USB_READ_I2C_CMD_LEN    24
313*786baecfSMauro Carvalho Chehab 
314*786baecfSMauro Carvalho Chehab #define I2C_MUX_REG           0x30
315*786baecfSMauro Carvalho Chehab #define I2C_CONTROL_REG       0x00
316*786baecfSMauro Carvalho Chehab #define I2C_SLAVE_ADDR_REG    0x08
317*786baecfSMauro Carvalho Chehab #define I2C_DATA_REG          0x0c
318*786baecfSMauro Carvalho Chehab #define I2C_INT_STATUS_REG    0x10
319*786baecfSMauro Carvalho Chehab 
320*786baecfSMauro Carvalho Chehab static int mxl111sf_i2c_send_data(struct mxl111sf_state *state,
321*786baecfSMauro Carvalho Chehab 				  u8 index, u8 *wdata)
322*786baecfSMauro Carvalho Chehab {
323*786baecfSMauro Carvalho Chehab 	int ret = mxl111sf_ctrl_msg(state->d, wdata[0],
324*786baecfSMauro Carvalho Chehab 				    &wdata[1], 25, NULL, 0);
325*786baecfSMauro Carvalho Chehab 	mxl_fail(ret);
326*786baecfSMauro Carvalho Chehab 
327*786baecfSMauro Carvalho Chehab 	return ret;
328*786baecfSMauro Carvalho Chehab }
329*786baecfSMauro Carvalho Chehab 
330*786baecfSMauro Carvalho Chehab static int mxl111sf_i2c_get_data(struct mxl111sf_state *state,
331*786baecfSMauro Carvalho Chehab 				 u8 index, u8 *wdata, u8 *rdata)
332*786baecfSMauro Carvalho Chehab {
333*786baecfSMauro Carvalho Chehab 	int ret = mxl111sf_ctrl_msg(state->d, wdata[0],
334*786baecfSMauro Carvalho Chehab 				    &wdata[1], 25, rdata, 24);
335*786baecfSMauro Carvalho Chehab 	mxl_fail(ret);
336*786baecfSMauro Carvalho Chehab 
337*786baecfSMauro Carvalho Chehab 	return ret;
338*786baecfSMauro Carvalho Chehab }
339*786baecfSMauro Carvalho Chehab 
340*786baecfSMauro Carvalho Chehab static u8 mxl111sf_i2c_check_status(struct mxl111sf_state *state)
341*786baecfSMauro Carvalho Chehab {
342*786baecfSMauro Carvalho Chehab 	u8 status = 0;
343*786baecfSMauro Carvalho Chehab 	u8 buf[26];
344*786baecfSMauro Carvalho Chehab 
345*786baecfSMauro Carvalho Chehab 	mxl_i2c_adv("()");
346*786baecfSMauro Carvalho Chehab 
347*786baecfSMauro Carvalho Chehab 	buf[0] = USB_READ_I2C_CMD;
348*786baecfSMauro Carvalho Chehab 	buf[1] = 0x00;
349*786baecfSMauro Carvalho Chehab 
350*786baecfSMauro Carvalho Chehab 	buf[2] = I2C_INT_STATUS_REG;
351*786baecfSMauro Carvalho Chehab 	buf[3] = 0x00;
352*786baecfSMauro Carvalho Chehab 	buf[4] = 0x00;
353*786baecfSMauro Carvalho Chehab 
354*786baecfSMauro Carvalho Chehab 	buf[5] = USB_END_I2C_CMD;
355*786baecfSMauro Carvalho Chehab 
356*786baecfSMauro Carvalho Chehab 	mxl111sf_i2c_get_data(state, 0, buf, buf);
357*786baecfSMauro Carvalho Chehab 
358*786baecfSMauro Carvalho Chehab 	if (buf[1] & 0x04)
359*786baecfSMauro Carvalho Chehab 		status = 1;
360*786baecfSMauro Carvalho Chehab 
361*786baecfSMauro Carvalho Chehab 	return status;
362*786baecfSMauro Carvalho Chehab }
363*786baecfSMauro Carvalho Chehab 
364*786baecfSMauro Carvalho Chehab static u8 mxl111sf_i2c_check_fifo(struct mxl111sf_state *state)
365*786baecfSMauro Carvalho Chehab {
366*786baecfSMauro Carvalho Chehab 	u8 status = 0;
367*786baecfSMauro Carvalho Chehab 	u8 buf[26];
368*786baecfSMauro Carvalho Chehab 
369*786baecfSMauro Carvalho Chehab 	mxl_i2c("()");
370*786baecfSMauro Carvalho Chehab 
371*786baecfSMauro Carvalho Chehab 	buf[0] = USB_READ_I2C_CMD;
372*786baecfSMauro Carvalho Chehab 	buf[1] = 0x00;
373*786baecfSMauro Carvalho Chehab 
374*786baecfSMauro Carvalho Chehab 	buf[2] = I2C_MUX_REG;
375*786baecfSMauro Carvalho Chehab 	buf[3] = 0x00;
376*786baecfSMauro Carvalho Chehab 	buf[4] = 0x00;
377*786baecfSMauro Carvalho Chehab 
378*786baecfSMauro Carvalho Chehab 	buf[5] = I2C_INT_STATUS_REG;
379*786baecfSMauro Carvalho Chehab 	buf[6] = 0x00;
380*786baecfSMauro Carvalho Chehab 	buf[7] = 0x00;
381*786baecfSMauro Carvalho Chehab 	buf[8] = USB_END_I2C_CMD;
382*786baecfSMauro Carvalho Chehab 
383*786baecfSMauro Carvalho Chehab 	mxl111sf_i2c_get_data(state, 0, buf, buf);
384*786baecfSMauro Carvalho Chehab 
385*786baecfSMauro Carvalho Chehab 	if (0x08 == (buf[1] & 0x08))
386*786baecfSMauro Carvalho Chehab 		status = 1;
387*786baecfSMauro Carvalho Chehab 
388*786baecfSMauro Carvalho Chehab 	if ((buf[5] & 0x02) == 0x02)
389*786baecfSMauro Carvalho Chehab 		mxl_i2c("(buf[5] & 0x02) == 0x02"); /* FIXME */
390*786baecfSMauro Carvalho Chehab 
391*786baecfSMauro Carvalho Chehab 	return status;
392*786baecfSMauro Carvalho Chehab }
393*786baecfSMauro Carvalho Chehab 
394*786baecfSMauro Carvalho Chehab static int mxl111sf_i2c_readagain(struct mxl111sf_state *state,
395*786baecfSMauro Carvalho Chehab 				  u8 count, u8 *rbuf)
396*786baecfSMauro Carvalho Chehab {
397*786baecfSMauro Carvalho Chehab 	u8 i2c_w_data[26];
398*786baecfSMauro Carvalho Chehab 	u8 i2c_r_data[24];
399*786baecfSMauro Carvalho Chehab 	u8 i = 0;
400*786baecfSMauro Carvalho Chehab 	u8 fifo_status = 0;
401*786baecfSMauro Carvalho Chehab 	int status = 0;
402*786baecfSMauro Carvalho Chehab 
403*786baecfSMauro Carvalho Chehab 	mxl_i2c("read %d bytes", count);
404*786baecfSMauro Carvalho Chehab 
405*786baecfSMauro Carvalho Chehab 	while ((fifo_status == 0) && (i++ < 5))
406*786baecfSMauro Carvalho Chehab 		fifo_status = mxl111sf_i2c_check_fifo(state);
407*786baecfSMauro Carvalho Chehab 
408*786baecfSMauro Carvalho Chehab 	i2c_w_data[0] = 0xDD;
409*786baecfSMauro Carvalho Chehab 	i2c_w_data[1] = 0x00;
410*786baecfSMauro Carvalho Chehab 
411*786baecfSMauro Carvalho Chehab 	for (i = 2; i < 26; i++)
412*786baecfSMauro Carvalho Chehab 		i2c_w_data[i] = 0xFE;
413*786baecfSMauro Carvalho Chehab 
414*786baecfSMauro Carvalho Chehab 	for (i = 0; i < count; i++) {
415*786baecfSMauro Carvalho Chehab 		i2c_w_data[2+(i*3)] = 0x0C;
416*786baecfSMauro Carvalho Chehab 		i2c_w_data[3+(i*3)] = 0x00;
417*786baecfSMauro Carvalho Chehab 		i2c_w_data[4+(i*3)] = 0x00;
418*786baecfSMauro Carvalho Chehab 	}
419*786baecfSMauro Carvalho Chehab 
420*786baecfSMauro Carvalho Chehab 	mxl111sf_i2c_get_data(state, 0, i2c_w_data, i2c_r_data);
421*786baecfSMauro Carvalho Chehab 
422*786baecfSMauro Carvalho Chehab 	/* Check for I2C NACK status */
423*786baecfSMauro Carvalho Chehab 	if (mxl111sf_i2c_check_status(state) == 1) {
424*786baecfSMauro Carvalho Chehab 		mxl_i2c("error!");
425*786baecfSMauro Carvalho Chehab 	} else {
426*786baecfSMauro Carvalho Chehab 		for (i = 0; i < count; i++) {
427*786baecfSMauro Carvalho Chehab 			rbuf[i] = i2c_r_data[(i*3)+1];
428*786baecfSMauro Carvalho Chehab 			mxl_i2c("%02x\t %02x",
429*786baecfSMauro Carvalho Chehab 				i2c_r_data[(i*3)+1],
430*786baecfSMauro Carvalho Chehab 				i2c_r_data[(i*3)+2]);
431*786baecfSMauro Carvalho Chehab 		}
432*786baecfSMauro Carvalho Chehab 
433*786baecfSMauro Carvalho Chehab 		status = 1;
434*786baecfSMauro Carvalho Chehab 	}
435*786baecfSMauro Carvalho Chehab 
436*786baecfSMauro Carvalho Chehab 	return status;
437*786baecfSMauro Carvalho Chehab }
438*786baecfSMauro Carvalho Chehab 
439*786baecfSMauro Carvalho Chehab #define HWI2C400 1
440*786baecfSMauro Carvalho Chehab static int mxl111sf_i2c_hw_xfer_msg(struct mxl111sf_state *state,
441*786baecfSMauro Carvalho Chehab 				    struct i2c_msg *msg)
442*786baecfSMauro Carvalho Chehab {
443*786baecfSMauro Carvalho Chehab 	int i, k, ret = 0;
444*786baecfSMauro Carvalho Chehab 	u16 index = 0;
445*786baecfSMauro Carvalho Chehab 	u8 buf[26];
446*786baecfSMauro Carvalho Chehab 	u8 i2c_r_data[24];
447*786baecfSMauro Carvalho Chehab 	u16 block_len;
448*786baecfSMauro Carvalho Chehab 	u16 left_over_len;
449*786baecfSMauro Carvalho Chehab 	u8 rd_status[8];
450*786baecfSMauro Carvalho Chehab 	u8 ret_status;
451*786baecfSMauro Carvalho Chehab 	u8 readbuff[26];
452*786baecfSMauro Carvalho Chehab 
453*786baecfSMauro Carvalho Chehab 	mxl_i2c("addr: 0x%02x, read buff len: %d, write buff len: %d",
454*786baecfSMauro Carvalho Chehab 		msg->addr, (msg->flags & I2C_M_RD) ? msg->len : 0,
455*786baecfSMauro Carvalho Chehab 		(!(msg->flags & I2C_M_RD)) ? msg->len : 0);
456*786baecfSMauro Carvalho Chehab 
457*786baecfSMauro Carvalho Chehab 	for (index = 0; index < 26; index++)
458*786baecfSMauro Carvalho Chehab 		buf[index] = USB_END_I2C_CMD;
459*786baecfSMauro Carvalho Chehab 
460*786baecfSMauro Carvalho Chehab 	/* command to indicate data payload is destined for I2C interface */
461*786baecfSMauro Carvalho Chehab 	buf[0] = USB_WRITE_I2C_CMD;
462*786baecfSMauro Carvalho Chehab 	buf[1] = 0x00;
463*786baecfSMauro Carvalho Chehab 
464*786baecfSMauro Carvalho Chehab 	/* enable I2C interface */
465*786baecfSMauro Carvalho Chehab 	buf[2] = I2C_MUX_REG;
466*786baecfSMauro Carvalho Chehab 	buf[3] = 0x80;
467*786baecfSMauro Carvalho Chehab 	buf[4] = 0x00;
468*786baecfSMauro Carvalho Chehab 
469*786baecfSMauro Carvalho Chehab 	/* enable I2C interface */
470*786baecfSMauro Carvalho Chehab 	buf[5] = I2C_MUX_REG;
471*786baecfSMauro Carvalho Chehab 	buf[6] = 0x81;
472*786baecfSMauro Carvalho Chehab 	buf[7] = 0x00;
473*786baecfSMauro Carvalho Chehab 
474*786baecfSMauro Carvalho Chehab 	/* set Timeout register on I2C interface */
475*786baecfSMauro Carvalho Chehab 	buf[8] = 0x14;
476*786baecfSMauro Carvalho Chehab 	buf[9] = 0xff;
477*786baecfSMauro Carvalho Chehab 	buf[10] = 0x00;
478*786baecfSMauro Carvalho Chehab #if 0
479*786baecfSMauro Carvalho Chehab 	/* enable Interrupts on I2C interface */
480*786baecfSMauro Carvalho Chehab 	buf[8] = 0x24;
481*786baecfSMauro Carvalho Chehab 	buf[9] = 0xF7;
482*786baecfSMauro Carvalho Chehab 	buf[10] = 0x00;
483*786baecfSMauro Carvalho Chehab #endif
484*786baecfSMauro Carvalho Chehab 	buf[11] = 0x24;
485*786baecfSMauro Carvalho Chehab 	buf[12] = 0xF7;
486*786baecfSMauro Carvalho Chehab 	buf[13] = 0x00;
487*786baecfSMauro Carvalho Chehab 
488*786baecfSMauro Carvalho Chehab 	ret = mxl111sf_i2c_send_data(state, 0, buf);
489*786baecfSMauro Carvalho Chehab 
490*786baecfSMauro Carvalho Chehab 	/* write data on I2C bus */
491*786baecfSMauro Carvalho Chehab 	if (!(msg->flags & I2C_M_RD) && (msg->len > 0)) {
492*786baecfSMauro Carvalho Chehab 		mxl_i2c("%d\t%02x", msg->len, msg->buf[0]);
493*786baecfSMauro Carvalho Chehab 
494*786baecfSMauro Carvalho Chehab 		/* control register on I2C interface to initialize I2C bus */
495*786baecfSMauro Carvalho Chehab 		buf[2] = I2C_CONTROL_REG;
496*786baecfSMauro Carvalho Chehab 		buf[3] = 0x5E;
497*786baecfSMauro Carvalho Chehab 		buf[4] = (HWI2C400) ? 0x03 : 0x0D;
498*786baecfSMauro Carvalho Chehab 
499*786baecfSMauro Carvalho Chehab 		/* I2C Slave device Address */
500*786baecfSMauro Carvalho Chehab 		buf[5] = I2C_SLAVE_ADDR_REG;
501*786baecfSMauro Carvalho Chehab 		buf[6] = (msg->addr);
502*786baecfSMauro Carvalho Chehab 		buf[7] = 0x00;
503*786baecfSMauro Carvalho Chehab 		buf[8] = USB_END_I2C_CMD;
504*786baecfSMauro Carvalho Chehab 		ret = mxl111sf_i2c_send_data(state, 0, buf);
505*786baecfSMauro Carvalho Chehab 
506*786baecfSMauro Carvalho Chehab 		/* check for slave device status */
507*786baecfSMauro Carvalho Chehab 		if (mxl111sf_i2c_check_status(state) == 1) {
508*786baecfSMauro Carvalho Chehab 			mxl_i2c("NACK writing slave address %02x",
509*786baecfSMauro Carvalho Chehab 				msg->addr);
510*786baecfSMauro Carvalho Chehab 			/* if NACK, stop I2C bus and exit */
511*786baecfSMauro Carvalho Chehab 			buf[2] = I2C_CONTROL_REG;
512*786baecfSMauro Carvalho Chehab 			buf[3] = 0x4E;
513*786baecfSMauro Carvalho Chehab 			buf[4] = (HWI2C400) ? 0x03 : 0x0D;
514*786baecfSMauro Carvalho Chehab 			ret = -EIO;
515*786baecfSMauro Carvalho Chehab 			goto exit;
516*786baecfSMauro Carvalho Chehab 		}
517*786baecfSMauro Carvalho Chehab 
518*786baecfSMauro Carvalho Chehab 		/* I2C interface can do I2C operations in block of 8 bytes of
519*786baecfSMauro Carvalho Chehab 		   I2C data. calculation to figure out number of blocks of i2c
520*786baecfSMauro Carvalho Chehab 		   data required to program */
521*786baecfSMauro Carvalho Chehab 		block_len = (msg->len / 8);
522*786baecfSMauro Carvalho Chehab 		left_over_len = (msg->len % 8);
523*786baecfSMauro Carvalho Chehab 		index = 0;
524*786baecfSMauro Carvalho Chehab 
525*786baecfSMauro Carvalho Chehab 		mxl_i2c("block_len %d, left_over_len %d",
526*786baecfSMauro Carvalho Chehab 			block_len, left_over_len);
527*786baecfSMauro Carvalho Chehab 
528*786baecfSMauro Carvalho Chehab 		for (index = 0; index < block_len; index++) {
529*786baecfSMauro Carvalho Chehab 			for (i = 0; i < 8; i++) {
530*786baecfSMauro Carvalho Chehab 				/* write data on I2C interface */
531*786baecfSMauro Carvalho Chehab 				buf[2+(i*3)] = I2C_DATA_REG;
532*786baecfSMauro Carvalho Chehab 				buf[3+(i*3)] = msg->buf[(index*8)+i];
533*786baecfSMauro Carvalho Chehab 				buf[4+(i*3)] = 0x00;
534*786baecfSMauro Carvalho Chehab 			}
535*786baecfSMauro Carvalho Chehab 
536*786baecfSMauro Carvalho Chehab 			ret = mxl111sf_i2c_send_data(state, 0, buf);
537*786baecfSMauro Carvalho Chehab 
538*786baecfSMauro Carvalho Chehab 			/* check for I2C NACK status */
539*786baecfSMauro Carvalho Chehab 			if (mxl111sf_i2c_check_status(state) == 1) {
540*786baecfSMauro Carvalho Chehab 				mxl_i2c("NACK writing slave address %02x",
541*786baecfSMauro Carvalho Chehab 					msg->addr);
542*786baecfSMauro Carvalho Chehab 
543*786baecfSMauro Carvalho Chehab 				/* if NACK, stop I2C bus and exit */
544*786baecfSMauro Carvalho Chehab 				buf[2] = I2C_CONTROL_REG;
545*786baecfSMauro Carvalho Chehab 				buf[3] = 0x4E;
546*786baecfSMauro Carvalho Chehab 				buf[4] = (HWI2C400) ? 0x03 : 0x0D;
547*786baecfSMauro Carvalho Chehab 				ret = -EIO;
548*786baecfSMauro Carvalho Chehab 				goto exit;
549*786baecfSMauro Carvalho Chehab 			}
550*786baecfSMauro Carvalho Chehab 
551*786baecfSMauro Carvalho Chehab 		}
552*786baecfSMauro Carvalho Chehab 
553*786baecfSMauro Carvalho Chehab 		if (left_over_len) {
554*786baecfSMauro Carvalho Chehab 			for (k = 0; k < 26; k++)
555*786baecfSMauro Carvalho Chehab 				buf[k] = USB_END_I2C_CMD;
556*786baecfSMauro Carvalho Chehab 
557*786baecfSMauro Carvalho Chehab 			buf[0] = 0x99;
558*786baecfSMauro Carvalho Chehab 			buf[1] = 0x00;
559*786baecfSMauro Carvalho Chehab 
560*786baecfSMauro Carvalho Chehab 			for (i = 0; i < left_over_len; i++) {
561*786baecfSMauro Carvalho Chehab 				buf[2+(i*3)] = I2C_DATA_REG;
562*786baecfSMauro Carvalho Chehab 				buf[3+(i*3)] = msg->buf[(index*8)+i];
563*786baecfSMauro Carvalho Chehab 				mxl_i2c("index = %d %d data %d",
564*786baecfSMauro Carvalho Chehab 					index, i, msg->buf[(index*8)+i]);
565*786baecfSMauro Carvalho Chehab 				buf[4+(i*3)] = 0x00;
566*786baecfSMauro Carvalho Chehab 			}
567*786baecfSMauro Carvalho Chehab 			ret = mxl111sf_i2c_send_data(state, 0, buf);
568*786baecfSMauro Carvalho Chehab 
569*786baecfSMauro Carvalho Chehab 			/* check for I2C NACK status */
570*786baecfSMauro Carvalho Chehab 			if (mxl111sf_i2c_check_status(state) == 1) {
571*786baecfSMauro Carvalho Chehab 				mxl_i2c("NACK writing slave address %02x",
572*786baecfSMauro Carvalho Chehab 					msg->addr);
573*786baecfSMauro Carvalho Chehab 
574*786baecfSMauro Carvalho Chehab 				/* if NACK, stop I2C bus and exit */
575*786baecfSMauro Carvalho Chehab 				buf[2] = I2C_CONTROL_REG;
576*786baecfSMauro Carvalho Chehab 				buf[3] = 0x4E;
577*786baecfSMauro Carvalho Chehab 				buf[4] = (HWI2C400) ? 0x03 : 0x0D;
578*786baecfSMauro Carvalho Chehab 				ret = -EIO;
579*786baecfSMauro Carvalho Chehab 				goto exit;
580*786baecfSMauro Carvalho Chehab 			}
581*786baecfSMauro Carvalho Chehab 
582*786baecfSMauro Carvalho Chehab 		}
583*786baecfSMauro Carvalho Chehab 
584*786baecfSMauro Carvalho Chehab 		/* issue I2C STOP after write */
585*786baecfSMauro Carvalho Chehab 		buf[2] = I2C_CONTROL_REG;
586*786baecfSMauro Carvalho Chehab 		buf[3] = 0x4E;
587*786baecfSMauro Carvalho Chehab 		buf[4] = (HWI2C400) ? 0x03 : 0x0D;
588*786baecfSMauro Carvalho Chehab 
589*786baecfSMauro Carvalho Chehab 	}
590*786baecfSMauro Carvalho Chehab 
591*786baecfSMauro Carvalho Chehab 	/* read data from I2C bus */
592*786baecfSMauro Carvalho Chehab 	if ((msg->flags & I2C_M_RD) && (msg->len > 0)) {
593*786baecfSMauro Carvalho Chehab 		mxl_i2c("read buf len %d", msg->len);
594*786baecfSMauro Carvalho Chehab 
595*786baecfSMauro Carvalho Chehab 		/* command to indicate data payload is
596*786baecfSMauro Carvalho Chehab 		   destined for I2C interface */
597*786baecfSMauro Carvalho Chehab 		buf[2] = I2C_CONTROL_REG;
598*786baecfSMauro Carvalho Chehab 		buf[3] = 0xDF;
599*786baecfSMauro Carvalho Chehab 		buf[4] = (HWI2C400) ? 0x03 : 0x0D;
600*786baecfSMauro Carvalho Chehab 
601*786baecfSMauro Carvalho Chehab 		/* I2C xfer length */
602*786baecfSMauro Carvalho Chehab 		buf[5] = 0x14;
603*786baecfSMauro Carvalho Chehab 		buf[6] = (msg->len & 0xFF);
604*786baecfSMauro Carvalho Chehab 		buf[7] = 0;
605*786baecfSMauro Carvalho Chehab 
606*786baecfSMauro Carvalho Chehab 		/* I2C slave device Address */
607*786baecfSMauro Carvalho Chehab 		buf[8] = I2C_SLAVE_ADDR_REG;
608*786baecfSMauro Carvalho Chehab 		buf[9] = msg->addr;
609*786baecfSMauro Carvalho Chehab 		buf[10] = 0x00;
610*786baecfSMauro Carvalho Chehab 		buf[11] = USB_END_I2C_CMD;
611*786baecfSMauro Carvalho Chehab 		ret = mxl111sf_i2c_send_data(state, 0, buf);
612*786baecfSMauro Carvalho Chehab 
613*786baecfSMauro Carvalho Chehab 		/* check for I2C NACK status */
614*786baecfSMauro Carvalho Chehab 		if (mxl111sf_i2c_check_status(state) == 1) {
615*786baecfSMauro Carvalho Chehab 			mxl_i2c("NACK reading slave address %02x",
616*786baecfSMauro Carvalho Chehab 				msg->addr);
617*786baecfSMauro Carvalho Chehab 
618*786baecfSMauro Carvalho Chehab 			/* if NACK, stop I2C bus and exit */
619*786baecfSMauro Carvalho Chehab 			buf[2] = I2C_CONTROL_REG;
620*786baecfSMauro Carvalho Chehab 			buf[3] = 0xC7;
621*786baecfSMauro Carvalho Chehab 			buf[4] = (HWI2C400) ? 0x03 : 0x0D;
622*786baecfSMauro Carvalho Chehab 			ret = -EIO;
623*786baecfSMauro Carvalho Chehab 			goto exit;
624*786baecfSMauro Carvalho Chehab 		}
625*786baecfSMauro Carvalho Chehab 
626*786baecfSMauro Carvalho Chehab 		/* I2C interface can do I2C operations in block of 8 bytes of
627*786baecfSMauro Carvalho Chehab 		   I2C data. calculation to figure out number of blocks of
628*786baecfSMauro Carvalho Chehab 		   i2c data required to program */
629*786baecfSMauro Carvalho Chehab 		block_len = ((msg->len) / 8);
630*786baecfSMauro Carvalho Chehab 		left_over_len = ((msg->len) % 8);
631*786baecfSMauro Carvalho Chehab 		index = 0;
632*786baecfSMauro Carvalho Chehab 
633*786baecfSMauro Carvalho Chehab 		mxl_i2c("block_len %d, left_over_len %d",
634*786baecfSMauro Carvalho Chehab 			block_len, left_over_len);
635*786baecfSMauro Carvalho Chehab 
636*786baecfSMauro Carvalho Chehab 		/* command to read data from I2C interface */
637*786baecfSMauro Carvalho Chehab 		buf[0] = USB_READ_I2C_CMD;
638*786baecfSMauro Carvalho Chehab 		buf[1] = 0x00;
639*786baecfSMauro Carvalho Chehab 
640*786baecfSMauro Carvalho Chehab 		for (index = 0; index < block_len; index++) {
641*786baecfSMauro Carvalho Chehab 			/* setup I2C read request packet on I2C interface */
642*786baecfSMauro Carvalho Chehab 			for (i = 0; i < 8; i++) {
643*786baecfSMauro Carvalho Chehab 				buf[2+(i*3)] = I2C_DATA_REG;
644*786baecfSMauro Carvalho Chehab 				buf[3+(i*3)] = 0x00;
645*786baecfSMauro Carvalho Chehab 				buf[4+(i*3)] = 0x00;
646*786baecfSMauro Carvalho Chehab 			}
647*786baecfSMauro Carvalho Chehab 
648*786baecfSMauro Carvalho Chehab 			ret = mxl111sf_i2c_get_data(state, 0, buf, i2c_r_data);
649*786baecfSMauro Carvalho Chehab 
650*786baecfSMauro Carvalho Chehab 			/* check for I2C NACK status */
651*786baecfSMauro Carvalho Chehab 			if (mxl111sf_i2c_check_status(state) == 1) {
652*786baecfSMauro Carvalho Chehab 				mxl_i2c("NACK reading slave address %02x",
653*786baecfSMauro Carvalho Chehab 					msg->addr);
654*786baecfSMauro Carvalho Chehab 
655*786baecfSMauro Carvalho Chehab 				/* if NACK, stop I2C bus and exit */
656*786baecfSMauro Carvalho Chehab 				buf[2] = I2C_CONTROL_REG;
657*786baecfSMauro Carvalho Chehab 				buf[3] = 0xC7;
658*786baecfSMauro Carvalho Chehab 				buf[4] = (HWI2C400) ? 0x03 : 0x0D;
659*786baecfSMauro Carvalho Chehab 				ret = -EIO;
660*786baecfSMauro Carvalho Chehab 				goto exit;
661*786baecfSMauro Carvalho Chehab 			}
662*786baecfSMauro Carvalho Chehab 
663*786baecfSMauro Carvalho Chehab 			/* copy data from i2c data payload to read buffer */
664*786baecfSMauro Carvalho Chehab 			for (i = 0; i < 8; i++) {
665*786baecfSMauro Carvalho Chehab 				rd_status[i] = i2c_r_data[(i*3)+2];
666*786baecfSMauro Carvalho Chehab 
667*786baecfSMauro Carvalho Chehab 				if (rd_status[i] == 0x04) {
668*786baecfSMauro Carvalho Chehab 					if (i < 7) {
669*786baecfSMauro Carvalho Chehab 						mxl_i2c("i2c fifo empty!"
670*786baecfSMauro Carvalho Chehab 							" @ %d", i);
671*786baecfSMauro Carvalho Chehab 						msg->buf[(index*8)+i] =
672*786baecfSMauro Carvalho Chehab 							i2c_r_data[(i*3)+1];
673*786baecfSMauro Carvalho Chehab 						/* read again */
674*786baecfSMauro Carvalho Chehab 						ret_status =
675*786baecfSMauro Carvalho Chehab 							mxl111sf_i2c_readagain(
676*786baecfSMauro Carvalho Chehab 								state, 8-(i+1),
677*786baecfSMauro Carvalho Chehab 								readbuff);
678*786baecfSMauro Carvalho Chehab 						if (ret_status == 1) {
679*786baecfSMauro Carvalho Chehab 							for (k = 0;
680*786baecfSMauro Carvalho Chehab 							     k < 8-(i+1);
681*786baecfSMauro Carvalho Chehab 							     k++) {
682*786baecfSMauro Carvalho Chehab 
683*786baecfSMauro Carvalho Chehab 					msg->buf[(index*8)+(k+i+1)] =
684*786baecfSMauro Carvalho Chehab 						readbuff[k];
685*786baecfSMauro Carvalho Chehab 					mxl_i2c("read data: %02x\t %02x",
686*786baecfSMauro Carvalho Chehab 						msg->buf[(index*8)+(k+i)],
687*786baecfSMauro Carvalho Chehab 						(index*8)+(k+i));
688*786baecfSMauro Carvalho Chehab 					mxl_i2c("read data: %02x\t %02x",
689*786baecfSMauro Carvalho Chehab 						msg->buf[(index*8)+(k+i+1)],
690*786baecfSMauro Carvalho Chehab 						readbuff[k]);
691*786baecfSMauro Carvalho Chehab 
692*786baecfSMauro Carvalho Chehab 							}
693*786baecfSMauro Carvalho Chehab 							goto stop_copy;
694*786baecfSMauro Carvalho Chehab 						} else {
695*786baecfSMauro Carvalho Chehab 							mxl_i2c("readagain "
696*786baecfSMauro Carvalho Chehab 								"ERROR!");
697*786baecfSMauro Carvalho Chehab 						}
698*786baecfSMauro Carvalho Chehab 					} else {
699*786baecfSMauro Carvalho Chehab 						msg->buf[(index*8)+i] =
700*786baecfSMauro Carvalho Chehab 							i2c_r_data[(i*3)+1];
701*786baecfSMauro Carvalho Chehab 					}
702*786baecfSMauro Carvalho Chehab 				} else {
703*786baecfSMauro Carvalho Chehab 					msg->buf[(index*8)+i] =
704*786baecfSMauro Carvalho Chehab 						i2c_r_data[(i*3)+1];
705*786baecfSMauro Carvalho Chehab 				}
706*786baecfSMauro Carvalho Chehab 			}
707*786baecfSMauro Carvalho Chehab stop_copy:
708*786baecfSMauro Carvalho Chehab 			;
709*786baecfSMauro Carvalho Chehab 
710*786baecfSMauro Carvalho Chehab 		}
711*786baecfSMauro Carvalho Chehab 
712*786baecfSMauro Carvalho Chehab 		if (left_over_len) {
713*786baecfSMauro Carvalho Chehab 			for (k = 0; k < 26; k++)
714*786baecfSMauro Carvalho Chehab 				buf[k] = USB_END_I2C_CMD;
715*786baecfSMauro Carvalho Chehab 
716*786baecfSMauro Carvalho Chehab 			buf[0] = 0xDD;
717*786baecfSMauro Carvalho Chehab 			buf[1] = 0x00;
718*786baecfSMauro Carvalho Chehab 
719*786baecfSMauro Carvalho Chehab 			for (i = 0; i < left_over_len; i++) {
720*786baecfSMauro Carvalho Chehab 				buf[2+(i*3)] = I2C_DATA_REG;
721*786baecfSMauro Carvalho Chehab 				buf[3+(i*3)] = 0x00;
722*786baecfSMauro Carvalho Chehab 				buf[4+(i*3)] = 0x00;
723*786baecfSMauro Carvalho Chehab 			}
724*786baecfSMauro Carvalho Chehab 			ret = mxl111sf_i2c_get_data(state, 0, buf,
725*786baecfSMauro Carvalho Chehab 						    i2c_r_data);
726*786baecfSMauro Carvalho Chehab 
727*786baecfSMauro Carvalho Chehab 			/* check for I2C NACK status */
728*786baecfSMauro Carvalho Chehab 			if (mxl111sf_i2c_check_status(state) == 1) {
729*786baecfSMauro Carvalho Chehab 				mxl_i2c("NACK reading slave address %02x",
730*786baecfSMauro Carvalho Chehab 					msg->addr);
731*786baecfSMauro Carvalho Chehab 
732*786baecfSMauro Carvalho Chehab 				/* if NACK, stop I2C bus and exit */
733*786baecfSMauro Carvalho Chehab 				buf[2] = I2C_CONTROL_REG;
734*786baecfSMauro Carvalho Chehab 				buf[3] = 0xC7;
735*786baecfSMauro Carvalho Chehab 				buf[4] = (HWI2C400) ? 0x03 : 0x0D;
736*786baecfSMauro Carvalho Chehab 				ret = -EIO;
737*786baecfSMauro Carvalho Chehab 				goto exit;
738*786baecfSMauro Carvalho Chehab 			}
739*786baecfSMauro Carvalho Chehab 
740*786baecfSMauro Carvalho Chehab 			for (i = 0; i < left_over_len; i++) {
741*786baecfSMauro Carvalho Chehab 				msg->buf[(block_len*8)+i] =
742*786baecfSMauro Carvalho Chehab 					i2c_r_data[(i*3)+1];
743*786baecfSMauro Carvalho Chehab 				mxl_i2c("read data: %02x\t %02x",
744*786baecfSMauro Carvalho Chehab 					i2c_r_data[(i*3)+1],
745*786baecfSMauro Carvalho Chehab 					i2c_r_data[(i*3)+2]);
746*786baecfSMauro Carvalho Chehab 			}
747*786baecfSMauro Carvalho Chehab 		}
748*786baecfSMauro Carvalho Chehab 
749*786baecfSMauro Carvalho Chehab 		/* indicate I2C interface to issue NACK
750*786baecfSMauro Carvalho Chehab 		   after next I2C read op */
751*786baecfSMauro Carvalho Chehab 		buf[0] = USB_WRITE_I2C_CMD;
752*786baecfSMauro Carvalho Chehab 		buf[1] = 0x00;
753*786baecfSMauro Carvalho Chehab 
754*786baecfSMauro Carvalho Chehab 		/* control register */
755*786baecfSMauro Carvalho Chehab 		buf[2] = I2C_CONTROL_REG;
756*786baecfSMauro Carvalho Chehab 		buf[3] = 0x17;
757*786baecfSMauro Carvalho Chehab 		buf[4] = (HWI2C400) ? 0x03 : 0x0D;
758*786baecfSMauro Carvalho Chehab 
759*786baecfSMauro Carvalho Chehab 		buf[5] = USB_END_I2C_CMD;
760*786baecfSMauro Carvalho Chehab 		ret = mxl111sf_i2c_send_data(state, 0, buf);
761*786baecfSMauro Carvalho Chehab 
762*786baecfSMauro Carvalho Chehab 		/* control register */
763*786baecfSMauro Carvalho Chehab 		buf[2] = I2C_CONTROL_REG;
764*786baecfSMauro Carvalho Chehab 		buf[3] = 0xC7;
765*786baecfSMauro Carvalho Chehab 		buf[4] = (HWI2C400) ? 0x03 : 0x0D;
766*786baecfSMauro Carvalho Chehab 
767*786baecfSMauro Carvalho Chehab 	}
768*786baecfSMauro Carvalho Chehab exit:
769*786baecfSMauro Carvalho Chehab 	/* STOP and disable I2C MUX */
770*786baecfSMauro Carvalho Chehab 	buf[0] = USB_WRITE_I2C_CMD;
771*786baecfSMauro Carvalho Chehab 	buf[1] = 0x00;
772*786baecfSMauro Carvalho Chehab 
773*786baecfSMauro Carvalho Chehab 	/* de-initilize I2C BUS */
774*786baecfSMauro Carvalho Chehab 	buf[5] = USB_END_I2C_CMD;
775*786baecfSMauro Carvalho Chehab 	mxl111sf_i2c_send_data(state, 0, buf);
776*786baecfSMauro Carvalho Chehab 
777*786baecfSMauro Carvalho Chehab 	/* Control Register */
778*786baecfSMauro Carvalho Chehab 	buf[2] = I2C_CONTROL_REG;
779*786baecfSMauro Carvalho Chehab 	buf[3] = 0xDF;
780*786baecfSMauro Carvalho Chehab 	buf[4] = 0x03;
781*786baecfSMauro Carvalho Chehab 
782*786baecfSMauro Carvalho Chehab 	/* disable I2C interface */
783*786baecfSMauro Carvalho Chehab 	buf[5] = I2C_MUX_REG;
784*786baecfSMauro Carvalho Chehab 	buf[6] = 0x00;
785*786baecfSMauro Carvalho Chehab 	buf[7] = 0x00;
786*786baecfSMauro Carvalho Chehab 
787*786baecfSMauro Carvalho Chehab 	/* de-initilize I2C BUS */
788*786baecfSMauro Carvalho Chehab 	buf[8] = USB_END_I2C_CMD;
789*786baecfSMauro Carvalho Chehab 	mxl111sf_i2c_send_data(state, 0, buf);
790*786baecfSMauro Carvalho Chehab 
791*786baecfSMauro Carvalho Chehab 	/* disable I2C interface */
792*786baecfSMauro Carvalho Chehab 	buf[2] = I2C_MUX_REG;
793*786baecfSMauro Carvalho Chehab 	buf[3] = 0x81;
794*786baecfSMauro Carvalho Chehab 	buf[4] = 0x00;
795*786baecfSMauro Carvalho Chehab 
796*786baecfSMauro Carvalho Chehab 	/* disable I2C interface */
797*786baecfSMauro Carvalho Chehab 	buf[5] = I2C_MUX_REG;
798*786baecfSMauro Carvalho Chehab 	buf[6] = 0x00;
799*786baecfSMauro Carvalho Chehab 	buf[7] = 0x00;
800*786baecfSMauro Carvalho Chehab 
801*786baecfSMauro Carvalho Chehab 	/* disable I2C interface */
802*786baecfSMauro Carvalho Chehab 	buf[8] = I2C_MUX_REG;
803*786baecfSMauro Carvalho Chehab 	buf[9] = 0x00;
804*786baecfSMauro Carvalho Chehab 	buf[10] = 0x00;
805*786baecfSMauro Carvalho Chehab 
806*786baecfSMauro Carvalho Chehab 	buf[11] = USB_END_I2C_CMD;
807*786baecfSMauro Carvalho Chehab 	mxl111sf_i2c_send_data(state, 0, buf);
808*786baecfSMauro Carvalho Chehab 
809*786baecfSMauro Carvalho Chehab 	return ret;
810*786baecfSMauro Carvalho Chehab }
811*786baecfSMauro Carvalho Chehab 
812*786baecfSMauro Carvalho Chehab /* ------------------------------------------------------------------------ */
813*786baecfSMauro Carvalho Chehab 
814*786baecfSMauro Carvalho Chehab int mxl111sf_i2c_xfer(struct i2c_adapter *adap,
815*786baecfSMauro Carvalho Chehab 		      struct i2c_msg msg[], int num)
816*786baecfSMauro Carvalho Chehab {
817*786baecfSMauro Carvalho Chehab 	struct dvb_usb_device *d = i2c_get_adapdata(adap);
818*786baecfSMauro Carvalho Chehab 	struct mxl111sf_state *state = d->priv;
819*786baecfSMauro Carvalho Chehab 	int hwi2c = (state->chip_rev > MXL111SF_V6);
820*786baecfSMauro Carvalho Chehab 	int i, ret;
821*786baecfSMauro Carvalho Chehab 
822*786baecfSMauro Carvalho Chehab 	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
823*786baecfSMauro Carvalho Chehab 		return -EAGAIN;
824*786baecfSMauro Carvalho Chehab 
825*786baecfSMauro Carvalho Chehab 	for (i = 0; i < num; i++) {
826*786baecfSMauro Carvalho Chehab 		ret = (hwi2c) ?
827*786baecfSMauro Carvalho Chehab 			mxl111sf_i2c_hw_xfer_msg(state, &msg[i]) :
828*786baecfSMauro Carvalho Chehab 			mxl111sf_i2c_sw_xfer_msg(state, &msg[i]);
829*786baecfSMauro Carvalho Chehab 		if (mxl_fail(ret)) {
830*786baecfSMauro Carvalho Chehab 			mxl_debug_adv("failed with error %d on i2c "
831*786baecfSMauro Carvalho Chehab 				      "transaction %d of %d, %sing %d bytes "
832*786baecfSMauro Carvalho Chehab 				      "to/from 0x%02x", ret, i+1, num,
833*786baecfSMauro Carvalho Chehab 				      (msg[i].flags & I2C_M_RD) ?
834*786baecfSMauro Carvalho Chehab 				      "read" : "writ",
835*786baecfSMauro Carvalho Chehab 				      msg[i].len, msg[i].addr);
836*786baecfSMauro Carvalho Chehab 
837*786baecfSMauro Carvalho Chehab 			break;
838*786baecfSMauro Carvalho Chehab 		}
839*786baecfSMauro Carvalho Chehab 	}
840*786baecfSMauro Carvalho Chehab 
841*786baecfSMauro Carvalho Chehab 	mutex_unlock(&d->i2c_mutex);
842*786baecfSMauro Carvalho Chehab 
843*786baecfSMauro Carvalho Chehab 	return i == num ? num : -EREMOTEIO;
844*786baecfSMauro Carvalho Chehab }
845*786baecfSMauro Carvalho Chehab 
846*786baecfSMauro Carvalho Chehab /*
847*786baecfSMauro Carvalho Chehab  * Local variables:
848*786baecfSMauro Carvalho Chehab  * c-basic-offset: 8
849*786baecfSMauro Carvalho Chehab  * End:
850*786baecfSMauro Carvalho Chehab  */
851