All of lore.kernel.org
 help / color / mirror / Atom feed
From: Luka Panio <lukapanio@gmail.com>
To: lee@kernel.org, danielt@kernel.org, jingoohan1@gmail.com,
	pavel@kernel.org, robh@kernel.org, krzk+dt@kernel.org,
	conor+dt@kernel.org, deller@gmx.de
Cc: dri-devel@lists.freedesktop.org, linux-leds@vger.kernel.org,
	devicetree@vger.kernel.org, linux-fbdev@vger.kernel.org,
	linux-kernel@vger.kernel.org, Luka Panio <lukapanio@gmail.com>
Subject: [PATCH 2/2] backlight: Add Awinic AW99703 backlight driver
Date: Fri, 16 Oct 2026 18:29:12 +0200	[thread overview]
Message-ID: <20261016162912.64581-3-lukapanio@gmail.com> (raw)
In-Reply-To: <20261016162912.64581-1-lukapanio@gmail.com>

Add a driver for the Awinic AW99703 3-string WLED backlight controller.

Register values follow the AW99703 datasheet (V1.6), the structure
follows the aw99706 driver.

Signed-off-by: Luka Panio <lukapanio@gmail.com>
---
 MAINTAINERS                       |   6 +
 drivers/video/backlight/Kconfig   |  11 +
 drivers/video/backlight/Makefile  |   1 +
 drivers/video/backlight/aw99703.c | 583 ++++++++++++++++++++++++++++++
 4 files changed, 601 insertions(+)
 create mode 100644 drivers/video/backlight/aw99703.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 461a56850c84..e4168448e95c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4525,6 +4525,12 @@ L:	linux-sound@vger.kernel.org
 S:	Maintained
 F:	sound/hda/codecs/side-codecs/aw88399*
 
+AWINIC AW99703 WLED BACKLIGHT DRIVER
+M:	Luka Panio <lukapanio@gmail.com>
+S:	Maintained
+F:	Documentation/devicetree/bindings/leds/backlight/awinic,aw99703.yaml
+F:	drivers/video/backlight/aw99703.c
+
 AWINIC AW99706 WLED BACKLIGHT DRIVER
 M:	Junjie Cao <junjie.cao@linux.dev>
 S:	Maintained
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index dbf4ca23a9b6..c2494f7fa5d2 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -156,6 +156,17 @@ config BACKLIGHT_ATMEL_LCDC
 	  If in doubt, it's safe to enable this option; it doesn't kick
 	  in unless the board's description says it's wired that way.
 
+config BACKLIGHT_AW99703
+	tristate "Backlight Driver for Awinic AW99703"
+	depends on I2C
+	select REGMAP_I2C
+	help
+	  If you have a LCD backlight connected to the WLED outputs of an
+	  Awinic AW99703, say Y here to enable this driver.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called aw99703.
+
 config BACKLIGHT_AW99706
 	tristate "Backlight Driver for Awinic AW99706"
 	depends on I2C
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index 34469711c6cd..09ec9bd71c92 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_BACKLIGHT_ADP8870)		+= adp8870_bl.o
 obj-$(CONFIG_BACKLIGHT_APPLE)		+= apple_bl.o
 obj-$(CONFIG_BACKLIGHT_APPLE_DWI)	+= apple_dwi_bl.o
 obj-$(CONFIG_BACKLIGHT_AS3711)		+= as3711_bl.o
+obj-$(CONFIG_BACKLIGHT_AW99703)		+= aw99703.o
 obj-$(CONFIG_BACKLIGHT_AW99706)		+= aw99706.o
 obj-$(CONFIG_BACKLIGHT_BD6107)		+= bd6107.o
 obj-$(CONFIG_BACKLIGHT_CGBC)		+= cgbc_bl.o
diff --git a/drivers/video/backlight/aw99703.c b/drivers/video/backlight/aw99703.c
new file mode 100644
index 000000000000..b0a46753d176
--- /dev/null
+++ b/drivers/video/backlight/aw99703.c
@@ -0,0 +1,583 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * aw99703 - Backlight driver for the AWINIC AW99703
+ *
+ * Copyright (C) 2026 Luka Panio <lukapanio@gmail.com>
+ *
+ * Register layout and init sequence based on the AW99703 datasheet (V1.6)
+ */
+#include <linux/backlight.h>
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/regmap.h>
+
+#define AW99703_MAX_BRT_LVL		2047
+#define AW99703_ID			0x03
+
+#define AW99703_REG_ID			0x00
+#define AW99703_REG_SFTRST		0x01
+#define AW99703_REG_MODE		0x02
+#define AW99703_PDIS_MASK		BIT(4)
+#define AW99703_MAP_LINEAR_MASK		BIT(2)
+#define AW99703_WORKMODE_MASK		GENMASK(1, 0)
+#define AW99703_WORKMODE_STANDBY	0
+#define AW99703_WORKMODE_BACKLIGHT	1
+#define AW99703_REG_LEDCUR		0x03
+#define AW99703_BLFS_MASK		GENMASK(7, 3)
+#define AW99703_CHANNEL_MASK		GENMASK(2, 0)
+#define AW99703_REG_BSTCTR1		0x04
+#define AW99703_SW_FREQ_MASK		BIT(5)
+#define AW99703_OVPSEL_MASK		GENMASK(4, 2)
+#define AW99703_OCPSEL_MASK		GENMASK(1, 0)
+#define AW99703_REG_BSTCTR2		0x05
+#define AW99703_IDCTSEL_MASK		BIT(6)
+#define AW99703_REG_LEDLSB		0x06
+#define AW99703_BRT_LSB_MASK		GENMASK(2, 0)
+#define AW99703_REG_LEDMSB		0x07
+#define AW99703_REG_PWM			0x08
+#define AW99703_REG_TURNCFG		0x09
+#define AW99703_RAMP_ON_MASK		GENMASK(7, 4)
+#define AW99703_RAMP_OFF_MASK		GENMASK(3, 0)
+#define AW99703_REG_TRANCFG		0x0A
+#define AW99703_PWM_TRANS_MASK		GENMASK(6, 4)
+#define AW99703_I2C_TRANS_MASK		GENMASK(3, 0)
+#define AW99703_REG_FLASH		0x0B
+#define AW99703_REG_AFHIGH		0x0C
+#define AW99703_REG_AFLOW		0x0D
+#define AW99703_REG_FLAGS1		0x0E
+#define AW99703_REG_FLAGS2		0x0F
+#define AW99703_FLAGS2_MASK		GENMASK(7, 5)
+#define AW99703_REG_FLAGS3		0x11
+#define AW99703_REG_MAX			0x69
+
+#define AW99703_HWEN_ON_DELAY_US	3500
+#define AW99703_ID_RETRIES		5
+
+#define RESV	U32_MAX
+
+/* Boost switching frequency, in Hz */
+static const u32 aw99703_sw_freq_tbl[] = { 500000, 1000000 };
+
+/* Boost over-voltage protection threshold, in uV (1xx = 41.5 V) */
+static const u32 aw99703_ovp_tbl[] = {
+	17500000, 24000000, 31000000, 38000000, 41500000, RESV, RESV, RESV
+};
+
+/* Boost over-current protection threshold, in uA */
+static const u32 aw99703_ocp_tbl[] = { 900000, 1800000, 2700000, 3400000 };
+
+/* Boost inductor, in nH */
+static const u32 aw99703_inductor_tbl[] = { 4700, 10000 };
+
+/* Current sink turn on/off ramp time, in us */
+static const u32 aw99703_ramp_tbl[] = {
+	512, 1000, 2000, 4000, 8000, 16000, 32000, 64000, 128000, 256000,
+	512000, 1024000, 2048000, 4096000, 8192000, 16384000
+};
+
+/* PWM dimming transition time, in ms */
+static const u32 aw99703_pwm_trans_tbl[] = {
+	2, 4, 8, 16, 32, 64, 128, 256
+};
+
+/* I2C dimming transition time, in ms (code 0: 1 us per brightness step) */
+static const u32 aw99703_i2c_trans_tbl[] = {
+	RESV, 128, 192, 256, 320, 384, 448, 512, 576, 640, 768, 1024, 1280,
+	1536, 2560, 4096
+};
+
+struct aw99703_dt_prop {
+	const char * const name;
+	const u32 * const lookup_tbl;
+	u8 tbl_size;
+	u32 min;
+	u32 step;
+	u8 reg;
+	u8 mask;
+	u8 def_code;
+};
+
+static const struct aw99703_dt_prop aw99703_dt_props[] = {
+	{
+		.name = "awinic,sw-freq-hz",
+		.lookup_tbl = aw99703_sw_freq_tbl,
+		.tbl_size = ARRAY_SIZE(aw99703_sw_freq_tbl),
+		.reg = AW99703_REG_BSTCTR1,
+		.mask = AW99703_SW_FREQ_MASK,
+		.def_code = 1,
+	},
+	{
+		.name = "awinic,ovp-microvolt",
+		.lookup_tbl = aw99703_ovp_tbl,
+		.tbl_size = ARRAY_SIZE(aw99703_ovp_tbl),
+		.reg = AW99703_REG_BSTCTR1,
+		.mask = AW99703_OVPSEL_MASK,
+		.def_code = 3,
+	},
+	{
+		.name = "awinic,ocp-microamp",
+		.lookup_tbl = aw99703_ocp_tbl,
+		.tbl_size = ARRAY_SIZE(aw99703_ocp_tbl),
+		.reg = AW99703_REG_BSTCTR1,
+		.mask = AW99703_OCPSEL_MASK,
+		.def_code = 2,
+	},
+	{
+		.name = "awinic,inductor-nanohenry",
+		.lookup_tbl = aw99703_inductor_tbl,
+		.tbl_size = ARRAY_SIZE(aw99703_inductor_tbl),
+		.reg = AW99703_REG_BSTCTR2,
+		.mask = AW99703_IDCTSEL_MASK,
+		.def_code = 0,
+	},
+	{
+		.name = "awinic,iled-max-microamp",
+		.min = 4800,
+		.step = 800,
+		.reg = AW99703_REG_LEDCUR,
+		.mask = AW99703_BLFS_MASK,
+		.def_code = 19,
+	},
+	{
+		.name = "awinic,ramp-on-time-us",
+		.lookup_tbl = aw99703_ramp_tbl,
+		.tbl_size = ARRAY_SIZE(aw99703_ramp_tbl),
+		.reg = AW99703_REG_TURNCFG,
+		.mask = AW99703_RAMP_ON_MASK,
+		.def_code = 4,
+	},
+	{
+		.name = "awinic,ramp-off-time-us",
+		.lookup_tbl = aw99703_ramp_tbl,
+		.tbl_size = ARRAY_SIZE(aw99703_ramp_tbl),
+		.reg = AW99703_REG_TURNCFG,
+		.mask = AW99703_RAMP_OFF_MASK,
+		.def_code = 4,
+	},
+	{
+		.name = "awinic,pwm-trans-time-ms",
+		.lookup_tbl = aw99703_pwm_trans_tbl,
+		.tbl_size = ARRAY_SIZE(aw99703_pwm_trans_tbl),
+		.reg = AW99703_REG_TRANCFG,
+		.mask = AW99703_PWM_TRANS_MASK,
+		.def_code = 0,
+	},
+	{
+		.name = "awinic,i2c-trans-time-ms",
+		.lookup_tbl = aw99703_i2c_trans_tbl,
+		.tbl_size = ARRAY_SIZE(aw99703_i2c_trans_tbl),
+		.reg = AW99703_REG_TRANCFG,
+		.mask = AW99703_I2C_TRANS_MASK,
+		.def_code = 0,
+	},
+};
+
+struct reg_init_data {
+	u8 reg;
+	u8 mask;
+	u8 val;
+};
+
+#define AW99703_INIT_TBL_SIZE	(ARRAY_SIZE(aw99703_dt_props) + 3)
+
+struct aw99703_device {
+	struct device *dev;
+	struct regmap *regmap;
+	struct backlight_device *bl_dev;
+	struct gpio_desc *hwen_gpio;
+	struct reg_init_data init_tbl[AW99703_INIT_TBL_SIZE];
+	bool bl_enable;
+};
+
+static bool aw99703_readable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case AW99703_REG_ID:
+	case AW99703_REG_MODE ... AW99703_REG_FLAGS2:
+	case AW99703_REG_FLAGS3:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool aw99703_writeable_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case AW99703_REG_SFTRST ... AW99703_REG_AFLOW:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool aw99703_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case AW99703_REG_FLAGS1:
+	case AW99703_REG_FLAGS2:
+	case AW99703_REG_FLAGS3:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct regmap_config aw99703_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = AW99703_REG_MAX,
+	.readable_reg = aw99703_readable_reg,
+	.writeable_reg = aw99703_writeable_reg,
+	.volatile_reg = aw99703_volatile_reg,
+};
+
+static int aw99703_dt_lookup(const struct aw99703_dt_prop *prop, u32 dt_val,
+			     u8 *val)
+{
+	u32 max_code = prop->mask >> __ffs(prop->mask);
+	int i;
+
+	if (!prop->lookup_tbl) {
+		if (dt_val < prop->min || (dt_val - prop->min) % prop->step ||
+		    (dt_val - prop->min) / prop->step > max_code)
+			return -EINVAL;
+		*val = (dt_val - prop->min) / prop->step;
+		return 0;
+	}
+
+	for (i = 0; i < prop->tbl_size; i++)
+		if (prop->lookup_tbl[i] != RESV && prop->lookup_tbl[i] == dt_val)
+			break;
+
+	*val = i;
+	return i == prop->tbl_size ? -EINVAL : 0;
+}
+
+static void aw99703_dt_parse(struct aw99703_device *aw,
+			     struct backlight_properties *props)
+{
+	const struct aw99703_dt_prop *prop;
+	struct reg_init_data *init = aw->init_tbl;
+	bool exp_map;
+	u32 dt_val, strings = 3;
+	int i;
+	u8 val;
+
+	for (i = 0; i < ARRAY_SIZE(aw99703_dt_props); i++, init++) {
+		prop = &aw99703_dt_props[i];
+
+		val = prop->def_code;
+		if (!device_property_read_u32(aw->dev, prop->name, &dt_val) &&
+		    aw99703_dt_lookup(prop, dt_val, &val)) {
+			dev_warn(aw->dev, "invalid value %u for %s, using chip default\n",
+				 dt_val, prop->name);
+			val = prop->def_code;
+		}
+
+		init->reg = prop->reg;
+		init->mask = prop->mask;
+		init->val = val << __ffs(prop->mask);
+	}
+
+	device_property_read_u32(aw->dev, "awinic,led-strings", &strings);
+	if (strings < 1 || strings > 3) {
+		dev_warn(aw->dev, "invalid awinic,led-strings %u, using 3\n",
+			 strings);
+		strings = 3;
+	}
+	init->reg = AW99703_REG_LEDCUR;
+	init->mask = AW99703_CHANNEL_MASK;
+	init->val = GENMASK(strings - 1, 0);
+	init++;
+
+	init->reg = AW99703_REG_MODE;
+	init->mask = AW99703_PDIS_MASK;
+	init->val = device_property_read_bool(aw->dev, "awinic,pwm-input") ?
+		    0 : AW99703_PDIS_MASK;
+	init++;
+
+	exp_map = device_property_read_bool(aw->dev, "awinic,exponential-map");
+	init->reg = AW99703_REG_MODE;
+	init->mask = AW99703_MAP_LINEAR_MASK;
+	init->val = exp_map ? 0 : AW99703_MAP_LINEAR_MASK;
+	props->scale = exp_map ? BACKLIGHT_SCALE_NON_LINEAR :
+				 BACKLIGHT_SCALE_LINEAR;
+
+	props->max_brightness = AW99703_MAX_BRT_LVL;
+	device_property_read_u32(aw->dev, "max-brightness",
+				 &props->max_brightness);
+	if (props->max_brightness > AW99703_MAX_BRT_LVL)
+		props->max_brightness = AW99703_MAX_BRT_LVL;
+
+	props->brightness = props->max_brightness >> 1;
+	device_property_read_u32(aw->dev, "default-brightness",
+				 &props->brightness);
+	if (props->brightness > props->max_brightness)
+		props->brightness = props->max_brightness;
+}
+
+static int aw99703_hw_init(struct aw99703_device *aw)
+{
+	int ret, i;
+
+	if (aw->hwen_gpio) {
+		gpiod_set_value_cansleep(aw->hwen_gpio, 1);
+		fsleep(AW99703_HWEN_ON_DELAY_US);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(aw->init_tbl); i++) {
+		ret = regmap_update_bits(aw->regmap, aw->init_tbl[i].reg,
+					 aw->init_tbl[i].mask,
+					 aw->init_tbl[i].val);
+		if (ret) {
+			dev_err(aw->dev, "failed to write init data: %d\n", ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static const char * const aw99703_flags1_names[] = {
+	"over-temperature", "boost over-current", "LED3 short", "LED2 short",
+	"LED1 short", "LED3 open", "LED2 open", "LED1 open",
+};
+
+static const char * const aw99703_flags2_names[] = {
+	[5] = "flash timeout", [6] = "UVLO", [7] = "boost over-voltage",
+};
+
+static void aw99703_check_faults(struct aw99703_device *aw)
+{
+	unsigned int f1, f2;
+	unsigned long flags;
+	int bit;
+
+	if (regmap_read(aw->regmap, AW99703_REG_FLAGS1, &f1) ||
+	    regmap_read(aw->regmap, AW99703_REG_FLAGS2, &f2))
+		return;
+
+	flags = f1;
+	for_each_set_bit(bit, &flags, 8)
+		dev_warn_ratelimited(aw->dev, "fault: %s\n",
+				     aw99703_flags1_names[bit]);
+
+	flags = f2 & AW99703_FLAGS2_MASK;
+	for_each_set_bit(bit, &flags, 8)
+		dev_warn_ratelimited(aw->dev, "fault: %s\n",
+				     aw99703_flags2_names[bit]);
+}
+
+static int aw99703_update_brightness(struct aw99703_device *aw, u32 brt)
+{
+	bool enable = !!brt;
+	int ret;
+
+	ret = regmap_write(aw->regmap, AW99703_REG_LEDLSB,
+			   brt & AW99703_BRT_LSB_MASK);
+	if (ret)
+		return ret;
+
+	ret = regmap_write(aw->regmap, AW99703_REG_LEDMSB, brt >> 3);
+	if (ret)
+		return ret;
+
+	if (aw->bl_enable == enable)
+		return 0;
+
+	ret = regmap_update_bits(aw->regmap, AW99703_REG_MODE,
+				 AW99703_WORKMODE_MASK,
+				 enable ? AW99703_WORKMODE_BACKLIGHT :
+					  AW99703_WORKMODE_STANDBY);
+	if (ret) {
+		dev_err(aw->dev, "failed to %s backlight: %d\n",
+			enable ? "enable" : "disable", ret);
+		return ret;
+	}
+
+	aw->bl_enable = enable;
+	if (enable)
+		aw99703_check_faults(aw);
+
+	return 0;
+}
+
+static int aw99703_bl_update_status(struct backlight_device *bl)
+{
+	struct aw99703_device *aw = bl_get_data(bl);
+
+	return aw99703_update_brightness(aw, backlight_get_brightness(bl));
+}
+
+static const struct backlight_ops aw99703_bl_ops = {
+	.options = BL_CORE_SUSPENDRESUME,
+	.update_status = aw99703_bl_update_status,
+};
+
+static int aw99703_chip_id_read(struct aw99703_device *aw)
+{
+	unsigned int val = 0;
+	int ret = 0, i;
+
+	for (i = 0; i < AW99703_ID_RETRIES; i++) {
+		ret = regmap_read(aw->regmap, AW99703_REG_ID, &val);
+		if (!ret && val == AW99703_ID)
+			return 0;
+		fsleep(2000);
+	}
+
+	if (!ret)
+		dev_err(aw->dev, "unexpected chip id 0x%02x\n", val);
+
+	return ret ? ret : -ENODEV;
+}
+
+/*
+ * If the bootloader left the backlight on, start from its level so the
+ * handover doesn't flash the panel.
+ */
+static void aw99703_read_boot_brightness(struct aw99703_device *aw,
+					 struct backlight_properties *props)
+{
+	unsigned int mode, lsb, msb, brt;
+
+	if (regmap_read(aw->regmap, AW99703_REG_MODE, &mode) ||
+	    FIELD_GET(AW99703_WORKMODE_MASK, mode) != AW99703_WORKMODE_BACKLIGHT)
+		return;
+
+	if (regmap_read(aw->regmap, AW99703_REG_LEDLSB, &lsb) ||
+	    regmap_read(aw->regmap, AW99703_REG_LEDMSB, &msb))
+		return;
+
+	brt = (msb << 3) | (lsb & AW99703_BRT_LSB_MASK);
+	if (brt && brt <= props->max_brightness) {
+		props->brightness = brt;
+		aw->bl_enable = true;
+	}
+}
+
+static void aw99703_power_off(void *data)
+{
+	struct aw99703_device *aw = data;
+
+	aw99703_update_brightness(aw, 0);
+	gpiod_set_value_cansleep(aw->hwen_gpio, 0);
+}
+
+static int aw99703_probe(struct i2c_client *client)
+{
+	struct device *dev = &client->dev;
+	struct backlight_properties props = {};
+	struct aw99703_device *aw;
+	int ret;
+
+	aw = devm_kzalloc(dev, sizeof(*aw), GFP_KERNEL);
+	if (!aw)
+		return -ENOMEM;
+
+	aw->dev = dev;
+	i2c_set_clientdata(client, aw);
+
+	aw->regmap = devm_regmap_init_i2c(client, &aw99703_regmap_config);
+	if (IS_ERR(aw->regmap))
+		return dev_err_probe(dev, PTR_ERR(aw->regmap),
+				     "failed to init regmap\n");
+
+	aw->hwen_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_ASIS);
+	if (IS_ERR(aw->hwen_gpio))
+		return dev_err_probe(dev, PTR_ERR(aw->hwen_gpio),
+				     "failed to get enable gpio\n");
+	if (aw->hwen_gpio) {
+		ret = gpiod_direction_output(aw->hwen_gpio, 1);
+		if (ret)
+			return dev_err_probe(dev, ret,
+					     "failed to drive enable gpio\n");
+		fsleep(AW99703_HWEN_ON_DELAY_US);
+	}
+
+	ret = aw99703_chip_id_read(aw);
+	if (ret)
+		return dev_err_probe(dev, ret, "chip id check failed\n");
+
+	props.type = BACKLIGHT_RAW;
+	aw99703_dt_parse(aw, &props);
+	aw99703_read_boot_brightness(aw, &props);
+
+	ret = aw99703_hw_init(aw);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to initialize chip\n");
+
+	ret = devm_add_action_or_reset(dev, aw99703_power_off, aw);
+	if (ret)
+		return ret;
+
+	aw->bl_dev = devm_backlight_device_register(dev, "aw99703-backlight",
+						    dev, aw, &aw99703_bl_ops,
+						    &props);
+	if (IS_ERR(aw->bl_dev))
+		return dev_err_probe(dev, PTR_ERR(aw->bl_dev),
+				     "failed to register backlight\n");
+
+	return backlight_update_status(aw->bl_dev);
+}
+
+static void aw99703_shutdown(struct i2c_client *client)
+{
+	aw99703_power_off(i2c_get_clientdata(client));
+}
+
+static int aw99703_suspend(struct device *dev)
+{
+	struct aw99703_device *aw = dev_get_drvdata(dev);
+
+	if (aw->hwen_gpio) {
+		gpiod_set_value_cansleep(aw->hwen_gpio, 0);
+		aw->bl_enable = false;
+	}
+
+	return 0;
+}
+
+static int aw99703_resume(struct device *dev)
+{
+	struct aw99703_device *aw = dev_get_drvdata(dev);
+
+	return aw99703_hw_init(aw);
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(aw99703_pm_ops, aw99703_suspend,
+				aw99703_resume);
+
+static const struct i2c_device_id aw99703_ids[] = {
+	{ "aw99703" },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, aw99703_ids);
+
+static const struct of_device_id aw99703_match_table[] = {
+	{ .compatible = "awinic,aw99703" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, aw99703_match_table);
+
+static struct i2c_driver aw99703_i2c_driver = {
+	.probe = aw99703_probe,
+	.shutdown = aw99703_shutdown,
+	.id_table = aw99703_ids,
+	.driver = {
+		.name = "aw99703",
+		.of_match_table = aw99703_match_table,
+		.pm = pm_sleep_ptr(&aw99703_pm_ops),
+	},
+};
+module_i2c_driver(aw99703_i2c_driver);
+
+MODULE_AUTHOR("Luka Panio <lukapanio@gmail.com>");
+MODULE_DESCRIPTION("AWINIC AW99703 Backlight Driver");
+MODULE_LICENSE("GPL");
-- 
2.55.0


  parent reply	other threads:[~2026-10-16 16:29 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-16 16:29 [PATCH 0/2] backlight: Add Awinic AW99703 driver Luka Panio
2026-10-16 16:29 ` [PATCH 1/2] dt-bindings: leds: backlight: Add Awinic AW99703 backlight Luka Panio
2026-10-16 16:34   ` sashiko-bot
2026-10-16 16:29 ` Luka Panio [this message]
2026-10-16 16:39   ` [PATCH 2/2] backlight: Add Awinic AW99703 backlight driver sashiko-bot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261016162912.64581-3-lukapanio@gmail.com \
    --to=lukapanio@gmail.com \
    --cc=conor+dt@kernel.org \
    --cc=danielt@kernel.org \
    --cc=deller@gmx.de \
    --cc=devicetree@vger.kernel.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=jingoohan1@gmail.com \
    --cc=krzk+dt@kernel.org \
    --cc=lee@kernel.org \
    --cc=linux-fbdev@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-leds@vger.kernel.org \
    --cc=pavel@kernel.org \
    --cc=robh@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.