1c103de24SGrant Likely /* 2c103de24SGrant Likely * gpiolib support for Wolfson WM8994 3c103de24SGrant Likely * 4c103de24SGrant Likely * Copyright 2009 Wolfson Microelectronics PLC. 5c103de24SGrant Likely * 6c103de24SGrant Likely * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> 7c103de24SGrant Likely * 8c103de24SGrant Likely * This program is free software; you can redistribute it and/or modify it 9c103de24SGrant Likely * under the terms of the GNU General Public License as published by the 10c103de24SGrant Likely * Free Software Foundation; either version 2 of the License, or (at your 11c103de24SGrant Likely * option) any later version. 12c103de24SGrant Likely * 13c103de24SGrant Likely */ 14c103de24SGrant Likely 15c103de24SGrant Likely #include <linux/kernel.h> 16c103de24SGrant Likely #include <linux/slab.h> 17c103de24SGrant Likely #include <linux/module.h> 18*10833c4bSLinus Walleij #include <linux/gpio/driver.h> 19c103de24SGrant Likely #include <linux/mfd/core.h> 20c103de24SGrant Likely #include <linux/platform_device.h> 21c103de24SGrant Likely #include <linux/seq_file.h> 22224a1f90SMark Brown #include <linux/regmap.h> 23c103de24SGrant Likely 24c103de24SGrant Likely #include <linux/mfd/wm8994/core.h> 25c103de24SGrant Likely #include <linux/mfd/wm8994/pdata.h> 26c103de24SGrant Likely #include <linux/mfd/wm8994/gpio.h> 27c103de24SGrant Likely #include <linux/mfd/wm8994/registers.h> 28c103de24SGrant Likely 29c103de24SGrant Likely struct wm8994_gpio { 30c103de24SGrant Likely struct wm8994 *wm8994; 31c103de24SGrant Likely struct gpio_chip gpio_chip; 32c103de24SGrant Likely }; 33c103de24SGrant Likely 34c103de24SGrant Likely static int wm8994_gpio_request(struct gpio_chip *chip, unsigned offset) 35c103de24SGrant Likely { 36765aa587SLinus Walleij struct wm8994_gpio *wm8994_gpio = gpiochip_get_data(chip); 37c103de24SGrant Likely struct wm8994 *wm8994 = wm8994_gpio->wm8994; 38c103de24SGrant Likely 39c103de24SGrant Likely switch (wm8994->type) { 40c103de24SGrant Likely case WM8958: 41c103de24SGrant Likely switch (offset) { 42c103de24SGrant Likely case 1: 43c103de24SGrant Likely case 2: 44c103de24SGrant Likely case 3: 45c103de24SGrant Likely case 4: 46c103de24SGrant Likely case 6: 47c103de24SGrant Likely return -EINVAL; 48c103de24SGrant Likely } 49c103de24SGrant Likely break; 50c103de24SGrant Likely default: 51c103de24SGrant Likely break; 52c103de24SGrant Likely } 53c103de24SGrant Likely 54c103de24SGrant Likely return 0; 55c103de24SGrant Likely } 56c103de24SGrant Likely 57c103de24SGrant Likely static int wm8994_gpio_direction_in(struct gpio_chip *chip, unsigned offset) 58c103de24SGrant Likely { 59765aa587SLinus Walleij struct wm8994_gpio *wm8994_gpio = gpiochip_get_data(chip); 60c103de24SGrant Likely struct wm8994 *wm8994 = wm8994_gpio->wm8994; 61c103de24SGrant Likely 62c103de24SGrant Likely return wm8994_set_bits(wm8994, WM8994_GPIO_1 + offset, 63c103de24SGrant Likely WM8994_GPN_DIR, WM8994_GPN_DIR); 64c103de24SGrant Likely } 65c103de24SGrant Likely 66c103de24SGrant Likely static int wm8994_gpio_get(struct gpio_chip *chip, unsigned offset) 67c103de24SGrant Likely { 68765aa587SLinus Walleij struct wm8994_gpio *wm8994_gpio = gpiochip_get_data(chip); 69c103de24SGrant Likely struct wm8994 *wm8994 = wm8994_gpio->wm8994; 70c103de24SGrant Likely int ret; 71c103de24SGrant Likely 72c103de24SGrant Likely ret = wm8994_reg_read(wm8994, WM8994_GPIO_1 + offset); 73c103de24SGrant Likely if (ret < 0) 74c103de24SGrant Likely return ret; 75c103de24SGrant Likely 76c103de24SGrant Likely if (ret & WM8994_GPN_LVL) 77c103de24SGrant Likely return 1; 78c103de24SGrant Likely else 79c103de24SGrant Likely return 0; 80c103de24SGrant Likely } 81c103de24SGrant Likely 82c103de24SGrant Likely static int wm8994_gpio_direction_out(struct gpio_chip *chip, 83c103de24SGrant Likely unsigned offset, int value) 84c103de24SGrant Likely { 85765aa587SLinus Walleij struct wm8994_gpio *wm8994_gpio = gpiochip_get_data(chip); 86c103de24SGrant Likely struct wm8994 *wm8994 = wm8994_gpio->wm8994; 87c103de24SGrant Likely 888cd578b6SMark Brown if (value) 898cd578b6SMark Brown value = WM8994_GPN_LVL; 908cd578b6SMark Brown 91c103de24SGrant Likely return wm8994_set_bits(wm8994, WM8994_GPIO_1 + offset, 928cd578b6SMark Brown WM8994_GPN_DIR | WM8994_GPN_LVL, value); 93c103de24SGrant Likely } 94c103de24SGrant Likely 95c103de24SGrant Likely static void wm8994_gpio_set(struct gpio_chip *chip, unsigned offset, int value) 96c103de24SGrant Likely { 97765aa587SLinus Walleij struct wm8994_gpio *wm8994_gpio = gpiochip_get_data(chip); 98c103de24SGrant Likely struct wm8994 *wm8994 = wm8994_gpio->wm8994; 99c103de24SGrant Likely 100c103de24SGrant Likely if (value) 101c103de24SGrant Likely value = WM8994_GPN_LVL; 102c103de24SGrant Likely 103c103de24SGrant Likely wm8994_set_bits(wm8994, WM8994_GPIO_1 + offset, WM8994_GPN_LVL, value); 104c103de24SGrant Likely } 105c103de24SGrant Likely 1062956b5d9SMika Westerberg static int wm8994_gpio_set_config(struct gpio_chip *chip, unsigned int offset, 1072956b5d9SMika Westerberg unsigned long config) 108190ea434SLinus Walleij { 109190ea434SLinus Walleij struct wm8994_gpio *wm8994_gpio = gpiochip_get_data(chip); 110190ea434SLinus Walleij struct wm8994 *wm8994 = wm8994_gpio->wm8994; 111190ea434SLinus Walleij 1122956b5d9SMika Westerberg switch (pinconf_to_config_param(config)) { 1132956b5d9SMika Westerberg case PIN_CONFIG_DRIVE_OPEN_DRAIN: 114190ea434SLinus Walleij return wm8994_set_bits(wm8994, WM8994_GPIO_1 + offset, 115190ea434SLinus Walleij WM8994_GPN_OP_CFG_MASK, 116190ea434SLinus Walleij WM8994_GPN_OP_CFG); 1172956b5d9SMika Westerberg case PIN_CONFIG_DRIVE_PUSH_PULL: 118190ea434SLinus Walleij return wm8994_set_bits(wm8994, WM8994_GPIO_1 + offset, 119190ea434SLinus Walleij WM8994_GPN_OP_CFG_MASK, 0); 120190ea434SLinus Walleij default: 121190ea434SLinus Walleij break; 122190ea434SLinus Walleij } 123190ea434SLinus Walleij 124190ea434SLinus Walleij return -ENOTSUPP; 125190ea434SLinus Walleij } 126190ea434SLinus Walleij 127c103de24SGrant Likely static int wm8994_gpio_to_irq(struct gpio_chip *chip, unsigned offset) 128c103de24SGrant Likely { 129765aa587SLinus Walleij struct wm8994_gpio *wm8994_gpio = gpiochip_get_data(chip); 130c103de24SGrant Likely struct wm8994 *wm8994 = wm8994_gpio->wm8994; 131c103de24SGrant Likely 132224a1f90SMark Brown return regmap_irq_get_virq(wm8994->irq_data, offset); 133c103de24SGrant Likely } 134c103de24SGrant Likely 135c103de24SGrant Likely 136c103de24SGrant Likely #ifdef CONFIG_DEBUG_FS 137d0ad5e89SMark Brown static const char *wm8994_gpio_fn(u16 fn) 138d0ad5e89SMark Brown { 139d0ad5e89SMark Brown switch (fn) { 140d0ad5e89SMark Brown case WM8994_GP_FN_PIN_SPECIFIC: 141d0ad5e89SMark Brown return "pin-specific"; 142d0ad5e89SMark Brown case WM8994_GP_FN_GPIO: 143d0ad5e89SMark Brown return "GPIO"; 144d0ad5e89SMark Brown case WM8994_GP_FN_SDOUT: 145d0ad5e89SMark Brown return "SDOUT"; 146d0ad5e89SMark Brown case WM8994_GP_FN_IRQ: 147d0ad5e89SMark Brown return "IRQ"; 148d0ad5e89SMark Brown case WM8994_GP_FN_TEMPERATURE: 149d0ad5e89SMark Brown return "Temperature"; 150d0ad5e89SMark Brown case WM8994_GP_FN_MICBIAS1_DET: 151d0ad5e89SMark Brown return "MICBIAS1 detect"; 152d0ad5e89SMark Brown case WM8994_GP_FN_MICBIAS1_SHORT: 153d0ad5e89SMark Brown return "MICBIAS1 short"; 154d0ad5e89SMark Brown case WM8994_GP_FN_MICBIAS2_DET: 155d0ad5e89SMark Brown return "MICBIAS2 detect"; 156d0ad5e89SMark Brown case WM8994_GP_FN_MICBIAS2_SHORT: 157d0ad5e89SMark Brown return "MICBIAS2 short"; 158d0ad5e89SMark Brown case WM8994_GP_FN_FLL1_LOCK: 159d0ad5e89SMark Brown return "FLL1 lock"; 160d0ad5e89SMark Brown case WM8994_GP_FN_FLL2_LOCK: 161d0ad5e89SMark Brown return "FLL2 lock"; 162d0ad5e89SMark Brown case WM8994_GP_FN_SRC1_LOCK: 163d0ad5e89SMark Brown return "SRC1 lock"; 164d0ad5e89SMark Brown case WM8994_GP_FN_SRC2_LOCK: 165d0ad5e89SMark Brown return "SRC2 lock"; 166d0ad5e89SMark Brown case WM8994_GP_FN_DRC1_ACT: 167d0ad5e89SMark Brown return "DRC1 activity"; 168d0ad5e89SMark Brown case WM8994_GP_FN_DRC2_ACT: 169d0ad5e89SMark Brown return "DRC2 activity"; 170d0ad5e89SMark Brown case WM8994_GP_FN_DRC3_ACT: 171d0ad5e89SMark Brown return "DRC3 activity"; 172d0ad5e89SMark Brown case WM8994_GP_FN_WSEQ_STATUS: 173d0ad5e89SMark Brown return "Write sequencer"; 174d0ad5e89SMark Brown case WM8994_GP_FN_FIFO_ERROR: 175d0ad5e89SMark Brown return "FIFO error"; 176d0ad5e89SMark Brown case WM8994_GP_FN_OPCLK: 177d0ad5e89SMark Brown return "OPCLK"; 178d0ad5e89SMark Brown case WM8994_GP_FN_THW: 179d0ad5e89SMark Brown return "Thermal warning"; 180d0ad5e89SMark Brown case WM8994_GP_FN_DCS_DONE: 181d0ad5e89SMark Brown return "DC servo"; 182d0ad5e89SMark Brown case WM8994_GP_FN_FLL1_OUT: 183d0ad5e89SMark Brown return "FLL1 output"; 184d0ad5e89SMark Brown case WM8994_GP_FN_FLL2_OUT: 185d0ad5e89SMark Brown return "FLL1 output"; 186d0ad5e89SMark Brown default: 187d0ad5e89SMark Brown return "Unknown"; 188d0ad5e89SMark Brown } 189d0ad5e89SMark Brown } 190d0ad5e89SMark Brown 191c103de24SGrant Likely static void wm8994_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) 192c103de24SGrant Likely { 193765aa587SLinus Walleij struct wm8994_gpio *wm8994_gpio = gpiochip_get_data(chip); 194c103de24SGrant Likely struct wm8994 *wm8994 = wm8994_gpio->wm8994; 195c103de24SGrant Likely int i; 196c103de24SGrant Likely 197c103de24SGrant Likely for (i = 0; i < chip->ngpio; i++) { 198c103de24SGrant Likely int gpio = i + chip->base; 199c103de24SGrant Likely int reg; 200c103de24SGrant Likely const char *label; 201c103de24SGrant Likely 202c103de24SGrant Likely /* We report the GPIO even if it's not requested since 203c103de24SGrant Likely * we're also reporting things like alternate 204c103de24SGrant Likely * functions which apply even when the GPIO is not in 205c103de24SGrant Likely * use as a GPIO. 206c103de24SGrant Likely */ 207c103de24SGrant Likely label = gpiochip_is_requested(chip, i); 208c103de24SGrant Likely if (!label) 209c103de24SGrant Likely label = "Unrequested"; 210c103de24SGrant Likely 211c103de24SGrant Likely seq_printf(s, " gpio-%-3d (%-20.20s) ", gpio, label); 212c103de24SGrant Likely 213c103de24SGrant Likely reg = wm8994_reg_read(wm8994, WM8994_GPIO_1 + i); 214c103de24SGrant Likely if (reg < 0) { 215c103de24SGrant Likely dev_err(wm8994->dev, 216c103de24SGrant Likely "GPIO control %d read failed: %d\n", 217c103de24SGrant Likely gpio, reg); 218c103de24SGrant Likely seq_printf(s, "\n"); 219c103de24SGrant Likely continue; 220c103de24SGrant Likely } 221c103de24SGrant Likely 222d0ad5e89SMark Brown if (reg & WM8994_GPN_DIR) 223d0ad5e89SMark Brown seq_printf(s, "in "); 224d0ad5e89SMark Brown else 225d0ad5e89SMark Brown seq_printf(s, "out "); 226d0ad5e89SMark Brown 227d0ad5e89SMark Brown if (reg & WM8994_GPN_PU) 228d0ad5e89SMark Brown seq_printf(s, "pull up "); 229d0ad5e89SMark Brown 230d0ad5e89SMark Brown if (reg & WM8994_GPN_PD) 231d0ad5e89SMark Brown seq_printf(s, "pull down "); 232d0ad5e89SMark Brown 233d0ad5e89SMark Brown if (reg & WM8994_GPN_POL) 234d0ad5e89SMark Brown seq_printf(s, "inverted "); 235d0ad5e89SMark Brown else 236d0ad5e89SMark Brown seq_printf(s, "noninverted "); 237d0ad5e89SMark Brown 238d0ad5e89SMark Brown if (reg & WM8994_GPN_OP_CFG) 239d0ad5e89SMark Brown seq_printf(s, "open drain "); 240d0ad5e89SMark Brown else 241190ea434SLinus Walleij seq_printf(s, "push-pull "); 242d0ad5e89SMark Brown 243d0ad5e89SMark Brown seq_printf(s, "%s (%x)\n", 244d0ad5e89SMark Brown wm8994_gpio_fn(reg & WM8994_GPN_FN_MASK), reg); 245c103de24SGrant Likely } 246c103de24SGrant Likely } 247c103de24SGrant Likely #else 248c103de24SGrant Likely #define wm8994_gpio_dbg_show NULL 249c103de24SGrant Likely #endif 250c103de24SGrant Likely 251e35b5ab0SJulia Lawall static const struct gpio_chip template_chip = { 252c103de24SGrant Likely .label = "wm8994", 253c103de24SGrant Likely .owner = THIS_MODULE, 254c103de24SGrant Likely .request = wm8994_gpio_request, 255c103de24SGrant Likely .direction_input = wm8994_gpio_direction_in, 256c103de24SGrant Likely .get = wm8994_gpio_get, 257c103de24SGrant Likely .direction_output = wm8994_gpio_direction_out, 258c103de24SGrant Likely .set = wm8994_gpio_set, 2592956b5d9SMika Westerberg .set_config = wm8994_gpio_set_config, 260c103de24SGrant Likely .to_irq = wm8994_gpio_to_irq, 261c103de24SGrant Likely .dbg_show = wm8994_gpio_dbg_show, 2629fb1f39eSLinus Walleij .can_sleep = true, 263c103de24SGrant Likely }; 264c103de24SGrant Likely 2653836309dSBill Pemberton static int wm8994_gpio_probe(struct platform_device *pdev) 266c103de24SGrant Likely { 267c103de24SGrant Likely struct wm8994 *wm8994 = dev_get_drvdata(pdev->dev.parent); 268e56aee18SJingoo Han struct wm8994_pdata *pdata = dev_get_platdata(wm8994->dev); 269c103de24SGrant Likely struct wm8994_gpio *wm8994_gpio; 270c103de24SGrant Likely int ret; 271c103de24SGrant Likely 272f8d203c0SMark Brown wm8994_gpio = devm_kzalloc(&pdev->dev, sizeof(*wm8994_gpio), 273f8d203c0SMark Brown GFP_KERNEL); 274c103de24SGrant Likely if (wm8994_gpio == NULL) 275c103de24SGrant Likely return -ENOMEM; 276c103de24SGrant Likely 277c103de24SGrant Likely wm8994_gpio->wm8994 = wm8994; 278c103de24SGrant Likely wm8994_gpio->gpio_chip = template_chip; 279c103de24SGrant Likely wm8994_gpio->gpio_chip.ngpio = WM8994_GPIO_MAX; 28058383c78SLinus Walleij wm8994_gpio->gpio_chip.parent = &pdev->dev; 281c103de24SGrant Likely if (pdata && pdata->gpio_base) 282c103de24SGrant Likely wm8994_gpio->gpio_chip.base = pdata->gpio_base; 283c103de24SGrant Likely else 284c103de24SGrant Likely wm8994_gpio->gpio_chip.base = -1; 285c103de24SGrant Likely 286c87dc4e4SLaxman Dewangan ret = devm_gpiochip_add_data(&pdev->dev, &wm8994_gpio->gpio_chip, 287c87dc4e4SLaxman Dewangan wm8994_gpio); 288c103de24SGrant Likely if (ret < 0) { 289c103de24SGrant Likely dev_err(&pdev->dev, "Could not register gpiochip, %d\n", 290c103de24SGrant Likely ret); 291c87dc4e4SLaxman Dewangan return ret; 292c103de24SGrant Likely } 293c103de24SGrant Likely 294c103de24SGrant Likely platform_set_drvdata(pdev, wm8994_gpio); 295c103de24SGrant Likely 296c103de24SGrant Likely return ret; 297c103de24SGrant Likely } 298c103de24SGrant Likely 299c103de24SGrant Likely static struct platform_driver wm8994_gpio_driver = { 300c103de24SGrant Likely .driver.name = "wm8994-gpio", 301c103de24SGrant Likely .probe = wm8994_gpio_probe, 302c103de24SGrant Likely }; 303c103de24SGrant Likely 304c103de24SGrant Likely static int __init wm8994_gpio_init(void) 305c103de24SGrant Likely { 306c103de24SGrant Likely return platform_driver_register(&wm8994_gpio_driver); 307c103de24SGrant Likely } 308c103de24SGrant Likely subsys_initcall(wm8994_gpio_init); 309c103de24SGrant Likely 310c103de24SGrant Likely static void __exit wm8994_gpio_exit(void) 311c103de24SGrant Likely { 312c103de24SGrant Likely platform_driver_unregister(&wm8994_gpio_driver); 313c103de24SGrant Likely } 314c103de24SGrant Likely module_exit(wm8994_gpio_exit); 315c103de24SGrant Likely 316c103de24SGrant Likely MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); 317c103de24SGrant Likely MODULE_DESCRIPTION("GPIO interface for WM8994"); 318c103de24SGrant Likely MODULE_LICENSE("GPL"); 319c103de24SGrant Likely MODULE_ALIAS("platform:wm8994-gpio"); 320