From e2d2872e46753f17f4a3fc13a98cf8eafe8069ca Mon Sep 17 00:00:00 2001 From: Bogdan Kolendovskyy Date: Mon, 25 Nov 2024 14:07:07 +0100 Subject: [PATCH] Migrate KSZ8863 driver to new I2C driver implementation Closes https://github.com/espressif/esp-eth-drivers/issues/45 Closes https://github.com/espressif/esp-eth-drivers/issues/20 --- ksz8863/README.md | 4 +- .../simple_switch/main/simple_switch_main.c | 38 ++++---- .../examples/switch_mode/main/switch_main.c | 38 ++++---- .../two_ports_mode/main/two_ports_main.c | 38 ++++---- ksz8863/idf_component.yml | 2 +- ksz8863/include/ksz8863_ctrl.h | 6 +- ksz8863/src/esp_eth_ksz8863.c | 2 + ksz8863/src/ksz8863_ctrl.c | 89 ++++++------------- 8 files changed, 82 insertions(+), 135 deletions(-) diff --git a/ksz8863/README.md b/ksz8863/README.md index 0a73876..f39aa78 100644 --- a/ksz8863/README.md +++ b/ksz8863/README.md @@ -72,7 +72,9 @@ The figure below shows data path when KSZ8863 is used in this Port Mode. The con ## KSZ8863 Configuration & Control interface -KSZ8863 can be managed via either I2C or SPI bus. +KSZ8863 can be managed via either I2C or SPI bus. SMI is not supported. + +SMI used in KSZ8863 is a non-standard implementation of IEEE 802.3 MII management interface (MIIM). The core differences are the unusual addressing method used to get access to the full set of KSZ8863's registers and opcode numbering (MIIM sends opcode `0b10` to read and `0b01` to write, SMI expects `0b00` for both). It is impossible for ESP32 to produce opcode `0b00` by design, since it follows IEEE 802.3 MII management interface specification. ### KSZ8863 Control and Configuration diff --git a/ksz8863/examples/simple_switch/main/simple_switch_main.c b/ksz8863/examples/simple_switch/main/simple_switch_main.c index 946b3ff..025ec2f 100644 --- a/ksz8863/examples/simple_switch/main/simple_switch_main.c +++ b/ksz8863/examples/simple_switch/main/simple_switch_main.c @@ -132,11 +132,13 @@ static void eth_event_handler(void *arg, esp_event_base_t event_base, esp_err_t ret; /* we can get the ethernet driver handle from event data */ esp_eth_handle_t eth_handle = *(esp_eth_handle_t *)event_data; + /* we should not try to use KSZ8863-specific ioctl commands with the general host handle, only with port handles */ + esp_eth_handle_t host_eth_handle = *(esp_eth_handle_t *)arg; switch (event_id) { case ETHERNET_EVENT_CONNECTED: esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr); - ret = esp_eth_ioctl(eth_handle, KSZ8863_ETH_CMD_G_PORT_NUM, &port_num); + ret = eth_handle != host_eth_handle ? esp_eth_ioctl(eth_handle, KSZ8863_ETH_CMD_G_PORT_NUM, &port_num) : ESP_FAIL; if (ret == ESP_OK) { ESP_LOGI(TAG, "Ethernet Link Up Port %" PRIi32, port_num + 1); } else { @@ -146,7 +148,7 @@ static void eth_event_handler(void *arg, esp_event_base_t event_base, mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); break; case ETHERNET_EVENT_DISCONNECTED: - ret = esp_eth_ioctl(eth_handle, KSZ8863_ETH_CMD_G_PORT_NUM, &port_num); + ret = eth_handle != host_eth_handle ? esp_eth_ioctl(eth_handle, KSZ8863_ETH_CMD_G_PORT_NUM, &port_num) : ESP_FAIL; if (ret == ESP_OK) { ESP_LOGI(TAG, "Ethernet Link Down Port %" PRIi32, port_num + 1); } else { @@ -179,18 +181,6 @@ static void got_ip_event_handler(void *arg, esp_event_base_t event_base, ESP_LOGI(TAG, "~~~~~~~~~~~"); } -esp_err_t i2c_init(i2c_port_t i2c_master_port, i2c_config_t *i2c_conf) -{ - esp_err_t ret; - - ESP_GOTO_ON_ERROR(i2c_param_config(i2c_master_port, i2c_conf), err, TAG, "I2C parameters configuration failed"); - ESP_GOTO_ON_ERROR(i2c_driver_install(i2c_master_port, i2c_conf->mode, 0, 0, 0), err, TAG, "I2C driver install failed"); - - return ESP_OK; -err: - return ret; -} - // board specific initialization routine, user to update per specific needs esp_err_t ksz8863_board_specific_init(esp_eth_handle_t eth_handle) { @@ -198,18 +188,20 @@ esp_err_t ksz8863_board_specific_init(esp_eth_handle_t eth_handle) #if CONFIG_EXAMPLE_CTRL_I2C // initialize I2C interface - i2c_config_t i2c_bus_config = { - .mode = I2C_MODE_MASTER, - .sda_io_num = CONFIG_EXAMPLE_I2C_SDA_GPIO, + i2c_master_bus_config_t i2c_mst_config = { + .clk_source = I2C_CLK_SRC_DEFAULT, + .i2c_port = CONFIG_EXAMPLE_I2C_MASTER_PORT, .scl_io_num = CONFIG_EXAMPLE_I2C_SCL_GPIO, - .sda_pullup_en = GPIO_PULLUP_ENABLE, - .scl_pullup_en = GPIO_PULLUP_ENABLE, - .master.clk_speed = CONFIG_EXAMPLE_I2C_CLOCK_KHZ * 1000, + .sda_io_num = CONFIG_EXAMPLE_I2C_SDA_GPIO, + .glitch_ignore_cnt = 7, }; - ESP_GOTO_ON_ERROR(i2c_init(CONFIG_EXAMPLE_I2C_MASTER_PORT, &i2c_bus_config), err, TAG, "I2C initialization failed"); + i2c_master_bus_handle_t bus_handle; + ESP_GOTO_ON_ERROR(i2c_new_master_bus(&i2c_mst_config, &bus_handle), err, TAG, "I2C initialization failed"); ksz8863_ctrl_i2c_config_t i2c_dev_config = { + .bus_handle = bus_handle, .dev_addr = KSZ8863_I2C_DEV_ADDR, - .i2c_master_port = CONFIG_EXAMPLE_I2C_MASTER_PORT, + .i2c_port = CONFIG_EXAMPLE_I2C_MASTER_PORT, + .scl_speed_hz = CONFIG_EXAMPLE_I2C_CLOCK_KHZ * 1000 }; ksz8863_ctrl_intf_config_t ctrl_intf_cfg = { .host_mode = KSZ8863_I2C_MODE, @@ -318,7 +310,7 @@ void app_main(void) ESP_ERROR_CHECK(esp_eth_driver_install(&p2_config, &p2_eth_handle)); // Register user defined event handers - ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, ð_event_handler, NULL)); + ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, ð_event_handler, &host_eth_handle)); ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, NULL)); // start Ethernet driver state machines diff --git a/ksz8863/examples/switch_mode/main/switch_main.c b/ksz8863/examples/switch_mode/main/switch_main.c index 3d91da9..a6ae36b 100644 --- a/ksz8863/examples/switch_mode/main/switch_main.c +++ b/ksz8863/examples/switch_mode/main/switch_main.c @@ -171,11 +171,13 @@ static void eth_event_handler(void *arg, esp_event_base_t event_base, esp_err_t ret; /* we can get the ethernet driver handle from event data */ esp_eth_handle_t eth_handle = *(esp_eth_handle_t *)event_data; + /* we should not try to use KSZ8863-specific ioctl commands with the general host handle, only with port handles */ + esp_eth_handle_t host_eth_handle = *(esp_eth_handle_t *)arg; switch (event_id) { case ETHERNET_EVENT_CONNECTED: esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr); - ret = esp_eth_ioctl(eth_handle, KSZ8863_ETH_CMD_G_PORT_NUM, &port_num); + ret = eth_handle != host_eth_handle ? esp_eth_ioctl(eth_handle, KSZ8863_ETH_CMD_G_PORT_NUM, &port_num) : ESP_FAIL; if (ret == ESP_OK) { ESP_LOGI(TAG, "Ethernet Link Up Port %" PRIi32, port_num + 1); } else { @@ -185,7 +187,7 @@ static void eth_event_handler(void *arg, esp_event_base_t event_base, mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); break; case ETHERNET_EVENT_DISCONNECTED: - ret = esp_eth_ioctl(eth_handle, KSZ8863_ETH_CMD_G_PORT_NUM, &port_num); + ret = eth_handle != host_eth_handle ? esp_eth_ioctl(eth_handle, KSZ8863_ETH_CMD_G_PORT_NUM, &port_num) : ESP_FAIL; if (ret == ESP_OK) { ESP_LOGI(TAG, "Ethernet Link Down Port %" PRIi32, port_num + 1); } else { @@ -218,18 +220,6 @@ static void got_ip_event_handler(void *arg, esp_event_base_t event_base, ESP_LOGI(TAG, "~~~~~~~~~~~"); } -esp_err_t i2c_init(i2c_port_t i2c_master_port, i2c_config_t *i2c_conf) -{ - esp_err_t ret; - - ESP_GOTO_ON_ERROR(i2c_param_config(i2c_master_port, i2c_conf), err, TAG, "I2C parameters configuration failed"); - ESP_GOTO_ON_ERROR(i2c_driver_install(i2c_master_port, i2c_conf->mode, 0, 0, 0), err, TAG, "I2C driver install failed"); - - return ESP_OK; -err: - return ret; -} - // board specific initialization routine, user to update per specific needs esp_err_t ksz8863_board_specific_init(esp_eth_handle_t eth_handle) { @@ -237,18 +227,20 @@ esp_err_t ksz8863_board_specific_init(esp_eth_handle_t eth_handle) #if CONFIG_EXAMPLE_CTRL_I2C // initialize I2C interface - i2c_config_t i2c_bus_config = { - .mode = I2C_MODE_MASTER, - .sda_io_num = CONFIG_EXAMPLE_I2C_SDA_GPIO, + i2c_master_bus_config_t i2c_mst_config = { + .clk_source = I2C_CLK_SRC_DEFAULT, + .i2c_port = CONFIG_EXAMPLE_I2C_MASTER_PORT, .scl_io_num = CONFIG_EXAMPLE_I2C_SCL_GPIO, - .sda_pullup_en = GPIO_PULLUP_ENABLE, - .scl_pullup_en = GPIO_PULLUP_ENABLE, - .master.clk_speed = CONFIG_EXAMPLE_I2C_CLOCK_KHZ * 1000, + .sda_io_num = CONFIG_EXAMPLE_I2C_SDA_GPIO, + .glitch_ignore_cnt = 7, }; - ESP_GOTO_ON_ERROR(i2c_init(CONFIG_EXAMPLE_I2C_MASTER_PORT, &i2c_bus_config), err, TAG, "I2C initialization failed"); + i2c_master_bus_handle_t bus_handle; + ESP_GOTO_ON_ERROR(i2c_new_master_bus(&i2c_mst_config, &bus_handle), err, TAG, "I2C initialization failed"); ksz8863_ctrl_i2c_config_t i2c_dev_config = { + .bus_handle = bus_handle, .dev_addr = KSZ8863_I2C_DEV_ADDR, - .i2c_master_port = CONFIG_EXAMPLE_I2C_MASTER_PORT, + .i2c_port = CONFIG_EXAMPLE_I2C_MASTER_PORT, + .scl_speed_hz = CONFIG_EXAMPLE_I2C_CLOCK_KHZ * 1000 }; ksz8863_ctrl_intf_config_t ctrl_intf_cfg = { .host_mode = KSZ8863_I2C_MODE, @@ -371,7 +363,7 @@ void app_main(void) ESP_ERROR_CHECK(esp_netif_attach(eth_netif, ksz8863_esp_eth_new_netif_glue_switch(&sw_netif_glue_cfg))); // Register user defined event handers - ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, ð_event_handler, NULL)); + ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, ð_event_handler, &host_eth_handle)); ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, NULL)); // start Ethernet driver state machines diff --git a/ksz8863/examples/two_ports_mode/main/two_ports_main.c b/ksz8863/examples/two_ports_mode/main/two_ports_main.c index 4e2c574..e8e7023 100644 --- a/ksz8863/examples/two_ports_mode/main/two_ports_main.c +++ b/ksz8863/examples/two_ports_mode/main/two_ports_main.c @@ -164,11 +164,13 @@ static void eth_event_handler(void *arg, esp_event_base_t event_base, esp_err_t ret; /* we can get the ethernet driver handle from event data */ esp_eth_handle_t eth_handle = *(esp_eth_handle_t *)event_data; + /* we should not try to use KSZ8863-specific ioctl commands with the general host handle, only with port handles */ + esp_eth_handle_t host_eth_handle = *(esp_eth_handle_t *)arg; switch (event_id) { case ETHERNET_EVENT_CONNECTED: esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr); - ret = esp_eth_ioctl(eth_handle, KSZ8863_ETH_CMD_G_PORT_NUM, &port_num); + ret = eth_handle != host_eth_handle ? esp_eth_ioctl(eth_handle, KSZ8863_ETH_CMD_G_PORT_NUM, &port_num) : ESP_FAIL; if (ret == ESP_OK) { ESP_LOGI(TAG, "Ethernet Link Up Port %" PRIi32, port_num + 1); } else { @@ -178,7 +180,7 @@ static void eth_event_handler(void *arg, esp_event_base_t event_base, mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); break; case ETHERNET_EVENT_DISCONNECTED: - ret = esp_eth_ioctl(eth_handle, KSZ8863_ETH_CMD_G_PORT_NUM, &port_num); + ret = eth_handle != host_eth_handle ? esp_eth_ioctl(eth_handle, KSZ8863_ETH_CMD_G_PORT_NUM, &port_num) : ESP_FAIL; if (ret == ESP_OK) { ESP_LOGI(TAG, "Ethernet Link Down Port %" PRIi32, port_num + 1); } else { @@ -211,18 +213,6 @@ static void got_ip_event_handler(void *arg, esp_event_base_t event_base, ESP_LOGI(TAG, "~~~~~~~~~~~"); } -esp_err_t i2c_init(i2c_port_t i2c_master_port, i2c_config_t *i2c_conf) -{ - esp_err_t ret; - - ESP_GOTO_ON_ERROR(i2c_param_config(i2c_master_port, i2c_conf), err, TAG, "I2C parameters configuration failed"); - ESP_GOTO_ON_ERROR(i2c_driver_install(i2c_master_port, i2c_conf->mode, 0, 0, 0), err, TAG, "I2C driver install failed"); - - return ESP_OK; -err: - return ret; -} - // board specific initialization routine, user to update per specific needs esp_err_t ksz8863_board_specific_init(esp_eth_handle_t eth_handle) { @@ -230,18 +220,20 @@ esp_err_t ksz8863_board_specific_init(esp_eth_handle_t eth_handle) #if CONFIG_EXAMPLE_CTRL_I2C // initialize I2C interface - i2c_config_t i2c_bus_config = { - .mode = I2C_MODE_MASTER, - .sda_io_num = CONFIG_EXAMPLE_I2C_SDA_GPIO, + i2c_master_bus_config_t i2c_mst_config = { + .clk_source = I2C_CLK_SRC_DEFAULT, + .i2c_port = CONFIG_EXAMPLE_I2C_MASTER_PORT, .scl_io_num = CONFIG_EXAMPLE_I2C_SCL_GPIO, - .sda_pullup_en = GPIO_PULLUP_ENABLE, - .scl_pullup_en = GPIO_PULLUP_ENABLE, - .master.clk_speed = CONFIG_EXAMPLE_I2C_CLOCK_KHZ * 1000, + .sda_io_num = CONFIG_EXAMPLE_I2C_SDA_GPIO, + .glitch_ignore_cnt = 7, }; - ESP_GOTO_ON_ERROR(i2c_init(CONFIG_EXAMPLE_I2C_MASTER_PORT, &i2c_bus_config), err, TAG, "I2C initialization failed"); + i2c_master_bus_handle_t bus_handle; + ESP_GOTO_ON_ERROR(i2c_new_master_bus(&i2c_mst_config, &bus_handle), err, TAG, "I2C initialization failed"); ksz8863_ctrl_i2c_config_t i2c_dev_config = { + .bus_handle = bus_handle, .dev_addr = KSZ8863_I2C_DEV_ADDR, - .i2c_master_port = CONFIG_EXAMPLE_I2C_MASTER_PORT, + .i2c_port = CONFIG_EXAMPLE_I2C_MASTER_PORT, + .scl_speed_hz = CONFIG_EXAMPLE_I2C_CLOCK_KHZ * 1000 }; ksz8863_ctrl_intf_config_t ctrl_intf_cfg = { .host_mode = KSZ8863_I2C_MODE, @@ -386,7 +378,7 @@ void app_main(void) ESP_ERROR_CHECK(esp_netif_attach(eth_netif_port[1], esp_eth_new_netif_glue(p2_eth_handle))); // Register user defined event handers - ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, ð_event_handler, NULL)); + ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, ð_event_handler, &host_eth_handle)); ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, NULL)); // start Ethernet driver state machines diff --git a/ksz8863/idf_component.yml b/ksz8863/idf_component.yml index 2e3a796..4945df8 100644 --- a/ksz8863/idf_component.yml +++ b/ksz8863/idf_component.yml @@ -1,4 +1,4 @@ -version: "0.2.6" +version: "0.2.7" targets: - esp32 - esp32p4 diff --git a/ksz8863/include/ksz8863_ctrl.h b/ksz8863/include/ksz8863_ctrl.h index 6aef810..d8e51a5 100644 --- a/ksz8863/include/ksz8863_ctrl.h +++ b/ksz8863/include/ksz8863_ctrl.h @@ -6,7 +6,7 @@ #pragma once #include "esp_err.h" -#include "driver/i2c.h" +#include "driver/i2c_master.h" #include "driver/spi_master.h" #include "esp_eth_driver.h" // for esp_eth_handle_t @@ -24,7 +24,9 @@ typedef enum { typedef struct { uint8_t dev_addr; - i2c_port_t i2c_master_port; + uint32_t scl_speed_hz; + i2c_port_num_t i2c_port; + i2c_master_bus_handle_t bus_handle; } ksz8863_ctrl_i2c_config_t; typedef struct { diff --git a/ksz8863/src/esp_eth_ksz8863.c b/ksz8863/src/esp_eth_ksz8863.c index 53e15aa..64ebe23 100644 --- a/ksz8863/src/esp_eth_ksz8863.c +++ b/ksz8863/src/esp_eth_ksz8863.c @@ -10,6 +10,8 @@ #include #include "esp_log.h" #include "esp_check.h" +#include "driver/gpio.h" +#include "esp_rom_gpio.h" #include "esp_eth_ksz8863.h" #include "ksz8863.h" // registers diff --git a/ksz8863/src/ksz8863_ctrl.c b/ksz8863/src/ksz8863_ctrl.c index 158d966..f0c0e06 100644 --- a/ksz8863/src/ksz8863_ctrl.c +++ b/ksz8863/src/ksz8863_ctrl.c @@ -19,25 +19,15 @@ #define KSZ8863_I2C_LOCK_TIMEOUT_MS (KSZ8863_I2C_TIMEOUT_MS + 50) #define KSZ8863_SPI_LOCK_TIMEOUT_MS 500 -typedef struct { - i2c_port_t i2c_port; - uint8_t dev_addr; -} ksz8863_i2c_spec_t; - -typedef struct { - spi_device_handle_t spi_handle; -} ksz8863_spi_spec_t; - typedef struct { ksz8863_intf_mode_t mode; SemaphoreHandle_t bus_lock; esp_err_t (*ksz8863_reg_read)(uint8_t reg_addr, uint8_t *data, size_t len); esp_err_t (*ksz8863_reg_write)(uint8_t reg_addr, uint8_t *data, size_t len); union { - ksz8863_i2c_spec_t i2c_bus_spec; - ksz8863_spi_spec_t spi_bus_spec; + spi_device_handle_t spi_handle; + i2c_master_dev_handle_t i2c_handle; }; - } ksz8863_ctrl_intf_t; static ksz8863_ctrl_intf_t *s_ksz8863_ctrl_intf = NULL; @@ -57,56 +47,27 @@ static inline bool bus_unlock(void) static esp_err_t ksz8863_i2c_write(uint8_t reg_addr, uint8_t *data, size_t len) { esp_err_t ret = ESP_OK; - i2c_port_t i2c_port = s_ksz8863_ctrl_intf->i2c_bus_spec.i2c_port; - uint8_t dev_addr = s_ksz8863_ctrl_intf->i2c_bus_spec.dev_addr; - - i2c_cmd_handle_t cmd = i2c_cmd_link_create(); - ESP_RETURN_ON_FALSE(cmd, ESP_ERR_NO_MEM, TAG, "I2C link create error"); - ESP_GOTO_ON_ERROR(i2c_master_start(cmd), err, TAG, "I2C master start error"); - ESP_GOTO_ON_ERROR(i2c_master_write_byte(cmd, dev_addr | I2C_MASTER_WRITE, true), err, TAG, "I2C master write error"); - ESP_GOTO_ON_ERROR(i2c_master_write_byte(cmd, reg_addr, true), err, TAG, "I2C master write error"); - if (likely(reg_addr != KSZ8863_RESET_ADDR)) { - ESP_GOTO_ON_ERROR(i2c_master_write(cmd, data, len, true), err, TAG, "I2C master write error"); + uint8_t *reg_addr_and_data = malloc(len + 1); + // Create a packet containing the register and data to be transmitted + reg_addr_and_data[0] = reg_addr; + memcpy(reg_addr_and_data + 1, data, len); + // When performing a soft reset, the KSZ8863 doesn't produce an ACK. Print a warning that the error is expected and ignore it. + if unlikely(reg_addr == KSZ8863_RESET_ADDR) { + ESP_LOGW(TAG, "The following I2C error can be ignored. It is thrown by the I2C driver because KSZ8863 does not produce ACK when performing soft reset. It is expected behaviour and requires no actions on your side."); + i2c_master_transmit(s_ksz8863_ctrl_intf->i2c_handle, reg_addr_and_data, len + 1, KSZ8863_I2C_TIMEOUT_MS); } else { - // when SW reset is performed, KSZ does not generate ACK - ESP_GOTO_ON_ERROR(i2c_master_write(cmd, data, len, false), err, TAG, "I2C master write error"); + ESP_GOTO_ON_ERROR(i2c_master_transmit(s_ksz8863_ctrl_intf->i2c_handle, reg_addr_and_data, len + 1, KSZ8863_I2C_TIMEOUT_MS), err, TAG, "Error during i2c write operation"); } - ESP_GOTO_ON_ERROR(i2c_master_stop(cmd), err, TAG, "I2C master stop error"); - // Lock since multiple MAC/PHY instances exist and the KSZ may be also accessed by user (MAC tables, etc...) - ESP_GOTO_ON_FALSE(bus_lock(KSZ8863_I2C_LOCK_TIMEOUT_MS), ESP_ERR_TIMEOUT, err, TAG, "I2C bus lock timeout"); - ESP_GOTO_ON_ERROR(i2c_master_cmd_begin(i2c_port, cmd, pdMS_TO_TICKS(KSZ8863_I2C_TIMEOUT_MS)), err_release, TAG, - "I2C master command begin error"); -err_release: - bus_unlock(); err: - i2c_cmd_link_delete(cmd); + free(reg_addr_and_data); return ret; } static esp_err_t ksz8863_i2c_read(uint8_t reg_addr, uint8_t *data, size_t len) { esp_err_t ret = ESP_OK; - i2c_port_t i2c_port = s_ksz8863_ctrl_intf->i2c_bus_spec.i2c_port; - uint8_t dev_addr = s_ksz8863_ctrl_intf->i2c_bus_spec.dev_addr; - - i2c_cmd_handle_t cmd = i2c_cmd_link_create(); - ESP_RETURN_ON_FALSE(cmd, ESP_ERR_NO_MEM, TAG, "I2C link create error"); - ESP_GOTO_ON_ERROR(i2c_master_start(cmd), err, TAG, "I2C master start error"); - ESP_GOTO_ON_ERROR(i2c_master_write_byte(cmd, dev_addr | I2C_MASTER_WRITE, true), err, TAG, "I2C master write error"); - ESP_GOTO_ON_ERROR(i2c_master_write_byte(cmd, reg_addr, true), err, TAG, "I2C master write error"); - // restart before read - ESP_GOTO_ON_ERROR(i2c_master_start(cmd), err, TAG, "I2C master start error"); - ESP_GOTO_ON_ERROR(i2c_master_write_byte(cmd, dev_addr | I2C_MASTER_READ, true), err, TAG, "I2C master write error");; - ESP_GOTO_ON_ERROR(i2c_master_read(cmd, data, len, I2C_MASTER_LAST_NACK), err, TAG, "I2C master read error"); - ESP_GOTO_ON_ERROR(i2c_master_stop(cmd), err, TAG, "I2C master stop error");; - // Lock since multiple MAC/PHY instances exist and the KSZ may be also accessed by user (MAC tables, etc...) - ESP_GOTO_ON_FALSE(bus_lock(KSZ8863_I2C_LOCK_TIMEOUT_MS), ESP_ERR_TIMEOUT, err, TAG, "I2C bus lock timeout"); - ESP_GOTO_ON_ERROR(i2c_master_cmd_begin(i2c_port, cmd, pdMS_TO_TICKS(KSZ8863_I2C_TIMEOUT_MS)), err_release, TAG, - "I2C master command begin error"); -err_release: - bus_unlock(); + ESP_GOTO_ON_ERROR(i2c_master_transmit_receive(s_ksz8863_ctrl_intf->i2c_handle, ®_addr, 1, data, len, KSZ8863_I2C_TIMEOUT_MS), err, TAG, "Error during i2c read operation"); err: - i2c_cmd_link_delete(cmd); return ret; } @@ -121,7 +82,7 @@ static esp_err_t ksz8863_spi_write(uint8_t reg_addr, uint8_t *data, size_t len) .tx_buffer = data }; ESP_GOTO_ON_FALSE(bus_lock(KSZ8863_SPI_LOCK_TIMEOUT_MS), ESP_ERR_TIMEOUT, err, TAG, "SPI bus lock timeout"); - ESP_GOTO_ON_ERROR(spi_device_polling_transmit(s_ksz8863_ctrl_intf->spi_bus_spec.spi_handle, &trans), err_release, TAG, "SPI transmit fail"); + ESP_GOTO_ON_ERROR(spi_device_polling_transmit(s_ksz8863_ctrl_intf->spi_handle, &trans), err_release, TAG, "SPI transmit fail"); err_release: bus_unlock(); err: @@ -140,7 +101,7 @@ static esp_err_t ksz8863_spi_read(uint8_t reg_addr, uint8_t *data, size_t len) .rx_buffer = data }; ESP_GOTO_ON_FALSE(bus_lock(KSZ8863_SPI_LOCK_TIMEOUT_MS), ESP_ERR_TIMEOUT, err, TAG, "SPI bus lock timeout"); - ESP_GOTO_ON_ERROR(spi_device_polling_transmit(s_ksz8863_ctrl_intf->spi_bus_spec.spi_handle, &trans), err_release, TAG, "SPI transmit fail"); + ESP_GOTO_ON_ERROR(spi_device_polling_transmit(s_ksz8863_ctrl_intf->spi_handle, &trans), err_release, TAG, "SPI transmit fail"); bus_unlock(); if ((trans.flags & SPI_TRANS_USE_RXDATA) && len <= 4) { @@ -287,19 +248,24 @@ esp_err_t ksz8863_ctrl_intf_init(ksz8863_ctrl_intf_config_t *config) s_ksz8863_ctrl_intf = calloc(1, sizeof(ksz8863_ctrl_intf_t)); ESP_RETURN_ON_FALSE(s_ksz8863_ctrl_intf, ESP_ERR_NO_MEM, TAG, "no memory"); - ESP_GOTO_ON_FALSE(s_ksz8863_ctrl_intf->bus_lock = xSemaphoreCreateMutex(), ESP_ERR_NO_MEM, err, TAG, "mutex creation failed"); s_ksz8863_ctrl_intf->mode = config->host_mode; switch (config->host_mode) { case KSZ8863_I2C_MODE: - s_ksz8863_ctrl_intf->i2c_bus_spec.i2c_port = config->i2c_dev_config->i2c_master_port; - s_ksz8863_ctrl_intf->i2c_bus_spec.dev_addr = config->i2c_dev_config->dev_addr; + i2c_device_config_t dev_cfg = { + .dev_addr_length = I2C_ADDR_BIT_LEN_7, + .device_address = config->i2c_dev_config->dev_addr >> 1, + .scl_speed_hz = config->i2c_dev_config->scl_speed_hz, + }; + ESP_GOTO_ON_ERROR(i2c_master_bus_add_device(config->i2c_dev_config->bus_handle, &dev_cfg, &s_ksz8863_ctrl_intf->i2c_handle), err, TAG, "Error when trying to add the I2C device"); s_ksz8863_ctrl_intf->ksz8863_reg_read = ksz8863_i2c_read; s_ksz8863_ctrl_intf->ksz8863_reg_write = ksz8863_i2c_write; break; case KSZ8863_SPI_MODE:; + ESP_GOTO_ON_FALSE(s_ksz8863_ctrl_intf->bus_lock = xSemaphoreCreateMutex(), ESP_ERR_NO_MEM, err, TAG, "mutex creation failed"); + spi_device_interface_config_t devcfg = { .command_bits = 8, .address_bits = 8, @@ -308,11 +274,10 @@ esp_err_t ksz8863_ctrl_intf_init(ksz8863_ctrl_intf_config_t *config) .spics_io_num = config->spi_dev_config->spics_io_num, .queue_size = 20 }; - ESP_ERROR_CHECK(spi_bus_add_device(config->spi_dev_config->host_id, &devcfg, &s_ksz8863_ctrl_intf->spi_bus_spec.spi_handle)); + ESP_ERROR_CHECK(spi_bus_add_device(config->spi_dev_config->host_id, &devcfg, &s_ksz8863_ctrl_intf->spi_handle)); s_ksz8863_ctrl_intf->ksz8863_reg_read = ksz8863_spi_read; s_ksz8863_ctrl_intf->ksz8863_reg_write = ksz8863_spi_write; - case KSZ8863_SMI_MODE: default: break; } @@ -327,15 +292,15 @@ esp_err_t ksz8863_ctrl_intf_deinit(void) if (s_ksz8863_ctrl_intf != NULL) { switch (s_ksz8863_ctrl_intf->mode) { case KSZ8863_I2C_MODE: + i2c_master_bus_rm_device(s_ksz8863_ctrl_intf->i2c_handle); break; case KSZ8863_SPI_MODE: - spi_bus_remove_device(s_ksz8863_ctrl_intf->spi_bus_spec.spi_handle); - case KSZ8863_SMI_MODE: + vSemaphoreDelete(s_ksz8863_ctrl_intf->bus_lock); + spi_bus_remove_device(s_ksz8863_ctrl_intf->spi_handle); default: break; } - vSemaphoreDelete(s_ksz8863_ctrl_intf->bus_lock); free(s_ksz8863_ctrl_intf); s_ksz8863_ctrl_intf = NULL; }