2008-10-20 03:51:03 +04:00
/*
* arch / arm / plat - orion / gpio . c
*
* Marvell Orion SoC GPIO handling .
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed " as is " without any
* warranty of any kind , whether express or implied .
*/
2012-06-27 15:40:04 +04:00
# define DEBUG
2008-10-20 03:51:03 +04:00
# include <linux/kernel.h>
# include <linux/init.h>
2008-10-20 03:51:03 +04:00
# include <linux/irq.h>
2012-06-27 15:40:04 +04:00
# include <linux/irqdomain.h>
2008-10-20 03:51:03 +04:00
# include <linux/module.h>
# include <linux/spinlock.h>
# include <linux/bitops.h>
# include <linux/io.h>
2009-05-29 04:08:55 +04:00
# include <linux/gpio.h>
2012-04-19 01:16:40 +04:00
# include <linux/leds.h>
2012-06-27 15:40:04 +04:00
# include <linux/of.h>
# include <linux/of_irq.h>
# include <linux/of_address.h>
2012-08-29 19:16:55 +04:00
# include <plat/orion-gpio.h>
2008-10-20 03:51:03 +04:00
2010-12-14 14:54:03 +03:00
/*
* GPIO unit register offsets .
*/
# define GPIO_OUT_OFF 0x0000
# define GPIO_IO_CONF_OFF 0x0004
# define GPIO_BLINK_EN_OFF 0x0008
# define GPIO_IN_POL_OFF 0x000c
# define GPIO_DATA_IN_OFF 0x0010
# define GPIO_EDGE_CAUSE_OFF 0x0014
# define GPIO_EDGE_MASK_OFF 0x0018
# define GPIO_LEVEL_MASK_OFF 0x001c
struct orion_gpio_chip {
struct gpio_chip chip ;
spinlock_t lock ;
void __iomem * base ;
unsigned long valid_input ;
unsigned long valid_output ;
int mask_offset ;
int secondary_irq_base ;
2012-06-27 15:40:04 +04:00
struct irq_domain * domain ;
2010-12-14 14:54:03 +03:00
} ;
static void __iomem * GPIO_OUT ( struct orion_gpio_chip * ochip )
{
return ochip - > base + GPIO_OUT_OFF ;
}
static void __iomem * GPIO_IO_CONF ( struct orion_gpio_chip * ochip )
{
return ochip - > base + GPIO_IO_CONF_OFF ;
}
static void __iomem * GPIO_BLINK_EN ( struct orion_gpio_chip * ochip )
{
return ochip - > base + GPIO_BLINK_EN_OFF ;
}
static void __iomem * GPIO_IN_POL ( struct orion_gpio_chip * ochip )
{
return ochip - > base + GPIO_IN_POL_OFF ;
}
static void __iomem * GPIO_DATA_IN ( struct orion_gpio_chip * ochip )
{
return ochip - > base + GPIO_DATA_IN_OFF ;
}
static void __iomem * GPIO_EDGE_CAUSE ( struct orion_gpio_chip * ochip )
{
return ochip - > base + GPIO_EDGE_CAUSE_OFF ;
}
static void __iomem * GPIO_EDGE_MASK ( struct orion_gpio_chip * ochip )
{
return ochip - > base + ochip - > mask_offset + GPIO_EDGE_MASK_OFF ;
}
static void __iomem * GPIO_LEVEL_MASK ( struct orion_gpio_chip * ochip )
{
return ochip - > base + ochip - > mask_offset + GPIO_LEVEL_MASK_OFF ;
}
2008-10-20 03:51:03 +04:00
2010-12-14 14:54:03 +03:00
static struct orion_gpio_chip orion_gpio_chips [ 2 ] ;
static int orion_gpio_chip_count ;
static inline void
__set_direction ( struct orion_gpio_chip * ochip , unsigned pin , int input )
2008-10-20 03:51:03 +04:00
{
u32 u ;
2010-12-14 14:54:03 +03:00
u = readl ( GPIO_IO_CONF ( ochip ) ) ;
2008-10-20 03:51:03 +04:00
if ( input )
2010-12-14 14:54:03 +03:00
u | = 1 < < pin ;
2008-10-20 03:51:03 +04:00
else
2010-12-14 14:54:03 +03:00
u & = ~ ( 1 < < pin ) ;
writel ( u , GPIO_IO_CONF ( ochip ) ) ;
2008-10-20 03:51:03 +04:00
}
2010-12-14 14:54:03 +03:00
static void __set_level ( struct orion_gpio_chip * ochip , unsigned pin , int high )
2008-10-20 03:51:03 +04:00
{
u32 u ;
2010-12-14 14:54:03 +03:00
u = readl ( GPIO_OUT ( ochip ) ) ;
2008-10-20 03:51:03 +04:00
if ( high )
2010-12-14 14:54:03 +03:00
u | = 1 < < pin ;
2008-10-20 03:51:03 +04:00
else
2010-12-14 14:54:03 +03:00
u & = ~ ( 1 < < pin ) ;
writel ( u , GPIO_OUT ( ochip ) ) ;
2008-10-20 03:51:03 +04:00
}
2010-12-14 14:54:03 +03:00
static inline void
__set_blinking ( struct orion_gpio_chip * ochip , unsigned pin , int blink )
2008-10-20 03:51:03 +04:00
{
2009-05-29 04:08:55 +04:00
u32 u ;
2008-10-20 03:51:03 +04:00
2010-12-14 14:54:03 +03:00
u = readl ( GPIO_BLINK_EN ( ochip ) ) ;
2009-05-29 04:08:55 +04:00
if ( blink )
2010-12-14 14:54:03 +03:00
u | = 1 < < pin ;
2009-05-29 04:08:55 +04:00
else
2010-12-14 14:54:03 +03:00
u & = ~ ( 1 < < pin ) ;
writel ( u , GPIO_BLINK_EN ( ochip ) ) ;
2009-05-29 04:08:55 +04:00
}
2008-10-20 03:51:03 +04:00
2010-12-14 14:54:03 +03:00
static inline int
orion_gpio_is_valid ( struct orion_gpio_chip * ochip , unsigned pin , int mode )
2009-05-29 04:08:55 +04:00
{
2010-12-14 14:54:03 +03:00
if ( pin > = ochip - > chip . ngpio )
goto err_out ;
if ( ( mode & GPIO_INPUT_OK ) & & ! test_bit ( pin , & ochip - > valid_input ) )
goto err_out ;
if ( ( mode & GPIO_OUTPUT_OK ) & & ! test_bit ( pin , & ochip - > valid_output ) )
goto err_out ;
return 1 ;
2008-10-20 03:51:03 +04:00
2009-05-29 04:08:55 +04:00
err_out :
pr_debug ( " %s: invalid GPIO %d \n " , __func__ , pin ) ;
return false ;
2008-10-20 03:51:03 +04:00
}
2009-05-29 04:08:55 +04:00
/*
2013-03-28 16:07:46 +04:00
* GPIO primitives .
2009-05-29 04:08:55 +04:00
*/
2010-12-14 14:54:03 +03:00
static int orion_gpio_request ( struct gpio_chip * chip , unsigned pin )
{
struct orion_gpio_chip * ochip =
container_of ( chip , struct orion_gpio_chip , chip ) ;
if ( orion_gpio_is_valid ( ochip , pin , GPIO_INPUT_OK ) | |
orion_gpio_is_valid ( ochip , pin , GPIO_OUTPUT_OK ) )
return 0 ;
return - EINVAL ;
}
2009-05-29 04:08:55 +04:00
static int orion_gpio_direction_input ( struct gpio_chip * chip , unsigned pin )
2008-10-20 03:51:03 +04:00
{
2010-12-14 14:54:03 +03:00
struct orion_gpio_chip * ochip =
container_of ( chip , struct orion_gpio_chip , chip ) ;
2008-10-20 03:51:03 +04:00
unsigned long flags ;
2010-12-14 14:54:03 +03:00
if ( ! orion_gpio_is_valid ( ochip , pin , GPIO_INPUT_OK ) )
2008-10-20 03:51:03 +04:00
return - EINVAL ;
2010-12-14 14:54:03 +03:00
spin_lock_irqsave ( & ochip - > lock , flags ) ;
__set_direction ( ochip , pin , 1 ) ;
spin_unlock_irqrestore ( & ochip - > lock , flags ) ;
2008-10-20 03:51:03 +04:00
return 0 ;
}
2010-12-14 14:54:03 +03:00
static int orion_gpio_get ( struct gpio_chip * chip , unsigned pin )
2008-10-20 03:51:03 +04:00
{
2010-12-14 14:54:03 +03:00
struct orion_gpio_chip * ochip =
container_of ( chip , struct orion_gpio_chip , chip ) ;
2008-10-20 03:51:03 +04:00
int val ;
2010-12-14 14:54:03 +03:00
if ( readl ( GPIO_IO_CONF ( ochip ) ) & ( 1 < < pin ) ) {
val = readl ( GPIO_DATA_IN ( ochip ) ) ^ readl ( GPIO_IN_POL ( ochip ) ) ;
} else {
val = readl ( GPIO_OUT ( ochip ) ) ;
}
2008-10-20 03:51:03 +04:00
2010-12-14 14:54:03 +03:00
return ( val > > pin ) & 1 ;
2008-10-20 03:51:03 +04:00
}
2010-12-14 14:54:03 +03:00
static int
orion_gpio_direction_output ( struct gpio_chip * chip , unsigned pin , int value )
2008-10-20 03:51:03 +04:00
{
2010-12-14 14:54:03 +03:00
struct orion_gpio_chip * ochip =
container_of ( chip , struct orion_gpio_chip , chip ) ;
2008-10-20 03:51:03 +04:00
unsigned long flags ;
2009-05-29 04:08:55 +04:00
2010-12-14 14:54:03 +03:00
if ( ! orion_gpio_is_valid ( ochip , pin , GPIO_OUTPUT_OK ) )
2009-05-29 04:08:55 +04:00
return - EINVAL ;
2008-10-20 03:51:03 +04:00
2010-12-14 14:54:03 +03:00
spin_lock_irqsave ( & ochip - > lock , flags ) ;
__set_blinking ( ochip , pin , 0 ) ;
__set_level ( ochip , pin , value ) ;
__set_direction ( ochip , pin , 0 ) ;
spin_unlock_irqrestore ( & ochip - > lock , flags ) ;
2009-05-29 04:08:55 +04:00
return 0 ;
2008-10-20 03:51:03 +04:00
}
2010-12-14 14:54:03 +03:00
static void orion_gpio_set ( struct gpio_chip * chip , unsigned pin , int value )
2008-10-20 03:51:03 +04:00
{
2010-12-14 14:54:03 +03:00
struct orion_gpio_chip * ochip =
container_of ( chip , struct orion_gpio_chip , chip ) ;
2008-10-20 03:51:03 +04:00
unsigned long flags ;
2010-12-14 14:54:03 +03:00
spin_lock_irqsave ( & ochip - > lock , flags ) ;
__set_level ( ochip , pin , value ) ;
spin_unlock_irqrestore ( & ochip - > lock , flags ) ;
2008-10-20 03:51:03 +04:00
}
2010-12-14 14:54:03 +03:00
static int orion_gpio_to_irq ( struct gpio_chip * chip , unsigned pin )
2008-10-20 03:51:03 +04:00
{
2010-12-14 14:54:03 +03:00
struct orion_gpio_chip * ochip =
container_of ( chip , struct orion_gpio_chip , chip ) ;
2008-10-20 03:51:03 +04:00
2012-06-27 15:40:04 +04:00
return irq_create_mapping ( ochip - > domain ,
ochip - > secondary_irq_base + pin ) ;
2009-05-29 04:08:55 +04:00
}
2008-10-20 03:51:03 +04:00
/*
* Orion - specific GPIO API extensions .
*/
2010-12-14 14:54:03 +03:00
static struct orion_gpio_chip * orion_gpio_chip_find ( int pin )
{
int i ;
for ( i = 0 ; i < orion_gpio_chip_count ; i + + ) {
struct orion_gpio_chip * ochip = orion_gpio_chips + i ;
struct gpio_chip * chip = & ochip - > chip ;
if ( pin > = chip - > base & & pin < chip - > base + chip - > ngpio )
return ochip ;
}
return NULL ;
}
2008-10-20 03:51:03 +04:00
void __init orion_gpio_set_unused ( unsigned pin )
{
2010-12-14 14:54:03 +03:00
struct orion_gpio_chip * ochip = orion_gpio_chip_find ( pin ) ;
if ( ochip = = NULL )
return ;
pin - = ochip - > chip . base ;
2009-05-29 04:08:55 +04:00
/* Configure as output, drive low. */
2010-12-14 14:54:03 +03:00
__set_level ( ochip , pin , 0 ) ;
__set_direction ( ochip , pin , 0 ) ;
2008-10-20 03:51:03 +04:00
}
2009-02-02 23:27:55 +03:00
void __init orion_gpio_set_valid ( unsigned pin , int mode )
2008-10-20 03:51:03 +04:00
{
2010-12-14 14:54:03 +03:00
struct orion_gpio_chip * ochip = orion_gpio_chip_find ( pin ) ;
if ( ochip = = NULL )
return ;
pin - = ochip - > chip . base ;
2009-02-02 23:27:55 +03:00
if ( mode = = 1 )
mode = GPIO_INPUT_OK | GPIO_OUTPUT_OK ;
2010-12-14 14:54:03 +03:00
2009-02-02 23:27:55 +03:00
if ( mode & GPIO_INPUT_OK )
2010-12-14 14:54:03 +03:00
__set_bit ( pin , & ochip - > valid_input ) ;
2008-10-20 03:51:03 +04:00
else
2010-12-14 14:54:03 +03:00
__clear_bit ( pin , & ochip - > valid_input ) ;
2009-02-02 23:27:55 +03:00
if ( mode & GPIO_OUTPUT_OK )
2010-12-14 14:54:03 +03:00
__set_bit ( pin , & ochip - > valid_output ) ;
2009-02-02 23:27:55 +03:00
else
2010-12-14 14:54:03 +03:00
__clear_bit ( pin , & ochip - > valid_output ) ;
2008-10-20 03:51:03 +04:00
}
void orion_gpio_set_blink ( unsigned pin , int blink )
{
2010-12-14 14:54:03 +03:00
struct orion_gpio_chip * ochip = orion_gpio_chip_find ( pin ) ;
2008-10-20 03:51:03 +04:00
unsigned long flags ;
2010-12-14 14:54:03 +03:00
if ( ochip = = NULL )
return ;
2008-10-20 03:51:03 +04:00
2010-12-14 14:54:03 +03:00
spin_lock_irqsave ( & ochip - > lock , flags ) ;
2012-04-19 01:16:39 +04:00
__set_level ( ochip , pin & 31 , 0 ) ;
__set_blinking ( ochip , pin & 31 , blink ) ;
2010-12-14 14:54:03 +03:00
spin_unlock_irqrestore ( & ochip - > lock , flags ) ;
2008-10-20 03:51:03 +04:00
}
EXPORT_SYMBOL ( orion_gpio_set_blink ) ;
2008-10-20 03:51:03 +04:00
2012-04-19 01:16:40 +04:00
# define ORION_BLINK_HALF_PERIOD 100 /* ms */
int orion_gpio_led_blink_set ( unsigned gpio , int state ,
unsigned long * delay_on , unsigned long * delay_off )
{
if ( delay_on & & delay_off & & ! * delay_on & & ! * delay_off )
* delay_on = * delay_off = ORION_BLINK_HALF_PERIOD ;
switch ( state ) {
case GPIO_LED_NO_BLINK_LOW :
case GPIO_LED_NO_BLINK_HIGH :
orion_gpio_set_blink ( gpio , 0 ) ;
gpio_set_value ( gpio , state ) ;
break ;
case GPIO_LED_BLINK :
orion_gpio_set_blink ( gpio , 1 ) ;
}
return 0 ;
}
EXPORT_SYMBOL_GPL ( orion_gpio_led_blink_set ) ;
2008-10-20 03:51:03 +04:00
/*****************************************************************************
* Orion GPIO IRQ
*
* GPIO_IN_POL register controls whether GPIO_DATA_IN will hold the same
* value of the line or the opposite value .
*
* Level IRQ handlers : DATA_IN is used directly as cause register .
* Interrupt are masked by LEVEL_MASK registers .
* Edge IRQ handlers : Change in DATA_IN are latched in EDGE_CAUSE .
* Interrupt are masked by EDGE_MASK registers .
* Both - edge handlers : Similar to regular Edge handlers , but also swaps
* the polarity to catch the next line transaction .
* This is a race condition that might not perfectly
* work on some use cases .
*
* Every eight GPIO lines are grouped ( OR ' ed ) before going up to main
* cause register .
*
* EDGE cause mask
* data - in / - - - - - - - - | | - - - - - | | - - - - \
* - - - - - | | - - - - - - - - - to main cause reg
* X \ - - - - - - - - - - - - - - - - | | - - - - /
* polarity LEVEL mask
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-11-29 13:17:38 +03:00
static int gpio_irq_set_type ( struct irq_data * d , u32 type )
2008-10-20 03:51:03 +04:00
{
2011-04-14 21:17:57 +04:00
struct irq_chip_generic * gc = irq_data_get_irq_chip_data ( d ) ;
struct irq_chip_type * ct = irq_data_get_chip_type ( d ) ;
struct orion_gpio_chip * ochip = gc - > private ;
2010-12-14 14:54:03 +03:00
int pin ;
2008-10-20 03:51:03 +04:00
u32 u ;
2012-06-27 15:40:04 +04:00
pin = d - > hwirq - ochip - > secondary_irq_base ;
2010-12-14 14:54:03 +03:00
u = readl ( GPIO_IO_CONF ( ochip ) ) & ( 1 < < pin ) ;
2008-10-20 03:51:03 +04:00
if ( ! u ) {
return - EINVAL ;
}
2011-04-14 21:17:57 +04:00
type & = IRQ_TYPE_SENSE_MASK ;
if ( type = = IRQ_TYPE_NONE )
2008-10-20 03:51:03 +04:00
return - EINVAL ;
2011-04-14 21:17:57 +04:00
/* Check if we need to change chip and handler */
if ( ! ( ct - > type & type ) )
if ( irq_setup_alt_chip ( d , type ) )
return - EINVAL ;
2008-10-20 03:51:03 +04:00
/*
* Configure interrupt polarity .
*/
if ( type = = IRQ_TYPE_EDGE_RISING | | type = = IRQ_TYPE_LEVEL_HIGH ) {
2010-12-14 14:54:03 +03:00
u = readl ( GPIO_IN_POL ( ochip ) ) ;
u & = ~ ( 1 < < pin ) ;
writel ( u , GPIO_IN_POL ( ochip ) ) ;
2008-10-20 03:51:03 +04:00
} else if ( type = = IRQ_TYPE_EDGE_FALLING | | type = = IRQ_TYPE_LEVEL_LOW ) {
2010-12-14 14:54:03 +03:00
u = readl ( GPIO_IN_POL ( ochip ) ) ;
u | = 1 < < pin ;
writel ( u , GPIO_IN_POL ( ochip ) ) ;
2008-10-20 03:51:03 +04:00
} else if ( type = = IRQ_TYPE_EDGE_BOTH ) {
u32 v ;
2010-12-14 14:54:03 +03:00
v = readl ( GPIO_IN_POL ( ochip ) ) ^ readl ( GPIO_DATA_IN ( ochip ) ) ;
2008-10-20 03:51:03 +04:00
/*
* set initial polarity based on current input level
*/
2010-12-14 14:54:03 +03:00
u = readl ( GPIO_IN_POL ( ochip ) ) ;
if ( v & ( 1 < < pin ) )
u | = 1 < < pin ; /* falling */
2008-10-20 03:51:03 +04:00
else
2010-12-14 14:54:03 +03:00
u & = ~ ( 1 < < pin ) ; /* rising */
writel ( u , GPIO_IN_POL ( ochip ) ) ;
2008-10-20 03:51:03 +04:00
}
return 0 ;
}
2012-06-27 15:40:04 +04:00
static void gpio_irq_handler ( unsigned irq , struct irq_desc * desc )
{
struct orion_gpio_chip * ochip = irq_get_handler_data ( irq ) ;
u32 cause , type ;
int i ;
if ( ochip = = NULL )
return ;
cause = readl ( GPIO_DATA_IN ( ochip ) ) & readl ( GPIO_LEVEL_MASK ( ochip ) ) ;
cause | = readl ( GPIO_EDGE_CAUSE ( ochip ) ) & readl ( GPIO_EDGE_MASK ( ochip ) ) ;
for ( i = 0 ; i < ochip - > chip . ngpio ; i + + ) {
int irq ;
irq = ochip - > secondary_irq_base + i ;
if ( ! ( cause & ( 1 < < i ) ) )
continue ;
2013-06-14 20:40:47 +04:00
type = irq_get_trigger_type ( irq ) ;
2012-06-27 15:40:04 +04:00
if ( ( type & IRQ_TYPE_SENSE_MASK ) = = IRQ_TYPE_EDGE_BOTH ) {
/* Swap polarity (race with GPIO line) */
u32 polarity ;
polarity = readl ( GPIO_IN_POL ( ochip ) ) ;
polarity ^ = 1 < < i ;
writel ( polarity , GPIO_IN_POL ( ochip ) ) ;
}
generic_handle_irq ( irq ) ;
}
}
2013-03-24 18:45:30 +04:00
# ifdef CONFIG_DEBUG_FS
# include <linux/seq_file.h>
static void orion_gpio_dbg_show ( struct seq_file * s , struct gpio_chip * chip )
{
struct orion_gpio_chip * ochip =
container_of ( chip , struct orion_gpio_chip , chip ) ;
u32 out , io_conf , blink , in_pol , data_in , cause , edg_msk , lvl_msk ;
int i ;
out = readl_relaxed ( GPIO_OUT ( ochip ) ) ;
io_conf = readl_relaxed ( GPIO_IO_CONF ( ochip ) ) ;
blink = readl_relaxed ( GPIO_BLINK_EN ( ochip ) ) ;
in_pol = readl_relaxed ( GPIO_IN_POL ( ochip ) ) ;
data_in = readl_relaxed ( GPIO_DATA_IN ( ochip ) ) ;
cause = readl_relaxed ( GPIO_EDGE_CAUSE ( ochip ) ) ;
edg_msk = readl_relaxed ( GPIO_EDGE_MASK ( ochip ) ) ;
lvl_msk = readl_relaxed ( GPIO_LEVEL_MASK ( ochip ) ) ;
for ( i = 0 ; i < chip - > ngpio ; i + + ) {
const char * label ;
u32 msk ;
bool is_out ;
label = gpiochip_is_requested ( chip , i ) ;
if ( ! label )
continue ;
msk = 1 < < i ;
is_out = ! ( io_conf & msk ) ;
seq_printf ( s , " gpio-%-3d (%-20.20s) " , chip - > base + i , label ) ;
if ( is_out ) {
seq_printf ( s , " out %s %s \n " ,
out & msk ? " hi " : " lo " ,
blink & msk ? " (blink ) " : " " ) ;
continue ;
}
seq_printf ( s , " in %s (act %s) - IRQ " ,
( data_in ^ in_pol ) & msk ? " hi " : " lo " ,
in_pol & msk ? " lo " : " hi " ) ;
if ( ! ( ( edg_msk | lvl_msk ) & msk ) ) {
seq_printf ( s , " disabled \n " ) ;
continue ;
}
if ( edg_msk & msk )
seq_printf ( s , " edge " ) ;
if ( lvl_msk & msk )
seq_printf ( s , " level " ) ;
seq_printf ( s , " (%s) \n " , cause & msk ? " pending " : " clear " ) ;
}
}
# else
# define orion_gpio_dbg_show NULL
# endif
2012-06-27 15:40:04 +04:00
void __init orion_gpio_init ( struct device_node * np ,
int gpio_base , int ngpio ,
void __iomem * base , int mask_offset ,
int secondary_irq_base ,
int irqs [ 4 ] )
2010-12-14 14:54:03 +03:00
{
struct orion_gpio_chip * ochip ;
2011-04-14 21:17:57 +04:00
struct irq_chip_generic * gc ;
struct irq_chip_type * ct ;
2011-12-19 20:49:48 +04:00
char gc_label [ 16 ] ;
2012-06-27 15:40:04 +04:00
int i ;
2010-12-14 14:54:03 +03:00
if ( orion_gpio_chip_count = = ARRAY_SIZE ( orion_gpio_chips ) )
return ;
2011-12-19 20:49:48 +04:00
snprintf ( gc_label , sizeof ( gc_label ) , " orion_gpio%d " ,
orion_gpio_chip_count ) ;
2010-12-14 14:54:03 +03:00
ochip = orion_gpio_chips + orion_gpio_chip_count ;
2011-12-19 20:49:48 +04:00
ochip - > chip . label = kstrdup ( gc_label , GFP_KERNEL ) ;
2010-12-14 14:54:03 +03:00
ochip - > chip . request = orion_gpio_request ;
ochip - > chip . direction_input = orion_gpio_direction_input ;
ochip - > chip . get = orion_gpio_get ;
ochip - > chip . direction_output = orion_gpio_direction_output ;
ochip - > chip . set = orion_gpio_set ;
ochip - > chip . to_irq = orion_gpio_to_irq ;
ochip - > chip . base = gpio_base ;
ochip - > chip . ngpio = ngpio ;
ochip - > chip . can_sleep = 0 ;
2012-06-27 15:40:04 +04:00
# ifdef CONFIG_OF
ochip - > chip . of_node = np ;
# endif
2013-03-24 18:45:30 +04:00
ochip - > chip . dbg_show = orion_gpio_dbg_show ;
2012-06-27 15:40:04 +04:00
2010-12-14 14:54:03 +03:00
spin_lock_init ( & ochip - > lock ) ;
ochip - > base = ( void __iomem * ) base ;
ochip - > valid_input = 0 ;
ochip - > valid_output = 0 ;
ochip - > mask_offset = mask_offset ;
ochip - > secondary_irq_base = secondary_irq_base ;
gpiochip_add ( & ochip - > chip ) ;
/*
* Mask and clear GPIO interrupts .
*/
writel ( 0 , GPIO_EDGE_CAUSE ( ochip ) ) ;
writel ( 0 , GPIO_EDGE_MASK ( ochip ) ) ;
writel ( 0 , GPIO_LEVEL_MASK ( ochip ) ) ;
2012-06-27 15:40:04 +04:00
/* Setup the interrupt handlers. Each chip can have up to 4
* interrupt handlers , with each handler dealing with 8 GPIO
* pins . */
for ( i = 0 ; i < 4 ; i + + ) {
if ( irqs [ i ] ) {
irq_set_handler_data ( irqs [ i ] , ochip ) ;
irq_set_chained_handler ( irqs [ i ] , gpio_irq_handler ) ;
}
}
gc = irq_alloc_generic_chip ( " orion_gpio_irq " , 2 ,
secondary_irq_base ,
2011-04-14 21:17:57 +04:00
ochip - > base , handle_level_irq ) ;
gc - > private = ochip ;
ct = gc - > chip_types ;
ct - > regs . mask = ochip - > mask_offset + GPIO_LEVEL_MASK_OFF ;
ct - > type = IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW ;
ct - > chip . irq_mask = irq_gc_mask_clr_bit ;
ct - > chip . irq_unmask = irq_gc_mask_set_bit ;
ct - > chip . irq_set_type = gpio_irq_set_type ;
2012-06-27 15:40:04 +04:00
ct - > chip . name = ochip - > chip . label ;
2011-04-14 21:17:57 +04:00
ct + + ;
ct - > regs . mask = ochip - > mask_offset + GPIO_EDGE_MASK_OFF ;
ct - > regs . ack = GPIO_EDGE_CAUSE_OFF ;
ct - > type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING ;
2011-07-06 20:41:31 +04:00
ct - > chip . irq_ack = irq_gc_ack_clr_bit ;
2011-04-14 21:17:57 +04:00
ct - > chip . irq_mask = irq_gc_mask_clr_bit ;
ct - > chip . irq_unmask = irq_gc_mask_set_bit ;
ct - > chip . irq_set_type = gpio_irq_set_type ;
ct - > handler = handle_edge_irq ;
2012-06-27 15:40:04 +04:00
ct - > chip . name = ochip - > chip . label ;
2011-04-14 21:17:57 +04:00
irq_setup_generic_chip ( gc , IRQ_MSK ( ngpio ) , IRQ_GC_INIT_MASK_CACHE ,
IRQ_NOREQUEST , IRQ_LEVEL | IRQ_NOPROBE ) ;
2010-12-14 14:54:03 +03:00
2012-06-27 15:40:04 +04:00
/* Setup irq domain on top of the generic chip. */
ochip - > domain = irq_domain_add_legacy ( np ,
ochip - > chip . ngpio ,
ochip - > secondary_irq_base ,
ochip - > secondary_irq_base ,
& irq_domain_simple_ops ,
ochip ) ;
if ( ! ochip - > domain )
panic ( " %s: couldn't allocate irq domain (DT). \n " ,
ochip - > chip . label ) ;
2010-12-14 14:54:03 +03:00
2012-06-27 15:40:04 +04:00
orion_gpio_chip_count + + ;
}
2010-12-14 14:54:03 +03:00
2012-06-27 15:40:04 +04:00
# ifdef CONFIG_OF
static void __init orion_gpio_of_init_one ( struct device_node * np ,
int irq_gpio_base )
{
int ngpio , gpio_base , mask_offset ;
void __iomem * base ;
int ret , i ;
int irqs [ 4 ] ;
int secondary_irq_base ;
ret = of_property_read_u32 ( np , " ngpio " , & ngpio ) ;
if ( ret )
goto out ;
ret = of_property_read_u32 ( np , " mask-offset " , & mask_offset ) ;
if ( ret = = - EINVAL )
mask_offset = 0 ;
else
goto out ;
base = of_iomap ( np , 0 ) ;
if ( ! base )
goto out ;
secondary_irq_base = irq_gpio_base + ( 32 * orion_gpio_chip_count ) ;
gpio_base = 32 * orion_gpio_chip_count ;
/* Get the interrupt numbers. Each chip can have up to 4
* interrupt handlers , with each handler dealing with 8 GPIO
* pins . */
for ( i = 0 ; i < 4 ; i + + )
irqs [ i ] = irq_of_parse_and_map ( np , i ) ;
orion_gpio_init ( np , gpio_base , ngpio , base , mask_offset ,
secondary_irq_base , irqs ) ;
return ;
out :
pr_err ( " %s: %s: missing mandatory property \n " , __func__ , np - > name ) ;
}
2008-10-20 03:51:03 +04:00
2012-06-27 15:40:04 +04:00
void __init orion_gpio_of_init ( int irq_gpio_base )
{
struct device_node * np ;
2008-10-20 03:51:03 +04:00
2012-06-27 15:40:04 +04:00
for_each_compatible_node ( np , NULL , " marvell,orion-gpio " )
orion_gpio_of_init_one ( np , irq_gpio_base ) ;
2008-10-20 03:51:03 +04:00
}
2012-06-27 15:40:04 +04:00
# endif