FreeBSD kernel IICBUS device code
iicmux.c
Go to the documentation of this file.
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
58static int
59iicmux_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. */
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);
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)
121
122 return (err);
123}
124
125static u_int
127{
128 struct iicmux_softc *sc = device_get_softc(dev);
129
130 return (IICBUS_GET_FREQUENCY(sc->busdev, speed));
131}
132
133#ifdef FDT
134static phandle_t
135iicmux_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
148static int
149iicmux_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
156 return (0);
157}
158
159static int
160iicmux_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
167static int
169{
170 struct iicmux_softc *sc = device_get_softc(dev);
171
173}
174
175static int
176iicmux_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
183static int
184iicmux_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
191static int
193{
194 struct iicmux_softc *sc = device_get_softc(dev);
195
196 return (iicbus_stop(sc->busdev));
197}
198
199static int
200iicmux_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
207static int
208iicmux_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
220int
221iicmux_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
243static int
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 < (int)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
307int
308iicmux_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",
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
334int
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
352static device_method_t iicmux_methods [] = {
353 /* iicbus_if methods */
354 DEVMETHOD(iicbus_intr, iicmux_intr),
355 DEVMETHOD(iicbus_callback, iicmux_callback),
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),
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
373static int
374iicmux_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
385static moduledata_t iicmux_mod = {
386 "iicmux",
388 0
389};
390
392 sizeof(struct iicmux_softc));
393
394DECLARE_MODULE(iicmux, iicmux_mod, SI_SUB_DRIVERS, SI_ORDER_ANY);
396
u_char speed
Definition: iicbb_if.m:115
caddr_t data
Definition: iicbb_if.m:61
int index
Definition: iicbb_if.m:60
u_char addr
Definition: iicbb_if.m:116
u_char * oldaddr
Definition: iicbb_if.m:117
static u_int iicbus_get_frequency(device_t dev, u_char speed)
Definition: iicbus.c:331
char * buf
Definition: iicbus_if.m:55
int timeout
Definition: iicbus_if.m:77
int * bytes
Definition: iicbus_if.m:103
int delay
Definition: iicbus_if.m:105
int last
Definition: iicbus_if.m:104
u_char slave
Definition: iicbus_if.m:76
struct iic_msg * msgs
Definition: iicbus_if.m:134
int event
Definition: iicbus_if.m:54
uint32_t nmsgs
Definition: iicbus_if.m:135
INTERFACE iicbus
Definition: iicbus_if.m:32
int len
Definition: iicbus_if.m:102
int iicmux_detach(device_t dev)
Definition: iicmux.c:335
static u_int iicmux_get_frequency(device_t dev, u_char speed)
Definition: iicmux.c:126
static device_method_t iicmux_methods[]
Definition: iicmux.c:352
static int iicmux_attach_children(struct iicmux_softc *sc)
Definition: iicmux.c:244
DEFINE_CLASS_0(iicmux, iicmux_driver, iicmux_methods, sizeof(struct iicmux_softc))
static int iicmux_callback(device_t dev, int index, caddr_t data)
Definition: iicmux.c:59
static int iicmux_modevent(module_t mod, int type, void *unused)
Definition: iicmux.c:374
DECLARE_MODULE(iicmux, iicmux_mod, SI_SUB_DRIVERS, SI_ORDER_ANY)
__FBSDID("$FreeBSD$")
static int iicmux_write(device_t dev, const char *buf, int len, int *bytes, int timeout)
Definition: iicmux.c:208
int iicmux_attach(device_t dev, device_t busdev, int numbuses)
Definition: iicmux.c:308
static int iicmux_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs)
Definition: iicmux.c:200
MODULE_VERSION(iicmux, 1)
static int iicmux_repeated_start(device_t dev, u_char slave, int timeout)
Definition: iicmux.c:168
static int iicmux_start(device_t dev, u_char slave, int timeout)
Definition: iicmux.c:184
static int iicmux_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
Definition: iicmux.c:176
static int iicmux_stop(device_t dev)
Definition: iicmux.c:192
static int iicmux_intr(device_t dev, int event, char *buf)
Definition: iicmux.c:149
MODULE_DEPEND(iicmux, iicbus, 1, 1, 1)
int iicmux_add_child(device_t dev, device_t child, int busidx)
Definition: iicmux.c:221
static int iicmux_read(device_t dev, char *buf, int len, int *bytes, int last, int delay)
Definition: iicmux.c:160
static moduledata_t iicmux_mod
Definition: iicmux.c:385
#define IICMUX_SELECT_IDLE
Definition: iicmux.h:43
#define IICMUX_MAX_BUSES
Definition: iicmux.h:33
INTERFACE iicmux
Definition: iicmux_if.m:32
int busidx
Definition: iicmux_if.m:47
struct iic_reqbus_data * rd
Definition: iicmux_if.m:48
int iicbus_request_bus(device_t bus, device_t dev, int how)
Definition: iiconf.c:138
void iicbus_intr(device_t bus, int event, char *buf)
Definition: iiconf.c:97
int iicbus_transfer(device_t bus, struct iic_msg *msgs, uint32_t nmsgs)
Definition: iiconf.c:442
int iicbus_read(device_t bus, char *buf, int len, int *read, int last, int delay)
Definition: iiconf.c:339
int iic2errno(int iic_status)
Definition: iiconf.c:60
int iicbus_release_bus(device_t bus, device_t dev)
Definition: iiconf.c:206
int iicbus_write(device_t bus, const char *buf, int len, int *sent, int timeout)
Definition: iiconf.c:321
int iicbus_stop(device_t bus)
Definition: iiconf.c:298
int iicbus_repeated_start(device_t bus, u_char slave, int timeout)
Definition: iiconf.c:276
int iicbus_start(device_t bus, u_char slave, int timeout)
Definition: iiconf.c:254
#define iicbus_reset(bus, speed, addr, oldaddr)
Definition: iiconf.h:135
#define IIC_RELEASE_BUS
Definition: iiconf.h:91
#define IIC_NOERR
Definition: iiconf.h:107
#define IIC_REQUEST_BUS
Definition: iiconf.h:90
#define IIC_REQBUS_DEV
Definition: iiconf.h:50
device_t dev
Definition: ofw_iicbus_if.m:38
Definition: iic.h:38
device_t bus
Definition: iiconf.h:66
device_t dev
Definition: iiconf.h:67
int numbuses
Definition: iicmux.h:54
int debugmux
Definition: iicmux.h:55
int maxbus
Definition: iicmux.h:53
device_t busdev
Definition: iicmux.h:51
device_t dev
Definition: iicmux.h:52
device_t childdevs[IICMUX_MAX_BUSES]
Definition: iicmux.h:56