linux/drivers/gpio/gpio-rdc321x.c
<<
>>
Prefs
   1/*
   2 * RDC321x GPIO driver
   3 *
   4 * Copyright (C) 2008, Volker Weiss <dev@tintuc.de>
   5 * Copyright (C) 2007-2010 Florian Fainelli <florian@openwrt.org>
   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 as published by
   9 * the Free Software Foundation; either version 2 of the License, or
  10 * (at your option) any later version.
  11 *
  12 * This program is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 * GNU General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU General Public License
  18 * along with this program; if not, write to the Free Software
  19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20 *
  21 */
  22#include <linux/module.h>
  23#include <linux/kernel.h>
  24#include <linux/init.h>
  25#include <linux/spinlock.h>
  26#include <linux/platform_device.h>
  27#include <linux/pci.h>
  28#include <linux/gpio.h>
  29#include <linux/mfd/rdc321x.h>
  30#include <linux/slab.h>
  31
  32struct rdc321x_gpio {
  33        spinlock_t              lock;
  34        struct pci_dev          *sb_pdev;
  35        u32                     data_reg[2];
  36        int                     reg1_ctrl_base;
  37        int                     reg1_data_base;
  38        int                     reg2_ctrl_base;
  39        int                     reg2_data_base;
  40        struct gpio_chip        chip;
  41};
  42
  43/* read GPIO pin */
  44static int rdc_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
  45{
  46        struct rdc321x_gpio *gpch;
  47        u32 value = 0;
  48        int reg;
  49
  50        gpch = container_of(chip, struct rdc321x_gpio, chip);
  51        reg = gpio < 32 ? gpch->reg1_data_base : gpch->reg2_data_base;
  52
  53        spin_lock(&gpch->lock);
  54        pci_write_config_dword(gpch->sb_pdev, reg,
  55                                        gpch->data_reg[gpio < 32 ? 0 : 1]);
  56        pci_read_config_dword(gpch->sb_pdev, reg, &value);
  57        spin_unlock(&gpch->lock);
  58
  59        return (1 << (gpio & 0x1f)) & value ? 1 : 0;
  60}
  61
  62static void rdc_gpio_set_value_impl(struct gpio_chip *chip,
  63                                unsigned gpio, int value)
  64{
  65        struct rdc321x_gpio *gpch;
  66        int reg = (gpio < 32) ? 0 : 1;
  67
  68        gpch = container_of(chip, struct rdc321x_gpio, chip);
  69
  70        if (value)
  71                gpch->data_reg[reg] |= 1 << (gpio & 0x1f);
  72        else
  73                gpch->data_reg[reg] &= ~(1 << (gpio & 0x1f));
  74
  75        pci_write_config_dword(gpch->sb_pdev,
  76                        reg ? gpch->reg2_data_base : gpch->reg1_data_base,
  77                        gpch->data_reg[reg]);
  78}
  79
  80/* set GPIO pin to value */
  81static void rdc_gpio_set_value(struct gpio_chip *chip,
  82                                unsigned gpio, int value)
  83{
  84        struct rdc321x_gpio *gpch;
  85
  86        gpch = container_of(chip, struct rdc321x_gpio, chip);
  87        spin_lock(&gpch->lock);
  88        rdc_gpio_set_value_impl(chip, gpio, value);
  89        spin_unlock(&gpch->lock);
  90}
  91
  92static int rdc_gpio_config(struct gpio_chip *chip,
  93                                unsigned gpio, int value)
  94{
  95        struct rdc321x_gpio *gpch;
  96        int err;
  97        u32 reg;
  98
  99        gpch = container_of(chip, struct rdc321x_gpio, chip);
 100
 101        spin_lock(&gpch->lock);
 102        err = pci_read_config_dword(gpch->sb_pdev, gpio < 32 ?
 103                        gpch->reg1_ctrl_base : gpch->reg2_ctrl_base, &reg);
 104        if (err)
 105                goto unlock;
 106
 107        reg |= 1 << (gpio & 0x1f);
 108
 109        err = pci_write_config_dword(gpch->sb_pdev, gpio < 32 ?
 110                        gpch->reg1_ctrl_base : gpch->reg2_ctrl_base, reg);
 111        if (err)
 112                goto unlock;
 113
 114        rdc_gpio_set_value_impl(chip, gpio, value);
 115
 116unlock:
 117        spin_unlock(&gpch->lock);
 118
 119        return err;
 120}
 121
 122/* configure GPIO pin as input */
 123static int rdc_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
 124{
 125        return rdc_gpio_config(chip, gpio, 1);
 126}
 127
 128/*
 129 * Cache the initial value of both GPIO data registers
 130 */
 131static int rdc321x_gpio_probe(struct platform_device *pdev)
 132{
 133        int err;
 134        struct resource *r;
 135        struct rdc321x_gpio *rdc321x_gpio_dev;
 136        struct rdc321x_gpio_pdata *pdata;
 137
 138        pdata = pdev->dev.platform_data;
 139        if (!pdata) {
 140                dev_err(&pdev->dev, "no platform data supplied\n");
 141                return -ENODEV;
 142        }
 143
 144        rdc321x_gpio_dev = kzalloc(sizeof(struct rdc321x_gpio), GFP_KERNEL);
 145        if (!rdc321x_gpio_dev) {
 146                dev_err(&pdev->dev, "failed to allocate private data\n");
 147                return -ENOMEM;
 148        }
 149
 150        r = platform_get_resource_byname(pdev, IORESOURCE_IO, "gpio-reg1");
 151        if (!r) {
 152                dev_err(&pdev->dev, "failed to get gpio-reg1 resource\n");
 153                err = -ENODEV;
 154                goto out_free;
 155        }
 156
 157        spin_lock_init(&rdc321x_gpio_dev->lock);
 158        rdc321x_gpio_dev->sb_pdev = pdata->sb_pdev;
 159        rdc321x_gpio_dev->reg1_ctrl_base = r->start;
 160        rdc321x_gpio_dev->reg1_data_base = r->start + 0x4;
 161
 162        r = platform_get_resource_byname(pdev, IORESOURCE_IO, "gpio-reg2");
 163        if (!r) {
 164                dev_err(&pdev->dev, "failed to get gpio-reg2 resource\n");
 165                err = -ENODEV;
 166                goto out_free;
 167        }
 168
 169        rdc321x_gpio_dev->reg2_ctrl_base = r->start;
 170        rdc321x_gpio_dev->reg2_data_base = r->start + 0x4;
 171
 172        rdc321x_gpio_dev->chip.label = "rdc321x-gpio";
 173        rdc321x_gpio_dev->chip.owner = THIS_MODULE;
 174        rdc321x_gpio_dev->chip.direction_input = rdc_gpio_direction_input;
 175        rdc321x_gpio_dev->chip.direction_output = rdc_gpio_config;
 176        rdc321x_gpio_dev->chip.get = rdc_gpio_get_value;
 177        rdc321x_gpio_dev->chip.set = rdc_gpio_set_value;
 178        rdc321x_gpio_dev->chip.base = 0;
 179        rdc321x_gpio_dev->chip.ngpio = pdata->max_gpios;
 180
 181        platform_set_drvdata(pdev, rdc321x_gpio_dev);
 182
 183        /* This might not be, what others (BIOS, bootloader, etc.)
 184           wrote to these registers before, but it's a good guess. Still
 185           better than just using 0xffffffff. */
 186        err = pci_read_config_dword(rdc321x_gpio_dev->sb_pdev,
 187                                        rdc321x_gpio_dev->reg1_data_base,
 188                                        &rdc321x_gpio_dev->data_reg[0]);
 189        if (err)
 190                goto out_drvdata;
 191
 192        err = pci_read_config_dword(rdc321x_gpio_dev->sb_pdev,
 193                                        rdc321x_gpio_dev->reg2_data_base,
 194                                        &rdc321x_gpio_dev->data_reg[1]);
 195        if (err)
 196                goto out_drvdata;
 197
 198        dev_info(&pdev->dev, "registering %d GPIOs\n",
 199                                        rdc321x_gpio_dev->chip.ngpio);
 200        return gpiochip_add(&rdc321x_gpio_dev->chip);
 201
 202out_drvdata:
 203        platform_set_drvdata(pdev, NULL);
 204out_free:
 205        kfree(rdc321x_gpio_dev);
 206        return err;
 207}
 208
 209static int rdc321x_gpio_remove(struct platform_device *pdev)
 210{
 211        int ret;
 212        struct rdc321x_gpio *rdc321x_gpio_dev = platform_get_drvdata(pdev);
 213
 214        ret = gpiochip_remove(&rdc321x_gpio_dev->chip);
 215        if (ret)
 216                dev_err(&pdev->dev, "failed to unregister chip\n");
 217
 218        kfree(rdc321x_gpio_dev);
 219        platform_set_drvdata(pdev, NULL);
 220
 221        return ret;
 222}
 223
 224static struct platform_driver rdc321x_gpio_driver = {
 225        .driver.name    = "rdc321x-gpio",
 226        .driver.owner   = THIS_MODULE,
 227        .probe          = rdc321x_gpio_probe,
 228        .remove         = rdc321x_gpio_remove,
 229};
 230
 231module_platform_driver(rdc321x_gpio_driver);
 232
 233MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
 234MODULE_DESCRIPTION("RDC321x GPIO driver");
 235MODULE_LICENSE("GPL");
 236MODULE_ALIAS("platform:rdc321x-gpio");
 237