diff options
-rw-r--r-- | drivers/gpio/gpiolib-acpi.c | 82 | ||||
-rw-r--r-- | include/linux/acpi_gpio.h | 4 |
2 files changed, 86 insertions, 0 deletions
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index cbad6e908d30..54ce2269ed25 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/export.h> | 15 | #include <linux/export.h> |
16 | #include <linux/acpi_gpio.h> | 16 | #include <linux/acpi_gpio.h> |
17 | #include <linux/acpi.h> | 17 | #include <linux/acpi.h> |
18 | #include <linux/interrupt.h> | ||
18 | 19 | ||
19 | static int acpi_gpiochip_find(struct gpio_chip *gc, void *data) | 20 | static int acpi_gpiochip_find(struct gpio_chip *gc, void *data) |
20 | { | 21 | { |
@@ -52,3 +53,84 @@ int acpi_get_gpio(char *path, int pin) | |||
52 | return chip->base + pin; | 53 | return chip->base + pin; |
53 | } | 54 | } |
54 | EXPORT_SYMBOL_GPL(acpi_get_gpio); | 55 | EXPORT_SYMBOL_GPL(acpi_get_gpio); |
56 | |||
57 | |||
58 | static irqreturn_t acpi_gpio_irq_handler(int irq, void *data) | ||
59 | { | ||
60 | acpi_handle handle = data; | ||
61 | |||
62 | acpi_evaluate_object(handle, NULL, NULL, NULL); | ||
63 | |||
64 | return IRQ_HANDLED; | ||
65 | } | ||
66 | |||
67 | /** | ||
68 | * acpi_gpiochip_request_interrupts() - Register isr for gpio chip ACPI events | ||
69 | * @chip: gpio chip | ||
70 | * | ||
71 | * ACPI5 platforms can use GPIO signaled ACPI events. These GPIO interrupts are | ||
72 | * handled by ACPI event methods which need to be called from the GPIO | ||
73 | * chip's interrupt handler. acpi_gpiochip_request_interrupts finds out which | ||
74 | * gpio pins have acpi event methods and assigns interrupt handlers that calls | ||
75 | * the acpi event methods for those pins. | ||
76 | * | ||
77 | * Interrupts are automatically freed on driver detach | ||
78 | */ | ||
79 | |||
80 | void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) | ||
81 | { | ||
82 | struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; | ||
83 | struct acpi_resource *res; | ||
84 | acpi_handle handle, ev_handle; | ||
85 | acpi_status status; | ||
86 | unsigned int pin, irq; | ||
87 | char ev_name[5]; | ||
88 | |||
89 | if (!chip->dev || !chip->to_irq) | ||
90 | return; | ||
91 | |||
92 | handle = ACPI_HANDLE(chip->dev); | ||
93 | if (!handle) | ||
94 | return; | ||
95 | |||
96 | status = acpi_get_event_resources(handle, &buf); | ||
97 | if (ACPI_FAILURE(status)) | ||
98 | return; | ||
99 | |||
100 | /* If a gpio interrupt has an acpi event handler method, then | ||
101 | * set up an interrupt handler that calls the acpi event handler | ||
102 | */ | ||
103 | |||
104 | for (res = buf.pointer; | ||
105 | res && (res->type != ACPI_RESOURCE_TYPE_END_TAG); | ||
106 | res = ACPI_NEXT_RESOURCE(res)) { | ||
107 | |||
108 | if (res->type != ACPI_RESOURCE_TYPE_GPIO || | ||
109 | res->data.gpio.connection_type != | ||
110 | ACPI_RESOURCE_GPIO_TYPE_INT) | ||
111 | continue; | ||
112 | |||
113 | pin = res->data.gpio.pin_table[0]; | ||
114 | if (pin > chip->ngpio) | ||
115 | continue; | ||
116 | |||
117 | sprintf(ev_name, "_%c%02X", | ||
118 | res->data.gpio.triggering ? 'E' : 'L', pin); | ||
119 | |||
120 | status = acpi_get_handle(handle, ev_name, &ev_handle); | ||
121 | if (ACPI_FAILURE(status)) | ||
122 | continue; | ||
123 | |||
124 | irq = chip->to_irq(chip, pin); | ||
125 | if (irq < 0) | ||
126 | continue; | ||
127 | |||
128 | /* Assume BIOS sets the triggering, so no flags */ | ||
129 | devm_request_threaded_irq(chip->dev, irq, NULL, | ||
130 | acpi_gpio_irq_handler, | ||
131 | 0, | ||
132 | "GPIO-signaled-ACPI-event", | ||
133 | ev_handle); | ||
134 | } | ||
135 | } | ||
136 | EXPORT_SYMBOL(acpi_gpiochip_request_interrupts); | ||
diff --git a/include/linux/acpi_gpio.h b/include/linux/acpi_gpio.h index 91615a389b65..b76ebd08ff8e 100644 --- a/include/linux/acpi_gpio.h +++ b/include/linux/acpi_gpio.h | |||
@@ -2,10 +2,12 @@ | |||
2 | #define _LINUX_ACPI_GPIO_H_ | 2 | #define _LINUX_ACPI_GPIO_H_ |
3 | 3 | ||
4 | #include <linux/errno.h> | 4 | #include <linux/errno.h> |
5 | #include <linux/gpio.h> | ||
5 | 6 | ||
6 | #ifdef CONFIG_GPIO_ACPI | 7 | #ifdef CONFIG_GPIO_ACPI |
7 | 8 | ||
8 | int acpi_get_gpio(char *path, int pin); | 9 | int acpi_get_gpio(char *path, int pin); |
10 | void acpi_gpiochip_request_interrupts(struct gpio_chip *chip); | ||
9 | 11 | ||
10 | #else /* CONFIG_GPIO_ACPI */ | 12 | #else /* CONFIG_GPIO_ACPI */ |
11 | 13 | ||
@@ -14,6 +16,8 @@ static inline int acpi_get_gpio(char *path, int pin) | |||
14 | return -ENODEV; | 16 | return -ENODEV; |
15 | } | 17 | } |
16 | 18 | ||
19 | static inline void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) { } | ||
20 | |||
17 | #endif /* CONFIG_GPIO_ACPI */ | 21 | #endif /* CONFIG_GPIO_ACPI */ |
18 | 22 | ||
19 | #endif /* _LINUX_ACPI_GPIO_H_ */ | 23 | #endif /* _LINUX_ACPI_GPIO_H_ */ |