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