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-visconti.c (5191B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Toshiba Visconti GPIO Support
      4 *
      5 * (C) Copyright 2020 Toshiba Electronic Devices & Storage Corporation
      6 * (C) Copyright 2020 TOSHIBA CORPORATION
      7 *
      8 * Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
      9 */
     10
     11#include <linux/gpio/driver.h>
     12#include <linux/init.h>
     13#include <linux/interrupt.h>
     14#include <linux/module.h>
     15#include <linux/io.h>
     16#include <linux/of_irq.h>
     17#include <linux/platform_device.h>
     18#include <linux/bitops.h>
     19
     20/* register offset */
     21#define GPIO_DIR	0x00
     22#define GPIO_IDATA	0x08
     23#define GPIO_ODATA	0x10
     24#define GPIO_OSET	0x18
     25#define GPIO_OCLR	0x20
     26#define GPIO_INTMODE	0x30
     27
     28#define BASE_HW_IRQ 24
     29
     30struct visconti_gpio {
     31	void __iomem *base;
     32	spinlock_t lock; /* protect gpio register */
     33	struct gpio_chip gpio_chip;
     34	struct irq_chip irq_chip;
     35};
     36
     37static int visconti_gpio_irq_set_type(struct irq_data *d, unsigned int type)
     38{
     39	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
     40	struct visconti_gpio *priv = gpiochip_get_data(gc);
     41	u32 offset = irqd_to_hwirq(d);
     42	u32 bit = BIT(offset);
     43	u32 intc_type = IRQ_TYPE_EDGE_RISING;
     44	u32 intmode, odata;
     45	int ret = 0;
     46	unsigned long flags;
     47
     48	spin_lock_irqsave(&priv->lock, flags);
     49
     50	odata = readl(priv->base + GPIO_ODATA);
     51	intmode = readl(priv->base + GPIO_INTMODE);
     52
     53	switch (type) {
     54	case IRQ_TYPE_EDGE_RISING:
     55		odata &= ~bit;
     56		intmode &= ~bit;
     57		break;
     58	case IRQ_TYPE_EDGE_FALLING:
     59		odata |= bit;
     60		intmode &= ~bit;
     61		break;
     62	case IRQ_TYPE_EDGE_BOTH:
     63		intmode |= bit;
     64		break;
     65	case IRQ_TYPE_LEVEL_HIGH:
     66		intc_type = IRQ_TYPE_LEVEL_HIGH;
     67		odata &= ~bit;
     68		intmode &= ~bit;
     69		break;
     70	case IRQ_TYPE_LEVEL_LOW:
     71		intc_type = IRQ_TYPE_LEVEL_HIGH;
     72		odata |= bit;
     73		intmode &= ~bit;
     74		break;
     75	default:
     76		ret = -EINVAL;
     77		goto err;
     78	}
     79
     80	writel(odata, priv->base + GPIO_ODATA);
     81	writel(intmode, priv->base + GPIO_INTMODE);
     82	irq_set_irq_type(offset, intc_type);
     83
     84	ret = irq_chip_set_type_parent(d, type);
     85err:
     86	spin_unlock_irqrestore(&priv->lock, flags);
     87	return ret;
     88}
     89
     90static int visconti_gpio_child_to_parent_hwirq(struct gpio_chip *gc,
     91					       unsigned int child,
     92					       unsigned int child_type,
     93					       unsigned int *parent,
     94					       unsigned int *parent_type)
     95{
     96	/* Interrupts 0..15 mapped to interrupts 24..39 on the GIC */
     97	if (child < 16) {
     98		/* All these interrupts are level high in the CPU */
     99		*parent_type = IRQ_TYPE_LEVEL_HIGH;
    100		*parent = child + BASE_HW_IRQ;
    101		return 0;
    102	}
    103	return -EINVAL;
    104}
    105
    106static void *visconti_gpio_populate_parent_fwspec(struct gpio_chip *chip,
    107						  unsigned int parent_hwirq,
    108						  unsigned int parent_type)
    109{
    110	struct irq_fwspec *fwspec;
    111
    112	fwspec = kmalloc(sizeof(*fwspec), GFP_KERNEL);
    113	if (!fwspec)
    114		return NULL;
    115
    116	fwspec->fwnode = chip->irq.parent_domain->fwnode;
    117	fwspec->param_count = 3;
    118	fwspec->param[0] = 0;
    119	fwspec->param[1] = parent_hwirq;
    120	fwspec->param[2] = parent_type;
    121
    122	return fwspec;
    123}
    124
    125static int visconti_gpio_probe(struct platform_device *pdev)
    126{
    127	struct device *dev = &pdev->dev;
    128	struct visconti_gpio *priv;
    129	struct irq_chip *irq_chip;
    130	struct gpio_irq_chip *girq;
    131	struct irq_domain *parent;
    132	struct device_node *irq_parent;
    133	int ret;
    134
    135	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
    136	if (!priv)
    137		return -ENOMEM;
    138
    139	spin_lock_init(&priv->lock);
    140
    141	priv->base = devm_platform_ioremap_resource(pdev, 0);
    142	if (IS_ERR(priv->base))
    143		return PTR_ERR(priv->base);
    144
    145	irq_parent = of_irq_find_parent(dev->of_node);
    146	if (!irq_parent) {
    147		dev_err(dev, "No IRQ parent node\n");
    148		return -ENODEV;
    149	}
    150
    151	parent = irq_find_host(irq_parent);
    152	of_node_put(irq_parent);
    153	if (!parent) {
    154		dev_err(dev, "No IRQ parent domain\n");
    155		return -ENODEV;
    156	}
    157
    158	ret = bgpio_init(&priv->gpio_chip, dev, 4,
    159			 priv->base + GPIO_IDATA,
    160			 priv->base + GPIO_OSET,
    161			 priv->base + GPIO_OCLR,
    162			 priv->base + GPIO_DIR,
    163			 NULL,
    164			 0);
    165	if (ret) {
    166		dev_err(dev, "unable to init generic GPIO\n");
    167		return ret;
    168	}
    169
    170	irq_chip = &priv->irq_chip;
    171	irq_chip->name = dev_name(dev);
    172	irq_chip->irq_mask = irq_chip_mask_parent;
    173	irq_chip->irq_unmask = irq_chip_unmask_parent;
    174	irq_chip->irq_eoi = irq_chip_eoi_parent;
    175	irq_chip->irq_set_type = visconti_gpio_irq_set_type;
    176	irq_chip->flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND;
    177
    178	girq = &priv->gpio_chip.irq;
    179	girq->chip = irq_chip;
    180	girq->fwnode = of_node_to_fwnode(dev->of_node);
    181	girq->parent_domain = parent;
    182	girq->child_to_parent_hwirq = visconti_gpio_child_to_parent_hwirq;
    183	girq->populate_parent_alloc_arg = visconti_gpio_populate_parent_fwspec;
    184	girq->default_type = IRQ_TYPE_NONE;
    185	girq->handler = handle_level_irq;
    186
    187	return devm_gpiochip_add_data(dev, &priv->gpio_chip, priv);
    188}
    189
    190static const struct of_device_id visconti_gpio_of_match[] = {
    191	{ .compatible = "toshiba,gpio-tmpv7708", },
    192	{ /* end of table */ }
    193};
    194MODULE_DEVICE_TABLE(of, visconti_gpio_of_match);
    195
    196static struct platform_driver visconti_gpio_driver = {
    197	.probe		= visconti_gpio_probe,
    198	.driver		= {
    199		.name	= "visconti_gpio",
    200		.of_match_table = of_match_ptr(visconti_gpio_of_match),
    201	}
    202};
    203module_platform_driver(visconti_gpio_driver);
    204
    205MODULE_AUTHOR("Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>");
    206MODULE_DESCRIPTION("Toshiba Visconti GPIO Driver");
    207MODULE_LICENSE("GPL v2");