1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
27aea8389SJacek Anaszewski /*
37aea8389SJacek Anaszewski * LED Flash class interface
47aea8389SJacek Anaszewski *
57aea8389SJacek Anaszewski * Copyright (C) 2015 Samsung Electronics Co., Ltd.
67aea8389SJacek Anaszewski * Author: Jacek Anaszewski <j.anaszewski@samsung.com>
77aea8389SJacek Anaszewski */
87aea8389SJacek Anaszewski
97aea8389SJacek Anaszewski #include <linux/device.h>
107aea8389SJacek Anaszewski #include <linux/init.h>
117aea8389SJacek Anaszewski #include <linux/led-class-flash.h>
127aea8389SJacek Anaszewski #include <linux/leds.h>
137aea8389SJacek Anaszewski #include <linux/module.h>
147aea8389SJacek Anaszewski #include <linux/slab.h>
157aea8389SJacek Anaszewski #include "leds.h"
167aea8389SJacek Anaszewski
177aea8389SJacek Anaszewski #define has_flash_op(fled_cdev, op) \
187aea8389SJacek Anaszewski (fled_cdev && fled_cdev->ops->op)
197aea8389SJacek Anaszewski
207aea8389SJacek Anaszewski #define call_flash_op(fled_cdev, op, args...) \
217aea8389SJacek Anaszewski ((has_flash_op(fled_cdev, op)) ? \
227aea8389SJacek Anaszewski (fled_cdev->ops->op(fled_cdev, args)) : \
237aea8389SJacek Anaszewski -EINVAL)
247aea8389SJacek Anaszewski
257aea8389SJacek Anaszewski static const char * const led_flash_fault_names[] = {
267aea8389SJacek Anaszewski "led-over-voltage",
277aea8389SJacek Anaszewski "flash-timeout-exceeded",
287aea8389SJacek Anaszewski "controller-over-temperature",
297aea8389SJacek Anaszewski "controller-short-circuit",
307aea8389SJacek Anaszewski "led-power-supply-over-current",
317aea8389SJacek Anaszewski "indicator-led-fault",
327aea8389SJacek Anaszewski "led-under-voltage",
337aea8389SJacek Anaszewski "controller-under-voltage",
347aea8389SJacek Anaszewski "led-over-temperature",
357aea8389SJacek Anaszewski };
367aea8389SJacek Anaszewski
flash_brightness_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)377aea8389SJacek Anaszewski static ssize_t flash_brightness_store(struct device *dev,
387aea8389SJacek Anaszewski struct device_attribute *attr, const char *buf, size_t size)
397aea8389SJacek Anaszewski {
407aea8389SJacek Anaszewski struct led_classdev *led_cdev = dev_get_drvdata(dev);
417aea8389SJacek Anaszewski struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
427aea8389SJacek Anaszewski unsigned long state;
437aea8389SJacek Anaszewski ssize_t ret;
447aea8389SJacek Anaszewski
457aea8389SJacek Anaszewski mutex_lock(&led_cdev->led_access);
467aea8389SJacek Anaszewski
477aea8389SJacek Anaszewski if (led_sysfs_is_disabled(led_cdev)) {
487aea8389SJacek Anaszewski ret = -EBUSY;
497aea8389SJacek Anaszewski goto unlock;
507aea8389SJacek Anaszewski }
517aea8389SJacek Anaszewski
527aea8389SJacek Anaszewski ret = kstrtoul(buf, 10, &state);
537aea8389SJacek Anaszewski if (ret)
547aea8389SJacek Anaszewski goto unlock;
557aea8389SJacek Anaszewski
567aea8389SJacek Anaszewski ret = led_set_flash_brightness(fled_cdev, state);
577aea8389SJacek Anaszewski if (ret < 0)
587aea8389SJacek Anaszewski goto unlock;
597aea8389SJacek Anaszewski
607aea8389SJacek Anaszewski ret = size;
617aea8389SJacek Anaszewski unlock:
627aea8389SJacek Anaszewski mutex_unlock(&led_cdev->led_access);
637aea8389SJacek Anaszewski return ret;
647aea8389SJacek Anaszewski }
657aea8389SJacek Anaszewski
flash_brightness_show(struct device * dev,struct device_attribute * attr,char * buf)667aea8389SJacek Anaszewski static ssize_t flash_brightness_show(struct device *dev,
677aea8389SJacek Anaszewski struct device_attribute *attr, char *buf)
687aea8389SJacek Anaszewski {
697aea8389SJacek Anaszewski struct led_classdev *led_cdev = dev_get_drvdata(dev);
707aea8389SJacek Anaszewski struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
717aea8389SJacek Anaszewski
727aea8389SJacek Anaszewski /* no lock needed for this */
737aea8389SJacek Anaszewski led_update_flash_brightness(fled_cdev);
747aea8389SJacek Anaszewski
757aea8389SJacek Anaszewski return sprintf(buf, "%u\n", fled_cdev->brightness.val);
767aea8389SJacek Anaszewski }
777aea8389SJacek Anaszewski static DEVICE_ATTR_RW(flash_brightness);
787aea8389SJacek Anaszewski
max_flash_brightness_show(struct device * dev,struct device_attribute * attr,char * buf)797aea8389SJacek Anaszewski static ssize_t max_flash_brightness_show(struct device *dev,
807aea8389SJacek Anaszewski struct device_attribute *attr, char *buf)
817aea8389SJacek Anaszewski {
827aea8389SJacek Anaszewski struct led_classdev *led_cdev = dev_get_drvdata(dev);
837aea8389SJacek Anaszewski struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
847aea8389SJacek Anaszewski
857aea8389SJacek Anaszewski return sprintf(buf, "%u\n", fled_cdev->brightness.max);
867aea8389SJacek Anaszewski }
877aea8389SJacek Anaszewski static DEVICE_ATTR_RO(max_flash_brightness);
887aea8389SJacek Anaszewski
flash_strobe_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)897aea8389SJacek Anaszewski static ssize_t flash_strobe_store(struct device *dev,
907aea8389SJacek Anaszewski struct device_attribute *attr, const char *buf, size_t size)
917aea8389SJacek Anaszewski {
927aea8389SJacek Anaszewski struct led_classdev *led_cdev = dev_get_drvdata(dev);
937aea8389SJacek Anaszewski struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
947aea8389SJacek Anaszewski unsigned long state;
95654933aeSPavel Machek ssize_t ret = -EBUSY;
967aea8389SJacek Anaszewski
977aea8389SJacek Anaszewski mutex_lock(&led_cdev->led_access);
987aea8389SJacek Anaszewski
99654933aeSPavel Machek if (led_sysfs_is_disabled(led_cdev))
1007aea8389SJacek Anaszewski goto unlock;
1017aea8389SJacek Anaszewski
1027aea8389SJacek Anaszewski ret = kstrtoul(buf, 10, &state);
1037aea8389SJacek Anaszewski if (ret)
1047aea8389SJacek Anaszewski goto unlock;
1057aea8389SJacek Anaszewski
106abc19635SJacek Anaszewski if (state > 1) {
1077aea8389SJacek Anaszewski ret = -EINVAL;
1087aea8389SJacek Anaszewski goto unlock;
1097aea8389SJacek Anaszewski }
1107aea8389SJacek Anaszewski
1117aea8389SJacek Anaszewski ret = led_set_flash_strobe(fled_cdev, state);
1127aea8389SJacek Anaszewski if (ret < 0)
1137aea8389SJacek Anaszewski goto unlock;
1147aea8389SJacek Anaszewski ret = size;
1157aea8389SJacek Anaszewski unlock:
1167aea8389SJacek Anaszewski mutex_unlock(&led_cdev->led_access);
1177aea8389SJacek Anaszewski return ret;
1187aea8389SJacek Anaszewski }
1197aea8389SJacek Anaszewski
flash_strobe_show(struct device * dev,struct device_attribute * attr,char * buf)1207aea8389SJacek Anaszewski static ssize_t flash_strobe_show(struct device *dev,
1217aea8389SJacek Anaszewski struct device_attribute *attr, char *buf)
1227aea8389SJacek Anaszewski {
1237aea8389SJacek Anaszewski struct led_classdev *led_cdev = dev_get_drvdata(dev);
1247aea8389SJacek Anaszewski struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
1257aea8389SJacek Anaszewski bool state;
1267aea8389SJacek Anaszewski int ret;
1277aea8389SJacek Anaszewski
1287aea8389SJacek Anaszewski /* no lock needed for this */
1297aea8389SJacek Anaszewski ret = led_get_flash_strobe(fled_cdev, &state);
1307aea8389SJacek Anaszewski if (ret < 0)
1317aea8389SJacek Anaszewski return ret;
1327aea8389SJacek Anaszewski
1337aea8389SJacek Anaszewski return sprintf(buf, "%u\n", state);
1347aea8389SJacek Anaszewski }
1357aea8389SJacek Anaszewski static DEVICE_ATTR_RW(flash_strobe);
1367aea8389SJacek Anaszewski
flash_timeout_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)1377aea8389SJacek Anaszewski static ssize_t flash_timeout_store(struct device *dev,
1387aea8389SJacek Anaszewski struct device_attribute *attr, const char *buf, size_t size)
1397aea8389SJacek Anaszewski {
1407aea8389SJacek Anaszewski struct led_classdev *led_cdev = dev_get_drvdata(dev);
1417aea8389SJacek Anaszewski struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
1427aea8389SJacek Anaszewski unsigned long flash_timeout;
1437aea8389SJacek Anaszewski ssize_t ret;
1447aea8389SJacek Anaszewski
1457aea8389SJacek Anaszewski mutex_lock(&led_cdev->led_access);
1467aea8389SJacek Anaszewski
1477aea8389SJacek Anaszewski if (led_sysfs_is_disabled(led_cdev)) {
1487aea8389SJacek Anaszewski ret = -EBUSY;
1497aea8389SJacek Anaszewski goto unlock;
1507aea8389SJacek Anaszewski }
1517aea8389SJacek Anaszewski
1527aea8389SJacek Anaszewski ret = kstrtoul(buf, 10, &flash_timeout);
1537aea8389SJacek Anaszewski if (ret)
1547aea8389SJacek Anaszewski goto unlock;
1557aea8389SJacek Anaszewski
1567aea8389SJacek Anaszewski ret = led_set_flash_timeout(fled_cdev, flash_timeout);
1577aea8389SJacek Anaszewski if (ret < 0)
1587aea8389SJacek Anaszewski goto unlock;
1597aea8389SJacek Anaszewski
1607aea8389SJacek Anaszewski ret = size;
1617aea8389SJacek Anaszewski unlock:
1627aea8389SJacek Anaszewski mutex_unlock(&led_cdev->led_access);
1637aea8389SJacek Anaszewski return ret;
1647aea8389SJacek Anaszewski }
1657aea8389SJacek Anaszewski
flash_timeout_show(struct device * dev,struct device_attribute * attr,char * buf)1667aea8389SJacek Anaszewski static ssize_t flash_timeout_show(struct device *dev,
1677aea8389SJacek Anaszewski struct device_attribute *attr, char *buf)
1687aea8389SJacek Anaszewski {
1697aea8389SJacek Anaszewski struct led_classdev *led_cdev = dev_get_drvdata(dev);
1707aea8389SJacek Anaszewski struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
1717aea8389SJacek Anaszewski
1727aea8389SJacek Anaszewski return sprintf(buf, "%u\n", fled_cdev->timeout.val);
1737aea8389SJacek Anaszewski }
1747aea8389SJacek Anaszewski static DEVICE_ATTR_RW(flash_timeout);
1757aea8389SJacek Anaszewski
max_flash_timeout_show(struct device * dev,struct device_attribute * attr,char * buf)1767aea8389SJacek Anaszewski static ssize_t max_flash_timeout_show(struct device *dev,
1777aea8389SJacek Anaszewski struct device_attribute *attr, char *buf)
1787aea8389SJacek Anaszewski {
1797aea8389SJacek Anaszewski struct led_classdev *led_cdev = dev_get_drvdata(dev);
1807aea8389SJacek Anaszewski struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
1817aea8389SJacek Anaszewski
1827aea8389SJacek Anaszewski return sprintf(buf, "%u\n", fled_cdev->timeout.max);
1837aea8389SJacek Anaszewski }
1847aea8389SJacek Anaszewski static DEVICE_ATTR_RO(max_flash_timeout);
1857aea8389SJacek Anaszewski
flash_fault_show(struct device * dev,struct device_attribute * attr,char * buf)1867aea8389SJacek Anaszewski static ssize_t flash_fault_show(struct device *dev,
1877aea8389SJacek Anaszewski struct device_attribute *attr, char *buf)
1887aea8389SJacek Anaszewski {
1897aea8389SJacek Anaszewski struct led_classdev *led_cdev = dev_get_drvdata(dev);
1907aea8389SJacek Anaszewski struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
1917aea8389SJacek Anaszewski u32 fault, mask = 0x1;
1927aea8389SJacek Anaszewski char *pbuf = buf;
1937aea8389SJacek Anaszewski int i, ret, buf_len;
1947aea8389SJacek Anaszewski
1957aea8389SJacek Anaszewski ret = led_get_flash_fault(fled_cdev, &fault);
1967aea8389SJacek Anaszewski if (ret < 0)
1977aea8389SJacek Anaszewski return -EINVAL;
1987aea8389SJacek Anaszewski
1997aea8389SJacek Anaszewski *buf = '\0';
2007aea8389SJacek Anaszewski
2017aea8389SJacek Anaszewski for (i = 0; i < LED_NUM_FLASH_FAULTS; ++i) {
2027aea8389SJacek Anaszewski if (fault & mask) {
2037aea8389SJacek Anaszewski buf_len = sprintf(pbuf, "%s ",
2047aea8389SJacek Anaszewski led_flash_fault_names[i]);
2057aea8389SJacek Anaszewski pbuf += buf_len;
2067aea8389SJacek Anaszewski }
2077aea8389SJacek Anaszewski mask <<= 1;
2087aea8389SJacek Anaszewski }
2097aea8389SJacek Anaszewski
210*811b5440SArnd Bergmann return strlen(strcat(buf, "\n"));
2117aea8389SJacek Anaszewski }
2127aea8389SJacek Anaszewski static DEVICE_ATTR_RO(flash_fault);
2137aea8389SJacek Anaszewski
2147aea8389SJacek Anaszewski static struct attribute *led_flash_strobe_attrs[] = {
2157aea8389SJacek Anaszewski &dev_attr_flash_strobe.attr,
2167aea8389SJacek Anaszewski NULL,
2177aea8389SJacek Anaszewski };
2187aea8389SJacek Anaszewski
2197aea8389SJacek Anaszewski static struct attribute *led_flash_timeout_attrs[] = {
2207aea8389SJacek Anaszewski &dev_attr_flash_timeout.attr,
2217aea8389SJacek Anaszewski &dev_attr_max_flash_timeout.attr,
2227aea8389SJacek Anaszewski NULL,
2237aea8389SJacek Anaszewski };
2247aea8389SJacek Anaszewski
2257aea8389SJacek Anaszewski static struct attribute *led_flash_brightness_attrs[] = {
2267aea8389SJacek Anaszewski &dev_attr_flash_brightness.attr,
2277aea8389SJacek Anaszewski &dev_attr_max_flash_brightness.attr,
2287aea8389SJacek Anaszewski NULL,
2297aea8389SJacek Anaszewski };
2307aea8389SJacek Anaszewski
2317aea8389SJacek Anaszewski static struct attribute *led_flash_fault_attrs[] = {
2327aea8389SJacek Anaszewski &dev_attr_flash_fault.attr,
2337aea8389SJacek Anaszewski NULL,
2347aea8389SJacek Anaszewski };
2357aea8389SJacek Anaszewski
2367aea8389SJacek Anaszewski static const struct attribute_group led_flash_strobe_group = {
2377aea8389SJacek Anaszewski .attrs = led_flash_strobe_attrs,
2387aea8389SJacek Anaszewski };
2397aea8389SJacek Anaszewski
2407aea8389SJacek Anaszewski static const struct attribute_group led_flash_timeout_group = {
2417aea8389SJacek Anaszewski .attrs = led_flash_timeout_attrs,
2427aea8389SJacek Anaszewski };
2437aea8389SJacek Anaszewski
2447aea8389SJacek Anaszewski static const struct attribute_group led_flash_brightness_group = {
2457aea8389SJacek Anaszewski .attrs = led_flash_brightness_attrs,
2467aea8389SJacek Anaszewski };
2477aea8389SJacek Anaszewski
2487aea8389SJacek Anaszewski static const struct attribute_group led_flash_fault_group = {
2497aea8389SJacek Anaszewski .attrs = led_flash_fault_attrs,
2507aea8389SJacek Anaszewski };
2517aea8389SJacek Anaszewski
led_flash_resume(struct led_classdev * led_cdev)2527aea8389SJacek Anaszewski static void led_flash_resume(struct led_classdev *led_cdev)
2537aea8389SJacek Anaszewski {
2547aea8389SJacek Anaszewski struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
2557aea8389SJacek Anaszewski
2567aea8389SJacek Anaszewski call_flash_op(fled_cdev, flash_brightness_set,
2577aea8389SJacek Anaszewski fled_cdev->brightness.val);
2587aea8389SJacek Anaszewski call_flash_op(fled_cdev, timeout_set, fled_cdev->timeout.val);
2597aea8389SJacek Anaszewski }
2607aea8389SJacek Anaszewski
led_flash_init_sysfs_groups(struct led_classdev_flash * fled_cdev)2617aea8389SJacek Anaszewski static void led_flash_init_sysfs_groups(struct led_classdev_flash *fled_cdev)
2627aea8389SJacek Anaszewski {
2637aea8389SJacek Anaszewski struct led_classdev *led_cdev = &fled_cdev->led_cdev;
2647aea8389SJacek Anaszewski const struct led_flash_ops *ops = fled_cdev->ops;
2657aea8389SJacek Anaszewski const struct attribute_group **flash_groups = fled_cdev->sysfs_groups;
2667aea8389SJacek Anaszewski
2677aea8389SJacek Anaszewski int num_sysfs_groups = 0;
2687aea8389SJacek Anaszewski
2697aea8389SJacek Anaszewski flash_groups[num_sysfs_groups++] = &led_flash_strobe_group;
2707aea8389SJacek Anaszewski
2717aea8389SJacek Anaszewski if (ops->flash_brightness_set)
2727aea8389SJacek Anaszewski flash_groups[num_sysfs_groups++] = &led_flash_brightness_group;
2737aea8389SJacek Anaszewski
2747aea8389SJacek Anaszewski if (ops->timeout_set)
2757aea8389SJacek Anaszewski flash_groups[num_sysfs_groups++] = &led_flash_timeout_group;
2767aea8389SJacek Anaszewski
2777aea8389SJacek Anaszewski if (ops->fault_get)
2787aea8389SJacek Anaszewski flash_groups[num_sysfs_groups++] = &led_flash_fault_group;
2797aea8389SJacek Anaszewski
2807aea8389SJacek Anaszewski led_cdev->groups = flash_groups;
2817aea8389SJacek Anaszewski }
2827aea8389SJacek Anaszewski
led_classdev_flash_register_ext(struct device * parent,struct led_classdev_flash * fled_cdev,struct led_init_data * init_data)283b2b998c0SJacek Anaszewski int led_classdev_flash_register_ext(struct device *parent,
284b2b998c0SJacek Anaszewski struct led_classdev_flash *fled_cdev,
285b2b998c0SJacek Anaszewski struct led_init_data *init_data)
2867aea8389SJacek Anaszewski {
2877aea8389SJacek Anaszewski struct led_classdev *led_cdev;
2887aea8389SJacek Anaszewski const struct led_flash_ops *ops;
2897aea8389SJacek Anaszewski int ret;
2907aea8389SJacek Anaszewski
2917aea8389SJacek Anaszewski if (!fled_cdev)
2927aea8389SJacek Anaszewski return -EINVAL;
2937aea8389SJacek Anaszewski
2947aea8389SJacek Anaszewski led_cdev = &fled_cdev->led_cdev;
2957aea8389SJacek Anaszewski
2967aea8389SJacek Anaszewski if (led_cdev->flags & LED_DEV_CAP_FLASH) {
297437a4240SJacek Anaszewski if (!led_cdev->brightness_set_blocking)
2987aea8389SJacek Anaszewski return -EINVAL;
2997aea8389SJacek Anaszewski
3007aea8389SJacek Anaszewski ops = fled_cdev->ops;
3017aea8389SJacek Anaszewski if (!ops || !ops->strobe_set)
3027aea8389SJacek Anaszewski return -EINVAL;
3037aea8389SJacek Anaszewski
3047aea8389SJacek Anaszewski led_cdev->flash_resume = led_flash_resume;
3057aea8389SJacek Anaszewski
3067aea8389SJacek Anaszewski /* Select the sysfs attributes to be created for the device */
3077aea8389SJacek Anaszewski led_flash_init_sysfs_groups(fled_cdev);
3087aea8389SJacek Anaszewski }
3097aea8389SJacek Anaszewski
3107aea8389SJacek Anaszewski /* Register led class device */
311b2b998c0SJacek Anaszewski ret = led_classdev_register_ext(parent, led_cdev, init_data);
3127aea8389SJacek Anaszewski if (ret < 0)
3137aea8389SJacek Anaszewski return ret;
3147aea8389SJacek Anaszewski
3157aea8389SJacek Anaszewski return 0;
3167aea8389SJacek Anaszewski }
317b2b998c0SJacek Anaszewski EXPORT_SYMBOL_GPL(led_classdev_flash_register_ext);
3187aea8389SJacek Anaszewski
led_classdev_flash_unregister(struct led_classdev_flash * fled_cdev)3197aea8389SJacek Anaszewski void led_classdev_flash_unregister(struct led_classdev_flash *fled_cdev)
3207aea8389SJacek Anaszewski {
3217aea8389SJacek Anaszewski if (!fled_cdev)
3227aea8389SJacek Anaszewski return;
3237aea8389SJacek Anaszewski
3247aea8389SJacek Anaszewski led_classdev_unregister(&fled_cdev->led_cdev);
3257aea8389SJacek Anaszewski }
3267aea8389SJacek Anaszewski EXPORT_SYMBOL_GPL(led_classdev_flash_unregister);
3277aea8389SJacek Anaszewski
devm_led_classdev_flash_release(struct device * dev,void * res)32820cdba9dSDan Murphy static void devm_led_classdev_flash_release(struct device *dev, void *res)
32920cdba9dSDan Murphy {
33020cdba9dSDan Murphy led_classdev_flash_unregister(*(struct led_classdev_flash **)res);
33120cdba9dSDan Murphy }
33220cdba9dSDan Murphy
devm_led_classdev_flash_register_ext(struct device * parent,struct led_classdev_flash * fled_cdev,struct led_init_data * init_data)33320cdba9dSDan Murphy int devm_led_classdev_flash_register_ext(struct device *parent,
33420cdba9dSDan Murphy struct led_classdev_flash *fled_cdev,
33520cdba9dSDan Murphy struct led_init_data *init_data)
33620cdba9dSDan Murphy {
33720cdba9dSDan Murphy struct led_classdev_flash **dr;
33820cdba9dSDan Murphy int ret;
33920cdba9dSDan Murphy
34020cdba9dSDan Murphy dr = devres_alloc(devm_led_classdev_flash_release, sizeof(*dr),
34120cdba9dSDan Murphy GFP_KERNEL);
34220cdba9dSDan Murphy if (!dr)
34320cdba9dSDan Murphy return -ENOMEM;
34420cdba9dSDan Murphy
34520cdba9dSDan Murphy ret = led_classdev_flash_register_ext(parent, fled_cdev, init_data);
34620cdba9dSDan Murphy if (ret) {
34720cdba9dSDan Murphy devres_free(dr);
34820cdba9dSDan Murphy return ret;
34920cdba9dSDan Murphy }
35020cdba9dSDan Murphy
35120cdba9dSDan Murphy *dr = fled_cdev;
35220cdba9dSDan Murphy devres_add(parent, dr);
35320cdba9dSDan Murphy
35420cdba9dSDan Murphy return 0;
35520cdba9dSDan Murphy }
35620cdba9dSDan Murphy EXPORT_SYMBOL_GPL(devm_led_classdev_flash_register_ext);
35720cdba9dSDan Murphy
devm_led_classdev_flash_match(struct device * dev,void * res,void * data)35820cdba9dSDan Murphy static int devm_led_classdev_flash_match(struct device *dev,
35920cdba9dSDan Murphy void *res, void *data)
36020cdba9dSDan Murphy {
36120cdba9dSDan Murphy struct led_classdev_flash **p = res;
36220cdba9dSDan Murphy
36320cdba9dSDan Murphy if (WARN_ON(!p || !*p))
36420cdba9dSDan Murphy return 0;
36520cdba9dSDan Murphy
36620cdba9dSDan Murphy return *p == data;
36720cdba9dSDan Murphy }
36820cdba9dSDan Murphy
devm_led_classdev_flash_unregister(struct device * dev,struct led_classdev_flash * fled_cdev)36920cdba9dSDan Murphy void devm_led_classdev_flash_unregister(struct device *dev,
37020cdba9dSDan Murphy struct led_classdev_flash *fled_cdev)
37120cdba9dSDan Murphy {
37220cdba9dSDan Murphy WARN_ON(devres_release(dev,
37320cdba9dSDan Murphy devm_led_classdev_flash_release,
37420cdba9dSDan Murphy devm_led_classdev_flash_match, fled_cdev));
37520cdba9dSDan Murphy }
37620cdba9dSDan Murphy EXPORT_SYMBOL_GPL(devm_led_classdev_flash_unregister);
37720cdba9dSDan Murphy
led_clamp_align(struct led_flash_setting * s)3787aea8389SJacek Anaszewski static void led_clamp_align(struct led_flash_setting *s)
3797aea8389SJacek Anaszewski {
3807aea8389SJacek Anaszewski u32 v, offset;
3817aea8389SJacek Anaszewski
3827aea8389SJacek Anaszewski v = s->val + s->step / 2;
3837aea8389SJacek Anaszewski v = clamp(v, s->min, s->max);
3847aea8389SJacek Anaszewski offset = v - s->min;
3857aea8389SJacek Anaszewski offset = s->step * (offset / s->step);
3867aea8389SJacek Anaszewski s->val = s->min + offset;
3877aea8389SJacek Anaszewski }
3887aea8389SJacek Anaszewski
led_set_flash_timeout(struct led_classdev_flash * fled_cdev,u32 timeout)3897aea8389SJacek Anaszewski int led_set_flash_timeout(struct led_classdev_flash *fled_cdev, u32 timeout)
3907aea8389SJacek Anaszewski {
3917aea8389SJacek Anaszewski struct led_classdev *led_cdev = &fled_cdev->led_cdev;
3927aea8389SJacek Anaszewski struct led_flash_setting *s = &fled_cdev->timeout;
3937aea8389SJacek Anaszewski
3947aea8389SJacek Anaszewski s->val = timeout;
3957aea8389SJacek Anaszewski led_clamp_align(s);
3967aea8389SJacek Anaszewski
3977aea8389SJacek Anaszewski if (!(led_cdev->flags & LED_SUSPENDED))
3987aea8389SJacek Anaszewski return call_flash_op(fled_cdev, timeout_set, s->val);
3997aea8389SJacek Anaszewski
4007aea8389SJacek Anaszewski return 0;
4017aea8389SJacek Anaszewski }
4027aea8389SJacek Anaszewski EXPORT_SYMBOL_GPL(led_set_flash_timeout);
4037aea8389SJacek Anaszewski
led_get_flash_fault(struct led_classdev_flash * fled_cdev,u32 * fault)4047aea8389SJacek Anaszewski int led_get_flash_fault(struct led_classdev_flash *fled_cdev, u32 *fault)
4057aea8389SJacek Anaszewski {
4067aea8389SJacek Anaszewski return call_flash_op(fled_cdev, fault_get, fault);
4077aea8389SJacek Anaszewski }
4087aea8389SJacek Anaszewski EXPORT_SYMBOL_GPL(led_get_flash_fault);
4097aea8389SJacek Anaszewski
led_set_flash_brightness(struct led_classdev_flash * fled_cdev,u32 brightness)4107aea8389SJacek Anaszewski int led_set_flash_brightness(struct led_classdev_flash *fled_cdev,
4117aea8389SJacek Anaszewski u32 brightness)
4127aea8389SJacek Anaszewski {
4137aea8389SJacek Anaszewski struct led_classdev *led_cdev = &fled_cdev->led_cdev;
4147aea8389SJacek Anaszewski struct led_flash_setting *s = &fled_cdev->brightness;
4157aea8389SJacek Anaszewski
4167aea8389SJacek Anaszewski s->val = brightness;
4177aea8389SJacek Anaszewski led_clamp_align(s);
4187aea8389SJacek Anaszewski
4197aea8389SJacek Anaszewski if (!(led_cdev->flags & LED_SUSPENDED))
4207aea8389SJacek Anaszewski return call_flash_op(fled_cdev, flash_brightness_set, s->val);
4217aea8389SJacek Anaszewski
4227aea8389SJacek Anaszewski return 0;
4237aea8389SJacek Anaszewski }
4247aea8389SJacek Anaszewski EXPORT_SYMBOL_GPL(led_set_flash_brightness);
4257aea8389SJacek Anaszewski
led_update_flash_brightness(struct led_classdev_flash * fled_cdev)4267aea8389SJacek Anaszewski int led_update_flash_brightness(struct led_classdev_flash *fled_cdev)
4277aea8389SJacek Anaszewski {
4287aea8389SJacek Anaszewski struct led_flash_setting *s = &fled_cdev->brightness;
4297aea8389SJacek Anaszewski u32 brightness;
4307aea8389SJacek Anaszewski
4317aea8389SJacek Anaszewski if (has_flash_op(fled_cdev, flash_brightness_get)) {
4327aea8389SJacek Anaszewski int ret = call_flash_op(fled_cdev, flash_brightness_get,
4337aea8389SJacek Anaszewski &brightness);
4347aea8389SJacek Anaszewski if (ret < 0)
4357aea8389SJacek Anaszewski return ret;
4367aea8389SJacek Anaszewski
4377aea8389SJacek Anaszewski s->val = brightness;
4387aea8389SJacek Anaszewski }
4397aea8389SJacek Anaszewski
4407aea8389SJacek Anaszewski return 0;
4417aea8389SJacek Anaszewski }
4427aea8389SJacek Anaszewski EXPORT_SYMBOL_GPL(led_update_flash_brightness);
4437aea8389SJacek Anaszewski
4447aea8389SJacek Anaszewski MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>");
4457aea8389SJacek Anaszewski MODULE_DESCRIPTION("LED Flash class interface");
4467aea8389SJacek Anaszewski MODULE_LICENSE("GPL v2");
447