From 0510cfd8edaa3cf44e7e2ec986b8d8be4f319769 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Tue, 11 Nov 2014 12:41:58 +0100 Subject: 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(-) 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 93737f987a..47a158511c 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 0000000000..50e546fd47 --- /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 + * + * + * 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 + +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 0000000000..ce8ef2c809 --- /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 + * + * + * 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 + +#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 28e361b5e5..f73107b209 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 e6f2eb3437..20059afd14 100644 --- a/testsuites/libtests/i2c01/init.c +++ b/testsuites/libtests/i2c01/init.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -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; @@ -72,13 +75,19 @@ typedef struct { uint8_t data[EEPROM_SIZE]; } 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); -- cgit v1.2.3