Commit 2e23a70e authored by Zhang Lixu's avatar Zhang Lixu Committed by Jiri Kosina

HID: intel-ish-hid: ipc: finish power flow for EHL OOB

The EHL (Elkhart Lake) based platforms provide a OOB (Out of band)
service, which allows wakup device when the system is in S5 (Soft-Off
state). This OOB service can be enabled/disabled from BIOS settings. When
enabled, the ISH device gets PME wake capability. To enable PME wakeup,
driver also needs to enable ACPI GPE bit.

Once wakeup, BIOS will clear the wakeup bit to identify wakeup is
successful. So driver need to re-enable it in resume function to
keep the next wakeup capability.

Since this feature is only present on EHL, we use EHL PCI device id to
enable this feature.
Co-developed-by: default avatarNajumon Ba <najumon.ba@intel.com>
Signed-off-by: default avatarNajumon Ba <najumon.ba@intel.com>
Signed-off-by: default avatarEven Xu <even.xu@intel.com>
Signed-off-by: default avatarZhang Lixu <lixu.zhang@intel.com>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parent de925e2f
......@@ -5,6 +5,7 @@
* Copyright (c) 2014-2016, Intel Corporation.
*/
#include <linux/acpi.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
......@@ -111,6 +112,42 @@ static inline bool ish_should_leave_d0i3(struct pci_dev *pdev)
return !pm_resume_via_firmware() || pdev->device == CHV_DEVICE_ID;
}
static int enable_gpe(struct device *dev)
{
#ifdef CONFIG_ACPI
acpi_status acpi_sts;
struct acpi_device *adev;
struct acpi_device_wakeup *wakeup;
adev = ACPI_COMPANION(dev);
if (!adev) {
dev_err(dev, "get acpi handle failed\n");
return -ENODEV;
}
wakeup = &adev->wakeup;
acpi_sts = acpi_enable_gpe(wakeup->gpe_device, wakeup->gpe_number);
if (ACPI_FAILURE(acpi_sts)) {
dev_err(dev, "enable ose_gpe failed\n");
return -EIO;
}
return 0;
#else
return -ENODEV;
#endif
}
static void enable_pme_wake(struct pci_dev *pdev)
{
if ((pci_pme_capable(pdev, PCI_D0) ||
pci_pme_capable(pdev, PCI_D3hot) ||
pci_pme_capable(pdev, PCI_D3cold)) && !enable_gpe(&pdev->dev)) {
pci_pme_active(pdev, true);
dev_dbg(&pdev->dev, "ish ipc driver pme wake enabled\n");
}
}
/**
* ish_probe() - PCI driver probe callback
* @pdev: pci device
......@@ -179,6 +216,10 @@ static int ish_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
init_waitqueue_head(&ishtp->suspend_wait);
init_waitqueue_head(&ishtp->resume_wait);
/* Enable PME for EHL */
if (pdev->device == EHL_Ax_DEVICE_ID)
enable_pme_wake(pdev);
ret = ish_init(ishtp);
if (ret)
return ret;
......@@ -317,6 +358,13 @@ static int __maybe_unused ish_resume(struct device *device)
struct pci_dev *pdev = to_pci_dev(device);
struct ishtp_device *dev = pci_get_drvdata(pdev);
/* add this to finish power flow for EHL */
if (dev->pdev->device == EHL_Ax_DEVICE_ID) {
pci_set_power_state(pdev, PCI_D0);
enable_pme_wake(pdev);
dev_dbg(dev->devc, "set power state to D0 for ehl\n");
}
ish_resume_device = device;
dev->resume_flag = 1;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment