diff options
author | Even Xu <even.xu@intel.com> | 2017-02-03 01:24:53 -0500 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2017-02-07 22:11:57 -0500 |
commit | 291e9e3f6931eda50be839500c15b1135146aaf6 (patch) | |
tree | d214c5c7632d3d35a8d9fdbd7f124255e82f797d | |
parent | 5299a92a3b98b91b7230662b8b9b6c64bcf8cae6 (diff) |
HID: intel-ish-hid: ipc: check FW status to distinguish ISH resume paths
For ISH resume, there are two paths, they need different way to handle: one
where ISH is not powered off, in that case a simple resume message is enough,
in other case we need a reset sequence.
We can use ISH FW status to distinguish those two cases and handle them
properly.
Signed-off-by: Even Xu <even.xu@intel.com>
Acked-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
-rw-r--r-- | drivers/hid/intel-ish-hid/ipc/hw-ish-regs.h | 8 | ||||
-rw-r--r-- | drivers/hid/intel-ish-hid/ipc/hw-ish.h | 12 | ||||
-rw-r--r-- | drivers/hid/intel-ish-hid/ipc/pci-ish.c | 34 |
3 files changed, 44 insertions, 10 deletions
diff --git a/drivers/hid/intel-ish-hid/ipc/hw-ish-regs.h b/drivers/hid/intel-ish-hid/ipc/hw-ish-regs.h index ab68afcba2a2..a5897b9c0956 100644 --- a/drivers/hid/intel-ish-hid/ipc/hw-ish-regs.h +++ b/drivers/hid/intel-ish-hid/ipc/hw-ish-regs.h | |||
@@ -111,6 +111,14 @@ | |||
111 | #define IPC_ILUP_BIT (1<<IPC_ILUP_OFFS) | 111 | #define IPC_ILUP_BIT (1<<IPC_ILUP_OFFS) |
112 | 112 | ||
113 | /* | 113 | /* |
114 | * ISH FW status bits in ISH FW Status Register | ||
115 | */ | ||
116 | #define IPC_ISH_FWSTS_SHIFT 12 | ||
117 | #define IPC_ISH_FWSTS_MASK GENMASK(15, 12) | ||
118 | #define IPC_GET_ISH_FWSTS(status) \ | ||
119 | (((status) & IPC_ISH_FWSTS_MASK) >> IPC_ISH_FWSTS_SHIFT) | ||
120 | |||
121 | /* | ||
114 | * FW status bits (relevant) | 122 | * FW status bits (relevant) |
115 | */ | 123 | */ |
116 | #define IPC_FWSTS_ILUP 0x1 | 124 | #define IPC_FWSTS_ILUP 0x1 |
diff --git a/drivers/hid/intel-ish-hid/ipc/hw-ish.h b/drivers/hid/intel-ish-hid/ipc/hw-ish.h index 46615a03e78f..fd34307a7a70 100644 --- a/drivers/hid/intel-ish-hid/ipc/hw-ish.h +++ b/drivers/hid/intel-ish-hid/ipc/hw-ish.h | |||
@@ -61,6 +61,18 @@ struct ish_hw { | |||
61 | void __iomem *mem_addr; | 61 | void __iomem *mem_addr; |
62 | }; | 62 | }; |
63 | 63 | ||
64 | /* | ||
65 | * ISH FW status type | ||
66 | */ | ||
67 | enum { | ||
68 | FWSTS_AFTER_RESET = 0, | ||
69 | FWSTS_WAIT_FOR_HOST = 4, | ||
70 | FWSTS_START_KERNEL_DMA = 5, | ||
71 | FWSTS_FW_IS_RUNNING = 7, | ||
72 | FWSTS_SENSOR_APP_LOADED = 8, | ||
73 | FWSTS_SENSOR_APP_RUNNING = 15 | ||
74 | }; | ||
75 | |||
64 | #define to_ish_hw(dev) (struct ish_hw *)((dev)->hw) | 76 | #define to_ish_hw(dev) (struct ish_hw *)((dev)->hw) |
65 | 77 | ||
66 | irqreturn_t ish_irq_handler(int irq, void *dev_id); | 78 | irqreturn_t ish_irq_handler(int irq, void *dev_id); |
diff --git a/drivers/hid/intel-ish-hid/ipc/pci-ish.c b/drivers/hid/intel-ish-hid/ipc/pci-ish.c index 34c95de6885e..393f2e3d4679 100644 --- a/drivers/hid/intel-ish-hid/ipc/pci-ish.c +++ b/drivers/hid/intel-ish-hid/ipc/pci-ish.c | |||
@@ -206,12 +206,15 @@ static void ish_remove(struct pci_dev *pdev) | |||
206 | #ifdef CONFIG_PM | 206 | #ifdef CONFIG_PM |
207 | static struct device *ish_resume_device; | 207 | static struct device *ish_resume_device; |
208 | 208 | ||
209 | /* 50ms to get resume response */ | ||
210 | #define WAIT_FOR_RESUME_ACK_MS 50 | ||
211 | |||
209 | /** | 212 | /** |
210 | * ish_resume_handler() - Work function to complete resume | 213 | * ish_resume_handler() - Work function to complete resume |
211 | * @work: work struct | 214 | * @work: work struct |
212 | * | 215 | * |
213 | * The resume work function to complete resume function asynchronously. | 216 | * The resume work function to complete resume function asynchronously. |
214 | * There are two types of platforms, one where ISH is not powered off, | 217 | * There are two resume paths, one where ISH is not powered off, |
215 | * in that case a simple resume message is enough, others we need | 218 | * in that case a simple resume message is enough, others we need |
216 | * a reset sequence. | 219 | * a reset sequence. |
217 | */ | 220 | */ |
@@ -219,20 +222,31 @@ static void ish_resume_handler(struct work_struct *work) | |||
219 | { | 222 | { |
220 | struct pci_dev *pdev = to_pci_dev(ish_resume_device); | 223 | struct pci_dev *pdev = to_pci_dev(ish_resume_device); |
221 | struct ishtp_device *dev = pci_get_drvdata(pdev); | 224 | struct ishtp_device *dev = pci_get_drvdata(pdev); |
225 | uint32_t fwsts; | ||
222 | int ret; | 226 | int ret; |
223 | 227 | ||
224 | ishtp_send_resume(dev); | 228 | /* Get ISH FW status */ |
229 | fwsts = IPC_GET_ISH_FWSTS(dev->ops->get_fw_status(dev)); | ||
225 | 230 | ||
226 | /* 50 ms to get resume response */ | 231 | /* |
227 | if (dev->resume_flag) | 232 | * If currently, in ISH FW, sensor app is loaded or beyond that, |
228 | ret = wait_event_interruptible_timeout(dev->resume_wait, | 233 | * it means ISH isn't powered off, in this case, send a resume message. |
229 | !dev->resume_flag, | 234 | */ |
230 | msecs_to_jiffies(50)); | 235 | if (fwsts >= FWSTS_SENSOR_APP_LOADED) { |
236 | ishtp_send_resume(dev); | ||
237 | |||
238 | /* Waiting to get resume response */ | ||
239 | if (dev->resume_flag) | ||
240 | ret = wait_event_interruptible_timeout(dev->resume_wait, | ||
241 | !dev->resume_flag, | ||
242 | msecs_to_jiffies(WAIT_FOR_RESUME_ACK_MS)); | ||
243 | } | ||
231 | 244 | ||
232 | /* | 245 | /* |
233 | * If no resume response. This platform is not S0ix compatible | 246 | * If in ISH FW, sensor app isn't loaded yet, or no resume response. |
234 | * So on resume full reboot of ISH processor will happen, so | 247 | * That means this platform is not S0ix compatible, or something is |
235 | * need to go through init sequence again | 248 | * wrong with ISH FW. So on resume, full reboot of ISH processor will |
249 | * happen, so need to go through init sequence again. | ||
236 | */ | 250 | */ |
237 | if (dev->resume_flag) | 251 | if (dev->resume_flag) |
238 | ish_init(dev); | 252 | ish_init(dev); |