* Re: [PATCH 08/14] Input: elan_i2c - Replace devm_add_action() followed by failure action with devm_add_action_or_reset()
From: Dmitry Torokhov @ 2019-07-13 8:51 UTC (permalink / raw)
To: Fuqian Huang; +Cc: linux-input, linux-kernel
In-Reply-To: <20190708123332.11989-1-huangfq.daxian@gmail.com>
On Mon, Jul 08, 2019 at 08:33:32PM +0800, Fuqian Huang wrote:
> devm_add_action_or_reset() is introduced as a helper function which
> internally calls devm_add_action(). If devm_add_action() fails
> then it will execute the action mentioned and return the error code.
> This reduce source code size (avoid writing the action twice)
> and reduce the likelyhood of bugs.
>
> Signed-off-by: Fuqian Huang <huangfq.daxian@gmail.com>
> ---
> drivers/input/mouse/elan_i2c_core.c | 3 +--
> 1 file changed, 1 insertion(+), 2 deletions(-)
>
> diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c
> index 420efaab3860..a8d4f3bd09bf 100644
> --- a/drivers/input/mouse/elan_i2c_core.c
> +++ b/drivers/input/mouse/elan_i2c_core.c
> @@ -1234,9 +1234,8 @@ static int elan_probe(struct i2c_client *client,
> return error;
> }
>
> - error = devm_add_action(dev, elan_remove_sysfs_groups, data);
> + error = devm_add_action_or_reset(dev, elan_remove_sysfs_groups, data);
Actually, the driver should use devm_device_add_groups() and then we do
not need custom cleanup action, I posted a patch for that.
> if (error) {
> - elan_remove_sysfs_groups(data);
> dev_err(dev, "Failed to add sysfs cleanup action: %d\n",
> error);
> return error;
> --
> 2.11.0
>
Thanks.
--
Dmitry
^ permalink raw reply
* Re: [PATCH 10/14] Input: auo-pixcir-ts - Replace devm_add_action() followed by failure action with devm_add_action_or_reset()
From: Dmitry Torokhov @ 2019-07-13 8:49 UTC (permalink / raw)
To: Fuqian Huang; +Cc: linux-input, linux-kernel
In-Reply-To: <20190708123347.12081-1-huangfq.daxian@gmail.com>
On Mon, Jul 08, 2019 at 08:33:47PM +0800, Fuqian Huang wrote:
> devm_add_action_or_reset() is introduced as a helper function which
> internally calls devm_add_action(). If devm_add_action() fails
> then it will execute the action mentioned and return the error code.
> This reduce source code size (avoid writing the action twice)
> and reduce the likelyhood of bugs.
>
> Signed-off-by: Fuqian Huang <huangfq.daxian@gmail.com>
Applied, thank you.
> ---
> drivers/input/touchscreen/auo-pixcir-ts.c | 3 +--
> 1 file changed, 1 insertion(+), 2 deletions(-)
>
> diff --git a/drivers/input/touchscreen/auo-pixcir-ts.c b/drivers/input/touchscreen/auo-pixcir-ts.c
> index 8e48fbda487a..8e9f3b7b8180 100644
> --- a/drivers/input/touchscreen/auo-pixcir-ts.c
> +++ b/drivers/input/touchscreen/auo-pixcir-ts.c
> @@ -602,9 +602,8 @@ static int auo_pixcir_probe(struct i2c_client *client,
> return error;
> }
>
> - error = devm_add_action(&client->dev, auo_pixcir_reset, ts);
> + error = devm_add_action_or_reset(&client->dev, auo_pixcir_reset, ts);
> if (error) {
> - auo_pixcir_reset(ts);
> dev_err(&client->dev, "failed to register reset action, %d\n",
> error);
> return error;
> --
> 2.11.0
>
--
Dmitry
^ permalink raw reply
* [PATCH] Input: cyapa - switch to using devm_device_add_group
From: Dmitry Torokhov @ 2019-07-13 8:48 UTC (permalink / raw)
To: linux-input; +Cc: linux-kernel
Instead of installing custom devm cleanup action to remove attribute
groups on failure, let's use the dedicated devm API.
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
drivers/input/mouse/cyapa.c | 16 +---------------
1 file changed, 1 insertion(+), 15 deletions(-)
diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c
index dfd3873513e4..c675f156948b 100644
--- a/drivers/input/mouse/cyapa.c
+++ b/drivers/input/mouse/cyapa.c
@@ -1238,13 +1238,6 @@ static const struct attribute_group cyapa_sysfs_group = {
.attrs = cyapa_sysfs_entries,
};
-static void cyapa_remove_sysfs_group(void *data)
-{
- struct cyapa *cyapa = data;
-
- sysfs_remove_group(&cyapa->client->dev.kobj, &cyapa_sysfs_group);
-}
-
static void cyapa_disable_regulator(void *data)
{
struct cyapa *cyapa = data;
@@ -1312,19 +1305,12 @@ static int cyapa_probe(struct i2c_client *client,
return error;
}
- error = sysfs_create_group(&dev->kobj, &cyapa_sysfs_group);
+ error = devm_device_add_group(dev, &cyapa_sysfs_group);
if (error) {
dev_err(dev, "failed to create sysfs entries: %d\n", error);
return error;
}
- error = devm_add_action(dev, cyapa_remove_sysfs_group, cyapa);
- if (error) {
- cyapa_remove_sysfs_group(cyapa);
- dev_err(dev, "failed to add sysfs cleanup action: %d\n", error);
- return error;
- }
-
error = cyapa_prepare_wakeup_controls(cyapa);
if (error) {
dev_err(dev, "failed to prepare wakeup controls: %d\n", error);
--
2.22.0.510.g264f2c817a-goog
--
Dmitry
^ permalink raw reply related
* [PATCH] Input: elan_i2c - switch to using devm_add_action_or_reset()
From: Dmitry Torokhov @ 2019-07-13 8:47 UTC (permalink / raw)
To: linux-input; +Cc: Benjamin Tissoires, KT Liao, linux-kernel
Instead of manually disabling regulators when devm_add_action() fails we can
use devm_add_action_or_reset() which does it for us.
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
drivers/input/mouse/elan_i2c_core.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c
index b549d032da93..8719da540383 100644
--- a/drivers/input/mouse/elan_i2c_core.c
+++ b/drivers/input/mouse/elan_i2c_core.c
@@ -1187,9 +1187,8 @@ static int elan_probe(struct i2c_client *client,
return error;
}
- error = devm_add_action(dev, elan_disable_regulator, data);
+ error = devm_add_action_or_reset(dev, elan_disable_regulator, data);
if (error) {
- regulator_disable(data->vcc);
dev_err(dev, "Failed to add disable regulator action: %d\n",
error);
return error;
--
2.22.0.510.g264f2c817a-goog
--
Dmitry
^ permalink raw reply related
* [PATCH] Input: elan_i2c - switch to using devm_device_add_groups()
From: Dmitry Torokhov @ 2019-07-13 8:46 UTC (permalink / raw)
To: linux-input; +Cc: Benjamin Tissoires, KT Liao, linux-kernel
Instead of installing custom devm cleanup action to remove attribute
groups on failure, let's use the dedicated devm API.
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
drivers/input/mouse/elan_i2c_core.c | 17 +----------------
1 file changed, 1 insertion(+), 16 deletions(-)
diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c
index d9b103a81a79..b549d032da93 100644
--- a/drivers/input/mouse/elan_i2c_core.c
+++ b/drivers/input/mouse/elan_i2c_core.c
@@ -1138,13 +1138,6 @@ static void elan_disable_regulator(void *_data)
regulator_disable(data->vcc);
}
-static void elan_remove_sysfs_groups(void *_data)
-{
- struct elan_tp_data *data = _data;
-
- sysfs_remove_groups(&data->client->dev.kobj, elan_sysfs_groups);
-}
-
static int elan_probe(struct i2c_client *client,
const struct i2c_device_id *dev_id)
{
@@ -1269,20 +1262,12 @@ static int elan_probe(struct i2c_client *client,
return error;
}
- error = sysfs_create_groups(&dev->kobj, elan_sysfs_groups);
+ error = devm_device_add_groups(dev, elan_sysfs_groups);
if (error) {
dev_err(dev, "failed to create sysfs attributes: %d\n", error);
return error;
}
- error = devm_add_action(dev, elan_remove_sysfs_groups, data);
- if (error) {
- elan_remove_sysfs_groups(data);
- dev_err(dev, "Failed to add sysfs cleanup action: %d\n",
- error);
- return error;
- }
-
error = input_register_device(data->input);
if (error) {
dev_err(dev, "failed to register input device: %d\n", error);
--
2.22.0.510.g264f2c817a-goog
--
Dmitry
^ permalink raw reply related
* [PATCH v4 3/3] iio: Add PAT9125 optical tracker sensor
From: Alexandre Mergnat @ 2019-07-13 8:04 UTC (permalink / raw)
To: robh+dt, mark.rutland, jic23
Cc: linux-kernel, linux-iio, baylibre-upstreaming, dmitry.torokhov,
linux-input, devicetree, Alexandre Mergnat
In-Reply-To: <20190713080455.17513-1-amergnat@baylibre.com>
This adds support for PixArt Imaging’s miniature low power optical
navigation chip using LASER light source enabling digital surface tracking.
Features and datasheet: [0]
This IIO driver allows to read relative position from where the system
started on X and Y axis through two way:
- Punctual "read_raw" which will issue a read in the device registers to
get the delta between last/current read and return the addition of all
the deltas.
- Buffer read. Data can be retrieved using triggered buffer subscription
(i.e. iio_readdev). The buffer payload is:
|32 bits delta X|32 bits delta Y|timestamp|.
The possible I2C addresses are 0x73, 0x75 and 0x79.
X and Y axis CPI resolution can be get/set independently through IIO_SCALE.
The range value is 0-255 which means:
- 0 to ~1,275 Counts Per Inch on flat surface.
- 0 to ~630 Counts Per Rev on 1.0mm diameter STS shaft at 1.0mm distance.
More details on the datasheet.
The "position" directory is added to contain drivers which can provide
position data.
[0]: http://www.pixart.com/products-detail/72/PAT9125EL-TKIT___TKMT
Signed-off-by: Alexandre Mergnat <amergnat@baylibre.com>
---
drivers/iio/Kconfig | 1 +
drivers/iio/Makefile | 1 +
drivers/iio/position/Kconfig | 18 ++
drivers/iio/position/Makefile | 6 +
drivers/iio/position/pat9125.c | 506 +++++++++++++++++++++++++++++++++
5 files changed, 532 insertions(+)
create mode 100644 drivers/iio/position/Kconfig
create mode 100644 drivers/iio/position/Makefile
create mode 100644 drivers/iio/position/pat9125.c
diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
index 5bd51853b15e..aca6fcbceeab 100644
--- a/drivers/iio/Kconfig
+++ b/drivers/iio/Kconfig
@@ -85,6 +85,7 @@ source "drivers/iio/light/Kconfig"
source "drivers/iio/magnetometer/Kconfig"
source "drivers/iio/multiplexer/Kconfig"
source "drivers/iio/orientation/Kconfig"
+source "drivers/iio/position/Kconfig"
if IIO_TRIGGER
source "drivers/iio/trigger/Kconfig"
endif #IIO_TRIGGER
diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
index bff682ad1cfb..1712011c0f4a 100644
--- a/drivers/iio/Makefile
+++ b/drivers/iio/Makefile
@@ -31,6 +31,7 @@ obj-y += light/
obj-y += magnetometer/
obj-y += multiplexer/
obj-y += orientation/
+obj-y += position/
obj-y += potentiometer/
obj-y += potentiostat/
obj-y += pressure/
diff --git a/drivers/iio/position/Kconfig b/drivers/iio/position/Kconfig
new file mode 100644
index 000000000000..1cf28896511c
--- /dev/null
+++ b/drivers/iio/position/Kconfig
@@ -0,0 +1,18 @@
+#
+# Optical tracker sensors
+#
+# When adding new entries keep the list in alphabetical order
+
+menu "Optical tracker sensors"
+
+config PAT9125
+ tristate "Optical tracker PAT9125 I2C driver"
+ depends on I2C
+ select IIO_BUFFER
+ help
+ Say yes here to build support for PAT9125 optical tracker
+ sensors.
+
+ To compile this driver as a module, say M here: the module will
+ be called pat9125.
+endmenu
diff --git a/drivers/iio/position/Makefile b/drivers/iio/position/Makefile
new file mode 100644
index 000000000000..cf294917ae2c
--- /dev/null
+++ b/drivers/iio/position/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for industrial I/O Optical tracker sensor drivers
+#
+
+# When adding new entries keep the list in alphabetical order
+obj-$(CONFIG_PAT9125) += pat9125.o
diff --git a/drivers/iio/position/pat9125.c b/drivers/iio/position/pat9125.c
new file mode 100644
index 000000000000..2f04777e0790
--- /dev/null
+++ b/drivers/iio/position/pat9125.c
@@ -0,0 +1,506 @@
+// SPDX-License-Identifier: (GPL-2.0)
+/*
+ * Copyright (C) 2019 BayLibre, SAS
+ * Author: Alexandre Mergnat <amergnat@baylibre.com>
+ */
+
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+/* I2C Address function to ID pin*/
+#define PAT9125_I2C_ADDR_HI 0x73
+#define PAT9125_I2C_ADDR_LO 0x75
+#define PAT9125_I2C_ADDR_NC 0x79
+
+/* Registers */
+#define PAT9125_PRD_ID1_REG 0x00
+#define PAT9125_PRD_ID2_REG 0x01
+#define PAT9125_MOTION_STATUS_REG 0x02
+#define PAT9125_DELTA_X_LO_REG 0x03
+#define PAT9125_DELTA_Y_LO_REG 0x04
+#define PAT9125_OP_MODE_REG 0x05
+#define PAT9125_CONFIG_REG 0x06
+#define PAT9125_WRITE_PROTEC_REG 0x09
+#define PAT9125_SLEEP1_REG 0x0A
+#define PAT9125_SLEEP2_REG 0x0B
+#define PAT9125_RES_X_REG 0x0D
+#define PAT9125_RES_Y_REG 0x0E
+#define PAT9125_DELTA_XY_HI_REG 0x12
+#define PAT9125_SHUTER_REG 0x14
+#define PAT9125_FRAME_AVG_REG 0x17
+#define PAT9125_ORIENTATION_REG 0x19
+
+/* Bits */
+#define PAT9125_VALID_MOTION_DATA_BIT BIT(7)
+#define PAT9125_RESET_BIT BIT(7)
+
+/* Registers' values */
+#define PAT9125_SENSOR_ID_VAL 0x31
+#define PAT9125_DISABLE_WRITE_PROTECT_VAL 0x5A
+#define PAT9125_ENABLE_WRITE_PROTECT_VAL 0x00
+
+/* Default Value of sampled value size */
+#define PAT9125_SAMPLED_VAL_BIT_SIZE 12
+
+struct pat9125_data {
+ struct regmap *regmap;
+ struct iio_trigger *indio_trig; /* Motion detection */
+ s32 position_x;
+ s32 position_y;
+ bool sampling;
+};
+
+static const struct iio_chan_spec pat9125_channels[] = {
+ {
+ .type = IIO_DISTANCE,
+ .modified = 1,
+ .channel2 = IIO_MOD_X,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ .scan_index = 0,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 32,
+ .storagebits = 32,
+ .endianness = IIO_CPU,
+ },
+ },
+ {
+ .type = IIO_DISTANCE,
+ .modified = 1,
+ .channel2 = IIO_MOD_Y,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ .scan_index = 1,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 32,
+ .storagebits = 32,
+ .endianness = IIO_CPU,
+ },
+ },
+ IIO_CHAN_SOFT_TIMESTAMP(2),
+};
+
+/**
+ * pat9125_write_pretected_reg() - Write value in protected register.
+ *
+ * @regmap: Pointer to I2C register map.
+ * @reg_addr: Register address.
+ * @reg_value: Value to be write in register.
+ *
+ * A value of zero will be returned on success, a negative errno will
+ * be returned in error cases.
+ */
+static int pat9125_write_pretected_reg(struct iio_dev *indio_dev,
+ u8 reg_addr, u8 reg_value)
+{
+ struct pat9125_data *data = iio_priv(indio_dev);
+ int ret;
+
+ ret = regmap_write(data->regmap,
+ PAT9125_WRITE_PROTEC_REG,
+ PAT9125_DISABLE_WRITE_PROTECT_VAL);
+
+ if (!ret)
+ ret = regmap_write(data->regmap, reg_addr, reg_value);
+
+ /* Try to put back write protection everytime */
+ ret |= regmap_write(data->regmap,
+ PAT9125_WRITE_PROTEC_REG,
+ PAT9125_ENABLE_WRITE_PROTECT_VAL);
+
+ return ret;
+}
+/**
+ * pat9125_read_delta() - Read delta value, update delta & position data.
+ *
+ * @data: Driver's data structure.
+ *
+ * A value of zero will be returned on success, a negative errno will
+ * be returned in error cases.
+ */
+static int pat9125_read_delta(struct pat9125_data *data)
+{
+ struct regmap *regmap = data->regmap;
+ int status = 0;
+ int val_x = 0;
+ int val_y = 0;
+ int val_high_nibbles = 0;
+ int ret;
+
+ ret = regmap_read(regmap, PAT9125_MOTION_STATUS_REG, &status);
+ if (ret < 0)
+ return ret;
+
+ /* Check if motion is detected */
+ if (status & PAT9125_VALID_MOTION_DATA_BIT) {
+ ret = regmap_read(regmap, PAT9125_DELTA_X_LO_REG, &val_x);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_read(regmap, PAT9125_DELTA_Y_LO_REG, &val_y);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_read(regmap, PAT9125_DELTA_XY_HI_REG,
+ &val_high_nibbles);
+ if (ret < 0)
+ return ret;
+
+ val_x |= (val_high_nibbles << 4) & 0xF00;
+ val_y |= (val_high_nibbles << 8) & 0xF00;
+ val_x = sign_extend32(val_x,
+ PAT9125_SAMPLED_VAL_BIT_SIZE - 1);
+ val_y = sign_extend32(val_y,
+ PAT9125_SAMPLED_VAL_BIT_SIZE - 1);
+ data->position_x += val_x;
+ data->position_y += val_y;
+ }
+ return 0;
+}
+
+/**
+ * pat9125_read_raw() - Sample and return the value(s)
+ * function to the associated channel info enum.
+ *
+ * @indio_dev: Industrial I/O device.
+ * @chan: Specification of a single channel.
+ * @val: Contain the elements making up the returned value.
+ * @val2: Not used.
+ * @mask: (enum iio_chan_info_enum) Type of the info attribute.
+ *
+ * Zero will be returned on success, negative value otherwise.
+ **/
+static int pat9125_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct pat9125_data *data = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = pat9125_read_delta(data);
+ if (ret)
+ return ret;
+ switch (chan->channel2) {
+ case IIO_MOD_X:
+ *val = data->position_x;
+ return IIO_VAL_INT;
+ case IIO_MOD_Y:
+ *val = data->position_y;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->channel2) {
+ case IIO_MOD_X:
+ ret = regmap_read(data->regmap, PAT9125_RES_X_REG, val);
+ if (ret)
+ return ret;
+ else
+ return IIO_VAL_INT;
+ case IIO_MOD_Y:
+ ret = regmap_read(data->regmap, PAT9125_RES_Y_REG, val);
+ if (ret)
+ return ret;
+ else
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+/**
+ * pat9125_write_raw() - Write the value(s)
+ * function to the associated channel info enum.
+ *
+ * @indio_dev: Industrial I/O device.
+ * @chan: Specification of a single channel.
+ * @val: Value write in the channel.
+ * @val2: Not used.
+ * @mask: (enum iio_chan_info_enum) Type of the info attribute.
+ *
+ * Zero will be returned on success, negative value otherwise.
+ **/
+static int pat9125_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val,
+ int val2, long mask)
+{
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->channel2) {
+ case IIO_MOD_X:
+ ret = pat9125_write_pretected_reg(indio_dev,
+ PAT9125_RES_X_REG, val);
+ return ret;
+ case IIO_MOD_Y:
+ ret = pat9125_write_pretected_reg(indio_dev,
+ PAT9125_RES_Y_REG, val);
+ return ret;
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static irqreturn_t pat9125_threaded_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct pat9125_data *data = iio_priv(indio_dev);
+ u8 buf[16]; /* Payload: Pos_X (4) | Pos_Y (4) | Timestamp (8) */
+ int ret;
+ s64 timestamp;
+
+ data->sampling = true;
+ ret = pat9125_read_delta(data);
+ if (ret) {
+ dev_err(indio_dev->dev.parent, "Read delta failed %d\n", ret);
+ return IRQ_NONE;
+ }
+ timestamp = iio_get_time_ns(indio_dev);
+ *((s32 *)&buf[0]) = data->position_x;
+ *((s32 *)&buf[sizeof(s32)]) = data->position_y;
+ iio_push_to_buffers_with_timestamp(indio_dev, buf, timestamp);
+ iio_trigger_notify_done(indio_dev->trig);
+ return IRQ_HANDLED;
+}
+
+/**
+ * pat9125_threaded_event_handler() - Threaded motion detection event handler
+ * @irq: The irq being handled.
+ * @private: struct iio_device pointer for the device.
+ */
+static irqreturn_t pat9125_threaded_event_handler(int irq, void *private)
+{
+ struct iio_dev *indio_dev = private;
+ struct pat9125_data *data = iio_priv(indio_dev);
+
+ iio_trigger_poll_chained(data->indio_trig);
+ return IRQ_HANDLED;
+}
+
+/**
+ * pat9125_buffer_postenable() - Buffer post enable actions
+ *
+ * @indio_dev: Industrial I/O device.
+ */
+static int pat9125_buffer_postenable(struct iio_dev *indio_dev)
+{
+ struct pat9125_data *data = iio_priv(indio_dev);
+ int ret = 0;
+
+ ret = iio_triggered_buffer_postenable(indio_dev);
+ if (ret)
+ return ret;
+
+ /* Release interrupt pin on the device */
+ ret = pat9125_read_delta(data);
+
+ /* iio_trigger_detach_poll_func isn't reachable, so use this function */
+ if (ret)
+ ret = iio_triggered_buffer_predisable(indio_dev);
+
+ return ret;
+}
+
+static const struct iio_buffer_setup_ops pat9125_buffer_ops = {
+ .postenable = pat9125_buffer_postenable,
+};
+
+static const struct regmap_config pat9125_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+};
+
+static const struct iio_info pat9125_info = {
+ .read_raw = pat9125_read_raw,
+ .write_raw = pat9125_write_raw,
+};
+
+/*
+ * To detect if a new value is available, register status is checked. This
+ * method is safer than using a flag on GPIO IRQ to track event while sampling
+ * because falling edge is missed when device trig just after a read reg value
+ * (that happen for fast motions or high CPI setting).
+ *
+ * Note: To avoid infinite loop in "iio_trigger_notify_done" when it is not in
+ * buffer mode and kernel warning due to nested IRQ thread,
+ * this function must return 0.
+ */
+static int pat9125_trig_try_reenable(struct iio_trigger *trig)
+{
+ struct pat9125_data *data = iio_trigger_get_drvdata(trig);
+ struct regmap *regmap = data->regmap;
+ int status = 0;
+
+ if (data->sampling) {
+ regmap_read(regmap, PAT9125_MOTION_STATUS_REG, &status);
+ if (status & PAT9125_VALID_MOTION_DATA_BIT) {
+ data->sampling = false;
+ iio_trigger_poll_chained(data->indio_trig);
+ return 0;
+ }
+ }
+ data->sampling = false;
+ return 0;
+}
+
+static const struct iio_trigger_ops pat9125_trigger_ops = {
+ .try_reenable = pat9125_trig_try_reenable,
+};
+
+static int pat9125_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct pat9125_data *data;
+ struct iio_dev *indio_dev;
+ int ret, sensor_pid;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ if (!indio_dev) {
+ dev_err(&client->dev, "IIO device allocation failed\n");
+ return -ENOMEM;
+ }
+
+ data = iio_priv(indio_dev);
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->name = id->name;
+ indio_dev->channels = pat9125_channels;
+ indio_dev->num_channels = ARRAY_SIZE(pat9125_channels);
+ indio_dev->info = &pat9125_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev, NULL,
+ pat9125_threaded_trigger_handler, &pat9125_buffer_ops);
+ if (ret) {
+ dev_err(&client->dev, "unable to setup triggered buffer\n");
+ return ret;
+ }
+
+ data->indio_trig = devm_iio_trigger_alloc(&client->dev, "%s-dev%d",
+ indio_dev->name, indio_dev->id);
+ if (!data->indio_trig)
+ return -ENOMEM;
+ data->indio_trig->dev.parent = &client->dev;
+ data->indio_trig->ops = &pat9125_trigger_ops;
+ iio_trigger_set_drvdata(data->indio_trig, data);
+ ret = devm_iio_trigger_register(&client->dev, data->indio_trig);
+ if (ret) {
+ dev_err(&client->dev, "unable to register trigger\n");
+ return ret;
+ }
+
+ data->regmap = devm_regmap_init_i2c(client, &pat9125_regmap_config);
+ if (IS_ERR(data->regmap)) {
+ dev_err(&client->dev, "regmap init failed %ld\n",
+ PTR_ERR(data->regmap));
+ return PTR_ERR(data->regmap);
+ }
+
+ /* Check device ID */
+ ret = regmap_read(data->regmap, PAT9125_PRD_ID1_REG, &sensor_pid);
+ if (ret < 0) {
+ dev_err(&client->dev, "register 0x%x access failed %d\n",
+ PAT9125_PRD_ID1_REG, ret);
+ return ret;
+ }
+ if (sensor_pid != PAT9125_SENSOR_ID_VAL)
+ return -ENODEV;
+
+ /* Switch to bank0 (Magic number)*/
+ ret = regmap_write(data->regmap, 0x7F, 0x00);
+ if (ret < 0) {
+ dev_err(indio_dev->dev.parent, "register 0x%x access failed %d\n",
+ 0x7F, ret);
+ return ret;
+ }
+
+ /* Software reset */
+ ret = regmap_write_bits(data->regmap,
+ PAT9125_CONFIG_REG,
+ PAT9125_RESET_BIT,
+ 1);
+ if (ret < 0) {
+ dev_err(&client->dev, "register 0x%x access failed %d\n",
+ PAT9125_CONFIG_REG, ret);
+ return ret;
+ }
+
+ msleep(20);
+
+ /* Init GPIO IRQ */
+ if (client->irq) {
+ ret = devm_request_threaded_irq(&client->dev,
+ client->irq,
+ NULL,
+ pat9125_threaded_event_handler,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ "pat9125",
+ indio_dev);
+ if (ret) {
+ dev_err(&client->dev, "GPIO IRQ init failed\n");
+ return ret;
+ }
+ }
+
+ ret = devm_iio_device_register(&client->dev, indio_dev);
+ if (ret) {
+ dev_err(&client->dev, "IIO device register failed\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct i2c_device_id pat9125_id[] = {
+ { "pat9125", 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, pat9125_id);
+
+static const unsigned short normal_i2c[] = {
+ PAT9125_I2C_ADDR_HI,
+ PAT9125_I2C_ADDR_LO,
+ PAT9125_I2C_ADDR_NC,
+ I2C_CLIENT_END
+};
+
+static struct i2c_driver pat9125_driver = {
+ .driver = {
+ .name = "pat9125",
+ },
+ .probe = pat9125_probe,
+ .address_list = normal_i2c,
+ .id_table = pat9125_id,
+};
+
+module_i2c_driver(pat9125_driver);
+
+MODULE_AUTHOR("Alexandre Mergnat <amergnat@baylibre.com>");
+MODULE_DESCRIPTION("Optical Tracking sensor");
+MODULE_LICENSE("GPL");
--
2.17.1
^ permalink raw reply related
* [PATCH v4 2/3] dt-bindings: iio: position: Add docs pat9125
From: Alexandre Mergnat @ 2019-07-13 8:04 UTC (permalink / raw)
To: robh+dt, mark.rutland, jic23
Cc: linux-kernel, linux-iio, baylibre-upstreaming, dmitry.torokhov,
linux-input, devicetree, Alexandre Mergnat
In-Reply-To: <20190713080455.17513-1-amergnat@baylibre.com>
Add documentation for the optical tracker PAT9125 and
"position" directory for chip which can provides position data.
Signed-off-by: Alexandre Mergnat <amergnat@baylibre.com>
---
.../bindings/iio/position/pat9125.txt | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
create mode 100644 Documentation/devicetree/bindings/iio/position/pat9125.txt
diff --git a/Documentation/devicetree/bindings/iio/position/pat9125.txt b/Documentation/devicetree/bindings/iio/position/pat9125.txt
new file mode 100644
index 000000000000..4028aeef9b42
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/position/pat9125.txt
@@ -0,0 +1,18 @@
+PixArt Imaging PAT9125 Optical Tracking Miniature Chip device driver
+
+Required properties:
+ - compatible: must be "pixart,pat9125"
+ - reg: i2c address where to find the device
+ - interrupts: the sole interrupt generated by the device
+
+ Refer to interrupt-controller/interrupts.txt for generic
+ interrupt client node bindings.
+
+Example:
+
+pat9125@75 {
+ compatible = "pixart,pat9125";
+ reg = <0x75>;
+ interrupt-parent = <&gpio3>;
+ interrupts = <12 IRQ_TYPE_EDGE_FALLING>;
+};
--
2.17.1
^ permalink raw reply related
* [PATCH v4 1/3] dt-bindings: Add pixart vendor
From: Alexandre Mergnat @ 2019-07-13 8:04 UTC (permalink / raw)
To: robh+dt, mark.rutland, jic23
Cc: linux-kernel, linux-iio, baylibre-upstreaming, dmitry.torokhov,
linux-input, devicetree, Alexandre Mergnat
In-Reply-To: <20190713080455.17513-1-amergnat@baylibre.com>
PixArt Imaging Inc. is expertized in CMOS image sensors (CIS),
capacitive touch controllers and related imaging application development.
Signed-off-by: Alexandre Mergnat <amergnat@baylibre.com>
---
Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index 18b79c4cf7d5..120529f40c7c 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -705,6 +705,8 @@ patternProperties:
description: Pine64
"^pineriver,.*":
description: Shenzhen PineRiver Designs Co., Ltd.
+ "^pixart,.*":
+ description: PixArt Imaging Inc.
"^pixcir,.*":
description: PIXCIR MICROELECTRONICS Co., Ltd
"^plantower,.*":
--
2.17.1
^ permalink raw reply related
* [PATCH v4 0/3] Add PAT9125 optical tracker driver
From: Alexandre Mergnat @ 2019-07-13 8:04 UTC (permalink / raw)
To: robh+dt, mark.rutland, jic23
Cc: linux-kernel, linux-iio, baylibre-upstreaming, dmitry.torokhov,
linux-input, devicetree, Alexandre Mergnat
PixArt Imaging PAT9125 is a miniature low power optical navigation chip
using LASER light source enabling digital surface tracking.
This device driver use IIO API to provide punctual and/or buffered data.
The data is a relative position from where start the device on X and Y
axis, depend on CPI (Counts Per Inch) resolution setting chosen.
The device support CPI configuration through IIO interface.
This patchset :
- Update vendor prefix
- Add the bindings for this device
- Add the device driver
- Add directory for optical tracker devices
Change since v3:
- Replace delta value by relative position
- Improve write protected reg function by removing print log and obvious
returns
- Handle error in postenable buffer function
Change since v2:
- Fix typo
- Add constructor webpage and datasheet in commit message
- Use BIT() macro for define bit mask
- Remove shift from IIO channel spec structure
- Replace IIO_LE by IIO_CPU from IIO channel spec structure
- Replace memcpy() by cast (s32)
- Rename "pat9125_trig_try_reen" to "pat9125_trig_try_reenable"
- Add carriage return (\n) at the end of each "dev_err" function
- Remove "iio_trigger_unregister" in case of "iio_trigger_register" fail,
register function already manage it
- Remove log which print device name in case of successful initialization
- Fix enabled IRQ flag warning during nested IRQ thread
- Improve retry algo now based on status register
- Remove "ts", "motion_detected" and "buffer_mode" from pat9125_data
structure
- Rename all "ot" directories to "position"
- Polling sample through IIO_CHAN_INFO_RAW now return position value
(relative to the position at initialization time) instead of delta
position
- Clean iio_buffer_setup_ops structure by removing NULL pointer.
- Use devm_iio_ function for all init functions and then delete
"pat9125_remove"
- Move device_register at the end of probe function
- Replace MODULE_PARM_DESC by IIO_SCALE to set axis resolution (CPI)
Change since v1:
- Fix typo
- Rename some defines / variables
- Remove I2C client from driver structure
- Change type of delta_x and delta_y from s16 to s32 to simplify signed
operations
- Add module parameter for axis resolution
- Replace "IIO_MOD_X_AND_Y" by "IIO_MOD_X" and "IIO_MOD_Y"
- Add sign extension macro
- Improve read value algorithm to avoid data loss
- Implement a trigger handler function which can work with any IIO
trigger, independently of it own GPIO IRQ, to match with IIO
requirement/behaviour
- Replace iio push event function by iio trigger poll in GPIO IRQ handler
- Use triggered_buffer helpers to replace kfifo use, setup buffer,
implement enable/disable setup buffer operations, IIO trigger
allocation and re-enable operations
- Remove useless "goto"
- Change GPIO IRQ handler from planified thread to IRQ thread
- Change GPIO IRQ trigger from low level and one shot to falling edge
- Add device unregister and buffer cleanup to driver remove function
Alexandre Mergnat (3):
dt-bindings: Add pixart vendor
dt-bindings: iio: position: Add docs pat9125
iio: Add PAT9125 optical tracker sensor
.../bindings/iio/position/pat9125.txt | 18 +
.../devicetree/bindings/vendor-prefixes.yaml | 2 +
drivers/iio/Kconfig | 1 +
drivers/iio/Makefile | 1 +
drivers/iio/position/Kconfig | 18 +
drivers/iio/position/Makefile | 6 +
drivers/iio/position/pat9125.c | 506 ++++++++++++++++++
7 files changed, 552 insertions(+)
create mode 100644 Documentation/devicetree/bindings/iio/position/pat9125.txt
create mode 100644 drivers/iio/position/Kconfig
create mode 100644 drivers/iio/position/Makefile
create mode 100644 drivers/iio/position/pat9125.c
--
2.17.1
^ permalink raw reply
* Re: [PATCH] Input: gtco - bounds check collection indent level
From: Dmitry Torokhov @ 2019-07-13 8:02 UTC (permalink / raw)
To: Grant Hernandez; +Cc: linux-input, linux-usb, stable
In-Reply-To: <20190711222232.77701-1-granthernandez@google.com>
On Thu, Jul 11, 2019 at 03:22:32PM -0700, Grant Hernandez wrote:
> The GTCO tablet input driver configures itself from an HID report sent
> via USB during the initial enumeration process. Some debugging messages
> are generated during the parsing. A debugging message indentation
> counter is not bounds checked, leading to the ability for a specially
> crafted HID report to cause '-' and null bytes be written past the end
> of the indentation array. As long as the kernel has CONFIG_DYNAMIC_DEBUG
> enabled, this code will not be optimized out. This was discovered
> during code review after a previous syzkaller bug was found in this
> driver.
>
> Cc: stable@vger.kernel.org
> Signed-off-by: Grant Hernandez <granthernandez@google.com>
I wish we could convert gtco to be proper HID driver, so we woudl not
have to deal with custom HID parsing, but in the meantime this is
needed.
Applied, thank you.
--
Dmitry
^ permalink raw reply
* Re: [PATCH] input: API for Setting a Timestamp from a Driver
From: Dmitry Torokhov @ 2019-07-13 7:59 UTC (permalink / raw)
To: Peter Hutterer
Cc: Benjamin Tissoires, Atif Niyaz, Atif Niyaz, Siarhei Vishniakou,
open list:HID CORE LAYER, lkml
In-Reply-To: <20190712114619.GA7753@jelly>
On Fri, Jul 12, 2019 at 09:46:19PM +1000, Peter Hutterer wrote:
> On Fri, Jul 12, 2019 at 09:23:20AM +0200, Benjamin Tissoires wrote:
> > On Fri, Jul 12, 2019 at 8:41 AM Dmitry Torokhov
> > <dmitry.torokhov@gmail.com> wrote:
> > >
> > > Hi Atif,
> > >
> > > On Wed, Jul 10, 2019 at 04:04:10PM -0700, Atif Niyaz wrote:
> > > > Currently, evdev stamps time with timestamps acquired in
> > > > evdev_events. However, this timestamping may not be accurate in terms of
> > > > measuring when the actual event happened. This API allows any 3rd party
> > > > driver to be able to call input_set_timestamp, and provide a timestamp
> > > > that can be utilized in order to provide a more accurate sense of time
> > > > for the event
> > > >
> > > > Signed-off-by: Atif Niyaz <atifniyaz@google.com>
> > >
> > > This looks OK to me. Benjamin, Peter, any concerns here?
> > >
> >
> > No red flags from me (though Peter is the one using all of this).
> >
> > Just curious, which drivers do you think will be using this new API?
> > I can see that we might want to use hid-multitouch for it, with the
> > Scan Time forwarded by the device, but what do you have in mind?
>
> that'd be my question as well. I'm all for more precise evdev timestamps but
> there's some overlap with MSC_TIMESTAMP (which at least libinput isn't
> handling well right now, with the exception of some quirk detection).
I expect it will be used by drivers that use threaded interrupts to mark
the time in the hard interrupt and avoid the latency of scheduling the
thread, slow bus communication, etc.
This is not supposed to replace MSC_TIMESTAMP as MSC_TIMESTAMP carries
timestamp acquired by the device itself.
Thanks.
--
Dmitry
^ permalink raw reply
* [PATCH 2/2] gpiolib: add support for fetching descriptors from static properties
From: Dmitry Torokhov @ 2019-07-13 7:52 UTC (permalink / raw)
To: Linus Walleij, Rafael J . Wysocki,
Enrico Weigelt, metux IT consult
Cc: linux-input, linux-gpio, linux-kernel, Andy Shevchenko,
Heikki Krogerus
In-Reply-To: <20190713075259.243565-1-dmitry.torokhov@gmail.com>
Now that static device properties understand notion of child nodes, let's
teach gpiolib to tie such children and machine GPIO descriptor tables.
We will continue using a single table for entire device, but instead of
using connection ID as a lookup key in the GPIO descriptor table directly,
we will perform additional translation: fwnode_get_named_gpiod() when
dealing with property_set-backed fwnodes will try parsing string property
with name matching connection ID and use result of the lookup as the key in
the table:
static const struct property_entry dev_child1_props[] __initconst = {
...
PROPERTY_ENTRY_STRING("gpios", "child-1-gpios"),
{ }
};
static struct gpiod_lookup_table dev_gpiod_table = {
.dev_id = "some-device",
.table = {
...
GPIO_LOOKUP_IDX("B", 1, "child-1-gpios", 1, GPIO_ACTIVE_LOW),
...
},
};
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
drivers/gpio/gpiolib.c | 108 ++++++++++++++++++++++++++++++-----------
1 file changed, 79 insertions(+), 29 deletions(-)
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index e013d417a936..b6574febe2b8 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -4307,39 +4307,44 @@ struct gpio_desc *gpiod_get_from_of_node(struct device_node *node,
}
EXPORT_SYMBOL(gpiod_get_from_of_node);
-/**
- * fwnode_get_named_gpiod - obtain a GPIO from firmware node
- * @fwnode: handle of the firmware node
- * @propname: name of the firmware property representing the GPIO
- * @index: index of the GPIO to obtain for the consumer
- * @dflags: GPIO initialization flags
- * @label: label to attach to the requested GPIO
- *
- * This function can be used for drivers that get their configuration
- * from opaque firmware.
- *
- * The function properly finds the corresponding GPIO using whatever is the
- * underlying firmware interface and then makes sure that the GPIO
- * descriptor is requested before it is returned to the caller.
- *
- * Returns:
- * On successful request the GPIO pin is configured in accordance with
- * provided @dflags.
- *
- * In case of error an ERR_PTR() is returned.
- */
-struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
- const char *propname, int index,
- enum gpiod_flags dflags,
- const char *label)
+static struct gpio_desc *
+software_node_get_gpiod(struct fwnode_handle *fwnode,
+ const char *propname, int index, unsigned long *flags)
+{
+ struct device *dev;
+ const char *con_id;
+
+ dev = software_node_get_linked_device(fwnode);
+ if (IS_ERR_OR_NULL(dev))
+ return ERR_PTR(-EINVAL);
+
+ if (fwnode_property_read_string(fwnode, propname, &con_id)) {
+ /*
+ * We could not find string mapping property name to
+ * entry in gpio lookup table. Let's see if we are
+ * dealing with firmware node corresponding to the
+ * device (and not a child node): for such nodes we can
+ * try doing lookup directly with property name.
+ */
+ if (fwnode_get_parent(fwnode))
+ return ERR_PTR(-ENOENT);
+
+ con_id = propname;
+ }
+
+ return gpiod_find(dev, con_id, index, flags);
+}
+
+static struct gpio_desc *__fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
+ const char *propname,
+ int index,
+ enum gpiod_flags dflags,
+ const char *label)
{
unsigned long lflags = GPIO_LOOKUP_FLAGS_DEFAULT;
struct gpio_desc *desc = ERR_PTR(-ENODEV);
int ret;
- if (!fwnode)
- return ERR_PTR(-EINVAL);
-
if (is_of_node(fwnode)) {
desc = gpiod_get_from_of_node(to_of_node(fwnode),
propname, index,
@@ -4355,9 +4360,13 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
acpi_gpio_update_gpiod_flags(&dflags, &info);
acpi_gpio_update_gpiod_lookup_flags(&lflags, &info);
+ } else if (is_software_node(fwnode)) {
+ desc = software_node_get_gpiod(fwnode, propname, index,
+ &lflags);
+ if (IS_ERR(desc))
+ return desc;
}
- /* Currently only ACPI takes this path */
ret = gpiod_request(desc, label);
if (ret)
return ERR_PTR(ret);
@@ -4370,6 +4379,47 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
return desc;
}
+
+/**
+ * fwnode_get_named_gpiod - obtain a GPIO from firmware node
+ * @fwnode: handle of the firmware node
+ * @propname: name of the firmware property representing the GPIO
+ * @index: index of the GPIO to obtain for the consumer
+ * @dflags: GPIO initialization flags
+ * @label: label to attach to the requested GPIO
+ *
+ * This function can be used for drivers that get their configuration
+ * from opaque firmware.
+ *
+ * The function properly finds the corresponding GPIO using whatever is the
+ * underlying firmware interface and then makes sure that the GPIO
+ * descriptor is requested before it is returned to the caller.
+ *
+ * Returns:
+ * On successful request the GPIO pin is configured in accordance with
+ * provided @dflags.
+ *
+ * In case of error an ERR_PTR() is returned.
+ */
+struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
+ const char *propname, int index,
+ enum gpiod_flags dflags,
+ const char *label)
+{
+ struct gpio_desc *desc;
+
+ if (!fwnode)
+ return ERR_PTR(-EINVAL);
+
+ desc = __fwnode_get_named_gpiod(fwnode, propname, index, dflags, label);
+ if (IS_ERR(desc) && PTR_ERR(desc) == -ENOENT &&
+ !IS_ERR_OR_NULL(fwnode->secondary)) {
+ desc = __fwnode_get_named_gpiod(fwnode->secondary,
+ propname, index, dflags, label);
+ }
+
+ return desc;
+}
EXPORT_SYMBOL_GPL(fwnode_get_named_gpiod);
/**
--
2.22.0.510.g264f2c817a-goog
^ permalink raw reply related
* [PATCH 1/2] drivers: base: swnode: link devices to software nodes
From: Dmitry Torokhov @ 2019-07-13 7:52 UTC (permalink / raw)
To: Linus Walleij, Rafael J . Wysocki,
Enrico Weigelt, metux IT consult
Cc: linux-input, linux-gpio, linux-kernel, Andy Shevchenko,
Heikki Krogerus
In-Reply-To: <20190713075259.243565-1-dmitry.torokhov@gmail.com>
It is helpful to know what device, if any, a software node is tied to, so
let's store a pointer to the device in software node structure. Note that
children software nodes will inherit their parent's device pointer, so we
do not have to traverse hierarchy to see what device the [sub]tree belongs
to.
We will be using the device pointer to locate GPIO lookup tables for
devices with static properties.
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
drivers/base/property.c | 1 +
drivers/base/swnode.c | 35 ++++++++++++++++++++++++++++++++++-
include/linux/property.h | 5 +++++
3 files changed, 40 insertions(+), 1 deletion(-)
diff --git a/drivers/base/property.c b/drivers/base/property.c
index 348b37e64944..3bc93d4b35c4 100644
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -527,6 +527,7 @@ int device_add_properties(struct device *dev,
if (IS_ERR(fwnode))
return PTR_ERR(fwnode);
+ software_node_link_device(fwnode, dev);
set_secondary_fwnode(dev, fwnode);
return 0;
}
diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c
index 7fc5a18e02ad..fd12eea539b6 100644
--- a/drivers/base/swnode.c
+++ b/drivers/base/swnode.c
@@ -24,6 +24,9 @@ struct software_node {
/* properties */
const struct property_entry *properties;
+
+ /* device this node is associated with */
+ struct device *dev;
};
static DEFINE_IDA(swnode_root_ids);
@@ -607,8 +610,14 @@ fwnode_create_software_node(const struct property_entry *properties,
INIT_LIST_HEAD(&swnode->children);
swnode->parent = p;
- if (p)
+ if (p) {
list_add_tail(&swnode->entry, &p->children);
+ /*
+ * We want to maintain the same association as the parent node,
+ * so we can easily locate corresponding device.
+ */
+ swnode->dev = p->dev;
+ }
ret = kobject_init_and_add(&swnode->kobj, &software_node_type,
p ? &p->kobj : NULL, "node%d", swnode->id);
@@ -639,6 +648,30 @@ void fwnode_remove_software_node(struct fwnode_handle *fwnode)
}
EXPORT_SYMBOL_GPL(fwnode_remove_software_node);
+int software_node_link_device(struct fwnode_handle *fwnode, struct device *dev)
+{
+ struct software_node *swnode = to_software_node(fwnode);
+
+ if (!swnode)
+ return -EINVAL;
+
+ swnode->dev = dev;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(software_node_link_device);
+
+struct device *
+software_node_get_linked_device(const struct fwnode_handle *fwnode)
+{
+ const struct software_node *swnode = to_software_node(fwnode);
+
+ if (!swnode)
+ return ERR_PTR(-EINVAL);
+
+ return swnode->dev;
+}
+EXPORT_SYMBOL_GPL(software_node_get_linked_device);
+
int software_node_notify(struct device *dev, unsigned long action)
{
struct fwnode_handle *fwnode = dev_fwnode(dev);
diff --git a/include/linux/property.h b/include/linux/property.h
index e9caa290cda5..754188cfd9db 100644
--- a/include/linux/property.h
+++ b/include/linux/property.h
@@ -338,4 +338,9 @@ fwnode_create_software_node(const struct property_entry *properties,
const struct fwnode_handle *parent);
void fwnode_remove_software_node(struct fwnode_handle *fwnode);
+int software_node_link_device(struct fwnode_handle *fwnode,
+ struct device *device);
+struct device *
+software_node_get_linked_device(const struct fwnode_handle *fwnode);
+
#endif /* _LINUX_PROPERTY_H_ */
--
2.22.0.510.g264f2c817a-goog
^ permalink raw reply related
* [PATCH 0/2] Make gpiolib work with static device properties
From: Dmitry Torokhov @ 2019-07-13 7:52 UTC (permalink / raw)
To: Linus Walleij, Rafael J . Wysocki,
Enrico Weigelt, metux IT consult
Cc: linux-input, linux-gpio, linux-kernel, Andy Shevchenko,
Heikki Krogerus
Hi,
These 2 patches implement GPIOs lookup for boards still using static
properties (instead of OF or ACPI), which will allow drivers to abandon
the custom platform data structures and switch to using generic bindings
with gpiod_get_*() API working transparently.
The 2nd patch was posted in September of 2018, before Heikki did the
switch from psets to software_nodes; I finally rebased it.
Enrico, it looks like you are working with a board that uses gpio_keys
that still uses platform data, it would be great if you could try this
out as I have not.
Thanks!
Dmitry Torokhov (2):
drivers: base: swnode: link devices to software nodes
gpiolib: add support for fetching descriptors from static properties
drivers/base/property.c | 1 +
drivers/base/swnode.c | 35 ++++++++++++-
drivers/gpio/gpiolib.c | 108 ++++++++++++++++++++++++++++-----------
include/linux/property.h | 5 ++
4 files changed, 119 insertions(+), 30 deletions(-)
--
2.22.0.510.g264f2c817a-goog
^ permalink raw reply
* [PATCH] Input: synaptics - enable RMI mode for HP Spectre X360
From: Dmitry Torokhov @ 2019-07-13 7:41 UTC (permalink / raw)
To: linux-input; +Cc: Benjamin Tissoires, Nate Graham, linux-kernel
The 2016 kabylake HP Spectre X360 (model number 13-w013dx) works much better
with psmouse.synaptics_intertouch=1 kernel parameter, so let's enable RMI4
mode automatically.
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=204115
Reported-by: Nate Graham <pointedstick@zoho.com>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
drivers/input/mouse/synaptics.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 7f8f4780b511..c0e188cd3811 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -182,6 +182,7 @@ static const char * const smbus_pnp_ids[] = {
"LEN2055", /* E580 */
"SYN3052", /* HP EliteBook 840 G4 */
"SYN3221", /* HP 15-ay000 */
+ "SYN323d", /* HP Spectre X360 13-w013dx */
NULL
};
--
Dmitry
^ permalink raw reply related
* Re: [PATCH v4 0/3] Add PAT9125 optical tracker driver
From: Rob Herring @ 2019-07-12 13:34 UTC (permalink / raw)
To: Alexandre Mergnat
Cc: Mark Rutland, Jonathan Cameron, linux-kernel@vger.kernel.org,
open list:IIO SUBSYSTEM AND DRIVERS, baylibre-upstreaming,
Dmitry Torokhov, Linux Input
In-Reply-To: <20190712094050.17432-1-amergnat@baylibre.com>
On Fri, Jul 12, 2019 at 3:41 AM Alexandre Mergnat <amergnat@baylibre.com> wrote:
>
> PixArt Imaging PAT9125 is a miniature low power optical navigation chip
> using LASER light source enabling digital surface tracking.
Please resend to the DT list if you want this reviewed.
Rob
^ permalink raw reply
* Re: [PATCH] dt-bindings: input: Convert Allwinner LRADC to a schema
From: Rob Herring @ 2019-07-12 13:21 UTC (permalink / raw)
Cc: Mark Rutland, devicetree, Maxime Ripard, Dmitry Torokhov,
Chen-Yu Tsai, linux-input, Frank Rowand, linux-arm-kernel
In-Reply-To: <20190711093835.20663-1-maxime.ripard@bootlin.com>
On Thu, 11 Jul 2019 11:38:35 +0200, Maxime Ripard wrote:
> The Allwinner SoCs have an LRADC used to report keys and supported in
> Linux, with a matching Device Tree binding.
>
> Now that we have the DT validation in place, let's convert the device tree
> bindings for that controller over to a YAML schemas.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
> ---
> .../input/allwinner,sun4i-a10-lradc-keys.yaml | 95 +++++++++++++++++++
> .../bindings/input/sun4i-lradc-keys.txt | 65 -------------
> 2 files changed, 95 insertions(+), 65 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/input/allwinner,sun4i-a10-lradc-keys.yaml
> delete mode 100644 Documentation/devicetree/bindings/input/sun4i-lradc-keys.txt
>
Applied, thanks.
Rob
^ permalink raw reply
* Re: [PATCH] input: API for Setting a Timestamp from a Driver
From: Peter Hutterer @ 2019-07-12 11:46 UTC (permalink / raw)
To: Benjamin Tissoires
Cc: Dmitry Torokhov, Atif Niyaz, Atif Niyaz, Siarhei Vishniakou,
open list:HID CORE LAYER, lkml
In-Reply-To: <CAO-hwJK-VAGpjN03XDTmmT4fYxb1V_izfvT9Z3tKDmLJ3henGw@mail.gmail.com>
On Fri, Jul 12, 2019 at 09:23:20AM +0200, Benjamin Tissoires wrote:
> On Fri, Jul 12, 2019 at 8:41 AM Dmitry Torokhov
> <dmitry.torokhov@gmail.com> wrote:
> >
> > Hi Atif,
> >
> > On Wed, Jul 10, 2019 at 04:04:10PM -0700, Atif Niyaz wrote:
> > > Currently, evdev stamps time with timestamps acquired in
> > > evdev_events. However, this timestamping may not be accurate in terms of
> > > measuring when the actual event happened. This API allows any 3rd party
> > > driver to be able to call input_set_timestamp, and provide a timestamp
> > > that can be utilized in order to provide a more accurate sense of time
> > > for the event
> > >
> > > Signed-off-by: Atif Niyaz <atifniyaz@google.com>
> >
> > This looks OK to me. Benjamin, Peter, any concerns here?
> >
>
> No red flags from me (though Peter is the one using all of this).
>
> Just curious, which drivers do you think will be using this new API?
> I can see that we might want to use hid-multitouch for it, with the
> Scan Time forwarded by the device, but what do you have in mind?
that'd be my question as well. I'm all for more precise evdev timestamps but
there's some overlap with MSC_TIMESTAMP (which at least libinput isn't
handling well right now, with the exception of some quirk detection).
but yeah, overall this is a good solution from my POV.
Cheers,
Peter
> > > ---
> > > drivers/input/evdev.c | 42 ++++++++++++++++--------------------------
> > > drivers/input/input.c | 17 +++++++++++++++++
> > > include/linux/input.h | 38 ++++++++++++++++++++++++++++++++++++++
> > > 3 files changed, 71 insertions(+), 26 deletions(-)
> > >
> > > diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
> > > index 867c2cfd0038..a331efa0a3f6 100644
> > > --- a/drivers/input/evdev.c
> > > +++ b/drivers/input/evdev.c
> > > @@ -25,13 +25,6 @@
> > > #include <linux/cdev.h>
> > > #include "input-compat.h"
> > >
> > > -enum evdev_clock_type {
> > > - EV_CLK_REAL = 0,
> > > - EV_CLK_MONO,
> > > - EV_CLK_BOOT,
> > > - EV_CLK_MAX
> > > -};
> > > -
> > > struct evdev {
> > > int open;
> > > struct input_handle handle;
> > > @@ -53,7 +46,7 @@ struct evdev_client {
> > > struct fasync_struct *fasync;
> > > struct evdev *evdev;
> > > struct list_head node;
> > > - unsigned int clk_type;
> > > + input_clk_t clk_type;
> > > bool revoked;
> > > unsigned long *evmasks[EV_CNT];
> > > unsigned int bufsize;
> > > @@ -150,16 +143,18 @@ static void __evdev_flush_queue(struct evdev_client *client, unsigned int type)
> > > static void __evdev_queue_syn_dropped(struct evdev_client *client)
> > > {
> > > struct input_event ev;
> > > - ktime_t time;
> > > struct timespec64 ts;
> > > + ktime_t *time = input_get_timestamp(client->evdev->handle.dev);
> > >
> > > - time = client->clk_type == EV_CLK_REAL ?
> > > - ktime_get_real() :
> > > - client->clk_type == EV_CLK_MONO ?
> > > - ktime_get() :
> > > - ktime_get_boottime();
> > > + switch (client->clk_type) {
> > > + case INPUT_CLK_REAL:
> > > + case INPUT_CLK_MONO:
> > > + ts = ktime_to_timespec64(time[client->clk_type]);
> > > + break;
> > > + default:
> > > + ts = ktime_to_timespec64(time[INPUT_CLK_BOOT]);
> >
> > Add "break" here please.
> >
> > > + }
> > >
> > > - ts = ktime_to_timespec64(time);
> > > ev.input_event_sec = ts.tv_sec;
> > > ev.input_event_usec = ts.tv_nsec / NSEC_PER_USEC;
> > > ev.type = EV_SYN;
> > > @@ -185,21 +180,21 @@ static void evdev_queue_syn_dropped(struct evdev_client *client)
> > > spin_unlock_irqrestore(&client->buffer_lock, flags);
> > > }
> > >
> > > -static int evdev_set_clk_type(struct evdev_client *client, unsigned int clkid)
> > > +static int evdev_set_clk_type(struct evdev_client *client, clockid_t clkid)
> > > {
> > > unsigned long flags;
> > > - unsigned int clk_type;
> > > + input_clk_t clk_type;
> > >
> > > switch (clkid) {
> > >
> > > case CLOCK_REALTIME:
> > > - clk_type = EV_CLK_REAL;
> > > + clk_type = INPUT_CLK_REAL;
> > > break;
> > > case CLOCK_MONOTONIC:
> > > - clk_type = EV_CLK_MONO;
> > > + clk_type = INPUT_CLK_MONO;
> > > break;
> > > case CLOCK_BOOTTIME:
> > > - clk_type = EV_CLK_BOOT;
> > > + clk_type = INPUT_CLK_BOOT;
> > > break;
> > > default:
> > > return -EINVAL;
> > > @@ -307,12 +302,7 @@ static void evdev_events(struct input_handle *handle,
> > > {
> > > struct evdev *evdev = handle->private;
> > > struct evdev_client *client;
> > > - ktime_t ev_time[EV_CLK_MAX];
> > > -
> > > - ev_time[EV_CLK_MONO] = ktime_get();
> > > - ev_time[EV_CLK_REAL] = ktime_mono_to_real(ev_time[EV_CLK_MONO]);
> > > - ev_time[EV_CLK_BOOT] = ktime_mono_to_any(ev_time[EV_CLK_MONO],
> > > - TK_OFFS_BOOT);
> > > + ktime_t *ev_time = input_get_timestamp(handle->dev);
> > >
> > > rcu_read_lock();
> > >
> > > diff --git a/drivers/input/input.c b/drivers/input/input.c
> > > index 7f3c5fcb9ed6..ae8b0ee58120 100644
> > > --- a/drivers/input/input.c
> > > +++ b/drivers/input/input.c
> > > @@ -1894,6 +1894,23 @@ void input_free_device(struct input_dev *dev)
> > > }
> > > EXPORT_SYMBOL(input_free_device);
> > >
> > > +/**
> > > + * input_get_timestamp - get timestamp for input events
> > > + * @dev: input device to get timestamp from
> > > + *
> > > + * A valid timestamp is a timestamp of non-zero value.
> > > + */
> > > +ktime_t *input_get_timestamp(struct input_dev *dev)
> > > +{
> > > + const ktime_t invalid_timestamp = ktime_set(0, 0);
> > > +
> > > + if (!ktime_compare(dev->timestamp[INPUT_CLK_MONO], ktime_zero)) {
> >
> > You need to replace ktime_zero with invalid_timestamp here.
> >
> > > + input_set_timestamp(dev, ktime_get());
> > > + }
> >
> > No need for curly braces for 1-line body.
> >
> > > + return dev->timestamp;
> > > +}
> > > +EXPORT_SYMBOL(input_get_timestamp);
> > > +
> > > /**
> > > * input_set_capability - mark device as capable of a certain event
> > > * @dev: device that is capable of emitting or accepting event
> > > diff --git a/include/linux/input.h b/include/linux/input.h
> > > index 510e78558c10..3929b62ccbe5 100644
> > > --- a/include/linux/input.h
> > > +++ b/include/linux/input.h
> > > @@ -33,6 +33,14 @@ struct input_value {
> > > __s32 value;
> > > };
> > >
> > > +enum input_clock_type {
> > > + INPUT_CLK_REAL = 0,
> > > + INPUT_CLK_MONO,
> > > + INPUT_CLK_BOOT,
> > > + INPUT_CLK_MAX
> > > +};
> > > +typedef enum input_clock_type input_clk_t;
> >
> > We typically avoid typedefs unless we really want to hide kind of data
> > we are dealing with. Let's just use "enum input_clock_type" everywhere.
> >
> > > +
> > > /**
> > > * struct input_dev - represents an input device
> > > * @name: name of the device
> > > @@ -114,6 +122,8 @@ struct input_value {
> > > * @vals: array of values queued in the current frame
> > > * @devres_managed: indicates that devices is managed with devres framework
> > > * and needs not be explicitly unregistered or freed.
> > > + * @timestamp: storage for a timestamp set by input_set_timestamp called
> > > + * by a driver
> > > */
> > > struct input_dev {
> > > const char *name;
> > > @@ -184,6 +194,8 @@ struct input_dev {
> > > struct input_value *vals;
> > >
> > > bool devres_managed;
> > > +
> > > + ktime_t timestamp[INPUT_CLK_MAX];
> > > };
> > > #define to_input_dev(d) container_of(d, struct input_dev, dev)
> > >
> > > @@ -382,6 +394,32 @@ void input_close_device(struct input_handle *);
> > >
> > > int input_flush_device(struct input_handle *handle, struct file *file);
> > >
> > > +/**
> > > + * input_set_timestamp - set timestamp for input events
> > > + * @dev: input device to set timestamp for
> > > + * @timestamp: the time at which the event has occurred
> > > + * in CLOCK_MONOTONIC
> > > + *
> > > + * This function is intended to provide to the input system a more
> > > + * accurate time of when an event actually occurred. The driver should
> > > + * call this function as soon as a timestamp is acquired ensuring
> > > + * clock conversions in input_set_timestamp are done correctly.
> > > + *
> > > + * The system entering a suspend between timestamp acquisition and
> > > + * calling input_set_timestamp can result in inaccurate conversions.
> > > + *
> > > + */
> > > +static inline void input_set_timestamp(struct input_dev *dev,
> > > + ktime_t timestamp)
> > > +{
> > > + dev->timestamp[INPUT_CLK_MONO] = timestamp;
> > > + dev->timestamp[INPUT_CLK_REAL] = ktime_mono_to_real(timestamp);
> > > + dev->timestamp[INPUT_CLK_BOOT] = ktime_mono_to_any(
> > > + timestamp, TK_OFFS_BOOT);
> > > +}
> > > +
> > > +ktime_t *input_get_timestamp(struct input_dev *dev);
> > > +
> > > void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value);
> > > void input_inject_event(struct input_handle *handle, unsigned int type, unsigned int code, int value);
> > >
> > > --
> > > 2.22.0.410.gd8fdbe21b5-goog
> > >
> >
> > --
> > Dmitry
^ permalink raw reply
* [PATCH v4 3/3] iio: Add PAT9125 optical tracker sensor
From: Alexandre Mergnat @ 2019-07-12 9:40 UTC (permalink / raw)
To: robh+dt, mark.rutland, jic23
Cc: linux-kernel, linux-iio, baylibre-upstreaming, dmitry.torokhov,
linux-input, Alexandre Mergnat
In-Reply-To: <20190712094050.17432-1-amergnat@baylibre.com>
This adds support for PixArt Imaging’s miniature low power optical
navigation chip using LASER light source enabling digital surface tracking.
Features and datasheet: [0]
This IIO driver allows to read relative position from where the system
started on X and Y axis through two way:
- Punctual "read_raw" which will issue a read in the device registers to
get the delta between last/current read and return the addition of all
the deltas.
- Buffer read. Data can be retrieved using triggered buffer subscription
(i.e. iio_readdev). The buffer payload is:
|32 bits delta X|32 bits delta Y|timestamp|.
The possible I2C addresses are 0x73, 0x75 and 0x79.
X and Y axis CPI resolution can be get/set independently through IIO_SCALE.
The range value is 0-255 which means:
- 0 to ~1,275 Counts Per Inch on flat surface.
- 0 to ~630 Counts Per Rev on 1.0mm diameter STS shaft at 1.0mm distance.
More details on the datasheet.
The "position" directory is added to contain drivers which can provide
position data.
[0]: http://www.pixart.com/products-detail/72/PAT9125EL-TKIT___TKMT
Signed-off-by: Alexandre Mergnat <amergnat@baylibre.com>
---
drivers/iio/Kconfig | 1 +
drivers/iio/Makefile | 1 +
drivers/iio/position/Kconfig | 18 ++
drivers/iio/position/Makefile | 6 +
drivers/iio/position/pat9125.c | 506 +++++++++++++++++++++++++++++++++
5 files changed, 532 insertions(+)
create mode 100644 drivers/iio/position/Kconfig
create mode 100644 drivers/iio/position/Makefile
create mode 100644 drivers/iio/position/pat9125.c
diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
index 5bd51853b15e..aca6fcbceeab 100644
--- a/drivers/iio/Kconfig
+++ b/drivers/iio/Kconfig
@@ -85,6 +85,7 @@ source "drivers/iio/light/Kconfig"
source "drivers/iio/magnetometer/Kconfig"
source "drivers/iio/multiplexer/Kconfig"
source "drivers/iio/orientation/Kconfig"
+source "drivers/iio/position/Kconfig"
if IIO_TRIGGER
source "drivers/iio/trigger/Kconfig"
endif #IIO_TRIGGER
diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
index bff682ad1cfb..1712011c0f4a 100644
--- a/drivers/iio/Makefile
+++ b/drivers/iio/Makefile
@@ -31,6 +31,7 @@ obj-y += light/
obj-y += magnetometer/
obj-y += multiplexer/
obj-y += orientation/
+obj-y += position/
obj-y += potentiometer/
obj-y += potentiostat/
obj-y += pressure/
diff --git a/drivers/iio/position/Kconfig b/drivers/iio/position/Kconfig
new file mode 100644
index 000000000000..1cf28896511c
--- /dev/null
+++ b/drivers/iio/position/Kconfig
@@ -0,0 +1,18 @@
+#
+# Optical tracker sensors
+#
+# When adding new entries keep the list in alphabetical order
+
+menu "Optical tracker sensors"
+
+config PAT9125
+ tristate "Optical tracker PAT9125 I2C driver"
+ depends on I2C
+ select IIO_BUFFER
+ help
+ Say yes here to build support for PAT9125 optical tracker
+ sensors.
+
+ To compile this driver as a module, say M here: the module will
+ be called pat9125.
+endmenu
diff --git a/drivers/iio/position/Makefile b/drivers/iio/position/Makefile
new file mode 100644
index 000000000000..cf294917ae2c
--- /dev/null
+++ b/drivers/iio/position/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for industrial I/O Optical tracker sensor drivers
+#
+
+# When adding new entries keep the list in alphabetical order
+obj-$(CONFIG_PAT9125) += pat9125.o
diff --git a/drivers/iio/position/pat9125.c b/drivers/iio/position/pat9125.c
new file mode 100644
index 000000000000..2f04777e0790
--- /dev/null
+++ b/drivers/iio/position/pat9125.c
@@ -0,0 +1,506 @@
+// SPDX-License-Identifier: (GPL-2.0)
+/*
+ * Copyright (C) 2019 BayLibre, SAS
+ * Author: Alexandre Mergnat <amergnat@baylibre.com>
+ */
+
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+/* I2C Address function to ID pin*/
+#define PAT9125_I2C_ADDR_HI 0x73
+#define PAT9125_I2C_ADDR_LO 0x75
+#define PAT9125_I2C_ADDR_NC 0x79
+
+/* Registers */
+#define PAT9125_PRD_ID1_REG 0x00
+#define PAT9125_PRD_ID2_REG 0x01
+#define PAT9125_MOTION_STATUS_REG 0x02
+#define PAT9125_DELTA_X_LO_REG 0x03
+#define PAT9125_DELTA_Y_LO_REG 0x04
+#define PAT9125_OP_MODE_REG 0x05
+#define PAT9125_CONFIG_REG 0x06
+#define PAT9125_WRITE_PROTEC_REG 0x09
+#define PAT9125_SLEEP1_REG 0x0A
+#define PAT9125_SLEEP2_REG 0x0B
+#define PAT9125_RES_X_REG 0x0D
+#define PAT9125_RES_Y_REG 0x0E
+#define PAT9125_DELTA_XY_HI_REG 0x12
+#define PAT9125_SHUTER_REG 0x14
+#define PAT9125_FRAME_AVG_REG 0x17
+#define PAT9125_ORIENTATION_REG 0x19
+
+/* Bits */
+#define PAT9125_VALID_MOTION_DATA_BIT BIT(7)
+#define PAT9125_RESET_BIT BIT(7)
+
+/* Registers' values */
+#define PAT9125_SENSOR_ID_VAL 0x31
+#define PAT9125_DISABLE_WRITE_PROTECT_VAL 0x5A
+#define PAT9125_ENABLE_WRITE_PROTECT_VAL 0x00
+
+/* Default Value of sampled value size */
+#define PAT9125_SAMPLED_VAL_BIT_SIZE 12
+
+struct pat9125_data {
+ struct regmap *regmap;
+ struct iio_trigger *indio_trig; /* Motion detection */
+ s32 position_x;
+ s32 position_y;
+ bool sampling;
+};
+
+static const struct iio_chan_spec pat9125_channels[] = {
+ {
+ .type = IIO_DISTANCE,
+ .modified = 1,
+ .channel2 = IIO_MOD_X,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ .scan_index = 0,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 32,
+ .storagebits = 32,
+ .endianness = IIO_CPU,
+ },
+ },
+ {
+ .type = IIO_DISTANCE,
+ .modified = 1,
+ .channel2 = IIO_MOD_Y,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ .scan_index = 1,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 32,
+ .storagebits = 32,
+ .endianness = IIO_CPU,
+ },
+ },
+ IIO_CHAN_SOFT_TIMESTAMP(2),
+};
+
+/**
+ * pat9125_write_pretected_reg() - Write value in protected register.
+ *
+ * @regmap: Pointer to I2C register map.
+ * @reg_addr: Register address.
+ * @reg_value: Value to be write in register.
+ *
+ * A value of zero will be returned on success, a negative errno will
+ * be returned in error cases.
+ */
+static int pat9125_write_pretected_reg(struct iio_dev *indio_dev,
+ u8 reg_addr, u8 reg_value)
+{
+ struct pat9125_data *data = iio_priv(indio_dev);
+ int ret;
+
+ ret = regmap_write(data->regmap,
+ PAT9125_WRITE_PROTEC_REG,
+ PAT9125_DISABLE_WRITE_PROTECT_VAL);
+
+ if (!ret)
+ ret = regmap_write(data->regmap, reg_addr, reg_value);
+
+ /* Try to put back write protection everytime */
+ ret |= regmap_write(data->regmap,
+ PAT9125_WRITE_PROTEC_REG,
+ PAT9125_ENABLE_WRITE_PROTECT_VAL);
+
+ return ret;
+}
+/**
+ * pat9125_read_delta() - Read delta value, update delta & position data.
+ *
+ * @data: Driver's data structure.
+ *
+ * A value of zero will be returned on success, a negative errno will
+ * be returned in error cases.
+ */
+static int pat9125_read_delta(struct pat9125_data *data)
+{
+ struct regmap *regmap = data->regmap;
+ int status = 0;
+ int val_x = 0;
+ int val_y = 0;
+ int val_high_nibbles = 0;
+ int ret;
+
+ ret = regmap_read(regmap, PAT9125_MOTION_STATUS_REG, &status);
+ if (ret < 0)
+ return ret;
+
+ /* Check if motion is detected */
+ if (status & PAT9125_VALID_MOTION_DATA_BIT) {
+ ret = regmap_read(regmap, PAT9125_DELTA_X_LO_REG, &val_x);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_read(regmap, PAT9125_DELTA_Y_LO_REG, &val_y);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_read(regmap, PAT9125_DELTA_XY_HI_REG,
+ &val_high_nibbles);
+ if (ret < 0)
+ return ret;
+
+ val_x |= (val_high_nibbles << 4) & 0xF00;
+ val_y |= (val_high_nibbles << 8) & 0xF00;
+ val_x = sign_extend32(val_x,
+ PAT9125_SAMPLED_VAL_BIT_SIZE - 1);
+ val_y = sign_extend32(val_y,
+ PAT9125_SAMPLED_VAL_BIT_SIZE - 1);
+ data->position_x += val_x;
+ data->position_y += val_y;
+ }
+ return 0;
+}
+
+/**
+ * pat9125_read_raw() - Sample and return the value(s)
+ * function to the associated channel info enum.
+ *
+ * @indio_dev: Industrial I/O device.
+ * @chan: Specification of a single channel.
+ * @val: Contain the elements making up the returned value.
+ * @val2: Not used.
+ * @mask: (enum iio_chan_info_enum) Type of the info attribute.
+ *
+ * Zero will be returned on success, negative value otherwise.
+ **/
+static int pat9125_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct pat9125_data *data = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = pat9125_read_delta(data);
+ if (ret)
+ return ret;
+ switch (chan->channel2) {
+ case IIO_MOD_X:
+ *val = data->position_x;
+ return IIO_VAL_INT;
+ case IIO_MOD_Y:
+ *val = data->position_y;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->channel2) {
+ case IIO_MOD_X:
+ ret = regmap_read(data->regmap, PAT9125_RES_X_REG, val);
+ if (ret)
+ return ret;
+ else
+ return IIO_VAL_INT;
+ case IIO_MOD_Y:
+ ret = regmap_read(data->regmap, PAT9125_RES_Y_REG, val);
+ if (ret)
+ return ret;
+ else
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+/**
+ * pat9125_write_raw() - Write the value(s)
+ * function to the associated channel info enum.
+ *
+ * @indio_dev: Industrial I/O device.
+ * @chan: Specification of a single channel.
+ * @val: Value write in the channel.
+ * @val2: Not used.
+ * @mask: (enum iio_chan_info_enum) Type of the info attribute.
+ *
+ * Zero will be returned on success, negative value otherwise.
+ **/
+static int pat9125_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val,
+ int val2, long mask)
+{
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->channel2) {
+ case IIO_MOD_X:
+ ret = pat9125_write_pretected_reg(indio_dev,
+ PAT9125_RES_X_REG, val);
+ return ret;
+ case IIO_MOD_Y:
+ ret = pat9125_write_pretected_reg(indio_dev,
+ PAT9125_RES_Y_REG, val);
+ return ret;
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static irqreturn_t pat9125_threaded_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct pat9125_data *data = iio_priv(indio_dev);
+ u8 buf[16]; /* Payload: Pos_X (4) | Pos_Y (4) | Timestamp (8) */
+ int ret;
+ s64 timestamp;
+
+ data->sampling = true;
+ ret = pat9125_read_delta(data);
+ if (ret) {
+ dev_err(indio_dev->dev.parent, "Read delta failed %d\n", ret);
+ return IRQ_NONE;
+ }
+ timestamp = iio_get_time_ns(indio_dev);
+ *((s32 *)&buf[0]) = data->position_x;
+ *((s32 *)&buf[sizeof(s32)]) = data->position_y;
+ iio_push_to_buffers_with_timestamp(indio_dev, buf, timestamp);
+ iio_trigger_notify_done(indio_dev->trig);
+ return IRQ_HANDLED;
+}
+
+/**
+ * pat9125_threaded_event_handler() - Threaded motion detection event handler
+ * @irq: The irq being handled.
+ * @private: struct iio_device pointer for the device.
+ */
+static irqreturn_t pat9125_threaded_event_handler(int irq, void *private)
+{
+ struct iio_dev *indio_dev = private;
+ struct pat9125_data *data = iio_priv(indio_dev);
+
+ iio_trigger_poll_chained(data->indio_trig);
+ return IRQ_HANDLED;
+}
+
+/**
+ * pat9125_buffer_postenable() - Buffer post enable actions
+ *
+ * @indio_dev: Industrial I/O device.
+ */
+static int pat9125_buffer_postenable(struct iio_dev *indio_dev)
+{
+ struct pat9125_data *data = iio_priv(indio_dev);
+ int ret = 0;
+
+ ret = iio_triggered_buffer_postenable(indio_dev);
+ if (ret)
+ return ret;
+
+ /* Release interrupt pin on the device */
+ ret = pat9125_read_delta(data);
+
+ /* iio_trigger_detach_poll_func isn't reachable, so use this function */
+ if (ret)
+ ret = iio_triggered_buffer_predisable(indio_dev);
+
+ return ret;
+}
+
+static const struct iio_buffer_setup_ops pat9125_buffer_ops = {
+ .postenable = pat9125_buffer_postenable,
+};
+
+static const struct regmap_config pat9125_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+};
+
+static const struct iio_info pat9125_info = {
+ .read_raw = pat9125_read_raw,
+ .write_raw = pat9125_write_raw,
+};
+
+/*
+ * To detect if a new value is available, register status is checked. This
+ * method is safer than using a flag on GPIO IRQ to track event while sampling
+ * because falling edge is missed when device trig just after a read reg value
+ * (that happen for fast motions or high CPI setting).
+ *
+ * Note: To avoid infinite loop in "iio_trigger_notify_done" when it is not in
+ * buffer mode and kernel warning due to nested IRQ thread,
+ * this function must return 0.
+ */
+static int pat9125_trig_try_reenable(struct iio_trigger *trig)
+{
+ struct pat9125_data *data = iio_trigger_get_drvdata(trig);
+ struct regmap *regmap = data->regmap;
+ int status = 0;
+
+ if (data->sampling) {
+ regmap_read(regmap, PAT9125_MOTION_STATUS_REG, &status);
+ if (status & PAT9125_VALID_MOTION_DATA_BIT) {
+ data->sampling = false;
+ iio_trigger_poll_chained(data->indio_trig);
+ return 0;
+ }
+ }
+ data->sampling = false;
+ return 0;
+}
+
+static const struct iio_trigger_ops pat9125_trigger_ops = {
+ .try_reenable = pat9125_trig_try_reenable,
+};
+
+static int pat9125_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct pat9125_data *data;
+ struct iio_dev *indio_dev;
+ int ret, sensor_pid;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ if (!indio_dev) {
+ dev_err(&client->dev, "IIO device allocation failed\n");
+ return -ENOMEM;
+ }
+
+ data = iio_priv(indio_dev);
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->name = id->name;
+ indio_dev->channels = pat9125_channels;
+ indio_dev->num_channels = ARRAY_SIZE(pat9125_channels);
+ indio_dev->info = &pat9125_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev, NULL,
+ pat9125_threaded_trigger_handler, &pat9125_buffer_ops);
+ if (ret) {
+ dev_err(&client->dev, "unable to setup triggered buffer\n");
+ return ret;
+ }
+
+ data->indio_trig = devm_iio_trigger_alloc(&client->dev, "%s-dev%d",
+ indio_dev->name, indio_dev->id);
+ if (!data->indio_trig)
+ return -ENOMEM;
+ data->indio_trig->dev.parent = &client->dev;
+ data->indio_trig->ops = &pat9125_trigger_ops;
+ iio_trigger_set_drvdata(data->indio_trig, data);
+ ret = devm_iio_trigger_register(&client->dev, data->indio_trig);
+ if (ret) {
+ dev_err(&client->dev, "unable to register trigger\n");
+ return ret;
+ }
+
+ data->regmap = devm_regmap_init_i2c(client, &pat9125_regmap_config);
+ if (IS_ERR(data->regmap)) {
+ dev_err(&client->dev, "regmap init failed %ld\n",
+ PTR_ERR(data->regmap));
+ return PTR_ERR(data->regmap);
+ }
+
+ /* Check device ID */
+ ret = regmap_read(data->regmap, PAT9125_PRD_ID1_REG, &sensor_pid);
+ if (ret < 0) {
+ dev_err(&client->dev, "register 0x%x access failed %d\n",
+ PAT9125_PRD_ID1_REG, ret);
+ return ret;
+ }
+ if (sensor_pid != PAT9125_SENSOR_ID_VAL)
+ return -ENODEV;
+
+ /* Switch to bank0 (Magic number)*/
+ ret = regmap_write(data->regmap, 0x7F, 0x00);
+ if (ret < 0) {
+ dev_err(indio_dev->dev.parent, "register 0x%x access failed %d\n",
+ 0x7F, ret);
+ return ret;
+ }
+
+ /* Software reset */
+ ret = regmap_write_bits(data->regmap,
+ PAT9125_CONFIG_REG,
+ PAT9125_RESET_BIT,
+ 1);
+ if (ret < 0) {
+ dev_err(&client->dev, "register 0x%x access failed %d\n",
+ PAT9125_CONFIG_REG, ret);
+ return ret;
+ }
+
+ msleep(20);
+
+ /* Init GPIO IRQ */
+ if (client->irq) {
+ ret = devm_request_threaded_irq(&client->dev,
+ client->irq,
+ NULL,
+ pat9125_threaded_event_handler,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ "pat9125",
+ indio_dev);
+ if (ret) {
+ dev_err(&client->dev, "GPIO IRQ init failed\n");
+ return ret;
+ }
+ }
+
+ ret = devm_iio_device_register(&client->dev, indio_dev);
+ if (ret) {
+ dev_err(&client->dev, "IIO device register failed\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct i2c_device_id pat9125_id[] = {
+ { "pat9125", 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, pat9125_id);
+
+static const unsigned short normal_i2c[] = {
+ PAT9125_I2C_ADDR_HI,
+ PAT9125_I2C_ADDR_LO,
+ PAT9125_I2C_ADDR_NC,
+ I2C_CLIENT_END
+};
+
+static struct i2c_driver pat9125_driver = {
+ .driver = {
+ .name = "pat9125",
+ },
+ .probe = pat9125_probe,
+ .address_list = normal_i2c,
+ .id_table = pat9125_id,
+};
+
+module_i2c_driver(pat9125_driver);
+
+MODULE_AUTHOR("Alexandre Mergnat <amergnat@baylibre.com>");
+MODULE_DESCRIPTION("Optical Tracking sensor");
+MODULE_LICENSE("GPL");
--
2.17.1
^ permalink raw reply related
* [PATCH v4 2/3] dt-bindings: iio: position: Add docs pat9125
From: Alexandre Mergnat @ 2019-07-12 9:40 UTC (permalink / raw)
To: robh+dt, mark.rutland, jic23
Cc: linux-kernel, linux-iio, baylibre-upstreaming, dmitry.torokhov,
linux-input, Alexandre Mergnat
In-Reply-To: <20190712094050.17432-1-amergnat@baylibre.com>
Add documentation for the optical tracker PAT9125 and
"position" directory for chip which can provides position data.
Signed-off-by: Alexandre Mergnat <amergnat@baylibre.com>
---
.../bindings/iio/position/pat9125.txt | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
create mode 100644 Documentation/devicetree/bindings/iio/position/pat9125.txt
diff --git a/Documentation/devicetree/bindings/iio/position/pat9125.txt b/Documentation/devicetree/bindings/iio/position/pat9125.txt
new file mode 100644
index 000000000000..4028aeef9b42
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/position/pat9125.txt
@@ -0,0 +1,18 @@
+PixArt Imaging PAT9125 Optical Tracking Miniature Chip device driver
+
+Required properties:
+ - compatible: must be "pixart,pat9125"
+ - reg: i2c address where to find the device
+ - interrupts: the sole interrupt generated by the device
+
+ Refer to interrupt-controller/interrupts.txt for generic
+ interrupt client node bindings.
+
+Example:
+
+pat9125@75 {
+ compatible = "pixart,pat9125";
+ reg = <0x75>;
+ interrupt-parent = <&gpio3>;
+ interrupts = <12 IRQ_TYPE_EDGE_FALLING>;
+};
--
2.17.1
^ permalink raw reply related
* [PATCH v4 1/3] dt-bindings: Add pixart vendor
From: Alexandre Mergnat @ 2019-07-12 9:40 UTC (permalink / raw)
To: robh+dt, mark.rutland, jic23
Cc: linux-kernel, linux-iio, baylibre-upstreaming, dmitry.torokhov,
linux-input, Alexandre Mergnat
In-Reply-To: <20190712094050.17432-1-amergnat@baylibre.com>
PixArt Imaging Inc. is expertized in CMOS image sensors (CIS),
capacitive touch controllers and related imaging application development.
Signed-off-by: Alexandre Mergnat <amergnat@baylibre.com>
---
Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index 18b79c4cf7d5..120529f40c7c 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -705,6 +705,8 @@ patternProperties:
description: Pine64
"^pineriver,.*":
description: Shenzhen PineRiver Designs Co., Ltd.
+ "^pixart,.*":
+ description: PixArt Imaging Inc.
"^pixcir,.*":
description: PIXCIR MICROELECTRONICS Co., Ltd
"^plantower,.*":
--
2.17.1
^ permalink raw reply related
* [PATCH v4 0/3] Add PAT9125 optical tracker driver
From: Alexandre Mergnat @ 2019-07-12 9:40 UTC (permalink / raw)
To: robh+dt, mark.rutland, jic23
Cc: linux-kernel, linux-iio, baylibre-upstreaming, dmitry.torokhov,
linux-input, Alexandre Mergnat
PixArt Imaging PAT9125 is a miniature low power optical navigation chip
using LASER light source enabling digital surface tracking.
This device driver use IIO API to provide punctual and/or buffered data.
The data is a relative position from where start the device on X and Y
axis, depend on CPI (Counts Per Inch) resolution setting chosen.
The device support CPI configuration through IIO interface.
This patchset :
- Update vendor prefix
- Add the bindings for this device
- Add the device driver
- Add directory for optical tracker devices
Change since v3:
- Replace delta value by relative position
- Improve write protected reg function by removing print log and obvious
returns
- Handle error in postenable buffer function
Change since v2:
- Fix typo
- Add constructor webpage and datasheet in commit message
- Use BIT() macro for define bit mask
- Remove shift from IIO channel spec structure
- Replace IIO_LE by IIO_CPU from IIO channel spec structure
- Replace memcpy() by cast (s32)
- Rename "pat9125_trig_try_reen" to "pat9125_trig_try_reenable"
- Add carriage return (\n) at the end of each "dev_err" function
- Remove "iio_trigger_unregister" in case of "iio_trigger_register" fail,
register function already manage it
- Remove log which print device name in case of successful initialization
- Fix enabled IRQ flag warning during nested IRQ thread
- Improve retry algo now based on status register
- Remove "ts", "motion_detected" and "buffer_mode" from pat9125_data
structure
- Rename all "ot" directories to "position"
- Polling sample through IIO_CHAN_INFO_RAW now return position value
(relative to the position at initialization time) instead of delta
position
- Clean iio_buffer_setup_ops structure by removing NULL pointer.
- Use devm_iio_ function for all init functions and then delete
"pat9125_remove"
- Move device_register at the end of probe function
- Replace MODULE_PARM_DESC by IIO_SCALE to set axis resolution (CPI)
Change since v1:
- Fix typo
- Rename some defines / variables
- Remove I2C client from driver structure
- Change type of delta_x and delta_y from s16 to s32 to simplify signed
operations
- Add module parameter for axis resolution
- Replace "IIO_MOD_X_AND_Y" by "IIO_MOD_X" and "IIO_MOD_Y"
- Add sign extension macro
- Improve read value algorithm to avoid data loss
- Implement a trigger handler function which can work with any IIO
trigger, independently of it own GPIO IRQ, to match with IIO
requirement/behaviour
- Replace iio push event function by iio trigger poll in GPIO IRQ handler
- Use triggered_buffer helpers to replace kfifo use, setup buffer,
implement enable/disable setup buffer operations, IIO trigger
allocation and re-enable operations
- Remove useless "goto"
- Change GPIO IRQ handler from planified thread to IRQ thread
- Change GPIO IRQ trigger from low level and one shot to falling edge
- Add device unregister and buffer cleanup to driver remove function
Alexandre Mergnat (3):
dt-bindings: Add pixart vendor
dt-bindings: iio: position: Add docs pat9125
iio: Add PAT9125 optical tracker sensor
.../bindings/iio/position/pat9125.txt | 18 +
.../devicetree/bindings/vendor-prefixes.yaml | 2 +
drivers/iio/Kconfig | 1 +
drivers/iio/Makefile | 1 +
drivers/iio/position/Kconfig | 18 +
drivers/iio/position/Makefile | 6 +
drivers/iio/position/pat9125.c | 506 ++++++++++++++++++
7 files changed, 552 insertions(+)
create mode 100644 Documentation/devicetree/bindings/iio/position/pat9125.txt
create mode 100644 drivers/iio/position/Kconfig
create mode 100644 drivers/iio/position/Makefile
create mode 100644 drivers/iio/position/pat9125.c
--
2.17.1
^ permalink raw reply
* Re: [PATCH] input: API for Setting a Timestamp from a Driver
From: Benjamin Tissoires @ 2019-07-12 7:23 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Atif Niyaz, Peter Hutterer, Atif Niyaz, Siarhei Vishniakou,
open list:HID CORE LAYER, lkml
In-Reply-To: <20190712064134.GA150689@dtor-ws>
On Fri, Jul 12, 2019 at 8:41 AM Dmitry Torokhov
<dmitry.torokhov@gmail.com> wrote:
>
> Hi Atif,
>
> On Wed, Jul 10, 2019 at 04:04:10PM -0700, Atif Niyaz wrote:
> > Currently, evdev stamps time with timestamps acquired in
> > evdev_events. However, this timestamping may not be accurate in terms of
> > measuring when the actual event happened. This API allows any 3rd party
> > driver to be able to call input_set_timestamp, and provide a timestamp
> > that can be utilized in order to provide a more accurate sense of time
> > for the event
> >
> > Signed-off-by: Atif Niyaz <atifniyaz@google.com>
>
> This looks OK to me. Benjamin, Peter, any concerns here?
>
No red flags from me (though Peter is the one using all of this).
Just curious, which drivers do you think will be using this new API?
I can see that we might want to use hid-multitouch for it, with the
Scan Time forwarded by the device, but what do you have in mind?
Cheers,
Benjamin
>
> > ---
> > drivers/input/evdev.c | 42 ++++++++++++++++--------------------------
> > drivers/input/input.c | 17 +++++++++++++++++
> > include/linux/input.h | 38 ++++++++++++++++++++++++++++++++++++++
> > 3 files changed, 71 insertions(+), 26 deletions(-)
> >
> > diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
> > index 867c2cfd0038..a331efa0a3f6 100644
> > --- a/drivers/input/evdev.c
> > +++ b/drivers/input/evdev.c
> > @@ -25,13 +25,6 @@
> > #include <linux/cdev.h>
> > #include "input-compat.h"
> >
> > -enum evdev_clock_type {
> > - EV_CLK_REAL = 0,
> > - EV_CLK_MONO,
> > - EV_CLK_BOOT,
> > - EV_CLK_MAX
> > -};
> > -
> > struct evdev {
> > int open;
> > struct input_handle handle;
> > @@ -53,7 +46,7 @@ struct evdev_client {
> > struct fasync_struct *fasync;
> > struct evdev *evdev;
> > struct list_head node;
> > - unsigned int clk_type;
> > + input_clk_t clk_type;
> > bool revoked;
> > unsigned long *evmasks[EV_CNT];
> > unsigned int bufsize;
> > @@ -150,16 +143,18 @@ static void __evdev_flush_queue(struct evdev_client *client, unsigned int type)
> > static void __evdev_queue_syn_dropped(struct evdev_client *client)
> > {
> > struct input_event ev;
> > - ktime_t time;
> > struct timespec64 ts;
> > + ktime_t *time = input_get_timestamp(client->evdev->handle.dev);
> >
> > - time = client->clk_type == EV_CLK_REAL ?
> > - ktime_get_real() :
> > - client->clk_type == EV_CLK_MONO ?
> > - ktime_get() :
> > - ktime_get_boottime();
> > + switch (client->clk_type) {
> > + case INPUT_CLK_REAL:
> > + case INPUT_CLK_MONO:
> > + ts = ktime_to_timespec64(time[client->clk_type]);
> > + break;
> > + default:
> > + ts = ktime_to_timespec64(time[INPUT_CLK_BOOT]);
>
> Add "break" here please.
>
> > + }
> >
> > - ts = ktime_to_timespec64(time);
> > ev.input_event_sec = ts.tv_sec;
> > ev.input_event_usec = ts.tv_nsec / NSEC_PER_USEC;
> > ev.type = EV_SYN;
> > @@ -185,21 +180,21 @@ static void evdev_queue_syn_dropped(struct evdev_client *client)
> > spin_unlock_irqrestore(&client->buffer_lock, flags);
> > }
> >
> > -static int evdev_set_clk_type(struct evdev_client *client, unsigned int clkid)
> > +static int evdev_set_clk_type(struct evdev_client *client, clockid_t clkid)
> > {
> > unsigned long flags;
> > - unsigned int clk_type;
> > + input_clk_t clk_type;
> >
> > switch (clkid) {
> >
> > case CLOCK_REALTIME:
> > - clk_type = EV_CLK_REAL;
> > + clk_type = INPUT_CLK_REAL;
> > break;
> > case CLOCK_MONOTONIC:
> > - clk_type = EV_CLK_MONO;
> > + clk_type = INPUT_CLK_MONO;
> > break;
> > case CLOCK_BOOTTIME:
> > - clk_type = EV_CLK_BOOT;
> > + clk_type = INPUT_CLK_BOOT;
> > break;
> > default:
> > return -EINVAL;
> > @@ -307,12 +302,7 @@ static void evdev_events(struct input_handle *handle,
> > {
> > struct evdev *evdev = handle->private;
> > struct evdev_client *client;
> > - ktime_t ev_time[EV_CLK_MAX];
> > -
> > - ev_time[EV_CLK_MONO] = ktime_get();
> > - ev_time[EV_CLK_REAL] = ktime_mono_to_real(ev_time[EV_CLK_MONO]);
> > - ev_time[EV_CLK_BOOT] = ktime_mono_to_any(ev_time[EV_CLK_MONO],
> > - TK_OFFS_BOOT);
> > + ktime_t *ev_time = input_get_timestamp(handle->dev);
> >
> > rcu_read_lock();
> >
> > diff --git a/drivers/input/input.c b/drivers/input/input.c
> > index 7f3c5fcb9ed6..ae8b0ee58120 100644
> > --- a/drivers/input/input.c
> > +++ b/drivers/input/input.c
> > @@ -1894,6 +1894,23 @@ void input_free_device(struct input_dev *dev)
> > }
> > EXPORT_SYMBOL(input_free_device);
> >
> > +/**
> > + * input_get_timestamp - get timestamp for input events
> > + * @dev: input device to get timestamp from
> > + *
> > + * A valid timestamp is a timestamp of non-zero value.
> > + */
> > +ktime_t *input_get_timestamp(struct input_dev *dev)
> > +{
> > + const ktime_t invalid_timestamp = ktime_set(0, 0);
> > +
> > + if (!ktime_compare(dev->timestamp[INPUT_CLK_MONO], ktime_zero)) {
>
> You need to replace ktime_zero with invalid_timestamp here.
>
> > + input_set_timestamp(dev, ktime_get());
> > + }
>
> No need for curly braces for 1-line body.
>
> > + return dev->timestamp;
> > +}
> > +EXPORT_SYMBOL(input_get_timestamp);
> > +
> > /**
> > * input_set_capability - mark device as capable of a certain event
> > * @dev: device that is capable of emitting or accepting event
> > diff --git a/include/linux/input.h b/include/linux/input.h
> > index 510e78558c10..3929b62ccbe5 100644
> > --- a/include/linux/input.h
> > +++ b/include/linux/input.h
> > @@ -33,6 +33,14 @@ struct input_value {
> > __s32 value;
> > };
> >
> > +enum input_clock_type {
> > + INPUT_CLK_REAL = 0,
> > + INPUT_CLK_MONO,
> > + INPUT_CLK_BOOT,
> > + INPUT_CLK_MAX
> > +};
> > +typedef enum input_clock_type input_clk_t;
>
> We typically avoid typedefs unless we really want to hide kind of data
> we are dealing with. Let's just use "enum input_clock_type" everywhere.
>
> > +
> > /**
> > * struct input_dev - represents an input device
> > * @name: name of the device
> > @@ -114,6 +122,8 @@ struct input_value {
> > * @vals: array of values queued in the current frame
> > * @devres_managed: indicates that devices is managed with devres framework
> > * and needs not be explicitly unregistered or freed.
> > + * @timestamp: storage for a timestamp set by input_set_timestamp called
> > + * by a driver
> > */
> > struct input_dev {
> > const char *name;
> > @@ -184,6 +194,8 @@ struct input_dev {
> > struct input_value *vals;
> >
> > bool devres_managed;
> > +
> > + ktime_t timestamp[INPUT_CLK_MAX];
> > };
> > #define to_input_dev(d) container_of(d, struct input_dev, dev)
> >
> > @@ -382,6 +394,32 @@ void input_close_device(struct input_handle *);
> >
> > int input_flush_device(struct input_handle *handle, struct file *file);
> >
> > +/**
> > + * input_set_timestamp - set timestamp for input events
> > + * @dev: input device to set timestamp for
> > + * @timestamp: the time at which the event has occurred
> > + * in CLOCK_MONOTONIC
> > + *
> > + * This function is intended to provide to the input system a more
> > + * accurate time of when an event actually occurred. The driver should
> > + * call this function as soon as a timestamp is acquired ensuring
> > + * clock conversions in input_set_timestamp are done correctly.
> > + *
> > + * The system entering a suspend between timestamp acquisition and
> > + * calling input_set_timestamp can result in inaccurate conversions.
> > + *
> > + */
> > +static inline void input_set_timestamp(struct input_dev *dev,
> > + ktime_t timestamp)
> > +{
> > + dev->timestamp[INPUT_CLK_MONO] = timestamp;
> > + dev->timestamp[INPUT_CLK_REAL] = ktime_mono_to_real(timestamp);
> > + dev->timestamp[INPUT_CLK_BOOT] = ktime_mono_to_any(
> > + timestamp, TK_OFFS_BOOT);
> > +}
> > +
> > +ktime_t *input_get_timestamp(struct input_dev *dev);
> > +
> > void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value);
> > void input_inject_event(struct input_handle *handle, unsigned int type, unsigned int code, int value);
> >
> > --
> > 2.22.0.410.gd8fdbe21b5-goog
> >
>
> --
> Dmitry
^ permalink raw reply
* Re: [PATCH] input: keyboard: mtk-pmic-keys: Add of_node_put() before return
From: Dmitry Torokhov @ 2019-07-12 6:50 UTC (permalink / raw)
To: Nishka Dasgupta
Cc: matthias.bgg, linux-mediatek, linux-arm-kernel, linux-input
In-Reply-To: <20190709180019.14339-1-nishkadg.linux@gmail.com>
On Tue, Jul 09, 2019 at 11:30:19PM +0530, Nishka Dasgupta wrote:
> Each iteration of for_each_child_of_node puts the previous
> node, but in the case of a return from the middle of the loop, there is
> no put, thus causing a memory leak. Hence add an of_node_put before the
> return in three places.
> Issue found with Coccinelle.
>
> Signed-off-by: Nishka Dasgupta <nishkadg.linux@gmail.com>
Applied, thank you.
> ---
> drivers/input/keyboard/mtk-pmic-keys.c | 9 +++++++--
> 1 file changed, 7 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/input/keyboard/mtk-pmic-keys.c b/drivers/input/keyboard/mtk-pmic-keys.c
> index 746ff06eaf8d..62391d6c7da6 100644
> --- a/drivers/input/keyboard/mtk-pmic-keys.c
> +++ b/drivers/input/keyboard/mtk-pmic-keys.c
> @@ -277,8 +277,10 @@ static int mtk_pmic_keys_probe(struct platform_device *pdev)
> keys->keys[index].regs = &mtk_pmic_regs->keys_regs[index];
>
> keys->keys[index].irq = platform_get_irq(pdev, index);
> - if (keys->keys[index].irq < 0)
> + if (keys->keys[index].irq < 0) {
> + of_node_put(child);
> return keys->keys[index].irq;
> + }
>
> error = of_property_read_u32(child,
> "linux,keycodes", &keys->keys[index].keycode);
> @@ -286,6 +288,7 @@ static int mtk_pmic_keys_probe(struct platform_device *pdev)
> dev_err(keys->dev,
> "failed to read key:%d linux,keycode property: %d\n",
> index, error);
> + of_node_put(child);
> return error;
> }
>
> @@ -293,8 +296,10 @@ static int mtk_pmic_keys_probe(struct platform_device *pdev)
> keys->keys[index].wakeup = true;
>
> error = mtk_pmic_key_setup(keys, &keys->keys[index]);
> - if (error)
> + if (error) {
> + of_node_put(child);
> return error;
> + }
>
> index++;
> }
> --
> 2.19.1
>
--
Dmitry
^ permalink raw reply
* Re: [PATCH] input: keyboard: sun4i-lradc-keys: Add of_node_put() before return
From: Dmitry Torokhov @ 2019-07-12 6:50 UTC (permalink / raw)
To: Nishka Dasgupta
Cc: maxime.ripard, hdegoede, wens, linux-arm-kernel, linux-input
In-Reply-To: <20190709175707.14278-1-nishkadg.linux@gmail.com>
On Tue, Jul 09, 2019 at 11:27:07PM +0530, Nishka Dasgupta wrote:
> Each iteration of for_each_child_of_node puts the previous
> node, but in the case of a return from the middle of the loop, there is
> no put, thus causing a memory leak. Hence add an of_node_put before the
> return in three places.
> Issue found with Coccinelle.
>
> Signed-off-by: Nishka Dasgupta <nishkadg.linux@gmail.com>
Applied, thank you.
> ---
> drivers/input/keyboard/sun4i-lradc-keys.c | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/drivers/input/keyboard/sun4i-lradc-keys.c b/drivers/input/keyboard/sun4i-lradc-keys.c
> index 6ffdc26b9c89..4a796bed48ac 100644
> --- a/drivers/input/keyboard/sun4i-lradc-keys.c
> +++ b/drivers/input/keyboard/sun4i-lradc-keys.c
> @@ -198,18 +198,21 @@ static int sun4i_lradc_load_dt_keymap(struct device *dev,
> error = of_property_read_u32(pp, "channel", &channel);
> if (error || channel != 0) {
> dev_err(dev, "%pOFn: Inval channel prop\n", pp);
> + of_node_put(pp);
> return -EINVAL;
> }
>
> error = of_property_read_u32(pp, "voltage", &map->voltage);
> if (error) {
> dev_err(dev, "%pOFn: Inval voltage prop\n", pp);
> + of_node_put(pp);
> return -EINVAL;
> }
>
> error = of_property_read_u32(pp, "linux,code", &map->keycode);
> if (error) {
> dev_err(dev, "%pOFn: Inval linux,code prop\n", pp);
> + of_node_put(pp);
> return -EINVAL;
> }
>
> --
> 2.19.1
>
--
Dmitry
^ permalink raw reply
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