2010-03-15 19:40:06 -07:00
/*
* arch / arm / mach - tegra / gpio . c
*
* Copyright ( c ) 2010 Google , Inc
*
* Author :
* Erik Gilling < konkers @ google . com >
*
* This software is licensed under the terms of the GNU General Public
* License version 2 , as published by the Free Software Foundation , and
* may be copied , distributed , and modified under those terms .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
*/
# include <linux/init.h>
# include <linux/irq.h>
2010-04-07 12:59:42 -07:00
# include <linux/interrupt.h>
2010-03-15 19:40:06 -07:00
# include <linux/io.h>
# include <linux/gpio.h>
2012-03-16 17:35:08 -06:00
# include <linux/of_device.h>
2011-10-11 16:16:14 -06:00
# include <linux/platform_device.h>
# include <linux/module.h>
2012-01-04 08:39:37 +00:00
# include <linux/irqdomain.h>
2010-03-15 19:40:06 -07:00
2011-02-21 13:58:10 +00:00
# include <asm/mach/irq.h>
2011-09-26 19:00:02 +01:00
# include <mach/gpio-tegra.h>
2010-03-15 19:40:06 -07:00
# include <mach/iomap.h>
2010-10-04 08:49:49 -07:00
# include <mach/suspend.h>
2010-03-15 19:40:06 -07:00
# define GPIO_BANK(x) ((x) >> 5)
# define GPIO_PORT(x) (((x) >> 3) & 0x3)
# define GPIO_BIT(x) ((x) & 0x7)
2012-03-16 17:35:08 -06:00
# define GPIO_REG(x) (GPIO_BANK(x) * tegra_gpio_bank_stride + \
GPIO_PORT ( x ) * 4 )
2010-03-15 19:40:06 -07:00
# define GPIO_CNF(x) (GPIO_REG(x) + 0x00)
# define GPIO_OE(x) (GPIO_REG(x) + 0x10)
# define GPIO_OUT(x) (GPIO_REG(x) + 0X20)
# define GPIO_IN(x) (GPIO_REG(x) + 0x30)
# define GPIO_INT_STA(x) (GPIO_REG(x) + 0x40)
# define GPIO_INT_ENB(x) (GPIO_REG(x) + 0x50)
# define GPIO_INT_LVL(x) (GPIO_REG(x) + 0x60)
# define GPIO_INT_CLR(x) (GPIO_REG(x) + 0x70)
2012-03-16 17:35:08 -06:00
# define GPIO_MSK_CNF(x) (GPIO_REG(x) + tegra_gpio_upper_offset + 0x00)
# define GPIO_MSK_OE(x) (GPIO_REG(x) + tegra_gpio_upper_offset + 0x10)
# define GPIO_MSK_OUT(x) (GPIO_REG(x) + tegra_gpio_upper_offset + 0X20)
# define GPIO_MSK_INT_STA(x) (GPIO_REG(x) + tegra_gpio_upper_offset + 0x40)
# define GPIO_MSK_INT_ENB(x) (GPIO_REG(x) + tegra_gpio_upper_offset + 0x50)
# define GPIO_MSK_INT_LVL(x) (GPIO_REG(x) + tegra_gpio_upper_offset + 0x60)
2010-03-15 19:40:06 -07:00
# define GPIO_INT_LVL_MASK 0x010101
# define GPIO_INT_LVL_EDGE_RISING 0x000101
# define GPIO_INT_LVL_EDGE_FALLING 0x000100
# define GPIO_INT_LVL_EDGE_BOTH 0x010100
# define GPIO_INT_LVL_LEVEL_HIGH 0x000001
# define GPIO_INT_LVL_LEVEL_LOW 0x000000
struct tegra_gpio_bank {
int bank ;
int irq ;
spinlock_t lvl_lock [ 4 ] ;
2010-04-07 12:59:42 -07:00
# ifdef CONFIG_PM
u32 cnf [ 4 ] ;
u32 out [ 4 ] ;
u32 oe [ 4 ] ;
u32 int_enb [ 4 ] ;
u32 int_lvl [ 4 ] ;
# endif
2010-03-15 19:40:06 -07:00
} ;
2012-02-13 16:21:15 -07:00
static struct irq_domain * irq_domain ;
2011-10-11 16:16:14 -06:00
static void __iomem * regs ;
2012-01-19 08:16:35 +00:00
static u32 tegra_gpio_bank_count ;
2012-03-16 17:35:08 -06:00
static u32 tegra_gpio_bank_stride ;
static u32 tegra_gpio_upper_offset ;
2012-01-19 08:16:35 +00:00
static struct tegra_gpio_bank * tegra_gpio_banks ;
2011-10-11 16:16:14 -06:00
static inline void tegra_gpio_writel ( u32 val , u32 reg )
{
__raw_writel ( val , regs + reg ) ;
}
static inline u32 tegra_gpio_readl ( u32 reg )
{
return __raw_readl ( regs + reg ) ;
}
2010-03-15 19:40:06 -07:00
static int tegra_gpio_compose ( int bank , int port , int bit )
{
return ( bank < < 5 ) | ( ( port & 0x3 ) < < 3 ) | ( bit & 0x7 ) ;
}
static void tegra_gpio_mask_write ( u32 reg , int gpio , int value )
{
u32 val ;
val = 0x100 < < GPIO_BIT ( gpio ) ;
if ( value )
val | = 1 < < GPIO_BIT ( gpio ) ;
2011-10-11 16:16:14 -06:00
tegra_gpio_writel ( val , reg ) ;
2010-03-15 19:40:06 -07:00
}
void tegra_gpio_enable ( int gpio )
{
tegra_gpio_mask_write ( GPIO_MSK_CNF ( gpio ) , gpio , 1 ) ;
}
2012-03-02 17:32:24 -05:00
EXPORT_SYMBOL_GPL ( tegra_gpio_enable ) ;
2010-03-15 19:40:06 -07:00
void tegra_gpio_disable ( int gpio )
{
tegra_gpio_mask_write ( GPIO_MSK_CNF ( gpio ) , gpio , 0 ) ;
}
2012-03-02 17:32:24 -05:00
EXPORT_SYMBOL_GPL ( tegra_gpio_disable ) ;
2010-03-15 19:40:06 -07:00
static void tegra_gpio_set ( struct gpio_chip * chip , unsigned offset , int value )
{
tegra_gpio_mask_write ( GPIO_MSK_OUT ( offset ) , offset , value ) ;
}
static int tegra_gpio_get ( struct gpio_chip * chip , unsigned offset )
{
2011-10-11 16:16:14 -06:00
return ( tegra_gpio_readl ( GPIO_IN ( offset ) ) > > GPIO_BIT ( offset ) ) & 0x1 ;
2010-03-15 19:40:06 -07:00
}
static int tegra_gpio_direction_input ( struct gpio_chip * chip , unsigned offset )
{
tegra_gpio_mask_write ( GPIO_MSK_OE ( offset ) , offset , 0 ) ;
return 0 ;
}
static int tegra_gpio_direction_output ( struct gpio_chip * chip , unsigned offset ,
int value )
{
tegra_gpio_set ( chip , offset , value ) ;
tegra_gpio_mask_write ( GPIO_MSK_OE ( offset ) , offset , 1 ) ;
return 0 ;
}
2011-08-23 00:39:56 +01:00
static int tegra_gpio_to_irq ( struct gpio_chip * chip , unsigned offset )
{
2012-02-13 16:21:15 -07:00
return irq_find_mapping ( irq_domain , offset ) ;
2011-08-23 00:39:56 +01:00
}
2010-03-15 19:40:06 -07:00
static struct gpio_chip tegra_gpio_chip = {
. label = " tegra-gpio " ,
. direction_input = tegra_gpio_direction_input ,
. get = tegra_gpio_get ,
. direction_output = tegra_gpio_direction_output ,
. set = tegra_gpio_set ,
2011-08-23 00:39:56 +01:00
. to_irq = tegra_gpio_to_irq ,
2010-03-15 19:40:06 -07:00
. base = 0 ,
2010-04-07 12:59:42 -07:00
. ngpio = TEGRA_NR_GPIOS ,
2010-03-15 19:40:06 -07:00
} ;
2010-11-29 11:14:46 +01:00
static void tegra_gpio_irq_ack ( struct irq_data * d )
2010-03-15 19:40:06 -07:00
{
2012-01-04 08:39:37 +00:00
int gpio = d - > hwirq ;
2010-03-15 19:40:06 -07:00
2011-10-11 16:16:14 -06:00
tegra_gpio_writel ( 1 < < GPIO_BIT ( gpio ) , GPIO_INT_CLR ( gpio ) ) ;
2010-03-15 19:40:06 -07:00
}
2010-11-29 11:14:46 +01:00
static void tegra_gpio_irq_mask ( struct irq_data * d )
2010-03-15 19:40:06 -07:00
{
2012-01-04 08:39:37 +00:00
int gpio = d - > hwirq ;
2010-03-15 19:40:06 -07:00
tegra_gpio_mask_write ( GPIO_MSK_INT_ENB ( gpio ) , gpio , 0 ) ;
}
2010-11-29 11:14:46 +01:00
static void tegra_gpio_irq_unmask ( struct irq_data * d )
2010-03-15 19:40:06 -07:00
{
2012-01-04 08:39:37 +00:00
int gpio = d - > hwirq ;
2010-03-15 19:40:06 -07:00
tegra_gpio_mask_write ( GPIO_MSK_INT_ENB ( gpio ) , gpio , 1 ) ;
}
2010-11-29 11:14:46 +01:00
static int tegra_gpio_irq_set_type ( struct irq_data * d , unsigned int type )
2010-03-15 19:40:06 -07:00
{
2012-01-04 08:39:37 +00:00
int gpio = d - > hwirq ;
2010-11-29 11:14:46 +01:00
struct tegra_gpio_bank * bank = irq_data_get_irq_chip_data ( d ) ;
2010-03-15 19:40:06 -07:00
int port = GPIO_PORT ( gpio ) ;
int lvl_type ;
int val ;
unsigned long flags ;
switch ( type & IRQ_TYPE_SENSE_MASK ) {
case IRQ_TYPE_EDGE_RISING :
lvl_type = GPIO_INT_LVL_EDGE_RISING ;
break ;
case IRQ_TYPE_EDGE_FALLING :
lvl_type = GPIO_INT_LVL_EDGE_FALLING ;
break ;
case IRQ_TYPE_EDGE_BOTH :
lvl_type = GPIO_INT_LVL_EDGE_BOTH ;
break ;
case IRQ_TYPE_LEVEL_HIGH :
lvl_type = GPIO_INT_LVL_LEVEL_HIGH ;
break ;
case IRQ_TYPE_LEVEL_LOW :
lvl_type = GPIO_INT_LVL_LEVEL_LOW ;
break ;
default :
return - EINVAL ;
}
spin_lock_irqsave ( & bank - > lvl_lock [ port ] , flags ) ;
2011-10-11 16:16:14 -06:00
val = tegra_gpio_readl ( GPIO_INT_LVL ( gpio ) ) ;
2010-03-15 19:40:06 -07:00
val & = ~ ( GPIO_INT_LVL_MASK < < GPIO_BIT ( gpio ) ) ;
val | = lvl_type < < GPIO_BIT ( gpio ) ;
2011-10-11 16:16:14 -06:00
tegra_gpio_writel ( val , GPIO_INT_LVL ( gpio ) ) ;
2010-03-15 19:40:06 -07:00
spin_unlock_irqrestore ( & bank - > lvl_lock [ port ] , flags ) ;
if ( type & ( IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH ) )
2011-03-24 13:25:22 +01:00
__irq_set_handler_locked ( d - > irq , handle_level_irq ) ;
2010-03-15 19:40:06 -07:00
else if ( type & ( IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING ) )
2011-03-24 13:25:22 +01:00
__irq_set_handler_locked ( d - > irq , handle_edge_irq ) ;
2010-03-15 19:40:06 -07:00
return 0 ;
}
static void tegra_gpio_irq_handler ( unsigned int irq , struct irq_desc * desc )
{
struct tegra_gpio_bank * bank ;
int port ;
int pin ;
int unmasked = 0 ;
2011-02-21 13:58:10 +00:00
struct irq_chip * chip = irq_desc_get_chip ( desc ) ;
2010-03-15 19:40:06 -07:00
2011-02-21 13:58:10 +00:00
chained_irq_enter ( chip , desc ) ;
2010-03-15 19:40:06 -07:00
2011-03-24 13:25:22 +01:00
bank = irq_get_handler_data ( irq ) ;
2010-03-15 19:40:06 -07:00
for ( port = 0 ; port < 4 ; port + + ) {
int gpio = tegra_gpio_compose ( bank - > bank , port , 0 ) ;
2011-10-11 16:16:14 -06:00
unsigned long sta = tegra_gpio_readl ( GPIO_INT_STA ( gpio ) ) &
tegra_gpio_readl ( GPIO_INT_ENB ( gpio ) ) ;
u32 lvl = tegra_gpio_readl ( GPIO_INT_LVL ( gpio ) ) ;
2010-03-15 19:40:06 -07:00
for_each_set_bit ( pin , & sta , 8 ) {
2011-10-11 16:16:14 -06:00
tegra_gpio_writel ( 1 < < pin , GPIO_INT_CLR ( gpio ) ) ;
2010-03-15 19:40:06 -07:00
/* if gpio is edge triggered, clear condition
* before executing the hander so that we don ' t
* miss edges
*/
if ( lvl & ( 0x100 < < pin ) ) {
unmasked = 1 ;
2011-02-21 13:58:10 +00:00
chained_irq_exit ( chip , desc ) ;
2010-03-15 19:40:06 -07:00
}
generic_handle_irq ( gpio_to_irq ( gpio + pin ) ) ;
}
}
if ( ! unmasked )
2011-02-21 13:58:10 +00:00
chained_irq_exit ( chip , desc ) ;
2010-03-15 19:40:06 -07:00
}
2010-04-07 12:59:42 -07:00
# ifdef CONFIG_PM
void tegra_gpio_resume ( void )
{
unsigned long flags ;
2011-03-30 00:24:43 -07:00
int b ;
int p ;
2010-04-07 12:59:42 -07:00
local_irq_save ( flags ) ;
2012-01-19 08:16:35 +00:00
for ( b = 0 ; b < tegra_gpio_bank_count ; b + + ) {
2010-04-07 12:59:42 -07:00
struct tegra_gpio_bank * bank = & tegra_gpio_banks [ b ] ;
for ( p = 0 ; p < ARRAY_SIZE ( bank - > oe ) ; p + + ) {
unsigned int gpio = ( b < < 5 ) | ( p < < 3 ) ;
2011-10-11 16:16:14 -06:00
tegra_gpio_writel ( bank - > cnf [ p ] , GPIO_CNF ( gpio ) ) ;
tegra_gpio_writel ( bank - > out [ p ] , GPIO_OUT ( gpio ) ) ;
tegra_gpio_writel ( bank - > oe [ p ] , GPIO_OE ( gpio ) ) ;
tegra_gpio_writel ( bank - > int_lvl [ p ] , GPIO_INT_LVL ( gpio ) ) ;
tegra_gpio_writel ( bank - > int_enb [ p ] , GPIO_INT_ENB ( gpio ) ) ;
2010-04-07 12:59:42 -07:00
}
}
local_irq_restore ( flags ) ;
}
void tegra_gpio_suspend ( void )
{
unsigned long flags ;
2011-03-30 00:24:43 -07:00
int b ;
int p ;
2010-04-07 12:59:42 -07:00
local_irq_save ( flags ) ;
2012-01-19 08:16:35 +00:00
for ( b = 0 ; b < tegra_gpio_bank_count ; b + + ) {
2010-04-07 12:59:42 -07:00
struct tegra_gpio_bank * bank = & tegra_gpio_banks [ b ] ;
for ( p = 0 ; p < ARRAY_SIZE ( bank - > oe ) ; p + + ) {
unsigned int gpio = ( b < < 5 ) | ( p < < 3 ) ;
2011-10-11 16:16:14 -06:00
bank - > cnf [ p ] = tegra_gpio_readl ( GPIO_CNF ( gpio ) ) ;
bank - > out [ p ] = tegra_gpio_readl ( GPIO_OUT ( gpio ) ) ;
bank - > oe [ p ] = tegra_gpio_readl ( GPIO_OE ( gpio ) ) ;
bank - > int_enb [ p ] = tegra_gpio_readl ( GPIO_INT_ENB ( gpio ) ) ;
bank - > int_lvl [ p ] = tegra_gpio_readl ( GPIO_INT_LVL ( gpio ) ) ;
2010-04-07 12:59:42 -07:00
}
}
local_irq_restore ( flags ) ;
}
2010-11-29 11:14:46 +01:00
static int tegra_gpio_wake_enable ( struct irq_data * d , unsigned int enable )
2010-04-07 12:59:42 -07:00
{
2010-11-29 11:14:46 +01:00
struct tegra_gpio_bank * bank = irq_data_get_irq_chip_data ( d ) ;
2011-03-24 13:25:22 +01:00
return irq_set_irq_wake ( bank - > irq , enable ) ;
2010-04-07 12:59:42 -07:00
}
# endif
2010-03-15 19:40:06 -07:00
static struct irq_chip tegra_gpio_irq_chip = {
. name = " GPIO " ,
2010-11-29 11:14:46 +01:00
. irq_ack = tegra_gpio_irq_ack ,
. irq_mask = tegra_gpio_irq_mask ,
. irq_unmask = tegra_gpio_irq_unmask ,
. irq_set_type = tegra_gpio_irq_set_type ,
2010-04-07 12:59:42 -07:00
# ifdef CONFIG_PM
2010-11-29 11:14:46 +01:00
. irq_set_wake = tegra_gpio_wake_enable ,
2010-04-07 12:59:42 -07:00
# endif
2010-03-15 19:40:06 -07:00
} ;
2012-03-16 17:35:08 -06:00
struct tegra_gpio_soc_config {
u32 bank_stride ;
u32 upper_offset ;
} ;
static struct tegra_gpio_soc_config tegra20_gpio_config = {
. bank_stride = 0x80 ,
. upper_offset = 0x800 ,
} ;
static struct tegra_gpio_soc_config tegra30_gpio_config = {
. bank_stride = 0x100 ,
. upper_offset = 0x80 ,
} ;
static struct of_device_id tegra_gpio_of_match [ ] __devinitdata = {
{ . compatible = " nvidia,tegra30-gpio " , . data = & tegra30_gpio_config } ,
{ . compatible = " nvidia,tegra20-gpio " , . data = & tegra20_gpio_config } ,
{ } ,
} ;
2010-03-15 19:40:06 -07:00
/* This lock class tells lockdep that GPIO irqs are in a different
* category than their parents , so it won ' t report false recursion .
*/
static struct lock_class_key gpio_lock_class ;
2011-10-11 16:16:14 -06:00
static int __devinit tegra_gpio_probe ( struct platform_device * pdev )
2010-03-15 19:40:06 -07:00
{
2012-03-16 17:35:08 -06:00
const struct of_device_id * match ;
struct tegra_gpio_soc_config * config ;
2012-01-19 08:16:35 +00:00
int irq_base ;
2011-10-11 16:16:14 -06:00
struct resource * res ;
2010-03-15 19:40:06 -07:00
struct tegra_gpio_bank * bank ;
2011-08-23 00:39:55 +01:00
int gpio ;
2010-03-15 19:40:06 -07:00
int i ;
int j ;
2012-03-16 17:35:08 -06:00
match = of_match_device ( tegra_gpio_of_match , & pdev - > dev ) ;
if ( match )
config = ( struct tegra_gpio_soc_config * ) match - > data ;
else
config = & tegra20_gpio_config ;
tegra_gpio_bank_stride = config - > bank_stride ;
tegra_gpio_upper_offset = config - > upper_offset ;
2012-01-19 08:16:35 +00:00
for ( ; ; ) {
res = platform_get_resource ( pdev , IORESOURCE_IRQ , tegra_gpio_bank_count ) ;
if ( ! res )
break ;
tegra_gpio_bank_count + + ;
}
if ( ! tegra_gpio_bank_count ) {
dev_err ( & pdev - > dev , " Missing IRQ resource \n " ) ;
return - ENODEV ;
}
tegra_gpio_chip . ngpio = tegra_gpio_bank_count * 32 ;
tegra_gpio_banks = devm_kzalloc ( & pdev - > dev ,
tegra_gpio_bank_count * sizeof ( * tegra_gpio_banks ) ,
GFP_KERNEL ) ;
if ( ! tegra_gpio_banks ) {
dev_err ( & pdev - > dev , " Couldn't allocate bank structure \n " ) ;
return - ENODEV ;
}
irq_base = irq_alloc_descs ( - 1 , 0 , tegra_gpio_chip . ngpio , 0 ) ;
if ( irq_base < 0 ) {
2012-01-04 08:39:37 +00:00
dev_err ( & pdev - > dev , " Couldn't allocate IRQ numbers \n " ) ;
return - ENODEV ;
}
2012-02-13 16:21:15 -07:00
irq_domain = irq_domain_add_legacy ( pdev - > dev . of_node ,
tegra_gpio_chip . ngpio , irq_base , 0 ,
& irq_domain_simple_ops , NULL ) ;
2012-01-04 08:39:37 +00:00
2012-01-19 08:16:35 +00:00
for ( i = 0 ; i < tegra_gpio_bank_count ; i + + ) {
2011-10-11 16:16:14 -06:00
res = platform_get_resource ( pdev , IORESOURCE_IRQ , i ) ;
if ( ! res ) {
dev_err ( & pdev - > dev , " Missing IRQ resource \n " ) ;
return - ENODEV ;
}
bank = & tegra_gpio_banks [ i ] ;
bank - > bank = i ;
bank - > irq = res - > start ;
}
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
if ( ! res ) {
dev_err ( & pdev - > dev , " Missing MEM resource \n " ) ;
return - ENODEV ;
}
drivers/gpio/gpio-tegra.c: use devm_request_and_ioremap
Reimplement a call to devm_request_mem_region followed by a call to ioremap
or ioremap_nocache by a call to devm_request_and_ioremap.
The semantic patch that makes this transformation is as follows:
(http://coccinelle.lip6.fr/)
// <smpl>
@nm@
expression myname;
identifier i;
@@
struct platform_driver i = { .driver = { .name = myname } };
@@
expression dev,res,size;
expression nm.myname;
@@
-if (!devm_request_mem_region(dev, res->start, size,
- \(res->name\|dev_name(dev)\|myname\))) {
- ...
- return ...;
-}
... when != res->start
(
-devm_ioremap(dev,res->start,size)
+devm_request_and_ioremap(dev,res)
|
-devm_ioremap_nocache(dev,res->start,size)
+devm_request_and_ioremap(dev,res)
)
... when any
when != res->start
// </smpl>
Signed-off-by: Julia Lawall <julia@diku.dk>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
2011-12-27 15:01:26 +01:00
regs = devm_request_and_ioremap ( & pdev - > dev , res ) ;
2011-10-11 16:16:14 -06:00
if ( ! regs ) {
dev_err ( & pdev - > dev , " Couldn't ioremap regs \n " ) ;
return - ENODEV ;
}
2012-03-16 17:37:24 -06:00
for ( i = 0 ; i < tegra_gpio_bank_count ; i + + ) {
2010-03-15 19:40:06 -07:00
for ( j = 0 ; j < 4 ; j + + ) {
int gpio = tegra_gpio_compose ( i , j , 0 ) ;
2011-10-11 16:16:14 -06:00
tegra_gpio_writel ( 0x00 , GPIO_INT_ENB ( gpio ) ) ;
2010-03-15 19:40:06 -07:00
}
}
2011-06-15 14:54:14 -06:00
# ifdef CONFIG_OF_GPIO
2011-10-11 16:16:14 -06:00
tegra_gpio_chip . of_node = pdev - > dev . of_node ;
# endif
2011-06-15 14:54:14 -06:00
2010-03-15 19:40:06 -07:00
gpiochip_add ( & tegra_gpio_chip ) ;
2012-01-19 08:16:35 +00:00
for ( gpio = 0 ; gpio < tegra_gpio_chip . ngpio ; gpio + + ) {
2012-02-13 16:21:15 -07:00
int irq = irq_find_mapping ( irq_domain , gpio ) ;
2011-08-23 00:39:55 +01:00
/* No validity check; all Tegra GPIOs are valid IRQs */
2010-03-15 19:40:06 -07:00
2011-08-23 00:39:55 +01:00
bank = & tegra_gpio_banks [ GPIO_BANK ( gpio ) ] ;
2010-03-15 19:40:06 -07:00
2011-08-23 00:39:55 +01:00
irq_set_lockdep_class ( irq , & gpio_lock_class ) ;
irq_set_chip_data ( irq , bank ) ;
irq_set_chip_and_handler ( irq , & tegra_gpio_irq_chip ,
2011-03-24 13:35:09 +01:00
handle_simple_irq ) ;
2011-08-23 00:39:55 +01:00
set_irq_flags ( irq , IRQF_VALID ) ;
2010-03-15 19:40:06 -07:00
}
2012-01-19 08:16:35 +00:00
for ( i = 0 ; i < tegra_gpio_bank_count ; i + + ) {
2010-03-15 19:40:06 -07:00
bank = & tegra_gpio_banks [ i ] ;
2011-03-24 13:25:22 +01:00
irq_set_chained_handler ( bank - > irq , tegra_gpio_irq_handler ) ;
irq_set_handler_data ( bank - > irq , bank ) ;
2010-03-15 19:40:06 -07:00
for ( j = 0 ; j < 4 ; j + + )
spin_lock_init ( & bank - > lvl_lock [ j ] ) ;
}
return 0 ;
}
2011-10-11 16:16:14 -06:00
static struct platform_driver tegra_gpio_driver = {
. driver = {
. name = " tegra-gpio " ,
. owner = THIS_MODULE ,
. of_match_table = tegra_gpio_of_match ,
} ,
. probe = tegra_gpio_probe ,
} ;
static int __init tegra_gpio_init ( void )
{
return platform_driver_register ( & tegra_gpio_driver ) ;
}
2010-03-15 19:40:06 -07:00
postcore_initcall ( tegra_gpio_init ) ;
2012-03-19 11:36:00 -06:00
void tegra_gpio_config ( struct tegra_gpio_table * table , int num )
2011-02-13 19:12:27 -08:00
{
int i ;
for ( i = 0 ; i < num ; i + + ) {
int gpio = table [ i ] . gpio ;
if ( table [ i ] . enable )
tegra_gpio_enable ( gpio ) ;
else
tegra_gpio_disable ( gpio ) ;
}
}
2010-03-15 19:40:06 -07:00
# ifdef CONFIG_DEBUG_FS
# include <linux/debugfs.h>
# include <linux/seq_file.h>
static int dbg_gpio_show ( struct seq_file * s , void * unused )
{
int i ;
int j ;
2012-03-16 17:37:24 -06:00
for ( i = 0 ; i < tegra_gpio_bank_count ; i + + ) {
2010-03-15 19:40:06 -07:00
for ( j = 0 ; j < 4 ; j + + ) {
int gpio = tegra_gpio_compose ( i , j , 0 ) ;
2010-04-07 12:59:42 -07:00
seq_printf ( s ,
" %d:%d %02x %02x %02x %02x %02x %02x %06x \n " ,
i , j ,
2011-10-11 16:16:14 -06:00
tegra_gpio_readl ( GPIO_CNF ( gpio ) ) ,
tegra_gpio_readl ( GPIO_OE ( gpio ) ) ,
tegra_gpio_readl ( GPIO_OUT ( gpio ) ) ,
tegra_gpio_readl ( GPIO_IN ( gpio ) ) ,
tegra_gpio_readl ( GPIO_INT_STA ( gpio ) ) ,
tegra_gpio_readl ( GPIO_INT_ENB ( gpio ) ) ,
tegra_gpio_readl ( GPIO_INT_LVL ( gpio ) ) ) ;
2010-03-15 19:40:06 -07:00
}
}
return 0 ;
}
static int dbg_gpio_open ( struct inode * inode , struct file * file )
{
return single_open ( file , dbg_gpio_show , & inode - > i_private ) ;
}
static const struct file_operations debug_fops = {
. open = dbg_gpio_open ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = single_release ,
} ;
static int __init tegra_gpio_debuginit ( void )
{
( void ) debugfs_create_file ( " tegra_gpio " , S_IRUGO ,
NULL , NULL , & debug_fops ) ;
return 0 ;
}
late_initcall ( tegra_gpio_debuginit ) ;
# endif