From: Ramiro Oliveira <ramiro.oliveira@advantech.com>
To: Lee Jones <lee@kernel.org>, Linus Walleij <linusw@kernel.org>,
Bartosz Golaszewski <brgl@kernel.org>,
Guenter Roeck <linux@roeck-us.net>,
Andi Shyti <andi.shyti@kernel.org>,
Daniel Thompson <danielt@kernel.org>,
Jingoo Han <jingoohan1@gmail.com>, Helge Deller <deller@gmx.de>,
Wim Van Sebroeck <wim@linux-watchdog.org>,
"Rafael J. Wysocki" <rafael@kernel.org>,
Daniel Lezcano <daniel.lezcano@linaro.org>,
Zhang Rui <rui.zhang@intel.com>,
Lukasz Luba <lukasz.luba@arm.com>
Cc: linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org,
linux-hwmon@vger.kernel.org, linux-i2c@vger.kernel.org,
dri-devel@lists.freedesktop.org, linux-fbdev@vger.kernel.org,
linux-watchdog@vger.kernel.org, linux-pm@vger.kernel.org,
Wenkai Chung <wenkai.chung@advantech.com.tw>,
Francisco Aragon-Trivino
<francisco.aragon-trivino@advantech.com>,
Hongzhi Wang <hongzhi.wang@advantech.com>,
Mikhail Tsukerman <mikhail.tsukerman@advantech.com>,
Thomas Kastner <thomas.kastner@advantech.com>,
Ramiro Oliveira <ramiro.oliveira@advantech.com>
Subject: [PATCH 5/8] Add Advantech EIO Backlight driver
Date: Fri, 12 Dec 2025 17:40:56 +0100 [thread overview]
Message-ID: <20251212-upstream-v1-v1-5-d50d40ec8d8a@advantech.com> (raw)
In-Reply-To: <20251212-upstream-v1-v1-0-d50d40ec8d8a@advantech.com>
This driver controls the Video Backlight block of the Advantech EIO chip.
Signed-off-by: Ramiro Oliveira <ramiro.oliveira@advantech.com>
---
MAINTAINERS | 1 +
drivers/video/backlight/Kconfig | 6 +
drivers/video/backlight/Makefile | 1 +
drivers/video/backlight/eio_bl.c | 268 +++++++++++++++++++++++++++++++++++++++
4 files changed, 276 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index be9d3c4e1ce1..df4b4cc31257 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -623,6 +623,7 @@ F: drivers/gpio/gpio-eio.c
F: drivers/hwmon/eio-hwmon.c
F: drivers/i2c/busses/i2c-eio.c
F: drivers/mfd/eio_core.c
+F: drivers/video/backlight/eio_bl.c
F: include/linux/mfd/eio.h
ADXL313 THREE-AXIS DIGITAL ACCELEROMETER DRIVER
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index a1422ddd1c22..ddd3d6922553 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -496,6 +496,12 @@ config BACKLIGHT_RAVE_SP
help
Support for backlight control on RAVE SP device.
+config BACKLIGHT_EIO
+ tristate "Advantech EIO Backlight"
+ depends on MFD_EIO && BACKLIGHT_CLASS_DEVICE
+ help
+ Backlight driver for Advantech EIO.
+
config BACKLIGHT_LED
tristate "Generic LED based Backlight Driver"
depends on LEDS_CLASS && OF
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index a5d62b018102..4601b644b6d4 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_BACKLIGHT_BD6107) += bd6107.o
obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o
obj-$(CONFIG_BACKLIGHT_DA903X) += da903x_bl.o
obj-$(CONFIG_BACKLIGHT_DA9052) += da9052_bl.o
+obj-$(CONFIG_BACKLIGHT_EIO) += eio_bl.o
obj-$(CONFIG_BACKLIGHT_EP93XX) += ep93xx_bl.o
obj-$(CONFIG_BACKLIGHT_GPIO) += gpio_backlight.o
obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o
diff --git a/drivers/video/backlight/eio_bl.c b/drivers/video/backlight/eio_bl.c
new file mode 100644
index 000000000000..2b9fd4d48d30
--- /dev/null
+++ b/drivers/video/backlight/eio_bl.c
@@ -0,0 +1,268 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Backlight driver for Advantech EIO Embedded controller.
+ *
+ * Copyright (C) 2025 Advantech Corporation. All rights reserved.
+ */
+
+#include <linux/backlight.h>
+#include <linux/errno.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/eio.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+
+#define PMC_BL_WRITE 0x20
+#define PMC_BL_READ 0x21
+
+#define BL_CTRL_STATUS 0x00
+#define BL_CTRL_ENABLE 0x12
+#define BL_CTRL_ENABLE_INVERT 0x13
+#define BL_CTRL_DUTY 0x14
+#define BL_CTRL_INVERT 0x15
+#define BL_CTRL_FREQ 0x16
+
+#define BL_MAX 2
+
+#define BL_STATUS_AVAIL 0x01
+#define BL_ENABLE_OFF 0x00
+#define BL_ENABLE_ON 0x01
+#define BL_ENABLE_AUTO BIT(1)
+
+#define USE_DEFAULT -1
+#define THERMAL_MAX 100
+
+#define BL_AVAIL BIT(0)
+#define BL_PWM_DC BIT(1)
+#define BL_PWM_SRC BIT(2)
+#define BL_BRI_INVERT BIT(3)
+#define BL_ENABLE_PIN_SUPP BIT(4)
+#define BL_POWER_INVERT BIT(5)
+#define BL_ENABLE_PIN_EN BIT(6)
+#define BL_FIRMWARE_ERROR BIT(7)
+
+static uint bri_freq = USE_DEFAULT;
+module_param(bri_freq, uint, 0444);
+MODULE_PARM_DESC(bri_freq, "Setup backlight PWM frequency.\n");
+
+static int bri_invert = USE_DEFAULT;
+module_param(bri_invert, int, 0444);
+MODULE_PARM_DESC(bri_invert, "Setup backlight PWM polarity.\n");
+
+static int bl_power_invert = USE_DEFAULT;
+module_param(bl_power_invert, int, 0444);
+MODULE_PARM_DESC(bl_power_invert, "Setup backlight enable pin polarity.\n");
+
+static int timeout;
+module_param(timeout, int, 0444);
+MODULE_PARM_DESC(timeout, "Set PMC command timeout value.\n");
+
+struct eio_bl_dev {
+ struct device *mfd;
+ u8 id;
+ u8 max;
+};
+
+static int pmc_write(struct device *mfd, u8 ctrl, u8 dev_id, void *data)
+{
+ struct pmc_op op = {
+ .cmd = PMC_BL_WRITE,
+ .control = ctrl,
+ .device_id = dev_id,
+ .payload = (u8 *)data,
+ .size = (ctrl == BL_CTRL_FREQ) ? 4 : 1,
+ .timeout = timeout,
+ };
+
+ return eio_core_pmc_operation(mfd, &op);
+}
+
+static int pmc_read(struct device *mfd, u8 ctrl, u8 dev_id, void *data)
+{
+ struct pmc_op op = {
+ .cmd = PMC_BL_READ,
+ .control = ctrl,
+ .device_id = dev_id,
+ .payload = (u8 *)data,
+ .size = (ctrl == BL_CTRL_FREQ) ? 4 : 1,
+ .timeout = timeout,
+ };
+
+ return eio_core_pmc_operation(mfd, &op);
+}
+
+static int bl_update_status(struct backlight_device *bl)
+{
+ struct eio_bl_dev *eio_bl = bl_get_data(bl);
+ u32 max = bl->props.max_brightness;
+ u8 duty = clamp_val(bl->props.brightness, 0, max);
+ u8 sw = bl->props.power == BACKLIGHT_POWER_OFF;
+ int ret;
+
+ /* Setup PWM duty */
+ ret = pmc_write(eio_bl->mfd, BL_CTRL_DUTY, eio_bl->id, &duty);
+ if (ret)
+ return ret;
+
+ /* Setup backlight enable pin */
+ return pmc_write(eio_bl->mfd, BL_CTRL_ENABLE, eio_bl->id, &sw);
+}
+
+static int bl_get_brightness(struct backlight_device *bl)
+{
+ struct eio_bl_dev *eio_bl = bl_get_data(bl);
+ u8 duty = 0;
+ int ret;
+
+ ret = pmc_read(eio_bl->mfd, BL_CTRL_DUTY, eio_bl->id, &duty);
+
+ if (ret)
+ return ret;
+
+ return duty;
+}
+
+static const struct backlight_ops bl_ops = {
+ .get_brightness = bl_get_brightness,
+ .update_status = bl_update_status,
+ .options = BL_CORE_SUSPENDRESUME,
+};
+
+static int bl_init(struct device *dev, int id,
+ struct backlight_properties *props)
+{
+ int ret;
+ u8 enabled = 0;
+ u8 status = 0;
+
+ /* Check EC-supported backlight */
+ ret = pmc_read(dev, BL_CTRL_STATUS, id, &status);
+ if (ret)
+ return ret;
+
+ if (!(status & BL_STATUS_AVAIL)) {
+ dev_dbg(dev, "eio_bl%d hardware report disabled.\n", id);
+ return -ENXIO;
+ }
+
+ ret = pmc_read(dev, BL_CTRL_DUTY, id, &props->brightness);
+ if (ret)
+ return ret;
+
+ /* Invert PWM */
+ dev_dbg(dev, "bri_invert=%d\n", bri_invert);
+ if (bri_invert > USE_DEFAULT) {
+ ret = pmc_write(dev, BL_CTRL_INVERT, id, &bri_invert);
+ if (ret)
+ return ret;
+ }
+
+ bri_invert = 0;
+ ret = pmc_read(dev, BL_CTRL_INVERT, id, &bri_invert);
+ if (ret)
+ return ret;
+
+ dev_dbg(dev, "bri_freq=%u\n", bri_freq);
+ if (bri_freq != USE_DEFAULT) {
+ ret = pmc_write(dev, BL_CTRL_FREQ, id, &bri_freq);
+ if (ret)
+ return ret;
+ }
+
+ ret = pmc_read(dev, BL_CTRL_FREQ, id, &bri_freq);
+ if (ret)
+ return ret;
+
+ dev_dbg(dev, "bl_power_invert=%d\n", bl_power_invert);
+ if (bl_power_invert >= USE_DEFAULT) {
+ ret = pmc_write(dev, BL_CTRL_ENABLE_INVERT, id, &bl_power_invert);
+ if (ret)
+ return ret;
+ }
+
+ bl_power_invert = 0;
+ ret = pmc_read(dev, BL_CTRL_ENABLE_INVERT, id, &bl_power_invert);
+ if (ret)
+ return ret;
+
+ /* Read power state */
+ ret = pmc_read(dev, BL_CTRL_ENABLE, id, &enabled);
+ if (ret)
+ return ret;
+
+ props->power = enabled ? BACKLIGHT_POWER_OFF : BACKLIGHT_POWER_ON;
+
+ return 0;
+}
+
+static int bl_probe(struct platform_device *pdev)
+{
+ u8 id;
+ struct device *dev = &pdev->dev;
+ struct eio_dev *eio_dev = dev_get_drvdata(dev->parent);
+
+ if (!eio_dev) {
+ dev_err(dev, "eio_core not present\n");
+ return -ENODEV;
+ }
+
+ for (id = 0; id < BL_MAX; id++) {
+ char name[32];
+ struct backlight_properties props;
+ struct eio_bl_dev *eio_bl;
+ struct backlight_device *bl;
+ int ret;
+
+ memset(&props, 0, sizeof(props));
+ props.type = BACKLIGHT_RAW;
+ props.max_brightness = THERMAL_MAX;
+ props.power = BACKLIGHT_POWER_OFF;
+ props.brightness = props.max_brightness;
+
+ eio_bl = devm_kzalloc(dev, sizeof(*eio_bl), GFP_KERNEL);
+ if (!eio_bl)
+ return -ENOMEM;
+
+ eio_bl->mfd = dev->parent;
+ eio_bl->id = id;
+ eio_bl->max = props.max_brightness;
+
+ ret = bl_init(eio_bl->mfd, id, &props);
+ if (ret) {
+ dev_info(dev, "%d No Backlight %u enabled!\n", ret, id);
+ continue;
+ }
+
+ snprintf(name, sizeof(name), "%s%u", pdev->name, id);
+
+ bl = devm_backlight_device_register(dev, name, dev, eio_bl,
+ &bl_ops, &props);
+
+ if (IS_ERR(bl)) {
+ ret = PTR_ERR(bl);
+ if (ret == -EPROBE_DEFER)
+ return ret;
+
+ dev_err(dev, "register %s failed: %d\n", name, ret);
+ continue;
+ }
+
+ dev_info(dev, "%s registered (max=%u)\n", name, props.max_brightness);
+ }
+
+ return 0;
+}
+
+static struct platform_driver bl_driver = {
+ .probe = bl_probe,
+ .driver = {
+ .name = "eio_bl",
+ },
+};
+
+module_platform_driver(bl_driver);
+
+MODULE_AUTHOR("Wenkai Chung <wenkai.chung@advantech.com.tw>");
+MODULE_AUTHOR("Ramiro Oliveira <ramiro.oliveira@advantech.com>");
+MODULE_DESCRIPTION("Backlight driver for Advantech EIO embedded controller");
+MODULE_LICENSE("GPL");
--
2.43.0
next prev parent reply other threads:[~2025-12-12 16:41 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-12-12 16:40 [PATCH 0/8] Add support for Advantech EIO MFD series devices Ramiro Oliveira
2025-12-12 16:40 ` [PATCH 1/8] Add Advantech EIO MFD driver Ramiro Oliveira
2025-12-13 15:19 ` kernel test robot
2025-12-12 16:40 ` [PATCH 2/8] Add Advantech EIO GPIO driver Ramiro Oliveira
2025-12-14 0:54 ` Bartosz Golaszewski
2025-12-12 16:40 ` [PATCH 3/8] Add Advantech EIO Hardware Monitor driver Ramiro Oliveira
2025-12-12 18:21 ` Guenter Roeck
2025-12-12 16:40 ` [PATCH 4/8] Add Advantech EIO I2C driver Ramiro Oliveira
2025-12-12 16:40 ` Ramiro Oliveira [this message]
2025-12-12 17:59 ` [PATCH 5/8] Add Advantech EIO Backlight driver Daniel Thompson
2025-12-12 16:40 ` [PATCH 6/8] Add Advantech EIO Watchdog driver Ramiro Oliveira
2025-12-12 18:43 ` Guenter Roeck
2025-12-12 16:40 ` [PATCH 7/8] Add Advantech EIO Thermal driver Ramiro Oliveira
2025-12-12 16:40 ` [PATCH 8/8] Add Advantech EIO Fan driver Ramiro Oliveira
2025-12-13 17:33 ` kernel test robot
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=20251212-upstream-v1-v1-5-d50d40ec8d8a@advantech.com \
--to=ramiro.oliveira@advantech.com \
--cc=andi.shyti@kernel.org \
--cc=brgl@kernel.org \
--cc=daniel.lezcano@linaro.org \
--cc=danielt@kernel.org \
--cc=deller@gmx.de \
--cc=dri-devel@lists.freedesktop.org \
--cc=francisco.aragon-trivino@advantech.com \
--cc=hongzhi.wang@advantech.com \
--cc=jingoohan1@gmail.com \
--cc=lee@kernel.org \
--cc=linusw@kernel.org \
--cc=linux-fbdev@vger.kernel.org \
--cc=linux-gpio@vger.kernel.org \
--cc=linux-hwmon@vger.kernel.org \
--cc=linux-i2c@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pm@vger.kernel.org \
--cc=linux-watchdog@vger.kernel.org \
--cc=linux@roeck-us.net \
--cc=lukasz.luba@arm.com \
--cc=mikhail.tsukerman@advantech.com \
--cc=rafael@kernel.org \
--cc=rui.zhang@intel.com \
--cc=thomas.kastner@advantech.com \
--cc=wenkai.chung@advantech.com.tw \
--cc=wim@linux-watchdog.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).