xref: /rk3399_rockchip-uboot/drivers/i2c/davinci_i2c.c (revision 49d6da6032c2d55f7912ffedfbf222b6b4511b8c)
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 	int	dummy;
82942ba996SJean-Christophe PLAGNIOL-VILLARD 
83942ba996SJean-Christophe PLAGNIOL-VILLARD 	while (1) {
84942ba996SJean-Christophe PLAGNIOL-VILLARD 		if (!(REG(I2C_STAT) & I2C_STAT_RRDY))
85942ba996SJean-Christophe PLAGNIOL-VILLARD 			break;
86942ba996SJean-Christophe PLAGNIOL-VILLARD 
87942ba996SJean-Christophe PLAGNIOL-VILLARD 		dummy = REG(I2C_DRR);
88942ba996SJean-Christophe PLAGNIOL-VILLARD 		REG(I2C_STAT) = I2C_STAT_RRDY;
89942ba996SJean-Christophe PLAGNIOL-VILLARD 		udelay(1000);
90942ba996SJean-Christophe PLAGNIOL-VILLARD 	}
91942ba996SJean-Christophe PLAGNIOL-VILLARD }
92942ba996SJean-Christophe PLAGNIOL-VILLARD 
93942ba996SJean-Christophe PLAGNIOL-VILLARD 
94942ba996SJean-Christophe PLAGNIOL-VILLARD void i2c_init(int speed, int slaveadd)
95942ba996SJean-Christophe PLAGNIOL-VILLARD {
96942ba996SJean-Christophe PLAGNIOL-VILLARD 	u_int32_t	div, psc;
97942ba996SJean-Christophe PLAGNIOL-VILLARD 
98942ba996SJean-Christophe PLAGNIOL-VILLARD 	if (REG(I2C_CON) & I2C_CON_EN) {
99942ba996SJean-Christophe PLAGNIOL-VILLARD 		REG(I2C_CON) = 0;
100942ba996SJean-Christophe PLAGNIOL-VILLARD 		udelay (50000);
101942ba996SJean-Christophe PLAGNIOL-VILLARD 	}
102942ba996SJean-Christophe PLAGNIOL-VILLARD 
103942ba996SJean-Christophe PLAGNIOL-VILLARD 	psc = 2;
104942ba996SJean-Christophe PLAGNIOL-VILLARD 	div = (CONFIG_SYS_HZ_CLOCK / ((psc + 1) * speed)) - 10;	/* SCLL + SCLH */
105942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_PSC) = psc;			/* 27MHz / (2 + 1) = 9MHz */
106942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_SCLL) = (div * 50) / 100;	/* 50% Duty */
107942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_SCLH) = div - REG(I2C_SCLL);
108942ba996SJean-Christophe PLAGNIOL-VILLARD 
109942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_OA) = slaveadd;
110942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_CNT) = 0;
111942ba996SJean-Christophe PLAGNIOL-VILLARD 
112942ba996SJean-Christophe PLAGNIOL-VILLARD 	/* Interrupts must be enabled or I2C module won't work */
113942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_IE) = I2C_IE_SCD_IE | I2C_IE_XRDY_IE |
114942ba996SJean-Christophe PLAGNIOL-VILLARD 		I2C_IE_RRDY_IE | I2C_IE_ARDY_IE | I2C_IE_NACK_IE;
115942ba996SJean-Christophe PLAGNIOL-VILLARD 
116942ba996SJean-Christophe PLAGNIOL-VILLARD 	/* Now enable I2C controller (get it out of reset) */
117942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_CON) = I2C_CON_EN;
118942ba996SJean-Christophe PLAGNIOL-VILLARD 
119942ba996SJean-Christophe PLAGNIOL-VILLARD 	udelay(1000);
120942ba996SJean-Christophe PLAGNIOL-VILLARD }
121942ba996SJean-Christophe PLAGNIOL-VILLARD 
122*49d6da60SHeiko Schocher int i2c_set_bus_speed(unsigned int speed)
123*49d6da60SHeiko Schocher {
124*49d6da60SHeiko Schocher 	i2c_init(speed, CONFIG_SYS_I2C_SLAVE);
125*49d6da60SHeiko Schocher 	return 0;
126*49d6da60SHeiko Schocher }
127942ba996SJean-Christophe PLAGNIOL-VILLARD 
128942ba996SJean-Christophe PLAGNIOL-VILLARD int i2c_probe(u_int8_t chip)
129942ba996SJean-Christophe PLAGNIOL-VILLARD {
130942ba996SJean-Christophe PLAGNIOL-VILLARD 	int	rc = 1;
131942ba996SJean-Christophe PLAGNIOL-VILLARD 
132942ba996SJean-Christophe PLAGNIOL-VILLARD 	if (chip == REG(I2C_OA)) {
133942ba996SJean-Christophe PLAGNIOL-VILLARD 		return(rc);
134942ba996SJean-Christophe PLAGNIOL-VILLARD 	}
135942ba996SJean-Christophe PLAGNIOL-VILLARD 
136942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_CON) = 0;
137942ba996SJean-Christophe PLAGNIOL-VILLARD 	if (wait_for_bus()) {return(1);}
138942ba996SJean-Christophe PLAGNIOL-VILLARD 
139942ba996SJean-Christophe PLAGNIOL-VILLARD 	/* try to read one byte from current (or only) address */
140942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_CNT) = 1;
141942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_SA) = chip;
142942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_CON) = (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP);
143942ba996SJean-Christophe PLAGNIOL-VILLARD 	udelay (50000);
144942ba996SJean-Christophe PLAGNIOL-VILLARD 
145942ba996SJean-Christophe PLAGNIOL-VILLARD 	if (!(REG(I2C_STAT) & I2C_STAT_NACK)) {
146942ba996SJean-Christophe PLAGNIOL-VILLARD 		rc = 0;
147942ba996SJean-Christophe PLAGNIOL-VILLARD 		flush_rx();
148942ba996SJean-Christophe PLAGNIOL-VILLARD 		REG(I2C_STAT) = 0xffff;
149942ba996SJean-Christophe PLAGNIOL-VILLARD 	} else {
150942ba996SJean-Christophe PLAGNIOL-VILLARD 		REG(I2C_STAT) = 0xffff;
151942ba996SJean-Christophe PLAGNIOL-VILLARD 		REG(I2C_CON) |= I2C_CON_STP;
152942ba996SJean-Christophe PLAGNIOL-VILLARD 		udelay(20000);
153942ba996SJean-Christophe PLAGNIOL-VILLARD 		if (wait_for_bus()) {return(1);}
154942ba996SJean-Christophe PLAGNIOL-VILLARD 	}
155942ba996SJean-Christophe PLAGNIOL-VILLARD 
156942ba996SJean-Christophe PLAGNIOL-VILLARD 	flush_rx();
157942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_STAT) = 0xffff;
158942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_CNT) = 0;
159942ba996SJean-Christophe PLAGNIOL-VILLARD 	return(rc);
160942ba996SJean-Christophe PLAGNIOL-VILLARD }
161942ba996SJean-Christophe PLAGNIOL-VILLARD 
162942ba996SJean-Christophe PLAGNIOL-VILLARD 
163942ba996SJean-Christophe PLAGNIOL-VILLARD int i2c_read(u_int8_t chip, u_int32_t addr, int alen, u_int8_t *buf, int len)
164942ba996SJean-Christophe PLAGNIOL-VILLARD {
165942ba996SJean-Christophe PLAGNIOL-VILLARD 	u_int32_t	tmp;
166942ba996SJean-Christophe PLAGNIOL-VILLARD 	int		i;
167942ba996SJean-Christophe PLAGNIOL-VILLARD 
168942ba996SJean-Christophe PLAGNIOL-VILLARD 	if ((alen < 0) || (alen > 2)) {
169942ba996SJean-Christophe PLAGNIOL-VILLARD 		printf("%s(): bogus address length %x\n", __FUNCTION__, alen);
170942ba996SJean-Christophe PLAGNIOL-VILLARD 		return(1);
171942ba996SJean-Christophe PLAGNIOL-VILLARD 	}
172942ba996SJean-Christophe PLAGNIOL-VILLARD 
173942ba996SJean-Christophe PLAGNIOL-VILLARD 	if (wait_for_bus()) {return(1);}
174942ba996SJean-Christophe PLAGNIOL-VILLARD 
175942ba996SJean-Christophe PLAGNIOL-VILLARD 	if (alen != 0) {
176942ba996SJean-Christophe PLAGNIOL-VILLARD 		/* Start address phase */
177942ba996SJean-Christophe PLAGNIOL-VILLARD 		tmp = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX;
178942ba996SJean-Christophe PLAGNIOL-VILLARD 		REG(I2C_CNT) = alen;
179942ba996SJean-Christophe PLAGNIOL-VILLARD 		REG(I2C_SA) = chip;
180942ba996SJean-Christophe PLAGNIOL-VILLARD 		REG(I2C_CON) = tmp;
181942ba996SJean-Christophe PLAGNIOL-VILLARD 
182942ba996SJean-Christophe PLAGNIOL-VILLARD 		tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK);
183942ba996SJean-Christophe PLAGNIOL-VILLARD 
184942ba996SJean-Christophe PLAGNIOL-VILLARD 		CHECK_NACK();
185942ba996SJean-Christophe PLAGNIOL-VILLARD 
186942ba996SJean-Christophe PLAGNIOL-VILLARD 		switch (alen) {
187942ba996SJean-Christophe PLAGNIOL-VILLARD 			case 2:
188942ba996SJean-Christophe PLAGNIOL-VILLARD 				/* Send address MSByte */
189942ba996SJean-Christophe PLAGNIOL-VILLARD 				if (tmp & I2C_STAT_XRDY) {
190942ba996SJean-Christophe PLAGNIOL-VILLARD 					REG(I2C_DXR) = (addr >> 8) & 0xff;
191942ba996SJean-Christophe PLAGNIOL-VILLARD 				} else {
192942ba996SJean-Christophe PLAGNIOL-VILLARD 					REG(I2C_CON) = 0;
193942ba996SJean-Christophe PLAGNIOL-VILLARD 					return(1);
194942ba996SJean-Christophe PLAGNIOL-VILLARD 				}
195942ba996SJean-Christophe PLAGNIOL-VILLARD 
196942ba996SJean-Christophe PLAGNIOL-VILLARD 				tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK);
197942ba996SJean-Christophe PLAGNIOL-VILLARD 
198942ba996SJean-Christophe PLAGNIOL-VILLARD 				CHECK_NACK();
199942ba996SJean-Christophe PLAGNIOL-VILLARD 				/* No break, fall through */
200942ba996SJean-Christophe PLAGNIOL-VILLARD 			case 1:
201942ba996SJean-Christophe PLAGNIOL-VILLARD 				/* Send address LSByte */
202942ba996SJean-Christophe PLAGNIOL-VILLARD 				if (tmp & I2C_STAT_XRDY) {
203942ba996SJean-Christophe PLAGNIOL-VILLARD 					REG(I2C_DXR) = addr & 0xff;
204942ba996SJean-Christophe PLAGNIOL-VILLARD 				} else {
205942ba996SJean-Christophe PLAGNIOL-VILLARD 					REG(I2C_CON) = 0;
206942ba996SJean-Christophe PLAGNIOL-VILLARD 					return(1);
207942ba996SJean-Christophe PLAGNIOL-VILLARD 				}
208942ba996SJean-Christophe PLAGNIOL-VILLARD 
209942ba996SJean-Christophe PLAGNIOL-VILLARD 				tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK | I2C_STAT_ARDY);
210942ba996SJean-Christophe PLAGNIOL-VILLARD 
211942ba996SJean-Christophe PLAGNIOL-VILLARD 				CHECK_NACK();
212942ba996SJean-Christophe PLAGNIOL-VILLARD 
213942ba996SJean-Christophe PLAGNIOL-VILLARD 				if (!(tmp & I2C_STAT_ARDY)) {
214942ba996SJean-Christophe PLAGNIOL-VILLARD 					REG(I2C_CON) = 0;
215942ba996SJean-Christophe PLAGNIOL-VILLARD 					return(1);
216942ba996SJean-Christophe PLAGNIOL-VILLARD 				}
217942ba996SJean-Christophe PLAGNIOL-VILLARD 		}
218942ba996SJean-Christophe PLAGNIOL-VILLARD 	}
219942ba996SJean-Christophe PLAGNIOL-VILLARD 
220942ba996SJean-Christophe PLAGNIOL-VILLARD 	/* Address phase is over, now read 'len' bytes and stop */
221942ba996SJean-Christophe PLAGNIOL-VILLARD 	tmp = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP;
222942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_CNT) = len & 0xffff;
223942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_SA) = chip;
224942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_CON) = tmp;
225942ba996SJean-Christophe PLAGNIOL-VILLARD 
226942ba996SJean-Christophe PLAGNIOL-VILLARD 	for (i = 0; i < len; i++) {
227942ba996SJean-Christophe PLAGNIOL-VILLARD 		tmp = poll_i2c_irq(I2C_STAT_RRDY | I2C_STAT_NACK | I2C_STAT_ROVR);
228942ba996SJean-Christophe PLAGNIOL-VILLARD 
229942ba996SJean-Christophe PLAGNIOL-VILLARD 		CHECK_NACK();
230942ba996SJean-Christophe PLAGNIOL-VILLARD 
231942ba996SJean-Christophe PLAGNIOL-VILLARD 		if (tmp & I2C_STAT_RRDY) {
232942ba996SJean-Christophe PLAGNIOL-VILLARD 			buf[i] = REG(I2C_DRR);
233942ba996SJean-Christophe PLAGNIOL-VILLARD 		} else {
234942ba996SJean-Christophe PLAGNIOL-VILLARD 			REG(I2C_CON) = 0;
235942ba996SJean-Christophe PLAGNIOL-VILLARD 			return(1);
236942ba996SJean-Christophe PLAGNIOL-VILLARD 		}
237942ba996SJean-Christophe PLAGNIOL-VILLARD 	}
238942ba996SJean-Christophe PLAGNIOL-VILLARD 
239942ba996SJean-Christophe PLAGNIOL-VILLARD 	tmp = poll_i2c_irq(I2C_STAT_SCD | I2C_STAT_NACK);
240942ba996SJean-Christophe PLAGNIOL-VILLARD 
241942ba996SJean-Christophe PLAGNIOL-VILLARD 	CHECK_NACK();
242942ba996SJean-Christophe PLAGNIOL-VILLARD 
243942ba996SJean-Christophe PLAGNIOL-VILLARD 	if (!(tmp & I2C_STAT_SCD)) {
244942ba996SJean-Christophe PLAGNIOL-VILLARD 		REG(I2C_CON) = 0;
245942ba996SJean-Christophe PLAGNIOL-VILLARD 		return(1);
246942ba996SJean-Christophe PLAGNIOL-VILLARD 	}
247942ba996SJean-Christophe PLAGNIOL-VILLARD 
248942ba996SJean-Christophe PLAGNIOL-VILLARD 	flush_rx();
249942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_STAT) = 0xffff;
250942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_CNT) = 0;
251942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_CON) = 0;
252942ba996SJean-Christophe PLAGNIOL-VILLARD 
253942ba996SJean-Christophe PLAGNIOL-VILLARD 	return(0);
254942ba996SJean-Christophe PLAGNIOL-VILLARD }
255942ba996SJean-Christophe PLAGNIOL-VILLARD 
256942ba996SJean-Christophe PLAGNIOL-VILLARD 
257942ba996SJean-Christophe PLAGNIOL-VILLARD int i2c_write(u_int8_t chip, u_int32_t addr, int alen, u_int8_t *buf, int len)
258942ba996SJean-Christophe PLAGNIOL-VILLARD {
259942ba996SJean-Christophe PLAGNIOL-VILLARD 	u_int32_t	tmp;
260942ba996SJean-Christophe PLAGNIOL-VILLARD 	int		i;
261942ba996SJean-Christophe PLAGNIOL-VILLARD 
262942ba996SJean-Christophe PLAGNIOL-VILLARD 	if ((alen < 0) || (alen > 2)) {
263942ba996SJean-Christophe PLAGNIOL-VILLARD 		printf("%s(): bogus address length %x\n", __FUNCTION__, alen);
264942ba996SJean-Christophe PLAGNIOL-VILLARD 		return(1);
265942ba996SJean-Christophe PLAGNIOL-VILLARD 	}
266942ba996SJean-Christophe PLAGNIOL-VILLARD 	if (len < 0) {
267942ba996SJean-Christophe PLAGNIOL-VILLARD 		printf("%s(): bogus length %x\n", __FUNCTION__, len);
268942ba996SJean-Christophe PLAGNIOL-VILLARD 		return(1);
269942ba996SJean-Christophe PLAGNIOL-VILLARD 	}
270942ba996SJean-Christophe PLAGNIOL-VILLARD 
271942ba996SJean-Christophe PLAGNIOL-VILLARD 	if (wait_for_bus()) {return(1);}
272942ba996SJean-Christophe PLAGNIOL-VILLARD 
273942ba996SJean-Christophe PLAGNIOL-VILLARD 	/* Start address phase */
274942ba996SJean-Christophe PLAGNIOL-VILLARD 	tmp = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX | I2C_CON_STP;
275942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_CNT) = (alen == 0) ? len & 0xffff : (len & 0xffff) + alen;
276942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_SA) = chip;
277942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_CON) = tmp;
278942ba996SJean-Christophe PLAGNIOL-VILLARD 
279942ba996SJean-Christophe PLAGNIOL-VILLARD 	switch (alen) {
280942ba996SJean-Christophe PLAGNIOL-VILLARD 		case 2:
281942ba996SJean-Christophe PLAGNIOL-VILLARD 			/* Send address MSByte */
282942ba996SJean-Christophe PLAGNIOL-VILLARD 			tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK);
283942ba996SJean-Christophe PLAGNIOL-VILLARD 
284942ba996SJean-Christophe PLAGNIOL-VILLARD 			CHECK_NACK();
285942ba996SJean-Christophe PLAGNIOL-VILLARD 
286942ba996SJean-Christophe PLAGNIOL-VILLARD 			if (tmp & I2C_STAT_XRDY) {
287942ba996SJean-Christophe PLAGNIOL-VILLARD 				REG(I2C_DXR) = (addr >> 8) & 0xff;
288942ba996SJean-Christophe PLAGNIOL-VILLARD 			} else {
289942ba996SJean-Christophe PLAGNIOL-VILLARD 				REG(I2C_CON) = 0;
290942ba996SJean-Christophe PLAGNIOL-VILLARD 				return(1);
291942ba996SJean-Christophe PLAGNIOL-VILLARD 			}
292942ba996SJean-Christophe PLAGNIOL-VILLARD 			/* No break, fall through */
293942ba996SJean-Christophe PLAGNIOL-VILLARD 		case 1:
294942ba996SJean-Christophe PLAGNIOL-VILLARD 			/* Send address LSByte */
295942ba996SJean-Christophe PLAGNIOL-VILLARD 			tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK);
296942ba996SJean-Christophe PLAGNIOL-VILLARD 
297942ba996SJean-Christophe PLAGNIOL-VILLARD 			CHECK_NACK();
298942ba996SJean-Christophe PLAGNIOL-VILLARD 
299942ba996SJean-Christophe PLAGNIOL-VILLARD 			if (tmp & I2C_STAT_XRDY) {
300942ba996SJean-Christophe PLAGNIOL-VILLARD 				REG(I2C_DXR) = addr & 0xff;
301942ba996SJean-Christophe PLAGNIOL-VILLARD 			} else {
302942ba996SJean-Christophe PLAGNIOL-VILLARD 				REG(I2C_CON) = 0;
303942ba996SJean-Christophe PLAGNIOL-VILLARD 				return(1);
304942ba996SJean-Christophe PLAGNIOL-VILLARD 			}
305942ba996SJean-Christophe PLAGNIOL-VILLARD 	}
306942ba996SJean-Christophe PLAGNIOL-VILLARD 
307942ba996SJean-Christophe PLAGNIOL-VILLARD 	for (i = 0; i < len; i++) {
308942ba996SJean-Christophe PLAGNIOL-VILLARD 		tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK);
309942ba996SJean-Christophe PLAGNIOL-VILLARD 
310942ba996SJean-Christophe PLAGNIOL-VILLARD 		CHECK_NACK();
311942ba996SJean-Christophe PLAGNIOL-VILLARD 
312942ba996SJean-Christophe PLAGNIOL-VILLARD 		if (tmp & I2C_STAT_XRDY) {
313942ba996SJean-Christophe PLAGNIOL-VILLARD 			REG(I2C_DXR) = buf[i];
314942ba996SJean-Christophe PLAGNIOL-VILLARD 		} else {
315942ba996SJean-Christophe PLAGNIOL-VILLARD 			return(1);
316942ba996SJean-Christophe PLAGNIOL-VILLARD 		}
317942ba996SJean-Christophe PLAGNIOL-VILLARD 	}
318942ba996SJean-Christophe PLAGNIOL-VILLARD 
319942ba996SJean-Christophe PLAGNIOL-VILLARD 	tmp = poll_i2c_irq(I2C_STAT_SCD | I2C_STAT_NACK);
320942ba996SJean-Christophe PLAGNIOL-VILLARD 
321942ba996SJean-Christophe PLAGNIOL-VILLARD 	CHECK_NACK();
322942ba996SJean-Christophe PLAGNIOL-VILLARD 
323942ba996SJean-Christophe PLAGNIOL-VILLARD 	if (!(tmp & I2C_STAT_SCD)) {
324942ba996SJean-Christophe PLAGNIOL-VILLARD 		REG(I2C_CON) = 0;
325942ba996SJean-Christophe PLAGNIOL-VILLARD 		return(1);
326942ba996SJean-Christophe PLAGNIOL-VILLARD 	}
327942ba996SJean-Christophe PLAGNIOL-VILLARD 
328942ba996SJean-Christophe PLAGNIOL-VILLARD 	flush_rx();
329942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_STAT) = 0xffff;
330942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_CNT) = 0;
331942ba996SJean-Christophe PLAGNIOL-VILLARD 	REG(I2C_CON) = 0;
332942ba996SJean-Christophe PLAGNIOL-VILLARD 
333942ba996SJean-Christophe PLAGNIOL-VILLARD 	return(0);
334942ba996SJean-Christophe PLAGNIOL-VILLARD }
335