Linux Input/HID development
 help / color / mirror / Atom feed
* [PATCH 2/6] HID: i2c-hid-of: Allow using i2c-hid-of on non OF platforms
From: Hans de Goede @ 2023-04-09 14:42 UTC (permalink / raw)
  To: Jiri Kosina, Benjamin Tissoires, Douglas Anderson
  Cc: Hans de Goede, linux-input
In-Reply-To: <20230409144243.25360-1-hdegoede@redhat.com>

There are some x86 tablets / 2-in-1s which ship with Android as their
factory OS image. These have pretty broken ACPI tables, relying on
everything being hardcoded in the factory kernel image.

platform/x86/x86-android-tablets.c manually instantiates i2c-clients for
i2c devices on these tablets to make them work with the mainline kernel.

The Lenovo Yoga Book 1 (yb1-x90f/l) is such a 2-in-1. It has 2 I2C-HID
devices its main touchscreen and a Wacom digitizer. Its main touchscreen
can alternatively also be used in HiDeep's native protocol mode but
for the Wacom digitizer we really need I2C-HID.

This patch allows using i2c-hid-of on non OF platforms so that it can
bind to a non ACPI instantiated i2c_client on x86 for the Wacom digitizer.
Note the driver already has an "i2c-over-hid" i2c_device_id (rather then
an of_device_id).

Besides enabling building on non-OF platforms this also replaces
the only of_property_read_u32() call with device_property_read_u32() note
that other properties where already read using device_property_read_...().

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/hid/i2c-hid/Kconfig      | 6 ++++--
 drivers/hid/i2c-hid/i2c-hid-of.c | 4 +++-
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/drivers/hid/i2c-hid/Kconfig b/drivers/hid/i2c-hid/Kconfig
index 4439be7fa74d..3be17109301a 100644
--- a/drivers/hid/i2c-hid/Kconfig
+++ b/drivers/hid/i2c-hid/Kconfig
@@ -23,12 +23,14 @@ config I2C_HID_ACPI
 
 config I2C_HID_OF
 	tristate "HID over I2C transport layer Open Firmware driver"
-	depends on OF
+	# No "depends on OF" because this can also be used for manually
+	# (board-file) instantiated "hid-over-i2c" type i2c-clients.
 	select I2C_HID_CORE
 	help
 	  Say Y here if you use a keyboard, a touchpad, a touchscreen, or any
 	  other HID based devices which is connected to your computer via I2C.
-	  This driver supports Open Firmware (Device Tree)-based systems.
+	  This driver supports Open Firmware (Device Tree)-based systems as
+	  well as binding to manually (board-file) instantiated i2c-hid-clients.
 
 	  If unsure, say N.
 
diff --git a/drivers/hid/i2c-hid/i2c-hid-of.c b/drivers/hid/i2c-hid/i2c-hid-of.c
index c82a5a54c3e6..385f7460e03c 100644
--- a/drivers/hid/i2c-hid/i2c-hid-of.c
+++ b/drivers/hid/i2c-hid/i2c-hid-of.c
@@ -82,7 +82,7 @@ static int i2c_hid_of_probe(struct i2c_client *client)
 	ihid_of->ops.power_up = i2c_hid_of_power_up;
 	ihid_of->ops.power_down = i2c_hid_of_power_down;
 
-	ret = of_property_read_u32(dev->of_node, "hid-descr-addr", &val);
+	ret = device_property_read_u32(dev, "hid-descr-addr", &val);
 	if (ret) {
 		dev_err(dev, "HID register address not provided\n");
 		return -ENODEV;
@@ -113,11 +113,13 @@ static int i2c_hid_of_probe(struct i2c_client *client)
 				  hid_descriptor_address, quirks);
 }
 
+#ifdef CONFIG_OF
 static const struct of_device_id i2c_hid_of_match[] = {
 	{ .compatible = "hid-over-i2c" },
 	{},
 };
 MODULE_DEVICE_TABLE(of, i2c_hid_of_match);
+#endif
 
 static const struct i2c_device_id i2c_hid_of_id_table[] = {
 	{ "hid", 0 },
-- 
2.39.1


^ permalink raw reply related

* [PATCH 3/6] HID: i2c-hid-of: Add reset GPIO support to i2c-hid-of
From: Hans de Goede @ 2023-04-09 14:42 UTC (permalink / raw)
  To: Jiri Kosina, Benjamin Tissoires, Douglas Anderson
  Cc: Hans de Goede, linux-input
In-Reply-To: <20230409144243.25360-1-hdegoede@redhat.com>

Add reset GPIO support to the generic i2c-hid-of driver

This is necessary to make the Wacom digitizer on the Lenovo Yoga Book 1
(yb1-x90f/l) work and this will also allow consolidating the 2 specialized
i2c-hid-of-elan.c and i2c-hid-of-goodix.c drivers into the generic
i2c-hid-of driver.

For now the new "post-reset-deassert-delay-ms" property is only used on
x86/ACPI (non devicetree) devs. IOW it is not used in actual devicetree
files and the same goes for the reset GPIO. The devicetree-bindings
maintainers have requested properties like these to not be added to
the devicetree-bindings, so the new property + GPIO are deliberately
not added to the existing devicetree-bindings.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/hid/i2c-hid/i2c-hid-of.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/drivers/hid/i2c-hid/i2c-hid-of.c b/drivers/hid/i2c-hid/i2c-hid-of.c
index 385f7460e03c..d0289afa57dc 100644
--- a/drivers/hid/i2c-hid/i2c-hid-of.c
+++ b/drivers/hid/i2c-hid/i2c-hid-of.c
@@ -21,6 +21,7 @@
 
 #include <linux/delay.h>
 #include <linux/device.h>
+#include <linux/gpio/consumer.h>
 #include <linux/hid.h>
 #include <linux/i2c.h>
 #include <linux/kernel.h>
@@ -35,8 +36,10 @@ struct i2c_hid_of {
 	struct i2chid_ops ops;
 
 	struct i2c_client *client;
+	struct gpio_desc *reset_gpio;
 	struct regulator_bulk_data supplies[2];
 	int post_power_delay_ms;
+	int post_reset_delay_ms;
 };
 
 static int i2c_hid_of_power_up(struct i2chid_ops *ops)
@@ -55,6 +58,10 @@ static int i2c_hid_of_power_up(struct i2chid_ops *ops)
 	if (ihid_of->post_power_delay_ms)
 		msleep(ihid_of->post_power_delay_ms);
 
+	gpiod_set_value_cansleep(ihid_of->reset_gpio, 0);
+	if (ihid_of->post_reset_delay_ms)
+		msleep(ihid_of->post_reset_delay_ms);
+
 	return 0;
 }
 
@@ -62,6 +69,7 @@ static void i2c_hid_of_power_down(struct i2chid_ops *ops)
 {
 	struct i2c_hid_of *ihid_of = container_of(ops, struct i2c_hid_of, ops);
 
+	gpiod_set_value_cansleep(ihid_of->reset_gpio, 1);
 	regulator_bulk_disable(ARRAY_SIZE(ihid_of->supplies),
 			       ihid_of->supplies);
 }
@@ -96,6 +104,14 @@ static int i2c_hid_of_probe(struct i2c_client *client)
 	if (!device_property_read_u32(dev, "post-power-on-delay-ms", &val))
 		ihid_of->post_power_delay_ms = val;
 
+	if (!device_property_read_u32(dev, "post-reset-deassert-delay-ms", &val))
+		ihid_of->post_reset_delay_ms = val;
+
+	/* Start out with reset asserted */
+	ihid_of->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+	if (IS_ERR(ihid_of->reset_gpio))
+		return PTR_ERR(ihid_of->reset_gpio);
+
 	ihid_of->supplies[0].supply = "vdd";
 	ihid_of->supplies[1].supply = "vddl";
 	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ihid_of->supplies),
-- 
2.39.1


^ permalink raw reply related

* [PATCH 4/6] HID: i2c-hid-of: Add chip_data struct
From: Hans de Goede @ 2023-04-09 14:42 UTC (permalink / raw)
  To: Jiri Kosina, Benjamin Tissoires, Douglas Anderson
  Cc: Hans de Goede, linux-input
In-Reply-To: <20230409144243.25360-1-hdegoede@redhat.com>

Add a chip_data struct which can be used to set different supply-names
and default power-on-delay, reset-deassert-delay and hid_descriptor_address
values.

This is a preparation patch for consolidating the 2 specialized
i2c-hid-of-elan.c and i2c-hid-of-goodix.c drivers into the generic
i2c-hid-of driver.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/hid/i2c-hid/i2c-hid-of.c | 67 +++++++++++++++++++++++++-------
 1 file changed, 52 insertions(+), 15 deletions(-)

diff --git a/drivers/hid/i2c-hid/i2c-hid-of.c b/drivers/hid/i2c-hid/i2c-hid-of.c
index d0289afa57dc..4fafef1e36b9 100644
--- a/drivers/hid/i2c-hid/i2c-hid-of.c
+++ b/drivers/hid/i2c-hid/i2c-hid-of.c
@@ -32,24 +32,44 @@
 
 #include "i2c-hid.h"
 
+#define MAX_BULK_SUPPLIES	2
+
+struct i2c_hid_of_chip_data {
+	const char * const *supply_names;
+	int num_supplies;
+	int post_power_delay_ms;
+	int post_reset_delay_ms;
+	u16 hid_descriptor_address;
+};
+
 struct i2c_hid_of {
 	struct i2chid_ops ops;
 
 	struct i2c_client *client;
 	struct gpio_desc *reset_gpio;
-	struct regulator_bulk_data supplies[2];
+	struct regulator_bulk_data supplies[MAX_BULK_SUPPLIES];
+	int num_supplies;
 	int post_power_delay_ms;
 	int post_reset_delay_ms;
 };
 
+static const char * const i2c_hid_of_default_supply_names[] = {
+	"vdd",
+	"vddl",
+};
+
+static const struct i2c_hid_of_chip_data i2c_hid_of_default_chip_data = {
+	.supply_names = i2c_hid_of_default_supply_names,
+	.num_supplies = ARRAY_SIZE(i2c_hid_of_default_supply_names),
+};
+
 static int i2c_hid_of_power_up(struct i2chid_ops *ops)
 {
 	struct i2c_hid_of *ihid_of = container_of(ops, struct i2c_hid_of, ops);
 	struct device *dev = &ihid_of->client->dev;
 	int ret;
 
-	ret = regulator_bulk_enable(ARRAY_SIZE(ihid_of->supplies),
-				    ihid_of->supplies);
+	ret = regulator_bulk_enable(ihid_of->num_supplies, ihid_of->supplies);
 	if (ret) {
 		dev_warn(dev, "Failed to enable supplies: %d\n", ret);
 		return ret;
@@ -70,18 +90,28 @@ static void i2c_hid_of_power_down(struct i2chid_ops *ops)
 	struct i2c_hid_of *ihid_of = container_of(ops, struct i2c_hid_of, ops);
 
 	gpiod_set_value_cansleep(ihid_of->reset_gpio, 1);
-	regulator_bulk_disable(ARRAY_SIZE(ihid_of->supplies),
-			       ihid_of->supplies);
+	regulator_bulk_disable(ihid_of->num_supplies, ihid_of->supplies);
 }
 
 static int i2c_hid_of_probe(struct i2c_client *client)
 {
+	const struct i2c_hid_of_chip_data *chip_data;
 	struct device *dev = &client->dev;
 	struct i2c_hid_of *ihid_of;
 	u16 hid_descriptor_address;
 	u32 quirks = 0;
 	int ret;
 	u32 val;
+	int i;
+
+	chip_data = device_get_match_data(dev);
+	if (!chip_data)
+		chip_data = &i2c_hid_of_default_chip_data;
+
+	if (chip_data->num_supplies > MAX_BULK_SUPPLIES) {
+		dev_err(dev, "Error chip_data->num_supplies > MAX_BULK_SUPPLIES (internal kernel error)\n");
+		return -EINVAL;
+	}
 
 	ihid_of = devm_kzalloc(dev, sizeof(*ihid_of), GFP_KERNEL);
 	if (!ihid_of)
@@ -90,16 +120,22 @@ static int i2c_hid_of_probe(struct i2c_client *client)
 	ihid_of->ops.power_up = i2c_hid_of_power_up;
 	ihid_of->ops.power_down = i2c_hid_of_power_down;
 
+	/* chip_data as defaults, allow device-properties to override things */
+	ihid_of->post_power_delay_ms = chip_data->post_power_delay_ms;
+	ihid_of->post_reset_delay_ms = chip_data->post_reset_delay_ms;
+	hid_descriptor_address = chip_data->hid_descriptor_address;
+
 	ret = device_property_read_u32(dev, "hid-descr-addr", &val);
-	if (ret) {
+	if (ret == 0) {
+		if (val >> 16) {
+			dev_err(dev, "Bad HID register address: 0x%08x\n", val);
+			return -EINVAL;
+		}
+		hid_descriptor_address = val;
+	} else if (!hid_descriptor_address) {
 		dev_err(dev, "HID register address not provided\n");
 		return -ENODEV;
 	}
-	if (val >> 16) {
-		dev_err(dev, "Bad HID register address: 0x%08x\n", val);
-		return -EINVAL;
-	}
-	hid_descriptor_address = val;
 
 	if (!device_property_read_u32(dev, "post-power-on-delay-ms", &val))
 		ihid_of->post_power_delay_ms = val;
@@ -112,10 +148,11 @@ static int i2c_hid_of_probe(struct i2c_client *client)
 	if (IS_ERR(ihid_of->reset_gpio))
 		return PTR_ERR(ihid_of->reset_gpio);
 
-	ihid_of->supplies[0].supply = "vdd";
-	ihid_of->supplies[1].supply = "vddl";
-	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ihid_of->supplies),
-				      ihid_of->supplies);
+	ihid_of->num_supplies = chip_data->num_supplies;
+	for (i = 0; i < ihid_of->num_supplies; i++)
+		ihid_of->supplies[i].supply = chip_data->supply_names[i];
+
+	ret = devm_regulator_bulk_get(dev, ihid_of->num_supplies, ihid_of->supplies);
 	if (ret)
 		return ret;
 
-- 
2.39.1


^ permalink raw reply related

* [PATCH 5/6] HID: i2c-hid-of: Consolidate Elan support into generic i2c-hid-of driver
From: Hans de Goede @ 2023-04-09 14:42 UTC (permalink / raw)
  To: Jiri Kosina, Benjamin Tissoires, Douglas Anderson
  Cc: Hans de Goede, linux-input
In-Reply-To: <20230409144243.25360-1-hdegoede@redhat.com>

The generic i2c-hid-of driver nowsupports a reset GPIO and allows
setting the supply-names, hid_descriptor_address and delays through
match_data / chip_data.

This means that i2c-hid-of can be easily made to support
the elan,ekth6915 compatible directly and the i2c-hid-of-elan driver
can be dropped.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/hid/i2c-hid/Kconfig           |  15 ---
 drivers/hid/i2c-hid/Makefile          |   1 -
 drivers/hid/i2c-hid/i2c-hid-of-elan.c | 129 --------------------------
 drivers/hid/i2c-hid/i2c-hid-of.c      |  14 +++
 4 files changed, 14 insertions(+), 145 deletions(-)
 delete mode 100644 drivers/hid/i2c-hid/i2c-hid-of-elan.c

diff --git a/drivers/hid/i2c-hid/Kconfig b/drivers/hid/i2c-hid/Kconfig
index 3be17109301a..6aa7cf18fd2d 100644
--- a/drivers/hid/i2c-hid/Kconfig
+++ b/drivers/hid/i2c-hid/Kconfig
@@ -38,21 +38,6 @@ config I2C_HID_OF
 	  will be called i2c-hid-of.  It will also build/depend on the
 	  module i2c-hid.
 
-config I2C_HID_OF_ELAN
-	tristate "Driver for Elan hid-i2c based devices on OF systems"
-	depends on OF
-	select I2C_HID_CORE
-	help
-	  Say Y here if you want support for Elan i2c devices that use
-	  the i2c-hid protocol on Open Firmware (Device Tree)-based
-	  systems.
-
-	  If unsure, say N.
-
-	  This support is also available as a module.  If so, the module
-	  will be called i2c-hid-of-elan.  It will also build/depend on
-	  the module i2c-hid.
-
 config I2C_HID_OF_GOODIX
 	tristate "Driver for Goodix hid-i2c based devices on OF systems"
 	depends on OF
diff --git a/drivers/hid/i2c-hid/Makefile b/drivers/hid/i2c-hid/Makefile
index 55bd5e0f35af..302545a771f3 100644
--- a/drivers/hid/i2c-hid/Makefile
+++ b/drivers/hid/i2c-hid/Makefile
@@ -10,5 +10,4 @@ i2c-hid-$(CONFIG_DMI)				+= i2c-hid-dmi-quirks.o
 
 obj-$(CONFIG_I2C_HID_ACPI)			+= i2c-hid-acpi.o
 obj-$(CONFIG_I2C_HID_OF)			+= i2c-hid-of.o
-obj-$(CONFIG_I2C_HID_OF_ELAN)			+= i2c-hid-of-elan.o
 obj-$(CONFIG_I2C_HID_OF_GOODIX)			+= i2c-hid-of-goodix.o
diff --git a/drivers/hid/i2c-hid/i2c-hid-of-elan.c b/drivers/hid/i2c-hid/i2c-hid-of-elan.c
deleted file mode 100644
index 76ddc8be1cbb..000000000000
--- a/drivers/hid/i2c-hid/i2c-hid-of-elan.c
+++ /dev/null
@@ -1,129 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Driver for Elan touchscreens that use the i2c-hid protocol.
- *
- * Copyright 2020 Google LLC
- */
-
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/gpio/consumer.h>
-#include <linux/i2c.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/pm.h>
-#include <linux/regulator/consumer.h>
-
-#include "i2c-hid.h"
-
-struct elan_i2c_hid_chip_data {
-	unsigned int post_gpio_reset_delay_ms;
-	unsigned int post_power_delay_ms;
-	u16 hid_descriptor_address;
-};
-
-struct i2c_hid_of_elan {
-	struct i2chid_ops ops;
-
-	struct regulator *vcc33;
-	struct regulator *vccio;
-	struct gpio_desc *reset_gpio;
-	const struct elan_i2c_hid_chip_data *chip_data;
-};
-
-static int elan_i2c_hid_power_up(struct i2chid_ops *ops)
-{
-	struct i2c_hid_of_elan *ihid_elan =
-		container_of(ops, struct i2c_hid_of_elan, ops);
-	int ret;
-
-	ret = regulator_enable(ihid_elan->vcc33);
-	if (ret)
-		return ret;
-
-	ret = regulator_enable(ihid_elan->vccio);
-	if (ret) {
-		regulator_disable(ihid_elan->vcc33);
-		return ret;
-	}
-
-	if (ihid_elan->chip_data->post_power_delay_ms)
-		msleep(ihid_elan->chip_data->post_power_delay_ms);
-
-	gpiod_set_value_cansleep(ihid_elan->reset_gpio, 0);
-	if (ihid_elan->chip_data->post_gpio_reset_delay_ms)
-		msleep(ihid_elan->chip_data->post_gpio_reset_delay_ms);
-
-	return 0;
-}
-
-static void elan_i2c_hid_power_down(struct i2chid_ops *ops)
-{
-	struct i2c_hid_of_elan *ihid_elan =
-		container_of(ops, struct i2c_hid_of_elan, ops);
-
-	gpiod_set_value_cansleep(ihid_elan->reset_gpio, 1);
-	regulator_disable(ihid_elan->vccio);
-	regulator_disable(ihid_elan->vcc33);
-}
-
-static int i2c_hid_of_elan_probe(struct i2c_client *client)
-{
-	struct i2c_hid_of_elan *ihid_elan;
-
-	ihid_elan = devm_kzalloc(&client->dev, sizeof(*ihid_elan), GFP_KERNEL);
-	if (!ihid_elan)
-		return -ENOMEM;
-
-	ihid_elan->ops.power_up = elan_i2c_hid_power_up;
-	ihid_elan->ops.power_down = elan_i2c_hid_power_down;
-
-	/* Start out with reset asserted */
-	ihid_elan->reset_gpio =
-		devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_HIGH);
-	if (IS_ERR(ihid_elan->reset_gpio))
-		return PTR_ERR(ihid_elan->reset_gpio);
-
-	ihid_elan->vccio = devm_regulator_get(&client->dev, "vccio");
-	if (IS_ERR(ihid_elan->vccio))
-		return PTR_ERR(ihid_elan->vccio);
-
-	ihid_elan->vcc33 = devm_regulator_get(&client->dev, "vcc33");
-	if (IS_ERR(ihid_elan->vcc33))
-		return PTR_ERR(ihid_elan->vcc33);
-
-	ihid_elan->chip_data = device_get_match_data(&client->dev);
-
-	return i2c_hid_core_probe(client, &ihid_elan->ops,
-				  ihid_elan->chip_data->hid_descriptor_address, 0);
-}
-
-static const struct elan_i2c_hid_chip_data elan_ekth6915_chip_data = {
-	.post_power_delay_ms = 1,
-	.post_gpio_reset_delay_ms = 300,
-	.hid_descriptor_address = 0x0001,
-};
-
-static const struct of_device_id elan_i2c_hid_of_match[] = {
-	{ .compatible = "elan,ekth6915", .data = &elan_ekth6915_chip_data },
-	{ }
-};
-MODULE_DEVICE_TABLE(of, elan_i2c_hid_of_match);
-
-static struct i2c_driver elan_i2c_hid_ts_driver = {
-	.driver = {
-		.name	= "i2c_hid_of_elan",
-		.pm	= &i2c_hid_core_pm,
-		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
-		.of_match_table = of_match_ptr(elan_i2c_hid_of_match),
-	},
-	.probe_new	= i2c_hid_of_elan_probe,
-	.remove		= i2c_hid_core_remove,
-	.shutdown	= i2c_hid_core_shutdown,
-};
-module_i2c_driver(elan_i2c_hid_ts_driver);
-
-MODULE_AUTHOR("Douglas Anderson <dianders@chromium.org>");
-MODULE_DESCRIPTION("Elan i2c-hid touchscreen driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/hid/i2c-hid/i2c-hid-of.c b/drivers/hid/i2c-hid/i2c-hid-of.c
index 4fafef1e36b9..313eb198d840 100644
--- a/drivers/hid/i2c-hid/i2c-hid-of.c
+++ b/drivers/hid/i2c-hid/i2c-hid-of.c
@@ -167,8 +167,22 @@ static int i2c_hid_of_probe(struct i2c_client *client)
 }
 
 #ifdef CONFIG_OF
+static const char * const elan_ekth6915_supply_names[] = {
+	"vcc33",
+	"vccio",
+};
+
+static const struct i2c_hid_of_chip_data elan_ekth6915_chip_data = {
+	.supply_names = elan_ekth6915_supply_names,
+	.num_supplies = ARRAY_SIZE(elan_ekth6915_supply_names),
+	.post_power_delay_ms = 1,
+	.post_reset_delay_ms = 300,
+	.hid_descriptor_address = 0x0001,
+};
+
 static const struct of_device_id i2c_hid_of_match[] = {
 	{ .compatible = "hid-over-i2c" },
+	{ .compatible = "elan,ekth6915", .data = &elan_ekth6915_chip_data },
 	{},
 };
 MODULE_DEVICE_TABLE(of, i2c_hid_of_match);
-- 
2.39.1


^ permalink raw reply related

* [PATCH 6/6] HID: i2c-hid-of: Consolidate Goodix support into generic i2c-hid-of driver
From: Hans de Goede @ 2023-04-09 14:42 UTC (permalink / raw)
  To: Jiri Kosina, Benjamin Tissoires, Douglas Anderson
  Cc: Hans de Goede, linux-input
In-Reply-To: <20230409144243.25360-1-hdegoede@redhat.com>

The generic i2c-hid-of driver nowsupports a reset GPIO and allows
setting the supply-names, hid_descriptor_address and delays through
match_data / chip_data.

This means that i2c-hid-of can be easily made to support
the goodix,gt7375p compatible directly and the i2c-hid-of-goodix
driver can be dropped.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/hid/i2c-hid/Kconfig             |  15 ---
 drivers/hid/i2c-hid/Makefile            |   1 -
 drivers/hid/i2c-hid/i2c-hid-of-goodix.c | 125 ------------------------
 drivers/hid/i2c-hid/i2c-hid-of.c        |  14 +++
 4 files changed, 14 insertions(+), 141 deletions(-)
 delete mode 100644 drivers/hid/i2c-hid/i2c-hid-of-goodix.c

diff --git a/drivers/hid/i2c-hid/Kconfig b/drivers/hid/i2c-hid/Kconfig
index 6aa7cf18fd2d..10e4b368b818 100644
--- a/drivers/hid/i2c-hid/Kconfig
+++ b/drivers/hid/i2c-hid/Kconfig
@@ -38,21 +38,6 @@ config I2C_HID_OF
 	  will be called i2c-hid-of.  It will also build/depend on the
 	  module i2c-hid.
 
-config I2C_HID_OF_GOODIX
-	tristate "Driver for Goodix hid-i2c based devices on OF systems"
-	depends on OF
-	select I2C_HID_CORE
-	help
-	  Say Y here if you want support for Goodix i2c devices that use
-	  the i2c-hid protocol on Open Firmware (Device Tree)-based
-	  systems.
-
-	  If unsure, say N.
-
-	  This support is also available as a module.  If so, the module
-	  will be called i2c-hid-of-goodix.  It will also build/depend on
-	  the module i2c-hid.
-
 config I2C_HID_CORE
 	tristate
 endif
diff --git a/drivers/hid/i2c-hid/Makefile b/drivers/hid/i2c-hid/Makefile
index 302545a771f3..9b4a73446841 100644
--- a/drivers/hid/i2c-hid/Makefile
+++ b/drivers/hid/i2c-hid/Makefile
@@ -10,4 +10,3 @@ i2c-hid-$(CONFIG_DMI)				+= i2c-hid-dmi-quirks.o
 
 obj-$(CONFIG_I2C_HID_ACPI)			+= i2c-hid-acpi.o
 obj-$(CONFIG_I2C_HID_OF)			+= i2c-hid-of.o
-obj-$(CONFIG_I2C_HID_OF_GOODIX)			+= i2c-hid-of-goodix.o
diff --git a/drivers/hid/i2c-hid/i2c-hid-of-goodix.c b/drivers/hid/i2c-hid/i2c-hid-of-goodix.c
deleted file mode 100644
index 0060e3dcd775..000000000000
--- a/drivers/hid/i2c-hid/i2c-hid-of-goodix.c
+++ /dev/null
@@ -1,125 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Driver for Goodix touchscreens that use the i2c-hid protocol.
- *
- * Copyright 2020 Google LLC
- */
-
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/gpio/consumer.h>
-#include <linux/i2c.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/pm.h>
-#include <linux/regulator/consumer.h>
-
-#include "i2c-hid.h"
-
-struct goodix_i2c_hid_timing_data {
-	unsigned int post_gpio_reset_delay_ms;
-	unsigned int post_power_delay_ms;
-};
-
-struct i2c_hid_of_goodix {
-	struct i2chid_ops ops;
-
-	struct regulator *vdd;
-	struct regulator *vddio;
-	struct gpio_desc *reset_gpio;
-	const struct goodix_i2c_hid_timing_data *timings;
-};
-
-static int goodix_i2c_hid_power_up(struct i2chid_ops *ops)
-{
-	struct i2c_hid_of_goodix *ihid_goodix =
-		container_of(ops, struct i2c_hid_of_goodix, ops);
-	int ret;
-
-	ret = regulator_enable(ihid_goodix->vdd);
-	if (ret)
-		return ret;
-
-	ret = regulator_enable(ihid_goodix->vddio);
-	if (ret)
-		return ret;
-
-	if (ihid_goodix->timings->post_power_delay_ms)
-		msleep(ihid_goodix->timings->post_power_delay_ms);
-
-	gpiod_set_value_cansleep(ihid_goodix->reset_gpio, 0);
-	if (ihid_goodix->timings->post_gpio_reset_delay_ms)
-		msleep(ihid_goodix->timings->post_gpio_reset_delay_ms);
-
-	return 0;
-}
-
-static void goodix_i2c_hid_power_down(struct i2chid_ops *ops)
-{
-	struct i2c_hid_of_goodix *ihid_goodix =
-		container_of(ops, struct i2c_hid_of_goodix, ops);
-
-	gpiod_set_value_cansleep(ihid_goodix->reset_gpio, 1);
-	regulator_disable(ihid_goodix->vddio);
-	regulator_disable(ihid_goodix->vdd);
-}
-
-static int i2c_hid_of_goodix_probe(struct i2c_client *client)
-{
-	struct i2c_hid_of_goodix *ihid_goodix;
-
-	ihid_goodix = devm_kzalloc(&client->dev, sizeof(*ihid_goodix),
-				   GFP_KERNEL);
-	if (!ihid_goodix)
-		return -ENOMEM;
-
-	ihid_goodix->ops.power_up = goodix_i2c_hid_power_up;
-	ihid_goodix->ops.power_down = goodix_i2c_hid_power_down;
-
-	/* Start out with reset asserted */
-	ihid_goodix->reset_gpio =
-		devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_HIGH);
-	if (IS_ERR(ihid_goodix->reset_gpio))
-		return PTR_ERR(ihid_goodix->reset_gpio);
-
-	ihid_goodix->vdd = devm_regulator_get(&client->dev, "vdd");
-	if (IS_ERR(ihid_goodix->vdd))
-		return PTR_ERR(ihid_goodix->vdd);
-
-	ihid_goodix->vddio = devm_regulator_get(&client->dev, "mainboard-vddio");
-	if (IS_ERR(ihid_goodix->vddio))
-		return PTR_ERR(ihid_goodix->vddio);
-
-	ihid_goodix->timings = device_get_match_data(&client->dev);
-
-	return i2c_hid_core_probe(client, &ihid_goodix->ops, 0x0001, 0);
-}
-
-static const struct goodix_i2c_hid_timing_data goodix_gt7375p_timing_data = {
-	.post_power_delay_ms = 10,
-	.post_gpio_reset_delay_ms = 180,
-};
-
-static const struct of_device_id goodix_i2c_hid_of_match[] = {
-	{ .compatible = "goodix,gt7375p", .data = &goodix_gt7375p_timing_data },
-	{ }
-};
-MODULE_DEVICE_TABLE(of, goodix_i2c_hid_of_match);
-
-static struct i2c_driver goodix_i2c_hid_ts_driver = {
-	.driver = {
-		.name	= "i2c_hid_of_goodix",
-		.pm	= &i2c_hid_core_pm,
-		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
-		.of_match_table = of_match_ptr(goodix_i2c_hid_of_match),
-	},
-	.probe_new	= i2c_hid_of_goodix_probe,
-	.remove		= i2c_hid_core_remove,
-	.shutdown	= i2c_hid_core_shutdown,
-};
-module_i2c_driver(goodix_i2c_hid_ts_driver);
-
-MODULE_AUTHOR("Douglas Anderson <dianders@chromium.org>");
-MODULE_DESCRIPTION("Goodix i2c-hid touchscreen driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/hid/i2c-hid/i2c-hid-of.c b/drivers/hid/i2c-hid/i2c-hid-of.c
index 313eb198d840..7f298210447a 100644
--- a/drivers/hid/i2c-hid/i2c-hid-of.c
+++ b/drivers/hid/i2c-hid/i2c-hid-of.c
@@ -180,9 +180,23 @@ static const struct i2c_hid_of_chip_data elan_ekth6915_chip_data = {
 	.hid_descriptor_address = 0x0001,
 };
 
+static const char * const goodix_gt7375p_supply_names[] = {
+	"vdd",
+	"mainboard-vddio",
+};
+
+static const struct i2c_hid_of_chip_data goodix_gt7375p_chip_data = {
+	.supply_names = goodix_gt7375p_supply_names,
+	.num_supplies = ARRAY_SIZE(goodix_gt7375p_supply_names),
+	.post_power_delay_ms = 10,
+	.post_reset_delay_ms = 180,
+	.hid_descriptor_address = 0x0001,
+};
+
 static const struct of_device_id i2c_hid_of_match[] = {
 	{ .compatible = "hid-over-i2c" },
 	{ .compatible = "elan,ekth6915", .data = &elan_ekth6915_chip_data },
+	{ .compatible = "goodix,gt7375p", .data = &goodix_gt7375p_chip_data },
 	{},
 };
 MODULE_DEVICE_TABLE(of, i2c_hid_of_match);
-- 
2.39.1


^ permalink raw reply related

* [PATCH] HID: wacom: Set a default resolution for older tablets
From: Ping Cheng @ 2023-04-09 16:42 UTC (permalink / raw)
  To: linux-input
  Cc: jkosina, jason.gerecke, aaron.skomra, joshua.dickens, Ping Cheng

Some older tablets may not report physical maximum for X/Y
coordinates. Set a default to prevent undefined resolution.

Signed-off-by: Ping Cheng <ping.cheng@wacom.com>
---
 drivers/hid/wacom_wac.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
index 9312d611db8e..e499b447d48c 100644
--- a/drivers/hid/wacom_wac.c
+++ b/drivers/hid/wacom_wac.c
@@ -1895,6 +1895,7 @@ static void wacom_map_usage(struct input_dev *input, struct hid_usage *usage,
 	int fmax = field->logical_maximum;
 	unsigned int equivalent_usage = wacom_equivalent_usage(usage->hid);
 	int resolution_code = code;
+	int resolution = hidinput_calc_abs_res(field, resolution_code);
 
 	if (equivalent_usage == HID_DG_TWIST) {
 		resolution_code = ABS_RZ;
@@ -1915,8 +1916,15 @@ static void wacom_map_usage(struct input_dev *input, struct hid_usage *usage,
 	switch (type) {
 	case EV_ABS:
 		input_set_abs_params(input, code, fmin, fmax, fuzz, 0);
-		input_abs_set_res(input, code,
-				  hidinput_calc_abs_res(field, resolution_code));
+
+		/* older tablet may miss physical usage */
+		if ((code == ABS_X || code == ABS_Y) && !resolution) {
+			resolution = WACOM_INTUOS_RES;
+			hid_warn(input,
+				 "Wacom usage (%d) missing resolution \n",
+				 code);
+		}
+		input_abs_set_res(input, code, resolution);
 		break;
 	case EV_KEY:
 	case EV_MSC:
-- 
2.39.2


^ permalink raw reply related

* RE: [PATCH] Input: elan_i2c - Implement inhibit/uninhibit functions.
From: Jingle.Wu @ 2023-04-10  1:26 UTC (permalink / raw)
  To: 'Dmitry Torokhov'
  Cc: linux-kernel, linux-input, phoenix, josh.chen, dave.wang
In-Reply-To: <ZDBKwo4UMUm+TSnj@penguin>

HI Dmitry:

> +static void elan_close(struct input_dev *input_dev) {
> +	if ((input_dev->users) && (!input_dev->inhibited))
> +		elan_inhibit(input_dev);

This check is for "only inhibit request", and elan_open() its check is for
"only uninhibit request".
Because input_dev-> open() close() will be executed 2-3 times when initial.

Thanks
Jingle

-----Original Message-----
From: Dmitry Torokhov [mailto:dmitry.torokhov@gmail.com] 
Sent: Saturday, April 8, 2023 12:57 AM
To: jingle.wu <jingle.wu@emc.com.tw>
Cc: linux-kernel@vger.kernel.org; linux-input@vger.kernel.org;
phoenix@emc.com.tw; josh.chen@emc.com.tw; dave.wang@emc.com.tw
Subject: Re: [PATCH] Input: elan_i2c - Implement inhibit/uninhibit
functions.

Hi Jingle,

On Mon, Mar 20, 2023 at 09:14:56AM +0800, jingle.wu wrote:
> Add inhibit/uninhibit functions.
> 
> Signed-off-by: Jingle.wu <jingle.wu@emc.com.tw>
> ---
>  drivers/input/mouse/elan_i2c_core.c | 86 
> +++++++++++++++++++++++++++++
>  1 file changed, 86 insertions(+)
> 
> diff --git a/drivers/input/mouse/elan_i2c_core.c 
> b/drivers/input/mouse/elan_i2c_core.c
> index 5f0d75a45c80..b7100945c9cc 100644
> --- a/drivers/input/mouse/elan_i2c_core.c
> +++ b/drivers/input/mouse/elan_i2c_core.c
> @@ -329,6 +329,89 @@ static int elan_initialize(struct elan_tp_data *data,
bool skip_reset)
>  	return error;
>  }
>  
> +static int elan_reactivate(struct elan_tp_data *data) {
> +	struct device *dev = &data->client->dev;
> +	int ret;

Please call this variable and other similar ones "error".

> +
> +	ret = elan_set_power(data, true);
> +	if (ret)
> +		dev_err(dev, "failed to restore power: %d\n", ret);
> +
> +	ret = data->ops->sleep_control(data->client, false);
> +	if (ret) {
> +		dev_err(dev,
> +			"failed to wake device up: %d\n", ret);
> +		return ret;
> +	}
> +
> +	return ret;

return 0;

> +}
> +
> +static void elan_inhibit(struct input_dev *input_dev) {
> +	struct elan_tp_data *data = input_get_drvdata(input_dev);
> +	struct i2c_client *client = data->client;
> +	int ret;
> +
> +	if (data->in_fw_update)
> +		return;

Simply and silently ignoring inhibit request is not great. Can we wait for
firmware update to complete?

> +
> +	dev_dbg(&client->dev, "inhibiting\n");
> +	/*
> +	 * We are taking the mutex to make sure sysfs operations are
> +	 * complete before we attempt to bring the device into low[er]
> +	 * power mode.
> +	 */
> +	ret = mutex_lock_interruptible(&data->sysfs_mutex);
> +	if (ret)
> +		return;
> +
> +	disable_irq(client->irq);
> +
> +	ret = elan_set_power(data, false);
> +	if (ret)
> +		enable_irq(client->irq);
> +
> +	mutex_unlock(&data->sysfs_mutex);
> +
> +}
> +
> +static void elan_close(struct input_dev *input_dev) {
> +	if ((input_dev->users) && (!input_dev->inhibited))
> +		elan_inhibit(input_dev);

I am not sure why you need these checks. Input core will only call
input_dev->close() when device is powered up st (i.e. it is not inhibited
and there are users of it) and when either:

- there is inhibit request or
- the last user is letting go of the device

Similarly elan_open() will be called when first user opens device if device
is not inhibited, or when request to uninhibit comes for inhibited device
that has users.

But you need to make sure you start in a low power state.

Thanks.

--
Dmitry


^ permalink raw reply

* Re: [PATCH 2/2] Input: xpad - fix PowerA EnWired Controller guide button
From: Dmitry Torokhov @ 2023-04-10  2:09 UTC (permalink / raw)
  To: Vicki Pfau; +Cc: Benjamin Tissoires, linux-input, Pavel Rojtberg
In-Reply-To: <a02e0ba4-4ea7-40a0-1d33-8f87f2fe8f2f@endrift.com>

On Wed, Apr 05, 2023 at 07:40:32PM -0700, Vicki Pfau wrote:
> 
> 
> On 4/1/23 14:41, Dmitry Torokhov wrote:
> > On Wed, Mar 29, 2023 at 07:47:52PM -0700, Vicki Pfau wrote:
> >> This commit explicitly disables the audio interface the same way the official
> >> driver does. This is needed for some controllers, such as the PowerA Enhanced
> >> Wired Controller for Series X|S (0x20d6:0x200e) to report the guide button.
> >>
> >> Signed-off-by: Vicki Pfau <vi@endrift.com>
> >> ---
> >>  drivers/input/joystick/xpad.c | 8 ++++++++
> >>  1 file changed, 8 insertions(+)
> >>
> >> diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
> >> index 698224e1948f..c31fc4e9b310 100644
> >> --- a/drivers/input/joystick/xpad.c
> >> +++ b/drivers/input/joystick/xpad.c
> >> @@ -1396,6 +1396,14 @@ static int xpad_start_xbox_one(struct usb_xpad *xpad)
> >>  	unsigned long flags;
> >>  	int retval;
> >>  
> >> +	/* Explicitly disable the audio interface. This is needed for some
> >> +	 * controllers, such as the PowerA Enhanced Wired Controller
> >> +	 * for Series X|S (0x20d6:0x200e) to report the guide button */
> >> +	retval = usb_set_interface(xpad->udev, GIP_WIRED_INTF_AUDIO, 0);
> >> +	if (retval)
> >> +		dev_warn(&xpad->dev->dev,
> >> +			 "unable to disable audio interface: %d\n", retval);
> > 
> > I would prefer if we first validated that the interface is in fact
> > present. Can we do something like:
> > 
> > 	if (usb_ifnum_to_if(xpad->udev, GIP_WIRED_INTF_AUDIO)) {
> > 		error = usb_set_interface(xpad->udev, GIP_WIRED_INTF_AUDIO, 0);
> > 		if (error)
> > 			...
> > 	}
> > 
> 
> Yup, that makes sense. Wasn't sure what the cleanest way to do that was, though I'm unconvinced that the first party driver would work without this interface. It can't hurt to add the check.
> 
> Should I resubmit both patches in the series, or just this one?

Both please.

Thanks.

-- 
Dmitry

^ permalink raw reply

* Re: [PATCH v2] Input: cma3000_d0x - Remove duplicate code
From: Dmitry Torokhov @ 2023-04-10  2:10 UTC (permalink / raw)
  To: Jiapeng Chong; +Cc: linux-input, linux-kernel, Abaci Robot
In-Reply-To: <20230407021343.63512-1-jiapeng.chong@linux.alibaba.com>

On Fri, Apr 07, 2023 at 10:13:43AM +0800, Jiapeng Chong wrote:
> Function input_set_abs_params() has already set EV_ABS bit for us.
> 
> drivers/input/misc/cma3000_d0x.c:328 cma3000_init() warn: inconsistent indenting.
> 
> Reported-by: Abaci Robot <abaci@linux.alibaba.com>
> Link: https://bugzilla.openanolis.cn/show_bug.cgi?id=4588
> Signed-off-by: Jiapeng Chong <jiapeng.chong@linux.alibaba.com>

Applied, thank you.

-- 
Dmitry

^ permalink raw reply

* Re: [PATCH] Input: Check sanity of pipe in pegasus_probe()
From: Dmitry Torokhov @ 2023-04-10  2:24 UTC (permalink / raw)
  To: Soumya Negi; +Cc: linux-input, linux-kernel
In-Reply-To: <20230404074145.11523-1-soumya.negi97@gmail.com>

On Tue, Apr 04, 2023 at 12:41:45AM -0700, Soumya Negi wrote:
> Fix WARNING in pegasus_open/usb_submit_urb
> Syzbot bug: https://syzkaller.appspot.com/bug?id=bbc107584dcf3262253ce93183e51f3612aaeb13
> 
> Warning raised because pegasus_driver submits transfer request for
> bogus URB(pipe type does not match endpoint type). Add sanity check at
> probe time for pipe value extracted from endpoint descriptor. Probe
> will fail if sanity check fails.
> 
> Reported-and-tested-by: syzbot+04ee0cb4caccaed12d78@syzkaller.appspotmail.com
> Signed-off-by: Soumya Negi <soumya.negi97@gmail.com>

Applied, thank you.

-- 
Dmitry

^ permalink raw reply

* Re: [PATCH 2/2] input: imx_sc_key: add wakeup support
From: Dmitry Torokhov @ 2023-04-10  2:30 UTC (permalink / raw)
  To: Peng Fan (OSS)
  Cc: robh+dt, krzysztof.kozlowski+dt, shawnguo, aisheng.dong,
	linux-input, devicetree, linux-kernel, linux-arm-kernel, s.hauer,
	kernel, festevam, linux-imx, Peng Fan
In-Reply-To: <20230323093141.4070840-2-peng.fan@oss.nxp.com>

On Thu, Mar 23, 2023 at 05:31:41PM +0800, Peng Fan (OSS) wrote:
> From: Peng Fan <peng.fan@nxp.com>
> 
> Add support for waking up from system wide suspend.
> 
> Signed-off-by: Peng Fan <peng.fan@nxp.com>
> ---
>  drivers/input/keyboard/imx_sc_key.c | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/drivers/input/keyboard/imx_sc_key.c b/drivers/input/keyboard/imx_sc_key.c
> index d18839f1f4f6..234f23cf9990 100644
> --- a/drivers/input/keyboard/imx_sc_key.c
> +++ b/drivers/input/keyboard/imx_sc_key.c
> @@ -151,6 +151,8 @@ static int imx_sc_key_probe(struct platform_device *pdev)
>  	priv->input = input;
>  	platform_set_drvdata(pdev, priv);
>  
> +	device_init_wakeup(&pdev->dev, device_property_read_bool(&pdev->dev, "wakeup-source"));
> +

I wonder - could we move this to the device core?

>  	error = imx_scu_irq_group_enable(SC_IRQ_GROUP_WAKE, SC_IRQ_BUTTON,
>  					 true);
>  	if (error) {
> -- 
> 2.37.1
> 

Thanks.

-- 
Dmitry

^ permalink raw reply

* Re: [PATCH 1/2] Input: cs40l26: Support for CS40L26 Boosted Haptic Amplifier
From: Charles Keepax @ 2023-04-10  8:56 UTC (permalink / raw)
  To: Jeff LaBundy
  Cc: Fred Treven, dmitry.torokhov, ben.bright, james.ogletree, lee,
	jdelvare, joel, cy_huang, rdunlap, eajames, ping.bai, msp, arnd,
	bartosz.golaszewski, linux-kernel, linux-input, patches
In-Reply-To: <ZDI0p5Rkp74SzJCv@nixie71>

On Sat, Apr 08, 2023 at 10:44:39PM -0500, Jeff LaBundy wrote:

Hi Jeff,

Thanks for the detailed review, very much appreciated. I agree
with most of your comments, save a couple of exceptions below,
well and one that I just felt the need to agree with you
explictly:

> > +static bool cs40l26_readable_reg(struct device *dev, unsigned int reg)
> > +{
> > +	switch (reg) {
> > +	case CS40L26_DEVID ... CS40L26_REVID:
> > +	case CS40L26_TEST_KEY_CTRL:
> > +	case CS40L26_GLOBAL_ENABLES:
> > +	case CS40L26_ERROR_RELEASE:
> > +	case CS40L26_PWRMGT_CTL ... CS40L26_PWRMGT_STS:
> > +	case CS40L26_REFCLK_INPUT:
> > +	case CS40L26_PLL_REFCLK_DETECT_0:
> > +	case CS40L26_VBST_CTL_1 ... CS40L26_BST_IPK_CTL:
> > +	case CS40L26_TEST_LBST:
> > +	case CS40L26_NGATE1_INPUT:
> > +	case CS40L26_DAC_MSM_CONFIG ... CS40L26_TST_DAC_MSM_CONFIG:
> > +	case CS40L26_IRQ1_STATUS:
> > +	case CS40L26_IRQ1_EINT_1 ... CS40L26_IRQ1_EINT_5:
> > +	case CS40L26_IRQ1_STS_1 ... CS40L26_IRQ1_STS_5:
> > +	case CS40L26_IRQ1_MASK_1 ... CS40L26_IRQ1_MASK_5:
> > +	case CS40L26_MIXER_NGATE_CH1_CFG:
> > +	case CS40L26_DSP_MBOX_1 ... CS40L26_DSP_VIRTUAL2_MBOX_8:
> > +	case CS40L26_OTP_MEM0 ... CS40L26_OTP_MEM31:
> > +	case CS40L26_DSP1_XMEM_PACKED_0 ... CS40L26_DSP1_XMEM_PACKED_6143:
> > +	case CS40L26_DSP1_XROM_PACKED_0 ... CS40L26_DSP1_XROM_PACKED_4604:
> > +	case CS40L26_DSP1_XMEM_UNPACKED32_0 ... CS40L26_DSP1_XROM_UNPACKED32_3070:
> > +	case CS40L26_DSP1_SYS_INFO_ID:
> > +	case CS40L26_DSP1_XMEM_UNPACKED24_0 ... CS40L26_DSP1_XMEM_UNPACKED24_8191:
> > +	case CS40L26_DSP1_XROM_UNPACKED24_0 ... CS40L26_DSP1_XROM_UNPACKED24_6141:
> > +	case CS40L26_DSP1_CCM_CORE_CONTROL:
> > +	case CS40L26_DSP1_YMEM_PACKED_0 ... CS40L26_DSP1_YMEM_PACKED_1532:
> > +	case CS40L26_DSP1_YMEM_UNPACKED32_0 ... CS40L26_DSP1_YMEM_UNPACKED32_1022:
> > +	case CS40L26_DSP1_YMEM_UNPACKED24_0 ... CS40L26_DSP1_YMEM_UNPACKED24_2045:
> > +	case CS40L26_DSP1_PMEM_0 ... CS40L26_DSP1_PMEM_5114:
> > +	case CS40L26_DSP1_PROM_0 ... CS40L26_DSP1_PROM_30714:
> > +		return true;
> > +	default:
> > +		return false;
> > +	}
> 
> Is this function necessary? Are there cases throughout the driver that may
> attempt to read an illegal register, and you depend on the regmap call to
> fail? If not, I think you can just drop this function.
> 

I would much rather we kept this one, at the very least such
that the debugfs representation of the regmap shows the correct
registers.

> > +static inline void cs40l26_pm_runtime_setup(struct cs40l26_private *cs40l26)
> > +{
> > +	pm_runtime_mark_last_busy(cs40l26->dev);
> > +	pm_runtime_use_autosuspend(cs40l26->dev);
> > +	pm_runtime_set_autosuspend_delay(cs40l26->dev, CS40L26_AUTOSUSPEND_DELAY_MS);
> > +	pm_runtime_enable(cs40l26->dev);
> 
> My first impression was that this driver is doing an uncommonly large
> amount of PM-related housekeeping. In fact, not a single haptic driver
> in mainline is calling any of these. What is unique about this device
> that calls for this much overhead?
> 
> Can the device wake up from hibernation (AoH?) from both control port
> and GPIO triggers? If so, why not to simply allow the device to hibernate
> at its own discretion and avoid all PM-related housekeeping? Stated
> another way, it seems some of the DSP's job is unnecessarily duplicated
> in the kernel.
> 
> In case I have misunderstood, please let me know.
> 

I would far rather not have every single attempt to communicate
with the device wrapped in a retry if the communication failed
incase the device is hibernating. It seems much cleaner, and less
likely to risk odd behaviour, to know we have brought the device
out of hibernation.

> > +static int cs40l26_irq_update_mask(struct cs40l26_private *cs40l26, u32 reg, u32 val, u32 bit_mask)
> > +{
> > +	u32 eint_reg, cur_mask, new_mask;
> > +	int ret;
> > +
> > +	if (reg == CS40L26_IRQ1_MASK_1) {
> > +		eint_reg = CS40L26_IRQ1_EINT_1;
> > +	} else if (reg == CS40L26_IRQ1_MASK_2) {
> > +		eint_reg = CS40L26_IRQ1_EINT_2;
> > +	} else {
> > +		dev_err(cs40l26->dev, "Invalid IRQ mask reg: 0x%08X\n", reg);
> > +		return -EINVAL;
> > +	}
> > +
> > +	ret = regmap_read(cs40l26->regmap, reg, &cur_mask);
> > +	if (ret) {
> > +		dev_err(cs40l26->dev, "Failed to get IRQ mask\n");
> 
> Having a custom error message for every possible failed register read
> does not ultimately aid in debugging and unnecessarily grows the size
> of the driver.
> 
> If a specific message is absolutely necessary, then add wrappers around
> regmap_read/write and print the failed address. However, this does not
> seem necessary either. Simply propagate the error code all the way up
> to the caller, whether it is probe or a sysfs attribute.
> 
> Stated another way:
> 
> error = regmap_...(...);
> if (error)
> 	return error;
> 

Not sure I feel super strongly on this one, but I do find when
debugging issues on drivers that do this that I usually end up
adding the printks back in.

> > +static int cs40l26_dsp_state_get(struct cs40l26_private *cs40l26, u8 *state)
> > +{
> > +	bool mutex_available = !mutex_is_locked(&cs40l26->dsp.pwr_lock);
> 
> This is dangerous and a sign that locks are not properly managed. What would
> be a case where you do not know the state of the lock upon entering this function?
> If you do not know whether the mutex is locked inside this function, it is not the
> proper place to grab it.
> 

Yes I whole heartedly agree here this should not be done this
way.

> > +	cs40l26->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
> > +	if (IS_ERR_OR_NULL(cs40l26->reset_gpio)) {
> > +		dev_err(dev, "Failed to get reset GPIO: %d\n", (int) PTR_ERR(cs40l26->reset_gpio));
> > +		ret = -ENOENT;
> > +		goto err;
> > +	}
> > +
> > +	usleep_range(CS40L26_MIN_RESET_PULSE_WIDTH_US, CS40L26_MIN_RESET_PULSE_WIDTH_US + 100);
> > +
> > +	gpiod_set_value_cansleep(cs40l26->reset_gpio, 1);
> 
> This is backwards, which means your dts must be backwards as well. gpiod is
> a logical API, so you should actually declare the GPIO as GPIOD_OUT_HIGH, i.e.
> asserted, and then call gpiod_set_value_cansleep() with 0, i.e. de-asserted.
> The definition of "asserted" then comes from the polarity defined in dts.
> 
> By the way, did you test this driver without a reset GPIO defined in dts? It's
> an optional GPIO, rightfully so, but you need to check whether reset_gpio is
> NULL prior to acting upon it.
> 

gpiod does the NULL check for you no need to duplicate it in the
driver.

Thanks,
Charles

^ permalink raw reply

* [PATCH] staging: HID: Add ShanWan USB WirelessGamepad driver
From: Mubashshir @ 2023-04-10  9:17 UTC (permalink / raw)
  To: Jiri Kosina, Benjamin Tissoires; +Cc: Huseyin BIYIK, linux-kernel, linux-input

This device has a quirky initialization process.
Depending on how it was initialized, behaves completely differently.
In default mode, it behaves as expected, but in fallback it disables
force-feedback, analog stick configurations and L3/R3.

Signed-off-by: Huseyin BIYIK <huseyinbiyik@hotmail.com>
Signed-off-by: Mubashshir <ahmubashshir@gmail.com>
---
 drivers/hid/Kconfig       |  19 +++
 drivers/hid/Makefile      |   1 +
 drivers/hid/hid-ids.h     |   3 +
 drivers/hid/hid-shanwan.c | 256 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 279 insertions(+)
 create mode 100644 drivers/hid/hid-shanwan.c

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 82f64fb31fda..a17db9c9694c 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -990,6 +990,25 @@ config HID_SEMITEK
 	- Woo-dy
 	- X-Bows Nature/Knight
 
+config HID_SHANWAN
+	tristate "ShanWan USB WirelessGamepad"
+	depends on USB_HID
+	help
+	Support for Shanwan USB WirelessGamepad (and clones).
+
+	This device has a quirky initialization process.
+	Depending on how it was initialized, it behaves completely differently.
+	In default mode, it behaves as expected, but in fallback it disables
+	force-feedback, analog stick configurations and L3/R3.
+
+config SHANWAN_FF
+	bool "ShanWan USB WirelessGamepad force feedback support"
+	depends on HID_SHANWAN
+	select INPUT_FF_MEMLESS
+	help
+	Say Y here if you have a ShanWan USB WirelessGamepad and want to enable
+	force feedback support for it.
+
 config HID_SIGMAMICRO
 	tristate "SiGma Micro-based keyboards"
 	depends on USB_HID
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 5d37cacbde33..52878455fc10 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -116,6 +116,7 @@ obj-$(CONFIG_HID_RMI)		+= hid-rmi.o
 obj-$(CONFIG_HID_SAITEK)	+= hid-saitek.o
 obj-$(CONFIG_HID_SAMSUNG)	+= hid-samsung.o
 obj-$(CONFIG_HID_SEMITEK)	+= hid-semitek.o
+obj-$(CONFIG_HID_SHANWAN)	+= hid-shanwan.o
 obj-$(CONFIG_HID_SIGMAMICRO)	+= hid-sigmamicro.o
 obj-$(CONFIG_HID_SMARTJOYPLUS)	+= hid-sjoy.o
 obj-$(CONFIG_HID_SONY)		+= hid-sony.o
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 63545cd307e5..278914e37eb7 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -623,6 +623,9 @@
 #define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0641	0x0641
 #define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_1f4a	0x1f4a
 
+#define USB_VENDOR_ID_SHANWAN 0x2563
+#define USB_PRODUCT_ID_SHANWAN_USB_WIRELESSGAMEPAD 0x0575
+
 #define USB_VENDOR_ID_HUION		0x256c
 #define USB_DEVICE_ID_HUION_TABLET	0x006e
 #define USB_DEVICE_ID_HUION_TABLET2	0x006d
diff --git a/drivers/hid/hid-shanwan.c b/drivers/hid/hid-shanwan.c
new file mode 100644
index 000000000000..6c91a4d79036
--- /dev/null
+++ b/drivers/hid/hid-shanwan.c
@@ -0,0 +1,256 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Force feedback support for Shanwan USB WirelessGamepad
+ *
+ * Copyright (c) 2022-2023	Huseyin BIYIK	<huseyinbiyik@hotmail.com>
+ * Copyright (c) 2023	Ahmad Hasan Mubashshir	<ahmubashshir@gmail.com>
+ *
+ * mapping according to Gamepad Protocol
+ *
+ * Button 01: BTN_SOUTH (CROSS)
+ * Button 02: BTN_EAST(CIRCLE)
+ * Button 03: BTN_NORTH (TRIANGLE)
+ * Button 04: BTN_WEST (SQUARE)
+ * Button 05: BTL_TL (L1)
+ * Button 06: BTM_TR (R1)
+ * Button 07: BTN_TL2 (L2)
+ * Button 08: BTN_TR2 (R2)
+ * Button 09: BTN_SELECT
+ * Button 10: BTN_START
+ * Button 11: BTN_MODE
+ * Button 12: BTN_THUMBL (LS1)
+ * Button 13: BTN_THUMBR (LS1)
+ * LS1: X/Y AXIS
+ * LS2: Rx/Ry AXIS
+ * R2/L2 Touch Sensors: R/Rz
+ */
+
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/moduleparam.h>
+
+#include "hid-ids.h"
+
+#define PID0575_RDESC_ORIG_SIZE 137
+
+static bool swap_motors;
+module_param_named(swap, swap_motors, bool, 0);
+MODULE_PARM_DESC(swap, "Swap Weak/Strong Feedback motors");
+
+static __u8 pid0575_rdesc_fixed[] = {
+	0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
+	0x09, 0x05, // Usage (Game Pad)
+	0xA1, 0x01, // Collection (Application)
+	0x15, 0x00, // Logical Minimum (0)
+	0x25, 0x01, // Logical Maximum (1)
+	0x35, 0x00, // Physical Minimum (0)
+	0x45, 0x01, // Physical Maximum (1)
+	0x75, 0x01, // Report Size (1)
+	0x95, 0x0D, // Report Count (13)
+	0x05, 0x09, // Usage Page (Button)
+	0x09, 0x03, // Usage (BTN_NORTH)
+	0x09, 0x02, // Usage (BTN_EAST)
+	0x09, 0x01, // Usage (BTN_SOUTH)
+	0x09, 0x04, // Usage (BTN_WEST)
+	0x09, 0x05, // Usage (BTN_TL)
+	0x09, 0x06, // Usage (BTN_TR)
+	0x09, 0x07, // Usage (BTN_TL2)
+	0x09, 0x08, // Usage (BTN_TR2)
+	0x09, 0x09, // Usage (BTN_SELECT)
+	0x09, 0x10, // Usage (BTN_START)
+	0x09, 0x12, // Usage (BTN_THUMBL)
+	0x09, 0x13, // Usage (BTN_THUMBR)
+	0x09, 0x11, // Usage (BTN_MODE)
+	0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,PreferredState,NoNullPosition)
+	0x75, 0x01, // Report Size (1)
+	0x95, 0x03, // Report Count (3)
+	0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,PreferredState,NoNullPosition)
+	0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
+	0x25, 0x07, // Logical Maximum (7)
+	0x46, 0x3B, 0x01, // Physical Maximum (315)
+	0x75, 0x04, // Report Size (4)
+	0x95, 0x01, // Report Count (1)
+	0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter)
+	0x09, 0x39, // Usage (Hat switch)
+	0x81, 0x42, // Input (Data,Var,Abs,No Wrap,Linear,PreferredState,NullState)
+	0x65, 0x00, // Unit (None)
+	0x95, 0x01, // Report Count (1)
+	0x81, 0x01, // Input(Const,Array,Abs,NoWrap,Linear,PreferredState,NoNullPosition)
+	0x26, 0xFF, 0x00, // Logical Maximum (255)
+	0x46, 0xFF, 0x00, // Physical Maximum (255)
+	0x09, 0x30, // Usage (X)
+	0x09, 0x31, // Usage (Y)
+	0x09, 0x33, // Usage (Rx)
+	0x09, 0x34, // Usage (Ry)
+	0x75, 0x08, // Report Size (8)
+	0x95, 0x04, // Report Count (4)
+	0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,PreferredState,NoNullPosition)
+	0x95, 0x0A, // Report Count (10)
+	0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,PreferredState,NoNullPosition)
+	0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
+	0x26, 0xFF, 0x00, // Logical Maximum (255)
+	0x46, 0xFF, 0x00, // Physical Maximum (255)
+	0x09, 0x32, // Usage (Z)
+	0x09, 0x35, // Usage (Rz)
+	0x95, 0x02, // Report Count (2)
+	0x81, 0x02, // Input(Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+	0x95, 0x08, // Report Count (8)
+	0x81, 0x01, // Input(Const,Array,Abs,NoWrap,Linear,PreferredState,NoNullPosition)
+	0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)
+	0xB1, 0x02, // Feature(Data,Var,Abs,No Wrap,Linear,PreferredState,NoNullPosition,!volatile)
+	0x0A, 0x21, 0x26, // Usage (0x2621)
+	0x95, 0x08, // Report Count (8)
+	0x91, 0x02, // Output(Data,Var,Abs,No Wrap,Linear,PreferredState,NoNullPosition,!volatile)
+	0x0A, 0x21, 0x26, // Usage (0x2621)
+	0x95, 0x08, // Report Count (8)
+	0x81, 0x02, // Input(Data,Var,Abs,No Wrap,Linear,Preferred State,NoNullPosition)
+	0xC0,       // End Collection
+};
+
+struct shanwan_device {
+	struct hid_report *report;
+};
+
+#ifdef CONFIG_SHANWAN_FF
+static int shanwan_play_effect(struct input_dev *dev, void *data, struct ff_effect *effect)
+{
+	struct hid_device *hid = input_get_drvdata(dev);
+	struct shanwan_device *shanwan = data;
+	struct hid_report *report = shanwan->report;
+
+	if (effect->type != FF_RUMBLE)
+		return 0;
+
+	report->field[0]->value[0] = 0x02; /* 2 = rumble effect message */
+	report->field[0]->value[1] = 0x08; /* reserved value, always 8 */
+	if (swap_motors) {
+		/* weak rumble / strong rumble */
+		report->field[0]->value[2] = effect->u.rumble.strong_magnitude / 256;
+		report->field[0]->value[3] = effect->u.rumble.weak_magnitude / 256;
+	} else {
+		/* strong rumble / weak rumble */
+		report->field[0]->value[2] = effect->u.rumble.weak_magnitude / 256;
+		report->field[0]->value[3] = effect->u.rumble.strong_magnitude / 256;
+	}
+	report->field[0]->value[4] = 0xff; /* duration 0-254 (255 = nonstop) */
+	report->field[0]->value[5] = 0x00; /* padding */
+	report->field[0]->value[6] = 0x00; /* padding */
+	report->field[0]->value[7] = 0x00; /* padding */
+	hid_hw_request(hid, report, HID_REQ_SET_REPORT);
+
+	return 0;
+}
+
+static int shanwan_init_ff(struct hid_device *hid)
+{
+	struct shanwan_device *shanwan;
+	struct hid_report *report;
+	struct hid_input *hidinput;
+	struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+	struct input_dev *dev;
+
+	if (list_empty(&hid->inputs)) {
+		hid_err(hid, "no inputs found\n");
+		return -ENODEV;
+	}
+	hidinput = list_first_entry(&hid->inputs, struct hid_input, list);
+	dev = hidinput->input;
+
+	if (list_empty(report_list)) {
+		hid_err(hid, "no output reports found\n");
+		return -ENODEV;
+	}
+
+	report = list_first_entry(report_list, struct hid_report, list);
+
+	shanwan = kzalloc(sizeof(*shanwan), GFP_KERNEL);
+	if (!shanwan)
+		return -ENOMEM;
+
+	set_bit(FF_RUMBLE, dev->ffbit);
+
+	if (input_ff_create_memless(dev, shanwan, shanwan_play_effect)) {
+		kfree(shanwan);
+		return -ENODEV;
+	}
+
+	shanwan->report = report;
+
+	return 0;
+}
+#else
+static int shanwan_init_ff(struct hid_device *hid)
+{
+	return 0
+}
+#endif
+
+static int shanwan_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+	int error;
+
+	error = hid_parse(hdev);
+	if (error) {
+		hid_err(hdev, "parse failed\n");
+		return error;
+	}
+
+	error = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
+	if (error) {
+		hid_err(hdev, "hw start failed\n");
+		return error;
+	}
+
+	error = shanwan_init_ff(hdev);
+	if (error)
+		hid_warn(hdev, "Failed to enable force feedback support, error: %d\n", error);
+
+	error = hid_hw_open(hdev);
+	if (error) {
+		dev_err(&hdev->dev, "hw open failed\n");
+		hid_hw_stop(hdev);
+		return error;
+	}
+
+	return 0;
+}
+
+static void shanwan_remove(struct hid_device *hdev)
+{
+	hid_hw_close(hdev);
+	hid_hw_stop(hdev);
+}
+
+static __u8 *shanwan_report_fixup(struct hid_device *hid, __u8 *rdesc, unsigned int *rsize)
+{
+	if (*rsize == PID0575_RDESC_ORIG_SIZE) {
+		rdesc = pid0575_rdesc_fixed;
+		*rsize = sizeof(pid0575_rdesc_fixed);
+	} else {
+		hid_warn(hid, "unexpected rdesc, please submit for review\n");
+	}
+	return rdesc;
+}
+
+static const struct hid_device_id shanwan_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_SHANWAN, USB_PRODUCT_ID_SHANWAN_USB_WIRELESSGAMEPAD) },
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, shanwan_devices);
+
+static struct hid_driver shanwan_driver = {
+	.name			= "shanwan",
+	.id_table		= shanwan_devices,
+	.probe			= shanwan_probe,
+	.report_fixup		= shanwan_report_fixup,
+	.remove			= shanwan_remove,
+};
+module_hid_driver(shanwan_driver);
+
+MODULE_AUTHOR("Huseyin BIYIK <huseyinbiyik@hotmail.com>");
+MODULE_AUTHOR("Ahmad Hasan Mubashshir <ahmubashshir@gmail.com>")
+MODULE_DESCRIPTION("Force feedback support for Shanwan USB WirelessGamepad");
+MODULE_LICENSE("GPL");
-- 
2.40.0


^ permalink raw reply related

* [PATCH] Input: elan_i2c - Implement inhibit/uninhibit functions.
From: jingle.wu @ 2023-04-10 10:51 UTC (permalink / raw)
  To: linux-kernel, linux-input, dmitry.torokhov
  Cc: phoenix, josh.chen, dave.wang, jingle.wu

Add inhibit/uninhibit functions.

Signed-off-by: Jingle.wu <jingle.wu@emc.com.tw>
---
 drivers/input/mouse/elan_i2c_core.c | 83 +++++++++++++++++++++++++++++
 1 file changed, 83 insertions(+)

diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c
index 5f0d75a45c80..423f22fded59 100644
--- a/drivers/input/mouse/elan_i2c_core.c
+++ b/drivers/input/mouse/elan_i2c_core.c
@@ -329,6 +329,86 @@ static int elan_initialize(struct elan_tp_data *data, bool skip_reset)
 	return error;
 }
 
+static int elan_reactivate(struct elan_tp_data *data)
+{
+	struct device *dev = &data->client->dev;
+	int error;
+
+	error = elan_set_power(data, true);
+	if (error)
+		dev_err(dev, "failed to restore power: %d\n", error);
+
+	error = data->ops->sleep_control(data->client, false);
+	if (error) {
+		dev_err(dev,
+			"failed to wake device up: %d\n", error);
+		return error;
+	}
+
+	return error;
+}
+
+static void elan_inhibit(struct input_dev *input_dev)
+{
+	struct elan_tp_data *data = input_get_drvdata(input_dev);
+	struct i2c_client *client = data->client;
+	int error;
+
+	dev_dbg(&client->dev, "inhibiting\n");
+	/*
+	 * We are taking the mutex to make sure sysfs operations are
+	 * complete before we attempt to bring the device into low[er]
+	 * power mode.
+	 */
+	error = mutex_lock_interruptible(&data->sysfs_mutex);
+	if (error)
+		return;
+
+	disable_irq(client->irq);
+
+	error = elan_set_power(data, false);
+	if (error)
+		enable_irq(client->irq);
+
+	mutex_unlock(&data->sysfs_mutex);
+
+}
+
+static void elan_close(struct input_dev *input_dev)
+{
+	if ((input_dev->users) && (!input_dev->inhibited))
+		elan_inhibit(input_dev);
+
+}
+
+static int elan_uninhibit(struct input_dev *input_dev)
+{
+	struct elan_tp_data *data = input_get_drvdata(input_dev);
+	struct i2c_client *client = data->client;
+	int error;
+
+	dev_dbg(&client->dev, "uninhibiting\n");
+	error = mutex_lock_interruptible(&data->sysfs_mutex);
+	if (error)
+		return error;
+
+	error = elan_reactivate(data);
+	if (error == 0)
+		enable_irq(client->irq);
+
+	mutex_unlock(&data->sysfs_mutex);
+
+	return error;
+}
+
+static int elan_open(struct input_dev *input_dev)
+{
+	if ((input_dev->users) && (input_dev->inhibited))
+		return elan_uninhibit(input_dev);
+
+	return 0;
+}
+
 static int elan_query_device_info(struct elan_tp_data *data)
 {
 	int error;
@@ -1175,6 +1255,9 @@ static int elan_setup_input_device(struct elan_tp_data *data)
 				     0, ETP_FINGER_WIDTH * min_width, 0, 0);
 	}
 
+	input->open = elan_open;
+	input->close = elan_close;
+
 	data->input = input;
 
 	return 0;
-- 
2.34.1


^ permalink raw reply related

* [PATCH v2] staging: HID: Add ShanWan USB WirelessGamepad driver
From: Mubashshir @ 2023-04-10 11:59 UTC (permalink / raw)
  To: Jiri Kosina, Benjamin Tissoires; +Cc: Huseyin BIYIK, linux-kernel, linux-input
In-Reply-To: <39b44678dc54b519fa469b69d80757b36ab3cf25.1681118245.git.ahmubashshir@gmail.com>

This device has a quirky initialization process.
Depending on how it was initialized, behaves completely differently.
In default mode, it behaves as expected, but in fallback it disables
force-feedback, analog stick configurations and L3/R3.

Signed-off-by: Huseyin BIYIK <huseyinbiyik@hotmail.com>
Signed-off-by: Mubashshir <ahmubashshir@gmail.com>
---
 drivers/hid/Kconfig       |  19 +++
 drivers/hid/Makefile      |   1 +
 drivers/hid/hid-ids.h     |   3 +
 drivers/hid/hid-shanwan.c | 256 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 279 insertions(+)
 create mode 100644 drivers/hid/hid-shanwan.c

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 82f64fb31fda..a17db9c9694c 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -990,6 +990,25 @@ config HID_SEMITEK
 	- Woo-dy
 	- X-Bows Nature/Knight
 
+config HID_SHANWAN
+	tristate "ShanWan USB WirelessGamepad"
+	depends on USB_HID
+	help
+	Support for Shanwan USB WirelessGamepad (and clones).
+
+	This device has a quirky initialization process.
+	Depending on how it was initialized, it behaves completely differently.
+	In default mode, it behaves as expected, but in fallback it disables
+	force-feedback, analog stick configurations and L3/R3.
+
+config SHANWAN_FF
+	bool "ShanWan USB WirelessGamepad force feedback support"
+	depends on HID_SHANWAN
+	select INPUT_FF_MEMLESS
+	help
+	Say Y here if you have a ShanWan USB WirelessGamepad and want to enable
+	force feedback support for it.
+
 config HID_SIGMAMICRO
 	tristate "SiGma Micro-based keyboards"
 	depends on USB_HID
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 5d37cacbde33..52878455fc10 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -116,6 +116,7 @@ obj-$(CONFIG_HID_RMI)		+= hid-rmi.o
 obj-$(CONFIG_HID_SAITEK)	+= hid-saitek.o
 obj-$(CONFIG_HID_SAMSUNG)	+= hid-samsung.o
 obj-$(CONFIG_HID_SEMITEK)	+= hid-semitek.o
+obj-$(CONFIG_HID_SHANWAN)	+= hid-shanwan.o
 obj-$(CONFIG_HID_SIGMAMICRO)	+= hid-sigmamicro.o
 obj-$(CONFIG_HID_SMARTJOYPLUS)	+= hid-sjoy.o
 obj-$(CONFIG_HID_SONY)		+= hid-sony.o
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 63545cd307e5..278914e37eb7 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -623,6 +623,9 @@
 #define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0641	0x0641
 #define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_1f4a	0x1f4a
 
+#define USB_VENDOR_ID_SHANWAN 0x2563
+#define USB_PRODUCT_ID_SHANWAN_USB_WIRELESSGAMEPAD 0x0575
+
 #define USB_VENDOR_ID_HUION		0x256c
 #define USB_DEVICE_ID_HUION_TABLET	0x006e
 #define USB_DEVICE_ID_HUION_TABLET2	0x006d
diff --git a/drivers/hid/hid-shanwan.c b/drivers/hid/hid-shanwan.c
new file mode 100644
index 000000000000..dfe9ec26b31c
--- /dev/null
+++ b/drivers/hid/hid-shanwan.c
@@ -0,0 +1,256 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Force feedback support for Shanwan USB WirelessGamepad
+ *
+ * Copyright (c) 2022-2023	Huseyin BIYIK	<huseyinbiyik@hotmail.com>
+ * Copyright (c) 2023	Ahmad Hasan Mubashshir	<ahmubashshir@gmail.com>
+ *
+ * mapping according to Gamepad Protocol
+ *
+ * Button 01: BTN_SOUTH (CROSS)
+ * Button 02: BTN_EAST(CIRCLE)
+ * Button 03: BTN_NORTH (TRIANGLE)
+ * Button 04: BTN_WEST (SQUARE)
+ * Button 05: BTL_TL (L1)
+ * Button 06: BTM_TR (R1)
+ * Button 07: BTN_TL2 (L2)
+ * Button 08: BTN_TR2 (R2)
+ * Button 09: BTN_SELECT
+ * Button 10: BTN_START
+ * Button 11: BTN_MODE
+ * Button 12: BTN_THUMBL (LS1)
+ * Button 13: BTN_THUMBR (LS1)
+ * LS1: X/Y AXIS
+ * LS2: Rx/Ry AXIS
+ * R2/L2 Touch Sensors: R/Rz
+ */
+
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/moduleparam.h>
+
+#include "hid-ids.h"
+
+#define PID0575_RDESC_ORIG_SIZE 137
+
+static bool swap_motors;
+module_param_named(swap, swap_motors, bool, 0);
+MODULE_PARM_DESC(swap, "Swap Weak/Strong Feedback motors");
+
+static __u8 pid0575_rdesc_fixed[] = {
+	0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
+	0x09, 0x05, // Usage (Game Pad)
+	0xA1, 0x01, // Collection (Application)
+	0x15, 0x00, // Logical Minimum (0)
+	0x25, 0x01, // Logical Maximum (1)
+	0x35, 0x00, // Physical Minimum (0)
+	0x45, 0x01, // Physical Maximum (1)
+	0x75, 0x01, // Report Size (1)
+	0x95, 0x0D, // Report Count (13)
+	0x05, 0x09, // Usage Page (Button)
+	0x09, 0x03, // Usage (BTN_NORTH)
+	0x09, 0x02, // Usage (BTN_EAST)
+	0x09, 0x01, // Usage (BTN_SOUTH)
+	0x09, 0x04, // Usage (BTN_WEST)
+	0x09, 0x05, // Usage (BTN_TL)
+	0x09, 0x06, // Usage (BTN_TR)
+	0x09, 0x07, // Usage (BTN_TL2)
+	0x09, 0x08, // Usage (BTN_TR2)
+	0x09, 0x09, // Usage (BTN_SELECT)
+	0x09, 0x10, // Usage (BTN_START)
+	0x09, 0x12, // Usage (BTN_THUMBL)
+	0x09, 0x13, // Usage (BTN_THUMBR)
+	0x09, 0x11, // Usage (BTN_MODE)
+	0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,PreferredState,NoNullPosition)
+	0x75, 0x01, // Report Size (1)
+	0x95, 0x03, // Report Count (3)
+	0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,PreferredState,NoNullPosition)
+	0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
+	0x25, 0x07, // Logical Maximum (7)
+	0x46, 0x3B, 0x01, // Physical Maximum (315)
+	0x75, 0x04, // Report Size (4)
+	0x95, 0x01, // Report Count (1)
+	0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter)
+	0x09, 0x39, // Usage (Hat switch)
+	0x81, 0x42, // Input (Data,Var,Abs,No Wrap,Linear,PreferredState,NullState)
+	0x65, 0x00, // Unit (None)
+	0x95, 0x01, // Report Count (1)
+	0x81, 0x01, // Input(Const,Array,Abs,NoWrap,Linear,PreferredState,NoNullPosition)
+	0x26, 0xFF, 0x00, // Logical Maximum (255)
+	0x46, 0xFF, 0x00, // Physical Maximum (255)
+	0x09, 0x30, // Usage (X)
+	0x09, 0x31, // Usage (Y)
+	0x09, 0x33, // Usage (Rx)
+	0x09, 0x34, // Usage (Ry)
+	0x75, 0x08, // Report Size (8)
+	0x95, 0x04, // Report Count (4)
+	0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,PreferredState,NoNullPosition)
+	0x95, 0x0A, // Report Count (10)
+	0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,PreferredState,NoNullPosition)
+	0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
+	0x26, 0xFF, 0x00, // Logical Maximum (255)
+	0x46, 0xFF, 0x00, // Physical Maximum (255)
+	0x09, 0x32, // Usage (Z)
+	0x09, 0x35, // Usage (Rz)
+	0x95, 0x02, // Report Count (2)
+	0x81, 0x02, // Input(Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+	0x95, 0x08, // Report Count (8)
+	0x81, 0x01, // Input(Const,Array,Abs,NoWrap,Linear,PreferredState,NoNullPosition)
+	0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)
+	0xB1, 0x02, // Feature(Data,Var,Abs,No Wrap,Linear,PreferredState,NoNullPosition,!volatile)
+	0x0A, 0x21, 0x26, // Usage (0x2621)
+	0x95, 0x08, // Report Count (8)
+	0x91, 0x02, // Output(Data,Var,Abs,No Wrap,Linear,PreferredState,NoNullPosition,!volatile)
+	0x0A, 0x21, 0x26, // Usage (0x2621)
+	0x95, 0x08, // Report Count (8)
+	0x81, 0x02, // Input(Data,Var,Abs,No Wrap,Linear,Preferred State,NoNullPosition)
+	0xC0,       // End Collection
+};
+
+struct shanwan_device {
+	struct hid_report *report;
+};
+
+#ifdef CONFIG_SHANWAN_FF
+static int shanwan_play_effect(struct input_dev *dev, void *data, struct ff_effect *effect)
+{
+	struct hid_device *hid = input_get_drvdata(dev);
+	struct shanwan_device *shanwan = data;
+	struct hid_report *report = shanwan->report;
+
+	if (effect->type != FF_RUMBLE)
+		return 0;
+
+	report->field[0]->value[0] = 0x02; /* 2 = rumble effect message */
+	report->field[0]->value[1] = 0x08; /* reserved value, always 8 */
+	if (swap_motors) {
+		/* weak rumble / strong rumble */
+		report->field[0]->value[2] = effect->u.rumble.strong_magnitude / 256;
+		report->field[0]->value[3] = effect->u.rumble.weak_magnitude / 256;
+	} else {
+		/* strong rumble / weak rumble */
+		report->field[0]->value[2] = effect->u.rumble.weak_magnitude / 256;
+		report->field[0]->value[3] = effect->u.rumble.strong_magnitude / 256;
+	}
+	report->field[0]->value[4] = 0xff; /* duration 0-254 (255 = nonstop) */
+	report->field[0]->value[5] = 0x00; /* padding */
+	report->field[0]->value[6] = 0x00; /* padding */
+	report->field[0]->value[7] = 0x00; /* padding */
+	hid_hw_request(hid, report, HID_REQ_SET_REPORT);
+
+	return 0;
+}
+
+static int shanwan_init_ff(struct hid_device *hid)
+{
+	struct shanwan_device *shanwan;
+	struct hid_report *report;
+	struct hid_input *hidinput;
+	struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+	struct input_dev *dev;
+
+	if (list_empty(&hid->inputs)) {
+		hid_err(hid, "no inputs found\n");
+		return -ENODEV;
+	}
+	hidinput = list_first_entry(&hid->inputs, struct hid_input, list);
+	dev = hidinput->input;
+
+	if (list_empty(report_list)) {
+		hid_err(hid, "no output reports found\n");
+		return -ENODEV;
+	}
+
+	report = list_first_entry(report_list, struct hid_report, list);
+
+	shanwan = kzalloc(sizeof(*shanwan), GFP_KERNEL);
+	if (!shanwan)
+		return -ENOMEM;
+
+	set_bit(FF_RUMBLE, dev->ffbit);
+
+	if (input_ff_create_memless(dev, shanwan, shanwan_play_effect)) {
+		kfree(shanwan);
+		return -ENODEV;
+	}
+
+	shanwan->report = report;
+
+	return 0;
+}
+#else
+static int shanwan_init_ff(struct hid_device *hid)
+{
+	return 0
+}
+#endif
+
+static int shanwan_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+	int error;
+
+	error = hid_parse(hdev);
+	if (error) {
+		hid_err(hdev, "parse failed\n");
+		return error;
+	}
+
+	error = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
+	if (error) {
+		hid_err(hdev, "hw start failed\n");
+		return error;
+	}
+
+	error = shanwan_init_ff(hdev);
+	if (error)
+		hid_warn(hdev, "Failed to enable force feedback support, error: %d\n", error);
+
+	error = hid_hw_open(hdev);
+	if (error) {
+		dev_err(&hdev->dev, "hw open failed\n");
+		hid_hw_stop(hdev);
+		return error;
+	}
+
+	return 0;
+}
+
+static void shanwan_remove(struct hid_device *hdev)
+{
+	hid_hw_close(hdev);
+	hid_hw_stop(hdev);
+}
+
+static __u8 *shanwan_report_fixup(struct hid_device *hid, __u8 *rdesc, unsigned int *rsize)
+{
+	if (*rsize == PID0575_RDESC_ORIG_SIZE) {
+		rdesc = pid0575_rdesc_fixed;
+		*rsize = sizeof(pid0575_rdesc_fixed);
+	} else {
+		hid_warn(hid, "unexpected rdesc, please submit for review\n");
+	}
+	return rdesc;
+}
+
+static const struct hid_device_id shanwan_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_SHANWAN, USB_PRODUCT_ID_SHANWAN_USB_WIRELESSGAMEPAD) },
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, shanwan_devices);
+
+static struct hid_driver shanwan_driver = {
+	.name			= "shanwan",
+	.id_table		= shanwan_devices,
+	.probe			= shanwan_probe,
+	.report_fixup		= shanwan_report_fixup,
+	.remove			= shanwan_remove,
+};
+module_hid_driver(shanwan_driver);
+
+MODULE_AUTHOR("Huseyin BIYIK <huseyinbiyik@hotmail.com>");
+MODULE_AUTHOR("Ahmad Hasan Mubashshir <ahmubashshir@gmail.com>");
+MODULE_DESCRIPTION("Force feedback support for Shanwan USB WirelessGamepad");
+MODULE_LICENSE("GPL");
-- 
2.40.0


^ permalink raw reply related

* Re: [PATCH v2] staging: HID: Add ShanWan USB WirelessGamepad driver
From: Mubashshir @ 2023-04-10 12:04 UTC (permalink / raw)
  To: Jiri Kosina, Benjamin Tissoires; +Cc: Huseyin BIYIK, linux-kernel, linux-input
In-Reply-To: <f2e84ed47b84847c7e555c871d9851c6d70d6964.1681127968.git.ahmubashshir@gmail.com>

On Mon, Apr 10 2023 at 05:59:30 PM +06:00:00, Mubashshir 
<ahmubashshir@gmail.com> wrote:
> +MODULE_AUTHOR("Ahmad Hasan Mubashshir <ahmubashshir@gmail.com>");

Sorry, I missed the semicolon here on my previous patch.



^ permalink raw reply

* Re: [PATCH] staging: HID: Add ShanWan USB WirelessGamepad driver
From: kernel test robot @ 2023-04-10 12:30 UTC (permalink / raw)
  To: Mubashshir, Jiri Kosina, Benjamin Tissoires
  Cc: oe-kbuild-all, Huseyin BIYIK, linux-kernel, linux-input
In-Reply-To: <39b44678dc54b519fa469b69d80757b36ab3cf25.1681118245.git.ahmubashshir@gmail.com>

Hi Mubashshir,

kernel test robot noticed the following build errors:

[auto build test ERROR on staging/staging-testing]

url:    https://github.com/intel-lab-lkp/linux/commits/Mubashshir/staging-HID-Add-ShanWan-USB-WirelessGamepad-driver/20230410-172120
patch link:    https://lore.kernel.org/r/39b44678dc54b519fa469b69d80757b36ab3cf25.1681118245.git.ahmubashshir%40gmail.com
patch subject: [PATCH] staging: HID: Add ShanWan USB WirelessGamepad driver
config: sh-allmodconfig (https://download.01.org/0day-ci/archive/20230410/202304102017.yQ3YHaXX-lkp@intel.com/config)
compiler: sh4-linux-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/bdfd2a839da337ac583bfa8ae2cb19f0388619b8
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Mubashshir/staging-HID-Add-ShanWan-USB-WirelessGamepad-driver/20230410-172120
        git checkout bdfd2a839da337ac583bfa8ae2cb19f0388619b8
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=sh olddefconfig
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=sh SHELL=/bin/bash drivers/hid/

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>
| Link: https://lore.kernel.org/oe-kbuild-all/202304102017.yQ3YHaXX-lkp@intel.com/

All errors (new ones prefixed by >>):

   In file included from include/linux/module.h:22,
                    from include/linux/device/driver.h:21,
                    from include/linux/device.h:32,
                    from include/linux/input.h:19,
                    from drivers/hid/hid-shanwan.c:28:
>> include/linux/moduleparam.h:24:9: error: expected ',' or ';' before 'static'
      24 |         static const char __UNIQUE_ID(name)[]                             \
         |         ^~~~~~
   include/linux/module.h:165:32: note: in expansion of macro '__MODULE_INFO'
     165 | #define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info)
         |                                ^~~~~~~~~~~~~
   include/linux/module.h:238:42: note: in expansion of macro 'MODULE_INFO'
     238 | #define MODULE_DESCRIPTION(_description) MODULE_INFO(description, _description)
         |                                          ^~~~~~~~~~~
   drivers/hid/hid-shanwan.c:255:1: note: in expansion of macro 'MODULE_DESCRIPTION'
     255 | MODULE_DESCRIPTION("Force feedback support for Shanwan USB WirelessGamepad");
         | ^~~~~~~~~~~~~~~~~~


vim +24 include/linux/moduleparam.h

730b69d2252595 Rusty Russell  2008-10-22  22  
^1da177e4c3f41 Linus Torvalds 2005-04-16  23  #define __MODULE_INFO(tag, name, info)					  \
34182eea36fc1d Rusty Russell  2012-11-22 @24  	static const char __UNIQUE_ID(name)[]				  \
2aec389e19150e Johan Hovold   2020-11-23  25  		__used __section(".modinfo") __aligned(1)		  \
898490c010b5d2 Alexey Gladkov 2019-04-29  26  		= __MODULE_INFO_PREFIX __stringify(tag) "=" info
898490c010b5d2 Alexey Gladkov 2019-04-29  27  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests

^ permalink raw reply

* [PATCH v3] staging: HID: Add ShanWan USB WirelessGamepad driver
From: Mubashshir @ 2023-04-10 12:59 UTC (permalink / raw)
  To: Jiri Kosina, Benjamin Tissoires; +Cc: Huseyin BIYIK, linux-kernel, linux-input
In-Reply-To: <39b44678dc54b519fa469b69d80757b36ab3cf25.1681118245.git.ahmubashshir@gmail.com>

This device has a quirky initialization process.
Depending on how it was initialized, behaves completely differently.
In default mode, it behaves as expected, but in fallback it disables
force-feedback, analog stick configurations and L3/R3.

Signed-off-by: Huseyin BIYIK <huseyinbiyik@hotmail.com>
Signed-off-by: Mubashshir <ahmubashshir@gmail.com>
---
v3: Another missed semicolon

 drivers/hid/Kconfig       |  19 +++
 drivers/hid/Makefile      |   1 +
 drivers/hid/hid-ids.h     |   3 +
 drivers/hid/hid-shanwan.c | 256 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 279 insertions(+)
 create mode 100644 drivers/hid/hid-shanwan.c

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 82f64fb31fda..a17db9c9694c 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -990,6 +990,25 @@ config HID_SEMITEK
 	- Woo-dy
 	- X-Bows Nature/Knight
 
+config HID_SHANWAN
+	tristate "ShanWan USB WirelessGamepad"
+	depends on USB_HID
+	help
+	Support for Shanwan USB WirelessGamepad (and clones).
+
+	This device has a quirky initialization process.
+	Depending on how it was initialized, it behaves completely differently.
+	In default mode, it behaves as expected, but in fallback it disables
+	force-feedback, analog stick configurations and L3/R3.
+
+config SHANWAN_FF
+	bool "ShanWan USB WirelessGamepad force feedback support"
+	depends on HID_SHANWAN
+	select INPUT_FF_MEMLESS
+	help
+	Say Y here if you have a ShanWan USB WirelessGamepad and want to enable
+	force feedback support for it.
+
 config HID_SIGMAMICRO
 	tristate "SiGma Micro-based keyboards"
 	depends on USB_HID
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 5d37cacbde33..52878455fc10 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -116,6 +116,7 @@ obj-$(CONFIG_HID_RMI)		+= hid-rmi.o
 obj-$(CONFIG_HID_SAITEK)	+= hid-saitek.o
 obj-$(CONFIG_HID_SAMSUNG)	+= hid-samsung.o
 obj-$(CONFIG_HID_SEMITEK)	+= hid-semitek.o
+obj-$(CONFIG_HID_SHANWAN)	+= hid-shanwan.o
 obj-$(CONFIG_HID_SIGMAMICRO)	+= hid-sigmamicro.o
 obj-$(CONFIG_HID_SMARTJOYPLUS)	+= hid-sjoy.o
 obj-$(CONFIG_HID_SONY)		+= hid-sony.o
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 63545cd307e5..278914e37eb7 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -623,6 +623,9 @@
 #define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0641	0x0641
 #define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_1f4a	0x1f4a
 
+#define USB_VENDOR_ID_SHANWAN 0x2563
+#define USB_PRODUCT_ID_SHANWAN_USB_WIRELESSGAMEPAD 0x0575
+
 #define USB_VENDOR_ID_HUION		0x256c
 #define USB_DEVICE_ID_HUION_TABLET	0x006e
 #define USB_DEVICE_ID_HUION_TABLET2	0x006d
diff --git a/drivers/hid/hid-shanwan.c b/drivers/hid/hid-shanwan.c
new file mode 100644
index 000000000000..39c1bb6f40c6
--- /dev/null
+++ b/drivers/hid/hid-shanwan.c
@@ -0,0 +1,256 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Force feedback support for Shanwan USB WirelessGamepad
+ *
+ * Copyright (c) 2022-2023	Huseyin BIYIK	<huseyinbiyik@hotmail.com>
+ * Copyright (c) 2023	Ahmad Hasan Mubashshir	<ahmubashshir@gmail.com>
+ *
+ * mapping according to Gamepad Protocol
+ *
+ * Button 01: BTN_SOUTH (CROSS)
+ * Button 02: BTN_EAST(CIRCLE)
+ * Button 03: BTN_NORTH (TRIANGLE)
+ * Button 04: BTN_WEST (SQUARE)
+ * Button 05: BTL_TL (L1)
+ * Button 06: BTM_TR (R1)
+ * Button 07: BTN_TL2 (L2)
+ * Button 08: BTN_TR2 (R2)
+ * Button 09: BTN_SELECT
+ * Button 10: BTN_START
+ * Button 11: BTN_MODE
+ * Button 12: BTN_THUMBL (LS1)
+ * Button 13: BTN_THUMBR (LS1)
+ * LS1: X/Y AXIS
+ * LS2: Rx/Ry AXIS
+ * R2/L2 Touch Sensors: R/Rz
+ */
+
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/moduleparam.h>
+
+#include "hid-ids.h"
+
+#define PID0575_RDESC_ORIG_SIZE 137
+
+static bool swap_motors;
+module_param_named(swap, swap_motors, bool, 0);
+MODULE_PARM_DESC(swap, "Swap Weak/Strong Feedback motors");
+
+static __u8 pid0575_rdesc_fixed[] = {
+	0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
+	0x09, 0x05, // Usage (Game Pad)
+	0xA1, 0x01, // Collection (Application)
+	0x15, 0x00, // Logical Minimum (0)
+	0x25, 0x01, // Logical Maximum (1)
+	0x35, 0x00, // Physical Minimum (0)
+	0x45, 0x01, // Physical Maximum (1)
+	0x75, 0x01, // Report Size (1)
+	0x95, 0x0D, // Report Count (13)
+	0x05, 0x09, // Usage Page (Button)
+	0x09, 0x03, // Usage (BTN_NORTH)
+	0x09, 0x02, // Usage (BTN_EAST)
+	0x09, 0x01, // Usage (BTN_SOUTH)
+	0x09, 0x04, // Usage (BTN_WEST)
+	0x09, 0x05, // Usage (BTN_TL)
+	0x09, 0x06, // Usage (BTN_TR)
+	0x09, 0x07, // Usage (BTN_TL2)
+	0x09, 0x08, // Usage (BTN_TR2)
+	0x09, 0x09, // Usage (BTN_SELECT)
+	0x09, 0x10, // Usage (BTN_START)
+	0x09, 0x12, // Usage (BTN_THUMBL)
+	0x09, 0x13, // Usage (BTN_THUMBR)
+	0x09, 0x11, // Usage (BTN_MODE)
+	0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,PreferredState,NoNullPosition)
+	0x75, 0x01, // Report Size (1)
+	0x95, 0x03, // Report Count (3)
+	0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,PreferredState,NoNullPosition)
+	0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
+	0x25, 0x07, // Logical Maximum (7)
+	0x46, 0x3B, 0x01, // Physical Maximum (315)
+	0x75, 0x04, // Report Size (4)
+	0x95, 0x01, // Report Count (1)
+	0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter)
+	0x09, 0x39, // Usage (Hat switch)
+	0x81, 0x42, // Input (Data,Var,Abs,No Wrap,Linear,PreferredState,NullState)
+	0x65, 0x00, // Unit (None)
+	0x95, 0x01, // Report Count (1)
+	0x81, 0x01, // Input(Const,Array,Abs,NoWrap,Linear,PreferredState,NoNullPosition)
+	0x26, 0xFF, 0x00, // Logical Maximum (255)
+	0x46, 0xFF, 0x00, // Physical Maximum (255)
+	0x09, 0x30, // Usage (X)
+	0x09, 0x31, // Usage (Y)
+	0x09, 0x33, // Usage (Rx)
+	0x09, 0x34, // Usage (Ry)
+	0x75, 0x08, // Report Size (8)
+	0x95, 0x04, // Report Count (4)
+	0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,PreferredState,NoNullPosition)
+	0x95, 0x0A, // Report Count (10)
+	0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,PreferredState,NoNullPosition)
+	0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
+	0x26, 0xFF, 0x00, // Logical Maximum (255)
+	0x46, 0xFF, 0x00, // Physical Maximum (255)
+	0x09, 0x32, // Usage (Z)
+	0x09, 0x35, // Usage (Rz)
+	0x95, 0x02, // Report Count (2)
+	0x81, 0x02, // Input(Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+	0x95, 0x08, // Report Count (8)
+	0x81, 0x01, // Input(Const,Array,Abs,NoWrap,Linear,PreferredState,NoNullPosition)
+	0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)
+	0xB1, 0x02, // Feature(Data,Var,Abs,No Wrap,Linear,PreferredState,NoNullPosition,!volatile)
+	0x0A, 0x21, 0x26, // Usage (0x2621)
+	0x95, 0x08, // Report Count (8)
+	0x91, 0x02, // Output(Data,Var,Abs,No Wrap,Linear,PreferredState,NoNullPosition,!volatile)
+	0x0A, 0x21, 0x26, // Usage (0x2621)
+	0x95, 0x08, // Report Count (8)
+	0x81, 0x02, // Input(Data,Var,Abs,No Wrap,Linear,Preferred State,NoNullPosition)
+	0xC0,       // End Collection
+};
+
+struct shanwan_device {
+	struct hid_report *report;
+};
+
+#ifdef CONFIG_SHANWAN_FF
+static int shanwan_play_effect(struct input_dev *dev, void *data, struct ff_effect *effect)
+{
+	struct hid_device *hid = input_get_drvdata(dev);
+	struct shanwan_device *shanwan = data;
+	struct hid_report *report = shanwan->report;
+
+	if (effect->type != FF_RUMBLE)
+		return 0;
+
+	report->field[0]->value[0] = 0x02; /* 2 = rumble effect message */
+	report->field[0]->value[1] = 0x08; /* reserved value, always 8 */
+	if (swap_motors) {
+		/* weak rumble / strong rumble */
+		report->field[0]->value[2] = effect->u.rumble.strong_magnitude / 256;
+		report->field[0]->value[3] = effect->u.rumble.weak_magnitude / 256;
+	} else {
+		/* strong rumble / weak rumble */
+		report->field[0]->value[2] = effect->u.rumble.weak_magnitude / 256;
+		report->field[0]->value[3] = effect->u.rumble.strong_magnitude / 256;
+	}
+	report->field[0]->value[4] = 0xff; /* duration 0-254 (255 = nonstop) */
+	report->field[0]->value[5] = 0x00; /* padding */
+	report->field[0]->value[6] = 0x00; /* padding */
+	report->field[0]->value[7] = 0x00; /* padding */
+	hid_hw_request(hid, report, HID_REQ_SET_REPORT);
+
+	return 0;
+}
+
+static int shanwan_init_ff(struct hid_device *hid)
+{
+	struct shanwan_device *shanwan;
+	struct hid_report *report;
+	struct hid_input *hidinput;
+	struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+	struct input_dev *dev;
+
+	if (list_empty(&hid->inputs)) {
+		hid_err(hid, "no inputs found\n");
+		return -ENODEV;
+	}
+	hidinput = list_first_entry(&hid->inputs, struct hid_input, list);
+	dev = hidinput->input;
+
+	if (list_empty(report_list)) {
+		hid_err(hid, "no output reports found\n");
+		return -ENODEV;
+	}
+
+	report = list_first_entry(report_list, struct hid_report, list);
+
+	shanwan = kzalloc(sizeof(*shanwan), GFP_KERNEL);
+	if (!shanwan)
+		return -ENOMEM;
+
+	set_bit(FF_RUMBLE, dev->ffbit);
+
+	if (input_ff_create_memless(dev, shanwan, shanwan_play_effect)) {
+		kfree(shanwan);
+		return -ENODEV;
+	}
+
+	shanwan->report = report;
+
+	return 0;
+}
+#else
+static int shanwan_init_ff(struct hid_device *hid)
+{
+	return 0;
+}
+#endif
+
+static int shanwan_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+	int error;
+
+	error = hid_parse(hdev);
+	if (error) {
+		hid_err(hdev, "parse failed\n");
+		return error;
+	}
+
+	error = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
+	if (error) {
+		hid_err(hdev, "hw start failed\n");
+		return error;
+	}
+
+	error = shanwan_init_ff(hdev);
+	if (error)
+		hid_warn(hdev, "Failed to enable force feedback support, error: %d\n", error);
+
+	error = hid_hw_open(hdev);
+	if (error) {
+		dev_err(&hdev->dev, "hw open failed\n");
+		hid_hw_stop(hdev);
+		return error;
+	}
+
+	return 0;
+}
+
+static void shanwan_remove(struct hid_device *hdev)
+{
+	hid_hw_close(hdev);
+	hid_hw_stop(hdev);
+}
+
+static __u8 *shanwan_report_fixup(struct hid_device *hid, __u8 *rdesc, unsigned int *rsize)
+{
+	if (*rsize == PID0575_RDESC_ORIG_SIZE) {
+		rdesc = pid0575_rdesc_fixed;
+		*rsize = sizeof(pid0575_rdesc_fixed);
+	} else {
+		hid_warn(hid, "unexpected rdesc, please submit for review\n");
+	}
+	return rdesc;
+}
+
+static const struct hid_device_id shanwan_devices[] = {
+	{ HID_USB_DEVICE(USB_VENDOR_ID_SHANWAN, USB_PRODUCT_ID_SHANWAN_USB_WIRELESSGAMEPAD) },
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, shanwan_devices);
+
+static struct hid_driver shanwan_driver = {
+	.name			= "shanwan",
+	.id_table		= shanwan_devices,
+	.probe			= shanwan_probe,
+	.report_fixup		= shanwan_report_fixup,
+	.remove			= shanwan_remove,
+};
+module_hid_driver(shanwan_driver);
+
+MODULE_AUTHOR("Huseyin BIYIK <huseyinbiyik@hotmail.com>");
+MODULE_AUTHOR("Ahmad Hasan Mubashshir <ahmubashshir@gmail.com>");
+MODULE_DESCRIPTION("Force feedback support for Shanwan USB WirelessGamepad");
+MODULE_LICENSE("GPL");
-- 
2.40.0


^ permalink raw reply related

* [PATCH v2 0/5] Add support for Focaltech FTS Touchscreen
From: Joel Selvaraj @ 2023-04-10 16:01 UTC (permalink / raw)
  To: Caleb Connolly, Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski,
	Andy Gross, Bjorn Andersson, Konrad Dybcio, Henrik Rydberg,
	Arnd Bergmann, Robert Jarzmik, Jeff LaBundy, Markuss Broks,
	Jean Delvare, Job Noorman, Alistair Francis, Chris Morgan,
	Hans de Goede
  Cc: linux-input, devicetree, linux-kernel, linux-arm-msm,
	~postmarketos/upstreaming, phone-devel, Joel Selvaraj

Changes in v2:
--------------
1. dt-bindings changes (Suggested by Krzysztof Kozlowski)
	- changed file name from focaltech,fts.yaml to focaltech,fts5452.yaml
	- removed focaltech,max-touch-number property, handled in driver now
	- removed touchscreen-* properties and used unevaluatedProperties: false
	instead of additionalProperties: false
	- fixed the example dts node name to be generic
	
2. FTS Touchscreen driver changes (Suggested by Markuss Broks and Jeff LaBundy)
	- removed repeated license terms since SPDX tag is used
	- includes are now sorted
	- added the missing input_mt_sync_frame when reporting touch
	- focaltech,max-touch-number is no longer read from dts and instead
	specified in the driver as compatible data.
	- removed redundant __set_bits
	- input_mt_init_slots is now called after the axes are defined
	- irq handler now returns IRQ_NONE when there is an i2c error
	- other minor fixes and refactoring as suggested
	- renamed driver filename from focaltech_fts.c to focaltech_fts5452.c
	(Suggested by Krzysztof Kozlowski)
	
3. dts changes (Suggested by Krzysztof Kozlowski)
	- use generic touchscreen nodes
	- removed focaltech,max-touch-number property
	- irq type was specified wrongly for Poco F1 in v1. Changed the irq
	type to IRQ_TYPE_EDGE_FALLING as that is correct.

Some Clarifications:
--------------------
1. Jeff LaBundy suggested I could read chip id with the following:
	__be16 val;
	regmap_raw_read(data->regmap, FTS_REG_CHIP_ID_H, &val, sizeof(val));
But this is not possible because FTS_REG_CHIP_ID_H and FTS_REG_CHIP_ID_L
are not continous register, therefore reading it together as 16-bit values
will not work. So I went with what Markuss Broks suggested:
	regmap_read(data->regmap, FTS_REG_CHIP_ID_L, &id);
        regmap_read(data->regmap, FTS_REG_CHIP_ID_H, &val);
        id |= val << 8;

2. As Markuss Broks suggested, I tried to cast the buffer to struct, but 
unfortunately was not able to successfully do it. The buffer layout is 
weirdly split into 4 bits and 12 bits at someplaces which makes it hard 
to cast into a struct. For example, we can note
	type = buf[base + 3] >> 6
	x = ((buf[base + 3] & 0x0F) << 8) + (buf[base + 4] & 0xFF);
Here at buffer index 3, the first two bits (>>6) are used for denoting
event type. The next two bits are not used. But the last 4 bits (&0x0F)
of buffer[3] are added with buffer index 4 to get the x position. 
I don't know how to handle these when casting to a struct. I tried
experimenting with bitfields in struct, but to no avail. So I am sticking
with my initial implementation for now.

Kindly let me know if any further improvements are needed. Thanks.

The Focaltech FTS driver supports several variants of focaltech
touchscreens found in ~2018 era smartphones including variants found on
the PocoPhone F1 and the SHIFT6mq which are already present in mainline.
This driver is loosely based on the original driver from Focaltech and
the patches submitted by Caleb Connolly previously[1] but has been
simplified and largely reworked.

[1] https://patchwork.kernel.org/project/linux-input/patch/20220123173650.290349-3-caleb@connolly.tech/

Joel Selvaraj (5):
  dt-bindings: input: touchscreen: add bindings for focaltech,fts5452
  Input: add driver for Focaltech FTS touchscreen
  arm64: dts: qcom: sdm845-xiaomi-beryllium-common: add touchscreen
    related nodes
  arm64: dts: qcom: sdm845-xiaomi-beryllium-ebbg: introduce support for
    fts touchscreen
  arm64: dts: qcom: sdm845-shift-axolotl: update focaltech touchscreen
    properties

 .../input/touchscreen/focaltech,fts5452.yaml  |  71 +++
 MAINTAINERS                                   |   8 +
 .../boot/dts/qcom/sdm845-shift-axolotl.dts    |  15 +-
 .../qcom/sdm845-xiaomi-beryllium-common.dtsi  |  39 ++
 .../dts/qcom/sdm845-xiaomi-beryllium-ebbg.dts |  26 ++
 drivers/input/touchscreen/Kconfig             |  12 +
 drivers/input/touchscreen/Makefile            |   1 +
 drivers/input/touchscreen/focaltech_fts5452.c | 432 ++++++++++++++++++
 8 files changed, 596 insertions(+), 8 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/input/touchscreen/focaltech,fts5452.yaml
 create mode 100644 drivers/input/touchscreen/focaltech_fts5452.c

-- 
2.40.0


^ permalink raw reply

* [PATCH v2 1/5] dt-bindings: input: touchscreen: add bindings for focaltech,fts5452
From: Joel Selvaraj @ 2023-04-10 16:01 UTC (permalink / raw)
  To: Caleb Connolly, Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski,
	Andy Gross, Bjorn Andersson, Konrad Dybcio, Henrik Rydberg,
	Arnd Bergmann, Robert Jarzmik, Jeff LaBundy, Markuss Broks,
	Jean Delvare, Job Noorman, Alistair Francis, Chris Morgan,
	Hans de Goede
  Cc: linux-input, devicetree, linux-kernel, linux-arm-msm,
	~postmarketos/upstreaming, phone-devel, Joel Selvaraj
In-Reply-To: <20230410160200.57261-1-joelselvaraj.oss@gmail.com>

Add devicetree bindings for the Focaltech FTS touchscreen drivers.

Signed-off-by: Joel Selvaraj <joelselvaraj.oss@gmail.com>
Signed-off-by: Caleb Connolly <caleb@connolly.tech>
---
 .../input/touchscreen/focaltech,fts5452.yaml  | 71 +++++++++++++++++++
 1 file changed, 71 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/input/touchscreen/focaltech,fts5452.yaml

diff --git a/Documentation/devicetree/bindings/input/touchscreen/focaltech,fts5452.yaml b/Documentation/devicetree/bindings/input/touchscreen/focaltech,fts5452.yaml
new file mode 100644
index 000000000000..f42868293439
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/focaltech,fts5452.yaml
@@ -0,0 +1,71 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/input/touchscreen/focaltech,fts5452.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Focaltech FTS I2C Touchscreen Controller
+
+maintainers:
+  - Joel Selvaraj <joelselvaraj.oss@gmail.com>
+  - Caleb Connolly <caleb@connolly.tech>
+
+allOf:
+  - $ref: touchscreen.yaml#
+
+properties:
+  compatible:
+    enum:
+      - focaltech,fts5452
+      - focaltech,fts8719
+
+  reg:
+    const: 0x38
+
+  interrupts:
+    maxItems: 1
+
+  reset-gpios:
+    maxItems: 1
+
+  avdd-supply:
+    description: regulator supplying analog power (2.6V to 3.3V).
+
+  vddio-supply:
+    description: regulator supplying IO power (1.8V).
+
+unevaluatedProperties: false
+
+required:
+  - compatible
+  - reg
+  - touchscreen-size-x
+  - touchscreen-size-y
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    #include <dt-bindings/gpio/gpio.h>
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      touchscreen@38 {
+        compatible = "focaltech,fts5452";
+        reg = <0x38>;
+
+        interrupt-parent = <&tlmm>;
+        interrupts = <125 IRQ_TYPE_EDGE_FALLING>;
+        reset-gpios = <&tlmm 99 GPIO_ACTIVE_LOW>;
+
+        avdd-supply = <&vreg_l28a_3p0>;
+        vddio-supply = <&vreg_l14a_1p88>;
+
+        pinctrl-names = "default", "suspend";
+        pinctrl-0 = <&ts_int_active &ts_reset_active>;
+        pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>;
+
+        touchscreen-size-x = <1080>;
+        touchscreen-size-y = <2160>;
+      };
+    };
-- 
2.40.0


^ permalink raw reply related

* [PATCH v2 3/5] arm64: dts: qcom: sdm845-xiaomi-beryllium-common: add touchscreen related nodes
From: Joel Selvaraj @ 2023-04-10 16:01 UTC (permalink / raw)
  To: Caleb Connolly, Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski,
	Andy Gross, Bjorn Andersson, Konrad Dybcio, Henrik Rydberg,
	Arnd Bergmann, Robert Jarzmik, Jeff LaBundy, Markuss Broks,
	Jean Delvare, Job Noorman, Alistair Francis, Chris Morgan,
	Hans de Goede
  Cc: linux-input, devicetree, linux-kernel, linux-arm-msm,
	~postmarketos/upstreaming, phone-devel, Joel Selvaraj
In-Reply-To: <20230410160200.57261-1-joelselvaraj.oss@gmail.com>

Enable qupv3_id_1 and gpi_dma1 as they are required for configuring
touchscreen. Also add pinctrl configurations needed for touchscreen.
These are common for both the tianma and ebbg touchscreen variant.
In the subsequent patch, we will initially enable support for the focaltech
touchscreen used in the EBBG variant. This is done in preparation for that.

Signed-off-by: Joel Selvaraj <joelselvaraj.oss@gmail.com>
---
 .../qcom/sdm845-xiaomi-beryllium-common.dtsi  | 39 +++++++++++++++++++
 1 file changed, 39 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi
index 5ed975cc6ecb..b580a32fdc3b 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi
@@ -268,6 +268,10 @@ &gmu {
 	status = "okay";
 };
 
+&gpi_dma1 {
+	status = "okay";
+};
+
 &gpu {
 	status = "okay";
 
@@ -376,6 +380,10 @@ &qupv3_id_0 {
 	status = "okay";
 };
 
+&qupv3_id_1 {
+	status = "okay";
+};
+
 &sdhc_2 {
 	status = "okay";
 
@@ -481,6 +489,37 @@ sdc2_card_det_n: sd-card-det-n-state {
 		function = "gpio";
 		bias-pull-up;
 	};
+
+	ts_int_default: ts-int-default-state {
+		pins = "gpio31";
+		function = "gpio";
+		drive-strength = <16>;
+		bias-pull-down;
+		input-enable;
+	};
+
+	ts_reset_default: ts-reset-default-state {
+		pins = "gpio32";
+		function = "gpio";
+		drive-strength = <16>;
+		output-high;
+	};
+
+	ts_int_sleep: ts-int-sleep-state {
+		pins = "gpio31";
+		function = "gpio";
+		drive-strength = <2>;
+		bias-pull-down;
+		input-enable;
+	};
+
+	ts_reset_sleep: ts-reset-sleep-state {
+		pins = "gpio32";
+		function = "gpio";
+		drive-strength = <2>;
+		bias-disable;
+		output-low;
+	};
 };
 
 &uart6 {
-- 
2.40.0


^ permalink raw reply related

* [PATCH v2 4/5] arm64: dts: qcom: sdm845-xiaomi-beryllium-ebbg: introduce support for fts touchscreen
From: Joel Selvaraj @ 2023-04-10 16:01 UTC (permalink / raw)
  To: Caleb Connolly, Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski,
	Andy Gross, Bjorn Andersson, Konrad Dybcio, Henrik Rydberg,
	Arnd Bergmann, Robert Jarzmik, Jeff LaBundy, Markuss Broks,
	Jean Delvare, Job Noorman, Alistair Francis, Chris Morgan,
	Hans de Goede
  Cc: linux-input, devicetree, linux-kernel, linux-arm-msm,
	~postmarketos/upstreaming, phone-devel, Joel Selvaraj
In-Reply-To: <20230410160200.57261-1-joelselvaraj.oss@gmail.com>

The Poco F1 EBBG variant uses Focaltech FTS8719 touchscreen. Introduce
support for it.

Signed-off-by: Joel Selvaraj <joelselvaraj.oss@gmail.com>
---
 .../dts/qcom/sdm845-xiaomi-beryllium-ebbg.dts | 26 +++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-ebbg.dts b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-ebbg.dts
index 76931ebad065..f857ed3e2df4 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-ebbg.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-ebbg.dts
@@ -13,3 +13,29 @@ &display_panel {
 	compatible = "ebbg,ft8719";
 	status = "okay";
 };
+
+&i2c14 {
+	status = "okay";
+
+	dmas =  <&gpi_dma1 0 6 QCOM_GPI_I2C>,
+		<&gpi_dma1 1 6 QCOM_GPI_I2C>;
+	dma-names = "tx", "rx";
+
+	touchscreen@38 {
+		compatible = "focaltech,fts8719";
+		reg = <0x38>;
+
+		interrupt-parent = <&tlmm>;
+		interrupts = <31 IRQ_TYPE_EDGE_FALLING>;
+		reset-gpios = <&tlmm 32 GPIO_ACTIVE_LOW>;
+
+		vddio-supply = <&vreg_l14a_1p8>;
+
+		pinctrl-names = "default", "sleep";
+		pinctrl-0 = <&ts_int_default &ts_reset_default>;
+		pinctrl-1 = <&ts_int_sleep &ts_reset_sleep>;
+
+		touchscreen-size-x = <1080>;
+		touchscreen-size-y = <2246>;
+	};
+};
-- 
2.40.0


^ permalink raw reply related

* [PATCH v2 2/5] Input: add driver for Focaltech FTS touchscreen
From: Joel Selvaraj @ 2023-04-10 16:01 UTC (permalink / raw)
  To: Caleb Connolly, Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski,
	Andy Gross, Bjorn Andersson, Konrad Dybcio, Henrik Rydberg,
	Arnd Bergmann, Robert Jarzmik, Jeff LaBundy, Markuss Broks,
	Jean Delvare, Job Noorman, Alistair Francis, Chris Morgan,
	Hans de Goede
  Cc: linux-input, devicetree, linux-kernel, linux-arm-msm,
	~postmarketos/upstreaming, phone-devel, Joel Selvaraj
In-Reply-To: <20230410160200.57261-1-joelselvaraj.oss@gmail.com>

The Focaltech FTS driver supports several variants of focaltech
touchscreens found in ~2018 era smartphones including variants found on
the PocoPhone F1 and the SHIFT6mq which are already present in mainline.
This driver is loosely based on the original driver from Focaltech
but has been simplified and largely reworked.

Co-developed-by: Caleb Connolly <caleb@connolly.tech>
Signed-off-by: Caleb Connolly <caleb@connolly.tech>
Signed-off-by: Joel Selvaraj <joelselvaraj.oss@gmail.com>
---
 MAINTAINERS                                   |   8 +
 drivers/input/touchscreen/Kconfig             |  12 +
 drivers/input/touchscreen/Makefile            |   1 +
 drivers/input/touchscreen/focaltech_fts5452.c | 432 ++++++++++++++++++
 4 files changed, 453 insertions(+)
 create mode 100644 drivers/input/touchscreen/focaltech_fts5452.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 7ec4ce64f66d..1a3ea61e1f52 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8028,6 +8028,14 @@ L:	linux-input@vger.kernel.org
 S:	Maintained
 F:	drivers/input/joystick/fsia6b.c
 
+FOCALTECH FTS5452 TOUCHSCREEN DRIVER
+M:	Joel Selvaraj <joelselvaraj.oss@gmail.com>
+M:	Caleb Connolly <caleb@connolly.tech>
+L:	linux-input@vger.kernel.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/input/touchscreen/focaltech,fts5452.yaml
+F:	drivers/input/touchscreen/focaltech_fts5452.c
+
 FOCUSRITE SCARLETT GEN 2/3 MIXER DRIVER
 M:	Geoffrey D. Bennett <g@b4.vu>
 L:	alsa-devel@alsa-project.org (moderated for non-subscribers)
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 1feecd7ed3cb..11af91504969 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -388,6 +388,18 @@ config TOUCHSCREEN_EXC3000
 	  To compile this driver as a module, choose M here: the
 	  module will be called exc3000.
 
+config TOUCHSCREEN_FOCALTECH_FTS5452
+	tristate "Focaltech FTS Touchscreen"
+	depends on I2C
+	help
+	  Say Y here to enable support for I2C connected Focaltech FTS
+	  based touch panels, including the 5452 and 8917 panels.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called focaltech_fts.
+
 config TOUCHSCREEN_FUJITSU
 	tristate "Fujitsu serial touchscreen"
 	select SERIO
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 159cd5136fdb..47d78c9cff21 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -45,6 +45,7 @@ obj-$(CONFIG_TOUCHSCREEN_ELO)		+= elo.o
 obj-$(CONFIG_TOUCHSCREEN_EGALAX)	+= egalax_ts.o
 obj-$(CONFIG_TOUCHSCREEN_EGALAX_SERIAL)	+= egalax_ts_serial.o
 obj-$(CONFIG_TOUCHSCREEN_EXC3000)	+= exc3000.o
+obj-$(CONFIG_TOUCHSCREEN_FOCALTECH_FTS5452)	+= focaltech_fts5452.o
 obj-$(CONFIG_TOUCHSCREEN_FUJITSU)	+= fujitsu_ts.o
 obj-$(CONFIG_TOUCHSCREEN_GOODIX)	+= goodix_ts.o
 obj-$(CONFIG_TOUCHSCREEN_HIDEEP)	+= hideep.o
diff --git a/drivers/input/touchscreen/focaltech_fts5452.c b/drivers/input/touchscreen/focaltech_fts5452.c
new file mode 100644
index 000000000000..abf8a2f271ca
--- /dev/null
+++ b/drivers/input/touchscreen/focaltech_fts5452.c
@@ -0,0 +1,432 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * FocalTech touchscreen driver.
+ *
+ * Copyright (c) 2010-2017, FocalTech Systems, Ltd., all rights reserved.
+ * Copyright (C) 2018 XiaoMi, Inc.
+ * Copyright (c) 2021 Caleb Connolly <caleb@connolly.tech>
+ * Copyright (c) 2023 Joel Selvaraj <joelselvaraj.oss@gmail.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/input/touchscreen.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+#define FTS_REG_CHIP_ID_H		0xA3
+#define FTS_REG_CHIP_ID_L		0x9F
+
+#define FTS_MAX_POINTS_SUPPORT		10
+#define FTS_ONE_TOUCH_LEN		6
+
+#define FTS_TOUCH_X_H_OFFSET		3
+#define FTS_TOUCH_X_L_OFFSET		4
+#define FTS_TOUCH_Y_H_OFFSET		5
+#define FTS_TOUCH_Y_L_OFFSET		6
+#define FTS_TOUCH_PRESSURE_OFFSET	7
+#define FTS_TOUCH_AREA_OFFSET		8
+#define FTS_TOUCH_TYPE_OFFSET		3
+#define FTS_TOUCH_ID_OFFSET		5
+
+#define FTS_TOUCH_DOWN			0
+#define FTS_TOUCH_UP			1
+#define FTS_TOUCH_CONTACT		2
+
+#define FTS_INTERVAL_READ_REG_MS	100
+#define FTS_TIMEOUT_READ_REG_MS		2000
+
+#define FTS_DRIVER_NAME			"fts-i2c"
+
+static const u16 fts_chip_types[] = {
+	0x5452,
+	0x8719,
+};
+
+struct fts_ts_data {
+	struct i2c_client *client;
+	struct input_dev *input_dev;
+	struct regmap *regmap;
+	int irq;
+	struct regulator_bulk_data regulators[2];
+	u8 max_touch_points;
+	u8 *point_buf;
+	int point_buf_size;
+	struct gpio_desc *reset_gpio;
+	struct touchscreen_properties prop;
+};
+
+struct fts_i2c_chip_data {
+	int max_touch_points;
+};
+
+int fts_check_status(struct fts_ts_data *data)
+{
+	int error, i = 0, count = 0;
+	unsigned int val, id;
+
+	do {
+		error = regmap_read(data->regmap, FTS_REG_CHIP_ID_L, &id);
+		if (error)
+			dev_err(&data->client->dev, "I2C read failed: %d\n", error);
+
+		error = regmap_read(data->regmap, FTS_REG_CHIP_ID_H, &val);
+		if (error)
+			dev_err(&data->client->dev, "I2C read failed: %d\n", error);
+
+		id |= val << 8;
+
+		for (i = 0; i < ARRAY_SIZE(fts_chip_types); i++)
+			if (id == fts_chip_types[i])
+				return 0;
+
+		count++;
+		msleep(FTS_INTERVAL_READ_REG_MS);
+	} while ((count * FTS_INTERVAL_READ_REG_MS) < FTS_TIMEOUT_READ_REG_MS);
+
+	return -EIO;
+}
+
+static int fts_report_touch(struct fts_ts_data *data)
+{
+	struct input_dev *input_dev = data->input_dev;
+	int base;
+	unsigned int x, y, z, maj;
+	u8 slot, type;
+	int error, i = 0;
+
+	u8 *buf = data->point_buf;
+
+	memset(buf, 0, data->point_buf_size);
+
+	error = regmap_bulk_read(data->regmap, 0, buf, data->point_buf_size);
+	if (error) {
+		dev_err(&data->client->dev, "I2C read failed: %d\n", error);
+		return error;
+	}
+
+	for (i = 0; i < data->max_touch_points; i++) {
+		base = FTS_ONE_TOUCH_LEN * i;
+
+		slot = buf[base + FTS_TOUCH_ID_OFFSET] >> 4;
+		if (slot >= data->max_touch_points)
+			break;
+
+		x = ((buf[base + FTS_TOUCH_X_H_OFFSET] & 0x0F) << 8) +
+		    (buf[base + FTS_TOUCH_X_L_OFFSET] & 0xFF);
+		y = ((buf[base + FTS_TOUCH_Y_H_OFFSET] & 0x0F) << 8) +
+		    (buf[base + FTS_TOUCH_Y_L_OFFSET] & 0xFF);
+
+		z = buf[base + FTS_TOUCH_PRESSURE_OFFSET];
+		if (z == 0)
+			z = 0x3f;
+
+		maj = buf[base + FTS_TOUCH_AREA_OFFSET] >> 4;
+		if (maj == 0)
+			maj = 0x09;
+
+		type = buf[base + FTS_TOUCH_TYPE_OFFSET] >> 6;
+
+		input_mt_slot(input_dev, slot);
+		if (type == FTS_TOUCH_DOWN || type == FTS_TOUCH_CONTACT) {
+			input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, true);
+			touchscreen_report_pos(data->input_dev, &data->prop, x, y, true);
+			input_report_abs(input_dev, ABS_MT_PRESSURE, z);
+			input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, maj);
+			input_report_key(data->input_dev, BTN_TOUCH, 1);
+		} else {
+			input_report_key(data->input_dev, BTN_TOUCH, 0);
+			input_mt_report_slot_inactive(input_dev);
+		}
+	}
+	input_mt_sync_frame(input_dev);
+	input_sync(input_dev);
+
+	return 0;
+}
+
+static irqreturn_t fts_ts_interrupt(int irq, void *dev_id)
+{
+	struct fts_ts_data *data = dev_id;
+
+	return fts_report_touch(data) ? IRQ_NONE : IRQ_HANDLED;
+}
+
+static void fts_power_off(void *d)
+{
+	struct fts_ts_data *data = d;
+
+	regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators);
+}
+
+static int fts_start(struct fts_ts_data *data)
+{
+	int error;
+
+	error = regulator_bulk_enable(ARRAY_SIZE(data->regulators),
+				      data->regulators);
+	if (error) {
+		dev_err(&data->client->dev, "failed to enable regulators\n");
+		return error;
+	}
+
+	gpiod_set_value_cansleep(data->reset_gpio, 0);
+	msleep(200);
+
+	enable_irq(data->irq);
+
+	return 0;
+}
+
+static int fts_stop(struct fts_ts_data *data)
+{
+	disable_irq(data->irq);
+	gpiod_set_value_cansleep(data->reset_gpio, 1);
+	fts_power_off(data);
+
+	return 0;
+}
+
+static int fts_input_open(struct input_dev *dev)
+{
+	struct fts_ts_data *data = input_get_drvdata(dev);
+	int error;
+
+	error = fts_start(data);
+	if (error)
+		return error;
+
+	error = fts_check_status(data);
+	if (error) {
+		dev_err(&data->client->dev, "Failed to start or unsupported chip");
+		return error;
+	}
+
+	return 0;
+}
+
+static void fts_input_close(struct input_dev *dev)
+{
+	struct fts_ts_data *data = input_get_drvdata(dev);
+
+	fts_stop(data);
+}
+
+static int fts_input_init(struct fts_ts_data *data)
+{
+	struct device *dev = &data->client->dev;
+	struct input_dev *input_dev;
+	int error = 0;
+
+	input_dev = devm_input_allocate_device(dev);
+	if (!input_dev)
+		return -ENOMEM;
+
+	data->input_dev = input_dev;
+
+	input_dev->name = FTS_DRIVER_NAME;
+	input_dev->id.bustype = BUS_I2C;
+	input_dev->dev.parent = dev;
+	input_dev->open = fts_input_open;
+	input_dev->close = fts_input_close;
+	input_set_drvdata(input_dev, data);
+
+	input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_X);
+	input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_Y);
+	input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
+	input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, 255, 0, 0);
+
+	touchscreen_parse_properties(input_dev, true, &data->prop);
+	if (!data->prop.max_x || !data->prop.max_y) {
+		dev_err(dev,
+			"touchscreen-size-x and/or touchscreen-size-y not set in device properties\n");
+		return -EINVAL;
+	}
+
+	error = input_mt_init_slots(input_dev, data->max_touch_points,
+				    INPUT_MT_DIRECT);
+	if (error)
+		return error;
+
+	data->point_buf_size = (data->max_touch_points * FTS_ONE_TOUCH_LEN) + 3;
+	data->point_buf = devm_kzalloc(dev, data->point_buf_size, GFP_KERNEL);
+	if (!data->point_buf)
+		return -ENOMEM;
+
+	error = input_register_device(input_dev);
+	if (error) {
+		dev_err(dev, "Failed to register input device\n");
+		return error;
+	}
+
+	return 0;
+}
+
+static const struct regmap_config fts_ts_i2c_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+};
+
+static int fts_ts_probe(struct i2c_client *client)
+{
+	const struct i2c_device_id *id = i2c_client_get_device_id(client);
+	const struct fts_i2c_chip_data *chip_data;
+	struct fts_ts_data *data;
+	int error = 0;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		dev_err(&client->dev, "I2C not supported");
+		return -ENODEV;
+	}
+
+	if (!client->irq) {
+		dev_err(&client->dev, "No irq specified\n");
+		return -EINVAL;
+	}
+
+	data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	chip_data = device_get_match_data(&client->dev);
+	if (!chip_data)
+		chip_data = (const struct fts_i2c_chip_data *)id->driver_data;
+	if (!chip_data || !chip_data->max_touch_points) {
+		dev_err(&client->dev, "invalid or missing chip data\n");
+		return -EINVAL;
+	}
+	if (chip_data->max_touch_points > FTS_MAX_POINTS_SUPPORT) {
+		dev_err(&client->dev,
+			"invalid chip data, max_touch_points should be less than or equal to %d\n",
+			FTS_MAX_POINTS_SUPPORT);
+		return -EINVAL;
+	}
+	data->max_touch_points = chip_data->max_touch_points;
+
+	data->client = client;
+	i2c_set_clientdata(client, data);
+
+	data->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_HIGH);
+	if (IS_ERR(data->reset_gpio)) {
+		error = PTR_ERR(data->reset_gpio);
+		dev_err(&client->dev, "Failed to request reset gpio, error %d\n", error);
+		return error;
+	}
+
+	data->regmap = devm_regmap_init_i2c(client, &fts_ts_i2c_regmap_config);
+	if (IS_ERR(data->regmap)) {
+		error = PTR_ERR(data->regmap);
+		dev_err(&client->dev, "regmap allocation failed, error %d\n", error);
+		return error;
+	}
+
+	/*
+	 * AVDD is the analog voltage supply (2.6V to 3.3V)
+	 * VDDIO is the digital voltage supply (1.8V)
+	 */
+	data->regulators[0].supply = "avdd";
+	data->regulators[1].supply = "vddio";
+	error = devm_regulator_bulk_get(&client->dev, ARRAY_SIZE(data->regulators),
+					data->regulators);
+	if (error) {
+		dev_err(&client->dev, "Failed to get regulators %d\n", error);
+		return error;
+	}
+
+	error = devm_add_action_or_reset(&client->dev, fts_power_off, data);
+	if (error) {
+		dev_err(&client->dev, "failed to install power off handler\n");
+		return error;
+	}
+
+	error = devm_request_threaded_irq(&client->dev, client->irq, NULL,
+					  fts_ts_interrupt, IRQF_ONESHOT,
+					  client->name, data);
+	if (error) {
+		dev_err(&client->dev, "Failed to request IRQ: %d\n", error);
+		return error;
+	}
+
+	error = fts_input_init(data);
+	if (error)
+		return error;
+
+	return 0;
+}
+
+static int fts_pm_suspend(struct device *dev)
+{
+	struct fts_ts_data *data = dev_get_drvdata(dev);
+
+	mutex_lock(&data->input_dev->mutex);
+
+	if (input_device_enabled(data->input_dev))
+		fts_stop(data);
+
+	mutex_unlock(&data->input_dev->mutex);
+
+	return 0;
+}
+
+static int fts_pm_resume(struct device *dev)
+{
+	struct fts_ts_data *data = dev_get_drvdata(dev);
+	int error = 0;
+
+	mutex_lock(&data->input_dev->mutex);
+
+	if (input_device_enabled(data->input_dev))
+		error = fts_start(data);
+
+	mutex_unlock(&data->input_dev->mutex);
+
+	return error;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(fts_dev_pm_ops, fts_pm_suspend, fts_pm_resume);
+
+static const struct fts_i2c_chip_data fts5452_chip_data = {
+	.max_touch_points = 5,
+};
+
+static const struct fts_i2c_chip_data fts8719_chip_data = {
+	.max_touch_points = 10,
+};
+
+static const struct i2c_device_id fts_i2c_id[] = {
+	{ .name = "fts5452", .driver_data = (long)&fts5452_chip_data },
+	{ .name = "fts8719", .driver_data = (long)&fts8719_chip_data },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(i2c, fts_i2c_id);
+
+static const struct of_device_id fts_of_match[] = {
+	{ .compatible = "focaltech,fts5452", .data = &fts5452_chip_data },
+	{ .compatible = "focaltech,fts8719", .data = &fts8719_chip_data },
+	{ /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, fts_of_match);
+
+static struct i2c_driver fts_ts_driver = {
+	.probe_new = fts_ts_probe,
+	.id_table = fts_i2c_id,
+	.driver = {
+		.name = FTS_DRIVER_NAME,
+		.pm = pm_sleep_ptr(&fts_dev_pm_ops),
+		.of_match_table = fts_of_match,
+	},
+};
+module_i2c_driver(fts_ts_driver);
+
+MODULE_AUTHOR("Joel Selvaraj <joelselvaraj.oss@gmail.com>");
+MODULE_AUTHOR("Caleb Connolly <caleb@connolly.tech>");
+MODULE_DESCRIPTION("Focaltech Touchscreen Driver");
+MODULE_LICENSE("GPL");
-- 
2.40.0


^ permalink raw reply related

* [PATCH v2 5/5] arm64: dts: qcom: sdm845-shift-axolotl: update focaltech touchscreen properties
From: Joel Selvaraj @ 2023-04-10 16:02 UTC (permalink / raw)
  To: Caleb Connolly, Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski,
	Andy Gross, Bjorn Andersson, Konrad Dybcio, Henrik Rydberg,
	Arnd Bergmann, Robert Jarzmik, Jeff LaBundy, Markuss Broks,
	Jean Delvare, Job Noorman, Alistair Francis, Chris Morgan,
	Hans de Goede
  Cc: linux-input, devicetree, linux-kernel, linux-arm-msm,
	~postmarketos/upstreaming, phone-devel, Joel Selvaraj
In-Reply-To: <20230410160200.57261-1-joelselvaraj.oss@gmail.com>

The touchscreen nodes were added before the driver patches were merged.
Update the focaltech touchscreen properties to match with the upstreamed
focaltech driver. Also, the touchscreen used is in axolotl is fts5452
and not fts8719.

Signed-off-by: Joel Selvaraj <joelselvaraj.oss@gmail.com>
---
 arch/arm64/boot/dts/qcom/sdm845-shift-axolotl.dts | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/arch/arm64/boot/dts/qcom/sdm845-shift-axolotl.dts b/arch/arm64/boot/dts/qcom/sdm845-shift-axolotl.dts
index b54e304abf71..96dd4628d9a7 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-shift-axolotl.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-shift-axolotl.dts
@@ -474,23 +474,22 @@ &i2c5 {
 	status = "okay";
 
 	touchscreen@38 {
-		compatible = "focaltech,fts8719";
+		compatible = "focaltech,fts5452";
 		reg = <0x38>;
-		wakeup-source;
+
 		interrupt-parent = <&tlmm>;
-		interrupts = <125 0x2>;
-		vdd-supply = <&vreg_l28a_3p0>;
-		vcc-i2c-supply = <&vreg_l14a_1p88>;
+		interrupts = <125 IRQ_TYPE_EDGE_FALLING>;
+		reset-gpios = <&tlmm 99 GPIO_ACTIVE_LOW>;
+
+		avdd-supply = <&vreg_l28a_3p0>;
+		vddio-supply = <&vreg_l14a_1p88>;
 
 		pinctrl-names = "default", "suspend";
 		pinctrl-0 = <&ts_int_active &ts_reset_active>;
 		pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>;
 
-		reset-gpio = <&tlmm 99 GPIO_ACTIVE_HIGH>;
-		irq-gpio = <&tlmm 125 GPIO_TRANSITORY>;
 		touchscreen-size-x = <1080>;
 		touchscreen-size-y = <2160>;
-		focaltech,max-touch-number = <5>;
 	};
 };
 
-- 
2.40.0


^ permalink raw reply related

* [dtor-input:next] BUILD SUCCESS cd7cd6f386df21725eeab5d803226d4f74177203
From: kernel test robot @ 2023-04-10 16:15 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: linux-input

tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git next
branch HEAD: cd7cd6f386df21725eeab5d803226d4f74177203  Input: cma3000_d0x - remove unneeded code

elapsed time: 812m

configs tested: 192
configs skipped: 18

The following configs have been built successfully.
More configs may be tested in the coming days.

tested configs:
alpha                            allyesconfig   gcc  
alpha        buildonly-randconfig-r005-20230409   gcc  
alpha                               defconfig   gcc  
alpha                randconfig-r005-20230409   gcc  
arc                              allyesconfig   gcc  
arc          buildonly-randconfig-r001-20230409   gcc  
arc          buildonly-randconfig-r002-20230410   gcc  
arc          buildonly-randconfig-r005-20230410   gcc  
arc                                 defconfig   gcc  
arc                  randconfig-r005-20230409   gcc  
arc                  randconfig-r013-20230410   gcc  
arc                  randconfig-r016-20230410   gcc  
arc                  randconfig-r033-20230409   gcc  
arc                  randconfig-r036-20230410   gcc  
arc                  randconfig-r043-20230409   gcc  
arc                  randconfig-r043-20230410   gcc  
arc                           tb10x_defconfig   gcc  
arm                              allmodconfig   gcc  
arm                              allyesconfig   gcc  
arm                                 defconfig   gcc  
arm                        mvebu_v7_defconfig   gcc  
arm                       omap2plus_defconfig   gcc  
arm                             pxa_defconfig   gcc  
arm                  randconfig-r001-20230409   gcc  
arm                  randconfig-r046-20230409   clang
arm                  randconfig-r046-20230410   clang
arm64                            alldefconfig   gcc  
arm64                            allyesconfig   gcc  
arm64        buildonly-randconfig-r002-20230409   clang
arm64                               defconfig   gcc  
arm64                randconfig-r002-20230410   clang
arm64                randconfig-r004-20230410   clang
arm64                randconfig-r031-20230410   clang
csky         buildonly-randconfig-r003-20230410   gcc  
csky                                defconfig   gcc  
csky                 randconfig-r032-20230409   gcc  
hexagon      buildonly-randconfig-r006-20230410   clang
hexagon              randconfig-r011-20230410   clang
hexagon              randconfig-r012-20230409   clang
hexagon              randconfig-r013-20230410   clang
hexagon              randconfig-r025-20230410   clang
hexagon              randconfig-r041-20230409   clang
hexagon              randconfig-r041-20230410   clang
hexagon              randconfig-r045-20230409   clang
hexagon              randconfig-r045-20230410   clang
i386                             allyesconfig   gcc  
i386         buildonly-randconfig-r006-20230410   clang
i386                              debian-10.3   gcc  
i386                                defconfig   gcc  
i386                 randconfig-a001-20230410   clang
i386                 randconfig-a002-20230410   clang
i386                 randconfig-a003-20230410   clang
i386                 randconfig-a004-20230410   clang
i386                 randconfig-a005-20230410   clang
i386                 randconfig-a006-20230410   clang
i386                 randconfig-a011-20230410   gcc  
i386                 randconfig-a012-20230410   gcc  
i386                 randconfig-a013-20230410   gcc  
i386                 randconfig-a014-20230410   gcc  
i386                 randconfig-a015-20230410   gcc  
i386                 randconfig-a016-20230410   gcc  
i386                 randconfig-r006-20230410   clang
i386                 randconfig-r026-20230410   gcc  
i386                 randconfig-r033-20230410   clang
ia64                             allmodconfig   gcc  
ia64         buildonly-randconfig-r003-20230410   gcc  
ia64                                defconfig   gcc  
ia64                 randconfig-r001-20230410   gcc  
ia64                 randconfig-r013-20230409   gcc  
ia64                 randconfig-r015-20230410   gcc  
ia64                 randconfig-r025-20230409   gcc  
ia64                 randconfig-r035-20230409   gcc  
ia64                          tiger_defconfig   gcc  
ia64                            zx1_defconfig   gcc  
loongarch                        allmodconfig   gcc  
loongarch                         allnoconfig   gcc  
loongarch    buildonly-randconfig-r003-20230409   gcc  
loongarch    buildonly-randconfig-r006-20230409   gcc  
loongarch                           defconfig   gcc  
loongarch            randconfig-r003-20230410   gcc  
loongarch            randconfig-r004-20230409   gcc  
loongarch            randconfig-r016-20230410   gcc  
loongarch            randconfig-r023-20230409   gcc  
loongarch            randconfig-r032-20230409   gcc  
m68k                             allmodconfig   gcc  
m68k                                defconfig   gcc  
m68k                 randconfig-r002-20230409   gcc  
m68k                 randconfig-r031-20230410   gcc  
m68k                 randconfig-r035-20230409   gcc  
m68k                 randconfig-r035-20230410   gcc  
microblaze                          defconfig   gcc  
microblaze           randconfig-r005-20230410   gcc  
mips                             allmodconfig   gcc  
mips                             allyesconfig   gcc  
mips                           ip22_defconfig   clang
mips                           ip27_defconfig   clang
mips                 randconfig-r032-20230410   gcc  
mips                           rs90_defconfig   clang
nios2        buildonly-randconfig-r004-20230410   gcc  
nios2                               defconfig   gcc  
nios2                randconfig-r011-20230409   gcc  
openrisc     buildonly-randconfig-r006-20230409   gcc  
openrisc             randconfig-r003-20230409   gcc  
openrisc             randconfig-r006-20230409   gcc  
openrisc             randconfig-r006-20230410   gcc  
openrisc             randconfig-r024-20230409   gcc  
openrisc             randconfig-r031-20230409   gcc  
openrisc             randconfig-r033-20230409   gcc  
parisc       buildonly-randconfig-r002-20230410   gcc  
parisc                              defconfig   gcc  
parisc               randconfig-r002-20230410   gcc  
parisc               randconfig-r011-20230409   gcc  
parisc               randconfig-r011-20230410   gcc  
parisc               randconfig-r012-20230409   gcc  
parisc               randconfig-r022-20230409   gcc  
parisc               randconfig-r034-20230410   gcc  
parisc64                            defconfig   gcc  
powerpc                          allmodconfig   gcc  
powerpc                           allnoconfig   gcc  
powerpc      buildonly-randconfig-r004-20230409   gcc  
powerpc                       eiger_defconfig   gcc  
powerpc                 mpc836x_mds_defconfig   clang
powerpc                      pasemi_defconfig   gcc  
powerpc              randconfig-r001-20230410   clang
powerpc              randconfig-r003-20230410   clang
powerpc              randconfig-r015-20230410   gcc  
powerpc              randconfig-r022-20230409   gcc  
riscv                            allmodconfig   gcc  
riscv                             allnoconfig   gcc  
riscv                               defconfig   gcc  
riscv                randconfig-r014-20230410   gcc  
riscv                randconfig-r026-20230409   gcc  
riscv                randconfig-r034-20230409   clang
riscv                randconfig-r042-20230409   gcc  
riscv                randconfig-r042-20230410   gcc  
riscv                          rv32_defconfig   gcc  
s390                             allmodconfig   gcc  
s390                             allyesconfig   gcc  
s390         buildonly-randconfig-r005-20230410   gcc  
s390                                defconfig   gcc  
s390                 randconfig-r001-20230409   clang
s390                 randconfig-r004-20230410   clang
s390                 randconfig-r021-20230409   gcc  
s390                 randconfig-r023-20230409   gcc  
s390                 randconfig-r044-20230409   gcc  
s390                 randconfig-r044-20230410   gcc  
sh                               allmodconfig   gcc  
sh                         ap325rxa_defconfig   gcc  
sh           buildonly-randconfig-r001-20230410   gcc  
sh           buildonly-randconfig-r004-20230410   gcc  
sh                        edosk7760_defconfig   gcc  
sh                   randconfig-r004-20230409   gcc  
sh                   randconfig-r012-20230410   gcc  
sh                   randconfig-r014-20230409   gcc  
sh                   randconfig-r015-20230409   gcc  
sh                   randconfig-r026-20230409   gcc  
sh                           se7750_defconfig   gcc  
sparc                               defconfig   gcc  
sparc                randconfig-r021-20230410   gcc  
sparc                randconfig-r031-20230409   gcc  
sparc64      buildonly-randconfig-r001-20230409   gcc  
sparc64      buildonly-randconfig-r003-20230409   gcc  
sparc64              randconfig-r005-20230410   gcc  
sparc64              randconfig-r006-20230409   gcc  
sparc64              randconfig-r021-20230409   gcc  
um                             i386_defconfig   gcc  
um                           x86_64_defconfig   gcc  
x86_64                            allnoconfig   gcc  
x86_64                           allyesconfig   gcc  
x86_64                              defconfig   gcc  
x86_64                                  kexec   gcc  
x86_64               randconfig-a001-20230410   clang
x86_64               randconfig-a002-20230410   clang
x86_64               randconfig-a003-20230410   clang
x86_64               randconfig-a004-20230410   clang
x86_64               randconfig-a005-20230410   clang
x86_64               randconfig-a006-20230410   clang
x86_64               randconfig-a011-20230410   gcc  
x86_64               randconfig-a012-20230410   gcc  
x86_64               randconfig-a013-20230410   gcc  
x86_64               randconfig-a014-20230410   gcc  
x86_64               randconfig-a015-20230410   gcc  
x86_64               randconfig-a016-20230410   gcc  
x86_64                        randconfig-k001   clang
x86_64               randconfig-r024-20230410   gcc  
x86_64               randconfig-r033-20230410   clang
x86_64                               rhel-8.3   gcc  
xtensa               randconfig-r014-20230410   gcc  
xtensa               randconfig-r015-20230409   gcc  
xtensa               randconfig-r016-20230409   gcc  
xtensa               randconfig-r034-20230410   gcc  
xtensa               randconfig-r036-20230410   gcc  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests

^ permalink raw reply


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