[PATCH] acpi: implement Generic Event Device
From: Sinan Kaya <hidden>
Date: 2016-01-26 13:49:19
Also in:
linux-acpi, linux-arm-msm, lkml
On 1/26/2016 7:38 AM, Andy Shevchenko wrote:
On Mon, Jan 25, 2016 at 11:29 PM, Sinan Kaya [off-list ref] wrote: Few comments below.quoted
Generic Event Device described in ACPI 6.1 allows platforms to handle platform interrupts in ACPI ASL statements. It borrows constructs like _EVT from GPIO events.Can it share code with gpiolib-acpi.c ? I see some duplication.
The interrupt registration mechanism could be made common but they have their own data structure types. Can Rafael think of any higher level API like acpi_dev_resource_interrupt below?
quoted
All interrupts are listed in _CRS and the handler is written in _EVT method. Here is an example.quoted
Device (GED0) { Name (_HID, "ACPI0013") Name (_UID, 0) Name(_CRS, ResourceTemplate () { Interrupt(ResourceConsumer, Edge, ActiveHigh, Shared, , , ) {123} }) Method (_EVT, 1) { if (Lequal(123, Arg0)) { } } } Wake capability has not been implemented yet. Signed-off-by: Sinan Kaya <redacted> --- drivers/acpi/Makefile | 1 + drivers/acpi/evged.c | 162 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 163 insertions(+) create mode 100644 drivers/acpi/evged.cdiff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index b5e7cd8..4dbb732 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile@@ -46,6 +46,7 @@ acpi-y += acpi_pnp.o acpi-y += int340x_thermal.o acpi-y += power.o acpi-y += event.o +acpi-$(CONFIG_ACPI_REDUCED_HARDWARE_ONLY) += evged.o acpi-y += sysfs.o acpi-y += property.o acpi-$(CONFIG_X86) += acpi_cmos_rtc.odiff --git a/drivers/acpi/evged.c b/drivers/acpi/evged.c new file mode 100644 index 0000000..a904676 --- /dev/null +++ b/drivers/acpi/evged.c@@ -0,0 +1,162 @@ +/* + * Generic Event Device for ACPI. + * + * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Generic Event Device allows platforms to handle + * interrupts in ACPI ASL statements. It follows very similar + * _EVT method approach from GPIO events. + * All interrupts are listed in _CRS and the handler + * is written in _EVT method. Here is an example.Can it be wider on screen?
sure
quoted
+ + event = devm_kzalloc(dev, sizeof(*event), GFP_KERNEL); + if (!event) + return AE_ERROR; + + event->gsi = gsi; + event->dev = dev; + event->irq = irq; + event->handle = evt_handle; + + if (r.flags & IORESOURCE_IRQ_SHAREABLE) + irqflags |= IRQF_SHARED; + + if (devm_request_threaded_irq(dev, irq, NULL, acpi_ged_irq_handler, + irqflags, "ACPI:Ged", event)) { + dev_err(dev, "failed to setup event handler for irq %u\n", irq); + return AE_ERROR; + }The above part is clearly belongs to ged_probe().
It depends. The implementation needs to find all the interrupt entries in _CRS. That's why, the interrupt registration is done inside the ACPI callback. I originally tried using the platform_get_irq() method rather than walking the ACPI resources. Any resource listed in _CRS is accessible via standard platform API. However, I couldn't obtain the shareability and other edge/level attributes through the standard APIs. Most drivers I have seen hardcode this information when calling devm_request_threaded_irq function. Here, the type of interrupt is declared in the ACPI and the registration is done based on passed attributes.
quoted
+ + return AE_OK; +} + +static int ged_probe(struct platform_device *pdev) +{ + acpi_status acpi_ret; + + acpi_ret = acpi_walk_resources(ACPI_HANDLE(&pdev->dev), "_CRS", + acpi_ged_request_interrupt, &pdev->dev); + if (ACPI_FAILURE(acpi_ret)) { + dev_err(&pdev->dev, "unable to parse the _CRS record\n"); + return -EINVAL; + } + + return 0; +} + +static const struct acpi_device_id ged_acpi_ids[] = { + {"ACPI0013"}, + {}, +}; + +static struct platform_driver ged_driver = { + .probe = ged_probe, + .driver = { + .name = MODULE_NAME,quoted
+ .owner = THIS_MODULE,Do you need this one?
I'll get rid of it.
quoted
+ .acpi_match_table = ACPI_PTR(ged_acpi_ids), + }, +}; + +static int __init ged_init(void) +{ + return platform_driver_register(&ged_driver); +} +quoted
+subsys_initcall(ged_init);Any specific reason to have on that level?
changed to module_platform_driver(ged_driver); -- Sinan Kaya Qualcomm Technologies, Inc. on behalf of Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project