Add NXP PCA9548A 8-channel switch I2C driver

This commit is contained in:
Sebastian Huber
2014-11-11 12:41:58 +01:00
parent 67ac69fc3f
commit 0510cfd8ed
5 changed files with 252 additions and 1 deletions

View File

@@ -9,6 +9,7 @@ include_dev_i2c_HEADERS =
include_dev_i2c_HEADERS += include/dev/i2c/eeprom.h 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/gpio-nxp-pca9535.h
include_dev_i2c_HEADERS += include/dev/i2c/i2c.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_linuxdir = $(includedir)/linux
include_linux_HEADERS = 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/gpio-nxp-pca9535.c
libdev_a_SOURCES += i2c/i2c-bus.c libdev_a_SOURCES += i2c/i2c-bus.c
libdev_a_SOURCES += i2c/i2c-dev.c libdev_a_SOURCES += i2c/i2c-dev.c
libdev_a_SOURCES += i2c/switch-nxp-pca9548a.c
include $(srcdir)/preinstall.am include $(srcdir)/preinstall.am
include $(top_srcdir)/automake/local.am include $(top_srcdir)/automake/local.am

View File

@@ -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@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);
}

View File

@@ -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@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 */

View File

@@ -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 $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/dev/i2c/i2c.h
PREINSTALL_FILES += $(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): $(PROJECT_INCLUDE)/linux/$(dirstamp):
@$(MKDIR_P) $(PROJECT_INCLUDE)/linux @$(MKDIR_P) $(PROJECT_INCLUDE)/linux
@: > $(PROJECT_INCLUDE)/linux/$(dirstamp) @: > $(PROJECT_INCLUDE)/linux/$(dirstamp)

View File

@@ -19,6 +19,7 @@
#include <dev/i2c/i2c.h> #include <dev/i2c/i2c.h>
#include <dev/i2c/eeprom.h> #include <dev/i2c/eeprom.h>
#include <dev/i2c/gpio-nxp-pca9535.h> #include <dev/i2c/gpio-nxp-pca9535.h>
#include <dev/i2c/switch-nxp-pca9548a.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/stat.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_GPIO_NXP_PCA9535 (2UL << SPARE_ADDRESS_BITS)
#define DEVICE_SWITCH_NXP_PCA9548A (3UL << SPARE_ADDRESS_BITS)
#define EEPROM_SIZE 512 #define EEPROM_SIZE 512
typedef struct test_device test_device; typedef struct test_device test_device;
@@ -72,13 +75,19 @@ typedef struct {
uint8_t data[EEPROM_SIZE]; uint8_t data[EEPROM_SIZE];
} test_device_eeprom; } test_device_eeprom;
typedef struct {
test_device base;
uint8_t control;
} test_device_switch_nxp_pca9548a;
typedef struct { typedef struct {
i2c_bus base; i2c_bus base;
unsigned long clock; unsigned long clock;
test_device *devices[3]; test_device *devices[4];
test_device_simple_read_write simple_read_write; test_device_simple_read_write simple_read_write;
test_device_gpio_nxp_pca9535 gpio_nxp_pca9535; test_device_gpio_nxp_pca9535 gpio_nxp_pca9535;
test_device_eeprom eeprom; test_device_eeprom eeprom;
test_device_switch_nxp_pca9548a switch_nxp_pca9548a;
} test_bus; } test_bus;
static const char bus_path[] = "/dev/i2c-0"; 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 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) static void cyclic_inc(unsigned *val, unsigned cycle)
{ {
unsigned v = *val; unsigned v = *val;
@@ -217,6 +229,34 @@ static int test_eeprom_transfer(
return 0; 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) static int test_transfer(i2c_bus *base, i2c_msg *msgs, uint32_t msg_count)
{ {
test_bus *bus = (test_bus *) base; test_bus *bus = (test_bus *) base;
@@ -438,6 +478,40 @@ static void test_eeprom(void)
rtems_test_assert(rv == 0); 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) static void test(void)
{ {
rtems_resource_snapshot snapshot; rtems_resource_snapshot snapshot;
@@ -465,6 +539,9 @@ static void test(void)
bus->gpio_nxp_pca9535.base.transfer = test_gpio_nxp_pca9535_transfer; bus->gpio_nxp_pca9535.base.transfer = test_gpio_nxp_pca9535_transfer;
bus->devices[2] = &bus->gpio_nxp_pca9535.base; 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]); rv = i2c_bus_register(&bus->base, &bus_path[0]);
rtems_test_assert(rv == 0); rtems_test_assert(rv == 0);
@@ -533,6 +610,7 @@ static void test(void)
test_simple_read_write(bus, fd); test_simple_read_write(bus, fd);
test_eeprom(); test_eeprom();
test_gpio_nxp_pca9535(); test_gpio_nxp_pca9535();
test_switch_nxp_pca9548a();
rv = close(fd); rv = close(fd);
rtems_test_assert(rv == 0); rtems_test_assert(rv == 0);