Skip to content

Commit e04653a

Browse files
apatni7884Lee Jones
authored andcommitted
mfd: cros_ec: Add ACPI GPE handler for LID0 devices
This patch installs an ACPI GPE handler for LID0 ACPI device to indicate ACPI core that this GPE should stay enabled for lid to work in suspend to idle path. Signed-off-by: Archana Patni <archana.patni@intel.com> Signed-off-by: Thierry Escande <thierry.escande@collabora.com> Signed-off-by: Lee Jones <lee.jones@linaro.org>
1 parent 18973ce commit e04653a

4 files changed

Lines changed: 136 additions & 4 deletions

File tree

drivers/mfd/Makefile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ obj-$(CONFIG_MFD_ACT8945A) += act8945a.o
1010
obj-$(CONFIG_MFD_SM501) += sm501.o
1111
obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o
1212
obj-$(CONFIG_MFD_BCM590XX) += bcm590xx.o
13-
obj-$(CONFIG_MFD_CROS_EC) += cros_ec.o
13+
cros_ec_core-objs := cros_ec.o
14+
cros_ec_core-$(CONFIG_ACPI) += cros_ec_acpi_gpe.o
15+
obj-$(CONFIG_MFD_CROS_EC) += cros_ec_core.o
1416
obj-$(CONFIG_MFD_CROS_EC_I2C) += cros_ec_i2c.o
1517
obj-$(CONFIG_MFD_CROS_EC_SPI) += cros_ec_spi.o
1618
obj-$(CONFIG_MFD_EXYNOS_LPASS) += exynos-lpass.o

drivers/mfd/cros_ec.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,8 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
166166

167167
dev_info(dev, "Chrome EC device registered\n");
168168

169+
cros_ec_acpi_install_gpe_handler(dev);
170+
169171
return 0;
170172

171173
fail_mfd:
@@ -179,6 +181,8 @@ int cros_ec_remove(struct cros_ec_device *ec_dev)
179181
{
180182
mfd_remove_devices(ec_dev->dev);
181183

184+
cros_ec_acpi_remove_gpe_handler();
185+
182186
return 0;
183187
}
184188
EXPORT_SYMBOL(cros_ec_remove);
@@ -190,9 +194,14 @@ int cros_ec_suspend(struct cros_ec_device *ec_dev)
190194
int ret;
191195
u8 sleep_event;
192196

193-
sleep_event = (!IS_ENABLED(CONFIG_ACPI) || pm_suspend_via_firmware()) ?
194-
HOST_SLEEP_EVENT_S3_RESUME :
195-
HOST_SLEEP_EVENT_S0IX_RESUME;
197+
if (!IS_ENABLED(CONFIG_ACPI) || pm_suspend_via_firmware()) {
198+
sleep_event = HOST_SLEEP_EVENT_S3_SUSPEND;
199+
} else {
200+
sleep_event = HOST_SLEEP_EVENT_S0IX_SUSPEND;
201+
202+
/* Clearing the GPE status for any pending event */
203+
cros_ec_acpi_clear_gpe();
204+
}
196205

197206
ret = cros_ec_sleep_event(ec_dev, sleep_event);
198207
if (ret < 0)

drivers/mfd/cros_ec_acpi_gpe.c

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/*
2+
* ChromeOS EC multi-function device
3+
*
4+
* Copyright (C) 2017 Google, Inc
5+
*
6+
* This software is licensed under the terms of the GNU General Public
7+
* License version 2, as published by the Free Software Foundation, and
8+
* may be copied, distributed, and modified under those terms.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* The ChromeOS EC multi function device is used to mux all the requests
16+
* to the EC device for its multiple features: keyboard controller,
17+
* battery charging and regulator control, firmware update.
18+
*/
19+
#include <linux/acpi.h>
20+
21+
#define ACPI_LID_DEVICE "LID0"
22+
23+
static int ec_wake_gpe = -EINVAL;
24+
25+
/*
26+
* This handler indicates to ACPI core that this GPE should stay enabled for
27+
* lid to work in suspend to idle path.
28+
*/
29+
static u32 cros_ec_gpe_handler(acpi_handle gpe_device, u32 gpe_number,
30+
void *data)
31+
{
32+
return ACPI_INTERRUPT_HANDLED | ACPI_REENABLE_GPE;
33+
}
34+
35+
/*
36+
* Get ACPI GPE for LID0 device.
37+
*/
38+
static int cros_ec_get_ec_wake_gpe(struct device *dev)
39+
{
40+
struct acpi_device *cros_acpi_dev;
41+
struct acpi_device *adev;
42+
acpi_handle handle;
43+
acpi_status status;
44+
int ret;
45+
46+
cros_acpi_dev = ACPI_COMPANION(dev);
47+
48+
if (!cros_acpi_dev || !cros_acpi_dev->parent ||
49+
!cros_acpi_dev->parent->handle)
50+
return -EINVAL;
51+
52+
status = acpi_get_handle(cros_acpi_dev->parent->handle, ACPI_LID_DEVICE,
53+
&handle);
54+
if (ACPI_FAILURE(status))
55+
return -EINVAL;
56+
57+
ret = acpi_bus_get_device(handle, &adev);
58+
if (ret)
59+
return ret;
60+
61+
return adev->wakeup.gpe_number;
62+
}
63+
64+
int cros_ec_acpi_install_gpe_handler(struct device *dev)
65+
{
66+
acpi_status status;
67+
68+
ec_wake_gpe = cros_ec_get_ec_wake_gpe(dev);
69+
70+
if (ec_wake_gpe < 0)
71+
return ec_wake_gpe;
72+
73+
status = acpi_install_gpe_handler(NULL, ec_wake_gpe,
74+
ACPI_GPE_EDGE_TRIGGERED,
75+
&cros_ec_gpe_handler, NULL);
76+
if (ACPI_FAILURE(status))
77+
return -ENODEV;
78+
79+
dev_info(dev, "Initialized, GPE = 0x%x\n", ec_wake_gpe);
80+
81+
return 0;
82+
}
83+
84+
void cros_ec_acpi_remove_gpe_handler(void)
85+
{
86+
acpi_status status;
87+
88+
if (ec_wake_gpe < 0)
89+
return;
90+
91+
status = acpi_remove_gpe_handler(NULL, ec_wake_gpe,
92+
&cros_ec_gpe_handler);
93+
if (ACPI_FAILURE(status))
94+
pr_err("failed to remove gpe handler\n");
95+
}
96+
97+
void cros_ec_acpi_clear_gpe(void)
98+
{
99+
if (ec_wake_gpe < 0)
100+
return;
101+
102+
acpi_clear_gpe(NULL, ec_wake_gpe);
103+
}

include/linux/mfd/cros_ec.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,4 +304,22 @@ extern struct attribute_group cros_ec_attr_group;
304304
extern struct attribute_group cros_ec_lightbar_attr_group;
305305
extern struct attribute_group cros_ec_vbc_attr_group;
306306

307+
/* ACPI GPE handler */
308+
#ifdef CONFIG_ACPI
309+
310+
int cros_ec_acpi_install_gpe_handler(struct device *dev);
311+
void cros_ec_acpi_remove_gpe_handler(void);
312+
void cros_ec_acpi_clear_gpe(void);
313+
314+
#else /* CONFIG_ACPI */
315+
316+
static inline int cros_ec_acpi_install_gpe_handler(struct device *dev)
317+
{
318+
return -ENODEV;
319+
}
320+
static inline void cros_ec_acpi_remove_gpe_handler(void) {}
321+
static inline void cros_ec_acpi_clear_gpe(void) {}
322+
323+
#endif /* CONFIG_ACPI */
324+
307325
#endif /* __LINUX_MFD_CROS_EC_H */

0 commit comments

Comments
 (0)