]> git.donarmstrong.com Git - qmk_firmware.git/blob - tool/mbed/mbed-sdk/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC11XX_11CXX/spi_api.c
Squashed 'tmk_core/' changes from 7967731..b9e0ea0
[qmk_firmware.git] / tool / mbed / mbed-sdk / libraries / mbed / targets / hal / TARGET_NXP / TARGET_LPC11XX_11CXX / spi_api.c
1 /* mbed Microcontroller Library
2  * Copyright (c) 2006-2013 ARM Limited
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include "mbed_assert.h"
17 #include <math.h>
18 #include "spi_api.h"
19 #include "cmsis.h"
20 #include "pinmap.h"
21 #include "mbed_error.h"
22
23 static const PinMap PinMap_SPI_SCLK[] = {
24     {P0_6 , SPI_0, 0x02},
25     // {P0_10, SPI_0, 0x02}, -- should be mapped to SWCLK only
26     {P2_11, SPI_0, 0x01},
27     {P2_1 , SPI_1, 0x02},
28     {NC   , NC   , 0}
29 };
30
31 static const PinMap PinMap_SPI_MOSI[] = {
32     {P0_9 , SPI_0, 0x01},
33     {P2_3 , SPI_1, 0x02},
34     {NC   , NC   , 0}
35 };
36
37 static const PinMap PinMap_SPI_MISO[] = {
38     {P0_8 , SPI_0, 0x01},
39     {P2_2 , SPI_1, 0x02},
40     {NC   , NC   , 0}
41 };
42
43 static const PinMap PinMap_SPI_SSEL[] = {
44     {P0_2 , SPI_0, 0x01},
45     {P2_0 , SPI_1, 0x02},
46     {NC   , NC   , 0}
47 };
48
49 static inline int ssp_disable(spi_t *obj);
50 static inline int ssp_enable(spi_t *obj);
51
52 void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel) {
53     // determine the SPI to use
54     SPIName spi_mosi = (SPIName)pinmap_peripheral(mosi, PinMap_SPI_MOSI);
55     SPIName spi_miso = (SPIName)pinmap_peripheral(miso, PinMap_SPI_MISO);
56     SPIName spi_sclk = (SPIName)pinmap_peripheral(sclk, PinMap_SPI_SCLK);
57     SPIName spi_ssel = (SPIName)pinmap_peripheral(ssel, PinMap_SPI_SSEL);
58     SPIName spi_data = (SPIName)pinmap_merge(spi_mosi, spi_miso);
59     SPIName spi_cntl = (SPIName)pinmap_merge(spi_sclk, spi_ssel);
60     
61     obj->spi = (LPC_SSP_TypeDef*)pinmap_merge(spi_data, spi_cntl);
62     MBED_ASSERT((int)obj->spi != NC);
63     
64     // enable power and clocking
65     switch ((int)obj->spi) {
66         case SPI_0:
67             LPC_SYSCON->SYSAHBCLKCTRL |= 1 << 11;
68             LPC_SYSCON->SSP0CLKDIV = 0x01;
69             LPC_SYSCON->PRESETCTRL |= 1 << 0;
70             if (sclk == P0_6) {
71                 LPC_IOCON->SCK_LOC = 0x02;
72             }
73             else {
74                 LPC_IOCON->SCK_LOC = 0x01;
75             }
76             break;
77         case SPI_1:
78             LPC_SYSCON->SYSAHBCLKCTRL |= 1 << 18;
79             LPC_SYSCON->SSP1CLKDIV = 0x01;
80             LPC_SYSCON->PRESETCTRL |= 1 << 2;
81             LPC_IOCON->SCK1_LOC = 0x00;
82             LPC_IOCON->MISO1_LOC = 0x00;
83             LPC_IOCON->MOSI1_LOC = 0x00;
84             if (ssel != NC) {
85                 LPC_IOCON->SSEL1_LOC = 0x00;
86             }
87             break;
88     }
89     
90     // set default format and frequency
91     if (ssel == NC) {
92         spi_format(obj, 8, 0, 0);  // 8 bits, mode 0, master
93     } else {
94         spi_format(obj, 8, 0, 1);  // 8 bits, mode 0, slave
95     }
96     spi_frequency(obj, 1000000);
97     
98     // enable the ssp channel
99     ssp_enable(obj);
100     
101     // pin out the spi pins
102     pinmap_pinout(mosi, PinMap_SPI_MOSI);
103     pinmap_pinout(miso, PinMap_SPI_MISO);
104     pinmap_pinout(sclk, PinMap_SPI_SCLK);
105     if (ssel != NC) {
106         pinmap_pinout(ssel, PinMap_SPI_SSEL);
107     }
108 }
109
110 void spi_free(spi_t *obj) {}
111
112 void spi_format(spi_t *obj, int bits, int mode, int slave) {
113     MBED_ASSERT((bits >= 4 && bits <= 16) || (mode >= 0 && mode <= 3));
114     ssp_disable(obj);
115     
116     int polarity = (mode & 0x2) ? 1 : 0;
117     int phase = (mode & 0x1) ? 1 : 0;
118     
119     // set it up
120     int DSS = bits - 1;            // DSS (data select size)
121     int SPO = (polarity) ? 1 : 0;  // SPO - clock out polarity
122     int SPH = (phase) ? 1 : 0;     // SPH - clock out phase
123     
124     int FRF = 0;                   // FRF (frame format) = SPI
125     uint32_t tmp = obj->spi->CR0;
126     tmp &= ~(0xFFFF);
127     tmp |= DSS << 0
128         | FRF << 4
129         | SPO << 6
130         | SPH << 7;
131     obj->spi->CR0 = tmp;
132     
133     tmp = obj->spi->CR1;
134     tmp &= ~(0xD);
135     tmp |= 0 << 0                   // LBM - loop back mode - off
136         | ((slave) ? 1 : 0) << 2   // MS - master slave mode, 1 = slave
137         | 0 << 3;                  // SOD - slave output disable - na
138     obj->spi->CR1 = tmp;
139     
140     ssp_enable(obj);
141 }
142
143 void spi_frequency(spi_t *obj, int hz) {
144     ssp_disable(obj);
145     
146     uint32_t PCLK = SystemCoreClock;
147     
148     int prescaler;
149     
150     for (prescaler = 2; prescaler <= 254; prescaler += 2) {
151         int prescale_hz = PCLK / prescaler;
152         
153         // calculate the divider
154         int divider = floor(((float)prescale_hz / (float)hz) + 0.5f);
155         
156         // check we can support the divider
157         if (divider < 256) {
158             // prescaler
159             obj->spi->CPSR = prescaler;
160             
161             // divider
162             obj->spi->CR0 &= ~(0xFFFF << 8);
163             obj->spi->CR0 |= (divider - 1) << 8;
164             ssp_enable(obj);
165             return;
166         }
167     }
168     error("Couldn't setup requested SPI frequency");
169 }
170
171 static inline int ssp_disable(spi_t *obj) {
172     return obj->spi->CR1 &= ~(1 << 1);
173 }
174
175 static inline int ssp_enable(spi_t *obj) {
176     return obj->spi->CR1 |= (1 << 1);
177 }
178
179 static inline int ssp_readable(spi_t *obj) {
180     return obj->spi->SR & (1 << 2);
181 }
182
183 static inline int ssp_writeable(spi_t *obj) {
184     return obj->spi->SR & (1 << 1);
185 }
186
187 static inline void ssp_write(spi_t *obj, int value) {
188     while (!ssp_writeable(obj));
189     obj->spi->DR = value;
190 }
191
192 static inline int ssp_read(spi_t *obj) {
193     while (!ssp_readable(obj));
194     return obj->spi->DR;
195 }
196
197 static inline int ssp_busy(spi_t *obj) {
198     return (obj->spi->SR & (1 << 4)) ? (1) : (0);
199 }
200
201 int spi_master_write(spi_t *obj, int value) {
202     ssp_write(obj, value);
203     return ssp_read(obj);
204 }
205
206 int spi_slave_receive(spi_t *obj) {
207     return ssp_readable(obj) ? (1) : (0);
208 }
209
210 int spi_slave_read(spi_t *obj) {
211     return obj->spi->DR & 0xFFFF;
212 }
213
214 void spi_slave_write(spi_t *obj, int value) {
215     while (ssp_writeable(obj) == 0) ;
216     obj->spi->DR = value;
217 }
218
219 int spi_busy(spi_t *obj) {
220     return ssp_busy(obj);
221 }