]> git.donarmstrong.com Git - qmk_firmware.git/blob - tool/mbed/mbed-sdk/libraries/mbed/targets/hal/TARGET_NXP/TARGET_LPC15XX/i2c_api.c
Squashed 'tmk_core/' changes from 7967731..b9e0ea0
[qmk_firmware.git] / tool / mbed / mbed-sdk / libraries / mbed / targets / hal / TARGET_NXP / TARGET_LPC15XX / i2c_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 "i2c_api.h"
18 #include "cmsis.h"
19 #include "pinmap.h"
20
21 static uint8_t repeated_start = 0;
22
23 #define I2C_STAT(x)         ((LPC_I2C0->STAT >> 1) & (0x07))
24
25 static inline int i2c_status(i2c_t *obj) {
26     return I2C_STAT(obj);
27 }
28
29 // Wait until the Serial Interrupt (SI) is set
30 static int i2c_wait_SI(i2c_t *obj) {
31     volatile int timeout = 0;
32     while (!(LPC_I2C0->STAT & (1 << 0))) {
33         timeout++;
34         if (timeout > 100000) return -1;
35     }
36     return 0;
37 }
38
39 static inline void i2c_interface_enable(i2c_t *obj) {
40     LPC_I2C0->CFG |= (1 << 0);
41 }
42
43 void i2c_init(i2c_t *obj, PinName sda, PinName scl) {
44     MBED_ASSERT((sda == P0_23) && (scl == P0_22));
45     
46     // Enables clock for I2C0
47     LPC_SYSCON->SYSAHBCLKCTRL1 |= (1 << 13);
48
49     LPC_SYSCON->PRESETCTRL1 |=  (1 << 13);
50     LPC_SYSCON->PRESETCTRL1 &= ~(1 << 13);
51
52     // pin enable
53     LPC_SWM->PINENABLE1 &= ~(0x3 << 3);
54
55     // set default frequency at 100kHz
56     i2c_frequency(obj, 100000);
57     i2c_interface_enable(obj);
58 }
59
60 inline int i2c_start(i2c_t *obj) {
61     int status = 0;
62     if (repeated_start) {
63         LPC_I2C0->MSTCTL = (1 << 1) | (1 << 0);
64         repeated_start = 0;
65     } else {
66         LPC_I2C0->MSTCTL = (1 << 1);
67     }
68     return status;
69 }
70
71 inline int i2c_stop(i2c_t *obj) {
72     volatile int timeout = 0;
73
74     LPC_I2C0->MSTCTL = (1 << 2) | (1 << 0);
75     while ((LPC_I2C0->STAT & ((1 << 0) | (7 << 1))) != ((1 << 0) | (0 << 1))) {
76         timeout ++;
77         if (timeout > 100000) return 1;
78     }
79
80     return 0;
81 }
82
83
84 static inline int i2c_do_write(i2c_t *obj, int value, uint8_t addr) {
85     // write the data
86     LPC_I2C0->MSTDAT = value;
87     
88     if (!addr)
89         LPC_I2C0->MSTCTL = (1 << 0);
90     
91     // wait and return status
92     i2c_wait_SI(obj);
93     return i2c_status(obj);
94 }
95
96 static inline int i2c_do_read(i2c_t *obj, int last) {
97     // wait for it to arrive
98     i2c_wait_SI(obj);
99     if (!last)
100         LPC_I2C0->MSTCTL = (1 << 0);
101     
102     // return the data
103     return (LPC_I2C0->MSTDAT & 0xFF);
104 }
105
106 void i2c_frequency(i2c_t *obj, int hz) {
107     // No peripheral clock divider on the M0
108     uint32_t PCLK = SystemCoreClock;
109     uint32_t clkdiv = PCLK / (hz * 4) - 1;
110     
111     LPC_I2C0->DIV = clkdiv;
112     LPC_I2C0->MSTTIME = 0;
113 }
114
115 int i2c_read(i2c_t *obj, int address, char *data, int length, int stop) {
116     int count, status;
117     
118     i2c_start(obj);
119     
120     LPC_I2C0->MSTDAT = (address | 0x01);
121     LPC_I2C0->MSTCTL |= 0x20;
122     if (i2c_wait_SI(obj) == -1)
123         return -1;
124
125     status = ((LPC_I2C0->STAT >> 1) & (0x07));
126     if (status != 0x01) {
127         i2c_stop(obj);
128         return I2C_ERROR_NO_SLAVE;
129     }
130     
131     // Read in all except last byte
132     for (count = 0; count < (length - 1); count++) {
133         if (i2c_wait_SI(obj) == -1)
134             return -1;
135         LPC_I2C0->MSTCTL = (1 << 0);
136         data[count] = (LPC_I2C0->MSTDAT & 0xFF);
137         status = ((LPC_I2C0->STAT >> 1) & (0x07));
138         if (status != 0x01) {
139             i2c_stop(obj);
140             return count;
141         }
142     }
143     
144     // read in last byte
145     if (i2c_wait_SI(obj) == -1)
146         return -1;
147
148     data[count] = (LPC_I2C0->MSTDAT & 0xFF);
149     status = i2c_status(obj);
150     if (status != 0x01) {
151         i2c_stop(obj);
152         return length - 1;
153     }
154     // If not repeated start, send stop.
155     if (stop) {
156         i2c_stop(obj);
157     } else {
158         repeated_start = 1;
159     }
160     
161     return length;
162 }
163
164 int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop) {
165     int i, status;
166     
167     i2c_start(obj);
168     
169     LPC_I2C0->MSTDAT = (address & 0xFE);
170     LPC_I2C0->MSTCTL |= 0x20;
171     if (i2c_wait_SI(obj) == -1)
172         return -1;
173
174     status = ((LPC_I2C0->STAT >> 1) & (0x07));
175     if (status != 0x02) {
176         i2c_stop(obj);
177         return I2C_ERROR_NO_SLAVE;
178     }
179     
180     for (i=0; i<length; i++) {
181         LPC_I2C0->MSTDAT = data[i];
182         LPC_I2C0->MSTCTL = (1 << 0);
183         if (i2c_wait_SI(obj) == -1)
184             return -1;
185
186         status = ((LPC_I2C0->STAT >> 1) & (0x07));
187         if (status != 0x02) {
188             i2c_stop(obj);
189             return i;
190         }
191     }
192     
193     // If not repeated start, send stop.
194     if (stop) {
195         i2c_stop(obj);
196     } else {
197         repeated_start = 1;
198     }
199     
200     return length;
201 }
202
203 void i2c_reset(i2c_t *obj) {
204     i2c_stop(obj);
205 }
206
207 int i2c_byte_read(i2c_t *obj, int last) {
208     return (i2c_do_read(obj, last) & 0xFF);
209 }
210
211 int i2c_byte_write(i2c_t *obj, int data) {
212     if (i2c_do_write(obj, (data & 0xFF), 0) == 2) {
213         return 1;
214     } else {
215         return 0;
216     }
217 }