1/* 2 * arch/arm/plat-s5pc100/gpiolib.c 3 * 4 * Copyright 2009 Samsung Electronics Co 5 * Kyungmin Park <kyungmin.park@samsung.com> 6 * 7 * S5PC100 - GPIOlib support 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 14#include <linux/kernel.h> 15#include <linux/irq.h> 16#include <linux/io.h> 17#include <linux/gpio.h> 18 19#include <mach/map.h> 20#include <mach/regs-gpio.h> 21 22#include <plat/gpio-core.h> 23#include <plat/gpio-cfg.h> 24#include <plat/gpio-cfg-helpers.h> 25 26/* S5PC100 GPIO bank summary: 27 * 28 * Bank GPIOs Style INT Type 29 * A0 8 4Bit GPIO_INT0 30 * A1 5 4Bit GPIO_INT1 31 * B 8 4Bit GPIO_INT2 32 * C 5 4Bit GPIO_INT3 33 * D 7 4Bit GPIO_INT4 34 * E0 8 4Bit GPIO_INT5 35 * E1 6 4Bit GPIO_INT6 36 * F0 8 4Bit GPIO_INT7 37 * F1 8 4Bit GPIO_INT8 38 * F2 8 4Bit GPIO_INT9 39 * F3 4 4Bit GPIO_INT10 40 * G0 8 4Bit GPIO_INT11 41 * G1 3 4Bit GPIO_INT12 42 * G2 7 4Bit GPIO_INT13 43 * G3 7 4Bit GPIO_INT14 44 * H0 8 4Bit WKUP_INT 45 * H1 8 4Bit WKUP_INT 46 * H2 8 4Bit WKUP_INT 47 * H3 8 4Bit WKUP_INT 48 * I 8 4Bit GPIO_INT15 49 * J0 8 4Bit GPIO_INT16 50 * J1 5 4Bit GPIO_INT17 51 * J2 8 4Bit GPIO_INT18 52 * J3 8 4Bit GPIO_INT19 53 * J4 4 4Bit GPIO_INT20 54 * K0 8 4Bit None 55 * K1 6 4Bit None 56 * K2 8 4Bit None 57 * K3 8 4Bit None 58 * L0 8 4Bit None 59 * L1 8 4Bit None 60 * L2 8 4Bit None 61 * L3 8 4Bit None 62 */ 63 64static int s5pc100_gpiolib_to_irq(struct gpio_chip *chip, unsigned int offset) 65{ 66 return S3C_IRQ_GPIO(chip->base + offset); 67} 68 69static int s5pc100_gpiolib_to_eint(struct gpio_chip *chip, unsigned int offset) 70{ 71 int base; 72 73 base = chip->base - S5PC100_GPH0(0); 74 if (base == 0) 75 return IRQ_EINT(offset); 76 base = chip->base - S5PC100_GPH1(0); 77 if (base == 0) 78 return IRQ_EINT(8 + offset); 79 base = chip->base - S5PC100_GPH2(0); 80 if (base == 0) 81 return IRQ_EINT(16 + offset); 82 base = chip->base - S5PC100_GPH3(0); 83 if (base == 0) 84 return IRQ_EINT(24 + offset); 85 return -EINVAL; 86} 87 88static struct s3c_gpio_cfg gpio_cfg = { 89 .set_config = s3c_gpio_setcfg_s3c64xx_4bit, 90 .set_pull = s3c_gpio_setpull_updown, 91 .get_pull = s3c_gpio_getpull_updown, 92}; 93 94static struct s3c_gpio_cfg gpio_cfg_eint = { 95 .cfg_eint = 0xf, 96 .set_config = s3c_gpio_setcfg_s3c64xx_4bit, 97 .set_pull = s3c_gpio_setpull_updown, 98 .get_pull = s3c_gpio_getpull_updown, 99}; 100 101static struct s3c_gpio_cfg gpio_cfg_noint = { 102 .set_config = s3c_gpio_setcfg_s3c64xx_4bit, 103 .set_pull = s3c_gpio_setpull_updown, 104 .get_pull = s3c_gpio_getpull_updown, 105}; 106 107static struct s3c_gpio_chip s5pc100_gpio_chips[] = { 108 { 109 .base = S5PC100_GPA0_BASE, 110 .config = &gpio_cfg, 111 .chip = { 112 .base = S5PC100_GPA0(0), 113 .ngpio = S5PC100_GPIO_A0_NR, 114 .label = "GPA0", 115 }, 116 }, { 117 .base = S5PC100_GPA1_BASE, 118 .config = &gpio_cfg, 119 .chip = { 120 .base = S5PC100_GPA1(0), 121 .ngpio = S5PC100_GPIO_A1_NR, 122 .label = "GPA1", 123 }, 124 }, { 125 .base = S5PC100_GPB_BASE, 126 .config = &gpio_cfg, 127 .chip = { 128 .base = S5PC100_GPB(0), 129 .ngpio = S5PC100_GPIO_B_NR, 130 .label = "GPB", 131 }, 132 }, { 133 .base = S5PC100_GPC_BASE, 134 .config = &gpio_cfg, 135 .chip = { 136 .base = S5PC100_GPC(0), 137 .ngpio = S5PC100_GPIO_C_NR, 138 .label = "GPC", 139 }, 140 }, { 141 .base = S5PC100_GPD_BASE, 142 .config = &gpio_cfg, 143 .chip = { 144 .base = S5PC100_GPD(0), 145 .ngpio = S5PC100_GPIO_D_NR, 146 .label = "GPD", 147 }, 148 }, { 149 .base = S5PC100_GPE0_BASE, 150 .config = &gpio_cfg, 151 .chip = { 152 .base = S5PC100_GPE0(0), 153 .ngpio = S5PC100_GPIO_E0_NR, 154 .label = "GPE0", 155 }, 156 }, { 157 .base = S5PC100_GPE1_BASE, 158 .config = &gpio_cfg, 159 .chip = { 160 .base = S5PC100_GPE1(0), 161 .ngpio = S5PC100_GPIO_E1_NR, 162 .label = "GPE1", 163 }, 164 }, { 165 .base = S5PC100_GPF0_BASE, 166 .config = &gpio_cfg, 167 .chip = { 168 .base = S5PC100_GPF0(0), 169 .ngpio = S5PC100_GPIO_F0_NR, 170 .label = "GPF0", 171 }, 172 }, { 173 .base = S5PC100_GPF1_BASE, 174 .config = &gpio_cfg, 175 .chip = { 176 .base = S5PC100_GPF1(0), 177 .ngpio = S5PC100_GPIO_F1_NR, 178 .label = "GPF1", 179 }, 180 }, { 181 .base = S5PC100_GPF2_BASE, 182 .config = &gpio_cfg, 183 .chip = { 184 .base = S5PC100_GPF2(0), 185 .ngpio = S5PC100_GPIO_F2_NR, 186 .label = "GPF2", 187 }, 188 }, { 189 .base = S5PC100_GPF3_BASE, 190 .config = &gpio_cfg, 191 .chip = { 192 .base = S5PC100_GPF3(0), 193 .ngpio = S5PC100_GPIO_F3_NR, 194 .label = "GPF3", 195 }, 196 }, { 197 .base = S5PC100_GPG0_BASE, 198 .config = &gpio_cfg, 199 .chip = { 200 .base = S5PC100_GPG0(0), 201 .ngpio = S5PC100_GPIO_G0_NR, 202 .label = "GPG0", 203 }, 204 }, { 205 .base = S5PC100_GPG1_BASE, 206 .config = &gpio_cfg, 207 .chip = { 208 .base = S5PC100_GPG1(0), 209 .ngpio = S5PC100_GPIO_G1_NR, 210 .label = "GPG1", 211 }, 212 }, { 213 .base = S5PC100_GPG2_BASE, 214 .config = &gpio_cfg, 215 .chip = { 216 .base = S5PC100_GPG2(0), 217 .ngpio = S5PC100_GPIO_G2_NR, 218 .label = "GPG2", 219 }, 220 }, { 221 .base = S5PC100_GPG3_BASE, 222 .config = &gpio_cfg, 223 .chip = { 224 .base = S5PC100_GPG3(0), 225 .ngpio = S5PC100_GPIO_G3_NR, 226 .label = "GPG3", 227 }, 228 }, { 229 .base = S5PC100_GPH0_BASE, 230 .config = &gpio_cfg_eint, 231 .chip = { 232 .base = S5PC100_GPH0(0), 233 .ngpio = S5PC100_GPIO_H0_NR, 234 .label = "GPH0", 235 }, 236 }, { 237 .base = S5PC100_GPH1_BASE, 238 .config = &gpio_cfg_eint, 239 .chip = { 240 .base = S5PC100_GPH1(0), 241 .ngpio = S5PC100_GPIO_H1_NR, 242 .label = "GPH1", 243 }, 244 }, { 245 .base = S5PC100_GPH2_BASE, 246 .config = &gpio_cfg_eint, 247 .chip = { 248 .base = S5PC100_GPH2(0), 249 .ngpio = S5PC100_GPIO_H2_NR, 250 .label = "GPH2", 251 }, 252 }, { 253 .base = S5PC100_GPH3_BASE, 254 .config = &gpio_cfg_eint, 255 .chip = { 256 .base = S5PC100_GPH3(0), 257 .ngpio = S5PC100_GPIO_H3_NR, 258 .label = "GPH3", 259 }, 260 }, { 261 .base = S5PC100_GPI_BASE, 262 .config = &gpio_cfg, 263 .chip = { 264 .base = S5PC100_GPI(0), 265 .ngpio = S5PC100_GPIO_I_NR, 266 .label = "GPI", 267 }, 268 }, { 269 .base = S5PC100_GPJ0_BASE, 270 .config = &gpio_cfg, 271 .chip = { 272 .base = S5PC100_GPJ0(0), 273 .ngpio = S5PC100_GPIO_J0_NR, 274 .label = "GPJ0", 275 }, 276 }, { 277 .base = S5PC100_GPJ1_BASE, 278 .config = &gpio_cfg, 279 .chip = { 280 .base = S5PC100_GPJ1(0), 281 .ngpio = S5PC100_GPIO_J1_NR, 282 .label = "GPJ1", 283 }, 284 }, { 285 .base = S5PC100_GPJ2_BASE, 286 .config = &gpio_cfg, 287 .chip = { 288 .base = S5PC100_GPJ2(0), 289 .ngpio = S5PC100_GPIO_J2_NR, 290 .label = "GPJ2", 291 }, 292 }, { 293 .base = S5PC100_GPJ3_BASE, 294 .config = &gpio_cfg, 295 .chip = { 296 .base = S5PC100_GPJ3(0), 297 .ngpio = S5PC100_GPIO_J3_NR, 298 .label = "GPJ3", 299 }, 300 }, { 301 .base = S5PC100_GPJ4_BASE, 302 .config = &gpio_cfg, 303 .chip = { 304 .base = S5PC100_GPJ4(0), 305 .ngpio = S5PC100_GPIO_J4_NR, 306 .label = "GPJ4", 307 }, 308 }, { 309 .base = S5PC100_GPK0_BASE, 310 .config = &gpio_cfg_noint, 311 .chip = { 312 .base = S5PC100_GPK0(0), 313 .ngpio = S5PC100_GPIO_K0_NR, 314 .label = "GPK0", 315 }, 316 }, { 317 .base = S5PC100_GPK1_BASE, 318 .config = &gpio_cfg_noint, 319 .chip = { 320 .base = S5PC100_GPK1(0), 321 .ngpio = S5PC100_GPIO_K1_NR, 322 .label = "GPK1", 323 }, 324 }, { 325 .base = S5PC100_GPK2_BASE, 326 .config = &gpio_cfg_noint, 327 .chip = { 328 .base = S5PC100_GPK2(0), 329 .ngpio = S5PC100_GPIO_K2_NR, 330 .label = "GPK2", 331 }, 332 }, { 333 .base = S5PC100_GPK3_BASE, 334 .config = &gpio_cfg_noint, 335 .chip = { 336 .base = S5PC100_GPK3(0), 337 .ngpio = S5PC100_GPIO_K3_NR, 338 .label = "GPK3", 339 }, 340 }, { 341 .base = S5PC100_GPL0_BASE, 342 .config = &gpio_cfg_noint, 343 .chip = { 344 .base = S5PC100_GPL0(0), 345 .ngpio = S5PC100_GPIO_L0_NR, 346 .label = "GPL0", 347 }, 348 }, { 349 .base = S5PC100_GPL1_BASE, 350 .config = &gpio_cfg_noint, 351 .chip = { 352 .base = S5PC100_GPL1(0), 353 .ngpio = S5PC100_GPIO_L1_NR, 354 .label = "GPL1", 355 }, 356 }, { 357 .base = S5PC100_GPL2_BASE, 358 .config = &gpio_cfg_noint, 359 .chip = { 360 .base = S5PC100_GPL2(0), 361 .ngpio = S5PC100_GPIO_L2_NR, 362 .label = "GPL2", 363 }, 364 }, { 365 .base = S5PC100_GPL3_BASE, 366 .config = &gpio_cfg_noint, 367 .chip = { 368 .base = S5PC100_GPL3(0), 369 .ngpio = S5PC100_GPIO_L3_NR, 370 .label = "GPL3", 371 }, 372 }, { 373 .base = S5PC100_GPL4_BASE, 374 .config = &gpio_cfg_noint, 375 .chip = { 376 .base = S5PC100_GPL4(0), 377 .ngpio = S5PC100_GPIO_L4_NR, 378 .label = "GPL4", 379 }, 380 }, 381}; 382 383extern struct irq_chip s5pc100_gpioint; 384extern void s5pc100_irq_gpioint_handler(unsigned int irq, struct irq_desc *desc); 385 386static __init void s5pc100_gpiolib_link(struct s3c_gpio_chip *chip) 387{ 388 /* Interrupt */ 389 if (chip->config == &gpio_cfg) { 390 int i, irq; 391 392 chip->chip.to_irq = s5pc100_gpiolib_to_irq; 393 394 for (i = 0; i < chip->chip.ngpio; i++) { 395 irq = S3C_IRQ_GPIO_BASE + chip->chip.base + i; 396 set_irq_chip(irq, &s5pc100_gpioint); 397 set_irq_data(irq, &chip->chip); 398 set_irq_handler(irq, handle_level_irq); 399 set_irq_flags(irq, IRQF_VALID); 400 } 401 } else if (chip->config == &gpio_cfg_eint) { 402 chip->chip.to_irq = s5pc100_gpiolib_to_eint; 403 } 404} 405 406static __init int s5pc100_gpiolib_init(void) 407{ 408 struct s3c_gpio_chip *chip; 409 int nr_chips; 410 411 chip = s5pc100_gpio_chips; 412 nr_chips = ARRAY_SIZE(s5pc100_gpio_chips); 413 414 for (; nr_chips > 0; nr_chips--, chip++) 415 s5pc100_gpiolib_link(chip); 416 417 samsung_gpiolib_add_4bit_chips(s5pc100_gpio_chips, 418 ARRAY_SIZE(s5pc100_gpio_chips)); 419 420 /* Interrupt */ 421 set_irq_chained_handler(IRQ_GPIOINT, s5pc100_irq_gpioint_handler); 422 423 return 0; 424} 425core_initcall(s5pc100_gpiolib_init); 426