summaryrefslogtreecommitdiff
path: root/drivers/gpio/gpiolib-acpi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpio/gpiolib-acpi.c')
-rw-r--r--drivers/gpio/gpiolib-acpi.c79
1 files changed, 46 insertions, 33 deletions
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
index 4a987917c186..05c6275da224 100644
--- a/drivers/gpio/gpiolib-acpi.c
+++ b/drivers/gpio/gpiolib-acpi.c
@@ -25,10 +25,12 @@ struct acpi_gpio_event {
acpi_handle handle;
unsigned int pin;
unsigned int irq;
+ struct gpio_desc *desc;
};
struct acpi_gpio_connection {
struct list_head node;
+ unsigned int pin;
struct gpio_desc *desc;
};
@@ -143,21 +145,15 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
if (!handler)
return AE_BAD_PARAMETER;
- desc = gpiochip_get_desc(chip, pin);
+ desc = gpiochip_request_own_desc(chip, pin, "ACPI:Event");
if (IS_ERR(desc)) {
- dev_err(chip->dev, "Failed to get GPIO descriptor\n");
- return AE_ERROR;
- }
-
- ret = gpiochip_request_own_desc(desc, "ACPI:Event");
- if (ret) {
dev_err(chip->dev, "Failed to request GPIO\n");
return AE_ERROR;
}
gpiod_direction_input(desc);
- ret = gpiod_lock_as_irq(desc);
+ ret = gpio_lock_as_irq(chip, pin);
if (ret) {
dev_err(chip->dev, "Failed to lock GPIO as interrupt\n");
goto fail_free_desc;
@@ -197,6 +193,7 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
event->handle = evt_handle;
event->irq = irq;
event->pin = pin;
+ event->desc = desc;
ret = request_threaded_irq(event->irq, NULL, handler, irqflags,
"ACPI:Event", event);
@@ -212,7 +209,7 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
fail_free_event:
kfree(event);
fail_unlock_irq:
- gpiod_unlock_as_irq(desc);
+ gpio_unlock_as_irq(chip, pin);
fail_free_desc:
gpiochip_free_own_desc(desc);
@@ -221,7 +218,7 @@ fail_free_desc:
/**
* acpi_gpiochip_request_interrupts() - Register isr for gpio chip ACPI events
- * @acpi_gpio: ACPI GPIO chip
+ * @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
@@ -229,11 +226,21 @@ fail_free_desc:
* gpio pins have acpi event methods and assigns interrupt handlers that calls
* the acpi event methods for those pins.
*/
-static void acpi_gpiochip_request_interrupts(struct acpi_gpio_chip *acpi_gpio)
+void acpi_gpiochip_request_interrupts(struct gpio_chip *chip)
{
- struct gpio_chip *chip = acpi_gpio->chip;
+ struct acpi_gpio_chip *acpi_gpio;
+ acpi_handle handle;
+ acpi_status status;
+
+ if (!chip->dev || !chip->to_irq)
+ return;
- if (!chip->to_irq)
+ handle = ACPI_HANDLE(chip->dev);
+ if (!handle)
+ return;
+
+ status = acpi_get_data(handle, acpi_gpio_chip_dh, (void **)&acpi_gpio);
+ if (ACPI_FAILURE(status))
return;
INIT_LIST_HEAD(&acpi_gpio->events);
@@ -243,27 +250,37 @@ static void acpi_gpiochip_request_interrupts(struct acpi_gpio_chip *acpi_gpio)
/**
* acpi_gpiochip_free_interrupts() - Free GPIO ACPI event interrupts.
- * @acpi_gpio: ACPI GPIO chip
+ * @chip: GPIO chip
*
* Free interrupts associated with GPIO ACPI event method for the given
* GPIO chip.
*/
-static void acpi_gpiochip_free_interrupts(struct acpi_gpio_chip *acpi_gpio)
+void acpi_gpiochip_free_interrupts(struct gpio_chip *chip)
{
+ struct acpi_gpio_chip *acpi_gpio;
struct acpi_gpio_event *event, *ep;
- struct gpio_chip *chip = acpi_gpio->chip;
+ acpi_handle handle;
+ acpi_status status;
+
+ if (!chip->dev || !chip->to_irq)
+ return;
+
+ handle = ACPI_HANDLE(chip->dev);
+ if (!handle)
+ return;
- if (!chip->to_irq)
+ status = acpi_get_data(handle, acpi_gpio_chip_dh, (void **)&acpi_gpio);
+ if (ACPI_FAILURE(status))
return;
list_for_each_entry_safe_reverse(event, ep, &acpi_gpio->events, node) {
struct gpio_desc *desc;
free_irq(event->irq, event);
- desc = gpiochip_get_desc(chip, event->pin);
+ desc = event->desc;
if (WARN_ON(IS_ERR(desc)))
continue;
- gpiod_unlock_as_irq(desc);
+ gpio_unlock_as_irq(chip, event->pin);
gpiochip_free_own_desc(desc);
list_del(&event->node);
kfree(event);
@@ -357,8 +374,10 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
struct gpio_chip *chip = achip->chip;
struct acpi_resource_gpio *agpio;
struct acpi_resource *ares;
+ int pin_index = (int)address;
acpi_status status;
bool pull_up;
+ int length;
int i;
status = acpi_buffer_to_resource(achip->conn_info.connection,
@@ -380,32 +399,27 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
return AE_BAD_PARAMETER;
}
- for (i = 0; i < agpio->pin_table_length; i++) {
+ length = min(agpio->pin_table_length, (u16)(pin_index + bits));
+ for (i = pin_index; i < length; ++i) {
unsigned pin = agpio->pin_table[i];
struct acpi_gpio_connection *conn;
struct gpio_desc *desc;
bool found;
- desc = gpiochip_get_desc(chip, pin);
- if (IS_ERR(desc)) {
- status = AE_ERROR;
- goto out;
- }
-
mutex_lock(&achip->conn_lock);
found = false;
list_for_each_entry(conn, &achip->conns, node) {
- if (conn->desc == desc) {
+ if (conn->pin == pin) {
found = true;
+ desc = conn->desc;
break;
}
}
if (!found) {
- int ret;
-
- ret = gpiochip_request_own_desc(desc, "ACPI:OpRegion");
- if (ret) {
+ desc = gpiochip_request_own_desc(chip, pin,
+ "ACPI:OpRegion");
+ if (IS_ERR(desc)) {
status = AE_ERROR;
mutex_unlock(&achip->conn_lock);
goto out;
@@ -442,6 +456,7 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
goto out;
}
+ conn->pin = pin;
conn->desc = desc;
list_add_tail(&conn->node, &achip->conns);
}
@@ -525,7 +540,6 @@ void acpi_gpiochip_add(struct gpio_chip *chip)
return;
}
- acpi_gpiochip_request_interrupts(acpi_gpio);
acpi_gpiochip_request_regions(acpi_gpio);
}
@@ -549,7 +563,6 @@ void acpi_gpiochip_remove(struct gpio_chip *chip)
}
acpi_gpiochip_free_regions(acpi_gpio);
- acpi_gpiochip_free_interrupts(acpi_gpio);
acpi_detach_data(handle, acpi_gpio_chip_dh);
kfree(acpi_gpio);