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