From 818d03b3d4ae00eeb56687d2115a930406b2c7b3 Mon Sep 17 00:00:00 2001 From: Sven Schwermer Date: Wed, 4 May 2022 20:49:46 +0200 Subject: leds: Move pwm-multicolor driver into rgb directory The drivers/leds/rgb subdirectory is relatively fresh, so we move this new PWM multi-color driver into it. Signed-off-by: Sven Schwermer Signed-off-by: Pavel Machek --- drivers/leds/Kconfig | 11 -- drivers/leds/Makefile | 1 - drivers/leds/leds-pwm-multicolor.c | 186 --------------------------------- drivers/leds/rgb/Kconfig | 10 ++ drivers/leds/rgb/Makefile | 3 +- drivers/leds/rgb/leds-pwm-multicolor.c | 186 +++++++++++++++++++++++++++++++++ 6 files changed, 198 insertions(+), 199 deletions(-) delete mode 100644 drivers/leds/leds-pwm-multicolor.c create mode 100644 drivers/leds/rgb/leds-pwm-multicolor.c (limited to 'drivers/leds') diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index ea4481000bfe..a49979f41eee 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -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 diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index c6a147865705..4fd2f92cd198 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -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 index 45e38708ecb1..000000000000 --- a/drivers/leds/leds-pwm-multicolor.c +++ /dev/null @@ -1,186 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * PWM-based multi-color LED control - * - * Copyright 2022 Sven Schwermer - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -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 "); -MODULE_DESCRIPTION("multi-color PWM LED driver"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:leds-pwm-multicolor"); diff --git a/drivers/leds/rgb/Kconfig b/drivers/leds/rgb/Kconfig index 5dd27ad80856..63fd40b257ec 100644 --- a/drivers/leds/rgb/Kconfig +++ b/drivers/leds/rgb/Kconfig @@ -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 diff --git a/drivers/leds/rgb/Makefile b/drivers/leds/rgb/Makefile index 83114f44c4ea..0675bc0f6e18 100644 --- a/drivers/leds/rgb/Makefile +++ b/drivers/leds/rgb/Makefile @@ -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 index 000000000000..45e38708ecb1 --- /dev/null +++ b/drivers/leds/rgb/leds-pwm-multicolor.c @@ -0,0 +1,186 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * PWM-based multi-color LED control + * + * Copyright 2022 Sven Schwermer + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 "); +MODULE_DESCRIPTION("multi-color PWM LED driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:leds-pwm-multicolor"); -- cgit v1.2.3