36#include "gpio-hal-arch.h"
46#define LOG_MODULE "spi-hal-arch"
47#define LOG_LEVEL LOG_LEVEL_NONE
50#ifdef SPI_ARCH_CONF_SPI0_CPRS_CPSDVSR
51#define SPI_ARCH_SPI0_CPRS_CPSDVSR SPI_ARCH_CONF_SPI0_CPRS_CPSDVSR
53#define SPI_ARCH_SPI0_CPRS_CPSDVSR 2
56#ifdef SPI_ARCH_CONF_SPI1_CPRS_CPSDVSR
57#define SPI_ARCH_SPI1_CPRS_CPSDVSR SPI_ARCH_CONF_SPI1_CPRS_CPSDVSR
59#define SPI_ARCH_SPI1_CPRS_CPSDVSR 2
62#if (SPI_ARCH_SPI0_CPRS_CPSDVSR & 1) == 1 || \
63 SPI_ARCH_SPI0_CPRS_CPSDVSR < 2 || \
64 SPI_ARCH_SPI0_CPRS_CPSDVSR > 254
65#error SPI_ARCH_SPI0_CPRS_CPSDVSR must be an even number between 2 and 254
68#if (SPI_ARCH_SPI1_CPRS_CPSDVSR & 1) == 1 || \
69 SPI_ARCH_SPI1_CPRS_CPSDVSR < 2 || \
70 SPI_ARCH_SPI1_CPRS_CPSDVSR > 254
71#error SPI_ARCH_SPI1_CPRS_CPSDVSR must be an even number between 2 and 254
75#define SPIX_CS_CLR(port, pin) GPIO_CLR_PIN(GPIO_PORT_TO_BASE(port), GPIO_PIN_MASK(pin))
76#define SPIX_CS_SET(port, pin) GPIO_SET_PIN(GPIO_PORT_TO_BASE(port), GPIO_PIN_MASK(pin))
82#define SSI_SYS_CLOCK SYS_CTRL_SYS_CLOCK
86 uint32_t ioc_ssirxd_ssi;
87 uint32_t ioc_pxx_sel_ssi_clkout;
88 uint32_t ioc_pxx_sel_ssi_txd;
89 uint8_t ssi_cprs_cpsdvsr;
92static const spi_regs_t spi_regs[SSI_INSTANCE_COUNT] = {
96 .ioc_pxx_sel_ssi_clkout = IOC_PXX_SEL_SSI0_CLKOUT,
97 .ioc_pxx_sel_ssi_txd = IOC_PXX_SEL_SSI0_TXD,
98 .ssi_cprs_cpsdvsr = SPI_ARCH_SPI0_CPRS_CPSDVSR,
102 .ioc_pxx_sel_ssi_clkout = IOC_PXX_SEL_SSI1_CLKOUT,
103 .ioc_pxx_sel_ssi_txd = IOC_PXX_SEL_SSI1_TXD,
104 .ssi_cprs_cpsdvsr = SPI_ARCH_SPI1_CPRS_CPSDVSR,
108typedef struct spi_locks_s {
114spi_locks_t board_spi_locks_spi[SPI_CONTROLLER_COUNT] = { { MUTEX_STATUS_UNLOCKED, NULL } };
127 return REG(spi_regs[dev->spi_controller].base +
SSI_DR);
133 REG(spi_regs[dev->spi_controller].base +
SSI_DR) = data;
153 if(board_spi_locks_spi[dev->spi_controller].owner == dev) {
163 if(board_spi_locks_spi[dev->spi_controller].lock == MUTEX_STATUS_LOCKED) {
173 const spi_regs_t *regs;
177 uint32_t cs_port = PIN_TO_PORT(dev->pin_spi_cs);
178 uint32_t cs_pin = PIN_TO_NUM(dev->pin_spi_cs);
180 uint32_t clk_port = PIN_TO_PORT(dev->pin_spi_sck);
181 uint32_t clk_pin = PIN_TO_NUM(dev->pin_spi_sck);
183 uint32_t miso_port = PIN_TO_PORT(dev->pin_spi_miso);
184 uint32_t miso_pin = PIN_TO_NUM(dev->pin_spi_miso);
186 uint32_t mosi_port = PIN_TO_PORT(dev->pin_spi_mosi);
187 uint32_t mosi_pin = PIN_TO_NUM(dev->pin_spi_mosi);
192 if(
mutex_try_lock(&board_spi_locks_spi[dev->spi_controller].lock) ==
false) {
193 return SPI_DEV_STATUS_BUS_LOCKED;
196 board_spi_locks_spi[dev->spi_controller].owner = dev;
199 if(dev->spi_pha != 0) {
204 if(dev->spi_pol != 0) {
215 regs = &spi_regs[dev->spi_controller];
224 REG(regs->base +
SSI_CC) = 0;
227 ioc_set_sel(clk_port, clk_pin, regs->ioc_pxx_sel_ssi_clkout);
228 ioc_set_sel(mosi_port, mosi_pin, regs->ioc_pxx_sel_ssi_txd);
229 REG(regs->ioc_ssirxd_ssi) = dev->pin_spi_miso;
245 REG(regs->base +
SSI_CPSR) = regs->ssi_cprs_cpsdvsr;
248 REG(regs->base +
SSI_CR0) = mode | (0x07);
251 if(!dev->spi_bit_rate) {
254 div = (uint64_t)regs->ssi_cprs_cpsdvsr * dev->spi_bit_rate;
255 scr = (SSI_SYS_CLOCK + div - 1) / div;
256 scr = MIN(MAX(scr, 1), 256) - 1;
258 REG(regs->base +
SSI_CR0) = (REG(regs->base +
SSI_CR0) & ~SSI_CR0_SCR_M) |
264 return SPI_DEV_STATUS_OK;
271 return SPI_DEV_STATUS_BUS_NOT_OWNED;
278 board_spi_locks_spi[dev->spi_controller].owner = NULL;
279 mutex_unlock(&board_spi_locks_spi[dev->spi_controller].lock);
281 return SPI_DEV_STATUS_OK;
287 const uint8_t *write_buf,
int wlen,
288 uint8_t *inbuf,
int rlen,
int ignore_len)
295 return SPI_DEV_STATUS_BUS_NOT_OWNED;
298 LOG_DBG(
"SPI: transfer (r:%d,w:%d) ", rlen, wlen);
300 if(write_buf == NULL && wlen > 0) {
301 return SPI_DEV_STATUS_EINVAL;
303 if(inbuf == NULL && rlen > 0) {
304 return SPI_DEV_STATUS_EINVAL;
307 totlen = MAX(rlen + ignore_len, wlen);
311 return SPI_DEV_STATUS_OK;
314 LOG_DBG_(
"%c%c%c: %u ", rlen > 0 ?
'R' :
'-', wlen > 0 ?
'W' :
'-',
315 ignore_len > 0 ?
'S' :
'-', totlen);
317 for(i = 0; i < totlen; i++) {
318 spix_wait_tx_ready(dev);
319 c = i < wlen ? write_buf[i] : 0;
320 spix_write_buf(dev, c);
321 LOG_DBG_(
"%c%02x->", i < rlen ?
' ' :
'#', c);
324 c = spix_read_buf(dev);
332 return SPI_DEV_STATUS_OK;
Default definitions of C compiler quirk work-arounds.
Header file with register and macro declarations for the cc2538 GPIO module.
#define GPIO_PIN_MASK(PIN)
Converts a pin number to a pin mask.
#define GPIO_PERIPHERAL_CONTROL(PORT_BASE, PIN_MASK)
Configure the pin to be under peripheral control with PIN_MASK of port with PORT_BASE.
#define GPIO_SOFTWARE_CONTROL(PORT_BASE, PIN_MASK)
Configure the pin to be software controlled with PIN_MASK of port with PORT_BASE.
#define GPIO_PORT_TO_BASE(PORT)
Converts a port number to the port base address.
#define GPIO_SET_PIN(PORT_BASE, PIN_MASK)
Set pins with PIN_MASK of port with PORT_BASE high.
#define GPIO_SET_OUTPUT(PORT_BASE, PIN_MASK)
Set pins with PIN_MASK of port with PORT_BASE to output.
void ioc_set_sel(uint8_t port, uint8_t pin, uint8_t sel)
Function select for Port:Pin.
#define IOC_SSIRXD_SSI0
SSI0 RX.
void ioc_set_over(uint8_t port, uint8_t pin, uint8_t over)
Set Port:Pin override function.
#define IOC_OVERRIDE_DIS
Override Disabled.
#define IOC_SSIRXD_SSI1
SSI1 RX.
#define SSI_DR
Access the TX and RX FIFO.
#define SSI1_BASE
Base address for SSI1.
#define SSI_SR_BSY
Busy bit.
#define SSI_CR1
Control register 1.
#define SSI_SR_TNF
Transmit FIFO not full.
#define SSI_SR
Meta information about FIFO.
#define SSI_CR0
Control register 0.
#define SSI_CC
Clock configuration.
#define SSI_CR0_SCR_S
Serial clock rate shift.
#define SSI_CR0_SPH
Serial clock phase (H)
#define SSI0_BASE
Base address for SSI0.
#define SSI_SR_RNE
Receive FIFO not empty.
#define SSI_CPSR
Clock divider.
#define SSI_CR0_SPO
Serial clock phase (O)
#define SSI_CR1_SSE
Synchronous serial port enable.
#define SYS_CTRL_RCGCSSI
SSI[1:0] clocks - active mode.
#define mutex_try_lock(m)
Try to lock a mutex.
#define mutex_unlock(m)
Unlock a previously acquired mutex.
spi_status_t spi_arch_close_and_unlock(const spi_device_t *dev)
Closes and unlocks an SPI controller.
spi_status_t spi_arch_transfer(const spi_device_t *dev, const uint8_t *write_buf, int wlen, uint8_t *inbuf, int rlen, int ignore_len)
Performs an SPI transfer.
spi_status_t
SPI return codes.
spi_status_t spi_arch_lock_and_open(const spi_device_t *dev)
Locks and opens an SPI controller to the configuration specified.
bool spi_arch_has_lock(const spi_device_t *dev)
Checks if a device has locked an SPI controller.
bool spi_arch_is_bus_locked(const spi_device_t *dev)
Checks if an SPI controller is locked by any device.
Header file with declarations for the I/O Control module.
Header file for the logging system.
Header file with register manipulation macro definitions.
Header file for the SPI HAL.
Header file for the cc2538 Synchronous Serial Interface.
SPI Device Configuration.
Header file for the cc2538 System Control driver.