summaryrefslogtreecommitdiff
path: root/drivers/leds
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2023-02-21 17:32:50 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2023-02-21 17:32:50 -0800
commit69308402ca6f5b80a5a090ade0b13bd146891420 (patch)
tree5e220abeed09416d93773824f5d2cf84c017859a /drivers/leds
parent5f5ce6bcfcc3abbaf690fca30a22d0dcf6f36d32 (diff)
parent0d9bdd8a550170306c2021b8d6766c5343b870c2 (diff)
downloadlwn-69308402ca6f5b80a5a090ade0b13bd146891420.tar.gz
lwn-69308402ca6f5b80a5a090ade0b13bd146891420.zip
Merge tag 'platform-drivers-x86-v6.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86
Pull x86 platform driver updates from Hans de Goede: - AMD PMC: Improvements to aid s2idle debugging - Dell WMI-DDV: hwmon support - INT3472 camera sensor power-management: Improve privacy LED support - Intel VSEC: Base TPMI (Topology Aware Register and PM Capsule Interface) support - Mellanox: SN5600 and Nvidia L1 switch support - Microsoft Surface Support: Various cleanups + code improvements - tools/intel-speed-select: Various improvements - Miscellaneous other cleanups / fixes * tag 'platform-drivers-x86-v6.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86: (80 commits) platform/x86: nvidia-wmi-ec-backlight: Add force module parameter platform/x86/amd/pmf: Add depends on CONFIG_POWER_SUPPLY platform/x86: dell-ddv: Prefer asynchronous probing platform/x86: dell-ddv: Add hwmon support Documentation/ABI: Add new attribute for mlxreg-io sysfs interfaces platform: mellanox: mlx-platform: Move bus shift assignment out of the loop platform: mellanox: mlx-platform: Add mux selection register to regmap platform_data/mlxreg: Add field with mapped resource address platform/mellanox: mlxreg-hotplug: Allow more flexible hotplug events configuration platform: mellanox: Extend all systems with I2C notification callback platform: mellanox: Split logic in init and exit flow platform: mellanox: Split initialization procedure platform: mellanox: Introduce support of new Nvidia L1 switch platform: mellanox: Introduce support for next-generation 800GB/s switch platform: mellanox: Cosmetic changes - rename to more common name platform: mellanox: Change "reset_pwr_converter_fail" attribute platform: mellanox: Introduce support for rack manager switch MAINTAINERS: dell-wmi-sysman: drop Divya Bharathi x86/platform/uv: Make kobj_type structure constant platform/x86: think-lmi: Make kobj_type structure constant ...
Diffstat (limited to 'drivers/leds')
-rw-r--r--drivers/leds/led-class.c138
1 files changed, 118 insertions, 20 deletions
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index 6a8ea94834fa..0c4b8d8d2b4f 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -23,6 +23,8 @@
#include "leds.h"
static struct class *leds_class;
+static DEFINE_MUTEX(leds_lookup_lock);
+static LIST_HEAD(leds_lookup_list);
static ssize_t brightness_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -215,6 +217,23 @@ static int led_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(leds_class_dev_pm_ops, led_suspend, led_resume);
+static struct led_classdev *led_module_get(struct device *led_dev)
+{
+ struct led_classdev *led_cdev;
+
+ if (!led_dev)
+ return ERR_PTR(-EPROBE_DEFER);
+
+ led_cdev = dev_get_drvdata(led_dev);
+
+ if (!try_module_get(led_cdev->dev->parent->driver->owner)) {
+ put_device(led_cdev->dev);
+ return ERR_PTR(-ENODEV);
+ }
+
+ return led_cdev;
+}
+
/**
* of_led_get() - request a LED device via the LED framework
* @np: device node to get the LED device from
@@ -226,7 +245,6 @@ static SIMPLE_DEV_PM_OPS(leds_class_dev_pm_ops, led_suspend, led_resume);
struct led_classdev *of_led_get(struct device_node *np, int index)
{
struct device *led_dev;
- struct led_classdev *led_cdev;
struct device_node *led_node;
led_node = of_parse_phandle(np, "leds", index);
@@ -236,15 +254,7 @@ struct led_classdev *of_led_get(struct device_node *np, int index)
led_dev = class_find_device_by_of_node(leds_class, led_node);
of_node_put(led_node);
- if (!led_dev)
- return ERR_PTR(-EPROBE_DEFER);
-
- led_cdev = dev_get_drvdata(led_dev);
-
- if (!try_module_get(led_cdev->dev->parent->driver->owner))
- return ERR_PTR(-ENODEV);
-
- return led_cdev;
+ return led_module_get(led_dev);
}
EXPORT_SYMBOL_GPL(of_led_get);
@@ -255,6 +265,7 @@ EXPORT_SYMBOL_GPL(of_led_get);
void led_put(struct led_classdev *led_cdev)
{
module_put(led_cdev->dev->parent->driver->owner);
+ put_device(led_cdev->dev);
}
EXPORT_SYMBOL_GPL(led_put);
@@ -265,6 +276,22 @@ static void devm_led_release(struct device *dev, void *res)
led_put(*p);
}
+static struct led_classdev *__devm_led_get(struct device *dev, struct led_classdev *led)
+{
+ struct led_classdev **dr;
+
+ dr = devres_alloc(devm_led_release, sizeof(struct led_classdev *), GFP_KERNEL);
+ if (!dr) {
+ led_put(led);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ *dr = led;
+ devres_add(dev, dr);
+
+ return led;
+}
+
/**
* devm_of_led_get - Resource-managed request of a LED device
* @dev: LED consumer
@@ -280,7 +307,6 @@ struct led_classdev *__must_check devm_of_led_get(struct device *dev,
int index)
{
struct led_classdev *led;
- struct led_classdev **dr;
if (!dev)
return ERR_PTR(-EINVAL);
@@ -289,19 +315,91 @@ struct led_classdev *__must_check devm_of_led_get(struct device *dev,
if (IS_ERR(led))
return led;
- dr = devres_alloc(devm_led_release, sizeof(struct led_classdev *),
- GFP_KERNEL);
- if (!dr) {
- led_put(led);
- return ERR_PTR(-ENOMEM);
+ return __devm_led_get(dev, led);
+}
+EXPORT_SYMBOL_GPL(devm_of_led_get);
+
+/**
+ * led_get() - request a LED device via the LED framework
+ * @dev: device for which to get the LED device
+ * @con_id: name of the LED from the device's point of view
+ *
+ * @return a pointer to a LED device or ERR_PTR(errno) on failure.
+ */
+struct led_classdev *led_get(struct device *dev, char *con_id)
+{
+ struct led_lookup_data *lookup;
+ const char *provider = NULL;
+ struct device *led_dev;
+
+ mutex_lock(&leds_lookup_lock);
+ list_for_each_entry(lookup, &leds_lookup_list, list) {
+ if (!strcmp(lookup->dev_id, dev_name(dev)) &&
+ !strcmp(lookup->con_id, con_id)) {
+ provider = kstrdup_const(lookup->provider, GFP_KERNEL);
+ break;
+ }
}
+ mutex_unlock(&leds_lookup_lock);
- *dr = led;
- devres_add(dev, dr);
+ if (!provider)
+ return ERR_PTR(-ENOENT);
- return led;
+ led_dev = class_find_device_by_name(leds_class, provider);
+ kfree_const(provider);
+
+ return led_module_get(led_dev);
}
-EXPORT_SYMBOL_GPL(devm_of_led_get);
+EXPORT_SYMBOL_GPL(led_get);
+
+/**
+ * devm_led_get() - request a LED device via the LED framework
+ * @dev: device for which to get the LED device
+ * @con_id: name of the LED from the device's point of view
+ *
+ * The LED device returned from this function is automatically released
+ * on driver detach.
+ *
+ * @return a pointer to a LED device or ERR_PTR(errno) on failure.
+ */
+struct led_classdev *devm_led_get(struct device *dev, char *con_id)
+{
+ struct led_classdev *led;
+
+ led = led_get(dev, con_id);
+ if (IS_ERR(led))
+ return led;
+
+ return __devm_led_get(dev, led);
+}
+EXPORT_SYMBOL_GPL(devm_led_get);
+
+/**
+ * led_add_lookup() - Add a LED lookup table entry
+ * @led_lookup: the lookup table entry to add
+ *
+ * Add a LED lookup table entry. On systems without devicetree the lookup table
+ * is used by led_get() to find LEDs.
+ */
+void led_add_lookup(struct led_lookup_data *led_lookup)
+{
+ mutex_lock(&leds_lookup_lock);
+ list_add_tail(&led_lookup->list, &leds_lookup_list);
+ mutex_unlock(&leds_lookup_lock);
+}
+EXPORT_SYMBOL_GPL(led_add_lookup);
+
+/**
+ * led_remove_lookup() - Remove a LED lookup table entry
+ * @led_lookup: the lookup table entry to remove
+ */
+void led_remove_lookup(struct led_lookup_data *led_lookup)
+{
+ mutex_lock(&leds_lookup_lock);
+ list_del(&led_lookup->list);
+ mutex_unlock(&leds_lookup_lock);
+}
+EXPORT_SYMBOL_GPL(led_remove_lookup);
static int led_classdev_next_name(const char *init_name, char *name,
size_t len)