]> git.donarmstrong.com Git - qmk_firmware.git/blob - tool/mbed/mbed-sdk/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC408X/TARGET_LPC4088/spi_api.c
Squashed 'tmk_core/' changes from 7967731..b9e0ea0
[qmk_firmware.git] / tool / mbed / mbed-sdk / libraries / mbed / targets / hal / TARGET_NXP / TARGET_LPC408X / TARGET_LPC4088 / 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 <math.h>
17
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_7 , SPI_1, 2},
25     {P0_15, SPI_0, 2},
26     {P1_0,  SPI_2, 4},
27     {P1_19, SPI_1, 5},
28     {P1_20, SPI_0, 5},
29     {P1_31, SPI_1, 2},
30     {P2_22, SPI_0, 2},
31     {P4_20, SPI_1, 3},
32     {P5_2,  SPI_2, 2},
33     {NC   , NC   , 0}
34 };
35
36 static const PinMap PinMap_SPI_MOSI[] = {
37     {P0_9 , SPI_1, 2},
38     {P0_13, SPI_1, 2},
39     {P0_18, SPI_0, 2},
40     {P1_1,  SPI_2, 4},
41     {P1_22, SPI_1, 5},
42     {P1_24, SPI_0, 5},
43     {P2_27, SPI_0, 2},
44     {P4_23, SPI_1, 3},
45     {P5_0,  SPI_2, 2},
46     {NC   , NC   , 0}
47 };
48
49 static const PinMap PinMap_SPI_MISO[] = {
50     {P0_8 , SPI_1, 2},
51     {P0_12, SPI_1, 2},
52     {P0_17, SPI_0, 2},
53     {P1_4,  SPI_2, 4},
54     {P1_18, SPI_1, 5},
55     {P1_23, SPI_0, 5},
56     {P2_26, SPI_0, 2},
57     {P4_22, SPI_1, 3},
58     {P5_1,  SPI_2, 2},
59     {NC   , NC   , 0}
60 };
61
62 static const PinMap PinMap_SPI_SSEL[] = {
63     {P0_6 , SPI_1, 2},
64     {P0_14, SPI_1, 2},
65     {P0_16, SPI_0, 2},
66     {P1_8,  SPI_2, 4},
67     {P1_21, SPI_0, 3},
68     {P1_26, SPI_1, 5},
69     {P1_28, SPI_0, 5},
70     {P2_23, SPI_0, 2},
71     {P4_21, SPI_1, 3},
72     {NC   , NC   , 0}
73 };
74
75 static inline int ssp_disable(spi_t *obj);
76 static inline int ssp_enable(spi_t *obj);
77
78 void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel) {
79     // determine the SPI to use
80     SPIName spi_mosi = (SPIName)pinmap_peripheral(mosi, PinMap_SPI_MOSI);
81     SPIName spi_miso = (SPIName)pinmap_peripheral(miso, PinMap_SPI_MISO);
82     SPIName spi_sclk = (SPIName)pinmap_peripheral(sclk, PinMap_SPI_SCLK);
83     SPIName spi_ssel = (SPIName)pinmap_peripheral(ssel, PinMap_SPI_SSEL);
84     SPIName spi_data = (SPIName)pinmap_merge(spi_mosi, spi_miso);
85     SPIName spi_cntl = (SPIName)pinmap_merge(spi_sclk, spi_ssel);
86     obj->spi = (LPC_SSP_TypeDef*)pinmap_merge(spi_data, spi_cntl);
87     MBED_ASSERT((int)obj->spi != NC);
88     
89     // enable power and clocking
90     switch ((int)obj->spi) {
91         case SPI_0: LPC_SC->PCONP |= 1 << 21; break;
92         case SPI_1: LPC_SC->PCONP |= 1 << 10; break;
93         case SPI_2: LPC_SC->PCONP |= 1 << 20; break;
94     }
95     
96     // set default format and frequency
97     if (ssel == NC) {
98         spi_format(obj, 8, 0, 0);  // 8 bits, mode 0, master
99     } else {
100         spi_format(obj, 8, 0, 1);  // 8 bits, mode 0, slave
101     }
102     spi_frequency(obj, 1000000);
103     
104     // enable the ssp channel
105     ssp_enable(obj);
106     
107     // pin out the spi pins
108     pinmap_pinout(mosi, PinMap_SPI_MOSI);
109     pinmap_pinout(miso, PinMap_SPI_MISO);
110     pinmap_pinout(sclk, PinMap_SPI_SCLK);
111     if (ssel != NC) {
112         pinmap_pinout(ssel, PinMap_SPI_SSEL);
113     }
114 }
115
116 void spi_free(spi_t *obj) {}
117
118 void spi_format(spi_t *obj, int bits, int mode, int slave) {
119     MBED_ASSERT(((bits >= 4) && (bits <= 16)) && ((mode >= 0) && (mode <= 3)));
120     ssp_disable(obj);
121     
122     int polarity = (mode & 0x2) ? 1 : 0;
123     int phase = (mode & 0x1) ? 1 : 0;
124     
125     // set it up
126     int DSS = bits - 1;            // DSS (data select size)
127     int SPO = (polarity) ? 1 : 0;  // SPO - clock out polarity
128     int SPH = (phase) ? 1 : 0;     // SPH - clock out phase
129     
130     int FRF = 0;                   // FRF (frame format) = SPI
131     uint32_t tmp = obj->spi->CR0;
132     tmp &= ~(0xFFFF);
133     tmp |= DSS << 0
134         | FRF << 4
135         | SPO << 6
136         | SPH << 7;
137     obj->spi->CR0 = tmp;
138     
139     tmp = obj->spi->CR1;
140     tmp &= ~(0xD);
141     tmp |= 0 << 0                   // LBM - loop back mode - off
142         | ((slave) ? 1 : 0) << 2   // MS - master slave mode, 1 = slave
143         | 0 << 3;                  // SOD - slave output disable - na
144     obj->spi->CR1 = tmp;
145     ssp_enable(obj);
146 }
147
148 void spi_frequency(spi_t *obj, int hz) {
149     ssp_disable(obj);
150     
151     uint32_t PCLK = PeripheralClock;
152     
153     int prescaler;
154     
155     for (prescaler = 2; prescaler <= 254; prescaler += 2) {
156         int prescale_hz = PCLK / prescaler;
157         
158         // calculate the divider
159         int divider = floor(((float)prescale_hz / (float)hz) + 0.5f);
160         
161         // check we can support the divider
162         if (divider < 256) {
163             // prescaler
164             obj->spi->CPSR = prescaler;
165             
166             // divider
167             obj->spi->CR0 &= ~(0xFFFF << 8);
168             obj->spi->CR0 |= (divider - 1) << 8;
169             ssp_enable(obj);
170             return;
171         }
172     }
173     error("Couldn't setup requested SPI frequency");
174 }
175
176 static inline int ssp_disable(spi_t *obj) {
177     return obj->spi->CR1 &= ~(1 << 1);
178 }
179
180 static inline int ssp_enable(spi_t *obj) {
181     return obj->spi->CR1 |= (1 << 1);
182 }
183
184 static inline int ssp_readable(spi_t *obj) {
185     return obj->spi->SR & (1 << 2);
186 }
187
188 static inline int ssp_writeable(spi_t *obj) {
189     return obj->spi->SR & (1 << 1);
190 }
191
192 static inline void ssp_write(spi_t *obj, int value) {
193     while (!ssp_writeable(obj));
194     obj->spi->DR = value;
195 }
196
197 static inline int ssp_read(spi_t *obj) {
198     while (!ssp_readable(obj));
199     return obj->spi->DR;
200 }
201
202 static inline int ssp_busy(spi_t *obj) {
203     return (obj->spi->SR & (1 << 4)) ? (1) : (0);
204 }
205
206 int spi_master_write(spi_t *obj, int value) {
207     ssp_write(obj, value);
208     return ssp_read(obj);
209 }
210
211 int spi_slave_receive(spi_t *obj) {
212     return (ssp_readable(obj) && !ssp_busy(obj)) ? (1) : (0);
213 }
214
215 int spi_slave_read(spi_t *obj) {
216     return obj->spi->DR;
217 }
218
219 void spi_slave_write(spi_t *obj, int value) {
220     while (ssp_writeable(obj) == 0) ;
221     obj->spi->DR = value;
222 }
223
224 int spi_busy(spi_t *obj) {
225     return ssp_busy(obj);
226 }