Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/arm/freescale/vybrid/vf_gpio.c
39536 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2013 Ruslan Bukin <[email protected]>
5
* All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
*
16
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
* SUCH DAMAGE.
27
*/
28
29
/*
30
* Vybrid Family General-Purpose Input/Output (GPIO)
31
* Chapter 7, Vybrid Reference Manual, Rev. 5, 07/2013
32
*/
33
34
#include <sys/param.h>
35
#include <sys/systm.h>
36
#include <sys/bus.h>
37
#include <sys/kernel.h>
38
#include <sys/module.h>
39
#include <sys/malloc.h>
40
#include <sys/rman.h>
41
#include <sys/timeet.h>
42
#include <sys/timetc.h>
43
#include <sys/watchdog.h>
44
#include <sys/mutex.h>
45
#include <sys/gpio.h>
46
47
#include <dev/gpio/gpiobusvar.h>
48
#include <dev/ofw/openfirm.h>
49
#include <dev/ofw/ofw_bus.h>
50
#include <dev/ofw/ofw_bus_subr.h>
51
52
#include <machine/bus.h>
53
#include <machine/cpu.h>
54
#include <machine/intr.h>
55
56
#include "gpio_if.h"
57
58
#include <arm/freescale/vybrid/vf_common.h>
59
#include <arm/freescale/vybrid/vf_port.h>
60
61
#define GPIO_PDOR(n) (0x00 + 0x40 * (n >> 5))
62
#define GPIO_PSOR(n) (0x04 + 0x40 * (n >> 5))
63
#define GPIO_PCOR(n) (0x08 + 0x40 * (n >> 5))
64
#define GPIO_PTOR(n) (0x0C + 0x40 * (n >> 5))
65
#define GPIO_PDIR(n) (0x10 + 0x40 * (n >> 5))
66
67
#define GPIO_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
68
#define GPIO_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
69
70
#define DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)
71
72
/*
73
* GPIO interface
74
*/
75
static device_t vf_gpio_get_bus(device_t);
76
static int vf_gpio_pin_max(device_t, int *);
77
static int vf_gpio_pin_getcaps(device_t, uint32_t, uint32_t *);
78
static int vf_gpio_pin_getname(device_t, uint32_t, char *);
79
static int vf_gpio_pin_getflags(device_t, uint32_t, uint32_t *);
80
static int vf_gpio_pin_setflags(device_t, uint32_t, uint32_t);
81
static int vf_gpio_pin_set(device_t, uint32_t, unsigned int);
82
static int vf_gpio_pin_get(device_t, uint32_t, unsigned int *);
83
static int vf_gpio_pin_toggle(device_t, uint32_t pin);
84
85
struct vf_gpio_softc {
86
struct resource *res[1];
87
bus_space_tag_t bst;
88
bus_space_handle_t bsh;
89
90
device_t sc_busdev;
91
struct mtx sc_mtx;
92
int gpio_npins;
93
struct gpio_pin gpio_pins[NGPIO];
94
};
95
96
struct vf_gpio_softc *gpio_sc;
97
98
static struct resource_spec vf_gpio_spec[] = {
99
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
100
{ -1, 0 }
101
};
102
103
static int
104
vf_gpio_probe(device_t dev)
105
{
106
107
if (!ofw_bus_status_okay(dev))
108
return (ENXIO);
109
110
if (!ofw_bus_is_compatible(dev, "fsl,mvf600-gpio"))
111
return (ENXIO);
112
113
device_set_desc(dev, "Vybrid Family GPIO Unit");
114
return (BUS_PROBE_DEFAULT);
115
}
116
117
static int
118
vf_gpio_attach(device_t dev)
119
{
120
struct vf_gpio_softc *sc;
121
int i;
122
123
sc = device_get_softc(dev);
124
mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
125
126
if (bus_alloc_resources(dev, vf_gpio_spec, sc->res)) {
127
device_printf(dev, "could not allocate resources\n");
128
mtx_destroy(&sc->sc_mtx);
129
return (ENXIO);
130
}
131
132
/* Memory interface */
133
sc->bst = rman_get_bustag(sc->res[0]);
134
sc->bsh = rman_get_bushandle(sc->res[0]);
135
136
gpio_sc = sc;
137
138
sc->gpio_npins = NGPIO;
139
140
for (i = 0; i < sc->gpio_npins; i++) {
141
sc->gpio_pins[i].gp_pin = i;
142
sc->gpio_pins[i].gp_caps = DEFAULT_CAPS;
143
sc->gpio_pins[i].gp_flags =
144
(READ4(sc, GPIO_PDOR(i)) & (1 << (i % 32))) ?
145
GPIO_PIN_OUTPUT: GPIO_PIN_INPUT;
146
snprintf(sc->gpio_pins[i].gp_name, GPIOMAXNAME,
147
"vf_gpio%d.%d", device_get_unit(dev), i);
148
}
149
150
sc->sc_busdev = gpiobus_add_bus(dev);
151
if (sc->sc_busdev == NULL) {
152
bus_release_resources(dev, vf_gpio_spec, sc->res);
153
mtx_destroy(&sc->sc_mtx);
154
return (ENXIO);
155
}
156
157
bus_attach_children(dev);
158
return (0);
159
}
160
161
static device_t
162
vf_gpio_get_bus(device_t dev)
163
{
164
struct vf_gpio_softc *sc;
165
166
sc = device_get_softc(dev);
167
168
return (sc->sc_busdev);
169
}
170
171
static int
172
vf_gpio_pin_max(device_t dev, int *maxpin)
173
{
174
175
*maxpin = NGPIO - 1;
176
return (0);
177
}
178
179
static int
180
vf_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
181
{
182
struct vf_gpio_softc *sc;
183
int i;
184
185
sc = device_get_softc(dev);
186
for (i = 0; i < sc->gpio_npins; i++) {
187
if (sc->gpio_pins[i].gp_pin == pin)
188
break;
189
}
190
191
if (i >= sc->gpio_npins)
192
return (EINVAL);
193
194
GPIO_LOCK(sc);
195
memcpy(name, sc->gpio_pins[i].gp_name, GPIOMAXNAME);
196
GPIO_UNLOCK(sc);
197
198
return (0);
199
}
200
201
static int
202
vf_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
203
{
204
struct vf_gpio_softc *sc;
205
int i;
206
207
sc = device_get_softc(dev);
208
for (i = 0; i < sc->gpio_npins; i++) {
209
if (sc->gpio_pins[i].gp_pin == pin)
210
break;
211
}
212
213
if (i >= sc->gpio_npins)
214
return (EINVAL);
215
216
GPIO_LOCK(sc);
217
*caps = sc->gpio_pins[i].gp_caps;
218
GPIO_UNLOCK(sc);
219
220
return (0);
221
}
222
223
static int
224
vf_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
225
{
226
struct vf_gpio_softc *sc;
227
int i;
228
229
sc = device_get_softc(dev);
230
for (i = 0; i < sc->gpio_npins; i++) {
231
if (sc->gpio_pins[i].gp_pin == pin)
232
break;
233
}
234
235
if (i >= sc->gpio_npins)
236
return (EINVAL);
237
238
GPIO_LOCK(sc);
239
*flags = sc->gpio_pins[i].gp_flags;
240
GPIO_UNLOCK(sc);
241
242
return (0);
243
}
244
245
static int
246
vf_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
247
{
248
struct vf_gpio_softc *sc;
249
int i;
250
251
sc = device_get_softc(dev);
252
for (i = 0; i < sc->gpio_npins; i++) {
253
if (sc->gpio_pins[i].gp_pin == pin)
254
break;
255
}
256
257
if (i >= sc->gpio_npins)
258
return (EINVAL);
259
260
GPIO_LOCK(sc);
261
*val = (READ4(sc, GPIO_PDIR(i)) & (1 << (i % 32))) ? 1 : 0;
262
GPIO_UNLOCK(sc);
263
264
return (0);
265
}
266
267
static int
268
vf_gpio_pin_toggle(device_t dev, uint32_t pin)
269
{
270
struct vf_gpio_softc *sc;
271
int i;
272
273
sc = device_get_softc(dev);
274
for (i = 0; i < sc->gpio_npins; i++) {
275
if (sc->gpio_pins[i].gp_pin == pin)
276
break;
277
}
278
279
if (i >= sc->gpio_npins)
280
return (EINVAL);
281
282
GPIO_LOCK(sc);
283
WRITE4(sc, GPIO_PTOR(i), (1 << (i % 32)));
284
GPIO_UNLOCK(sc);
285
286
return (0);
287
}
288
289
static void
290
vf_gpio_pin_configure(struct vf_gpio_softc *sc, struct gpio_pin *pin,
291
unsigned int flags)
292
{
293
294
GPIO_LOCK(sc);
295
296
/*
297
* Manage input/output
298
*/
299
if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) {
300
pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT);
301
if (flags & GPIO_PIN_OUTPUT) {
302
pin->gp_flags |= GPIO_PIN_OUTPUT;
303
304
} else {
305
pin->gp_flags |= GPIO_PIN_INPUT;
306
WRITE4(sc, GPIO_PCOR(pin->gp_pin),
307
(1 << (pin->gp_pin % 32)));
308
}
309
}
310
311
GPIO_UNLOCK(sc);
312
}
313
314
static int
315
vf_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
316
{
317
struct vf_gpio_softc *sc;
318
int i;
319
320
sc = device_get_softc(dev);
321
for (i = 0; i < sc->gpio_npins; i++) {
322
if (sc->gpio_pins[i].gp_pin == pin)
323
break;
324
}
325
326
if (i >= sc->gpio_npins)
327
return (EINVAL);
328
329
vf_gpio_pin_configure(sc, &sc->gpio_pins[i], flags);
330
331
return (0);
332
}
333
334
static int
335
vf_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
336
{
337
struct vf_gpio_softc *sc;
338
int i;
339
340
sc = device_get_softc(dev);
341
for (i = 0; i < sc->gpio_npins; i++) {
342
if (sc->gpio_pins[i].gp_pin == pin)
343
break;
344
}
345
346
if (i >= sc->gpio_npins)
347
return (EINVAL);
348
349
GPIO_LOCK(sc);
350
if (value)
351
WRITE4(sc, GPIO_PSOR(i), (1 << (i % 32)));
352
else
353
WRITE4(sc, GPIO_PCOR(i), (1 << (i % 32)));
354
GPIO_UNLOCK(sc);
355
356
return (0);
357
}
358
359
static device_method_t vf_gpio_methods[] = {
360
DEVMETHOD(device_probe, vf_gpio_probe),
361
DEVMETHOD(device_attach, vf_gpio_attach),
362
363
/* GPIO protocol */
364
DEVMETHOD(gpio_get_bus, vf_gpio_get_bus),
365
DEVMETHOD(gpio_pin_max, vf_gpio_pin_max),
366
DEVMETHOD(gpio_pin_getname, vf_gpio_pin_getname),
367
DEVMETHOD(gpio_pin_getcaps, vf_gpio_pin_getcaps),
368
DEVMETHOD(gpio_pin_getflags, vf_gpio_pin_getflags),
369
DEVMETHOD(gpio_pin_get, vf_gpio_pin_get),
370
DEVMETHOD(gpio_pin_toggle, vf_gpio_pin_toggle),
371
DEVMETHOD(gpio_pin_setflags, vf_gpio_pin_setflags),
372
DEVMETHOD(gpio_pin_set, vf_gpio_pin_set),
373
{ 0, 0 }
374
};
375
376
static driver_t vf_gpio_driver = {
377
"gpio",
378
vf_gpio_methods,
379
sizeof(struct vf_gpio_softc),
380
};
381
382
DRIVER_MODULE(vf_gpio, simplebus, vf_gpio_driver, 0, 0);
383
384