Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+67 −18
Original line number Diff line number Diff line
@@ -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;

@@ -238,33 +240,38 @@ 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);
}

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

@@ -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
@@ -384,7 +433,7 @@ void __init ixp2000_init_irq(void)

	/*
	 * 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);
+2 −1
Original line number Diff line number Diff line
@@ -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)
{
+12 −19
Original line number Diff line number Diff line
/*
 * include/asm-arm/arch-ixp2000/ixp2000-gpio.h
 * include/asm-arm/arch-ixp2000/gpio.h
 *
 * Copyright (C) 2002 Intel Corporation.
 *
@@ -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)
{
@@ -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_ */
+1 −21
Original line number Diff line number Diff line
@@ -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__ */