summaryrefslogtreecommitdiffstats
path: root/cpukit/libi2c/libi2c.h
diff options
context:
space:
mode:
Diffstat (limited to 'cpukit/libi2c/libi2c.h')
-rw-r--r--cpukit/libi2c/libi2c.h510
1 files changed, 510 insertions, 0 deletions
diff --git a/cpukit/libi2c/libi2c.h b/cpukit/libi2c/libi2c.h
new file mode 100644
index 0000000000..89edcb95d1
--- /dev/null
+++ b/cpukit/libi2c/libi2c.h
@@ -0,0 +1,510 @@
+/**
+ * @file
+ *
+ * @ingroup libi2c
+ *
+ * @brief I2C library.
+ */
+
+#ifndef _RTEMS_LIBI2C_H
+#define _RTEMS_LIBI2C_H
+/*$Id$*/
+
+/*
+ * Authorship
+ * ----------
+ * This software was created by
+ * Till Straumann <strauman@slac.stanford.edu>, 2005,
+ * Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * This software was produced by
+ * the Stanford Linear Accelerator Center, Stanford University,
+ * under Contract DE-AC03-76SFO0515 with the Department of Energy.
+ *
+ * Government disclaimer of liability
+ * ----------------------------------
+ * Neither the United States nor the United States Department of Energy,
+ * nor any of their employees, makes any warranty, express or implied, or
+ * assumes any legal liability or responsibility for the accuracy,
+ * completeness, or usefulness of any data, apparatus, product, or process
+ * disclosed, or represents that its use would not infringe privately owned
+ * rights.
+ *
+ * Stanford disclaimer of liability
+ * --------------------------------
+ * Stanford University makes no representations or warranties, express or
+ * implied, nor assumes any liability for the use of this software.
+ *
+ * Stanford disclaimer of copyright
+ * --------------------------------
+ * Stanford University, owner of the copyright, hereby disclaims its
+ * copyright and all other rights in this software. Hence, anyone may
+ * freely use it for any purpose without restriction.
+ *
+ * Maintenance of notices
+ * ----------------------
+ * In the interest of clarity regarding the origin and status of this
+ * SLAC software, this and all the preceding Stanford University notices
+ * are to remain affixed to any copy or derivative of this software made
+ * or distributed by the recipient and are to be affixed to any copy of
+ * software made or distributed by the recipient that contains a copy or
+ * derivative of this software.
+ *
+ * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
+ */
+
+#include <rtems.h>
+
+#include <rtems/io.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @defgroup libi2c I2C Library
+ *
+ * @brief I2C library.
+ *
+ * @{
+ */
+
+/* Simple I2C driver API */
+
+/* Initialize the libary - may fail if no semaphore or no driver slot is available */
+extern int rtems_libi2c_initialize (void);
+
+/* Alternatively to rtems_libi2c_initialize() the library can also be
+ * initialized by means of a traditional driver table entry containing
+ * the following entry points:
+ */
+extern rtems_status_code
+rtems_i2c_init (
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg);
+
+extern rtems_status_code
+rtems_i2c_open (
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg);
+
+extern rtems_status_code
+rtems_i2c_close (
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg);
+
+extern rtems_status_code
+rtems_i2c_read (
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg);
+
+extern rtems_status_code
+rtems_i2c_write (
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg);
+
+extern rtems_status_code
+rtems_i2c_ioctl (
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg);
+
+extern const rtems_driver_address_table rtems_libi2c_io_ops;
+
+/* Unfortunately, if you want to add this driver to
+ * a RTEMS configuration table then you need all the
+ * members explicitly :-( (Device_driver_table should
+ * hold pointers to rtems_driver_address_tables rather
+ * than full structs).
+ *
+ * The difficulty is that adding this driver to the
+ * configuration table is not enough; you still need
+ * to populate the framework with low-level bus-driver(s)
+ * and high-level drivers and/or device-files...
+ *
+ * Currently the preferred way is having the BSP
+ * call 'rtems_libi2c_initialize' followed by
+ * 'rtems_libi2c_register_bus' and
+ * 'rtems_libi2c_register_drv' and/or
+ * 'mknod' (for 'raw' device nodes)
+ * from the 'pretasking_hook'.
+ */
+#define RTEMS_LIBI2C_DRIVER_TABLE_ENTRY \
+{ \
+ initialization_entry: rtems_i2c_init, \
+ open_entry: rtems_i2c_open, \
+ close_entry: rtems_i2c_close, \
+ read_entry: rtems_i2c_read, \
+ write_entry: rtems_i2c_write, \
+ control_entry: rtems_i2c_ioctl, \
+}
+
+/* Bus Driver API
+ *
+ * Bus drivers provide access to low-level i2c functions
+ * such as 'send start', 'send address', 'get bytes' etc.
+ */
+
+/* first field must be a pointer to ops; driver
+ * may add its own fields after this.
+ * the struct that is registered with the library
+ * is not copied; a pointer will we passed
+ * to the callback functions (ops).
+ */
+typedef struct rtems_libi2c_bus_t_
+{
+ const struct rtems_libi2c_bus_ops_ *ops;
+ int size; /* size of whole structure */
+} rtems_libi2c_bus_t;
+
+/* Access functions a low level driver must provide;
+ *
+ * All of these, except read_bytes and write_bytes
+ * return RTEMS_SUCCESSFUL on success and an error status
+ * otherwise. The read and write ops return the number
+ * of chars read/written or -(status code) on error.
+ */
+typedef struct rtems_libi2c_bus_ops_
+{
+ /* Initialize the bus; might be called again to reset the bus driver */
+ rtems_status_code (*init) (rtems_libi2c_bus_t * bushdl);
+ /* Send start condition */
+ rtems_status_code (*send_start) (rtems_libi2c_bus_t * bushdl);
+ /* Send stop condition */
+ rtems_status_code (*send_stop) (rtems_libi2c_bus_t * bushdl);
+ /* initiate transfer from (rw!=0) or to a device */
+ rtems_status_code (*send_addr) (rtems_libi2c_bus_t * bushdl,
+ uint32_t addr, int rw);
+ /* read a number of bytes */
+ int (*read_bytes) (rtems_libi2c_bus_t * bushdl, unsigned char *bytes,
+ int nbytes);
+ /* write a number of bytes */
+ int (*write_bytes) (rtems_libi2c_bus_t * bushdl, unsigned char *bytes,
+ int nbytes);
+ /* ioctl misc functions */
+ int (*ioctl) (rtems_libi2c_bus_t * bushdl,
+ int cmd,
+ void *buffer
+ );
+} rtems_libi2c_bus_ops_t;
+
+
+/*
+ * Register a lowlevel driver
+ *
+ * TODO: better description
+ *
+ * This allocates a major number identifying *this* driver
+ * (i.e., libi2c) and the minor number encodes a bus# and a i2c address.
+ *
+ * The name will be registered in the filesystem (parent
+ * directories must exist, also IMFS filesystem must exist see
+ * CONFIGURE_USE_IMFS_AS_BASE_FILESYSTEM). It may be NULL in which case
+ * the library will pick a default.
+ *
+ * RETURNS: bus # (>=0) or -1 on error (errno set).
+ */
+
+extern int rtems_libi2c_register_bus (const char *name, rtems_libi2c_bus_t * bus);
+
+extern rtems_device_major_number rtems_libi2c_major;
+
+#define RTEMS_LIBI2C_MAKE_MINOR(busno, i2caddr) \
+ ((((busno)&((1<<3)-1))<<10) | ((i2caddr)&((1<<10)-1)))
+
+/* After the library is initialized, a major number is available.
+ * As soon as a low-level bus driver is registered (above routine
+ * returns a 'busno'), a device node can be created in the filesystem
+ * with a major/minor number pair of
+ *
+ * rtems_libi2c_major / RTEMS_LIBI2C_MAKE_MINOR(busno, i2caddr)
+ *
+ * and a 'raw' hi-level driver is then attached to this device
+ * node.
+ * This 'raw' driver has very simple semantics:
+ *
+ * 'open' sends a start condition
+ * 'read'/'write' address the device identified by the i2c bus# and address
+ * encoded in the minor number and read or write, respectively
+ * a stream of bytes from or to the device. Every time the
+ * direction is changed, a 're-start' condition followed by
+ * an 'address' cycle is generated on the i2c bus.
+ * 'close' sends a stop condition.
+ *
+ * Hence, using the 'raw' driver, e.g., 100 bytes at offset 0x200 can be
+ * read from an EEPROM by the following pseudo-code:
+ *
+ * mknod("/dev/i2c-54", mode, MKDEV(rtems_libi2c_major, RTEMS_LIBI2C_MAKE_MINOR(0,0x54)))
+ *
+ * int fd;
+ * char off[2]={0x02,0x00};
+ *
+ * fd = open("/dev/i2c-54",O_RDWR);
+ * write(fd,off,2);
+ * read(fd,buf,100);
+ * close(fd);
+ *
+ */
+
+/* Higher Level Driver API
+ *
+ * Higher level drivers know how to deal with specific i2c
+ * devices (independent of the bus interface chip) and provide
+ * an abstraction, i.e., the usual read/write/ioctl access.
+ *
+ * Using the above example, such a high level driver could
+ * prevent the user from issuing potentially destructive write
+ * operations (the aforementioned EEPROM interprets any 3rd
+ * and following byte written to the device as data, i.e., the
+ * contents could easily be changed!).
+ * The correct 'read-pointer offset' programming could be
+ * implemented in 'open' and 'ioctl' of a high-level driver and
+ * the user would then only have to perform harmless read
+ * operations, e.g.,
+ *
+ * fd = open("/dev/i2c.eeprom",O_RDONLY) / * opens and sets EEPROM read pointer * /
+ * ioctl(fd, IOCTL_SEEK, 0x200) / * repositions the read pointer * /
+ * read(fd, buf, 100)
+ * close(fd)
+ *
+ */
+
+/* struct provided at driver registration. The driver may store
+ * private data behind the mandatory first fields but the size
+ * must be set to the size of the entire struct, e.g.,
+ *
+ * struct driver_pvt {
+ * rtems_libi2c_drv_t pub;
+ * struct { ... } pvt;
+ * } my_driver = {
+ * { ops: my_ops,
+ * size: sizeof(my_driver)
+ * },
+ * { ...};
+ * };
+ *
+ * A pointer to this struct is passed to the callback ops.
+ */
+
+typedef struct rtems_libi2c_drv_t_
+{
+ const rtems_driver_address_table *ops; /* the driver ops */
+ int size; /* size of whole structure (including appended private data) */
+} rtems_libi2c_drv_t;
+
+/*
+ * The high level driver must be registered with a particular
+ * bus number and i2c address.
+ *
+ * The registration procedure also creates a filesystem node,
+ * i.e., the returned minor number is not really needed.
+ *
+ * If the 'name' argument is NULL, no filesystem node is
+ * created (but this can be done 'manually' using rtems_libi2c_major
+ * and the return value of this routine).
+ *
+ * RETURNS minor number (FYI) or -1 on failure
+ */
+extern int
+rtems_libi2c_register_drv (const char *name, rtems_libi2c_drv_t * drvtbl,
+ unsigned bus, unsigned i2caddr);
+
+/* Operations available to high level drivers */
+
+/* NOTES: The bus a device is attached to is LOCKED from the first send_start
+ * until send_stop is executed!
+ *
+ * Bus tenure MUST NOT span multiple system calls - otherwise, a single
+ * thread could get into the protected sections (or would deadlock if the
+ * mutex was not nestable).
+ * E.g., consider what happens if 'open' sends a 'start' and 'close'
+ * sends a 'stop' (i.e., the bus mutex would be locked in 'open' and
+ * released in 'close'. A single thread could try to open two devices
+ * on the same bus and would either deadlock or nest into the bus mutex
+ * and potentially mess up the i2c messages.
+ *
+ * The correct way is to *always* relinquish the i2c bus (i.e., send 'stop'
+ * from any driver routine prior to returning control to the caller.
+ * Consult the implementation of the generic driver routines (open, close, ...)
+ * below or the examples in i2c-2b-eeprom.c and i2c-2b-ds1621.c
+ *
+ * Drivers just pass the minor number on to these routines...
+ */
+extern rtems_status_code rtems_libi2c_send_start (rtems_device_minor_number minor);
+
+extern rtems_status_code rtems_libi2c_send_stop (rtems_device_minor_number minor);
+
+extern rtems_status_code
+rtems_libi2c_send_addr (rtems_device_minor_number minor, int rw);
+
+/* the read/write routines return the number of bytes transferred
+ * or -(status_code) on error.
+ */
+extern int
+rtems_libi2c_read_bytes (rtems_device_minor_number minor,
+ unsigned char *bytes, int nbytes);
+
+extern int
+rtems_libi2c_write_bytes (rtems_device_minor_number minor,
+ const unsigned char *bytes, int nbytes);
+
+/* Send start, send address and read bytes */
+extern int
+rtems_libi2c_start_read_bytes (rtems_device_minor_number minor,
+ unsigned char *bytes,
+ int nbytes);
+
+/* Send start, send address and write bytes */
+extern int
+rtems_libi2c_start_write_bytes (rtems_device_minor_number minor,
+ const unsigned char *bytes,
+ int nbytes);
+
+
+/* call misc iocontrol function */
+extern int
+rtems_libi2c_ioctl (rtems_device_minor_number minor,
+ int cmd,
+ ...);
+/*
+ * NOTE: any low-level driver ioctl returning a negative
+ * result for release the bus (perform a STOP condition)
+ */
+/*******************************
+ * defined IOCTLs:
+ *******************************/
+#define RTEMS_LIBI2C_IOCTL_READ_WRITE 1
+/*
+ * retval = rtems_libi2c_ioctl(rtems_device_minor_number minor,
+ * RTEMS_LIBI2C_IOCTL_READ_WRITE,
+ * rtems_libi2c_read_write_t *arg);
+ *
+ * This call performs a simultanous read/write transfer,
+ * which is possible (and sometimes needed) for SPI devices
+ *
+ * arg is a pointer to a rd_wr info data structure
+ *
+ * This call is only needed for SPI devices
+ */
+#define RTEMS_LIBI2C_IOCTL_START_TFM_READ_WRITE 2
+/*
+ * retval = rtems_libi2c_ioctl(rtems_device_minor_number minor,
+ * RTEMS_LIBI2C_IOCTL_START_READ_WRITE,
+ * unsigned char *rd_buffer,
+ * const unsigned char *wr_buffer,
+ * int byte_cnt,
+ * const rtems_libi2c_tfr_mode_t *tfr_mode_ptr);
+ *
+ * This call addresses a slave and then:
+ * - sets the proper transfer mode,
+ * - performs a simultanous read/write transfer,
+ * (which is possible and sometimes needed for SPI devices)
+ * NOTE: - if rd_buffer is NULL, receive data will be dropped
+ * - if wr_buffer is NULL, bytes with content 0 will transmitted
+ *
+ * rd_buffer is a pointer to a receive buffer (or NULL)
+ * wr_buffer is a pointer to the data to be sent (or NULL)
+ *
+ * This call is only needed for SPI devices
+ */
+
+#define RTEMS_LIBI2C_IOCTL_SET_TFRMODE 3
+/*
+ * retval = rtems_libi2c_ioctl(rtems_device_minor_number minor,
+ * RTEMS_LIBI2C_IOCTL_SET_TFRMODE,
+ * const rtems_libi2c_tfr_mode_t *tfr_mode_ptr);
+ *
+ * This call sets an SPI device to the transfer mode needed (baudrate etc.)
+ *
+ * tfr_mode is a pointer to a structure defining the SPI transfer mode needed
+ * (see below).
+ *
+ * This call is only needed for SPI devices
+ */
+
+#define RTEMS_LIBI2C_IOCTL_GET_DRV_T 4
+
+/*
+ * retval = rtems_libi2c_ioctl(rtems_device_minor_number minor,
+ * RTEMS_LIBI2C_IOCTL_GET_DRV_T,
+ * const rtems_libi2c_drv_t *drv_t_ptr);
+ *
+ * This call allows the a high-level driver to query its driver table entry,
+ * including its private data appended to it during creation of the entry
+ *
+ */
+
+/**
+ * @brief IO control command for asynchronous read and write.
+ *
+ * @see rtems_libi2c_read_write_done_t and rtems_libi2c_read_write_async_t.
+ *
+ * @warning This is work in progress!
+ */
+#define RTEMS_LIBI2C_IOCTL_READ_WRITE_ASYNC 5
+
+/*
+ * argument data structures for IOCTLs defined above
+ */
+typedef struct {
+ unsigned char *rd_buf;
+ const unsigned char *wr_buf;
+ int byte_cnt;
+} rtems_libi2c_read_write_t;
+
+typedef struct {
+ uint32_t baudrate; /* maximum bits per second */
+ /* only valid for SPI drivers: */
+ uint8_t bits_per_char; /* how many bits per byte/word/longword? */
+ bool lsb_first; /* true: send LSB first */
+ bool clock_inv; /* true: inverted clock (high active) */
+ bool clock_phs; /* true: clock starts toggling at start of data tfr */
+ uint32_t idle_char; /* This character will be continuously transmitted in read only functions */
+} rtems_libi2c_tfr_mode_t;
+
+typedef struct {
+ rtems_libi2c_tfr_mode_t tfr_mode;
+ rtems_libi2c_read_write_t rd_wr;
+} rtems_libi2c_tfm_read_write_t;
+
+/**
+ * @brief Notification function type for asynchronous read and write.
+ *
+ * @see RTEMS_LIBI2C_IOCTL_READ_WRITE_ASYNC and
+ * rtems_libi2c_read_write_async_t.
+ *
+ * @warning This is work in progress!
+ */
+typedef void (*rtems_libi2c_read_write_done_t) \
+ ( int /* return value */, int /* nbytes */, void * /* arg */);
+
+/**
+ * @brief IO command data for asynchronous read and write.
+ *
+ * @see RTEMS_LIBI2C_IOCTL_READ_WRITE_ASYNC and
+ * rtems_libi2c_read_write_done_t.
+ *
+ * @warning This is work in progress!
+ */
+typedef struct {
+ unsigned char *rd_buf;
+ const unsigned char *wr_buf;
+ int byte_cnt;
+ rtems_libi2c_read_write_done_t done;
+ void *arg;
+} rtems_libi2c_read_write_async_t;
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif