Drop main() prototype. Syncs with NetBSD-8
[minix.git] / minix / lib / libi2cdriver / i2cdriver.c
blob0aca71db3b9438d2e24c932f8d421c153895112b
1 /* This file contains device independent i2c device driver helpers. */
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>
11 void
12 i2cdriver_announce(uint32_t bus)
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.";
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).
24 if ((r = sys_statectl(SYS_STATE_CLEAR_IPC_REFS, 0, 0)) != OK) {
25 panic("chardriver_init: sys_statectl failed: %d", r);
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);
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);
41 int
42 i2cdriver_env_parse(uint32_t * bus, i2c_addr_t * address,
43 i2c_addr_t * valid_addrs)
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;
51 r = env_parse("bus", "d", 0, &busl, 1, 3);
52 if (r != EP_SET) {
53 return -1;
55 *bus = (uint32_t) busl;
57 r = env_parse("address", "x", 0, &addressl, 0x0000, 0x03ff);
58 if (r != EP_SET) {
59 return -1;
61 *address = addressl;
63 found = 0;
64 while (*valid_addrs != 0x0000) {
66 if (*address == *valid_addrs) {
67 found = 1;
68 break;
71 valid_addrs++;
74 if (!found) {
75 return 1;
78 return 0;
81 endpoint_t
82 i2cdriver_bus_endpoint(uint32_t bus)
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;
90 snprintf(label, DS_MAX_KEYLEN, "%s%d", label_prefix, bus);
92 r = ds_retrieve_label_endpt(label, &bus_endpoint);
93 if (r != OK) {
94 return 0;
97 return bus_endpoint;
101 i2cdriver_subscribe_bus_updates(uint32_t bus)
103 int r;
104 char regex[DS_MAX_KEYLEN];
106 /* only capture events for the specified bus */
107 snprintf(regex, DS_MAX_KEYLEN, "drv\\.chr\\.i2c\\.%d", bus);
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;
115 return OK;
118 void
119 i2cdriver_handle_bus_update(endpoint_t * bus_endpoint, uint32_t bus,
120 i2c_addr_t address)
122 char key[DS_MAX_KEYLEN];
123 u32_t value;
124 int type;
125 endpoint_t owner_endpoint, old_endpoint;
126 int r;
128 /* check for pending events */
129 while ((r = ds_check(key, &type, &owner_endpoint)) == OK) {
131 r = ds_retrieve_u32(key, &value);
132 if (r != OK) {
133 return;
136 if (value == DS_DRIVER_UP) {
137 old_endpoint = *bus_endpoint;
139 /* look up the bus's (potentially new) endpoint */
140 *bus_endpoint = i2cdriver_bus_endpoint(bus);
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.
148 i2cdriver_reserve_device(*bus_endpoint,
149 address);
156 i2cdriver_reserve_device(endpoint_t bus_endpoint, i2c_addr_t address)
158 int r;
159 message m;
161 m.m_type = BUSC_I2C_RESERVE;
162 m.m_li2cdriver_i2c_busc_i2c_reserve.addr = address;
164 r = ipc_sendrec(bus_endpoint, &m);
165 if (r != OK) {
166 return EIO;
169 return m.m_type; /* return reply code OK, EBUSY, EINVAL, etc. */
173 i2cdriver_exec(endpoint_t bus_endpoint, minix_i2c_ioctl_exec_t * ioctl_exec)
175 int r;
176 message m;
177 cp_grant_id_t grant_nr;
179 grant_nr = cpf_grant_direct(bus_endpoint, (vir_bytes) ioctl_exec,
180 sizeof(minix_i2c_ioctl_exec_t), CPF_READ | CPF_WRITE);
182 memset(&m, '\0', sizeof(message));
184 m.m_type = BUSC_I2C_EXEC;
185 m.m_li2cdriver_i2c_busc_i2c_exec.grant = grant_nr;
187 r = ipc_sendrec(bus_endpoint, &m);
188 cpf_revoke(grant_nr);
189 if (r != OK) {
190 return EIO;
193 return m.m_type;
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)
200 uint32_t i;
201 int r;
202 minix_i2c_ioctl_exec_t ioctl_exec;
204 assert(val != NULL);
205 assert(vallen >= 1 && vallen <= 4);
207 memset(&ioctl_exec, '\0', sizeof(minix_i2c_ioctl_exec_t));
209 /* Read from chip */
210 ioctl_exec.iie_op = I2C_OP_READ_WITH_STOP;
211 ioctl_exec.iie_addr = address;
213 if (!raw) {
214 /* write the register address */
215 ioctl_exec.iie_cmd[0] = reg;
216 ioctl_exec.iie_cmdlen = 1;
219 /* read vallen bytes */
220 ioctl_exec.iie_buflen = vallen;
222 r = i2cdriver_exec(bus_endpoint, &ioctl_exec);
223 if (r != OK) {
224 return -1;
227 for (*val = 0, i = 0; i < vallen; i++) {
228 *val = ((*val) << 8) | ioctl_exec.iie_buf[i];
231 return OK;
235 i2creg_raw_read8(endpoint_t bus_endpoint, i2c_addr_t address, uint8_t * val)
237 int r;
238 uint32_t val32;
240 r = __i2creg_read(bus_endpoint, address, 1, 0, &val32, 1);
241 *val = val32 & 0xff;
243 return r;
247 i2creg_read8(endpoint_t bus_endpoint, i2c_addr_t address, uint8_t reg,
248 uint8_t * val)
250 int r;
251 uint32_t val32;
253 r = __i2creg_read(bus_endpoint, address, 0, reg, &val32, 1);
254 *val = val32 & 0xff;
256 return r;
260 i2creg_read16(endpoint_t bus_endpoint, i2c_addr_t address, uint8_t reg,
261 uint16_t * val)
263 int r;
264 uint32_t val32;
266 r = __i2creg_read(bus_endpoint, address, 0, reg, &val32, 2);
267 *val = val32 & 0xffff;
269 return r;
273 i2creg_read24(endpoint_t bus_endpoint, i2c_addr_t address, uint8_t reg,
274 uint32_t * val)
276 return __i2creg_read(bus_endpoint, address, 0, reg, val, 3);
279 static int
280 __i2creg_write(endpoint_t bus_endpoint, i2c_addr_t address, uint8_t raw,
281 uint8_t reg, uint8_t val)
283 int r;
284 minix_i2c_ioctl_exec_t ioctl_exec;
286 memset(&ioctl_exec, '\0', sizeof(minix_i2c_ioctl_exec_t));
288 /* Write to chip */
289 ioctl_exec.iie_op = I2C_OP_WRITE_WITH_STOP;
290 ioctl_exec.iie_addr = address;
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;
303 r = i2cdriver_exec(bus_endpoint, &ioctl_exec);
304 if (r != OK) {
305 return -1;
308 return OK;
312 i2creg_write8(endpoint_t bus_endpoint, i2c_addr_t address, uint8_t reg,
313 uint8_t val)
315 return __i2creg_write(bus_endpoint, address, 0, reg, val);
319 i2creg_raw_write8(endpoint_t bus_endpoint, i2c_addr_t address, uint8_t val)
321 return __i2creg_write(bus_endpoint, address, 1, 0, val);
325 i2creg_set_bits8(endpoint_t bus_endpoint, i2c_addr_t address, uint8_t reg,
326 uint8_t bits)
328 int r;
329 uint8_t val;
331 r = i2creg_read8(bus_endpoint, address, reg, &val);
332 if (r != OK) {
333 return -1;
336 val |= bits;
338 r = i2creg_write8(bus_endpoint, address, reg, val);
339 if (r != OK) {
340 return -1;
343 return OK;
347 i2creg_clear_bits8(endpoint_t bus_endpoint, i2c_addr_t address, uint8_t reg,
348 uint8_t bits)
350 int r;
351 uint8_t val;
353 r = i2creg_read8(bus_endpoint, address, reg, &val);
354 if (r != OK) {
355 return -1;
358 val &= ~bits;
360 r = i2creg_write8(bus_endpoint, address, reg, val);
361 if (r != OK) {
362 return -1;
365 return OK;