diff --git a/drivers/stepper/adi_tmc/bus/CMakeLists.txt b/drivers/stepper/adi_tmc/bus/CMakeLists.txt index fc10daf070d1d..bfb9dc7b712e5 100644 --- a/drivers/stepper/adi_tmc/bus/CMakeLists.txt +++ b/drivers/stepper/adi_tmc/bus/CMakeLists.txt @@ -3,5 +3,9 @@ zephyr_library_include_directories(include) +# Generic bus adapter +zephyr_library_sources(adi_tmc_bus.c) + +# Low-level bus implementations zephyr_library_sources_ifdef(CONFIG_STEPPER_ADI_TMC_SPI adi_tmc_spi.c) zephyr_library_sources_ifdef(CONFIG_STEPPER_ADI_TMC_UART adi_tmc_uart.c) diff --git a/drivers/stepper/adi_tmc/bus/adi_tmc_bus.c b/drivers/stepper/adi_tmc/bus/adi_tmc_bus.c new file mode 100644 index 0000000000000..86a87d5ea265f --- /dev/null +++ b/drivers/stepper/adi_tmc/bus/adi_tmc_bus.c @@ -0,0 +1,129 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2025 Dipak Shetty + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#ifdef CONFIG_STEPPER_ADI_TMC_SPI +#include +#endif +#ifdef CONFIG_STEPPER_ADI_TMC_UART +#include +#endif + +LOG_MODULE_REGISTER(tmc_bus, CONFIG_STEPPER_LOG_LEVEL); + +/* + * Generic SPI Bus Adapter - works for all TMC series + */ + +#ifdef CONFIG_STEPPER_ADI_TMC_SPI + +static int tmc_bus_check_spi(const union tmc_bus *bus, uint8_t comm_type) +{ + if (comm_type != TMC_COMM_SPI) { + return -ENOTSUP; + } + return spi_is_ready_dt(&bus->spi) ? 0 : -ENODEV; +} + +static int tmc_bus_read_spi(const struct device *dev, const uint8_t reg_addr, uint32_t *reg_val) +{ + const struct tmc_common_config *config = dev->config; + int err; + + err = tmc_spi_read_register(&config->bus.spi, reg_addr, reg_val); + + if (err < 0) { + LOG_ERR("Failed to read register 0x%x", reg_addr); + } + return err; +} + +static int tmc_bus_write_spi(const struct device *dev, const uint8_t reg_addr, + const uint32_t reg_val) +{ + const struct tmc_common_config *config = dev->config; + int err; + + err = tmc_spi_write_register(&config->bus.spi, reg_addr, reg_val); + + if (err < 0) { + LOG_ERR("Failed to write register 0x%x with value 0x%x", reg_addr, reg_val); + } + return err; +} + +const struct tmc_bus_io tmc_spi_bus_io = { + .check = tmc_bus_check_spi, + .read = tmc_bus_read_spi, + .write = tmc_bus_write_spi, +}; + +#endif /* CONFIG_STEPPER_ADI_TMC_SPI */ + +/* + * Generic UART Bus Adapter - works for all TMC series + */ + +#ifdef CONFIG_STEPPER_ADI_TMC_UART + +/* Forward declaration for UART-specific config extraction */ +struct tmc_uart_device_config { + struct tmc_common_config common; + /* UART-specific fields that generic adapter needs */ + uint8_t uart_addr; +}; + +static int tmc_bus_check_uart(const union tmc_bus *bus, uint8_t comm_type) +{ + if (comm_type != TMC_COMM_UART) { + return -ENOTSUP; + } + return device_is_ready(bus->uart) ? 0 : -ENODEV; +} + +static int tmc_bus_read_uart(const struct device *dev, const uint8_t reg_addr, uint32_t *reg_val) +{ + const struct tmc_uart_device_config *config = dev->config; + int err; + + /* Route to the adi_tmc_uart.h implementation */ + err = tmc_uart_read_register(config->common.bus.uart, config->uart_addr, reg_addr, + reg_val); + + if (err < 0) { + LOG_ERR("Failed to read register 0x%x", reg_addr); + } + /* Wait for the read to complete */ + k_sleep(K_MSEC(1)); + return err; +} + +static int tmc_bus_write_uart(const struct device *dev, const uint8_t reg_addr, + const uint32_t reg_val) +{ + const struct tmc_uart_device_config *config = dev->config; + int err; + + /* Route to the adi_tmc_uart.h implementation */ + err = tmc_uart_write_register(config->common.bus.uart, config->uart_addr, reg_addr, + reg_val); + + if (err < 0) { + LOG_ERR("Failed to write register 0x%x with value 0x%x", reg_addr, reg_val); + } + /* Wait for the write to complete */ + k_sleep(K_MSEC(1)); + return err; +} + +const struct tmc_bus_io tmc_uart_bus_io = { + .check = tmc_bus_check_uart, + .read = tmc_bus_read_uart, + .write = tmc_bus_write_uart, +}; + +#endif /* CONFIG_STEPPER_ADI_TMC_UART */ diff --git a/drivers/stepper/adi_tmc/bus/adi_tmc_spi.c b/drivers/stepper/adi_tmc/bus/adi_tmc_spi.c index ef75fe166a783..eb9bbc5191e0b 100644 --- a/drivers/stepper/adi_tmc/bus/adi_tmc_spi.c +++ b/drivers/stepper/adi_tmc/bus/adi_tmc_spi.c @@ -3,15 +3,19 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include #include +#include "../adi_tmc_reg.h" #define BUFFER_SIZE 5U -int tmc_spi_read_register(const struct spi_dt_spec *bus, const uint8_t read_address_mask, - const uint8_t register_address, uint32_t *data) +/* TMC SPI protocol constants */ +#define ADI_TMC_SPI_WRITE_BIT 0x80U /* MSB=1 for write access */ +#define ADI_TMC_SPI_ADDRESS_MASK 0x7FU /* 7-bit address field mask */ + +int tmc_spi_read_register(const struct spi_dt_spec *bus, uint8_t register_address, uint32_t *data) { - uint8_t tx_buffer[BUFFER_SIZE] = {read_address_mask & register_address, 0U, 0U, 0U, 0U}; + uint8_t tx_buffer[BUFFER_SIZE] = {ADI_TMC_SPI_ADDRESS_MASK & register_address, 0U, 0U, 0U, 0U}; uint8_t rx_buffer[BUFFER_SIZE]; int status; @@ -45,19 +49,18 @@ int tmc_spi_read_register(const struct spi_dt_spec *bus, const uint8_t read_addr return status; } - *data = ((uint32_t)rx_buffer[1] << 24) + ((uint32_t)rx_buffer[2] << 16) + - ((uint32_t)rx_buffer[3] << 8) + (uint32_t)rx_buffer[4]; + *data = sys_get_be32(&rx_buffer[1]); return status; } -int tmc_spi_write_register(const struct spi_dt_spec *bus, const uint8_t write_bit, - const uint8_t register_address, const uint32_t data) +int tmc_spi_write_register(const struct spi_dt_spec *bus, uint8_t register_address, uint32_t data) { - uint8_t tx_buffer[BUFFER_SIZE] = {write_bit | register_address, data >> 24, data >> 16, - data >> 8, data}; + uint8_t tx_buffer[BUFFER_SIZE]; uint8_t rx_buffer[BUFFER_SIZE]; - int status; + + tx_buffer[0] = ADI_TMC_SPI_WRITE_BIT | (register_address & ADI_TMC_SPI_ADDRESS_MASK); + sys_put_be32(data, &tx_buffer[1]); const struct spi_buf spi_buffer_tx = { .buf = &tx_buffer, @@ -77,10 +80,5 @@ int tmc_spi_write_register(const struct spi_dt_spec *bus, const uint8_t write_bi .count = 1U, }; - status = spi_transceive_dt(bus, &spi_buffer_array_tx, &spi_buffer_array_rx); - if (status < 0) { - return status; - } - - return status; + return spi_transceive_dt(bus, &spi_buffer_array_tx, &spi_buffer_array_rx); } diff --git a/drivers/stepper/adi_tmc/bus/include/adi_tmc_bus.h b/drivers/stepper/adi_tmc/bus/include/adi_tmc_bus.h index ed72a3ea6b607..f8ddca5ef698c 100644 --- a/drivers/stepper/adi_tmc/bus/include/adi_tmc_bus.h +++ b/drivers/stepper/adi_tmc/bus/include/adi_tmc_bus.h @@ -56,4 +56,24 @@ struct tmc_bus_io { tmc_reg_write_fn write; /* Function to write to a register */ }; +/** + * @brief Common configuration base for all TMC series drivers. + * All series-specific config structures MUST have these fields at the beginning. + * This allows generic bus adapters to access bus information regardless of series. + */ +struct tmc_common_config { + union tmc_bus bus; + const struct tmc_bus_io *bus_io; + uint8_t comm_type; +}; + +/* Generic bus I/O operations - work for all TMC series */ +#ifdef CONFIG_STEPPER_ADI_TMC_SPI +extern const struct tmc_bus_io tmc_spi_bus_io; +#endif + +#ifdef CONFIG_STEPPER_ADI_TMC_UART +extern const struct tmc_bus_io tmc_uart_bus_io; +#endif + #endif /* ZEPHYR_DRIVERS_STEPPER_ADI_TMC_BUS_H_ */ diff --git a/drivers/stepper/adi_tmc/bus/include/adi_tmc_spi.h b/drivers/stepper/adi_tmc/bus/include/adi_tmc_spi.h index a49a0a6ba5939..90a3e9ad29555 100644 --- a/drivers/stepper/adi_tmc/bus/include/adi_tmc_spi.h +++ b/drivers/stepper/adi_tmc/bus/include/adi_tmc_spi.h @@ -30,27 +30,23 @@ extern "C" { * @brief Read a register from the TMC module using the SPI Bus. * * @param bus SPI DT information of the bus. - * @param read_address_mask Address Mask for read operation. - * @param register_address Register. + * @param register_address Register address to read. * @param data Pointer to read value. * * @return a value from spi_transceive(). */ -int tmc_spi_read_register(const struct spi_dt_spec *bus, const uint8_t read_address_mask, - const uint8_t register_address, uint32_t *data); +int tmc_spi_read_register(const struct spi_dt_spec *bus, uint8_t register_address, uint32_t *data); /** * @brief Write into a register in the TMC module using the SPI Bus. * * @param bus SPI DT information of the bus. - * @param write_bit Write bit for write operation. - * @param register_address Register. + * @param register_address Register address to write. * @param data Value to be written in the register. * * @return a value from spi_transceive(). */ -int tmc_spi_write_register(const struct spi_dt_spec *bus, const uint8_t write_bit, - const uint8_t register_address, const uint32_t data); +int tmc_spi_write_register(const struct spi_dt_spec *bus, uint8_t register_address, uint32_t data); /** * @} diff --git a/drivers/stepper/adi_tmc/tmc50xx.c b/drivers/stepper/adi_tmc/tmc50xx.c index 56a2bd3bedc36..9635e0f07e1e3 100644 --- a/drivers/stepper/adi_tmc/tmc50xx.c +++ b/drivers/stepper/adi_tmc/tmc50xx.c @@ -11,7 +11,7 @@ #include #include -#include +#include #include "adi_tmc5xxx_common.h" #include @@ -22,8 +22,12 @@ struct tmc50xx_data { }; struct tmc50xx_config { + /* Common config base - MUST be first for generic bus adapters */ + union tmc_bus bus; + const struct tmc_bus_io *bus_io; + uint8_t comm_type; + /* Series-specific configuration */ const uint32_t gconf; - struct spi_dt_spec spi; const uint32_t clock_frequency; }; @@ -53,16 +57,22 @@ struct tmc50xx_stepper_config { static int read_actual_position(const struct tmc50xx_stepper_config *config, int32_t *position); +static inline int tmc50xx_bus_check(const struct device *dev) +{ + const struct tmc50xx_config *config = dev->config; + + return config->bus_io->check(&config->bus, config->comm_type); +} + static int tmc50xx_write(const struct device *dev, const uint8_t reg_addr, const uint32_t reg_val) { const struct tmc50xx_config *config = dev->config; struct tmc50xx_data *data = dev->data; - const struct spi_dt_spec bus = config->spi; int err; k_sem_take(&data->sem, K_FOREVER); - err = tmc_spi_write_register(&bus, TMC5XXX_WRITE_BIT, reg_addr, reg_val); + err = config->bus_io->write(dev, reg_addr, reg_val); k_sem_give(&data->sem); @@ -77,12 +87,11 @@ static int tmc50xx_read(const struct device *dev, const uint8_t reg_addr, uint32 { const struct tmc50xx_config *config = dev->config; struct tmc50xx_data *data = dev->data; - const struct spi_dt_spec bus = config->spi; int err; k_sem_take(&data->sem, K_FOREVER); - err = tmc_spi_read_register(&bus, TMC5XXX_ADDRESS_MASK, reg_addr, reg_val); + err = config->bus_io->read(dev, reg_addr, reg_val); k_sem_give(&data->sem); @@ -635,9 +644,10 @@ static int tmc50xx_init(const struct device *dev) k_sem_init(&data->sem, 1, 1); - if (!spi_is_ready_dt(&config->spi)) { - LOG_ERR("SPI bus is not ready"); - return -ENODEV; + err = tmc50xx_bus_check(dev); + if (err < 0) { + LOG_ERR("Bus not ready for '%s'", dev->name); + return err; } /* Init non motor-index specific registers here. */ @@ -761,13 +771,15 @@ static DEVICE_API(stepper, tmc50xx_stepper_api) = { "clock frequency must be non-zero positive value"); \ static struct tmc50xx_data tmc50xx_data_##inst; \ static const struct tmc50xx_config tmc50xx_config_##inst = { \ + .comm_type = TMC_COMM_SPI, \ + .bus.spi = SPI_DT_SPEC_INST_GET(inst, (SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | \ + SPI_MODE_CPOL | SPI_MODE_CPHA | SPI_WORD_SET(8))), \ + .bus_io = &tmc_spi_bus_io, \ .gconf = ( \ (DT_INST_PROP(inst, poscmp_enable) << TMC50XX_GCONF_POSCMP_ENABLE_SHIFT) | \ (DT_INST_PROP(inst, test_mode) << TMC50XX_GCONF_TEST_MODE_SHIFT) | \ DT_INST_FOREACH_CHILD(inst, TMC50XX_SHAFT_CONFIG) \ (DT_INST_PROP(inst, lock_gconf) << TMC50XX_LOCK_GCONF_SHIFT)), \ - .spi = SPI_DT_SPEC_INST_GET(inst, (SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | \ - SPI_MODE_CPOL | SPI_MODE_CPHA | SPI_WORD_SET(8))), \ .clock_frequency = DT_INST_PROP(inst, clock_frequency),}; \ DT_INST_FOREACH_CHILD(inst, TMC50XX_STEPPER_CONFIG_DEFINE); \ DT_INST_FOREACH_CHILD(inst, TMC50XX_STEPPER_DATA_DEFINE); \ diff --git a/drivers/stepper/adi_tmc/tmc51xx/CMakeLists.txt b/drivers/stepper/adi_tmc/tmc51xx/CMakeLists.txt index 027a7be4b51fd..5886e78a241a7 100644 --- a/drivers/stepper/adi_tmc/tmc51xx/CMakeLists.txt +++ b/drivers/stepper/adi_tmc/tmc51xx/CMakeLists.txt @@ -1,4 +1,4 @@ # SPDX-FileCopyrightText: Copyright (c) 2025 Dipak Shetty # SPDX-License-Identifier: Apache-2.0 -zephyr_library_sources_ifdef(CONFIG_STEPPER_ADI_TMC51XX tmc51xx.c tmc51xx_spi.c tmc51xx_uart.c) +zephyr_library_sources_ifdef(CONFIG_STEPPER_ADI_TMC51XX tmc51xx.c) diff --git a/drivers/stepper/adi_tmc/tmc51xx/tmc51xx.c b/drivers/stepper/adi_tmc/tmc51xx/tmc51xx.c index 9586d88f1a7b2..879e7f778f051 100644 --- a/drivers/stepper/adi_tmc/tmc51xx/tmc51xx.c +++ b/drivers/stepper/adi_tmc/tmc51xx/tmc51xx.c @@ -819,13 +819,13 @@ static DEVICE_API(stepper, tmc51xx_api) = { .bus.spi = SPI_DT_SPEC_INST_GET(inst, \ (SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | SPI_MODE_CPOL | \ SPI_MODE_CPHA | SPI_WORD_SET(8))), \ - .bus_io = &tmc51xx_spi_bus_io, \ + .bus_io = &tmc_spi_bus_io, \ .diag0_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, diag0_gpios, {0}) /* Initializes a struct tmc51xx_config for an instance on a UART bus. */ #define TMC51XX_CONFIG_UART(inst) \ .comm_type = TMC_COMM_UART, .bus.uart = DEVICE_DT_GET(DT_INST_BUS(inst)), \ - .bus_io = &tmc51xx_uart_bus_io, .uart_addr = DT_INST_PROP_OR(inst, uart_device_addr, 1U), \ + .bus_io = &tmc_uart_bus_io, .uart_addr = DT_INST_PROP_OR(inst, uart_device_addr, 1U), \ .sw_sel_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, sw_sel_gpios, {0}) /* Device initialization macros */ diff --git a/drivers/stepper/adi_tmc/tmc51xx/tmc51xx.h b/drivers/stepper/adi_tmc/tmc51xx/tmc51xx.h index 43c26255dfd85..656f4754fae1d 100644 --- a/drivers/stepper/adi_tmc/tmc51xx/tmc51xx.h +++ b/drivers/stepper/adi_tmc/tmc51xx/tmc51xx.h @@ -20,9 +20,15 @@ /* Common configuration structure for TMC51xx */ struct tmc51xx_config { + /* Common config base */ union tmc_bus bus; const struct tmc_bus_io *bus_io; uint8_t comm_type; + /* UART-specific field */ +#if TMC51XX_BUS_UART + uint8_t uart_addr; +#endif + /* Series-specific configuration */ const uint32_t gconf; const uint32_t clock_frequency; const uint16_t default_micro_step_res; @@ -35,7 +41,6 @@ struct tmc51xx_config { #endif #if TMC51XX_BUS_UART const struct gpio_dt_spec sw_sel_gpio; - uint8_t uart_addr; #endif #if TMC51XX_BUS_SPI struct gpio_dt_spec diag0_gpio; @@ -52,14 +57,4 @@ struct tmc51xx_data { void *event_cb_user_data; }; -#if TMC51XX_BUS_SPI -/* SPI bus I/O operations for TMC51xx devices */ -extern const struct tmc_bus_io tmc51xx_spi_bus_io; -#endif - -#if TMC51XX_BUS_UART -/* UART bus I/O operations for TMC51xx devices */ -extern const struct tmc_bus_io tmc51xx_uart_bus_io; -#endif - #endif /* ZEPHYR_DRIVERS_STEPPER_ADI_TMC51XX_H */ diff --git a/drivers/stepper/adi_tmc/tmc51xx/tmc51xx_spi.c b/drivers/stepper/adi_tmc/tmc51xx/tmc51xx_spi.c deleted file mode 100644 index 5a4871bd860ac..0000000000000 --- a/drivers/stepper/adi_tmc/tmc51xx/tmc51xx_spi.c +++ /dev/null @@ -1,58 +0,0 @@ -/* - * SPDX-FileCopyrightText: Copyright (c) 2025 Dipak Shetty - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include - -#include -#include - -#include "tmc51xx.h" -#include "../adi_tmc_reg.h" - -#if TMC51XX_BUS_SPI -LOG_MODULE_DECLARE(tmc51xx, CONFIG_STEPPER_LOG_LEVEL); - -static int tmc51xx_bus_check_spi(const union tmc_bus *bus, uint8_t comm_type) -{ - if (comm_type != TMC_COMM_SPI) { - return -ENOTSUP; - } - return spi_is_ready_dt(&bus->spi) ? 0 : -ENODEV; -} - -static int tmc51xx_reg_write_spi(const struct device *dev, const uint8_t reg_addr, - const uint32_t reg_val) -{ - const struct tmc51xx_config *config = dev->config; - int err; - - err = tmc_spi_write_register(&config->bus.spi, TMC5XXX_WRITE_BIT, reg_addr, reg_val); - - if (err < 0) { - LOG_ERR("Failed to write register 0x%x with value 0x%x", reg_addr, reg_val); - } - return err; -} - -static int tmc51xx_reg_read_spi(const struct device *dev, const uint8_t reg_addr, uint32_t *reg_val) -{ - const struct tmc51xx_config *config = dev->config; - int err; - - err = tmc_spi_read_register(&config->bus.spi, TMC5XXX_ADDRESS_MASK, reg_addr, reg_val); - - if (err < 0) { - LOG_ERR("Failed to read register 0x%x", reg_addr); - } - return err; -} - -const struct tmc_bus_io tmc51xx_spi_bus_io = { - .check = tmc51xx_bus_check_spi, - .read = tmc51xx_reg_read_spi, - .write = tmc51xx_reg_write_spi, -}; -#endif /* TMC51XX_BUS_SPI */ diff --git a/drivers/stepper/adi_tmc/tmc51xx/tmc51xx_uart.c b/drivers/stepper/adi_tmc/tmc51xx/tmc51xx_uart.c deleted file mode 100644 index bc523bfe73356..0000000000000 --- a/drivers/stepper/adi_tmc/tmc51xx/tmc51xx_uart.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * SPDX-FileCopyrightText: Copyright (c) 2025 Dipak Shetty - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include - -#include "tmc51xx.h" -#include -#include - -#if TMC51XX_BUS_UART -LOG_MODULE_DECLARE(tmc51xx, CONFIG_STEPPER_LOG_LEVEL); - -static int tmc51xx_bus_check_uart(const union tmc_bus *bus, uint8_t comm_type) -{ - if (comm_type != TMC_COMM_UART) { - return -ENOTSUP; - } - return device_is_ready(bus->uart) ? 0 : -ENODEV; -} - -static int tmc51xx_reg_write_uart(const struct device *dev, const uint8_t reg_addr, - const uint32_t reg_val) -{ - const struct tmc51xx_config *config = dev->config; - int err; - - /* Route to the adi_tmc_uart.h implementation */ - err = tmc_uart_write_register(config->bus.uart, config->uart_addr, reg_addr, reg_val); - - if (err < 0) { - LOG_ERR("Failed to write register 0x%x with value 0x%x", reg_addr, reg_val); - } - /* Wait for the write to complete */ - k_sleep(K_MSEC(1)); - return err; -} - -static int tmc51xx_reg_read_uart(const struct device *dev, const uint8_t reg_addr, - uint32_t *reg_val) -{ - const struct tmc51xx_config *config = dev->config; - int err; - - /* Route to the adi_tmc_uart.h implementation */ - err = tmc_uart_read_register(config->bus.uart, config->uart_addr, reg_addr, reg_val); - - if (err < 0) { - LOG_ERR("Failed to read register 0x%x", reg_addr); - } - /* Wait for the read to complete */ - k_sleep(K_MSEC(1)); - return err; -} - -const struct tmc_bus_io tmc51xx_uart_bus_io = { - .check = tmc51xx_bus_check_uart, - .read = tmc51xx_reg_read_uart, - .write = tmc51xx_reg_write_uart, -}; -#endif /* TMC51XX_BUS_UART */