18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2019 SiFive
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/bitops.h>
78c2ecf20Sopenharmony_ci#include <linux/device.h>
88c2ecf20Sopenharmony_ci#include <linux/errno.h>
98c2ecf20Sopenharmony_ci#include <linux/of_irq.h>
108c2ecf20Sopenharmony_ci#include <linux/gpio/driver.h>
118c2ecf20Sopenharmony_ci#include <linux/init.h>
128c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
138c2ecf20Sopenharmony_ci#include <linux/slab.h>
148c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
158c2ecf20Sopenharmony_ci#include <linux/regmap.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#define SIFIVE_GPIO_INPUT_VAL	0x00
188c2ecf20Sopenharmony_ci#define SIFIVE_GPIO_INPUT_EN	0x04
198c2ecf20Sopenharmony_ci#define SIFIVE_GPIO_OUTPUT_EN	0x08
208c2ecf20Sopenharmony_ci#define SIFIVE_GPIO_OUTPUT_VAL	0x0C
218c2ecf20Sopenharmony_ci#define SIFIVE_GPIO_RISE_IE	0x18
228c2ecf20Sopenharmony_ci#define SIFIVE_GPIO_RISE_IP	0x1C
238c2ecf20Sopenharmony_ci#define SIFIVE_GPIO_FALL_IE	0x20
248c2ecf20Sopenharmony_ci#define SIFIVE_GPIO_FALL_IP	0x24
258c2ecf20Sopenharmony_ci#define SIFIVE_GPIO_HIGH_IE	0x28
268c2ecf20Sopenharmony_ci#define SIFIVE_GPIO_HIGH_IP	0x2C
278c2ecf20Sopenharmony_ci#define SIFIVE_GPIO_LOW_IE	0x30
288c2ecf20Sopenharmony_ci#define SIFIVE_GPIO_LOW_IP	0x34
298c2ecf20Sopenharmony_ci#define SIFIVE_GPIO_OUTPUT_XOR	0x40
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#define SIFIVE_GPIO_MAX		32
328c2ecf20Sopenharmony_ci#define SIFIVE_GPIO_IRQ_OFFSET	7
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistruct sifive_gpio {
358c2ecf20Sopenharmony_ci	void __iomem		*base;
368c2ecf20Sopenharmony_ci	struct gpio_chip	gc;
378c2ecf20Sopenharmony_ci	struct regmap		*regs;
388c2ecf20Sopenharmony_ci	unsigned long		irq_state;
398c2ecf20Sopenharmony_ci	unsigned int		trigger[SIFIVE_GPIO_MAX];
408c2ecf20Sopenharmony_ci	unsigned int		irq_parent[SIFIVE_GPIO_MAX];
418c2ecf20Sopenharmony_ci};
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_cistatic void sifive_gpio_set_ie(struct sifive_gpio *chip, unsigned int offset)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	unsigned long flags;
468c2ecf20Sopenharmony_ci	unsigned int trigger;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	spin_lock_irqsave(&chip->gc.bgpio_lock, flags);
498c2ecf20Sopenharmony_ci	trigger = (chip->irq_state & BIT(offset)) ? chip->trigger[offset] : 0;
508c2ecf20Sopenharmony_ci	regmap_update_bits(chip->regs, SIFIVE_GPIO_RISE_IE, BIT(offset),
518c2ecf20Sopenharmony_ci			   (trigger & IRQ_TYPE_EDGE_RISING) ? BIT(offset) : 0);
528c2ecf20Sopenharmony_ci	regmap_update_bits(chip->regs, SIFIVE_GPIO_FALL_IE, BIT(offset),
538c2ecf20Sopenharmony_ci			   (trigger & IRQ_TYPE_EDGE_FALLING) ? BIT(offset) : 0);
548c2ecf20Sopenharmony_ci	regmap_update_bits(chip->regs, SIFIVE_GPIO_HIGH_IE, BIT(offset),
558c2ecf20Sopenharmony_ci			   (trigger & IRQ_TYPE_LEVEL_HIGH) ? BIT(offset) : 0);
568c2ecf20Sopenharmony_ci	regmap_update_bits(chip->regs, SIFIVE_GPIO_LOW_IE, BIT(offset),
578c2ecf20Sopenharmony_ci			   (trigger & IRQ_TYPE_LEVEL_LOW) ? BIT(offset) : 0);
588c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&chip->gc.bgpio_lock, flags);
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistatic int sifive_gpio_irq_set_type(struct irq_data *d, unsigned int trigger)
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
648c2ecf20Sopenharmony_ci	struct sifive_gpio *chip = gpiochip_get_data(gc);
658c2ecf20Sopenharmony_ci	int offset = irqd_to_hwirq(d);
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	if (offset < 0 || offset >= gc->ngpio)
688c2ecf20Sopenharmony_ci		return -EINVAL;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	chip->trigger[offset] = trigger;
718c2ecf20Sopenharmony_ci	sifive_gpio_set_ie(chip, offset);
728c2ecf20Sopenharmony_ci	return 0;
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cistatic void sifive_gpio_irq_enable(struct irq_data *d)
768c2ecf20Sopenharmony_ci{
778c2ecf20Sopenharmony_ci	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
788c2ecf20Sopenharmony_ci	struct sifive_gpio *chip = gpiochip_get_data(gc);
798c2ecf20Sopenharmony_ci	int offset = irqd_to_hwirq(d) % SIFIVE_GPIO_MAX;
808c2ecf20Sopenharmony_ci	u32 bit = BIT(offset);
818c2ecf20Sopenharmony_ci	unsigned long flags;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	irq_chip_enable_parent(d);
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	/* Switch to input */
868c2ecf20Sopenharmony_ci	gc->direction_input(gc, offset);
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	spin_lock_irqsave(&gc->bgpio_lock, flags);
898c2ecf20Sopenharmony_ci	/* Clear any sticky pending interrupts */
908c2ecf20Sopenharmony_ci	regmap_write(chip->regs, SIFIVE_GPIO_RISE_IP, bit);
918c2ecf20Sopenharmony_ci	regmap_write(chip->regs, SIFIVE_GPIO_FALL_IP, bit);
928c2ecf20Sopenharmony_ci	regmap_write(chip->regs, SIFIVE_GPIO_HIGH_IP, bit);
938c2ecf20Sopenharmony_ci	regmap_write(chip->regs, SIFIVE_GPIO_LOW_IP, bit);
948c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&gc->bgpio_lock, flags);
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	/* Enable interrupts */
978c2ecf20Sopenharmony_ci	assign_bit(offset, &chip->irq_state, 1);
988c2ecf20Sopenharmony_ci	sifive_gpio_set_ie(chip, offset);
998c2ecf20Sopenharmony_ci}
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_cistatic void sifive_gpio_irq_disable(struct irq_data *d)
1028c2ecf20Sopenharmony_ci{
1038c2ecf20Sopenharmony_ci	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
1048c2ecf20Sopenharmony_ci	struct sifive_gpio *chip = gpiochip_get_data(gc);
1058c2ecf20Sopenharmony_ci	int offset = irqd_to_hwirq(d) % SIFIVE_GPIO_MAX;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	assign_bit(offset, &chip->irq_state, 0);
1088c2ecf20Sopenharmony_ci	sifive_gpio_set_ie(chip, offset);
1098c2ecf20Sopenharmony_ci	irq_chip_disable_parent(d);
1108c2ecf20Sopenharmony_ci}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_cistatic void sifive_gpio_irq_eoi(struct irq_data *d)
1138c2ecf20Sopenharmony_ci{
1148c2ecf20Sopenharmony_ci	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
1158c2ecf20Sopenharmony_ci	struct sifive_gpio *chip = gpiochip_get_data(gc);
1168c2ecf20Sopenharmony_ci	int offset = irqd_to_hwirq(d) % SIFIVE_GPIO_MAX;
1178c2ecf20Sopenharmony_ci	u32 bit = BIT(offset);
1188c2ecf20Sopenharmony_ci	unsigned long flags;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	spin_lock_irqsave(&gc->bgpio_lock, flags);
1218c2ecf20Sopenharmony_ci	/* Clear all pending interrupts */
1228c2ecf20Sopenharmony_ci	regmap_write(chip->regs, SIFIVE_GPIO_RISE_IP, bit);
1238c2ecf20Sopenharmony_ci	regmap_write(chip->regs, SIFIVE_GPIO_FALL_IP, bit);
1248c2ecf20Sopenharmony_ci	regmap_write(chip->regs, SIFIVE_GPIO_HIGH_IP, bit);
1258c2ecf20Sopenharmony_ci	regmap_write(chip->regs, SIFIVE_GPIO_LOW_IP, bit);
1268c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&gc->bgpio_lock, flags);
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	irq_chip_eoi_parent(d);
1298c2ecf20Sopenharmony_ci}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_cistatic struct irq_chip sifive_gpio_irqchip = {
1328c2ecf20Sopenharmony_ci	.name		= "sifive-gpio",
1338c2ecf20Sopenharmony_ci	.irq_set_type	= sifive_gpio_irq_set_type,
1348c2ecf20Sopenharmony_ci	.irq_mask	= irq_chip_mask_parent,
1358c2ecf20Sopenharmony_ci	.irq_unmask	= irq_chip_unmask_parent,
1368c2ecf20Sopenharmony_ci	.irq_enable	= sifive_gpio_irq_enable,
1378c2ecf20Sopenharmony_ci	.irq_disable	= sifive_gpio_irq_disable,
1388c2ecf20Sopenharmony_ci	.irq_eoi	= sifive_gpio_irq_eoi,
1398c2ecf20Sopenharmony_ci};
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_cistatic int sifive_gpio_child_to_parent_hwirq(struct gpio_chip *gc,
1428c2ecf20Sopenharmony_ci					     unsigned int child,
1438c2ecf20Sopenharmony_ci					     unsigned int child_type,
1448c2ecf20Sopenharmony_ci					     unsigned int *parent,
1458c2ecf20Sopenharmony_ci					     unsigned int *parent_type)
1468c2ecf20Sopenharmony_ci{
1478c2ecf20Sopenharmony_ci	*parent_type = IRQ_TYPE_NONE;
1488c2ecf20Sopenharmony_ci	*parent = child + SIFIVE_GPIO_IRQ_OFFSET;
1498c2ecf20Sopenharmony_ci	return 0;
1508c2ecf20Sopenharmony_ci}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_cistatic const struct regmap_config sifive_gpio_regmap_config = {
1538c2ecf20Sopenharmony_ci	.reg_bits = 32,
1548c2ecf20Sopenharmony_ci	.reg_stride = 4,
1558c2ecf20Sopenharmony_ci	.val_bits = 32,
1568c2ecf20Sopenharmony_ci	.fast_io = true,
1578c2ecf20Sopenharmony_ci	.disable_locking = true,
1588c2ecf20Sopenharmony_ci};
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_cistatic int sifive_gpio_probe(struct platform_device *pdev)
1618c2ecf20Sopenharmony_ci{
1628c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
1638c2ecf20Sopenharmony_ci	struct device_node *node = pdev->dev.of_node;
1648c2ecf20Sopenharmony_ci	struct device_node *irq_parent;
1658c2ecf20Sopenharmony_ci	struct irq_domain *parent;
1668c2ecf20Sopenharmony_ci	struct gpio_irq_chip *girq;
1678c2ecf20Sopenharmony_ci	struct sifive_gpio *chip;
1688c2ecf20Sopenharmony_ci	int ret, ngpio;
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
1718c2ecf20Sopenharmony_ci	if (!chip)
1728c2ecf20Sopenharmony_ci		return -ENOMEM;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	chip->base = devm_platform_ioremap_resource(pdev, 0);
1758c2ecf20Sopenharmony_ci	if (IS_ERR(chip->base)) {
1768c2ecf20Sopenharmony_ci		dev_err(dev, "failed to allocate device memory\n");
1778c2ecf20Sopenharmony_ci		return PTR_ERR(chip->base);
1788c2ecf20Sopenharmony_ci	}
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	chip->regs = devm_regmap_init_mmio(dev, chip->base,
1818c2ecf20Sopenharmony_ci					   &sifive_gpio_regmap_config);
1828c2ecf20Sopenharmony_ci	if (IS_ERR(chip->regs))
1838c2ecf20Sopenharmony_ci		return PTR_ERR(chip->regs);
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	ngpio = of_irq_count(node);
1868c2ecf20Sopenharmony_ci	if (ngpio > SIFIVE_GPIO_MAX) {
1878c2ecf20Sopenharmony_ci		dev_err(dev, "Too many GPIO interrupts (max=%d)\n",
1888c2ecf20Sopenharmony_ci			SIFIVE_GPIO_MAX);
1898c2ecf20Sopenharmony_ci		return -ENXIO;
1908c2ecf20Sopenharmony_ci	}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	irq_parent = of_irq_find_parent(node);
1938c2ecf20Sopenharmony_ci	if (!irq_parent) {
1948c2ecf20Sopenharmony_ci		dev_err(dev, "no IRQ parent node\n");
1958c2ecf20Sopenharmony_ci		return -ENODEV;
1968c2ecf20Sopenharmony_ci	}
1978c2ecf20Sopenharmony_ci	parent = irq_find_host(irq_parent);
1988c2ecf20Sopenharmony_ci	of_node_put(irq_parent);
1998c2ecf20Sopenharmony_ci	if (!parent) {
2008c2ecf20Sopenharmony_ci		dev_err(dev, "no IRQ parent domain\n");
2018c2ecf20Sopenharmony_ci		return -ENODEV;
2028c2ecf20Sopenharmony_ci	}
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	ret = bgpio_init(&chip->gc, dev, 4,
2058c2ecf20Sopenharmony_ci			 chip->base + SIFIVE_GPIO_INPUT_VAL,
2068c2ecf20Sopenharmony_ci			 chip->base + SIFIVE_GPIO_OUTPUT_VAL,
2078c2ecf20Sopenharmony_ci			 NULL,
2088c2ecf20Sopenharmony_ci			 chip->base + SIFIVE_GPIO_OUTPUT_EN,
2098c2ecf20Sopenharmony_ci			 chip->base + SIFIVE_GPIO_INPUT_EN,
2108c2ecf20Sopenharmony_ci			 BGPIOF_READ_OUTPUT_REG_SET);
2118c2ecf20Sopenharmony_ci	if (ret) {
2128c2ecf20Sopenharmony_ci		dev_err(dev, "unable to init generic GPIO\n");
2138c2ecf20Sopenharmony_ci		return ret;
2148c2ecf20Sopenharmony_ci	}
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	/* Disable all GPIO interrupts before enabling parent interrupts */
2178c2ecf20Sopenharmony_ci	regmap_write(chip->regs, SIFIVE_GPIO_RISE_IE, 0);
2188c2ecf20Sopenharmony_ci	regmap_write(chip->regs, SIFIVE_GPIO_FALL_IE, 0);
2198c2ecf20Sopenharmony_ci	regmap_write(chip->regs, SIFIVE_GPIO_HIGH_IE, 0);
2208c2ecf20Sopenharmony_ci	regmap_write(chip->regs, SIFIVE_GPIO_LOW_IE, 0);
2218c2ecf20Sopenharmony_ci	chip->irq_state = 0;
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	chip->gc.base = -1;
2248c2ecf20Sopenharmony_ci	chip->gc.ngpio = ngpio;
2258c2ecf20Sopenharmony_ci	chip->gc.label = dev_name(dev);
2268c2ecf20Sopenharmony_ci	chip->gc.parent = dev;
2278c2ecf20Sopenharmony_ci	chip->gc.owner = THIS_MODULE;
2288c2ecf20Sopenharmony_ci	girq = &chip->gc.irq;
2298c2ecf20Sopenharmony_ci	girq->chip = &sifive_gpio_irqchip;
2308c2ecf20Sopenharmony_ci	girq->fwnode = of_node_to_fwnode(node);
2318c2ecf20Sopenharmony_ci	girq->parent_domain = parent;
2328c2ecf20Sopenharmony_ci	girq->child_to_parent_hwirq = sifive_gpio_child_to_parent_hwirq;
2338c2ecf20Sopenharmony_ci	girq->handler = handle_bad_irq;
2348c2ecf20Sopenharmony_ci	girq->default_type = IRQ_TYPE_NONE;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, chip);
2378c2ecf20Sopenharmony_ci	return gpiochip_add_data(&chip->gc, chip);
2388c2ecf20Sopenharmony_ci}
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_cistatic const struct of_device_id sifive_gpio_match[] = {
2418c2ecf20Sopenharmony_ci	{ .compatible = "sifive,gpio0" },
2428c2ecf20Sopenharmony_ci	{ .compatible = "sifive,fu540-c000-gpio" },
2438c2ecf20Sopenharmony_ci	{ },
2448c2ecf20Sopenharmony_ci};
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_cistatic struct platform_driver sifive_gpio_driver = {
2478c2ecf20Sopenharmony_ci	.probe		= sifive_gpio_probe,
2488c2ecf20Sopenharmony_ci	.driver = {
2498c2ecf20Sopenharmony_ci		.name	= "sifive_gpio",
2508c2ecf20Sopenharmony_ci		.of_match_table = of_match_ptr(sifive_gpio_match),
2518c2ecf20Sopenharmony_ci	},
2528c2ecf20Sopenharmony_ci};
2538c2ecf20Sopenharmony_cibuiltin_platform_driver(sifive_gpio_driver)
254