xref: /rk3399_rockchip-uboot/drivers/i2c/davinci_i2c.c (revision bd0f5ca806c73f9e1ef4a2a0416233ab7e257df9)
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  *
8942ba996SJean-Christophe PLAGNIOL-VILLARD  * See file CREDITS for list of people who contributed to this
9942ba996SJean-Christophe PLAGNIOL-VILLARD  * project.
10942ba996SJean-Christophe PLAGNIOL-VILLARD  *
11942ba996SJean-Christophe PLAGNIOL-VILLARD  * This program is free software; you can redistribute it and/or
12942ba996SJean-Christophe PLAGNIOL-VILLARD  * modify it under the terms of the GNU General Public License as
13942ba996SJean-Christophe PLAGNIOL-VILLARD  * published by the Free Software Foundation; either version 2 of
14942ba996SJean-Christophe PLAGNIOL-VILLARD  * the License, or (at your option) any later version.
15942ba996SJean-Christophe PLAGNIOL-VILLARD  *
16942ba996SJean-Christophe PLAGNIOL-VILLARD  * This program is distributed in the hope that it will be useful,
17942ba996SJean-Christophe PLAGNIOL-VILLARD  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18942ba996SJean-Christophe PLAGNIOL-VILLARD  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19942ba996SJean-Christophe PLAGNIOL-VILLARD  * GNU General Public License for more details.
20942ba996SJean-Christophe PLAGNIOL-VILLARD  *
21942ba996SJean-Christophe PLAGNIOL-VILLARD  * You should have received a copy of the GNU General Public License
22942ba996SJean-Christophe PLAGNIOL-VILLARD  * along with this program; if not, write to the Free Software
23942ba996SJean-Christophe PLAGNIOL-VILLARD  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
24942ba996SJean-Christophe PLAGNIOL-VILLARD  * MA 02111-1307 USA
25942ba996SJean-Christophe PLAGNIOL-VILLARD  */
26942ba996SJean-Christophe PLAGNIOL-VILLARD 
27942ba996SJean-Christophe PLAGNIOL-VILLARD #include <common.h>
28942ba996SJean-Christophe PLAGNIOL-VILLARD #include <i2c.h>
29942ba996SJean-Christophe PLAGNIOL-VILLARD #include <asm/arch/hardware.h>
30942ba996SJean-Christophe PLAGNIOL-VILLARD #include <asm/arch/i2c_defs.h>
31942ba996SJean-Christophe PLAGNIOL-VILLARD 
32942ba996SJean-Christophe PLAGNIOL-VILLARD #define CHECK_NACK() \
33942ba996SJean-Christophe PLAGNIOL-VILLARD 	do {\
34942ba996SJean-Christophe PLAGNIOL-VILLARD 		if (tmp & (I2C_TIMEOUT | I2C_STAT_NACK)) {\
35942ba996SJean-Christophe PLAGNIOL-VILLARD 			REG(I2C_CON) = 0;\
36942ba996SJean-Christophe PLAGNIOL-VILLARD 			return(1);\
37942ba996SJean-Christophe PLAGNIOL-VILLARD 		}\
38942ba996SJean-Christophe PLAGNIOL-VILLARD 	} while (0)
39942ba996SJean-Christophe PLAGNIOL-VILLARD 
40942ba996SJean-Christophe PLAGNIOL-VILLARD 
41942ba996SJean-Christophe PLAGNIOL-VILLARD static int wait_for_bus(void)
42942ba996SJean-Christophe PLAGNIOL-VILLARD {
43942ba996SJean-Christophe PLAGNIOL-VILLARD 	int	stat, timeout;
44942ba996SJean-Christophe PLAGNIOL-VILLARD 
45942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_STAT) = 0xffff;
46942ba996SJean-Christophe PLAGNIOL-VILLARD 
47942ba996SJean-Christophe PLAGNIOL-VILLARD 	for (timeout = 0; timeout < 10; timeout++) {
48942ba996SJean-Christophe PLAGNIOL-VILLARD 		if (!((stat = REG(I2C_STAT)) & I2C_STAT_BB)) {
49942ba996SJean-Christophe PLAGNIOL-VILLARD 			REG(I2C_STAT) = 0xffff;
50942ba996SJean-Christophe PLAGNIOL-VILLARD 			return(0);
51942ba996SJean-Christophe PLAGNIOL-VILLARD 		}
52942ba996SJean-Christophe PLAGNIOL-VILLARD 
53942ba996SJean-Christophe PLAGNIOL-VILLARD 		REG(I2C_STAT) = stat;
54942ba996SJean-Christophe PLAGNIOL-VILLARD 		udelay(50000);
55942ba996SJean-Christophe PLAGNIOL-VILLARD 	}
56942ba996SJean-Christophe PLAGNIOL-VILLARD 
57942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_STAT) = 0xffff;
58942ba996SJean-Christophe PLAGNIOL-VILLARD 	return(1);
59942ba996SJean-Christophe PLAGNIOL-VILLARD }
60942ba996SJean-Christophe PLAGNIOL-VILLARD 
61942ba996SJean-Christophe PLAGNIOL-VILLARD 
62942ba996SJean-Christophe PLAGNIOL-VILLARD static int poll_i2c_irq(int mask)
63942ba996SJean-Christophe PLAGNIOL-VILLARD {
64942ba996SJean-Christophe PLAGNIOL-VILLARD 	int	stat, timeout;
65942ba996SJean-Christophe PLAGNIOL-VILLARD 
66942ba996SJean-Christophe PLAGNIOL-VILLARD 	for (timeout = 0; timeout < 10; timeout++) {
67942ba996SJean-Christophe PLAGNIOL-VILLARD 		udelay(1000);
68942ba996SJean-Christophe PLAGNIOL-VILLARD 		stat = REG(I2C_STAT);
69942ba996SJean-Christophe PLAGNIOL-VILLARD 		if (stat & mask) {
70942ba996SJean-Christophe PLAGNIOL-VILLARD 			return(stat);
71942ba996SJean-Christophe PLAGNIOL-VILLARD 		}
72942ba996SJean-Christophe PLAGNIOL-VILLARD 	}
73942ba996SJean-Christophe PLAGNIOL-VILLARD 
74942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_STAT) = 0xffff;
75942ba996SJean-Christophe PLAGNIOL-VILLARD 	return(stat | I2C_TIMEOUT);
76942ba996SJean-Christophe PLAGNIOL-VILLARD }
77942ba996SJean-Christophe PLAGNIOL-VILLARD 
78942ba996SJean-Christophe PLAGNIOL-VILLARD 
79942ba996SJean-Christophe PLAGNIOL-VILLARD void flush_rx(void)
80942ba996SJean-Christophe PLAGNIOL-VILLARD {
81942ba996SJean-Christophe PLAGNIOL-VILLARD 	while (1) {
82942ba996SJean-Christophe PLAGNIOL-VILLARD 		if (!(REG(I2C_STAT) & I2C_STAT_RRDY))
83942ba996SJean-Christophe PLAGNIOL-VILLARD 			break;
84942ba996SJean-Christophe PLAGNIOL-VILLARD 
85*bd0f5ca8SAnatolij Gustschin 		REG(I2C_DRR);
86942ba996SJean-Christophe PLAGNIOL-VILLARD 		REG(I2C_STAT) = I2C_STAT_RRDY;
87942ba996SJean-Christophe PLAGNIOL-VILLARD 		udelay(1000);
88942ba996SJean-Christophe PLAGNIOL-VILLARD 	}
89942ba996SJean-Christophe PLAGNIOL-VILLARD }
90942ba996SJean-Christophe PLAGNIOL-VILLARD 
91942ba996SJean-Christophe PLAGNIOL-VILLARD 
92942ba996SJean-Christophe PLAGNIOL-VILLARD void i2c_init(int speed, int slaveadd)
93942ba996SJean-Christophe PLAGNIOL-VILLARD {
94942ba996SJean-Christophe PLAGNIOL-VILLARD 	u_int32_t	div, psc;
95942ba996SJean-Christophe PLAGNIOL-VILLARD 
96942ba996SJean-Christophe PLAGNIOL-VILLARD 	if (REG(I2C_CON) & I2C_CON_EN) {
97942ba996SJean-Christophe PLAGNIOL-VILLARD 		REG(I2C_CON) = 0;
98942ba996SJean-Christophe PLAGNIOL-VILLARD 		udelay (50000);
99942ba996SJean-Christophe PLAGNIOL-VILLARD 	}
100942ba996SJean-Christophe PLAGNIOL-VILLARD 
101942ba996SJean-Christophe PLAGNIOL-VILLARD 	psc = 2;
102942ba996SJean-Christophe PLAGNIOL-VILLARD 	div = (CONFIG_SYS_HZ_CLOCK / ((psc + 1) * speed)) - 10;	/* SCLL + SCLH */
103942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_PSC) = psc;			/* 27MHz / (2 + 1) = 9MHz */
104942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_SCLL) = (div * 50) / 100;	/* 50% Duty */
105942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_SCLH) = div - REG(I2C_SCLL);
106942ba996SJean-Christophe PLAGNIOL-VILLARD 
107942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_OA) = slaveadd;
108942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_CNT) = 0;
109942ba996SJean-Christophe PLAGNIOL-VILLARD 
110942ba996SJean-Christophe PLAGNIOL-VILLARD 	/* Interrupts must be enabled or I2C module won't work */
111942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_IE) = I2C_IE_SCD_IE | I2C_IE_XRDY_IE |
112942ba996SJean-Christophe PLAGNIOL-VILLARD 		I2C_IE_RRDY_IE | I2C_IE_ARDY_IE | I2C_IE_NACK_IE;
113942ba996SJean-Christophe PLAGNIOL-VILLARD 
114942ba996SJean-Christophe PLAGNIOL-VILLARD 	/* Now enable I2C controller (get it out of reset) */
115942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_CON) = I2C_CON_EN;
116942ba996SJean-Christophe PLAGNIOL-VILLARD 
117942ba996SJean-Christophe PLAGNIOL-VILLARD 	udelay(1000);
118942ba996SJean-Christophe PLAGNIOL-VILLARD }
119942ba996SJean-Christophe PLAGNIOL-VILLARD 
12049d6da60SHeiko Schocher int i2c_set_bus_speed(unsigned int speed)
12149d6da60SHeiko Schocher {
12249d6da60SHeiko Schocher 	i2c_init(speed, CONFIG_SYS_I2C_SLAVE);
12349d6da60SHeiko Schocher 	return 0;
12449d6da60SHeiko Schocher }
125942ba996SJean-Christophe PLAGNIOL-VILLARD 
126942ba996SJean-Christophe PLAGNIOL-VILLARD int i2c_probe(u_int8_t chip)
127942ba996SJean-Christophe PLAGNIOL-VILLARD {
128942ba996SJean-Christophe PLAGNIOL-VILLARD 	int	rc = 1;
129942ba996SJean-Christophe PLAGNIOL-VILLARD 
130942ba996SJean-Christophe PLAGNIOL-VILLARD 	if (chip == REG(I2C_OA)) {
131942ba996SJean-Christophe PLAGNIOL-VILLARD 		return(rc);
132942ba996SJean-Christophe PLAGNIOL-VILLARD 	}
133942ba996SJean-Christophe PLAGNIOL-VILLARD 
134942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_CON) = 0;
135942ba996SJean-Christophe PLAGNIOL-VILLARD 	if (wait_for_bus()) {return(1);}
136942ba996SJean-Christophe PLAGNIOL-VILLARD 
137942ba996SJean-Christophe PLAGNIOL-VILLARD 	/* try to read one byte from current (or only) address */
138942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_CNT) = 1;
139942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_SA) = chip;
140942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_CON) = (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP);
141942ba996SJean-Christophe PLAGNIOL-VILLARD 	udelay (50000);
142942ba996SJean-Christophe PLAGNIOL-VILLARD 
143942ba996SJean-Christophe PLAGNIOL-VILLARD 	if (!(REG(I2C_STAT) & I2C_STAT_NACK)) {
144942ba996SJean-Christophe PLAGNIOL-VILLARD 		rc = 0;
145942ba996SJean-Christophe PLAGNIOL-VILLARD 		flush_rx();
146942ba996SJean-Christophe PLAGNIOL-VILLARD 		REG(I2C_STAT) = 0xffff;
147942ba996SJean-Christophe PLAGNIOL-VILLARD 	} else {
148942ba996SJean-Christophe PLAGNIOL-VILLARD 		REG(I2C_STAT) = 0xffff;
149942ba996SJean-Christophe PLAGNIOL-VILLARD 		REG(I2C_CON) |= I2C_CON_STP;
150942ba996SJean-Christophe PLAGNIOL-VILLARD 		udelay(20000);
151942ba996SJean-Christophe PLAGNIOL-VILLARD 		if (wait_for_bus()) {return(1);}
152942ba996SJean-Christophe PLAGNIOL-VILLARD 	}
153942ba996SJean-Christophe PLAGNIOL-VILLARD 
154942ba996SJean-Christophe PLAGNIOL-VILLARD 	flush_rx();
155942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_STAT) = 0xffff;
156942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_CNT) = 0;
157942ba996SJean-Christophe PLAGNIOL-VILLARD 	return(rc);
158942ba996SJean-Christophe PLAGNIOL-VILLARD }
159942ba996SJean-Christophe PLAGNIOL-VILLARD 
160942ba996SJean-Christophe PLAGNIOL-VILLARD 
161942ba996SJean-Christophe PLAGNIOL-VILLARD int i2c_read(u_int8_t chip, u_int32_t addr, int alen, u_int8_t *buf, int len)
162942ba996SJean-Christophe PLAGNIOL-VILLARD {
163942ba996SJean-Christophe PLAGNIOL-VILLARD 	u_int32_t	tmp;
164942ba996SJean-Christophe PLAGNIOL-VILLARD 	int		i;
165942ba996SJean-Christophe PLAGNIOL-VILLARD 
166942ba996SJean-Christophe PLAGNIOL-VILLARD 	if ((alen < 0) || (alen > 2)) {
167942ba996SJean-Christophe PLAGNIOL-VILLARD 		printf("%s(): bogus address length %x\n", __FUNCTION__, alen);
168942ba996SJean-Christophe PLAGNIOL-VILLARD 		return(1);
169942ba996SJean-Christophe PLAGNIOL-VILLARD 	}
170942ba996SJean-Christophe PLAGNIOL-VILLARD 
171942ba996SJean-Christophe PLAGNIOL-VILLARD 	if (wait_for_bus()) {return(1);}
172942ba996SJean-Christophe PLAGNIOL-VILLARD 
173942ba996SJean-Christophe PLAGNIOL-VILLARD 	if (alen != 0) {
174942ba996SJean-Christophe PLAGNIOL-VILLARD 		/* Start address phase */
175942ba996SJean-Christophe PLAGNIOL-VILLARD 		tmp = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX;
176942ba996SJean-Christophe PLAGNIOL-VILLARD 		REG(I2C_CNT) = alen;
177942ba996SJean-Christophe PLAGNIOL-VILLARD 		REG(I2C_SA) = chip;
178942ba996SJean-Christophe PLAGNIOL-VILLARD 		REG(I2C_CON) = tmp;
179942ba996SJean-Christophe PLAGNIOL-VILLARD 
180942ba996SJean-Christophe PLAGNIOL-VILLARD 		tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK);
181942ba996SJean-Christophe PLAGNIOL-VILLARD 
182942ba996SJean-Christophe PLAGNIOL-VILLARD 		CHECK_NACK();
183942ba996SJean-Christophe PLAGNIOL-VILLARD 
184942ba996SJean-Christophe PLAGNIOL-VILLARD 		switch (alen) {
185942ba996SJean-Christophe PLAGNIOL-VILLARD 			case 2:
186942ba996SJean-Christophe PLAGNIOL-VILLARD 				/* Send address MSByte */
187942ba996SJean-Christophe PLAGNIOL-VILLARD 				if (tmp & I2C_STAT_XRDY) {
188942ba996SJean-Christophe PLAGNIOL-VILLARD 					REG(I2C_DXR) = (addr >> 8) & 0xff;
189942ba996SJean-Christophe PLAGNIOL-VILLARD 				} else {
190942ba996SJean-Christophe PLAGNIOL-VILLARD 					REG(I2C_CON) = 0;
191942ba996SJean-Christophe PLAGNIOL-VILLARD 					return(1);
192942ba996SJean-Christophe PLAGNIOL-VILLARD 				}
193942ba996SJean-Christophe PLAGNIOL-VILLARD 
194942ba996SJean-Christophe PLAGNIOL-VILLARD 				tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK);
195942ba996SJean-Christophe PLAGNIOL-VILLARD 
196942ba996SJean-Christophe PLAGNIOL-VILLARD 				CHECK_NACK();
197942ba996SJean-Christophe PLAGNIOL-VILLARD 				/* No break, fall through */
198942ba996SJean-Christophe PLAGNIOL-VILLARD 			case 1:
199942ba996SJean-Christophe PLAGNIOL-VILLARD 				/* Send address LSByte */
200942ba996SJean-Christophe PLAGNIOL-VILLARD 				if (tmp & I2C_STAT_XRDY) {
201942ba996SJean-Christophe PLAGNIOL-VILLARD 					REG(I2C_DXR) = addr & 0xff;
202942ba996SJean-Christophe PLAGNIOL-VILLARD 				} else {
203942ba996SJean-Christophe PLAGNIOL-VILLARD 					REG(I2C_CON) = 0;
204942ba996SJean-Christophe PLAGNIOL-VILLARD 					return(1);
205942ba996SJean-Christophe PLAGNIOL-VILLARD 				}
206942ba996SJean-Christophe PLAGNIOL-VILLARD 
207942ba996SJean-Christophe PLAGNIOL-VILLARD 				tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK | I2C_STAT_ARDY);
208942ba996SJean-Christophe PLAGNIOL-VILLARD 
209942ba996SJean-Christophe PLAGNIOL-VILLARD 				CHECK_NACK();
210942ba996SJean-Christophe PLAGNIOL-VILLARD 
211942ba996SJean-Christophe PLAGNIOL-VILLARD 				if (!(tmp & I2C_STAT_ARDY)) {
212942ba996SJean-Christophe PLAGNIOL-VILLARD 					REG(I2C_CON) = 0;
213942ba996SJean-Christophe PLAGNIOL-VILLARD 					return(1);
214942ba996SJean-Christophe PLAGNIOL-VILLARD 				}
215942ba996SJean-Christophe PLAGNIOL-VILLARD 		}
216942ba996SJean-Christophe PLAGNIOL-VILLARD 	}
217942ba996SJean-Christophe PLAGNIOL-VILLARD 
218942ba996SJean-Christophe PLAGNIOL-VILLARD 	/* Address phase is over, now read 'len' bytes and stop */
219942ba996SJean-Christophe PLAGNIOL-VILLARD 	tmp = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP;
220942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_CNT) = len & 0xffff;
221942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_SA) = chip;
222942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_CON) = tmp;
223942ba996SJean-Christophe PLAGNIOL-VILLARD 
224942ba996SJean-Christophe PLAGNIOL-VILLARD 	for (i = 0; i < len; i++) {
225942ba996SJean-Christophe PLAGNIOL-VILLARD 		tmp = poll_i2c_irq(I2C_STAT_RRDY | I2C_STAT_NACK | I2C_STAT_ROVR);
226942ba996SJean-Christophe PLAGNIOL-VILLARD 
227942ba996SJean-Christophe PLAGNIOL-VILLARD 		CHECK_NACK();
228942ba996SJean-Christophe PLAGNIOL-VILLARD 
229942ba996SJean-Christophe PLAGNIOL-VILLARD 		if (tmp & I2C_STAT_RRDY) {
230942ba996SJean-Christophe PLAGNIOL-VILLARD 			buf[i] = REG(I2C_DRR);
231942ba996SJean-Christophe PLAGNIOL-VILLARD 		} else {
232942ba996SJean-Christophe PLAGNIOL-VILLARD 			REG(I2C_CON) = 0;
233942ba996SJean-Christophe PLAGNIOL-VILLARD 			return(1);
234942ba996SJean-Christophe PLAGNIOL-VILLARD 		}
235942ba996SJean-Christophe PLAGNIOL-VILLARD 	}
236942ba996SJean-Christophe PLAGNIOL-VILLARD 
237942ba996SJean-Christophe PLAGNIOL-VILLARD 	tmp = poll_i2c_irq(I2C_STAT_SCD | I2C_STAT_NACK);
238942ba996SJean-Christophe PLAGNIOL-VILLARD 
239942ba996SJean-Christophe PLAGNIOL-VILLARD 	CHECK_NACK();
240942ba996SJean-Christophe PLAGNIOL-VILLARD 
241942ba996SJean-Christophe PLAGNIOL-VILLARD 	if (!(tmp & I2C_STAT_SCD)) {
242942ba996SJean-Christophe PLAGNIOL-VILLARD 		REG(I2C_CON) = 0;
243942ba996SJean-Christophe PLAGNIOL-VILLARD 		return(1);
244942ba996SJean-Christophe PLAGNIOL-VILLARD 	}
245942ba996SJean-Christophe PLAGNIOL-VILLARD 
246942ba996SJean-Christophe PLAGNIOL-VILLARD 	flush_rx();
247942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_STAT) = 0xffff;
248942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_CNT) = 0;
249942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_CON) = 0;
250942ba996SJean-Christophe PLAGNIOL-VILLARD 
251942ba996SJean-Christophe PLAGNIOL-VILLARD 	return(0);
252942ba996SJean-Christophe PLAGNIOL-VILLARD }
253942ba996SJean-Christophe PLAGNIOL-VILLARD 
254942ba996SJean-Christophe PLAGNIOL-VILLARD 
255942ba996SJean-Christophe PLAGNIOL-VILLARD int i2c_write(u_int8_t chip, u_int32_t addr, int alen, u_int8_t *buf, int len)
256942ba996SJean-Christophe PLAGNIOL-VILLARD {
257942ba996SJean-Christophe PLAGNIOL-VILLARD 	u_int32_t	tmp;
258942ba996SJean-Christophe PLAGNIOL-VILLARD 	int		i;
259942ba996SJean-Christophe PLAGNIOL-VILLARD 
260942ba996SJean-Christophe PLAGNIOL-VILLARD 	if ((alen < 0) || (alen > 2)) {
261942ba996SJean-Christophe PLAGNIOL-VILLARD 		printf("%s(): bogus address length %x\n", __FUNCTION__, alen);
262942ba996SJean-Christophe PLAGNIOL-VILLARD 		return(1);
263942ba996SJean-Christophe PLAGNIOL-VILLARD 	}
264942ba996SJean-Christophe PLAGNIOL-VILLARD 	if (len < 0) {
265942ba996SJean-Christophe PLAGNIOL-VILLARD 		printf("%s(): bogus length %x\n", __FUNCTION__, len);
266942ba996SJean-Christophe PLAGNIOL-VILLARD 		return(1);
267942ba996SJean-Christophe PLAGNIOL-VILLARD 	}
268942ba996SJean-Christophe PLAGNIOL-VILLARD 
269942ba996SJean-Christophe PLAGNIOL-VILLARD 	if (wait_for_bus()) {return(1);}
270942ba996SJean-Christophe PLAGNIOL-VILLARD 
271942ba996SJean-Christophe PLAGNIOL-VILLARD 	/* Start address phase */
272942ba996SJean-Christophe PLAGNIOL-VILLARD 	tmp = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX | I2C_CON_STP;
273942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_CNT) = (alen == 0) ? len & 0xffff : (len & 0xffff) + alen;
274942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_SA) = chip;
275942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_CON) = tmp;
276942ba996SJean-Christophe PLAGNIOL-VILLARD 
277942ba996SJean-Christophe PLAGNIOL-VILLARD 	switch (alen) {
278942ba996SJean-Christophe PLAGNIOL-VILLARD 		case 2:
279942ba996SJean-Christophe PLAGNIOL-VILLARD 			/* Send address MSByte */
280942ba996SJean-Christophe PLAGNIOL-VILLARD 			tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK);
281942ba996SJean-Christophe PLAGNIOL-VILLARD 
282942ba996SJean-Christophe PLAGNIOL-VILLARD 			CHECK_NACK();
283942ba996SJean-Christophe PLAGNIOL-VILLARD 
284942ba996SJean-Christophe PLAGNIOL-VILLARD 			if (tmp & I2C_STAT_XRDY) {
285942ba996SJean-Christophe PLAGNIOL-VILLARD 				REG(I2C_DXR) = (addr >> 8) & 0xff;
286942ba996SJean-Christophe PLAGNIOL-VILLARD 			} else {
287942ba996SJean-Christophe PLAGNIOL-VILLARD 				REG(I2C_CON) = 0;
288942ba996SJean-Christophe PLAGNIOL-VILLARD 				return(1);
289942ba996SJean-Christophe PLAGNIOL-VILLARD 			}
290942ba996SJean-Christophe PLAGNIOL-VILLARD 			/* No break, fall through */
291942ba996SJean-Christophe PLAGNIOL-VILLARD 		case 1:
292942ba996SJean-Christophe PLAGNIOL-VILLARD 			/* Send address LSByte */
293942ba996SJean-Christophe PLAGNIOL-VILLARD 			tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK);
294942ba996SJean-Christophe PLAGNIOL-VILLARD 
295942ba996SJean-Christophe PLAGNIOL-VILLARD 			CHECK_NACK();
296942ba996SJean-Christophe PLAGNIOL-VILLARD 
297942ba996SJean-Christophe PLAGNIOL-VILLARD 			if (tmp & I2C_STAT_XRDY) {
298942ba996SJean-Christophe PLAGNIOL-VILLARD 				REG(I2C_DXR) = addr & 0xff;
299942ba996SJean-Christophe PLAGNIOL-VILLARD 			} else {
300942ba996SJean-Christophe PLAGNIOL-VILLARD 				REG(I2C_CON) = 0;
301942ba996SJean-Christophe PLAGNIOL-VILLARD 				return(1);
302942ba996SJean-Christophe PLAGNIOL-VILLARD 			}
303942ba996SJean-Christophe PLAGNIOL-VILLARD 	}
304942ba996SJean-Christophe PLAGNIOL-VILLARD 
305942ba996SJean-Christophe PLAGNIOL-VILLARD 	for (i = 0; i < len; i++) {
306942ba996SJean-Christophe PLAGNIOL-VILLARD 		tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK);
307942ba996SJean-Christophe PLAGNIOL-VILLARD 
308942ba996SJean-Christophe PLAGNIOL-VILLARD 		CHECK_NACK();
309942ba996SJean-Christophe PLAGNIOL-VILLARD 
310942ba996SJean-Christophe PLAGNIOL-VILLARD 		if (tmp & I2C_STAT_XRDY) {
311942ba996SJean-Christophe PLAGNIOL-VILLARD 			REG(I2C_DXR) = buf[i];
312942ba996SJean-Christophe PLAGNIOL-VILLARD 		} else {
313942ba996SJean-Christophe PLAGNIOL-VILLARD 			return(1);
314942ba996SJean-Christophe PLAGNIOL-VILLARD 		}
315942ba996SJean-Christophe PLAGNIOL-VILLARD 	}
316942ba996SJean-Christophe PLAGNIOL-VILLARD 
317942ba996SJean-Christophe PLAGNIOL-VILLARD 	tmp = poll_i2c_irq(I2C_STAT_SCD | I2C_STAT_NACK);
318942ba996SJean-Christophe PLAGNIOL-VILLARD 
319942ba996SJean-Christophe PLAGNIOL-VILLARD 	CHECK_NACK();
320942ba996SJean-Christophe PLAGNIOL-VILLARD 
321942ba996SJean-Christophe PLAGNIOL-VILLARD 	if (!(tmp & I2C_STAT_SCD)) {
322942ba996SJean-Christophe PLAGNIOL-VILLARD 		REG(I2C_CON) = 0;
323942ba996SJean-Christophe PLAGNIOL-VILLARD 		return(1);
324942ba996SJean-Christophe PLAGNIOL-VILLARD 	}
325942ba996SJean-Christophe PLAGNIOL-VILLARD 
326942ba996SJean-Christophe PLAGNIOL-VILLARD 	flush_rx();
327942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_STAT) = 0xffff;
328942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_CNT) = 0;
329942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_CON) = 0;
330942ba996SJean-Christophe PLAGNIOL-VILLARD 
331942ba996SJean-Christophe PLAGNIOL-VILLARD 	return(0);
332942ba996SJean-Christophe PLAGNIOL-VILLARD }
333