]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/p2sb/lewisburg_gpio.c
contrib/tzdata: import tzdata 2021c
[FreeBSD/FreeBSD.git] / sys / dev / p2sb / lewisburg_gpio.c
1 /*-
2  * Copyright (c) 2018 Stormshield
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
13  *
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
24  * SUCH DAMAGE.
25  */
26
27 #include <sys/param.h>          /* defines used in kernel.h */
28 #include <sys/module.h>
29 #include <sys/systm.h>
30 #include <sys/errno.h>
31 #include <sys/kernel.h>         /* types used in module initialization */
32 #include <sys/conf.h>           /* cdevsw struct */
33 #include <sys/uio.h>            /* uio struct */
34 #include <sys/malloc.h>
35 #include <sys/bus.h>            /* structs, prototypes for pci bus stuff and DEVMETHOD macros! */
36 #include <sys/gpio.h>
37
38 #include <machine/bus.h>
39 #include <sys/rman.h>
40 #include <machine/resource.h>
41
42 #include <dev/gpio/gpiobusvar.h>
43
44 #include "gpio_if.h"
45
46 #include "lewisburg_gpiocm.h"
47
48 #define P2SB_GROUP_GPIO_MAX_PINS 24
49 struct lbggpio_softc
50 {
51         device_t                sc_busdev;
52         int groupid;
53         int pins_off;
54         int npins;
55         char grpname;
56         struct gpio_pin gpio_setup[P2SB_GROUP_GPIO_MAX_PINS];
57 };
58
59 static device_t
60 lbggpio_get_bus(device_t dev)
61 {
62         struct lbggpio_softc *sc;
63
64         sc = device_get_softc(dev);
65
66         return (sc->sc_busdev);
67 }
68
69 static int
70 lbggpio_pin_max(device_t dev, int *maxpin)
71 {
72         struct lbggpio_softc *sc;
73
74         if (maxpin == NULL)
75                 return (EINVAL);
76
77         sc = device_get_softc(dev);
78
79         *maxpin = sc->npins - 1;
80
81         return (0);
82 }
83
84 static int
85 lbggpio_pin_getname(device_t dev, uint32_t pin, char *name)
86 {
87         struct lbggpio_softc *sc = device_get_softc(dev);
88
89         if (name == NULL)
90                 return (EINVAL);
91
92         if (pin >= sc->npins)
93                 return (EINVAL);
94
95         strlcpy(name, sc->gpio_setup[pin].gp_name, GPIOMAXNAME);
96
97         return (0);
98 }
99
100 static int
101 lbggpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
102 {
103         struct lbggpio_softc *sc = device_get_softc(dev);
104
105         if (flags == NULL)
106                 return (EINVAL);
107
108         if (pin >= sc->npins)
109                 return (EINVAL);
110
111         *flags = sc->gpio_setup[pin].gp_flags;
112
113         return (0);
114 }
115
116 static int
117 lbggpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
118 {
119         struct lbggpio_softc *sc = device_get_softc(dev);
120
121         if (caps == NULL)
122                 return (EINVAL);
123
124         if (pin >= sc->npins)
125                 return (EINVAL);
126
127         *caps = sc->gpio_setup[pin].gp_caps;
128
129         return (0);
130 }
131
132 static int
133 lbggpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
134 {
135         struct lbggpio_softc *sc = device_get_softc(dev);
136
137         if (pin >= sc->npins)
138                 return (EINVAL);
139
140         /* Check for unwanted flags. */
141         if ((flags & sc->gpio_setup[pin].gp_caps) != flags)
142                 return (EINVAL);
143
144         lbggpiocm_pin_setflags(device_get_parent(dev), dev, pin, flags);
145         sc->gpio_setup[pin].gp_flags = flags;
146
147         return (0);
148 }
149
150 static int
151 lbggpio_pin_get(device_t dev, uint32_t pin, uint32_t *value)
152 {
153         struct lbggpio_softc *sc = device_get_softc(dev);
154
155         if (value == NULL)
156                 return (EINVAL);
157
158         if (pin >= sc->npins)
159                 return (EINVAL);
160
161         return (lbggpiocm_pin_get(device_get_parent(dev), dev, pin, value));
162 }
163
164 static int
165 lbggpio_pin_set(device_t dev, uint32_t pin, uint32_t value)
166 {
167         struct lbggpio_softc *sc = device_get_softc(dev);
168
169         if (pin >= sc->npins)
170                 return (EINVAL);
171
172         return (lbggpiocm_pin_set(device_get_parent(dev), dev, pin, value));
173 }
174
175 static int
176 lbggpio_pin_toggle(device_t dev, uint32_t pin)
177 {
178         struct lbggpio_softc *sc = device_get_softc(dev);
179
180         if (pin >= sc->npins)
181                 return (EINVAL);
182
183         return (lbggpiocm_pin_toggle(device_get_parent(dev), dev, pin));
184 }
185
186 static int
187 lbggpio_probe(device_t dev)
188 {
189         struct lbggpio_softc *sc = device_get_softc(dev);
190         /* X is a placeholder for the actual one letter group name. */
191         static char desc[] = "LewisBurg GPIO Group X";
192
193         sc->npins = lbggpiocm_get_group_npins(device_get_parent(dev), dev);
194         sc->grpname = lbggpiocm_get_group_name(device_get_parent(dev), dev);
195         if (sc->npins <= 0)
196                 return (ENXIO);
197
198         desc[sizeof(desc)-2] = sc->grpname;
199         device_set_desc_copy(dev, desc);
200         return (BUS_PROBE_DEFAULT);
201 }
202
203 static int
204 lbggpio_attach(device_t dev)
205 {
206         uint32_t i;
207         struct lbggpio_softc *sc;
208
209         sc = device_get_softc(dev);
210         /* GPIO config */
211         for (i = 0; i < sc->npins; ++i) {
212                 sc->gpio_setup[i].gp_pin = i;
213                 snprintf(sc->gpio_setup[i].gp_name,
214                     sizeof(sc->gpio_setup[i].gp_name),
215                     "GPIO %c%u", sc->grpname, i);
216                 sc->gpio_setup[i].gp_caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT;
217         }
218
219         /* support gpio */
220         sc->sc_busdev = gpiobus_attach_bus(dev);
221         if (sc->sc_busdev == NULL)
222                 return (ENXIO);
223
224         return (0);
225 }
226
227 static int
228 lbggpio_detach(device_t dev)
229 {
230         struct lbggpio_softc *sc;
231
232         sc = device_get_softc(dev);
233
234         if (sc->sc_busdev)
235                 gpiobus_detach_bus(dev);
236
237         return (0);
238 }
239
240 static device_method_t lbggpio_methods[] = {
241         /* Device interface */
242         DEVMETHOD(device_probe,         lbggpio_probe),
243         DEVMETHOD(device_attach,        lbggpio_attach),
244         DEVMETHOD(device_detach,        lbggpio_detach),
245
246         /* GPIO protocol */
247         DEVMETHOD(gpio_get_bus,         lbggpio_get_bus),
248         DEVMETHOD(gpio_pin_max,         lbggpio_pin_max),
249         DEVMETHOD(gpio_pin_getcaps,     lbggpio_pin_getcaps),
250         DEVMETHOD(gpio_pin_getflags,    lbggpio_pin_getflags),
251         DEVMETHOD(gpio_pin_setflags,    lbggpio_pin_setflags),
252         DEVMETHOD(gpio_pin_getname,     lbggpio_pin_getname),
253         DEVMETHOD(gpio_pin_set,         lbggpio_pin_set),
254         DEVMETHOD(gpio_pin_get,         lbggpio_pin_get),
255         DEVMETHOD(gpio_pin_toggle,      lbggpio_pin_toggle),
256
257         DEVMETHOD_END
258 };
259
260 static driver_t lbggpio_driver = {
261         "gpio",
262         lbggpio_methods,
263         sizeof(struct lbggpio_softc)
264 };
265
266 static devclass_t lbggpio_devclass;
267
268 DRIVER_MODULE(lbggpio, lbggpiocm, lbggpio_driver, lbggpio_devclass, NULL, NULL);
269 MODULE_DEPEND(lbggpio, gpiobus, 1, 1, 1);