From: Hao Wu Date: Thu, 25 Aug 2011 11:20:35 +0000 (+0100) Subject: usb: penwell_otg: add runtime pm support X-Git-Tag: 2.1b_release~2096 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=4fecc95fde1e5a4cc59795271d990485c4bf7c3e;p=kernel%2Fkernel-mfld-blackbay.git usb: penwell_otg: add runtime pm support Add runtime pm support in penwell_otg transceiver driver. Change-Id: I30f9bbb33efb3a0a6d8e313c6dd6dfefe656c3a8 Signed-off-by: Hao Wu Signed-off-by: Dirk Brandewie --- diff --git a/drivers/usb/otg/penwell_otg.c b/drivers/usb/otg/penwell_otg.c index 71edaf4..890dcc7 100644 --- a/drivers/usb/otg/penwell_otg.c +++ b/drivers/usb/otg/penwell_otg.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include "../core/usb.h" @@ -63,27 +64,6 @@ static int penwell_otg_set_peripheral(struct otg_transceiver *otg, static int penwell_otg_start_srp(struct otg_transceiver *otg); static int penwell_otg_msic_write(u16 addr, u8 data); -static const struct pci_device_id pci_ids[] = {{ - .class = ((PCI_CLASS_SERIAL_USB << 8) | 0x20), - .class_mask = ~0, - .vendor = 0x8086, - .device = 0x0829, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, -}, { /* end: all zeroes */ } -}; - -static struct pci_driver otg_pci_driver = { - .name = (char *) driver_name, - .id_table = pci_ids, - - .probe = penwell_otg_probe, - .remove = penwell_otg_remove, - - .suspend = penwell_otg_suspend, - .resume = penwell_otg_resume, -}; - static const char *state_string(enum usb_otg_state state) { switch (state) { @@ -1103,6 +1083,9 @@ static irqreturn_t otg_irq(int irq, void *_dev) int_en = (int_sts & OTGSC_INTEN_MASK) >> 8; int_mask = int_sts & int_en; + if (int_mask == 0) + return IRQ_NONE; + if (int_mask) { dev_dbg(pnw->dev, "OTGSC = 0x%x, mask =0x%x\n", int_sts, int_mask); @@ -1309,6 +1292,8 @@ static void penwell_otg_work(struct work_struct *work) dev_dbg(pnw->dev, "old state = %s\n", state_string(iotg->otg.state)); + pm_runtime_get_sync(pnw->dev); + switch (iotg->otg.state) { case OTG_STATE_UNDEFINED: case OTG_STATE_B_IDLE: @@ -2139,6 +2124,8 @@ static void penwell_otg_work(struct work_struct *work) ; } + pm_runtime_put_sync(pnw->dev); + dev_dbg(pnw->dev, "new state = %s\n", state_string(iotg->otg.state)); } @@ -2870,6 +2857,153 @@ error: return ret; } +#ifdef CONFIG_PM_RUNTIME +/* Runtime PM */ +static int penwell_otg_runtime_suspend(struct device *dev) +{ + struct penwell_otg *pnw = the_transceiver; + struct pci_dev *pdev; + int ret = 0; + + dev_dbg(dev, "%s --->\n", __func__); + + pdev = to_pci_dev(dev); + + switch (pnw->iotg.otg.state) { + case OTG_STATE_A_IDLE: + case OTG_STATE_B_IDLE: + /* Transceiver handle it itself */ + penwell_otg_phy_low_power(1); + pci_save_state(pdev); + pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D3hot); + break; + case OTG_STATE_A_WAIT_BCON: + case OTG_STATE_A_HOST: + case OTG_STATE_A_SUSPEND: + if (pnw->iotg.runtime_suspend_host) + ret = pnw->iotg.runtime_suspend_host(&pnw->iotg); + break; + case OTG_STATE_A_PERIPHERAL: + case OTG_STATE_B_PERIPHERAL: + if (pnw->iotg.runtime_suspend_peripheral) + ret = pnw->iotg.runtime_suspend_peripheral(&pnw->iotg); + break; + default: + break; + } + + dev_dbg(dev, "%s <---\n", __func__); + return ret; +} + +static int penwell_otg_runtime_resume(struct device *dev) +{ + struct penwell_otg *pnw = the_transceiver; + struct pci_dev *pdev; + int ret = 0; + + dev_dbg(dev, "%s --->\n", __func__); + + pdev = to_pci_dev(dev); + + penwell_otg_intr(1); + penwell_otg_phy_low_power(0); + + switch (pnw->iotg.otg.state) { + case OTG_STATE_A_IDLE: + case OTG_STATE_B_IDLE: + /* Transceiver handle it itself */ + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + ret = pci_enable_device(pdev); + if (ret) + dev_err(&pdev->dev, "device cant be enabled\n"); + penwell_otg_phy_low_power(0); + break; + case OTG_STATE_A_WAIT_BCON: + case OTG_STATE_A_HOST: + case OTG_STATE_A_SUSPEND: + if (pnw->iotg.runtime_resume_host) + ret = pnw->iotg.runtime_resume_host(&pnw->iotg); + break; + case OTG_STATE_A_PERIPHERAL: + case OTG_STATE_B_PERIPHERAL: + if (pnw->iotg.runtime_resume_peripheral) + ret = pnw->iotg.runtime_resume_peripheral(&pnw->iotg); + break; + default: + break; + } + + dev_dbg(dev, "%s <---\n", __func__); + return 0; +} + +static int penwell_otg_runtime_idle(struct device *dev) +{ + struct penwell_otg *pnw = the_transceiver; + + dev_dbg(dev, "%s --->\n", __func__); + + switch (pnw->iotg.otg.state) { + case OTG_STATE_A_WAIT_VRISE: + case OTG_STATE_A_WAIT_VFALL: + case OTG_STATE_A_VBUS_ERR: + case OTG_STATE_B_WAIT_ACON: + case OTG_STATE_B_HOST: + dev_dbg(dev, "Keep in active\n"); + return -EBUSY; + default: + break; + } + + dev_dbg(dev, "%s <---\n", __func__); + + return 0; +} + +#else + +#define penwell_otg_runtime_suspend NULL +#define penwell_otg_runtime_resume NULL +#define penwell_otg_runtime_idle NULL + +#endif + +/*----------------------------------------------------------*/ + +static const struct pci_device_id pci_ids[] = {{ + .class = ((PCI_CLASS_SERIAL_USB << 8) | 0x20), + .class_mask = ~0, + .vendor = 0x8086, + .device = 0x0829, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, +}, { /* end: all zeroes */ } +}; + +static const struct dev_pm_ops penwell_otg_pm_ops = { + .runtime_suspend = penwell_otg_runtime_suspend, + .runtime_resume = penwell_otg_runtime_resume, + .runtime_idle = penwell_otg_runtime_idle, +}; + +static struct pci_driver otg_pci_driver = { + .name = (char *) driver_name, + .id_table = pci_ids, + + .probe = penwell_otg_probe, + .remove = penwell_otg_remove, + + .suspend = penwell_otg_suspend, + .resume = penwell_otg_resume, + + .driver = { + .pm = &penwell_otg_pm_ops + }, +}; + static int __init penwell_otg_init(void) { return pci_register_driver(&otg_pci_driver); diff --git a/include/linux/usb/intel_mid_otg.h b/include/linux/usb/intel_mid_otg.h index c9ec416..62db841 100644 --- a/include/linux/usb/intel_mid_otg.h +++ b/include/linux/usb/intel_mid_otg.h @@ -143,6 +143,13 @@ struct intel_mid_otg_xceiv { int (*suspend_peripheral)(struct intel_mid_otg_xceiv *iotg, pm_message_t message); int (*resume_peripheral)(struct intel_mid_otg_xceiv *iotg); + + /* runtime suspend/resume */ + int (*runtime_suspend_host)(struct intel_mid_otg_xceiv *iotg); + int (*runtime_resume_host)(struct intel_mid_otg_xceiv *iotg); + int (*runtime_suspend_peripheral)(struct intel_mid_otg_xceiv *iotg); + int (*runtime_resume_peripheral)(struct intel_mid_otg_xceiv *iotg); + #endif };