Commit f5c31bcf authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents f3d8f29d 45066c4b
......@@ -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
......
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";
};
};
...
# 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 @@ static int aw2013_probe(struct i2c_client *client)
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 @@ static int pca963x_register_leds(struct i2c_client *client,
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)
......
// 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", &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");
This diff is collapsed.
......@@ -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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment