2005-07-10 22:58:15 +04:00
/*
* linux / arch / arm / plat - omap / gpio . c
*
* Support functions for OMAP GPIO
*
2005-09-07 20:20:26 +04:00
* Copyright ( C ) 2003 - 2005 Nokia Corporation
2005-07-10 22:58:15 +04:00
* Written by Juha Yrj <EFBFBD> l <EFBFBD> < juha . yrjola @ nokia . com >
*
* 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 .
*/
# include <linux/init.h>
# include <linux/module.h>
# include <linux/sched.h>
# include <linux/interrupt.h>
# include <linux/ptrace.h>
2005-09-07 20:20:26 +04:00
# include <linux/sysdev.h>
# include <linux/err.h>
2006-01-07 19:15:52 +03:00
# include <linux/clk.h>
2005-07-10 22:58:15 +04:00
# include <asm/hardware.h>
# include <asm/irq.h>
# include <asm/arch/irqs.h>
# include <asm/arch/gpio.h>
# include <asm/mach/irq.h>
# include <asm/io.h>
/*
* OMAP1510 GPIO registers
*/
2005-09-07 20:20:26 +04:00
# define OMAP1510_GPIO_BASE (void __iomem *)0xfffce000
2005-07-10 22:58:15 +04:00
# define OMAP1510_GPIO_DATA_INPUT 0x00
# define OMAP1510_GPIO_DATA_OUTPUT 0x04
# define OMAP1510_GPIO_DIR_CONTROL 0x08
# define OMAP1510_GPIO_INT_CONTROL 0x0c
# define OMAP1510_GPIO_INT_MASK 0x10
# define OMAP1510_GPIO_INT_STATUS 0x14
# define OMAP1510_GPIO_PIN_CONTROL 0x18
# define OMAP1510_IH_GPIO_BASE 64
/*
* OMAP1610 specific GPIO registers
*/
2005-09-07 20:20:26 +04:00
# define OMAP1610_GPIO1_BASE (void __iomem *)0xfffbe400
# define OMAP1610_GPIO2_BASE (void __iomem *)0xfffbec00
# define OMAP1610_GPIO3_BASE (void __iomem *)0xfffbb400
# define OMAP1610_GPIO4_BASE (void __iomem *)0xfffbbc00
2005-07-10 22:58:15 +04:00
# define OMAP1610_GPIO_REVISION 0x0000
# define OMAP1610_GPIO_SYSCONFIG 0x0010
# define OMAP1610_GPIO_SYSSTATUS 0x0014
# define OMAP1610_GPIO_IRQSTATUS1 0x0018
# define OMAP1610_GPIO_IRQENABLE1 0x001c
2005-09-07 20:20:26 +04:00
# define OMAP1610_GPIO_WAKEUPENABLE 0x0028
2005-07-10 22:58:15 +04:00
# define OMAP1610_GPIO_DATAIN 0x002c
# define OMAP1610_GPIO_DATAOUT 0x0030
# define OMAP1610_GPIO_DIRECTION 0x0034
# define OMAP1610_GPIO_EDGE_CTRL1 0x0038
# define OMAP1610_GPIO_EDGE_CTRL2 0x003c
# define OMAP1610_GPIO_CLEAR_IRQENABLE1 0x009c
2005-09-07 20:20:26 +04:00
# define OMAP1610_GPIO_CLEAR_WAKEUPENA 0x00a8
2005-07-10 22:58:15 +04:00
# define OMAP1610_GPIO_CLEAR_DATAOUT 0x00b0
# define OMAP1610_GPIO_SET_IRQENABLE1 0x00dc
2005-09-07 20:20:26 +04:00
# define OMAP1610_GPIO_SET_WAKEUPENA 0x00e8
2005-07-10 22:58:15 +04:00
# define OMAP1610_GPIO_SET_DATAOUT 0x00f0
/*
* OMAP730 specific GPIO registers
*/
2005-09-07 20:20:26 +04:00
# define OMAP730_GPIO1_BASE (void __iomem *)0xfffbc000
# define OMAP730_GPIO2_BASE (void __iomem *)0xfffbc800
# define OMAP730_GPIO3_BASE (void __iomem *)0xfffbd000
# define OMAP730_GPIO4_BASE (void __iomem *)0xfffbd800
# define OMAP730_GPIO5_BASE (void __iomem *)0xfffbe000
# define OMAP730_GPIO6_BASE (void __iomem *)0xfffbe800
2005-07-10 22:58:15 +04:00
# define OMAP730_GPIO_DATA_INPUT 0x00
# define OMAP730_GPIO_DATA_OUTPUT 0x04
# define OMAP730_GPIO_DIR_CONTROL 0x08
# define OMAP730_GPIO_INT_CONTROL 0x0c
# define OMAP730_GPIO_INT_MASK 0x10
# define OMAP730_GPIO_INT_STATUS 0x14
2005-09-07 20:20:26 +04:00
/*
* omap24xx specific GPIO registers
*/
# define OMAP24XX_GPIO1_BASE (void __iomem *)0x48018000
# define OMAP24XX_GPIO2_BASE (void __iomem *)0x4801a000
# define OMAP24XX_GPIO3_BASE (void __iomem *)0x4801c000
# define OMAP24XX_GPIO4_BASE (void __iomem *)0x4801e000
# define OMAP24XX_GPIO_REVISION 0x0000
# define OMAP24XX_GPIO_SYSCONFIG 0x0010
# define OMAP24XX_GPIO_SYSSTATUS 0x0014
# define OMAP24XX_GPIO_IRQSTATUS1 0x0018
# define OMAP24XX_GPIO_IRQENABLE1 0x001c
# define OMAP24XX_GPIO_CTRL 0x0030
# define OMAP24XX_GPIO_OE 0x0034
# define OMAP24XX_GPIO_DATAIN 0x0038
# define OMAP24XX_GPIO_DATAOUT 0x003c
# define OMAP24XX_GPIO_LEVELDETECT0 0x0040
# define OMAP24XX_GPIO_LEVELDETECT1 0x0044
# define OMAP24XX_GPIO_RISINGDETECT 0x0048
# define OMAP24XX_GPIO_FALLINGDETECT 0x004c
# define OMAP24XX_GPIO_CLEARIRQENABLE1 0x0060
# define OMAP24XX_GPIO_SETIRQENABLE1 0x0064
# define OMAP24XX_GPIO_CLEARWKUENA 0x0080
# define OMAP24XX_GPIO_SETWKUENA 0x0084
# define OMAP24XX_GPIO_CLEARDATAOUT 0x0090
# define OMAP24XX_GPIO_SETDATAOUT 0x0094
2005-07-10 22:58:15 +04:00
struct gpio_bank {
2005-09-07 20:20:26 +04:00
void __iomem * base ;
2005-07-10 22:58:15 +04:00
u16 irq ;
u16 virtual_irq_start ;
2005-09-07 20:20:26 +04:00
int method ;
2005-07-10 22:58:15 +04:00
u32 reserved_map ;
2005-09-07 20:20:26 +04:00
u32 suspend_wakeup ;
u32 saved_wakeup ;
2005-07-10 22:58:15 +04:00
spinlock_t lock ;
} ;
# define METHOD_MPUIO 0
# define METHOD_GPIO_1510 1
# define METHOD_GPIO_1610 2
# define METHOD_GPIO_730 3
2005-09-07 20:20:26 +04:00
# define METHOD_GPIO_24XX 4
2005-07-10 22:58:15 +04:00
2005-09-07 20:20:26 +04:00
# ifdef CONFIG_ARCH_OMAP16XX
2005-07-10 22:58:15 +04:00
static struct gpio_bank gpio_bank_1610 [ 5 ] = {
{ OMAP_MPUIO_BASE , INT_MPUIO , IH_MPUIO_BASE , METHOD_MPUIO } ,
{ OMAP1610_GPIO1_BASE , INT_GPIO_BANK1 , IH_GPIO_BASE , METHOD_GPIO_1610 } ,
{ OMAP1610_GPIO2_BASE , INT_1610_GPIO_BANK2 , IH_GPIO_BASE + 16 , METHOD_GPIO_1610 } ,
{ OMAP1610_GPIO3_BASE , INT_1610_GPIO_BANK3 , IH_GPIO_BASE + 32 , METHOD_GPIO_1610 } ,
{ OMAP1610_GPIO4_BASE , INT_1610_GPIO_BANK4 , IH_GPIO_BASE + 48 , METHOD_GPIO_1610 } ,
} ;
# endif
2005-11-10 17:26:50 +03:00
# ifdef CONFIG_ARCH_OMAP15XX
2005-07-10 22:58:15 +04:00
static struct gpio_bank gpio_bank_1510 [ 2 ] = {
{ OMAP_MPUIO_BASE , INT_MPUIO , IH_MPUIO_BASE , METHOD_MPUIO } ,
{ OMAP1510_GPIO_BASE , INT_GPIO_BANK1 , IH_GPIO_BASE , METHOD_GPIO_1510 }
} ;
# endif
# ifdef CONFIG_ARCH_OMAP730
static struct gpio_bank gpio_bank_730 [ 7 ] = {
{ OMAP_MPUIO_BASE , INT_730_MPUIO , IH_MPUIO_BASE , METHOD_MPUIO } ,
{ OMAP730_GPIO1_BASE , INT_730_GPIO_BANK1 , IH_GPIO_BASE , METHOD_GPIO_730 } ,
{ OMAP730_GPIO2_BASE , INT_730_GPIO_BANK2 , IH_GPIO_BASE + 32 , METHOD_GPIO_730 } ,
{ OMAP730_GPIO3_BASE , INT_730_GPIO_BANK3 , IH_GPIO_BASE + 64 , METHOD_GPIO_730 } ,
{ OMAP730_GPIO4_BASE , INT_730_GPIO_BANK4 , IH_GPIO_BASE + 96 , METHOD_GPIO_730 } ,
{ OMAP730_GPIO5_BASE , INT_730_GPIO_BANK5 , IH_GPIO_BASE + 128 , METHOD_GPIO_730 } ,
{ OMAP730_GPIO6_BASE , INT_730_GPIO_BANK6 , IH_GPIO_BASE + 160 , METHOD_GPIO_730 } ,
} ;
# endif
2005-09-07 20:20:26 +04:00
# ifdef CONFIG_ARCH_OMAP24XX
static struct gpio_bank gpio_bank_24xx [ 4 ] = {
{ OMAP24XX_GPIO1_BASE , INT_24XX_GPIO_BANK1 , IH_GPIO_BASE , METHOD_GPIO_24XX } ,
{ OMAP24XX_GPIO2_BASE , INT_24XX_GPIO_BANK2 , IH_GPIO_BASE + 32 , METHOD_GPIO_24XX } ,
{ OMAP24XX_GPIO3_BASE , INT_24XX_GPIO_BANK3 , IH_GPIO_BASE + 64 , METHOD_GPIO_24XX } ,
{ OMAP24XX_GPIO4_BASE , INT_24XX_GPIO_BANK4 , IH_GPIO_BASE + 96 , METHOD_GPIO_24XX } ,
} ;
# endif
2005-07-10 22:58:15 +04:00
static struct gpio_bank * gpio_bank ;
static int gpio_bank_count ;
static inline struct gpio_bank * get_gpio_bank ( int gpio )
{
2005-11-10 17:26:50 +03:00
# ifdef CONFIG_ARCH_OMAP15XX
2006-04-02 20:46:23 +04:00
if ( cpu_is_omap15xx ( ) ) {
2005-07-10 22:58:15 +04:00
if ( OMAP_GPIO_IS_MPUIO ( gpio ) )
return & gpio_bank [ 0 ] ;
return & gpio_bank [ 1 ] ;
}
# endif
# if defined(CONFIG_ARCH_OMAP16XX)
if ( cpu_is_omap16xx ( ) ) {
if ( OMAP_GPIO_IS_MPUIO ( gpio ) )
return & gpio_bank [ 0 ] ;
return & gpio_bank [ 1 + ( gpio > > 4 ) ] ;
}
# endif
# ifdef CONFIG_ARCH_OMAP730
if ( cpu_is_omap730 ( ) ) {
if ( OMAP_GPIO_IS_MPUIO ( gpio ) )
return & gpio_bank [ 0 ] ;
return & gpio_bank [ 1 + ( gpio > > 5 ) ] ;
}
# endif
2005-09-07 20:20:26 +04:00
# ifdef CONFIG_ARCH_OMAP24XX
if ( cpu_is_omap24xx ( ) )
return & gpio_bank [ gpio > > 5 ] ;
# endif
2005-07-10 22:58:15 +04:00
}
static inline int get_gpio_index ( int gpio )
{
2005-09-07 20:20:26 +04:00
# ifdef CONFIG_ARCH_OMAP730
2005-07-10 22:58:15 +04:00
if ( cpu_is_omap730 ( ) )
return gpio & 0x1f ;
2005-09-07 20:20:26 +04:00
# endif
# ifdef CONFIG_ARCH_OMAP24XX
if ( cpu_is_omap24xx ( ) )
return gpio & 0x1f ;
# endif
return gpio & 0x0f ;
2005-07-10 22:58:15 +04:00
}
static inline int gpio_valid ( int gpio )
{
if ( gpio < 0 )
return - 1 ;
2006-09-25 13:41:27 +04:00
# ifndef CONFIG_ARCH_OMAP24XX
2005-07-10 22:58:15 +04:00
if ( OMAP_GPIO_IS_MPUIO ( gpio ) ) {
2006-09-25 13:41:30 +04:00
if ( gpio > = OMAP_MAX_GPIO_LINES + 16 )
2005-07-10 22:58:15 +04:00
return - 1 ;
return 0 ;
}
2006-09-25 13:41:27 +04:00
# endif
2005-11-10 17:26:50 +03:00
# ifdef CONFIG_ARCH_OMAP15XX
2006-04-02 20:46:23 +04:00
if ( cpu_is_omap15xx ( ) & & gpio < 16 )
2005-07-10 22:58:15 +04:00
return 0 ;
# endif
# if defined(CONFIG_ARCH_OMAP16XX)
if ( ( cpu_is_omap16xx ( ) ) & & gpio < 64 )
return 0 ;
# endif
# ifdef CONFIG_ARCH_OMAP730
if ( cpu_is_omap730 ( ) & & gpio < 192 )
return 0 ;
2005-09-07 20:20:26 +04:00
# endif
# ifdef CONFIG_ARCH_OMAP24XX
if ( cpu_is_omap24xx ( ) & & gpio < 128 )
return 0 ;
2005-07-10 22:58:15 +04:00
# endif
return - 1 ;
}
static int check_gpio ( int gpio )
{
if ( unlikely ( gpio_valid ( gpio ) ) < 0 ) {
printk ( KERN_ERR " omap-gpio: invalid GPIO %d \n " , gpio ) ;
dump_stack ( ) ;
return - 1 ;
}
return 0 ;
}
static void _set_gpio_direction ( struct gpio_bank * bank , int gpio , int is_input )
{
2005-09-07 20:20:26 +04:00
void __iomem * reg = bank - > base ;
2005-07-10 22:58:15 +04:00
u32 l ;
switch ( bank - > method ) {
case METHOD_MPUIO :
reg + = OMAP_MPUIO_IO_CNTL ;
break ;
case METHOD_GPIO_1510 :
reg + = OMAP1510_GPIO_DIR_CONTROL ;
break ;
case METHOD_GPIO_1610 :
reg + = OMAP1610_GPIO_DIRECTION ;
break ;
case METHOD_GPIO_730 :
reg + = OMAP730_GPIO_DIR_CONTROL ;
break ;
2005-09-07 20:20:26 +04:00
case METHOD_GPIO_24XX :
reg + = OMAP24XX_GPIO_OE ;
break ;
2005-07-10 22:58:15 +04:00
}
l = __raw_readl ( reg ) ;
if ( is_input )
l | = 1 < < gpio ;
else
l & = ~ ( 1 < < gpio ) ;
__raw_writel ( l , reg ) ;
}
void omap_set_gpio_direction ( int gpio , int is_input )
{
struct gpio_bank * bank ;
if ( check_gpio ( gpio ) < 0 )
return ;
bank = get_gpio_bank ( gpio ) ;
spin_lock ( & bank - > lock ) ;
_set_gpio_direction ( bank , get_gpio_index ( gpio ) , is_input ) ;
spin_unlock ( & bank - > lock ) ;
}
static void _set_gpio_dataout ( struct gpio_bank * bank , int gpio , int enable )
{
2005-09-07 20:20:26 +04:00
void __iomem * reg = bank - > base ;
2005-07-10 22:58:15 +04:00
u32 l = 0 ;
switch ( bank - > method ) {
case METHOD_MPUIO :
reg + = OMAP_MPUIO_OUTPUT ;
l = __raw_readl ( reg ) ;
if ( enable )
l | = 1 < < gpio ;
else
l & = ~ ( 1 < < gpio ) ;
break ;
case METHOD_GPIO_1510 :
reg + = OMAP1510_GPIO_DATA_OUTPUT ;
l = __raw_readl ( reg ) ;
if ( enable )
l | = 1 < < gpio ;
else
l & = ~ ( 1 < < gpio ) ;
break ;
case METHOD_GPIO_1610 :
if ( enable )
reg + = OMAP1610_GPIO_SET_DATAOUT ;
else
reg + = OMAP1610_GPIO_CLEAR_DATAOUT ;
l = 1 < < gpio ;
break ;
case METHOD_GPIO_730 :
reg + = OMAP730_GPIO_DATA_OUTPUT ;
l = __raw_readl ( reg ) ;
if ( enable )
l | = 1 < < gpio ;
else
l & = ~ ( 1 < < gpio ) ;
break ;
2005-09-07 20:20:26 +04:00
case METHOD_GPIO_24XX :
if ( enable )
reg + = OMAP24XX_GPIO_SETDATAOUT ;
else
reg + = OMAP24XX_GPIO_CLEARDATAOUT ;
l = 1 < < gpio ;
break ;
2005-07-10 22:58:15 +04:00
default :
BUG ( ) ;
return ;
}
__raw_writel ( l , reg ) ;
}
void omap_set_gpio_dataout ( int gpio , int enable )
{
struct gpio_bank * bank ;
if ( check_gpio ( gpio ) < 0 )
return ;
bank = get_gpio_bank ( gpio ) ;
spin_lock ( & bank - > lock ) ;
_set_gpio_dataout ( bank , get_gpio_index ( gpio ) , enable ) ;
spin_unlock ( & bank - > lock ) ;
}
int omap_get_gpio_datain ( int gpio )
{
struct gpio_bank * bank ;
2005-09-07 20:20:26 +04:00
void __iomem * reg ;
2005-07-10 22:58:15 +04:00
if ( check_gpio ( gpio ) < 0 )
return - 1 ;
bank = get_gpio_bank ( gpio ) ;
reg = bank - > base ;
switch ( bank - > method ) {
case METHOD_MPUIO :
reg + = OMAP_MPUIO_INPUT_LATCH ;
break ;
case METHOD_GPIO_1510 :
reg + = OMAP1510_GPIO_DATA_INPUT ;
break ;
case METHOD_GPIO_1610 :
reg + = OMAP1610_GPIO_DATAIN ;
break ;
case METHOD_GPIO_730 :
reg + = OMAP730_GPIO_DATA_INPUT ;
break ;
2005-09-07 20:20:26 +04:00
case METHOD_GPIO_24XX :
reg + = OMAP24XX_GPIO_DATAIN ;
break ;
2005-07-10 22:58:15 +04:00
default :
BUG ( ) ;
return - 1 ;
}
2005-09-07 20:20:26 +04:00
return ( __raw_readl ( reg )
& ( 1 < < get_gpio_index ( gpio ) ) ) ! = 0 ;
2005-07-10 22:58:15 +04:00
}
2005-09-07 20:20:26 +04:00
# define MOD_REG_BIT(reg, bit_mask, set) \
do { \
int l = __raw_readl ( base + reg ) ; \
if ( set ) l | = bit_mask ; \
else l & = ~ bit_mask ; \
__raw_writel ( l , base + reg ) ; \
} while ( 0 )
static inline void set_24xx_gpio_triggering ( void __iomem * base , int gpio , int trigger )
2005-07-10 22:58:15 +04:00
{
2005-09-07 20:20:26 +04:00
u32 gpio_bit = 1 < < gpio ;
MOD_REG_BIT ( OMAP24XX_GPIO_LEVELDETECT0 , gpio_bit ,
2006-04-02 20:46:23 +04:00
trigger & __IRQT_LOWLVL ) ;
2005-09-07 20:20:26 +04:00
MOD_REG_BIT ( OMAP24XX_GPIO_LEVELDETECT1 , gpio_bit ,
2006-04-02 20:46:23 +04:00
trigger & __IRQT_HIGHLVL ) ;
2005-09-07 20:20:26 +04:00
MOD_REG_BIT ( OMAP24XX_GPIO_RISINGDETECT , gpio_bit ,
2006-04-02 20:46:23 +04:00
trigger & __IRQT_RISEDGE ) ;
2005-09-07 20:20:26 +04:00
MOD_REG_BIT ( OMAP24XX_GPIO_FALLINGDETECT , gpio_bit ,
2006-04-02 20:46:23 +04:00
trigger & __IRQT_FALEDGE ) ;
2005-09-07 20:20:26 +04:00
/* FIXME: Possibly do 'set_irq_handler(j, do_level_IRQ)' if only level
* triggering requested . */
}
static int _set_gpio_triggering ( struct gpio_bank * bank , int gpio , int trigger )
{
void __iomem * reg = bank - > base ;
u32 l = 0 ;
2005-07-10 22:58:15 +04:00
switch ( bank - > method ) {
case METHOD_MPUIO :
reg + = OMAP_MPUIO_GPIO_INT_EDGE ;
l = __raw_readl ( reg ) ;
2006-04-02 20:46:23 +04:00
if ( trigger & __IRQT_RISEDGE )
2005-07-10 22:58:15 +04:00
l | = 1 < < gpio ;
2006-04-02 20:46:23 +04:00
else if ( trigger & __IRQT_FALEDGE )
2005-07-10 22:58:15 +04:00
l & = ~ ( 1 < < gpio ) ;
2005-09-07 20:20:26 +04:00
else
goto bad ;
2005-07-10 22:58:15 +04:00
break ;
case METHOD_GPIO_1510 :
reg + = OMAP1510_GPIO_INT_CONTROL ;
l = __raw_readl ( reg ) ;
2006-04-02 20:46:23 +04:00
if ( trigger & __IRQT_RISEDGE )
2005-07-10 22:58:15 +04:00
l | = 1 < < gpio ;
2006-04-02 20:46:23 +04:00
else if ( trigger & __IRQT_FALEDGE )
2005-07-10 22:58:15 +04:00
l & = ~ ( 1 < < gpio ) ;
2005-09-07 20:20:26 +04:00
else
goto bad ;
2005-07-10 22:58:15 +04:00
break ;
case METHOD_GPIO_1610 :
if ( gpio & 0x08 )
reg + = OMAP1610_GPIO_EDGE_CTRL2 ;
else
reg + = OMAP1610_GPIO_EDGE_CTRL1 ;
gpio & = 0x07 ;
2005-09-07 20:20:26 +04:00
/* We allow only edge triggering, i.e. two lowest bits */
2006-04-02 20:46:23 +04:00
if ( trigger & ( __IRQT_LOWLVL | __IRQT_HIGHLVL ) )
2005-09-07 20:20:26 +04:00
BUG ( ) ;
2005-07-10 22:58:15 +04:00
l = __raw_readl ( reg ) ;
l & = ~ ( 3 < < ( gpio < < 1 ) ) ;
2006-04-02 20:46:23 +04:00
if ( trigger & __IRQT_RISEDGE )
l | = 2 < < ( gpio < < 1 ) ;
if ( trigger & __IRQT_FALEDGE )
l | = 1 < < ( gpio < < 1 ) ;
2005-07-10 22:58:15 +04:00
break ;
case METHOD_GPIO_730 :
reg + = OMAP730_GPIO_INT_CONTROL ;
l = __raw_readl ( reg ) ;
2006-04-02 20:46:23 +04:00
if ( trigger & __IRQT_RISEDGE )
2005-07-10 22:58:15 +04:00
l | = 1 < < gpio ;
2006-04-02 20:46:23 +04:00
else if ( trigger & __IRQT_FALEDGE )
2005-07-10 22:58:15 +04:00
l & = ~ ( 1 < < gpio ) ;
2005-09-07 20:20:26 +04:00
else
goto bad ;
break ;
case METHOD_GPIO_24XX :
set_24xx_gpio_triggering ( reg , gpio , trigger ) ;
2005-07-10 22:58:15 +04:00
break ;
default :
BUG ( ) ;
2005-09-07 20:20:26 +04:00
goto bad ;
2005-07-10 22:58:15 +04:00
}
2005-09-07 20:20:26 +04:00
__raw_writel ( l , reg ) ;
return 0 ;
bad :
return - EINVAL ;
2005-07-10 22:58:15 +04:00
}
2005-09-07 20:20:26 +04:00
static int gpio_irq_type ( unsigned irq , unsigned type )
2005-07-10 22:58:15 +04:00
{
struct gpio_bank * bank ;
2005-09-07 20:20:26 +04:00
unsigned gpio ;
int retval ;
if ( irq > IH_MPUIO_BASE )
gpio = OMAP_MPUIO ( irq - IH_MPUIO_BASE ) ;
else
gpio = irq - IH_GPIO_BASE ;
2005-07-10 22:58:15 +04:00
if ( check_gpio ( gpio ) < 0 )
2005-09-07 20:20:26 +04:00
return - EINVAL ;
2006-04-02 20:46:23 +04:00
if ( type & IRQT_PROBE )
return - EINVAL ;
if ( ! cpu_is_omap24xx ( ) & & ( type & ( __IRQT_LOWLVL | __IRQT_HIGHLVL ) ) )
2005-09-07 20:20:26 +04:00
return - EINVAL ;
2005-07-10 22:58:15 +04:00
bank = get_gpio_bank ( gpio ) ;
spin_lock ( & bank - > lock ) ;
2005-09-07 20:20:26 +04:00
retval = _set_gpio_triggering ( bank , get_gpio_index ( gpio ) , type ) ;
2005-07-10 22:58:15 +04:00
spin_unlock ( & bank - > lock ) ;
2005-09-07 20:20:26 +04:00
return retval ;
2005-07-10 22:58:15 +04:00
}
static void _clear_gpio_irqbank ( struct gpio_bank * bank , int gpio_mask )
{
2005-09-07 20:20:26 +04:00
void __iomem * reg = bank - > base ;
2005-07-10 22:58:15 +04:00
switch ( bank - > method ) {
case METHOD_MPUIO :
/* MPUIO irqstatus is reset by reading the status register,
* so do nothing here */
return ;
case METHOD_GPIO_1510 :
reg + = OMAP1510_GPIO_INT_STATUS ;
break ;
case METHOD_GPIO_1610 :
reg + = OMAP1610_GPIO_IRQSTATUS1 ;
break ;
case METHOD_GPIO_730 :
reg + = OMAP730_GPIO_INT_STATUS ;
break ;
2005-09-07 20:20:26 +04:00
case METHOD_GPIO_24XX :
reg + = OMAP24XX_GPIO_IRQSTATUS1 ;
break ;
2005-07-10 22:58:15 +04:00
default :
BUG ( ) ;
return ;
}
__raw_writel ( gpio_mask , reg ) ;
}
static inline void _clear_gpio_irqstatus ( struct gpio_bank * bank , int gpio )
{
_clear_gpio_irqbank ( bank , 1 < < get_gpio_index ( gpio ) ) ;
}
2006-06-27 03:16:00 +04:00
static u32 _get_gpio_irqbank_mask ( struct gpio_bank * bank )
{
void __iomem * reg = bank - > base ;
2006-06-27 03:16:07 +04:00
int inv = 0 ;
u32 l ;
u32 mask ;
2006-06-27 03:16:00 +04:00
switch ( bank - > method ) {
case METHOD_MPUIO :
reg + = OMAP_MPUIO_GPIO_MASKIT ;
2006-06-27 03:16:07 +04:00
mask = 0xffff ;
inv = 1 ;
2006-06-27 03:16:00 +04:00
break ;
case METHOD_GPIO_1510 :
reg + = OMAP1510_GPIO_INT_MASK ;
2006-06-27 03:16:07 +04:00
mask = 0xffff ;
inv = 1 ;
2006-06-27 03:16:00 +04:00
break ;
case METHOD_GPIO_1610 :
reg + = OMAP1610_GPIO_IRQENABLE1 ;
2006-06-27 03:16:07 +04:00
mask = 0xffff ;
2006-06-27 03:16:00 +04:00
break ;
case METHOD_GPIO_730 :
reg + = OMAP730_GPIO_INT_MASK ;
2006-06-27 03:16:07 +04:00
mask = 0xffffffff ;
inv = 1 ;
2006-06-27 03:16:00 +04:00
break ;
case METHOD_GPIO_24XX :
reg + = OMAP24XX_GPIO_IRQENABLE1 ;
2006-06-27 03:16:07 +04:00
mask = 0xffffffff ;
2006-06-27 03:16:00 +04:00
break ;
default :
BUG ( ) ;
return 0 ;
}
2006-06-27 03:16:07 +04:00
l = __raw_readl ( reg ) ;
if ( inv )
l = ~ l ;
l & = mask ;
return l ;
2006-06-27 03:16:00 +04:00
}
2005-07-10 22:58:15 +04:00
static void _enable_gpio_irqbank ( struct gpio_bank * bank , int gpio_mask , int enable )
{
2005-09-07 20:20:26 +04:00
void __iomem * reg = bank - > base ;
2005-07-10 22:58:15 +04:00
u32 l ;
switch ( bank - > method ) {
case METHOD_MPUIO :
reg + = OMAP_MPUIO_GPIO_MASKIT ;
l = __raw_readl ( reg ) ;
if ( enable )
l & = ~ ( gpio_mask ) ;
else
l | = gpio_mask ;
break ;
case METHOD_GPIO_1510 :
reg + = OMAP1510_GPIO_INT_MASK ;
l = __raw_readl ( reg ) ;
if ( enable )
l & = ~ ( gpio_mask ) ;
else
l | = gpio_mask ;
break ;
case METHOD_GPIO_1610 :
if ( enable )
reg + = OMAP1610_GPIO_SET_IRQENABLE1 ;
else
reg + = OMAP1610_GPIO_CLEAR_IRQENABLE1 ;
l = gpio_mask ;
break ;
case METHOD_GPIO_730 :
reg + = OMAP730_GPIO_INT_MASK ;
l = __raw_readl ( reg ) ;
if ( enable )
l & = ~ ( gpio_mask ) ;
else
l | = gpio_mask ;
break ;
2005-09-07 20:20:26 +04:00
case METHOD_GPIO_24XX :
if ( enable )
reg + = OMAP24XX_GPIO_SETIRQENABLE1 ;
else
reg + = OMAP24XX_GPIO_CLEARIRQENABLE1 ;
l = gpio_mask ;
break ;
2005-07-10 22:58:15 +04:00
default :
BUG ( ) ;
return ;
}
__raw_writel ( l , reg ) ;
}
static inline void _set_gpio_irqenable ( struct gpio_bank * bank , int gpio , int enable )
{
_enable_gpio_irqbank ( bank , 1 < < get_gpio_index ( gpio ) , enable ) ;
}
2005-09-07 20:20:26 +04:00
/*
* Note that ENAWAKEUP needs to be enabled in GPIO_SYSCONFIG register .
* 1510 does not seem to have a wake - up register . If JTAG is connected
* to the target , system will wake up always on GPIO events . While
* system is running all registered GPIO interrupts need to have wake - up
* enabled . When system is suspended , only selected GPIO interrupts need
* to have wake - up enabled .
*/
static int _set_gpio_wakeup ( struct gpio_bank * bank , int gpio , int enable )
{
switch ( bank - > method ) {
case METHOD_GPIO_1610 :
case METHOD_GPIO_24XX :
spin_lock ( & bank - > lock ) ;
if ( enable )
bank - > suspend_wakeup | = ( 1 < < gpio ) ;
else
bank - > suspend_wakeup & = ~ ( 1 < < gpio ) ;
spin_unlock ( & bank - > lock ) ;
return 0 ;
default :
printk ( KERN_ERR " Can't enable GPIO wakeup for method %i \n " ,
bank - > method ) ;
return - EINVAL ;
}
}
2006-09-25 13:41:38 +04:00
static void _reset_gpio ( struct gpio_bank * bank , int gpio )
{
_set_gpio_direction ( bank , get_gpio_index ( gpio ) , 1 ) ;
_set_gpio_irqenable ( bank , gpio , 0 ) ;
_clear_gpio_irqstatus ( bank , gpio ) ;
_set_gpio_triggering ( bank , get_gpio_index ( gpio ) , IRQT_NOEDGE ) ;
}
2005-09-07 20:20:26 +04:00
/* Use disable_irq_wake() and enable_irq_wake() functions from drivers */
static int gpio_wake_enable ( unsigned int irq , unsigned int enable )
{
unsigned int gpio = irq - IH_GPIO_BASE ;
struct gpio_bank * bank ;
int retval ;
if ( check_gpio ( gpio ) < 0 )
return - ENODEV ;
bank = get_gpio_bank ( gpio ) ;
retval = _set_gpio_wakeup ( bank , get_gpio_index ( gpio ) , enable ) ;
return retval ;
}
2005-07-10 22:58:15 +04:00
int omap_request_gpio ( int gpio )
{
struct gpio_bank * bank ;
if ( check_gpio ( gpio ) < 0 )
return - EINVAL ;
bank = get_gpio_bank ( gpio ) ;
spin_lock ( & bank - > lock ) ;
if ( unlikely ( bank - > reserved_map & ( 1 < < get_gpio_index ( gpio ) ) ) ) {
printk ( KERN_ERR " omap-gpio: GPIO %d is already reserved! \n " , gpio ) ;
dump_stack ( ) ;
spin_unlock ( & bank - > lock ) ;
return - 1 ;
}
bank - > reserved_map | = ( 1 < < get_gpio_index ( gpio ) ) ;
2005-09-07 20:20:26 +04:00
2006-09-25 13:41:38 +04:00
/* Set trigger to none. You need to enable the desired trigger with
* request_irq ( ) or set_irq_type ( ) .
*/
2005-09-07 20:20:26 +04:00
_set_gpio_triggering ( bank , get_gpio_index ( gpio ) , IRQT_NOEDGE ) ;
2005-11-10 17:26:50 +03:00
# ifdef CONFIG_ARCH_OMAP15XX
2005-07-10 22:58:15 +04:00
if ( bank - > method = = METHOD_GPIO_1510 ) {
2005-09-07 20:20:26 +04:00
void __iomem * reg ;
2005-07-10 22:58:15 +04:00
2005-09-07 20:20:26 +04:00
/* Claim the pin for MPU */
2005-07-10 22:58:15 +04:00
reg = bank - > base + OMAP1510_GPIO_PIN_CONTROL ;
__raw_writel ( __raw_readl ( reg ) | ( 1 < < get_gpio_index ( gpio ) ) , reg ) ;
}
2005-09-07 20:20:26 +04:00
# endif
# ifdef CONFIG_ARCH_OMAP16XX
if ( bank - > method = = METHOD_GPIO_1610 ) {
/* Enable wake-up during idle for dynamic tick */
void __iomem * reg = bank - > base + OMAP1610_GPIO_SET_WAKEUPENA ;
__raw_writel ( 1 < < get_gpio_index ( gpio ) , reg ) ;
}
# endif
# ifdef CONFIG_ARCH_OMAP24XX
if ( bank - > method = = METHOD_GPIO_24XX ) {
/* Enable wake-up during idle for dynamic tick */
void __iomem * reg = bank - > base + OMAP24XX_GPIO_SETWKUENA ;
__raw_writel ( 1 < < get_gpio_index ( gpio ) , reg ) ;
}
2005-07-10 22:58:15 +04:00
# endif
spin_unlock ( & bank - > lock ) ;
return 0 ;
}
void omap_free_gpio ( int gpio )
{
struct gpio_bank * bank ;
if ( check_gpio ( gpio ) < 0 )
return ;
bank = get_gpio_bank ( gpio ) ;
spin_lock ( & bank - > lock ) ;
if ( unlikely ( ! ( bank - > reserved_map & ( 1 < < get_gpio_index ( gpio ) ) ) ) ) {
printk ( KERN_ERR " omap-gpio: GPIO %d wasn't reserved! \n " , gpio ) ;
dump_stack ( ) ;
spin_unlock ( & bank - > lock ) ;
return ;
}
2005-09-07 20:20:26 +04:00
# ifdef CONFIG_ARCH_OMAP16XX
if ( bank - > method = = METHOD_GPIO_1610 ) {
/* Disable wake-up during idle for dynamic tick */
void __iomem * reg = bank - > base + OMAP1610_GPIO_CLEAR_WAKEUPENA ;
__raw_writel ( 1 < < get_gpio_index ( gpio ) , reg ) ;
}
# endif
# ifdef CONFIG_ARCH_OMAP24XX
if ( bank - > method = = METHOD_GPIO_24XX ) {
/* Disable wake-up during idle for dynamic tick */
void __iomem * reg = bank - > base + OMAP24XX_GPIO_CLEARWKUENA ;
__raw_writel ( 1 < < get_gpio_index ( gpio ) , reg ) ;
}
# endif
2005-07-10 22:58:15 +04:00
bank - > reserved_map & = ~ ( 1 < < get_gpio_index ( gpio ) ) ;
2006-09-25 13:41:38 +04:00
_reset_gpio ( bank , gpio ) ;
2005-07-10 22:58:15 +04:00
spin_unlock ( & bank - > lock ) ;
}
/*
* We need to unmask the GPIO bank interrupt as soon as possible to
* avoid missing GPIO interrupts for other lines in the bank .
* Then we need to mask - read - clear - unmask the triggered GPIO lines
* in the bank to avoid missing nested interrupts for a GPIO line .
* If we wait to unmask individual GPIO lines in the bank after the
* line ' s interrupt handler has been run , we may miss some nested
* interrupts .
*/
static void gpio_irq_handler ( unsigned int irq , struct irqdesc * desc ,
struct pt_regs * regs )
{
2005-09-07 20:20:26 +04:00
void __iomem * isr_reg = NULL ;
2005-07-10 22:58:15 +04:00
u32 isr ;
unsigned int gpio_irq ;
struct gpio_bank * bank ;
2006-06-27 03:16:00 +04:00
u32 retrigger = 0 ;
int unmasked = 0 ;
2005-07-10 22:58:15 +04:00
desc - > chip - > ack ( irq ) ;
2006-07-02 01:32:41 +04:00
bank = get_irq_data ( irq ) ;
2005-07-10 22:58:15 +04:00
if ( bank - > method = = METHOD_MPUIO )
isr_reg = bank - > base + OMAP_MPUIO_GPIO_INT ;
2005-11-10 17:26:50 +03:00
# ifdef CONFIG_ARCH_OMAP15XX
2005-07-10 22:58:15 +04:00
if ( bank - > method = = METHOD_GPIO_1510 )
isr_reg = bank - > base + OMAP1510_GPIO_INT_STATUS ;
# endif
# if defined(CONFIG_ARCH_OMAP16XX)
if ( bank - > method = = METHOD_GPIO_1610 )
isr_reg = bank - > base + OMAP1610_GPIO_IRQSTATUS1 ;
# endif
# ifdef CONFIG_ARCH_OMAP730
if ( bank - > method = = METHOD_GPIO_730 )
isr_reg = bank - > base + OMAP730_GPIO_INT_STATUS ;
# endif
2005-09-07 20:20:26 +04:00
# ifdef CONFIG_ARCH_OMAP24XX
if ( bank - > method = = METHOD_GPIO_24XX )
isr_reg = bank - > base + OMAP24XX_GPIO_IRQSTATUS1 ;
# endif
while ( 1 ) {
2006-04-02 20:46:23 +04:00
u32 isr_saved , level_mask = 0 ;
2006-06-27 03:16:00 +04:00
u32 enabled ;
2006-04-02 20:46:23 +04:00
2006-06-27 03:16:00 +04:00
enabled = _get_gpio_irqbank_mask ( bank ) ;
isr_saved = isr = __raw_readl ( isr_reg ) & enabled ;
2006-04-02 20:46:23 +04:00
if ( cpu_is_omap15xx ( ) & & ( bank - > method = = METHOD_MPUIO ) )
isr & = 0x0000ffff ;
2006-06-27 03:16:00 +04:00
if ( cpu_is_omap24xx ( ) ) {
2006-04-02 20:46:23 +04:00
level_mask =
__raw_readl ( bank - > base +
OMAP24XX_GPIO_LEVELDETECT0 ) |
__raw_readl ( bank - > base +
OMAP24XX_GPIO_LEVELDETECT1 ) ;
2006-06-27 03:16:00 +04:00
level_mask & = enabled ;
}
2006-04-02 20:46:23 +04:00
/* clear edge sensitive interrupts before handler(s) are
called so that we don ' t miss any interrupt occurred while
executing them */
_enable_gpio_irqbank ( bank , isr_saved & ~ level_mask , 0 ) ;
_clear_gpio_irqbank ( bank , isr_saved & ~ level_mask ) ;
_enable_gpio_irqbank ( bank , isr_saved & ~ level_mask , 1 ) ;
/* if there is only edge sensitive GPIO pin interrupts
configured , we could unmask GPIO bank interrupt immediately */
2006-06-27 03:16:00 +04:00
if ( ! level_mask & & ! unmasked ) {
unmasked = 1 ;
2006-04-02 20:46:23 +04:00
desc - > chip - > unmask ( irq ) ;
2006-06-27 03:16:00 +04:00
}
2005-09-07 20:20:26 +04:00
2006-06-27 03:16:00 +04:00
isr | = retrigger ;
retrigger = 0 ;
2005-09-07 20:20:26 +04:00
if ( ! isr )
break ;
gpio_irq = bank - > virtual_irq_start ;
for ( ; isr ! = 0 ; isr > > = 1 , gpio_irq + + ) {
struct irqdesc * d ;
2006-06-27 03:16:00 +04:00
int irq_mask ;
2005-09-07 20:20:26 +04:00
if ( ! ( isr & 1 ) )
continue ;
d = irq_desc + gpio_irq ;
2006-06-27 03:16:00 +04:00
/* Don't run the handler if it's already running
* or was disabled lazely .
*/
2006-07-03 04:22:22 +04:00
if ( unlikely ( ( d - > depth | |
( d - > status & IRQ_INPROGRESS ) ) ) ) {
2006-06-27 03:16:00 +04:00
irq_mask = 1 < <
( gpio_irq - bank - > virtual_irq_start ) ;
/* The unmasking will be done by
* enable_irq in case it is disabled or
* after returning from the handler if
* it ' s already running .
*/
_enable_gpio_irqbank ( bank , irq_mask , 0 ) ;
2006-07-03 04:22:22 +04:00
if ( ! d - > depth ) {
2006-06-27 03:16:00 +04:00
/* Level triggered interrupts
* won ' t ever be reentered
*/
BUG_ON ( level_mask & irq_mask ) ;
2006-07-03 04:22:22 +04:00
d - > status | = IRQ_PENDING ;
2006-06-27 03:16:00 +04:00
}
continue ;
}
2006-07-03 04:22:22 +04:00
2005-09-07 20:20:26 +04:00
desc_handle_irq ( gpio_irq , d , regs ) ;
2006-07-03 04:22:22 +04:00
if ( unlikely ( ( d - > status & IRQ_PENDING ) & & ! d - > depth ) ) {
2006-06-27 03:16:00 +04:00
irq_mask = 1 < <
( gpio_irq - bank - > virtual_irq_start ) ;
2006-07-03 04:22:22 +04:00
d - > status & = ~ IRQ_PENDING ;
2006-06-27 03:16:00 +04:00
_enable_gpio_irqbank ( bank , irq_mask , 1 ) ;
retrigger | = irq_mask ;
}
2005-09-07 20:20:26 +04:00
}
2006-04-02 20:46:23 +04:00
if ( cpu_is_omap24xx ( ) ) {
/* clear level sensitive interrupts after handler(s) */
_enable_gpio_irqbank ( bank , isr_saved & level_mask , 0 ) ;
_clear_gpio_irqbank ( bank , isr_saved & level_mask ) ;
_enable_gpio_irqbank ( bank , isr_saved & level_mask , 1 ) ;
}
2005-11-10 17:26:50 +03:00
}
2006-06-27 03:16:00 +04:00
/* if bank has any level sensitive GPIO pin interrupt
configured , we must unmask the bank interrupt only after
handler ( s ) are executed in order to avoid spurious bank
interrupt */
if ( ! unmasked )
desc - > chip - > unmask ( irq ) ;
2005-07-10 22:58:15 +04:00
}
2006-09-25 13:41:38 +04:00
static void gpio_irq_shutdown ( unsigned int irq )
{
unsigned int gpio = irq - IH_GPIO_BASE ;
struct gpio_bank * bank = get_gpio_bank ( gpio ) ;
_reset_gpio ( bank , gpio ) ;
}
2005-07-10 22:58:15 +04:00
static void gpio_ack_irq ( unsigned int irq )
{
unsigned int gpio = irq - IH_GPIO_BASE ;
struct gpio_bank * bank = get_gpio_bank ( gpio ) ;
_clear_gpio_irqstatus ( bank , gpio ) ;
}
static void gpio_mask_irq ( unsigned int irq )
{
unsigned int gpio = irq - IH_GPIO_BASE ;
struct gpio_bank * bank = get_gpio_bank ( gpio ) ;
_set_gpio_irqenable ( bank , gpio , 0 ) ;
}
static void gpio_unmask_irq ( unsigned int irq )
{
unsigned int gpio = irq - IH_GPIO_BASE ;
2005-09-07 20:20:26 +04:00
unsigned int gpio_idx = get_gpio_index ( gpio ) ;
2005-07-10 22:58:15 +04:00
struct gpio_bank * bank = get_gpio_bank ( gpio ) ;
2005-09-07 20:20:26 +04:00
_set_gpio_irqenable ( bank , gpio_idx , 1 ) ;
2005-07-10 22:58:15 +04:00
}
static void mpuio_ack_irq ( unsigned int irq )
{
/* The ISR is reset automatically, so do nothing here. */
}
static void mpuio_mask_irq ( unsigned int irq )
{
unsigned int gpio = OMAP_MPUIO ( irq - IH_MPUIO_BASE ) ;
struct gpio_bank * bank = get_gpio_bank ( gpio ) ;
_set_gpio_irqenable ( bank , gpio , 0 ) ;
}
static void mpuio_unmask_irq ( unsigned int irq )
{
unsigned int gpio = OMAP_MPUIO ( irq - IH_MPUIO_BASE ) ;
struct gpio_bank * bank = get_gpio_bank ( gpio ) ;
_set_gpio_irqenable ( bank , gpio , 1 ) ;
}
2006-08-02 01:26:25 +04:00
static struct irq_chip gpio_irq_chip = {
. name = " GPIO " ,
2006-09-25 13:41:38 +04:00
. shutdown = gpio_irq_shutdown ,
2005-09-07 20:20:26 +04:00
. ack = gpio_ack_irq ,
. mask = gpio_mask_irq ,
. unmask = gpio_unmask_irq ,
. set_type = gpio_irq_type ,
. set_wake = gpio_wake_enable ,
2005-07-10 22:58:15 +04:00
} ;
2006-08-02 01:26:25 +04:00
static struct irq_chip mpuio_irq_chip = {
. name = " MPUIO " ,
2005-07-10 22:58:15 +04:00
. ack = mpuio_ack_irq ,
. mask = mpuio_mask_irq ,
2006-08-02 01:26:25 +04:00
. unmask = mpuio_unmask_irq
2005-07-10 22:58:15 +04:00
} ;
2005-11-10 17:26:50 +03:00
static int initialized ;
static struct clk * gpio_ick ;
static struct clk * gpio_fck ;
2005-07-10 22:58:15 +04:00
static int __init _omap_gpio_init ( void )
{
int i ;
struct gpio_bank * bank ;
initialized = 1 ;
2006-04-02 20:46:23 +04:00
if ( cpu_is_omap15xx ( ) ) {
2005-11-10 17:26:50 +03:00
gpio_ick = clk_get ( NULL , " arm_gpio_ck " ) ;
if ( IS_ERR ( gpio_ick ) )
2005-09-07 20:20:26 +04:00
printk ( " Could not get arm_gpio_ck \n " ) ;
else
2006-01-18 02:33:51 +03:00
clk_enable ( gpio_ick ) ;
2005-11-10 17:26:50 +03:00
}
if ( cpu_is_omap24xx ( ) ) {
gpio_ick = clk_get ( NULL , " gpios_ick " ) ;
if ( IS_ERR ( gpio_ick ) )
printk ( " Could not get gpios_ick \n " ) ;
else
2006-01-18 02:33:51 +03:00
clk_enable ( gpio_ick ) ;
2005-11-10 17:26:50 +03:00
gpio_fck = clk_get ( NULL , " gpios_fck " ) ;
if ( IS_ERR ( gpio_ick ) )
printk ( " Could not get gpios_fck \n " ) ;
else
2006-01-18 02:33:51 +03:00
clk_enable ( gpio_fck ) ;
2005-09-07 20:20:26 +04:00
}
2005-11-10 17:26:50 +03:00
# ifdef CONFIG_ARCH_OMAP15XX
2006-04-02 20:46:23 +04:00
if ( cpu_is_omap15xx ( ) ) {
2005-07-10 22:58:15 +04:00
printk ( KERN_INFO " OMAP1510 GPIO hardware \n " ) ;
gpio_bank_count = 2 ;
gpio_bank = gpio_bank_1510 ;
}
# endif
# if defined(CONFIG_ARCH_OMAP16XX)
if ( cpu_is_omap16xx ( ) ) {
2005-09-07 20:20:26 +04:00
u32 rev ;
2005-07-10 22:58:15 +04:00
gpio_bank_count = 5 ;
gpio_bank = gpio_bank_1610 ;
rev = omap_readw ( gpio_bank [ 1 ] . base + OMAP1610_GPIO_REVISION ) ;
printk ( KERN_INFO " OMAP GPIO hardware version %d.%d \n " ,
( rev > > 4 ) & 0x0f , rev & 0x0f ) ;
}
# endif
# ifdef CONFIG_ARCH_OMAP730
if ( cpu_is_omap730 ( ) ) {
printk ( KERN_INFO " OMAP730 GPIO hardware \n " ) ;
gpio_bank_count = 7 ;
gpio_bank = gpio_bank_730 ;
}
2005-09-07 20:20:26 +04:00
# endif
# ifdef CONFIG_ARCH_OMAP24XX
if ( cpu_is_omap24xx ( ) ) {
int rev ;
gpio_bank_count = 4 ;
gpio_bank = gpio_bank_24xx ;
rev = omap_readl ( gpio_bank [ 0 ] . base + OMAP24XX_GPIO_REVISION ) ;
printk ( KERN_INFO " OMAP24xx GPIO hardware version %d.%d \n " ,
( rev > > 4 ) & 0x0f , rev & 0x0f ) ;
}
2005-07-10 22:58:15 +04:00
# endif
for ( i = 0 ; i < gpio_bank_count ; i + + ) {
int j , gpio_count = 16 ;
bank = & gpio_bank [ i ] ;
bank - > reserved_map = 0 ;
bank - > base = IO_ADDRESS ( bank - > base ) ;
spin_lock_init ( & bank - > lock ) ;
if ( bank - > method = = METHOD_MPUIO ) {
omap_writew ( 0xFFFF , OMAP_MPUIO_BASE + OMAP_MPUIO_GPIO_MASKIT ) ;
}
2005-11-10 17:26:50 +03:00
# ifdef CONFIG_ARCH_OMAP15XX
2005-07-10 22:58:15 +04:00
if ( bank - > method = = METHOD_GPIO_1510 ) {
__raw_writew ( 0xffff , bank - > base + OMAP1510_GPIO_INT_MASK ) ;
__raw_writew ( 0x0000 , bank - > base + OMAP1510_GPIO_INT_STATUS ) ;
}
# endif
# if defined(CONFIG_ARCH_OMAP16XX)
if ( bank - > method = = METHOD_GPIO_1610 ) {
__raw_writew ( 0x0000 , bank - > base + OMAP1610_GPIO_IRQENABLE1 ) ;
__raw_writew ( 0xffff , bank - > base + OMAP1610_GPIO_IRQSTATUS1 ) ;
2005-09-07 20:20:26 +04:00
__raw_writew ( 0x0014 , bank - > base + OMAP1610_GPIO_SYSCONFIG ) ;
2005-07-10 22:58:15 +04:00
}
# endif
# ifdef CONFIG_ARCH_OMAP730
if ( bank - > method = = METHOD_GPIO_730 ) {
__raw_writel ( 0xffffffff , bank - > base + OMAP730_GPIO_INT_MASK ) ;
__raw_writel ( 0x00000000 , bank - > base + OMAP730_GPIO_INT_STATUS ) ;
gpio_count = 32 ; /* 730 has 32-bit GPIOs */
}
2005-09-07 20:20:26 +04:00
# endif
# ifdef CONFIG_ARCH_OMAP24XX
if ( bank - > method = = METHOD_GPIO_24XX ) {
__raw_writel ( 0x00000000 , bank - > base + OMAP24XX_GPIO_IRQENABLE1 ) ;
__raw_writel ( 0xffffffff , bank - > base + OMAP24XX_GPIO_IRQSTATUS1 ) ;
gpio_count = 32 ;
}
2005-07-10 22:58:15 +04:00
# endif
for ( j = bank - > virtual_irq_start ;
j < bank - > virtual_irq_start + gpio_count ; j + + ) {
if ( bank - > method = = METHOD_MPUIO )
set_irq_chip ( j , & mpuio_irq_chip ) ;
else
set_irq_chip ( j , & gpio_irq_chip ) ;
set_irq_handler ( j , do_simple_IRQ ) ;
set_irq_flags ( j , IRQF_VALID ) ;
}
set_irq_chained_handler ( bank - > irq , gpio_irq_handler ) ;
set_irq_data ( bank - > irq , bank ) ;
}
/* Enable system clock for GPIO module.
* The CAM_CLK_CTRL * is * really the right place . */
2005-09-07 20:20:26 +04:00
if ( cpu_is_omap16xx ( ) )
2005-07-10 22:58:15 +04:00
omap_writel ( omap_readl ( ULPD_CAM_CLK_CTRL ) | 0x04 , ULPD_CAM_CLK_CTRL ) ;
return 0 ;
}
2005-09-07 20:20:26 +04:00
# if defined (CONFIG_ARCH_OMAP16XX) || defined (CONFIG_ARCH_OMAP24XX)
static int omap_gpio_suspend ( struct sys_device * dev , pm_message_t mesg )
{
int i ;
if ( ! cpu_is_omap24xx ( ) & & ! cpu_is_omap16xx ( ) )
return 0 ;
for ( i = 0 ; i < gpio_bank_count ; i + + ) {
struct gpio_bank * bank = & gpio_bank [ i ] ;
void __iomem * wake_status ;
void __iomem * wake_clear ;
void __iomem * wake_set ;
switch ( bank - > method ) {
case METHOD_GPIO_1610 :
wake_status = bank - > base + OMAP1610_GPIO_WAKEUPENABLE ;
wake_clear = bank - > base + OMAP1610_GPIO_CLEAR_WAKEUPENA ;
wake_set = bank - > base + OMAP1610_GPIO_SET_WAKEUPENA ;
break ;
case METHOD_GPIO_24XX :
wake_status = bank - > base + OMAP24XX_GPIO_SETWKUENA ;
wake_clear = bank - > base + OMAP24XX_GPIO_CLEARWKUENA ;
wake_set = bank - > base + OMAP24XX_GPIO_SETWKUENA ;
break ;
default :
continue ;
}
spin_lock ( & bank - > lock ) ;
bank - > saved_wakeup = __raw_readl ( wake_status ) ;
__raw_writel ( 0xffffffff , wake_clear ) ;
__raw_writel ( bank - > suspend_wakeup , wake_set ) ;
spin_unlock ( & bank - > lock ) ;
}
return 0 ;
}
static int omap_gpio_resume ( struct sys_device * dev )
{
int i ;
if ( ! cpu_is_omap24xx ( ) & & ! cpu_is_omap16xx ( ) )
return 0 ;
for ( i = 0 ; i < gpio_bank_count ; i + + ) {
struct gpio_bank * bank = & gpio_bank [ i ] ;
void __iomem * wake_clear ;
void __iomem * wake_set ;
switch ( bank - > method ) {
case METHOD_GPIO_1610 :
wake_clear = bank - > base + OMAP1610_GPIO_CLEAR_WAKEUPENA ;
wake_set = bank - > base + OMAP1610_GPIO_SET_WAKEUPENA ;
break ;
case METHOD_GPIO_24XX :
2006-09-25 13:41:45 +04:00
wake_clear = bank - > base + OMAP24XX_GPIO_CLEARWKUENA ;
wake_set = bank - > base + OMAP24XX_GPIO_SETWKUENA ;
2005-09-07 20:20:26 +04:00
break ;
default :
continue ;
}
spin_lock ( & bank - > lock ) ;
__raw_writel ( 0xffffffff , wake_clear ) ;
__raw_writel ( bank - > saved_wakeup , wake_set ) ;
spin_unlock ( & bank - > lock ) ;
}
return 0 ;
}
static struct sysdev_class omap_gpio_sysclass = {
set_kset_name ( " gpio " ) ,
. suspend = omap_gpio_suspend ,
. resume = omap_gpio_resume ,
} ;
static struct sys_device omap_gpio_device = {
. id = 0 ,
. cls = & omap_gpio_sysclass ,
} ;
# endif
2005-07-10 22:58:15 +04:00
/*
* This may get called early from board specific init
2005-11-10 17:26:50 +03:00
* for boards that have interrupts routed via FPGA .
2005-07-10 22:58:15 +04:00
*/
int omap_gpio_init ( void )
{
if ( ! initialized )
return _omap_gpio_init ( ) ;
else
return 0 ;
}
2005-09-07 20:20:26 +04:00
static int __init omap_gpio_sysinit ( void )
{
int ret = 0 ;
if ( ! initialized )
ret = _omap_gpio_init ( ) ;
# if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP24XX)
if ( cpu_is_omap16xx ( ) | | cpu_is_omap24xx ( ) ) {
if ( ret = = 0 ) {
ret = sysdev_class_register ( & omap_gpio_sysclass ) ;
if ( ret = = 0 )
ret = sysdev_register ( & omap_gpio_device ) ;
}
}
# endif
return ret ;
}
2005-07-10 22:58:15 +04:00
EXPORT_SYMBOL ( omap_request_gpio ) ;
EXPORT_SYMBOL ( omap_free_gpio ) ;
EXPORT_SYMBOL ( omap_set_gpio_direction ) ;
EXPORT_SYMBOL ( omap_set_gpio_dataout ) ;
EXPORT_SYMBOL ( omap_get_gpio_datain ) ;
2005-09-07 20:20:26 +04:00
arch_initcall ( omap_gpio_sysinit ) ;