#include "spi.h" #include "gpio.h" #include "register.h" #define WRITE_SPI_REG(spi, reg, value) (WRITE_REGISTER(spi_base_addresses[spi], reg, value)) #define READ_SPI_REG(spi, reg) (READ_REGISTER(spi_base_addresses[spi], reg)) enum spi_register { TASKS_START = 0x10, TASKS_STOP = 0x14, TASKS_SUSPEND = 0x1c, TASKS_RESUME = 0x20, EVENTS_STOPPED = 0x104, EVENTS_ENDRX = 0x110, EVENTS_END = 0x118, EVENTS_ENDTX = 0x120, EVENTS_STARTED = 0x14c, SHORTS = 0x200, INTENSET = 0x304, INTENCLR = 0x308, ENABLE = 0x500, PSEL_SCK = 0x508, PSEL_MOSI = 0x50c, PSEL_MISO = 0x510, FREQUENCY = 0x524, RXD_PTR = 0x534, RXD_MAXCNT = 0x538, RXD_AMOUNT = 0x53c, RXD_LIST = 0x540, TXD_PTR = 0x544, TXD_MAXCNT = 0x548, TXD_AMOUNT = 0x54c, TXD_LIST = 0x550, CONFIG = 0x544, ORC = 0x5c0, }; static const hwaddr spi_base_addresses[] = { [SPI_0] = 0x40003000, [SPI_1] = 0x40004000, [SPI_2] = 0x40023000, }; static const u32 frequency_register_values[] = { [K125] = 0x02000000, [K250] = 0x04000000, [K500] = 0x08000000, [M1] = 0x10000000, [M2] = 0x20000000, [M4] = 0x40000000, [M8] = 0x80000000, }; void spi_master_init(enum spi_interface spi, enum gpio_pin clock, enum gpio_pin mosi, enum gpio_pin miso, enum spi_bits_order order, enum spi_clock_polarity polarity, enum spi_clock_phase phase, enum spi_frequency frequency, char overread_char) { /* Setup GPIO pins */ gpio_output_pin_init(clock, S0S1); WRITE_SPI_REG(spi, PSEL_SCK, (0xffffffff >> 1) & (0xffffffe0 | clock)); gpio_output_pin_init(mosi, S0S1); WRITE_SPI_REG(spi, PSEL_MOSI, (0xffffffff >> 1) & (0xffffffe0 | mosi)); gpio_input_pin_init(miso, PULL_DOWN, HIGH); WRITE_SPI_REG(spi, PSEL_MISO, (0xffffffff >> 1) & (0xffffffe0 | miso)); /* Configure communication behaviour */ u32 spi_config = 0x0; spi_config |= order; spi_config |= phase << 1; spi_config |= polarity << 2; WRITE_SPI_REG(spi, CONFIG, spi_config); WRITE_SPI_REG(spi, RXD_MAXCNT, MAX_TRANSFER_SIZE); WRITE_SPI_REG(spi, TXD_MAXCNT, MAX_TRANSFER_SIZE); WRITE_SPI_REG(spi, FREQUENCY, frequency_register_values[frequency]); WRITE_SPI_REG(spi, ORC, overread_char); /* Enable SPI Master */ WRITE_SPI_REG(spi, ENABLE, 0x7); } u8 spi_master_transfer(enum spi_interface spi, u8 tx_size, u8 tx[], u8 rx_size, u8 rx[]) { u32 events_started_reg = 0; u32 events_end_reg = 0; WRITE_SPI_REG(spi, RXD_MAXCNT, rx_size & 0xff); WRITE_SPI_REG(spi, TXD_MAXCNT, tx_size & 0xff); WRITE_SPI_REG(spi, RXD_PTR, (hwaddr) rx); WRITE_SPI_REG(spi, TXD_PTR, (hwaddr) tx); WRITE_SPI_REG(spi, TASKS_START, 0x1); do { events_started_reg = READ_SPI_REG(spi, EVENTS_STARTED); } while (events_started_reg == 0); do { events_end_reg = READ_SPI_REG(spi, EVENTS_END); } while (events_end_reg == 0); return 0; } void spi_master_stop(enum spi_interface spi, enum gpio_pin clock, enum gpio_pin mosi, enum gpio_pin miso) { u32 events_stopped_reg = 0; WRITE_SPI_REG(spi, TASKS_STOP, 0x1); do { events_stopped_reg = READ_SPI_REG(spi, EVENTS_STOPPED); } while (events_stopped_reg == 0); /* Disable SPI*/ WRITE_SPI_REG(spi, ENABLE, 0x0); /* Set configuration registers to reset values */ WRITE_SPI_REG(spi, CONFIG, 0x0); WRITE_SPI_REG(spi, RXD_MAXCNT, 0x0); WRITE_SPI_REG(spi, TXD_MAXCNT, 0x0); WRITE_SPI_REG(spi, FREQUENCY, frequency_register_values[K250]); WRITE_SPI_REG(spi, ORC, 0x0); /* Free GPIO pins */ WRITE_SPI_REG(spi, PSEL_SCK, 0xffffffff); gpio_pin_disable(clock); WRITE_SPI_REG(spi, PSEL_MOSI, 0xffffffff); gpio_pin_disable(mosi); WRITE_SPI_REG(spi, PSEL_MISO, 0xffffffff); gpio_pin_disable(miso); }