summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/regulator/da9211.txt205
-rw-r--r--Documentation/devicetree/bindings/regulator/dlg,da9211.yaml103
-rw-r--r--drivers/regulator/core.c124
-rw-r--r--drivers/regulator/sy7636a-regulator.c27
-rw-r--r--include/linux/regulator/driver.h3
5 files changed, 257 insertions, 205 deletions
diff --git a/Documentation/devicetree/bindings/regulator/da9211.txt b/Documentation/devicetree/bindings/regulator/da9211.txt
deleted file mode 100644
index eb871447d508..000000000000
--- a/Documentation/devicetree/bindings/regulator/da9211.txt
+++ /dev/null
@@ -1,205 +0,0 @@
-* Dialog Semiconductor DA9211/DA9212/DA9213/DA9223/DA9214/DA9224/DA9215/DA9225
- Voltage Regulator
-
-Required properties:
-- compatible: "dlg,da9211" or "dlg,da9212" or "dlg,da9213" or "dlg,da9223"
- or "dlg,da9214" or "dlg,da9224" or "dlg,da9215" or "dlg,da9225"
-- reg: I2C slave address, usually 0x68.
-- interrupts: the interrupt outputs of the controller
-- regulators: A node that houses a sub-node for each regulator within the
- device. Each sub-node is identified using the node's name, with valid
- values listed below. The content of each sub-node is defined by the
- standard binding for regulators; see regulator.txt.
- BUCKA and BUCKB.
-
-Optional properties:
-- enable-gpios: platform gpio for control of BUCKA/BUCKB.
-- Any optional property defined in regulator.txt
- - regulator-initial-mode and regulator-allowed-modes may be specified using
- mode values from dt-bindings/regulator/dlg,da9211-regulator.h
-
-Example 1) DA9211
- pmic: da9211@68 {
- compatible = "dlg,da9211";
- reg = <0x68>;
- interrupts = <3 27>;
-
- regulators {
- BUCKA {
- regulator-name = "VBUCKA";
- regulator-min-microvolt = < 300000>;
- regulator-max-microvolt = <1570000>;
- regulator-min-microamp = <2000000>;
- regulator-max-microamp = <5000000>;
- enable-gpios = <&gpio 27 0>;
- regulator-allowed-modes = <DA9211_BUCK_MODE_SYNC
- DA9211_BUCK_MODE_AUTO>;
- };
- };
- };
-
-Example 2) DA9212
- pmic: da9212@68 {
- compatible = "dlg,da9212";
- reg = <0x68>;
- interrupts = <3 27>;
-
- regulators {
- BUCKA {
- regulator-name = "VBUCKA";
- regulator-min-microvolt = < 300000>;
- regulator-max-microvolt = <1570000>;
- regulator-min-microamp = <2000000>;
- regulator-max-microamp = <5000000>;
- enable-gpios = <&gpio 27 0>;
- };
- BUCKB {
- regulator-name = "VBUCKB";
- regulator-min-microvolt = < 300000>;
- regulator-max-microvolt = <1570000>;
- regulator-min-microamp = <2000000>;
- regulator-max-microamp = <5000000>;
- enable-gpios = <&gpio 17 0>;
- };
- };
- };
-
-Example 3) DA9213
- pmic: da9213@68 {
- compatible = "dlg,da9213";
- reg = <0x68>;
- interrupts = <3 27>;
-
- regulators {
- BUCKA {
- regulator-name = "VBUCKA";
- regulator-min-microvolt = < 300000>;
- regulator-max-microvolt = <1570000>;
- regulator-min-microamp = <3000000>;
- regulator-max-microamp = <6000000>;
- enable-gpios = <&gpio 27 0>;
- };
- };
- };
-
-Example 4) DA9223
- pmic: da9223@68 {
- compatible = "dlg,da9223";
- reg = <0x68>;
- interrupts = <3 27>;
-
- regulators {
- BUCKA {
- regulator-name = "VBUCKA";
- regulator-min-microvolt = < 300000>;
- regulator-max-microvolt = <1570000>;
- regulator-min-microamp = <3000000>;
- regulator-max-microamp = <6000000>;
- enable-gpios = <&gpio 27 0>;
- };
- };
- };
-
-Example 5) DA9214
- pmic: da9214@68 {
- compatible = "dlg,da9214";
- reg = <0x68>;
- interrupts = <3 27>;
-
- regulators {
- BUCKA {
- regulator-name = "VBUCKA";
- regulator-min-microvolt = < 300000>;
- regulator-max-microvolt = <1570000>;
- regulator-min-microamp = <3000000>;
- regulator-max-microamp = <6000000>;
- enable-gpios = <&gpio 27 0>;
- };
- BUCKB {
- regulator-name = "VBUCKB";
- regulator-min-microvolt = < 300000>;
- regulator-max-microvolt = <1570000>;
- regulator-min-microamp = <3000000>;
- regulator-max-microamp = <6000000>;
- enable-gpios = <&gpio 17 0>;
- };
- };
- };
-
-Example 6) DA9224
- pmic: da9224@68 {
- compatible = "dlg,da9224";
- reg = <0x68>;
- interrupts = <3 27>;
-
- regulators {
- BUCKA {
- regulator-name = "VBUCKA";
- regulator-min-microvolt = < 300000>;
- regulator-max-microvolt = <1570000>;
- regulator-min-microamp = <3000000>;
- regulator-max-microamp = <6000000>;
- enable-gpios = <&gpio 27 0>;
- };
- BUCKB {
- regulator-name = "VBUCKB";
- regulator-min-microvolt = < 300000>;
- regulator-max-microvolt = <1570000>;
- regulator-min-microamp = <3000000>;
- regulator-max-microamp = <6000000>;
- enable-gpios = <&gpio 17 0>;
- };
- };
- };
-
-Example 7) DA9215
- pmic: da9215@68 {
- compatible = "dlg,da9215";
- reg = <0x68>;
- interrupts = <3 27>;
-
- regulators {
- BUCKA {
- regulator-name = "VBUCKA";
- regulator-min-microvolt = < 300000>;
- regulator-max-microvolt = <1570000>;
- regulator-min-microamp = <4000000>;
- regulator-max-microamp = <7000000>;
- enable-gpios = <&gpio 27 0>;
- };
- BUCKB {
- regulator-name = "VBUCKB";
- regulator-min-microvolt = < 300000>;
- regulator-max-microvolt = <1570000>;
- regulator-min-microamp = <4000000>;
- regulator-max-microamp = <7000000>;
- enable-gpios = <&gpio 17 0>;
- };
- };
- };
-
-Example 8) DA9225
- pmic: da9225@68 {
- compatible = "dlg,da9225";
- reg = <0x68>;
- interrupts = <3 27>;
-
- regulators {
- BUCKA {
- regulator-name = "VBUCKA";
- regulator-min-microvolt = < 300000>;
- regulator-max-microvolt = <1570000>;
- regulator-min-microamp = <4000000>;
- regulator-max-microamp = <7000000>;
- enable-gpios = <&gpio 27 0>;
- };
- BUCKB {
- regulator-name = "VBUCKB";
- regulator-min-microvolt = < 300000>;
- regulator-max-microvolt = <1570000>;
- regulator-min-microamp = <4000000>;
- regulator-max-microamp = <7000000>;
- enable-gpios = <&gpio 17 0>;
- };
- };
- };
diff --git a/Documentation/devicetree/bindings/regulator/dlg,da9211.yaml b/Documentation/devicetree/bindings/regulator/dlg,da9211.yaml
new file mode 100644
index 000000000000..4d7e495a6f59
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/dlg,da9211.yaml
@@ -0,0 +1,103 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/regulator/dlg,da9211.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title:
+ Dialog Semiconductor DA9211-9215, DA9223-9225 Voltage Regulators
+
+maintainers:
+ - Ariel D'Alessandro <ariel.dalessandro@collabora.com>
+
+properties:
+ compatible:
+ enum:
+ - dlg,da9211
+ - dlg,da9212
+ - dlg,da9213
+ - dlg,da9214
+ - dlg,da9215
+ - dlg,da9223
+ - dlg,da9224
+ - dlg,da9225
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ regulators:
+ type: object
+ additionalProperties: false
+ description:
+ List of regulators provided by the device
+
+ patternProperties:
+ "^BUCK([AB])$":
+ type: object
+ $ref: regulator.yaml#
+ unevaluatedProperties: false
+ description:
+ Properties for a single BUCK regulator
+
+ properties:
+ regulator-initial-mode:
+ items:
+ enum: [ 1, 2, 3 ]
+ description:
+ Defined in include/dt-bindings/regulator/dlg,da9211-regulator.h
+
+ regulator-allowed-modes:
+ items:
+ enum: [ 1, 2, 3 ]
+ description:
+ Defined in include/dt-bindings/regulator/dlg,da9211-regulator.h
+
+ enable-gpios:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - regulators
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/regulator/dlg,da9211-regulator.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ regulator@68 {
+ compatible = "dlg,da9212";
+ reg = <0x68>;
+ interrupts = <3 27>;
+
+ regulators {
+ BUCKA {
+ regulator-name = "VBUCKA";
+ regulator-min-microvolt = < 300000>;
+ regulator-max-microvolt = <1570000>;
+ regulator-min-microamp = <2000000>;
+ regulator-max-microamp = <5000000>;
+ enable-gpios = <&gpio 27 0>;
+ };
+ BUCKB {
+ regulator-name = "VBUCKB";
+ regulator-min-microvolt = < 300000>;
+ regulator-max-microvolt = <1570000>;
+ regulator-min-microamp = <2000000>;
+ regulator-max-microamp = <5000000>;
+ enable-gpios = <&gpio 17 0>;
+ };
+ };
+ };
+ };
+
+...
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index dd7b10e768c0..84bc38911dba 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -83,6 +83,19 @@ struct regulator_supply_alias {
const char *alias_supply;
};
+/*
+ * Work item used to forward regulator events.
+ *
+ * @work: workqueue entry
+ * @rdev: regulator device to notify (consumer receiving the forwarded event)
+ * @event: event code to be forwarded
+ */
+struct regulator_event_work {
+ struct work_struct work;
+ struct regulator_dev *rdev;
+ unsigned long event;
+};
+
static int _regulator_is_enabled(struct regulator_dev *rdev);
static int _regulator_disable(struct regulator *regulator);
static int _regulator_get_error_flags(struct regulator_dev *rdev, unsigned int *flags);
@@ -1659,6 +1672,104 @@ static int set_machine_constraints(struct regulator_dev *rdev)
}
/**
+ * regulator_event_work_fn - process a deferred regulator event
+ * @work: work_struct queued by the notifier
+ *
+ * Calls the regulator's notifier chain in process context while holding
+ * the rdev lock, then releases the device reference.
+ */
+static void regulator_event_work_fn(struct work_struct *work)
+{
+ struct regulator_event_work *rew =
+ container_of(work, struct regulator_event_work, work);
+ struct regulator_dev *rdev = rew->rdev;
+ int ret;
+
+ regulator_lock(rdev);
+ ret = regulator_notifier_call_chain(rdev, rew->event, NULL);
+ regulator_unlock(rdev);
+ if (ret == NOTIFY_BAD)
+ dev_err(rdev_get_dev(rdev), "failed to forward regulator event\n");
+
+ put_device(rdev_get_dev(rdev));
+ kfree(rew);
+}
+
+/**
+ * regulator_event_forward_notifier - notifier callback for supply events
+ * @nb: notifier block embedded in the regulator
+ * @event: regulator event code
+ * @data: unused
+ *
+ * Packages the event into a work item and schedules it in process context.
+ * Takes a reference on @rdev->dev to pin the regulator until the work
+ * completes (see put_device() in the worker).
+ *
+ * Return: NOTIFY_OK on success, NOTIFY_DONE for events that are not forwarded.
+ */
+static int regulator_event_forward_notifier(struct notifier_block *nb,
+ unsigned long event,
+ void __always_unused *data)
+{
+ struct regulator_dev *rdev = container_of(nb, struct regulator_dev,
+ supply_fwd_nb);
+ struct regulator_event_work *rew;
+
+ switch (event) {
+ case REGULATOR_EVENT_UNDER_VOLTAGE:
+ break;
+ default:
+ /* Only forward allowed events downstream. */
+ return NOTIFY_DONE;
+ }
+
+ rew = kmalloc(sizeof(*rew), GFP_ATOMIC);
+ if (!rew)
+ return NOTIFY_DONE;
+
+ get_device(rdev_get_dev(rdev));
+ rew->rdev = rdev;
+ rew->event = event;
+ INIT_WORK(&rew->work, regulator_event_work_fn);
+
+ queue_work(system_highpri_wq, &rew->work);
+
+ return NOTIFY_OK;
+}
+
+/**
+ * register_regulator_event_forwarding - enable supply event forwarding
+ * @rdev: regulator device
+ *
+ * Registers a notifier on the regulator's supply so that supply events
+ * are forwarded to the consumer regulator via the deferred work handler.
+ *
+ * Return: 0 on success, -EALREADY if already enabled, or a negative error code.
+ */
+static int register_regulator_event_forwarding(struct regulator_dev *rdev)
+{
+ int ret;
+
+ if (!rdev->supply)
+ return 0; /* top-level regulator: nothing to forward */
+
+ if (rdev->supply_fwd_nb.notifier_call)
+ return -EALREADY;
+
+ rdev->supply_fwd_nb.notifier_call = regulator_event_forward_notifier;
+
+ ret = regulator_register_notifier(rdev->supply, &rdev->supply_fwd_nb);
+ if (ret) {
+ dev_err(&rdev->dev, "failed to register supply notifier: %pe\n",
+ ERR_PTR(ret));
+ rdev->supply_fwd_nb.notifier_call = NULL;
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
* set_supply - set regulator supply regulator
* @rdev: regulator (locked)
* @supply_rdev: supply regulator (locked))
@@ -2144,6 +2255,16 @@ static int regulator_resolve_supply(struct regulator_dev *rdev)
goto out;
}
+ /*
+ * Automatically register for event forwarding from the new supply.
+ * This creates the downstream propagation link for events like
+ * under-voltage.
+ */
+ ret = register_regulator_event_forwarding(rdev);
+ if (ret < 0)
+ rdev_warn(rdev, "Failed to register event forwarding: %pe\n",
+ ERR_PTR(ret));
+
regulator_unlock_two(rdev, r, &ww_ctx);
/* rdev->supply was created in set_supply() */
@@ -6031,6 +6152,9 @@ void regulator_unregister(struct regulator_dev *rdev)
return;
if (rdev->supply) {
+ regulator_unregister_notifier(rdev->supply,
+ &rdev->supply_fwd_nb);
+
while (rdev->use_count--)
regulator_disable(rdev->supply);
regulator_put(rdev->supply);
diff --git a/drivers/regulator/sy7636a-regulator.c b/drivers/regulator/sy7636a-regulator.c
index 27e3d939b7bb..551647bc1052 100644
--- a/drivers/regulator/sy7636a-regulator.c
+++ b/drivers/regulator/sy7636a-regulator.c
@@ -12,6 +12,7 @@
#include <linux/mfd/sy7636a.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regmap.h>
@@ -19,6 +20,8 @@
struct sy7636a_data {
struct regmap *regmap;
struct gpio_desc *pgood_gpio;
+ struct gpio_desc *en_gpio;
+ struct gpio_desc *vcom_en_gpio;
};
static int sy7636a_get_vcom_voltage_op(struct regulator_dev *rdev)
@@ -98,6 +101,30 @@ static int sy7636a_regulator_probe(struct platform_device *pdev)
data->regmap = regmap;
data->pgood_gpio = gdp;
+ ret = devm_regulator_get_enable_optional(&pdev->dev, "vin");
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "failed to get vin regulator\n");
+
+ data->en_gpio = devm_gpiod_get_optional(&pdev->dev, "enable",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(data->en_gpio))
+ return dev_err_probe(&pdev->dev,
+ PTR_ERR(data->en_gpio),
+ "failed to get en gpio\n");
+
+ /* Let VCOM just follow the default power on sequence */
+ data->vcom_en_gpio = devm_gpiod_get_optional(&pdev->dev,
+ "vcom-en", GPIOD_OUT_LOW);
+ if (IS_ERR(data->vcom_en_gpio))
+ return dev_err_probe(&pdev->dev,
+ PTR_ERR(data->vcom_en_gpio),
+ "failed to get vcom-en gpio\n");
+
+ /* if chip was not enabled, give it time to wake up */
+ if (data->en_gpio)
+ usleep_range(2500, 4000);
+
platform_set_drvdata(pdev, data);
ret = regmap_write(regmap, SY7636A_REG_POWER_ON_DELAY_TIME, 0x0);
diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h
index 4a216fdba354..978cf593b662 100644
--- a/include/linux/regulator/driver.h
+++ b/include/linux/regulator/driver.h
@@ -658,6 +658,9 @@ struct regulator_dev {
spinlock_t err_lock;
int pw_requested_mW;
+
+ /* regulator notification forwarding */
+ struct notifier_block supply_fwd_nb;
};
/*