summaryrefslogtreecommitdiffstats
path: root/drivers/regulator/bcm2835.c
blob: ea7cf7fe1ed5824c2d18558e88129f1a96acecf3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/*
 * 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;
	struct regulator_desc rdesc;
} 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;
}

const 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->rdesc.ops = &bcm2835_ops;
		rb->rdev.desc = &rb->rdesc;
		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);