~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to drivers/regulator/userspace-consumer.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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/module.h>
 
22
#include <linux/platform_device.h>
 
23
#include <linux/regulator/consumer.h>
 
24
#include <linux/regulator/userspace-consumer.h>
 
25
#include <linux/slab.h>
 
26
 
 
27
struct userspace_consumer_data {
 
28
        const char *name;
 
29
 
 
30
        struct mutex lock;
 
31
        bool enabled;
 
32
 
 
33
        int num_supplies;
 
34
        struct regulator_bulk_data *supplies;
 
35
};
 
36
 
 
37
static ssize_t reg_show_name(struct device *dev,
 
38
                          struct device_attribute *attr, char *buf)
 
39
{
 
40
        struct userspace_consumer_data *data = dev_get_drvdata(dev);
 
41
 
 
42
        return sprintf(buf, "%s\n", data->name);
 
43
}
 
44
 
 
45
static ssize_t reg_show_state(struct device *dev,
 
46
                          struct device_attribute *attr, char *buf)
 
47
{
 
48
        struct userspace_consumer_data *data = dev_get_drvdata(dev);
 
49
 
 
50
        if (data->enabled)
 
51
                return sprintf(buf, "enabled\n");
 
52
 
 
53
        return sprintf(buf, "disabled\n");
 
54
}
 
55
 
 
56
static ssize_t reg_set_state(struct device *dev, struct device_attribute *attr,
 
57
                         const char *buf, size_t count)
 
58
{
 
59
        struct userspace_consumer_data *data = dev_get_drvdata(dev);
 
60
        bool enabled;
 
61
        int ret;
 
62
 
 
63
        /*
 
64
         * sysfs_streq() doesn't need the \n's, but we add them so the strings
 
65
         * will be shared with show_state(), above.
 
66
         */
 
67
        if (sysfs_streq(buf, "enabled\n") || sysfs_streq(buf, "1"))
 
68
                enabled = true;
 
69
        else if (sysfs_streq(buf, "disabled\n") || sysfs_streq(buf, "0"))
 
70
                enabled = false;
 
71
        else {
 
72
                dev_err(dev, "Configuring invalid mode\n");
 
73
                return count;
 
74
        }
 
75
 
 
76
        mutex_lock(&data->lock);
 
77
        if (enabled != data->enabled) {
 
78
                if (enabled)
 
79
                        ret = regulator_bulk_enable(data->num_supplies,
 
80
                                                    data->supplies);
 
81
                else
 
82
                        ret = regulator_bulk_disable(data->num_supplies,
 
83
                                                     data->supplies);
 
84
 
 
85
                if (ret == 0)
 
86
                        data->enabled = enabled;
 
87
                else
 
88
                        dev_err(dev, "Failed to configure state: %d\n", ret);
 
89
        }
 
90
        mutex_unlock(&data->lock);
 
91
 
 
92
        return count;
 
93
}
 
94
 
 
95
static DEVICE_ATTR(name, 0444, reg_show_name, NULL);
 
96
static DEVICE_ATTR(state, 0644, reg_show_state, reg_set_state);
 
97
 
 
98
static struct attribute *attributes[] = {
 
99
        &dev_attr_name.attr,
 
100
        &dev_attr_state.attr,
 
101
        NULL,
 
102
};
 
103
 
 
104
static const struct attribute_group attr_group = {
 
105
        .attrs  = attributes,
 
106
};
 
107
 
 
108
static int regulator_userspace_consumer_probe(struct platform_device *pdev)
 
109
{
 
110
        struct regulator_userspace_consumer_data *pdata;
 
111
        struct userspace_consumer_data *drvdata;
 
112
        int ret;
 
113
 
 
114
        pdata = pdev->dev.platform_data;
 
115
        if (!pdata)
 
116
                return -EINVAL;
 
117
 
 
118
        drvdata = kzalloc(sizeof(struct userspace_consumer_data), GFP_KERNEL);
 
119
        if (drvdata == NULL)
 
120
                return -ENOMEM;
 
121
 
 
122
        drvdata->name = pdata->name;
 
123
        drvdata->num_supplies = pdata->num_supplies;
 
124
        drvdata->supplies = pdata->supplies;
 
125
 
 
126
        mutex_init(&drvdata->lock);
 
127
 
 
128
        ret = regulator_bulk_get(&pdev->dev, drvdata->num_supplies,
 
129
                                 drvdata->supplies);
 
130
        if (ret) {
 
131
                dev_err(&pdev->dev, "Failed to get supplies: %d\n", ret);
 
132
                goto err_alloc_supplies;
 
133
        }
 
134
 
 
135
        ret = sysfs_create_group(&pdev->dev.kobj, &attr_group);
 
136
        if (ret != 0)
 
137
                goto err_create_attrs;
 
138
 
 
139
        if (pdata->init_on) {
 
140
                ret = regulator_bulk_enable(drvdata->num_supplies,
 
141
                                            drvdata->supplies);
 
142
                if (ret) {
 
143
                        dev_err(&pdev->dev,
 
144
                                "Failed to set initial state: %d\n", ret);
 
145
                        goto err_enable;
 
146
                }
 
147
        }
 
148
 
 
149
        drvdata->enabled = pdata->init_on;
 
150
        platform_set_drvdata(pdev, drvdata);
 
151
 
 
152
        return 0;
 
153
 
 
154
err_enable:
 
155
        sysfs_remove_group(&pdev->dev.kobj, &attr_group);
 
156
 
 
157
err_create_attrs:
 
158
        regulator_bulk_free(drvdata->num_supplies, drvdata->supplies);
 
159
 
 
160
err_alloc_supplies:
 
161
        kfree(drvdata);
 
162
        return ret;
 
163
}
 
164
 
 
165
static int regulator_userspace_consumer_remove(struct platform_device *pdev)
 
166
{
 
167
        struct userspace_consumer_data *data = platform_get_drvdata(pdev);
 
168
 
 
169
        sysfs_remove_group(&pdev->dev.kobj, &attr_group);
 
170
 
 
171
        if (data->enabled)
 
172
                regulator_bulk_disable(data->num_supplies, data->supplies);
 
173
 
 
174
        regulator_bulk_free(data->num_supplies, data->supplies);
 
175
        kfree(data);
 
176
 
 
177
        return 0;
 
178
}
 
179
 
 
180
static struct platform_driver regulator_userspace_consumer_driver = {
 
181
        .probe          = regulator_userspace_consumer_probe,
 
182
        .remove         = regulator_userspace_consumer_remove,
 
183
        .driver         = {
 
184
                .name           = "reg-userspace-consumer",
 
185
        },
 
186
};
 
187
 
 
188
 
 
189
static int __init regulator_userspace_consumer_init(void)
 
190
{
 
191
        return platform_driver_register(&regulator_userspace_consumer_driver);
 
192
}
 
193
module_init(regulator_userspace_consumer_init);
 
194
 
 
195
static void __exit regulator_userspace_consumer_exit(void)
 
196
{
 
197
        platform_driver_unregister(&regulator_userspace_consumer_driver);
 
198
}
 
199
module_exit(regulator_userspace_consumer_exit);
 
200
 
 
201
MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
 
202
MODULE_DESCRIPTION("Userspace consumer for voltage and current regulators");
 
203
MODULE_LICENSE("GPL");