diff --git a/drivers/mdio/CMakeLists.txt b/drivers/mdio/CMakeLists.txt index 5e1718cc8f..4a16b4c36c 100644 --- a/drivers/mdio/CMakeLists.txt +++ b/drivers/mdio/CMakeLists.txt @@ -4,3 +4,4 @@ zephyr_library() zephyr_library_sources_ifdef(CONFIG_MDIO_SHELL mdio_shell.c) zephyr_library_sources_ifdef(CONFIG_MDIO_ATMEL_SAM mdio_sam.c) +zephyr_library_sources_ifdef(CONFIG_MDIO_ESP32 mdio_esp32.c) diff --git a/drivers/mdio/Kconfig b/drivers/mdio/Kconfig index 3bf3b2116d..15fbead025 100644 --- a/drivers/mdio/Kconfig +++ b/drivers/mdio/Kconfig @@ -25,6 +25,7 @@ config MDIO_SHELL # Include these first so that any properties (e.g. defaults) below can be # overridden (by defining symbols in multiple locations) +source "drivers/mdio/Kconfig.esp32" source "drivers/mdio/Kconfig.sam" config MDIO_INIT_PRIORITY diff --git a/drivers/mdio/Kconfig.esp32 b/drivers/mdio/Kconfig.esp32 new file mode 100644 index 0000000000..39c98eaa3b --- /dev/null +++ b/drivers/mdio/Kconfig.esp32 @@ -0,0 +1,9 @@ +# Copyright (c) 2022 Grant Ramsay +# SPDX-License-Identifier: Apache-2.0 + +config MDIO_ESP32 + bool "ESP32 MDIO driver" + depends on SOC_ESP32 + default y + help + Enable ESP32 MCU Family MDIO driver. diff --git a/drivers/mdio/mdio_esp32.c b/drivers/mdio/mdio_esp32.c new file mode 100644 index 0000000000..49186d3243 --- /dev/null +++ b/drivers/mdio/mdio_esp32.c @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2022 Grant Ramsay + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT espressif_esp32_mdio + +#include +#include +#include +#include +#include + +#include +#include +#include + +LOG_MODULE_REGISTER(mdio_esp32, CONFIG_MDIO_LOG_LEVEL); + +#define PHY_OPERATION_TIMEOUT_US 1000 + +struct mdio_esp32_dev_data { + struct k_sem sem; + emac_hal_context_t hal; +}; + +struct mdio_esp32_dev_config { + const struct pinctrl_dev_config *pcfg; +}; + +static int mdio_transfer(const struct device *dev, uint8_t prtad, uint8_t devad, + bool write, uint16_t data_in, uint16_t *data_out) +{ + struct mdio_esp32_dev_data *const dev_data = dev->data; + + k_sem_take(&dev_data->sem, K_FOREVER); + + if (emac_ll_is_mii_busy(dev_data->hal.mac_regs)) { + LOG_ERR("phy busy"); + k_sem_give(&dev_data->sem); + return -EBUSY; + } + + if (write) { + emac_ll_set_phy_data(dev_data->hal.mac_regs, data_in); + } + emac_hal_set_phy_cmd(&dev_data->hal, prtad, devad, write); + + /* Poll until operation complete */ + bool success = false; + + for (uint32_t t_us = 0; t_us < PHY_OPERATION_TIMEOUT_US; t_us += 100) { + k_sleep(K_USEC(100)); + if (!emac_ll_is_mii_busy(dev_data->hal.mac_regs)) { + success = true; + break; + } + } + if (!success) { + LOG_ERR("phy timeout"); + k_sem_give(&dev_data->sem); + return -ETIMEDOUT; + } + + if (!write && data_out != NULL) { + *data_out = emac_ll_get_phy_data(dev_data->hal.mac_regs); + } + + k_sem_give(&dev_data->sem); + + return 0; +} + +static int mdio_esp32_read(const struct device *dev, uint8_t prtad, uint8_t devad, + uint16_t *data) +{ + return mdio_transfer(dev, prtad, devad, false, 0, data); + +} + +static int mdio_esp32_write(const struct device *dev, uint8_t prtad, + uint8_t devad, uint16_t data) +{ + return mdio_transfer(dev, prtad, devad, true, data, NULL); +} + +static void mdio_esp32_bus_enable(const struct device *dev) +{ + ARG_UNUSED(dev); +} + +static void mdio_esp32_bus_disable(const struct device *dev) +{ + ARG_UNUSED(dev); +} + +static int mdio_esp32_initialize(const struct device *dev) +{ + const struct mdio_esp32_dev_config *const cfg = dev->config; + struct mdio_esp32_dev_data *const dev_data = dev->data; + int res; + + k_sem_init(&dev_data->sem, 1, 1); + + res = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); + if (res != 0) { + goto err; + } + + const struct device *clock_dev = + DEVICE_DT_GET(DT_CLOCKS_CTLR(DT_NODELABEL(mdio))); + clock_control_subsys_t clock_subsys = + (clock_control_subsys_t)DT_CLOCKS_CELL(DT_NODELABEL(mdio), offset); + + res = clock_control_on(clock_dev, clock_subsys); + if (res != 0) { + goto err; + } + + /* Only the mac registers are required for MDIO */ + dev_data->hal.mac_regs = &EMAC_MAC; + + /* Init MDIO clock */ + emac_hal_set_csr_clock_range(&dev_data->hal, esp_clk_apb_freq()); + + return 0; + +err: + return res; +} + +static const struct mdio_driver_api mdio_esp32_driver_api = { + .read = mdio_esp32_read, + .write = mdio_esp32_write, + .bus_enable = mdio_esp32_bus_enable, + .bus_disable = mdio_esp32_bus_disable, +}; + +#define MDIO_ESP32_CONFIG(n) \ +static const struct mdio_esp32_dev_config mdio_esp32_dev_config_##n = { \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ +}; + +#define MDIO_ESP32_PROTOCOL_ASSERT(n) \ + BUILD_ASSERT(DT_INST_ENUM_IDX(n, protocol) == CLAUSE_22, \ + "ESP32 MDIO only supports CLAUSE_22 protocol") + +#define MDIO_ESP32_DEVICE(n) \ + MDIO_ESP32_PROTOCOL_ASSERT(n); \ + PINCTRL_DT_INST_DEFINE(n); \ + MDIO_ESP32_CONFIG(n); \ + static struct mdio_esp32_dev_data mdio_esp32_dev_data##n; \ + DEVICE_DT_INST_DEFINE(n, \ + &mdio_esp32_initialize, \ + NULL, \ + &mdio_esp32_dev_data##n, \ + &mdio_esp32_dev_config_##n, POST_KERNEL, \ + CONFIG_MDIO_INIT_PRIORITY, \ + &mdio_esp32_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(MDIO_ESP32_DEVICE) diff --git a/drivers/mdio/mdio_shell.c b/drivers/mdio/mdio_shell.c index 972f1e222f..6e7d274ef5 100644 --- a/drivers/mdio/mdio_shell.c +++ b/drivers/mdio/mdio_shell.c @@ -14,7 +14,15 @@ #include LOG_MODULE_REGISTER(mdio_shell, CONFIG_LOG_DEFAULT_LEVEL); -#define MDIO_NODE_ID DT_COMPAT_GET_ANY_STATUS_OKAY(atmel_sam_mdio) +#if DT_HAS_COMPAT_STATUS_OKAY(atmel_sam_mdio) +#define DT_DRV_COMPAT atmel_sam_mdio +#elif DT_HAS_COMPAT_STATUS_OKAY(espressif_esp32_mdio) +#define DT_DRV_COMPAT espressif_esp32_mdio +#else +#error "No known devicetree compatible match for MDIO shell" +#endif + +#define MDIO_NODE_ID DT_COMPAT_GET_ANY_STATUS_OKAY(DT_DRV_COMPAT) /* * Scan the entire 5-bit address space of the MDIO bus diff --git a/dts/bindings/mdio/espressif,esp32-mdio.yaml b/dts/bindings/mdio/espressif,esp32-mdio.yaml new file mode 100644 index 0000000000..a6405e4f37 --- /dev/null +++ b/dts/bindings/mdio/espressif,esp32-mdio.yaml @@ -0,0 +1,10 @@ +# Copyright (c) 2022 Grant Ramsay +# SPDX-License-Identifier: Apache-2.0 + +description: ESP32 MDIO Driver node + +compatible: "espressif,esp32-mdio" + +include: + - name: mdio-controller.yaml + - name: pinctrl-device.yaml diff --git a/dts/xtensa/espressif/esp32.dtsi b/dts/xtensa/espressif/esp32.dtsi index b29f7f374e..824a946893 100644 --- a/dts/xtensa/espressif/esp32.dtsi +++ b/dts/xtensa/espressif/esp32.dtsi @@ -42,6 +42,13 @@ status = "disabled"; }; + mdio: mdio { + compatible = "espressif,esp32-mdio"; + protocol = "clause 22"; + clocks = <&rtc ESP32_EMAC_MODULE>; + status = "disabled"; + }; + pinctrl: pin-controller { compatible = "espressif,esp32-pinctrl"; status = "okay";