linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 00/18] Synaptics RMI4 and SMBus implementation
@ 2016-10-13 15:50 Benjamin Tissoires
  2016-10-13 15:50 ` [PATCH v3 01/18] Input: synaptics-rmi4 - Move IRQ handling to rmi_driver Benjamin Tissoires
                   ` (18 more replies)
  0 siblings, 19 replies; 28+ messages in thread
From: Benjamin Tissoires @ 2016-10-13 15:50 UTC (permalink / raw)
  To: Dmitry Torokhov, Andrew Duggan, Lyude Paul, Christopher Heiny,
	Nick Dyer, Bjorn Andersson, Dennis Wassenberg
  Cc: linux-kernel, linux-input

Hi guys,

This is the third submission of this series, with some addition of RMI4 patches
currently waiting on the list.

I integrated Bjorn's patch because in the end, it seems to be the right thing
to do. We can create an irqchip in hid-rmi and also provide an IRQ there.
Worse case, if this doesn't work, we can always add a special case to
disable the handling of the IRQs in core.

I took Nick's patch as it's a nice cleanup and it solves an issue where
the mutex irq_mutex might not be initialized (in the case we are not handling
IRQ directly in core).

I also took some patches from Andrew that were submitted back in July, and that
were left over. They are required to allow hid-rmi to use rmi4-core without
losing functionality. The DT binding seemed to be problematic, so I just lefted
it out of the series. We can add it later when required (if required).
Andrew, regarding hid-rmi, I'll try to give you a draft of the irqchip
implementation based on what I did for SMBus Host Notify.

The rest is an update of the SMBus work. The main differences is that now
rmi4-smbus doesn't handle anymore the IRQ and I hope that the SMBus Host Notify
patches I posted on linux-i2c will be approved by Wolfram.

Cheers,
Benjamin

Andrew Duggan (4):
  Input: synaptics-rmi4 - Handle incomplete input data
  Input: synaptics-rmi4 - Add parameters for dribble packets and palm
    detect gesture
  Input: synaptics-rmi4 - Add support for controlling dribble packets in
    F12
  Input: synaptics-rmi4 - Set the ABS_MT_TOOL_TYPE bit to report tool
    type

Benjamin Tissoires (10):
  Input: synaptics-rmi4 - add SMBus support
  Input: serio - store the pt_buttons in the struct serio directly
  Input: synaptics-rmi4 - have only one struct platform data
  Input: synaptics-rmi4 - Add rmi_find_function()
  Input: synaptics-rmi4 - f30/f03: Forward mechanical buttons on
    buttonpads to PS/2 guest
  Input: synaptics - allocate a Synaptics Intertouch device
  Input: synaptics-rmi4 - add rmi_platform
  Input: synaptics-rmi4 - smbus: call psmouse_deactivate before
    binding/resume
  Input: synaptics-rmi4 - smbus: on resume, try 3 times if init fails
  Input: synaptics-rmi4 - fix documentation of
    rmi_2d_sensor_platform_data

Bjorn Andersson (1):
  Input: synaptics-rmi4 - Move IRQ handling to rmi_driver

Dennis Wassenberg (1):
  Input: synaptics-rmi4 - f03: grab data passed by transport device

Lyude Paul (1):
  Input: synaptics-rmi4 - add support for F03

Nick Dyer (1):
  Input: synaptics-rmi4 - factor out functions from probe

 drivers/input/mouse/psmouse-base.c |  12 +
 drivers/input/mouse/psmouse.h      |   1 +
 drivers/input/mouse/synaptics.c    | 153 +++++++++++-
 drivers/input/mouse/synaptics.h    |   5 +-
 drivers/input/rmi4/Kconfig         |  33 +++
 drivers/input/rmi4/Makefile        |   3 +
 drivers/input/rmi4/rmi_2d_sensor.c |   2 +
 drivers/input/rmi4/rmi_2d_sensor.h |   2 +
 drivers/input/rmi4/rmi_bus.c       |   3 +
 drivers/input/rmi4/rmi_bus.h       |  12 +
 drivers/input/rmi4/rmi_driver.c    | 225 ++++++++++++-----
 drivers/input/rmi4/rmi_driver.h    |  15 ++
 drivers/input/rmi4/rmi_f01.c       |   6 +-
 drivers/input/rmi4/rmi_f03.c       | 272 +++++++++++++++++++++
 drivers/input/rmi4/rmi_f11.c       |  90 +++++--
 drivers/input/rmi4/rmi_f12.c       | 100 +++++++-
 drivers/input/rmi4/rmi_f30.c       |  83 +++++--
 drivers/input/rmi4/rmi_i2c.c       |  74 +-----
 drivers/input/rmi4/rmi_platform.c  | 235 ++++++++++++++++++
 drivers/input/rmi4/rmi_smbus.c     | 477 +++++++++++++++++++++++++++++++++++++
 drivers/input/rmi4/rmi_spi.c       |  72 +-----
 include/linux/rmi.h                |  47 ++--
 include/linux/serio.h              |   8 +
 include/uapi/linux/serio.h         |   1 +
 24 files changed, 1663 insertions(+), 268 deletions(-)
 create mode 100644 drivers/input/rmi4/rmi_f03.c
 create mode 100644 drivers/input/rmi4/rmi_platform.c
 create mode 100644 drivers/input/rmi4/rmi_smbus.c

-- 
2.7.4

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

* [PATCH v3 01/18] Input: synaptics-rmi4 - Move IRQ handling to rmi_driver
  2016-10-13 15:50 [PATCH v3 00/18] Synaptics RMI4 and SMBus implementation Benjamin Tissoires
@ 2016-10-13 15:50 ` Benjamin Tissoires
  2016-11-09  0:47   ` Dmitry Torokhov
  2016-10-13 15:50 ` [PATCH v3 02/18] Input: synaptics-rmi4 - factor out functions from probe Benjamin Tissoires
                   ` (17 subsequent siblings)
  18 siblings, 1 reply; 28+ messages in thread
From: Benjamin Tissoires @ 2016-10-13 15:50 UTC (permalink / raw)
  To: Dmitry Torokhov, Andrew Duggan, Lyude Paul, Christopher Heiny,
	Nick Dyer, Bjorn Andersson, Dennis Wassenberg
  Cc: linux-kernel, linux-input

From: Bjorn Andersson <bjorn.andersson@linaro.org>

The attn IRQ is related to the chip, rather than the transport, so move
all handling of interrupts to the core driver. This also makes sure that
there are no races between interrupts and availability of the resources
used by the core driver.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>

---

new in v3

changes since Bjorn's submission:
- call disable_irq on remove()
---
 drivers/input/rmi4/rmi_driver.c | 73 +++++++++++++++++++++++++++++++++++++---
 drivers/input/rmi4/rmi_i2c.c    | 74 +++--------------------------------------
 drivers/input/rmi4/rmi_spi.c    | 72 +++------------------------------------
 include/linux/rmi.h             |  7 ++--
 4 files changed, 83 insertions(+), 143 deletions(-)

diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c
index c83bce8..cf780ef 100644
--- a/drivers/input/rmi4/rmi_driver.c
+++ b/drivers/input/rmi4/rmi_driver.c
@@ -17,6 +17,7 @@
 #include <linux/bitmap.h>
 #include <linux/delay.h>
 #include <linux/fs.h>
+#include <linux/irq.h>
 #include <linux/kconfig.h>
 #include <linux/pm.h>
 #include <linux/slab.h>
@@ -134,7 +135,7 @@ static void process_one_interrupt(struct rmi_driver_data *data,
 	}
 }
 
-int rmi_process_interrupt_requests(struct rmi_device *rmi_dev)
+static int rmi_process_interrupt_requests(struct rmi_device *rmi_dev)
 {
 	struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
 	struct device *dev = &rmi_dev->dev;
@@ -179,7 +180,42 @@ int rmi_process_interrupt_requests(struct rmi_device *rmi_dev)
 
 	return 0;
 }
-EXPORT_SYMBOL_GPL(rmi_process_interrupt_requests);
+
+static irqreturn_t rmi_irq_fn(int irq, void *dev_id)
+{
+	struct rmi_device *rmi_dev = dev_id;
+	int ret;
+
+	ret = rmi_process_interrupt_requests(rmi_dev);
+	if (ret)
+		rmi_dbg(RMI_DEBUG_CORE, &rmi_dev->dev,
+			"Failed to process interrupt request: %d\n", ret);
+
+	return IRQ_HANDLED;
+}
+
+static int rmi_irq_init(struct rmi_device *rmi_dev)
+{
+	struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev);
+	int irq_flags = irq_get_trigger_type(pdata->irq);
+	int ret;
+
+	if (!irq_flags)
+		irq_flags = IRQF_TRIGGER_LOW;
+
+	ret = devm_request_threaded_irq(&rmi_dev->dev, pdata->irq, NULL,
+					rmi_irq_fn, irq_flags | IRQF_ONESHOT,
+					dev_name(rmi_dev->xport->dev),
+					rmi_dev);
+	if (ret < 0) {
+		dev_warn(&rmi_dev->dev, "Failed to register interrupt %d\n",
+			 pdata->irq);
+
+		return ret;
+	}
+
+	return 0;
+}
 
 static int suspend_one_function(struct rmi_function *fn)
 {
@@ -787,8 +823,10 @@ err_put_fn:
 	return error;
 }
 
-int rmi_driver_suspend(struct rmi_device *rmi_dev)
+int rmi_driver_suspend(struct rmi_device *rmi_dev, bool enable_wake)
 {
+	struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev);
+	int irq = pdata->irq;
 	int retval = 0;
 
 	retval = rmi_suspend_functions(rmi_dev);
@@ -796,14 +834,33 @@ int rmi_driver_suspend(struct rmi_device *rmi_dev)
 		dev_warn(&rmi_dev->dev, "Failed to suspend functions: %d\n",
 			retval);
 
+	disable_irq(irq);
+	if (enable_wake && device_may_wakeup(rmi_dev->xport->dev)) {
+		retval = enable_irq_wake(irq);
+		if (!retval)
+			dev_warn(&rmi_dev->dev,
+				 "Failed to enable irq for wake: %d\n",
+				 retval);
+	}
 	return retval;
 }
 EXPORT_SYMBOL_GPL(rmi_driver_suspend);
 
-int rmi_driver_resume(struct rmi_device *rmi_dev)
+int rmi_driver_resume(struct rmi_device *rmi_dev, bool clear_wake)
 {
+	struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev);
+	int irq = pdata->irq;
 	int retval;
 
+	enable_irq(irq);
+	if (clear_wake && device_may_wakeup(rmi_dev->xport->dev)) {
+		retval = disable_irq_wake(irq);
+		if (!retval)
+			dev_warn(&rmi_dev->dev,
+				 "Failed to disable irq for wake: %d\n",
+				 retval);
+	}
+
 	retval = rmi_resume_functions(rmi_dev);
 	if (retval)
 		dev_warn(&rmi_dev->dev, "Failed to suspend functions: %d\n",
@@ -816,6 +873,10 @@ EXPORT_SYMBOL_GPL(rmi_driver_resume);
 static int rmi_driver_remove(struct device *dev)
 {
 	struct rmi_device *rmi_dev = to_rmi_device(dev);
+	struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev);
+	int irq = pdata->irq;
+
+	disable_irq(irq);
 
 	rmi_free_function_list(rmi_dev);
 
@@ -1004,6 +1065,10 @@ static int rmi_driver_probe(struct device *dev)
 		}
 	}
 
+	retval = rmi_irq_init(rmi_dev);
+	if (retval < 0)
+		goto err_destroy_functions;
+
 	if (data->f01_container->dev.driver)
 		/* Driver already bound, so enable ATTN now. */
 		return enable_sensor(rmi_dev);
diff --git a/drivers/input/rmi4/rmi_i2c.c b/drivers/input/rmi4/rmi_i2c.c
index 6f2e0e4..64a5488 100644
--- a/drivers/input/rmi4/rmi_i2c.c
+++ b/drivers/input/rmi4/rmi_i2c.c
@@ -9,7 +9,6 @@
 
 #include <linux/i2c.h>
 #include <linux/rmi.h>
-#include <linux/irq.h>
 #include <linux/of.h>
 #include <linux/delay.h>
 #include <linux/regulator/consumer.h>
@@ -35,8 +34,6 @@ struct rmi_i2c_xport {
 	struct mutex page_mutex;
 	int page;
 
-	int irq;
-
 	u8 *tx_buf;
 	size_t tx_buf_size;
 
@@ -177,42 +174,6 @@ static const struct rmi_transport_ops rmi_i2c_ops = {
 	.read_block	= rmi_i2c_read_block,
 };
 
-static irqreturn_t rmi_i2c_irq(int irq, void *dev_id)
-{
-	struct rmi_i2c_xport *rmi_i2c = dev_id;
-	struct rmi_device *rmi_dev = rmi_i2c->xport.rmi_dev;
-	int ret;
-
-	ret = rmi_process_interrupt_requests(rmi_dev);
-	if (ret)
-		rmi_dbg(RMI_DEBUG_XPORT, &rmi_dev->dev,
-			"Failed to process interrupt request: %d\n", ret);
-
-	return IRQ_HANDLED;
-}
-
-static int rmi_i2c_init_irq(struct i2c_client *client)
-{
-	struct rmi_i2c_xport *rmi_i2c = i2c_get_clientdata(client);
-	int irq_flags = irqd_get_trigger_type(irq_get_irq_data(rmi_i2c->irq));
-	int ret;
-
-	if (!irq_flags)
-		irq_flags = IRQF_TRIGGER_LOW;
-
-	ret = devm_request_threaded_irq(&client->dev, rmi_i2c->irq, NULL,
-			rmi_i2c_irq, irq_flags | IRQF_ONESHOT, client->name,
-			rmi_i2c);
-	if (ret < 0) {
-		dev_warn(&client->dev, "Failed to register interrupt %d\n",
-			rmi_i2c->irq);
-
-		return ret;
-	}
-
-	return 0;
-}
-
 #ifdef CONFIG_OF
 static const struct of_device_id rmi_i2c_of_match[] = {
 	{ .compatible = "syna,rmi4-i2c" },
@@ -240,8 +201,7 @@ static int rmi_i2c_probe(struct i2c_client *client,
 	if (!client->dev.of_node && client_pdata)
 		*pdata = *client_pdata;
 
-	if (client->irq > 0)
-		rmi_i2c->irq = client->irq;
+	pdata->irq = client->irq;
 
 	rmi_dbg(RMI_DEBUG_XPORT, &client->dev, "Probing %s.\n",
 			dev_name(&client->dev));
@@ -295,10 +255,6 @@ static int rmi_i2c_probe(struct i2c_client *client,
 		return retval;
 	}
 
-	retval = rmi_i2c_init_irq(client);
-	if (retval < 0)
-		return retval;
-
 	dev_info(&client->dev, "registered rmi i2c driver at %#04x.\n",
 			client->addr);
 	return 0;
@@ -322,18 +278,10 @@ static int rmi_i2c_suspend(struct device *dev)
 	struct rmi_i2c_xport *rmi_i2c = i2c_get_clientdata(client);
 	int ret;
 
-	ret = rmi_driver_suspend(rmi_i2c->xport.rmi_dev);
+	ret = rmi_driver_suspend(rmi_i2c->xport.rmi_dev, true);
 	if (ret)
 		dev_warn(dev, "Failed to resume device: %d\n", ret);
 
-	disable_irq(rmi_i2c->irq);
-	if (device_may_wakeup(&client->dev)) {
-		ret = enable_irq_wake(rmi_i2c->irq);
-		if (!ret)
-			dev_warn(dev, "Failed to enable irq for wake: %d\n",
-				ret);
-	}
-
 	regulator_bulk_disable(ARRAY_SIZE(rmi_i2c->supplies),
 			       rmi_i2c->supplies);
 
@@ -353,15 +301,7 @@ static int rmi_i2c_resume(struct device *dev)
 
 	msleep(rmi_i2c->startup_delay);
 
-	enable_irq(rmi_i2c->irq);
-	if (device_may_wakeup(&client->dev)) {
-		ret = disable_irq_wake(rmi_i2c->irq);
-		if (!ret)
-			dev_warn(dev, "Failed to disable irq for wake: %d\n",
-				ret);
-	}
-
-	ret = rmi_driver_resume(rmi_i2c->xport.rmi_dev);
+	ret = rmi_driver_resume(rmi_i2c->xport.rmi_dev, true);
 	if (ret)
 		dev_warn(dev, "Failed to resume device: %d\n", ret);
 
@@ -376,12 +316,10 @@ static int rmi_i2c_runtime_suspend(struct device *dev)
 	struct rmi_i2c_xport *rmi_i2c = i2c_get_clientdata(client);
 	int ret;
 
-	ret = rmi_driver_suspend(rmi_i2c->xport.rmi_dev);
+	ret = rmi_driver_suspend(rmi_i2c->xport.rmi_dev, false);
 	if (ret)
 		dev_warn(dev, "Failed to resume device: %d\n", ret);
 
-	disable_irq(rmi_i2c->irq);
-
 	regulator_bulk_disable(ARRAY_SIZE(rmi_i2c->supplies),
 			       rmi_i2c->supplies);
 
@@ -401,9 +339,7 @@ static int rmi_i2c_runtime_resume(struct device *dev)
 
 	msleep(rmi_i2c->startup_delay);
 
-	enable_irq(rmi_i2c->irq);
-
-	ret = rmi_driver_resume(rmi_i2c->xport.rmi_dev);
+	ret = rmi_driver_resume(rmi_i2c->xport.rmi_dev, false);
 	if (ret)
 		dev_warn(dev, "Failed to resume device: %d\n", ret);
 
diff --git a/drivers/input/rmi4/rmi_spi.c b/drivers/input/rmi4/rmi_spi.c
index 55bd1b3..f3e9e48 100644
--- a/drivers/input/rmi4/rmi_spi.c
+++ b/drivers/input/rmi4/rmi_spi.c
@@ -12,7 +12,6 @@
 #include <linux/rmi.h>
 #include <linux/slab.h>
 #include <linux/spi/spi.h>
-#include <linux/irq.h>
 #include <linux/of.h>
 #include "rmi_driver.h"
 
@@ -44,8 +43,6 @@ struct rmi_spi_xport {
 	struct mutex page_mutex;
 	int page;
 
-	int irq;
-
 	u8 *rx_buf;
 	u8 *tx_buf;
 	int xfer_buf_size;
@@ -326,41 +323,6 @@ static const struct rmi_transport_ops rmi_spi_ops = {
 	.read_block	= rmi_spi_read_block,
 };
 
-static irqreturn_t rmi_spi_irq(int irq, void *dev_id)
-{
-	struct rmi_spi_xport *rmi_spi = dev_id;
-	struct rmi_device *rmi_dev = rmi_spi->xport.rmi_dev;
-	int ret;
-
-	ret = rmi_process_interrupt_requests(rmi_dev);
-	if (ret)
-		rmi_dbg(RMI_DEBUG_XPORT, &rmi_dev->dev,
-			"Failed to process interrupt request: %d\n", ret);
-
-	return IRQ_HANDLED;
-}
-
-static int rmi_spi_init_irq(struct spi_device *spi)
-{
-	struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
-	int irq_flags = irqd_get_trigger_type(irq_get_irq_data(rmi_spi->irq));
-	int ret;
-
-	if (!irq_flags)
-		irq_flags = IRQF_TRIGGER_LOW;
-
-	ret = devm_request_threaded_irq(&spi->dev, rmi_spi->irq, NULL,
-			rmi_spi_irq, irq_flags | IRQF_ONESHOT,
-			dev_name(&spi->dev), rmi_spi);
-	if (ret < 0) {
-		dev_warn(&spi->dev, "Failed to register interrupt %d\n",
-			rmi_spi->irq);
-		return ret;
-	}
-
-	return 0;
-}
-
 #ifdef CONFIG_OF
 static int rmi_spi_of_probe(struct spi_device *spi,
 			struct rmi_device_platform_data *pdata)
@@ -433,8 +395,7 @@ static int rmi_spi_probe(struct spi_device *spi)
 		return retval;
 	}
 
-	if (spi->irq > 0)
-		rmi_spi->irq = spi->irq;
+	pdata->irq = spi->irq;
 
 	rmi_spi->spi = spi;
 	mutex_init(&rmi_spi->page_mutex);
@@ -465,10 +426,6 @@ static int rmi_spi_probe(struct spi_device *spi)
 		return retval;
 	}
 
-	retval = rmi_spi_init_irq(spi);
-	if (retval < 0)
-		return retval;
-
 	dev_info(&spi->dev, "registered RMI SPI driver\n");
 	return 0;
 }
@@ -489,17 +446,10 @@ static int rmi_spi_suspend(struct device *dev)
 	struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
 	int ret;
 
-	ret = rmi_driver_suspend(rmi_spi->xport.rmi_dev);
+	ret = rmi_driver_suspend(rmi_spi->xport.rmi_dev, true);
 	if (ret)
 		dev_warn(dev, "Failed to resume device: %d\n", ret);
 
-	disable_irq(rmi_spi->irq);
-	if (device_may_wakeup(&spi->dev)) {
-		ret = enable_irq_wake(rmi_spi->irq);
-		if (!ret)
-			dev_warn(dev, "Failed to enable irq for wake: %d\n",
-				ret);
-	}
 	return ret;
 }
 
@@ -509,15 +459,7 @@ static int rmi_spi_resume(struct device *dev)
 	struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
 	int ret;
 
-	enable_irq(rmi_spi->irq);
-	if (device_may_wakeup(&spi->dev)) {
-		ret = disable_irq_wake(rmi_spi->irq);
-		if (!ret)
-			dev_warn(dev, "Failed to disable irq for wake: %d\n",
-				ret);
-	}
-
-	ret = rmi_driver_resume(rmi_spi->xport.rmi_dev);
+	ret = rmi_driver_resume(rmi_spi->xport.rmi_dev, true);
 	if (ret)
 		dev_warn(dev, "Failed to resume device: %d\n", ret);
 
@@ -532,12 +474,10 @@ static int rmi_spi_runtime_suspend(struct device *dev)
 	struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
 	int ret;
 
-	ret = rmi_driver_suspend(rmi_spi->xport.rmi_dev);
+	ret = rmi_driver_suspend(rmi_spi->xport.rmi_dev, false);
 	if (ret)
 		dev_warn(dev, "Failed to resume device: %d\n", ret);
 
-	disable_irq(rmi_spi->irq);
-
 	return 0;
 }
 
@@ -547,9 +487,7 @@ static int rmi_spi_runtime_resume(struct device *dev)
 	struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
 	int ret;
 
-	enable_irq(rmi_spi->irq);
-
-	ret = rmi_driver_resume(rmi_spi->xport.rmi_dev);
+	ret = rmi_driver_resume(rmi_spi->xport.rmi_dev, false);
 	if (ret)
 		dev_warn(dev, "Failed to resume device: %d\n", ret);
 
diff --git a/include/linux/rmi.h b/include/linux/rmi.h
index e0aca14..5944e6c 100644
--- a/include/linux/rmi.h
+++ b/include/linux/rmi.h
@@ -204,9 +204,11 @@ struct rmi_device_platform_data_spi {
  * @reset_delay_ms - after issuing a reset command to the touch sensor, the
  * driver waits a few milliseconds to give the firmware a chance to
  * to re-initialize.  You can override the default wait period here.
+ * @irq: irq associated with the attn gpio line, or negative
  */
 struct rmi_device_platform_data {
 	int reset_delay_ms;
+	int irq;
 
 	struct rmi_device_platform_data_spi spi_data;
 
@@ -352,8 +354,7 @@ struct rmi_driver_data {
 
 int rmi_register_transport_device(struct rmi_transport_dev *xport);
 void rmi_unregister_transport_device(struct rmi_transport_dev *xport);
-int rmi_process_interrupt_requests(struct rmi_device *rmi_dev);
 
-int rmi_driver_suspend(struct rmi_device *rmi_dev);
-int rmi_driver_resume(struct rmi_device *rmi_dev);
+int rmi_driver_suspend(struct rmi_device *rmi_dev, bool enable_wake);
+int rmi_driver_resume(struct rmi_device *rmi_dev, bool clear_wake);
 #endif
-- 
2.7.4

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

* [PATCH v3 02/18] Input: synaptics-rmi4 - factor out functions from probe
  2016-10-13 15:50 [PATCH v3 00/18] Synaptics RMI4 and SMBus implementation Benjamin Tissoires
  2016-10-13 15:50 ` [PATCH v3 01/18] Input: synaptics-rmi4 - Move IRQ handling to rmi_driver Benjamin Tissoires
@ 2016-10-13 15:50 ` Benjamin Tissoires
  2016-10-13 15:50 ` [PATCH v3 03/18] Input: synaptics-rmi4 - Handle incomplete input data Benjamin Tissoires
                   ` (16 subsequent siblings)
  18 siblings, 0 replies; 28+ messages in thread
From: Benjamin Tissoires @ 2016-10-13 15:50 UTC (permalink / raw)
  To: Dmitry Torokhov, Andrew Duggan, Lyude Paul, Christopher Heiny,
	Nick Dyer, Bjorn Andersson, Dennis Wassenberg
  Cc: linux-kernel, linux-input

From: Nick Dyer <nick@shmanahar.org>

Signed-off-by: Nick Dyer <nick@shmanahar.org>
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>

---

new in v3
---
 drivers/input/rmi4/rmi_driver.c | 139 +++++++++++++++++++++++++---------------
 1 file changed, 86 insertions(+), 53 deletions(-)

diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c
index cf780ef..e3f674e 100644
--- a/drivers/input/rmi4/rmi_driver.c
+++ b/drivers/input/rmi4/rmi_driver.c
@@ -40,6 +40,8 @@ static void rmi_free_function_list(struct rmi_device *rmi_dev)
 	struct rmi_function *fn, *tmp;
 	struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
 
+	rmi_dbg(RMI_DEBUG_CORE, &rmi_dev->dev, "Freeing function list\n");
+
 	data->f01_container = NULL;
 
 	/* Doing it in the reverse order so F01 will be removed last */
@@ -904,15 +906,90 @@ static inline int rmi_driver_of_probe(struct device *dev,
 }
 #endif
 
+static int rmi_probe_interrupts(struct rmi_driver_data *data)
+{
+	struct rmi_device *rmi_dev = data->rmi_dev;
+	struct device *dev = &rmi_dev->dev;
+	int irq_count;
+	size_t size;
+	void *irq_memory;
+	int retval;
+
+	/*
+	 * We need to count the IRQs and allocate their storage before scanning
+	 * the PDT and creating the function entries, because adding a new
+	 * function can trigger events that result in the IRQ related storage
+	 * being accessed.
+	 */
+	rmi_dbg(RMI_DEBUG_CORE, dev, "%s: Counting IRQs.\n", __func__);
+	irq_count = 0;
+	retval = rmi_scan_pdt(rmi_dev, &irq_count, rmi_count_irqs);
+	if (retval < 0) {
+		dev_err(dev, "IRQ counting failed with code %d.\n", retval);
+		return retval;
+	}
+	data->irq_count = irq_count;
+	data->num_of_irq_regs = (data->irq_count + 7) / 8;
+
+	size = BITS_TO_LONGS(data->irq_count) * sizeof(unsigned long);
+	irq_memory = devm_kzalloc(dev, size * 4, GFP_KERNEL);
+	if (!irq_memory) {
+		dev_err(dev, "Failed to allocate memory for irq masks.\n");
+		return retval;
+	}
+
+	data->irq_status	= irq_memory + size * 0;
+	data->fn_irq_bits	= irq_memory + size * 1;
+	data->current_irq_mask	= irq_memory + size * 2;
+	data->new_irq_mask	= irq_memory + size * 3;
+
+	return retval;
+}
+
+static int rmi_init_functions(struct rmi_driver_data *data)
+{
+	struct rmi_device *rmi_dev = data->rmi_dev;
+	struct device *dev = &rmi_dev->dev;
+	int irq_count;
+	int retval;
+
+	irq_count = 0;
+	rmi_dbg(RMI_DEBUG_CORE, dev, "%s: Creating functions.\n", __func__);
+	retval = rmi_scan_pdt(rmi_dev, &irq_count, rmi_create_function);
+	if (retval < 0) {
+		dev_err(dev, "Function creation failed with code %d.\n",
+			retval);
+		goto err_destroy_functions;
+	}
+
+	if (!data->f01_container) {
+		dev_err(dev, "Missing F01 container!\n");
+		retval = -EINVAL;
+		goto err_destroy_functions;
+	}
+
+	retval = rmi_read_block(rmi_dev,
+				data->f01_container->fd.control_base_addr + 1,
+				data->current_irq_mask, data->num_of_irq_regs);
+	if (retval < 0) {
+		dev_err(dev, "%s: Failed to read current IRQ mask.\n",
+			__func__);
+		goto err_destroy_functions;
+	}
+
+	return 0;
+
+err_destroy_functions:
+	rmi_free_function_list(rmi_dev);
+	return retval;
+}
+
 static int rmi_driver_probe(struct device *dev)
 {
 	struct rmi_driver *rmi_driver;
 	struct rmi_driver_data *data;
 	struct rmi_device_platform_data *pdata;
 	struct rmi_device *rmi_dev;
-	size_t size;
-	void *irq_memory;
-	int irq_count;
 	int retval;
 
 	rmi_dbg(RMI_DEBUG_CORE, dev, "%s: Starting probe.\n",
@@ -978,35 +1055,11 @@ static int rmi_driver_probe(struct device *dev)
 			 PDT_PROPERTIES_LOCATION, retval);
 	}
 
-	/*
-	 * We need to count the IRQs and allocate their storage before scanning
-	 * the PDT and creating the function entries, because adding a new
-	 * function can trigger events that result in the IRQ related storage
-	 * being accessed.
-	 */
-	rmi_dbg(RMI_DEBUG_CORE, dev, "Counting IRQs.\n");
-	irq_count = 0;
-	retval = rmi_scan_pdt(rmi_dev, &irq_count, rmi_count_irqs);
-	if (retval < 0) {
-		dev_err(dev, "IRQ counting failed with code %d.\n", retval);
-		goto err;
-	}
-	data->irq_count = irq_count;
-	data->num_of_irq_regs = (data->irq_count + 7) / 8;
-
 	mutex_init(&data->irq_mutex);
 
-	size = BITS_TO_LONGS(data->irq_count) * sizeof(unsigned long);
-	irq_memory = devm_kzalloc(dev, size * 4, GFP_KERNEL);
-	if (!irq_memory) {
-		dev_err(dev, "Failed to allocate memory for irq masks.\n");
+	retval = rmi_probe_interrupts(data);
+	if (retval)
 		goto err;
-	}
-
-	data->irq_status	= irq_memory + size * 0;
-	data->fn_irq_bits	= irq_memory + size * 1;
-	data->current_irq_mask	= irq_memory + size * 2;
-	data->new_irq_mask	= irq_memory + size * 3;
 
 	if (rmi_dev->xport->input) {
 		/*
@@ -1023,36 +1076,16 @@ static int rmi_driver_probe(struct device *dev)
 			dev_err(dev, "%s: Failed to allocate input device.\n",
 				__func__);
 			retval = -ENOMEM;
-			goto err_destroy_functions;
+			goto err;
 		}
 		rmi_driver_set_input_params(rmi_dev, data->input);
 		data->input->phys = devm_kasprintf(dev, GFP_KERNEL,
 						"%s/input0", dev_name(dev));
 	}
 
-	irq_count = 0;
-	rmi_dbg(RMI_DEBUG_CORE, dev, "Creating functions.");
-	retval = rmi_scan_pdt(rmi_dev, &irq_count, rmi_create_function);
-	if (retval < 0) {
-		dev_err(dev, "Function creation failed with code %d.\n",
-			retval);
-		goto err_destroy_functions;
-	}
-
-	if (!data->f01_container) {
-		dev_err(dev, "Missing F01 container!\n");
-		retval = -EINVAL;
-		goto err_destroy_functions;
-	}
-
-	retval = rmi_read_block(rmi_dev,
-				data->f01_container->fd.control_base_addr + 1,
-				data->current_irq_mask, data->num_of_irq_regs);
-	if (retval < 0) {
-		dev_err(dev, "%s: Failed to read current IRQ mask.\n",
-			__func__);
-		goto err_destroy_functions;
-	}
+	retval = rmi_init_functions(data);
+	if (retval)
+		goto err;
 
 	if (data->input) {
 		rmi_driver_set_input_name(rmi_dev, data->input);
-- 
2.7.4

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

* [PATCH v3 03/18] Input: synaptics-rmi4 - Handle incomplete input data
  2016-10-13 15:50 [PATCH v3 00/18] Synaptics RMI4 and SMBus implementation Benjamin Tissoires
  2016-10-13 15:50 ` [PATCH v3 01/18] Input: synaptics-rmi4 - Move IRQ handling to rmi_driver Benjamin Tissoires
  2016-10-13 15:50 ` [PATCH v3 02/18] Input: synaptics-rmi4 - factor out functions from probe Benjamin Tissoires
@ 2016-10-13 15:50 ` Benjamin Tissoires
  2016-11-09  0:46   ` Dmitry Torokhov
  2016-10-13 15:50 ` [PATCH v3 04/18] Input: synaptics-rmi4 - Add parameters for dribble packets and palm detect gesture Benjamin Tissoires
                   ` (15 subsequent siblings)
  18 siblings, 1 reply; 28+ messages in thread
From: Benjamin Tissoires @ 2016-10-13 15:50 UTC (permalink / raw)
  To: Dmitry Torokhov, Andrew Duggan, Lyude Paul, Christopher Heiny,
	Nick Dyer, Bjorn Andersson, Dennis Wassenberg
  Cc: linux-kernel, linux-input

From: Andrew Duggan <aduggan@synaptics.com>

Commit 5b65c2a02966 ("HID: rmi: check sanity of the incoming report") added
support for handling incomplete HID reports do to the input data being
corrupted in transit. This patch reimplements this functionality in the
function drivers so they can handle getting less valid data then they
expect.

Signed-off-by: Andrew Duggan <aduggan@synaptics.com>
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>

---

new in v3
---
 drivers/input/rmi4/rmi_f11.c | 54 ++++++++++++++++++++++++++++++++------------
 drivers/input/rmi4/rmi_f12.c | 23 ++++++++++++++-----
 drivers/input/rmi4/rmi_f30.c |  4 ++++
 3 files changed, 61 insertions(+), 20 deletions(-)

diff --git a/drivers/input/rmi4/rmi_f11.c b/drivers/input/rmi4/rmi_f11.c
index 20c7134..3218742 100644
--- a/drivers/input/rmi4/rmi_f11.c
+++ b/drivers/input/rmi4/rmi_f11.c
@@ -572,31 +572,48 @@ static inline u8 rmi_f11_parse_finger_state(const u8 *f_state, u8 n_finger)
 
 static void rmi_f11_finger_handler(struct f11_data *f11,
 				   struct rmi_2d_sensor *sensor,
-				   unsigned long *irq_bits, int num_irq_regs)
+				   unsigned long *irq_bits, int num_irq_regs,
+				   int size)
 {
 	const u8 *f_state = f11->data.f_state;
 	u8 finger_state;
 	u8 i;
+	int abs_fingers;
+	int rel_fingers;
+	int abs_size = sensor->nbr_fingers * RMI_F11_ABS_BYTES;
 
 	int abs_bits = bitmap_and(f11->result_bits, irq_bits, f11->abs_mask,
 				  num_irq_regs * 8);
 	int rel_bits = bitmap_and(f11->result_bits, irq_bits, f11->rel_mask,
 				  num_irq_regs * 8);
 
-	for (i = 0; i < sensor->nbr_fingers; i++) {
-		/* Possible of having 4 fingers per f_statet register */
-		finger_state = rmi_f11_parse_finger_state(f_state, i);
-		if (finger_state == F11_RESERVED) {
-			pr_err("Invalid finger state[%d]: 0x%02x", i,
-				finger_state);
-			continue;
-		}
+	if (abs_bits) {
+		if (abs_size > size)
+			abs_fingers = size / RMI_F11_ABS_BYTES;
+		else
+			abs_fingers = sensor->nbr_fingers;
+
+		for (i = 0; i < abs_fingers; i++) {
+			/* Possible of having 4 fingers per f_state register */
+			finger_state = rmi_f11_parse_finger_state(f_state, i);
+			if (finger_state == F11_RESERVED) {
+				pr_err("Invalid finger state[%d]: 0x%02x", i,
+					finger_state);
+				continue;
+			}
 
-		if (abs_bits)
 			rmi_f11_abs_pos_process(f11, sensor, &sensor->objs[i],
 							finger_state, i);
+		}
+	}
+
+	if (rel_bits) {
+		if ((abs_size + sensor->nbr_fingers * RMI_F11_REL_BYTES) > size)
+			rel_fingers = (size - abs_size) / RMI_F11_REL_BYTES;
+		else
+			rel_fingers = sensor->nbr_fingers;
 
-		if (rel_bits)
+		for (i = 0; i < rel_fingers; i++)
 			rmi_f11_rel_pos_report(f11, i);
 	}
 
@@ -612,7 +629,7 @@ static void rmi_f11_finger_handler(struct f11_data *f11,
 					      sensor->nbr_fingers,
 					      sensor->dmax);
 
-		for (i = 0; i < sensor->nbr_fingers; i++) {
+		for (i = 0; i < abs_fingers; i++) {
 			finger_state = rmi_f11_parse_finger_state(f_state, i);
 			if (finger_state == F11_RESERVED)
 				/* no need to send twice the error */
@@ -1242,10 +1259,19 @@ static int rmi_f11_attention(struct rmi_function *fn, unsigned long *irq_bits)
 	struct f11_data *f11 = dev_get_drvdata(&fn->dev);
 	u16 data_base_addr = fn->fd.data_base_addr;
 	int error;
+	int valid_bytes = f11->sensor.pkt_size;
 
 	if (rmi_dev->xport->attn_data) {
+		/*
+		 * The valid data in the attention report is less then
+		 * expected. Only process the complete fingers.
+		 */
+		if (f11->sensor.attn_size > rmi_dev->xport->attn_size)
+			valid_bytes = rmi_dev->xport->attn_size;
+		else
+			valid_bytes = f11->sensor.attn_size;
 		memcpy(f11->sensor.data_pkt, rmi_dev->xport->attn_data,
-			f11->sensor.attn_size);
+			valid_bytes);
 		rmi_dev->xport->attn_data += f11->sensor.attn_size;
 		rmi_dev->xport->attn_size -= f11->sensor.attn_size;
 	} else {
@@ -1257,7 +1283,7 @@ static int rmi_f11_attention(struct rmi_function *fn, unsigned long *irq_bits)
 	}
 
 	rmi_f11_finger_handler(f11, &f11->sensor, irq_bits,
-				drvdata->num_of_irq_regs);
+				drvdata->num_of_irq_regs, valid_bytes);
 
 	return 0;
 }
diff --git a/drivers/input/rmi4/rmi_f12.c b/drivers/input/rmi4/rmi_f12.c
index 332c02f..767ac79 100644
--- a/drivers/input/rmi4/rmi_f12.c
+++ b/drivers/input/rmi4/rmi_f12.c
@@ -26,6 +26,8 @@ enum rmi_f12_object_type {
 	RMI_F12_OBJECT_SMALL_OBJECT		= 0x0D,
 };
 
+#define F12_DATA1_BYTES_PER_OBJ			8
+
 struct f12_data {
 	struct rmi_2d_sensor sensor;
 	struct rmi_2d_sensor_platform_data sensor_pdata;
@@ -146,12 +148,16 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12)
 	return 0;
 }
 
-static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1)
+static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1, int size)
 {
 	int i;
 	struct rmi_2d_sensor *sensor = &f12->sensor;
+	int objects = f12->data1->num_subpackets;
+
+	if ((f12->data1->num_subpackets * F12_DATA1_BYTES_PER_OBJ) > size)
+		objects = size / F12_DATA1_BYTES_PER_OBJ;
 
-	for (i = 0; i < f12->data1->num_subpackets; i++) {
+	for (i = 0; i < objects; i++) {
 		struct rmi_2d_sensor_abs_object *obj = &sensor->objs[i];
 
 		obj->type = RMI_2D_OBJECT_NONE;
@@ -182,7 +188,7 @@ static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1)
 
 		rmi_2d_sensor_abs_process(sensor, obj, i);
 
-		data1 += 8;
+		data1 += F12_DATA1_BYTES_PER_OBJ;
 	}
 
 	if (sensor->kernel_tracking)
@@ -192,7 +198,7 @@ static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1)
 				      sensor->nbr_fingers,
 				      sensor->dmax);
 
-	for (i = 0; i < sensor->nbr_fingers; i++)
+	for (i = 0; i < objects; i++)
 		rmi_2d_sensor_abs_report(sensor, &sensor->objs[i], i);
 }
 
@@ -203,10 +209,15 @@ static int rmi_f12_attention(struct rmi_function *fn,
 	struct rmi_device *rmi_dev = fn->rmi_dev;
 	struct f12_data *f12 = dev_get_drvdata(&fn->dev);
 	struct rmi_2d_sensor *sensor = &f12->sensor;
+	int valid_bytes = sensor->pkt_size;
 
 	if (rmi_dev->xport->attn_data) {
+		if (sensor->attn_size > rmi_dev->xport->attn_size)
+			valid_bytes = rmi_dev->xport->attn_size;
+		else
+			valid_bytes = sensor->attn_size;
 		memcpy(sensor->data_pkt, rmi_dev->xport->attn_data,
-			sensor->attn_size);
+			valid_bytes);
 		rmi_dev->xport->attn_data += sensor->attn_size;
 		rmi_dev->xport->attn_size -= sensor->attn_size;
 	} else {
@@ -221,7 +232,7 @@ static int rmi_f12_attention(struct rmi_function *fn,
 
 	if (f12->data1)
 		rmi_f12_process_objects(f12,
-			&sensor->data_pkt[f12->data1_offset]);
+			&sensor->data_pkt[f12->data1_offset], valid_bytes);
 
 	input_mt_sync_frame(sensor->input);
 
diff --git a/drivers/input/rmi4/rmi_f30.c b/drivers/input/rmi4/rmi_f30.c
index 760aff1..485907f 100644
--- a/drivers/input/rmi4/rmi_f30.c
+++ b/drivers/input/rmi4/rmi_f30.c
@@ -110,6 +110,10 @@ static int rmi_f30_attention(struct rmi_function *fn, unsigned long *irq_bits)
 
 	/* Read the gpi led data. */
 	if (rmi_dev->xport->attn_data) {
+		if (rmi_dev->xport->attn_size < f30->register_count) {
+			dev_warn(&fn->dev, "F30 interrupted, but data is missing\n");
+			return 0;
+		}
 		memcpy(f30->data_regs, rmi_dev->xport->attn_data,
 			f30->register_count);
 		rmi_dev->xport->attn_data += f30->register_count;
-- 
2.7.4

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

* [PATCH v3 04/18] Input: synaptics-rmi4 - Add parameters for dribble packets and palm detect gesture
  2016-10-13 15:50 [PATCH v3 00/18] Synaptics RMI4 and SMBus implementation Benjamin Tissoires
                   ` (2 preceding siblings ...)
  2016-10-13 15:50 ` [PATCH v3 03/18] Input: synaptics-rmi4 - Handle incomplete input data Benjamin Tissoires
@ 2016-10-13 15:50 ` Benjamin Tissoires
  2016-11-09  0:51   ` Dmitry Torokhov
  2016-10-13 15:50 ` [PATCH v3 05/18] Input: synaptics-rmi4 - Add support for controlling dribble packets in F12 Benjamin Tissoires
                   ` (14 subsequent siblings)
  18 siblings, 1 reply; 28+ messages in thread
From: Benjamin Tissoires @ 2016-10-13 15:50 UTC (permalink / raw)
  To: Dmitry Torokhov, Andrew Duggan, Lyude Paul, Christopher Heiny,
	Nick Dyer, Bjorn Andersson, Dennis Wassenberg
  Cc: linux-kernel, linux-input

From: Andrew Duggan <aduggan@synaptics.com>

The rmi_f11 driver currently disables dribble packets and the palm detect
gesture for all devices. This patch creates a parameter in the 2d sensor
platform data for controlling this functionality on a per device basis.

For more information on dribble packets:
Commit 05ba999fcabb ("HID: rmi: disable dribble packets on Synaptics
touchpads")

For more information on the palm detect gesture:
Commit f097deef59a6 ("HID: rmi: disable palm detect gesture when present")

Signed-off-by: Andrew Duggan <aduggan@synaptics.com>
Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>

---

new in v3
---
 drivers/input/rmi4/rmi_2d_sensor.h |  2 ++
 drivers/input/rmi4/rmi_f01.c       |  6 +++---
 drivers/input/rmi4/rmi_f11.c       | 32 ++++++++++++++++++++++++++++----
 include/linux/rmi.h                | 21 +++++++++++++--------
 4 files changed, 46 insertions(+), 15 deletions(-)

diff --git a/drivers/input/rmi4/rmi_2d_sensor.h b/drivers/input/rmi4/rmi_2d_sensor.h
index 77fcdfe..c871bef 100644
--- a/drivers/input/rmi4/rmi_2d_sensor.h
+++ b/drivers/input/rmi4/rmi_2d_sensor.h
@@ -67,6 +67,8 @@ struct rmi_2d_sensor {
 	u8 report_rel;
 	u8 x_mm;
 	u8 y_mm;
+	enum rmi_reg_state dribble;
+	enum rmi_reg_state palm_detect;
 };
 
 int rmi_2d_sensor_of_probe(struct device *dev,
diff --git a/drivers/input/rmi4/rmi_f01.c b/drivers/input/rmi4/rmi_f01.c
index fac81fc..2cfa9f6 100644
--- a/drivers/input/rmi4/rmi_f01.c
+++ b/drivers/input/rmi4/rmi_f01.c
@@ -327,12 +327,12 @@ static int rmi_f01_probe(struct rmi_function *fn)
 	}
 
 	switch (pdata->power_management.nosleep) {
-	case RMI_F01_NOSLEEP_DEFAULT:
+	case RMI_REG_STATE_DEFAULT:
 		break;
-	case RMI_F01_NOSLEEP_OFF:
+	case RMI_REG_STATE_OFF:
 		f01->device_control.ctrl0 &= ~RMI_F01_CTRL0_NOSLEEP_BIT;
 		break;
-	case RMI_F01_NOSLEEP_ON:
+	case RMI_REG_STATE_ON:
 		f01->device_control.ctrl0 |= RMI_F01_CTRL0_NOSLEEP_BIT;
 		break;
 	}
diff --git a/drivers/input/rmi4/rmi_f11.c b/drivers/input/rmi4/rmi_f11.c
index 3218742..cce82a1 100644
--- a/drivers/input/rmi4/rmi_f11.c
+++ b/drivers/input/rmi4/rmi_f11.c
@@ -1142,6 +1142,8 @@ static int rmi_f11_initialize(struct rmi_function *fn)
 	sensor->topbuttonpad = f11->sensor_pdata.topbuttonpad;
 	sensor->kernel_tracking = f11->sensor_pdata.kernel_tracking;
 	sensor->dmax = f11->sensor_pdata.dmax;
+	sensor->dribble = f11->sensor_pdata.dribble;
+	sensor->palm_detect = f11->sensor_pdata.palm_detect;
 
 	if (f11->sens_query.has_physical_props) {
 		sensor->x_mm = f11->sens_query.x_sensor_size_mm;
@@ -1209,11 +1211,33 @@ static int rmi_f11_initialize(struct rmi_function *fn)
 		ctrl->ctrl0_11[RMI_F11_DELTA_Y_THRESHOLD] =
 			sensor->axis_align.delta_y_threshold;
 
-	if (f11->sens_query.has_dribble)
-		ctrl->ctrl0_11[0] = ctrl->ctrl0_11[0] & ~BIT(6);
+	if (f11->sens_query.has_dribble) {
+		switch (sensor->dribble) {
+		case RMI_REG_STATE_OFF:
+			ctrl->ctrl0_11[0] = ctrl->ctrl0_11[0] & ~BIT(6);
+			break;
+		case RMI_REG_STATE_ON:
+			ctrl->ctrl0_11[0] = ctrl->ctrl0_11[0] | BIT(6);
+			break;
+		case RMI_REG_STATE_DEFAULT:
+		default:
+			break;
+		}
+	}
 
-	if (f11->sens_query.has_palm_det)
-		ctrl->ctrl0_11[11] = ctrl->ctrl0_11[11] & ~BIT(0);
+	if (f11->sens_query.has_palm_det) {
+		switch (sensor->palm_detect) {
+		case RMI_REG_STATE_OFF:
+			ctrl->ctrl0_11[11] = ctrl->ctrl0_11[11] & ~BIT(0);
+			break;
+		case RMI_REG_STATE_ON:
+			ctrl->ctrl0_11[11] = ctrl->ctrl0_11[11] & BIT(0);
+			break;
+		case RMI_REG_STATE_DEFAULT:
+		default:
+			break;
+		}
+	}
 
 	rc = f11_write_control_regs(fn, &f11->sens_query,
 			   &f11->dev_controls, fn->fd.query_base_addr);
diff --git a/include/linux/rmi.h b/include/linux/rmi.h
index 5944e6c..ac904bb 100644
--- a/include/linux/rmi.h
+++ b/include/linux/rmi.h
@@ -99,6 +99,8 @@ struct rmi_2d_sensor_platform_data {
 	bool topbuttonpad;
 	bool kernel_tracking;
 	int dmax;
+	int dribble;
+	int palm_detect;
 };
 
 /**
@@ -116,14 +118,17 @@ struct rmi_f30_data {
 	bool disable;
 };
 
-/**
- * struct rmi_f01_power - override default power management settings.
- *
+
+/*
+ * Set the state of a register
+ *	DEFAULT - use the default value set by the firmware config
+ *	OFF - explicitly disable the register
+ *	ON - explicitly enable the register
  */
-enum rmi_f01_nosleep {
-	RMI_F01_NOSLEEP_DEFAULT = 0,
-	RMI_F01_NOSLEEP_OFF = 1,
-	RMI_F01_NOSLEEP_ON = 2
+enum rmi_reg_state {
+	RMI_REG_STATE_DEFAULT = 0,
+	RMI_REG_STATE_OFF = 1,
+	RMI_REG_STATE_ON = 2
 };
 
 /**
@@ -143,7 +148,7 @@ enum rmi_f01_nosleep {
  * when the touch sensor is in doze mode, in units of 10ms.
  */
 struct rmi_f01_power_management {
-	enum rmi_f01_nosleep nosleep;
+	enum rmi_reg_state nosleep;
 	u8 wakeup_threshold;
 	u8 doze_holdoff;
 	u8 doze_interval;
-- 
2.7.4

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

* [PATCH v3 05/18] Input: synaptics-rmi4 - Add support for controlling dribble packets in F12
  2016-10-13 15:50 [PATCH v3 00/18] Synaptics RMI4 and SMBus implementation Benjamin Tissoires
                   ` (3 preceding siblings ...)
  2016-10-13 15:50 ` [PATCH v3 04/18] Input: synaptics-rmi4 - Add parameters for dribble packets and palm detect gesture Benjamin Tissoires
@ 2016-10-13 15:50 ` Benjamin Tissoires
  2016-11-09  1:02   ` Dmitry Torokhov
  2016-10-13 15:51 ` [PATCH v3 06/18] Input: synaptics-rmi4 - Set the ABS_MT_TOOL_TYPE bit to report tool type Benjamin Tissoires
                   ` (13 subsequent siblings)
  18 siblings, 1 reply; 28+ messages in thread
From: Benjamin Tissoires @ 2016-10-13 15:50 UTC (permalink / raw)
  To: Dmitry Torokhov, Andrew Duggan, Lyude Paul, Christopher Heiny,
	Nick Dyer, Bjorn Andersson, Dennis Wassenberg
  Cc: linux-kernel, linux-input

From: Andrew Duggan <aduggan@synaptics.com>

Implements reading and setting the dribble bit in F12's control registers.

Signed-off-by: Andrew Duggan <aduggan@synaptics.com>
Acked-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>

---

new in v3
---
 drivers/input/rmi4/rmi_f12.c | 73 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 72 insertions(+), 1 deletion(-)

diff --git a/drivers/input/rmi4/rmi_f12.c b/drivers/input/rmi4/rmi_f12.c
index 767ac79..f79a785 100644
--- a/drivers/input/rmi4/rmi_f12.c
+++ b/drivers/input/rmi4/rmi_f12.c
@@ -31,6 +31,7 @@ enum rmi_f12_object_type {
 struct f12_data {
 	struct rmi_2d_sensor sensor;
 	struct rmi_2d_sensor_platform_data sensor_pdata;
+	bool has_dribble;
 
 	u16 data_addr;
 
@@ -239,12 +240,79 @@ static int rmi_f12_attention(struct rmi_function *fn,
 	return 0;
 }
 
+static int rmi_f12_write_control_regs(struct rmi_function *fn)
+{
+	int ret;
+	const struct rmi_register_desc_item *item;
+	struct rmi_device *rmi_dev = fn->rmi_dev;
+	struct f12_data *f12 = dev_get_drvdata(&fn->dev);
+	int control_size;
+	char buf[3];
+	u16 control_offset = 0;
+	u8 subpacket_offset = 0;
+
+	if (f12->has_dribble
+	    && (f12->sensor.dribble != RMI_REG_STATE_DEFAULT)) {
+		item = rmi_get_register_desc_item(&f12->control_reg_desc, 20);
+		if (item) {
+			control_offset = rmi_register_desc_calc_reg_offset(
+						&f12->control_reg_desc, 20);
+
+			/*
+			 * The byte containing the EnableDribble bit will be
+			 * in either byte 0 or byte 2 of control 20. Depending
+			 * on the existence of subpacket 0. If control 20 is
+			 * larger then 3 bytes, just read the first 3.
+			 */
+			if (item->reg_size >= 3)
+				control_size = 3;
+			else
+				control_size = item->reg_size;
+
+			ret = rmi_read_block(rmi_dev, fn->fd.control_base_addr
+					+ control_offset, buf, control_size);
+			if (ret)
+				return ret;
+
+			if (rmi_register_desc_has_subpacket(item, 0))
+				subpacket_offset += 1;
+
+			switch (f12->sensor.dribble) {
+			case RMI_REG_STATE_OFF:
+				buf[subpacket_offset] &= ~BIT(2);
+				break;
+			case RMI_REG_STATE_ON:
+				buf[subpacket_offset] |= BIT(2);
+				break;
+			case RMI_REG_STATE_DEFAULT:
+			default:
+				break;
+			}
+
+			ret = rmi_write_block(rmi_dev,
+				fn->fd.control_base_addr + control_offset,
+				buf, control_size);
+			if (ret)
+				return ret;
+		}
+	}
+
+	return 0;
+
+}
+
 static int rmi_f12_config(struct rmi_function *fn)
 {
 	struct rmi_driver *drv = fn->rmi_dev->driver;
+	int ret;
 
 	drv->set_irq_bits(fn->rmi_dev, fn->irq_mask);
 
+	ret = rmi_f12_write_control_regs(fn);
+	if (ret)
+		dev_warn(&fn->dev,
+			"Failed to write F12 control registers: %d\n", ret);
+
 	return 0;
 }
 
@@ -271,7 +339,7 @@ static int rmi_f12_probe(struct rmi_function *fn)
 	}
 	++query_addr;
 
-	if (!(buf & 0x1)) {
+	if (!(buf & BIT(0))) {
 		dev_err(&fn->dev,
 			"Behavior of F12 without register descriptors is undefined.\n");
 		return -ENODEV;
@@ -281,6 +349,8 @@ static int rmi_f12_probe(struct rmi_function *fn)
 	if (!f12)
 		return -ENOMEM;
 
+	f12->has_dribble = !!(buf & BIT(3));
+
 	if (fn->dev.of_node) {
 		ret = rmi_2d_sensor_of_probe(&fn->dev, &f12->sensor_pdata);
 		if (ret)
@@ -329,6 +399,7 @@ static int rmi_f12_probe(struct rmi_function *fn)
 
 	sensor->x_mm = f12->sensor_pdata.x_mm;
 	sensor->y_mm = f12->sensor_pdata.y_mm;
+	sensor->dribble = f12->sensor_pdata.dribble;
 
 	if (sensor->sensor_type == rmi_sensor_default)
 		sensor->sensor_type =
-- 
2.7.4

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

* [PATCH v3 06/18] Input: synaptics-rmi4 - Set the ABS_MT_TOOL_TYPE bit to report tool type
  2016-10-13 15:50 [PATCH v3 00/18] Synaptics RMI4 and SMBus implementation Benjamin Tissoires
                   ` (4 preceding siblings ...)
  2016-10-13 15:50 ` [PATCH v3 05/18] Input: synaptics-rmi4 - Add support for controlling dribble packets in F12 Benjamin Tissoires
@ 2016-10-13 15:51 ` Benjamin Tissoires
  2016-11-09  1:03   ` Dmitry Torokhov
  2016-10-13 15:51 ` [PATCH v3 07/18] Input: synaptics-rmi4 - add SMBus support Benjamin Tissoires
                   ` (12 subsequent siblings)
  18 siblings, 1 reply; 28+ messages in thread
From: Benjamin Tissoires @ 2016-10-13 15:51 UTC (permalink / raw)
  To: Dmitry Torokhov, Andrew Duggan, Lyude Paul, Christopher Heiny,
	Nick Dyer, Bjorn Andersson, Dennis Wassenberg
  Cc: linux-kernel, linux-input

From: Andrew Duggan <aduggan@synaptics.com>

The rmi4 2D sensor functions report the tool type via
input_mt_report_slot_state(), but the abs parameter bit has not been
set so the tool type is not reported to userspace. This patch set
the ABS_MT_TOOL_TYPE bit.

Signed-off-by: Andrew Duggan <aduggan@synaptics.com>
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>

---

new in v3
---
 drivers/input/rmi4/rmi_2d_sensor.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/input/rmi4/rmi_2d_sensor.c b/drivers/input/rmi4/rmi_2d_sensor.c
index e97bd7f..0747890 100644
--- a/drivers/input/rmi4/rmi_2d_sensor.c
+++ b/drivers/input/rmi4/rmi_2d_sensor.c
@@ -181,6 +181,8 @@ static void rmi_2d_sensor_set_input_params(struct rmi_2d_sensor *sensor)
 		input_set_abs_params(input, ABS_MT_TOUCH_MAJOR,	0, 0x0f, 0, 0);
 		input_set_abs_params(input, ABS_MT_TOUCH_MINOR,	0, 0x0f, 0, 0);
 		input_set_abs_params(input, ABS_MT_ORIENTATION,	0, 1, 0, 0);
+		input_set_abs_params(input, ABS_MT_TOOL_TYPE, 0, MT_TOOL_MAX,
+					0, 0);
 
 		if (sensor->sensor_type == rmi_sensor_touchpad)
 			input_flags = INPUT_MT_POINTER;
-- 
2.7.4

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

* [PATCH v3 07/18] Input: synaptics-rmi4 - add SMBus support
  2016-10-13 15:50 [PATCH v3 00/18] Synaptics RMI4 and SMBus implementation Benjamin Tissoires
                   ` (5 preceding siblings ...)
  2016-10-13 15:51 ` [PATCH v3 06/18] Input: synaptics-rmi4 - Set the ABS_MT_TOOL_TYPE bit to report tool type Benjamin Tissoires
@ 2016-10-13 15:51 ` Benjamin Tissoires
  2016-11-09  1:08   ` Dmitry Torokhov
  2016-10-13 15:51 ` [PATCH v3 08/18] Input: serio - store the pt_buttons in the struct serio directly Benjamin Tissoires
                   ` (11 subsequent siblings)
  18 siblings, 1 reply; 28+ messages in thread
From: Benjamin Tissoires @ 2016-10-13 15:51 UTC (permalink / raw)
  To: Dmitry Torokhov, Andrew Duggan, Lyude Paul, Christopher Heiny,
	Nick Dyer, Bjorn Andersson, Dennis Wassenberg
  Cc: linux-kernel, linux-input

Code obtained from https://raw.githubusercontent.com/mightybigcar/synaptics-rmi4/jf/drivers/input/rmi4/rmi_smbus.c
and updated to match upstream. And fixed to make it work.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: Andrew Duggan <aduggan@synaptics.com>

---

changes in v3:
- use of irq for Host Notify, not alert
- forward the irq to rmi_core and let it handling it

no changes in v2

Changes in v1 of this series:
- rely on PM functions for resume handling

Changes from the Host Notify series:
new in v5

no changes in v6

changes in v7:
- fixed typos as per Andrew's requests
- changed module author from Allie to Andrew as per Andrew's request
- add suspend/resume callbacks to match upstream rmi4 behavior

no changes in v8
---
 drivers/input/rmi4/Kconfig     |  12 ++
 drivers/input/rmi4/Makefile    |   1 +
 drivers/input/rmi4/rmi_bus.h   |  12 ++
 drivers/input/rmi4/rmi_smbus.c | 448 +++++++++++++++++++++++++++++++++++++++++
 4 files changed, 473 insertions(+)
 create mode 100644 drivers/input/rmi4/rmi_smbus.c

diff --git a/drivers/input/rmi4/Kconfig b/drivers/input/rmi4/Kconfig
index 4c8a558..8cbd362 100644
--- a/drivers/input/rmi4/Kconfig
+++ b/drivers/input/rmi4/Kconfig
@@ -27,6 +27,18 @@ config RMI4_SPI
 
 	  If unsure, say N.
 
+config RMI4_SMB
+	tristate "RMI4 SMB Support"
+	depends on RMI4_CORE && I2C
+	help
+	  Say Y here if you want to support RMI4 devices connected to an SMB
+	  bus.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called rmi_smbus.
+
 config RMI4_2D_SENSOR
 	bool
 	depends on RMI4_CORE
diff --git a/drivers/input/rmi4/Makefile b/drivers/input/rmi4/Makefile
index 0bafc85..a6e2752 100644
--- a/drivers/input/rmi4/Makefile
+++ b/drivers/input/rmi4/Makefile
@@ -12,3 +12,4 @@ rmi_core-$(CONFIG_RMI4_F54) += rmi_f54.o
 # Transports
 obj-$(CONFIG_RMI4_I2C) += rmi_i2c.o
 obj-$(CONFIG_RMI4_SPI) += rmi_spi.o
+obj-$(CONFIG_RMI4_SMB) += rmi_smbus.o
diff --git a/drivers/input/rmi4/rmi_bus.h b/drivers/input/rmi4/rmi_bus.h
index 8995798..b7625a9 100644
--- a/drivers/input/rmi4/rmi_bus.h
+++ b/drivers/input/rmi4/rmi_bus.h
@@ -105,6 +105,18 @@ rmi_get_platform_data(struct rmi_device *d)
 bool rmi_is_physical_device(struct device *dev);
 
 /**
+ * rmi_reset - reset a RMI4 device
+ * @d: Pointer to an RMI device
+ *
+ * Calls for a reset of each function implemented by a specific device.
+ * Returns 0 on success or a negative error code.
+ */
+static inline int rmi_reset(struct rmi_device *d)
+{
+	return d->driver->reset_handler(d);
+}
+
+/**
  * rmi_read - read a single byte
  * @d: Pointer to an RMI device
  * @addr: The address to read from
diff --git a/drivers/input/rmi4/rmi_smbus.c b/drivers/input/rmi4/rmi_smbus.c
new file mode 100644
index 0000000..96ad325
--- /dev/null
+++ b/drivers/input/rmi4/rmi_smbus.c
@@ -0,0 +1,448 @@
+/*
+ * Copyright (c) 2015 - 2016 Red Hat, Inc
+ * Copyright (c) 2011, 2012 Synaptics Incorporated
+ * Copyright (c) 2011 Unixphere
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/kconfig.h>
+#include <linux/lockdep.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/rmi.h>
+#include <linux/slab.h>
+#include "rmi_driver.h"
+
+#define SMB_PROTOCOL_VERSION_ADDRESS	0xfd
+#define SMB_MAX_COUNT			32
+#define RMI_SMB2_MAP_SIZE		8 /* 8 entry of 4 bytes each */
+#define RMI_SMB2_MAP_FLAGS_WE		0x01
+
+struct mapping_table_entry {
+	__le16 rmiaddr;
+	u8 readcount;
+	u8 flags;
+};
+
+struct rmi_smb_xport {
+	struct rmi_transport_dev xport;
+	struct i2c_client *client;
+
+	struct mutex page_mutex;
+	int page;
+	u8 table_index;
+	struct mutex mappingtable_mutex;
+	struct mapping_table_entry mapping_table[RMI_SMB2_MAP_SIZE];
+};
+
+static int rmi_smb_get_version(struct rmi_smb_xport *rmi_smb)
+{
+	struct i2c_client *client = rmi_smb->client;
+	int retval;
+
+	/* Check if for SMBus new version device by reading version byte. */
+	retval = i2c_smbus_read_byte_data(client, SMB_PROTOCOL_VERSION_ADDRESS);
+	if (retval < 0) {
+		dev_err(&client->dev, "failed to get SMBus version number!\n");
+		return retval;
+	}
+	return retval + 1;
+}
+
+/* SMB block write - wrapper over ic2_smb_write_block */
+static int smb_block_write(struct rmi_transport_dev *xport,
+			      u8 commandcode, const void *buf, size_t len)
+{
+	struct rmi_smb_xport *rmi_smb =
+		container_of(xport, struct rmi_smb_xport, xport);
+	struct i2c_client *client = rmi_smb->client;
+	int retval;
+
+	retval = i2c_smbus_write_block_data(client, commandcode, len, buf);
+
+	rmi_dbg(RMI_DEBUG_XPORT, &client->dev,
+		"wrote %zd bytes at %#04x: %d (%*ph)\n",
+		len, commandcode, retval, (int)len, buf);
+
+	return retval;
+}
+
+/*
+ * The function to get command code for smbus operations and keeps
+ * records to the driver mapping table
+ */
+static int rmi_smb_get_command_code(struct rmi_transport_dev *xport,
+		u16 rmiaddr, int bytecount, bool isread, u8 *commandcode)
+{
+	struct rmi_smb_xport *rmi_smb =
+		container_of(xport, struct rmi_smb_xport, xport);
+	int i;
+	int retval;
+	struct mapping_table_entry mapping_data[1];
+
+	mutex_lock(&rmi_smb->mappingtable_mutex);
+	for (i = 0; i < RMI_SMB2_MAP_SIZE; i++) {
+		if (rmi_smb->mapping_table[i].rmiaddr == rmiaddr) {
+			if (isread) {
+				if (rmi_smb->mapping_table[i].readcount
+							== bytecount) {
+					*commandcode = i;
+					retval = 0;
+					goto exit;
+				}
+			} else {
+				if (rmi_smb->mapping_table[i].flags &
+							RMI_SMB2_MAP_FLAGS_WE) {
+					*commandcode = i;
+					retval = 0;
+					goto exit;
+				}
+			}
+		}
+	}
+	i = rmi_smb->table_index;
+	rmi_smb->table_index = (i + 1) % RMI_SMB2_MAP_SIZE;
+
+	/* constructs mapping table data entry. 4 bytes each entry */
+	memset(mapping_data, 0, sizeof(mapping_data));
+
+	mapping_data[0].rmiaddr = cpu_to_le16(rmiaddr);
+	mapping_data[0].readcount = bytecount;
+	mapping_data[0].flags = !isread ? RMI_SMB2_MAP_FLAGS_WE : 0;
+
+	retval = smb_block_write(xport, i + 0x80, mapping_data,
+				 sizeof(mapping_data));
+
+	if (retval < 0) {
+		/*
+		 * if not written to device mapping table
+		 * clear the driver mapping table records
+		 */
+		rmi_smb->mapping_table[i].rmiaddr = 0x0000;
+		rmi_smb->mapping_table[i].readcount = 0;
+		rmi_smb->mapping_table[i].flags = 0;
+		goto exit;
+	}
+	/* save to the driver level mapping table */
+	rmi_smb->mapping_table[i].rmiaddr = rmiaddr;
+	rmi_smb->mapping_table[i].readcount = bytecount;
+	rmi_smb->mapping_table[i].flags = !isread ? RMI_SMB2_MAP_FLAGS_WE : 0;
+	*commandcode = i;
+
+exit:
+	mutex_unlock(&rmi_smb->mappingtable_mutex);
+
+	return retval;
+}
+
+static int rmi_smb_write_block(struct rmi_transport_dev *xport, u16 rmiaddr,
+				const void *databuff, size_t len)
+{
+	int retval = 0;
+	u8 commandcode;
+	struct rmi_smb_xport *rmi_smb =
+		container_of(xport, struct rmi_smb_xport, xport);
+	int cur_len = (int)len;
+
+	mutex_lock(&rmi_smb->page_mutex);
+
+	while (cur_len > 0) {
+		/*
+		 * break into 32 bytes chunks to write get command code
+		 */
+		int block_len = min_t(int, len, SMB_MAX_COUNT);
+
+		retval = rmi_smb_get_command_code(xport, rmiaddr, block_len,
+						  false, &commandcode);
+		if (retval < 0)
+			goto exit;
+
+		retval = smb_block_write(xport, commandcode,
+					 databuff, block_len);
+		if (retval < 0)
+			goto exit;
+
+		/* prepare to write next block of bytes */
+		cur_len -= SMB_MAX_COUNT;
+		databuff += SMB_MAX_COUNT;
+		rmiaddr += SMB_MAX_COUNT;
+	}
+exit:
+	mutex_unlock(&rmi_smb->page_mutex);
+	return retval;
+}
+
+/* SMB block read - wrapper over ic2_smb_read_block */
+static int smb_block_read(struct rmi_transport_dev *xport,
+			     u8 commandcode, void *buf, size_t len)
+{
+	struct rmi_smb_xport *rmi_smb =
+		container_of(xport, struct rmi_smb_xport, xport);
+	struct i2c_client *client = rmi_smb->client;
+	int retval;
+
+	retval = i2c_smbus_read_block_data(client, commandcode, buf);
+	if (retval < 0)
+		return retval;
+
+	return retval;
+}
+
+static int rmi_smb_read_block(struct rmi_transport_dev *xport, u16 rmiaddr,
+			      void *databuff, size_t len)
+{
+	struct rmi_smb_xport *rmi_smb =
+		container_of(xport, struct rmi_smb_xport, xport);
+	int retval;
+	u8 commandcode;
+	int cur_len = (int)len;
+
+	mutex_lock(&rmi_smb->page_mutex);
+	memset(databuff, 0, len);
+
+	while (cur_len > 0) {
+		/* break into 32 bytes chunks to write get command code */
+		int block_len =  min_t(int, cur_len, SMB_MAX_COUNT);
+
+		retval = rmi_smb_get_command_code(xport, rmiaddr, block_len,
+						  true, &commandcode);
+		if (retval < 0)
+			goto exit;
+
+		retval = smb_block_read(xport, commandcode,
+					databuff, block_len);
+		if (retval < 0)
+			goto exit;
+
+		/* prepare to read next block of bytes */
+		cur_len -= SMB_MAX_COUNT;
+		databuff += SMB_MAX_COUNT;
+		rmiaddr += SMB_MAX_COUNT;
+	}
+
+	retval = 0;
+
+exit:
+	mutex_unlock(&rmi_smb->page_mutex);
+	return retval;
+}
+
+static void rmi_smb_clear_state(struct rmi_smb_xport *rmi_smb)
+{
+	/* the mapping table has been flushed, discard the current one */
+	mutex_lock(&rmi_smb->mappingtable_mutex);
+	memset(rmi_smb->mapping_table, 0, sizeof(rmi_smb->mapping_table));
+	mutex_unlock(&rmi_smb->mappingtable_mutex);
+}
+
+static int rmi_smb_enable_smbus_mode(struct rmi_smb_xport *rmi_smb)
+{
+	int retval;
+
+	/* we need to get the smbus version to activate the touchpad */
+	retval = rmi_smb_get_version(rmi_smb);
+	if (retval < 0)
+		return retval;
+
+	return 0;
+}
+
+static int rmi_smb_reset(struct rmi_transport_dev *xport, u16 reset_addr)
+{
+	struct rmi_smb_xport *rmi_smb =
+		container_of(xport, struct rmi_smb_xport, xport);
+
+	rmi_smb_clear_state(rmi_smb);
+
+	/*
+	 * we do not call the actual reset command, it has to be handled in
+	 * PS/2 or there will be races between PS/2 and SMBus.
+	 * PS/2 should ensure that a psmouse_reset is called before
+	 * intializing the device and after it has been removed to be in a known
+	 * state.
+	 */
+	return rmi_smb_enable_smbus_mode(rmi_smb);
+}
+
+static const struct rmi_transport_ops rmi_smb_ops = {
+	.write_block	= rmi_smb_write_block,
+	.read_block	= rmi_smb_read_block,
+	.reset		= rmi_smb_reset,
+};
+
+static int rmi_smb_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct rmi_device_platform_data *pdata = dev_get_platdata(&client->dev);
+	struct rmi_smb_xport *rmi_smb;
+	int retval;
+	int smbus_version;
+
+	if (!i2c_check_functionality(client->adapter,
+				     I2C_FUNC_SMBUS_READ_BLOCK_DATA |
+				     I2C_FUNC_SMBUS_HOST_NOTIFY)) {
+		dev_err(&client->dev,
+			"adapter does not support required functionality.\n");
+		return -ENODEV;
+	}
+
+	if (client->irq <= 0) {
+		dev_err(&client->dev, "no IRQ provided, giving up.\n");
+		return client->irq ? client->irq : -ENODEV;
+	}
+
+	rmi_smb = devm_kzalloc(&client->dev, sizeof(struct rmi_smb_xport),
+				GFP_KERNEL);
+	if (!rmi_smb)
+		return -ENOMEM;
+
+	if (!pdata) {
+		dev_err(&client->dev, "no platform data, aborting\n");
+		return -ENOMEM;
+	}
+
+	rmi_dbg(RMI_DEBUG_XPORT, &client->dev, "Probing %s.\n",
+		dev_name(&client->dev));
+
+	rmi_smb->client = client;
+	mutex_init(&rmi_smb->page_mutex);
+	mutex_init(&rmi_smb->mappingtable_mutex);
+
+	rmi_smb->xport.dev = &client->dev;
+	rmi_smb->xport.pdata = *pdata;
+	rmi_smb->xport.pdata.irq = client->irq;
+	rmi_smb->xport.proto_name = "smb2";
+	rmi_smb->xport.ops = &rmi_smb_ops;
+
+	retval = rmi_smb_get_version(rmi_smb);
+	if (retval < 0)
+		return retval;
+
+	smbus_version = retval;
+	rmi_dbg(RMI_DEBUG_XPORT, &client->dev, "Smbus version is %d",
+		smbus_version);
+
+	if (smbus_version != 2) {
+		dev_err(&client->dev, "Unrecognized SMB version %d.\n",
+				smbus_version);
+		return -ENODEV;
+	}
+
+	i2c_set_clientdata(client, rmi_smb);
+
+	retval = rmi_register_transport_device(&rmi_smb->xport);
+	if (retval) {
+		dev_err(&client->dev, "Failed to register transport driver at 0x%.2X.\n",
+			client->addr);
+		i2c_set_clientdata(client, NULL);
+		return retval;
+	}
+
+	dev_info(&client->dev, "registered rmi smb driver at %#04x.\n",
+			client->addr);
+	return 0;
+
+}
+
+static int rmi_smb_remove(struct i2c_client *client)
+{
+	struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
+
+	rmi_unregister_transport_device(&rmi_smb->xport);
+
+	return 0;
+}
+
+static int __maybe_unused rmi_smb_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
+	int ret;
+
+	ret = rmi_driver_suspend(rmi_smb->xport.rmi_dev, true);
+	if (ret)
+		dev_warn(dev, "Failed to suspend device: %d\n", ret);
+
+	return ret;
+}
+
+static int __maybe_unused rmi_smb_runtime_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
+	int ret;
+
+	ret = rmi_driver_suspend(rmi_smb->xport.rmi_dev, false);
+	if (ret)
+		dev_warn(dev, "Failed to suspend device: %d\n", ret);
+
+	return ret;
+}
+
+static int __maybe_unused rmi_smb_resume(struct device *dev)
+{
+	struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+	struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
+	struct rmi_device *rmi_dev = rmi_smb->xport.rmi_dev;
+	int ret;
+
+	rmi_smb_reset(&rmi_smb->xport, 0);
+
+	rmi_reset(rmi_dev);
+
+	ret = rmi_driver_resume(rmi_smb->xport.rmi_dev, true);
+	if (ret)
+		dev_warn(dev, "Failed to resume device: %d\n", ret);
+
+	return 0;
+}
+
+static int __maybe_unused rmi_smb_runtime_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
+	int ret;
+
+	ret = rmi_driver_resume(rmi_smb->xport.rmi_dev, false);
+	if (ret)
+		dev_warn(dev, "Failed to resume device: %d\n", ret);
+
+	return 0;
+}
+
+static const struct dev_pm_ops rmi_smb_pm = {
+	SET_SYSTEM_SLEEP_PM_OPS(rmi_smb_suspend, rmi_smb_resume)
+	SET_RUNTIME_PM_OPS(rmi_smb_runtime_suspend, rmi_smb_runtime_resume,
+			   NULL)
+};
+
+static const struct i2c_device_id rmi_id[] = {
+	{ "rmi4_smbus", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, rmi_id);
+
+static struct i2c_driver rmi_smb_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "rmi4_smbus",
+		.pm	= &rmi_smb_pm,
+	},
+	.id_table	= rmi_id,
+	.probe		= rmi_smb_probe,
+	.remove		= rmi_smb_remove,
+};
+
+module_i2c_driver(rmi_smb_driver);
+
+MODULE_AUTHOR("Andrew Duggan <aduggan@synaptics.com>");
+MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@redhat.com>");
+MODULE_DESCRIPTION("RMI4 SMBus driver");
+MODULE_LICENSE("GPL");
-- 
2.7.4

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

* [PATCH v3 08/18] Input: serio - store the pt_buttons in the struct serio directly
  2016-10-13 15:50 [PATCH v3 00/18] Synaptics RMI4 and SMBus implementation Benjamin Tissoires
                   ` (6 preceding siblings ...)
  2016-10-13 15:51 ` [PATCH v3 07/18] Input: synaptics-rmi4 - add SMBus support Benjamin Tissoires
@ 2016-10-13 15:51 ` Benjamin Tissoires
  2016-10-13 15:51 ` [PATCH v3 09/18] Input: synaptics-rmi4 - have only one struct platform data Benjamin Tissoires
                   ` (10 subsequent siblings)
  18 siblings, 0 replies; 28+ messages in thread
From: Benjamin Tissoires @ 2016-10-13 15:51 UTC (permalink / raw)
  To: Dmitry Torokhov, Andrew Duggan, Lyude Paul, Christopher Heiny,
	Nick Dyer, Bjorn Andersson, Dennis Wassenberg
  Cc: linux-kernel, linux-input

With RMI4 over SMBus, the pass-through device can be instantiated
in a SMBus driver. However, compared to the psmouse-synaptics driver,
this pass-through PS/2 driver has no clue whether the current
serio_interrupt() is the beginning of the frame or not. Instead of
adding a protocol analysis in RMI4 function F03, we can add an extra
byte in struct serio to handle the extra data we want to append to the
first byte.

Convert the psmouse-synaptics device to use it too.

Partially reverts cdd9dc1 ("Input: synaptics - re-route tracksticks
buttons on the Lenovo 2015 series")

Acked-by: Andrew Duggan <aduggan@synaptics.com>
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>

---

no changes in v3

no changes in v2
---
 drivers/input/mouse/psmouse-base.c |  3 +++
 drivers/input/mouse/synaptics.c    | 19 ++++++++++---------
 drivers/input/mouse/synaptics.h    |  1 -
 include/linux/serio.h              |  8 ++++++++
 4 files changed, 21 insertions(+), 10 deletions(-)

diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index fb4b185..f9b04fd 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -365,6 +365,9 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
 		goto out;
 	}
 
+	if (psmouse->pktcnt == 1)
+		psmouse->packet[0] |= serio->extra_byte;
+
 	psmouse->last = jiffies;
 	psmouse_handle_byte(psmouse);
 
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index a41d832..8781e23 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -597,15 +597,13 @@ static int synaptics_is_pt_packet(unsigned char *buf)
 	return (buf[0] & 0xFC) == 0x84 && (buf[3] & 0xCC) == 0xC4;
 }
 
-static void synaptics_pass_pt_packet(struct psmouse *psmouse,
-				     struct serio *ptport,
+static void synaptics_pass_pt_packet(struct serio *ptport,
 				     unsigned char *packet)
 {
-	struct synaptics_data *priv = psmouse->private;
 	struct psmouse *child = serio_get_drvdata(ptport);
 
 	if (child && child->state == PSMOUSE_ACTIVATED) {
-		serio_interrupt(ptport, packet[1] | priv->pt_buttons, 0);
+		serio_interrupt(ptport, packet[1], 0);
 		serio_interrupt(ptport, packet[4], 0);
 		serio_interrupt(ptport, packet[5], 0);
 		if (child->pktsize == 4)
@@ -857,6 +855,7 @@ static void synaptics_report_ext_buttons(struct psmouse *psmouse,
 	struct synaptics_data *priv = psmouse->private;
 	int ext_bits = (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) + 1) >> 1;
 	char buf[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+	int pt_buttons;
 	int i;
 
 	if (!SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap))
@@ -887,11 +886,13 @@ static void synaptics_report_ext_buttons(struct psmouse *psmouse,
 		return;
 
 	/* The trackstick expects at most 3 buttons */
-	priv->pt_buttons = SYN_CAP_EXT_BUTTON_STICK_L(hw->ext_buttons)      |
-			   SYN_CAP_EXT_BUTTON_STICK_R(hw->ext_buttons) << 1 |
-			   SYN_CAP_EXT_BUTTON_STICK_M(hw->ext_buttons) << 2;
+	pt_buttons = SYN_CAP_EXT_BUTTON_STICK_L(hw->ext_buttons)      |
+		     SYN_CAP_EXT_BUTTON_STICK_R(hw->ext_buttons) << 1 |
+		     SYN_CAP_EXT_BUTTON_STICK_M(hw->ext_buttons) << 2;
+
+	priv->pt_port->extra_byte = pt_buttons;
 
-	synaptics_pass_pt_packet(psmouse, priv->pt_port, buf);
+	synaptics_pass_pt_packet(priv->pt_port, buf);
 }
 
 static void synaptics_report_buttons(struct psmouse *psmouse,
@@ -1132,7 +1133,7 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse)
 		if (SYN_CAP_PASS_THROUGH(priv->capabilities) &&
 		    synaptics_is_pt_packet(psmouse->packet)) {
 			if (priv->pt_port)
-				synaptics_pass_pt_packet(psmouse, priv->pt_port,
+				synaptics_pass_pt_packet(priv->pt_port,
 							 psmouse->packet);
 		} else
 			synaptics_process_packet(psmouse);
diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h
index 56faa7e..116ae25 100644
--- a/drivers/input/mouse/synaptics.h
+++ b/drivers/input/mouse/synaptics.h
@@ -183,7 +183,6 @@ struct synaptics_data {
 	bool disable_gesture;			/* disable gestures */
 
 	struct serio *pt_port;			/* Pass-through serio port */
-	unsigned char pt_buttons;		/* Pass-through buttons */
 
 	/*
 	 * Last received Advanced Gesture Mode (AGM) packet. An AGM packet
diff --git a/include/linux/serio.h b/include/linux/serio.h
index c733cff..f3b75c8 100644
--- a/include/linux/serio.h
+++ b/include/linux/serio.h
@@ -64,6 +64,14 @@ struct serio {
 	 * may get indigestion when exposed to concurrent access (i8042).
 	 */
 	struct mutex *ps2_cmd_mutex;
+
+	/*
+	 * For use with Synaptics devices that have the trackstick buttons
+	 * not actually wired to the trackstick PS/2 device.
+	 * This byte will be OR-ed with the first byte of the incoming packet
+	 * that contains actual data (not commands).
+	 */
+	u8 extra_byte;
 };
 #define to_serio_port(d)	container_of(d, struct serio, dev)
 
-- 
2.7.4

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

* [PATCH v3 09/18] Input: synaptics-rmi4 - have only one struct platform data
  2016-10-13 15:50 [PATCH v3 00/18] Synaptics RMI4 and SMBus implementation Benjamin Tissoires
                   ` (7 preceding siblings ...)
  2016-10-13 15:51 ` [PATCH v3 08/18] Input: serio - store the pt_buttons in the struct serio directly Benjamin Tissoires
@ 2016-10-13 15:51 ` Benjamin Tissoires
  2016-10-13 15:51 ` [PATCH v3 10/18] Input: synaptics-rmi4 - add support for F03 Benjamin Tissoires
                   ` (9 subsequent siblings)
  18 siblings, 0 replies; 28+ messages in thread
From: Benjamin Tissoires @ 2016-10-13 15:51 UTC (permalink / raw)
  To: Dmitry Torokhov, Andrew Duggan, Lyude Paul, Christopher Heiny,
	Nick Dyer, Bjorn Andersson, Dennis Wassenberg
  Cc: linux-kernel, linux-input

If struct rmi_device_platform_data contains pointers to other struct,
it gets difficult to allocate a fixed size struct and copy it over between
drivers.

Change the pointers into a struct and change the code in rmi4 accordingly.

Reviewed-by: Andrew Duggan <aduggan@synaptics.com>
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>

---

this patch will conflict with Andrew's patch to switch hid-rmi
to use rmi4_core...

no changes in v3

changes in v2:
- removed the pdata checks as they are allways true
---
 drivers/input/rmi4/rmi_f11.c | 4 ++--
 drivers/input/rmi4/rmi_f12.c | 4 ++--
 drivers/input/rmi4/rmi_f30.c | 9 ++++-----
 include/linux/rmi.h          | 4 ++--
 4 files changed, 10 insertions(+), 11 deletions(-)

diff --git a/drivers/input/rmi4/rmi_f11.c b/drivers/input/rmi4/rmi_f11.c
index cce82a1..0af5500 100644
--- a/drivers/input/rmi4/rmi_f11.c
+++ b/drivers/input/rmi4/rmi_f11.c
@@ -1080,8 +1080,8 @@ static int rmi_f11_initialize(struct rmi_function *fn)
 		rc = rmi_2d_sensor_of_probe(&fn->dev, &f11->sensor_pdata);
 		if (rc)
 			return rc;
-	} else if (pdata->sensor_pdata) {
-		f11->sensor_pdata = *pdata->sensor_pdata;
+	} else {
+		f11->sensor_pdata = pdata->sensor_pdata;
 	}
 
 	f11->rezero_wait_ms = f11->sensor_pdata.rezero_wait;
diff --git a/drivers/input/rmi4/rmi_f12.c b/drivers/input/rmi4/rmi_f12.c
index f79a785..2388682 100644
--- a/drivers/input/rmi4/rmi_f12.c
+++ b/drivers/input/rmi4/rmi_f12.c
@@ -355,8 +355,8 @@ static int rmi_f12_probe(struct rmi_function *fn)
 		ret = rmi_2d_sensor_of_probe(&fn->dev, &f12->sensor_pdata);
 		if (ret)
 			return ret;
-	} else if (pdata->sensor_pdata) {
-		f12->sensor_pdata = *pdata->sensor_pdata;
+	} else {
+		f12->sensor_pdata = pdata->sensor_pdata;
 	}
 
 	ret = rmi_read_register_desc(rmi_dev, query_addr,
diff --git a/drivers/input/rmi4/rmi_f30.c b/drivers/input/rmi4/rmi_f30.c
index 485907f..f696137 100644
--- a/drivers/input/rmi4/rmi_f30.c
+++ b/drivers/input/rmi4/rmi_f30.c
@@ -196,7 +196,7 @@ static int rmi_f30_config(struct rmi_function *fn)
 				rmi_get_platform_data(fn->rmi_dev);
 	int error;
 
-	if (pdata->f30_data && pdata->f30_data->disable) {
+	if (pdata->f30_data.disable) {
 		drv->clear_irq_bits(fn->rmi_dev, fn->irq_mask);
 	} else {
 		/* Write Control Register values back to device */
@@ -355,7 +355,7 @@ static inline int rmi_f30_initialize(struct rmi_function *fn)
 	f30->gpioled_key_map = (u16 *)map_memory;
 
 	pdata = rmi_get_platform_data(rmi_dev);
-	if (pdata && f30->has_gpio) {
+	if (f30->has_gpio) {
 		button = BTN_LEFT;
 		for (i = 0; i < f30->gpioled_count; i++) {
 			if (rmi_f30_is_valid_button(i, f30->ctrl)) {
@@ -366,8 +366,7 @@ static inline int rmi_f30_initialize(struct rmi_function *fn)
 				 * f30->has_mech_mouse_btns, but I am
 				 * not sure, so use only the pdata info
 				 */
-				if (pdata->f30_data &&
-				    pdata->f30_data->buttonpad)
+				if (pdata->f30_data.buttonpad)
 					break;
 			}
 		}
@@ -382,7 +381,7 @@ static int rmi_f30_probe(struct rmi_function *fn)
 	const struct rmi_device_platform_data *pdata =
 				rmi_get_platform_data(fn->rmi_dev);
 
-	if (pdata->f30_data && pdata->f30_data->disable)
+	if (pdata->f30_data.disable)
 		return 0;
 
 	rc = rmi_f30_initialize(fn);
diff --git a/include/linux/rmi.h b/include/linux/rmi.h
index ac904bb..aa18bef 100644
--- a/include/linux/rmi.h
+++ b/include/linux/rmi.h
@@ -218,9 +218,9 @@ struct rmi_device_platform_data {
 	struct rmi_device_platform_data_spi spi_data;
 
 	/* function handler pdata */
-	struct rmi_2d_sensor_platform_data *sensor_pdata;
+	struct rmi_2d_sensor_platform_data sensor_pdata;
 	struct rmi_f01_power_management power_management;
-	struct rmi_f30_data *f30_data;
+	struct rmi_f30_data f30_data;
 };
 
 /**
-- 
2.7.4

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

* [PATCH v3 10/18] Input: synaptics-rmi4 - add support for F03
  2016-10-13 15:50 [PATCH v3 00/18] Synaptics RMI4 and SMBus implementation Benjamin Tissoires
                   ` (8 preceding siblings ...)
  2016-10-13 15:51 ` [PATCH v3 09/18] Input: synaptics-rmi4 - have only one struct platform data Benjamin Tissoires
@ 2016-10-13 15:51 ` Benjamin Tissoires
  2016-10-13 15:51 ` [PATCH v3 11/18] Input: synaptics-rmi4 - f03: grab data passed by transport device Benjamin Tissoires
                   ` (8 subsequent siblings)
  18 siblings, 0 replies; 28+ messages in thread
From: Benjamin Tissoires @ 2016-10-13 15:51 UTC (permalink / raw)
  To: Dmitry Torokhov, Andrew Duggan, Lyude Paul, Christopher Heiny,
	Nick Dyer, Bjorn Andersson, Dennis Wassenberg
  Cc: linux-kernel, linux-input

From: Lyude Paul <thatslyude@gmail.com>

This adds basic functionality for PS/2 passthrough on Synaptics
Touchpads using RMI4 through smbus.

Reviewed-by: Andrew Duggan <aduggan@synaptics.com>
Signed-off-by: Lyude Paul <thatslyude@gmail.com>
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>

---

no changes in v3

changes in v2:
- switch to use rmi_dbg instead of plain dev_dbg
---
 drivers/input/mouse/psmouse-base.c |   6 +
 drivers/input/rmi4/Kconfig         |   9 ++
 drivers/input/rmi4/Makefile        |   1 +
 drivers/input/rmi4/rmi_bus.c       |   3 +
 drivers/input/rmi4/rmi_driver.h    |   1 +
 drivers/input/rmi4/rmi_f03.c       | 227 +++++++++++++++++++++++++++++++++++++
 include/uapi/linux/serio.h         |   1 +
 7 files changed, 248 insertions(+)
 create mode 100644 drivers/input/rmi4/rmi_f03.c

diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index f9b04fd..59d7c37 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -1666,6 +1666,12 @@ static struct serio_device_id psmouse_serio_ids[] = {
 		.id	= SERIO_ANY,
 		.extra	= SERIO_ANY,
 	},
+	{
+		.type	= SERIO_RMI_PSTHRU,
+		.proto	= SERIO_ANY,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
 	{ 0 }
 };
 
diff --git a/drivers/input/rmi4/Kconfig b/drivers/input/rmi4/Kconfig
index 8cbd362..eea1862 100644
--- a/drivers/input/rmi4/Kconfig
+++ b/drivers/input/rmi4/Kconfig
@@ -39,6 +39,15 @@ config RMI4_SMB
 	  To compile this driver as a module, choose M here: the module will be
 	  called rmi_smbus.
 
+config RMI4_F03
+        bool "RMI4 Function 03 (PS2 Guest)"
+        depends on RMI4_CORE
+        help
+          Say Y here if you want to add support for RMI4 function 03.
+
+          Function 03 provides PS2 guest support for RMI4 devices. This
+          includes support for TrackPoints on TouchPads.
+
 config RMI4_2D_SENSOR
 	bool
 	depends on RMI4_CORE
diff --git a/drivers/input/rmi4/Makefile b/drivers/input/rmi4/Makefile
index a6e2752..8271b65 100644
--- a/drivers/input/rmi4/Makefile
+++ b/drivers/input/rmi4/Makefile
@@ -4,6 +4,7 @@ rmi_core-y := rmi_bus.o rmi_driver.o rmi_f01.o
 rmi_core-$(CONFIG_RMI4_2D_SENSOR) += rmi_2d_sensor.o
 
 # Function drivers
+rmi_core-$(CONFIG_RMI4_F03) += rmi_f03.o
 rmi_core-$(CONFIG_RMI4_F11) += rmi_f11.o
 rmi_core-$(CONFIG_RMI4_F12) += rmi_f12.o
 rmi_core-$(CONFIG_RMI4_F30) += rmi_f30.o
diff --git a/drivers/input/rmi4/rmi_bus.c b/drivers/input/rmi4/rmi_bus.c
index 09c769c..fd97384 100644
--- a/drivers/input/rmi4/rmi_bus.c
+++ b/drivers/input/rmi4/rmi_bus.c
@@ -303,6 +303,9 @@ struct bus_type rmi_bus_type = {
 
 static struct rmi_function_handler *fn_handlers[] = {
 	&rmi_f01_handler,
+#ifdef CONFIG_RMI4_F03
+	&rmi_f03_handler,
+#endif
 #ifdef CONFIG_RMI4_F11
 	&rmi_f11_handler,
 #endif
diff --git a/drivers/input/rmi4/rmi_driver.h b/drivers/input/rmi4/rmi_driver.h
index 8dfbebe..fe26aca 100644
--- a/drivers/input/rmi4/rmi_driver.h
+++ b/drivers/input/rmi4/rmi_driver.h
@@ -99,6 +99,7 @@ void rmi_unregister_physical_driver(void);
 char *rmi_f01_get_product_ID(struct rmi_function *fn);
 
 extern struct rmi_function_handler rmi_f01_handler;
+extern struct rmi_function_handler rmi_f03_handler;
 extern struct rmi_function_handler rmi_f11_handler;
 extern struct rmi_function_handler rmi_f12_handler;
 extern struct rmi_function_handler rmi_f30_handler;
diff --git a/drivers/input/rmi4/rmi_f03.c b/drivers/input/rmi4/rmi_f03.c
new file mode 100644
index 0000000..a7e1b98
--- /dev/null
+++ b/drivers/input/rmi4/rmi_f03.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2015-2016 Red Hat
+ * Copyright (C) 2015 Lyude Paul <thatslyude@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/serio.h>
+#include <linux/notifier.h>
+#include "rmi_driver.h"
+
+#define RMI_F03_RX_DATA_OFB		0x01
+#define RMI_F03_OB_SIZE			2
+
+#define RMI_F03_OB_OFFSET		2
+#define RMI_F03_OB_DATA_OFFSET		1
+#define RMI_F03_OB_FLAG_TIMEOUT		(1 << 6)
+#define RMI_F03_OB_FLAG_PARITY		(1 << 7)
+
+#define RMI_F03_DEVICE_COUNT		0x07
+#define RMI_F03_BYTES_PER_DEVICE_MASK	0x70
+#define RMI_F03_BYTES_PER_DEVICE_SHIFT	4
+#define RMI_F03_QUEUE_LENGTH		0x0F
+
+struct f03_data {
+	struct rmi_function *fn;
+
+	struct serio *serio;
+
+	unsigned int overwrite_buttons;
+
+	u8 device_count;
+	u8 rx_queue_length;
+};
+
+static int rmi_f03_pt_write(struct serio *id, unsigned char val)
+{
+	struct f03_data *f03 = id->port_data;
+	int rc;
+
+	rmi_dbg(RMI_DEBUG_FN, &f03->fn->dev,
+		"%s: Wrote %.2hhx to PS/2 passthrough address",
+		__func__, val);
+
+	rc = rmi_write(f03->fn->rmi_dev, f03->fn->fd.data_base_addr, val);
+	if (rc) {
+		dev_err(&f03->fn->dev,
+			"%s: Failed to write to F03 TX register.\n", __func__);
+		return rc;
+	}
+
+	return 0;
+}
+
+static inline int rmi_f03_initialize(struct rmi_function *fn)
+{
+	struct f03_data *f03;
+	struct device *dev = &fn->dev;
+	int rc;
+	u8 bytes_per_device;
+	u8 query1;
+	size_t query2_len;
+
+	rc = rmi_read(fn->rmi_dev, fn->fd.query_base_addr, &query1);
+	if (rc) {
+		dev_err(dev, "Failed to read query register.\n");
+		return rc;
+	}
+
+	f03 = devm_kzalloc(dev, sizeof(struct f03_data), GFP_KERNEL);
+	if (!f03)
+		return -ENOMEM;
+
+	f03->device_count = query1 & RMI_F03_DEVICE_COUNT;
+	bytes_per_device = (query1 & RMI_F03_BYTES_PER_DEVICE_MASK) >>
+		RMI_F03_BYTES_PER_DEVICE_SHIFT;
+
+	query2_len = f03->device_count * bytes_per_device;
+
+	/*
+	 * The first generation of image sensors don't have a second part to
+	 * their f03 query, as such we have to set some of these values manually
+	 */
+	if (query2_len < 1) {
+		f03->device_count = 1;
+		f03->rx_queue_length = 7;
+	} else {
+		u8 query2[query2_len];
+
+		rc = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr + 1,
+				    query2, query2_len);
+		if (rc) {
+			dev_err(dev, "Failed to read second set of query registers.\n");
+			return rc;
+		}
+
+		f03->rx_queue_length = query2[0] & RMI_F03_QUEUE_LENGTH;
+	}
+
+	f03->fn = fn;
+
+	dev_set_drvdata(dev, f03);
+
+	return f03->device_count;
+}
+
+static inline int rmi_f03_register_pt(struct rmi_function *fn)
+{
+	struct f03_data *f03 = dev_get_drvdata(&fn->dev);
+	struct serio *serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
+
+	if (!serio)
+		return -ENOMEM;
+
+	serio->id.type = SERIO_RMI_PSTHRU;
+	serio->write = rmi_f03_pt_write;
+	serio->port_data = f03;
+
+	strlcpy(serio->name, "Synaptics RMI4 PS2 pass-through",
+		sizeof(serio->name));
+	strlcpy(serio->phys, "synaptics-rmi4-pt/serio1",
+		sizeof(serio->phys));
+	 serio->dev.parent = &fn->dev;
+
+	f03->serio = serio;
+
+	serio_register_port(serio);
+
+	return 0;
+}
+
+static int rmi_f03_probe(struct rmi_function *fn)
+{
+	int rc;
+
+	rc = rmi_f03_initialize(fn);
+	if (rc < 0)
+		return rc;
+
+	rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%d devices on PS/2 passthrough", rc);
+
+	rc = rmi_f03_register_pt(fn);
+	if (rc)
+		return rc;
+
+	return 0;
+}
+
+static int rmi_f03_config(struct rmi_function *fn)
+{
+	fn->rmi_dev->driver->set_irq_bits(fn->rmi_dev, fn->irq_mask);
+
+	return 0;
+}
+
+static int rmi_f03_attention(struct rmi_function *fn, unsigned long *irq_bits)
+{
+	struct f03_data *f03 = dev_get_drvdata(&fn->dev);
+	u16 data_addr = fn->fd.data_base_addr;
+	const u8 ob_len = f03->rx_queue_length * RMI_F03_OB_SIZE;
+	u8 obs[ob_len];
+	u8 ob_status;
+	u8 ob_data;
+	unsigned int serio_flags;
+	int i;
+	int retval;
+
+	/* Grab all of the data registers, and check them for data */
+	retval = rmi_read_block(fn->rmi_dev, data_addr + RMI_F03_OB_OFFSET,
+				&obs, ob_len);
+	if (retval) {
+		dev_err(&fn->dev, "%s: Failed to read F03 output buffers.\n",
+			__func__);
+		serio_interrupt(f03->serio, 0, SERIO_TIMEOUT);
+		return retval;
+	}
+
+	for (i = 0; i < ob_len; i += RMI_F03_OB_SIZE) {
+		ob_status = obs[i];
+		ob_data = obs[i + RMI_F03_OB_DATA_OFFSET];
+		serio_flags = 0;
+
+		if (!(ob_status & RMI_F03_RX_DATA_OFB))
+			continue;
+
+		if (ob_status & RMI_F03_OB_FLAG_TIMEOUT)
+			serio_flags |= SERIO_TIMEOUT;
+		if (ob_status & RMI_F03_OB_FLAG_PARITY)
+			serio_flags |= SERIO_PARITY;
+
+		rmi_dbg(RMI_DEBUG_FN, &fn->dev,
+			"%s: Received %.2hhx from PS2 guest T: %c P: %c\n",
+			__func__, ob_data,
+			serio_flags & SERIO_TIMEOUT ?  'Y' : 'N',
+			serio_flags & SERIO_PARITY ? 'Y' : 'N');
+
+		serio_interrupt(f03->serio, ob_data, serio_flags);
+	}
+
+	return 0;
+}
+
+static void rmi_f03_remove(struct rmi_function *fn)
+{
+	struct f03_data *f03 = dev_get_drvdata(&fn->dev);
+
+	serio_unregister_port(f03->serio);
+}
+
+struct rmi_function_handler rmi_f03_handler = {
+	.driver = {
+		.name = "rmi4_f03",
+	},
+	.func = 0x03,
+	.probe = rmi_f03_probe,
+	.config = rmi_f03_config,
+	.attention = rmi_f03_attention,
+	.remove = rmi_f03_remove,
+};
+
+MODULE_AUTHOR("Lyude Paul <thatslyude@gmail.com>");
+MODULE_DESCRIPTION("RMI F03 module");
+MODULE_LICENSE("GPL");
diff --git a/include/uapi/linux/serio.h b/include/uapi/linux/serio.h
index f2447a8..7012178 100644
--- a/include/uapi/linux/serio.h
+++ b/include/uapi/linux/serio.h
@@ -30,6 +30,7 @@
 #define SERIO_HIL_MLC	0x03
 #define SERIO_PS_PSTHRU	0x05
 #define SERIO_8042_XL	0x06
+#define SERIO_RMI_PSTHRU	0x07
 
 /*
  * Serio protocols
-- 
2.7.4

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

* [PATCH v3 11/18] Input: synaptics-rmi4 - f03: grab data passed by transport device
  2016-10-13 15:50 [PATCH v3 00/18] Synaptics RMI4 and SMBus implementation Benjamin Tissoires
                   ` (9 preceding siblings ...)
  2016-10-13 15:51 ` [PATCH v3 10/18] Input: synaptics-rmi4 - add support for F03 Benjamin Tissoires
@ 2016-10-13 15:51 ` Benjamin Tissoires
  2016-10-13 15:51 ` [PATCH v3 12/18] Input: synaptics-rmi4 - Add rmi_find_function() Benjamin Tissoires
                   ` (7 subsequent siblings)
  18 siblings, 0 replies; 28+ messages in thread
From: Benjamin Tissoires @ 2016-10-13 15:51 UTC (permalink / raw)
  To: Dmitry Torokhov, Andrew Duggan, Lyude Paul, Christopher Heiny,
	Nick Dyer, Bjorn Andersson, Dennis Wassenberg
  Cc: linux-kernel, linux-input

From: Dennis Wassenberg <dennis.wassenberg@secunet.com>

First check if there are data available passed by the transport device.
If data available use these data. If there are no data available
try to read the rmi block if dsata are passed this way.

This is the way the other rmi function handlers will do this.

This patch is needed on HID devices because the firmware reads F03 data
registers and adds them to the HID attention report. Reading those registers
from the driver after the firmware read them will result in invalid data.
Which is exactly what Dennis is describing here.

Reviewed-by: Andrew Duggan <aduggan@synaptics.com>
Signed-off-by: Dennis Wassenberg <dennis.wassenberg@secunet.com>
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>

---

no changes in v3

changes in v2:
- fixed commit message to include Andrew's explanation
---
 drivers/input/rmi4/rmi_f03.c | 37 +++++++++++++++++++++++++++----------
 1 file changed, 27 insertions(+), 10 deletions(-)

diff --git a/drivers/input/rmi4/rmi_f03.c b/drivers/input/rmi4/rmi_f03.c
index a7e1b98..a124b33 100644
--- a/drivers/input/rmi4/rmi_f03.c
+++ b/drivers/input/rmi4/rmi_f03.c
@@ -159,6 +159,7 @@ static int rmi_f03_config(struct rmi_function *fn)
 
 static int rmi_f03_attention(struct rmi_function *fn, unsigned long *irq_bits)
 {
+	struct rmi_device *rmi_dev = fn->rmi_dev;
 	struct f03_data *f03 = dev_get_drvdata(&fn->dev);
 	u16 data_addr = fn->fd.data_base_addr;
 	const u8 ob_len = f03->rx_queue_length * RMI_F03_OB_SIZE;
@@ -167,16 +168,32 @@ static int rmi_f03_attention(struct rmi_function *fn, unsigned long *irq_bits)
 	u8 ob_data;
 	unsigned int serio_flags;
 	int i;
-	int retval;
-
-	/* Grab all of the data registers, and check them for data */
-	retval = rmi_read_block(fn->rmi_dev, data_addr + RMI_F03_OB_OFFSET,
-				&obs, ob_len);
-	if (retval) {
-		dev_err(&fn->dev, "%s: Failed to read F03 output buffers.\n",
-			__func__);
-		serio_interrupt(f03->serio, 0, SERIO_TIMEOUT);
-		return retval;
+	int ret;
+
+	if (!rmi_dev || !rmi_dev->xport)
+		return -ENODEV;
+
+	if (rmi_dev->xport->attn_data) {
+		/* First grab the data passed by the transport device */
+		if (rmi_dev->xport->attn_size < ob_len) {
+			dev_warn(&fn->dev, "F03 interrupted, but data is missing!\n");
+			return 0;
+		}
+
+		memcpy(obs, rmi_dev->xport->attn_data, ob_len);
+
+		rmi_dev->xport->attn_data += ob_len;
+		rmi_dev->xport->attn_size -= ob_len;
+	} else {
+		/* Grab all of the data registers, and check them for data */
+		ret = rmi_read_block(fn->rmi_dev, data_addr + RMI_F03_OB_OFFSET,
+				     &obs, ob_len);
+		if (ret) {
+			dev_err(&fn->dev, "%s: Failed to read F03 output buffers.\n",
+				__func__);
+			serio_interrupt(f03->serio, 0, SERIO_TIMEOUT);
+			return ret;
+		}
 	}
 
 	for (i = 0; i < ob_len; i += RMI_F03_OB_SIZE) {
-- 
2.7.4

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

* [PATCH v3 12/18] Input: synaptics-rmi4 - Add rmi_find_function()
  2016-10-13 15:50 [PATCH v3 00/18] Synaptics RMI4 and SMBus implementation Benjamin Tissoires
                   ` (10 preceding siblings ...)
  2016-10-13 15:51 ` [PATCH v3 11/18] Input: synaptics-rmi4 - f03: grab data passed by transport device Benjamin Tissoires
@ 2016-10-13 15:51 ` Benjamin Tissoires
  2016-10-13 15:51 ` [PATCH v3 13/18] Input: synaptics-rmi4 - f30/f03: Forward mechanical buttons on buttonpads to PS/2 guest Benjamin Tissoires
                   ` (6 subsequent siblings)
  18 siblings, 0 replies; 28+ messages in thread
From: Benjamin Tissoires @ 2016-10-13 15:51 UTC (permalink / raw)
  To: Dmitry Torokhov, Andrew Duggan, Lyude Paul, Christopher Heiny,
	Nick Dyer, Bjorn Andersson, Dennis Wassenberg
  Cc: linux-kernel, linux-input

If a function needs to communicate with an other, it's better to have
a way to retrieve this other.

Reviewed-by: Andrew Duggan <aduggan@synaptics.com>
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>

---

no changes in v3

no changes in v2
---
 drivers/input/rmi4/rmi_driver.c | 13 +++++++++++++
 drivers/input/rmi4/rmi_driver.h |  1 +
 2 files changed, 14 insertions(+)

diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c
index e3f674e..1d20c5b 100644
--- a/drivers/input/rmi4/rmi_driver.c
+++ b/drivers/input/rmi4/rmi_driver.c
@@ -219,6 +219,19 @@ static int rmi_irq_init(struct rmi_device *rmi_dev)
 	return 0;
 }
 
+struct rmi_function *rmi_find_function(struct rmi_device *rmi_dev, u8 number)
+{
+	struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
+	struct rmi_function *entry;
+
+	list_for_each_entry(entry, &data->function_list, node) {
+		if (entry->fd.function_number == number)
+			return entry;
+	}
+
+	return NULL;
+}
+
 static int suspend_one_function(struct rmi_function *fn)
 {
 	struct rmi_function_handler *fh;
diff --git a/drivers/input/rmi4/rmi_driver.h b/drivers/input/rmi4/rmi_driver.h
index fe26aca..9da1ee4 100644
--- a/drivers/input/rmi4/rmi_driver.h
+++ b/drivers/input/rmi4/rmi_driver.h
@@ -95,6 +95,7 @@ bool rmi_register_desc_has_subpacket(const struct rmi_register_desc_item *item,
 bool rmi_is_physical_driver(struct device_driver *);
 int rmi_register_physical_driver(void);
 void rmi_unregister_physical_driver(void);
+struct rmi_function *rmi_find_function(struct rmi_device *rmi_dev, u8 number);
 
 char *rmi_f01_get_product_ID(struct rmi_function *fn);
 
-- 
2.7.4

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

* [PATCH v3 13/18] Input: synaptics-rmi4 - f30/f03: Forward mechanical buttons on buttonpads to PS/2 guest
  2016-10-13 15:50 [PATCH v3 00/18] Synaptics RMI4 and SMBus implementation Benjamin Tissoires
                   ` (11 preceding siblings ...)
  2016-10-13 15:51 ` [PATCH v3 12/18] Input: synaptics-rmi4 - Add rmi_find_function() Benjamin Tissoires
@ 2016-10-13 15:51 ` Benjamin Tissoires
  2016-10-13 15:51 ` [PATCH v3 14/18] Input: synaptics - allocate a Synaptics Intertouch device Benjamin Tissoires
                   ` (5 subsequent siblings)
  18 siblings, 0 replies; 28+ messages in thread
From: Benjamin Tissoires @ 2016-10-13 15:51 UTC (permalink / raw)
  To: Dmitry Torokhov, Andrew Duggan, Lyude Paul, Christopher Heiny,
	Nick Dyer, Bjorn Andersson, Dennis Wassenberg
  Cc: linux-kernel, linux-input

On the latest series of ThinkPads, the button events for the TrackPoint
are reported through the touchpad itself as opposed to the TrackPoint
device. In order to report these buttons properly, we need to forward
them to the TrackPoint device and send the button presses/releases
through there instead.

Signed-off-by: Lyude Paul <thatslyude@gmail.com>
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>

---

no changes in v3

changes in v2:
- make sure we don't break other devices using F30
---
 drivers/input/rmi4/rmi_driver.h | 13 ++++++++
 drivers/input/rmi4/rmi_f03.c    | 28 ++++++++++++++++
 drivers/input/rmi4/rmi_f30.c    | 72 ++++++++++++++++++++++++++++++++---------
 3 files changed, 98 insertions(+), 15 deletions(-)

diff --git a/drivers/input/rmi4/rmi_driver.h b/drivers/input/rmi4/rmi_driver.h
index 9da1ee4..898cadc 100644
--- a/drivers/input/rmi4/rmi_driver.h
+++ b/drivers/input/rmi4/rmi_driver.h
@@ -99,6 +99,19 @@ struct rmi_function *rmi_find_function(struct rmi_device *rmi_dev, u8 number);
 
 char *rmi_f01_get_product_ID(struct rmi_function *fn);
 
+#ifdef CONFIG_RMI4_F03
+int rmi_f03_overwrite_button(struct rmi_function *fn, unsigned int button,
+			     int value);
+void rmi_f03_commit_buttons(struct rmi_function *fn);
+#else
+static inline int rmi_f03_overwrite_button(struct rmi_function *fn,
+					   unsigned int button, int value)
+{
+	return 0;
+}
+static inline void rmi_f03_commit_buttons(struct rmi_function *fn) {}
+#endif
+
 extern struct rmi_function_handler rmi_f01_handler;
 extern struct rmi_function_handler rmi_f03_handler;
 extern struct rmi_function_handler rmi_f11_handler;
diff --git a/drivers/input/rmi4/rmi_f03.c b/drivers/input/rmi4/rmi_f03.c
index a124b33..f309b5f 100644
--- a/drivers/input/rmi4/rmi_f03.c
+++ b/drivers/input/rmi4/rmi_f03.c
@@ -37,6 +37,34 @@ struct f03_data {
 	u8 rx_queue_length;
 };
 
+int rmi_f03_overwrite_button(struct rmi_function *fn, unsigned int button,
+			     int value)
+{
+	struct f03_data *f03 = dev_get_drvdata(&fn->dev);
+	unsigned int bit = BIT(button);
+
+	if (button > 2)
+		return -EINVAL;
+
+	if (value)
+		f03->overwrite_buttons |= bit;
+	else
+		f03->overwrite_buttons &= ~bit;
+
+	return 0;
+}
+
+void rmi_f03_commit_buttons(struct rmi_function *fn)
+{
+	struct f03_data *f03 = dev_get_drvdata(&fn->dev);
+	int i;
+
+	f03->serio->extra_byte = f03->overwrite_buttons;
+
+	for (i = 0; i < 3; i++)
+		serio_interrupt(f03->serio, 0x00, 0x00);
+}
+
 static int rmi_f03_pt_write(struct serio *id, unsigned char val)
 {
 	struct f03_data *f03 = id->port_data;
diff --git a/drivers/input/rmi4/rmi_f30.c b/drivers/input/rmi4/rmi_f30.c
index f696137..eae3e0f 100644
--- a/drivers/input/rmi4/rmi_f30.c
+++ b/drivers/input/rmi4/rmi_f30.c
@@ -74,8 +74,11 @@ struct f30_data {
 
 	u8 data_regs[RMI_F30_CTRL_MAX_BYTES];
 	u16 *gpioled_key_map;
+	u16 *gpio_passthrough_key_map;
 
 	struct input_dev *input;
+	bool trackstick_buttons;
+	struct rmi_function *f03;
 };
 
 static int rmi_f30_read_control_parameters(struct rmi_function *fn,
@@ -108,6 +111,13 @@ static int rmi_f30_attention(struct rmi_function *fn, unsigned long *irq_bits)
 	if (!f30->input)
 		return 0;
 
+	if (f30->trackstick_buttons && !f30->f03) {
+		f30->f03 = rmi_find_function(rmi_dev, 3);
+
+		if (!f30->f03)
+			return -EBUSY;
+	}
+
 	/* Read the gpi led data. */
 	if (rmi_dev->xport->attn_data) {
 		if (rmi_dev->xport->attn_size < f30->register_count) {
@@ -132,23 +142,29 @@ static int rmi_f30_attention(struct rmi_function *fn, unsigned long *irq_bits)
 	for (reg_num = 0; reg_num < f30->register_count; ++reg_num) {
 		for (i = 0; gpiled < f30->gpioled_count && i < 8; ++i,
 			++gpiled) {
-			if (f30->gpioled_key_map[gpiled] != 0) {
-				/* buttons have pull up resistors */
-				value = (((f30->data_regs[reg_num] >> i) & 0x01)
-									== 0);
+			/* buttons have pull up resistors */
+			value = (((f30->data_regs[reg_num] >> i) & 0x01) == 0);
 
+			if (f30->gpioled_key_map[gpiled] != 0) {
 				rmi_dbg(RMI_DEBUG_FN, &fn->dev,
 					"%s: call input report key (0x%04x) value (0x%02x)",
 					__func__,
 					f30->gpioled_key_map[gpiled], value);
+
 				input_report_key(f30->input,
 						 f30->gpioled_key_map[gpiled],
 						 value);
+			} else if (f30->gpio_passthrough_key_map[gpiled]) {
+				rmi_f03_overwrite_button(f30->f03,
+						f30->gpio_passthrough_key_map[gpiled] - BTN_LEFT,
+						value);
 			}
-
 		}
 	}
 
+	if (f30->trackstick_buttons)
+		rmi_f03_commit_buttons(f30->f03);
+
 	return 0;
 }
 
@@ -246,10 +262,11 @@ static inline int rmi_f30_initialize(struct rmi_function *fn)
 	int retval = 0;
 	int control_address;
 	int i;
-	int button;
+	int button, extra_button;
 	u8 buf[RMI_F30_QUERY_SIZE];
 	u8 *ctrl_reg;
-	u8 *map_memory;
+	u8 *map_memory, *pt_memory;
+	bool buttonpad;
 
 	f30 = devm_kzalloc(&fn->dev, sizeof(struct f30_data),
 			   GFP_KERNEL);
@@ -347,29 +364,54 @@ static inline int rmi_f30_initialize(struct rmi_function *fn)
 	map_memory = devm_kzalloc(&fn->dev,
 				  (f30->gpioled_count * (sizeof(u16))),
 				  GFP_KERNEL);
-	if (!map_memory) {
+	pt_memory = devm_kzalloc(&fn->dev,
+				 (f30->gpioled_count * (sizeof(u16))),
+				 GFP_KERNEL);
+	if (!map_memory || !pt_memory) {
 		dev_err(&fn->dev, "Failed to allocate gpioled map memory.\n");
 		return -ENOMEM;
 	}
 
 	f30->gpioled_key_map = (u16 *)map_memory;
+	f30->gpio_passthrough_key_map = (u16 *)pt_memory;
 
 	pdata = rmi_get_platform_data(rmi_dev);
 	if (f30->has_gpio) {
+		/*
+		 * buttonpad might be given by f30->has_mech_mouse_btns,
+		 * but I am not sure, so use only the pdata info
+		 */
+		buttonpad = pdata->f30_data.buttonpad;
+		f30->trackstick_buttons = pdata->f30_data.trackstick_buttons;
+
+		/*
+		 * For touchpads the buttons are mapped as:
+		 * - bit 0 = Left, bit 1 = right, bit 2 = middle / clickbutton
+		 * - 3, 4, 5 are extended buttons and
+		 * - 6 and 7 are other sorts of GPIOs
+		 */
 		button = BTN_LEFT;
-		for (i = 0; i < f30->gpioled_count; i++) {
+		extra_button = BTN_LEFT;
+		for (i = 0; i < f30->gpioled_count && i < 3; i++) {
 			if (rmi_f30_is_valid_button(i, f30->ctrl)) {
 				f30->gpioled_key_map[i] = button++;
 
-				/*
-				 * buttonpad might be given by
-				 * f30->has_mech_mouse_btns, but I am
-				 * not sure, so use only the pdata info
-				 */
-				if (pdata->f30_data.buttonpad)
+				if (buttonpad)
 					break;
 			}
 		}
+
+		if (f30->trackstick_buttons) {
+			for (i = 3; i < f30->gpioled_count && i < 6; i++) {
+				if (rmi_f30_is_valid_button(i, f30->ctrl))
+					f30->gpio_passthrough_key_map[i] = extra_button++;
+			}
+		} else if (!buttonpad) {
+			for (i = 3; i < f30->gpioled_count; i++) {
+				if (rmi_f30_is_valid_button(i, f30->ctrl))
+					f30->gpioled_key_map[i] = button++;
+			}
+		}
 	}
 
 	return 0;
-- 
2.7.4

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

* [PATCH v3 14/18] Input: synaptics - allocate a Synaptics Intertouch device
  2016-10-13 15:50 [PATCH v3 00/18] Synaptics RMI4 and SMBus implementation Benjamin Tissoires
                   ` (12 preceding siblings ...)
  2016-10-13 15:51 ` [PATCH v3 13/18] Input: synaptics-rmi4 - f30/f03: Forward mechanical buttons on buttonpads to PS/2 guest Benjamin Tissoires
@ 2016-10-13 15:51 ` Benjamin Tissoires
  2016-10-13 15:51 ` [PATCH v3 15/18] Input: synaptics-rmi4 - add rmi_platform Benjamin Tissoires
                   ` (4 subsequent siblings)
  18 siblings, 0 replies; 28+ messages in thread
From: Benjamin Tissoires @ 2016-10-13 15:51 UTC (permalink / raw)
  To: Dmitry Torokhov, Andrew Duggan, Lyude Paul, Christopher Heiny,
	Nick Dyer, Bjorn Andersson, Dennis Wassenberg
  Cc: linux-kernel, linux-input

Most of the Synaptics devices are connected through PS/2 and a different
bus (SMBus or HID over I2C).
The secondary bus capability is indicated by the InterTouch bit in
extended capability 0x0C.

When we encounter such a device, we can create a platform device with
the information gathered through the PS/2 enumeration as some information
might be missing through the other bus. Using a platform device allows
to not add any dependency on the psmouse driver.

We only enable the InterTouch device to be created for the laptops
registered with the top software button property or those we know
that are functional.

In the future, we might change the default to always rely on the
InterTouch bus. Currently, users can enable/disable the feature
with the psmouse parameter synaptics_intertouch.

The SMBus devices keep their PS/2 connection alive. If the initialization
process goes too far (psmouse_activate called), the device disconnects
from the I2C bus and stays on the PS/2 bus. We need to be sure the psmouse
driver will stop communicating with the device (and the pass-through
trackstick too). This part is not addressed here but will be in a
following patch.

The HID over I2C devices are enumerated through the ACPI DSDT, and
their PS/2 device also exports the InterTouch bit in the extended
capability 0x0C. However, the firmware keeps its I2C connection open
even after going further in the PS/2 initialization. We don't need
to take extra precautions with those device, especially because they
block their PS/2 communication when HID over I2C is used.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>

---

no changes in v3

changes in v2:
- also forward the buttonpad information from PS/2 to RMI4 (doesn't
  change the resulting input node, but it seems more relevant)
---
 drivers/input/mouse/synaptics.c | 100 ++++++++++++++++++++++++++++++++++++++++
 drivers/input/mouse/synaptics.h |   4 ++
 2 files changed, 104 insertions(+)

diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 8781e23..e3c46f9 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -29,6 +29,8 @@
 #include <linux/input/mt.h>
 #include <linux/serio.h>
 #include <linux/libps2.h>
+#include <linux/platform_device.h>
+#include <linux/rmi.h>
 #include <linux/slab.h>
 #include "psmouse.h"
 #include "synaptics.h"
@@ -70,6 +72,21 @@
 /* maximum ABS_MT_POSITION displacement (in mm) */
 #define DMAX 10
 
+/*
+ * The newest Synaptics device can use a secondary bus (called InterTouch) which
+ * provides a better bandwidth and allow a better control of the touchpads.
+ * This is used to decide if we need to use this bus or not.
+ */
+enum {
+	SYNAPTICS_INTERTOUCH_NOT_SET = -1,
+	SYNAPTICS_INTERTOUCH_OFF,
+	SYNAPTICS_INTERTOUCH_ON,
+};
+
+static int synaptics_intertouch = SYNAPTICS_INTERTOUCH_NOT_SET;
+module_param_named(synaptics_intertouch, synaptics_intertouch, int, 0644);
+MODULE_PARM_DESC(synaptics_intertouch, "Use a secondary bus for the Synaptics device.");
+
 /*****************************************************************************
  *	Stuff we need even when we do not want native Synaptics support
  ****************************************************************************/
@@ -218,6 +235,81 @@ static const char * const forcepad_pnp_ids[] = {
 	NULL
 };
 
+static const char * const smbus_pnp_ids[] = {
+	/* all of the topbuttonpad_pnp_ids are valid, we just add some extras */
+	"LEN0048", /* X1 Carbon 3 */
+	"LEN0046", /* X250 */
+	"LEN004a", /* W541 */
+	"LEN200f", /* T450s */
+};
+
+static int rmi4_id;
+
+static int synaptics_create_intertouch(struct psmouse *psmouse)
+{
+	struct synaptics_data *priv = psmouse->private;
+	struct platform_device_info pdevinfo;
+	struct platform_device *pdev;
+	struct rmi_device_platform_data pdata = {
+		.sensor_pdata = {
+			.sensor_type = rmi_sensor_touchpad,
+			.axis_align.flip_y = true,
+			/* to prevent cursors jumps: */
+			.kernel_tracking = true,
+		},
+		.f30_data = {
+			.buttonpad = SYN_CAP_CLICKPAD(priv->ext_cap_0c),
+			.trackstick_buttons =
+			  !!SYN_CAP_EXT_BUTTONS_STICK(priv->ext_cap_10),
+		},
+	};
+
+	if (priv->intertouch)
+		return -EINVAL;
+
+	pdata.sensor_pdata.topbuttonpad =
+			psmouse_matches_pnp_id(psmouse, topbuttonpad_pnp_ids) &&
+			!SYN_CAP_EXT_BUTTONS_STICK(priv->ext_cap_10);
+
+	memset(&pdevinfo, 0, sizeof(pdevinfo));
+	pdevinfo.name = "rmi4";
+	pdevinfo.id = rmi4_id++;
+	pdevinfo.data = &pdata;
+	pdevinfo.size_data = sizeof(pdata);
+	pdevinfo.parent = &psmouse->ps2dev.serio->dev;
+
+	pdev = platform_device_register_full(&pdevinfo);
+	if (IS_ERR(pdev))
+		return PTR_ERR(pdev);
+
+	priv->intertouch = pdev;
+
+	return 0;
+}
+
+/**
+ * synaptics_setup_intertouch - called once the PS/2 devices are enumerated
+ * and decides to instantiate a SMBus InterTouch device.
+ */
+static void synaptics_setup_intertouch(struct psmouse *psmouse)
+{
+	int ret;
+
+	if (synaptics_intertouch == SYNAPTICS_INTERTOUCH_OFF)
+		return;
+
+	if (synaptics_intertouch == SYNAPTICS_INTERTOUCH_NOT_SET) {
+		if (!psmouse_matches_pnp_id(psmouse, topbuttonpad_pnp_ids) &&
+		    !psmouse_matches_pnp_id(psmouse, smbus_pnp_ids))
+			return;
+	}
+
+	psmouse_info(psmouse, "device also supported by an other bus.\n");
+	ret = synaptics_create_intertouch(psmouse);
+	if (ret)
+		psmouse_info(psmouse,
+			     "unable to create intertouch device.\n");
+}
 /*****************************************************************************
  *	Synaptics communications functions
  ****************************************************************************/
@@ -1305,6 +1397,11 @@ static void synaptics_disconnect(struct psmouse *psmouse)
 		device_remove_file(&psmouse->ps2dev.serio->dev,
 				   &psmouse_attr_disable_gesture.dattr);
 
+	if (priv->intertouch) {
+		platform_device_unregister(priv->intertouch);
+		priv->intertouch = NULL;
+	}
+
 	synaptics_reset(psmouse);
 	kfree(priv);
 	psmouse->private = NULL;
@@ -1547,6 +1644,9 @@ static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode)
 		}
 	}
 
+	if (SYN_CAP_INTERTOUCH(priv->ext_cap_0c))
+		synaptics_setup_intertouch(psmouse);
+
 	return 0;
 
  init_fail:
diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h
index 116ae25..b88755d 100644
--- a/drivers/input/mouse/synaptics.h
+++ b/drivers/input/mouse/synaptics.h
@@ -90,6 +90,7 @@
 #define SYN_CAP_ADV_GESTURE(ex0c)	((ex0c) & 0x080000)
 #define SYN_CAP_REDUCED_FILTERING(ex0c)	((ex0c) & 0x000400)
 #define SYN_CAP_IMAGE_SENSOR(ex0c)	((ex0c) & 0x000800)
+#define SYN_CAP_INTERTOUCH(ex0c)	((ex0c) & 0x004000)
 
 /*
  * The following descibes response for the 0x10 query.
@@ -196,6 +197,9 @@ struct synaptics_data {
 	bool					press;
 	bool					report_press;
 	bool					is_forcepad;
+
+	/* Intertouch handling */
+	struct platform_device *intertouch;
 };
 
 void synaptics_module_init(void);
-- 
2.7.4

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

* [PATCH v3 15/18] Input: synaptics-rmi4 - add rmi_platform
  2016-10-13 15:50 [PATCH v3 00/18] Synaptics RMI4 and SMBus implementation Benjamin Tissoires
                   ` (13 preceding siblings ...)
  2016-10-13 15:51 ` [PATCH v3 14/18] Input: synaptics - allocate a Synaptics Intertouch device Benjamin Tissoires
@ 2016-10-13 15:51 ` Benjamin Tissoires
  2016-10-13 15:51 ` [PATCH v3 16/18] Input: synaptics-rmi4 - smbus: call psmouse_deactivate before binding/resume Benjamin Tissoires
                   ` (3 subsequent siblings)
  18 siblings, 0 replies; 28+ messages in thread
From: Benjamin Tissoires @ 2016-10-13 15:51 UTC (permalink / raw)
  To: Dmitry Torokhov, Andrew Duggan, Lyude Paul, Christopher Heiny,
	Nick Dyer, Bjorn Andersson, Dennis Wassenberg
  Cc: linux-kernel, linux-input

This driver is a glue between PS/2 devices that enumerate
the RMI4 device and the RMI4 SMBus driver.

We mostly use an intermediate platform device to not
add a dependency between psmouse and I2C. It also handles
the subtleties of going around the serio mutex lock by
deferring the i2c creation/destruction in a separate
thread.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>

---

no changes in v3

changes in v2:
- use alloc_ordered_workqueue instead of create_singlethread_workqueue
- Remove unneeded semicolon reported by scripts/coccinelle/misc/semicolon.cocci
---
 drivers/input/rmi4/Kconfig        |  12 ++
 drivers/input/rmi4/Makefile       |   1 +
 drivers/input/rmi4/rmi_platform.c | 235 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 248 insertions(+)
 create mode 100644 drivers/input/rmi4/rmi_platform.c

diff --git a/drivers/input/rmi4/Kconfig b/drivers/input/rmi4/Kconfig
index eea1862..7a755fe 100644
--- a/drivers/input/rmi4/Kconfig
+++ b/drivers/input/rmi4/Kconfig
@@ -30,6 +30,7 @@ config RMI4_SPI
 config RMI4_SMB
 	tristate "RMI4 SMB Support"
 	depends on RMI4_CORE && I2C
+	select RMI4_PLATFORM
 	help
 	  Say Y here if you want to support RMI4 devices connected to an SMB
 	  bus.
@@ -39,6 +40,17 @@ config RMI4_SMB
 	  To compile this driver as a module, choose M here: the module will be
 	  called rmi_smbus.
 
+config RMI4_PLATFORM
+	tristate "RMI4 Platform Support"
+	depends on RMI4_CORE && RMI4_SMB && I2C
+	help
+	  Say Y here if you want to support RMI4 devices connected to an SMB
+	  bus but enumerated through PS/2.
+
+	  if unsure, say N.
+	  To compile this driver as a module, choose M here: the module will be
+	  called rmi_platform.
+
 config RMI4_F03
         bool "RMI4 Function 03 (PS2 Guest)"
         depends on RMI4_CORE
diff --git a/drivers/input/rmi4/Makefile b/drivers/input/rmi4/Makefile
index 8271b65..c5a34ce 100644
--- a/drivers/input/rmi4/Makefile
+++ b/drivers/input/rmi4/Makefile
@@ -14,3 +14,4 @@ rmi_core-$(CONFIG_RMI4_F54) += rmi_f54.o
 obj-$(CONFIG_RMI4_I2C) += rmi_i2c.o
 obj-$(CONFIG_RMI4_SPI) += rmi_spi.o
 obj-$(CONFIG_RMI4_SMB) += rmi_smbus.o
+obj-$(CONFIG_RMI4_PLATFORM) += rmi_platform.o
diff --git a/drivers/input/rmi4/rmi_platform.c b/drivers/input/rmi4/rmi_platform.c
new file mode 100644
index 0000000..6d31aea
--- /dev/null
+++ b/drivers/input/rmi4/rmi_platform.c
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2016 Red Hat, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/rmi.h>
+#include <linux/slab.h>
+
+#define DRIVER_DESC	"RMI4 Platform PS/2 - SMBus bridge driver"
+
+MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@redhat.com>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+static struct workqueue_struct *krmi_wq;
+DEFINE_MUTEX(rmi_mutex);
+
+struct rmi_pltf {
+	struct i2c_client *smbus_client;
+	struct notifier_block i2c_notifier;
+	struct rmi_device_platform_data *pdata;
+};
+
+enum rmi_event_type {
+	RMI_REGISTER_DEVICE,
+	RMI_UNREGISTER_DEVICE,
+};
+
+struct rmi_work {
+	struct work_struct work;
+	enum rmi_event_type type;
+	struct rmi_pltf *rmi;
+	struct i2c_adapter *adap;
+};
+
+static void rmi_create_intertouch(struct rmi_pltf *rmi_pltf,
+				  struct i2c_adapter *adap)
+{
+	const struct i2c_board_info i2c_info = {
+		I2C_BOARD_INFO("rmi4_smbus", 0x2c),
+		.platform_data = rmi_pltf->pdata,
+	};
+
+	rmi_pltf->smbus_client = i2c_new_device(adap, &i2c_info);
+}
+
+static void rmi_worker(struct work_struct *work)
+{
+	struct rmi_work *rmi_work = container_of(work, struct rmi_work, work);
+
+	mutex_lock(&rmi_mutex);
+
+	switch (rmi_work->type) {
+	case RMI_REGISTER_DEVICE:
+		rmi_create_intertouch(rmi_work->rmi, rmi_work->adap);
+		break;
+	case RMI_UNREGISTER_DEVICE:
+		if (rmi_work->rmi->smbus_client)
+			i2c_unregister_device(rmi_work->rmi->smbus_client);
+		break;
+	}
+
+	kfree(rmi_work);
+
+	mutex_unlock(&rmi_mutex);
+}
+
+static int rmi_schedule_work(enum rmi_event_type type,
+			     struct rmi_pltf *rmi,
+			     struct i2c_adapter *adap)
+{
+	struct rmi_work *rmi_work = kzalloc(sizeof(*rmi_work), GFP_KERNEL);
+
+	if (!rmi_work)
+		return -ENOMEM;
+
+	rmi_work->type = type;
+	rmi_work->rmi = rmi;
+	rmi_work->adap = adap;
+
+	INIT_WORK(&rmi_work->work, rmi_worker);
+
+	queue_work(krmi_wq, &rmi_work->work);
+
+	return 0;
+}
+
+static int rmi_attach_i2c_device(struct device *dev, void *data)
+{
+	struct rmi_pltf *rmi_pltf = data;
+	struct i2c_adapter *adap;
+
+	if (dev->type != &i2c_adapter_type)
+		return 0;
+
+	adap = to_i2c_adapter(dev);
+
+	if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_HOST_NOTIFY))
+		return 0;
+
+	if (rmi_pltf->smbus_client)
+		return 0;
+
+	rmi_schedule_work(RMI_REGISTER_DEVICE, rmi_pltf, adap);
+
+	pr_debug("rmi_platform: adapter [%s] registered\n", adap->name);
+	return 0;
+}
+
+static int rmi_detach_i2c_device(struct device *dev, struct rmi_pltf *rmi_pltf)
+{
+	struct i2c_client *client;
+
+	if (dev->type == &i2c_adapter_type)
+		return 0;
+
+	mutex_lock(&rmi_mutex);
+
+	client = to_i2c_client(dev);
+	if (client == rmi_pltf->smbus_client)
+		rmi_pltf->smbus_client = NULL;
+
+	mutex_unlock(&rmi_mutex);
+
+	pr_debug("rmi_platform: client [%s] unregistered\n", client->name);
+	return 0;
+}
+
+static int rmi_notifier_call(struct notifier_block *nb,
+				   unsigned long action, void *data)
+{
+	struct device *dev = data;
+	struct rmi_pltf *rmi_pltf;
+
+	rmi_pltf = container_of(nb, struct rmi_pltf, i2c_notifier);
+
+	switch (action) {
+	case BUS_NOTIFY_ADD_DEVICE:
+		return rmi_attach_i2c_device(dev, rmi_pltf);
+	case BUS_NOTIFY_DEL_DEVICE:
+		return rmi_detach_i2c_device(dev, rmi_pltf);
+	}
+
+	return 0;
+}
+
+static int rmi_probe(struct platform_device *pdev)
+{
+	struct rmi_device_platform_data *pdata = pdev->dev.platform_data;
+	struct rmi_pltf *rmi_pltf;
+	int error;
+
+	rmi_pltf = devm_kzalloc(&pdev->dev, sizeof(struct rmi_pltf),
+				GFP_KERNEL);
+	if (!rmi_pltf)
+		return -ENOMEM;
+
+	rmi_pltf->i2c_notifier.notifier_call = rmi_notifier_call;
+
+	rmi_pltf->pdata = pdata;
+
+	/* Keep track of adapters which will be added or removed later */
+	error = bus_register_notifier(&i2c_bus_type, &rmi_pltf->i2c_notifier);
+	if (error)
+		return error;
+
+	/* Bind to already existing adapters right away */
+	i2c_for_each_dev(rmi_pltf, rmi_attach_i2c_device);
+
+	platform_set_drvdata(pdev, rmi_pltf);
+
+	return 0;
+}
+
+static int rmi_remove(struct platform_device *pdev)
+{
+	struct rmi_pltf *rmi_pltf = platform_get_drvdata(pdev);
+
+	bus_unregister_notifier(&i2c_bus_type, &rmi_pltf->i2c_notifier);
+
+	if (rmi_pltf->smbus_client)
+		rmi_schedule_work(RMI_UNREGISTER_DEVICE, rmi_pltf, NULL);
+
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static const struct platform_device_id rmi_id_table[] = {
+	{ .name = "rmi4" },
+	{ }
+};
+MODULE_DEVICE_TABLE(platform, rmi_id_table);
+
+static struct platform_driver rmi_drv = {
+	.driver		= {
+		.name	= "rmi4",
+	},
+	.probe		= rmi_probe,
+	.remove		= rmi_remove,
+	.id_table	= rmi_id_table,
+};
+
+static int __init rmi_init(void)
+{
+	int err;
+
+	krmi_wq = alloc_ordered_workqueue("krmid", WQ_MEM_RECLAIM);
+	if (!krmi_wq) {
+		pr_err("failed to create krmid workqueue\n");
+		return -ENOMEM;
+	}
+
+	err = platform_driver_register(&rmi_drv);
+	if (err)
+		destroy_workqueue(krmi_wq);
+
+	return err;
+}
+
+static void __exit rmi_exit(void)
+{
+	platform_driver_unregister(&rmi_drv);
+	destroy_workqueue(krmi_wq);
+}
+
+module_init(rmi_init);
+module_exit(rmi_exit);
-- 
2.7.4

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

* [PATCH v3 16/18] Input: synaptics-rmi4 - smbus: call psmouse_deactivate before binding/resume
  2016-10-13 15:50 [PATCH v3 00/18] Synaptics RMI4 and SMBus implementation Benjamin Tissoires
                   ` (14 preceding siblings ...)
  2016-10-13 15:51 ` [PATCH v3 15/18] Input: synaptics-rmi4 - add rmi_platform Benjamin Tissoires
@ 2016-10-13 15:51 ` Benjamin Tissoires
  2016-10-13 15:51 ` [PATCH v3 17/18] Input: synaptics-rmi4 - smbus: on resume, try 3 times if init fails Benjamin Tissoires
                   ` (2 subsequent siblings)
  18 siblings, 0 replies; 28+ messages in thread
From: Benjamin Tissoires @ 2016-10-13 15:51 UTC (permalink / raw)
  To: Dmitry Torokhov, Andrew Duggan, Lyude Paul, Christopher Heiny,
	Nick Dyer, Bjorn Andersson, Dennis Wassenberg
  Cc: linux-kernel, linux-input

The SMBus Synaptics devices enumerated as PS/2 devices have
the problem of being deaf to I2C if the touchpad has been
fully initialized over PS/2 (psmouse_activate being called).
A simple PS/2 deactivate command is enough to make it back alive.

To make sure the pass-through device does not interfere, we also
remove it from serio while using InterTouch.

Add a platform_data callback to reset the PS/2 device and
prevent it to be asynchronously re-enabled at resume.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>

---

no changes in v3

changes in v2:
- fix an oops when synaptics_disconnect() was called, which leaded
  to a null parameter as psmouse in synaptics_intertouch_enable()
---
 drivers/input/mouse/psmouse-base.c |  3 +++
 drivers/input/mouse/psmouse.h      |  1 +
 drivers/input/mouse/synaptics.c    | 34 ++++++++++++++++++++++++++++++++++
 drivers/input/rmi4/rmi_smbus.c     | 30 ++++++++++++++++++++----------
 include/linux/rmi.h                | 13 +++++++++++++
 5 files changed, 71 insertions(+), 10 deletions(-)

diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index 59d7c37..0b1f09a 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -1607,6 +1607,9 @@ static int psmouse_reconnect(struct serio *serio)
 	unsigned char type;
 	int rc = -1;
 
+	if (psmouse->ignore_reconnect)
+		return 0;
+
 	mutex_lock(&psmouse_mutex);
 
 	if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
index e0ca6cd..e9dc1a1 100644
--- a/drivers/input/mouse/psmouse.h
+++ b/drivers/input/mouse/psmouse.h
@@ -81,6 +81,7 @@ struct psmouse {
 
 	void (*pt_activate)(struct psmouse *psmouse);
 	void (*pt_deactivate)(struct psmouse *psmouse);
+	bool ignore_reconnect;
 };
 
 enum psmouse_type {
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index e3c46f9..e10be58 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -245,6 +245,32 @@ static const char * const smbus_pnp_ids[] = {
 
 static int rmi4_id;
 
+static void synaptics_pt_create(struct psmouse *psmouse);
+
+static int synaptics_intertouch_enable(void *data, bool value)
+{
+	struct psmouse *psmouse = data;
+	struct synaptics_data *priv;
+
+	if (!psmouse)
+		return 0;
+
+	priv = psmouse->private;
+
+	psmouse->ignore_reconnect = value;
+
+	if (value) {
+		serio_unregister_child_port(psmouse->ps2dev.serio);
+		psmouse_deactivate(psmouse);
+	} else {
+		psmouse_activate(psmouse);
+		if (SYN_CAP_PASS_THROUGH(priv->capabilities))
+			synaptics_pt_create(psmouse);
+	}
+
+	return 0;
+}
+
 static int synaptics_create_intertouch(struct psmouse *psmouse)
 {
 	struct synaptics_data *priv = psmouse->private;
@@ -262,6 +288,8 @@ static int synaptics_create_intertouch(struct psmouse *psmouse)
 			.trackstick_buttons =
 			  !!SYN_CAP_EXT_BUTTONS_STICK(priv->ext_cap_10),
 		},
+		.transport_enable = synaptics_intertouch_enable,
+		.transport_data = psmouse,
 	};
 
 	if (priv->intertouch)
@@ -1398,6 +1426,12 @@ static void synaptics_disconnect(struct psmouse *psmouse)
 				   &psmouse_attr_disable_gesture.dattr);
 
 	if (priv->intertouch) {
+		struct rmi_device_platform_data *pdata;
+
+		/* reset transport_data as it will get eventually freed */
+		pdata = priv->intertouch->dev.platform_data;
+		pdata->transport_data = NULL;
+
 		platform_device_unregister(priv->intertouch);
 		priv->intertouch = NULL;
 	}
diff --git a/drivers/input/rmi4/rmi_smbus.c b/drivers/input/rmi4/rmi_smbus.c
index 96ad325..8d7ffe4 100644
--- a/drivers/input/rmi4/rmi_smbus.c
+++ b/drivers/input/rmi4/rmi_smbus.c
@@ -244,8 +244,15 @@ static void rmi_smb_clear_state(struct rmi_smb_xport *rmi_smb)
 
 static int rmi_smb_enable_smbus_mode(struct rmi_smb_xport *rmi_smb)
 {
+	struct rmi_device_platform_data *pdata;
 	int retval;
 
+	pdata = dev_get_platdata(&rmi_smb->client->dev);
+
+	retval = rmi_transport_enable(pdata, true);
+	if (retval)
+		return retval;
+
 	/* we need to get the smbus version to activate the touchpad */
 	retval = rmi_smb_get_version(rmi_smb);
 	if (retval < 0)
@@ -261,13 +268,6 @@ static int rmi_smb_reset(struct rmi_transport_dev *xport, u16 reset_addr)
 
 	rmi_smb_clear_state(rmi_smb);
 
-	/*
-	 * we do not call the actual reset command, it has to be handled in
-	 * PS/2 or there will be races between PS/2 and SMBus.
-	 * PS/2 should ensure that a psmouse_reset is called before
-	 * intializing the device and after it has been removed to be in a known
-	 * state.
-	 */
 	return rmi_smb_enable_smbus_mode(rmi_smb);
 }
 
@@ -321,9 +321,13 @@ static int rmi_smb_probe(struct i2c_client *client,
 	rmi_smb->xport.proto_name = "smb2";
 	rmi_smb->xport.ops = &rmi_smb_ops;
 
+	retval = rmi_transport_enable(pdata, true);
+	if (retval)
+		return retval;
+
 	retval = rmi_smb_get_version(rmi_smb);
 	if (retval < 0)
-		return retval;
+		goto fail;
 
 	smbus_version = retval;
 	rmi_dbg(RMI_DEBUG_XPORT, &client->dev, "Smbus version is %d",
@@ -332,7 +336,8 @@ static int rmi_smb_probe(struct i2c_client *client,
 	if (smbus_version != 2) {
 		dev_err(&client->dev, "Unrecognized SMB version %d.\n",
 				smbus_version);
-		return -ENODEV;
+		retval = -ENODEV;
+		goto fail;
 	}
 
 	i2c_set_clientdata(client, rmi_smb);
@@ -342,20 +347,25 @@ static int rmi_smb_probe(struct i2c_client *client,
 		dev_err(&client->dev, "Failed to register transport driver at 0x%.2X.\n",
 			client->addr);
 		i2c_set_clientdata(client, NULL);
-		return retval;
+		goto fail;
 	}
 
 	dev_info(&client->dev, "registered rmi smb driver at %#04x.\n",
 			client->addr);
 	return 0;
 
+fail:
+	rmi_transport_enable(pdata, false);
+	return retval;
 }
 
 static int rmi_smb_remove(struct i2c_client *client)
 {
+	struct rmi_device_platform_data *pdata = dev_get_platdata(&client->dev);
 	struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
 
 	rmi_unregister_transport_device(&rmi_smb->xport);
+	rmi_transport_enable(pdata, false);
 
 	return 0;
 }
diff --git a/include/linux/rmi.h b/include/linux/rmi.h
index aa18bef..6b22948 100644
--- a/include/linux/rmi.h
+++ b/include/linux/rmi.h
@@ -221,6 +221,9 @@ struct rmi_device_platform_data {
 	struct rmi_2d_sensor_platform_data sensor_pdata;
 	struct rmi_f01_power_management power_management;
 	struct rmi_f30_data f30_data;
+
+	int (*transport_enable)(void*, bool);
+	void *transport_data;
 };
 
 /**
@@ -357,6 +360,16 @@ struct rmi_driver_data {
 	void *data;
 };
 
+static inline int rmi_transport_enable(struct rmi_device_platform_data *pdata,
+				       bool value)
+{
+	if (!pdata->transport_enable)
+		return 0;
+
+	return pdata->transport_enable(pdata->transport_data, value);
+}
+
+
 int rmi_register_transport_device(struct rmi_transport_dev *xport);
 void rmi_unregister_transport_device(struct rmi_transport_dev *xport);
 
-- 
2.7.4

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

* [PATCH v3 17/18] Input: synaptics-rmi4 - smbus: on resume, try 3 times if init fails
  2016-10-13 15:50 [PATCH v3 00/18] Synaptics RMI4 and SMBus implementation Benjamin Tissoires
                   ` (15 preceding siblings ...)
  2016-10-13 15:51 ` [PATCH v3 16/18] Input: synaptics-rmi4 - smbus: call psmouse_deactivate before binding/resume Benjamin Tissoires
@ 2016-10-13 15:51 ` Benjamin Tissoires
  2016-10-13 15:51 ` [PATCH v3 18/18] Input: synaptics-rmi4 - fix documentation of rmi_2d_sensor_platform_data Benjamin Tissoires
  2016-11-04  8:23 ` [PATCH v3 00/18] Synaptics RMI4 and SMBus implementation Benjamin Tissoires
  18 siblings, 0 replies; 28+ messages in thread
From: Benjamin Tissoires @ 2016-10-13 15:51 UTC (permalink / raw)
  To: Dmitry Torokhov, Andrew Duggan, Lyude Paul, Christopher Heiny,
	Nick Dyer, Bjorn Andersson, Dennis Wassenberg
  Cc: linux-kernel, linux-input

In some rare cases, we can't retrieve the SMBus version and so we fail
binding the touchpad back. Instead of leaving a touchpad dead, try again
to reinitialize it.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>

---

no changes in v3

no changes in v2
---
 drivers/input/rmi4/rmi_smbus.c | 21 ++++++++++++++++++++-
 1 file changed, 20 insertions(+), 1 deletion(-)

diff --git a/drivers/input/rmi4/rmi_smbus.c b/drivers/input/rmi4/rmi_smbus.c
index 8d7ffe4..b2d5932 100644
--- a/drivers/input/rmi4/rmi_smbus.c
+++ b/drivers/input/rmi4/rmi_smbus.c
@@ -265,10 +265,29 @@ static int rmi_smb_reset(struct rmi_transport_dev *xport, u16 reset_addr)
 {
 	struct rmi_smb_xport *rmi_smb =
 		container_of(xport, struct rmi_smb_xport, xport);
+	struct i2c_client *client = rmi_smb->client;
+	struct rmi_device_platform_data *pdata;
+	int tries, ret;
 
 	rmi_smb_clear_state(rmi_smb);
 
-	return rmi_smb_enable_smbus_mode(rmi_smb);
+	for (tries = 3; tries > 0; tries--) {
+		ret = rmi_smb_enable_smbus_mode(rmi_smb);
+		if (!ret)
+			break;
+
+		/* we failed enabling SMBus, try again later */
+		msleep(500);
+	}
+
+	if (ret < 0) {
+		dev_warn(&client->dev,
+			 "failed to enable SMBus mode, giving up.\n");
+		pdata = dev_get_platdata(&rmi_smb->client->dev);
+		rmi_transport_enable(pdata, false);
+	}
+
+	return ret;
 }
 
 static const struct rmi_transport_ops rmi_smb_ops = {
-- 
2.7.4

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

* [PATCH v3 18/18] Input: synaptics-rmi4 - fix documentation of rmi_2d_sensor_platform_data
  2016-10-13 15:50 [PATCH v3 00/18] Synaptics RMI4 and SMBus implementation Benjamin Tissoires
                   ` (16 preceding siblings ...)
  2016-10-13 15:51 ` [PATCH v3 17/18] Input: synaptics-rmi4 - smbus: on resume, try 3 times if init fails Benjamin Tissoires
@ 2016-10-13 15:51 ` Benjamin Tissoires
  2016-11-04  8:23 ` [PATCH v3 00/18] Synaptics RMI4 and SMBus implementation Benjamin Tissoires
  18 siblings, 0 replies; 28+ messages in thread
From: Benjamin Tissoires @ 2016-10-13 15:51 UTC (permalink / raw)
  To: Dmitry Torokhov, Andrew Duggan, Lyude Paul, Christopher Heiny,
	Nick Dyer, Bjorn Andersson, Dennis Wassenberg
  Cc: linux-kernel, linux-input

Typos...

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>

---

no changes in v3

new in v2
---
 include/linux/rmi.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/linux/rmi.h b/include/linux/rmi.h
index 6b22948..2fdb4fb 100644
--- a/include/linux/rmi.h
+++ b/include/linux/rmi.h
@@ -108,7 +108,7 @@ struct rmi_2d_sensor_platform_data {
  * @buttonpad - the touchpad is a buttonpad, so enable only the first actual
  * button that is found.
  * @trackstick_buttons - Set when the function 30 is handling the physical
- * buttons of the trackstick (as a PD/2 passthrough device.
+ * buttons of the trackstick (as a PS/2 passthrough device).
  * @disable - the touchpad incorrectly reports F30 and it should be ignored.
  * This is a special case which is due to misconfigured firmware.
  */
-- 
2.7.4

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

* Re: [PATCH v3 00/18] Synaptics RMI4 and SMBus implementation
  2016-10-13 15:50 [PATCH v3 00/18] Synaptics RMI4 and SMBus implementation Benjamin Tissoires
                   ` (17 preceding siblings ...)
  2016-10-13 15:51 ` [PATCH v3 18/18] Input: synaptics-rmi4 - fix documentation of rmi_2d_sensor_platform_data Benjamin Tissoires
@ 2016-11-04  8:23 ` Benjamin Tissoires
  2016-11-07 23:17   ` Nick Dyer
  18 siblings, 1 reply; 28+ messages in thread
From: Benjamin Tissoires @ 2016-11-04  8:23 UTC (permalink / raw)
  To: Benjamin Tissoires
  Cc: Dmitry Torokhov, Andrew Duggan, Lyude Paul, Christopher Heiny,
	Nick Dyer, Bjorn Andersson, Dennis Wassenberg, linux-kernel,
	linux-input, Jiri Kosina

Hi Dmitry,

On Thu, Oct 13, 2016 at 5:50 PM, Benjamin Tissoires
<benjamin.tissoires@redhat.com> wrote:
> Hi guys,
>
> This is the third submission of this series, with some addition of RMI4 patches
> currently waiting on the list.
>
> I integrated Bjorn's patch because in the end, it seems to be the right thing
> to do. We can create an irqchip in hid-rmi and also provide an IRQ there.
> Worse case, if this doesn't work, we can always add a special case to
> disable the handling of the IRQs in core.
>
> I took Nick's patch as it's a nice cleanup and it solves an issue where
> the mutex irq_mutex might not be initialized (in the case we are not handling
> IRQ directly in core).
>
> I also took some patches from Andrew that were submitted back in July, and that
> were left over. They are required to allow hid-rmi to use rmi4-core without
> losing functionality. The DT binding seemed to be problematic, so I just lefted
> it out of the series. We can add it later when required (if required).
> Andrew, regarding hid-rmi, I'll try to give you a draft of the irqchip
> implementation based on what I did for SMBus Host Notify.
>
> The rest is an update of the SMBus work. The main differences is that now
> rmi4-smbus doesn't handle anymore the IRQ and I hope that the SMBus Host Notify
> patches I posted on linux-i2c will be approved by Wolfram.

I understand you are busy with many other projects, but it would be
great if we could have this series (or a subset of this series)
landing ASAP.

We already have at least 2 machines (the Lenovo X1 Tablet and the HP
Pavilion x2) that need to be using the function 12 in Synaptics RMI4,
and so this series is a requirement to enable those touchpads.

If you really want to postpone the review of the new files in this
series, I think merging only the following patches would be
acceptable:
[v3,01/18] Input: synaptics-rmi4 - Move IRQ handling to rmi_driver
[v3,02/18] Input: synaptics-rmi4 - factor out functions from probe
[v3,03/18] Input: synaptics-rmi4 - Handle incomplete input data
[v3,04/18] Input: synaptics-rmi4 - Add parameters for dribble packets
and palm detect gesture
[v3,05/18] Input: synaptics-rmi4 - Add support for controlling dribble
packets in F12
[v3,06/18] Input: synaptics-rmi4 - Set the ABS_MT_TOOL_TYPE bit to
report tool type
[v3,09/18] Input: synaptics-rmi4 - have only one struct platform data
[v3,18/18] Input: synaptics-rmi4 - fix documentation of
rmi_2d_sensor_platform_data

This is the bare minimum I think to enable the F12 in hid-rmi. It
should apply gracefully (crossing finger for 9/18), and would allow us
to switch hid-rmi to rmi4-core.

I guess Jiri will probably want a stable branch with those commits so
we can also merge the switch from hid-rmi to use rmi4-core in v4.10.

Cheers,
Benjamin

>
> Cheers,
> Benjamin
>
> Andrew Duggan (4):
>   Input: synaptics-rmi4 - Handle incomplete input data
>   Input: synaptics-rmi4 - Add parameters for dribble packets and palm
>     detect gesture
>   Input: synaptics-rmi4 - Add support for controlling dribble packets in
>     F12
>   Input: synaptics-rmi4 - Set the ABS_MT_TOOL_TYPE bit to report tool
>     type
>
> Benjamin Tissoires (10):
>   Input: synaptics-rmi4 - add SMBus support
>   Input: serio - store the pt_buttons in the struct serio directly
>   Input: synaptics-rmi4 - have only one struct platform data
>   Input: synaptics-rmi4 - Add rmi_find_function()
>   Input: synaptics-rmi4 - f30/f03: Forward mechanical buttons on
>     buttonpads to PS/2 guest
>   Input: synaptics - allocate a Synaptics Intertouch device
>   Input: synaptics-rmi4 - add rmi_platform
>   Input: synaptics-rmi4 - smbus: call psmouse_deactivate before
>     binding/resume
>   Input: synaptics-rmi4 - smbus: on resume, try 3 times if init fails
>   Input: synaptics-rmi4 - fix documentation of
>     rmi_2d_sensor_platform_data
>
> Bjorn Andersson (1):
>   Input: synaptics-rmi4 - Move IRQ handling to rmi_driver
>
> Dennis Wassenberg (1):
>   Input: synaptics-rmi4 - f03: grab data passed by transport device
>
> Lyude Paul (1):
>   Input: synaptics-rmi4 - add support for F03
>
> Nick Dyer (1):
>   Input: synaptics-rmi4 - factor out functions from probe
>
>  drivers/input/mouse/psmouse-base.c |  12 +
>  drivers/input/mouse/psmouse.h      |   1 +
>  drivers/input/mouse/synaptics.c    | 153 +++++++++++-
>  drivers/input/mouse/synaptics.h    |   5 +-
>  drivers/input/rmi4/Kconfig         |  33 +++
>  drivers/input/rmi4/Makefile        |   3 +
>  drivers/input/rmi4/rmi_2d_sensor.c |   2 +
>  drivers/input/rmi4/rmi_2d_sensor.h |   2 +
>  drivers/input/rmi4/rmi_bus.c       |   3 +
>  drivers/input/rmi4/rmi_bus.h       |  12 +
>  drivers/input/rmi4/rmi_driver.c    | 225 ++++++++++++-----
>  drivers/input/rmi4/rmi_driver.h    |  15 ++
>  drivers/input/rmi4/rmi_f01.c       |   6 +-
>  drivers/input/rmi4/rmi_f03.c       | 272 +++++++++++++++++++++
>  drivers/input/rmi4/rmi_f11.c       |  90 +++++--
>  drivers/input/rmi4/rmi_f12.c       | 100 +++++++-
>  drivers/input/rmi4/rmi_f30.c       |  83 +++++--
>  drivers/input/rmi4/rmi_i2c.c       |  74 +-----
>  drivers/input/rmi4/rmi_platform.c  | 235 ++++++++++++++++++
>  drivers/input/rmi4/rmi_smbus.c     | 477 +++++++++++++++++++++++++++++++++++++
>  drivers/input/rmi4/rmi_spi.c       |  72 +-----
>  include/linux/rmi.h                |  47 ++--
>  include/linux/serio.h              |   8 +
>  include/uapi/linux/serio.h         |   1 +
>  24 files changed, 1663 insertions(+), 268 deletions(-)
>  create mode 100644 drivers/input/rmi4/rmi_f03.c
>  create mode 100644 drivers/input/rmi4/rmi_platform.c
>  create mode 100644 drivers/input/rmi4/rmi_smbus.c
>
> --
> 2.7.4
>

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

* Re: [PATCH v3 00/18] Synaptics RMI4 and SMBus implementation
  2016-11-04  8:23 ` [PATCH v3 00/18] Synaptics RMI4 and SMBus implementation Benjamin Tissoires
@ 2016-11-07 23:17   ` Nick Dyer
  2016-11-08 15:09     ` Benjamin Tissoires
  0 siblings, 1 reply; 28+ messages in thread
From: Nick Dyer @ 2016-11-07 23:17 UTC (permalink / raw)
  To: Benjamin Tissoires
  Cc: Benjamin Tissoires, Dmitry Torokhov, Andrew Duggan, Lyude Paul,
	Christopher Heiny, Bjorn Andersson, Dennis Wassenberg,
	linux-kernel, linux-input, Jiri Kosina, Chris Healy

On Fri, Nov 04, 2016 at 09:23:48AM +0100, Benjamin Tissoires wrote:
> On Thu, Oct 13, 2016 at 5:50 PM, Benjamin Tissoires
> <benjamin.tissoires@redhat.com> wrote:
> > Hi guys,
> >
> > This is the third submission of this series, with some addition of RMI4 patches
> > currently waiting on the list.
> >
> > I integrated Bjorn's patch because in the end, it seems to be the right thing
> > to do. We can create an irqchip in hid-rmi and also provide an IRQ there.
> > Worse case, if this doesn't work, we can always add a special case to
> > disable the handling of the IRQs in core.
> >
> > I took Nick's patch as it's a nice cleanup and it solves an issue where
> > the mutex irq_mutex might not be initialized (in the case we are not handling
> > IRQ directly in core).
> >
> > I also took some patches from Andrew that were submitted back in July, and that
> > were left over. They are required to allow hid-rmi to use rmi4-core without
> > losing functionality. The DT binding seemed to be problematic, so I just lefted
> > it out of the series. We can add it later when required (if required).
> > Andrew, regarding hid-rmi, I'll try to give you a draft of the irqchip
> > implementation based on what I did for SMBus Host Notify.
> >
> > The rest is an update of the SMBus work. The main differences is that now
> > rmi4-smbus doesn't handle anymore the IRQ and I hope that the SMBus Host Notify
> > patches I posted on linux-i2c will be approved by Wolfram.
> 
> I understand you are busy with many other projects, but it would be
> great if we could have this series (or a subset of this series)
> landing ASAP.
> 
> We already have at least 2 machines (the Lenovo X1 Tablet and the HP
> Pavilion x2) that need to be using the function 12 in Synaptics RMI4,
> and so this series is a requirement to enable those touchpads.
> 
> If you really want to postpone the review of the new files in this
> series, I think merging only the following patches would be
> acceptable:
> [v3,01/18] Input: synaptics-rmi4 - Move IRQ handling to rmi_driver
> [v3,02/18] Input: synaptics-rmi4 - factor out functions from probe
> [v3,03/18] Input: synaptics-rmi4 - Handle incomplete input data
> [v3,04/18] Input: synaptics-rmi4 - Add parameters for dribble packets
> and palm detect gesture
> [v3,05/18] Input: synaptics-rmi4 - Add support for controlling dribble
> packets in F12
> [v3,06/18] Input: synaptics-rmi4 - Set the ABS_MT_TOOL_TYPE bit to
> report tool type
> [v3,09/18] Input: synaptics-rmi4 - have only one struct platform data
> [v3,18/18] Input: synaptics-rmi4 - fix documentation of
> rmi_2d_sensor_platform_data
> 
> This is the bare minimum I think to enable the F12 in hid-rmi. It
> should apply gracefully (crossing finger for 9/18), and would allow us
> to switch hid-rmi to rmi4-core.
> 
> I guess Jiri will probably want a stable branch with those commits so
> we can also merge the switch from hid-rmi to use rmi4-core in v4.10.

Hi Benjamin-

Just to say, there's a few other patches that we would be keen to also
get into v4.10 if possible:

These three enable the F54 support to work properly on more devices:

Input: synaptics-rmi4 - stop scanning PDT after two empty pages
https://patchwork.kernel.org/patch/9398323/

Input: synaptics-rmi4 - add support for F55 sensor tuning
https://patchwork.kernel.org/patch/9359055/

Input: synaptics-rmi4 - Propagate correct number of rx and tx electrodes
to F54
https://patchwork.kernel.org/patch/9359059/


I would also be keen to get at least some of the F34 reflash support in:
http://www.spinics.net/lists/linux-input/msg47479.html

Would you be able to merge any of these into your series? I am happy to
do some of the work if you are busy.

cheers

Nick

> > Andrew Duggan (4):
> >   Input: synaptics-rmi4 - Handle incomplete input data
> >   Input: synaptics-rmi4 - Add parameters for dribble packets and palm
> >     detect gesture
> >   Input: synaptics-rmi4 - Add support for controlling dribble packets in
> >     F12
> >   Input: synaptics-rmi4 - Set the ABS_MT_TOOL_TYPE bit to report tool
> >     type
> >
> > Benjamin Tissoires (10):
> >   Input: synaptics-rmi4 - add SMBus support
> >   Input: serio - store the pt_buttons in the struct serio directly
> >   Input: synaptics-rmi4 - have only one struct platform data
> >   Input: synaptics-rmi4 - Add rmi_find_function()
> >   Input: synaptics-rmi4 - f30/f03: Forward mechanical buttons on
> >     buttonpads to PS/2 guest
> >   Input: synaptics - allocate a Synaptics Intertouch device
> >   Input: synaptics-rmi4 - add rmi_platform
> >   Input: synaptics-rmi4 - smbus: call psmouse_deactivate before
> >     binding/resume
> >   Input: synaptics-rmi4 - smbus: on resume, try 3 times if init fails
> >   Input: synaptics-rmi4 - fix documentation of
> >     rmi_2d_sensor_platform_data
> >
> > Bjorn Andersson (1):
> >   Input: synaptics-rmi4 - Move IRQ handling to rmi_driver
> >
> > Dennis Wassenberg (1):
> >   Input: synaptics-rmi4 - f03: grab data passed by transport device
> >
> > Lyude Paul (1):
> >   Input: synaptics-rmi4 - add support for F03
> >
> > Nick Dyer (1):
> >   Input: synaptics-rmi4 - factor out functions from probe

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

* Re: [PATCH v3 00/18] Synaptics RMI4 and SMBus implementation
  2016-11-07 23:17   ` Nick Dyer
@ 2016-11-08 15:09     ` Benjamin Tissoires
  0 siblings, 0 replies; 28+ messages in thread
From: Benjamin Tissoires @ 2016-11-08 15:09 UTC (permalink / raw)
  To: Nick Dyer
  Cc: Dmitry Torokhov, Andrew Duggan, Lyude Paul, Christopher Heiny,
	Bjorn Andersson, Dennis Wassenberg, linux-kernel, linux-input,
	Jiri Kosina, Chris Healy

Hi Nick,

On Nov 07 2016 or thereabouts, Nick Dyer wrote:
> On Fri, Nov 04, 2016 at 09:23:48AM +0100, Benjamin Tissoires wrote:
> > On Thu, Oct 13, 2016 at 5:50 PM, Benjamin Tissoires
> > <benjamin.tissoires@redhat.com> wrote:
> > > Hi guys,
> > >
> > > This is the third submission of this series, with some addition of RMI4 patches
> > > currently waiting on the list.
> > >
> > > I integrated Bjorn's patch because in the end, it seems to be the right thing
> > > to do. We can create an irqchip in hid-rmi and also provide an IRQ there.
> > > Worse case, if this doesn't work, we can always add a special case to
> > > disable the handling of the IRQs in core.
> > >
> > > I took Nick's patch as it's a nice cleanup and it solves an issue where
> > > the mutex irq_mutex might not be initialized (in the case we are not handling
> > > IRQ directly in core).
> > >
> > > I also took some patches from Andrew that were submitted back in July, and that
> > > were left over. They are required to allow hid-rmi to use rmi4-core without
> > > losing functionality. The DT binding seemed to be problematic, so I just lefted
> > > it out of the series. We can add it later when required (if required).
> > > Andrew, regarding hid-rmi, I'll try to give you a draft of the irqchip
> > > implementation based on what I did for SMBus Host Notify.
> > >
> > > The rest is an update of the SMBus work. The main differences is that now
> > > rmi4-smbus doesn't handle anymore the IRQ and I hope that the SMBus Host Notify
> > > patches I posted on linux-i2c will be approved by Wolfram.
> > 
> > I understand you are busy with many other projects, but it would be
> > great if we could have this series (or a subset of this series)
> > landing ASAP.
> > 
> > We already have at least 2 machines (the Lenovo X1 Tablet and the HP
> > Pavilion x2) that need to be using the function 12 in Synaptics RMI4,
> > and so this series is a requirement to enable those touchpads.
> > 
> > If you really want to postpone the review of the new files in this
> > series, I think merging only the following patches would be
> > acceptable:
> > [v3,01/18] Input: synaptics-rmi4 - Move IRQ handling to rmi_driver
> > [v3,02/18] Input: synaptics-rmi4 - factor out functions from probe
> > [v3,03/18] Input: synaptics-rmi4 - Handle incomplete input data
> > [v3,04/18] Input: synaptics-rmi4 - Add parameters for dribble packets
> > and palm detect gesture
> > [v3,05/18] Input: synaptics-rmi4 - Add support for controlling dribble
> > packets in F12
> > [v3,06/18] Input: synaptics-rmi4 - Set the ABS_MT_TOOL_TYPE bit to
> > report tool type
> > [v3,09/18] Input: synaptics-rmi4 - have only one struct platform data
> > [v3,18/18] Input: synaptics-rmi4 - fix documentation of
> > rmi_2d_sensor_platform_data
> > 
> > This is the bare minimum I think to enable the F12 in hid-rmi. It
> > should apply gracefully (crossing finger for 9/18), and would allow us
> > to switch hid-rmi to rmi4-core.
> > 
> > I guess Jiri will probably want a stable branch with those commits so
> > we can also merge the switch from hid-rmi to use rmi4-core in v4.10.
> 
> Hi Benjamin-
> 
> Just to say, there's a few other patches that we would be keen to also
> get into v4.10 if possible:
> 
> These three enable the F54 support to work properly on more devices:
> 
> Input: synaptics-rmi4 - stop scanning PDT after two empty pages
> https://patchwork.kernel.org/patch/9398323/
> 
> Input: synaptics-rmi4 - add support for F55 sensor tuning
> https://patchwork.kernel.org/patch/9359055/
> 
> Input: synaptics-rmi4 - Propagate correct number of rx and tx electrodes
> to F54
> https://patchwork.kernel.org/patch/9359059/
> 
> 
> I would also be keen to get at least some of the F34 reflash support in:
> http://www.spinics.net/lists/linux-input/msg47479.html
> 
> Would you be able to merge any of these into your series? I am happy to
> do some of the work if you are busy.

I would have answered, yes, sure, but given that Dmitry started to
review/apply part of the F34 series, I am not so sure anymore.

I am a little bit busy this week, but I still kept an eye on the review
I need to do on F34.

I think it would be good to have a common tree with the changes we want
to push in rmi4. An other solution could be to set a group of patches in
patchwork to keep track of them and not lose one.
If you want to lead that, feel free to setup a branch.

Cheers,
Benjamin

> 
> cheers
> 
> Nick
> 
> > > Andrew Duggan (4):
> > >   Input: synaptics-rmi4 - Handle incomplete input data
> > >   Input: synaptics-rmi4 - Add parameters for dribble packets and palm
> > >     detect gesture
> > >   Input: synaptics-rmi4 - Add support for controlling dribble packets in
> > >     F12
> > >   Input: synaptics-rmi4 - Set the ABS_MT_TOOL_TYPE bit to report tool
> > >     type
> > >
> > > Benjamin Tissoires (10):
> > >   Input: synaptics-rmi4 - add SMBus support
> > >   Input: serio - store the pt_buttons in the struct serio directly
> > >   Input: synaptics-rmi4 - have only one struct platform data
> > >   Input: synaptics-rmi4 - Add rmi_find_function()
> > >   Input: synaptics-rmi4 - f30/f03: Forward mechanical buttons on
> > >     buttonpads to PS/2 guest
> > >   Input: synaptics - allocate a Synaptics Intertouch device
> > >   Input: synaptics-rmi4 - add rmi_platform
> > >   Input: synaptics-rmi4 - smbus: call psmouse_deactivate before
> > >     binding/resume
> > >   Input: synaptics-rmi4 - smbus: on resume, try 3 times if init fails
> > >   Input: synaptics-rmi4 - fix documentation of
> > >     rmi_2d_sensor_platform_data
> > >
> > > Bjorn Andersson (1):
> > >   Input: synaptics-rmi4 - Move IRQ handling to rmi_driver
> > >
> > > Dennis Wassenberg (1):
> > >   Input: synaptics-rmi4 - f03: grab data passed by transport device
> > >
> > > Lyude Paul (1):
> > >   Input: synaptics-rmi4 - add support for F03
> > >
> > > Nick Dyer (1):
> > >   Input: synaptics-rmi4 - factor out functions from probe

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

* Re: [PATCH v3 03/18] Input: synaptics-rmi4 - Handle incomplete input data
  2016-10-13 15:50 ` [PATCH v3 03/18] Input: synaptics-rmi4 - Handle incomplete input data Benjamin Tissoires
@ 2016-11-09  0:46   ` Dmitry Torokhov
  0 siblings, 0 replies; 28+ messages in thread
From: Dmitry Torokhov @ 2016-11-09  0:46 UTC (permalink / raw)
  To: Benjamin Tissoires
  Cc: Andrew Duggan, Lyude Paul, Christopher Heiny, Nick Dyer,
	Bjorn Andersson, Dennis Wassenberg, linux-kernel, linux-input

On Thu, Oct 13, 2016 at 05:50:57PM +0200, Benjamin Tissoires wrote:
> From: Andrew Duggan <aduggan@synaptics.com>
> 
> Commit 5b65c2a02966 ("HID: rmi: check sanity of the incoming report") added
> support for handling incomplete HID reports do to the input data being
> corrupted in transit. This patch reimplements this functionality in the
> function drivers so they can handle getting less valid data then they
> expect.
> 
> Signed-off-by: Andrew Duggan <aduggan@synaptics.com>
> Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>

Applied, thank you.

> 
> ---
> 
> new in v3
> ---
>  drivers/input/rmi4/rmi_f11.c | 54 ++++++++++++++++++++++++++++++++------------
>  drivers/input/rmi4/rmi_f12.c | 23 ++++++++++++++-----
>  drivers/input/rmi4/rmi_f30.c |  4 ++++
>  3 files changed, 61 insertions(+), 20 deletions(-)
> 
> diff --git a/drivers/input/rmi4/rmi_f11.c b/drivers/input/rmi4/rmi_f11.c
> index 20c7134..3218742 100644
> --- a/drivers/input/rmi4/rmi_f11.c
> +++ b/drivers/input/rmi4/rmi_f11.c
> @@ -572,31 +572,48 @@ static inline u8 rmi_f11_parse_finger_state(const u8 *f_state, u8 n_finger)
>  
>  static void rmi_f11_finger_handler(struct f11_data *f11,
>  				   struct rmi_2d_sensor *sensor,
> -				   unsigned long *irq_bits, int num_irq_regs)
> +				   unsigned long *irq_bits, int num_irq_regs,
> +				   int size)
>  {
>  	const u8 *f_state = f11->data.f_state;
>  	u8 finger_state;
>  	u8 i;
> +	int abs_fingers;
> +	int rel_fingers;
> +	int abs_size = sensor->nbr_fingers * RMI_F11_ABS_BYTES;
>  
>  	int abs_bits = bitmap_and(f11->result_bits, irq_bits, f11->abs_mask,
>  				  num_irq_regs * 8);
>  	int rel_bits = bitmap_and(f11->result_bits, irq_bits, f11->rel_mask,
>  				  num_irq_regs * 8);
>  
> -	for (i = 0; i < sensor->nbr_fingers; i++) {
> -		/* Possible of having 4 fingers per f_statet register */
> -		finger_state = rmi_f11_parse_finger_state(f_state, i);
> -		if (finger_state == F11_RESERVED) {
> -			pr_err("Invalid finger state[%d]: 0x%02x", i,
> -				finger_state);
> -			continue;
> -		}
> +	if (abs_bits) {
> +		if (abs_size > size)
> +			abs_fingers = size / RMI_F11_ABS_BYTES;
> +		else
> +			abs_fingers = sensor->nbr_fingers;
> +
> +		for (i = 0; i < abs_fingers; i++) {
> +			/* Possible of having 4 fingers per f_state register */
> +			finger_state = rmi_f11_parse_finger_state(f_state, i);
> +			if (finger_state == F11_RESERVED) {
> +				pr_err("Invalid finger state[%d]: 0x%02x", i,
> +					finger_state);
> +				continue;
> +			}
>  
> -		if (abs_bits)
>  			rmi_f11_abs_pos_process(f11, sensor, &sensor->objs[i],
>  							finger_state, i);
> +		}
> +	}
> +
> +	if (rel_bits) {
> +		if ((abs_size + sensor->nbr_fingers * RMI_F11_REL_BYTES) > size)
> +			rel_fingers = (size - abs_size) / RMI_F11_REL_BYTES;
> +		else
> +			rel_fingers = sensor->nbr_fingers;
>  
> -		if (rel_bits)
> +		for (i = 0; i < rel_fingers; i++)
>  			rmi_f11_rel_pos_report(f11, i);
>  	}
>  
> @@ -612,7 +629,7 @@ static void rmi_f11_finger_handler(struct f11_data *f11,
>  					      sensor->nbr_fingers,
>  					      sensor->dmax);
>  
> -		for (i = 0; i < sensor->nbr_fingers; i++) {
> +		for (i = 0; i < abs_fingers; i++) {
>  			finger_state = rmi_f11_parse_finger_state(f_state, i);
>  			if (finger_state == F11_RESERVED)
>  				/* no need to send twice the error */
> @@ -1242,10 +1259,19 @@ static int rmi_f11_attention(struct rmi_function *fn, unsigned long *irq_bits)
>  	struct f11_data *f11 = dev_get_drvdata(&fn->dev);
>  	u16 data_base_addr = fn->fd.data_base_addr;
>  	int error;
> +	int valid_bytes = f11->sensor.pkt_size;
>  
>  	if (rmi_dev->xport->attn_data) {
> +		/*
> +		 * The valid data in the attention report is less then
> +		 * expected. Only process the complete fingers.
> +		 */
> +		if (f11->sensor.attn_size > rmi_dev->xport->attn_size)
> +			valid_bytes = rmi_dev->xport->attn_size;
> +		else
> +			valid_bytes = f11->sensor.attn_size;
>  		memcpy(f11->sensor.data_pkt, rmi_dev->xport->attn_data,
> -			f11->sensor.attn_size);
> +			valid_bytes);
>  		rmi_dev->xport->attn_data += f11->sensor.attn_size;
>  		rmi_dev->xport->attn_size -= f11->sensor.attn_size;
>  	} else {
> @@ -1257,7 +1283,7 @@ static int rmi_f11_attention(struct rmi_function *fn, unsigned long *irq_bits)
>  	}
>  
>  	rmi_f11_finger_handler(f11, &f11->sensor, irq_bits,
> -				drvdata->num_of_irq_regs);
> +				drvdata->num_of_irq_regs, valid_bytes);
>  
>  	return 0;
>  }
> diff --git a/drivers/input/rmi4/rmi_f12.c b/drivers/input/rmi4/rmi_f12.c
> index 332c02f..767ac79 100644
> --- a/drivers/input/rmi4/rmi_f12.c
> +++ b/drivers/input/rmi4/rmi_f12.c
> @@ -26,6 +26,8 @@ enum rmi_f12_object_type {
>  	RMI_F12_OBJECT_SMALL_OBJECT		= 0x0D,
>  };
>  
> +#define F12_DATA1_BYTES_PER_OBJ			8
> +
>  struct f12_data {
>  	struct rmi_2d_sensor sensor;
>  	struct rmi_2d_sensor_platform_data sensor_pdata;
> @@ -146,12 +148,16 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12)
>  	return 0;
>  }
>  
> -static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1)
> +static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1, int size)
>  {
>  	int i;
>  	struct rmi_2d_sensor *sensor = &f12->sensor;
> +	int objects = f12->data1->num_subpackets;
> +
> +	if ((f12->data1->num_subpackets * F12_DATA1_BYTES_PER_OBJ) > size)
> +		objects = size / F12_DATA1_BYTES_PER_OBJ;
>  
> -	for (i = 0; i < f12->data1->num_subpackets; i++) {
> +	for (i = 0; i < objects; i++) {
>  		struct rmi_2d_sensor_abs_object *obj = &sensor->objs[i];
>  
>  		obj->type = RMI_2D_OBJECT_NONE;
> @@ -182,7 +188,7 @@ static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1)
>  
>  		rmi_2d_sensor_abs_process(sensor, obj, i);
>  
> -		data1 += 8;
> +		data1 += F12_DATA1_BYTES_PER_OBJ;
>  	}
>  
>  	if (sensor->kernel_tracking)
> @@ -192,7 +198,7 @@ static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1)
>  				      sensor->nbr_fingers,
>  				      sensor->dmax);
>  
> -	for (i = 0; i < sensor->nbr_fingers; i++)
> +	for (i = 0; i < objects; i++)
>  		rmi_2d_sensor_abs_report(sensor, &sensor->objs[i], i);
>  }
>  
> @@ -203,10 +209,15 @@ static int rmi_f12_attention(struct rmi_function *fn,
>  	struct rmi_device *rmi_dev = fn->rmi_dev;
>  	struct f12_data *f12 = dev_get_drvdata(&fn->dev);
>  	struct rmi_2d_sensor *sensor = &f12->sensor;
> +	int valid_bytes = sensor->pkt_size;
>  
>  	if (rmi_dev->xport->attn_data) {
> +		if (sensor->attn_size > rmi_dev->xport->attn_size)
> +			valid_bytes = rmi_dev->xport->attn_size;
> +		else
> +			valid_bytes = sensor->attn_size;
>  		memcpy(sensor->data_pkt, rmi_dev->xport->attn_data,
> -			sensor->attn_size);
> +			valid_bytes);
>  		rmi_dev->xport->attn_data += sensor->attn_size;
>  		rmi_dev->xport->attn_size -= sensor->attn_size;
>  	} else {
> @@ -221,7 +232,7 @@ static int rmi_f12_attention(struct rmi_function *fn,
>  
>  	if (f12->data1)
>  		rmi_f12_process_objects(f12,
> -			&sensor->data_pkt[f12->data1_offset]);
> +			&sensor->data_pkt[f12->data1_offset], valid_bytes);
>  
>  	input_mt_sync_frame(sensor->input);
>  
> diff --git a/drivers/input/rmi4/rmi_f30.c b/drivers/input/rmi4/rmi_f30.c
> index 760aff1..485907f 100644
> --- a/drivers/input/rmi4/rmi_f30.c
> +++ b/drivers/input/rmi4/rmi_f30.c
> @@ -110,6 +110,10 @@ static int rmi_f30_attention(struct rmi_function *fn, unsigned long *irq_bits)
>  
>  	/* Read the gpi led data. */
>  	if (rmi_dev->xport->attn_data) {
> +		if (rmi_dev->xport->attn_size < f30->register_count) {
> +			dev_warn(&fn->dev, "F30 interrupted, but data is missing\n");
> +			return 0;
> +		}
>  		memcpy(f30->data_regs, rmi_dev->xport->attn_data,
>  			f30->register_count);
>  		rmi_dev->xport->attn_data += f30->register_count;
> -- 
> 2.7.4
> 

-- 
Dmitry

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

* Re: [PATCH v3 01/18] Input: synaptics-rmi4 - Move IRQ handling to rmi_driver
  2016-10-13 15:50 ` [PATCH v3 01/18] Input: synaptics-rmi4 - Move IRQ handling to rmi_driver Benjamin Tissoires
@ 2016-11-09  0:47   ` Dmitry Torokhov
  0 siblings, 0 replies; 28+ messages in thread
From: Dmitry Torokhov @ 2016-11-09  0:47 UTC (permalink / raw)
  To: Benjamin Tissoires
  Cc: Andrew Duggan, Lyude Paul, Christopher Heiny, Nick Dyer,
	Bjorn Andersson, Dennis Wassenberg, linux-kernel, linux-input

On Thu, Oct 13, 2016 at 05:50:55PM +0200, Benjamin Tissoires wrote:
> From: Bjorn Andersson <bjorn.andersson@linaro.org>
> 
> The attn IRQ is related to the chip, rather than the transport, so move
> all handling of interrupts to the core driver. This also makes sure that
> there are no races between interrupts and availability of the resources
> used by the core driver.
> 
> Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
> Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>

Applied, thank you.

> 
> ---
> 
> new in v3
> 
> changes since Bjorn's submission:
> - call disable_irq on remove()
> ---
>  drivers/input/rmi4/rmi_driver.c | 73 +++++++++++++++++++++++++++++++++++++---
>  drivers/input/rmi4/rmi_i2c.c    | 74 +++--------------------------------------
>  drivers/input/rmi4/rmi_spi.c    | 72 +++------------------------------------
>  include/linux/rmi.h             |  7 ++--
>  4 files changed, 83 insertions(+), 143 deletions(-)
> 
> diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c
> index c83bce8..cf780ef 100644
> --- a/drivers/input/rmi4/rmi_driver.c
> +++ b/drivers/input/rmi4/rmi_driver.c
> @@ -17,6 +17,7 @@
>  #include <linux/bitmap.h>
>  #include <linux/delay.h>
>  #include <linux/fs.h>
> +#include <linux/irq.h>
>  #include <linux/kconfig.h>
>  #include <linux/pm.h>
>  #include <linux/slab.h>
> @@ -134,7 +135,7 @@ static void process_one_interrupt(struct rmi_driver_data *data,
>  	}
>  }
>  
> -int rmi_process_interrupt_requests(struct rmi_device *rmi_dev)
> +static int rmi_process_interrupt_requests(struct rmi_device *rmi_dev)
>  {
>  	struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
>  	struct device *dev = &rmi_dev->dev;
> @@ -179,7 +180,42 @@ int rmi_process_interrupt_requests(struct rmi_device *rmi_dev)
>  
>  	return 0;
>  }
> -EXPORT_SYMBOL_GPL(rmi_process_interrupt_requests);
> +
> +static irqreturn_t rmi_irq_fn(int irq, void *dev_id)
> +{
> +	struct rmi_device *rmi_dev = dev_id;
> +	int ret;
> +
> +	ret = rmi_process_interrupt_requests(rmi_dev);
> +	if (ret)
> +		rmi_dbg(RMI_DEBUG_CORE, &rmi_dev->dev,
> +			"Failed to process interrupt request: %d\n", ret);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int rmi_irq_init(struct rmi_device *rmi_dev)
> +{
> +	struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev);
> +	int irq_flags = irq_get_trigger_type(pdata->irq);
> +	int ret;
> +
> +	if (!irq_flags)
> +		irq_flags = IRQF_TRIGGER_LOW;
> +
> +	ret = devm_request_threaded_irq(&rmi_dev->dev, pdata->irq, NULL,
> +					rmi_irq_fn, irq_flags | IRQF_ONESHOT,
> +					dev_name(rmi_dev->xport->dev),
> +					rmi_dev);
> +	if (ret < 0) {
> +		dev_warn(&rmi_dev->dev, "Failed to register interrupt %d\n",
> +			 pdata->irq);
> +
> +		return ret;
> +	}
> +
> +	return 0;
> +}
>  
>  static int suspend_one_function(struct rmi_function *fn)
>  {
> @@ -787,8 +823,10 @@ err_put_fn:
>  	return error;
>  }
>  
> -int rmi_driver_suspend(struct rmi_device *rmi_dev)
> +int rmi_driver_suspend(struct rmi_device *rmi_dev, bool enable_wake)
>  {
> +	struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev);
> +	int irq = pdata->irq;
>  	int retval = 0;
>  
>  	retval = rmi_suspend_functions(rmi_dev);
> @@ -796,14 +834,33 @@ int rmi_driver_suspend(struct rmi_device *rmi_dev)
>  		dev_warn(&rmi_dev->dev, "Failed to suspend functions: %d\n",
>  			retval);
>  
> +	disable_irq(irq);
> +	if (enable_wake && device_may_wakeup(rmi_dev->xport->dev)) {
> +		retval = enable_irq_wake(irq);
> +		if (!retval)
> +			dev_warn(&rmi_dev->dev,
> +				 "Failed to enable irq for wake: %d\n",
> +				 retval);
> +	}
>  	return retval;
>  }
>  EXPORT_SYMBOL_GPL(rmi_driver_suspend);
>  
> -int rmi_driver_resume(struct rmi_device *rmi_dev)
> +int rmi_driver_resume(struct rmi_device *rmi_dev, bool clear_wake)
>  {
> +	struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev);
> +	int irq = pdata->irq;
>  	int retval;
>  
> +	enable_irq(irq);
> +	if (clear_wake && device_may_wakeup(rmi_dev->xport->dev)) {
> +		retval = disable_irq_wake(irq);
> +		if (!retval)
> +			dev_warn(&rmi_dev->dev,
> +				 "Failed to disable irq for wake: %d\n",
> +				 retval);
> +	}
> +
>  	retval = rmi_resume_functions(rmi_dev);
>  	if (retval)
>  		dev_warn(&rmi_dev->dev, "Failed to suspend functions: %d\n",
> @@ -816,6 +873,10 @@ EXPORT_SYMBOL_GPL(rmi_driver_resume);
>  static int rmi_driver_remove(struct device *dev)
>  {
>  	struct rmi_device *rmi_dev = to_rmi_device(dev);
> +	struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev);
> +	int irq = pdata->irq;
> +
> +	disable_irq(irq);
>  
>  	rmi_free_function_list(rmi_dev);
>  
> @@ -1004,6 +1065,10 @@ static int rmi_driver_probe(struct device *dev)
>  		}
>  	}
>  
> +	retval = rmi_irq_init(rmi_dev);
> +	if (retval < 0)
> +		goto err_destroy_functions;
> +
>  	if (data->f01_container->dev.driver)
>  		/* Driver already bound, so enable ATTN now. */
>  		return enable_sensor(rmi_dev);
> diff --git a/drivers/input/rmi4/rmi_i2c.c b/drivers/input/rmi4/rmi_i2c.c
> index 6f2e0e4..64a5488 100644
> --- a/drivers/input/rmi4/rmi_i2c.c
> +++ b/drivers/input/rmi4/rmi_i2c.c
> @@ -9,7 +9,6 @@
>  
>  #include <linux/i2c.h>
>  #include <linux/rmi.h>
> -#include <linux/irq.h>
>  #include <linux/of.h>
>  #include <linux/delay.h>
>  #include <linux/regulator/consumer.h>
> @@ -35,8 +34,6 @@ struct rmi_i2c_xport {
>  	struct mutex page_mutex;
>  	int page;
>  
> -	int irq;
> -
>  	u8 *tx_buf;
>  	size_t tx_buf_size;
>  
> @@ -177,42 +174,6 @@ static const struct rmi_transport_ops rmi_i2c_ops = {
>  	.read_block	= rmi_i2c_read_block,
>  };
>  
> -static irqreturn_t rmi_i2c_irq(int irq, void *dev_id)
> -{
> -	struct rmi_i2c_xport *rmi_i2c = dev_id;
> -	struct rmi_device *rmi_dev = rmi_i2c->xport.rmi_dev;
> -	int ret;
> -
> -	ret = rmi_process_interrupt_requests(rmi_dev);
> -	if (ret)
> -		rmi_dbg(RMI_DEBUG_XPORT, &rmi_dev->dev,
> -			"Failed to process interrupt request: %d\n", ret);
> -
> -	return IRQ_HANDLED;
> -}
> -
> -static int rmi_i2c_init_irq(struct i2c_client *client)
> -{
> -	struct rmi_i2c_xport *rmi_i2c = i2c_get_clientdata(client);
> -	int irq_flags = irqd_get_trigger_type(irq_get_irq_data(rmi_i2c->irq));
> -	int ret;
> -
> -	if (!irq_flags)
> -		irq_flags = IRQF_TRIGGER_LOW;
> -
> -	ret = devm_request_threaded_irq(&client->dev, rmi_i2c->irq, NULL,
> -			rmi_i2c_irq, irq_flags | IRQF_ONESHOT, client->name,
> -			rmi_i2c);
> -	if (ret < 0) {
> -		dev_warn(&client->dev, "Failed to register interrupt %d\n",
> -			rmi_i2c->irq);
> -
> -		return ret;
> -	}
> -
> -	return 0;
> -}
> -
>  #ifdef CONFIG_OF
>  static const struct of_device_id rmi_i2c_of_match[] = {
>  	{ .compatible = "syna,rmi4-i2c" },
> @@ -240,8 +201,7 @@ static int rmi_i2c_probe(struct i2c_client *client,
>  	if (!client->dev.of_node && client_pdata)
>  		*pdata = *client_pdata;
>  
> -	if (client->irq > 0)
> -		rmi_i2c->irq = client->irq;
> +	pdata->irq = client->irq;
>  
>  	rmi_dbg(RMI_DEBUG_XPORT, &client->dev, "Probing %s.\n",
>  			dev_name(&client->dev));
> @@ -295,10 +255,6 @@ static int rmi_i2c_probe(struct i2c_client *client,
>  		return retval;
>  	}
>  
> -	retval = rmi_i2c_init_irq(client);
> -	if (retval < 0)
> -		return retval;
> -
>  	dev_info(&client->dev, "registered rmi i2c driver at %#04x.\n",
>  			client->addr);
>  	return 0;
> @@ -322,18 +278,10 @@ static int rmi_i2c_suspend(struct device *dev)
>  	struct rmi_i2c_xport *rmi_i2c = i2c_get_clientdata(client);
>  	int ret;
>  
> -	ret = rmi_driver_suspend(rmi_i2c->xport.rmi_dev);
> +	ret = rmi_driver_suspend(rmi_i2c->xport.rmi_dev, true);
>  	if (ret)
>  		dev_warn(dev, "Failed to resume device: %d\n", ret);
>  
> -	disable_irq(rmi_i2c->irq);
> -	if (device_may_wakeup(&client->dev)) {
> -		ret = enable_irq_wake(rmi_i2c->irq);
> -		if (!ret)
> -			dev_warn(dev, "Failed to enable irq for wake: %d\n",
> -				ret);
> -	}
> -
>  	regulator_bulk_disable(ARRAY_SIZE(rmi_i2c->supplies),
>  			       rmi_i2c->supplies);
>  
> @@ -353,15 +301,7 @@ static int rmi_i2c_resume(struct device *dev)
>  
>  	msleep(rmi_i2c->startup_delay);
>  
> -	enable_irq(rmi_i2c->irq);
> -	if (device_may_wakeup(&client->dev)) {
> -		ret = disable_irq_wake(rmi_i2c->irq);
> -		if (!ret)
> -			dev_warn(dev, "Failed to disable irq for wake: %d\n",
> -				ret);
> -	}
> -
> -	ret = rmi_driver_resume(rmi_i2c->xport.rmi_dev);
> +	ret = rmi_driver_resume(rmi_i2c->xport.rmi_dev, true);
>  	if (ret)
>  		dev_warn(dev, "Failed to resume device: %d\n", ret);
>  
> @@ -376,12 +316,10 @@ static int rmi_i2c_runtime_suspend(struct device *dev)
>  	struct rmi_i2c_xport *rmi_i2c = i2c_get_clientdata(client);
>  	int ret;
>  
> -	ret = rmi_driver_suspend(rmi_i2c->xport.rmi_dev);
> +	ret = rmi_driver_suspend(rmi_i2c->xport.rmi_dev, false);
>  	if (ret)
>  		dev_warn(dev, "Failed to resume device: %d\n", ret);
>  
> -	disable_irq(rmi_i2c->irq);
> -
>  	regulator_bulk_disable(ARRAY_SIZE(rmi_i2c->supplies),
>  			       rmi_i2c->supplies);
>  
> @@ -401,9 +339,7 @@ static int rmi_i2c_runtime_resume(struct device *dev)
>  
>  	msleep(rmi_i2c->startup_delay);
>  
> -	enable_irq(rmi_i2c->irq);
> -
> -	ret = rmi_driver_resume(rmi_i2c->xport.rmi_dev);
> +	ret = rmi_driver_resume(rmi_i2c->xport.rmi_dev, false);
>  	if (ret)
>  		dev_warn(dev, "Failed to resume device: %d\n", ret);
>  
> diff --git a/drivers/input/rmi4/rmi_spi.c b/drivers/input/rmi4/rmi_spi.c
> index 55bd1b3..f3e9e48 100644
> --- a/drivers/input/rmi4/rmi_spi.c
> +++ b/drivers/input/rmi4/rmi_spi.c
> @@ -12,7 +12,6 @@
>  #include <linux/rmi.h>
>  #include <linux/slab.h>
>  #include <linux/spi/spi.h>
> -#include <linux/irq.h>
>  #include <linux/of.h>
>  #include "rmi_driver.h"
>  
> @@ -44,8 +43,6 @@ struct rmi_spi_xport {
>  	struct mutex page_mutex;
>  	int page;
>  
> -	int irq;
> -
>  	u8 *rx_buf;
>  	u8 *tx_buf;
>  	int xfer_buf_size;
> @@ -326,41 +323,6 @@ static const struct rmi_transport_ops rmi_spi_ops = {
>  	.read_block	= rmi_spi_read_block,
>  };
>  
> -static irqreturn_t rmi_spi_irq(int irq, void *dev_id)
> -{
> -	struct rmi_spi_xport *rmi_spi = dev_id;
> -	struct rmi_device *rmi_dev = rmi_spi->xport.rmi_dev;
> -	int ret;
> -
> -	ret = rmi_process_interrupt_requests(rmi_dev);
> -	if (ret)
> -		rmi_dbg(RMI_DEBUG_XPORT, &rmi_dev->dev,
> -			"Failed to process interrupt request: %d\n", ret);
> -
> -	return IRQ_HANDLED;
> -}
> -
> -static int rmi_spi_init_irq(struct spi_device *spi)
> -{
> -	struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
> -	int irq_flags = irqd_get_trigger_type(irq_get_irq_data(rmi_spi->irq));
> -	int ret;
> -
> -	if (!irq_flags)
> -		irq_flags = IRQF_TRIGGER_LOW;
> -
> -	ret = devm_request_threaded_irq(&spi->dev, rmi_spi->irq, NULL,
> -			rmi_spi_irq, irq_flags | IRQF_ONESHOT,
> -			dev_name(&spi->dev), rmi_spi);
> -	if (ret < 0) {
> -		dev_warn(&spi->dev, "Failed to register interrupt %d\n",
> -			rmi_spi->irq);
> -		return ret;
> -	}
> -
> -	return 0;
> -}
> -
>  #ifdef CONFIG_OF
>  static int rmi_spi_of_probe(struct spi_device *spi,
>  			struct rmi_device_platform_data *pdata)
> @@ -433,8 +395,7 @@ static int rmi_spi_probe(struct spi_device *spi)
>  		return retval;
>  	}
>  
> -	if (spi->irq > 0)
> -		rmi_spi->irq = spi->irq;
> +	pdata->irq = spi->irq;
>  
>  	rmi_spi->spi = spi;
>  	mutex_init(&rmi_spi->page_mutex);
> @@ -465,10 +426,6 @@ static int rmi_spi_probe(struct spi_device *spi)
>  		return retval;
>  	}
>  
> -	retval = rmi_spi_init_irq(spi);
> -	if (retval < 0)
> -		return retval;
> -
>  	dev_info(&spi->dev, "registered RMI SPI driver\n");
>  	return 0;
>  }
> @@ -489,17 +446,10 @@ static int rmi_spi_suspend(struct device *dev)
>  	struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
>  	int ret;
>  
> -	ret = rmi_driver_suspend(rmi_spi->xport.rmi_dev);
> +	ret = rmi_driver_suspend(rmi_spi->xport.rmi_dev, true);
>  	if (ret)
>  		dev_warn(dev, "Failed to resume device: %d\n", ret);
>  
> -	disable_irq(rmi_spi->irq);
> -	if (device_may_wakeup(&spi->dev)) {
> -		ret = enable_irq_wake(rmi_spi->irq);
> -		if (!ret)
> -			dev_warn(dev, "Failed to enable irq for wake: %d\n",
> -				ret);
> -	}
>  	return ret;
>  }
>  
> @@ -509,15 +459,7 @@ static int rmi_spi_resume(struct device *dev)
>  	struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
>  	int ret;
>  
> -	enable_irq(rmi_spi->irq);
> -	if (device_may_wakeup(&spi->dev)) {
> -		ret = disable_irq_wake(rmi_spi->irq);
> -		if (!ret)
> -			dev_warn(dev, "Failed to disable irq for wake: %d\n",
> -				ret);
> -	}
> -
> -	ret = rmi_driver_resume(rmi_spi->xport.rmi_dev);
> +	ret = rmi_driver_resume(rmi_spi->xport.rmi_dev, true);
>  	if (ret)
>  		dev_warn(dev, "Failed to resume device: %d\n", ret);
>  
> @@ -532,12 +474,10 @@ static int rmi_spi_runtime_suspend(struct device *dev)
>  	struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
>  	int ret;
>  
> -	ret = rmi_driver_suspend(rmi_spi->xport.rmi_dev);
> +	ret = rmi_driver_suspend(rmi_spi->xport.rmi_dev, false);
>  	if (ret)
>  		dev_warn(dev, "Failed to resume device: %d\n", ret);
>  
> -	disable_irq(rmi_spi->irq);
> -
>  	return 0;
>  }
>  
> @@ -547,9 +487,7 @@ static int rmi_spi_runtime_resume(struct device *dev)
>  	struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
>  	int ret;
>  
> -	enable_irq(rmi_spi->irq);
> -
> -	ret = rmi_driver_resume(rmi_spi->xport.rmi_dev);
> +	ret = rmi_driver_resume(rmi_spi->xport.rmi_dev, false);
>  	if (ret)
>  		dev_warn(dev, "Failed to resume device: %d\n", ret);
>  
> diff --git a/include/linux/rmi.h b/include/linux/rmi.h
> index e0aca14..5944e6c 100644
> --- a/include/linux/rmi.h
> +++ b/include/linux/rmi.h
> @@ -204,9 +204,11 @@ struct rmi_device_platform_data_spi {
>   * @reset_delay_ms - after issuing a reset command to the touch sensor, the
>   * driver waits a few milliseconds to give the firmware a chance to
>   * to re-initialize.  You can override the default wait period here.
> + * @irq: irq associated with the attn gpio line, or negative
>   */
>  struct rmi_device_platform_data {
>  	int reset_delay_ms;
> +	int irq;
>  
>  	struct rmi_device_platform_data_spi spi_data;
>  
> @@ -352,8 +354,7 @@ struct rmi_driver_data {
>  
>  int rmi_register_transport_device(struct rmi_transport_dev *xport);
>  void rmi_unregister_transport_device(struct rmi_transport_dev *xport);
> -int rmi_process_interrupt_requests(struct rmi_device *rmi_dev);
>  
> -int rmi_driver_suspend(struct rmi_device *rmi_dev);
> -int rmi_driver_resume(struct rmi_device *rmi_dev);
> +int rmi_driver_suspend(struct rmi_device *rmi_dev, bool enable_wake);
> +int rmi_driver_resume(struct rmi_device *rmi_dev, bool clear_wake);
>  #endif
> -- 
> 2.7.4
> 

-- 
Dmitry

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

* Re: [PATCH v3 04/18] Input: synaptics-rmi4 - Add parameters for dribble packets and palm detect gesture
  2016-10-13 15:50 ` [PATCH v3 04/18] Input: synaptics-rmi4 - Add parameters for dribble packets and palm detect gesture Benjamin Tissoires
@ 2016-11-09  0:51   ` Dmitry Torokhov
  0 siblings, 0 replies; 28+ messages in thread
From: Dmitry Torokhov @ 2016-11-09  0:51 UTC (permalink / raw)
  To: Benjamin Tissoires
  Cc: Andrew Duggan, Lyude Paul, Christopher Heiny, Nick Dyer,
	Bjorn Andersson, Dennis Wassenberg, linux-kernel, linux-input

On Thu, Oct 13, 2016 at 05:50:58PM +0200, Benjamin Tissoires wrote:
> From: Andrew Duggan <aduggan@synaptics.com>
> 
> The rmi_f11 driver currently disables dribble packets and the palm detect
> gesture for all devices. This patch creates a parameter in the 2d sensor
> platform data for controlling this functionality on a per device basis.
> 
> For more information on dribble packets:
> Commit 05ba999fcabb ("HID: rmi: disable dribble packets on Synaptics
> touchpads")
> 
> For more information on the palm detect gesture:
> Commit f097deef59a6 ("HID: rmi: disable palm detect gesture when present")
> 
> Signed-off-by: Andrew Duggan <aduggan@synaptics.com>
> Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
> Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>

Applied, thank you.

> 
> ---
> 
> new in v3
> ---
>  drivers/input/rmi4/rmi_2d_sensor.h |  2 ++
>  drivers/input/rmi4/rmi_f01.c       |  6 +++---
>  drivers/input/rmi4/rmi_f11.c       | 32 ++++++++++++++++++++++++++++----
>  include/linux/rmi.h                | 21 +++++++++++++--------
>  4 files changed, 46 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/input/rmi4/rmi_2d_sensor.h b/drivers/input/rmi4/rmi_2d_sensor.h
> index 77fcdfe..c871bef 100644
> --- a/drivers/input/rmi4/rmi_2d_sensor.h
> +++ b/drivers/input/rmi4/rmi_2d_sensor.h
> @@ -67,6 +67,8 @@ struct rmi_2d_sensor {
>  	u8 report_rel;
>  	u8 x_mm;
>  	u8 y_mm;
> +	enum rmi_reg_state dribble;
> +	enum rmi_reg_state palm_detect;
>  };
>  
>  int rmi_2d_sensor_of_probe(struct device *dev,
> diff --git a/drivers/input/rmi4/rmi_f01.c b/drivers/input/rmi4/rmi_f01.c
> index fac81fc..2cfa9f6 100644
> --- a/drivers/input/rmi4/rmi_f01.c
> +++ b/drivers/input/rmi4/rmi_f01.c
> @@ -327,12 +327,12 @@ static int rmi_f01_probe(struct rmi_function *fn)
>  	}
>  
>  	switch (pdata->power_management.nosleep) {
> -	case RMI_F01_NOSLEEP_DEFAULT:
> +	case RMI_REG_STATE_DEFAULT:
>  		break;
> -	case RMI_F01_NOSLEEP_OFF:
> +	case RMI_REG_STATE_OFF:
>  		f01->device_control.ctrl0 &= ~RMI_F01_CTRL0_NOSLEEP_BIT;
>  		break;
> -	case RMI_F01_NOSLEEP_ON:
> +	case RMI_REG_STATE_ON:
>  		f01->device_control.ctrl0 |= RMI_F01_CTRL0_NOSLEEP_BIT;
>  		break;
>  	}
> diff --git a/drivers/input/rmi4/rmi_f11.c b/drivers/input/rmi4/rmi_f11.c
> index 3218742..cce82a1 100644
> --- a/drivers/input/rmi4/rmi_f11.c
> +++ b/drivers/input/rmi4/rmi_f11.c
> @@ -1142,6 +1142,8 @@ static int rmi_f11_initialize(struct rmi_function *fn)
>  	sensor->topbuttonpad = f11->sensor_pdata.topbuttonpad;
>  	sensor->kernel_tracking = f11->sensor_pdata.kernel_tracking;
>  	sensor->dmax = f11->sensor_pdata.dmax;
> +	sensor->dribble = f11->sensor_pdata.dribble;
> +	sensor->palm_detect = f11->sensor_pdata.palm_detect;
>  
>  	if (f11->sens_query.has_physical_props) {
>  		sensor->x_mm = f11->sens_query.x_sensor_size_mm;
> @@ -1209,11 +1211,33 @@ static int rmi_f11_initialize(struct rmi_function *fn)
>  		ctrl->ctrl0_11[RMI_F11_DELTA_Y_THRESHOLD] =
>  			sensor->axis_align.delta_y_threshold;
>  
> -	if (f11->sens_query.has_dribble)
> -		ctrl->ctrl0_11[0] = ctrl->ctrl0_11[0] & ~BIT(6);
> +	if (f11->sens_query.has_dribble) {
> +		switch (sensor->dribble) {
> +		case RMI_REG_STATE_OFF:
> +			ctrl->ctrl0_11[0] = ctrl->ctrl0_11[0] & ~BIT(6);

Changed to

			ctrl->ctrl0_11[0] &= ~BIT(6);

> +			break;
> +		case RMI_REG_STATE_ON:
> +			ctrl->ctrl0_11[0] = ctrl->ctrl0_11[0] | BIT(6);
> +			break;
> +		case RMI_REG_STATE_DEFAULT:
> +		default:
> +			break;
> +		}
> +	}
>  
> -	if (f11->sens_query.has_palm_det)
> -		ctrl->ctrl0_11[11] = ctrl->ctrl0_11[11] & ~BIT(0);
> +	if (f11->sens_query.has_palm_det) {
> +		switch (sensor->palm_detect) {
> +		case RMI_REG_STATE_OFF:
> +			ctrl->ctrl0_11[11] = ctrl->ctrl0_11[11] & ~BIT(0);
> +			break;
> +		case RMI_REG_STATE_ON:
> +			ctrl->ctrl0_11[11] = ctrl->ctrl0_11[11] & BIT(0);
> +			break;
> +		case RMI_REG_STATE_DEFAULT:
> +		default:
> +			break;
> +		}
> +	}
>  
>  	rc = f11_write_control_regs(fn, &f11->sens_query,
>  			   &f11->dev_controls, fn->fd.query_base_addr);
> diff --git a/include/linux/rmi.h b/include/linux/rmi.h
> index 5944e6c..ac904bb 100644
> --- a/include/linux/rmi.h
> +++ b/include/linux/rmi.h
> @@ -99,6 +99,8 @@ struct rmi_2d_sensor_platform_data {
>  	bool topbuttonpad;
>  	bool kernel_tracking;
>  	int dmax;
> +	int dribble;
> +	int palm_detect;
>  };
>  
>  /**
> @@ -116,14 +118,17 @@ struct rmi_f30_data {
>  	bool disable;
>  };
>  
> -/**
> - * struct rmi_f01_power - override default power management settings.
> - *
> +
> +/*
> + * Set the state of a register
> + *	DEFAULT - use the default value set by the firmware config
> + *	OFF - explicitly disable the register
> + *	ON - explicitly enable the register
>   */
> -enum rmi_f01_nosleep {
> -	RMI_F01_NOSLEEP_DEFAULT = 0,
> -	RMI_F01_NOSLEEP_OFF = 1,
> -	RMI_F01_NOSLEEP_ON = 2
> +enum rmi_reg_state {
> +	RMI_REG_STATE_DEFAULT = 0,
> +	RMI_REG_STATE_OFF = 1,
> +	RMI_REG_STATE_ON = 2
>  };
>  
>  /**
> @@ -143,7 +148,7 @@ enum rmi_f01_nosleep {
>   * when the touch sensor is in doze mode, in units of 10ms.
>   */
>  struct rmi_f01_power_management {
> -	enum rmi_f01_nosleep nosleep;
> +	enum rmi_reg_state nosleep;
>  	u8 wakeup_threshold;
>  	u8 doze_holdoff;
>  	u8 doze_interval;
> -- 
> 2.7.4
> 

-- 
Dmitry

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

* Re: [PATCH v3 05/18] Input: synaptics-rmi4 - Add support for controlling dribble packets in F12
  2016-10-13 15:50 ` [PATCH v3 05/18] Input: synaptics-rmi4 - Add support for controlling dribble packets in F12 Benjamin Tissoires
@ 2016-11-09  1:02   ` Dmitry Torokhov
  0 siblings, 0 replies; 28+ messages in thread
From: Dmitry Torokhov @ 2016-11-09  1:02 UTC (permalink / raw)
  To: Benjamin Tissoires
  Cc: Andrew Duggan, Lyude Paul, Christopher Heiny, Nick Dyer,
	Bjorn Andersson, Dennis Wassenberg, linux-kernel, linux-input

On Thu, Oct 13, 2016 at 05:50:59PM +0200, Benjamin Tissoires wrote:
> From: Andrew Duggan <aduggan@synaptics.com>
> 
> Implements reading and setting the dribble bit in F12's control registers.
> 
> Signed-off-by: Andrew Duggan <aduggan@synaptics.com>
> Acked-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
> Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>

Applied, thank you.

> 
> ---
> 
> new in v3
> ---
>  drivers/input/rmi4/rmi_f12.c | 73 +++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 72 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/input/rmi4/rmi_f12.c b/drivers/input/rmi4/rmi_f12.c
> index 767ac79..f79a785 100644
> --- a/drivers/input/rmi4/rmi_f12.c
> +++ b/drivers/input/rmi4/rmi_f12.c
> @@ -31,6 +31,7 @@ enum rmi_f12_object_type {
>  struct f12_data {
>  	struct rmi_2d_sensor sensor;
>  	struct rmi_2d_sensor_platform_data sensor_pdata;
> +	bool has_dribble;
>  
>  	u16 data_addr;
>  
> @@ -239,12 +240,79 @@ static int rmi_f12_attention(struct rmi_function *fn,
>  	return 0;
>  }
>  
> +static int rmi_f12_write_control_regs(struct rmi_function *fn)
> +{
> +	int ret;
> +	const struct rmi_register_desc_item *item;
> +	struct rmi_device *rmi_dev = fn->rmi_dev;
> +	struct f12_data *f12 = dev_get_drvdata(&fn->dev);
> +	int control_size;
> +	char buf[3];
> +	u16 control_offset = 0;
> +	u8 subpacket_offset = 0;
> +
> +	if (f12->has_dribble
> +	    && (f12->sensor.dribble != RMI_REG_STATE_DEFAULT)) {
> +		item = rmi_get_register_desc_item(&f12->control_reg_desc, 20);
> +		if (item) {
> +			control_offset = rmi_register_desc_calc_reg_offset(
> +						&f12->control_reg_desc, 20);
> +
> +			/*
> +			 * The byte containing the EnableDribble bit will be
> +			 * in either byte 0 or byte 2 of control 20. Depending
> +			 * on the existence of subpacket 0. If control 20 is
> +			 * larger then 3 bytes, just read the first 3.
> +			 */
> +			if (item->reg_size >= 3)
> +				control_size = 3;
> +			else
> +				control_size = item->reg_size;

Changed to
			control_size = min(item->reg_size, 3UL);

> +
> +			ret = rmi_read_block(rmi_dev, fn->fd.control_base_addr
> +					+ control_offset, buf, control_size);
> +			if (ret)
> +				return ret;
> +
> +			if (rmi_register_desc_has_subpacket(item, 0))
> +				subpacket_offset += 1;
> +
> +			switch (f12->sensor.dribble) {
> +			case RMI_REG_STATE_OFF:
> +				buf[subpacket_offset] &= ~BIT(2);
> +				break;
> +			case RMI_REG_STATE_ON:
> +				buf[subpacket_offset] |= BIT(2);
> +				break;
> +			case RMI_REG_STATE_DEFAULT:
> +			default:
> +				break;
> +			}
> +
> +			ret = rmi_write_block(rmi_dev,
> +				fn->fd.control_base_addr + control_offset,
> +				buf, control_size);
> +			if (ret)
> +				return ret;
> +		}
> +	}
> +
> +	return 0;
> +
> +}
> +
>  static int rmi_f12_config(struct rmi_function *fn)
>  {
>  	struct rmi_driver *drv = fn->rmi_dev->driver;
> +	int ret;
>  
>  	drv->set_irq_bits(fn->rmi_dev, fn->irq_mask);
>  
> +	ret = rmi_f12_write_control_regs(fn);
> +	if (ret)
> +		dev_warn(&fn->dev,
> +			"Failed to write F12 control registers: %d\n", ret);
> +
>  	return 0;
>  }
>  
> @@ -271,7 +339,7 @@ static int rmi_f12_probe(struct rmi_function *fn)
>  	}
>  	++query_addr;
>  
> -	if (!(buf & 0x1)) {
> +	if (!(buf & BIT(0))) {
>  		dev_err(&fn->dev,
>  			"Behavior of F12 without register descriptors is undefined.\n");
>  		return -ENODEV;
> @@ -281,6 +349,8 @@ static int rmi_f12_probe(struct rmi_function *fn)
>  	if (!f12)
>  		return -ENOMEM;
>  
> +	f12->has_dribble = !!(buf & BIT(3));
> +
>  	if (fn->dev.of_node) {
>  		ret = rmi_2d_sensor_of_probe(&fn->dev, &f12->sensor_pdata);
>  		if (ret)
> @@ -329,6 +399,7 @@ static int rmi_f12_probe(struct rmi_function *fn)
>  
>  	sensor->x_mm = f12->sensor_pdata.x_mm;
>  	sensor->y_mm = f12->sensor_pdata.y_mm;
> +	sensor->dribble = f12->sensor_pdata.dribble;
>  
>  	if (sensor->sensor_type == rmi_sensor_default)
>  		sensor->sensor_type =
> -- 
> 2.7.4
> 

-- 
Dmitry

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

* Re: [PATCH v3 06/18] Input: synaptics-rmi4 - Set the ABS_MT_TOOL_TYPE bit to report tool type
  2016-10-13 15:51 ` [PATCH v3 06/18] Input: synaptics-rmi4 - Set the ABS_MT_TOOL_TYPE bit to report tool type Benjamin Tissoires
@ 2016-11-09  1:03   ` Dmitry Torokhov
  0 siblings, 0 replies; 28+ messages in thread
From: Dmitry Torokhov @ 2016-11-09  1:03 UTC (permalink / raw)
  To: Benjamin Tissoires
  Cc: Andrew Duggan, Lyude Paul, Christopher Heiny, Nick Dyer,
	Bjorn Andersson, Dennis Wassenberg, linux-kernel, linux-input

On Thu, Oct 13, 2016 at 05:51:00PM +0200, Benjamin Tissoires wrote:
> From: Andrew Duggan <aduggan@synaptics.com>
> 
> The rmi4 2D sensor functions report the tool type via
> input_mt_report_slot_state(), but the abs parameter bit has not been
> set so the tool type is not reported to userspace. This patch set
> the ABS_MT_TOOL_TYPE bit.
> 
> Signed-off-by: Andrew Duggan <aduggan@synaptics.com>
> Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>

Applied, thank you.

> 
> ---
> 
> new in v3
> ---
>  drivers/input/rmi4/rmi_2d_sensor.c | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/drivers/input/rmi4/rmi_2d_sensor.c b/drivers/input/rmi4/rmi_2d_sensor.c
> index e97bd7f..0747890 100644
> --- a/drivers/input/rmi4/rmi_2d_sensor.c
> +++ b/drivers/input/rmi4/rmi_2d_sensor.c
> @@ -181,6 +181,8 @@ static void rmi_2d_sensor_set_input_params(struct rmi_2d_sensor *sensor)
>  		input_set_abs_params(input, ABS_MT_TOUCH_MAJOR,	0, 0x0f, 0, 0);
>  		input_set_abs_params(input, ABS_MT_TOUCH_MINOR,	0, 0x0f, 0, 0);
>  		input_set_abs_params(input, ABS_MT_ORIENTATION,	0, 1, 0, 0);
> +		input_set_abs_params(input, ABS_MT_TOOL_TYPE, 0, MT_TOOL_MAX,
> +					0, 0);
>  
>  		if (sensor->sensor_type == rmi_sensor_touchpad)
>  			input_flags = INPUT_MT_POINTER;
> -- 
> 2.7.4
> 

-- 
Dmitry

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

* Re: [PATCH v3 07/18] Input: synaptics-rmi4 - add SMBus support
  2016-10-13 15:51 ` [PATCH v3 07/18] Input: synaptics-rmi4 - add SMBus support Benjamin Tissoires
@ 2016-11-09  1:08   ` Dmitry Torokhov
  0 siblings, 0 replies; 28+ messages in thread
From: Dmitry Torokhov @ 2016-11-09  1:08 UTC (permalink / raw)
  To: Benjamin Tissoires
  Cc: Andrew Duggan, Lyude Paul, Christopher Heiny, Nick Dyer,
	Bjorn Andersson, Dennis Wassenberg, linux-kernel, linux-input

On Thu, Oct 13, 2016 at 05:51:01PM +0200, Benjamin Tissoires wrote:
> Code obtained from https://raw.githubusercontent.com/mightybigcar/synaptics-rmi4/jf/drivers/input/rmi4/rmi_smbus.c
> and updated to match upstream. And fixed to make it work.
> 
> Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
> Signed-off-by: Andrew Duggan <aduggan@synaptics.com>

Applied, thank you.

> 
> ---
> 
> changes in v3:
> - use of irq for Host Notify, not alert
> - forward the irq to rmi_core and let it handling it
> 
> no changes in v2
> 
> Changes in v1 of this series:
> - rely on PM functions for resume handling
> 
> Changes from the Host Notify series:
> new in v5
> 
> no changes in v6
> 
> changes in v7:
> - fixed typos as per Andrew's requests
> - changed module author from Allie to Andrew as per Andrew's request
> - add suspend/resume callbacks to match upstream rmi4 behavior
> 
> no changes in v8
> ---
>  drivers/input/rmi4/Kconfig     |  12 ++
>  drivers/input/rmi4/Makefile    |   1 +
>  drivers/input/rmi4/rmi_bus.h   |  12 ++
>  drivers/input/rmi4/rmi_smbus.c | 448 +++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 473 insertions(+)
>  create mode 100644 drivers/input/rmi4/rmi_smbus.c
> 
> diff --git a/drivers/input/rmi4/Kconfig b/drivers/input/rmi4/Kconfig
> index 4c8a558..8cbd362 100644
> --- a/drivers/input/rmi4/Kconfig
> +++ b/drivers/input/rmi4/Kconfig
> @@ -27,6 +27,18 @@ config RMI4_SPI
>  
>  	  If unsure, say N.
>  
> +config RMI4_SMB
> +	tristate "RMI4 SMB Support"
> +	depends on RMI4_CORE && I2C
> +	help
> +	  Say Y here if you want to support RMI4 devices connected to an SMB
> +	  bus.
> +
> +	  If unsure, say N.
> +
> +	  To compile this driver as a module, choose M here: the module will be
> +	  called rmi_smbus.
> +
>  config RMI4_2D_SENSOR
>  	bool
>  	depends on RMI4_CORE
> diff --git a/drivers/input/rmi4/Makefile b/drivers/input/rmi4/Makefile
> index 0bafc85..a6e2752 100644
> --- a/drivers/input/rmi4/Makefile
> +++ b/drivers/input/rmi4/Makefile
> @@ -12,3 +12,4 @@ rmi_core-$(CONFIG_RMI4_F54) += rmi_f54.o
>  # Transports
>  obj-$(CONFIG_RMI4_I2C) += rmi_i2c.o
>  obj-$(CONFIG_RMI4_SPI) += rmi_spi.o
> +obj-$(CONFIG_RMI4_SMB) += rmi_smbus.o
> diff --git a/drivers/input/rmi4/rmi_bus.h b/drivers/input/rmi4/rmi_bus.h
> index 8995798..b7625a9 100644
> --- a/drivers/input/rmi4/rmi_bus.h
> +++ b/drivers/input/rmi4/rmi_bus.h
> @@ -105,6 +105,18 @@ rmi_get_platform_data(struct rmi_device *d)
>  bool rmi_is_physical_device(struct device *dev);
>  
>  /**
> + * rmi_reset - reset a RMI4 device
> + * @d: Pointer to an RMI device
> + *
> + * Calls for a reset of each function implemented by a specific device.
> + * Returns 0 on success or a negative error code.
> + */
> +static inline int rmi_reset(struct rmi_device *d)
> +{
> +	return d->driver->reset_handler(d);
> +}
> +
> +/**
>   * rmi_read - read a single byte
>   * @d: Pointer to an RMI device
>   * @addr: The address to read from
> diff --git a/drivers/input/rmi4/rmi_smbus.c b/drivers/input/rmi4/rmi_smbus.c
> new file mode 100644
> index 0000000..96ad325
> --- /dev/null
> +++ b/drivers/input/rmi4/rmi_smbus.c
> @@ -0,0 +1,448 @@
> +/*
> + * Copyright (c) 2015 - 2016 Red Hat, Inc
> + * Copyright (c) 2011, 2012 Synaptics Incorporated
> + * Copyright (c) 2011 Unixphere
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License version 2 as published by
> + * the Free Software Foundation.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/delay.h>
> +#include <linux/i2c.h>
> +#include <linux/interrupt.h>
> +#include <linux/kconfig.h>
> +#include <linux/lockdep.h>
> +#include <linux/module.h>
> +#include <linux/pm.h>
> +#include <linux/rmi.h>
> +#include <linux/slab.h>
> +#include "rmi_driver.h"
> +
> +#define SMB_PROTOCOL_VERSION_ADDRESS	0xfd
> +#define SMB_MAX_COUNT			32
> +#define RMI_SMB2_MAP_SIZE		8 /* 8 entry of 4 bytes each */
> +#define RMI_SMB2_MAP_FLAGS_WE		0x01
> +
> +struct mapping_table_entry {
> +	__le16 rmiaddr;
> +	u8 readcount;
> +	u8 flags;
> +};
> +
> +struct rmi_smb_xport {
> +	struct rmi_transport_dev xport;
> +	struct i2c_client *client;
> +
> +	struct mutex page_mutex;
> +	int page;
> +	u8 table_index;
> +	struct mutex mappingtable_mutex;
> +	struct mapping_table_entry mapping_table[RMI_SMB2_MAP_SIZE];
> +};
> +
> +static int rmi_smb_get_version(struct rmi_smb_xport *rmi_smb)
> +{
> +	struct i2c_client *client = rmi_smb->client;
> +	int retval;
> +
> +	/* Check if for SMBus new version device by reading version byte. */
> +	retval = i2c_smbus_read_byte_data(client, SMB_PROTOCOL_VERSION_ADDRESS);
> +	if (retval < 0) {
> +		dev_err(&client->dev, "failed to get SMBus version number!\n");
> +		return retval;
> +	}
> +	return retval + 1;
> +}
> +
> +/* SMB block write - wrapper over ic2_smb_write_block */
> +static int smb_block_write(struct rmi_transport_dev *xport,
> +			      u8 commandcode, const void *buf, size_t len)
> +{
> +	struct rmi_smb_xport *rmi_smb =
> +		container_of(xport, struct rmi_smb_xport, xport);
> +	struct i2c_client *client = rmi_smb->client;
> +	int retval;
> +
> +	retval = i2c_smbus_write_block_data(client, commandcode, len, buf);
> +
> +	rmi_dbg(RMI_DEBUG_XPORT, &client->dev,
> +		"wrote %zd bytes at %#04x: %d (%*ph)\n",
> +		len, commandcode, retval, (int)len, buf);
> +
> +	return retval;
> +}
> +
> +/*
> + * The function to get command code for smbus operations and keeps
> + * records to the driver mapping table
> + */
> +static int rmi_smb_get_command_code(struct rmi_transport_dev *xport,
> +		u16 rmiaddr, int bytecount, bool isread, u8 *commandcode)
> +{
> +	struct rmi_smb_xport *rmi_smb =
> +		container_of(xport, struct rmi_smb_xport, xport);
> +	int i;
> +	int retval;
> +	struct mapping_table_entry mapping_data[1];
> +
> +	mutex_lock(&rmi_smb->mappingtable_mutex);
> +	for (i = 0; i < RMI_SMB2_MAP_SIZE; i++) {
> +		if (rmi_smb->mapping_table[i].rmiaddr == rmiaddr) {
> +			if (isread) {
> +				if (rmi_smb->mapping_table[i].readcount
> +							== bytecount) {
> +					*commandcode = i;
> +					retval = 0;
> +					goto exit;
> +				}
> +			} else {
> +				if (rmi_smb->mapping_table[i].flags &
> +							RMI_SMB2_MAP_FLAGS_WE) {
> +					*commandcode = i;
> +					retval = 0;
> +					goto exit;
> +				}
> +			}
> +		}
> +	}
> +	i = rmi_smb->table_index;
> +	rmi_smb->table_index = (i + 1) % RMI_SMB2_MAP_SIZE;
> +
> +	/* constructs mapping table data entry. 4 bytes each entry */
> +	memset(mapping_data, 0, sizeof(mapping_data));
> +
> +	mapping_data[0].rmiaddr = cpu_to_le16(rmiaddr);
> +	mapping_data[0].readcount = bytecount;
> +	mapping_data[0].flags = !isread ? RMI_SMB2_MAP_FLAGS_WE : 0;
> +
> +	retval = smb_block_write(xport, i + 0x80, mapping_data,
> +				 sizeof(mapping_data));
> +
> +	if (retval < 0) {
> +		/*
> +		 * if not written to device mapping table
> +		 * clear the driver mapping table records
> +		 */
> +		rmi_smb->mapping_table[i].rmiaddr = 0x0000;
> +		rmi_smb->mapping_table[i].readcount = 0;
> +		rmi_smb->mapping_table[i].flags = 0;
> +		goto exit;
> +	}
> +	/* save to the driver level mapping table */
> +	rmi_smb->mapping_table[i].rmiaddr = rmiaddr;
> +	rmi_smb->mapping_table[i].readcount = bytecount;
> +	rmi_smb->mapping_table[i].flags = !isread ? RMI_SMB2_MAP_FLAGS_WE : 0;
> +	*commandcode = i;
> +
> +exit:
> +	mutex_unlock(&rmi_smb->mappingtable_mutex);
> +
> +	return retval;
> +}
> +
> +static int rmi_smb_write_block(struct rmi_transport_dev *xport, u16 rmiaddr,
> +				const void *databuff, size_t len)
> +{
> +	int retval = 0;
> +	u8 commandcode;
> +	struct rmi_smb_xport *rmi_smb =
> +		container_of(xport, struct rmi_smb_xport, xport);
> +	int cur_len = (int)len;
> +
> +	mutex_lock(&rmi_smb->page_mutex);
> +
> +	while (cur_len > 0) {
> +		/*
> +		 * break into 32 bytes chunks to write get command code
> +		 */
> +		int block_len = min_t(int, len, SMB_MAX_COUNT);
> +
> +		retval = rmi_smb_get_command_code(xport, rmiaddr, block_len,
> +						  false, &commandcode);
> +		if (retval < 0)
> +			goto exit;
> +
> +		retval = smb_block_write(xport, commandcode,
> +					 databuff, block_len);
> +		if (retval < 0)
> +			goto exit;
> +
> +		/* prepare to write next block of bytes */
> +		cur_len -= SMB_MAX_COUNT;
> +		databuff += SMB_MAX_COUNT;
> +		rmiaddr += SMB_MAX_COUNT;
> +	}
> +exit:
> +	mutex_unlock(&rmi_smb->page_mutex);
> +	return retval;
> +}
> +
> +/* SMB block read - wrapper over ic2_smb_read_block */
> +static int smb_block_read(struct rmi_transport_dev *xport,
> +			     u8 commandcode, void *buf, size_t len)
> +{
> +	struct rmi_smb_xport *rmi_smb =
> +		container_of(xport, struct rmi_smb_xport, xport);
> +	struct i2c_client *client = rmi_smb->client;
> +	int retval;
> +
> +	retval = i2c_smbus_read_block_data(client, commandcode, buf);
> +	if (retval < 0)
> +		return retval;
> +
> +	return retval;
> +}
> +
> +static int rmi_smb_read_block(struct rmi_transport_dev *xport, u16 rmiaddr,
> +			      void *databuff, size_t len)
> +{
> +	struct rmi_smb_xport *rmi_smb =
> +		container_of(xport, struct rmi_smb_xport, xport);
> +	int retval;
> +	u8 commandcode;
> +	int cur_len = (int)len;
> +
> +	mutex_lock(&rmi_smb->page_mutex);
> +	memset(databuff, 0, len);
> +
> +	while (cur_len > 0) {
> +		/* break into 32 bytes chunks to write get command code */
> +		int block_len =  min_t(int, cur_len, SMB_MAX_COUNT);
> +
> +		retval = rmi_smb_get_command_code(xport, rmiaddr, block_len,
> +						  true, &commandcode);
> +		if (retval < 0)
> +			goto exit;
> +
> +		retval = smb_block_read(xport, commandcode,
> +					databuff, block_len);
> +		if (retval < 0)
> +			goto exit;
> +
> +		/* prepare to read next block of bytes */
> +		cur_len -= SMB_MAX_COUNT;
> +		databuff += SMB_MAX_COUNT;
> +		rmiaddr += SMB_MAX_COUNT;
> +	}
> +
> +	retval = 0;
> +
> +exit:
> +	mutex_unlock(&rmi_smb->page_mutex);
> +	return retval;
> +}
> +
> +static void rmi_smb_clear_state(struct rmi_smb_xport *rmi_smb)
> +{
> +	/* the mapping table has been flushed, discard the current one */
> +	mutex_lock(&rmi_smb->mappingtable_mutex);
> +	memset(rmi_smb->mapping_table, 0, sizeof(rmi_smb->mapping_table));
> +	mutex_unlock(&rmi_smb->mappingtable_mutex);
> +}
> +
> +static int rmi_smb_enable_smbus_mode(struct rmi_smb_xport *rmi_smb)
> +{
> +	int retval;
> +
> +	/* we need to get the smbus version to activate the touchpad */
> +	retval = rmi_smb_get_version(rmi_smb);
> +	if (retval < 0)
> +		return retval;
> +
> +	return 0;
> +}
> +
> +static int rmi_smb_reset(struct rmi_transport_dev *xport, u16 reset_addr)
> +{
> +	struct rmi_smb_xport *rmi_smb =
> +		container_of(xport, struct rmi_smb_xport, xport);
> +
> +	rmi_smb_clear_state(rmi_smb);
> +
> +	/*
> +	 * we do not call the actual reset command, it has to be handled in
> +	 * PS/2 or there will be races between PS/2 and SMBus.
> +	 * PS/2 should ensure that a psmouse_reset is called before
> +	 * intializing the device and after it has been removed to be in a known
> +	 * state.
> +	 */
> +	return rmi_smb_enable_smbus_mode(rmi_smb);
> +}
> +
> +static const struct rmi_transport_ops rmi_smb_ops = {
> +	.write_block	= rmi_smb_write_block,
> +	.read_block	= rmi_smb_read_block,
> +	.reset		= rmi_smb_reset,
> +};
> +
> +static int rmi_smb_probe(struct i2c_client *client,
> +			 const struct i2c_device_id *id)
> +{
> +	struct rmi_device_platform_data *pdata = dev_get_platdata(&client->dev);
> +	struct rmi_smb_xport *rmi_smb;
> +	int retval;
> +	int smbus_version;
> +
> +	if (!i2c_check_functionality(client->adapter,
> +				     I2C_FUNC_SMBUS_READ_BLOCK_DATA |
> +				     I2C_FUNC_SMBUS_HOST_NOTIFY)) {
> +		dev_err(&client->dev,
> +			"adapter does not support required functionality.\n");
> +		return -ENODEV;
> +	}
> +
> +	if (client->irq <= 0) {
> +		dev_err(&client->dev, "no IRQ provided, giving up.\n");
> +		return client->irq ? client->irq : -ENODEV;
> +	}
> +
> +	rmi_smb = devm_kzalloc(&client->dev, sizeof(struct rmi_smb_xport),
> +				GFP_KERNEL);
> +	if (!rmi_smb)
> +		return -ENOMEM;
> +
> +	if (!pdata) {
> +		dev_err(&client->dev, "no platform data, aborting\n");
> +		return -ENOMEM;
> +	}
> +
> +	rmi_dbg(RMI_DEBUG_XPORT, &client->dev, "Probing %s.\n",
> +		dev_name(&client->dev));
> +
> +	rmi_smb->client = client;
> +	mutex_init(&rmi_smb->page_mutex);
> +	mutex_init(&rmi_smb->mappingtable_mutex);
> +
> +	rmi_smb->xport.dev = &client->dev;
> +	rmi_smb->xport.pdata = *pdata;
> +	rmi_smb->xport.pdata.irq = client->irq;
> +	rmi_smb->xport.proto_name = "smb2";
> +	rmi_smb->xport.ops = &rmi_smb_ops;
> +
> +	retval = rmi_smb_get_version(rmi_smb);
> +	if (retval < 0)
> +		return retval;
> +
> +	smbus_version = retval;
> +	rmi_dbg(RMI_DEBUG_XPORT, &client->dev, "Smbus version is %d",
> +		smbus_version);
> +
> +	if (smbus_version != 2) {
> +		dev_err(&client->dev, "Unrecognized SMB version %d.\n",
> +				smbus_version);
> +		return -ENODEV;
> +	}
> +
> +	i2c_set_clientdata(client, rmi_smb);
> +
> +	retval = rmi_register_transport_device(&rmi_smb->xport);
> +	if (retval) {
> +		dev_err(&client->dev, "Failed to register transport driver at 0x%.2X.\n",
> +			client->addr);
> +		i2c_set_clientdata(client, NULL);
> +		return retval;
> +	}
> +
> +	dev_info(&client->dev, "registered rmi smb driver at %#04x.\n",
> +			client->addr);
> +	return 0;
> +
> +}
> +
> +static int rmi_smb_remove(struct i2c_client *client)
> +{
> +	struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
> +
> +	rmi_unregister_transport_device(&rmi_smb->xport);
> +
> +	return 0;
> +}
> +
> +static int __maybe_unused rmi_smb_suspend(struct device *dev)
> +{
> +	struct i2c_client *client = to_i2c_client(dev);
> +	struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
> +	int ret;
> +
> +	ret = rmi_driver_suspend(rmi_smb->xport.rmi_dev, true);
> +	if (ret)
> +		dev_warn(dev, "Failed to suspend device: %d\n", ret);
> +
> +	return ret;
> +}
> +
> +static int __maybe_unused rmi_smb_runtime_suspend(struct device *dev)
> +{
> +	struct i2c_client *client = to_i2c_client(dev);
> +	struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
> +	int ret;
> +
> +	ret = rmi_driver_suspend(rmi_smb->xport.rmi_dev, false);
> +	if (ret)
> +		dev_warn(dev, "Failed to suspend device: %d\n", ret);
> +
> +	return ret;
> +}
> +
> +static int __maybe_unused rmi_smb_resume(struct device *dev)
> +{
> +	struct i2c_client *client = container_of(dev, struct i2c_client, dev);
> +	struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
> +	struct rmi_device *rmi_dev = rmi_smb->xport.rmi_dev;
> +	int ret;
> +
> +	rmi_smb_reset(&rmi_smb->xport, 0);
> +
> +	rmi_reset(rmi_dev);
> +
> +	ret = rmi_driver_resume(rmi_smb->xport.rmi_dev, true);
> +	if (ret)
> +		dev_warn(dev, "Failed to resume device: %d\n", ret);
> +
> +	return 0;
> +}
> +
> +static int __maybe_unused rmi_smb_runtime_resume(struct device *dev)
> +{
> +	struct i2c_client *client = to_i2c_client(dev);
> +	struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
> +	int ret;
> +
> +	ret = rmi_driver_resume(rmi_smb->xport.rmi_dev, false);
> +	if (ret)
> +		dev_warn(dev, "Failed to resume device: %d\n", ret);
> +
> +	return 0;
> +}
> +
> +static const struct dev_pm_ops rmi_smb_pm = {
> +	SET_SYSTEM_SLEEP_PM_OPS(rmi_smb_suspend, rmi_smb_resume)
> +	SET_RUNTIME_PM_OPS(rmi_smb_runtime_suspend, rmi_smb_runtime_resume,
> +			   NULL)
> +};
> +
> +static const struct i2c_device_id rmi_id[] = {
> +	{ "rmi4_smbus", 0 },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(i2c, rmi_id);
> +
> +static struct i2c_driver rmi_smb_driver = {
> +	.driver = {
> +		.owner	= THIS_MODULE,
> +		.name	= "rmi4_smbus",
> +		.pm	= &rmi_smb_pm,
> +	},
> +	.id_table	= rmi_id,
> +	.probe		= rmi_smb_probe,
> +	.remove		= rmi_smb_remove,
> +};
> +
> +module_i2c_driver(rmi_smb_driver);
> +
> +MODULE_AUTHOR("Andrew Duggan <aduggan@synaptics.com>");
> +MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@redhat.com>");
> +MODULE_DESCRIPTION("RMI4 SMBus driver");
> +MODULE_LICENSE("GPL");
> -- 
> 2.7.4
> 

-- 
Dmitry

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

end of thread, other threads:[~2016-11-09  1:08 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-10-13 15:50 [PATCH v3 00/18] Synaptics RMI4 and SMBus implementation Benjamin Tissoires
2016-10-13 15:50 ` [PATCH v3 01/18] Input: synaptics-rmi4 - Move IRQ handling to rmi_driver Benjamin Tissoires
2016-11-09  0:47   ` Dmitry Torokhov
2016-10-13 15:50 ` [PATCH v3 02/18] Input: synaptics-rmi4 - factor out functions from probe Benjamin Tissoires
2016-10-13 15:50 ` [PATCH v3 03/18] Input: synaptics-rmi4 - Handle incomplete input data Benjamin Tissoires
2016-11-09  0:46   ` Dmitry Torokhov
2016-10-13 15:50 ` [PATCH v3 04/18] Input: synaptics-rmi4 - Add parameters for dribble packets and palm detect gesture Benjamin Tissoires
2016-11-09  0:51   ` Dmitry Torokhov
2016-10-13 15:50 ` [PATCH v3 05/18] Input: synaptics-rmi4 - Add support for controlling dribble packets in F12 Benjamin Tissoires
2016-11-09  1:02   ` Dmitry Torokhov
2016-10-13 15:51 ` [PATCH v3 06/18] Input: synaptics-rmi4 - Set the ABS_MT_TOOL_TYPE bit to report tool type Benjamin Tissoires
2016-11-09  1:03   ` Dmitry Torokhov
2016-10-13 15:51 ` [PATCH v3 07/18] Input: synaptics-rmi4 - add SMBus support Benjamin Tissoires
2016-11-09  1:08   ` Dmitry Torokhov
2016-10-13 15:51 ` [PATCH v3 08/18] Input: serio - store the pt_buttons in the struct serio directly Benjamin Tissoires
2016-10-13 15:51 ` [PATCH v3 09/18] Input: synaptics-rmi4 - have only one struct platform data Benjamin Tissoires
2016-10-13 15:51 ` [PATCH v3 10/18] Input: synaptics-rmi4 - add support for F03 Benjamin Tissoires
2016-10-13 15:51 ` [PATCH v3 11/18] Input: synaptics-rmi4 - f03: grab data passed by transport device Benjamin Tissoires
2016-10-13 15:51 ` [PATCH v3 12/18] Input: synaptics-rmi4 - Add rmi_find_function() Benjamin Tissoires
2016-10-13 15:51 ` [PATCH v3 13/18] Input: synaptics-rmi4 - f30/f03: Forward mechanical buttons on buttonpads to PS/2 guest Benjamin Tissoires
2016-10-13 15:51 ` [PATCH v3 14/18] Input: synaptics - allocate a Synaptics Intertouch device Benjamin Tissoires
2016-10-13 15:51 ` [PATCH v3 15/18] Input: synaptics-rmi4 - add rmi_platform Benjamin Tissoires
2016-10-13 15:51 ` [PATCH v3 16/18] Input: synaptics-rmi4 - smbus: call psmouse_deactivate before binding/resume Benjamin Tissoires
2016-10-13 15:51 ` [PATCH v3 17/18] Input: synaptics-rmi4 - smbus: on resume, try 3 times if init fails Benjamin Tissoires
2016-10-13 15:51 ` [PATCH v3 18/18] Input: synaptics-rmi4 - fix documentation of rmi_2d_sensor_platform_data Benjamin Tissoires
2016-11-04  8:23 ` [PATCH v3 00/18] Synaptics RMI4 and SMBus implementation Benjamin Tissoires
2016-11-07 23:17   ` Nick Dyer
2016-11-08 15:09     ` Benjamin Tissoires

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).