1 /*
2 * Copyright (c) 2013 Google Inc.
3 *
4 * Use of this source code is governed by a MIT-style
5 * license that can be found in the LICENSE file or at
6 * https://opensource.org/licenses/MIT
7 */
8
9 #include <assert.h>
10 #include <lk/compiler.h>
11 #include <lk/debug.h>
12 #include <printf.h>
13 #include <lk/err.h>
14
15 #include <dev/gpio.h>
16 #include <dev/gpio_i2c.h>
17 #include <kernel/mutex.h>
18
19 #if (!(defined(GPIO_I2C_BUS_COUNT)) || (GPIO_I2C_BUS_COUNT <= 0))
20 #error ERROR: Must define GPIO_I2C_BUS_COUNT
21 #endif
22
23 #if GPIO_I2C_PULLUPS
24 #define GPIO_I2C_INPUT (GPIO_INPUT | GPIO_PULLUP)
25 #else
26 #define GPIO_I2C_INPUT (GPIO_INPUT)
27 #endif // GPIO_I2C_PULLUPS
28
29 typedef struct gpio_i2c_state {
30 mutex_t lock;
31 const gpio_i2c_info_t *info;
32 } gpio_i2c_state_t;
33
34 static gpio_i2c_state_t gpio_i2c_states[GPIO_I2C_BUS_COUNT];
35
36 /******************************************************************************
37 *
38 * Internal implementation.
39 *
40 ******************************************************************************/
send_start(const gpio_i2c_info_t * i)41 static inline void send_start(const gpio_i2c_info_t *i) {
42 gpio_config(i->sda, GPIO_OUTPUT);
43 spin_cycles(i->qcd);
44 gpio_config(i->scl, GPIO_OUTPUT);
45 spin_cycles(i->hcd);
46 }
47
send_stop(const gpio_i2c_info_t * i)48 static inline void send_stop(const gpio_i2c_info_t *i) {
49 gpio_config(i->sda, GPIO_OUTPUT);
50 gpio_config(i->scl, GPIO_I2C_INPUT);
51 spin_cycles(i->qcd);
52 gpio_config(i->sda, GPIO_I2C_INPUT);
53 }
54
send_restart(const gpio_i2c_info_t * i)55 static inline void send_restart(const gpio_i2c_info_t *i) {
56 gpio_config(i->scl, GPIO_I2C_INPUT);
57 spin_cycles(i->qcd);
58 send_start(i);
59 }
60
send_nack(const gpio_i2c_info_t * i)61 static inline void send_nack(const gpio_i2c_info_t *i) {
62 spin_cycles(i->hcd);
63 gpio_config(i->scl, GPIO_I2C_INPUT);
64 spin_cycles(i->hcd);
65 gpio_config(i->scl, GPIO_OUTPUT);
66 gpio_config(i->sda, GPIO_I2C_INPUT);
67 }
68
send_ack(const gpio_i2c_info_t * i)69 static inline void send_ack(const gpio_i2c_info_t *i) {
70 gpio_config(i->sda, GPIO_OUTPUT);
71 send_nack(i);
72 }
73
send_byte(const gpio_i2c_info_t * i,uint32_t b)74 static inline bool send_byte(const gpio_i2c_info_t *i, uint32_t b) {
75 bool ret;
76
77 for (size_t j = 0; j < 8; ++j) {
78 if (b & 0x80)
79 gpio_config(i->sda, GPIO_I2C_INPUT);
80 else
81 gpio_config(i->sda, GPIO_OUTPUT);
82 b <<= 1;
83 /* setup time for data (the time between when data becomes stable and
84 * clock becomes a stable high) is spec'ed to be 250ns for 100KHz i2c
85 * and 100nsec for 400KHz i2c. If any micro running LK needs to spin
86 * here in order to hit that timing, they are welcome to add a spin
87 * right here.
88 */
89 spin_cycles(i->hcd);
90 gpio_config(i->scl, GPIO_I2C_INPUT);
91 spin_cycles(i->hcd);
92 gpio_config(i->scl, GPIO_OUTPUT);
93 }
94
95 gpio_config(i->sda, GPIO_I2C_INPUT);
96 spin_cycles(i->hcd);
97 gpio_config(i->scl, GPIO_I2C_INPUT);
98 spin_cycles(i->hcd);
99 ret = (0 == gpio_get(i->sda));
100 gpio_config(i->scl, GPIO_OUTPUT);
101 spin_cycles(i->hcd);
102
103 return ret;
104 }
105
recv_byte(const gpio_i2c_info_t * i,uint8_t * b)106 static inline void recv_byte(const gpio_i2c_info_t *i, uint8_t *b) {
107 uint32_t tmp = 0;
108
109 for (size_t j = 0; j < 7; ++j) {
110 gpio_config(i->scl, GPIO_I2C_INPUT);
111 spin_cycles(i->hcd);
112 if (gpio_get(i->sda))
113 tmp |= 1;
114 tmp <<= 1;
115 gpio_config(i->scl, GPIO_OUTPUT);
116 spin_cycles(i->hcd);
117 }
118
119 gpio_config(i->scl, GPIO_I2C_INPUT);
120 spin_cycles(i->hcd);
121 if (gpio_get(i->sda))
122 tmp |= 1;
123 gpio_config(i->scl, GPIO_OUTPUT);
124
125 *b = (uint8_t)tmp;
126 }
127
gpio_i2c_tx_common(gpio_i2c_state_t * s,uint8_t address,const uint8_t * reg,const void * buf,size_t cnt)128 static status_t gpio_i2c_tx_common(gpio_i2c_state_t *s,
129 uint8_t address,
130 const uint8_t *reg,
131 const void *buf,
132 size_t cnt) {
133 const gpio_i2c_info_t *i = s->info;
134 status_t ret = ERR_I2C_NACK;
135
136 DEBUG_ASSERT(buf || !cnt);
137
138 mutex_acquire(&s->lock);
139 send_start(i);
140 if (!send_byte(i, address << 1))
141 goto finished;
142
143 if ((NULL != reg) && !send_byte(i, *reg))
144 goto finished;
145
146 for (size_t j = 0; j < cnt; ++j)
147 if (!send_byte(i, ((const uint8_t *)buf)[j]))
148 goto finished;
149
150 ret = NO_ERROR;
151
152 finished:
153 send_stop(i);
154 mutex_release(&s->lock);
155 return ret;
156 }
157
gpio_i2c_rx_common(gpio_i2c_state_t * s,uint8_t address,const uint8_t * reg,void * buf,size_t cnt)158 static status_t gpio_i2c_rx_common(gpio_i2c_state_t *s,
159 uint8_t address,
160 const uint8_t *reg,
161 void *buf,
162 size_t cnt) {
163 const gpio_i2c_info_t *i = s->info;
164 status_t ret = ERR_I2C_NACK;
165
166 DEBUG_ASSERT(buf && cnt);
167
168 address <<= 1;
169
170 mutex_acquire(&s->lock);
171 send_start(i);
172 if (!send_byte(i, address | (!reg ? 0x1 : 0x0)))
173 goto finished;
174
175 if (NULL != reg) {
176 if (!send_byte(i, *reg))
177 goto finished;
178
179 send_restart(i);
180
181 if (!send_byte(i, address | 0x1))
182 goto finished;
183 }
184
185 recv_byte(i, buf++);
186 for (size_t j = 0; j < (cnt - 1); ++j) {
187 send_ack(i);
188 recv_byte(i, buf++);
189 }
190 send_nack(i);
191 ret = NO_ERROR;
192
193 finished:
194 send_stop(i);
195 mutex_release(&s->lock);
196 return ret;
197 }
198
gpio_i2c_add_bus(uint32_t bus_id,const gpio_i2c_info_t * info)199 void gpio_i2c_add_bus(uint32_t bus_id, const gpio_i2c_info_t *info) {
200 gpio_i2c_state_t *s = gpio_i2c_states + bus_id;
201
202 DEBUG_ASSERT(info);
203 DEBUG_ASSERT(bus_id < GPIO_I2C_BUS_COUNT);
204 DEBUG_ASSERT(!s->info);
205
206 gpio_config(info->scl, GPIO_I2C_INPUT);
207 gpio_config(info->sda, GPIO_I2C_INPUT);
208 gpio_set(info->scl, 0);
209 gpio_set(info->sda, 0);
210
211 mutex_init(&s->lock);
212 s->info = info;
213 }
214
215 /******************************************************************************
216 *
217 * LK facing API
218 *
219 * *****************************************************************************/
gpio_i2c_init_early(void)220 void gpio_i2c_init_early(void) { }
gpio_i2c_init(void)221 void gpio_i2c_init(void) { }
222
gpio_i2c_transmit(int bus,uint8_t address,const void * buf,size_t cnt)223 status_t gpio_i2c_transmit(int bus, uint8_t address, const void *buf, size_t cnt) {
224 gpio_i2c_state_t *s = gpio_i2c_states + bus;
225 if (((unsigned)bus >= countof(gpio_i2c_states)) || !s->info)
226 return ERR_NOT_FOUND;
227
228 return gpio_i2c_tx_common(s, address, NULL, buf, cnt);
229 }
230
gpio_i2c_receive(int bus,uint8_t address,void * buf,size_t cnt)231 status_t gpio_i2c_receive(int bus, uint8_t address, void *buf, size_t cnt) {
232 gpio_i2c_state_t *s = gpio_i2c_states + bus;
233 if (((unsigned)bus >= countof(gpio_i2c_states)) || !s->info)
234 return ERR_NOT_FOUND;
235
236 return gpio_i2c_rx_common(s, address, NULL, buf, cnt);
237 }
238
gpio_i2c_write_reg_bytes(int bus,uint8_t address,uint8_t reg,const uint8_t * buf,size_t cnt)239 status_t gpio_i2c_write_reg_bytes(int bus, uint8_t address, uint8_t reg, const uint8_t *buf, size_t cnt) {
240 gpio_i2c_state_t *s = gpio_i2c_states + bus;
241 if (((unsigned)bus >= countof(gpio_i2c_states)) || !s->info)
242 return ERR_NOT_FOUND;
243
244 return gpio_i2c_tx_common(s, address, ®, buf, cnt);
245 }
246
gpio_i2c_read_reg_bytes(int bus,uint8_t address,uint8_t reg,uint8_t * buf,size_t cnt)247 status_t gpio_i2c_read_reg_bytes(int bus, uint8_t address, uint8_t reg, uint8_t *buf, size_t cnt) {
248 gpio_i2c_state_t *s = gpio_i2c_states + bus;
249 if (((unsigned)bus >= countof(gpio_i2c_states)) || !s->info) {
250 return ERR_NOT_FOUND;
251 }
252
253 return gpio_i2c_rx_common(s, address, ®, buf, cnt);
254 }
255
256 void i2c_init_early(void) __WEAK_ALIAS("gpio_i2c_init_early");
257 void i2c_init(void) __WEAK_ALIAS("gpio_i2c_init");
258 status_t i2c_transmit(int, uint8_t, const void *, size_t) __WEAK_ALIAS("gpio_i2c_transmit");
259 status_t i2c_receive(int, uint8_t, void *, size_t) __WEAK_ALIAS("gpio_i2c_receive");
260 status_t i2c_write_reg_bytes(int, uint8_t, uint8_t,
261 const uint8_t *, size_t) __WEAK_ALIAS("gpio_i2c_write_reg_bytes");
262 status_t i2c_read_reg_bytes(int, uint8_t, uint8_t,
263 uint8_t *, size_t) __WEAK_ALIAS("gpio_i2c_read_reg_bytes");
264