131 lines
3.5 KiB
C
131 lines
3.5 KiB
C
#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;
|
|
}
|