1 /*
2  * Copyright (c) 2013 Google Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files
6  * (the "Software"), to deal in the Software without restriction,
7  * including without limitation the rights to use, copy, modify, merge,
8  * publish, distribute, sublicense, and/or sell copies of the Software,
9  * and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23 
24 #include <assert.h>
25 #include <compiler.h>
26 #include <debug.h>
27 #include <printf.h>
28 #include <err.h>
29 
30 #include <dev/gpio.h>
31 #include <dev/gpio_i2c.h>
32 #include <kernel/mutex.h>
33 
34 #if (!(defined(GPIO_I2C_BUS_COUNT)) || (GPIO_I2C_BUS_COUNT <= 0))
35 #error ERROR: Must define GPIO_I2C_BUS_COUNT
36 #endif
37 
38 #if GPIO_I2C_PULLUPS
39 #define GPIO_I2C_INPUT (GPIO_INPUT | GPIO_PULLUP)
40 #else
41 #define GPIO_I2C_INPUT (GPIO_INPUT)
42 #endif  // GPIO_I2C_PULLUPS
43 
44 typedef struct gpio_i2c_state {
45     mutex_t                 lock;
46     const gpio_i2c_info_t  *info;
47 } gpio_i2c_state_t;
48 
49 static gpio_i2c_state_t gpio_i2c_states[GPIO_I2C_BUS_COUNT];
50 
51 /******************************************************************************
52  *
53  * Internal implementation.
54  *
55  ******************************************************************************/
send_start(const gpio_i2c_info_t * i)56 static inline void send_start(const gpio_i2c_info_t *i)
57 {
58     gpio_config(i->sda, GPIO_OUTPUT);
59     spin_cycles(i->qcd);
60     gpio_config(i->scl, GPIO_OUTPUT);
61     spin_cycles(i->hcd);
62 }
63 
send_stop(const gpio_i2c_info_t * i)64 static inline void send_stop(const gpio_i2c_info_t *i)
65 {
66     gpio_config(i->sda, GPIO_OUTPUT);
67     gpio_config(i->scl, GPIO_I2C_INPUT);
68     spin_cycles(i->qcd);
69     gpio_config(i->sda, GPIO_I2C_INPUT);
70 }
71 
send_restart(const gpio_i2c_info_t * i)72 static inline void send_restart(const gpio_i2c_info_t *i)
73 {
74     gpio_config(i->scl, GPIO_I2C_INPUT);
75     spin_cycles(i->qcd);
76     send_start(i);
77 }
78 
send_nack(const gpio_i2c_info_t * i)79 static inline void send_nack(const gpio_i2c_info_t *i)
80 {
81     spin_cycles(i->hcd);
82     gpio_config(i->scl, GPIO_I2C_INPUT);
83     spin_cycles(i->hcd);
84     gpio_config(i->scl, GPIO_OUTPUT);
85     gpio_config(i->sda, GPIO_I2C_INPUT);
86 }
87 
send_ack(const gpio_i2c_info_t * i)88 static inline void send_ack(const gpio_i2c_info_t *i)
89 {
90     gpio_config(i->sda, GPIO_OUTPUT);
91     send_nack(i);
92 }
93 
send_byte(const gpio_i2c_info_t * i,uint32_t b)94 static inline bool send_byte(const gpio_i2c_info_t *i, uint32_t b)
95 {
96     bool ret;
97 
98     for (size_t j = 0; j < 8; ++j) {
99         if (b & 0x80)
100             gpio_config(i->sda, GPIO_I2C_INPUT);
101         else
102             gpio_config(i->sda, GPIO_OUTPUT);
103         b <<= 1;
104         /* setup time for data (the time between when data becomes stable and
105          * clock becomes a stable high) is spec'ed to be 250ns for 100KHz i2c
106          * and 100nsec for 400KHz i2c.  If any micro running LK needs to spin
107          * here in order to hit that timing, they are welcome to add a spin
108          * right here.
109          */
110         spin_cycles(i->hcd);
111         gpio_config(i->scl, GPIO_I2C_INPUT);
112         spin_cycles(i->hcd);
113         gpio_config(i->scl, GPIO_OUTPUT);
114     }
115 
116     gpio_config(i->sda, GPIO_I2C_INPUT);
117     spin_cycles(i->hcd);
118     gpio_config(i->scl, GPIO_I2C_INPUT);
119     spin_cycles(i->hcd);
120     ret = (0 == gpio_get(i->sda));
121     gpio_config(i->scl, GPIO_OUTPUT);
122     spin_cycles(i->hcd);
123 
124     return ret;
125 }
126 
recv_byte(const gpio_i2c_info_t * i,uint8_t * b)127 static inline void recv_byte(const gpio_i2c_info_t *i, uint8_t *b)
128 {
129     uint32_t tmp = 0;
130 
131     for (size_t j = 0; j < 7; ++j) {
132         gpio_config(i->scl, GPIO_I2C_INPUT);
133         spin_cycles(i->hcd);
134         if (gpio_get(i->sda))
135             tmp |= 1;
136         tmp <<= 1;
137         gpio_config(i->scl, GPIO_OUTPUT);
138         spin_cycles(i->hcd);
139     }
140 
141     gpio_config(i->scl, GPIO_I2C_INPUT);
142     spin_cycles(i->hcd);
143     if (gpio_get(i->sda))
144         tmp |= 1;
145     gpio_config(i->scl, GPIO_OUTPUT);
146 
147     *b = (uint8_t)tmp;
148 }
149 
gpio_i2c_tx_common(gpio_i2c_state_t * s,uint8_t address,const uint8_t * reg,const void * buf,size_t cnt)150 static status_t gpio_i2c_tx_common(gpio_i2c_state_t *s,
151                                    uint8_t address,
152                                    const uint8_t *reg,
153                                    const void *buf,
154                                    size_t cnt)
155 {
156     const gpio_i2c_info_t *i = s->info;
157     status_t ret = ERR_I2C_NACK;
158 
159     DEBUG_ASSERT(buf || !cnt);
160 
161     mutex_acquire(&s->lock);
162     send_start(i);
163     if (!send_byte(i, address << 1))
164         goto finished;
165 
166     if ((NULL != reg) && !send_byte(i, *reg))
167         goto finished;
168 
169     for (size_t j = 0; j < cnt; ++j)
170         if (!send_byte(i, ((const uint8_t *)buf)[j]))
171             goto finished;
172 
173     ret = NO_ERROR;
174 
175 finished:
176     send_stop(i);
177     mutex_release(&s->lock);
178     return ret;
179 }
180 
gpio_i2c_rx_common(gpio_i2c_state_t * s,uint8_t address,const uint8_t * reg,void * buf,size_t cnt)181 static status_t gpio_i2c_rx_common(gpio_i2c_state_t *s,
182                                    uint8_t address,
183                                    const uint8_t *reg,
184                                    void *buf,
185                                    size_t cnt)
186 {
187     const gpio_i2c_info_t *i = s->info;
188     status_t ret = ERR_I2C_NACK;
189 
190     DEBUG_ASSERT(buf && cnt);
191 
192     address <<= 1;
193 
194     mutex_acquire(&s->lock);
195     send_start(i);
196     if (!send_byte(i, address | (!reg ? 0x1 : 0x0)))
197         goto finished;
198 
199     if (NULL != reg) {
200         if (!send_byte(i, *reg))
201             goto finished;
202 
203         send_restart(i);
204 
205         if (!send_byte(i, address | 0x1))
206             goto finished;
207     }
208 
209     recv_byte(i, buf++);
210     for (size_t j = 0; j < (cnt - 1); ++j) {
211         send_ack(i);
212         recv_byte(i, buf++);
213     }
214     send_nack(i);
215     ret = NO_ERROR;
216 
217 finished:
218     send_stop(i);
219     mutex_release(&s->lock);
220     return ret;
221 }
222 
gpio_i2c_add_bus(uint32_t bus_id,const gpio_i2c_info_t * info)223 void gpio_i2c_add_bus(uint32_t bus_id, const gpio_i2c_info_t *info)
224 {
225     gpio_i2c_state_t *s = gpio_i2c_states + bus_id;
226 
227     DEBUG_ASSERT(info);
228     DEBUG_ASSERT(bus_id < GPIO_I2C_BUS_COUNT);
229     DEBUG_ASSERT(!s->info);
230 
231     gpio_config(info->scl, GPIO_I2C_INPUT);
232     gpio_config(info->sda, GPIO_I2C_INPUT);
233     gpio_set(info->scl, 0);
234     gpio_set(info->sda, 0);
235 
236     mutex_init(&s->lock);
237     s->info = info;
238 }
239 
240 /******************************************************************************
241 *
242 *  LK facing API
243 *
244 * *****************************************************************************/
gpio_i2c_init_early(void)245 void gpio_i2c_init_early(void) { }
gpio_i2c_init(void)246 void gpio_i2c_init(void) { }
247 
gpio_i2c_transmit(int bus,uint8_t address,const void * buf,size_t cnt)248 status_t gpio_i2c_transmit(int bus, uint8_t address, const void *buf, size_t cnt)
249 {
250     gpio_i2c_state_t *s = gpio_i2c_states + bus;
251     if (((unsigned)bus >= countof(gpio_i2c_states)) || !s->info)
252         return ERR_NOT_FOUND;
253 
254     return gpio_i2c_tx_common(s, address, NULL, buf, cnt);
255 }
256 
gpio_i2c_receive(int bus,uint8_t address,void * buf,size_t cnt)257 status_t gpio_i2c_receive(int bus, uint8_t address, void *buf, size_t cnt)
258 {
259     gpio_i2c_state_t *s = gpio_i2c_states + bus;
260     if (((unsigned)bus >= countof(gpio_i2c_states)) || !s->info)
261         return ERR_NOT_FOUND;
262 
263     return gpio_i2c_rx_common(s, address, NULL, buf, cnt);
264 }
265 
gpio_i2c_write_reg_bytes(int bus,uint8_t address,uint8_t reg,const uint8_t * buf,size_t cnt)266 status_t gpio_i2c_write_reg_bytes(int bus, uint8_t address, uint8_t reg, const uint8_t *buf, size_t cnt)
267 {
268     gpio_i2c_state_t *s = gpio_i2c_states + bus;
269     if (((unsigned)bus >= countof(gpio_i2c_states)) || !s->info)
270         return ERR_NOT_FOUND;
271 
272     return gpio_i2c_tx_common(s, address, &reg, buf, cnt);
273 }
274 
gpio_i2c_read_reg_bytes(int bus,uint8_t address,uint8_t reg,uint8_t * buf,size_t cnt)275 status_t gpio_i2c_read_reg_bytes(int bus, uint8_t address, uint8_t reg, uint8_t *buf, size_t cnt)
276 {
277     gpio_i2c_state_t *s = gpio_i2c_states + bus;
278     if (((unsigned)bus >= countof(gpio_i2c_states)) || !s->info) {
279         return ERR_NOT_FOUND;
280     }
281 
282     return gpio_i2c_rx_common(s, address, &reg, buf, cnt);
283 }
284 
285 void i2c_init_early(void) __WEAK_ALIAS("gpio_i2c_init_early");
286 void i2c_init(void) __WEAK_ALIAS("gpio_i2c_init");
287 status_t i2c_transmit(int, uint8_t, const void *, size_t) __WEAK_ALIAS("gpio_i2c_transmit");
288 status_t i2c_receive(int, uint8_t, void *, size_t) __WEAK_ALIAS("gpio_i2c_receive");
289 status_t i2c_write_reg_bytes(int, uint8_t, uint8_t,
290                              const uint8_t *, size_t) __WEAK_ALIAS("gpio_i2c_write_reg_bytes");
291 status_t i2c_read_reg_bytes(int, uint8_t, uint8_t,
292                             uint8_t *, size_t) __WEAK_ALIAS("gpio_i2c_read_reg_bytes");
293