Contiki-NG
spi-arch.c
1 /*
2  * Copyright (c) 2016-2017, Yanzi Networks.
3  * Copyright (c) 2018, University of Bristol.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  * 3. Neither the name of the copyright holder nor the names of its
15  * contributors may be used to endorse or promote products derived
16  * from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
29  * OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <stdint.h>
33 #include "contiki.h"
34 #include "reg.h"
35 #include "dev/spi.h"
36 #include "gpio-hal-arch.h"
37 #include "sys/cc.h"
38 #include "ioc.h"
39 #include "sys-ctrl.h"
40 #include "ssi.h"
41 #include "gpio.h"
42 #include "sys/log.h"
43 #include "sys/mutex.h"
44 /*---------------------------------------------------------------------------*/
45 /* Log configuration */
46 #define LOG_MODULE "spi-hal-arch"
47 #define LOG_LEVEL LOG_LEVEL_NONE
48 /*---------------------------------------------------------------------------*/
49 /* Default values for the clock rate divider */
50 #ifdef SPI_ARCH_CONF_SPI0_CPRS_CPSDVSR
51 #define SPI_ARCH_SPI0_CPRS_CPSDVSR SPI_ARCH_CONF_SPI0_CPRS_CPSDVSR
52 #else
53 #define SPI_ARCH_SPI0_CPRS_CPSDVSR 2
54 #endif
55 
56 #ifdef SPI_ARCH_CONF_SPI1_CPRS_CPSDVSR
57 #define SPI_ARCH_SPI1_CPRS_CPSDVSR SPI_ARCH_CONF_SPI1_CPRS_CPSDVSR
58 #else
59 #define SPI_ARCH_SPI1_CPRS_CPSDVSR 2
60 #endif
61 
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
66 #endif
67 
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
72 #endif
73 /*---------------------------------------------------------------------------*/
74 /* CS set and clear macros */
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))
77 /*---------------------------------------------------------------------------*/
78 /*
79  * Clock source from which the baud clock is determined for the SSI, according
80  * to SSI_CC.CS.
81  */
82 #define SSI_SYS_CLOCK SYS_CTRL_SYS_CLOCK
83 /*---------------------------------------------------------------------------*/
84 typedef struct {
85  uint32_t base;
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;
90 } spi_regs_t;
91 /*---------------------------------------------------------------------------*/
92 static const spi_regs_t spi_regs[SSI_INSTANCE_COUNT] = {
93  {
94  .base = SSI0_BASE,
95  .ioc_ssirxd_ssi = IOC_SSIRXD_SSI0,
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,
99  }, {
100  .base = SSI1_BASE,
101  .ioc_ssirxd_ssi = IOC_SSIRXD_SSI1,
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,
105  }
106 };
107 
108 typedef struct spi_locks_s {
109  mutex_t lock;
110  const spi_device_t *owner;
111 } spi_locks_t;
112 
113 /* One lock per SPI controller */
114 spi_locks_t board_spi_locks_spi[SPI_CONTROLLER_COUNT] = { { MUTEX_STATUS_UNLOCKED, NULL } };
115 
116 /*---------------------------------------------------------------------------*/
117 static void
118 spix_wait_tx_ready(const spi_device_t *dev)
119 {
120  /* Infinite loop until SR_TNF - Transmit FIFO Not Full */
121  while(!(REG(spi_regs[dev->spi_controller].base + SSI_SR) & SSI_SR_TNF));
122 }
123 /*---------------------------------------------------------------------------*/
124 static int
125 spix_read_buf(const spi_device_t *dev)
126 {
127  return REG(spi_regs[dev->spi_controller].base + SSI_DR);
128 }
129 /*---------------------------------------------------------------------------*/
130 static void
131 spix_write_buf(const spi_device_t *dev, int data)
132 {
133  REG(spi_regs[dev->spi_controller].base + SSI_DR) = data;
134 }
135 /*---------------------------------------------------------------------------*/
136 static void
137 spix_wait_eotx(const spi_device_t *dev)
138 {
139  /* wait until not busy */
140  while(REG(spi_regs[dev->spi_controller].base + SSI_SR) & SSI_SR_BSY);
141 }
142 /*---------------------------------------------------------------------------*/
143 static void
144 spix_wait_eorx(const spi_device_t *dev)
145 {
146  /* wait as long as receive is empty */
147  while(!(REG(spi_regs[dev->spi_controller].base + SSI_SR) & SSI_SR_RNE));
148 }
149 /*---------------------------------------------------------------------------*/
150 bool
152 {
153  if(board_spi_locks_spi[dev->spi_controller].owner == dev) {
154  return true;
155  }
156 
157  return false;
158 }
159 /*---------------------------------------------------------------------------*/
160 bool
162 {
163  if(board_spi_locks_spi[dev->spi_controller].lock == MUTEX_STATUS_LOCKED) {
164  return true;
165  }
166 
167  return false;
168 }
169 /*---------------------------------------------------------------------------*/
172 {
173  const spi_regs_t *regs;
174  uint32_t scr;
175  uint64_t div;
176 
177  uint32_t cs_port = PIN_TO_PORT(dev->pin_spi_cs);
178  uint32_t cs_pin = PIN_TO_NUM(dev->pin_spi_cs);
179 
180  uint32_t clk_port = PIN_TO_PORT(dev->pin_spi_sck);
181  uint32_t clk_pin = PIN_TO_NUM(dev->pin_spi_sck);
182 
183  uint32_t miso_port = PIN_TO_PORT(dev->pin_spi_miso);
184  uint32_t miso_pin = PIN_TO_NUM(dev->pin_spi_miso);
185 
186  uint32_t mosi_port = PIN_TO_PORT(dev->pin_spi_mosi);
187  uint32_t mosi_pin = PIN_TO_NUM(dev->pin_spi_mosi);
188 
189  uint32_t mode = 0;
190 
191  /* lock the SPI bus */
192  if(mutex_try_lock(&board_spi_locks_spi[dev->spi_controller].lock) == false) {
193  return SPI_DEV_STATUS_BUS_LOCKED;
194  }
195 
196  board_spi_locks_spi[dev->spi_controller].owner = dev;
197 
198  /* Set SPI phase */
199  if(dev->spi_pha != 0) {
200  mode = mode | SSI_CR0_SPH;
201  }
202 
203  /* Set SPI polarity */
204  if(dev->spi_pol != 0) {
205  mode = mode | SSI_CR0_SPO;
206  }
207 
208  /* CS pin configuration */
210  GPIO_PIN_MASK(cs_pin));
211  ioc_set_over(cs_port, cs_pin, IOC_OVERRIDE_DIS);
213  GPIO_SET_PIN(GPIO_PORT_TO_BASE(cs_port), GPIO_PIN_MASK(cs_pin));
214 
215  regs = &spi_regs[dev->spi_controller];
216 
217  /* SSI Enable */
218  REG(SYS_CTRL_RCGCSSI) |= (1 << dev->spi_controller);
219 
220  /* Start by disabling the peripheral before configuring it */
221  REG(regs->base + SSI_CR1) = 0;
222 
223  /* Set the system clock as the SSI clock */
224  REG(regs->base + SSI_CC) = 0;
225 
226  /* Set the mux correctly to connect the SSI pins to the correct GPIO pins */
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;
230 
231  /* Put all the SSI gpios into peripheral mode */
233  GPIO_PIN_MASK(clk_pin));
235  GPIO_PIN_MASK(mosi_pin));
237  GPIO_PIN_MASK(miso_pin));
238 
239  /* Disable any pull ups or the like */
240  ioc_set_over(clk_port, clk_pin, IOC_OVERRIDE_DIS);
241  ioc_set_over(mosi_port, mosi_pin, IOC_OVERRIDE_DIS);
242  ioc_set_over(miso_port, miso_pin, IOC_OVERRIDE_DIS);
243 
244  /* Configure the clock */
245  REG(regs->base + SSI_CPSR) = regs->ssi_cprs_cpsdvsr;
246 
247  /* Configure the mode */
248  REG(regs->base + SSI_CR0) = mode | (0x07);
249 
250  /* Configure the SSI serial clock rate */
251  if(!dev->spi_bit_rate) {
252  scr = 255;
253  } else {
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;
257  }
258  REG(regs->base + SSI_CR0) = (REG(regs->base + SSI_CR0) & ~SSI_CR0_SCR_M) |
259  scr << SSI_CR0_SCR_S;
260 
261  /* Enable the SSI */
262  REG(regs->base + SSI_CR1) |= SSI_CR1_SSE;
263 
264  return SPI_DEV_STATUS_OK;
265 }
266 /*---------------------------------------------------------------------------*/
269 {
270  if(!spi_arch_has_lock(dev)) {
271  return SPI_DEV_STATUS_BUS_NOT_OWNED;
272  }
273 
274  /* Disable SSI */
275  REG(SYS_CTRL_RCGCSSI) &= ~(1 << dev->spi_controller);
276 
277  /* Unlock the SPI bus */
278  board_spi_locks_spi[dev->spi_controller].owner = NULL;
279  mutex_unlock(&board_spi_locks_spi[dev->spi_controller].lock);
280 
281  return SPI_DEV_STATUS_OK;
282 }
283 /*---------------------------------------------------------------------------*/
284 /* Assumes that checking dev and bus is not NULL before calling this */
287  const uint8_t *write_buf, int wlen,
288  uint8_t *inbuf, int rlen, int ignore_len)
289 {
290  int i;
291  int totlen;
292  uint8_t c;
293 
294  if(!spi_arch_has_lock(dev)) {
295  return SPI_DEV_STATUS_BUS_NOT_OWNED;
296  }
297 
298  LOG_DBG("SPI: transfer (r:%d,w:%d) ", rlen, wlen);
299 
300  if(write_buf == NULL && wlen > 0) {
301  return SPI_DEV_STATUS_EINVAL;
302  }
303  if(inbuf == NULL && rlen > 0) {
304  return SPI_DEV_STATUS_EINVAL;
305  }
306 
307  totlen = MAX(rlen + ignore_len, wlen);
308 
309  if(totlen == 0) {
310  /* Nothing to do */
311  return SPI_DEV_STATUS_OK;
312  }
313 
314  LOG_DBG_("%c%c%c: %u ", rlen > 0 ? 'R' : '-', wlen > 0 ? 'W' : '-',
315  ignore_len > 0 ? 'S' : '-', totlen);
316 
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);
322  spix_wait_eotx(dev);
323  spix_wait_eorx(dev);
324  c = spix_read_buf(dev);
325  if(i < rlen) {
326  inbuf[i] = c;
327  }
328  LOG_DBG_("%02x", c);
329  }
330  LOG_DBG_("\n");
331 
332  return SPI_DEV_STATUS_OK;
333 }
334 /*---------------------------------------------------------------------------*/
bool spi_arch_has_lock(const spi_device_t *dev)
Checks if a device has locked an SPI controller.
Definition: spi-arch.c:151
#define SSI_CR0_SPH
Serial clock phase (H)
Definition: ssi.h:154
#define IOC_SSIRXD_SSI0
SSI0 RX.
Definition: ioc.h:129
Header file for the cc2538 System Control driver.
#define SSI_CC
Clock configuration.
Definition: ssi.h:77
#define GPIO_SET_PIN(PORT_BASE, PIN_MASK)
Set pins with PIN_MASK of port with PORT_BASE high.
Definition: gpio.h:106
#define SSI_CR0_SCR_M
Serial clock rate mask.
Definition: ssi.h:83
#define SSI_CPSR
Clock divider.
Definition: ssi.h:71
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.
Definition: ssi.h:166
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.
Definition: spi-arch.c:286
Header file with register manipulation macro definitions.
#define SSI1_BASE
Base address for SSI1.
Definition: ssi.h:59
#define mutex_unlock(m)
Unlock a previously acquired mutex.
Definition: mutex.h:103
#define SSI_CR1
Control register 1.
Definition: ssi.h:68
#define IOC_OVERRIDE_DIS
Override Disabled.
Definition: ioc.h:226
#define SSI_CR0_SPO
Serial clock phase (O)
Definition: ssi.h:155
#define SSI0_BASE
Base address for SSI0.
Definition: ssi.h:58
Header file for the SPI HAL.
#define GPIO_PIN_MASK(PIN)
Converts a pin number to a pin mask.
Definition: gpio.h:320
spi_status_t
SPI return codes.
Definition: spi.h:80
#define SSI_SR
Meta information about FIFO.
Definition: ssi.h:70
spi_status_t spi_arch_lock_and_open(const spi_device_t *dev)
Locks and opens an SPI controller to the configuration specified.
Definition: spi-arch.c:171
#define GPIO_SOFTWARE_CONTROL(PORT_BASE, PIN_MASK)
Configure the pin to be software controlled with PIN_MASK of port with PORT_BASE. ...
Definition: gpio.h:258
#define SSI_SR_BSY
Busy bit.
Definition: ssi.h:163
#define mutex_try_lock(m)
Try to lock a mutex.
Definition: mutex.h:91
void ioc_set_over(uint8_t port, uint8_t pin, uint8_t over)
Set Port:Pin override function.
Definition: ioc.c:54
#define SSI_CR0
Control register 0.
Definition: ssi.h:67
#define GPIO_SET_OUTPUT(PORT_BASE, PIN_MASK)
Set pins with PIN_MASK of port with PORT_BASE to output.
Definition: gpio.h:85
#define SSI_CR0_SCR_S
Serial clock rate shift.
Definition: ssi.h:84
#define SSI_DR
Access the TX and RX FIFO.
Definition: ssi.h:69
#define SYS_CTRL_RCGCSSI
SSI[1:0] clocks - active mode.
Definition: sys-ctrl.h:71
#define SSI_SR_RNE
Receive FIFO not empty.
Definition: ssi.h:165
#define SSI_CR1_SSE
Synchronous serial port enable.
Definition: ssi.h:161
#define GPIO_PERIPHERAL_CONTROL(PORT_BASE, PIN_MASK)
Configure the pin to be under peripheral control with PIN_MASK of port with PORT_BASE.
Definition: gpio.h:250
#define IOC_SSIRXD_SSI1
SSI1 RX.
Definition: ioc.h:133
bool spi_arch_is_bus_locked(const spi_device_t *dev)
Checks if an SPI controller is locked by any device.
Definition: spi-arch.c:161
void ioc_set_sel(uint8_t port, uint8_t pin, uint8_t sel)
Function select for Port:Pin.
Definition: ioc.c:66
SPI Device Configuration.
Definition: spi.h:100
Default definitions of C compiler quirk work-arounds.
#define GPIO_PORT_TO_BASE(PORT)
Converts a port number to the port base address.
Definition: gpio.h:328
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.
Definition: spi-arch.c:268