summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2019-02-25 07:07:19 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2019-03-15 16:02:22 +0100
commit007d4e12977ca76d981368bd5e0303115f657946 (patch)
tree048c9f9c908d885a12c96bebc4a604a093b4dd7e
parent9e4895805af7023c23ba0cedf8f48934e3be5acc (diff)
downloadrtems-007d4e12977ca76d981368bd5e0303115f657946.tar.bz2
bsp/lpc24xx: Convert I2C driver to Linux API
Change license to BSD-2-Clause. Close #3725.
-rw-r--r--bsps/arm/lpc24xx/i2c/i2c-config.c91
-rw-r--r--bsps/arm/lpc24xx/i2c/i2c.c642
-rw-r--r--bsps/arm/lpc24xx/include/bsp/i2c.h66
-rw-r--r--c/src/lib/libbsp/arm/lpc24xx/Makefile.am1
4 files changed, 435 insertions, 365 deletions
diff --git a/bsps/arm/lpc24xx/i2c/i2c-config.c b/bsps/arm/lpc24xx/i2c/i2c-config.c
deleted file mode 100644
index c1251a1c3e..0000000000
--- a/bsps/arm/lpc24xx/i2c/i2c-config.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/**
- * @file
- *
- * @ingroup RTEMSBSPsARMLPC24XX_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
index 5a6303b106..98fe0832d5 100644
--- a/bsps/arm/lpc24xx/i2c/i2c.c
+++ b/bsps/arm/lpc24xx/i2c/i2c.c
@@ -1,324 +1,490 @@
/**
* @file
*
- * @ingroup RTEMSBSPsARMLPC24XX_libi2c
- *
- * @brief LibI2C bus driver for the I2C modules.
+ * @ingroup RTEMSBSPsARMLPC24XXI2C
*/
/*
- * Copyright (c) 2009-2011 embedded brains GmbH. All rights reserved.
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (C) 2009, 2019 embedded brains GmbH
*
- * embedded brains GmbH
- * Obere Lagerstr. 30
- * 82178 Puchheim
- * Germany
- * <rtems@embedded-brains.de>
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
*
- * 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.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
*/
-#include <bsp.h>
#include <bsp/i2c.h>
+#include <bsp.h>
+#include <bsp/io.h>
#include <bsp/irq.h>
#include <bsp/irq-generic.h>
-#include <bsp/system-clocks.h>
-#define RTEMS_STATUS_CHECKS_USE_PRINTK
+#include <rtems/score/assert.h>
+
+#include <dev/i2c/i2c.h>
+
+RTEMS_STATIC_ASSERT(I2C_M_RD == 1, lpc24xx_i2c_read_flag);
+
+typedef struct {
+ i2c_bus base;
+ volatile lpc24xx_i2c *regs;
+ uint8_t *buf;
+ const uint8_t *buf_end;
+ size_t todo;
+ const i2c_msg *msg;
+ const i2c_msg *msg_end;
+ int error;
+ rtems_binary_semaphore sem;
+ lpc24xx_module module;
+ rtems_vector_number irq;
+} lpc24xx_i2c_bus;
+
+typedef struct {
+ volatile lpc24xx_i2c *regs;
+ lpc24xx_module module;
+ rtems_vector_number irq;
+} lpc24xx_i2c_config;
+
+static const i2c_msg *lpc24xx_i2c_msg_inc(lpc24xx_i2c_bus *bus)
+{
+ const i2c_msg *msg;
+
+ msg = bus->msg + 1;
+ bus->msg = msg;
+ return msg;
+}
+
+static void lpc24xx_i2c_msg_inc_and_set_buf(lpc24xx_i2c_bus *bus)
+{
+ const i2c_msg *msg;
+
+ msg = lpc24xx_i2c_msg_inc(bus);
+ bus->buf = msg->buf;
+ bus->buf_end = bus->buf + msg->len;
+}
+
+static void lpc24xx_i2c_buf_inc(lpc24xx_i2c_bus *bus)
+{
+ ++bus->buf;
+ --bus->todo;
+}
+
+static void lpc24xx_i2c_buf_push(lpc24xx_i2c_bus *bus, uint8_t c)
+{
+ while (true) {
+ if (bus->buf != bus->buf_end) {
+ bus->buf[0] = c;
+ lpc24xx_i2c_buf_inc(bus);
+ break;
+ }
+
+ lpc24xx_i2c_msg_inc_and_set_buf(bus);
+ }
+}
+
+static uint8_t lpc24xx_i2c_buf_pop(lpc24xx_i2c_bus *bus)
+{
+ while (true) {
+ if (bus->buf != bus->buf_end) {
+ uint8_t c;
+
+ c = bus->buf[0];
+ lpc24xx_i2c_buf_inc(bus);
+ return c;
+ }
+
+ lpc24xx_i2c_msg_inc_and_set_buf(bus);
+ }
+}
+
+static void lpc24xx_i2c_setup_msg(lpc24xx_i2c_bus *bus, const i2c_msg *msg)
+{
+ int can_continue;
+ size_t todo;
+
+ bus->msg = msg;
+ bus->buf = msg->buf;
+ todo = msg->len;
+ bus->buf_end = bus->buf + todo;
+
+ can_continue = (msg->flags & I2C_M_RD) | I2C_M_NOSTART;
+ ++msg;
+
+ while (msg != bus->msg_end) {
+ if ((msg->flags & (I2C_M_RD | I2C_M_NOSTART)) != can_continue) {
+ break;
+ }
+
+ todo += msg->len;
+ ++msg;
+ }
-#include <rtems/status-checks.h>
+ bus->todo = todo;
+}
-static void lpc24xx_i2c_handler(void *arg)
+static int lpc24xx_i2c_next_msg(
+ lpc24xx_i2c_bus *bus,
+ volatile lpc24xx_i2c *regs
+)
{
- 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;
+ const i2c_msg *msg;
+ int error;
+
+ msg = bus->msg + 1;
+ error = 1;
+
+ if (msg != bus->msg_end) {
+ lpc24xx_i2c_setup_msg(bus, msg);
+
+ if ((msg->flags & I2C_M_NOSTART) == 0) {
+ regs->conset = LPC24XX_I2C_STA;
+ regs->conclr = LPC24XX_I2C_SI;
+ } else {
+ regs->conset = LPC24XX_I2C_STO;
+ regs->conclr = LPC24XX_I2C_SI;
+ error = -EINVAL;
+ }
+ } else {
+ regs->conset = LPC24XX_I2C_STO;
+ regs->conclr = LPC24XX_I2C_SI;
+ error = 0;
+ }
+
+ return error;
+}
+
+static void lpc24xx_i2c_interrupt(void *arg)
+{
+ lpc24xx_i2c_bus *bus;
+ volatile lpc24xx_i2c *regs;
+ const i2c_msg *msg;
+ int error;
+
+ bus = arg;
+ regs = bus->regs;
+ error = 1;
+
+ switch (regs->stat) {
+ case 0x00:
+ /* Bus error */
+ case 0x20:
+ /* Slave address plus write sent, NACK received */
+ case 0x48:
+ /* Slave address plus read sent, NACK received */
+ regs->conset = LPC24XX_I2C_STO | LPC24XX_I2C_AA;
+ regs->conclr = LPC24XX_I2C_SI;
+ error = -EIO;
+ break;
+ case 0x08:
+ /* Start sent */
+ case 0x10:
+ /* Repeated start sent */
+ msg = bus->msg;
+ regs->dat = (uint8_t) ((msg->addr << 1) | (msg->flags & I2C_M_RD));
+ regs->conset = LPC24XX_I2C_AA;
+ regs->conclr = LPC24XX_I2C_STA | LPC24XX_I2C_SI;
+ break;
+ case 0x18:
+ /* Slave address plus write sent, ACK received */
+ case 0x28:
+ /* Data sent, ACK received */
+ if (bus->todo > 0) {
+ regs->dat = lpc24xx_i2c_buf_pop(bus);
regs->conset = LPC24XX_I2C_AA;
regs->conclr = LPC24XX_I2C_SI;
- notify = false;
- e->data = data;
+ } else {
+ error = lpc24xx_i2c_next_msg(bus, regs);
}
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 */
- }
+ case 0x30:
+ /* Data sent, NACK received */
+ if (bus->todo == 0) {
+ error = lpc24xx_i2c_next_msg(bus, regs);
+ } else {
+ regs->conset = LPC24XX_I2C_STO;
+ regs->conclr = LPC24XX_I2C_SI;
+ error = -EIO;
}
break;
- case 0x58U:
- /* Last data has been received */
- if (data != end) {
- *data = (uint8_t) regs->dat;
+ case 0x40:
+ /* Slave address plus read sent, ACK received */
+ if (bus->todo > 1) {
+ regs->conset = LPC24XX_I2C_AA;
+ regs->conclr = LPC24XX_I2C_SI;
+ } else {
+ regs->conclr = LPC24XX_I2C_SI | LPC24XX_I2C_AA;
}
break;
- default:
+ case 0x50:
+ /* Data received, ACK returned */
+ case 0x58:
+ /* Data received, NACK returned */
+ lpc24xx_i2c_buf_push(bus, regs->dat);
+
+ if (bus->todo > 1) {
+ regs->conset = LPC24XX_I2C_AA;
+ regs->conclr = LPC24XX_I2C_SI;
+ } else if (bus->todo == 1) {
+ regs->conclr = LPC24XX_I2C_SI | LPC24XX_I2C_AA;
+ } else {
+ error = lpc24xx_i2c_next_msg(bus, regs);
+ }
+ break;
+ case 0xF8:
/* Do nothing */
break;
+ default:
+ error = -EIO;
+ break;
}
- /* Notify task if necessary */
- if (notify) {
- bsp_interrupt_vector_disable(e->vector);
-
- rtems_semaphore_release(e->state_update);
+ if (error <= 0) {
+ bus->error = error;
+ bsp_interrupt_vector_disable(bus->irq);
+ rtems_binary_semaphore_post(&bus->sem);
}
}
-static rtems_status_code lpc24xx_i2c_wait(lpc24xx_i2c_bus_entry *e)
+static int
+lpc24xx_i2c_transfer(i2c_bus *base, i2c_msg *msgs, uint32_t msg_count)
{
- bsp_interrupt_vector_enable(e->vector);
+ lpc24xx_i2c_bus *bus;
+ volatile lpc24xx_i2c *regs;
+ uint16_t supported;
+ uint32_t i;
+ int eno;
+
+ if (msg_count == 0){
+ return 0;
+ }
- return rtems_semaphore_obtain(e->state_update, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
-}
+ supported = I2C_M_RD;
-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");
+ for (i = 0; i < msg_count; ++i) {
+ if ((msgs[i].flags & ~supported) != 0) {
+ return -EINVAL;
+ }
- /* Enable module power */
- sc = lpc24xx_module_enable(LPC24XX_MODULE_I2C_0 + e->index, LPC24XX_MODULE_CCLK_8);
- RTEMS_CHECK_SC(sc, "enable module");
+ supported |= I2C_M_NOSTART;
+ }
- /* Pin configuration */
- sc = lpc24xx_pin_config(e->pins, LPC24XX_PIN_SET_FUNCTION);
- RTEMS_CHECK_SC(sc, "pin configuration");
+ bus = (lpc24xx_i2c_bus *) base;
+ bus->msg_end = msgs + msg_count;
+ lpc24xx_i2c_setup_msg(bus, msgs);
- /* Clock high and low duty cycles */
- regs->sclh = cycles;
- regs->scll = cycles;
+ regs = bus->regs;
- /* Disable module */
- regs->conclr = LPC24XX_I2C_EN;
+ /* Start */
+ regs->conset = LPC24XX_I2C_STA;
- /* Install interrupt handler and disable this vector */
- sc = rtems_interrupt_handler_install(
- e->vector,
- "I2C",
- RTEMS_INTERRUPT_UNIQUE,
- lpc24xx_i2c_handler,
- e
+ bsp_interrupt_vector_enable(bus->irq);
+ eno = rtems_binary_semaphore_wait_timed_ticks(
+ &bus->sem,
+ bus->base.timeout
);
- 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;
+ if (eno != 0) {
+ regs->conclr = LPC24XX_I2C_EN;
+ regs->conset = LPC24XX_I2C_EN;
+ rtems_binary_semaphore_try_wait(&bus->sem);
+ return -ETIMEDOUT;
+ }
- return RTEMS_SUCCESSFUL;
+ return bus->error;
}
-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;
+/* I2C-Bus Specification and User Manual, Table 10 */
+static const uint16_t lpc24xx_i2c_t_low_high[3][2] = {
+ { 4700, 4000 },
+ { 1300, 600 },
+ { 500, 260 }
+};
- /* Start */
- regs->conclr = LPC24XX_I2C_STA | LPC24XX_I2C_AA | LPC24XX_I2C_SI;
- regs->conset = LPC24XX_I2C_STA;
+static uint32_t lpc24xx_i2c_cycle_count(uint32_t scl, uint32_t x, uint32_t t)
+{
+ scl = (scl * x + t - 1) / t;
- /* Wait */
- sc = lpc24xx_i2c_wait(e);
- RTEMS_CHECK_SC(sc, "wait for state update");
+ if (scl <= 4) {
+ scl = 4;
+ } else if (scl >= 0xffff) {
+ scl = 0xffff;
+ }
- return RTEMS_SUCCESSFUL;
+ return scl;
}
-static rtems_status_code lpc24xx_i2c_send_stop(rtems_libi2c_bus_t *bus)
+static int lpc24xx_i2c_set_clock(i2c_bus *base, unsigned long clock)
{
- lpc24xx_i2c_bus_entry *e = (lpc24xx_i2c_bus_entry *) bus;
- volatile lpc24xx_i2c *regs = e->regs;
+ lpc24xx_i2c_bus *bus;
+ volatile lpc24xx_i2c *regs;
+ size_t i;
+ uint32_t low;
+ uint32_t high;
+ uint32_t t;
+ uint32_t scl;
+
+ if (clock <= 100000) {
+ i = 0;
+ } else if (clock <= 400000) {
+ i = 1;
+ } else {
+ i = 2;
+ }
+
+ low = lpc24xx_i2c_t_low_high[i][0];
+ high = lpc24xx_i2c_t_low_high[i][1];
+ t = low + high;
+ scl = (LPC24XX_PCLK + clock - 1) / clock;
- /* Stop */
- regs->conset = LPC24XX_I2C_STO | LPC24XX_I2C_AA;
- regs->conclr = LPC24XX_I2C_STA | LPC24XX_I2C_SI;
+ bus = (lpc24xx_i2c_bus *) base;
+ regs = bus->regs;
- return RTEMS_SUCCESSFUL;
+ regs->scll = lpc24xx_i2c_cycle_count(scl, low, t);
+ regs->sclh = lpc24xx_i2c_cycle_count(scl, high, t);
+
+ return 0;
}
-static rtems_status_code lpc24xx_i2c_send_addr(
- rtems_libi2c_bus_t *bus,
- uint32_t addr,
- int rw
-)
+static void
+lpc24xx_i2c_destroy(i2c_bus *base)
{
- 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;
- }
+ lpc24xx_i2c_bus *bus;
+ rtems_status_code sc;
- /* 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;
+ bus = (lpc24xx_i2c_bus *) base;
- /* Wait */
- sc = lpc24xx_i2c_wait(e);
- RTEMS_CHECK_SC_RV(sc, "wait for state update");
+ sc = rtems_interrupt_handler_remove(bus->irq, lpc24xx_i2c_interrupt, bus);
+ _Assert(sc == RTEMS_SUCCESSFUL);
+ (void) sc;
- /* Check state */
- state = regs->stat;
- if (state != 0x18U && state != 0x40U) {
- return -RTEMS_IO_ERROR;
- }
+ /* Disable I2C module */
+ bus->regs->conclr = LPC24XX_I2C_EN;
+
+ sc = lpc24xx_module_disable(bus->module);
+ _Assert(sc == RTEMS_SUCCESSFUL);
+ (void) sc;
- return RTEMS_SUCCESSFUL;
+ rtems_binary_semaphore_destroy(&bus->sem);
+ i2c_bus_destroy_and_free(&bus->base);
}
-static int lpc24xx_i2c_read(rtems_libi2c_bus_t *bus, unsigned char *in, int n)
+static int lpc24xx_i2c_init(lpc24xx_i2c_bus *bus)
{
- 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;
- }
+ rtems_status_code sc;
- /* Setup receive buffer */
- e->data = data;
- e->end = end;
+ sc = lpc24xx_module_enable(bus->module, LPC24XX_MODULE_PCLK_DEFAULT);
+ _Assert(sc == RTEMS_SUCCESSFUL);
+ (void) sc;
- /* Ready to receive data */
- if (data + 1 != end) {
- regs->conset = LPC24XX_I2C_AA;
- } else {
- regs->conclr = LPC24XX_I2C_AA;
+ /* Disable I2C module */
+ bus->regs->conclr = LPC24XX_I2C_EN;
+
+ sc = rtems_interrupt_handler_install(
+ bus->irq,
+ "I2C",
+ RTEMS_INTERRUPT_UNIQUE,
+ lpc24xx_i2c_interrupt,
+ bus
+ );
+ if (sc != RTEMS_SUCCESSFUL) {
+ return EAGAIN;
}
- regs->conclr = LPC24XX_I2C_SI;
- /* Wait */
- sc = lpc24xx_i2c_wait(e);
- RTEMS_CHECK_SC_RV(sc, "wait for state update");
+ rtems_binary_semaphore_init(&bus->sem, "I2C");
- /* Check state */
- state = regs->stat;
- if (state != 0x58U) {
- return -RTEMS_IO_ERROR;
- }
+ lpc24xx_i2c_set_clock(&bus->base, I2C_BUS_CLOCK_DEFAULT);
+
+ /* Initialize I2C module */
+ bus->regs->conset = LPC24XX_I2C_EN;
- return n;
+ return 0;
}
-static int lpc24xx_i2c_write(
- rtems_libi2c_bus_t *bus,
- unsigned char *out,
- int n
+static int i2c_bus_register_lpc24xx(
+ const char *bus_path,
+ const lpc24xx_i2c_config *config
)
{
- 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;
+ lpc24xx_i2c_bus *bus;
+ int eno;
- if (n <= 0) {
- return n;
+ bus = (lpc24xx_i2c_bus *) i2c_bus_alloc_and_init(sizeof(*bus));
+ if (bus == NULL){
+ return -1;
}
- /* Setup transmit buffer */
- e->data = out + 1;
- e->end = out + n;
+ bus->regs = config->regs;
+ bus->module = config->module;
+ bus->irq = config->irq;
- /* 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;
+ eno = lpc24xx_i2c_init(bus);
+ if (eno != 0) {
+ (*bus->base.destroy)(&bus->base);
+ rtems_set_errno_and_return_minus_one(eno);
}
- return n;
+ bus->base.transfer = lpc24xx_i2c_transfer;
+ bus->base.set_clock = lpc24xx_i2c_set_clock;
+ bus->base.destroy = lpc24xx_i2c_destroy;
+
+ return i2c_bus_register(&bus->base, bus_path);
}
-static int lpc24xx_i2c_set_transfer_mode(
- rtems_libi2c_bus_t *bus,
- const rtems_libi2c_tfr_mode_t *mode
-)
+int lpc24xx_register_i2c_0(void)
{
- return -RTEMS_NOT_IMPLEMENTED;
+ static const lpc24xx_i2c_config config = {
+ .regs = (volatile lpc24xx_i2c *) I2C0_BASE_ADDR,
+ .module = LPC24XX_MODULE_I2C_0,
+ .irq = LPC24XX_IRQ_I2C_0
+ };
+
+ return i2c_bus_register_lpc24xx(
+ LPC24XX_I2C_0_BUS_PATH,
+ &config
+ );
}
-static int lpc24xx_i2c_ioctl(rtems_libi2c_bus_t *bus, int cmd, void *arg)
+int lpc24xx_register_i2c_1(void)
{
- 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 lpc24xx_i2c_config config = {
+ .regs = (volatile lpc24xx_i2c *) I2C1_BASE_ADDR,
+ .module = LPC24XX_MODULE_I2C_1,
+ .irq = LPC24XX_IRQ_I2C_1
+ };
+
+ return i2c_bus_register_lpc24xx(
+ LPC24XX_I2C_2_BUS_PATH,
+ &config
+ );
}
-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
-};
+int lpc24xx_register_i2c_2(void)
+{
+ static const lpc24xx_i2c_config config = {
+ .regs = (volatile lpc24xx_i2c *) I2C2_BASE_ADDR,
+ .module = LPC24XX_MODULE_I2C_2,
+ .irq = LPC24XX_IRQ_I2C_2
+ };
+
+ return i2c_bus_register_lpc24xx(
+ LPC24XX_I2C_2_BUS_PATH,
+ &config
+ );
+}
diff --git a/bsps/arm/lpc24xx/include/bsp/i2c.h b/bsps/arm/lpc24xx/include/bsp/i2c.h
index 3c29468c4e..9c3566cd86 100644
--- a/bsps/arm/lpc24xx/include/bsp/i2c.h
+++ b/bsps/arm/lpc24xx/include/bsp/i2c.h
@@ -1,66 +1,62 @@
/**
* @file
*
- * @ingroup RTEMSBSPsARMLPC24XX_libi2c
- *
- * @brief LibI2C bus driver for the I2C modules.
+ * @ingroup RTEMSBSPsARMLPC24XXI2C
*/
/*
- * Copyright (c) 2009-2011 embedded brains GmbH. All rights reserved.
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (C) 2009, 2019 embedded brains GmbH
*
- * embedded brains GmbH
- * Obere Lagerstr. 30
- * 82178 Puchheim
- * Germany
- * <rtems@embedded-brains.de>
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
*
- * 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.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef LIBBSP_ARM_LPC24XX_I2C_H
#define LIBBSP_ARM_LPC24XX_I2C_H
-#include <rtems.h>
-#include <rtems/libi2c.h>
-
-#include <bsp/io.h>
-#include <bsp/lpc24xx.h>
-
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/**
- * @defgroup lpc24xx_libi2c LPC24XX Bus Drivers
+ * @defgroup RTEMSBSPsARMLPC24XXI2C I2C Driver
*
* @ingroup RTEMSBSPsARMLPC24XX
*
- * @brief LibI2C bus drivers for LPC24XX.
- *
* @{
*/
-typedef struct {
- rtems_libi2c_bus_t bus;
- volatile lpc24xx_i2c *regs;
- size_t index;
- const lpc24xx_pin_range *pins;
- rtems_vector_number vector;
- rtems_id state_update;
- uint8_t *volatile data;
- uint8_t *volatile end;
-} lpc24xx_i2c_bus_entry;
+#define LPC24XX_I2C_0_BUS_PATH "/dev/i2c-0"
+
+#define LPC24XX_I2C_1_BUS_PATH "/dev/i2c-1"
-extern const rtems_libi2c_bus_ops_t lpc24xx_i2c_ops;
+#define LPC24XX_I2C_2_BUS_PATH "/dev/i2c-2"
-extern rtems_libi2c_bus_t *const lpc24xx_i2c_0;
+int lpc24xx_register_i2c_0(void);
-extern rtems_libi2c_bus_t *const lpc24xx_i2c_1;
+int lpc24xx_register_i2c_1(void);
-extern rtems_libi2c_bus_t *const lpc24xx_i2c_2;
+int lpc24xx_register_i2c_2(void);
/** @} */
diff --git a/c/src/lib/libbsp/arm/lpc24xx/Makefile.am b/c/src/lib/libbsp/arm/lpc24xx/Makefile.am
index 0a921f6230..58ae4da79b 100644
--- a/c/src/lib/libbsp/arm/lpc24xx/Makefile.am
+++ b/c/src/lib/libbsp/arm/lpc24xx/Makefile.am
@@ -100,7 +100,6 @@ librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/lpc24xx/spi/ssp.c
# I2C
librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/lpc24xx/i2c/i2c.c
-librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/lpc24xx/i2c/i2c-config.c
# Framebuffer
librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/shared/fb/arm-pl111.c