#include "bsp/max2771_spi.h" #include "bsp/mmio.h" #include "bsp/soc.h" #define MAX2771_COMMAND (BSP_MAX2771_SPI_BASE + 0x00u) #define MAX2771_WRITE_DATA (BSP_MAX2771_SPI_BASE + 0x04u) #define MAX2771_READ_DATA (BSP_MAX2771_SPI_BASE + 0x08u) #define MAX2771_STATUS (BSP_MAX2771_SPI_BASE + 0x0cu) #define MAX2771_INPUT_CLOCK (BSP_MAX2771_SPI_BASE + 0x10u) #define MAX2771_SCLK (BSP_MAX2771_SPI_BASE + 0x14u) #define MAX2771_HALF_PERIOD (BSP_MAX2771_SPI_BASE + 0x18u) #define MAX2771_IDENT (BSP_MAX2771_SPI_BASE + 0x1cu) #define MAX2771_STATUS_READY 0x1u #define MAX2771_STATUS_BUSY 0x2u #define MAX2771_COMMAND_READ 0x100u #define MAX2771_IDENT_VALUE 0x4d415831u #define MAX2771_TIMEOUT_US 1000u static bsp_max2771_status_t max2771_wait_ready(void) { uint64_t timeout_ticks = ((uint64_t)BSP_CLINT_TIMEBASE_HZ * MAX2771_TIMEOUT_US + 999999u) / 1000000u; if (timeout_ticks == 0u) { timeout_ticks = 1u; } const uint64_t start = bsp_read64(BSP_CLINT_MTIME); while ((bsp_read32(MAX2771_STATUS) & MAX2771_STATUS_READY) == 0u) { if ((bsp_read64(BSP_CLINT_MTIME) - start) >= timeout_ticks) { return BSP_MAX2771_ERR_TIMEOUT; } } return BSP_MAX2771_OK; } uint32_t bsp_max2771_status(void) { return bsp_read32(MAX2771_STATUS); } uint32_t bsp_max2771_input_clock_hz(void) { return bsp_read32(MAX2771_INPUT_CLOCK); } uint32_t bsp_max2771_sclk_hz(void) { return bsp_read32(MAX2771_SCLK); } uint32_t bsp_max2771_half_period_cycles(void) { return bsp_read32(MAX2771_HALF_PERIOD); } bsp_max2771_status_t bsp_max2771_spi_init(void) { if (bsp_read32(MAX2771_IDENT) != MAX2771_IDENT_VALUE) { return BSP_MAX2771_ERR_IP; } const uint32_t input_hz = bsp_max2771_input_clock_hz(); const uint32_t sclk_hz = bsp_max2771_sclk_hz(); const uint32_t half_cycles = bsp_max2771_half_period_cycles(); if ((input_hz == 0u) || (half_cycles == 0u) || (sclk_hz == 0u) || (sclk_hz > BSP_MAX2771_MAX_SCLK_HZ) || (sclk_hz != (input_hz / (2u * half_cycles)))) { return BSP_MAX2771_ERR_CLOCK; } #ifdef BSP_MAX2771_INPUT_CLOCK_HZ if (input_hz != (uint32_t)BSP_MAX2771_INPUT_CLOCK_HZ) { return BSP_MAX2771_ERR_CLOCK; } #endif return max2771_wait_ready(); } bsp_max2771_status_t bsp_max2771_write(uint8_t address, uint32_t value) { if (address > BSP_MAX2771_MAX_REGISTER) { return BSP_MAX2771_ERR_ARGUMENT; } bsp_max2771_status_t status = max2771_wait_ready(); if (status != BSP_MAX2771_OK) { return status; } bsp_write32(MAX2771_WRITE_DATA, value); bsp_write32(MAX2771_COMMAND, (uint32_t)address); return max2771_wait_ready(); } bsp_max2771_status_t bsp_max2771_read(uint8_t address, uint32_t *value) { if ((address > BSP_MAX2771_MAX_REGISTER) || (value == 0)) { return BSP_MAX2771_ERR_ARGUMENT; } bsp_max2771_status_t status = max2771_wait_ready(); if (status != BSP_MAX2771_OK) { return status; } bsp_write32(MAX2771_COMMAND, MAX2771_COMMAND_READ | (uint32_t)address); status = max2771_wait_ready(); if (status == BSP_MAX2771_OK) { *value = bsp_read32(MAX2771_READ_DATA); } return status; } bsp_max2771_status_t bsp_max2771_write_verified(uint8_t address, uint32_t value) { bsp_max2771_status_t status = bsp_max2771_write(address, value); if (status != BSP_MAX2771_OK) { return status; } uint32_t readback = 0u; status = bsp_max2771_read(address, &readback); if (status != BSP_MAX2771_OK) { return status; } return (readback == value) ? BSP_MAX2771_OK : BSP_MAX2771_ERR_VERIFY; }