1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * GPIO testing driver based on configfs. |
4 | * |
5 | * Copyright (C) 2021 Bartosz Golaszewski <brgl@bgdev.pl> |
6 | */ |
7 | |
8 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
9 | |
10 | #include <linux/bitmap.h> |
11 | #include <linux/cleanup.h> |
12 | #include <linux/completion.h> |
13 | #include <linux/configfs.h> |
14 | #include <linux/device.h> |
15 | #include <linux/err.h> |
16 | #include <linux/gpio/consumer.h> |
17 | #include <linux/gpio/driver.h> |
18 | #include <linux/gpio/machine.h> |
19 | #include <linux/idr.h> |
20 | #include <linux/interrupt.h> |
21 | #include <linux/irq.h> |
22 | #include <linux/irq_sim.h> |
23 | #include <linux/kernel.h> |
24 | #include <linux/list.h> |
25 | #include <linux/lockdep.h> |
26 | #include <linux/minmax.h> |
27 | #include <linux/mod_devicetable.h> |
28 | #include <linux/module.h> |
29 | #include <linux/mutex.h> |
30 | #include <linux/notifier.h> |
31 | #include <linux/platform_device.h> |
32 | #include <linux/property.h> |
33 | #include <linux/seq_file.h> |
34 | #include <linux/slab.h> |
35 | #include <linux/string.h> |
36 | #include <linux/string_helpers.h> |
37 | #include <linux/sysfs.h> |
38 | #include <linux/types.h> |
39 | |
40 | #define GPIO_SIM_NGPIO_MAX 1024 |
41 | #define GPIO_SIM_PROP_MAX 4 /* Max 3 properties + sentinel. */ |
42 | #define GPIO_SIM_NUM_ATTRS 3 /* value, pull and sentinel */ |
43 | |
44 | static DEFINE_IDA(gpio_sim_ida); |
45 | |
46 | struct gpio_sim_chip { |
47 | struct gpio_chip gc; |
48 | struct device *dev; |
49 | unsigned long *request_map; |
50 | unsigned long *direction_map; |
51 | unsigned long *value_map; |
52 | unsigned long *pull_map; |
53 | struct irq_domain *irq_sim; |
54 | struct mutex lock; |
55 | const struct attribute_group **attr_groups; |
56 | }; |
57 | |
58 | struct gpio_sim_attribute { |
59 | struct device_attribute dev_attr; |
60 | unsigned int offset; |
61 | }; |
62 | |
63 | static struct gpio_sim_attribute * |
64 | to_gpio_sim_attr(struct device_attribute *dev_attr) |
65 | { |
66 | return container_of(dev_attr, struct gpio_sim_attribute, dev_attr); |
67 | } |
68 | |
69 | static int gpio_sim_apply_pull(struct gpio_sim_chip *chip, |
70 | unsigned int offset, int value) |
71 | { |
72 | int irq, irq_type, ret; |
73 | |
74 | guard(mutex)(T: &chip->lock); |
75 | |
76 | if (test_bit(offset, chip->request_map) && |
77 | test_bit(offset, chip->direction_map)) { |
78 | if (value == !!test_bit(offset, chip->value_map)) |
79 | goto set_pull; |
80 | |
81 | /* |
82 | * This is fine - it just means, nobody is listening |
83 | * for interrupts on this line, otherwise |
84 | * irq_create_mapping() would have been called from |
85 | * the to_irq() callback. |
86 | */ |
87 | irq = irq_find_mapping(domain: chip->irq_sim, hwirq: offset); |
88 | if (!irq) |
89 | goto set_value; |
90 | |
91 | irq_type = irq_get_trigger_type(irq); |
92 | |
93 | if ((value && (irq_type & IRQ_TYPE_EDGE_RISING)) || |
94 | (!value && (irq_type & IRQ_TYPE_EDGE_FALLING))) { |
95 | ret = irq_set_irqchip_state(irq, which: IRQCHIP_STATE_PENDING, |
96 | state: true); |
97 | if (ret) |
98 | goto set_pull; |
99 | } |
100 | } |
101 | |
102 | set_value: |
103 | /* Change the value unless we're actively driving the line. */ |
104 | if (!test_bit(offset, chip->request_map) || |
105 | test_bit(offset, chip->direction_map)) |
106 | __assign_bit(nr: offset, addr: chip->value_map, value); |
107 | |
108 | set_pull: |
109 | __assign_bit(nr: offset, addr: chip->pull_map, value); |
110 | return 0; |
111 | } |
112 | |
113 | static int gpio_sim_get(struct gpio_chip *gc, unsigned int offset) |
114 | { |
115 | struct gpio_sim_chip *chip = gpiochip_get_data(gc); |
116 | |
117 | guard(mutex)(T: &chip->lock); |
118 | |
119 | return !!test_bit(offset, chip->value_map); |
120 | } |
121 | |
122 | static void gpio_sim_set(struct gpio_chip *gc, unsigned int offset, int value) |
123 | { |
124 | struct gpio_sim_chip *chip = gpiochip_get_data(gc); |
125 | |
126 | scoped_guard(mutex, &chip->lock) |
127 | __assign_bit(nr: offset, addr: chip->value_map, value); |
128 | } |
129 | |
130 | static int gpio_sim_get_multiple(struct gpio_chip *gc, |
131 | unsigned long *mask, unsigned long *bits) |
132 | { |
133 | struct gpio_sim_chip *chip = gpiochip_get_data(gc); |
134 | |
135 | scoped_guard(mutex, &chip->lock) |
136 | bitmap_replace(dst: bits, old: bits, new: chip->value_map, mask, nbits: gc->ngpio); |
137 | |
138 | return 0; |
139 | } |
140 | |
141 | static void gpio_sim_set_multiple(struct gpio_chip *gc, |
142 | unsigned long *mask, unsigned long *bits) |
143 | { |
144 | struct gpio_sim_chip *chip = gpiochip_get_data(gc); |
145 | |
146 | scoped_guard(mutex, &chip->lock) |
147 | bitmap_replace(dst: chip->value_map, old: chip->value_map, new: bits, mask, |
148 | nbits: gc->ngpio); |
149 | } |
150 | |
151 | static int gpio_sim_direction_output(struct gpio_chip *gc, |
152 | unsigned int offset, int value) |
153 | { |
154 | struct gpio_sim_chip *chip = gpiochip_get_data(gc); |
155 | |
156 | scoped_guard(mutex, &chip->lock) { |
157 | __clear_bit(offset, chip->direction_map); |
158 | __assign_bit(nr: offset, addr: chip->value_map, value); |
159 | } |
160 | |
161 | return 0; |
162 | } |
163 | |
164 | static int gpio_sim_direction_input(struct gpio_chip *gc, unsigned int offset) |
165 | { |
166 | struct gpio_sim_chip *chip = gpiochip_get_data(gc); |
167 | |
168 | scoped_guard(mutex, &chip->lock) |
169 | __set_bit(offset, chip->direction_map); |
170 | |
171 | return 0; |
172 | } |
173 | |
174 | static int gpio_sim_get_direction(struct gpio_chip *gc, unsigned int offset) |
175 | { |
176 | struct gpio_sim_chip *chip = gpiochip_get_data(gc); |
177 | int direction; |
178 | |
179 | scoped_guard(mutex, &chip->lock) |
180 | direction = !!test_bit(offset, chip->direction_map); |
181 | |
182 | return direction ? GPIO_LINE_DIRECTION_IN : GPIO_LINE_DIRECTION_OUT; |
183 | } |
184 | |
185 | static int gpio_sim_set_config(struct gpio_chip *gc, unsigned int offset, |
186 | unsigned long config) |
187 | { |
188 | struct gpio_sim_chip *chip = gpiochip_get_data(gc); |
189 | |
190 | switch (pinconf_to_config_param(config)) { |
191 | case PIN_CONFIG_BIAS_PULL_UP: |
192 | return gpio_sim_apply_pull(chip, offset, value: 1); |
193 | case PIN_CONFIG_BIAS_PULL_DOWN: |
194 | return gpio_sim_apply_pull(chip, offset, value: 0); |
195 | default: |
196 | break; |
197 | } |
198 | |
199 | return -ENOTSUPP; |
200 | } |
201 | |
202 | static int gpio_sim_to_irq(struct gpio_chip *gc, unsigned int offset) |
203 | { |
204 | struct gpio_sim_chip *chip = gpiochip_get_data(gc); |
205 | |
206 | return irq_create_mapping(host: chip->irq_sim, hwirq: offset); |
207 | } |
208 | |
209 | static int gpio_sim_request(struct gpio_chip *gc, unsigned int offset) |
210 | { |
211 | struct gpio_sim_chip *chip = gpiochip_get_data(gc); |
212 | |
213 | scoped_guard(mutex, &chip->lock) |
214 | __set_bit(offset, chip->request_map); |
215 | |
216 | return 0; |
217 | } |
218 | |
219 | static void gpio_sim_free(struct gpio_chip *gc, unsigned int offset) |
220 | { |
221 | struct gpio_sim_chip *chip = gpiochip_get_data(gc); |
222 | |
223 | scoped_guard(mutex, &chip->lock) { |
224 | __assign_bit(nr: offset, addr: chip->value_map, |
225 | value: !!test_bit(offset, chip->pull_map)); |
226 | __clear_bit(offset, chip->request_map); |
227 | } |
228 | } |
229 | |
230 | static void gpio_sim_dbg_show(struct seq_file *seq, struct gpio_chip *gc) |
231 | { |
232 | struct gpio_sim_chip *chip = gpiochip_get_data(gc); |
233 | const char *label; |
234 | int i; |
235 | |
236 | guard(mutex)(T: &chip->lock); |
237 | |
238 | for_each_hwgpio(gc, i, label) |
239 | seq_printf(m: seq, fmt: " gpio-%-3d (%s) %s,%s\n" , |
240 | gc->base + i, |
241 | label ?: "<unused>" , |
242 | test_bit(i, chip->direction_map) ? "input" : |
243 | test_bit(i, chip->value_map) ? "output-high" : |
244 | "output-low" , |
245 | test_bit(i, chip->pull_map) ? "pull-up" : |
246 | "pull-down" ); |
247 | } |
248 | |
249 | static ssize_t gpio_sim_sysfs_val_show(struct device *dev, |
250 | struct device_attribute *attr, char *buf) |
251 | { |
252 | struct gpio_sim_attribute *line_attr = to_gpio_sim_attr(dev_attr: attr); |
253 | struct gpio_sim_chip *chip = dev_get_drvdata(dev); |
254 | int val; |
255 | |
256 | scoped_guard(mutex, &chip->lock) |
257 | val = !!test_bit(line_attr->offset, chip->value_map); |
258 | |
259 | return sysfs_emit(buf, fmt: "%d\n" , val); |
260 | } |
261 | |
262 | static ssize_t gpio_sim_sysfs_val_store(struct device *dev, |
263 | struct device_attribute *attr, |
264 | const char *buf, size_t count) |
265 | { |
266 | /* |
267 | * Not assigning this function will result in write() returning -EIO |
268 | * which is confusing. Return -EPERM explicitly. |
269 | */ |
270 | return -EPERM; |
271 | } |
272 | |
273 | static const char *const gpio_sim_sysfs_pull_strings[] = { |
274 | [0] = "pull-down" , |
275 | [1] = "pull-up" , |
276 | }; |
277 | |
278 | static ssize_t gpio_sim_sysfs_pull_show(struct device *dev, |
279 | struct device_attribute *attr, |
280 | char *buf) |
281 | { |
282 | struct gpio_sim_attribute *line_attr = to_gpio_sim_attr(dev_attr: attr); |
283 | struct gpio_sim_chip *chip = dev_get_drvdata(dev); |
284 | int pull; |
285 | |
286 | scoped_guard(mutex, &chip->lock) |
287 | pull = !!test_bit(line_attr->offset, chip->pull_map); |
288 | |
289 | return sysfs_emit(buf, fmt: "%s\n" , gpio_sim_sysfs_pull_strings[pull]); |
290 | } |
291 | |
292 | static ssize_t gpio_sim_sysfs_pull_store(struct device *dev, |
293 | struct device_attribute *attr, |
294 | const char *buf, size_t len) |
295 | { |
296 | struct gpio_sim_attribute *line_attr = to_gpio_sim_attr(dev_attr: attr); |
297 | struct gpio_sim_chip *chip = dev_get_drvdata(dev); |
298 | int ret, pull; |
299 | |
300 | pull = sysfs_match_string(gpio_sim_sysfs_pull_strings, buf); |
301 | if (pull < 0) |
302 | return pull; |
303 | |
304 | ret = gpio_sim_apply_pull(chip, offset: line_attr->offset, value: pull); |
305 | if (ret) |
306 | return ret; |
307 | |
308 | return len; |
309 | } |
310 | |
311 | static void gpio_sim_mutex_destroy(void *data) |
312 | { |
313 | struct mutex *lock = data; |
314 | |
315 | mutex_destroy(lock); |
316 | } |
317 | |
318 | static void gpio_sim_put_device(void *data) |
319 | { |
320 | struct device *dev = data; |
321 | |
322 | put_device(dev); |
323 | } |
324 | |
325 | static void gpio_sim_dispose_mappings(void *data) |
326 | { |
327 | struct gpio_sim_chip *chip = data; |
328 | unsigned int i; |
329 | |
330 | for (i = 0; i < chip->gc.ngpio; i++) |
331 | irq_dispose_mapping(virq: irq_find_mapping(domain: chip->irq_sim, hwirq: i)); |
332 | } |
333 | |
334 | static void gpio_sim_sysfs_remove(void *data) |
335 | { |
336 | struct gpio_sim_chip *chip = data; |
337 | |
338 | sysfs_remove_groups(kobj: &chip->dev->kobj, groups: chip->attr_groups); |
339 | } |
340 | |
341 | static int gpio_sim_setup_sysfs(struct gpio_sim_chip *chip) |
342 | { |
343 | struct device_attribute *val_dev_attr, *pull_dev_attr; |
344 | struct gpio_sim_attribute *val_attr, *pull_attr; |
345 | unsigned int num_lines = chip->gc.ngpio; |
346 | struct device *dev = chip->gc.parent; |
347 | struct attribute_group *attr_group; |
348 | struct attribute **attrs; |
349 | int i, ret; |
350 | |
351 | chip->attr_groups = devm_kcalloc(dev, n: sizeof(*chip->attr_groups), |
352 | size: num_lines + 1, GFP_KERNEL); |
353 | if (!chip->attr_groups) |
354 | return -ENOMEM; |
355 | |
356 | for (i = 0; i < num_lines; i++) { |
357 | attr_group = devm_kzalloc(dev, size: sizeof(*attr_group), GFP_KERNEL); |
358 | attrs = devm_kcalloc(dev, GPIO_SIM_NUM_ATTRS, size: sizeof(*attrs), |
359 | GFP_KERNEL); |
360 | val_attr = devm_kzalloc(dev, size: sizeof(*val_attr), GFP_KERNEL); |
361 | pull_attr = devm_kzalloc(dev, size: sizeof(*pull_attr), GFP_KERNEL); |
362 | if (!attr_group || !attrs || !val_attr || !pull_attr) |
363 | return -ENOMEM; |
364 | |
365 | attr_group->name = devm_kasprintf(dev, GFP_KERNEL, |
366 | fmt: "sim_gpio%u" , i); |
367 | if (!attr_group->name) |
368 | return -ENOMEM; |
369 | |
370 | val_attr->offset = pull_attr->offset = i; |
371 | |
372 | val_dev_attr = &val_attr->dev_attr; |
373 | pull_dev_attr = &pull_attr->dev_attr; |
374 | |
375 | sysfs_attr_init(&val_dev_attr->attr); |
376 | sysfs_attr_init(&pull_dev_attr->attr); |
377 | |
378 | val_dev_attr->attr.name = "value" ; |
379 | pull_dev_attr->attr.name = "pull" ; |
380 | |
381 | val_dev_attr->attr.mode = pull_dev_attr->attr.mode = 0644; |
382 | |
383 | val_dev_attr->show = gpio_sim_sysfs_val_show; |
384 | val_dev_attr->store = gpio_sim_sysfs_val_store; |
385 | pull_dev_attr->show = gpio_sim_sysfs_pull_show; |
386 | pull_dev_attr->store = gpio_sim_sysfs_pull_store; |
387 | |
388 | attrs[0] = &val_dev_attr->attr; |
389 | attrs[1] = &pull_dev_attr->attr; |
390 | |
391 | attr_group->attrs = attrs; |
392 | chip->attr_groups[i] = attr_group; |
393 | } |
394 | |
395 | ret = sysfs_create_groups(kobj: &chip->dev->kobj, groups: chip->attr_groups); |
396 | if (ret) |
397 | return ret; |
398 | |
399 | return devm_add_action_or_reset(dev, gpio_sim_sysfs_remove, chip); |
400 | } |
401 | |
402 | static int gpio_sim_dev_match_fwnode(struct device *dev, void *data) |
403 | { |
404 | return device_match_fwnode(dev, fwnode: data); |
405 | } |
406 | |
407 | static int gpio_sim_add_bank(struct fwnode_handle *swnode, struct device *dev) |
408 | { |
409 | struct gpio_sim_chip *chip; |
410 | struct gpio_chip *gc; |
411 | const char *label; |
412 | u32 num_lines; |
413 | int ret; |
414 | |
415 | ret = fwnode_property_read_u32(fwnode: swnode, propname: "ngpios" , val: &num_lines); |
416 | if (ret) |
417 | return ret; |
418 | |
419 | if (num_lines > GPIO_SIM_NGPIO_MAX) |
420 | return -ERANGE; |
421 | |
422 | ret = fwnode_property_read_string(fwnode: swnode, propname: "gpio-sim,label" , val: &label); |
423 | if (ret) { |
424 | label = devm_kasprintf(dev, GFP_KERNEL, fmt: "%s:%pfwP" , |
425 | dev_name(dev), swnode); |
426 | if (!label) |
427 | return -ENOMEM; |
428 | } |
429 | |
430 | chip = devm_kzalloc(dev, size: sizeof(*chip), GFP_KERNEL); |
431 | if (!chip) |
432 | return -ENOMEM; |
433 | |
434 | chip->request_map = devm_bitmap_zalloc(dev, nbits: num_lines, GFP_KERNEL); |
435 | if (!chip->request_map) |
436 | return -ENOMEM; |
437 | |
438 | chip->direction_map = devm_bitmap_alloc(dev, nbits: num_lines, GFP_KERNEL); |
439 | if (!chip->direction_map) |
440 | return -ENOMEM; |
441 | |
442 | /* Default to input mode. */ |
443 | bitmap_fill(dst: chip->direction_map, nbits: num_lines); |
444 | |
445 | chip->value_map = devm_bitmap_zalloc(dev, nbits: num_lines, GFP_KERNEL); |
446 | if (!chip->value_map) |
447 | return -ENOMEM; |
448 | |
449 | chip->pull_map = devm_bitmap_zalloc(dev, nbits: num_lines, GFP_KERNEL); |
450 | if (!chip->pull_map) |
451 | return -ENOMEM; |
452 | |
453 | chip->irq_sim = devm_irq_domain_create_sim(dev, fwnode: swnode, num_irqs: num_lines); |
454 | if (IS_ERR(ptr: chip->irq_sim)) |
455 | return PTR_ERR(ptr: chip->irq_sim); |
456 | |
457 | ret = devm_add_action_or_reset(dev, gpio_sim_dispose_mappings, chip); |
458 | if (ret) |
459 | return ret; |
460 | |
461 | mutex_init(&chip->lock); |
462 | ret = devm_add_action_or_reset(dev, gpio_sim_mutex_destroy, |
463 | &chip->lock); |
464 | if (ret) |
465 | return ret; |
466 | |
467 | gc = &chip->gc; |
468 | gc->base = -1; |
469 | gc->ngpio = num_lines; |
470 | gc->label = label; |
471 | gc->owner = THIS_MODULE; |
472 | gc->parent = dev; |
473 | gc->fwnode = swnode; |
474 | gc->get = gpio_sim_get; |
475 | gc->set = gpio_sim_set; |
476 | gc->get_multiple = gpio_sim_get_multiple; |
477 | gc->set_multiple = gpio_sim_set_multiple; |
478 | gc->direction_output = gpio_sim_direction_output; |
479 | gc->direction_input = gpio_sim_direction_input; |
480 | gc->get_direction = gpio_sim_get_direction; |
481 | gc->set_config = gpio_sim_set_config; |
482 | gc->to_irq = gpio_sim_to_irq; |
483 | gc->request = gpio_sim_request; |
484 | gc->free = gpio_sim_free; |
485 | gc->dbg_show = PTR_IF(IS_ENABLED(CONFIG_DEBUG_FS), gpio_sim_dbg_show); |
486 | gc->can_sleep = true; |
487 | |
488 | ret = devm_gpiochip_add_data(dev, gc, chip); |
489 | if (ret) |
490 | return ret; |
491 | |
492 | chip->dev = device_find_child(dev, data: swnode, match: gpio_sim_dev_match_fwnode); |
493 | if (!chip->dev) |
494 | return -ENODEV; |
495 | |
496 | ret = devm_add_action_or_reset(dev, gpio_sim_put_device, chip->dev); |
497 | if (ret) |
498 | return ret; |
499 | |
500 | /* Used by sysfs callbacks. */ |
501 | dev_set_drvdata(dev: chip->dev, data: chip); |
502 | |
503 | return gpio_sim_setup_sysfs(chip); |
504 | } |
505 | |
506 | static int gpio_sim_probe(struct platform_device *pdev) |
507 | { |
508 | struct device *dev = &pdev->dev; |
509 | struct fwnode_handle *swnode; |
510 | int ret; |
511 | |
512 | device_for_each_child_node(dev, swnode) { |
513 | ret = gpio_sim_add_bank(swnode, dev); |
514 | if (ret) { |
515 | fwnode_handle_put(fwnode: swnode); |
516 | return ret; |
517 | } |
518 | } |
519 | |
520 | return 0; |
521 | } |
522 | |
523 | static const struct of_device_id gpio_sim_of_match[] = { |
524 | { .compatible = "gpio-simulator" }, |
525 | { } |
526 | }; |
527 | MODULE_DEVICE_TABLE(of, gpio_sim_of_match); |
528 | |
529 | static struct platform_driver gpio_sim_driver = { |
530 | .driver = { |
531 | .name = "gpio-sim" , |
532 | .of_match_table = gpio_sim_of_match, |
533 | }, |
534 | .probe = gpio_sim_probe, |
535 | }; |
536 | |
537 | struct gpio_sim_device { |
538 | struct config_group group; |
539 | |
540 | /* |
541 | * If pdev is NULL, the device is 'pending' (waiting for configuration). |
542 | * Once the pointer is assigned, the device has been created and the |
543 | * item is 'live'. |
544 | */ |
545 | struct platform_device *pdev; |
546 | int id; |
547 | |
548 | /* |
549 | * Each configfs filesystem operation is protected with the subsystem |
550 | * mutex. Each separate attribute is protected with the buffer mutex. |
551 | * This structure however can be modified by callbacks of different |
552 | * attributes so we need another lock. |
553 | * |
554 | * We use this lock for protecting all data structures owned by this |
555 | * object too. |
556 | */ |
557 | struct mutex lock; |
558 | |
559 | /* |
560 | * This is used to synchronously wait for the driver's probe to complete |
561 | * and notify the user-space about any errors. |
562 | */ |
563 | struct notifier_block bus_notifier; |
564 | struct completion probe_completion; |
565 | bool driver_bound; |
566 | |
567 | struct gpiod_hog *hogs; |
568 | |
569 | struct list_head bank_list; |
570 | }; |
571 | |
572 | /* This is called with dev->lock already taken. */ |
573 | static int gpio_sim_bus_notifier_call(struct notifier_block *nb, |
574 | unsigned long action, void *data) |
575 | { |
576 | struct gpio_sim_device *simdev = container_of(nb, |
577 | struct gpio_sim_device, |
578 | bus_notifier); |
579 | struct device *dev = data; |
580 | char devname[32]; |
581 | |
582 | snprintf(buf: devname, size: sizeof(devname), fmt: "gpio-sim.%u" , simdev->id); |
583 | |
584 | if (strcmp(dev_name(dev), devname) == 0) { |
585 | if (action == BUS_NOTIFY_BOUND_DRIVER) |
586 | simdev->driver_bound = true; |
587 | else if (action == BUS_NOTIFY_DRIVER_NOT_BOUND) |
588 | simdev->driver_bound = false; |
589 | else |
590 | return NOTIFY_DONE; |
591 | |
592 | complete(&simdev->probe_completion); |
593 | return NOTIFY_OK; |
594 | } |
595 | |
596 | return NOTIFY_DONE; |
597 | } |
598 | |
599 | static struct gpio_sim_device *to_gpio_sim_device(struct config_item *item) |
600 | { |
601 | struct config_group *group = to_config_group(item); |
602 | |
603 | return container_of(group, struct gpio_sim_device, group); |
604 | } |
605 | |
606 | struct gpio_sim_bank { |
607 | struct config_group group; |
608 | |
609 | /* |
610 | * We could have used the ci_parent field of the config_item but |
611 | * configfs is stupid and calls the item's release callback after |
612 | * already having cleared the parent pointer even though the parent |
613 | * is guaranteed to survive the child... |
614 | * |
615 | * So we need to store the pointer to the parent struct here. We can |
616 | * dereference it anywhere we need with no checks and no locking as |
617 | * it's guaranteed to survive the children and protected by configfs |
618 | * locks. |
619 | * |
620 | * Same for other structures. |
621 | */ |
622 | struct gpio_sim_device *parent; |
623 | struct list_head siblings; |
624 | |
625 | char *label; |
626 | unsigned int num_lines; |
627 | |
628 | struct list_head line_list; |
629 | |
630 | struct fwnode_handle *swnode; |
631 | }; |
632 | |
633 | static struct gpio_sim_bank *to_gpio_sim_bank(struct config_item *item) |
634 | { |
635 | struct config_group *group = to_config_group(item); |
636 | |
637 | return container_of(group, struct gpio_sim_bank, group); |
638 | } |
639 | |
640 | static bool gpio_sim_bank_has_label(struct gpio_sim_bank *bank) |
641 | { |
642 | return bank->label && *bank->label; |
643 | } |
644 | |
645 | static struct gpio_sim_device * |
646 | gpio_sim_bank_get_device(struct gpio_sim_bank *bank) |
647 | { |
648 | return bank->parent; |
649 | } |
650 | |
651 | struct gpio_sim_hog; |
652 | |
653 | struct gpio_sim_line { |
654 | struct config_group group; |
655 | |
656 | struct gpio_sim_bank *parent; |
657 | struct list_head siblings; |
658 | |
659 | unsigned int offset; |
660 | char *name; |
661 | |
662 | /* There can only be one hog per line. */ |
663 | struct gpio_sim_hog *hog; |
664 | }; |
665 | |
666 | static struct gpio_sim_line *to_gpio_sim_line(struct config_item *item) |
667 | { |
668 | struct config_group *group = to_config_group(item); |
669 | |
670 | return container_of(group, struct gpio_sim_line, group); |
671 | } |
672 | |
673 | static struct gpio_sim_device * |
674 | gpio_sim_line_get_device(struct gpio_sim_line *line) |
675 | { |
676 | struct gpio_sim_bank *bank = line->parent; |
677 | |
678 | return gpio_sim_bank_get_device(bank); |
679 | } |
680 | |
681 | struct gpio_sim_hog { |
682 | struct config_item item; |
683 | struct gpio_sim_line *parent; |
684 | |
685 | char *name; |
686 | int dir; |
687 | }; |
688 | |
689 | static struct gpio_sim_hog *to_gpio_sim_hog(struct config_item *item) |
690 | { |
691 | return container_of(item, struct gpio_sim_hog, item); |
692 | } |
693 | |
694 | static struct gpio_sim_device *gpio_sim_hog_get_device(struct gpio_sim_hog *hog) |
695 | { |
696 | struct gpio_sim_line *line = hog->parent; |
697 | |
698 | return gpio_sim_line_get_device(line); |
699 | } |
700 | |
701 | static bool gpio_sim_device_is_live(struct gpio_sim_device *dev) |
702 | { |
703 | lockdep_assert_held(&dev->lock); |
704 | |
705 | return !!dev->pdev; |
706 | } |
707 | |
708 | static char *gpio_sim_strdup_trimmed(const char *str, size_t count) |
709 | { |
710 | char *trimmed; |
711 | |
712 | trimmed = kstrndup(s: skip_spaces(str), len: count, GFP_KERNEL); |
713 | if (!trimmed) |
714 | return NULL; |
715 | |
716 | return strim(trimmed); |
717 | } |
718 | |
719 | static ssize_t gpio_sim_device_config_dev_name_show(struct config_item *item, |
720 | char *page) |
721 | { |
722 | struct gpio_sim_device *dev = to_gpio_sim_device(item); |
723 | struct platform_device *pdev; |
724 | |
725 | guard(mutex)(T: &dev->lock); |
726 | |
727 | pdev = dev->pdev; |
728 | if (pdev) |
729 | return sprintf(buf: page, fmt: "%s\n" , dev_name(dev: &pdev->dev)); |
730 | |
731 | return sprintf(buf: page, fmt: "gpio-sim.%d\n" , dev->id); |
732 | } |
733 | |
734 | CONFIGFS_ATTR_RO(gpio_sim_device_config_, dev_name); |
735 | |
736 | static ssize_t |
737 | gpio_sim_device_config_live_show(struct config_item *item, char *page) |
738 | { |
739 | struct gpio_sim_device *dev = to_gpio_sim_device(item); |
740 | bool live; |
741 | |
742 | scoped_guard(mutex, &dev->lock) |
743 | live = gpio_sim_device_is_live(dev); |
744 | |
745 | return sprintf(buf: page, fmt: "%c\n" , live ? '1' : '0'); |
746 | } |
747 | |
748 | static unsigned int gpio_sim_get_line_names_size(struct gpio_sim_bank *bank) |
749 | { |
750 | struct gpio_sim_line *line; |
751 | unsigned int size = 0; |
752 | |
753 | list_for_each_entry(line, &bank->line_list, siblings) { |
754 | if (!line->name || (line->offset >= bank->num_lines)) |
755 | continue; |
756 | |
757 | size = max(size, line->offset + 1); |
758 | } |
759 | |
760 | return size; |
761 | } |
762 | |
763 | static void |
764 | gpio_sim_set_line_names(struct gpio_sim_bank *bank, char **line_names) |
765 | { |
766 | struct gpio_sim_line *line; |
767 | |
768 | list_for_each_entry(line, &bank->line_list, siblings) { |
769 | if (!line->name || (line->offset >= bank->num_lines)) |
770 | continue; |
771 | |
772 | line_names[line->offset] = line->name; |
773 | } |
774 | } |
775 | |
776 | static void gpio_sim_remove_hogs(struct gpio_sim_device *dev) |
777 | { |
778 | struct gpiod_hog *hog; |
779 | |
780 | if (!dev->hogs) |
781 | return; |
782 | |
783 | gpiod_remove_hogs(hogs: dev->hogs); |
784 | |
785 | for (hog = dev->hogs; hog->chip_label; hog++) { |
786 | kfree(objp: hog->chip_label); |
787 | kfree(objp: hog->line_name); |
788 | } |
789 | |
790 | kfree(objp: dev->hogs); |
791 | dev->hogs = NULL; |
792 | } |
793 | |
794 | static int gpio_sim_add_hogs(struct gpio_sim_device *dev) |
795 | { |
796 | unsigned int num_hogs = 0, idx = 0; |
797 | struct gpio_sim_bank *bank; |
798 | struct gpio_sim_line *line; |
799 | struct gpiod_hog *hog; |
800 | |
801 | list_for_each_entry(bank, &dev->bank_list, siblings) { |
802 | list_for_each_entry(line, &bank->line_list, siblings) { |
803 | if (line->offset >= bank->num_lines) |
804 | continue; |
805 | |
806 | if (line->hog) |
807 | num_hogs++; |
808 | } |
809 | } |
810 | |
811 | if (!num_hogs) |
812 | return 0; |
813 | |
814 | /* Allocate one more for the sentinel. */ |
815 | dev->hogs = kcalloc(n: num_hogs + 1, size: sizeof(*dev->hogs), GFP_KERNEL); |
816 | if (!dev->hogs) |
817 | return -ENOMEM; |
818 | |
819 | list_for_each_entry(bank, &dev->bank_list, siblings) { |
820 | list_for_each_entry(line, &bank->line_list, siblings) { |
821 | if (line->offset >= bank->num_lines) |
822 | continue; |
823 | |
824 | if (!line->hog) |
825 | continue; |
826 | |
827 | hog = &dev->hogs[idx++]; |
828 | |
829 | /* |
830 | * We need to make this string manually because at this |
831 | * point the device doesn't exist yet and so dev_name() |
832 | * is not available. |
833 | */ |
834 | if (gpio_sim_bank_has_label(bank)) |
835 | hog->chip_label = kstrdup(s: bank->label, |
836 | GFP_KERNEL); |
837 | else |
838 | hog->chip_label = kasprintf(GFP_KERNEL, |
839 | fmt: "gpio-sim.%u:%pfwP" , |
840 | dev->id, |
841 | bank->swnode); |
842 | if (!hog->chip_label) { |
843 | gpio_sim_remove_hogs(dev); |
844 | return -ENOMEM; |
845 | } |
846 | |
847 | /* |
848 | * We need to duplicate this because the hog config |
849 | * item can be removed at any time (and we can't block |
850 | * it) and gpiolib doesn't make a deep copy of the hog |
851 | * data. |
852 | */ |
853 | if (line->hog->name) { |
854 | hog->line_name = kstrdup(s: line->hog->name, |
855 | GFP_KERNEL); |
856 | if (!hog->line_name) { |
857 | gpio_sim_remove_hogs(dev); |
858 | return -ENOMEM; |
859 | } |
860 | } |
861 | |
862 | hog->chip_hwnum = line->offset; |
863 | hog->dflags = line->hog->dir; |
864 | } |
865 | } |
866 | |
867 | gpiod_add_hogs(hogs: dev->hogs); |
868 | |
869 | return 0; |
870 | } |
871 | |
872 | static struct fwnode_handle * |
873 | gpio_sim_make_bank_swnode(struct gpio_sim_bank *bank, |
874 | struct fwnode_handle *parent) |
875 | { |
876 | struct property_entry properties[GPIO_SIM_PROP_MAX]; |
877 | unsigned int prop_idx = 0, line_names_size; |
878 | char **line_names __free(kfree) = NULL; |
879 | |
880 | memset(properties, 0, sizeof(properties)); |
881 | |
882 | properties[prop_idx++] = PROPERTY_ENTRY_U32("ngpios" , bank->num_lines); |
883 | |
884 | if (gpio_sim_bank_has_label(bank)) |
885 | properties[prop_idx++] = PROPERTY_ENTRY_STRING("gpio-sim,label" , |
886 | bank->label); |
887 | |
888 | line_names_size = gpio_sim_get_line_names_size(bank); |
889 | if (line_names_size) { |
890 | line_names = kcalloc(n: line_names_size, size: sizeof(*line_names), |
891 | GFP_KERNEL); |
892 | if (!line_names) |
893 | return ERR_PTR(error: -ENOMEM); |
894 | |
895 | gpio_sim_set_line_names(bank, line_names); |
896 | |
897 | properties[prop_idx++] = PROPERTY_ENTRY_STRING_ARRAY_LEN( |
898 | "gpio-line-names" , |
899 | line_names, line_names_size); |
900 | } |
901 | |
902 | return fwnode_create_software_node(properties, parent); |
903 | } |
904 | |
905 | static void gpio_sim_remove_swnode_recursive(struct fwnode_handle *swnode) |
906 | { |
907 | struct fwnode_handle *child; |
908 | |
909 | fwnode_for_each_child_node(swnode, child) |
910 | fwnode_remove_software_node(fwnode: child); |
911 | |
912 | fwnode_remove_software_node(fwnode: swnode); |
913 | } |
914 | |
915 | static bool gpio_sim_bank_labels_non_unique(struct gpio_sim_device *dev) |
916 | { |
917 | struct gpio_sim_bank *this, *pos; |
918 | |
919 | list_for_each_entry(this, &dev->bank_list, siblings) { |
920 | list_for_each_entry(pos, &dev->bank_list, siblings) { |
921 | if (this == pos || (!this->label || !pos->label)) |
922 | continue; |
923 | |
924 | if (strcmp(this->label, pos->label) == 0) |
925 | return true; |
926 | } |
927 | } |
928 | |
929 | return false; |
930 | } |
931 | |
932 | static int gpio_sim_device_activate(struct gpio_sim_device *dev) |
933 | { |
934 | struct platform_device_info pdevinfo; |
935 | struct fwnode_handle *swnode; |
936 | struct platform_device *pdev; |
937 | struct gpio_sim_bank *bank; |
938 | int ret; |
939 | |
940 | lockdep_assert_held(&dev->lock); |
941 | |
942 | if (list_empty(head: &dev->bank_list)) |
943 | return -ENODATA; |
944 | |
945 | /* |
946 | * Non-unique GPIO device labels are a corner-case we don't support |
947 | * as it would interfere with machine hogging mechanism and has little |
948 | * use in real life. |
949 | */ |
950 | if (gpio_sim_bank_labels_non_unique(dev)) |
951 | return -EINVAL; |
952 | |
953 | memset(&pdevinfo, 0, sizeof(pdevinfo)); |
954 | |
955 | swnode = fwnode_create_software_node(NULL, NULL); |
956 | if (IS_ERR(ptr: swnode)) |
957 | return PTR_ERR(ptr: swnode); |
958 | |
959 | list_for_each_entry(bank, &dev->bank_list, siblings) { |
960 | bank->swnode = gpio_sim_make_bank_swnode(bank, parent: swnode); |
961 | if (IS_ERR(ptr: bank->swnode)) { |
962 | ret = PTR_ERR(ptr: bank->swnode); |
963 | gpio_sim_remove_swnode_recursive(swnode); |
964 | return ret; |
965 | } |
966 | } |
967 | |
968 | ret = gpio_sim_add_hogs(dev); |
969 | if (ret) { |
970 | gpio_sim_remove_swnode_recursive(swnode); |
971 | return ret; |
972 | } |
973 | |
974 | pdevinfo.name = "gpio-sim" ; |
975 | pdevinfo.fwnode = swnode; |
976 | pdevinfo.id = dev->id; |
977 | |
978 | reinit_completion(x: &dev->probe_completion); |
979 | dev->driver_bound = false; |
980 | bus_register_notifier(bus: &platform_bus_type, nb: &dev->bus_notifier); |
981 | |
982 | pdev = platform_device_register_full(pdevinfo: &pdevinfo); |
983 | if (IS_ERR(ptr: pdev)) { |
984 | bus_unregister_notifier(bus: &platform_bus_type, nb: &dev->bus_notifier); |
985 | gpio_sim_remove_hogs(dev); |
986 | gpio_sim_remove_swnode_recursive(swnode); |
987 | return PTR_ERR(ptr: pdev); |
988 | } |
989 | |
990 | wait_for_completion(&dev->probe_completion); |
991 | bus_unregister_notifier(bus: &platform_bus_type, nb: &dev->bus_notifier); |
992 | |
993 | if (!dev->driver_bound) { |
994 | /* Probe failed, check kernel log. */ |
995 | platform_device_unregister(pdev); |
996 | gpio_sim_remove_hogs(dev); |
997 | gpio_sim_remove_swnode_recursive(swnode); |
998 | return -ENXIO; |
999 | } |
1000 | |
1001 | dev->pdev = pdev; |
1002 | |
1003 | return 0; |
1004 | } |
1005 | |
1006 | static void gpio_sim_device_deactivate(struct gpio_sim_device *dev) |
1007 | { |
1008 | struct fwnode_handle *swnode; |
1009 | |
1010 | lockdep_assert_held(&dev->lock); |
1011 | |
1012 | swnode = dev_fwnode(&dev->pdev->dev); |
1013 | platform_device_unregister(dev->pdev); |
1014 | gpio_sim_remove_hogs(dev); |
1015 | gpio_sim_remove_swnode_recursive(swnode); |
1016 | dev->pdev = NULL; |
1017 | } |
1018 | |
1019 | static ssize_t |
1020 | gpio_sim_device_config_live_store(struct config_item *item, |
1021 | const char *page, size_t count) |
1022 | { |
1023 | struct gpio_sim_device *dev = to_gpio_sim_device(item); |
1024 | bool live; |
1025 | int ret; |
1026 | |
1027 | ret = kstrtobool(s: page, res: &live); |
1028 | if (ret) |
1029 | return ret; |
1030 | |
1031 | guard(mutex)(T: &dev->lock); |
1032 | |
1033 | if (live == gpio_sim_device_is_live(dev)) |
1034 | ret = -EPERM; |
1035 | else if (live) |
1036 | ret = gpio_sim_device_activate(dev); |
1037 | else |
1038 | gpio_sim_device_deactivate(dev); |
1039 | |
1040 | return ret ?: count; |
1041 | } |
1042 | |
1043 | CONFIGFS_ATTR(gpio_sim_device_config_, live); |
1044 | |
1045 | static struct configfs_attribute *gpio_sim_device_config_attrs[] = { |
1046 | &gpio_sim_device_config_attr_dev_name, |
1047 | &gpio_sim_device_config_attr_live, |
1048 | NULL |
1049 | }; |
1050 | |
1051 | struct gpio_sim_chip_name_ctx { |
1052 | struct fwnode_handle *swnode; |
1053 | char *page; |
1054 | }; |
1055 | |
1056 | static int gpio_sim_emit_chip_name(struct device *dev, void *data) |
1057 | { |
1058 | struct gpio_sim_chip_name_ctx *ctx = data; |
1059 | |
1060 | /* This would be the sysfs device exported in /sys/class/gpio. */ |
1061 | if (dev->class) |
1062 | return 0; |
1063 | |
1064 | if (device_match_fwnode(dev, fwnode: ctx->swnode)) |
1065 | return sprintf(buf: ctx->page, fmt: "%s\n" , dev_name(dev)); |
1066 | |
1067 | return 0; |
1068 | } |
1069 | |
1070 | static ssize_t gpio_sim_bank_config_chip_name_show(struct config_item *item, |
1071 | char *page) |
1072 | { |
1073 | struct gpio_sim_bank *bank = to_gpio_sim_bank(item); |
1074 | struct gpio_sim_device *dev = gpio_sim_bank_get_device(bank); |
1075 | struct gpio_sim_chip_name_ctx ctx = { bank->swnode, page }; |
1076 | |
1077 | guard(mutex)(T: &dev->lock); |
1078 | |
1079 | if (gpio_sim_device_is_live(dev)) |
1080 | return device_for_each_child(dev: &dev->pdev->dev, data: &ctx, |
1081 | fn: gpio_sim_emit_chip_name); |
1082 | |
1083 | return sprintf(buf: page, fmt: "none\n" ); |
1084 | } |
1085 | |
1086 | CONFIGFS_ATTR_RO(gpio_sim_bank_config_, chip_name); |
1087 | |
1088 | static ssize_t |
1089 | gpio_sim_bank_config_label_show(struct config_item *item, char *page) |
1090 | { |
1091 | struct gpio_sim_bank *bank = to_gpio_sim_bank(item); |
1092 | struct gpio_sim_device *dev = gpio_sim_bank_get_device(bank); |
1093 | |
1094 | guard(mutex)(T: &dev->lock); |
1095 | |
1096 | return sprintf(buf: page, fmt: "%s\n" , bank->label ?: "" ); |
1097 | } |
1098 | |
1099 | static ssize_t gpio_sim_bank_config_label_store(struct config_item *item, |
1100 | const char *page, size_t count) |
1101 | { |
1102 | struct gpio_sim_bank *bank = to_gpio_sim_bank(item); |
1103 | struct gpio_sim_device *dev = gpio_sim_bank_get_device(bank); |
1104 | char *trimmed; |
1105 | |
1106 | guard(mutex)(T: &dev->lock); |
1107 | |
1108 | if (gpio_sim_device_is_live(dev)) |
1109 | return -EBUSY; |
1110 | |
1111 | trimmed = gpio_sim_strdup_trimmed(str: page, count); |
1112 | if (!trimmed) |
1113 | return -ENOMEM; |
1114 | |
1115 | kfree(objp: bank->label); |
1116 | bank->label = trimmed; |
1117 | |
1118 | return count; |
1119 | } |
1120 | |
1121 | CONFIGFS_ATTR(gpio_sim_bank_config_, label); |
1122 | |
1123 | static ssize_t |
1124 | gpio_sim_bank_config_num_lines_show(struct config_item *item, char *page) |
1125 | { |
1126 | struct gpio_sim_bank *bank = to_gpio_sim_bank(item); |
1127 | struct gpio_sim_device *dev = gpio_sim_bank_get_device(bank); |
1128 | |
1129 | guard(mutex)(T: &dev->lock); |
1130 | |
1131 | return sprintf(buf: page, fmt: "%u\n" , bank->num_lines); |
1132 | } |
1133 | |
1134 | static ssize_t |
1135 | gpio_sim_bank_config_num_lines_store(struct config_item *item, |
1136 | const char *page, size_t count) |
1137 | { |
1138 | struct gpio_sim_bank *bank = to_gpio_sim_bank(item); |
1139 | struct gpio_sim_device *dev = gpio_sim_bank_get_device(bank); |
1140 | unsigned int num_lines; |
1141 | int ret; |
1142 | |
1143 | ret = kstrtouint(s: page, base: 0, res: &num_lines); |
1144 | if (ret) |
1145 | return ret; |
1146 | |
1147 | if (num_lines == 0) |
1148 | return -EINVAL; |
1149 | |
1150 | guard(mutex)(T: &dev->lock); |
1151 | |
1152 | if (gpio_sim_device_is_live(dev)) |
1153 | return -EBUSY; |
1154 | |
1155 | bank->num_lines = num_lines; |
1156 | |
1157 | return count; |
1158 | } |
1159 | |
1160 | CONFIGFS_ATTR(gpio_sim_bank_config_, num_lines); |
1161 | |
1162 | static struct configfs_attribute *gpio_sim_bank_config_attrs[] = { |
1163 | &gpio_sim_bank_config_attr_chip_name, |
1164 | &gpio_sim_bank_config_attr_label, |
1165 | &gpio_sim_bank_config_attr_num_lines, |
1166 | NULL |
1167 | }; |
1168 | |
1169 | static ssize_t |
1170 | gpio_sim_line_config_name_show(struct config_item *item, char *page) |
1171 | { |
1172 | struct gpio_sim_line *line = to_gpio_sim_line(item); |
1173 | struct gpio_sim_device *dev = gpio_sim_line_get_device(line); |
1174 | |
1175 | guard(mutex)(T: &dev->lock); |
1176 | |
1177 | return sprintf(buf: page, fmt: "%s\n" , line->name ?: "" ); |
1178 | } |
1179 | |
1180 | static ssize_t gpio_sim_line_config_name_store(struct config_item *item, |
1181 | const char *page, size_t count) |
1182 | { |
1183 | struct gpio_sim_line *line = to_gpio_sim_line(item); |
1184 | struct gpio_sim_device *dev = gpio_sim_line_get_device(line); |
1185 | char *trimmed; |
1186 | |
1187 | guard(mutex)(T: &dev->lock); |
1188 | |
1189 | if (gpio_sim_device_is_live(dev)) |
1190 | return -EBUSY; |
1191 | |
1192 | trimmed = gpio_sim_strdup_trimmed(str: page, count); |
1193 | if (!trimmed) |
1194 | return -ENOMEM; |
1195 | |
1196 | kfree(objp: line->name); |
1197 | line->name = trimmed; |
1198 | |
1199 | return count; |
1200 | } |
1201 | |
1202 | CONFIGFS_ATTR(gpio_sim_line_config_, name); |
1203 | |
1204 | static struct configfs_attribute *gpio_sim_line_config_attrs[] = { |
1205 | &gpio_sim_line_config_attr_name, |
1206 | NULL |
1207 | }; |
1208 | |
1209 | static ssize_t gpio_sim_hog_config_name_show(struct config_item *item, |
1210 | char *page) |
1211 | { |
1212 | struct gpio_sim_hog *hog = to_gpio_sim_hog(item); |
1213 | struct gpio_sim_device *dev = gpio_sim_hog_get_device(hog); |
1214 | |
1215 | guard(mutex)(T: &dev->lock); |
1216 | |
1217 | return sprintf(buf: page, fmt: "%s\n" , hog->name ?: "" ); |
1218 | } |
1219 | |
1220 | static ssize_t gpio_sim_hog_config_name_store(struct config_item *item, |
1221 | const char *page, size_t count) |
1222 | { |
1223 | struct gpio_sim_hog *hog = to_gpio_sim_hog(item); |
1224 | struct gpio_sim_device *dev = gpio_sim_hog_get_device(hog); |
1225 | char *trimmed; |
1226 | |
1227 | guard(mutex)(T: &dev->lock); |
1228 | |
1229 | if (gpio_sim_device_is_live(dev)) |
1230 | return -EBUSY; |
1231 | |
1232 | trimmed = gpio_sim_strdup_trimmed(str: page, count); |
1233 | if (!trimmed) |
1234 | return -ENOMEM; |
1235 | |
1236 | kfree(objp: hog->name); |
1237 | hog->name = trimmed; |
1238 | |
1239 | return count; |
1240 | } |
1241 | |
1242 | CONFIGFS_ATTR(gpio_sim_hog_config_, name); |
1243 | |
1244 | static ssize_t gpio_sim_hog_config_direction_show(struct config_item *item, |
1245 | char *page) |
1246 | { |
1247 | struct gpio_sim_hog *hog = to_gpio_sim_hog(item); |
1248 | struct gpio_sim_device *dev = gpio_sim_hog_get_device(hog); |
1249 | char *repr; |
1250 | int dir; |
1251 | |
1252 | scoped_guard(mutex, &dev->lock) |
1253 | dir = hog->dir; |
1254 | |
1255 | switch (dir) { |
1256 | case GPIOD_IN: |
1257 | repr = "input" ; |
1258 | break; |
1259 | case GPIOD_OUT_HIGH: |
1260 | repr = "output-high" ; |
1261 | break; |
1262 | case GPIOD_OUT_LOW: |
1263 | repr = "output-low" ; |
1264 | break; |
1265 | default: |
1266 | /* This would be a programmer bug. */ |
1267 | WARN(1, "Unexpected hog direction value: %d" , dir); |
1268 | return -EINVAL; |
1269 | } |
1270 | |
1271 | return sprintf(buf: page, fmt: "%s\n" , repr); |
1272 | } |
1273 | |
1274 | static ssize_t |
1275 | gpio_sim_hog_config_direction_store(struct config_item *item, |
1276 | const char *page, size_t count) |
1277 | { |
1278 | struct gpio_sim_hog *hog = to_gpio_sim_hog(item); |
1279 | struct gpio_sim_device *dev = gpio_sim_hog_get_device(hog); |
1280 | int dir; |
1281 | |
1282 | guard(mutex)(T: &dev->lock); |
1283 | |
1284 | if (gpio_sim_device_is_live(dev)) |
1285 | return -EBUSY; |
1286 | |
1287 | if (sysfs_streq(s1: page, s2: "input" )) |
1288 | dir = GPIOD_IN; |
1289 | else if (sysfs_streq(s1: page, s2: "output-high" )) |
1290 | dir = GPIOD_OUT_HIGH; |
1291 | else if (sysfs_streq(s1: page, s2: "output-low" )) |
1292 | dir = GPIOD_OUT_LOW; |
1293 | else |
1294 | return -EINVAL; |
1295 | |
1296 | hog->dir = dir; |
1297 | |
1298 | return count; |
1299 | } |
1300 | |
1301 | CONFIGFS_ATTR(gpio_sim_hog_config_, direction); |
1302 | |
1303 | static struct configfs_attribute *gpio_sim_hog_config_attrs[] = { |
1304 | &gpio_sim_hog_config_attr_name, |
1305 | &gpio_sim_hog_config_attr_direction, |
1306 | NULL |
1307 | }; |
1308 | |
1309 | static void gpio_sim_hog_config_item_release(struct config_item *item) |
1310 | { |
1311 | struct gpio_sim_hog *hog = to_gpio_sim_hog(item); |
1312 | struct gpio_sim_line *line = hog->parent; |
1313 | struct gpio_sim_device *dev = gpio_sim_hog_get_device(hog); |
1314 | |
1315 | scoped_guard(mutex, &dev->lock) |
1316 | line->hog = NULL; |
1317 | |
1318 | kfree(objp: hog->name); |
1319 | kfree(objp: hog); |
1320 | } |
1321 | |
1322 | static struct configfs_item_operations gpio_sim_hog_config_item_ops = { |
1323 | .release = gpio_sim_hog_config_item_release, |
1324 | }; |
1325 | |
1326 | static const struct config_item_type gpio_sim_hog_config_type = { |
1327 | .ct_item_ops = &gpio_sim_hog_config_item_ops, |
1328 | .ct_attrs = gpio_sim_hog_config_attrs, |
1329 | .ct_owner = THIS_MODULE, |
1330 | }; |
1331 | |
1332 | static struct config_item * |
1333 | gpio_sim_line_config_make_hog_item(struct config_group *group, const char *name) |
1334 | { |
1335 | struct gpio_sim_line *line = to_gpio_sim_line(item: &group->cg_item); |
1336 | struct gpio_sim_device *dev = gpio_sim_line_get_device(line); |
1337 | struct gpio_sim_hog *hog; |
1338 | |
1339 | if (strcmp(name, "hog" ) != 0) |
1340 | return ERR_PTR(error: -EINVAL); |
1341 | |
1342 | guard(mutex)(T: &dev->lock); |
1343 | |
1344 | hog = kzalloc(size: sizeof(*hog), GFP_KERNEL); |
1345 | if (!hog) |
1346 | return ERR_PTR(error: -ENOMEM); |
1347 | |
1348 | config_item_init_type_name(item: &hog->item, name, |
1349 | type: &gpio_sim_hog_config_type); |
1350 | |
1351 | hog->dir = GPIOD_IN; |
1352 | hog->name = NULL; |
1353 | hog->parent = line; |
1354 | line->hog = hog; |
1355 | |
1356 | return &hog->item; |
1357 | } |
1358 | |
1359 | static void gpio_sim_line_config_group_release(struct config_item *item) |
1360 | { |
1361 | struct gpio_sim_line *line = to_gpio_sim_line(item); |
1362 | struct gpio_sim_device *dev = gpio_sim_line_get_device(line); |
1363 | |
1364 | scoped_guard(mutex, &dev->lock) |
1365 | list_del(entry: &line->siblings); |
1366 | |
1367 | kfree(objp: line->name); |
1368 | kfree(objp: line); |
1369 | } |
1370 | |
1371 | static struct configfs_item_operations gpio_sim_line_config_item_ops = { |
1372 | .release = gpio_sim_line_config_group_release, |
1373 | }; |
1374 | |
1375 | static struct configfs_group_operations gpio_sim_line_config_group_ops = { |
1376 | .make_item = gpio_sim_line_config_make_hog_item, |
1377 | }; |
1378 | |
1379 | static const struct config_item_type gpio_sim_line_config_type = { |
1380 | .ct_item_ops = &gpio_sim_line_config_item_ops, |
1381 | .ct_group_ops = &gpio_sim_line_config_group_ops, |
1382 | .ct_attrs = gpio_sim_line_config_attrs, |
1383 | .ct_owner = THIS_MODULE, |
1384 | }; |
1385 | |
1386 | static struct config_group * |
1387 | gpio_sim_bank_config_make_line_group(struct config_group *group, |
1388 | const char *name) |
1389 | { |
1390 | struct gpio_sim_bank *bank = to_gpio_sim_bank(item: &group->cg_item); |
1391 | struct gpio_sim_device *dev = gpio_sim_bank_get_device(bank); |
1392 | struct gpio_sim_line *line; |
1393 | unsigned int offset; |
1394 | int ret, nchar; |
1395 | |
1396 | ret = sscanf(name, "line%u%n" , &offset, &nchar); |
1397 | if (ret != 1 || nchar != strlen(name)) |
1398 | return ERR_PTR(error: -EINVAL); |
1399 | |
1400 | guard(mutex)(T: &dev->lock); |
1401 | |
1402 | if (gpio_sim_device_is_live(dev)) |
1403 | return ERR_PTR(error: -EBUSY); |
1404 | |
1405 | line = kzalloc(size: sizeof(*line), GFP_KERNEL); |
1406 | if (!line) |
1407 | return ERR_PTR(error: -ENOMEM); |
1408 | |
1409 | config_group_init_type_name(group: &line->group, name, |
1410 | type: &gpio_sim_line_config_type); |
1411 | |
1412 | line->parent = bank; |
1413 | line->offset = offset; |
1414 | list_add_tail(new: &line->siblings, head: &bank->line_list); |
1415 | |
1416 | return &line->group; |
1417 | } |
1418 | |
1419 | static void gpio_sim_bank_config_group_release(struct config_item *item) |
1420 | { |
1421 | struct gpio_sim_bank *bank = to_gpio_sim_bank(item); |
1422 | struct gpio_sim_device *dev = gpio_sim_bank_get_device(bank); |
1423 | |
1424 | scoped_guard(mutex, &dev->lock) |
1425 | list_del(entry: &bank->siblings); |
1426 | |
1427 | kfree(objp: bank->label); |
1428 | kfree(objp: bank); |
1429 | } |
1430 | |
1431 | static struct configfs_item_operations gpio_sim_bank_config_item_ops = { |
1432 | .release = gpio_sim_bank_config_group_release, |
1433 | }; |
1434 | |
1435 | static struct configfs_group_operations gpio_sim_bank_config_group_ops = { |
1436 | .make_group = gpio_sim_bank_config_make_line_group, |
1437 | }; |
1438 | |
1439 | static const struct config_item_type gpio_sim_bank_config_group_type = { |
1440 | .ct_item_ops = &gpio_sim_bank_config_item_ops, |
1441 | .ct_group_ops = &gpio_sim_bank_config_group_ops, |
1442 | .ct_attrs = gpio_sim_bank_config_attrs, |
1443 | .ct_owner = THIS_MODULE, |
1444 | }; |
1445 | |
1446 | static struct config_group * |
1447 | gpio_sim_device_config_make_bank_group(struct config_group *group, |
1448 | const char *name) |
1449 | { |
1450 | struct gpio_sim_device *dev = to_gpio_sim_device(item: &group->cg_item); |
1451 | struct gpio_sim_bank *bank; |
1452 | |
1453 | guard(mutex)(T: &dev->lock); |
1454 | |
1455 | if (gpio_sim_device_is_live(dev)) |
1456 | return ERR_PTR(error: -EBUSY); |
1457 | |
1458 | bank = kzalloc(size: sizeof(*bank), GFP_KERNEL); |
1459 | if (!bank) |
1460 | return ERR_PTR(error: -ENOMEM); |
1461 | |
1462 | config_group_init_type_name(group: &bank->group, name, |
1463 | type: &gpio_sim_bank_config_group_type); |
1464 | bank->num_lines = 1; |
1465 | bank->parent = dev; |
1466 | INIT_LIST_HEAD(list: &bank->line_list); |
1467 | list_add_tail(new: &bank->siblings, head: &dev->bank_list); |
1468 | |
1469 | return &bank->group; |
1470 | } |
1471 | |
1472 | static void gpio_sim_device_config_group_release(struct config_item *item) |
1473 | { |
1474 | struct gpio_sim_device *dev = to_gpio_sim_device(item); |
1475 | |
1476 | scoped_guard(mutex, &dev->lock) { |
1477 | if (gpio_sim_device_is_live(dev)) |
1478 | gpio_sim_device_deactivate(dev); |
1479 | } |
1480 | |
1481 | mutex_destroy(lock: &dev->lock); |
1482 | ida_free(&gpio_sim_ida, id: dev->id); |
1483 | kfree(objp: dev); |
1484 | } |
1485 | |
1486 | static struct configfs_item_operations gpio_sim_device_config_item_ops = { |
1487 | .release = gpio_sim_device_config_group_release, |
1488 | }; |
1489 | |
1490 | static struct configfs_group_operations gpio_sim_device_config_group_ops = { |
1491 | .make_group = gpio_sim_device_config_make_bank_group, |
1492 | }; |
1493 | |
1494 | static const struct config_item_type gpio_sim_device_config_group_type = { |
1495 | .ct_item_ops = &gpio_sim_device_config_item_ops, |
1496 | .ct_group_ops = &gpio_sim_device_config_group_ops, |
1497 | .ct_attrs = gpio_sim_device_config_attrs, |
1498 | .ct_owner = THIS_MODULE, |
1499 | }; |
1500 | |
1501 | static struct config_group * |
1502 | gpio_sim_config_make_device_group(struct config_group *group, const char *name) |
1503 | { |
1504 | int id; |
1505 | |
1506 | struct gpio_sim_device *dev __free(kfree) = kzalloc(size: sizeof(*dev), |
1507 | GFP_KERNEL); |
1508 | if (!dev) |
1509 | return ERR_PTR(error: -ENOMEM); |
1510 | |
1511 | id = ida_alloc(ida: &gpio_sim_ida, GFP_KERNEL); |
1512 | if (id < 0) |
1513 | return ERR_PTR(error: id); |
1514 | |
1515 | config_group_init_type_name(group: &dev->group, name, |
1516 | type: &gpio_sim_device_config_group_type); |
1517 | dev->id = id; |
1518 | mutex_init(&dev->lock); |
1519 | INIT_LIST_HEAD(list: &dev->bank_list); |
1520 | |
1521 | dev->bus_notifier.notifier_call = gpio_sim_bus_notifier_call; |
1522 | init_completion(x: &dev->probe_completion); |
1523 | |
1524 | return &no_free_ptr(dev)->group; |
1525 | } |
1526 | |
1527 | static struct configfs_group_operations gpio_sim_config_group_ops = { |
1528 | .make_group = gpio_sim_config_make_device_group, |
1529 | }; |
1530 | |
1531 | static const struct config_item_type gpio_sim_config_type = { |
1532 | .ct_group_ops = &gpio_sim_config_group_ops, |
1533 | .ct_owner = THIS_MODULE, |
1534 | }; |
1535 | |
1536 | static struct configfs_subsystem gpio_sim_config_subsys = { |
1537 | .su_group = { |
1538 | .cg_item = { |
1539 | .ci_namebuf = "gpio-sim" , |
1540 | .ci_type = &gpio_sim_config_type, |
1541 | }, |
1542 | }, |
1543 | }; |
1544 | |
1545 | static int __init gpio_sim_init(void) |
1546 | { |
1547 | int ret; |
1548 | |
1549 | ret = platform_driver_register(&gpio_sim_driver); |
1550 | if (ret) { |
1551 | pr_err("Error %d while registering the platform driver\n" , ret); |
1552 | return ret; |
1553 | } |
1554 | |
1555 | config_group_init(group: &gpio_sim_config_subsys.su_group); |
1556 | mutex_init(&gpio_sim_config_subsys.su_mutex); |
1557 | ret = configfs_register_subsystem(subsys: &gpio_sim_config_subsys); |
1558 | if (ret) { |
1559 | pr_err("Error %d while registering the configfs subsystem %s\n" , |
1560 | ret, gpio_sim_config_subsys.su_group.cg_item.ci_namebuf); |
1561 | mutex_destroy(lock: &gpio_sim_config_subsys.su_mutex); |
1562 | platform_driver_unregister(&gpio_sim_driver); |
1563 | return ret; |
1564 | } |
1565 | |
1566 | return 0; |
1567 | } |
1568 | module_init(gpio_sim_init); |
1569 | |
1570 | static void __exit gpio_sim_exit(void) |
1571 | { |
1572 | configfs_unregister_subsystem(subsys: &gpio_sim_config_subsys); |
1573 | mutex_destroy(lock: &gpio_sim_config_subsys.su_mutex); |
1574 | platform_driver_unregister(&gpio_sim_driver); |
1575 | } |
1576 | module_exit(gpio_sim_exit); |
1577 | |
1578 | MODULE_AUTHOR("Bartosz Golaszewski <brgl@bgdev.pl>" ); |
1579 | MODULE_DESCRIPTION("GPIO Simulator Module" ); |
1580 | MODULE_LICENSE("GPL" ); |
1581 | |