blob: 56d305dab2d487f7b07b8c9f5424320823aea03a [file] [log] [blame]
Archana Patnie04653a2017-02-01 17:22:03 +01001/*
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
23static 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 */
29static 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 */
38static 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
64int 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
84void 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
97void 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}