mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 22:21:40 +00:00
- Core Frameworks
- Introduce ExpressWire library - New Drivers - Add support for ON Semiconductor NCP5623 RGB LED Driver - New Device Support - Add support for PM660L to Qualcomm's LPG driver - New Functionality - Dynamically load modules required for the default-trigger - Add some support for suspend and resume - Allow LEDs to remain lit during suspend - Fix-ups - Device Tree binding adaptions/conversions/creation - Fix include lists; alphabetise, remove unused, explicitly add used - Add new led_match_default_trigger to avoid duplication - Add module alias' to aid auto-loading - Default to hw_control if no others are specified - De-bloat the supported link speed attribute lists - Remove superfluous code and simplify overall - Constify some variables - Bug Fixes - Prevent kernel panic when renaming the net interface - Fix Kconfig related build errors - Ensure mutexes are unlocked prior to destroying them - Provide clean-up between state changes to avoid invalid state - Fix some broken kernel-doc headers -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEdrbJNaO+IJqU8IdIUa+KL4f8d2EFAmXzCvUACgkQUa+KL4f8 d2Fh0A/+KQiuzluglEsnyG7gfb2771x9dQ9pIwaR68UkCwThNH8ico+NqUDs8Jur 6jtfYfKcWIz3i5kbnWBDGJfEEiVuDGu8Zv9UFxzQViyWQqawkJWNMsYqL3KtfI4i Ujj2Ja1MsoqO7COngry9I+3sT6rEwdQJMrVfNAdvOYjlXwr3O8Z2NipPACEqutUr 0gxKAEEbGOj3+s3UGInrGi9RGuOVBe9UNA2etmtie1kxkdowTxCNY94ukUf9tnvC WVXF8iOByUgVAxMh1ugSc27CTCV+VcDMYKKr9ABVhskI/pT3zMFoUCYY1EqhaOTF Q40+yFX8ERomNTgy1tbNf06PkzaN+NJ4P/SHFU79madfy4OM6QobpTSt7bBpaSEP gm3zuI1a353NPfAUZiIsTgv8jCh18w/adphTNsXY/4PnmkKF0+Pm57PJf8BDhlY3 KiScK7WXhGS9G3wNpLH+7QBdWiON3oWYJhVK4ijEfgRpEDofv+W16GzcETkUsyQ1 5DLu/W8wHN9zxHj1YXaitmnRjX3IMoltcIix8FI3YUKrx3m3twm2Vj5ZLziaPm83 7rBBPyePXwIamLokiTPCfXOxygO7Qv6VAp1aCR6400R/rtjykziboqvT2o6OMpkS W/88631VIuL9jAaP/zdUHrle1NpKDiHs2MF0Rtj+0OOoMJyOC7k= =m2vY -----END PGP SIGNATURE----- Merge tag 'leds-next-6.9' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/leds Pull LED updates from Lee Jones: "Core Framework: - Introduce ExpressWire library New Drivers: - Add support for ON Semiconductor NCP5623 RGB LED Driver New Device Support: - Add support for PM660L to Qualcomm's LPG driver New Functionality: - Dynamically load modules required for the default-trigger - Add some support for suspend and resume - Allow LEDs to remain lit during suspend Fix-ups: - Device Tree binding adaptions/conversions/creation - Fix include lists; alphabetise, remove unused, explicitly add used - Add new led_match_default_trigger to avoid duplication - Add module alias' to aid auto-loading - Default to hw_control if no others are specified - De-bloat the supported link speed attribute lists - Remove superfluous code and simplify overall - Constify some variables Bug Fixes: - Prevent kernel panic when renaming the net interface - Fix Kconfig related build errors - Ensure mutexes are unlocked prior to destroying them - Provide clean-up between state changes to avoid invalid state - Fix some broken kernel-doc headers" * tag 'leds-next-6.9' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/leds: (41 commits) leds: ncp5623: Add MS suffix to time defines leds: Add NCP5623 multi-led driver dt-bindings: leds: Add NCP5623 multi-LED Controller leds: mlxreg: Drop an excess struct mlxreg_led_data member leds: leds-mlxcpld: Fix struct mlxcpld_led_priv member name leds: lm3601x: Fix struct lm3601_led kernel-doc warnings leds: Fix ifdef check for gpio_led_register_device() dt-bindings: leds: qcom-lpg: Narrow nvmem for other variants dt-bindings: leds: qcom-lpg: Drop redundant qcom,pm8550-pwm in if:then: dt-bindings: leds: Add LED_FUNCTION_WAN_ONLINE for Internet access leds: sgm3140: Add missing timer cleanup and flash gpio control leds: expresswire: Don't depend on NEW_LEDS Revert "leds: Only descend into leds directory when CONFIG_NEW_LEDS is set" leds: aw2013: Unlock mutex before destroying it leds: qcom-lpg: Add QCOM_PBS dependency leds: rgb: leds-group-multicolor: Allow LEDs to stay on in suspend leds: trigger: netdev: Fix kernel panic on interface rename trig notify leds: qcom-lpg: Add PM660L configuration and compatible leds: spi-byte: Use devm_led_classdev_register_ext() leds: pca963x: Add support for suspend and resume ...
This commit is contained in:
commit
f5c31bcf60
@ -88,6 +88,8 @@ Description:
|
||||
speed of 10MBps of the named network device.
|
||||
Setting this value also immediately changes the LED state.
|
||||
|
||||
Present only if the named network device supports 10Mbps link speed.
|
||||
|
||||
What: /sys/class/leds/<led>/link_100
|
||||
Date: Jun 2023
|
||||
KernelVersion: 6.5
|
||||
@ -101,6 +103,8 @@ Description:
|
||||
speed of 100Mbps of the named network device.
|
||||
Setting this value also immediately changes the LED state.
|
||||
|
||||
Present only if the named network device supports 100Mbps link speed.
|
||||
|
||||
What: /sys/class/leds/<led>/link_1000
|
||||
Date: Jun 2023
|
||||
KernelVersion: 6.5
|
||||
@ -114,6 +118,8 @@ Description:
|
||||
speed of 1000Mbps of the named network device.
|
||||
Setting this value also immediately changes the LED state.
|
||||
|
||||
Present only if the named network device supports 1000Mbps link speed.
|
||||
|
||||
What: /sys/class/leds/<led>/link_2500
|
||||
Date: Nov 2023
|
||||
KernelVersion: 6.8
|
||||
@ -127,6 +133,8 @@ Description:
|
||||
speed of 2500Mbps of the named network device.
|
||||
Setting this value also immediately changes the LED state.
|
||||
|
||||
Present only if the named network device supports 2500Mbps link speed.
|
||||
|
||||
What: /sys/class/leds/<led>/link_5000
|
||||
Date: Nov 2023
|
||||
KernelVersion: 6.8
|
||||
@ -140,6 +148,8 @@ Description:
|
||||
speed of 5000Mbps of the named network device.
|
||||
Setting this value also immediately changes the LED state.
|
||||
|
||||
Present only if the named network device supports 5000Mbps link speed.
|
||||
|
||||
What: /sys/class/leds/<led>/link_10000
|
||||
Date: Nov 2023
|
||||
KernelVersion: 6.8
|
||||
@ -153,6 +163,8 @@ Description:
|
||||
speed of 10000Mbps of the named network device.
|
||||
Setting this value also immediately changes the LED state.
|
||||
|
||||
Present only if the named network device supports 10000Mbps link speed.
|
||||
|
||||
What: /sys/class/leds/<led>/half_duplex
|
||||
Date: Jun 2023
|
||||
KernelVersion: 6.5
|
||||
|
@ -1,11 +1,11 @@
|
||||
What: /sys/class/leds/<led>/ttyname
|
||||
What: /sys/class/leds/<tty_led>/ttyname
|
||||
Date: Dec 2020
|
||||
KernelVersion: 5.10
|
||||
Contact: linux-leds@vger.kernel.org
|
||||
Description:
|
||||
Specifies the tty device name of the triggering tty
|
||||
|
||||
What: /sys/class/leds/<led>/rx
|
||||
What: /sys/class/leds/<tty_led>/rx
|
||||
Date: February 2024
|
||||
KernelVersion: 6.8
|
||||
Description:
|
||||
@ -13,7 +13,7 @@ Description:
|
||||
If set to 0, the LED will not blink on reception.
|
||||
If set to 1 (default), the LED will blink on reception.
|
||||
|
||||
What: /sys/class/leds/<led>/tx
|
||||
What: /sys/class/leds/<tty_led>/tx
|
||||
Date: February 2024
|
||||
KernelVersion: 6.8
|
||||
Description:
|
||||
@ -21,7 +21,7 @@ Description:
|
||||
If set to 0, the LED will not blink on transmission.
|
||||
If set to 1 (default), the LED will blink on transmission.
|
||||
|
||||
What: /sys/class/leds/<led>/cts
|
||||
What: /sys/class/leds/<tty_led>/cts
|
||||
Date: February 2024
|
||||
KernelVersion: 6.8
|
||||
Description:
|
||||
@ -31,7 +31,7 @@ Description:
|
||||
If set to 0 (default), the LED will not evaluate CTS.
|
||||
If set to 1, the LED will evaluate CTS.
|
||||
|
||||
What: /sys/class/leds/<led>/dsr
|
||||
What: /sys/class/leds/<tty_led>/dsr
|
||||
Date: February 2024
|
||||
KernelVersion: 6.8
|
||||
Description:
|
||||
@ -41,7 +41,7 @@ Description:
|
||||
If set to 0 (default), the LED will not evaluate DSR.
|
||||
If set to 1, the LED will evaluate DSR.
|
||||
|
||||
What: /sys/class/leds/<led>/dcd
|
||||
What: /sys/class/leds/<tty_led>/dcd
|
||||
Date: February 2024
|
||||
KernelVersion: 6.8
|
||||
Description:
|
||||
@ -51,7 +51,7 @@ Description:
|
||||
If set to 0 (default), the LED will not evaluate CAR (DCD).
|
||||
If set to 1, the LED will evaluate CAR (DCD).
|
||||
|
||||
What: /sys/class/leds/<led>/rng
|
||||
What: /sys/class/leds/<tty_led>/rng
|
||||
Date: February 2024
|
||||
KernelVersion: 6.8
|
||||
Description:
|
||||
|
@ -11,7 +11,7 @@ maintainers:
|
||||
|
||||
description: >
|
||||
The Qualcomm Light Pulse Generator consists of three different hardware blocks;
|
||||
a ramp generator with lookup table, the light pulse generator and a three
|
||||
a ramp generator with lookup table (LUT), the light pulse generator and a three
|
||||
channel current sink. These blocks are found in a wide range of Qualcomm PMICs.
|
||||
|
||||
properties:
|
||||
@ -63,6 +63,29 @@ properties:
|
||||
- description: dtest line to attach
|
||||
- description: flags for the attachment
|
||||
|
||||
nvmem:
|
||||
description: >
|
||||
This property is required for PMICs that supports PPG, which is when a
|
||||
PMIC stores LPG per-channel data and pattern LUT in SDAM modules instead
|
||||
of in a LUT peripheral. For PMICs, such as PM8350C, per-channel data
|
||||
and pattern LUT is separated into 2 SDAM modules. In that case, phandles
|
||||
to both SDAM modules need to be specified.
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
nvmem-names:
|
||||
minItems: 1
|
||||
items:
|
||||
- const: lpg_chan_sdam
|
||||
- const: lut_sdam
|
||||
|
||||
qcom,pbs:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description: >
|
||||
Phandle of the Qualcomm Programmable Boot Sequencer node (PBS).
|
||||
PBS node is used to trigger LPG pattern sequences for PMICs that support
|
||||
single SDAM PPG.
|
||||
|
||||
multi-led:
|
||||
type: object
|
||||
$ref: leds-class-multicolor.yaml#
|
||||
@ -106,6 +129,52 @@ required:
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,pm660l-lpg
|
||||
- qcom,pm8150b-lpg
|
||||
- qcom,pm8150l-lpg
|
||||
- qcom,pm8916-pwm
|
||||
- qcom,pm8941-lpg
|
||||
- qcom,pm8994-lpg
|
||||
- qcom,pmc8180c-lpg
|
||||
- qcom,pmi8994-lpg
|
||||
- qcom,pmi8998-lpg
|
||||
- qcom,pmk8550-pwm
|
||||
then:
|
||||
properties:
|
||||
nvmem: false
|
||||
nvmem-names: false
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: qcom,pmi632-lpg
|
||||
then:
|
||||
properties:
|
||||
nvmem:
|
||||
maxItems: 1
|
||||
nvmem-names:
|
||||
maxItems: 1
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,pm8350c-pwm
|
||||
then:
|
||||
properties:
|
||||
nvmem:
|
||||
minItems: 2
|
||||
nvmem-names:
|
||||
minItems: 2
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/leds/common.h>
|
||||
@ -191,4 +260,35 @@ examples:
|
||||
compatible = "qcom,pm8916-pwm";
|
||||
#pwm-cells = <2>;
|
||||
};
|
||||
- |
|
||||
#include <dt-bindings/leds/common.h>
|
||||
|
||||
led-controller {
|
||||
compatible = "qcom,pmi632-lpg";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
#pwm-cells = <2>;
|
||||
nvmem-names = "lpg_chan_sdam";
|
||||
nvmem = <&pmi632_sdam_7>;
|
||||
qcom,pbs = <&pmi632_pbs_client3>;
|
||||
|
||||
led@1 {
|
||||
reg = <1>;
|
||||
color = <LED_COLOR_ID_RED>;
|
||||
label = "red";
|
||||
};
|
||||
|
||||
led@2 {
|
||||
reg = <2>;
|
||||
color = <LED_COLOR_ID_GREEN>;
|
||||
label = "green";
|
||||
};
|
||||
|
||||
led@3 {
|
||||
reg = <3>;
|
||||
color = <LED_COLOR_ID_BLUE>;
|
||||
label = "blue";
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
|
96
Documentation/devicetree/bindings/leds/onnn,ncp5623.yaml
Normal file
96
Documentation/devicetree/bindings/leds/onnn,ncp5623.yaml
Normal file
@ -0,0 +1,96 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/leds/onnn,ncp5623.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: ON Semiconductor NCP5623 multi-LED Driver
|
||||
|
||||
maintainers:
|
||||
- Abdel Alkuor <alkuor@gmail.com>
|
||||
|
||||
description:
|
||||
NCP5623 Triple Output I2C Controlled LED Driver.
|
||||
https://www.onsemi.com/pdf/datasheet/ncp5623-d.pdf
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- onnn,ncp5623
|
||||
|
||||
reg:
|
||||
const: 0x38
|
||||
|
||||
multi-led:
|
||||
type: object
|
||||
$ref: leds-class-multicolor.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
||||
properties:
|
||||
"#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
|
||||
- color
|
||||
|
||||
required:
|
||||
- "#address-cells"
|
||||
- "#size-cells"
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- multi-led
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/leds/common.h>
|
||||
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
led-controller@38 {
|
||||
compatible = "onnn,ncp5623";
|
||||
reg = <0x38>;
|
||||
|
||||
multi-led {
|
||||
color = <LED_COLOR_ID_RGB>;
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
led@0 {
|
||||
reg = <0>;
|
||||
color = <LED_COLOR_ID_RED>;
|
||||
};
|
||||
|
||||
led@1 {
|
||||
reg = <1>;
|
||||
color = <LED_COLOR_ID_GREEN>;
|
||||
};
|
||||
|
||||
led@2 {
|
||||
reg = <2>;
|
||||
color = <LED_COLOR_ID_BLUE>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
@ -135,7 +135,7 @@ obj-$(CONFIG_CPU_IDLE) += cpuidle/
|
||||
obj-y += mmc/
|
||||
obj-y += ufs/
|
||||
obj-$(CONFIG_MEMSTICK) += memstick/
|
||||
obj-$(CONFIG_NEW_LEDS) += leds/
|
||||
obj-y += leds/
|
||||
obj-$(CONFIG_INFINIBAND) += infiniband/
|
||||
obj-y += firmware/
|
||||
obj-$(CONFIG_CRYPTO) += crypto/
|
||||
|
@ -6,6 +6,12 @@ config LEDS_GPIO_REGISTER
|
||||
As this function is used by arch code it must not be compiled as a
|
||||
module.
|
||||
|
||||
# This library does not depend on NEW_LEDS and must be independent so it can be
|
||||
# selected from other subsystems (specifically backlight).
|
||||
config LEDS_EXPRESSWIRE
|
||||
bool
|
||||
depends on GPIOLIB
|
||||
|
||||
menuconfig NEW_LEDS
|
||||
bool "LED Support"
|
||||
help
|
||||
@ -399,7 +405,7 @@ config LEDS_LP3952
|
||||
config LEDS_LP50XX
|
||||
tristate "LED Support for TI LP5036/30/24/18/12/09 LED driver chip"
|
||||
depends on LEDS_CLASS && REGMAP_I2C
|
||||
depends on LEDS_CLASS_MULTICOLOR || !LEDS_CLASS_MULTICOLOR
|
||||
depends on LEDS_CLASS_MULTICOLOR
|
||||
help
|
||||
If you say yes here you get support for the Texas Instruments
|
||||
LP5036, LP5030, LP5024, LP5018, LP5012 and LP5009 LED driver.
|
||||
@ -410,7 +416,7 @@ config LEDS_LP50XX
|
||||
config LEDS_LP55XX_COMMON
|
||||
tristate "Common Driver for TI/National LP5521/5523/55231/5562/8501"
|
||||
depends on LEDS_CLASS
|
||||
depends on LEDS_CLASS_MULTICOLOR || !LEDS_CLASS_MULTICOLOR
|
||||
depends on LEDS_CLASS_MULTICOLOR
|
||||
depends on OF
|
||||
depends on I2C
|
||||
select FW_LOADER
|
||||
|
@ -52,8 +52,8 @@ config LEDS_MAX77693
|
||||
config LEDS_MT6360
|
||||
tristate "LED Support for Mediatek MT6360 PMIC"
|
||||
depends on LEDS_CLASS && OF
|
||||
depends on LEDS_CLASS_FLASH || !LEDS_CLASS_FLASH
|
||||
depends on LEDS_CLASS_MULTICOLOR || !LEDS_CLASS_MULTICOLOR
|
||||
depends on LEDS_CLASS_FLASH
|
||||
depends on LEDS_CLASS_MULTICOLOR
|
||||
depends on V4L2_FLASH_LED_CLASS || !V4L2_FLASH_LED_CLASS
|
||||
depends on MFD_MT6360
|
||||
help
|
||||
|
@ -70,12 +70,11 @@ enum lm3601x_type {
|
||||
};
|
||||
|
||||
/**
|
||||
* struct lm3601x_led -
|
||||
* struct lm3601x_led - private lm3601x LED data
|
||||
* @fled_cdev: flash LED class device pointer
|
||||
* @client: Pointer to the I2C client
|
||||
* @regmap: Devices register map
|
||||
* @lock: Lock for reading/writing the device
|
||||
* @led_name: LED label for the Torch or IR LED
|
||||
* @flash_timeout: the timeout for the flash
|
||||
* @last_flag: last known flags register value
|
||||
* @torch_current_max: maximum current for the torch
|
||||
|
@ -114,8 +114,11 @@ static int sgm3140_brightness_set(struct led_classdev *led_cdev,
|
||||
"failed to enable regulator: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
gpiod_set_value_cansleep(priv->flash_gpio, 0);
|
||||
gpiod_set_value_cansleep(priv->enable_gpio, 1);
|
||||
} else {
|
||||
del_timer_sync(&priv->powerdown_timer);
|
||||
gpiod_set_value_cansleep(priv->flash_gpio, 0);
|
||||
gpiod_set_value_cansleep(priv->enable_gpio, 0);
|
||||
ret = regulator_disable(priv->vin_regulator);
|
||||
if (ret) {
|
||||
|
@ -552,6 +552,12 @@ int led_classdev_register_ext(struct device *parent,
|
||||
led_init_core(led_cdev);
|
||||
|
||||
#ifdef CONFIG_LEDS_TRIGGERS
|
||||
/*
|
||||
* If no default trigger was given and hw_control_trigger is set,
|
||||
* make it the default trigger.
|
||||
*/
|
||||
if (!led_cdev->default_trigger && led_cdev->hw_control_trigger)
|
||||
led_cdev->default_trigger = led_cdev->hw_control_trigger;
|
||||
led_trigger_set_default(led_cdev);
|
||||
#endif
|
||||
|
||||
|
@ -23,7 +23,7 @@
|
||||
* Nests outside led_cdev->trigger_lock
|
||||
*/
|
||||
static DECLARE_RWSEM(triggers_list_lock);
|
||||
LIST_HEAD(trigger_list);
|
||||
static LIST_HEAD(trigger_list);
|
||||
|
||||
/* Used by LED Class */
|
||||
|
||||
@ -247,9 +247,23 @@ void led_trigger_remove(struct led_classdev *led_cdev)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(led_trigger_remove);
|
||||
|
||||
static bool led_match_default_trigger(struct led_classdev *led_cdev,
|
||||
struct led_trigger *trig)
|
||||
{
|
||||
if (!strcmp(led_cdev->default_trigger, trig->name) &&
|
||||
trigger_relevant(led_cdev, trig)) {
|
||||
led_cdev->flags |= LED_INIT_DEFAULT_TRIGGER;
|
||||
led_trigger_set(led_cdev, trig);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void led_trigger_set_default(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct led_trigger *trig;
|
||||
bool found = false;
|
||||
|
||||
if (!led_cdev->default_trigger)
|
||||
return;
|
||||
@ -257,15 +271,19 @@ void led_trigger_set_default(struct led_classdev *led_cdev)
|
||||
down_read(&triggers_list_lock);
|
||||
down_write(&led_cdev->trigger_lock);
|
||||
list_for_each_entry(trig, &trigger_list, next_trig) {
|
||||
if (!strcmp(led_cdev->default_trigger, trig->name) &&
|
||||
trigger_relevant(led_cdev, trig)) {
|
||||
led_cdev->flags |= LED_INIT_DEFAULT_TRIGGER;
|
||||
led_trigger_set(led_cdev, trig);
|
||||
found = led_match_default_trigger(led_cdev, trig);
|
||||
if (found)
|
||||
break;
|
||||
}
|
||||
}
|
||||
up_write(&led_cdev->trigger_lock);
|
||||
up_read(&triggers_list_lock);
|
||||
|
||||
/*
|
||||
* If default trigger wasn't found, maybe trigger module isn't loaded yet.
|
||||
* Once loaded it will re-probe with all led_cdev's.
|
||||
*/
|
||||
if (!found)
|
||||
request_module_nowait("ledtrig:%s", led_cdev->default_trigger);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(led_trigger_set_default);
|
||||
|
||||
@ -297,12 +315,8 @@ int led_trigger_register(struct led_trigger *trig)
|
||||
down_read(&leds_list_lock);
|
||||
list_for_each_entry(led_cdev, &leds_list, node) {
|
||||
down_write(&led_cdev->trigger_lock);
|
||||
if (!led_cdev->trigger && led_cdev->default_trigger &&
|
||||
!strcmp(led_cdev->default_trigger, trig->name) &&
|
||||
trigger_relevant(led_cdev, trig)) {
|
||||
led_cdev->flags |= LED_INIT_DEFAULT_TRIGGER;
|
||||
led_trigger_set(led_cdev, trig);
|
||||
}
|
||||
if (!led_cdev->trigger && led_cdev->default_trigger)
|
||||
led_match_default_trigger(led_cdev, trig);
|
||||
up_write(&led_cdev->trigger_lock);
|
||||
}
|
||||
up_read(&leds_list_lock);
|
||||
|
@ -282,7 +282,7 @@ static int aw200xx_set_imax(const struct aw200xx *const chip,
|
||||
u32 led_imax_uA)
|
||||
{
|
||||
u32 g_imax_uA = aw200xx_imax_to_global(chip, led_imax_uA);
|
||||
u32 coeff_table[] = {1, 2, 3, 4, 6, 8, 12, 16};
|
||||
static const u32 coeff_table[] = {1, 2, 3, 4, 6, 8, 12, 16};
|
||||
u32 gccr_imax = UINT_MAX;
|
||||
u32 cur_imax = 0;
|
||||
int i;
|
||||
|
@ -405,6 +405,7 @@ error_reg:
|
||||
chip->regulators);
|
||||
|
||||
error:
|
||||
mutex_unlock(&chip->mutex);
|
||||
mutex_destroy(&chip->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ struct mlxcpld_param {
|
||||
|
||||
/**
|
||||
* struct mlxcpld_led_priv - LED private data:
|
||||
* @cled: LED class device instance
|
||||
* @cdev: LED class device instance
|
||||
* @param: LED CPLD access parameters
|
||||
**/
|
||||
struct mlxcpld_led_priv {
|
||||
|
@ -29,7 +29,6 @@
|
||||
* @data: led configuration data;
|
||||
* @led_cdev: led class data;
|
||||
* @base_color: base led color (other colors have constant offset from base);
|
||||
* @led_data: led data;
|
||||
* @data_parent: pointer to private device control data of parent;
|
||||
* @led_cdev_name: class device name
|
||||
*/
|
||||
|
@ -39,6 +39,7 @@
|
||||
#define PCA963X_LED_PWM 0x2 /* Controlled through PWM */
|
||||
#define PCA963X_LED_GRP_PWM 0x3 /* Controlled through PWM/GRPPWM */
|
||||
|
||||
#define PCA963X_MODE1_SLEEP 0x04 /* Normal mode or Low Power mode, oscillator off */
|
||||
#define PCA963X_MODE2_OUTDRV 0x04 /* Open-drain or totem pole */
|
||||
#define PCA963X_MODE2_INVRT 0x10 /* Normal or inverted direction */
|
||||
#define PCA963X_MODE2_DMBLNK 0x20 /* Enable blinking */
|
||||
@ -380,6 +381,32 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pca963x_suspend(struct device *dev)
|
||||
{
|
||||
struct pca963x *chip = dev_get_drvdata(dev);
|
||||
u8 reg;
|
||||
|
||||
reg = i2c_smbus_read_byte_data(chip->client, PCA963X_MODE1);
|
||||
reg = reg | BIT(PCA963X_MODE1_SLEEP);
|
||||
i2c_smbus_write_byte_data(chip->client, PCA963X_MODE1, reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pca963x_resume(struct device *dev)
|
||||
{
|
||||
struct pca963x *chip = dev_get_drvdata(dev);
|
||||
u8 reg;
|
||||
|
||||
reg = i2c_smbus_read_byte_data(chip->client, PCA963X_MODE1);
|
||||
reg = reg & ~BIT(PCA963X_MODE1_SLEEP);
|
||||
i2c_smbus_write_byte_data(chip->client, PCA963X_MODE1, reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(pca963x_pm, pca963x_suspend, pca963x_resume);
|
||||
|
||||
static const struct of_device_id of_pca963x_match[] = {
|
||||
{ .compatible = "nxp,pca9632", },
|
||||
{ .compatible = "nxp,pca9633", },
|
||||
@ -430,6 +457,7 @@ static struct i2c_driver pca963x_driver = {
|
||||
.driver = {
|
||||
.name = "leds-pca963x",
|
||||
.of_match_table = of_pca963x_match,
|
||||
.pm = pm_sleep_ptr(&pca963x_pm)
|
||||
},
|
||||
.probe = pca963x_probe,
|
||||
.id_table = pca963x_id,
|
||||
|
@ -83,7 +83,7 @@ static int spi_byte_probe(struct spi_device *spi)
|
||||
struct device_node *child;
|
||||
struct device *dev = &spi->dev;
|
||||
struct spi_byte_led *led;
|
||||
const char *name = "leds-spi-byte::";
|
||||
struct led_init_data init_data = {};
|
||||
const char *state;
|
||||
int ret;
|
||||
|
||||
@ -97,12 +97,9 @@ static int spi_byte_probe(struct spi_device *spi)
|
||||
if (!led)
|
||||
return -ENOMEM;
|
||||
|
||||
of_property_read_string(child, "label", &name);
|
||||
strscpy(led->name, name, sizeof(led->name));
|
||||
led->spi = spi;
|
||||
mutex_init(&led->mutex);
|
||||
led->cdef = device_get_match_data(dev);
|
||||
led->ldev.name = led->name;
|
||||
led->ldev.brightness = LED_OFF;
|
||||
led->ldev.max_brightness = led->cdef->max_value - led->cdef->off_value;
|
||||
led->ldev.brightness_set_blocking = spi_byte_brightness_set_blocking;
|
||||
@ -120,7 +117,11 @@ static int spi_byte_probe(struct spi_device *spi)
|
||||
spi_byte_brightness_set_blocking(&led->ldev,
|
||||
led->ldev.brightness);
|
||||
|
||||
ret = devm_led_classdev_register(&spi->dev, &led->ldev);
|
||||
init_data.fwnode = of_fwnode_handle(child);
|
||||
init_data.devicename = "leds-spi-byte";
|
||||
init_data.default_label = ":";
|
||||
|
||||
ret = devm_led_classdev_register_ext(&spi->dev, &led->ldev, &init_data);
|
||||
if (ret) {
|
||||
mutex_destroy(&led->mutex);
|
||||
return ret;
|
||||
|
@ -30,7 +30,6 @@ ssize_t led_trigger_write(struct file *filp, struct kobject *kobj,
|
||||
|
||||
extern struct rw_semaphore leds_list_lock;
|
||||
extern struct list_head leds_list;
|
||||
extern struct list_head trigger_list;
|
||||
extern const char * const led_colors[LED_COLOR_ID_MAX];
|
||||
|
||||
#endif /* __LEDS_H_INCLUDED */
|
||||
|
@ -27,6 +27,17 @@ config LEDS_KTD202X
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called leds-ktd202x.
|
||||
|
||||
config LEDS_NCP5623
|
||||
tristate "LED support for NCP5623"
|
||||
depends on I2C
|
||||
depends on OF
|
||||
help
|
||||
This option enables support for ON semiconductor NCP5623
|
||||
Triple Output I2C Controlled RGB LED Driver.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called leds-ncp5623.
|
||||
|
||||
config LEDS_PWM_MULTICOLOR
|
||||
tristate "PWM driven multi-color LED Support"
|
||||
depends on PWM
|
||||
@ -41,6 +52,7 @@ config LEDS_QCOM_LPG
|
||||
tristate "LED support for Qualcomm LPG"
|
||||
depends on OF
|
||||
depends on PWM
|
||||
depends on QCOM_PBS || !QCOM_PBS
|
||||
depends on SPMI
|
||||
help
|
||||
This option enables support for the Light Pulse Generator found in a
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
obj-$(CONFIG_LEDS_GROUP_MULTICOLOR) += leds-group-multicolor.o
|
||||
obj-$(CONFIG_LEDS_KTD202X) += leds-ktd202x.o
|
||||
obj-$(CONFIG_LEDS_NCP5623) += leds-ncp5623.o
|
||||
obj-$(CONFIG_LEDS_PWM_MULTICOLOR) += leds-pwm-multicolor.o
|
||||
obj-$(CONFIG_LEDS_QCOM_LPG) += leds-qcom-lpg.o
|
||||
obj-$(CONFIG_LEDS_MT6370_RGB) += leds-mt6370-rgb.o
|
||||
|
@ -69,7 +69,7 @@ static int leds_gmc_probe(struct platform_device *pdev)
|
||||
struct mc_subled *subled;
|
||||
struct leds_multicolor *priv;
|
||||
unsigned int max_brightness = 0;
|
||||
int i, ret, count = 0;
|
||||
int i, ret, count = 0, common_flags = 0;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
@ -91,6 +91,7 @@ static int leds_gmc_probe(struct platform_device *pdev)
|
||||
if (!priv->monochromatics)
|
||||
return -ENOMEM;
|
||||
|
||||
common_flags |= led_cdev->flags;
|
||||
priv->monochromatics[count] = led_cdev;
|
||||
|
||||
max_brightness = max(max_brightness, led_cdev->max_brightness);
|
||||
@ -114,12 +115,15 @@ static int leds_gmc_probe(struct platform_device *pdev)
|
||||
|
||||
/* Initialise the multicolor's LED class device */
|
||||
cdev = &priv->mc_cdev.led_cdev;
|
||||
cdev->flags = LED_CORE_SUSPENDRESUME;
|
||||
cdev->brightness_set_blocking = leds_gmc_set;
|
||||
cdev->max_brightness = max_brightness;
|
||||
cdev->color = LED_COLOR_ID_MULTI;
|
||||
priv->mc_cdev.num_colors = count;
|
||||
|
||||
/* we only need suspend/resume if a sub-led requests it */
|
||||
if (common_flags & LED_CORE_SUSPENDRESUME)
|
||||
cdev->flags = LED_CORE_SUSPENDRESUME;
|
||||
|
||||
init_data.fwnode = dev_fwnode(dev);
|
||||
ret = devm_led_classdev_multicolor_register_ext(dev, &priv->mc_cdev, &init_data);
|
||||
if (ret)
|
||||
|
271
drivers/leds/rgb/leds-ncp5623.c
Normal file
271
drivers/leds/rgb/leds-ncp5623.c
Normal file
@ -0,0 +1,271 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* NCP5623 Multi-LED Driver
|
||||
*
|
||||
* Author: Abdel Alkuor <alkuor@gmail.com>
|
||||
* Datasheet: https://www.onsemi.com/pdf/datasheet/ncp5623-d.pdf
|
||||
*/
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/led-class-multicolor.h>
|
||||
|
||||
#define NCP5623_FUNCTION_OFFSET 0x5
|
||||
#define NCP5623_REG(x) ((x) << NCP5623_FUNCTION_OFFSET)
|
||||
|
||||
#define NCP5623_SHUTDOWN_REG NCP5623_REG(0x0)
|
||||
#define NCP5623_ILED_REG NCP5623_REG(0x1)
|
||||
#define NCP5623_PWM_REG(index) NCP5623_REG(0x2 + (index))
|
||||
#define NCP5623_UPWARD_STEP_REG NCP5623_REG(0x5)
|
||||
#define NCP5623_DOWNWARD_STEP_REG NCP5623_REG(0x6)
|
||||
#define NCP5623_DIMMING_TIME_REG NCP5623_REG(0x7)
|
||||
|
||||
#define NCP5623_MAX_BRIGHTNESS 0x1f
|
||||
#define NCP5623_MAX_DIM_TIME_MS 240
|
||||
#define NCP5623_DIM_STEP_MS 8
|
||||
|
||||
struct ncp5623 {
|
||||
struct i2c_client *client;
|
||||
struct led_classdev_mc mc_dev;
|
||||
struct mutex lock;
|
||||
|
||||
int current_brightness;
|
||||
unsigned long delay;
|
||||
};
|
||||
|
||||
static int ncp5623_write(struct i2c_client *client, u8 reg, u8 data)
|
||||
{
|
||||
return i2c_smbus_write_byte_data(client, reg | data, 0);
|
||||
}
|
||||
|
||||
static int ncp5623_brightness_set(struct led_classdev *cdev,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(cdev);
|
||||
struct ncp5623 *ncp = container_of(mc_cdev, struct ncp5623, mc_dev);
|
||||
int ret;
|
||||
|
||||
guard(mutex)(&ncp->lock);
|
||||
|
||||
if (ncp->delay && time_is_after_jiffies(ncp->delay))
|
||||
return -EBUSY;
|
||||
|
||||
ncp->delay = 0;
|
||||
|
||||
for (int i = 0; i < mc_cdev->num_colors; i++) {
|
||||
ret = ncp5623_write(ncp->client,
|
||||
NCP5623_PWM_REG(mc_cdev->subled_info[i].channel),
|
||||
min(mc_cdev->subled_info[i].intensity,
|
||||
NCP5623_MAX_BRIGHTNESS));
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ncp5623_write(ncp->client, NCP5623_DIMMING_TIME_REG, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ncp5623_write(ncp->client, NCP5623_ILED_REG, brightness);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ncp->current_brightness = brightness;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ncp5623_pattern_set(struct led_classdev *cdev,
|
||||
struct led_pattern *pattern,
|
||||
u32 len, int repeat)
|
||||
{
|
||||
struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(cdev);
|
||||
struct ncp5623 *ncp = container_of(mc_cdev, struct ncp5623, mc_dev);
|
||||
int brightness_diff;
|
||||
u8 reg;
|
||||
int ret;
|
||||
|
||||
guard(mutex)(&ncp->lock);
|
||||
|
||||
if (ncp->delay && time_is_after_jiffies(ncp->delay))
|
||||
return -EBUSY;
|
||||
|
||||
ncp->delay = 0;
|
||||
|
||||
if (pattern[0].delta_t > NCP5623_MAX_DIM_TIME_MS ||
|
||||
(pattern[0].delta_t % NCP5623_DIM_STEP_MS) != 0)
|
||||
return -EINVAL;
|
||||
|
||||
brightness_diff = pattern[0].brightness - ncp->current_brightness;
|
||||
|
||||
if (brightness_diff == 0)
|
||||
return 0;
|
||||
|
||||
if (pattern[0].delta_t) {
|
||||
if (brightness_diff > 0)
|
||||
reg = NCP5623_UPWARD_STEP_REG;
|
||||
else
|
||||
reg = NCP5623_DOWNWARD_STEP_REG;
|
||||
} else {
|
||||
reg = NCP5623_ILED_REG;
|
||||
}
|
||||
|
||||
ret = ncp5623_write(ncp->client, reg,
|
||||
min(pattern[0].brightness, NCP5623_MAX_BRIGHTNESS));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ncp5623_write(ncp->client,
|
||||
NCP5623_DIMMING_TIME_REG,
|
||||
pattern[0].delta_t / NCP5623_DIM_STEP_MS);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* During testing, when the brightness difference is 1, for some
|
||||
* unknown reason, the time factor it takes to change to the new
|
||||
* value is the longest time possible. Otherwise, the time factor
|
||||
* is simply the brightness difference.
|
||||
*
|
||||
* For example:
|
||||
* current_brightness = 20 and new_brightness = 21 then the time it
|
||||
* takes to set the new brightness increments to the maximum possible
|
||||
* brightness from 20 then from 0 to 21.
|
||||
* time_factor = max_brightness - 20 + 21
|
||||
*/
|
||||
if (abs(brightness_diff) == 1)
|
||||
ncp->delay = NCP5623_MAX_BRIGHTNESS + brightness_diff;
|
||||
else
|
||||
ncp->delay = abs(brightness_diff);
|
||||
|
||||
ncp->delay = msecs_to_jiffies(ncp->delay * pattern[0].delta_t) + jiffies;
|
||||
|
||||
ncp->current_brightness = pattern[0].brightness;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ncp5623_pattern_clear(struct led_classdev *led_cdev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ncp5623_probe(struct i2c_client *client)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct fwnode_handle *mc_node, *led_node;
|
||||
struct led_init_data init_data = { };
|
||||
int num_subleds = 0;
|
||||
struct ncp5623 *ncp;
|
||||
struct mc_subled *subled_info;
|
||||
u32 color_index;
|
||||
u32 reg;
|
||||
int ret;
|
||||
|
||||
ncp = devm_kzalloc(dev, sizeof(*ncp), GFP_KERNEL);
|
||||
if (!ncp)
|
||||
return -ENOMEM;
|
||||
|
||||
ncp->client = client;
|
||||
|
||||
mc_node = device_get_named_child_node(dev, "multi-led");
|
||||
if (!mc_node)
|
||||
return -EINVAL;
|
||||
|
||||
fwnode_for_each_child_node(mc_node, led_node)
|
||||
num_subleds++;
|
||||
|
||||
subled_info = devm_kcalloc(dev, num_subleds, sizeof(*subled_info), GFP_KERNEL);
|
||||
if (!subled_info) {
|
||||
ret = -ENOMEM;
|
||||
goto release_mc_node;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
ret = fwnode_property_read_u32(led_node, "reg", ®);
|
||||
if (ret) {
|
||||
fwnode_handle_put(led_node);
|
||||
goto release_mc_node;
|
||||
}
|
||||
|
||||
subled_info[ncp->mc_dev.num_colors].channel = reg;
|
||||
subled_info[ncp->mc_dev.num_colors++].color_index = color_index;
|
||||
}
|
||||
|
||||
init_data.fwnode = mc_node;
|
||||
|
||||
ncp->mc_dev.led_cdev.max_brightness = NCP5623_MAX_BRIGHTNESS;
|
||||
ncp->mc_dev.subled_info = subled_info;
|
||||
ncp->mc_dev.led_cdev.brightness_set_blocking = ncp5623_brightness_set;
|
||||
ncp->mc_dev.led_cdev.pattern_set = ncp5623_pattern_set;
|
||||
ncp->mc_dev.led_cdev.pattern_clear = ncp5623_pattern_clear;
|
||||
ncp->mc_dev.led_cdev.default_trigger = "pattern";
|
||||
|
||||
mutex_init(&ncp->lock);
|
||||
i2c_set_clientdata(client, ncp);
|
||||
|
||||
ret = led_classdev_multicolor_register_ext(dev, &ncp->mc_dev, &init_data);
|
||||
if (ret)
|
||||
goto destroy_lock;
|
||||
|
||||
return 0;
|
||||
|
||||
destroy_lock:
|
||||
mutex_destroy(&ncp->lock);
|
||||
|
||||
release_mc_node:
|
||||
fwnode_handle_put(mc_node);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ncp5623_remove(struct i2c_client *client)
|
||||
{
|
||||
struct ncp5623 *ncp = i2c_get_clientdata(client);
|
||||
|
||||
mutex_lock(&ncp->lock);
|
||||
ncp->delay = 0;
|
||||
mutex_unlock(&ncp->lock);
|
||||
|
||||
ncp5623_write(client, NCP5623_DIMMING_TIME_REG, 0);
|
||||
led_classdev_multicolor_unregister(&ncp->mc_dev);
|
||||
mutex_destroy(&ncp->lock);
|
||||
}
|
||||
|
||||
static void ncp5623_shutdown(struct i2c_client *client)
|
||||
{
|
||||
struct ncp5623 *ncp = i2c_get_clientdata(client);
|
||||
|
||||
if (!(ncp->mc_dev.led_cdev.flags & LED_RETAIN_AT_SHUTDOWN))
|
||||
ncp5623_write(client, NCP5623_SHUTDOWN_REG, 0);
|
||||
|
||||
mutex_destroy(&ncp->lock);
|
||||
}
|
||||
|
||||
static const struct of_device_id ncp5623_id[] = {
|
||||
{ .compatible = "onnn,ncp5623" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ncp5623_id);
|
||||
|
||||
static struct i2c_driver ncp5623_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "ncp5623",
|
||||
.of_match_table = ncp5623_id,
|
||||
},
|
||||
.probe = ncp5623_probe,
|
||||
.remove = ncp5623_remove,
|
||||
.shutdown = ncp5623_shutdown,
|
||||
};
|
||||
|
||||
module_i2c_driver(ncp5623_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Abdel Alkuor <alkuor@gmail.com>");
|
||||
MODULE_DESCRIPTION("NCP5623 Multi-LED driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -8,11 +8,13 @@
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/led-class-multicolor.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/nvmem-consumer.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pwm.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/soc/qcom/qcom-pbs.h>
|
||||
|
||||
#define LPG_SUBTYPE_REG 0x05
|
||||
#define LPG_SUBTYPE_LPG 0x2
|
||||
@ -39,6 +41,10 @@
|
||||
#define PWM_SEC_ACCESS_REG 0xd0
|
||||
#define PWM_DTEST_REG(x) (0xe2 + (x) - 1)
|
||||
|
||||
#define SDAM_REG_PBS_SEQ_EN 0x42
|
||||
#define SDAM_PBS_TRIG_SET 0xe5
|
||||
#define SDAM_PBS_TRIG_CLR 0xe6
|
||||
|
||||
#define TRI_LED_SRC_SEL 0x45
|
||||
#define TRI_LED_EN_CTL 0x46
|
||||
#define TRI_LED_ATC_CTL 0x47
|
||||
@ -48,9 +54,31 @@
|
||||
|
||||
#define LPG_RESOLUTION_9BIT BIT(9)
|
||||
#define LPG_RESOLUTION_15BIT BIT(15)
|
||||
#define PPG_MAX_LED_BRIGHTNESS 255
|
||||
|
||||
#define LPG_MAX_M 7
|
||||
#define LPG_MAX_PREDIV 6
|
||||
|
||||
#define DEFAULT_TICK_DURATION_US 7800
|
||||
#define RAMP_STEP_DURATION(x) (((x) * 1000 / DEFAULT_TICK_DURATION_US) & 0xff)
|
||||
|
||||
#define SDAM_MAX_DEVICES 2
|
||||
/* LPG common config settings for PPG */
|
||||
#define SDAM_START_BASE 0x40
|
||||
#define SDAM_REG_RAMP_STEP_DURATION 0x47
|
||||
|
||||
#define SDAM_LUT_SDAM_LUT_PATTERN_OFFSET 0x45
|
||||
#define SDAM_LPG_SDAM_LUT_PATTERN_OFFSET 0x80
|
||||
|
||||
/* LPG per channel config settings for PPG */
|
||||
#define SDAM_LUT_EN_OFFSET 0x0
|
||||
#define SDAM_PATTERN_CONFIG_OFFSET 0x1
|
||||
#define SDAM_END_INDEX_OFFSET 0x3
|
||||
#define SDAM_START_INDEX_OFFSET 0x4
|
||||
#define SDAM_PBS_SCRATCH_LUT_COUNTER_OFFSET 0x6
|
||||
#define SDAM_PAUSE_HI_MULTIPLIER_OFFSET 0x8
|
||||
#define SDAM_PAUSE_LO_MULTIPLIER_OFFSET 0x9
|
||||
|
||||
struct lpg_channel;
|
||||
struct lpg_data;
|
||||
|
||||
@ -64,6 +92,10 @@ struct lpg_data;
|
||||
* @lut_base: base address of the LUT block (optional)
|
||||
* @lut_size: number of entries in the LUT block
|
||||
* @lut_bitmap: allocation bitmap for LUT entries
|
||||
* @pbs_dev: PBS device
|
||||
* @lpg_chan_sdam: LPG SDAM peripheral device
|
||||
* @lut_sdam: LUT SDAM peripheral device
|
||||
* @pbs_en_bitmap: bitmap for tracking PBS triggers
|
||||
* @triled_base: base address of the TRILED block (optional)
|
||||
* @triled_src: power-source for the TRILED
|
||||
* @triled_has_atc_ctl: true if there is TRI_LED_ATC_CTL register
|
||||
@ -85,6 +117,11 @@ struct lpg {
|
||||
u32 lut_size;
|
||||
unsigned long *lut_bitmap;
|
||||
|
||||
struct pbs_dev *pbs_dev;
|
||||
struct nvmem_device *lpg_chan_sdam;
|
||||
struct nvmem_device *lut_sdam;
|
||||
unsigned long pbs_en_bitmap;
|
||||
|
||||
u32 triled_base;
|
||||
u32 triled_src;
|
||||
bool triled_has_atc_ctl;
|
||||
@ -101,6 +138,7 @@ struct lpg {
|
||||
* @triled_mask: mask in TRILED to enable this channel
|
||||
* @lut_mask: mask in LUT to start pattern generator for this channel
|
||||
* @subtype: PMIC hardware block subtype
|
||||
* @sdam_offset: channel offset in LPG SDAM
|
||||
* @in_use: channel is exposed to LED framework
|
||||
* @color: color of the LED attached to this channel
|
||||
* @dtest_line: DTEST line for output, or 0 if disabled
|
||||
@ -129,6 +167,7 @@ struct lpg_channel {
|
||||
unsigned int triled_mask;
|
||||
unsigned int lut_mask;
|
||||
unsigned int subtype;
|
||||
u32 sdam_offset;
|
||||
|
||||
bool in_use;
|
||||
|
||||
@ -178,10 +217,12 @@ struct lpg_led {
|
||||
|
||||
/**
|
||||
* struct lpg_channel_data - per channel initialization data
|
||||
* @sdam_offset: Channel offset in LPG SDAM
|
||||
* @base: base address for PWM channel registers
|
||||
* @triled_mask: bitmask for controlling this channel in TRILED
|
||||
*/
|
||||
struct lpg_channel_data {
|
||||
unsigned int sdam_offset;
|
||||
unsigned int base;
|
||||
u8 triled_mask;
|
||||
};
|
||||
@ -206,6 +247,65 @@ struct lpg_data {
|
||||
const struct lpg_channel_data *channels;
|
||||
};
|
||||
|
||||
#define PBS_SW_TRIG_BIT BIT(0)
|
||||
|
||||
static int lpg_clear_pbs_trigger(struct lpg *lpg, unsigned int lut_mask)
|
||||
{
|
||||
u8 val = 0;
|
||||
int rc;
|
||||
|
||||
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);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
if (lpg->lut_sdam) {
|
||||
val = PBS_SW_TRIG_BIT;
|
||||
rc = nvmem_device_write(lpg->lpg_chan_sdam, SDAM_PBS_TRIG_CLR, 1, &val);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lpg_set_pbs_trigger(struct lpg *lpg, unsigned int lut_mask)
|
||||
{
|
||||
u8 val = PBS_SW_TRIG_BIT;
|
||||
int rc;
|
||||
|
||||
if (!lpg->pbs_en_bitmap) {
|
||||
rc = nvmem_device_write(lpg->lpg_chan_sdam, SDAM_REG_PBS_SEQ_EN, 1, &val);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
if (lpg->lut_sdam) {
|
||||
rc = nvmem_device_write(lpg->lpg_chan_sdam, SDAM_PBS_TRIG_SET, 1, &val);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
} else {
|
||||
rc = qcom_pbs_trigger_event(lpg->pbs_dev, val);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
lpg->pbs_en_bitmap |= lut_mask;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lpg_sdam_configure_triggers(struct lpg_channel *chan, u8 set_trig)
|
||||
{
|
||||
u32 addr = SDAM_LUT_EN_OFFSET + chan->sdam_offset;
|
||||
|
||||
if (!chan->lpg->lpg_chan_sdam)
|
||||
return 0;
|
||||
|
||||
return nvmem_device_write(chan->lpg->lpg_chan_sdam, addr, 1, &set_trig);
|
||||
}
|
||||
|
||||
static int triled_set(struct lpg *lpg, unsigned int mask, unsigned int enable)
|
||||
{
|
||||
/* Skip if we don't have a triled block */
|
||||
@ -216,6 +316,47 @@ static int triled_set(struct lpg *lpg, unsigned int mask, unsigned int enable)
|
||||
mask, enable);
|
||||
}
|
||||
|
||||
static int lpg_lut_store_sdam(struct lpg *lpg, struct led_pattern *pattern,
|
||||
size_t len, unsigned int *lo_idx, unsigned int *hi_idx)
|
||||
{
|
||||
unsigned int idx;
|
||||
u8 brightness;
|
||||
int i, rc;
|
||||
u16 addr;
|
||||
|
||||
if (len > lpg->lut_size) {
|
||||
dev_err(lpg->dev, "Pattern length (%zu) exceeds maximum pattern length (%d)\n",
|
||||
len, lpg->lut_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
idx = bitmap_find_next_zero_area(lpg->lut_bitmap, lpg->lut_size, 0, len, 0);
|
||||
if (idx >= lpg->lut_size)
|
||||
return -ENOSPC;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
brightness = pattern[i].brightness;
|
||||
|
||||
if (lpg->lut_sdam) {
|
||||
addr = SDAM_LUT_SDAM_LUT_PATTERN_OFFSET + i + idx;
|
||||
rc = nvmem_device_write(lpg->lut_sdam, addr, 1, &brightness);
|
||||
} else {
|
||||
addr = SDAM_LPG_SDAM_LUT_PATTERN_OFFSET + i + idx;
|
||||
rc = nvmem_device_write(lpg->lpg_chan_sdam, addr, 1, &brightness);
|
||||
}
|
||||
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
}
|
||||
|
||||
bitmap_set(lpg->lut_bitmap, idx, len);
|
||||
|
||||
*lo_idx = idx;
|
||||
*hi_idx = idx + len - 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lpg_lut_store(struct lpg *lpg, struct led_pattern *pattern,
|
||||
size_t len, unsigned int *lo_idx, unsigned int *hi_idx)
|
||||
{
|
||||
@ -256,6 +397,9 @@ static void lpg_lut_free(struct lpg *lpg, unsigned int lo_idx, unsigned int hi_i
|
||||
|
||||
static int lpg_lut_sync(struct lpg *lpg, unsigned int mask)
|
||||
{
|
||||
if (!lpg->lut_base)
|
||||
return 0;
|
||||
|
||||
return regmap_write(lpg->map, lpg->lut_base + RAMP_CONTROL_REG, mask);
|
||||
}
|
||||
|
||||
@ -462,6 +606,49 @@ static void lpg_apply_pwm_value(struct lpg_channel *chan)
|
||||
#define LPG_PATTERN_CONFIG_PAUSE_HI BIT(1)
|
||||
#define LPG_PATTERN_CONFIG_PAUSE_LO BIT(0)
|
||||
|
||||
static void lpg_sdam_apply_lut_control(struct lpg_channel *chan)
|
||||
{
|
||||
struct nvmem_device *lpg_chan_sdam = chan->lpg->lpg_chan_sdam;
|
||||
unsigned int lo_idx = chan->pattern_lo_idx;
|
||||
unsigned int hi_idx = chan->pattern_hi_idx;
|
||||
u8 val = 0, conf = 0, lut_offset = 0;
|
||||
unsigned int hi_pause, lo_pause;
|
||||
struct lpg *lpg = chan->lpg;
|
||||
|
||||
if (!chan->ramp_enabled || chan->pattern_lo_idx == chan->pattern_hi_idx)
|
||||
return;
|
||||
|
||||
hi_pause = DIV_ROUND_UP(chan->ramp_hi_pause_ms, chan->ramp_tick_ms);
|
||||
lo_pause = DIV_ROUND_UP(chan->ramp_lo_pause_ms, chan->ramp_tick_ms);
|
||||
|
||||
if (!chan->ramp_oneshot)
|
||||
conf |= LPG_PATTERN_CONFIG_REPEAT;
|
||||
if (chan->ramp_hi_pause_ms && lpg->lut_sdam)
|
||||
conf |= LPG_PATTERN_CONFIG_PAUSE_HI;
|
||||
if (chan->ramp_lo_pause_ms && lpg->lut_sdam)
|
||||
conf |= LPG_PATTERN_CONFIG_PAUSE_LO;
|
||||
|
||||
if (lpg->lut_sdam) {
|
||||
lut_offset = SDAM_LUT_SDAM_LUT_PATTERN_OFFSET - SDAM_START_BASE;
|
||||
hi_idx += lut_offset;
|
||||
lo_idx += lut_offset;
|
||||
}
|
||||
|
||||
nvmem_device_write(lpg_chan_sdam, SDAM_PBS_SCRATCH_LUT_COUNTER_OFFSET + chan->sdam_offset, 1, &val);
|
||||
nvmem_device_write(lpg_chan_sdam, SDAM_PATTERN_CONFIG_OFFSET + chan->sdam_offset, 1, &conf);
|
||||
nvmem_device_write(lpg_chan_sdam, SDAM_END_INDEX_OFFSET + chan->sdam_offset, 1, &hi_idx);
|
||||
nvmem_device_write(lpg_chan_sdam, SDAM_START_INDEX_OFFSET + chan->sdam_offset, 1, &lo_idx);
|
||||
|
||||
val = RAMP_STEP_DURATION(chan->ramp_tick_ms);
|
||||
nvmem_device_write(lpg_chan_sdam, SDAM_REG_RAMP_STEP_DURATION, 1, &val);
|
||||
|
||||
if (lpg->lut_sdam) {
|
||||
nvmem_device_write(lpg_chan_sdam, SDAM_PAUSE_HI_MULTIPLIER_OFFSET + chan->sdam_offset, 1, &hi_pause);
|
||||
nvmem_device_write(lpg_chan_sdam, SDAM_PAUSE_LO_MULTIPLIER_OFFSET + chan->sdam_offset, 1, &lo_pause);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void lpg_apply_lut_control(struct lpg_channel *chan)
|
||||
{
|
||||
struct lpg *lpg = chan->lpg;
|
||||
@ -596,7 +783,10 @@ static void lpg_apply(struct lpg_channel *chan)
|
||||
lpg_apply_pwm_value(chan);
|
||||
lpg_apply_control(chan);
|
||||
lpg_apply_sync(chan);
|
||||
lpg_apply_lut_control(chan);
|
||||
if (chan->lpg->lpg_chan_sdam)
|
||||
lpg_sdam_apply_lut_control(chan);
|
||||
else
|
||||
lpg_apply_lut_control(chan);
|
||||
lpg_enable_glitch(chan);
|
||||
}
|
||||
|
||||
@ -621,6 +811,7 @@ static void lpg_brightness_set(struct lpg_led *led, struct led_classdev *cdev,
|
||||
chan->ramp_enabled = false;
|
||||
} else if (chan->pattern_lo_idx != chan->pattern_hi_idx) {
|
||||
lpg_calc_freq(chan, NSEC_PER_MSEC);
|
||||
lpg_sdam_configure_triggers(chan, 1);
|
||||
|
||||
chan->enabled = true;
|
||||
chan->ramp_enabled = true;
|
||||
@ -648,8 +839,10 @@ static void lpg_brightness_set(struct lpg_led *led, struct led_classdev *cdev,
|
||||
triled_set(lpg, triled_mask, triled_enabled);
|
||||
|
||||
/* Trigger start of ramp generator(s) */
|
||||
if (lut_mask)
|
||||
if (lut_mask) {
|
||||
lpg_lut_sync(lpg, lut_mask);
|
||||
lpg_set_pbs_trigger(lpg, lut_mask);
|
||||
}
|
||||
}
|
||||
|
||||
static int lpg_brightness_single_set(struct led_classdev *cdev,
|
||||
@ -766,9 +959,9 @@ static int lpg_pattern_set(struct lpg_led *led, struct led_pattern *led_pattern,
|
||||
struct led_pattern *pattern;
|
||||
unsigned int brightness_a;
|
||||
unsigned int brightness_b;
|
||||
unsigned int hi_pause = 0;
|
||||
unsigned int lo_pause = 0;
|
||||
unsigned int actual_len;
|
||||
unsigned int hi_pause;
|
||||
unsigned int lo_pause;
|
||||
unsigned int delta_t;
|
||||
unsigned int lo_idx;
|
||||
unsigned int hi_idx;
|
||||
@ -835,18 +1028,24 @@ static int lpg_pattern_set(struct lpg_led *led, struct led_pattern *led_pattern,
|
||||
* If the specified pattern is a palindrome the ping pong mode is
|
||||
* enabled. In this scenario the delta_t of the middle entry (i.e. the
|
||||
* last in the programmed pattern) determines the "high pause".
|
||||
*
|
||||
* SDAM-based devices do not support "ping pong", and only supports
|
||||
* "low pause" and "high pause" with a dedicated SDAM LUT.
|
||||
*/
|
||||
|
||||
/* Detect palindromes and use "ping pong" to reduce LUT usage */
|
||||
for (i = 0; i < len / 2; i++) {
|
||||
brightness_a = pattern[i].brightness;
|
||||
brightness_b = pattern[len - i - 1].brightness;
|
||||
if (lpg->lut_base) {
|
||||
for (i = 0; i < len / 2; i++) {
|
||||
brightness_a = pattern[i].brightness;
|
||||
brightness_b = pattern[len - i - 1].brightness;
|
||||
|
||||
if (brightness_a != brightness_b) {
|
||||
ping_pong = false;
|
||||
break;
|
||||
if (brightness_a != brightness_b) {
|
||||
ping_pong = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else
|
||||
ping_pong = false;
|
||||
|
||||
/* The pattern length to be written to the LUT */
|
||||
if (ping_pong)
|
||||
@ -874,12 +1073,27 @@ static int lpg_pattern_set(struct lpg_led *led, struct led_pattern *led_pattern,
|
||||
if (delta_t >= BIT(9))
|
||||
goto out_free_pattern;
|
||||
|
||||
/* Find "low pause" and "high pause" in the pattern */
|
||||
lo_pause = pattern[0].delta_t;
|
||||
hi_pause = pattern[actual_len - 1].delta_t;
|
||||
/*
|
||||
* Find "low pause" and "high pause" in the pattern in the LUT case.
|
||||
* SDAM-based devices without dedicated LUT SDAM require equal
|
||||
* duration of all steps.
|
||||
*/
|
||||
if (lpg->lut_base || lpg->lut_sdam) {
|
||||
lo_pause = pattern[0].delta_t;
|
||||
hi_pause = pattern[actual_len - 1].delta_t;
|
||||
} else {
|
||||
if (delta_t != pattern[0].delta_t || delta_t != pattern[actual_len - 1].delta_t)
|
||||
goto out_free_pattern;
|
||||
}
|
||||
|
||||
|
||||
mutex_lock(&lpg->lock);
|
||||
ret = lpg_lut_store(lpg, pattern, actual_len, &lo_idx, &hi_idx);
|
||||
|
||||
if (lpg->lut_base)
|
||||
ret = lpg_lut_store(lpg, pattern, actual_len, &lo_idx, &hi_idx);
|
||||
else
|
||||
ret = lpg_lut_store_sdam(lpg, pattern, actual_len, &lo_idx, &hi_idx);
|
||||
|
||||
if (ret < 0)
|
||||
goto out_unlock;
|
||||
|
||||
@ -927,7 +1141,12 @@ static int lpg_pattern_mc_set(struct led_classdev *cdev,
|
||||
{
|
||||
struct led_classdev_mc *mc = lcdev_to_mccdev(cdev);
|
||||
struct lpg_led *led = container_of(mc, struct lpg_led, mcdev);
|
||||
int ret;
|
||||
unsigned int triled_mask = 0;
|
||||
int ret, i;
|
||||
|
||||
for (i = 0; i < led->num_channels; i++)
|
||||
triled_mask |= led->channels[i]->triled_mask;
|
||||
triled_set(led->lpg, triled_mask, 0);
|
||||
|
||||
ret = lpg_pattern_set(led, pattern, len, repeat);
|
||||
if (ret < 0)
|
||||
@ -952,6 +1171,8 @@ static int lpg_pattern_clear(struct lpg_led *led)
|
||||
|
||||
for (i = 0; i < led->num_channels; i++) {
|
||||
chan = led->channels[i];
|
||||
lpg_sdam_configure_triggers(chan, 0);
|
||||
lpg_clear_pbs_trigger(chan->lpg, chan->lut_mask);
|
||||
chan->pattern_lo_idx = 0;
|
||||
chan->pattern_hi_idx = 0;
|
||||
}
|
||||
@ -1191,8 +1412,8 @@ static int lpg_add_led(struct lpg *lpg, struct device_node *np)
|
||||
cdev->brightness_set_blocking = lpg_brightness_mc_set;
|
||||
cdev->blink_set = lpg_blink_mc_set;
|
||||
|
||||
/* Register pattern accessors only if we have a LUT block */
|
||||
if (lpg->lut_base) {
|
||||
/* Register pattern accessors if we have a LUT block or when using PPG */
|
||||
if (lpg->lut_base || lpg->lpg_chan_sdam) {
|
||||
cdev->pattern_set = lpg_pattern_mc_set;
|
||||
cdev->pattern_clear = lpg_pattern_mc_clear;
|
||||
}
|
||||
@ -1205,15 +1426,19 @@ static int lpg_add_led(struct lpg *lpg, struct device_node *np)
|
||||
cdev->brightness_set_blocking = lpg_brightness_single_set;
|
||||
cdev->blink_set = lpg_blink_single_set;
|
||||
|
||||
/* Register pattern accessors only if we have a LUT block */
|
||||
if (lpg->lut_base) {
|
||||
/* Register pattern accessors if we have a LUT block or when using PPG */
|
||||
if (lpg->lut_base || lpg->lpg_chan_sdam) {
|
||||
cdev->pattern_set = lpg_pattern_single_set;
|
||||
cdev->pattern_clear = lpg_pattern_single_clear;
|
||||
}
|
||||
}
|
||||
|
||||
cdev->default_trigger = of_get_property(np, "linux,default-trigger", NULL);
|
||||
cdev->max_brightness = LPG_RESOLUTION_9BIT - 1;
|
||||
|
||||
if (lpg->lpg_chan_sdam)
|
||||
cdev->max_brightness = PPG_MAX_LED_BRIGHTNESS;
|
||||
else
|
||||
cdev->max_brightness = LPG_RESOLUTION_9BIT - 1;
|
||||
|
||||
if (!of_property_read_string(np, "default-state", &state) &&
|
||||
!strcmp(state, "on"))
|
||||
@ -1254,6 +1479,7 @@ static int lpg_init_channels(struct lpg *lpg)
|
||||
chan->base = data->channels[i].base;
|
||||
chan->triled_mask = data->channels[i].triled_mask;
|
||||
chan->lut_mask = BIT(i);
|
||||
chan->sdam_offset = data->channels[i].sdam_offset;
|
||||
|
||||
regmap_read(lpg->map, chan->base + LPG_SUBTYPE_REG, &chan->subtype);
|
||||
}
|
||||
@ -1299,11 +1525,12 @@ static int lpg_init_lut(struct lpg *lpg)
|
||||
{
|
||||
const struct lpg_data *data = lpg->data;
|
||||
|
||||
if (!data->lut_base)
|
||||
if (!data->lut_size)
|
||||
return 0;
|
||||
|
||||
lpg->lut_base = data->lut_base;
|
||||
lpg->lut_size = data->lut_size;
|
||||
if (data->lut_base)
|
||||
lpg->lut_base = data->lut_base;
|
||||
|
||||
lpg->lut_bitmap = devm_bitmap_zalloc(lpg->dev, lpg->lut_size, GFP_KERNEL);
|
||||
if (!lpg->lut_bitmap)
|
||||
@ -1312,6 +1539,59 @@ static int lpg_init_lut(struct lpg *lpg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lpg_init_sdam(struct lpg *lpg)
|
||||
{
|
||||
int i, sdam_count, rc;
|
||||
u8 val = 0;
|
||||
|
||||
sdam_count = of_property_count_strings(lpg->dev->of_node, "nvmem-names");
|
||||
if (sdam_count <= 0)
|
||||
return 0;
|
||||
if (sdam_count > SDAM_MAX_DEVICES)
|
||||
return -EINVAL;
|
||||
|
||||
/* Get the 1st SDAM device for LPG/LUT config */
|
||||
lpg->lpg_chan_sdam = devm_nvmem_device_get(lpg->dev, "lpg_chan_sdam");
|
||||
if (IS_ERR(lpg->lpg_chan_sdam))
|
||||
return dev_err_probe(lpg->dev, PTR_ERR(lpg->lpg_chan_sdam),
|
||||
"Failed to get LPG chan SDAM device\n");
|
||||
|
||||
if (sdam_count == 1) {
|
||||
/* Get PBS device node if single SDAM device */
|
||||
lpg->pbs_dev = get_pbs_client_device(lpg->dev);
|
||||
if (IS_ERR(lpg->pbs_dev))
|
||||
return dev_err_probe(lpg->dev, PTR_ERR(lpg->pbs_dev),
|
||||
"Failed to get PBS client device\n");
|
||||
} else if (sdam_count == 2) {
|
||||
/* Get the 2nd SDAM device for LUT pattern */
|
||||
lpg->lut_sdam = devm_nvmem_device_get(lpg->dev, "lut_sdam");
|
||||
if (IS_ERR(lpg->lut_sdam))
|
||||
return dev_err_probe(lpg->dev, PTR_ERR(lpg->lut_sdam),
|
||||
"Failed to get LPG LUT SDAM device\n");
|
||||
}
|
||||
|
||||
for (i = 0; i < lpg->num_channels; i++) {
|
||||
struct lpg_channel *chan = &lpg->channels[i];
|
||||
|
||||
if (chan->sdam_offset) {
|
||||
rc = nvmem_device_write(lpg->lpg_chan_sdam,
|
||||
SDAM_PBS_SCRATCH_LUT_COUNTER_OFFSET + chan->sdam_offset, 1, &val);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = lpg_sdam_configure_triggers(chan, 0);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = lpg_clear_pbs_trigger(chan->lpg, chan->lut_mask);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lpg_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np;
|
||||
@ -1346,6 +1626,10 @@ static int lpg_probe(struct platform_device *pdev)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = lpg_init_sdam(lpg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = lpg_init_lut(lpg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@ -1364,6 +1648,23 @@ static int lpg_probe(struct platform_device *pdev)
|
||||
return lpg_add_pwm(lpg);
|
||||
}
|
||||
|
||||
static const struct lpg_data pm660l_lpg_data = {
|
||||
.lut_base = 0xb000,
|
||||
.lut_size = 49,
|
||||
|
||||
.triled_base = 0xd000,
|
||||
.triled_has_atc_ctl = true,
|
||||
.triled_has_src_sel = true,
|
||||
|
||||
.num_channels = 4,
|
||||
.channels = (const struct lpg_channel_data[]) {
|
||||
{ .base = 0xb100, .triled_mask = BIT(5) },
|
||||
{ .base = 0xb200, .triled_mask = BIT(6) },
|
||||
{ .base = 0xb300, .triled_mask = BIT(7) },
|
||||
{ .base = 0xb400 },
|
||||
},
|
||||
};
|
||||
|
||||
static const struct lpg_data pm8916_pwm_data = {
|
||||
.num_channels = 1,
|
||||
.channels = (const struct lpg_channel_data[]) {
|
||||
@ -1411,11 +1712,13 @@ static const struct lpg_data pm8994_lpg_data = {
|
||||
static const struct lpg_data pmi632_lpg_data = {
|
||||
.triled_base = 0xd000,
|
||||
|
||||
.lut_size = 64,
|
||||
|
||||
.num_channels = 5,
|
||||
.channels = (const struct lpg_channel_data[]) {
|
||||
{ .base = 0xb300, .triled_mask = BIT(7) },
|
||||
{ .base = 0xb400, .triled_mask = BIT(6) },
|
||||
{ .base = 0xb500, .triled_mask = BIT(5) },
|
||||
{ .base = 0xb300, .triled_mask = BIT(7), .sdam_offset = 0x48 },
|
||||
{ .base = 0xb400, .triled_mask = BIT(6), .sdam_offset = 0x56 },
|
||||
{ .base = 0xb500, .triled_mask = BIT(5), .sdam_offset = 0x64 },
|
||||
{ .base = 0xb600 },
|
||||
{ .base = 0xb700 },
|
||||
},
|
||||
@ -1488,11 +1791,13 @@ static const struct lpg_data pm8150l_lpg_data = {
|
||||
static const struct lpg_data pm8350c_pwm_data = {
|
||||
.triled_base = 0xef00,
|
||||
|
||||
.lut_size = 122,
|
||||
|
||||
.num_channels = 4,
|
||||
.channels = (const struct lpg_channel_data[]) {
|
||||
{ .base = 0xe800, .triled_mask = BIT(7) },
|
||||
{ .base = 0xe900, .triled_mask = BIT(6) },
|
||||
{ .base = 0xea00, .triled_mask = BIT(5) },
|
||||
{ .base = 0xe800, .triled_mask = BIT(7), .sdam_offset = 0x48 },
|
||||
{ .base = 0xe900, .triled_mask = BIT(6), .sdam_offset = 0x56 },
|
||||
{ .base = 0xea00, .triled_mask = BIT(5), .sdam_offset = 0x64 },
|
||||
{ .base = 0xeb00 },
|
||||
},
|
||||
};
|
||||
@ -1506,6 +1811,7 @@ static const struct lpg_data pmk8550_pwm_data = {
|
||||
};
|
||||
|
||||
static const struct of_device_id lpg_of_table[] = {
|
||||
{ .compatible = "qcom,pm660l-lpg", .data = &pm660l_lpg_data },
|
||||
{ .compatible = "qcom,pm8150b-lpg", .data = &pm8150b_lpg_data },
|
||||
{ .compatible = "qcom,pm8150l-lpg", .data = &pm8150l_lpg_data },
|
||||
{ .compatible = "qcom,pm8350c-pwm", .data = &pm8350c_pwm_data },
|
||||
|
@ -63,3 +63,5 @@ module_exit(ledtrig_audio_exit);
|
||||
|
||||
MODULE_DESCRIPTION("LED trigger for audio mute control");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("ledtrig:audio-mute");
|
||||
MODULE_ALIAS("ledtrig:audio-micmute");
|
||||
|
@ -28,3 +28,4 @@ module_led_trigger(defon_led_trigger);
|
||||
MODULE_AUTHOR("Nick Forbes <nick.forbes@incepta.com>");
|
||||
MODULE_DESCRIPTION("Default-ON LED trigger");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("ledtrig:default-on");
|
||||
|
@ -18,10 +18,12 @@
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/linkmode.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/timer.h>
|
||||
#include "../leds.h"
|
||||
@ -65,12 +67,15 @@ struct led_netdev_data {
|
||||
|
||||
unsigned long mode;
|
||||
int link_speed;
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(supported_link_modes);
|
||||
u8 duplex;
|
||||
|
||||
bool carrier_link_up;
|
||||
bool hw_control;
|
||||
};
|
||||
|
||||
static const struct attribute_group netdev_trig_link_speed_attrs_group;
|
||||
|
||||
static void set_baseline_state(struct led_netdev_data *trigger_data)
|
||||
{
|
||||
int current_brightness;
|
||||
@ -218,13 +223,20 @@ static void get_device_state(struct led_netdev_data *trigger_data)
|
||||
struct ethtool_link_ksettings cmd;
|
||||
|
||||
trigger_data->carrier_link_up = netif_carrier_ok(trigger_data->net_dev);
|
||||
if (!trigger_data->carrier_link_up)
|
||||
|
||||
if (__ethtool_get_link_ksettings(trigger_data->net_dev, &cmd))
|
||||
return;
|
||||
|
||||
if (!__ethtool_get_link_ksettings(trigger_data->net_dev, &cmd)) {
|
||||
if (trigger_data->carrier_link_up) {
|
||||
trigger_data->link_speed = cmd.base.speed;
|
||||
trigger_data->duplex = cmd.base.duplex;
|
||||
}
|
||||
|
||||
/*
|
||||
* Have a local copy of the link speed supported to avoid rtnl lock every time
|
||||
* modes are refreshed on any change event
|
||||
*/
|
||||
linkmode_copy(trigger_data->supported_link_modes, cmd.link_modes.supported);
|
||||
}
|
||||
|
||||
static ssize_t device_name_show(struct device *dev,
|
||||
@ -277,7 +289,10 @@ static int set_device_name(struct led_netdev_data *trigger_data,
|
||||
|
||||
trigger_data->last_activity = 0;
|
||||
|
||||
set_baseline_state(trigger_data);
|
||||
/* Skip if we're called from netdev_trig_activate() and hw_control is true */
|
||||
if (!trigger_data->hw_control || led_get_trigger_data(trigger_data->led_cdev))
|
||||
set_baseline_state(trigger_data);
|
||||
|
||||
mutex_unlock(&trigger_data->lock);
|
||||
rtnl_unlock();
|
||||
|
||||
@ -295,6 +310,10 @@ static ssize_t device_name_store(struct device *dev,
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Refresh link_speed visibility */
|
||||
sysfs_update_group(&dev->kobj, &netdev_trig_link_speed_attrs_group);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
@ -458,15 +477,63 @@ static ssize_t offloaded_show(struct device *dev,
|
||||
|
||||
static DEVICE_ATTR_RO(offloaded);
|
||||
|
||||
static struct attribute *netdev_trig_attrs[] = {
|
||||
&dev_attr_device_name.attr,
|
||||
&dev_attr_link.attr,
|
||||
#define CHECK_LINK_MODE_ATTR(link_speed) \
|
||||
do { \
|
||||
if (attr == &dev_attr_link_##link_speed.attr && \
|
||||
link_ksettings.base.speed == SPEED_##link_speed) \
|
||||
return attr->mode; \
|
||||
} while (0)
|
||||
|
||||
static umode_t netdev_trig_link_speed_visible(struct kobject *kobj,
|
||||
struct attribute *attr, int n)
|
||||
{
|
||||
struct device *dev = kobj_to_dev(kobj);
|
||||
struct led_netdev_data *trigger_data;
|
||||
unsigned long *supported_link_modes;
|
||||
u32 mode;
|
||||
|
||||
trigger_data = led_trigger_get_drvdata(dev);
|
||||
supported_link_modes = trigger_data->supported_link_modes;
|
||||
|
||||
/*
|
||||
* Search in the supported link mode mask a matching supported mode.
|
||||
* Stop at the first matching entry as we care only to check if a particular
|
||||
* speed is supported and not the kind.
|
||||
*/
|
||||
for_each_set_bit(mode, supported_link_modes, __ETHTOOL_LINK_MODE_MASK_NBITS) {
|
||||
struct ethtool_link_ksettings link_ksettings;
|
||||
|
||||
ethtool_params_from_link_mode(&link_ksettings, mode);
|
||||
|
||||
CHECK_LINK_MODE_ATTR(10);
|
||||
CHECK_LINK_MODE_ATTR(100);
|
||||
CHECK_LINK_MODE_ATTR(1000);
|
||||
CHECK_LINK_MODE_ATTR(2500);
|
||||
CHECK_LINK_MODE_ATTR(5000);
|
||||
CHECK_LINK_MODE_ATTR(10000);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct attribute *netdev_trig_link_speed_attrs[] = {
|
||||
&dev_attr_link_10.attr,
|
||||
&dev_attr_link_100.attr,
|
||||
&dev_attr_link_1000.attr,
|
||||
&dev_attr_link_2500.attr,
|
||||
&dev_attr_link_5000.attr,
|
||||
&dev_attr_link_10000.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group netdev_trig_link_speed_attrs_group = {
|
||||
.attrs = netdev_trig_link_speed_attrs,
|
||||
.is_visible = netdev_trig_link_speed_visible,
|
||||
};
|
||||
|
||||
static struct attribute *netdev_trig_attrs[] = {
|
||||
&dev_attr_device_name.attr,
|
||||
&dev_attr_link.attr,
|
||||
&dev_attr_full_duplex.attr,
|
||||
&dev_attr_half_duplex.attr,
|
||||
&dev_attr_rx.attr,
|
||||
@ -475,7 +542,16 @@ static struct attribute *netdev_trig_attrs[] = {
|
||||
&dev_attr_offloaded.attr,
|
||||
NULL
|
||||
};
|
||||
ATTRIBUTE_GROUPS(netdev_trig);
|
||||
|
||||
static const struct attribute_group netdev_trig_attrs_group = {
|
||||
.attrs = netdev_trig_attrs,
|
||||
};
|
||||
|
||||
static const struct attribute_group *netdev_trig_groups[] = {
|
||||
&netdev_trig_attrs_group,
|
||||
&netdev_trig_link_speed_attrs_group,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static int netdev_trig_notify(struct notifier_block *nb,
|
||||
unsigned long evt, void *dv)
|
||||
@ -484,6 +560,7 @@ static int netdev_trig_notify(struct notifier_block *nb,
|
||||
netdev_notifier_info_to_dev((struct netdev_notifier_info *)dv);
|
||||
struct led_netdev_data *trigger_data =
|
||||
container_of(nb, struct led_netdev_data, notifier);
|
||||
struct led_classdev *led_cdev = trigger_data->led_cdev;
|
||||
|
||||
if (evt != NETDEV_UP && evt != NETDEV_DOWN && evt != NETDEV_CHANGE
|
||||
&& evt != NETDEV_REGISTER && evt != NETDEV_UNREGISTER
|
||||
@ -504,12 +581,12 @@ static int netdev_trig_notify(struct notifier_block *nb,
|
||||
trigger_data->duplex = DUPLEX_UNKNOWN;
|
||||
switch (evt) {
|
||||
case NETDEV_CHANGENAME:
|
||||
get_device_state(trigger_data);
|
||||
fallthrough;
|
||||
case NETDEV_REGISTER:
|
||||
dev_put(trigger_data->net_dev);
|
||||
dev_hold(dev);
|
||||
trigger_data->net_dev = dev;
|
||||
if (evt == NETDEV_CHANGENAME)
|
||||
get_device_state(trigger_data);
|
||||
break;
|
||||
case NETDEV_UNREGISTER:
|
||||
dev_put(trigger_data->net_dev);
|
||||
@ -518,6 +595,10 @@ static int netdev_trig_notify(struct notifier_block *nb,
|
||||
case NETDEV_UP:
|
||||
case NETDEV_CHANGE:
|
||||
get_device_state(trigger_data);
|
||||
/* Refresh link_speed visibility */
|
||||
if (evt == NETDEV_CHANGE)
|
||||
sysfs_update_group(&led_cdev->dev->kobj,
|
||||
&netdev_trig_link_speed_attrs_group);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -617,8 +698,8 @@ static int netdev_trig_activate(struct led_classdev *led_cdev)
|
||||
if (dev) {
|
||||
const char *name = dev_name(dev);
|
||||
|
||||
set_device_name(trigger_data, name, strlen(name));
|
||||
trigger_data->hw_control = true;
|
||||
set_device_name(trigger_data, name, strlen(name));
|
||||
|
||||
rc = led_cdev->hw_control_get(led_cdev, &mode);
|
||||
if (!rc)
|
||||
@ -663,3 +744,4 @@ MODULE_AUTHOR("Ben Whitten <ben.whitten@gmail.com>");
|
||||
MODULE_AUTHOR("Oliver Jowett <oliver@opencloud.com>");
|
||||
MODULE_DESCRIPTION("Netdev LED trigger");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("ledtrig:netdev");
|
||||
|
@ -21,24 +21,15 @@ static struct led_trigger *trigger;
|
||||
*/
|
||||
static void led_trigger_set_panic(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct led_trigger *trig;
|
||||
if (led_cdev->trigger)
|
||||
list_del(&led_cdev->trig_list);
|
||||
list_add_tail(&led_cdev->trig_list, &trigger->led_cdevs);
|
||||
|
||||
list_for_each_entry(trig, &trigger_list, next_trig) {
|
||||
if (strcmp("panic", trig->name))
|
||||
continue;
|
||||
if (led_cdev->trigger)
|
||||
list_del(&led_cdev->trig_list);
|
||||
list_add_tail(&led_cdev->trig_list, &trig->led_cdevs);
|
||||
/* Avoid the delayed blink path */
|
||||
led_cdev->blink_delay_on = 0;
|
||||
led_cdev->blink_delay_off = 0;
|
||||
|
||||
/* Avoid the delayed blink path */
|
||||
led_cdev->blink_delay_on = 0;
|
||||
led_cdev->blink_delay_off = 0;
|
||||
|
||||
led_cdev->trigger = trig;
|
||||
if (trig->activate)
|
||||
trig->activate(led_cdev);
|
||||
break;
|
||||
}
|
||||
led_cdev->trigger = trigger;
|
||||
}
|
||||
|
||||
static int led_trigger_panic_notifier(struct notifier_block *nb,
|
||||
|
@ -64,7 +64,7 @@ config GREYBUS_HID
|
||||
|
||||
config GREYBUS_LIGHT
|
||||
tristate "Greybus LED Class driver"
|
||||
depends on LEDS_CLASS
|
||||
depends on LEDS_CLASS_FLASH
|
||||
help
|
||||
Select this option if you have a device that follows the
|
||||
Greybus LED Class specification.
|
||||
|
@ -29,13 +29,9 @@ struct gb_channel {
|
||||
struct attribute_group *attr_group;
|
||||
const struct attribute_group **attr_groups;
|
||||
struct led_classdev *led;
|
||||
#if IS_REACHABLE(CONFIG_LEDS_CLASS_FLASH)
|
||||
struct led_classdev_flash fled;
|
||||
struct led_flash_setting intensity_uA;
|
||||
struct led_flash_setting timeout_us;
|
||||
#else
|
||||
struct led_classdev cled;
|
||||
#endif
|
||||
struct gb_light *light;
|
||||
bool is_registered;
|
||||
bool releasing;
|
||||
@ -84,7 +80,6 @@ static bool is_channel_flash(struct gb_channel *channel)
|
||||
| GB_CHANNEL_MODE_INDICATOR));
|
||||
}
|
||||
|
||||
#if IS_REACHABLE(CONFIG_LEDS_CLASS_FLASH)
|
||||
static struct gb_channel *get_channel_from_cdev(struct led_classdev *cdev)
|
||||
{
|
||||
struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(cdev);
|
||||
@ -153,22 +148,6 @@ static int __gb_lights_flash_brightness_set(struct gb_channel *channel)
|
||||
|
||||
return __gb_lights_flash_intensity_set(channel, intensity);
|
||||
}
|
||||
#else
|
||||
static struct gb_channel *get_channel_from_cdev(struct led_classdev *cdev)
|
||||
{
|
||||
return container_of(cdev, struct gb_channel, cled);
|
||||
}
|
||||
|
||||
static struct led_classdev *get_channel_cdev(struct gb_channel *channel)
|
||||
{
|
||||
return &channel->cled;
|
||||
}
|
||||
|
||||
static int __gb_lights_flash_brightness_set(struct gb_channel *channel)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int gb_lights_color_set(struct gb_channel *channel, u32 color);
|
||||
static int gb_lights_fade_set(struct gb_channel *channel);
|
||||
|
@ -100,7 +100,11 @@
|
||||
#define LED_FUNCTION_TX "tx"
|
||||
#define LED_FUNCTION_USB "usb"
|
||||
#define LED_FUNCTION_WAN "wan"
|
||||
#define LED_FUNCTION_WAN_ONLINE "wan-online"
|
||||
#define LED_FUNCTION_WLAN "wlan"
|
||||
#define LED_FUNCTION_WLAN_2GHZ "wlan-2ghz"
|
||||
#define LED_FUNCTION_WLAN_5GHZ "wlan-5ghz"
|
||||
#define LED_FUNCTION_WLAN_6GHZ "wlan-6ghz"
|
||||
#define LED_FUNCTION_WPS "wps"
|
||||
|
||||
#endif /* __DT_BINDINGS_LEDS_H */
|
||||
|
@ -85,7 +85,6 @@ static inline struct led_classdev_flash *lcdev_to_flcdev(
|
||||
return container_of(lcdev, struct led_classdev_flash, led_cdev);
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_LEDS_CLASS_FLASH)
|
||||
/**
|
||||
* led_classdev_flash_register_ext - register a new object of LED class with
|
||||
* init data and with support for flash LEDs
|
||||
@ -116,29 +115,6 @@ int devm_led_classdev_flash_register_ext(struct device *parent,
|
||||
void devm_led_classdev_flash_unregister(struct device *parent,
|
||||
struct led_classdev_flash *fled_cdev);
|
||||
|
||||
#else
|
||||
|
||||
static inline int led_classdev_flash_register_ext(struct device *parent,
|
||||
struct led_classdev_flash *fled_cdev,
|
||||
struct led_init_data *init_data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void led_classdev_flash_unregister(struct led_classdev_flash *fled_cdev) {};
|
||||
static inline int devm_led_classdev_flash_register_ext(struct device *parent,
|
||||
struct led_classdev_flash *fled_cdev,
|
||||
struct led_init_data *init_data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void devm_led_classdev_flash_unregister(struct device *parent,
|
||||
struct led_classdev_flash *fled_cdev)
|
||||
{};
|
||||
|
||||
#endif /* IS_ENABLED(CONFIG_LEDS_CLASS_FLASH) */
|
||||
|
||||
static inline int led_classdev_flash_register(struct device *parent,
|
||||
struct led_classdev_flash *fled_cdev)
|
||||
{
|
||||
|
@ -30,7 +30,6 @@ static inline struct led_classdev_mc *lcdev_to_mccdev(
|
||||
return container_of(led_cdev, struct led_classdev_mc, led_cdev);
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_LEDS_CLASS_MULTICOLOR)
|
||||
/**
|
||||
* led_classdev_multicolor_register_ext - register a new object of led_classdev
|
||||
* class with support for multicolor LEDs
|
||||
@ -64,34 +63,6 @@ int devm_led_classdev_multicolor_register_ext(struct device *parent,
|
||||
|
||||
void devm_led_classdev_multicolor_unregister(struct device *parent,
|
||||
struct led_classdev_mc *mcled_cdev);
|
||||
#else
|
||||
|
||||
static inline int led_classdev_multicolor_register_ext(struct device *parent,
|
||||
struct led_classdev_mc *mcled_cdev,
|
||||
struct led_init_data *init_data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void led_classdev_multicolor_unregister(struct led_classdev_mc *mcled_cdev) {};
|
||||
static inline int led_mc_calc_color_components(struct led_classdev_mc *mcled_cdev,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int devm_led_classdev_multicolor_register_ext(struct device *parent,
|
||||
struct led_classdev_mc *mcled_cdev,
|
||||
struct led_init_data *init_data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void devm_led_classdev_multicolor_unregister(struct device *parent,
|
||||
struct led_classdev_mc *mcled_cdev)
|
||||
{};
|
||||
|
||||
#endif /* IS_ENABLED(CONFIG_LEDS_CLASS_MULTICOLOR) */
|
||||
|
||||
static inline int led_classdev_multicolor_register(struct device *parent,
|
||||
struct led_classdev_mc *mcled_cdev)
|
||||
|
@ -82,15 +82,7 @@ struct led_init_data {
|
||||
bool devname_mandatory;
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_NEW_LEDS)
|
||||
enum led_default_state led_init_default_state_get(struct fwnode_handle *fwnode);
|
||||
#else
|
||||
static inline enum led_default_state
|
||||
led_init_default_state_get(struct fwnode_handle *fwnode)
|
||||
{
|
||||
return LEDS_DEFSTATE_OFF;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct led_hw_trigger_type {
|
||||
int dummy;
|
||||
@ -279,20 +271,9 @@ static inline int led_classdev_register(struct device *parent,
|
||||
return led_classdev_register_ext(parent, led_cdev, NULL);
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_LEDS_CLASS)
|
||||
int devm_led_classdev_register_ext(struct device *parent,
|
||||
struct led_classdev *led_cdev,
|
||||
struct led_init_data *init_data);
|
||||
#else
|
||||
static inline int
|
||||
devm_led_classdev_register_ext(struct device *parent,
|
||||
struct led_classdev *led_cdev,
|
||||
struct led_init_data *init_data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline int devm_led_classdev_register(struct device *parent,
|
||||
struct led_classdev *led_cdev)
|
||||
{
|
||||
@ -658,7 +639,7 @@ struct gpio_led_platform_data {
|
||||
gpio_blink_set_t gpio_blink_set;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_NEW_LEDS
|
||||
#ifdef CONFIG_LEDS_GPIO_REGISTER
|
||||
struct platform_device *gpio_led_register_device(
|
||||
int id, const struct gpio_led_platform_data *pdata);
|
||||
#else
|
||||
|
Loading…
Reference in New Issue
Block a user