diff options
Diffstat (limited to 'drivers/leds/rgb')
-rw-r--r-- | drivers/leds/rgb/Kconfig | 1 | ||||
-rw-r--r-- | drivers/leds/rgb/leds-group-multicolor.c | 2 | ||||
-rw-r--r-- | drivers/leds/rgb/leds-ktd202x.c | 82 | ||||
-rw-r--r-- | drivers/leds/rgb/leds-mt6370-rgb.c | 42 | ||||
-rw-r--r-- | drivers/leds/rgb/leds-ncp5623.c | 16 | ||||
-rw-r--r-- | drivers/leds/rgb/leds-pwm-multicolor.c | 8 | ||||
-rw-r--r-- | drivers/leds/rgb/leds-qcom-lpg.c | 30 |
7 files changed, 94 insertions, 87 deletions
diff --git a/drivers/leds/rgb/Kconfig b/drivers/leds/rgb/Kconfig index 8fc12d6a2958..222d943d826a 100644 --- a/drivers/leds/rgb/Kconfig +++ b/drivers/leds/rgb/Kconfig @@ -17,7 +17,6 @@ config LEDS_GROUP_MULTICOLOR config LEDS_KTD202X tristate "LED support for KTD202x Chips" depends on I2C - depends on OF select REGMAP_I2C help This option enables support for the Kinetic KTD2026/KTD2027 diff --git a/drivers/leds/rgb/leds-group-multicolor.c b/drivers/leds/rgb/leds-group-multicolor.c index b6c7679015fd..548c7dd63ba1 100644 --- a/drivers/leds/rgb/leds-group-multicolor.c +++ b/drivers/leds/rgb/leds-group-multicolor.c @@ -55,7 +55,7 @@ static void restore_sysfs_write_access(void *data) { struct led_classdev *led_cdev = data; - /* Restore the write acccess to the LED */ + /* Restore the write access to the LED */ mutex_lock(&led_cdev->led_access); led_sysfs_enable(led_cdev); mutex_unlock(&led_cdev->led_access); diff --git a/drivers/leds/rgb/leds-ktd202x.c b/drivers/leds/rgb/leds-ktd202x.c index 514965795a10..04e62faa3a00 100644 --- a/drivers/leds/rgb/leds-ktd202x.c +++ b/drivers/leds/rgb/leds-ktd202x.c @@ -99,7 +99,7 @@ struct ktd202x { struct device *dev; struct regmap *regmap; bool enabled; - int num_leds; + unsigned long num_leds; struct ktd202x_led leds[] __counted_by(num_leds); }; @@ -381,16 +381,19 @@ static int ktd202x_blink_mc_set(struct led_classdev *cdev, mc->num_colors); } -static int ktd202x_setup_led_rgb(struct ktd202x *chip, struct device_node *np, +static int ktd202x_setup_led_rgb(struct ktd202x *chip, struct fwnode_handle *fwnode, struct ktd202x_led *led, struct led_init_data *init_data) { + struct fwnode_handle *child; struct led_classdev *cdev; - struct device_node *child; struct mc_subled *info; int num_channels; int i = 0; - num_channels = of_get_available_child_count(np); + num_channels = 0; + fwnode_for_each_available_child_node(fwnode, child) + num_channels++; + if (!num_channels || num_channels > chip->num_leds) return -EINVAL; @@ -398,22 +401,22 @@ static int ktd202x_setup_led_rgb(struct ktd202x *chip, struct device_node *np, if (!info) return -ENOMEM; - for_each_available_child_of_node(np, child) { + fwnode_for_each_available_child_node(fwnode, child) { u32 mono_color; u32 reg; int ret; - ret = of_property_read_u32(child, "reg", ®); + ret = fwnode_property_read_u32(child, "reg", ®); if (ret != 0 || reg >= chip->num_leds) { - dev_err(chip->dev, "invalid 'reg' of %pOFn\n", child); - of_node_put(child); - return -EINVAL; + dev_err(chip->dev, "invalid 'reg' of %pfw\n", child); + fwnode_handle_put(child); + return ret; } - ret = of_property_read_u32(child, "color", &mono_color); + ret = fwnode_property_read_u32(child, "color", &mono_color); if (ret < 0 && ret != -EINVAL) { - dev_err(chip->dev, "failed to parse 'color' of %pOF\n", child); - of_node_put(child); + dev_err(chip->dev, "failed to parse 'color' of %pfw\n", child); + fwnode_handle_put(child); return ret; } @@ -433,16 +436,16 @@ static int ktd202x_setup_led_rgb(struct ktd202x *chip, struct device_node *np, return devm_led_classdev_multicolor_register_ext(chip->dev, &led->mcdev, init_data); } -static int ktd202x_setup_led_single(struct ktd202x *chip, struct device_node *np, +static int ktd202x_setup_led_single(struct ktd202x *chip, struct fwnode_handle *fwnode, struct ktd202x_led *led, struct led_init_data *init_data) { struct led_classdev *cdev; u32 reg; int ret; - ret = of_property_read_u32(np, "reg", ®); + ret = fwnode_property_read_u32(fwnode, "reg", ®); if (ret != 0 || reg >= chip->num_leds) { - dev_err(chip->dev, "invalid 'reg' of %pOFn\n", np); + dev_err(chip->dev, "invalid 'reg' of %pfw\n", fwnode); return -EINVAL; } led->index = reg; @@ -454,7 +457,7 @@ static int ktd202x_setup_led_single(struct ktd202x *chip, struct device_node *np return devm_led_classdev_register_ext(chip->dev, &led->cdev, init_data); } -static int ktd202x_add_led(struct ktd202x *chip, struct device_node *np, unsigned int index) +static int ktd202x_add_led(struct ktd202x *chip, struct fwnode_handle *fwnode, unsigned int index) { struct ktd202x_led *led = &chip->leds[index]; struct led_init_data init_data = {}; @@ -463,21 +466,21 @@ static int ktd202x_add_led(struct ktd202x *chip, struct device_node *np, unsigne int ret; /* Color property is optional in single color case */ - ret = of_property_read_u32(np, "color", &color); + ret = fwnode_property_read_u32(fwnode, "color", &color); if (ret < 0 && ret != -EINVAL) { - dev_err(chip->dev, "failed to parse 'color' of %pOF\n", np); + dev_err(chip->dev, "failed to parse 'color' of %pfw\n", fwnode); return ret; } led->chip = chip; - init_data.fwnode = of_fwnode_handle(np); + init_data.fwnode = fwnode; if (color == LED_COLOR_ID_RGB) { cdev = &led->mcdev.led_cdev; - ret = ktd202x_setup_led_rgb(chip, np, led, &init_data); + ret = ktd202x_setup_led_rgb(chip, fwnode, led, &init_data); } else { cdev = &led->cdev; - ret = ktd202x_setup_led_single(chip, np, led, &init_data); + ret = ktd202x_setup_led_single(chip, fwnode, led, &init_data); } if (ret) { @@ -490,15 +493,13 @@ static int ktd202x_add_led(struct ktd202x *chip, struct device_node *np, unsigne return 0; } -static int ktd202x_probe_dt(struct ktd202x *chip) +static int ktd202x_probe_fw(struct ktd202x *chip) { - struct device_node *np = dev_of_node(chip->dev), *child; + struct device *dev = chip->dev; int count; int i = 0; - chip->num_leds = (int)(unsigned long)of_device_get_match_data(chip->dev); - - count = of_get_available_child_count(np); + count = device_get_child_node_count(dev); if (!count || count > chip->num_leds) return -EINVAL; @@ -507,13 +508,12 @@ static int ktd202x_probe_dt(struct ktd202x *chip) /* Allow the device to execute the complete reset */ usleep_range(200, 300); - for_each_available_child_of_node(np, child) { + device_for_each_child_node_scoped(dev, child) { int ret = ktd202x_add_led(chip, child, i); - if (ret) { - of_node_put(child); + if (ret) return ret; - } + i++; } @@ -554,6 +554,12 @@ static int ktd202x_probe(struct i2c_client *client) return ret; } + ret = devm_mutex_init(dev, &chip->mutex); + if (ret) + return ret; + + chip->num_leds = (unsigned long)i2c_get_match_data(client); + chip->regulators[0].supply = "vin"; chip->regulators[1].supply = "vio"; ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(chip->regulators), chip->regulators); @@ -568,7 +574,7 @@ static int ktd202x_probe(struct i2c_client *client) return ret; } - ret = ktd202x_probe_dt(chip); + ret = ktd202x_probe_fw(chip); if (ret < 0) { regulator_bulk_disable(ARRAY_SIZE(chip->regulators), chip->regulators); return ret; @@ -580,8 +586,6 @@ static int ktd202x_probe(struct i2c_client *client) return ret; } - mutex_init(&chip->mutex); - return 0; } @@ -590,8 +594,6 @@ static void ktd202x_remove(struct i2c_client *client) struct ktd202x *chip = i2c_get_clientdata(client); ktd202x_chip_disable(chip); - - mutex_destroy(&chip->mutex); } static void ktd202x_shutdown(struct i2c_client *client) @@ -602,10 +604,17 @@ static void ktd202x_shutdown(struct i2c_client *client) regmap_write(chip->regmap, KTD202X_REG_RESET_CONTROL, KTD202X_RSTR_RESET); } +static const struct i2c_device_id ktd202x_id[] = { + {"ktd2026", KTD2026_NUM_LEDS}, + {"ktd2027", KTD2027_NUM_LEDS}, + {} +}; +MODULE_DEVICE_TABLE(i2c, ktd202x_id); + static const struct of_device_id ktd202x_match_table[] = { { .compatible = "kinetic,ktd2026", .data = (void *)KTD2026_NUM_LEDS }, { .compatible = "kinetic,ktd2027", .data = (void *)KTD2027_NUM_LEDS }, - {}, + {} }; MODULE_DEVICE_TABLE(of, ktd202x_match_table); @@ -617,6 +626,7 @@ static struct i2c_driver ktd202x_driver = { .probe = ktd202x_probe, .remove = ktd202x_remove, .shutdown = ktd202x_shutdown, + .id_table = ktd202x_id, }; module_i2c_driver(ktd202x_driver); diff --git a/drivers/leds/rgb/leds-mt6370-rgb.c b/drivers/leds/rgb/leds-mt6370-rgb.c index 448d0da11848..ebd3ba878dd5 100644 --- a/drivers/leds/rgb/leds-mt6370-rgb.c +++ b/drivers/leds/rgb/leds-mt6370-rgb.c @@ -21,7 +21,7 @@ #include <linux/regmap.h> #include <linux/util_macros.h> -#include <asm/unaligned.h> +#include <linux/unaligned.h> enum { MT6370_LED_ISNK1 = 0, @@ -149,7 +149,6 @@ struct mt6370_priv { struct regmap_field *fields[F_MAX_FIELDS]; const struct reg_field *reg_fields; const struct linear_range *ranges; - struct reg_cfg *reg_cfgs; const struct mt6370_pdata *pdata; unsigned int leds_count; unsigned int leds_active; @@ -588,7 +587,7 @@ static inline int mt6370_mc_pattern_clear(struct led_classdev *lcdev) struct mt6370_led *led = container_of(mccdev, struct mt6370_led, mc); struct mt6370_priv *priv = led->priv; struct mc_subled *subled; - int i, ret; + int i, ret = 0; mutex_lock(&led->priv->lock); @@ -906,7 +905,6 @@ static int mt6370_leds_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct mt6370_priv *priv; - struct fwnode_handle *child; size_t count; unsigned int i = 0; int ret; @@ -937,37 +935,27 @@ static int mt6370_leds_probe(struct platform_device *pdev) if (ret) return dev_err_probe(dev, ret, "Failed to allocate regmap field\n"); - device_for_each_child_node(dev, child) { + device_for_each_child_node_scoped(dev, child) { struct mt6370_led *led = priv->leds + i++; struct led_init_data init_data = { .fwnode = child }; u32 reg, color; ret = fwnode_property_read_u32(child, "reg", ®); - if (ret) { - dev_err(dev, "Failed to parse reg property\n"); - goto fwnode_release; - } + if (ret) + dev_err_probe(dev, ret, "Failed to parse reg property\n"); - if (reg >= MT6370_MAX_LEDS) { - ret = -EINVAL; - dev_err(dev, "Error reg property number\n"); - goto fwnode_release; - } + if (reg >= MT6370_MAX_LEDS) + return dev_err_probe(dev, -EINVAL, "Error reg property number\n"); ret = fwnode_property_read_u32(child, "color", &color); - if (ret) { - dev_err(dev, "Failed to parse color property\n"); - goto fwnode_release; - } + if (ret) + return dev_err_probe(dev, ret, "Failed to parse color property\n"); if (color == LED_COLOR_ID_RGB || color == LED_COLOR_ID_MULTI) reg = MT6370_VIRTUAL_MULTICOLOR; - if (priv->leds_active & BIT(reg)) { - ret = -EINVAL; - dev_err(dev, "Duplicate reg property\n"); - goto fwnode_release; - } + if (priv->leds_active & BIT(reg)) + return dev_err_probe(dev, -EINVAL, "Duplicate reg property\n"); priv->leds_active |= BIT(reg); @@ -976,18 +964,14 @@ static int mt6370_leds_probe(struct platform_device *pdev) ret = mt6370_init_led_properties(dev, led, &init_data); if (ret) - goto fwnode_release; + return ret; ret = mt6370_led_register(dev, led, &init_data); if (ret) - goto fwnode_release; + return ret; } return 0; - -fwnode_release: - fwnode_handle_put(child); - return ret; } static const struct of_device_id mt6370_rgbled_device_table[] = { diff --git a/drivers/leds/rgb/leds-ncp5623.c b/drivers/leds/rgb/leds-ncp5623.c index 2be4ff918516..f18156683375 100644 --- a/drivers/leds/rgb/leds-ncp5623.c +++ b/drivers/leds/rgb/leds-ncp5623.c @@ -183,16 +183,12 @@ static int ncp5623_probe(struct i2c_client *client) fwnode_for_each_available_child_node(mc_node, led_node) { ret = fwnode_property_read_u32(led_node, "color", &color_index); - if (ret) { - fwnode_handle_put(led_node); - goto release_mc_node; - } + if (ret) + goto release_led_node; ret = fwnode_property_read_u32(led_node, "reg", ®); - if (ret) { - fwnode_handle_put(led_node); - goto release_mc_node; - } + if (ret) + goto release_led_node; subled_info[ncp->mc_dev.num_colors].channel = reg; subled_info[ncp->mc_dev.num_colors++].color_index = color_index; @@ -223,6 +219,10 @@ release_mc_node: fwnode_handle_put(mc_node); return ret; + +release_led_node: + fwnode_handle_put(led_node); + goto release_mc_node; } static void ncp5623_remove(struct i2c_client *client) diff --git a/drivers/leds/rgb/leds-pwm-multicolor.c b/drivers/leds/rgb/leds-pwm-multicolor.c index e1a81e0109e8..f80a06cc31f8 100644 --- a/drivers/leds/rgb/leds-pwm-multicolor.c +++ b/drivers/leds/rgb/leds-pwm-multicolor.c @@ -50,7 +50,13 @@ static int led_pwm_mc_set(struct led_classdev *cdev, duty = priv->leds[i].state.period - duty; priv->leds[i].state.duty_cycle = duty; - priv->leds[i].state.enabled = duty > 0; + /* + * Disabling a PWM doesn't guarantee that it emits the inactive level. + * So keep it on. Only for suspending the PWM should be disabled because + * otherwise it refuses to suspend. The possible downside is that the + * LED might stay (or even go) on. + */ + priv->leds[i].state.enabled = !(cdev->flags & LED_SUSPENDED); ret = pwm_apply_might_sleep(priv->leds[i].pwm, &priv->leds[i].state); if (ret) diff --git a/drivers/leds/rgb/leds-qcom-lpg.c b/drivers/leds/rgb/leds-qcom-lpg.c index 6bdc5b923f98..f3c9ef2bfa57 100644 --- a/drivers/leds/rgb/leds-qcom-lpg.c +++ b/drivers/leds/rgb/leds-qcom-lpg.c @@ -2,7 +2,7 @@ /* * Copyright (c) 2017-2022 Linaro Ltd * Copyright (c) 2010-2012, The Linux Foundation. All rights reserved. - * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2023-2024, Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/bits.h> #include <linux/bitfield.h> @@ -254,6 +254,9 @@ static int lpg_clear_pbs_trigger(struct lpg *lpg, unsigned int lut_mask) u8 val = 0; int rc; + if (!lpg->lpg_chan_sdam) + return 0; + lpg->pbs_en_bitmap &= (~lut_mask); if (!lpg->pbs_en_bitmap) { rc = nvmem_device_write(lpg->lpg_chan_sdam, SDAM_REG_PBS_SEQ_EN, 1, &val); @@ -276,6 +279,9 @@ static int lpg_set_pbs_trigger(struct lpg *lpg, unsigned int lut_mask) u8 val = PBS_SW_TRIG_BIT; int rc; + if (!lpg->lpg_chan_sdam) + return 0; + if (!lpg->pbs_en_bitmap) { rc = nvmem_device_write(lpg->lpg_chan_sdam, SDAM_REG_PBS_SEQ_EN, 1, &val); if (rc < 0) @@ -1362,7 +1368,6 @@ static int lpg_add_led(struct lpg *lpg, struct device_node *np) { struct led_init_data init_data = {}; struct led_classdev *cdev; - struct device_node *child; struct mc_subled *info; struct lpg_led *led; const char *state; @@ -1393,12 +1398,10 @@ static int lpg_add_led(struct lpg *lpg, struct device_node *np) if (!info) return -ENOMEM; i = 0; - for_each_available_child_of_node(np, child) { + for_each_available_child_of_node_scoped(np, child) { ret = lpg_parse_channel(lpg, child, &led->channels[i]); - if (ret < 0) { - of_node_put(child); + if (ret < 0) return ret; - } info[i].color_index = led->channels[i]->color; info[i].intensity = 0; @@ -1594,7 +1597,6 @@ static int lpg_init_sdam(struct lpg *lpg) static int lpg_probe(struct platform_device *pdev) { - struct device_node *np; struct lpg *lpg; int ret; int i; @@ -1634,12 +1636,10 @@ static int lpg_probe(struct platform_device *pdev) if (ret < 0) return ret; - for_each_available_child_of_node(pdev->dev.of_node, np) { + for_each_available_child_of_node_scoped(pdev->dev.of_node, np) { ret = lpg_add_led(lpg, np); - if (ret) { - of_node_put(np); + if (ret) return ret; - } } for (i = 0; i < lpg->num_channels; i++) @@ -1693,6 +1693,13 @@ static const struct lpg_data pm8941_lpg_data = { }, }; +static const struct lpg_data pmi8950_pwm_data = { + .num_channels = 1, + .channels = (const struct lpg_channel_data[]) { + { .base = 0xb000 }, + }, +}; + static const struct lpg_data pm8994_lpg_data = { .lut_base = 0xb000, .lut_size = 64, @@ -1819,6 +1826,7 @@ static const struct of_device_id lpg_of_table[] = { { .compatible = "qcom,pm8941-lpg", .data = &pm8941_lpg_data }, { .compatible = "qcom,pm8994-lpg", .data = &pm8994_lpg_data }, { .compatible = "qcom,pmi632-lpg", .data = &pmi632_lpg_data }, + { .compatible = "qcom,pmi8950-pwm", .data = &pmi8950_pwm_data }, { .compatible = "qcom,pmi8994-lpg", .data = &pmi8994_lpg_data }, { .compatible = "qcom,pmi8998-lpg", .data = &pmi8998_lpg_data }, { .compatible = "qcom,pmc8180c-lpg", .data = &pm8150l_lpg_data }, |