1 /* This file contains device independent i2c device driver helpers. */
2
3 #include <assert.h>
4 #include <minix/drivers.h>
5 #include <minix/endpoint.h>
6 #include <minix/i2c.h>
7 #include <minix/i2cdriver.h>
8 #include <minix/ipc.h>
9 #include <minix/ds.h>
10
11 void
i2cdriver_announce(uint32_t bus)12 i2cdriver_announce(uint32_t bus)
13 {
14 /* Announce we are up after a fresh start or restart. */
15 int r;
16 char key[DS_MAX_KEYLEN];
17 char label[DS_MAX_KEYLEN];
18 const char *driver_prefix = "drv.i2c.";
19
20 /* Callers are allowed to use ipc_sendrec to communicate with drivers.
21 * For this reason, there may blocked callers when a driver restarts.
22 * Ask the kernel to unblock them (if any).
23 */
24 if ((r = sys_statectl(SYS_STATE_CLEAR_IPC_REFS, 0, 0)) != OK) {
25 panic("chardriver_init: sys_statectl failed: %d", r);
26 }
27
28 /* Publish a driver up event. */
29 r = ds_retrieve_label_name(label, sef_self());
30 if (r != OK) {
31 panic("unable to get own label: %d\n", r);
32 }
33 /* example key: drv.i2c.1.cat24c245.0x50 */
34 snprintf(key, DS_MAX_KEYLEN, "%s%d.%s", driver_prefix, bus, label);
35 r = ds_publish_u32(key, DS_DRIVER_UP, DSF_OVERWRITE);
36 if (r != OK) {
37 panic("unable to publish driver up event: %d\n", r);
38 }
39 }
40
41 int
i2cdriver_env_parse(uint32_t * bus,i2c_addr_t * address,i2c_addr_t * valid_addrs)42 i2cdriver_env_parse(uint32_t * bus, i2c_addr_t * address,
43 i2c_addr_t * valid_addrs)
44 {
45 /* fill in bus and address with the values passed on the command line */
46 int r;
47 int found;
48 long int busl;
49 long int addressl;
50
51 r = env_parse("bus", "d", 0, &busl, 1, 3);
52 if (r != EP_SET) {
53 return -1;
54 }
55 *bus = (uint32_t) busl;
56
57 r = env_parse("address", "x", 0, &addressl, 0x0000, 0x03ff);
58 if (r != EP_SET) {
59 return -1;
60 }
61 *address = addressl;
62
63 found = 0;
64 while (*valid_addrs != 0x0000) {
65
66 if (*address == *valid_addrs) {
67 found = 1;
68 break;
69 }
70
71 valid_addrs++;
72 }
73
74 if (!found) {
75 return 1;
76 }
77
78 return 0;
79 }
80
81 endpoint_t
i2cdriver_bus_endpoint(uint32_t bus)82 i2cdriver_bus_endpoint(uint32_t bus)
83 {
84 /* locate the driver for the i2c bus itself */
85 int r;
86 const char *label_prefix = "i2c.";
87 char label[DS_MAX_KEYLEN];
88 endpoint_t bus_endpoint;
89
90 snprintf(label, DS_MAX_KEYLEN, "%s%d", label_prefix, bus);
91
92 r = ds_retrieve_label_endpt(label, &bus_endpoint);
93 if (r != OK) {
94 return 0;
95 }
96
97 return bus_endpoint;
98 }
99
100 int
i2cdriver_subscribe_bus_updates(uint32_t bus)101 i2cdriver_subscribe_bus_updates(uint32_t bus)
102 {
103 int r;
104 char regex[DS_MAX_KEYLEN];
105
106 /* only capture events for the specified bus */
107 snprintf(regex, DS_MAX_KEYLEN, "drv\\.chr\\.i2c\\.%d", bus);
108
109 /* Subscribe to driver events from the i2c bus */
110 r = ds_subscribe(regex, DSF_INITIAL | DSF_OVERWRITE);
111 if (r != OK) {
112 return r;
113 }
114
115 return OK;
116 }
117
118 void
i2cdriver_handle_bus_update(endpoint_t * bus_endpoint,uint32_t bus,i2c_addr_t address)119 i2cdriver_handle_bus_update(endpoint_t * bus_endpoint, uint32_t bus,
120 i2c_addr_t address)
121 {
122 char key[DS_MAX_KEYLEN];
123 u32_t value;
124 int type;
125 endpoint_t owner_endpoint, old_endpoint;
126 int r;
127
128 /* check for pending events */
129 while ((r = ds_check(key, &type, &owner_endpoint)) == OK) {
130
131 r = ds_retrieve_u32(key, &value);
132 if (r != OK) {
133 return;
134 }
135
136 if (value == DS_DRIVER_UP) {
137 old_endpoint = *bus_endpoint;
138
139 /* look up the bus's (potentially new) endpoint */
140 *bus_endpoint = i2cdriver_bus_endpoint(bus);
141
142 /* was updated endpoint? */
143 if (old_endpoint != *bus_endpoint) {
144 /* re-reserve device to allow the driver to
145 * continue working, even through a manual
146 * down/up.
147 */
148 i2cdriver_reserve_device(*bus_endpoint,
149 address);
150 }
151 }
152 }
153 }
154
155 int
i2cdriver_reserve_device(endpoint_t bus_endpoint,i2c_addr_t address)156 i2cdriver_reserve_device(endpoint_t bus_endpoint, i2c_addr_t address)
157 {
158 int r;
159 message m;
160
161 m.m_type = BUSC_I2C_RESERVE;
162 m.m_li2cdriver_i2c_busc_i2c_reserve.addr = address;
163
164 r = ipc_sendrec(bus_endpoint, &m);
165 if (r != OK) {
166 return EIO;
167 }
168
169 return m.m_type; /* return reply code OK, EBUSY, EINVAL, etc. */
170 }
171
172 int
i2cdriver_exec(endpoint_t bus_endpoint,minix_i2c_ioctl_exec_t * ioctl_exec)173 i2cdriver_exec(endpoint_t bus_endpoint, minix_i2c_ioctl_exec_t * ioctl_exec)
174 {
175 int r;
176 message m;
177 cp_grant_id_t grant_nr;
178
179 grant_nr = cpf_grant_direct(bus_endpoint, (vir_bytes) ioctl_exec,
180 sizeof(minix_i2c_ioctl_exec_t), CPF_READ | CPF_WRITE);
181
182 memset(&m, '\0', sizeof(message));
183
184 m.m_type = BUSC_I2C_EXEC;
185 m.m_li2cdriver_i2c_busc_i2c_exec.grant = grant_nr;
186
187 r = ipc_sendrec(bus_endpoint, &m);
188 cpf_revoke(grant_nr);
189 if (r != OK) {
190 return EIO;
191 }
192
193 return m.m_type;
194 }
195
196 static int
__i2creg_read(endpoint_t bus_endpoint,i2c_addr_t address,uint8_t raw,uint8_t reg,uint32_t * val,size_t vallen)197 __i2creg_read(endpoint_t bus_endpoint, i2c_addr_t address, uint8_t raw,
198 uint8_t reg, uint32_t * val, size_t vallen)
199 {
200 uint32_t i;
201 int r;
202 minix_i2c_ioctl_exec_t ioctl_exec;
203
204 assert(val != NULL);
205 assert(vallen >= 1 && vallen <= 4);
206
207 memset(&ioctl_exec, '\0', sizeof(minix_i2c_ioctl_exec_t));
208
209 /* Read from chip */
210 ioctl_exec.iie_op = I2C_OP_READ_WITH_STOP;
211 ioctl_exec.iie_addr = address;
212
213 if (!raw) {
214 /* write the register address */
215 ioctl_exec.iie_cmd[0] = reg;
216 ioctl_exec.iie_cmdlen = 1;
217 }
218
219 /* read vallen bytes */
220 ioctl_exec.iie_buflen = vallen;
221
222 r = i2cdriver_exec(bus_endpoint, &ioctl_exec);
223 if (r != OK) {
224 return -1;
225 }
226
227 for (*val = 0, i = 0; i < vallen; i++) {
228 *val = ((*val) << 8) | ioctl_exec.iie_buf[i];
229 }
230
231 return OK;
232 }
233
234 int
i2creg_raw_read8(endpoint_t bus_endpoint,i2c_addr_t address,uint8_t * val)235 i2creg_raw_read8(endpoint_t bus_endpoint, i2c_addr_t address, uint8_t * val)
236 {
237 int r;
238 uint32_t val32;
239
240 r = __i2creg_read(bus_endpoint, address, 1, 0, &val32, 1);
241 *val = val32 & 0xff;
242
243 return r;
244 }
245
246 int
i2creg_read8(endpoint_t bus_endpoint,i2c_addr_t address,uint8_t reg,uint8_t * val)247 i2creg_read8(endpoint_t bus_endpoint, i2c_addr_t address, uint8_t reg,
248 uint8_t * val)
249 {
250 int r;
251 uint32_t val32;
252
253 r = __i2creg_read(bus_endpoint, address, 0, reg, &val32, 1);
254 *val = val32 & 0xff;
255
256 return r;
257 }
258
259 int
i2creg_read16(endpoint_t bus_endpoint,i2c_addr_t address,uint8_t reg,uint16_t * val)260 i2creg_read16(endpoint_t bus_endpoint, i2c_addr_t address, uint8_t reg,
261 uint16_t * val)
262 {
263 int r;
264 uint32_t val32;
265
266 r = __i2creg_read(bus_endpoint, address, 0, reg, &val32, 2);
267 *val = val32 & 0xffff;
268
269 return r;
270 }
271
272 int
i2creg_read24(endpoint_t bus_endpoint,i2c_addr_t address,uint8_t reg,uint32_t * val)273 i2creg_read24(endpoint_t bus_endpoint, i2c_addr_t address, uint8_t reg,
274 uint32_t * val)
275 {
276 return __i2creg_read(bus_endpoint, address, 0, reg, val, 3);
277 }
278
279 static int
__i2creg_write(endpoint_t bus_endpoint,i2c_addr_t address,uint8_t raw,uint8_t reg,uint8_t val)280 __i2creg_write(endpoint_t bus_endpoint, i2c_addr_t address, uint8_t raw,
281 uint8_t reg, uint8_t val)
282 {
283 int r;
284 minix_i2c_ioctl_exec_t ioctl_exec;
285
286 memset(&ioctl_exec, '\0', sizeof(minix_i2c_ioctl_exec_t));
287
288 /* Write to chip */
289 ioctl_exec.iie_op = I2C_OP_WRITE_WITH_STOP;
290 ioctl_exec.iie_addr = address;
291
292 if (raw) {
293 /* write just the value */
294 ioctl_exec.iie_buf[0] = val;
295 ioctl_exec.iie_buflen = 1;
296 } else {
297 /* write the register address and value */
298 ioctl_exec.iie_buf[0] = reg;
299 ioctl_exec.iie_buf[1] = val;
300 ioctl_exec.iie_buflen = 2;
301 }
302
303 r = i2cdriver_exec(bus_endpoint, &ioctl_exec);
304 if (r != OK) {
305 return -1;
306 }
307
308 return OK;
309 }
310
311 int
i2creg_write8(endpoint_t bus_endpoint,i2c_addr_t address,uint8_t reg,uint8_t val)312 i2creg_write8(endpoint_t bus_endpoint, i2c_addr_t address, uint8_t reg,
313 uint8_t val)
314 {
315 return __i2creg_write(bus_endpoint, address, 0, reg, val);
316 }
317
318 int
i2creg_raw_write8(endpoint_t bus_endpoint,i2c_addr_t address,uint8_t val)319 i2creg_raw_write8(endpoint_t bus_endpoint, i2c_addr_t address, uint8_t val)
320 {
321 return __i2creg_write(bus_endpoint, address, 1, 0, val);
322 }
323
324 int
i2creg_set_bits8(endpoint_t bus_endpoint,i2c_addr_t address,uint8_t reg,uint8_t bits)325 i2creg_set_bits8(endpoint_t bus_endpoint, i2c_addr_t address, uint8_t reg,
326 uint8_t bits)
327 {
328 int r;
329 uint8_t val;
330
331 r = i2creg_read8(bus_endpoint, address, reg, &val);
332 if (r != OK) {
333 return -1;
334 }
335
336 val |= bits;
337
338 r = i2creg_write8(bus_endpoint, address, reg, val);
339 if (r != OK) {
340 return -1;
341 }
342
343 return OK;
344 }
345
346 int
i2creg_clear_bits8(endpoint_t bus_endpoint,i2c_addr_t address,uint8_t reg,uint8_t bits)347 i2creg_clear_bits8(endpoint_t bus_endpoint, i2c_addr_t address, uint8_t reg,
348 uint8_t bits)
349 {
350 int r;
351 uint8_t val;
352
353 r = i2creg_read8(bus_endpoint, address, reg, &val);
354 if (r != OK) {
355 return -1;
356 }
357
358 val &= ~bits;
359
360 r = i2creg_write8(bus_endpoint, address, reg, val);
361 if (r != OK) {
362 return -1;
363 }
364
365 return OK;
366 }
367