xref: /illumos-gate/usr/src/uts/common/sys/i2c/client.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 _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