1aaec1a0fSWilliam Breathitt Gray // SPDX-License-Identifier: GPL-2.0
2aaec1a0fSWilliam Breathitt Gray /*
3aaec1a0fSWilliam Breathitt Gray  * Generic Counter sysfs interface
4aaec1a0fSWilliam Breathitt Gray  * Copyright (C) 2020 William Breathitt Gray
5aaec1a0fSWilliam Breathitt Gray  */
6aaec1a0fSWilliam Breathitt Gray #include <linux/counter.h>
7aaec1a0fSWilliam Breathitt Gray #include <linux/device.h>
8aaec1a0fSWilliam Breathitt Gray #include <linux/err.h>
9aaec1a0fSWilliam Breathitt Gray #include <linux/gfp.h>
10aaec1a0fSWilliam Breathitt Gray #include <linux/kernel.h>
11feff17a5SWilliam Breathitt Gray #include <linux/kfifo.h>
12aaec1a0fSWilliam Breathitt Gray #include <linux/kstrtox.h>
13aaec1a0fSWilliam Breathitt Gray #include <linux/list.h>
148ac33b8bSWilliam Breathitt Gray #include <linux/mutex.h>
158ac33b8bSWilliam Breathitt Gray #include <linux/spinlock.h>
16aaec1a0fSWilliam Breathitt Gray #include <linux/string.h>
17aaec1a0fSWilliam Breathitt Gray #include <linux/sysfs.h>
18aaec1a0fSWilliam Breathitt Gray #include <linux/types.h>
19aaec1a0fSWilliam Breathitt Gray 
20aaec1a0fSWilliam Breathitt Gray #include "counter-sysfs.h"
21aaec1a0fSWilliam Breathitt Gray 
counter_from_dev(struct device * dev)2201b44ef2SUwe Kleine-König static inline struct counter_device *counter_from_dev(struct device *dev)
2301b44ef2SUwe Kleine-König {
2401b44ef2SUwe Kleine-König 	return container_of(dev, struct counter_device, dev);
2501b44ef2SUwe Kleine-König }
2601b44ef2SUwe Kleine-König 
27aaec1a0fSWilliam Breathitt Gray /**
28aaec1a0fSWilliam Breathitt Gray  * struct counter_attribute - Counter sysfs attribute
29aaec1a0fSWilliam Breathitt Gray  * @dev_attr:	device attribute for sysfs
30aaec1a0fSWilliam Breathitt Gray  * @l:		node to add Counter attribute to attribute group list
31aaec1a0fSWilliam Breathitt Gray  * @comp:	Counter component callbacks and data
32aaec1a0fSWilliam Breathitt Gray  * @scope:	Counter scope of the attribute
33aaec1a0fSWilliam Breathitt Gray  * @parent:	pointer to the parent component
34aaec1a0fSWilliam Breathitt Gray  */
35aaec1a0fSWilliam Breathitt Gray struct counter_attribute {
36aaec1a0fSWilliam Breathitt Gray 	struct device_attribute dev_attr;
37aaec1a0fSWilliam Breathitt Gray 	struct list_head l;
38aaec1a0fSWilliam Breathitt Gray 
39aaec1a0fSWilliam Breathitt Gray 	struct counter_comp comp;
40aaec1a0fSWilliam Breathitt Gray 	enum counter_scope scope;
41aaec1a0fSWilliam Breathitt Gray 	void *parent;
42aaec1a0fSWilliam Breathitt Gray };
43aaec1a0fSWilliam Breathitt Gray 
44aaec1a0fSWilliam Breathitt Gray #define to_counter_attribute(_dev_attr) \
45aaec1a0fSWilliam Breathitt Gray 	container_of(_dev_attr, struct counter_attribute, dev_attr)
46aaec1a0fSWilliam Breathitt Gray 
47aaec1a0fSWilliam Breathitt Gray /**
48aaec1a0fSWilliam Breathitt Gray  * struct counter_attribute_group - container for attribute group
49aaec1a0fSWilliam Breathitt Gray  * @name:	name of the attribute group
50aaec1a0fSWilliam Breathitt Gray  * @attr_list:	list to keep track of created attributes
51aaec1a0fSWilliam Breathitt Gray  * @num_attr:	number of attributes
52aaec1a0fSWilliam Breathitt Gray  */
53aaec1a0fSWilliam Breathitt Gray struct counter_attribute_group {
54aaec1a0fSWilliam Breathitt Gray 	const char *name;
55aaec1a0fSWilliam Breathitt Gray 	struct list_head attr_list;
56aaec1a0fSWilliam Breathitt Gray 	size_t num_attr;
57aaec1a0fSWilliam Breathitt Gray };
58aaec1a0fSWilliam Breathitt Gray 
59aaec1a0fSWilliam Breathitt Gray static const char *const counter_function_str[] = {
60aaec1a0fSWilliam Breathitt Gray 	[COUNTER_FUNCTION_INCREASE] = "increase",
61aaec1a0fSWilliam Breathitt Gray 	[COUNTER_FUNCTION_DECREASE] = "decrease",
62aaec1a0fSWilliam Breathitt Gray 	[COUNTER_FUNCTION_PULSE_DIRECTION] = "pulse-direction",
63aaec1a0fSWilliam Breathitt Gray 	[COUNTER_FUNCTION_QUADRATURE_X1_A] = "quadrature x1 a",
64aaec1a0fSWilliam Breathitt Gray 	[COUNTER_FUNCTION_QUADRATURE_X1_B] = "quadrature x1 b",
65aaec1a0fSWilliam Breathitt Gray 	[COUNTER_FUNCTION_QUADRATURE_X2_A] = "quadrature x2 a",
66aaec1a0fSWilliam Breathitt Gray 	[COUNTER_FUNCTION_QUADRATURE_X2_B] = "quadrature x2 b",
67aaec1a0fSWilliam Breathitt Gray 	[COUNTER_FUNCTION_QUADRATURE_X4] = "quadrature x4"
68aaec1a0fSWilliam Breathitt Gray };
69aaec1a0fSWilliam Breathitt Gray 
70aaec1a0fSWilliam Breathitt Gray static const char *const counter_signal_value_str[] = {
71aaec1a0fSWilliam Breathitt Gray 	[COUNTER_SIGNAL_LEVEL_LOW] = "low",
72aaec1a0fSWilliam Breathitt Gray 	[COUNTER_SIGNAL_LEVEL_HIGH] = "high"
73aaec1a0fSWilliam Breathitt Gray };
74aaec1a0fSWilliam Breathitt Gray 
75aaec1a0fSWilliam Breathitt Gray static const char *const counter_synapse_action_str[] = {
76aaec1a0fSWilliam Breathitt Gray 	[COUNTER_SYNAPSE_ACTION_NONE] = "none",
77aaec1a0fSWilliam Breathitt Gray 	[COUNTER_SYNAPSE_ACTION_RISING_EDGE] = "rising edge",
78aaec1a0fSWilliam Breathitt Gray 	[COUNTER_SYNAPSE_ACTION_FALLING_EDGE] = "falling edge",
79aaec1a0fSWilliam Breathitt Gray 	[COUNTER_SYNAPSE_ACTION_BOTH_EDGES] = "both edges"
80aaec1a0fSWilliam Breathitt Gray };
81aaec1a0fSWilliam Breathitt Gray 
82aaec1a0fSWilliam Breathitt Gray static const char *const counter_count_direction_str[] = {
83aaec1a0fSWilliam Breathitt Gray 	[COUNTER_COUNT_DIRECTION_FORWARD] = "forward",
84aaec1a0fSWilliam Breathitt Gray 	[COUNTER_COUNT_DIRECTION_BACKWARD] = "backward"
85aaec1a0fSWilliam Breathitt Gray };
86aaec1a0fSWilliam Breathitt Gray 
87aaec1a0fSWilliam Breathitt Gray static const char *const counter_count_mode_str[] = {
88aaec1a0fSWilliam Breathitt Gray 	[COUNTER_COUNT_MODE_NORMAL] = "normal",
89aaec1a0fSWilliam Breathitt Gray 	[COUNTER_COUNT_MODE_RANGE_LIMIT] = "range limit",
90aaec1a0fSWilliam Breathitt Gray 	[COUNTER_COUNT_MODE_NON_RECYCLE] = "non-recycle",
91*d4284874SWilliam Breathitt Gray 	[COUNTER_COUNT_MODE_MODULO_N] = "modulo-n",
92*d4284874SWilliam Breathitt Gray 	[COUNTER_COUNT_MODE_INTERRUPT_ON_TERMINAL_COUNT] = "interrupt on terminal count",
93*d4284874SWilliam Breathitt Gray 	[COUNTER_COUNT_MODE_HARDWARE_RETRIGGERABLE_ONESHOT] = "hardware retriggerable one-shot",
94*d4284874SWilliam Breathitt Gray 	[COUNTER_COUNT_MODE_RATE_GENERATOR] = "rate generator",
95*d4284874SWilliam Breathitt Gray 	[COUNTER_COUNT_MODE_SQUARE_WAVE_MODE] = "square wave mode",
96*d4284874SWilliam Breathitt Gray 	[COUNTER_COUNT_MODE_SOFTWARE_TRIGGERED_STROBE] = "software triggered strobe",
97*d4284874SWilliam Breathitt Gray 	[COUNTER_COUNT_MODE_HARDWARE_TRIGGERED_STROBE] = "hardware triggered strobe",
98aaec1a0fSWilliam Breathitt Gray };
99aaec1a0fSWilliam Breathitt Gray 
100650ae67bSWilliam Breathitt Gray static const char *const counter_signal_polarity_str[] = {
101650ae67bSWilliam Breathitt Gray 	[COUNTER_SIGNAL_POLARITY_POSITIVE] = "positive",
102650ae67bSWilliam Breathitt Gray 	[COUNTER_SIGNAL_POLARITY_NEGATIVE] = "negative"
103650ae67bSWilliam Breathitt Gray };
104650ae67bSWilliam Breathitt Gray 
counter_comp_u8_show(struct device * dev,struct device_attribute * attr,char * buf)105aaec1a0fSWilliam Breathitt Gray static ssize_t counter_comp_u8_show(struct device *dev,
106aaec1a0fSWilliam Breathitt Gray 				    struct device_attribute *attr, char *buf)
107aaec1a0fSWilliam Breathitt Gray {
108aaec1a0fSWilliam Breathitt Gray 	const struct counter_attribute *const a = to_counter_attribute(attr);
10901b44ef2SUwe Kleine-König 	struct counter_device *const counter = counter_from_dev(dev);
110aaec1a0fSWilliam Breathitt Gray 	int err;
111aaec1a0fSWilliam Breathitt Gray 	u8 data = 0;
112aaec1a0fSWilliam Breathitt Gray 
113aaec1a0fSWilliam Breathitt Gray 	switch (a->scope) {
114aaec1a0fSWilliam Breathitt Gray 	case COUNTER_SCOPE_DEVICE:
115aaec1a0fSWilliam Breathitt Gray 		err = a->comp.device_u8_read(counter, &data);
116aaec1a0fSWilliam Breathitt Gray 		break;
117aaec1a0fSWilliam Breathitt Gray 	case COUNTER_SCOPE_SIGNAL:
118aaec1a0fSWilliam Breathitt Gray 		err = a->comp.signal_u8_read(counter, a->parent, &data);
119aaec1a0fSWilliam Breathitt Gray 		break;
120aaec1a0fSWilliam Breathitt Gray 	case COUNTER_SCOPE_COUNT:
121aaec1a0fSWilliam Breathitt Gray 		err = a->comp.count_u8_read(counter, a->parent, &data);
122aaec1a0fSWilliam Breathitt Gray 		break;
123aaec1a0fSWilliam Breathitt Gray 	default:
124aaec1a0fSWilliam Breathitt Gray 		return -EINVAL;
125aaec1a0fSWilliam Breathitt Gray 	}
126aaec1a0fSWilliam Breathitt Gray 	if (err < 0)
127aaec1a0fSWilliam Breathitt Gray 		return err;
128aaec1a0fSWilliam Breathitt Gray 
129aaec1a0fSWilliam Breathitt Gray 	if (a->comp.type == COUNTER_COMP_BOOL)
130aaec1a0fSWilliam Breathitt Gray 		/* data should already be boolean but ensure just to be safe */
131aaec1a0fSWilliam Breathitt Gray 		data = !!data;
132aaec1a0fSWilliam Breathitt Gray 
133c3ed761cSDavid Lechner 	return sysfs_emit(buf, "%u\n", (unsigned int)data);
134aaec1a0fSWilliam Breathitt Gray }
135aaec1a0fSWilliam Breathitt Gray 
counter_comp_u8_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)136aaec1a0fSWilliam Breathitt Gray static ssize_t counter_comp_u8_store(struct device *dev,
137aaec1a0fSWilliam Breathitt Gray 				     struct device_attribute *attr,
138aaec1a0fSWilliam Breathitt Gray 				     const char *buf, size_t len)
139aaec1a0fSWilliam Breathitt Gray {
140aaec1a0fSWilliam Breathitt Gray 	const struct counter_attribute *const a = to_counter_attribute(attr);
14101b44ef2SUwe Kleine-König 	struct counter_device *const counter = counter_from_dev(dev);
142aaec1a0fSWilliam Breathitt Gray 	int err;
143aaec1a0fSWilliam Breathitt Gray 	bool bool_data = 0;
144aaec1a0fSWilliam Breathitt Gray 	u8 data = 0;
145aaec1a0fSWilliam Breathitt Gray 
146aaec1a0fSWilliam Breathitt Gray 	if (a->comp.type == COUNTER_COMP_BOOL) {
147aaec1a0fSWilliam Breathitt Gray 		err = kstrtobool(buf, &bool_data);
148aaec1a0fSWilliam Breathitt Gray 		data = bool_data;
149aaec1a0fSWilliam Breathitt Gray 	} else
150aaec1a0fSWilliam Breathitt Gray 		err = kstrtou8(buf, 0, &data);
151aaec1a0fSWilliam Breathitt Gray 	if (err < 0)
152aaec1a0fSWilliam Breathitt Gray 		return err;
153aaec1a0fSWilliam Breathitt Gray 
154aaec1a0fSWilliam Breathitt Gray 	switch (a->scope) {
155aaec1a0fSWilliam Breathitt Gray 	case COUNTER_SCOPE_DEVICE:
156aaec1a0fSWilliam Breathitt Gray 		err = a->comp.device_u8_write(counter, data);
157aaec1a0fSWilliam Breathitt Gray 		break;
158aaec1a0fSWilliam Breathitt Gray 	case COUNTER_SCOPE_SIGNAL:
159aaec1a0fSWilliam Breathitt Gray 		err = a->comp.signal_u8_write(counter, a->parent, data);
160aaec1a0fSWilliam Breathitt Gray 		break;
161aaec1a0fSWilliam Breathitt Gray 	case COUNTER_SCOPE_COUNT:
162aaec1a0fSWilliam Breathitt Gray 		err = a->comp.count_u8_write(counter, a->parent, data);
163aaec1a0fSWilliam Breathitt Gray 		break;
164aaec1a0fSWilliam Breathitt Gray 	default:
165aaec1a0fSWilliam Breathitt Gray 		return -EINVAL;
166aaec1a0fSWilliam Breathitt Gray 	}
167aaec1a0fSWilliam Breathitt Gray 	if (err < 0)
168aaec1a0fSWilliam Breathitt Gray 		return err;
169aaec1a0fSWilliam Breathitt Gray 
170aaec1a0fSWilliam Breathitt Gray 	return len;
171aaec1a0fSWilliam Breathitt Gray }
172aaec1a0fSWilliam Breathitt Gray 
counter_comp_u32_show(struct device * dev,struct device_attribute * attr,char * buf)173aaec1a0fSWilliam Breathitt Gray static ssize_t counter_comp_u32_show(struct device *dev,
174aaec1a0fSWilliam Breathitt Gray 				     struct device_attribute *attr, char *buf)
175aaec1a0fSWilliam Breathitt Gray {
176aaec1a0fSWilliam Breathitt Gray 	const struct counter_attribute *const a = to_counter_attribute(attr);
17701b44ef2SUwe Kleine-König 	struct counter_device *const counter = counter_from_dev(dev);
178aaec1a0fSWilliam Breathitt Gray 	const struct counter_available *const avail = a->comp.priv;
179aaec1a0fSWilliam Breathitt Gray 	int err;
180aaec1a0fSWilliam Breathitt Gray 	u32 data = 0;
181aaec1a0fSWilliam Breathitt Gray 
182aaec1a0fSWilliam Breathitt Gray 	switch (a->scope) {
183aaec1a0fSWilliam Breathitt Gray 	case COUNTER_SCOPE_DEVICE:
184aaec1a0fSWilliam Breathitt Gray 		err = a->comp.device_u32_read(counter, &data);
185aaec1a0fSWilliam Breathitt Gray 		break;
186aaec1a0fSWilliam Breathitt Gray 	case COUNTER_SCOPE_SIGNAL:
187aaec1a0fSWilliam Breathitt Gray 		err = a->comp.signal_u32_read(counter, a->parent, &data);
188aaec1a0fSWilliam Breathitt Gray 		break;
189aaec1a0fSWilliam Breathitt Gray 	case COUNTER_SCOPE_COUNT:
190aaec1a0fSWilliam Breathitt Gray 		if (a->comp.type == COUNTER_COMP_SYNAPSE_ACTION)
191aaec1a0fSWilliam Breathitt Gray 			err = a->comp.action_read(counter, a->parent,
192aaec1a0fSWilliam Breathitt Gray 						  a->comp.priv, &data);
193aaec1a0fSWilliam Breathitt Gray 		else
194aaec1a0fSWilliam Breathitt Gray 			err = a->comp.count_u32_read(counter, a->parent, &data);
195aaec1a0fSWilliam Breathitt Gray 		break;
196aaec1a0fSWilliam Breathitt Gray 	default:
197aaec1a0fSWilliam Breathitt Gray 		return -EINVAL;
198aaec1a0fSWilliam Breathitt Gray 	}
199aaec1a0fSWilliam Breathitt Gray 	if (err < 0)
200aaec1a0fSWilliam Breathitt Gray 		return err;
201aaec1a0fSWilliam Breathitt Gray 
202aaec1a0fSWilliam Breathitt Gray 	switch (a->comp.type) {
203aaec1a0fSWilliam Breathitt Gray 	case COUNTER_COMP_FUNCTION:
204aaec1a0fSWilliam Breathitt Gray 		return sysfs_emit(buf, "%s\n", counter_function_str[data]);
205aaec1a0fSWilliam Breathitt Gray 	case COUNTER_COMP_SIGNAL_LEVEL:
206aaec1a0fSWilliam Breathitt Gray 		return sysfs_emit(buf, "%s\n", counter_signal_value_str[data]);
207aaec1a0fSWilliam Breathitt Gray 	case COUNTER_COMP_SYNAPSE_ACTION:
208aaec1a0fSWilliam Breathitt Gray 		return sysfs_emit(buf, "%s\n", counter_synapse_action_str[data]);
209aaec1a0fSWilliam Breathitt Gray 	case COUNTER_COMP_ENUM:
210aaec1a0fSWilliam Breathitt Gray 		return sysfs_emit(buf, "%s\n", avail->strs[data]);
211aaec1a0fSWilliam Breathitt Gray 	case COUNTER_COMP_COUNT_DIRECTION:
212aaec1a0fSWilliam Breathitt Gray 		return sysfs_emit(buf, "%s\n", counter_count_direction_str[data]);
213aaec1a0fSWilliam Breathitt Gray 	case COUNTER_COMP_COUNT_MODE:
214aaec1a0fSWilliam Breathitt Gray 		return sysfs_emit(buf, "%s\n", counter_count_mode_str[data]);
215650ae67bSWilliam Breathitt Gray 	case COUNTER_COMP_SIGNAL_POLARITY:
216650ae67bSWilliam Breathitt Gray 		return sysfs_emit(buf, "%s\n", counter_signal_polarity_str[data]);
217aaec1a0fSWilliam Breathitt Gray 	default:
218c3ed761cSDavid Lechner 		return sysfs_emit(buf, "%u\n", (unsigned int)data);
219aaec1a0fSWilliam Breathitt Gray 	}
220aaec1a0fSWilliam Breathitt Gray }
221aaec1a0fSWilliam Breathitt Gray 
counter_find_enum(u32 * const enum_item,const u32 * const enums,const size_t num_enums,const char * const buf,const char * const string_array[])222aaec1a0fSWilliam Breathitt Gray static int counter_find_enum(u32 *const enum_item, const u32 *const enums,
223aaec1a0fSWilliam Breathitt Gray 			     const size_t num_enums, const char *const buf,
224aaec1a0fSWilliam Breathitt Gray 			     const char *const string_array[])
225aaec1a0fSWilliam Breathitt Gray {
226aaec1a0fSWilliam Breathitt Gray 	size_t index;
227aaec1a0fSWilliam Breathitt Gray 
228aaec1a0fSWilliam Breathitt Gray 	for (index = 0; index < num_enums; index++) {
229aaec1a0fSWilliam Breathitt Gray 		*enum_item = enums[index];
230aaec1a0fSWilliam Breathitt Gray 		if (sysfs_streq(buf, string_array[*enum_item]))
231aaec1a0fSWilliam Breathitt Gray 			return 0;
232aaec1a0fSWilliam Breathitt Gray 	}
233aaec1a0fSWilliam Breathitt Gray 
234aaec1a0fSWilliam Breathitt Gray 	return -EINVAL;
235aaec1a0fSWilliam Breathitt Gray }
236aaec1a0fSWilliam Breathitt Gray 
counter_comp_u32_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)237aaec1a0fSWilliam Breathitt Gray static ssize_t counter_comp_u32_store(struct device *dev,
238aaec1a0fSWilliam Breathitt Gray 				      struct device_attribute *attr,
239aaec1a0fSWilliam Breathitt Gray 				      const char *buf, size_t len)
240aaec1a0fSWilliam Breathitt Gray {
241aaec1a0fSWilliam Breathitt Gray 	const struct counter_attribute *const a = to_counter_attribute(attr);
24201b44ef2SUwe Kleine-König 	struct counter_device *const counter = counter_from_dev(dev);
243aaec1a0fSWilliam Breathitt Gray 	struct counter_count *const count = a->parent;
244aaec1a0fSWilliam Breathitt Gray 	struct counter_synapse *const synapse = a->comp.priv;
245aaec1a0fSWilliam Breathitt Gray 	const struct counter_available *const avail = a->comp.priv;
246aaec1a0fSWilliam Breathitt Gray 	int err;
247aaec1a0fSWilliam Breathitt Gray 	u32 data = 0;
248aaec1a0fSWilliam Breathitt Gray 
249aaec1a0fSWilliam Breathitt Gray 	switch (a->comp.type) {
250aaec1a0fSWilliam Breathitt Gray 	case COUNTER_COMP_FUNCTION:
251aaec1a0fSWilliam Breathitt Gray 		err = counter_find_enum(&data, count->functions_list,
252aaec1a0fSWilliam Breathitt Gray 					count->num_functions, buf,
253aaec1a0fSWilliam Breathitt Gray 					counter_function_str);
254aaec1a0fSWilliam Breathitt Gray 		break;
255aaec1a0fSWilliam Breathitt Gray 	case COUNTER_COMP_SYNAPSE_ACTION:
256aaec1a0fSWilliam Breathitt Gray 		err = counter_find_enum(&data, synapse->actions_list,
257aaec1a0fSWilliam Breathitt Gray 					synapse->num_actions, buf,
258aaec1a0fSWilliam Breathitt Gray 					counter_synapse_action_str);
259aaec1a0fSWilliam Breathitt Gray 		break;
260aaec1a0fSWilliam Breathitt Gray 	case COUNTER_COMP_ENUM:
261aaec1a0fSWilliam Breathitt Gray 		err = __sysfs_match_string(avail->strs, avail->num_items, buf);
262aaec1a0fSWilliam Breathitt Gray 		data = err;
263aaec1a0fSWilliam Breathitt Gray 		break;
264aaec1a0fSWilliam Breathitt Gray 	case COUNTER_COMP_COUNT_MODE:
265aaec1a0fSWilliam Breathitt Gray 		err = counter_find_enum(&data, avail->enums, avail->num_items,
266aaec1a0fSWilliam Breathitt Gray 					buf, counter_count_mode_str);
267aaec1a0fSWilliam Breathitt Gray 		break;
268650ae67bSWilliam Breathitt Gray 	case COUNTER_COMP_SIGNAL_POLARITY:
269650ae67bSWilliam Breathitt Gray 		err = counter_find_enum(&data, avail->enums, avail->num_items,
270650ae67bSWilliam Breathitt Gray 					buf, counter_signal_polarity_str);
271650ae67bSWilliam Breathitt Gray 		break;
272aaec1a0fSWilliam Breathitt Gray 	default:
273aaec1a0fSWilliam Breathitt Gray 		err = kstrtou32(buf, 0, &data);
274aaec1a0fSWilliam Breathitt Gray 		break;
275aaec1a0fSWilliam Breathitt Gray 	}
276aaec1a0fSWilliam Breathitt Gray 	if (err < 0)
277aaec1a0fSWilliam Breathitt Gray 		return err;
278aaec1a0fSWilliam Breathitt Gray 
279aaec1a0fSWilliam Breathitt Gray 	switch (a->scope) {
280aaec1a0fSWilliam Breathitt Gray 	case COUNTER_SCOPE_DEVICE:
281aaec1a0fSWilliam Breathitt Gray 		err = a->comp.device_u32_write(counter, data);
282aaec1a0fSWilliam Breathitt Gray 		break;
283aaec1a0fSWilliam Breathitt Gray 	case COUNTER_SCOPE_SIGNAL:
284aaec1a0fSWilliam Breathitt Gray 		err = a->comp.signal_u32_write(counter, a->parent, data);
285aaec1a0fSWilliam Breathitt Gray 		break;
286aaec1a0fSWilliam Breathitt Gray 	case COUNTER_SCOPE_COUNT:
287aaec1a0fSWilliam Breathitt Gray 		if (a->comp.type == COUNTER_COMP_SYNAPSE_ACTION)
288aaec1a0fSWilliam Breathitt Gray 			err = a->comp.action_write(counter, count, synapse,
289aaec1a0fSWilliam Breathitt Gray 						   data);
290aaec1a0fSWilliam Breathitt Gray 		else
291aaec1a0fSWilliam Breathitt Gray 			err = a->comp.count_u32_write(counter, count, data);
292aaec1a0fSWilliam Breathitt Gray 		break;
293aaec1a0fSWilliam Breathitt Gray 	default:
294aaec1a0fSWilliam Breathitt Gray 		return -EINVAL;
295aaec1a0fSWilliam Breathitt Gray 	}
296aaec1a0fSWilliam Breathitt Gray 	if (err < 0)
297aaec1a0fSWilliam Breathitt Gray 		return err;
298aaec1a0fSWilliam Breathitt Gray 
299aaec1a0fSWilliam Breathitt Gray 	return len;
300aaec1a0fSWilliam Breathitt Gray }
301aaec1a0fSWilliam Breathitt Gray 
counter_comp_u64_show(struct device * dev,struct device_attribute * attr,char * buf)302aaec1a0fSWilliam Breathitt Gray static ssize_t counter_comp_u64_show(struct device *dev,
303aaec1a0fSWilliam Breathitt Gray 				     struct device_attribute *attr, char *buf)
304aaec1a0fSWilliam Breathitt Gray {
305aaec1a0fSWilliam Breathitt Gray 	const struct counter_attribute *const a = to_counter_attribute(attr);
30601b44ef2SUwe Kleine-König 	struct counter_device *const counter = counter_from_dev(dev);
307aaec1a0fSWilliam Breathitt Gray 	int err;
308aaec1a0fSWilliam Breathitt Gray 	u64 data = 0;
309aaec1a0fSWilliam Breathitt Gray 
310aaec1a0fSWilliam Breathitt Gray 	switch (a->scope) {
311aaec1a0fSWilliam Breathitt Gray 	case COUNTER_SCOPE_DEVICE:
312aaec1a0fSWilliam Breathitt Gray 		err = a->comp.device_u64_read(counter, &data);
313aaec1a0fSWilliam Breathitt Gray 		break;
314aaec1a0fSWilliam Breathitt Gray 	case COUNTER_SCOPE_SIGNAL:
315aaec1a0fSWilliam Breathitt Gray 		err = a->comp.signal_u64_read(counter, a->parent, &data);
316aaec1a0fSWilliam Breathitt Gray 		break;
317aaec1a0fSWilliam Breathitt Gray 	case COUNTER_SCOPE_COUNT:
318aaec1a0fSWilliam Breathitt Gray 		err = a->comp.count_u64_read(counter, a->parent, &data);
319aaec1a0fSWilliam Breathitt Gray 		break;
320aaec1a0fSWilliam Breathitt Gray 	default:
321aaec1a0fSWilliam Breathitt Gray 		return -EINVAL;
322aaec1a0fSWilliam Breathitt Gray 	}
323aaec1a0fSWilliam Breathitt Gray 	if (err < 0)
324aaec1a0fSWilliam Breathitt Gray 		return err;
325aaec1a0fSWilliam Breathitt Gray 
326c3ed761cSDavid Lechner 	return sysfs_emit(buf, "%llu\n", (unsigned long long)data);
327aaec1a0fSWilliam Breathitt Gray }
328aaec1a0fSWilliam Breathitt Gray 
counter_comp_u64_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)329aaec1a0fSWilliam Breathitt Gray static ssize_t counter_comp_u64_store(struct device *dev,
330aaec1a0fSWilliam Breathitt Gray 				      struct device_attribute *attr,
331aaec1a0fSWilliam Breathitt Gray 				      const char *buf, size_t len)
332aaec1a0fSWilliam Breathitt Gray {
333aaec1a0fSWilliam Breathitt Gray 	const struct counter_attribute *const a = to_counter_attribute(attr);
33401b44ef2SUwe Kleine-König 	struct counter_device *const counter = counter_from_dev(dev);
335aaec1a0fSWilliam Breathitt Gray 	int err;
336aaec1a0fSWilliam Breathitt Gray 	u64 data = 0;
337aaec1a0fSWilliam Breathitt Gray 
338aaec1a0fSWilliam Breathitt Gray 	err = kstrtou64(buf, 0, &data);
339aaec1a0fSWilliam Breathitt Gray 	if (err < 0)
340aaec1a0fSWilliam Breathitt Gray 		return err;
341aaec1a0fSWilliam Breathitt Gray 
342aaec1a0fSWilliam Breathitt Gray 	switch (a->scope) {
343aaec1a0fSWilliam Breathitt Gray 	case COUNTER_SCOPE_DEVICE:
344aaec1a0fSWilliam Breathitt Gray 		err = a->comp.device_u64_write(counter, data);
345aaec1a0fSWilliam Breathitt Gray 		break;
346aaec1a0fSWilliam Breathitt Gray 	case COUNTER_SCOPE_SIGNAL:
347aaec1a0fSWilliam Breathitt Gray 		err = a->comp.signal_u64_write(counter, a->parent, data);
348aaec1a0fSWilliam Breathitt Gray 		break;
349aaec1a0fSWilliam Breathitt Gray 	case COUNTER_SCOPE_COUNT:
350aaec1a0fSWilliam Breathitt Gray 		err = a->comp.count_u64_write(counter, a->parent, data);
351aaec1a0fSWilliam Breathitt Gray 		break;
352aaec1a0fSWilliam Breathitt Gray 	default:
353aaec1a0fSWilliam Breathitt Gray 		return -EINVAL;
354aaec1a0fSWilliam Breathitt Gray 	}
355aaec1a0fSWilliam Breathitt Gray 	if (err < 0)
356aaec1a0fSWilliam Breathitt Gray 		return err;
357aaec1a0fSWilliam Breathitt Gray 
358aaec1a0fSWilliam Breathitt Gray 	return len;
359aaec1a0fSWilliam Breathitt Gray }
360aaec1a0fSWilliam Breathitt Gray 
counter_comp_array_u32_show(struct device * dev,struct device_attribute * attr,char * buf)361d2011be1SWilliam Breathitt Gray static ssize_t counter_comp_array_u32_show(struct device *dev,
362d2011be1SWilliam Breathitt Gray 					   struct device_attribute *attr,
363d2011be1SWilliam Breathitt Gray 					   char *buf)
364d2011be1SWilliam Breathitt Gray {
365d2011be1SWilliam Breathitt Gray 	const struct counter_attribute *const a = to_counter_attribute(attr);
366d2011be1SWilliam Breathitt Gray 	struct counter_device *const counter = counter_from_dev(dev);
367d2011be1SWilliam Breathitt Gray 	const struct counter_array *const element = a->comp.priv;
368d2011be1SWilliam Breathitt Gray 	int err;
369d2011be1SWilliam Breathitt Gray 	u32 data = 0;
370d2011be1SWilliam Breathitt Gray 
371d2011be1SWilliam Breathitt Gray 	if (a->scope != COUNTER_SCOPE_SIGNAL ||
372d2011be1SWilliam Breathitt Gray 	    element->type != COUNTER_COMP_SIGNAL_POLARITY)
373d2011be1SWilliam Breathitt Gray 		return -EINVAL;
374d2011be1SWilliam Breathitt Gray 
375d2011be1SWilliam Breathitt Gray 	err = a->comp.signal_array_u32_read(counter, a->parent, element->idx,
376d2011be1SWilliam Breathitt Gray 					    &data);
377d2011be1SWilliam Breathitt Gray 	if (err < 0)
378d2011be1SWilliam Breathitt Gray 		return err;
379d2011be1SWilliam Breathitt Gray 
380d2011be1SWilliam Breathitt Gray 	return sysfs_emit(buf, "%s\n", counter_signal_polarity_str[data]);
381d2011be1SWilliam Breathitt Gray }
382d2011be1SWilliam Breathitt Gray 
counter_comp_array_u32_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)383d2011be1SWilliam Breathitt Gray static ssize_t counter_comp_array_u32_store(struct device *dev,
384d2011be1SWilliam Breathitt Gray 					    struct device_attribute *attr,
385d2011be1SWilliam Breathitt Gray 					    const char *buf, size_t len)
386d2011be1SWilliam Breathitt Gray {
387d2011be1SWilliam Breathitt Gray 	const struct counter_attribute *const a = to_counter_attribute(attr);
388d2011be1SWilliam Breathitt Gray 	struct counter_device *const counter = counter_from_dev(dev);
389d2011be1SWilliam Breathitt Gray 	const struct counter_array *const element = a->comp.priv;
390d2011be1SWilliam Breathitt Gray 	int err;
391d2011be1SWilliam Breathitt Gray 	u32 data = 0;
392d2011be1SWilliam Breathitt Gray 
393d2011be1SWilliam Breathitt Gray 	if (element->type != COUNTER_COMP_SIGNAL_POLARITY ||
394d2011be1SWilliam Breathitt Gray 	    a->scope != COUNTER_SCOPE_SIGNAL)
395d2011be1SWilliam Breathitt Gray 		return -EINVAL;
396d2011be1SWilliam Breathitt Gray 
397d2011be1SWilliam Breathitt Gray 	err = counter_find_enum(&data, element->avail->enums,
398d2011be1SWilliam Breathitt Gray 				element->avail->num_items, buf,
399d2011be1SWilliam Breathitt Gray 				counter_signal_polarity_str);
400d2011be1SWilliam Breathitt Gray 	if (err < 0)
401d2011be1SWilliam Breathitt Gray 		return err;
402d2011be1SWilliam Breathitt Gray 
403d2011be1SWilliam Breathitt Gray 	err = a->comp.signal_array_u32_write(counter, a->parent, element->idx,
404d2011be1SWilliam Breathitt Gray 					     data);
405d2011be1SWilliam Breathitt Gray 	if (err < 0)
406d2011be1SWilliam Breathitt Gray 		return err;
407d2011be1SWilliam Breathitt Gray 
408d2011be1SWilliam Breathitt Gray 	return len;
409d2011be1SWilliam Breathitt Gray }
410d2011be1SWilliam Breathitt Gray 
counter_comp_array_u64_show(struct device * dev,struct device_attribute * attr,char * buf)411d2011be1SWilliam Breathitt Gray static ssize_t counter_comp_array_u64_show(struct device *dev,
412d2011be1SWilliam Breathitt Gray 					   struct device_attribute *attr,
413d2011be1SWilliam Breathitt Gray 					   char *buf)
414d2011be1SWilliam Breathitt Gray {
415d2011be1SWilliam Breathitt Gray 	const struct counter_attribute *const a = to_counter_attribute(attr);
416d2011be1SWilliam Breathitt Gray 	struct counter_device *const counter = counter_from_dev(dev);
417d2011be1SWilliam Breathitt Gray 	const struct counter_array *const element = a->comp.priv;
418d2011be1SWilliam Breathitt Gray 	int err;
419d2011be1SWilliam Breathitt Gray 	u64 data = 0;
420d2011be1SWilliam Breathitt Gray 
421d2011be1SWilliam Breathitt Gray 	switch (a->scope) {
422d2011be1SWilliam Breathitt Gray 	case COUNTER_SCOPE_DEVICE:
423d2011be1SWilliam Breathitt Gray 		err = a->comp.device_array_u64_read(counter, element->idx,
424d2011be1SWilliam Breathitt Gray 						    &data);
425d2011be1SWilliam Breathitt Gray 		break;
426d2011be1SWilliam Breathitt Gray 	case COUNTER_SCOPE_SIGNAL:
427d2011be1SWilliam Breathitt Gray 		err = a->comp.signal_array_u64_read(counter, a->parent,
428d2011be1SWilliam Breathitt Gray 						    element->idx, &data);
429d2011be1SWilliam Breathitt Gray 		break;
430d2011be1SWilliam Breathitt Gray 	case COUNTER_SCOPE_COUNT:
431d2011be1SWilliam Breathitt Gray 		err = a->comp.count_array_u64_read(counter, a->parent,
432d2011be1SWilliam Breathitt Gray 						   element->idx, &data);
433d2011be1SWilliam Breathitt Gray 		break;
434d2011be1SWilliam Breathitt Gray 	default:
435d2011be1SWilliam Breathitt Gray 		return -EINVAL;
436d2011be1SWilliam Breathitt Gray 	}
437d2011be1SWilliam Breathitt Gray 	if (err < 0)
438d2011be1SWilliam Breathitt Gray 		return err;
439d2011be1SWilliam Breathitt Gray 
440d2011be1SWilliam Breathitt Gray 	return sysfs_emit(buf, "%llu\n", (unsigned long long)data);
441d2011be1SWilliam Breathitt Gray }
442d2011be1SWilliam Breathitt Gray 
counter_comp_array_u64_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)443d2011be1SWilliam Breathitt Gray static ssize_t counter_comp_array_u64_store(struct device *dev,
444d2011be1SWilliam Breathitt Gray 					    struct device_attribute *attr,
445d2011be1SWilliam Breathitt Gray 					    const char *buf, size_t len)
446d2011be1SWilliam Breathitt Gray {
447d2011be1SWilliam Breathitt Gray 	const struct counter_attribute *const a = to_counter_attribute(attr);
448d2011be1SWilliam Breathitt Gray 	struct counter_device *const counter = counter_from_dev(dev);
449d2011be1SWilliam Breathitt Gray 	const struct counter_array *const element = a->comp.priv;
450d2011be1SWilliam Breathitt Gray 	int err;
451d2011be1SWilliam Breathitt Gray 	u64 data = 0;
452d2011be1SWilliam Breathitt Gray 
453d2011be1SWilliam Breathitt Gray 	err = kstrtou64(buf, 0, &data);
454d2011be1SWilliam Breathitt Gray 	if (err < 0)
455d2011be1SWilliam Breathitt Gray 		return err;
456d2011be1SWilliam Breathitt Gray 
457d2011be1SWilliam Breathitt Gray 	switch (a->scope) {
458d2011be1SWilliam Breathitt Gray 	case COUNTER_SCOPE_DEVICE:
459d2011be1SWilliam Breathitt Gray 		err = a->comp.device_array_u64_write(counter, element->idx,
460d2011be1SWilliam Breathitt Gray 						     data);
461d2011be1SWilliam Breathitt Gray 		break;
462d2011be1SWilliam Breathitt Gray 	case COUNTER_SCOPE_SIGNAL:
463d2011be1SWilliam Breathitt Gray 		err = a->comp.signal_array_u64_write(counter, a->parent,
464d2011be1SWilliam Breathitt Gray 						     element->idx, data);
465d2011be1SWilliam Breathitt Gray 		break;
466d2011be1SWilliam Breathitt Gray 	case COUNTER_SCOPE_COUNT:
467d2011be1SWilliam Breathitt Gray 		err = a->comp.count_array_u64_write(counter, a->parent,
468d2011be1SWilliam Breathitt Gray 						    element->idx, data);
469d2011be1SWilliam Breathitt Gray 		break;
470d2011be1SWilliam Breathitt Gray 	default:
471d2011be1SWilliam Breathitt Gray 		return -EINVAL;
472d2011be1SWilliam Breathitt Gray 	}
473d2011be1SWilliam Breathitt Gray 	if (err < 0)
474d2011be1SWilliam Breathitt Gray 		return err;
475d2011be1SWilliam Breathitt Gray 
476d2011be1SWilliam Breathitt Gray 	return len;
477d2011be1SWilliam Breathitt Gray }
478d2011be1SWilliam Breathitt Gray 
enums_available_show(const u32 * const enums,const size_t num_enums,const char * const strs[],char * buf)479aaec1a0fSWilliam Breathitt Gray static ssize_t enums_available_show(const u32 *const enums,
480aaec1a0fSWilliam Breathitt Gray 				    const size_t num_enums,
481aaec1a0fSWilliam Breathitt Gray 				    const char *const strs[], char *buf)
482aaec1a0fSWilliam Breathitt Gray {
483aaec1a0fSWilliam Breathitt Gray 	size_t len = 0;
484aaec1a0fSWilliam Breathitt Gray 	size_t index;
485aaec1a0fSWilliam Breathitt Gray 
486aaec1a0fSWilliam Breathitt Gray 	for (index = 0; index < num_enums; index++)
487aaec1a0fSWilliam Breathitt Gray 		len += sysfs_emit_at(buf, len, "%s\n", strs[enums[index]]);
488aaec1a0fSWilliam Breathitt Gray 
489aaec1a0fSWilliam Breathitt Gray 	return len;
490aaec1a0fSWilliam Breathitt Gray }
491aaec1a0fSWilliam Breathitt Gray 
strs_available_show(const struct counter_available * const avail,char * buf)492aaec1a0fSWilliam Breathitt Gray static ssize_t strs_available_show(const struct counter_available *const avail,
493aaec1a0fSWilliam Breathitt Gray 				   char *buf)
494aaec1a0fSWilliam Breathitt Gray {
495aaec1a0fSWilliam Breathitt Gray 	size_t len = 0;
496aaec1a0fSWilliam Breathitt Gray 	size_t index;
497aaec1a0fSWilliam Breathitt Gray 
498aaec1a0fSWilliam Breathitt Gray 	for (index = 0; index < avail->num_items; index++)
499aaec1a0fSWilliam Breathitt Gray 		len += sysfs_emit_at(buf, len, "%s\n", avail->strs[index]);
500aaec1a0fSWilliam Breathitt Gray 
501aaec1a0fSWilliam Breathitt Gray 	return len;
502aaec1a0fSWilliam Breathitt Gray }
503aaec1a0fSWilliam Breathitt Gray 
counter_comp_available_show(struct device * dev,struct device_attribute * attr,char * buf)504aaec1a0fSWilliam Breathitt Gray static ssize_t counter_comp_available_show(struct device *dev,
505aaec1a0fSWilliam Breathitt Gray 					   struct device_attribute *attr,
506aaec1a0fSWilliam Breathitt Gray 					   char *buf)
507aaec1a0fSWilliam Breathitt Gray {
508aaec1a0fSWilliam Breathitt Gray 	const struct counter_attribute *const a = to_counter_attribute(attr);
509aaec1a0fSWilliam Breathitt Gray 	const struct counter_count *const count = a->parent;
510aaec1a0fSWilliam Breathitt Gray 	const struct counter_synapse *const synapse = a->comp.priv;
511aaec1a0fSWilliam Breathitt Gray 	const struct counter_available *const avail = a->comp.priv;
512aaec1a0fSWilliam Breathitt Gray 
513aaec1a0fSWilliam Breathitt Gray 	switch (a->comp.type) {
514aaec1a0fSWilliam Breathitt Gray 	case COUNTER_COMP_FUNCTION:
515aaec1a0fSWilliam Breathitt Gray 		return enums_available_show(count->functions_list,
516aaec1a0fSWilliam Breathitt Gray 					    count->num_functions,
517aaec1a0fSWilliam Breathitt Gray 					    counter_function_str, buf);
518aaec1a0fSWilliam Breathitt Gray 	case COUNTER_COMP_SYNAPSE_ACTION:
519aaec1a0fSWilliam Breathitt Gray 		return enums_available_show(synapse->actions_list,
520aaec1a0fSWilliam Breathitt Gray 					    synapse->num_actions,
521aaec1a0fSWilliam Breathitt Gray 					    counter_synapse_action_str, buf);
522aaec1a0fSWilliam Breathitt Gray 	case COUNTER_COMP_ENUM:
523aaec1a0fSWilliam Breathitt Gray 		return strs_available_show(avail, buf);
524aaec1a0fSWilliam Breathitt Gray 	case COUNTER_COMP_COUNT_MODE:
525aaec1a0fSWilliam Breathitt Gray 		return enums_available_show(avail->enums, avail->num_items,
526aaec1a0fSWilliam Breathitt Gray 					    counter_count_mode_str, buf);
527aaec1a0fSWilliam Breathitt Gray 	default:
528aaec1a0fSWilliam Breathitt Gray 		return -EINVAL;
529aaec1a0fSWilliam Breathitt Gray 	}
530aaec1a0fSWilliam Breathitt Gray }
531aaec1a0fSWilliam Breathitt Gray 
counter_avail_attr_create(struct device * const dev,struct counter_attribute_group * const group,const struct counter_comp * const comp,void * const parent)532aaec1a0fSWilliam Breathitt Gray static int counter_avail_attr_create(struct device *const dev,
533aaec1a0fSWilliam Breathitt Gray 	struct counter_attribute_group *const group,
534aaec1a0fSWilliam Breathitt Gray 	const struct counter_comp *const comp, void *const parent)
535aaec1a0fSWilliam Breathitt Gray {
536aaec1a0fSWilliam Breathitt Gray 	struct counter_attribute *counter_attr;
537aaec1a0fSWilliam Breathitt Gray 	struct device_attribute *dev_attr;
538aaec1a0fSWilliam Breathitt Gray 
539aaec1a0fSWilliam Breathitt Gray 	counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL);
540aaec1a0fSWilliam Breathitt Gray 	if (!counter_attr)
541aaec1a0fSWilliam Breathitt Gray 		return -ENOMEM;
542aaec1a0fSWilliam Breathitt Gray 
543aaec1a0fSWilliam Breathitt Gray 	/* Configure Counter attribute */
544aaec1a0fSWilliam Breathitt Gray 	counter_attr->comp.type = comp->type;
545aaec1a0fSWilliam Breathitt Gray 	counter_attr->comp.priv = comp->priv;
546aaec1a0fSWilliam Breathitt Gray 	counter_attr->parent = parent;
547aaec1a0fSWilliam Breathitt Gray 
548aaec1a0fSWilliam Breathitt Gray 	/* Initialize sysfs attribute */
549aaec1a0fSWilliam Breathitt Gray 	dev_attr = &counter_attr->dev_attr;
550aaec1a0fSWilliam Breathitt Gray 	sysfs_attr_init(&dev_attr->attr);
551aaec1a0fSWilliam Breathitt Gray 
552aaec1a0fSWilliam Breathitt Gray 	/* Configure device attribute */
553aaec1a0fSWilliam Breathitt Gray 	dev_attr->attr.name = devm_kasprintf(dev, GFP_KERNEL, "%s_available",
554aaec1a0fSWilliam Breathitt Gray 					     comp->name);
555aaec1a0fSWilliam Breathitt Gray 	if (!dev_attr->attr.name)
556aaec1a0fSWilliam Breathitt Gray 		return -ENOMEM;
557aaec1a0fSWilliam Breathitt Gray 	dev_attr->attr.mode = 0444;
558aaec1a0fSWilliam Breathitt Gray 	dev_attr->show = counter_comp_available_show;
559aaec1a0fSWilliam Breathitt Gray 
560aaec1a0fSWilliam Breathitt Gray 	/* Store list node */
561aaec1a0fSWilliam Breathitt Gray 	list_add(&counter_attr->l, &group->attr_list);
562aaec1a0fSWilliam Breathitt Gray 	group->num_attr++;
563aaec1a0fSWilliam Breathitt Gray 
564aaec1a0fSWilliam Breathitt Gray 	return 0;
565aaec1a0fSWilliam Breathitt Gray }
566aaec1a0fSWilliam Breathitt Gray 
counter_attr_create(struct device * const dev,struct counter_attribute_group * const group,const struct counter_comp * const comp,const enum counter_scope scope,void * const parent)567aaec1a0fSWilliam Breathitt Gray static int counter_attr_create(struct device *const dev,
568aaec1a0fSWilliam Breathitt Gray 			       struct counter_attribute_group *const group,
569aaec1a0fSWilliam Breathitt Gray 			       const struct counter_comp *const comp,
570aaec1a0fSWilliam Breathitt Gray 			       const enum counter_scope scope,
571aaec1a0fSWilliam Breathitt Gray 			       void *const parent)
572aaec1a0fSWilliam Breathitt Gray {
573d2011be1SWilliam Breathitt Gray 	const struct counter_array *const array = comp->priv;
574aaec1a0fSWilliam Breathitt Gray 	struct counter_attribute *counter_attr;
575aaec1a0fSWilliam Breathitt Gray 	struct device_attribute *dev_attr;
576aaec1a0fSWilliam Breathitt Gray 
577aaec1a0fSWilliam Breathitt Gray 	counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL);
578aaec1a0fSWilliam Breathitt Gray 	if (!counter_attr)
579aaec1a0fSWilliam Breathitt Gray 		return -ENOMEM;
580aaec1a0fSWilliam Breathitt Gray 
581aaec1a0fSWilliam Breathitt Gray 	/* Configure Counter attribute */
582aaec1a0fSWilliam Breathitt Gray 	counter_attr->comp = *comp;
583aaec1a0fSWilliam Breathitt Gray 	counter_attr->scope = scope;
584aaec1a0fSWilliam Breathitt Gray 	counter_attr->parent = parent;
585aaec1a0fSWilliam Breathitt Gray 
586aaec1a0fSWilliam Breathitt Gray 	/* Configure device attribute */
587aaec1a0fSWilliam Breathitt Gray 	dev_attr = &counter_attr->dev_attr;
588aaec1a0fSWilliam Breathitt Gray 	sysfs_attr_init(&dev_attr->attr);
589aaec1a0fSWilliam Breathitt Gray 	dev_attr->attr.name = comp->name;
590aaec1a0fSWilliam Breathitt Gray 	switch (comp->type) {
591aaec1a0fSWilliam Breathitt Gray 	case COUNTER_COMP_U8:
592aaec1a0fSWilliam Breathitt Gray 	case COUNTER_COMP_BOOL:
593aaec1a0fSWilliam Breathitt Gray 		if (comp->device_u8_read) {
594aaec1a0fSWilliam Breathitt Gray 			dev_attr->attr.mode |= 0444;
595aaec1a0fSWilliam Breathitt Gray 			dev_attr->show = counter_comp_u8_show;
596aaec1a0fSWilliam Breathitt Gray 		}
597aaec1a0fSWilliam Breathitt Gray 		if (comp->device_u8_write) {
598aaec1a0fSWilliam Breathitt Gray 			dev_attr->attr.mode |= 0200;
599aaec1a0fSWilliam Breathitt Gray 			dev_attr->store = counter_comp_u8_store;
600aaec1a0fSWilliam Breathitt Gray 		}
601aaec1a0fSWilliam Breathitt Gray 		break;
602aaec1a0fSWilliam Breathitt Gray 	case COUNTER_COMP_SIGNAL_LEVEL:
603aaec1a0fSWilliam Breathitt Gray 	case COUNTER_COMP_FUNCTION:
604aaec1a0fSWilliam Breathitt Gray 	case COUNTER_COMP_SYNAPSE_ACTION:
605aaec1a0fSWilliam Breathitt Gray 	case COUNTER_COMP_ENUM:
606aaec1a0fSWilliam Breathitt Gray 	case COUNTER_COMP_COUNT_DIRECTION:
607aaec1a0fSWilliam Breathitt Gray 	case COUNTER_COMP_COUNT_MODE:
608650ae67bSWilliam Breathitt Gray 	case COUNTER_COMP_SIGNAL_POLARITY:
609aaec1a0fSWilliam Breathitt Gray 		if (comp->device_u32_read) {
610aaec1a0fSWilliam Breathitt Gray 			dev_attr->attr.mode |= 0444;
611aaec1a0fSWilliam Breathitt Gray 			dev_attr->show = counter_comp_u32_show;
612aaec1a0fSWilliam Breathitt Gray 		}
613aaec1a0fSWilliam Breathitt Gray 		if (comp->device_u32_write) {
614aaec1a0fSWilliam Breathitt Gray 			dev_attr->attr.mode |= 0200;
615aaec1a0fSWilliam Breathitt Gray 			dev_attr->store = counter_comp_u32_store;
616aaec1a0fSWilliam Breathitt Gray 		}
617aaec1a0fSWilliam Breathitt Gray 		break;
618aaec1a0fSWilliam Breathitt Gray 	case COUNTER_COMP_U64:
619aaec1a0fSWilliam Breathitt Gray 		if (comp->device_u64_read) {
620aaec1a0fSWilliam Breathitt Gray 			dev_attr->attr.mode |= 0444;
621aaec1a0fSWilliam Breathitt Gray 			dev_attr->show = counter_comp_u64_show;
622aaec1a0fSWilliam Breathitt Gray 		}
623aaec1a0fSWilliam Breathitt Gray 		if (comp->device_u64_write) {
624aaec1a0fSWilliam Breathitt Gray 			dev_attr->attr.mode |= 0200;
625aaec1a0fSWilliam Breathitt Gray 			dev_attr->store = counter_comp_u64_store;
626aaec1a0fSWilliam Breathitt Gray 		}
627aaec1a0fSWilliam Breathitt Gray 		break;
628d2011be1SWilliam Breathitt Gray 	case COUNTER_COMP_ARRAY:
629d2011be1SWilliam Breathitt Gray 		switch (array->type) {
630d2011be1SWilliam Breathitt Gray 		case COUNTER_COMP_SIGNAL_POLARITY:
631d2011be1SWilliam Breathitt Gray 			if (comp->signal_array_u32_read) {
632d2011be1SWilliam Breathitt Gray 				dev_attr->attr.mode |= 0444;
633d2011be1SWilliam Breathitt Gray 				dev_attr->show = counter_comp_array_u32_show;
634d2011be1SWilliam Breathitt Gray 			}
635d2011be1SWilliam Breathitt Gray 			if (comp->signal_array_u32_write) {
636d2011be1SWilliam Breathitt Gray 				dev_attr->attr.mode |= 0200;
637d2011be1SWilliam Breathitt Gray 				dev_attr->store = counter_comp_array_u32_store;
638d2011be1SWilliam Breathitt Gray 			}
639d2011be1SWilliam Breathitt Gray 			break;
640d2011be1SWilliam Breathitt Gray 		case COUNTER_COMP_U64:
641d2011be1SWilliam Breathitt Gray 			if (comp->device_array_u64_read) {
642d2011be1SWilliam Breathitt Gray 				dev_attr->attr.mode |= 0444;
643d2011be1SWilliam Breathitt Gray 				dev_attr->show = counter_comp_array_u64_show;
644d2011be1SWilliam Breathitt Gray 			}
645d2011be1SWilliam Breathitt Gray 			if (comp->device_array_u64_write) {
646d2011be1SWilliam Breathitt Gray 				dev_attr->attr.mode |= 0200;
647d2011be1SWilliam Breathitt Gray 				dev_attr->store = counter_comp_array_u64_store;
648d2011be1SWilliam Breathitt Gray 			}
649d2011be1SWilliam Breathitt Gray 			break;
650d2011be1SWilliam Breathitt Gray 		default:
651d2011be1SWilliam Breathitt Gray 			return -EINVAL;
652d2011be1SWilliam Breathitt Gray 		}
653d2011be1SWilliam Breathitt Gray 		break;
654aaec1a0fSWilliam Breathitt Gray 	default:
655aaec1a0fSWilliam Breathitt Gray 		return -EINVAL;
656aaec1a0fSWilliam Breathitt Gray 	}
657aaec1a0fSWilliam Breathitt Gray 
658aaec1a0fSWilliam Breathitt Gray 	/* Store list node */
659aaec1a0fSWilliam Breathitt Gray 	list_add(&counter_attr->l, &group->attr_list);
660aaec1a0fSWilliam Breathitt Gray 	group->num_attr++;
661aaec1a0fSWilliam Breathitt Gray 
662aaec1a0fSWilliam Breathitt Gray 	/* Create "*_available" attribute if needed */
663aaec1a0fSWilliam Breathitt Gray 	switch (comp->type) {
664aaec1a0fSWilliam Breathitt Gray 	case COUNTER_COMP_FUNCTION:
665aaec1a0fSWilliam Breathitt Gray 	case COUNTER_COMP_SYNAPSE_ACTION:
666aaec1a0fSWilliam Breathitt Gray 	case COUNTER_COMP_ENUM:
667aaec1a0fSWilliam Breathitt Gray 	case COUNTER_COMP_COUNT_MODE:
668aaec1a0fSWilliam Breathitt Gray 		return counter_avail_attr_create(dev, group, comp, parent);
669aaec1a0fSWilliam Breathitt Gray 	default:
670aaec1a0fSWilliam Breathitt Gray 		return 0;
671aaec1a0fSWilliam Breathitt Gray 	}
672aaec1a0fSWilliam Breathitt Gray }
673aaec1a0fSWilliam Breathitt Gray 
counter_comp_name_show(struct device * dev,struct device_attribute * attr,char * buf)674aaec1a0fSWilliam Breathitt Gray static ssize_t counter_comp_name_show(struct device *dev,
675aaec1a0fSWilliam Breathitt Gray 				      struct device_attribute *attr, char *buf)
676aaec1a0fSWilliam Breathitt Gray {
677aaec1a0fSWilliam Breathitt Gray 	return sysfs_emit(buf, "%s\n", to_counter_attribute(attr)->comp.name);
678aaec1a0fSWilliam Breathitt Gray }
679aaec1a0fSWilliam Breathitt Gray 
counter_name_attr_create(struct device * const dev,struct counter_attribute_group * const group,const char * const name)680aaec1a0fSWilliam Breathitt Gray static int counter_name_attr_create(struct device *const dev,
681aaec1a0fSWilliam Breathitt Gray 				    struct counter_attribute_group *const group,
682aaec1a0fSWilliam Breathitt Gray 				    const char *const name)
683aaec1a0fSWilliam Breathitt Gray {
684aaec1a0fSWilliam Breathitt Gray 	struct counter_attribute *counter_attr;
685aaec1a0fSWilliam Breathitt Gray 
686aaec1a0fSWilliam Breathitt Gray 	counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL);
687aaec1a0fSWilliam Breathitt Gray 	if (!counter_attr)
688aaec1a0fSWilliam Breathitt Gray 		return -ENOMEM;
689aaec1a0fSWilliam Breathitt Gray 
690aaec1a0fSWilliam Breathitt Gray 	/* Configure Counter attribute */
691aaec1a0fSWilliam Breathitt Gray 	counter_attr->comp.name = name;
692aaec1a0fSWilliam Breathitt Gray 
693aaec1a0fSWilliam Breathitt Gray 	/* Configure device attribute */
694aaec1a0fSWilliam Breathitt Gray 	sysfs_attr_init(&counter_attr->dev_attr.attr);
695aaec1a0fSWilliam Breathitt Gray 	counter_attr->dev_attr.attr.name = "name";
696aaec1a0fSWilliam Breathitt Gray 	counter_attr->dev_attr.attr.mode = 0444;
697aaec1a0fSWilliam Breathitt Gray 	counter_attr->dev_attr.show = counter_comp_name_show;
698aaec1a0fSWilliam Breathitt Gray 
699aaec1a0fSWilliam Breathitt Gray 	/* Store list node */
700aaec1a0fSWilliam Breathitt Gray 	list_add(&counter_attr->l, &group->attr_list);
701aaec1a0fSWilliam Breathitt Gray 	group->num_attr++;
702aaec1a0fSWilliam Breathitt Gray 
703aaec1a0fSWilliam Breathitt Gray 	return 0;
704aaec1a0fSWilliam Breathitt Gray }
705aaec1a0fSWilliam Breathitt Gray 
counter_comp_id_show(struct device * dev,struct device_attribute * attr,char * buf)706bb6264a6SWilliam Breathitt Gray static ssize_t counter_comp_id_show(struct device *dev,
707bb6264a6SWilliam Breathitt Gray 				    struct device_attribute *attr, char *buf)
708bb6264a6SWilliam Breathitt Gray {
709bb6264a6SWilliam Breathitt Gray 	const size_t id = (size_t)to_counter_attribute(attr)->comp.priv;
710bb6264a6SWilliam Breathitt Gray 
711c3ed761cSDavid Lechner 	return sysfs_emit(buf, "%zu\n", id);
712bb6264a6SWilliam Breathitt Gray }
713bb6264a6SWilliam Breathitt Gray 
counter_comp_id_attr_create(struct device * const dev,struct counter_attribute_group * const group,const char * name,const size_t id)714bb6264a6SWilliam Breathitt Gray static int counter_comp_id_attr_create(struct device *const dev,
715bb6264a6SWilliam Breathitt Gray 				       struct counter_attribute_group *const group,
716bb6264a6SWilliam Breathitt Gray 				       const char *name, const size_t id)
717bb6264a6SWilliam Breathitt Gray {
718bb6264a6SWilliam Breathitt Gray 	struct counter_attribute *counter_attr;
719bb6264a6SWilliam Breathitt Gray 
720bb6264a6SWilliam Breathitt Gray 	/* Allocate Counter attribute */
721bb6264a6SWilliam Breathitt Gray 	counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL);
722bb6264a6SWilliam Breathitt Gray 	if (!counter_attr)
723bb6264a6SWilliam Breathitt Gray 		return -ENOMEM;
724bb6264a6SWilliam Breathitt Gray 
725bb6264a6SWilliam Breathitt Gray 	/* Generate component ID name */
726bb6264a6SWilliam Breathitt Gray 	name = devm_kasprintf(dev, GFP_KERNEL, "%s_component_id", name);
727bb6264a6SWilliam Breathitt Gray 	if (!name)
728bb6264a6SWilliam Breathitt Gray 		return -ENOMEM;
729bb6264a6SWilliam Breathitt Gray 
730bb6264a6SWilliam Breathitt Gray 	/* Configure Counter attribute */
731bb6264a6SWilliam Breathitt Gray 	counter_attr->comp.priv = (void *)id;
732bb6264a6SWilliam Breathitt Gray 
733bb6264a6SWilliam Breathitt Gray 	/* Configure device attribute */
734bb6264a6SWilliam Breathitt Gray 	sysfs_attr_init(&counter_attr->dev_attr.attr);
735bb6264a6SWilliam Breathitt Gray 	counter_attr->dev_attr.attr.name = name;
736bb6264a6SWilliam Breathitt Gray 	counter_attr->dev_attr.attr.mode = 0444;
737bb6264a6SWilliam Breathitt Gray 	counter_attr->dev_attr.show = counter_comp_id_show;
738bb6264a6SWilliam Breathitt Gray 
739bb6264a6SWilliam Breathitt Gray 	/* Store list node */
740bb6264a6SWilliam Breathitt Gray 	list_add(&counter_attr->l, &group->attr_list);
741bb6264a6SWilliam Breathitt Gray 	group->num_attr++;
742bb6264a6SWilliam Breathitt Gray 
743bb6264a6SWilliam Breathitt Gray 	return 0;
744bb6264a6SWilliam Breathitt Gray }
745bb6264a6SWilliam Breathitt Gray 
counter_ext_attrs_create(struct device * const dev,struct counter_attribute_group * const group,const struct counter_comp * const ext,const enum counter_scope scope,void * const parent,const size_t id)746bb4bbbecSWilliam Breathitt Gray static int counter_ext_attrs_create(struct device *const dev,
747bb4bbbecSWilliam Breathitt Gray 				    struct counter_attribute_group *const group,
748bb4bbbecSWilliam Breathitt Gray 				    const struct counter_comp *const ext,
749bb4bbbecSWilliam Breathitt Gray 				    const enum counter_scope scope,
750bb4bbbecSWilliam Breathitt Gray 				    void *const parent, const size_t id)
751bb4bbbecSWilliam Breathitt Gray {
752bb4bbbecSWilliam Breathitt Gray 	int err;
753bb4bbbecSWilliam Breathitt Gray 
754bb4bbbecSWilliam Breathitt Gray 	/* Create main extension attribute */
755bb4bbbecSWilliam Breathitt Gray 	err = counter_attr_create(dev, group, ext, scope, parent);
756bb4bbbecSWilliam Breathitt Gray 	if (err < 0)
757bb4bbbecSWilliam Breathitt Gray 		return err;
758bb4bbbecSWilliam Breathitt Gray 
759bb4bbbecSWilliam Breathitt Gray 	/* Create extension id attribute */
760bb4bbbecSWilliam Breathitt Gray 	return counter_comp_id_attr_create(dev, group, ext->name, id);
761bb4bbbecSWilliam Breathitt Gray }
762bb4bbbecSWilliam Breathitt Gray 
counter_array_attrs_create(struct device * const dev,struct counter_attribute_group * const group,const struct counter_comp * const comp,const enum counter_scope scope,void * const parent,const size_t id)763d2011be1SWilliam Breathitt Gray static int counter_array_attrs_create(struct device *const dev,
764d2011be1SWilliam Breathitt Gray 				      struct counter_attribute_group *const group,
765d2011be1SWilliam Breathitt Gray 				      const struct counter_comp *const comp,
766d2011be1SWilliam Breathitt Gray 				      const enum counter_scope scope,
767d2011be1SWilliam Breathitt Gray 				      void *const parent, const size_t id)
768d2011be1SWilliam Breathitt Gray {
769d2011be1SWilliam Breathitt Gray 	const struct counter_array *const array = comp->priv;
770d2011be1SWilliam Breathitt Gray 	struct counter_comp ext = *comp;
771d2011be1SWilliam Breathitt Gray 	struct counter_array *element;
772d2011be1SWilliam Breathitt Gray 	size_t idx;
773d2011be1SWilliam Breathitt Gray 	int err;
774d2011be1SWilliam Breathitt Gray 
775d2011be1SWilliam Breathitt Gray 	/* Create an attribute for each array element */
776d2011be1SWilliam Breathitt Gray 	for (idx = 0; idx < array->length; idx++) {
777d2011be1SWilliam Breathitt Gray 		/* Generate array element attribute name */
778d2011be1SWilliam Breathitt Gray 		ext.name = devm_kasprintf(dev, GFP_KERNEL, "%s%zu", comp->name,
779d2011be1SWilliam Breathitt Gray 					  idx);
780d2011be1SWilliam Breathitt Gray 		if (!ext.name)
781d2011be1SWilliam Breathitt Gray 			return -ENOMEM;
782d2011be1SWilliam Breathitt Gray 
783d2011be1SWilliam Breathitt Gray 		/* Allocate and configure array element */
784d2011be1SWilliam Breathitt Gray 		element = devm_kzalloc(dev, sizeof(*element), GFP_KERNEL);
785d2011be1SWilliam Breathitt Gray 		if (!element)
786d2011be1SWilliam Breathitt Gray 			return -ENOMEM;
787d2011be1SWilliam Breathitt Gray 		element->type = array->type;
788d2011be1SWilliam Breathitt Gray 		element->avail = array->avail;
789d2011be1SWilliam Breathitt Gray 		element->idx = idx;
790d2011be1SWilliam Breathitt Gray 		ext.priv = element;
791d2011be1SWilliam Breathitt Gray 
792d2011be1SWilliam Breathitt Gray 		/* Create all attributes associated with the array element */
793d2011be1SWilliam Breathitt Gray 		err = counter_ext_attrs_create(dev, group, &ext, scope, parent,
794d2011be1SWilliam Breathitt Gray 					       id + idx);
795d2011be1SWilliam Breathitt Gray 		if (err < 0)
796d2011be1SWilliam Breathitt Gray 			return err;
797d2011be1SWilliam Breathitt Gray 	}
798d2011be1SWilliam Breathitt Gray 
799d2011be1SWilliam Breathitt Gray 	return 0;
800d2011be1SWilliam Breathitt Gray }
801d2011be1SWilliam Breathitt Gray 
counter_sysfs_exts_add(struct device * const dev,struct counter_attribute_group * const group,const struct counter_comp * const exts,const size_t num_ext,const enum counter_scope scope,void * const parent)802bb4bbbecSWilliam Breathitt Gray static int counter_sysfs_exts_add(struct device *const dev,
803bb4bbbecSWilliam Breathitt Gray 				  struct counter_attribute_group *const group,
804bb4bbbecSWilliam Breathitt Gray 				  const struct counter_comp *const exts,
805bb4bbbecSWilliam Breathitt Gray 				  const size_t num_ext,
806bb4bbbecSWilliam Breathitt Gray 				  const enum counter_scope scope,
807bb4bbbecSWilliam Breathitt Gray 				  void *const parent)
808bb4bbbecSWilliam Breathitt Gray {
809bb4bbbecSWilliam Breathitt Gray 	size_t i;
810bb4bbbecSWilliam Breathitt Gray 	const struct counter_comp *ext;
811bb4bbbecSWilliam Breathitt Gray 	int err;
812d2011be1SWilliam Breathitt Gray 	size_t id = 0;
813d2011be1SWilliam Breathitt Gray 	const struct counter_array *array;
814bb4bbbecSWilliam Breathitt Gray 
815bb4bbbecSWilliam Breathitt Gray 	/* Create attributes for each extension */
816bb4bbbecSWilliam Breathitt Gray 	for (i = 0; i < num_ext; i++) {
817bb4bbbecSWilliam Breathitt Gray 		ext = &exts[i];
818d2011be1SWilliam Breathitt Gray 		if (ext->type == COUNTER_COMP_ARRAY) {
819d2011be1SWilliam Breathitt Gray 			err = counter_array_attrs_create(dev, group, ext, scope,
820d2011be1SWilliam Breathitt Gray 							 parent, id);
821d2011be1SWilliam Breathitt Gray 			array = ext->priv;
822d2011be1SWilliam Breathitt Gray 			id += array->length;
823d2011be1SWilliam Breathitt Gray 		} else {
824d2011be1SWilliam Breathitt Gray 			err = counter_ext_attrs_create(dev, group, ext, scope,
825d2011be1SWilliam Breathitt Gray 						       parent, id);
826d2011be1SWilliam Breathitt Gray 			id++;
827d2011be1SWilliam Breathitt Gray 		}
828bb4bbbecSWilliam Breathitt Gray 		if (err < 0)
829bb4bbbecSWilliam Breathitt Gray 			return err;
830bb4bbbecSWilliam Breathitt Gray 	}
831bb4bbbecSWilliam Breathitt Gray 
832bb4bbbecSWilliam Breathitt Gray 	return 0;
833bb4bbbecSWilliam Breathitt Gray }
834bb4bbbecSWilliam Breathitt Gray 
835aaec1a0fSWilliam Breathitt Gray static struct counter_comp counter_signal_comp = {
836aaec1a0fSWilliam Breathitt Gray 	.type = COUNTER_COMP_SIGNAL_LEVEL,
837aaec1a0fSWilliam Breathitt Gray 	.name = "signal",
838aaec1a0fSWilliam Breathitt Gray };
839aaec1a0fSWilliam Breathitt Gray 
counter_signal_attrs_create(struct counter_device * const counter,struct counter_attribute_group * const cattr_group,struct counter_signal * const signal)840aaec1a0fSWilliam Breathitt Gray static int counter_signal_attrs_create(struct counter_device *const counter,
841aaec1a0fSWilliam Breathitt Gray 	struct counter_attribute_group *const cattr_group,
842aaec1a0fSWilliam Breathitt Gray 	struct counter_signal *const signal)
843aaec1a0fSWilliam Breathitt Gray {
844aaec1a0fSWilliam Breathitt Gray 	const enum counter_scope scope = COUNTER_SCOPE_SIGNAL;
845aaec1a0fSWilliam Breathitt Gray 	struct device *const dev = &counter->dev;
846aaec1a0fSWilliam Breathitt Gray 	int err;
847aaec1a0fSWilliam Breathitt Gray 	struct counter_comp comp;
848aaec1a0fSWilliam Breathitt Gray 
849aaec1a0fSWilliam Breathitt Gray 	/* Create main Signal attribute */
850aaec1a0fSWilliam Breathitt Gray 	comp = counter_signal_comp;
851aaec1a0fSWilliam Breathitt Gray 	comp.signal_u32_read = counter->ops->signal_read;
852aaec1a0fSWilliam Breathitt Gray 	err = counter_attr_create(dev, cattr_group, &comp, scope, signal);
853aaec1a0fSWilliam Breathitt Gray 	if (err < 0)
854aaec1a0fSWilliam Breathitt Gray 		return err;
855aaec1a0fSWilliam Breathitt Gray 
856aaec1a0fSWilliam Breathitt Gray 	/* Create Signal name attribute */
857aaec1a0fSWilliam Breathitt Gray 	err = counter_name_attr_create(dev, cattr_group, signal->name);
858aaec1a0fSWilliam Breathitt Gray 	if (err < 0)
859aaec1a0fSWilliam Breathitt Gray 		return err;
860aaec1a0fSWilliam Breathitt Gray 
861bb4bbbecSWilliam Breathitt Gray 	/* Add Signal extensions */
862bb4bbbecSWilliam Breathitt Gray 	return counter_sysfs_exts_add(dev, cattr_group, signal->ext,
863bb4bbbecSWilliam Breathitt Gray 				      signal->num_ext, scope, signal);
864aaec1a0fSWilliam Breathitt Gray }
865aaec1a0fSWilliam Breathitt Gray 
counter_sysfs_signals_add(struct counter_device * const counter,struct counter_attribute_group * const groups)866aaec1a0fSWilliam Breathitt Gray static int counter_sysfs_signals_add(struct counter_device *const counter,
867aaec1a0fSWilliam Breathitt Gray 	struct counter_attribute_group *const groups)
868aaec1a0fSWilliam Breathitt Gray {
869aaec1a0fSWilliam Breathitt Gray 	size_t i;
870aaec1a0fSWilliam Breathitt Gray 	int err;
871aaec1a0fSWilliam Breathitt Gray 
872aaec1a0fSWilliam Breathitt Gray 	/* Add each Signal */
873aaec1a0fSWilliam Breathitt Gray 	for (i = 0; i < counter->num_signals; i++) {
874aaec1a0fSWilliam Breathitt Gray 		/* Generate Signal attribute directory name */
875aaec1a0fSWilliam Breathitt Gray 		groups[i].name = devm_kasprintf(&counter->dev, GFP_KERNEL,
876aaec1a0fSWilliam Breathitt Gray 						"signal%zu", i);
877aaec1a0fSWilliam Breathitt Gray 		if (!groups[i].name)
878aaec1a0fSWilliam Breathitt Gray 			return -ENOMEM;
879aaec1a0fSWilliam Breathitt Gray 
880aaec1a0fSWilliam Breathitt Gray 		/* Create all attributes associated with Signal */
881aaec1a0fSWilliam Breathitt Gray 		err = counter_signal_attrs_create(counter, groups + i,
882aaec1a0fSWilliam Breathitt Gray 						  counter->signals + i);
883aaec1a0fSWilliam Breathitt Gray 		if (err < 0)
884aaec1a0fSWilliam Breathitt Gray 			return err;
885aaec1a0fSWilliam Breathitt Gray 	}
886aaec1a0fSWilliam Breathitt Gray 
887aaec1a0fSWilliam Breathitt Gray 	return 0;
888aaec1a0fSWilliam Breathitt Gray }
889aaec1a0fSWilliam Breathitt Gray 
counter_sysfs_synapses_add(struct counter_device * const counter,struct counter_attribute_group * const group,struct counter_count * const count)890aaec1a0fSWilliam Breathitt Gray static int counter_sysfs_synapses_add(struct counter_device *const counter,
891aaec1a0fSWilliam Breathitt Gray 	struct counter_attribute_group *const group,
892aaec1a0fSWilliam Breathitt Gray 	struct counter_count *const count)
893aaec1a0fSWilliam Breathitt Gray {
894aaec1a0fSWilliam Breathitt Gray 	size_t i;
895aaec1a0fSWilliam Breathitt Gray 
896aaec1a0fSWilliam Breathitt Gray 	/* Add each Synapse */
897aaec1a0fSWilliam Breathitt Gray 	for (i = 0; i < count->num_synapses; i++) {
898aaec1a0fSWilliam Breathitt Gray 		struct device *const dev = &counter->dev;
899aaec1a0fSWilliam Breathitt Gray 		struct counter_synapse *synapse;
900aaec1a0fSWilliam Breathitt Gray 		size_t id;
901aaec1a0fSWilliam Breathitt Gray 		struct counter_comp comp;
902aaec1a0fSWilliam Breathitt Gray 		int err;
903aaec1a0fSWilliam Breathitt Gray 
904aaec1a0fSWilliam Breathitt Gray 		synapse = count->synapses + i;
905aaec1a0fSWilliam Breathitt Gray 
906aaec1a0fSWilliam Breathitt Gray 		/* Generate Synapse action name */
907aaec1a0fSWilliam Breathitt Gray 		id = synapse->signal - counter->signals;
908aaec1a0fSWilliam Breathitt Gray 		comp.name = devm_kasprintf(dev, GFP_KERNEL, "signal%zu_action",
909aaec1a0fSWilliam Breathitt Gray 					   id);
910aaec1a0fSWilliam Breathitt Gray 		if (!comp.name)
911aaec1a0fSWilliam Breathitt Gray 			return -ENOMEM;
912aaec1a0fSWilliam Breathitt Gray 
913aaec1a0fSWilliam Breathitt Gray 		/* Create action attribute */
914aaec1a0fSWilliam Breathitt Gray 		comp.type = COUNTER_COMP_SYNAPSE_ACTION;
915aaec1a0fSWilliam Breathitt Gray 		comp.action_read = counter->ops->action_read;
916aaec1a0fSWilliam Breathitt Gray 		comp.action_write = counter->ops->action_write;
917aaec1a0fSWilliam Breathitt Gray 		comp.priv = synapse;
918aaec1a0fSWilliam Breathitt Gray 		err = counter_attr_create(dev, group, &comp,
919aaec1a0fSWilliam Breathitt Gray 					  COUNTER_SCOPE_COUNT, count);
920aaec1a0fSWilliam Breathitt Gray 		if (err < 0)
921aaec1a0fSWilliam Breathitt Gray 			return err;
922bb6264a6SWilliam Breathitt Gray 
923bb6264a6SWilliam Breathitt Gray 		/* Create Synapse component ID attribute */
924bb6264a6SWilliam Breathitt Gray 		err = counter_comp_id_attr_create(dev, group, comp.name, i);
925bb6264a6SWilliam Breathitt Gray 		if (err < 0)
926bb6264a6SWilliam Breathitt Gray 			return err;
927aaec1a0fSWilliam Breathitt Gray 	}
928aaec1a0fSWilliam Breathitt Gray 
929aaec1a0fSWilliam Breathitt Gray 	return 0;
930aaec1a0fSWilliam Breathitt Gray }
931aaec1a0fSWilliam Breathitt Gray 
932aaec1a0fSWilliam Breathitt Gray static struct counter_comp counter_count_comp =
933aaec1a0fSWilliam Breathitt Gray 	COUNTER_COMP_COUNT_U64("count", NULL, NULL);
934aaec1a0fSWilliam Breathitt Gray 
935aaec1a0fSWilliam Breathitt Gray static struct counter_comp counter_function_comp = {
936aaec1a0fSWilliam Breathitt Gray 	.type = COUNTER_COMP_FUNCTION,
937aaec1a0fSWilliam Breathitt Gray 	.name = "function",
938aaec1a0fSWilliam Breathitt Gray };
939aaec1a0fSWilliam Breathitt Gray 
counter_count_attrs_create(struct counter_device * const counter,struct counter_attribute_group * const cattr_group,struct counter_count * const count)940aaec1a0fSWilliam Breathitt Gray static int counter_count_attrs_create(struct counter_device *const counter,
941aaec1a0fSWilliam Breathitt Gray 	struct counter_attribute_group *const cattr_group,
942aaec1a0fSWilliam Breathitt Gray 	struct counter_count *const count)
943aaec1a0fSWilliam Breathitt Gray {
944aaec1a0fSWilliam Breathitt Gray 	const enum counter_scope scope = COUNTER_SCOPE_COUNT;
945aaec1a0fSWilliam Breathitt Gray 	struct device *const dev = &counter->dev;
946aaec1a0fSWilliam Breathitt Gray 	int err;
947aaec1a0fSWilliam Breathitt Gray 	struct counter_comp comp;
948aaec1a0fSWilliam Breathitt Gray 
949aaec1a0fSWilliam Breathitt Gray 	/* Create main Count attribute */
950aaec1a0fSWilliam Breathitt Gray 	comp = counter_count_comp;
951aaec1a0fSWilliam Breathitt Gray 	comp.count_u64_read = counter->ops->count_read;
952aaec1a0fSWilliam Breathitt Gray 	comp.count_u64_write = counter->ops->count_write;
953aaec1a0fSWilliam Breathitt Gray 	err = counter_attr_create(dev, cattr_group, &comp, scope, count);
954aaec1a0fSWilliam Breathitt Gray 	if (err < 0)
955aaec1a0fSWilliam Breathitt Gray 		return err;
956aaec1a0fSWilliam Breathitt Gray 
957aaec1a0fSWilliam Breathitt Gray 	/* Create Count name attribute */
958aaec1a0fSWilliam Breathitt Gray 	err = counter_name_attr_create(dev, cattr_group, count->name);
959aaec1a0fSWilliam Breathitt Gray 	if (err < 0)
960aaec1a0fSWilliam Breathitt Gray 		return err;
961aaec1a0fSWilliam Breathitt Gray 
962aaec1a0fSWilliam Breathitt Gray 	/* Create Count function attribute */
963aaec1a0fSWilliam Breathitt Gray 	comp = counter_function_comp;
964aaec1a0fSWilliam Breathitt Gray 	comp.count_u32_read = counter->ops->function_read;
965aaec1a0fSWilliam Breathitt Gray 	comp.count_u32_write = counter->ops->function_write;
966aaec1a0fSWilliam Breathitt Gray 	err = counter_attr_create(dev, cattr_group, &comp, scope, count);
967aaec1a0fSWilliam Breathitt Gray 	if (err < 0)
968aaec1a0fSWilliam Breathitt Gray 		return err;
969aaec1a0fSWilliam Breathitt Gray 
970bb4bbbecSWilliam Breathitt Gray 	/* Add Count extensions */
971bb4bbbecSWilliam Breathitt Gray 	return counter_sysfs_exts_add(dev, cattr_group, count->ext,
972bb4bbbecSWilliam Breathitt Gray 				      count->num_ext, scope, count);
973aaec1a0fSWilliam Breathitt Gray }
974aaec1a0fSWilliam Breathitt Gray 
counter_sysfs_counts_add(struct counter_device * const counter,struct counter_attribute_group * const groups)975aaec1a0fSWilliam Breathitt Gray static int counter_sysfs_counts_add(struct counter_device *const counter,
976aaec1a0fSWilliam Breathitt Gray 	struct counter_attribute_group *const groups)
977aaec1a0fSWilliam Breathitt Gray {
978aaec1a0fSWilliam Breathitt Gray 	size_t i;
979aaec1a0fSWilliam Breathitt Gray 	struct counter_count *count;
980aaec1a0fSWilliam Breathitt Gray 	int err;
981aaec1a0fSWilliam Breathitt Gray 
982aaec1a0fSWilliam Breathitt Gray 	/* Add each Count */
983aaec1a0fSWilliam Breathitt Gray 	for (i = 0; i < counter->num_counts; i++) {
984aaec1a0fSWilliam Breathitt Gray 		count = counter->counts + i;
985aaec1a0fSWilliam Breathitt Gray 
986aaec1a0fSWilliam Breathitt Gray 		/* Generate Count attribute directory name */
987aaec1a0fSWilliam Breathitt Gray 		groups[i].name = devm_kasprintf(&counter->dev, GFP_KERNEL,
988aaec1a0fSWilliam Breathitt Gray 						"count%zu", i);
989aaec1a0fSWilliam Breathitt Gray 		if (!groups[i].name)
990aaec1a0fSWilliam Breathitt Gray 			return -ENOMEM;
991aaec1a0fSWilliam Breathitt Gray 
992aaec1a0fSWilliam Breathitt Gray 		/* Add sysfs attributes of the Synapses */
993aaec1a0fSWilliam Breathitt Gray 		err = counter_sysfs_synapses_add(counter, groups + i, count);
994aaec1a0fSWilliam Breathitt Gray 		if (err < 0)
995aaec1a0fSWilliam Breathitt Gray 			return err;
996aaec1a0fSWilliam Breathitt Gray 
997aaec1a0fSWilliam Breathitt Gray 		/* Create all attributes associated with Count */
998aaec1a0fSWilliam Breathitt Gray 		err = counter_count_attrs_create(counter, groups + i, count);
999aaec1a0fSWilliam Breathitt Gray 		if (err < 0)
1000aaec1a0fSWilliam Breathitt Gray 			return err;
1001aaec1a0fSWilliam Breathitt Gray 	}
1002aaec1a0fSWilliam Breathitt Gray 
1003aaec1a0fSWilliam Breathitt Gray 	return 0;
1004aaec1a0fSWilliam Breathitt Gray }
1005aaec1a0fSWilliam Breathitt Gray 
counter_num_signals_read(struct counter_device * counter,u8 * val)1006aaec1a0fSWilliam Breathitt Gray static int counter_num_signals_read(struct counter_device *counter, u8 *val)
1007aaec1a0fSWilliam Breathitt Gray {
1008aaec1a0fSWilliam Breathitt Gray 	*val = counter->num_signals;
1009aaec1a0fSWilliam Breathitt Gray 	return 0;
1010aaec1a0fSWilliam Breathitt Gray }
1011aaec1a0fSWilliam Breathitt Gray 
counter_num_counts_read(struct counter_device * counter,u8 * val)1012aaec1a0fSWilliam Breathitt Gray static int counter_num_counts_read(struct counter_device *counter, u8 *val)
1013aaec1a0fSWilliam Breathitt Gray {
1014aaec1a0fSWilliam Breathitt Gray 	*val = counter->num_counts;
1015aaec1a0fSWilliam Breathitt Gray 	return 0;
1016aaec1a0fSWilliam Breathitt Gray }
1017aaec1a0fSWilliam Breathitt Gray 
counter_events_queue_size_read(struct counter_device * counter,u64 * val)1018feff17a5SWilliam Breathitt Gray static int counter_events_queue_size_read(struct counter_device *counter,
1019feff17a5SWilliam Breathitt Gray 					  u64 *val)
1020feff17a5SWilliam Breathitt Gray {
1021feff17a5SWilliam Breathitt Gray 	*val = kfifo_size(&counter->events);
1022feff17a5SWilliam Breathitt Gray 	return 0;
1023feff17a5SWilliam Breathitt Gray }
1024feff17a5SWilliam Breathitt Gray 
counter_events_queue_size_write(struct counter_device * counter,u64 val)1025feff17a5SWilliam Breathitt Gray static int counter_events_queue_size_write(struct counter_device *counter,
1026feff17a5SWilliam Breathitt Gray 					   u64 val)
1027feff17a5SWilliam Breathitt Gray {
1028feff17a5SWilliam Breathitt Gray 	DECLARE_KFIFO_PTR(events, struct counter_event);
1029f5245a5fSDavid Lechner 	int err;
10308ac33b8bSWilliam Breathitt Gray 	unsigned long flags;
1031feff17a5SWilliam Breathitt Gray 
1032feff17a5SWilliam Breathitt Gray 	/* Allocate new events queue */
1033feff17a5SWilliam Breathitt Gray 	err = kfifo_alloc(&events, val, GFP_KERNEL);
1034feff17a5SWilliam Breathitt Gray 	if (err)
1035f5245a5fSDavid Lechner 		return err;
1036feff17a5SWilliam Breathitt Gray 
1037feff17a5SWilliam Breathitt Gray 	/* Swap in new events queue */
10388ac33b8bSWilliam Breathitt Gray 	mutex_lock(&counter->events_out_lock);
10398ac33b8bSWilliam Breathitt Gray 	spin_lock_irqsave(&counter->events_in_lock, flags);
1040feff17a5SWilliam Breathitt Gray 	kfifo_free(&counter->events);
1041feff17a5SWilliam Breathitt Gray 	counter->events.kfifo = events.kfifo;
10428ac33b8bSWilliam Breathitt Gray 	spin_unlock_irqrestore(&counter->events_in_lock, flags);
10438ac33b8bSWilliam Breathitt Gray 	mutex_unlock(&counter->events_out_lock);
1044feff17a5SWilliam Breathitt Gray 
1045f5245a5fSDavid Lechner 	return 0;
1046feff17a5SWilliam Breathitt Gray }
1047feff17a5SWilliam Breathitt Gray 
1048aaec1a0fSWilliam Breathitt Gray static struct counter_comp counter_num_signals_comp =
1049aaec1a0fSWilliam Breathitt Gray 	COUNTER_COMP_DEVICE_U8("num_signals", counter_num_signals_read, NULL);
1050aaec1a0fSWilliam Breathitt Gray 
1051aaec1a0fSWilliam Breathitt Gray static struct counter_comp counter_num_counts_comp =
1052aaec1a0fSWilliam Breathitt Gray 	COUNTER_COMP_DEVICE_U8("num_counts", counter_num_counts_read, NULL);
1053aaec1a0fSWilliam Breathitt Gray 
1054feff17a5SWilliam Breathitt Gray static struct counter_comp counter_events_queue_size_comp =
1055feff17a5SWilliam Breathitt Gray 	COUNTER_COMP_DEVICE_U64("events_queue_size",
1056feff17a5SWilliam Breathitt Gray 				counter_events_queue_size_read,
1057feff17a5SWilliam Breathitt Gray 				counter_events_queue_size_write);
1058feff17a5SWilliam Breathitt Gray 
counter_sysfs_attr_add(struct counter_device * const counter,struct counter_attribute_group * cattr_group)1059aaec1a0fSWilliam Breathitt Gray static int counter_sysfs_attr_add(struct counter_device *const counter,
1060aaec1a0fSWilliam Breathitt Gray 				  struct counter_attribute_group *cattr_group)
1061aaec1a0fSWilliam Breathitt Gray {
1062aaec1a0fSWilliam Breathitt Gray 	const enum counter_scope scope = COUNTER_SCOPE_DEVICE;
1063aaec1a0fSWilliam Breathitt Gray 	struct device *const dev = &counter->dev;
1064aaec1a0fSWilliam Breathitt Gray 	int err;
1065aaec1a0fSWilliam Breathitt Gray 
1066aaec1a0fSWilliam Breathitt Gray 	/* Add Signals sysfs attributes */
1067aaec1a0fSWilliam Breathitt Gray 	err = counter_sysfs_signals_add(counter, cattr_group);
1068aaec1a0fSWilliam Breathitt Gray 	if (err < 0)
1069aaec1a0fSWilliam Breathitt Gray 		return err;
1070aaec1a0fSWilliam Breathitt Gray 	cattr_group += counter->num_signals;
1071aaec1a0fSWilliam Breathitt Gray 
1072aaec1a0fSWilliam Breathitt Gray 	/* Add Counts sysfs attributes */
1073aaec1a0fSWilliam Breathitt Gray 	err = counter_sysfs_counts_add(counter, cattr_group);
1074aaec1a0fSWilliam Breathitt Gray 	if (err < 0)
1075aaec1a0fSWilliam Breathitt Gray 		return err;
1076aaec1a0fSWilliam Breathitt Gray 	cattr_group += counter->num_counts;
1077aaec1a0fSWilliam Breathitt Gray 
1078aaec1a0fSWilliam Breathitt Gray 	/* Create name attribute */
1079aaec1a0fSWilliam Breathitt Gray 	err = counter_name_attr_create(dev, cattr_group, counter->name);
1080aaec1a0fSWilliam Breathitt Gray 	if (err < 0)
1081aaec1a0fSWilliam Breathitt Gray 		return err;
1082aaec1a0fSWilliam Breathitt Gray 
1083aaec1a0fSWilliam Breathitt Gray 	/* Create num_signals attribute */
1084aaec1a0fSWilliam Breathitt Gray 	err = counter_attr_create(dev, cattr_group, &counter_num_signals_comp,
1085aaec1a0fSWilliam Breathitt Gray 				  scope, NULL);
1086aaec1a0fSWilliam Breathitt Gray 	if (err < 0)
1087aaec1a0fSWilliam Breathitt Gray 		return err;
1088aaec1a0fSWilliam Breathitt Gray 
1089aaec1a0fSWilliam Breathitt Gray 	/* Create num_counts attribute */
1090aaec1a0fSWilliam Breathitt Gray 	err = counter_attr_create(dev, cattr_group, &counter_num_counts_comp,
1091aaec1a0fSWilliam Breathitt Gray 				  scope, NULL);
1092aaec1a0fSWilliam Breathitt Gray 	if (err < 0)
1093aaec1a0fSWilliam Breathitt Gray 		return err;
1094aaec1a0fSWilliam Breathitt Gray 
1095feff17a5SWilliam Breathitt Gray 	/* Create events_queue_size attribute */
1096feff17a5SWilliam Breathitt Gray 	err = counter_attr_create(dev, cattr_group,
1097feff17a5SWilliam Breathitt Gray 				  &counter_events_queue_size_comp, scope, NULL);
1098feff17a5SWilliam Breathitt Gray 	if (err < 0)
1099feff17a5SWilliam Breathitt Gray 		return err;
1100feff17a5SWilliam Breathitt Gray 
1101bb4bbbecSWilliam Breathitt Gray 	/* Add device extensions */
1102bb4bbbecSWilliam Breathitt Gray 	return counter_sysfs_exts_add(dev, cattr_group, counter->ext,
1103bb4bbbecSWilliam Breathitt Gray 				      counter->num_ext, scope, NULL);
1104aaec1a0fSWilliam Breathitt Gray 
1105aaec1a0fSWilliam Breathitt Gray 	return 0;
1106aaec1a0fSWilliam Breathitt Gray }
1107aaec1a0fSWilliam Breathitt Gray 
1108aaec1a0fSWilliam Breathitt Gray /**
1109aaec1a0fSWilliam Breathitt Gray  * counter_sysfs_add - Adds Counter sysfs attributes to the device structure
1110aaec1a0fSWilliam Breathitt Gray  * @counter:	Pointer to the Counter device structure
1111aaec1a0fSWilliam Breathitt Gray  *
1112aaec1a0fSWilliam Breathitt Gray  * Counter sysfs attributes are created and added to the respective device
1113aaec1a0fSWilliam Breathitt Gray  * structure for later registration to the system. Resource-managed memory
1114aaec1a0fSWilliam Breathitt Gray  * allocation is performed by this function, and this memory should be freed
1115aaec1a0fSWilliam Breathitt Gray  * when no longer needed (automatically by a device_unregister call, or
1116aaec1a0fSWilliam Breathitt Gray  * manually by a devres_release_all call).
1117aaec1a0fSWilliam Breathitt Gray  */
counter_sysfs_add(struct counter_device * const counter)1118aaec1a0fSWilliam Breathitt Gray int counter_sysfs_add(struct counter_device *const counter)
1119aaec1a0fSWilliam Breathitt Gray {
1120aaec1a0fSWilliam Breathitt Gray 	struct device *const dev = &counter->dev;
1121aaec1a0fSWilliam Breathitt Gray 	const size_t num_groups = counter->num_signals + counter->num_counts + 1;
1122aaec1a0fSWilliam Breathitt Gray 	struct counter_attribute_group *cattr_groups;
1123aaec1a0fSWilliam Breathitt Gray 	size_t i, j;
1124aaec1a0fSWilliam Breathitt Gray 	int err;
1125aaec1a0fSWilliam Breathitt Gray 	struct attribute_group *groups;
1126aaec1a0fSWilliam Breathitt Gray 	struct counter_attribute *p;
1127aaec1a0fSWilliam Breathitt Gray 
1128aaec1a0fSWilliam Breathitt Gray 	/* Allocate space for attribute groups (signals, counts, and ext) */
1129aaec1a0fSWilliam Breathitt Gray 	cattr_groups = devm_kcalloc(dev, num_groups, sizeof(*cattr_groups),
1130aaec1a0fSWilliam Breathitt Gray 				    GFP_KERNEL);
1131aaec1a0fSWilliam Breathitt Gray 	if (!cattr_groups)
1132aaec1a0fSWilliam Breathitt Gray 		return -ENOMEM;
1133aaec1a0fSWilliam Breathitt Gray 
1134aaec1a0fSWilliam Breathitt Gray 	/* Initialize attribute lists */
1135aaec1a0fSWilliam Breathitt Gray 	for (i = 0; i < num_groups; i++)
1136aaec1a0fSWilliam Breathitt Gray 		INIT_LIST_HEAD(&cattr_groups[i].attr_list);
1137aaec1a0fSWilliam Breathitt Gray 
1138aaec1a0fSWilliam Breathitt Gray 	/* Add Counter device sysfs attributes */
1139aaec1a0fSWilliam Breathitt Gray 	err = counter_sysfs_attr_add(counter, cattr_groups);
1140aaec1a0fSWilliam Breathitt Gray 	if (err < 0)
1141aaec1a0fSWilliam Breathitt Gray 		return err;
1142aaec1a0fSWilliam Breathitt Gray 
1143aaec1a0fSWilliam Breathitt Gray 	/* Allocate attribute group pointers for association with device */
1144aaec1a0fSWilliam Breathitt Gray 	dev->groups = devm_kcalloc(dev, num_groups + 1, sizeof(*dev->groups),
1145aaec1a0fSWilliam Breathitt Gray 				   GFP_KERNEL);
1146aaec1a0fSWilliam Breathitt Gray 	if (!dev->groups)
1147aaec1a0fSWilliam Breathitt Gray 		return -ENOMEM;
1148aaec1a0fSWilliam Breathitt Gray 
1149aaec1a0fSWilliam Breathitt Gray 	/* Allocate space for attribute groups */
1150aaec1a0fSWilliam Breathitt Gray 	groups = devm_kcalloc(dev, num_groups, sizeof(*groups), GFP_KERNEL);
1151aaec1a0fSWilliam Breathitt Gray 	if (!groups)
1152aaec1a0fSWilliam Breathitt Gray 		return -ENOMEM;
1153aaec1a0fSWilliam Breathitt Gray 
1154aaec1a0fSWilliam Breathitt Gray 	/* Prepare each group of attributes for association */
1155aaec1a0fSWilliam Breathitt Gray 	for (i = 0; i < num_groups; i++) {
1156aaec1a0fSWilliam Breathitt Gray 		groups[i].name = cattr_groups[i].name;
1157aaec1a0fSWilliam Breathitt Gray 
1158aaec1a0fSWilliam Breathitt Gray 		/* Allocate space for attribute pointers */
1159aaec1a0fSWilliam Breathitt Gray 		groups[i].attrs = devm_kcalloc(dev,
1160aaec1a0fSWilliam Breathitt Gray 					       cattr_groups[i].num_attr + 1,
1161aaec1a0fSWilliam Breathitt Gray 					       sizeof(*groups[i].attrs),
1162aaec1a0fSWilliam Breathitt Gray 					       GFP_KERNEL);
1163aaec1a0fSWilliam Breathitt Gray 		if (!groups[i].attrs)
1164aaec1a0fSWilliam Breathitt Gray 			return -ENOMEM;
1165aaec1a0fSWilliam Breathitt Gray 
1166aaec1a0fSWilliam Breathitt Gray 		/* Add attribute pointers to attribute group */
1167aaec1a0fSWilliam Breathitt Gray 		j = 0;
1168aaec1a0fSWilliam Breathitt Gray 		list_for_each_entry(p, &cattr_groups[i].attr_list, l)
1169aaec1a0fSWilliam Breathitt Gray 			groups[i].attrs[j++] = &p->dev_attr.attr;
1170aaec1a0fSWilliam Breathitt Gray 
1171aaec1a0fSWilliam Breathitt Gray 		/* Associate attribute group */
1172aaec1a0fSWilliam Breathitt Gray 		dev->groups[i] = &groups[i];
1173aaec1a0fSWilliam Breathitt Gray 	}
1174aaec1a0fSWilliam Breathitt Gray 
1175aaec1a0fSWilliam Breathitt Gray 	return 0;
1176aaec1a0fSWilliam Breathitt Gray }
1177