summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2024-07-17 17:51:30 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2024-07-17 17:51:30 -0700
commitfea17683c4fbb06a727cd94abf4c9588a580ab12 (patch)
tree280723b4c6b82580d18acd4a6fc945c70dbf2c87 /drivers
parente0d97b04eceb637a476a2d0233bc7721611a9cb2 (diff)
parentb0eed397623f897d3ccac9bda2bd2f53331b571a (diff)
downloadlinux-fea17683c4fbb06a727cd94abf4c9588a580ab12.tar.gz
linux-fea17683c4fbb06a727cd94abf4c9588a580ab12.tar.bz2
linux-fea17683c4fbb06a727cd94abf4c9588a580ab12.zip
Merge tag 'leds-next-6.11' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/leds
Pull LED updates from Lee Jones: "Core Frameworks: - New trigger for Input Events - New led_mc_set_brightness() call to adapt colour/brightness for mutli-colour LEDs - New lled_mc_trigger_event() call to call the above based on given trigger conditions - New led_get_color_name() call, a wrapper around the existing led_colors[] array - A new flag to avoid automatic renaming of LED devices New Drivers: - Silergy SY7802 Flash LED Controller - Texas Instruments LP5569 LED Controller - ChromeOS EC LED Controller New Device Support: - KTD202{6,7} support for Kinetic KTD2026/7 LEDs Fix-ups: - Replace ACPI/DT firmware helpers with agnostic variants - Make use of resource managed devm_* API calls - Device Tree binding adaptions/conversions/creation - Constify/staticise applicable data structures - Trivial; spelling, whitespace, coding-style adaptions - Drop i2c_device_id::driver_data where the value is unused - Utilise centrally provided helpers and macros to aid simplicity and avoid duplication - Use generic platform device properties instead of OF/ACPI specific ones - Consolidate/de-duplicate various functionality - Remove superfluous/duplicated/unused sections - Make use of the new *_scoped() guard APIs - Improve/simplify error handling Bug Fixes: - Flush pending brightness changes before activating the trigger - Repair incorrect device naming preventing matches - Prevent memory leaks by correctly free resources during error handling routines - Repair locking issue causing circular dependency splats and lock-ups - Unregister sysfs entries before deactivating triggers to prevent use-after issues - Supply a bunch of MODULE_DESCRIPTIONs to silence modpost warnings - Use correct return codes expected by the callers - Omit set_brightness() error message for a LEDs that support only HW triggers" * tag 'leds-next-6.11' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/leds: (65 commits) leds: leds-lp5569: Enable chip after chip configuration leds: leds-lp5569: Better handle enabling clock internal setting leds: leds-lp5569: Fix typo in driver name leds: flash: leds-qcom-flash: Test the correct variable in init leds: leds-lp55xx: Convert mutex lock/unlock to guard API leds: leds-lp5523: Convert to sysfs_emit API leds: leds-lp5569: Convert to sysfs_emit API Revert "leds: led-core: Fix refcount leak in of_led_get()" leds: leds-lp5569: Add support for Texas Instruments LP5569 leds: leds-lp55xx: Drop deprecated defines leds: leds-lp55xx: Support ENGINE program up to 128 bytes leds: leds-lp55xx: Generalize sysfs master_fader leds: leds-lp55xx: Generalize sysfs engine_leds leds: leds-lp55xx: Generalize sysfs engine_load and engine_mode leds: leds-lp55xx: Generalize stop_engine function leds: leds-lp55xx: Generalize turn_off_channels function leds: leds-lp55xx: Generalize set_led_current function leds: leds-lp55xx: Generalize multicolor_brightness function leds: leds-lp55xx: Generalize led_brightness function leds: leds-lp55xx: Generalize firmware_loaded function ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/leds/Kconfig17
-rw-r--r--drivers/leds/Makefile1
-rw-r--r--drivers/leds/blink/leds-bcm63138.c1
-rw-r--r--drivers/leds/flash/Kconfig11
-rw-r--r--drivers/leds/flash/Makefile1
-rw-r--r--drivers/leds/flash/leds-as3645a.c4
-rw-r--r--drivers/leds/flash/leds-mt6360.c5
-rw-r--r--drivers/leds/flash/leds-qcom-flash.c10
-rw-r--r--drivers/leds/flash/leds-rt4505.c1
-rw-r--r--drivers/leds/flash/leds-sy7802.c539
-rw-r--r--drivers/leds/led-class-multicolor.c1
-rw-r--r--drivers/leds/led-class.c1
-rw-r--r--drivers/leds/led-core.c50
-rw-r--r--drivers/leds/led-triggers.c35
-rw-r--r--drivers/leds/leds-an30259a.c4
-rw-r--r--drivers/leds/leds-bd2802.c2
-rw-r--r--drivers/leds/leds-blinkm.c2
-rw-r--r--drivers/leds/leds-is31fl319x.c4
-rw-r--r--drivers/leds/leds-lm3530.c2
-rw-r--r--drivers/leds/leds-lm3532.c2
-rw-r--r--drivers/leds/leds-lm3642.c2
-rw-r--r--drivers/leds/leds-lm3697.c2
-rw-r--r--drivers/leds/leds-lp3944.c2
-rw-r--r--drivers/leds/leds-lp3952.c2
-rw-r--r--drivers/leds/leds-lp5521.c410
-rw-r--r--drivers/leds/leds-lp5523.c763
-rw-r--r--drivers/leds/leds-lp5562.c274
-rw-r--r--drivers/leds/leds-lp5569.c544
-rw-r--r--drivers/leds/leds-lp55xx-common.c760
-rw-r--r--drivers/leds/leds-lp55xx-common.h163
-rw-r--r--drivers/leds/leds-lp8501.c313
-rw-r--r--drivers/leds/leds-lp8860.c2
-rw-r--r--drivers/leds/leds-pca9532.c81
-rw-r--r--drivers/leds/leds-powernv.c28
-rw-r--r--drivers/leds/leds-spi-byte.c63
-rw-r--r--drivers/leds/leds-ss4200.c7
-rw-r--r--drivers/leds/leds-tlc591xx.c18
-rw-r--r--drivers/leds/leds-turris-omnia.c2
-rw-r--r--drivers/leds/rgb/Kconfig1
-rw-r--r--drivers/leds/rgb/leds-ktd202x.c80
-rw-r--r--drivers/leds/rgb/leds-ncp5623.c16
-rw-r--r--drivers/leds/rgb/leds-qcom-lpg.c8
-rw-r--r--drivers/leds/simple/simatic-ipc-leds-gpio-apollolake.c1
-rw-r--r--drivers/leds/simple/simatic-ipc-leds-gpio-core.c1
-rw-r--r--drivers/leds/simple/simatic-ipc-leds-gpio-elkhartlake.c1
-rw-r--r--drivers/leds/simple/simatic-ipc-leds-gpio-f7188x.c1
-rw-r--r--drivers/leds/simple/simatic-ipc-leds.c1
-rw-r--r--drivers/leds/trigger/Kconfig16
-rw-r--r--drivers/leds/trigger/Makefile1
-rw-r--r--drivers/leds/trigger/ledtrig-input-events.c165
-rw-r--r--drivers/leds/trigger/ledtrig-timer.c5
-rw-r--r--drivers/power/supply/power_supply_leds.c23
52 files changed, 2587 insertions, 1862 deletions
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index aa2fec9a34ed..8d9d8da376e4 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -429,7 +429,7 @@ config LEDS_LP50XX
module will be called leds-lp50xx.
config LEDS_LP55XX_COMMON
- tristate "Common Driver for TI/National LP5521/5523/55231/5562/8501"
+ tristate "Common Driver for TI/National LP5521/5523/55231/5562/5569/8501"
depends on LEDS_CLASS
depends on LEDS_CLASS_MULTICOLOR
depends on OF
@@ -437,8 +437,8 @@ config LEDS_LP55XX_COMMON
select FW_LOADER
select FW_LOADER_USER_HELPER
help
- This option supports common operations for LP5521/5523/55231/5562/8501
- devices.
+ This option supports common operations for LP5521/5523/55231/5562/5569/
+ 8501 devices.
config LEDS_LP5521
tristate "LED Support for N.S. LP5521 LED driver chip"
@@ -471,6 +471,16 @@ config LEDS_LP5562
Driver provides direct control via LED class and interface for
programming the engines.
+config LEDS_LP5569
+ tristate "LED Support for TI LP5569 LED driver chip"
+ depends on LEDS_CLASS && I2C
+ depends on LEDS_LP55XX_COMMON
+ help
+ If you say yes here you get support for TI LP5569 LED driver.
+ It is 9 channels chip with programmable engines.
+ Driver provides direct control via LED class and interface for
+ programming the engines.
+
config LEDS_LP8501
tristate "LED Support for TI LP8501 LED driver chip"
depends on LEDS_CLASS && I2C
@@ -884,7 +894,6 @@ config LEDS_SPI_BYTE
tristate "LED support for SPI LED controller with a single byte"
depends on LEDS_CLASS
depends on SPI
- depends on OF
help
This option enables support for LED controller which use a single byte
for controlling the brightness. Currently the following controller is
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 3491904e13f7..18afbb5a23ee 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -52,6 +52,7 @@ obj-$(CONFIG_LEDS_LP50XX) += leds-lp50xx.o
obj-$(CONFIG_LEDS_LP5521) += leds-lp5521.o
obj-$(CONFIG_LEDS_LP5523) += leds-lp5523.o
obj-$(CONFIG_LEDS_LP5562) += leds-lp5562.o
+obj-$(CONFIG_LEDS_LP5569) += leds-lp5569.o
obj-$(CONFIG_LEDS_LP55XX_COMMON) += leds-lp55xx-common.o
obj-$(CONFIG_LEDS_LP8501) += leds-lp8501.o
obj-$(CONFIG_LEDS_LP8788) += leds-lp8788.o
diff --git a/drivers/leds/blink/leds-bcm63138.c b/drivers/leds/blink/leds-bcm63138.c
index 2cf2761e4914..3a5e0b98bfbc 100644
--- a/drivers/leds/blink/leds-bcm63138.c
+++ b/drivers/leds/blink/leds-bcm63138.c
@@ -303,5 +303,6 @@ static struct platform_driver bcm63138_leds_driver = {
module_platform_driver(bcm63138_leds_driver);
MODULE_AUTHOR("Rafał Miłecki");
+MODULE_DESCRIPTION("Broadcom BCM63138 SoC LED driver");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(of, bcm63138_leds_of_match_table);
diff --git a/drivers/leds/flash/Kconfig b/drivers/leds/flash/Kconfig
index 809b6d98bb3e..f39f0bfe6eef 100644
--- a/drivers/leds/flash/Kconfig
+++ b/drivers/leds/flash/Kconfig
@@ -121,4 +121,15 @@ config LEDS_SGM3140
This option enables support for the SGM3140 500mA Buck/Boost Charge
Pump LED Driver.
+config LEDS_SY7802
+ tristate "LED support for the Silergy SY7802"
+ depends on I2C && OF
+ depends on GPIOLIB
+ select REGMAP_I2C
+ help
+ This option enables support for the SY7802 flash LED controller.
+ SY7802 includes torch and flash functions with programmable current.
+
+ This driver can be built as a module, it will be called "leds-sy7802".
+
endif # LEDS_CLASS_FLASH
diff --git a/drivers/leds/flash/Makefile b/drivers/leds/flash/Makefile
index 91d60a4b7952..48860eeced79 100644
--- a/drivers/leds/flash/Makefile
+++ b/drivers/leds/flash/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_LEDS_QCOM_FLASH) += leds-qcom-flash.o
obj-$(CONFIG_LEDS_RT4505) += leds-rt4505.o
obj-$(CONFIG_LEDS_RT8515) += leds-rt8515.o
obj-$(CONFIG_LEDS_SGM3140) += leds-sgm3140.o
+obj-$(CONFIG_LEDS_SY7802) += leds-sy7802.o
diff --git a/drivers/leds/flash/leds-as3645a.c b/drivers/leds/flash/leds-as3645a.c
index 12c2609c1137..2c6ef321b7c8 100644
--- a/drivers/leds/flash/leds-as3645a.c
+++ b/drivers/leds/flash/leds-as3645a.c
@@ -743,8 +743,8 @@ static void as3645a_remove(struct i2c_client *client)
}
static const struct i2c_device_id as3645a_id_table[] = {
- { AS_NAME, 0 },
- { },
+ { AS_NAME },
+ { }
};
MODULE_DEVICE_TABLE(i2c, as3645a_id_table);
diff --git a/drivers/leds/flash/leds-mt6360.c b/drivers/leds/flash/leds-mt6360.c
index 1b75b4d36834..4c74f1cf01f0 100644
--- a/drivers/leds/flash/leds-mt6360.c
+++ b/drivers/leds/flash/leds-mt6360.c
@@ -643,14 +643,17 @@ static int mt6360_init_isnk_properties(struct mt6360_led *led,
ret = fwnode_property_read_u32(child, "reg", &reg);
if (ret || reg > MT6360_LED_ISNK3 ||
- priv->leds_active & BIT(reg))
+ priv->leds_active & BIT(reg)) {
+ fwnode_handle_put(child);
return -EINVAL;
+ }
ret = fwnode_property_read_u32(child, "color", &color);
if (ret) {
dev_err(priv->dev,
"led %d, no color specified\n",
led->led_no);
+ fwnode_handle_put(child);
return ret;
}
diff --git a/drivers/leds/flash/leds-qcom-flash.c b/drivers/leds/flash/leds-qcom-flash.c
index 7c99a3039171..bf70bf6fb0d5 100644
--- a/drivers/leds/flash/leds-qcom-flash.c
+++ b/drivers/leds/flash/leds-qcom-flash.c
@@ -505,6 +505,7 @@ qcom_flash_v4l2_init(struct device *dev, struct qcom_flash_led *led, struct fwno
struct qcom_flash_data *flash_data = led->flash_data;
struct v4l2_flash_config v4l2_cfg = { 0 };
struct led_flash_setting *intensity = &v4l2_cfg.intensity;
+ struct v4l2_flash *v4l2_flash;
if (!(led->flash.led_cdev.flags & LED_DEV_CAP_FLASH))
return 0;
@@ -523,9 +524,12 @@ qcom_flash_v4l2_init(struct device *dev, struct qcom_flash_led *led, struct fwno
LED_FAULT_OVER_TEMPERATURE |
LED_FAULT_TIMEOUT;
- flash_data->v4l2_flash[flash_data->leds_count] =
- v4l2_flash_init(dev, fwnode, &led->flash, &qcom_v4l2_flash_ops, &v4l2_cfg);
- return PTR_ERR_OR_ZERO(flash_data->v4l2_flash);
+ v4l2_flash = v4l2_flash_init(dev, fwnode, &led->flash, &qcom_v4l2_flash_ops, &v4l2_cfg);
+ if (IS_ERR(v4l2_flash))
+ return PTR_ERR(v4l2_flash);
+
+ flash_data->v4l2_flash[flash_data->leds_count] = v4l2_flash;
+ return 0;
}
# else
static int
diff --git a/drivers/leds/flash/leds-rt4505.c b/drivers/leds/flash/leds-rt4505.c
index 1ae5b387f4a5..f16358b8dfc1 100644
--- a/drivers/leds/flash/leds-rt4505.c
+++ b/drivers/leds/flash/leds-rt4505.c
@@ -426,4 +426,5 @@ static struct i2c_driver rt4505_driver = {
module_i2c_driver(rt4505_driver);
MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
+MODULE_DESCRIPTION("Richtek RT4505 LED driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/leds/flash/leds-sy7802.c b/drivers/leds/flash/leds-sy7802.c
new file mode 100644
index 000000000000..ddac836762af
--- /dev/null
+++ b/drivers/leds/flash/leds-sy7802.c
@@ -0,0 +1,539 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Silergy SY7802 flash LED driver with an I2C interface
+ *
+ * Copyright 2024 André Apitzsch <git@apitzsch.eu>
+ */
+
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/led-class-flash.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+
+#define SY7802_MAX_LEDS 2
+#define SY7802_LED_JOINT 2
+
+#define SY7802_REG_ENABLE 0x10
+#define SY7802_REG_TORCH_BRIGHTNESS 0xa0
+#define SY7802_REG_FLASH_BRIGHTNESS 0xb0
+#define SY7802_REG_FLASH_DURATION 0xc0
+#define SY7802_REG_FLAGS 0xd0
+#define SY7802_REG_CONFIG_1 0xe0
+#define SY7802_REG_CONFIG_2 0xf0
+#define SY7802_REG_VIN_MONITOR 0x80
+#define SY7802_REG_LAST_FLASH 0x81
+#define SY7802_REG_VLED_MONITOR 0x30
+#define SY7802_REG_ADC_DELAY 0x31
+#define SY7802_REG_DEV_ID 0xff
+
+#define SY7802_MODE_OFF 0
+#define SY7802_MODE_TORCH 2
+#define SY7802_MODE_FLASH 3
+#define SY7802_MODE_MASK GENMASK(1, 0)
+
+#define SY7802_LEDS_SHIFT 3
+#define SY7802_LEDS_MASK(_id) (BIT(_id) << SY7802_LEDS_SHIFT)
+#define SY7802_LEDS_MASK_ALL (SY7802_LEDS_MASK(0) | SY7802_LEDS_MASK(1))
+
+#define SY7802_TORCH_CURRENT_SHIFT 3
+#define SY7802_TORCH_CURRENT_MASK(_id) \
+ (GENMASK(2, 0) << (SY7802_TORCH_CURRENT_SHIFT * (_id)))
+#define SY7802_TORCH_CURRENT_MASK_ALL \
+ (SY7802_TORCH_CURRENT_MASK(0) | SY7802_TORCH_CURRENT_MASK(1))
+
+#define SY7802_FLASH_CURRENT_SHIFT 4
+#define SY7802_FLASH_CURRENT_MASK(_id) \
+ (GENMASK(3, 0) << (SY7802_FLASH_CURRENT_SHIFT * (_id)))
+#define SY7802_FLASH_CURRENT_MASK_ALL \
+ (SY7802_FLASH_CURRENT_MASK(0) | SY7802_FLASH_CURRENT_MASK(1))
+
+#define SY7802_TIMEOUT_DEFAULT_US 512000U
+#define SY7802_TIMEOUT_MIN_US 32000U
+#define SY7802_TIMEOUT_MAX_US 1024000U
+#define SY7802_TIMEOUT_STEPSIZE_US 32000U
+
+#define SY7802_TORCH_BRIGHTNESS_MAX 8
+
+#define SY7802_FLASH_BRIGHTNESS_DEFAULT 14
+#define SY7802_FLASH_BRIGHTNESS_MIN 0
+#define SY7802_FLASH_BRIGHTNESS_MAX 15
+#define SY7802_FLASH_BRIGHTNESS_STEP 1
+
+#define SY7802_FLAG_TIMEOUT BIT(0)
+#define SY7802_FLAG_THERMAL_SHUTDOWN BIT(1)
+#define SY7802_FLAG_LED_FAULT BIT(2)
+#define SY7802_FLAG_TX1_INTERRUPT BIT(3)
+#define SY7802_FLAG_TX2_INTERRUPT BIT(4)
+#define SY7802_FLAG_LED_THERMAL_FAULT BIT(5)
+#define SY7802_FLAG_FLASH_INPUT_VOLTAGE_LOW BIT(6)
+#define SY7802_FLAG_INPUT_VOLTAGE_LOW BIT(7)
+
+#define SY7802_CHIP_ID 0x51
+
+static const struct reg_default sy7802_regmap_defs[] = {
+ { SY7802_REG_ENABLE, SY7802_LEDS_MASK_ALL },
+ { SY7802_REG_TORCH_BRIGHTNESS, 0x92 },
+ { SY7802_REG_FLASH_BRIGHTNESS, SY7802_FLASH_BRIGHTNESS_DEFAULT |
+ SY7802_FLASH_BRIGHTNESS_DEFAULT << SY7802_FLASH_CURRENT_SHIFT },
+ { SY7802_REG_FLASH_DURATION, 0x6f },
+ { SY7802_REG_FLAGS, 0x0 },
+ { SY7802_REG_CONFIG_1, 0x68 },
+ { SY7802_REG_CONFIG_2, 0xf0 },
+};
+
+struct sy7802_led {
+ struct led_classdev_flash flash;
+ struct sy7802 *chip;
+ u8 led_id;
+};
+
+struct sy7802 {
+ struct device *dev;
+ struct regmap *regmap;
+ struct mutex mutex;
+
+ struct gpio_desc *enable_gpio;
+ struct regulator *vin_regulator;
+
+ unsigned int fled_strobe_used;
+ unsigned int fled_torch_used;
+ unsigned int leds_active;
+ int num_leds;
+ struct sy7802_led leds[] __counted_by(num_leds);
+};
+
+static int sy7802_torch_brightness_set(struct led_classdev *lcdev, enum led_brightness brightness)
+{
+ struct sy7802_led *led = container_of(lcdev, struct sy7802_led, flash.led_cdev);
+ struct sy7802 *chip = led->chip;
+ u32 fled_torch_used_tmp;
+ u32 led_enable_mask;
+ u32 enable_mask;
+ u32 torch_mask;
+ u32 val;
+ int ret;
+
+ mutex_lock(&chip->mutex);
+
+ if (chip->fled_strobe_used) {
+ dev_warn(chip->dev, "Cannot set torch brightness whilst strobe is enabled\n");
+ ret = -EBUSY;
+ goto unlock;
+ }
+
+ if (brightness)
+ fled_torch_used_tmp = chip->fled_torch_used | BIT(led->led_id);
+ else
+ fled_torch_used_tmp = chip->fled_torch_used & ~BIT(led->led_id);
+
+ led_enable_mask = led->led_id == SY7802_LED_JOINT ?
+ SY7802_LEDS_MASK_ALL :
+ SY7802_LEDS_MASK(led->led_id);
+
+ val = brightness ? led_enable_mask : SY7802_MODE_OFF;
+ if (fled_torch_used_tmp)
+ val |= SY7802_MODE_TORCH;
+
+ /* Disable torch to apply brightness */
+ ret = regmap_update_bits(chip->regmap, SY7802_REG_ENABLE, SY7802_MODE_MASK,
+ SY7802_MODE_OFF);
+ if (ret)
+ goto unlock;
+
+ torch_mask = led->led_id == SY7802_LED_JOINT ?
+ SY7802_TORCH_CURRENT_MASK_ALL :
+ SY7802_TORCH_CURRENT_MASK(led->led_id);
+
+ /* Register expects brightness between 0 and MAX_BRIGHTNESS - 1 */
+ if (brightness)
+ brightness -= 1;
+
+ brightness |= (brightness << SY7802_TORCH_CURRENT_SHIFT);
+
+ ret = regmap_update_bits(chip->regmap, SY7802_REG_TORCH_BRIGHTNESS, torch_mask, brightness);
+ if (ret)
+ goto unlock;
+
+ enable_mask = SY7802_MODE_MASK | led_enable_mask;
+ ret = regmap_update_bits(chip->regmap, SY7802_REG_ENABLE, enable_mask, val);
+ if (ret)
+ goto unlock;
+
+ chip->fled_torch_used = fled_torch_used_tmp;
+
+unlock:
+ mutex_unlock(&chip->mutex);
+ return ret;
+}
+
+static int sy7802_flash_brightness_set(struct led_classdev_flash *fl_cdev, u32 brightness)
+{
+ struct sy7802_led *led = container_of(fl_cdev, struct sy7802_led, flash);
+ struct led_flash_setting *s = &fl_cdev->brightness;
+ u32 val = (brightness - s->min) / s->step;
+ struct sy7802 *chip = led->chip;
+ u32 flash_mask;
+ int ret;
+
+ val |= (val << SY7802_FLASH_CURRENT_SHIFT);
+ flash_mask = led->led_id == SY7802_LED_JOINT ?
+ SY7802_FLASH_CURRENT_MASK_ALL :
+ SY7802_FLASH_CURRENT_MASK(led->led_id);
+
+ mutex_lock(&chip->mutex);
+ ret = regmap_update_bits(chip->regmap, SY7802_REG_FLASH_BRIGHTNESS, flash_mask, val);
+ mutex_unlock(&chip->mutex);
+
+ return ret;
+}
+
+static int sy7802_strobe_set(struct led_classdev_flash *fl_cdev, bool state)
+{
+ struct sy7802_led *led = container_of(fl_cdev, struct sy7802_led, flash);
+ struct sy7802 *chip = led->chip;
+ u32 fled_strobe_used_tmp;
+ u32 led_enable_mask;
+ u32 enable_mask;
+ u32 val;
+ int ret;
+
+ mutex_lock(&chip->mutex);
+
+ if (chip->fled_torch_used) {
+ dev_warn(chip->dev, "Cannot set strobe brightness whilst torch is enabled\n");
+ ret = -EBUSY;
+ goto unlock;
+ }
+
+ if (state)
+ fled_strobe_used_tmp = chip->fled_strobe_used | BIT(led->led_id);
+ else
+ fled_strobe_used_tmp = chip->fled_strobe_used & ~BIT(led->led_id);
+
+ led_enable_mask = led->led_id == SY7802_LED_JOINT ?
+ SY7802_LEDS_MASK_ALL :
+ SY7802_LEDS_MASK(led->led_id);
+
+ val = state ? led_enable_mask : SY7802_MODE_OFF;
+ if (fled_strobe_used_tmp)
+ val |= SY7802_MODE_FLASH;
+
+ enable_mask = SY7802_MODE_MASK | led_enable_mask;
+ ret = regmap_update_bits(chip->regmap, SY7802_REG_ENABLE, enable_mask, val);
+
+ if (ret)
+ goto unlock;
+
+ chip->fled_strobe_used = fled_strobe_used_tmp;
+
+unlock:
+ mutex_unlock(&chip->mutex);
+ return ret;
+}
+
+static int sy7802_strobe_get(struct led_classdev_flash *fl_cdev, bool *state)
+{
+ struct sy7802_led *led = container_of(fl_cdev, struct sy7802_led, flash);
+ struct sy7802 *chip = led->chip;
+
+ mutex_lock(&chip->mutex);
+ *state = !!(chip->fled_strobe_used & BIT(led->led_id));
+ mutex_unlock(&chip->mutex);
+
+ return 0;
+}
+
+static int sy7802_timeout_set(struct led_classdev_flash *fl_cdev, u32 timeout)
+{
+ struct sy7802_led *led = container_of(fl_cdev, struct sy7802_led, flash);
+ struct led_flash_setting *s = &fl_cdev->timeout;
+ u32 val = (timeout - s->min) / s->step;
+ struct sy7802 *chip = led->chip;
+
+ return regmap_write(chip->regmap, SY7802_REG_FLASH_DURATION, val);
+}
+
+static int sy7802_fault_get(struct led_classdev_flash *fl_cdev, u32 *fault)
+{
+ struct sy7802_led *led = container_of(fl_cdev, struct sy7802_led, flash);
+ struct sy7802 *chip = led->chip;
+ u32 val, led_faults = 0;
+ int ret;
+
+ /* NOTE: reading register clears fault status */
+ ret = regmap_read(chip->regmap, SY7802_REG_FLAGS, &val);
+ if (ret)
+ return ret;
+
+ if (val & (SY7802_FLAG_FLASH_INPUT_VOLTAGE_LOW | SY7802_FLAG_INPUT_VOLTAGE_LOW))
+ led_faults |= LED_FAULT_INPUT_VOLTAGE;
+
+ if (val & SY7802_FLAG_THERMAL_SHUTDOWN)
+ led_faults |= LED_FAULT_OVER_TEMPERATURE;
+
+ if (val & SY7802_FLAG_TIMEOUT)
+ led_faults |= LED_FAULT_TIMEOUT;
+
+ *fault = led_faults;
+ return 0;
+}
+
+static const struct led_flash_ops sy7802_flash_ops = {
+ .flash_brightness_set = sy7802_flash_brightness_set,
+ .strobe_set = sy7802_strobe_set,
+ .strobe_get = sy7802_strobe_get,
+ .timeout_set = sy7802_timeout_set,
+ .fault_get = sy7802_fault_get,
+};
+
+static void sy7802_init_flash_brightness(struct led_classdev_flash *fl_cdev)
+{
+ struct led_flash_setting *s;
+
+ /* Init flash brightness setting */
+ s = &fl_cdev->brightness;
+ s->min = SY7802_FLASH_BRIGHTNESS_MIN;
+ s->max = SY7802_FLASH_BRIGHTNESS_MAX;
+ s->step = SY7802_FLASH_BRIGHTNESS_STEP;
+ s->val = SY7802_FLASH_BRIGHTNESS_DEFAULT;
+}
+
+static void sy7802_init_flash_timeout(struct led_classdev_flash *fl_cdev)
+{
+ struct led_flash_setting *s;
+
+ /* Init flash timeout setting */
+ s = &fl_cdev->timeout;
+ s->min = SY7802_TIMEOUT_MIN_US;
+ s->max = SY7802_TIMEOUT_MAX_US;
+ s->step = SY7802_TIMEOUT_STEPSIZE_US;
+ s->val = SY7802_TIMEOUT_DEFAULT_US;
+}
+
+static int sy7802_led_register(struct device *dev, struct sy7802_led *led,
+ struct device_node *np)
+{
+ struct led_init_data init_data = {};
+ int ret;
+
+ init_data.fwnode = of_fwnode_handle(np);
+
+ ret = devm_led_classdev_flash_register_ext(dev, &led->flash, &init_data);
+ if (ret) {
+ dev_err(dev, "Couldn't register flash %d\n", led->led_id);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int sy7802_init_flash_properties(struct device *dev, struct sy7802_led *led,
+ struct device_node *np)
+{
+ struct led_classdev_flash *flash = &led->flash;
+ struct led_classdev *lcdev = &flash->led_cdev;
+ u32 sources[SY7802_MAX_LEDS];
+ int i, num, ret;
+
+ num = of_property_count_u32_elems(np, "led-sources");
+ if (num < 1) {
+ dev_err(dev, "Not specified or wrong number of led-sources\n");
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32_array(np, "led-sources", sources, num);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < num; i++) {
+ if (sources[i] >= SY7802_MAX_LEDS)
+ return -EINVAL;
+ if (led->chip->leds_active & BIT(sources[i]))
+ return -EINVAL;
+ led->chip->leds_active |= BIT(sources[i]);
+ }
+
+ /* If both channels are specified in 'led-sources', joint flash output mode is used */
+ led->led_id = num == 2 ? SY7802_LED_JOINT : sources[0];
+
+ lcdev->max_brightness = SY7802_TORCH_BRIGHTNESS_MAX;
+ lcdev->brightness_set_blocking = sy7802_torch_brightness_set;
+ lcdev->flags |= LED_DEV_CAP_FLASH;
+
+ flash->ops = &sy7802_flash_ops;
+
+ sy7802_init_flash_brightness(flash);
+ sy7802_init_flash_timeout(flash);
+
+ return 0;
+}
+
+static int sy7802_chip_check(struct sy7802 *chip)
+{
+ struct device *dev = chip->dev;
+ u32 chipid;
+ int ret;
+
+ ret = regmap_read(chip->regmap, SY7802_REG_DEV_ID, &chipid);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to read chip ID\n");
+
+ if (chipid != SY7802_CHIP_ID)
+ return dev_err_probe(dev, -ENODEV, "Unsupported chip detected: %x\n", chipid);
+
+ return 0;
+}
+
+static void sy7802_enable(struct sy7802 *chip)
+{