Skip to content

Commit

Permalink
[PATCH] ARM: 2744/1: ixp2000 gpio irq support
Browse files Browse the repository at this point in the history
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: Lennert Buytenhek <buytenh@wantstofly.org>
Signed-off-by: Deepak Saxena
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
  • Loading branch information
Lennert Buytenhek authored and Russell King committed Jun 24, 2005
1 parent c6b5694 commit c498288
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 59 deletions.
85 changes: 67 additions & 18 deletions arch/arm/mach-ixp2000/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
#include <asm/mach/time.h>
#include <asm/mach/irq.h>

#include <asm/arch/gpio.h>

static DEFINE_SPINLOCK(ixp2000_slowport_lock);
static unsigned long ixp2000_slowport_irq_flags;

Expand Down Expand Up @@ -179,7 +181,7 @@ static int ixp2000_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)

/* clear timer 1 */
ixp2000_reg_write(IXP2000_T1_CLR, 1);

while ((next_jiffy_time - *missing_jiffy_timer_csr) > ticks_per_jiffy) {
timer_tick(regs);
next_jiffy_time -= ticks_per_jiffy;
Expand Down Expand Up @@ -238,35 +240,40 @@ void __init ixp2000_init_time(unsigned long tick_rate)
/*************************************************************************
* GPIO helpers
*************************************************************************/
static unsigned long GPIO_IRQ_rising_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_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;

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 */
ixp2000_reg_write(IXP2000_GPIO_PDSR, (1 << line));
GPIO_IRQ_falling_edge &= ~(1 << line);
GPIO_IRQ_rising_edge &= ~(1 << line);
GPIO_IRQ_level_low &= ~(1 << line);
GPIO_IRQ_level_high &= ~(1 << line);
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_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));
update_gpio_int_csrs();

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);
}
}


/*************************************************************************
Expand All @@ -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)
{
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)));
}

Expand All @@ -302,6 +350,7 @@ static void ixp2000_GPIO_irq_unmask(unsigned int irq)
}

static struct irqchip ixp2000_GPIO_irq_chip = {
.type = ixp2000_GPIO_irq_type,
.ack = ixp2000_GPIO_irq_mask_ack,
.mask = ixp2000_GPIO_irq_mask,
.unmask = ixp2000_GPIO_irq_unmask
Expand Down Expand Up @@ -338,7 +387,7 @@ static void ixp2000_irq_mask(unsigned int irq)

static void ixp2000_irq_unmask(unsigned int irq)
{
ixp2000_reg_write(IXP2000_IRQ_ENABLE_SET, (1 << irq));
ixp2000_reg_write(IXP2000_IRQ_ENABLE_SET, (1 << irq));
}

static struct irqchip ixp2000_irq_chip = {
Expand Down Expand Up @@ -375,16 +424,16 @@ void __init ixp2000_init_irq(void)
* our mask/unmask code much simpler.
*/
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_handler(irq, do_level_IRQ);
set_irq_flags(irq, IRQF_VALID);
} else set_irq_flags(irq, 0);
}

/*
* 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++) {
set_irq_chip(irq, &ixp2000_GPIO_irq_chip);
Expand Down
3 changes: 2 additions & 1 deletion drivers/i2c/busses/i2c-ixp2000.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@
#include <linux/i2c.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)
{
Expand Down
31 changes: 12 additions & 19 deletions include/asm-arm/arch-ixp2000/gpio.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* include/asm-arm/arch-ixp2000/ixp2000-gpio.h
* include/asm-arm/arch-ixp2000/gpio.h
*
* Copyright (C) 2002 Intel Corporation.
*
Expand All @@ -16,26 +16,18 @@
* Use this instead of directly setting the GPIO registers.
* GPIOs may also be used as GPIOs (e.g. for emulating i2c/smb)
*/
#ifndef _ASM_ARCH_IXP2000_GPIO_H_
#define _ASM_ARCH_IXP2000_GPIO_H_
#ifndef __ASM_ARCH_GPIO_H
#define __ASM_ARCH_GPIO_H

#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_HIGH 1

#define GPIO_NO_EDGES 0
#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);
extern void gpio_line_config(int line, int direction);

static inline int gpio_line_get(int line)
{
Expand All @@ -45,11 +37,12 @@ static inline int gpio_line_get(int line)
static inline void gpio_line_set(int line, int value)
{
if (value == IXP2000_GPIO_HIGH) {
ixp_reg_write(IXP2000_GPIO_POSR, BIT(line));
} else if (value == IXP2000_GPIO_LOW)
ixp_reg_write(IXP2000_GPIO_POCR, BIT(line));
ixp2000_reg_write(IXP2000_GPIO_POSR, 1 << line);
} else if (value == IXP2000_GPIO_LOW) {
ixp2000_reg_write(IXP2000_GPIO_POCR, 1 << line);
}
}

#endif /* !__ASSEMBLY__ */
#endif /* ASM_ARCH_IXP2000_GPIO_H_ */

#endif /* ASM_ARCH_IXP2000_GPIO_H_ */
22 changes: 1 addition & 21 deletions include/asm-arm/arch-ixp2000/platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,30 +138,10 @@ struct ixp2000_flash_data {
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 {
unsigned long sda_pin;
unsigned long scl_pin;
};


#endif /* !__ASSEMBLY__ */

0 comments on commit c498288

Please sign in to comment.