diff options
Diffstat (limited to 'drivers/gpio')
| -rw-r--r-- | drivers/gpio/gpio-exynos4.c | 385 | ||||
| -rw-r--r-- | drivers/gpio/gpio-nomadik.c | 1087 | ||||
| -rw-r--r-- | drivers/gpio/gpio-plat-samsung.c | 205 | ||||
| -rw-r--r-- | drivers/gpio/gpio-s5pc100.c | 354 | ||||
| -rw-r--r-- | drivers/gpio/gpio-s5pv210.c | 287 | ||||
| -rw-r--r-- | drivers/gpio/gpio-u300.c | 697 |
6 files changed, 3015 insertions, 0 deletions
diff --git a/drivers/gpio/gpio-exynos4.c b/drivers/gpio/gpio-exynos4.c new file mode 100644 index 00000000000..d24b337cf1a --- /dev/null +++ b/drivers/gpio/gpio-exynos4.c | |||
| @@ -0,0 +1,385 @@ | |||
| 1 | /* | ||
| 2 | * EXYNOS4 - GPIOlib support | ||
| 3 | * | ||
| 4 | * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. | ||
| 5 | * http://www.samsung.com | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/kernel.h> | ||
| 13 | #include <linux/irq.h> | ||
| 14 | #include <linux/io.h> | ||
| 15 | #include <linux/gpio.h> | ||
| 16 | |||
| 17 | #include <mach/map.h> | ||
| 18 | |||
| 19 | #include <plat/gpio-core.h> | ||
| 20 | #include <plat/gpio-cfg.h> | ||
| 21 | #include <plat/gpio-cfg-helpers.h> | ||
| 22 | |||
| 23 | int s3c_gpio_setpull_exynos4(struct s3c_gpio_chip *chip, | ||
| 24 | unsigned int off, s3c_gpio_pull_t pull) | ||
| 25 | { | ||
| 26 | if (pull == S3C_GPIO_PULL_UP) | ||
| 27 | pull = 3; | ||
| 28 | |||
| 29 | return s3c_gpio_setpull_updown(chip, off, pull); | ||
| 30 | } | ||
| 31 | |||
| 32 | s3c_gpio_pull_t s3c_gpio_getpull_exynos4(struct s3c_gpio_chip *chip, | ||
| 33 | unsigned int off) | ||
| 34 | { | ||
| 35 | s3c_gpio_pull_t pull; | ||
| 36 | |||
| 37 | pull = s3c_gpio_getpull_updown(chip, off); | ||
| 38 | if (pull == 3) | ||
| 39 | pull = S3C_GPIO_PULL_UP; | ||
| 40 | |||
| 41 | return pull; | ||
| 42 | } | ||
| 43 | |||
| 44 | static struct s3c_gpio_cfg gpio_cfg = { | ||
| 45 | .set_config = s3c_gpio_setcfg_s3c64xx_4bit, | ||
| 46 | .set_pull = s3c_gpio_setpull_exynos4, | ||
| 47 | .get_pull = s3c_gpio_getpull_exynos4, | ||
| 48 | }; | ||
| 49 | |||
| 50 | static struct s3c_gpio_cfg gpio_cfg_noint = { | ||
| 51 | .set_config = s3c_gpio_setcfg_s3c64xx_4bit, | ||
| 52 | .set_pull = s3c_gpio_setpull_exynos4, | ||
| 53 | .get_pull = s3c_gpio_getpull_exynos4, | ||
| 54 | }; | ||
| 55 | |||
| 56 | /* | ||
| 57 | * Following are the gpio banks in v310. | ||
| 58 | * | ||
| 59 | * The 'config' member when left to NULL, is initialized to the default | ||
| 60 | * structure gpio_cfg in the init function below. | ||
| 61 | * | ||
| 62 | * The 'base' member is also initialized in the init function below. | ||
| 63 | * Note: The initialization of 'base' member of s3c_gpio_chip structure | ||
| 64 | * uses the above macro and depends on the banks being listed in order here. | ||
| 65 | */ | ||
| 66 | static struct s3c_gpio_chip exynos4_gpio_part1_4bit[] = { | ||
| 67 | { | ||
| 68 | .chip = { | ||
| 69 | .base = EXYNOS4_GPA0(0), | ||
| 70 | .ngpio = EXYNOS4_GPIO_A0_NR, | ||
| 71 | .label = "GPA0", | ||
| 72 | }, | ||
| 73 | }, { | ||
| 74 | .chip = { | ||
| 75 | .base = EXYNOS4_GPA1(0), | ||
| 76 | .ngpio = EXYNOS4_GPIO_A1_NR, | ||
| 77 | .label = "GPA1", | ||
| 78 | }, | ||
| 79 | }, { | ||
| 80 | .chip = { | ||
| 81 | .base = EXYNOS4_GPB(0), | ||
| 82 | .ngpio = EXYNOS4_GPIO_B_NR, | ||
| 83 | .label = "GPB", | ||
| 84 | }, | ||
| 85 | }, { | ||
| 86 | .chip = { | ||
| 87 | .base = EXYNOS4_GPC0(0), | ||
| 88 | .ngpio = EXYNOS4_GPIO_C0_NR, | ||
| 89 | .label = "GPC0", | ||
| 90 | }, | ||
| 91 | }, { | ||
| 92 | .chip = { | ||
| 93 | .base = EXYNOS4_GPC1(0), | ||
| 94 | .ngpio = EXYNOS4_GPIO_C1_NR, | ||
| 95 | .label = "GPC1", | ||
| 96 | }, | ||
| 97 | }, { | ||
| 98 | .chip = { | ||
| 99 | .base = EXYNOS4_GPD0(0), | ||
| 100 | .ngpio = EXYNOS4_GPIO_D0_NR, | ||
| 101 | .label = "GPD0", | ||
| 102 | }, | ||
| 103 | }, { | ||
| 104 | .chip = { | ||
| 105 | .base = EXYNOS4_GPD1(0), | ||
| 106 | .ngpio = EXYNOS4_GPIO_D1_NR, | ||
| 107 | .label = "GPD1", | ||
| 108 | }, | ||
| 109 | }, { | ||
| 110 | .chip = { | ||
| 111 | .base = EXYNOS4_GPE0(0), | ||
| 112 | .ngpio = EXYNOS4_GPIO_E0_NR, | ||
| 113 | .label = "GPE0", | ||
| 114 | }, | ||
| 115 | }, { | ||
| 116 | .chip = { | ||
| 117 | .base = EXYNOS4_GPE1(0), | ||
| 118 | .ngpio = EXYNOS4_GPIO_E1_NR, | ||
| 119 | .label = "GPE1", | ||
| 120 | }, | ||
| 121 | }, { | ||
| 122 | .chip = { | ||
| 123 | .base = EXYNOS4_GPE2(0), | ||
| 124 | .ngpio = EXYNOS4_GPIO_E2_NR, | ||
| 125 | .label = "GPE2", | ||
| 126 | }, | ||
| 127 | }, { | ||
| 128 | .chip = { | ||
| 129 | .base = EXYNOS4_GPE3(0), | ||
| 130 | .ngpio = EXYNOS4_GPIO_E3_NR, | ||
| 131 | .label = "GPE3", | ||
| 132 | }, | ||
| 133 | }, { | ||
| 134 | .chip = { | ||
| 135 | .base = EXYNOS4_GPE4(0), | ||
| 136 | .ngpio = EXYNOS4_GPIO_E4_NR, | ||
| 137 | .label = "GPE4", | ||
| 138 | }, | ||
| 139 | }, { | ||
| 140 | .chip = { | ||
| 141 | .base = EXYNOS4_GPF0(0), | ||
| 142 | .ngpio = EXYNOS4_GPIO_F0_NR, | ||
| 143 | .label = "GPF0", | ||
| 144 | }, | ||
| 145 | }, { | ||
| 146 | .chip = { | ||
| 147 | .base = EXYNOS4_GPF1(0), | ||
| 148 | .ngpio = EXYNOS4_GPIO_F1_NR, | ||
| 149 | .label = "GPF1", | ||
| 150 | }, | ||
| 151 | }, { | ||
| 152 | .chip = { | ||
| 153 | .base = EXYNOS4_GPF2(0), | ||
| 154 | .ngpio = EXYNOS4_GPIO_F2_NR, | ||
| 155 | .label = "GPF2", | ||
| 156 | }, | ||
| 157 | }, { | ||
| 158 | .chip = { | ||
| 159 | .base = EXYNOS4_GPF3(0), | ||
| 160 | .ngpio = EXYNOS4_GPIO_F3_NR, | ||
| 161 | .label = "GPF3", | ||
| 162 | }, | ||
| 163 | }, | ||
| 164 | }; | ||
| 165 | |||
| 166 | static struct s3c_gpio_chip exynos4_gpio_part2_4bit[] = { | ||
| 167 | { | ||
| 168 | .chip = { | ||
| 169 | .base = EXYNOS4_GPJ0(0), | ||
| 170 | .ngpio = EXYNOS4_GPIO_J0_NR, | ||
| 171 | .label = "GPJ0", | ||
| 172 | }, | ||
| 173 | }, { | ||
| 174 | .chip = { | ||
| 175 | .base = EXYNOS4_GPJ1(0), | ||
| 176 | .ngpio = EXYNOS4_GPIO_J1_NR, | ||
| 177 | .label = "GPJ1", | ||
| 178 | }, | ||
| 179 | }, { | ||
| 180 | .chip = { | ||
| 181 | .base = EXYNOS4_GPK0(0), | ||
| 182 | .ngpio = EXYNOS4_GPIO_K0_NR, | ||
| 183 | .label = "GPK0", | ||
| 184 | }, | ||
| 185 | }, { | ||
| 186 | .chip = { | ||
| 187 | .base = EXYNOS4_GPK1(0), | ||
| 188 | .ngpio = EXYNOS4_GPIO_K1_NR, | ||
| 189 | .label = "GPK1", | ||
| 190 | }, | ||
| 191 | }, { | ||
| 192 | .chip = { | ||
| 193 | .base = EXYNOS4_GPK2(0), | ||
| 194 | .ngpio = EXYNOS4_GPIO_K2_NR, | ||
| 195 | .label = "GPK2", | ||
| 196 | }, | ||
| 197 | }, { | ||
| 198 | .chip = { | ||
| 199 | .base = EXYNOS4_GPK3(0), | ||
| 200 | .ngpio = EXYNOS4_GPIO_K3_NR, | ||
| 201 | .label = "GPK3", | ||
| 202 | }, | ||
| 203 | }, { | ||
| 204 | .chip = { | ||
| 205 | .base = EXYNOS4_GPL0(0), | ||
| 206 | .ngpio = EXYNOS4_GPIO_L0_NR, | ||
| 207 | .label = "GPL0", | ||
| 208 | }, | ||
| 209 | }, { | ||
| 210 | .chip = { | ||
| 211 | .base = EXYNOS4_GPL1(0), | ||
| 212 | .ngpio = EXYNOS4_GPIO_L1_NR, | ||
| 213 | .label = "GPL1", | ||
| 214 | }, | ||
| 215 | }, { | ||
| 216 | .chip = { | ||
| 217 | .base = EXYNOS4_GPL2(0), | ||
| 218 | .ngpio = EXYNOS4_GPIO_L2_NR, | ||
| 219 | .label = "GPL2", | ||
| 220 | }, | ||
| 221 | }, { | ||
| 222 | .config = &gpio_cfg_noint, | ||
| 223 | .chip = { | ||
| 224 | .base = EXYNOS4_GPY0(0), | ||
| 225 | .ngpio = EXYNOS4_GPIO_Y0_NR, | ||
| 226 | .label = "GPY0", | ||
| 227 | }, | ||
| 228 | }, { | ||
| 229 | .config = &gpio_cfg_noint, | ||
| 230 | .chip = { | ||
| 231 | .base = EXYNOS4_GPY1(0), | ||
| 232 | .ngpio = EXYNOS4_GPIO_Y1_NR, | ||
| 233 | .label = "GPY1", | ||
| 234 | }, | ||
| 235 | }, { | ||
| 236 | .config = &gpio_cfg_noint, | ||
| 237 | .chip = { | ||
| 238 | .base = EXYNOS4_GPY2(0), | ||
| 239 | .ngpio = EXYNOS4_GPIO_Y2_NR, | ||
| 240 | .label = "GPY2", | ||
| 241 | }, | ||
| 242 | }, { | ||
| 243 | .config = &gpio_cfg_noint, | ||
| 244 | .chip = { | ||
| 245 | .base = EXYNOS4_GPY3(0), | ||
| 246 | .ngpio = EXYNOS4_GPIO_Y3_NR, | ||
| 247 | .label = "GPY3", | ||
| 248 | }, | ||
| 249 | }, { | ||
| 250 | .config = &gpio_cfg_noint, | ||
| 251 | .chip = { | ||
| 252 | .base = EXYNOS4_GPY4(0), | ||
| 253 | .ngpio = EXYNOS4_GPIO_Y4_NR, | ||
| 254 | .label = "GPY4", | ||
| 255 | }, | ||
| 256 | }, { | ||
| 257 | .config = &gpio_cfg_noint, | ||
| 258 | .chip = { | ||
| 259 | .base = EXYNOS4_GPY5(0), | ||
| 260 | .ngpio = EXYNOS4_GPIO_Y5_NR, | ||
| 261 | .label = "GPY5", | ||
| 262 | }, | ||
| 263 | }, { | ||
| 264 | .config = &gpio_cfg_noint, | ||
| 265 | .chip = { | ||
| 266 | .base = EXYNOS4_GPY6(0), | ||
| 267 | .ngpio = EXYNOS4_GPIO_Y6_NR, | ||
| 268 | .label = "GPY6", | ||
| 269 | }, | ||
| 270 | }, { | ||
| 271 | .base = (S5P_VA_GPIO2 + 0xC00), | ||
| 272 | .config = &gpio_cfg_noint, | ||
| 273 | .irq_base = IRQ_EINT(0), | ||
| 274 | .chip = { | ||
| 275 | .base = EXYNOS4_GPX0(0), | ||
| 276 | .ngpio = EXYNOS4_GPIO_X0_NR, | ||
| 277 | .label = "GPX0", | ||
| 278 | .to_irq = samsung_gpiolib_to_irq, | ||
| 279 | }, | ||
| 280 | }, { | ||
| 281 | .base = (S5P_VA_GPIO2 + 0xC20), | ||
| 282 | .config = &gpio_cfg_noint, | ||
| 283 | .irq_base = IRQ_EINT(8), | ||
| 284 | .chip = { | ||
| 285 | .base = EXYNOS4_GPX1(0), | ||
| 286 | .ngpio = EXYNOS4_GPIO_X1_NR, | ||
| 287 | .label = "GPX1", | ||
| 288 | .to_irq = samsung_gpiolib_to_irq, | ||
| 289 | }, | ||
| 290 | }, { | ||
| 291 | .base = (S5P_VA_GPIO2 + 0xC40), | ||
| 292 | .config = &gpio_cfg_noint, | ||
| 293 | .irq_base = IRQ_EINT(16), | ||
| 294 | .chip = { | ||
| 295 | .base = EXYNOS4_GPX2(0), | ||
| 296 | .ngpio = EXYNOS4_GPIO_X2_NR, | ||
| 297 | .label = "GPX2", | ||
| 298 | .to_irq = samsung_gpiolib_to_irq, | ||
| 299 | }, | ||
| 300 | }, { | ||
| 301 | .base = (S5P_VA_GPIO2 + 0xC60), | ||
| 302 | .config = &gpio_cfg_noint, | ||
| 303 | .irq_base = IRQ_EINT(24), | ||
| 304 | .chip = { | ||
| 305 | .base = EXYNOS4_GPX3(0), | ||
| 306 | .ngpio = EXYNOS4_GPIO_X3_NR, | ||
| 307 | .label = "GPX3", | ||
| 308 | .to_irq = samsung_gpiolib_to_irq, | ||
| 309 | }, | ||
| 310 | }, | ||
| 311 | }; | ||
| 312 | |||
| 313 | static struct s3c_gpio_chip exynos4_gpio_part3_4bit[] = { | ||
| 314 | { | ||
| 315 | .chip = { | ||
| 316 | .base = EXYNOS4_GPZ(0), | ||
| 317 | .ngpio = EXYNOS4_GPIO_Z_NR, | ||
| 318 | .label = "GPZ", | ||
| 319 | }, | ||
| 320 | }, | ||
| 321 | }; | ||
| 322 | |||
| 323 | static __init int exynos4_gpiolib_init(void) | ||
| 324 | { | ||
| 325 | struct s3c_gpio_chip *chip; | ||
| 326 | int i; | ||
| 327 | int group = 0; | ||
| 328 | int nr_chips; | ||
| 329 | |||
| 330 | /* GPIO part 1 */ | ||
| 331 | |||
| 332 | chip = exynos4_gpio_part1_4bit; | ||
| 333 | nr_chips = ARRAY_SIZE(exynos4_gpio_part1_4bit); | ||
| 334 | |||
| 335 | for (i = 0; i < nr_chips; i++, chip++) { | ||
| 336 | if (chip->config == NULL) { | ||
| 337 | chip->config = &gpio_cfg; | ||
| 338 | /* Assign the GPIO interrupt group */ | ||
| 339 | chip->group = group++; | ||
| 340 | } | ||
| 341 | if (chip->base == NULL) | ||
| 342 | chip->base = S5P_VA_GPIO1 + (i) * 0x20; | ||
| 343 | } | ||
| 344 | |||
| 345 | samsung_gpiolib_add_4bit_chips(exynos4_gpio_part1_4bit, nr_chips); | ||
| 346 | |||
| 347 | /* GPIO part 2 */ | ||
| 348 | |||
| 349 | chip = exynos4_gpio_part2_4bit; | ||
| 350 | nr_chips = ARRAY_SIZE(exynos4_gpio_part2_4bit); | ||
| 351 | |||
| 352 | for (i = 0; i < nr_chips; i++, chip++) { | ||
| 353 | if (chip->config == NULL) { | ||
| 354 | chip->config = &gpio_cfg; | ||
| 355 | /* Assign the GPIO interrupt group */ | ||
| 356 | chip->group = group++; | ||
| 357 | } | ||
| 358 | if (chip->base == NULL) | ||
| 359 | chip->base = S5P_VA_GPIO2 + (i) * 0x20; | ||
| 360 | } | ||
| 361 | |||
| 362 | samsung_gpiolib_add_4bit_chips(exynos4_gpio_part2_4bit, nr_chips); | ||
| 363 | |||
| 364 | /* GPIO part 3 */ | ||
| 365 | |||
| 366 | chip = exynos4_gpio_part3_4bit; | ||
| 367 | nr_chips = ARRAY_SIZE(exynos4_gpio_part3_4bit); | ||
| 368 | |||
| 369 | for (i = 0; i < nr_chips; i++, chip++) { | ||
| 370 | if (chip->config == NULL) { | ||
| 371 | chip->config = &gpio_cfg; | ||
| 372 | /* Assign the GPIO interrupt group */ | ||
| 373 | chip->group = group++; | ||
| 374 | } | ||
| 375 | if (chip->base == NULL) | ||
| 376 | chip->base = S5P_VA_GPIO3 + (i) * 0x20; | ||
| 377 | } | ||
| 378 | |||
| 379 | samsung_gpiolib_add_4bit_chips(exynos4_gpio_part3_4bit, nr_chips); | ||
| 380 | s5p_register_gpioint_bank(IRQ_GPIO_XA, 0, IRQ_GPIO1_NR_GROUPS); | ||
| 381 | s5p_register_gpioint_bank(IRQ_GPIO_XB, IRQ_GPIO1_NR_GROUPS, IRQ_GPIO2_NR_GROUPS); | ||
| 382 | |||
| 383 | return 0; | ||
| 384 | } | ||
| 385 | core_initcall(exynos4_gpiolib_init); | ||
diff --git a/drivers/gpio/gpio-nomadik.c b/drivers/gpio/gpio-nomadik.c new file mode 100644 index 00000000000..2c212c732d7 --- /dev/null +++ b/drivers/gpio/gpio-nomadik.c | |||
| @@ -0,0 +1,1087 @@ | |||
| 1 | /* | ||
| 2 | * Generic GPIO driver for logic cells found in the Nomadik SoC | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008,2009 STMicroelectronics | ||
| 5 | * Copyright (C) 2009 Alessandro Rubini <rubini@unipv.it> | ||
| 6 | * Rewritten based on work by Prafulla WADASKAR <prafulla.wadaskar@st.com> | ||
| 7 | * Copyright (C) 2011 Linus Walleij <linus.walleij@linaro.org> | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License version 2 as | ||
| 11 | * published by the Free Software Foundation. | ||
| 12 | */ | ||
| 13 | #include <linux/kernel.h> | ||
| 14 | #include <linux/module.h> | ||
| 15 | #include <linux/init.h> | ||
| 16 | #include <linux/device.h> | ||
| 17 | #include <linux/platform_device.h> | ||
| 18 | #include <linux/io.h> | ||
| 19 | #include <linux/clk.h> | ||
| 20 | #include <linux/err.h> | ||
| 21 | #include <linux/gpio.h> | ||
| 22 | #include <linux/spinlock.h> | ||
| 23 | #include <linux/interrupt.h> | ||
| 24 | #include <linux/irq.h> | ||
| 25 | #include <linux/slab.h> | ||
| 26 | |||
| 27 | #include <asm/mach/irq.h> | ||
| 28 | |||
| 29 | #include <plat/pincfg.h> | ||
| 30 | #include <mach/hardware.h> | ||
| 31 | #include <mach/gpio.h> | ||
| 32 | |||
| 33 | /* | ||
| 34 | * The GPIO module in the Nomadik family of Systems-on-Chip is an | ||
| 35 | * AMBA device, managing 32 pins and alternate functions. The logic block | ||
| 36 | * is currently used in the Nomadik and ux500. | ||
| 37 | * | ||
| 38 | * Symbols in this file are called "nmk_gpio" for "nomadik gpio" | ||
| 39 | */ | ||
| 40 | |||
| 41 | #define NMK_GPIO_PER_CHIP 32 | ||
| 42 | |||
| 43 | struct nmk_gpio_chip { | ||
| 44 | struct gpio_chip chip; | ||
| 45 | void __iomem *addr; | ||
| 46 | struct clk *clk; | ||
| 47 | unsigned int bank; | ||
| 48 | unsigned int parent_irq; | ||
| 49 | int secondary_parent_irq; | ||
| 50 | u32 (*get_secondary_status)(unsigned int bank); | ||
| 51 | void (*set_ioforce)(bool enable); | ||
| 52 | spinlock_t lock; | ||
| 53 | bool sleepmode; | ||
| 54 | /* Keep track of configured edges */ | ||
| 55 | u32 edge_rising; | ||
| 56 | u32 edge_falling; | ||
| 57 | u32 real_wake; | ||
| 58 | u32 rwimsc; | ||
| 59 | u32 fwimsc; | ||
| 60 | u32 slpm; | ||
| 61 | u32 enabled; | ||
| 62 | u32 pull_up; | ||
| 63 | }; | ||
| 64 | |||
| 65 | static struct nmk_gpio_chip * | ||
| 66 | nmk_gpio_chips[DIV_ROUND_UP(ARCH_NR_GPIOS, NMK_GPIO_PER_CHIP)]; | ||
| 67 | |||
| 68 | static DEFINE_SPINLOCK(nmk_gpio_slpm_lock); | ||
| 69 | |||
| 70 | #define NUM_BANKS ARRAY_SIZE(nmk_gpio_chips) | ||
| 71 | |||
| 72 | static void __nmk_gpio_set_mode(struct nmk_gpio_chip *nmk_chip, | ||
| 73 | unsigned offset, int gpio_mode) | ||
| 74 | { | ||
| 75 | u32 bit = 1 << offset; | ||
| 76 | u32 afunc, bfunc; | ||
| 77 | |||
| 78 | afunc = readl(nmk_chip->addr + NMK_GPIO_AFSLA) & ~bit; | ||
| 79 | bfunc = readl(nmk_chip->addr + NMK_GPIO_AFSLB) & ~bit; | ||
| 80 | if (gpio_mode & NMK_GPIO_ALT_A) | ||
| 81 | afunc |= bit; | ||
| 82 | if (gpio_mode & NMK_GPIO_ALT_B) | ||
| 83 | bfunc |= bit; | ||
| 84 | writel(afunc, nmk_chip->addr + NMK_GPIO_AFSLA); | ||
| 85 | writel(bfunc, nmk_chip->addr + NMK_GPIO_AFSLB); | ||
| 86 | } | ||
| 87 | |||
| 88 | static void __nmk_gpio_set_slpm(struct nmk_gpio_chip *nmk_chip, | ||
| 89 | unsigned offset, enum nmk_gpio_slpm mode) | ||
| 90 | { | ||
| 91 | u32 bit = 1 << offset; | ||
| 92 | u32 slpm; | ||
| 93 | |||
| 94 | slpm = readl(nmk_chip->addr + NMK_GPIO_SLPC); | ||
| 95 | if (mode == NMK_GPIO_SLPM_NOCHANGE) | ||
| 96 | slpm |= bit; | ||
| 97 | else | ||
| 98 | slpm &= ~bit; | ||
| 99 | writel(slpm, nmk_chip->addr + NMK_GPIO_SLPC); | ||
| 100 | } | ||
| 101 | |||
| 102 | static void __nmk_gpio_set_pull(struct nmk_gpio_chip *nmk_chip, | ||
| 103 | unsigned offset, enum nmk_gpio_pull pull) | ||
| 104 | { | ||
| 105 | u32 bit = 1 << offset; | ||
| 106 | u32 pdis; | ||
| 107 | |||
| 108 | pdis = readl(nmk_chip->addr + NMK_GPIO_PDIS); | ||
| 109 | if (pull == NMK_GPIO_PULL_NONE) { | ||
| 110 | pdis |= bit; | ||
| 111 | nmk_chip->pull_up &= ~bit; | ||
| 112 | } else { | ||
| 113 | pdis &= ~bit; | ||
| 114 | } | ||
| 115 | |||
| 116 | writel(pdis, nmk_chip->addr + NMK_GPIO_PDIS); | ||
| 117 | |||
| 118 | if (pull == NMK_GPIO_PULL_UP) { | ||
| 119 | nmk_chip->pull_up |= bit; | ||
| 120 | writel(bit, nmk_chip->addr + NMK_GPIO_DATS); | ||
| 121 | } else if (pull == NMK_GPIO_PULL_DOWN) { | ||
| 122 | nmk_chip->pull_up &= ~bit; | ||
| 123 | writel(bit, nmk_chip->addr + NMK_GPIO_DATC); | ||
| 124 | } | ||
| 125 | } | ||
| 126 | |||
| 127 | static void __nmk_gpio_make_input(struct nmk_gpio_chip *nmk_chip, | ||
| 128 | unsigned offset) | ||
| 129 | { | ||
| 130 | writel(1 << offset, nmk_chip->addr + NMK_GPIO_DIRC); | ||
| 131 | } | ||
| 132 | |||
| 133 | static void __nmk_gpio_set_output(struct nmk_gpio_chip *nmk_chip, | ||
| 134 | unsigned offset, int val) | ||
| 135 | { | ||
| 136 | if (val) | ||
| 137 | writel(1 << offset, nmk_chip->addr + NMK_GPIO_DATS); | ||
| 138 | else | ||
| 139 | writel(1 << offset, nmk_chip->addr + NMK_GPIO_DATC); | ||
| 140 | } | ||
| 141 | |||
| 142 | static void __nmk_gpio_make_output(struct nmk_gpio_chip *nmk_chip, | ||
| 143 | unsigned offset, int val) | ||
| 144 | { | ||
| 145 | writel(1 << offset, nmk_chip->addr + NMK_GPIO_DIRS); | ||
| 146 | __nmk_gpio_set_output(nmk_chip, offset, val); | ||
| 147 | } | ||
| 148 | |||
| 149 | static void __nmk_gpio_set_mode_safe(struct nmk_gpio_chip *nmk_chip, | ||
| 150 | unsigned offset, int gpio_mode, | ||
| 151 | bool glitch) | ||
| 152 | { | ||
| 153 | u32 rwimsc = readl(nmk_chip->addr + NMK_GPIO_RWIMSC); | ||
| 154 | u32 fwimsc = readl(nmk_chip->addr + NMK_GPIO_FWIMSC); | ||
| 155 | |||
| 156 | if (glitch && nmk_chip->set_ioforce) { | ||
| 157 | u32 bit = BIT(offset); | ||
| 158 | |||
| 159 | /* Prevent spurious wakeups */ | ||
| 160 | writel(rwimsc & ~bit, nmk_chip->addr + NMK_GPIO_RWIMSC); | ||
| 161 | writel(fwimsc & ~bit, nmk_chip->addr + NMK_GPIO_FWIMSC); | ||
| 162 | |||
| 163 | nmk_chip->set_ioforce(true); | ||
| 164 | } | ||
| 165 | |||
| 166 | __nmk_gpio_set_mode(nmk_chip, offset, gpio_mode); | ||
| 167 | |||
| 168 | if (glitch && nmk_chip->set_ioforce) { | ||
| 169 | nmk_chip->set_ioforce(false); | ||
| 170 | |||
| 171 | writel(rwimsc, nmk_chip->addr + NMK_GPIO_RWIMSC); | ||
| 172 | writel(fwimsc, nmk_chip->addr + NMK_GPIO_FWIMSC); | ||
| 173 | } | ||
| 174 | } | ||
| 175 | |||
| 176 | static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset, | ||
| 177 | pin_cfg_t cfg, bool sleep, unsigned int *slpmregs) | ||
| 178 | { | ||
| 179 | static const char *afnames[] = { | ||
| 180 | [NMK_GPIO_ALT_GPIO] = "GPIO", | ||
| 181 | [NMK_GPIO_ALT_A] = "A", | ||
| 182 | [NMK_GPIO_ALT_B] = "B", | ||
| 183 | [NMK_GPIO_ALT_C] = "C" | ||
| 184 | }; | ||
| 185 | static const char *pullnames[] = { | ||
| 186 | [NMK_GPIO_PULL_NONE] = "none", | ||
| 187 | [NMK_GPIO_PULL_UP] = "up", | ||
| 188 | [NMK_GPIO_PULL_DOWN] = "down", | ||
| 189 | [3] /* illegal */ = "??" | ||
| 190 | }; | ||
| 191 | static const char *slpmnames[] = { | ||
| 192 | [NMK_GPIO_SLPM_INPUT] = "input/wakeup", | ||
| 193 | [NMK_GPIO_SLPM_NOCHANGE] = "no-change/no-wakeup", | ||
| 194 | }; | ||
| 195 | |||
| 196 | int pin = PIN_NUM(cfg); | ||
| 197 | int pull = PIN_PULL(cfg); | ||
| 198 | int af = PIN_ALT(cfg); | ||
| 199 | int slpm = PIN_SLPM(cfg); | ||
| 200 | int output = PIN_DIR(cfg); | ||
| 201 | int val = PIN_VAL(cfg); | ||
| 202 | bool glitch = af == NMK_GPIO_ALT_C; | ||
| 203 | |||
| 204 | dev_dbg(nmk_chip->chip.dev, "pin %d [%#lx]: af %s, pull %s, slpm %s (%s%s)\n", | ||
| 205 | pin, cfg, afnames[af], pullnames[pull], slpmnames[slpm], | ||
| 206 | output ? "output " : "input", | ||
| 207 | output ? (val ? "high" : "low") : ""); | ||
| 208 | |||
| 209 | if (sleep) { | ||
| 210 | int slpm_pull = PIN_SLPM_PULL(cfg); | ||
| 211 | int slpm_output = PIN_SLPM_DIR(cfg); | ||
| 212 | int slpm_val = PIN_SLPM_VAL(cfg); | ||
| 213 | |||
| 214 | af = NMK_GPIO_ALT_GPIO; | ||
| 215 | |||
| 216 | /* | ||
| 217 | * The SLPM_* values are normal values + 1 to allow zero to | ||
| 218 | * mean "same as normal". | ||
| 219 | */ | ||
| 220 | if (slpm_pull) | ||
| 221 | pull = slpm_pull - 1; | ||
| 222 | if (slpm_output) | ||
| 223 | output = slpm_output - 1; | ||
| 224 | if (slpm_val) | ||
| 225 | val = slpm_val - 1; | ||
| 226 | |||
| 227 | dev_dbg(nmk_chip->chip.dev, "pin %d: sleep pull %s, dir %s, val %s\n", | ||
| 228 | pin, | ||
| 229 | slpm_pull ? pullnames[pull] : "same", | ||
| 230 | slpm_output ? (output ? "output" : "input") : "same", | ||
| 231 | slpm_val ? (val ? "high" : "low") : "same"); | ||
| 232 | } | ||
| 233 | |||
| 234 | if (output) | ||
| 235 | __nmk_gpio_make_output(nmk_chip, offset, val); | ||
| 236 | else { | ||
| 237 | __nmk_gpio_make_input(nmk_chip, offset); | ||
| 238 | __nmk_gpio_set_pull(nmk_chip, offset, pull); | ||
| 239 | } | ||
| 240 | |||
| 241 | /* | ||
| 242 | * If we've backed up the SLPM registers (glitch workaround), modify | ||
| 243 | * the backups since they will be restored. | ||
| 244 | */ | ||
| 245 | if (slpmregs) { | ||
| 246 | if (slpm == NMK_GPIO_SLPM_NOCHANGE) | ||
| 247 | slpmregs[nmk_chip->bank] |= BIT(offset); | ||
| 248 | else | ||
| 249 | slpmregs[nmk_chip->bank] &= ~BIT(offset); | ||
| 250 | } else | ||
| 251 | __nmk_gpio_set_slpm(nmk_chip, offset, slpm); | ||
| 252 | |||
| 253 | __nmk_gpio_set_mode_safe(nmk_chip, offset, af, glitch); | ||
| 254 | } | ||
| 255 | |||
| 256 | /* | ||
| 257 | * Safe sequence used to switch IOs between GPIO and Alternate-C mode: | ||
| 258 | * - Save SLPM registers | ||
| 259 | * - Set SLPM=0 for the IOs you want to switch and others to 1 | ||
| 260 | * - Configure the GPIO registers for the IOs that are being switched | ||
| 261 | * - Set IOFORCE=1 | ||
| 262 | * - Modify the AFLSA/B registers for the IOs that are being switched | ||
| 263 | * - Set IOFORCE=0 | ||
| 264 | * - Restore SLPM registers | ||
| 265 | * - Any spurious wake up event during switch sequence to be ignored and | ||
| 266 | * cleared | ||
| 267 | */ | ||
| 268 | static void nmk_gpio_glitch_slpm_init(unsigned int *slpm) | ||
| 269 | { | ||
| 270 | int i; | ||
| 271 | |||
| 272 | for (i = 0; i < NUM_BANKS; i++) { | ||
| 273 | struct nmk_gpio_chip *chip = nmk_gpio_chips[i]; | ||
| 274 | unsigned int temp = slpm[i]; | ||
| 275 | |||
| 276 | if (!chip) | ||
| 277 | break; | ||
| 278 | |||
| 279 | slpm[i] = readl(chip->addr + NMK_GPIO_SLPC); | ||
| 280 | writel(temp, chip->addr + NMK_GPIO_SLPC); | ||
| 281 | } | ||
| 282 | } | ||
| 283 | |||
| 284 | static void nmk_gpio_glitch_slpm_restore(unsigned int *slpm) | ||
| 285 | { | ||
| 286 | int i; | ||
| 287 | |||
| 288 | for (i = 0; i < NUM_BANKS; i++) { | ||
| 289 | struct nmk_gpio_chip *chip = nmk_gpio_chips[i]; | ||
| 290 | |||
| 291 | if (!chip) | ||
| 292 | break; | ||
| 293 | |||
| 294 | writel(slpm[i], chip->addr + NMK_GPIO_SLPC); | ||
| 295 | } | ||
| 296 | } | ||
| 297 | |||
| 298 | static int __nmk_config_pins(pin_cfg_t *cfgs, int num, bool sleep) | ||
| 299 | { | ||
| 300 | static unsigned int slpm[NUM_BANKS]; | ||
| 301 | unsigned long flags; | ||
| 302 | bool glitch = false; | ||
| 303 | int ret = 0; | ||
| 304 | int i; | ||
| 305 | |||
| 306 | for (i = 0; i < num; i++) { | ||
| 307 | if (PIN_ALT(cfgs[i]) == NMK_GPIO_ALT_C) { | ||
| 308 | glitch = true; | ||
| 309 | break; | ||
| 310 | } | ||
| 311 | } | ||
| 312 | |||
| 313 | spin_lock_irqsave(&nmk_gpio_slpm_lock, flags); | ||
| 314 | |||
| 315 | if (glitch) { | ||
| 316 | memset(slpm, 0xff, sizeof(slpm)); | ||
| 317 | |||
| 318 | for (i = 0; i < num; i++) { | ||
| 319 | int pin = PIN_NUM(cfgs[i]); | ||
| 320 | int offset = pin % NMK_GPIO_PER_CHIP; | ||
| 321 | |||
| 322 | if (PIN_ALT(cfgs[i]) == NMK_GPIO_ALT_C) | ||
| 323 | slpm[pin / NMK_GPIO_PER_CHIP] &= ~BIT(offset); | ||
| 324 | } | ||
| 325 | |||
| 326 | nmk_gpio_glitch_slpm_init(slpm); | ||
| 327 | } | ||
| 328 | |||
| 329 | for (i = 0; i < num; i++) { | ||
| 330 | struct nmk_gpio_chip *nmk_chip; | ||
| 331 | int pin = PIN_NUM(cfgs[i]); | ||
| 332 | |||
| 333 | nmk_chip = irq_get_chip_data(NOMADIK_GPIO_TO_IRQ(pin)); | ||
| 334 | if (!nmk_chip) { | ||
| 335 | ret = -EINVAL; | ||
| 336 | break; | ||
| 337 | } | ||
| 338 | |||
| 339 | spin_lock(&nmk_chip->lock); | ||
| 340 | __nmk_config_pin(nmk_chip, pin - nmk_chip->chip.base, | ||
| 341 | cfgs[i], sleep, glitch ? slpm : NULL); | ||
| 342 | spin_unlock(&nmk_chip->lock); | ||
| 343 | } | ||
| 344 | |||
| 345 | if (glitch) | ||
| 346 | nmk_gpio_glitch_slpm_restore(slpm); | ||
| 347 | |||
| 348 | spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags); | ||
| 349 | |||
| 350 | return ret; | ||
| 351 | } | ||
| 352 | |||
| 353 | /** | ||
| 354 | * nmk_config_pin - configure a pin's mux attributes | ||
| 355 | * @cfg: pin confguration | ||
| 356 | * | ||
| 357 | * Configures a pin's mode (alternate function or GPIO), its pull up status, | ||
| 358 | * and its sleep mode based on the specified configuration. The @cfg is | ||
| 359 | * usually one of the SoC specific macros defined in mach/<soc>-pins.h. These | ||
| 360 | * are constructed using, and can be further enhanced with, the macros in | ||
| 361 | * plat/pincfg.h. | ||
| 362 | * | ||
| 363 | * If a pin's mode is set to GPIO, it is configured as an input to avoid | ||
| 364 | * side-effects. The gpio can be manipulated later using standard GPIO API | ||
| 365 | * calls. | ||
| 366 | */ | ||
| 367 | int nmk_config_pin(pin_cfg_t cfg, bool sleep) | ||
| 368 | { | ||
| 369 | return __nmk_config_pins(&cfg, 1, sleep); | ||
| 370 | } | ||
| 371 | EXPORT_SYMBOL(nmk_config_pin); | ||
| 372 | |||
| 373 | /** | ||
| 374 | * nmk_config_pins - configure several pins at once | ||
| 375 | * @cfgs: array of pin configurations | ||
| 376 | * @num: number of elments in the array | ||
| 377 | * | ||
| 378 | * Configures several pins using nmk_config_pin(). Refer to that function for | ||
| 379 | * further information. | ||
| 380 | */ | ||
| 381 | int nmk_config_pins(pin_cfg_t *cfgs, int num) | ||
| 382 | { | ||
| 383 | return __nmk_config_pins(cfgs, num, false); | ||
| 384 | } | ||
| 385 | EXPORT_SYMBOL(nmk_config_pins); | ||
| 386 | |||
| 387 | int nmk_config_pins_sleep(pin_cfg_t *cfgs, int num) | ||
| 388 | { | ||
| 389 | return __nmk_config_pins(cfgs, num, true); | ||
| 390 | } | ||
| 391 | EXPORT_SYMBOL(nmk_config_pins_sleep); | ||
| 392 | |||
| 393 | /** | ||
| 394 | * nmk_gpio_set_slpm() - configure the sleep mode of a pin | ||
| 395 | * @gpio: pin number | ||
| 396 | * @mode: NMK_GPIO_SLPM_INPUT or NMK_GPIO_SLPM_NOCHANGE, | ||
| 397 | * | ||
| 398 | * This register is actually in the pinmux layer, not the GPIO block itself. | ||
| 399 | * The GPIO1B_SLPM register defines the GPIO mode when SLEEP/DEEP-SLEEP | ||
| 400 | * mode is entered (i.e. when signal IOFORCE is HIGH by the platform code). | ||
| 401 | * Each GPIO can be configured to be forced into GPIO mode when IOFORCE is | ||
| 402 | * HIGH, overriding the normal setting defined by GPIO_AFSELx registers. | ||
| 403 | * When IOFORCE returns LOW (by software, after SLEEP/DEEP-SLEEP exit), | ||
| 404 | * the GPIOs return to the normal setting defined by GPIO_AFSELx registers. | ||
| 405 | * | ||
| 406 | * If @mode is NMK_GPIO_SLPM_INPUT, the corresponding GPIO is switched to GPIO | ||
| 407 | * mode when signal IOFORCE is HIGH (i.e. when SLEEP/DEEP-SLEEP mode is | ||
| 408 | * entered) regardless of the altfunction selected. Also wake-up detection is | ||
| 409 | * ENABLED. | ||
| 410 | * | ||
| 411 | * If @mode is NMK_GPIO_SLPM_NOCHANGE, the corresponding GPIO remains | ||
| 412 | * controlled by NMK_GPIO_DATC, NMK_GPIO_DATS, NMK_GPIO_DIR, NMK_GPIO_PDIS | ||
| 413 | * (for altfunction GPIO) or respective on-chip peripherals (for other | ||
| 414 | * altfuncs) when IOFORCE is HIGH. Also wake-up detection DISABLED. | ||
| 415 | * | ||
| 416 | * Note that enable_irq_wake() will automatically enable wakeup detection. | ||
| 417 | */ | ||
| 418 | int nmk_gpio_set_slpm(int gpio, enum nmk_gpio_slpm mode) | ||
| 419 | { | ||
| 420 | struct nmk_gpio_chip *nmk_chip; | ||
| 421 | unsigned long flags; | ||
| 422 | |||
| 423 | nmk_chip = irq_get_chip_data(NOMADIK_GPIO_TO_IRQ(gpio)); | ||
| 424 | if (!nmk_chip) | ||
| 425 | return -EINVAL; | ||
| 426 | |||
| 427 | spin_lock_irqsave(&nmk_gpio_slpm_lock, flags); | ||
| 428 | spin_lock(&nmk_chip->lock); | ||
| 429 | |||
| 430 | __nmk_gpio_set_slpm(nmk_chip, gpio - nmk_chip->chip.base, mode); | ||
| 431 | |||
| 432 | spin_unlock(&nmk_chip->lock); | ||
| 433 | spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags); | ||
| 434 | |||
| 435 | return 0; | ||
| 436 | } | ||
| 437 | |||
| 438 | /** | ||
| 439 | * nmk_gpio_set_pull() - enable/disable pull up/down on a gpio | ||
| 440 | * @gpio: pin number | ||
| 441 | * @pull: one of NMK_GPIO_PULL_DOWN, NMK_GPIO_PULL_UP, and NMK_GPIO_PULL_NONE | ||
| 442 | * | ||
| 443 | * Enables/disables pull up/down on a specified pin. This only takes effect if | ||
| 444 | * the pin is configured as an input (either explicitly or by the alternate | ||
| 445 | * function). | ||
| 446 | * | ||
| 447 | * NOTE: If enabling the pull up/down, the caller must ensure that the GPIO is | ||
| 448 | * configured as an input. Otherwise, due to the way the controller registers | ||
| 449 | * work, this function will change the value output on the pin. | ||
| 450 | */ | ||
| 451 | int nmk_gpio_set_pull(int gpio, enum nmk_gpio_pull pull) | ||
| 452 | { | ||
| 453 | struct nmk_gpio_chip *nmk_chip; | ||
| 454 | unsigned long flags; | ||
| 455 | |||
| 456 | nmk_chip = irq_get_chip_data(NOMADIK_GPIO_TO_IRQ(gpio)); | ||
| 457 | if (!nmk_chip) | ||
| 458 | return -EINVAL; | ||
| 459 | |||
| 460 | spin_lock_irqsave(&nmk_chip->lock, flags); | ||
| 461 | __nmk_gpio_set_pull(nmk_chip, gpio - nmk_chip->chip.base, pull); | ||
| 462 | spin_unlock_irqrestore(&nmk_chip->lock, flags); | ||
| 463 | |||
| 464 | return 0; | ||
| 465 | } | ||
| 466 | |||
| 467 | /* Mode functions */ | ||
| 468 | /** | ||
| 469 | * nmk_gpio_set_mode() - set the mux mode of a gpio pin | ||
| 470 | * @gpio: pin number | ||
| 471 | * @gpio_mode: one of NMK_GPIO_ALT_GPIO, NMK_GPIO_ALT_A, | ||
| 472 | * NMK_GPIO_ALT_B, and NMK_GPIO_ALT_C | ||
| 473 | * | ||
| 474 | * Sets the mode of the specified pin to one of the alternate functions or | ||
| 475 | * plain GPIO. | ||
| 476 | */ | ||
| 477 | int nmk_gpio_set_mode(int gpio, int gpio_mode) | ||
| 478 | { | ||
| 479 | struct nmk_gpio_chip *nmk_chip; | ||
| 480 | unsigned long flags; | ||
| 481 | |||
| 482 | nmk_chip = irq_get_chip_data(NOMADIK_GPIO_TO_IRQ(gpio)); | ||
| 483 | if (!nmk_chip) | ||
| 484 | return -EINVAL; | ||
| 485 | |||
| 486 | spin_lock_irqsave(&nmk_chip->lock, flags); | ||
| 487 | __nmk_gpio_set_mode(nmk_chip, gpio - nmk_chip->chip.base, gpio_mode); | ||
| 488 | spin_unlock_irqrestore(&nmk_chip->lock, flags); | ||
| 489 | |||
| 490 | return 0; | ||
| 491 | } | ||
| 492 | EXPORT_SYMBOL(nmk_gpio_set_mode); | ||
| 493 | |||
| 494 | int nmk_gpio_get_mode(int gpio) | ||
| 495 | { | ||
| 496 | struct nmk_gpio_chip *nmk_chip; | ||
| 497 | u32 afunc, bfunc, bit; | ||
| 498 | |||
| 499 | nmk_chip = irq_get_chip_data(NOMADIK_GPIO_TO_IRQ(gpio)); | ||
| 500 | if (!nmk_chip) | ||
| 501 | return -EINVAL; | ||
| 502 | |||
| 503 | bit = 1 << (gpio - nmk_chip->chip.base); | ||
| 504 | |||
| 505 | afunc = readl(nmk_chip->addr + NMK_GPIO_AFSLA) & bit; | ||
| 506 | bfunc = readl(nmk_chip->addr + NMK_GPIO_AFSLB) & bit; | ||
| 507 | |||
| 508 | return (afunc ? NMK_GPIO_ALT_A : 0) | (bfunc ? NMK_GPIO_ALT_B : 0); | ||
| 509 | } | ||
| 510 | EXPORT_SYMBOL(nmk_gpio_get_mode); | ||
| 511 | |||
| 512 | |||
| 513 | /* IRQ functions */ | ||
| 514 | static inline int nmk_gpio_get_bitmask(int gpio) | ||
| 515 | { | ||
| 516 | return 1 << (gpio % 32); | ||
| 517 | } | ||
| 518 | |||
| 519 | static void nmk_gpio_irq_ack(struct irq_data *d) | ||
| 520 | { | ||
| 521 | int gpio; | ||
| 522 | struct nmk_gpio_chip *nmk_chip; | ||
| 523 | |||
| 524 | gpio = NOMADIK_IRQ_TO_GPIO(d->irq); | ||
| 525 | nmk_chip = irq_data_get_irq_chip_data(d); | ||
| 526 | if (!nmk_chip) | ||
| 527 | return; | ||
| 528 | writel(nmk_gpio_get_bitmask(gpio), nmk_chip->addr + NMK_GPIO_IC); | ||
| 529 | } | ||
| 530 | |||
| 531 | enum nmk_gpio_irq_type { | ||
| 532 | NORMAL, | ||
| 533 | WAKE, | ||
| 534 | }; | ||
| 535 | |||
| 536 | static void __nmk_gpio_irq_modify(struct nmk_gpio_chip *nmk_chip, | ||
| 537 | int gpio, enum nmk_gpio_irq_type which, | ||
| 538 | bool enable) | ||
| 539 | { | ||
| 540 | u32 rimsc = which == WAKE ? NMK_GPIO_RWIMSC : NMK_GPIO_RIMSC; | ||
| 541 | u32 fimsc = which == WAKE ? NMK_GPIO_FWIMSC : NMK_GPIO_FIMSC; | ||
| 542 | u32 bitmask = nmk_gpio_get_bitmask(gpio); | ||
| 543 | u32 reg; | ||
| 544 | |||
| 545 | /* we must individually set/clear the two edges */ | ||
| 546 | if (nmk_chip->edge_rising & bitmask) { | ||
| 547 | reg = readl(nmk_chip->addr + rimsc); | ||
| 548 | if (enable) | ||
| 549 | reg |= bitmask; | ||
| 550 | else | ||
| 551 | reg &= ~bitmask; | ||
| 552 | writel(reg, nmk_chip->addr + rimsc); | ||
| 553 | } | ||
| 554 | if (nmk_chip->edge_falling & bitmask) { | ||
| 555 | reg = readl(nmk_chip->addr + fimsc); | ||
| 556 | if (enable) | ||
| 557 | reg |= bitmask; | ||
| 558 | else | ||
| 559 | reg &= ~bitmask; | ||
| 560 | writel(reg, nmk_chip->addr + fimsc); | ||
| 561 | } | ||
| 562 | } | ||
| 563 | |||
| 564 | static void __nmk_gpio_set_wake(struct nmk_gpio_chip *nmk_chip, | ||
| 565 | int gpio, bool on) | ||
| 566 | { | ||
| 567 | if (nmk_chip->sleepmode) { | ||
| 568 | __nmk_gpio_set_slpm(nmk_chip, gpio - nmk_chip->chip.base, | ||
| 569 | on ? NMK_GPIO_SLPM_WAKEUP_ENABLE | ||
| 570 | : NMK_GPIO_SLPM_WAKEUP_DISABLE); | ||
| 571 | } | ||
| 572 | |||
| 573 | __nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, on); | ||
| 574 | } | ||
| 575 | |||
| 576 | static int nmk_gpio_irq_maskunmask(struct irq_data *d, bool enable) | ||
| 577 | { | ||
| 578 | int gpio; | ||
| 579 | struct nmk_gpio_chip *nmk_chip; | ||
| 580 | unsigned long flags; | ||
| 581 | u32 bitmask; | ||
| 582 | |||
| 583 | gpio = NOMADIK_IRQ_TO_GPIO(d->irq); | ||
| 584 | nmk_chip = irq_data_get_irq_chip_data(d); | ||
| 585 | bitmask = nmk_gpio_get_bitmask(gpio); | ||
| 586 | if (!nmk_chip) | ||
| 587 | return -EINVAL; | ||
| 588 | |||
| 589 | if (enable) | ||
| 590 | nmk_chip->enabled |= bitmask; | ||
| 591 | else | ||
| 592 | nmk_chip->enabled &= ~bitmask; | ||
| 593 | |||
| 594 | spin_lock_irqsave(&nmk_gpio_slpm_lock, flags); | ||
| 595 | spin_lock(&nmk_chip->lock); | ||
| 596 | |||
| 597 | __nmk_gpio_irq_modify(nmk_chip, gpio, NORMAL, enable); | ||
| 598 | |||
| 599 | if (!(nmk_chip->real_wake & bitmask)) | ||
| 600 | __nmk_gpio_set_wake(nmk_chip, gpio, enable); | ||
| 601 | |||
| 602 | spin_unlock(&nmk_chip->lock); | ||
| 603 | spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags); | ||
| 604 | |||
| 605 | return 0; | ||
| 606 | } | ||
| 607 | |||
| 608 | static void nmk_gpio_irq_mask(struct irq_data *d) | ||
| 609 | { | ||
| 610 | nmk_gpio_irq_maskunmask(d, false); | ||
| 611 | } | ||
| 612 | |||
| 613 | static void nmk_gpio_irq_unmask(struct irq_data *d) | ||
| 614 | { | ||
| 615 | nmk_gpio_irq_maskunmask(d, true); | ||
| 616 | } | ||
| 617 | |||
| 618 | static int nmk_gpio_irq_set_wake(struct irq_data *d, unsigned int on) | ||
| 619 | { | ||
| 620 | struct nmk_gpio_chip *nmk_chip; | ||
| 621 | unsigned long flags; | ||
| 622 | u32 bitmask; | ||
| 623 | int gpio; | ||
| 624 | |||
| 625 | gpio = NOMADIK_IRQ_TO_GPIO(d->irq); | ||
| 626 | nmk_chip = irq_data_get_irq_chip_data(d); | ||
| 627 | if (!nmk_chip) | ||
| 628 | return -EINVAL; | ||
| 629 | bitmask = nmk_gpio_get_bitmask(gpio); | ||
| 630 | |||
| 631 | spin_lock_irqsave(&nmk_gpio_slpm_lock, flags); | ||
| 632 | spin_lock(&nmk_chip->lock); | ||
| 633 | |||
| 634 | if (!(nmk_chip->enabled & bitmask)) | ||
| 635 | __nmk_gpio_set_wake(nmk_chip, gpio, on); | ||
| 636 | |||
| 637 | if (on) | ||
| 638 | nmk_chip->real_wake |= bitmask; | ||
| 639 | else | ||
| 640 | nmk_chip->real_wake &= ~bitmask; | ||
| 641 | |||
| 642 | spin_unlock(&nmk_chip->lock); | ||
| 643 | spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags); | ||
| 644 | |||
| 645 | return 0; | ||
| 646 | } | ||
| 647 | |||
| 648 | static int nmk_gpio_irq_set_type(struct irq_data *d, unsigned int type) | ||
| 649 | { | ||
| 650 | bool enabled, wake = irqd_is_wakeup_set(d); | ||
| 651 | int gpio; | ||
| 652 | struct nmk_gpio_chip *nmk_chip; | ||
| 653 | unsigned long flags; | ||
| 654 | u32 bitmask; | ||
| 655 | |||
| 656 | gpio = NOMADIK_IRQ_TO_GPIO(d->irq); | ||
| 657 | nmk_chip = irq_data_get_irq_chip_data(d); | ||
| 658 | bitmask = nmk_gpio_get_bitmask(gpio); | ||
| 659 | if (!nmk_chip) | ||
| 660 | return -EINVAL; | ||
| 661 | |||
| 662 | if (type & IRQ_TYPE_LEVEL_HIGH) | ||
| 663 | return -EINVAL; | ||
| 664 | if (type & IRQ_TYPE_LEVEL_LOW) | ||
| 665 | return -EINVAL; | ||
| 666 | |||
| 667 | enabled = nmk_chip->enabled & bitmask; | ||
| 668 | |||
| 669 | spin_lock_irqsave(&nmk_chip->lock, flags); | ||
| 670 | |||
| 671 | if (enabled) | ||
| 672 | __nmk_gpio_irq_modify(nmk_chip, gpio, NORMAL, false); | ||
| 673 | |||
| 674 | if (enabled || wake) | ||
| 675 | __nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, false); | ||
| 676 | |||
| 677 | nmk_chip->edge_rising &= ~bitmask; | ||
| 678 | if (type & IRQ_TYPE_EDGE_RISING) | ||
| 679 | nmk_chip->edge_rising |= bitmask; | ||
| 680 | |||
| 681 | nmk_chip->edge_falling &= ~bitmask; | ||
| 682 | if (type & IRQ_TYPE_EDGE_FALLING) | ||
| 683 | nmk_chip->edge_falling |= bitmask; | ||
| 684 | |||
| 685 | if (enabled) | ||
| 686 | __nmk_gpio_irq_modify(nmk_chip, gpio, NORMAL, true); | ||
| 687 | |||
| 688 | if (enabled || wake) | ||
| 689 | __nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, true); | ||
| 690 | |||
| 691 | spin_unlock_irqrestore(&nmk_chip->lock, flags); | ||
| 692 | |||
| 693 | return 0; | ||
| 694 | } | ||
| 695 | |||
| 696 | static struct irq_chip nmk_gpio_irq_chip = { | ||
| 697 | .name = "Nomadik-GPIO", | ||
| 698 | .irq_ack = nmk_gpio_irq_ack, | ||
| 699 | .irq_mask = nmk_gpio_irq_mask, | ||
| 700 | .irq_unmask = nmk_gpio_irq_unmask, | ||
| 701 | .irq_set_type = nmk_gpio_irq_set_type, | ||
| 702 | .irq_set_wake = nmk_gpio_irq_set_wake, | ||
| 703 | }; | ||
| 704 | |||
| 705 | static void __nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc, | ||
| 706 | u32 status) | ||
| 707 | { | ||
| 708 | struct nmk_gpio_chip *nmk_chip; | ||
| 709 | struct irq_chip *host_chip = irq_get_chip(irq); | ||
| 710 | unsigned int first_irq; | ||
| 711 | |||
| 712 | chained_irq_enter(host_chip, desc); | ||
| 713 | |||
| 714 | nmk_chip = irq_get_handler_data(irq); | ||
| 715 | first_irq = NOMADIK_GPIO_TO_IRQ(nmk_chip->chip.base); | ||
| 716 | while (status) { | ||
| 717 | int bit = __ffs(status); | ||
| 718 | |||
| 719 | generic_handle_irq(first_irq + bit); | ||
| 720 | status &= ~BIT(bit); | ||
| 721 | } | ||
| 722 | |||
| 723 | chained_irq_exit(host_chip, desc); | ||
| 724 | } | ||
| 725 | |||
| 726 | static void nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) | ||
| 727 | { | ||
| 728 | struct nmk_gpio_chip *nmk_chip = irq_get_handler_data(irq); | ||
| 729 | u32 status = readl(nmk_chip->addr + NMK_GPIO_IS); | ||
| 730 | |||
| 731 | __nmk_gpio_irq_handler(irq, desc, status); | ||
| 732 | } | ||
| 733 | |||
| 734 | static void nmk_gpio_secondary_irq_handler(unsigned int irq, | ||
| 735 | struct irq_desc *desc) | ||
| 736 | { | ||
| 737 | struct nmk_gpio_chip *nmk_chip = irq_get_handler_data(irq); | ||
| 738 | u32 status = nmk_chip->get_secondary_status(nmk_chip->bank); | ||
| 739 | |||
| 740 | __nmk_gpio_irq_handler(irq, desc, status); | ||
| 741 | } | ||
| 742 | |||
| 743 | static int nmk_gpio_init_irq(struct nmk_gpio_chip *nmk_chip) | ||
| 744 | { | ||
| 745 | unsigned int first_irq; | ||
| 746 | int i; | ||
| 747 | |||
| 748 | first_irq = NOMADIK_GPIO_TO_IRQ(nmk_chip->chip.base); | ||
| 749 | for (i = first_irq; i < first_irq + nmk_chip->chip.ngpio; i++) { | ||
| 750 | irq_set_chip_and_handler(i, &nmk_gpio_irq_chip, | ||
| 751 | handle_edge_irq); | ||
| 752 | set_irq_flags(i, IRQF_VALID); | ||
| 753 | irq_set_chip_data(i, nmk_chip); | ||
| 754 | irq_set_irq_type(i, IRQ_TYPE_EDGE_FALLING); | ||
| 755 | } | ||
| 756 | |||
| 757 | irq_set_chained_handler(nmk_chip->parent_irq, nmk_gpio_irq_handler); | ||
| 758 | irq_set_handler_data(nmk_chip->parent_irq, nmk_chip); | ||
| 759 | |||
| 760 | if (nmk_chip->secondary_parent_irq >= 0) { | ||
| 761 | irq_set_chained_handler(nmk_chip->secondary_parent_irq, | ||
| 762 | nmk_gpio_secondary_irq_handler); | ||
| 763 | irq_set_handler_data(nmk_chip->secondary_parent_irq, nmk_chip); | ||
| 764 | } | ||
| 765 | |||
| 766 | return 0; | ||
| 767 | } | ||
| 768 | |||
| 769 | /* I/O Functions */ | ||
| 770 | static int nmk_gpio_make_input(struct gpio_chip *chip, unsigned offset) | ||
| 771 | { | ||
| 772 | struct nmk_gpio_chip *nmk_chip = | ||
| 773 | container_of(chip, struct nmk_gpio_chip, chip); | ||
| 774 | |||
| 775 | writel(1 << offset, nmk_chip->addr + NMK_GPIO_DIRC); | ||
| 776 | return 0; | ||
| 777 | } | ||
| 778 | |||
| 779 | static int nmk_gpio_get_input(struct gpio_chip *chip, unsigned offset) | ||
| 780 | { | ||
| 781 | struct nmk_gpio_chip *nmk_chip = | ||
| 782 | container_of(chip, struct nmk_gpio_chip, chip); | ||
| 783 | u32 bit = 1 << offset; | ||
| 784 | |||
| 785 | return (readl(nmk_chip->addr + NMK_GPIO_DAT) & bit) != 0; | ||
| 786 | } | ||
| 787 | |||
| 788 | static void nmk_gpio_set_output(struct gpio_chip *chip, unsigned offset, | ||
| 789 | int val) | ||
| 790 | { | ||
| 791 | struct nmk_gpio_chip *nmk_chip = | ||
| 792 | container_of(chip, struct nmk_gpio_chip, chip); | ||
| 793 | |||
| 794 | __nmk_gpio_set_output(nmk_chip, offset, val); | ||
| 795 | } | ||
| 796 | |||
| 797 | static int nmk_gpio_make_output(struct gpio_chip *chip, unsigned offset, | ||
| 798 | int val) | ||
| 799 | { | ||
| 800 | struct nmk_gpio_chip *nmk_chip = | ||
| 801 | container_of(chip, struct nmk_gpio_chip, chip); | ||
| 802 | |||
| 803 | __nmk_gpio_make_output(nmk_chip, offset, val); | ||
| 804 | |||
| 805 | return 0; | ||
| 806 | } | ||
| 807 | |||
| 808 | static int nmk_gpio_to_irq(struct gpio_chip *chip, unsigned offset) | ||
| 809 | { | ||
| 810 | struct nmk_gpio_chip *nmk_chip = | ||
| 811 | container_of(chip, struct nmk_gpio_chip, chip); | ||
| 812 | |||
| 813 | return NOMADIK_GPIO_TO_IRQ(nmk_chip->chip.base) + offset; | ||
| 814 | } | ||
| 815 | |||
| 816 | #ifdef CONFIG_DEBUG_FS | ||
| 817 | |||
| 818 | #include <linux/seq_file.h> | ||
| 819 | |||
| 820 | static void nmk_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) | ||
| 821 | { | ||
| 822 | int mode; | ||
| 823 | unsigned i; | ||
| 824 | unsigned gpio = chip->base; | ||
| 825 | int is_out; | ||
| 826 | struct nmk_gpio_chip *nmk_chip = | ||
| 827 | container_of(chip, struct nmk_gpio_chip, chip); | ||
| 828 | const char *modes[] = { | ||
| 829 | [NMK_GPIO_ALT_GPIO] = "gpio", | ||
| 830 | [NMK_GPIO_ALT_A] = "altA", | ||
| 831 | [NMK_GPIO_ALT_B] = "altB", | ||
| 832 | [NMK_GPIO_ALT_C] = "altC", | ||
| 833 | }; | ||
| 834 | |||
| 835 | for (i = 0; i < chip->ngpio; i++, gpio++) { | ||
| 836 | const char *label = gpiochip_is_requested(chip, i); | ||
| 837 | bool pull; | ||
| 838 | u32 bit = 1 << i; | ||
| 839 | |||
| 840 | is_out = readl(nmk_chip->addr + NMK_GPIO_DIR) & bit; | ||
| 841 | pull = !(readl(nmk_chip->addr + NMK_GPIO_PDIS) & bit); | ||
| 842 | mode = nmk_gpio_get_mode(gpio); | ||
| 843 | seq_printf(s, " gpio-%-3d (%-20.20s) %s %s %s %s", | ||
| 844 | gpio, label ?: "(none)", | ||
| 845 | is_out ? "out" : "in ", | ||
| 846 | chip->get | ||
| 847 | ? (chip->get(chip, i) ? "hi" : "lo") | ||
| 848 | : "? ", | ||
| 849 | (mode < 0) ? "unknown" : modes[mode], | ||
| 850 | pull ? "pull" : "none"); | ||
| 851 | |||
| 852 | if (label && !is_out) { | ||
| 853 | int irq = gpio_to_irq(gpio); | ||
| 854 | struct irq_desc *desc = irq_to_desc(irq); | ||
| 855 | |||
| 856 | /* This races with request_irq(), set_irq_type(), | ||
| 857 | * and set_irq_wake() ... but those are "rare". | ||
| 858 | */ | ||
| 859 | if (irq >= 0 && desc->action) { | ||
| 860 | char *trigger; | ||
| 861 | u32 bitmask = nmk_gpio_get_bitmask(gpio); | ||
| 862 | |||
| 863 | if (nmk_chip->edge_rising & bitmask) | ||
| 864 | trigger = "edge-rising"; | ||
| 865 | else if (nmk_chip->edge_falling & bitmask) | ||
| 866 | trigger = "edge-falling"; | ||
| 867 | else | ||
| 868 | trigger = "edge-undefined"; | ||
| 869 | |||
| 870 | seq_printf(s, " irq-%d %s%s", | ||
| 871 | irq, trigger, | ||
| 872 | irqd_is_wakeup_set(&desc->irq_data) | ||
| 873 | ? " wakeup" : ""); | ||
| 874 | } | ||
| 875 | } | ||
| 876 | |||
| 877 | seq_printf(s, "\n"); | ||
| 878 | } | ||
| 879 | } | ||
| 880 | |||
| 881 | #else | ||
| 882 | #define nmk_gpio_dbg_show NULL | ||
| 883 | #endif | ||
| 884 | |||
| 885 | /* This structure is replicated for each GPIO block allocated at probe time */ | ||
| 886 | static struct gpio_chip nmk_gpio_template = { | ||
| 887 | .direction_input = nmk_gpio_make_input, | ||
| 888 | .get = nmk_gpio_get_input, | ||
| 889 | .direction_output = nmk_gpio_make_output, | ||
| 890 | .set = nmk_gpio_set_output, | ||
| 891 | .to_irq = nmk_gpio_to_irq, | ||
| 892 | .dbg_show = nmk_gpio_dbg_show, | ||
| 893 | .can_sleep = 0, | ||
| 894 | }; | ||
| 895 | |||
| 896 | /* | ||
| 897 | * Called from the suspend/resume path to only keep the real wakeup interrupts | ||
| 898 | * (those that have had set_irq_wake() called on them) as wakeup interrupts, | ||
| 899 | * and not the rest of the interrupts which we needed to have as wakeups for | ||
| 900 | * cpuidle. | ||
| 901 | * | ||
| 902 | * PM ops are not used since this needs to be done at the end, after all the | ||
| 903 | * other drivers are done with their suspend callbacks. | ||
| 904 | */ | ||
| 905 | void nmk_gpio_wakeups_suspend(void) | ||
| 906 | { | ||
| 907 | int i; | ||
| 908 | |||
| 909 | for (i = 0; i < NUM_BANKS; i++) { | ||
| 910 | struct nmk_gpio_chip *chip = nmk_gpio_chips[i]; | ||
| 911 | |||
| 912 | if (!chip) | ||
| 913 | break; | ||
| 914 | |||
| 915 | chip->rwimsc = readl(chip->addr + NMK_GPIO_RWIMSC); | ||
| 916 | chip->fwimsc = readl(chip->addr + NMK_GPIO_FWIMSC); | ||
| 917 | |||
| 918 | writel(chip->rwimsc & chip->real_wake, | ||
| 919 | chip->addr + NMK_GPIO_RWIMSC); | ||
| 920 | writel(chip->fwimsc & chip->real_wake, | ||
| 921 | chip->addr + NMK_GPIO_FWIMSC); | ||
| 922 | |||
| 923 | if (chip->sleepmode) { | ||
| 924 | chip->slpm = readl(chip->addr + NMK_GPIO_SLPC); | ||
| 925 | |||
| 926 | /* 0 -> wakeup enable */ | ||
| 927 | writel(~chip->real_wake, chip->addr + NMK_GPIO_SLPC); | ||
| 928 | } | ||
| 929 | } | ||
| 930 | } | ||
| 931 | |||
| 932 | void nmk_gpio_wakeups_resume(void) | ||
| 933 | { | ||
| 934 | int i; | ||
| 935 | |||
| 936 | for (i = 0; i < NUM_BANKS; i++) { | ||
| 937 | struct nmk_gpio_chip *chip = nmk_gpio_chips[i]; | ||
| 938 | |||
| 939 | if (!chip) | ||
| 940 | break; | ||
| 941 | |||
| 942 | writel(chip->rwimsc, chip->addr + NMK_GPIO_RWIMSC); | ||
| 943 | writel(chip->fwimsc, chip->addr + NMK_GPIO_FWIMSC); | ||
| 944 | |||
| 945 | if (chip->sleepmode) | ||
| 946 | writel(chip->slpm, chip->addr + NMK_GPIO_SLPC); | ||
| 947 | } | ||
| 948 | } | ||
| 949 | |||
| 950 | /* | ||
| 951 | * Read the pull up/pull down status. | ||
| 952 | * A bit set in 'pull_up' means that pull up | ||
| 953 | * is selected if pull is enabled in PDIS register. | ||
| 954 | * Note: only pull up/down set via this driver can | ||
| 955 | * be detected due to HW limitations. | ||
| 956 | */ | ||
| 957 | void nmk_gpio_read_pull(int gpio_bank, u32 *pull_up) | ||
| 958 | { | ||
| 959 | if (gpio_bank < NUM_BANKS) { | ||
| 960 | struct nmk_gpio_chip *chip = nmk_gpio_chips[gpio_bank]; | ||
| 961 | |||
| 962 | if (!chip) | ||
| 963 | return; | ||
| 964 | |||
| 965 | *pull_up = chip->pull_up; | ||
| 966 | } | ||
| 967 | } | ||
| 968 | |||
| 969 | static int __devinit nmk_gpio_probe(struct platform_device *dev) | ||
| 970 | { | ||
| 971 | struct nmk_gpio_platform_data *pdata = dev->dev.platform_data; | ||
| 972 | struct nmk_gpio_chip *nmk_chip; | ||
| 973 | struct gpio_chip *chip; | ||
| 974 | struct resource *res; | ||
| 975 | struct clk *clk; | ||
| 976 | int secondary_irq; | ||
| 977 | int irq; | ||
| 978 | int ret; | ||
| 979 | |||
| 980 | if (!pdata) | ||
| 981 | return -ENODEV; | ||
| 982 | |||
| 983 | res = platform_get_resource(dev, IORESOURCE_MEM, 0); | ||
| 984 | if (!res) { | ||
| 985 | ret = -ENOENT; | ||
| 986 | goto out; | ||
| 987 | } | ||
| 988 | |||
| 989 | irq = platform_get_irq(dev, 0); | ||
| 990 | if (irq < 0) { | ||
| 991 | ret = irq; | ||
| 992 | goto out; | ||
| 993 | } | ||
| 994 | |||
| 995 | secondary_irq = platform_get_irq(dev, 1); | ||
| 996 | if (secondary_irq >= 0 && !pdata->get_secondary_status) { | ||
| 997 | ret = -EINVAL; | ||
| 998 | goto out; | ||
| 999 | } | ||
| 1000 | |||
| 1001 | if (request_mem_region(res->start, resource_size(res), | ||
| 1002 | dev_name(&dev->dev)) == NULL) { | ||
| 1003 | ret = -EBUSY; | ||
| 1004 | goto out; | ||
| 1005 | } | ||
| 1006 | |||
| 1007 | clk = clk_get(&dev->dev, NULL); | ||
| 1008 | if (IS_ERR(clk)) { | ||
| 1009 | ret = PTR_ERR(clk); | ||
| 1010 | goto out_release; | ||
| 1011 | } | ||
| 1012 | |||
| 1013 | clk_enable(clk); | ||
| 1014 | |||
| 1015 | nmk_chip = kzalloc(sizeof(*nmk_chip), GFP_KERNEL); | ||
| 1016 | if (!nmk_chip) { | ||
| 1017 | ret = -ENOMEM; | ||
| 1018 | goto out_clk; | ||
| 1019 | } | ||
| 1020 | /* | ||
| 1021 | * The virt address in nmk_chip->addr is in the nomadik register space, | ||
| 1022 | * so we can simply convert the resource address, without remapping | ||
| 1023 | */ | ||
| 1024 | nmk_chip->bank = dev->id; | ||
| 1025 | nmk_chip->clk = clk; | ||
| 1026 | nmk_chip->addr = io_p2v(res->start); | ||
| 1027 | nmk_chip->chip = nmk_gpio_template; | ||
| 1028 | nmk_chip->parent_irq = irq; | ||
| 1029 | nmk_chip->secondary_parent_irq = secondary_irq; | ||
| 1030 | nmk_chip->get_secondary_status = pdata->get_secondary_status; | ||
| 1031 | nmk_chip->set_ioforce = pdata->set_ioforce; | ||
| 1032 | nmk_chip->sleepmode = pdata->supports_sleepmode; | ||
| 1033 | spin_lock_init(&nmk_chip->lock); | ||
| 1034 | |||
| 1035 | chip = &nmk_chip->chip; | ||
| 1036 | chip->base = pdata->first_gpio; | ||
| 1037 | chip->ngpio = pdata->num_gpio; | ||
| 1038 | chip->label = pdata->name ?: dev_name(&dev->dev); | ||
| 1039 | chip->dev = &dev->dev; | ||
| 1040 | chip->owner = THIS_MODULE; | ||
| 1041 | |||
| 1042 | ret = gpiochip_add(&nmk_chip->chip); | ||
| 1043 | if (ret) | ||
| 1044 | goto out_free; | ||
| 1045 | |||
| 1046 | BUG_ON(nmk_chip->bank >= ARRAY_SIZE(nmk_gpio_chips)); | ||
| 1047 | |||
| 1048 | nmk_gpio_chips[nmk_chip->bank] = nmk_chip; | ||
| 1049 | platform_set_drvdata(dev, nmk_chip); | ||
| 1050 | |||
| 1051 | nmk_gpio_init_irq(nmk_chip); | ||
| 1052 | |||
| 1053 | dev_info(&dev->dev, "Bits %i-%i at address %p\n", | ||
| 1054 | nmk_chip->chip.base, nmk_chip->chip.base+31, nmk_chip->addr); | ||
| 1055 | return 0; | ||
| 1056 | |||
| 1057 | out_free: | ||
| 1058 | kfree(nmk_chip); | ||
| 1059 | out_clk: | ||
| 1060 | clk_disable(clk); | ||
| 1061 | clk_put(clk); | ||
| 1062 | out_release: | ||
| 1063 | release_mem_region(res->start, resource_size(res)); | ||
| 1064 | out: | ||
| 1065 | dev_err(&dev->dev, "Failure %i for GPIO %i-%i\n", ret, | ||
| 1066 | pdata->first_gpio, pdata->first_gpio+31); | ||
| 1067 | return ret; | ||
| 1068 | } | ||
| 1069 | |||
| 1070 | static struct platform_driver nmk_gpio_driver = { | ||
| 1071 | .driver = { | ||
| 1072 | .owner = THIS_MODULE, | ||
| 1073 | .name = "gpio", | ||
| 1074 | }, | ||
| 1075 | .probe = nmk_gpio_probe, | ||
| 1076 | }; | ||
| 1077 | |||
| 1078 | static int __init nmk_gpio_init(void) | ||
| 1079 | { | ||
| 1080 | return platform_driver_register(&nmk_gpio_driver); | ||
| 1081 | } | ||
| 1082 | |||
| 1083 | core_initcall(nmk_gpio_init); | ||
| 1084 | |||
| 1085 | MODULE_AUTHOR("Prafulla WADASKAR and Alessandro Rubini"); | ||
| 1086 | MODULE_DESCRIPTION("Nomadik GPIO Driver"); | ||
| 1087 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/gpio/gpio-plat-samsung.c b/drivers/gpio/gpio-plat-samsung.c new file mode 100644 index 00000000000..ef67f1952a7 --- /dev/null +++ b/drivers/gpio/gpio-plat-samsung.c | |||
| @@ -0,0 +1,205 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2008 Openmoko, Inc. | ||
| 3 | * Copyright 2008 Simtec Electronics | ||
| 4 | * Ben Dooks <ben@simtec.co.uk> | ||
| 5 | * http://armlinux.simtec.co.uk/ | ||
| 6 | * | ||
| 7 | * Copyright (c) 2009 Samsung Electronics Co., Ltd. | ||
| 8 | * http://www.samsung.com/ | ||
| 9 | * | ||
| 10 | * SAMSUNG - GPIOlib support | ||
| 11 | * | ||
| 12 | * This program is free software; you can redistribute it and/or modify | ||
| 13 | * it under the terms of the GNU General Public License version 2 as | ||
| 14 | * published by the Free Software Foundation. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/kernel.h> | ||
| 18 | #include <linux/irq.h> | ||
| 19 | #include <linux/io.h> | ||
| 20 | #include <linux/gpio.h> | ||
| 21 | #include <plat/gpio-core.h> | ||
| 22 | #include <plat/gpio-cfg.h> | ||
| 23 | #include <plat/gpio-cfg-helpers.h> | ||
| 24 | |||
| 25 | #ifndef DEBUG_GPIO | ||
| 26 | #define gpio_dbg(x...) do { } while (0) | ||
| 27 | #else | ||
| 28 | #define gpio_dbg(x...) printk(KERN_DEBUG x) | ||
| 29 | #endif | ||
| 30 | |||
| 31 | /* The samsung_gpiolib_4bit routines are to control the gpio banks where | ||
| 32 | * the gpio configuration register (GPxCON) has 4 bits per GPIO, as the | ||
| 33 | * following example: | ||
| 34 | * | ||
| 35 | * base + 0x00: Control register, 4 bits per gpio | ||
| 36 | * gpio n: 4 bits starting at (4*n) | ||
| 37 | * 0000 = input, 0001 = output, others mean special-function | ||
| 38 | * base + 0x04: Data register, 1 bit per gpio | ||
| 39 | * bit n: data bit n | ||
| 40 | * | ||
| 41 | * Note, since the data register is one bit per gpio and is at base + 0x4 | ||
| 42 | * we can use s3c_gpiolib_get and s3c_gpiolib_set to change the state of | ||
| 43 | * the output. | ||
| 44 | */ | ||
| 45 | |||
| 46 | static int samsung_gpiolib_4bit_input(struct gpio_chip *chip, | ||
| 47 | unsigned int offset) | ||
| 48 | { | ||
| 49 | struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip); | ||
| 50 | void __iomem *base = ourchip->base; | ||
| 51 | unsigned long con; | ||
| 52 | |||
| 53 | con = __raw_readl(base + GPIOCON_OFF); | ||
| 54 | con &= ~(0xf << con_4bit_shift(offset)); | ||
| 55 | __raw_writel(con, base + GPIOCON_OFF); | ||
| 56 | |||
| 57 | gpio_dbg("%s: %p: CON now %08lx\n", __func__, base, con); | ||
| 58 | |||
| 59 | return 0; | ||
| 60 | } | ||
| 61 | |||
| 62 | static int samsung_gpiolib_4bit_output(struct gpio_chip *chip, | ||
| 63 | unsigned int offset, int value) | ||
| 64 | { | ||
| 65 | struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip); | ||
| 66 | void __iomem *base = ourchip->base; | ||
| 67 | unsigned long con; | ||
| 68 | unsigned long dat; | ||
| 69 | |||
| 70 | con = __raw_readl(base + GPIOCON_OFF); | ||
| 71 | con &= ~(0xf << con_4bit_shift(offset)); | ||
| 72 | con |= 0x1 << con_4bit_shift(offset); | ||
| 73 | |||
| 74 | dat = __raw_readl(base + GPIODAT_OFF); | ||
| 75 | |||
| 76 | if (value) | ||
| 77 | dat |= 1 << offset; | ||
| 78 | else | ||
| 79 | dat &= ~(1 << offset); | ||
| 80 | |||
| 81 | __raw_writel(dat, base + GPIODAT_OFF); | ||
| 82 | __raw_writel(con, base + GPIOCON_OFF); | ||
| 83 | __raw_writel(dat, base + GPIODAT_OFF); | ||
| 84 | |||
| 85 | gpio_dbg("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat); | ||
| 86 | |||
| 87 | return 0; | ||
| 88 | } | ||
| 89 | |||
| 90 | /* The next set of routines are for the case where the GPIO configuration | ||
| 91 | * registers are 4 bits per GPIO but there is more than one register (the | ||
| 92 | * bank has more than 8 GPIOs. | ||
| 93 | * | ||
| 94 | * This case is the similar to the 4 bit case, but the registers are as | ||
| 95 | * follows: | ||
| 96 | * | ||
| 97 | * base + 0x00: Control register, 4 bits per gpio (lower 8 GPIOs) | ||
| 98 | * gpio n: 4 bits starting at (4*n) | ||
| 99 | * 0000 = input, 0001 = output, others mean special-function | ||
| 100 | * base + 0x04: Control register, 4 bits per gpio (up to 8 additions GPIOs) | ||
| 101 | * gpio n: 4 bits starting at (4*n) | ||
| 102 | * 0000 = input, 0001 = output, others mean special-function | ||
| 103 | * base + 0x08: Data register, 1 bit per gpio | ||
| 104 | * bit n: data bit n | ||
| 105 | * | ||
| 106 | * To allow us to use the s3c_gpiolib_get and s3c_gpiolib_set routines we | ||
| 107 | * store the 'base + 0x4' address so that these routines see the data | ||
| 108 | * register at ourchip->base + 0x04. | ||
| 109 | */ | ||
| 110 | |||
| 111 | static int samsung_gpiolib_4bit2_input(struct gpio_chip *chip, | ||
| 112 | unsigned int offset) | ||
| 113 | { | ||
| 114 | struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip); | ||
| 115 | void __iomem *base = ourchip->base; | ||
| 116 | void __iomem *regcon = base; | ||
| 117 | unsigned long con; | ||
| 118 | |||
| 119 | if (offset > 7) | ||
| 120 | offset -= 8; | ||
| 121 | else | ||
| 122 | regcon -= 4; | ||
| 123 | |||
| 124 | con = __raw_readl(regcon); | ||
| 125 | con &= ~(0xf << con_4bit_shift(offset)); | ||
| 126 | __raw_writel(con, regcon); | ||
| 127 | |||
| 128 | gpio_dbg("%s: %p: CON %08lx\n", __func__, base, con); | ||
| 129 | |||
| 130 | return 0; | ||
| 131 | } | ||
| 132 | |||
| 133 | static int samsung_gpiolib_4bit2_output(struct gpio_chip *chip, | ||
| 134 | unsigned int offset, int value) | ||
| 135 | { | ||
| 136 | struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip); | ||
| 137 | void __iomem *base = ourchip->base; | ||
| 138 | void __iomem *regcon = base; | ||
| 139 | unsigned long con; | ||
| 140 | unsigned long dat; | ||
| 141 | unsigned con_offset = offset; | ||
| 142 | |||
| 143 | if (con_offset > 7) | ||
| 144 | con_offset -= 8; | ||
| 145 | else | ||
| 146 | regcon -= 4; | ||
| 147 | |||
| 148 | con = __raw_readl(regcon); | ||
| 149 | con &= ~(0xf << con_4bit_shift(con_offset)); | ||
| 150 | con |= 0x1 << con_4bit_shift(con_offset); | ||
| 151 | |||
| 152 | dat = __raw_readl(base + GPIODAT_OFF); | ||
| 153 | |||
| 154 | if (value) | ||
| 155 | dat |= 1 << offset; | ||
| 156 | else | ||
| 157 | dat &= ~(1 << offset); | ||
| 158 | |||
| 159 | __raw_writel(dat, base + GPIODAT_OFF); | ||
| 160 | __raw_writel(con, regcon); | ||
| 161 | __raw_writel(dat, base + GPIODAT_OFF); | ||
| 162 | |||
| 163 | gpio_dbg("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat); | ||
| 164 | |||
| 165 | return 0; | ||
| 166 | } | ||
| 167 | |||
| 168 | void __init samsung_gpiolib_add_4bit(struct s3c_gpio_chip *chip) | ||
| 169 | { | ||
| 170 | chip->chip.direction_input = samsung_gpiolib_4bit_input; | ||
| 171 | chip->chip.direction_output = samsung_gpiolib_4bit_output; | ||
| 172 | chip->pm = __gpio_pm(&s3c_gpio_pm_4bit); | ||
| 173 | } | ||
| 174 | |||
| 175 | void __init samsung_gpiolib_add_4bit2(struct s3c_gpio_chip *chip) | ||
| 176 | { | ||
| 177 | chip->chip.direction_input = samsung_gpiolib_4bit2_input; | ||
| 178 | chip->chip.direction_output = samsung_gpiolib_4bit2_output; | ||
| 179 | chip->pm = __gpio_pm(&s3c_gpio_pm_4bit); | ||
| 180 | } | ||
| 181 | |||
| 182 | void __init samsung_gpiolib_add_4bit_chips(struct s3c_gpio_chip *chip, | ||
| 183 | int nr_chips) | ||
| 184 | { | ||
| 185 | for (; nr_chips > 0; nr_chips--, chip++) { | ||
| 186 | samsung_gpiolib_add_4bit(chip); | ||
| 187 | s3c_gpiolib_add(chip); | ||
| 188 | } | ||
| 189 | } | ||
| 190 | |||
| 191 | void __init samsung_gpiolib_add_4bit2_chips(struct s3c_gpio_chip *chip, | ||
| 192 | int nr_chips) | ||
| 193 | { | ||
| 194 | for (; nr_chips > 0; nr_chips--, chip++) { | ||
| 195 | samsung_gpiolib_add_4bit2(chip); | ||
| 196 | s3c_gpiolib_add(chip); | ||
| 197 | } | ||
| 198 | } | ||
| 199 | |||
| 200 | void __init samsung_gpiolib_add_2bit_chips(struct s3c_gpio_chip *chip, | ||
| 201 | int nr_chips) | ||
| 202 | { | ||
| 203 | for (; nr_chips > 0; nr_chips--, chip++) | ||
| 204 | s3c_gpiolib_add(chip); | ||
| 205 | } | ||
diff --git a/drivers/gpio/gpio-s5pc100.c b/drivers/gpio/gpio-s5pc100.c new file mode 100644 index 00000000000..7f87b0c76e0 --- /dev/null +++ b/drivers/gpio/gpio-s5pc100.c | |||
| @@ -0,0 +1,354 @@ | |||
| 1 | /* | ||
| 2 | * S5PC100 - GPIOlib support | ||
| 3 | * | ||
| 4 | * Copyright (c) 2010 Samsung Electronics Co., Ltd. | ||
| 5 | * http://www.samsung.com | ||
| 6 | * | ||
| 7 | * Copyright 2009 Samsung Electronics Co | ||
| 8 | * Kyungmin Park <kyungmin.park@samsung.com> | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License version 2 as | ||
| 12 | * published by the Free Software Foundation. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include <linux/kernel.h> | ||
| 16 | #include <linux/irq.h> | ||
| 17 | #include <linux/io.h> | ||
| 18 | #include <linux/gpio.h> | ||
| 19 | |||
| 20 | #include <mach/map.h> | ||
| 21 | #include <mach/regs-gpio.h> | ||
| 22 | |||
| 23 | #include <plat/gpio-core.h> | ||
| 24 | #include <plat/gpio-cfg.h> | ||
| 25 | #include <plat/gpio-cfg-helpers.h> | ||
| 26 | |||
| 27 | /* S5PC100 GPIO bank summary: | ||
| 28 | * | ||
| 29 | * Bank GPIOs Style INT Type | ||
| 30 | * A0 8 4Bit GPIO_INT0 | ||
| 31 | * A1 5 4Bit GPIO_INT1 | ||
| 32 | * B 8 4Bit GPIO_INT2 | ||
| 33 | * C 5 4Bit GPIO_INT3 | ||
| 34 | * D 7 4Bit GPIO_INT4 | ||
| 35 | * E0 8 4Bit GPIO_INT5 | ||
| 36 | * E1 6 4Bit GPIO_INT6 | ||
| 37 | * F0 8 4Bit GPIO_INT7 | ||
| 38 | * F1 8 4Bit GPIO_INT8 | ||
| 39 | * F2 8 4Bit GPIO_INT9 | ||
| 40 | * F3 4 4Bit GPIO_INT10 | ||
| 41 | * G0 8 4Bit GPIO_INT11 | ||
| 42 | * G1 3 4Bit GPIO_INT12 | ||
| 43 | * G2 7 4Bit GPIO_INT13 | ||
| 44 | * G3 7 4Bit GPIO_INT14 | ||
| 45 | * H0 8 4Bit WKUP_INT | ||
| 46 | * H1 8 4Bit WKUP_INT | ||
| 47 | * H2 8 4Bit WKUP_INT | ||
| 48 | * H3 8 4Bit WKUP_INT | ||
| 49 | * I 8 4Bit GPIO_INT15 | ||
| 50 | * J0 8 4Bit GPIO_INT16 | ||
| 51 | * J1 5 4Bit GPIO_INT17 | ||
| 52 | * J2 8 4Bit GPIO_INT18 | ||
| 53 | * J3 8 4Bit GPIO_INT19 | ||
| 54 | * J4 4 4Bit GPIO_INT20 | ||
| 55 | * K0 8 4Bit None | ||
| 56 | * K1 6 4Bit None | ||
| 57 | * K2 8 4Bit None | ||
| 58 | * K3 8 4Bit None | ||
| 59 | * L0 8 4Bit None | ||
| 60 | * L1 8 4Bit None | ||
| 61 | * L2 8 4Bit None | ||
| 62 | * L3 8 4Bit None | ||
| 63 | */ | ||
| 64 | |||
| 65 | static struct s3c_gpio_cfg gpio_cfg = { | ||
| 66 | .set_config = s3c_gpio_setcfg_s3c64xx_4bit, | ||
| 67 | .set_pull = s3c_gpio_setpull_updown, | ||
| 68 | .get_pull = s3c_gpio_getpull_updown, | ||
| 69 | }; | ||
| 70 | |||
| 71 | static struct s3c_gpio_cfg gpio_cfg_eint = { | ||
| 72 | .cfg_eint = 0xf, | ||
| 73 | .set_config = s3c_gpio_setcfg_s3c64xx_4bit, | ||
| 74 | .set_pull = s3c_gpio_setpull_updown, | ||
| 75 | .get_pull = s3c_gpio_getpull_updown, | ||
| 76 | }; | ||
| 77 | |||
| 78 | static struct s3c_gpio_cfg gpio_cfg_noint = { | ||
| 79 | .set_config = s3c_gpio_setcfg_s3c64xx_4bit, | ||
| 80 | .set_pull = s3c_gpio_setpull_updown, | ||
| 81 | .get_pull = s3c_gpio_getpull_updown, | ||
| 82 | }; | ||
| 83 | |||
| 84 | /* | ||
| 85 | * GPIO bank's base address given the index of the bank in the | ||
| 86 | * list of all gpio banks. | ||
| 87 | */ | ||
| 88 | #define S5PC100_BANK_BASE(bank_nr) (S5P_VA_GPIO + ((bank_nr) * 0x20)) | ||
| 89 | |||
| 90 | /* | ||
| 91 | * Following are the gpio banks in S5PC100. | ||
| 92 | * | ||
| 93 | * The 'config' member when left to NULL, is initialized to the default | ||
| 94 | * structure gpio_cfg in the init function below. | ||
| 95 | * | ||
| 96 | * The 'base' member is also initialized in the init function below. | ||
| 97 | * Note: The initialization of 'base' member of s3c_gpio_chip structure | ||
| 98 | * uses the above macro and depends on the banks being listed in order here. | ||
| 99 | */ | ||
| 100 | static struct s3c_gpio_chip s5pc100_gpio_chips[] = { | ||
| 101 | { | ||
| 102 | .chip = { | ||
| 103 | .base = S5PC100_GPA0(0), | ||
| 104 | .ngpio = S5PC100_GPIO_A0_NR, | ||
| 105 | .label = "GPA0", | ||
| 106 | }, | ||
| 107 | }, { | ||
| 108 | .chip = { | ||
| 109 | .base = S5PC100_GPA1(0), | ||
| 110 | .ngpio = S5PC100_GPIO_A1_NR, | ||
| 111 | .label = "GPA1", | ||
| 112 | }, | ||
| 113 | }, { | ||
| 114 | .chip = { | ||
| 115 | .base = S5PC100_GPB(0), | ||
| 116 | .ngpio = S5PC100_GPIO_B_NR, | ||
| 117 | .label = "GPB", | ||
| 118 | }, | ||
| 119 | }, { | ||
| 120 | .chip = { | ||
| 121 | .base = S5PC100_GPC(0), | ||
| 122 | .ngpio = S5PC100_GPIO_C_NR, | ||
| 123 | .label = "GPC", | ||
| 124 | }, | ||
| 125 | }, { | ||
| 126 | .chip = { | ||
| 127 | .base = S5PC100_GPD(0), | ||
| 128 | .ngpio = S5PC100_GPIO_D_NR, | ||
| 129 | .label = "GPD", | ||
| 130 | }, | ||
| 131 | }, { | ||
| 132 | .chip = { | ||
| 133 | .base = S5PC100_GPE0(0), | ||
| 134 | .ngpio = S5PC100_GPIO_E0_NR, | ||
| 135 | .label = "GPE0", | ||
| 136 | }, | ||
| 137 | }, { | ||
| 138 | .chip = { | ||
| 139 | .base = S5PC100_GPE1(0), | ||
| 140 | .ngpio = S5PC100_GPIO_E1_NR, | ||
| 141 | .label = "GPE1", | ||
| 142 | }, | ||
| 143 | }, { | ||
| 144 | .chip = { | ||
| 145 | .base = S5PC100_GPF0(0), | ||
| 146 | .ngpio = S5PC100_GPIO_F0_NR, | ||
| 147 | .label = "GPF0", | ||
| 148 | }, | ||
| 149 | }, { | ||
| 150 | .chip = { | ||
| 151 | .base = S5PC100_GPF1(0), | ||
| 152 | .ngpio = S5PC100_GPIO_F1_NR, | ||
| 153 | .label = "GPF1", | ||
| 154 | }, | ||
| 155 | }, { | ||
| 156 | .chip = { | ||
| 157 | .base = S5PC100_GPF2(0), | ||
| 158 | .ngpio = S5PC100_GPIO_F2_NR, | ||
| 159 | .label = "GPF2", | ||
| 160 | }, | ||
| 161 | }, { | ||
| 162 | .chip = { | ||
| 163 | .base = S5PC100_GPF3(0), | ||
| 164 | .ngpio = S5PC100_GPIO_F3_NR, | ||
| 165 | .label = "GPF3", | ||
| 166 | }, | ||
| 167 | }, { | ||
| 168 | .chip = { | ||
| 169 | .base = S5PC100_GPG0(0), | ||
| 170 | .ngpio = S5PC100_GPIO_G0_NR, | ||
| 171 | .label = "GPG0", | ||
| 172 | }, | ||
| 173 | }, { | ||
| 174 | .chip = { | ||
| 175 | .base = S5PC100_GPG1(0), | ||
| 176 | .ngpio = S5PC100_GPIO_G1_NR, | ||
| 177 | .label = "GPG1", | ||
| 178 | }, | ||
| 179 | }, { | ||
| 180 | .chip = { | ||
| 181 | .base = S5PC100_GPG2(0), | ||
| 182 | .ngpio = S5PC100_GPIO_G2_NR, | ||
| 183 | .label = "GPG2", | ||
| 184 | }, | ||
| 185 | }, { | ||
| 186 | .chip = { | ||
| 187 | .base = S5PC100_GPG3(0), | ||
| 188 | .ngpio = S5PC100_GPIO_G3_NR, | ||
| 189 | .label = "GPG3", | ||
| 190 | }, | ||
| 191 | }, { | ||
| 192 | .chip = { | ||
| 193 | .base = S5PC100_GPI(0), | ||
| 194 | .ngpio = S5PC100_GPIO_I_NR, | ||
| 195 | .label = "GPI", | ||
| 196 | }, | ||
| 197 | }, { | ||
| 198 | .chip = { | ||
| 199 | .base = S5PC100_GPJ0(0), | ||
| 200 | .ngpio = S5PC100_GPIO_J0_NR, | ||
| 201 | .label = "GPJ0", | ||
| 202 | }, | ||
| 203 | }, { | ||
| 204 | .chip = { | ||
| 205 | .base = S5PC100_GPJ1(0), | ||
| 206 | .ngpio = S5PC100_GPIO_J1_NR, | ||
| 207 | .label = "GPJ1", | ||
| 208 | }, | ||
| 209 | }, { | ||
| 210 | .chip = { | ||
| 211 | .base = S5PC100_GPJ2(0), | ||
| 212 | .ngpio = S5PC100_GPIO_J2_NR, | ||
| 213 | .label = "GPJ2", | ||
| 214 | }, | ||
| 215 | }, { | ||
| 216 | .chip = { | ||
| 217 | .base = S5PC100_GPJ3(0), | ||
| 218 | .ngpio = S5PC100_GPIO_J3_NR, | ||
| 219 | .label = "GPJ3", | ||
| 220 | }, | ||
| 221 | }, { | ||
| 222 | .chip = { | ||
| 223 | .base = S5PC100_GPJ4(0), | ||
| 224 | .ngpio = S5PC100_GPIO_J4_NR, | ||
| 225 | .label = "GPJ4", | ||
| 226 | }, | ||
| 227 | }, { | ||
| 228 | .config = &gpio_cfg_noint, | ||
| 229 | .chip = { | ||
| 230 | .base = S5PC100_GPK0(0), | ||
| 231 | .ngpio = S5PC100_GPIO_K0_NR, | ||
| 232 | .label = "GPK0", | ||
| 233 | }, | ||
| 234 | }, { | ||
| 235 | .config = &gpio_cfg_noint, | ||
| 236 | .chip = { | ||
| 237 | .base = S5PC100_GPK1(0), | ||
| 238 | .ngpio = S5PC100_GPIO_K1_NR, | ||
| 239 | .label = "GPK1", | ||
| 240 | }, | ||
| 241 | }, { | ||
| 242 | .config = &gpio_cfg_noint, | ||
| 243 | .chip = { | ||
| 244 | .base = S5PC100_GPK2(0), | ||
| 245 | .ngpio = S5PC100_GPIO_K2_NR, | ||
| 246 | .label = "GPK2", | ||
| 247 | }, | ||
| 248 | }, { | ||
| 249 | .config = &gpio_cfg_noint, | ||
| 250 | .chip = { | ||
| 251 | .base = S5PC100_GPK3(0), | ||
| 252 | .ngpio = S5PC100_GPIO_K3_NR, | ||
| 253 | .label = "GPK3", | ||
| 254 | }, | ||
| 255 | }, { | ||
| 256 | .config = &gpio_cfg_noint, | ||
| 257 | .chip = { | ||
| 258 | .base = S5PC100_GPL0(0), | ||
| 259 | .ngpio = S5PC100_GPIO_L0_NR, | ||
| 260 | .label = "GPL0", | ||
| 261 | }, | ||
| 262 | }, { | ||
| 263 | .config = &gpio_cfg_noint, | ||
| 264 | .chip = { | ||
| 265 | .base = S5PC100_GPL1(0), | ||
| 266 | .ngpio = S5PC100_GPIO_L1_NR, | ||
| 267 | .label = "GPL1", | ||
| 268 | }, | ||
| 269 | }, { | ||
| 270 | .config = &gpio_cfg_noint, | ||
| 271 | .chip = { | ||
| 272 | .base = S5PC100_GPL2(0), | ||
| 273 | .ngpio = S5PC100_GPIO_L2_NR, | ||
| 274 | .label = "GPL2", | ||
| 275 | }, | ||
| 276 | }, { | ||
| 277 | .config = &gpio_cfg_noint, | ||
| 278 | .chip = { | ||
| 279 | .base = S5PC100_GPL3(0), | ||
| 280 | .ngpio = S5PC100_GPIO_L3_NR, | ||
| 281 | .label = "GPL3", | ||
| 282 | }, | ||
| 283 | }, { | ||
| 284 | .config = &gpio_cfg_noint, | ||
| 285 | .chip = { | ||
| 286 | .base = S5PC100_GPL4(0), | ||
| 287 | .ngpio = S5PC100_GPIO_L4_NR, | ||
| 288 | .label = "GPL4", | ||
| 289 | }, | ||
| 290 | }, { | ||
| 291 | .base = (S5P_VA_GPIO + 0xC00), | ||
| 292 | .config = &gpio_cfg_eint, | ||
| 293 | .irq_base = IRQ_EINT(0), | ||
| 294 | .chip = { | ||
| 295 | .base = S5PC100_GPH0(0), | ||
| 296 | .ngpio = S5PC100_GPIO_H0_NR, | ||
| 297 | .label = "GPH0", | ||
| 298 | .to_irq = samsung_gpiolib_to_irq, | ||
| 299 | }, | ||
| 300 | }, { | ||
| 301 | .base = (S5P_VA_GPIO + 0xC20), | ||
| 302 | .config = &gpio_cfg_eint, | ||
| 303 | .irq_base = IRQ_EINT(8), | ||
| 304 | .chip = { | ||
| 305 | .base = S5PC100_GPH1(0), | ||
| 306 | .ngpio = S5PC100_GPIO_H1_NR, | ||
| 307 | .label = "GPH1", | ||
| 308 | .to_irq = samsung_gpiolib_to_irq, | ||
| 309 | }, | ||
| 310 | }, { | ||
| 311 | .base = (S5P_VA_GPIO + 0xC40), | ||
| 312 | .config = &gpio_cfg_eint, | ||
| 313 | .irq_base = IRQ_EINT(16), | ||
| 314 | .chip = { | ||
| 315 | .base = S5PC100_GPH2(0), | ||
| 316 | .ngpio = S5PC100_GPIO_H2_NR, | ||
| 317 | .label = "GPH2", | ||
| 318 | .to_irq = samsung_gpiolib_to_irq, | ||
| 319 | }, | ||
| 320 | }, { | ||
| 321 | .base = (S5P_VA_GPIO + 0xC60), | ||
| 322 | .config = &gpio_cfg_eint, | ||
| 323 | .irq_base = IRQ_EINT(24), | ||
| 324 | .chip = { | ||
| 325 | .base = S5PC100_GPH3(0), | ||
| 326 | .ngpio = S5PC100_GPIO_H3_NR, | ||
| 327 | .label = "GPH3", | ||
| 328 | .to_irq = samsung_gpiolib_to_irq, | ||
| 329 | }, | ||
| 330 | }, | ||
| 331 | }; | ||
| 332 | |||
| 333 | static __init int s5pc100_gpiolib_init(void) | ||
| 334 | { | ||
| 335 | struct s3c_gpio_chip *chip = s5pc100_gpio_chips; | ||
| 336 | int nr_chips = ARRAY_SIZE(s5pc100_gpio_chips); | ||
| 337 | int gpioint_group = 0; | ||
| 338 | int i; | ||
| 339 | |||
| 340 | for (i = 0; i < nr_chips; i++, chip++) { | ||
| 341 | if (chip->config == NULL) { | ||
| 342 | chip->config = &gpio_cfg; | ||
| 343 | chip->group = gpioint_group++; | ||
| 344 | } | ||
| 345 | if (chip->base == NULL) | ||
| 346 | chip->base = S5PC100_BANK_BASE(i); | ||
| 347 | } | ||
| 348 | |||
| 349 | samsung_gpiolib_add_4bit_chips(s5pc100_gpio_chips, nr_chips); | ||
| 350 | s5p_register_gpioint_bank(IRQ_GPIOINT, 0, S5P_GPIOINT_GROUP_MAXNR); | ||
| 351 | |||
| 352 | return 0; | ||
| 353 | } | ||
| 354 | core_initcall(s5pc100_gpiolib_init); | ||
diff --git a/drivers/gpio/gpio-s5pv210.c b/drivers/gpio/gpio-s5pv210.c new file mode 100644 index 00000000000..eb12f1602de --- /dev/null +++ b/drivers/gpio/gpio-s5pv210.c | |||
| @@ -0,0 +1,287 @@ | |||
| 1 | /* | ||
| 2 | * S5PV210 - GPIOlib support | ||
| 3 | * | ||
| 4 | * Copyright (c) 2010 Samsung Electronics Co., Ltd. | ||
| 5 | * http://www.samsung.com/ | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/kernel.h> | ||
| 13 | #include <linux/irq.h> | ||
| 14 | #include <linux/io.h> | ||
| 15 | #include <linux/gpio.h> | ||
| 16 | #include <plat/gpio-core.h> | ||
| 17 | #include <plat/gpio-cfg.h> | ||
| 18 | #include <plat/gpio-cfg-helpers.h> | ||
| 19 | #include <mach/map.h> | ||
| 20 | |||
| 21 | static struct s3c_gpio_cfg gpio_cfg = { | ||
| 22 | .set_config = s3c_gpio_setcfg_s3c64xx_4bit, | ||
| 23 | .set_pull = s3c_gpio_setpull_updown, | ||
| 24 | .get_pull = s3c_gpio_getpull_updown, | ||
| 25 | }; | ||
| 26 | |||
| 27 | static struct s3c_gpio_cfg gpio_cfg_noint = { | ||
| 28 | .set_config = s3c_gpio_setcfg_s3c64xx_4bit, | ||
| 29 | .set_pull = s3c_gpio_setpull_updown, | ||
| 30 | .get_pull = s3c_gpio_getpull_updown, | ||
| 31 | }; | ||
| 32 | |||
| 33 | /* GPIO bank's base address given the index of the bank in the | ||
| 34 | * list of all gpio banks. | ||
| 35 | */ | ||
| 36 | #define S5PV210_BANK_BASE(bank_nr) (S5P_VA_GPIO + ((bank_nr) * 0x20)) | ||
| 37 | |||
| 38 | /* | ||
| 39 | * Following are the gpio banks in v210. | ||
| 40 | * | ||
| 41 | * The 'config' member when left to NULL, is initialized to the default | ||
| 42 | * structure gpio_cfg in the init function below. | ||
| 43 | * | ||
| 44 | * The 'base' member is also initialized in the init function below. | ||
| 45 | * Note: The initialization of 'base' member of s3c_gpio_chip structure | ||
| 46 | * uses the above macro and depends on the banks being listed in order here. | ||
| 47 | */ | ||
| 48 | static struct s3c_gpio_chip s5pv210_gpio_4bit[] = { | ||
| 49 | { | ||
| 50 | .chip = { | ||
| 51 | .base = S5PV210_GPA0(0), | ||
| 52 | .ngpio = S5PV210_GPIO_A0_NR, | ||
| 53 | .label = "GPA0", | ||
| 54 | }, | ||
| 55 | }, { | ||
| 56 | .chip = { | ||
| 57 | .base = S5PV210_GPA1(0), | ||
| 58 | .ngpio = S5PV210_GPIO_A1_NR, | ||
| 59 | .label = "GPA1", | ||
| 60 | }, | ||
| 61 | }, { | ||
| 62 | .chip = { | ||
| 63 | .base = S5PV210_GPB(0), | ||
| 64 | .ngpio = S5PV210_GPIO_B_NR, | ||
| 65 | .label = "GPB", | ||
| 66 | }, | ||
| 67 | }, { | ||
| 68 | .chip = { | ||
| 69 | .base = S5PV210_GPC0(0), | ||
| 70 | .ngpio = S5PV210_GPIO_C0_NR, | ||
| 71 | .label = "GPC0", | ||
| 72 | }, | ||
| 73 | }, { | ||
| 74 | .chip = { | ||
| 75 | .base = S5PV210_GPC1(0), | ||
| 76 | .ngpio = S5PV210_GPIO_C1_NR, | ||
| 77 | .label = "GPC1", | ||
| 78 | }, | ||
| 79 | }, { | ||
| 80 | .chip = { | ||
| 81 | .base = S5PV210_GPD0(0), | ||
| 82 | .ngpio = S5PV210_GPIO_D0_NR, | ||
| 83 | .label = "GPD0", | ||
| 84 | }, | ||
| 85 | }, { | ||
| 86 | .chip = { | ||
| 87 | .base = S5PV210_GPD1(0), | ||
| 88 | .ngpio = S5PV210_GPIO_D1_NR, | ||
| 89 | .label = "GPD1", | ||
| 90 | }, | ||
| 91 | }, { | ||
| 92 | .chip = { | ||
| 93 | .base = S5PV210_GPE0(0), | ||
| 94 | .ngpio = S5PV210_GPIO_E0_NR, | ||
| 95 | .label = "GPE0", | ||
| 96 | }, | ||
| 97 | }, { | ||
| 98 | .chip = { | ||
| 99 | .base = S5PV210_GPE1(0), | ||
| 100 | .ngpio = S5PV210_GPIO_E1_NR, | ||
| 101 | .label = "GPE1", | ||
| 102 | }, | ||
| 103 | }, { | ||
| 104 | .chip = { | ||
| 105 | .base = S5PV210_GPF0(0), | ||
| 106 | .ngpio = S5PV210_GPIO_F0_NR, | ||
| 107 | .label = "GPF0", | ||
| 108 | }, | ||
| 109 | }, { | ||
| 110 | .chip = { | ||
| 111 | .base = S5PV210_GPF1(0), | ||
| 112 | .ngpio = S5PV210_GPIO_F1_NR, | ||
| 113 | .label = "GPF1", | ||
| 114 | }, | ||
| 115 | }, { | ||
| 116 | .chip = { | ||
| 117 | .base = S5PV210_GPF2(0), | ||
| 118 | .ngpio = S5PV210_GPIO_F2_NR, | ||
| 119 | .label = "GPF2", | ||
| 120 | }, | ||
| 121 | }, { | ||
| 122 | .chip = { | ||
| 123 | .base = S5PV210_GPF3(0), | ||
| 124 | .ngpio = S5PV210_GPIO_F3_NR, | ||
| 125 | .label = "GPF3", | ||
| 126 | }, | ||
| 127 | }, { | ||
| 128 | .chip = { | ||
| 129 | .base = S5PV210_GPG0(0), | ||
| 130 | .ngpio = S5PV210_GPIO_G0_NR, | ||
| 131 | .label = "GPG0", | ||
| 132 | }, | ||
| 133 | }, { | ||
| 134 | .chip = { | ||
| 135 | .base = S5PV210_GPG1(0), | ||
| 136 | .ngpio = S5PV210_GPIO_G1_NR, | ||
| 137 | .label = "GPG1", | ||
| 138 | }, | ||
| 139 | }, { | ||
| 140 | .chip = { | ||
| 141 | .base = S5PV210_GPG2(0), | ||
| 142 | .ngpio = S5PV210_GPIO_G2_NR, | ||
| 143 | .label = "GPG2", | ||
| 144 | }, | ||
| 145 | }, { | ||
| 146 | .chip = { | ||
| 147 | .base = S5PV210_GPG3(0), | ||
| 148 | .ngpio = S5PV210_GPIO_G3_NR, | ||
| 149 | .label = "GPG3", | ||
| 150 | }, | ||
| 151 | }, { | ||
| 152 | .config = &gpio_cfg_noint, | ||
| 153 | .chip = { | ||
| 154 | .base = S5PV210_GPI(0), | ||
| 155 | .ngpio = S5PV210_GPIO_I_NR, | ||
| 156 | .label = "GPI", | ||
| 157 | }, | ||
| 158 | }, { | ||
| 159 | .chip = { | ||
| 160 | .base = S5PV210_GPJ0(0), | ||
| 161 | .ngpio = S5PV210_GPIO_J0_NR, | ||
| 162 | .label = "GPJ0", | ||
| 163 | }, | ||
| 164 | }, { | ||
| 165 | .chip = { | ||
| 166 | .base = S5PV210_GPJ1(0), | ||
| 167 | .ngpio = S5PV210_GPIO_J1_NR, | ||
| 168 | .label = "GPJ1", | ||
| 169 | }, | ||
| 170 | }, { | ||
| 171 | .chip = { | ||
| 172 | .base = S5PV210_GPJ2(0), | ||
| 173 | .ngpio = S5PV210_GPIO_J2_NR, | ||
| 174 | .label = "GPJ2", | ||
| 175 | }, | ||
| 176 | }, { | ||
| 177 | .chip = { | ||
| 178 | .base = S5PV210_GPJ3(0), | ||
| 179 | .ngpio = S5PV210_GPIO_J3_NR, | ||
| 180 | .label = "GPJ3", | ||
| 181 | }, | ||
| 182 | }, { | ||
| 183 | .chip = { | ||
| 184 | .base = S5PV210_GPJ4(0), | ||
| 185 | .ngpio = S5PV210_GPIO_J4_NR, | ||
| 186 | .label = "GPJ4", | ||
| 187 | }, | ||
| 188 | }, { | ||
| 189 | .config = &gpio_cfg_noint, | ||
| 190 | .chip = { | ||
| 191 | .base = S5PV210_MP01(0), | ||
| 192 | .ngpio = S5PV210_GPIO_MP01_NR, | ||
| 193 | .label = "MP01", | ||
| 194 | }, | ||
| 195 | }, { | ||
| 196 | .config = &gpio_cfg_noint, | ||
| 197 | .chip = { | ||
| 198 | .base = S5PV210_MP02(0), | ||
| 199 | .ngpio = S5PV210_GPIO_MP02_NR, | ||
| 200 | .label = "MP02", | ||
| 201 | }, | ||
| 202 | }, { | ||
| 203 | .config = &gpio_cfg_noint, | ||
| 204 | .chip = { | ||
| 205 | .base = S5PV210_MP03(0), | ||
| 206 | .ngpio = S5PV210_GPIO_MP03_NR, | ||
| 207 | .label = "MP03", | ||
| 208 | }, | ||
| 209 | }, { | ||
| 210 | .config = &gpio_cfg_noint, | ||
| 211 | .chip = { | ||
| 212 | .base = S5PV210_MP04(0), | ||
| 213 | .ngpio = S5PV210_GPIO_MP04_NR, | ||
| 214 | .label = "MP04", | ||
| 215 | }, | ||
| 216 | }, { | ||
| 217 | .config = &gpio_cfg_noint, | ||
| 218 | .chip = { | ||
| 219 | .base = S5PV210_MP05(0), | ||
| 220 | .ngpio = S5PV210_GPIO_MP05_NR, | ||
| 221 | .label = "MP05", | ||
| 222 | }, | ||
| 223 | }, { | ||
| 224 | .base = (S5P_VA_GPIO + 0xC00), | ||
| 225 | .config = &gpio_cfg_noint, | ||
| 226 | .irq_base = IRQ_EINT(0), | ||
| 227 | .chip = { | ||
| 228 | .base = S5PV210_GPH0(0), | ||
| 229 | .ngpio = S5PV210_GPIO_H0_NR, | ||
| 230 | .label = "GPH0", | ||
| 231 | .to_irq = samsung_gpiolib_to_irq, | ||
| 232 | }, | ||
| 233 | }, { | ||
| 234 | .base = (S5P_VA_GPIO + 0xC20), | ||
| 235 | .config = &gpio_cfg_noint, | ||
| 236 | .irq_base = IRQ_EINT(8), | ||
| 237 | .chip = { | ||
| 238 | .base = S5PV210_GPH1(0), | ||
| 239 | .ngpio = S5PV210_GPIO_H1_NR, | ||
| 240 | .label = "GPH1", | ||
| 241 | .to_irq = samsung_gpiolib_to_irq, | ||
| 242 | }, | ||
| 243 | }, { | ||
| 244 | .base = (S5P_VA_GPIO + 0xC40), | ||
| 245 | .config = &gpio_cfg_noint, | ||
| 246 | .irq_base = IRQ_EINT(16), | ||
| 247 | .chip = { | ||
| 248 | .base = S5PV210_GPH2(0), | ||
| 249 | .ngpio = S5PV210_GPIO_H2_NR, | ||
| 250 | .label = "GPH2", | ||
| 251 | .to_irq = samsung_gpiolib_to_irq, | ||
| 252 | }, | ||
| 253 | }, { | ||
| 254 | .base = (S5P_VA_GPIO + 0xC60), | ||
| 255 | .config = &gpio_cfg_noint, | ||
| 256 | .irq_base = IRQ_EINT(24), | ||
| 257 | .chip = { | ||
| 258 | .base = S5PV210_GPH3(0), | ||
| 259 | .ngpio = S5PV210_GPIO_H3_NR, | ||
| 260 | .label = "GPH3", | ||
| 261 | .to_irq = samsung_gpiolib_to_irq, | ||
| 262 | }, | ||
| 263 | }, | ||
| 264 | }; | ||
| 265 | |||
| 266 | static __init int s5pv210_gpiolib_init(void) | ||
| 267 | { | ||
| 268 | struct s3c_gpio_chip *chip = s5pv210_gpio_4bit; | ||
| 269 | int nr_chips = ARRAY_SIZE(s5pv210_gpio_4bit); | ||
| 270 | int gpioint_group = 0; | ||
| 271 | int i = 0; | ||
| 272 | |||
| 273 | for (i = 0; i < nr_chips; i++, chip++) { | ||
| 274 | if (chip->config == NULL) { | ||
| 275 | chip->config = &gpio_cfg; | ||
| 276 | chip->group = gpioint_group++; | ||
| 277 | } | ||
| 278 | if (chip->base == NULL) | ||
| 279 | chip->base = S5PV210_BANK_BASE(i); | ||
| 280 | } | ||
| 281 | |||
| 282 | samsung_gpiolib_add_4bit_chips(s5pv210_gpio_4bit, nr_chips); | ||
| 283 | s5p_register_gpioint_bank(IRQ_GPIOINT, 0, S5P_GPIOINT_GROUP_MAXNR); | ||
| 284 | |||
| 285 | return 0; | ||
| 286 | } | ||
| 287 | core_initcall(s5pv210_gpiolib_init); | ||
diff --git a/drivers/gpio/gpio-u300.c b/drivers/gpio/gpio-u300.c new file mode 100644 index 00000000000..53e8255cb0b --- /dev/null +++ b/drivers/gpio/gpio-u300.c | |||
| @@ -0,0 +1,697 @@ | |||
| 1 | /* | ||
| 2 | * U300 GPIO module. | ||
| 3 | * | ||
| 4 | * Copyright (C) 2007-2009 ST-Ericsson AB | ||
| 5 | * License terms: GNU General Public License (GPL) version 2 | ||
| 6 | * This can driver either of the two basic GPIO cores | ||
| 7 | * available in the U300 platforms: | ||
| 8 | * COH 901 335 - Used in DB3150 (U300 1.0) and DB3200 (U330 1.0) | ||
| 9 | * COH 901 571/3 - Used in DB3210 (U365 2.0) and DB3350 (U335 1.0) | ||
| 10 | * Notice that you also have inline macros in <asm-arch/gpio.h> | ||
| 11 | * Author: Linus Walleij <linus.walleij@stericsson.com> | ||
| 12 | * Author: Jonas Aaberg <jonas.aberg@stericsson.com> | ||
| 13 | * | ||
| 14 | */ | ||
| 15 | #include <linux/module.h> | ||
| 16 | #include <linux/interrupt.h> | ||
| 17 | #include <linux/delay.h> | ||
| 18 | #include <linux/errno.h> | ||
| 19 | #include <linux/io.h> | ||
| 20 | #include <linux/clk.h> | ||
| 21 | #include <linux/err.h> | ||
| 22 | #include <linux/platform_device.h> | ||
| 23 | #include <linux/gpio.h> | ||
| 24 | |||
| 25 | /* Reference to GPIO block clock */ | ||
| 26 | static struct clk *clk; | ||
| 27 | |||
| 28 | /* Memory resource */ | ||
| 29 | static struct resource *memres; | ||
| 30 | static void __iomem *virtbase; | ||
| 31 | static struct device *gpiodev; | ||
| 32 | |||
| 33 | struct u300_gpio_port { | ||
| 34 | const char *name; | ||
| 35 | int irq; | ||
| 36 | int number; | ||
| 37 | }; | ||
| 38 | |||
| 39 | |||
| 40 | static struct u300_gpio_port gpio_ports[] = { | ||
| 41 | { | ||
| 42 | .name = "gpio0", | ||
| 43 | .number = 0, | ||
| 44 | }, | ||
| 45 | { | ||
| 46 | .name = "gpio1", | ||
| 47 | .number = 1, | ||
| 48 | }, | ||
| 49 | { | ||
| 50 | .name = "gpio2", | ||
| 51 | .number = 2, | ||
| 52 | }, | ||
| 53 | #ifdef U300_COH901571_3 | ||
| 54 | { | ||
| 55 | .name = "gpio3", | ||
| 56 | .number = 3, | ||
| 57 | }, | ||
| 58 | { | ||
| 59 | .name = "gpio4", | ||
| 60 | .number = 4, | ||
| 61 | }, | ||
| 62 | #ifdef CONFIG_MACH_U300_BS335 | ||
| 63 | { | ||
| 64 | .name = "gpio5", | ||
| 65 | .number = 5, | ||
| 66 | }, | ||
| 67 | { | ||
| 68 | .name = "gpio6", | ||
| 69 | .number = 6, | ||
| 70 | }, | ||
| 71 | #endif | ||
| 72 | #endif | ||
| 73 | |||
| 74 | }; | ||
| 75 | |||
| 76 | |||
| 77 | #ifdef U300_COH901571_3 | ||
| 78 | |||
| 79 | /* Default input value */ | ||
| 80 | #define DEFAULT_OUTPUT_LOW 0 | ||
| 81 | #define DEFAULT_OUTPUT_HIGH 1 | ||
| 82 | |||
| 83 | /* GPIO Pull-Up status */ | ||
| 84 | #define DISABLE_PULL_UP 0 | ||
| 85 | #define ENABLE_PULL_UP 1 | ||
| 86 | |||
| 87 | #define GPIO_NOT_USED 0 | ||
| 88 | #define GPIO_IN 1 | ||
| 89 | #define GPIO_OUT 2 | ||
| 90 | |||
| 91 | struct u300_gpio_configuration_data { | ||
| 92 | unsigned char pin_usage; | ||
| 93 | unsigned char default_output_value; | ||
| 94 | unsigned char pull_up; | ||
| 95 | }; | ||
| 96 | |||
| 97 | /* Initial configuration */ | ||
| 98 | const struct u300_gpio_configuration_data | ||
| 99 | u300_gpio_config[U300_GPIO_NUM_PORTS][U300_GPIO_PINS_PER_PORT] = { | ||
| 100 | #ifdef CONFIG_MACH_U300_BS335 | ||
| 101 | /* Port 0, pins 0-7 */ | ||
| 102 | { | ||
| 103 | {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 104 | {GPIO_OUT, DEFAULT_OUTPUT_HIGH, DISABLE_PULL_UP}, | ||
| 105 | {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 106 | {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 107 | {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 108 | {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 109 | {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 110 | {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP} | ||
| 111 | }, | ||
| 112 | /* Port 1, pins 0-7 */ | ||
| 113 | { | ||
| 114 | {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 115 | {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 116 | {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 117 | {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, | ||
| 118 | {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 119 | {GPIO_OUT, DEFAULT_OUTPUT_HIGH, DISABLE_PULL_UP}, | ||
| 120 | {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 121 | {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP} | ||
| 122 | }, | ||
| 123 | /* Port 2, pins 0-7 */ | ||
| 124 | { | ||
| 125 | {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 126 | {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 127 | {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 128 | {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 129 | {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 130 | {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, | ||
| 131 | {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 132 | {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP} | ||
| 133 | }, | ||
| 134 | /* Port 3, pins 0-7 */ | ||
| 135 | { | ||
| 136 | {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, | ||
| 137 | {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 138 | {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 139 | {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 140 | {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 141 | {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 142 | {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 143 | {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP} | ||
| 144 | }, | ||
| 145 | /* Port 4, pins 0-7 */ | ||
| 146 | { | ||
| 147 | {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 148 | {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 149 | {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 150 | {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 151 | {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 152 | {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 153 | {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 154 | {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP} | ||
| 155 | }, | ||
| 156 | /* Port 5, pins 0-7 */ | ||
| 157 | { | ||
| 158 | {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 159 | {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 160 | {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 161 | {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 162 | {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 163 | {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 164 | {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 165 | {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP} | ||
| 166 | }, | ||
| 167 | /* Port 6, pind 0-7 */ | ||
| 168 | { | ||
| 169 | {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 170 | {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 171 | {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 172 | {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 173 | {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 174 | {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 175 | {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 176 | {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP} | ||
| 177 | } | ||
| 178 | #endif | ||
| 179 | |||
| 180 | #ifdef CONFIG_MACH_U300_BS365 | ||
| 181 | /* Port 0, pins 0-7 */ | ||
| 182 | { | ||
| 183 | {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 184 | {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 185 | {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 186 | {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 187 | {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 188 | {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 189 | {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, | ||
| 190 | {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP} | ||
| 191 | }, | ||
| 192 | /* Port 1, pins 0-7 */ | ||
| 193 | { | ||
| 194 | {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 195 | {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 196 | {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 197 | {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 198 | {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 199 | {GPIO_OUT, DEFAULT_OUTPUT_HIGH, DISABLE_PULL_UP}, | ||
| 200 | {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 201 | {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP} | ||
| 202 | }, | ||
| 203 | /* Port 2, pins 0-7 */ | ||
| 204 | { | ||
| 205 | {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 206 | {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, | ||
| 207 | {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 208 | {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}, | ||
| 209 | {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, | ||
| 210 | {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, | ||
| 211 | {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, | ||
| 212 | {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP} | ||
| 213 | }, | ||
| 214 | /* Port 3, pins 0-7 */ | ||
| 215 | { | ||
| 216 | {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, | ||
| 217 | {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, | ||
| 218 | {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, | ||
| 219 | {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, | ||
| 220 | {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, | ||
| 221 | {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, | ||
| 222 | {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, | ||
| 223 | {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP} | ||
| 224 | }, | ||
| 225 | /* Port 4, pins 0-7 */ | ||
| 226 | { | ||
| 227 | {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, | ||
| 228 | {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, | ||
| 229 | {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, | ||
| 230 | {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, | ||
| 231 | /* These 4 pins doesn't exist on DB3210 */ | ||
| 232 | {GPIO_OUT, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, | ||
| 233 | {GPIO_OUT, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, | ||
| 234 | {GPIO_OUT, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}, | ||
| 235 | {GPIO_OUT, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP} | ||
| 236 | } | ||
| 237 | #endif | ||
| 238 | }; | ||
| 239 | #endif | ||
| 240 | |||
| 241 | |||
| 242 | /* No users == we can power down GPIO */ | ||
| 243 | static int gpio_users; | ||
| 244 | |||
| 245 | struct gpio_struct { | ||
| 246 | int (*callback)(void *); | ||
| 247 | void *data; | ||
| 248 | int users; | ||
| 249 | }; | ||
| 250 | |||
| 251 | static struct gpio_struct gpio_pin[U300_GPIO_MAX]; | ||
| 252 | |||
| 253 | /* | ||
| 254 | * Let drivers register callback in order to get notified when there is | ||
| 255 | * an interrupt on the gpio pin | ||
| 256 | */ | ||
| 257 | int gpio_register_callback(unsigned gpio, int (*func)(void *arg), void *data) | ||
| 258 | { | ||
| 259 | if (gpio_pin[gpio].callback) | ||
| 260 | dev_warn(gpiodev, "%s: WARNING: callback already " | ||
| 261 | "registered for gpio pin#%d\n", __func__, gpio); | ||
| 262 | gpio_pin[gpio].callback = func; | ||
| 263 | gpio_pin[gpio].data = data; | ||
| 264 | |||
| 265 | return 0; | ||
| 266 | } | ||
| 267 | EXPORT_SYMBOL(gpio_register_callback); | ||
| 268 | |||
| 269 | int gpio_unregister_callback(unsigned gpio) | ||
| 270 | { | ||
| 271 | if (!gpio_pin[gpio].callback) | ||
| 272 | dev_warn(gpiodev, "%s: WARNING: callback already " | ||
| 273 | "unregistered for gpio pin#%d\n", __func__, gpio); | ||
| 274 | gpio_pin[gpio].callback = NULL; | ||
| 275 | gpio_pin[gpio].data = NULL; | ||
| 276 | |||
| 277 | return 0; | ||
| 278 | } | ||
| 279 | EXPORT_SYMBOL(gpio_unregister_callback); | ||
| 280 | |||
| 281 | /* Non-zero means valid */ | ||
| 282 | int gpio_is_valid(int number) | ||
| 283 | { | ||
| 284 | if (number >= 0 && | ||
| 285 | number < (U300_GPIO_NUM_PORTS * U300_GPIO_PINS_PER_PORT)) | ||
| 286 | return 1; | ||
| 287 | return 0; | ||
| 288 | } | ||
| 289 | EXPORT_SYMBOL(gpio_is_valid); | ||
| 290 | |||
| 291 | int gpio_request(unsigned gpio, const char *label) | ||
| 292 | { | ||
| 293 | if (gpio_pin[gpio].users) | ||
| 294 | return -EINVAL; | ||
| 295 | else | ||
| 296 | gpio_pin[gpio].users++; | ||
| 297 | |||
| 298 | gpio_users++; | ||
| 299 | |||
| 300 | return 0; | ||
| 301 | } | ||
| 302 | EXPORT_SYMBOL(gpio_request); | ||
| 303 | |||
| 304 | void gpio_free(unsigned gpio) | ||
| 305 | { | ||
| 306 | gpio_users--; | ||
| 307 | gpio_pin[gpio].users--; | ||
| 308 | if (unlikely(gpio_pin[gpio].users < 0)) { | ||
| 309 | dev_warn(gpiodev, "warning: gpio#%d release mismatch\n", | ||
| 310 | gpio); | ||
| 311 | gpio_pin[gpio].users = 0; | ||
| 312 | } | ||
| 313 | |||
| 314 | return; | ||
| 315 | } | ||
| 316 | EXPORT_SYMBOL(gpio_free); | ||
| 317 | |||
| 318 | /* This returns zero or nonzero */ | ||
| 319 | int gpio_get_value(unsigned gpio) | ||
| 320 | { | ||
| 321 | return readl(virtbase + U300_GPIO_PXPDIR + | ||
| 322 | PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING) & (1 << (gpio & 0x07)); | ||
| 323 | } | ||
| 324 | EXPORT_SYMBOL(gpio_get_value); | ||
| 325 | |||
| 326 | /* | ||
| 327 | * We hope that the compiler will optimize away the unused branch | ||
| 328 | * in case "value" is a constant | ||
| 329 | */ | ||
| 330 | void gpio_set_value(unsigned gpio, int value) | ||
| 331 | { | ||
| 332 | u32 val; | ||
| 333 | unsigned long flags; | ||
| 334 | |||
| 335 | local_irq_save(flags); | ||
| 336 | if (value) { | ||
| 337 | /* set */ | ||
| 338 | val = readl(virtbase + U300_GPIO_PXPDOR + | ||
| 339 | PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING) | ||
| 340 | & (1 << (gpio & 0x07)); | ||
| 341 | writel(val | (1 << (gpio & 0x07)), virtbase + | ||
| 342 | U300_GPIO_PXPDOR + | ||
| 343 | PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING); | ||
| 344 | } else { | ||
| 345 | /* clear */ | ||
| 346 | val = readl(virtbase + U300_GPIO_PXPDOR + | ||
| 347 | PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING) | ||
| 348 | & (1 << (gpio & 0x07)); | ||
| 349 | writel(val & ~(1 << (gpio & 0x07)), virtbase + | ||
| 350 | U300_GPIO_PXPDOR + | ||
| 351 | PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING); | ||
| 352 | } | ||
| 353 | local_irq_restore(flags); | ||
| 354 | } | ||
| 355 | EXPORT_SYMBOL(gpio_set_value); | ||
| 356 | |||
| 357 | int gpio_direction_input(unsigned gpio) | ||
| 358 | { | ||
| 359 | unsigned long flags; | ||
| 360 | u32 val; | ||
| 361 | |||
| 362 | if (gpio > U300_GPIO_MAX) | ||
| 363 | return -EINVAL; | ||
| 364 | |||
| 365 | local_irq_save(flags); | ||
| 366 | val = readl(virtbase + U300_GPIO_PXPCR + PIN_TO_PORT(gpio) * | ||
| 367 | U300_GPIO_PORTX_SPACING); | ||
| 368 | /* Mask out this pin*/ | ||
| 369 | val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK << ((gpio & 0x07) << 1)); | ||
| 370 | /* This is not needed since it sets the bits to zero.*/ | ||
| 371 | /* val |= (U300_GPIO_PXPCR_PIN_MODE_INPUT << (gpio*2)); */ | ||
| 372 | writel(val, virtbase + U300_GPIO_PXPCR + PIN_TO_PORT(gpio) * | ||
| 373 | U300_GPIO_PORTX_SPACING); | ||
| 374 | local_irq_restore(flags); | ||
| 375 | return 0; | ||
| 376 | } | ||
| 377 | EXPORT_SYMBOL(gpio_direction_input); | ||
| 378 | |||
| 379 | int gpio_direction_output(unsigned gpio, int value) | ||
| 380 | { | ||
| 381 | unsigned long flags; | ||
| 382 | u32 val; | ||
| 383 | |||
| 384 | if (gpio > U300_GPIO_MAX) | ||
| 385 | return -EINVAL; | ||
| 386 | |||
| 387 | local_irq_save(flags); | ||
| 388 | val = readl(virtbase + U300_GPIO_PXPCR + PIN_TO_PORT(gpio) * | ||
| 389 | U300_GPIO_PORTX_SPACING); | ||
| 390 | /* Mask out this pin */ | ||
| 391 | val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK << ((gpio & 0x07) << 1)); | ||
| 392 | /* | ||
| 393 | * FIXME: configure for push/pull, open drain or open source per pin | ||
| 394 | * in setup. The current driver will only support push/pull. | ||
| 395 | */ | ||
| 396 | val |= (U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL | ||
| 397 | << ((gpio & 0x07) << 1)); | ||
| 398 | writel(val, virtbase + U300_GPIO_PXPCR + PIN_TO_PORT(gpio) * | ||
| 399 | U300_GPIO_PORTX_SPACING); | ||
| 400 | gpio_set_value(gpio, value); | ||
| 401 | local_irq_restore(flags); | ||
| 402 | return 0; | ||
| 403 | } | ||
| 404 | EXPORT_SYMBOL(gpio_direction_output); | ||
| 405 | |||
| 406 | /* | ||
| 407 | * Enable an IRQ, edge is rising edge (!= 0) or falling edge (==0). | ||
| 408 | */ | ||
| 409 | void enable_irq_on_gpio_pin(unsigned gpio, int edge) | ||
| 410 | { | ||
| 411 | u32 val; | ||
| 412 | unsigned long flags; | ||
| 413 | local_irq_save(flags); | ||
| 414 | |||
| 415 | val = readl(virtbase + U300_GPIO_PXIEN + PIN_TO_PORT(gpio) * | ||
| 416 | U300_GPIO_PORTX_SPACING); | ||
| 417 | val |= (1 << (gpio & 0x07)); | ||
| 418 | writel(val, virtbase + U300_GPIO_PXIEN + PIN_TO_PORT(gpio) * | ||
| 419 | U300_GPIO_PORTX_SPACING); | ||
| 420 | val = readl(virtbase + U300_GPIO_PXICR + PIN_TO_PORT(gpio) * | ||
| 421 | U300_GPIO_PORTX_SPACING); | ||
| 422 | if (edge) | ||
| 423 | val |= (1 << (gpio & 0x07)); | ||
| 424 | else | ||
| 425 | val &= ~(1 << (gpio & 0x07)); | ||
| 426 | writel(val, virtbase + U300_GPIO_PXICR + PIN_TO_PORT(gpio) * | ||
| 427 | U300_GPIO_PORTX_SPACING); | ||
| 428 | local_irq_restore(flags); | ||
| 429 | } | ||
| 430 | EXPORT_SYMBOL(enable_irq_on_gpio_pin); | ||
| 431 | |||
| 432 | void disable_irq_on_gpio_pin(unsigned gpio) | ||
| 433 | { | ||
| 434 | u32 val; | ||
| 435 | unsigned long flags; | ||
| 436 | |||
| 437 | local_irq_save(flags); | ||
| 438 | val = readl(virtbase + U300_GPIO_PXIEN + PIN_TO_PORT(gpio) * | ||
| 439 | U300_GPIO_PORTX_SPACING); | ||
| 440 | val &= ~(1 << (gpio & 0x07)); | ||
| 441 | writel(val, virtbase + U300_GPIO_PXIEN + PIN_TO_PORT(gpio) * | ||
| 442 | U300_GPIO_PORTX_SPACING); | ||
| 443 | local_irq_restore(flags); | ||
| 444 | } | ||
| 445 | EXPORT_SYMBOL(disable_irq_on_gpio_pin); | ||
| 446 | |||
| 447 | /* Enable (value == 0) or disable (value == 1) internal pullup */ | ||
| 448 | void gpio_pullup(unsigned gpio, int value) | ||
| 449 | { | ||
| 450 | u32 val; | ||
| 451 | unsigned long flags; | ||
| 452 | |||
| 453 | local_irq_save(flags); | ||
| 454 | if (value) { | ||
| 455 | val = readl(virtbase + U300_GPIO_PXPER + PIN_TO_PORT(gpio) * | ||
| 456 | U300_GPIO_PORTX_SPACING); | ||
| 457 | writel(val | (1 << (gpio & 0x07)), virtbase + U300_GPIO_PXPER + | ||
| 458 | PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING); | ||
| 459 | } else { | ||
| 460 | val = readl(virtbase + U300_GPIO_PXPER + PIN_TO_PORT(gpio) * | ||
| 461 | U300_GPIO_PORTX_SPACING); | ||
| 462 | writel(val & ~(1 << (gpio & 0x07)), virtbase + U300_GPIO_PXPER + | ||
| 463 | PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING); | ||
| 464 | } | ||
| 465 | local_irq_restore(flags); | ||
| 466 | } | ||
| 467 | EXPORT_SYMBOL(gpio_pullup); | ||
| 468 | |||
| 469 | static irqreturn_t gpio_irq_handler(int irq, void *dev_id) | ||
| 470 | { | ||
| 471 | struct u300_gpio_port *port = dev_id; | ||
| 472 | u32 val; | ||
| 473 | int pin; | ||
| 474 | |||
| 475 | /* Read event register */ | ||
| 476 | val = readl(virtbase + U300_GPIO_PXIEV + port->number * | ||
| 477 | U300_GPIO_PORTX_SPACING); | ||
| 478 | /* Mask with enable register */ | ||
| 479 | val &= readl(virtbase + U300_GPIO_PXIEV + port->number * | ||
| 480 | U300_GPIO_PORTX_SPACING); | ||
| 481 | /* Mask relevant bits */ | ||
| 482 | val &= U300_GPIO_PXIEV_ALL_IRQ_EVENT_MASK; | ||
| 483 | /* ACK IRQ (clear event) */ | ||
| 484 | writel(val, virtbase + U300_GPIO_PXIEV + port->number * | ||
| 485 | U300_GPIO_PORTX_SPACING); | ||
| 486 | /* Print message */ | ||
| 487 | while (val != 0) { | ||
| 488 | unsigned gpio; | ||
| 489 | |||
| 490 | pin = __ffs(val); | ||
| 491 | /* mask off this pin */ | ||
| 492 | val &= ~(1 << pin); | ||
| 493 | gpio = (port->number << 3) + pin; | ||
| 494 | |||
| 495 | if (gpio_pin[gpio].callback) | ||
| 496 | (void)gpio_pin[gpio].callback(gpio_pin[gpio].data); | ||
| 497 | else | ||
| 498 | dev_dbg(gpiodev, "stray GPIO IRQ on line %d\n", | ||
| 499 | gpio); | ||
| 500 | } | ||
| 501 | return IRQ_HANDLED; | ||
| 502 | } | ||
| 503 | |||
| 504 | static void gpio_set_initial_values(void) | ||
| 505 | { | ||
| 506 | #ifdef U300_COH901571_3 | ||
| 507 | int i, j; | ||
| 508 | unsigned long flags; | ||
| 509 | u32 val; | ||
| 510 | |||
| 511 | /* Write default values to all pins */ | ||
| 512 | for (i = 0; i < U300_GPIO_NUM_PORTS; i++) { | ||
| 513 | val = 0; | ||
| 514 | for (j = 0; j < 8; j++) | ||
| 515 | val |= (u32) (u300_gpio_config[i][j].default_output_value != DEFAULT_OUTPUT_LOW) << j; | ||
| 516 | local_irq_save(flags); | ||
| 517 | writel(val, virtbase + U300_GPIO_PXPDOR + i * U300_GPIO_PORTX_SPACING); | ||
| 518 | local_irq_restore(flags); | ||
| 519 | } | ||
| 520 | |||
| 521 | /* | ||
| 522 | * Put all pins that are set to either 'GPIO_OUT' or 'GPIO_NOT_USED' | ||
| 523 | * to output and 'GPIO_IN' to input for each port. And initialize | ||
| 524 | * default value on outputs. | ||
| 525 | */ | ||
| 526 | for (i = 0; i < U300_GPIO_NUM_PORTS; i++) { | ||
| 527 | for (j = 0; j < U300_GPIO_PINS_PER_PORT; j++) { | ||
| 528 | local_irq_save(flags); | ||
| 529 | val = readl(virtbase + U300_GPIO_PXPCR + | ||
| 530 | i * U300_GPIO_PORTX_SPACING); | ||
| 531 | /* Mask out this pin */ | ||
| 532 | val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK << (j << 1)); | ||
| 533 | |||
| 534 | if (u300_gpio_config[i][j].pin_usage != GPIO_IN) | ||
| 535 | val |= (U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL << (j << 1)); | ||
| 536 | writel(val, virtbase + U300_GPIO_PXPCR + | ||
| 537 | i * U300_GPIO_PORTX_SPACING); | ||
| 538 | local_irq_restore(flags); | ||
| 539 | } | ||
| 540 | } | ||
| 541 | |||
| 542 | /* Enable or disable the internal pull-ups in the GPIO ASIC block */ | ||
| 543 | for (i = 0; i < U300_GPIO_MAX; i++) { | ||
| 544 | val = 0; | ||
| 545 | for (j = 0; j < 8; j++) | ||
| 546 | val |= (u32)((u300_gpio_config[i][j].pull_up == DISABLE_PULL_UP) << j); | ||
| 547 | local_irq_save(flags); | ||
| 548 | writel(val, virtbase + U300_GPIO_PXPER + i * U300_GPIO_PORTX_SPACING); | ||
| 549 | local_irq_restore(flags); | ||
| 550 | } | ||
| 551 | #endif | ||
| 552 | } | ||
| 553 | |||
| 554 | static int __init gpio_probe(struct platform_device *pdev) | ||
| 555 | { | ||
| 556 | u32 val; | ||
| 557 | int err = 0; | ||
| 558 | int i; | ||
| 559 | int num_irqs; | ||
| 560 | |||
| 561 | gpiodev = &pdev->dev; | ||
| 562 | memset(gpio_pin, 0, sizeof(gpio_pin)); | ||
| 563 | |||
| 564 | /* Get GPIO clock */ | ||
| 565 | clk = clk_get(&pdev->dev, NULL); | ||
| 566 | if (IS_ERR(clk)) { | ||
| 567 | err = PTR_ERR(clk); | ||
| 568 | dev_err(gpiodev, "could not get GPIO clock\n"); | ||
| 569 | goto err_no_clk; | ||
| 570 | } | ||
| 571 | err = clk_enable(clk); | ||
| 572 | if (err) { | ||
| 573 | dev_err(gpiodev, "could not enable GPIO clock\n"); | ||
| 574 | goto err_no_clk_enable; | ||
| 575 | } | ||
| 576 | |||
| 577 | memres = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 578 | if (!memres) | ||
| 579 | goto err_no_resource; | ||
| 580 | |||
| 581 | if (!request_mem_region(memres->start, resource_size(memres), | ||
| 582 | "GPIO Controller")) { | ||
| 583 | err = -ENODEV; | ||
| 584 | goto err_no_ioregion; | ||
| 585 | } | ||
| 586 | |||
| 587 | virtbase = ioremap(memres->start, resource_size(memres)); | ||
| 588 | if (!virtbase) { | ||
| 589 | err = -ENOMEM; | ||
| 590 | goto err_no_ioremap; | ||
| 591 | } | ||
| 592 | dev_info(gpiodev, "remapped 0x%08x to %p\n", | ||
| 593 | memres->start, virtbase); | ||
| 594 | |||
| 595 | #ifdef U300_COH901335 | ||
| 596 | dev_info(gpiodev, "initializing GPIO Controller COH 901 335\n"); | ||
| 597 | /* Turn on the GPIO block */ | ||
| 598 | writel(U300_GPIO_CR_BLOCK_CLOCK_ENABLE, virtbase + U300_GPIO_CR); | ||
| 599 | #endif | ||
| 600 | |||
| 601 | #ifdef U300_COH901571_3 | ||
| 602 | dev_info(gpiodev, "initializing GPIO Controller COH 901 571/3\n"); | ||
| 603 | val = readl(virtbase + U300_GPIO_CR); | ||
| 604 | dev_info(gpiodev, "COH901571/3 block version: %d, " \ | ||
| 605 | "number of cores: %d\n", | ||
| 606 | ((val & 0x0000FE00) >> 9), | ||
| 607 | ((val & 0x000001FC) >> 2)); | ||
| 608 | writel(U300_GPIO_CR_BLOCK_CLKRQ_ENABLE, virtbase + U300_GPIO_CR); | ||
| 609 | #endif | ||
| 610 | |||
| 611 | gpio_set_initial_values(); | ||
| 612 | |||
| 613 | for (num_irqs = 0 ; num_irqs < U300_GPIO_NUM_PORTS; num_irqs++) { | ||
| 614 | |||
| 615 | gpio_ports[num_irqs].irq = | ||
| 616 | platform_get_irq_byname(pdev, | ||
| 617 | gpio_ports[num_irqs].name); | ||
| 618 | |||
| 619 | err = request_irq(gpio_ports[num_irqs].irq, | ||
| 620 | gpio_irq_handler, IRQF_DISABLED, | ||
| 621 | gpio_ports[num_irqs].name, | ||
| 622 | &gpio_ports[num_irqs]); | ||
| 623 | if (err) { | ||
| 624 | dev_err(gpiodev, "cannot allocate IRQ for %s!\n", | ||
| 625 | gpio_ports[num_irqs].name); | ||
| 626 | goto err_no_irq; | ||
| 627 | } | ||
| 628 | /* Turns off PortX_irq_force */ | ||
| 629 | writel(0x0, virtbase + U300_GPIO_PXIFR + | ||
| 630 | num_irqs * U300_GPIO_PORTX_SPACING); | ||
| 631 | } | ||
| 632 | |||
| 633 | return 0; | ||
| 634 | |||
| 635 | err_no_irq: | ||
| 636 | for (i = 0; i < num_irqs; i++) | ||
| 637 | free_irq(gpio_ports[i].irq, &gpio_ports[i]); | ||
| 638 | iounmap(virtbase); | ||
| 639 | err_no_ioremap: | ||
| 640 | release_mem_region(memres->start, resource_size(memres)); | ||
| 641 | err_no_ioregion: | ||
| 642 | err_no_resource: | ||
| 643 | clk_disable(clk); | ||
| 644 | err_no_clk_enable: | ||
| 645 | clk_put(clk); | ||
| 646 | err_no_clk: | ||
| 647 | dev_info(gpiodev, "module ERROR:%d\n", err); | ||
| 648 | return err; | ||
| 649 | } | ||
| 650 | |||
| 651 | static int __exit gpio_remove(struct platform_device *pdev) | ||
| 652 | { | ||
| 653 | int i; | ||
| 654 | |||
| 655 | /* Turn off the GPIO block */ | ||
| 656 | writel(0x00000000U, virtbase + U300_GPIO_CR); | ||
| 657 | for (i = 0 ; i < U300_GPIO_NUM_PORTS; i++) | ||
| 658 | free_irq(gpio_ports[i].irq, &gpio_ports[i]); | ||
| 659 | iounmap(virtbase); | ||
| 660 | release_mem_region(memres->start, resource_size(memres)); | ||
| 661 | clk_disable(clk); | ||
| 662 | clk_put(clk); | ||
| 663 | return 0; | ||
| 664 | } | ||
| 665 | |||
| 666 | static struct platform_driver gpio_driver = { | ||
| 667 | .driver = { | ||
| 668 | .name = "u300-gpio", | ||
| 669 | }, | ||
| 670 | .remove = __exit_p(gpio_remove), | ||
| 671 | }; | ||
| 672 | |||
| 673 | |||
| 674 | static int __init u300_gpio_init(void) | ||
| 675 | { | ||
| 676 | return platform_driver_probe(&gpio_driver, gpio_probe); | ||
| 677 | } | ||
| 678 | |||
| 679 | static void __exit u300_gpio_exit(void) | ||
| 680 | { | ||
| 681 | platform_driver_unregister(&gpio_driver); | ||
| 682 | } | ||
| 683 | |||
| 684 | arch_initcall(u300_gpio_init); | ||
| 685 | module_exit(u300_gpio_exit); | ||
| 686 | |||
| 687 | MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>"); | ||
| 688 | |||
| 689 | #ifdef U300_COH901571_3 | ||
| 690 | MODULE_DESCRIPTION("ST-Ericsson AB COH 901 571/3 GPIO driver"); | ||
| 691 | #endif | ||
| 692 | |||
| 693 | #ifdef U300_COH901335 | ||
| 694 | MODULE_DESCRIPTION("ST-Ericsson AB COH 901 335 GPIO driver"); | ||
| 695 | #endif | ||
| 696 | |||
| 697 | MODULE_LICENSE("GPL"); | ||
