xref: /openbmc/linux/drivers/gpio/gpio-xlp.c (revision c7e66e48)
1130a990bSLinus Walleij // SPDX-License-Identifier: GPL-2.0
2ff718800SKamlakant Patel /*
3ff718800SKamlakant Patel  * Copyright (C) 2003-2015 Broadcom Corporation
4ff718800SKamlakant Patel  * All Rights Reserved
5ff718800SKamlakant Patel  */
6ff718800SKamlakant Patel 
7121111d7SLinus Walleij #include <linux/gpio/driver.h>
8ff718800SKamlakant Patel #include <linux/platform_device.h>
9ff718800SKamlakant Patel #include <linux/of_device.h>
10ff718800SKamlakant Patel #include <linux/module.h>
11ff718800SKamlakant Patel #include <linux/irq.h>
12ff718800SKamlakant Patel #include <linux/interrupt.h>
1383ea24fdSKamlakant Patel #include <linux/irqchip/chained_irq.h>
14baa1b920SKamlakant Patel #include <linux/acpi.h>
15ff718800SKamlakant Patel 
16ff718800SKamlakant Patel /*
17ff718800SKamlakant Patel  * XLP GPIO has multiple 32 bit registers for each feature where each register
18ff718800SKamlakant Patel  * controls 32 pins. So, pins up to 64 require 2 32-bit registers and up to 96
19ff718800SKamlakant Patel  * require 3 32-bit registers for each feature.
20ff718800SKamlakant Patel  * Here we only define offset of the first register for each feature. Offset of
21ff718800SKamlakant Patel  * the registers for pins greater than 32 can be calculated as following(Use
22ff718800SKamlakant Patel  * GPIO_INT_STAT as example):
23ff718800SKamlakant Patel  *
24ff718800SKamlakant Patel  * offset = (gpio / XLP_GPIO_REGSZ) * 4;
25ff718800SKamlakant Patel  * reg_addr = addr + offset;
26ff718800SKamlakant Patel  *
27ff718800SKamlakant Patel  * where addr is base address of the that feature register and gpio is the pin.
28ff718800SKamlakant Patel  */
29ff718800SKamlakant Patel #define GPIO_OUTPUT_EN		0x00
30ff718800SKamlakant Patel #define GPIO_PADDRV		0x08
31ff718800SKamlakant Patel #define GPIO_INT_EN00		0x18
32ff718800SKamlakant Patel #define GPIO_INT_EN10		0x20
33ff718800SKamlakant Patel #define GPIO_INT_EN20		0x28
34ff718800SKamlakant Patel #define GPIO_INT_EN30		0x30
35ff718800SKamlakant Patel #define GPIO_INT_POL		0x38
36ff718800SKamlakant Patel #define GPIO_INT_TYPE		0x40
37ff718800SKamlakant Patel #define GPIO_INT_STAT		0x48
38ff718800SKamlakant Patel 
39ff718800SKamlakant Patel #define GPIO_9XX_BYTESWAP	0X00
40ff718800SKamlakant Patel #define GPIO_9XX_CTRL		0X04
41ff718800SKamlakant Patel #define GPIO_9XX_OUTPUT_EN	0x14
42ff718800SKamlakant Patel #define GPIO_9XX_PADDRV		0x24
43ff718800SKamlakant Patel /*
44ff718800SKamlakant Patel  * Only for 4 interrupt enable reg are defined for now,
45ff718800SKamlakant Patel  * total reg available are 12.
46ff718800SKamlakant Patel  */
47ff718800SKamlakant Patel #define GPIO_9XX_INT_EN00	0x44
48ff718800SKamlakant Patel #define GPIO_9XX_INT_EN10	0x54
49ff718800SKamlakant Patel #define GPIO_9XX_INT_EN20	0x64
50ff718800SKamlakant Patel #define GPIO_9XX_INT_EN30	0x74
51ff718800SKamlakant Patel #define GPIO_9XX_INT_POL	0x104
52ff718800SKamlakant Patel #define GPIO_9XX_INT_TYPE	0x114
53ff718800SKamlakant Patel #define GPIO_9XX_INT_STAT	0x124
54ff718800SKamlakant Patel 
55ff718800SKamlakant Patel #define GPIO_3XX_INT_EN00	0x18
56ff718800SKamlakant Patel #define GPIO_3XX_INT_EN10	0x20
57ff718800SKamlakant Patel #define GPIO_3XX_INT_EN20	0x28
58ff718800SKamlakant Patel #define GPIO_3XX_INT_EN30	0x30
59ff718800SKamlakant Patel #define GPIO_3XX_INT_POL	0x78
60ff718800SKamlakant Patel #define GPIO_3XX_INT_TYPE	0x80
61ff718800SKamlakant Patel #define GPIO_3XX_INT_STAT	0x88
62ff718800SKamlakant Patel 
63ff718800SKamlakant Patel /* Interrupt type register mask */
64ff718800SKamlakant Patel #define XLP_GPIO_IRQ_TYPE_LVL	0x0
65ff718800SKamlakant Patel #define XLP_GPIO_IRQ_TYPE_EDGE	0x1
66ff718800SKamlakant Patel 
67ff718800SKamlakant Patel /* Interrupt polarity register mask */
68ff718800SKamlakant Patel #define XLP_GPIO_IRQ_POL_HIGH	0x0
69ff718800SKamlakant Patel #define XLP_GPIO_IRQ_POL_LOW	0x1
70ff718800SKamlakant Patel 
71ff718800SKamlakant Patel #define XLP_GPIO_REGSZ		32
72ff718800SKamlakant Patel #define XLP_GPIO_IRQ_BASE	768
73ff718800SKamlakant Patel #define XLP_MAX_NR_GPIO		96
74ff718800SKamlakant Patel 
75ff718800SKamlakant Patel /* XLP variants supported by this driver */
76ff718800SKamlakant Patel enum {
77ff718800SKamlakant Patel 	XLP_GPIO_VARIANT_XLP832 = 1,
78ff718800SKamlakant Patel 	XLP_GPIO_VARIANT_XLP316,
79ff718800SKamlakant Patel 	XLP_GPIO_VARIANT_XLP208,
80ff718800SKamlakant Patel 	XLP_GPIO_VARIANT_XLP980,
81dd98756dSKamlakant Patel 	XLP_GPIO_VARIANT_XLP532,
82dd98756dSKamlakant Patel 	GPIO_VARIANT_VULCAN
83ff718800SKamlakant Patel };
84ff718800SKamlakant Patel 
85ff718800SKamlakant Patel struct xlp_gpio_priv {
86ff718800SKamlakant Patel 	struct gpio_chip chip;
87ff718800SKamlakant Patel 	DECLARE_BITMAP(gpio_enabled_mask, XLP_MAX_NR_GPIO);
88ff718800SKamlakant Patel 	void __iomem *gpio_intr_en;	/* pointer to first intr enable reg */
89ff718800SKamlakant Patel 	void __iomem *gpio_intr_stat;	/* pointer to first intr status reg */
90ff718800SKamlakant Patel 	void __iomem *gpio_intr_type;	/* pointer to first intr type reg */
91ff718800SKamlakant Patel 	void __iomem *gpio_intr_pol;	/* pointer to first intr polarity reg */
92ff718800SKamlakant Patel 	void __iomem *gpio_out_en;	/* pointer to first output enable reg */
93ff718800SKamlakant Patel 	void __iomem *gpio_paddrv;	/* pointer to first pad drive reg */
94ff718800SKamlakant Patel 	spinlock_t lock;
95ff718800SKamlakant Patel };
96ff718800SKamlakant Patel 
97ff718800SKamlakant Patel static int xlp_gpio_get_reg(void __iomem *addr, unsigned gpio)
98ff718800SKamlakant Patel {
99ff718800SKamlakant Patel 	u32 pos, regset;
100ff718800SKamlakant Patel 
101ff718800SKamlakant Patel 	pos = gpio % XLP_GPIO_REGSZ;
102ff718800SKamlakant Patel 	regset = (gpio / XLP_GPIO_REGSZ) * 4;
103ff718800SKamlakant Patel 	return !!(readl(addr + regset) & BIT(pos));
104ff718800SKamlakant Patel }
105ff718800SKamlakant Patel 
106ff718800SKamlakant Patel static void xlp_gpio_set_reg(void __iomem *addr, unsigned gpio, int state)
107ff718800SKamlakant Patel {
108ff718800SKamlakant Patel 	u32 value, pos, regset;
109ff718800SKamlakant Patel 
110ff718800SKamlakant Patel 	pos = gpio % XLP_GPIO_REGSZ;
111ff718800SKamlakant Patel 	regset = (gpio / XLP_GPIO_REGSZ) * 4;
112ff718800SKamlakant Patel 	value = readl(addr + regset);
113ff718800SKamlakant Patel 
114ff718800SKamlakant Patel 	if (state)
115ff718800SKamlakant Patel 		value |= BIT(pos);
116ff718800SKamlakant Patel 	else
117ff718800SKamlakant Patel 		value &= ~BIT(pos);
118ff718800SKamlakant Patel 
119ff718800SKamlakant Patel 	writel(value, addr + regset);
120ff718800SKamlakant Patel }
121ff718800SKamlakant Patel 
122ff718800SKamlakant Patel static void xlp_gpio_irq_disable(struct irq_data *d)
123ff718800SKamlakant Patel {
124ff718800SKamlakant Patel 	struct gpio_chip *gc  = irq_data_get_irq_chip_data(d);
125e730a595SLinus Walleij 	struct xlp_gpio_priv *priv = gpiochip_get_data(gc);
126ff718800SKamlakant Patel 	unsigned long flags;
127ff718800SKamlakant Patel 
128ff718800SKamlakant Patel 	spin_lock_irqsave(&priv->lock, flags);
129ff718800SKamlakant Patel 	xlp_gpio_set_reg(priv->gpio_intr_en, d->hwirq, 0x0);
130ff718800SKamlakant Patel 	__clear_bit(d->hwirq, priv->gpio_enabled_mask);
131ff718800SKamlakant Patel 	spin_unlock_irqrestore(&priv->lock, flags);
132ff718800SKamlakant Patel }
133ff718800SKamlakant Patel 
134ff718800SKamlakant Patel static void xlp_gpio_irq_mask_ack(struct irq_data *d)
135ff718800SKamlakant Patel {
136ff718800SKamlakant Patel 	struct gpio_chip *gc  = irq_data_get_irq_chip_data(d);
137e730a595SLinus Walleij 	struct xlp_gpio_priv *priv = gpiochip_get_data(gc);
138ff718800SKamlakant Patel 	unsigned long flags;
139ff718800SKamlakant Patel 
140ff718800SKamlakant Patel 	spin_lock_irqsave(&priv->lock, flags);
141ff718800SKamlakant Patel 	xlp_gpio_set_reg(priv->gpio_intr_en, d->hwirq, 0x0);
142ff718800SKamlakant Patel 	xlp_gpio_set_reg(priv->gpio_intr_stat, d->hwirq, 0x1);
143ff718800SKamlakant Patel 	__clear_bit(d->hwirq, priv->gpio_enabled_mask);
144ff718800SKamlakant Patel 	spin_unlock_irqrestore(&priv->lock, flags);
145ff718800SKamlakant Patel }
146ff718800SKamlakant Patel 
147ff718800SKamlakant Patel static void xlp_gpio_irq_unmask(struct irq_data *d)
148ff718800SKamlakant Patel {
149ff718800SKamlakant Patel 	struct gpio_chip *gc  = irq_data_get_irq_chip_data(d);
150e730a595SLinus Walleij 	struct xlp_gpio_priv *priv = gpiochip_get_data(gc);
151ff718800SKamlakant Patel 	unsigned long flags;
152ff718800SKamlakant Patel 
153ff718800SKamlakant Patel 	spin_lock_irqsave(&priv->lock, flags);
154ff718800SKamlakant Patel 	xlp_gpio_set_reg(priv->gpio_intr_en, d->hwirq, 0x1);
155ff718800SKamlakant Patel 	__set_bit(d->hwirq, priv->gpio_enabled_mask);
156ff718800SKamlakant Patel 	spin_unlock_irqrestore(&priv->lock, flags);
157ff718800SKamlakant Patel }
158ff718800SKamlakant Patel 
159ff718800SKamlakant Patel static int xlp_gpio_set_irq_type(struct irq_data *d, unsigned int type)
160ff718800SKamlakant Patel {
161ff718800SKamlakant Patel 	struct gpio_chip *gc  = irq_data_get_irq_chip_data(d);
162e730a595SLinus Walleij 	struct xlp_gpio_priv *priv = gpiochip_get_data(gc);
163ff718800SKamlakant Patel 	int pol, irq_type;
164ff718800SKamlakant Patel 
165ff718800SKamlakant Patel 	switch (type) {
166ff718800SKamlakant Patel 	case IRQ_TYPE_EDGE_RISING:
167ff718800SKamlakant Patel 		irq_type = XLP_GPIO_IRQ_TYPE_EDGE;
168ff718800SKamlakant Patel 		pol = XLP_GPIO_IRQ_POL_HIGH;
169ff718800SKamlakant Patel 		break;
170ff718800SKamlakant Patel 	case IRQ_TYPE_EDGE_FALLING:
171ff718800SKamlakant Patel 		irq_type = XLP_GPIO_IRQ_TYPE_EDGE;
172ff718800SKamlakant Patel 		pol = XLP_GPIO_IRQ_POL_LOW;
173ff718800SKamlakant Patel 		break;
174ff718800SKamlakant Patel 	case IRQ_TYPE_LEVEL_HIGH:
175ff718800SKamlakant Patel 		irq_type = XLP_GPIO_IRQ_TYPE_LVL;
176ff718800SKamlakant Patel 		pol = XLP_GPIO_IRQ_POL_HIGH;
177ff718800SKamlakant Patel 		break;
178ff718800SKamlakant Patel 	case IRQ_TYPE_LEVEL_LOW:
179ff718800SKamlakant Patel 		irq_type = XLP_GPIO_IRQ_TYPE_LVL;
180ff718800SKamlakant Patel 		pol = XLP_GPIO_IRQ_POL_LOW;
181ff718800SKamlakant Patel 		break;
182ff718800SKamlakant Patel 	default:
183ff718800SKamlakant Patel 		return -EINVAL;
184ff718800SKamlakant Patel 	}
185ff718800SKamlakant Patel 
186ff718800SKamlakant Patel 	xlp_gpio_set_reg(priv->gpio_intr_type, d->hwirq, irq_type);
187ff718800SKamlakant Patel 	xlp_gpio_set_reg(priv->gpio_intr_pol, d->hwirq, pol);
188ff718800SKamlakant Patel 
189ff718800SKamlakant Patel 	return 0;
190ff718800SKamlakant Patel }
191ff718800SKamlakant Patel 
192ff718800SKamlakant Patel static struct irq_chip xlp_gpio_irq_chip = {
193ff718800SKamlakant Patel 	.name		= "XLP-GPIO",
194ff718800SKamlakant Patel 	.irq_mask_ack	= xlp_gpio_irq_mask_ack,
195ff718800SKamlakant Patel 	.irq_disable	= xlp_gpio_irq_disable,
196ff718800SKamlakant Patel 	.irq_set_type	= xlp_gpio_set_irq_type,
197ff718800SKamlakant Patel 	.irq_unmask	= xlp_gpio_irq_unmask,
198ff718800SKamlakant Patel 	.flags		= IRQCHIP_ONESHOT_SAFE,
199ff718800SKamlakant Patel };
200ff718800SKamlakant Patel 
20183ea24fdSKamlakant Patel static void xlp_gpio_generic_handler(struct irq_desc *desc)
202ff718800SKamlakant Patel {
20383ea24fdSKamlakant Patel 	struct xlp_gpio_priv *priv = irq_desc_get_handler_data(desc);
20483ea24fdSKamlakant Patel 	struct irq_chip *irqchip = irq_desc_get_chip(desc);
205ff718800SKamlakant Patel 	int gpio, regoff;
206ff718800SKamlakant Patel 	u32 gpio_stat;
207ff718800SKamlakant Patel 
208ff718800SKamlakant Patel 	regoff = -1;
209ff718800SKamlakant Patel 	gpio_stat = 0;
21083ea24fdSKamlakant Patel 
21183ea24fdSKamlakant Patel 	chained_irq_enter(irqchip, desc);
212ff718800SKamlakant Patel 	for_each_set_bit(gpio, priv->gpio_enabled_mask, XLP_MAX_NR_GPIO) {
213ff718800SKamlakant Patel 		if (regoff != gpio / XLP_GPIO_REGSZ) {
214ff718800SKamlakant Patel 			regoff = gpio / XLP_GPIO_REGSZ;
215ff718800SKamlakant Patel 			gpio_stat = readl(priv->gpio_intr_stat + regoff * 4);
216ff718800SKamlakant Patel 		}
21783ea24fdSKamlakant Patel 
218ff718800SKamlakant Patel 		if (gpio_stat & BIT(gpio % XLP_GPIO_REGSZ))
219ff718800SKamlakant Patel 			generic_handle_irq(irq_find_mapping(
220f0fbe7bcSThierry Reding 						priv->chip.irq.domain, gpio));
221ff718800SKamlakant Patel 	}
22283ea24fdSKamlakant Patel 	chained_irq_exit(irqchip, desc);
223ff718800SKamlakant Patel }
224ff718800SKamlakant Patel 
225ff718800SKamlakant Patel static int xlp_gpio_dir_output(struct gpio_chip *gc, unsigned gpio, int state)
226ff718800SKamlakant Patel {
227e730a595SLinus Walleij 	struct xlp_gpio_priv *priv = gpiochip_get_data(gc);
228ff718800SKamlakant Patel 
229ff718800SKamlakant Patel 	BUG_ON(gpio >= gc->ngpio);
230ff718800SKamlakant Patel 	xlp_gpio_set_reg(priv->gpio_out_en, gpio, 0x1);
231ff718800SKamlakant Patel 
232ff718800SKamlakant Patel 	return 0;
233ff718800SKamlakant Patel }
234ff718800SKamlakant Patel 
235ff718800SKamlakant Patel static int xlp_gpio_dir_input(struct gpio_chip *gc, unsigned gpio)
236ff718800SKamlakant Patel {
237e730a595SLinus Walleij 	struct xlp_gpio_priv *priv = gpiochip_get_data(gc);
238ff718800SKamlakant Patel 
239ff718800SKamlakant Patel 	BUG_ON(gpio >= gc->ngpio);
240ff718800SKamlakant Patel 	xlp_gpio_set_reg(priv->gpio_out_en, gpio, 0x0);
241ff718800SKamlakant Patel 
242ff718800SKamlakant Patel 	return 0;
243ff718800SKamlakant Patel }
244ff718800SKamlakant Patel 
245ff718800SKamlakant Patel static int xlp_gpio_get(struct gpio_chip *gc, unsigned gpio)
246ff718800SKamlakant Patel {
247e730a595SLinus Walleij 	struct xlp_gpio_priv *priv = gpiochip_get_data(gc);
248ff718800SKamlakant Patel 
249ff718800SKamlakant Patel 	BUG_ON(gpio >= gc->ngpio);
250ff718800SKamlakant Patel 	return xlp_gpio_get_reg(priv->gpio_paddrv, gpio);
251ff718800SKamlakant Patel }
252ff718800SKamlakant Patel 
253ff718800SKamlakant Patel static void xlp_gpio_set(struct gpio_chip *gc, unsigned gpio, int state)
254ff718800SKamlakant Patel {
255e730a595SLinus Walleij 	struct xlp_gpio_priv *priv = gpiochip_get_data(gc);
256ff718800SKamlakant Patel 
257ff718800SKamlakant Patel 	BUG_ON(gpio >= gc->ngpio);
258ff718800SKamlakant Patel 	xlp_gpio_set_reg(priv->gpio_paddrv, gpio, state);
259ff718800SKamlakant Patel }
260ff718800SKamlakant Patel 
261ff718800SKamlakant Patel static const struct of_device_id xlp_gpio_of_ids[] = {
262ff718800SKamlakant Patel 	{
263ff718800SKamlakant Patel 		.compatible = "netlogic,xlp832-gpio",
264ff718800SKamlakant Patel 		.data	    = (void *)XLP_GPIO_VARIANT_XLP832,
265ff718800SKamlakant Patel 	},
266ff718800SKamlakant Patel 	{
267ff718800SKamlakant Patel 		.compatible = "netlogic,xlp316-gpio",
268ff718800SKamlakant Patel 		.data	    = (void *)XLP_GPIO_VARIANT_XLP316,
269ff718800SKamlakant Patel 	},
270ff718800SKamlakant Patel 	{
271ff718800SKamlakant Patel 		.compatible = "netlogic,xlp208-gpio",
272ff718800SKamlakant Patel 		.data	    = (void *)XLP_GPIO_VARIANT_XLP208,
273ff718800SKamlakant Patel 	},
274ff718800SKamlakant Patel 	{
275ff718800SKamlakant Patel 		.compatible = "netlogic,xlp980-gpio",
276ff718800SKamlakant Patel 		.data	    = (void *)XLP_GPIO_VARIANT_XLP980,
277ff718800SKamlakant Patel 	},
278ff718800SKamlakant Patel 	{
279ff718800SKamlakant Patel 		.compatible = "netlogic,xlp532-gpio",
280ff718800SKamlakant Patel 		.data	    = (void *)XLP_GPIO_VARIANT_XLP532,
281ff718800SKamlakant Patel 	},
282dd98756dSKamlakant Patel 	{
283dd98756dSKamlakant Patel 		.compatible = "brcm,vulcan-gpio",
284dd98756dSKamlakant Patel 		.data	    = (void *)GPIO_VARIANT_VULCAN,
285dd98756dSKamlakant Patel 	},
286ff718800SKamlakant Patel 	{ /* sentinel */ },
287ff718800SKamlakant Patel };
288ff718800SKamlakant Patel MODULE_DEVICE_TABLE(of, xlp_gpio_of_ids);
289ff718800SKamlakant Patel 
290ff718800SKamlakant Patel static int xlp_gpio_probe(struct platform_device *pdev)
291ff718800SKamlakant Patel {
292ff718800SKamlakant Patel 	struct gpio_chip *gc;
293c7e66e48SLinus Walleij 	struct gpio_irq_chip *girq;
294ff718800SKamlakant Patel 	struct xlp_gpio_priv *priv;
295ff718800SKamlakant Patel 	void __iomem *gpio_base;
296ff718800SKamlakant Patel 	int irq_base, irq, err;
297ff718800SKamlakant Patel 	int ngpio;
298ff718800SKamlakant Patel 	u32 soc_type;
299ff718800SKamlakant Patel 
300ff718800SKamlakant Patel 	priv = devm_kzalloc(&pdev->dev,	sizeof(*priv), GFP_KERNEL);
301ff718800SKamlakant Patel 	if (!priv)
302ff718800SKamlakant Patel 		return -ENOMEM;
303ff718800SKamlakant Patel 
3043883de02SEnrico Weigelt, metux IT consult 	gpio_base = devm_platform_ioremap_resource(pdev, 0);
305ff718800SKamlakant Patel 	if (IS_ERR(gpio_base))
306ff718800SKamlakant Patel 		return PTR_ERR(gpio_base);
307ff718800SKamlakant Patel 
308ff718800SKamlakant Patel 	irq = platform_get_irq(pdev, 0);
309ff718800SKamlakant Patel 	if (irq < 0)
310ff718800SKamlakant Patel 		return irq;
311ff718800SKamlakant Patel 
312baa1b920SKamlakant Patel 	if (pdev->dev.of_node) {
3130c695e38SThierry Reding 		soc_type = (uintptr_t)of_device_get_match_data(&pdev->dev);
314baa1b920SKamlakant Patel 	} else {
315baa1b920SKamlakant Patel 		const struct acpi_device_id *acpi_id;
316baa1b920SKamlakant Patel 
317baa1b920SKamlakant Patel 		acpi_id = acpi_match_device(pdev->dev.driver->acpi_match_table,
318baa1b920SKamlakant Patel 						&pdev->dev);
319baa1b920SKamlakant Patel 		if (!acpi_id || !acpi_id->driver_data) {
320baa1b920SKamlakant Patel 			dev_err(&pdev->dev, "Unable to match ACPI ID\n");
321baa1b920SKamlakant Patel 			return -ENODEV;
322baa1b920SKamlakant Patel 		}
323baa1b920SKamlakant Patel 		soc_type = (uintptr_t) acpi_id->driver_data;
324baa1b920SKamlakant Patel 	}
325ff718800SKamlakant Patel 
326ff718800SKamlakant Patel 	switch (soc_type) {
327ff718800SKamlakant Patel 	case XLP_GPIO_VARIANT_XLP832:
328ff718800SKamlakant Patel 		priv->gpio_out_en = gpio_base + GPIO_OUTPUT_EN;
329ff718800SKamlakant Patel 		priv->gpio_paddrv = gpio_base + GPIO_PADDRV;
330ff718800SKamlakant Patel 		priv->gpio_intr_stat = gpio_base + GPIO_INT_STAT;
331ff718800SKamlakant Patel 		priv->gpio_intr_type = gpio_base + GPIO_INT_TYPE;
332ff718800SKamlakant Patel 		priv->gpio_intr_pol = gpio_base + GPIO_INT_POL;
333ff718800SKamlakant Patel 		priv->gpio_intr_en = gpio_base + GPIO_INT_EN00;
334ff718800SKamlakant Patel 		ngpio = 41;
335ff718800SKamlakant Patel 		break;
336ff718800SKamlakant Patel 	case XLP_GPIO_VARIANT_XLP208:
337ff718800SKamlakant Patel 	case XLP_GPIO_VARIANT_XLP316:
338ff718800SKamlakant Patel 		priv->gpio_out_en = gpio_base + GPIO_OUTPUT_EN;
339ff718800SKamlakant Patel 		priv->gpio_paddrv = gpio_base + GPIO_PADDRV;
340ff718800SKamlakant Patel 		priv->gpio_intr_stat = gpio_base + GPIO_3XX_INT_STAT;
341ff718800SKamlakant Patel 		priv->gpio_intr_type = gpio_base + GPIO_3XX_INT_TYPE;
342ff718800SKamlakant Patel 		priv->gpio_intr_pol = gpio_base + GPIO_3XX_INT_POL;
343ff718800SKamlakant Patel 		priv->gpio_intr_en = gpio_base + GPIO_3XX_INT_EN00;
344ff718800SKamlakant Patel 
345ff718800SKamlakant Patel 		ngpio = (soc_type == XLP_GPIO_VARIANT_XLP208) ? 42 : 57;
346ff718800SKamlakant Patel 		break;
347ff718800SKamlakant Patel 	case XLP_GPIO_VARIANT_XLP980:
348ff718800SKamlakant Patel 	case XLP_GPIO_VARIANT_XLP532:
349dd98756dSKamlakant Patel 	case GPIO_VARIANT_VULCAN:
350ff718800SKamlakant Patel 		priv->gpio_out_en = gpio_base + GPIO_9XX_OUTPUT_EN;
351ff718800SKamlakant Patel 		priv->gpio_paddrv = gpio_base + GPIO_9XX_PADDRV;
352ff718800SKamlakant Patel 		priv->gpio_intr_stat = gpio_base + GPIO_9XX_INT_STAT;
353ff718800SKamlakant Patel 		priv->gpio_intr_type = gpio_base + GPIO_9XX_INT_TYPE;
354ff718800SKamlakant Patel 		priv->gpio_intr_pol = gpio_base + GPIO_9XX_INT_POL;
355ff718800SKamlakant Patel 		priv->gpio_intr_en = gpio_base + GPIO_9XX_INT_EN00;
356ff718800SKamlakant Patel 
357dd98756dSKamlakant Patel 		if (soc_type == XLP_GPIO_VARIANT_XLP980)
358dd98756dSKamlakant Patel 			ngpio = 66;
359dd98756dSKamlakant Patel 		else if (soc_type == XLP_GPIO_VARIANT_XLP532)
360dd98756dSKamlakant Patel 			ngpio = 67;
361dd98756dSKamlakant Patel 		else
362dd98756dSKamlakant Patel 			ngpio = 70;
363ff718800SKamlakant Patel 		break;
364ff718800SKamlakant Patel 	default:
365ff718800SKamlakant Patel 		dev_err(&pdev->dev, "Unknown Processor type!\n");
366ff718800SKamlakant Patel 		return -ENODEV;
367ff718800SKamlakant Patel 	}
368ff718800SKamlakant Patel 
369ff718800SKamlakant Patel 	bitmap_zero(priv->gpio_enabled_mask, XLP_MAX_NR_GPIO);
370ff718800SKamlakant Patel 
371ff718800SKamlakant Patel 	gc = &priv->chip;
372ff718800SKamlakant Patel 
373b8a3f52eSAxel Lin 	gc->owner = THIS_MODULE;
374b8a3f52eSAxel Lin 	gc->label = dev_name(&pdev->dev);
375ff718800SKamlakant Patel 	gc->base = 0;
37658383c78SLinus Walleij 	gc->parent = &pdev->dev;
377ff718800SKamlakant Patel 	gc->ngpio = ngpio;
378ff718800SKamlakant Patel 	gc->of_node = pdev->dev.of_node;
379ff718800SKamlakant Patel 	gc->direction_output = xlp_gpio_dir_output;
380ff718800SKamlakant Patel 	gc->direction_input = xlp_gpio_dir_input;
381ff718800SKamlakant Patel 	gc->set = xlp_gpio_set;
382ff718800SKamlakant Patel 	gc->get = xlp_gpio_get;
383ff718800SKamlakant Patel 
384ff718800SKamlakant Patel 	spin_lock_init(&priv->lock);
3851630a062SKamlakant Patel 
3861630a062SKamlakant Patel 	/* XLP(MIPS) has fixed range for GPIO IRQs, Vulcan(ARM64) does not */
3871630a062SKamlakant Patel 	if (soc_type != GPIO_VARIANT_VULCAN) {
38831bd86d9SBartosz Golaszewski 		irq_base = devm_irq_alloc_descs(&pdev->dev, -1,
38931bd86d9SBartosz Golaszewski 						XLP_GPIO_IRQ_BASE,
39031bd86d9SBartosz Golaszewski 						gc->ngpio, 0);
391287980e4SArnd Bergmann 		if (irq_base < 0) {
392ff718800SKamlakant Patel 			dev_err(&pdev->dev, "Failed to allocate IRQ numbers\n");
393dd98756dSKamlakant Patel 			return irq_base;
394ff718800SKamlakant Patel 		}
3951630a062SKamlakant Patel 	} else {
3961630a062SKamlakant Patel 		irq_base = 0;
3971630a062SKamlakant Patel 	}
398ff718800SKamlakant Patel 
399c7e66e48SLinus Walleij 	girq = &gc->irq;
400c7e66e48SLinus Walleij 	girq->chip = &xlp_gpio_irq_chip;
401c7e66e48SLinus Walleij 	girq->parent_handler = xlp_gpio_generic_handler;
402c7e66e48SLinus Walleij 	girq->num_parents = 1;
403c7e66e48SLinus Walleij 	girq->parents = devm_kcalloc(&pdev->dev, 1,
404c7e66e48SLinus Walleij 				     sizeof(*girq->parents),
405c7e66e48SLinus Walleij 				     GFP_KERNEL);
406c7e66e48SLinus Walleij 	if (!girq->parents)
407c7e66e48SLinus Walleij 		return -ENOMEM;
408c7e66e48SLinus Walleij 	girq->parents[0] = irq;
409c7e66e48SLinus Walleij 	girq->first = irq_base;
410c7e66e48SLinus Walleij 	girq->default_type = IRQ_TYPE_NONE;
411c7e66e48SLinus Walleij 	girq->handler = handle_level_irq;
412c7e66e48SLinus Walleij 
413e730a595SLinus Walleij 	err = gpiochip_add_data(gc, priv);
414ff718800SKamlakant Patel 	if (err < 0)
41531bd86d9SBartosz Golaszewski 		return err;
416ff718800SKamlakant Patel 
417ff718800SKamlakant Patel 	dev_info(&pdev->dev, "registered %d GPIOs\n", gc->ngpio);
418ff718800SKamlakant Patel 
419ff718800SKamlakant Patel 	return 0;
420ff718800SKamlakant Patel }
421ff718800SKamlakant Patel 
422baa1b920SKamlakant Patel #ifdef CONFIG_ACPI
423baa1b920SKamlakant Patel static const struct acpi_device_id xlp_gpio_acpi_match[] = {
424baa1b920SKamlakant Patel 	{ "BRCM9006", GPIO_VARIANT_VULCAN },
425529f75d8SJayachandran C 	{ "CAV9006",  GPIO_VARIANT_VULCAN },
426baa1b920SKamlakant Patel 	{},
427baa1b920SKamlakant Patel };
428baa1b920SKamlakant Patel MODULE_DEVICE_TABLE(acpi, xlp_gpio_acpi_match);
429baa1b920SKamlakant Patel #endif
430baa1b920SKamlakant Patel 
431ff718800SKamlakant Patel static struct platform_driver xlp_gpio_driver = {
432ff718800SKamlakant Patel 	.driver		= {
433ff718800SKamlakant Patel 		.name	= "xlp-gpio",
434ff718800SKamlakant Patel 		.of_match_table = xlp_gpio_of_ids,
435baa1b920SKamlakant Patel 		.acpi_match_table = ACPI_PTR(xlp_gpio_acpi_match),
436ff718800SKamlakant Patel 	},
437ff718800SKamlakant Patel 	.probe		= xlp_gpio_probe,
438ff718800SKamlakant Patel };
439ff718800SKamlakant Patel module_platform_driver(xlp_gpio_driver);
440ff718800SKamlakant Patel 
441ff718800SKamlakant Patel MODULE_AUTHOR("Kamlakant Patel <kamlakant.patel@broadcom.com>");
442ff718800SKamlakant Patel MODULE_AUTHOR("Ganesan Ramalingam <ganesanr@broadcom.com>");
443ff718800SKamlakant Patel MODULE_DESCRIPTION("Netlogic XLP GPIO Driver");
444ff718800SKamlakant Patel MODULE_LICENSE("GPL v2");
445