2008-04-10 16:31:47 +04:00
/*
* linux / arch / arm / mach - sa1100 / gpio . c
*
* Generic SA - 1100 GPIO handling
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*/
2011-07-26 13:53:52 +04:00
# include <linux/gpio.h>
2008-04-10 16:31:47 +04:00
# include <linux/init.h>
# include <linux/module.h>
2013-09-25 16:33:55 +04:00
# include <linux/io.h>
2015-01-15 04:32:26 +03:00
# include <linux/syscore_ops.h>
2008-08-05 19:14:15 +04:00
# include <mach/hardware.h>
2012-02-24 03:06:51 +04:00
# include <mach/irqs.h>
2008-04-10 16:31:47 +04:00
static int sa1100_gpio_get ( struct gpio_chip * chip , unsigned offset )
{
return GPLR & GPIO_GPIO ( offset ) ;
}
static void sa1100_gpio_set ( struct gpio_chip * chip , unsigned offset , int value )
{
if ( value )
GPSR = GPIO_GPIO ( offset ) ;
else
GPCR = GPIO_GPIO ( offset ) ;
}
static int sa1100_direction_input ( struct gpio_chip * chip , unsigned offset )
{
unsigned long flags ;
local_irq_save ( flags ) ;
GPDR & = ~ GPIO_GPIO ( offset ) ;
local_irq_restore ( flags ) ;
return 0 ;
}
static int sa1100_direction_output ( struct gpio_chip * chip , unsigned offset , int value )
{
unsigned long flags ;
local_irq_save ( flags ) ;
sa1100_gpio_set ( chip , offset , value ) ;
GPDR | = GPIO_GPIO ( offset ) ;
local_irq_restore ( flags ) ;
return 0 ;
}
2011-12-18 22:24:57 +04:00
static int sa1100_to_irq ( struct gpio_chip * chip , unsigned offset )
{
2015-01-15 04:29:16 +03:00
return IRQ_GPIO0 + offset ;
2011-12-18 22:24:57 +04:00
}
2008-04-10 16:31:47 +04:00
static struct gpio_chip sa1100_gpio_chip = {
. label = " gpio " ,
. direction_input = sa1100_direction_input ,
. direction_output = sa1100_direction_output ,
. set = sa1100_gpio_set ,
. get = sa1100_gpio_get ,
2011-12-18 22:24:57 +04:00
. to_irq = sa1100_to_irq ,
2008-04-10 16:31:47 +04:00
. base = 0 ,
. ngpio = GPIO_MAX + 1 ,
} ;
2015-01-15 04:32:26 +03:00
/*
* SA1100 GPIO edge detection for IRQs :
* IRQs are generated on Falling - Edge , Rising - Edge , or both .
* Use this instead of directly setting GRER / GFER .
*/
static int GPIO_IRQ_rising_edge ;
static int GPIO_IRQ_falling_edge ;
static int GPIO_IRQ_mask ;
static int sa1100_gpio_type ( struct irq_data * d , unsigned int type )
{
unsigned int mask ;
mask = BIT ( d - > hwirq ) ;
if ( type = = IRQ_TYPE_PROBE ) {
if ( ( GPIO_IRQ_rising_edge | GPIO_IRQ_falling_edge ) & mask )
return 0 ;
type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING ;
}
if ( type & IRQ_TYPE_EDGE_RISING )
GPIO_IRQ_rising_edge | = mask ;
else
GPIO_IRQ_rising_edge & = ~ mask ;
if ( type & IRQ_TYPE_EDGE_FALLING )
GPIO_IRQ_falling_edge | = mask ;
else
GPIO_IRQ_falling_edge & = ~ mask ;
GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask ;
GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask ;
return 0 ;
}
/*
* GPIO IRQs must be acknowledged .
*/
static void sa1100_gpio_ack ( struct irq_data * d )
{
GEDR = BIT ( d - > hwirq ) ;
}
static void sa1100_gpio_mask ( struct irq_data * d )
{
unsigned int mask = BIT ( d - > hwirq ) ;
GPIO_IRQ_mask & = ~ mask ;
GRER & = ~ mask ;
GFER & = ~ mask ;
}
static void sa1100_gpio_unmask ( struct irq_data * d )
{
unsigned int mask = BIT ( d - > hwirq ) ;
GPIO_IRQ_mask | = mask ;
GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask ;
GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask ;
}
static int sa1100_gpio_wake ( struct irq_data * d , unsigned int on )
{
if ( on )
PWER | = BIT ( d - > hwirq ) ;
else
PWER & = ~ BIT ( d - > hwirq ) ;
return 0 ;
}
/*
* This is for GPIO IRQs
*/
static struct irq_chip sa1100_gpio_irq_chip = {
. name = " GPIO " ,
. irq_ack = sa1100_gpio_ack ,
. irq_mask = sa1100_gpio_mask ,
. irq_unmask = sa1100_gpio_unmask ,
. irq_set_type = sa1100_gpio_type ,
. irq_set_wake = sa1100_gpio_wake ,
} ;
static int sa1100_gpio_irqdomain_map ( struct irq_domain * d ,
unsigned int irq , irq_hw_number_t hwirq )
{
irq_set_chip_and_handler ( irq , & sa1100_gpio_irq_chip ,
handle_edge_irq ) ;
2015-07-27 23:55:16 +03:00
irq_set_noprobe ( irq ) ;
2015-01-15 04:32:26 +03:00
return 0 ;
}
2015-04-27 15:54:07 +03:00
static const struct irq_domain_ops sa1100_gpio_irqdomain_ops = {
2015-01-15 04:32:26 +03:00
. map = sa1100_gpio_irqdomain_map ,
. xlate = irq_domain_xlate_onetwocell ,
} ;
static struct irq_domain * sa1100_gpio_irqdomain ;
/*
* IRQ 0 - 11 ( GPIO ) handler . We enter here with the
* irq_controller_lock held , and IRQs disabled . Decode the IRQ
* and call the handler .
*/
static void
2015-07-13 01:11:27 +03:00
sa1100_gpio_handler ( unsigned int __irq , struct irq_desc * desc )
2015-01-15 04:32:26 +03:00
{
2015-07-13 01:11:27 +03:00
unsigned int irq , mask ;
2015-01-15 04:32:26 +03:00
mask = GEDR ;
do {
/*
* clear down all currently active IRQ sources .
* We will be processing them all .
*/
GEDR = mask ;
irq = IRQ_GPIO0 ;
do {
if ( mask & 1 )
generic_handle_irq ( irq ) ;
mask > > = 1 ;
irq + + ;
} while ( mask ) ;
mask = GEDR ;
} while ( mask ) ;
}
static int sa1100_gpio_suspend ( void )
{
/*
* Set the appropriate edges for wakeup .
*/
GRER = PWER & GPIO_IRQ_rising_edge ;
GFER = PWER & GPIO_IRQ_falling_edge ;
/*
* Clear any pending GPIO interrupts .
*/
GEDR = GEDR ;
return 0 ;
}
static void sa1100_gpio_resume ( void )
{
GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask ;
GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask ;
}
static struct syscore_ops sa1100_gpio_syscore_ops = {
. suspend = sa1100_gpio_suspend ,
. resume = sa1100_gpio_resume ,
} ;
static int __init sa1100_gpio_init_devicefs ( void )
{
register_syscore_ops ( & sa1100_gpio_syscore_ops ) ;
return 0 ;
}
device_initcall ( sa1100_gpio_init_devicefs ) ;
2008-04-10 16:31:47 +04:00
void __init sa1100_init_gpio ( void )
{
2015-01-15 04:32:26 +03:00
/* clear all GPIO edge detects */
GFER = 0 ;
GRER = 0 ;
GEDR = - 1 ;
2008-04-10 16:31:47 +04:00
gpiochip_add ( & sa1100_gpio_chip ) ;
2015-01-15 04:32:26 +03:00
sa1100_gpio_irqdomain = irq_domain_add_simple ( NULL ,
28 , IRQ_GPIO0 ,
& sa1100_gpio_irqdomain_ops , NULL ) ;
/*
* Install handlers for GPIO 0 - 10 edge detect interrupts
*/
irq_set_chained_handler ( IRQ_GPIO0_SC , sa1100_gpio_handler ) ;
irq_set_chained_handler ( IRQ_GPIO1_SC , sa1100_gpio_handler ) ;
irq_set_chained_handler ( IRQ_GPIO2_SC , sa1100_gpio_handler ) ;
irq_set_chained_handler ( IRQ_GPIO3_SC , sa1100_gpio_handler ) ;
irq_set_chained_handler ( IRQ_GPIO4_SC , sa1100_gpio_handler ) ;
irq_set_chained_handler ( IRQ_GPIO5_SC , sa1100_gpio_handler ) ;
irq_set_chained_handler ( IRQ_GPIO6_SC , sa1100_gpio_handler ) ;
irq_set_chained_handler ( IRQ_GPIO7_SC , sa1100_gpio_handler ) ;
irq_set_chained_handler ( IRQ_GPIO8_SC , sa1100_gpio_handler ) ;
irq_set_chained_handler ( IRQ_GPIO9_SC , sa1100_gpio_handler ) ;
irq_set_chained_handler ( IRQ_GPIO10_SC , sa1100_gpio_handler ) ;
/*
* Install handler for GPIO 11 - 27 edge detect interrupts
*/
irq_set_chained_handler ( IRQ_GPIO11_27 , sa1100_gpio_handler ) ;
2008-04-10 16:31:47 +04:00
}