linux/drivers/gpio/gpio-xgene.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * AppliedMicro X-Gene SoC GPIO Driver
   4 *
   5 * Copyright (c) 2014, Applied Micro Circuits Corporation
   6 * Author: Feng Kan <fkan@apm.com>.
   7 */
   8
   9#include <linux/acpi.h>
  10#include <linux/kernel.h>
  11#include <linux/init.h>
  12#include <linux/io.h>
  13#include <linux/spinlock.h>
  14#include <linux/platform_device.h>
  15#include <linux/gpio/driver.h>
  16#include <linux/types.h>
  17#include <linux/bitops.h>
  18
  19#define GPIO_SET_DR_OFFSET      0x0C
  20#define GPIO_DATA_OFFSET        0x14
  21#define GPIO_BANK_STRIDE        0x0C
  22
  23#define XGENE_GPIOS_PER_BANK    16
  24#define XGENE_MAX_GPIO_BANKS    3
  25#define XGENE_MAX_GPIOS         (XGENE_GPIOS_PER_BANK * XGENE_MAX_GPIO_BANKS)
  26
  27#define GPIO_BIT_OFFSET(x)      (x % XGENE_GPIOS_PER_BANK)
  28#define GPIO_BANK_OFFSET(x)     ((x / XGENE_GPIOS_PER_BANK) * GPIO_BANK_STRIDE)
  29
  30struct xgene_gpio {
  31        struct gpio_chip        chip;
  32        void __iomem            *base;
  33        spinlock_t              lock;
  34        u32                     set_dr_val[XGENE_MAX_GPIO_BANKS];
  35};
  36
  37static int xgene_gpio_get(struct gpio_chip *gc, unsigned int offset)
  38{
  39        struct xgene_gpio *chip = gpiochip_get_data(gc);
  40        unsigned long bank_offset;
  41        u32 bit_offset;
  42
  43        bank_offset = GPIO_DATA_OFFSET + GPIO_BANK_OFFSET(offset);
  44        bit_offset = GPIO_BIT_OFFSET(offset);
  45        return !!(ioread32(chip->base + bank_offset) & BIT(bit_offset));
  46}
  47
  48static void __xgene_gpio_set(struct gpio_chip *gc, unsigned int offset, int val)
  49{
  50        struct xgene_gpio *chip = gpiochip_get_data(gc);
  51        unsigned long bank_offset;
  52        u32 setval, bit_offset;
  53
  54        bank_offset = GPIO_SET_DR_OFFSET + GPIO_BANK_OFFSET(offset);
  55        bit_offset = GPIO_BIT_OFFSET(offset) + XGENE_GPIOS_PER_BANK;
  56
  57        setval = ioread32(chip->base + bank_offset);
  58        if (val)
  59                setval |= BIT(bit_offset);
  60        else
  61                setval &= ~BIT(bit_offset);
  62        iowrite32(setval, chip->base + bank_offset);
  63}
  64
  65static void xgene_gpio_set(struct gpio_chip *gc, unsigned int offset, int val)
  66{
  67        struct xgene_gpio *chip = gpiochip_get_data(gc);
  68        unsigned long flags;
  69
  70        spin_lock_irqsave(&chip->lock, flags);
  71        __xgene_gpio_set(gc, offset, val);
  72        spin_unlock_irqrestore(&chip->lock, flags);
  73}
  74
  75static int xgene_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
  76{
  77        struct xgene_gpio *chip = gpiochip_get_data(gc);
  78        unsigned long bank_offset, bit_offset;
  79
  80        bank_offset = GPIO_SET_DR_OFFSET + GPIO_BANK_OFFSET(offset);
  81        bit_offset = GPIO_BIT_OFFSET(offset);
  82
  83        if (ioread32(chip->base + bank_offset) & BIT(bit_offset))
  84                return GPIO_LINE_DIRECTION_IN;
  85
  86        return GPIO_LINE_DIRECTION_OUT;
  87}
  88
  89static int xgene_gpio_dir_in(struct gpio_chip *gc, unsigned int offset)
  90{
  91        struct xgene_gpio *chip = gpiochip_get_data(gc);
  92        unsigned long flags, bank_offset;
  93        u32 dirval, bit_offset;
  94
  95        bank_offset = GPIO_SET_DR_OFFSET + GPIO_BANK_OFFSET(offset);
  96        bit_offset = GPIO_BIT_OFFSET(offset);
  97
  98        spin_lock_irqsave(&chip->lock, flags);
  99
 100        dirval = ioread32(chip->base + bank_offset);
 101        dirval |= BIT(bit_offset);
 102        iowrite32(dirval, chip->base + bank_offset);
 103
 104        spin_unlock_irqrestore(&chip->lock, flags);
 105
 106        return 0;
 107}
 108
 109static int xgene_gpio_dir_out(struct gpio_chip *gc,
 110                                        unsigned int offset, int val)
 111{
 112        struct xgene_gpio *chip = gpiochip_get_data(gc);
 113        unsigned long flags, bank_offset;
 114        u32 dirval, bit_offset;
 115
 116        bank_offset = GPIO_SET_DR_OFFSET + GPIO_BANK_OFFSET(offset);
 117        bit_offset = GPIO_BIT_OFFSET(offset);
 118
 119        spin_lock_irqsave(&chip->lock, flags);
 120
 121        dirval = ioread32(chip->base + bank_offset);
 122        dirval &= ~BIT(bit_offset);
 123        iowrite32(dirval, chip->base + bank_offset);
 124        __xgene_gpio_set(gc, offset, val);
 125
 126        spin_unlock_irqrestore(&chip->lock, flags);
 127
 128        return 0;
 129}
 130
 131static __maybe_unused int xgene_gpio_suspend(struct device *dev)
 132{
 133        struct xgene_gpio *gpio = dev_get_drvdata(dev);
 134        unsigned long bank_offset;
 135        unsigned int bank;
 136
 137        for (bank = 0; bank < XGENE_MAX_GPIO_BANKS; bank++) {
 138                bank_offset = GPIO_SET_DR_OFFSET + bank * GPIO_BANK_STRIDE;
 139                gpio->set_dr_val[bank] = ioread32(gpio->base + bank_offset);
 140        }
 141        return 0;
 142}
 143
 144static __maybe_unused int xgene_gpio_resume(struct device *dev)
 145{
 146        struct xgene_gpio *gpio = dev_get_drvdata(dev);
 147        unsigned long bank_offset;
 148        unsigned int bank;
 149
 150        for (bank = 0; bank < XGENE_MAX_GPIO_BANKS; bank++) {
 151                bank_offset = GPIO_SET_DR_OFFSET + bank * GPIO_BANK_STRIDE;
 152                iowrite32(gpio->set_dr_val[bank], gpio->base + bank_offset);
 153        }
 154        return 0;
 155}
 156
 157static SIMPLE_DEV_PM_OPS(xgene_gpio_pm, xgene_gpio_suspend, xgene_gpio_resume);
 158
 159static int xgene_gpio_probe(struct platform_device *pdev)
 160{
 161        struct xgene_gpio *gpio;
 162
 163        gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
 164        if (!gpio)
 165                return -ENOMEM;
 166
 167        gpio->base = devm_platform_ioremap_resource(pdev, 0);
 168        if (IS_ERR(gpio->base))
 169                return PTR_ERR(gpio->base);
 170
 171        gpio->chip.ngpio = XGENE_MAX_GPIOS;
 172
 173        spin_lock_init(&gpio->lock);
 174        gpio->chip.parent = &pdev->dev;
 175        gpio->chip.get_direction = xgene_gpio_get_direction;
 176        gpio->chip.direction_input = xgene_gpio_dir_in;
 177        gpio->chip.direction_output = xgene_gpio_dir_out;
 178        gpio->chip.get = xgene_gpio_get;
 179        gpio->chip.set = xgene_gpio_set;
 180        gpio->chip.label = dev_name(&pdev->dev);
 181        gpio->chip.base = -1;
 182
 183        platform_set_drvdata(pdev, gpio);
 184
 185        return devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
 186}
 187
 188static const struct of_device_id xgene_gpio_of_match[] = {
 189        { .compatible = "apm,xgene-gpio", },
 190        {},
 191};
 192
 193#ifdef CONFIG_ACPI
 194static const struct acpi_device_id xgene_gpio_acpi_match[] = {
 195        { "APMC0D14", 0 },
 196        { },
 197};
 198#endif
 199
 200static struct platform_driver xgene_gpio_driver = {
 201        .driver = {
 202                .name = "xgene-gpio",
 203                .of_match_table = xgene_gpio_of_match,
 204                .acpi_match_table = ACPI_PTR(xgene_gpio_acpi_match),
 205                .pm     = &xgene_gpio_pm,
 206        },
 207        .probe = xgene_gpio_probe,
 208};
 209builtin_platform_driver(xgene_gpio_driver);
 210