[rtems commit] Add NXP PCA9548A 8-channel switch I2C driver

Sebastian Huber sebh at rtems.org
Thu Nov 20 13:53:25 UTC 2014


Module:    rtems
Branch:    master
Commit:    0510cfd8edaa3cf44e7e2ec986b8d8be4f319769
Changeset: http://git.rtems.org/rtems/commit/?id=0510cfd8edaa3cf44e7e2ec986b8d8be4f319769

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Tue Nov 11 12:41:58 2014 +0100

Add NXP PCA9548A 8-channel switch I2C driver

---

 cpukit/dev/Makefile.am                           |  2 +
 cpukit/dev/i2c/switch-nxp-pca9548a.c             | 99 ++++++++++++++++++++++++
 cpukit/dev/include/dev/i2c/switch-nxp-pca9548a.h | 68 ++++++++++++++++
 cpukit/dev/preinstall.am                         |  4 +
 testsuites/libtests/i2c01/init.c                 | 80 ++++++++++++++++++-
 5 files changed, 252 insertions(+), 1 deletion(-)

diff --git a/cpukit/dev/Makefile.am b/cpukit/dev/Makefile.am
index 93737f9..47a1585 100644
--- a/cpukit/dev/Makefile.am
+++ b/cpukit/dev/Makefile.am
@@ -9,6 +9,7 @@ include_dev_i2c_HEADERS =
 include_dev_i2c_HEADERS += include/dev/i2c/eeprom.h
 include_dev_i2c_HEADERS += include/dev/i2c/gpio-nxp-pca9535.h
 include_dev_i2c_HEADERS += include/dev/i2c/i2c.h
+include_dev_i2c_HEADERS += include/dev/i2c/switch-nxp-pca9548a.h
 
 include_linuxdir = $(includedir)/linux
 include_linux_HEADERS =
@@ -22,6 +23,7 @@ libdev_a_SOURCES += i2c/eeprom.c
 libdev_a_SOURCES += i2c/gpio-nxp-pca9535.c
 libdev_a_SOURCES += i2c/i2c-bus.c
 libdev_a_SOURCES += i2c/i2c-dev.c
+libdev_a_SOURCES += i2c/switch-nxp-pca9548a.c
 
 include $(srcdir)/preinstall.am
 include $(top_srcdir)/automake/local.am
diff --git a/cpukit/dev/i2c/switch-nxp-pca9548a.c b/cpukit/dev/i2c/switch-nxp-pca9548a.c
new file mode 100644
index 0000000..50e546f
--- /dev/null
+++ b/cpukit/dev/i2c/switch-nxp-pca9548a.c
@@ -0,0 +1,99 @@
+/**
+ * @file
+ *
+ * @brief Switch NXP PCA9548A Driver Implementation
+ *
+ * @ingroup I2CSWITCHNXPPCA9548A
+ */
+
+/*
+ * Copyright (c) 2014 embedded brains GmbH.  All rights reserved.
+ *
+ *  embedded brains GmbH
+ *  Dornierstr. 4
+ *  82178 Puchheim
+ *  Germany
+ *  <rtems 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.
+ */
+
+#if HAVE_CONFIG_H
+  #include "config.h"
+#endif
+
+#include <dev/i2c/switch-nxp-pca9548a.h>
+
+static int switch_nxp_pca9548a_do_get_control(
+  i2c_dev *dev,
+  uint8_t *val
+)
+{
+  i2c_msg msg = {
+    .addr = dev->address,
+    .flags = I2C_M_RD,
+    .len = (uint16_t) sizeof(*val),
+    .buf = val
+  };
+
+  return i2c_bus_transfer(dev->bus, &msg, 1);
+}
+
+static int switch_nxp_pca9548a_do_set_control(
+  i2c_dev *dev,
+  uint8_t val
+)
+{
+  i2c_msg msg = {
+    .addr = dev->address,
+    .flags = 0,
+    .len = (uint16_t) sizeof(val),
+    .buf = &val
+  };
+
+  return i2c_bus_transfer(dev->bus, &msg, 1);
+}
+
+static int switch_nxp_pca9548a_ioctl(
+  i2c_dev *dev,
+  ioctl_command_t command,
+  void *arg
+)
+{
+  uint8_t v8 = (uint8_t)(uintptr_t) arg;
+  int err;
+
+  switch (command) {
+    case SWITCH_NXP_PCA9548A_GET_CONTROL:
+      err = switch_nxp_pca9548a_do_get_control(dev, arg);
+      break;
+    case SWITCH_NXP_PCA9548A_SET_CONTROL:
+      err = switch_nxp_pca9548a_do_set_control(dev, v8);
+      break;
+    default:
+      err = -ENOTTY;
+      break;
+  }
+
+  return err;
+}
+
+int i2c_dev_register_switch_nxp_pca9548a(
+  const char *bus_path,
+  const char *dev_path,
+  uint16_t address
+)
+{
+  i2c_dev *dev;
+
+  dev = i2c_dev_alloc_and_init(sizeof(*dev), bus_path, address);
+  if (dev == NULL) {
+    return -1;
+  }
+
+  dev->ioctl = switch_nxp_pca9548a_ioctl;
+
+  return i2c_dev_register(dev, dev_path);
+}
diff --git a/cpukit/dev/include/dev/i2c/switch-nxp-pca9548a.h b/cpukit/dev/include/dev/i2c/switch-nxp-pca9548a.h
new file mode 100644
index 0000000..ce8ef2c
--- /dev/null
+++ b/cpukit/dev/include/dev/i2c/switch-nxp-pca9548a.h
@@ -0,0 +1,68 @@
+/**
+ * @file
+ *
+ * @brief Switch NXP PCA9548A Driver API
+ *
+ * @ingroup I2CSWITCHNXPPCA9548A
+ */
+
+/*
+ * Copyright (c) 2014 embedded brains GmbH.  All rights reserved.
+ *
+ *  embedded brains GmbH
+ *  Dornierstr. 4
+ *  82178 Puchheim
+ *  Germany
+ *  <rtems 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 _DEV_I2C_SWITCH_NXP_PCA9548A_H
+#define _DEV_I2C_SWITCH_NXP_PCA9548A_H
+
+#include <dev/i2c/i2c.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * @defgroup I2CSWITCHNXPPCA9548A Switch NXP PCA9535 Driver
+ *
+ * @ingroup I2CDevice
+ *
+ * @brief Driver for NXP PCA9548A 8-channel switch device.
+ *
+ * @{
+ */
+
+int i2c_dev_register_switch_nxp_pca9548a(
+  const char *bus_path,
+  const char *dev_path,
+  uint16_t address
+);
+
+#define SWITCH_NXP_PCA9548A_GET_CONTROL (I2C_DEV_IO_CONTROL + 0)
+
+#define SWITCH_NXP_PCA9548A_SET_CONTROL (I2C_DEV_IO_CONTROL + 1)
+
+static inline int switch_nxp_pca9548a_get_control(int fd, uint8_t *val)
+{
+  return ioctl(fd, SWITCH_NXP_PCA9548A_GET_CONTROL, val);
+}
+
+static inline int switch_nxp_pca9548a_set_control(int fd, uint8_t val)
+{
+  return ioctl(fd, SWITCH_NXP_PCA9548A_SET_CONTROL, (void *)(uintptr_t) val);
+}
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* _DEV_I2C_SWITCH_NXP_PCA9548A_H */
diff --git a/cpukit/dev/preinstall.am b/cpukit/dev/preinstall.am
index 28e361b..f73107b 100644
--- a/cpukit/dev/preinstall.am
+++ b/cpukit/dev/preinstall.am
@@ -35,6 +35,10 @@ $(PROJECT_INCLUDE)/dev/i2c/i2c.h: include/dev/i2c/i2c.h $(PROJECT_INCLUDE)/dev/i
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/dev/i2c/i2c.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/dev/i2c/i2c.h
 
+$(PROJECT_INCLUDE)/dev/i2c/switch-nxp-pca9548a.h: include/dev/i2c/switch-nxp-pca9548a.h $(PROJECT_INCLUDE)/dev/i2c/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/dev/i2c/switch-nxp-pca9548a.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/dev/i2c/switch-nxp-pca9548a.h
+
 $(PROJECT_INCLUDE)/linux/$(dirstamp):
 	@$(MKDIR_P) $(PROJECT_INCLUDE)/linux
 	@: > $(PROJECT_INCLUDE)/linux/$(dirstamp)
diff --git a/testsuites/libtests/i2c01/init.c b/testsuites/libtests/i2c01/init.c
index e6f2eb3..20059af 100644
--- a/testsuites/libtests/i2c01/init.c
+++ b/testsuites/libtests/i2c01/init.c
@@ -19,6 +19,7 @@
 #include <dev/i2c/i2c.h>
 #include <dev/i2c/eeprom.h>
 #include <dev/i2c/gpio-nxp-pca9535.h>
+#include <dev/i2c/switch-nxp-pca9548a.h>
 
 #include <sys/ioctl.h>
 #include <sys/stat.h>
@@ -42,6 +43,8 @@ const char rtems_test_name[] = "I2C 1";
 
 #define DEVICE_GPIO_NXP_PCA9535 (2UL << SPARE_ADDRESS_BITS)
 
+#define DEVICE_SWITCH_NXP_PCA9548A (3UL << SPARE_ADDRESS_BITS)
+
 #define EEPROM_SIZE 512
 
 typedef struct test_device test_device;
@@ -73,12 +76,18 @@ typedef struct {
 } test_device_eeprom;
 
 typedef struct {
+  test_device base;
+  uint8_t control;
+} test_device_switch_nxp_pca9548a;
+
+typedef struct {
   i2c_bus base;
   unsigned long clock;
-  test_device *devices[3];
+  test_device *devices[4];
   test_device_simple_read_write simple_read_write;
   test_device_gpio_nxp_pca9535 gpio_nxp_pca9535;
   test_device_eeprom eeprom;
+  test_device_switch_nxp_pca9548a switch_nxp_pca9548a;
 } test_bus;
 
 static const char bus_path[] = "/dev/i2c-0";
@@ -87,6 +96,9 @@ static const char gpio_nxp_pca9535_path[] = "/dev/i2c-0.gpio-nxp-pc9535-0";
 
 static const char eeprom_path[] = "/dev/i2c-0.eeprom-0";
 
+static const char switch_nxp_pca9548a_path[] =
+  "/dev/i2c-0.switch-nxp-pca9548a-0";
+
 static void cyclic_inc(unsigned *val, unsigned cycle)
 {
   unsigned v = *val;
@@ -217,6 +229,34 @@ static int test_eeprom_transfer(
   return 0;
 }
 
+static int test_switch_nxp_pca9548a_transfer(
+  i2c_bus *bus,
+  i2c_msg *msgs,
+  uint32_t msg_count,
+  test_device *base
+)
+{
+  test_device_switch_nxp_pca9548a *dev = (test_device_switch_nxp_pca9548a *) base;
+  uint32_t i;
+
+  for (i = 0; i < msg_count; ++i) {
+    i2c_msg *msg = &msgs[i];
+    int j;
+
+    if ((msg->flags & I2C_M_RD) != 0) {
+      for (j = 0; j < msg->len; ++j) {
+        msg->buf[j] = dev->control;
+      }
+    } else {
+      for (j = 0; j < msg->len; ++j) {
+        dev->control = msg->buf[j];
+      }
+    }
+  }
+
+  return 0;
+}
+
 static int test_transfer(i2c_bus *base, i2c_msg *msgs, uint32_t msg_count)
 {
   test_bus *bus = (test_bus *) base;
@@ -438,6 +478,40 @@ static void test_eeprom(void)
   rtems_test_assert(rv == 0);
 }
 
+static void test_switch_nxp_pca9548a(void)
+{
+  int rv;
+  int fd;
+  uint8_t val;
+
+  rv = i2c_dev_register_switch_nxp_pca9548a(
+    &bus_path[0],
+    &switch_nxp_pca9548a_path[0],
+    DEVICE_SWITCH_NXP_PCA9548A
+  );
+  rtems_test_assert(rv == 0);
+
+  fd = open(&switch_nxp_pca9548a_path[0], O_RDWR);
+  rtems_test_assert(fd >= 0);
+
+  rv = switch_nxp_pca9548a_get_control(fd, &val);
+  rtems_test_assert(rv == 0);
+  rtems_test_assert(val == 0);
+
+  rv = switch_nxp_pca9548a_set_control(fd, 0xa5);
+  rtems_test_assert(rv == 0);
+
+  rv = switch_nxp_pca9548a_get_control(fd, &val);
+  rtems_test_assert(rv == 0);
+  rtems_test_assert(val == 0xa5);
+
+  rv = close(fd);
+  rtems_test_assert(rv == 0);
+
+  rv = unlink(&switch_nxp_pca9548a_path[0]);
+  rtems_test_assert(rv == 0);
+}
+
 static void test(void)
 {
   rtems_resource_snapshot snapshot;
@@ -465,6 +539,9 @@ static void test(void)
   bus->gpio_nxp_pca9535.base.transfer = test_gpio_nxp_pca9535_transfer;
   bus->devices[2] = &bus->gpio_nxp_pca9535.base;
 
+  bus->switch_nxp_pca9548a.base.transfer = test_switch_nxp_pca9548a_transfer;
+  bus->devices[3] = &bus->switch_nxp_pca9548a.base;
+
   rv = i2c_bus_register(&bus->base, &bus_path[0]);
   rtems_test_assert(rv == 0);
 
@@ -533,6 +610,7 @@ static void test(void)
   test_simple_read_write(bus, fd);
   test_eeprom();
   test_gpio_nxp_pca9535();
+  test_switch_nxp_pca9548a();
 
   rv = close(fd);
   rtems_test_assert(rv == 0);



More information about the vc mailing list