Skip to content

Commit 2e23a70

Browse files
lixuzhaJiri Kosina
authored andcommitted
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: Najumon Ba <najumon.ba@intel.com> Signed-off-by: Najumon Ba <najumon.ba@intel.com> Signed-off-by: Even Xu <even.xu@intel.com> Signed-off-by: Zhang Lixu <lixu.zhang@intel.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
1 parent de925e2 commit 2e23a70

1 file changed

Lines changed: 48 additions & 0 deletions

File tree

drivers/hid/intel-ish-hid/ipc/pci-ish.c

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
* Copyright (c) 2014-2016, Intel Corporation.
66
*/
77

8+
#include <linux/acpi.h>
89
#include <linux/module.h>
910
#include <linux/moduleparam.h>
1011
#include <linux/kernel.h>
@@ -111,6 +112,42 @@ static inline bool ish_should_leave_d0i3(struct pci_dev *pdev)
111112
return !pm_resume_via_firmware() || pdev->device == CHV_DEVICE_ID;
112113
}
113114

115+
static int enable_gpe(struct device *dev)
116+
{
117+
#ifdef CONFIG_ACPI
118+
acpi_status acpi_sts;
119+
struct acpi_device *adev;
120+
struct acpi_device_wakeup *wakeup;
121+
122+
adev = ACPI_COMPANION(dev);
123+
if (!adev) {
124+
dev_err(dev, "get acpi handle failed\n");
125+
return -ENODEV;
126+
}
127+
wakeup = &adev->wakeup;
128+
129+
acpi_sts = acpi_enable_gpe(wakeup->gpe_device, wakeup->gpe_number);
130+
if (ACPI_FAILURE(acpi_sts)) {
131+
dev_err(dev, "enable ose_gpe failed\n");
132+
return -EIO;
133+
}
134+
135+
return 0;
136+
#else
137+
return -ENODEV;
138+
#endif
139+
}
140+
141+
static void enable_pme_wake(struct pci_dev *pdev)
142+
{
143+
if ((pci_pme_capable(pdev, PCI_D0) ||
144+
pci_pme_capable(pdev, PCI_D3hot) ||
145+
pci_pme_capable(pdev, PCI_D3cold)) && !enable_gpe(&pdev->dev)) {
146+
pci_pme_active(pdev, true);
147+
dev_dbg(&pdev->dev, "ish ipc driver pme wake enabled\n");
148+
}
149+
}
150+
114151
/**
115152
* ish_probe() - PCI driver probe callback
116153
* @pdev: pci device
@@ -179,6 +216,10 @@ static int ish_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
179216
init_waitqueue_head(&ishtp->suspend_wait);
180217
init_waitqueue_head(&ishtp->resume_wait);
181218

219+
/* Enable PME for EHL */
220+
if (pdev->device == EHL_Ax_DEVICE_ID)
221+
enable_pme_wake(pdev);
222+
182223
ret = ish_init(ishtp);
183224
if (ret)
184225
return ret;
@@ -317,6 +358,13 @@ static int __maybe_unused ish_resume(struct device *device)
317358
struct pci_dev *pdev = to_pci_dev(device);
318359
struct ishtp_device *dev = pci_get_drvdata(pdev);
319360

361+
/* add this to finish power flow for EHL */
362+
if (dev->pdev->device == EHL_Ax_DEVICE_ID) {
363+
pci_set_power_state(pdev, PCI_D0);
364+
enable_pme_wake(pdev);
365+
dev_dbg(dev->devc, "set power state to D0 for ehl\n");
366+
}
367+
320368
ish_resume_device = device;
321369
dev->resume_flag = 1;
322370

0 commit comments

Comments
 (0)