[PATCH 5/9] Add NXP PCA9548A 8-channel switch I2C driver
Sebastian Huber
sebastian.huber at embedded-brains.de
Thu Nov 13 09:30:23 UTC 2014
---
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(-)
create mode 100644 cpukit/dev/i2c/switch-nxp-pca9548a.c
create mode 100644 cpukit/dev/include/dev/i2c/switch-nxp-pca9548a.h
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..cc89749
--- /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_DEVICE_IO_CONTROL + 0)
+
+#define SWITCH_NXP_PCA9548A_SET_CONTROL (I2C_DEVICE_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);
--
1.8.4.5
More information about the devel
mailing list