summaryrefslogtreecommitdiffstats
path: root/bsps/arm/lpc24xx
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2018-04-23 09:45:28 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2018-04-23 15:18:43 +0200
commita2dad96ab736f66ed54421cad53caf31f250e181 (patch)
tree1935320b5b52276ed2e52741cdae71637f209f77 /bsps/arm/lpc24xx
parentbsps/arm: Remove unused stm32f* files (diff)
downloadrtems-a2dad96ab736f66ed54421cad53caf31f250e181.tar.bz2
bsps: Move I2C drivers to bsps
This patch is a part of the BSP source reorganization. Update #3285.
Diffstat (limited to 'bsps/arm/lpc24xx')
-rw-r--r--bsps/arm/lpc24xx/i2c/i2c-config.c91
-rw-r--r--bsps/arm/lpc24xx/i2c/i2c.c324
2 files changed, 415 insertions, 0 deletions
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
+ * <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.org/license/LICENSE.
+ */
+
+#include <bspopts.h>
+#include <bsp/i2c.h>
+#include <bsp/irq.h>
+
+#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
+ * <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.org/license/LICENSE.
+ */
+
+#include <bsp.h>
+#include <bsp/i2c.h>
+#include <bsp/irq.h>
+#include <bsp/irq-generic.h>
+#include <bsp/system-clocks.h>
+
+#define RTEMS_STATUS_CHECKS_USE_PRINTK
+
+#include <rtems/status-checks.h>
+
+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
+};