2022-05-04 17:15:37

by Zev Weiss

[permalink] [raw]
Subject: [PATCH 1/6] dt-bindings: regulator: Add regulator-external-output property

Some regulators do not provide power to anything within the system
described by a device tree, and simply supply an external output. The
regulator-external-output property can now be used to mark such
regulators.

Signed-off-by: Zev Weiss <[email protected]>
---
Documentation/devicetree/bindings/regulator/regulator.yaml | 6 ++++++
1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/regulator/regulator.yaml b/Documentation/devicetree/bindings/regulator/regulator.yaml
index a9b66ececccf..0e418e68b0e6 100644
--- a/Documentation/devicetree/bindings/regulator/regulator.yaml
+++ b/Documentation/devicetree/bindings/regulator/regulator.yaml
@@ -226,6 +226,12 @@ properties:
description: Maximum difference between current and target voltages
that can be changed safely in a single step.

+ regulator-external-output:
+ description: The regulator's output is external to the system
+ described by the device-tree; no devices within the system are
+ downstream of it.
+ type: boolean
+
patternProperties:
".*-supply$":
description: Input supply phandle(s) for this node
--
2.36.0



2022-05-04 17:33:58

by Zev Weiss

[permalink] [raw]
Subject: [PATCH 4/6] regulator: core: Add external-output support

Regulators feeding external outputs (i.e. supplying devices we don't
control) can be switched on and off by userspace via the 'state' sysfs
attribute, which is now (conditionally) writable. They are also not
automatically disabled in regulator_late_cleanup(), since we have no
way of knowing that they're not actually in use.

Signed-off-by: Zev Weiss <[email protected]>
---
.../ABI/testing/sysfs-class-regulator | 4 ++
drivers/regulator/core.c | 41 ++++++++++++++++---
drivers/regulator/of_regulator.c | 2 +
include/linux/regulator/machine.h | 1 +
4 files changed, 43 insertions(+), 5 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-class-regulator b/Documentation/ABI/testing/sysfs-class-regulator
index 475b9a372657..1c0451730df2 100644
--- a/Documentation/ABI/testing/sysfs-class-regulator
+++ b/Documentation/ABI/testing/sysfs-class-regulator
@@ -23,6 +23,10 @@ Description:
'unknown' means software cannot determine the state, or
the reported state is invalid.

+ For regulators supplying external outputs, 'enabled'
+ or 'disabled' can be written to this file to turn the
+ regulator on and off.
+
NOTE: this field can be used in conjunction with microvolts
or microamps to determine configured regulator output levels.

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 9094bd8772e5..b7617926336f 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -83,6 +83,8 @@ struct regulator_supply_alias {

static int _regulator_is_enabled(struct regulator_dev *rdev);
static int _regulator_disable(struct regulator *regulator);
+static int _regulator_do_enable(struct regulator_dev *rdev);
+static int _regulator_do_disable(struct regulator_dev *rdev);
static int _regulator_get_error_flags(struct regulator_dev *rdev, unsigned int *flags);
static int _regulator_get_current_limit(struct regulator_dev *rdev);
static unsigned int _regulator_get_mode(struct regulator_dev *rdev);
@@ -667,7 +669,33 @@ static ssize_t state_show(struct device *dev,

return ret;
}
-static DEVICE_ATTR_RO(state);
+
+static ssize_t state_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
+ bool enabled;
+ ssize_t ret = 0;
+
+ if (sysfs_streq(buf, "enabled"))
+ enabled = true;
+ else if (sysfs_streq(buf, "disabled"))
+ enabled = false;
+ else
+ return -EINVAL;
+
+ regulator_lock(rdev);
+ if (enabled != _regulator_is_enabled(rdev)) {
+ if (enabled)
+ ret = _regulator_do_enable(rdev);
+ else
+ ret = _regulator_do_disable(rdev);
+ }
+ regulator_unlock(rdev);
+
+ return ret ? : count;
+}
+static DEVICE_ATTR_RW(state);

static ssize_t status_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -5051,8 +5079,11 @@ static umode_t regulator_attr_is_visible(struct kobject *kobj,
if (attr == &dev_attr_opmode.attr)
return ops->get_mode ? mode : 0;

- if (attr == &dev_attr_state.attr)
+ if (attr == &dev_attr_state.attr) {
+ if (!(rdev->constraints && rdev->constraints->external_output))
+ mode &= ~0222;
return (rdev->ena_pin || ops->is_enabled) ? mode : 0;
+ }

if (attr == &dev_attr_status.attr)
return ops->get_status ? mode : 0;
@@ -6062,7 +6093,7 @@ static int regulator_late_cleanup(struct device *dev, void *data)
struct regulation_constraints *c = rdev->constraints;
int ret;

- if (c && c->always_on)
+ if (c && (c->always_on || c->external_output))
return 0;

if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_STATUS))
@@ -6114,8 +6145,8 @@ static void regulator_init_complete_work_function(struct work_struct *work)

/* If we have a full configuration then disable any regulators
* we have permission to change the status for and which are
- * not in use or always_on. This is effectively the default
- * for DT and ACPI as they have full constraints.
+ * not in use, always_on, or external_output. This is effectively
+ * the default for DT and ACPI as they have full constraints.
*/
class_for_each_device(&regulator_class, NULL, NULL,
regulator_late_cleanup);
diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c
index f54d4f176882..f48e6ea2b97e 100644
--- a/drivers/regulator/of_regulator.c
+++ b/drivers/regulator/of_regulator.c
@@ -96,6 +96,8 @@ static int of_get_regulation_constraints(struct device *dev,

constraints->name = of_get_property(np, "regulator-name", NULL);

+ constraints->external_output = of_property_read_bool(np, "regulator-external-output");
+
if (!of_property_read_u32(np, "regulator-min-microvolt", &pval))
constraints->min_uV = pval;

diff --git a/include/linux/regulator/machine.h b/include/linux/regulator/machine.h
index 621b7f4a3639..a38e7db9f82e 100644
--- a/include/linux/regulator/machine.h
+++ b/include/linux/regulator/machine.h
@@ -219,6 +219,7 @@ struct regulation_constraints {
unsigned over_voltage_detection:1; /* notify on over voltage */
unsigned under_voltage_detection:1; /* notify on under voltage */
unsigned over_temp_detection:1; /* notify on over temperature */
+ unsigned external_output:1; /* output supplies only external devices */
};

/**
--
2.36.0


2022-05-04 19:00:53

by Zev Weiss

[permalink] [raw]
Subject: [PATCH 6/6] regulator: core: Add external-consumer driver

An external consumer is a dummy device representing a device external
to the system that is supplied by a regulator designated for external
output. It is purely a virtual placeholder to instantiate a regulator
by calling regulator_get() on it from its probe function.

Signed-off-by: Zev Weiss <[email protected]>
---
drivers/regulator/Kconfig | 9 +++++++++
drivers/regulator/core.c | 28 ++++++++++++++++++++++++++++
2 files changed, 37 insertions(+)

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 5ef2306fce04..5ec390687a81 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -56,6 +56,15 @@ config REGULATOR_USERSPACE_CONSUMER

If unsure, say no.

+config REGULATOR_EXTERNAL_CONSUMER
+ bool "External regulator consumer support"
+ help
+ Some regulators supply devices that are entirely external to
+ the system. This driver provides a placeholder consumer
+ representing such devices.
+
+ If unsure, say no.
+
config REGULATOR_88PG86X
tristate "Marvell 88PG86X voltage regulators"
depends on I2C
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index d873606eb41f..4f348b3d5290 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -19,6 +19,7 @@
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/of.h>
+#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/consumer.h>
@@ -6070,6 +6071,33 @@ static int regulator_summary_show(struct seq_file *s, void *data)
DEFINE_SHOW_ATTRIBUTE(regulator_summary);
#endif /* CONFIG_DEBUG_FS */

+#ifdef CONFIG_REGULATOR_EXTERNAL_CONSUMER
+static int regulator_external_output_probe(struct platform_device *pdev)
+{
+ struct regulator *reg;
+
+ reg = devm_regulator_get_external(&pdev->dev, "vout");
+ if (IS_ERR(reg))
+ return PTR_ERR(reg);
+
+ return 0;
+}
+
+static const struct of_device_id reg_external_consumer_of_match_table[] = {
+ { .compatible = "regulator-external-output" },
+ { },
+};
+
+static struct platform_driver reg_external_consumer_driver = {
+ .driver = {
+ .name = "reg-external-consumer",
+ .of_match_table = reg_external_consumer_of_match_table,
+ },
+ .probe = regulator_external_output_probe,
+};
+builtin_platform_driver(reg_external_consumer_driver);
+#endif /* CONFIG_REGULATOR_EXTERNAL_CONSUMER */
+
static int __init regulator_init(void)
{
int ret;
--
2.36.0


2022-05-04 21:57:08

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH 1/6] dt-bindings: regulator: Add regulator-external-output property

On Tue, May 03, 2022 at 11:52:47PM -0700, Zev Weiss wrote:
> Some regulators do not provide power to anything within the system
> described by a device tree, and simply supply an external output. The
> regulator-external-output property can now be used to mark such
> regulators.

Why not just add a device representing this output? Presumably it has
some other properties (eg, labelling for a connector) and may need some
integration with some form of control mechanism.


Attachments:
(No filename) (483.00 B)
signature.asc (499.00 B)
Download all attachments

2022-05-05 18:29:26

by Mark Brown

[permalink] [raw]
Subject: Re: (subset) [PATCH 1/6] dt-bindings: regulator: Add regulator-external-output property

On Tue, 3 May 2022 23:52:47 -0700, Zev Weiss wrote:
> Some regulators do not provide power to anything within the system
> described by a device tree, and simply supply an external output. The
> regulator-external-output property can now be used to mark such
> regulators.
>
>

Applied to

https://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git for-next

Thanks!

[3/6] regulator: core: Add error flags to sysfs attributes
commit: 0f2d636e7d1fd76f704dd3ea5089ce29a8aee049

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark