Contiki-NG
Loading...
Searching...
No Matches
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
38typedef 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 */
44spi_locks_t board_spi_locks_spi[SPI_CONTROLLER_COUNT] = { { MUTEX_STATUS_UNLOCKED, NULL } };
45
46/*---------------------------------------------------------------------------*/
47/* Arch-specific properties of each SPI controller */
48typedef 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
55static 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/*---------------------------------------------------------------------------*/
70bool
72{
73 if(board_spi_locks_spi[dev->spi_controller].owner == dev) {
74 return true;
75 }
76
77 return false;
78}
79/*---------------------------------------------------------------------------*/
80bool
82{
83 if(board_spi_locks_spi[dev->spi_controller].lock == MUTEX_STATUS_LOCKED) {
84 return true;
85 }
86
87 return false;
88}
89/*---------------------------------------------------------------------------*/
90static uint32_t
91get_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/*---------------------------------------------------------------------------*/
#define SSI1_BASE
Base address for SSI1.
Definition ssi.h:59
#define SSI0_BASE
Base address for SSI0.
Definition ssi.h:58
spi_status_t spi_arch_close_and_unlock(const spi_device_t *dev)
Closes and unlocks an SPI controller.
Definition spi-arch.c:268
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
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
bool spi_arch_has_lock(const spi_device_t *dev)
Checks if a device has locked an SPI controller.
Definition spi-arch.c:151
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
Header file for the SPI HAL.
SPI Device Configuration.
Definition spi.h:100
Header file with macros which rename TI CC26xxware functions.