Commit a58fbcd8 authored by Eric Miao's avatar Eric Miao
Browse files

[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: default avatarEric Miao <eric.miao@marvell.com>
parent 7ebc8d56
Loading
Loading
Loading
Loading
+2 −4
Original line number Diff line number Diff line
@@ -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);
+25 −88
Original line number Diff line number Diff line
@@ -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
+36 −2
Original line number Diff line number Diff line
@@ -57,9 +57,43 @@ static inline void gpio_set_value(unsigned gpio, int value)
}

#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
+68 −0
Original line number Diff line number Diff line
@@ -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
+3 −2
Original line number Diff line number Diff line
@@ -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

Loading