mirror of
https://github.com/Dasharo/linux.git
synced 2026-03-06 15:25:10 -08:00
Merge tag 'leds-next-6.12' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/leds
Pull LED updates from Lee Jones: - Limited LED current based on thermal conditions in the QCOM flash LED driver - Fixed device child node usage in the BD2606MVV and PCA995x drivers - Used device_for_each_child_node_scoped() to access child nodes in the IS31FL319X driver - Reset the LED controller during the probe in the LM3601X driver - Used device_for_each_child_node() to access device child nodes in the PCA995X driver - Fixed CONFIG_LEDS_CLASS_MULTICOLOR dependency in the BlinkM driver - Replaced msleep() with usleep_range() in the SUN50I-A100 driver - Used scoped device node handling to simplify error paths in the AAT1290, KTD2692, and MC13783 drivers - Added missing of_node_get for probe duration in the MAX77693 driver - Simplified using for_each_available_child_of_node_scoped() loops when iterating over device nodes - Used devm_clk_get_enabled() helpers in the LP55XX driver - Converted DT bindings from TXT to YAML format for various drivers, including LM3692x and SC2731-BLTC - Set num_leds after allocation in the GPIO driver - Removed irrelevant blink configuration error message in the PCA9532 driver - Fixed module autoloading with MODULE_DEVICE_TABLE() in the Turris Omnia driver * tag 'leds-next-6.12' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/leds: (38 commits) leds: turris-omnia: Fix module autoloading with MODULE_DEVICE_TABLE() leds: pca9532: Remove irrelevant blink configuration error message leds: gpio: Set num_leds after allocation dt-bindings: leds: Convert leds-lm3692x to YAML format leds: lp55xx: Use devm_clk_get_enabled() helpers leds: as3645a: Use device_* to iterate over device child nodes leds: qcom-lpg: Simplify with scoped for each OF child loop leds: turris-omnia: Simplify with scoped for each OF child loop leds: sc27xx: Simplify with scoped for each OF child loop leds: pca9532: Simplify with scoped for each OF child loop leds: netxbig: Simplify with scoped for each OF child loop leds: mt6323: Simplify with scoped for each OF child loop leds: mc13783: Use scoped device node handling to simplify error paths leds: lp55xx: Simplify with scoped for each OF child loop leds: is31fl32xx: Simplify with scoped for each OF child loop leds: bcm6358: Simplify with scoped for each OF child loop leds: bcm6328: Simplify with scoped for each OF child loop leds: aw2013: Simplify with scoped for each OF child loop leds: 88pm860x: Simplify with scoped for each OF child loop leds: max77693: Simplify with scoped for each OF child loop ...
This commit is contained in:
@@ -113,6 +113,8 @@ properties:
|
||||
# LED indicates NAND memory activity (deprecated),
|
||||
# in new implementations use "mtd"
|
||||
- nand-disk
|
||||
# LED indicates network activity
|
||||
- netdev
|
||||
# No trigger assigned to the LED. This is the default mode
|
||||
# if trigger is absent
|
||||
- none
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
* Texas Instruments - LM3692x Highly Efficient White LED Driver
|
||||
|
||||
The LM3692x is an ultra-compact, highly efficient,
|
||||
white-LED driver designed for LCD display backlighting.
|
||||
|
||||
The main difference between the LM36922 and LM36923 is the number of
|
||||
LED strings it supports. The LM36922 supports two strings while the LM36923
|
||||
supports three strings.
|
||||
|
||||
Required properties:
|
||||
- compatible:
|
||||
"ti,lm36922"
|
||||
"ti,lm36923"
|
||||
- reg : I2C slave address
|
||||
- #address-cells : 1
|
||||
- #size-cells : 0
|
||||
|
||||
Optional properties:
|
||||
- enable-gpios : gpio pin to enable/disable the device.
|
||||
- vled-supply : LED supply
|
||||
- ti,ovp-microvolt: Overvoltage protection in
|
||||
micro-volt, can be 17000000, 21000000, 25000000 or
|
||||
29000000. If ti,ovp-microvolt is not specified it
|
||||
defaults to 29000000.
|
||||
|
||||
Required child properties:
|
||||
- reg : 0 - Will enable all LED sync paths
|
||||
1 - Will enable the LED1 sync
|
||||
2 - Will enable the LED2 sync
|
||||
3 - Will enable the LED3 sync (LM36923 only)
|
||||
|
||||
Optional child properties:
|
||||
- function : see Documentation/devicetree/bindings/leds/common.txt
|
||||
- color : see Documentation/devicetree/bindings/leds/common.txt
|
||||
- label : see Documentation/devicetree/bindings/leds/common.txt (deprecated)
|
||||
- linux,default-trigger :
|
||||
see Documentation/devicetree/bindings/leds/common.txt
|
||||
- led-max-microamp :
|
||||
see Documentation/devicetree/bindings/leds/common.txt
|
||||
|
||||
Example:
|
||||
|
||||
#include <dt-bindings/leds/common.h>
|
||||
|
||||
led-controller@36 {
|
||||
compatible = "ti,lm3692x";
|
||||
reg = <0x36>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
enable-gpios = <&gpio1 28 GPIO_ACTIVE_HIGH>;
|
||||
vled-supply = <&vbatt>;
|
||||
ti,ovp-microvolt = <29000000>;
|
||||
|
||||
led@0 {
|
||||
reg = <0>;
|
||||
function = LED_FUNCTION_BACKLIGHT;
|
||||
color = <LED_COLOR_ID_WHITE>;
|
||||
linux,default-trigger = "backlight";
|
||||
led-max-microamp = <20000>;
|
||||
};
|
||||
}
|
||||
|
||||
For more product information please see the link below:
|
||||
https://www.ti.com/lit/ds/snvsa29/snvsa29.pdf
|
||||
@@ -1,43 +0,0 @@
|
||||
LEDs connected to Spreadtrum SC27XX PMIC breathing light controller
|
||||
|
||||
The SC27xx breathing light controller supports to 3 outputs:
|
||||
red LED, green LED and blue LED. Each LED can work at normal
|
||||
PWM mode or breath light mode.
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "sprd,sc2731-bltc".
|
||||
- #address-cells: Must be 1.
|
||||
- #size-cells: Must be 0.
|
||||
- reg: Specify the controller address.
|
||||
|
||||
Required child properties:
|
||||
- reg: Port this LED is connected to.
|
||||
|
||||
Optional child properties:
|
||||
- function: See Documentation/devicetree/bindings/leds/common.txt.
|
||||
- color: See Documentation/devicetree/bindings/leds/common.txt.
|
||||
- label: See Documentation/devicetree/bindings/leds/common.txt (deprecated).
|
||||
|
||||
Examples:
|
||||
|
||||
led-controller@200 {
|
||||
compatible = "sprd,sc2731-bltc";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0x200>;
|
||||
|
||||
led@0 {
|
||||
color = <LED_COLOR_ID_RED>;
|
||||
reg = <0x0>;
|
||||
};
|
||||
|
||||
led@1 {
|
||||
color = <LED_COLOR_ID_GREEN>;
|
||||
reg = <0x1>;
|
||||
};
|
||||
|
||||
led@2 {
|
||||
color = <LED_COLOR_ID_BLUE>;
|
||||
reg = <0x2>;
|
||||
};
|
||||
};
|
||||
@@ -11,19 +11,21 @@ maintainers:
|
||||
- Marek Vasut <marex@denx.de>
|
||||
|
||||
description:
|
||||
The NXP PCA9952/PCA9955B are programmable LED controllers connected via I2C
|
||||
that can drive 16 separate lines. Each of them can be individually switched
|
||||
The NXP PCA995x family are programmable LED controllers connected via I2C
|
||||
that can drive separate lines. Each of them can be individually switched
|
||||
on and off, and brightness can be controlled via individual PWM.
|
||||
|
||||
Datasheets are available at
|
||||
https://www.nxp.com/docs/en/data-sheet/PCA9952_PCA9955.pdf
|
||||
https://www.nxp.com/docs/en/data-sheet/PCA9955B.pdf
|
||||
https://www.nxp.com/docs/en/data-sheet/PCA9956B.pdf
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- nxp,pca9952
|
||||
- nxp,pca9955b
|
||||
- nxp,pca9956b
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
84
Documentation/devicetree/bindings/leds/sprd,sc2731-bltc.yaml
Normal file
84
Documentation/devicetree/bindings/leds/sprd,sc2731-bltc.yaml
Normal file
@@ -0,0 +1,84 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/leds/sprd,sc2731-bltc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Spreadtrum SC2731 PMIC breathing light controller
|
||||
|
||||
maintainers:
|
||||
- Orson Zhai <orsonzhai@gmail.com>
|
||||
- Baolin Wang <baolin.wang7@gmail.com>
|
||||
- Chunyan Zhang <zhang.lyra@gmail.com>
|
||||
|
||||
description: |
|
||||
The SC2731 breathing light controller supports up to 3 outputs:
|
||||
red LED, green LED and blue LED. Each LED can work at normal PWM mode
|
||||
or breath light mode.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: sprd,sc2731-bltc
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
'#address-cells':
|
||||
const: 1
|
||||
|
||||
'#size-cells':
|
||||
const: 0
|
||||
|
||||
patternProperties:
|
||||
"^led@[0-2]$":
|
||||
type: object
|
||||
$ref: common.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
||||
properties:
|
||||
reg:
|
||||
minimum: 0
|
||||
maximum: 2
|
||||
|
||||
required:
|
||||
- reg
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- '#address-cells'
|
||||
- '#size-cells'
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/leds/common.h>
|
||||
|
||||
pmic {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
led-controller@200 {
|
||||
compatible = "sprd,sc2731-bltc";
|
||||
reg = <0x200>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
led@0 {
|
||||
reg = <0x0>;
|
||||
color = <LED_COLOR_ID_RED>;
|
||||
};
|
||||
|
||||
led@1 {
|
||||
reg = <0x1>;
|
||||
color = <LED_COLOR_ID_GREEN>;
|
||||
};
|
||||
|
||||
led@2 {
|
||||
reg = <0x2>;
|
||||
color = <LED_COLOR_ID_BLUE>;
|
||||
};
|
||||
};
|
||||
};
|
||||
...
|
||||
110
Documentation/devicetree/bindings/leds/ti.lm36922.yaml
Normal file
110
Documentation/devicetree/bindings/leds/ti.lm36922.yaml
Normal file
@@ -0,0 +1,110 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/leds/ti.lm36922.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Texas Instruments - LM3692x Highly Efficient White LED Driver
|
||||
|
||||
maintainers:
|
||||
- Dan Murphy <dmurphy@ti.com>
|
||||
|
||||
description: |
|
||||
The LM3692x is an ultra-compact, highly efficient,
|
||||
white-LED driver designed for LCD display backlighting.
|
||||
|
||||
The main difference between the LM36922 and LM36923 is the number of
|
||||
LED strings it supports. The LM36922 supports two strings while the LM36923
|
||||
supports three strings.
|
||||
|
||||
For more product information please see the link below:
|
||||
https://www.ti.com/lit/ds/snvsa29/snvsa29.pdf
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- ti,lm36922
|
||||
- ti,lm36923
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
"#address-cells":
|
||||
const: 1
|
||||
|
||||
"#size-cells":
|
||||
const: 0
|
||||
|
||||
enable-gpios:
|
||||
description: gpio pin to enable/disable the device.
|
||||
|
||||
vled-supply:
|
||||
description: LED supply
|
||||
|
||||
ti,ovp-microvolt:
|
||||
description: Overvoltage protection.
|
||||
default: 29000000
|
||||
enum: [17000000, 21000000, 25000000, 29000000]
|
||||
|
||||
patternProperties:
|
||||
'^led@[0-3]$':
|
||||
type: object
|
||||
$ref: common.yaml
|
||||
properties:
|
||||
reg:
|
||||
enum: [0, 1, 2, 3]
|
||||
description: |
|
||||
0 - Will enable all LED sync paths
|
||||
1 - Will enable the LED1 sync
|
||||
2 - Will enable the LED2 sync
|
||||
3 - Will enable the LED3 sync (LM36923 only)
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- "#address-cells"
|
||||
- "#size-cells"
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: ti,lm36922
|
||||
then:
|
||||
properties:
|
||||
led@3: false
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/leds/common.h>
|
||||
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
led-controller@36 {
|
||||
compatible = "ti,lm36922";
|
||||
reg = <0x36>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
enable-gpios = <&gpio1 28 GPIO_ACTIVE_HIGH>;
|
||||
vled-supply = <&vbatt>;
|
||||
ti,ovp-microvolt = <29000000>;
|
||||
|
||||
led@0 {
|
||||
reg = <0>;
|
||||
function = LED_FUNCTION_BACKLIGHT;
|
||||
color = <LED_COLOR_ID_WHITE>;
|
||||
linux,default-trigger = "backlight";
|
||||
led-max-microamp = <20000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -13,9 +13,31 @@ The device accepts RGB and HSB color values through separate commands.
|
||||
Also you can store blinking sequences as "scripts" in
|
||||
the controller and run them. Also fading is an option.
|
||||
|
||||
The interface this driver provides is 2-fold:
|
||||
The interface this driver provides is 3-fold:
|
||||
|
||||
a) LED class interface for use with triggers
|
||||
a) LED multicolor class interface for use with triggers
|
||||
#######################################################
|
||||
|
||||
The registration follows the scheme::
|
||||
|
||||
blinkm-<i2c-bus-nr>-<i2c-device-nr>:rgb:indicator
|
||||
|
||||
$ ls -h /sys/class/leds/blinkm-1-9:rgb:indicator
|
||||
brightness device max_brightness multi_index multi_intensity power subsystem trigger uevent
|
||||
|
||||
Hue is controlled by the multi_intensity file and lightness is controlled by
|
||||
the brightness file.
|
||||
|
||||
The order in which to write the intensity values can be found in multi_index.
|
||||
Exactly three values between 0 and 255 must be written to multi_intensity to
|
||||
change the color::
|
||||
|
||||
$ echo 255 100 50 > multi_intensity
|
||||
|
||||
The overall lightness be changed by writing a value between 0 and 255 to the
|
||||
brightness file.
|
||||
|
||||
b) LED class interface for use with triggers
|
||||
############################################
|
||||
|
||||
The registration follows the scheme::
|
||||
@@ -79,6 +101,7 @@ E.g.::
|
||||
|
||||
|
||||
|
||||
as of 6/2012
|
||||
as of 07/2024
|
||||
|
||||
dl9pf <at> gmx <dot> de
|
||||
jstrauss <at> mailbox <dot> org
|
||||
|
||||
@@ -72,6 +72,14 @@ Good: "platform:*:charging" (allwinner sun50i, leds-cht-wcove)
|
||||
|
||||
Good: ":backlight" (Motorola Droid 4)
|
||||
|
||||
* Indicators
|
||||
|
||||
Good: ":indicator" (Blinkm)
|
||||
|
||||
* RGB
|
||||
|
||||
Good: ":rgb" (Blinkm)
|
||||
|
||||
* Ethernet LEDs
|
||||
|
||||
Currently two types of Network LEDs are support, those controlled by
|
||||
|
||||
@@ -825,6 +825,14 @@ config LEDS_BLINKM
|
||||
This option enables support for the BlinkM RGB LED connected
|
||||
through I2C. Say Y to enable support for the BlinkM LED.
|
||||
|
||||
config LEDS_BLINKM_MULTICOLOR
|
||||
bool "Enable multicolor support for BlinkM I2C RGB LED"
|
||||
depends on LEDS_BLINKM
|
||||
depends on LEDS_CLASS_MULTICOLOR=y || LEDS_CLASS_MULTICOLOR=LEDS_BLINKM
|
||||
help
|
||||
This option enables multicolor sysfs class support for BlinkM LED and
|
||||
disables the older, separated sysfs interface
|
||||
|
||||
config LEDS_POWERNV
|
||||
tristate "LED support for PowerNV Platform"
|
||||
depends on LEDS_CLASS
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
* Author: Jacek Anaszewski <j.anaszewski@samsung.com>
|
||||
*/
|
||||
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/led-class-flash.h>
|
||||
@@ -215,7 +216,6 @@ static int aat1290_led_parse_dt(struct aat1290_led *led,
|
||||
struct device_node **sub_node)
|
||||
{
|
||||
struct device *dev = &led->pdev->dev;
|
||||
struct device_node *child_node;
|
||||
#if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS)
|
||||
struct pinctrl *pinctrl;
|
||||
#endif
|
||||
@@ -246,7 +246,8 @@ static int aat1290_led_parse_dt(struct aat1290_led *led,
|
||||
}
|
||||
#endif
|
||||
|
||||
child_node = of_get_next_available_child(dev_of_node(dev), NULL);
|
||||
struct device_node *child_node __free(device_node) =
|
||||
of_get_next_available_child(dev_of_node(dev), NULL);
|
||||
if (!child_node) {
|
||||
dev_err(dev, "No DT child node found for connected LED.\n");
|
||||
return -EINVAL;
|
||||
@@ -267,7 +268,7 @@ static int aat1290_led_parse_dt(struct aat1290_led *led,
|
||||
if (ret < 0) {
|
||||
dev_err(dev,
|
||||
"flash-max-microamp DT property missing\n");
|
||||
goto err_parse_dt;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(child_node, "flash-max-timeout-us",
|
||||
@@ -275,15 +276,12 @@ static int aat1290_led_parse_dt(struct aat1290_led *led,
|
||||
if (ret < 0) {
|
||||
dev_err(dev,
|
||||
"flash-max-timeout-us DT property missing\n");
|
||||
goto err_parse_dt;
|
||||
return ret;
|
||||
}
|
||||
|
||||
*sub_node = child_node;
|
||||
|
||||
err_parse_dt:
|
||||
of_node_put(child_node);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void aat1290_led_validate_mm_current(struct aat1290_led *led,
|
||||
|
||||
@@ -478,14 +478,12 @@ static int as3645a_detect(struct as3645a *flash)
|
||||
return as3645a_write(flash, AS_BOOST_REG, AS_BOOST_CURRENT_DISABLE);
|
||||
}
|
||||
|
||||
static int as3645a_parse_node(struct as3645a *flash,
|
||||
struct fwnode_handle *fwnode)
|
||||
static int as3645a_parse_node(struct device *dev, struct as3645a *flash)
|
||||
{
|
||||
struct as3645a_config *cfg = &flash->cfg;
|
||||
struct fwnode_handle *child;
|
||||
int rval;
|
||||
|
||||
fwnode_for_each_child_node(fwnode, child) {
|
||||
device_for_each_child_node_scoped(dev, child) {
|
||||
u32 id = 0;
|
||||
|
||||
fwnode_property_read_u32(child, "reg", &id);
|
||||
@@ -686,7 +684,7 @@ static int as3645a_probe(struct i2c_client *client)
|
||||
|
||||
flash->client = client;
|
||||
|
||||
rval = as3645a_parse_node(flash, dev_fwnode(&client->dev));
|
||||
rval = as3645a_parse_node(&client->dev, flash);
|
||||
if (rval < 0)
|
||||
return rval;
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
* Ingi Kim <ingi2.kim@samsung.com>
|
||||
*/
|
||||
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/leds-expresswire.h>
|
||||
@@ -208,7 +209,6 @@ static int ktd2692_parse_dt(struct ktd2692_context *led, struct device *dev,
|
||||
struct ktd2692_led_config_data *cfg)
|
||||
{
|
||||
struct device_node *np = dev_of_node(dev);
|
||||
struct device_node *child_node;
|
||||
int ret;
|
||||
|
||||
if (!np)
|
||||
@@ -239,7 +239,8 @@ static int ktd2692_parse_dt(struct ktd2692_context *led, struct device *dev,
|
||||
}
|
||||
}
|
||||
|
||||
child_node = of_get_next_available_child(np, NULL);
|
||||
struct device_node *child_node __free(device_node) =
|
||||
of_get_next_available_child(np, NULL);
|
||||
if (!child_node) {
|
||||
dev_err(dev, "No DT child node found for connected LED.\n");
|
||||
return -EINVAL;
|
||||
@@ -252,26 +253,24 @@ static int ktd2692_parse_dt(struct ktd2692_context *led, struct device *dev,
|
||||
&cfg->movie_max_microamp);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to parse led-max-microamp\n");
|
||||
goto err_parse_dt;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(child_node, "flash-max-microamp",
|
||||
&cfg->flash_max_microamp);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to parse flash-max-microamp\n");
|
||||
goto err_parse_dt;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(child_node, "flash-max-timeout-us",
|
||||
&cfg->flash_max_timeout);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to parse flash-max-timeout-us\n");
|
||||
goto err_parse_dt;
|
||||
return ret;
|
||||
}
|
||||
|
||||
err_parse_dt:
|
||||
of_node_put(child_node);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct led_flash_ops flash_ops = {
|
||||
|
||||
@@ -190,7 +190,7 @@ static int lm3601x_brightness_set(struct led_classdev *cdev,
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = regmap_write(led->regmap, LM3601X_LED_TORCH_REG, brightness);
|
||||
ret = regmap_write(led->regmap, LM3601X_LED_TORCH_REG, brightness - 1);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
@@ -341,8 +341,9 @@ static int lm3601x_register_leds(struct lm3601x_led *led,
|
||||
|
||||
led_cdev = &led->fled_cdev.led_cdev;
|
||||
led_cdev->brightness_set_blocking = lm3601x_brightness_set;
|
||||
led_cdev->max_brightness = DIV_ROUND_UP(led->torch_current_max,
|
||||
LM3601X_TORCH_REG_DIV);
|
||||
led_cdev->max_brightness =
|
||||
DIV_ROUND_UP(led->torch_current_max - LM3601X_MIN_TORCH_I_UA + 1,
|
||||
LM3601X_TORCH_REG_DIV);
|
||||
led_cdev->flags |= LED_DEV_CAP_FLASH;
|
||||
|
||||
init_data.fwnode = fwnode;
|
||||
@@ -386,6 +387,14 @@ static int lm3601x_parse_node(struct lm3601x_led *led,
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (led->torch_current_max > LM3601X_MAX_TORCH_I_UA) {
|
||||
dev_warn(&led->client->dev,
|
||||
"Max torch current set too high (%d vs %d)\n",
|
||||
led->torch_current_max,
|
||||
LM3601X_MAX_TORCH_I_UA);
|
||||
led->torch_current_max = LM3601X_MAX_TORCH_I_UA;
|
||||
}
|
||||
|
||||
ret = fwnode_property_read_u32(child, "flash-max-microamp",
|
||||
&led->flash_current_max);
|
||||
if (ret) {
|
||||
@@ -434,6 +443,10 @@ static int lm3601x_probe(struct i2c_client *client)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_write(led->regmap, LM3601X_DEV_ID_REG, LM3601X_SW_RESET);
|
||||
if (ret)
|
||||
dev_warn(&client->dev, "Failed to reset the LED controller\n");
|
||||
|
||||
mutex_init(&led->lock);
|
||||
|
||||
return lm3601x_register_leds(led, fwnode);
|
||||
|
||||
@@ -599,7 +599,7 @@ static int max77693_led_parse_dt(struct max77693_led_device *led,
|
||||
{
|
||||
struct device *dev = &led->pdev->dev;
|
||||
struct max77693_sub_led *sub_leds = led->sub_leds;
|
||||
struct device_node *node = dev_of_node(dev), *child_node;
|
||||
struct device_node *node = dev_of_node(dev);
|
||||
struct property *prop;
|
||||
u32 led_sources[2];
|
||||
int i, ret, fled_id;
|
||||
@@ -608,7 +608,7 @@ static int max77693_led_parse_dt(struct max77693_led_device *led,
|
||||
of_property_read_u32(node, "maxim,boost-mvout", &cfg->boost_vout);
|
||||
of_property_read_u32(node, "maxim,mvsys-min", &cfg->low_vsys);
|
||||
|
||||
for_each_available_child_of_node(node, child_node) {
|
||||
for_each_available_child_of_node_scoped(node, child_node) {
|
||||
prop = of_find_property(child_node, "led-sources", NULL);
|
||||
if (prop) {
|
||||
const __be32 *srcs = NULL;
|
||||
@@ -622,7 +622,6 @@ static int max77693_led_parse_dt(struct max77693_led_device *led,
|
||||
} else {
|
||||
dev_err(dev,
|
||||
"led-sources DT property missing\n");
|
||||
of_node_put(child_node);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -638,18 +637,16 @@ static int max77693_led_parse_dt(struct max77693_led_device *led,
|
||||
} else {
|
||||
dev_err(dev,
|
||||
"Wrong led-sources DT property value.\n");
|
||||
of_node_put(child_node);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (sub_nodes[fled_id]) {
|
||||
dev_err(dev,
|
||||
"Conflicting \"led-sources\" DT properties\n");
|
||||
of_node_put(child_node);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sub_nodes[fled_id] = child_node;
|
||||
sub_nodes[fled_id] = of_node_get(child_node);
|
||||
sub_leds[fled_id].fled_id = fled_id;
|
||||
|
||||
cfg->label[fled_id] =
|
||||
@@ -681,10 +678,8 @@ static int max77693_led_parse_dt(struct max77693_led_device *led,
|
||||
|
||||
if (++cfg->num_leds == 2 ||
|
||||
(max77693_fled_used(led, FLED1) &&
|
||||
max77693_fled_used(led, FLED2))) {
|
||||
of_node_put(child_node);
|
||||
max77693_fled_used(led, FLED2)))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg->num_leds == 0) {
|
||||
@@ -968,7 +963,7 @@ static int max77693_led_probe(struct platform_device *pdev)
|
||||
|
||||
ret = max77693_setup(led, &led_cfg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
goto err_setup;
|
||||
|
||||
mutex_init(&led->lock);
|
||||
|
||||
@@ -1000,6 +995,8 @@ static int max77693_led_probe(struct platform_device *pdev)
|
||||
else
|
||||
goto err_register_led1;
|
||||
}
|
||||
of_node_put(sub_nodes[i]);
|
||||
sub_nodes[i] = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1013,6 +1010,9 @@ err_register_led2:
|
||||
err_register_led1:
|
||||
mutex_destroy(&led->lock);
|
||||
|
||||
err_setup:
|
||||
for (i = FLED1; i <= FLED2; i++)
|
||||
of_node_put(sub_nodes[i]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
@@ -14,6 +14,9 @@
|
||||
#include <media/v4l2-flash-led-class.h>
|
||||
|
||||
/* registers definitions */
|
||||
#define FLASH_REVISION_REG 0x00
|
||||
#define FLASH_4CH_REVISION_V0P1 0x01
|
||||
|
||||
#define FLASH_TYPE_REG 0x04
|
||||
#define FLASH_TYPE_VAL 0x18
|
||||
|
||||
@@ -73,6 +76,16 @@
|
||||
|
||||
#define UA_PER_MA 1000
|
||||
|
||||
/* thermal threshold constants */
|
||||
#define OTST_3CH_MIN_VAL 3
|
||||
#define OTST1_4CH_MIN_VAL 0
|
||||
#define OTST1_4CH_V0P1_MIN_VAL 3
|
||||
#define OTST2_4CH_MIN_VAL 0
|
||||
|
||||
#define OTST1_MAX_CURRENT_MA 1000
|
||||
#define OTST2_MAX_CURRENT_MA 500
|
||||
#define OTST3_MAX_CURRENT_MA 200
|
||||
|
||||
enum hw_type {
|
||||
QCOM_MVFLASH_3CH,
|
||||
QCOM_MVFLASH_4CH,
|
||||
@@ -98,6 +111,9 @@ enum {
|
||||
REG_IRESOLUTION,
|
||||
REG_CHAN_STROBE,
|
||||
REG_CHAN_EN,
|
||||
REG_THERM_THRSH1,
|
||||
REG_THERM_THRSH2,
|
||||
REG_THERM_THRSH3,
|
||||
REG_MAX_COUNT,
|
||||
};
|
||||
|
||||
@@ -111,6 +127,9 @@ static struct reg_field mvflash_3ch_regs[REG_MAX_COUNT] = {
|
||||
REG_FIELD(0x47, 0, 5), /* iresolution */
|
||||
REG_FIELD_ID(0x49, 0, 2, 3, 1), /* chan_strobe */
|
||||
REG_FIELD(0x4c, 0, 2), /* chan_en */
|
||||
REG_FIELD(0x56, 0, 2), /* therm_thrsh1 */
|
||||
REG_FIELD(0x57, 0, 2), /* therm_thrsh2 */
|
||||
REG_FIELD(0x58, 0, 2), /* therm_thrsh3 */
|
||||
};
|
||||
|
||||
static struct reg_field mvflash_4ch_regs[REG_MAX_COUNT] = {
|
||||
@@ -123,6 +142,8 @@ static struct reg_field mvflash_4ch_regs[REG_MAX_COUNT] = {
|
||||
REG_FIELD(0x49, 0, 3), /* iresolution */
|
||||
REG_FIELD_ID(0x4a, 0, 6, 4, 1), /* chan_strobe */
|
||||
REG_FIELD(0x4e, 0, 3), /* chan_en */
|
||||
REG_FIELD(0x7a, 0, 2), /* therm_thrsh1 */
|
||||
REG_FIELD(0x78, 0, 2), /* therm_thrsh2 */
|
||||
};
|
||||
|
||||
struct qcom_flash_data {
|
||||
@@ -130,9 +151,11 @@ struct qcom_flash_data {
|
||||
struct regmap_field *r_fields[REG_MAX_COUNT];
|
||||
struct mutex lock;
|
||||
enum hw_type hw_type;
|
||||
u32 total_ma;
|
||||
u8 leds_count;
|
||||
u8 max_channels;
|
||||
u8 chan_en_bits;
|
||||
u8 revision;
|
||||
};
|
||||
|
||||
struct qcom_flash_led {
|
||||
@@ -143,6 +166,7 @@ struct qcom_flash_led {
|
||||
u32 max_timeout_ms;
|
||||
u32 flash_current_ma;
|
||||
u32 flash_timeout_ms;
|
||||
u32 current_in_use_ma;
|
||||
u8 *chan_id;
|
||||
u8 chan_count;
|
||||
bool enabled;
|
||||
@@ -172,6 +196,127 @@ static int set_flash_module_en(struct qcom_flash_led *led, bool en)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int update_allowed_flash_current(struct qcom_flash_led *led, u32 *current_ma, bool strobe)
|
||||
{
|
||||
struct qcom_flash_data *flash_data = led->flash_data;
|
||||
u32 therm_ma, avail_ma, thrsh[3], min_thrsh, sts;
|
||||
int rc = 0;
|
||||
|
||||
mutex_lock(&flash_data->lock);
|
||||
/*
|
||||
* Put previously allocated current into allowed budget in either of these two cases:
|
||||
* 1) LED is disabled;
|
||||
* 2) LED is enabled repeatedly
|
||||
*/
|
||||
if (!strobe || led->current_in_use_ma != 0) {
|
||||
if (flash_data->total_ma >= led->current_in_use_ma)
|
||||
flash_data->total_ma -= led->current_in_use_ma;
|
||||
else
|
||||
flash_data->total_ma = 0;
|
||||
|
||||
led->current_in_use_ma = 0;
|
||||
if (!strobe)
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
/*
|
||||
* Cache the default thermal threshold settings, and set them to the lowest levels before
|
||||
* reading over-temp real time status. If over-temp has been triggered at the lowest
|
||||
* threshold, it's very likely that it would be triggered at a higher (default) threshold
|
||||
* when more flash current is requested. Prevent device from triggering over-temp condition
|
||||
* by limiting the flash current for the new request.
|
||||
*/
|
||||
rc = regmap_field_read(flash_data->r_fields[REG_THERM_THRSH1], &thrsh[0]);
|
||||
if (rc < 0)
|
||||
goto unlock;
|
||||
|
||||
rc = regmap_field_read(flash_data->r_fields[REG_THERM_THRSH2], &thrsh[1]);
|
||||
if (rc < 0)
|
||||
goto unlock;
|
||||
|
||||
if (flash_data->hw_type == QCOM_MVFLASH_3CH) {
|
||||
rc = regmap_field_read(flash_data->r_fields[REG_THERM_THRSH3], &thrsh[2]);
|
||||
if (rc < 0)
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
min_thrsh = OTST_3CH_MIN_VAL;
|
||||
if (flash_data->hw_type == QCOM_MVFLASH_4CH)
|
||||
min_thrsh = (flash_data->revision == FLASH_4CH_REVISION_V0P1) ?
|
||||
OTST1_4CH_V0P1_MIN_VAL : OTST1_4CH_MIN_VAL;
|
||||
|
||||
rc = regmap_field_write(flash_data->r_fields[REG_THERM_THRSH1], min_thrsh);
|
||||
if (rc < 0)
|
||||
goto unlock;
|
||||
|
||||
if (flash_data->hw_type == QCOM_MVFLASH_4CH)
|
||||
min_thrsh = OTST2_4CH_MIN_VAL;
|
||||
|
||||
/*
|
||||
* The default thermal threshold settings have been updated hence
|
||||
* restore them if any fault happens starting from here.
|
||||
*/
|
||||
rc = regmap_field_write(flash_data->r_fields[REG_THERM_THRSH2], min_thrsh);
|
||||
if (rc < 0)
|
||||
goto restore;
|
||||
|
||||
if (flash_data->hw_type == QCOM_MVFLASH_3CH) {
|
||||
rc = regmap_field_write(flash_data->r_fields[REG_THERM_THRSH3], min_thrsh);
|
||||
if (rc < 0)
|
||||
goto restore;
|
||||
}
|
||||
|
||||
/* Read thermal level status to get corresponding derating flash current */
|
||||
rc = regmap_field_read(flash_data->r_fields[REG_STATUS2], &sts);
|
||||
if (rc)
|
||||
goto restore;
|
||||
|
||||
therm_ma = FLASH_TOTAL_CURRENT_MAX_UA / 1000;
|
||||
if (flash_data->hw_type == QCOM_MVFLASH_3CH) {
|
||||
if (sts & FLASH_STS_3CH_OTST3)
|
||||
therm_ma = OTST3_MAX_CURRENT_MA;
|
||||
else if (sts & FLASH_STS_3CH_OTST2)
|
||||
therm_ma = OTST2_MAX_CURRENT_MA;
|
||||
else if (sts & FLASH_STS_3CH_OTST1)
|
||||
therm_ma = OTST1_MAX_CURRENT_MA;
|
||||
} else {
|
||||
if (sts & FLASH_STS_4CH_OTST2)
|
||||
therm_ma = OTST2_MAX_CURRENT_MA;
|
||||
else if (sts & FLASH_STS_4CH_OTST1)
|
||||
therm_ma = OTST1_MAX_CURRENT_MA;
|
||||
}
|
||||
|
||||
/* Calculate the allowed flash current for the request */
|
||||
if (therm_ma <= flash_data->total_ma)
|
||||
avail_ma = 0;
|
||||
else
|
||||
avail_ma = therm_ma - flash_data->total_ma;
|
||||
|
||||
*current_ma = min_t(u32, *current_ma, avail_ma);
|
||||
led->current_in_use_ma = *current_ma;
|
||||
flash_data->total_ma += led->current_in_use_ma;
|
||||
|
||||
dev_dbg(led->flash.led_cdev.dev, "allowed flash current: %dmA, total current: %dmA\n",
|
||||
led->current_in_use_ma, flash_data->total_ma);
|
||||
|
||||
restore:
|
||||
/* Restore to default thermal threshold settings */
|
||||
rc = regmap_field_write(flash_data->r_fields[REG_THERM_THRSH1], thrsh[0]);
|
||||
if (rc < 0)
|
||||
goto unlock;
|
||||
|
||||
rc = regmap_field_write(flash_data->r_fields[REG_THERM_THRSH2], thrsh[1]);
|
||||
if (rc < 0)
|
||||
goto unlock;
|
||||
|
||||
if (flash_data->hw_type == QCOM_MVFLASH_3CH)
|
||||
rc = regmap_field_write(flash_data->r_fields[REG_THERM_THRSH3], thrsh[2]);
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&flash_data->lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int set_flash_current(struct qcom_flash_led *led, u32 current_ma, enum led_mode mode)
|
||||
{
|
||||
struct qcom_flash_data *flash_data = led->flash_data;
|
||||
@@ -313,6 +458,10 @@ static int qcom_flash_strobe_set(struct led_classdev_flash *fled_cdev, bool stat
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = update_allowed_flash_current(led, &led->flash_current_ma, state);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = set_flash_current(led, led->flash_current_ma, FLASH_MODE);
|
||||
if (rc)
|
||||
return rc;
|
||||
@@ -429,6 +578,10 @@ static int qcom_flash_led_brightness_set(struct led_classdev *led_cdev,
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = update_allowed_flash_current(led, ¤t_ma, enable);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = set_flash_current(led, current_ma, TORCH_MODE);
|
||||
if (rc)
|
||||
return rc;
|
||||
@@ -707,6 +860,14 @@ static int qcom_flash_led_probe(struct platform_device *pdev)
|
||||
flash_data->hw_type = QCOM_MVFLASH_4CH;
|
||||
flash_data->max_channels = 4;
|
||||
regs = mvflash_4ch_regs;
|
||||
|
||||
rc = regmap_read(regmap, reg_base + FLASH_REVISION_REG, &val);
|
||||
if (rc < 0) {
|
||||
dev_err(dev, "Failed to read flash LED module revision, rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
flash_data->revision = val;
|
||||
} else {
|
||||
dev_err(dev, "flash LED subtype %#x is not yet supported\n", val);
|
||||
return -ENODEV;
|
||||
|
||||
@@ -115,7 +115,7 @@ static int pm860x_led_set(struct led_classdev *cdev,
|
||||
static int pm860x_led_dt_init(struct platform_device *pdev,
|
||||
struct pm860x_led *data)
|
||||
{
|
||||
struct device_node *nproot, *np;
|
||||
struct device_node *nproot;
|
||||
int iset = 0;
|
||||
|
||||
if (!dev_of_node(pdev->dev.parent))
|
||||
@@ -125,12 +125,11 @@ static int pm860x_led_dt_init(struct platform_device *pdev,
|
||||
dev_err(&pdev->dev, "failed to find leds node\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
for_each_available_child_of_node(nproot, np) {
|
||||
for_each_available_child_of_node_scoped(nproot, np) {
|
||||
if (of_node_name_eq(np, data->name)) {
|
||||
of_property_read_u32(np, "marvell,88pm860x-iset",
|
||||
&iset);
|
||||
data->iset = PM8606_LED_CURRENT(iset);
|
||||
of_node_put(np);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -263,7 +263,7 @@ out:
|
||||
|
||||
static int aw2013_probe_dt(struct aw2013 *chip)
|
||||
{
|
||||
struct device_node *np = dev_of_node(&chip->client->dev), *child;
|
||||
struct device_node *np = dev_of_node(&chip->client->dev);
|
||||
int count, ret = 0, i = 0;
|
||||
struct aw2013_led *led;
|
||||
|
||||
@@ -273,7 +273,7 @@ static int aw2013_probe_dt(struct aw2013 *chip)
|
||||
|
||||
regmap_write(chip->regmap, AW2013_RSTR, AW2013_RSTR_RESET);
|
||||
|
||||
for_each_available_child_of_node(np, child) {
|
||||
for_each_available_child_of_node_scoped(np, child) {
|
||||
struct led_init_data init_data = {};
|
||||
u32 source;
|
||||
u32 imax;
|
||||
@@ -304,10 +304,8 @@ static int aw2013_probe_dt(struct aw2013 *chip)
|
||||
|
||||
ret = devm_led_classdev_register_ext(&chip->client->dev,
|
||||
&led->cdev, &init_data);
|
||||
if (ret < 0) {
|
||||
of_node_put(child);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
@@ -392,7 +392,6 @@ static int bcm6328_leds_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev_of_node(&pdev->dev);
|
||||
struct device_node *child;
|
||||
void __iomem *mem;
|
||||
spinlock_t *lock; /* memory lock */
|
||||
unsigned long val, *blink_leds, *blink_delay;
|
||||
@@ -435,7 +434,7 @@ static int bcm6328_leds_probe(struct platform_device *pdev)
|
||||
val |= BCM6328_SERIAL_LED_SHIFT_DIR;
|
||||
bcm6328_led_write(mem + BCM6328_REG_INIT, val);
|
||||
|
||||
for_each_available_child_of_node(np, child) {
|
||||
for_each_available_child_of_node_scoped(np, child) {
|
||||
int rc;
|
||||
u32 reg;
|
||||
|
||||
@@ -454,10 +453,8 @@ static int bcm6328_leds_probe(struct platform_device *pdev)
|
||||
rc = bcm6328_led(dev, child, reg, mem, lock,
|
||||
blink_leds, blink_delay);
|
||||
|
||||
if (rc < 0) {
|
||||
of_node_put(child);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -147,7 +147,6 @@ static int bcm6358_leds_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev_of_node(&pdev->dev);
|
||||
struct device_node *child;
|
||||
void __iomem *mem;
|
||||
spinlock_t *lock; /* memory lock */
|
||||
unsigned long val;
|
||||
@@ -184,7 +183,7 @@ static int bcm6358_leds_probe(struct platform_device *pdev)
|
||||
}
|
||||
bcm6358_led_write(mem + BCM6358_REG_CTRL, val);
|
||||
|
||||
for_each_available_child_of_node(np, child) {
|
||||
for_each_available_child_of_node_scoped(np, child) {
|
||||
int rc;
|
||||
u32 reg;
|
||||
|
||||
@@ -198,10 +197,8 @@ static int bcm6358_leds_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
rc = bcm6358_led(dev, child, reg, mem, lock);
|
||||
if (rc < 0) {
|
||||
of_node_put(child);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -69,16 +69,14 @@ static const struct regmap_config bd2606mvv_regmap = {
|
||||
|
||||
static int bd2606mvv_probe(struct i2c_client *client)
|
||||
{
|
||||
struct fwnode_handle *np, *child;
|
||||
struct device *dev = &client->dev;
|
||||
struct bd2606mvv_priv *priv;
|
||||
struct fwnode_handle *led_fwnodes[BD2606_MAX_LEDS] = { 0 };
|
||||
int active_pairs[BD2606_MAX_LEDS / 2] = { 0 };
|
||||
int err, reg;
|
||||
int i;
|
||||
int i, j;
|
||||
|
||||
np = dev_fwnode(dev);
|
||||
if (!np)
|
||||
if (!dev_fwnode(dev))
|
||||
return -ENODEV;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
@@ -94,20 +92,18 @@ static int bd2606mvv_probe(struct i2c_client *client)
|
||||
|
||||
i2c_set_clientdata(client, priv);
|
||||
|
||||
fwnode_for_each_available_child_node(np, child) {
|
||||
device_for_each_child_node_scoped(dev, child) {
|
||||
struct bd2606mvv_led *led;
|
||||
|
||||
err = fwnode_property_read_u32(child, "reg", ®);
|
||||
if (err) {
|
||||
fwnode_handle_put(child);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
if (reg < 0 || reg >= BD2606_MAX_LEDS || led_fwnodes[reg]) {
|
||||
fwnode_handle_put(child);
|
||||
|
||||
if (reg < 0 || reg >= BD2606_MAX_LEDS || led_fwnodes[reg])
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
led = &priv->leds[reg];
|
||||
led_fwnodes[reg] = child;
|
||||
led_fwnodes[reg] = fwnode_handle_get(child);
|
||||
active_pairs[reg / 2]++;
|
||||
led->priv = priv;
|
||||
led->led_no = reg;
|
||||
@@ -130,7 +126,8 @@ static int bd2606mvv_probe(struct i2c_client *client)
|
||||
&priv->leds[i].ldev,
|
||||
&init_data);
|
||||
if (err < 0) {
|
||||
fwnode_handle_put(child);
|
||||
for (j = i; j < BD2606_MAX_LEDS; j++)
|
||||
fwnode_handle_put(led_fwnodes[j]);
|
||||
return dev_err_probe(dev, err,
|
||||
"couldn't register LED %s\n",
|
||||
priv->leds[i].ldev.name);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user