diff options
author | Thomas Doerfler <Thomas.Doerfler@embedded-brains.de> | 2009-07-20 07:24:06 +0000 |
---|---|---|
committer | Thomas Doerfler <Thomas.Doerfler@embedded-brains.de> | 2009-07-20 07:24:06 +0000 |
commit | 72ea4cc86f6e728792392e67809594006ed10c50 (patch) | |
tree | 5348a134ce68786ff0c5016b50754770f902d0c5 /c/src/lib/libbsp/arm/lpc24xx/i2c/i2c.c | |
parent | 2009-07-19 Joel Sherrill <joel.sherrill@oarcorp.com> (diff) | |
download | rtems-72ea4cc86f6e728792392e67809594006ed10c50.tar.bz2 |
add missing i2c.c file
Diffstat (limited to '')
-rw-r--r-- | c/src/lib/libbsp/arm/lpc24xx/i2c/i2c.c | 386 |
1 files changed, 386 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/arm/lpc24xx/i2c/i2c.c b/c/src/lib/libbsp/arm/lpc24xx/i2c/i2c.c new file mode 100644 index 0000000000..2827732918 --- /dev/null +++ b/c/src/lib/libbsp/arm/lpc24xx/i2c/i2c.c @@ -0,0 +1,386 @@ +/** + * @file + * + * @ingroup lpc24xx + * + * LibI2C bus driver for the I2C modules. + */ + +/* + * Copyright (c) 2009 + * embedded brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#include <rtems.h> + +#include <bsp.h> +#include <bsp/i2c.h> +#include <bsp/io.h> +#include <bsp/irq.h> +#include <bsp/irq-generic.h> +#include <bsp/lpc24xx.h> +#include <bsp/system-clocks.h> + +#define RTEMS_STATUS_CHECKS_USE_PRINTK + +#include <rtems/status-checks.h> + +typedef struct { + rtems_libi2c_bus_t bus; + volatile lpc24xx_i2c *regs; + unsigned index; + unsigned config; + rtems_vector_number vector; + rtems_id state_update; + uint8_t * volatile data; + uint8_t * volatile end; +} lpc24xx_i2c_bus_entry; + +static void lpc24xx_i2c_handler( rtems_vector_number vector, void *arg) +{ + lpc24xx_i2c_bus_entry *e = arg; + volatile lpc24xx_i2c *regs = e->regs; + unsigned state = regs->stat; + uint8_t *data = e->data; + uint8_t *end = e->end; + bool notify = true; + + switch (state) { + case 0x28U: + /* Data has been transmitted successfully */ + if (data != end) { + regs->dat = *data; + ++data; + regs->conset = LPC24XX_I2C_AA; + regs->conclr = LPC24XX_I2C_SI; + notify = false; + e->data = data; + } + break; + case 0x50U: + /* Data has been received */ + if (data != end) { + *data = (uint8_t) regs->dat; + ++data; + if (data != end) { + if (data + 1 != end) { + regs->conset = LPC24XX_I2C_AA; + } else { + regs->conclr = LPC24XX_I2C_AA; + } + regs->conclr = LPC24XX_I2C_SI; + notify = false; + e->data = data; + } else { + /* This is an error and should never happen */ + } + } + break; + case 0x58U: + /* Last data has been received */ + if (data != end) { + *data = (uint8_t) regs->dat; + } + break; + default: + /* Do nothing */ + break; + } + + /* Notify task if necessary */ + if (notify) { + bsp_interrupt_vector_disable( e->vector); + + rtems_semaphore_release( e->state_update); + } +} + +static rtems_status_code lpc24xx_i2c_wait( lpc24xx_i2c_bus_entry *e) +{ + bsp_interrupt_vector_enable( e->vector); + + return rtems_semaphore_obtain( e->state_update, RTEMS_WAIT, RTEMS_NO_TIMEOUT); +} + +static rtems_status_code lpc24xx_i2c_init( rtems_libi2c_bus_t *bus) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + lpc24xx_i2c_bus_entry *e = (lpc24xx_i2c_bus_entry *) bus; + volatile lpc24xx_i2c *regs = e->regs; + unsigned cycles = LPC24XX_CCLK / (8U * 100000U * 2U); + + /* Create semaphore */ + sc = rtems_semaphore_create ( + rtems_build_name ( 'I', '2', 'C', '0' + e->index), + 0, + RTEMS_SIMPLE_BINARY_SEMAPHORE, + 0, + &e->state_update + ); + RTEMS_CHECK_SC( sc, "create status update semaphore"); + + /* Enable module power */ + sc = lpc24xx_module_enable( LPC24XX_MODULE_I2C, e->index, LPC24XX_MODULE_CCLK_8); + RTEMS_CHECK_SC( sc, "enable module"); + + /* IO configuration */ + sc = lpc24xx_io_config( LPC24XX_MODULE_I2C, e->index, e->config); + RTEMS_CHECK_SC( sc, "IO configuration"); + + /* Clock high and low duty cycles */ + regs->sclh = cycles; + regs->scll = cycles; + + /* Disable module */ + regs->conclr = LPC24XX_I2C_EN; + + /* Install interrupt handler and disable this vector */ + sc = rtems_interrupt_handler_install( + e->vector, + "I2C", + RTEMS_INTERRUPT_UNIQUE, + lpc24xx_i2c_handler, + e + ); + RTEMS_CHECK_SC( sc, "install interrupt handler"); + bsp_interrupt_vector_disable( e->vector); + + /* Enable module in master mode */ + regs->conset = LPC24XX_I2C_EN; + + /* Set self address */ + regs->adr = 0; + + return RTEMS_SUCCESSFUL; +} + +static rtems_status_code lpc24xx_i2c_send_start( rtems_libi2c_bus_t *bus) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + lpc24xx_i2c_bus_entry *e = (lpc24xx_i2c_bus_entry *) bus; + volatile lpc24xx_i2c *regs = e->regs; + + /* Start */ + regs->conclr = LPC24XX_I2C_STA | LPC24XX_I2C_AA | LPC24XX_I2C_SI; + regs->conset = LPC24XX_I2C_STA; + + /* Wait */ + sc = lpc24xx_i2c_wait( e); + RTEMS_CHECK_SC( sc, "wait for state update"); + + return RTEMS_SUCCESSFUL; +} + +static rtems_status_code lpc24xx_i2c_send_stop( rtems_libi2c_bus_t *bus) +{ + lpc24xx_i2c_bus_entry *e = (lpc24xx_i2c_bus_entry *) bus; + volatile lpc24xx_i2c *regs = e->regs; + + /* Stop */ + regs->conset = LPC24XX_I2C_STO | LPC24XX_I2C_AA; + regs->conclr = LPC24XX_I2C_STA | LPC24XX_I2C_SI; + + return RTEMS_SUCCESSFUL; +} + +static rtems_status_code lpc24xx_i2c_send_addr( + rtems_libi2c_bus_t *bus, + uint32_t addr, + int rw +) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + lpc24xx_i2c_bus_entry *e = (lpc24xx_i2c_bus_entry *) bus; + volatile lpc24xx_i2c *regs = e->regs; + unsigned state = regs->stat; + + /* Check state */ + if (state != 0x8U && state != 0x10U) { + return -RTEMS_IO_ERROR; + } + + /* Send address */ + regs->dat = (uint8_t) ((addr << 1U) | ((rw != 0) ? 1U : 0U)); + regs->conset = LPC24XX_I2C_AA; + regs->conclr = LPC24XX_I2C_STA | LPC24XX_I2C_SI; + + /* Wait */ + sc = lpc24xx_i2c_wait( e); + RTEMS_CHECK_SC_RV( sc, "wait for state update"); + + /* Check state */ + state = regs->stat; + if (state != 0x18U && state != 0x40U) { + return -RTEMS_IO_ERROR; + } + + return RTEMS_SUCCESSFUL; +} + +static int lpc24xx_i2c_read( rtems_libi2c_bus_t *bus, unsigned char *in, int n) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + lpc24xx_i2c_bus_entry *e = (lpc24xx_i2c_bus_entry *) bus; + volatile lpc24xx_i2c *regs = e->regs; + unsigned state = regs->stat; + uint8_t *data = in; + uint8_t *end = in + n; + + if (n <= 0) { + return n; + } else if (state != 0x40U) { + return -RTEMS_IO_ERROR; + } + + /* Setup receive buffer */ + e->data = data; + e->end = end; + + /* Ready to receive data */ + if (data + 1 != end) { + regs->conset = LPC24XX_I2C_AA; + } else { + regs->conclr = LPC24XX_I2C_AA; + } + regs->conclr = LPC24XX_I2C_SI; + + /* Wait */ + sc = lpc24xx_i2c_wait( e); + RTEMS_CHECK_SC_RV( sc, "wait for state update"); + + /* Check state */ + state = regs->stat; + if (state != 0x58U) { + return -RTEMS_IO_ERROR; + } + + return n; +} + +static int lpc24xx_i2c_write( + rtems_libi2c_bus_t *bus, + unsigned char *out, + int n +) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + lpc24xx_i2c_bus_entry *e = (lpc24xx_i2c_bus_entry *) bus; + volatile lpc24xx_i2c *regs = e->regs; + unsigned state = 0; + + if (n <= 0) { + return n; + } + + /* Setup transmit buffer */ + e->data = out + 1; + e->end = out + n; + + /* Transmit first byte */ + regs->dat = *out; + regs->conset = LPC24XX_I2C_AA; + regs->conclr = LPC24XX_I2C_SI; + + /* Wait */ + sc = lpc24xx_i2c_wait( e); + RTEMS_CHECK_SC_RV( sc, "wait for state update"); + + /* Check state */ + state = regs->stat; + if (state != 0x28U) { + return -RTEMS_IO_ERROR; + } + + return n; +} + +static int lpc24xx_i2c_set_transfer_mode( + rtems_libi2c_bus_t *bus, + const rtems_libi2c_tfr_mode_t *mode +) +{ + return -RTEMS_NOT_IMPLEMENTED; +} + +static int lpc24xx_i2c_ioctl( rtems_libi2c_bus_t *bus, int cmd, void *arg) +{ + int rv = -1; + const rtems_libi2c_tfr_mode_t *tm = (const rtems_libi2c_tfr_mode_t *) arg; + + switch (cmd) { + case RTEMS_LIBI2C_IOCTL_SET_TFRMODE: + rv = lpc24xx_i2c_set_transfer_mode( bus, tm); + break; + default: + rv = -RTEMS_NOT_DEFINED; + break; + } + + return rv; +} + +static const rtems_libi2c_bus_ops_t lpc24xx_i2c_ops = { + .init = lpc24xx_i2c_init, + .send_start = lpc24xx_i2c_send_start, + .send_stop = lpc24xx_i2c_send_stop, + .send_addr = lpc24xx_i2c_send_addr, + .read_bytes = lpc24xx_i2c_read, + .write_bytes = lpc24xx_i2c_write, + .ioctl = lpc24xx_i2c_ioctl +}; + +#ifdef LPC24XX_CONFIG_I2C_0 + static lpc24xx_i2c_bus_entry lpc24xx_i2c_entry_0 = { + .bus = { + .ops = &lpc24xx_i2c_ops, + .size = sizeof( lpc24xx_i2c_bus_entry) + }, + .regs = (volatile lpc24xx_i2c *) I2C0_BASE_ADDR, + .index = 0, + .config = LPC24XX_CONFIG_I2C_0, + .vector = LPC24XX_IRQ_I2C_0 + }; + + rtems_libi2c_bus_t * const lpc24xx_i2c_0 = + (rtems_libi2c_bus_t *) &lpc24xx_i2c_entry_0; +#endif + +#ifdef LPC24XX_CONFIG_I2C_1 + static lpc24xx_i2c_bus_entry lpc24xx_i2c_entry_1 = { + .bus = { + .ops = &lpc24xx_i2c_ops, + .size = sizeof( lpc24xx_i2c_bus_entry) + }, + .regs = (volatile lpc24xx_i2c *) I2C1_BASE_ADDR, + .index = 1, + .config = LPC24XX_CONFIG_I2C_1, + .vector = LPC24XX_IRQ_I2C_1 + }; + + rtems_libi2c_bus_t * const lpc24xx_i2c_1 = + (rtems_libi2c_bus_t *) &lpc24xx_i2c_entry_1; +#endif + +#ifdef LPC24XX_CONFIG_I2C_2 + static lpc24xx_i2c_bus_entry lpc24xx_i2c_entry_2 = { + .bus = { + .ops = &lpc24xx_i2c_ops, + .size = sizeof( lpc24xx_i2c_bus_entry) + }, + .regs = (volatile lpc24xx_i2c *) I2C2_BASE_ADDR, + .index = 2, + .config = LPC24XX_CONFIG_I2C_2, + .vector = LPC24XX_IRQ_I2C_2 + }; + + rtems_libi2c_bus_t * const lpc24xx_i2c_2 = + (rtems_libi2c_bus_t *) &lpc24xx_i2c_entry_2; +#endif |