1 /* $NetBSD: omap_gpio.c,v 1.4 2008/12/12 17:36:14 matt Exp $ */
4 * The OMAP GPIO Controller interface is inspired by pxa2x0_gpio.c
6 * Copyright 2003 Wasabi Systems, Inc.
9 * Written by Steve C. Woodford for Wasabi Systems, Inc.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed for the NetBSD Project by
22 * Wasabi Systems, Inc.
23 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
24 * or promote products derived from this software without specific prior
27 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
40 #include <sys/cdefs.h>
41 __KERNEL_RCSID(0, "$NetBSD: omap_gpio.c,v 1.4 2008/12/12 17:36:14 matt Exp $");
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/device.h>
46 #include <sys/malloc.h>
48 #include <machine/intr.h>
49 #include <machine/bus.h>
51 #include <arm/omap/omap_tipb.h>
52 #include <arm/omap/omap_gpio.h>
53 #include <arm/omap/omap_gpioreg.h>
57 #define GPIOEVNAMESZ 25
59 struct gpio_irq_handler
{
60 int (*gh_func
)(void *);
64 char name
[GPIOEVNAMESZ
];
68 struct omapgpio_softc
{
70 bus_space_tag_t sc_bust
;
71 bus_space_handle_t sc_bush
;
74 struct gpio_irq_handler
*sc_handlers
[GPIO_NPINS
];
77 static int omapgpio_match(device_t
, cfdata_t
, void *);
78 static void omapgpio_attach(device_t
, device_t
, void *);
80 extern struct cfdriver omapgpio_cd
;
82 CFATTACH_DECL_NEW(omapgpio
, sizeof(struct omapgpio_softc
),
83 omapgpio_match
, omapgpio_attach
, NULL
, NULL
);
85 static int omapgpio_intr(void *);
88 omapgpio_match(device_t parent
, cfdata_t cf
, void *aux
)
90 struct tipb_attach_args
*tipb
= aux
;
92 if (tipb
->tipb_addr
== -1 || tipb
->tipb_intr
== -1) {
93 panic("omapgpio must have addr and intr specified in config.");
96 tipb
->tipb_size
= OMAP_GPIO_SIZE
;
102 omapgpio_attach(device_t parent
, device_t self
, void *aux
)
104 struct omapgpio_softc
*sc
= device_private(self
);
105 struct tipb_attach_args
*tipb
= aux
;
109 sc
->sc_bust
= tipb
->tipb_iot
;
111 aprint_normal(": GPIO Controller\n");
113 if (device_unit(self
) > NOMAPGPIO
- 1) {
114 aprint_error("%s: Unsupported GPIO module unit number.\n",
115 device_xname(sc
->sc_dev
));
119 if (bus_space_map(sc
->sc_bust
, tipb
->tipb_addr
, tipb
->tipb_size
, 0,
121 aprint_error("%s: Failed to map registers.\n",
122 device_xname(sc
->sc_dev
));
127 memset(sc
->sc_handlers
, 0, sizeof(sc
->sc_handlers
));
129 /* Reset the module and wait for it to come back online. */
130 reg
= bus_space_read_4(sc
->sc_bust
, sc
->sc_bush
, GPIO_SYSCONFIG
);
131 bus_space_write_4(sc
->sc_bust
, sc
->sc_bush
, GPIO_SYSCONFIG
,
132 reg
| (1 << GPIO_SYSCONFIG_SOFTRESET
));
134 reg
= bus_space_read_4(sc
->sc_bust
, sc
->sc_bush
,
136 } while ((reg
& 1) == 0);
138 /* Enable sleep wakeups, and need "smart idle" mode for that, plus
139 autoidle the OCP interface clock. */
141 reg
= bus_space_read_4(sc
->sc_bust
, sc
->sc_bush
, GPIO_SYSCONFIG
);
142 reg
&= ~(GPIO_SYSCONFIG_IDLEMODE_MASK
<< GPIO_SYSCONFIG_IDLEMODE
);
143 bus_space_write_4(sc
->sc_bust
, sc
->sc_bush
, GPIO_SYSCONFIG
,
144 reg
| (1 << GPIO_SYSCONFIG_ENAWAKEUP
) |
145 (GPIO_SYSCONFIG_SMARTIDLE
<<
146 GPIO_SYSCONFIG_IDLEMODE
) |
147 (1 << GPIO_SYSCONFIG_AUTOIDLE
));
149 /* Install our ISR. */
150 sc
->sc_irqcookie
= omap_intr_establish(tipb
->tipb_intr
, IPL_BIO
,
151 device_xname(sc
->sc_dev
), omapgpio_intr
, sc
);
152 if (sc
->sc_irqcookie
== NULL
) {
153 aprint_error("%s: Failed to install interrupt handler.\n",
154 device_xname(sc
->sc_dev
));
160 omap_gpio_get_direction(u_int gpio
)
162 struct omapgpio_softc
*sc
;
166 KDASSERT(gpio
< NOMAPGPIO
* GPIO_NPINS
);
168 sc
= device_lookup_private(&omapgpio_cd
, GPIO_MODULE(gpio
));
170 panic("omapgpio: GPIO Module for pin %d not configured.\n", gpio
);
174 bit
= GPIO_BIT(gpio
);
175 reg
= bus_space_read_4(sc
->sc_bust
, sc
->sc_bush
, GPIO_DIRECTION
);
177 if ((reg
& bit
) == 0)
185 omap_gpio_set_direction(u_int gpio
, u_int dir
)
187 struct omapgpio_softc
*sc
;
190 KDASSERT(gpio
< NOMAPGPIO
* GPIO_NPINS
);
192 sc
= device_lookup_private(&omapgpio_cd
, GPIO_MODULE(gpio
));
194 panic("omapgpio: GPIO Module for pin %d not configured.\n", gpio
);
197 bit
= GPIO_BIT(gpio
);
198 reg
= bus_space_read_4(sc
->sc_bust
, sc
->sc_bush
,
201 if (GPIO_IS_IN(dir
)) {
203 bus_space_write_4(sc
->sc_bust
, sc
->sc_bush
,
204 GPIO_DIRECTION
, reg
| bit
);
207 bus_space_write_4(sc
->sc_bust
, sc
->sc_bush
,
208 GPIO_DIRECTION
, (reg
& ~bit
));
212 u_int
omap_gpio_read(u_int gpio
)
214 struct omapgpio_softc
*sc
;
217 sc
= device_lookup_private(&omapgpio_cd
, GPIO_MODULE(gpio
));
219 panic("omapgpio: GPIO Module for pin %d not configured.",
222 bit
= GPIO_BIT(gpio
);
224 return (bus_space_read_4(sc
->sc_bust
, sc
->sc_bush
,
225 GPIO_DATAIN
) & bit
) ? 1 : 0;
228 void omap_gpio_write(u_int gpio
, u_int value
)
230 struct omapgpio_softc
*sc
;
233 sc
= device_lookup_private(&omapgpio_cd
, GPIO_MODULE(gpio
));
235 panic("omapgpio: GPIO Module for pin %d not configured.",
238 bit
= GPIO_BIT(gpio
);
241 bus_space_write_4(sc
->sc_bust
, sc
->sc_bush
,
242 GPIO_SET_DATAOUT
, bit
);
244 bus_space_write_4(sc
->sc_bust
, sc
->sc_bush
,
245 GPIO_CLEAR_DATAOUT
, bit
);
250 omap_gpio_intr_establish(u_int gpio
, int level
, int spl
,
251 const char *name
, int (*func
)(void *), void *arg
)
253 struct omapgpio_softc
*sc
;
254 struct gpio_irq_handler
*gh
;
255 uint32_t bit
, levelreg
;
256 u_int dir
, relnum
, off
, reg
;
259 KDASSERT(gpio
< NOMAPGPIO
* GPIO_NPINS
);
261 sc
= device_lookup_private(&omapgpio_cd
, GPIO_MODULE(gpio
));
263 panic("omapgpio: GPIO Module for pin %d not configured.", gpio
);
266 dir
= omap_gpio_get_direction(gpio
);
267 if (!GPIO_IS_IN(dir
)) {
268 panic("omapgpio: GPIO pin %d not an input.", gpio
);
271 relnum
= GPIO_RELNUM(gpio
);
272 bit
= GPIO_BIT(gpio
);
274 if (sc
->sc_handlers
[relnum
] != NULL
) {
275 panic("omapgpio: Illegal shared interrupt on pin %d", gpio
);
278 gh
= malloc(sizeof(struct gpio_irq_handler
), M_DEVBUF
, M_NOWAIT
);
286 sc
->sc_handlers
[relnum
] = gh
;
288 snprintf(gh
->name
, GPIOEVNAMESZ
, "#%d %s", gpio
, name
);
289 evcnt_attach_dynamic(&gh
->ev
, EVCNT_TYPE_INTR
, NULL
,
290 "omap gpio", gh
->name
);
293 * Set up the level control.
295 * Note: Pins 0->7 on a module use EDGE_CTRL1, pins 8->15 use
300 case IST_EDGE_FALLING
:
301 case IST_LEVEL_LOW
: /* emulation */
304 case IST_EDGE_RISING
:
305 case IST_LEVEL_HIGH
: /* emulation */
312 panic("omapgpio: Unknown level %d.", level
);
316 off
= 2 * (relnum
& 7);
318 reg
= GPIO_EDGE_CTRL1
;
320 reg
= GPIO_EDGE_CTRL2
;
323 /* Temporarily set the level control to no trigger. */
324 levelreg
= bus_space_read_4(sc
->sc_bust
, sc
->sc_bush
, reg
);
325 levelreg
&= ~(0x3 << off
);
326 bus_space_write_4(sc
->sc_bust
, sc
->sc_bush
, reg
, levelreg
);
328 /* Clear the IRQSTATUS bit for the pin we're about to change. */
329 bus_space_write_4(sc
->sc_bust
, sc
->sc_bush
, GPIO_IRQSTATUS
, bit
);
331 /* Set the new level control value. */
332 levelreg
|= levelctrl
<< off
;
333 bus_space_write_4(sc
->sc_bust
, sc
->sc_bush
, reg
, levelreg
);
335 /* Disable sleep wakeups for this pin unless enabled later. */
336 bus_space_write_4(sc
->sc_bust
, sc
->sc_bush
, GPIO_CLEAR_WAKEUPENA
,
339 /* Enable interrupt generation for that pin. */
340 bus_space_write_4(sc
->sc_bust
, sc
->sc_bush
, GPIO_SET_IRQENABLE
,
347 omap_gpio_intr_disestablish(void *cookie
)
349 struct omapgpio_softc
*sc
;
350 struct gpio_irq_handler
*gh
= cookie
;
354 KDASSERT(cookie
!= NULL
);
357 sc
= device_lookup_private(&omapgpio_cd
, GPIO_MODULE(gpio
));
358 bit
= GPIO_BIT(gpio
);
359 relnum
= GPIO_RELNUM(gpio
);
360 evcnt_detach(&gh
->ev
);
362 /* Disable Wakeup enable for this gpio. */
363 bus_space_write_4(sc
->sc_bust
, sc
->sc_bush
, GPIO_CLEAR_WAKEUPENA
,
366 /* Disable interrupt generation for that gpio. */
367 bus_space_write_4(sc
->sc_bust
, sc
->sc_bush
, GPIO_CLEAR_IRQENABLE
,
371 sc
->sc_handlers
[relnum
] = NULL
;
378 omap_gpio_intr_mask(void *cookie
)
380 struct omapgpio_softc
*sc
;
381 struct gpio_irq_handler
*gh
= cookie
;
385 KDASSERT(cookie
!= NULL
);
388 sc
= device_lookup_private(&omapgpio_cd
, GPIO_MODULE(gpio
));
389 bit
= GPIO_BIT(gpio
);
390 relnum
= GPIO_RELNUM(gpio
);
392 /* Disable interrupt generation for that gpio. */
393 bus_space_write_4(sc
->sc_bust
, sc
->sc_bush
, GPIO_CLEAR_IRQENABLE
,
400 omap_gpio_intr_unmask(void *cookie
)
402 struct omapgpio_softc
*sc
;
403 struct gpio_irq_handler
*gh
= cookie
;
407 KDASSERT(cookie
!= NULL
);
410 sc
= device_lookup_private(&omapgpio_cd
, GPIO_MODULE(gpio
));
411 bit
= GPIO_BIT(gpio
);
412 relnum
= GPIO_RELNUM(gpio
);
414 /* Enable interrupt generation for that pin. */
415 bus_space_write_4(sc
->sc_bust
, sc
->sc_bush
, GPIO_SET_IRQENABLE
,
422 omap_gpio_intr_wakeup(void *cookie
, int enable
)
424 struct omapgpio_softc
*sc
;
425 struct gpio_irq_handler
*gh
= cookie
;
429 KDASSERT(cookie
!= NULL
);
432 sc
= device_lookup_private(&omapgpio_cd
, GPIO_MODULE(gpio
));
433 bit
= GPIO_BIT(gpio
);
434 relnum
= GPIO_RELNUM(gpio
);
437 bus_space_write_4(sc
->sc_bust
, sc
->sc_bush
,
438 GPIO_SET_WAKEUPENA
, bit
);
440 bus_space_write_4(sc
->sc_bust
, sc
->sc_bush
,
441 GPIO_CLEAR_WAKEUPENA
, bit
);
445 omapgpio_intr(void *arg
)
447 struct omapgpio_softc
*sc
= arg
;
448 struct gpio_irq_handler
*gh
;
450 int idx
, handled
, s
, nattempts
;
452 /* Fetch the GPIO interrupts pending. */
453 irqs
= bus_space_read_4(sc
->sc_bust
, sc
->sc_bush
, GPIO_IRQSTATUS
);
454 irqs
&= GPIO_REG_MASK
;
455 bus_space_write_4(sc
->sc_bust
, sc
->sc_bush
, GPIO_IRQSTATUS
, irqs
);
458 * Since IRQSTATUS can change out from under us while we are busy
459 * servicing everything, keep on doing things until the IRQSTATUS
462 for (nattempts
= 0, handled
= 0;;) {
464 * Note: Apparently the GPIO block will set the bits in IRQSTATUS if
465 * the level trigger for that pin is set to anything other than NONE
466 * regardless of the IRQENABLE status. Just mask off the ones that we
467 * care about when processing the ISR.
471 /* Pretend that we handled everything. */
475 for (idx
= 0; idx
< GPIO_NPINS
; idx
++, irqs
>>= 1) {
479 if ((gh
= sc
->sc_handlers
[idx
]) == NULL
) {
480 printf("%s: unhandled GPIO interrupt. GPIO# %d\n",
481 device_xname(sc
->sc_dev
), idx
);
486 s
= _splraise(gh
->gh_spl
);
487 handled
|= (gh
->gh_func
)(gh
->gh_arg
);
491 /* Check IRQSTATUS again. */
492 irqs
= bus_space_read_4(sc
->sc_bust
, sc
->sc_bush
, GPIO_IRQSTATUS
);
493 irqs
&= GPIO_REG_MASK
;
495 /* Done servicing interrupts. */
497 } else if (nattempts
++ == 10000) {
498 /* TODO: Fix up the # of attempts and this logic after
499 some experimentation. */
501 /* Ensure that we don't get stuck here. */
502 panic("%s: Stuck in GPIO interrupt service routine.",
503 device_xname(sc
->sc_dev
));
505 bus_space_write_4(sc
->sc_bust
, sc
->sc_bush
, GPIO_IRQSTATUS
, irqs
);