All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/3] Add support for STM32 vrefbuf regulator
@ 2017-08-30 15:55 ` Fabrice Gasnier
  0 siblings, 0 replies; 18+ messages in thread
From: Fabrice Gasnier @ 2017-08-30 15:55 UTC (permalink / raw)
  To: broonie, lgirdwood, robh+dt, alexandre.torgue
  Cc: mark.rutland, mcoquelin.stm32, fabrice.gasnier, linux,
	devicetree, linux-arm-kernel, linux-kernel

Some STM32 devices embed a voltage reference buffer which can be used as
voltage reference for ADCs, DACs and also as voltage reference
for external components through the dedicated VREF+ pin.

This patchset adds vrefbuf regulator driver, device tree bindings and
vrefbuf device tree node for STM32H7 SoC.

---
Changes in v2:
- Update regulator driver following Mark's remarks

Fabrice Gasnier (3):
  dt-bindings: regulator: Add STM32 Voltage Reference Buffer
  regulator: Add support for stm32-vrefbuf
  ARM: dts: stm32: add vrefbuf to stm32h743

 .../bindings/regulator/st,stm32-vrefbuf.txt        |  20 ++
 arch/arm/boot/dts/stm32h743.dtsi                   |   9 +
 drivers/regulator/Kconfig                          |  12 ++
 drivers/regulator/Makefile                         |   1 +
 drivers/regulator/stm32-vrefbuf.c                  | 202 +++++++++++++++++++++
 5 files changed, 244 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/regulator/st,stm32-vrefbuf.txt
 create mode 100644 drivers/regulator/stm32-vrefbuf.c

-- 
1.9.1

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH v2 0/3] Add support for STM32 vrefbuf regulator
@ 2017-08-30 15:55 ` Fabrice Gasnier
  0 siblings, 0 replies; 18+ messages in thread
From: Fabrice Gasnier @ 2017-08-30 15:55 UTC (permalink / raw)
  To: broonie, lgirdwood, robh+dt, alexandre.torgue
  Cc: mark.rutland, devicetree, linux, linux-kernel, mcoquelin.stm32,
	fabrice.gasnier, linux-arm-kernel

Some STM32 devices embed a voltage reference buffer which can be used as
voltage reference for ADCs, DACs and also as voltage reference
for external components through the dedicated VREF+ pin.

This patchset adds vrefbuf regulator driver, device tree bindings and
vrefbuf device tree node for STM32H7 SoC.

---
Changes in v2:
- Update regulator driver following Mark's remarks

Fabrice Gasnier (3):
  dt-bindings: regulator: Add STM32 Voltage Reference Buffer
  regulator: Add support for stm32-vrefbuf
  ARM: dts: stm32: add vrefbuf to stm32h743

 .../bindings/regulator/st,stm32-vrefbuf.txt        |  20 ++
 arch/arm/boot/dts/stm32h743.dtsi                   |   9 +
 drivers/regulator/Kconfig                          |  12 ++
 drivers/regulator/Makefile                         |   1 +
 drivers/regulator/stm32-vrefbuf.c                  | 202 +++++++++++++++++++++
 5 files changed, 244 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/regulator/st,stm32-vrefbuf.txt
 create mode 100644 drivers/regulator/stm32-vrefbuf.c

-- 
1.9.1

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH v2 0/3] Add support for STM32 vrefbuf regulator
@ 2017-08-30 15:55 ` Fabrice Gasnier
  0 siblings, 0 replies; 18+ messages in thread
From: Fabrice Gasnier @ 2017-08-30 15:55 UTC (permalink / raw)
  To: linux-arm-kernel

Some STM32 devices embed a voltage reference buffer which can be used as
voltage reference for ADCs, DACs and also as voltage reference
for external components through the dedicated VREF+ pin.

This patchset adds vrefbuf regulator driver, device tree bindings and
vrefbuf device tree node for STM32H7 SoC.

---
Changes in v2:
- Update regulator driver following Mark's remarks

Fabrice Gasnier (3):
  dt-bindings: regulator: Add STM32 Voltage Reference Buffer
  regulator: Add support for stm32-vrefbuf
  ARM: dts: stm32: add vrefbuf to stm32h743

 .../bindings/regulator/st,stm32-vrefbuf.txt        |  20 ++
 arch/arm/boot/dts/stm32h743.dtsi                   |   9 +
 drivers/regulator/Kconfig                          |  12 ++
 drivers/regulator/Makefile                         |   1 +
 drivers/regulator/stm32-vrefbuf.c                  | 202 +++++++++++++++++++++
 5 files changed, 244 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/regulator/st,stm32-vrefbuf.txt
 create mode 100644 drivers/regulator/stm32-vrefbuf.c

-- 
1.9.1

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH v2 1/3] dt-bindings: regulator: Add STM32 Voltage Reference Buffer
@ 2017-08-30 15:55   ` Fabrice Gasnier
  0 siblings, 0 replies; 18+ messages in thread
From: Fabrice Gasnier @ 2017-08-30 15:55 UTC (permalink / raw)
  To: broonie, lgirdwood, robh+dt, alexandre.torgue
  Cc: mark.rutland, mcoquelin.stm32, fabrice.gasnier, linux,
	devicetree, linux-arm-kernel, linux-kernel

Document STM32 VREFBUF (voltage reference buffer) which can be used as
voltage reference for ADCs, DACs and external components.

Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
Acked-by: Rob Herring <robh@kernel.org>
---
 .../bindings/regulator/st,stm32-vrefbuf.txt          | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/regulator/st,stm32-vrefbuf.txt

diff --git a/Documentation/devicetree/bindings/regulator/st,stm32-vrefbuf.txt b/Documentation/devicetree/bindings/regulator/st,stm32-vrefbuf.txt
new file mode 100644
index 0000000..3944ee3
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/st,stm32-vrefbuf.txt
@@ -0,0 +1,20 @@
+STM32 VREFBUF - Voltage reference buffer
+
+Some STM32 devices embed a voltage reference buffer which can be used as
+voltage reference for ADCs, DACs and also as voltage reference for external
+components through the dedicated VREF+ pin.
+
+Required properties:
+- compatible:		Must be "st,stm32-vrefbuf".
+- reg:			Offset and length of VREFBUF register set.
+- clocks:		Must contain an entry for peripheral clock.
+
+Example:
+	vrefbuf: regulator@58003C00 {
+		compatible = "st,stm32-vrefbuf";
+		reg = <0x58003C00 0x8>;
+		clocks = <&rcc VREF_CK>;
+		regulator-min-microvolt = <1500000>;
+		regulator-max-microvolt = <2500000>;
+		vdda-supply = <&vdda>;
+	};
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v2 1/3] dt-bindings: regulator: Add STM32 Voltage Reference Buffer
@ 2017-08-30 15:55   ` Fabrice Gasnier
  0 siblings, 0 replies; 18+ messages in thread
From: Fabrice Gasnier @ 2017-08-30 15:55 UTC (permalink / raw)
  To: broonie-DgEjT+Ai2ygdnm+yROfE0A, lgirdwood-Re5JQEeQqe8AvxtiuMwx3w,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, alexandre.torgue-qxv4g6HH51o
  Cc: mark.rutland-5wv7dgnIgG8, mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w,
	fabrice.gasnier-qxv4g6HH51o, linux-I+IVW8TIWO2tmTQ+vhA3Yw,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

Document STM32 VREFBUF (voltage reference buffer) which can be used as
voltage reference for ADCs, DACs and external components.

Signed-off-by: Fabrice Gasnier <fabrice.gasnier-qxv4g6HH51o@public.gmane.org>
Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
---
 .../bindings/regulator/st,stm32-vrefbuf.txt          | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/regulator/st,stm32-vrefbuf.txt

diff --git a/Documentation/devicetree/bindings/regulator/st,stm32-vrefbuf.txt b/Documentation/devicetree/bindings/regulator/st,stm32-vrefbuf.txt
new file mode 100644
index 0000000..3944ee3
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/st,stm32-vrefbuf.txt
@@ -0,0 +1,20 @@
+STM32 VREFBUF - Voltage reference buffer
+
+Some STM32 devices embed a voltage reference buffer which can be used as
+voltage reference for ADCs, DACs and also as voltage reference for external
+components through the dedicated VREF+ pin.
+
+Required properties:
+- compatible:		Must be "st,stm32-vrefbuf".
+- reg:			Offset and length of VREFBUF register set.
+- clocks:		Must contain an entry for peripheral clock.
+
+Example:
+	vrefbuf: regulator@58003C00 {
+		compatible = "st,stm32-vrefbuf";
+		reg = <0x58003C00 0x8>;
+		clocks = <&rcc VREF_CK>;
+		regulator-min-microvolt = <1500000>;
+		regulator-max-microvolt = <2500000>;
+		vdda-supply = <&vdda>;
+	};
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v2 1/3] dt-bindings: regulator: Add STM32 Voltage Reference Buffer
@ 2017-08-30 15:55   ` Fabrice Gasnier
  0 siblings, 0 replies; 18+ messages in thread
From: Fabrice Gasnier @ 2017-08-30 15:55 UTC (permalink / raw)
  To: linux-arm-kernel

Document STM32 VREFBUF (voltage reference buffer) which can be used as
voltage reference for ADCs, DACs and external components.

Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
Acked-by: Rob Herring <robh@kernel.org>
---
 .../bindings/regulator/st,stm32-vrefbuf.txt          | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/regulator/st,stm32-vrefbuf.txt

diff --git a/Documentation/devicetree/bindings/regulator/st,stm32-vrefbuf.txt b/Documentation/devicetree/bindings/regulator/st,stm32-vrefbuf.txt
new file mode 100644
index 0000000..3944ee3
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/st,stm32-vrefbuf.txt
@@ -0,0 +1,20 @@
+STM32 VREFBUF - Voltage reference buffer
+
+Some STM32 devices embed a voltage reference buffer which can be used as
+voltage reference for ADCs, DACs and also as voltage reference for external
+components through the dedicated VREF+ pin.
+
+Required properties:
+- compatible:		Must be "st,stm32-vrefbuf".
+- reg:			Offset and length of VREFBUF register set.
+- clocks:		Must contain an entry for peripheral clock.
+
+Example:
+	vrefbuf: regulator at 58003C00 {
+		compatible = "st,stm32-vrefbuf";
+		reg = <0x58003C00 0x8>;
+		clocks = <&rcc VREF_CK>;
+		regulator-min-microvolt = <1500000>;
+		regulator-max-microvolt = <2500000>;
+		vdda-supply = <&vdda>;
+	};
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v2 2/3] regulator: Add support for stm32-vrefbuf
  2017-08-30 15:55 ` Fabrice Gasnier
  (?)
@ 2017-08-30 15:55   ` Fabrice Gasnier
  -1 siblings, 0 replies; 18+ messages in thread
From: Fabrice Gasnier @ 2017-08-30 15:55 UTC (permalink / raw)
  To: broonie, lgirdwood, robh+dt, alexandre.torgue
  Cc: mark.rutland, mcoquelin.stm32, fabrice.gasnier, linux,
	devicetree, linux-arm-kernel, linux-kernel

Add regulator driver for STM32 voltage reference buffer which can be
used as voltage reference for ADCs, DACs and external components through
dedicated VREF+ pin.

Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
---
Changes in v2:
- Remarks from Mark: include error codes when printing errors, remove noisy
  info, remove subsys_initcall(), replace it with regular
  module_platform_driver().
---
 drivers/regulator/Kconfig         |  12 +++
 drivers/regulator/Makefile        |   1 +
 drivers/regulator/stm32-vrefbuf.c | 202 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 215 insertions(+)
 create mode 100644 drivers/regulator/stm32-vrefbuf.c

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 99b9362..2cb2c63 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -746,6 +746,18 @@ config REGULATOR_SKY81452
 	  This driver can also be built as a module. If so, the module
 	  will be called sky81452-regulator.
 
+config REGULATOR_STM32_VREFBUF
+	tristate "STMicroelectronics STM32 VREFBUF"
+	depends on ARCH_STM32 || COMPILE_TEST
+	help
+	  This driver supports STMicroelectronics STM32 VREFBUF (voltage
+	  reference buffer) which can be used as voltage reference for
+	  internal ADCs, DACs and also for external components through
+	  dedicated Vref+ pin.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called stm32-vrefbuf.
+
 config REGULATOR_TI_ABB
 	tristate "TI Adaptive Body Bias on-chip LDO"
 	depends on ARCH_OMAP
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 95b1e86..5af3788 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -94,6 +94,7 @@ obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o
 obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o
 obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
 obj-$(CONFIG_REGULATOR_SKY81452) += sky81452-regulator.o
+obj-$(CONFIG_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o
 obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o
 obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o
 obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
diff --git a/drivers/regulator/stm32-vrefbuf.c b/drivers/regulator/stm32-vrefbuf.c
new file mode 100644
index 0000000..72c8b3e
--- /dev/null
+++ b/drivers/regulator/stm32-vrefbuf.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) STMicroelectronics 2017
+ *
+ * Author: Fabrice Gasnier <fabrice.gasnier@st.com>
+ *
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+
+/* STM32 VREFBUF registers */
+#define STM32_VREFBUF_CSR		0x00
+
+/* STM32 VREFBUF CSR bitfields */
+#define STM32_VRS			GENMASK(6, 4)
+#define STM32_VRR			BIT(3)
+#define STM32_HIZ			BIT(1)
+#define STM32_ENVR			BIT(0)
+
+struct stm32_vrefbuf {
+	void __iomem *base;
+	struct clk *clk;
+};
+
+static const unsigned int stm32_vrefbuf_voltages[] = {
+	/* Matches resp. VRS = 000b, 001b, 010b, 011b */
+	2500000, 2048000, 1800000, 1500000,
+};
+
+static int stm32_vrefbuf_enable(struct regulator_dev *rdev)
+{
+	struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
+	u32 val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
+	int ret;
+
+	val = (val & ~STM32_HIZ) | STM32_ENVR;
+	writel_relaxed(val, priv->base + STM32_VREFBUF_CSR);
+
+	/*
+	 * Vrefbuf startup time depends on external capacitor: wait here for
+	 * VRR to be set. That means output has reached expected value.
+	 * ~650us sleep should be enough for caps up to 1.5uF. Use 10ms as
+	 * arbitrary timeout.
+	 */
+	ret = readl_poll_timeout(priv->base + STM32_VREFBUF_CSR, val,
+				 !(val & STM32_VRR), 650, 10000);
+	if (ret) {
+		dev_err(&rdev->dev, "stm32 vrefbuf timed out!\n");
+		val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
+		val = (val & ~STM32_ENVR) | STM32_HIZ;
+		writel_relaxed(val, priv->base + STM32_VREFBUF_CSR);
+	}
+
+	return ret;
+}
+
+static int stm32_vrefbuf_disable(struct regulator_dev *rdev)
+{
+	struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
+	u32 val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
+
+	val = (val & ~STM32_ENVR) | STM32_HIZ;
+	writel_relaxed(val, priv->base + STM32_VREFBUF_CSR);
+
+	return 0;
+}
+
+static int stm32_vrefbuf_is_enabled(struct regulator_dev *rdev)
+{
+	struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
+
+	return readl_relaxed(priv->base + STM32_VREFBUF_CSR) & STM32_ENVR;
+}
+
+static int stm32_vrefbuf_set_voltage_sel(struct regulator_dev *rdev,
+					 unsigned sel)
+{
+	struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
+	u32 val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
+
+	val = (val & ~STM32_VRS) | FIELD_PREP(STM32_VRS, sel);
+	writel_relaxed(val, priv->base + STM32_VREFBUF_CSR);
+
+	return 0;
+}
+
+static int stm32_vrefbuf_get_voltage_sel(struct regulator_dev *rdev)
+{
+	struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
+	u32 val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
+
+	return FIELD_GET(STM32_VRS, val);
+}
+
+static const struct regulator_ops stm32_vrefbuf_volt_ops = {
+	.enable		= stm32_vrefbuf_enable,
+	.disable	= stm32_vrefbuf_disable,
+	.is_enabled	= stm32_vrefbuf_is_enabled,
+	.get_voltage_sel = stm32_vrefbuf_get_voltage_sel,
+	.set_voltage_sel = stm32_vrefbuf_set_voltage_sel,
+	.list_voltage	= regulator_list_voltage_table,
+};
+
+static const struct regulator_desc stm32_vrefbuf_regu = {
+	.name = "vref",
+	.supply_name = "vdda",
+	.volt_table = stm32_vrefbuf_voltages,
+	.n_voltages = ARRAY_SIZE(stm32_vrefbuf_voltages),
+	.ops = &stm32_vrefbuf_volt_ops,
+	.type = REGULATOR_VOLTAGE,
+	.owner = THIS_MODULE,
+};
+
+static int stm32_vrefbuf_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	struct stm32_vrefbuf *priv;
+	struct regulator_config config = { };
+	struct regulator_dev *rdev;
+	int ret;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	priv->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(priv->base))
+		return PTR_ERR(priv->base);
+
+	priv->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(priv->clk))
+		return PTR_ERR(priv->clk);
+
+	ret = clk_prepare_enable(priv->clk);
+	if (ret) {
+		dev_err(&pdev->dev, "clk prepare failed with error %d\n", ret);
+		return ret;
+	}
+
+	config.dev = &pdev->dev;
+	config.driver_data = priv;
+	config.of_node = pdev->dev.of_node;
+	config.init_data = of_get_regulator_init_data(&pdev->dev,
+						      pdev->dev.of_node,
+						      &stm32_vrefbuf_regu);
+
+	rdev = regulator_register(&stm32_vrefbuf_regu, &config);
+	if (IS_ERR(rdev)) {
+		ret = PTR_ERR(rdev);
+		dev_err(&pdev->dev, "register failed with error %d\n", ret);
+		goto err_clk_dis;
+	}
+	platform_set_drvdata(pdev, rdev);
+
+	return 0;
+
+err_clk_dis:
+	clk_disable_unprepare(priv->clk);
+
+	return ret;
+}
+
+static int stm32_vrefbuf_remove(struct platform_device *pdev)
+{
+	struct regulator_dev *rdev = platform_get_drvdata(pdev);
+	struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
+
+	regulator_unregister(rdev);
+	clk_disable_unprepare(priv->clk);
+
+	return 0;
+};
+
+static const struct of_device_id stm32_vrefbuf_of_match[] = {
+	{ .compatible = "st,stm32-vrefbuf", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, stm32_vrefbuf_of_match);
+
+static struct platform_driver stm32_vrefbuf_driver = {
+	.probe = stm32_vrefbuf_probe,
+	.remove = stm32_vrefbuf_remove,
+	.driver = {
+		.name  = "stm32-vrefbuf",
+		.of_match_table = of_match_ptr(stm32_vrefbuf_of_match),
+	},
+};
+module_platform_driver(stm32_vrefbuf_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Fabrice Gasnier <fabrice.gasnier@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics STM32 VREFBUF driver");
+MODULE_ALIAS("platform:stm32-vrefbuf");
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v2 2/3] regulator: Add support for stm32-vrefbuf
@ 2017-08-30 15:55   ` Fabrice Gasnier
  0 siblings, 0 replies; 18+ messages in thread
From: Fabrice Gasnier @ 2017-08-30 15:55 UTC (permalink / raw)
  To: broonie, lgirdwood, robh+dt, alexandre.torgue
  Cc: mark.rutland, mcoquelin.stm32, fabrice.gasnier, linux,
	devicetree, linux-arm-kernel, linux-kernel

Add regulator driver for STM32 voltage reference buffer which can be
used as voltage reference for ADCs, DACs and external components through
dedicated VREF+ pin.

Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
---
Changes in v2:
- Remarks from Mark: include error codes when printing errors, remove noisy
  info, remove subsys_initcall(), replace it with regular
  module_platform_driver().
---
 drivers/regulator/Kconfig         |  12 +++
 drivers/regulator/Makefile        |   1 +
 drivers/regulator/stm32-vrefbuf.c | 202 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 215 insertions(+)
 create mode 100644 drivers/regulator/stm32-vrefbuf.c

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 99b9362..2cb2c63 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -746,6 +746,18 @@ config REGULATOR_SKY81452
 	  This driver can also be built as a module. If so, the module
 	  will be called sky81452-regulator.
 
+config REGULATOR_STM32_VREFBUF
+	tristate "STMicroelectronics STM32 VREFBUF"
+	depends on ARCH_STM32 || COMPILE_TEST
+	help
+	  This driver supports STMicroelectronics STM32 VREFBUF (voltage
+	  reference buffer) which can be used as voltage reference for
+	  internal ADCs, DACs and also for external components through
+	  dedicated Vref+ pin.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called stm32-vrefbuf.
+
 config REGULATOR_TI_ABB
 	tristate "TI Adaptive Body Bias on-chip LDO"
 	depends on ARCH_OMAP
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 95b1e86..5af3788 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -94,6 +94,7 @@ obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o
 obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o
 obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
 obj-$(CONFIG_REGULATOR_SKY81452) += sky81452-regulator.o
+obj-$(CONFIG_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o
 obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o
 obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o
 obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
diff --git a/drivers/regulator/stm32-vrefbuf.c b/drivers/regulator/stm32-vrefbuf.c
new file mode 100644
index 0000000..72c8b3e
--- /dev/null
+++ b/drivers/regulator/stm32-vrefbuf.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) STMicroelectronics 2017
+ *
+ * Author: Fabrice Gasnier <fabrice.gasnier@st.com>
+ *
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+
+/* STM32 VREFBUF registers */
+#define STM32_VREFBUF_CSR		0x00
+
+/* STM32 VREFBUF CSR bitfields */
+#define STM32_VRS			GENMASK(6, 4)
+#define STM32_VRR			BIT(3)
+#define STM32_HIZ			BIT(1)
+#define STM32_ENVR			BIT(0)
+
+struct stm32_vrefbuf {
+	void __iomem *base;
+	struct clk *clk;
+};
+
+static const unsigned int stm32_vrefbuf_voltages[] = {
+	/* Matches resp. VRS = 000b, 001b, 010b, 011b */
+	2500000, 2048000, 1800000, 1500000,
+};
+
+static int stm32_vrefbuf_enable(struct regulator_dev *rdev)
+{
+	struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
+	u32 val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
+	int ret;
+
+	val = (val & ~STM32_HIZ) | STM32_ENVR;
+	writel_relaxed(val, priv->base + STM32_VREFBUF_CSR);
+
+	/*
+	 * Vrefbuf startup time depends on external capacitor: wait here for
+	 * VRR to be set. That means output has reached expected value.
+	 * ~650us sleep should be enough for caps up to 1.5uF. Use 10ms as
+	 * arbitrary timeout.
+	 */
+	ret = readl_poll_timeout(priv->base + STM32_VREFBUF_CSR, val,
+				 !(val & STM32_VRR), 650, 10000);
+	if (ret) {
+		dev_err(&rdev->dev, "stm32 vrefbuf timed out!\n");
+		val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
+		val = (val & ~STM32_ENVR) | STM32_HIZ;
+		writel_relaxed(val, priv->base + STM32_VREFBUF_CSR);
+	}
+
+	return ret;
+}
+
+static int stm32_vrefbuf_disable(struct regulator_dev *rdev)
+{
+	struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
+	u32 val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
+
+	val = (val & ~STM32_ENVR) | STM32_HIZ;
+	writel_relaxed(val, priv->base + STM32_VREFBUF_CSR);
+
+	return 0;
+}
+
+static int stm32_vrefbuf_is_enabled(struct regulator_dev *rdev)
+{
+	struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
+
+	return readl_relaxed(priv->base + STM32_VREFBUF_CSR) & STM32_ENVR;
+}
+
+static int stm32_vrefbuf_set_voltage_sel(struct regulator_dev *rdev,
+					 unsigned sel)
+{
+	struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
+	u32 val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
+
+	val = (val & ~STM32_VRS) | FIELD_PREP(STM32_VRS, sel);
+	writel_relaxed(val, priv->base + STM32_VREFBUF_CSR);
+
+	return 0;
+}
+
+static int stm32_vrefbuf_get_voltage_sel(struct regulator_dev *rdev)
+{
+	struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
+	u32 val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
+
+	return FIELD_GET(STM32_VRS, val);
+}
+
+static const struct regulator_ops stm32_vrefbuf_volt_ops = {
+	.enable		= stm32_vrefbuf_enable,
+	.disable	= stm32_vrefbuf_disable,
+	.is_enabled	= stm32_vrefbuf_is_enabled,
+	.get_voltage_sel = stm32_vrefbuf_get_voltage_sel,
+	.set_voltage_sel = stm32_vrefbuf_set_voltage_sel,
+	.list_voltage	= regulator_list_voltage_table,
+};
+
+static const struct regulator_desc stm32_vrefbuf_regu = {
+	.name = "vref",
+	.supply_name = "vdda",
+	.volt_table = stm32_vrefbuf_voltages,
+	.n_voltages = ARRAY_SIZE(stm32_vrefbuf_voltages),
+	.ops = &stm32_vrefbuf_volt_ops,
+	.type = REGULATOR_VOLTAGE,
+	.owner = THIS_MODULE,
+};
+
+static int stm32_vrefbuf_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	struct stm32_vrefbuf *priv;
+	struct regulator_config config = { };
+	struct regulator_dev *rdev;
+	int ret;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	priv->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(priv->base))
+		return PTR_ERR(priv->base);
+
+	priv->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(priv->clk))
+		return PTR_ERR(priv->clk);
+
+	ret = clk_prepare_enable(priv->clk);
+	if (ret) {
+		dev_err(&pdev->dev, "clk prepare failed with error %d\n", ret);
+		return ret;
+	}
+
+	config.dev = &pdev->dev;
+	config.driver_data = priv;
+	config.of_node = pdev->dev.of_node;
+	config.init_data = of_get_regulator_init_data(&pdev->dev,
+						      pdev->dev.of_node,
+						      &stm32_vrefbuf_regu);
+
+	rdev = regulator_register(&stm32_vrefbuf_regu, &config);
+	if (IS_ERR(rdev)) {
+		ret = PTR_ERR(rdev);
+		dev_err(&pdev->dev, "register failed with error %d\n", ret);
+		goto err_clk_dis;
+	}
+	platform_set_drvdata(pdev, rdev);
+
+	return 0;
+
+err_clk_dis:
+	clk_disable_unprepare(priv->clk);
+
+	return ret;
+}
+
+static int stm32_vrefbuf_remove(struct platform_device *pdev)
+{
+	struct regulator_dev *rdev = platform_get_drvdata(pdev);
+	struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
+
+	regulator_unregister(rdev);
+	clk_disable_unprepare(priv->clk);
+
+	return 0;
+};
+
+static const struct of_device_id stm32_vrefbuf_of_match[] = {
+	{ .compatible = "st,stm32-vrefbuf", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, stm32_vrefbuf_of_match);
+
+static struct platform_driver stm32_vrefbuf_driver = {
+	.probe = stm32_vrefbuf_probe,
+	.remove = stm32_vrefbuf_remove,
+	.driver = {
+		.name  = "stm32-vrefbuf",
+		.of_match_table = of_match_ptr(stm32_vrefbuf_of_match),
+	},
+};
+module_platform_driver(stm32_vrefbuf_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Fabrice Gasnier <fabrice.gasnier@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics STM32 VREFBUF driver");
+MODULE_ALIAS("platform:stm32-vrefbuf");
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v2 2/3] regulator: Add support for stm32-vrefbuf
@ 2017-08-30 15:55   ` Fabrice Gasnier
  0 siblings, 0 replies; 18+ messages in thread
From: Fabrice Gasnier @ 2017-08-30 15:55 UTC (permalink / raw)
  To: linux-arm-kernel

Add regulator driver for STM32 voltage reference buffer which can be
used as voltage reference for ADCs, DACs and external components through
dedicated VREF+ pin.

Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
---
Changes in v2:
- Remarks from Mark: include error codes when printing errors, remove noisy
  info, remove subsys_initcall(), replace it with regular
  module_platform_driver().
---
 drivers/regulator/Kconfig         |  12 +++
 drivers/regulator/Makefile        |   1 +
 drivers/regulator/stm32-vrefbuf.c | 202 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 215 insertions(+)
 create mode 100644 drivers/regulator/stm32-vrefbuf.c

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 99b9362..2cb2c63 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -746,6 +746,18 @@ config REGULATOR_SKY81452
 	  This driver can also be built as a module. If so, the module
 	  will be called sky81452-regulator.
 
+config REGULATOR_STM32_VREFBUF
+	tristate "STMicroelectronics STM32 VREFBUF"
+	depends on ARCH_STM32 || COMPILE_TEST
+	help
+	  This driver supports STMicroelectronics STM32 VREFBUF (voltage
+	  reference buffer) which can be used as voltage reference for
+	  internal ADCs, DACs and also for external components through
+	  dedicated Vref+ pin.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called stm32-vrefbuf.
+
 config REGULATOR_TI_ABB
 	tristate "TI Adaptive Body Bias on-chip LDO"
 	depends on ARCH_OMAP
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 95b1e86..5af3788 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -94,6 +94,7 @@ obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o
 obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o
 obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
 obj-$(CONFIG_REGULATOR_SKY81452) += sky81452-regulator.o
+obj-$(CONFIG_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o
 obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o
 obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o
 obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
diff --git a/drivers/regulator/stm32-vrefbuf.c b/drivers/regulator/stm32-vrefbuf.c
new file mode 100644
index 0000000..72c8b3e
--- /dev/null
+++ b/drivers/regulator/stm32-vrefbuf.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) STMicroelectronics 2017
+ *
+ * Author: Fabrice Gasnier <fabrice.gasnier@st.com>
+ *
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+
+/* STM32 VREFBUF registers */
+#define STM32_VREFBUF_CSR		0x00
+
+/* STM32 VREFBUF CSR bitfields */
+#define STM32_VRS			GENMASK(6, 4)
+#define STM32_VRR			BIT(3)
+#define STM32_HIZ			BIT(1)
+#define STM32_ENVR			BIT(0)
+
+struct stm32_vrefbuf {
+	void __iomem *base;
+	struct clk *clk;
+};
+
+static const unsigned int stm32_vrefbuf_voltages[] = {
+	/* Matches resp. VRS = 000b, 001b, 010b, 011b */
+	2500000, 2048000, 1800000, 1500000,
+};
+
+static int stm32_vrefbuf_enable(struct regulator_dev *rdev)
+{
+	struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
+	u32 val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
+	int ret;
+
+	val = (val & ~STM32_HIZ) | STM32_ENVR;
+	writel_relaxed(val, priv->base + STM32_VREFBUF_CSR);
+
+	/*
+	 * Vrefbuf startup time depends on external capacitor: wait here for
+	 * VRR to be set. That means output has reached expected value.
+	 * ~650us sleep should be enough for caps up to 1.5uF. Use 10ms as
+	 * arbitrary timeout.
+	 */
+	ret = readl_poll_timeout(priv->base + STM32_VREFBUF_CSR, val,
+				 !(val & STM32_VRR), 650, 10000);
+	if (ret) {
+		dev_err(&rdev->dev, "stm32 vrefbuf timed out!\n");
+		val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
+		val = (val & ~STM32_ENVR) | STM32_HIZ;
+		writel_relaxed(val, priv->base + STM32_VREFBUF_CSR);
+	}
+
+	return ret;
+}
+
+static int stm32_vrefbuf_disable(struct regulator_dev *rdev)
+{
+	struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
+	u32 val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
+
+	val = (val & ~STM32_ENVR) | STM32_HIZ;
+	writel_relaxed(val, priv->base + STM32_VREFBUF_CSR);
+
+	return 0;
+}
+
+static int stm32_vrefbuf_is_enabled(struct regulator_dev *rdev)
+{
+	struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
+
+	return readl_relaxed(priv->base + STM32_VREFBUF_CSR) & STM32_ENVR;
+}
+
+static int stm32_vrefbuf_set_voltage_sel(struct regulator_dev *rdev,
+					 unsigned sel)
+{
+	struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
+	u32 val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
+
+	val = (val & ~STM32_VRS) | FIELD_PREP(STM32_VRS, sel);
+	writel_relaxed(val, priv->base + STM32_VREFBUF_CSR);
+
+	return 0;
+}
+
+static int stm32_vrefbuf_get_voltage_sel(struct regulator_dev *rdev)
+{
+	struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
+	u32 val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
+
+	return FIELD_GET(STM32_VRS, val);
+}
+
+static const struct regulator_ops stm32_vrefbuf_volt_ops = {
+	.enable		= stm32_vrefbuf_enable,
+	.disable	= stm32_vrefbuf_disable,
+	.is_enabled	= stm32_vrefbuf_is_enabled,
+	.get_voltage_sel = stm32_vrefbuf_get_voltage_sel,
+	.set_voltage_sel = stm32_vrefbuf_set_voltage_sel,
+	.list_voltage	= regulator_list_voltage_table,
+};
+
+static const struct regulator_desc stm32_vrefbuf_regu = {
+	.name = "vref",
+	.supply_name = "vdda",
+	.volt_table = stm32_vrefbuf_voltages,
+	.n_voltages = ARRAY_SIZE(stm32_vrefbuf_voltages),
+	.ops = &stm32_vrefbuf_volt_ops,
+	.type = REGULATOR_VOLTAGE,
+	.owner = THIS_MODULE,
+};
+
+static int stm32_vrefbuf_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	struct stm32_vrefbuf *priv;
+	struct regulator_config config = { };
+	struct regulator_dev *rdev;
+	int ret;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	priv->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(priv->base))
+		return PTR_ERR(priv->base);
+
+	priv->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(priv->clk))
+		return PTR_ERR(priv->clk);
+
+	ret = clk_prepare_enable(priv->clk);
+	if (ret) {
+		dev_err(&pdev->dev, "clk prepare failed with error %d\n", ret);
+		return ret;
+	}
+
+	config.dev = &pdev->dev;
+	config.driver_data = priv;
+	config.of_node = pdev->dev.of_node;
+	config.init_data = of_get_regulator_init_data(&pdev->dev,
+						      pdev->dev.of_node,
+						      &stm32_vrefbuf_regu);
+
+	rdev = regulator_register(&stm32_vrefbuf_regu, &config);
+	if (IS_ERR(rdev)) {
+		ret = PTR_ERR(rdev);
+		dev_err(&pdev->dev, "register failed with error %d\n", ret);
+		goto err_clk_dis;
+	}
+	platform_set_drvdata(pdev, rdev);
+
+	return 0;
+
+err_clk_dis:
+	clk_disable_unprepare(priv->clk);
+
+	return ret;
+}
+
+static int stm32_vrefbuf_remove(struct platform_device *pdev)
+{
+	struct regulator_dev *rdev = platform_get_drvdata(pdev);
+	struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
+
+	regulator_unregister(rdev);
+	clk_disable_unprepare(priv->clk);
+
+	return 0;
+};
+
+static const struct of_device_id stm32_vrefbuf_of_match[] = {
+	{ .compatible = "st,stm32-vrefbuf", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, stm32_vrefbuf_of_match);
+
+static struct platform_driver stm32_vrefbuf_driver = {
+	.probe = stm32_vrefbuf_probe,
+	.remove = stm32_vrefbuf_remove,
+	.driver = {
+		.name  = "stm32-vrefbuf",
+		.of_match_table = of_match_ptr(stm32_vrefbuf_of_match),
+	},
+};
+module_platform_driver(stm32_vrefbuf_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Fabrice Gasnier <fabrice.gasnier@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics STM32 VREFBUF driver");
+MODULE_ALIAS("platform:stm32-vrefbuf");
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v2 3/3] ARM: dts: stm32: add vrefbuf to stm32h743
@ 2017-08-30 15:55   ` Fabrice Gasnier
  0 siblings, 0 replies; 18+ messages in thread
From: Fabrice Gasnier @ 2017-08-30 15:55 UTC (permalink / raw)
  To: broonie, lgirdwood, robh+dt, alexandre.torgue
  Cc: mark.rutland, mcoquelin.stm32, fabrice.gasnier, linux,
	devicetree, linux-arm-kernel, linux-kernel

Add STM32H743 VREFBUF (Voltage Reference Buffer) definition.

Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
---
 arch/arm/boot/dts/stm32h743.dtsi | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arch/arm/boot/dts/stm32h743.dtsi b/arch/arm/boot/dts/stm32h743.dtsi
index 36a99db..83ee8fe 100644
--- a/arch/arm/boot/dts/stm32h743.dtsi
+++ b/arch/arm/boot/dts/stm32h743.dtsi
@@ -82,6 +82,15 @@
 			interrupts = <50>;
 			clocks = <&timer_clk>;
 		};
+
+		vrefbuf: regulator@58003C00 {
+			compatible = "st,stm32-vrefbuf";
+			reg = <0x58003C00 0x8>;
+			clocks = <&timer_clk>;
+			regulator-min-microvolt = <1500000>;
+			regulator-max-microvolt = <2500000>;
+			status = "disabled";
+		};
 	};
 };
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v2 3/3] ARM: dts: stm32: add vrefbuf to stm32h743
@ 2017-08-30 15:55   ` Fabrice Gasnier
  0 siblings, 0 replies; 18+ messages in thread
From: Fabrice Gasnier @ 2017-08-30 15:55 UTC (permalink / raw)
  To: broonie-DgEjT+Ai2ygdnm+yROfE0A, lgirdwood-Re5JQEeQqe8AvxtiuMwx3w,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, alexandre.torgue-qxv4g6HH51o
  Cc: mark.rutland-5wv7dgnIgG8, mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w,
	fabrice.gasnier-qxv4g6HH51o, linux-I+IVW8TIWO2tmTQ+vhA3Yw,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

Add STM32H743 VREFBUF (Voltage Reference Buffer) definition.

Signed-off-by: Fabrice Gasnier <fabrice.gasnier-qxv4g6HH51o@public.gmane.org>
---
 arch/arm/boot/dts/stm32h743.dtsi | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arch/arm/boot/dts/stm32h743.dtsi b/arch/arm/boot/dts/stm32h743.dtsi
index 36a99db..83ee8fe 100644
--- a/arch/arm/boot/dts/stm32h743.dtsi
+++ b/arch/arm/boot/dts/stm32h743.dtsi
@@ -82,6 +82,15 @@
 			interrupts = <50>;
 			clocks = <&timer_clk>;
 		};
+
+		vrefbuf: regulator@58003C00 {
+			compatible = "st,stm32-vrefbuf";
+			reg = <0x58003C00 0x8>;
+			clocks = <&timer_clk>;
+			regulator-min-microvolt = <1500000>;
+			regulator-max-microvolt = <2500000>;
+			status = "disabled";
+		};
 	};
 };
 
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v2 3/3] ARM: dts: stm32: add vrefbuf to stm32h743
@ 2017-08-30 15:55   ` Fabrice Gasnier
  0 siblings, 0 replies; 18+ messages in thread
From: Fabrice Gasnier @ 2017-08-30 15:55 UTC (permalink / raw)
  To: linux-arm-kernel

Add STM32H743 VREFBUF (Voltage Reference Buffer) definition.

Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
---
 arch/arm/boot/dts/stm32h743.dtsi | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arch/arm/boot/dts/stm32h743.dtsi b/arch/arm/boot/dts/stm32h743.dtsi
index 36a99db..83ee8fe 100644
--- a/arch/arm/boot/dts/stm32h743.dtsi
+++ b/arch/arm/boot/dts/stm32h743.dtsi
@@ -82,6 +82,15 @@
 			interrupts = <50>;
 			clocks = <&timer_clk>;
 		};
+
+		vrefbuf: regulator at 58003C00 {
+			compatible = "st,stm32-vrefbuf";
+			reg = <0x58003C00 0x8>;
+			clocks = <&timer_clk>;
+			regulator-min-microvolt = <1500000>;
+			regulator-max-microvolt = <2500000>;
+			status = "disabled";
+		};
 	};
 };
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Applied "regulator: Add support for stm32-vrefbuf" to the regulator tree
  2017-08-30 15:55   ` Fabrice Gasnier
  (?)
@ 2017-08-30 17:57     ` Mark Brown
  -1 siblings, 0 replies; 18+ messages in thread
From: Mark Brown @ 2017-08-30 17:57 UTC (permalink / raw)
  To: Fabrice Gasnier
  Cc: Mark Brown, broonie, lgirdwood, robh+dt, alexandre.torgue,
	mark.rutland, mcoquelin.stm32, fabrice.gasnier, linux,
	devicetree, linux-arm-kernel, linux-kernel, linux-kernel

The patch

   regulator: Add support for stm32-vrefbuf

has been applied to the regulator tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git 

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

>From 0cdbf481e927278787042857e02c3944f588ad25 Mon Sep 17 00:00:00 2001
From: Fabrice Gasnier <fabrice.gasnier@st.com>
Date: Wed, 30 Aug 2017 17:55:28 +0200
Subject: [PATCH] regulator: Add support for stm32-vrefbuf

Add regulator driver for STM32 voltage reference buffer which can be
used as voltage reference for ADCs, DACs and external components through
dedicated VREF+ pin.

Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
 drivers/regulator/Kconfig         |  12 +++
 drivers/regulator/Makefile        |   1 +
 drivers/regulator/stm32-vrefbuf.c | 202 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 215 insertions(+)
 create mode 100644 drivers/regulator/stm32-vrefbuf.c

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 99b9362331b5..2cb2c6324480 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -746,6 +746,18 @@ config REGULATOR_SKY81452
 	  This driver can also be built as a module. If so, the module
 	  will be called sky81452-regulator.
 
+config REGULATOR_STM32_VREFBUF
+	tristate "STMicroelectronics STM32 VREFBUF"
+	depends on ARCH_STM32 || COMPILE_TEST
+	help
+	  This driver supports STMicroelectronics STM32 VREFBUF (voltage
+	  reference buffer) which can be used as voltage reference for
+	  internal ADCs, DACs and also for external components through
+	  dedicated Vref+ pin.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called stm32-vrefbuf.
+
 config REGULATOR_TI_ABB
 	tristate "TI Adaptive Body Bias on-chip LDO"
 	depends on ARCH_OMAP
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 95b1e86ae692..5af3788be631 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -94,6 +94,7 @@ obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o
 obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o
 obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
 obj-$(CONFIG_REGULATOR_SKY81452) += sky81452-regulator.o
+obj-$(CONFIG_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o
 obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o
 obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o
 obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
diff --git a/drivers/regulator/stm32-vrefbuf.c b/drivers/regulator/stm32-vrefbuf.c
new file mode 100644
index 000000000000..72c8b3e1022b
--- /dev/null
+++ b/drivers/regulator/stm32-vrefbuf.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) STMicroelectronics 2017
+ *
+ * Author: Fabrice Gasnier <fabrice.gasnier@st.com>
+ *
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+
+/* STM32 VREFBUF registers */
+#define STM32_VREFBUF_CSR		0x00
+
+/* STM32 VREFBUF CSR bitfields */
+#define STM32_VRS			GENMASK(6, 4)
+#define STM32_VRR			BIT(3)
+#define STM32_HIZ			BIT(1)
+#define STM32_ENVR			BIT(0)
+
+struct stm32_vrefbuf {
+	void __iomem *base;
+	struct clk *clk;
+};
+
+static const unsigned int stm32_vrefbuf_voltages[] = {
+	/* Matches resp. VRS = 000b, 001b, 010b, 011b */
+	2500000, 2048000, 1800000, 1500000,
+};
+
+static int stm32_vrefbuf_enable(struct regulator_dev *rdev)
+{
+	struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
+	u32 val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
+	int ret;
+
+	val = (val & ~STM32_HIZ) | STM32_ENVR;
+	writel_relaxed(val, priv->base + STM32_VREFBUF_CSR);
+
+	/*
+	 * Vrefbuf startup time depends on external capacitor: wait here for
+	 * VRR to be set. That means output has reached expected value.
+	 * ~650us sleep should be enough for caps up to 1.5uF. Use 10ms as
+	 * arbitrary timeout.
+	 */
+	ret = readl_poll_timeout(priv->base + STM32_VREFBUF_CSR, val,
+				 !(val & STM32_VRR), 650, 10000);
+	if (ret) {
+		dev_err(&rdev->dev, "stm32 vrefbuf timed out!\n");
+		val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
+		val = (val & ~STM32_ENVR) | STM32_HIZ;
+		writel_relaxed(val, priv->base + STM32_VREFBUF_CSR);
+	}
+
+	return ret;
+}
+
+static int stm32_vrefbuf_disable(struct regulator_dev *rdev)
+{
+	struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
+	u32 val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
+
+	val = (val & ~STM32_ENVR) | STM32_HIZ;
+	writel_relaxed(val, priv->base + STM32_VREFBUF_CSR);
+
+	return 0;
+}
+
+static int stm32_vrefbuf_is_enabled(struct regulator_dev *rdev)
+{
+	struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
+
+	return readl_relaxed(priv->base + STM32_VREFBUF_CSR) & STM32_ENVR;
+}
+
+static int stm32_vrefbuf_set_voltage_sel(struct regulator_dev *rdev,
+					 unsigned sel)
+{
+	struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
+	u32 val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
+
+	val = (val & ~STM32_VRS) | FIELD_PREP(STM32_VRS, sel);
+	writel_relaxed(val, priv->base + STM32_VREFBUF_CSR);
+
+	return 0;
+}
+
+static int stm32_vrefbuf_get_voltage_sel(struct regulator_dev *rdev)
+{
+	struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
+	u32 val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
+
+	return FIELD_GET(STM32_VRS, val);
+}
+
+static const struct regulator_ops stm32_vrefbuf_volt_ops = {
+	.enable		= stm32_vrefbuf_enable,
+	.disable	= stm32_vrefbuf_disable,
+	.is_enabled	= stm32_vrefbuf_is_enabled,
+	.get_voltage_sel = stm32_vrefbuf_get_voltage_sel,
+	.set_voltage_sel = stm32_vrefbuf_set_voltage_sel,
+	.list_voltage	= regulator_list_voltage_table,
+};
+
+static const struct regulator_desc stm32_vrefbuf_regu = {
+	.name = "vref",
+	.supply_name = "vdda",
+	.volt_table = stm32_vrefbuf_voltages,
+	.n_voltages = ARRAY_SIZE(stm32_vrefbuf_voltages),
+	.ops = &stm32_vrefbuf_volt_ops,
+	.type = REGULATOR_VOLTAGE,
+	.owner = THIS_MODULE,
+};
+
+static int stm32_vrefbuf_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	struct stm32_vrefbuf *priv;
+	struct regulator_config config = { };
+	struct regulator_dev *rdev;
+	int ret;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	priv->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(priv->base))
+		return PTR_ERR(priv->base);
+
+	priv->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(priv->clk))
+		return PTR_ERR(priv->clk);
+
+	ret = clk_prepare_enable(priv->clk);
+	if (ret) {
+		dev_err(&pdev->dev, "clk prepare failed with error %d\n", ret);
+		return ret;
+	}
+
+	config.dev = &pdev->dev;
+	config.driver_data = priv;
+	config.of_node = pdev->dev.of_node;
+	config.init_data = of_get_regulator_init_data(&pdev->dev,
+						      pdev->dev.of_node,
+						      &stm32_vrefbuf_regu);
+
+	rdev = regulator_register(&stm32_vrefbuf_regu, &config);
+	if (IS_ERR(rdev)) {
+		ret = PTR_ERR(rdev);
+		dev_err(&pdev->dev, "register failed with error %d\n", ret);
+		goto err_clk_dis;
+	}
+	platform_set_drvdata(pdev, rdev);
+
+	return 0;
+
+err_clk_dis:
+	clk_disable_unprepare(priv->clk);
+
+	return ret;
+}
+
+static int stm32_vrefbuf_remove(struct platform_device *pdev)
+{
+	struct regulator_dev *rdev = platform_get_drvdata(pdev);
+	struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
+
+	regulator_unregister(rdev);
+	clk_disable_unprepare(priv->clk);
+
+	return 0;
+};
+
+static const struct of_device_id stm32_vrefbuf_of_match[] = {
+	{ .compatible = "st,stm32-vrefbuf", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, stm32_vrefbuf_of_match);
+
+static struct platform_driver stm32_vrefbuf_driver = {
+	.probe = stm32_vrefbuf_probe,
+	.remove = stm32_vrefbuf_remove,
+	.driver = {
+		.name  = "stm32-vrefbuf",
+		.of_match_table = of_match_ptr(stm32_vrefbuf_of_match),
+	},
+};
+module_platform_driver(stm32_vrefbuf_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Fabrice Gasnier <fabrice.gasnier@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics STM32 VREFBUF driver");
+MODULE_ALIAS("platform:stm32-vrefbuf");
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Applied "regulator: Add support for stm32-vrefbuf" to the regulator tree
@ 2017-08-30 17:57     ` Mark Brown
  0 siblings, 0 replies; 18+ messages in thread
From: Mark Brown @ 2017-08-30 17:57 UTC (permalink / raw)
  Cc: Mark Brown

The patch

   regulator: Add support for stm32-vrefbuf

has been applied to the regulator tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git 

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

>From 0cdbf481e927278787042857e02c3944f588ad25 Mon Sep 17 00:00:00 2001
From: Fabrice Gasnier <fabrice.gasnier@st.com>
Date: Wed, 30 Aug 2017 17:55:28 +0200
Subject: [PATCH] regulator: Add support for stm32-vrefbuf

Add regulator driver for STM32 voltage reference buffer which can be
used as voltage reference for ADCs, DACs and external components through
dedicated VREF+ pin.

Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
 drivers/regulator/Kconfig         |  12 +++
 drivers/regulator/Makefile        |   1 +
 drivers/regulator/stm32-vrefbuf.c | 202 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 215 insertions(+)
 create mode 100644 drivers/regulator/stm32-vrefbuf.c

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 99b9362331b5..2cb2c6324480 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -746,6 +746,18 @@ config REGULATOR_SKY81452
 	  This driver can also be built as a module. If so, the module
 	  will be called sky81452-regulator.
 
+config REGULATOR_STM32_VREFBUF
+	tristate "STMicroelectronics STM32 VREFBUF"
+	depends on ARCH_STM32 || COMPILE_TEST
+	help
+	  This driver supports STMicroelectronics STM32 VREFBUF (voltage
+	  reference buffer) which can be used as voltage reference for
+	  internal ADCs, DACs and also for external components through
+	  dedicated Vref+ pin.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called stm32-vrefbuf.
+
 config REGULATOR_TI_ABB
 	tristate "TI Adaptive Body Bias on-chip LDO"
 	depends on ARCH_OMAP
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 95b1e86ae692..5af3788be631 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -94,6 +94,7 @@ obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o
 obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o
 obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
 obj-$(CONFIG_REGULATOR_SKY81452) += sky81452-regulator.o
+obj-$(CONFIG_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o
 obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o
 obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o
 obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
diff --git a/drivers/regulator/stm32-vrefbuf.c b/drivers/regulator/stm32-vrefbuf.c
new file mode 100644
index 000000000000..72c8b3e1022b
--- /dev/null
+++ b/drivers/regulator/stm32-vrefbuf.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) STMicroelectronics 2017
+ *
+ * Author: Fabrice Gasnier <fabrice.gasnier@st.com>
+ *
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+
+/* STM32 VREFBUF registers */
+#define STM32_VREFBUF_CSR		0x00
+
+/* STM32 VREFBUF CSR bitfields */
+#define STM32_VRS			GENMASK(6, 4)
+#define STM32_VRR			BIT(3)
+#define STM32_HIZ			BIT(1)
+#define STM32_ENVR			BIT(0)
+
+struct stm32_vrefbuf {
+	void __iomem *base;
+	struct clk *clk;
+};
+
+static const unsigned int stm32_vrefbuf_voltages[] = {
+	/* Matches resp. VRS = 000b, 001b, 010b, 011b */
+	2500000, 2048000, 1800000, 1500000,
+};
+
+static int stm32_vrefbuf_enable(struct regulator_dev *rdev)
+{
+	struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
+	u32 val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
+	int ret;
+
+	val = (val & ~STM32_HIZ) | STM32_ENVR;
+	writel_relaxed(val, priv->base + STM32_VREFBUF_CSR);
+
+	/*
+	 * Vrefbuf startup time depends on external capacitor: wait here for
+	 * VRR to be set. That means output has reached expected value.
+	 * ~650us sleep should be enough for caps up to 1.5uF. Use 10ms as
+	 * arbitrary timeout.
+	 */
+	ret = readl_poll_timeout(priv->base + STM32_VREFBUF_CSR, val,
+				 !(val & STM32_VRR), 650, 10000);
+	if (ret) {
+		dev_err(&rdev->dev, "stm32 vrefbuf timed out!\n");
+		val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
+		val = (val & ~STM32_ENVR) | STM32_HIZ;
+		writel_relaxed(val, priv->base + STM32_VREFBUF_CSR);
+	}
+
+	return ret;
+}
+
+static int stm32_vrefbuf_disable(struct regulator_dev *rdev)
+{
+	struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
+	u32 val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
+
+	val = (val & ~STM32_ENVR) | STM32_HIZ;
+	writel_relaxed(val, priv->base + STM32_VREFBUF_CSR);
+
+	return 0;
+}
+
+static int stm32_vrefbuf_is_enabled(struct regulator_dev *rdev)
+{
+	struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
+
+	return readl_relaxed(priv->base + STM32_VREFBUF_CSR) & STM32_ENVR;
+}
+
+static int stm32_vrefbuf_set_voltage_sel(struct regulator_dev *rdev,
+					 unsigned sel)
+{
+	struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
+	u32 val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
+
+	val = (val & ~STM32_VRS) | FIELD_PREP(STM32_VRS, sel);
+	writel_relaxed(val, priv->base + STM32_VREFBUF_CSR);
+
+	return 0;
+}
+
+static int stm32_vrefbuf_get_voltage_sel(struct regulator_dev *rdev)
+{
+	struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
+	u32 val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
+
+	return FIELD_GET(STM32_VRS, val);
+}
+
+static const struct regulator_ops stm32_vrefbuf_volt_ops = {
+	.enable		= stm32_vrefbuf_enable,
+	.disable	= stm32_vrefbuf_disable,
+	.is_enabled	= stm32_vrefbuf_is_enabled,
+	.get_voltage_sel = stm32_vrefbuf_get_voltage_sel,
+	.set_voltage_sel = stm32_vrefbuf_set_voltage_sel,
+	.list_voltage	= regulator_list_voltage_table,
+};
+
+static const struct regulator_desc stm32_vrefbuf_regu = {
+	.name = "vref",
+	.supply_name = "vdda",
+	.volt_table = stm32_vrefbuf_voltages,
+	.n_voltages = ARRAY_SIZE(stm32_vrefbuf_voltages),
+	.ops = &stm32_vrefbuf_volt_ops,
+	.type = REGULATOR_VOLTAGE,
+	.owner = THIS_MODULE,
+};
+
+static int stm32_vrefbuf_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	struct stm32_vrefbuf *priv;
+	struct regulator_config config = { };
+	struct regulator_dev *rdev;
+	int ret;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	priv->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(priv->base))
+		return PTR_ERR(priv->base);
+
+	priv->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(priv->clk))
+		return PTR_ERR(priv->clk);
+
+	ret = clk_prepare_enable(priv->clk);
+	if (ret) {
+		dev_err(&pdev->dev, "clk prepare failed with error %d\n", ret);
+		return ret;
+	}
+
+	config.dev = &pdev->dev;
+	config.driver_data = priv;
+	config.of_node = pdev->dev.of_node;
+	config.init_data = of_get_regulator_init_data(&pdev->dev,
+						      pdev->dev.of_node,
+						      &stm32_vrefbuf_regu);
+
+	rdev = regulator_register(&stm32_vrefbuf_regu, &config);
+	if (IS_ERR(rdev)) {
+		ret = PTR_ERR(rdev);
+		dev_err(&pdev->dev, "register failed with error %d\n", ret);
+		goto err_clk_dis;
+	}
+	platform_set_drvdata(pdev, rdev);
+
+	return 0;
+
+err_clk_dis:
+	clk_disable_unprepare(priv->clk);
+
+	return ret;
+}
+
+static int stm32_vrefbuf_remove(struct platform_device *pdev)
+{
+	struct regulator_dev *rdev = platform_get_drvdata(pdev);
+	struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
+
+	regulator_unregister(rdev);
+	clk_disable_unprepare(priv->clk);
+
+	return 0;
+};
+
+static const struct of_device_id stm32_vrefbuf_of_match[] = {
+	{ .compatible = "st,stm32-vrefbuf", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, stm32_vrefbuf_of_match);
+
+static struct platform_driver stm32_vrefbuf_driver = {
+	.probe = stm32_vrefbuf_probe,
+	.remove = stm32_vrefbuf_remove,
+	.driver = {
+		.name  = "stm32-vrefbuf",
+		.of_match_table = of_match_ptr(stm32_vrefbuf_of_match),
+	},
+};
+module_platform_driver(stm32_vrefbuf_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Fabrice Gasnier <fabrice.gasnier@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics STM32 VREFBUF driver");
+MODULE_ALIAS("platform:stm32-vrefbuf");
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Applied "regulator: Add support for stm32-vrefbuf" to the regulator tree
@ 2017-08-30 17:57     ` Mark Brown
  0 siblings, 0 replies; 18+ messages in thread
From: Mark Brown @ 2017-08-30 17:57 UTC (permalink / raw)
  To: linux-arm-kernel

The patch

   regulator: Add support for stm32-vrefbuf

has been applied to the regulator tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git 

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

>From 0cdbf481e927278787042857e02c3944f588ad25 Mon Sep 17 00:00:00 2001
From: Fabrice Gasnier <fabrice.gasnier@st.com>
Date: Wed, 30 Aug 2017 17:55:28 +0200
Subject: [PATCH] regulator: Add support for stm32-vrefbuf

Add regulator driver for STM32 voltage reference buffer which can be
used as voltage reference for ADCs, DACs and external components through
dedicated VREF+ pin.

Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
 drivers/regulator/Kconfig         |  12 +++
 drivers/regulator/Makefile        |   1 +
 drivers/regulator/stm32-vrefbuf.c | 202 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 215 insertions(+)
 create mode 100644 drivers/regulator/stm32-vrefbuf.c

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 99b9362331b5..2cb2c6324480 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -746,6 +746,18 @@ config REGULATOR_SKY81452
 	  This driver can also be built as a module. If so, the module
 	  will be called sky81452-regulator.
 
+config REGULATOR_STM32_VREFBUF
+	tristate "STMicroelectronics STM32 VREFBUF"
+	depends on ARCH_STM32 || COMPILE_TEST
+	help
+	  This driver supports STMicroelectronics STM32 VREFBUF (voltage
+	  reference buffer) which can be used as voltage reference for
+	  internal ADCs, DACs and also for external components through
+	  dedicated Vref+ pin.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called stm32-vrefbuf.
+
 config REGULATOR_TI_ABB
 	tristate "TI Adaptive Body Bias on-chip LDO"
 	depends on ARCH_OMAP
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 95b1e86ae692..5af3788be631 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -94,6 +94,7 @@ obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o
 obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o
 obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
 obj-$(CONFIG_REGULATOR_SKY81452) += sky81452-regulator.o
+obj-$(CONFIG_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o
 obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o
 obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o
 obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
diff --git a/drivers/regulator/stm32-vrefbuf.c b/drivers/regulator/stm32-vrefbuf.c
new file mode 100644
index 000000000000..72c8b3e1022b
--- /dev/null
+++ b/drivers/regulator/stm32-vrefbuf.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) STMicroelectronics 2017
+ *
+ * Author: Fabrice Gasnier <fabrice.gasnier@st.com>
+ *
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+
+/* STM32 VREFBUF registers */
+#define STM32_VREFBUF_CSR		0x00
+
+/* STM32 VREFBUF CSR bitfields */
+#define STM32_VRS			GENMASK(6, 4)
+#define STM32_VRR			BIT(3)
+#define STM32_HIZ			BIT(1)
+#define STM32_ENVR			BIT(0)
+
+struct stm32_vrefbuf {
+	void __iomem *base;
+	struct clk *clk;
+};
+
+static const unsigned int stm32_vrefbuf_voltages[] = {
+	/* Matches resp. VRS = 000b, 001b, 010b, 011b */
+	2500000, 2048000, 1800000, 1500000,
+};
+
+static int stm32_vrefbuf_enable(struct regulator_dev *rdev)
+{
+	struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
+	u32 val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
+	int ret;
+
+	val = (val & ~STM32_HIZ) | STM32_ENVR;
+	writel_relaxed(val, priv->base + STM32_VREFBUF_CSR);
+
+	/*
+	 * Vrefbuf startup time depends on external capacitor: wait here for
+	 * VRR to be set. That means output has reached expected value.
+	 * ~650us sleep should be enough for caps up to 1.5uF. Use 10ms as
+	 * arbitrary timeout.
+	 */
+	ret = readl_poll_timeout(priv->base + STM32_VREFBUF_CSR, val,
+				 !(val & STM32_VRR), 650, 10000);
+	if (ret) {
+		dev_err(&rdev->dev, "stm32 vrefbuf timed out!\n");
+		val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
+		val = (val & ~STM32_ENVR) | STM32_HIZ;
+		writel_relaxed(val, priv->base + STM32_VREFBUF_CSR);
+	}
+
+	return ret;
+}
+
+static int stm32_vrefbuf_disable(struct regulator_dev *rdev)
+{
+	struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
+	u32 val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
+
+	val = (val & ~STM32_ENVR) | STM32_HIZ;
+	writel_relaxed(val, priv->base + STM32_VREFBUF_CSR);
+
+	return 0;
+}
+
+static int stm32_vrefbuf_is_enabled(struct regulator_dev *rdev)
+{
+	struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
+
+	return readl_relaxed(priv->base + STM32_VREFBUF_CSR) & STM32_ENVR;
+}
+
+static int stm32_vrefbuf_set_voltage_sel(struct regulator_dev *rdev,
+					 unsigned sel)
+{
+	struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
+	u32 val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
+
+	val = (val & ~STM32_VRS) | FIELD_PREP(STM32_VRS, sel);
+	writel_relaxed(val, priv->base + STM32_VREFBUF_CSR);
+
+	return 0;
+}
+
+static int stm32_vrefbuf_get_voltage_sel(struct regulator_dev *rdev)
+{
+	struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
+	u32 val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
+
+	return FIELD_GET(STM32_VRS, val);
+}
+
+static const struct regulator_ops stm32_vrefbuf_volt_ops = {
+	.enable		= stm32_vrefbuf_enable,
+	.disable	= stm32_vrefbuf_disable,
+	.is_enabled	= stm32_vrefbuf_is_enabled,
+	.get_voltage_sel = stm32_vrefbuf_get_voltage_sel,
+	.set_voltage_sel = stm32_vrefbuf_set_voltage_sel,
+	.list_voltage	= regulator_list_voltage_table,
+};
+
+static const struct regulator_desc stm32_vrefbuf_regu = {
+	.name = "vref",
+	.supply_name = "vdda",
+	.volt_table = stm32_vrefbuf_voltages,
+	.n_voltages = ARRAY_SIZE(stm32_vrefbuf_voltages),
+	.ops = &stm32_vrefbuf_volt_ops,
+	.type = REGULATOR_VOLTAGE,
+	.owner = THIS_MODULE,
+};
+
+static int stm32_vrefbuf_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	struct stm32_vrefbuf *priv;
+	struct regulator_config config = { };
+	struct regulator_dev *rdev;
+	int ret;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	priv->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(priv->base))
+		return PTR_ERR(priv->base);
+
+	priv->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(priv->clk))
+		return PTR_ERR(priv->clk);
+
+	ret = clk_prepare_enable(priv->clk);
+	if (ret) {
+		dev_err(&pdev->dev, "clk prepare failed with error %d\n", ret);
+		return ret;
+	}
+
+	config.dev = &pdev->dev;
+	config.driver_data = priv;
+	config.of_node = pdev->dev.of_node;
+	config.init_data = of_get_regulator_init_data(&pdev->dev,
+						      pdev->dev.of_node,
+						      &stm32_vrefbuf_regu);
+
+	rdev = regulator_register(&stm32_vrefbuf_regu, &config);
+	if (IS_ERR(rdev)) {
+		ret = PTR_ERR(rdev);
+		dev_err(&pdev->dev, "register failed with error %d\n", ret);
+		goto err_clk_dis;
+	}
+	platform_set_drvdata(pdev, rdev);
+
+	return 0;
+
+err_clk_dis:
+	clk_disable_unprepare(priv->clk);
+
+	return ret;
+}
+
+static int stm32_vrefbuf_remove(struct platform_device *pdev)
+{
+	struct regulator_dev *rdev = platform_get_drvdata(pdev);
+	struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
+
+	regulator_unregister(rdev);
+	clk_disable_unprepare(priv->clk);
+
+	return 0;
+};
+
+static const struct of_device_id stm32_vrefbuf_of_match[] = {
+	{ .compatible = "st,stm32-vrefbuf", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, stm32_vrefbuf_of_match);
+
+static struct platform_driver stm32_vrefbuf_driver = {
+	.probe = stm32_vrefbuf_probe,
+	.remove = stm32_vrefbuf_remove,
+	.driver = {
+		.name  = "stm32-vrefbuf",
+		.of_match_table = of_match_ptr(stm32_vrefbuf_of_match),
+	},
+};
+module_platform_driver(stm32_vrefbuf_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Fabrice Gasnier <fabrice.gasnier@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics STM32 VREFBUF driver");
+MODULE_ALIAS("platform:stm32-vrefbuf");
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCH v2 3/3] ARM: dts: stm32: add vrefbuf to stm32h743
@ 2017-10-06 13:01     ` Alexandre Torgue
  0 siblings, 0 replies; 18+ messages in thread
From: Alexandre Torgue @ 2017-10-06 13:01 UTC (permalink / raw)
  To: Fabrice Gasnier, broonie, lgirdwood, robh+dt
  Cc: mark.rutland, mcoquelin.stm32, linux, devicetree,
	linux-arm-kernel, linux-kernel

Hi Fabrice,

On 08/30/2017 05:55 PM, Fabrice Gasnier wrote:
> Add STM32H743 VREFBUF (Voltage Reference Buffer) definition.
> 
> Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
> ---
>   arch/arm/boot/dts/stm32h743.dtsi | 9 +++++++++
>   1 file changed, 9 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/stm32h743.dtsi b/arch/arm/boot/dts/stm32h743.dtsi
> index 36a99db..83ee8fe 100644
> --- a/arch/arm/boot/dts/stm32h743.dtsi
> +++ b/arch/arm/boot/dts/stm32h743.dtsi
> @@ -82,6 +82,15 @@
>   			interrupts = <50>;
>   			clocks = <&timer_clk>;
>   		};
> +
> +		vrefbuf: regulator@58003C00 {
> +			compatible = "st,stm32-vrefbuf";
> +			reg = <0x58003C00 0x8>;
> +			clocks = <&timer_clk>;
> +			regulator-min-microvolt = <1500000>;
> +			regulator-max-microvolt = <2500000>;
> +			status = "disabled";
> +		};
>   	};
>   };
>   
> 
Applied on stm32-dt-for-v4.15 branch.

Thanks
Alex

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v2 3/3] ARM: dts: stm32: add vrefbuf to stm32h743
@ 2017-10-06 13:01     ` Alexandre Torgue
  0 siblings, 0 replies; 18+ messages in thread
From: Alexandre Torgue @ 2017-10-06 13:01 UTC (permalink / raw)
  To: Fabrice Gasnier, broonie-DgEjT+Ai2ygdnm+yROfE0A,
	lgirdwood-Re5JQEeQqe8AvxtiuMwx3w, robh+dt-DgEjT+Ai2ygdnm+yROfE0A
  Cc: mark.rutland-5wv7dgnIgG8, mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w,
	linux-I+IVW8TIWO2tmTQ+vhA3Yw, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

Hi Fabrice,

On 08/30/2017 05:55 PM, Fabrice Gasnier wrote:
> Add STM32H743 VREFBUF (Voltage Reference Buffer) definition.
> 
> Signed-off-by: Fabrice Gasnier <fabrice.gasnier-qxv4g6HH51o@public.gmane.org>
> ---
>   arch/arm/boot/dts/stm32h743.dtsi | 9 +++++++++
>   1 file changed, 9 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/stm32h743.dtsi b/arch/arm/boot/dts/stm32h743.dtsi
> index 36a99db..83ee8fe 100644
> --- a/arch/arm/boot/dts/stm32h743.dtsi
> +++ b/arch/arm/boot/dts/stm32h743.dtsi
> @@ -82,6 +82,15 @@
>   			interrupts = <50>;
>   			clocks = <&timer_clk>;
>   		};
> +
> +		vrefbuf: regulator@58003C00 {
> +			compatible = "st,stm32-vrefbuf";
> +			reg = <0x58003C00 0x8>;
> +			clocks = <&timer_clk>;
> +			regulator-min-microvolt = <1500000>;
> +			regulator-max-microvolt = <2500000>;
> +			status = "disabled";
> +		};
>   	};
>   };
>   
> 
Applied on stm32-dt-for-v4.15 branch.

Thanks
Alex
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH v2 3/3] ARM: dts: stm32: add vrefbuf to stm32h743
@ 2017-10-06 13:01     ` Alexandre Torgue
  0 siblings, 0 replies; 18+ messages in thread
From: Alexandre Torgue @ 2017-10-06 13:01 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Fabrice,

On 08/30/2017 05:55 PM, Fabrice Gasnier wrote:
> Add STM32H743 VREFBUF (Voltage Reference Buffer) definition.
> 
> Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
> ---
>   arch/arm/boot/dts/stm32h743.dtsi | 9 +++++++++
>   1 file changed, 9 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/stm32h743.dtsi b/arch/arm/boot/dts/stm32h743.dtsi
> index 36a99db..83ee8fe 100644
> --- a/arch/arm/boot/dts/stm32h743.dtsi
> +++ b/arch/arm/boot/dts/stm32h743.dtsi
> @@ -82,6 +82,15 @@
>   			interrupts = <50>;
>   			clocks = <&timer_clk>;
>   		};
> +
> +		vrefbuf: regulator at 58003C00 {
> +			compatible = "st,stm32-vrefbuf";
> +			reg = <0x58003C00 0x8>;
> +			clocks = <&timer_clk>;
> +			regulator-min-microvolt = <1500000>;
> +			regulator-max-microvolt = <2500000>;
> +			status = "disabled";
> +		};
>   	};
>   };
>   
> 
Applied on stm32-dt-for-v4.15 branch.

Thanks
Alex

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2017-10-06 13:02 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-08-30 15:55 [PATCH v2 0/3] Add support for STM32 vrefbuf regulator Fabrice Gasnier
2017-08-30 15:55 ` Fabrice Gasnier
2017-08-30 15:55 ` Fabrice Gasnier
2017-08-30 15:55 ` [PATCH v2 1/3] dt-bindings: regulator: Add STM32 Voltage Reference Buffer Fabrice Gasnier
2017-08-30 15:55   ` Fabrice Gasnier
2017-08-30 15:55   ` Fabrice Gasnier
2017-08-30 15:55 ` [PATCH v2 2/3] regulator: Add support for stm32-vrefbuf Fabrice Gasnier
2017-08-30 15:55   ` Fabrice Gasnier
2017-08-30 15:55   ` Fabrice Gasnier
2017-08-30 17:57   ` Applied "regulator: Add support for stm32-vrefbuf" to the regulator tree Mark Brown
2017-08-30 17:57     ` Mark Brown
2017-08-30 17:57     ` Mark Brown
2017-08-30 15:55 ` [PATCH v2 3/3] ARM: dts: stm32: add vrefbuf to stm32h743 Fabrice Gasnier
2017-08-30 15:55   ` Fabrice Gasnier
2017-08-30 15:55   ` Fabrice Gasnier
2017-10-06 13:01   ` Alexandre Torgue
2017-10-06 13:01     ` Alexandre Torgue
2017-10-06 13:01     ` Alexandre Torgue

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.