[ARM] pxa: move IRQ handling of GPIO 0 and 1 outside of gpio.c
This is part of the work making gpio.c generic enough, the changes include: 1. move IRQ handling of GPIO 0 and 1 outside (and back into irq.c) 2. pxa_init_gpio() accepts a range for muxed GPIO IRQs, and an IRQ number for the muxed GPIOs 3. __gpio_is_occupied() and __gpio_is_inverted() are made inline, and are moved into <mach/gpio.h> instead of generic gpio.c Signed-off-by: Eric Miao <eric.miao@marvell.com>
This commit is contained in:
parent
7ebc8d56f4
commit
a58fbcd8ad
|
@ -9,13 +9,11 @@
|
|||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
typedef int (*set_wake_t)(unsigned int, unsigned int);
|
||||
|
||||
struct sys_timer;
|
||||
|
||||
extern struct sys_timer pxa_timer;
|
||||
extern void __init pxa_init_irq(int irq_nr, set_wake_t fn);
|
||||
extern void __init pxa_init_gpio(int gpio_nr, set_wake_t fn);
|
||||
extern void __init pxa_init_irq(int irq_nr,
|
||||
int (*set_wake)(unsigned int, unsigned int));
|
||||
extern void __init pxa25x_init_irq(void);
|
||||
extern void __init pxa27x_init_irq(void);
|
||||
extern void __init pxa3xx_init_irq(void);
|
||||
|
|
|
@ -45,18 +45,6 @@ struct pxa_gpio_chip {
|
|||
|
||||
int pxa_last_gpio;
|
||||
|
||||
#ifdef CONFIG_CPU_PXA26x
|
||||
/* GPIO86/87/88/89 on PXA26x have their direction bits in GPDR2 inverted,
|
||||
* as well as their Alternate Function value being '1' for GPIO in GAFRx.
|
||||
*/
|
||||
static int __gpio_is_inverted(unsigned gpio)
|
||||
{
|
||||
return cpu_is_pxa25x() && gpio > 85;
|
||||
}
|
||||
#else
|
||||
#define __gpio_is_inverted(gpio) (0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Configure pins for GPIO or other functions
|
||||
*/
|
||||
|
@ -185,6 +173,20 @@ static struct pxa_gpio_chip pxa_gpio_chip[] = {
|
|||
#endif
|
||||
};
|
||||
|
||||
static void __init pxa_init_gpio_chip(int gpio_nr)
|
||||
{
|
||||
int i, gpio;
|
||||
|
||||
/* add a GPIO chip for each register bank.
|
||||
* the last PXA25x register only contains 21 GPIOs
|
||||
*/
|
||||
for (gpio = 0, i = 0; gpio < gpio_nr; gpio += 32, i++) {
|
||||
if (gpio + 32 > gpio_nr)
|
||||
pxa_gpio_chip[i].chip.ngpio = gpio_nr - gpio;
|
||||
gpiochip_add(&pxa_gpio_chip[i].chip);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* PXA GPIO edge detection for IRQs:
|
||||
* IRQs are generated on Falling-Edge, Rising-Edge, or both.
|
||||
|
@ -195,27 +197,6 @@ static unsigned long GPIO_IRQ_rising_edge[4];
|
|||
static unsigned long GPIO_IRQ_falling_edge[4];
|
||||
static unsigned long GPIO_IRQ_mask[4];
|
||||
|
||||
/*
|
||||
* On PXA25x and PXA27x, GAFRx and GPDRx together decide the alternate
|
||||
* function of a GPIO, and GPDRx cannot be altered once configured. It
|
||||
* is attributed as "occupied" here (I know this terminology isn't
|
||||
* accurate, you are welcome to propose a better one :-)
|
||||
*/
|
||||
static int __gpio_is_occupied(unsigned gpio)
|
||||
{
|
||||
if (cpu_is_pxa27x() || cpu_is_pxa25x()) {
|
||||
int af = (GAFR(gpio) >> ((gpio & 0xf) * 2)) & 0x3;
|
||||
int dir = GPDR(gpio) & GPIO_bit(gpio);
|
||||
|
||||
if (__gpio_is_inverted(gpio))
|
||||
return af != 1 || dir == 0;
|
||||
else
|
||||
return af != 0 || dir != 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pxa_gpio_irq_type(unsigned int irq, unsigned int type)
|
||||
{
|
||||
int gpio, idx;
|
||||
|
@ -261,33 +242,6 @@ static int pxa_gpio_irq_type(unsigned int irq, unsigned int type)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* GPIO IRQs must be acknowledged. This is for GPIO 0 and 1.
|
||||
*/
|
||||
|
||||
static void pxa_ack_low_gpio(unsigned int irq)
|
||||
{
|
||||
GEDR0 = (1 << (irq - IRQ_GPIO0));
|
||||
}
|
||||
|
||||
static void pxa_mask_low_gpio(unsigned int irq)
|
||||
{
|
||||
ICMR &= ~(1 << (irq - PXA_IRQ(0)));
|
||||
}
|
||||
|
||||
static void pxa_unmask_low_gpio(unsigned int irq)
|
||||
{
|
||||
ICMR |= 1 << (irq - PXA_IRQ(0));
|
||||
}
|
||||
|
||||
static struct irq_chip pxa_low_gpio_chip = {
|
||||
.name = "GPIO-l",
|
||||
.ack = pxa_ack_low_gpio,
|
||||
.mask = pxa_mask_low_gpio,
|
||||
.unmask = pxa_unmask_low_gpio,
|
||||
.set_type = pxa_gpio_irq_type,
|
||||
};
|
||||
|
||||
/*
|
||||
* Demux handler for GPIO>=2 edge detect interrupts
|
||||
*/
|
||||
|
@ -352,48 +306,31 @@ static struct irq_chip pxa_muxed_gpio_chip = {
|
|||
.set_type = pxa_gpio_irq_type,
|
||||
};
|
||||
|
||||
void __init pxa_init_gpio(int gpio_nr, set_wake_t fn)
|
||||
void __init pxa_init_gpio(int mux_irq, int start, int end, set_wake_t fn)
|
||||
{
|
||||
int irq, i, gpio;
|
||||
int irq, i;
|
||||
|
||||
pxa_last_gpio = gpio_nr - 1;
|
||||
pxa_last_gpio = end;
|
||||
|
||||
/* clear all GPIO edge detects */
|
||||
for (i = 0; i < gpio_nr; i += 32) {
|
||||
GFER(i) = 0;
|
||||
GRER(i) = 0;
|
||||
GEDR(i) = GEDR(i);
|
||||
for (i = start; i <= end; i += 32) {
|
||||
GFER(i) &= ~GPIO_IRQ_mask[i];
|
||||
GRER(i) &= ~GPIO_IRQ_mask[i];
|
||||
GEDR(i) = GPIO_IRQ_mask[i];
|
||||
}
|
||||
|
||||
/* GPIO 0 and 1 must have their mask bit always set */
|
||||
GPIO_IRQ_mask[0] = 3;
|
||||
|
||||
for (irq = IRQ_GPIO0; irq <= IRQ_GPIO1; irq++) {
|
||||
set_irq_chip(irq, &pxa_low_gpio_chip);
|
||||
set_irq_handler(irq, handle_edge_irq);
|
||||
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
|
||||
}
|
||||
|
||||
for (irq = IRQ_GPIO(2); irq < IRQ_GPIO(gpio_nr); irq++) {
|
||||
for (irq = gpio_to_irq(start); irq <= gpio_to_irq(end); irq++) {
|
||||
set_irq_chip(irq, &pxa_muxed_gpio_chip);
|
||||
set_irq_handler(irq, handle_edge_irq);
|
||||
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
|
||||
}
|
||||
|
||||
/* Install handler for GPIO>=2 edge detect interrupts */
|
||||
set_irq_chained_handler(IRQ_GPIO_2_x, pxa_gpio_demux_handler);
|
||||
|
||||
pxa_low_gpio_chip.set_wake = fn;
|
||||
set_irq_chained_handler(mux_irq, pxa_gpio_demux_handler);
|
||||
pxa_muxed_gpio_chip.set_wake = fn;
|
||||
|
||||
/* add a GPIO chip for each register bank.
|
||||
* the last PXA25x register only contains 21 GPIOs
|
||||
*/
|
||||
for (gpio = 0, i = 0; gpio < gpio_nr; gpio += 32, i++) {
|
||||
if (gpio + 32 > gpio_nr)
|
||||
pxa_gpio_chip[i].chip.ngpio = gpio_nr - gpio;
|
||||
gpiochip_add(&pxa_gpio_chip[i].chip);
|
||||
}
|
||||
/* Initialize GPIO chips */
|
||||
pxa_init_gpio_chip(end + 1);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
|
|
@ -56,10 +56,44 @@ static inline void gpio_set_value(unsigned gpio, int value)
|
|||
}
|
||||
}
|
||||
|
||||
#define gpio_cansleep __gpio_cansleep
|
||||
|
||||
#define gpio_cansleep __gpio_cansleep
|
||||
#define gpio_to_irq(gpio) IRQ_GPIO(gpio)
|
||||
#define irq_to_gpio(irq) IRQ_TO_GPIO(irq)
|
||||
|
||||
|
||||
#ifdef CONFIG_CPU_PXA26x
|
||||
/* GPIO86/87/88/89 on PXA26x have their direction bits in GPDR2 inverted,
|
||||
* as well as their Alternate Function value being '1' for GPIO in GAFRx.
|
||||
*/
|
||||
static inline int __gpio_is_inverted(unsigned gpio)
|
||||
{
|
||||
return cpu_is_pxa25x() && gpio > 85;
|
||||
}
|
||||
#else
|
||||
static inline int __gpio_is_inverted(unsigned gpio) { return 0; }
|
||||
#endif
|
||||
|
||||
/*
|
||||
* On PXA25x and PXA27x, GAFRx and GPDRx together decide the alternate
|
||||
* function of a GPIO, and GPDRx cannot be altered once configured. It
|
||||
* is attributed as "occupied" here (I know this terminology isn't
|
||||
* accurate, you are welcome to propose a better one :-)
|
||||
*/
|
||||
static inline int __gpio_is_occupied(unsigned gpio)
|
||||
{
|
||||
if (cpu_is_pxa27x() || cpu_is_pxa25x()) {
|
||||
int af = (GAFR(gpio) >> ((gpio & 0xf) * 2)) & 0x3;
|
||||
int dir = GPDR(gpio) & GPIO_bit(gpio);
|
||||
|
||||
if (__gpio_is_inverted(gpio))
|
||||
return af != 1 || dir == 0;
|
||||
else
|
||||
return af != 0 || dir != 0;
|
||||
} else
|
||||
return GPDR(gpio) & GPIO_bit(gpio);
|
||||
}
|
||||
|
||||
typedef int (*set_wake_t)(unsigned int irq, unsigned int on);
|
||||
|
||||
extern void pxa_init_gpio(int mux_irq, int start, int end, set_wake_t fn);
|
||||
#endif
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <asm/irq.h>
|
||||
#include <asm/mach/irq.h>
|
||||
#include <mach/pxa-regs.h>
|
||||
#include <mach/gpio.h>
|
||||
|
||||
#include "generic.h"
|
||||
|
||||
|
@ -51,6 +52,72 @@ static struct irq_chip pxa_internal_irq_chip = {
|
|||
.unmask = pxa_unmask_irq,
|
||||
};
|
||||
|
||||
/*
|
||||
* GPIO IRQs for GPIO 0 and 1
|
||||
*/
|
||||
static int pxa_set_low_gpio_type(unsigned int irq, unsigned int type)
|
||||
{
|
||||
int gpio = irq - IRQ_GPIO0;
|
||||
|
||||
if (__gpio_is_occupied(gpio)) {
|
||||
pr_err("%s failed: GPIO is configured\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (type & IRQ_TYPE_EDGE_RISING)
|
||||
GRER0 |= GPIO_bit(gpio);
|
||||
else
|
||||
GRER0 &= ~GPIO_bit(gpio);
|
||||
|
||||
if (type & IRQ_TYPE_EDGE_FALLING)
|
||||
GFER0 |= GPIO_bit(gpio);
|
||||
else
|
||||
GFER0 &= ~GPIO_bit(gpio);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pxa_ack_low_gpio(unsigned int irq)
|
||||
{
|
||||
GEDR0 = (1 << (irq - IRQ_GPIO0));
|
||||
}
|
||||
|
||||
static void pxa_mask_low_gpio(unsigned int irq)
|
||||
{
|
||||
ICMR &= ~(1 << (irq - PXA_IRQ(0)));
|
||||
}
|
||||
|
||||
static void pxa_unmask_low_gpio(unsigned int irq)
|
||||
{
|
||||
ICMR |= 1 << (irq - PXA_IRQ(0));
|
||||
}
|
||||
|
||||
static struct irq_chip pxa_low_gpio_chip = {
|
||||
.name = "GPIO-l",
|
||||
.ack = pxa_ack_low_gpio,
|
||||
.mask = pxa_mask_low_gpio,
|
||||
.unmask = pxa_unmask_low_gpio,
|
||||
.set_type = pxa_set_low_gpio_type,
|
||||
};
|
||||
|
||||
static void __init pxa_init_low_gpio_irq(set_wake_t fn)
|
||||
{
|
||||
int irq;
|
||||
|
||||
/* clear edge detection on GPIO 0 and 1 */
|
||||
GFER0 &= ~0x3;
|
||||
GRER0 &= ~0x3;
|
||||
GEDR0 = 0x3;
|
||||
|
||||
for (irq = IRQ_GPIO0; irq <= IRQ_GPIO1; irq++) {
|
||||
set_irq_chip(irq, &pxa_low_gpio_chip);
|
||||
set_irq_handler(irq, handle_edge_irq);
|
||||
set_irq_flags(irq, IRQF_VALID);
|
||||
}
|
||||
|
||||
pxa_low_gpio_chip.set_wake = fn;
|
||||
}
|
||||
|
||||
void __init pxa_init_irq(int irq_nr, set_wake_t fn)
|
||||
{
|
||||
int irq;
|
||||
|
@ -72,6 +139,7 @@ void __init pxa_init_irq(int irq_nr, set_wake_t fn)
|
|||
}
|
||||
|
||||
pxa_internal_irq_chip.set_wake = fn;
|
||||
pxa_init_low_gpio_irq(fn);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/irqs.h>
|
||||
#include <mach/gpio.h>
|
||||
#include <mach/pxa25x.h>
|
||||
#include <mach/reset.h>
|
||||
#include <mach/pm.h>
|
||||
|
@ -308,14 +309,14 @@ set_pwer:
|
|||
void __init pxa25x_init_irq(void)
|
||||
{
|
||||
pxa_init_irq(32, pxa25x_set_wake);
|
||||
pxa_init_gpio(85, pxa25x_set_wake);
|
||||
pxa_init_gpio(IRQ_GPIO_2_x, 2, 84, pxa25x_set_wake);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CPU_PXA26x
|
||||
void __init pxa26x_init_irq(void)
|
||||
{
|
||||
pxa_init_irq(32, pxa25x_set_wake);
|
||||
pxa_init_gpio(90, pxa25x_set_wake);
|
||||
pxa_init_gpio(IRQ_GPIO_2_x, 2, 89, pxa25x_set_wake);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <mach/hardware.h>
|
||||
#include <asm/irq.h>
|
||||
#include <mach/irqs.h>
|
||||
#include <mach/gpio.h>
|
||||
#include <mach/pxa27x.h>
|
||||
#include <mach/reset.h>
|
||||
#include <mach/ohci.h>
|
||||
|
@ -330,7 +331,7 @@ static int pxa27x_set_wake(unsigned int irq, unsigned int on)
|
|||
void __init pxa27x_init_irq(void)
|
||||
{
|
||||
pxa_init_irq(34, pxa27x_set_wake);
|
||||
pxa_init_gpio(121, pxa27x_set_wake);
|
||||
pxa_init_gpio(IRQ_GPIO_2_x, 2, 120, pxa27x_set_wake);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <linux/sysdev.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/gpio.h>
|
||||
#include <mach/pxa3xx-regs.h>
|
||||
#include <mach/reset.h>
|
||||
#include <mach/ohci.h>
|
||||
|
@ -538,7 +539,7 @@ void __init pxa3xx_init_irq(void)
|
|||
__asm__ __volatile__("mcr p15, 0, %0, c15, c1, 0\n": :"r"(value));
|
||||
|
||||
pxa_init_irq(56, pxa3xx_set_wake);
|
||||
pxa_init_gpio(128, NULL);
|
||||
pxa_init_gpio(IRQ_GPIO_2_x, 2, 127, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue