Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

drivers: misc: Add support for WIZ550io module #69696

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions boards/shields/wiznet_wiz550io/Kconfig.defconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Copyright (c) 2024 Grant Ramsay
# SPDX-License-Identifier: Apache-2.0

if SHIELD_WIZNET_WIZ550IO

if NETWORKING

config NET_L2_ETHERNET
default y

endif # NETWORKING

endif # SHIELD_WIZNET_WIZ550IO
5 changes: 5 additions & 0 deletions boards/shields/wiznet_wiz550io/Kconfig.shield
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Copyright (c) 2024 Grant Ramsay
# SPDX-License-Identifier: Apache-2.0

config SHIELD_WIZNET_WIZ550IO
def_bool $(shields_list_contains,wiznet_wiz550io)
63 changes: 63 additions & 0 deletions boards/shields/wiznet_wiz550io/doc/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
.. _wiznet_wiz550io:

WIZnet WIZ550io
###############

Overview
********

WIZnet `WIZ550io`_ is a W5500 Ethernet breakout board with an extra PIC12F519
MCU. The PIC12F519 MCU initialises the W5500 with a unique MAC address after
a GPIO reset.

`W5500`_ is 10/100 MBPS stand alone Ethernet controller with on-board MAC &
PHY, 16 KiloBytes for FIFO buffer and SPI serial interface.

Pins Assignment of the WIZ550io Shield
======================================

+-----------------------+---------------------------------------------+
| Shield Connector Pin | Function |
+=======================+=============================================+
| RST# | Ethernet Controller's Reset |
+-----------------------+---------------------------------------------+
| CS# | SPI's Chip Select |
+-----------------------+---------------------------------------------+
| SCK | SPI's ClocK |
+-----------------------+---------------------------------------------+
| SDO | SPI's Slave Data Output (MISO) |
+-----------------------+---------------------------------------------+
| SDI | SPI's Slave Data Input (MISO) |
+-----------------------+---------------------------------------------+
| INT | Ethernet Controller's Interrupt Output |
+-----------------------+---------------------------------------------+
| RDY | WIZ550io Ready Output |
+-----------------------+---------------------------------------------+

Requirements
************

This shield/breakout board can be used with any board with SPI interfaces in
Arduino header or custom header (by adjusting the overlay).

Programming
***********

Set ``-DSHIELD=wiznet_wiz550io`` when you invoke ``west build``. For example:

.. zephyr-app-commands::
:zephyr-app: samples/net/dhcpv4_client
:board: nrf52840dk/nrf52840
:shield: wiznet_wiz550io
:goals: build

References
**********

.. target-notes::

.. _WIZ550io:
https://wiznet.io/products/network-modules/wiz550io

.. _W5500:
https://wiznet.io/products/iethernet-chips/w5500
25 changes: 25 additions & 0 deletions boards/shields/wiznet_wiz550io/wiznet_wiz550io.overlay
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/* Copyright (c) 2024 Grant Ramsay
* SPDX-License-Identifier: Apache-2.0
*/

&arduino_spi {
status = "okay";

eth_w5500: eth_w5500@0 {
compatible = "wiznet,w5500";
reg = <0x0>;
/* Note: Reducing spi-max-frequency may help with errors/stability */
spi-max-frequency = <DT_FREQ_M(80)>;
int-gpios = <&arduino_header 15 GPIO_ACTIVE_LOW>; /* D9 */
/* Do not put the reset-gpios property here */
};
};

/ {
wiz550io {
compatible = "wiznet,wiz550io";
wiznet,w5500 = <&eth_w5500>;
reset-gpios = <&arduino_header 14 GPIO_ACTIVE_LOW>; /* D8 */
ready-gpios = <&arduino_header 13 GPIO_ACTIVE_HIGH>; /* D7 */
};
};
4 changes: 2 additions & 2 deletions drivers/ethernet/eth_w5500.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ LOG_MODULE_REGISTER(eth_w5500, CONFIG_ETHERNET_LOG_LEVEL);
#define W5500_SPI_WRITE_CONTROL(addr) \
((W5500_SPI_BLOCK_SELECT(addr) << 3) | BIT(2))

static int w5500_spi_read(const struct device *dev, uint32_t addr,
uint8_t *data, uint32_t len)
int w5500_spi_read(const struct device *dev, uint32_t addr,
uint8_t *data, uint32_t len)
{
const struct w5500_config *cfg = dev->config;
int ret;
Expand Down
3 changes: 3 additions & 0 deletions drivers/ethernet/eth_w5500_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,4 +100,7 @@ struct w5500_runtime {
uint8_t buf[NET_ETH_MAX_FRAME_SIZE];
};

int w5500_spi_read(const struct device *dev, uint32_t addr,
uint8_t *data, uint32_t len);

#endif /*_W5500_*/
1 change: 1 addition & 0 deletions drivers/misc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ add_subdirectory_ifdef(CONFIG_TIMEAWARE_GPIO timeaware_gpio)
add_subdirectory_ifdef(CONFIG_DEVMUX devmux)
add_subdirectory_ifdef(CONFIG_NORDIC_VPR_LAUNCHER nordic_vpr_launcher)
add_subdirectory_ifdef(CONFIG_MCUX_FLEXIO mcux_flexio)
add_subdirectory_ifdef(CONFIG_WIZ550IO wiz550io)
1 change: 1 addition & 0 deletions drivers/misc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@ source "drivers/misc/timeaware_gpio/Kconfig"
source "drivers/misc/devmux/Kconfig"
source "drivers/misc/nordic_vpr_launcher/Kconfig"
source "drivers/misc/mcux_flexio/Kconfig"
source "drivers/misc/wiz550io/Kconfig"

endmenu
9 changes: 9 additions & 0 deletions drivers/misc/wiz550io/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Copyright (c) 2024 Grant Ramsay
# SPDX-License-Identifier: Apache-2.0

zephyr_library()

# Allow access to private W5500 Ethernet header
zephyr_library_include_directories(${ZEPHYR_BASE}/drivers/ethernet)

zephyr_library_sources(wiz550io.c)
24 changes: 24 additions & 0 deletions drivers/misc/wiz550io/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# WIZ550io (W5500 Ethernet) driver configuration options

# Copyright (c) 2024 Grant Ramsay
# SPDX-License-Identifier: Apache-2.0

menuconfig WIZ550IO
bool "WIZ550io (W5500 Ethernet) driver"
default y
depends on DT_HAS_WIZNET_WIZ550IO_ENABLED && ETH_W5500
help
This driver provides the initialsation sequence required for
WIZ550io to configure the W5500 Ethernet controller with its
embedded unique MAC address.

if WIZ550IO

config WIZ550IO_INIT_PRIORITY
int "WIZ550io init priority"
default 79
help
WIZ550io init must occur before W5500 init.
The default is ETH_INIT_PRIORITY - 1.

endif # WIZ550IO
136 changes: 136 additions & 0 deletions drivers/misc/wiz550io/wiz550io.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/*
* Copyright (c) 2024 Grant Ramsay
*
* SPDX-License-Identifier: Apache-2.0
*
* This driver provides the initialsation sequence required for
* WIZ550io to configure the W5500 Ethernet controller with its
* embedded unique MAC address.
*/

#define DT_DRV_COMPAT wiznet_wiz550io

#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(eth_w5500, CONFIG_ETHERNET_LOG_LEVEL);

#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/spi.h>
#include <zephyr/net/ethernet.h>

#include "eth_w5500_priv.h"

struct wiz550io_config {
const struct device *w5500_dev;
struct gpio_dt_spec reset;
struct gpio_dt_spec ready;
};

/* WIZ550io documentation recommends 150ms delay after HW reset
* for PIC12F519 MCU to configure the W5500.
*/
#define WIZ550IO_RESET_DELAY K_MSEC(150)

static int wiz550io_init(const struct wiz550io_config *config)
{
int err;
const struct w5500_config *w5500_config = config->w5500_dev->config;
struct w5500_runtime *w5500_runtime = config->w5500_dev->data;

if (!spi_is_ready_dt(&w5500_config->spi)) {
LOG_ERR("SPI master port %s not ready", w5500_config->spi.bus->name);
return -EINVAL;
}

if (!gpio_is_ready_dt(&config->reset)) {
LOG_ERR("GPIO port %s not ready", config->reset.port->name);
return -EINVAL;
}

if (gpio_pin_configure_dt(&config->reset, GPIO_OUTPUT)) {
LOG_ERR("Unable to configure GPIO pin %u", config->reset.pin);
return -EINVAL;
}

/* Hold reset pin low for 500us to perform a hardware reset */
gpio_pin_set_dt(&config->reset, 1);
k_usleep(500);
gpio_pin_set_dt(&config->reset, 0);

/* Wait for the device to be ready */
if (config->ready.port) {
if (!gpio_is_ready_dt(&config->ready)) {
LOG_ERR("GPIO port %s not ready", config->ready.port->name);
return -EINVAL;
}
if (gpio_pin_configure_dt(&config->ready, GPIO_INPUT)) {
LOG_ERR("Unable to configure GPIO pin %u", config->ready.pin);
return -EINVAL;
}

k_timepoint_t timeout = sys_timepoint_calc(WIZ550IO_RESET_DELAY);

while (!gpio_pin_get_dt(&config->ready)) {
if (sys_timepoint_expired(timeout)) {
LOG_ERR("WIZ550io not ready");
return -ETIMEDOUT;
}
k_msleep(1);
}
} else {
k_sleep(WIZ550IO_RESET_DELAY);
}

/* Read/assign the WIZ550io unique MAC address set by the PIC12F519
* after hardware reset. It needs to be read after a hardware reset
* and before software reset.
*/
err = w5500_spi_read(config->w5500_dev, W5500_SHAR,
w5500_runtime->mac_addr,
sizeof(w5500_runtime->mac_addr));
if (err) {
LOG_ERR("WIZ550io unable to read MAC address");
return -EIO;
}

LOG_INF("%s MAC set to %02x:%02x:%02x:%02x:%02x:%02x",
config->w5500_dev->name,
w5500_runtime->mac_addr[0], w5500_runtime->mac_addr[1],
w5500_runtime->mac_addr[2], w5500_runtime->mac_addr[3],
w5500_runtime->mac_addr[4], w5500_runtime->mac_addr[5]);

return 0;
}

static int wiz550io_init_all(void)
{
int res;

#define W5500_NODE(inst) DT_INST_PHANDLE(inst, wiznet_w5500)

#define WIZ550IO_INIT(inst) \
BUILD_ASSERT(!DT_NODE_HAS_PROP(W5500_NODE(inst), reset_gpios), \
"The reset-gpios property must be assigned to WIZ550io " \
"rather than the W5500 device"); \
\
static const struct wiz550io_config wiz550io_config_##inst = { \
.w5500_dev = DEVICE_DT_GET(W5500_NODE(inst)), \
.reset = GPIO_DT_SPEC_INST_GET(inst, reset_gpios), \
.ready = GPIO_DT_SPEC_INST_GET_OR(inst, ready_gpios, { 0 }), \
}; \
\
res = wiz550io_init(&wiz550io_config_##inst); \
if (res != 0) { \
return res; \
}

DT_INST_FOREACH_STATUS_OKAY(WIZ550IO_INIT)

return 0;
}

BUILD_ASSERT(CONFIG_WIZ550IO_INIT_PRIORITY < CONFIG_ETH_INIT_PRIORITY,
"WIZ550io init must occur before W5500 init");

SYS_INIT(wiz550io_init_all, POST_KERNEL, CONFIG_WIZ550IO_INIT_PRIORITY);
36 changes: 36 additions & 0 deletions dts/bindings/misc/wiznet,wiz550io.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Copyright (c) 2024 Grant Ramsay
# SPDX-License-Identifier: Apache-2.0

description: |
WIZnet WIZ550io - W5500 Ethernet controller.
WIZ550io contains a W5500 Ethernet controller with an extra PIC12F519 MCU.
The PIC12F519 MCU initialises the W5500 with a unique MAC address after a
GPIO reset. The unique MAC address is used if neither
"zephyr,random-mac-address" or "local-mac-address" properties are
configured in the corresponding W5500 device.

compatible: "wiznet,wiz550io"

include: base.yaml

properties:
wiznet,w5500:
type: phandle
required: true
description: The corresponding W5500 device within the WIZ550io module
reset-gpios:
type: phandle-array
required: true
description: |
Reset pin (active low output).
The reset-gpios property must be assigned to WIZ550io rather than
the W5500 device. The hardware reset pin is required for WIZ550io,
as a software reset of W5500 will clear the MAC address assigned
by the PIC12F519.
ready-gpios:
type: phandle-array
description: |
Ready pin (active high input).
Optional GPIO pin that signals when the PIC12F519 has finished
configuring the W5500. Enabling this reduces the 150ms delay
after GPIO reset.
Loading