Skip to content
Draft
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
4 changes: 4 additions & 0 deletions drivers/stepper/adi_tmc/bus/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
129 changes: 129 additions & 0 deletions drivers/stepper/adi_tmc/bus/adi_tmc_bus.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2025 Dipak Shetty
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <zephyr/logging/log.h>
#include <adi_tmc_bus.h>
#ifdef CONFIG_STEPPER_ADI_TMC_SPI
#include <adi_tmc_spi.h>
#endif
#ifdef CONFIG_STEPPER_ADI_TMC_UART
#include <adi_tmc_uart.h>
#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 */
32 changes: 15 additions & 17 deletions drivers/stepper/adi_tmc/bus/adi_tmc_spi.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,19 @@
* SPDX-License-Identifier: Apache-2.0
*/

#include <zephyr/sys/util.h>
#include <zephyr/sys/byteorder.h>
#include <adi_tmc_spi.h>
#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};

Check warning on line 18 in drivers/stepper/adi_tmc/bus/adi_tmc_spi.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

LONG_LINE

drivers/stepper/adi_tmc/bus/adi_tmc_spi.c:18 line length of 103 exceeds 100 columns
uint8_t rx_buffer[BUFFER_SIZE];
int status;

Expand Down Expand Up @@ -45,19 +49,18 @@
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,
Expand All @@ -77,10 +80,5 @@
.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);
}
20 changes: 20 additions & 0 deletions drivers/stepper/adi_tmc/bus/include/adi_tmc_bus.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_ */
12 changes: 4 additions & 8 deletions drivers/stepper/adi_tmc/bus/include/adi_tmc_spi.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

/**
* @}
Expand Down
34 changes: 23 additions & 11 deletions drivers/stepper/adi_tmc/tmc50xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#include <zephyr/drivers/stepper.h>
#include <zephyr/drivers/stepper/stepper_trinamic.h>

#include <adi_tmc_spi.h>
#include <adi_tmc_bus.h>
#include "adi_tmc5xxx_common.h"

#include <zephyr/logging/log.h>
Expand All @@ -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;
};

Expand Down Expand Up @@ -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);

Expand All @@ -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);

Expand Down Expand Up @@ -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. */
Expand Down Expand Up @@ -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); \
Expand Down
2 changes: 1 addition & 1 deletion drivers/stepper/adi_tmc/tmc51xx/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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)
4 changes: 2 additions & 2 deletions drivers/stepper/adi_tmc/tmc51xx/tmc51xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
Loading
Loading