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 __init 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 __init 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;
231 kfree(sgs[i].sgattrs);
232 kfree(sgs[i].sg.attrs);
234 kobject_put(sg_kobj);