linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Tomáš Juřena" <jurenatomas@gmail.com>
To: dmitry.torokhov@gmail.com
Cc: robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org,
	linux-input@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org,
	Tomas Jurena <jurenatomas@gmail.com>
Subject: [PATCH] Input: tca6416-keypad - Add OF support for driver instantiation
Date: Tue, 10 Jun 2025 17:46:10 +0200	[thread overview]
Message-ID: <20250610154609.1382818-1-jurenatomas@gmail.com> (raw)

From: Tomas Jurena <jurenatomas@gmail.com>

Adds support for instantiating the tca6416-keypad driver via
Device Tree. If no platform data is present, the driver can now be
probed based on OF bindings.

A corresponding Device Tree binding document is added at:
  Documentation/devicetree/bindings/input/tca6416-keypad.yaml

This allows the driver to be used in systems that rely solely on the
Device Tree for hardware description, such as embedded ARM platforms.

Tested on Toradex Ixora 1.3A board and Apalis imx8 SOM.

Signed-off-by: Tomas Jurena <jurenatomas@gmail.com>
---
 .../bindings/input/tca6416-keypad.yaml        | 87 ++++++++++++++++++
 drivers/input/keyboard/tca6416-keypad.c       | 88 +++++++++++++++++--
 2 files changed, 170 insertions(+), 5 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/input/tca6416-keypad.yaml

diff --git a/Documentation/devicetree/bindings/input/tca6416-keypad.yaml b/Documentation/devicetree/bindings/input/tca6416-keypad.yaml
new file mode 100644
index 000000000000..f050403c4dbe
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/tca6416-keypad.yaml
@@ -0,0 +1,87 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/input/tca6416-keypad.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: TI TCA6416 keypad
+
+maintainers:
+
+description: |
+  Texas Instruments TCA6416 IO expander as a keypad input device.
+
+allOf:
+  - $ref: input.yaml#
+
+properties:
+  compatible:
+    enum:
+      - ti,tca6416_keys
+      - ti,tca6408_keys
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  linux,gpio-keymap:
+    $ref: /schemas/types.yaml#/definitions/uint32-array
+    description: |
+      Array of gpio keys provided by the driver instance. Each entry is a
+      bitfield holding configuration of the input key. The bitfield looks like
+      this:
+      +------------------------------------------------------------+
+      | Bits     | 31:18    |         17 | 16:14 | 13:10    | 9:0  |
+      | Function | reserved | active_low | type  | reserved | code |
+      +------------------------------------------------------------+
+      code - Linux key code
+      type - EV_KEY or EV_SW
+      active_low - Key is active in low state
+
+  linux,keycodes:
+    minItems: 1
+    maxItems: 16
+
+  autorepeat:
+    type: boolean
+    description: |
+      Enables the Linux input system's autorepeat feature on the input device.
+
+  polling:
+    type: boolean
+    description: |
+      Forces driver to use polling mode instead of IRQ.
+
+  pinmask:
+    description: |
+      Allows to disable certain keys. By default are all inputs enabled.
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+      keypad@21 {
+        compatible = "ti,tca6416_keys";
+        reg = <0x21>;
+        interrupt-parent = <&gpio>;
+        interrupts = <26 IRQ_TYPE_EDGE_FALLING>;
+        linux,gpio-keymap = <
+                            0x24290, // active low, EV_KEY, 0, KEY_MACRO1
+                            0x24291, // active low, EV_KEY, 1, KEY_MACRO2
+                            0x24292, // active low, EV_KEY, 2, KEY_MACRO3
+        >;
+      };
+    };
+
+...
diff --git a/drivers/input/keyboard/tca6416-keypad.c b/drivers/input/keyboard/tca6416-keypad.c
index fbc674d7b9f0..8910498cf266 100644
--- a/drivers/input/keyboard/tca6416-keypad.c
+++ b/drivers/input/keyboard/tca6416-keypad.c
@@ -17,6 +17,7 @@
 #include <linux/i2c.h>
 #include <linux/input.h>
 #include <linux/tca6416_keypad.h>
+#include <linux/bitfield.h>
 
 #define TCA6416_INPUT          0
 #define TCA6416_OUTPUT         1
@@ -24,6 +25,7 @@
 #define TCA6416_DIRECTION      3
 
 #define TCA6416_POLL_INTERVAL	100 /* msec */
+#define TCA6416_MAX_IO_SIZE 16 /* maximum number of inputs */
 
 static const struct i2c_device_id tca6416_id[] = {
 	{ "tca6416-keys", 16, },
@@ -173,9 +175,67 @@ static int tca6416_setup_registers(struct tca6416_keypad_chip *chip)
 	return 0;
 }
 
+/* Configuration bitmap
+ * | 31:18    |         17 | 16:14 | 13:10    | 9:0  |
+ * | reserved | active_low | type  | reserved | code |
+ */
+#define CFG_CODE GENMASK(9, 0)
+#define CFG_TYPE GENMASK(16, 14)
+#define CFG_ACTIVE_LOW BIT(17)
+
+static struct tca6416_keys_platform_data *
+tca6416_parse_properties(struct device *dev, uint8_t io_size)
+{
+	static const char keymap_property[] = "linux,gpio-keymap";
+	struct tca6416_keys_platform_data *pdata;
+	u32 keymap[TCA6416_MAX_IO_SIZE];
+	struct tca6416_button *buttons;
+	int ret, i;
+	u8 pin;
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return NULL;
+
+	ret = device_property_count_u32(dev, keymap_property);
+	if (ret <= 0)
+		return NULL;
+
+	pdata->nbuttons = ret;
+	if (pdata->nbuttons > io_size)
+		pdata->nbuttons = io_size;
+
+	ret = device_property_read_u32_array(dev, keymap_property, keymap,
+					     pdata->nbuttons);
+	if (ret)
+		return NULL;
+
+	buttons = devm_kcalloc(dev, pdata->nbuttons, sizeof(*buttons),
+			       GFP_KERNEL);
+	if (!buttons)
+		return NULL;
+
+	for (i = 0; i < pdata->nbuttons; i++) {
+		buttons[i].code = FIELD_GET(CFG_CODE, keymap[i]);
+		buttons[i].type = FIELD_GET(CFG_TYPE, keymap[i]);
+		buttons[i].active_low = FIELD_GET(CFG_ACTIVE_LOW, keymap[i]);
+		/* enable all inputs by default */
+		pdata->pinmask |= BIT(i);
+	}
+
+	pdata->buttons = buttons;
+
+	pdata->rep = device_property_read_bool(dev, "autorepeat");
+	/* we can ignore the result as by default all inputs are enabled */
+	device_property_read_u16(dev, "pinmask", &pdata->pinmask);
+	pdata->use_polling = device_property_read_bool(dev, "polling");
+
+	return pdata;
+}
+
 static int tca6416_keypad_probe(struct i2c_client *client)
 {
-	const struct i2c_device_id *id = i2c_client_get_device_id(client);
+	uint8_t io_size = (uintptr_t)i2c_get_match_data(client);
 	struct tca6416_keys_platform_data *pdata;
 	struct tca6416_keypad_chip *chip;
 	struct input_dev *input;
@@ -190,9 +250,13 @@ static int tca6416_keypad_probe(struct i2c_client *client)
 	}
 
 	pdata = dev_get_platdata(&client->dev);
-	if (!pdata) {
-		dev_dbg(&client->dev, "no platform data\n");
-		return -EINVAL;
+	if (!pdata && dev_fwnode(&client->dev)) {
+		pdata = tca6416_parse_properties(&client->dev, io_size);
+		if (!pdata) {
+			dev_err(&client->dev,
+				"Failed to parse device configuration from properties\n");
+			return -EINVAL;
+		}
 	}
 
 	chip = devm_kzalloc(&client->dev,
@@ -207,7 +271,7 @@ static int tca6416_keypad_probe(struct i2c_client *client)
 
 	chip->client = client;
 	chip->input = input;
-	chip->io_size = id->driver_data;
+	chip->io_size = io_size;
 	chip->pinmask = pdata->pinmask;
 	chip->use_polling = pdata->use_polling;
 
@@ -279,9 +343,23 @@ static int tca6416_keypad_probe(struct i2c_client *client)
 	return 0;
 }
 
+static const struct of_device_id tca6416_of_match[] = {
+	{
+		.compatible = "ti,tca6416_keys",
+		.data = (void *)16,
+	},
+	{
+		.compatible = "ti,tca6408_keys",
+		.data = (void *)8,
+	},
+	{}
+};
+MODULE_DEVICE_TABLE(of, tca6416_of_match);
+
 static struct i2c_driver tca6416_keypad_driver = {
 	.driver = {
 		.name	= "tca6416-keypad",
+		.of_match_table = tca6416_of_match,
 	},
 	.probe		= tca6416_keypad_probe,
 	.id_table	= tca6416_id,
-- 
2.34.1


             reply	other threads:[~2025-06-10 15:46 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-06-10 15:46 Tomáš Juřena [this message]
2025-06-10 17:37 ` [PATCH] Input: tca6416-keypad - Add OF support for driver instantiation Rob Herring (Arm)
2025-06-10 18:15 ` Rob Herring
2025-06-11 16:08   ` Tomas Jurena
2025-06-11 17:44     ` Dmitry Torokhov
2025-06-11 14:22 ` kernel test robot
2025-06-18 17:40 ` Dan Carpenter

Reply instructions:

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

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

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

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

  git send-email \
    --in-reply-to=20250610154609.1382818-1-jurenatomas@gmail.com \
    --to=jurenatomas@gmail.com \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=dmitry.torokhov@gmail.com \
    --cc=krzk+dt@kernel.org \
    --cc=linux-input@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=robh@kernel.org \
    /path/to/YOUR_REPLY

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

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).