xref: /openbmc/linux/drivers/gpio/gpio-visconti.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
12ad74f40SNobuhiro Iwamatsu // SPDX-License-Identifier: GPL-2.0
22ad74f40SNobuhiro Iwamatsu /*
32ad74f40SNobuhiro Iwamatsu  * Toshiba Visconti GPIO Support
42ad74f40SNobuhiro Iwamatsu  *
52ad74f40SNobuhiro Iwamatsu  * (C) Copyright 2020 Toshiba Electronic Devices & Storage Corporation
62ad74f40SNobuhiro Iwamatsu  * (C) Copyright 2020 TOSHIBA CORPORATION
72ad74f40SNobuhiro Iwamatsu  *
82ad74f40SNobuhiro Iwamatsu  * Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
92ad74f40SNobuhiro Iwamatsu  */
102ad74f40SNobuhiro Iwamatsu 
112ad74f40SNobuhiro Iwamatsu #include <linux/gpio/driver.h>
122ad74f40SNobuhiro Iwamatsu #include <linux/init.h>
132ad74f40SNobuhiro Iwamatsu #include <linux/interrupt.h>
142ad74f40SNobuhiro Iwamatsu #include <linux/module.h>
152ad74f40SNobuhiro Iwamatsu #include <linux/io.h>
162ad74f40SNobuhiro Iwamatsu #include <linux/of_irq.h>
172ad74f40SNobuhiro Iwamatsu #include <linux/platform_device.h>
18*5cf3e019SLinus Walleij #include <linux/seq_file.h>
192ad74f40SNobuhiro Iwamatsu #include <linux/bitops.h>
202ad74f40SNobuhiro Iwamatsu 
212ad74f40SNobuhiro Iwamatsu /* register offset */
222ad74f40SNobuhiro Iwamatsu #define GPIO_DIR	0x00
232ad74f40SNobuhiro Iwamatsu #define GPIO_IDATA	0x08
242ad74f40SNobuhiro Iwamatsu #define GPIO_ODATA	0x10
252ad74f40SNobuhiro Iwamatsu #define GPIO_OSET	0x18
262ad74f40SNobuhiro Iwamatsu #define GPIO_OCLR	0x20
272ad74f40SNobuhiro Iwamatsu #define GPIO_INTMODE	0x30
282ad74f40SNobuhiro Iwamatsu 
292ad74f40SNobuhiro Iwamatsu #define BASE_HW_IRQ 24
302ad74f40SNobuhiro Iwamatsu 
312ad74f40SNobuhiro Iwamatsu struct visconti_gpio {
322ad74f40SNobuhiro Iwamatsu 	void __iomem *base;
332ad74f40SNobuhiro Iwamatsu 	spinlock_t lock; /* protect gpio register */
342ad74f40SNobuhiro Iwamatsu 	struct gpio_chip gpio_chip;
35*5cf3e019SLinus Walleij 	struct device *dev;
362ad74f40SNobuhiro Iwamatsu };
372ad74f40SNobuhiro Iwamatsu 
visconti_gpio_irq_set_type(struct irq_data * d,unsigned int type)382ad74f40SNobuhiro Iwamatsu static int visconti_gpio_irq_set_type(struct irq_data *d, unsigned int type)
392ad74f40SNobuhiro Iwamatsu {
402ad74f40SNobuhiro Iwamatsu 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
412ad74f40SNobuhiro Iwamatsu 	struct visconti_gpio *priv = gpiochip_get_data(gc);
422ad74f40SNobuhiro Iwamatsu 	u32 offset = irqd_to_hwirq(d);
432ad74f40SNobuhiro Iwamatsu 	u32 bit = BIT(offset);
442ad74f40SNobuhiro Iwamatsu 	u32 intc_type = IRQ_TYPE_EDGE_RISING;
452ad74f40SNobuhiro Iwamatsu 	u32 intmode, odata;
462ad74f40SNobuhiro Iwamatsu 	int ret = 0;
472ad74f40SNobuhiro Iwamatsu 	unsigned long flags;
482ad74f40SNobuhiro Iwamatsu 
492ad74f40SNobuhiro Iwamatsu 	spin_lock_irqsave(&priv->lock, flags);
502ad74f40SNobuhiro Iwamatsu 
512ad74f40SNobuhiro Iwamatsu 	odata = readl(priv->base + GPIO_ODATA);
522ad74f40SNobuhiro Iwamatsu 	intmode = readl(priv->base + GPIO_INTMODE);
532ad74f40SNobuhiro Iwamatsu 
542ad74f40SNobuhiro Iwamatsu 	switch (type) {
552ad74f40SNobuhiro Iwamatsu 	case IRQ_TYPE_EDGE_RISING:
562ad74f40SNobuhiro Iwamatsu 		odata &= ~bit;
572ad74f40SNobuhiro Iwamatsu 		intmode &= ~bit;
582ad74f40SNobuhiro Iwamatsu 		break;
592ad74f40SNobuhiro Iwamatsu 	case IRQ_TYPE_EDGE_FALLING:
602ad74f40SNobuhiro Iwamatsu 		odata |= bit;
612ad74f40SNobuhiro Iwamatsu 		intmode &= ~bit;
622ad74f40SNobuhiro Iwamatsu 		break;
632ad74f40SNobuhiro Iwamatsu 	case IRQ_TYPE_EDGE_BOTH:
642ad74f40SNobuhiro Iwamatsu 		intmode |= bit;
652ad74f40SNobuhiro Iwamatsu 		break;
662ad74f40SNobuhiro Iwamatsu 	case IRQ_TYPE_LEVEL_HIGH:
672ad74f40SNobuhiro Iwamatsu 		intc_type = IRQ_TYPE_LEVEL_HIGH;
682ad74f40SNobuhiro Iwamatsu 		odata &= ~bit;
692ad74f40SNobuhiro Iwamatsu 		intmode &= ~bit;
702ad74f40SNobuhiro Iwamatsu 		break;
712ad74f40SNobuhiro Iwamatsu 	case IRQ_TYPE_LEVEL_LOW:
722ad74f40SNobuhiro Iwamatsu 		intc_type = IRQ_TYPE_LEVEL_HIGH;
732ad74f40SNobuhiro Iwamatsu 		odata |= bit;
742ad74f40SNobuhiro Iwamatsu 		intmode &= ~bit;
752ad74f40SNobuhiro Iwamatsu 		break;
762ad74f40SNobuhiro Iwamatsu 	default:
772ad74f40SNobuhiro Iwamatsu 		ret = -EINVAL;
782ad74f40SNobuhiro Iwamatsu 		goto err;
792ad74f40SNobuhiro Iwamatsu 	}
802ad74f40SNobuhiro Iwamatsu 
812ad74f40SNobuhiro Iwamatsu 	writel(odata, priv->base + GPIO_ODATA);
822ad74f40SNobuhiro Iwamatsu 	writel(intmode, priv->base + GPIO_INTMODE);
832ad74f40SNobuhiro Iwamatsu 	irq_set_irq_type(offset, intc_type);
842ad74f40SNobuhiro Iwamatsu 
852ad74f40SNobuhiro Iwamatsu 	ret = irq_chip_set_type_parent(d, type);
862ad74f40SNobuhiro Iwamatsu err:
872ad74f40SNobuhiro Iwamatsu 	spin_unlock_irqrestore(&priv->lock, flags);
882ad74f40SNobuhiro Iwamatsu 	return ret;
892ad74f40SNobuhiro Iwamatsu }
902ad74f40SNobuhiro Iwamatsu 
visconti_gpio_child_to_parent_hwirq(struct gpio_chip * gc,unsigned int child,unsigned int child_type,unsigned int * parent,unsigned int * parent_type)912ad74f40SNobuhiro Iwamatsu static int visconti_gpio_child_to_parent_hwirq(struct gpio_chip *gc,
922ad74f40SNobuhiro Iwamatsu 					       unsigned int child,
932ad74f40SNobuhiro Iwamatsu 					       unsigned int child_type,
942ad74f40SNobuhiro Iwamatsu 					       unsigned int *parent,
952ad74f40SNobuhiro Iwamatsu 					       unsigned int *parent_type)
962ad74f40SNobuhiro Iwamatsu {
972ad74f40SNobuhiro Iwamatsu 	/* Interrupts 0..15 mapped to interrupts 24..39 on the GIC */
982ad74f40SNobuhiro Iwamatsu 	if (child < 16) {
992ad74f40SNobuhiro Iwamatsu 		/* All these interrupts are level high in the CPU */
1002ad74f40SNobuhiro Iwamatsu 		*parent_type = IRQ_TYPE_LEVEL_HIGH;
1012ad74f40SNobuhiro Iwamatsu 		*parent = child + BASE_HW_IRQ;
1022ad74f40SNobuhiro Iwamatsu 		return 0;
1032ad74f40SNobuhiro Iwamatsu 	}
1042ad74f40SNobuhiro Iwamatsu 	return -EINVAL;
1052ad74f40SNobuhiro Iwamatsu }
1062ad74f40SNobuhiro Iwamatsu 
visconti_gpio_populate_parent_fwspec(struct gpio_chip * chip,union gpio_irq_fwspec * gfwspec,unsigned int parent_hwirq,unsigned int parent_type)10791a29af4SMarc Zyngier static int visconti_gpio_populate_parent_fwspec(struct gpio_chip *chip,
10891a29af4SMarc Zyngier 						union gpio_irq_fwspec *gfwspec,
1092ad74f40SNobuhiro Iwamatsu 						unsigned int parent_hwirq,
1102ad74f40SNobuhiro Iwamatsu 						unsigned int parent_type)
1112ad74f40SNobuhiro Iwamatsu {
11291a29af4SMarc Zyngier 	struct irq_fwspec *fwspec = &gfwspec->fwspec;
1132ad74f40SNobuhiro Iwamatsu 
1142ad74f40SNobuhiro Iwamatsu 	fwspec->fwnode = chip->irq.parent_domain->fwnode;
1152ad74f40SNobuhiro Iwamatsu 	fwspec->param_count = 3;
1162ad74f40SNobuhiro Iwamatsu 	fwspec->param[0] = 0;
1172ad74f40SNobuhiro Iwamatsu 	fwspec->param[1] = parent_hwirq;
1182ad74f40SNobuhiro Iwamatsu 	fwspec->param[2] = parent_type;
1192ad74f40SNobuhiro Iwamatsu 
12091a29af4SMarc Zyngier 	return 0;
1212ad74f40SNobuhiro Iwamatsu }
1222ad74f40SNobuhiro Iwamatsu 
visconti_gpio_mask_irq(struct irq_data * d)123*5cf3e019SLinus Walleij static void visconti_gpio_mask_irq(struct irq_data *d)
124*5cf3e019SLinus Walleij {
125*5cf3e019SLinus Walleij 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
126*5cf3e019SLinus Walleij 
127*5cf3e019SLinus Walleij 	irq_chip_mask_parent(d);
128*5cf3e019SLinus Walleij 	gpiochip_disable_irq(gc, irqd_to_hwirq(d));
129*5cf3e019SLinus Walleij }
130*5cf3e019SLinus Walleij 
visconti_gpio_unmask_irq(struct irq_data * d)131*5cf3e019SLinus Walleij static void visconti_gpio_unmask_irq(struct irq_data *d)
132*5cf3e019SLinus Walleij {
133*5cf3e019SLinus Walleij 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
134*5cf3e019SLinus Walleij 
135*5cf3e019SLinus Walleij 	gpiochip_enable_irq(gc, irqd_to_hwirq(d));
136*5cf3e019SLinus Walleij 	irq_chip_unmask_parent(d);
137*5cf3e019SLinus Walleij }
138*5cf3e019SLinus Walleij 
visconti_gpio_irq_print_chip(struct irq_data * d,struct seq_file * p)139*5cf3e019SLinus Walleij static void visconti_gpio_irq_print_chip(struct irq_data *d, struct seq_file *p)
140*5cf3e019SLinus Walleij {
141*5cf3e019SLinus Walleij 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
142*5cf3e019SLinus Walleij 	struct visconti_gpio *priv = gpiochip_get_data(gc);
143*5cf3e019SLinus Walleij 
144*5cf3e019SLinus Walleij 	seq_printf(p, dev_name(priv->dev));
145*5cf3e019SLinus Walleij }
146*5cf3e019SLinus Walleij 
147*5cf3e019SLinus Walleij static const struct irq_chip visconti_gpio_irq_chip = {
148*5cf3e019SLinus Walleij 	.irq_mask = visconti_gpio_mask_irq,
149*5cf3e019SLinus Walleij 	.irq_unmask = visconti_gpio_unmask_irq,
150*5cf3e019SLinus Walleij 	.irq_eoi = irq_chip_eoi_parent,
151*5cf3e019SLinus Walleij 	.irq_set_type = visconti_gpio_irq_set_type,
152*5cf3e019SLinus Walleij 	.irq_print_chip = visconti_gpio_irq_print_chip,
153*5cf3e019SLinus Walleij 	.flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND |
154*5cf3e019SLinus Walleij 		 IRQCHIP_IMMUTABLE,
155*5cf3e019SLinus Walleij 	GPIOCHIP_IRQ_RESOURCE_HELPERS,
156*5cf3e019SLinus Walleij };
157*5cf3e019SLinus Walleij 
visconti_gpio_probe(struct platform_device * pdev)1582ad74f40SNobuhiro Iwamatsu static int visconti_gpio_probe(struct platform_device *pdev)
1592ad74f40SNobuhiro Iwamatsu {
1602ad74f40SNobuhiro Iwamatsu 	struct device *dev = &pdev->dev;
1612ad74f40SNobuhiro Iwamatsu 	struct visconti_gpio *priv;
1622ad74f40SNobuhiro Iwamatsu 	struct gpio_irq_chip *girq;
1632ad74f40SNobuhiro Iwamatsu 	struct irq_domain *parent;
1642ad74f40SNobuhiro Iwamatsu 	struct device_node *irq_parent;
1652ad74f40SNobuhiro Iwamatsu 	int ret;
1662ad74f40SNobuhiro Iwamatsu 
1672ad74f40SNobuhiro Iwamatsu 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
1682ad74f40SNobuhiro Iwamatsu 	if (!priv)
1692ad74f40SNobuhiro Iwamatsu 		return -ENOMEM;
1702ad74f40SNobuhiro Iwamatsu 
1712ad74f40SNobuhiro Iwamatsu 	spin_lock_init(&priv->lock);
172*5cf3e019SLinus Walleij 	priv->dev = dev;
1732ad74f40SNobuhiro Iwamatsu 
1742ad74f40SNobuhiro Iwamatsu 	priv->base = devm_platform_ioremap_resource(pdev, 0);
1752ad74f40SNobuhiro Iwamatsu 	if (IS_ERR(priv->base))
1762ad74f40SNobuhiro Iwamatsu 		return PTR_ERR(priv->base);
1772ad74f40SNobuhiro Iwamatsu 
1782ad74f40SNobuhiro Iwamatsu 	irq_parent = of_irq_find_parent(dev->of_node);
1792ad74f40SNobuhiro Iwamatsu 	if (!irq_parent) {
1802ad74f40SNobuhiro Iwamatsu 		dev_err(dev, "No IRQ parent node\n");
1812ad74f40SNobuhiro Iwamatsu 		return -ENODEV;
1822ad74f40SNobuhiro Iwamatsu 	}
1832ad74f40SNobuhiro Iwamatsu 
1842ad74f40SNobuhiro Iwamatsu 	parent = irq_find_host(irq_parent);
185171865daSNobuhiro Iwamatsu 	of_node_put(irq_parent);
1862ad74f40SNobuhiro Iwamatsu 	if (!parent) {
1872ad74f40SNobuhiro Iwamatsu 		dev_err(dev, "No IRQ parent domain\n");
1882ad74f40SNobuhiro Iwamatsu 		return -ENODEV;
1892ad74f40SNobuhiro Iwamatsu 	}
1902ad74f40SNobuhiro Iwamatsu 
1912ad74f40SNobuhiro Iwamatsu 	ret = bgpio_init(&priv->gpio_chip, dev, 4,
1922ad74f40SNobuhiro Iwamatsu 			 priv->base + GPIO_IDATA,
1932ad74f40SNobuhiro Iwamatsu 			 priv->base + GPIO_OSET,
1942ad74f40SNobuhiro Iwamatsu 			 priv->base + GPIO_OCLR,
1952ad74f40SNobuhiro Iwamatsu 			 priv->base + GPIO_DIR,
1962ad74f40SNobuhiro Iwamatsu 			 NULL,
1972ad74f40SNobuhiro Iwamatsu 			 0);
1982ad74f40SNobuhiro Iwamatsu 	if (ret) {
1992ad74f40SNobuhiro Iwamatsu 		dev_err(dev, "unable to init generic GPIO\n");
2002ad74f40SNobuhiro Iwamatsu 		return ret;
2012ad74f40SNobuhiro Iwamatsu 	}
2022ad74f40SNobuhiro Iwamatsu 
2032ad74f40SNobuhiro Iwamatsu 	girq = &priv->gpio_chip.irq;
204*5cf3e019SLinus Walleij 	gpio_irq_chip_set_chip(girq, &visconti_gpio_irq_chip);
205171865daSNobuhiro Iwamatsu 	girq->fwnode = of_node_to_fwnode(dev->of_node);
2062ad74f40SNobuhiro Iwamatsu 	girq->parent_domain = parent;
2072ad74f40SNobuhiro Iwamatsu 	girq->child_to_parent_hwirq = visconti_gpio_child_to_parent_hwirq;
2082ad74f40SNobuhiro Iwamatsu 	girq->populate_parent_alloc_arg = visconti_gpio_populate_parent_fwspec;
2092ad74f40SNobuhiro Iwamatsu 	girq->default_type = IRQ_TYPE_NONE;
2102ad74f40SNobuhiro Iwamatsu 	girq->handler = handle_level_irq;
2112ad74f40SNobuhiro Iwamatsu 
212ec5aa31bSAlexandru Ardelean 	return devm_gpiochip_add_data(dev, &priv->gpio_chip, priv);
2132ad74f40SNobuhiro Iwamatsu }
2142ad74f40SNobuhiro Iwamatsu 
2152ad74f40SNobuhiro Iwamatsu static const struct of_device_id visconti_gpio_of_match[] = {
2162ad74f40SNobuhiro Iwamatsu 	{ .compatible = "toshiba,gpio-tmpv7708", },
2172ad74f40SNobuhiro Iwamatsu 	{ /* end of table */ }
2182ad74f40SNobuhiro Iwamatsu };
2192ad74f40SNobuhiro Iwamatsu MODULE_DEVICE_TABLE(of, visconti_gpio_of_match);
2202ad74f40SNobuhiro Iwamatsu 
2212ad74f40SNobuhiro Iwamatsu static struct platform_driver visconti_gpio_driver = {
2222ad74f40SNobuhiro Iwamatsu 	.probe		= visconti_gpio_probe,
2232ad74f40SNobuhiro Iwamatsu 	.driver		= {
2242ad74f40SNobuhiro Iwamatsu 		.name	= "visconti_gpio",
225b39cf819SKrzysztof Kozlowski 		.of_match_table = visconti_gpio_of_match,
2262ad74f40SNobuhiro Iwamatsu 	}
2272ad74f40SNobuhiro Iwamatsu };
2282ad74f40SNobuhiro Iwamatsu module_platform_driver(visconti_gpio_driver);
2292ad74f40SNobuhiro Iwamatsu 
2302ad74f40SNobuhiro Iwamatsu MODULE_AUTHOR("Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>");
2312ad74f40SNobuhiro Iwamatsu MODULE_DESCRIPTION("Toshiba Visconti GPIO Driver");
2322ad74f40SNobuhiro Iwamatsu MODULE_LICENSE("GPL v2");
233