1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * PowerNV OPAL Sensor-groups interface
5 * Copyright 2017 IBM Corp.
8 #define pr_fmt(fmt) "opal-sensor-groups: " fmt
11 #include <linux/kobject.h>
12 #include <linux/slab.h>
16 static DEFINE_MUTEX(sg_mutex
);
18 static struct kobject
*sg_kobj
;
22 struct kobj_attribute attr
;
25 static struct sensor_group
{
27 struct attribute_group sg
;
28 struct sg_attr
*sgattrs
;
31 int sensor_group_enable(u32 handle
, bool enable
)
36 token
= opal_async_get_token_interruptible();
40 ret
= opal_sensor_group_enable(handle
, token
, enable
);
41 if (ret
== OPAL_ASYNC_COMPLETION
) {
42 ret
= opal_async_wait_response(token
, &msg
);
44 pr_devel("Failed to wait for the async response\n");
48 ret
= opal_error_code(opal_get_async_rc(msg
));
50 ret
= opal_error_code(ret
);
54 opal_async_release_token(token
);
57 EXPORT_SYMBOL_GPL(sensor_group_enable
);
59 static ssize_t
sg_store(struct kobject
*kobj
, struct kobj_attribute
*attr
,
60 const char *buf
, size_t count
)
62 struct sg_attr
*sattr
= container_of(attr
, struct sg_attr
, attr
);
67 ret
= kstrtoint(buf
, 0, &data
);
74 token
= opal_async_get_token_interruptible();
76 pr_devel("Failed to get token\n");
80 ret
= mutex_lock_interruptible(&sg_mutex
);
84 ret
= opal_sensor_group_clear(sattr
->handle
, token
);
86 case OPAL_ASYNC_COMPLETION
:
87 ret
= opal_async_wait_response(token
, &msg
);
89 pr_devel("Failed to wait for the async response\n");
93 ret
= opal_error_code(opal_get_async_rc(msg
));
101 ret
= opal_error_code(ret
);
105 mutex_unlock(&sg_mutex
);
107 opal_async_release_token(token
);
111 static struct sg_ops_info
{
113 const char *attr_name
;
114 ssize_t (*store
)(struct kobject
*kobj
, struct kobj_attribute
*attr
,
115 const char *buf
, size_t count
);
117 { OPAL_SENSOR_GROUP_CLEAR
, "clear", sg_store
},
120 static void add_attr(int handle
, struct sg_attr
*attr
, int index
)
122 attr
->handle
= handle
;
123 sysfs_attr_init(&attr
->attr
.attr
);
124 attr
->attr
.attr
.name
= ops_info
[index
].attr_name
;
125 attr
->attr
.attr
.mode
= 0220;
126 attr
->attr
.store
= ops_info
[index
].store
;
129 static int add_attr_group(const __be32
*ops
, int len
, struct sensor_group
*sg
,
135 for (i
= 0; i
< len
; i
++)
136 for (j
= 0; j
< ARRAY_SIZE(ops_info
); j
++)
137 if (be32_to_cpu(ops
[i
]) == ops_info
[j
].opal_no
) {
138 add_attr(handle
, &sg
->sgattrs
[count
], j
);
139 sg
->sg
.attrs
[count
] =
140 &sg
->sgattrs
[count
].attr
.attr
;
144 return sysfs_create_group(sg_kobj
, &sg
->sg
);
147 static int get_nr_attrs(const __be32
*ops
, int len
)
152 for (i
= 0; i
< len
; i
++)
153 for (j
= 0; j
< ARRAY_SIZE(ops_info
); j
++)
154 if (be32_to_cpu(ops
[i
]) == ops_info
[j
].opal_no
)
160 void __init
opal_sensor_groups_init(void)
162 struct device_node
*sg
, *node
;
165 sg
= of_find_compatible_node(NULL
, NULL
, "ibm,opal-sensor-group");
167 pr_devel("Sensor groups node not found\n");
171 sgs
= kcalloc(of_get_child_count(sg
), sizeof(*sgs
), GFP_KERNEL
);
175 sg_kobj
= kobject_create_and_add("sensor_groups", opal_kobj
);
177 pr_warn("Failed to create sensor group kobject\n");
181 for_each_child_of_node(sg
, node
) {
183 u32 sgid
, len
, nr_attrs
, chipid
;
185 ops
= of_get_property(node
, "ops", &len
);
189 nr_attrs
= get_nr_attrs(ops
, len
);
193 sgs
[i
].sgattrs
= kcalloc(nr_attrs
, sizeof(*sgs
[i
].sgattrs
),
196 goto out_sgs_sgattrs
;
198 sgs
[i
].sg
.attrs
= kcalloc(nr_attrs
+ 1,
199 sizeof(*sgs
[i
].sg
.attrs
),
202 if (!sgs
[i
].sg
.attrs
) {
203 kfree(sgs
[i
].sgattrs
);
204 goto out_sgs_sgattrs
;
207 if (of_property_read_u32(node
, "sensor-group-id", &sgid
)) {
208 pr_warn("sensor-group-id property not found\n");
209 goto out_sgs_sgattrs
;
212 if (!of_property_read_u32(node
, "ibm,chip-id", &chipid
))
213 sprintf(sgs
[i
].name
, "%pOFn%d", node
, chipid
);
215 sprintf(sgs
[i
].name
, "%pOFn", node
);
217 sgs
[i
].sg
.name
= sgs
[i
].name
;
218 if (add_attr_group(ops
, len
, &sgs
[i
], sgid
)) {
219 pr_warn("Failed to create sensor attribute group %s\n",
221 goto out_sgs_sgattrs
;
230 kfree(sgs
[i
].sgattrs
);
231 kfree(sgs
[i
].sg
.attrs
);
233 kobject_put(sg_kobj
);