1 /* 2 * Copyright (C) ST-Ericsson SA 2010 3 * 4 * License Terms: GNU General Public License, version 2 5 * Author: Hanumath Prasad <hanumath.prasad@stericsson.com> for ST-Ericsson 6 * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson 7 */ 8 9 #include <linux/module.h> 10 #include <linux/init.h> 11 #include <linux/platform_device.h> 12 #include <linux/slab.h> 13 #include <linux/gpio.h> 14 #include <linux/irq.h> 15 #include <linux/interrupt.h> 16 #include <linux/mfd/tc3589x.h> 17 18 /* 19 * These registers are modified under the irq bus lock and cached to avoid 20 * unnecessary writes in bus_sync_unlock. 21 */ 22 enum { REG_IBE, REG_IEV, REG_IS, REG_IE }; 23 24 #define CACHE_NR_REGS 4 25 #define CACHE_NR_BANKS 3 26 27 struct tc3589x_gpio { 28 struct gpio_chip chip; 29 struct tc3589x *tc3589x; 30 struct device *dev; 31 struct mutex irq_lock; 32 33 int irq_base; 34 35 /* Caches of interrupt control registers for bus_lock */ 36 u8 regs[CACHE_NR_REGS][CACHE_NR_BANKS]; 37 u8 oldregs[CACHE_NR_REGS][CACHE_NR_BANKS]; 38 }; 39 40 static inline struct tc3589x_gpio *to_tc3589x_gpio(struct gpio_chip *chip) 41 { 42 return container_of(chip, struct tc3589x_gpio, chip); 43 } 44 45 static int tc3589x_gpio_get(struct gpio_chip *chip, unsigned offset) 46 { 47 struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip); 48 struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; 49 u8 reg = TC3589x_GPIODATA0 + (offset / 8) * 2; 50 u8 mask = 1 << (offset % 8); 51 int ret; 52 53 ret = tc3589x_reg_read(tc3589x, reg); 54 if (ret < 0) 55 return ret; 56 57 return ret & mask; 58 } 59 60 static void tc3589x_gpio_set(struct gpio_chip *chip, unsigned offset, int val) 61 { 62 struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip); 63 struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; 64 u8 reg = TC3589x_GPIODATA0 + (offset / 8) * 2; 65 unsigned pos = offset % 8; 66 u8 data[] = {!!val << pos, 1 << pos}; 67 68 tc3589x_block_write(tc3589x, reg, ARRAY_SIZE(data), data); 69 } 70 71 static int tc3589x_gpio_direction_output(struct gpio_chip *chip, 72 unsigned offset, int val) 73 { 74 struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip); 75 struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; 76 u8 reg = TC3589x_GPIODIR0 + offset / 8; 77 unsigned pos = offset % 8; 78 79 tc3589x_gpio_set(chip, offset, val); 80 81 return tc3589x_set_bits(tc3589x, reg, 1 << pos, 1 << pos); 82 } 83 84 static int tc3589x_gpio_direction_input(struct gpio_chip *chip, 85 unsigned offset) 86 { 87 struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip); 88 struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; 89 u8 reg = TC3589x_GPIODIR0 + offset / 8; 90 unsigned pos = offset % 8; 91 92 return tc3589x_set_bits(tc3589x, reg, 1 << pos, 0); 93 } 94 95 static int tc3589x_gpio_to_irq(struct gpio_chip *chip, unsigned offset) 96 { 97 struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip); 98 99 return tc3589x_gpio->irq_base + offset; 100 } 101 102 static struct gpio_chip template_chip = { 103 .label = "tc3589x", 104 .owner = THIS_MODULE, 105 .direction_input = tc3589x_gpio_direction_input, 106 .get = tc3589x_gpio_get, 107 .direction_output = tc3589x_gpio_direction_output, 108 .set = tc3589x_gpio_set, 109 .to_irq = tc3589x_gpio_to_irq, 110 .can_sleep = 1, 111 }; 112 113 static int tc3589x_gpio_irq_set_type(struct irq_data *d, unsigned int type) 114 { 115 struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d); 116 int offset = d->irq - tc3589x_gpio->irq_base; 117 int regoffset = offset / 8; 118 int mask = 1 << (offset % 8); 119 120 if (type == IRQ_TYPE_EDGE_BOTH) { 121 tc3589x_gpio->regs[REG_IBE][regoffset] |= mask; 122 return 0; 123 } 124 125 tc3589x_gpio->regs[REG_IBE][regoffset] &= ~mask; 126 127 if (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_LEVEL_HIGH) 128 tc3589x_gpio->regs[REG_IS][regoffset] |= mask; 129 else 130 tc3589x_gpio->regs[REG_IS][regoffset] &= ~mask; 131 132 if (type == IRQ_TYPE_EDGE_RISING || type == IRQ_TYPE_LEVEL_HIGH) 133 tc3589x_gpio->regs[REG_IEV][regoffset] |= mask; 134 else 135 tc3589x_gpio->regs[REG_IEV][regoffset] &= ~mask; 136 137 return 0; 138 } 139 140 static void tc3589x_gpio_irq_lock(struct irq_data *d) 141 { 142 struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d); 143 144 mutex_lock(&tc3589x_gpio->irq_lock); 145 } 146 147 static void tc3589x_gpio_irq_sync_unlock(struct irq_data *d) 148 { 149 struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d); 150 struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; 151 static const u8 regmap[] = { 152 [REG_IBE] = TC3589x_GPIOIBE0, 153 [REG_IEV] = TC3589x_GPIOIEV0, 154 [REG_IS] = TC3589x_GPIOIS0, 155 [REG_IE] = TC3589x_GPIOIE0, 156 }; 157 int i, j; 158 159 for (i = 0; i < CACHE_NR_REGS; i++) { 160 for (j = 0; j < CACHE_NR_BANKS; j++) { 161 u8 old = tc3589x_gpio->oldregs[i][j]; 162 u8 new = tc3589x_gpio->regs[i][j]; 163 164 if (new == old) 165 continue; 166 167 tc3589x_gpio->oldregs[i][j] = new; 168 tc3589x_reg_write(tc3589x, regmap[i] + j * 8, new); 169 } 170 } 171 172 mutex_unlock(&tc3589x_gpio->irq_lock); 173 } 174 175 static void tc3589x_gpio_irq_mask(struct irq_data *d) 176 { 177 struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d); 178 int offset = d->irq - tc3589x_gpio->irq_base; 179 int regoffset = offset / 8; 180 int mask = 1 << (offset % 8); 181 182 tc3589x_gpio->regs[REG_IE][regoffset] &= ~mask; 183 } 184 185 static void tc3589x_gpio_irq_unmask(struct irq_data *d) 186 { 187 struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d); 188 int offset = d->irq - tc3589x_gpio->irq_base; 189 int regoffset = offset / 8; 190 int mask = 1 << (offset % 8); 191 192 tc3589x_gpio->regs[REG_IE][regoffset] |= mask; 193 } 194 195 static struct irq_chip tc3589x_gpio_irq_chip = { 196 .name = "tc3589x-gpio", 197 .irq_bus_lock = tc3589x_gpio_irq_lock, 198 .irq_bus_sync_unlock = tc3589x_gpio_irq_sync_unlock, 199 .irq_mask = tc3589x_gpio_irq_mask, 200 .irq_unmask = tc3589x_gpio_irq_unmask, 201 .irq_set_type = tc3589x_gpio_irq_set_type, 202 }; 203 204 static irqreturn_t tc3589x_gpio_irq(int irq, void *dev) 205 { 206 struct tc3589x_gpio *tc3589x_gpio = dev; 207 struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; 208 u8 status[CACHE_NR_BANKS]; 209 int ret; 210 int i; 211 212 ret = tc3589x_block_read(tc3589x, TC3589x_GPIOMIS0, 213 ARRAY_SIZE(status), status); 214 if (ret < 0) 215 return IRQ_NONE; 216 217 for (i = 0; i < ARRAY_SIZE(status); i++) { 218 unsigned int stat = status[i]; 219 if (!stat) 220 continue; 221 222 while (stat) { 223 int bit = __ffs(stat); 224 int line = i * 8 + bit; 225 226 handle_nested_irq(tc3589x_gpio->irq_base + line); 227 stat &= ~(1 << bit); 228 } 229 230 tc3589x_reg_write(tc3589x, TC3589x_GPIOIC0 + i, status[i]); 231 } 232 233 return IRQ_HANDLED; 234 } 235 236 static int tc3589x_gpio_irq_init(struct tc3589x_gpio *tc3589x_gpio) 237 { 238 int base = tc3589x_gpio->irq_base; 239 int irq; 240 241 for (irq = base; irq < base + tc3589x_gpio->chip.ngpio; irq++) { 242 irq_set_chip_data(irq, tc3589x_gpio); 243 irq_set_chip_and_handler(irq, &tc3589x_gpio_irq_chip, 244 handle_simple_irq); 245 irq_set_nested_thread(irq, 1); 246 #ifdef CONFIG_ARM 247 set_irq_flags(irq, IRQF_VALID); 248 #else 249 irq_set_noprobe(irq); 250 #endif 251 } 252 253 return 0; 254 } 255 256 static void tc3589x_gpio_irq_remove(struct tc3589x_gpio *tc3589x_gpio) 257 { 258 int base = tc3589x_gpio->irq_base; 259 int irq; 260 261 for (irq = base; irq < base + tc3589x_gpio->chip.ngpio; irq++) { 262 #ifdef CONFIG_ARM 263 set_irq_flags(irq, 0); 264 #endif 265 irq_set_chip_and_handler(irq, NULL, NULL); 266 irq_set_chip_data(irq, NULL); 267 } 268 } 269 270 static int __devinit tc3589x_gpio_probe(struct platform_device *pdev) 271 { 272 struct tc3589x *tc3589x = dev_get_drvdata(pdev->dev.parent); 273 struct tc3589x_gpio_platform_data *pdata; 274 struct tc3589x_gpio *tc3589x_gpio; 275 int ret; 276 int irq; 277 278 pdata = tc3589x->pdata->gpio; 279 if (!pdata) 280 return -ENODEV; 281 282 irq = platform_get_irq(pdev, 0); 283 if (irq < 0) 284 return irq; 285 286 tc3589x_gpio = kzalloc(sizeof(struct tc3589x_gpio), GFP_KERNEL); 287 if (!tc3589x_gpio) 288 return -ENOMEM; 289 290 mutex_init(&tc3589x_gpio->irq_lock); 291 292 tc3589x_gpio->dev = &pdev->dev; 293 tc3589x_gpio->tc3589x = tc3589x; 294 295 tc3589x_gpio->chip = template_chip; 296 tc3589x_gpio->chip.ngpio = tc3589x->num_gpio; 297 tc3589x_gpio->chip.dev = &pdev->dev; 298 tc3589x_gpio->chip.base = pdata->gpio_base; 299 300 tc3589x_gpio->irq_base = tc3589x->irq_base + TC3589x_INT_GPIO(0); 301 302 /* Bring the GPIO module out of reset */ 303 ret = tc3589x_set_bits(tc3589x, TC3589x_RSTCTRL, 304 TC3589x_RSTCTRL_GPIRST, 0); 305 if (ret < 0) 306 goto out_free; 307 308 ret = tc3589x_gpio_irq_init(tc3589x_gpio); 309 if (ret) 310 goto out_free; 311 312 ret = request_threaded_irq(irq, NULL, tc3589x_gpio_irq, IRQF_ONESHOT, 313 "tc3589x-gpio", tc3589x_gpio); 314 if (ret) { 315 dev_err(&pdev->dev, "unable to get irq: %d\n", ret); 316 goto out_removeirq; 317 } 318 319 ret = gpiochip_add(&tc3589x_gpio->chip); 320 if (ret) { 321 dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret); 322 goto out_freeirq; 323 } 324 325 if (pdata->setup) 326 pdata->setup(tc3589x, tc3589x_gpio->chip.base); 327 328 platform_set_drvdata(pdev, tc3589x_gpio); 329 330 return 0; 331 332 out_freeirq: 333 free_irq(irq, tc3589x_gpio); 334 out_removeirq: 335 tc3589x_gpio_irq_remove(tc3589x_gpio); 336 out_free: 337 kfree(tc3589x_gpio); 338 return ret; 339 } 340 341 static int __devexit tc3589x_gpio_remove(struct platform_device *pdev) 342 { 343 struct tc3589x_gpio *tc3589x_gpio = platform_get_drvdata(pdev); 344 struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; 345 struct tc3589x_gpio_platform_data *pdata = tc3589x->pdata->gpio; 346 int irq = platform_get_irq(pdev, 0); 347 int ret; 348 349 if (pdata->remove) 350 pdata->remove(tc3589x, tc3589x_gpio->chip.base); 351 352 ret = gpiochip_remove(&tc3589x_gpio->chip); 353 if (ret < 0) { 354 dev_err(tc3589x_gpio->dev, 355 "unable to remove gpiochip: %d\n", ret); 356 return ret; 357 } 358 359 free_irq(irq, tc3589x_gpio); 360 tc3589x_gpio_irq_remove(tc3589x_gpio); 361 362 platform_set_drvdata(pdev, NULL); 363 kfree(tc3589x_gpio); 364 365 return 0; 366 } 367 368 static struct platform_driver tc3589x_gpio_driver = { 369 .driver.name = "tc3589x-gpio", 370 .driver.owner = THIS_MODULE, 371 .probe = tc3589x_gpio_probe, 372 .remove = __devexit_p(tc3589x_gpio_remove), 373 }; 374 375 static int __init tc3589x_gpio_init(void) 376 { 377 return platform_driver_register(&tc3589x_gpio_driver); 378 } 379 subsys_initcall(tc3589x_gpio_init); 380 381 static void __exit tc3589x_gpio_exit(void) 382 { 383 platform_driver_unregister(&tc3589x_gpio_driver); 384 } 385 module_exit(tc3589x_gpio_exit); 386 387 MODULE_LICENSE("GPL v2"); 388 MODULE_DESCRIPTION("TC3589x GPIO driver"); 389 MODULE_AUTHOR("Hanumath Prasad, Rabin Vincent"); 390