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"
cef1717b7   Johan Hovold   gpio: sysfs: move...
14
15
16
17
  #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 ...
18
19
  struct gpiod_data {
  	struct gpio_desc *desc;
6ffcb7971   Johan Hovold   gpio: sysfs: use ...
20
21
  
  	struct mutex mutex;
a08f5c21f   Johan Hovold   gpio: sysfs: clea...
22
  	struct kernfs_node *value_kn;
2ec74a959   Johan Hovold   gpio: sysfs: spli...
23
  	int irq;
cef1717b7   Johan Hovold   gpio: sysfs: move...
24
  	unsigned char irq_flags;
427fdeef5   Johan Hovold   gpio: sysfs: remo...
25
26
  
  	bool direction_can_change;
c43960fbc   Johan Hovold   gpio: sysfs: add ...
27
  };
6ffcb7971   Johan Hovold   gpio: sysfs: use ...
28
29
30
  /*
   * Lock to serialise gpiod export and unexport, and prevent re-export of
   * gpiod whose chip is being unregistered.
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
   */
  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 ...
54
  static ssize_t direction_show(struct device *dev,
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
55
56
  		struct device_attribute *attr, char *buf)
  {
c43960fbc   Johan Hovold   gpio: sysfs: add ...
57
58
  	struct gpiod_data *data = dev_get_drvdata(dev);
  	struct gpio_desc *desc = data->desc;
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
59
  	ssize_t			status;
6ffcb7971   Johan Hovold   gpio: sysfs: use ...
60
  	mutex_lock(&data->mutex);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
61

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

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

f0b7866a0   Johan Hovold   gpio: sysfs: remo...
79
  	if (sysfs_streq(buf, "high"))
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
80
81
82
83
84
85
86
  		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 ...
87
  	mutex_unlock(&data->mutex);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
88
89
  	return status ? : size;
  }
6beac9d1a   Johan Hovold   gpio: sysfs: use ...
90
  static DEVICE_ATTR_RW(direction);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
91

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

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

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

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

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

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

2ec74a959   Johan Hovold   gpio: sysfs: spli...
157
158
  	data->irq = gpiod_to_irq(desc);
  	if (data->irq < 0)
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
159
  		return -EIO;
2ec74a959   Johan Hovold   gpio: sysfs: spli...
160
161
162
  	data->value_kn = sysfs_get_dirent(dev->kobj.sd, "value");
  	if (!data->value_kn)
  		return -ENODEV;
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
163
164
  
  	irq_flags = IRQF_SHARED;
cef1717b7   Johan Hovold   gpio: sysfs: move...
165
  	if (flags & GPIO_IRQF_TRIGGER_FALLING)
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
166
167
  		irq_flags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ?
  			IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING;
cef1717b7   Johan Hovold   gpio: sysfs: move...
168
  	if (flags & GPIO_IRQF_TRIGGER_RISING)
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
169
170
  		irq_flags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ?
  			IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING;
52176d0d3   Johan Hovold   gpio: sysfs: fix ...
171
172
173
174
175
176
177
178
  	/*
  	 * 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...
179
  	ret = gpiochip_lock_as_irq(desc->gdev->chip, gpio_chip_hwgpio(desc));
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
180
  	if (ret < 0)
2ec74a959   Johan Hovold   gpio: sysfs: spli...
181
  		goto err_put_kn;
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
182

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

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

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

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

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

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

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

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

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

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

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

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

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

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

ebbeba120   Johan Hovold   gpio: sysfs: fix ...
336
337
338
339
  static umode_t gpio_is_visible(struct kobject *kobj, struct attribute *attr,
  			       int n)
  {
  	struct device *dev = container_of(kobj, struct device, kobj);
c43960fbc   Johan Hovold   gpio: sysfs: add ...
340
341
  	struct gpiod_data *data = dev_get_drvdata(dev);
  	struct gpio_desc *desc = data->desc;
ebbeba120   Johan Hovold   gpio: sysfs: fix ...
342
  	umode_t mode = attr->mode;
427fdeef5   Johan Hovold   gpio: sysfs: remo...
343
  	bool show_direction = data->direction_can_change;
ebbeba120   Johan Hovold   gpio: sysfs: fix ...
344
345
346
347
348
349
350
351
352
353
354
355
356
  
  	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 ...
357
  static struct attribute *gpio_attrs[] = {
ebbeba120   Johan Hovold   gpio: sysfs: fix ...
358
359
  	&dev_attr_direction.attr,
  	&dev_attr_edge.attr,
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
360
361
362
363
  	&dev_attr_value.attr,
  	&dev_attr_active_low.attr,
  	NULL,
  };
ebbeba120   Johan Hovold   gpio: sysfs: fix ...
364
365
366
367
368
369
370
371
372
373
  
  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 ...
374
375
376
377
378
379
380
  
  /*
   * /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 ...
381
  static ssize_t base_show(struct device *dev,
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
382
383
384
385
386
387
388
  			       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 ...
389
  static DEVICE_ATTR_RO(base);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
390

6beac9d1a   Johan Hovold   gpio: sysfs: use ...
391
  static ssize_t label_show(struct device *dev,
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
392
393
394
395
396
397
398
  			       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 ...
399
  static DEVICE_ATTR_RO(label);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
400

6beac9d1a   Johan Hovold   gpio: sysfs: use ...
401
  static ssize_t ngpio_show(struct device *dev,
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
402
403
404
405
406
407
408
  			       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 ...
409
  static DEVICE_ATTR_RO(ngpio);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
410

121b6a799   Johan Hovold   gpio: sysfs: fix ...
411
  static struct attribute *gpiochip_attrs[] = {
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
412
413
414
415
416
  	&dev_attr_base.attr,
  	&dev_attr_label.attr,
  	&dev_attr_ngpio.attr,
  	NULL,
  };
121b6a799   Johan Hovold   gpio: sysfs: fix ...
417
  ATTRIBUTE_GROUPS(gpiochip);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
  
  /*
   * /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 ...
436
  	desc = gpio_to_desc(gpio);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
  	/* 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...
455
456
457
458
459
460
461
462
463
  
  	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 ...
464
465
466
467
468
469
470
  
  done:
  	if (status)
  		pr_debug("%s: status %d
  ", __func__, status);
  	return status ? : len;
  }
d83bb159f   Greg Kroah-Hartman   gpio: use class_g...
471
  static CLASS_ATTR_WO(export);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
472
473
474
475
476
477
478
479
480
481
482
483
  
  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 ...
484
  	desc = gpio_to_desc(gpio);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
  	/* 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...
508
  static CLASS_ATTR_WO(unexport);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
509

d83bb159f   Greg Kroah-Hartman   gpio: use class_g...
510
511
512
513
  static struct attribute *gpio_class_attrs[] = {
  	&class_attr_export.attr,
  	&class_attr_unexport.attr,
  	NULL,
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
514
  };
d83bb159f   Greg Kroah-Hartman   gpio: use class_g...
515
  ATTRIBUTE_GROUPS(gpio_class);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
516
517
518
519
  
  static struct class gpio_class = {
  	.name =		"gpio",
  	.owner =	THIS_MODULE,
d83bb159f   Greg Kroah-Hartman   gpio: use class_g...
520
  	.class_groups = gpio_class_groups,
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
521
522
523
524
525
  };
  
  
  /**
   * gpiod_export - export a GPIO through sysfs
2d9d05192   Thierry Reding   gpio: sysfs: Fixu...
526
527
   * @desc: GPIO to make available, already requested
   * @direction_may_change: true if userspace may change GPIO direction
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
528
529
530
531
532
533
534
535
536
537
538
539
540
   * 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 ...
541
  	struct gpio_chip	*chip;
ff2b13592   Linus Walleij   gpio: make the gp...
542
  	struct gpio_device	*gdev;
c43960fbc   Johan Hovold   gpio: sysfs: add ...
543
  	struct gpiod_data	*data;
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
  	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...
562
563
  	gdev = desc->gdev;
  	chip = gdev->chip;
483d82110   Johan Hovold   gpio: sysfs: fix ...
564

0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
565
  	mutex_lock(&sysfs_lock);
483d82110   Johan Hovold   gpio: sysfs: fix ...
566
  	/* check if chip is being removed */
afbc4f312   Linus Walleij   gpio: move sysfs ...
567
  	if (!chip || !gdev->mockdev) {
483d82110   Johan Hovold   gpio: sysfs: fix ...
568
  		status = -ENODEV;
c43960fbc   Johan Hovold   gpio: sysfs: add ...
569
  		goto err_unlock;
483d82110   Johan Hovold   gpio: sysfs: fix ...
570
  	}
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
571
572
573
574
575
576
577
578
579
580
  	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 ...
581
  		goto err_unlock;
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
582
  	}
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
583
  	spin_unlock_irqrestore(&gpio_lock, flags);
c43960fbc   Johan Hovold   gpio: sysfs: add ...
584
585
586
587
588
589
590
  	data = kzalloc(sizeof(*data), GFP_KERNEL);
  	if (!data) {
  		status = -ENOMEM;
  		goto err_unlock;
  	}
  
  	data->desc = desc;
6ffcb7971   Johan Hovold   gpio: sysfs: use ...
591
  	mutex_init(&data->mutex);
427fdeef5   Johan Hovold   gpio: sysfs: remo...
592
593
594
595
  	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 ...
596

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

ff2b13592   Linus Walleij   gpio: make the gp...
601
  	dev = device_create_with_groups(&gpio_class, &gdev->dev,
c43960fbc   Johan Hovold   gpio: sysfs: add ...
602
  					MKDEV(0, 0), data, gpio_groups,
0915e6feb   Johan Hovold   gpio: sysfs: fix ...
603
604
  					ioname ? ioname : "gpio%u",
  					desc_to_gpio(desc));
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
605
606
  	if (IS_ERR(dev)) {
  		status = PTR_ERR(dev);
c43960fbc   Johan Hovold   gpio: sysfs: add ...
607
  		goto err_free_data;
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
608
  	}
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
609
610
611
  	set_bit(FLAG_EXPORT, &desc->flags);
  	mutex_unlock(&sysfs_lock);
  	return 0;
c43960fbc   Johan Hovold   gpio: sysfs: add ...
612
613
614
  err_free_data:
  	kfree(data);
  err_unlock:
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
615
616
617
618
619
620
  	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 ...
621
  static int match_export(struct device *dev, const void *desc)
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
622
  {
c43960fbc   Johan Hovold   gpio: sysfs: add ...
623
624
625
  	struct gpiod_data *data = dev_get_drvdata(dev);
  
  	return data->desc == desc;
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
626
627
628
629
630
631
  }
  
  /**
   * 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...
632
   * @desc: GPIO to create symlink to, already exported
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
633
634
635
636
637
638
639
640
641
   *
   * 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...
642
643
  	struct device *cdev;
  	int ret;
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
644
645
646
647
648
649
  
  	if (!desc) {
  		pr_warn("%s: invalid GPIO
  ", __func__);
  		return -EINVAL;
  	}
56d30ec14   Johan Hovold   gpio: sysfs: clea...
650
651
652
  	cdev = class_find_device(&gpio_class, NULL, desc, match_export);
  	if (!cdev)
  		return -ENODEV;
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
653

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

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

72eba6f66   Johan Hovold   gpio: sysfs: fix ...
682
683
684
685
686
  	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 ...
687
688
689
690
691
692
693
  	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...
694
  	if (data->irq_flags)
72eba6f66   Johan Hovold   gpio: sysfs: fix ...
695
  		gpio_sysfs_free_irq(dev);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
696
697
  
  	mutex_unlock(&sysfs_lock);
72eba6f66   Johan Hovold   gpio: sysfs: fix ...
698
699
  	put_device(dev);
  	kfree(data);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
700

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

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

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

afbc4f312   Linus Walleij   gpio: move sysfs ...
751
  	device_unregister(gdev->mockdev);
6a4b6b0a3   Johan Hovold   gpio: sysfs: clea...
752
753
754
  
  	/* prevent further gpiod exports */
  	mutex_lock(&sysfs_lock);
afbc4f312   Linus Walleij   gpio: move sysfs ...
755
  	gdev->mockdev = NULL;
6a4b6b0a3   Johan Hovold   gpio: sysfs: clea...
756
  	mutex_unlock(&sysfs_lock);
483d82110   Johan Hovold   gpio: sysfs: fix ...
757
758
759
  
  	/* unregister gpiod class devices owned by sysfs */
  	for (i = 0; i < chip->ngpio; i++) {
fdeb8e154   Linus Walleij   gpio: reflect bas...
760
  		desc = &gdev->descs[i];
483d82110   Johan Hovold   gpio: sysfs: fix ...
761
762
763
  		if (test_and_clear_bit(FLAG_SYSFS, &desc->flags))
  			gpiod_free(desc);
  	}
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
764
765
766
767
768
769
  }
  
  static int __init gpiolib_sysfs_init(void)
  {
  	int		status;
  	unsigned long	flags;
ff2b13592   Linus Walleij   gpio: make the gp...
770
  	struct gpio_device *gdev;
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
771
772
773
774
775
776
777
778
779
780
781
782
  
  	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...
783
  	list_for_each_entry(gdev, &gpio_devices, list) {
afbc4f312   Linus Walleij   gpio: move sysfs ...
784
  		if (gdev->mockdev)
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
785
  			continue;
14141a935   Alexandre Courbot   gpio: simplify gp...
786
  		/*
426577bd8   Johan Hovold   gpio: sysfs: rena...
787
788
789
  		 * 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...
790
791
792
793
794
  		 *
  		 * 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 ...
795
  		spin_unlock_irqrestore(&gpio_lock, flags);
afbc4f312   Linus Walleij   gpio: move sysfs ...
796
  		status = gpiochip_sysfs_register(gdev);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
797
798
799
  		spin_lock_irqsave(&gpio_lock, flags);
  	}
  	spin_unlock_irqrestore(&gpio_lock, flags);
0eb4c6c26   Alexandre Courbot   gpio: move sysfs ...
800
801
802
  	return status;
  }
  postcore_initcall(gpiolib_sysfs_init);