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