#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"
{
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);
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
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);
}
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");