leds: Move pwm-multicolor driver into rgb directory
authorSven Schwermer <sven.schwermer@disruptive-technologies.com>
Wed, 4 May 2022 18:49:46 +0000 (20:49 +0200)
committerPavel Machek <pavel@ucw.cz>
Sat, 7 May 2022 21:09:31 +0000 (23:09 +0200)
The drivers/leds/rgb subdirectory is relatively fresh, so we move this
new PWM multi-color driver into it.

Signed-off-by: Sven Schwermer <sven.schwermer@disruptive-technologies.com>
Signed-off-by: Pavel Machek <pavel@ucw.cz>
drivers/leds/Kconfig
drivers/leds/Makefile
drivers/leds/leds-pwm-multicolor.c [deleted file]
drivers/leds/rgb/Kconfig
drivers/leds/rgb/Makefile
drivers/leds/rgb/leds-pwm-multicolor.c [new file with mode: 0644]

index ea4481000bfe3df8a4950879f172dd0c45ce71ea..a49979f41eee76967c1abb008e51f1209f64e3ed 100644 (file)
@@ -552,17 +552,6 @@ config LEDS_PWM
        help
          This option enables support for pwm driven LEDs
 
-config LEDS_PWM_MULTICOLOR
-       tristate "PWM driven multi-color LED Support"
-       depends on LEDS_CLASS_MULTICOLOR
-       depends on PWM
-       help
-         This option enables support for PWM driven monochrome LEDs that are
-         grouped into multicolor LEDs.
-
-         To compile this driver as a module, choose M here: the module
-         will be called leds-pwm-multicolor.
-
 config LEDS_REGULATOR
        tristate "REGULATOR driven LED support"
        depends on LEDS_CLASS
index c6a147865705c4d9e2da9c5f82787872e6b8b20b..4fd2f92cd19811c29c84ce395237fa0e8c9b59c8 100644 (file)
@@ -73,7 +73,6 @@ obj-$(CONFIG_LEDS_PCA963X)            += leds-pca963x.o
 obj-$(CONFIG_LEDS_PM8058)              += leds-pm8058.o
 obj-$(CONFIG_LEDS_POWERNV)             += leds-powernv.o
 obj-$(CONFIG_LEDS_PWM)                 += leds-pwm.o
-obj-$(CONFIG_LEDS_PWM_MULTICOLOR)      += leds-pwm-multicolor.o
 obj-$(CONFIG_LEDS_REGULATOR)           += leds-regulator.o
 obj-$(CONFIG_LEDS_S3C24XX)             += leds-s3c24xx.o
 obj-$(CONFIG_LEDS_SC27XX_BLTC)         += leds-sc27xx-bltc.o
diff --git a/drivers/leds/leds-pwm-multicolor.c b/drivers/leds/leds-pwm-multicolor.c
deleted file mode 100644 (file)
index 45e3870..0000000
+++ /dev/null
@@ -1,186 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * PWM-based multi-color LED control
- *
- * Copyright 2022 Sven Schwermer <sven.schwermer@disruptive-technologies.com>
- */
-
-#include <linux/err.h>
-#include <linux/kernel.h>
-#include <linux/led-class-multicolor.h>
-#include <linux/leds.h>
-#include <linux/mod_devicetable.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/platform_device.h>
-#include <linux/property.h>
-#include <linux/pwm.h>
-
-struct pwm_led {
-       struct pwm_device *pwm;
-       struct pwm_state state;
-};
-
-struct pwm_mc_led {
-       struct led_classdev_mc mc_cdev;
-       struct mutex lock;
-       struct pwm_led leds[];
-};
-
-static int led_pwm_mc_set(struct led_classdev *cdev,
-                         enum led_brightness brightness)
-{
-       struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(cdev);
-       struct pwm_mc_led *priv = container_of(mc_cdev, struct pwm_mc_led, mc_cdev);
-       unsigned long long duty;
-       int ret = 0;
-       int i;
-
-       led_mc_calc_color_components(mc_cdev, brightness);
-
-       mutex_lock(&priv->lock);
-
-       for (i = 0; i < mc_cdev->num_colors; i++) {
-               duty = priv->leds[i].state.period;
-               duty *= mc_cdev->subled_info[i].brightness;
-               do_div(duty, cdev->max_brightness);
-
-               priv->leds[i].state.duty_cycle = duty;
-               priv->leds[i].state.enabled = duty > 0;
-               ret = pwm_apply_state(priv->leds[i].pwm,
-                                     &priv->leds[i].state);
-               if (ret)
-                       break;
-       }
-
-       mutex_unlock(&priv->lock);
-
-       return ret;
-}
-
-static int iterate_subleds(struct device *dev, struct pwm_mc_led *priv,
-                          struct fwnode_handle *mcnode)
-{
-       struct mc_subled *subled = priv->mc_cdev.subled_info;
-       struct fwnode_handle *fwnode;
-       struct pwm_led *pwmled;
-       u32 color;
-       int ret;
-
-       /* iterate over the nodes inside the multi-led node */
-       fwnode_for_each_child_node(mcnode, fwnode) {
-               pwmled = &priv->leds[priv->mc_cdev.num_colors];
-               pwmled->pwm = devm_fwnode_pwm_get(dev, fwnode, NULL);
-               if (IS_ERR(pwmled->pwm)) {
-                       ret = PTR_ERR(pwmled->pwm);
-                       dev_err(dev, "unable to request PWM: %d\n", ret);
-                       goto release_fwnode;
-               }
-               pwm_init_state(pwmled->pwm, &pwmled->state);
-
-               ret = fwnode_property_read_u32(fwnode, "color", &color);
-               if (ret) {
-                       dev_err(dev, "cannot read color: %d\n", ret);
-                       goto release_fwnode;
-               }
-
-               subled[priv->mc_cdev.num_colors].color_index = color;
-               priv->mc_cdev.num_colors++;
-       }
-
-       return 0;
-
-release_fwnode:
-       fwnode_handle_put(fwnode);
-       return ret;
-}
-
-static int led_pwm_mc_probe(struct platform_device *pdev)
-{
-       struct fwnode_handle *mcnode, *fwnode;
-       struct led_init_data init_data = {};
-       struct led_classdev *cdev;
-       struct mc_subled *subled;
-       struct pwm_mc_led *priv;
-       int count = 0;
-       int ret = 0;
-
-       mcnode = device_get_named_child_node(&pdev->dev, "multi-led");
-       if (!mcnode)
-               return dev_err_probe(&pdev->dev, -ENODEV,
-                                    "expected multi-led node\n");
-
-       /* count the nodes inside the multi-led node */
-       fwnode_for_each_child_node(mcnode, fwnode)
-               count++;
-
-       priv = devm_kzalloc(&pdev->dev, struct_size(priv, leds, count),
-                           GFP_KERNEL);
-       if (!priv) {
-               ret = -ENOMEM;
-               goto release_mcnode;
-       }
-       mutex_init(&priv->lock);
-
-       subled = devm_kcalloc(&pdev->dev, count, sizeof(*subled), GFP_KERNEL);
-       if (!subled) {
-               ret = -ENOMEM;
-               goto release_mcnode;
-       }
-       priv->mc_cdev.subled_info = subled;
-
-       /* init the multicolor's LED class device */
-       cdev = &priv->mc_cdev.led_cdev;
-       fwnode_property_read_u32(mcnode, "max-brightness",
-                                &cdev->max_brightness);
-       cdev->flags = LED_CORE_SUSPENDRESUME;
-       cdev->brightness_set_blocking = led_pwm_mc_set;
-
-       ret = iterate_subleds(&pdev->dev, priv, mcnode);
-       if (ret)
-               goto release_mcnode;
-
-       init_data.fwnode = mcnode;
-       ret = devm_led_classdev_multicolor_register_ext(&pdev->dev,
-                                                       &priv->mc_cdev,
-                                                       &init_data);
-       if (ret) {
-               dev_err(&pdev->dev,
-                       "failed to register multicolor PWM led for %s: %d\n",
-                       cdev->name, ret);
-               goto release_mcnode;
-       }
-
-       ret = led_pwm_mc_set(cdev, cdev->brightness);
-       if (ret)
-               return dev_err_probe(&pdev->dev, ret,
-                                    "failed to set led PWM value for %s: %d",
-                                    cdev->name, ret);
-
-       platform_set_drvdata(pdev, priv);
-       return 0;
-
-release_mcnode:
-       fwnode_handle_put(mcnode);
-       return ret;
-}
-
-static const struct of_device_id of_pwm_leds_mc_match[] = {
-       { .compatible = "pwm-leds-multicolor", },
-       {}
-};
-MODULE_DEVICE_TABLE(of, of_pwm_leds_mc_match);
-
-static struct platform_driver led_pwm_mc_driver = {
-       .probe          = led_pwm_mc_probe,
-       .driver         = {
-               .name   = "leds_pwm_multicolor",
-               .of_match_table = of_pwm_leds_mc_match,
-       },
-};
-module_platform_driver(led_pwm_mc_driver);
-
-MODULE_AUTHOR("Sven Schwermer <sven.schwermer@disruptive-technologies.com>");
-MODULE_DESCRIPTION("multi-color PWM LED driver");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:leds-pwm-multicolor");
index 5dd27ad808562f917fbd61fd17c36b2648506e63..63fd40b257ec50f52eff52633af899a078a56213 100644 (file)
@@ -2,6 +2,16 @@
 
 if LEDS_CLASS_MULTICOLOR
 
+config LEDS_PWM_MULTICOLOR
+       tristate "PWM driven multi-color LED Support"
+       depends on PWM
+       help
+         This option enables support for PWM driven monochrome LEDs that are
+         grouped into multicolor LEDs.
+
+         To compile this driver as a module, choose M here: the module
+         will be called leds-pwm-multicolor.
+
 config LEDS_QCOM_LPG
        tristate "LED support for Qualcomm LPG"
        depends on OF
index 83114f44c4eaec404f74e0239a759555385e0f7d..0675bc0f6e18f87f5022ac245cb0b7769d5037b9 100644 (file)
@@ -1,3 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0
 
-obj-$(CONFIG_LEDS_QCOM_LPG)    += leds-qcom-lpg.o
+obj-$(CONFIG_LEDS_PWM_MULTICOLOR)      += leds-pwm-multicolor.o
+obj-$(CONFIG_LEDS_QCOM_LPG)            += leds-qcom-lpg.o
diff --git a/drivers/leds/rgb/leds-pwm-multicolor.c b/drivers/leds/rgb/leds-pwm-multicolor.c
new file mode 100644 (file)
index 0000000..45e3870
--- /dev/null
@@ -0,0 +1,186 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * PWM-based multi-color LED control
+ *
+ * Copyright 2022 Sven Schwermer <sven.schwermer@disruptive-technologies.com>
+ */
+
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/led-class-multicolor.h>
+#include <linux/leds.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/pwm.h>
+
+struct pwm_led {
+       struct pwm_device *pwm;
+       struct pwm_state state;
+};
+
+struct pwm_mc_led {
+       struct led_classdev_mc mc_cdev;
+       struct mutex lock;
+       struct pwm_led leds[];
+};
+
+static int led_pwm_mc_set(struct led_classdev *cdev,
+                         enum led_brightness brightness)
+{
+       struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(cdev);
+       struct pwm_mc_led *priv = container_of(mc_cdev, struct pwm_mc_led, mc_cdev);
+       unsigned long long duty;
+       int ret = 0;
+       int i;
+
+       led_mc_calc_color_components(mc_cdev, brightness);
+
+       mutex_lock(&priv->lock);
+
+       for (i = 0; i < mc_cdev->num_colors; i++) {
+               duty = priv->leds[i].state.period;
+               duty *= mc_cdev->subled_info[i].brightness;
+               do_div(duty, cdev->max_brightness);
+
+               priv->leds[i].state.duty_cycle = duty;
+               priv->leds[i].state.enabled = duty > 0;
+               ret = pwm_apply_state(priv->leds[i].pwm,
+                                     &priv->leds[i].state);
+               if (ret)
+                       break;
+       }
+
+       mutex_unlock(&priv->lock);
+
+       return ret;
+}
+
+static int iterate_subleds(struct device *dev, struct pwm_mc_led *priv,
+                          struct fwnode_handle *mcnode)
+{
+       struct mc_subled *subled = priv->mc_cdev.subled_info;
+       struct fwnode_handle *fwnode;
+       struct pwm_led *pwmled;
+       u32 color;
+       int ret;
+
+       /* iterate over the nodes inside the multi-led node */
+       fwnode_for_each_child_node(mcnode, fwnode) {
+               pwmled = &priv->leds[priv->mc_cdev.num_colors];
+               pwmled->pwm = devm_fwnode_pwm_get(dev, fwnode, NULL);
+               if (IS_ERR(pwmled->pwm)) {
+                       ret = PTR_ERR(pwmled->pwm);
+                       dev_err(dev, "unable to request PWM: %d\n", ret);
+                       goto release_fwnode;
+               }
+               pwm_init_state(pwmled->pwm, &pwmled->state);
+
+               ret = fwnode_property_read_u32(fwnode, "color", &color);
+               if (ret) {
+                       dev_err(dev, "cannot read color: %d\n", ret);
+                       goto release_fwnode;
+               }
+
+               subled[priv->mc_cdev.num_colors].color_index = color;
+               priv->mc_cdev.num_colors++;
+       }
+
+       return 0;
+
+release_fwnode:
+       fwnode_handle_put(fwnode);
+       return ret;
+}
+
+static int led_pwm_mc_probe(struct platform_device *pdev)
+{
+       struct fwnode_handle *mcnode, *fwnode;
+       struct led_init_data init_data = {};
+       struct led_classdev *cdev;
+       struct mc_subled *subled;
+       struct pwm_mc_led *priv;
+       int count = 0;
+       int ret = 0;
+
+       mcnode = device_get_named_child_node(&pdev->dev, "multi-led");
+       if (!mcnode)
+               return dev_err_probe(&pdev->dev, -ENODEV,
+                                    "expected multi-led node\n");
+
+       /* count the nodes inside the multi-led node */
+       fwnode_for_each_child_node(mcnode, fwnode)
+               count++;
+
+       priv = devm_kzalloc(&pdev->dev, struct_size(priv, leds, count),
+                           GFP_KERNEL);
+       if (!priv) {
+               ret = -ENOMEM;
+               goto release_mcnode;
+       }
+       mutex_init(&priv->lock);
+
+       subled = devm_kcalloc(&pdev->dev, count, sizeof(*subled), GFP_KERNEL);
+       if (!subled) {
+               ret = -ENOMEM;
+               goto release_mcnode;
+       }
+       priv->mc_cdev.subled_info = subled;
+
+       /* init the multicolor's LED class device */
+       cdev = &priv->mc_cdev.led_cdev;
+       fwnode_property_read_u32(mcnode, "max-brightness",
+                                &cdev->max_brightness);
+       cdev->flags = LED_CORE_SUSPENDRESUME;
+       cdev->brightness_set_blocking = led_pwm_mc_set;
+
+       ret = iterate_subleds(&pdev->dev, priv, mcnode);
+       if (ret)
+               goto release_mcnode;
+
+       init_data.fwnode = mcnode;
+       ret = devm_led_classdev_multicolor_register_ext(&pdev->dev,
+                                                       &priv->mc_cdev,
+                                                       &init_data);
+       if (ret) {
+               dev_err(&pdev->dev,
+                       "failed to register multicolor PWM led for %s: %d\n",
+                       cdev->name, ret);
+               goto release_mcnode;
+       }
+
+       ret = led_pwm_mc_set(cdev, cdev->brightness);
+       if (ret)
+               return dev_err_probe(&pdev->dev, ret,
+                                    "failed to set led PWM value for %s: %d",
+                                    cdev->name, ret);
+
+       platform_set_drvdata(pdev, priv);
+       return 0;
+
+release_mcnode:
+       fwnode_handle_put(mcnode);
+       return ret;
+}
+
+static const struct of_device_id of_pwm_leds_mc_match[] = {
+       { .compatible = "pwm-leds-multicolor", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, of_pwm_leds_mc_match);
+
+static struct platform_driver led_pwm_mc_driver = {
+       .probe          = led_pwm_mc_probe,
+       .driver         = {
+               .name   = "leds_pwm_multicolor",
+               .of_match_table = of_pwm_leds_mc_match,
+       },
+};
+module_platform_driver(led_pwm_mc_driver);
+
+MODULE_AUTHOR("Sven Schwermer <sven.schwermer@disruptive-technologies.com>");
+MODULE_DESCRIPTION("multi-color PWM LED driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:leds-pwm-multicolor");