2 * Copyright (c) 2018 Stormshield
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/param.h>
28 #include <sys/module.h>
29 #include <sys/systm.h>
30 #include <sys/errno.h>
31 #include <sys/kernel.h>
32 #include <sys/malloc.h>
36 #include <machine/bus.h>
38 #include <machine/resource.h>
42 #include "lewisburg_gpiocm.h"
47 #define PADCFG0_GPIORXDIS (1<<9)
48 #define PADCFG0_GPIOTXDIS (1<<8)
49 #define PADCFG0_GPIORXSTATE (1<<1)
50 #define PADCFG0_GPIOTXSTATE (1<<0)
52 #define MAX_PAD_PER_GROUP 24
54 #define LBGGPIOCM_READ(sc, reg) p2sb_port_read_4(sc->p2sb, sc->port, reg)
55 #define LBGGPIOCM_WRITE(sc, reg, val) \
56 p2sb_port_write_4(sc->p2sb, sc->port, reg, val)
57 #define LBGGPIOCM_LOCK(sc) p2sb_lock(sc->p2sb)
58 #define LBGGPIOCM_UNLOCK(sc) p2sb_unlock(sc->p2sb)
72 struct lbggroup groups[3];
76 #define LBG_COMMUNITY(n, np, g) \
83 static struct lbgcommunity lbg_communities[] = {
84 LBG_COMMUNITY("LewisBurg GPIO Community 0", 72, "ABF"),
85 LBG_COMMUNITY("LewisBurg GPIO Community 1", 61, "CDE"),
86 LBG_COMMUNITY("LewisBurg GPIO Community 2", 0, ""),
87 LBG_COMMUNITY("LewisBurg GPIO Community 3", 12, "I"),
88 LBG_COMMUNITY("LewisBurg GPIO Community 4", 36, "JK"),
89 LBG_COMMUNITY("LewisBurg GPIO Community 5", 66, "GHL"),
92 struct lbggpiocm_softc
96 struct lbgcommunity *community;
99 static struct lbggroup *lbggpiocm_get_group(struct lbggpiocm_softc *sc,
102 static __inline struct lbggroup *
103 lbggpiocm_get_group(struct lbggpiocm_softc *sc, device_t child)
107 for (i = 0; i < sc->community->ngroups; ++i)
108 if (sc->community->groups[i].dev == child)
109 return (&sc->community->groups[i]);
114 static __inline uint32_t
115 lbggpiocm_getpad(struct lbggpiocm_softc *sc, uint32_t pin)
118 if (pin >= sc->community->npins)
121 return (sc->community->pad_off + 2 * 4 * pin);
125 lbggpiocm_get_group_npins(device_t dev, device_t child)
127 struct lbggpiocm_softc *sc = device_get_softc(dev);
128 struct lbggroup *group;
130 group = lbggpiocm_get_group(sc, child);
132 return (group->npins);
137 lbggpiocm_get_group_name(device_t dev, device_t child)
139 struct lbggpiocm_softc *sc = device_get_softc(dev);
140 struct lbggroup *group;
142 group = lbggpiocm_get_group(sc, child);
144 return (group->grpname);
149 lbggpiocm_pin2cpin(struct lbggpiocm_softc *sc, device_t child, uint32_t pin)
151 struct lbggroup *group;
153 group = lbggpiocm_get_group(sc, child);
155 return (pin + group->pins_off);
160 lbggpiocm_pin_setflags(device_t dev, device_t child, uint32_t pin, uint32_t flags)
162 struct lbggpiocm_softc *sc = device_get_softc(dev);
163 uint32_t padreg, padval;
166 if ((flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) ==
167 (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT))
170 if ((flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) == 0)
173 rpin = lbggpiocm_pin2cpin(sc, child, pin);
177 padreg = lbggpiocm_getpad(sc, rpin);
180 padval = LBGGPIOCM_READ(sc, padreg);
182 if (flags & GPIO_PIN_INPUT) {
183 padval &= ~PADCFG0_GPIORXDIS;
184 padval |= PADCFG0_GPIOTXDIS;
185 } else if (flags & GPIO_PIN_OUTPUT) {
186 padval &= ~PADCFG0_GPIOTXDIS;
187 padval |= PADCFG0_GPIORXDIS;
190 LBGGPIOCM_WRITE(sc, padreg, padval);
191 LBGGPIOCM_UNLOCK(sc);
197 lbggpiocm_pin_get(device_t dev, device_t child, uint32_t pin, uint32_t *value)
199 struct lbggpiocm_softc *sc = device_get_softc(dev);
200 uint32_t padreg, val;
206 rpin = lbggpiocm_pin2cpin(sc, child, pin);
210 padreg = lbggpiocm_getpad(sc, rpin);
213 val = LBGGPIOCM_READ(sc, padreg);
214 LBGGPIOCM_UNLOCK(sc);
216 if (!(val & PADCFG0_GPIOTXDIS))
217 *value = !!(val & PADCFG0_GPIOTXSTATE);
219 *value = !!(val & PADCFG0_GPIORXSTATE);
225 lbggpiocm_pin_set(device_t dev, device_t child, uint32_t pin, uint32_t value)
227 struct lbggpiocm_softc *sc = device_get_softc(dev);
228 uint32_t padreg, padcfg;
231 rpin = lbggpiocm_pin2cpin(sc, child, pin);
235 padreg = lbggpiocm_getpad(sc, rpin);
239 padcfg = LBGGPIOCM_READ(sc, padreg);
241 padcfg |= PADCFG0_GPIOTXSTATE;
243 padcfg &= ~PADCFG0_GPIOTXSTATE;
244 LBGGPIOCM_WRITE(sc, padreg, padcfg);
246 LBGGPIOCM_UNLOCK(sc);
252 lbggpiocm_pin_toggle(device_t dev, device_t child, uint32_t pin)
254 struct lbggpiocm_softc *sc = device_get_softc(dev);
255 uint32_t padreg, padcfg;
258 rpin = lbggpiocm_pin2cpin(sc, child, pin);
262 padreg = lbggpiocm_getpad(sc, rpin);
265 padcfg = LBGGPIOCM_READ(sc, padreg);
266 padcfg ^= PADCFG0_GPIOTXSTATE;
267 LBGGPIOCM_WRITE(sc, padreg, padcfg);
269 LBGGPIOCM_UNLOCK(sc);
275 lbggpiocm_probe(device_t dev)
277 struct lbggpiocm_softc *sc = device_get_softc(dev);
280 sc->p2sb = device_get_parent(dev);
281 unit = device_get_unit(dev);
282 KASSERT(unit < nitems(lbg_communities), ("Wrong number of devices or communities"));
283 sc->port = p2sb_get_port(sc->p2sb, unit);
284 sc->community = &lbg_communities[unit];
288 device_set_desc(dev, sc->community->name);
289 return (BUS_PROBE_DEFAULT);
293 lbggpiocm_attach(device_t dev)
296 struct lbggpiocm_softc *sc;
297 struct lbggroup *group;
300 sc = device_get_softc(dev);
301 if (sc->community->npins == 0)
305 sc->community->pad_off = LBGGPIOCM_READ(sc, PADBAR);
306 LBGGPIOCM_UNLOCK(sc);
308 npins = sc->community->npins;
309 for (i = 0; i < nitems(sc->community->groups) && npins > 0; ++i) {
310 group = &sc->community->groups[i];
313 group->grpname = sc->community->grpnames[i];
314 group->pins_off = i * MAX_PAD_PER_GROUP;
315 group->npins = npins < MAX_PAD_PER_GROUP ? npins :
317 npins -= group->npins;
318 group->dev = device_add_child(dev, "gpio", -1);
320 sc->community->ngroups = i;
321 return (bus_generic_attach(dev));
325 lbggpiocm_detach(device_t dev)
329 error = device_delete_children(dev);
333 return (bus_generic_detach(dev));
336 static device_method_t lbggpiocm_methods[] = {
337 /* Device interface */
338 DEVMETHOD(device_probe, lbggpiocm_probe),
339 DEVMETHOD(device_attach, lbggpiocm_attach),
340 DEVMETHOD(device_detach, lbggpiocm_detach),
345 static driver_t lbggpiocm_driver = {
348 sizeof(struct lbggpiocm_softc)
350 static devclass_t lbggpiocm_devclass;
351 DRIVER_MODULE(lbggpiocm, p2sb, lbggpiocm_driver, lbggpiocm_devclass, NULL, NULL);