1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2019 Ian Lepore <ian@freebsd.org> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 31 #include "opt_platform.h" 32 33 #include <sys/param.h> 34 #include <sys/bus.h> 35 #include <sys/kernel.h> 36 #include <sys/module.h> 37 #include <sys/sysctl.h> 38 39 #ifdef FDT 40 #include <dev/ofw/ofw_bus.h> 41 #include <dev/ofw/ofw_bus_subr.h> 42 #include <dev/ofw/openfirm.h> 43 #endif 44 45 #include <dev/iicbus/iiconf.h> 46 #include "iicbus_if.h" 47 #include "iicmux_if.h" 48 #include "iicmux.h" 49 50 /*------------------------------------------------------------------------------ 51 * iicbus methods, called by the iicbus functions in iiconf.c. 52 * 53 * All these functions return an IIC adapter-layer error code (because we are 54 * pretending to be a host bridge/i2c controller). Standard errno values 55 * returned from these must be encoded using iic2errno(). 56 *----------------------------------------------------------------------------*/ 57 58 static int 59 iicmux_callback(device_t dev, int index, caddr_t data) 60 { 61 struct iicmux_softc *sc = device_get_softc(dev); 62 struct iic_reqbus_data *rd; 63 int err, i; 64 65 /* If it's not one of the operations we know about, bail early. */ 66 if (index != IIC_REQUEST_BUS && index != IIC_RELEASE_BUS) 67 return (iic2errno(EOPNOTSUPP)); 68 69 /* 70 * Ensure that the data passed to us includes the device_t of the child 71 * bus and device. If missing, someone bypassed iicbus_request_bus() 72 * and called this method directly using the old calling standard. If 73 * present, find the index of the child bus that called us. 74 */ 75 rd = (struct iic_reqbus_data *)data; 76 if (!(rd->flags & IIC_REQBUS_DEV)) 77 return (iic2errno(EINVAL)); 78 79 for (i = 0; i <= sc->maxbus && sc->childdevs[i] != rd->bus; ++i) 80 continue; 81 if (i > sc->maxbus) 82 return (iic2errno(ENOENT)); 83 84 /* 85 * If the operation is a release it "cannot fail". Idle the downstream 86 * bus, then release exclusive use of the upstream bus, and we're done. 87 */ 88 if (index == IIC_RELEASE_BUS) { 89 if (sc->debugmux > 0) { 90 device_printf(dev, "idle the bus for %s on bus %s\n", 91 device_get_nameunit(rd->dev), 92 device_get_nameunit(rd->bus)); 93 } 94 IICMUX_BUS_SELECT(dev, IICMUX_SELECT_IDLE, rd); 95 iicbus_release_bus(sc->busdev, dev); 96 return (IIC_NOERR); 97 } 98 99 if (sc->debugmux > 0) { 100 device_printf(dev, "select bus idx %d for %s on bus %s\n", i, 101 device_get_nameunit(rd->dev), device_get_nameunit(rd->bus)); 102 } 103 104 /* 105 * The operation is a request for exclusive use. First we have to 106 * request exclusive use of our upstream bus. If multiple slave devices 107 * from our different child buses attempt to do IO at the same time, 108 * this is what ensures that they don't switch the bus out from under 109 * each other. The first one in proceeds and others wait here (or get an 110 * EWOULDBLOCK return if they're using IIC_DONTWAIT). 111 */ 112 if ((err = iicbus_request_bus(sc->busdev, dev, rd->flags)) != 0) 113 return (err); /* Already an IIC error code. */ 114 115 /* 116 * Now that we own exclusive use of the upstream bus, connect it to the 117 * downstream bus where the request came from. 118 */ 119 if ((err = IICMUX_BUS_SELECT(dev, i, rd)) != 0) 120 iicbus_release_bus(sc->busdev, dev); 121 122 return (err); 123 } 124 125 static u_int 126 iicmux_get_frequency(device_t dev, u_char speed) 127 { 128 struct iicmux_softc *sc = device_get_softc(dev); 129 130 return (IICBUS_GET_FREQUENCY(sc->busdev, speed)); 131 } 132 133 #ifdef FDT 134 static phandle_t 135 iicmux_get_node(device_t dev, device_t child) 136 { 137 struct iicmux_softc *sc = device_get_softc(dev); 138 int i; 139 140 for (i = 0; i <= sc->maxbus; ++i) { 141 if (sc->childdevs[i] == child) 142 return (sc->childnodes[i]); 143 } 144 return (0); /* null handle */ 145 } 146 #endif 147 148 static int 149 iicmux_intr(device_t dev, int event, char *buf) 150 { 151 struct iicmux_softc *sc = device_get_softc(dev); 152 153 /* XXX iicbus_intr() in iiconf.c should return status. */ 154 155 iicbus_intr(sc->busdev, event, buf); 156 return (0); 157 } 158 159 static int 160 iicmux_read(device_t dev, char *buf, int len, int *bytes, int last, int delay) 161 { 162 struct iicmux_softc *sc = device_get_softc(dev); 163 164 return (iicbus_read(sc->busdev, buf, len, bytes, last, delay)); 165 } 166 167 static int 168 iicmux_repeated_start(device_t dev, u_char slave, int timeout) 169 { 170 struct iicmux_softc *sc = device_get_softc(dev); 171 172 return (iicbus_repeated_start(sc->busdev, slave, timeout)); 173 } 174 175 static int 176 iicmux_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr) 177 { 178 struct iicmux_softc *sc = device_get_softc(dev); 179 180 return (iicbus_reset(sc->busdev, speed, addr, oldaddr)); 181 } 182 183 static int 184 iicmux_start(device_t dev, u_char slave, int timeout) 185 { 186 struct iicmux_softc *sc = device_get_softc(dev); 187 188 return (iicbus_start(sc->busdev, slave, timeout)); 189 } 190 191 static int 192 iicmux_stop(device_t dev) 193 { 194 struct iicmux_softc *sc = device_get_softc(dev); 195 196 return (iicbus_stop(sc->busdev)); 197 } 198 199 static int 200 iicmux_transfer( device_t dev, struct iic_msg *msgs, uint32_t nmsgs) 201 { 202 struct iicmux_softc *sc = device_get_softc(dev); 203 204 return (iicbus_transfer(sc->busdev, msgs, nmsgs)); 205 } 206 207 static int 208 iicmux_write(device_t dev, const char *buf, int len, int *bytes, int timeout) 209 { 210 struct iicmux_softc *sc = device_get_softc(dev); 211 212 return (iicbus_write(sc->busdev, buf, len, bytes, timeout)); 213 } 214 215 /*------------------------------------------------------------------------------ 216 * iicmux helper functions, called by hardware-specific drivers. 217 * All these functions return a standard errno value. 218 *----------------------------------------------------------------------------*/ 219 220 int 221 iicmux_add_child(device_t dev, device_t child, int busidx) 222 { 223 struct iicmux_softc *sc = device_get_softc(dev); 224 225 if (busidx >= sc->numbuses) { 226 device_printf(dev, 227 "iicmux_add_child: bus idx %d too big", busidx); 228 return (EINVAL); 229 } 230 if (sc->childdevs[busidx] != NULL) { 231 device_printf(dev, "iicmux_add_child: bus idx %d already added", 232 busidx); 233 return (EINVAL); 234 } 235 236 sc->childdevs[busidx] = child; 237 if (sc->maxbus < busidx) 238 sc->maxbus = busidx; 239 240 return (0); 241 } 242 243 static int 244 iicmux_attach_children(struct iicmux_softc *sc) 245 { 246 int i; 247 #ifdef FDT 248 phandle_t child, node, parent; 249 pcell_t idx; 250 251 /* 252 * Find our FDT node. Child nodes within our node will become our 253 * iicbus children. 254 */ 255 if((node = ofw_bus_get_node(sc->dev)) == 0) { 256 device_printf(sc->dev, "cannot find FDT node\n"); 257 return (ENOENT); 258 } 259 260 /* 261 * First we have to see if there is a child node named "i2c-mux". If it 262 * exists, all children of that node are buses, else all children of the 263 * device node are buses. 264 */ 265 if ((parent = ofw_bus_find_child(node, "i2c-mux")) == 0) 266 parent = node; 267 268 /* 269 * Attach the children represented in the device tree. 270 */ 271 for (child = OF_child(parent); child != 0; child = OF_peer(child)) { 272 if (OF_getencprop(child, "reg", &idx, sizeof(idx)) == -1) { 273 device_printf(sc->dev, 274 "child bus missing required 'reg' property\n"); 275 continue; 276 } 277 if (idx >= sc->numbuses) { 278 device_printf(sc->dev, 279 "child bus 'reg' property %d exceeds the number " 280 "of buses supported by the device (%d)\n", 281 idx, sc->numbuses); 282 continue; 283 } 284 sc->childdevs[idx] = device_add_child(sc->dev, "iicbus", -1); 285 sc->childnodes[idx] = child; 286 if (sc->maxbus < idx) 287 sc->maxbus = idx; 288 } 289 290 /* If we configured anything using FDT data, we're done. */ 291 if (sc->maxbus >= 0) 292 return (0); 293 #endif /* FDT */ 294 295 /* 296 * If we make it to here, we didn't add any children based on FDT data. 297 * Add an iicbus child for every downstream bus supported by the mux. 298 */ 299 for (i = 0; i < sc->numbuses; ++i) { 300 sc->childdevs[i] = device_add_child(sc->dev, "iicbus", -1); 301 sc->maxbus = i; 302 } 303 304 return (0); 305 } 306 307 int 308 iicmux_attach(device_t dev, device_t busdev, int numbuses) 309 { 310 struct iicmux_softc *sc = device_get_softc(dev); 311 int err; 312 313 if (numbuses >= IICMUX_MAX_BUSES) { 314 device_printf(dev, "iicmux_attach: numbuses %d > max %d\n", 315 numbuses, IICMUX_MAX_BUSES); 316 return (EINVAL); 317 } 318 319 sc->dev = dev; 320 sc->busdev = busdev; 321 sc->maxbus = -1; 322 sc->numbuses = numbuses; 323 324 if ((err = iicmux_attach_children(sc)) != 0) 325 return (err); 326 327 SYSCTL_ADD_UINT(device_get_sysctl_ctx(sc->dev), 328 SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), OID_AUTO, 329 "debugmux", CTLFLAG_RWTUN, &sc->debugmux, 0, "debug mux operations"); 330 331 return (0); 332 } 333 334 int 335 iicmux_detach(device_t dev) 336 { 337 struct iicmux_softc *sc = device_get_softc(dev); 338 int err, i; 339 340 /* Delete only the children we added in iicmux_add* functions. */ 341 for (i = 0; i <= sc->maxbus; ++i) { 342 if (sc->childdevs[i] == NULL) 343 continue; 344 if ((err = device_delete_child(dev, sc->childdevs[i])) != 0) 345 return (err); 346 sc->childdevs[i] = NULL; 347 } 348 349 return (0); 350 } 351 352 static device_method_t iicmux_methods [] = { 353 /* iicbus_if methods */ 354 DEVMETHOD(iicbus_intr, iicmux_intr), 355 DEVMETHOD(iicbus_callback, iicmux_callback), 356 DEVMETHOD(iicbus_repeated_start, iicmux_repeated_start), 357 DEVMETHOD(iicbus_start, iicmux_start), 358 DEVMETHOD(iicbus_stop, iicmux_stop), 359 DEVMETHOD(iicbus_read, iicmux_read), 360 DEVMETHOD(iicbus_write, iicmux_write), 361 DEVMETHOD(iicbus_reset, iicmux_reset), 362 DEVMETHOD(iicbus_transfer, iicmux_transfer), 363 DEVMETHOD(iicbus_get_frequency, iicmux_get_frequency), 364 365 #ifdef FDT 366 /* ofwbus_if methods */ 367 DEVMETHOD(ofw_bus_get_node, iicmux_get_node), 368 #endif 369 370 DEVMETHOD_END 371 }; 372 373 static int 374 iicmux_modevent(module_t mod, int type, void *unused) 375 { 376 switch (type) { 377 case MOD_LOAD: 378 return 0; 379 case MOD_UNLOAD: 380 return 0; 381 } 382 return EINVAL; 383 } 384 385 static moduledata_t iicmux_mod = { 386 "iicmux", 387 iicmux_modevent, 388 0 389 }; 390 391 DEFINE_CLASS_0(iicmux, iicmux_driver, iicmux_methods, 392 sizeof(struct iicmux_softc)); 393 394 DECLARE_MODULE(iicmux, iicmux_mod, SI_SUB_DRIVERS, SI_ORDER_ANY); 395 MODULE_VERSION(iicmux, 1); 396 397 MODULE_DEPEND(iicmux, iicbus, 1, 1, 1); 398