xref: /illumos-gate/usr/src/lib/libi2c/common/libi2c.h (revision 32002227574cf0a435dc03de622191ca53724f0a)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2025 Oxide Computer Company
14  */
15 
16 #ifndef _LIBI2C_H
17 #define	_LIBI2C_H
18 
19 /*
20  * This file contains an evolving set of interfaces for dealing with i2c class
21  * devices in the system.
22  */
23 
24 #ifdef __cplusplus
25 extern "C" {
26 #endif
27 
28 #include <stdbool.h>
29 #include <libdevinfo.h>
30 #include <stdint.h>
31 #include <sys/i2c/i2c.h>
32 
33 typedef enum {
34 	I2C_ERR_OK	= 0,
35 	/*
36 	 * Indicates that a command issued to a controller failed for some
37 	 * reason. The driver's error is available through the i2c_ctrl_err()
38 	 * function.
39 	 */
40 	I2C_ERR_CONTROLLER,
41 	/*
42 	 * We were passed an invalid pointer argument for an argument.
43 	 */
44 	I2C_ERR_BAD_PTR,
45 	/*
46 	 * Indicates that there was a memory allocation error. The system error
47 	 * contains the specific errno.
48 	 */
49 	I2C_ERR_NO_MEM,
50 	/*
51 	 * Indicates that an error occurred while trying to use the devinfo
52 	 * library. The system error is generally populated for this (dependent
53 	 * on the underlying libdevinfo call).
54 	 */
55 	I2C_ERR_LIBDEVINFO,
56 	/*
57 	 * Indicates that the devinfo node we were given doesn't correspond to
58 	 * the correct type of i2c device.
59 	 */
60 	I2C_ERR_BAD_DEVI,
61 	/*
62 	 * Indicates that an internal error condition occurred.
63 	 */
64 	I2C_ERR_INTERNAL,
65 	/*
66 	 * Indicates that the caller did not contain sufficient privileges for
67 	 * a given operation.
68 	 */
69 	I2C_ERR_PRIVS,
70 	/*
71 	 * Indicates a failure to open a device file.
72 	 */
73 	I2C_ERR_OPEN_DEV,
74 	/*
75 	 * Indicates that a means of identify a controller, port, or device
76 	 * (name, instance, etc.) does not match the corresponding I2C entity.
77 	 * This can also happen when given a path that does not end at the
78 	 * expected component.
79 	 */
80 	I2C_ERR_BAD_CONTROLLER,
81 	I2C_ERR_BAD_PORT,
82 	I2C_ERR_BAD_DEVICE,
83 	/*
84 	 * Indicates that the address type is invalid or that the address is not
85 	 * a valid address.
86 	 */
87 	I2C_ERR_BAD_ADDR_TYPE,
88 	I2C_ERR_BAD_ADDR,
89 	/*
90 	 * Indicates that the requested address type is not supported by the
91 	 * controller.
92 	 */
93 	I2C_ERR_UNSUP_ADDR_TYPE,
94 	/*
95 	 * Indicates that the address could not be used because it is reserved.
96 	 */
97 	I2C_ERR_ADDR_RSVD,
98 	/*
99 	 * Indicates that the requested address is already in use.
100 	 */
101 	I2C_ERR_ADDR_IN_USE,
102 	/*
103 	 * Indicates that the requested address does not map to anything known.
104 	 */
105 	I2C_ERR_ADDR_UNKNOWN,
106 	/*
107 	 * Indicates that the I/O length is outside of the valid range for the
108 	 * request. The maximum SMBus 2.0 request is 32 bytes and SMBus 3.0 is
109 	 * 256 bytes. The maximum I2C request is similarly today 256 bytes.
110 	 */
111 	I2C_ERR_IO_READ_LEN_RANGE,
112 	I2C_ERR_IO_WRITE_LEN_RANGE,
113 	/*
114 	 * These two indicate general classes of issues with I/O requests. The
115 	 * first indicates that a given field has not been set. For example, an
116 	 * address or operation type. The second indicates that the combination
117 	 * of I/O is not supported. For example, a zero byte read and write.
118 	 */
119 	I2C_ERR_IO_REQ_MISSING_FIELDS,
120 	I2C_ERR_IO_REQ_IO_INVALID,
121 	/*
122 	 * Indicates that an I2C or SMBus request was submitted to a controller
123 	 * that does not support that protocol and the request could not be
124 	 * translated by the kernel.
125 	 */
126 	I2C_ERR_CANT_XLATE_IO_REQ,
127 	/*
128 	 * Indicates that the controller or the system does not support the
129 	 * requested SMBus operation.
130 	 */
131 	I2C_ERR_SMBUS_OP_UNSUP,
132 	/*
133 	 * Indicates that an attempt to take the controller lock would fail due
134 	 * to blocking or that a signal was taking, cancelling the operation,
135 	 * while waiting for the controller lock.
136 	 */
137 	I2C_ERR_LOCK_WAIT_SIGNAL,
138 	I2C_ERR_LOCK_WOULD_BLOCK,
139 	/*
140 	 * Indicates that the kernel did not have memory available to allocate
141 	 * on behalf of the caller.
142 	 */
143 	I2C_ERR_NO_KERN_MEM,
144 	/*
145 	 * Indicates that a string that is being used for a device name or
146 	 * compatible array contains illegal characters or is too long.
147 	 */
148 	I2C_ERR_BAD_DEV_NAME,
149 	/*
150 	 * Indicates that the length of the compatible range is longer than the
151 	 * system will allow to be set.
152 	 */
153 	I2C_ERR_COMPAT_LEN_RANGE,
154 	/*
155 	 * Indicates that some of the required fields are missing from a device
156 	 * add request.
157 	 */
158 	I2C_ERR_ADD_DEV_REQ_MISSING_FIELDS,
159 	/*
160 	 * Indicates that the I2C nexus had unexpected failures while trying to
161 	 * manipulate devices.
162 	 */
163 	I2C_ERR_NEXUS,
164 	/*
165 	 * Indicates that a library handle was used across multiple threads
166 	 * incorrectly (a handle should only be used by one thread at a time)
167 	 * and the kernel noted that an operation was already ongoing.
168 	 */
169 	I2C_ERR_OP_IN_PROGRESS,
170 	/*
171 	 * Indicates that the property is known to the system, but it is
172 	 * unsupported by the device.
173 	 */
174 	I2C_ERR_PROP_UNSUP,
175 	/*
176 	 * Indicates that the property name or id is not known to the system.
177 	 */
178 	I2C_ERR_BAD_PROP,
179 	/*
180 	 * Indicates that the property cannot be set because the controller does
181 	 * not support setting properties. This is followed by the controller
182 	 * (or system) indicating that the property is read-only.
183 	 */
184 	I2C_ERR_SET_PROP_UNSUP,
185 	I2C_ERR_PROP_READ_ONLY,
186 	/*
187 	 * These indicate that the property buffer is too small and too large
188 	 * respectively. This only fires on setting a property.
189 	 */
190 	I2C_ERR_PROP_BUF_TOO_SMALL,
191 	I2C_ERR_PROP_BUF_TOO_BIG,
192 	/*
193 	 * Indicates that the property value is invalid.
194 	 */
195 	I2C_ERR_BAD_PROP_VAL,
196 	/*
197 	 * Indicates that there is no default value available.
198 	 */
199 	I2C_ERR_NO_PROP_DEF_VAL,
200 	/*
201 	 * Indicates that the function used to get a value from a property
202 	 * didn't match the type of the data.
203 	 */
204 	I2C_ERR_PROP_TYPE_MISMATCH,
205 	/*
206 	 * Indicates that a user buffer argument is too small for the resulting
207 	 * string transformation.
208 	 */
209 	I2C_ERR_BUF_TOO_SMALL,
210 } i2c_err_t;
211 
212 typedef struct i2c_hdl i2c_hdl_t;
213 typedef struct i2c_ctrl i2c_ctrl_t;
214 typedef struct i2c_ctrl_iter i2c_ctrl_iter_t;
215 typedef struct i2c_ctrl_disc i2c_ctrl_disc_t;
216 typedef struct i2c_prop_info i2c_prop_info_t;
217 typedef struct i2c_port i2c_port_t;
218 typedef struct i2c_port_iter i2c_port_iter_t;
219 typedef struct i2c_port_disc i2c_port_disc_t;
220 typedef struct i2c_port_map i2c_port_map_t;
221 typedef struct i2c_dev_iter i2c_dev_iter_t;
222 typedef struct i2c_dev_disc i2c_dev_disc_t;
223 typedef struct i2c_dev_info i2c_dev_info_t;
224 typedef struct i2c_dev_add_req i2c_dev_add_req_t;
225 typedef struct i2c_mux_iter i2c_mux_iter_t;
226 typedef struct i2c_mux_disc i2c_mux_disc_t;
227 typedef struct i2c_io_req i2c_io_req_t;
228 typedef struct smbus_io_req smbus_io_req_t;
229 
230 typedef enum i2c_iter {
231 	I2C_ITER_VALID,
232 	I2C_ITER_DONE,
233 	I2C_ITER_ERROR
234 } i2c_iter_t;
235 
236 extern i2c_hdl_t *i2c_init(void);
237 extern void i2c_fini(i2c_hdl_t *);
238 
239 /*
240  * Error Information. Each handle (and objects created from it) has a single
241  * error and should only be used from one thread at any given time. An error can
242  * be a semantic error or a specific class of I/O error.
243  */
244 extern i2c_err_t i2c_err(i2c_hdl_t *);
245 extern i2c_ctrl_error_t i2c_ctrl_err(i2c_hdl_t *);
246 extern int32_t i2c_syserr(i2c_hdl_t *);
247 extern const char *i2c_errmsg(i2c_hdl_t *);
248 extern const char *i2c_errtostr(i2c_hdl_t *, i2c_err_t);
249 extern const char *i2c_ctrl_errtostr(i2c_hdl_t *, i2c_ctrl_error_t);
250 
251 /*
252  * Discover and initialize i2c controllers.
253  *
254  * Information that is obtained during discovery should only be considered to
255  * last as long as you are handling its relative discovery entry point. This
256  * includes the devinfo entities.
257  */
258 extern bool i2c_ctrl_discover_init(i2c_hdl_t *, i2c_ctrl_iter_t **);
259 extern i2c_iter_t i2c_ctrl_discover_step(i2c_ctrl_iter_t *,
260     const i2c_ctrl_disc_t **);
261 extern void i2c_ctrl_discover_fini(i2c_ctrl_iter_t *);
262 typedef bool (*i2c_ctrl_disc_f)(i2c_hdl_t *, const i2c_ctrl_disc_t *, void *);
263 extern bool i2c_ctrl_discover(i2c_hdl_t *, i2c_ctrl_disc_f, void *);
264 
265 extern di_node_t i2c_ctrl_disc_devi(const i2c_ctrl_disc_t *);
266 extern di_minor_t i2c_ctrl_disc_minor(const i2c_ctrl_disc_t *);
267 
268 extern bool i2c_ctrl_init(i2c_hdl_t *, di_node_t, i2c_ctrl_t **);
269 extern bool i2c_ctrl_init_by_path(i2c_hdl_t *, const char *, i2c_ctrl_t **);
270 extern void i2c_ctrl_fini(i2c_ctrl_t *);
271 extern i2c_hdl_t *i2c_ctrl_hdl(i2c_ctrl_t *);
272 extern const char *i2c_ctrl_name(i2c_ctrl_t *);
273 extern const char *i2c_ctrl_path(i2c_ctrl_t *);
274 extern int32_t i2c_ctrl_instance(i2c_ctrl_t *);
275 extern uint32_t i2c_ctrl_nprops(i2c_ctrl_t *);
276 
277 /*
278  * Controller property information. Note, there are no discovery APIs right now
279  * as all properties are currently part of the framework. The system will return
280  * information about all known properties. If the property is not supported by
281  * the controller, then only a subset of information will be valid: the id,
282  * type, and name.
283  */
284 extern const char *i2c_prop_info_name(i2c_prop_info_t *);
285 extern i2c_prop_t i2c_prop_info_id(i2c_prop_info_t *);
286 extern i2c_prop_type_t i2c_prop_info_type(i2c_prop_info_t *);
287 extern bool i2c_prop_info_sup(i2c_prop_info_t *);
288 extern i2c_prop_perm_t i2c_prop_info_perm(i2c_prop_info_t *);
289 extern bool i2c_prop_info_def_u32(i2c_prop_info_t *, uint32_t *);
290 extern const i2c_prop_range_t *i2c_prop_info_pos(i2c_prop_info_t *);
291 extern bool i2c_prop_info(i2c_ctrl_t *, i2c_prop_t, i2c_prop_info_t **);
292 extern bool i2c_prop_info_by_name(i2c_ctrl_t *, const char *,
293     i2c_prop_info_t **);
294 extern void i2c_prop_info_free(i2c_prop_info_t *);
295 
296 /*
297  * Get and set a property value.
298  */
299 extern bool i2c_prop_get(i2c_ctrl_t *, i2c_prop_t, void *, size_t *);
300 extern bool i2c_prop_set(i2c_ctrl_t *, i2c_prop_t, const void *, size_t);
301 
302 /*
303  * Port discovery.
304  */
305 extern bool i2c_port_discover_init(i2c_hdl_t *, i2c_port_iter_t **);
306 extern i2c_iter_t i2c_port_discover_step(i2c_port_iter_t *,
307     const i2c_port_disc_t **);
308 extern void i2c_port_discover_fini(i2c_port_iter_t *);
309 typedef bool (*i2c_port_disc_f)(i2c_hdl_t *, const i2c_port_disc_t *, void *);
310 extern bool i2c_port_discover(i2c_hdl_t *, i2c_port_disc_f, void *);
311 
312 extern di_node_t i2c_port_disc_devi(const i2c_port_disc_t *);
313 extern const char *i2c_port_disc_path(const i2c_port_disc_t *);
314 
315 extern bool i2c_port_init(i2c_hdl_t *, di_node_t, i2c_port_t **);
316 extern bool i2c_port_init_by_path(i2c_hdl_t *, const char *, i2c_port_t **);
317 extern void i2c_port_fini(i2c_port_t *);
318 extern const char *i2c_port_name(i2c_port_t *);
319 extern const char *i2c_port_path(i2c_port_t *);
320 extern uint32_t i2c_port_portno(i2c_port_t *);
321 typedef enum {
322 	I2C_PORT_TYPE_CTRL,
323 	I2C_PORT_TYPE_MUX
324 } i2c_port_type_t;
325 extern i2c_port_type_t i2c_port_type(i2c_port_t *);
326 
327 /*
328  * The port map provides information about all the addresses that are in use
329  * from this port's perspective. This is a point in time snapshot that is taken
330  * when the function is called. From there, information about a given address
331  * can be inquired.
332  */
333 extern bool i2c_port_map_snap(i2c_port_t *, i2c_port_map_t **);
334 extern void i2c_port_map_free(i2c_port_map_t *);
335 
336 extern void i2c_port_map_ndevs(const i2c_port_map_t *, uint32_t *, uint32_t *);
337 extern bool i2c_port_map_addr_info(const i2c_port_map_t *, const i2c_addr_t *,
338     uint32_t *, bool *, major_t *);
339 
340 /*
341  * Request to add a device under the given port. This is used to add the
342  * specified device into the tree under the given port (whether a controller or
343  * mux). This will create a device and attempt to bind a driver to it. It will
344  * also be accessible for user access.
345  */
346 extern bool i2c_device_add_req_init(i2c_port_t *, i2c_dev_add_req_t **);
347 extern void i2c_device_add_req_fini(i2c_dev_add_req_t *);
348 
349 extern bool i2c_device_add_req_set_addr(i2c_dev_add_req_t *,
350     const i2c_addr_t *);
351 extern bool i2c_device_add_req_set_name(i2c_dev_add_req_t *, const char *);
352 extern bool i2c_device_add_req_set_compatible(i2c_dev_add_req_t *,
353     char *const *, size_t);
354 extern bool i2c_device_add_req_exec(i2c_dev_add_req_t *);
355 
356 /*
357  * Remove a device, specified by address, that is directly under the given port.
358  */
359 extern bool i2c_device_rem(i2c_port_t *, const i2c_addr_t *);
360 
361 /*
362  * Discover devices.
363  *
364  * This returns information about devices that are known to the system. It does
365  * not go out and attempt to perform I/O to devices or try to infer what a
366  * device is based on the results of a scan.
367  */
368 extern bool i2c_device_discover_init(i2c_hdl_t *, i2c_dev_iter_t **);
369 extern i2c_iter_t i2c_device_discover_step(i2c_dev_iter_t *,
370     const i2c_dev_disc_t **);
371 extern void i2c_device_discover_fini(i2c_dev_iter_t *);
372 typedef bool (*i2c_dev_disc_f)(i2c_hdl_t *, const i2c_dev_disc_t *, void *);
373 extern bool i2c_device_discover(i2c_hdl_t *, i2c_dev_disc_f, void *);
374 
375 extern const char *i2c_device_disc_name(const i2c_dev_disc_t *);
376 extern const char *i2c_device_disc_path(const i2c_dev_disc_t *);
377 
378 extern di_node_t i2c_device_disc_devi(const i2c_dev_disc_t *);
379 extern di_minor_t i2c_device_disc_devctl(const i2c_dev_disc_t *);
380 
381 /*
382  * Get a snapshot of information about a device and its addresses.
383  */
384 extern bool i2c_device_info_snap(i2c_hdl_t *, di_node_t, i2c_dev_info_t **);
385 extern void i2c_device_info_free(i2c_dev_info_t *);
386 
387 extern const char *i2c_device_info_path(const i2c_dev_info_t *);
388 extern const char *i2c_device_info_name(const i2c_dev_info_t *);
389 extern const char *i2c_device_info_driver(const i2c_dev_info_t *);
390 extern int i2c_device_info_instance(const i2c_dev_info_t *);
391 extern uint32_t i2c_device_info_naddrs(const i2c_dev_info_t *);
392 extern const i2c_addr_t *i2c_device_info_addr(const i2c_dev_info_t *, uint32_t);
393 extern i2c_addr_source_t i2c_device_info_addr_source(const i2c_dev_info_t *,
394     uint32_t);
395 extern const i2c_addr_t *i2c_device_info_addr_primary(const i2c_dev_info_t *);
396 
397 /*
398  * Discover muxes.
399  */
400 extern bool i2c_mux_discover_init(i2c_hdl_t *, i2c_mux_iter_t **);
401 extern i2c_iter_t i2c_mux_discover_step(i2c_mux_iter_t *,
402     const i2c_mux_disc_t **);
403 extern void i2c_mux_discover_fini(i2c_mux_iter_t *);
404 typedef bool (*i2c_mux_disc_f)(i2c_hdl_t *, const i2c_mux_disc_t *, void *);
405 extern bool i2c_mux_discover(i2c_hdl_t *, i2c_mux_disc_f, void *);
406 
407 extern const char *i2c_mux_disc_name(const i2c_mux_disc_t *);
408 extern const char *i2c_mux_disc_path(const i2c_mux_disc_t *);
409 extern uint32_t i2c_mux_disc_nports(const i2c_mux_disc_t *);
410 extern di_node_t i2c_mux_disc_devi(const i2c_mux_disc_t *);
411 extern di_minor_t i2c_mux_disc_devctl(const i2c_mux_disc_t *);
412 
413 /*
414  * Perform I/O on a device from userland. I/O can be specific to a device, in
415  * which case an address is not required, or it can be specific to a port. When
416  * targeting a port, then an address is required; however, if the port is a port
417  * of a multiplexor, then all of the muxes will be implicitly activated to
418  * perform that I/O.
419  *
420  * I/O requests come in two different forms, an I2C style request and an SMBus
421  * style request. The system will translate between the two depending on the
422  * controllers capabilities.
423  */
424 extern bool i2c_io_req_init(i2c_port_t *, i2c_io_req_t **);
425 extern void i2c_io_req_fini(i2c_io_req_t *);
426 
427 extern bool i2c_io_req_set_addr(i2c_io_req_t *, const i2c_addr_t *);
428 extern bool i2c_io_req_set_transmit_data(i2c_io_req_t *, const void *, size_t);
429 extern bool i2c_io_req_set_receive_buf(i2c_io_req_t *, void *, size_t);
430 extern bool i2c_io_req_exec(i2c_io_req_t *);
431 
432 extern bool smbus_io_req_init(i2c_port_t *, smbus_io_req_t  **);
433 extern void smbus_io_req_fini(smbus_io_req_t *);
434 
435 extern bool smbus_io_req_set_addr(smbus_io_req_t *, const i2c_addr_t *);
436 extern bool smbus_io_req_set_quick_cmd(smbus_io_req_t *, bool);
437 extern bool smbus_io_req_set_send_byte(smbus_io_req_t *, uint8_t);
438 extern bool smbus_io_req_set_write_u8(smbus_io_req_t *, uint8_t, uint8_t);
439 extern bool smbus_io_req_set_write_u16(smbus_io_req_t *, uint8_t, uint16_t);
440 extern bool smbus_io_req_set_write_u32(smbus_io_req_t *, uint8_t, uint32_t);
441 extern bool smbus_io_req_set_write_u64(smbus_io_req_t *, uint8_t, uint64_t);
442 extern bool smbus_io_req_set_write_block(smbus_io_req_t *, uint8_t,
443     const void *, size_t, bool);
444 extern bool smbus_io_req_set_recv_byte(smbus_io_req_t *, uint8_t *);
445 extern bool smbus_io_req_set_read_u8(smbus_io_req_t *, uint8_t, uint8_t *);
446 extern bool smbus_io_req_set_read_u16(smbus_io_req_t *, uint8_t, uint16_t *);
447 extern bool smbus_io_req_set_read_u32(smbus_io_req_t *, uint8_t, uint32_t *);
448 extern bool smbus_io_req_set_read_u64(smbus_io_req_t *, uint8_t, uint64_t *);
449 extern bool smbus_io_req_set_read_block_i2c(smbus_io_req_t *, uint8_t, void *,
450     size_t);
451 extern bool smbus_io_req_set_process_call(smbus_io_req_t *, uint8_t, uint16_t,
452     uint16_t *);
453 extern bool smbus_io_req_exec(smbus_io_req_t *);
454 
455 /*
456  * I2C address classification routines. Note, i2c_addr_reserved() only returns
457  * true if the address is reserved. If the address is invalid, it will return
458  * false as well.
459  */
460 extern bool i2c_addr_reserved(const i2c_addr_t *);
461 
462 /*
463  * Initialize information about a port and device based on the path. If the bool
464  * is set to true, then we're allowed to return with just a port and no device
465  * information due to the path ending at a port.
466  */
467 extern bool i2c_port_dev_init_by_path(i2c_hdl_t *, const char *, bool,
468     i2c_port_t **, i2c_dev_info_t **);
469 
470 /*
471  * Utility functions to parse and transform an i2c_addr_t.
472  */
473 extern bool i2c_addr_parse(i2c_hdl_t *, const char *, i2c_addr_t *);
474 extern bool i2c_addr_to_string(i2c_hdl_t *, const i2c_addr_t *, char *, size_t);
475 
476 #ifdef __cplusplus
477 }
478 #endif
479 
480 #endif /* _LIBI2C_H */
481