forked from Minki/linux
e04653a9dc
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>
104 lines
2.4 KiB
C
104 lines
2.4 KiB
C
/*
|
|
* ChromeOS EC multi-function device
|
|
*
|
|
* Copyright (C) 2017 Google, Inc
|
|
*
|
|
* This software is licensed under the terms of the GNU General Public
|
|
* License version 2, as published by the Free Software Foundation, and
|
|
* may be copied, distributed, and modified under those terms.
|
|
*
|
|
* 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.
|
|
*
|
|
* The ChromeOS EC multi function device is used to mux all the requests
|
|
* to the EC device for its multiple features: keyboard controller,
|
|
* battery charging and regulator control, firmware update.
|
|
*/
|
|
#include <linux/acpi.h>
|
|
|
|
#define ACPI_LID_DEVICE "LID0"
|
|
|
|
static int ec_wake_gpe = -EINVAL;
|
|
|
|
/*
|
|
* This handler indicates to ACPI core that this GPE should stay enabled for
|
|
* lid to work in suspend to idle path.
|
|
*/
|
|
static u32 cros_ec_gpe_handler(acpi_handle gpe_device, u32 gpe_number,
|
|
void *data)
|
|
{
|
|
return ACPI_INTERRUPT_HANDLED | ACPI_REENABLE_GPE;
|
|
}
|
|
|
|
/*
|
|
* Get ACPI GPE for LID0 device.
|
|
*/
|
|
static int cros_ec_get_ec_wake_gpe(struct device *dev)
|
|
{
|
|
struct acpi_device *cros_acpi_dev;
|
|
struct acpi_device *adev;
|
|
acpi_handle handle;
|
|
acpi_status status;
|
|
int ret;
|
|
|
|
cros_acpi_dev = ACPI_COMPANION(dev);
|
|
|
|
if (!cros_acpi_dev || !cros_acpi_dev->parent ||
|
|
!cros_acpi_dev->parent->handle)
|
|
return -EINVAL;
|
|
|
|
status = acpi_get_handle(cros_acpi_dev->parent->handle, ACPI_LID_DEVICE,
|
|
&handle);
|
|
if (ACPI_FAILURE(status))
|
|
return -EINVAL;
|
|
|
|
ret = acpi_bus_get_device(handle, &adev);
|
|
if (ret)
|
|
return ret;
|
|
|
|
return adev->wakeup.gpe_number;
|
|
}
|
|
|
|
int cros_ec_acpi_install_gpe_handler(struct device *dev)
|
|
{
|
|
acpi_status status;
|
|
|
|
ec_wake_gpe = cros_ec_get_ec_wake_gpe(dev);
|
|
|
|
if (ec_wake_gpe < 0)
|
|
return ec_wake_gpe;
|
|
|
|
status = acpi_install_gpe_handler(NULL, ec_wake_gpe,
|
|
ACPI_GPE_EDGE_TRIGGERED,
|
|
&cros_ec_gpe_handler, NULL);
|
|
if (ACPI_FAILURE(status))
|
|
return -ENODEV;
|
|
|
|
dev_info(dev, "Initialized, GPE = 0x%x\n", ec_wake_gpe);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void cros_ec_acpi_remove_gpe_handler(void)
|
|
{
|
|
acpi_status status;
|
|
|
|
if (ec_wake_gpe < 0)
|
|
return;
|
|
|
|
status = acpi_remove_gpe_handler(NULL, ec_wake_gpe,
|
|
&cros_ec_gpe_handler);
|
|
if (ACPI_FAILURE(status))
|
|
pr_err("failed to remove gpe handler\n");
|
|
}
|
|
|
|
void cros_ec_acpi_clear_gpe(void)
|
|
{
|
|
if (ec_wake_gpe < 0)
|
|
return;
|
|
|
|
acpi_clear_gpe(NULL, ec_wake_gpe);
|
|
}
|