cf3c20ae |
1 | /* $OpenBSD: omgpio.c,v 1.6 2016/01/31 00:14:50 jsg Exp $ */ |
2 | /* |
3 | * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org> |
4 | * |
5 | * Permission to use, copy, modify, and distribute this software for any |
6 | * purpose with or without fee is hereby granted, provided that the above |
7 | * copyright notice and this permission notice appear in all copies. |
8 | * |
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
16 | */ |
17 | |
18 | #include <sys/param.h> |
19 | #include <sys/systm.h> |
20 | #include <sys/queue.h> |
21 | #include <sys/device.h> |
22 | #include <sys/malloc.h> |
23 | #include <sys/evcount.h> |
24 | #include <sys/gpio.h> |
25 | |
26 | #include <arm/cpufunc.h> |
27 | |
28 | #include <machine/bus.h> |
29 | #include <machine/intr.h> |
30 | |
31 | #include <dev/gpio/gpiovar.h> |
32 | |
33 | #include <armv7/armv7/armv7var.h> |
34 | #include <armv7/omap/prcmvar.h> |
35 | #include <armv7/omap/sitara_cm.h> |
36 | #include <armv7/omap/omgpiovar.h> |
37 | |
38 | #include "gpio.h" |
39 | |
40 | /* OMAP3 registers */ |
41 | #define GPIO3_REVISION 0x00 |
42 | #define GPIO3_SYSCONFIG 0x10 |
43 | #define GPIO3_SYSSTATUS 0x14 |
44 | #define GPIO3_IRQSTATUS1 0x18 |
45 | #define GPIO3_IRQENABLE1 0x1C |
46 | #define GPIO3_WAKEUPENABLE 0x20 |
47 | #define GPIO3_IRQSTATUS2 0x28 |
48 | #define GPIO3_IRQENABLE2 0x2C |
49 | #define GPIO3_CTRL 0x30 |
50 | #define GPIO3_OE 0x34 |
51 | #define GPIO3_DATAIN 0x38 |
52 | #define GPIO3_DATAOUT 0x3C |
53 | #define GPIO3_LEVELDETECT0 0x40 |
54 | #define GPIO3_LEVELDETECT1 0x44 |
55 | #define GPIO3_RISINGDETECT 0x48 |
56 | #define GPIO3_FALLINGDETECT 0x4C |
57 | #define GPIO3_DEBOUNCENABLE 0x50 |
58 | #define GPIO3_DEBOUNCINGTIME 0x54 |
59 | #define GPIO3_CLEARIRQENABLE1 0x60 |
60 | #define GPIO3_SETIRQENABLE1 0x64 |
61 | #define GPIO3_CLEARIRQENABLE2 0x70 |
62 | #define GPIO3_SETIRQENABLE2 0x74 |
63 | #define GPIO3_CLEARWKUENA 0x80 |
64 | #define GPIO3_SETWKUENA 0x84 |
65 | #define GPIO3_CLEARDATAOUT 0x90 |
66 | #define GPIO3_SETDATAOUT 0x94 |
67 | |
68 | /* OMAP4 registers */ |
69 | #define GPIO4_REVISION 0x00 |
70 | #define GPIO4_SYSCONFIG 0x10 |
71 | #define GPIO4_IRQSTATUS_RAW_0 0x24 |
72 | #define GPIO4_IRQSTATUS_RAW_1 0x28 |
73 | #define GPIO4_IRQSTATUS_0 0x2C |
74 | #define GPIO4_IRQSTATUS_1 0x30 |
75 | #define GPIO4_IRQSTATUS_SET_0 0x34 |
76 | #define GPIO4_IRQSTATUS_SET_1 0x38 |
77 | #define GPIO4_IRQSTATUS_CLR_0 0x3C |
78 | #define GPIO4_IRQSTATUS_CLR_1 0x40 |
79 | #define GPIO4_IRQWAKEN_0 0x44 |
80 | #define GPIO4_IRQWAKEN_1 0x48 |
81 | #define GPIO4_SYSSTATUS 0x114 |
82 | #define GPIO4_WAKEUPENABLE 0x120 |
83 | #define GPIO4_CTRL 0x130 |
84 | #define GPIO4_OE 0x134 |
85 | #define GPIO4_DATAIN 0x138 |
86 | #define GPIO4_DATAOUT 0x13C |
87 | #define GPIO4_LEVELDETECT0 0x140 |
88 | #define GPIO4_LEVELDETECT1 0x144 |
89 | #define GPIO4_RISINGDETECT 0x148 |
90 | #define GPIO4_FALLINGDETECT 0x14C |
91 | #define GPIO4_DEBOUNCENABLE 0x150 |
92 | #define GPIO4_DEBOUNCINGTIME 0x154 |
93 | #define GPIO4_CLEARWKUPENA 0x180 |
94 | #define GPIO4_SETWKUENA 0x184 |
95 | #define GPIO4_CLEARDATAOUT 0x190 |
96 | #define GPIO4_SETDATAOUT 0x194 |
97 | |
98 | /* AM335X registers */ |
99 | #define GPIO_AM335X_REVISION 0x00 |
100 | #define GPIO_AM335X_SYSCONFIG 0x10 |
101 | #define GPIO_AM335X_IRQSTATUS_RAW_0 0x24 |
102 | #define GPIO_AM335X_IRQSTATUS_RAW_1 0x28 |
103 | #define GPIO_AM335X_IRQSTATUS_0 0x2C |
104 | #define GPIO_AM335X_IRQSTATUS_1 0x30 |
105 | #define GPIO_AM335X_IRQSTATUS_SET_0 0x34 |
106 | #define GPIO_AM335X_IRQSTATUS_SET_1 0x38 |
107 | #define GPIO_AM335X_IRQSTATUS_CLR_0 0x3c |
108 | #define GPIO_AM335X_IRQSTATUS_CLR_1 0x40 |
109 | #define GPIO_AM335X_IRQWAKEN_0 0x44 |
110 | #define GPIO_AM335X_IRQWAKEN_1 0x48 |
111 | #define GPIO_AM335X_SYSSTATUS 0x114 |
112 | #define GPIO_AM335X_CTRL 0x130 |
113 | #define GPIO_AM335X_OE 0x134 |
114 | #define GPIO_AM335X_DATAIN 0x138 |
115 | #define GPIO_AM335X_DATAOUT 0x13C |
116 | #define GPIO_AM335X_LEVELDETECT0 0x140 |
117 | #define GPIO_AM335X_LEVELDETECT1 0x144 |
118 | #define GPIO_AM335X_RISINGDETECT 0x148 |
119 | #define GPIO_AM335X_FALLINGDETECT 0x14C |
120 | #define GPIO_AM335X_DEBOUNCENABLE 0x150 |
121 | #define GPIO_AM335X_DEBOUNCINGTIME 0x154 |
122 | #define GPIO_AM335X_CLEARDATAOUT 0x190 |
123 | #define GPIO_AM335X_SETDATAOUT 0x194 |
124 | |
125 | #define GPIO_NUM_PINS 32 |
126 | |
127 | struct intrhand { |
128 | int (*ih_func)(void *); /* handler */ |
129 | void *ih_arg; /* arg for handler */ |
130 | int ih_ipl; /* IPL_* */ |
131 | int ih_irq; /* IRQ number */ |
132 | int ih_gpio; /* gpio pin */ |
133 | struct evcount ih_count; |
134 | char *ih_name; |
135 | }; |
136 | |
137 | struct omgpio_regs { |
138 | u_int32_t revision; |
139 | u_int32_t sysconfig; |
140 | u_int32_t irqstatus_raw0; /* omap4/am335x only */ |
141 | u_int32_t irqstatus_raw1; /* omap4/am335x only */ |
142 | u_int32_t irqstatus0; |
143 | u_int32_t irqstatus1; |
144 | u_int32_t irqstatus_set0; |
145 | u_int32_t irqstatus_set1; |
146 | u_int32_t irqstatus_clear0; |
147 | u_int32_t irqstatus_clear1; |
148 | u_int32_t irqwaken0; |
149 | u_int32_t irqwaken1; |
150 | u_int32_t sysstatus; |
151 | u_int32_t wakeupenable; /* omap3/omap4 only */ |
152 | u_int32_t ctrl; |
153 | u_int32_t oe; |
154 | u_int32_t datain; |
155 | u_int32_t dataout; |
156 | u_int32_t leveldetect0; |
157 | u_int32_t leveldetect1; |
158 | u_int32_t risingdetect; |
159 | u_int32_t fallingdetect; |
160 | u_int32_t debounceenable; |
161 | u_int32_t debouncingtime; |
162 | u_int32_t clearwkupena; /* omap3/omap4 only */ |
163 | u_int32_t setwkupena; /* omap3/omap4 only */ |
164 | u_int32_t cleardataout; |
165 | u_int32_t setdataout; |
166 | }; |
167 | |
168 | struct omgpio_softc { |
169 | struct device sc_dev; |
170 | bus_space_tag_t sc_iot; |
171 | bus_space_handle_t sc_ioh; |
172 | void *sc_ih_h; |
173 | void *sc_ih_l; |
174 | int sc_max_il; |
175 | int sc_min_il; |
176 | int sc_irq; |
177 | struct intrhand *sc_handlers[GPIO_NUM_PINS]; |
178 | int sc_omap_ver; |
179 | struct gpio_chipset_tag sc_gpio_gc; |
180 | gpio_pin_t sc_gpio_pins[GPIO_NUM_PINS]; |
181 | struct omgpio_regs sc_regs; |
182 | }; |
183 | |
184 | #define GPIO_PIN_TO_INST(x) ((x) >> 5) |
185 | #define GPIO_PIN_TO_OFFSET(x) ((x) & 0x1f) |
186 | #define DEVNAME(sc) ((sc)->sc_dev.dv_xname) |
187 | #define READ4(sc, reg) omgpio_read4(sc, reg) |
188 | #define WRITE4(sc, reg, val) omgpio_write4(sc, reg, val) |
189 | |
190 | u_int32_t omgpio_read4(struct omgpio_softc *, u_int32_t); |
191 | void omgpio_write4(struct omgpio_softc *, u_int32_t, u_int32_t); |
192 | int omgpio_match(struct device *, void *, void *); |
193 | void omgpio_attach(struct device *, struct device *, void *); |
194 | void omgpio_recalc_interrupts(struct omgpio_softc *); |
195 | int omgpio_irq(void *); |
196 | int omgpio_irq_dummy(void *); |
197 | int omgpio_pin_dir_read(struct omgpio_softc *, unsigned int); |
198 | void omgpio_pin_dir_write(struct omgpio_softc *, unsigned int, unsigned int); |
199 | |
200 | struct cfattach omgpio_ca = { |
201 | sizeof (struct omgpio_softc), omgpio_match, omgpio_attach |
202 | }; |
203 | |
204 | struct cfdriver omgpio_cd = { |
205 | NULL, "omgpio", DV_DULL |
206 | }; |
207 | |
208 | u_int32_t |
209 | omgpio_read4(struct omgpio_softc *sc, u_int32_t reg) |
210 | { |
211 | if(reg == -1) |
212 | panic("%s: Invalid register address", DEVNAME(sc)); |
213 | |
214 | return bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)); |
215 | } |
216 | |
217 | void |
218 | omgpio_write4(struct omgpio_softc *sc, u_int32_t reg, u_int32_t val) |
219 | { |
220 | if(reg == -1) |
221 | panic("%s: Invalid register address", DEVNAME(sc)); |
222 | |
223 | bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)); |
224 | } |
225 | |
226 | int |
227 | omgpio_match(struct device *parent, void *v, void *aux) |
228 | { |
229 | switch (board_id) { |
230 | case BOARD_ID_OMAP3_BEAGLE: |
231 | case BOARD_ID_OMAP3_OVERO: |
232 | case BOARD_ID_AM335X_BEAGLEBONE: |
233 | case BOARD_ID_OMAP4_PANDA: |
234 | break; /* continue trying */ |
235 | default: |
236 | return 0; /* unknown */ |
237 | } |
238 | return (1); |
239 | } |
240 | |
241 | void |
242 | omgpio_attach(struct device *parent, struct device *self, void *args) |
243 | { |
244 | struct armv7_attach_args *aa = args; |
245 | struct omgpio_softc *sc = (struct omgpio_softc *) self; |
246 | struct gpiobus_attach_args gba; |
247 | u_int32_t rev; |
248 | int i; |
249 | |
250 | prcm_enablemodule(PRCM_GPIO0 + aa->aa_dev->unit); |
251 | |
252 | sc->sc_iot = aa->aa_iot; |
253 | if (bus_space_map(sc->sc_iot, aa->aa_dev->mem[0].addr, |
254 | aa->aa_dev->mem[0].size, 0, &sc->sc_ioh)) |
255 | panic("%s: bus_space_map failed!", DEVNAME(sc)); |
256 | |
257 | switch (board_id) { |
258 | case BOARD_ID_OMAP3_BEAGLE: |
259 | case BOARD_ID_OMAP3_OVERO: |
260 | sc->sc_regs.revision = GPIO3_REVISION; |
261 | sc->sc_regs.sysconfig = GPIO3_SYSCONFIG; |
262 | sc->sc_regs.irqstatus_raw0 = -1; |
263 | sc->sc_regs.irqstatus_raw1 = -1; |
264 | sc->sc_regs.irqstatus0 = GPIO3_IRQSTATUS1; |
265 | sc->sc_regs.irqstatus1 = GPIO3_IRQSTATUS2; |
266 | sc->sc_regs.irqstatus_set0 = GPIO3_SETIRQENABLE1; |
267 | sc->sc_regs.irqstatus_set1 = GPIO3_SETIRQENABLE2; |
268 | sc->sc_regs.irqstatus_clear0 = GPIO3_CLEARIRQENABLE1; |
269 | sc->sc_regs.irqstatus_clear1 = GPIO3_CLEARIRQENABLE2; |
270 | sc->sc_regs.irqwaken0 = -1; |
271 | sc->sc_regs.irqwaken1 = -1; |
272 | sc->sc_regs.sysstatus = GPIO3_SYSSTATUS; |
273 | sc->sc_regs.wakeupenable = GPIO3_WAKEUPENABLE; |
274 | sc->sc_regs.ctrl = GPIO3_CTRL; |
275 | sc->sc_regs.oe = GPIO3_OE; |
276 | sc->sc_regs.datain = GPIO3_DATAIN; |
277 | sc->sc_regs.dataout = GPIO3_DATAOUT; |
278 | sc->sc_regs.leveldetect0 = GPIO3_LEVELDETECT0; |
279 | sc->sc_regs.leveldetect1 = GPIO3_LEVELDETECT1; |
280 | sc->sc_regs.risingdetect = GPIO3_RISINGDETECT; |
281 | sc->sc_regs.fallingdetect = GPIO3_FALLINGDETECT; |
282 | sc->sc_regs.debounceenable = GPIO3_DEBOUNCENABLE; |
283 | sc->sc_regs.debouncingtime = GPIO3_DEBOUNCINGTIME; |
284 | sc->sc_regs.clearwkupena = GPIO3_CLEARWKUENA; |
285 | sc->sc_regs.setwkupena = GPIO3_SETWKUENA; |
286 | sc->sc_regs.cleardataout = GPIO3_CLEARDATAOUT; |
287 | sc->sc_regs.setdataout = GPIO3_SETDATAOUT; |
288 | break; |
289 | case BOARD_ID_OMAP4_PANDA: |
290 | sc->sc_regs.revision = GPIO4_REVISION; |
291 | sc->sc_regs.sysconfig = GPIO4_SYSCONFIG; |
292 | sc->sc_regs.irqstatus_raw0 = GPIO4_IRQSTATUS_RAW_0; |
293 | sc->sc_regs.irqstatus_raw1 = GPIO4_IRQSTATUS_RAW_1; |
294 | sc->sc_regs.irqstatus0 = GPIO4_IRQSTATUS_0; |
295 | sc->sc_regs.irqstatus1 = GPIO4_IRQSTATUS_1; |
296 | sc->sc_regs.irqstatus_set0 = GPIO4_IRQSTATUS_SET_0; |
297 | sc->sc_regs.irqstatus_set1 = GPIO4_IRQSTATUS_SET_1; |
298 | sc->sc_regs.irqstatus_clear0 = GPIO4_IRQSTATUS_CLR_0; |
299 | sc->sc_regs.irqstatus_clear1 = GPIO4_IRQSTATUS_CLR_1; |
300 | sc->sc_regs.irqwaken0 = GPIO4_IRQWAKEN_0; |
301 | sc->sc_regs.irqwaken1 = GPIO4_IRQWAKEN_1; |
302 | sc->sc_regs.sysstatus = GPIO4_SYSSTATUS; |
303 | sc->sc_regs.wakeupenable = GPIO4_WAKEUPENABLE; |
304 | sc->sc_regs.ctrl = GPIO4_CTRL; |
305 | sc->sc_regs.oe = GPIO4_OE; |
306 | sc->sc_regs.datain = GPIO4_DATAIN; |
307 | sc->sc_regs.dataout = GPIO4_DATAOUT; |
308 | sc->sc_regs.leveldetect0 = GPIO4_LEVELDETECT0; |
309 | sc->sc_regs.leveldetect1 = GPIO4_LEVELDETECT1; |
310 | sc->sc_regs.risingdetect = GPIO4_RISINGDETECT; |
311 | sc->sc_regs.fallingdetect = GPIO4_FALLINGDETECT; |
312 | sc->sc_regs.debounceenable = GPIO4_DEBOUNCENABLE; |
313 | sc->sc_regs.debouncingtime = GPIO4_DEBOUNCINGTIME; |
314 | sc->sc_regs.clearwkupena = GPIO4_CLEARWKUPENA; |
315 | sc->sc_regs.setwkupena = GPIO4_SETWKUENA; |
316 | sc->sc_regs.cleardataout = GPIO4_CLEARDATAOUT; |
317 | sc->sc_regs.setdataout = GPIO4_SETDATAOUT; |
318 | break; |
319 | case BOARD_ID_AM335X_BEAGLEBONE: |
320 | sc->sc_regs.revision = GPIO_AM335X_REVISION; |
321 | sc->sc_regs.sysconfig = GPIO_AM335X_SYSCONFIG; |
322 | sc->sc_regs.irqstatus_raw0 = GPIO_AM335X_IRQSTATUS_RAW_0; |
323 | sc->sc_regs.irqstatus_raw1 = GPIO_AM335X_IRQSTATUS_RAW_1; |
324 | sc->sc_regs.irqstatus0 = GPIO_AM335X_IRQSTATUS_0; |
325 | sc->sc_regs.irqstatus1 = GPIO_AM335X_IRQSTATUS_1; |
326 | sc->sc_regs.irqstatus_set0 = GPIO_AM335X_IRQSTATUS_SET_0; |
327 | sc->sc_regs.irqstatus_set1 = GPIO_AM335X_IRQSTATUS_SET_1; |
328 | sc->sc_regs.irqstatus_clear0 = GPIO_AM335X_IRQSTATUS_CLR_0; |
329 | sc->sc_regs.irqstatus_clear1 = GPIO_AM335X_IRQSTATUS_CLR_1; |
330 | sc->sc_regs.irqwaken0 = GPIO_AM335X_IRQWAKEN_0; |
331 | sc->sc_regs.irqwaken1 = GPIO_AM335X_IRQWAKEN_1; |
332 | sc->sc_regs.sysstatus = GPIO_AM335X_SYSSTATUS; |
333 | sc->sc_regs.wakeupenable = -1; |
334 | sc->sc_regs.ctrl = GPIO_AM335X_CTRL; |
335 | sc->sc_regs.oe = GPIO_AM335X_OE; |
336 | sc->sc_regs.datain = GPIO_AM335X_DATAIN; |
337 | sc->sc_regs.dataout = GPIO_AM335X_DATAOUT; |
338 | sc->sc_regs.leveldetect0 = GPIO_AM335X_LEVELDETECT0; |
339 | sc->sc_regs.leveldetect1 = GPIO_AM335X_LEVELDETECT1; |
340 | sc->sc_regs.risingdetect = GPIO_AM335X_RISINGDETECT; |
341 | sc->sc_regs.fallingdetect = GPIO_AM335X_FALLINGDETECT; |
342 | sc->sc_regs.debounceenable = GPIO_AM335X_DEBOUNCENABLE; |
343 | sc->sc_regs.debouncingtime = GPIO_AM335X_DEBOUNCINGTIME; |
344 | sc->sc_regs.clearwkupena = -1; |
345 | sc->sc_regs.setwkupena = -1; |
346 | sc->sc_regs.cleardataout = GPIO_AM335X_CLEARDATAOUT; |
347 | sc->sc_regs.setdataout = GPIO_AM335X_SETDATAOUT; |
348 | break; |
349 | } |
350 | |
351 | rev = READ4(sc, sc->sc_regs.revision); |
352 | |
353 | printf(": rev %d.%d\n", rev >> 4 & 0xf, rev & 0xf); |
354 | |
355 | sc->sc_irq = aa->aa_dev->irq[0]; |
356 | |
357 | WRITE4(sc, sc->sc_regs.irqstatus_clear0, ~0); |
358 | WRITE4(sc, sc->sc_regs.irqstatus_clear1, ~0); |
359 | |
360 | /* XXX - SYSCONFIG */ |
361 | /* XXX - CTRL */ |
362 | /* XXX - DEBOUNCE */ |
363 | |
364 | for (i = 0; i < GPIO_NUM_PINS; i++) { |
365 | sc->sc_gpio_pins[i].pin_num = i; |
366 | sc->sc_gpio_pins[i].pin_caps = GPIO_PIN_INPUT | |
367 | GPIO_PIN_OUTPUT | GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN; |
368 | sc->sc_gpio_pins[i].pin_state = omgpio_pin_read(sc, i) ? |
369 | GPIO_PIN_HIGH : GPIO_PIN_LOW; |
370 | sc->sc_gpio_pins[i].pin_flags = GPIO_PIN_SET; |
371 | } |
372 | |
373 | sc->sc_gpio_gc.gp_cookie = sc; |
374 | sc->sc_gpio_gc.gp_pin_read = omgpio_pin_read; |
375 | sc->sc_gpio_gc.gp_pin_write = omgpio_pin_write; |
376 | sc->sc_gpio_gc.gp_pin_ctl = omgpio_pin_ctl; |
377 | |
378 | gba.gba_name = "gpio"; |
379 | gba.gba_gc = &sc->sc_gpio_gc; |
380 | gba.gba_pins = sc->sc_gpio_pins; |
381 | gba.gba_npins = GPIO_NUM_PINS; |
382 | |
383 | #if NGPIO > 0 |
384 | config_found(&sc->sc_dev, &gba, gpiobus_print); |
385 | #endif |
386 | } |
387 | |
388 | /* XXX - This assumes MCU INTERRUPTS are IRQ1, and DSP are IRQ2 */ |
389 | |
390 | #if 0 |
391 | /* XXX - FIND THESE REGISTERS !!! */ |
392 | unsigned int |
393 | omgpio_get_function(unsigned int gpio, unsigned int fn) |
394 | { |
395 | return 0; |
396 | } |
397 | |
398 | void |
399 | omgpio_set_function(unsigned int gpio, unsigned int fn) |
400 | { |
401 | } |
402 | #endif |
403 | |
404 | unsigned int |
405 | omgpio_get_bit(unsigned int gpio) |
406 | { |
407 | struct omgpio_softc *sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)]; |
408 | |
409 | return omgpio_pin_read(sc, GPIO_PIN_TO_OFFSET(gpio)); |
410 | } |
411 | |
412 | void |
413 | omgpio_set_bit(unsigned int gpio) |
414 | { |
415 | struct omgpio_softc *sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)]; |
416 | |
417 | omgpio_pin_write(sc, GPIO_PIN_TO_OFFSET(gpio), GPIO_PIN_HIGH); |
418 | } |
419 | |
420 | void |
421 | omgpio_clear_bit(unsigned int gpio) |
422 | { |
423 | struct omgpio_softc *sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)]; |
424 | |
425 | omgpio_pin_write(sc, GPIO_PIN_TO_OFFSET(gpio), GPIO_PIN_LOW); |
426 | } |
427 | |
428 | void |
429 | omgpio_set_dir(unsigned int gpio, unsigned int dir) |
430 | { |
431 | struct omgpio_softc *sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)]; |
432 | |
433 | omgpio_pin_dir_write(sc, GPIO_PIN_TO_OFFSET(gpio), dir); |
434 | } |
435 | |
436 | int |
437 | omgpio_pin_read(void *arg, int pin) |
438 | { |
439 | struct omgpio_softc *sc = arg; |
440 | u_int32_t reg; |
441 | |
442 | if(omgpio_pin_dir_read(sc, pin) == OMGPIO_DIR_IN) |
443 | reg = READ4(sc, sc->sc_regs.datain); |
444 | else |
445 | reg = READ4(sc, sc->sc_regs.dataout); |
446 | return (reg >> GPIO_PIN_TO_OFFSET(pin)) & 0x1; |
447 | } |
448 | |
449 | void |
450 | omgpio_pin_write(void *arg, int pin, int value) |
451 | { |
452 | struct omgpio_softc *sc = arg; |
453 | |
454 | if (value) |
455 | WRITE4(sc, sc->sc_regs.setdataout, |
456 | 1 << GPIO_PIN_TO_OFFSET(pin)); |
457 | else |
458 | WRITE4(sc, sc->sc_regs.cleardataout, |
459 | 1 << GPIO_PIN_TO_OFFSET(pin)); |
460 | } |
461 | |
462 | void |
463 | omgpio_pin_ctl(void *arg, int pin, int flags) |
464 | { |
465 | struct omgpio_softc *sc = arg; |
466 | |
467 | if (flags & GPIO_PIN_INPUT) |
468 | omgpio_pin_dir_write(sc, pin, OMGPIO_DIR_IN); |
469 | else if (flags & GPIO_PIN_OUTPUT) |
470 | omgpio_pin_dir_write(sc, pin, OMGPIO_DIR_OUT); |
471 | |
472 | if (board_id == BOARD_ID_AM335X_BEAGLEBONE) |
473 | sitara_cm_padconf_set_gpioflags( |
474 | sc->sc_dev.dv_unit * GPIO_NUM_PINS + pin, flags); |
475 | } |
476 | |
477 | void |
478 | omgpio_pin_dir_write(struct omgpio_softc *sc, unsigned int gpio, |
479 | unsigned int dir) |
480 | { |
481 | int s; |
482 | u_int32_t reg; |
483 | |
484 | s = splhigh(); |
485 | |
486 | reg = READ4(sc, sc->sc_regs.oe); |
487 | if (dir == OMGPIO_DIR_IN) |
488 | reg |= 1 << GPIO_PIN_TO_OFFSET(gpio); |
489 | else |
490 | reg &= ~(1 << GPIO_PIN_TO_OFFSET(gpio)); |
491 | WRITE4(sc, sc->sc_regs.oe, reg); |
492 | |
493 | splx(s); |
494 | } |
495 | |
496 | int |
497 | omgpio_pin_dir_read(struct omgpio_softc *sc, unsigned int gpio) |
498 | { |
499 | u_int32_t reg; |
500 | reg = READ4(sc, sc->sc_regs.oe); |
501 | if (reg & (1 << GPIO_PIN_TO_OFFSET(gpio))) |
502 | return OMGPIO_DIR_IN; |
503 | else |
504 | return OMGPIO_DIR_OUT; |
505 | } |
506 | |
507 | #if 0 |
508 | void |
509 | omgpio_clear_intr(struct omgpio_softc *sc, unsigned int gpio) |
510 | { |
511 | struct omgpio_softc *sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)]; |
512 | |
513 | WRITE4(sc, sc->sc_regs.irqstatus0, 1 << GPIO_PIN_TO_OFFSET(gpio)); |
514 | } |
515 | |
516 | void |
517 | omgpio_intr_mask(struct omgpio_softc *sc, unsigned int gpio) |
518 | { |
519 | struct omgpio_softc *sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)]; |
520 | |
521 | WRITE4(sc, sc->sc_regs.irqstatus_clear0, 1 << GPIO_PIN_TO_OFFSET(gpio)); |
522 | } |
523 | |
524 | void |
525 | omgpio_intr_unmask(struct omgpio_softc *sc, unsigned int gpio) |
526 | { |
527 | struct omgpio_softc *sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)]; |
528 | |
529 | WRITE4(sc, sc->sc_regs.irqstatus_set0, 1 << GPIO_PIN_TO_OFFSET(gpio)); |
530 | } |
531 | |
532 | void |
533 | omgpio_intr_level(struct omgpio_softc *sc, unsigned int gpio, unsigned int level) |
534 | { |
535 | u_int32_t fe, re, l0, l1, bit; |
536 | struct omgpio_softc *sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)]; |
537 | int s; |
538 | |
539 | s = splhigh(); |
540 | |
541 | fe = READ4(sc, sc->sc_regs.fallingdetect); |
542 | re = READ4(sc, sc->sc_regs.risingdetect); |
543 | l0 = READ4(sc, sc->sc_regs.leveldetect0); |
544 | l1 = READ4(sc, sc->sc_regs.leveldetect1); |
545 | |
546 | bit = 1 << GPIO_PIN_TO_OFFSET(gpio); |
547 | |
548 | switch (level) { |
549 | case IST_NONE: |
550 | fe &= ~bit; |
551 | re &= ~bit; |
552 | l0 &= ~bit; |
553 | l1 &= ~bit; |
554 | break; |
555 | case IST_EDGE_FALLING: |
556 | fe |= bit; |
557 | re &= ~bit; |
558 | l0 &= ~bit; |
559 | l1 &= ~bit; |
560 | break; |
561 | case IST_EDGE_RISING: |
562 | fe &= ~bit; |
563 | re |= bit; |
564 | l0 &= ~bit; |
565 | l1 &= ~bit; |
566 | break; |
567 | case IST_PULSE: /* XXX */ |
568 | /* FALLTHRU */ |
569 | case IST_EDGE_BOTH: |
570 | fe |= bit; |
571 | re |= bit; |
572 | l0 &= ~bit; |
573 | l1 &= ~bit; |
574 | break; |
575 | case IST_LEVEL_LOW: |
576 | fe &= ~bit; |
577 | re &= ~bit; |
578 | l0 |= bit; |
579 | l1 &= ~bit; |
580 | break; |
581 | case IST_LEVEL_HIGH: |
582 | fe &= ~bit; |
583 | re &= ~bit; |
584 | l0 &= ~bit; |
585 | l1 |= bit; |
586 | break; |
587 | default: |
588 | panic("omgpio_intr_level: bad level: %d", level); |
589 | break; |
590 | } |
591 | |
592 | WRITE4(sc, sc->sc_regs.fallingdetect, fe); |
593 | WRITE4(sc, sc->sc_regs.risingdetect, re); |
594 | WRITE4(sc, sc->sc_regs.leveldetect0, l0); |
595 | WRITE4(sc, sc->sc_regs.leveldetect1, l1); |
596 | |
597 | splx(s); |
598 | } |
599 | |
600 | void * |
601 | omgpio_intr_establish(struct omgpio_softc *sc, unsigned int gpio, int level, int spl, |
602 | int (*func)(void *), void *arg, char *name) |
603 | { |
604 | int psw; |
605 | struct intrhand *ih; |
606 | struct omgpio_softc *sc; |
607 | |
608 | /* |
609 | * XXX - is gpio here the pin or the interrupt number |
610 | * which is 96 + gpio pin? |
611 | */ |
612 | |
613 | if (GPIO_PIN_TO_INST(gpio) > omgpio_cd.cd_ndevs) |
614 | panic("omgpio_intr_establish: bogus irqnumber %d: %s", |
615 | gpio, name); |
616 | |
617 | sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)]; |
618 | |
619 | if (sc->sc_handlers[GPIO_PIN_TO_OFFSET(gpio)] != NULL) |
620 | panic("omgpio_intr_establish: gpio pin busy %d old %s new %s", |
621 | gpio, sc->sc_handlers[GPIO_PIN_TO_OFFSET(gpio)]->ih_name, |
622 | name); |
623 | |
624 | psw = disable_interrupts(PSR_I); |
625 | |
626 | /* no point in sleeping unless someone can free memory. */ |
627 | ih = (struct intrhand *)malloc( sizeof *ih, M_DEVBUF, |
628 | cold ? M_NOWAIT : M_WAITOK); |
629 | if (ih == NULL) |
630 | panic("intr_establish: can't malloc handler info"); |
631 | ih->ih_func = func; |
632 | ih->ih_arg = arg; |
633 | ih->ih_ipl = level; |
634 | ih->ih_gpio = gpio; |
635 | ih->ih_irq = gpio + 512; |
636 | ih->ih_name = name; |
637 | |
638 | sc->sc_handlers[GPIO_PIN_TO_OFFSET(gpio)] = ih; |
639 | |
640 | evcount_attach(&ih->ih_count, name, &ih->ih_irq); |
641 | |
642 | omgpio_intr_level(gpio, level); |
643 | omgpio_intr_unmask(gpio); |
644 | |
645 | omgpio_recalc_interrupts(sc); |
646 | |
647 | restore_interrupts(psw); |
648 | |
649 | return (ih); |
650 | } |
651 | |
652 | void |
653 | omgpio_intr_disestablish(struct omgpio_softc *sc, void *cookie) |
654 | { |
655 | int psw; |
656 | struct intrhand *ih = cookie; |
657 | struct omgpio_softc *sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(ih->ih_gpio)]; |
658 | int gpio = ih->ih_gpio; |
659 | psw = disable_interrupts(PSR_I); |
660 | |
661 | ih = sc->sc_handlers[GPIO_PIN_TO_OFFSET(gpio)]; |
662 | sc->sc_handlers[GPIO_PIN_TO_OFFSET(gpio)] = NULL; |
663 | |
664 | evcount_detach(&ih->ih_count); |
665 | |
666 | free(ih, M_DEVBUF, 0); |
667 | |
668 | omgpio_intr_level(gpio, IST_NONE); |
669 | omgpio_intr_mask(gpio); |
670 | omgpio_clear_intr(gpio); /* Just in case */ |
671 | |
672 | omgpio_recalc_interrupts(sc); |
673 | |
674 | restore_interrupts(psw); |
675 | } |
676 | |
677 | int |
678 | omgpio_irq(void *v) |
679 | { |
680 | struct omgpio_softc *sc = v; |
681 | u_int32_t pending; |
682 | struct intrhand *ih; |
683 | int bit; |
684 | |
685 | pending = READ4(sc, omgpio.irqstatus0); |
686 | |
687 | while (pending != 0) { |
688 | bit = ffs(pending) - 1; |
689 | ih = sc->sc_handlers[bit]; |
690 | |
691 | if (ih != NULL) { |
692 | if (ih->ih_func(ih->ih_arg)) |
693 | ih->ih_count.ec_count++; |
694 | omgpio_clear_intr(ih->ih_gpio); |
695 | } else { |
696 | panic("omgpio: irq fired no handler, gpio %x %x %x", |
697 | sc->sc_dev.dv_unit * 32 + bit, pending, |
698 | READ4(sc, omgpio.irqstatus0) |
699 | |
700 | ); |
701 | } |
702 | pending &= ~(1 << bit); |
703 | } |
704 | return 1; |
705 | } |
706 | |
707 | int |
708 | omgpio_irq_dummy(void *v) |
709 | { |
710 | return 0; |
711 | } |
712 | |
713 | void |
714 | omgpio_recalc_interrupts(struct omgpio_softc *sc) |
715 | { |
716 | struct intrhand *ih; |
717 | int max = IPL_NONE; |
718 | int min = IPL_HIGH; |
719 | int i; |
720 | |
721 | for (i = 0; i < GPIO_NUM_PINS; i++) { |
722 | ih = sc->sc_handlers[i]; |
723 | if (ih != NULL) { |
724 | if (ih->ih_ipl > max) |
725 | max = ih->ih_ipl; |
726 | |
727 | if (ih->ih_ipl < min) |
728 | min = ih->ih_ipl; |
729 | } |
730 | } |
731 | if (max == IPL_NONE) |
732 | min = IPL_NONE; |
733 | |
734 | #if 0 |
735 | if ((max == IPL_NONE || max != sc->sc_max_il) && sc->sc_ih_h != NULL) |
736 | arm_intr_disestablish(sc->sc_ih_h); |
737 | |
738 | if (max != IPL_NONE && max != sc->sc_max_il) { |
739 | sc->sc_ih_h = arm_intr_establish(sc->sc_irq, max, omgpio_irq, |
740 | sc, NULL); |
741 | } |
742 | #else |
743 | if (sc->sc_ih_h != NULL) |
744 | arm_intr_disestablish(sc->sc_ih_h); |
745 | |
746 | if (max != IPL_NONE) { |
747 | sc->sc_ih_h = arm_intr_establish(sc->sc_irq, max, omgpio_irq, |
748 | sc, NULL); |
749 | } |
750 | #endif |
751 | |
752 | sc->sc_max_il = max; |
753 | |
754 | if (sc->sc_ih_l != NULL) |
755 | arm_intr_disestablish(sc->sc_ih_l); |
756 | |
757 | if (max != min) { |
758 | sc->sc_ih_h = arm_intr_establish(sc->sc_irq, min, |
759 | omgpio_irq_dummy, sc, NULL); |
760 | } |
761 | sc->sc_min_il = min; |
762 | } |
763 | #endif |