1/* 2 * arch/arm/mach-pnx4008/gpio.c 3 * 4 * PNX4008 GPIO driver 5 * 6 * Author: Dmitry Chigirev <source@mvista.com> 7 * 8 * Based on reference code by Iwo Mergler and Z.Tabaaloute from Philips: 9 * Copyright (c) 2005 Koninklijke Philips Electronics N.V. 10 * 11 * 2005 (c) MontaVista Software, Inc. This file is licensed under 12 * the terms of the GNU General Public License version 2. This program 13 * is licensed "as is" without any warranty of any kind, whether express 14 * or implied. 15 */ 16 17#include <linux/types.h> 18#include <linux/kernel.h> 19#include <linux/module.h> 20#include <linux/io.h> 21#include <mach/hardware.h> 22#include <mach/platform.h> 23#include <mach/gpio.h> 24 25/* register definitions */ 26#define PIO_VA_BASE IO_ADDRESS(PNX4008_PIO_BASE) 27 28#define PIO_INP_STATE (0x00U) 29#define PIO_OUTP_SET (0x04U) 30#define PIO_OUTP_CLR (0x08U) 31#define PIO_OUTP_STATE (0x0CU) 32#define PIO_DRV_SET (0x10U) 33#define PIO_DRV_CLR (0x14U) 34#define PIO_DRV_STATE (0x18U) 35#define PIO_SDINP_STATE (0x1CU) 36#define PIO_SDOUTP_SET (0x20U) 37#define PIO_SDOUTP_CLR (0x24U) 38#define PIO_MUX_SET (0x28U) 39#define PIO_MUX_CLR (0x2CU) 40#define PIO_MUX_STATE (0x30U) 41 42static inline void gpio_lock(void) 43{ 44 local_irq_disable(); 45} 46 47static inline void gpio_unlock(void) 48{ 49 local_irq_enable(); 50} 51 52/* Inline functions */ 53static inline int gpio_read_bit(u32 reg, int gpio) 54{ 55 u32 bit, val; 56 int ret = -EFAULT; 57 58 if (gpio < 0) 59 goto out; 60 61 bit = GPIO_BIT(gpio); 62 if (bit) { 63 val = __raw_readl(PIO_VA_BASE + reg); 64 ret = (val & bit) ? 1 : 0; 65 } 66out: 67 return ret; 68} 69 70static inline int gpio_set_bit(u32 reg, int gpio) 71{ 72 u32 bit, val; 73 int ret = -EFAULT; 74 75 if (gpio < 0) 76 goto out; 77 78 bit = GPIO_BIT(gpio); 79 if (bit) { 80 val = __raw_readl(PIO_VA_BASE + reg); 81 val |= bit; 82 __raw_writel(val, PIO_VA_BASE + reg); 83 ret = 0; 84 } 85out: 86 return ret; 87} 88 89/* Very simple access control, bitmap for allocated/free */ 90static unsigned long access_map[4]; 91#define INP_INDEX 0 92#define OUTP_INDEX 1 93#define GPIO_INDEX 2 94#define MUX_INDEX 3 95 96/*GPIO to Input Mapping */ 97static short gpio_to_inp_map[32] = { 98 -1, -1, -1, -1, -1, -1, -1, -1, 99 -1, -1, -1, -1, -1, -1, -1, -1, 100 -1, -1, -1, -1, -1, -1, -1, -1, 101 -1, 10, 11, 12, 13, 14, 24, -1 102}; 103 104/*GPIO to Mux Mapping */ 105static short gpio_to_mux_map[32] = { 106 -1, -1, -1, -1, -1, -1, -1, -1, 107 -1, -1, -1, -1, -1, -1, -1, -1, 108 -1, -1, -1, -1, -1, -1, -1, -1, 109 -1, -1, -1, 0, 1, 4, 5, -1 110}; 111 112/*Output to Mux Mapping */ 113static short outp_to_mux_map[32] = { 114 -1, -1, -1, 6, -1, -1, -1, -1, 115 -1, -1, -1, -1, -1, -1, -1, -1, 116 -1, -1, -1, -1, -1, 2, -1, -1, 117 -1, -1, -1, -1, -1, -1, -1, -1 118}; 119 120int pnx4008_gpio_register_pin(unsigned short pin) 121{ 122 unsigned long bit = GPIO_BIT(pin); 123 int ret = -EBUSY; /* Already in use */ 124 125 gpio_lock(); 126 127 if (GPIO_ISBID(pin)) { 128 if (access_map[GPIO_INDEX] & bit) 129 goto out; 130 access_map[GPIO_INDEX] |= bit; 131 132 } else if (GPIO_ISRAM(pin)) { 133 if (access_map[GPIO_INDEX] & bit) 134 goto out; 135 access_map[GPIO_INDEX] |= bit; 136 137 } else if (GPIO_ISMUX(pin)) { 138 if (access_map[MUX_INDEX] & bit) 139 goto out; 140 access_map[MUX_INDEX] |= bit; 141 142 } else if (GPIO_ISOUT(pin)) { 143 if (access_map[OUTP_INDEX] & bit) 144 goto out; 145 access_map[OUTP_INDEX] |= bit; 146 147 } else if (GPIO_ISIN(pin)) { 148 if (access_map[INP_INDEX] & bit) 149 goto out; 150 access_map[INP_INDEX] |= bit; 151 } else 152 goto out; 153 ret = 0; 154 155out: 156 gpio_unlock(); 157 return ret; 158} 159 160EXPORT_SYMBOL(pnx4008_gpio_register_pin); 161 162int pnx4008_gpio_unregister_pin(unsigned short pin) 163{ 164 unsigned long bit = GPIO_BIT(pin); 165 int ret = -EFAULT; /* Not registered */ 166 167 gpio_lock(); 168 169 if (GPIO_ISBID(pin)) { 170 if (~access_map[GPIO_INDEX] & bit) 171 goto out; 172 access_map[GPIO_INDEX] &= ~bit; 173 } else if (GPIO_ISRAM(pin)) { 174 if (~access_map[GPIO_INDEX] & bit) 175 goto out; 176 access_map[GPIO_INDEX] &= ~bit; 177 } else if (GPIO_ISMUX(pin)) { 178 if (~access_map[MUX_INDEX] & bit) 179 goto out; 180 access_map[MUX_INDEX] &= ~bit; 181 } else if (GPIO_ISOUT(pin)) { 182 if (~access_map[OUTP_INDEX] & bit) 183 goto out; 184 access_map[OUTP_INDEX] &= ~bit; 185 } else if (GPIO_ISIN(pin)) { 186 if (~access_map[INP_INDEX] & bit) 187 goto out; 188 access_map[INP_INDEX] &= ~bit; 189 } else 190 goto out; 191 ret = 0; 192 193out: 194 gpio_unlock(); 195 return ret; 196} 197 198EXPORT_SYMBOL(pnx4008_gpio_unregister_pin); 199 200unsigned long pnx4008_gpio_read_pin(unsigned short pin) 201{ 202 unsigned long ret = -EFAULT; 203 int gpio = GPIO_BIT_MASK(pin); 204 gpio_lock(); 205 if (GPIO_ISOUT(pin)) { 206 ret = gpio_read_bit(PIO_OUTP_STATE, gpio); 207 } else if (GPIO_ISRAM(pin)) { 208 if (gpio_read_bit(PIO_DRV_STATE, gpio) == 0) { 209 ret = gpio_read_bit(PIO_SDINP_STATE, gpio); 210 } 211 } else if (GPIO_ISBID(pin)) { 212 ret = gpio_read_bit(PIO_DRV_STATE, gpio); 213 if (ret > 0) 214 ret = gpio_read_bit(PIO_OUTP_STATE, gpio); 215 else if (ret == 0) 216 ret = 217 gpio_read_bit(PIO_INP_STATE, gpio_to_inp_map[gpio]); 218 } else if (GPIO_ISIN(pin)) { 219 ret = gpio_read_bit(PIO_INP_STATE, gpio); 220 } 221 gpio_unlock(); 222 return ret; 223} 224 225EXPORT_SYMBOL(pnx4008_gpio_read_pin); 226 227/* Write Value to output */ 228int pnx4008_gpio_write_pin(unsigned short pin, int output) 229{ 230 int gpio = GPIO_BIT_MASK(pin); 231 int ret = -EFAULT; 232 233 gpio_lock(); 234 if (GPIO_ISOUT(pin)) { 235 printk( "writing '%x' to '%x'\n", 236 gpio, output ? PIO_OUTP_SET : PIO_OUTP_CLR ); 237 ret = gpio_set_bit(output ? PIO_OUTP_SET : PIO_OUTP_CLR, gpio); 238 } else if (GPIO_ISRAM(pin)) { 239 if (gpio_read_bit(PIO_DRV_STATE, gpio) > 0) 240 ret = gpio_set_bit(output ? PIO_SDOUTP_SET : 241 PIO_SDOUTP_CLR, gpio); 242 } else if (GPIO_ISBID(pin)) { 243 if (gpio_read_bit(PIO_DRV_STATE, gpio) > 0) 244 ret = gpio_set_bit(output ? PIO_OUTP_SET : 245 PIO_OUTP_CLR, gpio); 246 } 247 gpio_unlock(); 248 return ret; 249} 250 251EXPORT_SYMBOL(pnx4008_gpio_write_pin); 252 253/* Value = 1 : Set GPIO pin as output */ 254/* Value = 0 : Set GPIO pin as input */ 255int pnx4008_gpio_set_pin_direction(unsigned short pin, int output) 256{ 257 int gpio = GPIO_BIT_MASK(pin); 258 int ret = -EFAULT; 259 260 gpio_lock(); 261 if (GPIO_ISBID(pin) || GPIO_ISRAM(pin)) { 262 ret = gpio_set_bit(output ? PIO_DRV_SET : PIO_DRV_CLR, gpio); 263 } 264 gpio_unlock(); 265 return ret; 266} 267 268EXPORT_SYMBOL(pnx4008_gpio_set_pin_direction); 269 270/* Read GPIO pin direction: 0= pin used as input, 1= pin used as output*/ 271int pnx4008_gpio_read_pin_direction(unsigned short pin) 272{ 273 int gpio = GPIO_BIT_MASK(pin); 274 int ret = -EFAULT; 275 276 gpio_lock(); 277 if (GPIO_ISBID(pin) || GPIO_ISRAM(pin)) { 278 ret = gpio_read_bit(PIO_DRV_STATE, gpio); 279 } 280 gpio_unlock(); 281 return ret; 282} 283 284EXPORT_SYMBOL(pnx4008_gpio_read_pin_direction); 285 286/* Value = 1 : Set pin to muxed function */ 287/* Value = 0 : Set pin as GPIO */ 288int pnx4008_gpio_set_pin_mux(unsigned short pin, int output) 289{ 290 int gpio = GPIO_BIT_MASK(pin); 291 int ret = -EFAULT; 292 293 gpio_lock(); 294 if (GPIO_ISBID(pin)) { 295 ret = 296 gpio_set_bit(output ? PIO_MUX_SET : PIO_MUX_CLR, 297 gpio_to_mux_map[gpio]); 298 } else if (GPIO_ISOUT(pin)) { 299 ret = 300 gpio_set_bit(output ? PIO_MUX_SET : PIO_MUX_CLR, 301 outp_to_mux_map[gpio]); 302 } else if (GPIO_ISMUX(pin)) { 303 ret = gpio_set_bit(output ? PIO_MUX_SET : PIO_MUX_CLR, gpio); 304 } 305 gpio_unlock(); 306 return ret; 307} 308 309EXPORT_SYMBOL(pnx4008_gpio_set_pin_mux); 310 311/* Read pin mux function: 0= pin used as GPIO, 1= pin used for muxed function*/ 312int pnx4008_gpio_read_pin_mux(unsigned short pin) 313{ 314 int gpio = GPIO_BIT_MASK(pin); 315 int ret = -EFAULT; 316 317 gpio_lock(); 318 if (GPIO_ISBID(pin)) { 319 ret = gpio_read_bit(PIO_MUX_STATE, gpio_to_mux_map[gpio]); 320 } else if (GPIO_ISOUT(pin)) { 321 ret = gpio_read_bit(PIO_MUX_STATE, outp_to_mux_map[gpio]); 322 } else if (GPIO_ISMUX(pin)) { 323 ret = gpio_read_bit(PIO_MUX_STATE, gpio); 324 } 325 gpio_unlock(); 326 return ret; 327} 328 329EXPORT_SYMBOL(pnx4008_gpio_read_pin_mux); 330