xref: /rk3399_rockchip-uboot/drivers/i2c/soft_i2c.c (revision 4d75e0aa9caca64d4a1d55d95cd1ca5f30d9fc56)
1*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD /*
2*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  * (C) Copyright 2001, 2002
3*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  *
5*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  * See file CREDITS for list of people who contributed to this
6*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  * project.
7*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  *
8*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  * This program is free software; you can redistribute it and/or
9*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  * modify it under the terms of the GNU General Public License as
10*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  * published by the Free Software Foundation; either version 2 of
11*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  * the License, or (at your option) any later version.
12*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  *
13*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  * This program is distributed in the hope that it will be useful,
14*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  * GNU General Public License for more details.
17*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  *
18*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  * You should have received a copy of the GNU General Public License
19*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  * along with this program; if not, write to the Free Software
20*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  * MA 02111-1307 USA
22*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  *
23*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  * This has been changed substantially by Gerald Van Baren, Custom IDEAS,
24*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  * vanbaren@cideas.com.  It was heavily influenced by LiMon, written by
25*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  * Neil Russell.
26*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  */
27*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
28*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #include <common.h>
29*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #ifdef	CONFIG_MPC8260			/* only valid for MPC8260 */
30*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #include <ioports.h>
31*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #endif
32*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #ifdef	CONFIG_AT91RM9200		/* need this for the at91rm9200 */
33*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #include <asm/io.h>
34*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #include <asm/arch/hardware.h>
35*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #endif
36*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #ifdef	CONFIG_IXP425			/* only valid for IXP425 */
37*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #include <asm/arch/ixp425.h>
38*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #endif
39*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_LPC2292
40*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #include <asm/arch/hardware.h>
41*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #endif
42*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #include <i2c.h>
43*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
44*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD /* #define	DEBUG_I2C	*/
45*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
46*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG_I2C
47*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD DECLARE_GLOBAL_DATA_PTR;
48*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #endif
49*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
50*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
51*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
52*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  * Definitions
53*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  */
54*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
55*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #define RETRIES		0
56*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
57*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
58*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #define I2C_ACK		0		/* PD_SDA level to ack a byte */
59*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #define I2C_NOACK	1		/* PD_SDA level to noack a byte */
60*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
61*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
62*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #ifdef DEBUG_I2C
63*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #define PRINTD(fmt,args...)	do {	\
64*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	if (gd->have_console)		\
65*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 		printf (fmt ,##args);	\
66*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	} while (0)
67*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #else
68*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #define PRINTD(fmt,args...)
69*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #endif
70*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
71*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
72*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  * Local functions
73*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  */
74*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD static void  send_reset	(void);
75*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD static void  send_start	(void);
76*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD static void  send_stop	(void);
77*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD static void  send_ack	(int);
78*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD static int   write_byte	(uchar byte);
79*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD static uchar read_byte	(int);
80*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
81*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
82*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
83*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  * Send a reset sequence consisting of 9 clocks with the data signal high
84*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  * to clock any confused device back into an idle state.  Also send a
85*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  * <stop> at the end of the sequence for belts & suspenders.
86*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  */
87*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD static void send_reset(void)
88*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD {
89*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #ifdef	CONFIG_MPC8260
90*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, I2C_PORT);
91*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #endif
92*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #ifdef	CONFIG_8xx
93*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	volatile immap_t *immr = (immap_t *)CFG_IMMR;
94*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #endif
95*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	int j;
96*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
97*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_SCL(1);
98*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_SDA(1);
99*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #ifdef	I2C_INIT
100*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_INIT;
101*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #endif
102*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_TRISTATE;
103*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	for(j = 0; j < 9; j++) {
104*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 		I2C_SCL(0);
105*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 		I2C_DELAY;
106*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 		I2C_DELAY;
107*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 		I2C_SCL(1);
108*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 		I2C_DELAY;
109*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 		I2C_DELAY;
110*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	}
111*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	send_stop();
112*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_TRISTATE;
113*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD }
114*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
115*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
116*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  * START: High -> Low on SDA while SCL is High
117*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  */
118*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD static void send_start(void)
119*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD {
120*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #ifdef	CONFIG_MPC8260
121*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, I2C_PORT);
122*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #endif
123*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #ifdef	CONFIG_8xx
124*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	volatile immap_t *immr = (immap_t *)CFG_IMMR;
125*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #endif
126*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
127*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_DELAY;
128*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_SDA(1);
129*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_ACTIVE;
130*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_DELAY;
131*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_SCL(1);
132*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_DELAY;
133*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_SDA(0);
134*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_DELAY;
135*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD }
136*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
137*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
138*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  * STOP: Low -> High on SDA while SCL is High
139*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  */
140*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD static void send_stop(void)
141*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD {
142*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #ifdef	CONFIG_MPC8260
143*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, I2C_PORT);
144*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #endif
145*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #ifdef	CONFIG_8xx
146*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	volatile immap_t *immr = (immap_t *)CFG_IMMR;
147*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #endif
148*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
149*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_SCL(0);
150*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_DELAY;
151*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_SDA(0);
152*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_ACTIVE;
153*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_DELAY;
154*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_SCL(1);
155*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_DELAY;
156*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_SDA(1);
157*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_DELAY;
158*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_TRISTATE;
159*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD }
160*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
161*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
162*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
163*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  * ack should be I2C_ACK or I2C_NOACK
164*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  */
165*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD static void send_ack(int ack)
166*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD {
167*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #ifdef	CONFIG_MPC8260
168*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, I2C_PORT);
169*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #endif
170*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #ifdef	CONFIG_8xx
171*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	volatile immap_t *immr = (immap_t *)CFG_IMMR;
172*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #endif
173*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
174*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_SCL(0);
175*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_DELAY;
176*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_ACTIVE;
177*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_SDA(ack);
178*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_DELAY;
179*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_SCL(1);
180*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_DELAY;
181*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_DELAY;
182*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_SCL(0);
183*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_DELAY;
184*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD }
185*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
186*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
187*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
188*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  * Send 8 bits and look for an acknowledgement.
189*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  */
190*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD static int write_byte(uchar data)
191*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD {
192*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #ifdef	CONFIG_MPC8260
193*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, I2C_PORT);
194*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #endif
195*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #ifdef	CONFIG_8xx
196*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	volatile immap_t *immr = (immap_t *)CFG_IMMR;
197*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #endif
198*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	int j;
199*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	int nack;
200*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
201*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_ACTIVE;
202*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	for(j = 0; j < 8; j++) {
203*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 		I2C_SCL(0);
204*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 		I2C_DELAY;
205*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 		I2C_SDA(data & 0x80);
206*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 		I2C_DELAY;
207*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 		I2C_SCL(1);
208*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 		I2C_DELAY;
209*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 		I2C_DELAY;
210*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
211*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 		data <<= 1;
212*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	}
213*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
214*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	/*
215*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	 * Look for an <ACK>(negative logic) and return it.
216*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	 */
217*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_SCL(0);
218*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_DELAY;
219*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_SDA(1);
220*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_TRISTATE;
221*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_DELAY;
222*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_SCL(1);
223*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_DELAY;
224*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_DELAY;
225*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	nack = I2C_READ;
226*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_SCL(0);
227*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_DELAY;
228*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_ACTIVE;
229*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
230*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	return(nack);	/* not a nack is an ack */
231*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD }
232*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
233*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
234*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
235*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  * if ack == I2C_ACK, ACK the byte so can continue reading, else
236*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  * send I2C_NOACK to end the read.
237*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  */
238*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD static uchar read_byte(int ack)
239*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD {
240*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #ifdef	CONFIG_MPC8260
241*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	volatile ioport_t *iop = ioport_addr((immap_t *)CFG_IMMR, I2C_PORT);
242*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #endif
243*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #ifdef	CONFIG_8xx
244*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	volatile immap_t *immr = (immap_t *)CFG_IMMR;
245*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #endif
246*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	int  data;
247*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	int  j;
248*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
249*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	/*
250*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	 * Read 8 bits, MSB first.
251*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	 */
252*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_TRISTATE;
253*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	I2C_SDA(1);
254*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	data = 0;
255*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	for(j = 0; j < 8; j++) {
256*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 		I2C_SCL(0);
257*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 		I2C_DELAY;
258*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 		I2C_SCL(1);
259*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 		I2C_DELAY;
260*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 		data <<= 1;
261*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 		data |= I2C_READ;
262*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 		I2C_DELAY;
263*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	}
264*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	send_ack(ack);
265*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
266*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	return(data);
267*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD }
268*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
269*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD /*=====================================================================*/
270*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD /*                         Public Functions                            */
271*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD /*=====================================================================*/
272*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
273*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
274*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  * Initialization
275*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  */
276*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD void i2c_init (int speed, int slaveaddr)
277*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD {
278*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	/*
279*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	 * WARNING: Do NOT save speed in a static variable: if the
280*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	 * I2C routines are called before RAM is initialized (to read
281*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	 * the DIMM SPD, for instance), RAM won't be usable and your
282*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	 * system will crash.
283*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	 */
284*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	send_reset ();
285*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD }
286*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
287*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
288*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  * Probe to see if a chip is present.  Also good for checking for the
289*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  * completion of EEPROM writes since the chip stops responding until
290*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  * the write completes (typically 10mSec).
291*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  */
292*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD int i2c_probe(uchar addr)
293*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD {
294*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	int rc;
295*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
296*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	/*
297*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	 * perform 1 byte write transaction with just address byte
298*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	 * (fake write)
299*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	 */
300*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	send_start();
301*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	rc = write_byte ((addr << 1) | 0);
302*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	send_stop();
303*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
304*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	return (rc ? 1 : 0);
305*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD }
306*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
307*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
308*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  * Read bytes
309*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  */
310*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD int  i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
311*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD {
312*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	int shift;
313*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	PRINTD("i2c_read: chip %02X addr %02X alen %d buffer %p len %d\n",
314*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 		chip, addr, alen, buffer, len);
315*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
316*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #ifdef CFG_I2C_EEPROM_ADDR_OVERFLOW
317*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	/*
318*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	 * EEPROM chips that implement "address overflow" are ones
319*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	 * like Catalyst 24WC04/08/16 which has 9/10/11 bits of
320*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	 * address and the extra bits end up in the "chip address"
321*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	 * bit slots. This makes a 24WC08 (1Kbyte) chip look like
322*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	 * four 256 byte chips.
323*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	 *
324*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	 * Note that we consider the length of the address field to
325*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	 * still be one byte because the extra address bits are
326*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	 * hidden in the chip address.
327*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	 */
328*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	chip |= ((addr >> (alen * 8)) & CFG_I2C_EEPROM_ADDR_OVERFLOW);
329*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
330*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	PRINTD("i2c_read: fix addr_overflow: chip %02X addr %02X\n",
331*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 		chip, addr);
332*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD #endif
333*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
334*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	/*
335*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	 * Do the addressing portion of a write cycle to set the
336*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	 * chip's address pointer.  If the address length is zero,
337*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	 * don't do the normal write cycle to set the address pointer,
338*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	 * there is no address pointer in this chip.
339*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	 */
340*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	send_start();
341*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	if(alen > 0) {
342*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 		if(write_byte(chip << 1)) {	/* write cycle */
343*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 			send_stop();
344*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 			PRINTD("i2c_read, no chip responded %02X\n", chip);
345*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 			return(1);
346*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 		}
347*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 		shift = (alen-1) * 8;
348*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 		while(alen-- > 0) {
349*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 			if(write_byte(addr >> shift)) {
350*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 				PRINTD("i2c_read, address not <ACK>ed\n");
351*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 				return(1);
352*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 			}
353*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 			shift -= 8;
354*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 		}
355*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 		send_stop();	/* reportedly some chips need a full stop */
356*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 		send_start();
357*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	}
358*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	/*
359*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	 * Send the chip address again, this time for a read cycle.
360*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	 * Then read the data.  On the last byte, we do a NACK instead
361*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	 * of an ACK(len == 0) to terminate the read.
362*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	 */
363*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	write_byte((chip << 1) | 1);	/* read cycle */
364*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	while(len-- > 0) {
365*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 		*buffer++ = read_byte(len == 0);
366*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	}
367*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	send_stop();
368*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	return(0);
369*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD }
370*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
371*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
372*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  * Write bytes
373*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  */
374*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD int  i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
375*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD {
376*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	int shift, failures = 0;
377*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
378*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	PRINTD("i2c_write: chip %02X addr %02X alen %d buffer %p len %d\n",
379*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 		chip, addr, alen, buffer, len);
380*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
381*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	send_start();
382*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	if(write_byte(chip << 1)) {	/* write cycle */
383*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 		send_stop();
384*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 		PRINTD("i2c_write, no chip responded %02X\n", chip);
385*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 		return(1);
386*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	}
387*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	shift = (alen-1) * 8;
388*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	while(alen-- > 0) {
389*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 		if(write_byte(addr >> shift)) {
390*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 			PRINTD("i2c_write, address not <ACK>ed\n");
391*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 			return(1);
392*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 		}
393*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 		shift -= 8;
394*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	}
395*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
396*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	while(len-- > 0) {
397*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 		if(write_byte(*buffer++)) {
398*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 			failures++;
399*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 		}
400*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	}
401*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	send_stop();
402*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	return(failures);
403*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD }
404*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
405*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
406*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  * Read a register
407*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  */
408*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD uchar i2c_reg_read(uchar i2c_addr, uchar reg)
409*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD {
410*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	uchar buf;
411*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
412*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	i2c_read(i2c_addr, reg, 1, &buf, 1);
413*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
414*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	return(buf);
415*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD }
416*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 
417*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD /*-----------------------------------------------------------------------
418*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  * Write a register
419*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD  */
420*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD void i2c_reg_write(uchar i2c_addr, uchar reg, uchar val)
421*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD {
422*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD 	i2c_write(i2c_addr, reg, 1, &val, 1);
423*4d75e0aaSJean-Christophe PLAGNIOL-VILLARD }
424