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