[RAMEN9610-14207][COMMON] scsi: ufs: UFS power recovery when probe fail.
[GitHub/MotorolaMobilityLLC/kernel-slsi.git] / drivers / scsi / ufs / ufshcd-pltfrm.c
index e82bde0772963cbbde59a52712984f56921d39d9..17b32bc5219289627f7637b1fb5f42240d67b256 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/of.h>
+#include <linux/of_gpio.h>
 
 #include "ufshcd.h"
 #include "ufshcd-pltfrm.h"
@@ -202,6 +203,7 @@ static int ufshcd_parse_regulator_info(struct ufs_hba *hba)
 {
        int err;
        struct device *dev = hba->dev;
+       struct device_node *np = dev->of_node;
        struct ufs_vreg_info *info = &hba->vreg_info;
 
        err = ufshcd_populate_vreg(dev, "vdd-hba", &info->vdd_hba);
@@ -217,10 +219,65 @@ static int ufshcd_parse_regulator_info(struct ufs_hba *hba)
                goto out;
 
        err = ufshcd_populate_vreg(dev, "vccq2", &info->vccq2);
+       if (err)
+               goto out;
+
+       if (of_get_property(np, "ufs-power-gpio", NULL))
+               info->ufs_power_gpio = of_get_named_gpio(np, "ufs-power-gpio", 0);
+
+       if (of_get_property(np, "ufs-reset-n-gpio", NULL))
+               info->ufs_reset_n_gpio = of_get_named_gpio(np, "ufs-reset-n-gpio", 0);
 out:
        return err;
 }
 
+static int ufshcd_parse_pm_lvl_policy(struct ufs_hba *hba)
+{
+       struct device *dev = hba->dev;
+       struct device_node *np = dev->of_node;
+       u32 lvl_def[] = {UFS_PM_LVL_2, UFS_PM_LVL_5};
+       u32 lvl[2] = {0,}, i;
+
+       for (i = 0; i < ARRAY_SIZE(lvl); i++) {
+               if (of_property_read_u32_index(np, "pm_lvl_states", i, lvl +i)) {
+                       dev_info(hba->dev,
+                               "UFS power management: set default level%d index %d\n",
+                               lvl_def[i], i);
+                       lvl[i] = lvl_def[i];
+               }
+
+               if (lvl[i] >= UFS_PM_LVL_MAX) {
+                       dev_warn(hba->dev,
+                               "UFS power management: out of range level%d index %d\n",
+                               lvl[i], i);
+                       lvl[i] =  lvl_def[i];
+               }
+       }
+
+       hba->rpm_lvl = lvl[0];
+       hba->spm_lvl = lvl[1];
+
+       return 0;
+}
+static int ufshcd_parse_caps_info(struct ufs_hba *hba)
+{
+       struct device *dev = hba->dev;
+       struct device_node *np = dev->of_node;
+
+       if (of_find_property(np, "ufs-cap-clk-gating", NULL))
+               hba->caps |= UFSHCD_CAP_CLK_GATING;
+       if (of_find_property(np, "ufs-cap-hibern8-with-clk-gating", NULL))
+               hba->caps |= UFSHCD_CAP_HIBERN8_WITH_CLK_GATING;
+       if (of_find_property(np, "ufs-cap-clk-scaling", NULL))
+               hba->caps |= UFSHCD_CAP_CLK_SCALING;
+       if (of_find_property(np, "ufs-cap-auto-bkops-suspend", NULL))
+               hba->caps |= UFSHCD_CAP_AUTO_BKOPS_SUSPEND;
+       if (of_find_property(np, "ufs-cap-fake-clk-gating", NULL))
+               hba->caps |= UFSHCD_CAP_FAKE_CLK_GATING;
+
+       return 0;
+}
+
 #ifdef CONFIG_PM
 /**
  * ufshcd_pltfrm_suspend - suspend power management function
@@ -340,6 +397,8 @@ int ufshcd_pltfrm_init(struct platform_device *pdev,
                goto dealloc_host;
        }
 
+       ufshcd_parse_pm_lvl_policy(hba);
+       ufshcd_parse_caps_info(hba);
        pm_runtime_set_active(&pdev->dev);
        pm_runtime_enable(&pdev->dev);
 
@@ -365,6 +424,20 @@ out:
 }
 EXPORT_SYMBOL_GPL(ufshcd_pltfrm_init);
 
+/**
+ * ufshcd_pltfrm_exit - exit common routine for platform driver
+ * @pdev: pointer to platform device handle
+ */
+void ufshcd_pltfrm_exit(struct platform_device *pdev)
+{
+       struct ufs_hba *hba =  platform_get_drvdata(pdev);
+
+       disable_irq(hba->irq);
+
+       ufshcd_remove(hba);
+}
+EXPORT_SYMBOL_GPL(ufshcd_pltfrm_exit);
+
 MODULE_AUTHOR("Santosh Yaragnavi <santosh.sy@samsung.com>");
 MODULE_AUTHOR("Vinayak Holikatti <h.vinayak@samsung.com>");
 MODULE_DESCRIPTION("UFS host controller Platform bus based glue driver");