From 6a771a656041f404fae143e5d753d37f5c0688e7 Mon Sep 17 00:00:00 2001 From: Raviv Shvili Date: Thu, 25 Sep 2014 15:32:24 +0300 Subject: [PATCH] ufs: add voting support for host controller power Add the support for voting of the regulator powering the host controller logic. Signed-off-by: Raviv Shvili Signed-off-by: Subhash Jadavani Signed-off-by: Dolev Raviv Signed-off-by: Christoph Hellwig --- .../devicetree/bindings/ufs/ufshcd-pltfrm.txt | 4 ++ drivers/scsi/ufs/ufs.h | 1 + drivers/scsi/ufs/ufshcd-pltfrm.c | 9 ++++ drivers/scsi/ufs/ufshcd.c | 42 ++++++++++++++++++- 4 files changed, 54 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt index b0f791a8b28d..fb1234e0532c 100644 --- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt +++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt @@ -9,6 +9,7 @@ Required properties: - reg : Optional properties: +- vdd-hba-supply : phandle to UFS host controller supply regulator node - vcc-supply : phandle to VCC supply regulator node - vccq-supply : phandle to VCCQ supply regulator node - vccq2-supply : phandle to VCCQ2 supply regulator node @@ -20,6 +21,7 @@ Optional properties: - vcc-max-microamp : specifies max. load that can be drawn from vcc supply - vccq-max-microamp : specifies max. load that can be drawn from vccq supply - vccq2-max-microamp : specifies max. load that can be drawn from vccq2 supply +- -fixed-regulator : boolean property specifying that -supply is a fixed regulator - clocks : List of phandle and clock specifier pairs - clock-names : List of clock input name strings sorted in the same @@ -39,6 +41,8 @@ Example: reg = <0xfc598000 0x800>; interrupts = <0 28 0>; + vdd-hba-supply = <&xxx_reg0>; + vdd-hba-fixed-regulator; vcc-supply = <&xxx_reg1>; vcc-supply-1p8; vccq-supply = <&xxx_reg2>; diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h index 729ce7d62d1e..9bb691962c47 100644 --- a/drivers/scsi/ufs/ufs.h +++ b/drivers/scsi/ufs/ufs.h @@ -385,6 +385,7 @@ struct ufs_vreg_info { struct ufs_vreg *vcc; struct ufs_vreg *vccq; struct ufs_vreg *vccq2; + struct ufs_vreg *vdd_hba; }; #endif /* End of Header */ diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c index 642d80fe1f80..dde4e6e3be70 100644 --- a/drivers/scsi/ufs/ufshcd-pltfrm.c +++ b/drivers/scsi/ufs/ufshcd-pltfrm.c @@ -147,6 +147,11 @@ static int ufshcd_populate_vreg(struct device *dev, const char *name, vreg->name = kstrdup(name, GFP_KERNEL); + /* if fixed regulator no need further initialization */ + snprintf(prop_name, MAX_PROP_SIZE, "%s-fixed-regulator", name); + if (of_property_read_bool(np, prop_name)) + goto out; + snprintf(prop_name, MAX_PROP_SIZE, "%s-max-microamp", name); ret = of_property_read_u32(np, prop_name, &vreg->max_uA); if (ret) { @@ -198,6 +203,10 @@ static int ufshcd_parse_regulator_info(struct ufs_hba *hba) struct device *dev = hba->dev; struct ufs_vreg_info *info = &hba->vreg_info; + err = ufshcd_populate_vreg(dev, "vdd-hba", &info->vdd_hba); + if (err) + goto out; + err = ufshcd_populate_vreg(dev, "vcc", &info->vcc); if (err) goto out; diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index b03370292070..26301b8325e8 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -3311,6 +3311,16 @@ out: return ret; } +static int ufshcd_setup_hba_vreg(struct ufs_hba *hba, bool on) +{ + struct ufs_vreg_info *info = &hba->vreg_info; + + if (info) + return ufshcd_toggle_vreg(hba->dev, info->vdd_hba, on); + + return 0; +} + static int ufshcd_get_vreg(struct device *dev, struct ufs_vreg *vreg) { int ret = 0; @@ -3350,6 +3360,16 @@ out: return ret; } +static int ufshcd_init_hba_vreg(struct ufs_hba *hba) +{ + struct ufs_vreg_info *info = &hba->vreg_info; + + if (info) + return ufshcd_get_vreg(hba->dev, info->vdd_hba); + + return 0; +} + static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on) { int ret = 0; @@ -3483,14 +3503,29 @@ static int ufshcd_hba_init(struct ufs_hba *hba) { int err; - err = ufshcd_init_clocks(hba); + /* + * Handle host controller power separately from the UFS device power + * rails as it will help controlling the UFS host controller power + * collapse easily which is different than UFS device power collapse. + * Also, enable the host controller power before we go ahead with rest + * of the initialization here. + */ + err = ufshcd_init_hba_vreg(hba); if (err) goto out; - err = ufshcd_setup_clocks(hba, true); + err = ufshcd_setup_hba_vreg(hba, true); if (err) goto out; + err = ufshcd_init_clocks(hba); + if (err) + goto out_disable_hba_vreg; + + err = ufshcd_setup_clocks(hba, true); + if (err) + goto out_disable_hba_vreg; + err = ufshcd_init_vreg(hba); if (err) goto out_disable_clks; @@ -3509,6 +3544,8 @@ out_disable_vreg: ufshcd_setup_vreg(hba, false); out_disable_clks: ufshcd_setup_clocks(hba, false); +out_disable_hba_vreg: + ufshcd_setup_hba_vreg(hba, false); out: return err; } @@ -3518,6 +3555,7 @@ static void ufshcd_hba_exit(struct ufs_hba *hba) ufshcd_variant_hba_exit(hba); ufshcd_setup_vreg(hba, false); ufshcd_setup_clocks(hba, false); + ufshcd_setup_hba_vreg(hba, false); } /** -- 2.20.1