xref: /linux/drivers/pinctrl/intel/pinctrl-lynxpoint.c (revision a718e68ede16957e091ee8f35f7b73765e51a092)
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 */
41eb83479eSAndy Shevchenko #define USE_SEL_BIT	BIT(0) /* 0: Native, 1: GPIO */
42eb83479eSAndy Shevchenko 
43eb83479eSAndy Shevchenko /* LP_CONFIG2 reg bits */
44eb83479eSAndy Shevchenko #define GPINDIS_BIT	BIT(2) /* disable input sensing */
45eb83479eSAndy Shevchenko #define GPIWP_BIT	(BIT(0) | BIT(1)) /* weak pull options */
46eb83479eSAndy Shevchenko 
47eb83479eSAndy Shevchenko struct lp_gpio {
48eb83479eSAndy Shevchenko 	struct gpio_chip	chip;
49eb83479eSAndy Shevchenko 	struct platform_device	*pdev;
50b2e05d63SAndy Shevchenko 	raw_spinlock_t		lock;
51eb83479eSAndy Shevchenko 	unsigned long		reg_base;
52eb83479eSAndy Shevchenko };
53eb83479eSAndy Shevchenko 
54eb83479eSAndy Shevchenko /*
55eb83479eSAndy Shevchenko  * Lynxpoint gpios are controlled through both bitmapped registers and
56eb83479eSAndy Shevchenko  * per gpio specific registers. The bitmapped registers are in chunks of
577c0bc7bbSAndy Shevchenko  * 3 x 32bit registers to cover all 95 GPIOs
58eb83479eSAndy Shevchenko  *
59eb83479eSAndy Shevchenko  * per gpio specific registers consist of two 32bit registers per gpio
607c0bc7bbSAndy Shevchenko  * (LP_CONFIG1 and LP_CONFIG2), with 95 GPIOs there's a total of
617c0bc7bbSAndy Shevchenko  * 190 config registers.
62eb83479eSAndy Shevchenko  *
63eb83479eSAndy Shevchenko  * A simplified view of the register layout look like this:
64eb83479eSAndy Shevchenko  *
65eb83479eSAndy Shevchenko  * LP_ACPI_OWNED[31:0] gpio ownerships for gpios 0-31  (bitmapped registers)
66eb83479eSAndy Shevchenko  * LP_ACPI_OWNED[63:32] gpio ownerships for gpios 32-63
67eb83479eSAndy Shevchenko  * LP_ACPI_OWNED[94:64] gpio ownerships for gpios 63-94
68eb83479eSAndy Shevchenko  * ...
69eb83479eSAndy Shevchenko  * LP_INT_ENABLE[31:0] ...
707c0bc7bbSAndy Shevchenko  * LP_INT_ENABLE[63:32] ...
71eb83479eSAndy Shevchenko  * LP_INT_ENABLE[94:64] ...
72eb83479eSAndy Shevchenko  * LP0_CONFIG1 (gpio 0) config1 reg for gpio 0 (per gpio registers)
73eb83479eSAndy Shevchenko  * LP0_CONFIG2 (gpio 0) config2 reg for gpio 0
74eb83479eSAndy Shevchenko  * LP1_CONFIG1 (gpio 1) config1 reg for gpio 1
75eb83479eSAndy Shevchenko  * LP1_CONFIG2 (gpio 1) config2 reg for gpio 1
76eb83479eSAndy Shevchenko  * LP2_CONFIG1 (gpio 2) ...
77eb83479eSAndy Shevchenko  * LP2_CONFIG2 (gpio 2) ...
78eb83479eSAndy Shevchenko  * ...
79eb83479eSAndy Shevchenko  * LP94_CONFIG1 (gpio 94) ...
80eb83479eSAndy Shevchenko  * LP94_CONFIG2 (gpio 94) ...
81eb83479eSAndy Shevchenko  */
82eb83479eSAndy Shevchenko 
83eb83479eSAndy Shevchenko static unsigned long lp_gpio_reg(struct gpio_chip *chip, unsigned offset,
84eb83479eSAndy Shevchenko 				 int reg)
85eb83479eSAndy Shevchenko {
86eb83479eSAndy Shevchenko 	struct lp_gpio *lg = gpiochip_get_data(chip);
87eb83479eSAndy Shevchenko 	int reg_offset;
88eb83479eSAndy Shevchenko 
89eb83479eSAndy Shevchenko 	if (reg == LP_CONFIG1 || reg == LP_CONFIG2)
90eb83479eSAndy Shevchenko 		/* per gpio specific config registers */
91eb83479eSAndy Shevchenko 		reg_offset = offset * 8;
92eb83479eSAndy Shevchenko 	else
93eb83479eSAndy Shevchenko 		/* bitmapped registers */
94eb83479eSAndy Shevchenko 		reg_offset = (offset / 32) * 4;
95eb83479eSAndy Shevchenko 
96eb83479eSAndy Shevchenko 	return lg->reg_base + reg + reg_offset;
97eb83479eSAndy Shevchenko }
98eb83479eSAndy Shevchenko 
99eb83479eSAndy Shevchenko static int lp_gpio_request(struct gpio_chip *chip, unsigned offset)
100eb83479eSAndy Shevchenko {
101eb83479eSAndy Shevchenko 	struct lp_gpio *lg = gpiochip_get_data(chip);
102eb83479eSAndy Shevchenko 	unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1);
103eb83479eSAndy Shevchenko 	unsigned long conf2 = lp_gpio_reg(chip, offset, LP_CONFIG2);
104eb83479eSAndy Shevchenko 	unsigned long acpi_use = lp_gpio_reg(chip, offset, LP_ACPI_OWNED);
105eb83479eSAndy Shevchenko 
106eb83479eSAndy Shevchenko 	pm_runtime_get(&lg->pdev->dev); /* should we put if failed */
107eb83479eSAndy Shevchenko 
108eb83479eSAndy Shevchenko 	/* Fail if BIOS reserved pin for ACPI use */
109eb83479eSAndy Shevchenko 	if (!(inl(acpi_use) & BIT(offset % 32))) {
110eb83479eSAndy Shevchenko 		dev_err(&lg->pdev->dev, "gpio %d reserved for ACPI\n", offset);
111eb83479eSAndy Shevchenko 		return -EBUSY;
112eb83479eSAndy Shevchenko 	}
113eb83479eSAndy Shevchenko 	/* Fail if pin is in alternate function mode (not GPIO mode) */
114eb83479eSAndy Shevchenko 	if (!(inl(reg) & USE_SEL_BIT))
115eb83479eSAndy Shevchenko 		return -ENODEV;
116eb83479eSAndy Shevchenko 
117eb83479eSAndy Shevchenko 	/* enable input sensing */
118eb83479eSAndy Shevchenko 	outl(inl(conf2) & ~GPINDIS_BIT, conf2);
119eb83479eSAndy Shevchenko 
120eb83479eSAndy Shevchenko 
121eb83479eSAndy Shevchenko 	return 0;
122eb83479eSAndy Shevchenko }
123eb83479eSAndy Shevchenko 
124eb83479eSAndy Shevchenko static void lp_gpio_free(struct gpio_chip *chip, unsigned offset)
125eb83479eSAndy Shevchenko {
126eb83479eSAndy Shevchenko 	struct lp_gpio *lg = gpiochip_get_data(chip);
127eb83479eSAndy Shevchenko 	unsigned long conf2 = lp_gpio_reg(chip, offset, LP_CONFIG2);
128eb83479eSAndy Shevchenko 
129eb83479eSAndy Shevchenko 	/* disable input sensing */
130eb83479eSAndy Shevchenko 	outl(inl(conf2) | GPINDIS_BIT, conf2);
131eb83479eSAndy Shevchenko 
132eb83479eSAndy Shevchenko 	pm_runtime_put(&lg->pdev->dev);
133eb83479eSAndy Shevchenko }
134eb83479eSAndy Shevchenko 
135eb83479eSAndy Shevchenko static int lp_irq_type(struct irq_data *d, unsigned type)
136eb83479eSAndy Shevchenko {
137eb83479eSAndy Shevchenko 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
138eb83479eSAndy Shevchenko 	struct lp_gpio *lg = gpiochip_get_data(gc);
139eb83479eSAndy Shevchenko 	u32 hwirq = irqd_to_hwirq(d);
140eb83479eSAndy Shevchenko 	unsigned long flags;
141eb83479eSAndy Shevchenko 	u32 value;
142eb83479eSAndy Shevchenko 	unsigned long reg = lp_gpio_reg(&lg->chip, hwirq, LP_CONFIG1);
143eb83479eSAndy Shevchenko 
144eb83479eSAndy Shevchenko 	if (hwirq >= lg->chip.ngpio)
145eb83479eSAndy Shevchenko 		return -EINVAL;
146eb83479eSAndy Shevchenko 
147b2e05d63SAndy Shevchenko 	raw_spin_lock_irqsave(&lg->lock, flags);
148eb83479eSAndy Shevchenko 	value = inl(reg);
149eb83479eSAndy Shevchenko 
150eb83479eSAndy Shevchenko 	/* set both TRIG_SEL and INV bits to 0 for rising edge */
151eb83479eSAndy Shevchenko 	if (type & IRQ_TYPE_EDGE_RISING)
152eb83479eSAndy Shevchenko 		value &= ~(TRIG_SEL_BIT | INT_INV_BIT);
153eb83479eSAndy Shevchenko 
154eb83479eSAndy Shevchenko 	/* TRIG_SEL bit 0, INV bit 1 for falling edge */
155eb83479eSAndy Shevchenko 	if (type & IRQ_TYPE_EDGE_FALLING)
156eb83479eSAndy Shevchenko 		value = (value | INT_INV_BIT) & ~TRIG_SEL_BIT;
157eb83479eSAndy Shevchenko 
158eb83479eSAndy Shevchenko 	/* TRIG_SEL bit 1, INV bit 0 for level low */
159eb83479eSAndy Shevchenko 	if (type & IRQ_TYPE_LEVEL_LOW)
160eb83479eSAndy Shevchenko 		value = (value | TRIG_SEL_BIT) & ~INT_INV_BIT;
161eb83479eSAndy Shevchenko 
162eb83479eSAndy Shevchenko 	/* TRIG_SEL bit 1, INV bit 1 for level high */
163eb83479eSAndy Shevchenko 	if (type & IRQ_TYPE_LEVEL_HIGH)
164eb83479eSAndy Shevchenko 		value |= TRIG_SEL_BIT | INT_INV_BIT;
165eb83479eSAndy Shevchenko 
166eb83479eSAndy Shevchenko 	outl(value, reg);
167eb83479eSAndy Shevchenko 
168eb83479eSAndy Shevchenko 	if (type & IRQ_TYPE_EDGE_BOTH)
169eb83479eSAndy Shevchenko 		irq_set_handler_locked(d, handle_edge_irq);
170eb83479eSAndy Shevchenko 	else if (type & IRQ_TYPE_LEVEL_MASK)
171eb83479eSAndy Shevchenko 		irq_set_handler_locked(d, handle_level_irq);
172eb83479eSAndy Shevchenko 
173b2e05d63SAndy Shevchenko 	raw_spin_unlock_irqrestore(&lg->lock, flags);
174eb83479eSAndy Shevchenko 
175eb83479eSAndy Shevchenko 	return 0;
176eb83479eSAndy Shevchenko }
177eb83479eSAndy Shevchenko 
178eb83479eSAndy Shevchenko static int lp_gpio_get(struct gpio_chip *chip, unsigned offset)
179eb83479eSAndy Shevchenko {
180eb83479eSAndy Shevchenko 	unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1);
181eb83479eSAndy Shevchenko 	return !!(inl(reg) & IN_LVL_BIT);
182eb83479eSAndy Shevchenko }
183eb83479eSAndy Shevchenko 
184eb83479eSAndy Shevchenko static void lp_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
185eb83479eSAndy Shevchenko {
186eb83479eSAndy Shevchenko 	struct lp_gpio *lg = gpiochip_get_data(chip);
187eb83479eSAndy Shevchenko 	unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1);
188eb83479eSAndy Shevchenko 	unsigned long flags;
189eb83479eSAndy Shevchenko 
190b2e05d63SAndy Shevchenko 	raw_spin_lock_irqsave(&lg->lock, flags);
191eb83479eSAndy Shevchenko 
192eb83479eSAndy Shevchenko 	if (value)
193eb83479eSAndy Shevchenko 		outl(inl(reg) | OUT_LVL_BIT, reg);
194eb83479eSAndy Shevchenko 	else
195eb83479eSAndy Shevchenko 		outl(inl(reg) & ~OUT_LVL_BIT, reg);
196eb83479eSAndy Shevchenko 
197b2e05d63SAndy Shevchenko 	raw_spin_unlock_irqrestore(&lg->lock, flags);
198eb83479eSAndy Shevchenko }
199eb83479eSAndy Shevchenko 
200eb83479eSAndy Shevchenko static int lp_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
201eb83479eSAndy Shevchenko {
202eb83479eSAndy Shevchenko 	struct lp_gpio *lg = gpiochip_get_data(chip);
203eb83479eSAndy Shevchenko 	unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1);
204eb83479eSAndy Shevchenko 	unsigned long flags;
205eb83479eSAndy Shevchenko 
206b2e05d63SAndy Shevchenko 	raw_spin_lock_irqsave(&lg->lock, flags);
207eb83479eSAndy Shevchenko 	outl(inl(reg) | DIR_BIT, reg);
208b2e05d63SAndy Shevchenko 	raw_spin_unlock_irqrestore(&lg->lock, flags);
209eb83479eSAndy Shevchenko 
210eb83479eSAndy Shevchenko 	return 0;
211eb83479eSAndy Shevchenko }
212eb83479eSAndy Shevchenko 
213eb83479eSAndy Shevchenko static int lp_gpio_direction_output(struct gpio_chip *chip,
214eb83479eSAndy Shevchenko 				      unsigned offset, int value)
215eb83479eSAndy Shevchenko {
216eb83479eSAndy Shevchenko 	struct lp_gpio *lg = gpiochip_get_data(chip);
217eb83479eSAndy Shevchenko 	unsigned long reg = lp_gpio_reg(chip, offset, LP_CONFIG1);
218eb83479eSAndy Shevchenko 	unsigned long flags;
219eb83479eSAndy Shevchenko 
220eb83479eSAndy Shevchenko 	lp_gpio_set(chip, offset, value);
221eb83479eSAndy Shevchenko 
222b2e05d63SAndy Shevchenko 	raw_spin_lock_irqsave(&lg->lock, flags);
223eb83479eSAndy Shevchenko 	outl(inl(reg) & ~DIR_BIT, reg);
224b2e05d63SAndy Shevchenko 	raw_spin_unlock_irqrestore(&lg->lock, flags);
225eb83479eSAndy Shevchenko 
226eb83479eSAndy Shevchenko 	return 0;
227eb83479eSAndy Shevchenko }
228eb83479eSAndy Shevchenko 
229eb83479eSAndy Shevchenko static void lp_gpio_irq_handler(struct irq_desc *desc)
230eb83479eSAndy Shevchenko {
231eb83479eSAndy Shevchenko 	struct irq_data *data = irq_desc_get_irq_data(desc);
232eb83479eSAndy Shevchenko 	struct gpio_chip *gc = irq_desc_get_handler_data(desc);
233eb83479eSAndy Shevchenko 	struct lp_gpio *lg = gpiochip_get_data(gc);
234eb83479eSAndy Shevchenko 	struct irq_chip *chip = irq_data_get_irq_chip(data);
235eb83479eSAndy Shevchenko 	unsigned long reg, ena, pending;
236eb83479eSAndy Shevchenko 	u32 base, pin;
237eb83479eSAndy Shevchenko 
238eb83479eSAndy Shevchenko 	/* check from GPIO controller which pin triggered the interrupt */
239eb83479eSAndy Shevchenko 	for (base = 0; base < lg->chip.ngpio; base += 32) {
240eb83479eSAndy Shevchenko 		reg = lp_gpio_reg(&lg->chip, base, LP_INT_STAT);
241eb83479eSAndy Shevchenko 		ena = lp_gpio_reg(&lg->chip, base, LP_INT_ENABLE);
242eb83479eSAndy Shevchenko 
243eb83479eSAndy Shevchenko 		/* Only interrupts that are enabled */
244eb83479eSAndy Shevchenko 		pending = inl(reg) & inl(ena);
245eb83479eSAndy Shevchenko 
246eb83479eSAndy Shevchenko 		for_each_set_bit(pin, &pending, 32) {
247eb83479eSAndy Shevchenko 			unsigned irq;
248eb83479eSAndy Shevchenko 
249eb83479eSAndy Shevchenko 			/* Clear before handling so we don't lose an edge */
250eb83479eSAndy Shevchenko 			outl(BIT(pin), reg);
251eb83479eSAndy Shevchenko 
252eb83479eSAndy Shevchenko 			irq = irq_find_mapping(lg->chip.irq.domain, base + pin);
253eb83479eSAndy Shevchenko 			generic_handle_irq(irq);
254eb83479eSAndy Shevchenko 		}
255eb83479eSAndy Shevchenko 	}
256eb83479eSAndy Shevchenko 	chip->irq_eoi(data);
257eb83479eSAndy Shevchenko }
258eb83479eSAndy Shevchenko 
259eb83479eSAndy Shevchenko static void lp_irq_unmask(struct irq_data *d)
260eb83479eSAndy Shevchenko {
261eb83479eSAndy Shevchenko }
262eb83479eSAndy Shevchenko 
263eb83479eSAndy Shevchenko static void lp_irq_mask(struct irq_data *d)
264eb83479eSAndy Shevchenko {
265eb83479eSAndy Shevchenko }
266eb83479eSAndy Shevchenko 
267eb83479eSAndy Shevchenko static void lp_irq_enable(struct irq_data *d)
268eb83479eSAndy Shevchenko {
269eb83479eSAndy Shevchenko 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
270eb83479eSAndy Shevchenko 	struct lp_gpio *lg = gpiochip_get_data(gc);
271eb83479eSAndy Shevchenko 	u32 hwirq = irqd_to_hwirq(d);
272eb83479eSAndy Shevchenko 	unsigned long reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_ENABLE);
273eb83479eSAndy Shevchenko 	unsigned long flags;
274eb83479eSAndy Shevchenko 
275b2e05d63SAndy Shevchenko 	raw_spin_lock_irqsave(&lg->lock, flags);
276eb83479eSAndy Shevchenko 	outl(inl(reg) | BIT(hwirq % 32), reg);
277b2e05d63SAndy Shevchenko 	raw_spin_unlock_irqrestore(&lg->lock, flags);
278eb83479eSAndy Shevchenko }
279eb83479eSAndy Shevchenko 
280eb83479eSAndy Shevchenko static void lp_irq_disable(struct irq_data *d)
281eb83479eSAndy Shevchenko {
282eb83479eSAndy Shevchenko 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
283eb83479eSAndy Shevchenko 	struct lp_gpio *lg = gpiochip_get_data(gc);
284eb83479eSAndy Shevchenko 	u32 hwirq = irqd_to_hwirq(d);
285eb83479eSAndy Shevchenko 	unsigned long reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_ENABLE);
286eb83479eSAndy Shevchenko 	unsigned long flags;
287eb83479eSAndy Shevchenko 
288b2e05d63SAndy Shevchenko 	raw_spin_lock_irqsave(&lg->lock, flags);
289eb83479eSAndy Shevchenko 	outl(inl(reg) & ~BIT(hwirq % 32), reg);
290b2e05d63SAndy Shevchenko 	raw_spin_unlock_irqrestore(&lg->lock, flags);
291eb83479eSAndy Shevchenko }
292eb83479eSAndy Shevchenko 
293eb83479eSAndy Shevchenko static struct irq_chip lp_irqchip = {
294eb83479eSAndy Shevchenko 	.name = "LP-GPIO",
295eb83479eSAndy Shevchenko 	.irq_mask = lp_irq_mask,
296eb83479eSAndy Shevchenko 	.irq_unmask = lp_irq_unmask,
297eb83479eSAndy Shevchenko 	.irq_enable = lp_irq_enable,
298eb83479eSAndy Shevchenko 	.irq_disable = lp_irq_disable,
299eb83479eSAndy Shevchenko 	.irq_set_type = lp_irq_type,
300eb83479eSAndy Shevchenko 	.flags = IRQCHIP_SKIP_SET_WAKE,
301eb83479eSAndy Shevchenko };
302eb83479eSAndy Shevchenko 
303eb83479eSAndy Shevchenko static int lp_gpio_irq_init_hw(struct gpio_chip *chip)
304eb83479eSAndy Shevchenko {
305eb83479eSAndy Shevchenko 	struct lp_gpio *lg = gpiochip_get_data(chip);
306eb83479eSAndy Shevchenko 	unsigned long reg;
307eb83479eSAndy Shevchenko 	unsigned base;
308eb83479eSAndy Shevchenko 
309eb83479eSAndy Shevchenko 	for (base = 0; base < lg->chip.ngpio; base += 32) {
310eb83479eSAndy Shevchenko 		/* disable gpio pin interrupts */
311eb83479eSAndy Shevchenko 		reg = lp_gpio_reg(&lg->chip, base, LP_INT_ENABLE);
312eb83479eSAndy Shevchenko 		outl(0, reg);
313eb83479eSAndy Shevchenko 		/* Clear interrupt status register */
314eb83479eSAndy Shevchenko 		reg = lp_gpio_reg(&lg->chip, base, LP_INT_STAT);
315eb83479eSAndy Shevchenko 		outl(0xffffffff, reg);
316eb83479eSAndy Shevchenko 	}
317eb83479eSAndy Shevchenko 
318eb83479eSAndy Shevchenko 	return 0;
319eb83479eSAndy Shevchenko }
320eb83479eSAndy Shevchenko 
321eb83479eSAndy Shevchenko static int lp_gpio_probe(struct platform_device *pdev)
322eb83479eSAndy Shevchenko {
323eb83479eSAndy Shevchenko 	struct lp_gpio *lg;
324eb83479eSAndy Shevchenko 	struct gpio_chip *gc;
325eb83479eSAndy Shevchenko 	struct resource *io_rc, *irq_rc;
326eb83479eSAndy Shevchenko 	struct device *dev = &pdev->dev;
327eb83479eSAndy Shevchenko 	unsigned long reg_len;
3283b4c2d8eSAndy Shevchenko 	int ret;
329eb83479eSAndy Shevchenko 
330*a718e68eSAndy Shevchenko 	lg = devm_kzalloc(dev, sizeof(*lg), GFP_KERNEL);
331eb83479eSAndy Shevchenko 	if (!lg)
332eb83479eSAndy Shevchenko 		return -ENOMEM;
333eb83479eSAndy Shevchenko 
334eb83479eSAndy Shevchenko 	lg->pdev = pdev;
335eb83479eSAndy Shevchenko 	platform_set_drvdata(pdev, lg);
336eb83479eSAndy Shevchenko 
337eb83479eSAndy Shevchenko 	io_rc = platform_get_resource(pdev, IORESOURCE_IO, 0);
338eb83479eSAndy Shevchenko 	irq_rc = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
339eb83479eSAndy Shevchenko 
340eb83479eSAndy Shevchenko 	if (!io_rc) {
341eb83479eSAndy Shevchenko 		dev_err(dev, "missing IO resources\n");
342eb83479eSAndy Shevchenko 		return -EINVAL;
343eb83479eSAndy Shevchenko 	}
344eb83479eSAndy Shevchenko 
345eb83479eSAndy Shevchenko 	lg->reg_base = io_rc->start;
346eb83479eSAndy Shevchenko 	reg_len = resource_size(io_rc);
347eb83479eSAndy Shevchenko 
348eb83479eSAndy Shevchenko 	if (!devm_request_region(dev, lg->reg_base, reg_len, "lp-gpio")) {
349caedcbd0SAndy Shevchenko 		dev_err(dev, "failed requesting IO region %pR\n", &io_rc);
350eb83479eSAndy Shevchenko 		return -EBUSY;
351eb83479eSAndy Shevchenko 	}
352eb83479eSAndy Shevchenko 
353b2e05d63SAndy Shevchenko 	raw_spin_lock_init(&lg->lock);
354eb83479eSAndy Shevchenko 
355eb83479eSAndy Shevchenko 	gc = &lg->chip;
356eb83479eSAndy Shevchenko 	gc->label = dev_name(dev);
357eb83479eSAndy Shevchenko 	gc->owner = THIS_MODULE;
358eb83479eSAndy Shevchenko 	gc->request = lp_gpio_request;
359eb83479eSAndy Shevchenko 	gc->free = lp_gpio_free;
360eb83479eSAndy Shevchenko 	gc->direction_input = lp_gpio_direction_input;
361eb83479eSAndy Shevchenko 	gc->direction_output = lp_gpio_direction_output;
362eb83479eSAndy Shevchenko 	gc->get = lp_gpio_get;
363eb83479eSAndy Shevchenko 	gc->set = lp_gpio_set;
364eb83479eSAndy Shevchenko 	gc->base = -1;
365eb83479eSAndy Shevchenko 	gc->ngpio = LP_NUM_GPIO;
366eb83479eSAndy Shevchenko 	gc->can_sleep = false;
367eb83479eSAndy Shevchenko 	gc->parent = dev;
368eb83479eSAndy Shevchenko 
369eb83479eSAndy Shevchenko 	/* set up interrupts  */
370eb83479eSAndy Shevchenko 	if (irq_rc && irq_rc->start) {
371eb83479eSAndy Shevchenko 		struct gpio_irq_chip *girq;
372eb83479eSAndy Shevchenko 
373eb83479eSAndy Shevchenko 		girq = &gc->irq;
374eb83479eSAndy Shevchenko 		girq->chip = &lp_irqchip;
375eb83479eSAndy Shevchenko 		girq->init_hw = lp_gpio_irq_init_hw;
376eb83479eSAndy Shevchenko 		girq->parent_handler = lp_gpio_irq_handler;
377eb83479eSAndy Shevchenko 		girq->num_parents = 1;
378eb83479eSAndy Shevchenko 		girq->parents = devm_kcalloc(&pdev->dev, girq->num_parents,
379eb83479eSAndy Shevchenko 					     sizeof(*girq->parents),
380eb83479eSAndy Shevchenko 					     GFP_KERNEL);
381eb83479eSAndy Shevchenko 		if (!girq->parents)
382eb83479eSAndy Shevchenko 			return -ENOMEM;
383eb83479eSAndy Shevchenko 		girq->parents[0] = (unsigned)irq_rc->start;
384eb83479eSAndy Shevchenko 		girq->default_type = IRQ_TYPE_NONE;
385eb83479eSAndy Shevchenko 		girq->handler = handle_bad_irq;
386eb83479eSAndy Shevchenko 	}
387eb83479eSAndy Shevchenko 
388eb83479eSAndy Shevchenko 	ret = devm_gpiochip_add_data(dev, gc, lg);
389eb83479eSAndy Shevchenko 	if (ret) {
390eb83479eSAndy Shevchenko 		dev_err(dev, "failed adding lp-gpio chip\n");
391eb83479eSAndy Shevchenko 		return ret;
392eb83479eSAndy Shevchenko 	}
393eb83479eSAndy Shevchenko 
394eb83479eSAndy Shevchenko 	pm_runtime_enable(dev);
395eb83479eSAndy Shevchenko 
396eb83479eSAndy Shevchenko 	return 0;
397eb83479eSAndy Shevchenko }
398eb83479eSAndy Shevchenko 
399eb83479eSAndy Shevchenko static int lp_gpio_runtime_suspend(struct device *dev)
400eb83479eSAndy Shevchenko {
401eb83479eSAndy Shevchenko 	return 0;
402eb83479eSAndy Shevchenko }
403eb83479eSAndy Shevchenko 
404eb83479eSAndy Shevchenko static int lp_gpio_runtime_resume(struct device *dev)
405eb83479eSAndy Shevchenko {
406eb83479eSAndy Shevchenko 	return 0;
407eb83479eSAndy Shevchenko }
408eb83479eSAndy Shevchenko 
409eb83479eSAndy Shevchenko static int lp_gpio_resume(struct device *dev)
410eb83479eSAndy Shevchenko {
411eb83479eSAndy Shevchenko 	struct lp_gpio *lg = dev_get_drvdata(dev);
412eb83479eSAndy Shevchenko 	unsigned long reg;
413eb83479eSAndy Shevchenko 	int i;
414eb83479eSAndy Shevchenko 
415eb83479eSAndy Shevchenko 	/* on some hardware suspend clears input sensing, re-enable it here */
416eb83479eSAndy Shevchenko 	for (i = 0; i < lg->chip.ngpio; i++) {
417eb83479eSAndy Shevchenko 		if (gpiochip_is_requested(&lg->chip, i) != NULL) {
418eb83479eSAndy Shevchenko 			reg = lp_gpio_reg(&lg->chip, i, LP_CONFIG2);
419eb83479eSAndy Shevchenko 			outl(inl(reg) & ~GPINDIS_BIT, reg);
420eb83479eSAndy Shevchenko 		}
421eb83479eSAndy Shevchenko 	}
422eb83479eSAndy Shevchenko 	return 0;
423eb83479eSAndy Shevchenko }
424eb83479eSAndy Shevchenko 
425eb83479eSAndy Shevchenko static const struct dev_pm_ops lp_gpio_pm_ops = {
426eb83479eSAndy Shevchenko 	.runtime_suspend = lp_gpio_runtime_suspend,
427eb83479eSAndy Shevchenko 	.runtime_resume = lp_gpio_runtime_resume,
428eb83479eSAndy Shevchenko 	.resume = lp_gpio_resume,
429eb83479eSAndy Shevchenko };
430eb83479eSAndy Shevchenko 
431eb83479eSAndy Shevchenko static const struct acpi_device_id lynxpoint_gpio_acpi_match[] = {
432eb83479eSAndy Shevchenko 	{ "INT33C7", 0 },
433eb83479eSAndy Shevchenko 	{ "INT3437", 0 },
434eb83479eSAndy Shevchenko 	{ }
435eb83479eSAndy Shevchenko };
436eb83479eSAndy Shevchenko MODULE_DEVICE_TABLE(acpi, lynxpoint_gpio_acpi_match);
437eb83479eSAndy Shevchenko 
438eb83479eSAndy Shevchenko static int lp_gpio_remove(struct platform_device *pdev)
439eb83479eSAndy Shevchenko {
440eb83479eSAndy Shevchenko 	pm_runtime_disable(&pdev->dev);
441eb83479eSAndy Shevchenko 	return 0;
442eb83479eSAndy Shevchenko }
443eb83479eSAndy Shevchenko 
444eb83479eSAndy Shevchenko static struct platform_driver lp_gpio_driver = {
445eb83479eSAndy Shevchenko 	.probe          = lp_gpio_probe,
446eb83479eSAndy Shevchenko 	.remove         = lp_gpio_remove,
447eb83479eSAndy Shevchenko 	.driver         = {
448eb83479eSAndy Shevchenko 		.name   = "lp_gpio",
449eb83479eSAndy Shevchenko 		.pm	= &lp_gpio_pm_ops,
450eb83479eSAndy Shevchenko 		.acpi_match_table = ACPI_PTR(lynxpoint_gpio_acpi_match),
451eb83479eSAndy Shevchenko 	},
452eb83479eSAndy Shevchenko };
453eb83479eSAndy Shevchenko 
454eb83479eSAndy Shevchenko static int __init lp_gpio_init(void)
455eb83479eSAndy Shevchenko {
456eb83479eSAndy Shevchenko 	return platform_driver_register(&lp_gpio_driver);
457eb83479eSAndy Shevchenko }
458eb83479eSAndy Shevchenko 
459eb83479eSAndy Shevchenko static void __exit lp_gpio_exit(void)
460eb83479eSAndy Shevchenko {
461eb83479eSAndy Shevchenko 	platform_driver_unregister(&lp_gpio_driver);
462eb83479eSAndy Shevchenko }
463eb83479eSAndy Shevchenko 
464eb83479eSAndy Shevchenko subsys_initcall(lp_gpio_init);
465eb83479eSAndy Shevchenko module_exit(lp_gpio_exit);
466eb83479eSAndy Shevchenko 
467eb83479eSAndy Shevchenko MODULE_AUTHOR("Mathias Nyman (Intel)");
468eb83479eSAndy Shevchenko MODULE_DESCRIPTION("GPIO interface for Intel Lynxpoint");
469eb83479eSAndy Shevchenko MODULE_LICENSE("GPL v2");
470eb83479eSAndy Shevchenko MODULE_ALIAS("platform:lp_gpio");
471