Added bit-bashing i2c interface code
[people/xl0/gpxe.git] / src / drivers / bitbash / i2c_bit.c
1 /*
2  * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 #include <stddef.h>
20 #include <stdint.h>
21 #include <errno.h>
22 #include <assert.h>
23 #include <gpxe/bitbash.h>
24 #include <gpxe/i2c.h>
25
26 /** @file
27  *
28  * I2C bit-bashing interface
29  *
30  * This implements a simple I2C master via a bit-bashing interface
31  * that provides two lines: SCL (clock) and SDA (data).
32  */
33
34 /**
35  * Set state of I2C SCL line
36  *
37  * @v basher            Bit-bashing interface
38  * @v state             New state of SCL
39  */
40 static inline __attribute__ (( always_inline )) void
41 setscl ( struct bit_basher *basher, int state ) {
42         write_bit ( basher, I2C_BIT_SCL, state );
43 }
44
45 /**
46  * Set state of I2C SDA line
47  *
48  * @v basher            Bit-bashing interface
49  * @v state             New state of SDA
50  */
51 static inline __attribute__ (( always_inline )) void
52 setsda ( struct bit_basher *basher, int state ) {
53         write_bit ( basher, I2C_BIT_SDA, state );
54 }
55
56 /**
57  * Get state of I2C SDA line
58  *
59  * @v basher            Bit-bashing interface
60  * @ret state           State of SDA
61  */
62 static inline __attribute__ (( always_inline )) int
63 getsda ( struct bit_basher *basher ) {
64         return read_bit ( basher, I2C_BIT_SDA );
65 }
66
67 /**
68  * Send an I2C start condition
69  *
70  * @v basher            Bit-bashing interface
71  */
72 static void i2c_start ( struct bit_basher *basher ) {
73         setscl ( basher, 1 );
74         setsda ( basher, 0 );
75         setscl ( basher, 0 );
76         setsda ( basher, 1 );
77 }
78
79 /**
80  * Send an I2C data bit
81  *
82  * @v basher            Bit-bashing interface
83  * @v bit               Bit to send
84  */
85 static void i2c_send_bit ( struct bit_basher *basher, int bit ) {
86         setsda ( basher, bit );
87         setscl ( basher, 1 );
88         setscl ( basher, 0 );
89         setsda ( basher, 1 );
90 }
91
92 /**
93  * Receive an I2C data bit
94  *
95  * @v basher            Bit-bashing interface
96  * @ret bit             Received bit
97  */
98 static int i2c_recv_bit ( struct bit_basher *basher ) {
99         int bit;
100
101         setscl ( basher, 1 );
102         bit = getsda ( basher );
103         setscl ( basher, 0 );
104         return bit;
105 }
106
107 /**
108  * Send an I2C stop condition
109  *
110  * @v basher            Bit-bashing interface
111  */
112 static void i2c_stop ( struct bit_basher *basher ) {
113         setsda ( basher, 0 );
114         setscl ( basher, 1 );
115         setsda ( basher, 1 );
116 }
117
118 /**
119  * Send byte via I2C bus and check for acknowledgement
120  *
121  * @v basher            Bit-bashing interface
122  * @v byte              Byte to send
123  * @ret rc              Return status code
124  *
125  * Sends a byte via the I2C bus and checks for an acknowledgement from
126  * the slave device.
127  */
128 static int i2c_send_byte ( struct bit_basher *basher, uint8_t byte ) {
129         int i;
130         
131         /* Send byte */
132         for ( i = 8 ; i ; i-- ) {
133                 i2c_send_bit ( basher, byte & 0x80 );
134                 byte <<= 1;
135         }
136
137         /* Check for acknowledgement from slave */
138         return ( i2c_recv_bit ( basher ) == 0 ? 0 : -EIO );
139 }
140
141 /**
142  * Receive byte via I2C bus
143  *
144  * @v basher            Bit-bashing interface
145  * @ret byte            Received byte
146  *
147  * Receives a byte via the I2C bus and sends NACK to the slave device.
148  */
149 static uint8_t i2c_recv_byte ( struct bit_basher *basher ) {
150         uint8_t value = 0;
151         int i;
152
153         /* Receive byte */
154         for ( i = 8 ; i ; i-- ) {
155                 value <<= 1;
156                 value |= i2c_recv_bit ( basher );
157         }
158
159         /* Send NACK */
160         i2c_send_bit ( basher, 1 );
161
162         return value;
163 }
164
165 /**
166  * Select I2C device for reading or writing
167  *
168  * @v basher            Bit-bashing interface
169  * @v i2cdev            I2C device
170  * @v direction         I2C_READ or I2C_WRITE
171  * @ret rc              Return status code
172  */
173 static int i2c_select ( struct bit_basher *basher, struct i2c_device *i2cdev,
174                         unsigned int direction ) {
175         unsigned int address;
176         int rc;
177
178         i2c_start ( basher );
179
180         /* First byte of the address */
181         address = i2cdev->address;
182         if ( i2cdev->tenbit ) {
183                 address |= I2C_TENBIT_ADDRESS;
184                 address >>= 8;
185         }
186         if ( ( rc = i2c_send_byte ( basher, 
187                                     ( ( address << 1 ) | direction ) ) ) != 0 )
188                 return rc;
189
190         /* Second byte of the address (10-bit addresses only) */
191         if ( i2cdev->tenbit ) {
192                 if ( ( rc = i2c_send_byte ( basher,
193                                             ( i2cdev->address & 0xff ) ) ) !=0)
194                         return rc;
195         }
196
197         return 0;
198 }
199
200 /**
201  * Read data from I2C device via bit-bashing interface
202  *
203  * @v i2c               I2C interface
204  * @v i2cdev            I2C device
205  * @v offset            Starting offset within the device
206  * @v data              Data buffer
207  * @v len               Length of data buffer
208  * @ret rc              Return status code
209  *
210  * Note that attempting to read zero bytes of data is a valid way to
211  * check for I2C device presence.
212  */
213 static int i2c_bit_read ( struct i2c_interface *i2c,
214                           struct i2c_device *i2cdev, unsigned int offset,
215                           uint8_t *data, unsigned int len ) {
216         struct i2c_bit_basher *i2cbit
217                 = container_of ( i2c, struct i2c_bit_basher, i2c );
218         struct bit_basher *basher = &i2cbit->basher;
219         int rc = 0;
220
221         DBG ( "Reading from I2C device %x: ", i2cdev->address );
222
223         while ( 1 ) {
224
225                 /* Select device for writing */
226                 if ( ( rc = i2c_select ( basher, i2cdev, I2C_WRITE ) ) != 0 )
227                         break;
228
229                 /* Abort at end of data */
230                 if ( ! ( len-- ) )
231                         break;
232
233                 /* Select offset */
234                 if ( ( rc = i2c_send_byte ( basher, offset++ ) ) != 0 )
235                         break;
236                 
237                 /* Select device for reading */
238                 if ( ( rc = i2c_select ( basher, i2cdev, I2C_READ ) ) != 0 )
239                         break;
240
241                 /* Read byte */
242                 *data++ = i2c_recv_byte ( basher );
243                 DBG ( "%02x ", *(data - 1) );
244         }
245         
246         DBG ( "%s\n", ( rc ? "failed" : "" ) );
247         i2c_stop ( basher );
248         return rc;
249 }
250
251 /**
252  * Write data to I2C device via bit-bashing interface
253  *
254  * @v i2c               I2C interface
255  * @v i2cdev            I2C device
256  * @v offset            Starting offset within the device
257  * @v data              Data buffer
258  * @v len               Length of data buffer
259  * @ret rc              Return status code
260  *
261  * Note that attempting to write zero bytes of data is a valid way to
262  * check for I2C device presence.
263  */
264 static int i2c_bit_write ( struct i2c_interface *i2c,
265                            struct i2c_device *i2cdev, unsigned int offset,
266                            const uint8_t *data, unsigned int len ) {
267         struct i2c_bit_basher *i2cbit
268                 = container_of ( i2c, struct i2c_bit_basher, i2c );
269         struct bit_basher *basher = &i2cbit->basher;
270         int rc = 0;
271
272         DBG ( "Writing to I2C device %x: ", i2cdev->address );
273
274         while ( 1 ) {
275
276                 /* Select device for writing */
277                 if ( ( rc = i2c_select ( basher, i2cdev, I2C_WRITE ) ) != 0 )
278                         break;
279                 
280                 /* Abort at end of data */
281                 if ( ! ( len-- ) )
282                         break;
283
284                 /* Select offset */
285                 if ( ( rc = i2c_send_byte ( basher, offset++ ) ) != 0 )
286                         break;
287                 
288                 /* Write data to device */
289                 DBG ( "%02x ", *data );
290                 if ( ( rc = i2c_send_byte ( basher, *data++ ) ) != 0 )
291                         break;
292         }
293         
294         DBG ( "%s\n", ( rc ? "failed" : "" ) );
295         i2c_stop ( basher );
296         return rc;
297 }
298
299 /**
300  * Initialise I2C bit-bashing interface
301  *
302  * @v i2cbit            I2C bit-bashing interface
303  */
304 void init_i2c_bit_basher ( struct i2c_bit_basher *i2cbit ) {
305         struct bit_basher *basher = &i2cbit->basher;
306         
307         assert ( basher->read != NULL );
308         assert ( basher->write != NULL );
309         i2cbit->i2c.read = i2c_bit_read;
310         i2cbit->i2c.write = i2c_bit_write;
311         basher->udelay = I2C_UDELAY;
312         i2c_stop ( basher );
313 }