diff options
Diffstat (limited to 'drivers/regulator')
-rw-r--r-- | drivers/regulator/Kconfig | 5 | ||||
-rw-r--r-- | drivers/regulator/Makefile | 1 | ||||
-rw-r--r-- | drivers/regulator/bcm2835.c | 149 |
3 files changed, 155 insertions, 0 deletions
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 4085b3fd6e..05c3f48980 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 65e65d8150..d663c16b1a 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 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 = ®s[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); |