summaryrefslogtreecommitdiffstats
path: root/drivers/regulator/bcm2835.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/regulator/bcm2835.c')
-rw-r--r--drivers/regulator/bcm2835.c149
1 files changed, 149 insertions, 0 deletions
diff --git a/drivers/regulator/bcm2835.c b/drivers/regulator/bcm2835.c
new file mode 100644
index 0000000000..0ada05db16
--- /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);