From 37e39dee58ac4c837962546d8f60db82f23b4bb6 Mon Sep 17 00:00:00 2001 From: Steve Boylan Date: Tue, 24 Sep 2024 11:03:52 -0400 Subject: [PATCH] drivers: wifi: infineon: Add SPI support to AIROC driver Added support for SPI in 4-wire and 3-wire configurations to the Infineon AIROC WiFi driver (drivers/wifi/infineon). Review changes: Move DT_DRV_COMPAT to common header file Correct board-specific preprocessor lines Removed AIROC_MAP_COUNTRY_CODE Move Pico W configuration details to devicetree Use pinctrl to manage shared data/interrupt GPIO Clean up bus selection in Kconfig.airoc Make SDIO and SPI bus struct independent Replace LOG_DBG with LOG_ERR Remove functionally duplicate operation Remove spurious Kconfig option Minor cleanup in CMakeLists.txt Signed-off-by: Steve Boylan --- drivers/wifi/infineon/CMakeLists.txt | 8 +- drivers/wifi/infineon/Kconfig.airoc | 23 +- drivers/wifi/infineon/airoc_whd_hal_common.c | 84 +++++ drivers/wifi/infineon/airoc_whd_hal_common.h | 51 ++++ .../{airoc_whd_hal.c => airoc_whd_hal_sdio.c} | 121 +------- drivers/wifi/infineon/airoc_whd_hal_spi.c | 288 ++++++++++++++++++ drivers/wifi/infineon/airoc_wifi.c | 17 +- drivers/wifi/infineon/airoc_wifi.h | 49 ++- drivers/wifi/infineon/cybsp.h | 13 +- .../wifi-host-driver/CMakeLists.txt | 5 +- 10 files changed, 535 insertions(+), 124 deletions(-) create mode 100644 drivers/wifi/infineon/airoc_whd_hal_common.c create mode 100644 drivers/wifi/infineon/airoc_whd_hal_common.h rename drivers/wifi/infineon/{airoc_whd_hal.c => airoc_whd_hal_sdio.c} (75%) create mode 100644 drivers/wifi/infineon/airoc_whd_hal_spi.c diff --git a/drivers/wifi/infineon/CMakeLists.txt b/drivers/wifi/infineon/CMakeLists.txt index 20f69f18111..ebca6fdc446 100644 --- a/drivers/wifi/infineon/CMakeLists.txt +++ b/drivers/wifi/infineon/CMakeLists.txt @@ -4,8 +4,12 @@ zephyr_include_directories(./) -zephyr_library_sources_ifdef(CONFIG_WIFI_AIROC airoc_wifi.c) -zephyr_library_sources_ifdef(CONFIG_WIFI_AIROC airoc_whd_hal.c) +zephyr_library_sources_ifdef(CONFIG_WIFI_AIROC + airoc_wifi.c + airoc_whd_hal_common.c +) +zephyr_library_sources_ifdef(CONFIG_AIROC_WIFI_BUS_SDIO airoc_whd_hal_sdio.c) +zephyr_library_sources_ifdef(CONFIG_AIROC_WIFI_BUS_SPI airoc_whd_hal_spi.c) zephyr_compile_definitions(CYBSP_WIFI_CAPABLE) zephyr_compile_definitions(CY_RTOS_AWARE) diff --git a/drivers/wifi/infineon/Kconfig.airoc b/drivers/wifi/infineon/Kconfig.airoc index 775396fb245..db83d57b734 100644 --- a/drivers/wifi/infineon/Kconfig.airoc +++ b/drivers/wifi/infineon/Kconfig.airoc @@ -4,20 +4,37 @@ menuconfig WIFI_AIROC bool "Infineon AIROC SoC Wi-Fi support" + depends on DT_HAS_INFINEON_AIROC_WIFI_ENABLED + default y select THREAD_CUSTOM_DATA select WIFI_OFFLOAD + select NET_L2_ETHERNET select NET_L2_WIFI_MGMT - select SDIO_STACK - select SDHC select GPIO select WIFI_USE_NATIVE_NETWORKING select USE_INFINEON_ABSTRACTION_RTOS - depends on DT_HAS_INFINEON_AIROC_WIFI_ENABLED help Enable Infineon AIROC SoC Wi-Fi support. if WIFI_AIROC +config AIROC_WIFI_BUS_SDIO + bool + default y + depends on $(dt_compat_on_bus,$(DT_COMPAT_INFINEON_AIROC_WIFI),sd) + select SDHC + select SDIO_STACK + help + Enable SDIO bus support. + +config AIROC_WIFI_BUS_SPI + bool + default y + depends on $(dt_compat_on_bus,$(DT_COMPAT_INFINEON_AIROC_WIFI),spi) + select SPI + help + Enable SPI bus support + config AIROC_WIFI_EVENT_TASK_STACK_SIZE int "Event Task Stack Size" default 4096 diff --git a/drivers/wifi/infineon/airoc_whd_hal_common.c b/drivers/wifi/infineon/airoc_whd_hal_common.c new file mode 100644 index 00000000000..d98c6532bbb --- /dev/null +++ b/drivers/wifi/infineon/airoc_whd_hal_common.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or + * an affiliate of Cypress Semiconductor Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "airoc_whd_hal_common.h" +#include "airoc_wifi.h" + +#include +#include + +LOG_MODULE_DECLARE(infineon_airoc_wifi, CONFIG_WIFI_LOG_LEVEL); + +#ifdef __cplusplus +extern "C" { +#endif + +/****************************************************** + * Function + ******************************************************/ + +int airoc_wifi_power_on(const struct device *dev) +{ +#if DT_INST_NODE_HAS_PROP(0, wifi_reg_on_gpios) + int ret; + const struct airoc_wifi_config *config = dev->config; + + /* Check WIFI REG_ON gpio instance */ + if (!device_is_ready(config->wifi_reg_on_gpio.port)) { + LOG_ERR("Error: failed to configure wifi_reg_on %s pin %d", + config->wifi_reg_on_gpio.port->name, config->wifi_reg_on_gpio.pin); + return -EIO; + } + + /* Configure wifi_reg_on as output */ + ret = gpio_pin_configure_dt(&config->wifi_reg_on_gpio, GPIO_OUTPUT); + if (ret) { + LOG_ERR("Error %d: failed to configure wifi_reg_on %s pin %d", ret, + config->wifi_reg_on_gpio.port->name, config->wifi_reg_on_gpio.pin); + return ret; + } + ret = gpio_pin_set_dt(&config->wifi_reg_on_gpio, 0); + if (ret) { + return ret; + } + + /* Allow CBUCK regulator to discharge */ + k_msleep(WLAN_CBUCK_DISCHARGE_MS); + + /* WIFI power on */ + ret = gpio_pin_set_dt(&config->wifi_reg_on_gpio, 1); + if (ret) { + return ret; + } + k_msleep(WLAN_POWER_UP_DELAY_MS); +#endif /* DT_INST_NODE_HAS_PROP(0, reg_on_gpios) */ + + return 0; +} + +/* + * Implement WHD memory wrappers + */ + +void *whd_mem_malloc(size_t size) +{ + return k_malloc(size); +} + +void *whd_mem_calloc(size_t nitems, size_t size) +{ + return k_calloc(nitems, size); +} + +void whd_mem_free(void *ptr) +{ + k_free(ptr); +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif diff --git a/drivers/wifi/infineon/airoc_whd_hal_common.h b/drivers/wifi/infineon/airoc_whd_hal_common.h new file mode 100644 index 00000000000..588073d5a39 --- /dev/null +++ b/drivers/wifi/infineon/airoc_whd_hal_common.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or + * an affiliate of Cypress Semiconductor Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +/** Defines the amount of stack memory available for the wifi thread. */ +#if !defined(CY_WIFI_THREAD_STACK_SIZE) +#define CY_WIFI_THREAD_STACK_SIZE (5120) +#endif + +/** Defines the priority of the thread that services wifi packets. Legal values are defined by the + * RTOS being used. + */ +#if !defined(CY_WIFI_THREAD_PRIORITY) +#define CY_WIFI_THREAD_PRIORITY (CY_RTOS_PRIORITY_HIGH) +#endif + +/** Defines the country this will operate in for wifi initialization parameters. See the + * wifi-host-driver's whd_country_code_t for legal options. + */ +#if !defined(CY_WIFI_COUNTRY) +#define CY_WIFI_COUNTRY (WHD_COUNTRY_AUSTRALIA) +#endif + +/** Defines the priority of the interrupt that handles out-of-band notifications from the wifi + * chip. Legal values are defined by the MCU running this code. + */ +#if !defined(CY_WIFI_OOB_INTR_PRIORITY) +#define CY_WIFI_OOB_INTR_PRIORITY (2) +#endif + +/** Defines whether to use the out-of-band pin to allow the WIFI chip to wake up the MCU. */ +#if defined(CY_WIFI_HOST_WAKE_SW_FORCE) +#define CY_USE_OOB_INTR (CY_WIFI_HOST_WAKE_SW_FORCE) +#else +#define CY_USE_OOB_INTR (1u) +#endif /* defined(CY_WIFI_HOST_WAKE_SW_FORCE) */ + +#define CY_WIFI_HOST_WAKE_IRQ_EVENT GPIO_INT_TRIG_LOW +#define DEFAULT_OOB_PIN (0) +#define WLAN_POWER_UP_DELAY_MS (250) +#define WLAN_CBUCK_DISCHARGE_MS (10) + +extern whd_resource_source_t resource_ops; + +int airoc_wifi_power_on(const struct device *dev); diff --git a/drivers/wifi/infineon/airoc_whd_hal.c b/drivers/wifi/infineon/airoc_whd_hal_sdio.c similarity index 75% rename from drivers/wifi/infineon/airoc_whd_hal.c rename to drivers/wifi/infineon/airoc_whd_hal_sdio.c index b3a68102851..4cc522c0319 100644 --- a/drivers/wifi/infineon/airoc_whd_hal.c +++ b/drivers/wifi/infineon/airoc_whd_hal_sdio.c @@ -5,118 +5,36 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include "airoc_wifi.h" +#include "airoc_whd_hal_common.h" #include #include #include #include -#include -#define DT_DRV_COMPAT infineon_airoc_wifi - -LOG_MODULE_REGISTER(infineon_airoc, CONFIG_WIFI_LOG_LEVEL); +LOG_MODULE_DECLARE(infineon_airoc_wifi, CONFIG_WIFI_LOG_LEVEL); #ifdef __cplusplus extern "C" { #endif -/** Defines the amount of stack memory available for the wifi thread. */ -#if !defined(CY_WIFI_THREAD_STACK_SIZE) -#define CY_WIFI_THREAD_STACK_SIZE (5120) -#endif - -/** Defines the priority of the thread that services wifi packets. Legal values are defined by the - * RTOS being used. - */ -#if !defined(CY_WIFI_THREAD_PRIORITY) -#define CY_WIFI_THREAD_PRIORITY (CY_RTOS_PRIORITY_HIGH) -#endif - -/** Defines the country this will operate in for wifi initialization parameters. See the - * wifi-host-driver's whd_country_code_t for legal options. - */ -#if !defined(CY_WIFI_COUNTRY) -#define CY_WIFI_COUNTRY (WHD_COUNTRY_AUSTRALIA) -#endif - -/** Defines the priority of the interrupt that handles out-of-band notifications from the wifi - * chip. Legal values are defined by the MCU running this code. - */ -#if !defined(CY_WIFI_OOB_INTR_PRIORITY) -#define CY_WIFI_OOB_INTR_PRIORITY (2) -#endif - -/** Defines whether to use the out-of-band pin to allow the WIFI chip to wake up the MCU. */ -#if defined(CY_WIFI_HOST_WAKE_SW_FORCE) -#define CY_USE_OOB_INTR (CY_WIFI_HOST_WAKE_SW_FORCE) -#else -#define CY_USE_OOB_INTR (1u) -#endif /* defined(CY_WIFI_HOST_WAKE_SW_FORCE) */ - -#define CY_WIFI_HOST_WAKE_IRQ_EVENT GPIO_INT_TRIG_LOW -#define DEFAULT_OOB_PIN (0) -#define WLAN_POWER_UP_DELAY_MS (250) -#define WLAN_CBUCK_DISCHARGE_MS (10) - -extern whd_resource_source_t resource_ops; - struct whd_bus_priv { whd_sdio_config_t sdio_config; whd_bus_stats_t whd_bus_stats; whd_sdio_t sdio_obj; }; -static whd_init_config_t init_config_default = { - .thread_stack_size = CY_WIFI_THREAD_STACK_SIZE, - .thread_stack_start = NULL, - .thread_priority = (uint32_t)CY_WIFI_THREAD_PRIORITY, - .country = CY_WIFI_COUNTRY -}; +static whd_init_config_t init_config_default = {.thread_stack_size = CY_WIFI_THREAD_STACK_SIZE, + .thread_stack_start = NULL, + .thread_priority = + (uint32_t)CY_WIFI_THREAD_PRIORITY, + .country = CY_WIFI_COUNTRY}; /****************************************************** * Function ******************************************************/ -int airoc_wifi_power_on(const struct device *dev) -{ -#if DT_INST_NODE_HAS_PROP(0, wifi_reg_on_gpios) - int ret; - const struct airoc_wifi_config *config = dev->config; - - /* Check WIFI REG_ON gpio instance */ - if (!device_is_ready(config->wifi_reg_on_gpio.port)) { - LOG_ERR("Error: failed to configure wifi_reg_on %s pin %d", - config->wifi_reg_on_gpio.port->name, config->wifi_reg_on_gpio.pin); - return -EIO; - } - - /* Configure wifi_reg_on as output */ - ret = gpio_pin_configure_dt(&config->wifi_reg_on_gpio, GPIO_OUTPUT); - if (ret) { - LOG_ERR("Error %d: failed to configure wifi_reg_on %s pin %d", ret, - config->wifi_reg_on_gpio.port->name, config->wifi_reg_on_gpio.pin); - return ret; - } - ret = gpio_pin_set_dt(&config->wifi_reg_on_gpio, 0); - if (ret) { - return ret; - } - - /* Allow CBUCK regulator to discharge */ - (void)k_msleep(WLAN_CBUCK_DISCHARGE_MS); - - /* WIFI power on */ - ret = gpio_pin_set_dt(&config->wifi_reg_on_gpio, 1); - if (ret) { - return ret; - } - (void)k_msleep(WLAN_POWER_UP_DELAY_MS); -#endif /* DT_INST_NODE_HAS_PROP(0, reg_on_gpios) */ - - return 0; -} - int airoc_wifi_init_primary(const struct device *dev, whd_interface_t *interface, whd_netif_funcs_t *netif_funcs, whd_buffer_funcs_t *buffer_if) { @@ -144,12 +62,12 @@ int airoc_wifi_init_primary(const struct device *dev, whd_interface_t *interface return -ENODEV; } - if (!device_is_ready(config->sdhc_dev)) { + if (!device_is_ready(config->bus_dev.bus_sdio)) { LOG_ERR("SDHC device is not ready"); return -ENODEV; } - ret = sd_init(config->sdhc_dev, &data->card); + ret = sd_init(config->bus_dev.bus_sdio, &data->card); if (ret) { return ret; } @@ -415,25 +333,6 @@ whd_result_t whd_bus_sdio_enable_oob_intr(whd_driver_t whd_driver, whd_bool_t en return WHD_SUCCESS; } -/* - * Implement WHD memory wrappers - */ - -void *whd_mem_malloc(size_t size) -{ - return k_malloc(size); -} - -void *whd_mem_calloc(size_t nitems, size_t size) -{ - return k_calloc(nitems, size); -} - -void whd_mem_free(void *ptr) -{ - k_free(ptr); -} - #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/drivers/wifi/infineon/airoc_whd_hal_spi.c b/drivers/wifi/infineon/airoc_whd_hal_spi.c new file mode 100644 index 00000000000..d5a631a0f1d --- /dev/null +++ b/drivers/wifi/infineon/airoc_whd_hal_spi.c @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2024 Stephen Boylan (stephen.boylan@beechwoods.com) + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "airoc_whd_hal_common.h" + +#include +#include +#include +#include + +LOG_MODULE_DECLARE(infineon_airoc_wifi, CONFIG_WIFI_LOG_LEVEL); + +#ifdef __cplusplus +extern "C" { +#endif + +struct whd_bus_priv { + whd_spi_config_t spi_config; + whd_spi_t spi_obj; +}; + +static whd_init_config_t init_config_default = {.thread_stack_size = CY_WIFI_THREAD_STACK_SIZE, + .thread_stack_start = NULL, + .thread_priority = + (uint32_t)CY_WIFI_THREAD_PRIORITY, + .country = CY_WIFI_COUNTRY}; + +/****************************************************** + * Function + ******************************************************/ + +int airoc_wifi_init_primary(const struct device *dev, whd_interface_t *interface, + whd_netif_funcs_t *netif_funcs, + whd_buffer_funcs_t *buffer_if) +{ + struct airoc_wifi_data *data = dev->data; + const struct airoc_wifi_config *config = dev->config; + + whd_spi_config_t whd_spi_config = { + .is_spi_normal_mode = WHD_FALSE, + }; + +#if DT_INST_NODE_HAS_PROP(0, wifi_host_wake_gpios) + whd_oob_config_t oob_config = { + .host_oob_pin = (void *)&config->wifi_host_wake_gpio, + .dev_gpio_sel = DEFAULT_OOB_PIN, + .is_falling_edge = + (CY_WIFI_HOST_WAKE_IRQ_EVENT == GPIO_INT_TRIG_LOW) ? WHD_TRUE : WHD_FALSE, + .intr_priority = CY_WIFI_OOB_INTR_PRIORITY}; + whd_spi_config.oob_config = oob_config; +#endif +#if defined(SPI_DATA_IRQ_SHARED) + data->prev_irq_state = 0; +#endif + + /* Pull bus select line low before enabling WiFi chip */ + gpio_pin_configure_dt(&config->bus_select_gpio, GPIO_OUTPUT_INACTIVE); + + if (airoc_wifi_power_on(dev)) { + LOG_ERR("airoc_wifi_power_on returns fail"); + return -ENODEV; + } + + if (!spi_is_ready_dt(&config->bus_dev.bus_spi)) { + LOG_ERR("SPI device is not ready"); + return -ENODEV; + } + + /* Init wifi host driver (whd) */ + cy_rslt_t whd_ret = whd_init(&data->whd_drv, &init_config_default, + &resource_ops, buffer_if, netif_funcs); + if (whd_ret == CY_RSLT_SUCCESS) { + whd_ret = whd_bus_spi_attach(data->whd_drv, &whd_spi_config, + (whd_spi_t)&config->bus_dev.bus_spi); + + if (whd_ret == CY_RSLT_SUCCESS) { + whd_ret = whd_wifi_on(data->whd_drv, interface); + } + + if (whd_ret != CY_RSLT_SUCCESS) { + whd_deinit(*interface); + return -ENODEV; + } + } + return 0; +} + +/* + * Implement SPI Transfer wrapper + */ + +whd_result_t whd_bus_spi_transfer(whd_driver_t whd_driver, const uint8_t *tx, size_t tx_length, + uint8_t *rx, size_t rx_length, uint8_t write_fill) +{ + const struct spi_dt_spec *spi_obj = whd_driver->bus_priv->spi_obj; + int ret; + whd_result_t whd_ret = WHD_SUCCESS; + +#if defined(SPI_DATA_IRQ_SHARED) + ret = whd_bus_spi_irq_enable(whd_driver, false); + if (ret) { + LOG_ERR("whd_bus_spi_irq_enable FAIL %d\n", ret); + whd_ret = WHD_WLAN_SDIO_ERROR; + } +#endif + + /* In some cases whd_bus_spi_protocol.c places the command at */ + /* the start of the rx buffer and passes NULL as the tx address, */ + /* reusing the same buffer (and overwriting the tx data). */ + if (tx == NULL && tx_length > 0 && rx_length >= tx_length) { + tx = rx; + } + + const struct spi_buf tx_buf = {.buf = (uint8_t *)tx, .len = tx_length}; + const struct spi_buf_set tx_set = {.buffers = &tx_buf, .count = 1}; + struct spi_buf rx_buf[2]; + struct spi_buf_set rx_set = {.buffers = rx_buf, .count = 2}; + + if (rx != NULL) { + rx += tx_length; + } + + if (rx_length >= tx_length) { + rx_length -= tx_length; + } else { + rx_length = 0; + } + + if (spi_obj->config.operation & SPI_HALF_DUPLEX) { + rx_buf[0].buf = rx; + rx_buf[0].len = rx_length; + rx_set.count = 1; + } else { + /* Talking to a half-duplex device via a full-duplex SPI driver, */ + /* it's necessary to ignore the data returned during send. The */ + /* SPI driver should not copy out the data if the buffer is NULL. */ + rx_buf[0].buf = NULL; + rx_buf[0].len = tx_length; + rx_buf[1].buf = rx; + rx_buf[1].len = rx_length; + } + + ret = spi_transceive_dt(spi_obj, &tx_set, &rx_set); + if (ret) { + LOG_ERR("spi_transceive FAIL %d\n", ret); + whd_ret = WHD_WLAN_SDIO_ERROR; + } + +#if defined(SPI_DATA_IRQ_SHARED) + ret = whd_bus_spi_irq_enable(whd_driver, true); + if (ret) { + LOG_ERR("whd_bus_spi_irq_enable FAIL %d\n", ret); + whd_ret = WHD_WLAN_SDIO_ERROR; + } +#endif + + return whd_ret; +} + +/* + * Implement OOB functionality + */ + +void whd_bus_spi_oob_irq_handler(const struct device *port, struct gpio_callback *cb, + gpio_port_pins_t pins) +{ +#if DT_INST_NODE_HAS_PROP(0, wifi_host_wake_gpios) + struct airoc_wifi_data *data = CONTAINER_OF(cb, struct airoc_wifi_data, host_oob_pin_cb); + + /* Get OOB pin info */ + const whd_oob_config_t *oob_config = &data->whd_drv->bus_priv->spi_config.oob_config; + const struct gpio_dt_spec *host_oob_pin = oob_config->host_oob_pin; + + /* Check OOB state is correct */ + int expected_event = (oob_config->is_falling_edge == WHD_TRUE) ? 0 : 1; + + if (!(pins & BIT(host_oob_pin->pin)) || (gpio_pin_get_dt(host_oob_pin) != expected_event)) { + WPRINT_WHD_ERROR(("Unexpected interrupt event %d\n", expected_event)); + return; + } + + /* Call thread notify to wake up WHD thread */ + whd_thread_notify_irq(data->whd_drv); + +#endif /* DT_INST_NODE_HAS_PROP(0, wifi-host-wake-gpios) */ +} + +whd_result_t whd_bus_spi_irq_register(whd_driver_t whd_driver) +{ +#if DT_INST_NODE_HAS_PROP(0, wifi_host_wake_gpios) + int ret; + const struct device *dev = DEVICE_DT_GET(DT_DRV_INST(0)); + struct airoc_wifi_data *data = dev->data; + + /* Get OOB pin info */ + const whd_oob_config_t *oob_config = &whd_driver->bus_priv->spi_config.oob_config; + const struct gpio_dt_spec *host_oob_pin = oob_config->host_oob_pin; + + /* Check if OOB pin is ready */ + if (!gpio_is_ready_dt(host_oob_pin)) { + WPRINT_WHD_ERROR(("%s: Failed at gpio_is_ready_dt for host_oob_pin\n", __func__)); + return WHD_HAL_ERROR; + } + + /* Configure OOB pin as input */ + ret = gpio_pin_configure_dt(host_oob_pin, GPIO_INPUT); + if (ret != 0) { + WPRINT_WHD_ERROR(( + " %s: Failed at gpio_pin_configure_dt for host_oob_pin, result code = %d\n", + __func__, ret)); + return WHD_HAL_ERROR; + } + + /* Initialize/add OOB pin callback */ + gpio_init_callback(&data->host_oob_pin_cb, whd_bus_spi_oob_irq_handler, + BIT(host_oob_pin->pin)); + + ret = gpio_add_callback_dt(host_oob_pin, &data->host_oob_pin_cb); + if (ret != 0) { + WPRINT_WHD_ERROR( + ("%s: Failed at gpio_add_callback_dt for host_oob_pin, result code = %d\n", + __func__, ret)); + return WHD_HAL_ERROR; + } +#endif /* DT_INST_NODE_HAS_PROP(0, wifi_host_wake_gpios) */ + + return WHD_SUCCESS; +} + +whd_result_t whd_bus_spi_irq_enable(whd_driver_t whd_driver, whd_bool_t enable) +{ +#if DT_INST_NODE_HAS_PROP(0, wifi_host_wake_gpios) + int ret; + const whd_oob_config_t *oob_config = &whd_driver->bus_priv->spi_config.oob_config; + struct gpio_dt_spec *gpio = (struct gpio_dt_spec *)oob_config->host_oob_pin; + +#if defined(SPI_DATA_IRQ_SHARED) + const struct device *dev = DEVICE_DT_INST_GET(0); + const struct airoc_wifi_config *config = dev->config; + struct airoc_wifi_data *data = dev->data; + + if (enable) { + ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_HOST_WAKE); + __ASSERT(ret == 0, "could not apply pinconfig, return code %d", ret); + ret = gpio_pin_interrupt_configure_dt( + gpio, (oob_config->is_falling_edge == WHD_TRUE) ? GPIO_INT_EDGE_FALLING + : GPIO_INT_EDGE_RISING); + __ASSERT(ret == 0, "gpio_pin_interrupt_configure_dt failed, return code %d", ret); + + int state = gpio_pin_get_dt(gpio); + int expected_event = (oob_config->is_falling_edge == WHD_TRUE) ? 0 : 1; + + /* Notify only if interrupt wasn't assert before. This code assumes that if */ + /* the interrupt was previously asserted, then the thread has already been */ + /* notified. */ + if (state == expected_event && state != data->prev_irq_state) { + whd_thread_notify_irq(whd_driver); + } + } else { + data->prev_irq_state = gpio_pin_get_dt(gpio); + ret = gpio_pin_interrupt_configure_dt(gpio, GPIO_INT_DISABLE); + __ASSERT(ret == 0, "gpio_pin_interrupt_configure_dt failed, return code %d", ret); + pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); + } +#else + if (enable) { + ret = gpio_pin_interrupt_configure_dt( + gpio, (oob_config->is_falling_edge == WHD_TRUE) ? GPIO_INT_EDGE_FALLING + : GPIO_INT_EDGE_RISING); + __ASSERT(ret == 0, "gpio_pin_interrupt_configure_dt failed, return code %d", ret); + } else { + ret = gpio_pin_interrupt_configure_dt(gpio, GPIO_INT_DISABLE); + __ASSERT(ret == 0, "gpio_pin_interrupt_configure_dt failed, return code %d", ret); + } +#endif /* defined(SPI_DATA_IRQ_SHARED) */ + +#endif /* DT_INST_NODE_HAS_PROP(0, wifi_host_wake_gpios) */ + + return WHD_SUCCESS; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif diff --git a/drivers/wifi/infineon/airoc_wifi.c b/drivers/wifi/infineon/airoc_wifi.c index 330227fd359..7960dee75be 100644 --- a/drivers/wifi/infineon/airoc_wifi.c +++ b/drivers/wifi/infineon/airoc_wifi.c @@ -9,11 +9,10 @@ * @brief AIROC Wi-Fi driver. */ -#define DT_DRV_COMPAT infineon_airoc_wifi - #include #include #include +#include LOG_MODULE_REGISTER(infineon_airoc_wifi, CONFIG_WIFI_LOG_LEVEL); @@ -76,8 +75,20 @@ static uint16_t sta_event_handler_index = 0xFF; static void airoc_event_task(void); static struct airoc_wifi_data airoc_wifi_data = {0}; +#if defined(SPI_DATA_IRQ_SHARED) +PINCTRL_DT_INST_DEFINE(0); +#endif + static struct airoc_wifi_config airoc_wifi_config = { - .sdhc_dev = DEVICE_DT_GET(DT_INST_PARENT(0)), +#if defined(CONFIG_AIROC_WIFI_BUS_SDIO) + .bus_dev.bus_sdio = DEVICE_DT_GET(DT_INST_PARENT(0)), +#elif defined(CONFIG_AIROC_WIFI_BUS_SPI) + .bus_dev.bus_spi = SPI_DT_SPEC_GET(DT_DRV_INST(0), AIROC_WIFI_SPI_OPERATION, 0), + .bus_select_gpio = GPIO_DT_SPEC_GET_OR(DT_DRV_INST(0), bus_select_gpios, {0}), +#if defined(SPI_DATA_IRQ_SHARED) + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0), +#endif +#endif .wifi_reg_on_gpio = GPIO_DT_SPEC_GET_OR(DT_DRV_INST(0), wifi_reg_on_gpios, {0}), .wifi_host_wake_gpio = GPIO_DT_SPEC_GET_OR(DT_DRV_INST(0), wifi_host_wake_gpios, {0}), .wifi_dev_wake_gpio = GPIO_DT_SPEC_GET_OR(DT_DRV_INST(0), wifi_dev_wake_gpios, {0}), diff --git a/drivers/wifi/infineon/airoc_wifi.h b/drivers/wifi/infineon/airoc_wifi.h index 1bf688e5d72..8b308e36414 100644 --- a/drivers/wifi/infineon/airoc_wifi.h +++ b/drivers/wifi/infineon/airoc_wifi.h @@ -6,16 +6,44 @@ */ #include -#include -#include #include #include + +#ifdef CONFIG_AIROC_WIFI_BUS_SDIO +#include +#include +#endif +#ifdef CONFIG_AIROC_WIFI_BUS_SPI +#include +#endif + #include +#define DT_DRV_COMPAT infineon_airoc_wifi + +#if DT_PROP(DT_DRV_INST(0), spi_data_irq_shared) +#define SPI_DATA_IRQ_SHARED +#include + +#define PINCTRL_STATE_HOST_WAKE PINCTRL_STATE_PRIV_START +#endif + +#if defined(CONFIG_AIROC_WIFI_BUS_SPI) +#define AIROC_WIFI_SPI_OPERATION (SPI_WORD_SET(DT_PROP_OR(DT_DRV_INST(0), spi_word_size, 8)) \ + | (DT_PROP(DT_DRV_INST(0), spi_half_duplex) \ + ? SPI_HALF_DUPLEX : SPI_FULL_DUPLEX) \ + | SPI_TRANSFER_MSB) +#endif + struct airoc_wifi_data { +#if defined(CONFIG_AIROC_WIFI_BUS_SDIO) struct sd_card card; struct sdio_func sdio_func1; struct sdio_func sdio_func2; +#endif +#if defined(SPI_DATA_IRQ_SHARED) + uint8_t prev_irq_state; +#endif struct net_if *iface; bool second_interface_init; bool is_ap_up; @@ -34,11 +62,26 @@ struct airoc_wifi_data { uint8_t frame_buf[NET_ETH_MAX_FRAME_SIZE]; }; +union airoc_wifi_bus { +#if defined(CONFIG_AIROC_WIFI_BUS_SDIO) + const struct device *bus_sdio; +#endif +#if defined(CONFIG_AIROC_WIFI_BUS_SPI) + const struct spi_dt_spec bus_spi; +#endif +}; + struct airoc_wifi_config { - const struct device *sdhc_dev; + const union airoc_wifi_bus bus_dev; struct gpio_dt_spec wifi_reg_on_gpio; struct gpio_dt_spec wifi_host_wake_gpio; struct gpio_dt_spec wifi_dev_wake_gpio; +#if defined(CONFIG_AIROC_WIFI_BUS_SPI) + struct gpio_dt_spec bus_select_gpio; +#if defined(SPI_DATA_IRQ_SHARED) + const struct pinctrl_dev_config *pcfg; +#endif +#endif }; /** diff --git a/drivers/wifi/infineon/cybsp.h b/drivers/wifi/infineon/cybsp.h index dfa23ffbae5..ef3712443d7 100644 --- a/drivers/wifi/infineon/cybsp.h +++ b/drivers/wifi/infineon/cybsp.h @@ -5,4 +5,15 @@ * SPDX-License-Identifier: Apache-2.0 */ -/* This is enpty/stub file used in WHD */ +/* required by whd_* header files. */ + +/* See cybsp_types.h, which is usually required by this file, but not available */ +/* here unless we pull in board-specific headers from the upstream driver. */ +#define CYBSP_SDIO_INTERFACE (0) +#define CYBSP_SPI_INTERFACE (1) + +#ifdef CONFIG_AIROC_WIFI_BUS_SDIO +#define CYBSP_WIFI_INTERFACE_TYPE CYBSP_SDIO_INTERFACE +#elif CONFIG_AIROC_WIFI_BUS_SPI +#define CYBSP_WIFI_INTERFACE_TYPE CYBSP_SPI_INTERFACE +#endif diff --git a/modules/hal_infineon/wifi-host-driver/CMakeLists.txt b/modules/hal_infineon/wifi-host-driver/CMakeLists.txt index 010518f1642..7f6d9420862 100644 --- a/modules/hal_infineon/wifi-host-driver/CMakeLists.txt +++ b/modules/hal_infineon/wifi-host-driver/CMakeLists.txt @@ -49,7 +49,10 @@ zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/whd_wifi_p2p.c) # src/bus_protocols zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/bus_protocols/whd_bus.c) zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/bus_protocols/whd_bus_common.c) -zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/src/bus_protocols/whd_bus_sdio_protocol.c) +zephyr_library_sources_ifdef(CONFIG_AIROC_WIFI_BUS_SDIO + ${hal_wifi_dir}/WiFi_Host_Driver/src/bus_protocols/whd_bus_sdio_protocol.c) +zephyr_library_sources_ifdef(CONFIG_AIROC_WIFI_BUS_SPI + ${hal_wifi_dir}/WiFi_Host_Driver/src/bus_protocols/whd_bus_spi_protocol.c) # resources/resource_imp zephyr_library_sources(${hal_wifi_dir}/WiFi_Host_Driver/resources/resource_imp/whd_resources.c)