diff --git a/Documentation/platforms/sim/index.rst b/Documentation/platforms/sim/index.rst index 84adbf17c8a3f..26642be6dbd06 100644 --- a/Documentation/platforms/sim/index.rst +++ b/Documentation/platforms/sim/index.rst @@ -15,3 +15,4 @@ The following Simulator/Emulators are supported: network_linux network_vpnkit sim_gpiochip + sim_ft2232h_gpio diff --git a/Documentation/platforms/sim/sim_ft2232h_gpio.rst b/Documentation/platforms/sim/sim_ft2232h_gpio.rst new file mode 100644 index 0000000000000..7535b3e37e0ff --- /dev/null +++ b/Documentation/platforms/sim/sim_ft2232h_gpio.rst @@ -0,0 +1,210 @@ +======================================= +Sim FT2232 GPIO Driver (Using libftdi1) +======================================= + +Overview +======== + +The NuttX simulation (sim) already has a GPIO Chip driver that provides a mechanism use GPIO to control external devices. However that solution depends on having a driver to Linux side and that adds more overhead. + +This FT2232H driver allows a direct use of libftdi1 to control up to 8 GPIOs. + +This driver is particularly useful for: + +- Testing GPIO-based applications in a simulated environment with real hardware +- Interfacing with USB-to-GPIO adapters from NuttX simulation +- Developing and debugging GPIO drivers without dedicated embedded hardware + +Host Prepare +============ + +Preparation required on the host side: + +- Hardware module required: FT2232H module like the CJMCU-2232HL module +- A udev rule on Linux side to avoid using the FT2232H as USB/Serial: + +.. code-block:: console + + $ cat /etc/udev/rules.d/99-ft2232h-d2xx.rules + ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6010", ATTRS{product}=="FTDI Device", MODE="0666" + +- The libftdi1-dev installed on your system. + +Architecture +============ + +The driver consists of two layers: + +1. **NuttX Layer** (``sim_ft2232h_ioexpander.c``): Implements the NuttX ``ioexpander_dev_s`` + interface, providing standard GPIO operations to upper-layer NuttX drivers. + +2. **Host Layer** (``sim_ft2232h.c``): Interfaces directly with libftdio1 to initialize and to provide the functions to control the GPIOs. + +.. uml:: + + @startuml + skinparam componentStyle rectangle + skinparam defaultFontName Monospaced + + [NuttX Application] as app + [GPIO Lower Half\n(gpio_lower_half)] as gpio + [sim_ft2232h_ioexpander.c\n(ioexpander_dev_s)] as ioex + note right of ioex : NuttX ioexpander interface + [sim_ft2232h.c\n(host interface)] as sim + note right of sim : Linux host GPIO interface + [libftdi1] as ftdi + note right of ftdi : Linux library to control FT2232H + + app --> gpio + gpio --> ioex + ioex --> sim + sim --> ftdi + @enduml + +Header Files +============ + +- ``arch/sim/src/sim/sim_ft2232h_ioexpander.h``: Host GPIO chip interface definitions and function prototypes. + +- ``include/nuttx/ioexpander/ioexpander.h``: Standard NuttX IO expander interface. + +- ``include/nuttx/ioexpander/gpio.h``: NuttX GPIO interface definitions. + +Configuration Options +===================== + +The following configuration options are relevant to this driver: + +- ``CONFIG_SIM_FT2232H``: Enable the FT2232H driver support. +- ``CONFIG_SIM_FT2232H_GPIO``: Enable the sim GPIO chip driver. + +Supported Operations +==================== + +The driver supports the following GPIO operations: + +Direction Control +----------------- + +.. code-block:: c + + int sim_ft2232h_gpio_direction(struct ioexpander_dev_s *dev, + uint8_t pin, int direction); + +Set GPIO pin direction. Supported directions: + +- ``IOEXPANDER_DIRECTION_IN``: Configure as input +- ``IOEXPANDER_DIRECTION_OUT``: Configure as output +- ``IOEXPANDER_DIRECTION_OUT_OPENDRAIN``: Configure as open-drain output + +Read/Write Pin +-------------- + +.. code-block:: c + + int sim_ft2232h_gpio_readpin(struct ioexpander_dev_s *dev, uint8_t pin, + bool *value); + int sim_ft2232h_gpio_writepin(struct ioexpander_dev_s *dev, uint8_t pin, + bool value); + +Read or write the value of a GPIO pin. + +Host Layer API +============== + +The host layer (``sim_ft2232h.c``) provides the following functions: + +.. code-block:: c + + /* Allocate and initialize a host GPIO chip device */ + struct host_ft2232h_gpio_dev *host_ft2232h_gpio_alloc(const char *filename); + + /* Free a host GPIO chip device */ + void host_ft2232h_gpio_free(struct host_ft2232h_gpio_dev *dev); + + /* Set GPIO pin direction */ + int host_ft2232h_gpio_direction(struct host_ft2232h_gpio_dev *dev, + uint8_t pin, bool input); + + /* Read GPIO pin value */ + int host_ft2232h_gpio_readpin(struct host_ft2232h_gpio_dev *dev, + uint8_t pin, bool *value); + + /* Write GPIO pin value */ + int host_ft2232h_gpio_writepin(struct host_ft2232h_gpio_dev *dev, + uint8_t pin, bool value); + + /* Request GPIO interrupt */ + int host_ft2232h_gpio_irq_request(struct host_ft2232h_gpio_dev *dev, + uint8_t pin, uint16_t cfgset); + + /* Check if GPIO interrupt is active */ + bool host_ft2232h_gpio_irq_active(struct host_ft2232h_gpio_dev *dev, uint8_t pin); + + /* Get GPIO line information */ + int host_ft2232h_gpio_get_line(struct host_ft2232h_gpio_dev *priv, + uint8_t pin, bool *input); + +Linux Kernel Version Requirements +================================= + +The driver uses Linux GPIO v2 ABI, which requires: + +- **Linux kernel >= 6.8.0**: Full functionality with GPIO v2 API support. +- **Linux kernel < 6.8.0**: The driver compiles but provides stub implementations + that return 0 or NULL. + +Usage Example +============= + +Initialization +-------------- + +Application Usage +----------------- + +After initialization, GPIO pins can be accessed through standard NuttX GPIO interface: + +.. code-block:: c + + #include + #include + #include + + int main(void) + { + int fd; + bool value; + + /* Open GPIO device */ + fd = open("/dev/gpio20", O_RD); + if (fd < 0) + { + return -1; + } + + /* Read GPIO value */ + ioctl(fd, GPIOC_READ, &value); + printf("GPIO value: %d\n", value); + + close(fd); + return 0; + } + +Files +===== + +- ``arch/sim/src/sim/sim_ft2232h_ioexpander.c``: NuttX IO expander implementation +- ``arch/sim/src/sim/posix/sim_ft2232h.c``: Linux host GPIO interface +- ``arch/sim/src/sim/sim_ft2232h_ioxpander.h``: Host GPIO chip header file + +Limitations +=========== + +1. **Polling-based interrupts**: Due to simulation constraints, interrupts are + implemented using polling rather than true hardware interrupts. + +3. **Pin count**: Limited to 8 pins of SYNBB AD0-7. + +4. **Invert option**: The ``IOEXPANDER_OPTION_INVERT`` option is not yet implemented. + diff --git a/arch/sim/Kconfig b/arch/sim/Kconfig index 7ad1e801c28be..d0e7e1f6866ea 100644 --- a/arch/sim/Kconfig +++ b/arch/sim/Kconfig @@ -256,6 +256,43 @@ config SIM_CANDEV_SOCK endif # SIM_CANDEV +config SIM_FT2232H + bool "Support FT2232H USB bridge to control external devices" + default n + depends on ARCH_SIM + ---help--- + It is possible to use a USB FTDI FT2232H to support external + devices connected to the computer. These devices could be GPIO, + I2C or SPI and NuttX on SIM will see it as a real device. + + +if SIM_FT2232H +choice + prompt "FT2232H Mode:" + default SIM_FT2232H_GPIO + +config SIM_FT2232H_SPI + bool "FT2232H as SPI via MPSSE" + depends on SPI + +config SIM_FT2232H_I2C + bool "FT2232H as I2C via MPSSE" + depends on I2C + +config SIM_FT2232H_GPIO + bool "FT2232H as GPIO (ADBUS via SYNCBB)" +endchoice + +config SIM_FT2232H_VID + hex "USB Vendor ID" + default 0x0403 + +config SIM_FT2232H_PID + hex "USB Product ID" + default 0x6010 + +endif # SIM_FT2232H + if SIM_NETDEV choice diff --git a/arch/sim/src/Makefile b/arch/sim/src/Makefile index d3857e52025c9..4068ec9afe112 100644 --- a/arch/sim/src/Makefile +++ b/arch/sim/src/Makefile @@ -186,6 +186,16 @@ ifeq ($(CONFIG_RTC_DRIVER),y) CSRCS += sim_rtc.c endif +ifeq ($(CONFIG_SIM_FT2232H),y) + HOSTSRCS += sim_ft2232h.c + HOSTCFLAGS += $(shell pkg-config --cflags libftdi1) + STDLIBS += $(shell pkg-config --libs libftdi1) + + ifeq ($(CONFIG_SIM_FT2232H_GPIO),y) + CSRCS += sim_ft2232h_ioexpander.c + endif +endif + ifeq ($(CONFIG_SIM_LCDDRIVER),y) CSRCS += sim_lcd.c else ifeq ($(CONFIG_SIM_FRAMEBUFFER),y) diff --git a/arch/sim/src/sim/posix/sim_ft2232h.c b/arch/sim/src/sim/posix/sim_ft2232h.c new file mode 100644 index 0000000000000..1ad647671ab2f --- /dev/null +++ b/arch/sim/src/sim/posix/sim_ft2232h.c @@ -0,0 +1,420 @@ +/**************************************************************************** + * arch/sim/src/sim/posix/sim_ft2232h.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sim_ft2232h_ioexpander.h" +#include "sim_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define gpioerr(fmt, ...) \ + syslog(LOG_ERR, "sim_ft2232h_gpio: " fmt "\n", ##__VA_ARGS__) +#define gpioinfo(fmt, ...) \ + syslog(LOG_ERR, "sim_ft2232h_gpio: " fmt "\n", ##__VA_ARGS__) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: host_ft2232h_gpio_direction + * + * Description: + * Provide ft2232h_gpio pin direction config. + * + * Input Parameters: + * priv - A pointer to instance of Linux ft2232h_gpio. + * pin - The pin number. + * input - The direction of the pin. + * + * Returned Value: + * 0 for success, other for fail. + ****************************************************************************/ + +int host_ft2232h_gpio_direction(struct host_ft2232h_gpio_dev *priv, + uint8_t pin, bool input) +{ + struct ftdi_context *ftdi = priv->ftdi; + uint8_t dir = priv->port_dir; + int ret; + + if (pin >= FT2232_GPIO_NPINS) + { + gpioerr("ERROR: Invalid pin %d config\n", pin); + return -EINVAL; + } + + /* FT2232H uses 1 as output and 0 as input, so invert input first */ + + input = !input; + dir &= ~(input << pin); + dir |= (input << pin); + + if (ftdi_set_bitmode(ftdi, dir, BITMODE_SYNCBB) < 0) + { + gpioerr("Failed to change pin %d direction\n", pin); + return -EIO; + } + + priv->port_dir = dir; + + return 0; +} + +/**************************************************************************** + * Name: host_ft2232h_gpio_irq_request + * + * Input Parameters: + * priv - A pointer to instance of Linux ft2232h_gpio. + * pin - The pin number. + * cfgset - The config set of the pin. + * + * Returned Value: + * 0 for success, other for fail. + ****************************************************************************/ + +int host_ft2232h_gpio_irq_request(struct host_ft2232h_gpio_dev *priv, uint8_t pin, + uint16_t cfg) +{ + struct gpio_v2_line_request req; + int nonblock = 1; + int ret; + + if (priv->line_fd[pin] > 0) + { + close(priv->line_fd[pin]); + priv->line_fd[pin] = -1; + } + + memset(&req, 0, sizeof(req)); + switch (cfg) + { + case GPIOCHIP_LINE_FLAG_FALLING: + req.config.flags = GPIO_V2_LINE_FLAG_EDGE_FALLING; + break; + case GPIOCHIP_LINE_FLAG_RISING: + req.config.flags = GPIO_V2_LINE_FLAG_EDGE_RISING; + break; + case GPIOCHIP_LINE_FLAG_BOTH: + req.config.flags = GPIO_V2_LINE_FLAG_EDGE_FALLING | + GPIO_V2_LINE_FLAG_EDGE_RISING; + break; + default: + req.config.flags = 0; + break; + } + + req.offsets[0] = pin; + req.num_lines = 1; + req.config.flags |= GPIO_V2_LINE_FLAG_INPUT; + if (req.config.flags != GPIO_V2_LINE_FLAG_INPUT) + { + snprintf(req.consumer, sizeof(req.consumer) - 1, "gpio-irq%d", pin); + } + + /* Warn only pin 10 can register in ch341A */ + + ret = host_uninterruptible(ioctl, priv->file, GPIO_V2_GET_LINE_IOCTL, + &req); + if (ret < 0) + { + gpioerr("ERROR: ioctl failed: %s \n", strerror(errno)); + return -errno; + } + + ret = host_uninterruptible(ioctl, req.fd, FIONBIO, &nonblock); + if (ret < 0) + { + gpioerr("ERROR: Failed to set non-blocking: %s\n", strerror(errno)); + return -errno; + } + + priv->line_fd[pin] = req.fd; + + return 0; +} + +/**************************************************************************** + * Name: host_ft2232h_gpio_writepin + * + * Description: + * Write ft2232h_gpio pin value. + * + * Input Parameters: + * priv - A pointer to instance of Linux ft2232h_gpio. + * pin - The pin number. + * value - The value write to the pin. + * + * Returned Value: + * 0 for success, other for fail. + ****************************************************************************/ + +int host_ft2232h_gpio_writepin(struct host_ft2232h_gpio_dev *priv, + uint8_t pin, bool value) +{ + struct ftdi_context *ftdi = priv->ftdi; + uint8_t pins = priv->port_value; + int ret; + + if (pin >= FT2232_GPIO_NPINS) + { + gpioerr("ERROR: Invalid pin %d config\n", pin); + return -EINVAL; + } + + pins &= ~(value << pin); + pins |= (value << pin); + ftdi_write_data(ftdi, &pins, 1); + priv->port_value = pins; + + return 0; +} + +/**************************************************************************** + * Name: host_ft2232h_gpio_readpin + * + * Description: + * Read ft2232h_gpio pin value. + * + * Input Parameters: + * priv - A pointer to instance of Linux ft2232h_gpio. + * pin - The pin number. + * value - The value write to the pin. + * + * Returned Value: + * 0 for success, other for fail. + ****************************************************************************/ + +int host_ft2232h_gpio_readpin(struct host_ft2232h_gpio_dev *priv, + uint8_t pin, bool *value) +{ + struct ftdi_context *ftdi = priv->ftdi; + uint8_t pins; + int ret; + + if (pin >= FT2232_GPIO_NPINS) + { + gpioerr("ERROR: Invalid pin %d config\n", pin); + return -EINVAL; + } + + ftdi_read_pins(ftdi, &pins); + priv->port_value = pins; + + *value = !!(pins & (1 << pin)); + + return 0; +} + +/**************************************************************************** + * Name: host_ft2232h_gpio_get_line + * + * Description: + * Get line info from ft2232h_gpio device + * + * Input Parameters: + * priv - A pointer to instance of Linux ft2232h_gpio. + * pin - gpio line of Linux ft2232h_gpio. + * input - A pointer to direction of gpioline. + * + * Returned Value: + * 0 for OK. + * + ****************************************************************************/ + +/**************************************************************************** + * Name: host_ft2232h_gpio_irq_active + * + * Description: + * register gpio for ft2232h_gpio device + * + * Input Parameters: + * priv - A pointer to instance of Linux ft2232h_gpio. + * pin - gpio pin of Linux ft2232h_gpio device. + * + * Returned Value: + * 0 for OK. + * + ****************************************************************************/ + +bool host_ft2232h_gpio_irq_active(struct host_ft2232h_gpio_dev *priv, uint8_t pin) +{ + if (priv->line_fd[pin] > 0) + { + struct gpio_v2_line_event ev; + int fd = priv->line_fd[pin]; + memset(&ev, 0, sizeof(ev)); + if (host_uninterruptible(read, fd, &ev, sizeof(ev)) == sizeof(ev)) + { + return true; + } + } + + return false; +} + +int host_ft2232h_gpio_get_line(struct host_ft2232h_gpio_dev *priv, + uint8_t pin, bool *input) +{ + struct ftdi_context *ftdi = priv->ftdi; + uint8_t dir = priv->port_dir; + int ret; + + if (pin >= FT2232_GPIO_NPINS) + { + gpioerr("ERROR: Invalid pin %d config\n", pin); + return -EINVAL; + } + + /* For FT2232H Input is defined as 0, so we need to invert here */ + + input = !(dir & (1 << pin)); + + return 0; +} + +/**************************************************************************** + * Name: host_ft2232h_gpio_alloc + * + * Description: + * Initialize one ft2232h_gpio device + * + * Input Parameters: + * None + * + * Returned Value: + * The pointer to the instance of Linux ft2232h_gpio device. + * + ****************************************************************************/ + +struct host_ft2232h_gpio_dev *host_ft2232h_gpio_alloc(uint8_t pins_dir) +{ + struct host_ft2232h_gpio_dev *dev; + + dev = malloc(sizeof(struct host_ft2232h_gpio_dev)); + if (!dev) + { + gpioerr("Failed to allocate memory for ft2232h_gpio device"); + return NULL; + } + + dev->ftdi = ftdi_new(); + if (dev->ftdi == NULL) + { + gpioerr("Failed to initialize the new FTDI device!\n"); + free(dev); + return NULL; + } + + /* Interface A controls AD0-AD7 pins on SYNCBB mode */ + + ftdi_set_interface(dev->ftdi, INTERFACE_A); + + /* Open the device */ + + if (ftdi_usb_open(dev->ftdi, CONFIG_SIM_FT2232H_VID, + CONFIG_SIM_FT2232H_PID) < 0) + { + gpioerr("Failed to open the FTDI FT2232H device!\n"); + ftdi_free(dev->ftdi); + free(dev); + return NULL; + } + + /* Reset the Bitmode */ + + ftdi_set_bitmode(dev->ftdi, 0x00, BITMODE_RESET); + + /* Configure SYNCBB mode with the pins direction */ + + if (ftdi_set_bitmode(dev->ftdi, pins_dir, BITMODE_SYNCBB) < 0) + { + gpioerr("Failed to enter SYNCBB mode\n"); + ftdi_usb_close(dev->ftdi); + ftdi_free(dev->ftdi); + free(dev); + return NULL; + } + + /* Save the current pins direction */ + + dev->port_dir = pins_dir; + dev->port_value = 0x00; + + /* Clear any previous residual buffers before start */ + + ftdi_usb_purge_buffers(dev->ftdi); + + return dev; +} + +/**************************************************************************** + * Name: host_ft2232h_gpio_free + * + * Description: + * Uninitialize an ft2232h_gpio device + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void host_ft2232h_gpio_free(struct host_ft2232h_gpio_dev *priv) +{ + ftdi_set_bitmode(priv->ftdi, 0x00, BITMODE_RESET); + ftdi_usb_close(priv->ftdi); + ftdi_free(priv->ftdi); + free(priv); +} + diff --git a/arch/sim/src/sim/sim_ft2232h_ioexpander.c b/arch/sim/src/sim/sim_ft2232h_ioexpander.c new file mode 100644 index 0000000000000..1298abe342eb3 --- /dev/null +++ b/arch/sim/src/sim/sim_ft2232h_ioexpander.c @@ -0,0 +1,500 @@ +/**************************************************************************** + * arch/sim/src/sim/sim_ft2232h_ioexpander.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include "sim_ft2232h_ioexpander.h" +#include "sim_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define SIM_GPIOCHIP_WDOG_DELAY USEC2TICK(500) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct sim_ft2232h_gpio_callback_s +{ + ioe_callback_t cbfunc; + void *cbarg; +}; + +struct sim_ft2232h_gpio_dev_s +{ + const struct ioexpander_ops_s *ops; /* ft2232h_gpio vtable */ + struct sim_ft2232h_gpio_callback_s cb[FT2232_GPIO_NPINS]; + struct host_ft2232h_gpio_dev *dev; +}; + +static struct work_s g_init_work; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int sim_ft2232h_gpio_direction(struct ioexpander_dev_s *dev, + uint8_t pin, int direction); +static int sim_ft2232h_gpio_option(struct ioexpander_dev_s *dev, uint8_t pin, + int option, void *val); +static int sim_ft2232h_gpio_writepin(struct ioexpander_dev_s *dev, + uint8_t pin, bool value); +static int sim_ft2232h_gpio_readpin(struct ioexpander_dev_s *dev, + uint8_t pin, bool *value); + +#ifdef CONFIG_IOEXPANDER_INT_ENABLE +static void *sim_ft2232h_gpio_attach(struct ioexpander_dev_s *dev, + uint16_t pinset, + ioe_callback_t callback, + void *arg); +static int sim_ft2232h_gpio_detach(struct ioexpander_dev_s *dev, + void *handle); +#endif + +static void sim_ft2232h_deferred_init(FAR void *arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct ioexpander_ops_s g_sim_ft2232h_gpio_ops = +{ + .ioe_direction = sim_ft2232h_gpio_direction, + .ioe_option = sim_ft2232h_gpio_option, + .ioe_writepin = sim_ft2232h_gpio_writepin, + .ioe_readpin = sim_ft2232h_gpio_readpin, + .ioe_readbuf = sim_ft2232h_gpio_readpin, +#ifdef CONFIG_IOEXPANDER_INT_ENABLE + .ioe_attach = sim_ft2232h_gpio_attach, + .ioe_detach = sim_ft2232h_gpio_detach, +#endif +}; + +struct ioexpander_dev_s *g_ft2232h_gpio = NULL; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sim_ft2232h_gpio_direction + * + * Description: + * Provide ft2232h_gpio pin direction config. + * + * Input Parameters: + * dev - A pointer to instance of sim ft2232h_gpio device. + * pin - The pin number. + * direction - The direction of the pin. + * + * Returned Value: + * 0 for success, other for fail. + ****************************************************************************/ + +static int sim_ft2232h_gpio_direction(struct ioexpander_dev_s *dev, + uint8_t pin, int direction) +{ + struct sim_ft2232h_gpio_dev_s *priv = (struct sim_ft2232h_gpio_dev_s *)dev; + + if (direction == IOEXPANDER_DIRECTION_OUT || + direction == IOEXPANDER_DIRECTION_OUT_OPENDRAIN) + { + return host_ft2232h_gpio_direction(priv->dev, pin, false); + } + else + { + return host_ft2232h_gpio_direction(priv->dev, pin, true); + } +} + +/**************************************************************************** + * Name: sim_ft2232h_gpio_option + * + * Description: + * Provide ft2232h_gpio pin option. + * + * Input Parameters: + * dev - A pointer to instance of sim ft2232h_gpio device. + * pin - The pin number. + * option.- The option type. + * val - A pointer to val of the pin. + * + * Returned Value: + * 0 for success, other for fail. + ****************************************************************************/ + +static int sim_ft2232h_gpio_option(struct ioexpander_dev_s *dev, uint8_t pin, + int option, void *val) +{ + struct sim_ft2232h_gpio_dev_s *priv = (struct sim_ft2232h_gpio_dev_s *)dev; + uint16_t cfgset = 0; + int ret = 0; + + if (option == IOEXPANDER_OPTION_INTCFG) + { + switch ((uintptr_t)val) + { + case IOEXPANDER_VAL_FALLING: + cfgset = GPIOCHIP_LINE_FLAG_FALLING; + break; + + case IOEXPANDER_VAL_RISING: + cfgset = GPIOCHIP_LINE_FLAG_RISING; + break; + + case IOEXPANDER_VAL_BOTH: + cfgset = GPIOCHIP_LINE_FLAG_BOTH; + break; + + case IOEXPANDER_VAL_DISABLE: + cfgset = GPIOCHIP_LINE_FLAG_DISABLE; + break; + + default: + return -ENOTSUP; + } + + ret = host_ft2232h_gpio_irq_request(priv->dev, pin, cfgset); + if (ret < 0) + { + gpioerr("ERROR: Failed to request event: %s\n", strerror(errno)); + } + } + else + { + gpioinfo("ft2232h_gpio io option not support\n"); + return -ENOTSUP; + } + + return ret; +} + +/**************************************************************************** + * Name: sim_ft2232h_gpio_writepin + * + * Description: + * Write ft2232h_gpio pin value. + * + * Input Parameters: + * dev - A pointer to instance of sim ft2232h_gpio device. + * pin - The pin number. + * value - The value write to the pin. + * + * Returned Value: + * 0 for success, other for fail. + ****************************************************************************/ + +static int sim_ft2232h_gpio_writepin(struct ioexpander_dev_s *dev, + uint8_t pin, bool value) +{ + struct sim_ft2232h_gpio_dev_s *priv = (struct sim_ft2232h_gpio_dev_s *)dev; + + return host_ft2232h_gpio_writepin(priv->dev, pin, value); +} + +/**************************************************************************** + * Name: sim_ft2232h_gpio_readpin + * + * Description: + * Read ft2232h_gpio pin value. + * + * Input Parameters: + * dev - A pointer to instance of sim ft2232h_gpio device. + * pin - The pin number. + * value - The value write to the pin. + * + * Returned Value: + * 0 for success, other for fail. + ****************************************************************************/ + +static int sim_ft2232h_gpio_readpin(struct ioexpander_dev_s *dev, + uint8_t pin, bool *value) +{ + struct sim_ft2232h_gpio_dev_s *priv = (struct sim_ft2232h_gpio_dev_s *)dev; + + return host_ft2232h_gpio_readpin(priv->dev, pin, value); +} + +#ifdef CONFIG_IOEXPANDER_INT_ENABLE + +/**************************************************************************** + * Name: sim_ft2232h_gpio_attach + * + * Returned Value: + * 0 for success, other for fail. + ****************************************************************************/ + +static void *sim_ft2232h_gpio_attach(struct ioexpander_dev_s *dev, + ioe_pinset_t pinset, + ioe_callback_t callback, + void *arg) +{ + struct sim_ft2232h_gpio_dev_s *priv = (struct sim_ft2232h_gpio_dev_s *)dev; + void *handle = NULL; + int i; + + for (i = 0; i < CONFIG_IOEXPANDER_NPINS; i++) + { + if (pinset & (1 << i)) + { + priv->cb[i].cbarg = arg; + handle = &priv->cb[i]; + priv->cb[i].cbfunc = callback; + } + } + + return handle; +} + +/**************************************************************************** + * Name: sim_ft2232h_gpio_detach + * + * Returned Value: + * 0 for success, other for fail. + ****************************************************************************/ + +static int sim_ft2232h_gpio_detach(struct ioexpander_dev_s *dev, void *handle) +{ + struct sim_ft2232h_gpio_dev_s *priv = (struct sim_ft2232h_gpio_dev_s *)dev; + struct sim_ft2232h_gpio_callback_s *cb = handle; + + if (priv == NULL || cb == NULL) + { + gpioerr("ERROR: Invalid handle\n"); + return -EINVAL; + } + + cb->cbfunc = NULL; + cb->cbarg = NULL; + return 0; +} +#endif + +/**************************************************************************** + * Name: sim_ft2232h_gpio_register_gpio + * + * Description: + * register gpio for ft2232h_gpio device + * + * Input Parameters: + * priv - A pointer to instance of sim ft2232h_gpio device. + * + * Returned Value: + * 0 for OK. + * + ****************************************************************************/ + +static int +sim_ft2232h_gpio_register_gpio(struct sim_ft2232h_gpio_dev_s *priv) +{ + struct ioexpander_dev_s *ioe = (struct ioexpander_dev_s *)priv; + bool input; + int line; + int ret; + + for (line = 0; line < FT2232_GPIO_NPINS; line++) + { + ret = host_ft2232h_gpio_get_line(priv->dev, line, &input); + if (ret != 0) + { + continue; + } + + if (input) + { + ret = gpio_lower_half(ioe, line, GPIO_INPUT_PIN, + FT2232H_GPIO_LINE_BASE + line); + } + else + { + ret = gpio_lower_half(ioe, line, GPIO_OUTPUT_PIN, + FT2232H_GPIO_LINE_BASE + line); + } + + if (ret < 0) + { + return ret; + } + } + + return 0; +} + +/**************************************************************************** + * Name: sim_ft2232h_gpio_irq_process + * + * Description: + * work to poll irq event for ft2232h_gpio device + * + * Input Parameters: + * priv - A pointer to instance of sim ft2232h_gpio device. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void sim_ft2232h_gpio_irq_process(struct sim_ft2232h_gpio_dev_s *priv) +{ + int line; + + for (line = 0; line < FT2232_GPIO_NPINS; line++) + { + if (host_ft2232h_gpio_irq_active(priv->dev, line)) + { + if (priv->cb[line].cbfunc) + { + priv->cb[line].cbfunc((struct ioexpander_dev_s *)priv, + line, priv->cb[line].cbarg); + } + } + } +} + +/**************************************************************************** + * Name: sim_ft2232h_gpio_interrupt + * + * Description: + * wdog timer function for ft2232h_gpio device + * + * Input Parameters: + * arg - A pointer to instance of sim ft2232h_gpio device. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void sim_ft2232h_gpio_interrupt(wdparm_t arg) +{ + struct sim_ft2232h_gpio_dev_s *priv = (struct sim_ft2232h_gpio_dev_s *)arg; + + if (priv) + { + sim_ft2232h_gpio_irq_process(priv); + + wd_start(&priv->wdog, SIM_GPIOCHIP_WDOG_DELAY, + sim_ft2232h_gpio_interrupt, (wdparm_t)priv); + } +} + +/**************************************************************************** + * Name: sim_ft2232h_deferred_init + * + * Description: + * Worker thread function to register the FT2232H to isolate the board + * bring-up function from ftdio initialization. + * + * Input Parameters: + * arg - A pointer to instance of sim_ft2232h_gpio_dev_s + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void sim_ft2232h_deferred_init(FAR void *arg) +{ + struct sim_ft2232h_gpio_dev_s *priv = arg; + + /* The ftdi calls happen here, safely */ + + sim_ft2232h_gpio_register_gpio(priv); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sim_ft2232h_gpio_initialize + * + * Description: + * Initialize one ft2232h_gpio device + * + * Input Parameters: + * None + * + * Returned Value: + * The pointer to the instance of sim ft2232h_gpio device. + * + ****************************************************************************/ + +int sim_ft2232h_gpio_initialize(uint8_t pins_dir) +{ + struct sim_ft2232h_gpio_dev_s *priv; + int ret; + + priv = kmm_zalloc(sizeof(struct sim_ft2232h_gpio_dev_s)); + if (priv == NULL) + { + gpioerr("Failed to allocate memory for ft2232h_gpio device"); + return -ENOMEM; + } + + priv->ops = &g_sim_ft2232h_gpio_ops; + + priv->dev = host_ft2232h_gpio_alloc(pins_dir); + if (priv->dev == NULL) + { + gpioerr("Failed to init ft2232h_gpio: %d", ret); + kmm_free(priv); + return -ENODEV; + } + + wd_start(&priv->wdog, SIM_GPIOCHIP_WDOG_DELAY, + sim_ft2232h_gpio_interrupt, (wdparm_t)priv); + + g_ft2232h_gpio = (struct ioexpander_dev_s *)priv; + + /* Defer gpio registration to work queue */ + + work_queue(LPWORK, &g_init_work, + sim_ft2232h_deferred_init, priv, 0); + + return 0; +} + +/**************************************************************************** + * Name: sim_ft2232h_gpio_get_ioe + * + * Description: + * Get the ioexpander pointer of ft2232h_gpio device + * + * Input Parameters: + * None. + * + * Returned Value: + * The pointer to the instance of sim ft2232h_gpio device. + * + ****************************************************************************/ + +struct ioexpander_dev_s *sim_ft2232h_gpio_get_ioe(void) +{ + return g_ft2232h_gpio; +} diff --git a/arch/sim/src/sim/sim_ft2232h_ioexpander.h b/arch/sim/src/sim/sim_ft2232h_ioexpander.h new file mode 100644 index 0000000000000..df8e6a4d1a797 --- /dev/null +++ b/arch/sim/src/sim/sim_ft2232h_ioexpander.h @@ -0,0 +1,75 @@ +/**************************************************************************** + * arch/sim/src/sim/sim_ft2232h_ioexpander.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_SIM_SRC_SIM_FT2232H_IOEXPANDER_H +#define __ARCH_SIM_SRC_SIM_FT2232H_IOEXPANDER_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#ifdef __SIM__ +# include "config.h" +#endif + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define FT2232H_GPIO_LINE_BASE 20 +#define FT2232_GPIO_NPINS 8 +#define GPIOCHIP_LINE_FLAG_DISABLE (1 << 0) +#define GPIOCHIP_LINE_FLAG_RISING (1 << 1) +#define GPIOCHIP_LINE_FLAG_FALLING (1 << 2) +#define GPIOCHIP_LINE_FLAG_BOTH (1 << 3) + +/**************************************************************************** + * Type Definitions + ****************************************************************************/ + +struct host_ft2232h_gpio_dev +{ + struct ftdi_context *ftdi; + uint8_t port_dir; + uint8_t port_value; +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +struct host_ft2232h_gpio_dev *host_ft2232h_gpio_alloc(uint8_t pins_dir); +void host_ft2232h_gpio_free(struct host_ft2232h_gpio_dev *dev); +int host_ft2232h_gpio_get_line(struct host_ft2232h_gpio_dev *priv, + uint8_t pin, bool *input); +int host_ft2232h_gpio_readpin(struct host_ft2232h_gpio_dev *dev, + uint8_t line, bool *value); +int host_ft2232h_gpio_writepin(struct host_ft2232h_gpio_dev *dev, + uint8_t pin, bool value); +int host_ft2232h_gpio_direction(struct host_ft2232h_gpio_dev *dev, + uint8_t pin, bool input); +int host_ft2232h_gpio_irq_request(struct host_ft2232h_gpio_dev *dev, + uint8_t pin, uint16_t cfgset); +bool host_ft2232h_gpio_irq_active(struct host_ft2232h_gpio_dev *dev, + uint8_t pin); +#endif /* __ARCH_SIM_SRC_SIM_FT2232H_IOEXPANDER_H */ diff --git a/arch/sim/src/sim/sim_internal.h b/arch/sim/src/sim/sim_internal.h index 3ca70b65e9421..999b0f497eb19 100644 --- a/arch/sim/src/sim/sim_internal.h +++ b/arch/sim/src/sim/sim_internal.h @@ -507,5 +507,10 @@ int sim_gpiochip_initialize(const char *filename); struct ioexpander_dev_s *sim_gpiochip_get_ioe(void); #endif +#ifdef CONFIG_SIM_FT2232H_GPIO +int sim_ft2232h_gpio_initialize(uint8_t pins_dir); +struct ioexpander_dev_s *sim_ft2232h_gpio_get_ioe(void); +#endif + #endif /* __ASSEMBLY__ */ #endif /* __ARCH_SIM_SRC_SIM_INTERNAL_H */ diff --git a/boards/sim/sim/sim/configs/ft2232h_gpio/defconfig b/boards/sim/sim/sim/configs/ft2232h_gpio/defconfig new file mode 100644 index 0000000000000..b21349e38555b --- /dev/null +++ b/boards/sim/sim/sim/configs/ft2232h_gpio/defconfig @@ -0,0 +1,75 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_NSH_CMDOPT_HEXDUMP is not set +CONFIG_ARCH="sim" +CONFIG_ARCH_BOARD="sim" +CONFIG_ARCH_BOARD_SIM=y +CONFIG_ARCH_CHIP="sim" +CONFIG_ARCH_SIM=y +CONFIG_BOARDCTL_APP_SYMTAB=y +CONFIG_BOARDCTL_POWEROFF=y +CONFIG_BOARD_LOOPSPERMSEC=0 +CONFIG_BOOT_RUNFROMEXTSRAM=y +CONFIG_BUILTIN=y +CONFIG_COVERAGE_ALL=y +CONFIG_COVERAGE_TOOLCHAIN=y +CONFIG_DEBUG_ASSERTIONS=y +CONFIG_DEBUG_ASSERTIONS_EXPRESSION=y +CONFIG_DEBUG_FEATURES=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_DEV_GPIO=y +CONFIG_DEV_LOOP=y +CONFIG_ETC_FATDEVNO=2 +CONFIG_ETC_ROMFS=y +CONFIG_ETC_ROMFSDEVNO=1 +CONFIG_EXAMPLES_GPIO=y +CONFIG_EXAMPLES_HELLO=y +CONFIG_FAT_LCNAMES=y +CONFIG_FAT_LFN=y +CONFIG_FS_BINFS=y +CONFIG_FS_FAT=y +CONFIG_FS_HOSTFS=y +CONFIG_FS_PROCFS=y +CONFIG_FS_RAMMAP=y +CONFIG_FS_ROMFS=y +CONFIG_GPIO_LOWER_HALF=y +CONFIG_HAVE_CXXINITIALIZE=y +CONFIG_IDLETHREAD_STACKSIZE=4096 +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_IOEXPANDER=y +CONFIG_IOEXPANDER_DUMMY=y +CONFIG_LIBC_ENVPATH=y +CONFIG_LIBC_EXECFUNCS=y +CONFIG_LIBC_LOCALE=y +CONFIG_LIBC_LOCALE_CATALOG=y +CONFIG_LIBC_LOCALE_GETTEXT=y +CONFIG_LIBC_MAX_EXITFUNS=1 +CONFIG_LIBC_NUMBERED_ARGS=y +CONFIG_NDEBUG=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FILE_APPS=y +CONFIG_NSH_READLINE=y +CONFIG_PATH_INITIAL="/bin" +CONFIG_PIPES=y +CONFIG_PSEUDOFS_ATTRIBUTES=y +CONFIG_PSEUDOFS_FILE=y +CONFIG_PSEUDOFS_SOFTLINKS=y +CONFIG_READLINE_TABCOMPLETION=y +CONFIG_SCHED_BACKTRACE=y +CONFIG_SCHED_EVENTS=y +CONFIG_SCHED_HAVE_PARENT=y +CONFIG_SCHED_WAITPID=y +CONFIG_SIM_FT2232H=y +CONFIG_SIM_HOSTFS=y +CONFIG_SIM_WALLTIME_SIGNAL=y +CONFIG_START_MONTH=6 +CONFIG_START_YEAR=2008 +CONFIG_SYSTEM_DUMPSTACK=y +CONFIG_SYSTEM_GCOV=y +CONFIG_SYSTEM_NSH=y +CONFIG_TESTING_OSTEST=y diff --git a/boards/sim/sim/sim/src/sim_bringup.c b/boards/sim/sim/sim/src/sim_bringup.c index c839d22333220..44756100ecb52 100644 --- a/boards/sim/sim/sim/src/sim_bringup.c +++ b/boards/sim/sim/sim/src/sim_bringup.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -122,6 +123,20 @@ int sim_bringup(void) #endif int ret = OK; +#ifdef CONFIG_SIM_FT2232H_GPIO + /* Initialize the FT2232H GPIO device + * pass a parameter defining which pins will be input (0) and + * which will be output (1). + * 0xf0 = AD0-AD3: Input; AD4-AD7: Output. + */ + + ret = sim_ft2232h_gpio_initialize(0xf0); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: Failed to initialize FT2232H: %d\n", ret); + } +#endif + #ifdef CONFIG_FS_BINFS /* Mount the binfs file system */