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