drivers: spi: spi-bitbang: Add support for half duplex
Implement support for half duplex communication in the bit bang SPI driver. The SPI driver will use the MOSI pin is for both TX and RX operations when using half duplex mode. In half-duplex mode, the driver configures the MOSI pin as an input pin for input only transactions. Transactions that are bidirectional are forbidden. After an SPI transaction, the MOSI pin is left as an input if it was an RX transaction or an output after a TX transaction. Like before, the MOSI pin is initialized as an (inactive) output pin when the bus is initialized. Signed-off-by: Andreas Sandberg <andreas@sandberg.uk>
This commit is contained in:
parent
8bfc215bef
commit
d33b89befe
1 changed files with 48 additions and 23 deletions
|
@ -27,20 +27,6 @@ struct spi_bitbang_config {
|
|||
struct gpio_dt_spec miso_gpio;
|
||||
};
|
||||
|
||||
static inline bool spi_bitbang_has_miso(const struct device *dev)
|
||||
{
|
||||
const struct spi_bitbang_config *info = dev->config;
|
||||
|
||||
return info->miso_gpio.port != NULL;
|
||||
}
|
||||
|
||||
static inline bool spi_bitbang_has_mosi(const struct device *dev)
|
||||
{
|
||||
const struct spi_bitbang_config *info = dev->config;
|
||||
|
||||
return info->mosi_gpio.port != NULL;
|
||||
}
|
||||
|
||||
static int spi_bitbang_configure(const struct spi_bitbang_config *info,
|
||||
struct spi_bitbang_data *data,
|
||||
const struct spi_config *config)
|
||||
|
@ -88,8 +74,50 @@ static int spi_bitbang_transceive(const struct device *dev,
|
|||
const struct spi_bitbang_config *info = dev->config;
|
||||
struct spi_bitbang_data *data = dev->data;
|
||||
struct spi_context *ctx = &data->ctx;
|
||||
int rc;
|
||||
const struct gpio_dt_spec *miso = NULL;
|
||||
const struct gpio_dt_spec *mosi = NULL;
|
||||
gpio_flags_t mosi_flags = GPIO_OUTPUT_INACTIVE;
|
||||
|
||||
spi_bitbang_configure(info, data, spi_cfg);
|
||||
rc = spi_bitbang_configure(info, data, spi_cfg);
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (spi_cfg->operation & SPI_HALF_DUPLEX) {
|
||||
if (!info->mosi_gpio.port) {
|
||||
LOG_ERR("No MOSI pin specified in half duplex mode");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (tx_bufs && rx_bufs) {
|
||||
LOG_ERR("Both RX and TX specified in half duplex mode");
|
||||
return -EINVAL;
|
||||
} else if (tx_bufs && !rx_bufs) {
|
||||
/* TX mode */
|
||||
mosi = &info->mosi_gpio;
|
||||
} else if (!tx_bufs && rx_bufs) {
|
||||
/* RX mode */
|
||||
mosi_flags = GPIO_INPUT;
|
||||
miso = &info->mosi_gpio;
|
||||
}
|
||||
} else {
|
||||
if (info->mosi_gpio.port) {
|
||||
mosi = &info->mosi_gpio;
|
||||
}
|
||||
|
||||
if (info->miso_gpio.port) {
|
||||
miso = &info->miso_gpio;
|
||||
}
|
||||
}
|
||||
|
||||
if (info->mosi_gpio.port) {
|
||||
rc = gpio_pin_configure_dt(&info->mosi_gpio, mosi_flags);
|
||||
if (rc < 0) {
|
||||
LOG_ERR("Couldn't configure MOSI pin: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
spi_context_buffers_setup(ctx, tx_bufs, rx_bufs, data->dfs);
|
||||
|
||||
|
@ -114,9 +142,6 @@ static int spi_bitbang_transceive(const struct device *dev,
|
|||
|
||||
const uint32_t wait_us = data->wait_us;
|
||||
|
||||
const bool has_miso = spi_bitbang_has_miso(dev);
|
||||
const bool has_mosi = spi_bitbang_has_mosi(dev);
|
||||
|
||||
while (spi_context_tx_buf_on(ctx) || spi_context_rx_buf_on(ctx)) {
|
||||
uint16_t w = 0;
|
||||
|
||||
|
@ -136,7 +161,7 @@ static int spi_bitbang_transceive(const struct device *dev,
|
|||
int b = 0;
|
||||
bool do_read = false;
|
||||
|
||||
if (has_miso && spi_context_rx_buf_on(ctx)) {
|
||||
if (miso && spi_context_rx_buf_on(ctx)) {
|
||||
do_read = true;
|
||||
}
|
||||
|
||||
|
@ -146,8 +171,8 @@ static int spi_bitbang_transceive(const struct device *dev,
|
|||
b = 0;
|
||||
|
||||
/* setup data out first thing */
|
||||
if (has_mosi) {
|
||||
gpio_pin_set_dt(&info->mosi_gpio, d);
|
||||
if (mosi) {
|
||||
gpio_pin_set_dt(mosi, d);
|
||||
}
|
||||
|
||||
k_busy_wait(wait_us);
|
||||
|
@ -156,7 +181,7 @@ static int spi_bitbang_transceive(const struct device *dev,
|
|||
gpio_pin_set_dt(&info->clk_gpio, !clock_state);
|
||||
|
||||
if (!loop && do_read && !cpha) {
|
||||
b = gpio_pin_get_dt(&info->miso_gpio);
|
||||
b = gpio_pin_get_dt(miso);
|
||||
}
|
||||
|
||||
k_busy_wait(wait_us);
|
||||
|
@ -165,7 +190,7 @@ static int spi_bitbang_transceive(const struct device *dev,
|
|||
gpio_pin_set_dt(&info->clk_gpio, clock_state);
|
||||
|
||||
if (!loop && do_read && cpha) {
|
||||
b = gpio_pin_get_dt(&info->miso_gpio);
|
||||
b = gpio_pin_get_dt(miso);
|
||||
}
|
||||
|
||||
if (loop) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue