cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

gpio-mb86s7x.c (5771B)


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