2007-07-10 16:03:43 +04:00
/*
* TI DaVinci GPIO Support
*
2008-09-08 10:41:04 +04:00
* Copyright ( c ) 2006 - 2007 David Brownell
2007-07-10 16:03:43 +04:00
* Copyright ( c ) 2007 , MontaVista Software , Inc . < source @ mvista . com >
*
* 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 .
*/
# include <linux/errno.h>
# include <linux/kernel.h>
# include <linux/list.h>
# include <linux/module.h>
# include <linux/clk.h>
# include <linux/err.h>
# include <linux/io.h>
# include <linux/irq.h>
# include <linux/bitops.h>
2008-08-05 19:14:15 +04:00
# include <mach/irqs.h>
# include <mach/hardware.h>
# include <mach/gpio.h>
2007-07-10 16:03:43 +04:00
# include <asm/mach/irq.h>
2008-09-08 10:41:04 +04:00
static DEFINE_SPINLOCK ( gpio_lock ) ;
2007-07-10 16:03:43 +04:00
2008-09-08 10:41:04 +04:00
struct davinci_gpio {
struct gpio_chip chip ;
struct gpio_controller * __iomem regs ;
} ;
2007-07-10 16:03:43 +04:00
2008-09-08 10:41:04 +04:00
static struct davinci_gpio chips [ DIV_ROUND_UP ( DAVINCI_N_GPIO , 32 ) ] ;
2007-07-10 16:03:43 +04:00
/* create a non-inlined version */
2008-09-08 10:41:04 +04:00
static struct gpio_controller * __iomem __init gpio2controller ( unsigned gpio )
2007-07-10 16:03:43 +04:00
{
return __gpio_to_controller ( gpio ) ;
}
2008-09-08 10:41:04 +04:00
/*--------------------------------------------------------------------------*/
2007-07-10 16:03:43 +04:00
/*
2008-09-08 10:41:04 +04:00
* board setup code * MUST * set PINMUX0 and PINMUX1 as
* needed , and enable the GPIO clock .
2007-07-10 16:03:43 +04:00
*/
2008-09-08 10:41:04 +04:00
static int davinci_direction_in ( struct gpio_chip * chip , unsigned offset )
2007-07-10 16:03:43 +04:00
{
2008-09-08 10:41:04 +04:00
struct davinci_gpio * d = container_of ( chip , struct davinci_gpio , chip ) ;
struct gpio_controller * __iomem g = d - > regs ;
u32 temp ;
2007-07-10 16:03:43 +04:00
2008-09-08 10:41:04 +04:00
spin_lock ( & gpio_lock ) ;
temp = __raw_readl ( & g - > dir ) ;
temp | = ( 1 < < offset ) ;
__raw_writel ( temp , & g - > dir ) ;
spin_unlock ( & gpio_lock ) ;
2007-07-10 16:03:43 +04:00
2008-09-08 10:41:04 +04:00
return 0 ;
}
2007-07-10 16:03:43 +04:00
/*
* Read the pin ' s value ( works even if it ' s set up as output ) ;
* returns zero / nonzero .
*
* Note that changes are synched to the GPIO clock , so reading values back
* right after you ' ve set them may give old values .
*/
2008-09-08 10:41:04 +04:00
static int davinci_gpio_get ( struct gpio_chip * chip , unsigned offset )
2007-07-10 16:03:43 +04:00
{
2008-09-08 10:41:04 +04:00
struct davinci_gpio * d = container_of ( chip , struct davinci_gpio , chip ) ;
struct gpio_controller * __iomem g = d - > regs ;
2007-07-10 16:03:43 +04:00
2008-09-08 10:41:04 +04:00
return ( 1 < < offset ) & __raw_readl ( & g - > in_data ) ;
2007-07-10 16:03:43 +04:00
}
2008-09-08 10:41:04 +04:00
static int
davinci_direction_out ( struct gpio_chip * chip , unsigned offset , int value )
2007-07-10 16:03:43 +04:00
{
2008-09-08 10:41:04 +04:00
struct davinci_gpio * d = container_of ( chip , struct davinci_gpio , chip ) ;
struct gpio_controller * __iomem g = d - > regs ;
2007-07-10 16:03:43 +04:00
u32 temp ;
2008-09-08 10:41:04 +04:00
u32 mask = 1 < < offset ;
2007-07-10 16:03:43 +04:00
spin_lock ( & gpio_lock ) ;
temp = __raw_readl ( & g - > dir ) ;
2008-09-08 10:41:04 +04:00
temp & = ~ mask ;
__raw_writel ( mask , value ? & g - > set_data : & g - > clr_data ) ;
2007-07-10 16:03:43 +04:00
__raw_writel ( temp , & g - > dir ) ;
spin_unlock ( & gpio_lock ) ;
return 0 ;
}
2008-09-08 10:41:04 +04:00
/*
* Assuming the pin is muxed as a gpio output , set its output value .
*/
static void
davinci_gpio_set ( struct gpio_chip * chip , unsigned offset , int value )
2007-07-10 16:03:43 +04:00
{
2008-09-08 10:41:04 +04:00
struct davinci_gpio * d = container_of ( chip , struct davinci_gpio , chip ) ;
struct gpio_controller * __iomem g = d - > regs ;
2007-07-10 16:03:43 +04:00
2008-09-08 10:41:04 +04:00
__raw_writel ( ( 1 < < offset ) , value ? & g - > set_data : & g - > clr_data ) ;
}
static int __init davinci_gpio_setup ( void )
{
int i , base ;
for ( i = 0 , base = 0 ;
i < ARRAY_SIZE ( chips ) ;
i + + , base + = 32 ) {
chips [ i ] . chip . label = " DaVinci " ;
chips [ i ] . chip . direction_input = davinci_direction_in ;
chips [ i ] . chip . get = davinci_gpio_get ;
chips [ i ] . chip . direction_output = davinci_direction_out ;
chips [ i ] . chip . set = davinci_gpio_set ;
chips [ i ] . chip . base = base ;
chips [ i ] . chip . ngpio = DAVINCI_N_GPIO - base ;
if ( chips [ i ] . chip . ngpio > 32 )
chips [ i ] . chip . ngpio = 32 ;
chips [ i ] . regs = gpio2controller ( base ) ;
gpiochip_add ( & chips [ i ] . chip ) ;
}
2007-07-10 16:03:43 +04:00
return 0 ;
}
2008-09-08 10:41:04 +04:00
pure_initcall ( davinci_gpio_setup ) ;
2007-07-10 16:03:43 +04:00
2008-09-08 10:41:04 +04:00
/*--------------------------------------------------------------------------*/
2007-07-10 16:03:43 +04:00
/*
* We expect irqs will normally be set up as input pins , but they can also be
* used as output pins . . . which is convenient for testing .
*
* NOTE : GPIO0 . . GPIO7 also have direct INTC hookups , which work in addition
* to their GPIOBNK0 irq ( but with a bit less overhead ) . But we don ' t have
* a good way to hook those up . . .
*
* All those INTC hookups ( GPIO0 . . GPIO7 plus five IRQ banks ) can also
* serve as EDMA event triggers .
*/
static void gpio_irq_disable ( unsigned irq )
{
struct gpio_controller * __iomem g = get_irq_chip_data ( irq ) ;
u32 mask = __gpio_mask ( irq_to_gpio ( irq ) ) ;
__raw_writel ( mask , & g - > clr_falling ) ;
__raw_writel ( mask , & g - > clr_rising ) ;
}
static void gpio_irq_enable ( unsigned irq )
{
struct gpio_controller * __iomem g = get_irq_chip_data ( irq ) ;
u32 mask = __gpio_mask ( irq_to_gpio ( irq ) ) ;
if ( irq_desc [ irq ] . status & IRQ_TYPE_EDGE_FALLING )
__raw_writel ( mask , & g - > set_falling ) ;
if ( irq_desc [ irq ] . status & IRQ_TYPE_EDGE_RISING )
__raw_writel ( mask , & g - > set_rising ) ;
}
static int gpio_irq_type ( unsigned irq , unsigned trigger )
{
struct gpio_controller * __iomem g = get_irq_chip_data ( irq ) ;
u32 mask = __gpio_mask ( irq_to_gpio ( irq ) ) ;
if ( trigger & ~ ( IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING ) )
return - EINVAL ;
irq_desc [ irq ] . status & = ~ IRQ_TYPE_SENSE_MASK ;
irq_desc [ irq ] . status | = trigger ;
__raw_writel ( mask , ( trigger & IRQ_TYPE_EDGE_FALLING )
? & g - > set_falling : & g - > clr_falling ) ;
__raw_writel ( mask , ( trigger & IRQ_TYPE_EDGE_RISING )
? & g - > set_rising : & g - > clr_rising ) ;
return 0 ;
}
static struct irq_chip gpio_irqchip = {
. name = " GPIO " ,
. enable = gpio_irq_enable ,
. disable = gpio_irq_disable ,
. set_type = gpio_irq_type ,
} ;
static void
gpio_irq_handler ( unsigned irq , struct irq_desc * desc )
{
struct gpio_controller * __iomem g = get_irq_chip_data ( irq ) ;
u32 mask = 0xffff ;
/* we only care about one bank */
if ( irq & 1 )
mask < < = 16 ;
/* temporarily mask (level sensitive) parent IRQ */
desc - > chip - > ack ( irq ) ;
while ( 1 ) {
u32 status ;
int n ;
int res ;
/* ack any irqs */
status = __raw_readl ( & g - > intstat ) & mask ;
if ( ! status )
break ;
__raw_writel ( status , & g - > intstat ) ;
if ( irq & 1 )
status > > = 16 ;
/* now demux them to the right lowlevel handler */
n = ( int ) get_irq_data ( irq ) ;
while ( status ) {
res = ffs ( status ) ;
n + = res ;
2008-10-09 16:36:24 +04:00
generic_handle_irq ( n - 1 ) ;
2007-07-10 16:03:43 +04:00
status > > = res ;
}
}
desc - > chip - > unmask ( irq ) ;
/* now it may re-trigger */
}
/*
* NOTE : for suspend / resume , probably best to make a sysdev ( and class )
* with its suspend / resume calls hooking into the results of the set_wake ( )
* calls . . . so if no gpios are wakeup events the clock can be disabled ,
* with outputs left at previously set levels , and so that VDD3P3V . IOPWDN0
* can be set appropriately for GPIOV33 pins .
*/
static int __init davinci_gpio_irq_setup ( void )
{
unsigned gpio , irq , bank ;
struct clk * clk ;
clk = clk_get ( NULL , " gpio " ) ;
if ( IS_ERR ( clk ) ) {
printk ( KERN_ERR " Error %ld getting gpio clock? \n " ,
PTR_ERR ( clk ) ) ;
return 0 ;
}
clk_enable ( clk ) ;
for ( gpio = 0 , irq = gpio_to_irq ( 0 ) , bank = IRQ_GPIOBNK0 ;
gpio < DAVINCI_N_GPIO ; bank + + ) {
struct gpio_controller * __iomem g = gpio2controller ( gpio ) ;
unsigned i ;
__raw_writel ( ~ 0 , & g - > clr_falling ) ;
__raw_writel ( ~ 0 , & g - > clr_rising ) ;
/* set up all irqs in this bank */
set_irq_chained_handler ( bank , gpio_irq_handler ) ;
set_irq_chip_data ( bank , g ) ;
set_irq_data ( bank , ( void * ) irq ) ;
for ( i = 0 ; i < 16 & & gpio < DAVINCI_N_GPIO ;
i + + , irq + + , gpio + + ) {
set_irq_chip ( irq , & gpio_irqchip ) ;
set_irq_chip_data ( irq , g ) ;
set_irq_handler ( irq , handle_simple_irq ) ;
set_irq_flags ( irq , IRQF_VALID ) ;
}
}
/* BINTEN -- per-bank interrupt enable. genirq would also let these
* bits be set / cleared dynamically .
*/
__raw_writel ( 0x1f , ( void * __iomem )
IO_ADDRESS ( DAVINCI_GPIO_BASE + 0x08 ) ) ;
printk ( KERN_INFO " DaVinci: %d gpio irqs \n " , irq - gpio_to_irq ( 0 ) ) ;
return 0 ;
}
arch_initcall ( davinci_gpio_irq_setup ) ;