diff options
-rw-r--r-- | Documentation/acpi/enumeration.txt | 32 | ||||
-rw-r--r-- | drivers/gpio/gpiolib-acpi.c | 77 | ||||
-rw-r--r-- | include/linux/acpi_gpio.h | 17 |
3 files changed, 125 insertions, 1 deletions
diff --git a/Documentation/acpi/enumeration.txt b/Documentation/acpi/enumeration.txt index 94a656131885..b0d541042ac6 100644 --- a/Documentation/acpi/enumeration.txt +++ b/Documentation/acpi/enumeration.txt | |||
@@ -199,6 +199,8 @@ the device to the driver. For example: | |||
199 | { | 199 | { |
200 | Name (SBUF, ResourceTemplate() | 200 | Name (SBUF, ResourceTemplate() |
201 | { | 201 | { |
202 | ... | ||
203 | // Used to power on/off the device | ||
202 | GpioIo (Exclusive, PullDefault, 0x0000, 0x0000, | 204 | GpioIo (Exclusive, PullDefault, 0x0000, 0x0000, |
203 | IoRestrictionOutputOnly, "\\_SB.PCI0.GPI0", | 205 | IoRestrictionOutputOnly, "\\_SB.PCI0.GPI0", |
204 | 0x00, ResourceConsumer,,) | 206 | 0x00, ResourceConsumer,,) |
@@ -206,10 +208,20 @@ the device to the driver. For example: | |||
206 | // Pin List | 208 | // Pin List |
207 | 0x0055 | 209 | 0x0055 |
208 | } | 210 | } |
211 | |||
212 | // Interrupt for the device | ||
213 | GpioInt (Edge, ActiveHigh, ExclusiveAndWake, PullNone, | ||
214 | 0x0000, "\\_SB.PCI0.GPI0", 0x00, ResourceConsumer,,) | ||
215 | { | ||
216 | // Pin list | ||
217 | 0x0058 | ||
218 | } | ||
219 | |||
209 | ... | 220 | ... |
210 | 221 | ||
211 | Return (SBUF) | ||
212 | } | 222 | } |
223 | |||
224 | Return (SBUF) | ||
213 | } | 225 | } |
214 | 226 | ||
215 | These GPIO numbers are controller relative and path "\\_SB.PCI0.GPI0" | 227 | These GPIO numbers are controller relative and path "\\_SB.PCI0.GPI0" |
@@ -220,6 +232,24 @@ The driver can do this by including <linux/acpi_gpio.h> and then calling | |||
220 | acpi_get_gpio(path, gpio). This will return the Linux GPIO number or | 232 | acpi_get_gpio(path, gpio). This will return the Linux GPIO number or |
221 | negative errno if there was no translation found. | 233 | negative errno if there was no translation found. |
222 | 234 | ||
235 | In a simple case of just getting the Linux GPIO number from device | ||
236 | resources one can use acpi_get_gpio_by_index() helper function. It takes | ||
237 | pointer to the device and index of the GpioIo/GpioInt descriptor in the | ||
238 | device resources list. For example: | ||
239 | |||
240 | int gpio_irq, gpio_power; | ||
241 | int ret; | ||
242 | |||
243 | gpio_irq = acpi_get_gpio_by_index(dev, 1, NULL); | ||
244 | if (gpio_irq < 0) | ||
245 | /* handle error */ | ||
246 | |||
247 | gpio_power = acpi_get_gpio_by_index(dev, 0, NULL); | ||
248 | if (gpio_power < 0) | ||
249 | /* handle error */ | ||
250 | |||
251 | /* Now we can use the GPIO numbers */ | ||
252 | |||
223 | Other GpioIo parameters must be converted first by the driver to be | 253 | Other GpioIo parameters must be converted first by the driver to be |
224 | suitable to the gpiolib before passing them. | 254 | suitable to the gpiolib before passing them. |
225 | 255 | ||
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 89336c4f82cd..5c1ef2b3ef18 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c | |||
@@ -201,6 +201,83 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) | |||
201 | } | 201 | } |
202 | EXPORT_SYMBOL(acpi_gpiochip_request_interrupts); | 202 | EXPORT_SYMBOL(acpi_gpiochip_request_interrupts); |
203 | 203 | ||
204 | struct acpi_gpio_lookup { | ||
205 | struct acpi_gpio_info info; | ||
206 | int index; | ||
207 | int gpio; | ||
208 | int n; | ||
209 | }; | ||
210 | |||
211 | static int acpi_find_gpio(struct acpi_resource *ares, void *data) | ||
212 | { | ||
213 | struct acpi_gpio_lookup *lookup = data; | ||
214 | |||
215 | if (ares->type != ACPI_RESOURCE_TYPE_GPIO) | ||
216 | return 1; | ||
217 | |||
218 | if (lookup->n++ == lookup->index && lookup->gpio < 0) { | ||
219 | const struct acpi_resource_gpio *agpio = &ares->data.gpio; | ||
220 | |||
221 | lookup->gpio = acpi_get_gpio(agpio->resource_source.string_ptr, | ||
222 | agpio->pin_table[0]); | ||
223 | lookup->info.gpioint = | ||
224 | agpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT; | ||
225 | } | ||
226 | |||
227 | return 1; | ||
228 | } | ||
229 | |||
230 | /** | ||
231 | * acpi_get_gpio_by_index() - get a GPIO number from device resources | ||
232 | * @dev: pointer to a device to get GPIO from | ||
233 | * @index: index of GpioIo/GpioInt resource (starting from %0) | ||
234 | * @info: info pointer to fill in (optional) | ||
235 | * | ||
236 | * Function goes through ACPI resources for @dev and based on @index looks | ||
237 | * up a GpioIo/GpioInt resource, translates it to the Linux GPIO number, | ||
238 | * and returns it. @index matches GpioIo/GpioInt resources only so if there | ||
239 | * are total %3 GPIO resources, the index goes from %0 to %2. | ||
240 | * | ||
241 | * If the GPIO cannot be translated or there is an error, negative errno is | ||
242 | * returned. | ||
243 | * | ||
244 | * Note: if the GPIO resource has multiple entries in the pin list, this | ||
245 | * function only returns the first. | ||
246 | */ | ||
247 | int acpi_get_gpio_by_index(struct device *dev, int index, | ||
248 | struct acpi_gpio_info *info) | ||
249 | { | ||
250 | struct acpi_gpio_lookup lookup; | ||
251 | struct list_head resource_list; | ||
252 | struct acpi_device *adev; | ||
253 | acpi_handle handle; | ||
254 | int ret; | ||
255 | |||
256 | if (!dev) | ||
257 | return -EINVAL; | ||
258 | |||
259 | handle = ACPI_HANDLE(dev); | ||
260 | if (!handle || acpi_bus_get_device(handle, &adev)) | ||
261 | return -ENODEV; | ||
262 | |||
263 | memset(&lookup, 0, sizeof(lookup)); | ||
264 | lookup.index = index; | ||
265 | lookup.gpio = -ENODEV; | ||
266 | |||
267 | INIT_LIST_HEAD(&resource_list); | ||
268 | ret = acpi_dev_get_resources(adev, &resource_list, acpi_find_gpio, | ||
269 | &lookup); | ||
270 | if (ret < 0) | ||
271 | return ret; | ||
272 | |||
273 | acpi_dev_free_resource_list(&resource_list); | ||
274 | |||
275 | if (lookup.gpio >= 0 && info) | ||
276 | *info = lookup.info; | ||
277 | |||
278 | return lookup.gpio; | ||
279 | } | ||
280 | EXPORT_SYMBOL_GPL(acpi_get_gpio_by_index); | ||
204 | 281 | ||
205 | /** | 282 | /** |
206 | * acpi_gpiochip_free_interrupts() - Free GPIO _EVT ACPI event interrupts. | 283 | * acpi_gpiochip_free_interrupts() - Free GPIO _EVT ACPI event interrupts. |
diff --git a/include/linux/acpi_gpio.h b/include/linux/acpi_gpio.h index 213135f44333..4c120a1e0ca3 100644 --- a/include/linux/acpi_gpio.h +++ b/include/linux/acpi_gpio.h | |||
@@ -1,12 +1,23 @@ | |||
1 | #ifndef _LINUX_ACPI_GPIO_H_ | 1 | #ifndef _LINUX_ACPI_GPIO_H_ |
2 | #define _LINUX_ACPI_GPIO_H_ | 2 | #define _LINUX_ACPI_GPIO_H_ |
3 | 3 | ||
4 | #include <linux/device.h> | ||
4 | #include <linux/errno.h> | 5 | #include <linux/errno.h> |
5 | #include <linux/gpio.h> | 6 | #include <linux/gpio.h> |
6 | 7 | ||
8 | /** | ||
9 | * struct acpi_gpio_info - ACPI GPIO specific information | ||
10 | * @gpioint: if %true this GPIO is of type GpioInt otherwise type is GpioIo | ||
11 | */ | ||
12 | struct acpi_gpio_info { | ||
13 | bool gpioint; | ||
14 | }; | ||
15 | |||
7 | #ifdef CONFIG_GPIO_ACPI | 16 | #ifdef CONFIG_GPIO_ACPI |
8 | 17 | ||
9 | int acpi_get_gpio(char *path, int pin); | 18 | int acpi_get_gpio(char *path, int pin); |
19 | int acpi_get_gpio_by_index(struct device *dev, int index, | ||
20 | struct acpi_gpio_info *info); | ||
10 | void acpi_gpiochip_request_interrupts(struct gpio_chip *chip); | 21 | void acpi_gpiochip_request_interrupts(struct gpio_chip *chip); |
11 | void acpi_gpiochip_free_interrupts(struct gpio_chip *chip); | 22 | void acpi_gpiochip_free_interrupts(struct gpio_chip *chip); |
12 | 23 | ||
@@ -17,6 +28,12 @@ static inline int acpi_get_gpio(char *path, int pin) | |||
17 | return -ENODEV; | 28 | return -ENODEV; |
18 | } | 29 | } |
19 | 30 | ||
31 | static inline int acpi_get_gpio_by_index(struct device *dev, int index, | ||
32 | struct acpi_gpio_info *info) | ||
33 | { | ||
34 | return -ENODEV; | ||
35 | } | ||
36 | |||
20 | static inline void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) { } | 37 | static inline void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) { } |
21 | static inline void acpi_gpiochip_free_interrupts(struct gpio_chip *chip) { } | 38 | static inline void acpi_gpiochip_free_interrupts(struct gpio_chip *chip) { } |
22 | 39 | ||