xref: /linux/drivers/pinctrl/intel/pinctrl-lynxpoint.c (revision 18213ad4187d44f2b58e96529f169c3ae4898b51)
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 
21cecddda7SAndy Shevchenko #include <linux/pinctrl/pinctrl.h>
22cecddda7SAndy Shevchenko #include <linux/pinctrl/pinmux.h>
23cecddda7SAndy Shevchenko #include <linux/pinctrl/pinconf.h>
24cecddda7SAndy Shevchenko #include <linux/pinctrl/pinconf-generic.h>
25cecddda7SAndy Shevchenko 
26cecddda7SAndy Shevchenko #include "pinctrl-intel.h"
27cecddda7SAndy Shevchenko 
28cecddda7SAndy Shevchenko #define COMMUNITY(p, n)			\
29cecddda7SAndy Shevchenko 	{				\
30cecddda7SAndy Shevchenko 		.pin_base	= (p),	\
31cecddda7SAndy Shevchenko 		.npins		= (n),	\
32cecddda7SAndy Shevchenko 	}
33cecddda7SAndy Shevchenko 
34cecddda7SAndy Shevchenko static const struct pinctrl_pin_desc lptlp_pins[] = {
35cecddda7SAndy Shevchenko 	PINCTRL_PIN(0, "GP0_UART1_RXD"),
36cecddda7SAndy Shevchenko 	PINCTRL_PIN(1, "GP1_UART1_TXD"),
37cecddda7SAndy Shevchenko 	PINCTRL_PIN(2, "GP2_UART1_RTSB"),
38cecddda7SAndy Shevchenko 	PINCTRL_PIN(3, "GP3_UART1_CTSB"),
39cecddda7SAndy Shevchenko 	PINCTRL_PIN(4, "GP4_I2C0_SDA"),
40cecddda7SAndy Shevchenko 	PINCTRL_PIN(5, "GP5_I2C0_SCL"),
41cecddda7SAndy Shevchenko 	PINCTRL_PIN(6, "GP6_I2C1_SDA"),
42cecddda7SAndy Shevchenko 	PINCTRL_PIN(7, "GP7_I2C1_SCL"),
43cecddda7SAndy Shevchenko 	PINCTRL_PIN(8, "GP8"),
44cecddda7SAndy Shevchenko 	PINCTRL_PIN(9, "GP9"),
45cecddda7SAndy Shevchenko 	PINCTRL_PIN(10, "GP10"),
46cecddda7SAndy Shevchenko 	PINCTRL_PIN(11, "GP11_SMBALERTB"),
47cecddda7SAndy Shevchenko 	PINCTRL_PIN(12, "GP12_LANPHYPC"),
48cecddda7SAndy Shevchenko 	PINCTRL_PIN(13, "GP13"),
49cecddda7SAndy Shevchenko 	PINCTRL_PIN(14, "GP14"),
50cecddda7SAndy Shevchenko 	PINCTRL_PIN(15, "GP15"),
51cecddda7SAndy Shevchenko 	PINCTRL_PIN(16, "GP16_MGPIO9"),
52cecddda7SAndy Shevchenko 	PINCTRL_PIN(17, "GP17_MGPIO10"),
53cecddda7SAndy Shevchenko 	PINCTRL_PIN(18, "GP18_SRC0CLKRQB"),
54cecddda7SAndy Shevchenko 	PINCTRL_PIN(19, "GP19_SRC1CLKRQB"),
55cecddda7SAndy Shevchenko 	PINCTRL_PIN(20, "GP20_SRC2CLKRQB"),
56cecddda7SAndy Shevchenko 	PINCTRL_PIN(21, "GP21_SRC3CLKRQB"),
57cecddda7SAndy Shevchenko 	PINCTRL_PIN(22, "GP22_SRC4CLKRQB_TRST2"),
58cecddda7SAndy Shevchenko 	PINCTRL_PIN(23, "GP23_SRC5CLKRQB_TDI2"),
59cecddda7SAndy Shevchenko 	PINCTRL_PIN(24, "GP24_MGPIO0"),
60cecddda7SAndy Shevchenko 	PINCTRL_PIN(25, "GP25_USBWAKEOUTB"),
61cecddda7SAndy Shevchenko 	PINCTRL_PIN(26, "GP26_MGPIO5"),
62cecddda7SAndy Shevchenko 	PINCTRL_PIN(27, "GP27_MGPIO6"),
63cecddda7SAndy Shevchenko 	PINCTRL_PIN(28, "GP28_MGPIO7"),
64cecddda7SAndy Shevchenko 	PINCTRL_PIN(29, "GP29_SLP_WLANB_MGPIO3"),
65cecddda7SAndy Shevchenko 	PINCTRL_PIN(30, "GP30_SUSWARNB_SUSPWRDNACK_MGPIO1"),
66cecddda7SAndy Shevchenko 	PINCTRL_PIN(31, "GP31_ACPRESENT_MGPIO2"),
67cecddda7SAndy Shevchenko 	PINCTRL_PIN(32, "GP32_CLKRUNB"),
68cecddda7SAndy Shevchenko 	PINCTRL_PIN(33, "GP33_DEVSLP0"),
69cecddda7SAndy Shevchenko 	PINCTRL_PIN(34, "GP34_SATA0XPCIE6L3B_SATA0GP"),
70cecddda7SAndy Shevchenko 	PINCTRL_PIN(35, "GP35_SATA1XPCIE6L2B_SATA1GP"),
71cecddda7SAndy Shevchenko 	PINCTRL_PIN(36, "GP36_SATA2XPCIE6L1B_SATA2GP"),
72cecddda7SAndy Shevchenko 	PINCTRL_PIN(37, "GP37_SATA3XPCIE6L0B_SATA3GP"),
73cecddda7SAndy Shevchenko 	PINCTRL_PIN(38, "GP38_DEVSLP1"),
74cecddda7SAndy Shevchenko 	PINCTRL_PIN(39, "GP39_DEVSLP2"),
75cecddda7SAndy Shevchenko 	PINCTRL_PIN(40, "GP40_OC0B"),
76cecddda7SAndy Shevchenko 	PINCTRL_PIN(41, "GP41_OC1B"),
77cecddda7SAndy Shevchenko 	PINCTRL_PIN(42, "GP42_OC2B"),
78cecddda7SAndy Shevchenko 	PINCTRL_PIN(43, "GP43_OC3B"),
79cecddda7SAndy Shevchenko 	PINCTRL_PIN(44, "GP44"),
80cecddda7SAndy Shevchenko 	PINCTRL_PIN(45, "GP45_TMS2"),
81cecddda7SAndy Shevchenko 	PINCTRL_PIN(46, "GP46_TDO2"),
82cecddda7SAndy Shevchenko 	PINCTRL_PIN(47, "GP47"),
83cecddda7SAndy Shevchenko 	PINCTRL_PIN(48, "GP48"),
84cecddda7SAndy Shevchenko 	PINCTRL_PIN(49, "GP49"),
85cecddda7SAndy Shevchenko 	PINCTRL_PIN(50, "GP50"),
86cecddda7SAndy Shevchenko 	PINCTRL_PIN(51, "GP51_GSXDOUT"),
87cecddda7SAndy Shevchenko 	PINCTRL_PIN(52, "GP52_GSXSLOAD"),
88cecddda7SAndy Shevchenko 	PINCTRL_PIN(53, "GP53_GSXDIN"),
89cecddda7SAndy Shevchenko 	PINCTRL_PIN(54, "GP54_GSXSRESETB"),
90cecddda7SAndy Shevchenko 	PINCTRL_PIN(55, "GP55_GSXCLK"),
91cecddda7SAndy Shevchenko 	PINCTRL_PIN(56, "GP56"),
92cecddda7SAndy Shevchenko 	PINCTRL_PIN(57, "GP57"),
93cecddda7SAndy Shevchenko 	PINCTRL_PIN(58, "GP58"),
94cecddda7SAndy Shevchenko 	PINCTRL_PIN(59, "GP59"),
95cecddda7SAndy Shevchenko 	PINCTRL_PIN(60, "GP60_SML0ALERTB_MGPIO4"),
96cecddda7SAndy Shevchenko 	PINCTRL_PIN(61, "GP61_SUS_STATB"),
97cecddda7SAndy Shevchenko 	PINCTRL_PIN(62, "GP62_SUSCLK"),
98cecddda7SAndy Shevchenko 	PINCTRL_PIN(63, "GP63_SLP_S5B"),
99cecddda7SAndy Shevchenko 	PINCTRL_PIN(64, "GP64_SDIO_CLK"),
100cecddda7SAndy Shevchenko 	PINCTRL_PIN(65, "GP65_SDIO_CMD"),
101cecddda7SAndy Shevchenko 	PINCTRL_PIN(66, "GP66_SDIO_D0"),
102cecddda7SAndy Shevchenko 	PINCTRL_PIN(67, "GP67_SDIO_D1"),
103cecddda7SAndy Shevchenko 	PINCTRL_PIN(68, "GP68_SDIO_D2"),
104cecddda7SAndy Shevchenko 	PINCTRL_PIN(69, "GP69_SDIO_D3"),
105cecddda7SAndy Shevchenko 	PINCTRL_PIN(70, "GP70_SDIO_POWER_EN"),
106cecddda7SAndy Shevchenko 	PINCTRL_PIN(71, "GP71_MPHYPC"),
107cecddda7SAndy Shevchenko 	PINCTRL_PIN(72, "GP72_BATLOWB"),
108cecddda7SAndy Shevchenko 	PINCTRL_PIN(73, "GP73_SML1ALERTB_PCHHOTB_MGPIO8"),
109cecddda7SAndy Shevchenko 	PINCTRL_PIN(74, "GP74_SML1DATA_MGPIO12"),
110cecddda7SAndy Shevchenko 	PINCTRL_PIN(75, "GP75_SML1CLK_MGPIO11"),
111cecddda7SAndy Shevchenko 	PINCTRL_PIN(76, "GP76_BMBUSYB"),
112cecddda7SAndy Shevchenko 	PINCTRL_PIN(77, "GP77_PIRQAB"),
113cecddda7SAndy Shevchenko 	PINCTRL_PIN(78, "GP78_PIRQBB"),
114cecddda7SAndy Shevchenko 	PINCTRL_PIN(79, "GP79_PIRQCB"),
115cecddda7SAndy Shevchenko 	PINCTRL_PIN(80, "GP80_PIRQDB"),
116cecddda7SAndy Shevchenko 	PINCTRL_PIN(81, "GP81_SPKR"),
117cecddda7SAndy Shevchenko 	PINCTRL_PIN(82, "GP82_RCINB"),
118cecddda7SAndy Shevchenko 	PINCTRL_PIN(83, "GP83_GSPI0_CSB"),
119cecddda7SAndy Shevchenko 	PINCTRL_PIN(84, "GP84_GSPI0_CLK"),
120cecddda7SAndy Shevchenko 	PINCTRL_PIN(85, "GP85_GSPI0_MISO"),
121cecddda7SAndy Shevchenko 	PINCTRL_PIN(86, "GP86_GSPI0_MOSI"),
122cecddda7SAndy Shevchenko 	PINCTRL_PIN(87, "GP87_GSPI1_CSB"),
123cecddda7SAndy Shevchenko 	PINCTRL_PIN(88, "GP88_GSPI1_CLK"),
124cecddda7SAndy Shevchenko 	PINCTRL_PIN(89, "GP89_GSPI1_MISO"),
125cecddda7SAndy Shevchenko 	PINCTRL_PIN(90, "GP90_GSPI1_MOSI"),
126cecddda7SAndy Shevchenko 	PINCTRL_PIN(91, "GP91_UART0_RXD"),
127cecddda7SAndy Shevchenko 	PINCTRL_PIN(92, "GP92_UART0_TXD"),
128cecddda7SAndy Shevchenko 	PINCTRL_PIN(93, "GP93_UART0_RTSB"),
129cecddda7SAndy Shevchenko 	PINCTRL_PIN(94, "GP94_UART0_CTSB"),
130cecddda7SAndy Shevchenko };
131cecddda7SAndy Shevchenko 
132cecddda7SAndy Shevchenko static const struct intel_community lptlp_communities[] = {
133cecddda7SAndy Shevchenko 	COMMUNITY(0, 95),
134cecddda7SAndy Shevchenko };
135cecddda7SAndy Shevchenko 
136cecddda7SAndy Shevchenko static const struct intel_pinctrl_soc_data lptlp_soc_data = {
137cecddda7SAndy Shevchenko 	.pins		= lptlp_pins,
138cecddda7SAndy Shevchenko 	.npins		= ARRAY_SIZE(lptlp_pins),
139cecddda7SAndy Shevchenko 	.communities	= lptlp_communities,
140cecddda7SAndy Shevchenko 	.ncommunities	= ARRAY_SIZE(lptlp_communities),
141cecddda7SAndy Shevchenko };
142cecddda7SAndy Shevchenko 
1437c0bc7bbSAndy Shevchenko /* LynxPoint chipset has support for 95 GPIO pins */
144eb83479eSAndy Shevchenko 
1457c0bc7bbSAndy Shevchenko #define LP_NUM_GPIO	95
146eb83479eSAndy Shevchenko 
147eb83479eSAndy Shevchenko /* Bitmapped register offsets */
148eb83479eSAndy Shevchenko #define LP_ACPI_OWNED	0x00 /* Bitmap, set by bios, 0: pin reserved for ACPI */
149eb83479eSAndy Shevchenko #define LP_GC		0x7C /* set APIC IRQ to IRQ14 or IRQ15 for all pins */
150eb83479eSAndy Shevchenko #define LP_INT_STAT	0x80
151eb83479eSAndy Shevchenko #define LP_INT_ENABLE	0x90
152eb83479eSAndy Shevchenko 
153eb83479eSAndy Shevchenko /* Each pin has two 32 bit config registers, starting at 0x100 */
154eb83479eSAndy Shevchenko #define LP_CONFIG1	0x100
155eb83479eSAndy Shevchenko #define LP_CONFIG2	0x104
156eb83479eSAndy Shevchenko 
157eb83479eSAndy Shevchenko /* LP_CONFIG1 reg bits */
158eb83479eSAndy Shevchenko #define OUT_LVL_BIT	BIT(31)
159eb83479eSAndy Shevchenko #define IN_LVL_BIT	BIT(30)
160eb83479eSAndy Shevchenko #define TRIG_SEL_BIT	BIT(4) /* 0: Edge, 1: Level */
161eb83479eSAndy Shevchenko #define INT_INV_BIT	BIT(3) /* Invert interrupt triggering */
162eb83479eSAndy Shevchenko #define DIR_BIT		BIT(2) /* 0: Output, 1: Input */
16376347d7aSAndy Shevchenko #define USE_SEL_MASK	GENMASK(1, 0)	/* 0: Native, 1: GPIO, ... */
16476347d7aSAndy Shevchenko #define USE_SEL_NATIVE	(0 << 0)
16576347d7aSAndy Shevchenko #define USE_SEL_GPIO	(1 << 0)
166eb83479eSAndy Shevchenko 
167eb83479eSAndy Shevchenko /* LP_CONFIG2 reg bits */
168eb83479eSAndy Shevchenko #define GPINDIS_BIT	BIT(2) /* disable input sensing */
169eb83479eSAndy Shevchenko #define GPIWP_BIT	(BIT(0) | BIT(1)) /* weak pull options */
170eb83479eSAndy Shevchenko 
171eb83479eSAndy Shevchenko /*
172eb83479eSAndy Shevchenko  * Lynxpoint gpios are controlled through both bitmapped registers and
173eb83479eSAndy Shevchenko  * per gpio specific registers. The bitmapped registers are in chunks of
1747c0bc7bbSAndy Shevchenko  * 3 x 32bit registers to cover all 95 GPIOs
175eb83479eSAndy Shevchenko  *
176eb83479eSAndy Shevchenko  * per gpio specific registers consist of two 32bit registers per gpio
1777c0bc7bbSAndy Shevchenko  * (LP_CONFIG1 and LP_CONFIG2), with 95 GPIOs there's a total of
1787c0bc7bbSAndy Shevchenko  * 190 config registers.
179eb83479eSAndy Shevchenko  *
180eb83479eSAndy Shevchenko  * A simplified view of the register layout look like this:
181eb83479eSAndy Shevchenko  *
182eb83479eSAndy Shevchenko  * LP_ACPI_OWNED[31:0] gpio ownerships for gpios 0-31  (bitmapped registers)
183eb83479eSAndy Shevchenko  * LP_ACPI_OWNED[63:32] gpio ownerships for gpios 32-63
184eb83479eSAndy Shevchenko  * LP_ACPI_OWNED[94:64] gpio ownerships for gpios 63-94
185eb83479eSAndy Shevchenko  * ...
186eb83479eSAndy Shevchenko  * LP_INT_ENABLE[31:0] ...
1877c0bc7bbSAndy Shevchenko  * LP_INT_ENABLE[63:32] ...
188eb83479eSAndy Shevchenko  * LP_INT_ENABLE[94:64] ...
189eb83479eSAndy Shevchenko  * LP0_CONFIG1 (gpio 0) config1 reg for gpio 0 (per gpio registers)
190eb83479eSAndy Shevchenko  * LP0_CONFIG2 (gpio 0) config2 reg for gpio 0
191eb83479eSAndy Shevchenko  * LP1_CONFIG1 (gpio 1) config1 reg for gpio 1
192eb83479eSAndy Shevchenko  * LP1_CONFIG2 (gpio 1) config2 reg for gpio 1
193eb83479eSAndy Shevchenko  * LP2_CONFIG1 (gpio 2) ...
194eb83479eSAndy Shevchenko  * LP2_CONFIG2 (gpio 2) ...
195eb83479eSAndy Shevchenko  * ...
196eb83479eSAndy Shevchenko  * LP94_CONFIG1 (gpio 94) ...
197eb83479eSAndy Shevchenko  * LP94_CONFIG2 (gpio 94) ...
198eb83479eSAndy Shevchenko  */
199eb83479eSAndy Shevchenko 
200*18213ad4SAndy Shevchenko static struct intel_community *lp_get_community(struct intel_pinctrl *lg,
201*18213ad4SAndy Shevchenko 						unsigned int pin)
202*18213ad4SAndy Shevchenko {
203*18213ad4SAndy Shevchenko 	struct intel_community *comm;
204*18213ad4SAndy Shevchenko 	int i;
205*18213ad4SAndy Shevchenko 
206*18213ad4SAndy Shevchenko 	for (i = 0; i < lg->ncommunities; i++) {
207*18213ad4SAndy Shevchenko 		comm = &lg->communities[i];
208*18213ad4SAndy Shevchenko 		if (pin < comm->pin_base + comm->npins && pin >= comm->pin_base)
209*18213ad4SAndy Shevchenko 			return comm;
210*18213ad4SAndy Shevchenko 	}
211*18213ad4SAndy Shevchenko 
212*18213ad4SAndy Shevchenko 	return NULL;
213*18213ad4SAndy Shevchenko }
214*18213ad4SAndy Shevchenko 
215c35f463aSAndy Shevchenko static void __iomem *lp_gpio_reg(struct gpio_chip *chip, unsigned int offset,
216eb83479eSAndy Shevchenko 				 int reg)
217eb83479eSAndy Shevchenko {
218*18213ad4SAndy Shevchenko 	struct intel_pinctrl *lg = gpiochip_get_data(chip);
219*18213ad4SAndy Shevchenko 	struct intel_community *comm;
220eb83479eSAndy Shevchenko 	int reg_offset;
221eb83479eSAndy Shevchenko 
222*18213ad4SAndy Shevchenko 	comm = lp_get_community(lg, offset);
223*18213ad4SAndy Shevchenko 	if (!comm)
224*18213ad4SAndy Shevchenko 		return NULL;
225*18213ad4SAndy Shevchenko 
226*18213ad4SAndy Shevchenko 	offset -= comm->pin_base;
227*18213ad4SAndy Shevchenko 
228eb83479eSAndy Shevchenko 	if (reg == LP_CONFIG1 || reg == LP_CONFIG2)
229eb83479eSAndy Shevchenko 		/* per gpio specific config registers */
230eb83479eSAndy Shevchenko 		reg_offset = offset * 8;
231eb83479eSAndy Shevchenko 	else
232eb83479eSAndy Shevchenko 		/* bitmapped registers */
233eb83479eSAndy Shevchenko 		reg_offset = (offset / 32) * 4;
234eb83479eSAndy Shevchenko 
235*18213ad4SAndy Shevchenko 	return comm->regs + reg_offset + reg;
236eb83479eSAndy Shevchenko }
237eb83479eSAndy Shevchenko 
238*18213ad4SAndy Shevchenko static bool lp_gpio_acpi_use(struct intel_pinctrl *lg, unsigned int pin)
23921a06495SAndy Shevchenko {
24021a06495SAndy Shevchenko 	void __iomem *acpi_use;
24121a06495SAndy Shevchenko 
24221a06495SAndy Shevchenko 	acpi_use = lp_gpio_reg(&lg->chip, pin, LP_ACPI_OWNED);
24321a06495SAndy Shevchenko 	if (!acpi_use)
24421a06495SAndy Shevchenko 		return true;
24521a06495SAndy Shevchenko 
24621a06495SAndy Shevchenko 	return !(ioread32(acpi_use) & BIT(pin % 32));
24721a06495SAndy Shevchenko }
24821a06495SAndy Shevchenko 
249c35f463aSAndy Shevchenko static int lp_gpio_request(struct gpio_chip *chip, unsigned int offset)
250eb83479eSAndy Shevchenko {
251*18213ad4SAndy Shevchenko 	struct intel_pinctrl *lg = gpiochip_get_data(chip);
252e1940adeSAndy Shevchenko 	void __iomem *reg = lp_gpio_reg(chip, offset, LP_CONFIG1);
253e1940adeSAndy Shevchenko 	void __iomem *conf2 = lp_gpio_reg(chip, offset, LP_CONFIG2);
25403fb681bSAndy Shevchenko 	u32 value;
255eb83479eSAndy Shevchenko 
2561e78ea71SAndy Shevchenko 	pm_runtime_get(lg->dev); /* should we put if failed */
257eb83479eSAndy Shevchenko 
25803fb681bSAndy Shevchenko 	/*
25903fb681bSAndy Shevchenko 	 * Reconfigure pin to GPIO mode if needed and issue a warning,
26003fb681bSAndy Shevchenko 	 * since we expect firmware to configure it properly.
26103fb681bSAndy Shevchenko 	 */
262e1940adeSAndy Shevchenko 	value = ioread32(reg);
26303fb681bSAndy Shevchenko 	if ((value & USE_SEL_MASK) != USE_SEL_GPIO) {
264e1940adeSAndy Shevchenko 		iowrite32((value & USE_SEL_MASK) | USE_SEL_GPIO, reg);
2651e78ea71SAndy Shevchenko 		dev_warn(lg->dev, FW_BUG "pin %u forcibly reconfigured as GPIO\n", offset);
26603fb681bSAndy Shevchenko 	}
267eb83479eSAndy Shevchenko 
268eb83479eSAndy Shevchenko 	/* enable input sensing */
269e1940adeSAndy Shevchenko 	iowrite32(ioread32(conf2) & ~GPINDIS_BIT, conf2);
270eb83479eSAndy Shevchenko 
271eb83479eSAndy Shevchenko 
272eb83479eSAndy Shevchenko 	return 0;
273eb83479eSAndy Shevchenko }
274eb83479eSAndy Shevchenko 
275c35f463aSAndy Shevchenko static void lp_gpio_free(struct gpio_chip *chip, unsigned int offset)
276eb83479eSAndy Shevchenko {
277*18213ad4SAndy Shevchenko 	struct intel_pinctrl *lg = gpiochip_get_data(chip);
278e1940adeSAndy Shevchenko 	void __iomem *conf2 = lp_gpio_reg(chip, offset, LP_CONFIG2);
279eb83479eSAndy Shevchenko 
280eb83479eSAndy Shevchenko 	/* disable input sensing */
281e1940adeSAndy Shevchenko 	iowrite32(ioread32(conf2) | GPINDIS_BIT, conf2);
282eb83479eSAndy Shevchenko 
2831e78ea71SAndy Shevchenko 	pm_runtime_put(lg->dev);
284eb83479eSAndy Shevchenko }
285eb83479eSAndy Shevchenko 
286c35f463aSAndy Shevchenko static int lp_gpio_get(struct gpio_chip *chip, unsigned int offset)
287eb83479eSAndy Shevchenko {
288e1940adeSAndy Shevchenko 	void __iomem *reg = lp_gpio_reg(chip, offset, LP_CONFIG1);
289e1940adeSAndy Shevchenko 	return !!(ioread32(reg) & IN_LVL_BIT);
290eb83479eSAndy Shevchenko }
291eb83479eSAndy Shevchenko 
292c35f463aSAndy Shevchenko static void lp_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
293eb83479eSAndy Shevchenko {
294*18213ad4SAndy Shevchenko 	struct intel_pinctrl *lg = gpiochip_get_data(chip);
295e1940adeSAndy Shevchenko 	void __iomem *reg = lp_gpio_reg(chip, offset, LP_CONFIG1);
296eb83479eSAndy Shevchenko 	unsigned long flags;
297eb83479eSAndy Shevchenko 
298b2e05d63SAndy Shevchenko 	raw_spin_lock_irqsave(&lg->lock, flags);
299eb83479eSAndy Shevchenko 
300eb83479eSAndy Shevchenko 	if (value)
301e1940adeSAndy Shevchenko 		iowrite32(ioread32(reg) | OUT_LVL_BIT, reg);
302eb83479eSAndy Shevchenko 	else
303e1940adeSAndy Shevchenko 		iowrite32(ioread32(reg) & ~OUT_LVL_BIT, reg);
304eb83479eSAndy Shevchenko 
305b2e05d63SAndy Shevchenko 	raw_spin_unlock_irqrestore(&lg->lock, flags);
306eb83479eSAndy Shevchenko }
307eb83479eSAndy Shevchenko 
308c35f463aSAndy Shevchenko static int lp_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
309eb83479eSAndy Shevchenko {
310*18213ad4SAndy Shevchenko 	struct intel_pinctrl *lg = gpiochip_get_data(chip);
311e1940adeSAndy Shevchenko 	void __iomem *reg = lp_gpio_reg(chip, offset, LP_CONFIG1);
312eb83479eSAndy Shevchenko 	unsigned long flags;
313eb83479eSAndy Shevchenko 
314b2e05d63SAndy Shevchenko 	raw_spin_lock_irqsave(&lg->lock, flags);
315e1940adeSAndy Shevchenko 	iowrite32(ioread32(reg) | DIR_BIT, reg);
316b2e05d63SAndy Shevchenko 	raw_spin_unlock_irqrestore(&lg->lock, flags);
317eb83479eSAndy Shevchenko 
318eb83479eSAndy Shevchenko 	return 0;
319eb83479eSAndy Shevchenko }
320eb83479eSAndy Shevchenko 
321c35f463aSAndy Shevchenko static int lp_gpio_direction_output(struct gpio_chip *chip, unsigned int offset,
322c35f463aSAndy Shevchenko 				    int value)
323eb83479eSAndy Shevchenko {
324*18213ad4SAndy Shevchenko 	struct intel_pinctrl *lg = gpiochip_get_data(chip);
325e1940adeSAndy Shevchenko 	void __iomem *reg = lp_gpio_reg(chip, offset, LP_CONFIG1);
326eb83479eSAndy Shevchenko 	unsigned long flags;
327eb83479eSAndy Shevchenko 
328eb83479eSAndy Shevchenko 	lp_gpio_set(chip, offset, value);
329eb83479eSAndy Shevchenko 
330b2e05d63SAndy Shevchenko 	raw_spin_lock_irqsave(&lg->lock, flags);
331e1940adeSAndy Shevchenko 	iowrite32(ioread32(reg) & ~DIR_BIT, reg);
332b2e05d63SAndy Shevchenko 	raw_spin_unlock_irqrestore(&lg->lock, flags);
333eb83479eSAndy Shevchenko 
334eb83479eSAndy Shevchenko 	return 0;
335eb83479eSAndy Shevchenko }
336eb83479eSAndy Shevchenko 
33754d371cfSAndy Shevchenko static int lp_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
33854d371cfSAndy Shevchenko {
33954d371cfSAndy Shevchenko 	void __iomem *reg = lp_gpio_reg(chip, offset, LP_CONFIG1);
34054d371cfSAndy Shevchenko 
34154d371cfSAndy Shevchenko 	if (ioread32(reg) & DIR_BIT)
34254d371cfSAndy Shevchenko 		return GPIO_LINE_DIRECTION_IN;
34354d371cfSAndy Shevchenko 
34454d371cfSAndy Shevchenko 	return GPIO_LINE_DIRECTION_OUT;
34554d371cfSAndy Shevchenko }
34654d371cfSAndy Shevchenko 
347eb83479eSAndy Shevchenko static void lp_gpio_irq_handler(struct irq_desc *desc)
348eb83479eSAndy Shevchenko {
349eb83479eSAndy Shevchenko 	struct irq_data *data = irq_desc_get_irq_data(desc);
350eb83479eSAndy Shevchenko 	struct gpio_chip *gc = irq_desc_get_handler_data(desc);
351*18213ad4SAndy Shevchenko 	struct intel_pinctrl *lg = gpiochip_get_data(gc);
352eb83479eSAndy Shevchenko 	struct irq_chip *chip = irq_data_get_irq_chip(data);
353e1940adeSAndy Shevchenko 	void __iomem *reg, *ena;
354e1940adeSAndy Shevchenko 	unsigned long pending;
355eb83479eSAndy Shevchenko 	u32 base, pin;
356eb83479eSAndy Shevchenko 
357eb83479eSAndy Shevchenko 	/* check from GPIO controller which pin triggered the interrupt */
358eb83479eSAndy Shevchenko 	for (base = 0; base < lg->chip.ngpio; base += 32) {
359eb83479eSAndy Shevchenko 		reg = lp_gpio_reg(&lg->chip, base, LP_INT_STAT);
360eb83479eSAndy Shevchenko 		ena = lp_gpio_reg(&lg->chip, base, LP_INT_ENABLE);
361eb83479eSAndy Shevchenko 
362eb83479eSAndy Shevchenko 		/* Only interrupts that are enabled */
363e1940adeSAndy Shevchenko 		pending = ioread32(reg) & ioread32(ena);
364eb83479eSAndy Shevchenko 
365eb83479eSAndy Shevchenko 		for_each_set_bit(pin, &pending, 32) {
366c35f463aSAndy Shevchenko 			unsigned int irq;
367eb83479eSAndy Shevchenko 
368eb83479eSAndy Shevchenko 			irq = irq_find_mapping(lg->chip.irq.domain, base + pin);
369eb83479eSAndy Shevchenko 			generic_handle_irq(irq);
370eb83479eSAndy Shevchenko 		}
371eb83479eSAndy Shevchenko 	}
372eb83479eSAndy Shevchenko 	chip->irq_eoi(data);
373eb83479eSAndy Shevchenko }
374eb83479eSAndy Shevchenko 
3755931e6edSAndy Shevchenko static void lp_irq_ack(struct irq_data *d)
3765931e6edSAndy Shevchenko {
3775931e6edSAndy Shevchenko 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
378*18213ad4SAndy Shevchenko 	struct intel_pinctrl *lg = gpiochip_get_data(gc);
3795931e6edSAndy Shevchenko 	u32 hwirq = irqd_to_hwirq(d);
3805931e6edSAndy Shevchenko 	void __iomem *reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_STAT);
3815931e6edSAndy Shevchenko 	unsigned long flags;
3825931e6edSAndy Shevchenko 
3835931e6edSAndy Shevchenko 	raw_spin_lock_irqsave(&lg->lock, flags);
3845931e6edSAndy Shevchenko 	iowrite32(BIT(hwirq % 32), reg);
3855931e6edSAndy Shevchenko 	raw_spin_unlock_irqrestore(&lg->lock, flags);
3865931e6edSAndy Shevchenko }
3875931e6edSAndy Shevchenko 
388eb83479eSAndy Shevchenko static void lp_irq_unmask(struct irq_data *d)
389eb83479eSAndy Shevchenko {
390eb83479eSAndy Shevchenko }
391eb83479eSAndy Shevchenko 
392eb83479eSAndy Shevchenko static void lp_irq_mask(struct irq_data *d)
393eb83479eSAndy Shevchenko {
394eb83479eSAndy Shevchenko }
395eb83479eSAndy Shevchenko 
396eb83479eSAndy Shevchenko static void lp_irq_enable(struct irq_data *d)
397eb83479eSAndy Shevchenko {
398eb83479eSAndy Shevchenko 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
399*18213ad4SAndy Shevchenko 	struct intel_pinctrl *lg = gpiochip_get_data(gc);
400eb83479eSAndy Shevchenko 	u32 hwirq = irqd_to_hwirq(d);
401e1940adeSAndy Shevchenko 	void __iomem *reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_ENABLE);
402eb83479eSAndy Shevchenko 	unsigned long flags;
403eb83479eSAndy Shevchenko 
404b2e05d63SAndy Shevchenko 	raw_spin_lock_irqsave(&lg->lock, flags);
405e1940adeSAndy Shevchenko 	iowrite32(ioread32(reg) | BIT(hwirq % 32), reg);
406b2e05d63SAndy Shevchenko 	raw_spin_unlock_irqrestore(&lg->lock, flags);
407eb83479eSAndy Shevchenko }
408eb83479eSAndy Shevchenko 
409eb83479eSAndy Shevchenko static void lp_irq_disable(struct irq_data *d)
410eb83479eSAndy Shevchenko {
411eb83479eSAndy Shevchenko 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
412*18213ad4SAndy Shevchenko 	struct intel_pinctrl *lg = gpiochip_get_data(gc);
413eb83479eSAndy Shevchenko 	u32 hwirq = irqd_to_hwirq(d);
414e1940adeSAndy Shevchenko 	void __iomem *reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_ENABLE);
415eb83479eSAndy Shevchenko 	unsigned long flags;
416eb83479eSAndy Shevchenko 
417b2e05d63SAndy Shevchenko 	raw_spin_lock_irqsave(&lg->lock, flags);
418e1940adeSAndy Shevchenko 	iowrite32(ioread32(reg) & ~BIT(hwirq % 32), reg);
419b2e05d63SAndy Shevchenko 	raw_spin_unlock_irqrestore(&lg->lock, flags);
420eb83479eSAndy Shevchenko }
421eb83479eSAndy Shevchenko 
422095f2a67SAndy Shevchenko static int lp_irq_set_type(struct irq_data *d, unsigned int type)
423095f2a67SAndy Shevchenko {
424095f2a67SAndy Shevchenko 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
425*18213ad4SAndy Shevchenko 	struct intel_pinctrl *lg = gpiochip_get_data(gc);
426095f2a67SAndy Shevchenko 	u32 hwirq = irqd_to_hwirq(d);
427095f2a67SAndy Shevchenko 	void __iomem *reg = lp_gpio_reg(&lg->chip, hwirq, LP_CONFIG1);
428095f2a67SAndy Shevchenko 	unsigned long flags;
429095f2a67SAndy Shevchenko 	u32 value;
430095f2a67SAndy Shevchenko 
431095f2a67SAndy Shevchenko 	if (hwirq >= lg->chip.ngpio)
432095f2a67SAndy Shevchenko 		return -EINVAL;
433095f2a67SAndy Shevchenko 
434540bff18SAndy Shevchenko 	/* Fail if BIOS reserved pin for ACPI use */
435540bff18SAndy Shevchenko 	if (lp_gpio_acpi_use(lg, hwirq)) {
436540bff18SAndy Shevchenko 		dev_err(lg->dev, "pin %u can't be used as IRQ\n", hwirq);
437540bff18SAndy Shevchenko 		return -EBUSY;
438540bff18SAndy Shevchenko 	}
439540bff18SAndy Shevchenko 
440095f2a67SAndy Shevchenko 	raw_spin_lock_irqsave(&lg->lock, flags);
441095f2a67SAndy Shevchenko 	value = ioread32(reg);
442095f2a67SAndy Shevchenko 
443095f2a67SAndy Shevchenko 	/* set both TRIG_SEL and INV bits to 0 for rising edge */
444095f2a67SAndy Shevchenko 	if (type & IRQ_TYPE_EDGE_RISING)
445095f2a67SAndy Shevchenko 		value &= ~(TRIG_SEL_BIT | INT_INV_BIT);
446095f2a67SAndy Shevchenko 
447095f2a67SAndy Shevchenko 	/* TRIG_SEL bit 0, INV bit 1 for falling edge */
448095f2a67SAndy Shevchenko 	if (type & IRQ_TYPE_EDGE_FALLING)
449095f2a67SAndy Shevchenko 		value = (value | INT_INV_BIT) & ~TRIG_SEL_BIT;
450095f2a67SAndy Shevchenko 
451095f2a67SAndy Shevchenko 	/* TRIG_SEL bit 1, INV bit 0 for level low */
452095f2a67SAndy Shevchenko 	if (type & IRQ_TYPE_LEVEL_LOW)
453095f2a67SAndy Shevchenko 		value = (value | TRIG_SEL_BIT) & ~INT_INV_BIT;
454095f2a67SAndy Shevchenko 
455095f2a67SAndy Shevchenko 	/* TRIG_SEL bit 1, INV bit 1 for level high */
456095f2a67SAndy Shevchenko 	if (type & IRQ_TYPE_LEVEL_HIGH)
457095f2a67SAndy Shevchenko 		value |= TRIG_SEL_BIT | INT_INV_BIT;
458095f2a67SAndy Shevchenko 
459095f2a67SAndy Shevchenko 	iowrite32(value, reg);
460095f2a67SAndy Shevchenko 
461095f2a67SAndy Shevchenko 	if (type & IRQ_TYPE_EDGE_BOTH)
462095f2a67SAndy Shevchenko 		irq_set_handler_locked(d, handle_edge_irq);
463095f2a67SAndy Shevchenko 	else if (type & IRQ_TYPE_LEVEL_MASK)
464095f2a67SAndy Shevchenko 		irq_set_handler_locked(d, handle_level_irq);
465095f2a67SAndy Shevchenko 
466095f2a67SAndy Shevchenko 	raw_spin_unlock_irqrestore(&lg->lock, flags);
467095f2a67SAndy Shevchenko 
468095f2a67SAndy Shevchenko 	return 0;
469095f2a67SAndy Shevchenko }
470095f2a67SAndy Shevchenko 
471eb83479eSAndy Shevchenko static struct irq_chip lp_irqchip = {
472eb83479eSAndy Shevchenko 	.name = "LP-GPIO",
4735931e6edSAndy Shevchenko 	.irq_ack = lp_irq_ack,
474eb83479eSAndy Shevchenko 	.irq_mask = lp_irq_mask,
475eb83479eSAndy Shevchenko 	.irq_unmask = lp_irq_unmask,
476eb83479eSAndy Shevchenko 	.irq_enable = lp_irq_enable,
477eb83479eSAndy Shevchenko 	.irq_disable = lp_irq_disable,
478095f2a67SAndy Shevchenko 	.irq_set_type = lp_irq_set_type,
479eb83479eSAndy Shevchenko 	.flags = IRQCHIP_SKIP_SET_WAKE,
480eb83479eSAndy Shevchenko };
481eb83479eSAndy Shevchenko 
482eb83479eSAndy Shevchenko static int lp_gpio_irq_init_hw(struct gpio_chip *chip)
483eb83479eSAndy Shevchenko {
484*18213ad4SAndy Shevchenko 	struct intel_pinctrl *lg = gpiochip_get_data(chip);
485e1940adeSAndy Shevchenko 	void __iomem *reg;
486c35f463aSAndy Shevchenko 	unsigned int base;
487eb83479eSAndy Shevchenko 
488eb83479eSAndy Shevchenko 	for (base = 0; base < lg->chip.ngpio; base += 32) {
489eb83479eSAndy Shevchenko 		/* disable gpio pin interrupts */
490eb83479eSAndy Shevchenko 		reg = lp_gpio_reg(&lg->chip, base, LP_INT_ENABLE);
491e1940adeSAndy Shevchenko 		iowrite32(0, reg);
492eb83479eSAndy Shevchenko 		/* Clear interrupt status register */
493eb83479eSAndy Shevchenko 		reg = lp_gpio_reg(&lg->chip, base, LP_INT_STAT);
494e1940adeSAndy Shevchenko 		iowrite32(0xffffffff, reg);
495eb83479eSAndy Shevchenko 	}
496eb83479eSAndy Shevchenko 
497eb83479eSAndy Shevchenko 	return 0;
498eb83479eSAndy Shevchenko }
499eb83479eSAndy Shevchenko 
500eb83479eSAndy Shevchenko static int lp_gpio_probe(struct platform_device *pdev)
501eb83479eSAndy Shevchenko {
502*18213ad4SAndy Shevchenko 	const struct intel_pinctrl_soc_data *soc;
503*18213ad4SAndy Shevchenko 	struct intel_pinctrl *lg;
504eb83479eSAndy Shevchenko 	struct gpio_chip *gc;
505eb83479eSAndy Shevchenko 	struct resource *io_rc, *irq_rc;
506eb83479eSAndy Shevchenko 	struct device *dev = &pdev->dev;
507e1940adeSAndy Shevchenko 	void __iomem *regs;
508*18213ad4SAndy Shevchenko 	unsigned int i;
5093b4c2d8eSAndy Shevchenko 	int ret;
510eb83479eSAndy Shevchenko 
511*18213ad4SAndy Shevchenko 	soc = (const struct intel_pinctrl_soc_data *)device_get_match_data(dev);
512*18213ad4SAndy Shevchenko 	if (!soc)
513*18213ad4SAndy Shevchenko 		return -ENODEV;
514*18213ad4SAndy Shevchenko 
515a718e68eSAndy Shevchenko 	lg = devm_kzalloc(dev, sizeof(*lg), GFP_KERNEL);
516eb83479eSAndy Shevchenko 	if (!lg)
517eb83479eSAndy Shevchenko 		return -ENOMEM;
518eb83479eSAndy Shevchenko 
5191e78ea71SAndy Shevchenko 	lg->dev = dev;
520*18213ad4SAndy Shevchenko 	lg->soc = soc;
521*18213ad4SAndy Shevchenko 
522*18213ad4SAndy Shevchenko 	lg->ncommunities = lg->soc->ncommunities;
523*18213ad4SAndy Shevchenko 	lg->communities = devm_kcalloc(dev, lg->ncommunities,
524*18213ad4SAndy Shevchenko 				       sizeof(*lg->communities), GFP_KERNEL);
525*18213ad4SAndy Shevchenko 	if (!lg->communities)
526*18213ad4SAndy Shevchenko 		return -ENOMEM;
527*18213ad4SAndy Shevchenko 
528eb83479eSAndy Shevchenko 	platform_set_drvdata(pdev, lg);
529eb83479eSAndy Shevchenko 
530eb83479eSAndy Shevchenko 	io_rc = platform_get_resource(pdev, IORESOURCE_IO, 0);
531eb83479eSAndy Shevchenko 	if (!io_rc) {
532eb83479eSAndy Shevchenko 		dev_err(dev, "missing IO resources\n");
533eb83479eSAndy Shevchenko 		return -EINVAL;
534eb83479eSAndy Shevchenko 	}
535eb83479eSAndy Shevchenko 
536e1940adeSAndy Shevchenko 	regs = devm_ioport_map(dev, io_rc->start, resource_size(io_rc));
537e1940adeSAndy Shevchenko 	if (!regs) {
538e1940adeSAndy Shevchenko 		dev_err(dev, "failed mapping IO region %pR\n", &io_rc);
539eb83479eSAndy Shevchenko 		return -EBUSY;
540eb83479eSAndy Shevchenko 	}
541eb83479eSAndy Shevchenko 
542*18213ad4SAndy Shevchenko 	for (i = 0; i < lg->soc->ncommunities; i++) {
543*18213ad4SAndy Shevchenko 		struct intel_community *comm = &lg->communities[i];
544*18213ad4SAndy Shevchenko 
545*18213ad4SAndy Shevchenko 		*comm = lg->soc->communities[i];
546*18213ad4SAndy Shevchenko 
547*18213ad4SAndy Shevchenko 		comm->regs = regs;
548*18213ad4SAndy Shevchenko 		comm->pad_regs = regs + 0x100;
549*18213ad4SAndy Shevchenko 	}
550e1940adeSAndy Shevchenko 
551b2e05d63SAndy Shevchenko 	raw_spin_lock_init(&lg->lock);
552eb83479eSAndy Shevchenko 
553eb83479eSAndy Shevchenko 	gc = &lg->chip;
554eb83479eSAndy Shevchenko 	gc->label = dev_name(dev);
555eb83479eSAndy Shevchenko 	gc->owner = THIS_MODULE;
556eb83479eSAndy Shevchenko 	gc->request = lp_gpio_request;
557eb83479eSAndy Shevchenko 	gc->free = lp_gpio_free;
558eb83479eSAndy Shevchenko 	gc->direction_input = lp_gpio_direction_input;
559eb83479eSAndy Shevchenko 	gc->direction_output = lp_gpio_direction_output;
560eb83479eSAndy Shevchenko 	gc->get = lp_gpio_get;
561eb83479eSAndy Shevchenko 	gc->set = lp_gpio_set;
56254d371cfSAndy Shevchenko 	gc->get_direction = lp_gpio_get_direction;
563eb83479eSAndy Shevchenko 	gc->base = -1;
564eb83479eSAndy Shevchenko 	gc->ngpio = LP_NUM_GPIO;
565eb83479eSAndy Shevchenko 	gc->can_sleep = false;
566eb83479eSAndy Shevchenko 	gc->parent = dev;
567eb83479eSAndy Shevchenko 
568eb83479eSAndy Shevchenko 	/* set up interrupts  */
569e1940adeSAndy Shevchenko 	irq_rc = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
570eb83479eSAndy Shevchenko 	if (irq_rc && irq_rc->start) {
571eb83479eSAndy Shevchenko 		struct gpio_irq_chip *girq;
572eb83479eSAndy Shevchenko 
573eb83479eSAndy Shevchenko 		girq = &gc->irq;
574eb83479eSAndy Shevchenko 		girq->chip = &lp_irqchip;
575eb83479eSAndy Shevchenko 		girq->init_hw = lp_gpio_irq_init_hw;
576eb83479eSAndy Shevchenko 		girq->parent_handler = lp_gpio_irq_handler;
577eb83479eSAndy Shevchenko 		girq->num_parents = 1;
5781e78ea71SAndy Shevchenko 		girq->parents = devm_kcalloc(dev, girq->num_parents,
579eb83479eSAndy Shevchenko 					     sizeof(*girq->parents),
580eb83479eSAndy Shevchenko 					     GFP_KERNEL);
581eb83479eSAndy Shevchenko 		if (!girq->parents)
582eb83479eSAndy Shevchenko 			return -ENOMEM;
583c35f463aSAndy Shevchenko 		girq->parents[0] = (unsigned int)irq_rc->start;
584eb83479eSAndy Shevchenko 		girq->default_type = IRQ_TYPE_NONE;
585eb83479eSAndy Shevchenko 		girq->handler = handle_bad_irq;
586eb83479eSAndy Shevchenko 	}
587eb83479eSAndy Shevchenko 
588eb83479eSAndy Shevchenko 	ret = devm_gpiochip_add_data(dev, gc, lg);
589eb83479eSAndy Shevchenko 	if (ret) {
590eb83479eSAndy Shevchenko 		dev_err(dev, "failed adding lp-gpio chip\n");
591eb83479eSAndy Shevchenko 		return ret;
592eb83479eSAndy Shevchenko 	}
593eb83479eSAndy Shevchenko 
594eb83479eSAndy Shevchenko 	pm_runtime_enable(dev);
595eb83479eSAndy Shevchenko 
596eb83479eSAndy Shevchenko 	return 0;
597eb83479eSAndy Shevchenko }
598eb83479eSAndy Shevchenko 
599d0f2df40SAndy Shevchenko static int lp_gpio_remove(struct platform_device *pdev)
600d0f2df40SAndy Shevchenko {
601d0f2df40SAndy Shevchenko 	pm_runtime_disable(&pdev->dev);
602d0f2df40SAndy Shevchenko 	return 0;
603d0f2df40SAndy Shevchenko }
604d0f2df40SAndy Shevchenko 
605eb83479eSAndy Shevchenko static int lp_gpio_runtime_suspend(struct device *dev)
606eb83479eSAndy Shevchenko {
607eb83479eSAndy Shevchenko 	return 0;
608eb83479eSAndy Shevchenko }
609eb83479eSAndy Shevchenko 
610eb83479eSAndy Shevchenko static int lp_gpio_runtime_resume(struct device *dev)
611eb83479eSAndy Shevchenko {
612eb83479eSAndy Shevchenko 	return 0;
613eb83479eSAndy Shevchenko }
614eb83479eSAndy Shevchenko 
615eb83479eSAndy Shevchenko static int lp_gpio_resume(struct device *dev)
616eb83479eSAndy Shevchenko {
617*18213ad4SAndy Shevchenko 	struct intel_pinctrl *lg = dev_get_drvdata(dev);
618e1940adeSAndy Shevchenko 	void __iomem *reg;
619eb83479eSAndy Shevchenko 	int i;
620eb83479eSAndy Shevchenko 
621eb83479eSAndy Shevchenko 	/* on some hardware suspend clears input sensing, re-enable it here */
622eb83479eSAndy Shevchenko 	for (i = 0; i < lg->chip.ngpio; i++) {
623eb83479eSAndy Shevchenko 		if (gpiochip_is_requested(&lg->chip, i) != NULL) {
624eb83479eSAndy Shevchenko 			reg = lp_gpio_reg(&lg->chip, i, LP_CONFIG2);
625e1940adeSAndy Shevchenko 			iowrite32(ioread32(reg) & ~GPINDIS_BIT, reg);
626eb83479eSAndy Shevchenko 		}
627eb83479eSAndy Shevchenko 	}
628eb83479eSAndy Shevchenko 	return 0;
629eb83479eSAndy Shevchenko }
630eb83479eSAndy Shevchenko 
631eb83479eSAndy Shevchenko static const struct dev_pm_ops lp_gpio_pm_ops = {
632eb83479eSAndy Shevchenko 	.runtime_suspend = lp_gpio_runtime_suspend,
633eb83479eSAndy Shevchenko 	.runtime_resume = lp_gpio_runtime_resume,
634eb83479eSAndy Shevchenko 	.resume = lp_gpio_resume,
635eb83479eSAndy Shevchenko };
636eb83479eSAndy Shevchenko 
637eb83479eSAndy Shevchenko static const struct acpi_device_id lynxpoint_gpio_acpi_match[] = {
638cecddda7SAndy Shevchenko 	{ "INT33C7", (kernel_ulong_t)&lptlp_soc_data },
639cecddda7SAndy Shevchenko 	{ "INT3437", (kernel_ulong_t)&lptlp_soc_data },
640eb83479eSAndy Shevchenko 	{ }
641eb83479eSAndy Shevchenko };
642eb83479eSAndy Shevchenko MODULE_DEVICE_TABLE(acpi, lynxpoint_gpio_acpi_match);
643eb83479eSAndy Shevchenko 
644eb83479eSAndy Shevchenko static struct platform_driver lp_gpio_driver = {
645eb83479eSAndy Shevchenko 	.probe          = lp_gpio_probe,
646eb83479eSAndy Shevchenko 	.remove         = lp_gpio_remove,
647eb83479eSAndy Shevchenko 	.driver         = {
648eb83479eSAndy Shevchenko 		.name   = "lp_gpio",
649eb83479eSAndy Shevchenko 		.pm	= &lp_gpio_pm_ops,
650eb83479eSAndy Shevchenko 		.acpi_match_table = ACPI_PTR(lynxpoint_gpio_acpi_match),
651eb83479eSAndy Shevchenko 	},
652eb83479eSAndy Shevchenko };
653eb83479eSAndy Shevchenko 
654eb83479eSAndy Shevchenko static int __init lp_gpio_init(void)
655eb83479eSAndy Shevchenko {
656eb83479eSAndy Shevchenko 	return platform_driver_register(&lp_gpio_driver);
657eb83479eSAndy Shevchenko }
658eb83479eSAndy Shevchenko 
659eb83479eSAndy Shevchenko static void __exit lp_gpio_exit(void)
660eb83479eSAndy Shevchenko {
661eb83479eSAndy Shevchenko 	platform_driver_unregister(&lp_gpio_driver);
662eb83479eSAndy Shevchenko }
663eb83479eSAndy Shevchenko 
664eb83479eSAndy Shevchenko subsys_initcall(lp_gpio_init);
665eb83479eSAndy Shevchenko module_exit(lp_gpio_exit);
666eb83479eSAndy Shevchenko 
667eb83479eSAndy Shevchenko MODULE_AUTHOR("Mathias Nyman (Intel)");
668eb83479eSAndy Shevchenko MODULE_DESCRIPTION("GPIO interface for Intel Lynxpoint");
669eb83479eSAndy Shevchenko MODULE_LICENSE("GPL v2");
670eb83479eSAndy Shevchenko MODULE_ALIAS("platform:lp_gpio");
671