[RFC linus/master 1/4] regulator: add raspberry pi driver

Alexander Aring alex.aring at gmail.com
Sat Oct 24 05:20:41 PDT 2015


This patch adds support for raspberrypi regulator driver. It supports
for enable/disable regulators via raspberry pi firmware.

It doesn't support to display/change(if frimware supports that) the
current voltage setting. Maybe somebody knows the default voltage which
the firmware sets and this can be added.

Cc: Eric Anholt <eric at anholt.net>
Signed-off-by: Alexander Aring <alex.aring at gmail.com>
---
 .../devicetree/bindings/regulator/raspberrypi.txt  |  59 +++++++
 drivers/regulator/Kconfig                          |  11 ++
 drivers/regulator/Makefile                         |   1 +
 drivers/regulator/raspberrypi-regulator.c          | 172 +++++++++++++++++++++
 4 files changed, 243 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/regulator/raspberrypi.txt
 create mode 100644 drivers/regulator/raspberrypi-regulator.c

diff --git a/Documentation/devicetree/bindings/regulator/raspberrypi.txt b/Documentation/devicetree/bindings/regulator/raspberrypi.txt
new file mode 100644
index 0000000..759ad12
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/raspberrypi.txt
@@ -0,0 +1,59 @@
+Raspberry Pi regulator
+
+Required properties:
+- compatible:	must be "raspberrypi,bcm2835-regulator"
+- firmware:	reference to the raspberrypi pi firmware node
+- regulators: A node that houses a sub-node for each regulator within the
+  device. Each sub-node is identified using the node's name (or the deprecated
+  regulator-compatible property if present), with valid values listed below.
+  The content of each sub-node is defined by the standard binding for
+  regulators; see regulator.txt.
+
+The valid names for regulators are:
+
+  sdhc1, uart0, uart1, usb_hcd, i2c0, i2c1, i2c2, spi, ccp2tx
+
+Example:
+
+	regulator: regulator {
+		compatible = "raspberrypi,bcm2835-regulator";
+		firmware = <&firmware>;
+
+		regulators {
+			sdhc1_reg: sdhc1 {
+				regulator-name = "SDHC1";
+			};
+
+			uart0_reg: uart0 {
+				regulator-name = "UART0";
+			};
+
+			uart1_reg: uart1 {
+				regulator-name = "UART1";
+			};
+
+			usb_hcd_reg: usb_hcd {
+				regulator-name = "USB_HCD";
+			};
+
+			i2c0_reg: i2c0 {
+				regulator-name = "I2C0";
+			};
+
+			i2c1_reg: i2c1 {
+				regulator-name = "I2C1";
+			};
+
+			i2c2_reg: i2c2 {
+				regulator-name = "I2C2";
+			};
+
+			spi_reg: spi {
+				regulator-name = "SPI";
+			};
+
+			ccp2tx_reg: ccp2tx {
+				regulator-name = "CCP2TX";
+			};
+		};
+	};
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 64bccff..6d4df3d 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -546,6 +546,17 @@ config REGULATOR_QCOM_SPMI
 	  Qualcomm SPMI PMICs as a module. The module will be named
 	  "qcom_spmi-regulator".
 
+config REGULATOR_RASPBERRYPI
+	tristate "Raspberry Pi regulator driver"
+	depends on RASPBERRYPI_FIRMWARE
+	help
+	  If you say yes to this option, support will be included for the
+	  regulators found in the firmware of Raspberry Pis.
+
+	  Say M here if you want to include support for the regulators on the
+	  Raspberry Pi as a module. The module will be named
+	  "raspberrypi-regulator".
+
 config REGULATOR_RC5T583
 	tristate "RICOH RC5T583 Power regulators"
 	depends on MFD_RC5T583
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 0f81749..20caea4 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -71,6 +71,7 @@ obj-$(CONFIG_REGULATOR_TPS51632) += tps51632-regulator.o
 obj-$(CONFIG_REGULATOR_PBIAS) += pbias-regulator.o
 obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o
 obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o
+obj-$(CONFIG_REGULATOR_RASPBERRYPI) += raspberrypi-regulator.o
 obj-$(CONFIG_REGULATOR_RC5T583)  += rc5t583-regulator.o
 obj-$(CONFIG_REGULATOR_RK808)   += rk808-regulator.o
 obj-$(CONFIG_REGULATOR_RN5T618) += rn5t618-regulator.o
diff --git a/drivers/regulator/raspberrypi-regulator.c b/drivers/regulator/raspberrypi-regulator.c
new file mode 100644
index 0000000..534d6bd
--- /dev/null
+++ b/drivers/regulator/raspberrypi-regulator.c
@@ -0,0 +1,172 @@
+/*
+ * Raspberry Pi regulator driver
+ *
+ * (C) 2015 Pengutronix, Alexander Aring <aar at pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under  the terms of the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+
+#include <soc/bcm2835/raspberrypi-firmware.h>
+
+#define RPI_REGULATOR(_name, _id, _of_match)	\
+	{					\
+		.name	= _name,		\
+		.id	= _id,			\
+		.of_match = of_match_ptr(_of_match),		\
+		.regulators_node = of_match_ptr("regulators"),	\
+		.ops	= &rpi_regulator_ops,	\
+		.type	= REGULATOR_VOLTAGE,	\
+	}
+
+
+enum {
+	RPI_REGULATOR_SDHC1	= 0,
+	RPI_REGULATOR_UART0	= 1,
+	RPI_REGULATOR_UART1	= 2,
+	RPI_REGULATOR_USB_HCD	= 3,
+	RPI_REGULATOR_I2C0	= 4,
+	RPI_REGULATOR_I2C1	= 5,
+	RPI_REGULATOR_I2C2	= 6,
+	RPI_REGULATOR_SPI	= 7,
+	RPI_REGULATOR_CCP2TX	= 8,
+};
+
+struct rpi_regulator {
+	struct rpi_firmware *fw;
+};
+
+struct rpi_packet {
+	u32 domain;
+	u32 on;
+} __packet;
+
+static inline int rpi_regulator_set_state(struct regulator_dev *rdev,
+					  u32 domain, u32 on)
+{
+	struct rpi_regulator *regulator = rdev_get_drvdata(rdev);
+	struct rpi_packet packet;
+
+	packet.domain = domain;
+	packet.on = on;
+	return rpi_firmware_property(regulator->fw,
+				     RPI_FIRMWARE_SET_POWER_STATE, &packet,
+				     sizeof(packet));
+}
+
+static int rpi_regulator_enable(struct regulator_dev *rdev)
+{
+	return rpi_regulator_set_state(rdev, rdev->desc->id, 1);
+}
+
+static int rpi_regulator_disable(struct regulator_dev *rdev)
+{
+	return rpi_regulator_set_state(rdev, rdev->desc->id, 0);
+}
+
+static int rpi_regulator_is_enabled(struct regulator_dev *rdev)
+{
+	struct rpi_regulator *reg = rdev_get_drvdata(rdev);
+	struct rpi_packet packet;
+	int ret;
+
+	packet.domain = rdev->desc->id;
+	ret = rpi_firmware_property(reg->fw, RPI_FIRMWARE_GET_POWER_STATE,
+				    &packet, sizeof(packet));
+	if (ret < 0)
+		return ret;
+
+	return packet.on & BIT(0);
+}
+
+static const struct regulator_ops rpi_regulator_ops = {
+	.enable = rpi_regulator_enable,
+	.disable = rpi_regulator_disable,
+	.is_enabled = rpi_regulator_is_enabled,
+};
+
+static const struct regulator_desc rpi_regulators[] = {
+	RPI_REGULATOR("SDHC1", RPI_REGULATOR_SDHC1, "sdhc1"),
+	RPI_REGULATOR("UART0", RPI_REGULATOR_UART0, "uart0"),
+	RPI_REGULATOR("UART1", RPI_REGULATOR_UART1, "uart1"),
+	RPI_REGULATOR("USB_HCD", RPI_REGULATOR_USB_HCD, "usb_hcd"),
+	RPI_REGULATOR("I2C0", RPI_REGULATOR_I2C0, "i2c0"),
+	RPI_REGULATOR("I2C1", RPI_REGULATOR_I2C1, "i2c1"),
+	RPI_REGULATOR("I2C2", RPI_REGULATOR_I2C2, "i2c2"),
+	RPI_REGULATOR("SPI", RPI_REGULATOR_SPI, "spi"),
+	RPI_REGULATOR("CCP2TX", RPI_REGULATOR_CCP2TX, "ccp2tx"),
+};
+
+static int rpi_regulator_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct regulator_config cfg = { };
+	struct rpi_regulator *regulator;
+	struct device_node *fw;
+	int i;
+
+	regulator = devm_kzalloc(&pdev->dev, sizeof(struct rpi_regulator),
+				 GFP_KERNEL);
+	if (!regulator)
+		return -ENOMEM;
+
+	fw = of_parse_phandle(pdev->dev.of_node, "firmware", 0);
+	if (!fw) {
+		dev_err(&pdev->dev, "no firmware node\n");
+		return -ENODEV;
+	}
+	regulator->fw = rpi_firmware_get(fw);
+	if (!regulator->fw)
+		return -EPROBE_DEFER;
+
+	cfg.dev = &pdev->dev;
+	cfg.driver_data = regulator;
+	cfg.of_node = np;
+
+	for (i = 0; i < ARRAY_SIZE(rpi_regulators); i++) {
+		struct regulator_init_data *initdata;
+		struct regulator_dev *rdev;
+
+		initdata = of_get_regulator_init_data(&pdev->dev, np,
+						      &rpi_regulators[i]);
+		if (!initdata)
+			return -ENOMEM;
+
+		cfg.init_data = initdata;
+
+		rdev = devm_regulator_register(&pdev->dev, &rpi_regulators[i],
+					       &cfg);
+		if (IS_ERR(rdev))
+			return PTR_ERR(rdev);
+
+	}
+
+	return 0;
+}
+
+static const struct of_device_id rpi_regulator_of_match[] = {
+	{ .compatible = "raspberrypi,bcm2835-regulator" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, pwm_of_match);
+
+static struct platform_driver rpi_regulator_driver = {
+	.driver = {
+		.name = "raspberrypi-regulator",
+		.of_match_table = rpi_regulator_of_match,
+	},
+	.probe = rpi_regulator_probe,
+};
+module_platform_driver(rpi_regulator_driver);
+
+MODULE_AUTHOR("Alexander Aring <aar at pengutronix.de>");
+MODULE_DESCRIPTION("Raspberry Pi regulator driver");
+MODULE_LICENSE("GPL v2");
-- 
2.6.1




More information about the linux-rpi-kernel mailing list