mirror of
https://github.com/apache/nuttx.git
synced 2026-06-02 17:48:54 +08:00
sim/gpiochip: add sim gpiochip for gpio autotest
add sim gpiochip driver Signed-off-by: yezhonghui <yezhonghui@xiaomi.com>
This commit is contained in:
committed by
Alan C. Assis
parent
e072356182
commit
36f91643ae
@@ -14,3 +14,4 @@ The following Simulator/Emulators are supported:
|
|||||||
*/*
|
*/*
|
||||||
network_linux
|
network_linux
|
||||||
network_vpnkit
|
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/
|
||||||
@@ -661,6 +661,38 @@ config SIM_SPIDEV_NAME
|
|||||||
|
|
||||||
endif
|
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"
|
menu "Simulated UART"
|
||||||
|
|
||||||
config SIM_UART_DMA
|
config SIM_UART_DMA
|
||||||
|
|||||||
@@ -246,6 +246,11 @@ ifeq ($(CONFIG_SIM_SPI_LINUX),y)
|
|||||||
HOSTSRCS += sim_linuxspi.c
|
HOSTSRCS += sim_linuxspi.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_SIM_GPIOCHIP_LINUX),y)
|
||||||
|
HOSTSRCS += sim_linux_gpiochip.c
|
||||||
|
CSRCS += sim_gpiochip.c
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(CONFIG_SIM_USB_DEV),y)
|
ifeq ($(CONFIG_SIM_USB_DEV),y)
|
||||||
CSRCS += sim_usbdev.c
|
CSRCS += sim_usbdev.c
|
||||||
ifeq ($(CONFIG_SIM_USB_RAW_GADGET),y)
|
ifeq ($(CONFIG_SIM_USB_RAW_GADGET),y)
|
||||||
|
|||||||
@@ -249,6 +249,11 @@ if(CONFIG_SIM_SPI_LINUX)
|
|||||||
list(APPEND HOSTSRCS sim_linuxspi.c)
|
list(APPEND HOSTSRCS sim_linuxspi.c)
|
||||||
endif()
|
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)
|
if(CONFIG_SIM_USB_DEV)
|
||||||
list(APPEND SRCS sim_usbdev.c)
|
list(APPEND SRCS sim_usbdev.c)
|
||||||
if(CONFIG_SIM_USB_RAW_GADGET)
|
if(CONFIG_SIM_USB_RAW_GADGET)
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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 */
|
||||||
@@ -516,5 +516,9 @@ size_t sim_stack_check(void *alloc, size_t size);
|
|||||||
void sim_stack_color(void *stackbase, size_t nbytes);
|
void sim_stack_color(void *stackbase, size_t nbytes);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_SIM_GPIOCHIP
|
||||||
|
int sim_gpiochip_initialize(const char *filename);
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* __ASSEMBLY__ */
|
#endif /* __ASSEMBLY__ */
|
||||||
#endif /* __ARCH_SIM_SRC_SIM_INTERNAL_H */
|
#endif /* __ARCH_SIM_SRC_SIM_INTERNAL_H */
|
||||||
|
|||||||
Reference in New Issue
Block a user