Commit c4982887 authored by Lennert Buytenhek's avatar Lennert Buytenhek Committed by Russell King

[PATCH] ARM: 2744/1: ixp2000 gpio irq support

Patch from Lennert Buytenhek

This patch cleans up the ixp2000 gpio irq code and implements the
set_irq_type method for gpio irqs so that users can select for which
events (falling edge/rising edge/level low/level high) on the gpio
pin they want the corresponding gpio irq to be triggered.
Signed-off-by: default avatarLennert Buytenhek <buytenh@wantstofly.org>
Signed-off-by: Deepak Saxena
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent c6b56949
...@@ -40,6 +40,8 @@ ...@@ -40,6 +40,8 @@
#include <asm/mach/time.h> #include <asm/mach/time.h>
#include <asm/mach/irq.h> #include <asm/mach/irq.h>
#include <asm/arch/gpio.h>
static DEFINE_SPINLOCK(ixp2000_slowport_lock); static DEFINE_SPINLOCK(ixp2000_slowport_lock);
static unsigned long ixp2000_slowport_irq_flags; static unsigned long ixp2000_slowport_irq_flags;
...@@ -238,33 +240,38 @@ void __init ixp2000_init_time(unsigned long tick_rate) ...@@ -238,33 +240,38 @@ void __init ixp2000_init_time(unsigned long tick_rate)
/************************************************************************* /*************************************************************************
* GPIO helpers * GPIO helpers
*************************************************************************/ *************************************************************************/
static unsigned long GPIO_IRQ_rising_edge;
static unsigned long GPIO_IRQ_falling_edge; static unsigned long GPIO_IRQ_falling_edge;
static unsigned long GPIO_IRQ_rising_edge;
static unsigned long GPIO_IRQ_level_low; static unsigned long GPIO_IRQ_level_low;
static unsigned long GPIO_IRQ_level_high; static unsigned long GPIO_IRQ_level_high;
void gpio_line_config(int line, int style) static void update_gpio_int_csrs(void)
{
ixp2000_reg_write(IXP2000_GPIO_FEDR, GPIO_IRQ_falling_edge);
ixp2000_reg_write(IXP2000_GPIO_REDR, GPIO_IRQ_rising_edge);
ixp2000_reg_write(IXP2000_GPIO_LSLR, GPIO_IRQ_level_low);
ixp2000_reg_write(IXP2000_GPIO_LSHR, GPIO_IRQ_level_high);
}
void gpio_line_config(int line, int direction)
{ {
unsigned long flags; unsigned long flags;
local_irq_save(flags); local_irq_save(flags);
if (direction == GPIO_OUT) {
irq_desc[line + IRQ_IXP2000_GPIO0].valid = 0;
if(style == GPIO_OUT) {
/* if it's an output, it ain't an interrupt anymore */ /* if it's an output, it ain't an interrupt anymore */
ixp2000_reg_write(IXP2000_GPIO_PDSR, (1 << line));
GPIO_IRQ_falling_edge &= ~(1 << line); GPIO_IRQ_falling_edge &= ~(1 << line);
GPIO_IRQ_rising_edge &= ~(1 << line); GPIO_IRQ_rising_edge &= ~(1 << line);
GPIO_IRQ_level_low &= ~(1 << line); GPIO_IRQ_level_low &= ~(1 << line);
GPIO_IRQ_level_high &= ~(1 << line); GPIO_IRQ_level_high &= ~(1 << line);
ixp2000_reg_write(IXP2000_GPIO_FEDR, GPIO_IRQ_falling_edge); update_gpio_int_csrs();
ixp2000_reg_write(IXP2000_GPIO_REDR, GPIO_IRQ_rising_edge);
ixp2000_reg_write(IXP2000_GPIO_LSHR, GPIO_IRQ_level_high);
ixp2000_reg_write(IXP2000_GPIO_LSLR, GPIO_IRQ_level_low);
irq_desc[line+IRQ_IXP2000_GPIO0].valid = 0;
} else if(style == GPIO_IN) {
ixp2000_reg_write(IXP2000_GPIO_PDCR, (1 << line));
}
ixp2000_reg_write(IXP2000_GPIO_PDSR, 1 << line);
} else if (direction == GPIO_IN) {
ixp2000_reg_write(IXP2000_GPIO_PDCR, 1 << line);
}
local_irq_restore(flags); local_irq_restore(flags);
} }
...@@ -285,9 +292,50 @@ static void ixp2000_GPIO_irq_handler(unsigned int irq, struct irqdesc *desc, str ...@@ -285,9 +292,50 @@ static void ixp2000_GPIO_irq_handler(unsigned int irq, struct irqdesc *desc, str
} }
} }
static int ixp2000_GPIO_irq_type(unsigned int irq, unsigned int type)
{
int line = irq - IRQ_IXP2000_GPIO0;
/*
* First, configure this GPIO line as an input.
*/
ixp2000_reg_write(IXP2000_GPIO_PDCR, 1 << line);
/*
* Then, set the proper trigger type.
*/
if (type & IRQT_FALLING)
GPIO_IRQ_falling_edge |= 1 << line;
else
GPIO_IRQ_falling_edge &= ~(1 << line);
if (type & IRQT_RISING)
GPIO_IRQ_rising_edge |= 1 << line;
else
GPIO_IRQ_rising_edge &= ~(1 << line);
if (type & IRQT_LOW)
GPIO_IRQ_level_low |= 1 << line;
else
GPIO_IRQ_level_low &= ~(1 << line);
if (type & IRQT_HIGH)
GPIO_IRQ_level_high |= 1 << line;
else
GPIO_IRQ_level_high &= ~(1 << line);
update_gpio_int_csrs();
/*
* Finally, mark the corresponding IRQ as valid.
*/
irq_desc[irq].valid = 1;
return 0;
}
static void ixp2000_GPIO_irq_mask_ack(unsigned int irq) static void ixp2000_GPIO_irq_mask_ack(unsigned int irq)
{ {
ixp2000_reg_write(IXP2000_GPIO_INCR, (1 << (irq - IRQ_IXP2000_GPIO0))); ixp2000_reg_write(IXP2000_GPIO_INCR, (1 << (irq - IRQ_IXP2000_GPIO0)));
ixp2000_reg_write(IXP2000_GPIO_EDSR, (1 << (irq - IRQ_IXP2000_GPIO0)));
ixp2000_reg_write(IXP2000_GPIO_LDSR, (1 << (irq - IRQ_IXP2000_GPIO0)));
ixp2000_reg_write(IXP2000_GPIO_INST, (1 << (irq - IRQ_IXP2000_GPIO0))); ixp2000_reg_write(IXP2000_GPIO_INST, (1 << (irq - IRQ_IXP2000_GPIO0)));
} }
...@@ -302,6 +350,7 @@ static void ixp2000_GPIO_irq_unmask(unsigned int irq) ...@@ -302,6 +350,7 @@ static void ixp2000_GPIO_irq_unmask(unsigned int irq)
} }
static struct irqchip ixp2000_GPIO_irq_chip = { static struct irqchip ixp2000_GPIO_irq_chip = {
.type = ixp2000_GPIO_irq_type,
.ack = ixp2000_GPIO_irq_mask_ack, .ack = ixp2000_GPIO_irq_mask_ack,
.mask = ixp2000_GPIO_irq_mask, .mask = ixp2000_GPIO_irq_mask,
.unmask = ixp2000_GPIO_irq_unmask .unmask = ixp2000_GPIO_irq_unmask
...@@ -375,7 +424,7 @@ void __init ixp2000_init_irq(void) ...@@ -375,7 +424,7 @@ void __init ixp2000_init_irq(void)
* our mask/unmask code much simpler. * our mask/unmask code much simpler.
*/ */
for (irq = IRQ_IXP2000_SOFT_INT; irq <= IRQ_IXP2000_THDB3; irq++) { for (irq = IRQ_IXP2000_SOFT_INT; irq <= IRQ_IXP2000_THDB3; irq++) {
if((1 << irq) & IXP2000_VALID_IRQ_MASK) { if ((1 << irq) & IXP2000_VALID_IRQ_MASK) {
set_irq_chip(irq, &ixp2000_irq_chip); set_irq_chip(irq, &ixp2000_irq_chip);
set_irq_handler(irq, do_level_IRQ); set_irq_handler(irq, do_level_IRQ);
set_irq_flags(irq, IRQF_VALID); set_irq_flags(irq, IRQF_VALID);
...@@ -384,7 +433,7 @@ void __init ixp2000_init_irq(void) ...@@ -384,7 +433,7 @@ void __init ixp2000_init_irq(void)
/* /*
* GPIO IRQs are invalid until someone sets the interrupt mode * GPIO IRQs are invalid until someone sets the interrupt mode
* by calling gpio_line_set(); * by calling set_irq_type().
*/ */
for (irq = IRQ_IXP2000_GPIO0; irq <= IRQ_IXP2000_GPIO7; irq++) { for (irq = IRQ_IXP2000_GPIO0; irq <= IRQ_IXP2000_GPIO7; irq++) {
set_irq_chip(irq, &ixp2000_GPIO_irq_chip); set_irq_chip(irq, &ixp2000_GPIO_irq_chip);
......
...@@ -33,7 +33,8 @@ ...@@ -33,7 +33,8 @@
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/i2c-algo-bit.h> #include <linux/i2c-algo-bit.h>
#include <asm/hardware.h> /* Pick up IXP42000-specific bits */ #include <asm/hardware.h> /* Pick up IXP2000-specific bits */
#include <asm/arch/gpio.h>
static inline int ixp2000_scl_pin(void *data) static inline int ixp2000_scl_pin(void *data)
{ {
......
/* /*
* include/asm-arm/arch-ixp2000/ixp2000-gpio.h * include/asm-arm/arch-ixp2000/gpio.h
* *
* Copyright (C) 2002 Intel Corporation. * Copyright (C) 2002 Intel Corporation.
* *
...@@ -16,26 +16,18 @@ ...@@ -16,26 +16,18 @@
* Use this instead of directly setting the GPIO registers. * Use this instead of directly setting the GPIO registers.
* GPIOs may also be used as GPIOs (e.g. for emulating i2c/smb) * GPIOs may also be used as GPIOs (e.g. for emulating i2c/smb)
*/ */
#ifndef _ASM_ARCH_IXP2000_GPIO_H_ #ifndef __ASM_ARCH_GPIO_H
#define _ASM_ARCH_IXP2000_GPIO_H_ #define __ASM_ARCH_GPIO_H
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
#define GPIO_OUT 0x0
#define GPIO_IN 0x80 #define GPIO_IN 0
#define GPIO_OUT 1
#define IXP2000_GPIO_LOW 0 #define IXP2000_GPIO_LOW 0
#define IXP2000_GPIO_HIGH 1 #define IXP2000_GPIO_HIGH 1
#define GPIO_NO_EDGES 0 extern void gpio_line_config(int line, int direction);
#define GPIO_FALLING_EDGE 1
#define GPIO_RISING_EDGE 2
#define GPIO_BOTH_EDGES 3
#define GPIO_LEVEL_LOW 4
#define GPIO_LEVEL_HIGH 8
extern void set_GPIO_IRQ_edge(int gpio_nr, int edge);
extern void set_GPIO_IRQ_level(int gpio_nr, int level);
extern void gpio_line_config(int line, int style);
static inline int gpio_line_get(int line) static inline int gpio_line_get(int line)
{ {
...@@ -45,11 +37,12 @@ static inline int gpio_line_get(int line) ...@@ -45,11 +37,12 @@ static inline int gpio_line_get(int line)
static inline void gpio_line_set(int line, int value) static inline void gpio_line_set(int line, int value)
{ {
if (value == IXP2000_GPIO_HIGH) { if (value == IXP2000_GPIO_HIGH) {
ixp_reg_write(IXP2000_GPIO_POSR, BIT(line)); ixp2000_reg_write(IXP2000_GPIO_POSR, 1 << line);
} else if (value == IXP2000_GPIO_LOW) } else if (value == IXP2000_GPIO_LOW) {
ixp_reg_write(IXP2000_GPIO_POCR, BIT(line)); ixp2000_reg_write(IXP2000_GPIO_POCR, 1 << line);
}
} }
#endif /* !__ASSEMBLY__ */ #endif /* !__ASSEMBLY__ */
#endif /* ASM_ARCH_IXP2000_GPIO_H_ */
#endif /* ASM_ARCH_IXP2000_GPIO_H_ */
...@@ -138,30 +138,10 @@ struct ixp2000_flash_data { ...@@ -138,30 +138,10 @@ struct ixp2000_flash_data {
unsigned long (*bank_setup)(unsigned long); unsigned long (*bank_setup)(unsigned long);
}; };
/*
* GPIO helper functions
*/
#define GPIO_IN 0
#define GPIO_OUT 1
extern void gpio_line_config(int line, int style);
static inline int gpio_line_get(int line)
{
return (((*IXP2000_GPIO_PLR) >> line) & 1);
}
static inline void gpio_line_set(int line, int value)
{
if (value)
ixp2000_reg_write(IXP2000_GPIO_POSR, (1 << line));
else
ixp2000_reg_write(IXP2000_GPIO_POCR, (1 << line));
}
struct ixp2000_i2c_pins { struct ixp2000_i2c_pins {
unsigned long sda_pin; unsigned long sda_pin;
unsigned long scl_pin; unsigned long scl_pin;
}; };
#endif /* !__ASSEMBLY__ */ #endif /* !__ASSEMBLY__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment