linux/drivers/gpio/gpio-wm8994.c
<<
>>
Prefs
   1/*
   2 * gpiolib support for Wolfson WM8994
   3 *
   4 * Copyright 2009 Wolfson Microelectronics PLC.
   5 *
   6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
   7 *
   8 *  This program is free software; you can redistribute  it and/or modify it
   9 *  under  the terms of  the GNU General  Public License as published by the
  10 *  Free Software Foundation;  either version 2 of the  License, or (at your
  11 *  option) any later version.
  12 *
  13 */
  14
  15#include <linux/kernel.h>
  16#include <linux/slab.h>
  17#include <linux/module.h>
  18#include <linux/gpio.h>
  19#include <linux/mfd/core.h>
  20#include <linux/platform_device.h>
  21#include <linux/seq_file.h>
  22
  23#include <linux/mfd/wm8994/core.h>
  24#include <linux/mfd/wm8994/pdata.h>
  25#include <linux/mfd/wm8994/gpio.h>
  26#include <linux/mfd/wm8994/registers.h>
  27
  28struct wm8994_gpio {
  29        struct wm8994 *wm8994;
  30        struct gpio_chip gpio_chip;
  31};
  32
  33static inline struct wm8994_gpio *to_wm8994_gpio(struct gpio_chip *chip)
  34{
  35        return container_of(chip, struct wm8994_gpio, gpio_chip);
  36}
  37
  38static int wm8994_gpio_request(struct gpio_chip *chip, unsigned offset)
  39{
  40        struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip);
  41        struct wm8994 *wm8994 = wm8994_gpio->wm8994;
  42
  43        switch (wm8994->type) {
  44        case WM8958:
  45                switch (offset) {
  46                case 1:
  47                case 2:
  48                case 3:
  49                case 4:
  50                case 6:
  51                        return -EINVAL;
  52                }
  53                break;
  54        default:
  55                break;
  56        }
  57
  58        return 0;
  59}
  60
  61static int wm8994_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
  62{
  63        struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip);
  64        struct wm8994 *wm8994 = wm8994_gpio->wm8994;
  65
  66        return wm8994_set_bits(wm8994, WM8994_GPIO_1 + offset,
  67                               WM8994_GPN_DIR, WM8994_GPN_DIR);
  68}
  69
  70static int wm8994_gpio_get(struct gpio_chip *chip, unsigned offset)
  71{
  72        struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip);
  73        struct wm8994 *wm8994 = wm8994_gpio->wm8994;
  74        int ret;
  75
  76        ret = wm8994_reg_read(wm8994, WM8994_GPIO_1 + offset);
  77        if (ret < 0)
  78                return ret;
  79
  80        if (ret & WM8994_GPN_LVL)
  81                return 1;
  82        else
  83                return 0;
  84}
  85
  86static int wm8994_gpio_direction_out(struct gpio_chip *chip,
  87                                     unsigned offset, int value)
  88{
  89        struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip);
  90        struct wm8994 *wm8994 = wm8994_gpio->wm8994;
  91
  92        return wm8994_set_bits(wm8994, WM8994_GPIO_1 + offset,
  93                               WM8994_GPN_DIR, 0);
  94}
  95
  96static void wm8994_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
  97{
  98        struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip);
  99        struct wm8994 *wm8994 = wm8994_gpio->wm8994;
 100
 101        if (value)
 102                value = WM8994_GPN_LVL;
 103
 104        wm8994_set_bits(wm8994, WM8994_GPIO_1 + offset, WM8994_GPN_LVL, value);
 105}
 106
 107static int wm8994_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
 108{
 109        struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip);
 110        struct wm8994 *wm8994 = wm8994_gpio->wm8994;
 111
 112        if (!wm8994->irq_base)
 113                return -EINVAL;
 114
 115        return wm8994->irq_base + offset;
 116}
 117
 118
 119#ifdef CONFIG_DEBUG_FS
 120static void wm8994_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
 121{
 122        struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip);
 123        struct wm8994 *wm8994 = wm8994_gpio->wm8994;
 124        int i;
 125
 126        for (i = 0; i < chip->ngpio; i++) {
 127                int gpio = i + chip->base;
 128                int reg;
 129                const char *label;
 130
 131                /* We report the GPIO even if it's not requested since
 132                 * we're also reporting things like alternate
 133                 * functions which apply even when the GPIO is not in
 134                 * use as a GPIO.
 135                 */
 136                label = gpiochip_is_requested(chip, i);
 137                if (!label)
 138                        label = "Unrequested";
 139
 140                seq_printf(s, " gpio-%-3d (%-20.20s) ", gpio, label);
 141
 142                reg = wm8994_reg_read(wm8994, WM8994_GPIO_1 + i);
 143                if (reg < 0) {
 144                        dev_err(wm8994->dev,
 145                                "GPIO control %d read failed: %d\n",
 146                                gpio, reg);
 147                        seq_printf(s, "\n");
 148                        continue;
 149                }
 150
 151                /* No decode yet; note that GPIO2 is special */
 152                seq_printf(s, "(%x)\n", reg);
 153        }
 154}
 155#else
 156#define wm8994_gpio_dbg_show NULL
 157#endif
 158
 159static struct gpio_chip template_chip = {
 160        .label                  = "wm8994",
 161        .owner                  = THIS_MODULE,
 162        .request                = wm8994_gpio_request,
 163        .direction_input        = wm8994_gpio_direction_in,
 164        .get                    = wm8994_gpio_get,
 165        .direction_output       = wm8994_gpio_direction_out,
 166        .set                    = wm8994_gpio_set,
 167        .to_irq                 = wm8994_gpio_to_irq,
 168        .dbg_show               = wm8994_gpio_dbg_show,
 169        .can_sleep              = 1,
 170};
 171
 172static int __devinit wm8994_gpio_probe(struct platform_device *pdev)
 173{
 174        struct wm8994 *wm8994 = dev_get_drvdata(pdev->dev.parent);
 175        struct wm8994_pdata *pdata = wm8994->dev->platform_data;
 176        struct wm8994_gpio *wm8994_gpio;
 177        int ret;
 178
 179        wm8994_gpio = kzalloc(sizeof(*wm8994_gpio), GFP_KERNEL);
 180        if (wm8994_gpio == NULL)
 181                return -ENOMEM;
 182
 183        wm8994_gpio->wm8994 = wm8994;
 184        wm8994_gpio->gpio_chip = template_chip;
 185        wm8994_gpio->gpio_chip.ngpio = WM8994_GPIO_MAX;
 186        wm8994_gpio->gpio_chip.dev = &pdev->dev;
 187        if (pdata && pdata->gpio_base)
 188                wm8994_gpio->gpio_chip.base = pdata->gpio_base;
 189        else
 190                wm8994_gpio->gpio_chip.base = -1;
 191
 192        ret = gpiochip_add(&wm8994_gpio->gpio_chip);
 193        if (ret < 0) {
 194                dev_err(&pdev->dev, "Could not register gpiochip, %d\n",
 195                        ret);
 196                goto err;
 197        }
 198
 199        platform_set_drvdata(pdev, wm8994_gpio);
 200
 201        return ret;
 202
 203err:
 204        kfree(wm8994_gpio);
 205        return ret;
 206}
 207
 208static int __devexit wm8994_gpio_remove(struct platform_device *pdev)
 209{
 210        struct wm8994_gpio *wm8994_gpio = platform_get_drvdata(pdev);
 211        int ret;
 212
 213        ret = gpiochip_remove(&wm8994_gpio->gpio_chip);
 214        if (ret == 0)
 215                kfree(wm8994_gpio);
 216
 217        return ret;
 218}
 219
 220static struct platform_driver wm8994_gpio_driver = {
 221        .driver.name    = "wm8994-gpio",
 222        .driver.owner   = THIS_MODULE,
 223        .probe          = wm8994_gpio_probe,
 224        .remove         = __devexit_p(wm8994_gpio_remove),
 225};
 226
 227static int __init wm8994_gpio_init(void)
 228{
 229        return platform_driver_register(&wm8994_gpio_driver);
 230}
 231subsys_initcall(wm8994_gpio_init);
 232
 233static void __exit wm8994_gpio_exit(void)
 234{
 235        platform_driver_unregister(&wm8994_gpio_driver);
 236}
 237module_exit(wm8994_gpio_exit);
 238
 239MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
 240MODULE_DESCRIPTION("GPIO interface for WM8994");
 241MODULE_LICENSE("GPL");
 242MODULE_ALIAS("platform:wm8994-gpio");
 243