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 _SYS_I2C_CLIENT_H 17 #define _SYS_I2C_CLIENT_H 18 19 /* 20 * I2C client device driver interface 21 */ 22 23 #include <sys/devops.h> 24 #include <sys/stdint.h> 25 #include <sys/stdbool.h> 26 #include <sys/i2c/i2c.h> 27 #include <sys/sensors.h> 28 29 #ifdef __cplusplus 30 extern "C" { 31 #endif 32 33 typedef struct i2c_client i2c_client_t; 34 typedef struct i2c_reg_hdl i2c_reg_hdl_t; 35 typedef struct i2c_txn i2c_txn_t; 36 37 /* 38 * Initialize a new I2C client that refers to the specified dev_info_t's 39 * register property to target a specific address. Each client is independent. 40 * Note, these calls all assume dip is the caller's dip. If it is not the 41 * caller's dip, then the caller must ensure that they have a hold on 42 * dev_info_t. Currently, this is not meant to be used as an LDI style 43 * interface. 44 */ 45 extern i2c_errno_t i2c_client_init(dev_info_t *, uint32_t, i2c_client_t **); 46 extern void i2c_client_destroy(i2c_client_t *); 47 48 /* 49 * Some devices may need access to addresses that they don't exclusively own or 50 * are missing from their reg[] property. This provides a means to get access to 51 * this address. For an exclusive address, no one must have it already. For a 52 * shared address, it is claimable if it is free or it is already owned by 53 * another instance of the calling driver. Multiple drivers cannot own a shared 54 * address. If the address is already in reg[], then this acts just like 55 * i2c_client_init(). 56 */ 57 typedef enum { 58 /* 59 * If specified, indicates that the address is shared across multiple 60 * devices. If not specified, this address will be unique to the device. 61 */ 62 I2C_CLAIM_F_SHARED = 1 << 0 63 } i2c_claim_flags_t; 64 65 extern i2c_errno_t i2c_client_claim_addr(dev_info_t *, const i2c_addr_t *, 66 i2c_claim_flags_t, i2c_client_t **); 67 68 /* 69 * Obtain the address that corresponds to a client. 70 */ 71 extern const i2c_addr_t *i2c_client_addr(i2c_client_t *); 72 73 /* 74 * There are many times when multiple operations need to be performed on the bus 75 * in a row without intervening traffic. Control of the bus is represented by an 76 * 'i2c_txn_t'. This is passed along to all I/O operations to indicate and track 77 * that the bus is owned. Similarly, this also blocks other operations on the 78 * controller / bus such as the getting and setting of properties. These holds 79 * are not intended to be long-lived due to the nature of them. 80 * 81 * Operations are not required to have an explicit hold in this way. If one 82 * passes NULL for the 'i2c_txn_t *' argument to any of the I/O functions, then 83 * the operation will take and release a bus hold for the duration of its 84 * operation as only one request can be active on the bus at any time. 85 */ 86 87 typedef enum { 88 I2C_BUS_LOCK_F_NONBLOCK = 1 << 0 89 } i2c_bus_lock_flags_t; 90 91 extern i2c_errno_t i2c_bus_lock(i2c_client_t *, i2c_bus_lock_flags_t, 92 i2c_txn_t **); 93 extern void i2c_bus_unlock(i2c_txn_t *); 94 95 /* 96 * Current version of the register access structure. The register access 97 * functions are intended to be a way to more easily access standard device 98 * registers. 99 */ 100 #define I2C_REG_ACC_ATTR_V0 0 101 102 typedef struct i2c_reg_acc_attr { 103 /* 104 * Specifies the current version of the attribute structure. This should 105 * be I2C_REG_ACC_ATTR_V0. 106 */ 107 uint16_t i2cacc_version; 108 /* 109 * Set as zero for now. 110 */ 111 uint16_t i2cacc_flags; 112 /* 113 * Indicates the length in bytes of the addresses and registers. 114 */ 115 uint8_t i2cacc_addr_len; 116 uint8_t i2cacc_reg_len; 117 /* 118 * These are the standard DDI swapping attributes (e.g. 119 * DDI_NEVERSWAP_ACC). These can be left at their default for a 1 byte 120 * value. For 2 byte values this must be set to either to the BE or LE 121 * access. 122 */ 123 uint8_t i2cacc_addr_endian; 124 uint8_t i2cacc_reg_endian; 125 /* 126 * The maximum valid address (inclusive) on the device. 127 */ 128 uint64_t i2cacc_addr_max; 129 } i2c_reg_acc_attr_t; 130 131 extern i2c_errno_t i2c_reg_handle_init(i2c_client_t *, 132 const i2c_reg_acc_attr_t *, i2c_reg_hdl_t **); 133 extern void i2c_reg_handle_destroy(i2c_reg_hdl_t *); 134 135 /* 136 * Read and write device registers from the requested address. This will read 137 * the specified number of registers from the device and assumes that i2c 138 * addresses auto-increment. The size is the size of the data buffer. It must be 139 * an even multiple of the number of registers that one wishes to read or write. 140 */ 141 extern bool i2c_reg_get(i2c_txn_t *, i2c_reg_hdl_t *, uint64_t, void *, 142 uint32_t, i2c_error_t *); 143 extern bool i2c_reg_put(i2c_txn_t *, i2c_reg_hdl_t *, uint64_t, const void *, 144 uint32_t, i2c_error_t *); 145 146 /* 147 * Operations to get at the maximums that a client can read, write, or otherwise 148 * perform. Currently we have plumbed through the ones that drivers have needed 149 * to date. As most things are encouraged to use the register interface. When 150 * they don't they are using small 1-2 byte SMBus read and write APIs that are 151 * easy to translate. We should feel free to add ways to get at the underlying 152 * controller limits if we find it useful. 153 */ 154 extern uint32_t i2c_reg_max_read(i2c_reg_hdl_t *); 155 extern uint32_t i2c_reg_max_write(i2c_reg_hdl_t *); 156 157 /* 158 * These are SMBus aliases for devices where that makes sense versus the general 159 * register interface. More can be added here based on driver need. 160 */ 161 extern bool smbus_client_send_byte(i2c_txn_t *, i2c_client_t *, uint8_t, 162 i2c_error_t *); 163 extern bool smbus_client_write_u8(i2c_txn_t *, i2c_client_t *, uint8_t, uint8_t, 164 i2c_error_t *); 165 extern bool smbus_client_write_u16(i2c_txn_t *, i2c_client_t *, uint8_t, 166 uint16_t, i2c_error_t *); 167 extern bool smbus_client_recv_byte(i2c_txn_t *, i2c_client_t *, uint8_t *, 168 i2c_error_t *); 169 extern bool smbus_client_read_u8(i2c_txn_t *, i2c_client_t *, uint8_t, 170 uint8_t *, i2c_error_t *); 171 extern bool smbus_client_read_u16(i2c_txn_t *, i2c_client_t *, uint8_t, 172 uint16_t *, i2c_error_t *); 173 174 extern const char *i2c_client_errtostr(i2c_client_t *, i2c_errno_t); 175 extern const char *i2c_client_ctrl_errtostr(i2c_client_t *, i2c_ctrl_error_t); 176 177 /* 178 * This is a conveience routine for ksensor creation. 179 */ 180 extern int i2c_client_ksensor_create_scalar(i2c_client_t *, uint64_t, 181 const ksensor_ops_t *, void *, const char *, id_t *); 182 183 #ifdef __cplusplus 184 } 185 #endif 186 187 #endif /* _SYS_I2C_CLIENT_H */ 188