aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2024-07-17 17:48:40 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2024-07-17 17:48:40 -0700
commite0d97b04eceb637a476a2d0233bc7721611a9cb2 (patch)
tree8ba1e373e0cae434e9a95c32bc89a65fb35348aa
parent1200af3ac16489d9f0b86000362a044ed7521cf6 (diff)
parent1df5aa3754cac2045998ca505edb84d994786c67 (diff)
Merge tag 'backlight-next-6.11' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/backlight
Pull backlight updates from Lee Jones: "New Drivers: - Texas Instruments LM3509 Backlight Driver Fix-ups: - Device Tree binding adaptions/conversions/creation - Drop i2c_device_id::driver_data where the value is unused - Make use of the new *_scoped() guard APIs - Decouple from fbdev by providing Backlight with its own BACKLIGHT_POWER_* constrains Bug Fixes: - Correctly assess return values (NULL vs IS_ERR()) - Supply a bunch of MODULE_DESCRIPTIONs to silence modpost warnings" * tag 'backlight-next-6.11' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/backlight: (23 commits) backlight: sky81452-backlight: Use backlight power constants backlight: rave-sp-backlight: Use backlight power constants backlight: pwm-backlight: Use backlight power constants backlight: pcf50633-backlight: Use backlight power constants backlight: pandora-backlight: Use backlight power constants backlight: mp3309c: Use backlight power constants backlight: lm3533-backlight: Use backlight power constants backlight: led-backlight: Use backlight power constants backlight: ktd253-backlight: Use backlight power constants backlight: kb3886-bl: Use backlight power constants backlight: journada_bl: Use backlight power constants backlight: ipaq-micro-backlight: Use backlight power constants backlight: gpio-backlight: Use backlight power constants backlight: corgi-lcd: Use backlight power constants backlight: ams369fb06: Use backlight power constants backlight: aat2870-backlight: Use blacklight power constants backlight: Add BACKLIGHT_POWER_ constants for power states backlight: lm3509_bl: Fix early returns in for_each_child_of_node() backlight: Drop explicit initialization of struct i2c_device_id::driver_data to 0 backlight: Add missing MODULE_DESCRIPTION() macros ...
-rw-r--r--Documentation/ABI/stable/sysfs-class-backlight7
-rw-r--r--Documentation/devicetree/bindings/leds/backlight/ti,lm3509.yaml136
-rw-r--r--drivers/video/backlight/Kconfig7
-rw-r--r--drivers/video/backlight/Makefile1
-rw-r--r--drivers/video/backlight/aat2870_bl.c4
-rw-r--r--drivers/video/backlight/adp8870_bl.c2
-rw-r--r--drivers/video/backlight/ams369fg06.c23
-rw-r--r--drivers/video/backlight/bd6107.c2
-rw-r--r--drivers/video/backlight/corgi_lcd.c4
-rw-r--r--drivers/video/backlight/gpio_backlight.c9
-rw-r--r--drivers/video/backlight/ipaq_micro_bl.c3
-rw-r--r--drivers/video/backlight/jornada720_bl.c3
-rw-r--r--drivers/video/backlight/kb3886_bl.c4
-rw-r--r--drivers/video/backlight/ktd253-backlight.c5
-rw-r--r--drivers/video/backlight/ktz8866.c4
-rw-r--r--drivers/video/backlight/led_bl.c4
-rw-r--r--drivers/video/backlight/lm3509_bl.c343
-rw-r--r--drivers/video/backlight/lm3533_bl.c3
-rw-r--r--drivers/video/backlight/lm3630a_bl.c2
-rw-r--r--drivers/video/backlight/lm3639_bl.c2
-rw-r--r--drivers/video/backlight/lv5207lp.c2
-rw-r--r--drivers/video/backlight/mp3309c.c6
-rw-r--r--drivers/video/backlight/pandora_bl.c3
-rw-r--r--drivers/video/backlight/pcf50633-backlight.c5
-rw-r--r--drivers/video/backlight/platform_lcd.c1
-rw-r--r--drivers/video/backlight/pwm_bl.c4
-rw-r--r--drivers/video/backlight/rave-sp-backlight.c2
-rw-r--r--drivers/video/backlight/rt4831-backlight.c1
-rw-r--r--drivers/video/backlight/sky81452-backlight.c2
-rw-r--r--include/linux/backlight.h20
30 files changed, 550 insertions, 64 deletions
diff --git a/Documentation/ABI/stable/sysfs-class-backlight b/Documentation/ABI/stable/sysfs-class-backlight
index 023fb52645f8..6102d6bebdf9 100644
--- a/Documentation/ABI/stable/sysfs-class-backlight
+++ b/Documentation/ABI/stable/sysfs-class-backlight
@@ -3,10 +3,11 @@ Date: April 2005
KernelVersion: 2.6.12
Contact: Richard Purdie <rpurdie@rpsys.net>
Description:
- Control BACKLIGHT power, values are FB_BLANK_* from fb.h
+ Control BACKLIGHT power, values are compatible with
+ FB_BLANK_* from fb.h
- - FB_BLANK_UNBLANK (0) : power on.
- - FB_BLANK_POWERDOWN (4) : power off
+ - 0 (FB_BLANK_UNBLANK) : power on.
+ - 4 (FB_BLANK_POWERDOWN) : power off
Users: HAL
What: /sys/class/backlight/<backlight>/brightness
diff --git a/Documentation/devicetree/bindings/leds/backlight/ti,lm3509.yaml b/Documentation/devicetree/bindings/leds/backlight/ti,lm3509.yaml
new file mode 100644
index 000000000000..482fae71dd53
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/backlight/ti,lm3509.yaml
@@ -0,0 +1,136 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/leds/backlight/ti,lm3509.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: TI LM3509 High Efficiency Boost for White LED's and/or OLED Displays
+
+maintainers:
+ - Patrick Gansterer <paroga@paroga.com>
+
+description:
+ The LM3509 current mode boost converter offers two separate outputs.
+ https://www.ti.com/product/LM3509
+
+properties:
+ compatible:
+ const: ti,lm3509
+
+ reg:
+ maxItems: 1
+
+ "#address-cells":
+ const: 1
+
+ "#size-cells":
+ const: 0
+
+ reset-gpios:
+ maxItems: 1
+
+ ti,brightness-rate-of-change-us:
+ description: Brightness Rate of Change in microseconds.
+ enum: [51, 13000, 26000, 52000]
+
+ ti,oled-mode:
+ description: Enable OLED mode.
+ type: boolean
+
+patternProperties:
+ "^led@[01]$":
+ type: object
+ description: Properties for a string of connected LEDs.
+ $ref: common.yaml#
+
+ properties:
+ reg:
+ description:
+ The control register that is used to program the two current sinks.
+ The LM3509 has two registers (BMAIN and BSUB) and are represented
+ as 0 or 1 in this property. The two current sinks can be controlled
+ independently with both registers, or register BMAIN can be
+ configured to control both sinks with the led-sources property.
+ minimum: 0
+ maximum: 1
+
+ label: true
+
+ led-sources:
+ minItems: 1
+ maxItems: 2
+ items:
+ minimum: 0
+ maximum: 1
+
+ default-brightness:
+ minimum: 0
+ maximum: 31
+ default: 18
+
+ max-brightness:
+ minimum: 0
+ maximum: 31
+ default: 31
+
+ required:
+ - reg
+
+ additionalProperties: false
+
+required:
+ - compatible
+ - reg
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ backlight@36 {
+ compatible = "ti,lm3509";
+ reg = <0x36>;
+ reset-gpios = <&gpio2 5 GPIO_ACTIVE_LOW>;
+
+ ti,oled-mode;
+ ti,brightness-rate-of-change-us = <52000>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ led@0 {
+ reg = <0>;
+ led-sources = <0 1>;
+ label = "lcd-backlight";
+ default-brightness = <12>;
+ max-brightness = <31>;
+ };
+ };
+ };
+ - |
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ backlight@36 {
+ compatible = "ti,lm3509";
+ reg = <0x36>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ led@0 {
+ reg = <0>;
+ default-brightness = <12>;
+ };
+
+ led@1 {
+ reg = <1>;
+ default-brightness = <15>;
+ };
+ };
+ };
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 230bca07b09d..3614a5d29c71 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -373,6 +373,13 @@ config BACKLIGHT_AAT2870
If you have a AnalogicTech AAT2870 say Y to enable the
backlight driver.
+config BACKLIGHT_LM3509
+ tristate "Backlight Driver for LM3509"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ This supports TI LM3509 Backlight Driver
+
config BACKLIGHT_LM3630A
tristate "Backlight Driver for LM3630A"
depends on I2C && PWM
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index 8d2cb252042d..8fc98f760a8a 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -36,6 +36,7 @@ obj-$(CONFIG_BACKLIGHT_IPAQ_MICRO) += ipaq_micro_bl.o
obj-$(CONFIG_BACKLIGHT_KTD253) += ktd253-backlight.o
obj-$(CONFIG_BACKLIGHT_KTD2801) += ktd2801-backlight.o
obj-$(CONFIG_BACKLIGHT_KTZ8866) += ktz8866.o
+obj-$(CONFIG_BACKLIGHT_LM3509) += lm3509_bl.o
obj-$(CONFIG_BACKLIGHT_LM3533) += lm3533_bl.o
obj-$(CONFIG_BACKLIGHT_LM3630A) += lm3630a_bl.o
obj-$(CONFIG_BACKLIGHT_LM3639) += lm3639_bl.o
diff --git a/drivers/video/backlight/aat2870_bl.c b/drivers/video/backlight/aat2870_bl.c
index b4c3354a1a8a..68d327ee4b2e 100644
--- a/drivers/video/backlight/aat2870_bl.c
+++ b/drivers/video/backlight/aat2870_bl.c
@@ -156,7 +156,7 @@ static int aat2870_bl_probe(struct platform_device *pdev)
bd->props.max_brightness = 255;
aat2870_bl->brightness = 0;
- bd->props.power = FB_BLANK_UNBLANK;
+ bd->props.power = BACKLIGHT_POWER_ON;
bd->props.brightness = bd->props.max_brightness;
ret = aat2870_bl_update_status(bd);
@@ -176,7 +176,7 @@ static void aat2870_bl_remove(struct platform_device *pdev)
struct aat2870_bl_driver_data *aat2870_bl = platform_get_drvdata(pdev);
struct backlight_device *bd = aat2870_bl->bd;
- bd->props.power = FB_BLANK_POWERDOWN;
+ bd->props.power = BACKLIGHT_POWER_OFF;
bd->props.brightness = 0;
backlight_update_status(bd);
}
diff --git a/drivers/video/backlight/adp8870_bl.c b/drivers/video/backlight/adp8870_bl.c
index 6bb18dc970e9..ad4bd4c8f441 100644
--- a/drivers/video/backlight/adp8870_bl.c
+++ b/drivers/video/backlight/adp8870_bl.c
@@ -963,7 +963,7 @@ static SIMPLE_DEV_PM_OPS(adp8870_i2c_pm_ops, adp8870_i2c_suspend,
adp8870_i2c_resume);
static const struct i2c_device_id adp8870_id[] = {
- { "adp8870", 0 },
+ { "adp8870" },
{ }
};
MODULE_DEVICE_TABLE(i2c, adp8870_id);
diff --git a/drivers/video/backlight/ams369fg06.c b/drivers/video/backlight/ams369fg06.c
index 57ec205d2bd2..f8442689ac43 100644
--- a/drivers/video/backlight/ams369fg06.c
+++ b/drivers/video/backlight/ams369fg06.c
@@ -10,7 +10,6 @@
#include <linux/backlight.h>
#include <linux/delay.h>
-#include <linux/fb.h>
#include <linux/lcd.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
@@ -300,7 +299,7 @@ static int ams369fg06_ldi_disable(struct ams369fg06 *lcd)
static int ams369fg06_power_is_on(int power)
{
- return power <= FB_BLANK_NORMAL;
+ return power <= BACKLIGHT_POWER_REDUCED;
}
static int ams369fg06_power_on(struct ams369fg06 *lcd)
@@ -396,8 +395,8 @@ static int ams369fg06_set_power(struct lcd_device *ld, int power)
{
struct ams369fg06 *lcd = lcd_get_data(ld);
- if (power != FB_BLANK_UNBLANK && power != FB_BLANK_POWERDOWN &&
- power != FB_BLANK_NORMAL) {
+ if (power != BACKLIGHT_POWER_ON && power != BACKLIGHT_POWER_OFF &&
+ power != BACKLIGHT_POWER_REDUCED) {
dev_err(lcd->dev, "power value should be 0, 1 or 4.\n");
return -EINVAL;
}
@@ -492,11 +491,11 @@ static int ams369fg06_probe(struct spi_device *spi)
* current lcd status is powerdown and then
* it enables lcd panel.
*/
- lcd->power = FB_BLANK_POWERDOWN;
+ lcd->power = BACKLIGHT_POWER_OFF;
- ams369fg06_power(lcd, FB_BLANK_UNBLANK);
+ ams369fg06_power(lcd, BACKLIGHT_POWER_ON);
} else {
- lcd->power = FB_BLANK_UNBLANK;
+ lcd->power = BACKLIGHT_POWER_ON;
}
spi_set_drvdata(spi, lcd);
@@ -510,7 +509,7 @@ static void ams369fg06_remove(struct spi_device *spi)
{
struct ams369fg06 *lcd = spi_get_drvdata(spi);
- ams369fg06_power(lcd, FB_BLANK_POWERDOWN);
+ ams369fg06_power(lcd, BACKLIGHT_POWER_OFF);
}
#ifdef CONFIG_PM_SLEEP
@@ -524,16 +523,16 @@ static int ams369fg06_suspend(struct device *dev)
* when lcd panel is suspend, lcd panel becomes off
* regardless of status.
*/
- return ams369fg06_power(lcd, FB_BLANK_POWERDOWN);
+ return ams369fg06_power(lcd, BACKLIGHT_POWER_OFF);
}
static int ams369fg06_resume(struct device *dev)
{
struct ams369fg06 *lcd = dev_get_drvdata(dev);
- lcd->power = FB_BLANK_POWERDOWN;
+ lcd->power = BACKLIGHT_POWER_OFF;
- return ams369fg06_power(lcd, FB_BLANK_UNBLANK);
+ return ams369fg06_power(lcd, BACKLIGHT_POWER_ON);
}
#endif
@@ -544,7 +543,7 @@ static void ams369fg06_shutdown(struct spi_device *spi)
{
struct ams369fg06 *lcd = spi_get_drvdata(spi);
- ams369fg06_power(lcd, FB_BLANK_POWERDOWN);
+ ams369fg06_power(lcd, BACKLIGHT_POWER_OFF);
}
static struct spi_driver ams369fg06_driver = {
diff --git a/drivers/video/backlight/bd6107.c b/drivers/video/backlight/bd6107.c
index 6be2c67ba85c..90764f83d2f1 100644
--- a/drivers/video/backlight/bd6107.c
+++ b/drivers/video/backlight/bd6107.c
@@ -180,7 +180,7 @@ static void bd6107_remove(struct i2c_client *client)
}
static const struct i2c_device_id bd6107_ids[] = {
- { "bd6107", 0 },
+ { "bd6107" },
{ }
};
MODULE_DEVICE_TABLE(i2c, bd6107_ids);
diff --git a/drivers/video/backlight/corgi_lcd.c b/drivers/video/backlight/corgi_lcd.c
index aad1680c9075..e4fcfbe38dc6 100644
--- a/drivers/video/backlight/corgi_lcd.c
+++ b/drivers/video/backlight/corgi_lcd.c
@@ -526,7 +526,7 @@ static int corgi_lcd_probe(struct spi_device *spi)
return PTR_ERR(lcd->bl_dev);
lcd->bl_dev->props.brightness = pdata->default_intensity;
- lcd->bl_dev->props.power = FB_BLANK_UNBLANK;
+ lcd->bl_dev->props.power = BACKLIGHT_POWER_ON;
ret = setup_gpio_backlight(lcd, pdata);
if (ret)
@@ -547,7 +547,7 @@ static void corgi_lcd_remove(struct spi_device *spi)
{
struct corgi_lcd *lcd = spi_get_drvdata(spi);
- lcd->bl_dev->props.power = FB_BLANK_UNBLANK;
+ lcd->bl_dev->props.power = BACKLIGHT_POWER_ON;
lcd->bl_dev->props.brightness = 0;
backlight_update_status(lcd->bl_dev);
corgi_lcd_set_power(lcd->lcd_dev, FB_BLANK_POWERDOWN);
diff --git a/drivers/video/backlight/gpio_backlight.c b/drivers/video/backlight/gpio_backlight.c
index 4476c317ce29..728a546904b0 100644
--- a/drivers/video/backlight/gpio_backlight.c
+++ b/drivers/video/backlight/gpio_backlight.c
@@ -5,7 +5,6 @@
#include <linux/backlight.h>
#include <linux/err.h>
-#include <linux/fb.h>
#include <linux/gpio/consumer.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -81,12 +80,12 @@ static int gpio_backlight_probe(struct platform_device *pdev)
/* Set the initial power state */
if (!of_node || !of_node->phandle)
/* Not booted with device tree or no phandle link to the node */
- bl->props.power = def_value ? FB_BLANK_UNBLANK
- : FB_BLANK_POWERDOWN;
+ bl->props.power = def_value ? BACKLIGHT_POWER_ON
+ : BACKLIGHT_POWER_OFF;
else if (gpiod_get_value_cansleep(gbl->gpiod) == 0)
- bl->props.power = FB_BLANK_POWERDOWN;
+ bl->props.power = BACKLIGHT_POWER_OFF;
else
- bl->props.power = FB_BLANK_UNBLANK;
+ bl->props.power = BACKLIGHT_POWER_ON;
bl->props.brightness = 1;
diff --git a/drivers/video/backlight/ipaq_micro_bl.c b/drivers/video/backlight/ipaq_micro_bl.c
index f595b8c8cbb2..19ff66e444bc 100644
--- a/drivers/video/backlight/ipaq_micro_bl.c
+++ b/drivers/video/backlight/ipaq_micro_bl.c
@@ -7,7 +7,6 @@
#include <linux/backlight.h>
#include <linux/err.h>
-#include <linux/fb.h>
#include <linux/init.h>
#include <linux/mfd/ipaq-micro.h>
#include <linux/module.h>
@@ -42,7 +41,7 @@ static const struct backlight_ops micro_bl_ops = {
static const struct backlight_properties micro_bl_props = {
.type = BACKLIGHT_RAW,
.max_brightness = 255,
- .power = FB_BLANK_UNBLANK,
+ .power = BACKLIGHT_POWER_ON,
.brightness = 64,
};
diff --git a/drivers/video/backlight/jornada720_bl.c b/drivers/video/backlight/jornada720_bl.c
index 066d0dc98f60..e28d2c071798 100644
--- a/drivers/video/backlight/jornada720_bl.c
+++ b/drivers/video/backlight/jornada720_bl.c
@@ -7,7 +7,6 @@
#include <linux/backlight.h>
#include <linux/device.h>
-#include <linux/fb.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
@@ -121,7 +120,7 @@ static int jornada_bl_probe(struct platform_device *pdev)
return ret;
}
- bd->props.power = FB_BLANK_UNBLANK;
+ bd->props.power = BACKLIGHT_POWER_ON;
bd->props.brightness = BL_DEF_BRIGHT;
/*
* note. make sure max brightness is set otherwise
diff --git a/drivers/video/backlight/kb3886_bl.c b/drivers/video/backlight/kb3886_bl.c
index 55794b239cff..050b5c21f4a8 100644
--- a/drivers/video/backlight/kb3886_bl.c
+++ b/drivers/video/backlight/kb3886_bl.c
@@ -10,9 +10,9 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/mutex.h>
-#include <linux/fb.h>
#include <linux/backlight.h>
#include <linux/delay.h>
#include <linux/dmi.h>
@@ -151,7 +151,7 @@ static int kb3886bl_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, kb3886_backlight_device);
- kb3886_backlight_device->props.power = FB_BLANK_UNBLANK;
+ kb3886_backlight_device->props.power = BACKLIGHT_POWER_ON;
kb3886_backlight_device->props.brightness = machinfo->default_intensity;
backlight_update_status(kb3886_backlight_device);
diff --git a/drivers/video/backlight/ktd253-backlight.c b/drivers/video/backlight/ktd253-backlight.c
index d7d43454f64a..327b4ee75254 100644
--- a/drivers/video/backlight/ktd253-backlight.c
+++ b/drivers/video/backlight/ktd253-backlight.c
@@ -7,7 +7,6 @@
#include <linux/backlight.h>
#include <linux/delay.h>
#include <linux/err.h>
-#include <linux/fb.h>
#include <linux/gpio/consumer.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -190,10 +189,10 @@ static int ktd253_backlight_probe(struct platform_device *pdev)
/* When we just enable the GPIO line we set max brightness */
if (brightness) {
bl->props.brightness = brightness;
- bl->props.power = FB_BLANK_UNBLANK;
+ bl->props.power = BACKLIGHT_POWER_ON;
} else {
bl->props.brightness = 0;
- bl->props.power = FB_BLANK_POWERDOWN;
+ bl->props.power = BACKLIGHT_POWER_OFF;
}
ktd253->bl = bl;
diff --git a/drivers/video/backlight/ktz8866.c b/drivers/video/backlight/ktz8866.c
index 014877b5a984..2e508741c0af 100644
--- a/drivers/video/backlight/ktz8866.c
+++ b/drivers/video/backlight/ktz8866.c
@@ -179,8 +179,8 @@ static void ktz8866_remove(struct i2c_client *client)
}
static const struct i2c_device_id ktz8866_ids[] = {
- { "ktz8866", 0 },
- {},
+ { "ktz8866" },
+ {}
};
MODULE_DEVICE_TABLE(i2c, ktz8866_ids);
diff --git a/drivers/video/backlight/led_bl.c b/drivers/video/backlight/led_bl.c
index 032f8bddf872..c7aefcd6e4e3 100644
--- a/drivers/video/backlight/led_bl.c
+++ b/drivers/video/backlight/led_bl.c
@@ -200,8 +200,8 @@ static int led_bl_probe(struct platform_device *pdev)
props.type = BACKLIGHT_RAW;
props.max_brightness = priv->max_brightness;
props.brightness = priv->default_brightness;
- props.power = (priv->default_brightness > 0) ? FB_BLANK_POWERDOWN :
- FB_BLANK_UNBLANK;
+ props.power = (priv->default_brightness > 0) ? BACKLIGHT_POWER_OFF :
+ BACKLIGHT_POWER_ON;
priv->bl_dev = backlight_device_register(dev_name(&pdev->dev),
&pdev->dev, priv, &led_bl_ops, &props);
if (IS_ERR(priv->bl_dev)) {
diff --git a/drivers/video/backlight/lm3509_bl.c b/drivers/video/backlight/lm3509_bl.c
new file mode 100644
index 000000000000..24e1a19ff72d
--- /dev/null
+++ b/drivers/video/backlight/lm3509_bl.c
@@ -0,0 +1,343 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <linux/backlight.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#define LM3509_NAME "lm3509_bl"
+
+#define LM3509_SINK_MAIN 0
+#define LM3509_SINK_SUB 1
+#define LM3509_NUM_SINKS 2
+
+#define LM3509_DEF_BRIGHTNESS 0x12
+#define LM3509_MAX_BRIGHTNESS 0x1F
+
+#define REG_GP 0x10
+#define REG_BMAIN 0xA0
+#define REG_BSUB 0xB0
+#define REG_MAX 0xFF
+
+enum {
+ REG_GP_ENM_BIT = 0,
+ REG_GP_ENS_BIT,
+ REG_GP_UNI_BIT,
+ REG_GP_RMP0_BIT,
+ REG_GP_RMP1_BIT,
+ REG_GP_OLED_BIT,
+};
+
+struct lm3509_bl {
+ struct regmap *regmap;
+ struct backlight_device *bl_main;
+ struct backlight_device *bl_sub;
+ struct gpio_desc *reset_gpio;
+};
+
+struct lm3509_bl_led_data {
+ const char *label;
+ int led_sources;
+ u32 brightness;
+ u32 max_brightness;
+};
+
+static void lm3509_reset(struct lm3509_bl *data)
+{
+ if (data->reset_gpio) {
+ gpiod_set_value(data->reset_gpio, 1);
+ udelay(1);
+ gpiod_set_value(data->reset_gpio, 0);
+ udelay(10);
+ }
+}
+
+static int lm3509_update_status(struct backlight_device *bl,
+ unsigned int en_mask, unsigned int br_reg)
+{
+ struct lm3509_bl *data = bl_get_data(bl);
+ int ret;
+ bool en;
+
+ ret = regmap_write(data->regmap, br_reg, backlight_get_brightness(bl));
+ if (ret < 0)
+ return ret;
+
+ en = !backlight_is_blank(bl);
+ return regmap_update_bits(data->regmap, REG_GP, en_mask,
+ en ? en_mask : 0);
+}
+
+static int lm3509_main_update_status(struct backlight_device *bl)
+{
+ return lm3509_update_status(bl, BIT(REG_GP_ENM_BIT), REG_BMAIN);
+}
+
+static const struct backlight_ops lm3509_main_ops = {
+ .options = BL_CORE_SUSPENDRESUME,
+ .update_status = lm3509_main_update_status,
+};
+
+static int lm3509_sub_update_status(struct backlight_device *bl)
+{
+ return lm3509_update_status(bl, BIT(REG_GP_ENS_BIT), REG_BSUB);
+}
+
+static const struct backlight_ops lm3509_sub_ops = {
+ .options = BL_CORE_SUSPENDRESUME,
+ .update_status = lm3509_sub_update_status,
+};
+
+static struct backlight_device *
+lm3509_backlight_register(struct device *dev, const char *name_suffix,
+ struct lm3509_bl *data,
+ const struct backlight_ops *ops,
+ const struct lm3509_bl_led_data *led_data)
+
+{
+ struct backlight_device *bd;
+ struct backlight_properties props;
+ const char *label = led_data->label;
+ char name[64];
+
+ memset(&props, 0, sizeof(props));
+ props.type = BACKLIGHT_RAW;
+ props.brightness = led_data->brightness;
+ props.max_brightness = led_data->max_brightness;
+ props.scale = BACKLIGHT_SCALE_NON_LINEAR;
+
+ if (!label) {
+ snprintf(name, sizeof(name), "lm3509-%s-%s", dev_name(dev),
+ name_suffix);
+ label = name;
+ }
+
+ bd = devm_backlight_device_register(dev, label, dev, data, ops, &props);
+ if (IS_ERR(bd))
+ return bd;
+
+ backlight_update_status(bd);
+ return bd;
+}
+
+static const struct regmap_config lm3509_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = REG_MAX,
+};
+
+static int lm3509_parse_led_sources(struct device_node *node,
+ int default_led_sources)
+{
+ u32 sources[LM3509_NUM_SINKS];
+ int ret, num_sources, i;
+
+ num_sources = of_property_count_u32_elems(node, "led-sources");
+ if (num_sources < 0)
+ return default_led_sources;
+ else if (num_sources > ARRAY_SIZE(sources))
+ return -EINVAL;
+
+ ret = of_property_read_u32_array(node, "led-sources", sources,
+ num_sources);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < num_sources; i++) {
+ if (sources[i] >= LM3509_NUM_SINKS)
+ return -EINVAL;
+
+ ret |= BIT(sources[i]);
+ }
+
+ return ret;
+}
+
+static int lm3509_parse_dt_node(struct device *dev,
+ struct lm3509_bl_led_data *led_data)
+{
+ int seen_led_sources = 0;
+
+ for_each_child_of_node_scoped(dev->of_node, child) {
+ struct lm3509_bl_led_data *ld;
+ int ret;
+ u32 reg;
+ int valid_led_sources;
+
+ ret = of_property_read_u32(child, "reg", &reg);
+ if (ret < 0)
+ return ret;
+ if (reg >= LM3509_NUM_SINKS)
+ return -EINVAL;
+ ld = &led_data[reg];
+
+ ld->le