2006-01-09 17:05:41 +00:00
/*
2007-02-05 11:42:07 +01:00
* linux / arch / arm / mach - at91 / gpio . c
2006-01-09 17:05:41 +00:00
*
* Copyright ( C ) 2005 HP Labs
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*/
2006-09-27 13:23:00 +01:00
# include <linux/clk.h>
2006-01-09 17:05:41 +00:00
# include <linux/errno.h>
2006-07-01 23:01:50 +01:00
# include <linux/interrupt.h>
# include <linux/irq.h>
2006-01-09 17:05:41 +00:00
# include <linux/kernel.h>
# include <linux/list.h>
# include <linux/module.h>
# include <asm/io.h>
2006-06-20 19:53:16 +01:00
# include <asm/hardware.h>
2006-11-30 17:16:43 +01:00
# include <asm/arch/at91_pio.h>
2006-01-09 17:05:41 +00:00
# include <asm/arch/gpio.h>
2006-09-27 13:23:00 +01:00
# include "generic.h"
static struct at91_gpio_bank * gpio ;
static int gpio_banks ;
2006-01-09 17:05:41 +00:00
static inline void __iomem * pin_to_controller ( unsigned pin )
{
void __iomem * sys_base = ( void __iomem * ) AT91_VA_BASE_SYS ;
pin - = PIN_BASE ;
pin / = 32 ;
2006-09-27 13:23:00 +01:00
if ( likely ( pin < gpio_banks ) )
return sys_base + gpio [ pin ] . offset ;
2006-01-09 17:05:41 +00:00
return NULL ;
}
static inline unsigned pin_to_mask ( unsigned pin )
{
pin - = PIN_BASE ;
return 1 < < ( pin % 32 ) ;
}
/*--------------------------------------------------------------------------*/
/* Not all hardware capabilities are exposed through these calls; they
* only encapsulate the most common features and modes . ( So if you
* want to change signals in groups , do it directly . )
*
* Bootloaders will usually handle some of the pin multiplexing setup .
* The intent is certainly that by the time Linux is fully booted , all
* pins should have been fully initialized . These setup calls should
* only be used by board setup routines , or possibly in driver probe ( ) .
*
* For bootloaders doing all that setup , these calls could be inlined
* as NOPs so Linux won ' t duplicate any setup code
*/
2007-02-12 00:53:13 -08:00
/*
* mux the pin to the " GPIO " peripheral role .
*/
int __init_or_module at91_set_GPIO_periph ( unsigned pin , int use_pullup )
{
void __iomem * pio = pin_to_controller ( pin ) ;
unsigned mask = pin_to_mask ( pin ) ;
if ( ! pio )
return - EINVAL ;
__raw_writel ( mask , pio + PIO_IDR ) ;
__raw_writel ( mask , pio + ( use_pullup ? PIO_PUER : PIO_PUDR ) ) ;
__raw_writel ( mask , pio + PIO_PER ) ;
return 0 ;
}
EXPORT_SYMBOL ( at91_set_GPIO_periph ) ;
2006-01-09 17:05:41 +00:00
/*
* mux the pin to the " A " internal peripheral role .
*/
int __init_or_module at91_set_A_periph ( unsigned pin , int use_pullup )
{
void __iomem * pio = pin_to_controller ( pin ) ;
unsigned mask = pin_to_mask ( pin ) ;
if ( ! pio )
return - EINVAL ;
__raw_writel ( mask , pio + PIO_IDR ) ;
__raw_writel ( mask , pio + ( use_pullup ? PIO_PUER : PIO_PUDR ) ) ;
__raw_writel ( mask , pio + PIO_ASR ) ;
__raw_writel ( mask , pio + PIO_PDR ) ;
return 0 ;
}
EXPORT_SYMBOL ( at91_set_A_periph ) ;
/*
* mux the pin to the " B " internal peripheral role .
*/
int __init_or_module at91_set_B_periph ( unsigned pin , int use_pullup )
{
void __iomem * pio = pin_to_controller ( pin ) ;
unsigned mask = pin_to_mask ( pin ) ;
if ( ! pio )
return - EINVAL ;
__raw_writel ( mask , pio + PIO_IDR ) ;
__raw_writel ( mask , pio + ( use_pullup ? PIO_PUER : PIO_PUDR ) ) ;
__raw_writel ( mask , pio + PIO_BSR ) ;
__raw_writel ( mask , pio + PIO_PDR ) ;
return 0 ;
}
EXPORT_SYMBOL ( at91_set_B_periph ) ;
/*
* mux the pin to the gpio controller ( instead of " A " or " B " peripheral ) , and
* configure it for an input .
*/
int __init_or_module at91_set_gpio_input ( unsigned pin , int use_pullup )
{
void __iomem * pio = pin_to_controller ( pin ) ;
unsigned mask = pin_to_mask ( pin ) ;
if ( ! pio )
return - EINVAL ;
__raw_writel ( mask , pio + PIO_IDR ) ;
__raw_writel ( mask , pio + ( use_pullup ? PIO_PUER : PIO_PUDR ) ) ;
__raw_writel ( mask , pio + PIO_ODR ) ;
__raw_writel ( mask , pio + PIO_PER ) ;
return 0 ;
}
EXPORT_SYMBOL ( at91_set_gpio_input ) ;
/*
* mux the pin to the gpio controller ( instead of " A " or " B " peripheral ) ,
* and configure it for an output .
*/
int __init_or_module at91_set_gpio_output ( unsigned pin , int value )
{
void __iomem * pio = pin_to_controller ( pin ) ;
unsigned mask = pin_to_mask ( pin ) ;
if ( ! pio )
return - EINVAL ;
__raw_writel ( mask , pio + PIO_IDR ) ;
__raw_writel ( mask , pio + PIO_PUDR ) ;
__raw_writel ( mask , pio + ( value ? PIO_SODR : PIO_CODR ) ) ;
__raw_writel ( mask , pio + PIO_OER ) ;
__raw_writel ( mask , pio + PIO_PER ) ;
return 0 ;
}
EXPORT_SYMBOL ( at91_set_gpio_output ) ;
/*
* enable / disable the glitch filter ; mostly used with IRQ handling .
*/
int __init_or_module at91_set_deglitch ( unsigned pin , int is_on )
{
void __iomem * pio = pin_to_controller ( pin ) ;
unsigned mask = pin_to_mask ( pin ) ;
if ( ! pio )
return - EINVAL ;
__raw_writel ( mask , pio + ( is_on ? PIO_IFER : PIO_IFDR ) ) ;
return 0 ;
}
EXPORT_SYMBOL ( at91_set_deglitch ) ;
2006-02-22 21:23:35 +00:00
/*
* enable / disable the multi - driver ; This is only valid for output and
* allows the output pin to run as an open collector output .
*/
int __init_or_module at91_set_multi_drive ( unsigned pin , int is_on )
{
void __iomem * pio = pin_to_controller ( pin ) ;
unsigned mask = pin_to_mask ( pin ) ;
if ( ! pio )
return - EINVAL ;
__raw_writel ( mask , pio + ( is_on ? PIO_MDER : PIO_MDDR ) ) ;
return 0 ;
}
EXPORT_SYMBOL ( at91_set_multi_drive ) ;
2006-01-09 17:05:41 +00:00
/*--------------------------------------------------------------------------*/
2007-02-12 00:53:13 -08:00
/* new-style GPIO calls; these expect at91_set_GPIO_periph to have been
* called , and maybe at91_set_multi_drive ( ) for putout pins .
*/
int gpio_direction_input ( unsigned pin )
{
void __iomem * pio = pin_to_controller ( pin ) ;
unsigned mask = pin_to_mask ( pin ) ;
if ( ! pio | | ! ( __raw_readl ( pio + PIO_PSR ) & mask ) )
return - EINVAL ;
2007-02-22 09:38:52 +01:00
__raw_writel ( mask , pio + PIO_ODR ) ;
2007-02-12 00:53:13 -08:00
return 0 ;
}
EXPORT_SYMBOL ( gpio_direction_input ) ;
int gpio_direction_output ( unsigned pin )
{
void __iomem * pio = pin_to_controller ( pin ) ;
unsigned mask = pin_to_mask ( pin ) ;
if ( ! pio | | ! ( __raw_readl ( pio + PIO_PSR ) & mask ) )
return - EINVAL ;
__raw_writel ( mask , pio + PIO_OER ) ;
return 0 ;
}
EXPORT_SYMBOL ( gpio_direction_output ) ;
/*--------------------------------------------------------------------------*/
2006-01-09 17:05:41 +00:00
/*
* assuming the pin is muxed as a gpio output , set its value .
*/
int at91_set_gpio_value ( unsigned pin , int value )
{
void __iomem * pio = pin_to_controller ( pin ) ;
unsigned mask = pin_to_mask ( pin ) ;
if ( ! pio )
return - EINVAL ;
__raw_writel ( mask , pio + ( value ? PIO_SODR : PIO_CODR ) ) ;
return 0 ;
}
EXPORT_SYMBOL ( at91_set_gpio_value ) ;
/*
* read the pin ' s value ( works even if it ' s not muxed as a gpio ) .
*/
int at91_get_gpio_value ( unsigned pin )
{
void __iomem * pio = pin_to_controller ( pin ) ;
unsigned mask = pin_to_mask ( pin ) ;
u32 pdsr ;
if ( ! pio )
return - EINVAL ;
pdsr = __raw_readl ( pio + PIO_PDSR ) ;
return ( pdsr & mask ) ! = 0 ;
}
EXPORT_SYMBOL ( at91_get_gpio_value ) ;
/*--------------------------------------------------------------------------*/
2006-06-19 15:26:54 +01:00
# ifdef CONFIG_PM
2006-09-27 13:23:00 +01:00
static u32 wakeups [ MAX_GPIO_BANKS ] ;
static u32 backups [ MAX_GPIO_BANKS ] ;
2006-06-19 15:26:54 +01:00
static int gpio_irq_set_wake ( unsigned pin , unsigned state )
{
unsigned mask = pin_to_mask ( pin ) ;
2007-01-09 13:47:29 +01:00
unsigned bank = ( pin - PIN_BASE ) / 32 ;
2006-06-19 15:26:54 +01:00
2007-01-09 13:47:29 +01:00
if ( unlikely ( bank > = MAX_GPIO_BANKS ) )
2006-06-19 15:26:54 +01:00
return - EINVAL ;
if ( state )
2007-01-09 13:47:29 +01:00
wakeups [ bank ] | = mask ;
2006-06-19 15:26:54 +01:00
else
2007-01-09 13:47:29 +01:00
wakeups [ bank ] & = ~ mask ;
set_irq_wake ( gpio [ bank ] . id , state ) ;
2006-06-19 15:26:54 +01:00
return 0 ;
}
void at91_gpio_suspend ( void )
{
int i ;
2006-09-27 13:23:00 +01:00
for ( i = 0 ; i < gpio_banks ; i + + ) {
u32 pio = gpio [ i ] . offset ;
2006-06-19 15:26:54 +01:00
backups [ i ] = at91_sys_read ( pio + PIO_IMR ) ;
2006-09-27 13:23:00 +01:00
at91_sys_write ( pio + PIO_IDR , backups [ i ] ) ;
at91_sys_write ( pio + PIO_IER , wakeups [ i ] ) ;
2006-06-19 15:26:54 +01:00
2007-01-09 13:47:29 +01:00
if ( ! wakeups [ i ] )
clk_disable ( gpio [ i ] . clock ) ;
else {
2006-06-19 15:26:54 +01:00
# ifdef CONFIG_PM_DEBUG
2007-01-09 13:47:29 +01:00
printk ( KERN_DEBUG " GPIO-%c may wake for %08x \n " , ' A ' + i , wakeups [ i ] ) ;
2006-06-19 15:26:54 +01:00
# endif
}
}
}
void at91_gpio_resume ( void )
{
int i ;
2006-09-27 13:23:00 +01:00
for ( i = 0 ; i < gpio_banks ; i + + ) {
u32 pio = gpio [ i ] . offset ;
2006-06-19 15:26:54 +01:00
2007-01-09 13:47:29 +01:00
if ( ! wakeups [ i ] )
clk_enable ( gpio [ i ] . clock ) ;
2006-09-27 13:23:00 +01:00
at91_sys_write ( pio + PIO_IDR , wakeups [ i ] ) ;
at91_sys_write ( pio + PIO_IER , backups [ i ] ) ;
}
2006-06-19 15:26:54 +01:00
}
# else
# define gpio_irq_set_wake NULL
# endif
2006-01-09 17:05:41 +00:00
/* Several AIC controller irqs are dispatched through this GPIO handler.
* To use any AT91_PIN_ * as an externally triggered IRQ , first call
* at91_set_gpio_input ( ) then maybe enable its glitch filter .
* Then just request_irq ( ) with the pin ID ; it works like any ARM IRQ
* handler , though it always triggers on rising and falling edges .
*
* Alternatively , certain pins may be used directly as IRQ0 . . IRQ6 after
* configuring them with at91_set_a_periph ( ) or at91_set_b_periph ( ) .
* IRQ0 . . IRQ6 should be configurable , e . g . level vs edge triggering .
*/
static void gpio_irq_mask ( unsigned pin )
{
void __iomem * pio = pin_to_controller ( pin ) ;
unsigned mask = pin_to_mask ( pin ) ;
if ( pio )
__raw_writel ( mask , pio + PIO_IDR ) ;
}
static void gpio_irq_unmask ( unsigned pin )
{
void __iomem * pio = pin_to_controller ( pin ) ;
unsigned mask = pin_to_mask ( pin ) ;
if ( pio )
__raw_writel ( mask , pio + PIO_IER ) ;
}
static int gpio_irq_type ( unsigned pin , unsigned type )
{
return ( type = = IRQT_BOTHEDGE ) ? 0 : - EINVAL ;
}
2006-08-01 22:26:25 +01:00
static struct irq_chip gpio_irqchip = {
. name = " GPIO " ,
2006-01-09 17:05:41 +00:00
. mask = gpio_irq_mask ,
. unmask = gpio_irq_unmask ,
. set_type = gpio_irq_type ,
2006-06-19 15:26:54 +01:00
. set_wake = gpio_irq_set_wake ,
2006-01-09 17:05:41 +00:00
} ;
2006-11-23 11:41:32 +00:00
static void gpio_irq_handler ( unsigned irq , struct irq_desc * desc )
2006-01-09 17:05:41 +00:00
{
unsigned pin ;
2006-11-23 11:41:32 +00:00
struct irq_desc * gpio ;
2006-01-09 17:05:41 +00:00
void __iomem * pio ;
u32 isr ;
2006-07-01 23:01:50 +01:00
pio = get_irq_chip_data ( irq ) ;
2006-01-09 17:05:41 +00:00
/* temporarily mask (level sensitive) parent IRQ */
desc - > chip - > ack ( irq ) ;
for ( ; ; ) {
2006-06-19 15:26:54 +01:00
/* reading ISR acks the pending (edge triggered) GPIO interrupt */
2006-01-09 17:05:41 +00:00
isr = __raw_readl ( pio + PIO_ISR ) & __raw_readl ( pio + PIO_IMR ) ;
if ( ! isr )
break ;
2006-07-01 23:01:50 +01:00
pin = ( unsigned ) get_irq_data ( irq ) ;
2006-01-09 17:05:41 +00:00
gpio = & irq_desc [ pin ] ;
while ( isr ) {
2006-02-24 22:27:50 +00:00
if ( isr & 1 ) {
2006-07-01 23:01:50 +01:00
if ( unlikely ( gpio - > depth ) ) {
2006-02-24 22:27:50 +00:00
/*
* The core ARM interrupt handler lazily disables IRQs so
* another IRQ must be generated before it actually gets
* here to be disabled on the GPIO controller .
*/
gpio_irq_mask ( pin ) ;
}
else
2006-10-06 10:53:39 -07:00
desc_handle_irq ( pin , gpio ) ;
2006-02-24 22:27:50 +00:00
}
2006-01-09 17:05:41 +00:00
pin + + ;
gpio + + ;
isr > > = 1 ;
}
}
desc - > chip - > unmask ( irq ) ;
/* now it may re-trigger */
}
2006-09-27 13:23:00 +01:00
/*--------------------------------------------------------------------------*/
/*
* Called from the processor - specific init to enable GPIO interrupt support .
*/
void __init at91_gpio_irq_setup ( void )
2006-01-09 17:05:41 +00:00
{
2006-09-27 13:23:00 +01:00
unsigned pioc , pin ;
2006-01-09 17:05:41 +00:00
2006-09-27 13:23:00 +01:00
for ( pioc = 0 , pin = PIN_BASE ;
pioc < gpio_banks ;
pioc + + ) {
2006-01-09 17:05:41 +00:00
void __iomem * controller ;
2006-09-27 13:23:00 +01:00
unsigned id = gpio [ pioc ] . id ;
2006-01-09 17:05:41 +00:00
unsigned i ;
2006-09-27 13:23:00 +01:00
clk_enable ( gpio [ pioc ] . clock ) ; /* enable PIO controller's clock */
controller = ( void __iomem * ) AT91_VA_BASE_SYS + gpio [ pioc ] . offset ;
2006-01-09 17:05:41 +00:00
__raw_writel ( ~ 0 , controller + PIO_IDR ) ;
set_irq_data ( id , ( void * ) pin ) ;
2006-11-23 11:41:32 +00:00
set_irq_chip_data ( id , controller ) ;
2006-01-09 17:05:41 +00:00
for ( i = 0 ; i < 32 ; i + + , pin + + ) {
2006-06-19 15:26:54 +01:00
/*
* Can use the " simple " and not " edge " handler since it ' s
* shorter , and the AIC handles interupts sanely .
*/
2006-01-09 17:05:41 +00:00
set_irq_chip ( pin , & gpio_irqchip ) ;
2006-11-23 11:41:32 +00:00
set_irq_handler ( pin , handle_simple_irq ) ;
2006-01-09 17:05:41 +00:00
set_irq_flags ( pin , IRQF_VALID ) ;
}
set_irq_chained_handler ( id , gpio_irq_handler ) ;
}
2006-09-27 13:23:00 +01:00
pr_info ( " AT91: %d gpio irqs in %d banks \n " , pin - PIN_BASE , gpio_banks ) ;
}
/*
* Called from the processor - specific init to enable GPIO pin support .
*/
void __init at91_gpio_init ( struct at91_gpio_bank * data , int nr_banks )
{
BUG_ON ( nr_banks > MAX_GPIO_BANKS ) ;
gpio = data ;
gpio_banks = nr_banks ;
2006-01-09 17:05:41 +00:00
}