xref: /linux/drivers/gpio/gpio-novalake-events.c (revision 1334d2a3b3235d062e5e1f51aebe7a64ed57cf72)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Intel Nova Lake GPIO-signaled ACPI events driver
4  *
5  * Copyright (c) 2026, Intel Corporation.
6  *
7  * Author: Alan Borzeszkowski <alan.borzeszkowski@linux.intel.com>
8  *
9  * Intel client platforms released in 2026 and later (starting with Intel Nova
10  * Lake) support two modes of handling ACPI General Purpose Events (GPE):
11  * exposed GPIO interrupt mode and legacy mode.
12  *
13  * By default, the platform uses legacy mode, handling GPEs as usual. If this
14  * driver is installed, it signals to the platform (on every boot) that exposed
15  * GPIO interrupt mode is supported. The platform then switches to exposed
16  * mode, which takes effect on next boot. From the user perspective, this
17  * change is transparent.
18  *
19  * However, if driver is uninstalled while in exposed interrupt mode, GPEs will
20  * _not_ be handled until platform falls back to legacy mode. This means that
21  * USB keyboard, mouse might not function properly for the fallback duration.
22  * Fallback requires two reboots to take effect: on first reboot, platform no
23  * longer receives signal from this driver and switches to legacy mode, which
24  * takes effect on second boot.
25  *
26  * Example ACPI event: Power Management Event coming from motherboard PCH,
27  * waking system from sleep following USB mouse hotplug.
28  *
29  * This driver supports up to 128 GPIO pins in each GPE block, per ACPI
30  * specification v6.6 section 5.6.4.
31  */
32 
33 #include <linux/acpi.h>
34 #include <linux/bitops.h>
35 #include <linux/cleanup.h>
36 #include <linux/device.h>
37 #include <linux/errno.h>
38 #include <linux/gfp_types.h>
39 #include <linux/interrupt.h>
40 #include <linux/io.h>
41 #include <linux/ioport.h>
42 #include <linux/irq.h>
43 #include <linux/module.h>
44 #include <linux/platform_device.h>
45 #include <linux/spinlock.h>
46 #include <linux/types.h>
47 #include <linux/uuid.h>
48 
49 #include <linux/gpio/driver.h>
50 
51 /*
52  * GPE block has two registers, each register takes half the block size.
53  * Convert size to bits to get total GPIO pin count.
54  */
55 #define GPE_BLK_REG_SIZE(block_size)	((block_size) / 2)
56 #define GPE_REG_PIN_COUNT(block_size)	BYTES_TO_BITS(GPE_BLK_REG_SIZE(block_size))
57 #define GPE_STS_REG_OFFSET		0
58 #define GPE_EN_REG_OFFSET(block_size)	GPE_BLK_REG_SIZE(block_size)
59 
60 /**
61  * struct nvl_gpio - Intel Nova Lake GPIO driver state
62  * @gc: GPIO controller interface
63  * @reg_base: Base address of the GPE registers
64  * @lock: Guard register access
65  * @blk_size: GPE block length
66  */
67 struct nvl_gpio {
68 	struct gpio_chip gc;
69 	void __iomem *reg_base;
70 	raw_spinlock_t lock;
71 	size_t blk_size;
72 };
73 
nvl_gpio_get_byte_addr(struct nvl_gpio * priv,unsigned int reg_offset,unsigned long gpio)74 static void __iomem *nvl_gpio_get_byte_addr(struct nvl_gpio *priv,
75 					    unsigned int reg_offset,
76 					    unsigned long gpio)
77 {
78 	return priv->reg_base + reg_offset + gpio;
79 }
80 
nvl_gpio_get(struct gpio_chip * gc,unsigned int gpio)81 static int nvl_gpio_get(struct gpio_chip *gc, unsigned int gpio)
82 {
83 	struct nvl_gpio *priv = gpiochip_get_data(gc);
84 	unsigned int byte_idx = gpio / BITS_PER_BYTE;
85 	unsigned int bit_idx = gpio % BITS_PER_BYTE;
86 	void __iomem *addr;
87 	u8 reg;
88 
89 	addr = nvl_gpio_get_byte_addr(priv, GPE_STS_REG_OFFSET, byte_idx);
90 
91 	guard(raw_spinlock_irqsave)(&priv->lock);
92 
93 	reg = ioread8(addr);
94 
95 	return !!(reg & BIT(bit_idx));
96 }
97 
98 static const struct gpio_chip nvl_gpio_chip = {
99 	.owner	= THIS_MODULE,
100 	.get	= nvl_gpio_get,
101 };
102 
nvl_gpio_irq_set_type(struct irq_data * d,unsigned int type)103 static int nvl_gpio_irq_set_type(struct irq_data *d, unsigned int type)
104 {
105 	if (type & IRQ_TYPE_EDGE_BOTH)
106 		irq_set_handler_locked(d, handle_edge_irq);
107 	else if (type & IRQ_TYPE_LEVEL_MASK)
108 		irq_set_handler_locked(d, handle_level_irq);
109 
110 	return 0;
111 }
112 
nvl_gpio_irq_mask_unmask(struct gpio_chip * gc,unsigned long hwirq,bool mask)113 static void nvl_gpio_irq_mask_unmask(struct gpio_chip *gc, unsigned long hwirq,
114 				     bool mask)
115 {
116 	struct nvl_gpio *priv = gpiochip_get_data(gc);
117 	unsigned int byte_idx = hwirq / BITS_PER_BYTE;
118 	unsigned int bit_idx = hwirq % BITS_PER_BYTE;
119 	void __iomem *addr;
120 	u8 reg;
121 
122 	addr = nvl_gpio_get_byte_addr(priv, GPE_EN_REG_OFFSET(priv->blk_size), byte_idx);
123 
124 	guard(raw_spinlock_irqsave)(&priv->lock);
125 
126 	reg = ioread8(addr);
127 	if (mask)
128 		reg &= ~BIT(bit_idx);
129 	else
130 		reg |= BIT(bit_idx);
131 	iowrite8(reg, addr);
132 }
133 
nvl_gpio_irq_unmask(struct irq_data * d)134 static void nvl_gpio_irq_unmask(struct irq_data *d)
135 {
136 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
137 	irq_hw_number_t hwirq = irqd_to_hwirq(d);
138 
139 	gpiochip_enable_irq(gc, hwirq);
140 	nvl_gpio_irq_mask_unmask(gc, hwirq, false);
141 }
142 
nvl_gpio_irq_mask(struct irq_data * d)143 static void nvl_gpio_irq_mask(struct irq_data *d)
144 {
145 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
146 	irq_hw_number_t hwirq = irqd_to_hwirq(d);
147 
148 	nvl_gpio_irq_mask_unmask(gc, hwirq, true);
149 	gpiochip_disable_irq(gc, hwirq);
150 }
151 
nvl_gpio_irq_ack(struct irq_data * d)152 static void nvl_gpio_irq_ack(struct irq_data *d)
153 {
154 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
155 	struct nvl_gpio *priv = gpiochip_get_data(gc);
156 	irq_hw_number_t hwirq = irqd_to_hwirq(d);
157 	unsigned int byte_idx = hwirq / BITS_PER_BYTE;
158 	unsigned int bit_idx = hwirq % BITS_PER_BYTE;
159 	void __iomem *addr;
160 	u8 reg;
161 
162 	addr = nvl_gpio_get_byte_addr(priv, GPE_STS_REG_OFFSET, byte_idx);
163 
164 	guard(raw_spinlock_irqsave)(&priv->lock);
165 
166 	reg = ioread8(addr);
167 	reg |= BIT(bit_idx);
168 	iowrite8(reg, addr);
169 }
170 
171 static const struct irq_chip nvl_gpio_irq_chip = {
172 	.name		= "gpio-novalake",
173 	.irq_ack	= nvl_gpio_irq_ack,
174 	.irq_mask	= nvl_gpio_irq_mask,
175 	.irq_unmask	= nvl_gpio_irq_unmask,
176 	.irq_set_type	= nvl_gpio_irq_set_type,
177 	.flags		= IRQCHIP_IMMUTABLE,
178 	GPIOCHIP_IRQ_RESOURCE_HELPERS,
179 };
180 
nvl_gpio_irq(int irq,void * data)181 static irqreturn_t nvl_gpio_irq(int irq, void *data)
182 {
183 	struct nvl_gpio *priv = data;
184 	const size_t block_size = priv->blk_size;
185 	unsigned int handled = 0;
186 
187 	for (unsigned int i = 0; i < block_size; i++) {
188 		const void __iomem *reg = priv->reg_base + i;
189 		unsigned long pending;
190 		unsigned long enabled;
191 		unsigned int bit_idx;
192 
193 		scoped_guard(raw_spinlock, &priv->lock) {
194 			pending = ioread8(reg + GPE_STS_REG_OFFSET);
195 			enabled = ioread8(reg + GPE_EN_REG_OFFSET(block_size));
196 		}
197 		pending &= enabled;
198 
199 		for_each_set_bit(bit_idx, &pending, BITS_PER_BYTE) {
200 			unsigned int hwirq = i * BITS_PER_BYTE + bit_idx;
201 
202 			generic_handle_domain_irq(priv->gc.irq.domain, hwirq);
203 		}
204 
205 		handled += pending ? 1 : 0;
206 	}
207 
208 	return IRQ_RETVAL(handled);
209 }
210 
211 /* UUID for GPE device _DSM: 079406e6-bdea-49cf-8563-03e2811901cb */
212 static const guid_t nvl_gpe_dsm_guid =
213 	GUID_INIT(0x079406e6, 0xbdea, 0x49cf,
214 		  0x85, 0x63, 0x03, 0xe2, 0x81, 0x19, 0x01, 0xcb);
215 
216 #define DSM_GPE_MODE_REV	1
217 #define DSM_GPE_MODE_FN_INDEX	1
218 #define DSM_ENABLE_GPE_MODE	1
219 
nvl_acpi_enable_gpe_mode(struct device * dev)220 static int nvl_acpi_enable_gpe_mode(struct device *dev)
221 {
222 	union acpi_object argv4[2];
223 	union acpi_object *obj;
224 
225 	argv4[0].type = ACPI_TYPE_PACKAGE;
226 	argv4[0].package.count = 1;
227 	argv4[0].package.elements = &argv4[1];
228 	argv4[1].integer.type = ACPI_TYPE_INTEGER;
229 	argv4[1].integer.value = DSM_ENABLE_GPE_MODE;
230 
231 	obj = acpi_evaluate_dsm_typed(ACPI_HANDLE(dev), &nvl_gpe_dsm_guid,
232 				      DSM_GPE_MODE_REV, DSM_GPE_MODE_FN_INDEX,
233 				      argv4, ACPI_TYPE_BUFFER);
234 	if (!obj)
235 		return -EIO;
236 	ACPI_FREE(obj);
237 
238 	return 0;
239 }
240 
nvl_gpio_probe(struct platform_device * pdev)241 static int nvl_gpio_probe(struct platform_device *pdev)
242 {
243 	struct device *dev = &pdev->dev;
244 	resource_size_t ioresource_size;
245 	struct gpio_irq_chip *girq;
246 	struct nvl_gpio *priv;
247 	struct resource *res;
248 	void __iomem *regs;
249 	int ret, irq;
250 
251 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
252 	if (!res)
253 		return -ENXIO;
254 
255 	/*
256 	 * GPE block length should be non-negative multiple of two and allow up
257 	 * to 128 pins. ACPI v6.6 section 5.2.9 and 5.6.4.
258 	 */
259 	ioresource_size = resource_size(res);
260 	if (!ioresource_size || ioresource_size % 2 || ioresource_size > 0x20)
261 		return dev_err_probe(dev, -EINVAL,
262 				     "invalid GPE block length, resource: %pR\n",
263 				     res);
264 
265 	regs = devm_ioport_map(dev, res->start, ioresource_size);
266 	if (!regs)
267 		return -ENOMEM;
268 
269 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
270 	if (!priv)
271 		return -ENOMEM;
272 	raw_spin_lock_init(&priv->lock);
273 
274 	priv->reg_base = regs;
275 	priv->blk_size = ioresource_size;
276 
277 	irq = platform_get_irq(pdev, 0);
278 	if (irq < 0)
279 		return irq;
280 
281 	ret = devm_request_irq(dev, irq, nvl_gpio_irq, IRQF_SHARED, dev_name(dev), priv);
282 	if (ret)
283 		return ret;
284 
285 	priv->gc	= nvl_gpio_chip;
286 	priv->gc.label	= dev_name(dev);
287 	priv->gc.parent	= dev;
288 	priv->gc.ngpio	= GPE_REG_PIN_COUNT(priv->blk_size);
289 	priv->gc.base	= -1;
290 
291 	girq = &priv->gc.irq;
292 	gpio_irq_chip_set_chip(girq, &nvl_gpio_irq_chip);
293 	girq->parent_handler	= NULL;
294 	girq->num_parents	= 0;
295 	girq->parents		= NULL;
296 	girq->default_type	= IRQ_TYPE_NONE;
297 	girq->handler		= handle_bad_irq;
298 
299 	ret = devm_gpiochip_add_data(dev, &priv->gc, priv);
300 	if (ret)
301 		return ret;
302 
303 	return nvl_acpi_enable_gpe_mode(dev);
304 }
305 
306 static const struct acpi_device_id nvl_gpio_acpi_match[] = {
307 	{ "INTC1114" },
308 	{}
309 };
310 MODULE_DEVICE_TABLE(acpi, nvl_gpio_acpi_match);
311 
312 static struct platform_driver nvl_gpio_driver = {
313 	.driver = {
314 		.name		  = "gpio-novalake-events",
315 		.acpi_match_table = nvl_gpio_acpi_match,
316 	},
317 	.probe = nvl_gpio_probe,
318 };
319 module_platform_driver(nvl_gpio_driver);
320 
321 MODULE_LICENSE("GPL");
322 MODULE_AUTHOR("Alan Borzeszkowski <alan.borzeszkowski@linux.intel.com>");
323 MODULE_DESCRIPTION("Intel Nova Lake ACPI GPIO events driver");
324