Skip to content

Commit

Permalink
ufs: Add regulator enable support
Browse files Browse the repository at this point in the history
UFS devices are powered by at most three external power supplies -
- VCC - The flash memory core power supply, 2.7V to 3.6V or 1.70V to 1.95V
- VCCQ - The controller and I/O power supply, 1.1V to 1.3V
- VCCQ2 - Secondary controller and/or I/O power supply, 1.65V to 1.95V

For some devices VCCQ or VCCQ2 are optional as they can be
generated using internal LDO inside the UFS device.

Add DT bindings for voltage regulators that can be controlled
from host driver.

Signed-off-by: Sujit Reddy Thumma <sthumma@codeaurora.org>
Signed-off-by: Dolev Raviv <draviv@codeaurora.org>
Signed-off-by: Christoph Hellwig <hch@lst.de>
  • Loading branch information
Sujit Reddy Thumma authored and Christoph Hellwig committed Oct 1, 2014
1 parent 5c0c28a commit aa49761
Show file tree
Hide file tree
Showing 5 changed files with 342 additions and 3 deletions.
24 changes: 24 additions & 0 deletions Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,33 @@ Required properties:
- interrupts : <interrupt mapping for UFS host controller IRQ>
- reg : <registers mapping>

Optional properties:
- vcc-supply : phandle to VCC supply regulator node
- vccq-supply : phandle to VCCQ supply regulator node
- vccq2-supply : phandle to VCCQ2 supply regulator node
- vcc-supply-1p8 : For embedded UFS devices, valid VCC range is 1.7-1.95V
or 2.7-3.6V. This boolean property when set, specifies
to use low voltage range of 1.7-1.95V. Note for external
UFS cards this property is invalid and valid VCC range is
always 2.7-3.6V.
- 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

Note: If above properties are not defined it can be assumed that the supply
regulators are always on.

Example:
ufshc@0xfc598000 {
compatible = "jedec,ufs-1.1";
reg = <0xfc598000 0x800>;
interrupts = <0 28 0>;

vcc-supply = <&xxx_reg1>;
vcc-supply-1p8;
vccq-supply = <&xxx_reg2>;
vccq2-supply = <&xxx_reg3>;
vcc-max-microamp = 500000;
vccq-max-microamp = 200000;
vccq2-max-microamp = 200000;
};
25 changes: 25 additions & 0 deletions drivers/scsi/ufs/ufs.h
Original file line number Diff line number Diff line change
Expand Up @@ -362,4 +362,29 @@ struct ufs_query_res {
struct utp_upiu_query upiu_res;
};

#define UFS_VREG_VCC_MIN_UV 2700000 /* uV */
#define UFS_VREG_VCC_MAX_UV 3600000 /* uV */
#define UFS_VREG_VCC_1P8_MIN_UV 1700000 /* uV */
#define UFS_VREG_VCC_1P8_MAX_UV 1950000 /* uV */
#define UFS_VREG_VCCQ_MIN_UV 1100000 /* uV */
#define UFS_VREG_VCCQ_MAX_UV 1300000 /* uV */
#define UFS_VREG_VCCQ2_MIN_UV 1650000 /* uV */
#define UFS_VREG_VCCQ2_MAX_UV 1950000 /* uV */

struct ufs_vreg {
struct regulator *reg;
const char *name;
bool enabled;
int min_uV;
int max_uV;
int min_uA;
int max_uA;
};

struct ufs_vreg_info {
struct ufs_vreg *vcc;
struct ufs_vreg *vccq;
struct ufs_vreg *vccq2;
};

#endif /* End of Header */
100 changes: 100 additions & 0 deletions drivers/scsi/ufs/ufshcd-pltfrm.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,99 @@ static struct ufs_hba_variant_ops *get_variant_ops(struct device *dev)
return NULL;
}

#define MAX_PROP_SIZE 32
static int ufshcd_populate_vreg(struct device *dev, const char *name,
struct ufs_vreg **out_vreg)
{
int ret = 0;
char prop_name[MAX_PROP_SIZE];
struct ufs_vreg *vreg = NULL;
struct device_node *np = dev->of_node;

if (!np) {
dev_err(dev, "%s: non DT initialization\n", __func__);
goto out;
}

snprintf(prop_name, MAX_PROP_SIZE, "%s-supply", name);
if (!of_parse_phandle(np, prop_name, 0)) {
dev_info(dev, "%s: Unable to find %s regulator, assuming enabled\n",
__func__, prop_name);
goto out;
}

vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
if (!vreg) {
dev_err(dev, "No memory for %s regulator\n", name);
goto out;
}

vreg->name = kstrdup(name, GFP_KERNEL);

snprintf(prop_name, MAX_PROP_SIZE, "%s-max-microamp", name);
ret = of_property_read_u32(np, prop_name, &vreg->max_uA);
if (ret) {
dev_err(dev, "%s: unable to find %s err %d\n",
__func__, prop_name, ret);
goto out_free;
}

vreg->min_uA = 0;
if (!strcmp(name, "vcc")) {
if (of_property_read_bool(np, "vcc-supply-1p8")) {
vreg->min_uV = UFS_VREG_VCC_1P8_MIN_UV;
vreg->max_uV = UFS_VREG_VCC_1P8_MAX_UV;
} else {
vreg->min_uV = UFS_VREG_VCC_MIN_UV;
vreg->max_uV = UFS_VREG_VCC_MAX_UV;
}
} else if (!strcmp(name, "vccq")) {
vreg->min_uV = UFS_VREG_VCCQ_MIN_UV;
vreg->max_uV = UFS_VREG_VCCQ_MAX_UV;
} else if (!strcmp(name, "vccq2")) {
vreg->min_uV = UFS_VREG_VCCQ2_MIN_UV;
vreg->max_uV = UFS_VREG_VCCQ2_MAX_UV;
}

goto out;

out_free:
devm_kfree(dev, vreg);
vreg = NULL;
out:
if (!ret)
*out_vreg = vreg;
return ret;
}

/**
* ufshcd_parse_regulator_info - get regulator info from device tree
* @hba: per adapter instance
*
* Get regulator info from device tree for vcc, vccq, vccq2 power supplies.
* If any of the supplies are not defined it is assumed that they are always-on
* and hence return zero. If the property is defined but parsing is failed
* then return corresponding error.
*/
static int ufshcd_parse_regulator_info(struct ufs_hba *hba)
{
int err;
struct device *dev = hba->dev;
struct ufs_vreg_info *info = &hba->vreg_info;

err = ufshcd_populate_vreg(dev, "vcc", &info->vcc);
if (err)
goto out;

err = ufshcd_populate_vreg(dev, "vccq", &info->vccq);
if (err)
goto out;

err = ufshcd_populate_vreg(dev, "vccq2", &info->vccq2);
out:
return err;
}

#ifdef CONFIG_PM
/**
* ufshcd_pltfrm_suspend - suspend power management function
Expand Down Expand Up @@ -173,6 +266,13 @@ static int ufshcd_pltfrm_probe(struct platform_device *pdev)

hba->vops = get_variant_ops(&pdev->dev);

err = ufshcd_parse_regulator_info(hba);
if (err) {
dev_err(&pdev->dev, "%s: regulator init failed %d\n",
__func__, err);
goto out;
}

pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);

Expand Down
Loading

0 comments on commit aa49761

Please sign in to comment.