xref: /minix/minix/lib/libi2cdriver/i2cdriver.c (revision 0a6a1f1d)
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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