aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Rapoport <mike@compulab.co.il>2009-04-26 09:49:39 -0400
committerLiam Girdwood <lrg@slimlogic.co.uk>2009-06-15 06:18:22 -0400
commit1d98cccf7f8b944ba4ea56d14bbb7c2eeee59bfe (patch)
tree079c8db0e879dbddcec7658dee610ade43d86c67
parent55f4fa4e33e90c6b25b4c8ed038392a73b654fef (diff)
regulator: add userspace-consumer driver
The userspace-consumer driver allows control of voltage and current regulator state from userspace. This is required for fine-grained power management of devices that are completely controller by userspace applications, e.g. a GPS transciever connected to a serial port. Signed-off-by: Mike Rapoport <mike@compulab.co.il> Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Liam Girdwood <lrg@slimlogic.co.uk>
-rw-r--r--drivers/regulator/Kconfig10
-rw-r--r--drivers/regulator/Makefile1
-rw-r--r--drivers/regulator/userspace-consumer.c200
-rw-r--r--include/linux/regulator/userspace-consumer.h25
4 files changed, 236 insertions, 0 deletions
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 707da4d23537..5bec17cf1d5c 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -47,6 +47,16 @@ config REGULATOR_VIRTUAL_CONSUMER
47 47
48 If unsure, say no. 48 If unsure, say no.
49 49
50config REGULATOR_USERSPACE_CONSUMER
51 tristate "Userspace regulator consumer support"
52 default n
53 help
54 There are some classes of devices that are controlled entirely
55 from user space. Usersapce consumer driver provides ability to
56 control power supplies for such devices.
57
58 If unsure, say no.
59
50config REGULATOR_BQ24022 60config REGULATOR_BQ24022
51 tristate "TI bq24022 Dual Input 1-Cell Li-Ion Charger IC" 61 tristate "TI bq24022 Dual Input 1-Cell Li-Ion Charger IC"
52 default n 62 default n
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 1d7de87a8e1e..faf7bcc1af98 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -6,6 +6,7 @@
6obj-$(CONFIG_REGULATOR) += core.o 6obj-$(CONFIG_REGULATOR) += core.o
7obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o 7obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o
8obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o 8obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o
9obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o
9 10
10obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o 11obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o
11obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o 12obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o
diff --git a/drivers/regulator/userspace-consumer.c b/drivers/regulator/userspace-consumer.c
new file mode 100644
index 000000000000..71fcf9df00f6
--- /dev/null
+++ b/drivers/regulator/userspace-consumer.c
@@ -0,0 +1,200 @@
1/*
2 * userspace-consumer.c
3 *
4 * Copyright 2009 CompuLab, Ltd.
5 *
6 * Author: Mike Rapoport <mike@compulab.co.il>
7 *
8 * Based of virtual consumer driver:
9 * Copyright 2008 Wolfson Microelectronics PLC.
10 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License as
14 * published by the Free Software Foundation; either version 2 of the
15 * License, or (at your option) any later version.
16 *
17 */
18
19#include <linux/err.h>
20#include <linux/mutex.h>
21#include <linux/platform_device.h>
22#include <linux/regulator/consumer.h>
23#include <linux/regulator/userspace-consumer.h>
24
25struct userspace_consumer_data {
26 const char *name;
27
28 struct mutex lock;
29 bool enabled;
30
31 int num_supplies;
32 struct regulator_bulk_data *supplies;
33};
34
35static ssize_t show_name(struct device *dev,
36 struct device_attribute *attr, char *buf)
37{
38 struct userspace_consumer_data *data = dev_get_drvdata(dev);
39
40 return sprintf(buf, "%s\n", data->name);
41}
42
43static ssize_t show_state(struct device *dev,
44 struct device_attribute *attr, char *buf)
45{
46 struct userspace_consumer_data *data = dev_get_drvdata(dev);
47
48 if (data->enabled)
49 return sprintf(buf, "enabled\n");
50
51 return sprintf(buf, "disabled\n");
52}
53
54static ssize_t set_state(struct device *dev, struct device_attribute *attr,
55 const char *buf, size_t count)
56{
57 struct userspace_consumer_data *data = dev_get_drvdata(dev);
58 bool enabled;
59 int ret;
60
61 /*
62 * sysfs_streq() doesn't need the \n's, but we add them so the strings
63 * will be shared with show_state(), above.
64 */
65 if (sysfs_streq(buf, "enabled\n") || sysfs_streq(buf, "1"))
66 enabled = true;
67 else if (sysfs_streq(buf, "disabled\n") || sysfs_streq(buf, "0"))
68 enabled = false;
69 else {
70 dev_err(dev, "Configuring invalid mode\n");
71 return count;
72 }
73
74 mutex_lock(&data->lock);
75 if (enabled != data->enabled) {
76 if (enabled)
77 ret = regulator_bulk_enable(data->num_supplies,
78 data->supplies);
79 else
80 ret = regulator_bulk_disable(data->num_supplies,
81 data->supplies);
82
83 if (ret == 0)
84 data->enabled = enabled;
85 else
86 dev_err(dev, "Failed to configure state: %d\n", ret);
87 }
88 mutex_unlock(&data->lock);
89
90 return count;
91}
92
93static DEVICE_ATTR(name, 0444, show_name, NULL);
94static DEVICE_ATTR(state, 0644, show_state, set_state);
95
96static struct device_attribute *attributes[] = {
97 &dev_attr_name,
98 &dev_attr_state,
99};
100
101static int regulator_userspace_consumer_probe(struct platform_device *pdev)
102{
103 struct regulator_userspace_consumer_data *pdata;
104 struct userspace_consumer_data *drvdata;
105 int ret, i;
106
107 pdata = pdev->dev.platform_data;
108 if (!pdata)
109 return -EINVAL;
110
111 drvdata = kzalloc(sizeof(struct userspace_consumer_data), GFP_KERNEL);
112 if (drvdata == NULL)
113 return -ENOMEM;
114
115 drvdata->name = pdata->name;
116 drvdata->num_supplies = pdata->num_supplies;
117 drvdata->supplies = pdata->supplies;
118
119 mutex_init(&drvdata->lock);
120
121 ret = regulator_bulk_get(&pdev->dev, drvdata->num_supplies,
122 drvdata->supplies);
123 if (ret) {
124 dev_err(&pdev->dev, "Failed to get supplies: %d\n", ret);
125 goto err_alloc_supplies;
126 }
127
128 for (i = 0; i < ARRAY_SIZE(attributes); i++) {
129 ret = device_create_file(&pdev->dev, attributes[i]);
130 if (ret != 0)
131 goto err_create_attrs;
132 }
133
134 if (pdata->init_on)
135 ret = regulator_bulk_enable(drvdata->num_supplies,
136 drvdata->supplies);
137
138 drvdata->enabled = pdata->init_on;
139
140 if (ret) {
141 dev_err(&pdev->dev, "Failed to set initial state: %d\n", ret);
142 goto err_create_attrs;
143 }
144
145 platform_set_drvdata(pdev, drvdata);
146
147 return 0;
148
149err_create_attrs:
150 for (i = 0; i < ARRAY_SIZE(attributes); i++)
151 device_remove_file(&pdev->dev, attributes[i]);
152
153 regulator_bulk_free(drvdata->num_supplies, drvdata->supplies);
154
155err_alloc_supplies:
156 kfree(drvdata);
157 return ret;
158}
159
160static int regulator_userspace_consumer_remove(struct platform_device *pdev)
161{
162 struct userspace_consumer_data *data = platform_get_drvdata(pdev);
163 int i;
164
165 for (i = 0; i < ARRAY_SIZE(attributes); i++)
166 device_remove_file(&pdev->dev, attributes[i]);
167
168 if (data->enabled)
169 regulator_bulk_disable(data->num_supplies, data->supplies);
170
171 regulator_bulk_free(data->num_supplies, data->supplies);
172 kfree(data);
173
174 return 0;
175}
176
177static struct platform_driver regulator_userspace_consumer_driver = {
178 .probe = regulator_userspace_consumer_probe,
179 .remove = regulator_userspace_consumer_remove,
180 .driver = {
181 .name = "reg-userspace-consumer",
182 },
183};
184
185
186static int __init regulator_userspace_consumer_init(void)
187{
188 return platform_driver_register(&regulator_userspace_consumer_driver);
189}
190module_init(regulator_userspace_consumer_init);
191
192static void __exit regulator_userspace_consumer_exit(void)
193{
194 platform_driver_unregister(&regulator_userspace_consumer_driver);
195}
196module_exit(regulator_userspace_consumer_exit);
197
198MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
199MODULE_DESCRIPTION("Userspace consumer for voltage and current regulators");
200MODULE_LICENSE("GPL");
diff --git a/include/linux/regulator/userspace-consumer.h b/include/linux/regulator/userspace-consumer.h
new file mode 100644
index 000000000000..b4554ce9d4bb
--- /dev/null
+++ b/include/linux/regulator/userspace-consumer.h
@@ -0,0 +1,25 @@
1#ifndef __REGULATOR_PLATFORM_CONSUMER_H_
2#define __REGULATOR_PLATFORM_CONSUMER_H_
3
4struct regulator_consumer_supply;
5
6/**
7 * struct regulator_userspace_consumer_data - line consumer
8 * initialisation data.
9 *
10 * @name: Name for the consumer line
11 * @num_supplies: Number of supplies feeding the line
12 * @supplies: Supplies configuration.
13 * @init_on: Set if the regulators supplying the line should be
14 * enabled during initialisation
15 */
16struct regulator_userspace_consumer_data {
17 const char *name;
18
19 int num_supplies;
20 struct regulator_bulk_data *supplies;
21
22 bool init_on;
23};
24
25#endif /* __REGULATOR_PLATFORM_CONSUMER_H_ */