[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:
@@ -9,13 +9,11 @@
|
|||||||
* published by the Free Software Foundation.
|
* published by the Free Software Foundation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef int (*set_wake_t)(unsigned int, unsigned int);
|
|
||||||
|
|
||||||
struct sys_timer;
|
struct sys_timer;
|
||||||
|
|
||||||
extern struct sys_timer pxa_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_irq(int irq_nr,
|
||||||
extern void __init pxa_init_gpio(int gpio_nr, set_wake_t fn);
|
int (*set_wake)(unsigned int, unsigned int));
|
||||||
extern void __init pxa25x_init_irq(void);
|
extern void __init pxa25x_init_irq(void);
|
||||||
extern void __init pxa27x_init_irq(void);
|
extern void __init pxa27x_init_irq(void);
|
||||||
extern void __init pxa3xx_init_irq(void);
|
extern void __init pxa3xx_init_irq(void);
|
||||||
|
@@ -45,18 +45,6 @@ struct pxa_gpio_chip {
|
|||||||
|
|
||||||
int pxa_last_gpio;
|
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
|
* Configure pins for GPIO or other functions
|
||||||
*/
|
*/
|
||||||
@@ -185,6 +173,20 @@ static struct pxa_gpio_chip pxa_gpio_chip[] = {
|
|||||||
#endif
|
#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:
|
* PXA GPIO edge detection for IRQs:
|
||||||
* IRQs are generated on Falling-Edge, Rising-Edge, or both.
|
* 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_falling_edge[4];
|
||||||
static unsigned long GPIO_IRQ_mask[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)
|
static int pxa_gpio_irq_type(unsigned int irq, unsigned int type)
|
||||||
{
|
{
|
||||||
int gpio, idx;
|
int gpio, idx;
|
||||||
@@ -261,33 +242,6 @@ static int pxa_gpio_irq_type(unsigned int irq, unsigned int type)
|
|||||||
return 0;
|
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
|
* 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,
|
.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 */
|
/* clear all GPIO edge detects */
|
||||||
for (i = 0; i < gpio_nr; i += 32) {
|
for (i = start; i <= end; i += 32) {
|
||||||
GFER(i) = 0;
|
GFER(i) &= ~GPIO_IRQ_mask[i];
|
||||||
GRER(i) = 0;
|
GRER(i) &= ~GPIO_IRQ_mask[i];
|
||||||
GEDR(i) = GEDR(i);
|
GEDR(i) = GPIO_IRQ_mask[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* GPIO 0 and 1 must have their mask bit always set */
|
for (irq = gpio_to_irq(start); irq <= gpio_to_irq(end); irq++) {
|
||||||
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++) {
|
|
||||||
set_irq_chip(irq, &pxa_muxed_gpio_chip);
|
set_irq_chip(irq, &pxa_muxed_gpio_chip);
|
||||||
set_irq_handler(irq, handle_edge_irq);
|
set_irq_handler(irq, handle_edge_irq);
|
||||||
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
|
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Install handler for GPIO>=2 edge detect interrupts */
|
/* Install handler for GPIO>=2 edge detect interrupts */
|
||||||
set_irq_chained_handler(IRQ_GPIO_2_x, pxa_gpio_demux_handler);
|
set_irq_chained_handler(mux_irq, pxa_gpio_demux_handler);
|
||||||
|
|
||||||
pxa_low_gpio_chip.set_wake = fn;
|
|
||||||
pxa_muxed_gpio_chip.set_wake = fn;
|
pxa_muxed_gpio_chip.set_wake = fn;
|
||||||
|
|
||||||
/* add a GPIO chip for each register bank.
|
/* Initialize GPIO chips */
|
||||||
* the last PXA25x register only contains 21 GPIOs
|
pxa_init_gpio_chip(end + 1);
|
||||||
*/
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#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 gpio_to_irq(gpio) IRQ_GPIO(gpio)
|
||||||
#define irq_to_gpio(irq) IRQ_TO_GPIO(irq)
|
#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
|
#endif
|
||||||
|
@@ -21,6 +21,7 @@
|
|||||||
#include <asm/irq.h>
|
#include <asm/irq.h>
|
||||||
#include <asm/mach/irq.h>
|
#include <asm/mach/irq.h>
|
||||||
#include <mach/pxa-regs.h>
|
#include <mach/pxa-regs.h>
|
||||||
|
#include <mach/gpio.h>
|
||||||
|
|
||||||
#include "generic.h"
|
#include "generic.h"
|
||||||
|
|
||||||
@@ -51,6 +52,72 @@ static struct irq_chip pxa_internal_irq_chip = {
|
|||||||
.unmask = pxa_unmask_irq,
|
.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)
|
void __init pxa_init_irq(int irq_nr, set_wake_t fn)
|
||||||
{
|
{
|
||||||
int irq;
|
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_internal_irq_chip.set_wake = fn;
|
||||||
|
pxa_init_low_gpio_irq(fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
|
@@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
#include <mach/hardware.h>
|
#include <mach/hardware.h>
|
||||||
#include <mach/irqs.h>
|
#include <mach/irqs.h>
|
||||||
|
#include <mach/gpio.h>
|
||||||
#include <mach/pxa25x.h>
|
#include <mach/pxa25x.h>
|
||||||
#include <mach/reset.h>
|
#include <mach/reset.h>
|
||||||
#include <mach/pm.h>
|
#include <mach/pm.h>
|
||||||
@@ -308,14 +309,14 @@ set_pwer:
|
|||||||
void __init pxa25x_init_irq(void)
|
void __init pxa25x_init_irq(void)
|
||||||
{
|
{
|
||||||
pxa_init_irq(32, pxa25x_set_wake);
|
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
|
#ifdef CONFIG_CPU_PXA26x
|
||||||
void __init pxa26x_init_irq(void)
|
void __init pxa26x_init_irq(void)
|
||||||
{
|
{
|
||||||
pxa_init_irq(32, pxa25x_set_wake);
|
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
|
#endif
|
||||||
|
|
||||||
|
@@ -21,6 +21,7 @@
|
|||||||
#include <mach/hardware.h>
|
#include <mach/hardware.h>
|
||||||
#include <asm/irq.h>
|
#include <asm/irq.h>
|
||||||
#include <mach/irqs.h>
|
#include <mach/irqs.h>
|
||||||
|
#include <mach/gpio.h>
|
||||||
#include <mach/pxa27x.h>
|
#include <mach/pxa27x.h>
|
||||||
#include <mach/reset.h>
|
#include <mach/reset.h>
|
||||||
#include <mach/ohci.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)
|
void __init pxa27x_init_irq(void)
|
||||||
{
|
{
|
||||||
pxa_init_irq(34, pxa27x_set_wake);
|
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 <linux/sysdev.h>
|
||||||
|
|
||||||
#include <mach/hardware.h>
|
#include <mach/hardware.h>
|
||||||
|
#include <mach/gpio.h>
|
||||||
#include <mach/pxa3xx-regs.h>
|
#include <mach/pxa3xx-regs.h>
|
||||||
#include <mach/reset.h>
|
#include <mach/reset.h>
|
||||||
#include <mach/ohci.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));
|
__asm__ __volatile__("mcr p15, 0, %0, c15, c1, 0\n": :"r"(value));
|
||||||
|
|
||||||
pxa_init_irq(56, pxa3xx_set_wake);
|
pxa_init_irq(56, pxa3xx_set_wake);
|
||||||
pxa_init_gpio(128, NULL);
|
pxa_init_gpio(IRQ_GPIO_2_x, 2, 127, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Reference in New Issue
Block a user