This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit eea880f1acbfd6ea90e39ac166d9ef025052eafa
Author: Marco Casaroli <[email protected]>
AuthorDate: Sat Jul 25 12:36:03 2026 +0200

    boards/arm/rp23xx: Add support for the Pimoroni Pico Plus 2 W.
    
    The Pimoroni Pico Plus 2 W is a Pico form-factor board built around the
    RP2350B, the 80-pin part with 48 GPIOs, carrying 16MB of flash, 8MB of PSRAM
    and a Raspberry Pi RM2 module for 2.4GHz WiFi.  The RM2 houses an Infineon
    CYW43439, wired to the same pins the Raspberry Pi Pico W uses: GPIO 23 for
    power enable, 24 for the shared gSPI data and interrupt line, 25 for chip
    select and 29 for the clock.
    
    Three configurations are provided: nsh and usbnsh without the wireless chip,
    and wifi, which brings up wlan0 in station mode with WAPI, a DHCP client and
    ping.  The CYW43439 firmware and CLM blob are linked in from the pico-sdk at
    build time, as on the Pico W; CONFIG_CYW43439_FIRMWARE_BIN_PATH selects the
    file and the board documentation covers converting it out of the C header 
that
    pico-sdk 2.x ships in place of the binary.  rp23xx_firmware.c is placed in 
the
    common source directory so that a future board with the same chip can reuse
    it, and unlike rp2040 the blob is staged for the CMake build as well.
    
    Two board details are worth calling out:
    
      - The only LED is wired to GPIO 0 of the CYW43439 rather than to a pin of
        the RP2350, so driving it means an iovar request over the gSPI bus.  
That
        works for CONFIG_USERLED but not for CONFIG_ARCH_LEDS, whose
        board_autoled_on() is called from interrupt handlers and from assertion
        handling, so a build selecting CONFIG_ARCH_LEDS is rejected with an
        explicit message.  The LED also only responds once wlan0 has been 
brought
        up, because that is when the chip's firmware is downloaded.
    
      - The BOOT button is also wired to GPIO 45, so it can be read as an 
ordinary
        user button once NuttX is running.  Its internal pull-up is enabled
        deliberately: erratum RP2350-E9 means a floating Bank 0 input on RP2350 
A2
        leaks enough current to settle around 2.2V, which the internal pull-down
        cannot overcome.
    
    Tested on the board with a Raspberry Pi Debug Probe: nsh and wifi boot on
    UART0, wlan0 reports the MAC read from the chip, wapi scan lists access
    points, and association to a WPA2 network followed by DHCP gives a working
    route with ping succeeding to both a literal address and a resolved name.
    The LED and the BOOT button were confirmed by hand.
    
    Assisted-by: Claude Code:claude-opus-5
    Signed-off-by: Marco Casaroli <[email protected]>
---
 .../rp23xx/boards/pimoroni-pico-plus-2-w/index.rst | 276 ++++++++++++++
 .../pimoroni-pico-plus-2-w.jpg                     | Bin 0 -> 451575 bytes
 boards/Kconfig                                     |  21 ++
 boards/arm/rp23xx/common/src/CMakeLists.txt        |  32 ++
 boards/arm/rp23xx/common/src/Make.defs             |   7 +
 boards/arm/rp23xx/common/src/rp23xx_firmware.c     | 164 +++++++++
 .../rp23xx/pimoroni-pico-plus-2-w/CMakeLists.txt   |  40 +++
 boards/arm/rp23xx/pimoroni-pico-plus-2-w/Kconfig   |  54 +++
 .../pimoroni-pico-plus-2-w/configs/nsh/defconfig   |  48 +++
 .../configs/usbnsh/defconfig                       |  52 +++
 .../pimoroni-pico-plus-2-w/configs/wifi/defconfig  |  89 +++++
 .../rp23xx/pimoroni-pico-plus-2-w/include/board.h  | 154 ++++++++
 .../include/rp23xx_extra_gpio.h                    | 139 ++++++++
 .../pimoroni-pico-plus-2-w/include/rp23xx_i2cdev.h |  72 ++++
 .../pimoroni-pico-plus-2-w/include/rp23xx_i2sdev.h |  72 ++++
 .../pimoroni-pico-plus-2-w/include/rp23xx_spidev.h |  69 ++++
 .../pimoroni-pico-plus-2-w/include/rp23xx_spisd.h  |  85 +++++
 .../pimoroni-pico-plus-2-w/scripts/Make.defs       |  43 +++
 .../scripts/memmap_copy_to_ram.ld                  | 340 ++++++++++++++++++
 .../scripts/memmap_default.ld                      | 353 ++++++++++++++++++
 .../scripts/memmap_no_flash.ld                     | 294 +++++++++++++++
 .../pimoroni-pico-plus-2-w/src/CMakeLists.txt      |  66 ++++
 .../rp23xx/pimoroni-pico-plus-2-w/src/Make.defs    |  95 +++++
 .../src/rp23xx_boardinitialize.c                   | 115 ++++++
 .../pimoroni-pico-plus-2-w/src/rp23xx_bringup.c    | 132 +++++++
 .../pimoroni-pico-plus-2-w/src/rp23xx_buttons.c    | 187 ++++++++++
 .../pimoroni-pico-plus-2-w/src/rp23xx_gpio.c       | 396 +++++++++++++++++++++
 .../pimoroni-pico-plus-2-w/src/rp23xx_pico.h       |  69 ++++
 .../pimoroni-pico-plus-2-w/src/rp23xx_userleds.c   |  94 +++++
 29 files changed, 3558 insertions(+)

diff --git 
a/Documentation/platforms/arm/rp23xx/boards/pimoroni-pico-plus-2-w/index.rst 
b/Documentation/platforms/arm/rp23xx/boards/pimoroni-pico-plus-2-w/index.rst
new file mode 100644
index 00000000000..28eb3e74a99
--- /dev/null
+++ b/Documentation/platforms/arm/rp23xx/boards/pimoroni-pico-plus-2-w/index.rst
@@ -0,0 +1,276 @@
+======================
+Pimoroni Pico Plus 2 W
+======================
+
+.. tags:: chip:rp2350, chip:rp2350b, wifi
+
+The `Pimoroni Pico Plus 2 W 
<https://shop.pimoroni.com/products/pimoroni-pico-plus-2-w>`_
+is a Raspberry Pi Pico form-factor board built around the RP2350B -- the 80-pin
+variant of the RP2350 with 48 GPIOs.  It adds 16MB of flash, 8MB of PSRAM, a
+USB-C connector, a Qw/ST (Qwiic/STEMMA QT) connector, and an Infineon CYW43439
+for 2.4GHz WiFi and Bluetooth.  The radio is carried on a Raspberry Pi RM2
+module, which is where the CYW43439 lives.
+
+.. figure:: pimoroni-pico-plus-2-w.jpg
+   :align: center
+
+   Pimoroni Pico Plus 2 W, front and back (photo: Pimoroni)
+
+Features
+========
+
+* RP2350B microcontroller chip (QFN-80 package)
+* Dual-core ARM Cortex-M33 processor at up to 150MHz, with FPU and DSP
+* Also contains two Hazard3 RISC-V cores, selectable instead of the M33 pair
+* 520kB of on-chip SRAM
+* 16MB of on-board QSPI flash
+* 8MB of on-board QSPI PSRAM (chip select on GPIO 47)
+* 48 multi-function GPIO pins, 30 of them on the castellated headers
+* 4x UART, 2x SPI, 2x I2C, 8x 12-bit ADC, 24x PWM channels
+* 12x Programmable IO (PIO) state machines across 3 PIO blocks
+* USB-C, supporting device and host
+* Infineon CYW43439 for 2.4GHz WiFi 4 (802.11n) and Bluetooth 5.2
+* Qw/ST connector on I2C0
+* BOOT and RESET buttons; BOOT is also readable at runtime on GPIO 45
+* Battery connector with charging, and VSYS monitoring on GPIO 43
+
+Serial Console
+==============
+
+By default the serial console is UART0 on GPIO 0 (TX, pin 1) and GPIO 1
+(RX, pin 2), at 115200-8N1.
+
+The board can instead be configured to put the console on the USB-C connector
+(the ``usbnsh`` configuration).  Note that the RP2350 USB device support is
+still marked experimental in NuttX and the CDC/ACM console is known to corrupt
+data and stop responding after a handful of commands.  Prefer the UART console
+for anything that matters.
+
+Wireless Communication
+======================
+
+The on-board Infineon CYW43439 is reached over a half-duplex gSPI bus driven by
+a PIO state machine, implemented in ``arch/arm/src/rp23xx/rp23xx_cyw43439.c``.
+It presents itself as the ``wlan0`` network device and supports 2.4GHz WiFi 4
+(802.11n) in station mode.  Bluetooth is not supported.
+
+The chip's firmware is not downloaded until ``wlan0`` is brought up, so nothing
+on the wireless chip -- including the LED, see below -- responds before that.
+
+CYW43439 firmware
+-----------------
+
+The driver links the wireless chip's firmware and CLM blob into the NuttX
+binary, so a copy has to be available at build time.  
``CONFIG_CYW43439_FIRMWARE_BIN_PATH``
+points at it and defaults to::
+
+  ${PICO_SDK_PATH}/lib/cyw43-driver/firmware/43439A0-7.95.49.00.combined
+
+This is the WiFi firmware padded up to a 256-byte boundary with the CLM blob
+appended, and ``CONFIG_CYW43439_FIRMWARE_LEN`` is the *unpadded* length of just
+the firmware part (224190 bytes for this release).
+
+pico-sdk 2.x no longer ships that file as a binary -- it only carries the same
+bytes as a C array in 
``lib/cyw43-driver/firmware/w43439A0_7_95_49_00_combined.h``.
+If that is all you have, convert the array back to a binary, for example::
+
+  $ python3 -c '
+  import re, sys
+  text = open(sys.argv[1]).read()
+  body = text.split("{", 1)[1].split("};", 1)[0]
+  data = bytes(int(b, 16) for b in re.findall(r"0x([0-9a-fA-F]{2})", body))
+  open(sys.argv[2], "wb").write(data)
+  ' ${PICO_SDK_PATH}/lib/cyw43-driver/firmware/w43439A0_7_95_49_00_combined.h \
+    ${PICO_SDK_PATH}/lib/cyw43-driver/firmware/43439A0-7.95.49.00.combined
+
+The header's own ``CYW43_WIFI_FW_LEN`` and ``CYW43_CLM_LEN`` macros tell you 
the
+lengths to expect: 224190 + 984, in a 225240-byte file.
+
+If the file is missing the build still succeeds, but a placeholder is linked in
+and the wireless chip will not come up.
+
+User LED
+========
+
+**The board's only LED is wired to GPIO 0 of the CYW43439, not to a pin of the
+RP2350.** Setting it therefore means an iovar request over the gSPI bus, which
+has two consequences:
+
+* The LED does not respond until ``wlan0`` has been brought up, because that is
+  when the wireless chip's firmware is downloaded.  Before that, every write
+  fails with ``-EIO``.
+* Driving the LED blocks, so it cannot be done from interrupt context.  That
+  rules out ``CONFIG_ARCH_LEDS``, whose ``board_autoled_on()`` is called from
+  interrupt handlers and from assertion handling.  This board therefore
+  supports ``CONFIG_USERLED`` only, and a build with ``CONFIG_ARCH_LEDS``
+  enabled is rejected with an explicit error.
+
+With ``CONFIG_USERLED`` the LED appears as ``/dev/userleds`` and can be driven
+with the ``leds`` example.  Board code can also reach it, and the CYW43439's
+other two GPIOs, through ``include/rp23xx_extra_gpio.h``:
+
+===== ========= ==============================================================
+GPIO  Direction Function
+===== ========= ==============================================================
+0     output    On-board LED
+1     output    Voltage regulator mode: 1 selects PWM (less ripple) over PFM
+2     input     Non-zero if power is coming from USB or the VBUS pin
+===== ========= ==============================================================
+
+Buttons
+-------
+
+The board has two physical buttons, BOOT and RESET.
+
+BOOT is also wired to GPIO 45, active low, so once NuttX is running it can be
+read as an ordinary user button -- this is the pin pico-sdk calls
+``PIMORONI_PICO_PLUS2_W_USER_SW_PIN``.  It appears as ``/dev/buttons`` with
+``CONFIG_INPUT_BUTTONS``, and is the single button reported by
+``board_buttons()``.  RESET is not readable as a GPIO.
+
+The internal pull-up is enabled on GPIO 45, and must be: erratum RP2350-E9
+means a floating Bank 0 input on RP2350 A2 leaks around 120uA and settles at
+roughly 2.2V, which the internal pull-down is far too weak to overcome.  The
+pull-up is unaffected by the erratum.
+
+Held down while power is applied or while RESET is released, BOOT instead makes
+the RP2350 come up in bootloader mode, where it appears as a storage device 
over
+USB; copying a .UF2 file to it replaces the flash contents.
+
+Pin Mapping
+===========
+
+The castellated headers follow the Raspberry Pi Pico pinout, with the RP2350B's
+extra GPIOs brought out on the two rows of pads inside the headers.
+
+===== ========== =============================================================
+Pin   Signal     Notes
+===== ========== =============================================================
+1     GPIO0      Default TX for UART0 serial console
+2     GPIO1      Default RX for UART0 serial console
+3     Ground
+4     GPIO2
+5     GPIO3
+6     GPIO4      Default SDA for I2C0, also on the Qw/ST connector
+7     GPIO5      Default SCL for I2C0, also on the Qw/ST connector
+8     Ground
+9     GPIO6
+10    GPIO7
+11    GPIO8
+12    GPIO9
+13    Ground
+14    GPIO10
+15    GPIO11
+16    GPIO12
+17    GPIO13
+18    Ground
+19    GPIO14
+20    GPIO15
+21    GPIO16     Default RX for SPI0
+22    GPIO17     Default CSn for SPI0
+23    Ground
+24    GPIO18     Default SCK for SPI0
+25    GPIO19     Default TX for SPI0
+26    GPIO20
+27    GPIO21
+28    Ground
+29    GPIO22
+30    Run
+31    GPIO26     ADC0
+32    GPIO27     ADC1
+33    AGND       Analog ground
+34    GPIO28     ADC2
+35    ADC_VREF   Analog reference voltage
+36    3V3        Power output to peripherals
+37    3V3_EN     Pull to ground to turn off
+38    Ground
+39    VSYS       +5V supply to the board
+40    VBUS       Connected to USB +5V
+===== ========== =============================================================
+
+Other RP2350B Pins
+==================
+
+===== ================================================================
+GPIO  Function
+===== ================================================================
+23    Output - CYW43439 power enable (WL_REG_ON)
+24    I/O    - CYW43439 gSPI data line, doubles as its interrupt request
+25    Output - CYW43439 chip select
+29    Output - CYW43439 gSPI clock
+43    Input  - VSYS monitoring, via ADC
+45    Input  - BOOT button, active low, readable as a user button
+47    Output - PSRAM chip select
+===== ================================================================
+
+Note that GPIO 23, 24, 25 and 29 are the same pins the Raspberry Pi Pico W uses
+for its CYW43439, so the wireless wiring is identical despite the larger
+package.  Do not use them for anything else.
+
+Installation & Build
+====================
+
+For instructions on how to install the build dependencies and create a NuttX
+image for this board, consult the main :doc:`RP23XX documentation 
<../../index>`.
+
+Configurations
+==============
+
+All configurations listed below can be configured using the following command
+in the ``nuttx`` directory (again, consult the main
+:doc:`RP23XX documentation <../../index>`):
+
+.. code:: console
+
+   $ ./tools/configure.sh pimoroni-pico-plus-2-w:<configname>
+
+nsh
+---
+
+Basic NuttShell configuration, console on UART0 at 115200 bps.  The wireless
+chip is not enabled, so this configuration has no network and no LED.
+
+usbnsh
+------
+
+Basic NuttShell configuration with the console on USB CDC/ACM at 115200 bps.
+See the caveat under `Serial Console`_.
+
+wifi
+----
+
+NuttShell configuration with the console on UART0 at 115200 bps and the
+CYW43439 enabled: ``wlan0`` in station mode, WAPI, DHCP client, DNS client and
+``ping``.  ``/dev/userleds`` and ``/dev/buttons`` are registered too.
+
+After loading this configuration, set the country code to match your region in
+:menuselection:`Device Drivers --> Wireless Device Support --> IEEE 802.11 
Device Support`,
+and set your network's credentials in
+:menuselection:`Application Configuration --> Network Utilities --> Network 
initialization --> WAPI Configuration`.
+
+Alternatively, leave the built-in credentials alone and associate at runtime:
+
+.. code:: console
+
+   nsh> wapi mode wlan0 2
+   nsh> wapi psk wlan0 "my-passphrase" 3 2
+   nsh> wapi essid wlan0 my-ssid 1
+   nsh> renew wlan0
+   nsh> ifconfig
+   lo    Link encap:Local Loopback at RUNNING mtu 1518
+      inet addr:127.0.0.1 DRaddr:127.0.0.1 Mask:255.0.0.0
+
+   wlan0    Link encap:Ethernet HWaddr 28:cd:c1:ff:d3:be at RUNNING mtu 576
+      inet addr:192.168.0.118 DRaddr:192.168.0.1 Mask:255.255.255.0
+
+   nsh> ping -c 3 8.8.8.8
+   PING 8.8.8.8 56 bytes of data
+   56 bytes from 8.8.8.8: icmp_seq=0 time=20.0 ms
+   56 bytes from 8.8.8.8: icmp_seq=1 time=10.0 ms
+   56 bytes from 8.8.8.8: icmp_seq=2 time=10.0 ms
+   3 packets transmitted, 3 received, 0% packet loss, time 3030 ms
+   rtt min/avg/max/mdev = 10.000/13.333/20.000/4.714 ms
+
+The ``3`` and ``2`` arguments to ``wapi psk`` select WPA_ALG_CCMP and 
WPA_VER_2;
+run ``wapi help`` for the other values.  ``wapi scan wlan0`` lists the visible
+access points.
diff --git 
a/Documentation/platforms/arm/rp23xx/boards/pimoroni-pico-plus-2-w/pimoroni-pico-plus-2-w.jpg
 
b/Documentation/platforms/arm/rp23xx/boards/pimoroni-pico-plus-2-w/pimoroni-pico-plus-2-w.jpg
new file mode 100644
index 00000000000..8ed9964f5a7
Binary files /dev/null and 
b/Documentation/platforms/arm/rp23xx/boards/pimoroni-pico-plus-2-w/pimoroni-pico-plus-2-w.jpg
 differ
diff --git a/boards/Kconfig b/boards/Kconfig
index 44e9a245bd3..5e58d7b6097 100644
--- a/boards/Kconfig
+++ b/boards/Kconfig
@@ -2266,6 +2266,23 @@ config ARCH_BOARD_PIMORONI_PICO_2_PLUS
        ---help---
                This is a port to the Pimoroni Pico 2 Plus board.
 
+config ARCH_BOARD_PIMORONI_PICO_PLUS_2_W
+       bool "Pimoroni Pico Plus 2 W"
+       depends on ARCH_CHIP_RP23XX
+       select ARCH_HAVE_LEDS
+       select ARCH_HAVE_BUTTONS
+       select ARCH_HAVE_IRQBUTTONS
+       select RP23XX_RP2350B
+       ---help---
+               This is a port to the Pimoroni Pico Plus 2 W board, which adds 
an
+               Infineon CYW43439 WiFi/Bluetooth chip to the Pico Plus 2.
+
+               The board's only LED is wired to a GPIO of the CYW43439 rather 
than
+               to a pin of the RP2350, so driving it means a transaction on 
the gSPI
+               bus.  That works for the CONFIG_USERLED interface but not for
+               CONFIG_ARCH_LEDS, which is called from interrupt context, so
+               CONFIG_ARCH_LEDS is rejected at build time on this board.
+
 config ARCH_BOARD_WAVESHARE_RP2040_LCD_1_28
        bool "Waveshare RP2040 LCD 1.28 board"
        depends on ARCH_CHIP_RP2040
@@ -3936,6 +3953,7 @@ config ARCH_BOARD
        default "raspberrypi-pico-2-rv"        if 
ARCH_BOARD_RASPBERRYPI_PICO_2_RV
        default "xiao-rp2350"                  if ARCH_BOARD_XIAO_RP2350
        default "pimoroni-pico-2-plus"         if 
ARCH_BOARD_PIMORONI_PICO_2_PLUS
+       default "pimoroni-pico-plus-2-w"       if 
ARCH_BOARD_PIMORONI_PICO_PLUS_2_W
        default "w5500-evb-pico"               if ARCH_BOARD_W5500_EVB_PICO
        default "waveshare-rp2040-zero"        if 
ARCH_BOARD_WAVESHARE_RP2040_ZERO
        default "rx65n"                        if ARCH_BOARD_RX65N
@@ -4473,6 +4491,9 @@ endif
 if ARCH_BOARD_PIMORONI_PICO_2_PLUS
 source "boards/arm/rp23xx/pimoroni-pico-2-plus/Kconfig"
 endif
+if ARCH_BOARD_PIMORONI_PICO_PLUS_2_W
+source "boards/arm/rp23xx/pimoroni-pico-plus-2-w/Kconfig"
+endif
 if ARCH_BOARD_ARDUINO_DUE
 source "boards/arm/sam34/arduino-due/Kconfig"
 endif
diff --git a/boards/arm/rp23xx/common/src/CMakeLists.txt 
b/boards/arm/rp23xx/common/src/CMakeLists.txt
index b56fd158592..02fc89626e4 100644
--- a/boards/arm/rp23xx/common/src/CMakeLists.txt
+++ b/boards/arm/rp23xx/common/src/CMakeLists.txt
@@ -110,6 +110,38 @@ if(CONFIG_ARCH_BOARD_COMMON)
     list(APPEND SRCS rp23xx_max6675.c)
   endif()
 
+  # Firmware blob for the Infineon CYW43439 WiFi chip.  rp23xx_firmware.c
+  # .incbin's it, so it has to be staged somewhere on the include path.
+  if(CONFIG_IEEE80211_INFINEON_CYW43439)
+    list(APPEND SRCS rp23xx_firmware.c)
+
+    string(REPLACE "\"" "" CYW43439_FIRMWARE_SRC
+                   "${CONFIG_CYW43439_FIRMWARE_BIN_PATH}")
+    string(CONFIGURE "${CYW43439_FIRMWARE_SRC}" CYW43439_FIRMWARE_SRC)
+
+    set(CYW43439_FIRMWARE 
"${CMAKE_CURRENT_BINARY_DIR}/cyw43439.firmware.image")
+
+    if(EXISTS "${CYW43439_FIRMWARE_SRC}")
+      configure_file("${CYW43439_FIRMWARE_SRC}" "${CYW43439_FIRMWARE}" 
COPYONLY)
+    else()
+      # NuttX built with this dummy will not talk to the wireless chip.  It 
only
+      # exists so that a tree without a pico-sdk checkout still compiles.
+      message(
+        WARNING "cyw43439 firmware not found at ${CYW43439_FIRMWARE_SRC}; "
+                "the wireless chip will not work.  See the board Kconfig 
help.")
+      file(WRITE "${CYW43439_FIRMWARE}" "dummy\n")
+    endif()
+
+    set_property(
+      SOURCE rp23xx_firmware.c
+      APPEND
+      PROPERTY INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}")
+    set_property(
+      SOURCE rp23xx_firmware.c
+      APPEND
+      PROPERTY OBJECT_DEPENDS "${CYW43439_FIRMWARE}")
+  endif()
+
 endif()
 target_sources(board PRIVATE ${SRCS})
 target_compile_options(board PRIVATE ${RP23XXFLAGS})
diff --git a/boards/arm/rp23xx/common/src/Make.defs 
b/boards/arm/rp23xx/common/src/Make.defs
index 52b1244b533..d400a49268c 100644
--- a/boards/arm/rp23xx/common/src/Make.defs
+++ b/boards/arm/rp23xx/common/src/Make.defs
@@ -110,6 +110,13 @@ ifeq ($(CONFIG_SENSORS_MAX6675),y)
  CSRCS += rp23xx_max6675.c
 endif
 
+# Firmware blob for the Infineon CYW43439 WiFi chip.  The board that carries
+# the chip stages the blob itself, see its src/Make.defs.
+
+ifeq ($(CONFIG_IEEE80211_INFINEON_CYW43439),y)
+ CSRCS += rp23xx_firmware.c
+endif
+
 DEPPATH += --dep-path src
 VPATH += :src
 CFLAGS += 
${INCDIR_PREFIX}$(TOPDIR)$(DELIM)arch$(DELIM)$(CONFIG_ARCH)$(DELIM)src$(DELIM)board$(DELIM)src
diff --git a/boards/arm/rp23xx/common/src/rp23xx_firmware.c 
b/boards/arm/rp23xx/common/src/rp23xx_firmware.c
new file mode 100644
index 00000000000..5a8b242d0a0
--- /dev/null
+++ b/boards/arm/rp23xx/common/src/rp23xx_firmware.c
@@ -0,0 +1,164 @@
+/****************************************************************************
+ * boards/arm/rp23xx/common/src/rp23xx_firmware.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 <nuttx/config.h>
+#include <stdint.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define _STR(x) #x
+#define STR(x) _STR(x)
+
+#define ROUNDED_FIRMWARE_LEN ((CONFIG_CYW43439_FIRMWARE_LEN + 0xff) & ~0xff)
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#ifdef CONFIG_IEEE80211_INFINEON_CYW43439
+
+/****************************************************************************
+ * Character array of NVRAM image
+ * Generated from cyw943439wlpth_rev1_0.txt
+ * $ Copyright Broadcom Corporation $
+ ****************************************************************************/
+
+const uint8_t g_cyw43439_nvram_image[] __attribute__((aligned(4))) =
+        "NVRAMRev=$Rev$"                         "\x00"
+        "manfid=0x2d0"                           "\x00"
+        "prodid=0x0727"                          "\x00"
+        "vendid=0x14e4"                          "\x00"
+        "devid=0x43e2"                           "\x00"
+        "boardtype=0x0887"                       "\x00"
+        "boardrev=0x1100"                        "\x00"
+        "boardnum=22"                            "\x00"
+        "macaddr=00:A0:50:b5:59:5e"              "\x00"
+        "sromrev=11"                             "\x00"
+        "boardflags=0x00404001"                  "\x00"
+        "boardflags3=0x04000000"                 "\x00"
+        "xtalfreq=37400"                         "\x00"
+        "nocrc=1"                                "\x00"
+        "ag0=255"                                "\x00"
+        "aa2g=1"                                 "\x00"
+        "ccode=ALL"                              "\x00"
+        "pa0itssit=0x20"                         "\x00"
+        "extpagain2g=0"                          "\x00"
+        "pa2ga0=-168,6649,-778"                  "\x00"
+        "AvVmid_c0=0x0,0xc8"                     "\x00"
+        "cckpwroffset0=5"                        "\x00"
+        "maxp2ga0=84"                            "\x00"
+        "txpwrbckof=6"                           "\x00"
+        "cckbw202gpo=0"                          "\x00"
+        "legofdmbw202gpo=0x66111111"             "\x00"
+        "mcsbw202gpo=0x77711111"                 "\x00"
+        "propbw202gpo=0xdd"                      "\x00"
+        "ofdmdigfilttype=18"                     "\x00"
+        "ofdmdigfilttypebe=18"                   "\x00"
+        "papdmode=1"                             "\x00"
+        "papdvalidtest=1"                        "\x00"
+        "pacalidx2g=45"                          "\x00"
+        "papdepsoffset=-30"                      "\x00"
+        "papdendidx=58"                          "\x00"
+        "ltecxmux=0"                             "\x00"
+        "ltecxpadnum=0x0102"                     "\x00"
+        "ltecxfnsel=0x44"                        "\x00"
+        "ltecxgcigpio=0x01"                      "\x00"
+        "il0macaddr=00:90:4c:c5:12:38"           "\x00"
+        "wl0id=0x431b"                           "\x00"
+        "deadman_to=0xffffffff"                  "\x00"
+        "muxenab=0x100"                          "\x00"
+        "spurconfig=0x3"                         "\x00"
+        "glitch_based_crsmin=1"                  "\x00"
+        "btc_mode=1"                             "\x00"
+        "\x00\x00";
+
+const unsigned int   g_cyw43439_nvram_len = sizeof(g_cyw43439_nvram_image);
+
+/****************************************************************************
+ * Include the firmware blob.  This assembly code defines the global
+ * symbol g_cyw43439_firmware_image as the address of this included
+ * blob. This is similar in effect to the C statement:
+ *     const uint8_t g_cyw43439_firmware_image[]  = {...};
+ *     const uint8_t ng_cyw43439_clm_blob_image[] = {...};
+ ****************************************************************************/
+
+/* These are defined as array because the symbols name an actual address
+ * not a pointer to an address.  This is not one of the many cases where
+ * pointers and arrays are interchangeable in C.
+ */
+
+extern const uint8_t       g_cyw43439_firmware_image[];
+extern const uint8_t       g_cyw43439_clm_blob_image[];
+extern const unsigned int  g_cyw43439_clm_blob_len;
+
+/* This assembly code does the following:
+ *    - Force 16-byte alignment
+ *    - Defines g_cyw43439_firmware_image as a location in memory
+ *    - Copies the firmware image file data to that location.
+ *    - Defines g_cyw43439_firmware_end as the location directly beyond
+ *      that data.
+ *    - Defines g_cyw43439_clm_blob_image as a location within that
+ *      data where the clm_blob begins.
+ *    - Force 4-byte alignment
+ *    - Allocates an integer named g_cyw43439_clm_blob_len that
+ *      contains the length of the clm_blob.
+ */
+
+__asm__("\n     .balign  16"
+        "\n     .globl   g_cyw43439_firmware_image"
+        "\n     .globl   g_cyw43439_clm_blob_image"
+        "\n     .globl   g_cyw43439_clm_blob_len"
+        "\n g_cyw43439_firmware_image:"
+        "\n     .incbin  \"cyw43439.firmware.image\""
+        "\n firmware_end:"
+        "\n g_cyw43439_clm_blob_image=g_cyw43439_firmware_image+"
+                         STR(ROUNDED_FIRMWARE_LEN)
+        "\n     .balign  4"
+        "\n g_cyw43439_clm_blob_len:"
+        "\n     .word    firmware_end-g_cyw43439_clm_blob_image"
+        "\n");
+
+/****************************************************************************
+ * Other CYW43439 Firmware global definitions
+ ****************************************************************************/
+
+#ifndef CONFIG_IEEE80211_BROADCOM_FWFILES
+
+const unsigned int  g_cyw43439_firmware_len = CONFIG_CYW43439_FIRMWARE_LEN;
+
+#endif /* CONFIG_IEEE80211_BROADCOM_FWFILES */
+
+#endif /* CONFIG_IEEE80211_INFINEON_CYW43439 */
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/* This file contributes data only.  The section banner is here because
+ * tools/checkpatch.sh refuses to check a C file without one.
+ */
diff --git a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/CMakeLists.txt 
b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/CMakeLists.txt
new file mode 100644
index 00000000000..d9f79aced51
--- /dev/null
+++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/CMakeLists.txt
@@ -0,0 +1,40 @@
+# 
##############################################################################
+# boards/arm/rp23xx/pimoroni-pico-plus-2-w/CMakeLists.txt
+#
+# 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.
+#
+# 
##############################################################################
+
+add_subdirectory(src)
+
+add_custom_target(
+  nuttx_post_build
+  DEPENDS nuttx
+  WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
+  COMMENT "Regenerate nuttx.uf2")
+
+# The uf2 command to convert ELF/BIN to UF2
+add_custom_command(
+  TARGET nuttx_post_build
+  POST_BUILD
+  COMMAND picotool ARGS uf2 convert --quiet -t elf nuttx nuttx.uf2
+  COMMAND_EXPAND_LISTS
+  COMMAND ${CMAKE_COMMAND} -E echo "nuttx.uf2" >>
+          ${CMAKE_BINARY_DIR}/nuttx.manifest
+  WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
+  COMMENT "Regenerate nuttx.uf2")
diff --git a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/Kconfig 
b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/Kconfig
new file mode 100644
index 00000000000..eab5f150fd0
--- /dev/null
+++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/Kconfig
@@ -0,0 +1,54 @@
+#
+# For a description of the syntax of this configuration file,
+# see the file kconfig-language.txt in the NuttX tools repository.
+#
+
+if ARCH_BOARD_PIMORONI_PICO_PLUS_2_W
+
+# The board's only LED hangs off a GPIO of the CYW43439, so setting it means a
+# transaction on the gSPI bus.  board_autoled_on() is called from interrupt
+# handlers and from assertion handling, where that is not permissible, so this
+# board supports the CONFIG_USERLED interface only.  Override the generic
+# "default y" so that a fresh configuration does not select something this
+# board cannot implement.
+
+config ARCH_LEDS
+       default n
+
+menuconfig RP23XX_INFINEON_CYW43439
+       bool "Has Infineon cyw43439 WiFi chip"
+       depends on IEEE80211_INFINEON_CYW43439
+       default y
+
+endif
+
+if RP23XX_INFINEON_CYW43439
+
+config CYW43439_FIRMWARE_BIN_PATH
+       string "Path to Infineon 43439 firmware file"
+       default 
"${PICO_SDK_PATH}/lib/cyw43-driver/firmware/43439A0-7.95.49.00.combined"
+       ---help---
+               This should be a path to a file containing both the cyw43439 
firmware and
+               the CLM blob.  The firmware should be padded to a 256 byte 
boundary and
+               then the CLM blob should be appended.
+
+               If this file is updated, check the CYW43439_FIRMWARE_LEN below 
to make sure
+               it reflects the un-padded length of the firmware part.
+
+               pico-sdk 2.x no longer ships this blob as a binary, only as the 
C header
+               lib/cyw43-driver/firmware/w43439A0_7_95_49_00_combined.h.  If 
that is all
+               you have, convert the byte array in that header back to a 
binary and point
+               this option at the result.
+
+config CYW43439_FIRMWARE_LEN
+       int "Infineon 43439 firmware length (bytes)"
+       default 224190
+       ---help---
+               This is the length of just the base firmware in the firmware 
file specified
+               by the "Path to Infineon 43439 firmware file" configuration 
option.
+
+               This length does not include the length of any padding nor the 
length of
+               the appended clm_blob. If a clm_blob is present in the firmware 
file, this
+               length will be less than the length of the whole file.
+
+endif
diff --git a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/configs/nsh/defconfig 
b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/configs/nsh/defconfig
new file mode 100644
index 00000000000..78496bffa9d
--- /dev/null
+++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/configs/nsh/defconfig
@@ -0,0 +1,48 @@
+#
+# 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_ARCH_LEDS is not set
+# CONFIG_NSH_ARGCAT is not set
+# CONFIG_NSH_CMDOPT_HEXDUMP is not set
+# CONFIG_NSH_DISABLE_DATE is not set
+# CONFIG_NSH_DISABLE_LOSMART is not set
+# CONFIG_STANDARD_SERIAL is not set
+CONFIG_ARCH="arm"
+CONFIG_ARCH_BOARD="pimoroni-pico-plus-2-w"
+CONFIG_ARCH_BOARD_COMMON=y
+CONFIG_ARCH_BOARD_PIMORONI_PICO_PLUS_2_W=y
+CONFIG_ARCH_CHIP="rp23xx"
+CONFIG_ARCH_CHIP_RP23XX=y
+CONFIG_ARCH_RAMVECTORS=y
+CONFIG_ARCH_STACKDUMP=y
+CONFIG_BOARDCTL_RESET=y
+CONFIG_BOARD_LOOPSPERMSEC=10450
+CONFIG_BUILTIN=y
+CONFIG_DEBUG_FULLOPT=y
+CONFIG_DEBUG_SYMBOLS=y
+CONFIG_DISABLE_POSIX_TIMERS=y
+CONFIG_EXAMPLES_HELLO=y
+CONFIG_FS_PROCFS=y
+CONFIG_FS_PROCFS_REGISTER=y
+CONFIG_HOST_MACOS=y
+CONFIG_INIT_ENTRYPOINT="nsh_main"
+CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=6
+CONFIG_NSH_BUILTIN_APPS=y
+CONFIG_NSH_READLINE=y
+CONFIG_RAM_SIZE=532480
+CONFIG_RAM_START=0x20000000
+CONFIG_READLINE_CMD_HISTORY=y
+CONFIG_RR_INTERVAL=200
+CONFIG_SCHED_WAITPID=y
+CONFIG_START_DAY=9
+CONFIG_START_MONTH=2
+CONFIG_START_YEAR=2021
+CONFIG_SYSLOG_CONSOLE=y
+CONFIG_SYSTEM_NSH=y
+CONFIG_TESTING_GETPRIME=y
+CONFIG_TESTING_OSTEST=y
+CONFIG_UART0_SERIAL_CONSOLE=y
diff --git a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/configs/usbnsh/defconfig 
b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/configs/usbnsh/defconfig
new file mode 100644
index 00000000000..eb4346b2307
--- /dev/null
+++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/configs/usbnsh/defconfig
@@ -0,0 +1,52 @@
+#
+# 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_ARCH_LEDS is not set
+# CONFIG_DEV_CONSOLE is not set
+# CONFIG_NSH_ARGCAT is not set
+# CONFIG_NSH_CMDOPT_HEXDUMP is not set
+# CONFIG_NSH_DISABLE_DATE is not set
+# CONFIG_NSH_DISABLE_LOSMART is not set
+# CONFIG_RP23XX_UART0 is not set
+CONFIG_ARCH="arm"
+CONFIG_ARCH_BOARD="pimoroni-pico-plus-2-w"
+CONFIG_ARCH_BOARD_COMMON=y
+CONFIG_ARCH_BOARD_PIMORONI_PICO_PLUS_2_W=y
+CONFIG_ARCH_CHIP="rp23xx"
+CONFIG_ARCH_CHIP_RP23XX=y
+CONFIG_ARCH_RAMVECTORS=y
+CONFIG_ARCH_STACKDUMP=y
+CONFIG_BOARDCTL_RESET=y
+CONFIG_BOARD_LOOPSPERMSEC=10450
+CONFIG_BUILTIN=y
+CONFIG_CDCACM=y
+CONFIG_CDCACM_CONSOLE=y
+CONFIG_DEBUG_FULLOPT=y
+CONFIG_DEBUG_SYMBOLS=y
+CONFIG_DISABLE_POSIX_TIMERS=y
+CONFIG_EXAMPLES_HELLO=y
+CONFIG_FS_PROCFS=y
+CONFIG_FS_PROCFS_REGISTER=y
+CONFIG_HOST_MACOS=y
+CONFIG_INIT_ENTRYPOINT="nsh_main"
+CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=6
+CONFIG_NSH_BUILTIN_APPS=y
+CONFIG_NSH_READLINE=y
+CONFIG_NSH_USBCONSOLE=y
+CONFIG_RAM_SIZE=532480
+CONFIG_RAM_START=0x20000000
+CONFIG_READLINE_CMD_HISTORY=y
+CONFIG_RR_INTERVAL=200
+CONFIG_SCHED_WAITPID=y
+CONFIG_START_DAY=9
+CONFIG_START_MONTH=2
+CONFIG_START_YEAR=2021
+CONFIG_SYSTEM_NSH=y
+CONFIG_TESTING_GETPRIME=y
+CONFIG_TESTING_OSTEST=y
+CONFIG_USBDEV=y
+CONFIG_USBDEV_BUSPOWERED=y
diff --git a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/configs/wifi/defconfig 
b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/configs/wifi/defconfig
new file mode 100644
index 00000000000..aea2230382f
--- /dev/null
+++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/configs/wifi/defconfig
@@ -0,0 +1,89 @@
+#
+# 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_ARCH_LEDS is not set
+# CONFIG_NSH_ARGCAT is not set
+# CONFIG_NSH_CMDOPT_HEXDUMP is not set
+# CONFIG_NSH_DISABLE_DATE is not set
+# CONFIG_NSH_DISABLE_LOSMART is not set
+# CONFIG_STANDARD_SERIAL is not set
+CONFIG_ARCH="arm"
+CONFIG_ARCH_BOARD="pimoroni-pico-plus-2-w"
+CONFIG_ARCH_BOARD_COMMON=y
+CONFIG_ARCH_BOARD_PIMORONI_PICO_PLUS_2_W=y
+CONFIG_ARCH_BUTTONS=y
+CONFIG_ARCH_CHIP="rp23xx"
+CONFIG_ARCH_CHIP_RP23XX=y
+CONFIG_ARCH_IRQBUTTONS=y
+CONFIG_ARCH_RAMVECTORS=y
+CONFIG_ARCH_STACKDUMP=y
+CONFIG_BOARDCTL_RESET=y
+CONFIG_BOARD_LOOPSPERMSEC=10450
+CONFIG_BUILTIN=y
+CONFIG_DEBUG_FULLOPT=y
+CONFIG_DEBUG_SYMBOLS=y
+CONFIG_DISABLE_POSIX_TIMERS=y
+CONFIG_DRIVERS_IEEE80211=y
+CONFIG_DRIVERS_WIRELESS=y
+CONFIG_EXAMPLES_BUTTONS=y
+CONFIG_EXAMPLES_HELLO=y
+CONFIG_EXAMPLES_LEDS=y
+CONFIG_FS_PROCFS=y
+CONFIG_FS_PROCFS_REGISTER=y
+CONFIG_HOST_MACOS=y
+CONFIG_IEEE80211_BROADCOM_DEFAULT_COUNTRY="XX"
+CONFIG_IEEE80211_BROADCOM_DMABUF_ALIGNMENT=16
+CONFIG_IEEE80211_BROADCOM_FRAME_POOL_SIZE=32
+CONFIG_IEEE80211_BROADCOM_FULLMAC_GSPI=y
+CONFIG_IEEE80211_INFINEON_CYW43439=y
+CONFIG_INIT_ENTRYPOINT="nsh_main"
+CONFIG_INPUT=y
+CONFIG_INPUT_BUTTONS=y
+CONFIG_INPUT_BUTTONS_LOWER=y
+CONFIG_IOB_NBUFFERS=196
+CONFIG_IOB_NCHAINS=24
+CONFIG_NET=y
+CONFIG_NETDB_DNSCLIENT=y
+CONFIG_NETDB_DNSCLIENT_RECV_TIMEOUT=3
+CONFIG_NETDEV_LATEINIT=y
+CONFIG_NETDEV_WIRELESS_IOCTL=y
+CONFIG_NETINIT_DHCPC=y
+CONFIG_NETINIT_DNS=y
+CONFIG_NETINIT_DNSIPADDR=0x08080808
+CONFIG_NETINIT_WAPI_PASSPHRASE="-ssid-passphrase-"
+CONFIG_NETINIT_WAPI_SSID="-my-ssid-"
+CONFIG_NET_BROADCAST=y
+CONFIG_NET_ICMP_SOCKET=y
+CONFIG_NET_LOOPBACK=y
+CONFIG_NET_TCP=y
+CONFIG_NET_TCP_DELAYED_ACK=y
+CONFIG_NET_UDP=y
+CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=6
+CONFIG_NSH_BUILTIN_APPS=y
+CONFIG_NSH_READLINE=y
+CONFIG_RAM_SIZE=532480
+CONFIG_RAM_START=0x20000000
+CONFIG_READLINE_CMD_HISTORY=y
+CONFIG_RR_INTERVAL=200
+CONFIG_SCHED_HPWORK=y
+CONFIG_SCHED_LPWORK=y
+CONFIG_SCHED_WAITPID=y
+CONFIG_START_DAY=9
+CONFIG_START_MONTH=2
+CONFIG_START_YEAR=2021
+CONFIG_SYSLOG_CONSOLE=y
+CONFIG_SYSTEM_DHCPC_RENEW=y
+CONFIG_SYSTEM_NSH=y
+CONFIG_SYSTEM_PING=y
+CONFIG_TESTING_GETPRIME=y
+CONFIG_TESTING_OSTEST=y
+CONFIG_UART0_SERIAL_CONSOLE=y
+CONFIG_USERLED=y
+CONFIG_USERLED_LOWER=y
+CONFIG_WIRELESS_WAPI=y
+CONFIG_WIRELESS_WAPI_CMDTOOL=y
+CONFIG_WQUEUE_NOTIFIER=y
diff --git a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/board.h 
b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/board.h
new file mode 100644
index 00000000000..b1ca2264d3f
--- /dev/null
+++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/board.h
@@ -0,0 +1,154 @@
+/****************************************************************************
+ * boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/board.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 __BOARDS_ARM_RP23XX_PIMORONI_PICO_PLUS_2_W_INCLUDE_BOARD_H
+#define __BOARDS_ARM_RP23XX_PIMORONI_PICO_PLUS_2_W_INCLUDE_BOARD_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include "rp23xx_i2cdev.h"
+#include "rp23xx_spidev.h"
+#include "rp23xx_i2sdev.h"
+#include "rp23xx_spisd.h"
+
+#ifndef __ASSEMBLY__
+#  include <stdint.h>
+#endif
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Clocking *****************************************************************/
+
+#define MHZ                     1000000
+
+#define BOARD_XOSC_FREQ         (12 * MHZ)
+#define BOARD_XOSC_STARTUPDELAY 1
+#define BOARD_PLL_SYS_FREQ      (150 * MHZ)
+#define BOARD_PLL_USB_FREQ      (48 * MHZ)
+
+#define BOARD_REF_FREQ          (12 * MHZ)
+#define BOARD_SYS_FREQ          (150 * MHZ)
+#define BOARD_PERI_FREQ         (150 * MHZ)
+#define BOARD_USB_FREQ          (48 * MHZ)
+#define BOARD_ADC_FREQ          (48 * MHZ)
+#define BOARD_HSTX_FREQ         (150 * MHZ)
+
+#define BOARD_UART_BASEFREQ     BOARD_PERI_FREQ
+
+#define BOARD_TICK_CLOCK        (1 * MHZ)
+
+/* definitions for pico-sdk */
+
+/* GPIO definitions *********************************************************/
+
+#define BOARD_NGPIOOUT          1
+#define BOARD_NGPIOIN           1
+#define BOARD_NGPIOINT          1
+
+/* LED definitions **********************************************************/
+
+/* The only LED on this board is wired to GPIO 0 of the CYW43439 wireless
+ * chip, not to a GPIO of the RP2350.  Driving it means sending an iovar
+ * request over the gSPI bus, which can only be done from task context and
+ * only once the wireless chip has been activated by bringing wlan0 up.
+ *
+ * That rules out CONFIG_ARCH_LEDS -- board_autoled_on() is called from
+ * interrupt handlers and from assertion handling, where a bus transaction
+ * is not permissible.  So this board provides the user LED interface only
+ * (CONFIG_USERLED) and does not select ARCH_HAVE_LEDS.
+ */
+
+/* LED index values for use with board_userled() */
+
+#define BOARD_LED1        0
+#define BOARD_NLEDS       1
+
+#define BOARD_LED_GREEN   BOARD_LED1
+
+/* LED bits for use with board_userled_all() */
+
+#define BOARD_LED1_BIT    (1 << BOARD_LED1)
+
+/* BUTTON definitions *******************************************************/
+
+/* The board has two physical buttons, BOOT and RESET.  BOOT is also wired
+ * to GPIO 45, active low, so once NuttX is running it can be read as an
+ * ordinary user button.  pico-sdk calls that pin the board's USER_SW_PIN.
+ * RESET is not visible as a GPIO.
+ */
+
+#define NUM_BUTTONS       1
+
+#define BUTTON_USER1      0
+#define BUTTON_USER1_BIT  (1 << BUTTON_USER1)
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+#ifndef __ASSEMBLY__
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: rp23xx_boardearlyinitialize
+ *
+ * Description:
+ *
+ ****************************************************************************/
+
+void rp23xx_boardearlyinitialize(void);
+
+/****************************************************************************
+ * Name: rp23xx_boardinitialize
+ *
+ * Description:
+ *
+ ****************************************************************************/
+
+void rp23xx_boardinitialize(void);
+
+#undef EXTERN
+#if defined(__cplusplus)
+}
+#endif
+#endif /* __ASSEMBLY__ */
+#endif /* __BOARDS_ARM_RP23XX_PIMORONI_PICO_PLUS_2_W_INCLUDE_BOARD_H */
diff --git 
a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/rp23xx_extra_gpio.h 
b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/rp23xx_extra_gpio.h
new file mode 100644
index 00000000000..a188c3c8a7d
--- /dev/null
+++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/rp23xx_extra_gpio.h
@@ -0,0 +1,139 @@
+/****************************************************************************
+ * boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/rp23xx_extra_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 __BOARDS_ARM_RP23XX_PIMORONI_PICO_PLUS_2_W_INCLUDE_RP23XX_EXTRA_GPIO_H
+#define __BOARDS_ARM_RP23XX_PIMORONI_PICO_PLUS_2_W_INCLUDE_RP23XX_EXTRA_GPIO_H
+
+/****************************************************************************
+ *  These functions control the GPIO pins on the CYW43439 wireless chip, not
+ *  the GPIO pins of the RP2350.  The pin assignments for the Pimoroni Pico
+ *  Plus 2 W are:
+ *
+ *  GPIO 0 - output - controls the onboard LED
+ *  GPIO 1 - output - controls the onboard voltage regulator mode.
+ *  GPIO 2 - input  - Reads as non-zero if power supplied by USB or VBUS pin.
+ *
+ *  These only work once the wireless chip has been activated, which happens
+ *  when the wlan0 network interface is brought up.  Until then every access
+ *  fails with -EIO.
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#ifndef __ASSEMBLY__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <nuttx/wireless/ieee80211/bcmf_gpio.h>
+#include <nuttx/wireless/ieee80211/bcmf_gspi.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define RP23XX_EXTRA_GPIO_NUM    3     /* Number of extra GPIO pins */
+
+#define RP23XX_EXTRA_GPIO_LED    0     /* Onboard LED               */
+#define RP23XX_EXTRA_GPIO_VREG   1     /* Voltage regulator mode    */
+#define RP23XX_EXTRA_GPIO_VBUS   2     /* VBUS present              */
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+EXTERN gspi_dev_t *g_cyw43439;
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: rp23xx_extra_gpio_put
+ *
+ * Description:
+ *   Change the state of a GPIO pin on the CYW43439.
+ *
+ * Returned Value:
+ *   OK on success, or a negated errno.  -EIO means the wireless chip is not
+ *   running yet, which is the case until wlan0 has been brought up.
+ *
+ ****************************************************************************/
+
+static inline int rp23xx_extra_gpio_put(uint32_t gpio, bool value)
+{
+  DEBUGASSERT(gpio < RP23XX_EXTRA_GPIO_NUM);
+
+  if (g_cyw43439 == NULL)
+    {
+      return -EIO;
+    }
+
+  return bcmf_set_gpio(g_cyw43439->priv, gpio, value);
+}
+
+/****************************************************************************
+ * Name: rp23xx_extra_gpio_get
+ *
+ * Description:
+ *   Read the state of a GPIO pin on the CYW43439.
+ *
+ * Returned Value:
+ *   OK on success, or a negated errno.  -EIO means the wireless chip is not
+ *   running yet, which is the case until wlan0 has been brought up.
+ *
+ ****************************************************************************/
+
+static inline int rp23xx_extra_gpio_get(uint32_t gpio, bool *value)
+{
+  DEBUGASSERT(gpio < RP23XX_EXTRA_GPIO_NUM);
+
+  if (g_cyw43439 == NULL)
+    {
+      return -EIO;
+    }
+
+  return bcmf_get_gpio(g_cyw43439->priv, gpio, value);
+}
+
+#undef EXTERN
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __ASSEMBLY__ */
+#endif /* 
__BOARDS_ARM_RP23XX_PIMORONI_PICO_PLUS_2_W_INCLUDE_RP23XX_EXTRA_GPIO_H */
diff --git a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/rp23xx_i2cdev.h 
b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/rp23xx_i2cdev.h
new file mode 100644
index 00000000000..408bc491ffd
--- /dev/null
+++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/rp23xx_i2cdev.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+ * boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/rp23xx_i2cdev.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 __BOARDS_ARM_RP23XX_PIMORONI_PICO_PLUS_2_W_INCLUDE_RP23XX_I2CDEV_H
+#define __BOARDS_ARM_RP23XX_PIMORONI_PICO_PLUS_2_W_INCLUDE_RP23XX_I2CDEV_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <stdint.h>
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+#ifndef __ASSEMBLY__
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: board_i2cdev_initialize
+ *
+ * Description:
+ *   Initialize i2c driver and register the /dev/i2c device.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_RP23XX_I2C_DRIVER
+int board_i2cdev_initialize(int bus);
+#endif
+
+#undef EXTERN
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __ASSEMBLY__ */
+#endif /* __BOARDS_ARM_RP23XX_PIMORONI_PICO_PLUS_2_W_INCLUDE_RP23XX_I2CDEV_H */
diff --git a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/rp23xx_i2sdev.h 
b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/rp23xx_i2sdev.h
new file mode 100644
index 00000000000..185d08d0dde
--- /dev/null
+++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/rp23xx_i2sdev.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+ * boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/rp23xx_i2sdev.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 __BOARDS_ARM_RP23XX_PIMORONI_PICO_PLUS_2_W_INCLUDE_RP23XX_I2SDEV_H
+#define __BOARDS_ARM_RP23XX_PIMORONI_PICO_PLUS_2_W_INCLUDE_RP23XX_I2SDEV_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <stdint.h>
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+#ifndef __ASSEMBLY__
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: board_i2sdev_initialize
+ *
+ * Description:
+ *   Initialize i2s driver and register the /dev/audio/pcm0 device.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_RP23XX_I2S
+int board_i2sdev_initialize(int bus);
+#endif
+
+#undef EXTERN
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __ASSEMBLY__ */
+#endif /* __BOARDS_ARM_RP23XX_PIMORONI_PICO_PLUS_2_W_INCLUDE_RP23XX_I2SDEV_H */
diff --git a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/rp23xx_spidev.h 
b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/rp23xx_spidev.h
new file mode 100644
index 00000000000..70444529a36
--- /dev/null
+++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/rp23xx_spidev.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+ * boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/rp23xx_spidev.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 __BOARDS_ARM_RP23XX_PIMORONI_PICO_PLUS_2_W_INCLUDE_RP23XX_SPIDEV_H
+#define __BOARDS_ARM_RP23XX_PIMORONI_PICO_PLUS_2_W_INCLUDE_RP23XX_SPIDEV_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+#ifndef __ASSEMBLY__
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: board_spidev_initialize
+ *
+ * Description:
+ *   Initialize spi driver and register the /dev/spi device.
+ *
+ ****************************************************************************/
+
+int board_spidev_initialize(int bus);
+
+#undef EXTERN
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __ASSEMBLY__ */
+#endif /* __BOARDS_ARM_RP23XX_PIMORONI_PICO_PLUS_2_W_INCLUDE_RP23XX_SPIDEV_H */
diff --git a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/rp23xx_spisd.h 
b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/rp23xx_spisd.h
new file mode 100644
index 00000000000..3c21497a667
--- /dev/null
+++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/rp23xx_spisd.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+ * boards/arm/rp23xx/pimoroni-pico-plus-2-w/include/rp23xx_spisd.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 __BOARDS_ARM_RP23XX_PIMORONI_PICO_PLUS_2_W_INCLUDE_RP23XX_SPISD_H
+#define __BOARDS_ARM_RP23XX_PIMORONI_PICO_PLUS_2_W_INCLUDE_RP23XX_SPISD_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+#ifndef __ASSEMBLY__
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: board_spisd_initialize
+ *
+ * Description:
+ *   Initialize the SPI-based SD card.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_RP23XX_SPISD
+int board_spisd_initialize(int minor, int bus);
+#endif
+
+/****************************************************************************
+ * Name: board_spisd_status
+ *
+ * Description:
+ *   Get the status whether SD Card is present or not.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_RP23XX_SPISD
+uint8_t board_spisd_status(struct spi_dev_s *dev, uint32_t devid);
+#endif
+
+#undef EXTERN
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __ASSEMBLY__ */
+#endif /* __BOARDS_ARM_RP23XX_PIMORONI_PICO_PLUS_2_W_INCLUDE_RP23XX_SPISD_H */
diff --git a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/scripts/Make.defs 
b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/scripts/Make.defs
new file mode 100644
index 00000000000..b3f9d906ec7
--- /dev/null
+++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/scripts/Make.defs
@@ -0,0 +1,43 @@
+############################################################################
+# boards/arm/rp23xx/pimoroni-pico-plus-2-w/scripts/Make.defs
+#
+# 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.
+#
+############################################################################
+
+include $(TOPDIR)/.config
+include $(TOPDIR)/tools/Config.mk
+include $(TOPDIR)/tools/rp23xx/Config.mk
+include $(TOPDIR)/arch/arm/src/armv8-m/Toolchain.defs
+
+ifeq ($(CONFIG_BOOT_RUNFROMFLASH),y)
+  LDSCRIPT = memmap_default.ld
+else ifeq ($(CONFIG_BOOT_COPYTORAM),y)
+  LDSCRIPT = memmap_copy_to_ram.ld
+else
+  LDSCRIPT = memmap_no_flash.ld
+endif
+
+ARCHSCRIPT += $(BOARD_DIR)$(DELIM)scripts$(DELIM)$(LDSCRIPT)
+
+CFLAGS := $(ARCHCFLAGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHINCLUDES) 
$(ARCHDEFINES) $(EXTRAFLAGS) -pipe
+CXXFLAGS := $(ARCHCXXFLAGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) 
$(ARCHXXINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS) -pipe
+CPPFLAGS := $(ARCHINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS)
+AFLAGS := $(CFLAGS) -D__ASSEMBLY__
+
+NXFLATLDFLAGS1 = -r -d -warn-common
+NXFLATLDFLAGS2 = $(NXFLATLDFLAGS1) 
-T$(TOPDIR)/binfmt/libnxflat/gnu-nxflat-pcrel.ld -no-check-sections
+LDNXFLATFLAGS = -e main -s 2048
diff --git 
a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/scripts/memmap_copy_to_ram.ld 
b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/scripts/memmap_copy_to_ram.ld
new file mode 100644
index 00000000000..3e75acbd25d
--- /dev/null
+++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/scripts/memmap_copy_to_ram.ld
@@ -0,0 +1,340 @@
+/****************************************************************************
+ * boards/arm/rp23xx/pimoroni-pico-plus-2-w/scripts/memmap_copy_to_ram.ld
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+/* Based on GCC ARM embedded samples.
+   Defines the following symbols for use by code:
+    __exidx_start
+    __exidx_end
+    __etext
+    __data_start__
+    __preinit_array_start
+    __preinit_array_end
+    __init_array_start
+    __init_array_end
+    __fini_array_start
+    __fini_array_end
+    __data_end__
+    __bss_start__
+    __bss_end__
+    __end__
+    end
+    __HeapLimit
+    __StackLimit
+    __StackTop
+    __stack (== StackTop)
+*/
+
+MEMORY
+{
+    FLASH(rx) : ORIGIN = 0x10000000, LENGTH = 16384k
+    RAM(rwx) : ORIGIN =  0x20000000, LENGTH = 512k
+    SCRATCH_X(rwx) : ORIGIN = 0x20080000, LENGTH = 4k
+    SCRATCH_Y(rwx) : ORIGIN = 0x20081000, LENGTH = 4k
+}
+
+ENTRY(_entry_point)
+
+SECTIONS
+{
+    /* Second stage bootloader is prepended to the image. It must be 256 bytes 
big
+       and checksummed. It is usually built by the boot_stage2 target
+       in the Raspberry Pi Pico SDK
+    */
+
+    .flash_begin : {
+        __flash_binary_start = .;
+    } > FLASH
+
+    /* The bootrom will enter the image at the point indicated in your
+       IMAGE_DEF, which is usually the reset handler of your vector table.
+
+       The debugger will use the ELF entry point, which is the _entry_point
+       symbol, and in our case is *different from the bootrom's entry point.*
+       This is used to go back through the bootrom on debugger launches only,
+       to perform the same initial flash setup that would be performed on a
+       cold boot.
+    */
+
+    .flashtext : {
+        __logical_binary_start = .;
+        KEEP (*(.vectors))
+        KEEP (*(.binary_info_header))
+        __binary_info_header_end = .;
+        KEEP (*(.embedded_block))
+        __embedded_block_end = .;
+        KEEP (*(.reset))
+        . = ALIGN(4);
+    } > FLASH
+
+    /* Note the boot2 section is optional, and should be discarded if there is
+       no reference to it *inside* the binary, as it is not called by the
+       bootrom. (The bootrom performs a simple best-effort XIP setup and
+       leaves it to the binary to do anything more sophisticated.) However
+       there is still a size limit of 256 bytes, to ensure the boot2 can be
+       stored in boot RAM.
+
+       Really this is a "XIP setup function" -- the name boot2 is historic and
+       refers to its dual-purpose on RP2040, where it also handled vectoring
+       from the bootrom into the user image.
+    */
+
+    .boot2 : {
+        __boot2_start__ = .;
+        *(.boot2)
+        __boot2_end__ = .;
+    } > FLASH
+
+    ASSERT(__boot2_end__ - __boot2_start__ <= 256,
+        "ERROR: Pico second stage bootloader must be no more than 256 bytes in 
size")
+
+    .rodata : {
+        /* segments not marked as .flashdata are instead pulled into .data (in 
RAM) to avoid accidental flash accesses */
+        *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*)))
+        . = ALIGN(4);
+    } > FLASH
+
+    .ARM.extab :
+    {
+        *(.ARM.extab* .gnu.linkonce.armextab.*)
+    } > FLASH
+
+    __exidx_start = .;
+    .ARM.exidx :
+    {
+        *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+    } > FLASH
+    __exidx_end = .;
+
+    /* Machine inspectable binary information */
+    . = ALIGN(4);
+    __binary_info_start = .;
+    .binary_info :
+    {
+        KEEP(*(.binary_info.keep.*))
+        *(.binary_info.*)
+    } > FLASH
+    __binary_info_end = .;
+    . = ALIGN(4);
+
+    /* Vector table goes first in RAM, to avoid large alignment hole */
+    .ram_vector_table (NOLOAD): {
+        *(.ram_vector_table)
+    } > RAM
+
+    .uninitialized_data (NOLOAD): {
+        . = ALIGN(4);
+        *(.uninitialized_data*)
+    } > RAM
+
+    .text : {
+        __ram_text_start__ = .;
+        *(.init)
+        *(.text*)
+        *(.fini)
+        /* Pull all c'tors into .text */
+        *crtbegin.o(.ctors)
+        *crtbegin?.o(.ctors)
+        *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
+        *(SORT(.ctors.*))
+        *(.ctors)
+        /* Followed by destructors */
+        *crtbegin.o(.dtors)
+        *crtbegin?.o(.dtors)
+        *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
+        *(SORT(.dtors.*))
+        *(.dtors)
+
+        *(.eh_frame*)
+        . = ALIGN(4);
+        __ram_text_end__ = .;
+    } > RAM AT> FLASH
+    __ram_text_source__ = LOADADDR(.text);
+    . = ALIGN(4);
+
+    .data : {
+        __data_start__ = .;
+        *(vtable)
+
+        *(.time_critical*)
+
+        . = ALIGN(4);
+        *(.rodata*)
+        *(.srodata*)
+        . = ALIGN(4);
+
+        *(.data*)
+        *(.sdata*)
+
+        /* GOT/PLT must live INSIDE the copied .data range so a flat
+         * -fPIC object (e.g. a PIC static library linked into an app)
+         * gets an initialised GOT in RAM at boot; otherwise an orphan
+         * .got lands after _edata, is never copied, and every GOT-
+         * indirected access reads a NULL pointer (hardfault). */
+        . = ALIGN(4);
+        *(.got)
+        *(.got.plt)
+        *(.got*)
+
+        . = ALIGN(4);
+        *(.after_data.*)
+        . = ALIGN(4);
+        /* preinit data */
+        PROVIDE_HIDDEN (__mutex_array_start = .);
+        KEEP(*(SORT(.mutex_array.*)))
+        KEEP(*(.mutex_array))
+        PROVIDE_HIDDEN (__mutex_array_end = .);
+
+        . = ALIGN(4);
+        /* preinit data */
+        PROVIDE_HIDDEN (__preinit_array_start = .);
+        KEEP(*(SORT(.preinit_array.*)))
+        KEEP(*(.preinit_array))
+        PROVIDE_HIDDEN (__preinit_array_end = .);
+
+        . = ALIGN(4);
+        /* init data */
+        PROVIDE_HIDDEN (__init_array_start = .);
+        KEEP(*(SORT(.init_array.*)))
+        KEEP(*(.init_array))
+        PROVIDE_HIDDEN (__init_array_end = .);
+
+        . = ALIGN(4);
+        /* finit data */
+        PROVIDE_HIDDEN (__fini_array_start = .);
+        *(SORT(.fini_array.*))
+        *(.fini_array)
+        PROVIDE_HIDDEN (__fini_array_end = .);
+
+        *(.jcr)
+        . = ALIGN(4);
+    } > RAM AT> FLASH
+
+    .tdata : {
+        . = ALIGN(4);
+               *(.tdata .tdata.* .gnu.linkonce.td.*)
+        /* All data end */
+        __tdata_end = .;
+    } > RAM AT> FLASH
+    PROVIDE(__data_end__ = .);
+
+    /* __etext is (for backwards compatibility) the name of the .data init 
source pointer (...) */
+    __etext = LOADADDR(.data);
+
+    .tbss (NOLOAD) : {
+        . = ALIGN(4);
+        __bss_start__ = .;
+        __tls_base = .;
+        *(.tbss .tbss.* .gnu.linkonce.tb.*)
+        *(.tcommon)
+
+        __tls_end = .;
+    } > RAM
+
+    .bss  : {
+        . = ALIGN(4);
+        __tbss_end = .;
+
+        *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*)))
+        *(COMMON)
+        PROVIDE(__global_pointer$ = . + 2K);
+        *(.sbss*)
+        . = ALIGN(4);
+        __bss_end__ = .;
+    } > RAM
+
+    .heap (NOLOAD):
+    {
+        __end__ = .;
+        end = __end__;
+        KEEP(*(.heap*))
+    } > RAM
+    /* historically on GCC sbrk was growing past __HeapLimit to __StackLimit, 
however
+       to be more compatible, we now set __HeapLimit explicitly to where the 
end of the heap is */
+    __HeapLimit = ORIGIN(RAM) + LENGTH(RAM);
+
+    /* Start and end symbols must be word-aligned */
+    .scratch_x : {
+        __scratch_x_start__ = .;
+        *(.scratch_x.*)
+        . = ALIGN(4);
+        __scratch_x_end__ = .;
+    } > SCRATCH_X AT > FLASH
+    __scratch_x_source__ = LOADADDR(.scratch_x);
+
+    .scratch_y : {
+        __scratch_y_start__ = .;
+        *(.scratch_y.*)
+        . = ALIGN(4);
+        __scratch_y_end__ = .;
+    } > SCRATCH_Y AT > FLASH
+    __scratch_y_source__ = LOADADDR(.scratch_y);
+
+    /* .stack*_dummy section doesn't contains any symbols. It is only
+     * used for linker to calculate size of stack sections, and assign
+     * values to stack symbols later
+     *
+     * stack1 section may be empty/missing if platform_launch_core1 is not 
used */
+
+    /* by default we put core 0 stack at the end of scratch Y, so that if core 
1
+     * stack is not used then all of SCRATCH_X is free.
+     */
+    .stack1_dummy (NOLOAD):
+    {
+        *(.stack1*)
+    } > SCRATCH_X
+    .stack_dummy (NOLOAD):
+    {
+        KEEP(*(.stack*))
+    } > SCRATCH_Y
+
+    .flash_end : {
+        KEEP(*(.embedded_end_block*))
+        PROVIDE(__flash_binary_end = .);
+    } > FLASH =0xaa
+
+    /* stack limit is poorly named, but historically is maximum heap ptr */
+    __StackLimit = ORIGIN(RAM) + LENGTH(RAM);
+    __StackOneTop = ORIGIN(SCRATCH_X) + LENGTH(SCRATCH_X);
+    __StackTop = ORIGIN(SCRATCH_Y) + LENGTH(SCRATCH_Y);
+    __StackOneBottom = __StackOneTop - SIZEOF(.stack1_dummy);
+    __StackBottom = __StackTop - SIZEOF(.stack_dummy);
+    PROVIDE(__stack = __StackTop);
+
+    /* picolibc and LLVM */
+    PROVIDE (__heap_start = __end__);
+    PROVIDE (__heap_end = __HeapLimit);
+    PROVIDE( __tls_align = MAX(ALIGNOF(.tdata), ALIGNOF(.tbss)) );
+    PROVIDE( __tls_size_align = (__tls_size + __tls_align - 1) & ~(__tls_align 
- 1));
+    PROVIDE( __arm32_tls_tcb_offset = MAX(8, __tls_align) );
+
+    /* llvm-libc */
+    PROVIDE (_end = __end__);
+    PROVIDE (__llvm_libc_heap_limit = __HeapLimit);
+
+    /* Check if data + heap + stack exceeds RAM limit */
+    ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed")
+
+    ASSERT( __binary_info_header_end - __logical_binary_start <= 1024, "Binary 
info must be in first 1024 bytes of the binary")
+    ASSERT( __embedded_block_end - __logical_binary_start <= 4096, "Embedded 
block must be in first 4096 bytes of the binary")
+
+    /* todo assert on extra code */
+}
diff --git a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/scripts/memmap_default.ld 
b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/scripts/memmap_default.ld
new file mode 100644
index 00000000000..ea93cf337b6
--- /dev/null
+++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/scripts/memmap_default.ld
@@ -0,0 +1,353 @@
+/****************************************************************************
+ * boards/arm/rp23xx/pimoroni-pico-plus-2-w/scripts/memmap_default.ld
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+/* Based on GCC ARM embedded samples.
+   Defines the following symbols for use by code:
+    __exidx_start
+    __exidx_end
+    __etext
+    __data_start__
+    __preinit_array_start
+    __preinit_array_end
+    __init_array_start
+    __init_array_end
+    __fini_array_start
+    __fini_array_end
+    __data_end__
+    __bss_start__
+    __bss_end__
+    __end__
+    end
+    __HeapLimit
+    __StackLimit
+    __StackTop
+    __stack (== StackTop)
+*/
+
+MEMORY
+{
+    FLASH(rx) : ORIGIN = 0x10000000, LENGTH = 16384k
+    RAM(rwx) : ORIGIN =  0x20000000, LENGTH = 512k
+    SCRATCH_X(rwx) : ORIGIN = 0x20080000, LENGTH = 4k
+    SCRATCH_Y(rwx) : ORIGIN = 0x20081000, LENGTH = 4k
+}
+
+ENTRY(_entry_point)
+
+SECTIONS
+{
+    .flash_begin : {
+        __flash_binary_start = .;
+    } > FLASH
+
+    /* The bootrom will enter the image at the point indicated in your
+       IMAGE_DEF, which is usually the reset handler of your vector table.
+
+       The debugger will use the ELF entry point, which is the _entry_point
+       symbol, and in our case is *different from the bootrom's entry point.*
+       This is used to go back through the bootrom on debugger launches only,
+       to perform the same initial flash setup that would be performed on a
+       cold boot.
+    */
+
+    .text : {
+        __logical_binary_start = .;
+        _stext = ABSOLUTE(.);
+
+        KEEP (*(.vectors))
+
+        LONG(0xffffded3)
+        LONG(0x10210142)
+        LONG(0x000001ff)
+        LONG(0x00000000)
+        LONG(0xab123579)
+
+        KEEP (*(.binary_info_header))
+        __binary_info_header_end = .;
+        KEEP (*(.embedded_block))
+        __embedded_block_end = .;
+        KEEP (*(.reset))
+        /* TODO revisit this now memset/memcpy/float in ROM */
+        /* bit of a hack right now to exclude all floating point and time 
critical (e.g. memset, memcpy) code from
+         * FLASH ... we will include any thing excluded here in .data below by 
default */
+        *(.init)
+        *libgcc.a:cmse_nonsecure_call.o
+        *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .text*)
+        *(.fini)
+        /* Pull all c'tors into .text */
+        *crtbegin.o(.ctors)
+        *crtbegin?.o(.ctors)
+        *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
+        *(SORT(.ctors.*))
+        *(.ctors)
+        /* Followed by destructors */
+        *crtbegin.o(.dtors)
+        *crtbegin?.o(.dtors)
+        *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
+        *(SORT(.dtors.*))
+        *(.dtors)
+
+        . = ALIGN(4);
+        /* preinit data */
+        PROVIDE_HIDDEN (__preinit_array_start = .);
+        KEEP(*(SORT(.preinit_array.*)))
+        KEEP(*(.preinit_array))
+        PROVIDE_HIDDEN (__preinit_array_end = .);
+
+        . = ALIGN(4);
+        /* init data */
+        PROVIDE_HIDDEN (__init_array_start = .);
+        KEEP(*(SORT(.init_array.*)))
+        KEEP(*(.init_array))
+        PROVIDE_HIDDEN (__init_array_end = .);
+
+        . = ALIGN(4);
+        /* finit data */
+        PROVIDE_HIDDEN (__fini_array_start = .);
+        *(SORT(.fini_array.*))
+        *(.fini_array)
+        PROVIDE_HIDDEN (__fini_array_end = .);
+
+        *(.eh_frame*)
+        . = ALIGN(4);
+        _etext = ABSOLUTE(.);
+    } > FLASH
+
+    /* Note the boot2 section is optional, and should be discarded if there is
+       no reference to it *inside* the binary, as it is not called by the
+       bootrom. (The bootrom performs a simple best-effort XIP setup and
+       leaves it to the binary to do anything more sophisticated.) However
+       there is still a size limit of 256 bytes, to ensure the boot2 can be
+       stored in boot RAM.
+
+       Really this is a "XIP setup function" -- the name boot2 is historic and
+       refers to its dual-purpose on RP2040, where it also handled vectoring
+       from the bootrom into the user image.
+    */
+
+    .boot2 : {
+        __boot2_start__ = .;
+        *(.boot2)
+        __boot2_end__ = .;
+    } > FLASH
+
+    ASSERT(__boot2_end__ - __boot2_start__ <= 256,
+        "ERROR: Pico second stage bootloader must be no more than 256 bytes in 
size")
+
+    .rodata : {
+        *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .rodata*)
+        *(.srodata*)
+        . = ALIGN(4);
+        *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*)))
+        . = ALIGN(4);
+    } > FLASH
+
+    .ARM.extab :
+    {
+        *(.ARM.extab* .gnu.linkonce.armextab.*)
+    } > FLASH
+
+    __exidx_start = .;
+    .ARM.exidx :
+    {
+        *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+    } > FLASH
+    __exidx_end = .;
+
+    /* Machine inspectable binary information */
+    . = ALIGN(4);
+    __binary_info_start = .;
+    .binary_info :
+    {
+        KEEP(*(.binary_info.keep.*))
+        *(.binary_info.*)
+    } > FLASH
+    _eronly = ABSOLUTE(.);
+    __binary_info_end = .;
+    . = ALIGN(4);
+
+    .ram_vector_table (NOLOAD): {
+        *(.ram_vector_table)
+    } > RAM
+
+    .uninitialized_data (NOLOAD): {
+        . = ALIGN(4);
+        *(.uninitialized_data*)
+    } > RAM
+
+    .data : {
+        __data_start__ = .;
+        _sdata = ABSOLUTE(.);
+
+        *(vtable)
+
+        *(.time_critical*)
+
+        /* remaining .text and .rodata; i.e. stuff we exclude above because we 
want it in RAM */
+        *(.text*)
+        . = ALIGN(4);
+        *(.rodata*)
+        . = ALIGN(4);
+
+        *(.data*)
+        *(.sdata*)
+
+        /* GOT/PLT must live INSIDE the copied .data range so a flat
+         * -fPIC object (e.g. a PIC static library linked into an app)
+         * gets an initialised GOT in RAM at boot; otherwise an orphan
+         * .got lands after _edata, is never copied, and every GOT-
+         * indirected access reads a NULL pointer (hardfault). */
+        . = ALIGN(4);
+        *(.got)
+        *(.got.plt)
+        *(.got*)
+
+        . = ALIGN(4);
+        *(.after_data.*)
+        . = ALIGN(4);
+        /* preinit data */
+        PROVIDE_HIDDEN (__mutex_array_start = .);
+        KEEP(*(SORT(.mutex_array.*)))
+        KEEP(*(.mutex_array))
+        PROVIDE_HIDDEN (__mutex_array_end = .);
+
+        *(.jcr)
+        . = ALIGN(4);
+        _edata = ABSOLUTE(.);
+    } > RAM AT> FLASH
+
+    .tdata : {
+        _stdata = ABSOLUTE(.);
+        . = ALIGN(4);
+               *(.tdata .tdata.* .gnu.linkonce.td.*)
+        /* All data end */
+        __tdata_end = .;
+        _etdata = ABSOLUTE(.);
+    } > RAM AT> FLASH
+    PROVIDE(__data_end__ = .);
+
+    /* __etext is (for backwards compatibility) the name of the .data init 
source pointer (...) */
+    __etext = LOADADDR(.data);
+
+    .tbss (NOLOAD) : {
+        _stbss = ABSOLUTE(.);
+        . = ALIGN(4);
+        __bss_start__ = .;
+        _sbss = ABSOLUTE(.);
+        __tls_base = .;
+        *(.tbss .tbss.* .gnu.linkonce.tb.*)
+        *(.tcommon)
+
+        __tls_end = .;
+        _etbss = ABSOLUTE(.);
+    } > RAM
+
+    .bss (NOLOAD) : {
+        . = ALIGN(4);
+        __tbss_end = .;
+
+        *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*)))
+        *(COMMON)
+        PROVIDE(__global_pointer$ = . + 2K);
+        *(.sbss*)
+        . = ALIGN(4);
+        __bss_end__ = .;
+        _ebss = ABSOLUTE(.);
+    } > RAM
+
+    .heap (NOLOAD):
+    {
+        __end__ = .;
+        end = __end__;
+        KEEP(*(.heap*))
+    } > RAM
+    /* historically on GCC sbrk was growing past __HeapLimit to __StackLimit, 
however
+       to be more compatible, we now set __HeapLimit explicitly to where the 
end of the heap is */
+    __HeapLimit = ORIGIN(RAM) + LENGTH(RAM);
+
+    /* Start and end symbols must be word-aligned */
+    .scratch_x : {
+        __scratch_x_start__ = .;
+        *(.scratch_x.*)
+        . = ALIGN(4);
+        __scratch_x_end__ = .;
+    } > SCRATCH_X AT > FLASH
+    __scratch_x_source__ = LOADADDR(.scratch_x);
+
+    .scratch_y : {
+        __scratch_y_start__ = .;
+        *(.scratch_y.*)
+        . = ALIGN(4);
+        __scratch_y_end__ = .;
+    } > SCRATCH_Y AT > FLASH
+    __scratch_y_source__ = LOADADDR(.scratch_y);
+
+    /* .stack*_dummy section doesn't contains any symbols. It is only
+     * used for linker to calculate size of stack sections, and assign
+     * values to stack symbols later
+     *
+     * stack1 section may be empty/missing if platform_launch_core1 is not 
used */
+
+    /* by default we put core 0 stack at the end of scratch Y, so that if core 
1
+     * stack is not used then all of SCRATCH_X is free.
+     */
+    .stack1_dummy (NOLOAD):
+    {
+        *(.stack1*)
+    } > SCRATCH_X
+    .stack_dummy (NOLOAD):
+    {
+        KEEP(*(.stack*))
+    } > SCRATCH_Y
+
+    .flash_end : {
+        KEEP(*(.embedded_end_block*))
+        PROVIDE(__flash_binary_end = .);
+    } > FLASH =0xaa
+
+    /* stack limit is poorly named, but historically is maximum heap ptr */
+    __StackLimit = ORIGIN(RAM) + LENGTH(RAM);
+    __StackOneTop = ORIGIN(SCRATCH_X) + LENGTH(SCRATCH_X);
+    __StackTop = ORIGIN(SCRATCH_Y) + LENGTH(SCRATCH_Y);
+    __StackOneBottom = __StackOneTop - SIZEOF(.stack1_dummy);
+    __StackBottom = __StackTop - SIZEOF(.stack_dummy);
+    PROVIDE(__stack = __StackTop);
+
+    /* picolibc and LLVM */
+    PROVIDE (__heap_start = __end__);
+    PROVIDE (__heap_end = __HeapLimit);
+    PROVIDE( __tls_align = MAX(ALIGNOF(.tdata), ALIGNOF(.tbss)) );
+    PROVIDE( __tls_size_align = (__tls_size + __tls_align - 1) & ~(__tls_align 
- 1));
+    PROVIDE( __arm32_tls_tcb_offset = MAX(8, __tls_align) );
+
+    /* llvm-libc */
+    PROVIDE (_end = __end__);
+    PROVIDE (__llvm_libc_heap_limit = __HeapLimit);
+
+    /* Check if data + heap + stack exceeds RAM limit */
+    ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed")
+
+    ASSERT( __binary_info_header_end - __logical_binary_start <= 1024, "Binary 
info must be in first 1024 bytes of the binary")
+    ASSERT( __embedded_block_end - __logical_binary_start <= 4096, "Embedded 
block must be in first 4096 bytes of the binary")
+
+    /* todo assert on extra code */
+}
diff --git 
a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/scripts/memmap_no_flash.ld 
b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/scripts/memmap_no_flash.ld
new file mode 100644
index 00000000000..56db21d1156
--- /dev/null
+++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/scripts/memmap_no_flash.ld
@@ -0,0 +1,294 @@
+/****************************************************************************
+ * boards/arm/rp23xx/pimoroni-pico-plus-2-w/scripts/memmap_no_flash.ld
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+/* Based on GCC ARM embedded samples.
+   Defines the following symbols for use by code:
+    __exidx_start
+    __exidx_end
+    __etext
+    __data_start__
+    __preinit_array_start
+    __preinit_array_end
+    __init_array_start
+    __init_array_end
+    __fini_array_start
+    __fini_array_end
+    __data_end__
+    __bss_start__
+    __bss_end__
+    __end__
+    end
+    __HeapLimit
+    __StackLimit
+    __StackTop
+    __stack (== StackTop)
+*/
+
+MEMORY
+{
+    RAM(rwx) : ORIGIN =  0x20000000, LENGTH = 512k
+    SCRATCH_X(rwx) : ORIGIN = 0x20080000, LENGTH = 4k
+    SCRATCH_Y(rwx) : ORIGIN = 0x20081000, LENGTH = 4k
+}
+
+ENTRY(_entry_point)
+
+SECTIONS
+{
+    /* Note unlike RP2040, we start the image with a vector table even for
+       NO_FLASH builds. On Arm, the bootrom expects a VT at the start of the
+       image by default; on RISC-V, the default is to enter the image at its
+       lowest address, so an IMAGEDEF item is required to specify the
+       nondefault entry point. */
+
+    .text : {
+        __logical_binary_start = .;
+        _stext = ABSOLUTE(.);
+        /* Vectors require 512-byte alignment on v8-M when >48 IRQs are used,
+           so we would waste RAM if the vector table were not at the
+           start. */
+        KEEP (*(.vectors))
+        KEEP (*(.binary_info_header))
+        __binary_info_header_end = .;
+        KEEP (*(.embedded_block))
+        __embedded_block_end = .;
+        __reset_start = .;
+        KEEP (*(.reset))
+        __reset_end = .;
+        *(.time_critical*)
+        *(.text*)
+        . = ALIGN(4);
+        *(.init)
+        *(.fini)
+        /* Pull all c'tors into .text */
+        *crtbegin.o(.ctors)
+        *crtbegin?.o(.ctors)
+        *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
+        *(SORT(.ctors.*))
+        *(.ctors)
+        /* Followed by destructors */
+        *crtbegin.o(.dtors)
+        *crtbegin?.o(.dtors)
+        *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
+        *(SORT(.dtors.*))
+        *(.dtors)
+
+        *(.eh_frame*)
+    } > RAM
+
+    .rodata : {
+        . = ALIGN(4);
+        *(.rodata*)
+        *(.srodata*)
+        . = ALIGN(4);
+        *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*)))
+        . = ALIGN(4);
+    } > RAM
+
+    .ARM.extab :
+    {
+        *(.ARM.extab* .gnu.linkonce.armextab.*)
+    } > RAM
+
+    __exidx_start = .;
+    .ARM.exidx :
+    {
+        *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+    } > RAM
+    __exidx_end = .;
+
+    /* Machine inspectable binary information */
+    . = ALIGN(4);
+    __binary_info_start = .;
+    .binary_info :
+    {
+        KEEP(*(.binary_info.keep.*))
+        *(.binary_info.*)
+    } > RAM
+    __binary_info_end = .;
+    . = ALIGN(4);
+
+    .data : {
+        __data_start__ = .;
+        *(vtable)
+        *(.data*)
+        *(.sdata*)
+
+        /* GOT/PLT must live INSIDE the copied .data range so a flat
+         * -fPIC object (e.g. a PIC static library linked into an app)
+         * gets an initialised GOT in RAM at boot; otherwise an orphan
+         * .got lands after _edata, is never copied, and every GOT-
+         * indirected access reads a NULL pointer (hardfault). */
+        . = ALIGN(4);
+        *(.got)
+        *(.got.plt)
+        *(.got*)
+
+        . = ALIGN(4);
+        *(.after_data.*)
+        . = ALIGN(4);
+        /* preinit data */
+        PROVIDE_HIDDEN (__mutex_array_start = .);
+        KEEP(*(SORT(.mutex_array.*)))
+        KEEP(*(.mutex_array))
+        PROVIDE_HIDDEN (__mutex_array_end = .);
+
+        . = ALIGN(4);
+        /* preinit data */
+        PROVIDE_HIDDEN (__preinit_array_start = .);
+        KEEP(*(SORT(.preinit_array.*)))
+        KEEP(*(.preinit_array))
+        PROVIDE_HIDDEN (__preinit_array_end = .);
+
+        . = ALIGN(4);
+        /* init data */
+        PROVIDE_HIDDEN (__init_array_start = .);
+        KEEP(*(SORT(.init_array.*)))
+        KEEP(*(.init_array))
+        PROVIDE_HIDDEN (__init_array_end = .);
+
+        . = ALIGN(4);
+        /* finit data */
+        PROVIDE_HIDDEN (__fini_array_start = .);
+        *(SORT(.fini_array.*))
+        *(.fini_array)
+        PROVIDE_HIDDEN (__fini_array_end = .);
+
+        *(.jcr)
+        . = ALIGN(4);
+   } > RAM
+
+    .tdata : {
+        . = ALIGN(4);
+               *(.tdata .tdata.* .gnu.linkonce.td.*)
+        /* All data end */
+        __tdata_end = .;
+    } > RAM
+    PROVIDE(__data_end__ = .);
+
+    .uninitialized_data (NOLOAD): {
+        . = ALIGN(4);
+        *(.uninitialized_data*)
+    } > RAM
+    /* __etext is (for backwards compatibility) the name of the .data init 
source pointer (...) */
+    __etext = LOADADDR(.data);
+    _etext = LOADADDR(.data);
+
+
+    .tbss (NOLOAD) : {
+        . = ALIGN(4);
+        __bss_start__ = .;
+        _stbss = ABSOLUTE(.);
+        __tls_base = .;
+        *(.tbss .tbss.* .gnu.linkonce.tb.*)
+        *(.tcommon)
+
+        __tls_end = .;
+        _etbss = ABSOLUTE(.);
+    } > RAM
+
+    .bss (NOLOAD) : {
+        . = ALIGN(4);
+        _sbss = ABSOLUTE(.);
+        __tbss_end = .;
+
+        *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*)))
+        *(COMMON)
+        PROVIDE(__global_pointer$ = . + 2K);
+        *(.sbss*)
+        . = ALIGN(4);
+        __bss_end__ = .;
+        _ebss = ABSOLUTE(.);
+    } > RAM
+
+    .heap (NOLOAD):
+    {
+        __end__ = .;
+        end = __end__;
+        KEEP(*(.heap*))
+    } > RAM
+    /* historically on GCC sbrk was growing past __HeapLimit to __StackLimit, 
however
+       to be more compatible, we now set __HeapLimit explicitly to where the 
end of the heap is */
+    __HeapLimit = ORIGIN(RAM) + LENGTH(RAM);
+
+    /* Start and end symbols must be word-aligned */
+    .scratch_x : {
+        __scratch_x_start__ = .;
+        *(.scratch_x.*)
+        . = ALIGN(4);
+        __scratch_x_end__ = .;
+    } > SCRATCH_X
+    __scratch_x_source__ = LOADADDR(.scratch_x);
+
+    .scratch_y : {
+        __scratch_y_start__ = .;
+        *(.scratch_y.*)
+        . = ALIGN(4);
+        __scratch_y_end__ = .;
+    } > SCRATCH_Y
+    __scratch_y_source__ = LOADADDR(.scratch_y);
+
+    /* .stack*_dummy section doesn't contains any symbols. It is only
+     * used for linker to calculate size of stack sections, and assign
+     * values to stack symbols later
+     *
+     * stack1 section may be empty/missing if platform_launch_core1 is not 
used */
+
+    /* by default we put core 0 stack at the end of scratch Y, so that if core 
1
+     * stack is not used then all of SCRATCH_X is free.
+     */
+    .stack1_dummy (NOLOAD):
+    {
+        *(.stack1*)
+    } > SCRATCH_X
+    .stack_dummy (NOLOAD):
+    {
+        KEEP(*(.stack*))
+    } > SCRATCH_Y
+
+    /* stack limit is poorly named, but historically is maximum heap ptr */
+    __StackLimit = ORIGIN(RAM) + LENGTH(RAM);
+    __StackOneTop = ORIGIN(SCRATCH_X) + LENGTH(SCRATCH_X);
+    __StackTop = ORIGIN(SCRATCH_Y) + LENGTH(SCRATCH_Y);
+    __StackOneBottom = __StackOneTop - SIZEOF(.stack1_dummy);
+    __StackBottom = __StackTop - SIZEOF(.stack_dummy);
+    PROVIDE(__stack = __StackTop);
+
+    /* picolibc and LLVM */
+    PROVIDE (__heap_start = __end__);
+    PROVIDE (__heap_end = __HeapLimit);
+    PROVIDE( __tls_align = MAX(ALIGNOF(.tdata), ALIGNOF(.tbss)) );
+    PROVIDE( __tls_size_align = (__tls_size + __tls_align - 1) & ~(__tls_align 
- 1));
+    PROVIDE( __arm32_tls_tcb_offset = MAX(8, __tls_align) );
+
+    /* llvm-libc */
+    PROVIDE (_end = __end__);
+    PROVIDE (__llvm_libc_heap_limit = __HeapLimit);
+
+    /* Check if data + heap + stack exceeds RAM limit */
+    ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed")
+
+    ASSERT( __binary_info_header_end - __logical_binary_start <= 1024, "Binary 
info must be in first 1024 bytes of the binary")
+    ASSERT( __embedded_block_end - __logical_binary_start <= 4096, "Embedded 
block must be in first 4096 bytes of the binary")
+
+    /* todo assert on extra code */
+}
diff --git a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/CMakeLists.txt 
b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/CMakeLists.txt
new file mode 100644
index 00000000000..9c6be9b7053
--- /dev/null
+++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/CMakeLists.txt
@@ -0,0 +1,66 @@
+# 
##############################################################################
+# boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/CMakeLists.txt
+#
+# 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.
+#
+# 
##############################################################################
+
+set(SRCS rp23xx_boardinitialize.c rp23xx_bringup.c)
+
+if(CONFIG_DEV_GPIO)
+  list(APPEND SRCS rp23xx_gpio.c)
+endif()
+
+# This board has no LED on an RP2350 pin -- its only LED hangs off the 
CYW43439,
+# and reaching it means a gSPI bus transaction.  That rules out
+# CONFIG_ARCH_LEDS, whose board_autoled_on() is called from interrupt handlers
+# and from assertion handling, so there is no rp23xx_autoleds.c.  It also means
+# there is no LED at all without the wireless chip.  See rp23xx_userleds.c.
+
+if(CONFIG_ARCH_LEDS)
+  message(
+    FATAL_ERROR
+      "CONFIG_ARCH_LEDS is not supported on this board: the LED hangs off the "
+      "CYW43439 and cannot be driven from interrupt context.  "
+      "Use CONFIG_USERLED instead.")
+endif()
+
+if(CONFIG_RP23XX_INFINEON_CYW43439)
+  list(APPEND SRCS rp23xx_userleds.c)
+endif()
+
+if(CONFIG_ARCH_BUTTONS)
+  list(APPEND SRCS rp23xx_buttons.c)
+endif()
+
+# rp23xx_firmware.c, which carries the CYW43439 firmware blob, is built from
+# boards/arm/rp23xx/common/src.
+
+target_sources(board PRIVATE ${SRCS})
+
+if(CONFIG_BOOT_RUNFROMFLASH)
+  set_property(GLOBAL PROPERTY LD_SCRIPT
+                               "${NUTTX_BOARD_DIR}/scripts/memmap_default.ld")
+elseif(CONFIG_BOOT_COPYTORAM)
+  set_property(
+    GLOBAL PROPERTY LD_SCRIPT
+                    "${NUTTX_BOARD_DIR}/scripts/memmap_copy_to_ram.ld")
+else()
+  set_property(GLOBAL PROPERTY LD_SCRIPT
+                               "${NUTTX_BOARD_DIR}/scripts/memmap_no_flash.ld")
+endif()
diff --git a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/Make.defs 
b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/Make.defs
new file mode 100644
index 00000000000..276b544dcc4
--- /dev/null
+++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/Make.defs
@@ -0,0 +1,95 @@
+############################################################################
+# boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/Make.defs
+#
+# 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.
+#
+############################################################################
+
+include $(TOPDIR)/Make.defs
+
+CSRCS = rp23xx_boardinitialize.c
+CSRCS += rp23xx_bringup.c
+
+ifeq ($(CONFIG_DEV_GPIO),y)
+CSRCS += rp23xx_gpio.c
+endif
+
+# This board has no LED on an RP2350 pin -- its only LED hangs off the
+# CYW43439, and reaching it means a gSPI bus transaction.  That rules out
+# CONFIG_ARCH_LEDS, whose board_autoled_on() is called from interrupt handlers
+# and from assertion handling, so there is no rp23xx_autoleds.c.  It also
+# means there is no LED at all without the wireless chip.
+# See src/rp23xx_userleds.c.
+
+ifeq ($(CONFIG_ARCH_LEDS),y)
+$(error CONFIG_ARCH_LEDS is not supported on this board: the LED hangs off \
+        the CYW43439 and cannot be driven from interrupt context. \
+        Use CONFIG_USERLED instead)
+endif
+
+ifeq ($(CONFIG_RP23XX_INFINEON_CYW43439),y)
+CSRCS += rp23xx_userleds.c
+endif
+
+ifeq ($(CONFIG_ARCH_BUTTONS),y)
+  CSRCS += rp23xx_buttons.c
+endif
+
+DEPPATH += --dep-path board
+VPATH += :board
+CFLAGS += 
${INCDIR_PREFIX}$(TOPDIR)$(DELIM)arch$(DELIM)$(CONFIG_ARCH)$(DELIM)src$(DELIM)board$(DELIM)board
+
+############################################################################
+# The rules below stage the cyw43439 blob out of pico_sdk so that the
+# .incbin in rp23xx_firmware.c can pick it up.
+#
+# rp23xx_firmware.c lives in the *common* src directory, which is both on the
+# include path (added by common/src/Make.defs) and reachable via VPATH, so the
+# blob is staged next to it there.  This mirrors what rp2040 does for the
+# Raspberry Pi Pico W.
+############################################################################
+
+ifeq ($(CONFIG_IEEE80211_INFINEON_CYW43439),y)
+
+FIRMWARE = src$(DELIM)cyw43439.firmware.image
+
+# --- If PICO_SDK_PATH is not defined set a dummy path. --------------------
+#     See comment below.
+
+ifeq ($(PICO_SDK_PATH),)
+       PICO_SDK_PATH = /tmp
+endif
+
+FIRMWARE_SRC := $(patsubst "%",%,$(CONFIG_CYW43439_FIRMWARE_BIN_PATH))
+
+# --- If the firmware source does not exist create a dummy file. -----------
+#     NuttX built with the cyw43439 driver will not talk to the wireless
+#     chip when built with this dummy file.  The sole purpose of adding
+#     this dummy is so the CI build tests will not fail.
+
+$(FIRMWARE_SRC):
+       $(Q) mkdir -p `dirname $(FIRMWARE_SRC)`
+       $(Q) echo "dummy" >$(FIRMWARE_SRC)
+
+$(FIRMWARE): $(FIRMWARE_SRC)
+       $(call CATFILE, $(FIRMWARE), $(FIRMWARE_SRC))
+
+src$(DELIM)rp23xx_firmware.c: $(FIRMWARE)
+
+distclean::
+       $(call DELFILE, $(FIRMWARE))
+
+endif
diff --git 
a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_boardinitialize.c 
b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_boardinitialize.c
new file mode 100644
index 00000000000..dfba32a568d
--- /dev/null
+++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_boardinitialize.c
@@ -0,0 +1,115 @@
+/****************************************************************************
+ * boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_boardinitialize.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 <nuttx/config.h>
+
+#include <nuttx/debug.h>
+
+#include <nuttx/board.h>
+#include <arch/board/board.h>
+
+#include "rp23xx_gpio.h"
+
+#ifdef CONFIG_RP23XX_PSRAM
+#include "rp23xx_psram.h"
+#endif
+
+#ifdef CONFIG_ARCH_BOARD_COMMON
+#include "rp23xx_common_initialize.h"
+#endif /* CONFIG_ARCH_BOARD_COMMON */
+
+#include "rp23xx_pico.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: rp23xx_boardearlyinitialize
+ *
+ * Description:
+ *
+ ****************************************************************************/
+
+void rp23xx_boardearlyinitialize(void)
+{
+  #ifdef CONFIG_ARCH_BOARD_COMMON
+  rp23xx_common_earlyinitialize();
+  #endif
+
+  /* --- Place any board specific early initialization here --- */
+
+  /* Nothing to do for the LED: it hangs off the CYW43439 wireless chip
+   * rather than an RP2350 pin, and cannot be touched this early.  See
+   * src/rp23xx_userleds.c.
+   */
+}
+
+/****************************************************************************
+ * Name: rp23xx_boardinitialize
+ *
+ * Description:
+ *
+ ****************************************************************************/
+
+void rp23xx_boardinitialize(void)
+{
+  #ifdef CONFIG_ARCH_BOARD_COMMON
+  rp23xx_common_initialize();
+  #endif
+
+  #ifdef CONFIG_RP23XX_PSRAM
+  rp23xx_psramconfig();
+  #endif
+
+  /* --- Place any board specific initialization here --- */
+}
+
+/****************************************************************************
+ * Name: board_late_initialize
+ *
+ * Description:
+ *   If CONFIG_BOARD_LATE_INITIALIZE is selected, then an additional
+ *   initialization call will be performed in the boot-up sequence to a
+ *   function called board_late_initialize(). board_late_initialize() will be
+ *   called immediately after up_initialize() is called and just before the
+ *   initial application is started.  This additional initialization phase
+ *   may be used, for example, to initialize board-specific device drivers.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_BOARD_LATE_INITIALIZE
+void board_late_initialize(void)
+{
+  rp23xx_bringup();
+}
+#endif
diff --git a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_bringup.c 
b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_bringup.c
new file mode 100644
index 00000000000..086a98a8732
--- /dev/null
+++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_bringup.c
@@ -0,0 +1,132 @@
+/****************************************************************************
+ * boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_bringup.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 <nuttx/config.h>
+
+#include <nuttx/debug.h>
+#include <stddef.h>
+#include <errno.h>
+
+#include <nuttx/fs/fs.h>
+
+#include <arch/board/board.h>
+
+#include "rp23xx_pico.h"
+
+#ifdef CONFIG_ARCH_BOARD_COMMON
+#include "rp23xx_common_bringup.h"
+#endif /* CONFIG_ARCH_BOARD_COMMON */
+
+#ifdef CONFIG_USERLED
+#  include <nuttx/leds/userled.h>
+#endif
+
+#ifdef CONFIG_INPUT_BUTTONS
+#  include <nuttx/input/buttons.h>
+#endif
+
+#ifdef CONFIG_RP23XX_INFINEON_CYW43439
+#  include "rp23xx_cyw43439.h"
+#endif
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#ifdef CONFIG_RP23XX_INFINEON_CYW43439
+gspi_dev_t *g_cyw43439 = NULL;
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: rp23xx_bringup
+ ****************************************************************************/
+
+int rp23xx_bringup(void)
+{
+  int ret;
+
+  UNUSED(ret);
+
+#ifdef CONFIG_ARCH_BOARD_COMMON
+
+  ret = rp23xx_common_bringup();
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+#endif /* CONFIG_ARCH_BOARD_COMMON */
+
+  /* --- Place any board specific bringup code here --- */
+
+#ifdef CONFIG_RP23XX_INFINEON_CYW43439
+  /* Bring up the CYW43439 wireless chip.  This registers the wlan0 network
+   * device; the chip's firmware is not downloaded until wlan0 is brought up.
+   *
+   * Do this before the LED driver, which drives a GPIO on this chip.
+   */
+
+  g_cyw43439 = rp23xx_cyw_setup(GPIO_CYW43439_ON,
+                                GPIO_CYW43439_CS,
+                                GPIO_CYW43439_DATA,
+                                GPIO_CYW43439_CLOCK,
+                                GPIO_CYW43439_DATA);
+
+  if (g_cyw43439 == NULL)
+    {
+      syslog(LOG_ERR,
+             "ERROR: failed to initialize the cyw43439 (WiFi chip): %d\n",
+             errno);
+    }
+#endif
+
+#if defined(CONFIG_USERLED_LOWER) && defined(CONFIG_RP23XX_INFINEON_CYW43439)
+  /* Register the LED driver.  The LED sits on the wireless chip, so there is
+   * nothing to register without it.
+   */
+
+  ret = userled_lower_initialize("/dev/userleds");
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, \
+      "ERROR: userled_lower_initialize() failed: %d\n", ret);
+    }
+#endif
+
+#ifdef CONFIG_INPUT_BUTTONS
+  /* Register the BUTTON driver */
+
+  ret = btn_lower_initialize("/dev/buttons");
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "ERROR: btn_lower_initialize() failed: %d\n", ret);
+    }
+#endif
+
+  return OK;
+}
diff --git a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_buttons.c 
b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_buttons.c
new file mode 100644
index 00000000000..4ef40e210a6
--- /dev/null
+++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_buttons.c
@@ -0,0 +1,187 @@
+/****************************************************************************
+ * boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_buttons.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 <nuttx/config.h>
+
+#include <stdint.h>
+#include <errno.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/board.h>
+#include <arch/board/board.h>
+
+#include "rp23xx_gpio.h"
+#include "rp23xx_pico.h"
+
+#if defined(CONFIG_ARCH_BUTTONS)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if defined(CONFIG_INPUT_BUTTONS) && !defined(CONFIG_ARCH_IRQBUTTONS)
+#  error "The NuttX Buttons Driver depends on IRQ support to work!\n"
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/* Pin configuration for the board's BOOT button, which doubles as a user
+ * button once NuttX is running.
+ */
+
+static const uint32_t g_buttons[NUM_BUTTONS] =
+{
+  GPIO_BTN_USER1
+};
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: board_button_initialize
+ *
+ * Description:
+ *   board_button_initialize() must be called to initialize button resources.
+ *   After that, board_buttons() may be called to collect the current state
+ *   of all buttons or board_button_irq() may be called to register button
+ *   interrupt handlers.
+ *
+ ****************************************************************************/
+
+uint32_t board_button_initialize(void)
+{
+  int i;
+
+  /* Configure the GPIO pins as inputs. And we will use interrupts */
+
+  for (i = 0; i < NUM_BUTTONS; i++)
+    {
+      /* Initialize input pin */
+
+      rp23xx_gpio_init(g_buttons[i]);
+
+      /* The button shorts the pin to ground, so pull it up.
+       *
+       * Do not be tempted to leave the pin floating or pulled down here:
+       * erratum RP2350-E9 means a floating Bank 0 input leaks enough current
+       * to sit at about 2.2 V, and the internal pull-down is far too weak to
+       * overcome it.  The pull-up is unaffected by the erratum.
+       *
+       * pull-up = true : pull-down = false
+       */
+
+      rp23xx_gpio_set_pulls(g_buttons[i], true, false);
+    }
+
+  return NUM_BUTTONS;
+}
+
+/****************************************************************************
+ * Name: board_buttons
+ ****************************************************************************/
+
+uint32_t board_buttons(void)
+{
+  uint32_t ret = 0;
+  int i;
+
+  /* Check that state of each key */
+
+  for (i = 0; i < NUM_BUTTONS; i++)
+    {
+      /* A LOW value means that the key is pressed. */
+
+      bool released = rp23xx_gpio_get(g_buttons[i]);
+
+      /* Accumulate the set of depressed (not released) keys */
+
+      if (!released)
+        {
+           ret |= (1 << i);
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Button support.
+ *
+ * Description:
+ *   board_button_initialize() must be called to initialize button resources.
+ *   After that, board_buttons() may be called to collect the current state
+ *   of all buttons or board_button_irq() may be called to register button
+ *   interrupt handlers.
+ *
+ *   After board_button_initialize() has been called, board_buttons() may be
+ *   called to collect the state of all buttons.  board_buttons() returns
+ *   an 32-bit bit set with each bit associated with a button.  See the
+ *   BUTTON_*_BIT definitions in board.h for the meaning of each bit.
+ *
+ *   board_button_irq() may be called to register an interrupt handler that
+ *   will be called when a button is depressed or released.  The ID value is
+ *   a button enumeration value that uniquely identifies a button resource.
+ *   See the BUTTON_* definitions in board.h for the meaning of enumeration
+ *   value.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ARCH_IRQBUTTONS
+int board_button_irq(int id, xcpt_t irqhandler, void *arg)
+{
+  int ret = -EINVAL;
+
+  /* The following should be atomic */
+
+  if (id >= MIN_IRQBUTTON && id <= MAX_IRQBUTTON)
+    {
+      /* Make sure the interrupt is disabled */
+
+      rp23xx_gpio_disable_irq(g_buttons[id]);
+
+      /* Attach the interrupt handler */
+
+      ret = rp23xx_gpio_irq_attach(g_buttons[id],
+                                   RP23XX_GPIO_INTR_EDGE_LOW,
+                                   irqhandler,
+                                   arg);
+      if (ret < 0)
+        {
+          syslog(LOG_ERR, "ERROR: irq_attach() failed: %d\n", ret);
+          return ret;
+        }
+
+      /* Enable interruption for this pin */
+
+      rp23xx_gpio_enable_irq(g_buttons[id]);
+    }
+
+  return ret;
+}
+#endif
+
+#endif /* CONFIG_ARCH_BUTTONS */
diff --git a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_gpio.c 
b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_gpio.c
new file mode 100644
index 00000000000..57c5e8629ac
--- /dev/null
+++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_gpio.c
@@ -0,0 +1,396 @@
+/****************************************************************************
+ * boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_gpio.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 <nuttx/config.h>
+
+#include <sys/types.h>
+#include <syslog.h>
+#include <nuttx/irq.h>
+#include <arch/irq.h>
+#include <assert.h>
+#include <nuttx/debug.h>
+
+#include <nuttx/ioexpander/gpio.h>
+
+#include <arch/board/board.h>
+
+#include "arm_internal.h"
+#include "chip.h"
+#include "rp23xx_gpio.h"
+
+#if defined(CONFIG_DEV_GPIO) && !defined(CONFIG_GPIO_LOWER_HALF)
+
+/* Output pins.
+ *
+ * There is no onboard LED on an RP2350 pin on this board -- it hangs off the
+ * CYW43439 -- so this is just a free header pin.  Note that GPIO 23, 24, 25
+ * and 29 are wired to the wireless chip and must not be used here.
+ */
+
+#define GPIO_OUT1     2
+
+/* Input pins.
+ */
+
+#define GPIO_IN1      6
+
+/* Interrupt pins.
+ */
+
+#define GPIO_IRQPIN1  14
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct rp23xxgpio_dev_s
+{
+  struct gpio_dev_s gpio;
+  uint8_t id;
+};
+
+struct rp23xxgpint_dev_s
+{
+  struct rp23xxgpio_dev_s rp23xxgpio;
+  pin_interrupt_t callback;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+#if BOARD_NGPIOOUT > 0
+static int gpout_read(struct gpio_dev_s *dev, bool *value);
+static int gpout_write(struct gpio_dev_s *dev, bool value);
+#endif
+
+#if BOARD_NGPIOIN > 0
+static int gpin_read(struct gpio_dev_s *dev, bool *value);
+#endif
+
+#if BOARD_NGPIOINT > 0
+static int gpint_read(struct gpio_dev_s *dev, bool *value);
+static int gpint_attach(struct gpio_dev_s *dev,
+                        pin_interrupt_t callback);
+static int gpint_enable(struct gpio_dev_s *dev, bool enable);
+#endif
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+#if BOARD_NGPIOOUT > 0
+static const struct gpio_operations_s gpout_ops =
+{
+  .go_read   = gpout_read,
+  .go_write  = gpout_write,
+  .go_attach = NULL,
+  .go_enable = NULL,
+};
+
+/* This array maps the GPIO pins used as OUTPUT */
+
+static const uint32_t g_gpiooutputs[BOARD_NGPIOOUT] =
+{
+  GPIO_OUT1
+};
+
+static struct rp23xxgpio_dev_s g_gpout[BOARD_NGPIOOUT];
+#endif
+
+#if BOARD_NGPIOIN > 0
+static const struct gpio_operations_s gpin_ops =
+{
+  .go_read   = gpin_read,
+  .go_write  = NULL,
+  .go_attach = NULL,
+  .go_enable = NULL,
+};
+
+/* This array maps the GPIO pins used as INTERRUPT INPUTS */
+
+static const uint32_t g_gpioinputs[BOARD_NGPIOIN] =
+{
+  GPIO_IN1
+};
+
+static struct rp23xxgpio_dev_s g_gpin[BOARD_NGPIOIN];
+#endif
+
+#if BOARD_NGPIOINT > 0
+static const struct gpio_operations_s gpint_ops =
+{
+  .go_read   = gpint_read,
+  .go_write  = NULL,
+  .go_attach = gpint_attach,
+  .go_enable = gpint_enable,
+};
+
+/* This array maps the GPIO pins used as INTERRUPT INPUTS */
+
+static const uint32_t g_gpiointinputs[BOARD_NGPIOINT] =
+{
+  GPIO_IRQPIN1,
+};
+
+static struct rp23xxgpint_dev_s g_gpint[BOARD_NGPIOINT];
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: gpout_read
+ ****************************************************************************/
+
+#if BOARD_NGPIOOUT > 0
+static int gpout_read(struct gpio_dev_s *dev, bool *value)
+{
+  struct rp23xxgpio_dev_s *rp23xxgpio =
+    (struct rp23xxgpio_dev_s *)dev;
+
+  DEBUGASSERT(rp23xxgpio != NULL && value != NULL);
+  DEBUGASSERT(rp23xxgpio->id < BOARD_NGPIOOUT);
+  gpioinfo("Reading...\n");
+
+  *value = rp23xx_gpio_get(g_gpiooutputs[rp23xxgpio->id]);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: gpout_write
+ ****************************************************************************/
+
+static int gpout_write(struct gpio_dev_s *dev, bool value)
+{
+  struct rp23xxgpio_dev_s *rp23xxgpio =
+    (struct rp23xxgpio_dev_s *)dev;
+
+  DEBUGASSERT(rp23xxgpio != NULL);
+  DEBUGASSERT(rp23xxgpio->id < BOARD_NGPIOOUT);
+  gpioinfo("Writing %d\n", (int)value);
+
+  rp23xx_gpio_put(g_gpiooutputs[rp23xxgpio->id], value);
+  return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: gpin_read
+ ****************************************************************************/
+
+#if BOARD_NGPIOIN > 0
+static int gpin_read(struct gpio_dev_s *dev, bool *value)
+{
+  struct rp23xxgpio_dev_s *rp23xxgpio =
+    (struct rp23xxgpio_dev_s *)dev;
+
+  DEBUGASSERT(rp23xxgpio != NULL && value != NULL);
+  DEBUGASSERT(rp23xxgpio->id < BOARD_NGPIOIN);
+  gpioinfo("Reading... pin %d\n", (int)g_gpioinputs[rp23xxgpio->id]);
+
+  *value = rp23xx_gpio_get(g_gpioinputs[rp23xxgpio->id]);
+  return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: rp23xxgpio_interrupt
+ ****************************************************************************/
+
+#if BOARD_NGPIOINT > 0
+static int rp23xxgpio_interrupt(int irq, void *context, void *arg)
+{
+  struct rp23xxgpint_dev_s *rp23xxgpint =
+    (struct rp23xxgpint_dev_s *)arg;
+
+  DEBUGASSERT(rp23xxgpint != NULL && rp23xxgpint->callback != NULL);
+  gpioinfo("Interrupt! callback=%p\n", rp23xxgpint->callback);
+
+  rp23xxgpint->callback(&rp23xxgpint->rp23xxgpio.gpio,
+                       rp23xxgpint->rp23xxgpio.id);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: gpint_read
+ ****************************************************************************/
+
+static int gpint_read(struct gpio_dev_s *dev, bool *value)
+{
+  struct rp23xxgpint_dev_s *rp23xxgpint =
+    (struct rp23xxgpint_dev_s *)dev;
+
+  DEBUGASSERT(rp23xxgpint != NULL && value != NULL);
+  DEBUGASSERT(rp23xxgpint->rp23xxgpio.id < BOARD_NGPIOINT);
+  gpioinfo("Reading int pin...\n");
+
+  *value = rp23xx_gpio_get(g_gpiointinputs[rp23xxgpint->rp23xxgpio.id]);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: gpint_attach
+ ****************************************************************************/
+
+static int gpint_attach(struct gpio_dev_s *dev,
+                        pin_interrupt_t callback)
+{
+  struct rp23xxgpint_dev_s *rp23xxgpint =
+    (struct rp23xxgpint_dev_s *)dev;
+  int irq = g_gpiointinputs[rp23xxgpint->rp23xxgpio.id];
+  int ret;
+
+  gpioinfo("Attaching the callback\n");
+
+  /* Make sure the interrupt is disabled */
+
+  rp23xx_gpio_disable_irq(irq);
+  ret = rp23xx_gpio_irq_attach(irq,
+                               RP23XX_GPIO_INTR_EDGE_LOW,
+                               rp23xxgpio_interrupt,
+                               &g_gpint[rp23xxgpint->rp23xxgpio.id]);
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "ERROR: gpint_attach() failed: %d\n", ret);
+      return ret;
+    }
+
+  gpioinfo("Attach %p\n", callback);
+  rp23xxgpint->callback = callback;
+  return OK;
+}
+
+/****************************************************************************
+ * Name: gpint_enable
+ ****************************************************************************/
+
+static int gpint_enable(struct gpio_dev_s *dev, bool enable)
+{
+  struct rp23xxgpint_dev_s *rp23xxgpint =
+    (struct rp23xxgpint_dev_s *)dev;
+  int irq = g_gpiointinputs[rp23xxgpint->rp23xxgpio.id];
+
+  if (enable)
+    {
+      if (rp23xxgpint->callback != NULL)
+        {
+          gpioinfo("Enabling the interrupt\n");
+
+          /* Configure the interrupt for rising edge */
+
+          rp23xx_gpio_enable_irq(irq);
+        }
+    }
+  else
+    {
+      gpioinfo("Disable the interrupt\n");
+      rp23xx_gpio_disable_irq(irq);
+    }
+
+  return OK;
+}
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: rp23xx_dev_gpio_init
+ ****************************************************************************/
+
+int rp23xx_dev_gpio_init(void)
+{
+  int i;
+  int pincount = 0;
+
+#if BOARD_NGPIOOUT > 0
+  for (i = 0; i < BOARD_NGPIOOUT; i++)
+    {
+      /* Setup and register the GPIO pin */
+
+      g_gpout[i].gpio.gp_pintype = GPIO_OUTPUT_PIN;
+      g_gpout[i].gpio.gp_ops     = &gpout_ops;
+      g_gpout[i].id              = i;
+      gpio_pin_register(&g_gpout[i].gpio, g_gpiooutputs[i]);
+
+      /* Configure the pins that will be used as output */
+
+      rp23xx_gpio_init(g_gpiooutputs[i]);
+      rp23xx_gpio_setdir(g_gpiooutputs[i], true);
+      rp23xx_gpio_put(g_gpiooutputs[i], false);
+
+      pincount++;
+    }
+#endif
+
+  pincount = 0;
+
+#if BOARD_NGPIOIN > 0
+  for (i = 0; i < BOARD_NGPIOIN; i++)
+    {
+      /* Setup and register the GPIO pin */
+
+      g_gpin[i].gpio.gp_pintype = GPIO_INPUT_PIN;
+      g_gpin[i].gpio.gp_ops     = &gpin_ops;
+      g_gpin[i].id              = i;
+      gpio_pin_register(&g_gpin[i].gpio, g_gpioinputs[i]);
+
+      /* Configure the pins that will be used as INPUT */
+
+      rp23xx_gpio_init(g_gpioinputs[i]);
+
+      pincount++;
+    }
+#endif
+
+  pincount = 0;
+
+#if BOARD_NGPIOINT > 0
+  for (i = 0; i < BOARD_NGPIOINT; i++)
+    {
+      /* Setup and register the GPIO pin */
+
+      g_gpint[i].rp23xxgpio.gpio.gp_pintype = GPIO_INTERRUPT_PIN;
+      g_gpint[i].rp23xxgpio.gpio.gp_ops     = &gpint_ops;
+      g_gpint[i].rp23xxgpio.id              = i;
+      gpio_pin_register(&g_gpint[i].rp23xxgpio.gpio, g_gpiointinputs[i]);
+
+      /* Configure the pins that will be used as interrupt input */
+
+      rp23xx_gpio_init(g_gpiointinputs[i]);
+
+      /* pull-up = false : pull-down = true */
+
+      rp23xx_gpio_set_pulls(g_gpiointinputs[i], false, true);
+
+      pincount++;
+    }
+#endif
+
+  return OK;
+}
+#endif /* CONFIG_DEV_GPIO && !CONFIG_GPIO_LOWER_HALF */
diff --git a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_pico.h 
b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_pico.h
new file mode 100644
index 00000000000..d3c656896d4
--- /dev/null
+++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_pico.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+ * boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_pico.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 __BOARDS_ARM_RP23XX_PIMORONI_PICO_PLUS_2_W_SRC_RP23XX_PICO_H
+#define __BOARDS_ARM_RP23XX_PIMORONI_PICO_PLUS_2_W_SRC_RP23XX_PICO_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+/* CYW43439 wireless chip
+ *
+ * The gSPI bus is half duplex -- a single data line carries both directions
+ * and doubles as the chip's interrupt request line.
+ */
+
+#define GPIO_CYW43439_ON      23  /* Drive high to power the chip up   */
+#define GPIO_CYW43439_DATA    24  /* Bidirectional data, also the IRQ  */
+#define GPIO_CYW43439_CS      25  /* Drive low to select the chip      */
+#define GPIO_CYW43439_CLOCK   29  /* gSPI clock                       */
+
+/* LEDs
+ *
+ * The board's only LED hangs off GPIO 0 of the CYW43439, see
+ * include/rp23xx_extra_gpio.h.  There is no LED on an RP2350 pin.
+ */
+
+/* Buttons */
+
+/* Buttons GPIO pins definition */
+
+/* The board's BOOT button doubles as a user button once NuttX is running.
+ * It is active low.  RESET is not readable as a GPIO.
+ */
+
+#define GPIO_BTN_USER1     45
+
+/* Buttons IRQ definitions */
+
+#define MIN_IRQBUTTON     BUTTON_USER1
+#define MAX_IRQBUTTON     BUTTON_USER1
+#define NUM_IRQBUTTONS    (MAX_IRQBUTTON - MIN_IRQBUTTON + 1)
+
+int rp23xx_bringup(void);
+
+#if defined(CONFIG_DEV_GPIO) && !defined(CONFIG_ARCH_BOARD_COMMON)
+int rp23xx_dev_gpio_init(void);
+#endif
+
+#endif /* __BOARDS_ARM_RP23XX_PIMORONI_PICO_PLUS_2_W_SRC_RP23XX_PICO_H */
diff --git a/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_userleds.c 
b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_userleds.c
new file mode 100644
index 00000000000..78981bb2cb3
--- /dev/null
+++ b/boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_userleds.c
@@ -0,0 +1,94 @@
+/****************************************************************************
+ * boards/arm/rp23xx/pimoroni-pico-plus-2-w/src/rp23xx_userleds.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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * The single LED on this board is wired to GPIO 0 of the CYW43439 wireless
+ * chip rather than to a pin of the RP2350, so setting it means sending an
+ * iovar request over the gSPI bus.  Two consequences:
+ *
+ *   - The LED only responds once the wireless chip is running, which happens
+ *     when wlan0 is brought up.  Before that every write fails with -EIO.
+ *   - Writing the LED blocks, so it must not be done from interrupt context.
+ *     That is why this board implements the user LED interface only and not
+ *     the CONFIG_ARCH_LEDS auto-LED interface.
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <debug.h>
+
+#include <nuttx/board.h>
+#include <arch/board/board.h>
+#include <arch/board/rp23xx_extra_gpio.h>
+
+#if defined(CONFIG_RP23XX_INFINEON_CYW43439) && !defined(CONFIG_ARCH_LEDS)
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: board_userled_initialize
+ ****************************************************************************/
+
+uint32_t board_userled_initialize(void)
+{
+  /* Nothing to configure -- the LED lives on the wireless chip, which the
+   * board bringup has already set up.
+   */
+
+  return BOARD_NLEDS;
+}
+
+/****************************************************************************
+ * Name: board_userled
+ ****************************************************************************/
+
+void board_userled(int led, bool ledon)
+{
+  if (led == BOARD_LED1)
+    {
+      int ret = rp23xx_extra_gpio_put(RP23XX_EXTRA_GPIO_LED, ledon);
+
+      if (ret < 0)
+        {
+          lederr("ERROR: cannot reach the LED on the CYW43439: %d\n", ret);
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: board_userled_all
+ ****************************************************************************/
+
+void board_userled_all(uint32_t ledset)
+{
+  board_userled(BOARD_LED1, (ledset & BOARD_LED1_BIT) != 0);
+}
+
+#endif /* CONFIG_RP23XX_INFINEON_CYW43439 && !CONFIG_ARCH_LEDS */

Reply via email to