xref: /linux/drivers/pinctrl/intel/pinctrl-lynxpoint.c (revision 21a06495d0e757b8a52774ce62e9cfdf07838971)
1eb83479eSAndy Shevchenko // SPDX-License-Identifier: GPL-2.0
2eb83479eSAndy Shevchenko /*
3eb83479eSAndy Shevchenko  * GPIO controller driver for Intel Lynxpoint PCH chipset>
4eb83479eSAndy Shevchenko  * Copyright (c) 2012, Intel Corporation.
5eb83479eSAndy Shevchenko  *
6eb83479eSAndy Shevchenko  * Author: Mathias Nyman <mathias.nyman@linux.intel.com>
7eb83479eSAndy Shevchenko  */
8eb83479eSAndy Shevchenko 
9eb83479eSAndy Shevchenko #include <linux/acpi.h>
10eb83479eSAndy Shevchenko #include <linux/bitops.h>
11eb83479eSAndy Shevchenko #include <linux/gpio/driver.h>
12eb83479eSAndy Shevchenko #include <linux/interrupt.h>
13eb83479eSAndy Shevchenko #include <linux/io.h>
14eb83479eSAndy Shevchenko #include <linux/kernel.h>
15eb83479eSAndy Shevchenko #include <linux/module.h>
16eb83479eSAndy Shevchenko #include <linux/platform_device.h>
17eb83479eSAndy Shevchenko #include <linux/pm_runtime.h>
18eb83479eSAndy Shevchenko #include <linux/slab.h>
19eb83479eSAndy Shevchenko #include <linux/types.h>
20eb83479eSAndy Shevchenko 
217c0bc7bbSAndy Shevchenko /* LynxPoint chipset has support for 95 GPIO pins */
22eb83479eSAndy Shevchenko 
237c0bc7bbSAndy Shevchenko #define LP_NUM_GPIO	95
24eb83479eSAndy Shevchenko 
25eb83479eSAndy Shevchenko /* Bitmapped register offsets */
26eb83479eSAndy Shevchenko #define LP_ACPI_OWNED	0x00 /* Bitmap, set by bios, 0: pin reserved for ACPI */
27eb83479eSAndy Shevchenko #define LP_GC		0x7C /* set APIC IRQ to IRQ14 or IRQ15 for all pins */
28eb83479eSAndy Shevchenko #define LP_INT_STAT	0x80
29eb83479eSAndy Shevchenko #define LP_INT_ENABLE	0x90
30eb83479eSAndy Shevchenko 
31eb83479eSAndy Shevchenko /* Each pin has two 32 bit config registers, starting at 0x100 */
32eb83479eSAndy Shevchenko #define LP_CONFIG1	0x100
33eb83479eSAndy Shevchenko #define LP_CONFIG2	0x104
34eb83479eSAndy Shevchenko 
35eb83479eSAndy Shevchenko /* LP_CONFIG1 reg bits */
36eb83479eSAndy Shevchenko #define OUT_LVL_BIT	BIT(31)
37eb83479eSAndy Shevchenko #define IN_LVL_BIT	BIT(30)
38eb83479eSAndy Shevchenko #define TRIG_SEL_BIT	BIT(4) /* 0: Edge, 1: Level */
39eb83479eSAndy Shevchenko #define INT_INV_BIT	BIT(3) /* Invert interrupt triggering */
40eb83479eSAndy Shevchenko #define DIR_BIT		BIT(2) /* 0: Output, 1: Input */
4176347d7aSAndy Shevchenko #define USE_SEL_MASK	GENMASK(1, 0)	/* 0: Native, 1: GPIO, ... */
4276347d7aSAndy Shevchenko #define USE_SEL_NATIVE	(0 << 0)
4376347d7aSAndy Shevchenko #define USE_SEL_GPIO	(1 << 0)
44eb83479eSAndy Shevchenko 
45eb83479eSAndy Shevchenko /* LP_CONFIG2 reg bits */
46eb83479eSAndy Shevchenko #define GPINDIS_BIT	BIT(2) /* disable input sensing */
47eb83479eSAndy Shevchenko #define GPIWP_BIT	(BIT(0) | BIT(1)) /* weak pull options */
48eb83479eSAndy Shevchenko 
49eb83479eSAndy Shevchenko struct lp_gpio {
50eb83479eSAndy Shevchenko 	struct gpio_chip	chip;
511e78ea71SAndy Shevchenko 	struct device		*dev;
52b2e05d63SAndy Shevchenko 	raw_spinlock_t		lock;
53e1940adeSAndy Shevchenko 	void __iomem		*regs;
54eb83479eSAndy Shevchenko };
55eb83479eSAndy Shevchenko 
56eb83479eSAndy Shevchenko /*
57eb83479eSAndy Shevchenko  * Lynxpoint gpios are controlled through both bitmapped registers and
58eb83479eSAndy Shevchenko  * per gpio specific registers. The bitmapped registers are in chunks of
597c0bc7bbSAndy Shevchenko  * 3 x 32bit registers to cover all 95 GPIOs
60eb83479eSAndy Shevchenko  *
61eb83479eSAndy Shevchenko  * per gpio specific registers consist of two 32bit registers per gpio
627c0bc7bbSAndy Shevchenko  * (LP_CONFIG1 and LP_CONFIG2), with 95 GPIOs there's a total of
637c0bc7bbSAndy Shevchenko  * 190 config registers.
64eb83479eSAndy Shevchenko  *
65eb83479eSAndy Shevchenko  * A simplified view of the register layout look like this:
66eb83479eSAndy Shevchenko  *
67eb83479eSAndy Shevchenko  * LP_ACPI_OWNED[31:0] gpio ownerships for gpios 0-31  (bitmapped registers)
68eb83479eSAndy Shevchenko  * LP_ACPI_OWNED[63:32] gpio ownerships for gpios 32-63
69eb83479eSAndy Shevchenko  * LP_ACPI_OWNED[94:64] gpio ownerships for gpios 63-94
70eb83479eSAndy Shevchenko  * ...
71eb83479eSAndy Shevchenko  * LP_INT_ENABLE[31:0] ...
727c0bc7bbSAndy Shevchenko  * LP_INT_ENABLE[63:32] ...
73eb83479eSAndy Shevchenko  * LP_INT_ENABLE[94:64] ...
74eb83479eSAndy Shevchenko  * LP0_CONFIG1 (gpio 0) config1 reg for gpio 0 (per gpio registers)
75eb83479eSAndy Shevchenko  * LP0_CONFIG2 (gpio 0) config2 reg for gpio 0
76eb83479eSAndy Shevchenko  * LP1_CONFIG1 (gpio 1) config1 reg for gpio 1
77eb83479eSAndy Shevchenko  * LP1_CONFIG2 (gpio 1) config2 reg for gpio 1
78eb83479eSAndy Shevchenko  * LP2_CONFIG1 (gpio 2) ...
79eb83479eSAndy Shevchenko  * LP2_CONFIG2 (gpio 2) ...
80eb83479eSAndy Shevchenko  * ...
81eb83479eSAndy Shevchenko  * LP94_CONFIG1 (gpio 94) ...
82eb83479eSAndy Shevchenko  * LP94_CONFIG2 (gpio 94) ...
83eb83479eSAndy Shevchenko  */
84eb83479eSAndy Shevchenko 
85c35f463aSAndy Shevchenko static void __iomem *lp_gpio_reg(struct gpio_chip *chip, unsigned int offset,
86eb83479eSAndy Shevchenko 				 int reg)
87eb83479eSAndy Shevchenko {
88eb83479eSAndy Shevchenko 	struct lp_gpio *lg = gpiochip_get_data(chip);
89eb83479eSAndy Shevchenko 	int reg_offset;
90eb83479eSAndy Shevchenko 
91eb83479eSAndy Shevchenko 	if (reg == LP_CONFIG1 || reg == LP_CONFIG2)
92eb83479eSAndy Shevchenko 		/* per gpio specific config registers */
93eb83479eSAndy Shevchenko 		reg_offset = offset * 8;
94eb83479eSAndy Shevchenko 	else
95eb83479eSAndy Shevchenko 		/* bitmapped registers */
96eb83479eSAndy Shevchenko 		reg_offset = (offset / 32) * 4;
97eb83479eSAndy Shevchenko 
98e1940adeSAndy Shevchenko 	return lg->regs + reg + reg_offset;
99eb83479eSAndy Shevchenko }
100eb83479eSAndy Shevchenko 
101*21a06495SAndy Shevchenko static bool lp_gpio_acpi_use(struct lp_gpio *lg, unsigned int pin)
102*21a06495SAndy Shevchenko {
103*21a06495SAndy Shevchenko 	void __iomem *acpi_use;
104*21a06495SAndy Shevchenko 
105*21a06495SAndy Shevchenko 	acpi_use = lp_gpio_reg(&lg->chip, pin, LP_ACPI_OWNED);
106*21a06495SAndy Shevchenko 	if (!acpi_use)
107*21a06495SAndy Shevchenko 		return true;
108*21a06495SAndy Shevchenko 
109*21a06495SAndy Shevchenko 	return !(ioread32(acpi_use) & BIT(pin % 32));
110*21a06495SAndy Shevchenko }
111*21a06495SAndy Shevchenko 
112c35f463aSAndy Shevchenko static int lp_gpio_request(struct gpio_chip *chip, unsigned int offset)
113eb83479eSAndy Shevchenko {
114eb83479eSAndy Shevchenko 	struct lp_gpio *lg = gpiochip_get_data(chip);
115e1940adeSAndy Shevchenko 	void __iomem *reg = lp_gpio_reg(chip, offset, LP_CONFIG1);
116e1940adeSAndy Shevchenko 	void __iomem *conf2 = lp_gpio_reg(chip, offset, LP_CONFIG2);
11703fb681bSAndy Shevchenko 	u32 value;
118eb83479eSAndy Shevchenko 
1191e78ea71SAndy Shevchenko 	pm_runtime_get(lg->dev); /* should we put if failed */
120eb83479eSAndy Shevchenko 
121eb83479eSAndy Shevchenko 	/* Fail if BIOS reserved pin for ACPI use */
122*21a06495SAndy Shevchenko 	if (lp_gpio_acpi_use(lg, offset)) {
1231e78ea71SAndy Shevchenko 		dev_err(lg->dev, "gpio %d reserved for ACPI\n", offset);
124eb83479eSAndy Shevchenko 		return -EBUSY;
125eb83479eSAndy Shevchenko 	}
12603fb681bSAndy Shevchenko 
12703fb681bSAndy Shevchenko 	/*
12803fb681bSAndy Shevchenko 	 * Reconfigure pin to GPIO mode if needed and issue a warning,
12903fb681bSAndy Shevchenko 	 * since we expect firmware to configure it properly.
13003fb681bSAndy Shevchenko 	 */
131e1940adeSAndy Shevchenko 	value = ioread32(reg);
13203fb681bSAndy Shevchenko 	if ((value & USE_SEL_MASK) != USE_SEL_GPIO) {
133e1940adeSAndy Shevchenko 		iowrite32((value & USE_SEL_MASK) | USE_SEL_GPIO, reg);
1341e78ea71SAndy Shevchenko 		dev_warn(lg->dev, FW_BUG "pin %u forcibly reconfigured as GPIO\n", offset);
13503fb681bSAndy Shevchenko 	}
136eb83479eSAndy Shevchenko 
137eb83479eSAndy Shevchenko 	/* enable input sensing */
138e1940adeSAndy Shevchenko 	iowrite32(ioread32(conf2) & ~GPINDIS_BIT, conf2);
139eb83479eSAndy Shevchenko 
140eb83479eSAndy Shevchenko 
141eb83479eSAndy Shevchenko 	return 0;
142eb83479eSAndy Shevchenko }
143eb83479eSAndy Shevchenko 
144c35f463aSAndy Shevchenko static void lp_gpio_free(struct gpio_chip *chip, unsigned int offset)
145eb83479eSAndy Shevchenko {
146eb83479eSAndy Shevchenko 	struct lp_gpio *lg = gpiochip_get_data(chip);
147e1940adeSAndy Shevchenko 	void __iomem *conf2 = lp_gpio_reg(chip, offset, LP_CONFIG2);
148eb83479eSAndy Shevchenko 
149eb83479eSAndy Shevchenko 	/* disable input sensing */
150e1940adeSAndy Shevchenko 	iowrite32(ioread32(conf2) | GPINDIS_BIT, conf2);
151eb83479eSAndy Shevchenko 
1521e78ea71SAndy Shevchenko 	pm_runtime_put(lg->dev);
153eb83479eSAndy Shevchenko }
154eb83479eSAndy Shevchenko 
155c35f463aSAndy Shevchenko static int lp_irq_type(struct irq_data *d, unsigned int type)
156eb83479eSAndy Shevchenko {
157eb83479eSAndy Shevchenko 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
158eb83479eSAndy Shevchenko 	struct lp_gpio *lg = gpiochip_get_data(gc);
159eb83479eSAndy Shevchenko 	u32 hwirq = irqd_to_hwirq(d);
160e1940adeSAndy Shevchenko 	void __iomem *reg = lp_gpio_reg(&lg->chip, hwirq, LP_CONFIG1);
161eb83479eSAndy Shevchenko 	unsigned long flags;
162eb83479eSAndy Shevchenko 	u32 value;
163eb83479eSAndy Shevchenko 
164eb83479eSAndy Shevchenko 	if (hwirq >= lg->chip.ngpio)
165eb83479eSAndy Shevchenko 		return -EINVAL;
166eb83479eSAndy Shevchenko 
167b2e05d63SAndy Shevchenko 	raw_spin_lock_irqsave(&lg->lock, flags);
168e1940adeSAndy Shevchenko 	value = ioread32(reg);
169eb83479eSAndy Shevchenko 
170eb83479eSAndy Shevchenko 	/* set both TRIG_SEL and INV bits to 0 for rising edge */
171eb83479eSAndy Shevchenko 	if (type & IRQ_TYPE_EDGE_RISING)
172eb83479eSAndy Shevchenko 		value &= ~(TRIG_SEL_BIT | INT_INV_BIT);
173eb83479eSAndy Shevchenko 
174eb83479eSAndy Shevchenko 	/* TRIG_SEL bit 0, INV bit 1 for falling edge */
175eb83479eSAndy Shevchenko 	if (type & IRQ_TYPE_EDGE_FALLING)
176eb83479eSAndy Shevchenko 		value = (value | INT_INV_BIT) & ~TRIG_SEL_BIT;
177eb83479eSAndy Shevchenko 
178eb83479eSAndy Shevchenko 	/* TRIG_SEL bit 1, INV bit 0 for level low */
179eb83479eSAndy Shevchenko 	if (type & IRQ_TYPE_LEVEL_LOW)
180eb83479eSAndy Shevchenko 		value = (value | TRIG_SEL_BIT) & ~INT_INV_BIT;
181eb83479eSAndy Shevchenko 
182eb83479eSAndy Shevchenko 	/* TRIG_SEL bit 1, INV bit 1 for level high */
183eb83479eSAndy Shevchenko 	if (type & IRQ_TYPE_LEVEL_HIGH)
184eb83479eSAndy Shevchenko 		value |= TRIG_SEL_BIT | INT_INV_BIT;
185eb83479eSAndy Shevchenko 
186e1940adeSAndy Shevchenko 	iowrite32(value, reg);
187eb83479eSAndy Shevchenko 
188eb83479eSAndy Shevchenko 	if (type & IRQ_TYPE_EDGE_BOTH)
189eb83479eSAndy Shevchenko 		irq_set_handler_locked(d, handle_edge_irq);
190eb83479eSAndy Shevchenko 	else if (type & IRQ_TYPE_LEVEL_MASK)
191eb83479eSAndy Shevchenko 		irq_set_handler_locked(d, handle_level_irq);
192eb83479eSAndy Shevchenko 
193b2e05d63SAndy Shevchenko 	raw_spin_unlock_irqrestore(&lg->lock, flags);
194eb83479eSAndy Shevchenko 
195eb83479eSAndy Shevchenko 	return 0;
196eb83479eSAndy Shevchenko }
197eb83479eSAndy Shevchenko 
198c35f463aSAndy Shevchenko static int lp_gpio_get(struct gpio_chip *chip, unsigned int offset)
199eb83479eSAndy Shevchenko {
200e1940adeSAndy Shevchenko 	void __iomem *reg = lp_gpio_reg(chip, offset, LP_CONFIG1);
201e1940adeSAndy Shevchenko 	return !!(ioread32(reg) & IN_LVL_BIT);
202eb83479eSAndy Shevchenko }
203eb83479eSAndy Shevchenko 
204c35f463aSAndy Shevchenko static void lp_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
205eb83479eSAndy Shevchenko {
206eb83479eSAndy Shevchenko 	struct lp_gpio *lg = gpiochip_get_data(chip);
207e1940adeSAndy Shevchenko 	void __iomem *reg = lp_gpio_reg(chip, offset, LP_CONFIG1);
208eb83479eSAndy Shevchenko 	unsigned long flags;
209eb83479eSAndy Shevchenko 
210b2e05d63SAndy Shevchenko 	raw_spin_lock_irqsave(&lg->lock, flags);
211eb83479eSAndy Shevchenko 
212eb83479eSAndy Shevchenko 	if (value)
213e1940adeSAndy Shevchenko 		iowrite32(ioread32(reg) | OUT_LVL_BIT, reg);
214eb83479eSAndy Shevchenko 	else
215e1940adeSAndy Shevchenko 		iowrite32(ioread32(reg) & ~OUT_LVL_BIT, reg);
216eb83479eSAndy Shevchenko 
217b2e05d63SAndy Shevchenko 	raw_spin_unlock_irqrestore(&lg->lock, flags);
218eb83479eSAndy Shevchenko }
219eb83479eSAndy Shevchenko 
220c35f463aSAndy Shevchenko static int lp_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
221eb83479eSAndy Shevchenko {
222eb83479eSAndy Shevchenko 	struct lp_gpio *lg = gpiochip_get_data(chip);
223e1940adeSAndy Shevchenko 	void __iomem *reg = lp_gpio_reg(chip, offset, LP_CONFIG1);
224eb83479eSAndy Shevchenko 	unsigned long flags;
225eb83479eSAndy Shevchenko 
226b2e05d63SAndy Shevchenko 	raw_spin_lock_irqsave(&lg->lock, flags);
227e1940adeSAndy Shevchenko 	iowrite32(ioread32(reg) | DIR_BIT, reg);
228b2e05d63SAndy Shevchenko 	raw_spin_unlock_irqrestore(&lg->lock, flags);
229eb83479eSAndy Shevchenko 
230eb83479eSAndy Shevchenko 	return 0;
231eb83479eSAndy Shevchenko }
232eb83479eSAndy Shevchenko 
233c35f463aSAndy Shevchenko static int lp_gpio_direction_output(struct gpio_chip *chip, unsigned int offset,
234c35f463aSAndy Shevchenko 				    int value)
235eb83479eSAndy Shevchenko {
236eb83479eSAndy Shevchenko 	struct lp_gpio *lg = gpiochip_get_data(chip);
237e1940adeSAndy Shevchenko 	void __iomem *reg = lp_gpio_reg(chip, offset, LP_CONFIG1);
238eb83479eSAndy Shevchenko 	unsigned long flags;
239eb83479eSAndy Shevchenko 
240eb83479eSAndy Shevchenko 	lp_gpio_set(chip, offset, value);
241eb83479eSAndy Shevchenko 
242b2e05d63SAndy Shevchenko 	raw_spin_lock_irqsave(&lg->lock, flags);
243e1940adeSAndy Shevchenko 	iowrite32(ioread32(reg) & ~DIR_BIT, reg);
244b2e05d63SAndy Shevchenko 	raw_spin_unlock_irqrestore(&lg->lock, flags);
245eb83479eSAndy Shevchenko 
246eb83479eSAndy Shevchenko 	return 0;
247eb83479eSAndy Shevchenko }
248eb83479eSAndy Shevchenko 
249eb83479eSAndy Shevchenko static void lp_gpio_irq_handler(struct irq_desc *desc)
250eb83479eSAndy Shevchenko {
251eb83479eSAndy Shevchenko 	struct irq_data *data = irq_desc_get_irq_data(desc);
252eb83479eSAndy Shevchenko 	struct gpio_chip *gc = irq_desc_get_handler_data(desc);
253eb83479eSAndy Shevchenko 	struct lp_gpio *lg = gpiochip_get_data(gc);
254eb83479eSAndy Shevchenko 	struct irq_chip *chip = irq_data_get_irq_chip(data);
255e1940adeSAndy Shevchenko 	void __iomem *reg, *ena;
256e1940adeSAndy Shevchenko 	unsigned long pending;
257eb83479eSAndy Shevchenko 	u32 base, pin;
258eb83479eSAndy Shevchenko 
259eb83479eSAndy Shevchenko 	/* check from GPIO controller which pin triggered the interrupt */
260eb83479eSAndy Shevchenko 	for (base = 0; base < lg->chip.ngpio; base += 32) {
261eb83479eSAndy Shevchenko 		reg = lp_gpio_reg(&lg->chip, base, LP_INT_STAT);
262eb83479eSAndy Shevchenko 		ena = lp_gpio_reg(&lg->chip, base, LP_INT_ENABLE);
263eb83479eSAndy Shevchenko 
264eb83479eSAndy Shevchenko 		/* Only interrupts that are enabled */
265e1940adeSAndy Shevchenko 		pending = ioread32(reg) & ioread32(ena);
266eb83479eSAndy Shevchenko 
267eb83479eSAndy Shevchenko 		for_each_set_bit(pin, &pending, 32) {
268c35f463aSAndy Shevchenko 			unsigned int irq;
269eb83479eSAndy Shevchenko 
270eb83479eSAndy Shevchenko 			/* Clear before handling so we don't lose an edge */
271e1940adeSAndy Shevchenko 			iowrite32(BIT(pin), reg);
272eb83479eSAndy Shevchenko 
273eb83479eSAndy Shevchenko 			irq = irq_find_mapping(lg->chip.irq.domain, base + pin);
274eb83479eSAndy Shevchenko 			generic_handle_irq(irq);
275eb83479eSAndy Shevchenko 		}
276eb83479eSAndy Shevchenko 	}
277eb83479eSAndy Shevchenko 	chip->irq_eoi(data);
278eb83479eSAndy Shevchenko }
279eb83479eSAndy Shevchenko 
280eb83479eSAndy Shevchenko static void lp_irq_unmask(struct irq_data *d)
281eb83479eSAndy Shevchenko {
282eb83479eSAndy Shevchenko }
283eb83479eSAndy Shevchenko 
284eb83479eSAndy Shevchenko static void lp_irq_mask(struct irq_data *d)
285eb83479eSAndy Shevchenko {
286eb83479eSAndy Shevchenko }
287eb83479eSAndy Shevchenko 
288eb83479eSAndy Shevchenko static void lp_irq_enable(struct irq_data *d)
289eb83479eSAndy Shevchenko {
290eb83479eSAndy Shevchenko 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
291eb83479eSAndy Shevchenko 	struct lp_gpio *lg = gpiochip_get_data(gc);
292eb83479eSAndy Shevchenko 	u32 hwirq = irqd_to_hwirq(d);
293e1940adeSAndy Shevchenko 	void __iomem *reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_ENABLE);
294eb83479eSAndy Shevchenko 	unsigned long flags;
295eb83479eSAndy Shevchenko 
296b2e05d63SAndy Shevchenko 	raw_spin_lock_irqsave(&lg->lock, flags);
297e1940adeSAndy Shevchenko 	iowrite32(ioread32(reg) | BIT(hwirq % 32), reg);
298b2e05d63SAndy Shevchenko 	raw_spin_unlock_irqrestore(&lg->lock, flags);
299eb83479eSAndy Shevchenko }
300eb83479eSAndy Shevchenko 
301eb83479eSAndy Shevchenko static void lp_irq_disable(struct irq_data *d)
302eb83479eSAndy Shevchenko {
303eb83479eSAndy Shevchenko 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
304eb83479eSAndy Shevchenko 	struct lp_gpio *lg = gpiochip_get_data(gc);
305eb83479eSAndy Shevchenko 	u32 hwirq = irqd_to_hwirq(d);
306e1940adeSAndy Shevchenko 	void __iomem *reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_ENABLE);
307eb83479eSAndy Shevchenko 	unsigned long flags;
308eb83479eSAndy Shevchenko 
309b2e05d63SAndy Shevchenko 	raw_spin_lock_irqsave(&lg->lock, flags);
310e1940adeSAndy Shevchenko 	iowrite32(ioread32(reg) & ~BIT(hwirq % 32), reg);
311b2e05d63SAndy Shevchenko 	raw_spin_unlock_irqrestore(&lg->lock, flags);
312eb83479eSAndy Shevchenko }
313eb83479eSAndy Shevchenko 
314eb83479eSAndy Shevchenko static struct irq_chip lp_irqchip = {
315eb83479eSAndy Shevchenko 	.name = "LP-GPIO",
316eb83479eSAndy Shevchenko 	.irq_mask = lp_irq_mask,
317eb83479eSAndy Shevchenko 	.irq_unmask = lp_irq_unmask,
318eb83479eSAndy Shevchenko 	.irq_enable = lp_irq_enable,
319eb83479eSAndy Shevchenko 	.irq_disable = lp_irq_disable,
320eb83479eSAndy Shevchenko 	.irq_set_type = lp_irq_type,
321eb83479eSAndy Shevchenko 	.flags = IRQCHIP_SKIP_SET_WAKE,
322eb83479eSAndy Shevchenko };
323eb83479eSAndy Shevchenko 
324eb83479eSAndy Shevchenko static int lp_gpio_irq_init_hw(struct gpio_chip *chip)
325eb83479eSAndy Shevchenko {
326eb83479eSAndy Shevchenko 	struct lp_gpio *lg = gpiochip_get_data(chip);
327e1940adeSAndy Shevchenko 	void __iomem *reg;
328c35f463aSAndy Shevchenko 	unsigned int base;
329eb83479eSAndy Shevchenko 
330eb83479eSAndy Shevchenko 	for (base = 0; base < lg->chip.ngpio; base += 32) {
331eb83479eSAndy Shevchenko 		/* disable gpio pin interrupts */
332eb83479eSAndy Shevchenko 		reg = lp_gpio_reg(&lg->chip, base, LP_INT_ENABLE);
333e1940adeSAndy Shevchenko 		iowrite32(0, reg);
334eb83479eSAndy Shevchenko 		/* Clear interrupt status register */
335eb83479eSAndy Shevchenko 		reg = lp_gpio_reg(&lg->chip, base, LP_INT_STAT);
336e1940adeSAndy Shevchenko 		iowrite32(0xffffffff, reg);
337eb83479eSAndy Shevchenko 	}
338eb83479eSAndy Shevchenko 
339eb83479eSAndy Shevchenko 	return 0;
340eb83479eSAndy Shevchenko }
341eb83479eSAndy Shevchenko 
342eb83479eSAndy Shevchenko static int lp_gpio_probe(struct platform_device *pdev)
343eb83479eSAndy Shevchenko {
344eb83479eSAndy Shevchenko 	struct lp_gpio *lg;
345eb83479eSAndy Shevchenko 	struct gpio_chip *gc;
346eb83479eSAndy Shevchenko 	struct resource *io_rc, *irq_rc;
347eb83479eSAndy Shevchenko 	struct device *dev = &pdev->dev;
348e1940adeSAndy Shevchenko 	void __iomem *regs;
3493b4c2d8eSAndy Shevchenko 	int ret;
350eb83479eSAndy Shevchenko 
351a718e68eSAndy Shevchenko 	lg = devm_kzalloc(dev, sizeof(*lg), GFP_KERNEL);
352eb83479eSAndy Shevchenko 	if (!lg)
353eb83479eSAndy Shevchenko 		return -ENOMEM;
354eb83479eSAndy Shevchenko 
3551e78ea71SAndy Shevchenko 	lg->dev = dev;
356eb83479eSAndy Shevchenko 	platform_set_drvdata(pdev, lg);
357eb83479eSAndy Shevchenko 
358eb83479eSAndy Shevchenko 	io_rc = platform_get_resource(pdev, IORESOURCE_IO, 0);
359eb83479eSAndy Shevchenko 	if (!io_rc) {
360eb83479eSAndy Shevchenko 		dev_err(dev, "missing IO resources\n");
361eb83479eSAndy Shevchenko 		return -EINVAL;
362eb83479eSAndy Shevchenko 	}
363eb83479eSAndy Shevchenko 
364e1940adeSAndy Shevchenko 	regs = devm_ioport_map(dev, io_rc->start, resource_size(io_rc));
365e1940adeSAndy Shevchenko 	if (!regs) {
366e1940adeSAndy Shevchenko 		dev_err(dev, "failed mapping IO region %pR\n", &io_rc);
367eb83479eSAndy Shevchenko 		return -EBUSY;
368eb83479eSAndy Shevchenko 	}
369eb83479eSAndy Shevchenko 
370e1940adeSAndy Shevchenko 	lg->regs = regs;
371e1940adeSAndy Shevchenko 
372b2e05d63SAndy Shevchenko 	raw_spin_lock_init(&lg->lock);
373eb83479eSAndy Shevchenko 
374eb83479eSAndy Shevchenko 	gc = &lg->chip;
375eb83479eSAndy Shevchenko 	gc->label = dev_name(dev);
376eb83479eSAndy Shevchenko 	gc->owner = THIS_MODULE;
377eb83479eSAndy Shevchenko 	gc->request = lp_gpio_request;
378eb83479eSAndy Shevchenko 	gc->free = lp_gpio_free;
379eb83479eSAndy Shevchenko 	gc->direction_input = lp_gpio_direction_input;
380eb83479eSAndy Shevchenko 	gc->direction_output = lp_gpio_direction_output;
381eb83479eSAndy Shevchenko 	gc->get = lp_gpio_get;
382eb83479eSAndy Shevchenko 	gc->set = lp_gpio_set;
383eb83479eSAndy Shevchenko 	gc->base = -1;
384eb83479eSAndy Shevchenko 	gc->ngpio = LP_NUM_GPIO;
385eb83479eSAndy Shevchenko 	gc->can_sleep = false;
386eb83479eSAndy Shevchenko 	gc->parent = dev;
387eb83479eSAndy Shevchenko 
388eb83479eSAndy Shevchenko 	/* set up interrupts  */
389e1940adeSAndy Shevchenko 	irq_rc = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
390eb83479eSAndy Shevchenko 	if (irq_rc && irq_rc->start) {
391eb83479eSAndy Shevchenko 		struct gpio_irq_chip *girq;
392eb83479eSAndy Shevchenko 
393eb83479eSAndy Shevchenko 		girq = &gc->irq;
394eb83479eSAndy Shevchenko 		girq->chip = &lp_irqchip;
395eb83479eSAndy Shevchenko 		girq->init_hw = lp_gpio_irq_init_hw;
396eb83479eSAndy Shevchenko 		girq->parent_handler = lp_gpio_irq_handler;
397eb83479eSAndy Shevchenko 		girq->num_parents = 1;
3981e78ea71SAndy Shevchenko 		girq->parents = devm_kcalloc(dev, girq->num_parents,
399eb83479eSAndy Shevchenko 					     sizeof(*girq->parents),
400eb83479eSAndy Shevchenko 					     GFP_KERNEL);
401eb83479eSAndy Shevchenko 		if (!girq->parents)
402eb83479eSAndy Shevchenko 			return -ENOMEM;
403c35f463aSAndy Shevchenko 		girq->parents[0] = (unsigned int)irq_rc->start;
404eb83479eSAndy Shevchenko 		girq->default_type = IRQ_TYPE_NONE;
405eb83479eSAndy Shevchenko 		girq->handler = handle_bad_irq;
406eb83479eSAndy Shevchenko 	}
407eb83479eSAndy Shevchenko 
408eb83479eSAndy Shevchenko 	ret = devm_gpiochip_add_data(dev, gc, lg);
409eb83479eSAndy Shevchenko 	if (ret) {
410eb83479eSAndy Shevchenko 		dev_err(dev, "failed adding lp-gpio chip\n");
411eb83479eSAndy Shevchenko 		return ret;
412eb83479eSAndy Shevchenko 	}
413eb83479eSAndy Shevchenko 
414eb83479eSAndy Shevchenko 	pm_runtime_enable(dev);
415eb83479eSAndy Shevchenko 
416eb83479eSAndy Shevchenko 	return 0;
417eb83479eSAndy Shevchenko }
418eb83479eSAndy Shevchenko 
419eb83479eSAndy Shevchenko static int lp_gpio_runtime_suspend(struct device *dev)
420eb83479eSAndy Shevchenko {
421eb83479eSAndy Shevchenko 	return 0;
422eb83479eSAndy Shevchenko }
423eb83479eSAndy Shevchenko 
424eb83479eSAndy Shevchenko static int lp_gpio_runtime_resume(struct device *dev)
425eb83479eSAndy Shevchenko {
426eb83479eSAndy Shevchenko 	return 0;
427eb83479eSAndy Shevchenko }
428eb83479eSAndy Shevchenko 
429eb83479eSAndy Shevchenko static int lp_gpio_resume(struct device *dev)
430eb83479eSAndy Shevchenko {
431eb83479eSAndy Shevchenko 	struct lp_gpio *lg = dev_get_drvdata(dev);
432e1940adeSAndy Shevchenko 	void __iomem *reg;
433eb83479eSAndy Shevchenko 	int i;
434eb83479eSAndy Shevchenko 
435eb83479eSAndy Shevchenko 	/* on some hardware suspend clears input sensing, re-enable it here */
436eb83479eSAndy Shevchenko 	for (i = 0; i < lg->chip.ngpio; i++) {
437eb83479eSAndy Shevchenko 		if (gpiochip_is_requested(&lg->chip, i) != NULL) {
438eb83479eSAndy Shevchenko 			reg = lp_gpio_reg(&lg->chip, i, LP_CONFIG2);
439e1940adeSAndy Shevchenko 			iowrite32(ioread32(reg) & ~GPINDIS_BIT, reg);
440eb83479eSAndy Shevchenko 		}
441eb83479eSAndy Shevchenko 	}
442eb83479eSAndy Shevchenko 	return 0;
443eb83479eSAndy Shevchenko }
444eb83479eSAndy Shevchenko 
445eb83479eSAndy Shevchenko static const struct dev_pm_ops lp_gpio_pm_ops = {
446eb83479eSAndy Shevchenko 	.runtime_suspend = lp_gpio_runtime_suspend,
447eb83479eSAndy Shevchenko 	.runtime_resume = lp_gpio_runtime_resume,
448eb83479eSAndy Shevchenko 	.resume = lp_gpio_resume,
449eb83479eSAndy Shevchenko };
450eb83479eSAndy Shevchenko 
451eb83479eSAndy Shevchenko static const struct acpi_device_id lynxpoint_gpio_acpi_match[] = {
452eb83479eSAndy Shevchenko 	{ "INT33C7", 0 },
453eb83479eSAndy Shevchenko 	{ "INT3437", 0 },
454eb83479eSAndy Shevchenko 	{ }
455eb83479eSAndy Shevchenko };
456eb83479eSAndy Shevchenko MODULE_DEVICE_TABLE(acpi, lynxpoint_gpio_acpi_match);
457eb83479eSAndy Shevchenko 
458eb83479eSAndy Shevchenko static int lp_gpio_remove(struct platform_device *pdev)
459eb83479eSAndy Shevchenko {
460eb83479eSAndy Shevchenko 	pm_runtime_disable(&pdev->dev);
461eb83479eSAndy Shevchenko 	return 0;
462eb83479eSAndy Shevchenko }
463eb83479eSAndy Shevchenko 
464eb83479eSAndy Shevchenko static struct platform_driver lp_gpio_driver = {
465eb83479eSAndy Shevchenko 	.probe          = lp_gpio_probe,
466eb83479eSAndy Shevchenko 	.remove         = lp_gpio_remove,
467eb83479eSAndy Shevchenko 	.driver         = {
468eb83479eSAndy Shevchenko 		.name   = "lp_gpio",
469eb83479eSAndy Shevchenko 		.pm	= &lp_gpio_pm_ops,
470eb83479eSAndy Shevchenko 		.acpi_match_table = ACPI_PTR(lynxpoint_gpio_acpi_match),
471eb83479eSAndy Shevchenko 	},
472eb83479eSAndy Shevchenko };
473eb83479eSAndy Shevchenko 
474eb83479eSAndy Shevchenko static int __init lp_gpio_init(void)
475eb83479eSAndy Shevchenko {
476eb83479eSAndy Shevchenko 	return platform_driver_register(&lp_gpio_driver);
477eb83479eSAndy Shevchenko }
478eb83479eSAndy Shevchenko 
479eb83479eSAndy Shevchenko static void __exit lp_gpio_exit(void)
480eb83479eSAndy Shevchenko {
481eb83479eSAndy Shevchenko 	platform_driver_unregister(&lp_gpio_driver);
482eb83479eSAndy Shevchenko }
483eb83479eSAndy Shevchenko 
484eb83479eSAndy Shevchenko subsys_initcall(lp_gpio_init);
485eb83479eSAndy Shevchenko module_exit(lp_gpio_exit);
486eb83479eSAndy Shevchenko 
487eb83479eSAndy Shevchenko MODULE_AUTHOR("Mathias Nyman (Intel)");
488eb83479eSAndy Shevchenko MODULE_DESCRIPTION("GPIO interface for Intel Lynxpoint");
489eb83479eSAndy Shevchenko MODULE_LICENSE("GPL v2");
490eb83479eSAndy Shevchenko MODULE_ALIAS("platform:lp_gpio");
491