Blame view

drivers/regulator/userspace-consumer.c 4.25 KB
2874c5fd2   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
1d98cccf7   Mike Rapoport   regulator: add us...
2
3
4
5
6
7
8
9
10
11
  /*
   * userspace-consumer.c
   *
   * Copyright 2009 CompuLab, Ltd.
   *
   * Author: Mike Rapoport <mike@compulab.co.il>
   *
   * Based of virtual consumer driver:
   *   Copyright 2008 Wolfson Microelectronics PLC.
   *   Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
1d98cccf7   Mike Rapoport   regulator: add us...
12
13
14
15
   */
  
  #include <linux/err.h>
  #include <linux/mutex.h>
65602c32e   Paul Gortmaker   regulator: Add mo...
16
  #include <linux/module.h>
1d98cccf7   Mike Rapoport   regulator: add us...
17
18
19
  #include <linux/platform_device.h>
  #include <linux/regulator/consumer.h>
  #include <linux/regulator/userspace-consumer.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
20
  #include <linux/slab.h>
1d98cccf7   Mike Rapoport   regulator: add us...
21
22
23
24
25
26
27
28
29
30
  
  struct userspace_consumer_data {
  	const char *name;
  
  	struct mutex lock;
  	bool enabled;
  
  	int num_supplies;
  	struct regulator_bulk_data *supplies;
  };
7c314991d   Liam Girdwood   regulator: build ...
31
  static ssize_t reg_show_name(struct device *dev,
1d98cccf7   Mike Rapoport   regulator: add us...
32
33
34
35
36
37
38
  			  struct device_attribute *attr, char *buf)
  {
  	struct userspace_consumer_data *data = dev_get_drvdata(dev);
  
  	return sprintf(buf, "%s
  ", data->name);
  }
7c314991d   Liam Girdwood   regulator: build ...
39
  static ssize_t reg_show_state(struct device *dev,
1d98cccf7   Mike Rapoport   regulator: add us...
40
41
42
43
44
45
46
47
48
49
50
  			  struct device_attribute *attr, char *buf)
  {
  	struct userspace_consumer_data *data = dev_get_drvdata(dev);
  
  	if (data->enabled)
  		return sprintf(buf, "enabled
  ");
  
  	return sprintf(buf, "disabled
  ");
  }
7c314991d   Liam Girdwood   regulator: build ...
51
  static ssize_t reg_set_state(struct device *dev, struct device_attribute *attr,
1d98cccf7   Mike Rapoport   regulator: add us...
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
  			 const char *buf, size_t count)
  {
  	struct userspace_consumer_data *data = dev_get_drvdata(dev);
  	bool enabled;
  	int ret;
  
  	/*
  	 * sysfs_streq() doesn't need the 
  's, but we add them so the strings
  	 * will be shared with show_state(), above.
  	 */
  	if (sysfs_streq(buf, "enabled
  ") || sysfs_streq(buf, "1"))
  		enabled = true;
  	else if (sysfs_streq(buf, "disabled
  ") || sysfs_streq(buf, "0"))
  		enabled = false;
  	else {
  		dev_err(dev, "Configuring invalid mode
  ");
  		return count;
  	}
  
  	mutex_lock(&data->lock);
  	if (enabled != data->enabled) {
  		if (enabled)
  			ret = regulator_bulk_enable(data->num_supplies,
  						    data->supplies);
  		else
  			ret = regulator_bulk_disable(data->num_supplies,
  						     data->supplies);
  
  		if (ret == 0)
  			data->enabled = enabled;
  		else
  			dev_err(dev, "Failed to configure state: %d
  ", ret);
  	}
  	mutex_unlock(&data->lock);
  
  	return count;
  }
7c314991d   Liam Girdwood   regulator: build ...
94
95
  static DEVICE_ATTR(name, 0444, reg_show_name, NULL);
  static DEVICE_ATTR(state, 0644, reg_show_state, reg_set_state);
1d98cccf7   Mike Rapoport   regulator: add us...
96

e9d62698e   Felipe Balbi   regulator: usersp...
97
98
99
100
101
102
103
104
  static struct attribute *attributes[] = {
  	&dev_attr_name.attr,
  	&dev_attr_state.attr,
  	NULL,
  };
  
  static const struct attribute_group attr_group = {
  	.attrs	= attributes,
1d98cccf7   Mike Rapoport   regulator: add us...
105
106
107
108
109
110
  };
  
  static int regulator_userspace_consumer_probe(struct platform_device *pdev)
  {
  	struct regulator_userspace_consumer_data *pdata;
  	struct userspace_consumer_data *drvdata;
e9d62698e   Felipe Balbi   regulator: usersp...
111
  	int ret;
1d98cccf7   Mike Rapoport   regulator: add us...
112

dff91d0b7   Jingoo Han   regulator: use de...
113
  	pdata = dev_get_platdata(&pdev->dev);
1d98cccf7   Mike Rapoport   regulator: add us...
114
115
  	if (!pdata)
  		return -EINVAL;
5abe0c400   Axel Lin   regulator: usersp...
116
117
118
  	drvdata = devm_kzalloc(&pdev->dev,
  			       sizeof(struct userspace_consumer_data),
  			       GFP_KERNEL);
1d98cccf7   Mike Rapoport   regulator: add us...
119
120
121
122
123
124
125
126
  	if (drvdata == NULL)
  		return -ENOMEM;
  
  	drvdata->name = pdata->name;
  	drvdata->num_supplies = pdata->num_supplies;
  	drvdata->supplies = pdata->supplies;
  
  	mutex_init(&drvdata->lock);
5abe0c400   Axel Lin   regulator: usersp...
127
128
  	ret = devm_regulator_bulk_get(&pdev->dev, drvdata->num_supplies,
  				      drvdata->supplies);
1d98cccf7   Mike Rapoport   regulator: add us...
129
130
131
  	if (ret) {
  		dev_err(&pdev->dev, "Failed to get supplies: %d
  ", ret);
5abe0c400   Axel Lin   regulator: usersp...
132
  		return ret;
1d98cccf7   Mike Rapoport   regulator: add us...
133
  	}
e9d62698e   Felipe Balbi   regulator: usersp...
134
135
  	ret = sysfs_create_group(&pdev->dev.kobj, &attr_group);
  	if (ret != 0)
5abe0c400   Axel Lin   regulator: usersp...
136
  		return ret;
1d98cccf7   Mike Rapoport   regulator: add us...
137

e9d62698e   Felipe Balbi   regulator: usersp...
138
  	if (pdata->init_on) {
1d98cccf7   Mike Rapoport   regulator: add us...
139
140
  		ret = regulator_bulk_enable(drvdata->num_supplies,
  					    drvdata->supplies);
e9d62698e   Felipe Balbi   regulator: usersp...
141
142
143
144
145
146
  		if (ret) {
  			dev_err(&pdev->dev,
  				"Failed to set initial state: %d
  ", ret);
  			goto err_enable;
  		}
1d98cccf7   Mike Rapoport   regulator: add us...
147
  	}
e9d62698e   Felipe Balbi   regulator: usersp...
148
  	drvdata->enabled = pdata->init_on;
1d98cccf7   Mike Rapoport   regulator: add us...
149
150
151
  	platform_set_drvdata(pdev, drvdata);
  
  	return 0;
e9d62698e   Felipe Balbi   regulator: usersp...
152
153
  err_enable:
  	sysfs_remove_group(&pdev->dev.kobj, &attr_group);
1d98cccf7   Mike Rapoport   regulator: add us...
154

1d98cccf7   Mike Rapoport   regulator: add us...
155
156
157
158
159
160
  	return ret;
  }
  
  static int regulator_userspace_consumer_remove(struct platform_device *pdev)
  {
  	struct userspace_consumer_data *data = platform_get_drvdata(pdev);
1d98cccf7   Mike Rapoport   regulator: add us...
161

e9d62698e   Felipe Balbi   regulator: usersp...
162
  	sysfs_remove_group(&pdev->dev.kobj, &attr_group);
1d98cccf7   Mike Rapoport   regulator: add us...
163
164
165
  
  	if (data->enabled)
  		regulator_bulk_disable(data->num_supplies, data->supplies);
1d98cccf7   Mike Rapoport   regulator: add us...
166
167
168
169
170
171
172
173
174
175
  	return 0;
  }
  
  static struct platform_driver regulator_userspace_consumer_driver = {
  	.probe		= regulator_userspace_consumer_probe,
  	.remove		= regulator_userspace_consumer_remove,
  	.driver		= {
  		.name		= "reg-userspace-consumer",
  	},
  };
005d610f2   Axel Lin   regulator: Conver...
176
  module_platform_driver(regulator_userspace_consumer_driver);
1d98cccf7   Mike Rapoport   regulator: add us...
177
178
179
180
  
  MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
  MODULE_DESCRIPTION("Userspace consumer for voltage and current regulators");
  MODULE_LICENSE("GPL");