[PATCH 9/9] bsp/xilinx-zynq: Add Cadence I2C bus driver

Sebastian Huber sebastian.huber at embedded-brains.de
Thu Nov 13 09:30:27 UTC 2014


---
 c/src/lib/libbsp/arm/xilinx-zynq/Makefile.am       |   6 +
 c/src/lib/libbsp/arm/xilinx-zynq/i2c/cadence-i2c.c | 481 +++++++++++++++++++++
 .../arm/xilinx-zynq/include/cadence-i2c-regs.h     |  73 ++++
 .../libbsp/arm/xilinx-zynq/include/cadence-i2c.h   |  35 ++
 c/src/lib/libbsp/arm/xilinx-zynq/include/i2c.h     |  50 +++
 c/src/lib/libbsp/arm/xilinx-zynq/preinstall.am     |  12 +
 6 files changed, 657 insertions(+)
 create mode 100644 c/src/lib/libbsp/arm/xilinx-zynq/i2c/cadence-i2c.c
 create mode 100644 c/src/lib/libbsp/arm/xilinx-zynq/include/cadence-i2c-regs.h
 create mode 100644 c/src/lib/libbsp/arm/xilinx-zynq/include/cadence-i2c.h
 create mode 100644 c/src/lib/libbsp/arm/xilinx-zynq/include/i2c.h

diff --git a/c/src/lib/libbsp/arm/xilinx-zynq/Makefile.am b/c/src/lib/libbsp/arm/xilinx-zynq/Makefile.am
index 1bce30a..15f8af4 100644
--- a/c/src/lib/libbsp/arm/xilinx-zynq/Makefile.am
+++ b/c/src/lib/libbsp/arm/xilinx-zynq/Makefile.am
@@ -43,6 +43,9 @@ include_bsp_HEADERS += ../shared/include/arm-gic-irq.h
 include_bsp_HEADERS += ../shared/include/arm-gic-regs.h
 include_bsp_HEADERS += ../shared/include/arm-gic-tm27.h
 include_bsp_HEADERS += ../shared/include/arm-release-id.h
+include_bsp_HEADERS += include/cadence-i2c.h
+include_bsp_HEADERS += include/cadence-i2c-regs.h
+include_bsp_HEADERS += include/i2c.h
 include_bsp_HEADERS += include/irq.h
 include_bsp_HEADERS += include/zynq-uart.h
 include_bsp_HEADERS += include/zynq-uart-regs.h
@@ -114,6 +117,9 @@ libbsp_a_SOURCES += console/zynq-uart.c
 libbsp_a_SOURCES += ../../shared/clockdrv_shell.h
 libbsp_a_SOURCES += ../shared/arm-a9mpcore-clock-config.c
 
+# I2C
+libbsp_a_SOURCES += i2c/cadence-i2c.c
+
 # Cache
 libbsp_a_SOURCES += ../../../libcpu/shared/src/cache_manager.c
 libbsp_a_SOURCES += ../shared/arm-l2c-310/cache_.h
diff --git a/c/src/lib/libbsp/arm/xilinx-zynq/i2c/cadence-i2c.c b/c/src/lib/libbsp/arm/xilinx-zynq/i2c/cadence-i2c.c
new file mode 100644
index 0000000..336fe48
--- /dev/null
+++ b/c/src/lib/libbsp/arm/xilinx-zynq/i2c/cadence-i2c.c
@@ -0,0 +1,481 @@
+/*
+ * Copyright (c) 2014 embedded brains GmbH.  All rights reserved.
+ *
+ *  embedded brains GmbH
+ *  Dornierstr. 4
+ *  82178 Puchheim
+ *  Germany
+ *  <info at 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/cadence-i2c.h>
+#include <bsp/cadence-i2c-regs.h>
+
+#include <rtems/irq-extension.h>
+#include <rtems/score/assert.h>
+
+#include <dev/i2c/i2c.h>
+
+#define CADENCE_I2C_DIV_A_MAX 4
+
+#define CADENCE_I2C_DIV_B_MAX 64
+
+#define CADENCE_I2C_FIFO_DEPTH 16
+
+#define CADENCE_I2C_DATA_IRQ_DEPTH (CADENCE_I2C_FIFO_DEPTH - 2)
+
+#define CADENCE_I2C_TRANSFER_SIZE_MAX 255
+
+#define CADENCE_I2C_TRANSFER_SIZE_ONCE_MAX (18 * CADENCE_I2C_DATA_IRQ_DEPTH)
+
+#define CADENCE_I2C_IRQ_ERROR \
+  (CADENCE_I2C_IXR_ARB_LOST \
+    | CADENCE_I2C_IXR_RX_UNF \
+    | CADENCE_I2C_IXR_TX_OVR \
+    | CADENCE_I2C_IXR_RX_OVR \
+    | CADENCE_I2C_IXR_NACK)
+
+#define CADENCE_I2C_IRQ_USED \
+  (CADENCE_I2C_IRQ_ERROR \
+    | CADENCE_I2C_IXR_DATA \
+    | CADENCE_I2C_IXR_COMP)
+
+typedef struct {
+  i2c_bus base;
+  volatile cadence_i2c *regs;
+  i2c_msg *msgs;
+  uint32_t msg_todo;
+  uint32_t current_msg_todo;
+  uint8_t *current_msg_byte;
+  uint32_t current_todo;
+  uint32_t irqstatus;
+  bool read;
+  bool hold;
+  rtems_id task_id;
+  uint32_t input_clock;
+  rtems_vector_number irq;
+} cadence_i2c_bus;
+
+static void cadence_i2c_disable_interrupts(volatile cadence_i2c *regs)
+{
+  regs->irqdisable = 0xffff;
+}
+
+static void cadence_i2c_clear_irq_status(volatile cadence_i2c *regs)
+{
+  regs->irqstatus = regs->irqstatus;
+}
+
+static void cadence_i2c_reset(cadence_i2c_bus *bus)
+{
+  volatile cadence_i2c *regs = bus->regs;
+  uint32_t val;
+
+  cadence_i2c_disable_interrupts(regs);
+
+  val = regs->control;
+  val &= ~CADENCE_I2C_CONTROL_HOLD;
+  val |= CADENCE_I2C_CONTROL_ACKEN
+    | CADENCE_I2C_CONTROL_MS
+    | CADENCE_I2C_CONTROL_CLR_FIFO;
+  regs->control = val;
+
+  regs->transfer_size = 0;
+  regs->status = regs->status;
+
+  cadence_i2c_clear_irq_status(regs);
+}
+
+static uint32_t cadence_i2c_set_address_size(
+  const i2c_msg *msg,
+  uint32_t control
+)
+{
+  if ((msg->flags & I2C_M_TEN) == 0) {
+    control |= CADENCE_I2C_CONTROL_NEA;
+  } else {
+    control &= ~CADENCE_I2C_CONTROL_NEA;
+  }
+
+  return control;
+}
+
+static void cadence_i2c_setup_read_transfer(
+  cadence_i2c_bus *bus,
+  volatile cadence_i2c *regs,
+  uint32_t control
+)
+{
+  control |= CADENCE_I2C_CONTROL_RW;
+  regs->control = control;
+
+  if (bus->current_todo <= CADENCE_I2C_TRANSFER_SIZE_MAX) {
+    regs->transfer_size = bus->current_todo;
+  } else {
+    regs->transfer_size = CADENCE_I2C_TRANSFER_SIZE_ONCE_MAX;
+  }
+}
+
+static void cadence_i2c_next_byte(cadence_i2c_bus *bus)
+{
+  --bus->current_msg_todo;
+  ++bus->current_msg_byte;
+
+  if (bus->current_msg_todo == 0) {
+    i2c_msg *msg;
+
+    ++bus->msgs;
+    --bus->msg_todo;
+
+    msg = &bus->msgs[0];
+
+    bus->current_msg_todo = msg->len;
+    bus->current_msg_byte = msg->buf;
+  }
+}
+
+static void cadence_i2c_write_to_fifo(
+  cadence_i2c_bus *bus,
+  volatile cadence_i2c *regs
+)
+{
+  uint32_t space_available;
+  uint32_t todo_now;
+  uint32_t i;
+
+  space_available = CADENCE_I2C_FIFO_DEPTH - regs->transfer_size;
+
+  if (bus->current_todo > space_available) {
+    todo_now = space_available;
+  } else {
+    todo_now = bus->current_todo;
+  }
+
+  bus->current_todo -= todo_now;
+
+  for (i = 0; i < todo_now; ++i) {
+    regs->data = *bus->current_msg_byte;
+
+    cadence_i2c_next_byte(bus);
+  }
+}
+
+static void cadence_i2c_setup_write_transfer(
+  cadence_i2c_bus *bus,
+  volatile cadence_i2c *regs,
+  uint32_t control
+)
+{
+  control &= ~CADENCE_I2C_CONTROL_RW;
+  regs->control = control;
+
+  cadence_i2c_write_to_fifo(bus, regs);
+}
+
+static void cadence_i2c_setup_transfer(
+  cadence_i2c_bus *bus,
+  volatile cadence_i2c *regs
+)
+{
+  const i2c_msg *msgs = bus->msgs;
+  uint32_t msg_todo = bus->msg_todo;
+  uint32_t i;
+  uint32_t control;
+
+  bus->current_todo = msgs[0].len;
+  for (i = 1; i < msg_todo && (msgs[i].flags & I2C_M_NOSTART) != 0; ++i) {
+    bus->current_todo += msgs[i].len;
+  }
+
+  regs = bus->regs;
+
+  control = regs->control;
+  control |= CADENCE_I2C_CONTROL_CLR_FIFO;
+
+  bus->hold = i < msg_todo;
+
+  if (bus->hold || bus->current_todo > CADENCE_I2C_FIFO_DEPTH) {
+    control |= CADENCE_I2C_CONTROL_HOLD;
+  } else {
+    control &= ~CADENCE_I2C_CONTROL_HOLD;
+  }
+
+  control = cadence_i2c_set_address_size(msgs, control);
+
+  bus->read = (msgs->flags & I2C_M_RD) != 0;
+  if (bus->read) {
+    cadence_i2c_setup_read_transfer(bus, regs, control);
+  } else {
+    cadence_i2c_setup_write_transfer(bus, regs, control);
+  }
+
+  cadence_i2c_clear_irq_status(regs);
+
+  regs->address = CADENCE_I2C_ADDRESS(msgs->addr);
+}
+
+static void cadence_i2c_continue_read_transfer(
+  cadence_i2c_bus *bus,
+  volatile cadence_i2c *regs
+)
+{
+  uint32_t i;
+
+  bus->current_todo -= CADENCE_I2C_DATA_IRQ_DEPTH;
+
+  /*
+   * This works since CADENCE_I2C_TRANSFER_SIZE_ONCE_MAX is an integral
+   * multiple of CADENCE_I2C_DATA_IRQ_DEPTH.
+   *
+   * FIXME: Tests with a 1024 byte EEPROM show that this doesn't work.  Needs
+   * further investigations with an I2C analyser or an oscilloscope.
+   */
+  if (regs->transfer_size == 0) {
+    if (bus->current_todo <= CADENCE_I2C_TRANSFER_SIZE_MAX) {
+      regs->transfer_size = bus->current_todo;
+    } else {
+      regs->transfer_size = CADENCE_I2C_TRANSFER_SIZE_ONCE_MAX;
+    }
+  }
+
+  for (i = 0; i < CADENCE_I2C_DATA_IRQ_DEPTH; ++i) {
+    *bus->current_msg_byte = (uint8_t) regs->data;
+
+    cadence_i2c_next_byte(bus);
+  }
+
+  if (!bus->hold && bus->current_todo <= CADENCE_I2C_FIFO_DEPTH) {
+    regs->control &= ~CADENCE_I2C_CONTROL_HOLD;
+  }
+}
+
+static void cadence_i2c_interrupt(void *arg)
+{
+  cadence_i2c_bus *bus = arg;
+  volatile cadence_i2c *regs = bus->regs;
+  uint32_t irqstatus = regs->irqstatus;
+  bool done = false;
+
+  /* Clear interrupts */
+  regs->irqstatus = irqstatus;
+
+  if ((irqstatus & (CADENCE_I2C_IXR_ARB_LOST | CADENCE_I2C_IXR_NACK)) != 0) {
+    done = true;
+  }
+
+  if (
+    (irqstatus & CADENCE_I2C_IXR_DATA) != 0
+      && bus->read
+      && bus->current_todo >= CADENCE_I2C_DATA_IRQ_DEPTH
+  ) {
+    cadence_i2c_continue_read_transfer(bus, regs);
+  }
+
+  if ((irqstatus & CADENCE_I2C_IXR_COMP) != 0) {
+    if (bus->read) {
+      uint32_t todo_now = bus->current_todo;
+      uint32_t i;
+
+      for (i = 0; i < todo_now; ++i) {
+        *bus->current_msg_byte = (uint8_t) regs->data;
+
+        cadence_i2c_next_byte(bus);
+      }
+
+      bus->current_todo = 0;
+
+      done = true;
+    } else {
+      if (bus->current_todo > 0) {
+        cadence_i2c_write_to_fifo(bus, regs);
+      } else {
+        done = true;
+      }
+
+      if (!bus->hold && bus->current_todo == 0) {
+        regs->control &= ~CADENCE_I2C_CONTROL_HOLD;
+      }
+    }
+  }
+
+  if (done) {
+    uint32_t err = irqstatus & CADENCE_I2C_IRQ_ERROR;
+
+    if (bus->msg_todo == 0 || err != 0) {
+      rtems_status_code sc;
+
+      cadence_i2c_disable_interrupts(regs);
+
+      bus->irqstatus = err;
+
+      sc = rtems_event_transient_send(bus->task_id);
+      _Assert(sc == RTEMS_SUCCESSFUL);
+      (void) sc;
+    } else {
+      cadence_i2c_setup_transfer(bus, regs);
+    }
+  }
+}
+
+static int cadence_i2c_transfer(
+  i2c_bus *base,
+  i2c_msg *msgs,
+  uint32_t msg_count
+)
+{
+  cadence_i2c_bus *bus = (cadence_i2c_bus *) base;
+  volatile cadence_i2c *regs;
+  rtems_status_code sc;
+  uint32_t i;
+  uint32_t j;
+
+  _Assert(msg_count > 0);
+
+  for (i = 0, j = 0; i < msg_count; ++i) {
+    /* FIXME: Not sure if we can support this. */
+    if ((msgs[i].flags & I2C_M_RECV_LEN) != 0) {
+      return -EINVAL;
+    }
+
+    if ((msgs[i].flags & I2C_M_NOSTART) != 0) {
+      if ((msgs[i].flags & I2C_M_RD) != (msgs[j].flags & I2C_M_RD)) {
+        return -EINVAL;
+      }
+
+      if (msgs[i].addr != msgs[j].addr) {
+        return -EINVAL;
+      }
+    } else {
+      j = i;
+    }
+  }
+
+  bus->msgs = &msgs[0];
+  bus->msg_todo = msg_count;
+  bus->current_msg_todo = msgs[0].len;
+  bus->current_msg_byte = msgs[0].buf;
+  bus->task_id = rtems_task_self();
+
+  regs = bus->regs;
+  cadence_i2c_setup_transfer(bus, regs);
+  regs->irqenable = CADENCE_I2C_IRQ_USED;
+
+  sc = rtems_event_transient_receive(RTEMS_WAIT, bus->base.timeout);
+  if (sc != RTEMS_SUCCESSFUL) {
+    cadence_i2c_reset(bus);
+
+    return -ETIMEDOUT;
+  }
+
+  return bus->irqstatus == 0 ? 0 : -EIO;
+}
+
+static int cadence_i2c_set_clock(i2c_bus *base, unsigned long clock)
+{
+  cadence_i2c_bus *bus = (cadence_i2c_bus *) base;
+  volatile cadence_i2c *regs = bus->regs;
+  uint32_t error = 0xffffffff;
+  uint32_t best_div_a = CADENCE_I2C_DIV_A_MAX - 1;
+  uint32_t best_div_b = CADENCE_I2C_DIV_B_MAX - 1;
+  uint32_t div = bus->input_clock / (22 * clock);
+  uint32_t div_a;
+  uint32_t control;
+
+  if (div <= 0 || div > (CADENCE_I2C_DIV_A_MAX * CADENCE_I2C_DIV_B_MAX)) {
+    return -EIO;
+  }
+
+  for (div_a = 0; div_a < CADENCE_I2C_DIV_A_MAX; ++div_a) {
+    uint32_t a = 22 * clock * (div_a + 1);
+    uint32_t b = (bus->input_clock + a - 1) / a;
+
+    if (b > 0 && b <= CADENCE_I2C_DIV_B_MAX) {
+      uint32_t actual_clock = bus->input_clock / (22 * (div_a + 1) * b);
+      uint32_t e = clock < actual_clock ?
+        actual_clock - clock : clock - actual_clock;
+
+      /*
+       * Favour greater div_a values according to UG585, Zynq-7000 AP SoC
+       * Technical Reference Manual, Table 20-1: Calculated Values for Standard
+       * and High Speed SCL Clock Values".
+       */
+      if (e <= error && actual_clock <= clock) {
+        error = e;
+        best_div_a = div_a;
+        best_div_b = b - 1;
+      }
+    }
+  }
+
+  control = regs->control;
+  control = CADENCE_I2C_CONTROL_DIV_A_SET(control, best_div_a);
+  control = CADENCE_I2C_CONTROL_DIV_B_SET(control, best_div_b);
+  regs->control = control;
+
+  return 0;
+}
+
+static void cadence_i2c_destroy(i2c_bus *base)
+{
+  cadence_i2c_bus *bus = (cadence_i2c_bus *) base;
+  rtems_status_code sc;
+
+  sc = rtems_interrupt_handler_remove(bus->irq, cadence_i2c_interrupt, bus);
+  _Assert(sc == RTEMS_SUCCESSFUL);
+  (void) sc;
+
+  i2c_bus_destroy_and_free(&bus->base);
+}
+
+int i2c_bus_register_cadence(
+  const char *bus_path,
+  uintptr_t register_base,
+  uint32_t input_clock,
+  rtems_vector_number irq
+)
+{
+  cadence_i2c_bus *bus;
+  rtems_status_code sc;
+  int err;
+
+  bus = (cadence_i2c_bus *) i2c_bus_alloc_and_init(sizeof(*bus));
+  if (bus == NULL) {
+    return -1;
+  }
+
+  bus->regs = (volatile cadence_i2c *) register_base;
+  bus->input_clock = input_clock;
+  bus->irq = irq;
+
+  cadence_i2c_reset(bus);
+
+  err = cadence_i2c_set_clock(&bus->base, I2C_BUS_CLOCK_DEFAULT);
+  if (err != 0) {
+    (*bus->base.destroy)(&bus->base);
+
+    rtems_set_errno_and_return_minus_one(-err);
+  }
+
+  sc = rtems_interrupt_handler_install(
+    irq,
+    "Cadence I2C",
+    RTEMS_INTERRUPT_UNIQUE,
+    cadence_i2c_interrupt,
+    bus
+  );
+  if (sc != RTEMS_SUCCESSFUL) {
+    (*bus->base.destroy)(&bus->base);
+
+    rtems_set_errno_and_return_minus_one(EIO);
+  }
+
+  bus->base.transfer = cadence_i2c_transfer;
+  bus->base.set_clock = cadence_i2c_set_clock;
+  bus->base.destroy = cadence_i2c_destroy;
+
+  return i2c_bus_register(&bus->base, bus_path);
+}
diff --git a/c/src/lib/libbsp/arm/xilinx-zynq/include/cadence-i2c-regs.h b/c/src/lib/libbsp/arm/xilinx-zynq/include/cadence-i2c-regs.h
new file mode 100644
index 0000000..c06a47c
--- /dev/null
+++ b/c/src/lib/libbsp/arm/xilinx-zynq/include/cadence-i2c-regs.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2014 embedded brains GmbH.  All rights reserved.
+ *
+ *  embedded brains GmbH
+ *  Dornierstr. 4
+ *  82178 Puchheim
+ *  Germany
+ *  <info at 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.
+ */
+
+#ifndef LIBBSP_ARM_XILINX_ZYNQ_CADENCE_I2C_REGS_H
+#define LIBBSP_ARM_XILINX_ZYNQ_CADENCE_I2C_REGS_H
+
+#include <bsp/utility.h>
+
+typedef struct {
+	uint32_t control;
+#define CADENCE_I2C_CONTROL_DIV_A(val) BSP_FLD32(val, 14, 15)
+#define CADENCE_I2C_CONTROL_DIV_A_GET(reg) BSP_FLD32GET(reg, 14, 15)
+#define CADENCE_I2C_CONTROL_DIV_A_SET(reg, val) BSP_FLD32SET(reg, val, 14, 15)
+#define CADENCE_I2C_CONTROL_DIV_B(val) BSP_FLD32(val, 8, 13)
+#define CADENCE_I2C_CONTROL_DIV_B_GET(reg) BSP_FLD32GET(reg, 8, 13)
+#define CADENCE_I2C_CONTROL_DIV_B_SET(reg, val) BSP_FLD32SET(reg, val, 8, 13)
+#define CADENCE_I2C_CONTROL_CLR_FIFO BSP_BIT32(6)
+#define CADENCE_I2C_CONTROL_SLVMON BSP_BIT32(5)
+#define CADENCE_I2C_CONTROL_HOLD BSP_BIT32(4)
+#define CADENCE_I2C_CONTROL_ACKEN BSP_BIT32(3)
+#define CADENCE_I2C_CONTROL_NEA BSP_BIT32(2)
+#define CADENCE_I2C_CONTROL_MS BSP_BIT32(1)
+#define CADENCE_I2C_CONTROL_RW BSP_BIT32(0)
+	uint32_t status;
+#define CADENCE_I2C_STATUS_BA BSP_BIT32(8)
+#define CADENCE_I2C_STATUS_RXOVF BSP_BIT32(7)
+#define CADENCE_I2C_STATUS_TXDV BSP_BIT32(6)
+#define CADENCE_I2C_STATUS_RXDV BSP_BIT32(5)
+#define CADENCE_I2C_STATUS_RXRW BSP_BIT32(3)
+	uint32_t address;
+#define CADENCE_I2C_ADDRESS(val) BSP_FLD32(val, 0, 9)
+#define CADENCE_I2C_ADDRESS_GET(reg) BSP_FLD32GET(reg, 0, 9)
+#define CADENCE_I2C_ADDRESS_SET(reg, val) BSP_FLD32SET(reg, val, 0, 9)
+	uint32_t data;
+	uint32_t irqstatus;
+#define CADENCE_I2C_IXR_ARB_LOST BSP_BIT32(9)
+#define CADENCE_I2C_IXR_RX_UNF BSP_BIT32(7)
+#define CADENCE_I2C_IXR_TX_OVR BSP_BIT32(6)
+#define CADENCE_I2C_IXR_RX_OVR BSP_BIT32(5)
+#define CADENCE_I2C_IXR_SLV_RDY BSP_BIT32(4)
+#define CADENCE_I2C_IXR_TO BSP_BIT32(3)
+#define CADENCE_I2C_IXR_NACK BSP_BIT32(2)
+#define CADENCE_I2C_IXR_DATA BSP_BIT32(1)
+#define CADENCE_I2C_IXR_COMP BSP_BIT32(0)
+	uint32_t transfer_size;
+#define CADENCE_I2C_TRANSFER_SIZE(val) BSP_FLD32(val, 0, 7)
+#define CADENCE_I2C_TRANSFER_SIZE_GET(reg) BSP_FLD32GET(reg, 0, 7)
+#define CADENCE_I2C_TRANSFER_SIZE_SET(reg, val) BSP_FLD32SET(reg, val, 0, 7)
+	uint32_t slave_mon_pause;
+#define CADENCE_I2C_SLAVE_MON_PAUSE(val) BSP_FLD32(val, 0, 3)
+#define CADENCE_I2C_SLAVE_MON_PAUSE_GET(reg) BSP_FLD32GET(reg, 0, 3)
+#define CADENCE_I2C_SLAVE_MON_PAUSE_SET(reg, val) BSP_FLD32SET(reg, val, 0, 3)
+	uint32_t timeout;
+#define CADENCE_I2C_TIMEOUT(val) BSP_FLD32(val, 0, 7)
+#define CADENCE_I2C_TIMEOUT_GET(reg) BSP_FLD32GET(reg, 0, 7)
+#define CADENCE_I2C_TIMEOUT_SET(reg, val) BSP_FLD32SET(reg, val, 0, 7)
+	uint32_t irqmask;
+	uint32_t irqenable;
+	uint32_t irqdisable;
+} cadence_i2c;
+
+#endif /* LIBBSP_ARM_XILINX_ZYNQ_CADENCE_I2C_REGS_H */
diff --git a/c/src/lib/libbsp/arm/xilinx-zynq/include/cadence-i2c.h b/c/src/lib/libbsp/arm/xilinx-zynq/include/cadence-i2c.h
new file mode 100644
index 0000000..9697cf3
--- /dev/null
+++ b/c/src/lib/libbsp/arm/xilinx-zynq/include/cadence-i2c.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2014 embedded brains GmbH.  All rights reserved.
+ *
+ *  embedded brains GmbH
+ *  Dornierstr. 4
+ *  82178 Puchheim
+ *  Germany
+ *  <info at 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.
+ */
+
+#ifndef LIBBSP_ARM_XILINX_ZYNQ_CADENCE_I2C_H
+#define LIBBSP_ARM_XILINX_ZYNQ_CADENCE_I2C_H
+
+#include <rtems.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+int i2c_bus_register_cadence(
+  const char *bus_path,
+  uintptr_t register_base,
+  uint32_t input_clock,
+  rtems_vector_number irq
+);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* LIBBSP_ARM_XILINX_ZYNQ_CADENCE_I2C_H */
diff --git a/c/src/lib/libbsp/arm/xilinx-zynq/include/i2c.h b/c/src/lib/libbsp/arm/xilinx-zynq/include/i2c.h
new file mode 100644
index 0000000..709ea01
--- /dev/null
+++ b/c/src/lib/libbsp/arm/xilinx-zynq/include/i2c.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2014 embedded brains GmbH.  All rights reserved.
+ *
+ *  embedded brains GmbH
+ *  Dornierstr. 4
+ *  82178 Puchheim
+ *  Germany
+ *  <info at 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.
+ */
+
+#ifndef LIBBSP_ARM_XILINX_ZYNQ_I2C_H
+#define LIBBSP_ARM_XILINX_ZYNQ_I2C_H
+
+#include <bsp/cadence-i2c.h>
+#include <bsp/irq.h>
+#include <bsp.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+static inline int zynq_register_i2c_0(void)
+{
+  return i2c_bus_register_cadence(
+    "/dev/i2c-0",
+    0xe0004000,
+    zynq_clock_cpu_1x(),
+    ZYNQ_IRQ_I2C_0
+  );
+}
+
+static inline int zynq_register_i2c_1(void)
+{
+  return i2c_bus_register_cadence(
+    "/dev/i2c-1",
+    0xe0005000,
+    zynq_clock_cpu_1x(),
+    ZYNQ_IRQ_I2C_1
+  );
+}
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* LIBBSP_ARM_XILINX_ZYNQ_I2C_H */
diff --git a/c/src/lib/libbsp/arm/xilinx-zynq/preinstall.am b/c/src/lib/libbsp/arm/xilinx-zynq/preinstall.am
index 980196d..a75c344 100644
--- a/c/src/lib/libbsp/arm/xilinx-zynq/preinstall.am
+++ b/c/src/lib/libbsp/arm/xilinx-zynq/preinstall.am
@@ -126,6 +126,18 @@ $(PROJECT_INCLUDE)/bsp/arm-release-id.h: ../shared/include/arm-release-id.h $(PR
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/arm-release-id.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/arm-release-id.h
 
+$(PROJECT_INCLUDE)/bsp/cadence-i2c.h: include/cadence-i2c.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/cadence-i2c.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/cadence-i2c.h
+
+$(PROJECT_INCLUDE)/bsp/cadence-i2c-regs.h: include/cadence-i2c-regs.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/cadence-i2c-regs.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/cadence-i2c-regs.h
+
+$(PROJECT_INCLUDE)/bsp/i2c.h: include/i2c.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/i2c.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/i2c.h
+
 $(PROJECT_INCLUDE)/bsp/irq.h: include/irq.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/irq.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/irq.h
-- 
1.8.4.5




More information about the devel mailing list