sim/gpiochip: add sim gpiochip for gpio autotest

add sim gpiochip driver

Signed-off-by: yezhonghui <yezhonghui@xiaomi.com>
This commit is contained in:
yezhonghui
2025-04-02 09:49:34 +08:00
committed by Alan C. Assis
parent e072356182
commit 36f91643ae
9 changed files with 1299 additions and 0 deletions
+1
View File
@@ -14,3 +14,4 @@ The following Simulator/Emulators are supported:
*/*
network_linux
network_vpnkit
sim_gpiochip
@@ -0,0 +1,308 @@
======================================
Sim GPIO Chip Driver (Linux Host GPIO)
======================================
Overview
========
The Sim GPIO Chip driver provides a mechanism for NuttX simulation (sim) to access
the Linux host's GPIO chip devices (``/dev/gpiochipN``). This allows NuttX applications
running in simulation mode to interact with real hardware GPIO pins connected to the
Linux host system.
This driver is particularly useful for:
- Testing GPIO-based applications in a simulated environment with real hardware
- Interfacing with USB-to-GPIO adapters (e.g., CH341A) from NuttX simulation
- Developing and debugging GPIO drivers without dedicated embedded hardware
Host Prepare
============
Preparation required on the host side:
- Hardware module required: USB-CH341A module
- Refer to https://github.com/frank-zago/ch341-i2c-spi-gpio, and install the driver
- Verify existence of /dev/gpiochipN device file
Architecture
============
The driver consists of two layers:
1. **NuttX Layer** (``sim_gpiochip.c``): Implements the NuttX ``ioexpander_dev_s``
interface, providing standard GPIO operations to upper-layer NuttX drivers.
2. **Host Layer** (``sim_linux_gpiochip.c``): Interfaces directly with Linux kernel's
GPIO character device (``/dev/gpiochipN``) using the GPIO v2 ABI.
::
+---------------------+
| NuttX Application |
+---------------------+
|
v
+---------------------+
| GPIO Lower Half |
| (gpio_lower_half) |
+---------------------+
|
v
+---------------------+
| sim_gpiochip.c | <-- NuttX ioexpander interface
| (ioexpander_dev_s) |
+---------------------+
|
v
+---------------------+
| sim_linux_gpiochip.c| <-- Linux host GPIO interface
| (GPIO v2 ABI) |
+---------------------+
|
v
+---------------------+
| /dev/gpiochipN | <-- Linux GPIO character device
+---------------------+
Header Files
============
- ``arch/sim/src/sim/sim_hostgpiochip.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_GPIOCHIP``: Enable the sim GPIO chip driver.
- ``CONFIG_IOEXPANDER_NPINS``: Maximum number of GPIO pins supported (default: 64).
- ``CONFIG_IOEXPANDER_INT_ENABLE``: Enable interrupt support for GPIO pins.
Supported Operations
====================
The driver supports the following GPIO operations:
Direction Control
-----------------
.. code-block:: c
int sim_gpiochip_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_gpiochip_readpin(struct ioexpander_dev_s *dev, uint8_t pin,
bool *value);
int sim_gpiochip_writepin(struct ioexpander_dev_s *dev, uint8_t pin,
bool value);
Read or write the value of a GPIO pin.
Interrupt Configuration
-----------------------
.. code-block:: c
int sim_gpiochip_option(struct ioexpander_dev_s *dev, uint8_t pin,
int option, void *val);
Configure GPIO pin options. Supported interrupt edge configurations:
- ``IOEXPANDER_VAL_RISING``: Trigger on rising edge
- ``IOEXPANDER_VAL_FALLING``: Trigger on falling edge
- ``IOEXPANDER_VAL_BOTH``: Trigger on both edges
- ``IOEXPANDER_VAL_DISABLE``: Disable interrupt
Interrupt Callback
------------------
.. code-block:: c
void *sim_gpiochip_attach(struct ioexpander_dev_s *dev,
ioe_pinset_t pinset,
ioe_callback_t callback,
void *arg);
int sim_gpiochip_detach(struct ioexpander_dev_s *dev, void *handle);
Attach or detach an interrupt callback function for GPIO pins.
Host Layer API
==============
The host layer (``sim_linux_gpiochip.c``) provides the following functions:
.. code-block:: c
/* Allocate and initialize a host GPIO chip device */
struct host_gpiochip_dev *host_gpiochip_alloc(const char *filename);
/* Free a host GPIO chip device */
void host_gpiochip_free(struct host_gpiochip_dev *dev);
/* Set GPIO pin direction */
int host_gpiochip_direction(struct host_gpiochip_dev *dev,
uint8_t pin, bool input);
/* Read GPIO pin value */
int host_gpiochip_readpin(struct host_gpiochip_dev *dev,
uint8_t pin, bool *value);
/* Write GPIO pin value */
int host_gpiochip_writepin(struct host_gpiochip_dev *dev,
uint8_t pin, bool value);
/* Request GPIO interrupt */
int host_gpiochip_irq_request(struct host_gpiochip_dev *dev,
uint8_t pin, uint16_t cfgset);
/* Check if GPIO interrupt is active */
bool host_gpiochip_irq_active(struct host_gpiochip_dev *dev, uint8_t pin);
/* Get GPIO line information */
int host_gpiochip_get_line(struct host_gpiochip_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
--------------
.. code-block:: c
#include <nuttx/ioexpander/gpio.h>
#include "sim_internal.h"
int board_gpio_initialize(void)
{
struct ioexpander_dev_s *ioe;
int ret;
/* Initialize the GPIO chip device */
ioe = sim_gpiochip_initialize("/dev/gpiochip0");
if (ioe == NULL)
{
return -ENODEV;
}
/* Register GPIO pins using gpio_lower_half */
ret = gpio_lower_half(ioe, 0, GPIO_INPUT_PIN, 60); /* Pin 0 as input, minor 60 */
if (ret < 0)
{
return ret;
}
ret = gpio_lower_half(ioe, 1, GPIO_OUTPUT_PIN, 61); /* Pin 1 as output, minor 61 */
if (ret < 0)
{
return ret;
}
return OK;
}
Application Usage
-----------------
After initialization, GPIO pins can be accessed through standard NuttX GPIO interface:
.. code-block:: c
#include <fcntl.h>
#include <sys/ioctl.h>
#include <nuttx/ioexpander/gpio.h>
int main(void)
{
int fd;
bool value;
/* Open GPIO device */
fd = open("/dev/gpio60", O_RDWR);
if (fd < 0)
{
return -1;
}
/* Read GPIO value */
ioctl(fd, GPIOC_READ, &value);
printf("GPIO value: %d\n", value);
close(fd);
return 0;
}
Interrupt Handling
==================
The driver uses a work queue to poll for GPIO events. The polling interval is
defined by ``SIM_GPIOCHIP_WORK_DELAY`` (default: 500 microseconds).
When an interrupt event is detected on a GPIO pin, the registered callback
function is invoked with the pin number and user-provided argument.
.. code-block:: c
static int gpio_interrupt_handler(struct ioexpander_dev_s *dev,
ioe_pinset_t pinset, void *arg)
{
printf("GPIO interrupt on pin %d\n", pinset);
return OK;
}
/* Attach interrupt handler */
void *handle = IOEP_ATTACH(ioe, (1 << pin), gpio_interrupt_handler, NULL);
/* Configure interrupt edge */
IOEP_SETOPTION(ioe, pin, IOEXPANDER_OPTION_INTCFG,
(void *)IOEXPANDER_VAL_RISING);
Files
=====
- ``arch/sim/src/sim/sim_gpiochip.c``: NuttX IO expander implementation
- ``arch/sim/src/sim/posix/sim_linux_gpiochip.c``: Linux host GPIO interface
- ``arch/sim/src/sim/sim_hostgpiochip.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.
2. **Linux kernel version**: Full functionality requires Linux kernel >= 6.8.0.
3. **Pin count**: Limited by ``CONFIG_IOEXPANDER_NPINS`` configuration.
4. **Invert option**: The ``IOEXPANDER_OPTION_INVERT`` option is not yet implemented.
See Also
========
- Linux GPIO documentation: https://www.kernel.org/doc/html/latest/driver-api/gpio/
+32
View File
@@ -661,6 +661,38 @@ config SIM_SPIDEV_NAME
endif
config SIM_GPIOCHIP
bool "Simulated gpiochip"
default n
depends on IOEXPANDER
---help---
Build in support for simulated gpiochip
if SIM_GPIOCHIP
choice
prompt "Simulated GPIOCHIP Type"
default SIM_GPIOCHIP_LINUX
config SIM_GPIOCHIP_LINUX
bool "Linux Gpiochip Character Dev"
depends on HOST_LINUX
---help---
Attach a Linux Gpiochip via the character device
interface. To achieve a SPI port on Linux host, it is
recommended to use a USB<>GPIO device such as CH341A/B.
endchoice
config SIM_GPIOCHIP_NAME
string "the name of host gpiochip dev to attach to simulator"
default "/dev/gpiochip0"
---help---
This is the name of the gpiochip device on the host implementation to
attach to the simulator driver.
endif
menu "Simulated UART"
config SIM_UART_DMA
+5
View File
@@ -246,6 +246,11 @@ ifeq ($(CONFIG_SIM_SPI_LINUX),y)
HOSTSRCS += sim_linuxspi.c
endif
ifeq ($(CONFIG_SIM_GPIOCHIP_LINUX),y)
HOSTSRCS += sim_linux_gpiochip.c
CSRCS += sim_gpiochip.c
endif
ifeq ($(CONFIG_SIM_USB_DEV),y)
CSRCS += sim_usbdev.c
ifeq ($(CONFIG_SIM_USB_RAW_GADGET),y)
+5
View File
@@ -249,6 +249,11 @@ if(CONFIG_SIM_SPI_LINUX)
list(APPEND HOSTSRCS sim_linuxspi.c)
endif()
if(CONFIG_SIM_GPIOCHIP_LINUX)
list(APPEND SRCS sim_gpiochip.c)
list(APPEND HOSTSRCS sim_linux_gpiochip.c)
endif()
if(CONFIG_SIM_USB_DEV)
list(APPEND SRCS sim_usbdev.c)
if(CONFIG_SIM_USB_RAW_GADGET)
+419
View File
@@ -0,0 +1,419 @@
/****************************************************************************
* arch/sim/src/sim/posix/sim_linux_gpiochip.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 <sys/types.h>
#include <sys/ioctl.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/const.h>
#include <linux/ioctl.h>
#include <linux/types.h>
#include <linux/gpio.h>
#include "sim_gpiochip.h"
#include "sim_internal.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define gpioerr(fmt, ...) \
syslog(LOG_ERR, "sim_linux_gpiochip: " fmt "\n", ##__VA_ARGS__)
#define gpioinfo(fmt, ...) \
syslog(LOG_ERR, "sim_linux_gpiochip: " fmt "\n", ##__VA_ARGS__)
/****************************************************************************
* Private Types
****************************************************************************/
/****************************************************************************
* Private Data
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: host_gpiochip_direction
*
* Description:
* Provide gpiochip pin direction config.
*
* Input Parameters:
* priv - A pointer to instance of Linux gpiochip.
* pin - The pin number.
* input - The direction of the pin.
*
* Returned Value:
* 0 for success, other for fail.
****************************************************************************/
int host_gpiochip_direction(struct host_gpiochip_dev *priv, uint8_t pin,
bool input)
{
struct gpio_v2_line_request req;
int nonblock = 1;
int ret;
memset(&req, 0, sizeof(req));
req.num_lines = 1;
req.offsets[0] = pin;
if (priv->line_fd[pin] > 0)
{
close(priv->line_fd[pin]);
priv->line_fd[pin] = -1;
}
if (input)
{
req.config.flags = GPIO_V2_LINE_FLAG_INPUT;
}
else
{
req.config.flags = GPIO_V2_LINE_FLAG_OUTPUT;
}
snprintf(req.consumer, sizeof(req.consumer) - 1, "gpio%d", pin);
ret = host_uninterruptible(ioctl, priv->file, GPIO_V2_GET_LINE_IOCTL,
&req);
if (ret < 0)
{
gpioerr("ERROR: pin %d set direction failed\n", pin);
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_gpiochip_irq_request
*
* Input Parameters:
* priv - A pointer to instance of Linux gpiochip.
* pin - The pin number.
* cfgset - The config set of the pin.
*
* Returned Value:
* 0 for success, other for fail.
****************************************************************************/
int host_gpiochip_irq_request(struct host_gpiochip_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_gpiochip_writepin
*
* Description:
* Write gpiochip pin value.
*
* Input Parameters:
* priv - A pointer to instance of Linux gpiochip.
* pin - The pin number.
* value - The value write to the pin.
*
* Returned Value:
* 0 for success, other for fail.
****************************************************************************/
int host_gpiochip_writepin(struct host_gpiochip_dev *priv, uint8_t pin,
bool value)
{
struct gpio_v2_line_values vals;
int ret;
if (priv->line_fd[pin] <= 0)
{
gpioerr("ERROR: Invalid pin %d config\n", pin);
return -EINVAL;
}
memset(&vals, 0, sizeof(vals));
vals.mask = 1;
vals.bits = !!value;
ret = host_uninterruptible(ioctl, priv->line_fd[pin],
GPIO_V2_LINE_SET_VALUES_IOCTL, &vals);
if (ret < 0)
{
gpioerr("ERROR: Failed to set pin %d value %d\n", pin, value);
return -errno;
}
return 0;
}
/****************************************************************************
* Name: host_gpiochip_readpin
*
* Description:
* Read gpiochip pin value.
*
* Input Parameters:
* priv - A pointer to instance of Linux gpiochip.
* pin - The pin number.
* value - The value write to the pin.
*
* Returned Value:
* 0 for success, other for fail.
****************************************************************************/
int host_gpiochip_readpin(struct host_gpiochip_dev *priv, uint8_t pin,
bool *value)
{
struct gpio_v2_line_values vals;
int ret;
if (priv->line_fd[pin] <= 0)
{
gpioerr("ERROR: Invalid pin %d config\n", pin);
return -EINVAL;
}
memset(&vals, 0, sizeof(vals));
vals.mask = 1;
ret = host_uninterruptible(ioctl, priv->line_fd[pin],
GPIO_V2_LINE_GET_VALUES_IOCTL, &vals);
if (ret < 0)
{
gpioerr("ERROR: Failed to get pin%d value, errno[%d]\n", pin, errno);
return -errno;
}
*value = !!(vals.bits & 0x01);
return 0;
}
/****************************************************************************
* Name: host_gpiochip_irq_active
*
* Description:
* register gpio for gpiochip device
*
* Input Parameters:
* priv - A pointer to instance of Linux gpiochip.
* pin - gpio pin of Linux gpiochip device.
*
* Returned Value:
* 0 for OK.
*
****************************************************************************/
bool host_gpiochip_irq_active(struct host_gpiochip_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;
}
/****************************************************************************
* Name: host_gpiochip_get_line
*
* Description:
* Get line info from gpiochip device
*
* Input Parameters:
* priv - A pointer to instance of Linux gpiochip.
* pin - gpio line of Linux gpiochip.
* input - A pointer to direction of gpioline.
*
* Returned Value:
* 0 for OK.
*
****************************************************************************/
int host_gpiochip_get_line(struct host_gpiochip_dev *priv, uint8_t pin,
bool *input)
{
struct gpio_v2_line_info info;
int ret;
memset(&info, 0, sizeof(info));
info.offset = pin;
ret = host_uninterruptible(ioctl, priv->file, GPIO_V2_GET_LINEINFO_IOCTL,
&info);
if (ret < 0)
{
gpioerr("Failed to get line info: %d", ret);
return -errno;
}
if (info.flags & GPIO_V2_LINE_FLAG_USED)
{
return 1;
}
if (info.flags & GPIO_V2_LINE_FLAG_OUTPUT)
{
*input = false;
}
else
{
*input = true;
}
return 0;
}
/****************************************************************************
* Name: host_gpiochip_alloc
*
* Description:
* Initialize one gpiochip device
*
* Input Parameters:
* filename - the name of gpiochip device in Linux, e.g. "/dev/gpiochipN".
*
* Returned Value:
* The pointer to the instance of Linux gpiochip device.
*
****************************************************************************/
struct host_gpiochip_dev *host_gpiochip_alloc(const char *filename)
{
struct host_gpiochip_dev *dev;
dev = malloc(sizeof(struct host_gpiochip_dev));
if (!dev)
{
gpioerr("Failed to allocate memory for gpiochip device");
return NULL;
}
dev->file = host_uninterruptible(open, filename, O_RDWR | O_CLOEXEC);
if (dev->file < 0)
{
gpioerr("Failed to open %s: %d", filename, dev->file);
free(dev);
return NULL;
}
return dev;
}
/****************************************************************************
* Name: host_gpiochip_free
*
* Description:
* Uninitialize an gpiochip device
*
* Returned Value:
* None.
*
****************************************************************************/
void host_gpiochip_free(struct host_gpiochip_dev *priv)
{
host_uninterruptible(close, priv->file);
free(priv);
}
+454
View File
@@ -0,0 +1,454 @@
/****************************************************************************
* arch/sim/src/sim/sim_gpiochip.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 <debug.h>
#include <nuttx/wdog.h>
#include <nuttx/ioexpander/gpio.h>
#include <nuttx/ioexpander/ioexpander.h>
#include "sim_gpiochip.h"
#include "sim_internal.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define GPIOCHIP_LINE_BASE 60
#define SIM_GPIOCHIP_WDOG_DELAY USEC2TICK(500)
/****************************************************************************
* Private Types
****************************************************************************/
struct sim_gpiochip_callback_s
{
ioe_callback_t cbfunc;
void *cbarg;
};
struct sim_gpiochip_dev_s
{
const struct ioexpander_ops_s *ops; /* gpiochip vtable */
struct sim_gpiochip_callback_s cb[CONFIG_IOEXPANDER_NPINS];
struct host_gpiochip_dev *dev;
struct wdog_s wdog; /* poll work */
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static int sim_gpiochip_direction(struct ioexpander_dev_s *dev,
uint8_t pin, int direction);
static int sim_gpiochip_option(struct ioexpander_dev_s *dev, uint8_t pin,
int option, void *val);
static int sim_gpiochip_writepin(struct ioexpander_dev_s *dev, uint8_t pin,
bool value);
static int sim_gpiochip_readpin(struct ioexpander_dev_s *dev, uint8_t pin,
bool *value);
#ifdef CONFIG_IOEXPANDER_INT_ENABLE
static void *sim_gpiochip_attach(struct ioexpander_dev_s *dev,
uint16_t pinset,
ioe_callback_t callback,
void *arg);
static int sim_gpiochip_detach(struct ioexpander_dev_s *dev,
void *handle);
#endif
/****************************************************************************
* Private Data
****************************************************************************/
static struct ioexpander_ops_s g_sim_gpiochip_ops =
{
.ioe_direction = sim_gpiochip_direction,
.ioe_option = sim_gpiochip_option,
.ioe_writepin = sim_gpiochip_writepin,
.ioe_readpin = sim_gpiochip_readpin,
.ioe_readbuf = sim_gpiochip_readpin,
#ifdef CONFIG_IOEXPANDER_INT_ENABLE
.ioe_attach = sim_gpiochip_attach,
.ioe_detach = sim_gpiochip_detach,
#endif
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: sim_gpiochip_direction
*
* Description:
* Provide gpiochip pin direction config.
*
* Input Parameters:
* dev - A pointer to instance of sim gpiochip device.
* pin - The pin number.
* direction - The direction of the pin.
*
* Returned Value:
* 0 for success, other for fail.
****************************************************************************/
static int sim_gpiochip_direction(struct ioexpander_dev_s *dev,
uint8_t pin, int direction)
{
struct sim_gpiochip_dev_s *priv = (struct sim_gpiochip_dev_s *)dev;
if (direction == IOEXPANDER_DIRECTION_OUT ||
direction == IOEXPANDER_DIRECTION_OUT_OPENDRAIN)
{
return host_gpiochip_direction(priv->dev, pin, false);
}
else
{
return host_gpiochip_direction(priv->dev, pin, true);
}
}
/****************************************************************************
* Name: sim_gpiochip_option
*
* Description:
* Provide gpiochip pin option.
*
* Input Parameters:
* dev - A pointer to instance of sim gpiochip 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_gpiochip_option(struct ioexpander_dev_s *dev, uint8_t pin,
int option, void *val)
{
struct sim_gpiochip_dev_s *priv = (struct sim_gpiochip_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_gpiochip_irq_request(priv->dev, pin, cfgset);
if (ret < 0)
{
gpioerr("ERROR: Failed to request event: %s\n", strerror(errno));
}
}
else
{
gpioinfo("gpiochip io option not support\n");
return -ENOTSUP;
}
return ret;
}
/****************************************************************************
* Name: sim_gpiochip_writepin
*
* Description:
* Write gpiochip pin value.
*
* Input Parameters:
* dev - A pointer to instance of sim gpiochip device.
* pin - The pin number.
* value - The value write to the pin.
*
* Returned Value:
* 0 for success, other for fail.
****************************************************************************/
static int sim_gpiochip_writepin(struct ioexpander_dev_s *dev, uint8_t pin,
bool value)
{
struct sim_gpiochip_dev_s *priv = (struct sim_gpiochip_dev_s *)dev;
return host_gpiochip_writepin(priv->dev, pin, value);
}
/****************************************************************************
* Name: sim_gpiochip_readpin
*
* Description:
* Read gpiochip pin value.
*
* Input Parameters:
* dev - A pointer to instance of sim gpiochip device.
* pin - The pin number.
* value - The value write to the pin.
*
* Returned Value:
* 0 for success, other for fail.
****************************************************************************/
static int sim_gpiochip_readpin(struct ioexpander_dev_s *dev, uint8_t pin,
bool *value)
{
struct sim_gpiochip_dev_s *priv = (struct sim_gpiochip_dev_s *)dev;
return host_gpiochip_readpin(priv->dev, pin, value);
}
#ifdef CONFIG_IOEXPANDER_INT_ENABLE
/****************************************************************************
* Name: sim_gpiochip_attach
*
* Returned Value:
* 0 for success, other for fail.
****************************************************************************/
static void *sim_gpiochip_attach(struct ioexpander_dev_s *dev,
ioe_pinset_t pinset,
ioe_callback_t callback,
void *arg)
{
struct sim_gpiochip_dev_s *priv = (struct sim_gpiochip_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_gpiochip_detach
*
* Returned Value:
* 0 for success, other for fail.
****************************************************************************/
static int sim_gpiochip_detach(struct ioexpander_dev_s *dev, void *handle)
{
struct sim_gpiochip_dev_s *priv = (struct sim_gpiochip_dev_s *)dev;
struct sim_gpiochip_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_gpiochip_register_gpio
*
* Description:
* register gpio for gpiochip device
*
* Input Parameters:
* priv - A pointer to instance of sim gpiochip device.
*
* Returned Value:
* 0 for OK.
*
****************************************************************************/
static int sim_gpiochip_register_gpio(struct sim_gpiochip_dev_s *priv)
{
struct ioexpander_dev_s *ioe = (struct ioexpander_dev_s *)priv;
bool input;
int line;
int ret;
for (line = 0; line < CONFIG_IOEXPANDER_NPINS; line++)
{
ret = host_gpiochip_get_line(priv->dev, line, &input);
if (ret != 0)
{
continue;
}
if (input)
{
ret = gpio_lower_half(ioe, line, GPIO_INPUT_PIN,
GPIOCHIP_LINE_BASE + line);
}
else
{
ret = gpio_lower_half(ioe, line, GPIO_OUTPUT_PIN,
GPIOCHIP_LINE_BASE + line);
}
if (ret < 0)
{
return ret;
}
}
return 0;
}
/****************************************************************************
* Name: sim_gpiochip_irq_process
*
* Description:
* work to poll irq event for gpiochip device
*
* Input Parameters:
* priv - A pointer to instance of sim gpiochip device.
*
* Returned Value:
* None.
*
****************************************************************************/
static void sim_gpiochip_irq_process(struct sim_gpiochip_dev_s *priv)
{
int line;
for (line = 0; line < CONFIG_IOEXPANDER_NPINS; line++)
{
if (host_gpiochip_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_gpiochip_interrupt
*
* Description:
* wdog timer function for gpiochip device
*
* Input Parameters:
* arg - A pointer to instance of sim gpiochip device.
*
* Returned Value:
* None.
*
****************************************************************************/
static void sim_gpiochip_interrupt(wdparm_t arg)
{
struct sim_gpiochip_dev_s *priv = (struct sim_gpiochip_dev_s *)arg;
if (priv)
{
sim_gpiochip_irq_process(priv);
wd_start(&priv->wdog, SIM_GPIOCHIP_WDOG_DELAY,
sim_gpiochip_interrupt, (wdparm_t)priv);
}
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: sim_gpiochip_initialize
*
* Description:
* Initialize one gpiochip device
*
* Input Parameters:
* path - the name of gpiochip device in sim, e.g. "/dev/gpiochipN".
*
* Returned Value:
* The pointer to the instance of sim gpiochip device.
*
****************************************************************************/
int sim_gpiochip_initialize(const char *path)
{
struct sim_gpiochip_dev_s *priv;
int ret;
priv = kmm_zalloc(sizeof(struct sim_gpiochip_dev_s));
if (priv == NULL)
{
gpioerr("Failed to allocate memory for gpiochip device");
return -ENOMEM;
}
priv->ops = &g_sim_gpiochip_ops;
priv->dev = host_gpiochip_alloc(path);
if (priv->dev == NULL)
{
gpioerr("Failed to init gpiochip: %d", ret);
kmm_free(priv);
return -ENODEV;
}
ret = sim_gpiochip_register_gpio(priv);
if (ret < 0)
{
gpioerr("Failed to register gpio: %d", ret);
host_gpiochip_free(priv->dev);
kmm_free(priv);
return ret;
}
wd_start(&priv->wdog, SIM_GPIOCHIP_WDOG_DELAY,
sim_gpiochip_interrupt, (wdparm_t)priv);
return 0;
}
+71
View File
@@ -0,0 +1,71 @@
/****************************************************************************
* arch/sim/src/sim/sim_gpiochip.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_GPIOCHIP_H
#define __ARCH_SIM_SRC_SIM_GPIOCHIP_H
/****************************************************************************
* Included Files
****************************************************************************/
#ifdef __SIM__
# include "config.h"
#endif
#include <stdint.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#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_gpiochip_dev
{
int file;
int line_fd[CONFIG_IOEXPANDER_NPINS];
};
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
struct host_gpiochip_dev *host_gpiochip_alloc(const char *filename);
void host_gpiochip_free(struct host_gpiochip_dev *dev);
int host_gpiochip_get_line(struct host_gpiochip_dev *priv, uint8_t pin,
bool *input);
int host_gpiochip_readpin(struct host_gpiochip_dev *dev,
uint8_t line, bool *value);
int host_gpiochip_writepin(struct host_gpiochip_dev *dev,
uint8_t pin, bool value);
int host_gpiochip_direction(struct host_gpiochip_dev *dev,
uint8_t pin, bool input);
int host_gpiochip_irq_request(struct host_gpiochip_dev *dev, uint8_t pin,
uint16_t cfgset);
bool host_gpiochip_irq_active(struct host_gpiochip_dev *dev, uint8_t pin);
#endif /* __ARCH_SIM_SRC_SIM_GPIOCHIP_H */
+4
View File
@@ -516,5 +516,9 @@ size_t sim_stack_check(void *alloc, size_t size);
void sim_stack_color(void *stackbase, size_t nbytes);
#endif
#ifdef CONFIG_SIM_GPIOCHIP
int sim_gpiochip_initialize(const char *filename);
#endif
#endif /* __ASSEMBLY__ */
#endif /* __ARCH_SIM_SRC_SIM_INTERNAL_H */