| /* |
| * 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 <asm/io.h> |
| #include <asm/arch/platform.h> |
| #include <asm/arch/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); |