0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/kernel.h>
0011 #include <linux/leds.h>
0012 #include <linux/list.h>
0013 #include <linux/module.h>
0014 #include <linux/mutex.h>
0015 #include <linux/of.h>
0016 #include <linux/property.h>
0017 #include <linux/rwsem.h>
0018 #include <linux/slab.h>
0019 #include <uapi/linux/uleds.h>
0020 #include "leds.h"
0021
0022 DECLARE_RWSEM(leds_list_lock);
0023 EXPORT_SYMBOL_GPL(leds_list_lock);
0024
0025 LIST_HEAD(leds_list);
0026 EXPORT_SYMBOL_GPL(leds_list);
0027
0028 const char * const led_colors[LED_COLOR_ID_MAX] = {
0029 [LED_COLOR_ID_WHITE] = "white",
0030 [LED_COLOR_ID_RED] = "red",
0031 [LED_COLOR_ID_GREEN] = "green",
0032 [LED_COLOR_ID_BLUE] = "blue",
0033 [LED_COLOR_ID_AMBER] = "amber",
0034 [LED_COLOR_ID_VIOLET] = "violet",
0035 [LED_COLOR_ID_YELLOW] = "yellow",
0036 [LED_COLOR_ID_IR] = "ir",
0037 [LED_COLOR_ID_MULTI] = "multicolor",
0038 [LED_COLOR_ID_RGB] = "rgb",
0039 };
0040 EXPORT_SYMBOL_GPL(led_colors);
0041
0042 static int __led_set_brightness(struct led_classdev *led_cdev, unsigned int value)
0043 {
0044 if (!led_cdev->brightness_set)
0045 return -ENOTSUPP;
0046
0047 led_cdev->brightness_set(led_cdev, value);
0048
0049 return 0;
0050 }
0051
0052 static int __led_set_brightness_blocking(struct led_classdev *led_cdev, unsigned int value)
0053 {
0054 if (!led_cdev->brightness_set_blocking)
0055 return -ENOTSUPP;
0056
0057 return led_cdev->brightness_set_blocking(led_cdev, value);
0058 }
0059
0060 static void led_timer_function(struct timer_list *t)
0061 {
0062 struct led_classdev *led_cdev = from_timer(led_cdev, t, blink_timer);
0063 unsigned long brightness;
0064 unsigned long delay;
0065
0066 if (!led_cdev->blink_delay_on || !led_cdev->blink_delay_off) {
0067 led_set_brightness_nosleep(led_cdev, LED_OFF);
0068 clear_bit(LED_BLINK_SW, &led_cdev->work_flags);
0069 return;
0070 }
0071
0072 if (test_and_clear_bit(LED_BLINK_ONESHOT_STOP,
0073 &led_cdev->work_flags)) {
0074 clear_bit(LED_BLINK_SW, &led_cdev->work_flags);
0075 return;
0076 }
0077
0078 brightness = led_get_brightness(led_cdev);
0079 if (!brightness) {
0080
0081 if (test_and_clear_bit(LED_BLINK_BRIGHTNESS_CHANGE,
0082 &led_cdev->work_flags))
0083 brightness = led_cdev->new_blink_brightness;
0084 else
0085 brightness = led_cdev->blink_brightness;
0086 delay = led_cdev->blink_delay_on;
0087 } else {
0088
0089
0090
0091 led_cdev->blink_brightness = brightness;
0092 brightness = LED_OFF;
0093 delay = led_cdev->blink_delay_off;
0094 }
0095
0096 led_set_brightness_nosleep(led_cdev, brightness);
0097
0098
0099
0100
0101
0102 if (test_bit(LED_BLINK_ONESHOT, &led_cdev->work_flags)) {
0103 if (test_bit(LED_BLINK_INVERT, &led_cdev->work_flags)) {
0104 if (brightness)
0105 set_bit(LED_BLINK_ONESHOT_STOP,
0106 &led_cdev->work_flags);
0107 } else {
0108 if (!brightness)
0109 set_bit(LED_BLINK_ONESHOT_STOP,
0110 &led_cdev->work_flags);
0111 }
0112 }
0113
0114 mod_timer(&led_cdev->blink_timer, jiffies + msecs_to_jiffies(delay));
0115 }
0116
0117 static void set_brightness_delayed(struct work_struct *ws)
0118 {
0119 struct led_classdev *led_cdev =
0120 container_of(ws, struct led_classdev, set_brightness_work);
0121 int ret = 0;
0122
0123 if (test_and_clear_bit(LED_BLINK_DISABLE, &led_cdev->work_flags)) {
0124 led_cdev->delayed_set_value = LED_OFF;
0125 led_stop_software_blink(led_cdev);
0126 }
0127
0128 ret = __led_set_brightness(led_cdev, led_cdev->delayed_set_value);
0129 if (ret == -ENOTSUPP)
0130 ret = __led_set_brightness_blocking(led_cdev,
0131 led_cdev->delayed_set_value);
0132 if (ret < 0 &&
0133
0134 !(ret == -ENODEV && (led_cdev->flags & LED_UNREGISTERING) &&
0135 (led_cdev->flags & LED_HW_PLUGGABLE)))
0136 dev_err(led_cdev->dev,
0137 "Setting an LED's brightness failed (%d)\n", ret);
0138 }
0139
0140 static void led_set_software_blink(struct led_classdev *led_cdev,
0141 unsigned long delay_on,
0142 unsigned long delay_off)
0143 {
0144 int current_brightness;
0145
0146 current_brightness = led_get_brightness(led_cdev);
0147 if (current_brightness)
0148 led_cdev->blink_brightness = current_brightness;
0149 if (!led_cdev->blink_brightness)
0150 led_cdev->blink_brightness = led_cdev->max_brightness;
0151
0152 led_cdev->blink_delay_on = delay_on;
0153 led_cdev->blink_delay_off = delay_off;
0154
0155
0156 if (!delay_on) {
0157 led_set_brightness_nosleep(led_cdev, LED_OFF);
0158 return;
0159 }
0160
0161
0162 if (!delay_off) {
0163 led_set_brightness_nosleep(led_cdev,
0164 led_cdev->blink_brightness);
0165 return;
0166 }
0167
0168 set_bit(LED_BLINK_SW, &led_cdev->work_flags);
0169 mod_timer(&led_cdev->blink_timer, jiffies + 1);
0170 }
0171
0172
0173 static void led_blink_setup(struct led_classdev *led_cdev,
0174 unsigned long *delay_on,
0175 unsigned long *delay_off)
0176 {
0177 if (!test_bit(LED_BLINK_ONESHOT, &led_cdev->work_flags) &&
0178 led_cdev->blink_set &&
0179 !led_cdev->blink_set(led_cdev, delay_on, delay_off))
0180 return;
0181
0182
0183 if (!*delay_on && !*delay_off)
0184 *delay_on = *delay_off = 500;
0185
0186 led_set_software_blink(led_cdev, *delay_on, *delay_off);
0187 }
0188
0189 void led_init_core(struct led_classdev *led_cdev)
0190 {
0191 INIT_WORK(&led_cdev->set_brightness_work, set_brightness_delayed);
0192
0193 timer_setup(&led_cdev->blink_timer, led_timer_function, 0);
0194 }
0195 EXPORT_SYMBOL_GPL(led_init_core);
0196
0197 void led_blink_set(struct led_classdev *led_cdev,
0198 unsigned long *delay_on,
0199 unsigned long *delay_off)
0200 {
0201 del_timer_sync(&led_cdev->blink_timer);
0202
0203 clear_bit(LED_BLINK_SW, &led_cdev->work_flags);
0204 clear_bit(LED_BLINK_ONESHOT, &led_cdev->work_flags);
0205 clear_bit(LED_BLINK_ONESHOT_STOP, &led_cdev->work_flags);
0206
0207 led_blink_setup(led_cdev, delay_on, delay_off);
0208 }
0209 EXPORT_SYMBOL_GPL(led_blink_set);
0210
0211 void led_blink_set_oneshot(struct led_classdev *led_cdev,
0212 unsigned long *delay_on,
0213 unsigned long *delay_off,
0214 int invert)
0215 {
0216 if (test_bit(LED_BLINK_ONESHOT, &led_cdev->work_flags) &&
0217 timer_pending(&led_cdev->blink_timer))
0218 return;
0219
0220 set_bit(LED_BLINK_ONESHOT, &led_cdev->work_flags);
0221 clear_bit(LED_BLINK_ONESHOT_STOP, &led_cdev->work_flags);
0222
0223 if (invert)
0224 set_bit(LED_BLINK_INVERT, &led_cdev->work_flags);
0225 else
0226 clear_bit(LED_BLINK_INVERT, &led_cdev->work_flags);
0227
0228 led_blink_setup(led_cdev, delay_on, delay_off);
0229 }
0230 EXPORT_SYMBOL_GPL(led_blink_set_oneshot);
0231
0232 void led_stop_software_blink(struct led_classdev *led_cdev)
0233 {
0234 del_timer_sync(&led_cdev->blink_timer);
0235 led_cdev->blink_delay_on = 0;
0236 led_cdev->blink_delay_off = 0;
0237 clear_bit(LED_BLINK_SW, &led_cdev->work_flags);
0238 }
0239 EXPORT_SYMBOL_GPL(led_stop_software_blink);
0240
0241 void led_set_brightness(struct led_classdev *led_cdev, unsigned int brightness)
0242 {
0243
0244
0245
0246
0247 if (test_bit(LED_BLINK_SW, &led_cdev->work_flags)) {
0248
0249
0250
0251
0252
0253 if (!brightness) {
0254 set_bit(LED_BLINK_DISABLE, &led_cdev->work_flags);
0255 schedule_work(&led_cdev->set_brightness_work);
0256 } else {
0257 set_bit(LED_BLINK_BRIGHTNESS_CHANGE,
0258 &led_cdev->work_flags);
0259 led_cdev->new_blink_brightness = brightness;
0260 }
0261 return;
0262 }
0263
0264 led_set_brightness_nosleep(led_cdev, brightness);
0265 }
0266 EXPORT_SYMBOL_GPL(led_set_brightness);
0267
0268 void led_set_brightness_nopm(struct led_classdev *led_cdev, unsigned int value)
0269 {
0270
0271 if (!__led_set_brightness(led_cdev, value))
0272 return;
0273
0274
0275 led_cdev->delayed_set_value = value;
0276 schedule_work(&led_cdev->set_brightness_work);
0277 }
0278 EXPORT_SYMBOL_GPL(led_set_brightness_nopm);
0279
0280 void led_set_brightness_nosleep(struct led_classdev *led_cdev, unsigned int value)
0281 {
0282 led_cdev->brightness = min(value, led_cdev->max_brightness);
0283
0284 if (led_cdev->flags & LED_SUSPENDED)
0285 return;
0286
0287 led_set_brightness_nopm(led_cdev, led_cdev->brightness);
0288 }
0289 EXPORT_SYMBOL_GPL(led_set_brightness_nosleep);
0290
0291 int led_set_brightness_sync(struct led_classdev *led_cdev, unsigned int value)
0292 {
0293 if (led_cdev->blink_delay_on || led_cdev->blink_delay_off)
0294 return -EBUSY;
0295
0296 led_cdev->brightness = min(value, led_cdev->max_brightness);
0297
0298 if (led_cdev->flags & LED_SUSPENDED)
0299 return 0;
0300
0301 return __led_set_brightness_blocking(led_cdev, led_cdev->brightness);
0302 }
0303 EXPORT_SYMBOL_GPL(led_set_brightness_sync);
0304
0305 int led_update_brightness(struct led_classdev *led_cdev)
0306 {
0307 int ret = 0;
0308
0309 if (led_cdev->brightness_get) {
0310 ret = led_cdev->brightness_get(led_cdev);
0311 if (ret >= 0) {
0312 led_cdev->brightness = ret;
0313 return 0;
0314 }
0315 }
0316
0317 return ret;
0318 }
0319 EXPORT_SYMBOL_GPL(led_update_brightness);
0320
0321 u32 *led_get_default_pattern(struct led_classdev *led_cdev, unsigned int *size)
0322 {
0323 struct fwnode_handle *fwnode = led_cdev->dev->fwnode;
0324 u32 *pattern;
0325 int count;
0326
0327 count = fwnode_property_count_u32(fwnode, "led-pattern");
0328 if (count < 0)
0329 return NULL;
0330
0331 pattern = kcalloc(count, sizeof(*pattern), GFP_KERNEL);
0332 if (!pattern)
0333 return NULL;
0334
0335 if (fwnode_property_read_u32_array(fwnode, "led-pattern", pattern, count)) {
0336 kfree(pattern);
0337 return NULL;
0338 }
0339
0340 *size = count;
0341
0342 return pattern;
0343 }
0344 EXPORT_SYMBOL_GPL(led_get_default_pattern);
0345
0346
0347 void led_sysfs_disable(struct led_classdev *led_cdev)
0348 {
0349 lockdep_assert_held(&led_cdev->led_access);
0350
0351 led_cdev->flags |= LED_SYSFS_DISABLE;
0352 }
0353 EXPORT_SYMBOL_GPL(led_sysfs_disable);
0354
0355
0356 void led_sysfs_enable(struct led_classdev *led_cdev)
0357 {
0358 lockdep_assert_held(&led_cdev->led_access);
0359
0360 led_cdev->flags &= ~LED_SYSFS_DISABLE;
0361 }
0362 EXPORT_SYMBOL_GPL(led_sysfs_enable);
0363
0364 static void led_parse_fwnode_props(struct device *dev,
0365 struct fwnode_handle *fwnode,
0366 struct led_properties *props)
0367 {
0368 int ret;
0369
0370 if (!fwnode)
0371 return;
0372
0373 if (fwnode_property_present(fwnode, "label")) {
0374 ret = fwnode_property_read_string(fwnode, "label", &props->label);
0375 if (ret)
0376 dev_err(dev, "Error parsing 'label' property (%d)\n", ret);
0377 return;
0378 }
0379
0380 if (fwnode_property_present(fwnode, "color")) {
0381 ret = fwnode_property_read_u32(fwnode, "color", &props->color);
0382 if (ret)
0383 dev_err(dev, "Error parsing 'color' property (%d)\n", ret);
0384 else if (props->color >= LED_COLOR_ID_MAX)
0385 dev_err(dev, "LED color identifier out of range\n");
0386 else
0387 props->color_present = true;
0388 }
0389
0390
0391 if (!fwnode_property_present(fwnode, "function"))
0392 return;
0393
0394 ret = fwnode_property_read_string(fwnode, "function", &props->function);
0395 if (ret) {
0396 dev_err(dev,
0397 "Error parsing 'function' property (%d)\n",
0398 ret);
0399 }
0400
0401 if (!fwnode_property_present(fwnode, "function-enumerator"))
0402 return;
0403
0404 ret = fwnode_property_read_u32(fwnode, "function-enumerator",
0405 &props->func_enum);
0406 if (ret) {
0407 dev_err(dev,
0408 "Error parsing 'function-enumerator' property (%d)\n",
0409 ret);
0410 } else {
0411 props->func_enum_present = true;
0412 }
0413 }
0414
0415 int led_compose_name(struct device *dev, struct led_init_data *init_data,
0416 char *led_classdev_name)
0417 {
0418 struct led_properties props = {};
0419 struct fwnode_handle *fwnode = init_data->fwnode;
0420 const char *devicename = init_data->devicename;
0421
0422
0423
0424 BUG_ON(props.color == LED_COLOR_ID_MULTI);
0425
0426 if (!led_classdev_name)
0427 return -EINVAL;
0428
0429 led_parse_fwnode_props(dev, fwnode, &props);
0430
0431 if (props.label) {
0432
0433
0434
0435
0436
0437
0438 if (!devicename) {
0439 strscpy(led_classdev_name, props.label,
0440 LED_MAX_NAME_SIZE);
0441 } else {
0442 snprintf(led_classdev_name, LED_MAX_NAME_SIZE, "%s:%s",
0443 devicename, props.label);
0444 }
0445 } else if (props.function || props.color_present) {
0446 char tmp_buf[LED_MAX_NAME_SIZE];
0447
0448 if (props.func_enum_present) {
0449 snprintf(tmp_buf, LED_MAX_NAME_SIZE, "%s:%s-%d",
0450 props.color_present ? led_colors[props.color] : "",
0451 props.function ?: "", props.func_enum);
0452 } else {
0453 snprintf(tmp_buf, LED_MAX_NAME_SIZE, "%s:%s",
0454 props.color_present ? led_colors[props.color] : "",
0455 props.function ?: "");
0456 }
0457 if (init_data->devname_mandatory) {
0458 snprintf(led_classdev_name, LED_MAX_NAME_SIZE, "%s:%s",
0459 devicename, tmp_buf);
0460 } else {
0461 strscpy(led_classdev_name, tmp_buf, LED_MAX_NAME_SIZE);
0462
0463 }
0464 } else if (init_data->default_label) {
0465 if (!devicename) {
0466 dev_err(dev, "Legacy LED naming requires devicename segment");
0467 return -EINVAL;
0468 }
0469 snprintf(led_classdev_name, LED_MAX_NAME_SIZE, "%s:%s",
0470 devicename, init_data->default_label);
0471 } else if (is_of_node(fwnode)) {
0472 strscpy(led_classdev_name, to_of_node(fwnode)->name,
0473 LED_MAX_NAME_SIZE);
0474 } else
0475 return -EINVAL;
0476
0477 return 0;
0478 }
0479 EXPORT_SYMBOL_GPL(led_compose_name);
0480
0481 enum led_default_state led_init_default_state_get(struct fwnode_handle *fwnode)
0482 {
0483 const char *state = NULL;
0484
0485 if (!fwnode_property_read_string(fwnode, "default-state", &state)) {
0486 if (!strcmp(state, "keep"))
0487 return LEDS_DEFSTATE_KEEP;
0488 if (!strcmp(state, "on"))
0489 return LEDS_DEFSTATE_ON;
0490 }
0491
0492 return LEDS_DEFSTATE_OFF;
0493 }
0494 EXPORT_SYMBOL_GPL(led_init_default_state_get);