The Crystal Cove PMIC has a pin which can be used to connect the IRQ of an external charger IC. On some boards this is used so we need a way to look this up. Note that the Intel PMICs have 2 levels of interrupts and thus 2 levels of IRQ domains all tied to a single fwnode. Level 1 is the irqchip which demultiplexes the actual PMIC interrupt into interrupts for the various MFD cells. Level 2 are the irqchips used in the cell drivers which themselves export IRQs, such as the crystal_cove_gpio driver, which de-multiplexes the level 2 interrupts for the GPIOs into individual per GPIO IRQs. The crystal_cove_charger driver registers an irqchip with a single IRQ for the charger driver to consume. Note the MFD cell IRQ cannot be consumed directly because the level 2 interrupts must be explicitly acked. To allow finding the right IRQ domain when looking up the IRQ for the charger, the crystal_cove_charger driver sets a DOMAIN_BUS_WIRED token on its IRQ domain. Add support for looking up the IRQ from the crystal_cove_charger driver. Signed-off-by: Hans de Goede <hdegoede@xxxxxxxxxx> --- drivers/platform/x86/x86-android-tablets.c | 31 +++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/x86-android-tablets.c b/drivers/platform/x86/x86-android-tablets.c index ea033d7f4439..44138882bc9f 100644 --- a/drivers/platform/x86/x86-android-tablets.c +++ b/drivers/platform/x86/x86-android-tablets.c @@ -17,6 +17,7 @@ #include <linux/gpio/machine.h> #include <linux/i2c.h> #include <linux/irq.h> +#include <linux/irqdomain.h> #include <linux/module.h> #include <linux/mod_devicetable.h> #include <linux/string.h> @@ -31,11 +32,13 @@ enum x86_acpi_irq_type { X86_ACPI_IRQ_TYPE_NONE, X86_ACPI_IRQ_TYPE_APIC, X86_ACPI_IRQ_TYPE_GPIOINT, + X86_ACPI_IRQ_TYPE_PMIC, }; struct x86_acpi_irq_data { - char *chip; /* GPIO chip label (GPIOINT) */ + char *chip; /* GPIO chip label (GPIOINT) or PMIC ACPI path (PMIC) */ enum x86_acpi_irq_type type; + enum irq_domain_bus_token domain; int index; int trigger; /* ACPI_EDGE_SENSITIVE / ACPI_LEVEL_SENSITIVE */ int polarity; /* ACPI_ACTIVE_HIGH / ACPI_ACTIVE_LOW / ACPI_ACTIVE_BOTH */ @@ -48,9 +51,14 @@ static int x86_acpi_irq_helper_gpiochip_find(struct gpio_chip *gc, void *data) static int x86_acpi_irq_helper_get(const struct x86_acpi_irq_data *data) { + struct irq_fwspec fwspec = { }; + struct irq_domain *domain; + struct acpi_device *adev; struct gpio_desc *gpiod; struct gpio_chip *chip; unsigned int irq_type; + acpi_handle handle; + acpi_status status; int irq, ret; switch (data->type) { @@ -86,6 +94,27 @@ static int x86_acpi_irq_helper_get(const struct x86_acpi_irq_data *data) irq_set_irq_type(irq, irq_type); return irq; + case X86_ACPI_IRQ_TYPE_PMIC: + status = acpi_get_handle(NULL, data->chip, &handle); + if (ACPI_FAILURE(status)) { + pr_err("error could not get %s handle\n", data->chip); + return -ENODEV; + } + + acpi_bus_get_device(handle, &adev); + if (!adev) { + pr_err("error could not get %s adev\n", data->chip); + return -ENODEV; + } + + fwspec.fwnode = acpi_fwnode_handle(adev); + domain = irq_find_matching_fwspec(&fwspec, data->domain); + if (!domain) { + pr_err("error could not find IRQ domain for %s\n", data->chip); + return -ENODEV; + } + + return irq_create_mapping(domain, data->index); default: return 0; } -- 2.33.1