Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^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");