* [GIT PULL] IB chrome-platform/input for atmel_mxt_ts & chromeos_laptop for device properties
From: Benson Leung @ 2018-05-23 19:56 UTC (permalink / raw)
To: dmitry.torokhov, bleung, bleung, linux-input, dtor, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 976 bytes --]
Hi Dmitry,
The following changes since commit 96a938aa214e965d5b4a2f10443b29cad14289b9:
Input: atmel_mxt_ts - remove platform data support (2018-04-09 22:55:16 -0700)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/bleung/chrome-platform.git ib-chrome-platform-atmel-mxt-ts-device-properties
for you to fetch changes up to 5020cd29d8bfcb3f3add43ea7d58b07011ab96d8:
platform/chrome: chromeos_laptop - supply properties for ACPI devices (2018-05-23 12:48:31 -0700)
----------------------------------------------------------------
Dmitry Torokhov (1):
platform/chrome: chromeos_laptop - supply properties for ACPI devices
drivers/platform/chrome/chromeos_laptop.c | 307 +++++++++++++++++++++++++++---
1 file changed, 278 insertions(+), 29 deletions(-)
Thanks!
--
Benson Leung
Staff Software Engineer
Chrome OS Kernel
Google Inc.
bleung@google.com
Chromium OS Project
bleung@chromium.org
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: [PATCH 1/2] platform/chrome: chromeos_laptop - supply properties for ACPI devices
From: Benson Leung @ 2018-05-23 19:50 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: linux-input, Benson Leung, Nick Dyer, linux-kernel, bleung
In-Reply-To: <20180504004135.67554-1-dmitry.torokhov@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 15650 bytes --]
Hi Dmitry,
On Thu, May 03, 2018 at 05:41:34PM -0700, Dmitry Torokhov wrote:
> BayTrail-based and newer Chromebooks describe their peripherals in ACPI;
> unfortunately their description is not complete, and peripherals
> drivers, such as driver for Atmel Touch controllers, has to resort to
> DMI-matching to configure the peripherals properly. To avoid polluting
> peripheral driver code, let's teach chromeos_laptop driver to supply
> missing data via generic device properties.
>
> Note we supply "compatible" string for Atmel peripherals not because it is
> needed for matching devices and driver (matching is still done on ACPI HID
> entries), but because peripherals driver will be using presence of
> "compatible" property to determine if device properties have been attached
> to the device, and fail to bind if they are absent.
>
> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Looks good to me. I'll send you an IB with this patch, and you can add
the second.
> ---
> drivers/platform/chrome/chromeos_laptop.c | 307 ++++++++++++++++++++--
> 1 file changed, 278 insertions(+), 29 deletions(-)
>
> diff --git a/drivers/platform/chrome/chromeos_laptop.c b/drivers/platform/chrome/chromeos_laptop.c
> index 5c47f451e43b1..3cecf7933f751 100644
> --- a/drivers/platform/chrome/chromeos_laptop.c
> +++ b/drivers/platform/chrome/chromeos_laptop.c
> @@ -6,6 +6,7 @@
>
> #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
>
> +#include <linux/acpi.h>
> #include <linux/dmi.h>
> #include <linux/i2c.h>
> #include <linux/input.h>
> @@ -54,6 +55,11 @@ struct i2c_peripheral {
> struct i2c_client *client;
> };
>
> +struct acpi_peripheral {
> + char hid[ACPI_ID_LEN];
> + const struct property_entry *properties;
> +};
> +
> struct chromeos_laptop {
> /*
> * Note that we can't mark this pointer as const because
> @@ -61,6 +67,9 @@ struct chromeos_laptop {
> */
> struct i2c_peripheral *i2c_peripherals;
> unsigned int num_i2c_peripherals;
> +
> + const struct acpi_peripheral *acpi_peripherals;
> + unsigned int num_acpi_peripherals;
> };
>
> static const struct chromeos_laptop *cros_laptop;
> @@ -148,6 +157,38 @@ static void chromeos_laptop_check_adapter(struct i2c_adapter *adapter)
> }
> }
>
> +static bool chromeos_laptop_adjust_client(struct i2c_client *client)
> +{
> + const struct acpi_peripheral *acpi_dev;
> + struct acpi_device_id acpi_ids[2] = { };
> + int i;
> + int error;
> +
> + if (!has_acpi_companion(&client->dev))
> + return false;
> +
> + for (i = 0; i < cros_laptop->num_acpi_peripherals; i++) {
> + acpi_dev = &cros_laptop->acpi_peripherals[i];
> +
> + memcpy(acpi_ids[0].id, acpi_dev->hid, ACPI_ID_LEN);
> +
> + if (acpi_match_device(acpi_ids, &client->dev)) {
> + error = device_add_properties(&client->dev,
> + acpi_dev->properties);
> + if (error) {
> + dev_err(&client->dev,
> + "failed to add properties: %d\n",
> + error);
> + break;
> + }
> +
> + return true;
> + }
> + }
> +
> + return false;
> +}
> +
> static void chromeos_laptop_detach_i2c_client(struct i2c_client *client)
> {
> struct i2c_peripheral *i2c_dev;
> @@ -170,6 +211,8 @@ static int chromeos_laptop_i2c_notifier_call(struct notifier_block *nb,
> case BUS_NOTIFY_ADD_DEVICE:
> if (dev->type == &i2c_adapter_type)
> chromeos_laptop_check_adapter(to_i2c_adapter(dev));
> + else if (dev->type == &i2c_client_type)
> + chromeos_laptop_adjust_client(to_i2c_client(dev));
> break;
>
> case BUS_NOTIFY_REMOVED_DEVICE:
> @@ -191,6 +234,12 @@ static const struct chromeos_laptop _name __initconst = { \
> .num_i2c_peripherals = ARRAY_SIZE(_name##_peripherals), \
> }
>
> +#define DECLARE_ACPI_CROS_LAPTOP(_name) \
> +static const struct chromeos_laptop _name __initconst = { \
> + .acpi_peripherals = _name##_peripherals, \
> + .num_acpi_peripherals = ARRAY_SIZE(_name##_peripherals), \
> +}
> +
> static struct i2c_peripheral samsung_series_5_550_peripherals[] __initdata = {
> /* Touchpad. */
> {
> @@ -234,16 +283,25 @@ static const int chromebook_pixel_tp_keys[] __initconst = {
>
> static const struct property_entry
> chromebook_pixel_trackpad_props[] __initconst = {
> + PROPERTY_ENTRY_STRING("compatible", "atmel,maxtouch"),
> PROPERTY_ENTRY_U32_ARRAY("linux,gpio-keymap", chromebook_pixel_tp_keys),
> { }
> };
>
> +static const struct property_entry
> +chromebook_atmel_touchscreen_props[] __initconst = {
> + PROPERTY_ENTRY_STRING("compatible", "atmel,maxtouch"),
> + { }
> +};
> +
> static struct i2c_peripheral chromebook_pixel_peripherals[] __initdata = {
> /* Touch Screen. */
> {
> .board_info = {
> I2C_BOARD_INFO("atmel_mxt_ts",
> ATMEL_TS_I2C_ADDR),
> + .properties =
> + chromebook_atmel_touchscreen_props,
> .flags = I2C_CLIENT_WAKE,
> },
> .dmi_name = "touchscreen",
> @@ -354,6 +412,8 @@ static struct i2c_peripheral acer_c720_peripherals[] __initdata = {
> .board_info = {
> I2C_BOARD_INFO("atmel_mxt_ts",
> ATMEL_TS_I2C_ADDR),
> + .properties =
> + chromebook_atmel_touchscreen_props,
> .flags = I2C_CLIENT_WAKE,
> },
> .dmi_name = "touchscreen",
> @@ -419,6 +479,47 @@ static struct i2c_peripheral cr48_peripherals[] __initdata = {
> };
> DECLARE_CROS_LAPTOP(cr48);
>
> +static const u32 samus_touchpad_buttons[] __initconst = {
> + KEY_RESERVED,
> + KEY_RESERVED,
> + KEY_RESERVED,
> + BTN_LEFT
> +};
> +
> +static const struct property_entry samus_trackpad_props[] __initconst = {
> + PROPERTY_ENTRY_STRING("compatible", "atmel,maxtouch"),
> + PROPERTY_ENTRY_U32_ARRAY("linux,gpio-keymap", samus_touchpad_buttons),
> + { }
> +};
> +
> +static struct acpi_peripheral samus_peripherals[] __initdata = {
> + /* Touchpad */
> + {
> + .hid = "ATML0000",
> + .properties = samus_trackpad_props,
> + },
> + /* Touchsceen */
> + {
> + .hid = "ATML0001",
> + .properties = chromebook_atmel_touchscreen_props,
> + },
> +};
> +DECLARE_ACPI_CROS_LAPTOP(samus);
> +
> +static struct acpi_peripheral generic_atmel_peripherals[] __initdata = {
> + /* Touchpad */
> + {
> + .hid = "ATML0000",
> + .properties = chromebook_pixel_trackpad_props,
> + },
> + /* Touchsceen */
> + {
> + .hid = "ATML0001",
> + .properties = chromebook_atmel_touchscreen_props,
> + },
> +};
> +DECLARE_ACPI_CROS_LAPTOP(generic_atmel);
> +
> static const struct dmi_system_id chromeos_laptop_dmi_table[] __initconst = {
> {
> .ident = "Samsung Series 5 550",
> @@ -502,17 +603,64 @@ static const struct dmi_system_id chromeos_laptop_dmi_table[] __initconst = {
> },
> .driver_data = (void *)&cr48,
> },
> + /* Devices with peripherals incompletely described in ACPI */
> + {
> + .ident = "Chromebook Pro",
> + .matches = {
> + DMI_MATCH(DMI_SYS_VENDOR, "Google"),
> + DMI_MATCH(DMI_PRODUCT_NAME, "Caroline"),
> + },
> + .driver_data = (void *)&samus,
> + },
> + {
> + .ident = "Google Pixel 2 (2015)",
> + .matches = {
> + DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
> + DMI_MATCH(DMI_PRODUCT_NAME, "Samus"),
> + },
> + .driver_data = (void *)&samus,
> + },
> + {
> + /*
> + * Other Chromebooks with Atmel touch controllers:
> + * - Celes, Winky (touchpad)
> + * - Clapper, Expresso, Rambi, Glimmer (touchscreen)
> + */
> + .ident = "Other Chromebook",
> + .matches = {
> + /*
> + * This will match all Google devices, not only devices
> + * with Atmel, but we will validate that the device
> + * actually has matching peripherals.
> + */
> + DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
> + },
> + .driver_data = (void *)&generic_atmel,
> + },
> { }
> };
> MODULE_DEVICE_TABLE(dmi, chromeos_laptop_dmi_table);
>
> -static int __init chromeos_laptop_scan_adapter(struct device *dev, void *data)
> +static int __init chromeos_laptop_scan_peripherals(struct device *dev, void *data)
> {
> - struct i2c_adapter *adapter;
> + int error;
>
> - adapter = i2c_verify_adapter(dev);
> - if (adapter)
> - chromeos_laptop_check_adapter(adapter);
> + if (dev->type == &i2c_adapter_type) {
> + chromeos_laptop_check_adapter(to_i2c_adapter(dev));
> + } else if (dev->type == &i2c_client_type) {
> + if (chromeos_laptop_adjust_client(to_i2c_client(dev))) {
> + /*
> + * Now that we have needed properties re-trigger
> + * driver probe in case driver was initialized
> + * earlier and probe failed.
> + */
> + error = device_attach(dev);
> + if (error < 0)
> + dev_warn(dev,
> + "%s: device_attach() failed: %d\n",
> + __func__, error);
> + }
> + }
>
> return 0;
> }
> @@ -556,27 +704,24 @@ static int __init chromeos_laptop_setup_irq(struct i2c_peripheral *i2c_dev)
> return 0;
> }
>
> -static struct chromeos_laptop * __init
> -chromeos_laptop_prepare(const struct chromeos_laptop *src)
> +static int __init
> +chromeos_laptop_prepare_i2c_peripherals(struct chromeos_laptop *cros_laptop,
> + const struct chromeos_laptop *src)
> {
> - struct chromeos_laptop *cros_laptop;
> struct i2c_peripheral *i2c_dev;
> struct i2c_board_info *info;
> - int error;
> int i;
> + int error;
>
> - cros_laptop = kzalloc(sizeof(*cros_laptop), GFP_KERNEL);
> - if (!cros_laptop)
> - return ERR_PTR(-ENOMEM);
> + if (!src->num_i2c_peripherals)
> + return 0;
>
> cros_laptop->i2c_peripherals = kmemdup(src->i2c_peripherals,
> src->num_i2c_peripherals *
> sizeof(*src->i2c_peripherals),
> GFP_KERNEL);
> - if (!cros_laptop->i2c_peripherals) {
> - error = -ENOMEM;
> - goto err_free_cros_laptop;
> - }
> + if (!cros_laptop->i2c_peripherals)
> + return -ENOMEM;
>
> cros_laptop->num_i2c_peripherals = src->num_i2c_peripherals;
>
> @@ -586,7 +731,7 @@ chromeos_laptop_prepare(const struct chromeos_laptop *src)
>
> error = chromeos_laptop_setup_irq(i2c_dev);
> if (error)
> - goto err_destroy_cros_peripherals;
> + goto err_out;
>
> /* We need to deep-copy properties */
> if (info->properties) {
> @@ -594,14 +739,14 @@ chromeos_laptop_prepare(const struct chromeos_laptop *src)
> property_entries_dup(info->properties);
> if (IS_ERR(info->properties)) {
> error = PTR_ERR(info->properties);
> - goto err_destroy_cros_peripherals;
> + goto err_out;
> }
> }
> }
>
> - return cros_laptop;
> + return 0;
>
> -err_destroy_cros_peripherals:
> +err_out:
> while (--i >= 0) {
> i2c_dev = &cros_laptop->i2c_peripherals[i];
> info = &i2c_dev->board_info;
> @@ -609,13 +754,74 @@ chromeos_laptop_prepare(const struct chromeos_laptop *src)
> property_entries_free(info->properties);
> }
> kfree(cros_laptop->i2c_peripherals);
> -err_free_cros_laptop:
> - kfree(cros_laptop);
> - return ERR_PTR(error);
> + return error;
> +}
> +
> +static int __init
> +chromeos_laptop_prepare_acpi_peripherals(struct chromeos_laptop *cros_laptop,
> + const struct chromeos_laptop *src)
> +{
> + struct acpi_peripheral *acpi_peripherals;
> + struct acpi_peripheral *acpi_dev;
> + const struct acpi_peripheral *src_dev;
> + int n_peripherals = 0;
> + int i;
> + int error;
> +
> + for (i = 0; i < src->num_acpi_peripherals; i++) {
> + if (acpi_dev_present(src->acpi_peripherals[i].hid, NULL, -1))
> + n_peripherals++;
> + }
> +
> + if (!n_peripherals)
> + return 0;
> +
> + acpi_peripherals = kcalloc(n_peripherals,
> + sizeof(*src->acpi_peripherals),
> + GFP_KERNEL);
> + if (!acpi_peripherals)
> + return -ENOMEM;
> +
> + acpi_dev = acpi_peripherals;
> + for (i = 0; i < src->num_acpi_peripherals; i++) {
> + src_dev = &src->acpi_peripherals[i];
> + if (!acpi_dev_present(src_dev->hid, NULL, -1))
> + continue;
> +
> + *acpi_dev = *src_dev;
> +
> + /* We need to deep-copy properties */
> + if (src_dev->properties) {
> + acpi_dev->properties =
> + property_entries_dup(src_dev->properties);
> + if (IS_ERR(acpi_dev->properties)) {
> + error = PTR_ERR(acpi_dev->properties);
> + goto err_out;
> + }
> + }
> +
> + acpi_dev++;
> + }
> +
> + cros_laptop->acpi_peripherals = acpi_peripherals;
> + cros_laptop->num_acpi_peripherals = n_peripherals;
> +
> + return 0;
> +
> +err_out:
> + while (--i >= 0) {
> + acpi_dev = &acpi_peripherals[i];
> + if (acpi_dev->properties)
> + property_entries_free(acpi_dev->properties);
> + }
> +
> + kfree(acpi_peripherals);
> + return error;
> }
>
> static void chromeos_laptop_destroy(const struct chromeos_laptop *cros_laptop)
> {
> + const struct acpi_peripheral *acpi_dev;
> struct i2c_peripheral *i2c_dev;
> struct i2c_board_info *info;
> int i;
> @@ -631,10 +837,41 @@ static void chromeos_laptop_destroy(const struct chromeos_laptop *cros_laptop)
> property_entries_free(info->properties);
> }
>
> + for (i = 0; i < cros_laptop->num_acpi_peripherals; i++) {
> + acpi_dev = &cros_laptop->acpi_peripherals[i];
> +
> + if (acpi_dev->properties)
> + property_entries_free(acpi_dev->properties);
> + }
> +
> kfree(cros_laptop->i2c_peripherals);
> + kfree(cros_laptop->acpi_peripherals);
> kfree(cros_laptop);
> }
>
> +static struct chromeos_laptop * __init
> +chromeos_laptop_prepare(const struct chromeos_laptop *src)
> +{
> + struct chromeos_laptop *cros_laptop;
> + int error;
> +
> + cros_laptop = kzalloc(sizeof(*cros_laptop), GFP_KERNEL);
> + if (!cros_laptop)
> + return ERR_PTR(-ENOMEM);
> +
> + error = chromeos_laptop_prepare_i2c_peripherals(cros_laptop, src);
> + if (!error)
> + error = chromeos_laptop_prepare_acpi_peripherals(cros_laptop,
> + src);
> +
> + if (error) {
> + chromeos_laptop_destroy(cros_laptop);
> + return ERR_PTR(error);
> + }
> +
> + return cros_laptop;
> +}
> +
> static int __init chromeos_laptop_init(void)
> {
> const struct dmi_system_id *dmi_id;
> @@ -652,21 +889,33 @@ static int __init chromeos_laptop_init(void)
> if (IS_ERR(cros_laptop))
> return PTR_ERR(cros_laptop);
>
> + if (!cros_laptop->num_i2c_peripherals &&
> + !cros_laptop->num_acpi_peripherals) {
> + pr_debug("no relevant devices detected\n");
> + error = -ENODEV;
> + goto err_destroy_cros_laptop;
> + }
> +
> error = bus_register_notifier(&i2c_bus_type,
> &chromeos_laptop_i2c_notifier);
> if (error) {
> - pr_err("failed to register i2c bus notifier: %d\n", error);
> - chromeos_laptop_destroy(cros_laptop);
> - return error;
> + pr_err("failed to register i2c bus notifier: %d\n",
> + error);
> + goto err_destroy_cros_laptop;
> }
>
> /*
> - * Scan adapters that have been registered before we installed
> - * the notifier to make sure we do not miss any devices.
> + * Scan adapters that have been registered and clients that have
> + * been created before we installed the notifier to make sure
> + * we do not miss any devices.
> */
> - i2c_for_each_dev(NULL, chromeos_laptop_scan_adapter);
> + i2c_for_each_dev(NULL, chromeos_laptop_scan_peripherals);
>
> return 0;
> +
> +err_destroy_cros_laptop:
> + chromeos_laptop_destroy(cros_laptop);
> + return error;
> }
>
> static void __exit chromeos_laptop_exit(void)
> --
> 2.17.0.441.gb46fe60e1d-goog
>
--
Benson Leung
Staff Software Engineer
Chrome OS Kernel
Google Inc.
bleung@google.com
Chromium OS Project
bleung@chromium.org
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: [PATCH 3/6] ASoC: ams_delta: use GPIO lookup table
From: Tony Lindgren @ 2018-05-23 18:52 UTC (permalink / raw)
To: Mark Brown
Cc: Janusz Krzysztofik, Dmitry Torokhov, Boris Brezillon,
Tomi Valkeinen, Aaro Koskinen, Richard Weinberger, Peter Ujfalusi,
Jarkko Nikula, Liam Girdwood, linux-arm-kernel, linux-omap,
linux-kernel, linux-input, linux-mtd, linux-fbdev, alsa-devel
In-Reply-To: <20180521100503.GA24638@sirena.org.uk>
* Mark Brown <broonie@kernel.org> [180521 10:07]:
> On Fri, May 18, 2018 at 11:09:51PM +0200, Janusz Krzysztofik wrote:
> > Now as the Amstrad Delta board provides GPIO lookup tables, switch from
> > GPIO numbers to GPIO descriptors and use the table to locate required
> > GPIO pins.
>
> Acked-by: Mark Brown <broonie@kernel.org>
Thanks applying patches 1 and 3 of this series into omap-for-v4.18/soc.
It's kind of getting late for v4.18, but let's see if we can still make
it.
Seems the others can be applied to the driver trees after no more
comments, then once all that is done we can apply the last patch
in this series.
Regards,
Tony
^ permalink raw reply
* [PATCH] cros_ec_keyb: Increment the wakeup count to the specific mfd device.
From: Ravi Chandra Sadineni @ 2018-05-23 18:29 UTC (permalink / raw)
To: dmitry.torokhov, lee.jones, ravisadineni, ravisadineni, dtor
Cc: tbroch, linux-kernel, linux-input, rajatja, bleung
If the IRQ is processed during resume, increment the wakeup count to the
specific mfd device based on the event, if the mfd device is wake enabled.
This helps in identifying the specific device that caused the wake.
Signed-off-by: Ravi Chandra Sadineni <ravisadineni@chromium.org>
---
drivers/input/keyboard/cros_ec_keyb.c | 20 +++++++++++++++-----
drivers/mfd/cros_ec.c | 25 +++++++++++--------------
2 files changed, 26 insertions(+), 19 deletions(-)
diff --git a/drivers/input/keyboard/cros_ec_keyb.c b/drivers/input/keyboard/cros_ec_keyb.c
index 79eb29550c348..9b39289774405 100644
--- a/drivers/input/keyboard/cros_ec_keyb.c
+++ b/drivers/input/keyboard/cros_ec_keyb.c
@@ -245,12 +245,16 @@ static int cros_ec_keyb_work(struct notifier_block *nb,
switch (ckdev->ec->event_data.event_type) {
case EC_MKBP_EVENT_KEY_MATRIX:
/*
- * If EC is not the wake source, discard key state changes
- * during suspend.
+ * If keyb input device is not wake enabled, discard key
+ * state changes during suspend.
*/
- if (queued_during_suspend)
+ if (queued_during_suspend && ckdev->idev
+ && !device_may_wakeup(&ckdev->idev->dev))
return NOTIFY_OK;
+ else if (queued_during_suspend && ckdev->idev)
+ pm_wakeup_event(&ckdev->idev->dev, 0);
+
if (ckdev->ec->event_size != ckdev->cols) {
dev_err(ckdev->dev,
"Discarded incomplete key matrix event.\n");
@@ -270,13 +274,17 @@ static int cros_ec_keyb_work(struct notifier_block *nb,
case EC_MKBP_EVENT_BUTTON:
case EC_MKBP_EVENT_SWITCH:
/*
- * If EC is not the wake source, discard key state
+ * If bs is not wake enabled, discard key state
* changes during suspend. Switches will be re-checked in
* cros_ec_keyb_resume() to be sure nothing is lost.
*/
- if (queued_during_suspend)
+ if (queued_during_suspend && ckdev->bs_idev
+ && !device_may_wakeup(&ckdev->bs_idev->dev))
return NOTIFY_OK;
+ else if (queued_during_suspend && ckdev->bs_idev)
+ pm_wakeup_event(&ckdev->bs_idev->dev, 0);
+
if (ckdev->ec->event_data.event_type == EC_MKBP_EVENT_BUTTON) {
val = get_unaligned_le32(
&ckdev->ec->event_data.data.buttons);
@@ -522,6 +530,7 @@ static int cros_ec_keyb_register_bs(struct cros_ec_keyb *ckdev)
return ret;
}
+ device_init_wakeup(&idev->dev, true);
return 0;
}
@@ -598,6 +607,7 @@ static int cros_ec_keyb_register_matrix(struct cros_ec_keyb *ckdev)
return err;
}
+ device_init_wakeup(&idev->dev, true);
return 0;
}
diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c
index d61024141e2b6..df9520365e54b 100644
--- a/drivers/mfd/cros_ec.c
+++ b/drivers/mfd/cros_ec.c
@@ -64,12 +64,14 @@ static irqreturn_t ec_irq_thread(int irq, void *data)
* cros_ec_get_next_event() returned an error (default value for
* wake_event is true)
*/
- if (wake_event && device_may_wakeup(ec_dev->dev))
+ if (device_may_wakeup(ec_dev->dev) && wake_event
+ && ec_dev->wake_enabled)
pm_wakeup_event(ec_dev->dev, 0);
if (ret > 0)
blocking_notifier_call_chain(&ec_dev->event_notifier,
- 0, ec_dev);
+ wake_event && ec_dev->wake_enabled,
+ ec_dev);
return IRQ_HANDLED;
}
@@ -229,7 +231,7 @@ int cros_ec_suspend(struct cros_ec_device *ec_dev)
}
EXPORT_SYMBOL(cros_ec_suspend);
-static void cros_ec_drain_events(struct cros_ec_device *ec_dev)
+static void cros_ec_report_events_during_suspend(struct cros_ec_device *ec_dev)
{
while (cros_ec_get_next_event(ec_dev, NULL) > 0)
blocking_notifier_call_chain(&ec_dev->event_notifier,
@@ -253,21 +255,16 @@ int cros_ec_resume(struct cros_ec_device *ec_dev)
dev_dbg(ec_dev->dev, "Error %d sending resume event to ec",
ret);
- /*
- * In some cases, we need to distinguish between events that occur
- * during suspend if the EC is not a wake source. For example,
- * keypresses during suspend should be discarded if it does not wake
- * the system.
- *
- * If the EC is not a wake source, drain the event queue and mark them
- * as "queued during suspend".
- */
if (ec_dev->wake_enabled) {
disable_irq_wake(ec_dev->irq);
ec_dev->wake_enabled = 0;
- } else {
- cros_ec_drain_events(ec_dev);
}
+ /*
+ * Let the mfd devices know about events that occur during
+ * suspend. This way the clients know what to do with them.
+ */
+ cros_ec_report_events_during_suspend(ec_dev);
+
return 0;
}
--
2.17.0.441.gb46fe60e1d-goog
^ permalink raw reply related
* [PATCH] HID: Add support for 146b:0902 Bigben Interactive Kids' gamepad
From: Hanno Zulla @ 2018-05-23 15:57 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires, linux-input; +Cc: linux-kernel
[-- Attachment #1: Type: text/plain, Size: 834 bytes --]
Hello,
this is a driver for the "BigBen Interactive Kid-friendly Wired
Controller PS3OFMINIPAD SONY" [1] with USB id 146b:0902. It was
originally sold as a PS3 accessory and serves as a very nice gamepad for
Retropie.
With the help of serialusb [2], it was possible to analyze the protocol
used by the gamepad and fix the missing entries for the descriptor.
This is my *first* driver, so please review accordingly.
Three things where I'm not sure and hope to hear from you about:
- is that the correct use of hid_validate_values() in bigben_probe()?
- is the error handling in bigben_probe() correct?
- how do I properly test possible suspend/resume scenarios?
Thanks,
Hanno
[1]
<https://www.bigben-interactive.co.uk/bigben-products/gaming-accessories/wired-mini-controller-ps3>
[2] <https://github.com/matlo/serialusb>
[-- Attachment #2: 0001-HID-Bigben-gamepad-driver.patch --]
[-- Type: text/x-patch, Size: 17447 bytes --]
---
drivers/hid/Kconfig | 10 +
drivers/hid/Makefile | 1 +
drivers/hid/hid-bigbenff.c | 429 +++++++++++++++++++++++++++++++++++++
drivers/hid/hid-ids.h | 3 +
drivers/hid/hid-quirks.c | 3 +
5 files changed, 446 insertions(+)
create mode 100644 drivers/hid/hid-bigbenff.c
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 0000434a1fbd..30352520b012 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -182,6 +182,16 @@ config HID_BETOP_FF
Currently the following devices are known to be supported:
- BETOP 2185 PC & BFM MODE
+config HID_BIGBEN_FF
+ tristate "BigBen Interactive force feedback support"
+ depends on USB_HID
+ depends on NEW_LEDS
+ depends on LEDS_CLASS
+ select INPUT_FF_MEMLESS
+ ---help---
+ Say Y here if you want to enable force feedback and LED support for
+ the Kid-friendly Wired Controller gamepad made by BigBen Interactive.
+
config HID_CHERRY
tristate "Cherry Cymotion keyboard"
depends on HID
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 17a8bd97da9d..db6365af3fcf 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -31,6 +31,7 @@ obj-$(CONFIG_HID_ASUS) += hid-asus.o
obj-$(CONFIG_HID_AUREAL) += hid-aureal.o
obj-$(CONFIG_HID_BELKIN) += hid-belkin.o
obj-$(CONFIG_HID_BETOP_FF) += hid-betopff.o
+obj-$(CONFIG_HID_BIGBEN_FF) += hid-bigbenff.o
obj-$(CONFIG_HID_CHERRY) += hid-cherry.o
obj-$(CONFIG_HID_CHICONY) += hid-chicony.o
obj-$(CONFIG_HID_CMEDIA) += hid-cmedia.o
diff --git a/drivers/hid/hid-bigbenff.c b/drivers/hid/hid-bigbenff.c
new file mode 100644
index 000000000000..d08eea9e4382
--- /dev/null
+++ b/drivers/hid/hid-bigbenff.c
@@ -0,0 +1,429 @@
+/*
+ * LED & force feedback support for BigBen Interactive
+ *
+ * 0x146b:0x0902 "Bigben Interactive Bigben Game Pad"
+ * "Kid-friendly Wired Controller" PS3OFMINIPAD SONY
+ * sold for use with the PS3
+ *
+ * Copyright (c) 2018 Hanno Zulla <kontakt@hanno.de>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/leds.h>
+#include <linux/hid.h>
+
+#include "hid-ids.h"
+
+
+/*
+ * The original descriptor for 0x146b:0x0902
+ *
+ * 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)
+ * 0x19, 0x01, // Usage Minimum (0x01)
+ * 0x29, 0x0D, // Usage Maximum (0x0D)
+ * 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ * 0x95, 0x03, // Report Count (3)
+ * 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ * 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,Preferred State,Null State)
+ * 0x65, 0x00, // Unit (None)
+ * 0x95, 0x01, // Report Count (1)
+ * 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ * 0x26, 0xFF, 0x00, // Logical Maximum (255)
+ * 0x46, 0xFF, 0x00, // Physical Maximum (255)
+ * 0x09, 0x30, // Usage (X)
+ * 0x09, 0x31, // Usage (Y)
+ * 0x09, 0x32, // Usage (Z)
+ * 0x09, 0x35, // Usage (Rz)
+ * 0x75, 0x08, // Report Size (8)
+ * 0x95, 0x04, // Report Count (4)
+ * 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ * 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)
+ * 0x09, 0x20, // Usage (0x20)
+ * 0x09, 0x21, // Usage (0x21)
+ * 0x09, 0x22, // Usage (0x22)
+ * 0x09, 0x23, // Usage (0x23)
+ * 0x09, 0x24, // Usage (0x24)
+ * 0x09, 0x25, // Usage (0x25)
+ * 0x09, 0x26, // Usage (0x26)
+ * 0x09, 0x27, // Usage (0x27)
+ * 0x09, 0x28, // Usage (0x28)
+ * 0x09, 0x29, // Usage (0x29)
+ * 0x09, 0x2A, // Usage (0x2A)
+ * 0x09, 0x2B, // Usage (0x2B)
+ * 0x95, 0x0C, // Report Count (12)
+ * 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ * 0x0A, 0x21, 0x26, // Usage (0x2621)
+ * 0x95, 0x08, // Report Count (8)
+ * 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+ * 0x0A, 0x21, 0x26, // Usage (0x2621)
+ * 0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+ * 0x26, 0xFF, 0x03, // Logical Maximum (1023)
+ * 0x46, 0xFF, 0x03, // Physical Maximum (1023)
+ * 0x09, 0x2C, // Usage (0x2C)
+ * 0x09, 0x2D, // Usage (0x2D)
+ * 0x09, 0x2E, // Usage (0x2E)
+ * 0x09, 0x2F, // Usage (0x2F)
+ * 0x75, 0x10, // Report Size (16)
+ * 0x95, 0x04, // Report Count (4)
+ * 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ * 0xC0, // End Collection
+ */
+
+#define PID0902_RDESC_ORIG_SIZE 137
+
+/*
+ * The fixed descriptor for 0x146b:0x0902
+ *
+ * - assign right stick from Z/Rz to Rx/Ry
+ * - map analog triggers to Z/RZ
+ * - simplify feature and output descriptor
+ */
+static __u8 pid0902_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)
+ 0x19, 0x01, // Usage Minimum (0x01)
+ 0x29, 0x0D, // Usage Maximum (0x0D)
+ 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ 0x75, 0x01, // Report Size (1)
+ 0x95, 0x03, // Report Count (3)
+ 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ 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,Preferred State,Null State)
+ 0x65, 0x00, // Unit (None)
+ 0x95, 0x01, // Report Count (1)
+ 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ 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,Preferred State,No Null Position)
+ 0x95, 0x0A, // Report Count (10)
+ 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ 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,No Wrap,Linear,Preferred State,No Null Position)
+ 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)
+ 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+ 0x0A, 0x21, 0x26, // Usage (0x2621)
+ 0x95, 0x08, // Report Count (8)
+ 0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+ 0x0A, 0x21, 0x26, // Usage (0x2621)
+ 0x95, 0x08, // Report Count (8)
+ 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+ 0xC0, // End Collection
+};
+
+
+#define NUM_LEDS 4
+
+struct bigben_device {
+ int device_id;
+ struct hid_device *hid;
+ struct hid_report *report;
+ u8 led_state; // LED1 = 1 .. LED4 = 8
+ u8 right_motor_on; // right motor off/on 0/1
+ u8 left_motor_force; // left motor force 0-255
+ struct led_classdev *leds[NUM_LEDS];
+ bool work_led;
+ bool work_ff;
+ struct work_struct worker;
+};
+
+
+static void bigben_worker(struct work_struct *work)
+{
+ struct bigben_device *bigben = container_of(work,
+ struct bigben_device, worker);
+ struct hid_field *report_field = bigben->report->field[0];
+
+ if (bigben->work_led) {
+ bigben->work_led = false;
+ report_field->value[0] = 0x01; // 1 = led message
+ report_field->value[1] = 0x08; // reserved value, always 8
+ report_field->value[2] = bigben->led_state;
+ report_field->value[3] = 0x00; // padding
+ report_field->value[4] = 0x00; // padding
+ report_field->value[5] = 0x00; // padding
+ report_field->value[6] = 0x00; // padding
+ report_field->value[7] = 0x00; // padding
+ hid_hw_request(bigben->hid, bigben->report, HID_REQ_SET_REPORT);
+ }
+
+ if (bigben->work_ff) {
+ bigben->work_ff = false;
+ report_field->value[0] = 0x02; // 2 = rumble effect message
+ report_field->value[1] = 0x08; // reserved value, always 8
+ report_field->value[2] = bigben->right_motor_on;
+ report_field->value[3] = bigben->left_motor_force;
+ report_field->value[4] = 0xff; // duration 0-254 (255 = nonstop)
+ report_field->value[5] = 0x00; // padding
+ report_field->value[6] = 0x00; // padding
+ report_field->value[7] = 0x00; // padding
+ hid_hw_request(bigben->hid, bigben->report, HID_REQ_SET_REPORT);
+ }
+}
+
+static int hid_bigben_play(struct input_dev *dev, void *data,
+ struct ff_effect *effect)
+{
+ struct bigben_device *bigben = data;
+ u8 right_motor_on;
+ u8 left_motor_force;
+
+ if (effect->type != FF_RUMBLE)
+ return 0;
+
+ right_motor_on = effect->u.rumble.weak_magnitude ? 1 : 0;
+ left_motor_force = effect->u.rumble.strong_magnitude / 256;
+
+ if (right_motor_on != bigben->right_motor_on ||
+ left_motor_force != bigben->left_motor_force) {
+ bigben->right_motor_on = right_motor_on;
+ bigben->left_motor_force = left_motor_force;
+ bigben->work_ff = true;
+ schedule_work(&bigben->worker);
+ }
+
+ return 0;
+}
+
+static void bigben_set_led(struct led_classdev *led,
+ enum led_brightness value)
+{
+ struct device *dev = led->dev->parent;
+ struct hid_device *hid = to_hid_device(dev);
+ struct bigben_device *bigben = hid_get_drvdata(hid);
+ int n;
+ bool work;
+
+ if (!bigben) {
+ hid_err(hid, "No device data\n");
+ return;
+ }
+
+ for (n = 0; n < NUM_LEDS; n++) {
+ if (led == bigben->leds[n]) {
+ if (value == LED_OFF) {
+ work = (bigben->led_state & BIT(n));
+ bigben->led_state &= ~BIT(n);
+ } else {
+ work = !(bigben->led_state & BIT(n));
+ bigben->led_state |= BIT(n);
+ }
+
+ if (work) {
+ bigben->work_led = true;
+ schedule_work(&bigben->worker);
+ }
+ return;
+ }
+ }
+}
+
+static enum led_brightness bigben_get_led(struct led_classdev *led)
+{
+ struct device *dev = led->dev->parent;
+ struct hid_device *hid = to_hid_device(dev);
+ struct bigben_device *bigben = hid_get_drvdata(hid);
+ int n;
+
+ if (!bigben) {
+ hid_err(hid, "No device data\n");
+ return LED_OFF;
+ }
+
+ for (n = 0; n < NUM_LEDS; n++) {
+ if (led == bigben->leds[n])
+ return (bigben->led_state & BIT(n)) ? LED_ON : LED_OFF;
+ }
+
+ return LED_OFF;
+}
+
+static void bigben_remove_leds(struct bigben_device *bigben) {
+ struct led_classdev *led;
+ int n;
+
+ for (n = 0; n < NUM_LEDS; n++) {
+ led = bigben->leds[n];
+ bigben->leds[n] = NULL;
+ if (!led)
+ continue;
+ led_classdev_unregister(led);
+ kfree(led);
+ }
+}
+
+static void bigben_remove(struct hid_device *hid)
+{
+ struct bigben_device *bigben = hid_get_drvdata(hid);
+ bigben_remove_leds(bigben);
+ cancel_work_sync(&bigben->worker);
+ hid_hw_close(hid);
+ hid_hw_stop(hid);
+}
+
+static int bigben_probe(struct hid_device *hid,
+ const struct hid_device_id *id)
+{
+ struct bigben_device *bigben;
+ struct hid_input *hidinput;
+ struct list_head *report_list;
+ struct led_classdev *led;
+ char *name;
+ size_t name_sz;
+ int n, error;
+
+ error = hid_parse(hid);
+ if (error) {
+ hid_err(hid, "parse failed\n");
+ return error;
+ }
+
+ error = hid_hw_start(hid, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
+ if (error) {
+ hid_err(hid, "hw start failed\n");
+ return error;
+ }
+
+ if (!hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 8))
+ return -ENODEV;
+
+ bigben = kzalloc(sizeof(*bigben), GFP_KERNEL);
+ if (!bigben)
+ return -ENOMEM;
+
+ hid_set_drvdata(hid, bigben);
+ bigben->hid = hid;
+ report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+ bigben->report = list_entry(report_list->next,
+ struct hid_report, list);
+
+ hidinput = list_first_entry(&hid->inputs, struct hid_input, list);
+ set_bit(FF_RUMBLE, hidinput->input->ffbit);
+
+ INIT_WORK(&bigben->worker, bigben_worker);
+
+ error = input_ff_create_memless(hidinput->input, bigben,
+ hid_bigben_play);
+ if (error)
+ goto error;
+
+ name_sz = strlen(dev_name(&hid->dev)) + strlen("::bigben#") + 1;
+
+ for (n = 0; n < NUM_LEDS; n++) {
+ led = kzalloc(sizeof(struct led_classdev) + name_sz, GFP_KERNEL);
+ if (!led) {
+ error = -ENOMEM;
+ goto error;
+ }
+ name = (void *)(&led[1]);
+ snprintf(name, name_sz,
+ "%s::bigben%d",
+ dev_name(&hid->dev), n + 1
+ );
+ led->name = name;
+ led->brightness = (n == 0) ? LED_ON : LED_OFF;
+ led->max_brightness = 1;
+ led->brightness_get = bigben_get_led;
+ led->brightness_set = bigben_set_led;
+ bigben->leds[n] = led;
+ error = led_classdev_register(&hid->dev, led);
+ if (error)
+ goto error;
+ }
+
+ // initial state: LED1 is on, no rumble effect
+ bigben->led_state = 0b0001;
+ bigben->right_motor_on = 0;
+ bigben->left_motor_force = 0;
+ bigben->work_led = true;
+ bigben->work_ff = true;
+ schedule_work(&bigben->worker);
+
+ hid_info(hid, "Force feedback and LED support for BigBen gamepad\n");
+
+ return 0;
+
+error:
+ bigben_remove_leds(bigben);
+ kfree(bigben);
+ return error;
+}
+
+static __u8 *bigben_report_fixup(struct hid_device *hid, __u8 *rdesc,
+ unsigned int *rsize)
+{
+ if (*rsize == PID0902_RDESC_ORIG_SIZE) {
+ rdesc = pid0902_rdesc_fixed;
+ *rsize = sizeof(pid0902_rdesc_fixed);
+ }
+ return rdesc;
+}
+
+static const struct hid_device_id bigben_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_BIGBEN, USB_DEVICE_ID_BIGBEN_PS3OFMINIPAD) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, bigben_devices);
+
+static struct hid_driver bigben_driver = {
+ .name = "bigben",
+ .id_table = bigben_devices,
+ .probe = bigben_probe,
+ .report_fixup = bigben_report_fixup,
+ .remove = bigben_remove,
+};
+module_hid_driver(bigben_driver);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 46f5ecd11bf7..50a7e7c63a37 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -227,6 +227,9 @@
#define USB_VENDOR_ID_BETOP_2185V2PC 0x8380
#define USB_VENDOR_ID_BETOP_2185V2BFM 0x20bc
+#define USB_VENDOR_ID_BIGBEN 0x146b
+#define USB_DEVICE_ID_BIGBEN_PS3OFMINIPAD 0x0902
+
#define USB_VENDOR_ID_BTC 0x046e
#define USB_DEVICE_ID_BTC_EMPREX_REMOTE 0x5578
#define USB_DEVICE_ID_BTC_EMPREX_REMOTE_2 0x5577
diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
index 587e2681a53f..f347df8767b3 100644
--- a/drivers/hid/hid-quirks.c
+++ b/drivers/hid/hid-quirks.c
@@ -303,6 +303,9 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185V2PC, 0x1850) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185V2BFM, 0x5500) },
#endif
+#if IS_ENABLED(CONFIG_HID_BIGBEN_FF)
+ { HID_USB_DEVICE(USB_VENDOR_ID_BIGBEN, USB_DEVICE_ID_BIGBEN_PS3OFMINIPAD) },
+#endif
#if IS_ENABLED(CONFIG_HID_CHERRY)
{ HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION_SOLAR) },
--
2.17.0
^ permalink raw reply related
* Re: [PATCH v2 1/3] input: touchscreen: edt-ft5x06: don't make device a wakeup source by default
From: Rob Herring @ 2018-05-23 14:45 UTC (permalink / raw)
To: Daniel Mack
Cc: Mark Rutland, devicetree, Dmitry Torokhov, Sascha Hauer,
linux-input, Fabio Estevam, Shawn Guo,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
In-Reply-To: <52c1cd13-3386-8f70-aaf2-e5f4b19fd1e6@zonque.org>
On Wed, May 23, 2018 at 3:27 AM, Daniel Mack <daniel@zonque.org> wrote:
> On Tuesday, May 22, 2018 07:54 PM, Rob Herring wrote:
>>
>> On Thu, May 17, 2018 at 11:05:50AM +0200, Daniel Mack wrote:
>>>
>>> Allow configuring the device as wakeup source through device properties,
>>> as
>>> not all platforms want to wake up on touch screen activity.
>>>
>>> The I2C core automatically reads the "wakeup-source" DT property to
>>> configure a device's wakeup capability, and board supports files can set
>>> I2C_CLIENT_WAKE in the flags.
>>
>>
>> This will break wake-up on working systems. Looks like mostly i.MX, but
>> there's one AM437x board. If that board doesn't care, then it is up to
>> Shawn.
>
>
> I added the property to the dts files, but as Dmitry pointed out, I missed
> some. Sorry for that.
Just adding the property to dts files doesn't fix the compatibility
problem. If a user uses an existing dtb (before this change) with a
new kernel (after this change), then wakeup will stop working.
Rob
^ permalink raw reply
* [PATCH 2/2] ARM: dts: am437x: make edt-ft5x06 a wakeup source for imx6 boards
From: Daniel Mack @ 2018-05-23 8:30 UTC (permalink / raw)
To: dmitry.torokhov, robh+dt, mark.rutland, shawnguo, kernel,
fabio.estevam
Cc: devicetree, Daniel Mack, linux-arm-kernel, linux-input
In-Reply-To: <20180523083013.7570-1-daniel@zonque.org>
The touchscreen driver no longer configures the device as wakeup source by
default. A "wakeup-source" property is needed.
Signed-off-by: Daniel Mack <daniel@zonque.org>
---
arch/arm/boot/dts/am437x-sk-evm.dts | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/arm/boot/dts/am437x-sk-evm.dts b/arch/arm/boot/dts/am437x-sk-evm.dts
index 4118802b7fea..f17ed89da06b 100644
--- a/arch/arm/boot/dts/am437x-sk-evm.dts
+++ b/arch/arm/boot/dts/am437x-sk-evm.dts
@@ -537,6 +537,8 @@
touchscreen-size-x = <480>;
touchscreen-size-y = <272>;
+
+ wakeup-source;
};
tlv320aic3106: tlv320aic3106@1b {
--
2.14.3
^ permalink raw reply related
* [PATCH 1/2] ARM: dts: imx6: make edt-ft5x06 a wakeup source for imx6 boards
From: Daniel Mack @ 2018-05-23 8:30 UTC (permalink / raw)
To: dmitry.torokhov, robh+dt, mark.rutland, shawnguo, kernel,
fabio.estevam
Cc: devicetree, Daniel Mack, linux-arm-kernel, linux-input
The touchscreen driver no longer configures the device as wakeup source by
default. A "wakeup-source" property is needed.
Signed-off-by: Daniel Mack <daniel@zonque.org>
---
arch/arm/boot/dts/imx6q-var-dt6customboard.dts | 1 +
arch/arm/boot/dts/imx6qdl-nit6xlite.dtsi | 1 +
arch/arm/boot/dts/imx6qdl-nitrogen6_max.dtsi | 1 +
arch/arm/boot/dts/imx6qdl-nitrogen6_som2.dtsi | 1 +
arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi | 1 +
5 files changed, 5 insertions(+)
diff --git a/arch/arm/boot/dts/imx6q-var-dt6customboard.dts b/arch/arm/boot/dts/imx6q-var-dt6customboard.dts
index e0728d475f6f..7537d77b3415 100644
--- a/arch/arm/boot/dts/imx6q-var-dt6customboard.dts
+++ b/arch/arm/boot/dts/imx6q-var-dt6customboard.dts
@@ -179,6 +179,7 @@
touchscreen-size-y = <480>;
touchscreen-inverted-x;
touchscreen-inverted-y;
+ wakeup-source;
};
rtc@68 {
diff --git a/arch/arm/boot/dts/imx6qdl-nit6xlite.dtsi b/arch/arm/boot/dts/imx6qdl-nit6xlite.dtsi
index aab088f318e8..aef4a756ca81 100644
--- a/arch/arm/boot/dts/imx6qdl-nit6xlite.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-nit6xlite.dtsi
@@ -292,6 +292,7 @@
reg = <0x38>;
interrupt-parent = <&gpio1>;
interrupts = <9 IRQ_TYPE_EDGE_FALLING>;
+ wakeup-source;
};
rtc@6f {
diff --git a/arch/arm/boot/dts/imx6qdl-nitrogen6_max.dtsi b/arch/arm/boot/dts/imx6qdl-nitrogen6_max.dtsi
index 87ca6ead4098..9cb464b65be1 100644
--- a/arch/arm/boot/dts/imx6qdl-nitrogen6_max.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-nitrogen6_max.dtsi
@@ -442,6 +442,7 @@
reg = <0x38>;
interrupt-parent = <&gpio1>;
interrupts = <9 IRQ_TYPE_EDGE_FALLING>;
+ wakeup-source;
};
};
diff --git a/arch/arm/boot/dts/imx6qdl-nitrogen6_som2.dtsi b/arch/arm/boot/dts/imx6qdl-nitrogen6_som2.dtsi
index f5b763d39285..5e4da6d6fcff 100644
--- a/arch/arm/boot/dts/imx6qdl-nitrogen6_som2.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-nitrogen6_som2.dtsi
@@ -360,6 +360,7 @@
reg = <0x38>;
interrupt-parent = <&gpio1>;
interrupts = <9 IRQ_TYPE_EDGE_FALLING>;
+ wakeup-source;
};
};
diff --git a/arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi b/arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi
index 596866b0a0d2..a14872436c5e 100644
--- a/arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi
@@ -370,6 +370,7 @@
reg = <0x38>;
interrupt-parent = <&gpio1>;
interrupts = <9 IRQ_TYPE_EDGE_FALLING>;
+ wakeup-source;
};
};
--
2.14.3
^ permalink raw reply related
* Re: [PATCH v2 1/3] input: touchscreen: edt-ft5x06: don't make device a wakeup source by default
From: Daniel Mack @ 2018-05-23 8:27 UTC (permalink / raw)
To: Rob Herring
Cc: mark.rutland, devicetree, dmitry.torokhov, kernel, linux-input,
fabio.estevam, shawnguo, linux-arm-kernel
In-Reply-To: <20180522175413.GA24850@rob-hp-laptop>
On Tuesday, May 22, 2018 07:54 PM, Rob Herring wrote:
> On Thu, May 17, 2018 at 11:05:50AM +0200, Daniel Mack wrote:
>> Allow configuring the device as wakeup source through device properties, as
>> not all platforms want to wake up on touch screen activity.
>>
>> The I2C core automatically reads the "wakeup-source" DT property to
>> configure a device's wakeup capability, and board supports files can set
>> I2C_CLIENT_WAKE in the flags.
>
> This will break wake-up on working systems. Looks like mostly i.MX, but
> there's one AM437x board. If that board doesn't care, then it is up to
> Shawn.
I added the property to the dts files, but as Dmitry pointed out, I
missed some. Sorry for that.
Thanks,
Daniel
^ permalink raw reply
* Re: [PATCH v2 3/3] ARM: dts: imx28/imx53: enable edt-ft5x06 wakeup source
From: Daniel Mack @ 2018-05-23 8:26 UTC (permalink / raw)
To: Dmitry Torokhov, Shawn Guo
Cc: mark.rutland, devicetree, robh+dt, kernel, linux-input,
fabio.estevam, linux-arm-kernel
In-Reply-To: <20180522182043.GA123708@dtor-ws>
On Tuesday, May 22, 2018 08:20 PM, Dmitry Torokhov wrote:
> On Sun, May 20, 2018 at 09:05:30PM +0800, Shawn Guo wrote:
>> On Thu, May 17, 2018 at 11:05:52AM +0200, Daniel Mack wrote:
>>> The touchscreen driver no longer configures the device as wakeup source by
>>> default. A "wakeup-source" property is needed.
>>>
>>> To avoid regressions, this patch changes the DTS files for the only two
>>> users of this driver that didn't have this property yet.
>>>
>>> Signed-off-by: Daniel Mack <daniel@zonque.org>
>>> Cc: Shawn Guo <shawnguo@kernel.org>
>>> Cc: Sascha Hauer <kernel@pengutronix.de>
>>> Cc: Fabio Estevam <fabio.estevam@nxp.com>
>>> Cc: Rob Herring <robh+dt@kernel.org>
>>
>> Applied this one, thanks.
>
> I think there are few more that need "wakeup-source" added:
>
> arch/arm/boot/dts/am437x-sk-evm.dts
> arch/arm/boot/dts/imx6q-var-dt6customboard.dts
> arch/arm/boot/dts/imx6qdl-nit6xlite.dtsi
> arch/arm/boot/dts/imx6qdl-nitrogen6_max.dtsi
> arch/arm/boot/dts/imx6qdl-nitrogen6_som2.dtsi
> arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi
Oh, sorry for having missed them. Will send patches.
Thanks,
Daniel
^ permalink raw reply
* [PATCH] HID: steam: use hid_device.driver_data instead of hid_set_drvdata()
From: Rodrigo Rivas Costa @ 2018-05-22 20:10 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires, Pierre-Loup A. Griffais,
Clément VUCHENER, lkml, linux-input
Cc: Rodrigo Rivas Costa
When creating the low-level hidraw device, the reference to steam_device
was stored using hid_set_drvdata(). But this value is not guaranteed to
be kept when set before calling probe. If this pointer is reset, it
crashes when opening the emulated hidraw device.
It looks like hid_set_drvdata() is for users "avobe" this hid_device,
while hid_device.driver_data it for users "below" this one.
In this case, we are creating a virtual hidraw device, so we must use
hid_device.driver_data.
Signed-off-by: Rodrigo Rivas Costa <rodrigorivascosta@gmail.com>
---
This patch is to be applied over hid/for-4.18/hid-steam. Is this the
proper way to signal it?
I don't know exactly when the problem started. I am pretty sure that it
worked with 4.16.2, but it failed with 4.16.9. Or maybe it is caused by
upgrading the firmware of the controller, although the protocol seems
identical.
drivers/hid/hid-steam.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/hid/hid-steam.c b/drivers/hid/hid-steam.c
index cb86cc834201..0422ec2b13d2 100644
--- a/drivers/hid/hid-steam.c
+++ b/drivers/hid/hid-steam.c
@@ -573,7 +573,7 @@ static bool steam_is_valve_interface(struct hid_device *hdev)
static int steam_client_ll_parse(struct hid_device *hdev)
{
- struct steam_device *steam = hid_get_drvdata(hdev);
+ struct steam_device *steam = hdev->driver_data;
return hid_parse_report(hdev, steam->hdev->dev_rdesc,
steam->hdev->dev_rsize);
@@ -590,7 +590,7 @@ static void steam_client_ll_stop(struct hid_device *hdev)
static int steam_client_ll_open(struct hid_device *hdev)
{
- struct steam_device *steam = hid_get_drvdata(hdev);
+ struct steam_device *steam = hdev->driver_data;
int ret;
ret = hid_hw_open(steam->hdev);
@@ -605,7 +605,7 @@ static int steam_client_ll_open(struct hid_device *hdev)
static void steam_client_ll_close(struct hid_device *hdev)
{
- struct steam_device *steam = hid_get_drvdata(hdev);
+ struct steam_device *steam = hdev->driver_data;
mutex_lock(&steam->mutex);
steam->client_opened = false;
@@ -623,7 +623,7 @@ static int steam_client_ll_raw_request(struct hid_device *hdev,
size_t count, unsigned char report_type,
int reqtype)
{
- struct steam_device *steam = hid_get_drvdata(hdev);
+ struct steam_device *steam = hdev->driver_data;
return hid_hw_raw_request(steam->hdev, reportnum, buf, count,
report_type, reqtype);
@@ -710,7 +710,7 @@ static int steam_probe(struct hid_device *hdev,
ret = PTR_ERR(steam->client_hdev);
goto client_hdev_fail;
}
- hid_set_drvdata(steam->client_hdev, steam);
+ steam->client_hdev->driver_data = steam;
/*
* With the real steam controller interface, do not connect hidraw.
--
2.17.0
^ permalink raw reply related
* Re: [PATCH v2 3/3] ARM: dts: imx28/imx53: enable edt-ft5x06 wakeup source
From: Dmitry Torokhov @ 2018-05-22 18:20 UTC (permalink / raw)
To: Shawn Guo
Cc: mark.rutland, devicetree, robh+dt, linux-arm-kernel, kernel,
linux-input, fabio.estevam, Daniel Mack
In-Reply-To: <20180520130528.GC26863@dragon>
On Sun, May 20, 2018 at 09:05:30PM +0800, Shawn Guo wrote:
> On Thu, May 17, 2018 at 11:05:52AM +0200, Daniel Mack wrote:
> > The touchscreen driver no longer configures the device as wakeup source by
> > default. A "wakeup-source" property is needed.
> >
> > To avoid regressions, this patch changes the DTS files for the only two
> > users of this driver that didn't have this property yet.
> >
> > Signed-off-by: Daniel Mack <daniel@zonque.org>
> > Cc: Shawn Guo <shawnguo@kernel.org>
> > Cc: Sascha Hauer <kernel@pengutronix.de>
> > Cc: Fabio Estevam <fabio.estevam@nxp.com>
> > Cc: Rob Herring <robh+dt@kernel.org>
>
> Applied this one, thanks.
I think there are few more that need "wakeup-source" added:
arch/arm/boot/dts/am437x-sk-evm.dts
arch/arm/boot/dts/imx6q-var-dt6customboard.dts
arch/arm/boot/dts/imx6qdl-nit6xlite.dtsi
arch/arm/boot/dts/imx6qdl-nitrogen6_max.dtsi
arch/arm/boot/dts/imx6qdl-nitrogen6_som2.dtsi
arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi
Thanks.
--
Dmitry
^ permalink raw reply
* Re: [PATCH v7 0/9] Add support for SAMA5D2 touchscreen
From: Jonathan Cameron @ 2018-05-22 17:57 UTC (permalink / raw)
To: Eugen Hristev
Cc: ludovic.desroches, alexandre.belloni, linux-arm-kernel,
devicetree, linux-kernel, linux-iio, linux-input, nicolas.ferre,
dmitry.torokhov, robh
In-Reply-To: <1526975559-18966-1-git-send-email-eugen.hristev@microchip.com>
On Tue, 22 May 2018 10:52:30 +0300
Eugen Hristev <eugen.hristev@microchip.com> wrote:
> Hello,
>
> This patch series is a rework of my previous series named:
> [PATCH 00/14] iio: triggers: add consumer support
>
> This is the version 7 of the series, and addresses the received feedback
> on the v2 series named:
> [PATCH v2 00/10] Add support for SAMA5D2 touchscreen
> and the v3 series named
> [PATCH v3 00/11] Add support for SAMA5D2 touchscreen
> and the v4 series named
> [PATCH v4 0/9] Add support for SAMA5D2 touchscreen
> and fixes one bug found in series named
> [PATCH v5 0/9] Add support for SAMA5D2 touchscreen
> and addresses comments in series named
> [PATCH v6 0/9] Add support for SAMA5D2 touchscreen
>
> This series applies on top of fixes-togreg branch of iio.git,
> specifically on top of commit:
> "f0c8d1f" : iio: adc: at91-sama5d2_adc:
> fix channel configuration for differential channels
>
> Jonathan, if you need me to rebase this on top of testing, let me know.
>
> Changes in previous versions are presented at the end of the cover letter below.
> Thanks everyone for the feedback. Below is the original v2 cover letter:
>
> In few words, this is the implementation of splitting the functionality
> of the IP block ADC device in SAMA5D2 SoC from ADC with touchscreen
> support. In order to avoid having a MFD device, two separate
> drivers that would work on same register base and split the IRQ,etc,
> as advised on the mailing list, I created a consumer driver for the
> channels, that will connect to the ADC as described in the device tree.
>
> I have collected feedback from everyone and here is the result:
> I have added a new generic resistive touchscreen driver, which acts
> as a iio consumer for the given channels and will create an input
> device and report the events. It uses a callback buffer to register
> to the IIO device and waits for data to be pushed.
> Inside the IIO device, I have kept a similar approach with the first version
> of the series, except that now the driver can take multiple buffers, and
> will configure the touchscreen part of the hardware device if the specific
> channels are requested.
>
> The SAMA5D2 ADC driver registers three new channels: two for the
> position on the X and Y axis, and one for the touch pressure.
> When channels are requested, it will check if the touchscreen channel mask
> includes the requested channels (it is possible that the consumer driver
> will not request pressure for example). If it's the case, it will work
> in touchscreen mode, and will refuse to do usual analog-digital conversion,
> because we have a single trigger and the touchscreen needs it.
> When the scan mask will include only old channels, the driver will function
> in the same way as before. If the scan mask somehow is a mix of the two (the
> masks intersect), the driver will refuse to work whatsoever (cannot have both
> in the same time).
> The driver allows reading raw data for the new channels, if claim direct
> mode works: no touchscreen driver requested anything. The new channels can
> act like the old ones. However, when requesting these channels, the usual
> trigger will not work and will not be enabled. The touchscreen channels
> require special trigger and irq configuration: pen detect, no pen detect
> and a periodic trigger to sample the touchscreen position and pressure.
> If the user attempts to use another trigger while there is a buffer
> that already requested the touchscreen channels (thus the trigger), the
> driver will refuse to comply.
>
> In order to have defines for the channel numbers, I added a bindings include
> file that goes on a separate commit :
> dt-bindings: iio: adc: at91-sama5d2_adc: add channel specific consumer info
> This should go in the same tree with the following commits :
> ARM: dts: at91: sama5d2: add channel cells for ADC device
> ARM: dts: at91: sama5d2: Add resistive touch device
>
> as build will break because these commits depend on the binding one
> which creates the included header file.
> V5 update: After discussing with Alexandre Belloni on Mailing list, the two
> DTS patches are to be taken in the next version after bindings reach mainline.
>
> Changes in v7:
> - Addressed some feedback from Dmitry, explained in input driver patch
> changelog.
> - Added Acked-by Dmitry.
>
> Changes in v6:
> - Fixed a crash in ADC driver , explained in driver patch changelog.
> - changed a dev_err to dev_dbg in input driver.
> - added Reviewed-by Rob Herring.
>
> Changes in v5:
> - renamed property touchscreen-threshold-pressure to touchscreen-min-pressure
> - added one return in touchscreen driver
>
> Changes in v4:
> - removed patch for inkern module get/set kref
> - addressed feedback on both the ADC and the touchscreen driver. each
> patch has a history inside the patch file for the specific changes.
> - patch that fixes the channel fix
> [PATCH v3 01/11] iio: adc: at91-sama5d2_adc:
> fix channel configuration for differential channels
> was accepted in fixes-togreg branch thus removed from this series.
> - added Reviewed-by for the bindings by Rob Herring
>
> Changes in v3:
> - changed input driver name according to feedback and reworked in commits
> to adapt to binding changes and new name.
> - moved channel index fix in at91-sama5d2_adc at the beginning of the series
> (PATCH 01/11)
> - created a new optional binding for the touchscreen as a separate commit
> and added it to the series :
> [PATCH v3 04/11] dt-bindings: input: touchscreen: add pressure
> threshold touchscreen property
> - changed at91-sama5d2_adc driver patch to address the comments. Exact changes
> are in the patch file for the driver source file.
>
> Eugen Hristev (9):
> MAINTAINERS: add generic resistive touchscreen adc
> iio: Add channel for Position Relative
> dt-bindings: input: touchscreen: add minimum pressure touchscreen
> property
> dt-bindings: input: touchscreen: resistive-adc-touch: create bindings
> iio: adc: at91-sama5d2_adc: add support for position and pressure
> channels
> input: touchscreen: resistive-adc-touch: add generic resistive ADC
> touchscreen
> dt-bindings: iio: adc: at91-sama5d2_adc: add channel specific consumer
> info
> ARM: dts: at91: sama5d2: add channel cells for ADC device
> ARM: dts: at91: sama5d2: Add resistive touch device
>
> Documentation/ABI/testing/sysfs-bus-iio | 12 +
> .../bindings/iio/adc/at91-sama5d2_adc.txt | 9 +
> .../input/touchscreen/resistive-adc-touch.txt | 30 +
> .../bindings/input/touchscreen/touchscreen.txt | 3 +
> MAINTAINERS | 6 +
> arch/arm/boot/dts/sama5d2.dtsi | 12 +
> drivers/iio/adc/at91-sama5d2_adc.c | 609 +++++++++++++++++++--
> drivers/iio/industrialio-core.c | 1 +
> drivers/input/touchscreen/Kconfig | 13 +
> drivers/input/touchscreen/Makefile | 1 +
> drivers/input/touchscreen/resistive-adc-touch.c | 204 +++++++
> include/dt-bindings/iio/adc/at91-sama5d2_adc.h | 16 +
> include/uapi/linux/iio/types.h | 1 +
> tools/iio/iio_event_monitor.c | 2 +
> 14 files changed, 861 insertions(+), 58 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/input/touchscreen/resistive-adc-touch.txt
> create mode 100644 drivers/input/touchscreen/resistive-adc-touch.c
> create mode 100644 include/dt-bindings/iio/adc/at91-sama5d2_adc.h
>
Hi All,
I'm happy to take this, but there is a slight issue that we have a fix working
it's way in which this is dependent on.
I'll see if we can get this sorted before the merge window, but we may be
cutting it fine.
Jonathan
^ permalink raw reply
* Re: [PATCH v2 1/3] input: touchscreen: edt-ft5x06: don't make device a wakeup source by default
From: Rob Herring @ 2018-05-22 17:54 UTC (permalink / raw)
To: Daniel Mack
Cc: mark.rutland, devicetree, dmitry.torokhov, kernel, linux-input,
fabio.estevam, shawnguo, linux-arm-kernel
In-Reply-To: <20180517090552.5704-2-daniel@zonque.org>
On Thu, May 17, 2018 at 11:05:50AM +0200, Daniel Mack wrote:
> Allow configuring the device as wakeup source through device properties, as
> not all platforms want to wake up on touch screen activity.
>
> The I2C core automatically reads the "wakeup-source" DT property to
> configure a device's wakeup capability, and board supports files can set
> I2C_CLIENT_WAKE in the flags.
This will break wake-up on working systems. Looks like mostly i.MX, but
there's one AM437x board. If that board doesn't care, then it is up to
Shawn.
Rob
^ permalink raw reply
* Re: [PATCH v2 11/11] docs: fix broken references with multiple hints
From: Rob Herring @ 2018-05-22 17:31 UTC (permalink / raw)
To: Mauro Carvalho Chehab
Cc: Mark Rutland, linux-fbdev, linux-usb, Linux Doc Mailing List,
David Airlie, dri-devel, Benjamin Tissoires, devel,
Jonathan Corbet, James Morris, Ingo Molnar, linux-input,
Roy Pledge, Serge E. Hallyn, devicetree,
Bartlomiej Zolnierkiewicz, Jiri Kosina, Steven Rostedt,
Mauro Carvalho Chehab, linux-gpio, Greg Kroah-Hartman,
Dmitry Torokhov, linux-kernel, linux-security-module
In-Reply-To: <63a4f8a93f9115475bc184d0f37d076c9b9c75ff.1525870886.git.mchehab+samsung@kernel.org>
On Wed, May 09, 2018 at 10:18:54AM -0300, Mauro Carvalho Chehab wrote:
> The script:
> ./scripts/documentation-file-ref-check --fix-rst
>
> Gives multiple hints for broken references on some files.
> Manually use the one that applies for some files.
>
> Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
> ---
> Documentation/ABI/obsolete/sysfs-gpio | 2 +-
> .../devicetree/bindings/display/bridge/tda998x.txt | 2 +-
Acked-by: Rob Herring <robh@kernel.org>
> Documentation/trace/events.rst | 2 +-
> Documentation/trace/tracepoint-analysis.rst | 2 +-
> Documentation/translations/zh_CN/SubmittingDrivers | 2 +-
> Documentation/translations/zh_CN/gpio.txt | 4 ++--
> MAINTAINERS | 2 +-
> drivers/hid/usbhid/Kconfig | 2 +-
> drivers/input/Kconfig | 4 ++--
> drivers/input/joystick/Kconfig | 4 ++--
> drivers/input/joystick/iforce/Kconfig | 2 +-
> drivers/input/serio/Kconfig | 4 ++--
> drivers/staging/fsl-mc/bus/dpio/dpio-driver.txt | 2 +-
> drivers/video/fbdev/skeletonfb.c | 8 ++++----
> include/linux/tracepoint.h | 2 +-
> security/device_cgroup.c | 2 +-
> 16 files changed, 23 insertions(+), 23 deletions(-)
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply
* RE: Sometimes unusable i2c-hid devices in 4.17-rcX
From: Mario.Limonciello @ 2018-05-22 16:15 UTC (permalink / raw)
To: benjamin.tissoires; +Cc: linux-input, linux-kernel
In-Reply-To: <CAN+gG=HPLAVb5kR6a8+vho5NBhkoY6oKU8P=pUt0qiPOZRvBbw@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 12090 bytes --]
Benjamin,
> -----Original Message-----
> From: Benjamin Tissoires [mailto:benjamin.tissoires@gmail.com]
> Sent: Friday, May 18, 2018 1:18 PM
> To: Limonciello, Mario
> Cc: linux-input; linux-kernel@vger.kernel.org
> Subject: Re: Sometimes unusable i2c-hid devices in 4.17-rcX
>
> On Thu, May 17, 2018 at 4:44 PM, <Mario.Limonciello@dell.com> wrote:
> >> -----Original Message-----
> >> From: Benjamin Tissoires [mailto:benjamin.tissoires@gmail.com]
> >> Sent: Thursday, May 17, 2018 9:28 AM
> >> To: Limonciello, Mario
> >> Cc: linux-input; linux-kernel@vger.kernel.org
> >> Subject: Re: Sometimes unusable i2c-hid devices in 4.17-rcX
> >>
> >> Hi Mario,
> >>
> >> On Wed, May 16, 2018 at 10:00 PM, <Mario.Limonciello@dell.com> wrote:
> >> > Hi All,
> >> >
> >> > I've been running 4.16-rc7 on an XPS 9365 for some time and recently moved
> up
> >> to 4.17-rc5.
> >> > Immediately I noticed that i2c-hid devices (both touchscreen and touchpad)
> were
> >> not working.
> >> > Also when shutting the system down or rebooting it would just hang. (magic
> sysrq
> >> still worked).
> >> >
> >> > I figured it was an easy to identify regression so I started a bisect but it came
> up
> >> with garbage
> >> > that ended in selftests shortly after 4.17-rc2. I realized that's because is still
> will
> >> fail on 4.17-rc2
> >> > occasionally, seemingly after trying something newer and warm rebooting.
> >> > So it seems like it's "worse" after 4.17-rc2 (doesn't work at all) but semi
> >> reproducible on 4.17-rc2.
> >> >
> >> > Not sure if I'm chasing some initialization race, but wanted to see if anyone
> else
> >> was running into this
> >> > or has some ideas?
> >>
> >> I am reliably running a v4.17-rc3 with a merge on Jiri's tree on the 9360.
> >>
> >> I doubt it's related to the event processing as I am not encountering
> >> those issues.
> >>
> >> It *could* be related to the interrupts not being properly raised.
> >>
> >> Could you monitor /proc/interrupts and check if the ones associated
> >> with your i2c-hid devices are increasing when you are using them?
> >> Also, does the device emits raw HID events? (you can use hid-recorder
> >> to check on the hidraw nodes.)
> >
>
> Sorry, I couldn't get to it today. Monday is a public holiday here, so
> I'll check on this Tuesday.
>
> > I checked both, /proc/interrupts isn't incrementing at all with the DLL077A:01
> device.
> > Hid-recorder is showing output from the raw HID node.
>
> I don't really understand how the hidraw node can send data while the
> interrupts are not raised.
>
> Could you share the output of hid-recorder?
Sure attached.
Note that I had a dock connected at the same time since I needed power. This was
different than my previous tests.
That dock has 2 HID endpoints (so that might muddy this, I can re-capture if you need me to)
>
> >
> > Same thing for the touchscreen, no incrementing for it on the i2c_designware.0
> device.
> >
> > Something notable however;
> > When in this bad state hid-recorder didn't show /dev/hidraw1 for the
> touchscreen (which
> > Happens to be a Wacom touch screen).
> > It only showed /dev/hidraw0 for the touchpad.
>
> This explains why the touchscreen doesn't increment the interrupts.
> Something I missed in the first email is that the hidraw0 node
> disappear for the wacom device as the touchpad gets the hidraw0 name.
>
> Could you provide the output of a working kernel configuration of:
> sudo hid-recorder /dev/hidraw*
>
> This should provide me the whole logs at the same time of all the
> hidraw nodes, and will allow me to reproduce the combination of
> wacom/hid-multitouch you are experiencing.
>
I was having a hard time getting it to work again with 4.17-rcX while trying
to capture this.
The only thing I got it to work with was when I turned off the touchscreen
In FW setup.
So I guess that means it's probably something Wacom race condition on
initialization since you noted the hidraw endpoint getting clobbered.
>
> >
> >
> >>
> >> Cheers,
> >> Benjamin
> >>
> >> >
> >> > #dmesg | grep 'i2c\|hid' doesn't show any obvious errors when in this state of
> >> non functional hid stuff.
> >> > [ 2.398649] i2c /dev entries driver
> >> > [ 2.881651] hidraw: raw HID events driver (C) Jiri Kosina
> >> > [ 3.683583] ish-hid {33AECD58-B679-4E54-9BD9-A04D34F0C226}: [hid-ish]:
> >> enum_devices_done OK, num_hid_devices=5
> >> > [ 3.701259] hid-generic 001F:8086:22D8.0001: hidraw0: <UNKNOWN> HID
> >> v2.00 Device [hid-ishtp 8086:22D8] on
> >> > [ 3.702204] hid-generic 001F:8086:22D8.0002: hidraw1: <UNKNOWN> HID
> >> v2.00 Device [hid-ishtp 8086:22D8] on
> >> > [ 3.703063] hid-generic 001F:8086:22D8.0003: hidraw2: <UNKNOWN> HID
> >> v2.00 Device [hid-ishtp 8086:22D8] on
> >> > [ 3.704276] hid-generic 001F:8086:22D8.0004: hidraw3: <UNKNOWN> HID
> >> v2.00 Device [hid-ishtp 8086:22D8] on
> >> > [ 3.704557] hid-generic 001F:8086:22D8.0005: hidraw4: <UNKNOWN> HID
> >> v2.00 Device [hid-ishtp 8086:22D8] on
> >> > [ 3.750710] psmouse serio1: synaptics: Your touchpad (PNP: DLL077a
> PNP0f13)
> >> says it can support a different bus. If i2c-hid and hid-rmi are not used, you might
> >> want to try setting psmouse.synaptics_intertouch to 1 and report this to linux-
> >> input@vger.kernel.org.
> >> > [ 7.030446] acpi INT33D5:00: intel-hid: created platform device
> >> > [ 7.199178] i2c_hid i2c-WCOM482F:00: i2c-WCOM482F:00 supply vdd not
> >> found, using dummy regulator
> >> > [ 7.246638] input: WCOM482F:00 056A:482F as
> >> /devices/pci0000:00/0000:00:15.0/i2c_designware.0/i2c-6/i2c-
> >> WCOM482F:00/0018:056A:482F.0006/input/input11
> >> > [ 7.246873] hid-generic 0018:056A:482F.0006: input,hidraw0: I2C HID v1.00
> >> Mouse [WCOM482F:00 056A:482F] on i2c-WCOM482F:00
> >> > [ 7.275279] i2c_hid i2c-DLL077A:01: i2c-DLL077A:01 supply vdd not found,
> >> using dummy regulator
> >> > [ 7.304107] input: DLL077A:01 06CB:76AF as
> >> /devices/pci0000:00/0000:00:15.1/i2c_designware.1/i2c-7/i2c-
> >> DLL077A:01/0018:06CB:76AF.0007/input/input14
> >> > [ 7.304212] hid-generic 0018:06CB:76AF.0007: input,hidraw1: I2C HID v1.00
> >> Mouse [DLL077A:01 06CB:76AF] on i2c-DLL077A:01
> >> > [ 7.657123] usbcore: registered new interface driver usbhid
> >> > [ 7.657124] usbhid: USB HID core driver
> >> > [ 7.722876] input: Wacom HID 482F Pen as
> >> /devices/pci0000:00/0000:00:15.0/i2c_designware.0/i2c-6/i2c-
> >> WCOM482F:00/0018:056A:482F.0006/input/input15
> >> > [ 7.723148] input: Wacom HID 482F Finger as
> >> /devices/pci0000:00/0000:00:15.0/i2c_designware.0/i2c-6/i2c-
> >> WCOM482F:00/0018:056A:482F.0006/input/input16
> >> > [ 7.723611] wacom 0018:056A:482F.0006: hidraw0: I2C HID v1.00 Mouse
> >> [WCOM482F:00 056A:482F] on i2c-WCOM482F:00
> >> > [ 7.768275] input: DLL077A:01 06CB:76AF Touchpad as
> >> /devices/pci0000:00/0000:00:15.1/i2c_designware.1/i2c-7/i2c-
> >> DLL077A:01/0018:06CB:76AF.0007/input/input19
> >> > [ 7.864201] hid-multitouch 0018:06CB:76AF.0007: input,hidraw0: I2C HID
> v1.00
> >> Mouse [DLL077A:01 06CB:76AF] on i2c-DLL077A:01
> >> >
> >> > However in this state, I can't rmmod i2c-hid. It just hangs the system with this
> >> trace:
> >> > [ 243.033779] INFO: task kworker/u8:0:6 blocked for more than 120 seconds.
> >> > [ 243.033793] Not tainted 4.17.0-rc1+ #37
> >> > [ 243.033798] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables
> this
> >> message.
> >> > [ 243.033804] kworker/u8:0 D 0 6 2 0x80000000
> >> > [ 243.033826] Workqueue: events_power_efficient
> >> power_supply_deferred_register_work
> >> > [ 243.033832] Call Trace:
> >> > [ 243.033850] __schedule+0x3c2/0x890
> >> > [ 243.033861] ? __switch_to_asm+0x40/0x70
> >> > [ 243.033868] schedule+0x36/0x80
> >> > [ 243.033875] schedule_preempt_disabled+0xe/0x10
> >> > [ 243.033882] __mutex_lock.isra.4+0x2ae/0x4e0
> >> > [ 243.033890] ? __switch_to_asm+0x34/0x70
> >> > [ 243.033899] ? __switch_to_asm+0x40/0x70
> >> > [ 243.033906] ? __switch_to_asm+0x40/0x70
> >> > [ 243.033914] __mutex_lock_slowpath+0x13/0x20
> >> > [ 243.033920] ? __mutex_lock_slowpath+0x13/0x20
> >> > [ 243.033927] mutex_lock+0x2f/0x40
> >> > [ 243.033933] power_supply_deferred_register_work+0x2b/0x50
> >> > [ 243.033944] process_one_work+0x148/0x3d0
> >> > [ 243.033952] worker_thread+0x4b/0x460
> >> > [ 243.033960] kthread+0x102/0x140
> >> > [ 243.033967] ? rescuer_thread+0x380/0x380
> >> > [ 243.033973] ? kthread_associate_blkcg+0xa0/0xa0
> >> > [ 243.033982] ret_from_fork+0x35/0x40
> >> > [ 243.034012] INFO: task systemd-udevd:308 blocked for more than 120
> seconds.
> >> > [ 243.034018] Not tainted 4.17.0-rc1+ #37
> >> > [ 243.034022] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables
> this
> >> message.
> >> > [ 243.034027] systemd-udevd D 0 308 279 0x80000104
> >> > [ 243.034033] Call Trace:
> >> > [ 243.034041] __schedule+0x3c2/0x890
> >> > [ 243.034049] schedule+0x36/0x80
> >> > [ 243.034056] schedule_timeout+0x1e7/0x360
> >> > [ 243.034066] ? ttwu_do_activate+0x77/0x80
> >> > [ 243.034074] wait_for_completion+0xb4/0x140
> >> > [ 243.034082] ? wake_up_q+0x70/0x70
> >> > [ 243.034090] flush_work+0x12a/0x1e0
> >> > [ 243.034097] ? worker_detach_from_pool+0xb0/0xb0
> >> > [ 243.034107] __cancel_work_timer+0x112/0x190
> >> > [ 243.034116] cancel_delayed_work_sync+0x13/0x20
> >> > [ 243.034122] power_supply_unregister+0x37/0xb0
> >> > [ 243.034127] devm_power_supply_release+0x11/0x20
> >> > [ 243.034135] release_nodes+0x107/0x1f0
> >> > [ 243.034147] devres_release_group+0x7c/0xb0
> >> > [ 243.034162] wacom_remove+0xce/0x120 [wacom]
> >> > [ 243.034178] hid_device_remove+0x4d/0xa0 [hid]
> >> > [ 243.034187] device_release_driver_internal+0x155/0x220
> >> > [ 243.034198] ? __hid_bus_driver_added+0x40/0x40 [hid]
> >> > [ 243.034208] ? hid_destroy_device+0x60/0x60 [hid]
> >> > [ 243.034215] device_release_driver+0x12/0x20
> >> > [ 243.034221] device_reprobe+0x30/0x50
> >> > [ 243.034231] __hid_bus_reprobe_drivers+0x45/0x50 [hid]
> >> > [ 243.034239] bus_for_each_dev+0x64/0xb0
> >> > [ 243.034250] __hid_bus_driver_added+0x2c/0x40 [hid]
> >> > [ 243.034256] bus_for_each_drv+0x67/0xb0
> >> > [ 243.034267] __hid_register_driver+0x6f/0x80 [hid]
> >> > [ 243.034275] ? 0xffffffffc07f5000
> >> > [ 243.034287] mt_driver_init+0x23/0x1000 [hid_multitouch]
> >> > [ 243.034296] do_one_initcall+0x4f/0x1ce
> >> > [ 243.034303] ? _cond_resched+0x1a/0x50
> >> > [ 243.034315] ? kmem_cache_alloc_trace+0xb8/0x1f0
> >> > [ 243.034327] do_init_module+0x5f/0x219
> >> > [ 243.034335] load_module+0x24c7/0x2be0
> >> > [ 243.034348] __do_sys_finit_module+0xe5/0x120
> >> > [ 243.034354] ? __do_sys_finit_module+0xe5/0x120
> >> > [ 243.034363] __x64_sys_finit_module+0x1a/0x20
> >> > [ 243.034370] do_syscall_64+0x54/0x110
> >> > [ 243.034380] entry_SYSCALL_64_after_hwframe+0x44/0xa9
> >> > [ 243.034386] RIP: 0033:0x7f2ec539c839
> >> > [ 243.034390] RSP: 002b:00007ffcfc620298 EFLAGS: 00000246 ORIG_RAX:
> >> 0000000000000139
> >> > [ 243.034396] RAX: ffffffffffffffda RBX: 000055d6a0147ec0 RCX:
> >> 00007f2ec539c839
> >> > [ 243.034399] RDX: 0000000000000000 RSI: 00007f2ec507b0e5 RDI:
> >> 000000000000000f
> >> > [ 243.034402] RBP: 00007f2ec507b0e5 R08: 0000000000000000 R09:
> >> 00007ffcfc6203b0
> >> > [ 243.034405] R10: 000000000000000f R11: 0000000000000246 R12:
> >> 0000000000000000
> >> > [ 243.034408] R13: 000055d6a017b3a0 R14: 0000000000020000 R15:
> >> 000055d6a0147ec0
> >> > --
> >> > To unsubscribe from this list: send the line "unsubscribe linux-input" in
> >> > the body of a message to majordomo@vger.kernel.org
> >> > More majordomo info at http://vger.kernel.org/majordomo-info.html
[-- Attachment #2: hid_recorder_just_dev2.txt --]
[-- Type: text/plain, Size: 8086 bytes --]
Available devices:
/dev/hidraw0: Generic
/dev/hidraw1: Generic
/dev/hidraw2: DLL077A:01 06CB:76AF
Select the device event number [0-2]: D: 0
R: 665 05 01 09 02 a1 01 85 02 09 01 a1 00 05 09 19 01 29 02 15 00 25 01 75 01 95 02 81 02 95 06 81 01 05 01 09 30 09 31 15 81 25 7f 75 08 95 02 81 06 c0 c0 05 0d 09 05 a1 01 85 03 05 0d 09 22 a1 02 15 00 25 01 09 47 09 42 95 02 75 01 81 02 95 01 75 03 25 05 09 51 81 02 75 01 95 03 81 03 05 01 15 00 26 c0 04 75 10 55 0e 65 11 09 30 35 00 46 f5 03 95 01 81 02 46 36 02 26 a8 02 09 31 81 02 c0 05 0d 09 22 a1 02 15 00 25 01 09 47 09 42 95 02 75 01 81 02 95 01 75 03 25 05 09 51 81 02 75 01 95 03 81 03 05 01 15 00 26 c0 04 75 10 55 0e 65 11 09 30 35 00 46 f5 03 95 01 81 02 46 36 02 26 a8 02 09 31 81 02 c0 05 0d 09 22 a1 02 15 00 25 01 09 47 09 42 95 02 75 01 81 02 95 01 75 03 25 05 09 51 81 02 75 01 95 03 81 03 05 01 15 00 26 c0 04 75 10 55 0e 65 11 09 30 35 00 46 f5 03 95 01 81 02 46 36 02 26 a8 02 09 31 81 02 c0 05 0d 09 22 a1 02 15 00 25 01 09 47 09 42 95 02 75 01 81 02 95 01 75 03 25 05 09 51 81 02 75 01 95 03 81 03 05 01 15 00 26 c0 04 75 10 55 0e 65 11 09 30 35 00 46 f5 03 95 01 81 02 46 36 02 26 a8 02 09 31 81 02 c0 05 0d 09 22 a1 02 15 00 25 01 09 47 09 42 95 02 75 01 81 02 95 01 75 03 25 05 09 51 81 02 75 01 95 03 81 03 05 01 15 00 26 c0 04 75 10 55 0e 65 11 09 30 35 00 46 f5 03 95 01 81 02 46 36 02 26 a8 02 09 31 81 02 c0 05 0d 55 0c 66 01 10 47 ff ff 00 00 27 ff ff 00 00 75 10 95 01 09 56 81 02 09 54 25 7f 95 01 75 08 81 02 05 09 09 01 25 01 75 01 95 01 81 02 95 07 81 03 05 0d 85 08 09 55 09 59 75 04 95 02 25 0f b1 02 85 0d 09 60 75 01 95 01 15 00 25 01 b1 02 95 07 b1 03 85 07 06 00 ff 09 c5 15 00 26 ff 00 75 08 96 00 01 b1 02 c0 05 0d 09 0e a1 01 85 04 09 22 a1 02 09 52 15 00 25 0a 75 08 95 01 b1 02 c0 09 22 a1 00 85 06 09 57 09 58 75 01 95 02 25 01 b1 02 95 06 b1 03 c0 c0 06 00 ff 09 01 a1 01 85 09 09 02 15 00 26 ff 00 75 08 95 14 91 02 85 0a 09 03 15 00 26 ff 00 75 08 95 14 91 02 85 0b 09 04 15 00 26 ff 00 75 08 95 3d 81 02 85 0c 09 05 15 00 26 ff 00 75 08 95 3d 81 02 85 0f 09 06 15 00 26 ff 00 75 08 95 03 b1 02 85 0e 09 07 15 00 26 ff 00 75 08 95 01 b1 02 c0
N: DLL077A:01 06CB:76AF
P: i2c-DLL077A:01
I: 18 06cb 76af
D: 0
E: 0.000000 30 03 03 c1 02 07 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 34 81 01 00
E: 0.007245 30 03 03 b2 02 14 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 7b 81 01 00
E: 0.014047 30 03 03 af 02 16 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 c2 81 01 00
E: 0.021276 30 03 03 a6 02 1b 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 09 82 01 00
E: 0.028403 30 03 03 9b 02 21 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 50 82 01 00
E: 0.035547 30 03 03 8c 02 27 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 97 82 01 00
E: 0.043140 30 03 03 7d 02 2c 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 de 82 01 00
E: 0.050006 30 03 03 70 02 2f 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 25 83 01 00
E: 0.057126 30 03 03 61 02 31 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 6c 83 01 00
E: 0.064354 30 03 03 54 02 31 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 b3 83 01 00
E: 0.071493 30 03 03 49 02 31 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fa 83 01 00
E: 0.078943 30 03 03 40 02 2f 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 41 84 01 00
E: 0.085995 30 03 03 38 02 2d 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 89 84 01 00
E: 0.093130 30 03 03 32 02 2b 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 d0 84 01 00
E: 0.100267 30 03 03 2e 02 29 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 17 85 01 00
E: 0.107363 30 03 03 2b 02 26 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 5e 85 01 00
E: 0.114793 30 03 03 29 02 20 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 a5 85 01 00
E: 0.121788 30 03 03 29 02 19 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ec 85 01 00
E: 0.128977 30 03 03 2b 02 12 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 33 86 01 00
E: 0.136232 30 03 03 2f 02 0b 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 7b 86 01 00
E: 0.143539 30 03 03 36 02 03 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 c2 86 01 00
E: 0.150646 30 03 03 3f 02 fb 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 09 87 01 00
E: 0.157762 30 03 03 4a 02 f3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 50 87 01 00
E: 0.164955 30 03 03 56 02 ec 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 97 87 01 00
E: 0.172098 30 03 03 64 02 e5 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 de 87 01 00
E: 0.179430 30 03 03 71 02 e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 25 88 01 00
E: 0.186516 30 03 03 7d 02 dc 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 6c 88 01 00
E: 0.193669 30 03 03 89 02 da 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 b3 88 01 00
E: 0.200834 30 03 03 95 02 d9 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fa 88 01 00
E: 0.208175 30 03 03 9f 02 d8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 41 89 01 00
E: 0.215204 30 03 03 a8 02 d8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 88 89 01 00
E: 0.222404 30 03 03 b1 02 d9 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 cf 89 01 00
E: 0.229827 30 03 03 b9 02 db 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 16 8a 01 00
E: 0.236947 30 03 03 bf 02 dd 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 5d 8a 01 00
E: 0.243932 30 03 03 c3 02 df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 a4 8a 01 00
E: 0.251084 30 03 03 c6 02 e1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 eb 8a 01 00
E: 0.258293 30 03 03 c7 02 e4 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 32 8b 01 00
E: 0.265510 30 03 03 c8 02 e7 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 79 8b 01 00
E: 0.272782 30 03 03 c8 02 eb 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 c0 8b 01 00
E: 0.279934 30 03 03 c7 02 f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 07 8c 01 00
E: 0.287072 30 03 03 c5 02 f5 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 4f 8c 01 00
E: 0.294455 30 03 03 c2 02 fa 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 96 8c 01 00
E: 0.301733 30 03 03 be 02 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 dd 8c 01 00
E: 0.308573 30 03 03 b9 02 05 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 25 8d 01 00
E: 0.315809 30 03 03 b2 02 0b 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 6c 8d 01 00
E: 0.322945 30 03 03 aa 02 10 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 b3 8d 01 00
E: 0.330299 30 03 03 a3 02 14 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fb 8d 01 00
E: 0.337434 30 03 03 9d 02 17 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 42 8e 01 00
E: 0.344549 30 03 03 98 02 1a 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 89 8e 01 00
E: 0.351778 30 03 03 95 02 1c 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 d0 8e 01 00
E: 0.358848 30 03 03 93 02 1d 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 17 8f 01 00
E: 0.366030 30 03 03 91 02 1e 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 5e 8f 01 00
E: 0.373273 30 03 03 90 02 1f 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 a5 8f 01 00
E: 0.380395 30 03 03 90 02 1f 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ec 8f 01 00
E: 0.387507 30 03 03 90 02 1f 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 33 90 01 00
E: 0.394062 30 03 01 90 02 1f 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 7a 90 01 00
^ permalink raw reply
* Re: [PATCH v7 7/9] dt-bindings: iio: adc: at91-sama5d2_adc: add channel specific consumer info
From: Ludovic Desroches @ 2018-05-22 12:23 UTC (permalink / raw)
To: Eugen Hristev
Cc: jic23, ludovic.desroches, alexandre.belloni, linux-arm-kernel,
devicetree, linux-kernel, linux-iio, linux-input, nicolas.ferre,
dmitry.torokhov, robh
In-Reply-To: <1526975559-18966-8-git-send-email-eugen.hristev@microchip.com>
On Tue, May 22, 2018 at 10:52:37AM +0300, Eugen Hristev wrote:
> Added defines for channel consumer device-tree binding
>
> Signed-off-by: Eugen Hristev <eugen.hristev@microchip.com>
> Reviewed-by: Rob Herring <robh@kernel.org>
Acked-by: Ludovic Desroches <ludovic.desroches@microchip.com>
> ---
> .../devicetree/bindings/iio/adc/at91-sama5d2_adc.txt | 9 +++++++++
> include/dt-bindings/iio/adc/at91-sama5d2_adc.h | 16 ++++++++++++++++
> 2 files changed, 25 insertions(+)
> create mode 100644 include/dt-bindings/iio/adc/at91-sama5d2_adc.h
>
> diff --git a/Documentation/devicetree/bindings/iio/adc/at91-sama5d2_adc.txt b/Documentation/devicetree/bindings/iio/adc/at91-sama5d2_adc.txt
> index 6469a4c..4a3c1d4 100644
> --- a/Documentation/devicetree/bindings/iio/adc/at91-sama5d2_adc.txt
> +++ b/Documentation/devicetree/bindings/iio/adc/at91-sama5d2_adc.txt
> @@ -21,6 +21,14 @@ Optional properties:
> - dmas: Phandle to dma channel for the ADC.
> - dma-names: Must be "rx" when dmas property is being used.
> See ../../dma/dma.txt for details.
> + - #io-channel-cells: in case consumer drivers are attached, this must be 1.
> + See <Documentation/devicetree/bindings/iio/iio-bindings.txt> for details.
> +
> +Properties for consumer drivers:
> + - Consumer drivers can be connected to this producer device, as specified
> + in <Documentation/devicetree/bindings/iio/iio-bindings.txt>
> + - Channels exposed are specified in:
> + <dt-bindings/iio/adc/at91-sama5d2_adc.txt>
>
> Example:
>
> @@ -38,4 +46,5 @@ adc: adc@fc030000 {
> atmel,trigger-edge-type = <IRQ_TYPE_EDGE_BOTH>;
> dmas = <&dma0 (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | AT91_XDMAC_DT_PERID(25))>;
> dma-names = "rx";
> + #io-channel-cells = <1>;
> }
> diff --git a/include/dt-bindings/iio/adc/at91-sama5d2_adc.h b/include/dt-bindings/iio/adc/at91-sama5d2_adc.h
> new file mode 100644
> index 0000000..70f99db
> --- /dev/null
> +++ b/include/dt-bindings/iio/adc/at91-sama5d2_adc.h
> @@ -0,0 +1,16 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * This header provides constants for configuring the AT91 SAMA5D2 ADC
> + */
> +
> +#ifndef _DT_BINDINGS_IIO_ADC_AT91_SAMA5D2_ADC_H
> +#define _DT_BINDINGS_IIO_ADC_AT91_SAMA5D2_ADC_H
> +
> +/* X relative position channel index */
> +#define AT91_SAMA5D2_ADC_X_CHANNEL 24
> +/* Y relative position channel index */
> +#define AT91_SAMA5D2_ADC_Y_CHANNEL 25
> +/* pressure channel index */
> +#define AT91_SAMA5D2_ADC_P_CHANNEL 26
> +
> +#endif
> --
> 2.7.4
>
^ permalink raw reply
* Re: [PATCH v7 5/9] iio: adc: at91-sama5d2_adc: add support for position and pressure channels
From: Ludovic Desroches @ 2018-05-22 12:22 UTC (permalink / raw)
To: Eugen Hristev
Cc: jic23, ludovic.desroches, alexandre.belloni, linux-arm-kernel,
devicetree, linux-kernel, linux-iio, linux-input, nicolas.ferre,
dmitry.torokhov, robh
In-Reply-To: <1526975559-18966-6-git-send-email-eugen.hristev@microchip.com>
On Tue, May 22, 2018 at 10:52:35AM +0300, Eugen Hristev wrote:
> This implements the support for position and pressure for the included
> touchscreen support in the SAMA5D2 SOC ADC block.
> Two position channels are added and one for pressure.
> They can be read in raw format, or through a buffer.
> A normal use case is for a consumer driver to register a callback buffer
> for these channels.
> When the touchscreen channels are in the active scan mask,
> the driver will start the touchscreen sampling and push the data to the
> buffer.
>
> Some parts of this patch are based on initial original work by
> Mohamed Jamsheeth Hajanajubudeen and Bandaru Venkateswara Swamy
>
> Signed-off-by: Eugen Hristev <eugen.hristev@microchip.com>
Acked-by: Ludovic Desroches <ludovic.desroches@microchip.com>
> ---
> Changes in v6:
> - fixed a crash when issuing buffer enable from sysfs, if no trigger was
> previously configured. This is because now the driver can work in software
> buffer mode (to connect the callback buffer). So, when trying to enable the
> buffer, check if we are going indeed to a triggered mode or not. If not, do
> not allow buffer to be started (we do not have the right trigger).
> It's in buffer_postenable and predisable.
>
> Changes in v4:
> - use return value of at91_adc_configure_touch
> - rewrote some part of the read_info_raw according to Jonathan's
> suggestion
>
> Changes in v3:
> - prefix macros with AT91_SAMA5D2
> - reworked the x_pos and y_pos functions into a single one with two
> additional wrappers
> - reworked pressure report to have it grow naturally and not top down
> - fixed some checks regarding IIO_VOLTAGE as suggested
> - added a comment explaining some code in trigger handling
> - reworked the frequency get handler to use the saved value instead of
> reading it from the hardware.
> - added comment on deffered work queueing
> - pulled out INFO_RAW function into a separate utility function as suggested
> - added iio_dev ops structure at all times . The functions are needed in
> case we do not have a hardware trigger attached, but we want to use the
> consumer touchscreen driver, thus a callback buffer is attached. Then we still
> need to have buffer preenable and postdisable to configure the touch IRQs (etc.)
>
> Changes in v2:
> - the support is now based on callback buffer.
>
> drivers/iio/adc/at91-sama5d2_adc.c | 609 +++++++++++++++++++++++++++++++++----
> 1 file changed, 551 insertions(+), 58 deletions(-)
>
> diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c
> index 8729d65..58c4c2b 100644
> --- a/drivers/iio/adc/at91-sama5d2_adc.c
> +++ b/drivers/iio/adc/at91-sama5d2_adc.c
> @@ -102,14 +102,26 @@
> #define AT91_SAMA5D2_LCDR 0x20
> /* Interrupt Enable Register */
> #define AT91_SAMA5D2_IER 0x24
> +/* Interrupt Enable Register - TS X measurement ready */
> +#define AT91_SAMA5D2_IER_XRDY BIT(20)
> +/* Interrupt Enable Register - TS Y measurement ready */
> +#define AT91_SAMA5D2_IER_YRDY BIT(21)
> +/* Interrupt Enable Register - TS pressure measurement ready */
> +#define AT91_SAMA5D2_IER_PRDY BIT(22)
> /* Interrupt Enable Register - general overrun error */
> #define AT91_SAMA5D2_IER_GOVRE BIT(25)
> +/* Interrupt Enable Register - Pen detect */
> +#define AT91_SAMA5D2_IER_PEN BIT(29)
> +/* Interrupt Enable Register - No pen detect */
> +#define AT91_SAMA5D2_IER_NOPEN BIT(30)
> /* Interrupt Disable Register */
> #define AT91_SAMA5D2_IDR 0x28
> /* Interrupt Mask Register */
> #define AT91_SAMA5D2_IMR 0x2c
> /* Interrupt Status Register */
> #define AT91_SAMA5D2_ISR 0x30
> +/* Interrupt Status Register - Pen touching sense status */
> +#define AT91_SAMA5D2_ISR_PENS BIT(31)
> /* Last Channel Trigger Mode Register */
> #define AT91_SAMA5D2_LCTMR 0x34
> /* Last Channel Compare Window Register */
> @@ -131,8 +143,38 @@
> #define AT91_SAMA5D2_CDR0 0x50
> /* Analog Control Register */
> #define AT91_SAMA5D2_ACR 0x94
> +/* Analog Control Register - Pen detect sensitivity mask */
> +#define AT91_SAMA5D2_ACR_PENDETSENS_MASK GENMASK(1, 0)
> +
> /* Touchscreen Mode Register */
> #define AT91_SAMA5D2_TSMR 0xb0
> +/* Touchscreen Mode Register - No touch mode */
> +#define AT91_SAMA5D2_TSMR_TSMODE_NONE 0
> +/* Touchscreen Mode Register - 4 wire screen, no pressure measurement */
> +#define AT91_SAMA5D2_TSMR_TSMODE_4WIRE_NO_PRESS 1
> +/* Touchscreen Mode Register - 4 wire screen, pressure measurement */
> +#define AT91_SAMA5D2_TSMR_TSMODE_4WIRE_PRESS 2
> +/* Touchscreen Mode Register - 5 wire screen */
> +#define AT91_SAMA5D2_TSMR_TSMODE_5WIRE 3
> +/* Touchscreen Mode Register - Average samples mask */
> +#define AT91_SAMA5D2_TSMR_TSAV_MASK GENMASK(5, 4)
> +/* Touchscreen Mode Register - Average samples */
> +#define AT91_SAMA5D2_TSMR_TSAV(x) ((x) << 4)
> +/* Touchscreen Mode Register - Touch/trigger frequency ratio mask */
> +#define AT91_SAMA5D2_TSMR_TSFREQ_MASK GENMASK(11, 8)
> +/* Touchscreen Mode Register - Touch/trigger frequency ratio */
> +#define AT91_SAMA5D2_TSMR_TSFREQ(x) ((x) << 8)
> +/* Touchscreen Mode Register - Pen Debounce Time mask */
> +#define AT91_SAMA5D2_TSMR_PENDBC_MASK GENMASK(31, 28)
> +/* Touchscreen Mode Register - Pen Debounce Time */
> +#define AT91_SAMA5D2_TSMR_PENDBC(x) ((x) << 28)
> +/* Touchscreen Mode Register - No DMA for touch measurements */
> +#define AT91_SAMA5D2_TSMR_NOTSDMA BIT(22)
> +/* Touchscreen Mode Register - Disable pen detection */
> +#define AT91_SAMA5D2_TSMR_PENDET_DIS (0 << 24)
> +/* Touchscreen Mode Register - Enable pen detection */
> +#define AT91_SAMA5D2_TSMR_PENDET_ENA BIT(24)
> +
> /* Touchscreen X Position Register */
> #define AT91_SAMA5D2_XPOSR 0xb4
> /* Touchscreen Y Position Register */
> @@ -151,6 +193,12 @@
> #define AT91_SAMA5D2_TRGR_TRGMOD_EXT_TRIG_FALL 2
> /* Trigger Mode external trigger any edge */
> #define AT91_SAMA5D2_TRGR_TRGMOD_EXT_TRIG_ANY 3
> +/* Trigger Mode internal periodic */
> +#define AT91_SAMA5D2_TRGR_TRGMOD_PERIODIC 5
> +/* Trigger Mode - trigger period mask */
> +#define AT91_SAMA5D2_TRGR_TRGPER_MASK GENMASK(31, 16)
> +/* Trigger Mode - trigger period */
> +#define AT91_SAMA5D2_TRGR_TRGPER(x) ((x) << 16)
>
> /* Correction Select Register */
> #define AT91_SAMA5D2_COSR 0xd0
> @@ -169,6 +217,22 @@
> #define AT91_SAMA5D2_SINGLE_CHAN_CNT 12
> #define AT91_SAMA5D2_DIFF_CHAN_CNT 6
>
> +#define AT91_SAMA5D2_TIMESTAMP_CHAN_IDX (AT91_SAMA5D2_SINGLE_CHAN_CNT + \
> + AT91_SAMA5D2_DIFF_CHAN_CNT + 1)
> +
> +#define AT91_SAMA5D2_TOUCH_X_CHAN_IDX (AT91_SAMA5D2_SINGLE_CHAN_CNT + \
> + AT91_SAMA5D2_DIFF_CHAN_CNT * 2)
> +#define AT91_SAMA5D2_TOUCH_Y_CHAN_IDX (AT91_SAMA5D2_TOUCH_X_CHAN_IDX + 1)
> +#define AT91_SAMA5D2_TOUCH_P_CHAN_IDX (AT91_SAMA5D2_TOUCH_Y_CHAN_IDX + 1)
> +#define AT91_SAMA5D2_MAX_CHAN_IDX AT91_SAMA5D2_TOUCH_P_CHAN_IDX
> +
> +#define AT91_SAMA5D2_TOUCH_SAMPLE_PERIOD_US 2000 /* 2ms */
> +#define AT91_SAMA5D2_TOUCH_PEN_DETECT_DEBOUNCE_US 200
> +
> +#define AT91_SAMA5D2_XYZ_MASK GENMASK(11, 0)
> +
> +#define AT91_SAMA5D2_MAX_POS_BITS 12
> +
> /*
> * Maximum number of bytes to hold conversion from all channels
> * without the timestamp.
> @@ -222,6 +286,37 @@
> .indexed = 1, \
> }
>
> +#define AT91_SAMA5D2_CHAN_TOUCH(num, name, mod) \
> + { \
> + .type = IIO_POSITIONRELATIVE, \
> + .modified = 1, \
> + .channel = num, \
> + .channel2 = mod, \
> + .scan_index = num, \
> + .scan_type = { \
> + .sign = 'u', \
> + .realbits = 12, \
> + .storagebits = 16, \
> + }, \
> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
> + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\
> + .datasheet_name = name, \
> + }
> +#define AT91_SAMA5D2_CHAN_PRESSURE(num, name) \
> + { \
> + .type = IIO_PRESSURE, \
> + .channel = num, \
> + .scan_index = num, \
> + .scan_type = { \
> + .sign = 'u', \
> + .realbits = 12, \
> + .storagebits = 16, \
> + }, \
> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
> + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\
> + .datasheet_name = name, \
> + }
> +
> #define at91_adc_readl(st, reg) readl_relaxed(st->base + reg)
> #define at91_adc_writel(st, reg, val) writel_relaxed(val, st->base + reg)
>
> @@ -260,6 +355,22 @@ struct at91_adc_dma {
> s64 dma_ts;
> };
>
> +/**
> + * at91_adc_touch - at91-sama5d2 touchscreen information struct
> + * @sample_period_val: the value for periodic trigger interval
> + * @touching: is the pen touching the screen or not
> + * @x_pos: temporary placeholder for pressure computation
> + * @channels_bitmask: bitmask with the touchscreen channels enabled
> + * @workq: workqueue for buffer data pushing
> + */
> +struct at91_adc_touch {
> + u16 sample_period_val;
> + bool touching;
> + u16 x_pos;
> + unsigned long channels_bitmask;
> + struct work_struct workq;
> +};
> +
> struct at91_adc_state {
> void __iomem *base;
> int irq;
> @@ -267,6 +378,7 @@ struct at91_adc_state {
> struct regulator *reg;
> struct regulator *vref;
> int vref_uv;
> + unsigned int current_sample_rate;
> struct iio_trigger *trig;
> const struct at91_adc_trigger *selected_trig;
> const struct iio_chan_spec *chan;
> @@ -275,6 +387,7 @@ struct at91_adc_state {
> struct at91_adc_soc_info soc_info;
> wait_queue_head_t wq_data_available;
> struct at91_adc_dma dma_st;
> + struct at91_adc_touch touch_st;
> u16 buffer[AT91_BUFFER_MAX_HWORDS];
> /*
> * lock to prevent concurrent 'single conversion' requests through
> @@ -329,8 +442,10 @@ static const struct iio_chan_spec at91_adc_channels[] = {
> AT91_SAMA5D2_CHAN_DIFF(6, 7, 0x68),
> AT91_SAMA5D2_CHAN_DIFF(8, 9, 0x70),
> AT91_SAMA5D2_CHAN_DIFF(10, 11, 0x78),
> - IIO_CHAN_SOFT_TIMESTAMP(AT91_SAMA5D2_SINGLE_CHAN_CNT
> - + AT91_SAMA5D2_DIFF_CHAN_CNT + 1),
> + IIO_CHAN_SOFT_TIMESTAMP(AT91_SAMA5D2_TIMESTAMP_CHAN_IDX),
> + AT91_SAMA5D2_CHAN_TOUCH(AT91_SAMA5D2_TOUCH_X_CHAN_IDX, "x", IIO_MOD_X),
> + AT91_SAMA5D2_CHAN_TOUCH(AT91_SAMA5D2_TOUCH_Y_CHAN_IDX, "y", IIO_MOD_Y),
> + AT91_SAMA5D2_CHAN_PRESSURE(AT91_SAMA5D2_TOUCH_P_CHAN_IDX, "pressure"),
> };
>
> static int at91_adc_chan_xlate(struct iio_dev *indio_dev, int chan)
> @@ -354,6 +469,160 @@ at91_adc_chan_get(struct iio_dev *indio_dev, int chan)
> return indio_dev->channels + index;
> }
>
> +static inline int at91_adc_of_xlate(struct iio_dev *indio_dev,
> + const struct of_phandle_args *iiospec)
> +{
> + return at91_adc_chan_xlate(indio_dev, iiospec->args[0]);
> +}
> +
> +static int at91_adc_configure_touch(struct at91_adc_state *st, bool state)
> +{
> + u32 clk_khz = st->current_sample_rate / 1000;
> + int i = 0;
> + u16 pendbc;
> + u32 tsmr, acr;
> +
> + if (!state) {
> + /* disabling touch IRQs and setting mode to no touch enabled */
> + at91_adc_writel(st, AT91_SAMA5D2_IDR,
> + AT91_SAMA5D2_IER_PEN | AT91_SAMA5D2_IER_NOPEN);
> + at91_adc_writel(st, AT91_SAMA5D2_TSMR, 0);
> + return 0;
> + }
> + /*
> + * debounce time is in microseconds, we need it in milliseconds to
> + * multiply with kilohertz, so, divide by 1000, but after the multiply.
> + * round up to make sure pendbc is at least 1
> + */
> + pendbc = round_up(AT91_SAMA5D2_TOUCH_PEN_DETECT_DEBOUNCE_US *
> + clk_khz / 1000, 1);
> +
> + /* get the required exponent */
> + while (pendbc >> i++)
> + ;
> +
> + pendbc = i;
> +
> + tsmr = AT91_SAMA5D2_TSMR_TSMODE_4WIRE_PRESS;
> +
> + tsmr |= AT91_SAMA5D2_TSMR_TSAV(2) & AT91_SAMA5D2_TSMR_TSAV_MASK;
> + tsmr |= AT91_SAMA5D2_TSMR_PENDBC(pendbc) &
> + AT91_SAMA5D2_TSMR_PENDBC_MASK;
> + tsmr |= AT91_SAMA5D2_TSMR_NOTSDMA;
> + tsmr |= AT91_SAMA5D2_TSMR_PENDET_ENA;
> + tsmr |= AT91_SAMA5D2_TSMR_TSFREQ(2) & AT91_SAMA5D2_TSMR_TSFREQ_MASK;
> +
> + at91_adc_writel(st, AT91_SAMA5D2_TSMR, tsmr);
> +
> + acr = at91_adc_readl(st, AT91_SAMA5D2_ACR);
> + acr &= ~AT91_SAMA5D2_ACR_PENDETSENS_MASK;
> + acr |= 0x02 & AT91_SAMA5D2_ACR_PENDETSENS_MASK;
> + at91_adc_writel(st, AT91_SAMA5D2_ACR, acr);
> +
> + /* Sample Period Time = (TRGPER + 1) / ADCClock */
> + st->touch_st.sample_period_val =
> + round_up((AT91_SAMA5D2_TOUCH_SAMPLE_PERIOD_US *
> + clk_khz / 1000) - 1, 1);
> + /* enable pen detect IRQ */
> + at91_adc_writel(st, AT91_SAMA5D2_IER, AT91_SAMA5D2_IER_PEN);
> +
> + return 0;
> +}
> +
> +static u16 at91_adc_touch_pos(struct at91_adc_state *st, int reg)
> +{
> + u32 val;
> + u32 scale, result, pos;
> +
> + /*
> + * to obtain the actual position we must divide by scale
> + * and multiply with max, where
> + * max = 2^AT91_SAMA5D2_MAX_POS_BITS - 1
> + */
> + /* first half of register is the x or y, second half is the scale */
> + val = at91_adc_readl(st, reg);
> + if (!val)
> + dev_dbg(&iio_priv_to_dev(st)->dev, "pos is 0\n");
> +
> + pos = val & AT91_SAMA5D2_XYZ_MASK;
> + result = (pos << AT91_SAMA5D2_MAX_POS_BITS) - pos;
> + scale = (val >> 16) & AT91_SAMA5D2_XYZ_MASK;
> + if (scale == 0) {
> + dev_err(&iio_priv_to_dev(st)->dev, "scale is 0\n");
> + return 0;
> + }
> + result /= scale;
> +
> + return result;
> +}
> +
> +static u16 at91_adc_touch_x_pos(struct at91_adc_state *st)
> +{
> + st->touch_st.x_pos = at91_adc_touch_pos(st, AT91_SAMA5D2_XPOSR);
> + return st->touch_st.x_pos;
> +}
> +
> +static u16 at91_adc_touch_y_pos(struct at91_adc_state *st)
> +{
> + return at91_adc_touch_pos(st, AT91_SAMA5D2_YPOSR);
> +}
> +
> +static u16 at91_adc_touch_pressure(struct at91_adc_state *st)
> +{
> + u32 val;
> + u32 z1, z2;
> + u32 pres;
> + u32 rxp = 1;
> + u32 factor = 1000;
> +
> + /* calculate the pressure */
> + val = at91_adc_readl(st, AT91_SAMA5D2_PRESSR);
> + z1 = val & AT91_SAMA5D2_XYZ_MASK;
> + z2 = (val >> 16) & AT91_SAMA5D2_XYZ_MASK;
> +
> + if (z1 != 0)
> + pres = rxp * (st->touch_st.x_pos * factor / 1024) *
> + (z2 * factor / z1 - factor) /
> + factor;
> + else
> + pres = 0xFFFF; /* no pen contact */
> +
> + /*
> + * The pressure from device grows down, minimum is 0xFFFF, maximum 0x0.
> + * We compute it this way, but let's return it in the expected way,
> + * growing from 0 to 0xFFFF.
> + */
> + return 0xFFFF - pres;
> +}
> +
> +static int at91_adc_read_position(struct at91_adc_state *st, int chan, u16 *val)
> +{
> + *val = 0;
> + if (!st->touch_st.touching)
> + return -ENODATA;
> + if (chan == AT91_SAMA5D2_TOUCH_X_CHAN_IDX)
> + *val = at91_adc_touch_x_pos(st);
> + else if (chan == AT91_SAMA5D2_TOUCH_Y_CHAN_IDX)
> + *val = at91_adc_touch_y_pos(st);
> + else
> + return -ENODATA;
> +
> + return IIO_VAL_INT;
> +}
> +
> +static int at91_adc_read_pressure(struct at91_adc_state *st, int chan, u16 *val)
> +{
> + *val = 0;
> + if (!st->touch_st.touching)
> + return -ENODATA;
> + if (chan == AT91_SAMA5D2_TOUCH_P_CHAN_IDX)
> + *val = at91_adc_touch_pressure(st);
> + else
> + return -ENODATA;
> +
> + return IIO_VAL_INT;
> +}
> +
> static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state)
> {
> struct iio_dev *indio = iio_trigger_get_drvdata(trig);
> @@ -375,6 +644,11 @@ static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state)
>
> if (!chan)
> continue;
> + /* these channel types cannot be handled by this trigger */
> + if (chan->type == IIO_POSITIONRELATIVE ||
> + chan->type == IIO_PRESSURE)
> + continue;
> +
> if (state) {
> at91_adc_writel(st, AT91_SAMA5D2_CHER,
> BIT(chan->channel));
> @@ -520,7 +794,20 @@ static int at91_adc_dma_start(struct iio_dev *indio_dev)
> static int at91_adc_buffer_postenable(struct iio_dev *indio_dev)
> {
> int ret;
> + struct at91_adc_state *st = iio_priv(indio_dev);
>
> + /* check if we are enabling triggered buffer or the touchscreen */
> + if (bitmap_subset(indio_dev->active_scan_mask,
> + &st->touch_st.channels_bitmask,
> + AT91_SAMA5D2_MAX_CHAN_IDX + 1)) {
> + /* touchscreen enabling */
> + return at91_adc_configure_touch(st, true);
> + }
> + /* if we are not in triggered mode, we cannot enable the buffer. */
> + if (!(indio_dev->currentmode & INDIO_ALL_TRIGGERED_MODES))
> + return -EINVAL;
> +
> + /* we continue with the triggered buffer */
> ret = at91_adc_dma_start(indio_dev);
> if (ret) {
> dev_err(&indio_dev->dev, "buffer postenable failed\n");
> @@ -536,6 +823,18 @@ static int at91_adc_buffer_predisable(struct iio_dev *indio_dev)
> int ret;
> u8 bit;
>
> + /* check if we are disabling triggered buffer or the touchscreen */
> + if (bitmap_subset(indio_dev->active_scan_mask,
> + &st->touch_st.channels_bitmask,
> + AT91_SAMA5D2_MAX_CHAN_IDX + 1)) {
> + /* touchscreen disable */
> + return at91_adc_configure_touch(st, false);
> + }
> + /* if we are not in triggered mode, nothing to do here */
> + if (!(indio_dev->currentmode & INDIO_ALL_TRIGGERED_MODES))
> + return -EINVAL;
> +
> + /* continue with the triggered buffer */
> ret = iio_triggered_buffer_predisable(indio_dev);
> if (ret < 0)
> dev_err(&indio_dev->dev, "buffer predisable failed\n");
> @@ -558,6 +857,10 @@ static int at91_adc_buffer_predisable(struct iio_dev *indio_dev)
>
> if (!chan)
> continue;
> + /* these channel types are virtual, no need to do anything */
> + if (chan->type == IIO_POSITIONRELATIVE ||
> + chan->type == IIO_PRESSURE)
> + continue;
> if (st->dma_st.dma_chan)
> at91_adc_readl(st, chan->address);
> }
> @@ -622,7 +925,22 @@ static void at91_adc_trigger_handler_nodma(struct iio_dev *indio_dev,
>
> if (!chan)
> continue;
> - st->buffer[i] = at91_adc_readl(st, chan->address);
> + /*
> + * Our external trigger only supports the voltage channels.
> + * In case someone requested a different type of channel
> + * just put zeroes to buffer.
> + * This should not happen because we check the scan mode
> + * and scan mask when we enable the buffer, and we don't allow
> + * the buffer to start with a mixed mask (voltage and something
> + * else).
> + * Thus, emit a warning.
> + */
> + if (chan->type == IIO_VOLTAGE) {
> + st->buffer[i] = at91_adc_readl(st, chan->address);
> + } else {
> + st->buffer[i] = 0;
> + WARN(true, "This trigger cannot handle this type of channel");
> + }
> i++;
> }
> iio_push_to_buffers_with_timestamp(indio_dev, st->buffer,
> @@ -688,9 +1006,20 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
>
> static int at91_adc_buffer_init(struct iio_dev *indio)
> {
> - return devm_iio_triggered_buffer_setup(&indio->dev, indio,
> + struct at91_adc_state *st = iio_priv(indio);
> +
> + if (st->selected_trig->hw_trig) {
> + return devm_iio_triggered_buffer_setup(&indio->dev, indio,
> &iio_pollfunc_store_time,
> &at91_adc_trigger_handler, &at91_buffer_setup_ops);
> + }
> + /*
> + * we need to prepare the buffer ops in case we will get
> + * another buffer attached (like a callback buffer for the touchscreen)
> + */
> + indio->setup_ops = &at91_buffer_setup_ops;
> +
> + return 0;
> }
>
> static unsigned at91_adc_startup_time(unsigned startup_time_min,
> @@ -736,19 +1065,83 @@ static void at91_adc_setup_samp_freq(struct at91_adc_state *st, unsigned freq)
>
> dev_dbg(&indio_dev->dev, "freq: %u, startup: %u, prescal: %u\n",
> freq, startup, prescal);
> + st->current_sample_rate = freq;
> }
>
> -static unsigned at91_adc_get_sample_freq(struct at91_adc_state *st)
> +static inline unsigned at91_adc_get_sample_freq(struct at91_adc_state *st)
> {
> - unsigned f_adc, f_per = clk_get_rate(st->per_clk);
> - unsigned mr, prescal;
> + return st->current_sample_rate;
> +}
>
> - mr = at91_adc_readl(st, AT91_SAMA5D2_MR);
> - prescal = (mr >> AT91_SAMA5D2_MR_PRESCAL_OFFSET)
> - & AT91_SAMA5D2_MR_PRESCAL_MAX;
> - f_adc = f_per / (2 * (prescal + 1));
> +static void at91_adc_touch_data_handler(struct iio_dev *indio_dev)
> +{
> + struct at91_adc_state *st = iio_priv(indio_dev);
> + u8 bit;
> + u16 val;
> + int i = 0;
>
> - return f_adc;
> + for_each_set_bit(bit, indio_dev->active_scan_mask,
> + AT91_SAMA5D2_MAX_CHAN_IDX + 1) {
> + struct iio_chan_spec const *chan =
> + at91_adc_chan_get(indio_dev, bit);
> +
> + if (chan->type == IIO_POSITIONRELATIVE)
> + at91_adc_read_position(st, chan->channel, &val);
> + else if (chan->type == IIO_PRESSURE)
> + at91_adc_read_pressure(st, chan->channel, &val);
> + else
> + continue;
> + st->buffer[i] = val;
> + i++;
> + }
> + /*
> + * Schedule work to push to buffers.
> + * This is intended to push to the callback buffer that another driver
> + * registered. We are still in a handler from our IRQ. If we push
> + * directly, it means the other driver has it's callback called
> + * from our IRQ context. Which is something we better avoid.
> + * Let's schedule it after our IRQ is completed.
> + */
> + schedule_work(&st->touch_st.workq);
> +}
> +
> +static void at91_adc_pen_detect_interrupt(struct at91_adc_state *st)
> +{
> + at91_adc_writel(st, AT91_SAMA5D2_IDR, AT91_SAMA5D2_IER_PEN);
> + at91_adc_writel(st, AT91_SAMA5D2_IER, AT91_SAMA5D2_IER_NOPEN |
> + AT91_SAMA5D2_IER_XRDY | AT91_SAMA5D2_IER_YRDY |
> + AT91_SAMA5D2_IER_PRDY);
> + at91_adc_writel(st, AT91_SAMA5D2_TRGR,
> + AT91_SAMA5D2_TRGR_TRGMOD_PERIODIC |
> + AT91_SAMA5D2_TRGR_TRGPER(st->touch_st.sample_period_val));
> + st->touch_st.touching = true;
> +}
> +
> +static void at91_adc_no_pen_detect_interrupt(struct at91_adc_state *st)
> +{
> + struct iio_dev *indio_dev = iio_priv_to_dev(st);
> +
> + at91_adc_writel(st, AT91_SAMA5D2_TRGR,
> + AT91_SAMA5D2_TRGR_TRGMOD_NO_TRIGGER);
> + at91_adc_writel(st, AT91_SAMA5D2_IDR, AT91_SAMA5D2_IER_NOPEN |
> + AT91_SAMA5D2_IER_XRDY | AT91_SAMA5D2_IER_YRDY |
> + AT91_SAMA5D2_IER_PRDY);
> + st->touch_st.touching = false;
> +
> + at91_adc_touch_data_handler(indio_dev);
> +
> + at91_adc_writel(st, AT91_SAMA5D2_IER, AT91_SAMA5D2_IER_PEN);
> +}
> +
> +static void at91_adc_workq_handler(struct work_struct *workq)
> +{
> + struct at91_adc_touch *touch_st = container_of(workq,
> + struct at91_adc_touch, workq);
> + struct at91_adc_state *st = container_of(touch_st,
> + struct at91_adc_state, touch_st);
> + struct iio_dev *indio_dev = iio_priv_to_dev(st);
> +
> + iio_push_to_buffers(indio_dev, st->buffer);
> }
>
> static irqreturn_t at91_adc_interrupt(int irq, void *private)
> @@ -757,17 +1150,39 @@ static irqreturn_t at91_adc_interrupt(int irq, void *private)
> struct at91_adc_state *st = iio_priv(indio);
> u32 status = at91_adc_readl(st, AT91_SAMA5D2_ISR);
> u32 imr = at91_adc_readl(st, AT91_SAMA5D2_IMR);
> + u32 rdy_mask = AT91_SAMA5D2_IER_XRDY | AT91_SAMA5D2_IER_YRDY |
> + AT91_SAMA5D2_IER_PRDY;
>
> if (!(status & imr))
> return IRQ_NONE;
> -
> - if (iio_buffer_enabled(indio) && !st->dma_st.dma_chan) {
> + if (status & AT91_SAMA5D2_IER_PEN) {
> + /* pen detected IRQ */
> + at91_adc_pen_detect_interrupt(st);
> + } else if ((status & AT91_SAMA5D2_IER_NOPEN)) {
> + /* nopen detected IRQ */
> + at91_adc_no_pen_detect_interrupt(st);
> + } else if ((status & AT91_SAMA5D2_ISR_PENS) &&
> + ((status & rdy_mask) == rdy_mask)) {
> + /* periodic trigger IRQ - during pen sense */
> + at91_adc_touch_data_handler(indio);
> + } else if (status & AT91_SAMA5D2_ISR_PENS) {
> + /*
> + * touching, but the measurements are not ready yet.
> + * read and ignore.
> + */
> + status = at91_adc_readl(st, AT91_SAMA5D2_XPOSR);
> + status = at91_adc_readl(st, AT91_SAMA5D2_YPOSR);
> + status = at91_adc_readl(st, AT91_SAMA5D2_PRESSR);
> + } else if (iio_buffer_enabled(indio) && !st->dma_st.dma_chan) {
> + /* triggered buffer without DMA */
> disable_irq_nosync(irq);
> iio_trigger_poll(indio->trig);
> } else if (iio_buffer_enabled(indio) && st->dma_st.dma_chan) {
> + /* triggered buffer with DMA - should not happen */
> disable_irq_nosync(irq);
> WARN(true, "Unexpected irq occurred\n");
> } else if (!iio_buffer_enabled(indio)) {
> + /* software requested conversion */
> st->conversion_value = at91_adc_readl(st, st->chan->address);
> st->conversion_done = true;
> wake_up_interruptible(&st->wq_data_available);
> @@ -775,58 +1190,97 @@ static irqreturn_t at91_adc_interrupt(int irq, void *private)
> return IRQ_HANDLED;
> }
>
> -static int at91_adc_read_raw(struct iio_dev *indio_dev,
> - struct iio_chan_spec const *chan,
> - int *val, int *val2, long mask)
> +static int at91_adc_read_info_raw(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan, int *val)
> {
> struct at91_adc_state *st = iio_priv(indio_dev);
> u32 cor = 0;
> int ret;
>
> - switch (mask) {
> - case IIO_CHAN_INFO_RAW:
> - /* we cannot use software trigger if hw trigger enabled */
> + /*
> + * Keep in mind that we cannot use software trigger or touchscreen
> + * if external trigger is enabled
> + */
> + if (chan->type == IIO_POSITIONRELATIVE) {
> ret = iio_device_claim_direct_mode(indio_dev);
> if (ret)
> return ret;
> mutex_lock(&st->lock);
>
> - st->chan = chan;
> + ret = at91_adc_read_position(st, chan->channel,
> + (u16 *)val);
> + mutex_unlock(&st->lock);
> + iio_device_release_direct_mode(indio_dev);
>
> - if (chan->differential)
> - cor = (BIT(chan->channel) | BIT(chan->channel2)) <<
> - AT91_SAMA5D2_COR_DIFF_OFFSET;
> -
> - at91_adc_writel(st, AT91_SAMA5D2_COR, cor);
> - at91_adc_writel(st, AT91_SAMA5D2_CHER, BIT(chan->channel));
> - at91_adc_writel(st, AT91_SAMA5D2_IER, BIT(chan->channel));
> - at91_adc_writel(st, AT91_SAMA5D2_CR, AT91_SAMA5D2_CR_START);
> -
> - ret = wait_event_interruptible_timeout(st->wq_data_available,
> - st->conversion_done,
> - msecs_to_jiffies(1000));
> - if (ret == 0)
> - ret = -ETIMEDOUT;
> -
> - if (ret > 0) {
> - *val = st->conversion_value;
> - if (chan->scan_type.sign == 's')
> - *val = sign_extend32(*val, 11);
> - ret = IIO_VAL_INT;
> - st->conversion_done = false;
> - }
> + return ret;
> + }
> + if (chan->type == IIO_PRESSURE) {
> + ret = iio_device_claim_direct_mode(indio_dev);
> + if (ret)
> + return ret;
> + mutex_lock(&st->lock);
>
> - at91_adc_writel(st, AT91_SAMA5D2_IDR, BIT(chan->channel));
> - at91_adc_writel(st, AT91_SAMA5D2_CHDR, BIT(chan->channel));
> + ret = at91_adc_read_pressure(st, chan->channel,
> + (u16 *)val);
> + mutex_unlock(&st->lock);
> + iio_device_release_direct_mode(indio_dev);
>
> - /* Needed to ACK the DRDY interruption */
> - at91_adc_readl(st, AT91_SAMA5D2_LCDR);
> + return ret;
> + }
>
> - mutex_unlock(&st->lock);
> + /* in this case we have a voltage channel */
>
> - iio_device_release_direct_mode(indio_dev);
> + ret = iio_device_claim_direct_mode(indio_dev);
> + if (ret)
> return ret;
> + mutex_lock(&st->lock);
> +
> + st->chan = chan;
> +
> + if (chan->differential)
> + cor = (BIT(chan->channel) | BIT(chan->channel2)) <<
> + AT91_SAMA5D2_COR_DIFF_OFFSET;
> +
> + at91_adc_writel(st, AT91_SAMA5D2_COR, cor);
> + at91_adc_writel(st, AT91_SAMA5D2_CHER, BIT(chan->channel));
> + at91_adc_writel(st, AT91_SAMA5D2_IER, BIT(chan->channel));
> + at91_adc_writel(st, AT91_SAMA5D2_CR, AT91_SAMA5D2_CR_START);
> +
> + ret = wait_event_interruptible_timeout(st->wq_data_available,
> + st->conversion_done,
> + msecs_to_jiffies(1000));
> + if (ret == 0)
> + ret = -ETIMEDOUT;
> +
> + if (ret > 0) {
> + *val = st->conversion_value;
> + if (chan->scan_type.sign == 's')
> + *val = sign_extend32(*val, 11);
> + ret = IIO_VAL_INT;
> + st->conversion_done = false;
> + }
> +
> + at91_adc_writel(st, AT91_SAMA5D2_IDR, BIT(chan->channel));
> + at91_adc_writel(st, AT91_SAMA5D2_CHDR, BIT(chan->channel));
> +
> + /* Needed to ACK the DRDY interruption */
> + at91_adc_readl(st, AT91_SAMA5D2_LCDR);
> +
> + mutex_unlock(&st->lock);
> +
> + iio_device_release_direct_mode(indio_dev);
> + return ret;
> +}
> +
> +static int at91_adc_read_raw(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan,
> + int *val, int *val2, long mask)
> +{
> + struct at91_adc_state *st = iio_priv(indio_dev);
>
> + switch (mask) {
> + case IIO_CHAN_INFO_RAW:
> + return at91_adc_read_info_raw(indio_dev, chan, val);
> case IIO_CHAN_INFO_SCALE:
> *val = st->vref_uv / 1000;
> if (chan->differential)
> @@ -974,9 +1428,29 @@ static int at91_adc_set_watermark(struct iio_dev *indio_dev, unsigned int val)
> return 0;
> }
>
> +static int at91_adc_update_scan_mode(struct iio_dev *indio_dev,
> + const unsigned long *scan_mask)
> +{
> + struct at91_adc_state *st = iio_priv(indio_dev);
> +
> + if (bitmap_subset(scan_mask, &st->touch_st.channels_bitmask,
> + AT91_SAMA5D2_MAX_CHAN_IDX + 1))
> + return 0;
> + /*
> + * if the new bitmap is a combination of touchscreen and regular
> + * channels, then we are not fine
> + */
> + if (bitmap_intersects(&st->touch_st.channels_bitmask, scan_mask,
> + AT91_SAMA5D2_MAX_CHAN_IDX + 1))
> + return -EINVAL;
> + return 0;
> +}
> +
> static const struct iio_info at91_adc_info = {
> .read_raw = &at91_adc_read_raw,
> .write_raw = &at91_adc_write_raw,
> + .update_scan_mode = &at91_adc_update_scan_mode,
> + .of_xlate = &at91_adc_of_xlate,
> .hwfifo_set_watermark = &at91_adc_set_watermark,
> };
>
> @@ -1044,13 +1518,20 @@ static int at91_adc_probe(struct platform_device *pdev)
>
> indio_dev->dev.parent = &pdev->dev;
> indio_dev->name = dev_name(&pdev->dev);
> - indio_dev->modes = INDIO_DIRECT_MODE;
> + indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
> indio_dev->info = &at91_adc_info;
> indio_dev->channels = at91_adc_channels;
> indio_dev->num_channels = ARRAY_SIZE(at91_adc_channels);
>
> st = iio_priv(indio_dev);
>
> + bitmap_set(&st->touch_st.channels_bitmask,
> + AT91_SAMA5D2_TOUCH_X_CHAN_IDX, 1);
> + bitmap_set(&st->touch_st.channels_bitmask,
> + AT91_SAMA5D2_TOUCH_Y_CHAN_IDX, 1);
> + bitmap_set(&st->touch_st.channels_bitmask,
> + AT91_SAMA5D2_TOUCH_P_CHAN_IDX, 1);
> +
> ret = of_property_read_u32(pdev->dev.of_node,
> "atmel,min-sample-rate-hz",
> &st->soc_info.min_sample_rate);
> @@ -1100,6 +1581,7 @@ static int at91_adc_probe(struct platform_device *pdev)
>
> init_waitqueue_head(&st->wq_data_available);
> mutex_init(&st->lock);
> + INIT_WORK(&st->touch_st.workq, at91_adc_workq_handler);
>
> res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> if (!res)
> @@ -1159,13 +1641,13 @@ static int at91_adc_probe(struct platform_device *pdev)
>
> platform_set_drvdata(pdev, indio_dev);
>
> - if (st->selected_trig->hw_trig) {
> - ret = at91_adc_buffer_init(indio_dev);
> - if (ret < 0) {
> - dev_err(&pdev->dev, "couldn't initialize the buffer.\n");
> - goto per_clk_disable_unprepare;
> - }
> + ret = at91_adc_buffer_init(indio_dev);
> + if (ret < 0) {
> + dev_err(&pdev->dev, "couldn't initialize the buffer.\n");
> + goto per_clk_disable_unprepare;
> + }
>
> + if (st->selected_trig->hw_trig) {
> ret = at91_adc_trigger_init(indio_dev);
> if (ret < 0) {
> dev_err(&pdev->dev, "couldn't setup the triggers.\n");
> @@ -1272,9 +1754,20 @@ static __maybe_unused int at91_adc_resume(struct device *dev)
> at91_adc_hw_init(st);
>
> /* reconfiguring trigger hardware state */
> - if (iio_buffer_enabled(indio_dev))
> - at91_adc_configure_trigger(st->trig, true);
> + if (!iio_buffer_enabled(indio_dev))
> + return 0;
> +
> + /* check if we are enabling triggered buffer or the touchscreen */
> + if (bitmap_subset(indio_dev->active_scan_mask,
> + &st->touch_st.channels_bitmask,
> + AT91_SAMA5D2_MAX_CHAN_IDX + 1)) {
> + /* touchscreen enabling */
> + return at91_adc_configure_touch(st, true);
> + } else {
> + return at91_adc_configure_trigger(st->trig, true);
> + }
>
> + /* not needed but more explicit */
> return 0;
>
> vref_disable_resume:
> --
> 2.7.4
>
^ permalink raw reply
* Re: [PATCH v6 6/9] input: touchscreen: resistive-adc-touch: add generic resistive ADC touchscreen
From: Eugen Hristev @ 2018-05-22 7:56 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: jic23, ludovic.desroches, alexandre.belloni, linux-arm-kernel,
devicetree, linux-kernel, linux-iio, linux-input, nicolas.ferre,
robh
In-Reply-To: <20180521210611.GB74396@dtor-ws>
On 22.05.2018 00:06, Dmitry Torokhov wrote:
> On Mon, May 21, 2018 at 01:27:54PM +0300, Eugen Hristev wrote:
>> This adds a generic resistive touchscreen (GRTS) driver, which is based
>> on an IIO device (an ADC). It must be connected to the channels of an ADC
>> to receive touch data. Then it will feed the data into the input subsystem
>> where it registers an input device.
>> It uses an IIO callback buffer to register to the IIO device
>>
>> Some parts of this patch are based on initial original work by
>> Mohamed Jamsheeth Hajanajubudeen and Bandaru Venkateswara Swamy
>>
>> Signed-off-by: Eugen Hristev <eugen.hristev@microchip.com>
>
> Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
>
> I assume this will go through IIO tree? Just a couple of comsmetic
> comments below, feel free to ignore.
Thank you, I modified as you suggested and sent out v7. Jonathan said in
an earlier e-mail that he will take them through IIO tree. Waiting on
his feedback.
Eugen
>
>> ---
>> Changes in v6:
>> - changed a dev_err to dev_dbg which was forgotten in v5.
>>
>> Changes in v5:
>> - return error on probe if failed add_action_or_reset
>> - renamed property touchscreen-threshold-pressure to
>> touchscreen-min-pressure, changed variables accordingly
>>
>> Changes in v4:
>> - added a small description in file header
>> - changed MAX_POS_MASK to GRTS_MAX_POS_MASK
>> - initialized press with 0, as this value means no touch.
>> press has to be initialized because compiler/checkpatch complains
>> that can be used uninitialized.
>> - changed of_property_read_u32 to device_*
>> - set_abs_params for pressure will have range according to threshold
>> - changed evbit and keybit with set_capability call
>> - changed variable names to error instead of ret
>> - checked errors for add_action_or_reset
>> - cosmetic cleaning
>>
>> Changes in v3:
>> - pressure now reported naturally growing down-up
>> - using helpers from touchscreen.h to parse DT properties
>> - added devm_add_action_or_reset to handle callback buffer clean on exit
>> - changed compatible and threshold property to adapt to changed bindings
>>
>> Changes in v2:
>> - this is now a generic resistive adc touchscreen driver
>>
>>
>> drivers/input/touchscreen/Kconfig | 13 ++
>> drivers/input/touchscreen/Makefile | 1 +
>> drivers/input/touchscreen/resistive-adc-touch.c | 201 ++++++++++++++++++++++++
>> 3 files changed, 215 insertions(+)
>> create mode 100644 drivers/input/touchscreen/resistive-adc-touch.c
>>
>> diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
>> index 4f15496..8f85d3a 100644
>> --- a/drivers/input/touchscreen/Kconfig
>> +++ b/drivers/input/touchscreen/Kconfig
>> @@ -92,6 +92,19 @@ config TOUCHSCREEN_AD7879_SPI
>> To compile this driver as a module, choose M here: the
>> module will be called ad7879-spi.
>>
>> +config TOUCHSCREEN_ADC
>> + tristate "Generic ADC based resistive touchscreen"
>> + depends on IIO
>> + select IIO_BUFFER_CB
>> + help
>> + Say Y here if you want to use the generic ADC
>> + resistive touchscreen driver.
>> +
>> + If unsure, say N (but it's safe to say "Y").
>> +
>> + To compile this driver as a module, choose M here: the
>> + module will be called resistive-adc-touch.ko.
>> +
>> config TOUCHSCREEN_AR1021_I2C
>> tristate "Microchip AR1020/1021 i2c touchscreen"
>> depends on I2C && OF
>> diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
>> index dddae79..843c7f9 100644
>> --- a/drivers/input/touchscreen/Makefile
>> +++ b/drivers/input/touchscreen/Makefile
>> @@ -13,6 +13,7 @@ obj-$(CONFIG_TOUCHSCREEN_AD7877) += ad7877.o
>> obj-$(CONFIG_TOUCHSCREEN_AD7879) += ad7879.o
>> obj-$(CONFIG_TOUCHSCREEN_AD7879_I2C) += ad7879-i2c.o
>> obj-$(CONFIG_TOUCHSCREEN_AD7879_SPI) += ad7879-spi.o
>> +obj-$(CONFIG_TOUCHSCREEN_ADC) += resistive-adc-touch.o
>> obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o
>> obj-$(CONFIG_TOUCHSCREEN_AR1021_I2C) += ar1021_i2c.o
>> obj-$(CONFIG_TOUCHSCREEN_ATMEL_MXT) += atmel_mxt_ts.o
>> diff --git a/drivers/input/touchscreen/resistive-adc-touch.c b/drivers/input/touchscreen/resistive-adc-touch.c
>> new file mode 100644
>> index 0000000..05d629b
>> --- /dev/null
>> +++ b/drivers/input/touchscreen/resistive-adc-touch.c
>> @@ -0,0 +1,201 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * ADC generic resistive touchscreen (GRTS)
>> + * This is a generic input driver that connects to an ADC
>> + * given the channels in device tree, and reports events to the input
>> + * subsystem.
>> + *
>> + * Copyright (C) 2017,2018 Microchip Technology,
>> + * Author: Eugen Hristev <eugen.hristev@microchip.com>
>> + *
>> + */
>> +#include <linux/input.h>
>> +#include <linux/input/touchscreen.h>
>> +#include <linux/iio/consumer.h>
>> +#include <linux/iio/iio.h>
>> +#include <linux/module.h>
>> +#include <linux/of.h>
>> +#include <linux/of_device.h>
>> +#include <linux/platform_device.h>
>> +
>> +#define DRIVER_NAME "resistive-adc-touch"
>> +#define GRTS_DEFAULT_PRESSURE_MIN 50000
>> +#define GRTS_MAX_POS_MASK GENMASK(11, 0)
>> +
>> +/**
>> + * grts_state - generic resistive touch screen information struct
>> + * @pressure_min: number representing the minimum for the pressure
>> + * @pressure: are we getting pressure info or not
>> + * @iio_chans: list of channels acquired
>> + * @iio_cb: iio_callback buffer for the data
>> + * @input: the input device structure that we register
>> + * @prop: touchscreen properties struct
>> + */
>> +struct grts_state {
>> + u32 pressure_min;
>> + bool pressure;
>> + struct iio_channel *iio_chans;
>> + struct iio_cb_buffer *iio_cb;
>> + struct input_dev *input;
>> + struct touchscreen_properties prop;
>> +};
>> +
>> +static int grts_cb(const void *data, void *private)
>> +{
>> + const u16 *touch_info = data;
>> + struct grts_state *st = private;
>> + unsigned int x, y, press = 0x0;
>> +
>> + /* channel data coming in buffer in the order below */
>> + x = touch_info[0];
>> + y = touch_info[1];
>> + if (st->pressure)
>> + press = touch_info[2];
>> +
>> + if ((!x && !y) || (st->pressure && (press < st->pressure_min))) {
>> + /* report end of touch */
>> + input_report_key(st->input, BTN_TOUCH, 0);
>> + input_sync(st->input);
>> + return 0;
>> + }
>> +
>> + /* report proper touch to subsystem*/
>> + touchscreen_report_pos(st->input, &st->prop, x, y, false);
>> + if (st->pressure)
>> + input_report_abs(st->input, ABS_PRESSURE, press);
>> + input_report_key(st->input, BTN_TOUCH, 1);
>> + input_sync(st->input);
>> +
>> + return 0;
>> +}
>> +
>> +static int grts_open(struct input_dev *dev)
>> +{
>> + int error;
>> + struct grts_state *st = input_get_drvdata(dev);
>> +
>> + error = iio_channel_start_all_cb(st->iio_cb);
>> + if (error) {
>> + dev_err(dev->dev.parent, "failed to start callback buffer.\n");
>> + return error;
>> + }
>> + return 0;
>> +}
>> +
>> +static void grts_close(struct input_dev *dev)
>> +{
>> + struct grts_state *st = input_get_drvdata(dev);
>> +
>> + iio_channel_stop_all_cb(st->iio_cb);
>> +}
>> +
>> +static void grts_disable(void *data)
>> +{
>> + iio_channel_release_all_cb(data);
>> +}
>> +
>> +static int grts_probe(struct platform_device *pdev)
>> +{
>> + struct grts_state *st;
>> + struct input_dev *input;
>> + struct device *dev = &pdev->dev;
>> + struct iio_channel *chan;
>> + int error;
>> +
>> + st = devm_kzalloc(dev, sizeof(struct grts_state), GFP_KERNEL);
>> + if (!st)
>> + return -ENOMEM;
>> +
>> + error = device_property_read_u32(dev, "touchscreen-min-pressure",
>> + &st->pressure_min);
>> + if (error) {
>> + dev_dbg(dev, "can't get touchscreen-min-pressure property.\n");
>> + st->pressure_min = GRTS_DEFAULT_PRESSURE_MIN;
>> + }
>
> I do not think it makes sense to complain about missing property if
> there is no "pressure" channel. Probably move down?
>
>> +
>> + /* get the channels from IIO device */
>> + st->iio_chans = devm_iio_channel_get_all(dev);
>> + if (IS_ERR(st->iio_chans)) {
>> + if (PTR_ERR(st->iio_chans) != -EPROBE_DEFER)
>> + dev_err(dev, "can't get iio channels.\n");
>> + return PTR_ERR(st->iio_chans);
>
> error = PTR_ERR(st->iio_chans);
> if (error != -EPROBE_DEFER)
> dev_err(dev, "can't get iio channels.\n");
> return error;
>
>> + }
>> +
>> + chan = &st->iio_chans[0];
>> + st->pressure = false;
>> + while (chan && chan->indio_dev) {
>> + if (!strcmp(chan->channel->datasheet_name, "pressure"))
>> + st->pressure = true;
>> + chan++;
>> + }
>> +
>> + input = devm_input_allocate_device(dev);
>> + if (!input) {
>> + dev_err(dev, "failed to allocate input device.\n");
>> + return -ENOMEM;
>> + }
>> +
>> + input->name = DRIVER_NAME;
>> + input->id.bustype = BUS_HOST;
>> + input->open = grts_open;
>> + input->close = grts_close;
>> +
>> + input_set_abs_params(input, ABS_X, 0, GRTS_MAX_POS_MASK - 1, 0, 0);
>> + input_set_abs_params(input, ABS_Y, 0, GRTS_MAX_POS_MASK - 1, 0, 0);
>> + if (st->pressure)
>> + input_set_abs_params(input, ABS_PRESSURE, st->pressure_min,
>> + 0xffff, 0, 0);
>> +
>> + input_set_capability(input, EV_KEY, BTN_TOUCH);
>> +
>> + /* parse optional device tree properties */
>> + touchscreen_parse_properties(input, false, &st->prop);
>> +
>> + st->input = input;
>> + input_set_drvdata(input, st);
>> +
>> + error = input_register_device(input);
>> + if (error) {
>> + dev_err(dev, "failed to register input device.");
>> + return error;
>> + }
>> +
>> + st->iio_cb = iio_channel_get_all_cb(dev, grts_cb, st);
>> + if (IS_ERR(st->iio_cb)) {
>> + dev_err(dev, "failed to allocate callback buffer.\n");
>> + error = PTR_ERR(st->iio_cb);
>> + return error;
>
> Simply:
>
> return PTR_ERR(st->iio_cb);
>
> since you opted out of printing error codes in error messages.
>
>> + }
>> +
>> + error = devm_add_action_or_reset(dev, grts_disable, st->iio_cb);
>> + if (error) {
>> + dev_err(dev, "failed to add disable action.\n");
>> + return error;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static const struct of_device_id grts_of_match[] = {
>> + {
>> + .compatible = "resistive-adc-touch",
>> + }, {
>> + /* sentinel */
>> + },
>> +};
>> +
>> +MODULE_DEVICE_TABLE(of, grts_of_match);
>> +
>> +static struct platform_driver grts_driver = {
>> + .probe = grts_probe,
>> + .driver = {
>> + .name = DRIVER_NAME,
>> + .of_match_table = of_match_ptr(grts_of_match),
>> + },
>> +};
>> +
>> +module_platform_driver(grts_driver);
>> +
>> +MODULE_AUTHOR("Eugen Hristev <eugen.hristev@microchip.com>");
>> +MODULE_DESCRIPTION("Generic ADC Resistive Touch Driver");
>> +MODULE_LICENSE("GPL v2");
>> --
>> 2.7.4
>>
>
> Thanks.
>
^ permalink raw reply
* [PATCH v7 9/9] ARM: dts: at91: sama5d2: Add resistive touch device
From: Eugen Hristev @ 2018-05-22 7:52 UTC (permalink / raw)
To: jic23, ludovic.desroches, alexandre.belloni, linux-arm-kernel,
devicetree, linux-kernel, linux-iio, linux-input, nicolas.ferre,
dmitry.torokhov, robh
Cc: Eugen Hristev
In-Reply-To: <1526975559-18966-1-git-send-email-eugen.hristev@microchip.com>
Add generic resistive touch device which is connected to ADC block
inside the SAMA5D2 SoC
Signed-off-by: Eugen Hristev <eugen.hristev@microchip.com>
---
Changes in v5:
- renamed touchscreen-threshold-pressure to touchscreen-min-pressure
arch/arm/boot/dts/sama5d2.dtsi | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi
index f06ba99..a44f325 100644
--- a/arch/arm/boot/dts/sama5d2.dtsi
+++ b/arch/arm/boot/dts/sama5d2.dtsi
@@ -1442,6 +1442,16 @@
status = "disabled";
};
+ resistive_touch: resistive-touch {
+ compatible = "resistive-adc-touch";
+ io-channels = <&adc AT91_SAMA5D2_ADC_X_CHANNEL>,
+ <&adc AT91_SAMA5D2_ADC_Y_CHANNEL>,
+ <&adc AT91_SAMA5D2_ADC_P_CHANNEL>;
+ io-channel-names = "x", "y", "pressure";
+ touchscreen-min-pressure = <50000>;
+ status = "disabled";
+ };
+
pioA: pinctrl@fc038000 {
compatible = "atmel,sama5d2-pinctrl";
reg = <0xfc038000 0x600>;
--
2.7.4
^ permalink raw reply related
* [PATCH v7 8/9] ARM: dts: at91: sama5d2: add channel cells for ADC device
From: Eugen Hristev @ 2018-05-22 7:52 UTC (permalink / raw)
To: jic23, ludovic.desroches, alexandre.belloni, linux-arm-kernel,
devicetree, linux-kernel, linux-iio, linux-input, nicolas.ferre,
dmitry.torokhov, robh
Cc: Eugen Hristev
In-Reply-To: <1526975559-18966-1-git-send-email-eugen.hristev@microchip.com>
Preparing the ADC device to connect channel consumer drivers
Signed-off-by: Eugen Hristev <eugen.hristev@microchip.com>
---
arch/arm/boot/dts/sama5d2.dtsi | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi
index 61f68e5..f06ba99 100644
--- a/arch/arm/boot/dts/sama5d2.dtsi
+++ b/arch/arm/boot/dts/sama5d2.dtsi
@@ -47,6 +47,7 @@
#include <dt-bindings/dma/at91.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/clock/at91.h>
+#include <dt-bindings/iio/adc/at91-sama5d2_adc.h>
/ {
model = "Atmel SAMA5D2 family SoC";
@@ -1437,6 +1438,7 @@
atmel,max-sample-rate-hz = <20000000>;
atmel,startup-time-ms = <4>;
atmel,trigger-edge-type = <IRQ_TYPE_EDGE_RISING>;
+ #io-channel-cells = <1>;
status = "disabled";
};
--
2.7.4
^ permalink raw reply related
* [PATCH v7 7/9] dt-bindings: iio: adc: at91-sama5d2_adc: add channel specific consumer info
From: Eugen Hristev @ 2018-05-22 7:52 UTC (permalink / raw)
To: jic23, ludovic.desroches, alexandre.belloni, linux-arm-kernel,
devicetree, linux-kernel, linux-iio, linux-input, nicolas.ferre,
dmitry.torokhov, robh
Cc: Eugen Hristev
In-Reply-To: <1526975559-18966-1-git-send-email-eugen.hristev@microchip.com>
Added defines for channel consumer device-tree binding
Signed-off-by: Eugen Hristev <eugen.hristev@microchip.com>
Reviewed-by: Rob Herring <robh@kernel.org>
---
.../devicetree/bindings/iio/adc/at91-sama5d2_adc.txt | 9 +++++++++
include/dt-bindings/iio/adc/at91-sama5d2_adc.h | 16 ++++++++++++++++
2 files changed, 25 insertions(+)
create mode 100644 include/dt-bindings/iio/adc/at91-sama5d2_adc.h
diff --git a/Documentation/devicetree/bindings/iio/adc/at91-sama5d2_adc.txt b/Documentation/devicetree/bindings/iio/adc/at91-sama5d2_adc.txt
index 6469a4c..4a3c1d4 100644
--- a/Documentation/devicetree/bindings/iio/adc/at91-sama5d2_adc.txt
+++ b/Documentation/devicetree/bindings/iio/adc/at91-sama5d2_adc.txt
@@ -21,6 +21,14 @@ Optional properties:
- dmas: Phandle to dma channel for the ADC.
- dma-names: Must be "rx" when dmas property is being used.
See ../../dma/dma.txt for details.
+ - #io-channel-cells: in case consumer drivers are attached, this must be 1.
+ See <Documentation/devicetree/bindings/iio/iio-bindings.txt> for details.
+
+Properties for consumer drivers:
+ - Consumer drivers can be connected to this producer device, as specified
+ in <Documentation/devicetree/bindings/iio/iio-bindings.txt>
+ - Channels exposed are specified in:
+ <dt-bindings/iio/adc/at91-sama5d2_adc.txt>
Example:
@@ -38,4 +46,5 @@ adc: adc@fc030000 {
atmel,trigger-edge-type = <IRQ_TYPE_EDGE_BOTH>;
dmas = <&dma0 (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | AT91_XDMAC_DT_PERID(25))>;
dma-names = "rx";
+ #io-channel-cells = <1>;
}
diff --git a/include/dt-bindings/iio/adc/at91-sama5d2_adc.h b/include/dt-bindings/iio/adc/at91-sama5d2_adc.h
new file mode 100644
index 0000000..70f99db
--- /dev/null
+++ b/include/dt-bindings/iio/adc/at91-sama5d2_adc.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * This header provides constants for configuring the AT91 SAMA5D2 ADC
+ */
+
+#ifndef _DT_BINDINGS_IIO_ADC_AT91_SAMA5D2_ADC_H
+#define _DT_BINDINGS_IIO_ADC_AT91_SAMA5D2_ADC_H
+
+/* X relative position channel index */
+#define AT91_SAMA5D2_ADC_X_CHANNEL 24
+/* Y relative position channel index */
+#define AT91_SAMA5D2_ADC_Y_CHANNEL 25
+/* pressure channel index */
+#define AT91_SAMA5D2_ADC_P_CHANNEL 26
+
+#endif
--
2.7.4
^ permalink raw reply related
* [PATCH v7 6/9] input: touchscreen: resistive-adc-touch: add generic resistive ADC touchscreen
From: Eugen Hristev @ 2018-05-22 7:52 UTC (permalink / raw)
To: jic23, ludovic.desroches, alexandre.belloni, linux-arm-kernel,
devicetree, linux-kernel, linux-iio, linux-input, nicolas.ferre,
dmitry.torokhov, robh
Cc: Eugen Hristev
In-Reply-To: <1526975559-18966-1-git-send-email-eugen.hristev@microchip.com>
This adds a generic resistive touchscreen (GRTS) driver, which is based
on an IIO device (an ADC). It must be connected to the channels of an ADC
to receive touch data. Then it will feed the data into the input subsystem
where it registers an input device.
It uses an IIO callback buffer to register to the IIO device
Some parts of this patch are based on initial original work by
Mohamed Jamsheeth Hajanajubudeen and Bandaru Venkateswara Swamy
Signed-off-by: Eugen Hristev <eugen.hristev@microchip.com>
Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
Changes in v7:
- cosmetic fixes as suggested by Dmitry: moved min pressure
property lookup below and only if pressure channel is available.
used the error variable in probe at some point, removed it at
different point.
Changes in v6:
- changed a dev_err to dev_dbg which was forgotten in v5.
Changes in v5:
- return error on probe if failed add_action_or_reset
- renamed property touchscreen-threshold-pressure to
touchscreen-min-pressure, changed variables accordingly
Changes in v4:
- added a small description in file header
- changed MAX_POS_MASK to GRTS_MAX_POS_MASK
- initialized press with 0, as this value means no touch.
press has to be initialized because compiler/checkpatch complains
that can be used uninitialized.
- changed of_property_read_u32 to device_*
- set_abs_params for pressure will have range according to threshold
- changed evbit and keybit with set_capability call
- changed variable names to error instead of ret
- checked errors for add_action_or_reset
- cosmetic cleaning
Changes in v3:
- pressure now reported naturally growing down-up
- using helpers from touchscreen.h to parse DT properties
- added devm_add_action_or_reset to handle callback buffer clean on exit
- changed compatible and threshold property to adapt to changed bindings
Changes in v2:
- this is now a generic resistive adc touchscreen driver
drivers/input/touchscreen/Kconfig | 13 ++
drivers/input/touchscreen/Makefile | 1 +
drivers/input/touchscreen/resistive-adc-touch.c | 204 ++++++++++++++++++++++++
3 files changed, 218 insertions(+)
create mode 100644 drivers/input/touchscreen/resistive-adc-touch.c
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 4f15496..8f85d3a 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -92,6 +92,19 @@ config TOUCHSCREEN_AD7879_SPI
To compile this driver as a module, choose M here: the
module will be called ad7879-spi.
+config TOUCHSCREEN_ADC
+ tristate "Generic ADC based resistive touchscreen"
+ depends on IIO
+ select IIO_BUFFER_CB
+ help
+ Say Y here if you want to use the generic ADC
+ resistive touchscreen driver.
+
+ If unsure, say N (but it's safe to say "Y").
+
+ To compile this driver as a module, choose M here: the
+ module will be called resistive-adc-touch.ko.
+
config TOUCHSCREEN_AR1021_I2C
tristate "Microchip AR1020/1021 i2c touchscreen"
depends on I2C && OF
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index dddae79..843c7f9 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_TOUCHSCREEN_AD7877) += ad7877.o
obj-$(CONFIG_TOUCHSCREEN_AD7879) += ad7879.o
obj-$(CONFIG_TOUCHSCREEN_AD7879_I2C) += ad7879-i2c.o
obj-$(CONFIG_TOUCHSCREEN_AD7879_SPI) += ad7879-spi.o
+obj-$(CONFIG_TOUCHSCREEN_ADC) += resistive-adc-touch.o
obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o
obj-$(CONFIG_TOUCHSCREEN_AR1021_I2C) += ar1021_i2c.o
obj-$(CONFIG_TOUCHSCREEN_ATMEL_MXT) += atmel_mxt_ts.o
diff --git a/drivers/input/touchscreen/resistive-adc-touch.c b/drivers/input/touchscreen/resistive-adc-touch.c
new file mode 100644
index 0000000..cfc8bb4
--- /dev/null
+++ b/drivers/input/touchscreen/resistive-adc-touch.c
@@ -0,0 +1,204 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ADC generic resistive touchscreen (GRTS)
+ * This is a generic input driver that connects to an ADC
+ * given the channels in device tree, and reports events to the input
+ * subsystem.
+ *
+ * Copyright (C) 2017,2018 Microchip Technology,
+ * Author: Eugen Hristev <eugen.hristev@microchip.com>
+ *
+ */
+#include <linux/input.h>
+#include <linux/input/touchscreen.h>
+#include <linux/iio/consumer.h>
+#include <linux/iio/iio.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#define DRIVER_NAME "resistive-adc-touch"
+#define GRTS_DEFAULT_PRESSURE_MIN 50000
+#define GRTS_MAX_POS_MASK GENMASK(11, 0)
+
+/**
+ * grts_state - generic resistive touch screen information struct
+ * @pressure_min: number representing the minimum for the pressure
+ * @pressure: are we getting pressure info or not
+ * @iio_chans: list of channels acquired
+ * @iio_cb: iio_callback buffer for the data
+ * @input: the input device structure that we register
+ * @prop: touchscreen properties struct
+ */
+struct grts_state {
+ u32 pressure_min;
+ bool pressure;
+ struct iio_channel *iio_chans;
+ struct iio_cb_buffer *iio_cb;
+ struct input_dev *input;
+ struct touchscreen_properties prop;
+};
+
+static int grts_cb(const void *data, void *private)
+{
+ const u16 *touch_info = data;
+ struct grts_state *st = private;
+ unsigned int x, y, press = 0x0;
+
+ /* channel data coming in buffer in the order below */
+ x = touch_info[0];
+ y = touch_info[1];
+ if (st->pressure)
+ press = touch_info[2];
+
+ if ((!x && !y) || (st->pressure && (press < st->pressure_min))) {
+ /* report end of touch */
+ input_report_key(st->input, BTN_TOUCH, 0);
+ input_sync(st->input);
+ return 0;
+ }
+
+ /* report proper touch to subsystem*/
+ touchscreen_report_pos(st->input, &st->prop, x, y, false);
+ if (st->pressure)
+ input_report_abs(st->input, ABS_PRESSURE, press);
+ input_report_key(st->input, BTN_TOUCH, 1);
+ input_sync(st->input);
+
+ return 0;
+}
+
+static int grts_open(struct input_dev *dev)
+{
+ int error;
+ struct grts_state *st = input_get_drvdata(dev);
+
+ error = iio_channel_start_all_cb(st->iio_cb);
+ if (error) {
+ dev_err(dev->dev.parent, "failed to start callback buffer.\n");
+ return error;
+ }
+ return 0;
+}
+
+static void grts_close(struct input_dev *dev)
+{
+ struct grts_state *st = input_get_drvdata(dev);
+
+ iio_channel_stop_all_cb(st->iio_cb);
+}
+
+static void grts_disable(void *data)
+{
+ iio_channel_release_all_cb(data);
+}
+
+static int grts_probe(struct platform_device *pdev)
+{
+ struct grts_state *st;
+ struct input_dev *input;
+ struct device *dev = &pdev->dev;
+ struct iio_channel *chan;
+ int error;
+
+ st = devm_kzalloc(dev, sizeof(struct grts_state), GFP_KERNEL);
+ if (!st)
+ return -ENOMEM;
+
+ /* get the channels from IIO device */
+ st->iio_chans = devm_iio_channel_get_all(dev);
+ if (IS_ERR(st->iio_chans)) {
+ error = PTR_ERR(st->iio_chans);
+ if (error != -EPROBE_DEFER)
+ dev_err(dev, "can't get iio channels.\n");
+ return error;
+ }
+
+ chan = &st->iio_chans[0];
+ st->pressure = false;
+ while (chan && chan->indio_dev) {
+ if (!strcmp(chan->channel->datasheet_name, "pressure"))
+ st->pressure = true;
+ chan++;
+ }
+
+ if (st->pressure) {
+ error = device_property_read_u32(dev,
+ "touchscreen-min-pressure",
+ &st->pressure_min);
+ if (error) {
+ dev_dbg(dev, "can't get touchscreen-min-pressure property.\n");
+ st->pressure_min = GRTS_DEFAULT_PRESSURE_MIN;
+ }
+ }
+
+ input = devm_input_allocate_device(dev);
+ if (!input) {
+ dev_err(dev, "failed to allocate input device.\n");
+ return -ENOMEM;
+ }
+
+ input->name = DRIVER_NAME;
+ input->id.bustype = BUS_HOST;
+ input->open = grts_open;
+ input->close = grts_close;
+
+ input_set_abs_params(input, ABS_X, 0, GRTS_MAX_POS_MASK - 1, 0, 0);
+ input_set_abs_params(input, ABS_Y, 0, GRTS_MAX_POS_MASK - 1, 0, 0);
+ if (st->pressure)
+ input_set_abs_params(input, ABS_PRESSURE, st->pressure_min,
+ 0xffff, 0, 0);
+
+ input_set_capability(input, EV_KEY, BTN_TOUCH);
+
+ /* parse optional device tree properties */
+ touchscreen_parse_properties(input, false, &st->prop);
+
+ st->input = input;
+ input_set_drvdata(input, st);
+
+ error = input_register_device(input);
+ if (error) {
+ dev_err(dev, "failed to register input device.");
+ return error;
+ }
+
+ st->iio_cb = iio_channel_get_all_cb(dev, grts_cb, st);
+ if (IS_ERR(st->iio_cb)) {
+ dev_err(dev, "failed to allocate callback buffer.\n");
+ return PTR_ERR(st->iio_cb);
+ }
+
+ error = devm_add_action_or_reset(dev, grts_disable, st->iio_cb);
+ if (error) {
+ dev_err(dev, "failed to add disable action.\n");
+ return error;
+ }
+
+ return 0;
+}
+
+static const struct of_device_id grts_of_match[] = {
+ {
+ .compatible = "resistive-adc-touch",
+ }, {
+ /* sentinel */
+ },
+};
+
+MODULE_DEVICE_TABLE(of, grts_of_match);
+
+static struct platform_driver grts_driver = {
+ .probe = grts_probe,
+ .driver = {
+ .name = DRIVER_NAME,
+ .of_match_table = of_match_ptr(grts_of_match),
+ },
+};
+
+module_platform_driver(grts_driver);
+
+MODULE_AUTHOR("Eugen Hristev <eugen.hristev@microchip.com>");
+MODULE_DESCRIPTION("Generic ADC Resistive Touch Driver");
+MODULE_LICENSE("GPL v2");
--
2.7.4
^ permalink raw reply related
* [PATCH v7 5/9] iio: adc: at91-sama5d2_adc: add support for position and pressure channels
From: Eugen Hristev @ 2018-05-22 7:52 UTC (permalink / raw)
To: jic23, ludovic.desroches, alexandre.belloni, linux-arm-kernel,
devicetree, linux-kernel, linux-iio, linux-input, nicolas.ferre,
dmitry.torokhov, robh
Cc: Eugen Hristev
In-Reply-To: <1526975559-18966-1-git-send-email-eugen.hristev@microchip.com>
This implements the support for position and pressure for the included
touchscreen support in the SAMA5D2 SOC ADC block.
Two position channels are added and one for pressure.
They can be read in raw format, or through a buffer.
A normal use case is for a consumer driver to register a callback buffer
for these channels.
When the touchscreen channels are in the active scan mask,
the driver will start the touchscreen sampling and push the data to the
buffer.
Some parts of this patch are based on initial original work by
Mohamed Jamsheeth Hajanajubudeen and Bandaru Venkateswara Swamy
Signed-off-by: Eugen Hristev <eugen.hristev@microchip.com>
---
Changes in v6:
- fixed a crash when issuing buffer enable from sysfs, if no trigger was
previously configured. This is because now the driver can work in software
buffer mode (to connect the callback buffer). So, when trying to enable the
buffer, check if we are going indeed to a triggered mode or not. If not, do
not allow buffer to be started (we do not have the right trigger).
It's in buffer_postenable and predisable.
Changes in v4:
- use return value of at91_adc_configure_touch
- rewrote some part of the read_info_raw according to Jonathan's
suggestion
Changes in v3:
- prefix macros with AT91_SAMA5D2
- reworked the x_pos and y_pos functions into a single one with two
additional wrappers
- reworked pressure report to have it grow naturally and not top down
- fixed some checks regarding IIO_VOLTAGE as suggested
- added a comment explaining some code in trigger handling
- reworked the frequency get handler to use the saved value instead of
reading it from the hardware.
- added comment on deffered work queueing
- pulled out INFO_RAW function into a separate utility function as suggested
- added iio_dev ops structure at all times . The functions are needed in
case we do not have a hardware trigger attached, but we want to use the
consumer touchscreen driver, thus a callback buffer is attached. Then we still
need to have buffer preenable and postdisable to configure the touch IRQs (etc.)
Changes in v2:
- the support is now based on callback buffer.
drivers/iio/adc/at91-sama5d2_adc.c | 609 +++++++++++++++++++++++++++++++++----
1 file changed, 551 insertions(+), 58 deletions(-)
diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c
index 8729d65..58c4c2b 100644
--- a/drivers/iio/adc/at91-sama5d2_adc.c
+++ b/drivers/iio/adc/at91-sama5d2_adc.c
@@ -102,14 +102,26 @@
#define AT91_SAMA5D2_LCDR 0x20
/* Interrupt Enable Register */
#define AT91_SAMA5D2_IER 0x24
+/* Interrupt Enable Register - TS X measurement ready */
+#define AT91_SAMA5D2_IER_XRDY BIT(20)
+/* Interrupt Enable Register - TS Y measurement ready */
+#define AT91_SAMA5D2_IER_YRDY BIT(21)
+/* Interrupt Enable Register - TS pressure measurement ready */
+#define AT91_SAMA5D2_IER_PRDY BIT(22)
/* Interrupt Enable Register - general overrun error */
#define AT91_SAMA5D2_IER_GOVRE BIT(25)
+/* Interrupt Enable Register - Pen detect */
+#define AT91_SAMA5D2_IER_PEN BIT(29)
+/* Interrupt Enable Register - No pen detect */
+#define AT91_SAMA5D2_IER_NOPEN BIT(30)
/* Interrupt Disable Register */
#define AT91_SAMA5D2_IDR 0x28
/* Interrupt Mask Register */
#define AT91_SAMA5D2_IMR 0x2c
/* Interrupt Status Register */
#define AT91_SAMA5D2_ISR 0x30
+/* Interrupt Status Register - Pen touching sense status */
+#define AT91_SAMA5D2_ISR_PENS BIT(31)
/* Last Channel Trigger Mode Register */
#define AT91_SAMA5D2_LCTMR 0x34
/* Last Channel Compare Window Register */
@@ -131,8 +143,38 @@
#define AT91_SAMA5D2_CDR0 0x50
/* Analog Control Register */
#define AT91_SAMA5D2_ACR 0x94
+/* Analog Control Register - Pen detect sensitivity mask */
+#define AT91_SAMA5D2_ACR_PENDETSENS_MASK GENMASK(1, 0)
+
/* Touchscreen Mode Register */
#define AT91_SAMA5D2_TSMR 0xb0
+/* Touchscreen Mode Register - No touch mode */
+#define AT91_SAMA5D2_TSMR_TSMODE_NONE 0
+/* Touchscreen Mode Register - 4 wire screen, no pressure measurement */
+#define AT91_SAMA5D2_TSMR_TSMODE_4WIRE_NO_PRESS 1
+/* Touchscreen Mode Register - 4 wire screen, pressure measurement */
+#define AT91_SAMA5D2_TSMR_TSMODE_4WIRE_PRESS 2
+/* Touchscreen Mode Register - 5 wire screen */
+#define AT91_SAMA5D2_TSMR_TSMODE_5WIRE 3
+/* Touchscreen Mode Register - Average samples mask */
+#define AT91_SAMA5D2_TSMR_TSAV_MASK GENMASK(5, 4)
+/* Touchscreen Mode Register - Average samples */
+#define AT91_SAMA5D2_TSMR_TSAV(x) ((x) << 4)
+/* Touchscreen Mode Register - Touch/trigger frequency ratio mask */
+#define AT91_SAMA5D2_TSMR_TSFREQ_MASK GENMASK(11, 8)
+/* Touchscreen Mode Register - Touch/trigger frequency ratio */
+#define AT91_SAMA5D2_TSMR_TSFREQ(x) ((x) << 8)
+/* Touchscreen Mode Register - Pen Debounce Time mask */
+#define AT91_SAMA5D2_TSMR_PENDBC_MASK GENMASK(31, 28)
+/* Touchscreen Mode Register - Pen Debounce Time */
+#define AT91_SAMA5D2_TSMR_PENDBC(x) ((x) << 28)
+/* Touchscreen Mode Register - No DMA for touch measurements */
+#define AT91_SAMA5D2_TSMR_NOTSDMA BIT(22)
+/* Touchscreen Mode Register - Disable pen detection */
+#define AT91_SAMA5D2_TSMR_PENDET_DIS (0 << 24)
+/* Touchscreen Mode Register - Enable pen detection */
+#define AT91_SAMA5D2_TSMR_PENDET_ENA BIT(24)
+
/* Touchscreen X Position Register */
#define AT91_SAMA5D2_XPOSR 0xb4
/* Touchscreen Y Position Register */
@@ -151,6 +193,12 @@
#define AT91_SAMA5D2_TRGR_TRGMOD_EXT_TRIG_FALL 2
/* Trigger Mode external trigger any edge */
#define AT91_SAMA5D2_TRGR_TRGMOD_EXT_TRIG_ANY 3
+/* Trigger Mode internal periodic */
+#define AT91_SAMA5D2_TRGR_TRGMOD_PERIODIC 5
+/* Trigger Mode - trigger period mask */
+#define AT91_SAMA5D2_TRGR_TRGPER_MASK GENMASK(31, 16)
+/* Trigger Mode - trigger period */
+#define AT91_SAMA5D2_TRGR_TRGPER(x) ((x) << 16)
/* Correction Select Register */
#define AT91_SAMA5D2_COSR 0xd0
@@ -169,6 +217,22 @@
#define AT91_SAMA5D2_SINGLE_CHAN_CNT 12
#define AT91_SAMA5D2_DIFF_CHAN_CNT 6
+#define AT91_SAMA5D2_TIMESTAMP_CHAN_IDX (AT91_SAMA5D2_SINGLE_CHAN_CNT + \
+ AT91_SAMA5D2_DIFF_CHAN_CNT + 1)
+
+#define AT91_SAMA5D2_TOUCH_X_CHAN_IDX (AT91_SAMA5D2_SINGLE_CHAN_CNT + \
+ AT91_SAMA5D2_DIFF_CHAN_CNT * 2)
+#define AT91_SAMA5D2_TOUCH_Y_CHAN_IDX (AT91_SAMA5D2_TOUCH_X_CHAN_IDX + 1)
+#define AT91_SAMA5D2_TOUCH_P_CHAN_IDX (AT91_SAMA5D2_TOUCH_Y_CHAN_IDX + 1)
+#define AT91_SAMA5D2_MAX_CHAN_IDX AT91_SAMA5D2_TOUCH_P_CHAN_IDX
+
+#define AT91_SAMA5D2_TOUCH_SAMPLE_PERIOD_US 2000 /* 2ms */
+#define AT91_SAMA5D2_TOUCH_PEN_DETECT_DEBOUNCE_US 200
+
+#define AT91_SAMA5D2_XYZ_MASK GENMASK(11, 0)
+
+#define AT91_SAMA5D2_MAX_POS_BITS 12
+
/*
* Maximum number of bytes to hold conversion from all channels
* without the timestamp.
@@ -222,6 +286,37 @@
.indexed = 1, \
}
+#define AT91_SAMA5D2_CHAN_TOUCH(num, name, mod) \
+ { \
+ .type = IIO_POSITIONRELATIVE, \
+ .modified = 1, \
+ .channel = num, \
+ .channel2 = mod, \
+ .scan_index = num, \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = 12, \
+ .storagebits = 16, \
+ }, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\
+ .datasheet_name = name, \
+ }
+#define AT91_SAMA5D2_CHAN_PRESSURE(num, name) \
+ { \
+ .type = IIO_PRESSURE, \
+ .channel = num, \
+ .scan_index = num, \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = 12, \
+ .storagebits = 16, \
+ }, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\
+ .datasheet_name = name, \
+ }
+
#define at91_adc_readl(st, reg) readl_relaxed(st->base + reg)
#define at91_adc_writel(st, reg, val) writel_relaxed(val, st->base + reg)
@@ -260,6 +355,22 @@ struct at91_adc_dma {
s64 dma_ts;
};
+/**
+ * at91_adc_touch - at91-sama5d2 touchscreen information struct
+ * @sample_period_val: the value for periodic trigger interval
+ * @touching: is the pen touching the screen or not
+ * @x_pos: temporary placeholder for pressure computation
+ * @channels_bitmask: bitmask with the touchscreen channels enabled
+ * @workq: workqueue for buffer data pushing
+ */
+struct at91_adc_touch {
+ u16 sample_period_val;
+ bool touching;
+ u16 x_pos;
+ unsigned long channels_bitmask;
+ struct work_struct workq;
+};
+
struct at91_adc_state {
void __iomem *base;
int irq;
@@ -267,6 +378,7 @@ struct at91_adc_state {
struct regulator *reg;
struct regulator *vref;
int vref_uv;
+ unsigned int current_sample_rate;
struct iio_trigger *trig;
const struct at91_adc_trigger *selected_trig;
const struct iio_chan_spec *chan;
@@ -275,6 +387,7 @@ struct at91_adc_state {
struct at91_adc_soc_info soc_info;
wait_queue_head_t wq_data_available;
struct at91_adc_dma dma_st;
+ struct at91_adc_touch touch_st;
u16 buffer[AT91_BUFFER_MAX_HWORDS];
/*
* lock to prevent concurrent 'single conversion' requests through
@@ -329,8 +442,10 @@ static const struct iio_chan_spec at91_adc_channels[] = {
AT91_SAMA5D2_CHAN_DIFF(6, 7, 0x68),
AT91_SAMA5D2_CHAN_DIFF(8, 9, 0x70),
AT91_SAMA5D2_CHAN_DIFF(10, 11, 0x78),
- IIO_CHAN_SOFT_TIMESTAMP(AT91_SAMA5D2_SINGLE_CHAN_CNT
- + AT91_SAMA5D2_DIFF_CHAN_CNT + 1),
+ IIO_CHAN_SOFT_TIMESTAMP(AT91_SAMA5D2_TIMESTAMP_CHAN_IDX),
+ AT91_SAMA5D2_CHAN_TOUCH(AT91_SAMA5D2_TOUCH_X_CHAN_IDX, "x", IIO_MOD_X),
+ AT91_SAMA5D2_CHAN_TOUCH(AT91_SAMA5D2_TOUCH_Y_CHAN_IDX, "y", IIO_MOD_Y),
+ AT91_SAMA5D2_CHAN_PRESSURE(AT91_SAMA5D2_TOUCH_P_CHAN_IDX, "pressure"),
};
static int at91_adc_chan_xlate(struct iio_dev *indio_dev, int chan)
@@ -354,6 +469,160 @@ at91_adc_chan_get(struct iio_dev *indio_dev, int chan)
return indio_dev->channels + index;
}
+static inline int at91_adc_of_xlate(struct iio_dev *indio_dev,
+ const struct of_phandle_args *iiospec)
+{
+ return at91_adc_chan_xlate(indio_dev, iiospec->args[0]);
+}
+
+static int at91_adc_configure_touch(struct at91_adc_state *st, bool state)
+{
+ u32 clk_khz = st->current_sample_rate / 1000;
+ int i = 0;
+ u16 pendbc;
+ u32 tsmr, acr;
+
+ if (!state) {
+ /* disabling touch IRQs and setting mode to no touch enabled */
+ at91_adc_writel(st, AT91_SAMA5D2_IDR,
+ AT91_SAMA5D2_IER_PEN | AT91_SAMA5D2_IER_NOPEN);
+ at91_adc_writel(st, AT91_SAMA5D2_TSMR, 0);
+ return 0;
+ }
+ /*
+ * debounce time is in microseconds, we need it in milliseconds to
+ * multiply with kilohertz, so, divide by 1000, but after the multiply.
+ * round up to make sure pendbc is at least 1
+ */
+ pendbc = round_up(AT91_SAMA5D2_TOUCH_PEN_DETECT_DEBOUNCE_US *
+ clk_khz / 1000, 1);
+
+ /* get the required exponent */
+ while (pendbc >> i++)
+ ;
+
+ pendbc = i;
+
+ tsmr = AT91_SAMA5D2_TSMR_TSMODE_4WIRE_PRESS;
+
+ tsmr |= AT91_SAMA5D2_TSMR_TSAV(2) & AT91_SAMA5D2_TSMR_TSAV_MASK;
+ tsmr |= AT91_SAMA5D2_TSMR_PENDBC(pendbc) &
+ AT91_SAMA5D2_TSMR_PENDBC_MASK;
+ tsmr |= AT91_SAMA5D2_TSMR_NOTSDMA;
+ tsmr |= AT91_SAMA5D2_TSMR_PENDET_ENA;
+ tsmr |= AT91_SAMA5D2_TSMR_TSFREQ(2) & AT91_SAMA5D2_TSMR_TSFREQ_MASK;
+
+ at91_adc_writel(st, AT91_SAMA5D2_TSMR, tsmr);
+
+ acr = at91_adc_readl(st, AT91_SAMA5D2_ACR);
+ acr &= ~AT91_SAMA5D2_ACR_PENDETSENS_MASK;
+ acr |= 0x02 & AT91_SAMA5D2_ACR_PENDETSENS_MASK;
+ at91_adc_writel(st, AT91_SAMA5D2_ACR, acr);
+
+ /* Sample Period Time = (TRGPER + 1) / ADCClock */
+ st->touch_st.sample_period_val =
+ round_up((AT91_SAMA5D2_TOUCH_SAMPLE_PERIOD_US *
+ clk_khz / 1000) - 1, 1);
+ /* enable pen detect IRQ */
+ at91_adc_writel(st, AT91_SAMA5D2_IER, AT91_SAMA5D2_IER_PEN);
+
+ return 0;
+}
+
+static u16 at91_adc_touch_pos(struct at91_adc_state *st, int reg)
+{
+ u32 val;
+ u32 scale, result, pos;
+
+ /*
+ * to obtain the actual position we must divide by scale
+ * and multiply with max, where
+ * max = 2^AT91_SAMA5D2_MAX_POS_BITS - 1
+ */
+ /* first half of register is the x or y, second half is the scale */
+ val = at91_adc_readl(st, reg);
+ if (!val)
+ dev_dbg(&iio_priv_to_dev(st)->dev, "pos is 0\n");
+
+ pos = val & AT91_SAMA5D2_XYZ_MASK;
+ result = (pos << AT91_SAMA5D2_MAX_POS_BITS) - pos;
+ scale = (val >> 16) & AT91_SAMA5D2_XYZ_MASK;
+ if (scale == 0) {
+ dev_err(&iio_priv_to_dev(st)->dev, "scale is 0\n");
+ return 0;
+ }
+ result /= scale;
+
+ return result;
+}
+
+static u16 at91_adc_touch_x_pos(struct at91_adc_state *st)
+{
+ st->touch_st.x_pos = at91_adc_touch_pos(st, AT91_SAMA5D2_XPOSR);
+ return st->touch_st.x_pos;
+}
+
+static u16 at91_adc_touch_y_pos(struct at91_adc_state *st)
+{
+ return at91_adc_touch_pos(st, AT91_SAMA5D2_YPOSR);
+}
+
+static u16 at91_adc_touch_pressure(struct at91_adc_state *st)
+{
+ u32 val;
+ u32 z1, z2;
+ u32 pres;
+ u32 rxp = 1;
+ u32 factor = 1000;
+
+ /* calculate the pressure */
+ val = at91_adc_readl(st, AT91_SAMA5D2_PRESSR);
+ z1 = val & AT91_SAMA5D2_XYZ_MASK;
+ z2 = (val >> 16) & AT91_SAMA5D2_XYZ_MASK;
+
+ if (z1 != 0)
+ pres = rxp * (st->touch_st.x_pos * factor / 1024) *
+ (z2 * factor / z1 - factor) /
+ factor;
+ else
+ pres = 0xFFFF; /* no pen contact */
+
+ /*
+ * The pressure from device grows down, minimum is 0xFFFF, maximum 0x0.
+ * We compute it this way, but let's return it in the expected way,
+ * growing from 0 to 0xFFFF.
+ */
+ return 0xFFFF - pres;
+}
+
+static int at91_adc_read_position(struct at91_adc_state *st, int chan, u16 *val)
+{
+ *val = 0;
+ if (!st->touch_st.touching)
+ return -ENODATA;
+ if (chan == AT91_SAMA5D2_TOUCH_X_CHAN_IDX)
+ *val = at91_adc_touch_x_pos(st);
+ else if (chan == AT91_SAMA5D2_TOUCH_Y_CHAN_IDX)
+ *val = at91_adc_touch_y_pos(st);
+ else
+ return -ENODATA;
+
+ return IIO_VAL_INT;
+}
+
+static int at91_adc_read_pressure(struct at91_adc_state *st, int chan, u16 *val)
+{
+ *val = 0;
+ if (!st->touch_st.touching)
+ return -ENODATA;
+ if (chan == AT91_SAMA5D2_TOUCH_P_CHAN_IDX)
+ *val = at91_adc_touch_pressure(st);
+ else
+ return -ENODATA;
+
+ return IIO_VAL_INT;
+}
+
static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state)
{
struct iio_dev *indio = iio_trigger_get_drvdata(trig);
@@ -375,6 +644,11 @@ static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state)
if (!chan)
continue;
+ /* these channel types cannot be handled by this trigger */
+ if (chan->type == IIO_POSITIONRELATIVE ||
+ chan->type == IIO_PRESSURE)
+ continue;
+
if (state) {
at91_adc_writel(st, AT91_SAMA5D2_CHER,
BIT(chan->channel));
@@ -520,7 +794,20 @@ static int at91_adc_dma_start(struct iio_dev *indio_dev)
static int at91_adc_buffer_postenable(struct iio_dev *indio_dev)
{
int ret;
+ struct at91_adc_state *st = iio_priv(indio_dev);
+ /* check if we are enabling triggered buffer or the touchscreen */
+ if (bitmap_subset(indio_dev->active_scan_mask,
+ &st->touch_st.channels_bitmask,
+ AT91_SAMA5D2_MAX_CHAN_IDX + 1)) {
+ /* touchscreen enabling */
+ return at91_adc_configure_touch(st, true);
+ }
+ /* if we are not in triggered mode, we cannot enable the buffer. */
+ if (!(indio_dev->currentmode & INDIO_ALL_TRIGGERED_MODES))
+ return -EINVAL;
+
+ /* we continue with the triggered buffer */
ret = at91_adc_dma_start(indio_dev);
if (ret) {
dev_err(&indio_dev->dev, "buffer postenable failed\n");
@@ -536,6 +823,18 @@ static int at91_adc_buffer_predisable(struct iio_dev *indio_dev)
int ret;
u8 bit;
+ /* check if we are disabling triggered buffer or the touchscreen */
+ if (bitmap_subset(indio_dev->active_scan_mask,
+ &st->touch_st.channels_bitmask,
+ AT91_SAMA5D2_MAX_CHAN_IDX + 1)) {
+ /* touchscreen disable */
+ return at91_adc_configure_touch(st, false);
+ }
+ /* if we are not in triggered mode, nothing to do here */
+ if (!(indio_dev->currentmode & INDIO_ALL_TRIGGERED_MODES))
+ return -EINVAL;
+
+ /* continue with the triggered buffer */
ret = iio_triggered_buffer_predisable(indio_dev);
if (ret < 0)
dev_err(&indio_dev->dev, "buffer predisable failed\n");
@@ -558,6 +857,10 @@ static int at91_adc_buffer_predisable(struct iio_dev *indio_dev)
if (!chan)
continue;
+ /* these channel types are virtual, no need to do anything */
+ if (chan->type == IIO_POSITIONRELATIVE ||
+ chan->type == IIO_PRESSURE)
+ continue;
if (st->dma_st.dma_chan)
at91_adc_readl(st, chan->address);
}
@@ -622,7 +925,22 @@ static void at91_adc_trigger_handler_nodma(struct iio_dev *indio_dev,
if (!chan)
continue;
- st->buffer[i] = at91_adc_readl(st, chan->address);
+ /*
+ * Our external trigger only supports the voltage channels.
+ * In case someone requested a different type of channel
+ * just put zeroes to buffer.
+ * This should not happen because we check the scan mode
+ * and scan mask when we enable the buffer, and we don't allow
+ * the buffer to start with a mixed mask (voltage and something
+ * else).
+ * Thus, emit a warning.
+ */
+ if (chan->type == IIO_VOLTAGE) {
+ st->buffer[i] = at91_adc_readl(st, chan->address);
+ } else {
+ st->buffer[i] = 0;
+ WARN(true, "This trigger cannot handle this type of channel");
+ }
i++;
}
iio_push_to_buffers_with_timestamp(indio_dev, st->buffer,
@@ -688,9 +1006,20 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
static int at91_adc_buffer_init(struct iio_dev *indio)
{
- return devm_iio_triggered_buffer_setup(&indio->dev, indio,
+ struct at91_adc_state *st = iio_priv(indio);
+
+ if (st->selected_trig->hw_trig) {
+ return devm_iio_triggered_buffer_setup(&indio->dev, indio,
&iio_pollfunc_store_time,
&at91_adc_trigger_handler, &at91_buffer_setup_ops);
+ }
+ /*
+ * we need to prepare the buffer ops in case we will get
+ * another buffer attached (like a callback buffer for the touchscreen)
+ */
+ indio->setup_ops = &at91_buffer_setup_ops;
+
+ return 0;
}
static unsigned at91_adc_startup_time(unsigned startup_time_min,
@@ -736,19 +1065,83 @@ static void at91_adc_setup_samp_freq(struct at91_adc_state *st, unsigned freq)
dev_dbg(&indio_dev->dev, "freq: %u, startup: %u, prescal: %u\n",
freq, startup, prescal);
+ st->current_sample_rate = freq;
}
-static unsigned at91_adc_get_sample_freq(struct at91_adc_state *st)
+static inline unsigned at91_adc_get_sample_freq(struct at91_adc_state *st)
{
- unsigned f_adc, f_per = clk_get_rate(st->per_clk);
- unsigned mr, prescal;
+ return st->current_sample_rate;
+}
- mr = at91_adc_readl(st, AT91_SAMA5D2_MR);
- prescal = (mr >> AT91_SAMA5D2_MR_PRESCAL_OFFSET)
- & AT91_SAMA5D2_MR_PRESCAL_MAX;
- f_adc = f_per / (2 * (prescal + 1));
+static void at91_adc_touch_data_handler(struct iio_dev *indio_dev)
+{
+ struct at91_adc_state *st = iio_priv(indio_dev);
+ u8 bit;
+ u16 val;
+ int i = 0;
- return f_adc;
+ for_each_set_bit(bit, indio_dev->active_scan_mask,
+ AT91_SAMA5D2_MAX_CHAN_IDX + 1) {
+ struct iio_chan_spec const *chan =
+ at91_adc_chan_get(indio_dev, bit);
+
+ if (chan->type == IIO_POSITIONRELATIVE)
+ at91_adc_read_position(st, chan->channel, &val);
+ else if (chan->type == IIO_PRESSURE)
+ at91_adc_read_pressure(st, chan->channel, &val);
+ else
+ continue;
+ st->buffer[i] = val;
+ i++;
+ }
+ /*
+ * Schedule work to push to buffers.
+ * This is intended to push to the callback buffer that another driver
+ * registered. We are still in a handler from our IRQ. If we push
+ * directly, it means the other driver has it's callback called
+ * from our IRQ context. Which is something we better avoid.
+ * Let's schedule it after our IRQ is completed.
+ */
+ schedule_work(&st->touch_st.workq);
+}
+
+static void at91_adc_pen_detect_interrupt(struct at91_adc_state *st)
+{
+ at91_adc_writel(st, AT91_SAMA5D2_IDR, AT91_SAMA5D2_IER_PEN);
+ at91_adc_writel(st, AT91_SAMA5D2_IER, AT91_SAMA5D2_IER_NOPEN |
+ AT91_SAMA5D2_IER_XRDY | AT91_SAMA5D2_IER_YRDY |
+ AT91_SAMA5D2_IER_PRDY);
+ at91_adc_writel(st, AT91_SAMA5D2_TRGR,
+ AT91_SAMA5D2_TRGR_TRGMOD_PERIODIC |
+ AT91_SAMA5D2_TRGR_TRGPER(st->touch_st.sample_period_val));
+ st->touch_st.touching = true;
+}
+
+static void at91_adc_no_pen_detect_interrupt(struct at91_adc_state *st)
+{
+ struct iio_dev *indio_dev = iio_priv_to_dev(st);
+
+ at91_adc_writel(st, AT91_SAMA5D2_TRGR,
+ AT91_SAMA5D2_TRGR_TRGMOD_NO_TRIGGER);
+ at91_adc_writel(st, AT91_SAMA5D2_IDR, AT91_SAMA5D2_IER_NOPEN |
+ AT91_SAMA5D2_IER_XRDY | AT91_SAMA5D2_IER_YRDY |
+ AT91_SAMA5D2_IER_PRDY);
+ st->touch_st.touching = false;
+
+ at91_adc_touch_data_handler(indio_dev);
+
+ at91_adc_writel(st, AT91_SAMA5D2_IER, AT91_SAMA5D2_IER_PEN);
+}
+
+static void at91_adc_workq_handler(struct work_struct *workq)
+{
+ struct at91_adc_touch *touch_st = container_of(workq,
+ struct at91_adc_touch, workq);
+ struct at91_adc_state *st = container_of(touch_st,
+ struct at91_adc_state, touch_st);
+ struct iio_dev *indio_dev = iio_priv_to_dev(st);
+
+ iio_push_to_buffers(indio_dev, st->buffer);
}
static irqreturn_t at91_adc_interrupt(int irq, void *private)
@@ -757,17 +1150,39 @@ static irqreturn_t at91_adc_interrupt(int irq, void *private)
struct at91_adc_state *st = iio_priv(indio);
u32 status = at91_adc_readl(st, AT91_SAMA5D2_ISR);
u32 imr = at91_adc_readl(st, AT91_SAMA5D2_IMR);
+ u32 rdy_mask = AT91_SAMA5D2_IER_XRDY | AT91_SAMA5D2_IER_YRDY |
+ AT91_SAMA5D2_IER_PRDY;
if (!(status & imr))
return IRQ_NONE;
-
- if (iio_buffer_enabled(indio) && !st->dma_st.dma_chan) {
+ if (status & AT91_SAMA5D2_IER_PEN) {
+ /* pen detected IRQ */
+ at91_adc_pen_detect_interrupt(st);
+ } else if ((status & AT91_SAMA5D2_IER_NOPEN)) {
+ /* nopen detected IRQ */
+ at91_adc_no_pen_detect_interrupt(st);
+ } else if ((status & AT91_SAMA5D2_ISR_PENS) &&
+ ((status & rdy_mask) == rdy_mask)) {
+ /* periodic trigger IRQ - during pen sense */
+ at91_adc_touch_data_handler(indio);
+ } else if (status & AT91_SAMA5D2_ISR_PENS) {
+ /*
+ * touching, but the measurements are not ready yet.
+ * read and ignore.
+ */
+ status = at91_adc_readl(st, AT91_SAMA5D2_XPOSR);
+ status = at91_adc_readl(st, AT91_SAMA5D2_YPOSR);
+ status = at91_adc_readl(st, AT91_SAMA5D2_PRESSR);
+ } else if (iio_buffer_enabled(indio) && !st->dma_st.dma_chan) {
+ /* triggered buffer without DMA */
disable_irq_nosync(irq);
iio_trigger_poll(indio->trig);
} else if (iio_buffer_enabled(indio) && st->dma_st.dma_chan) {
+ /* triggered buffer with DMA - should not happen */
disable_irq_nosync(irq);
WARN(true, "Unexpected irq occurred\n");
} else if (!iio_buffer_enabled(indio)) {
+ /* software requested conversion */
st->conversion_value = at91_adc_readl(st, st->chan->address);
st->conversion_done = true;
wake_up_interruptible(&st->wq_data_available);
@@ -775,58 +1190,97 @@ static irqreturn_t at91_adc_interrupt(int irq, void *private)
return IRQ_HANDLED;
}
-static int at91_adc_read_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int *val, int *val2, long mask)
+static int at91_adc_read_info_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val)
{
struct at91_adc_state *st = iio_priv(indio_dev);
u32 cor = 0;
int ret;
- switch (mask) {
- case IIO_CHAN_INFO_RAW:
- /* we cannot use software trigger if hw trigger enabled */
+ /*
+ * Keep in mind that we cannot use software trigger or touchscreen
+ * if external trigger is enabled
+ */
+ if (chan->type == IIO_POSITIONRELATIVE) {
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
mutex_lock(&st->lock);
- st->chan = chan;
+ ret = at91_adc_read_position(st, chan->channel,
+ (u16 *)val);
+ mutex_unlock(&st->lock);
+ iio_device_release_direct_mode(indio_dev);
- if (chan->differential)
- cor = (BIT(chan->channel) | BIT(chan->channel2)) <<
- AT91_SAMA5D2_COR_DIFF_OFFSET;
-
- at91_adc_writel(st, AT91_SAMA5D2_COR, cor);
- at91_adc_writel(st, AT91_SAMA5D2_CHER, BIT(chan->channel));
- at91_adc_writel(st, AT91_SAMA5D2_IER, BIT(chan->channel));
- at91_adc_writel(st, AT91_SAMA5D2_CR, AT91_SAMA5D2_CR_START);
-
- ret = wait_event_interruptible_timeout(st->wq_data_available,
- st->conversion_done,
- msecs_to_jiffies(1000));
- if (ret == 0)
- ret = -ETIMEDOUT;
-
- if (ret > 0) {
- *val = st->conversion_value;
- if (chan->scan_type.sign == 's')
- *val = sign_extend32(*val, 11);
- ret = IIO_VAL_INT;
- st->conversion_done = false;
- }
+ return ret;
+ }
+ if (chan->type == IIO_PRESSURE) {
+ ret = iio_device_claim_direct_mode(indio_dev);
+ if (ret)
+ return ret;
+ mutex_lock(&st->lock);
- at91_adc_writel(st, AT91_SAMA5D2_IDR, BIT(chan->channel));
- at91_adc_writel(st, AT91_SAMA5D2_CHDR, BIT(chan->channel));
+ ret = at91_adc_read_pressure(st, chan->channel,
+ (u16 *)val);
+ mutex_unlock(&st->lock);
+ iio_device_release_direct_mode(indio_dev);
- /* Needed to ACK the DRDY interruption */
- at91_adc_readl(st, AT91_SAMA5D2_LCDR);
+ return ret;
+ }
- mutex_unlock(&st->lock);
+ /* in this case we have a voltage channel */
- iio_device_release_direct_mode(indio_dev);
+ ret = iio_device_claim_direct_mode(indio_dev);
+ if (ret)
return ret;
+ mutex_lock(&st->lock);
+
+ st->chan = chan;
+
+ if (chan->differential)
+ cor = (BIT(chan->channel) | BIT(chan->channel2)) <<
+ AT91_SAMA5D2_COR_DIFF_OFFSET;
+
+ at91_adc_writel(st, AT91_SAMA5D2_COR, cor);
+ at91_adc_writel(st, AT91_SAMA5D2_CHER, BIT(chan->channel));
+ at91_adc_writel(st, AT91_SAMA5D2_IER, BIT(chan->channel));
+ at91_adc_writel(st, AT91_SAMA5D2_CR, AT91_SAMA5D2_CR_START);
+
+ ret = wait_event_interruptible_timeout(st->wq_data_available,
+ st->conversion_done,
+ msecs_to_jiffies(1000));
+ if (ret == 0)
+ ret = -ETIMEDOUT;
+
+ if (ret > 0) {
+ *val = st->conversion_value;
+ if (chan->scan_type.sign == 's')
+ *val = sign_extend32(*val, 11);
+ ret = IIO_VAL_INT;
+ st->conversion_done = false;
+ }
+
+ at91_adc_writel(st, AT91_SAMA5D2_IDR, BIT(chan->channel));
+ at91_adc_writel(st, AT91_SAMA5D2_CHDR, BIT(chan->channel));
+
+ /* Needed to ACK the DRDY interruption */
+ at91_adc_readl(st, AT91_SAMA5D2_LCDR);
+
+ mutex_unlock(&st->lock);
+
+ iio_device_release_direct_mode(indio_dev);
+ return ret;
+}
+
+static int at91_adc_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct at91_adc_state *st = iio_priv(indio_dev);
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ return at91_adc_read_info_raw(indio_dev, chan, val);
case IIO_CHAN_INFO_SCALE:
*val = st->vref_uv / 1000;
if (chan->differential)
@@ -974,9 +1428,29 @@ static int at91_adc_set_watermark(struct iio_dev *indio_dev, unsigned int val)
return 0;
}
+static int at91_adc_update_scan_mode(struct iio_dev *indio_dev,
+ const unsigned long *scan_mask)
+{
+ struct at91_adc_state *st = iio_priv(indio_dev);
+
+ if (bitmap_subset(scan_mask, &st->touch_st.channels_bitmask,
+ AT91_SAMA5D2_MAX_CHAN_IDX + 1))
+ return 0;
+ /*
+ * if the new bitmap is a combination of touchscreen and regular
+ * channels, then we are not fine
+ */
+ if (bitmap_intersects(&st->touch_st.channels_bitmask, scan_mask,
+ AT91_SAMA5D2_MAX_CHAN_IDX + 1))
+ return -EINVAL;
+ return 0;
+}
+
static const struct iio_info at91_adc_info = {
.read_raw = &at91_adc_read_raw,
.write_raw = &at91_adc_write_raw,
+ .update_scan_mode = &at91_adc_update_scan_mode,
+ .of_xlate = &at91_adc_of_xlate,
.hwfifo_set_watermark = &at91_adc_set_watermark,
};
@@ -1044,13 +1518,20 @@ static int at91_adc_probe(struct platform_device *pdev)
indio_dev->dev.parent = &pdev->dev;
indio_dev->name = dev_name(&pdev->dev);
- indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
indio_dev->info = &at91_adc_info;
indio_dev->channels = at91_adc_channels;
indio_dev->num_channels = ARRAY_SIZE(at91_adc_channels);
st = iio_priv(indio_dev);
+ bitmap_set(&st->touch_st.channels_bitmask,
+ AT91_SAMA5D2_TOUCH_X_CHAN_IDX, 1);
+ bitmap_set(&st->touch_st.channels_bitmask,
+ AT91_SAMA5D2_TOUCH_Y_CHAN_IDX, 1);
+ bitmap_set(&st->touch_st.channels_bitmask,
+ AT91_SAMA5D2_TOUCH_P_CHAN_IDX, 1);
+
ret = of_property_read_u32(pdev->dev.of_node,
"atmel,min-sample-rate-hz",
&st->soc_info.min_sample_rate);
@@ -1100,6 +1581,7 @@ static int at91_adc_probe(struct platform_device *pdev)
init_waitqueue_head(&st->wq_data_available);
mutex_init(&st->lock);
+ INIT_WORK(&st->touch_st.workq, at91_adc_workq_handler);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
@@ -1159,13 +1641,13 @@ static int at91_adc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, indio_dev);
- if (st->selected_trig->hw_trig) {
- ret = at91_adc_buffer_init(indio_dev);
- if (ret < 0) {
- dev_err(&pdev->dev, "couldn't initialize the buffer.\n");
- goto per_clk_disable_unprepare;
- }
+ ret = at91_adc_buffer_init(indio_dev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "couldn't initialize the buffer.\n");
+ goto per_clk_disable_unprepare;
+ }
+ if (st->selected_trig->hw_trig) {
ret = at91_adc_trigger_init(indio_dev);
if (ret < 0) {
dev_err(&pdev->dev, "couldn't setup the triggers.\n");
@@ -1272,9 +1754,20 @@ static __maybe_unused int at91_adc_resume(struct device *dev)
at91_adc_hw_init(st);
/* reconfiguring trigger hardware state */
- if (iio_buffer_enabled(indio_dev))
- at91_adc_configure_trigger(st->trig, true);
+ if (!iio_buffer_enabled(indio_dev))
+ return 0;
+
+ /* check if we are enabling triggered buffer or the touchscreen */
+ if (bitmap_subset(indio_dev->active_scan_mask,
+ &st->touch_st.channels_bitmask,
+ AT91_SAMA5D2_MAX_CHAN_IDX + 1)) {
+ /* touchscreen enabling */
+ return at91_adc_configure_touch(st, true);
+ } else {
+ return at91_adc_configure_trigger(st->trig, true);
+ }
+ /* not needed but more explicit */
return 0;
vref_disable_resume:
--
2.7.4
^ permalink raw reply related
* [PATCH v7 4/9] dt-bindings: input: touchscreen: resistive-adc-touch: create bindings
From: Eugen Hristev @ 2018-05-22 7:52 UTC (permalink / raw)
To: jic23, ludovic.desroches, alexandre.belloni, linux-arm-kernel,
devicetree, linux-kernel, linux-iio, linux-input, nicolas.ferre,
dmitry.torokhov, robh
Cc: Eugen Hristev
In-Reply-To: <1526975559-18966-1-git-send-email-eugen.hristev@microchip.com>
Added bindings for generic resistive touchscreen ADC.
Signed-off-by: Eugen Hristev <eugen.hristev@microchip.com>
Reviewed-by: Rob Herring <robh@kernel.org>
---
Changes in v5:
- changed property name touchscreen-threshold-pressure to
touchscreen-min-pressure
Changes in v3:
- renamed file and compatible to exclude "generic" keyword
- removed the pressure threshold property, added it as a common
touchscreen property in the touchscreen common bindings in a separate
commit.
Changes in v2:
- modified bindings to have a generic resistive touchscreen adc driver
instead of specific architecture one.
.../input/touchscreen/resistive-adc-touch.txt | 30 ++++++++++++++++++++++
1 file changed, 30 insertions(+)
create mode 100644 Documentation/devicetree/bindings/input/touchscreen/resistive-adc-touch.txt
diff --git a/Documentation/devicetree/bindings/input/touchscreen/resistive-adc-touch.txt b/Documentation/devicetree/bindings/input/touchscreen/resistive-adc-touch.txt
new file mode 100644
index 0000000..51456c0
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/resistive-adc-touch.txt
@@ -0,0 +1,30 @@
+Generic resistive touchscreen ADC
+
+Required properties:
+
+ - compatible: must be "resistive-adc-touch"
+The device must be connected to an ADC device that provides channels for
+position measurement and optional pressure.
+Refer to ../iio/iio-bindings.txt for details
+ - iio-channels: must have at least two channels connected to an ADC device.
+These should correspond to the channels exposed by the ADC device and should
+have the right index as the ADC device registers them. These channels
+represent the relative position on the "x" and "y" axes.
+ - iio-channel-names: must have all the channels' names. Mandatory channels
+are "x" and "y".
+
+Optional properties:
+ - iio-channels: The third channel named "pressure" is optional and can be
+used if the ADC device also measures pressure besides position.
+If this channel is missing, pressure will be ignored and the touchscreen
+will only report position.
+ - iio-channel-names: optional channel named "pressure".
+
+Example:
+
+ resistive_touch: resistive_touch {
+ compatible = "resistive-adc-touch";
+ touchscreen-min-pressure = <50000>;
+ io-channels = <&adc 24>, <&adc 25>, <&adc 26>;
+ io-channel-names = "x", "y", "pressure";
+ };
--
2.7.4
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox