diff options
-rw-r--r-- | chip/stm32/spi_master.c | 17 | ||||
-rw-r--r-- | chip/stm32/usb_spi.c | 16 | ||||
-rw-r--r-- | chip/stm32/usb_spi.h | 8 |
3 files changed, 28 insertions, 13 deletions
diff --git a/chip/stm32/spi_master.c b/chip/stm32/spi_master.c index 47c5be3979..4b48f8ea80 100644 --- a/chip/stm32/spi_master.c +++ b/chip/stm32/spi_master.c @@ -228,13 +228,16 @@ static int spi_master_initialize(int port) spi->cr1 |= STM32_SPI_CR1_BIDIMODE | STM32_SPI_CR1_BIDIOE; #endif + /* Drive Chip Select high for all ports before turning on SPI module */ for (i = 0; i < spi_devices_used; i++) { if (spi_devices[i].port != port) continue; - /* Drive SS high */ gpio_set_level(spi_devices[i].gpio_cs, 1); } + /* Enable SPI hardware module. This will actively drive the CLK pin */ + spi->cr1 |= STM32_SPI_CR1_SPE; + /* Set flag */ spi_enabled[port] = 1; @@ -257,7 +260,7 @@ static int spi_master_shutdown(int port) dma_disable(dma_tx_option[port].channel); dma_disable(dma_rx_option[port].channel); - /* Disable SPI */ + /* Disable SPI. Let the CLK pin float. */ spi->cr1 &= ~STM32_SPI_CR1_SPE; spi_clear_rx_fifo(spi); @@ -349,6 +352,10 @@ int spi_transaction_async(const struct spi_device_t *spi_device, stm32_spi_regs_t *spi = SPI_REGS[port]; char *buf = NULL; + /* We should not ever be called when disabled, but fail early if so. */ + if (!spi_enabled[port]) + return EC_ERROR_BUSY; + #ifndef CONFIG_SPI_HALFDUPLEX if (rxlen == SPI_READBACK_ALL) { buf = rxdata; @@ -372,7 +379,6 @@ int spi_transaction_async(const struct spi_device_t *spi_device, #ifdef CONFIG_SPI_HALFDUPLEX spi->cr1 |= STM32_SPI_CR1_BIDIOE; #endif - spi->cr1 |= STM32_SPI_CR1_SPE; if (full_readback) return EC_SUCCESS; @@ -383,8 +389,6 @@ int spi_transaction_async(const struct spi_device_t *spi_device, spi_clear_tx_fifo(spi); - spi->cr1 &= ~STM32_SPI_CR1_SPE; - if (rxlen) { rv = spi_dma_start(port, buf, rxdata, rxlen); if (rv != EC_SUCCESS) @@ -392,7 +396,6 @@ int spi_transaction_async(const struct spi_device_t *spi_device, #ifdef CONFIG_SPI_HALFDUPLEX spi->cr1 &= ~STM32_SPI_CR1_BIDIOE; #endif - spi->cr1 |= STM32_SPI_CR1_SPE; } err_free: @@ -406,9 +409,7 @@ err_free: int spi_transaction_flush(const struct spi_device_t *spi_device) { int rv = spi_dma_wait(spi_device->port); - stm32_spi_regs_t *spi = SPI_REGS[spi_device->port]; - spi->cr1 &= ~STM32_SPI_CR1_SPE; /* Drive SS high */ gpio_set_level(spi_device->gpio_cs, 1); diff --git a/chip/stm32/usb_spi.c b/chip/stm32/usb_spi.c index b560b55709..597d4c5df7 100644 --- a/chip/stm32/usb_spi.c +++ b/chip/stm32/usb_spi.c @@ -69,14 +69,19 @@ static int rx_valid(struct usb_spi_config const *config) void usb_spi_deferred(struct usb_spi_config const *config) { + int enabled; + + if (config->flags & USB_SPI_CONFIG_FLAGS_IGNORE_HOST_SIDE_ENABLE) + enabled = config->state->enabled_device; + else + enabled = config->state->enabled_device && + config->state->enabled_host; + /* * If our overall enabled state has changed we call the board specific * enable or disable routines and save our new state. */ - int enabled = (config->state->enabled_host && - config->state->enabled_device); - - if (enabled ^ config->state->enabled) { + if (enabled != config->state->enabled) { if (enabled) usb_spi_board_enable(config); else usb_spi_board_disable(config); @@ -180,7 +185,8 @@ int usb_spi_interface(struct usb_spi_config const *config, * Our state has changed, call the deferred function to handle the * state change. */ - hook_call_deferred(config->deferred, 0); + if (!(config->flags & USB_SPI_CONFIG_FLAGS_IGNORE_HOST_SIDE_ENABLE)) + hook_call_deferred(config->deferred, 0); btable_ep[0].tx_count = 0; STM32_TOGGLE_EP(0, EP_TX_RX_MASK, EP_TX_RX_VALID, EP_STATUS_OUT); diff --git a/chip/stm32/usb_spi.h b/chip/stm32/usb_spi.h index fda770345d..a32febce03 100644 --- a/chip/stm32/usb_spi.h +++ b/chip/stm32/usb_spi.h @@ -126,6 +126,14 @@ struct usb_spi_config { }; /* + * Use when you want the SPI subsystem to be enabled even when the USB SPI + * endpoint is not enabled by the host. This means that when this firmware + * enables SPI, then the HW SPI module is enabled (i.e. SPE bit is set) until + * this firmware disables the SPI module; it ignores the host's enables state. + */ +#define USB_SPI_CONFIG_FLAGS_IGNORE_HOST_SIDE_ENABLE BIT(0) + +/* * Convenience macro for defining a USB SPI bridge driver. * * NAME is used to construct the names of the trampoline functions and the |