36 #include "gpio-hal-arch.h" 43 #include "sys/mutex.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;
92 static 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,
108 typedef struct spi_locks_s {
114 spi_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;
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;
bool spi_arch_has_lock(const spi_device_t *dev)
Checks if a device has locked an SPI controller.
#define SSI_CR0_SPH
Serial clock phase (H)
#define IOC_SSIRXD_SSI0
SSI0 RX.
Header file for the cc2538 System Control driver.
#define SSI_CC
Clock configuration.
#define GPIO_SET_PIN(PORT_BASE, PIN_MASK)
Set pins with PIN_MASK of port with PORT_BASE high.
#define SSI_CR0_SCR_M
Serial clock rate mask.
#define SSI_CPSR
Clock divider.
Header file for the cc2538 Synchronous Serial Interface.
Header file with register and macro declarations for the cc2538 GPIO module.
#define SSI_SR_TNF
Transmit FIFO not full.
Header file with declarations for the I/O Control module.
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.
Header file with register manipulation macro definitions.
#define SSI1_BASE
Base address for SSI1.
#define mutex_unlock(m)
Unlock a previously acquired mutex.
#define SSI_CR1
Control register 1.
#define IOC_OVERRIDE_DIS
Override Disabled.
#define SSI_CR0_SPO
Serial clock phase (O)
#define SSI0_BASE
Base address for SSI0.
Header file for the SPI HAL.
#define GPIO_PIN_MASK(PIN)
Converts a pin number to a pin mask.
spi_status_t
SPI return codes.
#define SSI_SR
Meta information about FIFO.
spi_status_t spi_arch_lock_and_open(const spi_device_t *dev)
Locks and opens an SPI controller to the configuration specified.
#define GPIO_SOFTWARE_CONTROL(PORT_BASE, PIN_MASK)
Configure the pin to be software controlled with PIN_MASK of port with PORT_BASE. ...
#define SSI_SR_BSY
Busy bit.
#define mutex_try_lock(m)
Try to lock a mutex.
void ioc_set_over(uint8_t port, uint8_t pin, uint8_t over)
Set Port:Pin override function.
#define SSI_CR0
Control register 0.
#define GPIO_SET_OUTPUT(PORT_BASE, PIN_MASK)
Set pins with PIN_MASK of port with PORT_BASE to output.
#define SSI_CR0_SCR_S
Serial clock rate shift.
#define SSI_DR
Access the TX and RX FIFO.
#define SYS_CTRL_RCGCSSI
SSI[1:0] clocks - active mode.
#define SSI_SR_RNE
Receive FIFO not empty.
#define SSI_CR1_SSE
Synchronous serial port enable.
#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 IOC_SSIRXD_SSI1
SSI1 RX.
bool spi_arch_is_bus_locked(const spi_device_t *dev)
Checks if an SPI controller is locked by any device.
void ioc_set_sel(uint8_t port, uint8_t pin, uint8_t sel)
Function select for Port:Pin.
SPI Device Configuration.
Default definitions of C compiler quirk work-arounds.
#define GPIO_PORT_TO_BASE(PORT)
Converts a port number to the port base address.
Header file for the logging system
spi_status_t spi_arch_close_and_unlock(const spi_device_t *dev)
Closes and unlocks an SPI controller.