Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-only
2 : : /*
3 : : * Generic Event Device for ACPI.
4 : : *
5 : : * Copyright (c) 2016, The Linux Foundation. All rights reserved.
6 : : *
7 : : * Generic Event Device allows platforms to handle interrupts in ACPI
8 : : * ASL statements. It follows very similar to _EVT method approach
9 : : * from GPIO events. All interrupts are listed in _CRS and the handler
10 : : * is written in _EVT method. Here is an example.
11 : : *
12 : : * Device (GED0)
13 : : * {
14 : : *
15 : : * Name (_HID, "ACPI0013")
16 : : * Name (_UID, 0)
17 : : * Method (_CRS, 0x0, Serialized)
18 : : * {
19 : : * Name (RBUF, ResourceTemplate ()
20 : : * {
21 : : * Interrupt(ResourceConsumer, Edge, ActiveHigh, Shared, , , )
22 : : * {123}
23 : : * }
24 : : * })
25 : : *
26 : : * Method (_EVT, 1) {
27 : : * if (Lequal(123, Arg0))
28 : : * {
29 : : * }
30 : : * }
31 : : * }
32 : : */
33 : :
34 : : #include <linux/err.h>
35 : : #include <linux/init.h>
36 : : #include <linux/interrupt.h>
37 : : #include <linux/list.h>
38 : : #include <linux/platform_device.h>
39 : : #include <linux/acpi.h>
40 : :
41 : : #define MODULE_NAME "acpi-ged"
42 : :
43 : : struct acpi_ged_device {
44 : : struct device *dev;
45 : : struct list_head event_list;
46 : : };
47 : :
48 : : struct acpi_ged_event {
49 : : struct list_head node;
50 : : struct device *dev;
51 : : unsigned int gsi;
52 : : unsigned int irq;
53 : : acpi_handle handle;
54 : : };
55 : :
56 : 0 : static irqreturn_t acpi_ged_irq_handler(int irq, void *data)
57 : : {
58 : 0 : struct acpi_ged_event *event = data;
59 : 0 : acpi_status acpi_ret;
60 : :
61 : 0 : acpi_ret = acpi_execute_simple_method(event->handle, NULL, event->gsi);
62 [ # # ]: 0 : if (ACPI_FAILURE(acpi_ret))
63 [ # # ]: 0 : dev_err_once(event->dev, "IRQ method execution failed\n");
64 : :
65 : 0 : return IRQ_HANDLED;
66 : : }
67 : :
68 : 0 : static acpi_status acpi_ged_request_interrupt(struct acpi_resource *ares,
69 : : void *context)
70 : : {
71 : 0 : struct acpi_ged_event *event;
72 : 0 : unsigned int irq;
73 : 0 : unsigned int gsi;
74 : 0 : unsigned int irqflags = IRQF_ONESHOT;
75 : 0 : struct acpi_ged_device *geddev = context;
76 : 0 : struct device *dev = geddev->dev;
77 [ # # # # ]: 0 : acpi_handle handle = ACPI_HANDLE(dev);
78 : 0 : acpi_handle evt_handle;
79 : 0 : struct resource r;
80 : 0 : struct acpi_resource_irq *p = &ares->data.irq;
81 : 0 : struct acpi_resource_extended_irq *pext = &ares->data.extended_irq;
82 : :
83 [ # # ]: 0 : if (ares->type == ACPI_RESOURCE_TYPE_END_TAG)
84 : : return AE_OK;
85 : :
86 [ # # ]: 0 : if (!acpi_dev_resource_interrupt(ares, 0, &r)) {
87 : 0 : dev_err(dev, "unable to parse IRQ resource\n");
88 : 0 : return AE_ERROR;
89 : : }
90 [ # # ]: 0 : if (ares->type == ACPI_RESOURCE_TYPE_IRQ)
91 : 0 : gsi = p->interrupts[0];
92 : : else
93 : 0 : gsi = pext->interrupts[0];
94 : :
95 : 0 : irq = r.start;
96 : :
97 [ # # ]: 0 : if (ACPI_FAILURE(acpi_get_handle(handle, "_EVT", &evt_handle))) {
98 : 0 : dev_err(dev, "cannot locate _EVT method\n");
99 : 0 : return AE_ERROR;
100 : : }
101 : :
102 : 0 : event = devm_kzalloc(dev, sizeof(*event), GFP_KERNEL);
103 [ # # ]: 0 : if (!event)
104 : : return AE_ERROR;
105 : :
106 : 0 : event->gsi = gsi;
107 : 0 : event->dev = dev;
108 : 0 : event->irq = irq;
109 : 0 : event->handle = evt_handle;
110 : :
111 [ # # ]: 0 : if (r.flags & IORESOURCE_IRQ_SHAREABLE)
112 : 0 : irqflags |= IRQF_SHARED;
113 : :
114 [ # # ]: 0 : if (request_threaded_irq(irq, NULL, acpi_ged_irq_handler,
115 : : irqflags, "ACPI:Ged", event)) {
116 : 0 : dev_err(dev, "failed to setup event handler for irq %u\n", irq);
117 : 0 : return AE_ERROR;
118 : : }
119 : :
120 : 0 : dev_dbg(dev, "GED listening GSI %u @ IRQ %u\n", gsi, irq);
121 : 0 : list_add_tail(&event->node, &geddev->event_list);
122 : 0 : return AE_OK;
123 : : }
124 : :
125 : 0 : static int ged_probe(struct platform_device *pdev)
126 : : {
127 : 0 : struct acpi_ged_device *geddev;
128 : 0 : acpi_status acpi_ret;
129 : :
130 : 0 : geddev = devm_kzalloc(&pdev->dev, sizeof(*geddev), GFP_KERNEL);
131 [ # # ]: 0 : if (!geddev)
132 : : return -ENOMEM;
133 : :
134 : 0 : geddev->dev = &pdev->dev;
135 : 0 : INIT_LIST_HEAD(&geddev->event_list);
136 [ # # # # ]: 0 : acpi_ret = acpi_walk_resources(ACPI_HANDLE(&pdev->dev), "_CRS",
137 : : acpi_ged_request_interrupt, geddev);
138 [ # # ]: 0 : if (ACPI_FAILURE(acpi_ret)) {
139 : 0 : dev_err(&pdev->dev, "unable to parse the _CRS record\n");
140 : 0 : return -EINVAL;
141 : : }
142 : 0 : platform_set_drvdata(pdev, geddev);
143 : :
144 : 0 : return 0;
145 : : }
146 : :
147 : 0 : static void ged_shutdown(struct platform_device *pdev)
148 : : {
149 : 0 : struct acpi_ged_device *geddev = platform_get_drvdata(pdev);
150 : 0 : struct acpi_ged_event *event, *next;
151 : :
152 [ # # ]: 0 : list_for_each_entry_safe(event, next, &geddev->event_list, node) {
153 : 0 : free_irq(event->irq, event);
154 : 0 : list_del(&event->node);
155 : 0 : dev_dbg(geddev->dev, "GED releasing GSI %u @ IRQ %u\n",
156 : : event->gsi, event->irq);
157 : : }
158 : 0 : }
159 : :
160 : 0 : static int ged_remove(struct platform_device *pdev)
161 : : {
162 : 0 : ged_shutdown(pdev);
163 : 0 : return 0;
164 : : }
165 : :
166 : : static const struct acpi_device_id ged_acpi_ids[] = {
167 : : {"ACPI0013"},
168 : : {},
169 : : };
170 : :
171 : : static struct platform_driver ged_driver = {
172 : : .probe = ged_probe,
173 : : .remove = ged_remove,
174 : : .shutdown = ged_shutdown,
175 : : .driver = {
176 : : .name = MODULE_NAME,
177 : : .acpi_match_table = ACPI_PTR(ged_acpi_ids),
178 : : },
179 : : };
180 : 28 : builtin_platform_driver(ged_driver);
|