xref: /rk3399_rockchip-uboot/drivers/i2c/davinci_i2c.c (revision 1a4596601fd395f3afb8f82f3f840c5e00bdd57a)
1942ba996SJean-Christophe PLAGNIOL-VILLARD /*
2942ba996SJean-Christophe PLAGNIOL-VILLARD  * TI DaVinci (TMS320DM644x) I2C driver.
3942ba996SJean-Christophe PLAGNIOL-VILLARD  *
4942ba996SJean-Christophe PLAGNIOL-VILLARD  * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
5942ba996SJean-Christophe PLAGNIOL-VILLARD  *
6942ba996SJean-Christophe PLAGNIOL-VILLARD  * --------------------------------------------------------
7942ba996SJean-Christophe PLAGNIOL-VILLARD  *
8*1a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
9942ba996SJean-Christophe PLAGNIOL-VILLARD  */
10942ba996SJean-Christophe PLAGNIOL-VILLARD 
11942ba996SJean-Christophe PLAGNIOL-VILLARD #include <common.h>
12942ba996SJean-Christophe PLAGNIOL-VILLARD #include <i2c.h>
13942ba996SJean-Christophe PLAGNIOL-VILLARD #include <asm/arch/hardware.h>
14942ba996SJean-Christophe PLAGNIOL-VILLARD #include <asm/arch/i2c_defs.h>
15942ba996SJean-Christophe PLAGNIOL-VILLARD 
16942ba996SJean-Christophe PLAGNIOL-VILLARD #define CHECK_NACK() \
17942ba996SJean-Christophe PLAGNIOL-VILLARD 	do {\
18942ba996SJean-Christophe PLAGNIOL-VILLARD 		if (tmp & (I2C_TIMEOUT | I2C_STAT_NACK)) {\
19942ba996SJean-Christophe PLAGNIOL-VILLARD 			REG(I2C_CON) = 0;\
20942ba996SJean-Christophe PLAGNIOL-VILLARD 			return(1);\
21942ba996SJean-Christophe PLAGNIOL-VILLARD 		}\
22942ba996SJean-Christophe PLAGNIOL-VILLARD 	} while (0)
23942ba996SJean-Christophe PLAGNIOL-VILLARD 
24942ba996SJean-Christophe PLAGNIOL-VILLARD 
25942ba996SJean-Christophe PLAGNIOL-VILLARD static int wait_for_bus(void)
26942ba996SJean-Christophe PLAGNIOL-VILLARD {
27942ba996SJean-Christophe PLAGNIOL-VILLARD 	int	stat, timeout;
28942ba996SJean-Christophe PLAGNIOL-VILLARD 
29942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_STAT) = 0xffff;
30942ba996SJean-Christophe PLAGNIOL-VILLARD 
31942ba996SJean-Christophe PLAGNIOL-VILLARD 	for (timeout = 0; timeout < 10; timeout++) {
32942ba996SJean-Christophe PLAGNIOL-VILLARD 		if (!((stat = REG(I2C_STAT)) & I2C_STAT_BB)) {
33942ba996SJean-Christophe PLAGNIOL-VILLARD 			REG(I2C_STAT) = 0xffff;
34942ba996SJean-Christophe PLAGNIOL-VILLARD 			return(0);
35942ba996SJean-Christophe PLAGNIOL-VILLARD 		}
36942ba996SJean-Christophe PLAGNIOL-VILLARD 
37942ba996SJean-Christophe PLAGNIOL-VILLARD 		REG(I2C_STAT) = stat;
38942ba996SJean-Christophe PLAGNIOL-VILLARD 		udelay(50000);
39942ba996SJean-Christophe PLAGNIOL-VILLARD 	}
40942ba996SJean-Christophe PLAGNIOL-VILLARD 
41942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_STAT) = 0xffff;
42942ba996SJean-Christophe PLAGNIOL-VILLARD 	return(1);
43942ba996SJean-Christophe PLAGNIOL-VILLARD }
44942ba996SJean-Christophe PLAGNIOL-VILLARD 
45942ba996SJean-Christophe PLAGNIOL-VILLARD 
46942ba996SJean-Christophe PLAGNIOL-VILLARD static int poll_i2c_irq(int mask)
47942ba996SJean-Christophe PLAGNIOL-VILLARD {
48942ba996SJean-Christophe PLAGNIOL-VILLARD 	int	stat, timeout;
49942ba996SJean-Christophe PLAGNIOL-VILLARD 
50942ba996SJean-Christophe PLAGNIOL-VILLARD 	for (timeout = 0; timeout < 10; timeout++) {
51942ba996SJean-Christophe PLAGNIOL-VILLARD 		udelay(1000);
52942ba996SJean-Christophe PLAGNIOL-VILLARD 		stat = REG(I2C_STAT);
53942ba996SJean-Christophe PLAGNIOL-VILLARD 		if (stat & mask) {
54942ba996SJean-Christophe PLAGNIOL-VILLARD 			return(stat);
55942ba996SJean-Christophe PLAGNIOL-VILLARD 		}
56942ba996SJean-Christophe PLAGNIOL-VILLARD 	}
57942ba996SJean-Christophe PLAGNIOL-VILLARD 
58942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_STAT) = 0xffff;
59942ba996SJean-Christophe PLAGNIOL-VILLARD 	return(stat | I2C_TIMEOUT);
60942ba996SJean-Christophe PLAGNIOL-VILLARD }
61942ba996SJean-Christophe PLAGNIOL-VILLARD 
62942ba996SJean-Christophe PLAGNIOL-VILLARD 
63942ba996SJean-Christophe PLAGNIOL-VILLARD void flush_rx(void)
64942ba996SJean-Christophe PLAGNIOL-VILLARD {
65942ba996SJean-Christophe PLAGNIOL-VILLARD 	while (1) {
66942ba996SJean-Christophe PLAGNIOL-VILLARD 		if (!(REG(I2C_STAT) & I2C_STAT_RRDY))
67942ba996SJean-Christophe PLAGNIOL-VILLARD 			break;
68942ba996SJean-Christophe PLAGNIOL-VILLARD 
69bd0f5ca8SAnatolij Gustschin 		REG(I2C_DRR);
70942ba996SJean-Christophe PLAGNIOL-VILLARD 		REG(I2C_STAT) = I2C_STAT_RRDY;
71942ba996SJean-Christophe PLAGNIOL-VILLARD 		udelay(1000);
72942ba996SJean-Christophe PLAGNIOL-VILLARD 	}
73942ba996SJean-Christophe PLAGNIOL-VILLARD }
74942ba996SJean-Christophe PLAGNIOL-VILLARD 
75942ba996SJean-Christophe PLAGNIOL-VILLARD 
76942ba996SJean-Christophe PLAGNIOL-VILLARD void i2c_init(int speed, int slaveadd)
77942ba996SJean-Christophe PLAGNIOL-VILLARD {
78942ba996SJean-Christophe PLAGNIOL-VILLARD 	u_int32_t	div, psc;
79942ba996SJean-Christophe PLAGNIOL-VILLARD 
80942ba996SJean-Christophe PLAGNIOL-VILLARD 	if (REG(I2C_CON) & I2C_CON_EN) {
81942ba996SJean-Christophe PLAGNIOL-VILLARD 		REG(I2C_CON) = 0;
82942ba996SJean-Christophe PLAGNIOL-VILLARD 		udelay (50000);
83942ba996SJean-Christophe PLAGNIOL-VILLARD 	}
84942ba996SJean-Christophe PLAGNIOL-VILLARD 
85942ba996SJean-Christophe PLAGNIOL-VILLARD 	psc = 2;
86942ba996SJean-Christophe PLAGNIOL-VILLARD 	div = (CONFIG_SYS_HZ_CLOCK / ((psc + 1) * speed)) - 10;	/* SCLL + SCLH */
87942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_PSC) = psc;			/* 27MHz / (2 + 1) = 9MHz */
88942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_SCLL) = (div * 50) / 100;	/* 50% Duty */
89942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_SCLH) = div - REG(I2C_SCLL);
90942ba996SJean-Christophe PLAGNIOL-VILLARD 
91942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_OA) = slaveadd;
92942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_CNT) = 0;
93942ba996SJean-Christophe PLAGNIOL-VILLARD 
94942ba996SJean-Christophe PLAGNIOL-VILLARD 	/* Interrupts must be enabled or I2C module won't work */
95942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_IE) = I2C_IE_SCD_IE | I2C_IE_XRDY_IE |
96942ba996SJean-Christophe PLAGNIOL-VILLARD 		I2C_IE_RRDY_IE | I2C_IE_ARDY_IE | I2C_IE_NACK_IE;
97942ba996SJean-Christophe PLAGNIOL-VILLARD 
98942ba996SJean-Christophe PLAGNIOL-VILLARD 	/* Now enable I2C controller (get it out of reset) */
99942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_CON) = I2C_CON_EN;
100942ba996SJean-Christophe PLAGNIOL-VILLARD 
101942ba996SJean-Christophe PLAGNIOL-VILLARD 	udelay(1000);
102942ba996SJean-Christophe PLAGNIOL-VILLARD }
103942ba996SJean-Christophe PLAGNIOL-VILLARD 
10449d6da60SHeiko Schocher int i2c_set_bus_speed(unsigned int speed)
10549d6da60SHeiko Schocher {
10649d6da60SHeiko Schocher 	i2c_init(speed, CONFIG_SYS_I2C_SLAVE);
10749d6da60SHeiko Schocher 	return 0;
10849d6da60SHeiko Schocher }
109942ba996SJean-Christophe PLAGNIOL-VILLARD 
110942ba996SJean-Christophe PLAGNIOL-VILLARD int i2c_probe(u_int8_t chip)
111942ba996SJean-Christophe PLAGNIOL-VILLARD {
112942ba996SJean-Christophe PLAGNIOL-VILLARD 	int	rc = 1;
113942ba996SJean-Christophe PLAGNIOL-VILLARD 
114942ba996SJean-Christophe PLAGNIOL-VILLARD 	if (chip == REG(I2C_OA)) {
115942ba996SJean-Christophe PLAGNIOL-VILLARD 		return(rc);
116942ba996SJean-Christophe PLAGNIOL-VILLARD 	}
117942ba996SJean-Christophe PLAGNIOL-VILLARD 
118942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_CON) = 0;
119942ba996SJean-Christophe PLAGNIOL-VILLARD 	if (wait_for_bus()) {return(1);}
120942ba996SJean-Christophe PLAGNIOL-VILLARD 
121942ba996SJean-Christophe PLAGNIOL-VILLARD 	/* try to read one byte from current (or only) address */
122942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_CNT) = 1;
123942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_SA) = chip;
124942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_CON) = (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP);
125942ba996SJean-Christophe PLAGNIOL-VILLARD 	udelay (50000);
126942ba996SJean-Christophe PLAGNIOL-VILLARD 
127942ba996SJean-Christophe PLAGNIOL-VILLARD 	if (!(REG(I2C_STAT) & I2C_STAT_NACK)) {
128942ba996SJean-Christophe PLAGNIOL-VILLARD 		rc = 0;
129942ba996SJean-Christophe PLAGNIOL-VILLARD 		flush_rx();
130942ba996SJean-Christophe PLAGNIOL-VILLARD 		REG(I2C_STAT) = 0xffff;
131942ba996SJean-Christophe PLAGNIOL-VILLARD 	} else {
132942ba996SJean-Christophe PLAGNIOL-VILLARD 		REG(I2C_STAT) = 0xffff;
133942ba996SJean-Christophe PLAGNIOL-VILLARD 		REG(I2C_CON) |= I2C_CON_STP;
134942ba996SJean-Christophe PLAGNIOL-VILLARD 		udelay(20000);
135942ba996SJean-Christophe PLAGNIOL-VILLARD 		if (wait_for_bus()) {return(1);}
136942ba996SJean-Christophe PLAGNIOL-VILLARD 	}
137942ba996SJean-Christophe PLAGNIOL-VILLARD 
138942ba996SJean-Christophe PLAGNIOL-VILLARD 	flush_rx();
139942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_STAT) = 0xffff;
140942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_CNT) = 0;
141942ba996SJean-Christophe PLAGNIOL-VILLARD 	return(rc);
142942ba996SJean-Christophe PLAGNIOL-VILLARD }
143942ba996SJean-Christophe PLAGNIOL-VILLARD 
144942ba996SJean-Christophe PLAGNIOL-VILLARD 
145942ba996SJean-Christophe PLAGNIOL-VILLARD int i2c_read(u_int8_t chip, u_int32_t addr, int alen, u_int8_t *buf, int len)
146942ba996SJean-Christophe PLAGNIOL-VILLARD {
147942ba996SJean-Christophe PLAGNIOL-VILLARD 	u_int32_t	tmp;
148942ba996SJean-Christophe PLAGNIOL-VILLARD 	int		i;
149942ba996SJean-Christophe PLAGNIOL-VILLARD 
150942ba996SJean-Christophe PLAGNIOL-VILLARD 	if ((alen < 0) || (alen > 2)) {
151942ba996SJean-Christophe PLAGNIOL-VILLARD 		printf("%s(): bogus address length %x\n", __FUNCTION__, alen);
152942ba996SJean-Christophe PLAGNIOL-VILLARD 		return(1);
153942ba996SJean-Christophe PLAGNIOL-VILLARD 	}
154942ba996SJean-Christophe PLAGNIOL-VILLARD 
155942ba996SJean-Christophe PLAGNIOL-VILLARD 	if (wait_for_bus()) {return(1);}
156942ba996SJean-Christophe PLAGNIOL-VILLARD 
157942ba996SJean-Christophe PLAGNIOL-VILLARD 	if (alen != 0) {
158942ba996SJean-Christophe PLAGNIOL-VILLARD 		/* Start address phase */
159942ba996SJean-Christophe PLAGNIOL-VILLARD 		tmp = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX;
160942ba996SJean-Christophe PLAGNIOL-VILLARD 		REG(I2C_CNT) = alen;
161942ba996SJean-Christophe PLAGNIOL-VILLARD 		REG(I2C_SA) = chip;
162942ba996SJean-Christophe PLAGNIOL-VILLARD 		REG(I2C_CON) = tmp;
163942ba996SJean-Christophe PLAGNIOL-VILLARD 
164942ba996SJean-Christophe PLAGNIOL-VILLARD 		tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK);
165942ba996SJean-Christophe PLAGNIOL-VILLARD 
166942ba996SJean-Christophe PLAGNIOL-VILLARD 		CHECK_NACK();
167942ba996SJean-Christophe PLAGNIOL-VILLARD 
168942ba996SJean-Christophe PLAGNIOL-VILLARD 		switch (alen) {
169942ba996SJean-Christophe PLAGNIOL-VILLARD 			case 2:
170942ba996SJean-Christophe PLAGNIOL-VILLARD 				/* Send address MSByte */
171942ba996SJean-Christophe PLAGNIOL-VILLARD 				if (tmp & I2C_STAT_XRDY) {
172942ba996SJean-Christophe PLAGNIOL-VILLARD 					REG(I2C_DXR) = (addr >> 8) & 0xff;
173942ba996SJean-Christophe PLAGNIOL-VILLARD 				} else {
174942ba996SJean-Christophe PLAGNIOL-VILLARD 					REG(I2C_CON) = 0;
175942ba996SJean-Christophe PLAGNIOL-VILLARD 					return(1);
176942ba996SJean-Christophe PLAGNIOL-VILLARD 				}
177942ba996SJean-Christophe PLAGNIOL-VILLARD 
178942ba996SJean-Christophe PLAGNIOL-VILLARD 				tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK);
179942ba996SJean-Christophe PLAGNIOL-VILLARD 
180942ba996SJean-Christophe PLAGNIOL-VILLARD 				CHECK_NACK();
181942ba996SJean-Christophe PLAGNIOL-VILLARD 				/* No break, fall through */
182942ba996SJean-Christophe PLAGNIOL-VILLARD 			case 1:
183942ba996SJean-Christophe PLAGNIOL-VILLARD 				/* Send address LSByte */
184942ba996SJean-Christophe PLAGNIOL-VILLARD 				if (tmp & I2C_STAT_XRDY) {
185942ba996SJean-Christophe PLAGNIOL-VILLARD 					REG(I2C_DXR) = addr & 0xff;
186942ba996SJean-Christophe PLAGNIOL-VILLARD 				} else {
187942ba996SJean-Christophe PLAGNIOL-VILLARD 					REG(I2C_CON) = 0;
188942ba996SJean-Christophe PLAGNIOL-VILLARD 					return(1);
189942ba996SJean-Christophe PLAGNIOL-VILLARD 				}
190942ba996SJean-Christophe PLAGNIOL-VILLARD 
191942ba996SJean-Christophe PLAGNIOL-VILLARD 				tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK | I2C_STAT_ARDY);
192942ba996SJean-Christophe PLAGNIOL-VILLARD 
193942ba996SJean-Christophe PLAGNIOL-VILLARD 				CHECK_NACK();
194942ba996SJean-Christophe PLAGNIOL-VILLARD 
195942ba996SJean-Christophe PLAGNIOL-VILLARD 				if (!(tmp & I2C_STAT_ARDY)) {
196942ba996SJean-Christophe PLAGNIOL-VILLARD 					REG(I2C_CON) = 0;
197942ba996SJean-Christophe PLAGNIOL-VILLARD 					return(1);
198942ba996SJean-Christophe PLAGNIOL-VILLARD 				}
199942ba996SJean-Christophe PLAGNIOL-VILLARD 		}
200942ba996SJean-Christophe PLAGNIOL-VILLARD 	}
201942ba996SJean-Christophe PLAGNIOL-VILLARD 
202942ba996SJean-Christophe PLAGNIOL-VILLARD 	/* Address phase is over, now read 'len' bytes and stop */
203942ba996SJean-Christophe PLAGNIOL-VILLARD 	tmp = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP;
204942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_CNT) = len & 0xffff;
205942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_SA) = chip;
206942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_CON) = tmp;
207942ba996SJean-Christophe PLAGNIOL-VILLARD 
208942ba996SJean-Christophe PLAGNIOL-VILLARD 	for (i = 0; i < len; i++) {
209942ba996SJean-Christophe PLAGNIOL-VILLARD 		tmp = poll_i2c_irq(I2C_STAT_RRDY | I2C_STAT_NACK | I2C_STAT_ROVR);
210942ba996SJean-Christophe PLAGNIOL-VILLARD 
211942ba996SJean-Christophe PLAGNIOL-VILLARD 		CHECK_NACK();
212942ba996SJean-Christophe PLAGNIOL-VILLARD 
213942ba996SJean-Christophe PLAGNIOL-VILLARD 		if (tmp & I2C_STAT_RRDY) {
214942ba996SJean-Christophe PLAGNIOL-VILLARD 			buf[i] = REG(I2C_DRR);
215942ba996SJean-Christophe PLAGNIOL-VILLARD 		} else {
216942ba996SJean-Christophe PLAGNIOL-VILLARD 			REG(I2C_CON) = 0;
217942ba996SJean-Christophe PLAGNIOL-VILLARD 			return(1);
218942ba996SJean-Christophe PLAGNIOL-VILLARD 		}
219942ba996SJean-Christophe PLAGNIOL-VILLARD 	}
220942ba996SJean-Christophe PLAGNIOL-VILLARD 
221942ba996SJean-Christophe PLAGNIOL-VILLARD 	tmp = poll_i2c_irq(I2C_STAT_SCD | I2C_STAT_NACK);
222942ba996SJean-Christophe PLAGNIOL-VILLARD 
223942ba996SJean-Christophe PLAGNIOL-VILLARD 	CHECK_NACK();
224942ba996SJean-Christophe PLAGNIOL-VILLARD 
225942ba996SJean-Christophe PLAGNIOL-VILLARD 	if (!(tmp & I2C_STAT_SCD)) {
226942ba996SJean-Christophe PLAGNIOL-VILLARD 		REG(I2C_CON) = 0;
227942ba996SJean-Christophe PLAGNIOL-VILLARD 		return(1);
228942ba996SJean-Christophe PLAGNIOL-VILLARD 	}
229942ba996SJean-Christophe PLAGNIOL-VILLARD 
230942ba996SJean-Christophe PLAGNIOL-VILLARD 	flush_rx();
231942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_STAT) = 0xffff;
232942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_CNT) = 0;
233942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_CON) = 0;
234942ba996SJean-Christophe PLAGNIOL-VILLARD 
235942ba996SJean-Christophe PLAGNIOL-VILLARD 	return(0);
236942ba996SJean-Christophe PLAGNIOL-VILLARD }
237942ba996SJean-Christophe PLAGNIOL-VILLARD 
238942ba996SJean-Christophe PLAGNIOL-VILLARD 
239942ba996SJean-Christophe PLAGNIOL-VILLARD int i2c_write(u_int8_t chip, u_int32_t addr, int alen, u_int8_t *buf, int len)
240942ba996SJean-Christophe PLAGNIOL-VILLARD {
241942ba996SJean-Christophe PLAGNIOL-VILLARD 	u_int32_t	tmp;
242942ba996SJean-Christophe PLAGNIOL-VILLARD 	int		i;
243942ba996SJean-Christophe PLAGNIOL-VILLARD 
244942ba996SJean-Christophe PLAGNIOL-VILLARD 	if ((alen < 0) || (alen > 2)) {
245942ba996SJean-Christophe PLAGNIOL-VILLARD 		printf("%s(): bogus address length %x\n", __FUNCTION__, alen);
246942ba996SJean-Christophe PLAGNIOL-VILLARD 		return(1);
247942ba996SJean-Christophe PLAGNIOL-VILLARD 	}
248942ba996SJean-Christophe PLAGNIOL-VILLARD 	if (len < 0) {
249942ba996SJean-Christophe PLAGNIOL-VILLARD 		printf("%s(): bogus length %x\n", __FUNCTION__, len);
250942ba996SJean-Christophe PLAGNIOL-VILLARD 		return(1);
251942ba996SJean-Christophe PLAGNIOL-VILLARD 	}
252942ba996SJean-Christophe PLAGNIOL-VILLARD 
253942ba996SJean-Christophe PLAGNIOL-VILLARD 	if (wait_for_bus()) {return(1);}
254942ba996SJean-Christophe PLAGNIOL-VILLARD 
255942ba996SJean-Christophe PLAGNIOL-VILLARD 	/* Start address phase */
256942ba996SJean-Christophe PLAGNIOL-VILLARD 	tmp = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX | I2C_CON_STP;
257942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_CNT) = (alen == 0) ? len & 0xffff : (len & 0xffff) + alen;
258942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_SA) = chip;
259942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_CON) = tmp;
260942ba996SJean-Christophe PLAGNIOL-VILLARD 
261942ba996SJean-Christophe PLAGNIOL-VILLARD 	switch (alen) {
262942ba996SJean-Christophe PLAGNIOL-VILLARD 		case 2:
263942ba996SJean-Christophe PLAGNIOL-VILLARD 			/* Send address MSByte */
264942ba996SJean-Christophe PLAGNIOL-VILLARD 			tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK);
265942ba996SJean-Christophe PLAGNIOL-VILLARD 
266942ba996SJean-Christophe PLAGNIOL-VILLARD 			CHECK_NACK();
267942ba996SJean-Christophe PLAGNIOL-VILLARD 
268942ba996SJean-Christophe PLAGNIOL-VILLARD 			if (tmp & I2C_STAT_XRDY) {
269942ba996SJean-Christophe PLAGNIOL-VILLARD 				REG(I2C_DXR) = (addr >> 8) & 0xff;
270942ba996SJean-Christophe PLAGNIOL-VILLARD 			} else {
271942ba996SJean-Christophe PLAGNIOL-VILLARD 				REG(I2C_CON) = 0;
272942ba996SJean-Christophe PLAGNIOL-VILLARD 				return(1);
273942ba996SJean-Christophe PLAGNIOL-VILLARD 			}
274942ba996SJean-Christophe PLAGNIOL-VILLARD 			/* No break, fall through */
275942ba996SJean-Christophe PLAGNIOL-VILLARD 		case 1:
276942ba996SJean-Christophe PLAGNIOL-VILLARD 			/* Send address LSByte */
277942ba996SJean-Christophe PLAGNIOL-VILLARD 			tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK);
278942ba996SJean-Christophe PLAGNIOL-VILLARD 
279942ba996SJean-Christophe PLAGNIOL-VILLARD 			CHECK_NACK();
280942ba996SJean-Christophe PLAGNIOL-VILLARD 
281942ba996SJean-Christophe PLAGNIOL-VILLARD 			if (tmp & I2C_STAT_XRDY) {
282942ba996SJean-Christophe PLAGNIOL-VILLARD 				REG(I2C_DXR) = addr & 0xff;
283942ba996SJean-Christophe PLAGNIOL-VILLARD 			} else {
284942ba996SJean-Christophe PLAGNIOL-VILLARD 				REG(I2C_CON) = 0;
285942ba996SJean-Christophe PLAGNIOL-VILLARD 				return(1);
286942ba996SJean-Christophe PLAGNIOL-VILLARD 			}
287942ba996SJean-Christophe PLAGNIOL-VILLARD 	}
288942ba996SJean-Christophe PLAGNIOL-VILLARD 
289942ba996SJean-Christophe PLAGNIOL-VILLARD 	for (i = 0; i < len; i++) {
290942ba996SJean-Christophe PLAGNIOL-VILLARD 		tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK);
291942ba996SJean-Christophe PLAGNIOL-VILLARD 
292942ba996SJean-Christophe PLAGNIOL-VILLARD 		CHECK_NACK();
293942ba996SJean-Christophe PLAGNIOL-VILLARD 
294942ba996SJean-Christophe PLAGNIOL-VILLARD 		if (tmp & I2C_STAT_XRDY) {
295942ba996SJean-Christophe PLAGNIOL-VILLARD 			REG(I2C_DXR) = buf[i];
296942ba996SJean-Christophe PLAGNIOL-VILLARD 		} else {
297942ba996SJean-Christophe PLAGNIOL-VILLARD 			return(1);
298942ba996SJean-Christophe PLAGNIOL-VILLARD 		}
299942ba996SJean-Christophe PLAGNIOL-VILLARD 	}
300942ba996SJean-Christophe PLAGNIOL-VILLARD 
301942ba996SJean-Christophe PLAGNIOL-VILLARD 	tmp = poll_i2c_irq(I2C_STAT_SCD | I2C_STAT_NACK);
302942ba996SJean-Christophe PLAGNIOL-VILLARD 
303942ba996SJean-Christophe PLAGNIOL-VILLARD 	CHECK_NACK();
304942ba996SJean-Christophe PLAGNIOL-VILLARD 
305942ba996SJean-Christophe PLAGNIOL-VILLARD 	if (!(tmp & I2C_STAT_SCD)) {
306942ba996SJean-Christophe PLAGNIOL-VILLARD 		REG(I2C_CON) = 0;
307942ba996SJean-Christophe PLAGNIOL-VILLARD 		return(1);
308942ba996SJean-Christophe PLAGNIOL-VILLARD 	}
309942ba996SJean-Christophe PLAGNIOL-VILLARD 
310942ba996SJean-Christophe PLAGNIOL-VILLARD 	flush_rx();
311942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_STAT) = 0xffff;
312942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_CNT) = 0;
313942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_CON) = 0;
314942ba996SJean-Christophe PLAGNIOL-VILLARD 
315942ba996SJean-Christophe PLAGNIOL-VILLARD 	return(0);
316942ba996SJean-Christophe PLAGNIOL-VILLARD }
317