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