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/tc35892.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 */ 22enum { REG_IBE, REG_IEV, REG_IS, REG_IE }; 23 24#define CACHE_NR_REGS 4 25#define CACHE_NR_BANKS 3 26 27struct tc35892_gpio { 28 struct gpio_chip chip; 29 struct tc35892 *tc35892; 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 40static inline struct tc35892_gpio *to_tc35892_gpio(struct gpio_chip *chip) 41{ 42 return container_of(chip, struct tc35892_gpio, chip); 43} 44 45static int tc35892_gpio_get(struct gpio_chip *chip, unsigned offset) 46{ 47 struct tc35892_gpio *tc35892_gpio = to_tc35892_gpio(chip); 48 struct tc35892 *tc35892 = tc35892_gpio->tc35892; 49 u8 reg = TC35892_GPIODATA0 + (offset / 8) * 2; 50 u8 mask = 1 << (offset % 8); 51 int ret; 52 53 ret = tc35892_reg_read(tc35892, reg); 54 if (ret < 0) 55 return ret; 56 57 return ret & mask; 58} 59 60static void tc35892_gpio_set(struct gpio_chip *chip, unsigned offset, int val) 61{ 62 struct tc35892_gpio *tc35892_gpio = to_tc35892_gpio(chip); 63 struct tc35892 *tc35892 = tc35892_gpio->tc35892; 64 u8 reg = TC35892_GPIODATA0 + (offset / 8) * 2; 65 unsigned pos = offset % 8; 66 u8 data[] = {!!val << pos, 1 << pos}; 67 68 tc35892_block_write(tc35892, reg, ARRAY_SIZE(data), data); 69} 70 71static int tc35892_gpio_direction_output(struct gpio_chip *chip, 72 unsigned offset, int val) 73{ 74 struct tc35892_gpio *tc35892_gpio = to_tc35892_gpio(chip); 75 struct tc35892 *tc35892 = tc35892_gpio->tc35892; 76 u8 reg = TC35892_GPIODIR0 + offset / 8; 77 unsigned pos = offset % 8; 78 79 tc35892_gpio_set(chip, offset, val); 80 81 return tc35892_set_bits(tc35892, reg, 1 << pos, 1 << pos); 82} 83 84static int tc35892_gpio_direction_input(struct gpio_chip *chip, 85 unsigned offset) 86{ 87 struct tc35892_gpio *tc35892_gpio = to_tc35892_gpio(chip); 88 struct tc35892 *tc35892 = tc35892_gpio->tc35892; 89 u8 reg = TC35892_GPIODIR0 + offset / 8; 90 unsigned pos = offset % 8; 91 92 return tc35892_set_bits(tc35892, reg, 1 << pos, 0); 93} 94 95static int tc35892_gpio_to_irq(struct gpio_chip *chip, unsigned offset) 96{ 97 struct tc35892_gpio *tc35892_gpio = to_tc35892_gpio(chip); 98 99 return tc35892_gpio->irq_base + offset; 100} 101 102static struct gpio_chip template_chip = { 103 .label = "tc35892", 104 .owner = THIS_MODULE, 105 .direction_input = tc35892_gpio_direction_input, 106 .get = tc35892_gpio_get, 107 .direction_output = tc35892_gpio_direction_output, 108 .set = tc35892_gpio_set, 109 .to_irq = tc35892_gpio_to_irq, 110 .can_sleep = 1, 111}; 112 113static int tc35892_gpio_irq_set_type(unsigned int irq, unsigned int type) 114{ 115 struct tc35892_gpio *tc35892_gpio = get_irq_chip_data(irq); 116 int offset = irq - tc35892_gpio->irq_base; 117 int regoffset = offset / 8; 118 int mask = 1 << (offset % 8); 119 120 if (type == IRQ_TYPE_EDGE_BOTH) { 121 tc35892_gpio->regs[REG_IBE][regoffset] |= mask; 122 return 0; 123 } 124 125 tc35892_gpio->regs[REG_IBE][regoffset] &= ~mask; 126 127 if (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_LEVEL_HIGH) 128 tc35892_gpio->regs[REG_IS][regoffset] |= mask; 129 else 130 tc35892_gpio->regs[REG_IS][regoffset] &= ~mask; 131 132 if (type == IRQ_TYPE_EDGE_RISING || type == IRQ_TYPE_LEVEL_HIGH) 133 tc35892_gpio->regs[REG_IEV][regoffset] |= mask; 134 else 135 tc35892_gpio->regs[REG_IEV][regoffset] &= ~mask; 136 137 return 0; 138} 139 140static void tc35892_gpio_irq_lock(unsigned int irq) 141{ 142 struct tc35892_gpio *tc35892_gpio = get_irq_chip_data(irq); 143 144 mutex_lock(&tc35892_gpio->irq_lock); 145} 146 147static void tc35892_gpio_irq_sync_unlock(unsigned int irq) 148{ 149 struct tc35892_gpio *tc35892_gpio = get_irq_chip_data(irq); 150 struct tc35892 *tc35892 = tc35892_gpio->tc35892; 151 static const u8 regmap[] = { 152 [REG_IBE] = TC35892_GPIOIBE0, 153 [REG_IEV] = TC35892_GPIOIEV0, 154 [REG_IS] = TC35892_GPIOIS0, 155 [REG_IE] = TC35892_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 = tc35892_gpio->oldregs[i][j]; 162 u8 new = tc35892_gpio->regs[i][j]; 163 164 if (new == old) 165 continue; 166 167 tc35892_gpio->oldregs[i][j] = new; 168 tc35892_reg_write(tc35892, regmap[i] + j * 8, new); 169 } 170 } 171 172 mutex_unlock(&tc35892_gpio->irq_lock); 173} 174 175static void tc35892_gpio_irq_mask(unsigned int irq) 176{ 177 struct tc35892_gpio *tc35892_gpio = get_irq_chip_data(irq); 178 int offset = irq - tc35892_gpio->irq_base; 179 int regoffset = offset / 8; 180 int mask = 1 << (offset % 8); 181 182 tc35892_gpio->regs[REG_IE][regoffset] &= ~mask; 183} 184 185static void tc35892_gpio_irq_unmask(unsigned int irq) 186{ 187 struct tc35892_gpio *tc35892_gpio = get_irq_chip_data(irq); 188 int offset = irq - tc35892_gpio->irq_base; 189 int regoffset = offset / 8; 190 int mask = 1 << (offset % 8); 191 192 tc35892_gpio->regs[REG_IE][regoffset] |= mask; 193} 194 195static struct irq_chip tc35892_gpio_irq_chip = { 196 .name = "tc35892-gpio", 197 .bus_lock = tc35892_gpio_irq_lock, 198 .bus_sync_unlock = tc35892_gpio_irq_sync_unlock, 199 .mask = tc35892_gpio_irq_mask, 200 .unmask = tc35892_gpio_irq_unmask, 201 .set_type = tc35892_gpio_irq_set_type, 202}; 203 204static irqreturn_t tc35892_gpio_irq(int irq, void *dev) 205{ 206 struct tc35892_gpio *tc35892_gpio = dev; 207 struct tc35892 *tc35892 = tc35892_gpio->tc35892; 208 u8 status[CACHE_NR_BANKS]; 209 int ret; 210 int i; 211 212 ret = tc35892_block_read(tc35892, TC35892_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(tc35892_gpio->irq_base + line); 227 stat &= ~(1 << bit); 228 } 229 230 tc35892_reg_write(tc35892, TC35892_GPIOIC0 + i, status[i]); 231 } 232 233 return IRQ_HANDLED; 234} 235 236static int tc35892_gpio_irq_init(struct tc35892_gpio *tc35892_gpio) 237{ 238 int base = tc35892_gpio->irq_base; 239 int irq; 240 241 for (irq = base; irq < base + tc35892_gpio->chip.ngpio; irq++) { 242 set_irq_chip_data(irq, tc35892_gpio); 243 set_irq_chip_and_handler(irq, &tc35892_gpio_irq_chip, 244 handle_simple_irq); 245 set_irq_nested_thread(irq, 1); 246#ifdef CONFIG_ARM 247 set_irq_flags(irq, IRQF_VALID); 248#else 249 set_irq_noprobe(irq); 250#endif 251 } 252 253 return 0; 254} 255 256static void tc35892_gpio_irq_remove(struct tc35892_gpio *tc35892_gpio) 257{ 258 int base = tc35892_gpio->irq_base; 259 int irq; 260 261 for (irq = base; irq < base + tc35892_gpio->chip.ngpio; irq++) { 262#ifdef CONFIG_ARM 263 set_irq_flags(irq, 0); 264#endif 265 set_irq_chip_and_handler(irq, NULL, NULL); 266 set_irq_chip_data(irq, NULL); 267 } 268} 269 270static int __devinit tc35892_gpio_probe(struct platform_device *pdev) 271{ 272 struct tc35892 *tc35892 = dev_get_drvdata(pdev->dev.parent); 273 struct tc35892_gpio_platform_data *pdata; 274 struct tc35892_gpio *tc35892_gpio; 275 int ret; 276 int irq; 277 278 pdata = tc35892->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 tc35892_gpio = kzalloc(sizeof(struct tc35892_gpio), GFP_KERNEL); 287 if (!tc35892_gpio) 288 return -ENOMEM; 289 290 mutex_init(&tc35892_gpio->irq_lock); 291 292 tc35892_gpio->dev = &pdev->dev; 293 tc35892_gpio->tc35892 = tc35892; 294 295 tc35892_gpio->chip = template_chip; 296 tc35892_gpio->chip.ngpio = tc35892->num_gpio; 297 tc35892_gpio->chip.dev = &pdev->dev; 298 tc35892_gpio->chip.base = pdata->gpio_base; 299 300 tc35892_gpio->irq_base = tc35892->irq_base + TC35892_INT_GPIO(0); 301 302 /* Bring the GPIO module out of reset */ 303 ret = tc35892_set_bits(tc35892, TC35892_RSTCTRL, 304 TC35892_RSTCTRL_GPIRST, 0); 305 if (ret < 0) 306 goto out_free; 307 308 ret = tc35892_gpio_irq_init(tc35892_gpio); 309 if (ret) 310 goto out_free; 311 312 ret = request_threaded_irq(irq, NULL, tc35892_gpio_irq, IRQF_ONESHOT, 313 "tc35892-gpio", tc35892_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(&tc35892_gpio->chip); 320 if (ret) { 321 dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret); 322 goto out_freeirq; 323 } 324 325 platform_set_drvdata(pdev, tc35892_gpio); 326 327 return 0; 328 329out_freeirq: 330 free_irq(irq, tc35892_gpio); 331out_removeirq: 332 tc35892_gpio_irq_remove(tc35892_gpio); 333out_free: 334 kfree(tc35892_gpio); 335 return ret; 336} 337 338static int __devexit tc35892_gpio_remove(struct platform_device *pdev) 339{ 340 struct tc35892_gpio *tc35892_gpio = platform_get_drvdata(pdev); 341 int irq = platform_get_irq(pdev, 0); 342 int ret; 343 344 ret = gpiochip_remove(&tc35892_gpio->chip); 345 if (ret < 0) { 346 dev_err(tc35892_gpio->dev, 347 "unable to remove gpiochip: %d\n", ret); 348 return ret; 349 } 350 351 free_irq(irq, tc35892_gpio); 352 tc35892_gpio_irq_remove(tc35892_gpio); 353 354 platform_set_drvdata(pdev, NULL); 355 kfree(tc35892_gpio); 356 357 return 0; 358} 359 360static struct platform_driver tc35892_gpio_driver = { 361 .driver.name = "tc35892-gpio", 362 .driver.owner = THIS_MODULE, 363 .probe = tc35892_gpio_probe, 364 .remove = __devexit_p(tc35892_gpio_remove), 365}; 366 367static int __init tc35892_gpio_init(void) 368{ 369 return platform_driver_register(&tc35892_gpio_driver); 370} 371subsys_initcall(tc35892_gpio_init); 372 373static void __exit tc35892_gpio_exit(void) 374{ 375 platform_driver_unregister(&tc35892_gpio_driver); 376} 377module_exit(tc35892_gpio_exit); 378 379MODULE_LICENSE("GPL v2"); 380MODULE_DESCRIPTION("TC35892 GPIO driver"); 381MODULE_AUTHOR("Hanumath Prasad, Rabin Vincent"); 382