static int penwell_otg_ulpi_write(struct intel_mid_otg_xceiv *iotg,
u8 reg, u8 val);
+#ifdef CONFIG_PM_SLEEP
+#include <linux/suspend.h>
+DECLARE_WAIT_QUEUE_HEAD(stop_host_wait);
+atomic_t pnw_sys_suspended;
+
+static int pnw_sleep_pm_callback(struct notifier_block *nfb,
+ unsigned long action, void *ignored)
+{
+ switch (action) {
+ case PM_SUSPEND_PREPARE:
+ atomic_set(&pnw_sys_suspended, 1);
+ return NOTIFY_OK;
+ case PM_POST_SUSPEND:
+ atomic_set(&pnw_sys_suspended, 0);
+ return NOTIFY_OK;
+ }
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block pnw_sleep_pm_notifier = {
+ .notifier_call = pnw_sleep_pm_callback,
+ .priority = 0
+};
+
+#define PNW_PM_RESUME_WAIT(a) \
+ while (atomic_read(&pnw_sys_suspended)) { \
+ wait_event_timeout(a, false, HZ/100); \
+ }
+#else
+
+#define PNW_PM_RESUME_WAIT(a)
+
+#endif
+
+#define PNW_STOP_HOST(pnw) do { \
+ if ((pnw)->iotg.stop_host) { \
+ PNW_PM_RESUME_WAIT(stop_host_wait); \
+ (pnw)->iotg.stop_host(&(pnw)->iotg); \
+ } \
+ } while (0)
+
static inline int is_clovertrail(struct pci_dev *pdev)
{
return (pdev->vendor == 0x8086 && pdev->device == 0xE006);
hsm->a_srp_det = 0;
penwell_otg_HAAR(0);
- if (iotg->stop_host)
- iotg->stop_host(iotg);
- else
- dev_dbg(pnw->dev,
- "host driver has been removed.\n");
+
+ PNW_STOP_HOST(pnw);
set_host_mode();
penwell_otg_phy_low_power(1);
hsm->b_bus_req = 0;
penwell_otg_HAAR(0);
- if (iotg->stop_host)
- iotg->stop_host(iotg);
- else
- dev_dbg(pnw->dev,
- "host driver has been removed.\n");
+ PNW_STOP_HOST(pnw);
set_client_mode();
penwell_otg_phy_low_power(1);
penwell_otg_HAAR(0);
penwell_otg_nsf_msg(7);
- if (iotg->stop_host)
- iotg->stop_host(iotg);
- else
- dev_dbg(pnw->dev,
- "host driver has been removed.\n");
+ PNW_STOP_HOST(pnw);
hsm->a_bus_suspend = 0;
hsm->b_bus_req = 0;
/* Stop HNP polling */
iotg->stop_hnp_poll(iotg);
- if (iotg->stop_host)
- iotg->stop_host(iotg);
- else
- dev_dbg(pnw->dev,
- "host driver has been removed.\n");
+ PNW_STOP_HOST(pnw);
set_host_mode();
penwell_otg_phy_low_power(1);
/* Stop HNP polling */
iotg->stop_hnp_poll(iotg);
- if (iotg->stop_host)
- iotg->stop_host(iotg);
- else
- dev_dbg(pnw->dev,
- "host driver has been removed.\n");
+ PNW_STOP_HOST(pnw);
set_client_mode();
penwell_otg_phy_low_power(1);
/* Stop HNP polling */
iotg->stop_hnp_poll(iotg);
- if (iotg->stop_host)
- iotg->stop_host(iotg);
- else
- dev_dbg(pnw->dev,
- "host driver has been removed.\n");
-
+ PNW_STOP_HOST(pnw);
hsm->a_bus_suspend = 0;
/* Clear HNP polling flag */
hsm->b_bus_req = 0;
- if (iotg->stop_host)
- iotg->stop_host(iotg);
- else
- dev_dbg(pnw->dev,
- "host driver has been removed.\n");
+ PNW_STOP_HOST(pnw);
/* Turn off VBUS */
otg_set_vbus(&iotg->otg, false);
/* Delete current timer and disable host function */
penwell_otg_del_timer(TA_WAIT_BCON_TMR);
- if (iotg->stop_host)
- iotg->stop_host(iotg);
- else
- dev_dbg(pnw->dev,
- "host driver has been removed.\n");
+ PNW_STOP_HOST(pnw);
/* Turn off VBUS and enter PHY low power mode */
otg_set_vbus(&iotg->otg, false);
penwell_otg_phy_low_power(0);
- if (iotg->stop_host)
- iotg->stop_host(iotg);
- else
- dev_dbg(pnw->dev,
- "host driver has been removed.\n");
+ PNW_STOP_HOST(pnw);
/* Turn off VBUS */
otg_set_vbus(&iotg->otg, false);
penwell_otg_phy_low_power(0);
- if (iotg->stop_host)
- iotg->stop_host(iotg);
- else
- dev_dbg(pnw->dev,
- "host driver has been removed.\n");
+ PNW_STOP_HOST(pnw);
/* Turn off VBUS */
otg_set_vbus(&iotg->otg, false);
/* Stop HNP polling */
iotg->stop_hnp_poll(iotg);
- if (iotg->stop_host)
- iotg->stop_host(iotg);
- else
- dev_dbg(pnw->dev,
- "host driver has been removed.\n");
+ PNW_STOP_HOST(pnw);
/* Turn off VBUS */
otg_set_vbus(&iotg->otg, false);
penwell_otg_phy_low_power(0);
- if (iotg->stop_host)
- iotg->stop_host(iotg);
- else
- dev_dbg(pnw->dev,
- "host driver has been removed.\n");
+ PNW_STOP_HOST(pnw);
/* Turn off VBUS */
otg_set_vbus(&iotg->otg, false);
/* Stop HNP polling */
iotg->stop_hnp_poll(iotg);
- if (iotg->stop_host)
- iotg->stop_host(iotg);
- else
- dev_dbg(pnw->dev,
- "host driver has been removed.\n");
+ PNW_STOP_HOST(pnw);
/* Turn off VBUS */
otg_set_vbus(&iotg->otg, false);
/* Delete current timer and clear flags */
penwell_otg_del_timer(TA_AIDL_BDIS_TMR);
- if (iotg->stop_host)
- iotg->stop_host(iotg);
- else
- dev_dbg(pnw->dev,
- "host driver has been removed.\n");
+ PNW_STOP_HOST(pnw);
/* Turn off VBUS */
otg_set_vbus(&iotg->otg, false);
penwell_otg_del_timer(TA_AIDL_BDIS_TMR);
penwell_otg_phy_low_power(0);
- if (iotg->stop_host)
- iotg->stop_host(iotg);
- else
- dev_dbg(pnw->dev,
- "host driver has been removed.\n");
+ PNW_STOP_HOST(pnw);
penwell_otg_phy_low_power(0);
hsm->b_bus_suspend = 0;
retval = -EBUSY;
goto err;
}
+ if (register_pm_notifier(&pnw_sleep_pm_notifier)) {
+ dev_dbg(pnw->dev, "Fail to register PM notifier\n");
+ retval = -EBUSY;
+ goto err;
+ }
#ifdef CONFIG_BOARD_CTP
/* Set up gpio for Clovertrail */
case OTG_STATE_A_SUSPEND:
penwell_otg_del_timer(TA_AIDL_BDIS_TMR);
penwell_otg_HABA(0);
- if (pnw->iotg.stop_host)
- pnw->iotg.stop_host(&pnw->iotg);
- else
- dev_dbg(pnw->dev, "host driver has been removed.\n");
+ PNW_STOP_HOST(pnw);
iotg->hsm.a_srp_det = 0;
penwell_otg_phy_vbus_wakeup(false);
/* Stop HNP polling */
iotg->stop_hnp_poll(iotg);
- if (pnw->iotg.stop_host)
- pnw->iotg.stop_host(&pnw->iotg);
- else
- dev_dbg(pnw->dev, "host driver has been stopped.\n");
+ PNW_STOP_HOST(pnw);
iotg->hsm.b_bus_req = 0;
iotg->otg.state = OTG_STATE_B_IDLE;
break;
penwell_otg_HAAR(0);
- if (pnw->iotg.stop_host)
- pnw->iotg.stop_host(&pnw->iotg);
- else
- dev_dbg(pnw->dev, "host driver has been stopped.\n");
+ PNW_STOP_HOST(pnw);
iotg->hsm.b_bus_req = 0;
iotg->otg.state = OTG_STATE_B_IDLE;
break;