2006-05-16 11:54:37 +01:00
/*
* arch / arm / mach - pnx4008 / gpio . c
*
* PNX4008 GPIO driver
*
* Author : Dmitry Chigirev < source @ mvista . com >
*
* Based on reference code by Iwo Mergler and Z . Tabaaloute from Philips :
* Copyright ( c ) 2005 Koninklijke Philips Electronics N . V .
*
* 2005 ( c ) MontaVista Software , Inc . This file is licensed under
* the terms of the GNU General Public License version 2. This program
* is licensed " as is " without any warranty of any kind , whether express
* or implied .
*/
# include <linux/types.h>
# include <linux/kernel.h>
# include <linux/module.h>
2008-09-06 12:10:45 +01:00
# include <linux/io.h>
2009-01-08 11:00:03 +00:00
# include <mach/hardware.h>
2008-08-05 16:14:15 +01:00
# include <mach/platform.h>
# include <mach/gpio.h>
2006-05-16 11:54:37 +01:00
/* register definitions */
# define PIO_VA_BASE IO_ADDRESS(PNX4008_PIO_BASE)
# define PIO_INP_STATE (0x00U)
# define PIO_OUTP_SET (0x04U)
# define PIO_OUTP_CLR (0x08U)
# define PIO_OUTP_STATE (0x0CU)
# define PIO_DRV_SET (0x10U)
# define PIO_DRV_CLR (0x14U)
# define PIO_DRV_STATE (0x18U)
# define PIO_SDINP_STATE (0x1CU)
# define PIO_SDOUTP_SET (0x20U)
# define PIO_SDOUTP_CLR (0x24U)
# define PIO_MUX_SET (0x28U)
# define PIO_MUX_CLR (0x2CU)
# define PIO_MUX_STATE (0x30U)
static inline void gpio_lock ( void )
{
local_irq_disable ( ) ;
}
static inline void gpio_unlock ( void )
{
local_irq_enable ( ) ;
}
/* Inline functions */
static inline int gpio_read_bit ( u32 reg , int gpio )
{
u32 bit , val ;
int ret = - EFAULT ;
if ( gpio < 0 )
goto out ;
bit = GPIO_BIT ( gpio ) ;
if ( bit ) {
val = __raw_readl ( PIO_VA_BASE + reg ) ;
ret = ( val & bit ) ? 1 : 0 ;
}
out :
return ret ;
}
static inline int gpio_set_bit ( u32 reg , int gpio )
{
u32 bit , val ;
int ret = - EFAULT ;
if ( gpio < 0 )
goto out ;
bit = GPIO_BIT ( gpio ) ;
if ( bit ) {
val = __raw_readl ( PIO_VA_BASE + reg ) ;
val | = bit ;
__raw_writel ( val , PIO_VA_BASE + reg ) ;
ret = 0 ;
}
out :
return ret ;
}
/* Very simple access control, bitmap for allocated/free */
static unsigned long access_map [ 4 ] ;
# define INP_INDEX 0
# define OUTP_INDEX 1
# define GPIO_INDEX 2
# define MUX_INDEX 3
/*GPIO to Input Mapping */
static short gpio_to_inp_map [ 32 ] = {
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , 10 , 11 , 12 , 13 , 14 , 24 , - 1
} ;
/*GPIO to Mux Mapping */
static short gpio_to_mux_map [ 32 ] = {
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , 0 , 1 , 4 , 5 , - 1
} ;
/*Output to Mux Mapping */
static short outp_to_mux_map [ 32 ] = {
- 1 , - 1 , - 1 , 6 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , 2 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1
} ;
int pnx4008_gpio_register_pin ( unsigned short pin )
{
unsigned long bit = GPIO_BIT ( pin ) ;
int ret = - EBUSY ; /* Already in use */
gpio_lock ( ) ;
if ( GPIO_ISBID ( pin ) ) {
if ( access_map [ GPIO_INDEX ] & bit )
goto out ;
access_map [ GPIO_INDEX ] | = bit ;
} else if ( GPIO_ISRAM ( pin ) ) {
if ( access_map [ GPIO_INDEX ] & bit )
goto out ;
access_map [ GPIO_INDEX ] | = bit ;
} else if ( GPIO_ISMUX ( pin ) ) {
if ( access_map [ MUX_INDEX ] & bit )
goto out ;
access_map [ MUX_INDEX ] | = bit ;
} else if ( GPIO_ISOUT ( pin ) ) {
if ( access_map [ OUTP_INDEX ] & bit )
goto out ;
access_map [ OUTP_INDEX ] | = bit ;
} else if ( GPIO_ISIN ( pin ) ) {
if ( access_map [ INP_INDEX ] & bit )
goto out ;
access_map [ INP_INDEX ] | = bit ;
} else
goto out ;
ret = 0 ;
out :
gpio_unlock ( ) ;
return ret ;
}
EXPORT_SYMBOL ( pnx4008_gpio_register_pin ) ;
int pnx4008_gpio_unregister_pin ( unsigned short pin )
{
unsigned long bit = GPIO_BIT ( pin ) ;
int ret = - EFAULT ; /* Not registered */
gpio_lock ( ) ;
if ( GPIO_ISBID ( pin ) ) {
if ( ~ access_map [ GPIO_INDEX ] & bit )
goto out ;
access_map [ GPIO_INDEX ] & = ~ bit ;
} else if ( GPIO_ISRAM ( pin ) ) {
if ( ~ access_map [ GPIO_INDEX ] & bit )
goto out ;
access_map [ GPIO_INDEX ] & = ~ bit ;
} else if ( GPIO_ISMUX ( pin ) ) {
if ( ~ access_map [ MUX_INDEX ] & bit )
goto out ;
access_map [ MUX_INDEX ] & = ~ bit ;
} else if ( GPIO_ISOUT ( pin ) ) {
if ( ~ access_map [ OUTP_INDEX ] & bit )
goto out ;
access_map [ OUTP_INDEX ] & = ~ bit ;
} else if ( GPIO_ISIN ( pin ) ) {
if ( ~ access_map [ INP_INDEX ] & bit )
goto out ;
access_map [ INP_INDEX ] & = ~ bit ;
} else
goto out ;
ret = 0 ;
out :
gpio_unlock ( ) ;
return ret ;
}
EXPORT_SYMBOL ( pnx4008_gpio_unregister_pin ) ;
unsigned long pnx4008_gpio_read_pin ( unsigned short pin )
{
unsigned long ret = - EFAULT ;
int gpio = GPIO_BIT_MASK ( pin ) ;
gpio_lock ( ) ;
if ( GPIO_ISOUT ( pin ) ) {
ret = gpio_read_bit ( PIO_OUTP_STATE , gpio ) ;
} else if ( GPIO_ISRAM ( pin ) ) {
if ( gpio_read_bit ( PIO_DRV_STATE , gpio ) = = 0 ) {
ret = gpio_read_bit ( PIO_SDINP_STATE , gpio ) ;
}
} else if ( GPIO_ISBID ( pin ) ) {
ret = gpio_read_bit ( PIO_DRV_STATE , gpio ) ;
if ( ret > 0 )
ret = gpio_read_bit ( PIO_OUTP_STATE , gpio ) ;
else if ( ret = = 0 )
ret =
gpio_read_bit ( PIO_INP_STATE , gpio_to_inp_map [ gpio ] ) ;
} else if ( GPIO_ISIN ( pin ) ) {
ret = gpio_read_bit ( PIO_INP_STATE , gpio ) ;
}
gpio_unlock ( ) ;
return ret ;
}
EXPORT_SYMBOL ( pnx4008_gpio_read_pin ) ;
/* Write Value to output */
int pnx4008_gpio_write_pin ( unsigned short pin , int output )
{
int gpio = GPIO_BIT_MASK ( pin ) ;
int ret = - EFAULT ;
gpio_lock ( ) ;
if ( GPIO_ISOUT ( pin ) ) {
printk ( " writing '%x' to '%x' \n " ,
gpio , output ? PIO_OUTP_SET : PIO_OUTP_CLR ) ;
ret = gpio_set_bit ( output ? PIO_OUTP_SET : PIO_OUTP_CLR , gpio ) ;
} else if ( GPIO_ISRAM ( pin ) ) {
if ( gpio_read_bit ( PIO_DRV_STATE , gpio ) > 0 )
ret = gpio_set_bit ( output ? PIO_SDOUTP_SET :
PIO_SDOUTP_CLR , gpio ) ;
} else if ( GPIO_ISBID ( pin ) ) {
if ( gpio_read_bit ( PIO_DRV_STATE , gpio ) > 0 )
ret = gpio_set_bit ( output ? PIO_OUTP_SET :
PIO_OUTP_CLR , gpio ) ;
}
gpio_unlock ( ) ;
return ret ;
}
EXPORT_SYMBOL ( pnx4008_gpio_write_pin ) ;
/* Value = 1 : Set GPIO pin as output */
/* Value = 0 : Set GPIO pin as input */
int pnx4008_gpio_set_pin_direction ( unsigned short pin , int output )
{
int gpio = GPIO_BIT_MASK ( pin ) ;
int ret = - EFAULT ;
gpio_lock ( ) ;
if ( GPIO_ISBID ( pin ) | | GPIO_ISRAM ( pin ) ) {
ret = gpio_set_bit ( output ? PIO_DRV_SET : PIO_DRV_CLR , gpio ) ;
}
gpio_unlock ( ) ;
return ret ;
}
EXPORT_SYMBOL ( pnx4008_gpio_set_pin_direction ) ;
/* Read GPIO pin direction: 0= pin used as input, 1= pin used as output*/
int pnx4008_gpio_read_pin_direction ( unsigned short pin )
{
int gpio = GPIO_BIT_MASK ( pin ) ;
int ret = - EFAULT ;
gpio_lock ( ) ;
if ( GPIO_ISBID ( pin ) | | GPIO_ISRAM ( pin ) ) {
ret = gpio_read_bit ( PIO_DRV_STATE , gpio ) ;
}
gpio_unlock ( ) ;
return ret ;
}
EXPORT_SYMBOL ( pnx4008_gpio_read_pin_direction ) ;
/* Value = 1 : Set pin to muxed function */
/* Value = 0 : Set pin as GPIO */
int pnx4008_gpio_set_pin_mux ( unsigned short pin , int output )
{
int gpio = GPIO_BIT_MASK ( pin ) ;
int ret = - EFAULT ;
gpio_lock ( ) ;
if ( GPIO_ISBID ( pin ) ) {
ret =
gpio_set_bit ( output ? PIO_MUX_SET : PIO_MUX_CLR ,
gpio_to_mux_map [ gpio ] ) ;
} else if ( GPIO_ISOUT ( pin ) ) {
ret =
gpio_set_bit ( output ? PIO_MUX_SET : PIO_MUX_CLR ,
outp_to_mux_map [ gpio ] ) ;
} else if ( GPIO_ISMUX ( pin ) ) {
ret = gpio_set_bit ( output ? PIO_MUX_SET : PIO_MUX_CLR , gpio ) ;
}
gpio_unlock ( ) ;
return ret ;
}
EXPORT_SYMBOL ( pnx4008_gpio_set_pin_mux ) ;
/* Read pin mux function: 0= pin used as GPIO, 1= pin used for muxed function*/
int pnx4008_gpio_read_pin_mux ( unsigned short pin )
{
int gpio = GPIO_BIT_MASK ( pin ) ;
int ret = - EFAULT ;
gpio_lock ( ) ;
if ( GPIO_ISBID ( pin ) ) {
ret = gpio_read_bit ( PIO_MUX_STATE , gpio_to_mux_map [ gpio ] ) ;
} else if ( GPIO_ISOUT ( pin ) ) {
ret = gpio_read_bit ( PIO_MUX_STATE , outp_to_mux_map [ gpio ] ) ;
} else if ( GPIO_ISMUX ( pin ) ) {
ret = gpio_read_bit ( PIO_MUX_STATE , gpio ) ;
}
gpio_unlock ( ) ;
return ret ;
}
EXPORT_SYMBOL ( pnx4008_gpio_read_pin_mux ) ;