Skip to content

Commit 406857f

Browse files
dsdrafaeljw
authored andcommitted
ACPI: EC: add support for hardware-reduced systems
As defined in the ACPI spec section 12.11, ACPI hardware-reduced platforms define the EC SCI interrupt as a GpioInt in the _CRS object. This replaces the previous way of using a GPE for this interrupt; GPE blocks are not available on reduced hardware platforms. Add support for handling this interrupt as an EC event source, and avoid GPE usage on reduced hardware platforms. This enables the use of several media keys (e.g. screen brightness up/down) on Asus UX434DA. Signed-off-by: Daniel Drake <[email protected]> Signed-off-by: Rafael J. Wysocki <[email protected]>
1 parent 4446abc commit 406857f

File tree

2 files changed

+119
-35
lines changed

2 files changed

+119
-35
lines changed

drivers/acpi/ec.c

Lines changed: 117 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,7 @@ static void acpi_ec_submit_request(struct acpi_ec *ec)
398398
{
399399
ec->reference_count++;
400400
if (test_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags) &&
401-
ec->reference_count == 1)
401+
ec->gpe >= 0 && ec->reference_count == 1)
402402
acpi_ec_enable_gpe(ec, true);
403403
}
404404

@@ -408,7 +408,7 @@ static void acpi_ec_complete_request(struct acpi_ec *ec)
408408

409409
ec->reference_count--;
410410
if (test_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags) &&
411-
ec->reference_count == 0)
411+
ec->gpe >= 0 && ec->reference_count == 0)
412412
acpi_ec_disable_gpe(ec, true);
413413
flushed = acpi_ec_flushed(ec);
414414
if (flushed)
@@ -418,7 +418,11 @@ static void acpi_ec_complete_request(struct acpi_ec *ec)
418418
static void acpi_ec_mask_events(struct acpi_ec *ec)
419419
{
420420
if (!test_bit(EC_FLAGS_EVENTS_MASKED, &ec->flags)) {
421-
acpi_ec_disable_gpe(ec, false);
421+
if (ec->gpe >= 0)
422+
acpi_ec_disable_gpe(ec, false);
423+
else
424+
disable_irq_nosync(ec->irq);
425+
422426
ec_dbg_drv("Polling enabled");
423427
set_bit(EC_FLAGS_EVENTS_MASKED, &ec->flags);
424428
}
@@ -428,7 +432,11 @@ static void acpi_ec_unmask_events(struct acpi_ec *ec)
428432
{
429433
if (test_bit(EC_FLAGS_EVENTS_MASKED, &ec->flags)) {
430434
clear_bit(EC_FLAGS_EVENTS_MASKED, &ec->flags);
431-
acpi_ec_enable_gpe(ec, false);
435+
if (ec->gpe >= 0)
436+
acpi_ec_enable_gpe(ec, false);
437+
else
438+
enable_irq(ec->irq);
439+
432440
ec_dbg_drv("Polling disabled");
433441
}
434442
}
@@ -648,7 +656,9 @@ static void advance_transaction(struct acpi_ec *ec)
648656
* ensure a hardware STS 0->1 change after this clearing can always
649657
* trigger a GPE interrupt.
650658
*/
651-
acpi_ec_clear_gpe(ec);
659+
if (ec->gpe >= 0)
660+
acpi_ec_clear_gpe(ec);
661+
652662
status = acpi_ec_read_status(ec);
653663
t = ec->curr;
654664
/*
@@ -1275,18 +1285,28 @@ static void acpi_ec_event_handler(struct work_struct *work)
12751285
acpi_ec_check_event(ec);
12761286
}
12771287

1278-
static u32 acpi_ec_gpe_handler(acpi_handle gpe_device,
1279-
u32 gpe_number, void *data)
1288+
static void acpi_ec_handle_interrupt(struct acpi_ec *ec)
12801289
{
12811290
unsigned long flags;
1282-
struct acpi_ec *ec = data;
12831291

12841292
spin_lock_irqsave(&ec->lock, flags);
12851293
advance_transaction(ec);
12861294
spin_unlock_irqrestore(&ec->lock, flags);
1295+
}
1296+
1297+
static u32 acpi_ec_gpe_handler(acpi_handle gpe_device,
1298+
u32 gpe_number, void *data)
1299+
{
1300+
acpi_ec_handle_interrupt(data);
12871301
return ACPI_INTERRUPT_HANDLED;
12881302
}
12891303

1304+
static irqreturn_t acpi_ec_irq_handler(int irq, void *data)
1305+
{
1306+
acpi_ec_handle_interrupt(data);
1307+
return IRQ_HANDLED;
1308+
}
1309+
12901310
/* --------------------------------------------------------------------------
12911311
* Address Space Management
12921312
* -------------------------------------------------------------------------- */
@@ -1359,6 +1379,8 @@ static struct acpi_ec *acpi_ec_alloc(void)
13591379
ec->timestamp = jiffies;
13601380
ec->busy_polling = true;
13611381
ec->polling_guard = 0;
1382+
ec->gpe = -1;
1383+
ec->irq = -1;
13621384
return ec;
13631385
}
13641386

@@ -1406,9 +1428,13 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
14061428
/* Get GPE bit assignment (EC events). */
14071429
/* TODO: Add support for _GPE returning a package */
14081430
status = acpi_evaluate_integer(handle, "_GPE", NULL, &tmp);
1409-
if (ACPI_FAILURE(status))
1410-
return status;
1411-
ec->gpe = tmp;
1431+
if (ACPI_SUCCESS(status))
1432+
ec->gpe = tmp;
1433+
1434+
/*
1435+
* Errors are non-fatal, allowing for ACPI Reduced Hardware
1436+
* platforms which use GpioInt instead of GPE.
1437+
*/
14121438
}
14131439
/* Use the global lock for all EC transactions? */
14141440
tmp = 0;
@@ -1418,12 +1444,57 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
14181444
return AE_CTRL_TERMINATE;
14191445
}
14201446

1447+
static void install_gpe_event_handler(struct acpi_ec *ec)
1448+
{
1449+
acpi_status status =
1450+
acpi_install_gpe_raw_handler(NULL, ec->gpe,
1451+
ACPI_GPE_EDGE_TRIGGERED,
1452+
&acpi_ec_gpe_handler,
1453+
ec);
1454+
if (ACPI_SUCCESS(status)) {
1455+
/* This is not fatal as we can poll EC events */
1456+
set_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags);
1457+
acpi_ec_leave_noirq(ec);
1458+
if (test_bit(EC_FLAGS_STARTED, &ec->flags) &&
1459+
ec->reference_count >= 1)
1460+
acpi_ec_enable_gpe(ec, true);
1461+
}
1462+
}
1463+
1464+
/* ACPI reduced hardware platforms use a GpioInt specified in _CRS. */
1465+
static int install_gpio_irq_event_handler(struct acpi_ec *ec,
1466+
struct acpi_device *device)
1467+
{
1468+
int irq = acpi_dev_gpio_irq_get(device, 0);
1469+
int ret;
1470+
1471+
if (irq < 0)
1472+
return irq;
1473+
1474+
ret = request_irq(irq, acpi_ec_irq_handler, IRQF_SHARED,
1475+
"ACPI EC", ec);
1476+
1477+
/*
1478+
* Unlike the GPE case, we treat errors here as fatal, we'll only
1479+
* implement GPIO polling if we find a case that needs it.
1480+
*/
1481+
if (ret < 0)
1482+
return ret;
1483+
1484+
ec->irq = irq;
1485+
set_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags);
1486+
acpi_ec_leave_noirq(ec);
1487+
1488+
return 0;
1489+
}
1490+
14211491
/*
14221492
* Note: This function returns an error code only when the address space
14231493
* handler is not installed, which means "not able to handle
14241494
* transactions".
14251495
*/
1426-
static int ec_install_handlers(struct acpi_ec *ec, bool handle_events)
1496+
static int ec_install_handlers(struct acpi_ec *ec, struct acpi_device *device,
1497+
bool handle_events)
14271498
{
14281499
acpi_status status;
14291500

@@ -1464,16 +1535,15 @@ static int ec_install_handlers(struct acpi_ec *ec, bool handle_events)
14641535
set_bit(EC_FLAGS_QUERY_METHODS_INSTALLED, &ec->flags);
14651536
}
14661537
if (!test_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags)) {
1467-
status = acpi_install_gpe_raw_handler(NULL, ec->gpe,
1468-
ACPI_GPE_EDGE_TRIGGERED,
1469-
&acpi_ec_gpe_handler, ec);
1470-
/* This is not fatal as we can poll EC events */
1471-
if (ACPI_SUCCESS(status)) {
1472-
set_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags);
1473-
acpi_ec_leave_noirq(ec);
1474-
if (test_bit(EC_FLAGS_STARTED, &ec->flags) &&
1475-
ec->reference_count >= 1)
1476-
acpi_ec_enable_gpe(ec, true);
1538+
if (ec->gpe >= 0) {
1539+
install_gpe_event_handler(ec);
1540+
} else if (device) {
1541+
int ret = install_gpio_irq_event_handler(ec, device);
1542+
1543+
if (ret)
1544+
return ret;
1545+
} else { /* No GPE and no GpioInt? */
1546+
return -ENODEV;
14771547
}
14781548
}
14791549
/* EC is fully operational, allow queries */
@@ -1505,9 +1575,14 @@ static void ec_remove_handlers(struct acpi_ec *ec)
15051575
acpi_ec_stop(ec, false);
15061576

15071577
if (test_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags)) {
1508-
if (ACPI_FAILURE(acpi_remove_gpe_handler(NULL, ec->gpe,
1509-
&acpi_ec_gpe_handler)))
1578+
if (ec->gpe >= 0 &&
1579+
ACPI_FAILURE(acpi_remove_gpe_handler(NULL, ec->gpe,
1580+
&acpi_ec_gpe_handler)))
15101581
pr_err("failed to remove gpe handler\n");
1582+
1583+
if (ec->irq >= 0)
1584+
free_irq(ec->irq, ec);
1585+
15111586
clear_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags);
15121587
}
15131588
if (test_bit(EC_FLAGS_QUERY_METHODS_INSTALLED, &ec->flags)) {
@@ -1516,11 +1591,12 @@ static void ec_remove_handlers(struct acpi_ec *ec)
15161591
}
15171592
}
15181593

1519-
static int acpi_ec_setup(struct acpi_ec *ec, bool handle_events)
1594+
static int acpi_ec_setup(struct acpi_ec *ec, struct acpi_device *device,
1595+
bool handle_events)
15201596
{
15211597
int ret;
15221598

1523-
ret = ec_install_handlers(ec, handle_events);
1599+
ret = ec_install_handlers(ec, device, handle_events);
15241600
if (ret)
15251601
return ret;
15261602

@@ -1531,8 +1607,8 @@ static int acpi_ec_setup(struct acpi_ec *ec, bool handle_events)
15311607
}
15321608

15331609
acpi_handle_info(ec->handle,
1534-
"GPE=0x%x, EC_CMD/EC_SC=0x%lx, EC_DATA=0x%lx\n",
1535-
ec->gpe, ec->command_addr, ec->data_addr);
1610+
"GPE=0x%x, IRQ=%d, EC_CMD/EC_SC=0x%lx, EC_DATA=0x%lx\n",
1611+
ec->gpe, ec->irq, ec->command_addr, ec->data_addr);
15361612
return ret;
15371613
}
15381614

@@ -1596,7 +1672,7 @@ static int acpi_ec_add(struct acpi_device *device)
15961672
}
15971673
}
15981674

1599-
ret = acpi_ec_setup(ec, true);
1675+
ret = acpi_ec_setup(ec, device, true);
16001676
if (ret)
16011677
goto err_query;
16021678

@@ -1716,7 +1792,7 @@ void __init acpi_ec_dsdt_probe(void)
17161792
* At this point, the GPE is not fully initialized, so do not to
17171793
* handle the events.
17181794
*/
1719-
ret = acpi_ec_setup(ec, false);
1795+
ret = acpi_ec_setup(ec, NULL, false);
17201796
if (ret) {
17211797
acpi_ec_free(ec);
17221798
return;
@@ -1889,14 +1965,21 @@ void __init acpi_ec_ecdt_probe(void)
18891965
ec->command_addr = ecdt_ptr->control.address;
18901966
ec->data_addr = ecdt_ptr->data.address;
18911967
}
1892-
ec->gpe = ecdt_ptr->gpe;
1968+
1969+
/*
1970+
* Ignore the GPE value on Reduced Hardware platforms.
1971+
* Some products have this set to an erroneous value.
1972+
*/
1973+
if (!acpi_gbl_reduced_hardware)
1974+
ec->gpe = ecdt_ptr->gpe;
1975+
18931976
ec->handle = ACPI_ROOT_OBJECT;
18941977

18951978
/*
18961979
* At this point, the namespace is not initialized, so do not find
18971980
* the namespace objects, or handle the events.
18981981
*/
1899-
ret = acpi_ec_setup(ec, false);
1982+
ret = acpi_ec_setup(ec, NULL, false);
19001983
if (ret) {
19011984
acpi_ec_free(ec);
19021985
return;
@@ -1928,7 +2011,7 @@ static int acpi_ec_suspend_noirq(struct device *dev)
19282011
* masked at the low level without side effects.
19292012
*/
19302013
if (ec_no_wakeup && test_bit(EC_FLAGS_STARTED, &ec->flags) &&
1931-
ec->reference_count >= 1)
2014+
ec->gpe >= 0 && ec->reference_count >= 1)
19322015
acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_DISABLE);
19332016

19342017
acpi_ec_enter_noirq(ec);
@@ -1943,7 +2026,7 @@ static int acpi_ec_resume_noirq(struct device *dev)
19432026
acpi_ec_leave_noirq(ec);
19442027

19452028
if (ec_no_wakeup && test_bit(EC_FLAGS_STARTED, &ec->flags) &&
1946-
ec->reference_count >= 1)
2029+
ec->gpe >= 0 && ec->reference_count >= 1)
19472030
acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_ENABLE);
19482031

19492032
return 0;

drivers/acpi/internal.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,8 @@ static inline void acpi_early_processor_osc(void) {}
165165
-------------------------------------------------------------------------- */
166166
struct acpi_ec {
167167
acpi_handle handle;
168-
u32 gpe;
168+
int gpe;
169+
int irq;
169170
unsigned long command_addr;
170171
unsigned long data_addr;
171172
bool global_lock;

0 commit comments

Comments
 (0)