led-class.c 17 KB

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