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@kernel.org>,
Zhang Rui <rui.zhang@intel.com>,
Lukasz Luba <lukasz.luba@arm.com>
Cc: linux-kernel@vger.kernel.org, mfd@lists.linux.dev,
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 v2 3/8] Add Advantech EIO Hardware Monitor driver
Date: Tue, 14 Jul 2026 17:54:17 +0200 [thread overview]
Message-ID: <20260714-upstream-v2-v2-3-76e5e41026db@advantech.com> (raw)
In-Reply-To: <20260714-upstream-v2-v2-0-76e5e41026db@advantech.com>
This driver controls the Hardware Monitor block of the Advantech EIO chip.
There is a separate driver for the thermal device driver
since it's a use case we support currently, but if it's
really necessary we can move it to the same driver.
Signed-off-by: Ramiro Oliveira <ramiro.oliveira@advantech.com>
---
MAINTAINERS | 1 +
drivers/hwmon/Kconfig | 10 +
drivers/hwmon/Makefile | 1 +
drivers/hwmon/eio-hwmon.c | 461 ++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 473 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index a7da47393815..6d727d5182e4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -613,6 +613,7 @@ ADVANTECH EIO DRIVER
M: Ramiro Oliveira <ramiro.oliveira@advantech.com>
S: Maintained
F: drivers/gpio/gpio-eio.c
+F: drivers/hwmon/eio-hwmon.c
F: drivers/mfd/eio_core.c
F: include/linux/mfd/eio.h
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 08c29685126a..b8fd8ded846a 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -2094,6 +2094,16 @@ config SENSORS_EIC7700_PVT
This driver can also be built as a module. If so, the module will be
called eic7700-pvt.
+config SENSORS_EIO
+ tristate "Advantech EIO HWMON"
+ depends on MFD_EIO
+ help
+ If you say yes here you get support for the Advantech EIO
+ temperature, voltage and fan speed monitoring block.
+
+ This driver can also be built as a module. If so, the module
+ will be called eio-hwmon
+
config SENSORS_EMC1403
tristate "SMSC EMC1403/23 thermal sensor"
depends on I2C
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 63809eeec2f4..8e81a2bdc99b 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -73,6 +73,7 @@ obj-$(CONFIG_SENSORS_DRIVETEMP) += drivetemp.o
obj-$(CONFIG_SENSORS_DS620) += ds620.o
obj-$(CONFIG_SENSORS_DS1621) += ds1621.o
obj-$(CONFIG_SENSORS_EIC7700_PVT) += eic7700-pvt.o
+obj-$(CONFIG_SENSORS_EIO) += eio-hwmon.o
obj-$(CONFIG_SENSORS_EMC1403) += emc1403.o
obj-$(CONFIG_SENSORS_EMC1812) += emc1812.o
obj-$(CONFIG_SENSORS_EMC2103) += emc2103.o
diff --git a/drivers/hwmon/eio-hwmon.c b/drivers/hwmon/eio-hwmon.c
new file mode 100644
index 000000000000..dd877664e9e8
--- /dev/null
+++ b/drivers/hwmon/eio-hwmon.c
@@ -0,0 +1,461 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Hardware Monitoring driver for Advantech EIO embedded controller.
+ *
+ * Copyright (C) 2025 Advantech Corporation. All rights reserved.
+ */
+
+#include <linux/errno.h>
+#include <linux/hwmon.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/eio.h>
+#include <linux/module.h>
+
+#define MAX_CMD_SIZE 4
+#define MAX_NAME 32
+
+#define EIO_ITEM_INPUT 1
+#define EIO_ITEM_MAX 2
+#define EIO_ITEM_MIN 3
+#define EIO_ITEM_CRIT 4
+#define EIO_ITEM_EMERGENCY 5
+
+#define EIO_MAX_IN 8
+#define EIO_MAX_CURR 2
+#define EIO_MAX_TEMP 4
+#define EIO_MAX_FAN 4
+#define EIO_MAX_INTRUSION 1
+
+enum _sen_type {
+ NONE,
+ VOLTAGE,
+ CURRENT,
+ TEMP,
+ FAN,
+ CASEOPEN,
+};
+
+struct eio_chan {
+ bool available;
+ u8 label_idx;
+};
+
+struct eio_hwmon_dev {
+ struct device *mfd;
+ struct eio_chan in[EIO_MAX_IN];
+ struct eio_chan curr[EIO_MAX_CURR];
+ struct eio_chan temp[EIO_MAX_TEMP];
+ struct eio_chan fan[EIO_MAX_FAN];
+ struct eio_chan intrusion;
+};
+
+static struct {
+ u8 cmd;
+ u8 max;
+ signed int shift;
+ char name[MAX_NAME];
+ u8 ctrl[16];
+ u16 multi[16];
+ char item[16][MAX_NAME];
+ char labels[32][MAX_NAME];
+} sen_info[] = {
+ { 0x00, 0, 0, "none" },
+ { 0x12, 8, 0, "in",
+ { 0xFF, 0x10, 0x11, 0x12 },
+ { 1, 10, 10, 10 },
+ { "label", "input", "max", "min" },
+ { "5V", "5Vs5", "12V", "12Vs5",
+ "3V3", "3V3", "5Vsb", "3Vsb",
+ "Vcmos", "Vbat", "Vdc", "Vstb",
+ "Vcore_a", "Vcore_b", "", "",
+ "Voem0", "Voem1", "Voem2", "Voem3"
+ },
+ },
+ { 0x1a, 2, 0, "curr",
+ { 0xFF, 0x10, 0x11, 0x12 },
+ { 1, 10, 10, 10 },
+ { "label", "input", "max", "min" },
+ { "dc", "oem0" },
+ },
+ { 0x10, 4, -2731, "temp",
+ { 0xFF, 0x10, 0x11, 0x12, 0x21, 0x41 },
+ { 1, 100, 100, 100, 100, 100 },
+ { "label", "input", "max", "min", "crit", "emergency" },
+ { "cpu0", "cpu1", "cpu2", "cpu3",
+ "sys0", "sys1", "sys2", "sys3",
+ "aux0", "aux1", "aux2", "aux3",
+ "dimm0", "dimm1", "dimm2", "dimm3",
+ "pch", "gpu", "", "",
+ "", "", "", "",
+ "", "", "", "",
+ "oem0", "oem1", "oem", "oem3" },
+ },
+ { 0x24, 4, 0, "fan",
+ { 0xFF, 0x1A },
+ { 1, 1 },
+ { "label", "input"},
+ { "cpu0", "cpu1", "cpu2", "cpu3",
+ "sys0", "sys1", "sys2", "sys3",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "",
+ "oem0", "oem1", "oem2", "oem3",
+ },
+ },
+ { 0x28, 1, 0, "intrusion",
+ { 0xFF, 0x02 },
+ { 1, 1 },
+ { "label", "input" },
+ { "case_open" }
+ }
+};
+
+static struct {
+ enum _sen_type type;
+ u8 ctrl;
+ int size;
+ bool write;
+} ctrl_para[] = {
+ { NONE, 0x00, 0, false },
+
+ { VOLTAGE, 0x00, 1, false }, { VOLTAGE, 0x01, 1, false },
+ { VOLTAGE, 0x10, 2, false }, { VOLTAGE, 0x11, 2, false },
+ { VOLTAGE, 0x12, 2, false },
+
+ { CURRENT, 0x00, 1, false }, { CURRENT, 0x01, 1, false },
+ { CURRENT, 0x10, 2, false }, { CURRENT, 0x11, 2, false },
+ { CURRENT, 0x12, 2, false },
+
+ { TEMP, 0x00, 2, false }, { TEMP, 0x01, 1, false },
+ { TEMP, 0x04, 1, false }, { TEMP, 0x10, 2, false },
+ { TEMP, 0x11, 2, false }, { TEMP, 0x12, 2, false },
+ { TEMP, 0x21, 2, false }, { TEMP, 0x41, 2, false },
+
+ { FAN, 0x00, 1, false }, { FAN, 0x01, 1, false },
+ { FAN, 0x03, 1, true }, { FAN, 0x1A, 2, false },
+
+ { CASEOPEN, 0x00, 1, false }, { CASEOPEN, 0x02, 1, true },
+};
+
+static int para_idx(enum _sen_type type, u8 ctrl)
+{
+ int i;
+
+ for (i = 1 ; i < ARRAY_SIZE(ctrl_para) ; i++)
+ if (type == ctrl_para[i].type &&
+ ctrl == ctrl_para[i].ctrl)
+ return i;
+
+ return 0;
+}
+
+static int pmc_read(struct device *mfd, enum _sen_type type, u8 dev_id, u8 ctrl, void *data)
+{
+ int idx = para_idx(type, ctrl);
+ int ret = 0;
+
+ if (idx == 0)
+ return -EINVAL;
+
+ if (WARN_ON(!data))
+ return -EINVAL;
+
+ struct pmc_op op = {
+ .cmd = sen_info[type].cmd | EIO_FLAG_PMC_READ,
+ .control = ctrl,
+ .device_id = dev_id,
+ .size = ctrl_para[idx].size,
+ .payload = (u8 *)data,
+ };
+
+ ret = eio_core_pmc_operation(mfd, &op);
+ return ret;
+}
+
+
+static umode_t eio_is_visible(const void *drvdata, enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ const struct eio_hwmon_dev *eio = drvdata;
+
+ switch (type) {
+ case hwmon_in:
+ return (channel < EIO_MAX_IN && eio->in[channel].available) ? 0444 : 0;
+ case hwmon_curr:
+ return (channel < EIO_MAX_CURR && eio->curr[channel].available) ? 0444 : 0;
+ case hwmon_temp:
+ return (channel < EIO_MAX_TEMP && eio->temp[channel].available) ? 0444 : 0;
+ case hwmon_fan:
+ return (channel < EIO_MAX_FAN && eio->fan[channel].available) ? 0444 : 0;
+ case hwmon_intrusion:
+ return (channel < EIO_MAX_INTRUSION && eio->intrusion.available) ? 0444 : 0;
+ default:
+ return 0;
+ }
+}
+
+static int eio_read(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long *val)
+{
+ struct eio_hwmon_dev *eio = dev_get_drvdata(dev);
+ u8 data[MAX_CMD_SIZE] = {};
+ enum _sen_type ec_type;
+ u8 item;
+ u32 raw;
+ int ret;
+
+ switch (type) {
+ case hwmon_in:
+ switch (attr) {
+ case hwmon_in_input:
+ item = EIO_ITEM_INPUT;
+ break;
+ case hwmon_in_max:
+ item = EIO_ITEM_MAX;
+ break;
+ case hwmon_in_min:
+ item = EIO_ITEM_MIN;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+ ec_type = VOLTAGE;
+ break;
+ case hwmon_curr:
+ switch (attr) {
+ case hwmon_curr_input:
+ item = EIO_ITEM_INPUT;
+ break;
+ case hwmon_curr_max:
+ item = EIO_ITEM_MAX;
+ break;
+ case hwmon_curr_min:
+ item = EIO_ITEM_MIN;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+ ec_type = CURRENT;
+ break;
+ case hwmon_temp:
+ switch (attr) {
+ case hwmon_temp_input:
+ item = EIO_ITEM_INPUT;
+ break;
+ case hwmon_temp_max:
+ item = EIO_ITEM_MAX;
+ break;
+ case hwmon_temp_min:
+ item = EIO_ITEM_MIN;
+ break;
+ case hwmon_temp_crit:
+ item = EIO_ITEM_CRIT;
+ break;
+ case hwmon_temp_emergency:
+ item = EIO_ITEM_EMERGENCY;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+ ec_type = TEMP;
+ break;
+ case hwmon_fan:
+ if (attr != hwmon_fan_input)
+ return -EOPNOTSUPP;
+ item = EIO_ITEM_INPUT;
+ ec_type = FAN;
+ break;
+ case hwmon_intrusion:
+ if (attr != hwmon_intrusion_alarm)
+ return -EOPNOTSUPP;
+ item = EIO_ITEM_INPUT;
+ ec_type = CASEOPEN;
+ channel = 0;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ ret = pmc_read(eio->mfd, ec_type, channel, sen_info[ec_type].ctrl[item], data);
+ if (ret)
+ return ret;
+
+ raw = (u32)data[0] | (u32)data[1] << 8 | (u32)data[2] << 16 | (u32)data[3] << 24;
+ *val = ((long)(signed int)raw + sen_info[ec_type].shift) *
+ (long)sen_info[ec_type].multi[item];
+ return 0;
+}
+
+static int eio_read_string(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, const char **str)
+{
+ struct eio_hwmon_dev *eio = dev_get_drvdata(dev);
+ enum _sen_type ec_type;
+ u8 label_idx;
+
+ switch (type) {
+ case hwmon_in:
+ if (attr != hwmon_in_label)
+ return -EOPNOTSUPP;
+ ec_type = VOLTAGE;
+ label_idx = eio->in[channel].label_idx;
+ break;
+ case hwmon_curr:
+ if (attr != hwmon_curr_label)
+ return -EOPNOTSUPP;
+ ec_type = CURRENT;
+ label_idx = eio->curr[channel].label_idx;
+ break;
+ case hwmon_temp:
+ if (attr != hwmon_temp_label)
+ return -EOPNOTSUPP;
+ ec_type = TEMP;
+ label_idx = eio->temp[channel].label_idx;
+ break;
+ case hwmon_fan:
+ if (attr != hwmon_fan_label)
+ return -EOPNOTSUPP;
+ ec_type = FAN;
+ label_idx = eio->fan[channel].label_idx;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ if (label_idx >= ARRAY_SIZE(sen_info[ec_type].labels))
+ return -EOPNOTSUPP;
+
+ *str = sen_info[ec_type].labels[label_idx];
+ return 0;
+}
+
+static const struct hwmon_ops eio_hwmon_ops = {
+ .is_visible = eio_is_visible,
+ .read = eio_read,
+ .read_string = eio_read_string,
+};
+
+static const struct hwmon_channel_info * const eio_hwmon_info[] = {
+ HWMON_CHANNEL_INFO(in,
+ HWMON_I_LABEL | HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_MIN,
+ HWMON_I_LABEL | HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_MIN,
+ HWMON_I_LABEL | HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_MIN,
+ HWMON_I_LABEL | HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_MIN,
+ HWMON_I_LABEL | HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_MIN,
+ HWMON_I_LABEL | HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_MIN,
+ HWMON_I_LABEL | HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_MIN,
+ HWMON_I_LABEL | HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_MIN),
+ HWMON_CHANNEL_INFO(curr,
+ HWMON_C_LABEL | HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_MIN,
+ HWMON_C_LABEL | HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_MIN),
+ HWMON_CHANNEL_INFO(temp,
+ HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN | HWMON_T_CRIT | HWMON_T_EMERGENCY,
+ HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN | HWMON_T_CRIT | HWMON_T_EMERGENCY,
+ HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN | HWMON_T_CRIT | HWMON_T_EMERGENCY,
+ HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN | HWMON_T_CRIT | HWMON_T_EMERGENCY),
+ HWMON_CHANNEL_INFO(fan,
+ HWMON_F_LABEL | HWMON_F_INPUT,
+ HWMON_F_LABEL | HWMON_F_INPUT,
+ HWMON_F_LABEL | HWMON_F_INPUT,
+ HWMON_F_LABEL | HWMON_F_INPUT),
+ HWMON_CHANNEL_INFO(intrusion, HWMON_INTRUSION_ALARM),
+ NULL,
+};
+
+static const struct hwmon_chip_info eio_chip_info = {
+ .ops = &eio_hwmon_ops,
+ .info = eio_hwmon_info,
+};
+
+static int hwmon_init(struct device *mfd, struct eio_hwmon_dev *eio)
+{
+ enum _sen_type type;
+ u8 i, data[MAX_CMD_SIZE];
+ int n = 0;
+ int ret;
+
+ for (type = VOLTAGE ; type <= TEMP ; type++) {
+ struct eio_chan *chans = (type == VOLTAGE) ? eio->in :
+ (type == CURRENT) ? eio->curr : eio->temp;
+
+ for (i = 0 ; i < sen_info[type].max ; i++) {
+ memset(data, 0, sizeof(data));
+ if (pmc_read(mfd, type, i, 0x00, data) ||
+ (data[0] & 0x01) == 0)
+ continue;
+
+ memset(data, 0, sizeof(data));
+ ret = pmc_read(mfd, type, i, 0x01, data);
+ if (ret != 0 && ret != -EINVAL)
+ continue;
+
+ chans[i].available = true;
+ chans[i].label_idx = data[0];
+ n++;
+ }
+ }
+
+ for (i = 0 ; i < sen_info[FAN].max ; i++) {
+ memset(data, 0, sizeof(data));
+ if (pmc_read(mfd, FAN, i, 0x00, data) ||
+ (data[0] & 0x01) == 0)
+ continue;
+
+ memset(data, 0, sizeof(data));
+ ret = pmc_read(mfd, FAN, i, 0x01, data);
+ if (ret != 0 && ret != -EINVAL)
+ continue;
+
+ eio->fan[i].available = true;
+ eio->fan[i].label_idx = data[0];
+ n++;
+ }
+
+ memset(data, 0, sizeof(data));
+ if (!pmc_read(mfd, CASEOPEN, 0, 0x00, data) && (data[0] & 0x01)) {
+ eio->intrusion.available = true;
+ n++;
+ }
+
+ return n;
+}
+
+static int hwmon_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct eio_hwmon_dev *eio;
+ struct eio_dev *eio_dev = dev_get_drvdata(dev->parent);
+ struct device *hwmon;
+
+ if (!eio_dev) {
+ dev_err(dev, "Error contact eio_core\n");
+ return -ENODEV;
+ }
+
+ eio = devm_kzalloc(dev, sizeof(*eio), GFP_KERNEL);
+ if (!eio)
+ return -ENOMEM;
+
+ eio->mfd = dev->parent;
+
+ if (hwmon_init(dev->parent, eio) <= 0)
+ return -ENODEV;
+
+ hwmon = devm_hwmon_device_register_with_info(dev, KBUILD_MODNAME,
+ eio, &eio_chip_info, NULL);
+ return PTR_ERR_OR_ZERO(hwmon);
+}
+
+static struct platform_driver eio_hwmon_driver = {
+ .probe = hwmon_probe,
+ .driver = {
+ .name = "eio_hwmon",
+ },
+};
+
+module_platform_driver(eio_hwmon_driver);
+
+MODULE_AUTHOR("Wenkai Chung <wenkai.chung@advantech.com.tw>");
+MODULE_AUTHOR("Ramiro Oliveira <ramiro.oliveira@advantech.com>");
+MODULE_DESCRIPTION("Hardware monitor driver for Advantech EIO embedded controller");
+MODULE_LICENSE("GPL");
--
2.43.0
next prev parent reply other threads:[~2026-07-14 15:55 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-14 15:54 [PATCH v2 0/8] Add support for Advantech EIO MFD series devices Ramiro Oliveira
2026-07-14 15:54 ` [PATCH v2 1/8] Add Advantech EIO driver Ramiro Oliveira
2026-07-14 15:54 ` [PATCH v2 2/8] Add Advantech EIO GPIO driver Ramiro Oliveira
2026-07-14 15:54 ` Ramiro Oliveira [this message]
2026-07-14 15:54 ` [PATCH v2 4/8] Add Advantech EIO I2C driver Ramiro Oliveira
2026-07-14 15:54 ` [PATCH v2 5/8] Add Advantech EIO Backlight driver Ramiro Oliveira
2026-07-14 15:54 ` [PATCH v2 6/8] Add Advantech EIO Watchdog driver Ramiro Oliveira
2026-07-14 15:54 ` [PATCH v2 7/8] Add Advantech EIO Thermal driver Ramiro Oliveira
2026-07-14 15:54 ` [PATCH v2 8/8] Add Advantech EIO Fan driver Ramiro Oliveira
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=20260714-upstream-v2-v2-3-76e5e41026db@advantech.com \
--to=ramiro.oliveira@advantech.com \
--cc=andi.shyti@kernel.org \
--cc=brgl@kernel.org \
--cc=daniel.lezcano@kernel.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=mfd@lists.linux.dev \
--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