]> git.donarmstrong.com Git - qmk_firmware.git/blob - tool/mbed/mbed-sdk/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KLXX/TARGET_KL43Z/spi_api.c
Squashed 'tmk_core/' changes from 7967731..b9e0ea0
[qmk_firmware.git] / tool / mbed / mbed-sdk / libraries / mbed / targets / hal / TARGET_Freescale / TARGET_KLXX / TARGET_KL43Z / 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 "spi_api.h"
18
19 #include <math.h>
20
21 #include "cmsis.h"
22 #include "pinmap.h"
23
24 static const PinMap PinMap_SPI_SCLK[] = {
25     {PTC3,  SPI_1, 2},
26     {PTC5,  SPI_0, 2},
27     {PTD1,  SPI_0, 2},
28     {PTD5,  SPI_1, 2},
29     {NC  ,  NC   , 0}
30 };
31
32 static const PinMap PinMap_SPI_MOSI[] = {
33     {PTB16, SPI_1, 2},
34     {PTB17, SPI_1, 5},
35     {PTC6,  SPI_0, 2},
36     {PTC7,  SPI_0, 5},
37     {PTD2,  SPI_0, 2},
38     {PTD3,  SPI_0, 5},
39     {PTD6,  SPI_1, 2},
40     {PTD7,  SPI_1, 5},
41     {PTE1,  SPI_1, 2},
42     {NC  ,  NC   , 0}
43 };
44
45 static const PinMap PinMap_SPI_MISO[] = {
46     {PTB16, SPI_1, 5},
47     {PTB17, SPI_1, 2},
48     {PTC6,  SPI_0, 5},
49     {PTC7,  SPI_0, 2},
50     {PTD2,  SPI_0, 5},
51     {PTD3,  SPI_0, 2},
52     {PTD6,  SPI_1, 5},
53     {PTD7,  SPI_1, 2},
54     {PTE0,  SPI_1, 2},
55     {PTE1,  SPI_1, 5},
56     {NC   , NC   , 0}
57 };
58
59 static const PinMap PinMap_SPI_SSEL[] = {
60     {PTC4,  SPI_0, 2},
61     {PTD0,  SPI_0, 2},
62     {PTD4,  SPI_1, 2},
63     {NC  ,  NC   , 0}
64 };
65
66 void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel) {
67     // determine the SPI to use
68     SPIName spi_mosi = (SPIName)pinmap_peripheral(mosi, PinMap_SPI_MOSI);
69     SPIName spi_miso = (SPIName)pinmap_peripheral(miso, PinMap_SPI_MISO);
70     SPIName spi_sclk = (SPIName)pinmap_peripheral(sclk, PinMap_SPI_SCLK);
71     SPIName spi_ssel = (SPIName)pinmap_peripheral(ssel, PinMap_SPI_SSEL);
72     SPIName spi_data = (SPIName)pinmap_merge(spi_mosi, spi_miso);
73     SPIName spi_cntl = (SPIName)pinmap_merge(spi_sclk, spi_ssel);
74
75     obj->spi = (SPI_Type*)pinmap_merge(spi_data, spi_cntl);
76     MBED_ASSERT((int)obj->spi != NC);
77
78     // enable power and clocking
79     switch ((int)obj->spi) {
80         case SPI_0: SIM->SCGC5 |= 1 << 13; SIM->SCGC4 |= 1 << 22; break;
81         case SPI_1: SIM->SCGC5 |= 1 << 13; SIM->SCGC4 |= 1 << 23; break;
82     }
83
84     // set default format and frequency
85     if (ssel == NC) {
86         spi_format(obj, 8, 0, 0);  // 8 bits, mode 0, master
87     } else {
88         spi_format(obj, 8, 0, 1);  // 8 bits, mode 0, slave
89     }
90     spi_frequency(obj, 1000000);
91
92     // enable SPI
93     obj->spi->C1 |= SPI_C1_SPE_MASK;
94     obj->spi->C2 &= ~SPI_C2_SPIMODE_MASK; //8bit
95
96     // pin out the spi pins
97     pinmap_pinout(mosi, PinMap_SPI_MOSI);
98     pinmap_pinout(miso, PinMap_SPI_MISO);
99     pinmap_pinout(sclk, PinMap_SPI_SCLK);
100     if (ssel != NC) {
101         pinmap_pinout(ssel, PinMap_SPI_SSEL);
102     }
103 }
104
105 void spi_free(spi_t *obj) {
106     // [TODO]
107 }
108
109 void spi_format(spi_t *obj, int bits, int mode, int slave) {
110     MBED_ASSERT((bits == 8) || (bits == 16));
111     MBED_ASSERT((mode >= 0) && (mode <= 3));
112
113     uint8_t polarity = (mode & 0x2) ? 1 : 0;
114     uint8_t phase = (mode & 0x1) ? 1 : 0;
115     uint8_t c1_data = ((!slave) << 4) | (polarity << 3) | (phase << 2);
116
117     // clear MSTR, CPOL and CPHA bits
118     obj->spi->C1 &= ~(0x7 << 2);
119
120     // write new value
121     obj->spi->C1 |= c1_data;
122     if (bits == 8) {
123         obj->spi->C2 &= ~SPI_C2_SPIMODE_MASK;
124     } else {
125         obj->spi->C2 |= SPI_C2_SPIMODE_MASK;
126     }
127 }
128
129 void spi_frequency(spi_t *obj, int hz) {
130     uint32_t error = 0;
131     uint32_t p_error = 0xffffffff;
132     uint32_t ref = 0;
133     uint8_t  spr = 0;
134     uint8_t  ref_spr = 0;
135     uint8_t  ref_prescaler = 0;
136
137     // bus clk
138     uint32_t PCLK = SystemCoreClock / (((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV4_MASK) >> SIM_CLKDIV1_OUTDIV4_SHIFT) + 1);
139     uint8_t prescaler = 1;
140     uint8_t divisor = 2;
141
142     for (prescaler = 1; prescaler <= 8; prescaler++) {
143         divisor = 2;
144         for (spr = 0; spr <= 8; spr++, divisor *= 2) {
145             ref = PCLK / (prescaler*divisor);
146             if (ref > (uint32_t)hz)
147                 continue;
148             error = hz - ref;
149             if (error < p_error) {
150                 ref_spr = spr;
151                 ref_prescaler = prescaler - 1;
152                 p_error = error;
153             }
154         }
155     }
156
157     // set SPPR and SPR
158     obj->spi->BR = ((ref_prescaler & 0x7) << 4) | (ref_spr & 0xf);
159 }
160
161 static inline int spi_writeable(spi_t * obj) {
162     return (obj->spi->S & SPI_S_SPTEF_MASK) ? 1 : 0;
163 }
164
165 static inline int spi_readable(spi_t * obj) {
166     return (obj->spi->S & SPI_S_SPRF_MASK) ? 1 : 0;
167 }
168
169 int spi_master_write(spi_t *obj, int value) {
170     int ret;
171     if (obj->spi->C2 & SPI_C2_SPIMODE_MASK) {
172         // 16bit
173         while(!spi_writeable(obj));
174         obj->spi->DL = (value & 0xff);
175         obj->spi->DH = ((value >> 8) & 0xff);
176
177         // wait rx buffer full
178         while (!spi_readable(obj));
179         ret = obj->spi->DH;
180         ret = (ret << 8) | obj->spi->DL;
181     } else {
182         //8bit
183         while(!spi_writeable(obj));
184         obj->spi->DL = (value & 0xff);
185
186         // wait rx buffer full
187         while (!spi_readable(obj));
188         ret = (obj->spi->DL & 0xff);
189     }
190
191     return ret;
192 }
193
194 int spi_slave_receive(spi_t *obj) {
195     return spi_readable(obj);
196 }
197
198 int spi_slave_read(spi_t *obj) {
199     int ret;
200     if (obj->spi->C2 & SPI_C2_SPIMODE_MASK) {
201         ret = obj->spi->DH;
202         ret = ((ret << 8) | obj->spi->DL);
203     } else {
204         ret = obj->spi->DL;
205     }
206     return ret;
207 }
208
209 void spi_slave_write(spi_t *obj, int value) {
210     while (!spi_writeable(obj));
211     if (obj->spi->C2 & SPI_C2_SPIMODE_MASK) {
212         obj->spi->DL = (value & 0xff);
213         obj->spi->DH = ((value >> 8) & 0xff);
214     } else {
215         obj->spi->DL = value;
216     }
217
218 }