[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