1 | #ifndef RTEMS_LIBI2C_H |
---|
2 | #define RTEMS_LIBI2C_H |
---|
3 | /*$Id$*/ |
---|
4 | |
---|
5 | /* |
---|
6 | * Authorship |
---|
7 | * ---------- |
---|
8 | * This software was created by |
---|
9 | * Till Straumann <strauman@slac.stanford.edu>, 2005, |
---|
10 | * Stanford Linear Accelerator Center, Stanford University. |
---|
11 | * |
---|
12 | * Acknowledgement of sponsorship |
---|
13 | * ------------------------------ |
---|
14 | * This software was produced by |
---|
15 | * the Stanford Linear Accelerator Center, Stanford University, |
---|
16 | * under Contract DE-AC03-76SFO0515 with the Department of Energy. |
---|
17 | * |
---|
18 | * Government disclaimer of liability |
---|
19 | * ---------------------------------- |
---|
20 | * Neither the United States nor the United States Department of Energy, |
---|
21 | * nor any of their employees, makes any warranty, express or implied, or |
---|
22 | * assumes any legal liability or responsibility for the accuracy, |
---|
23 | * completeness, or usefulness of any data, apparatus, product, or process |
---|
24 | * disclosed, or represents that its use would not infringe privately owned |
---|
25 | * rights. |
---|
26 | * |
---|
27 | * Stanford disclaimer of liability |
---|
28 | * -------------------------------- |
---|
29 | * Stanford University makes no representations or warranties, express or |
---|
30 | * implied, nor assumes any liability for the use of this software. |
---|
31 | * |
---|
32 | * Stanford disclaimer of copyright |
---|
33 | * -------------------------------- |
---|
34 | * Stanford University, owner of the copyright, hereby disclaims its |
---|
35 | * copyright and all other rights in this software. Hence, anyone may |
---|
36 | * freely use it for any purpose without restriction. |
---|
37 | * |
---|
38 | * Maintenance of notices |
---|
39 | * ---------------------- |
---|
40 | * In the interest of clarity regarding the origin and status of this |
---|
41 | * SLAC software, this and all the preceding Stanford University notices |
---|
42 | * are to remain affixed to any copy or derivative of this software made |
---|
43 | * or distributed by the recipient and are to be affixed to any copy of |
---|
44 | * software made or distributed by the recipient that contains a copy or |
---|
45 | * derivative of this software. |
---|
46 | * |
---|
47 | * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 |
---|
48 | */ |
---|
49 | |
---|
50 | #include <rtems.h> |
---|
51 | |
---|
52 | #include <rtems/io.h> |
---|
53 | |
---|
54 | #ifdef __cplusplus |
---|
55 | extern "C" { |
---|
56 | #endif |
---|
57 | |
---|
58 | /* Simple I2C driver API */ |
---|
59 | |
---|
60 | /* Initialize the libary - may fail if no semaphore or no driver slot is available */ |
---|
61 | int rtems_libi2c_initialize (void); |
---|
62 | |
---|
63 | /* Alternatively to rtems_libi2c_initialize() the library can also be |
---|
64 | * initialized by means of a traditional driver table entry containing |
---|
65 | * the following entry points: |
---|
66 | */ |
---|
67 | rtems_status_code |
---|
68 | rtems_i2c_init ( |
---|
69 | rtems_device_major_number major, |
---|
70 | rtems_device_minor_number minor, |
---|
71 | void *arg); |
---|
72 | |
---|
73 | rtems_status_code |
---|
74 | rtems_i2c_open ( |
---|
75 | rtems_device_major_number major, |
---|
76 | rtems_device_minor_number minor, |
---|
77 | void *arg); |
---|
78 | |
---|
79 | rtems_status_code |
---|
80 | rtems_i2c_close ( |
---|
81 | rtems_device_major_number major, |
---|
82 | rtems_device_minor_number minor, |
---|
83 | void *arg); |
---|
84 | |
---|
85 | rtems_status_code |
---|
86 | rtems_i2c_read ( |
---|
87 | rtems_device_major_number major, |
---|
88 | rtems_device_minor_number minor, |
---|
89 | void *arg); |
---|
90 | |
---|
91 | rtems_status_code |
---|
92 | rtems_i2c_write ( |
---|
93 | rtems_device_major_number major, |
---|
94 | rtems_device_minor_number minor, |
---|
95 | void *arg); |
---|
96 | |
---|
97 | rtems_status_code |
---|
98 | rtems_i2c_ioctl ( |
---|
99 | rtems_device_major_number major, |
---|
100 | rtems_device_minor_number minor, |
---|
101 | void *arg); |
---|
102 | |
---|
103 | extern const rtems_driver_address_table rtems_libi2c_io_ops; |
---|
104 | |
---|
105 | /* Unfortunately, if you want to add this driver to |
---|
106 | * a RTEMS configuration table then you need all the |
---|
107 | * members explicitly :-( (Device_driver_table should |
---|
108 | * hold pointers to rtems_driver_address_tables rather |
---|
109 | * than full structs). |
---|
110 | * |
---|
111 | * The difficulty is that adding this driver to the |
---|
112 | * configuration table is not enough; you still need |
---|
113 | * to populate the framework with low-level bus-driver(s) |
---|
114 | * and high-level drivers and/or device-files... |
---|
115 | * |
---|
116 | * Currently the preferred way is having the BSP |
---|
117 | * call 'rtems_libi2c_initialize' followed by |
---|
118 | * 'rtems_libi2c_register_bus' and |
---|
119 | * 'rtems_libi2c_register_drv' and/or |
---|
120 | * 'mknod' (for 'raw' device nodes) |
---|
121 | * from the 'pretasking_hook'. |
---|
122 | */ |
---|
123 | #define RTEMS_LIBI2C_DRIVER_TABLE_ENTRY \ |
---|
124 | { \ |
---|
125 | initialization_entry: rtems_i2c_init, \ |
---|
126 | open_entry: rtems_i2c_open, \ |
---|
127 | close_entry: rtems_i2c_close, \ |
---|
128 | read_entry: rtems_i2c_read, \ |
---|
129 | write_entry: rtems_i2c_write, \ |
---|
130 | control_entry: rtems_i2c_ioctl, \ |
---|
131 | } |
---|
132 | |
---|
133 | /* Bus Driver API |
---|
134 | * |
---|
135 | * Bus drivers provide access to low-level i2c functions |
---|
136 | * such as 'send start', 'send address', 'get bytes' etc. |
---|
137 | */ |
---|
138 | |
---|
139 | /* first field must be a pointer to ops; driver |
---|
140 | * may add its own fields after this. |
---|
141 | * the struct that is registered with the library |
---|
142 | * is not copied; a pointer will we passed |
---|
143 | * to the callback functions (ops). |
---|
144 | */ |
---|
145 | typedef struct rtems_libi2c_bus_t_ |
---|
146 | { |
---|
147 | const struct rtems_libi2c_bus_ops_ *ops; |
---|
148 | int size; /* size of whole structure */ |
---|
149 | } rtems_libi2c_bus_t; |
---|
150 | |
---|
151 | /* Access functions a low level driver must provide; |
---|
152 | * |
---|
153 | * All of these, except read_bytes and write_bytes |
---|
154 | * return RTEMS_SUCCESSFUL on success and an error status |
---|
155 | * otherwise. The read and write ops return the number |
---|
156 | * of chars read/written or -(status code) on error. |
---|
157 | */ |
---|
158 | typedef struct rtems_libi2c_bus_ops_ |
---|
159 | { |
---|
160 | /* Initialize the bus; might be called again to reset the bus driver */ |
---|
161 | rtems_status_code (*init) (rtems_libi2c_bus_t * bushdl); |
---|
162 | /* Send start condition */ |
---|
163 | rtems_status_code (*send_start) (rtems_libi2c_bus_t * bushdl); |
---|
164 | /* Send stop condition */ |
---|
165 | rtems_status_code (*send_stop) (rtems_libi2c_bus_t * bushdl); |
---|
166 | /* initiate transfer from (rw!=0) or to a device */ |
---|
167 | rtems_status_code (*send_addr) (rtems_libi2c_bus_t * bushdl, |
---|
168 | uint32_t addr, int rw); |
---|
169 | /* read a number of bytes */ |
---|
170 | int (*read_bytes) (rtems_libi2c_bus_t * bushdl, unsigned char *bytes, |
---|
171 | int nbytes); |
---|
172 | /* write a number of bytes */ |
---|
173 | int (*write_bytes) (rtems_libi2c_bus_t * bushdl, unsigned char *bytes, |
---|
174 | int nbytes); |
---|
175 | /* ioctl misc functions */ |
---|
176 | int (*ioctl) (rtems_libi2c_bus_t * bushdl, |
---|
177 | int cmd, |
---|
178 | void *buffer |
---|
179 | ); |
---|
180 | } rtems_libi2c_bus_ops_t; |
---|
181 | |
---|
182 | |
---|
183 | /* |
---|
184 | * Register a lowlevel driver |
---|
185 | * |
---|
186 | * TODO: better description |
---|
187 | * |
---|
188 | * This allocates a major number identifying *this* driver |
---|
189 | * (i.e., libi2c) and the minor number encodes a bus# and a i2c address. |
---|
190 | * |
---|
191 | * The name will be registered in the filesystem (parent |
---|
192 | * directories must exist, also IMFS filesystem must exist see |
---|
193 | * CONFIGURE_USE_IMFS_AS_BASE_FILESYSTEM). It may be NULL in which case |
---|
194 | * the library will pick a default. |
---|
195 | * |
---|
196 | * RETURNS: bus # (>=0) or -1 on error (errno set). |
---|
197 | */ |
---|
198 | |
---|
199 | int rtems_libi2c_register_bus (const char *name, rtems_libi2c_bus_t * bus); |
---|
200 | |
---|
201 | extern rtems_device_major_number rtems_libi2c_major; |
---|
202 | |
---|
203 | #define RTEMS_LIBI2C_MAKE_MINOR(busno, i2caddr) \ |
---|
204 | ((((busno)&((1<<3)-1))<<10) | ((i2caddr)&((1<<10)-1))) |
---|
205 | |
---|
206 | /* After the library is initialized, a major number is available. |
---|
207 | * As soon as a low-level bus driver is registered (above routine |
---|
208 | * returns a 'busno'), a device node can be created in the filesystem |
---|
209 | * with a major/minor number pair of |
---|
210 | * |
---|
211 | * rtems_libi2c_major / RTEMS_LIBI2C_MAKE_MINOR(busno, i2caddr) |
---|
212 | * |
---|
213 | * and a 'raw' hi-level driver is then attached to this device |
---|
214 | * node. |
---|
215 | * This 'raw' driver has very simple semantics: |
---|
216 | * |
---|
217 | * 'open' sends a start condition |
---|
218 | * 'read'/'write' address the device identified by the i2c bus# and address |
---|
219 | * encoded in the minor number and read or write, respectively |
---|
220 | * a stream of bytes from or to the device. Every time the |
---|
221 | * direction is changed, a 're-start' condition followed by |
---|
222 | * an 'address' cycle is generated on the i2c bus. |
---|
223 | * 'close' sends a stop condition. |
---|
224 | * |
---|
225 | * Hence, using the 'raw' driver, e.g., 100 bytes at offset 0x200 can be |
---|
226 | * read from an EEPROM by the following pseudo-code: |
---|
227 | * |
---|
228 | * mknod("/dev/i2c-54", mode, MKDEV(rtems_libi2c_major, RTEMS_LIBI2C_MAKE_MINOR(0,0x54))) |
---|
229 | * |
---|
230 | * int fd; |
---|
231 | * char off[2]={0x02,0x00}; |
---|
232 | * |
---|
233 | * fd = open("/dev/i2c-54",O_RDWR); |
---|
234 | * write(fd,off,2); |
---|
235 | * read(fd,buf,100); |
---|
236 | * close(fd); |
---|
237 | * |
---|
238 | */ |
---|
239 | |
---|
240 | /* Higher Level Driver API |
---|
241 | * |
---|
242 | * Higher level drivers know how to deal with specific i2c |
---|
243 | * devices (independent of the bus interface chip) and provide |
---|
244 | * an abstraction, i.e., the usual read/write/ioctl access. |
---|
245 | * |
---|
246 | * Using the above example, such a high level driver could |
---|
247 | * prevent the user from issuing potentially destructive write |
---|
248 | * operations (the aforementioned EEPROM interprets any 3rd |
---|
249 | * and following byte written to the device as data, i.e., the |
---|
250 | * contents could easily be changed!). |
---|
251 | * The correct 'read-pointer offset' programming could be |
---|
252 | * implemented in 'open' and 'ioctl' of a high-level driver and |
---|
253 | * the user would then only have to perform harmless read |
---|
254 | * operations, e.g., |
---|
255 | * |
---|
256 | * fd = open("/dev/i2c.eeprom",O_RDONLY) / * opens and sets EEPROM read pointer * / |
---|
257 | * ioctl(fd, IOCTL_SEEK, 0x200) / * repositions the read pointer * / |
---|
258 | * read(fd, buf, 100) |
---|
259 | * close(fd) |
---|
260 | * |
---|
261 | */ |
---|
262 | |
---|
263 | /* struct provided at driver registration. The driver may store |
---|
264 | * private data behind the mandatory first fields but the size |
---|
265 | * must be set to the size of the entire struct, e.g., |
---|
266 | * |
---|
267 | * struct driver_pvt { |
---|
268 | * rtems_libi2c_drv_t pub; |
---|
269 | * struct { ... } pvt; |
---|
270 | * } my_driver = { |
---|
271 | * { ops: my_ops, |
---|
272 | * size: sizeof(my_driver) |
---|
273 | * }, |
---|
274 | * { ...}; |
---|
275 | * }; |
---|
276 | * |
---|
277 | * A pointer to this struct is passed to the callback ops. |
---|
278 | */ |
---|
279 | |
---|
280 | typedef struct rtems_libi2c_drv_t_ |
---|
281 | { |
---|
282 | const rtems_driver_address_table *ops; /* the driver ops */ |
---|
283 | int size; /* size of whole structure (including appended private data) */ |
---|
284 | } rtems_libi2c_drv_t; |
---|
285 | |
---|
286 | /* |
---|
287 | * The high level driver must be registered with a particular |
---|
288 | * bus number and i2c address. |
---|
289 | * |
---|
290 | * The registration procedure also creates a filesystem node, |
---|
291 | * i.e., the returned minor number is not really needed. |
---|
292 | * |
---|
293 | * If the 'name' argument is NULL, no filesystem node is |
---|
294 | * created (but this can be done 'manually' using rtems_libi2c_major |
---|
295 | * and the return value of this routine). |
---|
296 | * |
---|
297 | * RETURNS minor number (FYI) or -1 on failure |
---|
298 | */ |
---|
299 | int |
---|
300 | rtems_libi2c_register_drv (const char *name, rtems_libi2c_drv_t * drvtbl, |
---|
301 | unsigned bus, unsigned i2caddr); |
---|
302 | |
---|
303 | /* Operations available to high level drivers */ |
---|
304 | |
---|
305 | /* NOTES: The bus a device is attached to is LOCKED from the first send_start |
---|
306 | * until send_stop is executed! |
---|
307 | * |
---|
308 | * Bus tenure MUST NOT span multiple system calls - otherwise, a single |
---|
309 | * thread could get into the protected sections (or would deadlock if the |
---|
310 | * mutex was not nestable). |
---|
311 | * E.g., consider what happens if 'open' sends a 'start' and 'close' |
---|
312 | * sends a 'stop' (i.e., the bus mutex would be locked in 'open' and |
---|
313 | * released in 'close'. A single thread could try to open two devices |
---|
314 | * on the same bus and would either deadlock or nest into the bus mutex |
---|
315 | * and potentially mess up the i2c messages. |
---|
316 | * |
---|
317 | * The correct way is to *always* relinquish the i2c bus (i.e., send 'stop' |
---|
318 | * from any driver routine prior to returning control to the caller. |
---|
319 | * Consult the implementation of the generic driver routines (open, close, ...) |
---|
320 | * below or the examples in i2c-2b-eeprom.c and i2c-2b-ds1621.c |
---|
321 | * |
---|
322 | * Drivers just pass the minor number on to these routines... |
---|
323 | */ |
---|
324 | rtems_status_code rtems_libi2c_send_start (rtems_device_minor_number minor); |
---|
325 | |
---|
326 | rtems_status_code rtems_libi2c_send_stop (rtems_device_minor_number minor); |
---|
327 | |
---|
328 | rtems_status_code |
---|
329 | rtems_libi2c_send_addr (rtems_device_minor_number minor, int rw); |
---|
330 | |
---|
331 | /* the read/write routines return the number of bytes transferred |
---|
332 | * or -(status_code) on error. |
---|
333 | */ |
---|
334 | int |
---|
335 | rtems_libi2c_read_bytes (rtems_device_minor_number minor, |
---|
336 | unsigned char *bytes, int nbytes); |
---|
337 | |
---|
338 | int |
---|
339 | rtems_libi2c_write_bytes (rtems_device_minor_number minor, |
---|
340 | const unsigned char *bytes, int nbytes); |
---|
341 | |
---|
342 | /* Send start, send address and read bytes */ |
---|
343 | int |
---|
344 | rtems_libi2c_start_read_bytes (rtems_device_minor_number minor, |
---|
345 | unsigned char *bytes, |
---|
346 | int nbytes); |
---|
347 | |
---|
348 | /* Send start, send address and write bytes */ |
---|
349 | int |
---|
350 | rtems_libi2c_start_write_bytes (rtems_device_minor_number minor, |
---|
351 | const unsigned char *bytes, |
---|
352 | int nbytes); |
---|
353 | |
---|
354 | |
---|
355 | /* call misc iocontrol function */ |
---|
356 | int |
---|
357 | rtems_libi2c_ioctl (rtems_device_minor_number minor, |
---|
358 | int cmd, |
---|
359 | ...); |
---|
360 | /* |
---|
361 | * NOTE: any low-level driver ioctl returning a negative |
---|
362 | * result for release the bus (perform a STOP condition) |
---|
363 | */ |
---|
364 | /******************************* |
---|
365 | * defined IOCTLs: |
---|
366 | *******************************/ |
---|
367 | #define RTEMS_LIBI2C_IOCTL_READ_WRITE 1 |
---|
368 | /* |
---|
369 | * retval = rtems_libi2c_ioctl(rtems_device_minor_number minor, |
---|
370 | * RTEMS_LIBI2C_IOCTL_READ_WRITE, |
---|
371 | * rtems_libi2c_read_write_t *arg); |
---|
372 | * |
---|
373 | * This call performs a simultanous read/write transfer, |
---|
374 | * which is possible (and sometimes needed) for SPI devices |
---|
375 | * |
---|
376 | * arg is a pointer to a rd_wr info data structure |
---|
377 | * |
---|
378 | * This call is only needed for SPI devices |
---|
379 | */ |
---|
380 | #define RTEMS_LIBI2C_IOCTL_START_TFM_READ_WRITE 2 |
---|
381 | /* |
---|
382 | * retval = rtems_libi2c_ioctl(rtems_device_minor_number minor, |
---|
383 | * RTEMS_LIBI2C_IOCTL_START_READ_WRITE, |
---|
384 | * unsigned char *rd_buffer, |
---|
385 | * const unsigned char *wr_buffer, |
---|
386 | * int byte_cnt, |
---|
387 | * const rtems_libi2c_tfr_mode_t *tfr_mode_ptr); |
---|
388 | * |
---|
389 | * This call addresses a slave and then: |
---|
390 | * - sets the proper transfer mode, |
---|
391 | * - performs a simultanous read/write transfer, |
---|
392 | * (which is possible and sometimes needed for SPI devices) |
---|
393 | * NOTE: - if rd_buffer is NULL, receive data will be dropped |
---|
394 | * - if wr_buffer is NULL, bytes with content 0 will transmitted |
---|
395 | * |
---|
396 | * rd_buffer is a pointer to a receive buffer (or NULL) |
---|
397 | * wr_buffer is a pointer to the data to be sent (or NULL) |
---|
398 | * |
---|
399 | * This call is only needed for SPI devices |
---|
400 | */ |
---|
401 | |
---|
402 | #define RTEMS_LIBI2C_IOCTL_SET_TFRMODE 3 |
---|
403 | /* |
---|
404 | * retval = rtems_libi2c_ioctl(rtems_device_minor_number minor, |
---|
405 | * RTEMS_LIBI2C_IOCTL_SET_TFRMODE, |
---|
406 | * const rtems_libi2c_tfr_mode_t *tfr_mode_ptr); |
---|
407 | * |
---|
408 | * This call sets an SPI device to the transfer mode needed (baudrate etc.) |
---|
409 | * |
---|
410 | * tfr_mode is a pointer to a structure defining the SPI transfer mode needed |
---|
411 | * (see below). |
---|
412 | * |
---|
413 | * This call is only needed for SPI devices |
---|
414 | */ |
---|
415 | |
---|
416 | #define RTEMS_LIBI2C_IOCTL_GET_DRV_T 4 |
---|
417 | /* |
---|
418 | * retval = rtems_libi2c_ioctl(rtems_device_minor_number minor, |
---|
419 | * RTEMS_LIBI2C_IOCTL_GET_DRV_T, |
---|
420 | * const rtems_libi2c_drv_t *drv_t_ptr); |
---|
421 | * |
---|
422 | * This call allows the a high-level driver to query its driver table entry, |
---|
423 | * including its private data appended to it during creation of the entry |
---|
424 | * |
---|
425 | */ |
---|
426 | |
---|
427 | /* |
---|
428 | * argument data structures for IOCTLs defined above |
---|
429 | */ |
---|
430 | typedef struct { |
---|
431 | unsigned char *rd_buf; |
---|
432 | const unsigned char *wr_buf; |
---|
433 | int byte_cnt; |
---|
434 | } rtems_libi2c_read_write_t; |
---|
435 | |
---|
436 | typedef struct { |
---|
437 | uint32_t baudrate; /* maximum bits per second */ |
---|
438 | /* only valid for SPI drivers: */ |
---|
439 | uint8_t bits_per_char; /* how many bits per byte/word/longword? */ |
---|
440 | bool lsb_first; /* true: send LSB first */ |
---|
441 | bool clock_inv; /* true: inverted clock (high active) */ |
---|
442 | bool clock_phs; /* true: clock starts toggling at start of data tfr */ |
---|
443 | uint32_t idle_char; /* This character will be continuously transmitted in read only functions */ |
---|
444 | } rtems_libi2c_tfr_mode_t; |
---|
445 | |
---|
446 | typedef struct { |
---|
447 | rtems_libi2c_tfr_mode_t tfr_mode; |
---|
448 | rtems_libi2c_read_write_t rd_wr; |
---|
449 | } rtems_libi2c_tfm_read_write_t; |
---|
450 | |
---|
451 | |
---|
452 | #ifdef __cplusplus |
---|
453 | } |
---|
454 | #endif |
---|
455 | |
---|
456 | #endif |
---|