xref: /illumos-gate/usr/src/uts/common/io/i2c/nexus/i2cnex_util.c (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 /*
17  * This file contains misc. utility functions.
18  */
19 
20 #include <sys/ddi.h>
21 #include <sys/sunddi.h>
22 
23 #include "i2cnex.h"
24 
25 void
i2c_port_parent_iter(i2c_port_t * port,i2c_port_f func,void * arg)26 i2c_port_parent_iter(i2c_port_t *port, i2c_port_f func, void *arg)
27 {
28 	for (i2c_nexus_t *nex = port->ip_nex->in_pnex; nex != NULL;
29 	    nex = nex->in_pnex) {
30 		if (nex->in_type != I2C_NEXUS_T_PORT)
31 			continue;
32 		if (!func(nex->in_data.in_port, arg))
33 			return;
34 	}
35 }
36 
37 void
i2c_port_iter(i2c_port_t * port,i2c_port_f func,void * arg)38 i2c_port_iter(i2c_port_t *port, i2c_port_f func, void *arg)
39 {
40 	for (i2c_nexus_t *nex = port->ip_nex; nex != NULL; nex = nex->in_pnex) {
41 		if (nex->in_type != I2C_NEXUS_T_PORT)
42 			continue;
43 		if (!func(nex->in_data.in_port, arg))
44 			return;
45 	}
46 }
47 
48 bool
i2c_dip_is_dev(dev_info_t * dip)49 i2c_dip_is_dev(dev_info_t *dip)
50 {
51 	bool ret;
52 	char *dtype;
53 
54 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
55 	    "device_type", &dtype) != DDI_PROP_SUCCESS) {
56 		return (false);
57 	}
58 
59 	ret = strcmp(dtype, "i2c");
60 	ddi_prop_free(dtype);
61 	return (ret == 0);
62 }
63 
64 /*
65  * This translates a device to a dip. It should already have been validated as
66  * being an i2c type device. This should panic rather than fail as it means a
67  * programmer error has occurred and something bad is going to happen.
68  */
69 i2c_nexus_t *
i2c_dev_to_nexus(dev_info_t * dip)70 i2c_dev_to_nexus(dev_info_t *dip)
71 {
72 	i2c_nexus_t *nex;
73 
74 	VERIFY(i2c_dip_is_dev(dip));
75 	nex = ddi_get_parent_data(dip);
76 	VERIFY3P(nex, !=, NULL);
77 	VERIFY3U(nex->in_type, ==, I2C_NEXUS_T_DEV);
78 	VERIFY3P(nex->in_dip, ==, dip);
79 
80 	return (nex);
81 }
82 
83 /*
84  * This is a variant of error setting that is intended for use by controllers
85  * drivers. We also have a separate one for muxes and the main internal ones as
86  * well. We opt to use different signatures for internal vs. external functions
87  * and for each device type so we retain a bit of flexibility at the cost of
88  * minor duplication.
89  *
90  * i2c_ctrl_*: For controllers.
91  * i2c_io_*: For muxes and other device types that are both providers and
92  * consumers.
93  * i2c_error/i2c_success: Internal use in the driver.
94  */
95 void
i2c_ctrl_io_success(i2c_error_t * ep)96 i2c_ctrl_io_success(i2c_error_t *ep)
97 {
98 	ep->i2c_error = I2C_CORE_E_OK;
99 	ep->i2c_ctrl = I2C_CTRL_E_OK;
100 }
101 
102 void
i2c_ctrl_io_error(i2c_error_t * ep,i2c_errno_t err,i2c_ctrl_error_t ctrl)103 i2c_ctrl_io_error(i2c_error_t *ep, i2c_errno_t err, i2c_ctrl_error_t ctrl)
104 {
105 	ep->i2c_error = err;
106 	ep->i2c_ctrl = ctrl;
107 }
108 
109 bool
i2c_io_error(i2c_error_t * errp,i2c_errno_t err,i2c_ctrl_error_t ctrl)110 i2c_io_error(i2c_error_t *errp, i2c_errno_t err, i2c_ctrl_error_t ctrl)
111 {
112 	i2c_ctrl_io_error(errp, err, ctrl);
113 	return (false);
114 }
115 
116 bool
i2c_error(i2c_error_t * ioc,i2c_errno_t err,i2c_ctrl_error_t ctrl)117 i2c_error(i2c_error_t *ioc, i2c_errno_t err, i2c_ctrl_error_t ctrl)
118 {
119 	ioc->i2c_error = err;
120 	ioc->i2c_ctrl = ctrl;
121 
122 	return (false);
123 }
124 
125 void
i2c_success(i2c_error_t * ioc)126 i2c_success(i2c_error_t *ioc)
127 {
128 	ioc->i2c_error = I2C_CORE_E_OK;
129 	ioc->i2c_ctrl = I2C_CTRL_E_OK;
130 }
131