Contiki-NG
spi-arch.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2018, Texas Instruments Incorporated - http://www.ti.com/
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 HOLDERS 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/**
31 * \addtogroup cc13xx-cc26xx-cpu
32 * @{
33 *
34 * \defgroup cc13xx-cc26xx-spi CC13xx/CC26xx SPI HAL
35 *
36 * @{
37 * \file
38 * Implementation of the SPI HAL driver for CC13xx/CC26xx.
39 * \author
40 * Edvard Pettersen <e.pettersen@ti.com>
41 */
42/*---------------------------------------------------------------------------*/
43#include "contiki.h"
44#include "sys/cc.h"
45#include "dev/spi.h"
46/*---------------------------------------------------------------------------*/
47#include <ti/drivers/SPI.h>
48#include <ti/drivers/dpl/HwiP.h>
49#include <ti/drivers/pin/PINCC26XX.h>
50/*---------------------------------------------------------------------------*/
51#include <stdbool.h>
52#include <stddef.h>
53#include <stdint.h>
54/*---------------------------------------------------------------------------*/
55typedef struct {
56 SPI_Handle handle;
57 const spi_device_t *owner;
58} spi_arch_t;
59/*---------------------------------------------------------------------------*/
60#if (SPI_CONTROLLER_COUNT > 0)
61static spi_arch_t spi_arches[SPI_CONTROLLER_COUNT];
62#else
63static spi_arch_t *spi_arches = NULL;
64#endif
65/*---------------------------------------------------------------------------*/
66static inline spi_arch_t *
67get_handle(uint8_t spi_controller)
68{
69 if(spi_controller < SPI_CONTROLLER_COUNT) {
70 return &spi_arches[spi_controller];
71 } else {
72 return NULL;
73 }
74}
75/*---------------------------------------------------------------------------*/
76static SPI_FrameFormat
77convert_frame_format(uint8_t pol, uint8_t pha)
78{
79 pol = (pol) ? 1 : 0;
80 pha = (pha) ? 1 : 0;
81 /*
82 * Convert pol/pha to a single byte on the following format:
83 * xxxA xxxB
84 * where A is the polarity bit and B is the phase bit.
85 * Note that any other value deviating from this format will
86 * default to the SPI_POL1_PHA1 format.
87 */
88 uint8_t pol_pha = (pol << 4) | (pha << 0);
89 switch(pol_pha) {
90 case 0x00: return SPI_POL0_PHA0;
91 case 0x01: return SPI_POL0_PHA1;
92 case 0x10: return SPI_POL1_PHA0;
93 default: /* fallthrough */
94 case 0x11: return SPI_POL1_PHA1;
95 }
96}
97/*---------------------------------------------------------------------------*/
98bool
100{
101 /*
102 * The SPI device is the owner if the SPI controller returns a valid
103 * SPI arch object and the SPI device is owner of that object.
104 */
105 spi_arch_t *spi_arch = get_handle(dev->spi_controller);
106 return (spi_arch != NULL) && (spi_arch->owner == dev);
107}
108/*---------------------------------------------------------------------------*/
109bool
111{
112 /*
113 * The SPI controller is locked by any device if the SPI controller returns
114 * a valid SPI arch object and the SPI handle of that object is valid.
115 */
116 spi_arch_t *spi_arch = get_handle(dev->spi_controller);
117 return (spi_arch != NULL) && (spi_arch->handle != NULL);
118}
119/*---------------------------------------------------------------------------*/
122{
123 uint_least8_t spi_index;
124 spi_arch_t *spi_arch;
125 SPI_Params spi_params;
126
127 const uintptr_t hwi_key = HwiP_disable();
128
129 spi_index = dev->spi_controller;
130 spi_arch = get_handle(spi_index);
131
132 /* Ensure the provided SPI index is valid. */
133 if(spi_arch == NULL) {
134 HwiP_restore(hwi_key);
135 return SPI_DEV_STATUS_EINVAL;
136 }
137
138 /* Ensure the corresponding SPI interface is not already locked. */
139 if(spi_arch_is_bus_locked(dev)) {
140 HwiP_restore(hwi_key);
141 return SPI_DEV_STATUS_BUS_LOCKED;
142 }
143
144 SPI_Params_init(&spi_params);
145
146 spi_params.transferMode = SPI_MODE_BLOCKING;
147 spi_params.mode = SPI_MASTER;
148 spi_params.bitRate = dev->spi_bit_rate;
149 spi_params.dataSize = 8;
150 spi_params.frameFormat = convert_frame_format(dev->spi_pol, dev->spi_pha);
151
152 /*
153 * Try to open the SPI driver. Accessing the SPI driver also ensures
154 * atomic access to the SPI interface.
155 */
156 spi_arch->handle = SPI_open(spi_index, &spi_params);
157
158 if(spi_arch->handle == NULL) {
159 HwiP_restore(hwi_key);
160 return SPI_DEV_STATUS_BUS_LOCKED;
161 }
162
163 spi_arch->owner = dev;
164
165 HwiP_restore(hwi_key);
166 return SPI_DEV_STATUS_OK;
167}
168/*---------------------------------------------------------------------------*/
171{
172 spi_arch_t *spi_arch;
173
174 const uintptr_t hwi_key = HwiP_disable();
175
176 /* Ensure the provided SPI index is valid. */
177 spi_arch = get_handle(dev->spi_controller);
178 if(spi_arch == NULL) {
179 HwiP_restore(hwi_key);
180 return SPI_DEV_STATUS_EINVAL;
181 }
182
183 /* Ensure the corresponding SPI device owns the SPI controller. */
184 if(!spi_arch_has_lock(dev)) {
185 HwiP_restore(hwi_key);
186 return SPI_DEV_STATUS_BUS_NOT_OWNED;
187 }
188
189 SPI_close(spi_arch->handle);
190
191 spi_arch->handle = NULL;
192 spi_arch->owner = NULL;
193
194 HwiP_restore(hwi_key);
195 return SPI_DEV_STATUS_OK;
196}
197/*---------------------------------------------------------------------------*/
200 const uint8_t *write_buf, int wlen,
201 uint8_t *inbuf, int rlen, int ignore_len)
202{
203 spi_arch_t *spi_arch;
204 size_t totlen;
205 SPI_Transaction spi_transaction;
206 bool transfer_ok;
207
208 /* Ensure the provided SPI index is valid. */
209 spi_arch = get_handle(dev->spi_controller);
210 if(spi_arch == NULL) {
211 return SPI_DEV_STATUS_EINVAL;
212 }
213
214 if(!spi_arch_has_lock(dev)) {
215 return SPI_DEV_STATUS_BUS_NOT_OWNED;
216 }
217
218 totlen = MAX((size_t)(rlen + ignore_len), (size_t)wlen);
219
220 if(totlen == 0) {
221 /* Nothing to do */
222 return SPI_DEV_STATUS_OK;
223 }
224
225 spi_transaction.count = totlen;
226 spi_transaction.txBuf = (void *)write_buf;
227 spi_transaction.rxBuf = (void *)inbuf;
228
229 transfer_ok = SPI_transfer(spi_arch->handle, &spi_transaction);
230
231 if(!transfer_ok) {
232 return SPI_DEV_STATUS_TRANSFER_ERR;
233 }
234
235 return SPI_DEV_STATUS_OK;
236}
237/*---------------------------------------------------------------------------*/
238/**
239 * @}
240 * @}
241 */
Default definitions of C compiler quirk work-arounds.
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