Blame view

drivers/gpio/gpiolib-sysfs.c 19.4 KB
dae5f0afc   Linus Walleij   gpio: Use SPDX he...
1
  // SPDX-License-Identifier: GPL-2.0
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
2
3
4
5
6
7
8
9
  #include <linux/idr.h>
  #include <linux/mutex.h>
  #include <linux/device.h>
  #include <linux/sysfs.h>
  #include <linux/gpio/consumer.h>
  #include <linux/gpio/driver.h>
  #include <linux/interrupt.h>
  #include <linux/kdev_t.h>
c43960fbc   Johan Hovold   gpio: sysfs: add ...
10
  #include <linux/slab.h>
1efba35af   Christophe Leroy   gpio: sysfs: avoi...
11
  #include <linux/ctype.h>
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
12
13
  
  #include "gpiolib.h"
ef087d8e9   Kent Gibson   gpiolib: move gpi...
14
  #include "gpiolib-sysfs.h"
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
15

cef1717b7   Johan Hovold   gpio: sysfs: move...
16
17
18
19
  #define GPIO_IRQF_TRIGGER_FALLING	BIT(0)
  #define GPIO_IRQF_TRIGGER_RISING	BIT(1)
  #define GPIO_IRQF_TRIGGER_BOTH		(GPIO_IRQF_TRIGGER_FALLING | \
  					 GPIO_IRQF_TRIGGER_RISING)
c43960fbc   Johan Hovold   gpio: sysfs: add ...
20
21
  struct gpiod_data {
  	struct gpio_desc *desc;
6ffcb7971   Johan Hovold   gpio: sysfs: use ...
22
23
  
  	struct mutex mutex;
a08f5c21f   Johan Hovold   gpio: sysfs: clea...
24
  	struct kernfs_node *value_kn;
2ec74a959   Johan Hovold   gpio: sysfs: spli...
25
  	int irq;
cef1717b7   Johan Hovold   gpio: sysfs: move...
26
  	unsigned char irq_flags;
427fdeef5   Johan Hovold   gpio: sysfs: remo...
27
28
  
  	bool direction_can_change;
c43960fbc   Johan Hovold   gpio: sysfs: add ...
29
  };
6ffcb7971   Johan Hovold   gpio: sysfs: use ...
30
31
32
  /*
   * Lock to serialise gpiod export and unexport, and prevent re-export of
   * gpiod whose chip is being unregistered.
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
   */
  static DEFINE_MUTEX(sysfs_lock);
  
  /*
   * /sys/class/gpio/gpioN... only for GPIOs that are exported
   *   /direction
   *      * MAY BE OMITTED if kernel won't allow direction changes
   *      * is read/write as "in" or "out"
   *      * may also be written as "high" or "low", initializing
   *        output value as specified ("out" implies "low")
   *   /value
   *      * always readable, subject to hardware behavior
   *      * may be writable, as zero/nonzero
   *   /edge
   *      * configures behavior of poll(2) on /value
   *      * available only if pin can generate IRQs on input
   *      * is read/write as "none", "falling", "rising", or "both"
   *   /active_low
   *      * configures polarity of /value
   *      * is read/write as zero/nonzero
   *      * also affects existing and subsequent "falling" and "rising"
   *        /edge configuration
   */
6beac9d1a   Johan Hovold   gpio: sysfs: use ...
56
  static ssize_t direction_show(struct device *dev,
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
57
58
  		struct device_attribute *attr, char *buf)
  {
c43960fbc   Johan Hovold   gpio: sysfs: add ...
59
60
  	struct gpiod_data *data = dev_get_drvdata(dev);
  	struct gpio_desc *desc = data->desc;
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
61
  	ssize_t			status;
6ffcb7971   Johan Hovold   gpio: sysfs: use ...
62
  	mutex_lock(&data->mutex);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
63

f0b7866a0   Johan Hovold   gpio: sysfs: remo...
64
65
66
  	gpiod_get_direction(desc);
  	status = sprintf(buf, "%s
  ",
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
67
68
  			test_bit(FLAG_IS_OUT, &desc->flags)
  				? "out" : "in");
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
69

6ffcb7971   Johan Hovold   gpio: sysfs: use ...
70
  	mutex_unlock(&data->mutex);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
71
72
  	return status;
  }
6beac9d1a   Johan Hovold   gpio: sysfs: use ...
73
  static ssize_t direction_store(struct device *dev,
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
74
75
  		struct device_attribute *attr, const char *buf, size_t size)
  {
c43960fbc   Johan Hovold   gpio: sysfs: add ...
76
77
  	struct gpiod_data *data = dev_get_drvdata(dev);
  	struct gpio_desc *desc = data->desc;
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
78
  	ssize_t			status;
6ffcb7971   Johan Hovold   gpio: sysfs: use ...
79
  	mutex_lock(&data->mutex);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
80

f0b7866a0   Johan Hovold   gpio: sysfs: remo...
81
  	if (sysfs_streq(buf, "high"))
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
82
83
84
85
86
87
88
  		status = gpiod_direction_output_raw(desc, 1);
  	else if (sysfs_streq(buf, "out") || sysfs_streq(buf, "low"))
  		status = gpiod_direction_output_raw(desc, 0);
  	else if (sysfs_streq(buf, "in"))
  		status = gpiod_direction_input(desc);
  	else
  		status = -EINVAL;
6ffcb7971   Johan Hovold   gpio: sysfs: use ...
89
  	mutex_unlock(&data->mutex);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
90
91
  	return status ? : size;
  }
6beac9d1a   Johan Hovold   gpio: sysfs: use ...
92
  static DEVICE_ATTR_RW(direction);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
93

6beac9d1a   Johan Hovold   gpio: sysfs: use ...
94
  static ssize_t value_show(struct device *dev,
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
95
96
  		struct device_attribute *attr, char *buf)
  {
c43960fbc   Johan Hovold   gpio: sysfs: add ...
97
98
  	struct gpiod_data *data = dev_get_drvdata(dev);
  	struct gpio_desc *desc = data->desc;
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
99
  	ssize_t			status;
6ffcb7971   Johan Hovold   gpio: sysfs: use ...
100
  	mutex_lock(&data->mutex);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
101

9295c0125   Christophe Leroy   gpio: sysfs: corr...
102
103
104
  	status = gpiod_get_value_cansleep(desc);
  	if (status < 0)
  		goto err;
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
105

7a94b88cb   Christophe Leroy   gpio: sysfs: don'...
106
107
108
109
  	buf[0] = '0' + status;
  	buf[1] = '
  ';
  	status = 2;
9295c0125   Christophe Leroy   gpio: sysfs: corr...
110
  err:
6ffcb7971   Johan Hovold   gpio: sysfs: use ...
111
  	mutex_unlock(&data->mutex);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
112
113
  	return status;
  }
6beac9d1a   Johan Hovold   gpio: sysfs: use ...
114
  static ssize_t value_store(struct device *dev,
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
115
116
  		struct device_attribute *attr, const char *buf, size_t size)
  {
c43960fbc   Johan Hovold   gpio: sysfs: add ...
117
118
  	struct gpiod_data *data = dev_get_drvdata(dev);
  	struct gpio_desc *desc = data->desc;
1efba35af   Christophe Leroy   gpio: sysfs: avoi...
119
  	ssize_t status = 0;
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
120

6ffcb7971   Johan Hovold   gpio: sysfs: use ...
121
  	mutex_lock(&data->mutex);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
122

f0b7866a0   Johan Hovold   gpio: sysfs: remo...
123
  	if (!test_bit(FLAG_IS_OUT, &desc->flags)) {
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
124
  		status = -EPERM;
f0b7866a0   Johan Hovold   gpio: sysfs: remo...
125
  	} else {
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
126
  		long		value;
1efba35af   Christophe Leroy   gpio: sysfs: avoi...
127
128
129
130
131
132
  		if (size <= 2 && isdigit(buf[0]) &&
  		    (size == 1 || buf[1] == '
  '))
  			value = buf[0] - '0';
  		else
  			status = kstrtol(buf, 0, &value);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
133
134
135
136
137
  		if (status == 0) {
  			gpiod_set_value_cansleep(desc, value);
  			status = size;
  		}
  	}
6ffcb7971   Johan Hovold   gpio: sysfs: use ...
138
  	mutex_unlock(&data->mutex);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
139
140
  	return status;
  }
7fda9100b   Christophe Leroy   gpio: sysfs: chan...
141
  static DEVICE_ATTR_PREALLOC(value, S_IWUSR | S_IRUGO, value_show, value_store);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
142
143
144
  
  static irqreturn_t gpio_sysfs_irq(int irq, void *priv)
  {
a08f5c21f   Johan Hovold   gpio: sysfs: clea...
145
146
147
  	struct gpiod_data *data = priv;
  
  	sysfs_notify_dirent(data->value_kn);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
148

0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
149
150
  	return IRQ_HANDLED;
  }
6ffcb7971   Johan Hovold   gpio: sysfs: use ...
151
  /* Caller holds gpiod-data mutex. */
cef1717b7   Johan Hovold   gpio: sysfs: move...
152
  static int gpio_sysfs_request_irq(struct device *dev, unsigned char flags)
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
153
  {
0f6285080   Johan Hovold   gpio: sysfs: remo...
154
155
  	struct gpiod_data	*data = dev_get_drvdata(dev);
  	struct gpio_desc	*desc = data->desc;
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
156
  	unsigned long		irq_flags;
2ec74a959   Johan Hovold   gpio: sysfs: spli...
157
  	int			ret;
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
158

2ec74a959   Johan Hovold   gpio: sysfs: spli...
159
160
  	data->irq = gpiod_to_irq(desc);
  	if (data->irq < 0)
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
161
  		return -EIO;
2ec74a959   Johan Hovold   gpio: sysfs: spli...
162
163
164
  	data->value_kn = sysfs_get_dirent(dev->kobj.sd, "value");
  	if (!data->value_kn)
  		return -ENODEV;
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
165
166
  
  	irq_flags = IRQF_SHARED;
cef1717b7   Johan Hovold   gpio: sysfs: move...
167
  	if (flags & GPIO_IRQF_TRIGGER_FALLING)
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
168
169
  		irq_flags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ?
  			IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING;
cef1717b7   Johan Hovold   gpio: sysfs: move...
170
  	if (flags & GPIO_IRQF_TRIGGER_RISING)
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
171
172
  		irq_flags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ?
  			IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING;
52176d0d3   Johan Hovold   gpio: sysfs: fix ...
173
174
175
176
177
178
179
180
  	/*
  	 * FIXME: This should be done in the irq_request_resources callback
  	 *        when the irq is requested, but a few drivers currently fail
  	 *        to do so.
  	 *
  	 *        Remove this redundant call (along with the corresponding
  	 *        unlock) when those drivers have been fixed.
  	 */
fdeb8e154   Linus Walleij   gpio: reflect bas...
181
  	ret = gpiochip_lock_as_irq(desc->gdev->chip, gpio_chip_hwgpio(desc));
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
182
  	if (ret < 0)
2ec74a959   Johan Hovold   gpio: sysfs: spli...
183
  		goto err_put_kn;
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
184

2ec74a959   Johan Hovold   gpio: sysfs: spli...
185
  	ret = request_any_context_irq(data->irq, gpio_sysfs_irq, irq_flags,
a08f5c21f   Johan Hovold   gpio: sysfs: clea...
186
  				"gpiolib", data);
52176d0d3   Johan Hovold   gpio: sysfs: fix ...
187
188
  	if (ret < 0)
  		goto err_unlock;
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
189

cef1717b7   Johan Hovold   gpio: sysfs: move...
190
  	data->irq_flags = flags;
2ec74a959   Johan Hovold   gpio: sysfs: spli...
191

0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
192
  	return 0;
52176d0d3   Johan Hovold   gpio: sysfs: fix ...
193
  err_unlock:
fdeb8e154   Linus Walleij   gpio: reflect bas...
194
  	gpiochip_unlock_as_irq(desc->gdev->chip, gpio_chip_hwgpio(desc));
2ec74a959   Johan Hovold   gpio: sysfs: spli...
195
196
  err_put_kn:
  	sysfs_put(data->value_kn);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
197
198
  	return ret;
  }
6ffcb7971   Johan Hovold   gpio: sysfs: use ...
199
200
201
202
  /*
   * Caller holds gpiod-data mutex (unless called after class-device
   * deregistration).
   */
2ec74a959   Johan Hovold   gpio: sysfs: spli...
203
204
205
206
  static void gpio_sysfs_free_irq(struct device *dev)
  {
  	struct gpiod_data *data = dev_get_drvdata(dev);
  	struct gpio_desc *desc = data->desc;
cef1717b7   Johan Hovold   gpio: sysfs: move...
207
  	data->irq_flags = 0;
2ec74a959   Johan Hovold   gpio: sysfs: spli...
208
  	free_irq(data->irq, data);
fdeb8e154   Linus Walleij   gpio: reflect bas...
209
  	gpiochip_unlock_as_irq(desc->gdev->chip, gpio_chip_hwgpio(desc));
2ec74a959   Johan Hovold   gpio: sysfs: spli...
210
211
  	sysfs_put(data->value_kn);
  }
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
212
213
  static const struct {
  	const char *name;
cef1717b7   Johan Hovold   gpio: sysfs: move...
214
  	unsigned char flags;
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
215
216
  } trigger_types[] = {
  	{ "none",    0 },
cef1717b7   Johan Hovold   gpio: sysfs: move...
217
218
219
  	{ "falling", GPIO_IRQF_TRIGGER_FALLING },
  	{ "rising",  GPIO_IRQF_TRIGGER_RISING },
  	{ "both",    GPIO_IRQF_TRIGGER_BOTH },
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
220
  };
6beac9d1a   Johan Hovold   gpio: sysfs: use ...
221
  static ssize_t edge_show(struct device *dev,
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
222
223
  		struct device_attribute *attr, char *buf)
  {
c43960fbc   Johan Hovold   gpio: sysfs: add ...
224
  	struct gpiod_data *data = dev_get_drvdata(dev);
f0b7866a0   Johan Hovold   gpio: sysfs: remo...
225
226
  	ssize_t	status = 0;
  	int i;
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
227

6ffcb7971   Johan Hovold   gpio: sysfs: use ...
228
  	mutex_lock(&data->mutex);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
229

f0b7866a0   Johan Hovold   gpio: sysfs: remo...
230
  	for (i = 0; i < ARRAY_SIZE(trigger_types); i++) {
cef1717b7   Johan Hovold   gpio: sysfs: move...
231
  		if (data->irq_flags == trigger_types[i].flags) {
f0b7866a0   Johan Hovold   gpio: sysfs: remo...
232
233
234
235
  			status = sprintf(buf, "%s
  ", trigger_types[i].name);
  			break;
  		}
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
236
  	}
6ffcb7971   Johan Hovold   gpio: sysfs: use ...
237
  	mutex_unlock(&data->mutex);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
238
239
  	return status;
  }
6beac9d1a   Johan Hovold   gpio: sysfs: use ...
240
  static ssize_t edge_store(struct device *dev,
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
241
242
  		struct device_attribute *attr, const char *buf, size_t size)
  {
b91e18076   Johan Hovold   gpio: sysfs: only...
243
  	struct gpiod_data *data = dev_get_drvdata(dev);
cef1717b7   Johan Hovold   gpio: sysfs: move...
244
  	unsigned char flags;
2ec74a959   Johan Hovold   gpio: sysfs: spli...
245
  	ssize_t	status = size;
e4339ce32   Johan Hovold   gpio: sysfs: clea...
246
  	int i;
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
247

e4339ce32   Johan Hovold   gpio: sysfs: clea...
248
  	for (i = 0; i < ARRAY_SIZE(trigger_types); i++) {
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
249
  		if (sysfs_streq(trigger_types[i].name, buf))
e4339ce32   Johan Hovold   gpio: sysfs: clea...
250
251
252
253
254
  			break;
  	}
  
  	if (i == ARRAY_SIZE(trigger_types))
  		return -EINVAL;
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
255

b91e18076   Johan Hovold   gpio: sysfs: only...
256
  	flags = trigger_types[i].flags;
6ffcb7971   Johan Hovold   gpio: sysfs: use ...
257
  	mutex_lock(&data->mutex);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
258

cef1717b7   Johan Hovold   gpio: sysfs: move...
259
  	if (flags == data->irq_flags) {
b91e18076   Johan Hovold   gpio: sysfs: only...
260
261
262
  		status = size;
  		goto out_unlock;
  	}
cef1717b7   Johan Hovold   gpio: sysfs: move...
263
  	if (data->irq_flags)
2ec74a959   Johan Hovold   gpio: sysfs: spli...
264
265
266
267
268
269
270
  		gpio_sysfs_free_irq(dev);
  
  	if (flags) {
  		status = gpio_sysfs_request_irq(dev, flags);
  		if (!status)
  			status = size;
  	}
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
271

b91e18076   Johan Hovold   gpio: sysfs: only...
272
  out_unlock:
6ffcb7971   Johan Hovold   gpio: sysfs: use ...
273
  	mutex_unlock(&data->mutex);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
274
275
276
  
  	return status;
  }
6beac9d1a   Johan Hovold   gpio: sysfs: use ...
277
  static DEVICE_ATTR_RW(edge);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
278

6ffcb7971   Johan Hovold   gpio: sysfs: use ...
279
  /* Caller holds gpiod-data mutex. */
2f323b856   Johan Hovold   gpio: sysfs: rena...
280
  static int gpio_sysfs_set_active_low(struct device *dev, int value)
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
281
  {
0f6285080   Johan Hovold   gpio: sysfs: remo...
282
283
  	struct gpiod_data	*data = dev_get_drvdata(dev);
  	struct gpio_desc	*desc = data->desc;
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
284
  	int			status = 0;
cef1717b7   Johan Hovold   gpio: sysfs: move...
285
  	unsigned int		flags = data->irq_flags;
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
286
287
288
289
290
291
292
293
294
295
  
  	if (!!test_bit(FLAG_ACTIVE_LOW, &desc->flags) == !!value)
  		return 0;
  
  	if (value)
  		set_bit(FLAG_ACTIVE_LOW, &desc->flags);
  	else
  		clear_bit(FLAG_ACTIVE_LOW, &desc->flags);
  
  	/* reconfigure poll(2) support if enabled on one edge only */
cef1717b7   Johan Hovold   gpio: sysfs: move...
296
297
  	if (flags == GPIO_IRQF_TRIGGER_FALLING ||
  					flags == GPIO_IRQF_TRIGGER_RISING) {
2ec74a959   Johan Hovold   gpio: sysfs: spli...
298
  		gpio_sysfs_free_irq(dev);
cef1717b7   Johan Hovold   gpio: sysfs: move...
299
  		status = gpio_sysfs_request_irq(dev, flags);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
300
301
302
303
  	}
  
  	return status;
  }
6beac9d1a   Johan Hovold   gpio: sysfs: use ...
304
  static ssize_t active_low_show(struct device *dev,
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
305
306
  		struct device_attribute *attr, char *buf)
  {
c43960fbc   Johan Hovold   gpio: sysfs: add ...
307
308
  	struct gpiod_data *data = dev_get_drvdata(dev);
  	struct gpio_desc *desc = data->desc;
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
309
  	ssize_t			status;
6ffcb7971   Johan Hovold   gpio: sysfs: use ...
310
  	mutex_lock(&data->mutex);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
311

f0b7866a0   Johan Hovold   gpio: sysfs: remo...
312
313
  	status = sprintf(buf, "%d
  ",
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
314
  				!!test_bit(FLAG_ACTIVE_LOW, &desc->flags));
6ffcb7971   Johan Hovold   gpio: sysfs: use ...
315
  	mutex_unlock(&data->mutex);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
316
317
318
  
  	return status;
  }
6beac9d1a   Johan Hovold   gpio: sysfs: use ...
319
  static ssize_t active_low_store(struct device *dev,
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
320
321
  		struct device_attribute *attr, const char *buf, size_t size)
  {
6ffcb7971   Johan Hovold   gpio: sysfs: use ...
322
  	struct gpiod_data	*data = dev_get_drvdata(dev);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
323
  	ssize_t			status;
f0b7866a0   Johan Hovold   gpio: sysfs: remo...
324
  	long			value;
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
325

6ffcb7971   Johan Hovold   gpio: sysfs: use ...
326
  	mutex_lock(&data->mutex);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
327

f0b7866a0   Johan Hovold   gpio: sysfs: remo...
328
329
  	status = kstrtol(buf, 0, &value);
  	if (status == 0)
2f323b856   Johan Hovold   gpio: sysfs: rena...
330
  		status = gpio_sysfs_set_active_low(dev, value);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
331

6ffcb7971   Johan Hovold   gpio: sysfs: use ...
332
  	mutex_unlock(&data->mutex);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
333
334
335
  
  	return status ? : size;
  }
6beac9d1a   Johan Hovold   gpio: sysfs: use ...
336
  static DEVICE_ATTR_RW(active_low);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
337

ebbeba120   Johan Hovold   gpio: sysfs: fix ...
338
339
340
  static umode_t gpio_is_visible(struct kobject *kobj, struct attribute *attr,
  			       int n)
  {
97cd738c4   Wang Qing   gpiolib: sysfs: u...
341
  	struct device *dev = kobj_to_dev(kobj);
c43960fbc   Johan Hovold   gpio: sysfs: add ...
342
343
  	struct gpiod_data *data = dev_get_drvdata(dev);
  	struct gpio_desc *desc = data->desc;
ebbeba120   Johan Hovold   gpio: sysfs: fix ...
344
  	umode_t mode = attr->mode;
427fdeef5   Johan Hovold   gpio: sysfs: remo...
345
  	bool show_direction = data->direction_can_change;
ebbeba120   Johan Hovold   gpio: sysfs: fix ...
346
347
348
349
350
351
352
353
354
355
356
357
358
  
  	if (attr == &dev_attr_direction.attr) {
  		if (!show_direction)
  			mode = 0;
  	} else if (attr == &dev_attr_edge.attr) {
  		if (gpiod_to_irq(desc) < 0)
  			mode = 0;
  		if (!show_direction && test_bit(FLAG_IS_OUT, &desc->flags))
  			mode = 0;
  	}
  
  	return mode;
  }
0915e6feb   Johan Hovold   gpio: sysfs: fix ...
359
  static struct attribute *gpio_attrs[] = {
ebbeba120   Johan Hovold   gpio: sysfs: fix ...
360
361
  	&dev_attr_direction.attr,
  	&dev_attr_edge.attr,
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
362
363
364
365
  	&dev_attr_value.attr,
  	&dev_attr_active_low.attr,
  	NULL,
  };
ebbeba120   Johan Hovold   gpio: sysfs: fix ...
366
367
368
369
370
371
372
373
374
375
  
  static const struct attribute_group gpio_group = {
  	.attrs = gpio_attrs,
  	.is_visible = gpio_is_visible,
  };
  
  static const struct attribute_group *gpio_groups[] = {
  	&gpio_group,
  	NULL
  };
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
376
377
378
379
380
381
382
  
  /*
   * /sys/class/gpio/gpiochipN/
   *   /base ... matching gpio_chip.base (N)
   *   /label ... matching gpio_chip.label
   *   /ngpio ... matching gpio_chip.ngpio
   */
6beac9d1a   Johan Hovold   gpio: sysfs: use ...
383
  static ssize_t base_show(struct device *dev,
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
384
385
386
387
388
389
390
  			       struct device_attribute *attr, char *buf)
  {
  	const struct gpio_chip	*chip = dev_get_drvdata(dev);
  
  	return sprintf(buf, "%d
  ", chip->base);
  }
6beac9d1a   Johan Hovold   gpio: sysfs: use ...
391
  static DEVICE_ATTR_RO(base);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
392

6beac9d1a   Johan Hovold   gpio: sysfs: use ...
393
  static ssize_t label_show(struct device *dev,
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
394
395
396
397
398
399
400
  			       struct device_attribute *attr, char *buf)
  {
  	const struct gpio_chip	*chip = dev_get_drvdata(dev);
  
  	return sprintf(buf, "%s
  ", chip->label ? : "");
  }
6beac9d1a   Johan Hovold   gpio: sysfs: use ...
401
  static DEVICE_ATTR_RO(label);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
402

6beac9d1a   Johan Hovold   gpio: sysfs: use ...
403
  static ssize_t ngpio_show(struct device *dev,
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
404
405
406
407
408
409
410
  			       struct device_attribute *attr, char *buf)
  {
  	const struct gpio_chip	*chip = dev_get_drvdata(dev);
  
  	return sprintf(buf, "%u
  ", chip->ngpio);
  }
6beac9d1a   Johan Hovold   gpio: sysfs: use ...
411
  static DEVICE_ATTR_RO(ngpio);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
412

121b6a799   Johan Hovold   gpio: sysfs: fix ...
413
  static struct attribute *gpiochip_attrs[] = {
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
414
415
416
417
418
  	&dev_attr_base.attr,
  	&dev_attr_label.attr,
  	&dev_attr_ngpio.attr,
  	NULL,
  };
121b6a799   Johan Hovold   gpio: sysfs: fix ...
419
  ATTRIBUTE_GROUPS(gpiochip);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
  
  /*
   * /sys/class/gpio/export ... write-only
   *	integer N ... number of GPIO to export (full access)
   * /sys/class/gpio/unexport ... write-only
   *	integer N ... number of GPIO to unexport
   */
  static ssize_t export_store(struct class *class,
  				struct class_attribute *attr,
  				const char *buf, size_t len)
  {
  	long			gpio;
  	struct gpio_desc	*desc;
  	int			status;
  
  	status = kstrtol(buf, 0, &gpio);
  	if (status < 0)
  		goto done;
f13a0b0bb   Linus Walleij   gpio: Get rid of ...
438
  	desc = gpio_to_desc(gpio);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
  	/* reject invalid GPIOs */
  	if (!desc) {
  		pr_warn("%s: invalid GPIO %ld
  ", __func__, gpio);
  		return -EINVAL;
  	}
  
  	/* No extra locking here; FLAG_SYSFS just signifies that the
  	 * request and export were done by on behalf of userspace, so
  	 * they may be undone on its behalf too.
  	 */
  
  	status = gpiod_request(desc, "sysfs");
  	if (status < 0) {
  		if (status == -EPROBE_DEFER)
  			status = -ENODEV;
  		goto done;
  	}
e10f72bf4   Andrew Jeffery   gpio: gpiolib: Ge...
457
458
459
460
461
462
463
464
465
  
  	status = gpiod_set_transitory(desc, false);
  	if (!status) {
  		status = gpiod_export(desc, true);
  		if (status < 0)
  			gpiod_free(desc);
  		else
  			set_bit(FLAG_SYSFS, &desc->flags);
  	}
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
466
467
468
469
470
471
472
  
  done:
  	if (status)
  		pr_debug("%s: status %d
  ", __func__, status);
  	return status ? : len;
  }
d83bb159f   Greg Kroah-Hartman   gpio: use class_g...
473
  static CLASS_ATTR_WO(export);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
474
475
476
477
478
479
480
481
482
483
484
485
  
  static ssize_t unexport_store(struct class *class,
  				struct class_attribute *attr,
  				const char *buf, size_t len)
  {
  	long			gpio;
  	struct gpio_desc	*desc;
  	int			status;
  
  	status = kstrtol(buf, 0, &gpio);
  	if (status < 0)
  		goto done;
f13a0b0bb   Linus Walleij   gpio: Get rid of ...
486
  	desc = gpio_to_desc(gpio);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
  	/* reject bogus commands (gpio_unexport ignores them) */
  	if (!desc) {
  		pr_warn("%s: invalid GPIO %ld
  ", __func__, gpio);
  		return -EINVAL;
  	}
  
  	status = -EINVAL;
  
  	/* No extra locking here; FLAG_SYSFS just signifies that the
  	 * request and export were done by on behalf of userspace, so
  	 * they may be undone on its behalf too.
  	 */
  	if (test_and_clear_bit(FLAG_SYSFS, &desc->flags)) {
  		status = 0;
  		gpiod_free(desc);
  	}
  done:
  	if (status)
  		pr_debug("%s: status %d
  ", __func__, status);
  	return status ? : len;
  }
d83bb159f   Greg Kroah-Hartman   gpio: use class_g...
510
  static CLASS_ATTR_WO(unexport);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
511

d83bb159f   Greg Kroah-Hartman   gpio: use class_g...
512
513
514
515
  static struct attribute *gpio_class_attrs[] = {
  	&class_attr_export.attr,
  	&class_attr_unexport.attr,
  	NULL,
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
516
  };
d83bb159f   Greg Kroah-Hartman   gpio: use class_g...
517
  ATTRIBUTE_GROUPS(gpio_class);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
518
519
520
521
  
  static struct class gpio_class = {
  	.name =		"gpio",
  	.owner =	THIS_MODULE,
d83bb159f   Greg Kroah-Hartman   gpio: use class_g...
522
  	.class_groups = gpio_class_groups,
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
523
524
525
526
527
  };
  
  
  /**
   * gpiod_export - export a GPIO through sysfs
2d9d05192   Thierry Reding   gpio: sysfs: Fixu...
528
529
   * @desc: GPIO to make available, already requested
   * @direction_may_change: true if userspace may change GPIO direction
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
530
531
532
533
534
535
536
537
538
539
540
541
542
   * Context: arch_initcall or later
   *
   * When drivers want to make a GPIO accessible to userspace after they
   * have requested it -- perhaps while debugging, or as part of their
   * public interface -- they may use this routine.  If the GPIO can
   * change direction (some can't) and the caller allows it, userspace
   * will see "direction" sysfs attribute which may be used to change
   * the gpio's direction.  A "value" attribute will always be provided.
   *
   * Returns zero on success, else an error.
   */
  int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
  {
483d82110   Johan Hovold   gpio: sysfs: fix ...
543
  	struct gpio_chip	*chip;
ff2b13592   Linus Walleij   gpio: make the gp...
544
  	struct gpio_device	*gdev;
c43960fbc   Johan Hovold   gpio: sysfs: add ...
545
  	struct gpiod_data	*data;
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
  	unsigned long		flags;
  	int			status;
  	const char		*ioname = NULL;
  	struct device		*dev;
  	int			offset;
  
  	/* can't export until sysfs is available ... */
  	if (!gpio_class.p) {
  		pr_debug("%s: called too early!
  ", __func__);
  		return -ENOENT;
  	}
  
  	if (!desc) {
  		pr_debug("%s: invalid gpio descriptor
  ", __func__);
  		return -EINVAL;
  	}
fdeb8e154   Linus Walleij   gpio: reflect bas...
564
565
  	gdev = desc->gdev;
  	chip = gdev->chip;
483d82110   Johan Hovold   gpio: sysfs: fix ...
566

0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
567
  	mutex_lock(&sysfs_lock);
483d82110   Johan Hovold   gpio: sysfs: fix ...
568
  	/* check if chip is being removed */
afbc4f312   Linus Walleij   gpio: move sysfs ...
569
  	if (!chip || !gdev->mockdev) {
483d82110   Johan Hovold   gpio: sysfs: fix ...
570
  		status = -ENODEV;
c43960fbc   Johan Hovold   gpio: sysfs: add ...
571
  		goto err_unlock;
483d82110   Johan Hovold   gpio: sysfs: fix ...
572
  	}
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
573
574
575
576
577
578
579
580
581
582
  	spin_lock_irqsave(&gpio_lock, flags);
  	if (!test_bit(FLAG_REQUESTED, &desc->flags) ||
  	     test_bit(FLAG_EXPORT, &desc->flags)) {
  		spin_unlock_irqrestore(&gpio_lock, flags);
  		gpiod_dbg(desc, "%s: unavailable (requested=%d, exported=%d)
  ",
  				__func__,
  				test_bit(FLAG_REQUESTED, &desc->flags),
  				test_bit(FLAG_EXPORT, &desc->flags));
  		status = -EPERM;
c43960fbc   Johan Hovold   gpio: sysfs: add ...
583
  		goto err_unlock;
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
584
  	}
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
585
  	spin_unlock_irqrestore(&gpio_lock, flags);
c43960fbc   Johan Hovold   gpio: sysfs: add ...
586
587
588
589
590
591
592
  	data = kzalloc(sizeof(*data), GFP_KERNEL);
  	if (!data) {
  		status = -ENOMEM;
  		goto err_unlock;
  	}
  
  	data->desc = desc;
6ffcb7971   Johan Hovold   gpio: sysfs: use ...
593
  	mutex_init(&data->mutex);
427fdeef5   Johan Hovold   gpio: sysfs: remo...
594
595
596
597
  	if (chip->direction_input && chip->direction_output)
  		data->direction_can_change = direction_may_change;
  	else
  		data->direction_can_change = false;
c43960fbc   Johan Hovold   gpio: sysfs: add ...
598

0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
599
  	offset = gpio_chip_hwgpio(desc);
cecf58ab5   Johan Hovold   gpio: sysfs: prep...
600
601
  	if (chip->names && chip->names[offset])
  		ioname = chip->names[offset];
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
602

ff2b13592   Linus Walleij   gpio: make the gp...
603
  	dev = device_create_with_groups(&gpio_class, &gdev->dev,
c43960fbc   Johan Hovold   gpio: sysfs: add ...
604
  					MKDEV(0, 0), data, gpio_groups,
0915e6feb   Johan Hovold   gpio: sysfs: fix ...
605
606
  					ioname ? ioname : "gpio%u",
  					desc_to_gpio(desc));
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
607
608
  	if (IS_ERR(dev)) {
  		status = PTR_ERR(dev);
c43960fbc   Johan Hovold   gpio: sysfs: add ...
609
  		goto err_free_data;
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
610
  	}
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
611
612
613
  	set_bit(FLAG_EXPORT, &desc->flags);
  	mutex_unlock(&sysfs_lock);
  	return 0;
c43960fbc   Johan Hovold   gpio: sysfs: add ...
614
615
616
  err_free_data:
  	kfree(data);
  err_unlock:
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
617
618
619
620
621
622
  	mutex_unlock(&sysfs_lock);
  	gpiod_dbg(desc, "%s: status %d
  ", __func__, status);
  	return status;
  }
  EXPORT_SYMBOL_GPL(gpiod_export);
c43960fbc   Johan Hovold   gpio: sysfs: add ...
623
  static int match_export(struct device *dev, const void *desc)
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
624
  {
c43960fbc   Johan Hovold   gpio: sysfs: add ...
625
626
627
  	struct gpiod_data *data = dev_get_drvdata(dev);
  
  	return data->desc == desc;
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
628
629
630
631
632
633
  }
  
  /**
   * gpiod_export_link - create a sysfs link to an exported GPIO node
   * @dev: device under which to create symlink
   * @name: name of the symlink
2d9d05192   Thierry Reding   gpio: sysfs: Fixu...
634
   * @desc: GPIO to create symlink to, already exported
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
635
636
637
638
639
640
641
642
643
   *
   * Set up a symlink from /sys/.../dev/name to /sys/class/gpio/gpioN
   * node. Caller is responsible for unlinking.
   *
   * Returns zero on success, else an error.
   */
  int gpiod_export_link(struct device *dev, const char *name,
  		      struct gpio_desc *desc)
  {
56d30ec14   Johan Hovold   gpio: sysfs: clea...
644
645
  	struct device *cdev;
  	int ret;
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
646
647
648
649
650
651
  
  	if (!desc) {
  		pr_warn("%s: invalid GPIO
  ", __func__);
  		return -EINVAL;
  	}
56d30ec14   Johan Hovold   gpio: sysfs: clea...
652
653
654
  	cdev = class_find_device(&gpio_class, NULL, desc, match_export);
  	if (!cdev)
  		return -ENODEV;
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
655

56d30ec14   Johan Hovold   gpio: sysfs: clea...
656
657
  	ret = sysfs_create_link(&dev->kobj, &cdev->kobj, name);
  	put_device(cdev);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
658

56d30ec14   Johan Hovold   gpio: sysfs: clea...
659
  	return ret;
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
660
661
662
663
  }
  EXPORT_SYMBOL_GPL(gpiod_export_link);
  
  /**
31963eb03   Amitesh Singh   gpio: fix documen...
664
   * gpiod_unexport - reverse effect of gpiod_export()
2d9d05192   Thierry Reding   gpio: sysfs: Fixu...
665
   * @desc: GPIO to make unavailable
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
666
   *
31963eb03   Amitesh Singh   gpio: fix documen...
667
   * This is implicit on gpiod_free().
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
668
669
670
   */
  void gpiod_unexport(struct gpio_desc *desc)
  {
72eba6f66   Johan Hovold   gpio: sysfs: fix ...
671
672
  	struct gpiod_data *data;
  	struct device *dev;
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
673
674
675
676
677
678
679
680
  
  	if (!desc) {
  		pr_warn("%s: invalid GPIO
  ", __func__);
  		return;
  	}
  
  	mutex_lock(&sysfs_lock);
72eba6f66   Johan Hovold   gpio: sysfs: fix ...
681
682
  	if (!test_bit(FLAG_EXPORT, &desc->flags))
  		goto err_unlock;
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
683

72eba6f66   Johan Hovold   gpio: sysfs: fix ...
684
685
686
687
688
  	dev = class_find_device(&gpio_class, NULL, desc, match_export);
  	if (!dev)
  		goto err_unlock;
  
  	data = dev_get_drvdata(dev);
72eba6f66   Johan Hovold   gpio: sysfs: fix ...
689
690
691
692
693
694
695
  	clear_bit(FLAG_EXPORT, &desc->flags);
  
  	device_unregister(dev);
  
  	/*
  	 * Release irq after deregistration to prevent race with edge_store.
  	 */
cef1717b7   Johan Hovold   gpio: sysfs: move...
696
  	if (data->irq_flags)
72eba6f66   Johan Hovold   gpio: sysfs: fix ...
697
  		gpio_sysfs_free_irq(dev);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
698
699
  
  	mutex_unlock(&sysfs_lock);
72eba6f66   Johan Hovold   gpio: sysfs: fix ...
700
701
  	put_device(dev);
  	kfree(data);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
702

72eba6f66   Johan Hovold   gpio: sysfs: fix ...
703
704
705
706
  	return;
  
  err_unlock:
  	mutex_unlock(&sysfs_lock);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
707
708
  }
  EXPORT_SYMBOL_GPL(gpiod_unexport);
afbc4f312   Linus Walleij   gpio: move sysfs ...
709
  int gpiochip_sysfs_register(struct gpio_device *gdev)
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
710
  {
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
711
  	struct device	*dev;
d27c17285   Bamvor Jian Zhang   gpio: fix abi reg...
712
  	struct device	*parent;
afbc4f312   Linus Walleij   gpio: move sysfs ...
713
  	struct gpio_chip *chip = gdev->chip;
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
714

426577bd8   Johan Hovold   gpio: sysfs: rena...
715
716
  	/*
  	 * Many systems add gpio chips for SOC support very early,
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
717
  	 * before driver model support is available.  In those cases we
426577bd8   Johan Hovold   gpio: sysfs: rena...
718
  	 * register later, in gpiolib_sysfs_init() ... here we just
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
719
720
721
722
  	 * verify that _some_ field of gpio_class got initialized.
  	 */
  	if (!gpio_class.p)
  		return 0;
d27c17285   Bamvor Jian Zhang   gpio: fix abi reg...
723
724
725
726
727
728
729
730
  	/*
  	 * For sysfs backward compatibility we need to preserve this
  	 * preferred parenting to the gpio_chip parent field, if set.
  	 */
  	if (chip->parent)
  		parent = chip->parent;
  	else
  		parent = &gdev->dev;
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
731
  	/* use chip->base for the ID; it's already known to be unique */
ddd8891e0   Geert Uytterhoeven   gpiolib: Add GPIO...
732
733
734
  	dev = device_create_with_groups(&gpio_class, parent, MKDEV(0, 0), chip,
  					gpiochip_groups, GPIOCHIP_NAME "%d",
  					chip->base);
121b6a799   Johan Hovold   gpio: sysfs: fix ...
735
  	if (IS_ERR(dev))
6a4b6b0a3   Johan Hovold   gpio: sysfs: clea...
736
  		return PTR_ERR(dev);
3ff74be5c   Johan Hovold   gpio: sysfs: redu...
737
738
  
  	mutex_lock(&sysfs_lock);
afbc4f312   Linus Walleij   gpio: move sysfs ...
739
  	gdev->mockdev = dev;
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
740
  	mutex_unlock(&sysfs_lock);
6a4b6b0a3   Johan Hovold   gpio: sysfs: clea...
741
  	return 0;
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
742
  }
afbc4f312   Linus Walleij   gpio: move sysfs ...
743
  void gpiochip_sysfs_unregister(struct gpio_device *gdev)
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
744
  {
483d82110   Johan Hovold   gpio: sysfs: fix ...
745
  	struct gpio_desc *desc;
afbc4f312   Linus Walleij   gpio: move sysfs ...
746
  	struct gpio_chip *chip = gdev->chip;
483d82110   Johan Hovold   gpio: sysfs: fix ...
747
  	unsigned int i;
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
748

afbc4f312   Linus Walleij   gpio: move sysfs ...
749
  	if (!gdev->mockdev)
6a4b6b0a3   Johan Hovold   gpio: sysfs: clea...
750
  		return;
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
751

afbc4f312   Linus Walleij   gpio: move sysfs ...
752
  	device_unregister(gdev->mockdev);
6a4b6b0a3   Johan Hovold   gpio: sysfs: clea...
753
754
755
  
  	/* prevent further gpiod exports */
  	mutex_lock(&sysfs_lock);
afbc4f312   Linus Walleij   gpio: move sysfs ...
756
  	gdev->mockdev = NULL;
6a4b6b0a3   Johan Hovold   gpio: sysfs: clea...
757
  	mutex_unlock(&sysfs_lock);
483d82110   Johan Hovold   gpio: sysfs: fix ...
758
759
760
  
  	/* unregister gpiod class devices owned by sysfs */
  	for (i = 0; i < chip->ngpio; i++) {
fdeb8e154   Linus Walleij   gpio: reflect bas...
761
  		desc = &gdev->descs[i];
483d82110   Johan Hovold   gpio: sysfs: fix ...
762
763
764
  		if (test_and_clear_bit(FLAG_SYSFS, &desc->flags))
  			gpiod_free(desc);
  	}
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
765
766
767
768
769
770
  }
  
  static int __init gpiolib_sysfs_init(void)
  {
  	int		status;
  	unsigned long	flags;
ff2b13592   Linus Walleij   gpio: make the gp...
771
  	struct gpio_device *gdev;
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
772
773
774
775
776
777
778
779
780
781
782
783
  
  	status = class_register(&gpio_class);
  	if (status < 0)
  		return status;
  
  	/* Scan and register the gpio_chips which registered very
  	 * early (e.g. before the class_register above was called).
  	 *
  	 * We run before arch_initcall() so chip->dev nodes can have
  	 * registered, and so arch_initcall() can always gpio_export().
  	 */
  	spin_lock_irqsave(&gpio_lock, flags);
ff2b13592   Linus Walleij   gpio: make the gp...
784
  	list_for_each_entry(gdev, &gpio_devices, list) {
afbc4f312   Linus Walleij   gpio: move sysfs ...
785
  		if (gdev->mockdev)
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
786
  			continue;
14141a935   Alexandre Courbot   gpio: simplify gp...
787
  		/*
426577bd8   Johan Hovold   gpio: sysfs: rena...
788
789
790
  		 * TODO we yield gpio_lock here because
  		 * gpiochip_sysfs_register() acquires a mutex. This is unsafe
  		 * and needs to be fixed.
14141a935   Alexandre Courbot   gpio: simplify gp...
791
792
793
794
795
  		 *
  		 * Also it would be nice to use gpiochip_find() here so we
  		 * can keep gpio_chips local to gpiolib.c, but the yield of
  		 * gpio_lock prevents us from doing this.
  		 */
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
796
  		spin_unlock_irqrestore(&gpio_lock, flags);
afbc4f312   Linus Walleij   gpio: move sysfs ...
797
  		status = gpiochip_sysfs_register(gdev);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
798
799
800
  		spin_lock_irqsave(&gpio_lock, flags);
  	}
  	spin_unlock_irqrestore(&gpio_lock, flags);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
801
802
803
  	return status;
  }
  postcore_initcall(gpiolib_sysfs_init);