^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * LED Class Core
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2005 John Lenz <lenz@cs.wisc.edu>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 2005-2007 Richard Purdie <rpurdie@openedhand.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/ctype.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/leds.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/list.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/property.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/spinlock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/timer.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <uapi/linux/uleds.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include "leds.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) static struct class *leds_class;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) static ssize_t brightness_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) struct led_classdev *led_cdev = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) /* no lock needed for this */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) led_update_brightness(led_cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) return sprintf(buf, "%u\n", led_cdev->brightness);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) static ssize_t brightness_store(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) struct device_attribute *attr, const char *buf, size_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) struct led_classdev *led_cdev = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) unsigned long state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) ssize_t ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) mutex_lock(&led_cdev->led_access);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) if (led_sysfs_is_disabled(led_cdev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) ret = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) goto unlock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) ret = kstrtoul(buf, 10, &state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) goto unlock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) if (state == LED_OFF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) led_trigger_remove(led_cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) led_set_brightness(led_cdev, state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) flush_work(&led_cdev->set_brightness_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) ret = size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) unlock:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) mutex_unlock(&led_cdev->led_access);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) static DEVICE_ATTR_RW(brightness);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) static ssize_t max_brightness_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) struct led_classdev *led_cdev = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) return sprintf(buf, "%u\n", led_cdev->max_brightness);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) static DEVICE_ATTR_RO(max_brightness);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) #ifdef CONFIG_LEDS_TRIGGERS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) static BIN_ATTR(trigger, 0644, led_trigger_read, led_trigger_write, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) static struct bin_attribute *led_trigger_bin_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) &bin_attr_trigger,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) static const struct attribute_group led_trigger_group = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) .bin_attrs = led_trigger_bin_attrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) static struct attribute *led_class_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) &dev_attr_brightness.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) &dev_attr_max_brightness.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) static const struct attribute_group led_group = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) .attrs = led_class_attrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) static const struct attribute_group *led_groups[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) &led_group,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) #ifdef CONFIG_LEDS_TRIGGERS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) &led_trigger_group,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) #ifdef CONFIG_LEDS_BRIGHTNESS_HW_CHANGED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) static ssize_t brightness_hw_changed_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) struct led_classdev *led_cdev = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) if (led_cdev->brightness_hw_changed == -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) return -ENODATA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) return sprintf(buf, "%u\n", led_cdev->brightness_hw_changed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) static DEVICE_ATTR_RO(brightness_hw_changed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) static int led_add_brightness_hw_changed(struct led_classdev *led_cdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) struct device *dev = led_cdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) ret = device_create_file(dev, &dev_attr_brightness_hw_changed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) dev_err(dev, "Error creating brightness_hw_changed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) led_cdev->brightness_hw_changed_kn =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) sysfs_get_dirent(dev->kobj.sd, "brightness_hw_changed");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) if (!led_cdev->brightness_hw_changed_kn) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) dev_err(dev, "Error getting brightness_hw_changed kn\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) device_remove_file(dev, &dev_attr_brightness_hw_changed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) static void led_remove_brightness_hw_changed(struct led_classdev *led_cdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) sysfs_put(led_cdev->brightness_hw_changed_kn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) device_remove_file(led_cdev->dev, &dev_attr_brightness_hw_changed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) void led_classdev_notify_brightness_hw_changed(struct led_classdev *led_cdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) enum led_brightness brightness)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) if (WARN_ON(!led_cdev->brightness_hw_changed_kn))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) led_cdev->brightness_hw_changed = brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) sysfs_notify_dirent(led_cdev->brightness_hw_changed_kn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) EXPORT_SYMBOL_GPL(led_classdev_notify_brightness_hw_changed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) static int led_add_brightness_hw_changed(struct led_classdev *led_cdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) static void led_remove_brightness_hw_changed(struct led_classdev *led_cdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) * led_classdev_suspend - suspend an led_classdev.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) * @led_cdev: the led_classdev to suspend.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) void led_classdev_suspend(struct led_classdev *led_cdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) led_cdev->flags |= LED_SUSPENDED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) led_set_brightness_nopm(led_cdev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) flush_work(&led_cdev->set_brightness_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) EXPORT_SYMBOL_GPL(led_classdev_suspend);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) * led_classdev_resume - resume an led_classdev.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) * @led_cdev: the led_classdev to resume.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) void led_classdev_resume(struct led_classdev *led_cdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) led_set_brightness_nopm(led_cdev, led_cdev->brightness);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) if (led_cdev->flash_resume)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) led_cdev->flash_resume(led_cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) led_cdev->flags &= ~LED_SUSPENDED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) EXPORT_SYMBOL_GPL(led_classdev_resume);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) #ifdef CONFIG_PM_SLEEP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) static int led_suspend(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) struct led_classdev *led_cdev = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) if (led_cdev->flags & LED_CORE_SUSPENDRESUME)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) led_classdev_suspend(led_cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) static int led_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) struct led_classdev *led_cdev = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) if (led_cdev->flags & LED_CORE_SUSPENDRESUME)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) led_classdev_resume(led_cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) static SIMPLE_DEV_PM_OPS(leds_class_dev_pm_ops, led_suspend, led_resume);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) * of_led_get() - request a LED device via the LED framework
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) * @np: device node to get the LED device from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) * @index: the index of the LED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) * Returns the LED device parsed from the phandle specified in the "leds"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) * property of a device tree node or a negative error-code on failure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) struct led_classdev *of_led_get(struct device_node *np, int index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) struct device *led_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) struct led_classdev *led_cdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) struct device_node *led_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) led_node = of_parse_phandle(np, "leds", index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) if (!led_node)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) return ERR_PTR(-ENOENT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) led_dev = class_find_device_by_of_node(leds_class, led_node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) of_node_put(led_node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) if (!led_dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) return ERR_PTR(-EPROBE_DEFER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) led_cdev = dev_get_drvdata(led_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) if (!try_module_get(led_cdev->dev->parent->driver->owner))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) return ERR_PTR(-ENODEV);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) return led_cdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) EXPORT_SYMBOL_GPL(of_led_get);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) * led_put() - release a LED device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) * @led_cdev: LED device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) void led_put(struct led_classdev *led_cdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) module_put(led_cdev->dev->parent->driver->owner);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) EXPORT_SYMBOL_GPL(led_put);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) static void devm_led_release(struct device *dev, void *res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) struct led_classdev **p = res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) led_put(*p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) * devm_of_led_get - Resource-managed request of a LED device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) * @dev: LED consumer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) * @index: index of the LED to obtain in the consumer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) * The device node of the device is parse to find the request LED device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) * The LED device returned from this function is automatically released
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) * on driver detach.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) * @return a pointer to a LED device or ERR_PTR(errno) on failure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) struct led_classdev *__must_check devm_of_led_get(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) int index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) struct led_classdev *led;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) struct led_classdev **dr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) if (!dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) return ERR_PTR(-EINVAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) led = of_led_get(dev->of_node, index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) if (IS_ERR(led))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) return led;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) dr = devres_alloc(devm_led_release, sizeof(struct led_classdev *),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) if (!dr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) led_put(led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) *dr = led;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) devres_add(dev, dr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) return led;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) EXPORT_SYMBOL_GPL(devm_of_led_get);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) static int led_classdev_next_name(const char *init_name, char *name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) unsigned int i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) strlcpy(name, init_name, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) while ((ret < len) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) (dev = class_find_device_by_name(leds_class, name))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) put_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) ret = snprintf(name, len, "%s_%u", init_name, ++i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) if (ret >= len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) return i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) * led_classdev_register_ext - register a new object of led_classdev class
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) * with init data.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) * @parent: parent of LED device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) * @led_cdev: the led_classdev structure for this device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) * @init_data: LED class device initialization data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) int led_classdev_register_ext(struct device *parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) struct led_classdev *led_cdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) struct led_init_data *init_data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) char composed_name[LED_MAX_NAME_SIZE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) char final_name[LED_MAX_NAME_SIZE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) const char *proposed_name = composed_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) if (init_data) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) if (init_data->devname_mandatory && !init_data->devicename) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) dev_err(parent, "Mandatory device name is missing");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) ret = led_compose_name(parent, init_data, composed_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) if (init_data->fwnode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) fwnode_property_read_string(init_data->fwnode,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) "linux,default-trigger",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) &led_cdev->default_trigger);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) proposed_name = led_cdev->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) ret = led_classdev_next_name(proposed_name, final_name, sizeof(final_name));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) mutex_init(&led_cdev->led_access);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) mutex_lock(&led_cdev->led_access);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) led_cdev->dev = device_create_with_groups(leds_class, parent, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) led_cdev, led_cdev->groups, "%s", final_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) if (IS_ERR(led_cdev->dev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) mutex_unlock(&led_cdev->led_access);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) return PTR_ERR(led_cdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) if (init_data && init_data->fwnode) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) led_cdev->dev->fwnode = init_data->fwnode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) led_cdev->dev->of_node = to_of_node(init_data->fwnode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) dev_warn(parent, "Led %s renamed to %s due to name collision",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) proposed_name, dev_name(led_cdev->dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) if (led_cdev->flags & LED_BRIGHT_HW_CHANGED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) ret = led_add_brightness_hw_changed(led_cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) device_unregister(led_cdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) led_cdev->dev = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) mutex_unlock(&led_cdev->led_access);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) led_cdev->work_flags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) #ifdef CONFIG_LEDS_TRIGGERS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) init_rwsem(&led_cdev->trigger_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) #ifdef CONFIG_LEDS_BRIGHTNESS_HW_CHANGED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) led_cdev->brightness_hw_changed = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) /* add to the list of leds */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) down_write(&leds_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) list_add_tail(&led_cdev->node, &leds_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) up_write(&leds_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) if (!led_cdev->max_brightness)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) led_cdev->max_brightness = LED_FULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) led_update_brightness(led_cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) led_init_core(led_cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) #ifdef CONFIG_LEDS_TRIGGERS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) led_trigger_set_default(led_cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) mutex_unlock(&led_cdev->led_access);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) dev_dbg(parent, "Registered led device: %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) led_cdev->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) EXPORT_SYMBOL_GPL(led_classdev_register_ext);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) * led_classdev_unregister - unregisters a object of led_properties class.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) * @led_cdev: the led device to unregister
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) * Unregisters a previously registered via led_classdev_register object.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) void led_classdev_unregister(struct led_classdev *led_cdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) if (IS_ERR_OR_NULL(led_cdev->dev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) #ifdef CONFIG_LEDS_TRIGGERS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) down_write(&led_cdev->trigger_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) if (led_cdev->trigger)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) led_trigger_set(led_cdev, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) up_write(&led_cdev->trigger_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) led_cdev->flags |= LED_UNREGISTERING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) /* Stop blinking */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) led_stop_software_blink(led_cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) led_set_brightness(led_cdev, LED_OFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) flush_work(&led_cdev->set_brightness_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) if (led_cdev->flags & LED_BRIGHT_HW_CHANGED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) led_remove_brightness_hw_changed(led_cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) device_unregister(led_cdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) down_write(&leds_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) list_del(&led_cdev->node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) up_write(&leds_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) mutex_destroy(&led_cdev->led_access);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) EXPORT_SYMBOL_GPL(led_classdev_unregister);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) static void devm_led_classdev_release(struct device *dev, void *res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) led_classdev_unregister(*(struct led_classdev **)res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) * devm_led_classdev_register_ext - resource managed led_classdev_register_ext()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) * @parent: parent of LED device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) * @led_cdev: the led_classdev structure for this device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) * @init_data: LED class device initialization data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) int devm_led_classdev_register_ext(struct device *parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) struct led_classdev *led_cdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) struct led_init_data *init_data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) struct led_classdev **dr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) dr = devres_alloc(devm_led_classdev_release, sizeof(*dr), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) if (!dr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) rc = led_classdev_register_ext(parent, led_cdev, init_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) devres_free(dr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) *dr = led_cdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) devres_add(parent, dr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) EXPORT_SYMBOL_GPL(devm_led_classdev_register_ext);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) static int devm_led_classdev_match(struct device *dev, void *res, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) struct led_classdev **p = res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) if (WARN_ON(!p || !*p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) return *p == data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) * devm_led_classdev_unregister() - resource managed led_classdev_unregister()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) * @parent: The device to unregister.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) * @led_cdev: the led_classdev structure for this device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) void devm_led_classdev_unregister(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) struct led_classdev *led_cdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) WARN_ON(devres_release(dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) devm_led_classdev_release,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) devm_led_classdev_match, led_cdev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) EXPORT_SYMBOL_GPL(devm_led_classdev_unregister);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) static int __init leds_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) leds_class = class_create(THIS_MODULE, "leds");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) if (IS_ERR(leds_class))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) return PTR_ERR(leds_class);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) leds_class->pm = &leds_class_dev_pm_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) leds_class->dev_groups = led_groups;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) static void __exit leds_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) class_destroy(leds_class);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) subsys_initcall(leds_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) module_exit(leds_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) MODULE_AUTHOR("John Lenz, Richard Purdie");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) MODULE_DESCRIPTION("LED Class Interface");