329 lines
7.3 KiB
C
329 lines
7.3 KiB
C
/*
|
|
* 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>
|
|
#include <linux/io.h>
|
|
#include <mach/platform.h>
|
|
#include <mach/gpio.h>
|
|
|
|
/* 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);
|