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 
30 struct 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 
visconti_gpio_irq_set_type(struct irq_data * d,unsigned int type)37 static 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);
85 err:
86 	spin_unlock_irqrestore(&priv->lock, flags);
87 	return ret;
88 }
89 
visconti_gpio_child_to_parent_hwirq(struct gpio_chip * gc,unsigned int child,unsigned int child_type,unsigned int * parent,unsigned int * parent_type)90 static 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 
visconti_gpio_populate_parent_fwspec(struct gpio_chip * chip,union gpio_irq_fwspec * gfwspec,unsigned int parent_hwirq,unsigned int parent_type)106 static int visconti_gpio_populate_parent_fwspec(struct gpio_chip *chip,
107 						union gpio_irq_fwspec *gfwspec,
108 						unsigned int parent_hwirq,
109 						unsigned int parent_type)
110 {
111 	struct irq_fwspec *fwspec = &gfwspec->fwspec;
112 
113 	fwspec->fwnode = chip->irq.parent_domain->fwnode;
114 	fwspec->param_count = 3;
115 	fwspec->param[0] = 0;
116 	fwspec->param[1] = parent_hwirq;
117 	fwspec->param[2] = parent_type;
118 
119 	return 0;
120 }
121 
visconti_gpio_probe(struct platform_device * pdev)122 static int visconti_gpio_probe(struct platform_device *pdev)
123 {
124 	struct device *dev = &pdev->dev;
125 	struct visconti_gpio *priv;
126 	struct irq_chip *irq_chip;
127 	struct gpio_irq_chip *girq;
128 	struct irq_domain *parent;
129 	struct device_node *irq_parent;
130 	int ret;
131 
132 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
133 	if (!priv)
134 		return -ENOMEM;
135 
136 	spin_lock_init(&priv->lock);
137 
138 	priv->base = devm_platform_ioremap_resource(pdev, 0);
139 	if (IS_ERR(priv->base))
140 		return PTR_ERR(priv->base);
141 
142 	irq_parent = of_irq_find_parent(dev->of_node);
143 	if (!irq_parent) {
144 		dev_err(dev, "No IRQ parent node\n");
145 		return -ENODEV;
146 	}
147 
148 	parent = irq_find_host(irq_parent);
149 	of_node_put(irq_parent);
150 	if (!parent) {
151 		dev_err(dev, "No IRQ parent domain\n");
152 		return -ENODEV;
153 	}
154 
155 	ret = bgpio_init(&priv->gpio_chip, dev, 4,
156 			 priv->base + GPIO_IDATA,
157 			 priv->base + GPIO_OSET,
158 			 priv->base + GPIO_OCLR,
159 			 priv->base + GPIO_DIR,
160 			 NULL,
161 			 0);
162 	if (ret) {
163 		dev_err(dev, "unable to init generic GPIO\n");
164 		return ret;
165 	}
166 
167 	irq_chip = &priv->irq_chip;
168 	irq_chip->name = dev_name(dev);
169 	irq_chip->irq_mask = irq_chip_mask_parent;
170 	irq_chip->irq_unmask = irq_chip_unmask_parent;
171 	irq_chip->irq_eoi = irq_chip_eoi_parent;
172 	irq_chip->irq_set_type = visconti_gpio_irq_set_type;
173 	irq_chip->flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND;
174 
175 	girq = &priv->gpio_chip.irq;
176 	girq->chip = irq_chip;
177 	girq->fwnode = of_node_to_fwnode(dev->of_node);
178 	girq->parent_domain = parent;
179 	girq->child_to_parent_hwirq = visconti_gpio_child_to_parent_hwirq;
180 	girq->populate_parent_alloc_arg = visconti_gpio_populate_parent_fwspec;
181 	girq->default_type = IRQ_TYPE_NONE;
182 	girq->handler = handle_level_irq;
183 
184 	return devm_gpiochip_add_data(dev, &priv->gpio_chip, priv);
185 }
186 
187 static const struct of_device_id visconti_gpio_of_match[] = {
188 	{ .compatible = "toshiba,gpio-tmpv7708", },
189 	{ /* end of table */ }
190 };
191 MODULE_DEVICE_TABLE(of, visconti_gpio_of_match);
192 
193 static struct platform_driver visconti_gpio_driver = {
194 	.probe		= visconti_gpio_probe,
195 	.driver		= {
196 		.name	= "visconti_gpio",
197 		.of_match_table = of_match_ptr(visconti_gpio_of_match),
198 	}
199 };
200 module_platform_driver(visconti_gpio_driver);
201 
202 MODULE_AUTHOR("Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>");
203 MODULE_DESCRIPTION("Toshiba Visconti GPIO Driver");
204 MODULE_LICENSE("GPL v2");
205