From a2dad96ab736f66ed54421cad53caf31f250e181 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Mon, 23 Apr 2018 09:45:28 +0200 Subject: bsps: Move I2C drivers to bsps This patch is a part of the BSP source reorganization. Update #3285. --- bsps/arm/lpc24xx/i2c/i2c-config.c | 91 +++++++++++ bsps/arm/lpc24xx/i2c/i2c.c | 324 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 415 insertions(+) create mode 100644 bsps/arm/lpc24xx/i2c/i2c-config.c create mode 100644 bsps/arm/lpc24xx/i2c/i2c.c (limited to 'bsps/arm/lpc24xx') diff --git a/bsps/arm/lpc24xx/i2c/i2c-config.c b/bsps/arm/lpc24xx/i2c/i2c-config.c new file mode 100644 index 0000000000..5ba16ae874 --- /dev/null +++ b/bsps/arm/lpc24xx/i2c/i2c-config.c @@ -0,0 +1,91 @@ +/** + * @file + * + * @ingroup lpc24xx_libi2c + * + * @brief LibI2C bus driver for the I2C modules. + */ + +/* + * Copyright (c) 2009-2011 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 82178 Puchheim + * Germany + * + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include +#include +#include + +#ifdef LPC24XX_CONFIG_I2C_0 + static const lpc24xx_pin_range lpc24xx_i2c_pins_0 [] = { + LPC24XX_PIN_I2C_0_SDA, + LPC24XX_PIN_I2C_0_SCL, + LPC24XX_PIN_TERMINAL + }; + + 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, + .pins = &lpc24xx_i2c_pins_0 [0], + .vector = LPC24XX_IRQ_I2C_0 + }; + + rtems_libi2c_bus_t * const lpc24xx_i2c_0 = + &lpc24xx_i2c_entry_0.bus; +#endif + +#ifdef LPC24XX_CONFIG_I2C_1 + static const lpc24xx_pin_range lpc24xx_i2c_pins_1 [] = { + LPC24XX_PIN_I2C_1_SDA_P0_19, + LPC24XX_PIN_I2C_1_SCL_P0_20, + LPC24XX_PIN_TERMINAL + }; + + 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, + .pins = &lpc24xx_i2c_pins_1 [0], + .vector = LPC24XX_IRQ_I2C_1 + }; + + rtems_libi2c_bus_t * const lpc24xx_i2c_1 = + &lpc24xx_i2c_entry_1.bus; +#endif + +#ifdef LPC24XX_CONFIG_I2C_2 + static const lpc24xx_pin_range lpc24xx_i2c_pins_2 [] = { + LPC24XX_PIN_I2C_2_SDA_P0_10, + LPC24XX_PIN_I2C_2_SCL_P0_11, + LPC24XX_PIN_TERMINAL + }; + + 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, + .pins = &lpc24xx_i2c_pins_2 [0], + .vector = LPC24XX_IRQ_I2C_2 + }; + + rtems_libi2c_bus_t * const lpc24xx_i2c_2 = + &lpc24xx_i2c_entry_2.bus; +#endif diff --git a/bsps/arm/lpc24xx/i2c/i2c.c b/bsps/arm/lpc24xx/i2c/i2c.c new file mode 100644 index 0000000000..ef638e69b9 --- /dev/null +++ b/bsps/arm/lpc24xx/i2c/i2c.c @@ -0,0 +1,324 @@ +/** + * @file + * + * @ingroup lpc24xx_libi2c + * + * @brief LibI2C bus driver for the I2C modules. + */ + +/* + * Copyright (c) 2009-2011 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 82178 Puchheim + * Germany + * + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include +#include +#include +#include +#include + +#define RTEMS_STATUS_CHECKS_USE_PRINTK + +#include + +static void lpc24xx_i2c_handler(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_0 + e->index, LPC24XX_MODULE_CCLK_8); + RTEMS_CHECK_SC(sc, "enable module"); + + /* Pin configuration */ + sc = lpc24xx_pin_config(e->pins, LPC24XX_PIN_SET_FUNCTION); + RTEMS_CHECK_SC(sc, "pin 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; +} + +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 +}; -- cgit v1.2.3