int spi_slave_send_response_async(struct spi_comm_packet *resp) { int size = resp->size + SPI_PACKET_HEADER_SIZE; stm32_spi_regs_t *spi = STM32_SPI1_REGS; if (size > SPI_PACKET_MAX_SIZE) return EC_ERROR_OVERFLOW; if (out_msg != (uint8_t *)resp) memcpy(out_msg, resp, size); master_slave_sync(100); if (spi->sr & STM32_SPI_SR_RXNE) in_msg[0] = spi->dr; spi->dr = out_msg[0]; /* Set N_CHG (master SPI_NSS) to high */ STM32_GPIO_BSRR(GPIO_A) = 1 << 1; while (!(spi->sr & STM32_SPI_SR_RXNE)) ; in_msg[0] = spi->dr; dma_clear_isr(STM32_DMAC_SPI1_TX); dma_clear_isr(STM32_DMAC_SPI1_RX); dma_start_rx(&dma_rx_option, size - 1, in_msg); dma_prepare_tx(&dma_tx_option, size - 1, out_msg + 1); dma_go(dma_get_channel(STM32_DMAC_SPI1_TX)); master_slave_sync(5); return EC_SUCCESS; }
const struct spi_comm_packet *spi_master_wait_response_done(void) { const struct spi_comm_packet *resp = (const struct spi_comm_packet *)in_msg; stm32_spi_regs_t *spi = STM32_SPI1_REGS; if (dma_wait(STM32_DMAC_SPI1_TX) || dma_wait(STM32_DMAC_SPI1_RX)) { debug_printf("SPI: Incomplete response\n"); goto err_wait_response_done; } if (spi->sr & STM32_SPI_SR_CRCERR) { debug_printf("SPI: CRC mismatch\n"); goto err_wait_response_done; } if (resp->cmd_sts != EC_SUCCESS) { debug_printf("SPI: Slave error\n"); goto err_wait_response_done; } exit_wait_response_done: dma_disable(STM32_DMAC_SPI1_TX); dma_disable(STM32_DMAC_SPI1_RX); dma_clear_isr(STM32_DMAC_SPI1_TX); dma_clear_isr(STM32_DMAC_SPI1_RX); /* Set CS1 (slave SPI_NSS) to high */ STM32_GPIO_BSRR(GPIO_A) = 1 << 6; return resp; err_wait_response_done: resp = NULL; goto exit_wait_response_done; }
int spi_master_send_command(struct spi_comm_packet *cmd) { stm32_spi_regs_t *spi = STM32_SPI1_REGS; int ret; if (cmd->size + 3 > SPI_PACKET_MAX_SIZE) return EC_ERROR_OVERFLOW; /* Wait for SPI_NSS to go low */ if (wait_for_signal(GPIO_A, 1 << 0, 0, 10 * MSEC)) return EC_ERROR_TIMEOUT; /* Set CS1 (slave SPI_NSS) to low */ STM32_GPIO_BSRR(GPIO_A) = 1 << (6 + 16); /* Wait for the slave to acknowledge */ master_slave_sync(5); /* Clock out the packet size. */ spi->dr = cmd->size; while (!(spi->sr & STM32_SPI_SR_RXNE)) ; ret = spi->dr; /* Wait for the slave to acknowledge */ master_slave_sync(5); /* Clock out command. Don't care about input. */ ret = spi_master_read_write_byte(in_msg, ((uint8_t *)cmd) + 1, cmd->size + SPI_PACKET_HEADER_SIZE - 1); return ret; }
int spi_slave_send_response_flush(void) { int ret; ret = dma_wait(STM32_DMAC_SPI1_TX); ret |= dma_wait(STM32_DMAC_SPI1_RX); dma_disable(STM32_DMAC_SPI1_TX); dma_disable(STM32_DMAC_SPI1_RX); dma_clear_isr(STM32_DMAC_SPI1_TX); dma_clear_isr(STM32_DMAC_SPI1_RX); /* Set N_CHG (master SPI_NSS) to low */ STM32_GPIO_BSRR(GPIO_A) = 1 << (1 + 16); return ret; }
int spi_master_wait_response_async(void) { stm32_spi_regs_t *spi = STM32_SPI1_REGS; int size; master_slave_sync(40); if (wait_for_signal(GPIO_A, 1 << 0, 1, 40 * MSEC)) goto err_wait_resp_async; /* Discard potential garbage in SPI DR */ if (spi->sr & STM32_SPI_SR_RXNE) in_msg[0] = spi->dr; /* Get the packet size */ spi->dr = DUMMY_DATA; while (!(spi->sr & STM32_SPI_SR_RXNE)) ; in_msg[0] = spi->dr; size = in_msg[0] + SPI_PACKET_HEADER_SIZE; master_slave_sync(5); dma_clear_isr(STM32_DMAC_SPI1_TX); dma_clear_isr(STM32_DMAC_SPI1_RX); /* Get the rest of the packet*/ dma_start_rx(&dma_rx_option, size - 1, in_msg + 1); dma_prepare_tx(&dma_tx_option, size - 1, out_msg); dma_go(dma_get_channel(STM32_DMAC_SPI1_TX)); return EC_SUCCESS; err_wait_resp_async: /* Set CS1 (slave SPI_NSS) to high */ STM32_GPIO_BSRR(GPIO_A) = 1 << 6; return EC_ERROR_TIMEOUT; }
void gpio_set_level(enum gpio_signal signal, int value) { STM32_GPIO_BSRR(gpio_list[signal].port) = gpio_list[signal].mask << (value ? 0 : 16); }
static inline void output_disable(void) { /* GPF0 (disable OR'ing FETs) = 0 */ STM32_GPIO_BSRR(GPIO_F) = GPIO_RESET(0); }
static inline void output_enable(void) { /* GPF0 (enable OR'ing FETs) = 1 */ STM32_GPIO_BSRR(GPIO_F) = GPIO_SET(0); }
static inline void set_output_voltage(enum volt v) { /* set voltage_select on PA13/PA14 */ STM32_GPIO_BSRR(GPIO_A) = v; }
static inline void discharge_disable(void) { STM32_GPIO_BSRR(GPIO_F) = GPIO_RESET(1); adc_disable_watchdog(); }
static inline void discharge_enable(void) { STM32_GPIO_BSRR(GPIO_F) = GPIO_SET(1); }
void gpio_set_flags_by_mask(uint32_t port, uint32_t pmask, uint32_t flags) { uint32_t addr, cnf, mode, mask; gpio_config_info(port, pmask, &addr, &mode, &cnf); mask = REG32(addr) & ~(cnf | mode); /* * For STM32, the port configuration field changes meaning * depending on whether the port is an input, analog input, * output, or alternate function. */ if (flags & GPIO_OUTPUT) { /* * This sets output max speed to 10MHz. That should be * sufficient for most GPIO needs; the only thing that needs to * go faster is SPI, which overrides the port speed on its own. */ mask |= 0x11111111 & mode; if (flags & GPIO_OPEN_DRAIN) mask |= 0x44444444 & cnf; } else { /* * GPIOx_ODR determines which resistor to activate in * input mode, see Table 16 (datasheet rm0041) */ if (flags & GPIO_ANALOG) { /* Analog input, MODE=00 CNF=00 */ /* the 4 bits in mask are already reset above */ } else if (flags & GPIO_PULL_UP) { mask |= 0x88888888 & cnf; STM32_GPIO_BSRR(port) = pmask; } else if (flags & GPIO_PULL_DOWN) { mask |= 0x88888888 & cnf; STM32_GPIO_BSRR(port) = pmask << 16; } else { mask |= 0x44444444 & cnf; } } REG32(addr) = mask; if (flags & GPIO_OUTPUT) { /* * Set pin level after port has been set up as to avoid * potential damage, e.g. driving an open-drain output high * before it has been configured as such. */ if (flags & GPIO_HIGH) STM32_GPIO_BSRR(port) = pmask; else if (flags & GPIO_LOW) STM32_GPIO_BSRR(port) = pmask << 16; } /* Set up interrupts if necessary */ ASSERT(!(flags & (GPIO_INT_F_LOW | GPIO_INT_F_HIGH))); if (flags & GPIO_INT_F_RISING) STM32_EXTI_RTSR |= pmask; if (flags & GPIO_INT_F_FALLING) STM32_EXTI_FTSR |= pmask; /* Interrupt is enabled by gpio_enable_interrupt() */ }