Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 358754
b: refs/heads/master
c: 0d1c28a
h: refs/heads/master
v: v3
  • Loading branch information
Mathias Nyman authored and Linus Walleij committed Jan 29, 2013
1 parent d633922 commit 6315bed
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: b42748c970d1865685749960cb23f08e259a9f86
refs/heads/master: 0d1c28a449c6c23a126e3a08ee30914609aac227
82 changes: 82 additions & 0 deletions trunk/drivers/gpio/gpiolib-acpi.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <linux/export.h>
#include <linux/acpi_gpio.h>
#include <linux/acpi.h>
#include <linux/interrupt.h>

static int acpi_gpiochip_find(struct gpio_chip *gc, void *data)
{
Expand Down Expand Up @@ -52,3 +53,84 @@ int acpi_get_gpio(char *path, int pin)
return chip->base + pin;
}
EXPORT_SYMBOL_GPL(acpi_get_gpio);


static irqreturn_t acpi_gpio_irq_handler(int irq, void *data)
{
acpi_handle handle = data;

acpi_evaluate_object(handle, NULL, NULL, NULL);

return IRQ_HANDLED;
}

/**
* acpi_gpiochip_request_interrupts() - Register isr for gpio chip ACPI events
* @chip: gpio chip
*
* ACPI5 platforms can use GPIO signaled ACPI events. These GPIO interrupts are
* handled by ACPI event methods which need to be called from the GPIO
* chip's interrupt handler. acpi_gpiochip_request_interrupts finds out which
* gpio pins have acpi event methods and assigns interrupt handlers that calls
* the acpi event methods for those pins.
*
* Interrupts are automatically freed on driver detach
*/

void acpi_gpiochip_request_interrupts(struct gpio_chip *chip)
{
struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL};
struct acpi_resource *res;
acpi_handle handle, ev_handle;
acpi_status status;
unsigned int pin, irq;
char ev_name[5];

if (!chip->dev || !chip->to_irq)
return;

handle = ACPI_HANDLE(chip->dev);
if (!handle)
return;

status = acpi_get_event_resources(handle, &buf);
if (ACPI_FAILURE(status))
return;

/* If a gpio interrupt has an acpi event handler method, then
* set up an interrupt handler that calls the acpi event handler
*/

for (res = buf.pointer;
res && (res->type != ACPI_RESOURCE_TYPE_END_TAG);
res = ACPI_NEXT_RESOURCE(res)) {

if (res->type != ACPI_RESOURCE_TYPE_GPIO ||
res->data.gpio.connection_type !=
ACPI_RESOURCE_GPIO_TYPE_INT)
continue;

pin = res->data.gpio.pin_table[0];
if (pin > chip->ngpio)
continue;

sprintf(ev_name, "_%c%02X",
res->data.gpio.triggering ? 'E' : 'L', pin);

status = acpi_get_handle(handle, ev_name, &ev_handle);
if (ACPI_FAILURE(status))
continue;

irq = chip->to_irq(chip, pin);
if (irq < 0)
continue;

/* Assume BIOS sets the triggering, so no flags */
devm_request_threaded_irq(chip->dev, irq, NULL,
acpi_gpio_irq_handler,
0,
"GPIO-signaled-ACPI-event",
ev_handle);
}
}
EXPORT_SYMBOL(acpi_gpiochip_request_interrupts);
4 changes: 4 additions & 0 deletions trunk/include/linux/acpi_gpio.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
#define _LINUX_ACPI_GPIO_H_

#include <linux/errno.h>
#include <linux/gpio.h>

#ifdef CONFIG_GPIO_ACPI

int acpi_get_gpio(char *path, int pin);
void acpi_gpiochip_request_interrupts(struct gpio_chip *chip);

#else /* CONFIG_GPIO_ACPI */

Expand All @@ -14,6 +16,8 @@ static inline int acpi_get_gpio(char *path, int pin)
return -ENODEV;
}

static inline void acpi_gpiochip_request_interrupts(struct gpio_chip *chip) { }

#endif /* CONFIG_GPIO_ACPI */

#endif /* _LINUX_ACPI_GPIO_H_ */

0 comments on commit 6315bed

Please sign in to comment.