diff mbox series

[1/2] hid: intel-ish-hid: ipc: finish power flow for EHL OOB

Message ID 20201216063640.4086068-2-lixu.zhang@intel.com (mailing list archive)
State Mainlined
Commit 2e23a70edabe933284f690dff49497fb6b82b0e5
Delegated to: Jiri Kosina
Headers show
Series hid: intel-ish-hid: ipc: enable OOB support for EHL | expand

Commit Message

Zhang Lixu Dec. 16, 2020, 6:36 a.m. UTC
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>
---
 drivers/hid/intel-ish-hid/ipc/pci-ish.c | 48 +++++++++++++++++++++++++
 1 file changed, 48 insertions(+)

Comments

srinivas pandruvada Jan. 4, 2021, 3:59 p.m. UTC | #1
On Wed, 2020-12-16 at 14:36 +0800, Zhang Lixu wrote:
> 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>
Acked-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>

> ---
>  drivers/hid/intel-ish-hid/ipc/pci-ish.c | 48
> +++++++++++++++++++++++++
>  1 file changed, 48 insertions(+)
> 
> diff --git a/drivers/hid/intel-ish-hid/ipc/pci-ish.c
> b/drivers/hid/intel-ish-hid/ipc/pci-ish.c
> index c6d48a8648b7..c9c5488e44cb 100644
> --- a/drivers/hid/intel-ish-hid/ipc/pci-ish.c
> +++ b/drivers/hid/intel-ish-hid/ipc/pci-ish.c
> @@ -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;
>
diff mbox series

Patch

diff --git a/drivers/hid/intel-ish-hid/ipc/pci-ish.c b/drivers/hid/intel-ish-hid/ipc/pci-ish.c
index c6d48a8648b7..c9c5488e44cb 100644
--- a/drivers/hid/intel-ish-hid/ipc/pci-ish.c
+++ b/drivers/hid/intel-ish-hid/ipc/pci-ish.c
@@ -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;