1e4b736f1SMark Brown /* 2c103de24SGrant Likely * gpiolib support for Wolfson WM831x PMICs 3e4b736f1SMark Brown * 4e4b736f1SMark Brown * Copyright 2009 Wolfson Microelectronics PLC. 5e4b736f1SMark Brown * 6e4b736f1SMark Brown * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> 7e4b736f1SMark Brown * 8e4b736f1SMark Brown * This program is free software; you can redistribute it and/or modify it 9e4b736f1SMark Brown * under the terms of the GNU General Public License as published by the 10e4b736f1SMark Brown * Free Software Foundation; either version 2 of the License, or (at your 11e4b736f1SMark Brown * option) any later version. 12e4b736f1SMark Brown * 13e4b736f1SMark Brown */ 14e4b736f1SMark Brown 15e4b736f1SMark Brown #include <linux/kernel.h> 165a0e3ad6STejun Heo #include <linux/slab.h> 17e4b736f1SMark Brown #include <linux/module.h> 18e4b736f1SMark Brown #include <linux/gpio.h> 19e4b736f1SMark Brown #include <linux/mfd/core.h> 20e4b736f1SMark Brown #include <linux/platform_device.h> 21e4b736f1SMark Brown #include <linux/seq_file.h> 22e4b736f1SMark Brown 23e4b736f1SMark Brown #include <linux/mfd/wm831x/core.h> 24e4b736f1SMark Brown #include <linux/mfd/wm831x/pdata.h> 25e4b736f1SMark Brown #include <linux/mfd/wm831x/gpio.h> 26dc0fb25cSMark Brown #include <linux/mfd/wm831x/irq.h> 27e4b736f1SMark Brown 28e4b736f1SMark Brown struct wm831x_gpio { 29e4b736f1SMark Brown struct wm831x *wm831x; 30e4b736f1SMark Brown struct gpio_chip gpio_chip; 31e4b736f1SMark Brown }; 32e4b736f1SMark Brown 33e4b736f1SMark Brown static inline struct wm831x_gpio *to_wm831x_gpio(struct gpio_chip *chip) 34e4b736f1SMark Brown { 35e4b736f1SMark Brown return container_of(chip, struct wm831x_gpio, gpio_chip); 36e4b736f1SMark Brown } 37e4b736f1SMark Brown 38e4b736f1SMark Brown static int wm831x_gpio_direction_in(struct gpio_chip *chip, unsigned offset) 39e4b736f1SMark Brown { 40e4b736f1SMark Brown struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip); 41e4b736f1SMark Brown struct wm831x *wm831x = wm831x_gpio->wm831x; 42f92e8f81SMark Brown int val = WM831X_GPN_DIR; 43f92e8f81SMark Brown 44f92e8f81SMark Brown if (wm831x->has_gpio_ena) 45f92e8f81SMark Brown val |= WM831X_GPN_TRI; 46e4b736f1SMark Brown 47e4b736f1SMark Brown return wm831x_set_bits(wm831x, WM831X_GPIO1_CONTROL + offset, 481bca748cSMark Brown WM831X_GPN_DIR | WM831X_GPN_TRI | 491bca748cSMark Brown WM831X_GPN_FN_MASK, val); 50e4b736f1SMark Brown } 51e4b736f1SMark Brown 52e4b736f1SMark Brown static int wm831x_gpio_get(struct gpio_chip *chip, unsigned offset) 53e4b736f1SMark Brown { 54e4b736f1SMark Brown struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip); 55e4b736f1SMark Brown struct wm831x *wm831x = wm831x_gpio->wm831x; 56e4b736f1SMark Brown int ret; 57e4b736f1SMark Brown 58e4b736f1SMark Brown ret = wm831x_reg_read(wm831x, WM831X_GPIO_LEVEL); 59e4b736f1SMark Brown if (ret < 0) 60e4b736f1SMark Brown return ret; 61e4b736f1SMark Brown 62e4b736f1SMark Brown if (ret & 1 << offset) 63e4b736f1SMark Brown return 1; 64e4b736f1SMark Brown else 65e4b736f1SMark Brown return 0; 66e4b736f1SMark Brown } 67e4b736f1SMark Brown 68e4b736f1SMark Brown static void wm831x_gpio_set(struct gpio_chip *chip, unsigned offset, int value) 69e4b736f1SMark Brown { 70e4b736f1SMark Brown struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip); 71e4b736f1SMark Brown struct wm831x *wm831x = wm831x_gpio->wm831x; 72e4b736f1SMark Brown 73e4b736f1SMark Brown wm831x_set_bits(wm831x, WM831X_GPIO_LEVEL, 1 << offset, 74e4b736f1SMark Brown value << offset); 75e4b736f1SMark Brown } 76e4b736f1SMark Brown 773383d23dSMark Brown static int wm831x_gpio_direction_out(struct gpio_chip *chip, 783383d23dSMark Brown unsigned offset, int value) 793383d23dSMark Brown { 803383d23dSMark Brown struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip); 813383d23dSMark Brown struct wm831x *wm831x = wm831x_gpio->wm831x; 82f92e8f81SMark Brown int val = 0; 833383d23dSMark Brown int ret; 843383d23dSMark Brown 85f92e8f81SMark Brown if (wm831x->has_gpio_ena) 86f92e8f81SMark Brown val |= WM831X_GPN_TRI; 87f92e8f81SMark Brown 883383d23dSMark Brown ret = wm831x_set_bits(wm831x, WM831X_GPIO1_CONTROL + offset, 891bca748cSMark Brown WM831X_GPN_DIR | WM831X_GPN_TRI | 901bca748cSMark Brown WM831X_GPN_FN_MASK, val); 913383d23dSMark Brown if (ret < 0) 923383d23dSMark Brown return ret; 933383d23dSMark Brown 943383d23dSMark Brown /* Can only set GPIO state once it's in output mode */ 953383d23dSMark Brown wm831x_gpio_set(chip, offset, value); 963383d23dSMark Brown 973383d23dSMark Brown return 0; 983383d23dSMark Brown } 993383d23dSMark Brown 100dc0fb25cSMark Brown static int wm831x_gpio_to_irq(struct gpio_chip *chip, unsigned offset) 101dc0fb25cSMark Brown { 102dc0fb25cSMark Brown struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip); 103dc0fb25cSMark Brown struct wm831x *wm831x = wm831x_gpio->wm831x; 104dc0fb25cSMark Brown 105cd99758bSMark Brown return irq_create_mapping(wm831x->irq_domain, 106cd99758bSMark Brown WM831X_IRQ_GPIO_1 + offset); 107dc0fb25cSMark Brown } 108dc0fb25cSMark Brown 109b12c35e2SMark Brown static int wm831x_gpio_set_debounce(struct gpio_chip *chip, unsigned offset, 110b12c35e2SMark Brown unsigned debounce) 111b12c35e2SMark Brown { 112b12c35e2SMark Brown struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip); 113b12c35e2SMark Brown struct wm831x *wm831x = wm831x_gpio->wm831x; 114b12c35e2SMark Brown int reg = WM831X_GPIO1_CONTROL + offset; 115b12c35e2SMark Brown int ret, fn; 116b12c35e2SMark Brown 117b12c35e2SMark Brown ret = wm831x_reg_read(wm831x, reg); 118b12c35e2SMark Brown if (ret < 0) 119b12c35e2SMark Brown return ret; 120b12c35e2SMark Brown 121b12c35e2SMark Brown switch (ret & WM831X_GPN_FN_MASK) { 122b12c35e2SMark Brown case 0: 123b12c35e2SMark Brown case 1: 124b12c35e2SMark Brown break; 125b12c35e2SMark Brown default: 126b12c35e2SMark Brown /* Not in GPIO mode */ 127b12c35e2SMark Brown return -EBUSY; 128b12c35e2SMark Brown } 129b12c35e2SMark Brown 130b12c35e2SMark Brown if (debounce >= 32 && debounce <= 64) 131b12c35e2SMark Brown fn = 0; 132b12c35e2SMark Brown else if (debounce >= 4000 && debounce <= 8000) 133b12c35e2SMark Brown fn = 1; 134b12c35e2SMark Brown else 135b12c35e2SMark Brown return -EINVAL; 136b12c35e2SMark Brown 137b12c35e2SMark Brown return wm831x_set_bits(wm831x, reg, WM831X_GPN_FN_MASK, fn); 138b12c35e2SMark Brown } 139b12c35e2SMark Brown 140e4b736f1SMark Brown #ifdef CONFIG_DEBUG_FS 141e4b736f1SMark Brown static void wm831x_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) 142e4b736f1SMark Brown { 143e4b736f1SMark Brown struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip); 144e4b736f1SMark Brown struct wm831x *wm831x = wm831x_gpio->wm831x; 145f92e8f81SMark Brown int i, tristated; 146e4b736f1SMark Brown 147e4b736f1SMark Brown for (i = 0; i < chip->ngpio; i++) { 148e4b736f1SMark Brown int gpio = i + chip->base; 149e4b736f1SMark Brown int reg; 150e4b736f1SMark Brown const char *label, *pull, *powerdomain; 151e4b736f1SMark Brown 152e4b736f1SMark Brown /* We report the GPIO even if it's not requested since 153e4b736f1SMark Brown * we're also reporting things like alternate 154e4b736f1SMark Brown * functions which apply even when the GPIO is not in 155e4b736f1SMark Brown * use as a GPIO. 156e4b736f1SMark Brown */ 157e4b736f1SMark Brown label = gpiochip_is_requested(chip, i); 158e4b736f1SMark Brown if (!label) 159e4b736f1SMark Brown label = "Unrequested"; 160e4b736f1SMark Brown 161e4b736f1SMark Brown seq_printf(s, " gpio-%-3d (%-20.20s) ", gpio, label); 162e4b736f1SMark Brown 163e4b736f1SMark Brown reg = wm831x_reg_read(wm831x, WM831X_GPIO1_CONTROL + i); 164e4b736f1SMark Brown if (reg < 0) { 165e4b736f1SMark Brown dev_err(wm831x->dev, 166e4b736f1SMark Brown "GPIO control %d read failed: %d\n", 167e4b736f1SMark Brown gpio, reg); 168e4b736f1SMark Brown seq_printf(s, "\n"); 169e4b736f1SMark Brown continue; 170e4b736f1SMark Brown } 171e4b736f1SMark Brown 172e4b736f1SMark Brown switch (reg & WM831X_GPN_PULL_MASK) { 173e4b736f1SMark Brown case WM831X_GPIO_PULL_NONE: 174e4b736f1SMark Brown pull = "nopull"; 175e4b736f1SMark Brown break; 176e4b736f1SMark Brown case WM831X_GPIO_PULL_DOWN: 177e4b736f1SMark Brown pull = "pulldown"; 178e4b736f1SMark Brown break; 179e4b736f1SMark Brown case WM831X_GPIO_PULL_UP: 180e4b736f1SMark Brown pull = "pullup"; 181164d5c39SAxel Lin break; 182e4b736f1SMark Brown default: 183e4b736f1SMark Brown pull = "INVALID PULL"; 184e4b736f1SMark Brown break; 185e4b736f1SMark Brown } 186e4b736f1SMark Brown 187e4b736f1SMark Brown switch (i + 1) { 188e4b736f1SMark Brown case 1 ... 3: 189e4b736f1SMark Brown case 7 ... 9: 190e4b736f1SMark Brown if (reg & WM831X_GPN_PWR_DOM) 191e4b736f1SMark Brown powerdomain = "VPMIC"; 192e4b736f1SMark Brown else 193e4b736f1SMark Brown powerdomain = "DBVDD"; 194e4b736f1SMark Brown break; 195e4b736f1SMark Brown 196e4b736f1SMark Brown case 4 ... 6: 197e4b736f1SMark Brown case 10 ... 12: 198e4b736f1SMark Brown if (reg & WM831X_GPN_PWR_DOM) 199e4b736f1SMark Brown powerdomain = "SYSVDD"; 200e4b736f1SMark Brown else 201e4b736f1SMark Brown powerdomain = "DBVDD"; 202e4b736f1SMark Brown break; 203e4b736f1SMark Brown 204e4b736f1SMark Brown case 13 ... 16: 205e4b736f1SMark Brown powerdomain = "TPVDD"; 206e4b736f1SMark Brown break; 207e4b736f1SMark Brown 208e4b736f1SMark Brown default: 209e4b736f1SMark Brown BUG(); 210e4b736f1SMark Brown break; 211e4b736f1SMark Brown } 212e4b736f1SMark Brown 213f92e8f81SMark Brown tristated = reg & WM831X_GPN_TRI; 214f92e8f81SMark Brown if (wm831x->has_gpio_ena) 215f92e8f81SMark Brown tristated = !tristated; 216f92e8f81SMark Brown 217e4b736f1SMark Brown seq_printf(s, " %s %s %s %s%s\n" 218e4b736f1SMark Brown " %s%s (0x%4x)\n", 219e4b736f1SMark Brown reg & WM831X_GPN_DIR ? "in" : "out", 220e4b736f1SMark Brown wm831x_gpio_get(chip, i) ? "high" : "low", 221e4b736f1SMark Brown pull, 222e4b736f1SMark Brown powerdomain, 2236b8274faSMark Brown reg & WM831X_GPN_POL ? "" : " inverted", 224e4b736f1SMark Brown reg & WM831X_GPN_OD ? "open-drain" : "CMOS", 225f92e8f81SMark Brown tristated ? " tristated" : "", 226e4b736f1SMark Brown reg); 227e4b736f1SMark Brown } 228e4b736f1SMark Brown } 229e4b736f1SMark Brown #else 230e4b736f1SMark Brown #define wm831x_gpio_dbg_show NULL 231e4b736f1SMark Brown #endif 232e4b736f1SMark Brown 233e4b736f1SMark Brown static struct gpio_chip template_chip = { 234e4b736f1SMark Brown .label = "wm831x", 235e4b736f1SMark Brown .owner = THIS_MODULE, 236e4b736f1SMark Brown .direction_input = wm831x_gpio_direction_in, 237e4b736f1SMark Brown .get = wm831x_gpio_get, 238e4b736f1SMark Brown .direction_output = wm831x_gpio_direction_out, 239e4b736f1SMark Brown .set = wm831x_gpio_set, 240dc0fb25cSMark Brown .to_irq = wm831x_gpio_to_irq, 241b12c35e2SMark Brown .set_debounce = wm831x_gpio_set_debounce, 242e4b736f1SMark Brown .dbg_show = wm831x_gpio_dbg_show, 243e4b736f1SMark Brown .can_sleep = 1, 244e4b736f1SMark Brown }; 245e4b736f1SMark Brown 246e4b736f1SMark Brown static int __devinit wm831x_gpio_probe(struct platform_device *pdev) 247e4b736f1SMark Brown { 248e4b736f1SMark Brown struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); 249e4b736f1SMark Brown struct wm831x_pdata *pdata = wm831x->dev->platform_data; 250e4b736f1SMark Brown struct wm831x_gpio *wm831x_gpio; 251e4b736f1SMark Brown int ret; 252e4b736f1SMark Brown 253*718bc6e3SAxel Lin wm831x_gpio = devm_kzalloc(&pdev->dev, sizeof(*wm831x_gpio), 254*718bc6e3SAxel Lin GFP_KERNEL); 255e4b736f1SMark Brown if (wm831x_gpio == NULL) 256e4b736f1SMark Brown return -ENOMEM; 257e4b736f1SMark Brown 258e4b736f1SMark Brown wm831x_gpio->wm831x = wm831x; 259e4b736f1SMark Brown wm831x_gpio->gpio_chip = template_chip; 2606f2ecaaeSMark Brown wm831x_gpio->gpio_chip.ngpio = wm831x->num_gpio; 261e4b736f1SMark Brown wm831x_gpio->gpio_chip.dev = &pdev->dev; 262e4b736f1SMark Brown if (pdata && pdata->gpio_base) 263e4b736f1SMark Brown wm831x_gpio->gpio_chip.base = pdata->gpio_base; 264e4b736f1SMark Brown else 265e4b736f1SMark Brown wm831x_gpio->gpio_chip.base = -1; 266e4b736f1SMark Brown 267e4b736f1SMark Brown ret = gpiochip_add(&wm831x_gpio->gpio_chip); 268e4b736f1SMark Brown if (ret < 0) { 269*718bc6e3SAxel Lin dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret); 270*718bc6e3SAxel Lin return ret; 271e4b736f1SMark Brown } 272e4b736f1SMark Brown 273e4b736f1SMark Brown platform_set_drvdata(pdev, wm831x_gpio); 274e4b736f1SMark Brown 275e4b736f1SMark Brown return ret; 276e4b736f1SMark Brown } 277e4b736f1SMark Brown 278e4b736f1SMark Brown static int __devexit wm831x_gpio_remove(struct platform_device *pdev) 279e4b736f1SMark Brown { 280e4b736f1SMark Brown struct wm831x_gpio *wm831x_gpio = platform_get_drvdata(pdev); 281e4b736f1SMark Brown 282*718bc6e3SAxel Lin return gpiochip_remove(&wm831x_gpio->gpio_chip); 283e4b736f1SMark Brown } 284e4b736f1SMark Brown 285e4b736f1SMark Brown static struct platform_driver wm831x_gpio_driver = { 286e4b736f1SMark Brown .driver.name = "wm831x-gpio", 287e4b736f1SMark Brown .driver.owner = THIS_MODULE, 288e4b736f1SMark Brown .probe = wm831x_gpio_probe, 289e4b736f1SMark Brown .remove = __devexit_p(wm831x_gpio_remove), 290e4b736f1SMark Brown }; 291e4b736f1SMark Brown 292e4b736f1SMark Brown static int __init wm831x_gpio_init(void) 293e4b736f1SMark Brown { 294e4b736f1SMark Brown return platform_driver_register(&wm831x_gpio_driver); 295e4b736f1SMark Brown } 296e4b736f1SMark Brown subsys_initcall(wm831x_gpio_init); 297e4b736f1SMark Brown 298e4b736f1SMark Brown static void __exit wm831x_gpio_exit(void) 299e4b736f1SMark Brown { 300e4b736f1SMark Brown platform_driver_unregister(&wm831x_gpio_driver); 301e4b736f1SMark Brown } 302e4b736f1SMark Brown module_exit(wm831x_gpio_exit); 303e4b736f1SMark Brown 304e4b736f1SMark Brown MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); 305e4b736f1SMark Brown MODULE_DESCRIPTION("GPIO interface for WM831x PMICs"); 306e4b736f1SMark Brown MODULE_LICENSE("GPL"); 307e4b736f1SMark Brown MODULE_ALIAS("platform:wm831x-gpio"); 308