Contiki-NG
spi-arch.c
1 /*
2  * Copyright (c) 2017, University of Bristol - http://www.bristol.ac.uk/
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the copyright holder nor the names of its
14  * contributors may be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS
18  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28  * OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 #include "contiki.h"
31 #include "ti-lib.h"
32 #include "dev/spi.h"
33 #include "sys/mutex.h"
34 
35 #include <stdint.h>
36 #include <stdbool.h>
37 
38 typedef struct spi_locks_s {
39  mutex_t lock;
40  spi_device_t *owner;
41 } spi_locks_t;
42 
43 /* One lock per SPI controller */
44 spi_locks_t board_spi_locks_spi[SPI_CONTROLLER_COUNT] = { { MUTEX_STATUS_UNLOCKED, NULL } };
45 
46 /*---------------------------------------------------------------------------*/
47 /* Arch-specific properties of each SPI controller */
48 typedef struct board_spi_controller_s {
49  uint32_t ssi_base;
50  uint32_t power_domain;
51  uint32_t prcm_periph;
52  uint32_t ssi_clkgr_clk_en;
53 } board_spi_controller_t;
54 
55 static const board_spi_controller_t spi_controller[SPI_CONTROLLER_COUNT] = {
56  {
57  .ssi_base = SSI0_BASE,
58  .power_domain = PRCM_DOMAIN_SERIAL,
59  .prcm_periph = PRCM_PERIPH_SSI0,
60  .ssi_clkgr_clk_en = PRCM_SSICLKGR_CLK_EN_SSI0
61  },
62  {
63  .ssi_base = SSI1_BASE,
64  .power_domain = PRCM_DOMAIN_PERIPH,
65  .prcm_periph = PRCM_PERIPH_SSI1,
66  .ssi_clkgr_clk_en = PRCM_SSICLKGR_CLK_EN_SSI1
67  }
68 };
69 /*---------------------------------------------------------------------------*/
70 bool
72 {
73  if(board_spi_locks_spi[dev->spi_controller].owner == dev) {
74  return true;
75  }
76 
77  return false;
78 }
79 /*---------------------------------------------------------------------------*/
80 bool
82 {
83  if(board_spi_locks_spi[dev->spi_controller].lock == MUTEX_STATUS_LOCKED) {
84  return true;
85  }
86 
87  return false;
88 }
89 /*---------------------------------------------------------------------------*/
90 static uint32_t
91 get_mode(spi_device_t *dev)
92 {
93  /* Select the correct SPI mode */
94  if(dev->spi_pha == 0 && dev->spi_pol == 0) {
95  return SSI_FRF_MOTO_MODE_0;
96  } else if(dev->spi_pha != 0 && dev->spi_pol == 0) {
97  return SSI_FRF_MOTO_MODE_1;
98  } else if(dev->spi_pha == 0 && dev->spi_pol != 0) {
99  return SSI_FRF_MOTO_MODE_2;
100  } else {
101  return SSI_FRF_MOTO_MODE_3;
102  }
103 }
104 /*---------------------------------------------------------------------------*/
107 {
108  uint32_t c;
109 
110  /* Lock the SPI bus */
111  if(mutex_try_lock(&board_spi_locks_spi[dev->spi_controller].lock) == false) {
112  return SPI_DEV_STATUS_BUS_LOCKED;
113  }
114 
115  board_spi_locks_spi[dev->spi_controller].owner = dev;
116 
117  /* CS pin configuration */
118  ti_lib_ioc_pin_type_gpio_output(dev->pin_spi_cs);
119 
120  /* First, make sure the SERIAL PD is on */
121  ti_lib_prcm_power_domain_on(spi_controller[dev->spi_controller].power_domain);
122  while((ti_lib_prcm_power_domain_status(spi_controller[dev->spi_controller].power_domain)
123  != PRCM_DOMAIN_POWER_ON)) ;
124 
125  /* Enable clock in active mode */
126  ti_lib_rom_prcm_peripheral_run_enable(spi_controller[dev->spi_controller].prcm_periph);
127  ti_lib_prcm_load_set();
128  while(!ti_lib_prcm_load_get()) ;
129 
130  /* SPI configuration */
131  ti_lib_ssi_int_disable(spi_controller[dev->spi_controller].ssi_base, SSI_RXOR | SSI_RXFF | SSI_RXTO | SSI_TXFF);
132  ti_lib_ssi_int_clear(spi_controller[dev->spi_controller].ssi_base, SSI_RXOR | SSI_RXTO);
133  ti_lib_rom_ssi_config_set_exp_clk(spi_controller[dev->spi_controller].ssi_base, ti_lib_sys_ctrl_clock_get(),
134  get_mode(dev), SSI_MODE_MASTER, dev->spi_bit_rate, 8);
135  ti_lib_rom_ioc_pin_type_ssi_master(spi_controller[dev->spi_controller].ssi_base, dev->pin_spi_miso,
136  dev->pin_spi_mosi, IOID_UNUSED, dev->pin_spi_sck);
137 
138  ti_lib_ssi_enable(spi_controller[dev->spi_controller].ssi_base);
139 
140  /* Get rid of residual data from SSI port */
141  while(ti_lib_ssi_data_get_non_blocking(spi_controller[dev->spi_controller].ssi_base, &c)) ;
142 
143  return SPI_DEV_STATUS_OK;
144 }
145 /*---------------------------------------------------------------------------*/
148 {
149  if(!spi_arch_has_lock(dev)) {
150  return SPI_DEV_STATUS_BUS_NOT_OWNED;
151  }
152 
153  /* Power down SSI */
154  ti_lib_rom_prcm_peripheral_run_disable(spi_controller[dev->spi_controller].prcm_periph);
155  ti_lib_prcm_load_set();
156  while(!ti_lib_prcm_load_get()) ;
157 
158  /* Restore pins to a low-consumption state */
159  ti_lib_ioc_pin_type_gpio_input(dev->pin_spi_miso);
160  ti_lib_ioc_io_port_pull_set(dev->pin_spi_miso, IOC_IOPULL_DOWN);
161 
162  ti_lib_ioc_pin_type_gpio_input(dev->pin_spi_mosi);
163  ti_lib_ioc_io_port_pull_set(dev->pin_spi_mosi, IOC_IOPULL_DOWN);
164 
165  ti_lib_ioc_pin_type_gpio_input(dev->pin_spi_sck);
166  ti_lib_ioc_io_port_pull_set(dev->pin_spi_sck, IOC_IOPULL_DOWN);
167 
168  /* Unlock the SPI bus */
169  board_spi_locks_spi[dev->spi_controller].owner = NULL;
170  mutex_unlock(&board_spi_locks_spi[dev->spi_controller].lock);
171 
172  return SPI_DEV_STATUS_OK;
173 }
174 /*---------------------------------------------------------------------------*/
177  const uint8_t *write_buf, int wlen,
178  uint8_t *inbuf, int rlen, int ignore_len)
179 {
180  int i;
181  int totlen;
182  uint32_t c;
183 
184  if(!spi_arch_has_lock(dev)) {
185  return SPI_DEV_STATUS_BUS_NOT_OWNED;
186  }
187 
188  if(ti_lib_prcm_power_domain_status(spi_controller[dev->spi_controller].power_domain)
189  != PRCM_DOMAIN_POWER_ON) {
190  return SPI_DEV_STATUS_CLOSED;
191  }
192 
193  /* Then check the 'run mode' clock gate */
194  if(!(HWREG(PRCM_BASE + PRCM_O_SSICLKGR) & spi_controller[dev->spi_controller].ssi_clkgr_clk_en)) {
195  return SPI_DEV_STATUS_CLOSED;
196  }
197 
198  totlen = MAX(rlen + ignore_len, wlen);
199 
200  if(totlen == 0) {
201  /* Nothing to do */
202  return SPI_DEV_STATUS_OK;
203  }
204 
205  for(i = 0; i < totlen; i++) {
206  c = i < wlen ? write_buf[i] : 0;
207  ti_lib_ssi_data_put(spi_controller[dev->spi_controller].ssi_base, (uint8_t)c);
208  ti_lib_rom_ssi_data_get(spi_controller[dev->spi_controller].ssi_base, &c);
209  if(i < rlen) {
210  inbuf[i] = (uint8_t)c;
211  }
212  }
213 
214  while(ti_lib_rom_ssi_data_get_non_blocking(spi_controller[dev->spi_controller].ssi_base, &c)) ;
215 
216  return SPI_DEV_STATUS_OK;
217 }
218 /*---------------------------------------------------------------------------*/
221 {
222 
223  if(!spi_arch_has_lock(dev)) {
224  return SPI_DEV_STATUS_BUS_NOT_OWNED;
225  }
226 
227  ti_lib_gpio_clear_dio(dev->pin_spi_cs);
228 
229  return SPI_DEV_STATUS_OK;
230 }
233 {
234  ti_lib_gpio_set_dio(dev->pin_spi_cs);
235 
236  return SPI_DEV_STATUS_OK;
237 }
spi_status_t spi_arch_lock_and_open(spi_device_t *dev)
Locks and opens an SPI controller to the configuration specified.
Definition: spi-arch.c:171
Header file with macros which rename TI CC26xxware functions.
#define SSI1_BASE
Base address for SSI1.
Definition: ssi.h:59
#define mutex_unlock(m)
Unlock a previously acquired mutex.
Definition: mutex.h:103
bool spi_arch_has_lock(spi_device_t *dev)
Checks if a device has locked an SPI controller.
Definition: spi-arch.c:151
bool spi_arch_is_bus_locked(spi_device_t *dev)
Checks if an SPI controller is locked by any device.
Definition: spi-arch.c:161
#define SSI0_BASE
Base address for SSI0.
Definition: ssi.h:58
Header file for the SPI HAL.
spi_status_t
SPI return codes.
Definition: spi.h:80
spi_status_t spi_arch_deselect(spi_device_t *dev)
Deselects an SPI device.
Definition: spi-arch.c:298
#define mutex_try_lock(m)
Try to lock a mutex.
Definition: mutex.h:91
spi_status_t spi_arch_transfer(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:307
SPI Device Configuration.
Definition: spi.h:97
spi_status_t spi_arch_select(spi_device_t *dev)
Selects an SPI device.
Definition: spi-arch.c:285
spi_status_t spi_arch_close_and_unlock(spi_device_t *dev)
Closes and unlocks an SPI controller.
Definition: spi-arch.c:268