2009-09-28 12:23:41 +00:00
/*
* GPIOLIB interface for BF538 / 9 PORT C , D , and E GPIOs
*
2011-06-27 14:46:14 -04:00
* Copyright 2009 - 2011 Analog Devices Inc .
2009-09-28 12:23:41 +00:00
*
* Licensed under the GPL - 2 or later .
*/
# include <linux/module.h>
# include <linux/err.h>
# include <asm/blackfin.h>
# include <asm/gpio.h>
# include <asm/portmux.h>
# define DEFINE_REG(reg, off) \
static inline u16 read_ # # reg ( void __iomem * port ) \
{ return bfin_read16 ( port + off ) ; } \
static inline void write_ # # reg ( void __iomem * port , u16 v ) \
{ bfin_write16 ( port + off , v ) ; }
DEFINE_REG ( PORTIO , 0x00 )
DEFINE_REG ( PORTIO_CLEAR , 0x10 )
DEFINE_REG ( PORTIO_SET , 0x20 )
DEFINE_REG ( PORTIO_DIR , 0x40 )
DEFINE_REG ( PORTIO_INEN , 0x50 )
static void __iomem * gpio_chip_to_mmr ( struct gpio_chip * chip )
{
switch ( chip - > base ) {
default : /* not really needed, but keeps gcc happy */
case GPIO_PC0 : return ( void __iomem * ) PORTCIO ;
case GPIO_PD0 : return ( void __iomem * ) PORTDIO ;
case GPIO_PE0 : return ( void __iomem * ) PORTEIO ;
}
}
static int bf538_gpio_get_value ( struct gpio_chip * chip , unsigned gpio )
{
void __iomem * port = gpio_chip_to_mmr ( chip ) ;
return ! ! ( read_PORTIO ( port ) & ( 1u < < gpio ) ) ;
}
static void bf538_gpio_set_value ( struct gpio_chip * chip , unsigned gpio , int value )
{
void __iomem * port = gpio_chip_to_mmr ( chip ) ;
if ( value )
write_PORTIO_SET ( port , ( 1u < < gpio ) ) ;
else
write_PORTIO_CLEAR ( port , ( 1u < < gpio ) ) ;
}
static int bf538_gpio_direction_input ( struct gpio_chip * chip , unsigned gpio )
{
void __iomem * port = gpio_chip_to_mmr ( chip ) ;
write_PORTIO_DIR ( port , read_PORTIO_DIR ( port ) & ~ ( 1u < < gpio ) ) ;
write_PORTIO_INEN ( port , read_PORTIO_INEN ( port ) | ( 1u < < gpio ) ) ;
return 0 ;
}
static int bf538_gpio_direction_output ( struct gpio_chip * chip , unsigned gpio , int value )
{
void __iomem * port = gpio_chip_to_mmr ( chip ) ;
write_PORTIO_INEN ( port , read_PORTIO_INEN ( port ) & ~ ( 1u < < gpio ) ) ;
bf538_gpio_set_value ( port , gpio , value ) ;
write_PORTIO_DIR ( port , read_PORTIO_DIR ( port ) | ( 1u < < gpio ) ) ;
return 0 ;
}
static int bf538_gpio_request ( struct gpio_chip * chip , unsigned gpio )
{
return bfin_special_gpio_request ( chip - > base + gpio , chip - > label ) ;
}
static void bf538_gpio_free ( struct gpio_chip * chip , unsigned gpio )
{
return bfin_special_gpio_free ( chip - > base + gpio ) ;
}
/* We don't set the irq fields as these banks cannot generate interrupts */
static struct gpio_chip bf538_portc_chip = {
. label = " GPIO-PC " ,
. direction_input = bf538_gpio_direction_input ,
. get = bf538_gpio_get_value ,
. direction_output = bf538_gpio_direction_output ,
. set = bf538_gpio_set_value ,
. request = bf538_gpio_request ,
. free = bf538_gpio_free ,
. base = GPIO_PC0 ,
. ngpio = GPIO_PC9 - GPIO_PC0 + 1 ,
} ;
static struct gpio_chip bf538_portd_chip = {
. label = " GPIO-PD " ,
. direction_input = bf538_gpio_direction_input ,
. get = bf538_gpio_get_value ,
. direction_output = bf538_gpio_direction_output ,
. set = bf538_gpio_set_value ,
. request = bf538_gpio_request ,
. free = bf538_gpio_free ,
. base = GPIO_PD0 ,
. ngpio = GPIO_PD13 - GPIO_PD0 + 1 ,
} ;
static struct gpio_chip bf538_porte_chip = {
. label = " GPIO-PE " ,
. direction_input = bf538_gpio_direction_input ,
. get = bf538_gpio_get_value ,
. direction_output = bf538_gpio_direction_output ,
. set = bf538_gpio_set_value ,
. request = bf538_gpio_request ,
. free = bf538_gpio_free ,
. base = GPIO_PE0 ,
. ngpio = GPIO_PE15 - GPIO_PE0 + 1 ,
} ;
static int __init bf538_extgpio_setup ( void )
{
return gpiochip_add ( & bf538_portc_chip ) |
gpiochip_add ( & bf538_portd_chip ) |
gpiochip_add ( & bf538_porte_chip ) ;
}
arch_initcall ( bf538_extgpio_setup ) ;
2011-06-27 14:46:14 -04:00
# ifdef CONFIG_PM
static struct {
u16 data , dir , inen ;
} gpio_bank_saved [ 3 ] ;
static void __iomem * const port_bases [ 3 ] = {
( void * ) PORTCIO ,
( void * ) PORTDIO ,
( void * ) PORTEIO ,
} ;
void bfin_special_gpio_pm_hibernate_suspend ( void )
{
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( port_bases ) ; + + i ) {
gpio_bank_saved [ i ] . data = read_PORTIO ( port_bases [ i ] ) ;
gpio_bank_saved [ i ] . inen = read_PORTIO_INEN ( port_bases [ i ] ) ;
gpio_bank_saved [ i ] . dir = read_PORTIO_DIR ( port_bases [ i ] ) ;
}
}
void bfin_special_gpio_pm_hibernate_restore ( void )
{
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( port_bases ) ; + + i ) {
write_PORTIO_INEN ( port_bases [ i ] , gpio_bank_saved [ i ] . inen ) ;
write_PORTIO_SET ( port_bases [ i ] ,
gpio_bank_saved [ i ] . data & gpio_bank_saved [ i ] . dir ) ;
write_PORTIO_DIR ( port_bases [ i ] , gpio_bank_saved [ i ] . dir ) ;
}
}
# endif