linux/drivers/gpio/gpio-kempld.c
<<
>>
Prefs
   1/*
   2 * Kontron PLD GPIO driver
   3 *
   4 * Copyright (c) 2010-2013 Kontron Europe GmbH
   5 * Author: Michael Brunner <michael.brunner@kontron.com>
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License 2 as published
   9 * by the Free Software Foundation.
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License for more details.
  15 */
  16
  17#include <linux/init.h>
  18#include <linux/kernel.h>
  19#include <linux/module.h>
  20#include <linux/bitops.h>
  21#include <linux/errno.h>
  22#include <linux/platform_device.h>
  23#include <linux/gpio.h>
  24#include <linux/mfd/kempld.h>
  25
  26#define KEMPLD_GPIO_MAX_NUM             16
  27#define KEMPLD_GPIO_MASK(x)             (1 << ((x) % 8))
  28#define KEMPLD_GPIO_DIR_NUM(x)          (0x40 + (x) / 8)
  29#define KEMPLD_GPIO_LVL_NUM(x)          (0x42 + (x) / 8)
  30#define KEMPLD_GPIO_EVT_LVL_EDGE        0x46
  31#define KEMPLD_GPIO_IEN                 0x4A
  32
  33struct kempld_gpio_data {
  34        struct gpio_chip                chip;
  35        struct kempld_device_data       *pld;
  36};
  37
  38/*
  39 * Set or clear GPIO bit
  40 * kempld_get_mutex must be called prior to calling this function.
  41 */
  42static void kempld_gpio_bitop(struct kempld_device_data *pld,
  43                              u8 reg, u8 bit, u8 val)
  44{
  45        u8 status;
  46
  47        status = kempld_read8(pld, reg);
  48        if (val)
  49                status |= KEMPLD_GPIO_MASK(bit);
  50        else
  51                status &= ~KEMPLD_GPIO_MASK(bit);
  52        kempld_write8(pld, reg, status);
  53}
  54
  55static int kempld_gpio_get_bit(struct kempld_device_data *pld, u8 reg, u8 bit)
  56{
  57        u8 status;
  58
  59        kempld_get_mutex(pld);
  60        status = kempld_read8(pld, reg);
  61        kempld_release_mutex(pld);
  62
  63        return !!(status & KEMPLD_GPIO_MASK(bit));
  64}
  65
  66static int kempld_gpio_get(struct gpio_chip *chip, unsigned offset)
  67{
  68        struct kempld_gpio_data *gpio
  69                = container_of(chip, struct kempld_gpio_data, chip);
  70        struct kempld_device_data *pld = gpio->pld;
  71
  72        return kempld_gpio_get_bit(pld, KEMPLD_GPIO_LVL_NUM(offset), offset);
  73}
  74
  75static void kempld_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
  76{
  77        struct kempld_gpio_data *gpio
  78                = container_of(chip, struct kempld_gpio_data, chip);
  79        struct kempld_device_data *pld = gpio->pld;
  80
  81        kempld_get_mutex(pld);
  82        kempld_gpio_bitop(pld, KEMPLD_GPIO_LVL_NUM(offset), offset, value);
  83        kempld_release_mutex(pld);
  84}
  85
  86static int kempld_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
  87{
  88        struct kempld_gpio_data *gpio
  89                = container_of(chip, struct kempld_gpio_data, chip);
  90        struct kempld_device_data *pld = gpio->pld;
  91
  92        kempld_get_mutex(pld);
  93        kempld_gpio_bitop(pld, KEMPLD_GPIO_DIR_NUM(offset), offset, 0);
  94        kempld_release_mutex(pld);
  95
  96        return 0;
  97}
  98
  99static int kempld_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
 100                                        int value)
 101{
 102        struct kempld_gpio_data *gpio
 103                = container_of(chip, struct kempld_gpio_data, chip);
 104        struct kempld_device_data *pld = gpio->pld;
 105
 106        kempld_get_mutex(pld);
 107        kempld_gpio_bitop(pld, KEMPLD_GPIO_LVL_NUM(offset), offset, value);
 108        kempld_gpio_bitop(pld, KEMPLD_GPIO_DIR_NUM(offset), offset, 1);
 109        kempld_release_mutex(pld);
 110
 111        return 0;
 112}
 113
 114static int kempld_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
 115{
 116        struct kempld_gpio_data *gpio
 117                = container_of(chip, struct kempld_gpio_data, chip);
 118        struct kempld_device_data *pld = gpio->pld;
 119
 120        return kempld_gpio_get_bit(pld, KEMPLD_GPIO_DIR_NUM(offset), offset);
 121}
 122
 123static int kempld_gpio_pincount(struct kempld_device_data *pld)
 124{
 125        u16 evt, evt_back;
 126
 127        kempld_get_mutex(pld);
 128
 129        /* Backup event register as it might be already initialized */
 130        evt_back = kempld_read16(pld, KEMPLD_GPIO_EVT_LVL_EDGE);
 131        /* Clear event register */
 132        kempld_write16(pld, KEMPLD_GPIO_EVT_LVL_EDGE, 0x0000);
 133        /* Read back event register */
 134        evt = kempld_read16(pld, KEMPLD_GPIO_EVT_LVL_EDGE);
 135        /* Restore event register */
 136        kempld_write16(pld, KEMPLD_GPIO_EVT_LVL_EDGE, evt_back);
 137
 138        kempld_release_mutex(pld);
 139
 140        return evt ? __ffs(evt) : 16;
 141}
 142
 143static int kempld_gpio_probe(struct platform_device *pdev)
 144{
 145        struct device *dev = &pdev->dev;
 146        struct kempld_device_data *pld = dev_get_drvdata(dev->parent);
 147        struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
 148        struct kempld_gpio_data *gpio;
 149        struct gpio_chip *chip;
 150        int ret;
 151
 152        if (pld->info.spec_major < 2) {
 153                dev_err(dev,
 154                        "Driver only supports GPIO devices compatible to PLD spec. rev. 2.0 or higher\n");
 155                return -ENODEV;
 156        }
 157
 158        gpio = devm_kzalloc(dev, sizeof(*gpio), GFP_KERNEL);
 159        if (gpio == NULL)
 160                return -ENOMEM;
 161
 162        gpio->pld = pld;
 163
 164        platform_set_drvdata(pdev, gpio);
 165
 166        chip = &gpio->chip;
 167        chip->label = "gpio-kempld";
 168        chip->owner = THIS_MODULE;
 169        chip->dev = dev;
 170        chip->can_sleep = 1;
 171        if (pdata && pdata->gpio_base)
 172                chip->base = pdata->gpio_base;
 173        else
 174                chip->base = -1;
 175        chip->direction_input = kempld_gpio_direction_input;
 176        chip->direction_output = kempld_gpio_direction_output;
 177        chip->get_direction = kempld_gpio_get_direction;
 178        chip->get = kempld_gpio_get;
 179        chip->set = kempld_gpio_set;
 180        chip->ngpio = kempld_gpio_pincount(pld);
 181        if (chip->ngpio == 0) {
 182                dev_err(dev, "No GPIO pins detected\n");
 183                return -ENODEV;
 184        }
 185
 186        ret = gpiochip_add(chip);
 187        if (ret) {
 188                dev_err(dev, "Could not register GPIO chip\n");
 189                return ret;
 190        }
 191
 192        dev_info(dev, "GPIO functionality initialized with %d pins\n",
 193                 chip->ngpio);
 194
 195        return 0;
 196}
 197
 198static int kempld_gpio_remove(struct platform_device *pdev)
 199{
 200        struct kempld_gpio_data *gpio = platform_get_drvdata(pdev);
 201
 202        return gpiochip_remove(&gpio->chip);
 203}
 204
 205static struct platform_driver kempld_gpio_driver = {
 206        .driver = {
 207                .name = "kempld-gpio",
 208                .owner = THIS_MODULE,
 209        },
 210        .probe          = kempld_gpio_probe,
 211        .remove         = kempld_gpio_remove,
 212};
 213
 214module_platform_driver(kempld_gpio_driver);
 215
 216MODULE_DESCRIPTION("KEM PLD GPIO Driver");
 217MODULE_AUTHOR("Michael Brunner <michael.brunner@kontron.com>");
 218MODULE_LICENSE("GPL");
 219MODULE_ALIAS("platform:gpio-kempld");
 220
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.