public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/9] mfd: Add support for Asus Transformer embedded controller
@ 2026-02-09 10:43 Svyatoslav Ryhel
  2026-02-09 10:43 ` [PATCH v2 1/9] dt-bindings: misc: document ASUS Transformers EC DockRAM Svyatoslav Ryhel
                   ` (8 more replies)
  0 siblings, 9 replies; 30+ messages in thread
From: Svyatoslav Ryhel @ 2026-02-09 10:43 UTC (permalink / raw)
  To: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Dmitry Torokhov, Pavel Machek, Arnd Bergmann, Greg Kroah-Hartman,
	Sebastian Reichel, Svyatoslav Ryhel, Michał Mirosław,
	Ion Agorria
  Cc: devicetree, linux-kernel, linux-input, linux-leds, linux-pm

Add support for embedded controller used in Asus Transformers for
managing power and input functions.

---
Changes in v2:
- converted sysfs debug exports into debugfs
- added kernel-doc comments for exposed functions
- fixed minor typos and inconsistencies
---

Michał Mirosław (7):
  misc: Support Asus Transformer's EC access device
  mfd: Add driver for Asus Transformer embedded controller
  input: serio: Add driver for Asus Transformer dock keyboard and
    touchpad
  input: keyboard: Add driver for Asus Transformer dock multimedia keys
  leds: Add driver for Asus Transformer LEDs
  power: supply: Add driver for Asus Transformer battery
  power: supply: Add charger driver for Asus Transformers

Svyatoslav Ryhel (2):
  dt-bindings: misc: document ASUS Transformers EC DockRAM
  dt-bindings: mfd: document ASUS Transformer EC

 .../devicetree/bindings/mfd/asus,ec.yaml      | 152 ++++++
 .../bindings/misc/asus,dockram.yaml           |  40 ++
 drivers/input/keyboard/Kconfig                |  10 +
 drivers/input/keyboard/Makefile               |   1 +
 drivers/input/keyboard/asus-ec-keys.c         | 285 +++++++++++
 drivers/input/serio/Kconfig                   |  15 +
 drivers/input/serio/Makefile                  |   1 +
 drivers/input/serio/asus-ec-kbc.c             | 160 ++++++
 drivers/leds/Kconfig                          |  11 +
 drivers/leds/Makefile                         |   1 +
 drivers/leds/leds-asus-ec.c                   | 104 ++++
 drivers/mfd/Kconfig                           |  15 +
 drivers/mfd/Makefile                          |   1 +
 drivers/mfd/asus-ec.c                         | 467 ++++++++++++++++++
 drivers/misc/Kconfig                          |   9 +
 drivers/misc/Makefile                         |   1 +
 drivers/misc/asus-dockram.c                   | 370 ++++++++++++++
 drivers/power/supply/Kconfig                  |  22 +
 drivers/power/supply/Makefile                 |   2 +
 drivers/power/supply/asus-ec-battery.c        | 283 +++++++++++
 drivers/power/supply/asus-ec-charger.c        | 206 ++++++++
 include/linux/mfd/asus-ec.h                   | 162 ++++++
 22 files changed, 2318 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/asus,ec.yaml
 create mode 100644 Documentation/devicetree/bindings/misc/asus,dockram.yaml
 create mode 100644 drivers/input/keyboard/asus-ec-keys.c
 create mode 100644 drivers/input/serio/asus-ec-kbc.c
 create mode 100644 drivers/leds/leds-asus-ec.c
 create mode 100644 drivers/mfd/asus-ec.c
 create mode 100644 drivers/misc/asus-dockram.c
 create mode 100644 drivers/power/supply/asus-ec-battery.c
 create mode 100644 drivers/power/supply/asus-ec-charger.c
 create mode 100644 include/linux/mfd/asus-ec.h

-- 
2.51.0


^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH v2 1/9] dt-bindings: misc: document ASUS Transformers EC DockRAM
  2026-02-09 10:43 [PATCH v2 0/9] mfd: Add support for Asus Transformer embedded controller Svyatoslav Ryhel
@ 2026-02-09 10:43 ` Svyatoslav Ryhel
  2026-02-10  9:25   ` Krzysztof Kozlowski
  2026-02-09 10:44 ` [PATCH v2 2/9] misc: Support Asus Transformer's EC access device Svyatoslav Ryhel
                   ` (7 subsequent siblings)
  8 siblings, 1 reply; 30+ messages in thread
From: Svyatoslav Ryhel @ 2026-02-09 10:43 UTC (permalink / raw)
  To: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Dmitry Torokhov, Pavel Machek, Arnd Bergmann, Greg Kroah-Hartman,
	Sebastian Reichel, Svyatoslav Ryhel, Michał Mirosław,
	Ion Agorria
  Cc: devicetree, linux-kernel, linux-input, linux-leds, linux-pm

Documenting an I2C device used in conjunction with the EC on ASUS
Transformers. The main function of DockRAM (the name used by downstream
ASUS sources) is to provide power-related functions, such as battery and
charger communication. The device is exposed as an individual entity
because multiple embedded controllers can utilize the same DockRAM
instance.

Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
 .../bindings/misc/asus,dockram.yaml           | 40 +++++++++++++++++++
 1 file changed, 40 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/misc/asus,dockram.yaml

diff --git a/Documentation/devicetree/bindings/misc/asus,dockram.yaml b/Documentation/devicetree/bindings/misc/asus,dockram.yaml
new file mode 100644
index 000000000000..0cfde619ba01
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/asus,dockram.yaml
@@ -0,0 +1,40 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/misc/asus,dockram.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Asus Transformer EC DockRAM
+
+maintainers:
+  - Svyatoslav Ryhel <clamor95@gmail.com>
+
+description:
+  Dedicated i2c device used to provide power related functions of the
+  embedded controller used in ASUS Transformer device family.
+
+properties:
+  compatible:
+    const: asus,dockram
+
+  reg:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      dockram@17 {
+        compatible = "asus,dockram";
+        reg = <0x17>;
+      };
+    };
+...
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v2 2/9] misc: Support Asus Transformer's EC access device
  2026-02-09 10:43 [PATCH v2 0/9] mfd: Add support for Asus Transformer embedded controller Svyatoslav Ryhel
  2026-02-09 10:43 ` [PATCH v2 1/9] dt-bindings: misc: document ASUS Transformers EC DockRAM Svyatoslav Ryhel
@ 2026-02-09 10:44 ` Svyatoslav Ryhel
  2026-02-09 10:44 ` [PATCH v2 3/9] dt-bindings: mfd: document ASUS Transformer EC Svyatoslav Ryhel
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 30+ messages in thread
From: Svyatoslav Ryhel @ 2026-02-09 10:44 UTC (permalink / raw)
  To: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Dmitry Torokhov, Pavel Machek, Arnd Bergmann, Greg Kroah-Hartman,
	Sebastian Reichel, Svyatoslav Ryhel, Michał Mirosław,
	Ion Agorria
  Cc: devicetree, linux-kernel, linux-input, linux-leds, linux-pm

From: Michał Mirosław <mirq-linux@rere.qmqm.pl>

Add support for accessing Embedded Controller of Asus Transformer devices.
This will be used by the EC MFD drivers.

Co-developed-by: Svyatoslav Ryhel <clamor95@gmail.com>
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>
---
 drivers/misc/Kconfig        |   9 +
 drivers/misc/Makefile       |   1 +
 drivers/misc/asus-dockram.c | 370 ++++++++++++++++++++++++++++++++++++
 include/linux/mfd/asus-ec.h |  24 +++
 4 files changed, 404 insertions(+)
 create mode 100644 drivers/misc/asus-dockram.c
 create mode 100644 include/linux/mfd/asus-ec.h

diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index dd1ab7e445ac..e7faa7ab4199 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -50,6 +50,15 @@ config AD525X_DPOT_SPI
 	  To compile this driver as a module, choose M here: the
 	  module will be called ad525x_dpot-spi.
 
+config ASUS_DOCKRAM
+	tristate "Asus Transformer's EC DockRAM"
+	depends on I2C
+	help
+	  Select this if you are building for Asus Transformer's.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called asus-dockram.
+
 config DUMMY_IRQ
 	tristate "Dummy IRQ handler"
 	help
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index bfad6982591c..d2287e912d59 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_IBMVMC)		+= ibmvmc.o
 obj-$(CONFIG_AD525X_DPOT)	+= ad525x_dpot.o
 obj-$(CONFIG_AD525X_DPOT_I2C)	+= ad525x_dpot-i2c.o
 obj-$(CONFIG_AD525X_DPOT_SPI)	+= ad525x_dpot-spi.o
+obj-$(CONFIG_ASUS_DOCKRAM)	+= asus-dockram.o
 obj-$(CONFIG_ATMEL_SSC)		+= atmel-ssc.o
 obj-$(CONFIG_DUMMY_IRQ)		+= dummy-irq.o
 obj-$(CONFIG_ICS932S401)	+= ics932s401.o
diff --git a/drivers/misc/asus-dockram.c b/drivers/misc/asus-dockram.c
new file mode 100644
index 000000000000..ecda7b0c6d63
--- /dev/null
+++ b/drivers/misc/asus-dockram.c
@@ -0,0 +1,370 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * ASUS EC: DockRAM
+ */
+
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/mfd/asus-ec.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
+#include <linux/unaligned.h>
+
+struct dockram_ec_data {
+	struct mutex ctl_lock; /* prevent simultaneous access */
+	char ctl_data[DOCKRAM_ENTRY_BUFSIZE];
+};
+
+/**
+ * asus_dockram_read - Read a register from the DockRAM device.
+ * @client: Handle to the DockRAM device.
+ * @reg: Register to read.
+ * @buf: Byte array into which data will be read; must be large enough to
+ *	 hold the data returned by the DockRAM.
+ *
+ * This executes the DockRAM read based on the SMBus "block read" protocol
+ * or its emulation. It extracts DOCKRAM_ENTRY_SIZE bytes from the set
+ * register address.
+ *
+ * Returns a negative errno code else zero on success.
+ */
+int asus_dockram_read(struct i2c_client *client, int reg, char *buf)
+{
+	struct device *dev = &client->dev;
+	int ret;
+
+	memset(buf, 0, DOCKRAM_ENTRY_BUFSIZE);
+	ret = i2c_smbus_read_i2c_block_data(client, reg, DOCKRAM_ENTRY_BUFSIZE, buf);
+	if (ret < 0)
+		return ret;
+
+	if (buf[0] > DOCKRAM_ENTRY_SIZE) {
+		dev_err(dev, "bad data len; buffer: %*ph; ret: %d\n",
+			DOCKRAM_ENTRY_BUFSIZE, buf, ret);
+		return -EPROTO;
+	}
+
+	dev_dbg(dev, "got data; buffer: %*ph; ret: %d\n",
+		DOCKRAM_ENTRY_BUFSIZE, buf, ret);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(asus_dockram_read);
+
+/**
+ * asus_dockram_write - Write a byte array to a register of the DockRAM device.
+ * @client: Handle to the DockRAM device.
+ * @reg: Register to write to.
+ * @buf: Byte array to be written (up to DOCKRAM_ENTRY_SIZE bytes).
+ *
+ * This executes the DockRAM write based on the SMBus "block write" protocol
+ * or its emulation. It writes DOCKRAM_ENTRY_SIZE bytes to the specified
+ * register address.
+ *
+ * Returns a negative errno code else zero on success.
+ */
+int asus_dockram_write(struct i2c_client *client, int reg, const char *buf)
+{
+	if (buf[0] > DOCKRAM_ENTRY_SIZE)
+		return -EINVAL;
+
+	dev_dbg(&client->dev, "sending data; buffer: %*ph\n", buf[0] + 1, buf);
+
+	return i2c_smbus_write_i2c_block_data(client, reg, buf[0] + 1, buf);
+}
+EXPORT_SYMBOL_GPL(asus_dockram_write);
+
+/**
+ * asus_dockram_access_ctl - Read from or write to the DockRAM control register.
+ * @client: Handle to the DockRAM device.
+ * @out: Pointer to a variable where the register value will be stored.
+ * @mask: Bitmask of bits to be cleared.
+ * @xor: Bitmask of bits to be set (via XOR).
+ *
+ * This performs a control register read if @out is provided and both @mask
+ * and @xor are zero. Otherwise, it performs a control register update if
+ * @mask and @xor are provided.
+ *
+ * Returns a negative errno code else zero on success.
+ */
+int asus_dockram_access_ctl(struct i2c_client *client, u64 *out, u64 mask,
+			    u64 xor)
+{
+	struct dockram_ec_data *priv = i2c_get_clientdata(client);
+	char *buf = priv->ctl_data;
+	u64 val;
+	int ret = 0;
+
+	guard(mutex)(&priv->ctl_lock);
+
+	ret = asus_dockram_read(client, ASUSEC_DOCKRAM_CONTROL, buf);
+	if (ret < 0)
+		goto exit;
+
+	if (buf[0] != ASUSEC_CTL_SIZE) {
+		ret = -EPROTO;
+		goto exit;
+	}
+
+	val = get_unaligned_le64(buf + 1);
+
+	if (out)
+		*out = val;
+
+	if (mask || xor) {
+		put_unaligned_le64((val & ~mask) ^ xor, buf + 1);
+		ret = asus_dockram_write(client, ASUSEC_DOCKRAM_CONTROL, buf);
+	}
+
+exit:
+	if (ret < 0)
+		dev_err(&client->dev, "Failed to access control flags: %d\n",
+			ret);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(asus_dockram_access_ctl);
+
+static ssize_t dockram_read(struct file *filp, char __user *buf,
+			    size_t count, loff_t *ppos)
+{
+	struct i2c_client *client = filp->private_data;
+	unsigned int reg, rsize;
+	ssize_t n_read = 0, val;
+	loff_t off = *ppos;
+	char *data;
+	int ret;
+
+	reg = off / DOCKRAM_ENTRY_SIZE;
+	off %= DOCKRAM_ENTRY_SIZE;
+	rsize = DOCKRAM_ENTRIES * DOCKRAM_ENTRY_SIZE;
+
+	if (!count)
+		return 0;
+
+	data = kmalloc(DOCKRAM_ENTRY_BUFSIZE, GFP_KERNEL);
+
+	while (reg < DOCKRAM_ENTRIES) {
+		unsigned int len = DOCKRAM_ENTRY_SIZE - off;
+
+		if (len > rsize)
+			len = rsize;
+
+		ret = asus_dockram_read(client, reg, data);
+		if (ret < 0) {
+			if (!n_read)
+				n_read = ret;
+			break;
+		}
+
+		val = copy_to_user(buf, data + 1 + off, len);
+		if (val == len)
+			return -EFAULT;
+
+		*ppos += len;
+		n_read += len;
+
+		if (len == rsize)
+			break;
+
+		rsize -= len;
+		buf += len;
+		off = 0;
+		++reg;
+	}
+
+	kfree(data);
+
+	return n_read;
+}
+
+static int dockram_write_one(struct i2c_client *client, int reg,
+			     const char __user *buf, size_t count)
+{
+	struct dockram_ec_data *priv = i2c_get_clientdata(client);
+	int ret;
+
+	if (!count || count > DOCKRAM_ENTRY_SIZE)
+		return -EINVAL;
+	if (buf[0] != count - 1)
+		return -EINVAL;
+
+	guard(mutex)(&priv->ctl_lock);
+
+	priv->ctl_data[0] = (u8)count;
+	memcpy(priv->ctl_data + 1, buf, count);
+	ret = asus_dockram_write(client, reg, priv->ctl_data);
+
+	return ret;
+}
+
+static ssize_t dockram_write(struct file *filp, const char __user *buf,
+			     size_t count, loff_t *ppos)
+{
+	struct i2c_client *client = filp->private_data;
+	unsigned int reg;
+	loff_t off = *ppos;
+	int ret;
+
+	if (off % DOCKRAM_ENTRY_SIZE != 0)
+		return -EINVAL;
+
+	reg = off / DOCKRAM_ENTRY_SIZE;
+	if (reg >= DOCKRAM_ENTRIES)
+		return -EINVAL;
+
+	ret = dockram_write_one(client, reg, buf, count);
+
+	return ret < 0 ? ret : count;
+}
+
+static const struct debugfs_short_fops dockram_fops = {
+	.read	= dockram_read,
+	.write	= dockram_write,
+	.llseek	= default_llseek,
+};
+
+static int control_reg_get(void *client, u64 *val)
+{
+	return asus_dockram_access_ctl(client, val, 0, 0);
+}
+
+static int control_reg_set(void *client, u64 val)
+{
+	return asus_dockram_access_ctl(client, NULL, ~0ull, val);
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(control_reg_fops, control_reg_get, control_reg_set, "%016llx\n");
+
+/**
+ * asus_dockram_debugfs_init - Register DockRAM debugfs.
+ * @client: Handle to the DockRAM device.
+ * @debugfs_root: Pointer to the root directory dentry.
+ *
+ * Creates a debugfs setup for DockRAM in the directory of the linked EC.
+ * The debugfs setup must be removed by the caller.
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+void asus_dockram_debugfs_init(struct i2c_client *client, struct dentry *debugfs_root)
+{
+	struct dentry *dockram_dir;
+
+	dockram_dir = debugfs_create_dir("dockram", debugfs_root);
+
+	debugfs_create_file("control_reg", 0644, dockram_dir, client, &control_reg_fops);
+	debugfs_create_file("dockram", 0644, dockram_dir, client, &dockram_fops);
+}
+EXPORT_SYMBOL_GPL(asus_dockram_debugfs_init);
+
+static int asus_dockram_probe(struct i2c_client *client)
+{
+	struct dockram_ec_data *priv;
+	struct device *dev = &client->dev;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
+		return dev_err_probe(dev, -ENXIO,
+			"I2C bus is missing required SMBus block mode support\n");
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, priv);
+	mutex_init(&priv->ctl_lock);
+
+	return 0;
+}
+
+static const struct of_device_id asus_dockram_ids[] = {
+	{ .compatible = "asus,dockram" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, asus_dockram_ids);
+
+static struct i2c_driver asus_dockram_driver = {
+	.driver	= {
+		.name = "asus-dockram",
+		.of_match_table = of_match_ptr(asus_dockram_ids),
+	},
+	.probe = asus_dockram_probe,
+};
+module_i2c_driver(asus_dockram_driver);
+
+static void devm_i2c_device_release(struct device *dev, void *res)
+{
+	struct i2c_client **pdev = res;
+	struct i2c_client *child = *pdev;
+
+	if (child)
+		put_device(&child->dev);
+}
+
+static struct i2c_client *devm_i2c_device_get_by_phandle(struct device *dev,
+							 const char *name,
+							 int index)
+{
+	struct device_node *np;
+	struct i2c_client **pdev;
+
+	pdev = devres_alloc(devm_i2c_device_release, sizeof(*pdev),
+			    GFP_KERNEL);
+	if (!pdev)
+		return ERR_PTR(-ENOMEM);
+
+	np = of_parse_phandle(dev_of_node(dev), name, index);
+	if (!np) {
+		devres_free(pdev);
+		dev_err(dev, "can't resolve phandle %s: %d\n", name, index);
+		return ERR_PTR(-ENODEV);
+	}
+
+	*pdev = of_find_i2c_device_by_node(np);
+	of_node_put(np);
+
+	if (!*pdev) {
+		devres_free(pdev);
+		return ERR_PTR(-EPROBE_DEFER);
+	}
+
+	devres_add(dev, pdev);
+
+	return *pdev;
+}
+
+/**
+ * devm_asus_dockram_get - Device-managed request of DockRAM via device phandle.
+ * @parent: Parent device which requests the DockRAM device.
+ *
+ * Request the DockRAM device by phandle from the parent's device-tree node.
+ * The DockRAM device phandle will be automatically released and DockRAM will be
+ * detached on parent driver detach.
+ *
+ * Return: Pointer to the DockRAM I2C device on success, or an ERR_PTR on failure.
+ */
+struct i2c_client *devm_asus_dockram_get(struct device *parent)
+{
+	struct i2c_client *dockram =
+		devm_i2c_device_get_by_phandle(parent, "asus,dockram", 0);
+
+	if (IS_ERR(dockram))
+		return dockram;
+	if (!dockram->dev.driver)
+		return ERR_PTR(-EPROBE_DEFER);
+	if (dockram->dev.driver != &asus_dockram_driver.driver)
+		return ERR_PTR(-EBUSY);
+
+	return dockram;
+}
+EXPORT_SYMBOL_GPL(devm_asus_dockram_get);
+
+MODULE_AUTHOR("Michał Mirosław <mirq-linux@rere.qmqm.pl>");
+MODULE_DESCRIPTION("ASUS Transformer's dockram driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/asus-ec.h b/include/linux/mfd/asus-ec.h
new file mode 100644
index 000000000000..6a36313b9ebd
--- /dev/null
+++ b/include/linux/mfd/asus-ec.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __MISC_ASUS_EC_H
+#define __MISC_ASUS_EC_H
+
+struct i2c_client;
+
+#define DOCKRAM_ENTRIES			0x100
+#define DOCKRAM_ENTRY_SIZE		32
+#define DOCKRAM_ENTRY_BUFSIZE		(DOCKRAM_ENTRY_SIZE + 1)
+
+/* control register [0x0A] layout */
+#define ASUSEC_CTL_SIZE			8
+
+#define ASUSEC_DOCKRAM_CONTROL		0x0a
+
+/* dockram comm */
+int asus_dockram_read(struct i2c_client *client, int reg, char *buf);
+int asus_dockram_write(struct i2c_client *client, int reg, const char *buf);
+int asus_dockram_access_ctl(struct i2c_client *client,
+			    u64 *out, u64 mask, u64 xor);
+struct i2c_client *devm_asus_dockram_get(struct device *parent);
+void asus_dockram_debugfs_init(struct i2c_client *client,
+			       struct dentry *debugfs_root);
+#endif /* __MISC_ASUS_EC_H */
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v2 3/9] dt-bindings: mfd: document ASUS Transformer EC
  2026-02-09 10:43 [PATCH v2 0/9] mfd: Add support for Asus Transformer embedded controller Svyatoslav Ryhel
  2026-02-09 10:43 ` [PATCH v2 1/9] dt-bindings: misc: document ASUS Transformers EC DockRAM Svyatoslav Ryhel
  2026-02-09 10:44 ` [PATCH v2 2/9] misc: Support Asus Transformer's EC access device Svyatoslav Ryhel
@ 2026-02-09 10:44 ` Svyatoslav Ryhel
  2026-02-10  9:22   ` Krzysztof Kozlowski
  2026-02-09 10:44 ` [PATCH v2 4/9] mfd: Add driver for Asus Transformer embedded controller Svyatoslav Ryhel
                   ` (5 subsequent siblings)
  8 siblings, 1 reply; 30+ messages in thread
From: Svyatoslav Ryhel @ 2026-02-09 10:44 UTC (permalink / raw)
  To: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Dmitry Torokhov, Pavel Machek, Arnd Bergmann, Greg Kroah-Hartman,
	Sebastian Reichel, Svyatoslav Ryhel, Michał Mirosław,
	Ion Agorria
  Cc: devicetree, linux-kernel, linux-input, linux-leds, linux-pm

Document embedded controller used in ASUS Transformer device series.

Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
 .../devicetree/bindings/mfd/asus,ec.yaml      | 152 ++++++++++++++++++
 1 file changed, 152 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/asus,ec.yaml

diff --git a/Documentation/devicetree/bindings/mfd/asus,ec.yaml b/Documentation/devicetree/bindings/mfd/asus,ec.yaml
new file mode 100644
index 000000000000..1d1a62761b71
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/asus,ec.yaml
@@ -0,0 +1,152 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mfd/asus,ec.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ASUS Transformer's Embedded Controller
+
+description:
+  Several Nuvoton based Embedded Controller attached to an I2C bus,
+  running a custom ASUS firmware, specific to the Asus Transformer
+  device series.
+
+maintainers:
+  - Svyatoslav Ryhel <clamor95@gmail.com>
+
+properties:
+  compatible:
+    oneOf:
+      - enum:
+          - asus,ec-pad  # Pad part of Asus Transformer
+          - asus,ec-dock # Dock part of Asus Transformer
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  request-gpio:
+    maxItems: 1
+
+  asus,dockram:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description: I2C device used to access power related functions.
+
+  asus,clear-factory-mode:
+    type: boolean
+    description: clear Factory Mode bit in EC control register
+
+  battery:
+    type: object
+    $ref: /schemas/power/supply/power-supply.yaml
+    unevaluatedProperties: false
+
+    properties:
+      compatible:
+        const: asus,ec-battery
+
+    required:
+      - compatible
+
+  charger:
+    type: object
+    $ref: /schemas/power/supply/power-supply.yaml
+    additionalProperties: false
+
+    properties:
+      compatible:
+        const: asus,ec-charger
+
+      monitored-battery: true
+
+    required:
+      - compatible
+
+  keyboard-ext:
+    type: object
+    description: top row of multimedia keys
+    additionalProperties: false
+
+    properties:
+      compatible:
+        const: asus,ec-keys
+
+    required:
+      - compatible
+
+  led:
+    type: object
+    additionalProperties: false
+
+    properties:
+      compatible:
+        const: asus,ec-led
+
+    required:
+      - compatible
+
+  serio:
+    type: object
+    description: keyboard and touchpad
+    additionalProperties: false
+
+    properties:
+      compatible:
+        const: asus,ec-kbc
+
+    required:
+      - compatible
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - request-gpio
+  - asus,dockram
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      embedded-controller@19 {
+        compatible = "asus,ec-dock";
+        reg = <0x19>;
+
+        interrupt-parent = <&gpio>;
+        interrupts = <151 IRQ_TYPE_LEVEL_LOW>;
+
+        request-gpio = <&gpio 134 GPIO_ACTIVE_LOW>;
+        asus,dockram = <&dockram_ec>;
+
+        battery {
+          compatible = "asus,ec-battery";
+          monitored-battery = <&dock_battery>;
+        };
+
+        charger {
+          compatible = "asus,ec-charger";
+          monitored-battery = <&dock_battery>;
+        };
+
+        keyboard-ext {
+          compatible = "asus,ec-keys";
+        };
+
+        led {
+          compatible = "asus,ec-led";
+        };
+
+        serio {
+          compatible = "asus,ec-kbc";
+        };
+      };
+    };
+...
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v2 4/9] mfd: Add driver for Asus Transformer embedded controller
  2026-02-09 10:43 [PATCH v2 0/9] mfd: Add support for Asus Transformer embedded controller Svyatoslav Ryhel
                   ` (2 preceding siblings ...)
  2026-02-09 10:44 ` [PATCH v2 3/9] dt-bindings: mfd: document ASUS Transformer EC Svyatoslav Ryhel
@ 2026-02-09 10:44 ` Svyatoslav Ryhel
  2026-03-06  9:18   ` Lee Jones
  2026-02-09 10:44 ` [PATCH v2 5/9] input: serio: Add driver for Asus Transformer dock keyboard and touchpad Svyatoslav Ryhel
                   ` (4 subsequent siblings)
  8 siblings, 1 reply; 30+ messages in thread
From: Svyatoslav Ryhel @ 2026-02-09 10:44 UTC (permalink / raw)
  To: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Dmitry Torokhov, Pavel Machek, Arnd Bergmann, Greg Kroah-Hartman,
	Sebastian Reichel, Svyatoslav Ryhel, Michał Mirosław,
	Ion Agorria
  Cc: devicetree, linux-kernel, linux-input, linux-leds, linux-pm

From: Michał Mirosław <mirq-linux@rere.qmqm.pl>

Support Nuvoton NPCE795-based ECs as used in Asus Transformer TF201,
TF300T, TF300TG, TF300TL and TF700T pad and dock, as well as TF101 dock
and TF600T, P1801-T and TF701T pad. This is a glue driver handling
detection and common operations for EC's functions.

Co-developed-by: Svyatoslav Ryhel <clamor95@gmail.com>
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>
---
 drivers/mfd/Kconfig         |  15 ++
 drivers/mfd/Makefile        |   1 +
 drivers/mfd/asus-ec.c       | 467 ++++++++++++++++++++++++++++++++++++
 include/linux/mfd/asus-ec.h | 138 +++++++++++
 4 files changed, 621 insertions(+)
 create mode 100644 drivers/mfd/asus-ec.c

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 7192c9d1d268..312fd15eec6a 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -137,6 +137,21 @@ config MFD_AAT2870_CORE
 	  additional drivers must be enabled in order to use the
 	  functionality of the device.
 
+config MFD_ASUSEC
+	tristate "ASUS Transformer's embedded controller"
+	depends on I2C && OF
+	select SYSFS
+	select ASUS_DOCKRAM
+	help
+	  Support ECs found in ASUS Transformer's Pad and Mobile Dock.
+
+	  This provides shared glue for functional part drivers:
+	    asus-ec-kbc, asus-ec-keys, leds-asus-ec, asus-ec-battery
+	    and asus-ec-charger.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called asus-ec.
+
 config MFD_AT91_USART
 	tristate "AT91 USART Driver"
 	select MFD_CORE
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index e75e8045c28a..b676922601ba 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_MFD_88PM805)	+= 88pm805.o 88pm80x.o
 obj-$(CONFIG_MFD_88PM886_PMIC)	+= 88pm886.o
 obj-$(CONFIG_MFD_ACT8945A)	+= act8945a.o
 obj-$(CONFIG_MFD_SM501)		+= sm501.o
+obj-$(CONFIG_MFD_ASUSEC)	+= asus-ec.o
 obj-$(CONFIG_ARCH_BCM2835)	+= bcm2835-pm.o
 obj-$(CONFIG_MFD_BCM590XX)	+= bcm590xx.o
 obj-$(CONFIG_MFD_BD9571MWV)	+= bd9571mwv.o
diff --git a/drivers/mfd/asus-ec.c b/drivers/mfd/asus-ec.c
new file mode 100644
index 000000000000..e151c1506aa2
--- /dev/null
+++ b/drivers/mfd/asus-ec.c
@@ -0,0 +1,467 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * ASUS EC driver
+ */
+
+#include <linux/array_size.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/asus-ec.h>
+#include <linux/mfd/core.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/property.h>
+#include <linux/string.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
+
+#define ASUSEC_RSP_BUFFER_SIZE		8
+
+struct asus_ec_chip_data {
+	const char *name;
+	const struct mfd_cell *mfd_devices;
+	unsigned int num_devices;
+};
+
+struct asus_ec_data {
+	struct asusec_info info;
+	struct mutex ecreq_lock; /* prevent simultaneous access */
+	struct gpio_desc *ecreq;
+	struct i2c_client *self;
+	const struct asus_ec_chip_data *data;
+	u8 ec_data[DOCKRAM_ENTRY_BUFSIZE];
+	bool clr_fmode;
+	bool logging_disabled;
+};
+
+#define to_ec_data(ec) \
+	container_of(ec, struct asus_ec_data, info)
+
+static void asus_ec_remove_notifier(struct device *dev, void *res)
+{
+	struct asusec_info *ec = dev_get_drvdata(dev->parent);
+	struct notifier_block **nb = res;
+
+	blocking_notifier_chain_unregister(&ec->notify_list, *nb);
+}
+
+/**
+ * devm_asus_ec_register_notifier - Managed registration of notifier to an
+ *				    ASUS EC blocking notifier chain.
+ * @pdev: Device requesting the notifier (used for resource management).
+ * @nb: Notifier block to be registered.
+ *
+ * Register a notifier to the ASUS EC blocking notifier chain. The notifier
+ * will be automatically unregistered when the requesting device is detached.
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int devm_asus_ec_register_notifier(struct platform_device *pdev,
+				   struct notifier_block *nb)
+{
+	struct asusec_info *ec = dev_get_drvdata(pdev->dev.parent);
+	struct notifier_block **res;
+	int ret;
+
+	res = devres_alloc(asus_ec_remove_notifier, sizeof(*res), GFP_KERNEL);
+	if (!res)
+		return -ENOMEM;
+
+	*res = nb;
+	ret = blocking_notifier_chain_register(&ec->notify_list, nb);
+	if (ret) {
+		devres_free(res);
+		return ret;
+	}
+
+	devres_add(&pdev->dev, res);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(devm_asus_ec_register_notifier);
+
+static int asus_ec_signal_request(const struct asusec_info *ec)
+{
+	struct asus_ec_data *priv = to_ec_data(ec);
+
+	guard(mutex)(&priv->ecreq_lock);
+
+	dev_dbg(&priv->self->dev, "EC request\n");
+
+	gpiod_set_value_cansleep(priv->ecreq, 1);
+	msleep(50);
+
+	gpiod_set_value_cansleep(priv->ecreq, 0);
+	msleep(200);
+
+	return 0;
+}
+
+static int asus_ec_write(struct asus_ec_data *priv, u16 data)
+{
+	int ret = i2c_smbus_write_word_data(priv->self, ASUSEC_WRITE_BUF, data);
+
+	dev_dbg(&priv->self->dev, "EC write: %04x, ret = %d\n", data, ret);
+	return ret;
+}
+
+static int asus_ec_read(struct asus_ec_data *priv, bool in_irq)
+{
+	int ret = i2c_smbus_read_i2c_block_data(priv->self, ASUSEC_READ_BUF,
+						sizeof(priv->ec_data),
+						priv->ec_data);
+
+	dev_dbg(&priv->self->dev, "EC read: %*ph, ret = %d%s\n",
+		sizeof(priv->ec_data), priv->ec_data,
+		ret, in_irq ? "; in irq" : "");
+
+	return ret;
+}
+
+/**
+ * asus_ec_i2c_command - Send a 16-bit command to the ASUS EC.
+ * @ec: Pointer to the shared ASUS EC structure.
+ * @data: The 16-bit command (word) to be sent.
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
+int asus_ec_i2c_command(const struct asusec_info *ec, u16 data)
+{
+	return asus_ec_write(to_ec_data(ec), data);
+}
+EXPORT_SYMBOL_GPL(asus_ec_i2c_command);
+
+static void asus_ec_clear_buffer(struct asus_ec_data *priv)
+{
+	int retry = ASUSEC_RSP_BUFFER_SIZE;
+
+	while (retry--) {
+		if (asus_ec_read(priv, false) < 0)
+			continue;
+
+		if (priv->ec_data[1] & ASUSEC_OBF_MASK)
+			continue;
+
+		break;
+	}
+}
+
+static int asus_ec_log_info(struct asus_ec_data *priv, unsigned int reg,
+			    const char *name, char **out)
+{
+	char buf[DOCKRAM_ENTRY_BUFSIZE];
+	int ret;
+
+	ret = asus_dockram_read(priv->info.dockram, reg, buf);
+	if (ret < 0)
+		return ret;
+
+	if (!priv->logging_disabled)
+		dev_info(&priv->self->dev, "%-14s: %.*s\n", name, buf[0], buf + 1);
+
+	if (out)
+		*out = kstrndup(buf + 1, buf[0], GFP_KERNEL);
+
+	return 0;
+}
+
+static int asus_ec_reset(struct asus_ec_data *priv)
+{
+	int retry, ret;
+
+	for (retry = 0; retry < 3; retry++) {
+		ret = asus_ec_write(priv, 0);
+		if (!ret)
+			return 0;
+
+		msleep(300);
+	}
+
+	return ret;
+}
+
+static int asus_ec_magic_debug(struct asus_ec_data *priv)
+{
+	u64 flag;
+	int ret;
+
+	ret = asus_ec_get_ctl(&priv->info, &flag);
+	if (ret < 0)
+		return ret;
+
+	flag &= ASUSEC_CTL_SUSB_MODE;
+	dev_info(&priv->self->dev, "EC FW behaviour: %s\n",
+		 flag ? "susb on when receive ec_req" : "susb on when system wakeup");
+
+	return 0;
+}
+
+static int asus_ec_set_factory_mode(struct asus_ec_data *priv, bool on)
+{
+	dev_info(&priv->self->dev, "Entering %s mode.\n", on ? "factory" : "normal");
+	return asus_ec_update_ctl(&priv->info, ASUSEC_CTL_FACTORY_MODE,
+				  on ? ASUSEC_CTL_FACTORY_MODE : 0);
+}
+
+static void asus_ec_handle_smi(struct asus_ec_data *priv, unsigned int code);
+
+static irqreturn_t asus_ec_interrupt(int irq, void *dev_id)
+{
+	struct asus_ec_data *priv = dev_id;
+	unsigned long notify_action;
+	int ret;
+
+	ret = asus_ec_read(priv, true);
+	if (ret <= 0 || !(priv->ec_data[1] & ASUSEC_OBF_MASK))
+		return IRQ_NONE;
+
+	notify_action = priv->ec_data[1];
+	if (notify_action & ASUSEC_SMI_MASK) {
+		unsigned int code = priv->ec_data[2];
+
+		asus_ec_handle_smi(priv, code);
+
+		notify_action |= code << 8;
+		dev_dbg(&priv->self->dev, "SMI code: 0x%02x\n", code);
+	}
+
+	blocking_notifier_call_chain(&priv->info.notify_list,
+				     notify_action, priv->ec_data);
+
+	return IRQ_HANDLED;
+}
+
+static int asus_ec_detect(struct asus_ec_data *priv)
+{
+	char *model = NULL;
+	int ret;
+
+	ret = asus_ec_reset(priv);
+	if (ret)
+		goto err_exit;
+
+	asus_ec_clear_buffer(priv);
+
+	ret = asus_ec_log_info(priv, ASUSEC_DOCKRAM_INFO_MODEL, "model", &model);
+	if (ret)
+		goto err_exit;
+
+	ret = asus_ec_log_info(priv, ASUSEC_DOCKRAM_INFO_FW, "FW version", NULL);
+	if (ret)
+		goto err_exit;
+
+	ret = asus_ec_log_info(priv, ASUSEC_DOCKRAM_INFO_CFGFMT, "Config format", NULL);
+	if (ret)
+		goto err_exit;
+
+	ret = asus_ec_log_info(priv, ASUSEC_DOCKRAM_INFO_HW, "HW version", NULL);
+	if (ret)
+		goto err_exit;
+
+	priv->logging_disabled = true;
+
+	ret = asus_ec_magic_debug(priv);
+	if (ret)
+		goto err_exit;
+
+	priv->info.model = model;
+	priv->info.name = priv->data->name;
+
+	if (priv->clr_fmode)
+		asus_ec_set_factory_mode(priv, false);
+
+err_exit:
+	if (ret)
+		dev_err(&priv->self->dev, "failed to access EC: %d\n", ret);
+
+	return ret;
+}
+
+static void asus_ec_handle_smi(struct asus_ec_data *priv, unsigned int code)
+{
+	dev_dbg(&priv->self->dev, "SMI interrupt: 0x%02x\n", code);
+
+	switch (code) {
+	case ASUSEC_SMI_HANDSHAKE:
+	case ASUSEC_SMI_RESET:
+		asus_ec_detect(priv);
+		break;
+	}
+}
+
+static int ec_request_set(void *ec, u64 val)
+{
+	if (val)
+		asus_ec_signal_request(ec);
+
+	return 0;
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(ec_request_fops, NULL, ec_request_set, "%llu\n");
+
+static int ec_irq_set(void *ec, u64 val)
+{
+	struct asus_ec_data *priv = to_ec_data(ec);
+
+	if (val)
+		irq_wake_thread(priv->self->irq, priv);
+
+	return 0;
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(ec_irq_fops, NULL, ec_irq_set, "%llu\n");
+
+static void asus_ec_debugfs_remove(void *debugfs_root)
+{
+	debugfs_remove_recursive(debugfs_root);
+}
+
+static void devm_asus_ec_debugfs_init(struct device *dev)
+{
+	struct asusec_info *ec = dev_get_drvdata(dev);
+	struct asus_ec_data *priv = to_ec_data(ec);
+	struct dentry *debugfs_root;
+	char *name = devm_kasprintf(dev, GFP_KERNEL, "asus-ec-%s",
+				    priv->data->name);
+
+	debugfs_root = debugfs_create_dir(name, NULL);
+
+	debugfs_create_file("ec_irq", 0200, debugfs_root, ec, &ec_irq_fops);
+	debugfs_create_file("ec_request", 0200, debugfs_root, ec, &ec_request_fops);
+
+	asus_dockram_debugfs_init(priv->info.dockram, debugfs_root);
+
+	devm_add_action_or_reset(dev, asus_ec_debugfs_remove, debugfs_root);
+}
+
+static int asus_ec_probe(struct i2c_client *client)
+{
+	struct device *dev = &client->dev;
+	struct asus_ec_data *priv;
+	int ret;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->data = device_get_match_data(dev);
+	if (!priv->data)
+		return -ENODEV;
+
+	i2c_set_clientdata(client, priv);
+	priv->self = client;
+
+	priv->info.dockram = devm_asus_dockram_get(dev);
+	if (IS_ERR(priv->info.dockram))
+		return dev_err_probe(dev, PTR_ERR(priv->info.dockram),
+				     "failed to get dockram\n");
+
+	priv->ecreq = devm_gpiod_get(dev, "request", GPIOD_OUT_LOW);
+	if (IS_ERR(priv->ecreq))
+		return dev_err_probe(dev, PTR_ERR(priv->ecreq),
+				     "failed to get request GPIO\n");
+
+	BLOCKING_INIT_NOTIFIER_HEAD(&priv->info.notify_list);
+	mutex_init(&priv->ecreq_lock);
+
+	priv->clr_fmode = device_property_read_bool(dev, "asus,clear-factory-mode");
+
+	asus_ec_signal_request(&priv->info);
+
+	ret = asus_ec_detect(priv);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to detect EC version\n");
+
+	ret = devm_request_threaded_irq(dev, client->irq, NULL,
+					&asus_ec_interrupt,
+					IRQF_ONESHOT | IRQF_SHARED,
+					client->name, priv);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to register IRQ\n");
+
+	/* Parent I2C controller uses DMA, ASUS EC and child devices do not */
+	client->dev.coherent_dma_mask = 0;
+	client->dev.dma_mask = &client->dev.coherent_dma_mask;
+
+	devm_asus_ec_debugfs_init(dev);
+
+	return devm_mfd_add_devices(dev, 0, priv->data->mfd_devices,
+				    priv->data->num_devices, NULL, 0, NULL);
+}
+
+static const struct mfd_cell asus_ec_pad_mfd_devices[] = {
+	{
+		.name = "asus-ec-battery",
+		.id = 0,
+		.of_compatible = "asus,ec-battery",
+	}, {
+		.name = "asus-ec-charger",
+		.id = 0,
+		.of_compatible = "asus,ec-charger",
+	}, {
+		.name = "asus-ec-led",
+		.id = 0,
+		.of_compatible = "asus,ec-led",
+	},
+};
+
+static const struct mfd_cell asus_ec_dock_mfd_devices[] = {
+	{
+		.name = "asus-ec-battery",
+		.id = 1,
+		.of_compatible = "asus,ec-battery",
+	}, {
+		.name = "asus-ec-charger",
+		.id = 1,
+		.of_compatible = "asus,ec-charger",
+	}, {
+		.name = "asus-ec-led",
+		.id = 1,
+		.of_compatible = "asus,ec-led",
+	}, {
+		.name = "asus-ec-keys",
+		.of_compatible = "asus,ec-keys",
+	}, {
+		.name = "asus-ec-kbc",
+		.of_compatible = "asus,ec-kbc",
+	},
+};
+
+static const struct asus_ec_chip_data asus_ec_pad_data = {
+	.name = "pad",
+	.mfd_devices = asus_ec_pad_mfd_devices,
+	.num_devices = ARRAY_SIZE(asus_ec_pad_mfd_devices),
+};
+
+static const struct asus_ec_chip_data asus_ec_dock_data = {
+	.name = "dock",
+	.mfd_devices = asus_ec_dock_mfd_devices,
+	.num_devices = ARRAY_SIZE(asus_ec_dock_mfd_devices),
+};
+
+static const struct of_device_id asus_ec_match[] = {
+	{ .compatible = "asus,ec-pad", .data = &asus_ec_pad_data },
+	{ .compatible = "asus,ec-dock", .data = &asus_ec_dock_data },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, asus_ec_match);
+
+static struct i2c_driver asus_ec_driver = {
+	.driver	= {
+		.name = "asus-ec",
+		.of_match_table = asus_ec_match,
+	},
+	.probe = asus_ec_probe,
+};
+module_i2c_driver(asus_ec_driver);
+
+MODULE_AUTHOR("Michał Mirosław <mirq-linux@rere.qmqm.pl>");
+MODULE_AUTHOR("Svyatoslav Ryhel <clamor95@gmail.com>");
+MODULE_DESCRIPTION("ASUS Transformer's EC driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/asus-ec.h b/include/linux/mfd/asus-ec.h
index 6a36313b9ebd..6a06b125ba30 100644
--- a/include/linux/mfd/asus-ec.h
+++ b/include/linux/mfd/asus-ec.h
@@ -2,16 +2,78 @@
 #ifndef __MISC_ASUS_EC_H
 #define __MISC_ASUS_EC_H
 
+#include <linux/notifier.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+
 struct i2c_client;
 
+struct asusec_info {
+	const char *model;
+	const char *name;
+	struct i2c_client *dockram;
+	struct workqueue_struct *wq;
+	struct blocking_notifier_head notify_list;
+};
+
 #define DOCKRAM_ENTRIES			0x100
 #define DOCKRAM_ENTRY_SIZE		32
 #define DOCKRAM_ENTRY_BUFSIZE		(DOCKRAM_ENTRY_SIZE + 1)
 
+/* interrupt sources */
+#define ASUSEC_OBF_MASK			BIT(0)
+#define ASUSEC_KEY_MASK			BIT(2)
+#define ASUSEC_KBC_MASK			BIT(3)
+#define ASUSEC_AUX_MASK			BIT(5)
+#define ASUSEC_SCI_MASK			BIT(6)
+#define ASUSEC_SMI_MASK			BIT(7)
+
+/* SMI notification codes */
+#define ASUSEC_SMI_POWER_NOTIFY		0x31	/* [un]plugging USB cable */
+#define ASUSEC_SMI_HANDSHAKE		0x50	/* response to ec_req edge */
+#define ASUSEC_SMI_WAKE			0x53
+#define ASUSEC_SMI_RESET		0x5f
+#define ASUSEC_SMI_ADAPTER_EVENT	0x60	/* [un]plugging charger to dock */
+#define ASUSEC_SMI_BACKLIGHT_ON		0x63
+#define ASUSEC_SMI_AUDIO_DOCK_IN	0x70
+
+#define ASUSEC_SMI_ACTION(code)		(ASUSEC_SMI_MASK | ASUSEC_OBF_MASK | \
+					(ASUSEC_SMI_##code << 8))
+
 /* control register [0x0A] layout */
 #define ASUSEC_CTL_SIZE			8
 
+/*
+ * EC reports power from 40-pin connector in the LSB of the control
+ * register.  The following values have been observed (xor 0x02):
+ *
+ * PAD-ec no-plug  0x40 / PAD-ec DOCK     0x20 / DOCK-ec no-plug 0x40
+ * PAD-ec AC       0x25 / PAD-ec DOCK+AC  0x24 / DOCK-ec AC      0x25
+ * PAD-ec USB      0x45 / PAD-ec DOCK+USB 0x24 / DOCK-ec USB     0x41
+ */
+
+#define ASUSEC_CTL_DIRECT_POWER_SOURCE	BIT_ULL(0)
+#define ASUSEC_STAT_CHARGING		BIT_ULL(2)
+#define ASUSEC_CTL_FULL_POWER_SOURCE	BIT_ULL(5)
+#define ASUSEC_CTL_SUSB_MODE		BIT_ULL(11)
+#define ASUSEC_CMD_SUSPEND_S3		BIT_ULL(41)
+#define ASUSEC_CTL_TEST_DISCHARGE	BIT_ULL(43)
+#define ASUSEC_CMD_SUSPEND_INHIBIT	BIT_ULL(45)
+#define ASUSEC_CTL_FACTORY_MODE		BIT_ULL(46)
+#define ASUSEC_CTL_KEEP_AWAKE		BIT_ULL(47)
+#define ASUSEC_CTL_USB_CHARGE		BIT_ULL(50)
+#define ASUSEC_CMD_SWITCH_HDMI		BIT_ULL(70)
+#define ASUSEC_CMD_WIN_SHUTDOWN		BIT_ULL(76)
+
+#define ASUSEC_DOCKRAM_INFO_MODEL	0x01
+#define ASUSEC_DOCKRAM_INFO_FW		0x02
+#define ASUSEC_DOCKRAM_INFO_CFGFMT	0x03
+#define ASUSEC_DOCKRAM_INFO_HW		0x04
 #define ASUSEC_DOCKRAM_CONTROL		0x0a
+#define ASUSEC_DOCKRAM_BATT_CTL		0x14
+
+#define ASUSEC_WRITE_BUF		0x64
+#define ASUSEC_READ_BUF			0x6A
 
 /* dockram comm */
 int asus_dockram_read(struct i2c_client *client, int reg, char *buf);
@@ -21,4 +83,80 @@ int asus_dockram_access_ctl(struct i2c_client *client,
 struct i2c_client *devm_asus_dockram_get(struct device *parent);
 void asus_dockram_debugfs_init(struct i2c_client *client,
 			       struct dentry *debugfs_root);
+
+/* EC public API */
+
+/**
+ * cell_to_ec - Request the shared ASUS EC structure via a subdevice's pdev.
+ * @pdev: EC subdevice pdev requesting access to the shared ASUS EC structure.
+ *
+ * Returns a pointer to the asusec_info structure.
+ */
+static inline struct asusec_info *cell_to_ec(struct platform_device *pdev)
+{
+	return dev_get_drvdata(pdev->dev.parent);
+}
+
+/**
+ * asus_ec_get_ctl - Read from the DockRAM control register.
+ * @ec:  Pointer to the shared ASUS EC structure.
+ * @out: Pointer to the variable where the register value will be stored.
+ *
+ * Performs a control register read and stores the value in @out.
+ *
+ * Return: 0 on success, or a negative errno code on failure.
+ */
+static inline int asus_ec_get_ctl(const struct asusec_info *ec, u64 *out)
+{
+	return asus_dockram_access_ctl(ec->dockram, out, 0, 0);
+}
+
+/**
+ * asus_ec_update_ctl - Update the DockRAM control register.
+ * @ec:   Pointer to the shared ASUS EC structure.
+ * @mask: Bitmask of bits to be cleared.
+ * @xor:  Bitmask of bits to be toggled or set (via XOR).
+ *
+ * Performs a read-modify-write update on the control register using
+ * the provided @mask and @xor values.
+ *
+ * Return: 0 on success, or a negative errno code on failure.
+ */
+static inline int asus_ec_update_ctl(const struct asusec_info *ec,
+				     u64 mask, u64 xor)
+{
+	return asus_dockram_access_ctl(ec->dockram, NULL, mask, xor);
+}
+
+/**
+ * asus_ec_set_ctl_bits - Sets bits of the DockRAM control register.
+ * @ec:   Pointer to the shared ASUS EC structure.
+ * @mask: Bitmask of bits to be set.
+ *
+ * Sets bits of the control register using the provided @mask value.
+ *
+ * Return: 0 on success, or a negative errno code on failure.
+ */
+static inline int asus_ec_set_ctl_bits(const struct asusec_info *ec, u64 mask)
+{
+	return asus_dockram_access_ctl(ec->dockram, NULL, mask, mask);
+}
+
+/**
+ * asus_ec_clear_ctl_bits - Clears bits of the DockRAM control register.
+ * @ec:   Pointer to the shared ASUS EC structure.
+ * @mask: Bitmask of bits to be cleared.
+ *
+ * Clears bits of the control register using the provided @mask value.
+ *
+ * Return: 0 on success, or a negative errno code on failure.
+ */
+static inline int asus_ec_clear_ctl_bits(const struct asusec_info *ec, u64 mask)
+{
+	return asus_dockram_access_ctl(ec->dockram, NULL, mask, 0);
+}
+
+int asus_ec_i2c_command(const struct asusec_info *ec, u16 data);
+int devm_asus_ec_register_notifier(struct platform_device *dev,
+				   struct notifier_block *nb);
 #endif /* __MISC_ASUS_EC_H */
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v2 5/9] input: serio: Add driver for Asus Transformer dock keyboard and touchpad
  2026-02-09 10:43 [PATCH v2 0/9] mfd: Add support for Asus Transformer embedded controller Svyatoslav Ryhel
                   ` (3 preceding siblings ...)
  2026-02-09 10:44 ` [PATCH v2 4/9] mfd: Add driver for Asus Transformer embedded controller Svyatoslav Ryhel
@ 2026-02-09 10:44 ` Svyatoslav Ryhel
  2026-02-09 10:44 ` [PATCH v2 6/9] input: keyboard: Add driver for Asus Transformer dock multimedia keys Svyatoslav Ryhel
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 30+ messages in thread
From: Svyatoslav Ryhel @ 2026-02-09 10:44 UTC (permalink / raw)
  To: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Dmitry Torokhov, Pavel Machek, Arnd Bergmann, Greg Kroah-Hartman,
	Sebastian Reichel, Svyatoslav Ryhel, Michał Mirosław,
	Ion Agorria
  Cc: devicetree, linux-kernel, linux-input, linux-leds, linux-pm

From: Michał Mirosław <mirq-linux@rere.qmqm.pl>

Add input driver for Asus Transformer dock keyboard and touchpad.

Some keys in Asus Dock report keycodes that don't make sense according to
their position, this patch modifies the incoming data that is sent to
serio to send proper scancodes.

Co-developed-by: Ion Agorria <ion@agorria.com>
Signed-off-by: Ion Agorria <ion@agorria.com>
Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
 drivers/input/serio/Kconfig       |  15 +++
 drivers/input/serio/Makefile      |   1 +
 drivers/input/serio/asus-ec-kbc.c | 160 ++++++++++++++++++++++++++++++
 3 files changed, 176 insertions(+)
 create mode 100644 drivers/input/serio/asus-ec-kbc.c

diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
index c7ef347a4dff..46c4286cd5f6 100644
--- a/drivers/input/serio/Kconfig
+++ b/drivers/input/serio/Kconfig
@@ -97,6 +97,21 @@ config SERIO_RPCKBD
 	  To compile this driver as a module, choose M here: the
 	  module will be called rpckbd.
 
+config SERIO_ASUSEC
+	tristate "Asus Transformer's Dock keyboard and touchpad controller"
+	depends on MFD_ASUSEC
+	help
+	  Say Y here if you want to use the keyboard and/or touchpad on
+	  Asus Transformed's Mobile Dock.
+
+	  For keyboard support you also need atkbd driver.
+
+	  For touchpad support you also need psmouse driver with Elantech
+	  touchpad option enabled.
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called asus-ec-kbc.
+
 config SERIO_AMBAKMI
 	tristate "AMBA KMI keyboard controller"
 	depends on ARM_AMBA
diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
index 6d97bad7b844..444e3ea70e37 100644
--- a/drivers/input/serio/Makefile
+++ b/drivers/input/serio/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_SERIO_CT82C710)	+= ct82c710.o
 obj-$(CONFIG_SERIO_RPCKBD)	+= rpckbd.o
 obj-$(CONFIG_SERIO_SA1111)	+= sa1111ps2.o
 obj-$(CONFIG_SERIO_AMBAKMI)	+= ambakmi.o
+obj-$(CONFIG_SERIO_ASUSEC)	+= asus-ec-kbc.o
 obj-$(CONFIG_SERIO_Q40KBD)	+= q40kbd.o
 obj-$(CONFIG_SERIO_GSCPS2)	+= gscps2.o
 obj-$(CONFIG_HP_SDC)		+= hp_sdc.o
diff --git a/drivers/input/serio/asus-ec-kbc.c b/drivers/input/serio/asus-ec-kbc.c
new file mode 100644
index 000000000000..c03f4721fc33
--- /dev/null
+++ b/drivers/input/serio/asus-ec-kbc.c
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * ASUS EC - keyboard and touchpad
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/i8042.h>
+#include <linux/mfd/asus-ec.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/serio.h>
+
+struct asus_ec_kbc_data {
+	struct notifier_block nb;
+	struct asusec_info *ec;
+	struct serio *sdev[2];
+};
+
+static int asus_ec_kbc_notify(struct notifier_block *nb,
+			      unsigned long action, void *data_)
+{
+	struct asus_ec_kbc_data *priv = container_of(nb, struct asus_ec_kbc_data, nb);
+	unsigned int port_idx, n;
+	u8 *data = data_;
+
+	if (action & (ASUSEC_SMI_MASK | ASUSEC_SCI_MASK))
+		return NOTIFY_DONE;
+	else if (action & ASUSEC_AUX_MASK)
+		port_idx = 1;
+	else if (action & (ASUSEC_KBC_MASK | ASUSEC_KEY_MASK))
+		port_idx = 0;
+	else
+		return NOTIFY_DONE;
+
+	n = data[0] - 1;
+	data += 2;
+
+	/*
+	 * We need to replace these incoming data for keys:
+	 * RIGHT_META Press   0xE0 0x27      -> LEFT_ALT   Press   0x11
+	 * RIGHT_META Release 0xE0 0xF0 0x27 -> LEFT_ALT   Release 0xF0 0x11
+	 * COMPOSE    Press   0xE0 0x2F      -> RIGHT_META Press   0xE0 0x27
+	 * COMPOSE    Release 0xE0 0xF0 0x2F -> RIGHT_META Release 0xE0 0xF0 0x27
+	 */
+
+	if (port_idx == 0 && n >= 2 && data[0] == 0xE0) {
+		if (n == 3 && data[1] == 0xF0) {
+			switch (data[2]) {
+			case 0x27:
+				data[0] = 0xF0;
+				data[1] = 0x11;
+				n = 2;
+				break;
+			case 0x2F:
+				data[2] = 0x27;
+				break;
+			}
+		} else if (n == 2) {
+			switch (data[1]) {
+			case 0x27:
+				data[0] = 0x11;
+				n = 1;
+				break;
+			case 0x2F:
+				data[1] = 0x27;
+				break;
+			}
+		}
+	}
+
+	while (n--)
+		serio_interrupt(priv->sdev[port_idx], *data++, 0);
+
+	return NOTIFY_OK;
+}
+
+static int asus_ec_serio_write(struct serio *port, unsigned char data)
+{
+	const struct asusec_info *ec = port->port_data;
+
+	return asus_ec_i2c_command(ec, (data << 8) | port->id.extra);
+}
+
+static void asus_ec_serio_remove(void *data)
+{
+	serio_unregister_port(data);
+}
+
+static int asus_ec_register_serio(struct platform_device *pdev, int idx,
+				  const char *name, int cmd)
+{
+	struct asus_ec_kbc_data *priv = platform_get_drvdata(pdev);
+	struct i2c_client *parent = to_i2c_client(pdev->dev.parent);
+	struct serio *port = kzalloc(sizeof(*port), GFP_KERNEL);
+
+	if (!port)
+		return -ENOMEM;
+
+	priv->sdev[idx] = port;
+	port->dev.parent = &pdev->dev;
+	port->id.type = SERIO_8042;
+	port->id.extra = cmd & 0xFF;
+	port->write = asus_ec_serio_write;
+	port->port_data = (void *)priv->ec;
+	snprintf(port->name, sizeof(port->name), "%s %s",
+		 priv->ec->model, name);
+	snprintf(port->phys, sizeof(port->phys), "i2c-%u-%04x/serio%d",
+		 i2c_adapter_id(parent->adapter), parent->addr, idx);
+
+	serio_register_port(port);
+
+	return devm_add_action_or_reset(&pdev->dev, asus_ec_serio_remove, port);
+}
+
+static int asus_ec_kbc_probe(struct platform_device *pdev)
+{
+	struct asusec_info *ec = cell_to_ec(pdev);
+	struct asus_ec_kbc_data *priv;
+	int ret;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, priv);
+	priv->ec = ec;
+
+	ret = asus_ec_register_serio(pdev, 0, "Keyboard", 0);
+	if (ret < 0)
+		return ret;
+
+	ret = asus_ec_register_serio(pdev, 1, "Touchpad", I8042_CMD_AUX_SEND);
+	if (ret < 0)
+		return ret;
+
+	priv->nb.notifier_call = asus_ec_kbc_notify;
+
+	return devm_asus_ec_register_notifier(pdev, &priv->nb);
+}
+
+static const struct of_device_id asus_ec_kbc_match[] = {
+	{ .compatible = "asus,ec-kbc" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, asus_ec_kbc_match);
+
+static struct platform_driver asus_ec_kbc_driver = {
+	.driver = {
+		.name = "asus-ec-kbc",
+		.of_match_table = asus_ec_kbc_match,
+	},
+	.probe = asus_ec_kbc_probe,
+};
+module_platform_driver(asus_ec_kbc_driver);
+
+MODULE_AUTHOR("Michał Mirosław <mirq-linux@rere.qmqm.pl>");
+MODULE_DESCRIPTION("ASUS Transformer's Dock keyboard and touchpad controller driver");
+MODULE_LICENSE("GPL");
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v2 6/9] input: keyboard: Add driver for Asus Transformer dock multimedia keys
  2026-02-09 10:43 [PATCH v2 0/9] mfd: Add support for Asus Transformer embedded controller Svyatoslav Ryhel
                   ` (4 preceding siblings ...)
  2026-02-09 10:44 ` [PATCH v2 5/9] input: serio: Add driver for Asus Transformer dock keyboard and touchpad Svyatoslav Ryhel
@ 2026-02-09 10:44 ` Svyatoslav Ryhel
  2026-02-09 10:44 ` [PATCH v2 7/9] leds: Add driver for Asus Transformer LEDs Svyatoslav Ryhel
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 30+ messages in thread
From: Svyatoslav Ryhel @ 2026-02-09 10:44 UTC (permalink / raw)
  To: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Dmitry Torokhov, Pavel Machek, Arnd Bergmann, Greg Kroah-Hartman,
	Sebastian Reichel, Svyatoslav Ryhel, Michał Mirosław,
	Ion Agorria
  Cc: devicetree, linux-kernel, linux-input, linux-leds, linux-pm

From: Michał Mirosław <mirq-linux@rere.qmqm.pl>

Add support for multimedia top button row of ASUS Transformer's Mobile
Dock keyboard. Driver is made that function keys (F1-F12) are used by
default which suits average Linux use better and with pressing
ScreenLock + AltGr function keys layout is switched to multimedia keys.
Since this only modifies codes sent by asus-ec-keys it doesn't affect
normal keyboards at all.

Co-developed-by: Ion Agorria <ion@agorria.com>
Signed-off-by: Ion Agorria <ion@agorria.com>
Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
 drivers/input/keyboard/Kconfig        |  10 +
 drivers/input/keyboard/Makefile       |   1 +
 drivers/input/keyboard/asus-ec-keys.c | 285 ++++++++++++++++++++++++++
 3 files changed, 296 insertions(+)
 create mode 100644 drivers/input/keyboard/asus-ec-keys.c

diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index 2ff4fef322c2..d23af13ab99a 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -89,6 +89,16 @@ config KEYBOARD_APPLESPI
 	  To compile this driver as a module, choose M here: the
 	  module will be called applespi.
 
+config KEYBOARD_ASUSEC
+	tristate "Asus Transformer's Mobile Dock multimedia keys"
+	depends on MFD_ASUSEC
+	help
+	  Say Y here if you want to use multimedia keys present on Asus
+	  Transformer's Mobile Dock.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called asus-ec-keys.
+
 config KEYBOARD_ATARI
 	tristate "Atari keyboard"
 	depends on ATARI
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 2d906e14f3e2..7226aafddf7a 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_KEYBOARD_ADP5585)		+= adp5585-keys.o
 obj-$(CONFIG_KEYBOARD_ADP5588)		+= adp5588-keys.o
 obj-$(CONFIG_KEYBOARD_AMIGA)		+= amikbd.o
 obj-$(CONFIG_KEYBOARD_APPLESPI)		+= applespi.o
+obj-$(CONFIG_KEYBOARD_ASUSEC)		+= asus-ec-keys.o
 obj-$(CONFIG_KEYBOARD_ATARI)		+= atakbd.o
 obj-$(CONFIG_KEYBOARD_ATKBD)		+= atkbd.o
 obj-$(CONFIG_KEYBOARD_BCM)		+= bcm-keypad.o
diff --git a/drivers/input/keyboard/asus-ec-keys.c b/drivers/input/keyboard/asus-ec-keys.c
new file mode 100644
index 000000000000..42365db63bdf
--- /dev/null
+++ b/drivers/input/keyboard/asus-ec-keys.c
@@ -0,0 +1,285 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * ASUS Transformer Pad - multimedia keys
+ */
+
+#include <linux/array_size.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/mfd/asus-ec.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#define ASUSEC_EXT_KEY_CODES		0x20
+
+struct asus_ec_keys_data {
+	struct notifier_block nb;
+	struct asusec_info *ec;
+	struct input_dev *xidev;
+	bool special_key_pressed;
+	bool special_key_mode;
+	unsigned short keymap[ASUSEC_EXT_KEY_CODES * 2];
+};
+
+static void asus_ec_input_event(struct input_handle *handle,
+				unsigned int event_type,
+				unsigned int event_code, int value)
+{
+	struct asus_ec_keys_data *priv = handle->handler->private;
+
+	/* Store special key state */
+	if (event_type == EV_KEY && event_code == KEY_RIGHTALT)
+		priv->special_key_pressed = !!value;
+}
+
+static int asus_ec_input_connect(struct input_handler *handler, struct input_dev *dev,
+				 const struct input_device_id *id)
+{
+	struct input_handle *handle;
+	int error;
+
+	handle = kzalloc(sizeof(*handle), GFP_KERNEL);
+	if (!handle)
+		return -ENOMEM;
+
+	handle->dev = dev;
+	handle->handler = handler;
+	handle->name = "asusec-media-handler";
+
+	error = input_register_handle(handle);
+	if (error)
+		goto err_free_handle;
+
+	error = input_open_device(handle);
+	if (error)
+		goto err_unregister_handle;
+
+	return 0;
+
+ err_unregister_handle:
+	input_unregister_handle(handle);
+ err_free_handle:
+	kfree(handle);
+
+	return error;
+}
+
+static void asus_ec_input_disconnect(struct input_handle *handle)
+{
+	input_close_device(handle);
+	input_unregister_handle(handle);
+	kfree(handle);
+}
+
+static const struct input_device_id asus_ec_input_ids[] = {
+	{
+		.flags = INPUT_DEVICE_ID_MATCH_EVBIT,
+		.evbit = { BIT_MASK(EV_KEY) },
+	},
+	{ }
+};
+
+static struct input_handler asus_ec_input_handler = {
+	.name =	"asusec-media-handler",
+	.event = asus_ec_input_event,
+	.connect = asus_ec_input_connect,
+	.disconnect = asus_ec_input_disconnect,
+	.id_table = asus_ec_input_ids,
+};
+
+static const unsigned short asus_ec_dock_ext_keys[] = {
+	/* Function keys [0x00 - 0x19] */
+	[0x01] = KEY_DELETE,
+	[0x02] = KEY_F1,
+	[0x03] = KEY_F2,
+	[0x04] = KEY_F3,
+	[0x05] = KEY_F4,
+	[0x06] = KEY_F5,
+	[0x07] = KEY_F6,
+	[0x08] = KEY_F7,
+	[0x10] = KEY_F8,
+	[0x11] = KEY_F9,
+	[0x12] = KEY_F10,
+	[0x13] = KEY_F11,
+	[0x14] = KEY_F12,
+	[0x15] = KEY_MUTE,
+	[0x16] = KEY_VOLUMEDOWN,
+	[0x17] = KEY_VOLUMEUP,
+	/* Multimedia keys [0x20 - 0x39] */
+	[0x21] = KEY_SCREENLOCK,
+	[0x22] = KEY_WLAN,
+	[0x23] = KEY_BLUETOOTH,
+	[0x24] = KEY_TOUCHPAD_TOGGLE,
+	[0x25] = KEY_BRIGHTNESSDOWN,
+	[0x26] = KEY_BRIGHTNESSUP,
+	[0x27] = KEY_BRIGHTNESS_AUTO,
+	[0x28] = KEY_PRINT,
+	[0x30] = KEY_WWW,
+	[0x31] = KEY_CONFIG,
+	[0x32] = KEY_PREVIOUSSONG,
+	[0x33] = KEY_PLAYPAUSE,
+	[0x34] = KEY_NEXTSONG,
+	[0x35] = KEY_MUTE,
+	[0x36] = KEY_VOLUMEDOWN,
+	[0x37] = KEY_VOLUMEUP,
+};
+
+static void asus_ec_keys_report_key(struct input_dev *dev, unsigned int code,
+				    unsigned int key, bool value)
+{
+	input_event(dev, EV_MSC, MSC_SCAN, code);
+	input_report_key(dev, key, value);
+	input_sync(dev);
+}
+
+static int asus_ec_keys_process_key(struct input_dev *dev, u8 code)
+{
+	struct asus_ec_keys_data *priv = dev_get_drvdata(dev->dev.parent);
+	unsigned int key = 0;
+
+	if (code == 0)
+		return NOTIFY_DONE;
+
+	/* Flip special key mode state when pressing key 1 with special key pressed */
+	if (priv->special_key_pressed && code == 1) {
+		priv->special_key_mode = !priv->special_key_mode;
+		return NOTIFY_DONE;
+	}
+
+	/*
+	 * Relocate code to second "page" if pressed state XOR's mode state
+	 * This way special key will invert the current mode
+	 */
+	if (priv->special_key_mode ^ priv->special_key_pressed)
+		code += ASUSEC_EXT_KEY_CODES;
+
+	if (code < dev->keycodemax) {
+		unsigned short *map = dev->keycode;
+
+		key = map[code];
+	}
+
+	if (!key)
+		key = KEY_UNKNOWN;
+
+	asus_ec_keys_report_key(dev, code, key, 1);
+	asus_ec_keys_report_key(dev, code, key, 0);
+
+	return NOTIFY_OK;
+}
+
+static int asus_ec_keys_notify(struct notifier_block *nb,
+			       unsigned long action, void *data_)
+{
+	struct asus_ec_keys_data *priv = container_of(nb, struct asus_ec_keys_data, nb);
+	u8 *data = data_;
+
+	if (action & ASUSEC_SMI_MASK)
+		return NOTIFY_DONE;
+
+	if (action & ASUSEC_SCI_MASK)
+		return asus_ec_keys_process_key(priv->xidev, data[2]);
+
+	return NOTIFY_DONE;
+}
+
+static void asus_ec_keys_setup_keymap(struct asus_ec_keys_data *priv)
+{
+	struct input_dev *dev = priv->xidev;
+	unsigned int i;
+
+	BUILD_BUG_ON(ARRAY_SIZE(priv->keymap) < ARRAY_SIZE(asus_ec_dock_ext_keys));
+
+	dev->keycode = priv->keymap;
+	dev->keycodesize = sizeof(*priv->keymap);
+	dev->keycodemax = ARRAY_SIZE(priv->keymap);
+
+	input_set_capability(dev, EV_MSC, MSC_SCAN);
+	input_set_capability(dev, EV_KEY, KEY_UNKNOWN);
+
+	for (i = 0; i < ARRAY_SIZE(asus_ec_dock_ext_keys); i++) {
+		unsigned int code = asus_ec_dock_ext_keys[i];
+
+		if (!code)
+			continue;
+
+		__set_bit(code, dev->keybit);
+		priv->keymap[i] = code;
+	}
+}
+
+static void asus_ec_input_handler_deregister(void *priv)
+{
+	input_unregister_handler(&asus_ec_input_handler);
+}
+
+static int asus_ec_keys_probe(struct platform_device *pdev)
+{
+	struct asusec_info *ec = cell_to_ec(pdev);
+	struct i2c_client *parent = to_i2c_client(pdev->dev.parent);
+	struct asus_ec_keys_data *priv;
+	int ret;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, priv);
+	priv->ec = ec;
+
+	priv->xidev = devm_input_allocate_device(&pdev->dev);
+	if (!priv->xidev)
+		return -ENOMEM;
+
+	priv->xidev->name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
+					   "%s Keyboard Ext", ec->model);
+	priv->xidev->phys = devm_kasprintf(&pdev->dev, GFP_KERNEL,
+					   "i2c-%u-%04x",
+					   i2c_adapter_id(parent->adapter),
+					   parent->addr);
+	asus_ec_keys_setup_keymap(priv);
+
+	ret = input_register_device(priv->xidev);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to register extension keys: %d\n",
+			ret);
+		return ret;
+	}
+
+	asus_ec_input_handler.private = priv;
+
+	ret = input_register_handler(&asus_ec_input_handler);
+	if (ret)
+		return ret;
+
+	ret = devm_add_action_or_reset(&pdev->dev, asus_ec_input_handler_deregister,
+				       priv);
+	if (ret)
+		return ret;
+
+	priv->nb.notifier_call = asus_ec_keys_notify;
+
+	return devm_asus_ec_register_notifier(pdev, &priv->nb);
+}
+
+static const struct of_device_id asus_ec_keys_match[] = {
+	{ .compatible = "asus,ec-keys" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, asus_ec_keys_match);
+
+static struct platform_driver asus_ec_keys_driver = {
+	.driver = {
+		.name = "asus-ec-keys",
+		.of_match_table = asus_ec_keys_match,
+	},
+	.probe = asus_ec_keys_probe,
+};
+module_platform_driver(asus_ec_keys_driver);
+
+MODULE_AUTHOR("Michał Mirosław <mirq-linux@rere.qmqm.pl>");
+MODULE_DESCRIPTION("ASUS Transformer's multimedia keys driver");
+MODULE_LICENSE("GPL");
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v2 7/9] leds: Add driver for Asus Transformer LEDs
  2026-02-09 10:43 [PATCH v2 0/9] mfd: Add support for Asus Transformer embedded controller Svyatoslav Ryhel
                   ` (5 preceding siblings ...)
  2026-02-09 10:44 ` [PATCH v2 6/9] input: keyboard: Add driver for Asus Transformer dock multimedia keys Svyatoslav Ryhel
@ 2026-02-09 10:44 ` Svyatoslav Ryhel
  2026-03-06 10:04   ` Lee Jones
  2026-02-09 10:44 ` [PATCH v2 8/9] power: supply: Add driver for Asus Transformer battery Svyatoslav Ryhel
  2026-02-09 10:44 ` [PATCH v2 9/9] power: supply: Add charger driver for Asus Transformers Svyatoslav Ryhel
  8 siblings, 1 reply; 30+ messages in thread
From: Svyatoslav Ryhel @ 2026-02-09 10:44 UTC (permalink / raw)
  To: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Dmitry Torokhov, Pavel Machek, Arnd Bergmann, Greg Kroah-Hartman,
	Sebastian Reichel, Svyatoslav Ryhel, Michał Mirosław,
	Ion Agorria
  Cc: devicetree, linux-kernel, linux-input, linux-leds, linux-pm

From: Michał Mirosław <mirq-linux@rere.qmqm.pl>

Asus Transformer tablets have a green and an amber LED on both the Pad
and the Dock. If both LEDs are enabled simultaneously, the emitted light
will be yellow.

Co-developed-by: Svyatoslav Ryhel <clamor95@gmail.com>
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>
---
 drivers/leds/Kconfig        |  11 ++++
 drivers/leds/Makefile       |   1 +
 drivers/leds/leds-asus-ec.c | 104 ++++++++++++++++++++++++++++++++++++
 3 files changed, 116 insertions(+)
 create mode 100644 drivers/leds/leds-asus-ec.c

diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 597d7a79c988..96dab210f6ca 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -120,6 +120,17 @@ config LEDS_OSRAM_AMS_AS3668
 	  To compile this driver as a module, choose M here: the module
 	  will be called leds-as3668.
 
+config LEDS_ASUSEC
+	tristate "LED Support for Asus Transformer charging LED"
+	depends on LEDS_CLASS
+	depends on MFD_ASUSEC
+	help
+	  This option enables support for charging indicator on
+	  Asus Transformer's Pad and it's Dock.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called leds-asus-ec.
+
 config LEDS_AW200XX
 	tristate "LED support for Awinic AW20036/AW20054/AW20072/AW20108"
 	depends on LEDS_CLASS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 8fdb45d5b439..1117304dfdf4 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_LEDS_AN30259A)		+= leds-an30259a.o
 obj-$(CONFIG_LEDS_APU)			+= leds-apu.o
 obj-$(CONFIG_LEDS_ARIEL)		+= leds-ariel.o
 obj-$(CONFIG_LEDS_AS3668)		+= leds-as3668.o
+obj-$(CONFIG_LEDS_ASUSEC)		+= leds-asus-ec.o
 obj-$(CONFIG_LEDS_AW200XX)		+= leds-aw200xx.o
 obj-$(CONFIG_LEDS_AW2013)		+= leds-aw2013.o
 obj-$(CONFIG_LEDS_BCM6328)		+= leds-bcm6328.o
diff --git a/drivers/leds/leds-asus-ec.c b/drivers/leds/leds-asus-ec.c
new file mode 100644
index 000000000000..5dd76c9247ee
--- /dev/null
+++ b/drivers/leds/leds-asus-ec.c
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * ASUS EC driver - battery LED
+ */
+
+#include <linux/err.h>
+#include <linux/leds.h>
+#include <linux/mfd/asus-ec.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+/*
+ * F[5] & 0x07
+ *  auto: brightness == 0
+ *  bit 0: blink / charger on
+ *  bit 1: amber on
+ *  bit 2: green on
+ */
+
+#define ASUSEC_CTL_LED_BLINK		BIT_ULL(40)
+#define ASUSEC_CTL_LED_AMBER		BIT_ULL(41)
+#define ASUSEC_CTL_LED_GREEN		BIT_ULL(42)
+
+static void asus_ec_led_set_brightness_amber(struct led_classdev *led,
+					     enum led_brightness brightness)
+{
+	const struct asusec_info *ec = dev_get_drvdata(led->dev->parent);
+
+	if (brightness)
+		asus_ec_set_ctl_bits(ec, ASUSEC_CTL_LED_AMBER);
+	else
+		asus_ec_clear_ctl_bits(ec, ASUSEC_CTL_LED_AMBER);
+}
+
+static void asus_ec_led_set_brightness_green(struct led_classdev *led,
+					     enum led_brightness brightness)
+{
+	const struct asusec_info *ec = dev_get_drvdata(led->dev->parent);
+
+	if (brightness)
+		asus_ec_set_ctl_bits(ec, ASUSEC_CTL_LED_GREEN);
+	else
+		asus_ec_clear_ctl_bits(ec, ASUSEC_CTL_LED_GREEN);
+}
+
+static int asus_ec_led_probe(struct platform_device *pdev)
+{
+	struct asusec_info *ec = cell_to_ec(pdev);
+	struct device *dev = &pdev->dev;
+	struct led_classdev *amber_led, *green_led;
+	int ret;
+
+	platform_set_drvdata(pdev, ec);
+
+	amber_led = devm_kzalloc(dev, sizeof(*amber_led), GFP_KERNEL);
+	if (!amber_led)
+		return -ENOMEM;
+
+	amber_led->name = devm_kasprintf(dev, GFP_KERNEL, "%s::amber", ec->name);
+	amber_led->max_brightness = 1;
+	amber_led->flags = LED_CORE_SUSPENDRESUME | LED_RETAIN_AT_SHUTDOWN;
+	amber_led->brightness_set = asus_ec_led_set_brightness_amber;
+
+	ret = devm_led_classdev_register(dev, amber_led);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to register amber LED\n");
+
+	green_led = devm_kzalloc(dev, sizeof(*green_led), GFP_KERNEL);
+	if (!green_led)
+		return -ENOMEM;
+
+	green_led->name = devm_kasprintf(dev, GFP_KERNEL, "%s::green", ec->name);
+	green_led->max_brightness = 1;
+	green_led->flags = LED_CORE_SUSPENDRESUME | LED_RETAIN_AT_SHUTDOWN;
+	green_led->brightness_set = asus_ec_led_set_brightness_green;
+
+	ret = devm_led_classdev_register(dev, green_led);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to register green LED\n");
+
+	return 0;
+}
+
+static const struct of_device_id asus_ec_led_match[] = {
+	{ .compatible = "asus,ec-led" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, asus_ec_led_match);
+
+static struct platform_driver asus_ec_led_driver = {
+	.driver = {
+		.name = "asus-ec-led",
+		.of_match_table = asus_ec_led_match,
+	},
+	.probe = asus_ec_led_probe,
+};
+module_platform_driver(asus_ec_led_driver);
+
+MODULE_AUTHOR("Michał Mirosław <mirq-linux@rere.qmqm.pl>");
+MODULE_AUTHOR("Svyatoslav Ryhel <clamor95@gmail.com>");
+MODULE_DESCRIPTION("ASUS Transformer's charging LED driver");
+MODULE_LICENSE("GPL");
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v2 8/9] power: supply: Add driver for Asus Transformer battery
  2026-02-09 10:43 [PATCH v2 0/9] mfd: Add support for Asus Transformer embedded controller Svyatoslav Ryhel
                   ` (6 preceding siblings ...)
  2026-02-09 10:44 ` [PATCH v2 7/9] leds: Add driver for Asus Transformer LEDs Svyatoslav Ryhel
@ 2026-02-09 10:44 ` Svyatoslav Ryhel
  2026-02-09 10:44 ` [PATCH v2 9/9] power: supply: Add charger driver for Asus Transformers Svyatoslav Ryhel
  8 siblings, 0 replies; 30+ messages in thread
From: Svyatoslav Ryhel @ 2026-02-09 10:44 UTC (permalink / raw)
  To: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Dmitry Torokhov, Pavel Machek, Arnd Bergmann, Greg Kroah-Hartman,
	Sebastian Reichel, Svyatoslav Ryhel, Michał Mirosław,
	Ion Agorria
  Cc: devicetree, linux-kernel, linux-input, linux-leds, linux-pm

From: Michał Mirosław <mirq-linux@rere.qmqm.pl>

Driver implements one battery cell per EC controller and supports reading
of battery status for Asus Transformer's pad and mobile dock.

Co-developed-by: Svyatoslav Ryhel <clamor95@gmail.com>
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>
---
 drivers/power/supply/Kconfig           |  11 +
 drivers/power/supply/Makefile          |   1 +
 drivers/power/supply/asus-ec-battery.c | 283 +++++++++++++++++++++++++
 3 files changed, 295 insertions(+)
 create mode 100644 drivers/power/supply/asus-ec-battery.c

diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index 81fadb0695a9..bcf6a23858be 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -122,6 +122,17 @@ config BATTERY_CHAGALL
 	  This driver can also be built as a module. If so, the module will be
 	  called chagall-battery.
 
+config BATTERY_ASUSEC
+	tristate "Asus Transformer's battery driver"
+	depends on MFD_ASUSEC
+	help
+	  Say Y here to enable support APM status emulation using
+	  battery class devices.
+
+	  This sub-driver supports battery cells found in Asus Transformer
+	  tablets and mobile docks and controlled by special embedded
+	  controller.
+
 config BATTERY_CPCAP
 	tristate "Motorola CPCAP PMIC battery driver"
 	depends on MFD_CPCAP && IIO
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index 41c400bbf022..0a2cbfa96ed9 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_TEST_POWER)	+= test_power.o
 obj-$(CONFIG_BATTERY_88PM860X)	+= 88pm860x_battery.o
 obj-$(CONFIG_CHARGER_ADP5061)	+= adp5061.o
 obj-$(CONFIG_BATTERY_ACT8945A)	+= act8945a_charger.o
+obj-$(CONFIG_BATTERY_ASUSEC)	+= asus-ec-battery.o
 obj-$(CONFIG_BATTERY_AXP20X)	+= axp20x_battery.o
 obj-$(CONFIG_CHARGER_AXP20X)	+= axp20x_ac_power.o
 obj-$(CONFIG_BATTERY_CHAGALL)	+= chagall-battery.o
diff --git a/drivers/power/supply/asus-ec-battery.c b/drivers/power/supply/asus-ec-battery.c
new file mode 100644
index 000000000000..36ebc5093730
--- /dev/null
+++ b/drivers/power/supply/asus-ec-battery.c
@@ -0,0 +1,283 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * ASUS EC driver - battery monitoring
+ */
+
+#include <linux/array_size.h>
+#include <linux/devm-helpers.h>
+#include <linux/err.h>
+#include <linux/mfd/asus-ec.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/property.h>
+#include <linux/unaligned.h>
+
+#define ASUSEC_BATTERY_DATA_FRESH_MSEC		5000
+
+#define ASUSEC_BATTERY_DISCHARGING		0x40
+#define ASUSEC_BATTERY_FULL_CHARGED		0x20
+#define ASUSEC_BATTERY_NOT_CHARGING		0x10
+
+#define TEMP_CELSIUS_OFFSET			2731
+
+struct asus_ec_battery_data {
+	const struct asusec_info *ec;
+	struct power_supply *battery;
+	struct power_supply_desc psy_desc;
+	struct delayed_work poll_work;
+	struct mutex battery_lock; /* for data refresh */
+	unsigned long batt_data_ts;
+	int last_state;
+	u8 batt_data[DOCKRAM_ENTRY_BUFSIZE];
+};
+
+static int asus_ec_battery_refresh(struct asus_ec_battery_data *priv)
+{
+	int ret = 0;
+
+	guard(mutex)(&priv->battery_lock);
+
+	if (time_before(jiffies, priv->batt_data_ts))
+		return ret;
+
+	ret = asus_dockram_read(priv->ec->dockram, ASUSEC_DOCKRAM_BATT_CTL,
+				priv->batt_data);
+	if (ret < 0)
+		return ret;
+
+	priv->batt_data_ts = jiffies +
+		msecs_to_jiffies(ASUSEC_BATTERY_DATA_FRESH_MSEC);
+
+	return ret;
+}
+
+static enum power_supply_property asus_ec_battery_properties[] = {
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_VOLTAGE_MAX,
+	POWER_SUPPLY_PROP_CURRENT_MAX,
+	POWER_SUPPLY_PROP_TEMP,
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+	POWER_SUPPLY_PROP_CURRENT_NOW,
+	POWER_SUPPLY_PROP_CAPACITY,
+	POWER_SUPPLY_PROP_CHARGE_NOW,
+	POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
+	POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
+	POWER_SUPPLY_PROP_PRESENT,
+};
+
+static const unsigned int asus_ec_battery_prop_offs[] = {
+	[POWER_SUPPLY_PROP_STATUS] = 1,
+	[POWER_SUPPLY_PROP_VOLTAGE_MAX] = 3,
+	[POWER_SUPPLY_PROP_CURRENT_MAX] = 5,
+	[POWER_SUPPLY_PROP_TEMP] = 7,
+	[POWER_SUPPLY_PROP_VOLTAGE_NOW] = 9,
+	[POWER_SUPPLY_PROP_CURRENT_NOW] = 11,
+	[POWER_SUPPLY_PROP_CAPACITY] = 13,
+	[POWER_SUPPLY_PROP_CHARGE_NOW] = 15,
+	[POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW] = 17,
+	[POWER_SUPPLY_PROP_TIME_TO_FULL_NOW] = 19,
+};
+
+static int asus_ec_battery_get_value(struct asus_ec_battery_data *priv,
+				     enum power_supply_property psp)
+{
+	int ret, offs;
+
+	if (psp >= ARRAY_SIZE(asus_ec_battery_prop_offs))
+		return -EINVAL;
+
+	offs = asus_ec_battery_prop_offs[psp];
+	if (!offs)
+		return -EINVAL;
+
+	ret = asus_ec_battery_refresh(priv);
+	if (ret < 0)
+		return ret;
+
+	if (offs >= priv->batt_data[0])
+		return -ENODATA;
+
+	return get_unaligned_le16(priv->batt_data + offs);
+}
+
+static int asus_ec_battery_get_property(struct power_supply *psy,
+					enum power_supply_property psp,
+					union power_supply_propval *val)
+{
+	struct asus_ec_battery_data *priv = power_supply_get_drvdata(psy);
+	int ret;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_PRESENT:
+		val->intval = 1;
+		break;
+
+	default:
+		ret = asus_ec_battery_get_value(priv, psp);
+		if (ret < 0)
+			return ret;
+
+		val->intval = (s16)ret;
+
+		switch (psp) {
+		case POWER_SUPPLY_PROP_STATUS:
+			if (ret & ASUSEC_BATTERY_FULL_CHARGED)
+				val->intval = POWER_SUPPLY_STATUS_FULL;
+			else if (ret & ASUSEC_BATTERY_NOT_CHARGING)
+				val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+			else if (ret & ASUSEC_BATTERY_DISCHARGING)
+				val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+			else
+				val->intval = POWER_SUPPLY_STATUS_CHARGING;
+			break;
+
+		case POWER_SUPPLY_PROP_TEMP:
+			val->intval -= TEMP_CELSIUS_OFFSET;
+			break;
+
+		case POWER_SUPPLY_PROP_CHARGE_NOW:
+		case POWER_SUPPLY_PROP_CURRENT_NOW:
+		case POWER_SUPPLY_PROP_CURRENT_MAX:
+		case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		case POWER_SUPPLY_PROP_VOLTAGE_MAX:
+			val->intval *= 1000;
+			break;
+
+		case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
+		case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW:
+			val->intval *= 60;
+			break;
+
+		default:
+			break;
+		}
+
+		break;
+	}
+
+	return 0;
+}
+
+static void asus_ec_battery_poll_work(struct work_struct *work)
+{
+	struct asus_ec_battery_data *priv =
+		container_of(work, struct asus_ec_battery_data, poll_work.work);
+	int state;
+
+	state = asus_ec_battery_get_value(priv, POWER_SUPPLY_PROP_STATUS);
+	if (state < 0)
+		return;
+
+	if (state & ASUSEC_BATTERY_FULL_CHARGED)
+		state = POWER_SUPPLY_STATUS_FULL;
+	else if (state & ASUSEC_BATTERY_DISCHARGING)
+		state = POWER_SUPPLY_STATUS_DISCHARGING;
+	else
+		state = POWER_SUPPLY_STATUS_CHARGING;
+
+	if (priv->last_state != state) {
+		priv->last_state = state;
+		power_supply_changed(priv->battery);
+	}
+
+	/* continuously send uevent notification */
+	schedule_delayed_work(&priv->poll_work,
+			      msecs_to_jiffies(ASUSEC_BATTERY_DATA_FRESH_MSEC));
+}
+
+static const struct power_supply_desc asus_ec_battery_desc = {
+	.name = "asus-ec-battery",
+	.type = POWER_SUPPLY_TYPE_BATTERY,
+	.properties = asus_ec_battery_properties,
+	.num_properties = ARRAY_SIZE(asus_ec_battery_properties),
+	.get_property = asus_ec_battery_get_property,
+	.external_power_changed = power_supply_changed,
+};
+
+static int asus_ec_battery_probe(struct platform_device *pdev)
+{
+	struct asus_ec_battery_data *priv;
+	struct device *dev = &pdev->dev;
+	struct power_supply_config cfg = { };
+	int ret;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, priv);
+
+	mutex_init(&priv->battery_lock);
+
+	priv->ec = cell_to_ec(pdev);
+	priv->batt_data_ts = jiffies - 1;
+	priv->last_state = POWER_SUPPLY_STATUS_UNKNOWN;
+
+	cfg.fwnode = dev_fwnode(dev);
+	cfg.drv_data = priv;
+
+	memcpy(&priv->psy_desc, &asus_ec_battery_desc, sizeof(priv->psy_desc));
+	priv->psy_desc.name = devm_kasprintf(dev, GFP_KERNEL, "%s-battery",
+					     priv->ec->name);
+
+	priv->battery = devm_power_supply_register(dev, &priv->psy_desc, &cfg);
+	if (IS_ERR(priv->battery))
+		return dev_err_probe(dev, PTR_ERR(priv->battery),
+				     "Failed to register power supply\n");
+
+	ret = devm_delayed_work_autocancel(dev, &priv->poll_work,
+					   asus_ec_battery_poll_work);
+	if (ret)
+		return ret;
+
+	schedule_delayed_work(&priv->poll_work,
+			      msecs_to_jiffies(ASUSEC_BATTERY_DATA_FRESH_MSEC));
+
+	return 0;
+}
+
+static int __maybe_unused asus_ec_battery_suspend(struct device *dev)
+{
+	struct asus_ec_battery_data *priv = dev_get_drvdata(dev);
+
+	cancel_delayed_work_sync(&priv->poll_work);
+
+	return 0;
+}
+
+static int __maybe_unused asus_ec_battery_resume(struct device *dev)
+{
+	struct asus_ec_battery_data *priv = dev_get_drvdata(dev);
+
+	schedule_delayed_work(&priv->poll_work,
+			      msecs_to_jiffies(ASUSEC_BATTERY_DATA_FRESH_MSEC));
+
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(asus_ec_battery_pm_ops,
+			 asus_ec_battery_suspend, asus_ec_battery_resume);
+
+static const struct of_device_id asus_ec_battery_match[] = {
+	{ .compatible = "asus,ec-battery" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, asus_ec_battery_match);
+
+static struct platform_driver asus_ec_battery_driver = {
+	.driver = {
+		.name = "asus-ec-battery",
+		.of_match_table = asus_ec_battery_match,
+		.pm = &asus_ec_battery_pm_ops,
+	},
+	.probe = asus_ec_battery_probe,
+};
+module_platform_driver(asus_ec_battery_driver);
+
+MODULE_AUTHOR("Michał Mirosław <mirq-linux@rere.qmqm.pl>");
+MODULE_AUTHOR("Svyatoslav Ryhel <clamor95@gmail.com>");
+MODULE_DESCRIPTION("ASUS Transformer's battery driver");
+MODULE_LICENSE("GPL");
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v2 9/9] power: supply: Add charger driver for Asus Transformers
  2026-02-09 10:43 [PATCH v2 0/9] mfd: Add support for Asus Transformer embedded controller Svyatoslav Ryhel
                   ` (7 preceding siblings ...)
  2026-02-09 10:44 ` [PATCH v2 8/9] power: supply: Add driver for Asus Transformer battery Svyatoslav Ryhel
@ 2026-02-09 10:44 ` Svyatoslav Ryhel
  8 siblings, 0 replies; 30+ messages in thread
From: Svyatoslav Ryhel @ 2026-02-09 10:44 UTC (permalink / raw)
  To: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Dmitry Torokhov, Pavel Machek, Arnd Bergmann, Greg Kroah-Hartman,
	Sebastian Reichel, Svyatoslav Ryhel, Michał Mirosław,
	Ion Agorria
  Cc: devicetree, linux-kernel, linux-input, linux-leds, linux-pm

From: Michał Mirosław <mirq-linux@rere.qmqm.pl>

Add support for charger detection capabilities found in the embedded
controller of ASUS Transformer devices.

Suggested-by: Maxim Schwalm <maxim.schwalm@gmail.com>
Suggested-by: Svyatoslav Ryhel <clamor95@gmail.com>
Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
 drivers/power/supply/Kconfig           |  11 ++
 drivers/power/supply/Makefile          |   1 +
 drivers/power/supply/asus-ec-charger.c | 206 +++++++++++++++++++++++++
 3 files changed, 218 insertions(+)
 create mode 100644 drivers/power/supply/asus-ec-charger.c

diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index bcf6a23858be..43b902a12795 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -497,6 +497,17 @@ config CHARGER_88PM860X
 	help
 	  Say Y here to enable charger for Marvell 88PM860x chip.
 
+config CHARGER_ASUSEC
+	tristate "Asus Transformer's charger driver"
+	depends on MFD_ASUSEC
+	help
+	  Say Y here to enable support AC plug detection on Asus Transformer
+	  Dock.
+
+	  This sub-driver supports charger detection mechanism found in Asus
+	  Transformer tablets and mobile docks and controlled by special
+	  embedded controller.
+
 config CHARGER_PF1550
 	tristate "NXP PF1550 battery charger driver"
 	depends on MFD_PF1550
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index 0a2cbfa96ed9..b93848227f50 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_BATTERY_88PM860X)	+= 88pm860x_battery.o
 obj-$(CONFIG_CHARGER_ADP5061)	+= adp5061.o
 obj-$(CONFIG_BATTERY_ACT8945A)	+= act8945a_charger.o
 obj-$(CONFIG_BATTERY_ASUSEC)	+= asus-ec-battery.o
+obj-$(CONFIG_CHARGER_ASUSEC)	+= asus-ec-charger.o
 obj-$(CONFIG_BATTERY_AXP20X)	+= axp20x_battery.o
 obj-$(CONFIG_CHARGER_AXP20X)	+= axp20x_ac_power.o
 obj-$(CONFIG_BATTERY_CHAGALL)	+= chagall-battery.o
diff --git a/drivers/power/supply/asus-ec-charger.c b/drivers/power/supply/asus-ec-charger.c
new file mode 100644
index 000000000000..bcf798432755
--- /dev/null
+++ b/drivers/power/supply/asus-ec-charger.c
@@ -0,0 +1,206 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * ASUS EC driver - charger monitoring
+ */
+
+#include <linux/err.h>
+#include <linux/mfd/asus-ec.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/property.h>
+
+struct asus_ec_charger_data {
+	struct notifier_block nb;
+	const struct asusec_info *ec;
+	struct power_supply *psy;
+	struct power_supply_desc psy_desc;
+};
+
+static enum power_supply_property asus_ec_charger_properties[] = {
+	POWER_SUPPLY_PROP_USB_TYPE,
+	POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR,
+	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_MODEL_NAME,
+};
+
+static int asus_ec_charger_get_property(struct power_supply *psy,
+					enum power_supply_property psp,
+					union power_supply_propval *val)
+{
+	struct asus_ec_charger_data *priv = power_supply_get_drvdata(psy);
+	enum power_supply_usb_type psu;
+	int ret;
+	u64 ctl;
+
+	ret = asus_ec_get_ctl(priv->ec, &ctl);
+	if (ret)
+		return ret;
+
+	switch (ctl & (ASUSEC_CTL_FULL_POWER_SOURCE | ASUSEC_CTL_DIRECT_POWER_SOURCE)) {
+	case ASUSEC_CTL_FULL_POWER_SOURCE:
+		psu = POWER_SUPPLY_USB_TYPE_CDP;	/* DOCK */
+		break;
+	case ASUSEC_CTL_DIRECT_POWER_SOURCE:
+		psu = POWER_SUPPLY_USB_TYPE_SDP;	/* USB */
+		break;
+	case 0:
+		psu = POWER_SUPPLY_USB_TYPE_UNKNOWN;	/* no power source connected */
+		break;
+	default:
+		psu = POWER_SUPPLY_USB_TYPE_ACA;	/* power adapter */
+		break;
+	}
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_ONLINE:
+		val->intval = psu != POWER_SUPPLY_USB_TYPE_UNKNOWN;
+		return 0;
+
+	case POWER_SUPPLY_PROP_USB_TYPE:
+		val->intval = psu;
+		return 0;
+
+	case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:
+		if (ctl & ASUSEC_CTL_TEST_DISCHARGE)
+			val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE;
+		else if (ctl & ASUSEC_CTL_USB_CHARGE)
+			val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO;
+		else
+			val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE;
+		return 0;
+
+	case POWER_SUPPLY_PROP_MODEL_NAME:
+		val->strval = priv->ec->model;
+		return 0;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int asus_ec_charger_set_property(struct power_supply *psy,
+					enum power_supply_property psp,
+					const union power_supply_propval *val)
+{
+	struct asus_ec_charger_data *priv = power_supply_get_drvdata(psy);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:
+		switch ((enum power_supply_charge_behaviour)val->intval) {
+		case POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO:
+			return asus_ec_update_ctl(priv->ec,
+				ASUSEC_CTL_TEST_DISCHARGE | ASUSEC_CTL_USB_CHARGE,
+				ASUSEC_CTL_USB_CHARGE);
+
+		case POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE:
+			return asus_ec_clear_ctl_bits(priv->ec,
+				ASUSEC_CTL_TEST_DISCHARGE | ASUSEC_CTL_USB_CHARGE);
+
+		case POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE:
+			return asus_ec_update_ctl(priv->ec,
+				ASUSEC_CTL_TEST_DISCHARGE | ASUSEC_CTL_USB_CHARGE,
+				ASUSEC_CTL_TEST_DISCHARGE);
+		default:
+			return -EINVAL;
+		}
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int asus_ec_charger_property_is_writeable(struct power_supply *psy,
+						 enum power_supply_property psp)
+{
+	switch (psp) {
+	case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct power_supply_desc asus_ec_charger_desc = {
+	.name = "asus-ec-charger",
+	.type = POWER_SUPPLY_TYPE_USB,
+	.charge_behaviours = BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO) |
+			     BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE) |
+			     BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE),
+	.usb_types = BIT(POWER_SUPPLY_USB_TYPE_UNKNOWN) |
+		     BIT(POWER_SUPPLY_USB_TYPE_SDP) |
+		     BIT(POWER_SUPPLY_USB_TYPE_CDP) |
+		     BIT(POWER_SUPPLY_USB_TYPE_ACA),
+	.properties = asus_ec_charger_properties,
+	.num_properties = ARRAY_SIZE(asus_ec_charger_properties),
+	.get_property = asus_ec_charger_get_property,
+	.set_property = asus_ec_charger_set_property,
+	.property_is_writeable = asus_ec_charger_property_is_writeable,
+	.no_thermal = true,
+};
+
+static int asus_ec_charger_notify(struct notifier_block *nb,
+				  unsigned long action, void *data)
+{
+	struct asus_ec_charger_data *priv =
+		container_of(nb, struct asus_ec_charger_data, nb);
+
+	switch (action) {
+	case ASUSEC_SMI_ACTION(POWER_NOTIFY):
+	case ASUSEC_SMI_ACTION(ADAPTER_EVENT):
+		power_supply_changed(priv->psy);
+		break;
+	}
+
+	return NOTIFY_DONE;
+}
+
+static int asus_ec_charger_probe(struct platform_device *pdev)
+{
+	struct asus_ec_charger_data *priv;
+	struct device *dev = &pdev->dev;
+	struct power_supply_config cfg = { };
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, priv);
+	priv->ec = cell_to_ec(pdev);
+
+	cfg.fwnode = dev_fwnode(dev);
+	cfg.drv_data = priv;
+
+	memcpy(&priv->psy_desc, &asus_ec_charger_desc, sizeof(priv->psy_desc));
+	priv->psy_desc.name = devm_kasprintf(dev, GFP_KERNEL, "%s-charger",
+					     priv->ec->name);
+
+	priv->psy = devm_power_supply_register(dev, &priv->psy_desc, &cfg);
+	if (IS_ERR(priv->psy))
+		return dev_err_probe(dev, PTR_ERR(priv->psy),
+				     "Failed to register power supply\n");
+
+	priv->nb.notifier_call = asus_ec_charger_notify;
+
+	return devm_asus_ec_register_notifier(pdev, &priv->nb);
+}
+
+static const struct of_device_id asus_ec_charger_match[] = {
+	{ .compatible = "asus,ec-charger" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, asus_ec_charger_match);
+
+static struct platform_driver asus_ec_charger_driver = {
+	.driver = {
+		.name = "asus-ec-charger",
+		.of_match_table = asus_ec_charger_match,
+	},
+	.probe = asus_ec_charger_probe,
+};
+module_platform_driver(asus_ec_charger_driver);
+
+MODULE_AUTHOR("Michał Mirosław <mirq-linux@rere.qmqm.pl>");
+MODULE_DESCRIPTION("ASUS Transformer Pad battery charger driver");
+MODULE_LICENSE("GPL");
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* Re: [PATCH v2 3/9] dt-bindings: mfd: document ASUS Transformer EC
  2026-02-09 10:44 ` [PATCH v2 3/9] dt-bindings: mfd: document ASUS Transformer EC Svyatoslav Ryhel
@ 2026-02-10  9:22   ` Krzysztof Kozlowski
  2026-02-10  9:37     ` Svyatoslav Ryhel
  0 siblings, 1 reply; 30+ messages in thread
From: Krzysztof Kozlowski @ 2026-02-10  9:22 UTC (permalink / raw)
  To: Svyatoslav Ryhel
  Cc: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Dmitry Torokhov, Pavel Machek, Arnd Bergmann, Greg Kroah-Hartman,
	Sebastian Reichel, Michał Mirosław, Ion Agorria,
	devicetree, linux-kernel, linux-input, linux-leds, linux-pm

On Mon, Feb 09, 2026 at 12:44:01PM +0200, Svyatoslav Ryhel wrote:
> Document embedded controller used in ASUS Transformer device series.
> 
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> ---
>  .../devicetree/bindings/mfd/asus,ec.yaml      | 152 ++++++++++++++++++
>  1 file changed, 152 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mfd/asus,ec.yaml
> 
> diff --git a/Documentation/devicetree/bindings/mfd/asus,ec.yaml b/Documentation/devicetree/bindings/mfd/asus,ec.yaml
> new file mode 100644
> index 000000000000..1d1a62761b71
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mfd/asus,ec.yaml

EC do not go to MFD, but to dedicated directory (there is such).

> @@ -0,0 +1,152 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/mfd/asus,ec.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: ASUS Transformer's Embedded Controller
> +
> +description:
> +  Several Nuvoton based Embedded Controller attached to an I2C bus,
> +  running a custom ASUS firmware, specific to the Asus Transformer
> +  device series.
> +
> +maintainers:
> +  - Svyatoslav Ryhel <clamor95@gmail.com>
> +
> +properties:
> +  compatible:
> +    oneOf:

Drop oneOf

> +      - enum:
> +          - asus,ec-pad  # Pad part of Asus Transformer
> +          - asus,ec-dock # Dock part of Asus Transformer


Compatibles are way too generic. "ec" basically means you document all
Asus EC, which is for sure not true. You need specific compatible for
this specific model.

Missing blank line.

> +  reg:
> +    maxItems: 1
> +
> +  interrupts:
> +    maxItems: 1
> +
> +  request-gpio:

gpio is deprecated. gpios, look at any other binding.

> +    maxItems: 1
> +
> +  asus,dockram:
> +    $ref: /schemas/types.yaml#/definitions/phandle
> +    description: I2C device used to access power related functions.
> +
> +  asus,clear-factory-mode:
> +    type: boolean
> +    description: clear Factory Mode bit in EC control register

Why would this be a static/fixed property over lifecycle of all devices?

> +
> +  battery:
> +    type: object
> +    $ref: /schemas/power/supply/power-supply.yaml
> +    unevaluatedProperties: false
> +
> +    properties:
> +      compatible:
> +        const: asus,ec-battery
> +
> +    required:
> +      - compatible
> +
> +  charger:
> +    type: object
> +    $ref: /schemas/power/supply/power-supply.yaml
> +    additionalProperties: false
> +
> +    properties:
> +      compatible:
> +        const: asus,ec-charger
> +
> +      monitored-battery: true
> +
> +    required:
> +      - compatible
> +
> +  keyboard-ext:
> +    type: object
> +    description: top row of multimedia keys
> +    additionalProperties: false
> +
> +    properties:
> +      compatible:
> +        const: asus,ec-keys
> +
> +    required:
> +      - compatible
> +
> +  led:
> +    type: object
> +    additionalProperties: false
> +
> +    properties:
> +      compatible:
> +        const: asus,ec-led
> +
> +    required:
> +      - compatible
> +
> +  serio:

All of these children are pointless - no resources. Drop all of them,
it's btw explicitly documented rule in writing bindings.

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v2 1/9] dt-bindings: misc: document ASUS Transformers EC DockRAM
  2026-02-09 10:43 ` [PATCH v2 1/9] dt-bindings: misc: document ASUS Transformers EC DockRAM Svyatoslav Ryhel
@ 2026-02-10  9:25   ` Krzysztof Kozlowski
  2026-02-10  9:42     ` Svyatoslav Ryhel
  0 siblings, 1 reply; 30+ messages in thread
From: Krzysztof Kozlowski @ 2026-02-10  9:25 UTC (permalink / raw)
  To: Svyatoslav Ryhel
  Cc: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Dmitry Torokhov, Pavel Machek, Arnd Bergmann, Greg Kroah-Hartman,
	Sebastian Reichel, Michał Mirosław, Ion Agorria,
	devicetree, linux-kernel, linux-input, linux-leds, linux-pm

On Mon, Feb 09, 2026 at 12:43:59PM +0200, Svyatoslav Ryhel wrote:
> Documenting an I2C device used in conjunction with the EC on ASUS
> Transformers. The main function of DockRAM (the name used by downstream
> ASUS sources) is to provide power-related functions, such as battery and
> charger communication. The device is exposed as an individual entity
> because multiple embedded controllers can utilize the same DockRAM
> instance.
> 
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> ---
>  .../bindings/misc/asus,dockram.yaml           | 40 +++++++++++++++++++
>  1 file changed, 40 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/misc/asus,dockram.yaml
> 
> diff --git a/Documentation/devicetree/bindings/misc/asus,dockram.yaml b/Documentation/devicetree/bindings/misc/asus,dockram.yaml
> new file mode 100644
> index 000000000000..0cfde619ba01
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/misc/asus,dockram.yaml

Not a misc device. Find appropriate place, e.g. for EC or docking or
laptop devices or power-related.

> @@ -0,0 +1,40 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/misc/asus,dockram.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Asus Transformer EC DockRAM
> +
> +maintainers:
> +  - Svyatoslav Ryhel <clamor95@gmail.com>
> +
> +description:
> +  Dedicated i2c device used to provide power related functions of the
> +  embedded controller used in ASUS Transformer device family.
> +
> +properties:
> +  compatible:
> +    const: asus,dockram

Way too generic compatible. You are not documenting here all ASUS
laptops/devices dockram. For example this implies dockram is also on
ASUS Vivobook... or on any other asus device.

> +
> +  reg:
> +    maxItems: 1
> +
> +required:
> +  - compatible
> +  - reg
> +

Device looks weirdly empty. Probably you have it only to instantiate I2C
handle, so what you really wanted is i2c-parent. This is not a real
device.

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v2 3/9] dt-bindings: mfd: document ASUS Transformer EC
  2026-02-10  9:22   ` Krzysztof Kozlowski
@ 2026-02-10  9:37     ` Svyatoslav Ryhel
  2026-02-10 10:48       ` Krzysztof Kozlowski
  0 siblings, 1 reply; 30+ messages in thread
From: Svyatoslav Ryhel @ 2026-02-10  9:37 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Dmitry Torokhov, Pavel Machek, Arnd Bergmann, Greg Kroah-Hartman,
	Sebastian Reichel, Michał Mirosław, Ion Agorria,
	devicetree, linux-kernel, linux-input, linux-leds, linux-pm

вт, 10 лют. 2026 р. о 11:22 Krzysztof Kozlowski <krzk@kernel.org> пише:
>
> On Mon, Feb 09, 2026 at 12:44:01PM +0200, Svyatoslav Ryhel wrote:
> > Document embedded controller used in ASUS Transformer device series.
> >
> > Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > ---
> >  .../devicetree/bindings/mfd/asus,ec.yaml      | 152 ++++++++++++++++++
> >  1 file changed, 152 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/mfd/asus,ec.yaml
> >
> > diff --git a/Documentation/devicetree/bindings/mfd/asus,ec.yaml b/Documentation/devicetree/bindings/mfd/asus,ec.yaml
> > new file mode 100644
> > index 000000000000..1d1a62761b71
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/mfd/asus,ec.yaml
>
> EC do not go to MFD, but to dedicated directory (there is such).
>

Noted

> > @@ -0,0 +1,152 @@
> > +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/mfd/asus,ec.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: ASUS Transformer's Embedded Controller
> > +
> > +description:
> > +  Several Nuvoton based Embedded Controller attached to an I2C bus,
> > +  running a custom ASUS firmware, specific to the Asus Transformer
> > +  device series.
> > +
> > +maintainers:
> > +  - Svyatoslav Ryhel <clamor95@gmail.com>
> > +
> > +properties:
> > +  compatible:
> > +    oneOf:
>
> Drop oneOf
>

Noted

> > +      - enum:
> > +          - asus,ec-pad  # Pad part of Asus Transformer
> > +          - asus,ec-dock # Dock part of Asus Transformer
>
>
> Compatibles are way too generic. "ec" basically means you document all
> Asus EC, which is for sure not true. You need specific compatible for
> this specific model.
>

Asus were not so generous to provide more specific data, they call
there controllers asusdec and asusped in their sources.

> Missing blank line.
>

noted

> > +  reg:
> > +    maxItems: 1
> > +
> > +  interrupts:
> > +    maxItems: 1
> > +
> > +  request-gpio:
>
> gpio is deprecated. gpios, look at any other binding.
>

noted

> > +    maxItems: 1
> > +
> > +  asus,dockram:
> > +    $ref: /schemas/types.yaml#/definitions/phandle
> > +    description: I2C device used to access power related functions.
> > +
> > +  asus,clear-factory-mode:
> > +    type: boolean
> > +    description: clear Factory Mode bit in EC control register
>
> Why would this be a static/fixed property over lifecycle of all devices?
>

Specify pls.

> > +
> > +  battery:
> > +    type: object
> > +    $ref: /schemas/power/supply/power-supply.yaml
> > +    unevaluatedProperties: false
> > +
> > +    properties:
> > +      compatible:
> > +        const: asus,ec-battery
> > +
> > +    required:
> > +      - compatible
> > +
> > +  charger:
> > +    type: object
> > +    $ref: /schemas/power/supply/power-supply.yaml
> > +    additionalProperties: false
> > +
> > +    properties:
> > +      compatible:
> > +        const: asus,ec-charger
> > +
> > +      monitored-battery: true
> > +
> > +    required:
> > +      - compatible
> > +
> > +  keyboard-ext:
> > +    type: object
> > +    description: top row of multimedia keys
> > +    additionalProperties: false
> > +
> > +    properties:
> > +      compatible:
> > +        const: asus,ec-keys
> > +
> > +    required:
> > +      - compatible
> > +
> > +  led:
> > +    type: object
> > +    additionalProperties: false
> > +
> > +    properties:
> > +      compatible:
> > +        const: asus,ec-led
> > +
> > +    required:
> > +      - compatible
> > +
> > +  serio:
>
> All of these children are pointless - no resources. Drop all of them,
> it's btw explicitly documented rule in writing bindings.
>

They are all needed to be able to disable them individually from the
device tree if needed.

> Best regards,
> Krzysztof
>

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v2 1/9] dt-bindings: misc: document ASUS Transformers EC DockRAM
  2026-02-10  9:25   ` Krzysztof Kozlowski
@ 2026-02-10  9:42     ` Svyatoslav Ryhel
  2026-02-10 10:50       ` Krzysztof Kozlowski
  0 siblings, 1 reply; 30+ messages in thread
From: Svyatoslav Ryhel @ 2026-02-10  9:42 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Dmitry Torokhov, Pavel Machek, Arnd Bergmann, Greg Kroah-Hartman,
	Sebastian Reichel, Michał Mirosław, Ion Agorria,
	devicetree, linux-kernel, linux-input, linux-leds, linux-pm

вт, 10 лют. 2026 р. о 11:25 Krzysztof Kozlowski <krzk@kernel.org> пише:
>
> On Mon, Feb 09, 2026 at 12:43:59PM +0200, Svyatoslav Ryhel wrote:
> > Documenting an I2C device used in conjunction with the EC on ASUS
> > Transformers. The main function of DockRAM (the name used by downstream
> > ASUS sources) is to provide power-related functions, such as battery and
> > charger communication. The device is exposed as an individual entity
> > because multiple embedded controllers can utilize the same DockRAM
> > instance.
> >
> > Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > ---
> >  .../bindings/misc/asus,dockram.yaml           | 40 +++++++++++++++++++
> >  1 file changed, 40 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/misc/asus,dockram.yaml
> >
> > diff --git a/Documentation/devicetree/bindings/misc/asus,dockram.yaml b/Documentation/devicetree/bindings/misc/asus,dockram.yaml
> > new file mode 100644
> > index 000000000000..0cfde619ba01
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/misc/asus,dockram.yaml
>
> Not a misc device. Find appropriate place, e.g. for EC or docking or
> laptop devices or power-related.
>

Why not misc? be more specific pls where you want it to be.

> > @@ -0,0 +1,40 @@
> > +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/misc/asus,dockram.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: Asus Transformer EC DockRAM
> > +
> > +maintainers:
> > +  - Svyatoslav Ryhel <clamor95@gmail.com>
> > +
> > +description:
> > +  Dedicated i2c device used to provide power related functions of the
> > +  embedded controller used in ASUS Transformer device family.
> > +
> > +properties:
> > +  compatible:
> > +    const: asus,dockram
>
> Way too generic compatible. You are not documenting here all ASUS
> laptops/devices dockram. For example this implies dockram is also on
> ASUS Vivobook... or on any other asus device.
>

Asus were not so generous to provide more specific data, they call
this device dockram in their sources.

> > +
> > +  reg:
> > +    maxItems: 1
> > +
> > +required:
> > +  - compatible
> > +  - reg
> > +
>
> Device looks weirdly empty. Probably you have it only to instantiate I2C
> handle, so what you really wanted is i2c-parent. This is not a real
> device.
>

WDYM? it is a real physical i2c device located on a i2c bus and probed
by i2c driver just fine. Maybe you will deny RTC being a real device
like it was done for example for max77663 which now causes a massive
issues since it can occupy different i2c addresses?

> Best regards,
> Krzysztof
>

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v2 3/9] dt-bindings: mfd: document ASUS Transformer EC
  2026-02-10  9:37     ` Svyatoslav Ryhel
@ 2026-02-10 10:48       ` Krzysztof Kozlowski
  2026-02-10 10:59         ` Svyatoslav Ryhel
  0 siblings, 1 reply; 30+ messages in thread
From: Krzysztof Kozlowski @ 2026-02-10 10:48 UTC (permalink / raw)
  To: Svyatoslav Ryhel
  Cc: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Dmitry Torokhov, Pavel Machek, Arnd Bergmann, Greg Kroah-Hartman,
	Sebastian Reichel, Michał Mirosław, Ion Agorria,
	devicetree, linux-kernel, linux-input, linux-leds, linux-pm

On 10/02/2026 10:37, Svyatoslav Ryhel wrote:
> вт, 10 лют. 2026 р. о 11:22 Krzysztof Kozlowski <krzk@kernel.org> пише:
>>
>> On Mon, Feb 09, 2026 at 12:44:01PM +0200, Svyatoslav Ryhel wrote:
>>> Document embedded controller used in ASUS Transformer device series.
>>>
>>> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
>>> ---
>>>  .../devicetree/bindings/mfd/asus,ec.yaml      | 152 ++++++++++++++++++
>>>  1 file changed, 152 insertions(+)
>>>  create mode 100644 Documentation/devicetree/bindings/mfd/asus,ec.yaml
>>>
>>> diff --git a/Documentation/devicetree/bindings/mfd/asus,ec.yaml b/Documentation/devicetree/bindings/mfd/asus,ec.yaml
>>> new file mode 100644
>>> index 000000000000..1d1a62761b71
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/mfd/asus,ec.yaml
>>
>> EC do not go to MFD, but to dedicated directory (there is such).
>>
> 
> Noted
> 
>>> @@ -0,0 +1,152 @@
>>> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
>>> +%YAML 1.2
>>> +---
>>> +$id: http://devicetree.org/schemas/mfd/asus,ec.yaml#
>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>> +
>>> +title: ASUS Transformer's Embedded Controller
>>> +
>>> +description:
>>> +  Several Nuvoton based Embedded Controller attached to an I2C bus,
>>> +  running a custom ASUS firmware, specific to the Asus Transformer
>>> +  device series.
>>> +
>>> +maintainers:
>>> +  - Svyatoslav Ryhel <clamor95@gmail.com>
>>> +
>>> +properties:
>>> +  compatible:
>>> +    oneOf:
>>
>> Drop oneOf
>>
> 
> Noted
> 
>>> +      - enum:
>>> +          - asus,ec-pad  # Pad part of Asus Transformer
>>> +          - asus,ec-dock # Dock part of Asus Transformer
>>
>>
>> Compatibles are way too generic. "ec" basically means you document all
>> Asus EC, which is for sure not true. You need specific compatible for
>> this specific model.
>>
> 
> Asus were not so generous to provide more specific data, they call
> there controllers asusdec and asusped in their sources.

Look how other ECs are called. Your device is not "", but e.g.
"Transformer".

> 
>> Missing blank line.
>>
> 
> noted
> 
>>> +  reg:
>>> +    maxItems: 1
>>> +
>>> +  interrupts:
>>> +    maxItems: 1
>>> +
>>> +  request-gpio:
>>
>> gpio is deprecated. gpios, look at any other binding.
>>
> 
> noted
> 
>>> +    maxItems: 1
>>> +
>>> +  asus,dockram:
>>> +    $ref: /schemas/types.yaml#/definitions/phandle
>>> +    description: I2C device used to access power related functions.
>>> +
>>> +  asus,clear-factory-mode:
>>> +    type: boolean
>>> +    description: clear Factory Mode bit in EC control register
>>
>> Why would this be a static/fixed property over lifecycle of all devices?
>>
> 
> Specify pls.

Provide rationale why we need to clear it every time, not once. Or any
other rationale why we would accept that property.


> 
>>> +
>>> +  battery:
>>> +    type: object
>>> +    $ref: /schemas/power/supply/power-supply.yaml
>>> +    unevaluatedProperties: false
>>> +
>>> +    properties:
>>> +      compatible:
>>> +        const: asus,ec-battery
>>> +
>>> +    required:
>>> +      - compatible
>>> +
>>> +  charger:
>>> +    type: object
>>> +    $ref: /schemas/power/supply/power-supply.yaml
>>> +    additionalProperties: false
>>> +
>>> +    properties:
>>> +      compatible:
>>> +        const: asus,ec-charger
>>> +
>>> +      monitored-battery: true
>>> +
>>> +    required:
>>> +      - compatible
>>> +
>>> +  keyboard-ext:
>>> +    type: object
>>> +    description: top row of multimedia keys
>>> +    additionalProperties: false
>>> +
>>> +    properties:
>>> +      compatible:
>>> +        const: asus,ec-keys
>>> +
>>> +    required:
>>> +      - compatible
>>> +
>>> +  led:
>>> +    type: object
>>> +    additionalProperties: false
>>> +
>>> +    properties:
>>> +      compatible:
>>> +        const: asus,ec-led
>>> +
>>> +    required:
>>> +      - compatible
>>> +
>>> +  serio:
>>
>> All of these children are pointless - no resources. Drop all of them,
>> it's btw explicitly documented rule in writing bindings.
>>
> 
> They are all needed to be able to disable them individually from the
> device tree if needed.

They should not be disabled from DT, so they are not valid here. The
given EC for given device is fixed/static. Does not change.


Best regards,
Krzysztof

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v2 1/9] dt-bindings: misc: document ASUS Transformers EC DockRAM
  2026-02-10  9:42     ` Svyatoslav Ryhel
@ 2026-02-10 10:50       ` Krzysztof Kozlowski
  2026-02-10 11:08         ` Svyatoslav Ryhel
  0 siblings, 1 reply; 30+ messages in thread
From: Krzysztof Kozlowski @ 2026-02-10 10:50 UTC (permalink / raw)
  To: Svyatoslav Ryhel
  Cc: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Dmitry Torokhov, Pavel Machek, Arnd Bergmann, Greg Kroah-Hartman,
	Sebastian Reichel, Michał Mirosław, Ion Agorria,
	devicetree, linux-kernel, linux-input, linux-leds, linux-pm

On 10/02/2026 10:42, Svyatoslav Ryhel wrote:
> вт, 10 лют. 2026 р. о 11:25 Krzysztof Kozlowski <krzk@kernel.org> пише:
>>
>> On Mon, Feb 09, 2026 at 12:43:59PM +0200, Svyatoslav Ryhel wrote:
>>> Documenting an I2C device used in conjunction with the EC on ASUS
>>> Transformers. The main function of DockRAM (the name used by downstream
>>> ASUS sources) is to provide power-related functions, such as battery and
>>> charger communication. The device is exposed as an individual entity
>>> because multiple embedded controllers can utilize the same DockRAM
>>> instance.
>>>
>>> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
>>> ---
>>>  .../bindings/misc/asus,dockram.yaml           | 40 +++++++++++++++++++
>>>  1 file changed, 40 insertions(+)
>>>  create mode 100644 Documentation/devicetree/bindings/misc/asus,dockram.yaml
>>>
>>> diff --git a/Documentation/devicetree/bindings/misc/asus,dockram.yaml b/Documentation/devicetree/bindings/misc/asus,dockram.yaml
>>> new file mode 100644
>>> index 000000000000..0cfde619ba01
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/misc/asus,dockram.yaml
>>
>> Not a misc device. Find appropriate place, e.g. for EC or docking or
>> laptop devices or power-related.
>>
> 
> Why not misc? be more specific pls where you want it to be.

Because there is no such device as "misc". Otherwise explain me what
sort of device is "misc".

I already wrote where I want it to be placed. You keep bouncing
questions pointlessly, even when given exact request.



> 
>>> @@ -0,0 +1,40 @@
>>> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
>>> +%YAML 1.2
>>> +---
>>> +$id: http://devicetree.org/schemas/misc/asus,dockram.yaml#
>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>> +
>>> +title: Asus Transformer EC DockRAM
>>> +
>>> +maintainers:
>>> +  - Svyatoslav Ryhel <clamor95@gmail.com>
>>> +
>>> +description:
>>> +  Dedicated i2c device used to provide power related functions of the
>>> +  embedded controller used in ASUS Transformer device family.
>>> +
>>> +properties:
>>> +  compatible:
>>> +    const: asus,dockram
>>
>> Way too generic compatible. You are not documenting here all ASUS
>> laptops/devices dockram. For example this implies dockram is also on
>> ASUS Vivobook... or on any other asus device.
>>
> 
> Asus were not so generous to provide more specific data, they call
> this device dockram in their sources.



> 
>>> +
>>> +  reg:
>>> +    maxItems: 1
>>> +
>>> +required:
>>> +  - compatible
>>> +  - reg
>>> +
>>
>> Device looks weirdly empty. Probably you have it only to instantiate I2C
>> handle, so what you really wanted is i2c-parent. This is not a real
>> device.
>>
> 
> WDYM? it is a real physical i2c device located on a i2c bus and probed
> by i2c driver just fine. Maybe you will deny RTC being a real device

Driver does not matter here.

> like it was done for example for max77663 which now causes a massive
> issues since it can occupy different i2c addresses?

Then describe what is the device here. So far it looks exactly like
"ec-dock" for which you already have a binding.

Best regards,
Krzysztof

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v2 3/9] dt-bindings: mfd: document ASUS Transformer EC
  2026-02-10 10:48       ` Krzysztof Kozlowski
@ 2026-02-10 10:59         ` Svyatoslav Ryhel
  2026-02-10 11:04           ` Krzysztof Kozlowski
  0 siblings, 1 reply; 30+ messages in thread
From: Svyatoslav Ryhel @ 2026-02-10 10:59 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Dmitry Torokhov, Pavel Machek, Arnd Bergmann, Greg Kroah-Hartman,
	Sebastian Reichel, Michał Mirosław, Ion Agorria,
	devicetree, linux-kernel, linux-input, linux-leds, linux-pm

вт, 10 лют. 2026 р. о 12:48 Krzysztof Kozlowski <krzk@kernel.org> пише:
>
> On 10/02/2026 10:37, Svyatoslav Ryhel wrote:
> > вт, 10 лют. 2026 р. о 11:22 Krzysztof Kozlowski <krzk@kernel.org> пише:
> >>
> >> On Mon, Feb 09, 2026 at 12:44:01PM +0200, Svyatoslav Ryhel wrote:
> >>> Document embedded controller used in ASUS Transformer device series.
> >>>
> >>> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> >>> ---
> >>>  .../devicetree/bindings/mfd/asus,ec.yaml      | 152 ++++++++++++++++++
> >>>  1 file changed, 152 insertions(+)
> >>>  create mode 100644 Documentation/devicetree/bindings/mfd/asus,ec.yaml
> >>>
> >>> diff --git a/Documentation/devicetree/bindings/mfd/asus,ec.yaml b/Documentation/devicetree/bindings/mfd/asus,ec.yaml
> >>> new file mode 100644
> >>> index 000000000000..1d1a62761b71
> >>> --- /dev/null
> >>> +++ b/Documentation/devicetree/bindings/mfd/asus,ec.yaml
> >>
> >> EC do not go to MFD, but to dedicated directory (there is such).
> >>
> >
> > Noted
> >
> >>> @@ -0,0 +1,152 @@
> >>> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> >>> +%YAML 1.2
> >>> +---
> >>> +$id: http://devicetree.org/schemas/mfd/asus,ec.yaml#
> >>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> >>> +
> >>> +title: ASUS Transformer's Embedded Controller
> >>> +
> >>> +description:
> >>> +  Several Nuvoton based Embedded Controller attached to an I2C bus,
> >>> +  running a custom ASUS firmware, specific to the Asus Transformer
> >>> +  device series.
> >>> +
> >>> +maintainers:
> >>> +  - Svyatoslav Ryhel <clamor95@gmail.com>
> >>> +
> >>> +properties:
> >>> +  compatible:
> >>> +    oneOf:
> >>
> >> Drop oneOf
> >>
> >
> > Noted
> >
> >>> +      - enum:
> >>> +          - asus,ec-pad  # Pad part of Asus Transformer
> >>> +          - asus,ec-dock # Dock part of Asus Transformer
> >>
> >>
> >> Compatibles are way too generic. "ec" basically means you document all
> >> Asus EC, which is for sure not true. You need specific compatible for
> >> this specific model.
> >>
> >
> > Asus were not so generous to provide more specific data, they call
> > there controllers asusdec and asusped in their sources.
>
> Look how other ECs are called. Your device is not "", but e.g.
> "Transformer".
>
> >
> >> Missing blank line.
> >>
> >
> > noted
> >
> >>> +  reg:
> >>> +    maxItems: 1
> >>> +
> >>> +  interrupts:
> >>> +    maxItems: 1
> >>> +
> >>> +  request-gpio:
> >>
> >> gpio is deprecated. gpios, look at any other binding.
> >>
> >
> > noted
> >
> >>> +    maxItems: 1
> >>> +
> >>> +  asus,dockram:
> >>> +    $ref: /schemas/types.yaml#/definitions/phandle
> >>> +    description: I2C device used to access power related functions.
> >>> +
> >>> +  asus,clear-factory-mode:
> >>> +    type: boolean
> >>> +    description: clear Factory Mode bit in EC control register
> >>
> >> Why would this be a static/fixed property over lifecycle of all devices?
> >>
> >
> > Specify pls.
>
> Provide rationale why we need to clear it every time, not once. Or any
> other rationale why we would accept that property.
>

Cause it is done by original Asus code and Asus did not provide
schematic or any data apart from downstream source regarding this EC.

> >
> >>> +
> >>> +  battery:
> >>> +    type: object
> >>> +    $ref: /schemas/power/supply/power-supply.yaml
> >>> +    unevaluatedProperties: false
> >>> +
> >>> +    properties:
> >>> +      compatible:
> >>> +        const: asus,ec-battery
> >>> +
> >>> +    required:
> >>> +      - compatible
> >>> +
> >>> +  charger:
> >>> +    type: object
> >>> +    $ref: /schemas/power/supply/power-supply.yaml
> >>> +    additionalProperties: false
> >>> +
> >>> +    properties:
> >>> +      compatible:
> >>> +        const: asus,ec-charger
> >>> +
> >>> +      monitored-battery: true
> >>> +
> >>> +    required:
> >>> +      - compatible
> >>> +
> >>> +  keyboard-ext:
> >>> +    type: object
> >>> +    description: top row of multimedia keys
> >>> +    additionalProperties: false
> >>> +
> >>> +    properties:
> >>> +      compatible:
> >>> +        const: asus,ec-keys
> >>> +
> >>> +    required:
> >>> +      - compatible
> >>> +
> >>> +  led:
> >>> +    type: object
> >>> +    additionalProperties: false
> >>> +
> >>> +    properties:
> >>> +      compatible:
> >>> +        const: asus,ec-led
> >>> +
> >>> +    required:
> >>> +      - compatible
> >>> +
> >>> +  serio:
> >>
> >> All of these children are pointless - no resources. Drop all of them,
> >> it's btw explicitly documented rule in writing bindings.
> >>
> >
> > They are all needed to be able to disable them individually from the
> > device tree if needed.
>
> They should not be disabled from DT, so they are not valid here. The
> given EC for given device is fixed/static. Does not change.
>

Have you considered a possibility that function may be
disabled/unrouted within the controller. By the vendor.

>
> Best regards,
> Krzysztof

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v2 3/9] dt-bindings: mfd: document ASUS Transformer EC
  2026-02-10 10:59         ` Svyatoslav Ryhel
@ 2026-02-10 11:04           ` Krzysztof Kozlowski
  2026-02-10 11:14             ` Svyatoslav Ryhel
  0 siblings, 1 reply; 30+ messages in thread
From: Krzysztof Kozlowski @ 2026-02-10 11:04 UTC (permalink / raw)
  To: Svyatoslav Ryhel
  Cc: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Dmitry Torokhov, Pavel Machek, Arnd Bergmann, Greg Kroah-Hartman,
	Sebastian Reichel, Michał Mirosław, Ion Agorria,
	devicetree, linux-kernel, linux-input, linux-leds, linux-pm

On 10/02/2026 11:59, Svyatoslav Ryhel wrote:
>>>>> +  asus,clear-factory-mode:
>>>>> +    type: boolean
>>>>> +    description: clear Factory Mode bit in EC control register
>>>>
>>>> Why would this be a static/fixed property over lifecycle of all devices?
>>>>
>>>
>>> Specify pls.
>>
>> Provide rationale why we need to clear it every time, not once. Or any
>> other rationale why we would accept that property.
>>
> 
> Cause it is done by original Asus code and Asus did not provide
> schematic or any data apart from downstream source regarding this EC.

So that's a no. downstream code which is poor quality, not following DT
rules at all, is never an argument for a DT property.

> 
>>>
>>>>> +
>>>>> +  battery:
>>>>> +    type: object
>>>>> +    $ref: /schemas/power/supply/power-supply.yaml
>>>>> +    unevaluatedProperties: false
>>>>> +
>>>>> +    properties:
>>>>> +      compatible:
>>>>> +        const: asus,ec-battery
>>>>> +
>>>>> +    required:
>>>>> +      - compatible
>>>>> +
>>>>> +  charger:
>>>>> +    type: object
>>>>> +    $ref: /schemas/power/supply/power-supply.yaml
>>>>> +    additionalProperties: false
>>>>> +
>>>>> +    properties:
>>>>> +      compatible:
>>>>> +        const: asus,ec-charger
>>>>> +
>>>>> +      monitored-battery: true
>>>>> +
>>>>> +    required:
>>>>> +      - compatible
>>>>> +
>>>>> +  keyboard-ext:
>>>>> +    type: object
>>>>> +    description: top row of multimedia keys
>>>>> +    additionalProperties: false
>>>>> +
>>>>> +    properties:
>>>>> +      compatible:
>>>>> +        const: asus,ec-keys
>>>>> +
>>>>> +    required:
>>>>> +      - compatible
>>>>> +
>>>>> +  led:
>>>>> +    type: object
>>>>> +    additionalProperties: false
>>>>> +
>>>>> +    properties:
>>>>> +      compatible:
>>>>> +        const: asus,ec-led
>>>>> +
>>>>> +    required:
>>>>> +      - compatible
>>>>> +
>>>>> +  serio:
>>>>
>>>> All of these children are pointless - no resources. Drop all of them,
>>>> it's btw explicitly documented rule in writing bindings.
>>>>
>>>
>>> They are all needed to be able to disable them individually from the
>>> device tree if needed.
>>
>> They should not be disabled from DT, so they are not valid here. The
>> given EC for given device is fixed/static. Does not change.
>>
> 
> Have you considered a possibility that function may be
> disabled/unrouted within the controller. By the vendor.

And then it is implied by the compatible, so no need for any of that.
Otherwise, if it is not specific per device, then specifying it for DTS
for all devices would make no sense.

Best regards,
Krzysztof

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v2 1/9] dt-bindings: misc: document ASUS Transformers EC DockRAM
  2026-02-10 10:50       ` Krzysztof Kozlowski
@ 2026-02-10 11:08         ` Svyatoslav Ryhel
  0 siblings, 0 replies; 30+ messages in thread
From: Svyatoslav Ryhel @ 2026-02-10 11:08 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Dmitry Torokhov, Pavel Machek, Arnd Bergmann, Greg Kroah-Hartman,
	Sebastian Reichel, Michał Mirosław, Ion Agorria,
	devicetree, linux-kernel, linux-input, linux-leds, linux-pm

вт, 10 лют. 2026 р. о 12:50 Krzysztof Kozlowski <krzk@kernel.org> пише:
>
> On 10/02/2026 10:42, Svyatoslav Ryhel wrote:
> > вт, 10 лют. 2026 р. о 11:25 Krzysztof Kozlowski <krzk@kernel.org> пише:
> >>
> >> On Mon, Feb 09, 2026 at 12:43:59PM +0200, Svyatoslav Ryhel wrote:
> >>> Documenting an I2C device used in conjunction with the EC on ASUS
> >>> Transformers. The main function of DockRAM (the name used by downstream
> >>> ASUS sources) is to provide power-related functions, such as battery and
> >>> charger communication. The device is exposed as an individual entity
> >>> because multiple embedded controllers can utilize the same DockRAM
> >>> instance.
> >>>
> >>> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> >>> ---
> >>>  .../bindings/misc/asus,dockram.yaml           | 40 +++++++++++++++++++
> >>>  1 file changed, 40 insertions(+)
> >>>  create mode 100644 Documentation/devicetree/bindings/misc/asus,dockram.yaml
> >>>
> >>> diff --git a/Documentation/devicetree/bindings/misc/asus,dockram.yaml b/Documentation/devicetree/bindings/misc/asus,dockram.yaml
> >>> new file mode 100644
> >>> index 000000000000..0cfde619ba01
> >>> --- /dev/null
> >>> +++ b/Documentation/devicetree/bindings/misc/asus,dockram.yaml
> >>
> >> Not a misc device. Find appropriate place, e.g. for EC or docking or
> >> laptop devices or power-related.
> >>
> >
> > Why not misc? be more specific pls where you want it to be.
>
> Because there is no such device as "misc". Otherwise explain me what
> sort of device is "misc".
>
> I already wrote where I want it to be placed. You keep bouncing
> questions pointlessly, even when given exact request.
>

Among your list only EC exists. There are no docking or laptop devices
or power-related. Hence asking.

>
> >
> >>> @@ -0,0 +1,40 @@
> >>> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> >>> +%YAML 1.2
> >>> +---
> >>> +$id: http://devicetree.org/schemas/misc/asus,dockram.yaml#
> >>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> >>> +
> >>> +title: Asus Transformer EC DockRAM
> >>> +
> >>> +maintainers:
> >>> +  - Svyatoslav Ryhel <clamor95@gmail.com>
> >>> +
> >>> +description:
> >>> +  Dedicated i2c device used to provide power related functions of the
> >>> +  embedded controller used in ASUS Transformer device family.
> >>> +
> >>> +properties:
> >>> +  compatible:
> >>> +    const: asus,dockram
> >>
> >> Way too generic compatible. You are not documenting here all ASUS
> >> laptops/devices dockram. For example this implies dockram is also on
> >> ASUS Vivobook... or on any other asus device.
> >>
> >
> > Asus were not so generous to provide more specific data, they call
> > this device dockram in their sources.
>
>
>
> >
> >>> +
> >>> +  reg:
> >>> +    maxItems: 1
> >>> +
> >>> +required:
> >>> +  - compatible
> >>> +  - reg
> >>> +
> >>
> >> Device looks weirdly empty. Probably you have it only to instantiate I2C
> >> handle, so what you really wanted is i2c-parent. This is not a real
> >> device.
> >>
> >
> > WDYM? it is a real physical i2c device located on a i2c bus and probed
> > by i2c driver just fine. Maybe you will deny RTC being a real device
>
> Driver does not matter here.
>

It seems that you see a "forbidden" word and tear it out of context.

> > like it was done for example for max77663 which now causes a massive
> > issues since it can occupy different i2c addresses?
>
> Then describe what is the device here. So far it looks exactly like
> "ec-dock" for which you already have a binding.
>

Wrong, it has nothing to do with "ec-dock" specifically. It is has a
pretty discrete description. It used to provide power related
functions of the embedded controller used in ASUS Transformer device
family. To access to battery stats, charger status, leds control. Can
be used by multiple controllers at once (like on TF701T or TF600T)

> Best regards,
> Krzysztof

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v2 3/9] dt-bindings: mfd: document ASUS Transformer EC
  2026-02-10 11:04           ` Krzysztof Kozlowski
@ 2026-02-10 11:14             ` Svyatoslav Ryhel
  2026-02-10 11:24               ` Krzysztof Kozlowski
  0 siblings, 1 reply; 30+ messages in thread
From: Svyatoslav Ryhel @ 2026-02-10 11:14 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Dmitry Torokhov, Pavel Machek, Arnd Bergmann, Greg Kroah-Hartman,
	Sebastian Reichel, Michał Mirosław, Ion Agorria,
	devicetree, linux-kernel, linux-input, linux-leds, linux-pm

вт, 10 лют. 2026 р. о 13:04 Krzysztof Kozlowski <krzk@kernel.org> пише:
>
> On 10/02/2026 11:59, Svyatoslav Ryhel wrote:
> >>>>> +  asus,clear-factory-mode:
> >>>>> +    type: boolean
> >>>>> +    description: clear Factory Mode bit in EC control register
> >>>>
> >>>> Why would this be a static/fixed property over lifecycle of all devices?
> >>>>
> >>>
> >>> Specify pls.
> >>
> >> Provide rationale why we need to clear it every time, not once. Or any
> >> other rationale why we would accept that property.
> >>
> >
> > Cause it is done by original Asus code and Asus did not provide
> > schematic or any data apart from downstream source regarding this EC.
>
> So that's a no. downstream code which is poor quality, not following DT
> rules at all, is never an argument for a DT property.
>

This property indicates that this controller on every reset restores
factory bit hence it must be cleared. Bit is write only and cannot be
detected. EC remains in factory mode which blocks its functions.

> >
> >>>
> >>>>> +
> >>>>> +  battery:
> >>>>> +    type: object
> >>>>> +    $ref: /schemas/power/supply/power-supply.yaml
> >>>>> +    unevaluatedProperties: false
> >>>>> +
> >>>>> +    properties:
> >>>>> +      compatible:
> >>>>> +        const: asus,ec-battery
> >>>>> +
> >>>>> +    required:
> >>>>> +      - compatible
> >>>>> +
> >>>>> +  charger:
> >>>>> +    type: object
> >>>>> +    $ref: /schemas/power/supply/power-supply.yaml
> >>>>> +    additionalProperties: false
> >>>>> +
> >>>>> +    properties:
> >>>>> +      compatible:
> >>>>> +        const: asus,ec-charger
> >>>>> +
> >>>>> +      monitored-battery: true
> >>>>> +
> >>>>> +    required:
> >>>>> +      - compatible
> >>>>> +
> >>>>> +  keyboard-ext:
> >>>>> +    type: object
> >>>>> +    description: top row of multimedia keys
> >>>>> +    additionalProperties: false
> >>>>> +
> >>>>> +    properties:
> >>>>> +      compatible:
> >>>>> +        const: asus,ec-keys
> >>>>> +
> >>>>> +    required:
> >>>>> +      - compatible
> >>>>> +
> >>>>> +  led:
> >>>>> +    type: object
> >>>>> +    additionalProperties: false
> >>>>> +
> >>>>> +    properties:
> >>>>> +      compatible:
> >>>>> +        const: asus,ec-led
> >>>>> +
> >>>>> +    required:
> >>>>> +      - compatible
> >>>>> +
> >>>>> +  serio:
> >>>>
> >>>> All of these children are pointless - no resources. Drop all of them,
> >>>> it's btw explicitly documented rule in writing bindings.
> >>>>
> >>>
> >>> They are all needed to be able to disable them individually from the
> >>> device tree if needed.
> >>
> >> They should not be disabled from DT, so they are not valid here. The
> >> given EC for given device is fixed/static. Does not change.
> >>
> >
> > Have you considered a possibility that function may be
> > disabled/unrouted within the controller. By the vendor.
>
> And then it is implied by the compatible, so no need for any of that.
> Otherwise, if it is not specific per device, then specifying it for DTS
> for all devices would make no sense.
>

So you propose introduce a compatible for every single ec used in
transformers instead of simply disable unpopulated functions? And how
then battery and charger can reach monitored cell if they have no
dedicated node?

> Best regards,
> Krzysztof

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v2 3/9] dt-bindings: mfd: document ASUS Transformer EC
  2026-02-10 11:14             ` Svyatoslav Ryhel
@ 2026-02-10 11:24               ` Krzysztof Kozlowski
  2026-02-10 11:40                 ` Svyatoslav Ryhel
  0 siblings, 1 reply; 30+ messages in thread
From: Krzysztof Kozlowski @ 2026-02-10 11:24 UTC (permalink / raw)
  To: Svyatoslav Ryhel
  Cc: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Dmitry Torokhov, Pavel Machek, Arnd Bergmann, Greg Kroah-Hartman,
	Sebastian Reichel, Michał Mirosław, Ion Agorria,
	devicetree, linux-kernel, linux-input, linux-leds, linux-pm

On 10/02/2026 12:14, Svyatoslav Ryhel wrote:
> вт, 10 лют. 2026 р. о 13:04 Krzysztof Kozlowski <krzk@kernel.org> пише:
>>
>> On 10/02/2026 11:59, Svyatoslav Ryhel wrote:
>>>>>>> +  asus,clear-factory-mode:
>>>>>>> +    type: boolean
>>>>>>> +    description: clear Factory Mode bit in EC control register
>>>>>>
>>>>>> Why would this be a static/fixed property over lifecycle of all devices?
>>>>>>
>>>>>
>>>>> Specify pls.
>>>>
>>>> Provide rationale why we need to clear it every time, not once. Or any
>>>> other rationale why we would accept that property.
>>>>
>>>
>>> Cause it is done by original Asus code and Asus did not provide
>>> schematic or any data apart from downstream source regarding this EC.
>>
>> So that's a no. downstream code which is poor quality, not following DT
>> rules at all, is never an argument for a DT property.
>>
> 
> This property indicates that this controller on every reset restores

Implied by compatible then and you can drop the property.

> factory bit hence it must be cleared. Bit is write only and cannot be
> detected. EC remains in factory mode which blocks its functions.
> 
>>>
>>>>>
>>>>>>> +
>>>>>>> +  battery:
>>>>>>> +    type: object
>>>>>>> +    $ref: /schemas/power/supply/power-supply.yaml
>>>>>>> +    unevaluatedProperties: false
>>>>>>> +
>>>>>>> +    properties:
>>>>>>> +      compatible:
>>>>>>> +        const: asus,ec-battery
>>>>>>> +
>>>>>>> +    required:
>>>>>>> +      - compatible
>>>>>>> +
>>>>>>> +  charger:
>>>>>>> +    type: object
>>>>>>> +    $ref: /schemas/power/supply/power-supply.yaml
>>>>>>> +    additionalProperties: false
>>>>>>> +
>>>>>>> +    properties:
>>>>>>> +      compatible:
>>>>>>> +        const: asus,ec-charger
>>>>>>> +
>>>>>>> +      monitored-battery: true
>>>>>>> +
>>>>>>> +    required:
>>>>>>> +      - compatible
>>>>>>> +
>>>>>>> +  keyboard-ext:
>>>>>>> +    type: object
>>>>>>> +    description: top row of multimedia keys
>>>>>>> +    additionalProperties: false
>>>>>>> +
>>>>>>> +    properties:
>>>>>>> +      compatible:
>>>>>>> +        const: asus,ec-keys
>>>>>>> +
>>>>>>> +    required:
>>>>>>> +      - compatible
>>>>>>> +
>>>>>>> +  led:
>>>>>>> +    type: object
>>>>>>> +    additionalProperties: false
>>>>>>> +
>>>>>>> +    properties:
>>>>>>> +      compatible:
>>>>>>> +        const: asus,ec-led
>>>>>>> +
>>>>>>> +    required:
>>>>>>> +      - compatible
>>>>>>> +
>>>>>>> +  serio:
>>>>>>
>>>>>> All of these children are pointless - no resources. Drop all of them,
>>>>>> it's btw explicitly documented rule in writing bindings.
>>>>>>
>>>>>
>>>>> They are all needed to be able to disable them individually from the
>>>>> device tree if needed.
>>>>
>>>> They should not be disabled from DT, so they are not valid here. The
>>>> given EC for given device is fixed/static. Does not change.
>>>>
>>>
>>> Have you considered a possibility that function may be
>>> disabled/unrouted within the controller. By the vendor.
>>
>> And then it is implied by the compatible, so no need for any of that.
>> Otherwise, if it is not specific per device, then specifying it for DTS
>> for all devices would make no sense.
>>
> 
> So you propose introduce a compatible for every single ec used in
> transformers instead of simply disable unpopulated functions? And how
> then battery and charger can reach monitored cell if they have no
> dedicated node?

Just like for other bindings for nodes without resources, fold into
parent. This is already explained in writing bindings, so you could have
just read that. I will pass with answering more questions till you read
that doc.


Best regards,
Krzysztof

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v2 3/9] dt-bindings: mfd: document ASUS Transformer EC
  2026-02-10 11:24               ` Krzysztof Kozlowski
@ 2026-02-10 11:40                 ` Svyatoslav Ryhel
  2026-02-10 11:54                   ` Krzysztof Kozlowski
  0 siblings, 1 reply; 30+ messages in thread
From: Svyatoslav Ryhel @ 2026-02-10 11:40 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Dmitry Torokhov, Pavel Machek, Arnd Bergmann, Greg Kroah-Hartman,
	Sebastian Reichel, Michał Mirosław, Ion Agorria,
	devicetree, linux-kernel, linux-input, linux-leds, linux-pm

вт, 10 лют. 2026 р. о 13:24 Krzysztof Kozlowski <krzk@kernel.org> пише:
>
> On 10/02/2026 12:14, Svyatoslav Ryhel wrote:
> > вт, 10 лют. 2026 р. о 13:04 Krzysztof Kozlowski <krzk@kernel.org> пише:
> >>
> >> On 10/02/2026 11:59, Svyatoslav Ryhel wrote:
> >>>>>>> +  asus,clear-factory-mode:
> >>>>>>> +    type: boolean
> >>>>>>> +    description: clear Factory Mode bit in EC control register
> >>>>>>
> >>>>>> Why would this be a static/fixed property over lifecycle of all devices?
> >>>>>>
> >>>>>
> >>>>> Specify pls.
> >>>>
> >>>> Provide rationale why we need to clear it every time, not once. Or any
> >>>> other rationale why we would accept that property.
> >>>>
> >>>
> >>> Cause it is done by original Asus code and Asus did not provide
> >>> schematic or any data apart from downstream source regarding this EC.
> >>
> >> So that's a no. downstream code which is poor quality, not following DT
> >> rules at all, is never an argument for a DT property.
> >>
> >
> > This property indicates that this controller on every reset restores
>
> Implied by compatible then and you can drop the property.
>
> > factory bit hence it must be cleared. Bit is write only and cannot be
> > detected. EC remains in factory mode which blocks its functions.
> >
> >>>
> >>>>>
> >>>>>>> +
> >>>>>>> +  battery:
> >>>>>>> +    type: object
> >>>>>>> +    $ref: /schemas/power/supply/power-supply.yaml
> >>>>>>> +    unevaluatedProperties: false
> >>>>>>> +
> >>>>>>> +    properties:
> >>>>>>> +      compatible:
> >>>>>>> +        const: asus,ec-battery
> >>>>>>> +
> >>>>>>> +    required:
> >>>>>>> +      - compatible
> >>>>>>> +
> >>>>>>> +  charger:
> >>>>>>> +    type: object
> >>>>>>> +    $ref: /schemas/power/supply/power-supply.yaml
> >>>>>>> +    additionalProperties: false
> >>>>>>> +
> >>>>>>> +    properties:
> >>>>>>> +      compatible:
> >>>>>>> +        const: asus,ec-charger
> >>>>>>> +
> >>>>>>> +      monitored-battery: true
> >>>>>>> +
> >>>>>>> +    required:
> >>>>>>> +      - compatible
> >>>>>>> +
> >>>>>>> +  keyboard-ext:
> >>>>>>> +    type: object
> >>>>>>> +    description: top row of multimedia keys
> >>>>>>> +    additionalProperties: false
> >>>>>>> +
> >>>>>>> +    properties:
> >>>>>>> +      compatible:
> >>>>>>> +        const: asus,ec-keys
> >>>>>>> +
> >>>>>>> +    required:
> >>>>>>> +      - compatible
> >>>>>>> +
> >>>>>>> +  led:
> >>>>>>> +    type: object
> >>>>>>> +    additionalProperties: false
> >>>>>>> +
> >>>>>>> +    properties:
> >>>>>>> +      compatible:
> >>>>>>> +        const: asus,ec-led
> >>>>>>> +
> >>>>>>> +    required:
> >>>>>>> +      - compatible
> >>>>>>> +
> >>>>>>> +  serio:
> >>>>>>
> >>>>>> All of these children are pointless - no resources. Drop all of them,
> >>>>>> it's btw explicitly documented rule in writing bindings.
> >>>>>>
> >>>>>
> >>>>> They are all needed to be able to disable them individually from the
> >>>>> device tree if needed.
> >>>>
> >>>> They should not be disabled from DT, so they are not valid here. The
> >>>> given EC for given device is fixed/static. Does not change.
> >>>>
> >>>
> >>> Have you considered a possibility that function may be
> >>> disabled/unrouted within the controller. By the vendor.
> >>
> >> And then it is implied by the compatible, so no need for any of that.
> >> Otherwise, if it is not specific per device, then specifying it for DTS
> >> for all devices would make no sense.
> >>
> >
> > So you propose introduce a compatible for every single ec used in
> > transformers instead of simply disable unpopulated functions? And how
> > then battery and charger can reach monitored cell if they have no
> > dedicated node?
>
> Just like for other bindings for nodes without resources, fold into
> parent. This is already explained in writing bindings, so you could have
> just read that. I will pass with answering more questions till you read
> that doc.
>

Unfolding asus,ec-pad and asus,ec-dock will result in this list:

asus,tf101-dock-ec
asus,tf101g-dock-ec
asus,sl101-pad-ec
asus,tf201-pad-ec
asus,tf201-dock-ec
asus,tf300t-pad-ec
asus,tf300t-dock-ec
asus,tf300tg-pad-ec
asus,tf300tg-dock-ec
asus,tf300tl-pad-ec
asus,tf300tl-dock-ec
asus,tf600t-pad-ec
asus,tf700t-pad-ec
asus,tf700t-dock-ec
asus,tf701t-pad-ec
asus,p1801-t-pad-ec

with minor variations in populated cells. Is this acceptible?

>
> Best regards,
> Krzysztof

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v2 3/9] dt-bindings: mfd: document ASUS Transformer EC
  2026-02-10 11:40                 ` Svyatoslav Ryhel
@ 2026-02-10 11:54                   ` Krzysztof Kozlowski
  2026-02-10 12:48                     ` Krzysztof Kozlowski
  0 siblings, 1 reply; 30+ messages in thread
From: Krzysztof Kozlowski @ 2026-02-10 11:54 UTC (permalink / raw)
  To: Svyatoslav Ryhel
  Cc: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Dmitry Torokhov, Pavel Machek, Arnd Bergmann, Greg Kroah-Hartman,
	Sebastian Reichel, Michał Mirosław, Ion Agorria,
	devicetree, linux-kernel, linux-input, linux-leds, linux-pm

On 10/02/2026 12:40, Svyatoslav Ryhel wrote:
>>>
>>> So you propose introduce a compatible for every single ec used in
>>> transformers instead of simply disable unpopulated functions? And how
>>> then battery and charger can reach monitored cell if they have no
>>> dedicated node?
>>
>> Just like for other bindings for nodes without resources, fold into
>> parent. This is already explained in writing bindings, so you could have
>> just read that. I will pass with answering more questions till you read
>> that doc.
>>
> 
> Unfolding asus,ec-pad and asus,ec-dock will result in this list:
> 
> asus,tf101-dock-ec
> asus,tf101g-dock-ec
> asus,sl101-pad-ec
> asus,tf201-pad-ec
> asus,tf201-dock-ec
> asus,tf300t-pad-ec
> asus,tf300t-dock-ec
> asus,tf300tg-pad-ec
> asus,tf300tg-dock-ec
> asus,tf300tl-pad-ec
> asus,tf300tl-dock-ec
> asus,tf600t-pad-ec
> asus,tf700t-pad-ec
> asus,tf700t-dock-ec
> asus,tf701t-pad-ec
> asus,p1801-t-pad-ec
> 
> with minor variations in populated cells. Is this acceptible?


Yes, this looks correct.

Best regards,
Krzysztof

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v2 3/9] dt-bindings: mfd: document ASUS Transformer EC
  2026-02-10 11:54                   ` Krzysztof Kozlowski
@ 2026-02-10 12:48                     ` Krzysztof Kozlowski
  2026-02-11 10:48                       ` Svyatoslav Ryhel
  0 siblings, 1 reply; 30+ messages in thread
From: Krzysztof Kozlowski @ 2026-02-10 12:48 UTC (permalink / raw)
  To: Svyatoslav Ryhel
  Cc: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Dmitry Torokhov, Pavel Machek, Arnd Bergmann, Greg Kroah-Hartman,
	Sebastian Reichel, Michał Mirosław, Ion Agorria,
	devicetree, linux-kernel, linux-input, linux-leds, linux-pm

On 10/02/2026 12:54, Krzysztof Kozlowski wrote:
> On 10/02/2026 12:40, Svyatoslav Ryhel wrote:
>>>>
>>>> So you propose introduce a compatible for every single ec used in
>>>> transformers instead of simply disable unpopulated functions? And how
>>>> then battery and charger can reach monitored cell if they have no
>>>> dedicated node?
>>>
>>> Just like for other bindings for nodes without resources, fold into
>>> parent. This is already explained in writing bindings, so you could have
>>> just read that. I will pass with answering more questions till you read
>>> that doc.
>>>
>>
>> Unfolding asus,ec-pad and asus,ec-dock will result in this list:
>>
>> asus,tf101-dock-ec
>> asus,tf101g-dock-ec
>> asus,sl101-pad-ec
>> asus,tf201-pad-ec
>> asus,tf201-dock-ec
>> asus,tf300t-pad-ec
>> asus,tf300t-dock-ec
>> asus,tf300tg-pad-ec
>> asus,tf300tg-dock-ec
>> asus,tf300tl-pad-ec
>> asus,tf300tl-dock-ec
>> asus,tf600t-pad-ec
>> asus,tf700t-pad-ec
>> asus,tf700t-dock-ec
>> asus,tf701t-pad-ec
>> asus,p1801-t-pad-ec
>>
>> with minor variations in populated cells. Is this acceptible?
> 
> 
> Yes, this looks correct.

Update: with fallback-expressed compatibility when same interface and/or
superset of features.

Best regards,
Krzysztof

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v2 3/9] dt-bindings: mfd: document ASUS Transformer EC
  2026-02-10 12:48                     ` Krzysztof Kozlowski
@ 2026-02-11 10:48                       ` Svyatoslav Ryhel
  0 siblings, 0 replies; 30+ messages in thread
From: Svyatoslav Ryhel @ 2026-02-11 10:48 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Dmitry Torokhov, Pavel Machek, Arnd Bergmann, Greg Kroah-Hartman,
	Sebastian Reichel, Michał Mirosław, Ion Agorria,
	devicetree, linux-kernel, linux-input, linux-leds, linux-pm

вт, 10 лют. 2026 р. о 14:48 Krzysztof Kozlowski <krzk@kernel.org> пише:
>
> On 10/02/2026 12:54, Krzysztof Kozlowski wrote:
> > On 10/02/2026 12:40, Svyatoslav Ryhel wrote:
> >>>>
> >>>> So you propose introduce a compatible for every single ec used in
> >>>> transformers instead of simply disable unpopulated functions? And how
> >>>> then battery and charger can reach monitored cell if they have no
> >>>> dedicated node?
> >>>
> >>> Just like for other bindings for nodes without resources, fold into
> >>> parent. This is already explained in writing bindings, so you could have
> >>> just read that. I will pass with answering more questions till you read
> >>> that doc.
> >>>
> >>
> >> Unfolding asus,ec-pad and asus,ec-dock will result in this list:
> >>
> >> asus,tf101-dock-ec
> >> asus,tf101g-dock-ec
> >> asus,sl101-pad-ec
> >> asus,tf201-pad-ec
> >> asus,tf201-dock-ec
> >> asus,tf300t-pad-ec
> >> asus,tf300t-dock-ec
> >> asus,tf300tg-pad-ec
> >> asus,tf300tg-dock-ec
> >> asus,tf300tl-pad-ec
> >> asus,tf300tl-dock-ec
> >> asus,tf600t-pad-ec
> >> asus,tf700t-pad-ec
> >> asus,tf700t-dock-ec
> >> asus,tf701t-pad-ec
> >> asus,p1801-t-pad-ec
> >>
> >> with minor variations in populated cells. Is this acceptible?
> >
> >
> > Yes, this looks correct.
>
> Update: with fallback-expressed compatibility when same interface and/or
> superset of features.
>

I am removing separate DockRAM and merging it into this schema hence,
it should look like this

  reg:
    description:
      The ASUS Transformer EC has a main I2C address and an associated
      DockRAM device, which provides power-related functions for the
      embedded controller. Both addresses are required for operation.
    minItems: 2

  reg-names:
    items:
      - const: ec
      - const: dockram

How should I organize amount of regs? Would this example be acceptable
with minItems: 2 since EC requires both to work or should I set is as
items list or minItems: 2 maxItems: 2? Thank you.

> Best regards,
> Krzysztof

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v2 4/9] mfd: Add driver for Asus Transformer embedded controller
  2026-02-09 10:44 ` [PATCH v2 4/9] mfd: Add driver for Asus Transformer embedded controller Svyatoslav Ryhel
@ 2026-03-06  9:18   ` Lee Jones
  2026-03-06 12:36     ` Svyatoslav Ryhel
  0 siblings, 1 reply; 30+ messages in thread
From: Lee Jones @ 2026-03-06  9:18 UTC (permalink / raw)
  To: Svyatoslav Ryhel
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Dmitry Torokhov,
	Pavel Machek, Arnd Bergmann, Greg Kroah-Hartman,
	Sebastian Reichel, Michał Mirosław, Ion Agorria,
	devicetree, linux-kernel, linux-input, linux-leds, linux-pm

On Mon, 09 Feb 2026, Svyatoslav Ryhel wrote:

> From: Michał Mirosław <mirq-linux@rere.qmqm.pl>
> 
> Support Nuvoton NPCE795-based ECs as used in Asus Transformer TF201,
> TF300T, TF300TG, TF300TL and TF700T pad and dock, as well as TF101 dock
> and TF600T, P1801-T and TF701T pad. This is a glue driver handling
> detection and common operations for EC's functions.
> 
> Co-developed-by: Svyatoslav Ryhel <clamor95@gmail.com>
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>
> ---
>  drivers/mfd/Kconfig         |  15 ++
>  drivers/mfd/Makefile        |   1 +
>  drivers/mfd/asus-ec.c       | 467 ++++++++++++++++++++++++++++++++++++
>  include/linux/mfd/asus-ec.h | 138 +++++++++++
>  4 files changed, 621 insertions(+)
>  create mode 100644 drivers/mfd/asus-ec.c
> 
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index 7192c9d1d268..312fd15eec6a 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -137,6 +137,21 @@ config MFD_AAT2870_CORE
>  	  additional drivers must be enabled in order to use the
>  	  functionality of the device.
>  
> +config MFD_ASUSEC

MFD_ASUS_EC

> +	tristate "ASUS Transformer's embedded controller"
> +	depends on I2C && OF
> +	select SYSFS
> +	select ASUS_DOCKRAM
> +	help
> +	  Support ECs found in ASUS Transformer's Pad and Mobile Dock.
> +
> +	  This provides shared glue for functional part drivers:
> +	    asus-ec-kbc, asus-ec-keys, leds-asus-ec, asus-ec-battery
> +	    and asus-ec-charger.

Why the additional tabbing?  What example did you take that from?

> +	  This driver can also be built as a module. If so, the module
> +	  will be called asus-ec.
> +
>  config MFD_AT91_USART
>  	tristate "AT91 USART Driver"
>  	select MFD_CORE
> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> index e75e8045c28a..b676922601ba 100644
> --- a/drivers/mfd/Makefile
> +++ b/drivers/mfd/Makefile
> @@ -10,6 +10,7 @@ obj-$(CONFIG_MFD_88PM805)	+= 88pm805.o 88pm80x.o
>  obj-$(CONFIG_MFD_88PM886_PMIC)	+= 88pm886.o
>  obj-$(CONFIG_MFD_ACT8945A)	+= act8945a.o
>  obj-$(CONFIG_MFD_SM501)		+= sm501.o
> +obj-$(CONFIG_MFD_ASUSEC)	+= asus-ec.o
>  obj-$(CONFIG_ARCH_BCM2835)	+= bcm2835-pm.o
>  obj-$(CONFIG_MFD_BCM590XX)	+= bcm590xx.o
>  obj-$(CONFIG_MFD_BD9571MWV)	+= bd9571mwv.o
> diff --git a/drivers/mfd/asus-ec.c b/drivers/mfd/asus-ec.c
> new file mode 100644
> index 000000000000..e151c1506aa2
> --- /dev/null
> +++ b/drivers/mfd/asus-ec.c
> @@ -0,0 +1,467 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * ASUS EC driver

Copyright?  Author?

> + */
> +
> +#include <linux/array_size.h>
> +#include <linux/debugfs.h>
> +#include <linux/delay.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/device.h>
> +#include <linux/err.h>
> +#include <linux/i2c.h>
> +#include <linux/interrupt.h>
> +#include <linux/mfd/asus-ec.h>
> +#include <linux/mfd/core.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/property.h>
> +#include <linux/string.h>
> +#include <linux/sysfs.h>
> +#include <linux/types.h>

Alphabetical.

Are you sure all of these are in use?

> +#define ASUSEC_RSP_BUFFER_SIZE		8
> +
> +struct asus_ec_chip_data {
> +	const char *name;
> +	const struct mfd_cell *mfd_devices;
> +	unsigned int num_devices;
> +};
> +
> +struct asus_ec_data {
> +	struct asusec_info info;
> +	struct mutex ecreq_lock; /* prevent simultaneous access */

We know what mutexes do.

If you're going to provide a comment, state WHAT is is protecting.

Or just omit the comment altogether.

> +	struct gpio_desc *ecreq;
> +	struct i2c_client *self;

"client"

Why are you storing this?

> +	const struct asus_ec_chip_data *data;
> +	u8 ec_data[DOCKRAM_ENTRY_BUFSIZE];
> +	bool clr_fmode;
> +	bool logging_disabled;
> +};
> +
> +#define to_ec_data(ec) \
> +	container_of(ec, struct asus_ec_data, info)
> +
> +static void asus_ec_remove_notifier(struct device *dev, void *res)
> +{
> +	struct asusec_info *ec = dev_get_drvdata(dev->parent);
> +	struct notifier_block **nb = res;
> +
> +	blocking_notifier_chain_unregister(&ec->notify_list, *nb);
> +}
> +
> +/**
> + * devm_asus_ec_register_notifier - Managed registration of notifier to an
> + *				    ASUS EC blocking notifier chain.
> + * @pdev: Device requesting the notifier (used for resource management).
> + * @nb: Notifier block to be registered.
> + *
> + * Register a notifier to the ASUS EC blocking notifier chain. The notifier
> + * will be automatically unregistered when the requesting device is detached.
> + *
> + * Return: 0 on success or a negative error code on failure.
> + */
> +int devm_asus_ec_register_notifier(struct platform_device *pdev,
> +				   struct notifier_block *nb)
> +{
> +	struct asusec_info *ec = dev_get_drvdata(pdev->dev.parent);
> +	struct notifier_block **res;
> +	int ret;
> +
> +	res = devres_alloc(asus_ec_remove_notifier, sizeof(*res), GFP_KERNEL);
> +	if (!res)
> +		return -ENOMEM;
> +
> +	*res = nb;
> +	ret = blocking_notifier_chain_register(&ec->notify_list, nb);
> +	if (ret) {
> +		devres_free(res);
> +		return ret;
> +	}
> +
> +	devres_add(&pdev->dev, res);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(devm_asus_ec_register_notifier);
> +
> +static int asus_ec_signal_request(const struct asusec_info *ec)
> +{
> +	struct asus_ec_data *priv = to_ec_data(ec);
> +
> +	guard(mutex)(&priv->ecreq_lock);
> +
> +	dev_dbg(&priv->self->dev, "EC request\n");
> +
> +	gpiod_set_value_cansleep(priv->ecreq, 1);
> +	msleep(50);
> +
> +	gpiod_set_value_cansleep(priv->ecreq, 0);
> +	msleep(200);
> +
> +	return 0;
> +}
> +
> +static int asus_ec_write(struct asus_ec_data *priv, u16 data)
> +{
> +	int ret = i2c_smbus_write_word_data(priv->self, ASUSEC_WRITE_BUF, data);
> +
> +	dev_dbg(&priv->self->dev, "EC write: %04x, ret = %d\n", data, ret);
> +	return ret;
> +}
> +
> +static int asus_ec_read(struct asus_ec_data *priv, bool in_irq)
> +{
> +	int ret = i2c_smbus_read_i2c_block_data(priv->self, ASUSEC_READ_BUF,
> +						sizeof(priv->ec_data),
> +						priv->ec_data);
> +
> +	dev_dbg(&priv->self->dev, "EC read: %*ph, ret = %d%s\n",
> +		sizeof(priv->ec_data), priv->ec_data,
> +		ret, in_irq ? "; in irq" : "");
> +
> +	return ret;
> +}

Remove both of these functions and use the i2c_smbus_*() API instead.

> +
> +/**
> + * asus_ec_i2c_command - Send a 16-bit command to the ASUS EC.
> + * @ec: Pointer to the shared ASUS EC structure.
> + * @data: The 16-bit command (word) to be sent.
> + *
> + * Return: 0 on success or a negative error code on failure.
> + */
> +int asus_ec_i2c_command(const struct asusec_info *ec, u16 data)
> +{
> +	return asus_ec_write(to_ec_data(ec), data);
> +}
> +EXPORT_SYMBOL_GPL(asus_ec_i2c_command);

Why is this needed?  Why not share 'client' with the leave drivers and
let them make their own calls to i2c_smbus_write_word_data()?

> +static void asus_ec_clear_buffer(struct asus_ec_data *priv)
> +{
> +	int retry = ASUSEC_RSP_BUFFER_SIZE;
> +
> +	while (retry--) {

Why is the amount of retries related to the buffer size?

> +		if (asus_ec_read(priv, false) < 0)
> +			continue;
> +
> +		if (priv->ec_data[1] & ASUSEC_OBF_MASK)

No magic numbers.  Define the 1.

> +			continue;
> +
> +		break;
> +	}
> +}
> +
> +static int asus_ec_log_info(struct asus_ec_data *priv, unsigned int reg,
> +			    const char *name, char **out)
> +{
> +	char buf[DOCKRAM_ENTRY_BUFSIZE];
> +	int ret;
> +
> +	ret = asus_dockram_read(priv->info.dockram, reg, buf);
> +	if (ret < 0)
> +		return ret;
> +
> +	if (!priv->logging_disabled)
> +		dev_info(&priv->self->dev, "%-14s: %.*s\n", name, buf[0], buf + 1);
> +
> +	if (out)
> +		*out = kstrndup(buf + 1, buf[0], GFP_KERNEL);
> +
> +	return 0;
> +}

The driver is written now.  You can remove this over-engineered debugging
facility.

> +static int asus_ec_reset(struct asus_ec_data *priv)
> +{
> +	int retry, ret;
> +
> +	for (retry = 0; retry < 3; retry++) {

Why 3?

Why are you using for() here and while() above?

> +		ret = asus_ec_write(priv, 0);

Add a comment to explain how this works.

Or, better still, define the value.

> +		if (!ret)
> +			return 0;
> +
> +		msleep(300);

Why 300?

> +	}
> +
> +	return ret;
> +}
> +
> +static int asus_ec_magic_debug(struct asus_ec_data *priv)

What does this do?  More comments throughout please.

> +{
> +	u64 flag;
> +	int ret;
> +
> +	ret = asus_ec_get_ctl(&priv->info, &flag);
> +	if (ret < 0)
> +		return ret;
> +
> +	flag &= ASUSEC_CTL_SUSB_MODE;
> +	dev_info(&priv->self->dev, "EC FW behaviour: %s\n",
> +		 flag ? "susb on when receive ec_req" : "susb on when system wakeup");
> +
> +	return 0;
> +}
> +
> +static int asus_ec_set_factory_mode(struct asus_ec_data *priv, bool on)
> +{
> +	dev_info(&priv->self->dev, "Entering %s mode.\n", on ? "factory" : "normal");

Remove all of the debugging prints now.

> +	return asus_ec_update_ctl(&priv->info, ASUSEC_CTL_FACTORY_MODE,
> +				  on ? ASUSEC_CTL_FACTORY_MODE : 0);
> +}
> +
> +static void asus_ec_handle_smi(struct asus_ec_data *priv, unsigned int code);

No forward declarations.

> +static irqreturn_t asus_ec_interrupt(int irq, void *dev_id)
> +{
> +	struct asus_ec_data *priv = dev_id;
> +	unsigned long notify_action;
> +	int ret;
> +
> +	ret = asus_ec_read(priv, true);
> +	if (ret <= 0 || !(priv->ec_data[1] & ASUSEC_OBF_MASK))
> +		return IRQ_NONE;
> +
> +	notify_action = priv->ec_data[1];
> +	if (notify_action & ASUSEC_SMI_MASK) {
> +		unsigned int code = priv->ec_data[2];
> +
> +		asus_ec_handle_smi(priv, code);
> +
> +		notify_action |= code << 8;
> +		dev_dbg(&priv->self->dev, "SMI code: 0x%02x\n", code);
> +	}
> +
> +	blocking_notifier_call_chain(&priv->info.notify_list,
> +				     notify_action, priv->ec_data);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int asus_ec_detect(struct asus_ec_data *priv)
> +{
> +	char *model = NULL;
> +	int ret;
> +
> +	ret = asus_ec_reset(priv);
> +	if (ret)
> +		goto err_exit;
> +
> +	asus_ec_clear_buffer(priv);
> +
> +	ret = asus_ec_log_info(priv, ASUSEC_DOCKRAM_INFO_MODEL, "model", &model);
> +	if (ret)
> +		goto err_exit;
> +
> +	ret = asus_ec_log_info(priv, ASUSEC_DOCKRAM_INFO_FW, "FW version", NULL);
> +	if (ret)
> +		goto err_exit;
> +
> +	ret = asus_ec_log_info(priv, ASUSEC_DOCKRAM_INFO_CFGFMT, "Config format", NULL);
> +	if (ret)
> +		goto err_exit;
> +
> +	ret = asus_ec_log_info(priv, ASUSEC_DOCKRAM_INFO_HW, "HW version", NULL);
> +	if (ret)
> +		goto err_exit;
> +
> +	priv->logging_disabled = true;
> +
> +	ret = asus_ec_magic_debug(priv);
> +	if (ret)
> +		goto err_exit;
> +
> +	priv->info.model = model;
> +	priv->info.name = priv->data->name;
> +
> +	if (priv->clr_fmode)
> +		asus_ec_set_factory_mode(priv, false);
> +
> +err_exit:
> +	if (ret)
> +		dev_err(&priv->self->dev, "failed to access EC: %d\n", ret);
> +
> +	return ret;
> +}
> +
> +static void asus_ec_handle_smi(struct asus_ec_data *priv, unsigned int code)
> +{
> +	dev_dbg(&priv->self->dev, "SMI interrupt: 0x%02x\n", code);
> +
> +	switch (code) {
> +	case ASUSEC_SMI_HANDSHAKE:
> +	case ASUSEC_SMI_RESET:
> +		asus_ec_detect(priv);
> +		break;
> +	}
> +}
> +
> +static int ec_request_set(void *ec, u64 val)
> +{
> +	if (val)
> +		asus_ec_signal_request(ec);
> +
> +	return 0;
> +}
> +
> +DEFINE_DEBUGFS_ATTRIBUTE(ec_request_fops, NULL, ec_request_set, "%llu\n");
> +
> +static int ec_irq_set(void *ec, u64 val)
> +{
> +	struct asus_ec_data *priv = to_ec_data(ec);
> +
> +	if (val)
> +		irq_wake_thread(priv->self->irq, priv);
> +
> +	return 0;
> +}
> +
> +DEFINE_DEBUGFS_ATTRIBUTE(ec_irq_fops, NULL, ec_irq_set, "%llu\n");

Document these.

> +static void asus_ec_debugfs_remove(void *debugfs_root)
> +{
> +	debugfs_remove_recursive(debugfs_root);
> +}
> +
> +static void devm_asus_ec_debugfs_init(struct device *dev)
> +{
> +	struct asusec_info *ec = dev_get_drvdata(dev);
> +	struct asus_ec_data *priv = to_ec_data(ec);
> +	struct dentry *debugfs_root;
> +	char *name = devm_kasprintf(dev, GFP_KERNEL, "asus-ec-%s",
> +				    priv->data->name);
> +
> +	debugfs_root = debugfs_create_dir(name, NULL);
> +
> +	debugfs_create_file("ec_irq", 0200, debugfs_root, ec, &ec_irq_fops);
> +	debugfs_create_file("ec_request", 0200, debugfs_root, ec, &ec_request_fops);
> +
> +	asus_dockram_debugfs_init(priv->info.dockram, debugfs_root);
> +
> +	devm_add_action_or_reset(dev, asus_ec_debugfs_remove, debugfs_root);
> +}
> +
> +static int asus_ec_probe(struct i2c_client *client)
> +{
> +	struct device *dev = &client->dev;
> +	struct asus_ec_data *priv;

Call this "ddata".

> +	int ret;
> +
> +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	priv->data = device_get_match_data(dev);
> +	if (!priv->data)
> +		return -ENODEV;
> +
> +	i2c_set_clientdata(client, priv);
> +	priv->self = client;
> +
> +	priv->info.dockram = devm_asus_dockram_get(dev);
> +	if (IS_ERR(priv->info.dockram))
> +		return dev_err_probe(dev, PTR_ERR(priv->info.dockram),
> +				     "failed to get dockram\n");
> +
> +	priv->ecreq = devm_gpiod_get(dev, "request", GPIOD_OUT_LOW);
> +	if (IS_ERR(priv->ecreq))
> +		return dev_err_probe(dev, PTR_ERR(priv->ecreq),
> +				     "failed to get request GPIO\n");
> +
> +	BLOCKING_INIT_NOTIFIER_HEAD(&priv->info.notify_list);
> +	mutex_init(&priv->ecreq_lock);
> +
> +	priv->clr_fmode = device_property_read_bool(dev, "asus,clear-factory-mode");
> +
> +	asus_ec_signal_request(&priv->info);
> +
> +	ret = asus_ec_detect(priv);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "failed to detect EC version\n");
> +
> +	ret = devm_request_threaded_irq(dev, client->irq, NULL,
> +					&asus_ec_interrupt,
> +					IRQF_ONESHOT | IRQF_SHARED,
> +					client->name, priv);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "failed to register IRQ\n");
> +
> +	/* Parent I2C controller uses DMA, ASUS EC and child devices do not */
> +	client->dev.coherent_dma_mask = 0;
> +	client->dev.dma_mask = &client->dev.coherent_dma_mask;
> +
> +	devm_asus_ec_debugfs_init(dev);
> +
> +	return devm_mfd_add_devices(dev, 0, priv->data->mfd_devices,
> +				    priv->data->num_devices, NULL, 0, NULL);
> +}
> +
> +static const struct mfd_cell asus_ec_pad_mfd_devices[] = {
> +	{
> +		.name = "asus-ec-battery",
> +		.id = 0,
> +		.of_compatible = "asus,ec-battery",
> +	}, {
> +		.name = "asus-ec-charger",
> +		.id = 0,
> +		.of_compatible = "asus,ec-charger",
> +	}, {
> +		.name = "asus-ec-led",
> +		.id = 0,
> +		.of_compatible = "asus,ec-led",
> +	},
> +};
> +
> +static const struct mfd_cell asus_ec_dock_mfd_devices[] = {
> +	{
> +		.name = "asus-ec-battery",
> +		.id = 1,
> +		.of_compatible = "asus,ec-battery",
> +	}, {
> +		.name = "asus-ec-charger",
> +		.id = 1,
> +		.of_compatible = "asus,ec-charger",
> +	}, {
> +		.name = "asus-ec-led",
> +		.id = 1,
> +		.of_compatible = "asus,ec-led",
> +	}, {
> +		.name = "asus-ec-keys",
> +		.of_compatible = "asus,ec-keys",
> +	}, {
> +		.name = "asus-ec-kbc",
> +		.of_compatible = "asus,ec-kbc",
> +	},
> +};
> +
> +static const struct asus_ec_chip_data asus_ec_pad_data = {
> +	.name = "pad",
> +	.mfd_devices = asus_ec_pad_mfd_devices,
> +	.num_devices = ARRAY_SIZE(asus_ec_pad_mfd_devices),
> +};
> +
> +static const struct asus_ec_chip_data asus_ec_dock_data = {
> +	.name = "dock",
> +	.mfd_devices = asus_ec_dock_mfd_devices,
> +	.num_devices = ARRAY_SIZE(asus_ec_dock_mfd_devices),
> +};
> +
> +static const struct of_device_id asus_ec_match[] = {
> +	{ .compatible = "asus,ec-pad", .data = &asus_ec_pad_data },

Passing MFD data through a different registration mechanism is not
allowed.  Use identifiers to match in instead.

git grep "\.data =.*void" -- drivers/mfd

> +	{ .compatible = "asus,ec-dock", .data = &asus_ec_dock_data },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, asus_ec_match);
> +
> +static struct i2c_driver asus_ec_driver = {
> +	.driver	= {
> +		.name = "asus-ec",
> +		.of_match_table = asus_ec_match,
> +	},
> +	.probe = asus_ec_probe,
> +};
> +module_i2c_driver(asus_ec_driver);
> +
> +MODULE_AUTHOR("Michał Mirosław <mirq-linux@rere.qmqm.pl>");
> +MODULE_AUTHOR("Svyatoslav Ryhel <clamor95@gmail.com>");
> +MODULE_DESCRIPTION("ASUS Transformer's EC driver");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/mfd/asus-ec.h b/include/linux/mfd/asus-ec.h
> index 6a36313b9ebd..6a06b125ba30 100644
> --- a/include/linux/mfd/asus-ec.h
> +++ b/include/linux/mfd/asus-ec.h
> @@ -2,16 +2,78 @@
>  #ifndef __MISC_ASUS_EC_H
>  #define __MISC_ASUS_EC_H
>  
> +#include <linux/notifier.h>
> +#include <linux/platform_device.h>
> +#include <linux/workqueue.h>
> +
>  struct i2c_client;
>  
> +struct asusec_info {
> +	const char *model;
> +	const char *name;
> +	struct i2c_client *dockram;
> +	struct workqueue_struct *wq;
> +	struct blocking_notifier_head notify_list;
> +};
> +
>  #define DOCKRAM_ENTRIES			0x100
>  #define DOCKRAM_ENTRY_SIZE		32
>  #define DOCKRAM_ENTRY_BUFSIZE		(DOCKRAM_ENTRY_SIZE + 1)
>  
> +/* interrupt sources */
> +#define ASUSEC_OBF_MASK			BIT(0)
> +#define ASUSEC_KEY_MASK			BIT(2)
> +#define ASUSEC_KBC_MASK			BIT(3)
> +#define ASUSEC_AUX_MASK			BIT(5)
> +#define ASUSEC_SCI_MASK			BIT(6)
> +#define ASUSEC_SMI_MASK			BIT(7)
> +
> +/* SMI notification codes */
> +#define ASUSEC_SMI_POWER_NOTIFY		0x31	/* [un]plugging USB cable */
> +#define ASUSEC_SMI_HANDSHAKE		0x50	/* response to ec_req edge */
> +#define ASUSEC_SMI_WAKE			0x53
> +#define ASUSEC_SMI_RESET		0x5f
> +#define ASUSEC_SMI_ADAPTER_EVENT	0x60	/* [un]plugging charger to dock */
> +#define ASUSEC_SMI_BACKLIGHT_ON		0x63
> +#define ASUSEC_SMI_AUDIO_DOCK_IN	0x70
> +
> +#define ASUSEC_SMI_ACTION(code)		(ASUSEC_SMI_MASK | ASUSEC_OBF_MASK | \
> +					(ASUSEC_SMI_##code << 8))
> +
>  /* control register [0x0A] layout */
>  #define ASUSEC_CTL_SIZE			8
>  
> +/*
> + * EC reports power from 40-pin connector in the LSB of the control
> + * register.  The following values have been observed (xor 0x02):
> + *
> + * PAD-ec no-plug  0x40 / PAD-ec DOCK     0x20 / DOCK-ec no-plug 0x40
> + * PAD-ec AC       0x25 / PAD-ec DOCK+AC  0x24 / DOCK-ec AC      0x25
> + * PAD-ec USB      0x45 / PAD-ec DOCK+USB 0x24 / DOCK-ec USB     0x41
> + */
> +
> +#define ASUSEC_CTL_DIRECT_POWER_SOURCE	BIT_ULL(0)
> +#define ASUSEC_STAT_CHARGING		BIT_ULL(2)
> +#define ASUSEC_CTL_FULL_POWER_SOURCE	BIT_ULL(5)
> +#define ASUSEC_CTL_SUSB_MODE		BIT_ULL(11)
> +#define ASUSEC_CMD_SUSPEND_S3		BIT_ULL(41)
> +#define ASUSEC_CTL_TEST_DISCHARGE	BIT_ULL(43)
> +#define ASUSEC_CMD_SUSPEND_INHIBIT	BIT_ULL(45)
> +#define ASUSEC_CTL_FACTORY_MODE		BIT_ULL(46)
> +#define ASUSEC_CTL_KEEP_AWAKE		BIT_ULL(47)
> +#define ASUSEC_CTL_USB_CHARGE		BIT_ULL(50)
> +#define ASUSEC_CMD_SWITCH_HDMI		BIT_ULL(70)
> +#define ASUSEC_CMD_WIN_SHUTDOWN		BIT_ULL(76)
> +
> +#define ASUSEC_DOCKRAM_INFO_MODEL	0x01
> +#define ASUSEC_DOCKRAM_INFO_FW		0x02
> +#define ASUSEC_DOCKRAM_INFO_CFGFMT	0x03
> +#define ASUSEC_DOCKRAM_INFO_HW		0x04
>  #define ASUSEC_DOCKRAM_CONTROL		0x0a
> +#define ASUSEC_DOCKRAM_BATT_CTL		0x14
> +
> +#define ASUSEC_WRITE_BUF		0x64
> +#define ASUSEC_READ_BUF			0x6A
>  
>  /* dockram comm */
>  int asus_dockram_read(struct i2c_client *client, int reg, char *buf);
> @@ -21,4 +83,80 @@ int asus_dockram_access_ctl(struct i2c_client *client,
>  struct i2c_client *devm_asus_dockram_get(struct device *parent);
>  void asus_dockram_debugfs_init(struct i2c_client *client,
>  			       struct dentry *debugfs_root);
> +
> +/* EC public API */
> +
> +/**
> + * cell_to_ec - Request the shared ASUS EC structure via a subdevice's pdev.
> + * @pdev: EC subdevice pdev requesting access to the shared ASUS EC structure.
> + *
> + * Returns a pointer to the asusec_info structure.
> + */
> +static inline struct asusec_info *cell_to_ec(struct platform_device *pdev)
> +{
> +	return dev_get_drvdata(pdev->dev.parent);
> +}
> +
> +/**
> + * asus_ec_get_ctl - Read from the DockRAM control register.
> + * @ec:  Pointer to the shared ASUS EC structure.
> + * @out: Pointer to the variable where the register value will be stored.
> + *
> + * Performs a control register read and stores the value in @out.
> + *
> + * Return: 0 on success, or a negative errno code on failure.
> + */
> +static inline int asus_ec_get_ctl(const struct asusec_info *ec, u64 *out)
> +{
> +	return asus_dockram_access_ctl(ec->dockram, out, 0, 0);
> +}
> +
> +/**
> + * asus_ec_update_ctl - Update the DockRAM control register.
> + * @ec:   Pointer to the shared ASUS EC structure.
> + * @mask: Bitmask of bits to be cleared.
> + * @xor:  Bitmask of bits to be toggled or set (via XOR).
> + *
> + * Performs a read-modify-write update on the control register using
> + * the provided @mask and @xor values.
> + *
> + * Return: 0 on success, or a negative errno code on failure.
> + */
> +static inline int asus_ec_update_ctl(const struct asusec_info *ec,
> +				     u64 mask, u64 xor)
> +{
> +	return asus_dockram_access_ctl(ec->dockram, NULL, mask, xor);
> +}
> +
> +/**
> + * asus_ec_set_ctl_bits - Sets bits of the DockRAM control register.
> + * @ec:   Pointer to the shared ASUS EC structure.
> + * @mask: Bitmask of bits to be set.
> + *
> + * Sets bits of the control register using the provided @mask value.
> + *
> + * Return: 0 on success, or a negative errno code on failure.
> + */
> +static inline int asus_ec_set_ctl_bits(const struct asusec_info *ec, u64 mask)
> +{
> +	return asus_dockram_access_ctl(ec->dockram, NULL, mask, mask);
> +}
> +
> +/**
> + * asus_ec_clear_ctl_bits - Clears bits of the DockRAM control register.
> + * @ec:   Pointer to the shared ASUS EC structure.
> + * @mask: Bitmask of bits to be cleared.
> + *
> + * Clears bits of the control register using the provided @mask value.
> + *
> + * Return: 0 on success, or a negative errno code on failure.
> + */
> +static inline int asus_ec_clear_ctl_bits(const struct asusec_info *ec, u64 mask)
> +{
> +	return asus_dockram_access_ctl(ec->dockram, NULL, mask, 0);
> +}

This is all abstraction for he sake of abstraction.

> +int asus_ec_i2c_command(const struct asusec_info *ec, u16 data);
> +int devm_asus_ec_register_notifier(struct platform_device *dev,
> +				   struct notifier_block *nb);
>  #endif /* __MISC_ASUS_EC_H */
> -- 
> 2.51.0
> 
> 

-- 
Lee Jones [李琼斯]

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v2 7/9] leds: Add driver for Asus Transformer LEDs
  2026-02-09 10:44 ` [PATCH v2 7/9] leds: Add driver for Asus Transformer LEDs Svyatoslav Ryhel
@ 2026-03-06 10:04   ` Lee Jones
  2026-03-06 12:45     ` Svyatoslav Ryhel
  0 siblings, 1 reply; 30+ messages in thread
From: Lee Jones @ 2026-03-06 10:04 UTC (permalink / raw)
  To: Svyatoslav Ryhel
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Dmitry Torokhov,
	Pavel Machek, Arnd Bergmann, Greg Kroah-Hartman,
	Sebastian Reichel, Michał Mirosław, Ion Agorria,
	devicetree, linux-kernel, linux-input, linux-leds, linux-pm

On Mon, 09 Feb 2026, Svyatoslav Ryhel wrote:

> From: Michał Mirosław <mirq-linux@rere.qmqm.pl>
> 
> Asus Transformer tablets have a green and an amber LED on both the Pad
> and the Dock. If both LEDs are enabled simultaneously, the emitted light
> will be yellow.
> 
> Co-developed-by: Svyatoslav Ryhel <clamor95@gmail.com>
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>
> ---
>  drivers/leds/Kconfig        |  11 ++++
>  drivers/leds/Makefile       |   1 +
>  drivers/leds/leds-asus-ec.c | 104 ++++++++++++++++++++++++++++++++++++
>  3 files changed, 116 insertions(+)
>  create mode 100644 drivers/leds/leds-asus-ec.c
> 
> diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
> index 597d7a79c988..96dab210f6ca 100644
> --- a/drivers/leds/Kconfig
> +++ b/drivers/leds/Kconfig
> @@ -120,6 +120,17 @@ config LEDS_OSRAM_AMS_AS3668
>  	  To compile this driver as a module, choose M here: the module
>  	  will be called leds-as3668.
>  
> +config LEDS_ASUSEC
> +	tristate "LED Support for Asus Transformer charging LED"
> +	depends on LEDS_CLASS
> +	depends on MFD_ASUSEC
> +	help
> +	  This option enables support for charging indicator on
> +	  Asus Transformer's Pad and it's Dock.
> +
> +	  To compile this driver as a module, choose M here: the module
> +	  will be called leds-asus-ec.
> +
>  config LEDS_AW200XX
>  	tristate "LED support for Awinic AW20036/AW20054/AW20072/AW20108"
>  	depends on LEDS_CLASS
> diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
> index 8fdb45d5b439..1117304dfdf4 100644
> --- a/drivers/leds/Makefile
> +++ b/drivers/leds/Makefile
> @@ -16,6 +16,7 @@ obj-$(CONFIG_LEDS_AN30259A)		+= leds-an30259a.o
>  obj-$(CONFIG_LEDS_APU)			+= leds-apu.o
>  obj-$(CONFIG_LEDS_ARIEL)		+= leds-ariel.o
>  obj-$(CONFIG_LEDS_AS3668)		+= leds-as3668.o
> +obj-$(CONFIG_LEDS_ASUSEC)		+= leds-asus-ec.o
>  obj-$(CONFIG_LEDS_AW200XX)		+= leds-aw200xx.o
>  obj-$(CONFIG_LEDS_AW2013)		+= leds-aw2013.o
>  obj-$(CONFIG_LEDS_BCM6328)		+= leds-bcm6328.o
> diff --git a/drivers/leds/leds-asus-ec.c b/drivers/leds/leds-asus-ec.c
> new file mode 100644
> index 000000000000..5dd76c9247ee
> --- /dev/null
> +++ b/drivers/leds/leds-asus-ec.c
> @@ -0,0 +1,104 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * ASUS EC driver - battery LED
> + */
> +
> +#include <linux/err.h>
> +#include <linux/leds.h>
> +#include <linux/mfd/asus-ec.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +
> +/*
> + * F[5] & 0x07
> + *  auto: brightness == 0
> + *  bit 0: blink / charger on
> + *  bit 1: amber on
> + *  bit 2: green on
> + */
> +
> +#define ASUSEC_CTL_LED_BLINK		BIT_ULL(40)
> +#define ASUSEC_CTL_LED_AMBER		BIT_ULL(41)
> +#define ASUSEC_CTL_LED_GREEN		BIT_ULL(42)
> +
> +static void asus_ec_led_set_brightness_amber(struct led_classdev *led,
> +					     enum led_brightness brightness)
> +{
> +	const struct asusec_info *ec = dev_get_drvdata(led->dev->parent);
> +
> +	if (brightness)
> +		asus_ec_set_ctl_bits(ec, ASUSEC_CTL_LED_AMBER);
> +	else
> +		asus_ec_clear_ctl_bits(ec, ASUSEC_CTL_LED_AMBER);
> +}
> +
> +static void asus_ec_led_set_brightness_green(struct led_classdev *led,
> +					     enum led_brightness brightness)
> +{
> +	const struct asusec_info *ec = dev_get_drvdata(led->dev->parent);
> +
> +	if (brightness)
> +		asus_ec_set_ctl_bits(ec, ASUSEC_CTL_LED_GREEN);
> +	else
> +		asus_ec_clear_ctl_bits(ec, ASUSEC_CTL_LED_GREEN);
> +}
> +
> +static int asus_ec_led_probe(struct platform_device *pdev)
> +{
> +	struct asusec_info *ec = cell_to_ec(pdev);

Please remove all of your abstraction layers.  They serve little purpose
other than to complicate things.  Just use dev_get_drvdata() here.

Remove the "_info" part and change "ec" to "ddata".

> +	struct device *dev = &pdev->dev;
> +	struct led_classdev *amber_led, *green_led;
> +	int ret;
> +
> +	platform_set_drvdata(pdev, ec);

Wait, what?

Why are you doing that?

> +	amber_led = devm_kzalloc(dev, sizeof(*amber_led), GFP_KERNEL);
> +	if (!amber_led)
> +		return -ENOMEM;
> +
> +	amber_led->name = devm_kasprintf(dev, GFP_KERNEL, "%s::amber", ec->name);
> +	amber_led->max_brightness = 1;
> +	amber_led->flags = LED_CORE_SUSPENDRESUME | LED_RETAIN_AT_SHUTDOWN;
> +	amber_led->brightness_set = asus_ec_led_set_brightness_amber;
> +
> +	ret = devm_led_classdev_register(dev, amber_led);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "failed to register amber LED\n");
> +
> +	green_led = devm_kzalloc(dev, sizeof(*green_led), GFP_KERNEL);
> +	if (!green_led)
> +		return -ENOMEM;
> +
> +	green_led->name = devm_kasprintf(dev, GFP_KERNEL, "%s::green", ec->name);
> +	green_led->max_brightness = 1;
> +	green_led->flags = LED_CORE_SUSPENDRESUME | LED_RETAIN_AT_SHUTDOWN;
> +	green_led->brightness_set = asus_ec_led_set_brightness_green;
> +
> +	ret = devm_led_classdev_register(dev, green_led);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "failed to register green LED\n");

Lots of repetition here.

I'd make a sub-function that takes the differences.

Same with the set brightness functions.

Think to yourself - what if I had to support 16 different LEDs?

> +
> +	return 0;
> +}
> +
> +static const struct of_device_id asus_ec_led_match[] = {
> +	{ .compatible = "asus,ec-led" },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, asus_ec_led_match);
> +
> +static struct platform_driver asus_ec_led_driver = {
> +	.driver = {
> +		.name = "asus-ec-led",
> +		.of_match_table = asus_ec_led_match,
> +	},
> +	.probe = asus_ec_led_probe,
> +};
> +module_platform_driver(asus_ec_led_driver);
> +
> +MODULE_AUTHOR("Michał Mirosław <mirq-linux@rere.qmqm.pl>");
> +MODULE_AUTHOR("Svyatoslav Ryhel <clamor95@gmail.com>");
> +MODULE_DESCRIPTION("ASUS Transformer's charging LED driver");
> +MODULE_LICENSE("GPL");
> -- 
> 2.51.0
> 
> 

-- 
Lee Jones [李琼斯]

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v2 4/9] mfd: Add driver for Asus Transformer embedded controller
  2026-03-06  9:18   ` Lee Jones
@ 2026-03-06 12:36     ` Svyatoslav Ryhel
  0 siblings, 0 replies; 30+ messages in thread
From: Svyatoslav Ryhel @ 2026-03-06 12:36 UTC (permalink / raw)
  To: Lee Jones
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Dmitry Torokhov,
	Pavel Machek, Arnd Bergmann, Greg Kroah-Hartman,
	Sebastian Reichel, Michał Mirosław, Ion Agorria,
	devicetree, linux-kernel, linux-input, linux-leds, linux-pm

пт, 6 бер. 2026 р. о 11:19 Lee Jones <lee@kernel.org> пише:
>
> On Mon, 09 Feb 2026, Svyatoslav Ryhel wrote:
>
> > From: Michał Mirosław <mirq-linux@rere.qmqm.pl>
> >
> > Support Nuvoton NPCE795-based ECs as used in Asus Transformer TF201,
> > TF300T, TF300TG, TF300TL and TF700T pad and dock, as well as TF101 dock
> > and TF600T, P1801-T and TF701T pad. This is a glue driver handling
> > detection and common operations for EC's functions.
> >
> > Co-developed-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>
> > ---
> >  drivers/mfd/Kconfig         |  15 ++
> >  drivers/mfd/Makefile        |   1 +
> >  drivers/mfd/asus-ec.c       | 467 ++++++++++++++++++++++++++++++++++++
> >  include/linux/mfd/asus-ec.h | 138 +++++++++++
> >  4 files changed, 621 insertions(+)
> >  create mode 100644 drivers/mfd/asus-ec.c
> >
> > diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> > index 7192c9d1d268..312fd15eec6a 100644
> > --- a/drivers/mfd/Kconfig
> > +++ b/drivers/mfd/Kconfig
> > @@ -137,6 +137,21 @@ config MFD_AAT2870_CORE
> >         additional drivers must be enabled in order to use the
> >         functionality of the device.
> >
> > +config MFD_ASUSEC
>
> MFD_ASUS_EC
>
> > +     tristate "ASUS Transformer's embedded controller"
> > +     depends on I2C && OF
> > +     select SYSFS
> > +     select ASUS_DOCKRAM
> > +     help
> > +       Support ECs found in ASUS Transformer's Pad and Mobile Dock.
> > +
> > +       This provides shared glue for functional part drivers:
> > +         asus-ec-kbc, asus-ec-keys, leds-asus-ec, asus-ec-battery
> > +         and asus-ec-charger.
>
> Why the additional tabbing?  What example did you take that from?
>

MFD_MXS_LRADC
MFD_SL28CPLD
MFD_STMPE

They use 2 tabs, so I asume I have to switch to 2 tabs and a list too.

> > +       This driver can also be built as a module. If so, the module
> > +       will be called asus-ec.
> > +
> >  config MFD_AT91_USART
> >       tristate "AT91 USART Driver"
> >       select MFD_CORE
> > diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> > index e75e8045c28a..b676922601ba 100644
> > --- a/drivers/mfd/Makefile
> > +++ b/drivers/mfd/Makefile
> > @@ -10,6 +10,7 @@ obj-$(CONFIG_MFD_88PM805)   += 88pm805.o 88pm80x.o
> >  obj-$(CONFIG_MFD_88PM886_PMIC)       += 88pm886.o
> >  obj-$(CONFIG_MFD_ACT8945A)   += act8945a.o
> >  obj-$(CONFIG_MFD_SM501)              += sm501.o
> > +obj-$(CONFIG_MFD_ASUSEC)     += asus-ec.o
> >  obj-$(CONFIG_ARCH_BCM2835)   += bcm2835-pm.o
> >  obj-$(CONFIG_MFD_BCM590XX)   += bcm590xx.o
> >  obj-$(CONFIG_MFD_BD9571MWV)  += bd9571mwv.o
> > diff --git a/drivers/mfd/asus-ec.c b/drivers/mfd/asus-ec.c
> > new file mode 100644
> > index 000000000000..e151c1506aa2
> > --- /dev/null
> > +++ b/drivers/mfd/asus-ec.c
> > @@ -0,0 +1,467 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +/*
> > + * ASUS EC driver
>
> Copyright?  Author?
>
> > + */
> > +
> > +#include <linux/array_size.h>
> > +#include <linux/debugfs.h>
> > +#include <linux/delay.h>
> > +#include <linux/gpio/consumer.h>
> > +#include <linux/device.h>
> > +#include <linux/err.h>
> > +#include <linux/i2c.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/mfd/asus-ec.h>
> > +#include <linux/mfd/core.h>
> > +#include <linux/mod_devicetable.h>
> > +#include <linux/module.h>
> > +#include <linux/mutex.h>
> > +#include <linux/property.h>
> > +#include <linux/string.h>
> > +#include <linux/sysfs.h>
> > +#include <linux/types.h>
>
> Alphabetical.
>
> Are you sure all of these are in use?
>

Yes, but if you are willing to double check I would be happy to
include your findings.

> > +#define ASUSEC_RSP_BUFFER_SIZE               8
> > +
> > +struct asus_ec_chip_data {
> > +     const char *name;
> > +     const struct mfd_cell *mfd_devices;
> > +     unsigned int num_devices;
> > +};
> > +
> > +struct asus_ec_data {
> > +     struct asusec_info info;
> > +     struct mutex ecreq_lock; /* prevent simultaneous access */
>
> We know what mutexes do.
>
> If you're going to provide a comment, state WHAT is is protecting.
>
> Or just omit the comment altogether.
>

checkpatch script requires a brief comment why mutex is used, I added
a brief comment where it is used. If you don't like it, then propose a
fix to checkpatch.

> > +     struct gpio_desc *ecreq;
> > +     struct i2c_client *self;
>
> "client"
>

Is there any written convention that struct i2c_client pointer MUST be
named "client"? "self" is pretty well fitting to. You are just
nitpicking.

> Why are you storing this?
>

To use later on to get device and irq.

> > +     const struct asus_ec_chip_data *data;
> > +     u8 ec_data[DOCKRAM_ENTRY_BUFSIZE];
> > +     bool clr_fmode;
> > +     bool logging_disabled;
> > +};
> > +
> > +#define to_ec_data(ec) \
> > +     container_of(ec, struct asus_ec_data, info)
> > +
> > +static void asus_ec_remove_notifier(struct device *dev, void *res)
> > +{
> > +     struct asusec_info *ec = dev_get_drvdata(dev->parent);
> > +     struct notifier_block **nb = res;
> > +
> > +     blocking_notifier_chain_unregister(&ec->notify_list, *nb);
> > +}
> > +
> > +/**
> > + * devm_asus_ec_register_notifier - Managed registration of notifier to an
> > + *                               ASUS EC blocking notifier chain.
> > + * @pdev: Device requesting the notifier (used for resource management).
> > + * @nb: Notifier block to be registered.
> > + *
> > + * Register a notifier to the ASUS EC blocking notifier chain. The notifier
> > + * will be automatically unregistered when the requesting device is detached.
> > + *
> > + * Return: 0 on success or a negative error code on failure.
> > + */
> > +int devm_asus_ec_register_notifier(struct platform_device *pdev,
> > +                                struct notifier_block *nb)
> > +{
> > +     struct asusec_info *ec = dev_get_drvdata(pdev->dev.parent);
> > +     struct notifier_block **res;
> > +     int ret;
> > +
> > +     res = devres_alloc(asus_ec_remove_notifier, sizeof(*res), GFP_KERNEL);
> > +     if (!res)
> > +             return -ENOMEM;
> > +
> > +     *res = nb;
> > +     ret = blocking_notifier_chain_register(&ec->notify_list, nb);
> > +     if (ret) {
> > +             devres_free(res);
> > +             return ret;
> > +     }
> > +
> > +     devres_add(&pdev->dev, res);
> > +
> > +     return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(devm_asus_ec_register_notifier);
> > +
> > +static int asus_ec_signal_request(const struct asusec_info *ec)
> > +{
> > +     struct asus_ec_data *priv = to_ec_data(ec);
> > +
> > +     guard(mutex)(&priv->ecreq_lock);
> > +
> > +     dev_dbg(&priv->self->dev, "EC request\n");
> > +
> > +     gpiod_set_value_cansleep(priv->ecreq, 1);
> > +     msleep(50);
> > +
> > +     gpiod_set_value_cansleep(priv->ecreq, 0);
> > +     msleep(200);
> > +
> > +     return 0;
> > +}
> > +
> > +static int asus_ec_write(struct asus_ec_data *priv, u16 data)
> > +{
> > +     int ret = i2c_smbus_write_word_data(priv->self, ASUSEC_WRITE_BUF, data);
> > +
> > +     dev_dbg(&priv->self->dev, "EC write: %04x, ret = %d\n", data, ret);
> > +     return ret;
> > +}
> > +
> > +static int asus_ec_read(struct asus_ec_data *priv, bool in_irq)
> > +{
> > +     int ret = i2c_smbus_read_i2c_block_data(priv->self, ASUSEC_READ_BUF,
> > +                                             sizeof(priv->ec_data),
> > +                                             priv->ec_data);
> > +
> > +     dev_dbg(&priv->self->dev, "EC read: %*ph, ret = %d%s\n",
> > +             sizeof(priv->ec_data), priv->ec_data,
> > +             ret, in_irq ? "; in irq" : "");
> > +
> > +     return ret;
> > +}
>
> Remove both of these functions and use the i2c_smbus_*() API instead.
>

This would not reduce size much but it will reduce readability
significantly since i2c_smbus_*() API have quite extended names.

> > +
> > +/**
> > + * asus_ec_i2c_command - Send a 16-bit command to the ASUS EC.
> > + * @ec: Pointer to the shared ASUS EC structure.
> > + * @data: The 16-bit command (word) to be sent.
> > + *
> > + * Return: 0 on success or a negative error code on failure.
> > + */
> > +int asus_ec_i2c_command(const struct asusec_info *ec, u16 data)
> > +{
> > +     return asus_ec_write(to_ec_data(ec), data);
> > +}
> > +EXPORT_SYMBOL_GPL(asus_ec_i2c_command);
>
> Why is this needed?  Why not share 'client' with the leave drivers and
> let them make their own calls to i2c_smbus_write_word_data()?
>

Because parent should not share its internal stuff with subdevices.

> > +static void asus_ec_clear_buffer(struct asus_ec_data *priv)
> > +{
> > +     int retry = ASUSEC_RSP_BUFFER_SIZE;
> > +
> > +     while (retry--) {
>
> Why is the amount of retries related to the buffer size?
>

Buffer size is 256 bytes, 1 read is 32 bytes. Calculate

> > +             if (asus_ec_read(priv, false) < 0)
> > +                     continue;
> > +
> > +             if (priv->ec_data[1] & ASUSEC_OBF_MASK)
>
> No magic numbers.  Define the 1.
>

#define ONE 1

> > +                     continue;
> > +
> > +             break;
> > +     }
> > +}
> > +
> > +static int asus_ec_log_info(struct asus_ec_data *priv, unsigned int reg,
> > +                         const char *name, char **out)
> > +{
> > +     char buf[DOCKRAM_ENTRY_BUFSIZE];
> > +     int ret;
> > +
> > +     ret = asus_dockram_read(priv->info.dockram, reg, buf);
> > +     if (ret < 0)
> > +             return ret;
> > +
> > +     if (!priv->logging_disabled)
> > +             dev_info(&priv->self->dev, "%-14s: %.*s\n", name, buf[0], buf + 1);
> > +
> > +     if (out)
> > +             *out = kstrndup(buf + 1, buf[0], GFP_KERNEL);
> > +
> > +     return 0;
> > +}
>
> The driver is written now.  You can remove this over-engineered debugging
> facility.
>

No, this is logs EC firmware behaior. According to your logic kernel
should have no logging whatsoever, and dmesg output is obviously
redundant.

> > +static int asus_ec_reset(struct asus_ec_data *priv)
> > +{
> > +     int retry, ret;
> > +
> > +     for (retry = 0; retry < 3; retry++) {
>
> Why 3?
>
> Why are you using for() here and while() above?
>

Transferred from vendor source. No datasheet.

> > +             ret = asus_ec_write(priv, 0);
>
> Add a comment to explain how this works.
>
> Or, better still, define the value.
>

#define ZERO 0

> > +             if (!ret)
> > +                     return 0;
> > +
> > +             msleep(300);
>
> Why 300?
>

Transferred from vendor source. No datasheet.

> > +     }
> > +
> > +     return ret;
> > +}
> > +
> > +static int asus_ec_magic_debug(struct asus_ec_data *priv)
>
> What does this do?  More comments throughout please.
>

Checks firmware behavior. More is not known.

> > +{
> > +     u64 flag;
> > +     int ret;
> > +
> > +     ret = asus_ec_get_ctl(&priv->info, &flag);
> > +     if (ret < 0)
> > +             return ret;
> > +
> > +     flag &= ASUSEC_CTL_SUSB_MODE;
> > +     dev_info(&priv->self->dev, "EC FW behaviour: %s\n",
> > +              flag ? "susb on when receive ec_req" : "susb on when system wakeup");
> > +
> > +     return 0;
> > +}
> > +
> > +static int asus_ec_set_factory_mode(struct asus_ec_data *priv, bool on)
> > +{
> > +     dev_info(&priv->self->dev, "Entering %s mode.\n", on ? "factory" : "normal");
>
> Remove all of the debugging prints now.
>

No, this is logs EC firmware behavior.

> > +     return asus_ec_update_ctl(&priv->info, ASUSEC_CTL_FACTORY_MODE,
> > +                               on ? ASUSEC_CTL_FACTORY_MODE : 0);
> > +}
> > +
> > +static void asus_ec_handle_smi(struct asus_ec_data *priv, unsigned int code);
>
> No forward declarations.
>
> > +static irqreturn_t asus_ec_interrupt(int irq, void *dev_id)
> > +{
> > +     struct asus_ec_data *priv = dev_id;
> > +     unsigned long notify_action;
> > +     int ret;
> > +
> > +     ret = asus_ec_read(priv, true);
> > +     if (ret <= 0 || !(priv->ec_data[1] & ASUSEC_OBF_MASK))
> > +             return IRQ_NONE;
> > +
> > +     notify_action = priv->ec_data[1];
> > +     if (notify_action & ASUSEC_SMI_MASK) {
> > +             unsigned int code = priv->ec_data[2];
> > +
> > +             asus_ec_handle_smi(priv, code);
> > +
> > +             notify_action |= code << 8;
> > +             dev_dbg(&priv->self->dev, "SMI code: 0x%02x\n", code);
> > +     }
> > +
> > +     blocking_notifier_call_chain(&priv->info.notify_list,
> > +                                  notify_action, priv->ec_data);
> > +
> > +     return IRQ_HANDLED;
> > +}
> > +
> > +static int asus_ec_detect(struct asus_ec_data *priv)
> > +{
> > +     char *model = NULL;
> > +     int ret;
> > +
> > +     ret = asus_ec_reset(priv);
> > +     if (ret)
> > +             goto err_exit;
> > +
> > +     asus_ec_clear_buffer(priv);
> > +
> > +     ret = asus_ec_log_info(priv, ASUSEC_DOCKRAM_INFO_MODEL, "model", &model);
> > +     if (ret)
> > +             goto err_exit;
> > +
> > +     ret = asus_ec_log_info(priv, ASUSEC_DOCKRAM_INFO_FW, "FW version", NULL);
> > +     if (ret)
> > +             goto err_exit;
> > +
> > +     ret = asus_ec_log_info(priv, ASUSEC_DOCKRAM_INFO_CFGFMT, "Config format", NULL);
> > +     if (ret)
> > +             goto err_exit;
> > +
> > +     ret = asus_ec_log_info(priv, ASUSEC_DOCKRAM_INFO_HW, "HW version", NULL);
> > +     if (ret)
> > +             goto err_exit;
> > +
> > +     priv->logging_disabled = true;
> > +
> > +     ret = asus_ec_magic_debug(priv);
> > +     if (ret)
> > +             goto err_exit;
> > +
> > +     priv->info.model = model;
> > +     priv->info.name = priv->data->name;
> > +
> > +     if (priv->clr_fmode)
> > +             asus_ec_set_factory_mode(priv, false);
> > +
> > +err_exit:
> > +     if (ret)
> > +             dev_err(&priv->self->dev, "failed to access EC: %d\n", ret);
> > +
> > +     return ret;
> > +}
> > +
> > +static void asus_ec_handle_smi(struct asus_ec_data *priv, unsigned int code)
> > +{
> > +     dev_dbg(&priv->self->dev, "SMI interrupt: 0x%02x\n", code);
> > +
> > +     switch (code) {
> > +     case ASUSEC_SMI_HANDSHAKE:
> > +     case ASUSEC_SMI_RESET:
> > +             asus_ec_detect(priv);
> > +             break;
> > +     }
> > +}
> > +
> > +static int ec_request_set(void *ec, u64 val)
> > +{
> > +     if (val)
> > +             asus_ec_signal_request(ec);
> > +
> > +     return 0;
> > +}
> > +
> > +DEFINE_DEBUGFS_ATTRIBUTE(ec_request_fops, NULL, ec_request_set, "%llu\n");
> > +
> > +static int ec_irq_set(void *ec, u64 val)
> > +{
> > +     struct asus_ec_data *priv = to_ec_data(ec);
> > +
> > +     if (val)
> > +             irq_wake_thread(priv->self->irq, priv);
> > +
> > +     return 0;
> > +}
> > +
> > +DEFINE_DEBUGFS_ATTRIBUTE(ec_irq_fops, NULL, ec_irq_set, "%llu\n");
>
> Document these.
>

Debugfs does not require any documentation.

> > +static void asus_ec_debugfs_remove(void *debugfs_root)
> > +{
> > +     debugfs_remove_recursive(debugfs_root);
> > +}
> > +
> > +static void devm_asus_ec_debugfs_init(struct device *dev)
> > +{
> > +     struct asusec_info *ec = dev_get_drvdata(dev);
> > +     struct asus_ec_data *priv = to_ec_data(ec);
> > +     struct dentry *debugfs_root;
> > +     char *name = devm_kasprintf(dev, GFP_KERNEL, "asus-ec-%s",
> > +                                 priv->data->name);
> > +
> > +     debugfs_root = debugfs_create_dir(name, NULL);
> > +
> > +     debugfs_create_file("ec_irq", 0200, debugfs_root, ec, &ec_irq_fops);
> > +     debugfs_create_file("ec_request", 0200, debugfs_root, ec, &ec_request_fops);
> > +
> > +     asus_dockram_debugfs_init(priv->info.dockram, debugfs_root);
> > +
> > +     devm_add_action_or_reset(dev, asus_ec_debugfs_remove, debugfs_root);
> > +}
> > +
> > +static int asus_ec_probe(struct i2c_client *client)
> > +{
> > +     struct device *dev = &client->dev;
> > +     struct asus_ec_data *priv;
>
> Call this "ddata".
>

Is there any written convention that driver private data pointer MUST
be named "ddata"? "priv" is pretty well fitting to. You are just
nitpicking.

> > +     int ret;
> > +
> > +     priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> > +     if (!priv)
> > +             return -ENOMEM;
> > +
> > +     priv->data = device_get_match_data(dev);
> > +     if (!priv->data)
> > +             return -ENODEV;
> > +
> > +     i2c_set_clientdata(client, priv);
> > +     priv->self = client;
> > +
> > +     priv->info.dockram = devm_asus_dockram_get(dev);
> > +     if (IS_ERR(priv->info.dockram))
> > +             return dev_err_probe(dev, PTR_ERR(priv->info.dockram),
> > +                                  "failed to get dockram\n");
> > +
> > +     priv->ecreq = devm_gpiod_get(dev, "request", GPIOD_OUT_LOW);
> > +     if (IS_ERR(priv->ecreq))
> > +             return dev_err_probe(dev, PTR_ERR(priv->ecreq),
> > +                                  "failed to get request GPIO\n");
> > +
> > +     BLOCKING_INIT_NOTIFIER_HEAD(&priv->info.notify_list);
> > +     mutex_init(&priv->ecreq_lock);
> > +
> > +     priv->clr_fmode = device_property_read_bool(dev, "asus,clear-factory-mode");
> > +
> > +     asus_ec_signal_request(&priv->info);
> > +
> > +     ret = asus_ec_detect(priv);
> > +     if (ret)
> > +             return dev_err_probe(dev, ret, "failed to detect EC version\n");
> > +
> > +     ret = devm_request_threaded_irq(dev, client->irq, NULL,
> > +                                     &asus_ec_interrupt,
> > +                                     IRQF_ONESHOT | IRQF_SHARED,
> > +                                     client->name, priv);
> > +     if (ret)
> > +             return dev_err_probe(dev, ret, "failed to register IRQ\n");
> > +
> > +     /* Parent I2C controller uses DMA, ASUS EC and child devices do not */
> > +     client->dev.coherent_dma_mask = 0;
> > +     client->dev.dma_mask = &client->dev.coherent_dma_mask;
> > +
> > +     devm_asus_ec_debugfs_init(dev);
> > +
> > +     return devm_mfd_add_devices(dev, 0, priv->data->mfd_devices,
> > +                                 priv->data->num_devices, NULL, 0, NULL);
> > +}
> > +
> > +static const struct mfd_cell asus_ec_pad_mfd_devices[] = {
> > +     {
> > +             .name = "asus-ec-battery",
> > +             .id = 0,
> > +             .of_compatible = "asus,ec-battery",
> > +     }, {
> > +             .name = "asus-ec-charger",
> > +             .id = 0,
> > +             .of_compatible = "asus,ec-charger",
> > +     }, {
> > +             .name = "asus-ec-led",
> > +             .id = 0,
> > +             .of_compatible = "asus,ec-led",
> > +     },
> > +};
> > +
> > +static const struct mfd_cell asus_ec_dock_mfd_devices[] = {
> > +     {
> > +             .name = "asus-ec-battery",
> > +             .id = 1,
> > +             .of_compatible = "asus,ec-battery",
> > +     }, {
> > +             .name = "asus-ec-charger",
> > +             .id = 1,
> > +             .of_compatible = "asus,ec-charger",
> > +     }, {
> > +             .name = "asus-ec-led",
> > +             .id = 1,
> > +             .of_compatible = "asus,ec-led",
> > +     }, {
> > +             .name = "asus-ec-keys",
> > +             .of_compatible = "asus,ec-keys",
> > +     }, {
> > +             .name = "asus-ec-kbc",
> > +             .of_compatible = "asus,ec-kbc",
> > +     },
> > +};
> > +
> > +static const struct asus_ec_chip_data asus_ec_pad_data = {
> > +     .name = "pad",
> > +     .mfd_devices = asus_ec_pad_mfd_devices,
> > +     .num_devices = ARRAY_SIZE(asus_ec_pad_mfd_devices),
> > +};
> > +
> > +static const struct asus_ec_chip_data asus_ec_dock_data = {
> > +     .name = "dock",
> > +     .mfd_devices = asus_ec_dock_mfd_devices,
> > +     .num_devices = ARRAY_SIZE(asus_ec_dock_mfd_devices),
> > +};
> > +
> > +static const struct of_device_id asus_ec_match[] = {
> > +     { .compatible = "asus,ec-pad", .data = &asus_ec_pad_data },
>
> Passing MFD data through a different registration mechanism is not
> allowed.  Use identifiers to match in instead.
>
> git grep "\.data =.*void" -- drivers/mfd
>

Why? So for overwhelming majority of the kernel drivers this is
perfectly fine and ok, and for MFD this is no no? Point me please to
any written convention why using OF match (which is a must for any new
driver) is bad? Especially since this driver targets embedded devices
which rely mostly on OF device trees.

> > +     { .compatible = "asus,ec-dock", .data = &asus_ec_dock_data },
> > +     { }
> > +};
> > +MODULE_DEVICE_TABLE(of, asus_ec_match);
> > +
> > +static struct i2c_driver asus_ec_driver = {
> > +     .driver = {
> > +             .name = "asus-ec",
> > +             .of_match_table = asus_ec_match,
> > +     },
> > +     .probe = asus_ec_probe,
> > +};
> > +module_i2c_driver(asus_ec_driver);
> > +
> > +MODULE_AUTHOR("Michał Mirosław <mirq-linux@rere.qmqm.pl>");
> > +MODULE_AUTHOR("Svyatoslav Ryhel <clamor95@gmail.com>");
> > +MODULE_DESCRIPTION("ASUS Transformer's EC driver");
> > +MODULE_LICENSE("GPL");
> > diff --git a/include/linux/mfd/asus-ec.h b/include/linux/mfd/asus-ec.h
> > index 6a36313b9ebd..6a06b125ba30 100644
> > --- a/include/linux/mfd/asus-ec.h
> > +++ b/include/linux/mfd/asus-ec.h
> > @@ -2,16 +2,78 @@
> >  #ifndef __MISC_ASUS_EC_H
> >  #define __MISC_ASUS_EC_H
> >
> > +#include <linux/notifier.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/workqueue.h>
> > +
> >  struct i2c_client;
> >
> > +struct asusec_info {
> > +     const char *model;
> > +     const char *name;
> > +     struct i2c_client *dockram;
> > +     struct workqueue_struct *wq;
> > +     struct blocking_notifier_head notify_list;
> > +};
> > +
> >  #define DOCKRAM_ENTRIES                      0x100
> >  #define DOCKRAM_ENTRY_SIZE           32
> >  #define DOCKRAM_ENTRY_BUFSIZE                (DOCKRAM_ENTRY_SIZE + 1)
> >
> > +/* interrupt sources */
> > +#define ASUSEC_OBF_MASK                      BIT(0)
> > +#define ASUSEC_KEY_MASK                      BIT(2)
> > +#define ASUSEC_KBC_MASK                      BIT(3)
> > +#define ASUSEC_AUX_MASK                      BIT(5)
> > +#define ASUSEC_SCI_MASK                      BIT(6)
> > +#define ASUSEC_SMI_MASK                      BIT(7)
> > +
> > +/* SMI notification codes */
> > +#define ASUSEC_SMI_POWER_NOTIFY              0x31    /* [un]plugging USB cable */
> > +#define ASUSEC_SMI_HANDSHAKE         0x50    /* response to ec_req edge */
> > +#define ASUSEC_SMI_WAKE                      0x53
> > +#define ASUSEC_SMI_RESET             0x5f
> > +#define ASUSEC_SMI_ADAPTER_EVENT     0x60    /* [un]plugging charger to dock */
> > +#define ASUSEC_SMI_BACKLIGHT_ON              0x63
> > +#define ASUSEC_SMI_AUDIO_DOCK_IN     0x70
> > +
> > +#define ASUSEC_SMI_ACTION(code)              (ASUSEC_SMI_MASK | ASUSEC_OBF_MASK | \
> > +                                     (ASUSEC_SMI_##code << 8))
> > +
> >  /* control register [0x0A] layout */
> >  #define ASUSEC_CTL_SIZE                      8
> >
> > +/*
> > + * EC reports power from 40-pin connector in the LSB of the control
> > + * register.  The following values have been observed (xor 0x02):
> > + *
> > + * PAD-ec no-plug  0x40 / PAD-ec DOCK     0x20 / DOCK-ec no-plug 0x40
> > + * PAD-ec AC       0x25 / PAD-ec DOCK+AC  0x24 / DOCK-ec AC      0x25
> > + * PAD-ec USB      0x45 / PAD-ec DOCK+USB 0x24 / DOCK-ec USB     0x41
> > + */
> > +
> > +#define ASUSEC_CTL_DIRECT_POWER_SOURCE       BIT_ULL(0)
> > +#define ASUSEC_STAT_CHARGING         BIT_ULL(2)
> > +#define ASUSEC_CTL_FULL_POWER_SOURCE BIT_ULL(5)
> > +#define ASUSEC_CTL_SUSB_MODE         BIT_ULL(11)
> > +#define ASUSEC_CMD_SUSPEND_S3                BIT_ULL(41)
> > +#define ASUSEC_CTL_TEST_DISCHARGE    BIT_ULL(43)
> > +#define ASUSEC_CMD_SUSPEND_INHIBIT   BIT_ULL(45)
> > +#define ASUSEC_CTL_FACTORY_MODE              BIT_ULL(46)
> > +#define ASUSEC_CTL_KEEP_AWAKE                BIT_ULL(47)
> > +#define ASUSEC_CTL_USB_CHARGE                BIT_ULL(50)
> > +#define ASUSEC_CMD_SWITCH_HDMI               BIT_ULL(70)
> > +#define ASUSEC_CMD_WIN_SHUTDOWN              BIT_ULL(76)
> > +
> > +#define ASUSEC_DOCKRAM_INFO_MODEL    0x01
> > +#define ASUSEC_DOCKRAM_INFO_FW               0x02
> > +#define ASUSEC_DOCKRAM_INFO_CFGFMT   0x03
> > +#define ASUSEC_DOCKRAM_INFO_HW               0x04
> >  #define ASUSEC_DOCKRAM_CONTROL               0x0a
> > +#define ASUSEC_DOCKRAM_BATT_CTL              0x14
> > +
> > +#define ASUSEC_WRITE_BUF             0x64
> > +#define ASUSEC_READ_BUF                      0x6A
> >
> >  /* dockram comm */
> >  int asus_dockram_read(struct i2c_client *client, int reg, char *buf);
> > @@ -21,4 +83,80 @@ int asus_dockram_access_ctl(struct i2c_client *client,
> >  struct i2c_client *devm_asus_dockram_get(struct device *parent);
> >  void asus_dockram_debugfs_init(struct i2c_client *client,
> >                              struct dentry *debugfs_root);
> > +
> > +/* EC public API */
> > +
> > +/**
> > + * cell_to_ec - Request the shared ASUS EC structure via a subdevice's pdev.
> > + * @pdev: EC subdevice pdev requesting access to the shared ASUS EC structure.
> > + *
> > + * Returns a pointer to the asusec_info structure.
> > + */
> > +static inline struct asusec_info *cell_to_ec(struct platform_device *pdev)
> > +{
> > +     return dev_get_drvdata(pdev->dev.parent);
> > +}
> > +
> > +/**
> > + * asus_ec_get_ctl - Read from the DockRAM control register.
> > + * @ec:  Pointer to the shared ASUS EC structure.
> > + * @out: Pointer to the variable where the register value will be stored.
> > + *
> > + * Performs a control register read and stores the value in @out.
> > + *
> > + * Return: 0 on success, or a negative errno code on failure.
> > + */
> > +static inline int asus_ec_get_ctl(const struct asusec_info *ec, u64 *out)
> > +{
> > +     return asus_dockram_access_ctl(ec->dockram, out, 0, 0);
> > +}
> > +
> > +/**
> > + * asus_ec_update_ctl - Update the DockRAM control register.
> > + * @ec:   Pointer to the shared ASUS EC structure.
> > + * @mask: Bitmask of bits to be cleared.
> > + * @xor:  Bitmask of bits to be toggled or set (via XOR).
> > + *
> > + * Performs a read-modify-write update on the control register using
> > + * the provided @mask and @xor values.
> > + *
> > + * Return: 0 on success, or a negative errno code on failure.
> > + */
> > +static inline int asus_ec_update_ctl(const struct asusec_info *ec,
> > +                                  u64 mask, u64 xor)
> > +{
> > +     return asus_dockram_access_ctl(ec->dockram, NULL, mask, xor);
> > +}
> > +
> > +/**
> > + * asus_ec_set_ctl_bits - Sets bits of the DockRAM control register.
> > + * @ec:   Pointer to the shared ASUS EC structure.
> > + * @mask: Bitmask of bits to be set.
> > + *
> > + * Sets bits of the control register using the provided @mask value.
> > + *
> > + * Return: 0 on success, or a negative errno code on failure.
> > + */
> > +static inline int asus_ec_set_ctl_bits(const struct asusec_info *ec, u64 mask)
> > +{
> > +     return asus_dockram_access_ctl(ec->dockram, NULL, mask, mask);
> > +}
> > +
> > +/**
> > + * asus_ec_clear_ctl_bits - Clears bits of the DockRAM control register.
> > + * @ec:   Pointer to the shared ASUS EC structure.
> > + * @mask: Bitmask of bits to be cleared.
> > + *
> > + * Clears bits of the control register using the provided @mask value.
> > + *
> > + * Return: 0 on success, or a negative errno code on failure.
> > + */
> > +static inline int asus_ec_clear_ctl_bits(const struct asusec_info *ec, u64 mask)
> > +{
> > +     return asus_dockram_access_ctl(ec->dockram, NULL, mask, 0);
> > +}
>
> This is all abstraction for he sake of abstraction.
>

Is this nitpicking for the sake of nitpicking? All 3 are used by
subdevices and have proper descriptions. According to your logic maybe
all clear, set and setclr wrappers should be removed across kernel as
well. And all access functions can be dropped to xfer covers
everything.

> > +int asus_ec_i2c_command(const struct asusec_info *ec, u16 data);
> > +int devm_asus_ec_register_notifier(struct platform_device *dev,
> > +                                struct notifier_block *nb);
> >  #endif /* __MISC_ASUS_EC_H */
> > --
> > 2.51.0
> >
> >
>
> --
> Lee Jones [李琼斯]

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v2 7/9] leds: Add driver for Asus Transformer LEDs
  2026-03-06 10:04   ` Lee Jones
@ 2026-03-06 12:45     ` Svyatoslav Ryhel
  2026-03-09 19:04       ` Lee Jones
  0 siblings, 1 reply; 30+ messages in thread
From: Svyatoslav Ryhel @ 2026-03-06 12:45 UTC (permalink / raw)
  To: Lee Jones
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Dmitry Torokhov,
	Pavel Machek, Arnd Bergmann, Greg Kroah-Hartman,
	Sebastian Reichel, Michał Mirosław, Ion Agorria,
	devicetree, linux-kernel, linux-input, linux-leds, linux-pm

пт, 6 бер. 2026 р. о 12:04 Lee Jones <lee@kernel.org> пише:
>
> On Mon, 09 Feb 2026, Svyatoslav Ryhel wrote:
>
> > From: Michał Mirosław <mirq-linux@rere.qmqm.pl>
> >
> > Asus Transformer tablets have a green and an amber LED on both the Pad
> > and the Dock. If both LEDs are enabled simultaneously, the emitted light
> > will be yellow.
> >
> > Co-developed-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>
> > ---
> >  drivers/leds/Kconfig        |  11 ++++
> >  drivers/leds/Makefile       |   1 +
> >  drivers/leds/leds-asus-ec.c | 104 ++++++++++++++++++++++++++++++++++++
> >  3 files changed, 116 insertions(+)
> >  create mode 100644 drivers/leds/leds-asus-ec.c
> >
> > diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
> > index 597d7a79c988..96dab210f6ca 100644
> > --- a/drivers/leds/Kconfig
> > +++ b/drivers/leds/Kconfig
> > @@ -120,6 +120,17 @@ config LEDS_OSRAM_AMS_AS3668
> >         To compile this driver as a module, choose M here: the module
> >         will be called leds-as3668.
> >
> > +config LEDS_ASUSEC
> > +     tristate "LED Support for Asus Transformer charging LED"
> > +     depends on LEDS_CLASS
> > +     depends on MFD_ASUSEC
> > +     help
> > +       This option enables support for charging indicator on
> > +       Asus Transformer's Pad and it's Dock.
> > +
> > +       To compile this driver as a module, choose M here: the module
> > +       will be called leds-asus-ec.
> > +
> >  config LEDS_AW200XX
> >       tristate "LED support for Awinic AW20036/AW20054/AW20072/AW20108"
> >       depends on LEDS_CLASS
> > diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
> > index 8fdb45d5b439..1117304dfdf4 100644
> > --- a/drivers/leds/Makefile
> > +++ b/drivers/leds/Makefile
> > @@ -16,6 +16,7 @@ obj-$(CONFIG_LEDS_AN30259A)         += leds-an30259a.o
> >  obj-$(CONFIG_LEDS_APU)                       += leds-apu.o
> >  obj-$(CONFIG_LEDS_ARIEL)             += leds-ariel.o
> >  obj-$(CONFIG_LEDS_AS3668)            += leds-as3668.o
> > +obj-$(CONFIG_LEDS_ASUSEC)            += leds-asus-ec.o
> >  obj-$(CONFIG_LEDS_AW200XX)           += leds-aw200xx.o
> >  obj-$(CONFIG_LEDS_AW2013)            += leds-aw2013.o
> >  obj-$(CONFIG_LEDS_BCM6328)           += leds-bcm6328.o
> > diff --git a/drivers/leds/leds-asus-ec.c b/drivers/leds/leds-asus-ec.c
> > new file mode 100644
> > index 000000000000..5dd76c9247ee
> > --- /dev/null
> > +++ b/drivers/leds/leds-asus-ec.c
> > @@ -0,0 +1,104 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/*
> > + * ASUS EC driver - battery LED
> > + */
> > +
> > +#include <linux/err.h>
> > +#include <linux/leds.h>
> > +#include <linux/mfd/asus-ec.h>
> > +#include <linux/mod_devicetable.h>
> > +#include <linux/module.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/slab.h>
> > +
> > +/*
> > + * F[5] & 0x07
> > + *  auto: brightness == 0
> > + *  bit 0: blink / charger on
> > + *  bit 1: amber on
> > + *  bit 2: green on
> > + */
> > +
> > +#define ASUSEC_CTL_LED_BLINK         BIT_ULL(40)
> > +#define ASUSEC_CTL_LED_AMBER         BIT_ULL(41)
> > +#define ASUSEC_CTL_LED_GREEN         BIT_ULL(42)
> > +
> > +static void asus_ec_led_set_brightness_amber(struct led_classdev *led,
> > +                                          enum led_brightness brightness)
> > +{
> > +     const struct asusec_info *ec = dev_get_drvdata(led->dev->parent);
> > +
> > +     if (brightness)
> > +             asus_ec_set_ctl_bits(ec, ASUSEC_CTL_LED_AMBER);
> > +     else
> > +             asus_ec_clear_ctl_bits(ec, ASUSEC_CTL_LED_AMBER);
> > +}
> > +
> > +static void asus_ec_led_set_brightness_green(struct led_classdev *led,
> > +                                          enum led_brightness brightness)
> > +{
> > +     const struct asusec_info *ec = dev_get_drvdata(led->dev->parent);
> > +
> > +     if (brightness)
> > +             asus_ec_set_ctl_bits(ec, ASUSEC_CTL_LED_GREEN);
> > +     else
> > +             asus_ec_clear_ctl_bits(ec, ASUSEC_CTL_LED_GREEN);
> > +}
> > +
> > +static int asus_ec_led_probe(struct platform_device *pdev)
> > +{
> > +     struct asusec_info *ec = cell_to_ec(pdev);
>
> Please remove all of your abstraction layers.  They serve little purpose
> other than to complicate things.  Just use dev_get_drvdata() here.
>
> Remove the "_info" part and change "ec" to "ddata".
>

Controller exposes only required stuff, exposing controllers internal
parts is not desired. Is there any written convention that driver
private data pointer MUST be named "ddata"? "priv" is pretty well
fitting to. You are just nitpicking.

> > +     struct device *dev = &pdev->dev;
> > +     struct led_classdev *amber_led, *green_led;
> > +     int ret;
> > +
> > +     platform_set_drvdata(pdev, ec);
>
> Wait, what?
>
> Why are you doing that?
>

This is redundant, yes.

> > +     amber_led = devm_kzalloc(dev, sizeof(*amber_led), GFP_KERNEL);
> > +     if (!amber_led)
> > +             return -ENOMEM;
> > +
> > +     amber_led->name = devm_kasprintf(dev, GFP_KERNEL, "%s::amber", ec->name);
> > +     amber_led->max_brightness = 1;
> > +     amber_led->flags = LED_CORE_SUSPENDRESUME | LED_RETAIN_AT_SHUTDOWN;
> > +     amber_led->brightness_set = asus_ec_led_set_brightness_amber;
> > +
> > +     ret = devm_led_classdev_register(dev, amber_led);
> > +     if (ret)
> > +             return dev_err_probe(dev, ret, "failed to register amber LED\n");
> > +
> > +     green_led = devm_kzalloc(dev, sizeof(*green_led), GFP_KERNEL);
> > +     if (!green_led)
> > +             return -ENOMEM;
> > +
> > +     green_led->name = devm_kasprintf(dev, GFP_KERNEL, "%s::green", ec->name);
> > +     green_led->max_brightness = 1;
> > +     green_led->flags = LED_CORE_SUSPENDRESUME | LED_RETAIN_AT_SHUTDOWN;
> > +     green_led->brightness_set = asus_ec_led_set_brightness_green;
> > +
> > +     ret = devm_led_classdev_register(dev, green_led);
> > +     if (ret)
> > +             return dev_err_probe(dev, ret, "failed to register green LED\n");
>
> Lots of repetition here.
>
> I'd make a sub-function that takes the differences.
>
> Same with the set brightness functions.
>
> Think to yourself - what if I had to support 16 different LEDs?
>

That is not of my concern what you would do. I have 2 LEDs and I see
no point in "abstraction for he sake of abstraction".

> > +
> > +     return 0;
> > +}
> > +
> > +static const struct of_device_id asus_ec_led_match[] = {
> > +     { .compatible = "asus,ec-led" },
> > +     { }
> > +};
> > +MODULE_DEVICE_TABLE(of, asus_ec_led_match);
> > +
> > +static struct platform_driver asus_ec_led_driver = {
> > +     .driver = {
> > +             .name = "asus-ec-led",
> > +             .of_match_table = asus_ec_led_match,
> > +     },
> > +     .probe = asus_ec_led_probe,
> > +};
> > +module_platform_driver(asus_ec_led_driver);
> > +
> > +MODULE_AUTHOR("Michał Mirosław <mirq-linux@rere.qmqm.pl>");
> > +MODULE_AUTHOR("Svyatoslav Ryhel <clamor95@gmail.com>");
> > +MODULE_DESCRIPTION("ASUS Transformer's charging LED driver");
> > +MODULE_LICENSE("GPL");
> > --
> > 2.51.0
> >
> >
>
> --
> Lee Jones [李琼斯]

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v2 7/9] leds: Add driver for Asus Transformer LEDs
  2026-03-06 12:45     ` Svyatoslav Ryhel
@ 2026-03-09 19:04       ` Lee Jones
  0 siblings, 0 replies; 30+ messages in thread
From: Lee Jones @ 2026-03-09 19:04 UTC (permalink / raw)
  To: Svyatoslav Ryhel
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Dmitry Torokhov,
	Pavel Machek, Arnd Bergmann, Greg Kroah-Hartman,
	Sebastian Reichel, Michał Mirosław, Ion Agorria,
	devicetree, linux-kernel, linux-input, linux-leds, linux-pm

On Fri, 06 Mar 2026, Svyatoslav Ryhel wrote:

> пт, 6 бер. 2026 р. о 12:04 Lee Jones <lee@kernel.org> пише:
> >
> > On Mon, 09 Feb 2026, Svyatoslav Ryhel wrote:
> >
> > > From: Michał Mirosław <mirq-linux@rere.qmqm.pl>
> > >
> > > Asus Transformer tablets have a green and an amber LED on both the Pad
> > > and the Dock. If both LEDs are enabled simultaneously, the emitted light
> > > will be yellow.
> > >
> > > Co-developed-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > > Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > > Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>
> > > ---
> > >  drivers/leds/Kconfig        |  11 ++++
> > >  drivers/leds/Makefile       |   1 +
> > >  drivers/leds/leds-asus-ec.c | 104 ++++++++++++++++++++++++++++++++++++
> > >  3 files changed, 116 insertions(+)
> > >  create mode 100644 drivers/leds/leds-asus-ec.c
[
...]

> > > +static int asus_ec_led_probe(struct platform_device *pdev)
> > > +{
> > > +     struct asusec_info *ec = cell_to_ec(pdev);
> >
> > Please remove all of your abstraction layers.  They serve little purpose
> > other than to complicate things.  Just use dev_get_drvdata() here.
> >
> > Remove the "_info" part and change "ec" to "ddata".
> >
> 
> Controller exposes only required stuff, exposing controllers internal
> parts is not desired. Is there any written convention that driver
> private data pointer MUST be named "ddata"? "priv" is pretty well
> fitting to. You are just nitpicking.

[...] 

> > Lots of repetition here.
> >
> > I'd make a sub-function that takes the differences.
> >
> > Same with the set brightness functions.
> >
> > Think to yourself - what if I had to support 16 different LEDs?
> >
> 
> That is not of my concern what you would do. I have 2 LEDs and I see
> no point in "abstraction for he sake of abstraction".

Your attitude stinks!

All of your submissions are now on hold until I can be bothered to look
at them again.  In the mean time, I suggest you look inward and
re-evaluate how you choose to communicate with others.

-- 
Lee Jones [李琼斯]

^ permalink raw reply	[flat|nested] 30+ messages in thread

end of thread, other threads:[~2026-03-09 19:05 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-09 10:43 [PATCH v2 0/9] mfd: Add support for Asus Transformer embedded controller Svyatoslav Ryhel
2026-02-09 10:43 ` [PATCH v2 1/9] dt-bindings: misc: document ASUS Transformers EC DockRAM Svyatoslav Ryhel
2026-02-10  9:25   ` Krzysztof Kozlowski
2026-02-10  9:42     ` Svyatoslav Ryhel
2026-02-10 10:50       ` Krzysztof Kozlowski
2026-02-10 11:08         ` Svyatoslav Ryhel
2026-02-09 10:44 ` [PATCH v2 2/9] misc: Support Asus Transformer's EC access device Svyatoslav Ryhel
2026-02-09 10:44 ` [PATCH v2 3/9] dt-bindings: mfd: document ASUS Transformer EC Svyatoslav Ryhel
2026-02-10  9:22   ` Krzysztof Kozlowski
2026-02-10  9:37     ` Svyatoslav Ryhel
2026-02-10 10:48       ` Krzysztof Kozlowski
2026-02-10 10:59         ` Svyatoslav Ryhel
2026-02-10 11:04           ` Krzysztof Kozlowski
2026-02-10 11:14             ` Svyatoslav Ryhel
2026-02-10 11:24               ` Krzysztof Kozlowski
2026-02-10 11:40                 ` Svyatoslav Ryhel
2026-02-10 11:54                   ` Krzysztof Kozlowski
2026-02-10 12:48                     ` Krzysztof Kozlowski
2026-02-11 10:48                       ` Svyatoslav Ryhel
2026-02-09 10:44 ` [PATCH v2 4/9] mfd: Add driver for Asus Transformer embedded controller Svyatoslav Ryhel
2026-03-06  9:18   ` Lee Jones
2026-03-06 12:36     ` Svyatoslav Ryhel
2026-02-09 10:44 ` [PATCH v2 5/9] input: serio: Add driver for Asus Transformer dock keyboard and touchpad Svyatoslav Ryhel
2026-02-09 10:44 ` [PATCH v2 6/9] input: keyboard: Add driver for Asus Transformer dock multimedia keys Svyatoslav Ryhel
2026-02-09 10:44 ` [PATCH v2 7/9] leds: Add driver for Asus Transformer LEDs Svyatoslav Ryhel
2026-03-06 10:04   ` Lee Jones
2026-03-06 12:45     ` Svyatoslav Ryhel
2026-03-09 19:04       ` Lee Jones
2026-02-09 10:44 ` [PATCH v2 8/9] power: supply: Add driver for Asus Transformer battery Svyatoslav Ryhel
2026-02-09 10:44 ` [PATCH v2 9/9] power: supply: Add charger driver for Asus Transformers Svyatoslav Ryhel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox