Merge tag 'v5.10-rc1' into regulator-5.10
[linux-2.6-block.git] / drivers / counter / counter.c
CommitLineData
0040a390
WBG
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Generic Counter interface
4 * Copyright (C) 2018 William Breathitt Gray
5 */
6#include <linux/counter.h>
7#include <linux/device.h>
8#include <linux/err.h>
9#include <linux/export.h>
10#include <linux/fs.h>
11#include <linux/gfp.h>
12#include <linux/idr.h>
13#include <linux/init.h>
14#include <linux/kernel.h>
15#include <linux/list.h>
16#include <linux/module.h>
17#include <linux/printk.h>
18#include <linux/slab.h>
19#include <linux/string.h>
20#include <linux/sysfs.h>
21#include <linux/types.h>
22
23const char *const counter_count_direction_str[2] = {
24 [COUNTER_COUNT_DIRECTION_FORWARD] = "forward",
25 [COUNTER_COUNT_DIRECTION_BACKWARD] = "backward"
26};
27EXPORT_SYMBOL_GPL(counter_count_direction_str);
28
29const char *const counter_count_mode_str[4] = {
30 [COUNTER_COUNT_MODE_NORMAL] = "normal",
31 [COUNTER_COUNT_MODE_RANGE_LIMIT] = "range limit",
32 [COUNTER_COUNT_MODE_NON_RECYCLE] = "non-recycle",
33 [COUNTER_COUNT_MODE_MODULO_N] = "modulo-n"
34};
35EXPORT_SYMBOL_GPL(counter_count_mode_str);
36
37ssize_t counter_signal_enum_read(struct counter_device *counter,
38 struct counter_signal *signal, void *priv,
39 char *buf)
40{
41 const struct counter_signal_enum_ext *const e = priv;
42 int err;
43 size_t index;
44
45 if (!e->get)
46 return -EINVAL;
47
48 err = e->get(counter, signal, &index);
49 if (err)
50 return err;
51
52 if (index >= e->num_items)
53 return -EINVAL;
54
55 return sprintf(buf, "%s\n", e->items[index]);
56}
57EXPORT_SYMBOL_GPL(counter_signal_enum_read);
58
59ssize_t counter_signal_enum_write(struct counter_device *counter,
60 struct counter_signal *signal, void *priv,
61 const char *buf, size_t len)
62{
63 const struct counter_signal_enum_ext *const e = priv;
64 ssize_t index;
65 int err;
66
67 if (!e->set)
68 return -EINVAL;
69
70 index = __sysfs_match_string(e->items, e->num_items, buf);
71 if (index < 0)
72 return index;
73
74 err = e->set(counter, signal, index);
75 if (err)
76 return err;
77
78 return len;
79}
80EXPORT_SYMBOL_GPL(counter_signal_enum_write);
81
82ssize_t counter_signal_enum_available_read(struct counter_device *counter,
83 struct counter_signal *signal,
84 void *priv, char *buf)
85{
86 const struct counter_signal_enum_ext *const e = priv;
87 size_t i;
88 size_t len = 0;
89
90 if (!e->num_items)
91 return 0;
92
93 for (i = 0; i < e->num_items; i++)
94 len += sprintf(buf + len, "%s\n", e->items[i]);
95
96 return len;
97}
98EXPORT_SYMBOL_GPL(counter_signal_enum_available_read);
99
100ssize_t counter_count_enum_read(struct counter_device *counter,
101 struct counter_count *count, void *priv,
102 char *buf)
103{
104 const struct counter_count_enum_ext *const e = priv;
105 int err;
106 size_t index;
107
108 if (!e->get)
109 return -EINVAL;
110
111 err = e->get(counter, count, &index);
112 if (err)
113 return err;
114
115 if (index >= e->num_items)
116 return -EINVAL;
117
118 return sprintf(buf, "%s\n", e->items[index]);
119}
120EXPORT_SYMBOL_GPL(counter_count_enum_read);
121
122ssize_t counter_count_enum_write(struct counter_device *counter,
123 struct counter_count *count, void *priv,
124 const char *buf, size_t len)
125{
126 const struct counter_count_enum_ext *const e = priv;
127 ssize_t index;
128 int err;
129
130 if (!e->set)
131 return -EINVAL;
132
133 index = __sysfs_match_string(e->items, e->num_items, buf);
134 if (index < 0)
135 return index;
136
137 err = e->set(counter, count, index);
138 if (err)
139 return err;
140
141 return len;
142}
143EXPORT_SYMBOL_GPL(counter_count_enum_write);
144
145ssize_t counter_count_enum_available_read(struct counter_device *counter,
146 struct counter_count *count,
147 void *priv, char *buf)
148{
149 const struct counter_count_enum_ext *const e = priv;
150 size_t i;
151 size_t len = 0;
152
153 if (!e->num_items)
154 return 0;
155
156 for (i = 0; i < e->num_items; i++)
157 len += sprintf(buf + len, "%s\n", e->items[i]);
158
159 return len;
160}
161EXPORT_SYMBOL_GPL(counter_count_enum_available_read);
162
163ssize_t counter_device_enum_read(struct counter_device *counter, void *priv,
164 char *buf)
165{
166 const struct counter_device_enum_ext *const e = priv;
167 int err;
168 size_t index;
169
170 if (!e->get)
171 return -EINVAL;
172
173 err = e->get(counter, &index);
174 if (err)
175 return err;
176
177 if (index >= e->num_items)
178 return -EINVAL;
179
180 return sprintf(buf, "%s\n", e->items[index]);
181}
182EXPORT_SYMBOL_GPL(counter_device_enum_read);
183
184ssize_t counter_device_enum_write(struct counter_device *counter, void *priv,
185 const char *buf, size_t len)
186{
187 const struct counter_device_enum_ext *const e = priv;
188 ssize_t index;
189 int err;
190
191 if (!e->set)
192 return -EINVAL;
193
194 index = __sysfs_match_string(e->items, e->num_items, buf);
195 if (index < 0)
196 return index;
197
198 err = e->set(counter, index);
199 if (err)
200 return err;
201
202 return len;
203}
204EXPORT_SYMBOL_GPL(counter_device_enum_write);
205
206ssize_t counter_device_enum_available_read(struct counter_device *counter,
207 void *priv, char *buf)
208{
209 const struct counter_device_enum_ext *const e = priv;
210 size_t i;
211 size_t len = 0;
212
213 if (!e->num_items)
214 return 0;
215
216 for (i = 0; i < e->num_items; i++)
217 len += sprintf(buf + len, "%s\n", e->items[i]);
218
219 return len;
220}
221EXPORT_SYMBOL_GPL(counter_device_enum_available_read);
222
0040a390
WBG
223struct counter_attr_parm {
224 struct counter_device_attr_group *group;
225 const char *prefix;
226 const char *name;
227 ssize_t (*show)(struct device *dev, struct device_attribute *attr,
228 char *buf);
229 ssize_t (*store)(struct device *dev, struct device_attribute *attr,
230 const char *buf, size_t len);
231 void *component;
232};
233
234struct counter_device_attr {
235 struct device_attribute dev_attr;
236 struct list_head l;
237 void *component;
238};
239
240static int counter_attribute_create(const struct counter_attr_parm *const parm)
241{
242 struct counter_device_attr *counter_attr;
243 struct device_attribute *dev_attr;
244 int err;
245 struct list_head *const attr_list = &parm->group->attr_list;
246
247 /* Allocate a Counter device attribute */
248 counter_attr = kzalloc(sizeof(*counter_attr), GFP_KERNEL);
249 if (!counter_attr)
250 return -ENOMEM;
251 dev_attr = &counter_attr->dev_attr;
252
253 sysfs_attr_init(&dev_attr->attr);
254
255 /* Configure device attribute */
256 dev_attr->attr.name = kasprintf(GFP_KERNEL, "%s%s", parm->prefix,
257 parm->name);
258 if (!dev_attr->attr.name) {
259 err = -ENOMEM;
260 goto err_free_counter_attr;
261 }
262 if (parm->show) {
263 dev_attr->attr.mode |= 0444;
264 dev_attr->show = parm->show;
265 }
266 if (parm->store) {
267 dev_attr->attr.mode |= 0200;
268 dev_attr->store = parm->store;
269 }
270
271 /* Store associated Counter component with attribute */
272 counter_attr->component = parm->component;
273
274 /* Keep track of the attribute for later cleanup */
275 list_add(&counter_attr->l, attr_list);
276 parm->group->num_attr++;
277
278 return 0;
279
280err_free_counter_attr:
281 kfree(counter_attr);
282 return err;
283}
284
285#define to_counter_attr(_dev_attr) \
286 container_of(_dev_attr, struct counter_device_attr, dev_attr)
287
288struct counter_signal_unit {
289 struct counter_signal *signal;
290};
291
d49e6ee2
WBG
292static const char *const counter_signal_value_str[] = {
293 [COUNTER_SIGNAL_LOW] = "low",
294 [COUNTER_SIGNAL_HIGH] = "high"
295};
296
0040a390
WBG
297static ssize_t counter_signal_show(struct device *dev,
298 struct device_attribute *attr, char *buf)
299{
300 struct counter_device *const counter = dev_get_drvdata(dev);
301 const struct counter_device_attr *const devattr = to_counter_attr(attr);
302 const struct counter_signal_unit *const component = devattr->component;
303 struct counter_signal *const signal = component->signal;
304 int err;
d49e6ee2 305 enum counter_signal_value val;
0040a390
WBG
306
307 err = counter->ops->signal_read(counter, signal, &val);
308 if (err)
309 return err;
310
d49e6ee2 311 return sprintf(buf, "%s\n", counter_signal_value_str[val]);
0040a390
WBG
312}
313
314struct counter_name_unit {
315 const char *name;
316};
317
318static ssize_t counter_device_attr_name_show(struct device *dev,
319 struct device_attribute *attr,
320 char *buf)
321{
322 const struct counter_name_unit *const comp = to_counter_attr(attr)->component;
323
324 return sprintf(buf, "%s\n", comp->name);
325}
326
327static int counter_name_attribute_create(
328 struct counter_device_attr_group *const group,
329 const char *const name)
330{
331 struct counter_name_unit *name_comp;
332 struct counter_attr_parm parm;
333 int err;
334
335 /* Skip if no name */
336 if (!name)
337 return 0;
338
339 /* Allocate name attribute component */
340 name_comp = kmalloc(sizeof(*name_comp), GFP_KERNEL);
341 if (!name_comp)
342 return -ENOMEM;
343 name_comp->name = name;
344
345 /* Allocate Signal name attribute */
346 parm.group = group;
347 parm.prefix = "";
348 parm.name = "name";
349 parm.show = counter_device_attr_name_show;
350 parm.store = NULL;
351 parm.component = name_comp;
352 err = counter_attribute_create(&parm);
353 if (err)
354 goto err_free_name_comp;
355
356 return 0;
357
358err_free_name_comp:
359 kfree(name_comp);
360 return err;
361}
362
363struct counter_signal_ext_unit {
364 struct counter_signal *signal;
365 const struct counter_signal_ext *ext;
366};
367
368static ssize_t counter_signal_ext_show(struct device *dev,
369 struct device_attribute *attr, char *buf)
370{
371 const struct counter_device_attr *const devattr = to_counter_attr(attr);
372 const struct counter_signal_ext_unit *const comp = devattr->component;
373 const struct counter_signal_ext *const ext = comp->ext;
374
375 return ext->read(dev_get_drvdata(dev), comp->signal, ext->priv, buf);
376}
377
378static ssize_t counter_signal_ext_store(struct device *dev,
379 struct device_attribute *attr,
380 const char *buf, size_t len)
381{
382 const struct counter_device_attr *const devattr = to_counter_attr(attr);
383 const struct counter_signal_ext_unit *const comp = devattr->component;
384 const struct counter_signal_ext *const ext = comp->ext;
385
386 return ext->write(dev_get_drvdata(dev), comp->signal, ext->priv, buf,
387 len);
388}
389
390static void counter_device_attr_list_free(struct list_head *attr_list)
391{
392 struct counter_device_attr *p, *n;
393
394 list_for_each_entry_safe(p, n, attr_list, l) {
395 /* free attribute name and associated component memory */
396 kfree(p->dev_attr.attr.name);
397 kfree(p->component);
398 list_del(&p->l);
399 kfree(p);
400 }
401}
402
403static int counter_signal_ext_register(
404 struct counter_device_attr_group *const group,
405 struct counter_signal *const signal)
406{
407 const size_t num_ext = signal->num_ext;
408 size_t i;
409 const struct counter_signal_ext *ext;
410 struct counter_signal_ext_unit *signal_ext_comp;
411 struct counter_attr_parm parm;
412 int err;
413
414 /* Create an attribute for each extension */
415 for (i = 0 ; i < num_ext; i++) {
416 ext = signal->ext + i;
417
418 /* Allocate signal_ext attribute component */
419 signal_ext_comp = kmalloc(sizeof(*signal_ext_comp), GFP_KERNEL);
420 if (!signal_ext_comp) {
421 err = -ENOMEM;
422 goto err_free_attr_list;
423 }
424 signal_ext_comp->signal = signal;
425 signal_ext_comp->ext = ext;
426
427 /* Allocate a Counter device attribute */
428 parm.group = group;
429 parm.prefix = "";
430 parm.name = ext->name;
431 parm.show = (ext->read) ? counter_signal_ext_show : NULL;
432 parm.store = (ext->write) ? counter_signal_ext_store : NULL;
433 parm.component = signal_ext_comp;
434 err = counter_attribute_create(&parm);
435 if (err) {
436 kfree(signal_ext_comp);
437 goto err_free_attr_list;
438 }
439 }
440
441 return 0;
442
443err_free_attr_list:
444 counter_device_attr_list_free(&group->attr_list);
445 return err;
446}
447
448static int counter_signal_attributes_create(
449 struct counter_device_attr_group *const group,
450 const struct counter_device *const counter,
451 struct counter_signal *const signal)
452{
453 struct counter_signal_unit *signal_comp;
454 struct counter_attr_parm parm;
455 int err;
456
457 /* Allocate Signal attribute component */
458 signal_comp = kmalloc(sizeof(*signal_comp), GFP_KERNEL);
459 if (!signal_comp)
460 return -ENOMEM;
461 signal_comp->signal = signal;
462
463 /* Create main Signal attribute */
464 parm.group = group;
465 parm.prefix = "";
466 parm.name = "signal";
467 parm.show = (counter->ops->signal_read) ? counter_signal_show : NULL;
468 parm.store = NULL;
469 parm.component = signal_comp;
470 err = counter_attribute_create(&parm);
471 if (err) {
472 kfree(signal_comp);
473 return err;
474 }
475
476 /* Create Signal name attribute */
477 err = counter_name_attribute_create(group, signal->name);
478 if (err)
479 goto err_free_attr_list;
480
481 /* Register Signal extension attributes */
482 err = counter_signal_ext_register(group, signal);
483 if (err)
484 goto err_free_attr_list;
485
486 return 0;
487
488err_free_attr_list:
489 counter_device_attr_list_free(&group->attr_list);
490 return err;
491}
492
493static int counter_signals_register(
494 struct counter_device_attr_group *const groups_list,
495 const struct counter_device *const counter)
496{
497 const size_t num_signals = counter->num_signals;
498 size_t i;
499 struct counter_signal *signal;
500 const char *name;
501 int err;
502
503 /* Register each Signal */
504 for (i = 0; i < num_signals; i++) {
505 signal = counter->signals + i;
506
507 /* Generate Signal attribute directory name */
508 name = kasprintf(GFP_KERNEL, "signal%d", signal->id);
509 if (!name) {
510 err = -ENOMEM;
511 goto err_free_attr_groups;
512 }
513 groups_list[i].attr_group.name = name;
514
515 /* Create all attributes associated with Signal */
516 err = counter_signal_attributes_create(groups_list + i, counter,
517 signal);
518 if (err)
519 goto err_free_attr_groups;
520 }
521
522 return 0;
523
524err_free_attr_groups:
525 do {
526 kfree(groups_list[i].attr_group.name);
527 counter_device_attr_list_free(&groups_list[i].attr_list);
528 } while (i--);
529 return err;
530}
531
532static const char *const counter_synapse_action_str[] = {
533 [COUNTER_SYNAPSE_ACTION_NONE] = "none",
534 [COUNTER_SYNAPSE_ACTION_RISING_EDGE] = "rising edge",
535 [COUNTER_SYNAPSE_ACTION_FALLING_EDGE] = "falling edge",
536 [COUNTER_SYNAPSE_ACTION_BOTH_EDGES] = "both edges"
537};
538
539struct counter_action_unit {
540 struct counter_synapse *synapse;
541 struct counter_count *count;
542};
543
544static ssize_t counter_action_show(struct device *dev,
545 struct device_attribute *attr, char *buf)
546{
547 const struct counter_device_attr *const devattr = to_counter_attr(attr);
548 int err;
549 struct counter_device *const counter = dev_get_drvdata(dev);
550 const struct counter_action_unit *const component = devattr->component;
551 struct counter_count *const count = component->count;
552 struct counter_synapse *const synapse = component->synapse;
553 size_t action_index;
554 enum counter_synapse_action action;
555
556 err = counter->ops->action_get(counter, count, synapse, &action_index);
557 if (err)
558 return err;
559
560 synapse->action = action_index;
561
562 action = synapse->actions_list[action_index];
563 return sprintf(buf, "%s\n", counter_synapse_action_str[action]);
564}
565
566static ssize_t counter_action_store(struct device *dev,
567 struct device_attribute *attr,
568 const char *buf, size_t len)
569{
570 const struct counter_device_attr *const devattr = to_counter_attr(attr);
571 const struct counter_action_unit *const component = devattr->component;
572 struct counter_synapse *const synapse = component->synapse;
573 size_t action_index;
574 const size_t num_actions = synapse->num_actions;
575 enum counter_synapse_action action;
576 int err;
577 struct counter_device *const counter = dev_get_drvdata(dev);
578 struct counter_count *const count = component->count;
579
580 /* Find requested action mode */
581 for (action_index = 0; action_index < num_actions; action_index++) {
582 action = synapse->actions_list[action_index];
583 if (sysfs_streq(buf, counter_synapse_action_str[action]))
584 break;
585 }
586 /* If requested action mode not found */
587 if (action_index >= num_actions)
588 return -EINVAL;
589
590 err = counter->ops->action_set(counter, count, synapse, action_index);
591 if (err)
592 return err;
593
594 synapse->action = action_index;
595
596 return len;
597}
598
599struct counter_action_avail_unit {
600 const enum counter_synapse_action *actions_list;
601 size_t num_actions;
602};
603
604static ssize_t counter_synapse_action_available_show(struct device *dev,
605 struct device_attribute *attr, char *buf)
606{
607 const struct counter_device_attr *const devattr = to_counter_attr(attr);
608 const struct counter_action_avail_unit *const component = devattr->component;
609 size_t i;
610 enum counter_synapse_action action;
611 ssize_t len = 0;
612
613 for (i = 0; i < component->num_actions; i++) {
614 action = component->actions_list[i];
615 len += sprintf(buf + len, "%s\n",
616 counter_synapse_action_str[action]);
617 }
618
619 return len;
620}
621
622static int counter_synapses_register(
623 struct counter_device_attr_group *const group,
624 const struct counter_device *const counter,
625 struct counter_count *const count, const char *const count_attr_name)
626{
627 size_t i;
628 struct counter_synapse *synapse;
629 const char *prefix;
630 struct counter_action_unit *action_comp;
631 struct counter_attr_parm parm;
632 int err;
633 struct counter_action_avail_unit *avail_comp;
634
635 /* Register each Synapse */
636 for (i = 0; i < count->num_synapses; i++) {
637 synapse = count->synapses + i;
638
639 /* Generate attribute prefix */
640 prefix = kasprintf(GFP_KERNEL, "signal%d_",
641 synapse->signal->id);
642 if (!prefix) {
643 err = -ENOMEM;
644 goto err_free_attr_list;
645 }
646
647 /* Allocate action attribute component */
648 action_comp = kmalloc(sizeof(*action_comp), GFP_KERNEL);
649 if (!action_comp) {
650 err = -ENOMEM;
651 goto err_free_prefix;
652 }
653 action_comp->synapse = synapse;
654 action_comp->count = count;
655
656 /* Create action attribute */
657 parm.group = group;
658 parm.prefix = prefix;
659 parm.name = "action";
660 parm.show = (counter->ops->action_get) ? counter_action_show : NULL;
661 parm.store = (counter->ops->action_set) ? counter_action_store : NULL;
662 parm.component = action_comp;
663 err = counter_attribute_create(&parm);
664 if (err) {
665 kfree(action_comp);
666 goto err_free_prefix;
667 }
668
669 /* Allocate action available attribute component */
670 avail_comp = kmalloc(sizeof(*avail_comp), GFP_KERNEL);
671 if (!avail_comp) {
672 err = -ENOMEM;
673 goto err_free_prefix;
674 }
675 avail_comp->actions_list = synapse->actions_list;
676 avail_comp->num_actions = synapse->num_actions;
677
678 /* Create action_available attribute */
679 parm.group = group;
680 parm.prefix = prefix;
681 parm.name = "action_available";
682 parm.show = counter_synapse_action_available_show;
683 parm.store = NULL;
684 parm.component = avail_comp;
685 err = counter_attribute_create(&parm);
686 if (err) {
687 kfree(avail_comp);
688 goto err_free_prefix;
689 }
690
691 kfree(prefix);
692 }
693
694 return 0;
695
696err_free_prefix:
697 kfree(prefix);
698err_free_attr_list:
699 counter_device_attr_list_free(&group->attr_list);
700 return err;
701}
702
703struct counter_count_unit {
704 struct counter_count *count;
705};
706
707static ssize_t counter_count_show(struct device *dev,
708 struct device_attribute *attr,
709 char *buf)
710{
711 struct counter_device *const counter = dev_get_drvdata(dev);
712 const struct counter_device_attr *const devattr = to_counter_attr(attr);
713 const struct counter_count_unit *const component = devattr->component;
714 struct counter_count *const count = component->count;
715 int err;
d49e6ee2 716 unsigned long val;
0040a390
WBG
717
718 err = counter->ops->count_read(counter, count, &val);
719 if (err)
720 return err;
721
d49e6ee2 722 return sprintf(buf, "%lu\n", val);
0040a390
WBG
723}
724
725static ssize_t counter_count_store(struct device *dev,
726 struct device_attribute *attr,
727 const char *buf, size_t len)
728{
729 struct counter_device *const counter = dev_get_drvdata(dev);
730 const struct counter_device_attr *const devattr = to_counter_attr(attr);
731 const struct counter_count_unit *const component = devattr->component;
732 struct counter_count *const count = component->count;
733 int err;
d49e6ee2
WBG
734 unsigned long val;
735
736 err = kstrtoul(buf, 0, &val);
737 if (err)
738 return err;
0040a390 739
d49e6ee2 740 err = counter->ops->count_write(counter, count, val);
0040a390
WBG
741 if (err)
742 return err;
743
744 return len;
745}
746
747static const char *const counter_count_function_str[] = {
748 [COUNTER_COUNT_FUNCTION_INCREASE] = "increase",
749 [COUNTER_COUNT_FUNCTION_DECREASE] = "decrease",
750 [COUNTER_COUNT_FUNCTION_PULSE_DIRECTION] = "pulse-direction",
751 [COUNTER_COUNT_FUNCTION_QUADRATURE_X1_A] = "quadrature x1 a",
752 [COUNTER_COUNT_FUNCTION_QUADRATURE_X1_B] = "quadrature x1 b",
753 [COUNTER_COUNT_FUNCTION_QUADRATURE_X2_A] = "quadrature x2 a",
754 [COUNTER_COUNT_FUNCTION_QUADRATURE_X2_B] = "quadrature x2 b",
755 [COUNTER_COUNT_FUNCTION_QUADRATURE_X4] = "quadrature x4"
756};
757
758static ssize_t counter_function_show(struct device *dev,
759 struct device_attribute *attr, char *buf)
760{
761 int err;
762 struct counter_device *const counter = dev_get_drvdata(dev);
763 const struct counter_device_attr *const devattr = to_counter_attr(attr);
764 const struct counter_count_unit *const component = devattr->component;
765 struct counter_count *const count = component->count;
766 size_t func_index;
767 enum counter_count_function function;
768
769 err = counter->ops->function_get(counter, count, &func_index);
770 if (err)
771 return err;
772
773 count->function = func_index;
774
775 function = count->functions_list[func_index];
776 return sprintf(buf, "%s\n", counter_count_function_str[function]);
777}
778
779static ssize_t counter_function_store(struct device *dev,
780 struct device_attribute *attr,
781 const char *buf, size_t len)
782{
783 const struct counter_device_attr *const devattr = to_counter_attr(attr);
784 const struct counter_count_unit *const component = devattr->component;
785 struct counter_count *const count = component->count;
786 const size_t num_functions = count->num_functions;
787 size_t func_index;
788 enum counter_count_function function;
789 int err;
790 struct counter_device *const counter = dev_get_drvdata(dev);
791
792 /* Find requested Count function mode */
793 for (func_index = 0; func_index < num_functions; func_index++) {
794 function = count->functions_list[func_index];
795 if (sysfs_streq(buf, counter_count_function_str[function]))
796 break;
797 }
798 /* Return error if requested Count function mode not found */
799 if (func_index >= num_functions)
800 return -EINVAL;
801
802 err = counter->ops->function_set(counter, count, func_index);
803 if (err)
804 return err;
805
806 count->function = func_index;
807
808 return len;
809}
810
811struct counter_count_ext_unit {
812 struct counter_count *count;
813 const struct counter_count_ext *ext;
814};
815
816static ssize_t counter_count_ext_show(struct device *dev,
817 struct device_attribute *attr, char *buf)
818{
819 const struct counter_device_attr *const devattr = to_counter_attr(attr);
820 const struct counter_count_ext_unit *const comp = devattr->component;
821 const struct counter_count_ext *const ext = comp->ext;
822
823 return ext->read(dev_get_drvdata(dev), comp->count, ext->priv, buf);
824}
825
826static ssize_t counter_count_ext_store(struct device *dev,
827 struct device_attribute *attr,
828 const char *buf, size_t len)
829{
830 const struct counter_device_attr *const devattr = to_counter_attr(attr);
831 const struct counter_count_ext_unit *const comp = devattr->component;
832 const struct counter_count_ext *const ext = comp->ext;
833
834 return ext->write(dev_get_drvdata(dev), comp->count, ext->priv, buf,
835 len);
836}
837
838static int counter_count_ext_register(
839 struct counter_device_attr_group *const group,
840 struct counter_count *const count)
841{
842 size_t i;
843 const struct counter_count_ext *ext;
844 struct counter_count_ext_unit *count_ext_comp;
845 struct counter_attr_parm parm;
846 int err;
847
848 /* Create an attribute for each extension */
849 for (i = 0 ; i < count->num_ext; i++) {
850 ext = count->ext + i;
851
852 /* Allocate count_ext attribute component */
853 count_ext_comp = kmalloc(sizeof(*count_ext_comp), GFP_KERNEL);
854 if (!count_ext_comp) {
855 err = -ENOMEM;
856 goto err_free_attr_list;
857 }
858 count_ext_comp->count = count;
859 count_ext_comp->ext = ext;
860
861 /* Allocate count_ext attribute */
862 parm.group = group;
863 parm.prefix = "";
864 parm.name = ext->name;
865 parm.show = (ext->read) ? counter_count_ext_show : NULL;
866 parm.store = (ext->write) ? counter_count_ext_store : NULL;
867 parm.component = count_ext_comp;
868 err = counter_attribute_create(&parm);
869 if (err) {
870 kfree(count_ext_comp);
871 goto err_free_attr_list;
872 }
873 }
874
875 return 0;
876
877err_free_attr_list:
878 counter_device_attr_list_free(&group->attr_list);
879 return err;
880}
881
882struct counter_func_avail_unit {
883 const enum counter_count_function *functions_list;
884 size_t num_functions;
885};
886
887static ssize_t counter_count_function_available_show(struct device *dev,
888 struct device_attribute *attr, char *buf)
889{
890 const struct counter_device_attr *const devattr = to_counter_attr(attr);
891 const struct counter_func_avail_unit *const component = devattr->component;
892 const enum counter_count_function *const func_list = component->functions_list;
893 const size_t num_functions = component->num_functions;
894 size_t i;
895 enum counter_count_function function;
896 ssize_t len = 0;
897
898 for (i = 0; i < num_functions; i++) {
899 function = func_list[i];
900 len += sprintf(buf + len, "%s\n",
901 counter_count_function_str[function]);
902 }
903
904 return len;
905}
906
907static int counter_count_attributes_create(
908 struct counter_device_attr_group *const group,
909 const struct counter_device *const counter,
910 struct counter_count *const count)
911{
912 struct counter_count_unit *count_comp;
913 struct counter_attr_parm parm;
914 int err;
915 struct counter_count_unit *func_comp;
916 struct counter_func_avail_unit *avail_comp;
917
918 /* Allocate count attribute component */
919 count_comp = kmalloc(sizeof(*count_comp), GFP_KERNEL);
920 if (!count_comp)
921 return -ENOMEM;
922 count_comp->count = count;
923
924 /* Create main Count attribute */
925 parm.group = group;
926 parm.prefix = "";
927 parm.name = "count";
928 parm.show = (counter->ops->count_read) ? counter_count_show : NULL;
929 parm.store = (counter->ops->count_write) ? counter_count_store : NULL;
930 parm.component = count_comp;
931 err = counter_attribute_create(&parm);
932 if (err) {
933 kfree(count_comp);
934 return err;
935 }
936
937 /* Allocate function attribute component */
938 func_comp = kmalloc(sizeof(*func_comp), GFP_KERNEL);
939 if (!func_comp) {
940 err = -ENOMEM;
941 goto err_free_attr_list;
942 }
943 func_comp->count = count;
944
945 /* Create Count function attribute */
946 parm.group = group;
947 parm.prefix = "";
948 parm.name = "function";
949 parm.show = (counter->ops->function_get) ? counter_function_show : NULL;
950 parm.store = (counter->ops->function_set) ? counter_function_store : NULL;
951 parm.component = func_comp;
952 err = counter_attribute_create(&parm);
953 if (err) {
954 kfree(func_comp);
955 goto err_free_attr_list;
956 }
957
958 /* Allocate function available attribute component */
959 avail_comp = kmalloc(sizeof(*avail_comp), GFP_KERNEL);
960 if (!avail_comp) {
961 err = -ENOMEM;
962 goto err_free_attr_list;
963 }
964 avail_comp->functions_list = count->functions_list;
965 avail_comp->num_functions = count->num_functions;
966
967 /* Create Count function_available attribute */
968 parm.group = group;
969 parm.prefix = "";
970 parm.name = "function_available";
971 parm.show = counter_count_function_available_show;
972 parm.store = NULL;
973 parm.component = avail_comp;
974 err = counter_attribute_create(&parm);
975 if (err) {
976 kfree(avail_comp);
977 goto err_free_attr_list;
978 }
979
980 /* Create Count name attribute */
981 err = counter_name_attribute_create(group, count->name);
982 if (err)
983 goto err_free_attr_list;
984
985 /* Register Count extension attributes */
986 err = counter_count_ext_register(group, count);
987 if (err)
988 goto err_free_attr_list;
989
990 return 0;
991
992err_free_attr_list:
993 counter_device_attr_list_free(&group->attr_list);
994 return err;
995}
996
997static int counter_counts_register(
998 struct counter_device_attr_group *const groups_list,
999 const struct counter_device *const counter)
1000{
1001 size_t i;
1002 struct counter_count *count;
1003 const char *name;
1004 int err;
1005
1006 /* Register each Count */
1007 for (i = 0; i < counter->num_counts; i++) {
1008 count = counter->counts + i;
1009
1010 /* Generate Count attribute directory name */
1011 name = kasprintf(GFP_KERNEL, "count%d", count->id);
1012 if (!name) {
1013 err = -ENOMEM;
1014 goto err_free_attr_groups;
1015 }
1016 groups_list[i].attr_group.name = name;
1017
1018 /* Register the Synapses associated with each Count */
1019 err = counter_synapses_register(groups_list + i, counter, count,
1020 name);
1021 if (err)
1022 goto err_free_attr_groups;
1023
1024 /* Create all attributes associated with Count */
1025 err = counter_count_attributes_create(groups_list + i, counter,
1026 count);
1027 if (err)
1028 goto err_free_attr_groups;
1029 }
1030
1031 return 0;
1032
1033err_free_attr_groups:
1034 do {
1035 kfree(groups_list[i].attr_group.name);
1036 counter_device_attr_list_free(&groups_list[i].attr_list);
1037 } while (i--);
1038 return err;
1039}
1040
1041struct counter_size_unit {
1042 size_t size;
1043};
1044
1045static ssize_t counter_device_attr_size_show(struct device *dev,
1046 struct device_attribute *attr,
1047 char *buf)
1048{
1049 const struct counter_size_unit *const comp = to_counter_attr(attr)->component;
1050
1051 return sprintf(buf, "%zu\n", comp->size);
1052}
1053
1054static int counter_size_attribute_create(
1055 struct counter_device_attr_group *const group,
1056 const size_t size, const char *const name)
1057{
1058 struct counter_size_unit *size_comp;
1059 struct counter_attr_parm parm;
1060 int err;
1061
1062 /* Allocate size attribute component */
1063 size_comp = kmalloc(sizeof(*size_comp), GFP_KERNEL);
1064 if (!size_comp)
1065 return -ENOMEM;
1066 size_comp->size = size;
1067
1068 parm.group = group;
1069 parm.prefix = "";
1070 parm.name = name;
1071 parm.show = counter_device_attr_size_show;
1072 parm.store = NULL;
1073 parm.component = size_comp;
1074 err = counter_attribute_create(&parm);
1075 if (err)
1076 goto err_free_size_comp;
1077
1078 return 0;
1079
1080err_free_size_comp:
1081 kfree(size_comp);
1082 return err;
1083}
1084
1085struct counter_ext_unit {
1086 const struct counter_device_ext *ext;
1087};
1088
1089static ssize_t counter_device_ext_show(struct device *dev,
1090 struct device_attribute *attr, char *buf)
1091{
1092 const struct counter_device_attr *const devattr = to_counter_attr(attr);
1093 const struct counter_ext_unit *const component = devattr->component;
1094 const struct counter_device_ext *const ext = component->ext;
1095
1096 return ext->read(dev_get_drvdata(dev), ext->priv, buf);
1097}
1098
1099static ssize_t counter_device_ext_store(struct device *dev,
1100 struct device_attribute *attr,
1101 const char *buf, size_t len)
1102{
1103 const struct counter_device_attr *const devattr = to_counter_attr(attr);
1104 const struct counter_ext_unit *const component = devattr->component;
1105 const struct counter_device_ext *const ext = component->ext;
1106
1107 return ext->write(dev_get_drvdata(dev), ext->priv, buf, len);
1108}
1109
1110static int counter_device_ext_register(
1111 struct counter_device_attr_group *const group,
1112 struct counter_device *const counter)
1113{
1114 size_t i;
1115 struct counter_ext_unit *ext_comp;
1116 struct counter_attr_parm parm;
1117 int err;
1118
1119 /* Create an attribute for each extension */
1120 for (i = 0 ; i < counter->num_ext; i++) {
1121 /* Allocate extension attribute component */
1122 ext_comp = kmalloc(sizeof(*ext_comp), GFP_KERNEL);
1123 if (!ext_comp) {
1124 err = -ENOMEM;
1125 goto err_free_attr_list;
1126 }
1127
1128 ext_comp->ext = counter->ext + i;
1129
1130 /* Allocate extension attribute */
1131 parm.group = group;
1132 parm.prefix = "";
1133 parm.name = counter->ext[i].name;
1134 parm.show = (counter->ext[i].read) ? counter_device_ext_show : NULL;
1135 parm.store = (counter->ext[i].write) ? counter_device_ext_store : NULL;
1136 parm.component = ext_comp;
1137 err = counter_attribute_create(&parm);
1138 if (err) {
1139 kfree(ext_comp);
1140 goto err_free_attr_list;
1141 }
1142 }
1143
1144 return 0;
1145
1146err_free_attr_list:
1147 counter_device_attr_list_free(&group->attr_list);
1148 return err;
1149}
1150
1151static int counter_global_attr_register(
1152 struct counter_device_attr_group *const group,
1153 struct counter_device *const counter)
1154{
1155 int err;
1156
1157 /* Create name attribute */
1158 err = counter_name_attribute_create(group, counter->name);
1159 if (err)
1160 return err;
1161
1162 /* Create num_counts attribute */
1163 err = counter_size_attribute_create(group, counter->num_counts,
1164 "num_counts");
1165 if (err)
1166 goto err_free_attr_list;
1167
1168 /* Create num_signals attribute */
1169 err = counter_size_attribute_create(group, counter->num_signals,
1170 "num_signals");
1171 if (err)
1172 goto err_free_attr_list;
1173
1174 /* Register Counter device extension attributes */
1175 err = counter_device_ext_register(group, counter);
1176 if (err)
1177 goto err_free_attr_list;
1178
1179 return 0;
1180
1181err_free_attr_list:
1182 counter_device_attr_list_free(&group->attr_list);
1183 return err;
1184}
1185
1186static void counter_device_groups_list_free(
1187 struct counter_device_attr_group *const groups_list,
1188 const size_t num_groups)
1189{
1190 struct counter_device_attr_group *group;
1191 size_t i;
1192
1193 /* loop through all attribute groups (signals, counts, global, etc.) */
1194 for (i = 0; i < num_groups; i++) {
1195 group = groups_list + i;
1196
1197 /* free all attribute group and associated attributes memory */
1198 kfree(group->attr_group.name);
1199 kfree(group->attr_group.attrs);
1200 counter_device_attr_list_free(&group->attr_list);
1201 }
1202
1203 kfree(groups_list);
1204}
1205
1206static int counter_device_groups_list_prepare(
1207 struct counter_device *const counter)
1208{
1209 const size_t total_num_groups =
1210 counter->num_signals + counter->num_counts + 1;
1211 struct counter_device_attr_group *groups_list;
1212 size_t i;
1213 int err;
1214 size_t num_groups = 0;
1215
1216 /* Allocate space for attribute groups (signals, counts, and ext) */
1217 groups_list = kcalloc(total_num_groups, sizeof(*groups_list),
1218 GFP_KERNEL);
1219 if (!groups_list)
1220 return -ENOMEM;
1221
1222 /* Initialize attribute lists */
1223 for (i = 0; i < total_num_groups; i++)
1224 INIT_LIST_HEAD(&groups_list[i].attr_list);
1225
1226 /* Register Signals */
1227 err = counter_signals_register(groups_list, counter);
1228 if (err)
1229 goto err_free_groups_list;
1230 num_groups += counter->num_signals;
1231
1232 /* Register Counts and respective Synapses */
1233 err = counter_counts_register(groups_list + num_groups, counter);
1234 if (err)
1235 goto err_free_groups_list;
1236 num_groups += counter->num_counts;
1237
1238 /* Register Counter global attributes */
1239 err = counter_global_attr_register(groups_list + num_groups, counter);
1240 if (err)
1241 goto err_free_groups_list;
1242 num_groups++;
1243
1244 /* Store groups_list in device_state */
1245 counter->device_state->groups_list = groups_list;
1246 counter->device_state->num_groups = num_groups;
1247
1248 return 0;
1249
1250err_free_groups_list:
1251 counter_device_groups_list_free(groups_list, num_groups);
1252 return err;
1253}
1254
1255static int counter_device_groups_prepare(
1256 struct counter_device_state *const device_state)
1257{
1258 size_t i, j;
1259 struct counter_device_attr_group *group;
1260 int err;
1261 struct counter_device_attr *p;
1262
1263 /* Allocate attribute groups for association with device */
1264 device_state->groups = kcalloc(device_state->num_groups + 1,
1265 sizeof(*device_state->groups),
1266 GFP_KERNEL);
1267 if (!device_state->groups)
1268 return -ENOMEM;
1269
1270 /* Prepare each group of attributes for association */
1271 for (i = 0; i < device_state->num_groups; i++) {
1272 group = device_state->groups_list + i;
1273
1274 /* Allocate space for attribute pointers in attribute group */
1275 group->attr_group.attrs = kcalloc(group->num_attr + 1,
1276 sizeof(*group->attr_group.attrs), GFP_KERNEL);
1277 if (!group->attr_group.attrs) {
1278 err = -ENOMEM;
1279 goto err_free_groups;
1280 }
1281
1282 /* Add attribute pointers to attribute group */
1283 j = 0;
1284 list_for_each_entry(p, &group->attr_list, l)
1285 group->attr_group.attrs[j++] = &p->dev_attr.attr;
1286
1287 /* Group attributes in attribute group */
1288 device_state->groups[i] = &group->attr_group;
1289 }
1290 /* Associate attributes with device */
1291 device_state->dev.groups = device_state->groups;
1292
1293 return 0;
1294
1295err_free_groups:
1296 do {
1297 group = device_state->groups_list + i;
1298 kfree(group->attr_group.attrs);
1299 group->attr_group.attrs = NULL;
1300 } while (i--);
1301 kfree(device_state->groups);
1302 return err;
1303}
1304
1305/* Provides a unique ID for each counter device */
1306static DEFINE_IDA(counter_ida);
1307
1308static void counter_device_release(struct device *dev)
1309{
1310 struct counter_device *const counter = dev_get_drvdata(dev);
1311 struct counter_device_state *const device_state = counter->device_state;
1312
1313 kfree(device_state->groups);
1314 counter_device_groups_list_free(device_state->groups_list,
1315 device_state->num_groups);
1316 ida_simple_remove(&counter_ida, device_state->id);
1317 kfree(device_state);
1318}
1319
1320static struct device_type counter_device_type = {
1321 .name = "counter_device",
1322 .release = counter_device_release
1323};
1324
1325static struct bus_type counter_bus_type = {
1326 .name = "counter"
1327};
1328
1329/**
1330 * counter_register - register Counter to the system
1331 * @counter: pointer to Counter to register
1332 *
1333 * This function registers a Counter to the system. A sysfs "counter" directory
1334 * will be created and populated with sysfs attributes correlating with the
1335 * Counter Signals, Synapses, and Counts respectively.
1336 */
1337int counter_register(struct counter_device *const counter)
1338{
1339 struct counter_device_state *device_state;
1340 int err;
1341
1342 /* Allocate internal state container for Counter device */
1343 device_state = kzalloc(sizeof(*device_state), GFP_KERNEL);
1344 if (!device_state)
1345 return -ENOMEM;
1346 counter->device_state = device_state;
1347
1348 /* Acquire unique ID */
1349 device_state->id = ida_simple_get(&counter_ida, 0, 0, GFP_KERNEL);
1350 if (device_state->id < 0) {
1351 err = device_state->id;
1352 goto err_free_device_state;
1353 }
1354
1355 /* Configure device structure for Counter */
1356 device_state->dev.type = &counter_device_type;
1357 device_state->dev.bus = &counter_bus_type;
1358 if (counter->parent) {
1359 device_state->dev.parent = counter->parent;
1360 device_state->dev.of_node = counter->parent->of_node;
1361 }
1362 dev_set_name(&device_state->dev, "counter%d", device_state->id);
1363 device_initialize(&device_state->dev);
1364 dev_set_drvdata(&device_state->dev, counter);
1365
1366 /* Prepare device attributes */
1367 err = counter_device_groups_list_prepare(counter);
1368 if (err)
1369 goto err_free_id;
1370
1371 /* Organize device attributes to groups and match to device */
1372 err = counter_device_groups_prepare(device_state);
1373 if (err)
1374 goto err_free_groups_list;
1375
1376 /* Add device to system */
1377 err = device_add(&device_state->dev);
1378 if (err)
1379 goto err_free_groups;
1380
1381 return 0;
1382
1383err_free_groups:
1384 kfree(device_state->groups);
1385err_free_groups_list:
1386 counter_device_groups_list_free(device_state->groups_list,
1387 device_state->num_groups);
1388err_free_id:
1389 ida_simple_remove(&counter_ida, device_state->id);
1390err_free_device_state:
1391 kfree(device_state);
1392 return err;
1393}
1394EXPORT_SYMBOL_GPL(counter_register);
1395
1396/**
1397 * counter_unregister - unregister Counter from the system
1398 * @counter: pointer to Counter to unregister
1399 *
1400 * The Counter is unregistered from the system; all allocated memory is freed.
1401 */
1402void counter_unregister(struct counter_device *const counter)
1403{
1404 if (counter)
1405 device_del(&counter->device_state->dev);
1406}
1407EXPORT_SYMBOL_GPL(counter_unregister);
1408
1409static void devm_counter_unreg(struct device *dev, void *res)
1410{
1411 counter_unregister(*(struct counter_device **)res);
1412}
1413
1414/**
1415 * devm_counter_register - Resource-managed counter_register
1416 * @dev: device to allocate counter_device for
1417 * @counter: pointer to Counter to register
1418 *
1419 * Managed counter_register. The Counter registered with this function is
1420 * automatically unregistered on driver detach. This function calls
1421 * counter_register internally. Refer to that function for more information.
1422 *
1423 * If an Counter registered with this function needs to be unregistered
1424 * separately, devm_counter_unregister must be used.
1425 *
1426 * RETURNS:
1427 * 0 on success, negative error number on failure.
1428 */
1429int devm_counter_register(struct device *dev,
1430 struct counter_device *const counter)
1431{
1432 struct counter_device **ptr;
1433 int ret;
1434
1435 ptr = devres_alloc(devm_counter_unreg, sizeof(*ptr), GFP_KERNEL);
1436 if (!ptr)
1437 return -ENOMEM;
1438
1439 ret = counter_register(counter);
1440 if (!ret) {
1441 *ptr = counter;
1442 devres_add(dev, ptr);
1443 } else {
1444 devres_free(ptr);
1445 }
1446
1447 return ret;
1448}
1449EXPORT_SYMBOL_GPL(devm_counter_register);
1450
1451static int devm_counter_match(struct device *dev, void *res, void *data)
1452{
1453 struct counter_device **r = res;
1454
1455 if (!r || !*r) {
1456 WARN_ON(!r || !*r);
1457 return 0;
1458 }
1459
1460 return *r == data;
1461}
1462
1463/**
1464 * devm_counter_unregister - Resource-managed counter_unregister
1465 * @dev: device this counter_device belongs to
1466 * @counter: pointer to Counter associated with the device
1467 *
1468 * Unregister Counter registered with devm_counter_register.
1469 */
1470void devm_counter_unregister(struct device *dev,
1471 struct counter_device *const counter)
1472{
1473 int rc;
1474
1475 rc = devres_release(dev, devm_counter_unreg, devm_counter_match,
1476 counter);
1477 WARN_ON(rc);
1478}
1479EXPORT_SYMBOL_GPL(devm_counter_unregister);
1480
1481static int __init counter_init(void)
1482{
1483 return bus_register(&counter_bus_type);
1484}
1485
1486static void __exit counter_exit(void)
1487{
1488 bus_unregister(&counter_bus_type);
1489}
1490
1491subsys_initcall(counter_init);
1492module_exit(counter_exit);
1493
1494MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
1495MODULE_DESCRIPTION("Generic Counter interface");
1496MODULE_LICENSE("GPL v2");