From: Bjorn Andersson <bjorn.andersson@linaro.org>
To: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
Cc: linux-arm-msm@vger.kernel.org, agross@kernel.org,
lgirdwood@gmail.com, broonie@kernel.org, robh+dt@kernel.org,
sumit.semwal@linaro.org, linux-kernel@vger.kernel.org,
devicetree@vger.kernel.org, phone-devel@vger.kernel.org,
konrad.dybcio@somainline.org, marijn.suijten@somainline.org,
martin.botka@somainline.org
Subject: Re: [PATCH v2 2/7] regulator: qcom-labibb: Implement current limiting
Date: Thu, 14 Jan 2021 22:37:42 -0600 [thread overview]
Message-ID: <YAEcFhFFsYIumI2e@builder.lan> (raw)
In-Reply-To: <20210113194214.522238-3-angelogioacchino.delregno@somainline.org>
On Wed 13 Jan 13:42 CST 2021, AngeloGioacchino Del Regno wrote:
> LAB and IBB regulators can be current-limited by setting the
> appropriate registers, but this operation is granted only after
> sending an unlock code for secure access.
>
> Besides the secure access, it would be possible to use the
> regmap helper for get_current_limit, as there is no security
> blocking reads, but I chose not to as to avoid having a very
> big array containing current limits, especially for IBB.
>
> That said, these regulators support current limiting for:
> - LAB (pos): 200-1600mA, with 200mA per step (8 steps),
> - IBB (neg): 0-1550mA, with 50mA per step (32 steps).
>
> Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
> ---
> drivers/regulator/qcom-labibb-regulator.c | 92 +++++++++++++++++++++++
> 1 file changed, 92 insertions(+)
>
> diff --git a/drivers/regulator/qcom-labibb-regulator.c b/drivers/regulator/qcom-labibb-regulator.c
> index 9f51c96f16fb..d364f54ad294 100644
> --- a/drivers/regulator/qcom-labibb-regulator.c
> +++ b/drivers/regulator/qcom-labibb-regulator.c
> @@ -29,6 +29,15 @@
> #define LABIBB_STATUS1_VREG_OK_BIT BIT(7)
> #define LABIBB_CONTROL_ENABLE BIT(7)
>
> +#define REG_LABIBB_CURRENT_LIMIT 0x4b
> + #define LAB_CURRENT_LIMIT_MASK GENMASK(2, 0)
> + #define IBB_CURRENT_LIMIT_MASK GENMASK(4, 0)
> + #define LAB_CURRENT_LIMIT_OVERRIDE_EN BIT(3)
> + #define LABIBB_CURRENT_LIMIT_EN BIT(7)
> +
> +#define REG_LABIBB_SEC_ACCESS 0xd0
> + #define LABIBB_SEC_UNLOCK_CODE 0xa5
> +
> #define LAB_ENABLE_CTL_MASK BIT(7)
> #define IBB_ENABLE_CTL_MASK (BIT(7) | BIT(6))
>
> @@ -37,11 +46,18 @@
> #define IBB_ENABLE_TIME (LABIBB_OFF_ON_DELAY * 10)
> #define LABIBB_POLL_ENABLED_TIME 1000
>
> +struct labibb_current_limits {
> + u32 uA_min;
> + u32 uA_step;
> + u8 ovr_val;
> +};
> +
> struct labibb_regulator {
> struct regulator_desc desc;
> struct device *dev;
> struct regmap *regmap;
> struct regulator_dev *rdev;
> + struct labibb_current_limits uA_limits;
> u16 base;
> u8 type;
> };
> @@ -53,6 +69,57 @@ struct labibb_regulator_data {
> const struct regulator_desc *desc;
> };
>
> +static int qcom_labibb_set_current_limit(struct regulator_dev *rdev,
> + int min_uA, int max_uA)
I was under the impression that a regulator driver should either
implement set_voltage_* or set_current_limit, depending on which type of
regulator it is - i.e. this API isn't supposed to be setting the current
limit. Perhaps I'm wrong though?
> +{
> + struct labibb_regulator *vreg = rdev_get_drvdata(rdev);
> + struct regulator_desc *desc = &vreg->desc;
> + struct labibb_current_limits *lim = &vreg->uA_limits;
> + u32 mask, val;
> + int i, ret, sel = -1;
> +
> + if (min_uA < lim->uA_min || max_uA < lim->uA_min)
> + return -EINVAL;
> +
> + for (i = 0; i < desc->n_current_limits; i++) {
> + int uA_limit = (lim->uA_step * i) + lim->uA_min;
> +
> + if (max_uA >= uA_limit && min_uA <= uA_limit)
I presume here you rely on the client passing something like min_uA = 0
and max_uA 500? Because if the client where to
regulator_set_current_limit(475, 475) you will pass through this loop
without finding a match, but 450 would probably be a really good
pick...
But what does it even mean to pass min/max uA for a current limit?
That said, I think this loop would be better expressed as a single
subtract uA_min and then divide by uA_step.
Apart from that, this patch looks good to me.
Regards,
Bjorn
> + sel = i;
> + }
> + if (sel < 0)
> + return -EINVAL;
> +
> + /* Current limit setting needs secure access */
> + ret = regmap_write(vreg->regmap, vreg->base + REG_LABIBB_SEC_ACCESS,
> + LABIBB_SEC_UNLOCK_CODE);
> + if (ret)
> + return ret;
> +
> + mask = desc->csel_mask | lim->ovr_val;
> + mask |= LABIBB_CURRENT_LIMIT_EN;
> + val = (u32)sel | lim->ovr_val;
> + val |= LABIBB_CURRENT_LIMIT_EN;
> +
> + return regmap_update_bits(vreg->regmap, desc->csel_reg, mask, val);
> +}
> +
> +static int qcom_labibb_get_current_limit(struct regulator_dev *rdev)
> +{
> + struct labibb_regulator *vreg = rdev_get_drvdata(rdev);
> + struct regulator_desc *desc = &vreg->desc;
> + struct labibb_current_limits *lim = &vreg->uA_limits;
> + unsigned int cur_step;
> + int ret;
> +
> + ret = regmap_read(vreg->regmap, desc->csel_reg, &cur_step);
> + if (ret)
> + return ret;
> + cur_step &= desc->csel_mask;
> +
> + return (cur_step * lim->uA_step) + lim->uA_min;
> +}
> +
> static const struct regulator_ops qcom_labibb_ops = {
> .enable = regulator_enable_regmap,
> .disable = regulator_disable_regmap,
> @@ -61,6 +128,8 @@ static const struct regulator_ops qcom_labibb_ops = {
> .get_voltage_sel = regulator_get_voltage_sel_regmap,
> .list_voltage = regulator_list_voltage_linear_range,
> .map_voltage = regulator_map_voltage_linear_range,
> + .set_current_limit = qcom_labibb_set_current_limit,
> + .get_current_limit = qcom_labibb_get_current_limit,
> };
>
> static const struct regulator_desc pmi8998_lab_desc = {
> @@ -73,6 +142,9 @@ static const struct regulator_desc pmi8998_lab_desc = {
> .vsel_mask = LAB_VOLTAGE_SET_MASK,
> .apply_reg = (PMI8998_LAB_REG_BASE + REG_LABIBB_VOLTAGE),
> .apply_bit = LABIBB_VOLTAGE_OVERRIDE_EN,
> + .csel_reg = (PMI8998_LAB_REG_BASE + REG_LABIBB_CURRENT_LIMIT),
> + .csel_mask = LAB_CURRENT_LIMIT_MASK,
> + .n_current_limits = 8,
> .off_on_delay = LABIBB_OFF_ON_DELAY,
> .owner = THIS_MODULE,
> .type = REGULATOR_VOLTAGE,
> @@ -94,6 +166,9 @@ static const struct regulator_desc pmi8998_ibb_desc = {
> .vsel_mask = IBB_VOLTAGE_SET_MASK,
> .apply_reg = (PMI8998_IBB_REG_BASE + REG_LABIBB_VOLTAGE),
> .apply_bit = LABIBB_VOLTAGE_OVERRIDE_EN,
> + .csel_reg = (PMI8998_IBB_REG_BASE + REG_LABIBB_CURRENT_LIMIT),
> + .csel_mask = IBB_CURRENT_LIMIT_MASK,
> + .n_current_limits = 32,
> .off_on_delay = LABIBB_OFF_ON_DELAY,
> .owner = THIS_MODULE,
> .type = REGULATOR_VOLTAGE,
> @@ -167,6 +242,23 @@ static int qcom_labibb_regulator_probe(struct platform_device *pdev)
> vreg->base = reg_data->base;
> vreg->type = reg_data->type;
>
> + switch (vreg->type) {
> + case QCOM_LAB_TYPE:
> + /* LAB Limits: 200-1600mA */
> + vreg->uA_limits.uA_min = 200000;
> + vreg->uA_limits.uA_step = 200000;
> + vreg->uA_limits.ovr_val = LAB_CURRENT_LIMIT_OVERRIDE_EN;
> + break;
> + case QCOM_IBB_TYPE:
> + /* IBB Limits: 0-1550mA */
> + vreg->uA_limits.uA_min = 0;
> + vreg->uA_limits.uA_step = 50000;
> + vreg->uA_limits.ovr_val = 0; /* No override bit */
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> memcpy(&vreg->desc, reg_data->desc, sizeof(vreg->desc));
> vreg->desc.of_match = reg_data->name;
> vreg->desc.name = reg_data->name;
> --
> 2.29.2
>
next prev parent reply other threads:[~2021-01-15 4:38 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-01-13 19:42 [PATCH v2 0/7] Really implement Qualcomm LAB/IBB regulators AngeloGioacchino Del Regno
2021-01-13 19:42 ` [PATCH v2 1/7] regulator: qcom-labibb: Implement voltage selector ops AngeloGioacchino Del Regno
2021-01-15 4:40 ` Bjorn Andersson
2021-01-13 19:42 ` [PATCH v2 2/7] regulator: qcom-labibb: Implement current limiting AngeloGioacchino Del Regno
2021-01-15 4:37 ` Bjorn Andersson [this message]
2021-01-17 18:13 ` AngeloGioacchino Del Regno
2021-01-13 19:42 ` [PATCH v2 3/7] regulator: qcom-labibb: Implement pull-down, softstart, active discharge AngeloGioacchino Del Regno
2021-01-15 4:53 ` Bjorn Andersson
2021-01-17 18:15 ` AngeloGioacchino Del Regno
2021-01-13 19:42 ` [PATCH v2 4/7] dt-bindings: regulator: qcom-labibb: Document soft start properties AngeloGioacchino Del Regno
2021-01-15 4:54 ` Bjorn Andersson
2021-01-13 19:42 ` [PATCH v2 5/7] regulator: qcom-labibb: Implement short-circuit and over-current IRQs AngeloGioacchino Del Regno
2021-01-15 5:31 ` Bjorn Andersson
2021-01-17 19:06 ` AngeloGioacchino Del Regno
2021-01-13 19:42 ` [PATCH v2 6/7] dt-bindings: regulator: qcom-labibb: Document SCP/OCP interrupts AngeloGioacchino Del Regno
2021-01-15 5:35 ` Bjorn Andersson
2021-01-13 19:42 ` [PATCH v2 7/7] arm64: dts: pmi8998: Add the right interrupts for LAB/IBB SCP and OCP AngeloGioacchino Del Regno
2021-01-15 5:37 ` Bjorn Andersson
2021-01-15 18:19 ` (subset) [PATCH v2 0/7] Really implement Qualcomm LAB/IBB regulators Mark Brown
2021-01-15 19:15 ` AngeloGioacchino Del Regno
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=YAEcFhFFsYIumI2e@builder.lan \
--to=bjorn.andersson@linaro.org \
--cc=agross@kernel.org \
--cc=angelogioacchino.delregno@somainline.org \
--cc=broonie@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=konrad.dybcio@somainline.org \
--cc=lgirdwood@gmail.com \
--cc=linux-arm-msm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=marijn.suijten@somainline.org \
--cc=martin.botka@somainline.org \
--cc=phone-devel@vger.kernel.org \
--cc=robh+dt@kernel.org \
--cc=sumit.semwal@linaro.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.