xref: /minix3/minix/lib/libi2cdriver/i2cdriver.c (revision 41022be18241fb5c8cc01e14c238c7e5273a4a06)
1433d6423SLionel Sambuc /* This file contains device independent i2c device driver helpers. */
2433d6423SLionel Sambuc 
3433d6423SLionel Sambuc #include <assert.h>
4433d6423SLionel Sambuc #include <minix/drivers.h>
5433d6423SLionel Sambuc #include <minix/endpoint.h>
6433d6423SLionel Sambuc #include <minix/i2c.h>
7433d6423SLionel Sambuc #include <minix/i2cdriver.h>
8433d6423SLionel Sambuc #include <minix/ipc.h>
9433d6423SLionel Sambuc #include <minix/ds.h>
10433d6423SLionel Sambuc 
11433d6423SLionel Sambuc void
i2cdriver_announce(uint32_t bus)12433d6423SLionel Sambuc i2cdriver_announce(uint32_t bus)
13433d6423SLionel Sambuc {
14433d6423SLionel Sambuc 	/* Announce we are up after a fresh start or restart. */
15433d6423SLionel Sambuc 	int r;
16433d6423SLionel Sambuc 	char key[DS_MAX_KEYLEN];
17433d6423SLionel Sambuc 	char label[DS_MAX_KEYLEN];
1865f76edbSDavid van Moolenbroek 	const char *driver_prefix = "drv.i2c.";
19433d6423SLionel Sambuc 
20433d6423SLionel Sambuc 	/* Callers are allowed to use ipc_sendrec to communicate with drivers.
21433d6423SLionel Sambuc 	 * For this reason, there may blocked callers when a driver restarts.
22433d6423SLionel Sambuc 	 * Ask the kernel to unblock them (if any).
23433d6423SLionel Sambuc 	 */
24*41022be1SCristiano Giuffrida 	if ((r = sys_statectl(SYS_STATE_CLEAR_IPC_REFS, 0, 0)) != OK) {
25433d6423SLionel Sambuc 		panic("chardriver_init: sys_statectl failed: %d", r);
26433d6423SLionel Sambuc 	}
27433d6423SLionel Sambuc 
28433d6423SLionel Sambuc 	/* Publish a driver up event. */
29433d6423SLionel Sambuc 	r = ds_retrieve_label_name(label, sef_self());
30433d6423SLionel Sambuc 	if (r != OK) {
31433d6423SLionel Sambuc 		panic("unable to get own label: %d\n", r);
32433d6423SLionel Sambuc 	}
33433d6423SLionel Sambuc 	/* example key: drv.i2c.1.cat24c245.0x50 */
34433d6423SLionel Sambuc 	snprintf(key, DS_MAX_KEYLEN, "%s%d.%s", driver_prefix, bus, label);
35433d6423SLionel Sambuc 	r = ds_publish_u32(key, DS_DRIVER_UP, DSF_OVERWRITE);
36433d6423SLionel Sambuc 	if (r != OK) {
37433d6423SLionel Sambuc 		panic("unable to publish driver up event: %d\n", r);
38433d6423SLionel Sambuc 	}
39433d6423SLionel Sambuc }
40433d6423SLionel Sambuc 
41433d6423SLionel Sambuc int
i2cdriver_env_parse(uint32_t * bus,i2c_addr_t * address,i2c_addr_t * valid_addrs)42433d6423SLionel Sambuc i2cdriver_env_parse(uint32_t * bus, i2c_addr_t * address,
43433d6423SLionel Sambuc     i2c_addr_t * valid_addrs)
44433d6423SLionel Sambuc {
45433d6423SLionel Sambuc 	/* fill in bus and address with the values passed on the command line */
46433d6423SLionel Sambuc 	int r;
47433d6423SLionel Sambuc 	int found;
48433d6423SLionel Sambuc 	long int busl;
49433d6423SLionel Sambuc 	long int addressl;
50433d6423SLionel Sambuc 
51433d6423SLionel Sambuc 	r = env_parse("bus", "d", 0, &busl, 1, 3);
52433d6423SLionel Sambuc 	if (r != EP_SET) {
53433d6423SLionel Sambuc 		return -1;
54433d6423SLionel Sambuc 	}
55433d6423SLionel Sambuc 	*bus = (uint32_t) busl;
56433d6423SLionel Sambuc 
57433d6423SLionel Sambuc 	r = env_parse("address", "x", 0, &addressl, 0x0000, 0x03ff);
58433d6423SLionel Sambuc 	if (r != EP_SET) {
59433d6423SLionel Sambuc 		return -1;
60433d6423SLionel Sambuc 	}
61433d6423SLionel Sambuc 	*address = addressl;
62433d6423SLionel Sambuc 
63433d6423SLionel Sambuc 	found = 0;
64433d6423SLionel Sambuc 	while (*valid_addrs != 0x0000) {
65433d6423SLionel Sambuc 
66433d6423SLionel Sambuc 		if (*address == *valid_addrs) {
67433d6423SLionel Sambuc 			found = 1;
68433d6423SLionel Sambuc 			break;
69433d6423SLionel Sambuc 		}
70433d6423SLionel Sambuc 
71433d6423SLionel Sambuc 		valid_addrs++;
72433d6423SLionel Sambuc 	}
73433d6423SLionel Sambuc 
74433d6423SLionel Sambuc 	if (!found) {
75433d6423SLionel Sambuc 		return 1;
76433d6423SLionel Sambuc 	}
77433d6423SLionel Sambuc 
78433d6423SLionel Sambuc 	return 0;
79433d6423SLionel Sambuc }
80433d6423SLionel Sambuc 
81433d6423SLionel Sambuc endpoint_t
i2cdriver_bus_endpoint(uint32_t bus)82433d6423SLionel Sambuc i2cdriver_bus_endpoint(uint32_t bus)
83433d6423SLionel Sambuc {
84433d6423SLionel Sambuc 	/* locate the driver for the i2c bus itself */
85433d6423SLionel Sambuc 	int r;
8665f76edbSDavid van Moolenbroek 	const char *label_prefix = "i2c.";
87433d6423SLionel Sambuc 	char label[DS_MAX_KEYLEN];
88433d6423SLionel Sambuc 	endpoint_t bus_endpoint;
89433d6423SLionel Sambuc 
90433d6423SLionel Sambuc 	snprintf(label, DS_MAX_KEYLEN, "%s%d", label_prefix, bus);
91433d6423SLionel Sambuc 
92433d6423SLionel Sambuc 	r = ds_retrieve_label_endpt(label, &bus_endpoint);
93433d6423SLionel Sambuc 	if (r != OK) {
94433d6423SLionel Sambuc 		return 0;
95433d6423SLionel Sambuc 	}
96433d6423SLionel Sambuc 
97433d6423SLionel Sambuc 	return bus_endpoint;
98433d6423SLionel Sambuc }
99433d6423SLionel Sambuc 
100433d6423SLionel Sambuc int
i2cdriver_subscribe_bus_updates(uint32_t bus)101433d6423SLionel Sambuc i2cdriver_subscribe_bus_updates(uint32_t bus)
102433d6423SLionel Sambuc {
103433d6423SLionel Sambuc 	int r;
104433d6423SLionel Sambuc 	char regex[DS_MAX_KEYLEN];
105433d6423SLionel Sambuc 
106433d6423SLionel Sambuc 	/* only capture events for the specified bus */
107433d6423SLionel Sambuc 	snprintf(regex, DS_MAX_KEYLEN, "drv\\.chr\\.i2c\\.%d", bus);
108433d6423SLionel Sambuc 
109433d6423SLionel Sambuc 	/* Subscribe to driver events from the i2c bus */
110433d6423SLionel Sambuc 	r = ds_subscribe(regex, DSF_INITIAL | DSF_OVERWRITE);
111433d6423SLionel Sambuc 	if (r != OK) {
112433d6423SLionel Sambuc 		return r;
113433d6423SLionel Sambuc 	}
114433d6423SLionel Sambuc 
115433d6423SLionel Sambuc 	return OK;
116433d6423SLionel Sambuc }
117433d6423SLionel Sambuc 
118433d6423SLionel Sambuc void
i2cdriver_handle_bus_update(endpoint_t * bus_endpoint,uint32_t bus,i2c_addr_t address)119433d6423SLionel Sambuc i2cdriver_handle_bus_update(endpoint_t * bus_endpoint, uint32_t bus,
120433d6423SLionel Sambuc     i2c_addr_t address)
121433d6423SLionel Sambuc {
122433d6423SLionel Sambuc 	char key[DS_MAX_KEYLEN];
123433d6423SLionel Sambuc 	u32_t value;
124433d6423SLionel Sambuc 	int type;
125433d6423SLionel Sambuc 	endpoint_t owner_endpoint, old_endpoint;
126433d6423SLionel Sambuc 	int r;
127433d6423SLionel Sambuc 
128433d6423SLionel Sambuc 	/* check for pending events */
129433d6423SLionel Sambuc 	while ((r = ds_check(key, &type, &owner_endpoint)) == OK) {
130433d6423SLionel Sambuc 
131433d6423SLionel Sambuc 		r = ds_retrieve_u32(key, &value);
132433d6423SLionel Sambuc 		if (r != OK) {
133433d6423SLionel Sambuc 			return;
134433d6423SLionel Sambuc 		}
135433d6423SLionel Sambuc 
136433d6423SLionel Sambuc 		if (value == DS_DRIVER_UP) {
137433d6423SLionel Sambuc 			old_endpoint = *bus_endpoint;
138433d6423SLionel Sambuc 
139433d6423SLionel Sambuc 			/* look up the bus's (potentially new) endpoint */
140433d6423SLionel Sambuc 			*bus_endpoint = i2cdriver_bus_endpoint(bus);
141433d6423SLionel Sambuc 
142433d6423SLionel Sambuc 			/* was updated endpoint? */
143433d6423SLionel Sambuc 			if (old_endpoint != *bus_endpoint) {
144433d6423SLionel Sambuc 				/* re-reserve device to allow the driver to
145433d6423SLionel Sambuc 				 * continue working, even through a manual
146433d6423SLionel Sambuc 				 * down/up.
147433d6423SLionel Sambuc 				 */
148433d6423SLionel Sambuc 				i2cdriver_reserve_device(*bus_endpoint,
149433d6423SLionel Sambuc 				    address);
150433d6423SLionel Sambuc 			}
151433d6423SLionel Sambuc 		}
152433d6423SLionel Sambuc 	}
153433d6423SLionel Sambuc }
154433d6423SLionel Sambuc 
155433d6423SLionel Sambuc int
i2cdriver_reserve_device(endpoint_t bus_endpoint,i2c_addr_t address)156433d6423SLionel Sambuc i2cdriver_reserve_device(endpoint_t bus_endpoint, i2c_addr_t address)
157433d6423SLionel Sambuc {
158433d6423SLionel Sambuc 	int r;
159433d6423SLionel Sambuc 	message m;
160433d6423SLionel Sambuc 
161433d6423SLionel Sambuc 	m.m_type = BUSC_I2C_RESERVE;
162433d6423SLionel Sambuc 	m.m_li2cdriver_i2c_busc_i2c_reserve.addr = address;
163433d6423SLionel Sambuc 
164433d6423SLionel Sambuc 	r = ipc_sendrec(bus_endpoint, &m);
165433d6423SLionel Sambuc 	if (r != OK) {
166433d6423SLionel Sambuc 		return EIO;
167433d6423SLionel Sambuc 	}
168433d6423SLionel Sambuc 
169433d6423SLionel Sambuc 	return m.m_type;	/* return reply code OK, EBUSY, EINVAL, etc. */
170433d6423SLionel Sambuc }
171433d6423SLionel Sambuc 
172433d6423SLionel Sambuc int
i2cdriver_exec(endpoint_t bus_endpoint,minix_i2c_ioctl_exec_t * ioctl_exec)173433d6423SLionel Sambuc i2cdriver_exec(endpoint_t bus_endpoint, minix_i2c_ioctl_exec_t * ioctl_exec)
174433d6423SLionel Sambuc {
175433d6423SLionel Sambuc 	int r;
176433d6423SLionel Sambuc 	message m;
177433d6423SLionel Sambuc 	cp_grant_id_t grant_nr;
178433d6423SLionel Sambuc 
179433d6423SLionel Sambuc 	grant_nr = cpf_grant_direct(bus_endpoint, (vir_bytes) ioctl_exec,
180433d6423SLionel Sambuc 	    sizeof(minix_i2c_ioctl_exec_t), CPF_READ | CPF_WRITE);
181433d6423SLionel Sambuc 
182433d6423SLionel Sambuc 	memset(&m, '\0', sizeof(message));
183433d6423SLionel Sambuc 
184433d6423SLionel Sambuc 	m.m_type = BUSC_I2C_EXEC;
185433d6423SLionel Sambuc 	m.m_li2cdriver_i2c_busc_i2c_exec.grant = grant_nr;
186433d6423SLionel Sambuc 
187433d6423SLionel Sambuc 	r = ipc_sendrec(bus_endpoint, &m);
188433d6423SLionel Sambuc 	cpf_revoke(grant_nr);
189433d6423SLionel Sambuc 	if (r != OK) {
190433d6423SLionel Sambuc 		return EIO;
191433d6423SLionel Sambuc 	}
192433d6423SLionel Sambuc 
193433d6423SLionel Sambuc 	return m.m_type;
194433d6423SLionel Sambuc }
195433d6423SLionel Sambuc 
196433d6423SLionel Sambuc static int
__i2creg_read(endpoint_t bus_endpoint,i2c_addr_t address,uint8_t raw,uint8_t reg,uint32_t * val,size_t vallen)197433d6423SLionel Sambuc __i2creg_read(endpoint_t bus_endpoint, i2c_addr_t address, uint8_t raw,
198433d6423SLionel Sambuc     uint8_t reg, uint32_t * val, size_t vallen)
199433d6423SLionel Sambuc {
20065f76edbSDavid van Moolenbroek 	uint32_t i;
20165f76edbSDavid van Moolenbroek 	int r;
202433d6423SLionel Sambuc 	minix_i2c_ioctl_exec_t ioctl_exec;
203433d6423SLionel Sambuc 
204433d6423SLionel Sambuc 	assert(val != NULL);
205433d6423SLionel Sambuc 	assert(vallen >= 1 && vallen <= 4);
206433d6423SLionel Sambuc 
207433d6423SLionel Sambuc 	memset(&ioctl_exec, '\0', sizeof(minix_i2c_ioctl_exec_t));
208433d6423SLionel Sambuc 
209433d6423SLionel Sambuc 	/* Read from chip */
210433d6423SLionel Sambuc 	ioctl_exec.iie_op = I2C_OP_READ_WITH_STOP;
211433d6423SLionel Sambuc 	ioctl_exec.iie_addr = address;
212433d6423SLionel Sambuc 
213433d6423SLionel Sambuc 	if (!raw) {
214433d6423SLionel Sambuc 		/* write the register address */
215433d6423SLionel Sambuc 		ioctl_exec.iie_cmd[0] = reg;
216433d6423SLionel Sambuc 		ioctl_exec.iie_cmdlen = 1;
217433d6423SLionel Sambuc 	}
218433d6423SLionel Sambuc 
219433d6423SLionel Sambuc 	/* read vallen bytes */
220433d6423SLionel Sambuc 	ioctl_exec.iie_buflen = vallen;
221433d6423SLionel Sambuc 
222433d6423SLionel Sambuc 	r = i2cdriver_exec(bus_endpoint, &ioctl_exec);
223433d6423SLionel Sambuc 	if (r != OK) {
224433d6423SLionel Sambuc 		return -1;
225433d6423SLionel Sambuc 	}
226433d6423SLionel Sambuc 
227433d6423SLionel Sambuc 	for (*val = 0, i = 0; i < vallen; i++) {
228433d6423SLionel Sambuc 		*val = ((*val) << 8) | ioctl_exec.iie_buf[i];
229433d6423SLionel Sambuc 	}
230433d6423SLionel Sambuc 
231433d6423SLionel Sambuc 	return OK;
232433d6423SLionel Sambuc }
233433d6423SLionel Sambuc 
234433d6423SLionel Sambuc int
i2creg_raw_read8(endpoint_t bus_endpoint,i2c_addr_t address,uint8_t * val)235433d6423SLionel Sambuc i2creg_raw_read8(endpoint_t bus_endpoint, i2c_addr_t address, uint8_t * val)
236433d6423SLionel Sambuc {
237433d6423SLionel Sambuc 	int r;
238433d6423SLionel Sambuc 	uint32_t val32;
239433d6423SLionel Sambuc 
240433d6423SLionel Sambuc 	r = __i2creg_read(bus_endpoint, address, 1, 0, &val32, 1);
241433d6423SLionel Sambuc 	*val = val32 & 0xff;
242433d6423SLionel Sambuc 
243433d6423SLionel Sambuc 	return r;
244433d6423SLionel Sambuc }
245433d6423SLionel Sambuc 
246433d6423SLionel Sambuc int
i2creg_read8(endpoint_t bus_endpoint,i2c_addr_t address,uint8_t reg,uint8_t * val)247433d6423SLionel Sambuc i2creg_read8(endpoint_t bus_endpoint, i2c_addr_t address, uint8_t reg,
248433d6423SLionel Sambuc     uint8_t * val)
249433d6423SLionel Sambuc {
250433d6423SLionel Sambuc 	int r;
251433d6423SLionel Sambuc 	uint32_t val32;
252433d6423SLionel Sambuc 
253433d6423SLionel Sambuc 	r = __i2creg_read(bus_endpoint, address, 0, reg, &val32, 1);
254433d6423SLionel Sambuc 	*val = val32 & 0xff;
255433d6423SLionel Sambuc 
256433d6423SLionel Sambuc 	return r;
257433d6423SLionel Sambuc }
258433d6423SLionel Sambuc 
259433d6423SLionel Sambuc int
i2creg_read16(endpoint_t bus_endpoint,i2c_addr_t address,uint8_t reg,uint16_t * val)260433d6423SLionel Sambuc i2creg_read16(endpoint_t bus_endpoint, i2c_addr_t address, uint8_t reg,
261433d6423SLionel Sambuc     uint16_t * val)
262433d6423SLionel Sambuc {
263433d6423SLionel Sambuc 	int r;
264433d6423SLionel Sambuc 	uint32_t val32;
265433d6423SLionel Sambuc 
266433d6423SLionel Sambuc 	r = __i2creg_read(bus_endpoint, address, 0, reg, &val32, 2);
267433d6423SLionel Sambuc 	*val = val32 & 0xffff;
268433d6423SLionel Sambuc 
269433d6423SLionel Sambuc 	return r;
270433d6423SLionel Sambuc }
271433d6423SLionel Sambuc 
272433d6423SLionel Sambuc int
i2creg_read24(endpoint_t bus_endpoint,i2c_addr_t address,uint8_t reg,uint32_t * val)273433d6423SLionel Sambuc i2creg_read24(endpoint_t bus_endpoint, i2c_addr_t address, uint8_t reg,
274433d6423SLionel Sambuc     uint32_t * val)
275433d6423SLionel Sambuc {
276433d6423SLionel Sambuc 	return __i2creg_read(bus_endpoint, address, 0, reg, val, 3);
277433d6423SLionel Sambuc }
278433d6423SLionel Sambuc 
279433d6423SLionel Sambuc static int
__i2creg_write(endpoint_t bus_endpoint,i2c_addr_t address,uint8_t raw,uint8_t reg,uint8_t val)280433d6423SLionel Sambuc __i2creg_write(endpoint_t bus_endpoint, i2c_addr_t address, uint8_t raw,
281433d6423SLionel Sambuc     uint8_t reg, uint8_t val)
282433d6423SLionel Sambuc {
283433d6423SLionel Sambuc 	int r;
284433d6423SLionel Sambuc 	minix_i2c_ioctl_exec_t ioctl_exec;
285433d6423SLionel Sambuc 
286433d6423SLionel Sambuc 	memset(&ioctl_exec, '\0', sizeof(minix_i2c_ioctl_exec_t));
287433d6423SLionel Sambuc 
288433d6423SLionel Sambuc 	/* Write to chip */
289433d6423SLionel Sambuc 	ioctl_exec.iie_op = I2C_OP_WRITE_WITH_STOP;
290433d6423SLionel Sambuc 	ioctl_exec.iie_addr = address;
291433d6423SLionel Sambuc 
292433d6423SLionel Sambuc 	if (raw) {
293433d6423SLionel Sambuc 		/* write just the value */
294433d6423SLionel Sambuc 		ioctl_exec.iie_buf[0] = val;
295433d6423SLionel Sambuc 		ioctl_exec.iie_buflen = 1;
296433d6423SLionel Sambuc 	} else {
297433d6423SLionel Sambuc 		/* write the register address and value */
298433d6423SLionel Sambuc 		ioctl_exec.iie_buf[0] = reg;
299433d6423SLionel Sambuc 		ioctl_exec.iie_buf[1] = val;
300433d6423SLionel Sambuc 		ioctl_exec.iie_buflen = 2;
301433d6423SLionel Sambuc 	}
302433d6423SLionel Sambuc 
303433d6423SLionel Sambuc 	r = i2cdriver_exec(bus_endpoint, &ioctl_exec);
304433d6423SLionel Sambuc 	if (r != OK) {
305433d6423SLionel Sambuc 		return -1;
306433d6423SLionel Sambuc 	}
307433d6423SLionel Sambuc 
308433d6423SLionel Sambuc 	return OK;
309433d6423SLionel Sambuc }
310433d6423SLionel Sambuc 
311433d6423SLionel Sambuc int
i2creg_write8(endpoint_t bus_endpoint,i2c_addr_t address,uint8_t reg,uint8_t val)312433d6423SLionel Sambuc i2creg_write8(endpoint_t bus_endpoint, i2c_addr_t address, uint8_t reg,
313433d6423SLionel Sambuc     uint8_t val)
314433d6423SLionel Sambuc {
315433d6423SLionel Sambuc 	return __i2creg_write(bus_endpoint, address, 0, reg, val);
316433d6423SLionel Sambuc }
317433d6423SLionel Sambuc 
318433d6423SLionel Sambuc int
i2creg_raw_write8(endpoint_t bus_endpoint,i2c_addr_t address,uint8_t val)319433d6423SLionel Sambuc i2creg_raw_write8(endpoint_t bus_endpoint, i2c_addr_t address, uint8_t val)
320433d6423SLionel Sambuc {
321433d6423SLionel Sambuc 	return __i2creg_write(bus_endpoint, address, 1, 0, val);
322433d6423SLionel Sambuc }
323433d6423SLionel Sambuc 
324433d6423SLionel Sambuc int
i2creg_set_bits8(endpoint_t bus_endpoint,i2c_addr_t address,uint8_t reg,uint8_t bits)325433d6423SLionel Sambuc i2creg_set_bits8(endpoint_t bus_endpoint, i2c_addr_t address, uint8_t reg,
326433d6423SLionel Sambuc     uint8_t bits)
327433d6423SLionel Sambuc {
328433d6423SLionel Sambuc 	int r;
329433d6423SLionel Sambuc 	uint8_t val;
330433d6423SLionel Sambuc 
331433d6423SLionel Sambuc 	r = i2creg_read8(bus_endpoint, address, reg, &val);
332433d6423SLionel Sambuc 	if (r != OK) {
333433d6423SLionel Sambuc 		return -1;
334433d6423SLionel Sambuc 	}
335433d6423SLionel Sambuc 
336433d6423SLionel Sambuc 	val |= bits;
337433d6423SLionel Sambuc 
338433d6423SLionel Sambuc 	r = i2creg_write8(bus_endpoint, address, reg, val);
339433d6423SLionel Sambuc 	if (r != OK) {
340433d6423SLionel Sambuc 		return -1;
341433d6423SLionel Sambuc 	}
342433d6423SLionel Sambuc 
343433d6423SLionel Sambuc 	return OK;
344433d6423SLionel Sambuc }
345433d6423SLionel Sambuc 
346433d6423SLionel Sambuc int
i2creg_clear_bits8(endpoint_t bus_endpoint,i2c_addr_t address,uint8_t reg,uint8_t bits)347433d6423SLionel Sambuc i2creg_clear_bits8(endpoint_t bus_endpoint, i2c_addr_t address, uint8_t reg,
348433d6423SLionel Sambuc     uint8_t bits)
349433d6423SLionel Sambuc {
350433d6423SLionel Sambuc 	int r;
351433d6423SLionel Sambuc 	uint8_t val;
352433d6423SLionel Sambuc 
353433d6423SLionel Sambuc 	r = i2creg_read8(bus_endpoint, address, reg, &val);
354433d6423SLionel Sambuc 	if (r != OK) {
355433d6423SLionel Sambuc 		return -1;
356433d6423SLionel Sambuc 	}
357433d6423SLionel Sambuc 
358433d6423SLionel Sambuc 	val &= ~bits;
359433d6423SLionel Sambuc 
360433d6423SLionel Sambuc 	r = i2creg_write8(bus_endpoint, address, reg, val);
361433d6423SLionel Sambuc 	if (r != OK) {
362433d6423SLionel Sambuc 		return -1;
363433d6423SLionel Sambuc 	}
364433d6423SLionel Sambuc 
365433d6423SLionel Sambuc 	return OK;
366433d6423SLionel Sambuc }
367