]> git.friedersdorff.com Git - max/tmk_keyboard.git/blob - tool/mbed/mbed-sdk/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC11UXX/spi_api.c
Squashed 'tmk_core/' changes from 7967731..b9e0ea0
[max/tmk_keyboard.git] / tool / mbed / mbed-sdk / libraries / mbed / targets / hal / TARGET_NXP / TARGET_LPC11UXX / 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 #include "PeripheralPins.h" // For the Peripheral to Pin Definitions found in the individual Target's Platform
23
24 static inline int ssp_disable(spi_t *obj);
25 static inline int ssp_enable(spi_t *obj);
26
27 void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel) {
28     // determine the SPI to use
29     SPIName spi_mosi = (SPIName)pinmap_peripheral(mosi, PinMap_SPI_MOSI);
30     SPIName spi_miso = (SPIName)pinmap_peripheral(miso, PinMap_SPI_MISO);
31     SPIName spi_sclk = (SPIName)pinmap_peripheral(sclk, PinMap_SPI_SCLK);
32     SPIName spi_ssel = (SPIName)pinmap_peripheral(ssel, PinMap_SPI_SSEL);
33     SPIName spi_data = (SPIName)pinmap_merge(spi_mosi, spi_miso);
34     SPIName spi_cntl = (SPIName)pinmap_merge(spi_sclk, spi_ssel);
35     
36     obj->spi = (LPC_SSPx_Type*)pinmap_merge(spi_data, spi_cntl);
37     MBED_ASSERT((int)obj->spi != NC);
38     
39     // enable power and clocking
40     switch ((int)obj->spi) {
41         case SPI_0:
42             LPC_SYSCON->SYSAHBCLKCTRL |= 1 << 11;
43             LPC_SYSCON->SSP0CLKDIV = 0x01;
44             LPC_SYSCON->PRESETCTRL |= 1 << 0;
45             break;
46         case SPI_1:
47             LPC_SYSCON->SYSAHBCLKCTRL |= 1 << 18;
48             LPC_SYSCON->SSP1CLKDIV = 0x01;
49             LPC_SYSCON->PRESETCTRL |= 1 << 2;
50             break;
51     }
52     
53     // set default format and frequency
54     if (ssel == NC) {
55         spi_format(obj, 8, 0, 0);  // 8 bits, mode 0, master
56     } else {
57         spi_format(obj, 8, 0, 1);  // 8 bits, mode 0, slave
58     }
59     spi_frequency(obj, 1000000);
60     
61     // enable the ssp channel
62     ssp_enable(obj);
63     
64     // pin out the spi pins
65     pinmap_pinout(mosi, PinMap_SPI_MOSI);
66     pinmap_pinout(miso, PinMap_SPI_MISO);
67     pinmap_pinout(sclk, PinMap_SPI_SCLK);
68     if (ssel != NC) {
69         pinmap_pinout(ssel, PinMap_SPI_SSEL);
70     }
71 }
72
73 void spi_free(spi_t *obj) {}
74
75 void spi_format(spi_t *obj, int bits, int mode, int slave) {
76     MBED_ASSERT((bits >= 4 && bits <= 16) || (mode >= 0 && mode <= 3));
77
78     ssp_disable(obj);
79     
80     int polarity = (mode & 0x2) ? 1 : 0;
81     int phase = (mode & 0x1) ? 1 : 0;
82     
83     // set it up
84     int DSS = bits - 1;            // DSS (data select size)
85     int SPO = (polarity) ? 1 : 0;  // SPO - clock out polarity
86     int SPH = (phase) ? 1 : 0;     // SPH - clock out phase
87     
88     int FRF = 0;                   // FRF (frame format) = SPI
89     uint32_t tmp = obj->spi->CR0;
90     tmp &= ~(0xFFFF);
91     tmp |= DSS << 0
92         | FRF << 4
93         | SPO << 6
94         | SPH << 7;
95     obj->spi->CR0 = tmp;
96     
97     tmp = obj->spi->CR1;
98     tmp &= ~(0xD);
99     tmp |= 0 << 0                   // LBM - loop back mode - off
100         | ((slave) ? 1 : 0) << 2   // MS - master slave mode, 1 = slave
101         | 0 << 3;                  // SOD - slave output disable - na
102     obj->spi->CR1 = tmp;
103     
104     ssp_enable(obj);
105 }
106
107 void spi_frequency(spi_t *obj, int hz) {
108     ssp_disable(obj);
109     
110     uint32_t PCLK = SystemCoreClock;
111     
112     int prescaler;
113     
114     for (prescaler = 2; prescaler <= 254; prescaler += 2) {
115         int prescale_hz = PCLK / prescaler;
116         
117         // calculate the divider
118         int divider = floor(((float)prescale_hz / (float)hz) + 0.5f);
119         
120         // check we can support the divider
121         if (divider < 256) {
122             // prescaler
123             obj->spi->CPSR = prescaler;
124             
125             // divider
126             obj->spi->CR0 &= ~(0xFFFF << 8);
127             obj->spi->CR0 |= (divider - 1) << 8;
128             ssp_enable(obj);
129             return;
130         }
131     }
132     error("Couldn't setup requested SPI frequency");
133 }
134
135 static inline int ssp_disable(spi_t *obj) {
136     return obj->spi->CR1 &= ~(1 << 1);
137 }
138
139 static inline int ssp_enable(spi_t *obj) {
140     return obj->spi->CR1 |= (1 << 1);
141 }
142
143 static inline int ssp_readable(spi_t *obj) {
144     return obj->spi->SR & (1 << 2);
145 }
146
147 static inline int ssp_writeable(spi_t *obj) {
148     return obj->spi->SR & (1 << 1);
149 }
150
151 static inline void ssp_write(spi_t *obj, int value) {
152     while (!ssp_writeable(obj));
153     obj->spi->DR = value;
154 }
155
156 static inline int ssp_read(spi_t *obj) {
157     while (!ssp_readable(obj));
158     return obj->spi->DR;
159 }
160
161 static inline int ssp_busy(spi_t *obj) {
162     return (obj->spi->SR & (1 << 4)) ? (1) : (0);
163 }
164
165 int spi_master_write(spi_t *obj, int value) {
166     ssp_write(obj, value);
167     return ssp_read(obj);
168 }
169
170 int spi_slave_receive(spi_t *obj) {
171     return (ssp_readable(obj) && !ssp_busy(obj)) ? (1) : (0);
172 }
173
174 int spi_slave_read(spi_t *obj) {
175     return obj->spi->DR;
176 }
177
178 void spi_slave_write(spi_t *obj, int value) {
179     while (ssp_writeable(obj) == 0) ;
180     obj->spi->DR = value;
181 }
182
183 int spi_busy(spi_t *obj) {
184     return ssp_busy(obj);
185 }