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  const 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(const 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_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 
134  ti_lib_ssi_config_set_exp_clk(spi_controller[dev->spi_controller].ssi_base,
135  ti_lib_sys_ctrl_clock_get(),
136  get_mode(dev), SSI_MODE_MASTER,
137  dev->spi_bit_rate, 8);
138  ti_lib_ioc_pin_type_ssi_master(spi_controller[dev->spi_controller].ssi_base,
139  dev->pin_spi_miso,
140  dev->pin_spi_mosi, IOID_UNUSED,
141  dev->pin_spi_sck);
142 
143  ti_lib_ssi_enable(spi_controller[dev->spi_controller].ssi_base);
144 
145  /* Get rid of residual data from SSI port */
146  while(ti_lib_ssi_data_get_non_blocking(spi_controller[dev->spi_controller].ssi_base, &c)) ;
147 
148  return SPI_DEV_STATUS_OK;
149 }
150 /*---------------------------------------------------------------------------*/
153 {
154  if(!spi_arch_has_lock(dev)) {
155  return SPI_DEV_STATUS_BUS_NOT_OWNED;
156  }
157 
158  /* Power down SSI */
159  ti_lib_prcm_peripheral_run_disable(spi_controller[dev->spi_controller].prcm_periph);
160  ti_lib_prcm_load_set();
161  while(!ti_lib_prcm_load_get()) ;
162 
163  /* Restore pins to a low-consumption state */
164  ti_lib_ioc_pin_type_gpio_input(dev->pin_spi_miso);
165  ti_lib_ioc_io_port_pull_set(dev->pin_spi_miso, IOC_IOPULL_DOWN);
166 
167  ti_lib_ioc_pin_type_gpio_input(dev->pin_spi_mosi);
168  ti_lib_ioc_io_port_pull_set(dev->pin_spi_mosi, IOC_IOPULL_DOWN);
169 
170  ti_lib_ioc_pin_type_gpio_input(dev->pin_spi_sck);
171  ti_lib_ioc_io_port_pull_set(dev->pin_spi_sck, IOC_IOPULL_DOWN);
172 
173  /* Unlock the SPI bus */
174  board_spi_locks_spi[dev->spi_controller].owner = NULL;
175  mutex_unlock(&board_spi_locks_spi[dev->spi_controller].lock);
176 
177  return SPI_DEV_STATUS_OK;
178 }
179 /*---------------------------------------------------------------------------*/
182  const uint8_t *write_buf, int wlen,
183  uint8_t *inbuf, int rlen, int ignore_len)
184 {
185  int i;
186  int totlen;
187  uint32_t c;
188 
189  if(!spi_arch_has_lock(dev)) {
190  return SPI_DEV_STATUS_BUS_NOT_OWNED;
191  }
192 
193  if(ti_lib_prcm_power_domain_status(spi_controller[dev->spi_controller].power_domain)
194  != PRCM_DOMAIN_POWER_ON) {
195  return SPI_DEV_STATUS_CLOSED;
196  }
197 
198  /* Then check the 'run mode' clock gate */
199  if(!(HWREG(PRCM_BASE + PRCM_O_SSICLKGR) & spi_controller[dev->spi_controller].ssi_clkgr_clk_en)) {
200  return SPI_DEV_STATUS_CLOSED;
201  }
202 
203  totlen = MAX(rlen + ignore_len, wlen);
204 
205  if(totlen == 0) {
206  /* Nothing to do */
207  return SPI_DEV_STATUS_OK;
208  }
209 
210  for(i = 0; i < totlen; i++) {
211  c = i < wlen ? write_buf[i] : 0;
212  ti_lib_ssi_data_put(spi_controller[dev->spi_controller].ssi_base, (uint8_t)c);
213  ti_lib_ssi_data_get(spi_controller[dev->spi_controller].ssi_base, &c);
214  if(i < rlen) {
215  inbuf[i] = (uint8_t)c;
216  }
217  }
218  while(ti_lib_ssi_data_get_non_blocking(spi_controller[dev->spi_controller].ssi_base, &c)) ;
219  return SPI_DEV_STATUS_OK;
220 }
221 /*---------------------------------------------------------------------------*/
bool spi_arch_has_lock(const spi_device_t *dev)
Checks if a device has locked an SPI controller.
Definition: spi-arch.c:151
Header file with macros which rename TI CC26xxware functions.
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
#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 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_lock_and_open(const spi_device_t *dev)
Locks and opens an SPI controller to the configuration specified.
Definition: spi-arch.c:171
#define mutex_try_lock(m)
Try to lock a mutex.
Definition: mutex.h:91
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
SPI Device Configuration.
Definition: spi.h:100
spi_status_t spi_arch_close_and_unlock(const spi_device_t *dev)
Closes and unlocks an SPI controller.
Definition: spi-arch.c:268