9
0
Fork 0
barebox/drivers/regulator/bcm2835.c

150 lines
3.7 KiB
C

/*
* 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);