summaryrefslogtreecommitdiff
path: root/drivers/scsi/ufs/ufshcd-pltfrm.c
diff options
context:
space:
mode:
authorSubhash Jadavani <subhashj@codeaurora.org>2014-09-25 15:32:30 +0300
committerChristoph Hellwig <hch@lst.de>2014-10-01 13:11:23 +0200
commit57d104c153d3d6d7bea60089e80f37501851ed2c (patch)
tree551826a9cb50cd5284595edb939ae18206ef30c6 /drivers/scsi/ufs/ufshcd-pltfrm.c
parent0ce147d48a3e3352859f0c185e98e8392bee7a25 (diff)
ufs: add UFS power management support
This patch adds support for UFS device and UniPro link power management during runtime/system PM. Main idea is to define multiple UFS low power levels based on UFS device and UFS link power states. This would allow any specific platform or pci driver to choose the best suited low power level during runtime and system suspend based on their power goals. bkops handlig: To put the UFS device in sleep state when bkops is disabled, first query the bkops status from the device and enable bkops on device only if device needs time to perform the bkops. START_STOP handling: Before sending START_STOP_UNIT to the device well-known logical unit (w-lun) to make sure that the device w-lun unit attention condition is cleared. Write protection: UFS device specification allows LUs to be write protected, either permanently or power on write protected. If any LU is power on write protected and if the card is power cycled (by powering off VCCQ and/or VCC rails), LU's write protect status would be lost. So this means those LUs can be written now. To ensures that UFS device is power cycled only if the power on protect is not set for any of the LUs, check if power on write protect is set and if device is in sleep/power-off state & link in inactive state (Hibern8 or OFF state). If none of the Logical Units on UFS device is power on write protected then all UFS device power rails (VCC, VCCQ & VCCQ2) can be turned off if UFS device is in power-off state and UFS link is in OFF state. But current implementation would disable all device power rails even if UFS link is not in OFF state. Low power mode: If UFS link is in OFF state then UFS host controller can be power collapsed to avoid leakage current from it. Note that if UFS host controller is power collapsed, full UFS reinitialization will be required on resume to re-establish the link between host and device. Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org> Signed-off-by: Dolev Raviv <draviv@codeaurora.org> Signed-off-by: Sujit Reddy Thumma <sthumma@codeaurora.org> Signed-off-by: Christoph Hellwig <hch@lst.de>
Diffstat (limited to 'drivers/scsi/ufs/ufshcd-pltfrm.c')
-rw-r--r--drivers/scsi/ufs/ufshcd-pltfrm.c60
1 files changed, 15 insertions, 45 deletions
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index dde4e6e3be70..2482bbac3681 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -225,45 +225,24 @@ out:
* ufshcd_pltfrm_suspend - suspend power management function
* @dev: pointer to device handle
*
- *
- * Returns 0
+ * Returns 0 if successful
+ * Returns non-zero otherwise
*/
static int ufshcd_pltfrm_suspend(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct ufs_hba *hba = platform_get_drvdata(pdev);
-
- /*
- * TODO:
- * 1. Call ufshcd_suspend
- * 2. Do bus specific power management
- */
-
- disable_irq(hba->irq);
-
- return 0;
+ return ufshcd_system_suspend(dev_get_drvdata(dev));
}
/**
* ufshcd_pltfrm_resume - resume power management function
* @dev: pointer to device handle
*
- * Returns 0
+ * Returns 0 if successful
+ * Returns non-zero otherwise
*/
static int ufshcd_pltfrm_resume(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct ufs_hba *hba = platform_get_drvdata(pdev);
-
- /*
- * TODO:
- * 1. Call ufshcd_resume.
- * 2. Do bus specific wake up
- */
-
- enable_irq(hba->irq);
-
- return 0;
+ return ufshcd_system_resume(dev_get_drvdata(dev));
}
#else
#define ufshcd_pltfrm_suspend NULL
@@ -273,30 +252,15 @@ static int ufshcd_pltfrm_resume(struct device *dev)
#ifdef CONFIG_PM_RUNTIME
static int ufshcd_pltfrm_runtime_suspend(struct device *dev)
{
- struct ufs_hba *hba = dev_get_drvdata(dev);
-
- if (!hba)
- return 0;
-
- return ufshcd_runtime_suspend(hba);
+ return ufshcd_runtime_suspend(dev_get_drvdata(dev));
}
static int ufshcd_pltfrm_runtime_resume(struct device *dev)
{
- struct ufs_hba *hba = dev_get_drvdata(dev);
-
- if (!hba)
- return 0;
-
- return ufshcd_runtime_resume(hba);
+ return ufshcd_runtime_resume(dev_get_drvdata(dev));
}
static int ufshcd_pltfrm_runtime_idle(struct device *dev)
{
- struct ufs_hba *hba = dev_get_drvdata(dev);
-
- if (!hba)
- return 0;
-
- return ufshcd_runtime_idle(hba);
+ return ufshcd_runtime_idle(dev_get_drvdata(dev));
}
#else /* !CONFIG_PM_RUNTIME */
#define ufshcd_pltfrm_runtime_suspend NULL
@@ -304,6 +268,11 @@ static int ufshcd_pltfrm_runtime_idle(struct device *dev)
#define ufshcd_pltfrm_runtime_idle NULL
#endif /* CONFIG_PM_RUNTIME */
+static void ufshcd_pltfrm_shutdown(struct platform_device *pdev)
+{
+ ufshcd_shutdown((struct ufs_hba *)platform_get_drvdata(pdev));
+}
+
/**
* ufshcd_pltfrm_probe - probe routine of the driver
* @pdev: pointer to Platform device handle
@@ -404,6 +373,7 @@ static const struct dev_pm_ops ufshcd_dev_pm_ops = {
static struct platform_driver ufshcd_pltfrm_driver = {
.probe = ufshcd_pltfrm_probe,
.remove = ufshcd_pltfrm_remove,
+ .shutdown = ufshcd_pltfrm_shutdown,
.driver = {
.name = "ufshcd",
.owner = THIS_MODULE,