linux/drivers/gpio/gpio-mb86s7x.c
<<
>>
Prefs
   1/*
   2 *  linux/drivers/gpio/gpio-mb86s7x.c
   3 *
   4 *  Copyright (C) 2015 Fujitsu Semiconductor Limited
   5 *  Copyright (C) 2015 Linaro Ltd.
   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, version 2 of the License.
  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/io.h>
  18#include <linux/init.h>
  19#include <linux/clk.h>
  20#include <linux/module.h>
  21#include <linux/err.h>
  22#include <linux/errno.h>
  23#include <linux/ioport.h>
  24#include <linux/of_device.h>
  25#include <linux/gpio/driver.h>
  26#include <linux/platform_device.h>
  27#include <linux/spinlock.h>
  28#include <linux/slab.h>
  29
  30/*
  31 * Only first 8bits of a register correspond to each pin,
  32 * so there are 4 registers for 32 pins.
  33 */
  34#define PDR(x)  (0x0 + x / 8 * 4)
  35#define DDR(x)  (0x10 + x / 8 * 4)
  36#define PFR(x)  (0x20 + x / 8 * 4)
  37
  38#define OFFSET(x)       BIT((x) % 8)
  39
  40struct mb86s70_gpio_chip {
  41        struct gpio_chip gc;
  42        void __iomem *base;
  43        struct clk *clk;
  44        spinlock_t lock;
  45};
  46
  47static int mb86s70_gpio_request(struct gpio_chip *gc, unsigned gpio)
  48{
  49        struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc);
  50        unsigned long flags;
  51        u32 val;
  52
  53        spin_lock_irqsave(&gchip->lock, flags);
  54
  55        val = readl(gchip->base + PFR(gpio));
  56        val &= ~OFFSET(gpio);
  57        writel(val, gchip->base + PFR(gpio));
  58
  59        spin_unlock_irqrestore(&gchip->lock, flags);
  60
  61        return 0;
  62}
  63
  64static void mb86s70_gpio_free(struct gpio_chip *gc, unsigned gpio)
  65{
  66        struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc);
  67        unsigned long flags;
  68        u32 val;
  69
  70        spin_lock_irqsave(&gchip->lock, flags);
  71
  72        val = readl(gchip->base + PFR(gpio));
  73        val |= OFFSET(gpio);
  74        writel(val, gchip->base + PFR(gpio));
  75
  76        spin_unlock_irqrestore(&gchip->lock, flags);
  77}
  78
  79static int mb86s70_gpio_direction_input(struct gpio_chip *gc, unsigned gpio)
  80{
  81        struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc);
  82        unsigned long flags;
  83        unsigned char val;
  84
  85        spin_lock_irqsave(&gchip->lock, flags);
  86
  87        val = readl(gchip->base + DDR(gpio));
  88        val &= ~OFFSET(gpio);
  89        writel(val, gchip->base + DDR(gpio));
  90
  91        spin_unlock_irqrestore(&gchip->lock, flags);
  92
  93        return 0;
  94}
  95
  96static int mb86s70_gpio_direction_output(struct gpio_chip *gc,
  97                                         unsigned gpio, int value)
  98{
  99        struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc);
 100        unsigned long flags;
 101        unsigned char val;
 102
 103        spin_lock_irqsave(&gchip->lock, flags);
 104
 105        val = readl(gchip->base + PDR(gpio));
 106        if (value)
 107                val |= OFFSET(gpio);
 108        else
 109                val &= ~OFFSET(gpio);
 110        writel(val, gchip->base + PDR(gpio));
 111
 112        val = readl(gchip->base + DDR(gpio));
 113        val |= OFFSET(gpio);
 114        writel(val, gchip->base + DDR(gpio));
 115
 116        spin_unlock_irqrestore(&gchip->lock, flags);
 117
 118        return 0;
 119}
 120
 121static int mb86s70_gpio_get(struct gpio_chip *gc, unsigned gpio)
 122{
 123        struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc);
 124
 125        return !!(readl(gchip->base + PDR(gpio)) & OFFSET(gpio));
 126}
 127
 128static void mb86s70_gpio_set(struct gpio_chip *gc, unsigned gpio, int value)
 129{
 130        struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc);
 131        unsigned long flags;
 132        unsigned char val;
 133
 134        spin_lock_irqsave(&gchip->lock, flags);
 135
 136        val = readl(gchip->base + PDR(gpio));
 137        if (value)
 138                val |= OFFSET(gpio);
 139        else
 140                val &= ~OFFSET(gpio);
 141        writel(val, gchip->base + PDR(gpio));
 142
 143        spin_unlock_irqrestore(&gchip->lock, flags);
 144}
 145
 146static int mb86s70_gpio_probe(struct platform_device *pdev)
 147{
 148        struct mb86s70_gpio_chip *gchip;
 149        struct resource *res;
 150        int ret;
 151
 152        gchip = devm_kzalloc(&pdev->dev, sizeof(*gchip), GFP_KERNEL);
 153        if (gchip == NULL)
 154                return -ENOMEM;
 155
 156        platform_set_drvdata(pdev, gchip);
 157
 158        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 159        gchip->base = devm_ioremap_resource(&pdev->dev, res);
 160        if (IS_ERR(gchip->base))
 161                return PTR_ERR(gchip->base);
 162
 163        gchip->clk = devm_clk_get(&pdev->dev, NULL);
 164        if (IS_ERR(gchip->clk))
 165                return PTR_ERR(gchip->clk);
 166
 167        ret = clk_prepare_enable(gchip->clk);
 168        if (ret)
 169                return ret;
 170
 171        spin_lock_init(&gchip->lock);
 172
 173        gchip->gc.direction_output = mb86s70_gpio_direction_output;
 174        gchip->gc.direction_input = mb86s70_gpio_direction_input;
 175        gchip->gc.request = mb86s70_gpio_request;
 176        gchip->gc.free = mb86s70_gpio_free;
 177        gchip->gc.get = mb86s70_gpio_get;
 178        gchip->gc.set = mb86s70_gpio_set;
 179        gchip->gc.label = dev_name(&pdev->dev);
 180        gchip->gc.ngpio = 32;
 181        gchip->gc.owner = THIS_MODULE;
 182        gchip->gc.parent = &pdev->dev;
 183        gchip->gc.base = -1;
 184
 185        ret = gpiochip_add_data(&gchip->gc, gchip);
 186        if (ret) {
 187                dev_err(&pdev->dev, "couldn't register gpio driver\n");
 188                clk_disable_unprepare(gchip->clk);
 189        }
 190
 191        return ret;
 192}
 193
 194static int mb86s70_gpio_remove(struct platform_device *pdev)
 195{
 196        struct mb86s70_gpio_chip *gchip = platform_get_drvdata(pdev);
 197
 198        gpiochip_remove(&gchip->gc);
 199        clk_disable_unprepare(gchip->clk);
 200
 201        return 0;
 202}
 203
 204static const struct of_device_id mb86s70_gpio_dt_ids[] = {
 205        { .compatible = "fujitsu,mb86s70-gpio" },
 206        { /* sentinel */ }
 207};
 208MODULE_DEVICE_TABLE(of, mb86s70_gpio_dt_ids);
 209
 210static struct platform_driver mb86s70_gpio_driver = {
 211        .driver = {
 212                .name = "mb86s70-gpio",
 213                .of_match_table = mb86s70_gpio_dt_ids,
 214        },
 215        .probe = mb86s70_gpio_probe,
 216        .remove = mb86s70_gpio_remove,
 217};
 218module_platform_driver(mb86s70_gpio_driver);
 219
 220MODULE_DESCRIPTION("MB86S7x GPIO Driver");
 221MODULE_ALIAS("platform:mb86s70-gpio");
 222MODULE_LICENSE("GPL");
 223