From 3e2d3f845e3330f988ceb5062e78eca545ee5c5b Mon Sep 17 00:00:00 2001 From: dechao_gong Date: Mon, 13 Jul 2026 15:36:17 +0800 Subject: [PATCH] arch/arm/rtl8721dx: add shared Ameba GPIO driver. Add a board-agnostic GPIO driver for Realtek Ameba chips, exposing pins through the NuttX GPIO (ioexpander) upper half at /dev/gpioN. - arch/arm/src/common/ameba/ameba_gpio.{c,h}: the shared driver, sitting directly on the SDK fwlib register layer. The fwlib GPIO API it calls resolves at link time from the on-chip ROM symbol table, except GPIO_INTStatusGet/ClearEdge which are not in ROM and are compiled in from fwlib ram_common/ameba_gpio.c (that object also carries GPIO_Init, harmlessly overriding the equivalent ROM copy). Pin interrupts are dispatched NuttX-natively: the port's NVIC vector is owned by NuttX via irq_attach, and the ISR reads and clears status through the fwlib GPIO_INTStatus* helpers. - The driver keeps nothing IC-specific: the port count, the per-port NVIC vectors and the RCC gate bits come from a per-chip resolved on the include path, so bringing up a new Ameba chip only adds that header, not a change to the shared driver. - arch/arm/src/common/ameba/Kconfig: a shared "Ameba Peripheral Support" menu with the AMEBA_GPIO option, sourced by each Ameba chip's Kconfig so it is reused across ICs (RTL8721Dx, RTL8720F, ...). - arch/arm/src/rtl8721dx: provide ameba_gpio_chip.h, wire the driver into both the Make/Kconfig and CMake builds, and compile the fwlib ameba_gpio.c register layer into libameba_fwlib for the RTL8721Dx. - boards/arm/rtl8721dx/pke8721daf: board pin table (rtl8721dx_gpio.c), bring-up registration, and a standalone gpio defconfig. - Documentation: describe the gpio configuration and pin encoding. tools/nxstyle: whitelist the Ameba "GPIO_" SDK ROM symbol prefix (alongside the existing FLASH_/IPC_/... Ameba prefixes) so the vendor GPIO API's mixed-case identifiers do not trip nxstyle, matching how the other Ameba SDK prefixes are handled. Assisted-by: Claude Code:claude-opus-4-8 Signed-off-by: dechao_gong --- .../arm/rtl8721dx/boards/pke8721daf/index.rst | 20 + arch/arm/src/common/ameba/Kconfig | 25 + arch/arm/src/common/ameba/ameba_gpio.c | 572 ++++++++++++++++++ arch/arm/src/common/ameba/ameba_gpio.h | 93 +++ arch/arm/src/rtl8721dx/CMakeLists.txt | 10 + arch/arm/src/rtl8721dx/Kconfig | 5 + arch/arm/src/rtl8721dx/Make.defs | 4 + arch/arm/src/rtl8721dx/ameba_board.mk | 12 + arch/arm/src/rtl8721dx/ameba_gpio_chip.h | 70 +++ .../pke8721daf/configs/gpio/defconfig | 51 ++ .../rtl8721dx/pke8721daf/src/CMakeLists.txt | 11 + boards/arm/rtl8721dx/pke8721daf/src/Makefile | 9 + .../pke8721daf/src/rtl8721dx_bringup.c | 10 + .../rtl8721dx/pke8721daf/src/rtl8721dx_gpio.c | 98 +++ .../pke8721daf/src/rtl8721dx_pke8721daf.h | 13 + tools/nxstyle.c | 1 + 16 files changed, 1004 insertions(+) create mode 100644 arch/arm/src/common/ameba/Kconfig create mode 100644 arch/arm/src/common/ameba/ameba_gpio.c create mode 100644 arch/arm/src/common/ameba/ameba_gpio.h create mode 100644 arch/arm/src/rtl8721dx/ameba_gpio_chip.h create mode 100644 boards/arm/rtl8721dx/pke8721daf/configs/gpio/defconfig create mode 100644 boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_gpio.c diff --git a/Documentation/platforms/arm/rtl8721dx/boards/pke8721daf/index.rst b/Documentation/platforms/arm/rtl8721dx/boards/pke8721daf/index.rst index e0e317b445bd9..0570a3afd925b 100644 --- a/Documentation/platforms/arm/rtl8721dx/boards/pke8721daf/index.rst +++ b/Documentation/platforms/arm/rtl8721dx/boards/pke8721daf/index.rst @@ -33,6 +33,8 @@ Supported in this NuttX port: partition), backing the Wi-Fi key-value store * Wi-Fi station and SoftAP through the ``wapi`` tool * DHCP client (STA) and DHCP server (SoftAP) +* GPIO pins exposed as ``/dev/gpioN`` character devices (input, output and + interrupt), driven directly on the SDK fwlib register layer Buttons and LEDs ================ @@ -58,6 +60,24 @@ The console is the LOG-UART at 1500000 8N1 (the rate is configured by the bootloader and inherited by NuttX). The Wi-Fi examples below are available from this configuration. +gpio +---- + +Minimal NSH with the GPIO driver and the ``gpio`` example enabled (no Wi-Fi). +The board registers three pins from its pin table (see +``boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_gpio.c``): an output at +``/dev/gpio0``, an input at ``/dev/gpio1`` and an interrupt pin at +``/dev/gpio2``. Edit that table to match a board's wiring. Exercise them with +the example:: + + nsh> gpio -o 1 /dev/gpio0 # drive the output high + nsh> gpio /dev/gpio1 # read the input + nsh> gpio -w 1 /dev/gpio2 # wait for a rising-edge interrupt + +Pins are encoded with the ``AMEBA_PA()`` / ``AMEBA_PB()`` helpers from +``arch/arm/src/common/ameba/ameba_gpio.h`` (port A/B, pin 0-31), matching the +Ameba SDK ``PinName`` layout. + Wi-Fi ===== diff --git a/arch/arm/src/common/ameba/Kconfig b/arch/arm/src/common/ameba/Kconfig new file mode 100644 index 0000000000000..30d17d5ca06f2 --- /dev/null +++ b/arch/arm/src/common/ameba/Kconfig @@ -0,0 +1,25 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# +# Shared Realtek Ameba peripheral drivers (arch/arm/src/common/ameba). These +# options are common to every Ameba ARM chip (RTL8721Dx, RTL8720F, ...) and +# are sourced from each chip's own Kconfig. +# + +menu "Ameba Peripheral Support" + +config AMEBA_GPIO + bool "GPIO" + default n + select DEV_GPIO + ---help--- + Expose Ameba GPIO pins through the NuttX GPIO (ioexpander) upper + half at /dev/gpioN. The board selects which pins are registered + and their type (input, output or interrupt) in its bring-up code. + + The driver (arch/arm/src/common/ameba/ameba_gpio.c) sits on the SDK + fwlib register layer and dispatches pin interrupts through the ROM + GPIO interrupt handler. + +endmenu # Ameba Peripheral Support diff --git a/arch/arm/src/common/ameba/ameba_gpio.c b/arch/arm/src/common/ameba/ameba_gpio.c new file mode 100644 index 0000000000000..21e06ea5a1f05 --- /dev/null +++ b/arch/arm/src/common/ameba/ameba_gpio.c @@ -0,0 +1,572 @@ +/**************************************************************************** + * arch/arm/src/common/ameba/ameba_gpio.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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 + ****************************************************************************/ + +/* NuttX GPIO (ioexpander) lower half for the Realtek Ameba GPIO controller. + * + * The pad mux, pull resistors and GPIO port registers are all programmed + * through the SDK fwlib GPIO API (GPIO_Init(), GPIO_WriteBit(), ...). + * + * Most of the API has no SDK source and resolves to the on-chip ROM symbol + * table (GPIO_WriteBit, GPIO_ReadDataBit, GPIO_INTConfig, GPIO_Direction, + * GPIO_INTMode, Pinmux_Config, PAD_PullCtrl, ...). Only GPIO_INTStatusGet + * and GPIO_INTStatusClearEdge are missing from ROM; they live in fwlib + * ram_common/ameba_gpio.c, compiled into libameba_fwlib.a to provide them + * (see AMEBA_FWLIB_SRCS). That same source also defines GPIO_Init (which + * IS in ROM), so the local object overrides the ROM PROVIDE(GPIO_Init) as a + * harmless side effect -- same source, equivalent behaviour. To keep the + * vendor headers out of the NuttX include world, the handful of fwlib + * symbols and the GPIO_InitTypeDef layout used here are declared locally + * below rather than pulled in from . + * + * Interrupt dispatch stays NuttX-native: the port's NVIC vector is owned by + * NuttX (irq_attach), and the ISR reads/clears the controller status through + * the fwlib GPIO_INTStatus* helpers before calling each pending pin's + * registered callback. + */ + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "arm_internal.h" +#include "ameba_gpio.h" + +/* Per-chip GPIO parameters (port count, per-port NVIC vectors, RCC gate + * bits). Resolved from the configured chip's directory on the include path + * (arch/.../chip -> arch/arm/src/); see there. + */ + +#include "ameba_gpio_chip.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Pin encoding (SDK "PinName": port in bits[7:5], pin num in bits[4:0]). */ + +#define AMEBA_PIN_PORT(pin) (((pin) >> 5) & 0x07) +#define AMEBA_PIN_NUM(pin) ((pin) & 0x1f) + +/* Mirror of the fwlib GPIO_InitTypeDef field values (ameba_gpio.h). + * Declared locally so the SDK header need not leak into NuttX includes. + */ + +#define AMEBA_GPIO_MODE_IN 0x0 /* GPIO_Mode_IN */ +#define AMEBA_GPIO_MODE_OUT 0x1 /* GPIO_Mode_OUT */ +#define AMEBA_GPIO_MODE_INT 0x2 /* GPIO_Mode_INT */ + +#define AMEBA_GPIO_PUPD_NONE 0x0 /* GPIO_PuPd_NOPULL */ +#define AMEBA_GPIO_PUPD_DOWN 0x1 /* GPIO_PuPd_DOWN */ +#define AMEBA_GPIO_PUPD_UP 0x2 /* GPIO_PuPd_UP */ + +#define AMEBA_GPIO_IT_LEVEL 0x0 /* GPIO_INT_Trigger_LEVEL */ +#define AMEBA_GPIO_IT_EDGE 0x1 /* GPIO_INT_Trigger_EDGE */ +#define AMEBA_GPIO_IT_BOTHEDGE 0x2 /* GPIO_INT_Trigger_BOTHEDGE */ + +#define AMEBA_GPIO_POL_LOW 0x0 /* GPIO_INT_POLARITY_ACTIVE_LOW */ +#define AMEBA_GPIO_POL_HIGH 0x1 /* GPIO_INT_POLARITY_ACTIVE_HIGH */ + +#define AMEBA_GPIO_DEBOUNCE_OFF 0x0 /* GPIO_INT_DEBOUNCE_DISABLE */ + +/* Second argument to GPIO_INTConfig() / state passed to GPIO_WriteBit(). */ + +#define AMEBA_DISABLE 0x0 +#define AMEBA_ENABLE 0x1 + +/* AMEBA_APBPERIPH_GPIO (the RCC gate bits), AMEBA_GPIO_NPORTS and the + * AMEBA_GPIO_PORT_IRQS vector table come from . The + * fwlib GPIO_Init() leaves the peripheral clock to the caller, so the driver + * gates AMEBA_APBPERIPH_GPIO on before use (RCC touches the LSYS block). + */ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* Layout-compatible mirror of the fwlib GPIO_InitTypeDef (all u32, same + * order); passed by address to GPIO_Init(). + */ + +struct ameba_gpio_init_s +{ + uint32_t mode; /* GPIO_Mode */ + uint32_t pupd; /* GPIO_PuPd */ + uint32_t ittrigger; /* GPIO_ITTrigger */ + uint32_t itpolarity; /* GPIO_ITPolarity */ + uint32_t itdebounce; /* GPIO_ITDebounce */ + uint32_t pin; /* GPIO_Pin */ +}; + +struct ameba_gpio_dev_s +{ + struct gpio_dev_s gpio; /* Lower-half GPIO device (must be first) */ + uint8_t pin; /* SDK pin encoding (port[7:5] | num[4:0]) */ + pin_interrupt_t callback; /* Interrupt callback (interrupt pins only) */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* SDK fwlib GPIO API used by this driver. These are plain extern symbols; + * the driver does not care where each comes from -- every one is resolved + * at link time either by the on-chip ROM symbol table or by a fwlib object + * compiled into libameba_fwlib.a. Which source applies is per-chip: + * + * RCC_PeriphClockCmd, GPIO_Init, GPIO_WriteBit, GPIO_ReadDataBit and + * GPIO_INTConfig are in ROM on every Ameba ARM chip. (GPIO_Init also + * reaches Pinmux_Config, GPIO_Direction, GPIO_INTMode and PAD_PullCtrl + * internally, resolved inside ROM, so the driver never names them.) + * + * GPIO_INTStatusGet and GPIO_INTStatusClearEdge are the gap. On RTL8721Dx + * they come from fwlib ram_common/ameba_gpio.c, compiled in via + * AMEBA_FWLIB_SRCS (that object also carries GPIO_Init and harmlessly + * overrides the ROM copy). On amebalite/amebasmart they are in neither ROM + * nor any SDK source, so a chip adding those parts MUST supply its own + * definition -- a small object writing the port's GPIO_INT_STATUS / + * GPIO_INT_EOI -- via its board build. The shared driver needs no change; + * this is the per-chip contract for these two symbols. + */ + +extern void RCC_PeriphClockCmd(uint32_t periph, uint32_t clock, + uint8_t newstate); +extern void GPIO_Init(struct ameba_gpio_init_s *init); +extern void GPIO_WriteBit(uint32_t pin, uint32_t state); +extern uint32_t GPIO_ReadDataBit(uint32_t pin); +extern void GPIO_INTConfig(uint32_t pin, uint32_t newstate); +extern uint32_t GPIO_INTStatusGet(uint32_t port); +extern void GPIO_INTStatusClearEdge(uint32_t port); + +/* GPIO lower-half operations */ + +static int ameba_gpio_read(struct gpio_dev_s *dev, bool *value); +static int ameba_gpio_write(struct gpio_dev_s *dev, bool value); +static int ameba_gpio_attach(struct gpio_dev_s *dev, + pin_interrupt_t callback); +static int ameba_gpio_enable(struct gpio_dev_s *dev, bool enable); +static int ameba_gpio_setpintype(struct gpio_dev_s *dev, + enum gpio_pintype_e pintype); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct gpio_operations_s g_ameba_gpio_ops = +{ + .go_read = ameba_gpio_read, + .go_write = ameba_gpio_write, + .go_attach = ameba_gpio_attach, + .go_enable = ameba_gpio_enable, + .go_setpintype = ameba_gpio_setpintype, +}; + +/* Driver-wide state, kept in one controller instance instead of + * scattered file-scope globals. A single NVIC vector per port drives + * up to 32 pins, so the dispatch table, the attach flags and the NVIC + * vectors are all per-port, and one spinlock guards the shared table. + */ + +struct ameba_gpio_ctrl_s +{ + /* Per-pin device lookup for interrupt dispatch, indexed [port][pin-num]; + * set once an interrupt pin is registered, read by the port ISR. + */ + + struct ameba_gpio_dev_s *int_dev[AMEBA_GPIO_NPORTS][32]; + + /* Set once a port's NVIC vector has been attached + enabled. */ + + bool port_attached[AMEBA_GPIO_NPORTS]; + + /* Per-port NVIC vector, from the chip's . */ + + const int irq[AMEBA_GPIO_NPORTS]; + + spinlock_t lock; +}; + +static struct ameba_gpio_ctrl_s g_ameba_gpio = +{ + .irq = AMEBA_GPIO_PORT_IRQS, + .lock = SP_UNLOCKED, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ameba_gpio_configure + * + * Description: + * Program the pad mux, direction, pull and (for interrupt pins) trigger + * mode for the given pin type through the fwlib GPIO_Init(). Interrupt + * pins are left masked until the application enables them. + * + ****************************************************************************/ + +static void ameba_gpio_configure(struct ameba_gpio_dev_s *priv, + enum gpio_pintype_e pintype) +{ + struct ameba_gpio_init_s init; + + init.pin = priv->pin; + init.pupd = AMEBA_GPIO_PUPD_NONE; + init.ittrigger = AMEBA_GPIO_IT_EDGE; + init.itpolarity = AMEBA_GPIO_POL_LOW; + init.itdebounce = AMEBA_GPIO_DEBOUNCE_OFF; + + /* Gate on the GPIO peripheral clock (idempotent). */ + + RCC_PeriphClockCmd(AMEBA_APBPERIPH_GPIO, AMEBA_APBPERIPH_GPIO, + AMEBA_ENABLE); + + switch (pintype) + { + case GPIO_OUTPUT_PIN: + case GPIO_OUTPUT_PIN_OPENDRAIN: + init.mode = AMEBA_GPIO_MODE_OUT; + break; + + case GPIO_INPUT_PIN: + init.mode = AMEBA_GPIO_MODE_IN; + break; + + case GPIO_INPUT_PIN_PULLUP: + init.mode = AMEBA_GPIO_MODE_IN; + init.pupd = AMEBA_GPIO_PUPD_UP; + break; + + case GPIO_INPUT_PIN_PULLDOWN: + init.mode = AMEBA_GPIO_MODE_IN; + init.pupd = AMEBA_GPIO_PUPD_DOWN; + break; + + case GPIO_INTERRUPT_HIGH_PIN: + init.mode = AMEBA_GPIO_MODE_INT; + init.ittrigger = AMEBA_GPIO_IT_LEVEL; + init.itpolarity = AMEBA_GPIO_POL_HIGH; + break; + + case GPIO_INTERRUPT_LOW_PIN: + init.mode = AMEBA_GPIO_MODE_INT; + init.ittrigger = AMEBA_GPIO_IT_LEVEL; + init.itpolarity = AMEBA_GPIO_POL_LOW; + break; + + case GPIO_INTERRUPT_RISING_PIN: + init.mode = AMEBA_GPIO_MODE_INT; + init.ittrigger = AMEBA_GPIO_IT_EDGE; + init.itpolarity = AMEBA_GPIO_POL_HIGH; + break; + + case GPIO_INTERRUPT_BOTH_PIN: + init.mode = AMEBA_GPIO_MODE_INT; + init.ittrigger = AMEBA_GPIO_IT_BOTHEDGE; + init.itpolarity = AMEBA_GPIO_POL_LOW; + break; + + case GPIO_INTERRUPT_PIN: + case GPIO_INTERRUPT_FALLING_PIN: + default: + init.mode = AMEBA_GPIO_MODE_INT; + init.ittrigger = AMEBA_GPIO_IT_EDGE; + init.itpolarity = AMEBA_GPIO_POL_LOW; + break; + } + + GPIO_Init(&init); + + /* GPIO_Init() leaves the interrupt source enabled, and setting up the + * trigger can latch a stale edge. While the pin is still unmasked, clear + * that latch, then mask the pin until the application enables it. Order + * matters: GPIO_INTStatusClearEdge() acts through the masked + * GPIO_INT_STATUS, so it clears only a currently-unmasked pin -- + * clearing after masking would miss this pin. The clear+mask pair runs + * under the port lock so the ISR cannot dispatch a stale edge in between; + * clearing the whole port's edge latches is safe during registration, as + * no interrupt pin is application-enabled yet. + */ + + if (init.mode == AMEBA_GPIO_MODE_INT) + { + irqstate_t flags = spin_lock_irqsave(&g_ameba_gpio.lock); + + GPIO_INTStatusClearEdge(AMEBA_PIN_PORT(priv->pin)); + GPIO_INTConfig(priv->pin, AMEBA_DISABLE); + + spin_unlock_irqrestore(&g_ameba_gpio.lock, flags); + } +} + +/**************************************************************************** + * Name: ameba_gpio_interrupt + * + * Description: + * NuttX-native vector for a GPIO port. Reads the (masked) interrupt + * status, clears the edge latches and dispatches to each pending pin's + * registered callback. + * + ****************************************************************************/ + +static int ameba_gpio_interrupt(int irq, void *context, void *arg) +{ + int port = (int)(uintptr_t)arg; + uint32_t status = GPIO_INTStatusGet(port); + + /* Clear the port's edge latches. GPIO_INTStatusClearEdge() re-reads the + * status internally and takes no bitmask, so an edge that arrives between + * the read above and this clear is acknowledged without being dispatched + * this pass -- an inherent limit of the two-call fwlib interface. It is + * harmless for the board's single edge pin, and level-triggered sources + * re-assert and fire again regardless. + */ + + GPIO_INTStatusClearEdge(port); + + while (status != 0) + { + int num = __builtin_ctz(status); + struct ameba_gpio_dev_s *priv = g_ameba_gpio.int_dev[port][num]; + + status &= ~((uint32_t)1 << num); + + if (priv != NULL && priv->callback != NULL) + { + priv->callback(&priv->gpio, num); + } + } + + return OK; +} + +/**************************************************************************** + * Name: ameba_gpio_read + ****************************************************************************/ + +static int ameba_gpio_read(struct gpio_dev_s *dev, bool *value) +{ + struct ameba_gpio_dev_s *priv = (struct ameba_gpio_dev_s *)dev; + + DEBUGASSERT(priv != NULL && value != NULL); + + *value = (GPIO_ReadDataBit(priv->pin) != 0); + return OK; +} + +/**************************************************************************** + * Name: ameba_gpio_write + ****************************************************************************/ + +static int ameba_gpio_write(struct gpio_dev_s *dev, bool value) +{ + struct ameba_gpio_dev_s *priv = (struct ameba_gpio_dev_s *)dev; + + DEBUGASSERT(priv != NULL); + + GPIO_WriteBit(priv->pin, value ? AMEBA_ENABLE : AMEBA_DISABLE); + return OK; +} + +/**************************************************************************** + * Name: ameba_gpio_attach + ****************************************************************************/ + +static int ameba_gpio_attach(struct gpio_dev_s *dev, + pin_interrupt_t callback) +{ + struct ameba_gpio_dev_s *priv = (struct ameba_gpio_dev_s *)dev; + + DEBUGASSERT(priv != NULL); + + /* Mask the interrupt while (re)attaching, then record the callback. */ + + GPIO_INTConfig(priv->pin, AMEBA_DISABLE); + priv->callback = callback; + return OK; +} + +/**************************************************************************** + * Name: ameba_gpio_enable + ****************************************************************************/ + +static int ameba_gpio_enable(struct gpio_dev_s *dev, bool enable) +{ + struct ameba_gpio_dev_s *priv = (struct ameba_gpio_dev_s *)dev; + + DEBUGASSERT(priv != NULL); + + if (enable && priv->callback != NULL) + { + /* Unmask the pin, then drop any stale edge that unmasking just exposed + * (the GPIO_Init arming transient, or an edge latched while masked) so + * the first wait does not fire on a past interrupt. Clearing runs + * with the pin unmasked -- GPIO_INTStatusClearEdge() works through the + * masked GPIO_INT_STATUS -- and the port lock keeps the ISR from + * dispatching that stale edge between the two steps. Level-triggered + * pins do not latch, so a genuinely active level still fires at once. + */ + + irqstate_t flags = spin_lock_irqsave(&g_ameba_gpio.lock); + + GPIO_INTConfig(priv->pin, AMEBA_ENABLE); + GPIO_INTStatusClearEdge(AMEBA_PIN_PORT(priv->pin)); + + spin_unlock_irqrestore(&g_ameba_gpio.lock, flags); + } + else + { + GPIO_INTConfig(priv->pin, AMEBA_DISABLE); + } + + return OK; +} + +/**************************************************************************** + * Name: ameba_gpio_setpintype + ****************************************************************************/ + +static int ameba_gpio_setpintype(struct gpio_dev_s *dev, + enum gpio_pintype_e pintype) +{ + struct ameba_gpio_dev_s *priv = (struct ameba_gpio_dev_s *)dev; + + DEBUGASSERT(priv != NULL); + + if (pintype >= GPIO_NPINTYPES) + { + return -EINVAL; + } + + ameba_gpio_configure(priv, pintype); + dev->gp_pintype = pintype; + return OK; +} + +/**************************************************************************** + * Name: ameba_gpio_port_attach + * + * Description: + * Attach and enable the NuttX-native interrupt vector for the GPIO port + * that owns the given pin (once per port). + * + ****************************************************************************/ + +static void ameba_gpio_port_attach(uint8_t pin) +{ + irqstate_t flags; + int port = AMEBA_PIN_PORT(pin); + + flags = spin_lock_irqsave(&g_ameba_gpio.lock); + + if (!g_ameba_gpio.port_attached[port]) + { + int irq = g_ameba_gpio.irq[port]; + + irq_attach(irq, ameba_gpio_interrupt, (void *)(uintptr_t)port); + up_enable_irq(irq); + g_ameba_gpio.port_attached[port] = true; + } + + spin_unlock_irqrestore(&g_ameba_gpio.lock, flags); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ameba_gpio_register + * + * Description: + * See ameba_gpio.h. + * + ****************************************************************************/ + +int ameba_gpio_register(int minor, uint8_t pin, enum gpio_pintype_e pintype) +{ + struct ameba_gpio_dev_s *priv; + bool interrupt; + int ret; + + if (pintype >= GPIO_NPINTYPES) + { + return -EINVAL; + } + + interrupt = (pintype >= GPIO_INTERRUPT_PIN); + + priv = kmm_zalloc(sizeof(struct ameba_gpio_dev_s)); + if (priv == NULL) + { + return -ENOMEM; + } + + priv->pin = pin; + priv->gpio.gp_pintype = pintype; + priv->gpio.gp_ops = &g_ameba_gpio_ops; + + /* Apply the pad/pin configuration for this pin type. */ + + ameba_gpio_configure(priv, pintype); + + if (interrupt) + { + /* Publish the device for the port ISR and make sure the owning port's + * NuttX vector is live. The pin stays masked until the application + * attaches a callback and enables it. + */ + + g_ameba_gpio.int_dev[AMEBA_PIN_PORT(pin)][AMEBA_PIN_NUM(pin)] = priv; + ameba_gpio_port_attach(pin); + } + + ret = gpio_pin_register(&priv->gpio, minor); + if (ret < 0) + { + gpioerr("ERROR: gpio_pin_register(%d) failed: %d\n", minor, ret); + + if (interrupt) + { + GPIO_INTConfig(pin, AMEBA_DISABLE); + g_ameba_gpio.int_dev[AMEBA_PIN_PORT(pin)][AMEBA_PIN_NUM(pin)] = + NULL; + } + + kmm_free(priv); + } + + return ret; +} diff --git a/arch/arm/src/common/ameba/ameba_gpio.h b/arch/arm/src/common/ameba/ameba_gpio.h new file mode 100644 index 0000000000000..3dc0bd3214739 --- /dev/null +++ b/arch/arm/src/common/ameba/ameba_gpio.h @@ -0,0 +1,93 @@ +/**************************************************************************** + * arch/arm/src/common/ameba/ameba_gpio.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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_ARM_SRC_COMMON_AMEBA_AMEBA_GPIO_H +#define __ARCH_ARM_SRC_COMMON_AMEBA_AMEBA_GPIO_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* A pin is identified with the same encoding the Ameba SDK uses for its + * "PinName": bits[7:5] select the GPIO port and bits[4:0] the pin within + * the port. Boards build their pin table from these helpers so the shared + * driver never needs to know a board's wiring. + */ + +#define AMEBA_PORT_A 0 +#define AMEBA_PORT_B 1 + +#define AMEBA_PIN(port, num) ((uint8_t)(((port) << 5) | ((num) & 0x1f))) + +/* Convenience: the RTL8721Dx / RTL8720F break out ports A and B. */ + +#define AMEBA_PA(num) AMEBA_PIN(AMEBA_PORT_A, (num)) +#define AMEBA_PB(num) AMEBA_PIN(AMEBA_PORT_B, (num)) + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Name: ameba_gpio_register + * + * Description: + * Configure a single Ameba GPIO pin and register it with the NuttX GPIO + * (ioexpander) upper half at /dev/gpioN, where N is the given minor. + * + * Input Parameters: + * minor - The /dev/gpioN minor number. + * pin - The pin, encoded with AMEBA_PIN() / AMEBA_PA() / AMEBA_PB(). + * pintype - One of enum gpio_pintype_e (input, output or one of the + * interrupt pin types). + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int ameba_gpio_register(int minor, uint8_t pin, enum gpio_pintype_e pintype); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* __ARCH_ARM_SRC_COMMON_AMEBA_AMEBA_GPIO_H */ diff --git a/arch/arm/src/rtl8721dx/CMakeLists.txt b/arch/arm/src/rtl8721dx/CMakeLists.txt index 423a80470fef9..7bd0ded54f28e 100644 --- a/arch/arm/src/rtl8721dx/CMakeLists.txt +++ b/arch/arm/src/rtl8721dx/CMakeLists.txt @@ -40,6 +40,10 @@ if(CONFIG_RTL8721DX_FLASH_FS) list(APPEND SRCS ${AMEBA_COMMON}/ameba_flash_mtd.c) endif() +if(CONFIG_AMEBA_GPIO) + list(APPEND SRCS ${AMEBA_COMMON}/ameba_gpio.c) +endif() + target_include_directories(arch PRIVATE ${AMEBA_COMMON}) target_sources(arch PRIVATE ${SRCS}) @@ -90,6 +94,12 @@ if(CONFIG_RTL8721DX_FLASH_FS) list(APPEND AMEBA_FWLIB_SRCS ${AMEBA_SOC}/fwlib/ram_common/ameba_flash_ram.c) endif() +if(CONFIG_AMEBA_GPIO) + # GPIO_INTStatusGet/ClearEdge are not in the ROM symbol table; compile them in + # from the fwlib source (mirrors the make build's ameba_board.mk). + list(APPEND AMEBA_FWLIB_SRCS ${AMEBA_SOC}/fwlib/ram_common/ameba_gpio.c) +endif() + # Silence a couple of warnings the vendored SDK sources trip under NuttX's # warning set, scoped to this fwlib compile only (never relaxing NuttX's own): # -Wno-int-conversion: the SDK passes NULL to irq_register()'s u32 "Data" diff --git a/arch/arm/src/rtl8721dx/Kconfig b/arch/arm/src/rtl8721dx/Kconfig index 64efd1cecab8f..8f3018cbc801c 100644 --- a/arch/arm/src/rtl8721dx/Kconfig +++ b/arch/arm/src/rtl8721dx/Kconfig @@ -82,4 +82,9 @@ config RTL8721DX_FLASH_FS endmenu # RTL8721Dx Storage +# Shared Ameba peripheral drivers (GPIO, ...) live in the common IC-agnostic +# tree and are configured through one Kconfig reused by every Ameba chip. + +source "arch/arm/src/common/ameba/Kconfig" + endif # ARCH_CHIP_RTL8721DX diff --git a/arch/arm/src/rtl8721dx/Make.defs b/arch/arm/src/rtl8721dx/Make.defs index 44a9f2224b048..02c51ef4c12c9 100644 --- a/arch/arm/src/rtl8721dx/Make.defs +++ b/arch/arm/src/rtl8721dx/Make.defs @@ -50,6 +50,10 @@ ifeq ($(CONFIG_RTL8721DX_FLASH_FS),y) CHIP_CSRCS += ameba_flash_mtd.c endif +ifeq ($(CONFIG_AMEBA_GPIO),y) +CHIP_CSRCS += ameba_gpio.c +endif + ############################################################################ # Realtek RTL8721Dx SDK integration # diff --git a/arch/arm/src/rtl8721dx/ameba_board.mk b/arch/arm/src/rtl8721dx/ameba_board.mk index c326add632e43..d7a61fa4a94eb 100644 --- a/arch/arm/src/rtl8721dx/ameba_board.mk +++ b/arch/arm/src/rtl8721dx/ameba_board.mk @@ -116,6 +116,18 @@ AMEBA_FWLIB_SRCS += $(TOPDIR)/arch/arm/src/rtl8721dx/ameba_app_start.c \ ifeq ($(CONFIG_RTL8721DX_FLASH_FS),y) AMEBA_FWLIB_SRCS += $(AMEBA_SOC)/fwlib/ram_common/ameba_flash_ram.c endif +# GPIO register layer. The GPIO driver (arch/.../common/ameba/ameba_gpio.c) +# calls the fwlib GPIO API. GPIO_INTStatusGet/ClearEdge are NOT in the ROM +# symbol table, so fwlib ram_common/ameba_gpio.c is compiled in to provide +# them. That same source also defines GPIO_Init (which IS in ROM), so the +# local object overrides the ROM PROVIDE(GPIO_Init) as a harmless side effect +# (same source, equivalent behaviour). Everything else the driver calls +# (GPIO_WriteBit/ReadDataBit/Direction/INTMode/INTConfig, Pinmux_Config, +# PAD_PullCtrl) has no SDK source and resolves to the ROM symbol table. +ifeq ($(CONFIG_AMEBA_GPIO),y) +AMEBA_FWLIB_SRCS += $(AMEBA_SOC)/fwlib/ram_common/ameba_gpio.c +endif + # -Wno-int-conversion: the vendored SDK passes NULL to irq_register()'s u32 # "Data" (interrupt context) argument in many places -- an intentional # NULL-as-context idiom. Silence -Wint-conversion for the SDK fwlib sources diff --git a/arch/arm/src/rtl8721dx/ameba_gpio_chip.h b/arch/arm/src/rtl8721dx/ameba_gpio_chip.h new file mode 100644 index 0000000000000..280de546489b7 --- /dev/null +++ b/arch/arm/src/rtl8721dx/ameba_gpio_chip.h @@ -0,0 +1,70 @@ +/**************************************************************************** + * arch/arm/src/rtl8721dx/ameba_gpio_chip.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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_ARM_SRC_RTL8721DX_AMEBA_GPIO_CHIP_H +#define __ARCH_ARM_SRC_RTL8721DX_AMEBA_GPIO_CHIP_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Per-chip GPIO parameters for the shared driver + * (arch/arm/src/common/ameba/ameba_gpio.c). The driver logic, pin encoding + * and fwlib API are identical across every Ameba ARM chip, but the port + * count, the per-port NVIC vectors and the RCC gate bits are not. Each chip + * supplies its own on the include path (arch/.../chip); + * the common driver sizes its tables and wires its vectors from the macros + * below, so nothing IC-specific is left in common. + * + * RTL8721Dx (KM4) breaks out two GPIO ports, A and B, each a 32-pin bank + * with its own interrupt vector. + */ + +/* Number of GPIO ports (banks) this chip exposes. */ + +#define AMEBA_GPIO_NPORTS 2 + +/* NVIC vector for each port, as an initialiser indexed by port number + * (0 = A, 1 = B). Its width must match AMEBA_GPIO_NPORTS. + */ + +#define AMEBA_GPIO_PORT_IRQS { RTL8721DX_IRQ_GPIOA, RTL8721DX_IRQ_GPIOB } + +/* APBPeriph_GPIO / APBPeriph_GPIO_CLOCK (sysreg_lsys.h): the peripheral and + * clock bits RCC_PeriphClockCmd() gates for the GPIO block. On RTL8721Dx + * both are ((1 << 30) | (1 << 4)); this value differs on amebasmart, which + * is why it lives here rather than in the shared driver. + */ + +#define AMEBA_APBPERIPH_GPIO (((uint32_t)1 << 30) | ((uint32_t)1 << 4)) + +#endif /* __ARCH_ARM_SRC_RTL8721DX_AMEBA_GPIO_CHIP_H */ diff --git a/boards/arm/rtl8721dx/pke8721daf/configs/gpio/defconfig b/boards/arm/rtl8721dx/pke8721daf/configs/gpio/defconfig new file mode 100644 index 0000000000000..40d05ba350b84 --- /dev/null +++ b/boards/arm/rtl8721dx/pke8721daf/configs/gpio/defconfig @@ -0,0 +1,51 @@ +# +# 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_DEBUG_WARN is not set +CONFIG_AMEBA_GPIO=y +CONFIG_ARCH="arm" +CONFIG_ARCH_BOARD="pke8721daf" +CONFIG_ARCH_BOARD_PKE8721DAF=y +CONFIG_ARCH_CHIP="rtl8721dx" +CONFIG_ARCH_CHIP_RTL8721DX=y +CONFIG_ARCH_INTERRUPTSTACK=2048 +CONFIG_ARCH_STACKDUMP=y +CONFIG_ARMV8M_SYSTICK=y +CONFIG_BUILTIN=y +CONFIG_DEBUG_ASSERTIONS=y +CONFIG_DEBUG_FEATURES=y +CONFIG_DEBUG_FULLOPT=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_DEFAULT_TASK_STACKSIZE=4096 +CONFIG_EXAMPLES_GPIO=y +CONFIG_EXAMPLES_HELLO=y +CONFIG_FS_PROCFS=y +CONFIG_FS_TMPFS=y +CONFIG_IDLETHREAD_STACKSIZE=4096 +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_LIBC_MEMFD_ERROR=y +CONFIG_MM_DEFAULT_ALIGNMENT=32 +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_READLINE=y +CONFIG_PREALLOC_TIMERS=4 +CONFIG_RAM_SIZE=294912 +CONFIG_RAM_START=0x20020000 +CONFIG_RR_INTERVAL=200 +CONFIG_RTL8721DX_FLASH_FS=y +CONFIG_SCHED_HPWORK=y +CONFIG_SCHED_HPWORKPRIORITY=192 +CONFIG_SCHED_LPWORK=y +CONFIG_STACK_COLORATION=y +CONFIG_START_DAY=16 +CONFIG_START_MONTH=6 +CONFIG_START_YEAR=2026 +CONFIG_SYSTEM_NSH=y +CONFIG_SYSTEM_NSH_STACKSIZE=2500 +CONFIG_TIMER=y +CONFIG_TIMER_ARCH=y +CONFIG_USEC_PER_TICK=1000 diff --git a/boards/arm/rtl8721dx/pke8721daf/src/CMakeLists.txt b/boards/arm/rtl8721dx/pke8721daf/src/CMakeLists.txt index 170196b66b9c3..b1cc8e75471eb 100644 --- a/boards/arm/rtl8721dx/pke8721daf/src/CMakeLists.txt +++ b/boards/arm/rtl8721dx/pke8721daf/src/CMakeLists.txt @@ -22,7 +22,18 @@ set(SRCS rtl8721dx_boot.c rtl8721dx_bringup.c) +if(CONFIG_AMEBA_GPIO) + list(APPEND SRCS rtl8721dx_gpio.c) +endif() + target_sources(board PRIVATE ${SRCS}) +if(CONFIG_AMEBA_GPIO) + # The board pin table pulls in the shared driver's public header from + # arch/arm/src/common/ameba/, not on the default board include path. + target_include_directories(board + PRIVATE ${NUTTX_DIR}/arch/arm/src/common/ameba) +endif() + # LD_SCRIPT is not set here: the Ameba image2 linker script is generated # (prebuilt/ld.script.gen) and published by the shared ameba_board.cmake. diff --git a/boards/arm/rtl8721dx/pke8721daf/src/Makefile b/boards/arm/rtl8721dx/pke8721daf/src/Makefile index 957c553ddbec6..be0c63a792d8e 100644 --- a/boards/arm/rtl8721dx/pke8721daf/src/Makefile +++ b/boards/arm/rtl8721dx/pke8721daf/src/Makefile @@ -24,4 +24,13 @@ include $(TOPDIR)/Make.defs CSRCS = rtl8721dx_boot.c rtl8721dx_bringup.c +ifeq ($(CONFIG_AMEBA_GPIO),y) +CSRCS += rtl8721dx_gpio.c + +# The board pin table pulls in the shared driver's public header from +# arch/arm/src/common/ameba/, which is not on the default board include path. + +CFLAGS += ${INCDIR_PREFIX}$(TOPDIR)$(DELIM)arch$(DELIM)arm$(DELIM)src$(DELIM)common$(DELIM)ameba +endif + include $(TOPDIR)/boards/Board.mk diff --git a/boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_bringup.c b/boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_bringup.c index e091d1b96fe36..2532afcaf8fb1 100644 --- a/boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_bringup.c +++ b/boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_bringup.c @@ -108,6 +108,16 @@ int rtl8721dx_bringup(void) } #endif +#ifdef CONFIG_AMEBA_GPIO + /* Register the board's GPIO pins at /dev/gpioN. */ + + ret = rtl8721dx_gpio_initialize(); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: rtl8721dx_gpio_initialize failed: %d\n", ret); + } +#endif + /* Install the inter-core HW IPC-semaphore RTOS hooks LAST -- after all the * flash / WHC bring-up above, and just before this (board_late_initialize) * path returns and nx_start() hands off to the init task. diff --git a/boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_gpio.c b/boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_gpio.c new file mode 100644 index 0000000000000..6eb721f158b0d --- /dev/null +++ b/boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_gpio.c @@ -0,0 +1,98 @@ +/**************************************************************************** + * boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_gpio.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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 "ameba_gpio.h" +#include "rtl8721dx_pke8721daf.h" + +#ifdef CONFIG_AMEBA_GPIO + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* One entry per GPIO pin exposed to NuttX. The pins below are examples used + * by the `gpio` (examples/gpio) test -- adjust them to match your board's + * wiring. They are registered in order as /dev/gpio0, /dev/gpio1, ... + */ + +struct rtl8721dx_gpio_s +{ + uint8_t pin; /* AMEBA_PA()/AMEBA_PB() pin encoding */ + enum gpio_pintype_e pintype; /* Input, output or interrupt */ +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct rtl8721dx_gpio_s g_gpio_pins[] = +{ + { AMEBA_PB(18), GPIO_OUTPUT_PIN }, /* /dev/gpio0: output */ + { AMEBA_PB(19), GPIO_INPUT_PIN }, /* /dev/gpio1: input */ + { AMEBA_PB(20), GPIO_INTERRUPT_PIN }, /* /dev/gpio2: interrupt */ +}; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: rtl8721dx_gpio_initialize + * + * Description: + * Register the board's GPIO pins with the NuttX GPIO upper half. + * + ****************************************************************************/ + +int rtl8721dx_gpio_initialize(void) +{ + int ret; + size_t i; + + for (i = 0; i < nitems(g_gpio_pins); i++) + { + ret = ameba_gpio_register(i, g_gpio_pins[i].pin, + g_gpio_pins[i].pintype); + if (ret < 0) + { + syslog(LOG_ERR, + "ERROR: ameba_gpio_register(/dev/gpio%zu) failed: %d\n", + i, ret); + return ret; + } + } + + return OK; +} + +#endif /* CONFIG_AMEBA_GPIO */ diff --git a/boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_pke8721daf.h b/boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_pke8721daf.h index a8f1906edcf7d..85d13543d0e23 100644 --- a/boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_pke8721daf.h +++ b/boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_pke8721daf.h @@ -68,6 +68,19 @@ int rtl8721dx_bringup(void); int rtl8721dx_wifi_initialize(void); #endif +#ifdef CONFIG_AMEBA_GPIO +/**************************************************************************** + * Name: rtl8721dx_gpio_initialize + * + * Description: + * Register the board's GPIO pins with the NuttX GPIO upper half + * (boards/arm/rtl8721dx/pke8721daf/src/rtl8721dx_gpio.c). + * + ****************************************************************************/ + +int rtl8721dx_gpio_initialize(void); +#endif + #ifdef CONFIG_RTL8721DX_FLASH_FS /**************************************************************************** * Name: ameba_flash_fs_initialize diff --git a/tools/nxstyle.c b/tools/nxstyle.c index d0576f0f65598..ae827641677a6 100644 --- a/tools/nxstyle.c +++ b/tools/nxstyle.c @@ -272,6 +272,7 @@ static const char *g_white_prefix[] = "DCache_", "ChipInfo_", "FLASH_", + "GPIO_", "IPC_", "LOGUART_", "OSC2M_",