xref: /illumos-gate/usr/src/uts/common/sys/i2c/client.h (revision 32002227574cf0a435dc03de622191ca53724f0a)
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