Sun Jan 24 19:35:21 2021 UTC ()
trailing whitespace


(jmcneill)
diff -r1.1 -r1.2 src/sys/dev/i2c/i2cmux.c

cvs diff -r1.1 -r1.2 src/sys/dev/i2c/i2cmux.c (switch to unified diff)

--- src/sys/dev/i2c/i2cmux.c 2020/12/28 20:29:57 1.1
+++ src/sys/dev/i2c/i2cmux.c 2021/01/24 19:35:21 1.2
@@ -1,228 +1,228 @@ @@ -1,228 +1,228 @@
1/* $NetBSD: i2cmux.c,v 1.1 2020/12/28 20:29:57 thorpej Exp $ */ 1/* $NetBSD: i2cmux.c,v 1.2 2021/01/24 19:35:21 jmcneill Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2020 The NetBSD Foundation, Inc. 4 * Copyright (c) 2020 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe. 8 * by Jason R. Thorpe.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright 15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the 16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution. 17 * documentation and/or other materials provided with the distribution.
18 *  18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.  29 * POSSIBILITY OF SUCH DAMAGE.
30 */  30 */
31 31
32#include <sys/cdefs.h> 32#include <sys/cdefs.h>
33__KERNEL_RCSID(0, "$NetBSD: i2cmux.c,v 1.1 2020/12/28 20:29:57 thorpej Exp $"); 33__KERNEL_RCSID(0, "$NetBSD: i2cmux.c,v 1.2 2021/01/24 19:35:21 jmcneill Exp $");
34 34
35#include <sys/types.h> 35#include <sys/types.h>
36#include <sys/device.h> 36#include <sys/device.h>
37#include <sys/kernel.h> 37#include <sys/kernel.h>
38#include <sys/kmem.h>  38#include <sys/kmem.h>
39 39
40#include <dev/fdt/fdtvar.h> 40#include <dev/fdt/fdtvar.h>
41#include <dev/i2c/i2cvar.h> 41#include <dev/i2c/i2cvar.h>
42#include <dev/i2c/i2cmuxvar.h> 42#include <dev/i2c/i2cmuxvar.h>
43 43
44/*  44/*
45 * i2c mux  45 * i2c mux
46 *  46 *
47 * This works by interposing a set of virtual controllers behind the real 47 * This works by interposing a set of virtual controllers behind the real
48 * i2c controller. We provide our own acquire and release functions that 48 * i2c controller. We provide our own acquire and release functions that
49 * perform the following tasks: 49 * perform the following tasks:
50 *  50 *
51 * acquire -> acquire parent controller, program mux 51 * acquire -> acquire parent controller, program mux
52 *  52 *
53 * release -> idle mux, release parent controller 53 * release -> idle mux, release parent controller
54 *  54 *
55 * All of the actual I/O operations are transparently passed through. 55 * All of the actual I/O operations are transparently passed through.
56 *  56 *
57 * N.B. the locking order; the generic I2C layer has already acquired  57 * N.B. the locking order; the generic I2C layer has already acquired
58 * our virtual controller's mutex before calling our acquire function, 58 * our virtual controller's mutex before calling our acquire function,
59 * and we will then acquire the real controller's mutex when we acquire  59 * and we will then acquire the real controller's mutex when we acquire
60 * the bus, so the order is: 60 * the bus, so the order is:
61 *  61 *
62 * mux virtual controller -> parent controller 62 * mux virtual controller -> parent controller
63 * 63 *
64 * These are common routines used by various i2c mux controller 64 * These are common routines used by various i2c mux controller
65 * implementations (gpio, pin mux, i2c device, etc.). 65 * implementations (gpio, pin mux, i2c device, etc.).
66 */  66 */
67 67
68/*****************************************************************************/ 68/*****************************************************************************/
69 69
70static int 70static int
71iicmux_acquire_bus(void * const v, int const flags) 71iicmux_acquire_bus(void * const v, int const flags)
72{ 72{
73 struct iicmux_bus * const bus = v; 73 struct iicmux_bus * const bus = v;
74 struct iicmux_softc * const sc = bus->mux; 74 struct iicmux_softc * const sc = bus->mux;
75 int error; 75 int error;
76 76
77 error = iic_acquire_bus(sc->sc_i2c_parent, flags); 77 error = iic_acquire_bus(sc->sc_i2c_parent, flags);
78 if (error) { 78 if (error) {
79 return error; 79 return error;
80 } 80 }
81 81
82 error = sc->sc_config->acquire_bus(bus, flags); 82 error = sc->sc_config->acquire_bus(bus, flags);
83 if (error) { 83 if (error) {
84 iic_release_bus(sc->sc_i2c_parent, flags); 84 iic_release_bus(sc->sc_i2c_parent, flags);
85 } 85 }
86 86
87 return error; 87 return error;
88} 88}
89 89
90static void 90static void
91iicmux_release_bus(void * const v, int const flags) 91iicmux_release_bus(void * const v, int const flags)
92{ 92{
93 struct iicmux_bus * const bus = v; 93 struct iicmux_bus * const bus = v;
94 struct iicmux_softc * const sc = bus->mux; 94 struct iicmux_softc * const sc = bus->mux;
95 95
96 sc->sc_config->release_bus(bus, flags); 96 sc->sc_config->release_bus(bus, flags);
97 iic_release_bus(sc->sc_i2c_parent, flags); 97 iic_release_bus(sc->sc_i2c_parent, flags);
98} 98}
99 99
100static int 100static int
101iicmux_exec(void * const v, i2c_op_t const op, i2c_addr_t const addr, 101iicmux_exec(void * const v, i2c_op_t const op, i2c_addr_t const addr,
102 const void * const cmdbuf, size_t const cmdlen, void * const databuf, 102 const void * const cmdbuf, size_t const cmdlen, void * const databuf,
103 size_t const datalen, int const flags) 103 size_t const datalen, int const flags)
104{ 104{
105 struct iicmux_bus * const bus = v; 105 struct iicmux_bus * const bus = v;
106 struct iicmux_softc * const sc = bus->mux; 106 struct iicmux_softc * const sc = bus->mux;
107 107
108 return iic_exec(sc->sc_i2c_parent, op, addr, cmdbuf, cmdlen, 108 return iic_exec(sc->sc_i2c_parent, op, addr, cmdbuf, cmdlen,
109 databuf, datalen, flags); 109 databuf, datalen, flags);
110} 110}
111 111
112/*****************************************************************************/ 112/*****************************************************************************/
113 113
114static int 114static int
115iicmux_count_children(struct iicmux_softc * const sc) 115iicmux_count_children(struct iicmux_softc * const sc)
116{ 116{
117 char name[32]; 117 char name[32];
118 int child, count; 118 int child, count;
119 119
120 restart: 120 restart:
121 for (child = OF_child(sc->sc_i2c_mux_phandle), count = 0; child; 121 for (child = OF_child(sc->sc_i2c_mux_phandle), count = 0; child;
122 child = OF_peer(child)) { 122 child = OF_peer(child)) {
123 if (OF_getprop(child, "name", name, sizeof(name)) <= 0) { 123 if (OF_getprop(child, "name", name, sizeof(name)) <= 0) {
124 continue; 124 continue;
125 } 125 }
126 if (strcmp(name, "i2c-mux") == 0) { 126 if (strcmp(name, "i2c-mux") == 0) {
127 /* 127 /*
128 * The node we encountered is the acutal parent 128 * The node we encountered is the acutal parent
129 * of the i2c bus children. Stash its phandle 129 * of the i2c bus children. Stash its phandle
130 * and restart the enumeration. 130 * and restart the enumeration.
131 */ 131 */
132 sc->sc_i2c_mux_phandle = child; 132 sc->sc_i2c_mux_phandle = child;
133 goto restart; 133 goto restart;
134 } 134 }
135 count++; 135 count++;
136 } 136 }
137 137
138 return count; 138 return count;
139} 139}
140 140
141/* XXX iicbus_print() should be able to do this. */ 141/* XXX iicbus_print() should be able to do this. */
142static int 142static int
143iicmux_print(void * const aux, const char * const pnp) 143iicmux_print(void * const aux, const char * const pnp)
144{  144{
145 i2c_tag_t const tag = aux; 145 i2c_tag_t const tag = aux;
146 struct iicmux_bus * const bus = tag->ic_cookie; 146 struct iicmux_bus * const bus = tag->ic_cookie;
147 int rv; 147 int rv;
148 148
149 rv = iicbus_print(aux, pnp); 149 rv = iicbus_print(aux, pnp);
150 aprint_normal(" bus %d", bus->busidx); 150 aprint_normal(" bus %d", bus->busidx);
151 151
152 return rv; 152 return rv;
153} 153}
154 154
155static void  155static void
156iicmux_attach_bus(struct iicmux_softc * const sc, 156iicmux_attach_bus(struct iicmux_softc * const sc,
157 int const phandle, int const busidx) 157 int const phandle, int const busidx)
158{ 158{
159 struct iicmux_bus * const bus = &sc->sc_busses[busidx]; 159 struct iicmux_bus * const bus = &sc->sc_busses[busidx];
160 160
161 bus->mux = sc; 161 bus->mux = sc;
162 bus->busidx = busidx; 162 bus->busidx = busidx;
163 bus->phandle = phandle; 163 bus->phandle = phandle;
164 164
165 bus->bus_data = sc->sc_config->get_bus_info(bus); 165 bus->bus_data = sc->sc_config->get_bus_info(bus);
166 if (bus->bus_data == NULL) { 166 if (bus->bus_data == NULL) {
167 aprint_error_dev(sc->sc_dev, 167 aprint_error_dev(sc->sc_dev,
168 "unable to get info for bus %d\n", busidx); 168 "unable to get info for bus %d\n", busidx);
169 return; 169 return;
170 } 170 }
171 171
172 iic_tag_init(&bus->controller); 172 iic_tag_init(&bus->controller);
173 bus->controller.ic_cookie = bus; 173 bus->controller.ic_cookie = bus;
174 bus->controller.ic_acquire_bus = iicmux_acquire_bus; 174 bus->controller.ic_acquire_bus = iicmux_acquire_bus;
175 bus->controller.ic_release_bus = iicmux_release_bus; 175 bus->controller.ic_release_bus = iicmux_release_bus;
176 bus->controller.ic_exec = iicmux_exec; 176 bus->controller.ic_exec = iicmux_exec;
177 177
178 fdtbus_register_i2c_controller(&bus->controller, bus->phandle); 178 fdtbus_register_i2c_controller(&bus->controller, bus->phandle);
179 179
180 fdtbus_attach_i2cbus(sc->sc_dev, bus->phandle, &bus->controller, 180 fdtbus_attach_i2cbus(sc->sc_dev, bus->phandle, &bus->controller,
181 iicmux_print); 181 iicmux_print);
182} 182}
183 183
184void 184void
185iicmux_attach(struct iicmux_softc * const sc) 185iicmux_attach(struct iicmux_softc * const sc)
186{ 186{
187 187
188 /* 188 /*
189 * We expect sc->sc_phandle, sc->sc_config, and sc->sc_i2c_parent 189 * We expect sc->sc_phandle, sc->sc_config, and sc->sc_i2c_parent
190 * to be initialized by the front-end. 190 * to be initialized by the front-end.
191 */ 191 */
192 KASSERT(sc->sc_phandle > 0); 192 KASSERT(sc->sc_phandle > 0);
193 KASSERT(sc->sc_config != NULL); 193 KASSERT(sc->sc_config != NULL);
194 KASSERT(sc->sc_i2c_parent != NULL); 194 KASSERT(sc->sc_i2c_parent != NULL);
195 195
196 /* 196 /*
197 * We start out assuming that the i2c bus nodes are children of 197 * We start out assuming that the i2c bus nodes are children of
198 * our own node. We'll adjust later if we encounter an "i2c-mux" 198 * our own node. We'll adjust later if we encounter an "i2c-mux"
199 * node when counting our children. If we encounter such a node, 199 * node when counting our children. If we encounter such a node,
200 * then it's that node that is the parent of the i2c bus children. 200 * then it's that node that is the parent of the i2c bus children.
201 */ 201 */
202 sc->sc_i2c_mux_phandle = sc->sc_phandle; 202 sc->sc_i2c_mux_phandle = sc->sc_phandle;
203 203
204 /* 204 /*
205 * Gather up all of the various bits of information needed 205 * Gather up all of the various bits of information needed
206 * for this particular type of i2c mux. 206 * for this particular type of i2c mux.
207 */ 207 */
208 sc->sc_mux_data = sc->sc_config->get_mux_info(sc); 208 sc->sc_mux_data = sc->sc_config->get_mux_info(sc);
209 if (sc->sc_mux_data == NULL) { 209 if (sc->sc_mux_data == NULL) {
210 aprint_error_dev(sc->sc_dev, "unable to get info for mux\n"); 210 aprint_error_dev(sc->sc_dev, "unable to get info for mux\n");
211 return; 211 return;
212 } 212 }
213 213
214 sc->sc_nbusses = iicmux_count_children(sc); 214 sc->sc_nbusses = iicmux_count_children(sc);
215 if (sc->sc_nbusses == 0) { 215 if (sc->sc_nbusses == 0) {
216 return; 216 return;
217 } 217 }
218 218
219 sc->sc_busses = kmem_zalloc(sizeof(*sc->sc_busses) * sc->sc_nbusses, 219 sc->sc_busses = kmem_zalloc(sizeof(*sc->sc_busses) * sc->sc_nbusses,
220 KM_SLEEP); 220 KM_SLEEP);
221 221
222 int child, idx; 222 int child, idx;
223 for (child = OF_child(sc->sc_i2c_mux_phandle), idx = 0; child; 223 for (child = OF_child(sc->sc_i2c_mux_phandle), idx = 0; child;
224 child = OF_peer(child), idx++) { 224 child = OF_peer(child), idx++) {
225 KASSERT(idx < sc->sc_nbusses); 225 KASSERT(idx < sc->sc_nbusses);
226 iicmux_attach_bus(sc, child, idx); 226 iicmux_attach_bus(sc, child, idx);
227 } 227 }
228} 228}