summaryrefslogtreecommitdiffstats
path: root/drivers/regulator
diff options
context:
space:
mode:
authorJean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>2015-01-13 07:33:10 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2015-02-04 15:49:59 +0100
commitf72725e352fd8dfd38d622433dd5f626625b8402 (patch)
tree60fc4074a7790fcf420de6c6cc384bc6ef371347 /drivers/regulator
parent515fefa8a582d8705770e5b8d592fbaae5e7a4b8 (diff)
downloadbarebox-f72725e352fd8dfd38d622433dd5f626625b8402.tar.gz
regulator: add bcm2835 driver
this will allow to handle IP power automatically and not at board level Mainline kernel need this as they do not have the regulator driver support as some IP such as USB are not power on at boot Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'drivers/regulator')
-rw-r--r--drivers/regulator/Kconfig5
-rw-r--r--drivers/regulator/Makefile1
-rw-r--r--drivers/regulator/bcm2835.c149
3 files changed, 155 insertions, 0 deletions
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 4085b3f..05c3f48 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -11,4 +11,9 @@ config REGULATOR_FIXED
This enables a simple fixed regulator. It is used for regulators
which are not software controllable or controllable via gpio.
+config REGULATOR_BCM2835
+ bool
+ depends on ARCH_BCM2835
+ default y
+
endif
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 65e65d8..d663c16 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -1,2 +1,3 @@
obj-$(CONFIG_REGULATOR) += core.o
obj-$(CONFIG_REGULATOR_FIXED) += fixed.o
+obj-$(CONFIG_REGULATOR_BCM2835) += bcm2835.o
diff --git a/drivers/regulator/bcm2835.c b/drivers/regulator/bcm2835.c
new file mode 100644
index 0000000..0ada05d
--- /dev/null
+++ b/drivers/regulator/bcm2835.c
@@ -0,0 +1,149 @@
+/*
+ * bcm2835 regulator support
+ *
+ * Copyright (c) 2015 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * GPLv2 Only
+ */
+#include <common.h>
+#include <malloc.h>
+#include <init.h>
+#include <regulator.h>
+
+#include <mach/mbox.h>
+
+#define REG_DEV(_id, _name) \
+ { \
+ .id = _id, \
+ .devname = _name,\
+ }
+
+static struct regulator_bcm2835 {
+ int id;
+ char *devname;
+
+ struct device_d *dev;
+ struct regulator_dev rdev;
+} regs[] = {
+ REG_DEV(BCM2835_MBOX_POWER_DEVID_SDHCI, "bcm2835_mci0"),
+ REG_DEV(BCM2835_MBOX_POWER_DEVID_UART0, "uart0-pl0110"),
+ REG_DEV(BCM2835_MBOX_POWER_DEVID_UART1, "uart0-pl0111"),
+ REG_DEV(BCM2835_MBOX_POWER_DEVID_USB_HCD, "bcm2835_usb"),
+ REG_DEV(BCM2835_MBOX_POWER_DEVID_I2C0, "bcm2835_i2c0"),
+ REG_DEV(BCM2835_MBOX_POWER_DEVID_I2C1, "bcm2835_i2c1"),
+ REG_DEV(BCM2835_MBOX_POWER_DEVID_I2C2, "bcm2835_i2c2"),
+ REG_DEV(BCM2835_MBOX_POWER_DEVID_SPI, "bcm2835_spi"),
+ REG_DEV(BCM2835_MBOX_POWER_DEVID_CCP2TX, "bcm2835_ccp2tx"),
+};
+
+struct msg_set_power_state {
+ struct bcm2835_mbox_hdr hdr;
+ struct bcm2835_mbox_tag_set_power_state set_power_state;
+ u32 end_tag;
+};
+
+static int regulator_bcm2835_set(struct regulator_bcm2835 *rb, int state)
+{
+ BCM2835_MBOX_STACK_ALIGN(struct msg_set_power_state, msg_pwr);
+ int ret;
+
+ BCM2835_MBOX_INIT_HDR(msg_pwr);
+ BCM2835_MBOX_INIT_TAG(&msg_pwr->set_power_state,
+ SET_POWER_STATE);
+ msg_pwr->set_power_state.body.req.device_id = rb->id;
+ msg_pwr->set_power_state.body.req.state =
+ state |
+ BCM2835_MBOX_SET_POWER_STATE_REQ_WAIT;
+
+ ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN,
+ &msg_pwr->hdr);
+ if (ret) {
+ dev_err(rb->dev ,"bcm2835: Could not set module %u power state\n",
+ rb->id);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int regulator_bcm2835_enable(struct regulator_dev *rdev)
+{
+ struct regulator_bcm2835 *rb = container_of(rdev, struct regulator_bcm2835, rdev);
+
+ return regulator_bcm2835_set(rb, BCM2835_MBOX_SET_POWER_STATE_REQ_ON);
+}
+
+static int regulator_bcm2835_disable(struct regulator_dev *rdev)
+{
+ struct regulator_bcm2835 *rb = container_of(rdev, struct regulator_bcm2835, rdev);
+
+ return regulator_bcm2835_set(rb, BCM2835_MBOX_SET_POWER_STATE_REQ_OFF);
+}
+
+struct msg_get_power_state {
+ struct bcm2835_mbox_hdr hdr;
+ struct bcm2835_mbox_tag_get_power_state get_power_state;
+ u32 end_tag;
+};
+
+static int regulator_bcm2835_is_enabled(struct regulator_dev *rdev)
+{
+ struct regulator_bcm2835 *rb = container_of(rdev, struct regulator_bcm2835, rdev);
+ BCM2835_MBOX_STACK_ALIGN(struct msg_get_power_state, msg_pwr);
+ int ret;
+
+ BCM2835_MBOX_INIT_HDR(msg_pwr);
+ BCM2835_MBOX_INIT_TAG(&msg_pwr->get_power_state,
+ GET_POWER_STATE);
+ msg_pwr->get_power_state.body.req.device_id = rb->id;
+
+ ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN,
+ &msg_pwr->hdr);
+ if (ret) {
+ dev_err(rb->dev ,"bcm2835: Could not get module %u power state\n",
+ rb->id);
+ return ret;
+ }
+
+ return msg_pwr->get_power_state.body.resp.state;
+}
+
+static struct regulator_ops bcm2835_ops = {
+ .enable = regulator_bcm2835_enable,
+ .disable = regulator_bcm2835_disable,
+ .is_enabled = regulator_bcm2835_is_enabled,
+};
+
+static int regulator_bcm2835_probe(struct device_d *dev)
+{
+ struct regulator_bcm2835 *rb;
+ int ret, i;
+
+ for (i = 0; i < ARRAY_SIZE(regs); i++) {
+ rb = &regs[i];
+
+ rb->rdev.ops = &bcm2835_ops;
+ rb->dev = dev;
+
+ ret = dev_regulator_register(&rb->rdev, rb->devname, NULL);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct driver_d regulator_bcm2835_driver = {
+ .name = "regulator-bcm2835",
+ .probe = regulator_bcm2835_probe,
+};
+postcore_platform_driver(regulator_bcm2835_driver);
+
+static int regulator_bcm2835_init(void)
+{
+ add_generic_device("regulator-bcm2835", DEVICE_ID_SINGLE, NULL,
+ 0, 0, 0, NULL);
+
+ return 0;
+}
+postcore_initcall(regulator_bcm2835_init);