|
5 | 5 | * Copyright (c) 2014-2016, Intel Corporation. |
6 | 6 | */ |
7 | 7 |
|
| 8 | +#include <linux/acpi.h> |
8 | 9 | #include <linux/module.h> |
9 | 10 | #include <linux/moduleparam.h> |
10 | 11 | #include <linux/kernel.h> |
@@ -112,6 +113,42 @@ static inline bool ish_should_leave_d0i3(struct pci_dev *pdev) |
112 | 113 | return !pm_resume_via_firmware() || pdev->device == CHV_DEVICE_ID; |
113 | 114 | } |
114 | 115 |
|
| 116 | +static int enable_gpe(struct device *dev) |
| 117 | +{ |
| 118 | +#ifdef CONFIG_ACPI |
| 119 | + acpi_status acpi_sts; |
| 120 | + struct acpi_device *adev; |
| 121 | + struct acpi_device_wakeup *wakeup; |
| 122 | + |
| 123 | + adev = ACPI_COMPANION(dev); |
| 124 | + if (!adev) { |
| 125 | + dev_err(dev, "get acpi handle failed\n"); |
| 126 | + return -ENODEV; |
| 127 | + } |
| 128 | + wakeup = &adev->wakeup; |
| 129 | + |
| 130 | + acpi_sts = acpi_enable_gpe(wakeup->gpe_device, wakeup->gpe_number); |
| 131 | + if (ACPI_FAILURE(acpi_sts)) { |
| 132 | + dev_err(dev, "enable ose_gpe failed\n"); |
| 133 | + return -EIO; |
| 134 | + } |
| 135 | + |
| 136 | + return 0; |
| 137 | +#else |
| 138 | + return -ENODEV; |
| 139 | +#endif |
| 140 | +} |
| 141 | + |
| 142 | +static void enable_pme_wake(struct pci_dev *pdev) |
| 143 | +{ |
| 144 | + if ((pci_pme_capable(pdev, PCI_D0) || |
| 145 | + pci_pme_capable(pdev, PCI_D3hot) || |
| 146 | + pci_pme_capable(pdev, PCI_D3cold)) && !enable_gpe(&pdev->dev)) { |
| 147 | + pci_pme_active(pdev, true); |
| 148 | + dev_dbg(&pdev->dev, "ish ipc driver pme wake enabled\n"); |
| 149 | + } |
| 150 | +} |
| 151 | + |
115 | 152 | /** |
116 | 153 | * ish_probe() - PCI driver probe callback |
117 | 154 | * @pdev: pci device |
@@ -180,6 +217,10 @@ static int ish_probe(struct pci_dev *pdev, const struct pci_device_id *ent) |
180 | 217 | init_waitqueue_head(&ishtp->suspend_wait); |
181 | 218 | init_waitqueue_head(&ishtp->resume_wait); |
182 | 219 |
|
| 220 | + /* Enable PME for EHL */ |
| 221 | + if (pdev->device == EHL_Ax_DEVICE_ID) |
| 222 | + enable_pme_wake(pdev); |
| 223 | + |
183 | 224 | ret = ish_init(ishtp); |
184 | 225 | if (ret) |
185 | 226 | return ret; |
@@ -219,11 +260,15 @@ static void __maybe_unused ish_resume_handler(struct work_struct *work) |
219 | 260 | { |
220 | 261 | struct pci_dev *pdev = to_pci_dev(ish_resume_device); |
221 | 262 | struct ishtp_device *dev = pci_get_drvdata(pdev); |
| 263 | + uint32_t fwsts = dev->ops->get_fw_status(dev); |
222 | 264 | int ret; |
223 | 265 |
|
224 | | - if (ish_should_leave_d0i3(pdev) && !dev->suspend_flag) { |
| 266 | + if (ish_should_leave_d0i3(pdev) && !dev->suspend_flag |
| 267 | + && IPC_IS_ISH_ILUP(fwsts)) { |
225 | 268 | disable_irq_wake(pdev->irq); |
226 | 269 |
|
| 270 | + ish_set_host_ready(dev); |
| 271 | + |
227 | 272 | ishtp_send_resume(dev); |
228 | 273 |
|
229 | 274 | /* Waiting to get resume response */ |
@@ -318,6 +363,13 @@ static int __maybe_unused ish_resume(struct device *device) |
318 | 363 | struct pci_dev *pdev = to_pci_dev(device); |
319 | 364 | struct ishtp_device *dev = pci_get_drvdata(pdev); |
320 | 365 |
|
| 366 | + /* add this to finish power flow for EHL */ |
| 367 | + if (dev->pdev->device == EHL_Ax_DEVICE_ID) { |
| 368 | + pci_set_power_state(pdev, PCI_D0); |
| 369 | + enable_pme_wake(pdev); |
| 370 | + dev_dbg(dev->devc, "set power state to D0 for ehl\n"); |
| 371 | + } |
| 372 | + |
321 | 373 | ish_resume_device = device; |
322 | 374 | dev->resume_flag = 1; |
323 | 375 |
|
|
0 commit comments