summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/ec.c114
1 files changed, 61 insertions, 53 deletions
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 355d6973cb70..47baeec9190d 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -1427,54 +1427,43 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
return AE_CTRL_TERMINATE;
}
-static void install_gpe_event_handler(struct acpi_ec *ec)
-{
- acpi_status status =
- acpi_install_gpe_raw_handler(NULL, ec->gpe,
- ACPI_GPE_EDGE_TRIGGERED,
- &acpi_ec_gpe_handler,
- ec);
- if (ACPI_SUCCESS(status)) {
- /* This is not fatal as we can poll EC events */
- set_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags);
- acpi_ec_leave_noirq(ec);
- if (test_bit(EC_FLAGS_STARTED, &ec->flags) &&
- ec->reference_count >= 1)
- acpi_ec_enable_gpe(ec, true);
- }
-}
-
-/* ACPI reduced hardware platforms use a GpioInt specified in _CRS. */
-static int install_gpio_irq_event_handler(struct acpi_ec *ec,
- struct acpi_device *device)
+static bool install_gpe_event_handler(struct acpi_ec *ec)
{
- int irq = acpi_dev_gpio_irq_get(device, 0);
- int ret;
-
- if (irq < 0)
- return irq;
+ acpi_status status;
- ret = request_irq(irq, acpi_ec_irq_handler, IRQF_SHARED,
- "ACPI EC", ec);
+ status = acpi_install_gpe_raw_handler(NULL, ec->gpe,
+ ACPI_GPE_EDGE_TRIGGERED,
+ &acpi_ec_gpe_handler, ec);
+ if (ACPI_FAILURE(status))
+ return false;
- /*
- * Unlike the GPE case, we treat errors here as fatal, we'll only
- * implement GPIO polling if we find a case that needs it.
- */
- if (ret < 0)
- return ret;
+ if (test_bit(EC_FLAGS_STARTED, &ec->flags) && ec->reference_count >= 1)
+ acpi_ec_enable_gpe(ec, true);
- ec->irq = irq;
- set_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags);
- acpi_ec_leave_noirq(ec);
+ return true;
+}
- return 0;
+static bool install_gpio_irq_event_handler(struct acpi_ec *ec)
+{
+ return request_irq(ec->irq, acpi_ec_irq_handler, IRQF_SHARED,
+ "ACPI EC", ec) >= 0;
}
-/*
- * Note: This function returns an error code only when the address space
- * handler is not installed, which means "not able to handle
- * transactions".
+/**
+ * ec_install_handlers - Install service callbacks and register query methods.
+ * @ec: Target EC.
+ * @device: ACPI device object corresponding to @ec.
+ *
+ * Install a handler for the EC address space type unless it has been installed
+ * already. If @device is not NULL, also look for EC query methods in the
+ * namespace and register them, and install an event (either GPE or GPIO IRQ)
+ * handler for the EC, if possible.
+ *
+ * Return:
+ * -ENODEV if the address space handler cannot be installed, which means
+ * "unable to handle transactions",
+ * -EPROBE_DEFER if GPIO IRQ acquisition needs to be deferred,
+ * or 0 (success) otherwise.
*/
static int ec_install_handlers(struct acpi_ec *ec, struct acpi_device *device)
{
@@ -1498,6 +1487,19 @@ static int ec_install_handlers(struct acpi_ec *ec, struct acpi_device *device)
if (!device)
return 0;
+ if (ec->gpe < 0) {
+ /* ACPI reduced hardware platforms use a GpioInt from _CRS. */
+ int irq = acpi_dev_gpio_irq_get(device, 0);
+ /*
+ * Bail out right away for deferred probing or complete the
+ * initialization regardless of any other errors.
+ */
+ if (irq == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ else if (irq >= 0)
+ ec->irq = irq;
+ }
+
if (!test_bit(EC_FLAGS_QUERY_METHODS_INSTALLED, &ec->flags)) {
/* Find and register all query methods */
acpi_walk_namespace(ACPI_TYPE_METHOD, ec->handle, 1,
@@ -1506,13 +1508,21 @@ static int ec_install_handlers(struct acpi_ec *ec, struct acpi_device *device)
set_bit(EC_FLAGS_QUERY_METHODS_INSTALLED, &ec->flags);
}
if (!test_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags)) {
- if (ec->gpe >= 0) {
- install_gpe_event_handler(ec);
- } else {
- int ret = install_gpio_irq_event_handler(ec, device);
- if (ret)
- return ret;
+ bool ready = false;
+
+ if (ec->gpe >= 0)
+ ready = install_gpe_event_handler(ec);
+ else if (ec->irq >= 0)
+ ready = install_gpio_irq_event_handler(ec);
+
+ if (ready) {
+ set_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags);
+ acpi_ec_leave_noirq(ec);
}
+ /*
+ * Failures to install an event handler are not fatal, because
+ * the EC can be polled for events.
+ */
}
/* EC is fully operational, allow queries */
acpi_ec_enable_event(ec);
@@ -1625,7 +1635,7 @@ static int acpi_ec_add(struct acpi_device *device)
status = ec_parse_device(device->handle, 0, ec, NULL);
if (status != AE_CTRL_TERMINATE) {
ret = -EINVAL;
- goto err_alloc;
+ goto err;
}
if (boot_ec && ec->command_addr == boot_ec->command_addr &&
@@ -1646,7 +1656,7 @@ static int acpi_ec_add(struct acpi_device *device)
ret = acpi_ec_setup(ec, device);
if (ret)
- goto err_query;
+ goto err;
if (ec == boot_ec)
acpi_handle_info(boot_ec->handle,
@@ -1666,12 +1676,10 @@ static int acpi_ec_add(struct acpi_device *device)
acpi_handle_debug(ec->handle, "enumerated.\n");
return 0;
-err_query:
- if (ec != boot_ec)
- acpi_ec_remove_query_handlers(ec, true, 0);
-err_alloc:
+err:
if (ec != boot_ec)
acpi_ec_free(ec);
+
return ret;
}