1 /* This file contains device independent i2c device driver helpers. */
4 #include <minix/drivers.h>
5 #include <minix/endpoint.h>
7 #include <minix/i2cdriver.h>
12 i2cdriver_announce(uint32_t bus
)
14 /* Announce we are up after a fresh start or restart. */
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());
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
);
37 panic("unable to publish driver up event: %d\n", r
);
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 */
51 r
= env_parse("bus", "d", 0, &busl
, 1, 3);
55 *bus
= (uint32_t) busl
;
57 r
= env_parse("address", "x", 0, &addressl
, 0x0000, 0x03ff);
64 while (*valid_addrs
!= 0x0000) {
66 if (*address
== *valid_addrs
) {
82 i2cdriver_bus_endpoint(uint32_t bus
)
84 /* locate the driver for the i2c bus itself */
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
);
101 i2cdriver_subscribe_bus_updates(uint32_t bus
)
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
);
119 i2cdriver_handle_bus_update(endpoint_t
* bus_endpoint
, uint32_t bus
,
122 char key
[DS_MAX_KEYLEN
];
125 endpoint_t owner_endpoint
, old_endpoint
;
128 /* check for pending events */
129 while ((r
= ds_check(key
, &type
, &owner_endpoint
)) == OK
) {
131 r
= ds_retrieve_u32(key
, &value
);
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
148 i2cdriver_reserve_device(*bus_endpoint
,
156 i2cdriver_reserve_device(endpoint_t bus_endpoint
, i2c_addr_t address
)
161 m
.m_type
= BUSC_I2C_RESERVE
;
162 m
.m_li2cdriver_i2c_busc_i2c_reserve
.addr
= address
;
164 r
= ipc_sendrec(bus_endpoint
, &m
);
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
)
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
);
197 __i2creg_read(endpoint_t bus_endpoint
, i2c_addr_t address
, uint8_t raw
,
198 uint8_t reg
, uint32_t * val
, size_t vallen
)
202 minix_i2c_ioctl_exec_t ioctl_exec
;
205 assert(vallen
>= 1 && vallen
<= 4);
207 memset(&ioctl_exec
, '\0', sizeof(minix_i2c_ioctl_exec_t
));
210 ioctl_exec
.iie_op
= I2C_OP_READ_WITH_STOP
;
211 ioctl_exec
.iie_addr
= address
;
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
);
227 for (*val
= 0, i
= 0; i
< vallen
; i
++) {
228 *val
= ((*val
) << 8) | ioctl_exec
.iie_buf
[i
];
235 i2creg_raw_read8(endpoint_t bus_endpoint
, i2c_addr_t address
, uint8_t * val
)
240 r
= __i2creg_read(bus_endpoint
, address
, 1, 0, &val32
, 1);
247 i2creg_read8(endpoint_t bus_endpoint
, i2c_addr_t address
, uint8_t reg
,
253 r
= __i2creg_read(bus_endpoint
, address
, 0, reg
, &val32
, 1);
260 i2creg_read16(endpoint_t bus_endpoint
, i2c_addr_t address
, uint8_t reg
,
266 r
= __i2creg_read(bus_endpoint
, address
, 0, reg
, &val32
, 2);
267 *val
= val32
& 0xffff;
273 i2creg_read24(endpoint_t bus_endpoint
, i2c_addr_t address
, uint8_t reg
,
276 return __i2creg_read(bus_endpoint
, address
, 0, reg
, val
, 3);
280 __i2creg_write(endpoint_t bus_endpoint
, i2c_addr_t address
, uint8_t raw
,
281 uint8_t reg
, uint8_t val
)
284 minix_i2c_ioctl_exec_t ioctl_exec
;
286 memset(&ioctl_exec
, '\0', sizeof(minix_i2c_ioctl_exec_t
));
289 ioctl_exec
.iie_op
= I2C_OP_WRITE_WITH_STOP
;
290 ioctl_exec
.iie_addr
= address
;
293 /* write just the value */
294 ioctl_exec
.iie_buf
[0] = val
;
295 ioctl_exec
.iie_buflen
= 1;
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
);
312 i2creg_write8(endpoint_t bus_endpoint
, i2c_addr_t address
, uint8_t reg
,
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
,
331 r
= i2creg_read8(bus_endpoint
, address
, reg
, &val
);
338 r
= i2creg_write8(bus_endpoint
, address
, reg
, val
);
347 i2creg_clear_bits8(endpoint_t bus_endpoint
, i2c_addr_t address
, uint8_t reg
,
353 r
= i2creg_read8(bus_endpoint
, address
, reg
, &val
);
360 r
= i2creg_write8(bus_endpoint
, address
, reg
, val
);