2007-10-23 15:14:42 -04:00
/*
2008-03-27 14:51:41 -04:00
* arch / arm / mach - orion5x / gpio . c
2007-10-23 15:14:42 -04:00
*
* GPIO functions for Marvell Orion System On Chip
*
* Maintainer : Tzachi Perelstein < tzachi @ marvell . com >
*
2008-03-27 14:51:41 -04:00
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed " as is " without any
2007-10-23 15:14:42 -04:00
* warranty of any kind , whether express or implied .
*/
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/module.h>
# include <linux/spinlock.h>
# include <linux/bitops.h>
# include <asm/gpio.h>
2008-03-27 14:51:41 -04:00
# include <asm/io.h>
2008-08-05 16:14:15 +01:00
# include <mach/orion5x.h>
2007-10-23 15:14:42 -04:00
# include "common.h"
static DEFINE_SPINLOCK ( gpio_lock ) ;
static unsigned long gpio_valid [ BITS_TO_LONGS ( GPIO_MAX ) ] ;
static const char * gpio_label [ GPIO_MAX ] ; /* non null for allocated GPIOs */
2008-05-10 23:25:46 +02:00
void __init orion5x_gpio_set_valid ( unsigned pin , int valid )
2007-10-23 15:14:42 -04:00
{
2008-05-10 23:25:46 +02:00
if ( valid )
__set_bit ( pin , gpio_valid ) ;
else
__clear_bit ( pin , gpio_valid ) ;
2007-10-23 15:14:42 -04:00
}
/*
* GENERIC_GPIO primitives
*/
int gpio_direction_input ( unsigned pin )
{
unsigned long flags ;
if ( pin > = GPIO_MAX | | ! test_bit ( pin , gpio_valid ) ) {
2008-03-04 15:08:02 -08:00
pr_debug ( " %s: invalid GPIO %d \n " , __func__ , pin ) ;
2007-10-23 15:14:42 -04:00
return - EINVAL ;
}
spin_lock_irqsave ( & gpio_lock , flags ) ;
/*
* Some callers might have not used the gpio_request ( ) ,
* so flag this pin as requested now .
*/
if ( ! gpio_label [ pin ] )
gpio_label [ pin ] = " ? " ;
2008-03-27 14:51:41 -04:00
orion5x_setbits ( GPIO_IO_CONF , 1 < < pin ) ;
2007-10-23 15:14:42 -04:00
spin_unlock_irqrestore ( & gpio_lock , flags ) ;
return 0 ;
}
EXPORT_SYMBOL ( gpio_direction_input ) ;
int gpio_direction_output ( unsigned pin , int value )
{
unsigned long flags ;
int mask ;
if ( pin > = GPIO_MAX | | ! test_bit ( pin , gpio_valid ) ) {
2008-03-04 15:08:02 -08:00
pr_debug ( " %s: invalid GPIO %d \n " , __func__ , pin ) ;
2007-10-23 15:14:42 -04:00
return - EINVAL ;
}
spin_lock_irqsave ( & gpio_lock , flags ) ;
/*
* Some callers might have not used the gpio_request ( ) ,
* so flag this pin as requested now .
*/
if ( ! gpio_label [ pin ] )
gpio_label [ pin ] = " ? " ;
mask = 1 < < pin ;
2008-03-27 14:51:41 -04:00
orion5x_clrbits ( GPIO_BLINK_EN , mask ) ;
2007-10-23 15:14:42 -04:00
if ( value )
2008-03-27 14:51:41 -04:00
orion5x_setbits ( GPIO_OUT , mask ) ;
2007-10-23 15:14:42 -04:00
else
2008-03-27 14:51:41 -04:00
orion5x_clrbits ( GPIO_OUT , mask ) ;
orion5x_clrbits ( GPIO_IO_CONF , mask ) ;
2007-10-23 15:14:42 -04:00
spin_unlock_irqrestore ( & gpio_lock , flags ) ;
return 0 ;
}
EXPORT_SYMBOL ( gpio_direction_output ) ;
int gpio_get_value ( unsigned pin )
{
int val , mask = 1 < < pin ;
2008-05-28 16:43:48 +02:00
if ( readl ( GPIO_IO_CONF ) & mask )
val = readl ( GPIO_DATA_IN ) ^ readl ( GPIO_IN_POL ) ;
2007-10-23 15:14:42 -04:00
else
2008-05-28 16:43:48 +02:00
val = readl ( GPIO_OUT ) ;
2007-10-23 15:14:42 -04:00
return val & mask ;
}
EXPORT_SYMBOL ( gpio_get_value ) ;
void gpio_set_value ( unsigned pin , int value )
{
unsigned long flags ;
int mask = 1 < < pin ;
spin_lock_irqsave ( & gpio_lock , flags ) ;
2008-03-27 14:51:41 -04:00
orion5x_clrbits ( GPIO_BLINK_EN , mask ) ;
2007-10-23 15:14:42 -04:00
if ( value )
2008-03-27 14:51:41 -04:00
orion5x_setbits ( GPIO_OUT , mask ) ;
2007-10-23 15:14:42 -04:00
else
2008-03-27 14:51:41 -04:00
orion5x_clrbits ( GPIO_OUT , mask ) ;
2007-10-23 15:14:42 -04:00
spin_unlock_irqrestore ( & gpio_lock , flags ) ;
}
EXPORT_SYMBOL ( gpio_set_value ) ;
2008-03-27 14:51:41 -04:00
void orion5x_gpio_set_blink ( unsigned pin , int blink )
2007-11-29 15:19:56 +01:00
{
unsigned long flags ;
int mask = 1 < < pin ;
spin_lock_irqsave ( & gpio_lock , flags ) ;
2008-03-27 14:51:41 -04:00
orion5x_clrbits ( GPIO_OUT , mask ) ;
2007-11-29 15:19:56 +01:00
if ( blink )
2008-03-27 14:51:41 -04:00
orion5x_setbits ( GPIO_BLINK_EN , mask ) ;
2007-11-29 15:19:56 +01:00
else
2008-03-27 14:51:41 -04:00
orion5x_clrbits ( GPIO_BLINK_EN , mask ) ;
2007-11-29 15:19:56 +01:00
spin_unlock_irqrestore ( & gpio_lock , flags ) ;
}
2008-03-27 14:51:41 -04:00
EXPORT_SYMBOL ( orion5x_gpio_set_blink ) ;
2007-11-29 15:19:56 +01:00
2007-10-23 15:14:42 -04:00
int gpio_request ( unsigned pin , const char * label )
{
int ret = 0 ;
unsigned long flags ;
if ( pin > = GPIO_MAX | | ! test_bit ( pin , gpio_valid ) ) {
2008-03-04 15:08:02 -08:00
pr_debug ( " %s: invalid GPIO %d \n " , __func__ , pin ) ;
2007-10-23 15:14:42 -04:00
return - EINVAL ;
}
spin_lock_irqsave ( & gpio_lock , flags ) ;
if ( gpio_label [ pin ] ) {
pr_debug ( " %s: GPIO %d already used as %s \n " ,
2008-03-04 15:08:02 -08:00
__func__ , pin , gpio_label [ pin ] ) ;
2007-10-23 15:14:42 -04:00
ret = - EBUSY ;
} else
gpio_label [ pin ] = label ? label : " ? " ;
spin_unlock_irqrestore ( & gpio_lock , flags ) ;
return ret ;
}
EXPORT_SYMBOL ( gpio_request ) ;
void gpio_free ( unsigned pin )
{
if ( pin > = GPIO_MAX | | ! test_bit ( pin , gpio_valid ) ) {
2008-03-04 15:08:02 -08:00
pr_debug ( " %s: invalid GPIO %d \n " , __func__ , pin ) ;
2007-10-23 15:14:42 -04:00
return ;
}
if ( ! gpio_label [ pin ] )
2008-03-04 15:08:02 -08:00
pr_warning ( " %s: GPIO %d already freed \n " , __func__ , pin ) ;
2007-10-23 15:14:42 -04:00
else
gpio_label [ pin ] = NULL ;
}
EXPORT_SYMBOL ( gpio_free ) ;
/* Debug helper */
void gpio_display ( void )
{
int i ;
for ( i = 0 ; i < GPIO_MAX ; i + + ) {
printk ( KERN_DEBUG " Pin-%d: " , i ) ;
if ( ! test_bit ( i , gpio_valid ) ) {
printk ( " non-GPIO \n " ) ;
} else if ( ! gpio_label [ i ] ) {
printk ( " GPIO, free \n " ) ;
} else {
printk ( " GPIO, used by %s, " , gpio_label [ i ] ) ;
2008-05-28 16:43:48 +02:00
if ( readl ( GPIO_IO_CONF ) & ( 1 < < i ) ) {
2007-10-23 15:14:42 -04:00
printk ( " input, active %s, level %s, edge %s \n " ,
2008-05-28 16:43:48 +02:00
( ( readl ( GPIO_IN_POL ) > > i ) & 1 ) ? " low " : " high " ,
( ( readl ( GPIO_LEVEL_MASK ) > > i ) & 1 ) ? " enabled " : " masked " ,
( ( readl ( GPIO_EDGE_MASK ) > > i ) & 1 ) ? " enabled " : " masked " ) ;
2007-10-23 15:14:42 -04:00
} else {
2008-05-28 16:43:48 +02:00
printk ( " output, val=%d \n " , ( readl ( GPIO_OUT ) > > i ) & 1 ) ;
2007-10-23 15:14:42 -04:00
}
}
}
printk ( KERN_DEBUG " MPP_0_7_CTRL (0x%08x) = 0x%08x \n " ,
2008-05-28 16:43:48 +02:00
MPP_0_7_CTRL , readl ( MPP_0_7_CTRL ) ) ;
2007-10-23 15:14:42 -04:00
printk ( KERN_DEBUG " MPP_8_15_CTRL (0x%08x) = 0x%08x \n " ,
2008-05-28 16:43:48 +02:00
MPP_8_15_CTRL , readl ( MPP_8_15_CTRL ) ) ;
2007-10-23 15:14:42 -04:00
printk ( KERN_DEBUG " MPP_16_19_CTRL (0x%08x) = 0x%08x \n " ,
2008-05-28 16:43:48 +02:00
MPP_16_19_CTRL , readl ( MPP_16_19_CTRL ) ) ;
2007-10-23 15:14:42 -04:00
printk ( KERN_DEBUG " MPP_DEV_CTRL (0x%08x) = 0x%08x \n " ,
2008-05-28 16:43:48 +02:00
MPP_DEV_CTRL , readl ( MPP_DEV_CTRL ) ) ;
2007-10-23 15:14:42 -04:00
printk ( KERN_DEBUG " GPIO_OUT (0x%08x) = 0x%08x \n " ,
2008-05-28 16:43:48 +02:00
GPIO_OUT , readl ( GPIO_OUT ) ) ;
2007-10-23 15:14:42 -04:00
printk ( KERN_DEBUG " GPIO_IO_CONF (0x%08x) = 0x%08x \n " ,
2008-05-28 16:43:48 +02:00
GPIO_IO_CONF , readl ( GPIO_IO_CONF ) ) ;
2007-10-23 15:14:42 -04:00
printk ( KERN_DEBUG " GPIO_BLINK_EN (0x%08x) = 0x%08x \n " ,
2008-05-28 16:43:48 +02:00
GPIO_BLINK_EN , readl ( GPIO_BLINK_EN ) ) ;
2007-10-23 15:14:42 -04:00
printk ( KERN_DEBUG " GPIO_IN_POL (0x%08x) = 0x%08x \n " ,
2008-05-28 16:43:48 +02:00
GPIO_IN_POL , readl ( GPIO_IN_POL ) ) ;
2007-10-23 15:14:42 -04:00
printk ( KERN_DEBUG " GPIO_DATA_IN (0x%08x) = 0x%08x \n " ,
2008-05-28 16:43:48 +02:00
GPIO_DATA_IN , readl ( GPIO_DATA_IN ) ) ;
2007-10-23 15:14:42 -04:00
printk ( KERN_DEBUG " GPIO_LEVEL_MASK (0x%08x) = 0x%08x \n " ,
2008-05-28 16:43:48 +02:00
GPIO_LEVEL_MASK , readl ( GPIO_LEVEL_MASK ) ) ;
2007-10-23 15:14:42 -04:00
printk ( KERN_DEBUG " GPIO_EDGE_CAUSE (0x%08x) = 0x%08x \n " ,
2008-05-28 16:43:48 +02:00
GPIO_EDGE_CAUSE , readl ( GPIO_EDGE_CAUSE ) ) ;
2007-10-23 15:14:42 -04:00
printk ( KERN_DEBUG " GPIO_EDGE_MASK (0x%08x) = 0x%08x \n " ,
2008-05-28 16:43:48 +02:00
GPIO_EDGE_MASK , readl ( GPIO_EDGE_MASK ) ) ;
2007-10-23 15:14:42 -04:00
}