sched: Prevent balance_push() on remote runqueues
[linux-2.6-microblaze.git] / drivers / leds / led-class-flash.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * LED Flash class interface
4  *
5  * Copyright (C) 2015 Samsung Electronics Co., Ltd.
6  * Author: Jacek Anaszewski <j.anaszewski@samsung.com>
7  */
8
9 #include <linux/device.h>
10 #include <linux/init.h>
11 #include <linux/led-class-flash.h>
12 #include <linux/leds.h>
13 #include <linux/module.h>
14 #include <linux/slab.h>
15 #include "leds.h"
16
17 #define has_flash_op(fled_cdev, op)                             \
18         (fled_cdev && fled_cdev->ops->op)
19
20 #define call_flash_op(fled_cdev, op, args...)           \
21         ((has_flash_op(fled_cdev, op)) ?                        \
22                         (fled_cdev->ops->op(fled_cdev, args)) : \
23                         -EINVAL)
24
25 static const char * const led_flash_fault_names[] = {
26         "led-over-voltage",
27         "flash-timeout-exceeded",
28         "controller-over-temperature",
29         "controller-short-circuit",
30         "led-power-supply-over-current",
31         "indicator-led-fault",
32         "led-under-voltage",
33         "controller-under-voltage",
34         "led-over-temperature",
35 };
36
37 static ssize_t flash_brightness_store(struct device *dev,
38                 struct device_attribute *attr, const char *buf, size_t size)
39 {
40         struct led_classdev *led_cdev = dev_get_drvdata(dev);
41         struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
42         unsigned long state;
43         ssize_t ret;
44
45         mutex_lock(&led_cdev->led_access);
46
47         if (led_sysfs_is_disabled(led_cdev)) {
48                 ret = -EBUSY;
49                 goto unlock;
50         }
51
52         ret = kstrtoul(buf, 10, &state);
53         if (ret)
54                 goto unlock;
55
56         ret = led_set_flash_brightness(fled_cdev, state);
57         if (ret < 0)
58                 goto unlock;
59
60         ret = size;
61 unlock:
62         mutex_unlock(&led_cdev->led_access);
63         return ret;
64 }
65
66 static ssize_t flash_brightness_show(struct device *dev,
67                 struct device_attribute *attr, char *buf)
68 {
69         struct led_classdev *led_cdev = dev_get_drvdata(dev);
70         struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
71
72         /* no lock needed for this */
73         led_update_flash_brightness(fled_cdev);
74
75         return sprintf(buf, "%u\n", fled_cdev->brightness.val);
76 }
77 static DEVICE_ATTR_RW(flash_brightness);
78
79 static ssize_t max_flash_brightness_show(struct device *dev,
80                 struct device_attribute *attr, char *buf)
81 {
82         struct led_classdev *led_cdev = dev_get_drvdata(dev);
83         struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
84
85         return sprintf(buf, "%u\n", fled_cdev->brightness.max);
86 }
87 static DEVICE_ATTR_RO(max_flash_brightness);
88
89 static ssize_t flash_strobe_store(struct device *dev,
90                 struct device_attribute *attr, const char *buf, size_t size)
91 {
92         struct led_classdev *led_cdev = dev_get_drvdata(dev);
93         struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
94         unsigned long state;
95         ssize_t ret = -EINVAL;
96
97         mutex_lock(&led_cdev->led_access);
98
99         if (led_sysfs_is_disabled(led_cdev)) {
100                 ret = -EBUSY;
101                 goto unlock;
102         }
103
104         ret = kstrtoul(buf, 10, &state);
105         if (ret)
106                 goto unlock;
107
108         if (state > 1) {
109                 ret = -EINVAL;
110                 goto unlock;
111         }
112
113         ret = led_set_flash_strobe(fled_cdev, state);
114         if (ret < 0)
115                 goto unlock;
116         ret = size;
117 unlock:
118         mutex_unlock(&led_cdev->led_access);
119         return ret;
120 }
121
122 static ssize_t flash_strobe_show(struct device *dev,
123                 struct device_attribute *attr, char *buf)
124 {
125         struct led_classdev *led_cdev = dev_get_drvdata(dev);
126         struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
127         bool state;
128         int ret;
129
130         /* no lock needed for this */
131         ret = led_get_flash_strobe(fled_cdev, &state);
132         if (ret < 0)
133                 return ret;
134
135         return sprintf(buf, "%u\n", state);
136 }
137 static DEVICE_ATTR_RW(flash_strobe);
138
139 static ssize_t flash_timeout_store(struct device *dev,
140                 struct device_attribute *attr, const char *buf, size_t size)
141 {
142         struct led_classdev *led_cdev = dev_get_drvdata(dev);
143         struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
144         unsigned long flash_timeout;
145         ssize_t ret;
146
147         mutex_lock(&led_cdev->led_access);
148
149         if (led_sysfs_is_disabled(led_cdev)) {
150                 ret = -EBUSY;
151                 goto unlock;
152         }
153
154         ret = kstrtoul(buf, 10, &flash_timeout);
155         if (ret)
156                 goto unlock;
157
158         ret = led_set_flash_timeout(fled_cdev, flash_timeout);
159         if (ret < 0)
160                 goto unlock;
161
162         ret = size;
163 unlock:
164         mutex_unlock(&led_cdev->led_access);
165         return ret;
166 }
167
168 static ssize_t flash_timeout_show(struct device *dev,
169                 struct device_attribute *attr, char *buf)
170 {
171         struct led_classdev *led_cdev = dev_get_drvdata(dev);
172         struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
173
174         return sprintf(buf, "%u\n", fled_cdev->timeout.val);
175 }
176 static DEVICE_ATTR_RW(flash_timeout);
177
178 static ssize_t max_flash_timeout_show(struct device *dev,
179                 struct device_attribute *attr, char *buf)
180 {
181         struct led_classdev *led_cdev = dev_get_drvdata(dev);
182         struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
183
184         return sprintf(buf, "%u\n", fled_cdev->timeout.max);
185 }
186 static DEVICE_ATTR_RO(max_flash_timeout);
187
188 static ssize_t flash_fault_show(struct device *dev,
189                 struct device_attribute *attr, char *buf)
190 {
191         struct led_classdev *led_cdev = dev_get_drvdata(dev);
192         struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
193         u32 fault, mask = 0x1;
194         char *pbuf = buf;
195         int i, ret, buf_len;
196
197         ret = led_get_flash_fault(fled_cdev, &fault);
198         if (ret < 0)
199                 return -EINVAL;
200
201         *buf = '\0';
202
203         for (i = 0; i < LED_NUM_FLASH_FAULTS; ++i) {
204                 if (fault & mask) {
205                         buf_len = sprintf(pbuf, "%s ",
206                                           led_flash_fault_names[i]);
207                         pbuf += buf_len;
208                 }
209                 mask <<= 1;
210         }
211
212         return sprintf(buf, "%s\n", buf);
213 }
214 static DEVICE_ATTR_RO(flash_fault);
215
216 static struct attribute *led_flash_strobe_attrs[] = {
217         &dev_attr_flash_strobe.attr,
218         NULL,
219 };
220
221 static struct attribute *led_flash_timeout_attrs[] = {
222         &dev_attr_flash_timeout.attr,
223         &dev_attr_max_flash_timeout.attr,
224         NULL,
225 };
226
227 static struct attribute *led_flash_brightness_attrs[] = {
228         &dev_attr_flash_brightness.attr,
229         &dev_attr_max_flash_brightness.attr,
230         NULL,
231 };
232
233 static struct attribute *led_flash_fault_attrs[] = {
234         &dev_attr_flash_fault.attr,
235         NULL,
236 };
237
238 static const struct attribute_group led_flash_strobe_group = {
239         .attrs = led_flash_strobe_attrs,
240 };
241
242 static const struct attribute_group led_flash_timeout_group = {
243         .attrs = led_flash_timeout_attrs,
244 };
245
246 static const struct attribute_group led_flash_brightness_group = {
247         .attrs = led_flash_brightness_attrs,
248 };
249
250 static const struct attribute_group led_flash_fault_group = {
251         .attrs = led_flash_fault_attrs,
252 };
253
254 static void led_flash_resume(struct led_classdev *led_cdev)
255 {
256         struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
257
258         call_flash_op(fled_cdev, flash_brightness_set,
259                                         fled_cdev->brightness.val);
260         call_flash_op(fled_cdev, timeout_set, fled_cdev->timeout.val);
261 }
262
263 static void led_flash_init_sysfs_groups(struct led_classdev_flash *fled_cdev)
264 {
265         struct led_classdev *led_cdev = &fled_cdev->led_cdev;
266         const struct led_flash_ops *ops = fled_cdev->ops;
267         const struct attribute_group **flash_groups = fled_cdev->sysfs_groups;
268
269         int num_sysfs_groups = 0;
270
271         flash_groups[num_sysfs_groups++] = &led_flash_strobe_group;
272
273         if (ops->flash_brightness_set)
274                 flash_groups[num_sysfs_groups++] = &led_flash_brightness_group;
275
276         if (ops->timeout_set)
277                 flash_groups[num_sysfs_groups++] = &led_flash_timeout_group;
278
279         if (ops->fault_get)
280                 flash_groups[num_sysfs_groups++] = &led_flash_fault_group;
281
282         led_cdev->groups = flash_groups;
283 }
284
285 int led_classdev_flash_register_ext(struct device *parent,
286                                     struct led_classdev_flash *fled_cdev,
287                                     struct led_init_data *init_data)
288 {
289         struct led_classdev *led_cdev;
290         const struct led_flash_ops *ops;
291         int ret;
292
293         if (!fled_cdev)
294                 return -EINVAL;
295
296         led_cdev = &fled_cdev->led_cdev;
297
298         if (led_cdev->flags & LED_DEV_CAP_FLASH) {
299                 if (!led_cdev->brightness_set_blocking)
300                         return -EINVAL;
301
302                 ops = fled_cdev->ops;
303                 if (!ops || !ops->strobe_set)
304                         return -EINVAL;
305
306                 led_cdev->flash_resume = led_flash_resume;
307
308                 /* Select the sysfs attributes to be created for the device */
309                 led_flash_init_sysfs_groups(fled_cdev);
310         }
311
312         /* Register led class device */
313         ret = led_classdev_register_ext(parent, led_cdev, init_data);
314         if (ret < 0)
315                 return ret;
316
317         return 0;
318 }
319 EXPORT_SYMBOL_GPL(led_classdev_flash_register_ext);
320
321 void led_classdev_flash_unregister(struct led_classdev_flash *fled_cdev)
322 {
323         if (!fled_cdev)
324                 return;
325
326         led_classdev_unregister(&fled_cdev->led_cdev);
327 }
328 EXPORT_SYMBOL_GPL(led_classdev_flash_unregister);
329
330 static void devm_led_classdev_flash_release(struct device *dev, void *res)
331 {
332         led_classdev_flash_unregister(*(struct led_classdev_flash **)res);
333 }
334
335 int devm_led_classdev_flash_register_ext(struct device *parent,
336                                      struct led_classdev_flash *fled_cdev,
337                                      struct led_init_data *init_data)
338 {
339         struct led_classdev_flash **dr;
340         int ret;
341
342         dr = devres_alloc(devm_led_classdev_flash_release, sizeof(*dr),
343                           GFP_KERNEL);
344         if (!dr)
345                 return -ENOMEM;
346
347         ret = led_classdev_flash_register_ext(parent, fled_cdev, init_data);
348         if (ret) {
349                 devres_free(dr);
350                 return ret;
351         }
352
353         *dr = fled_cdev;
354         devres_add(parent, dr);
355
356         return 0;
357 }
358 EXPORT_SYMBOL_GPL(devm_led_classdev_flash_register_ext);
359
360 static int devm_led_classdev_flash_match(struct device *dev,
361                                               void *res, void *data)
362 {
363         struct led_classdev_flash **p = res;
364
365         if (WARN_ON(!p || !*p))
366                 return 0;
367
368         return *p == data;
369 }
370
371 void devm_led_classdev_flash_unregister(struct device *dev,
372                                         struct led_classdev_flash *fled_cdev)
373 {
374         WARN_ON(devres_release(dev,
375                                devm_led_classdev_flash_release,
376                                devm_led_classdev_flash_match, fled_cdev));
377 }
378 EXPORT_SYMBOL_GPL(devm_led_classdev_flash_unregister);
379
380 static void led_clamp_align(struct led_flash_setting *s)
381 {
382         u32 v, offset;
383
384         v = s->val + s->step / 2;
385         v = clamp(v, s->min, s->max);
386         offset = v - s->min;
387         offset = s->step * (offset / s->step);
388         s->val = s->min + offset;
389 }
390
391 int led_set_flash_timeout(struct led_classdev_flash *fled_cdev, u32 timeout)
392 {
393         struct led_classdev *led_cdev = &fled_cdev->led_cdev;
394         struct led_flash_setting *s = &fled_cdev->timeout;
395
396         s->val = timeout;
397         led_clamp_align(s);
398
399         if (!(led_cdev->flags & LED_SUSPENDED))
400                 return call_flash_op(fled_cdev, timeout_set, s->val);
401
402         return 0;
403 }
404 EXPORT_SYMBOL_GPL(led_set_flash_timeout);
405
406 int led_get_flash_fault(struct led_classdev_flash *fled_cdev, u32 *fault)
407 {
408         return call_flash_op(fled_cdev, fault_get, fault);
409 }
410 EXPORT_SYMBOL_GPL(led_get_flash_fault);
411
412 int led_set_flash_brightness(struct led_classdev_flash *fled_cdev,
413                                 u32 brightness)
414 {
415         struct led_classdev *led_cdev = &fled_cdev->led_cdev;
416         struct led_flash_setting *s = &fled_cdev->brightness;
417
418         s->val = brightness;
419         led_clamp_align(s);
420
421         if (!(led_cdev->flags & LED_SUSPENDED))
422                 return call_flash_op(fled_cdev, flash_brightness_set, s->val);
423
424         return 0;
425 }
426 EXPORT_SYMBOL_GPL(led_set_flash_brightness);
427
428 int led_update_flash_brightness(struct led_classdev_flash *fled_cdev)
429 {
430         struct led_flash_setting *s = &fled_cdev->brightness;
431         u32 brightness;
432
433         if (has_flash_op(fled_cdev, flash_brightness_get)) {
434                 int ret = call_flash_op(fled_cdev, flash_brightness_get,
435                                                 &brightness);
436                 if (ret < 0)
437                         return ret;
438
439                 s->val = brightness;
440         }
441
442         return 0;
443 }
444 EXPORT_SYMBOL_GPL(led_update_flash_brightness);
445
446 MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>");
447 MODULE_DESCRIPTION("LED Flash class interface");
448 MODULE_LICENSE("GPL v2");