* Re: input question: ambient light sensor button
From: Jiri Kosina @ 2013-11-13 10:47 UTC (permalink / raw)
To: Pali Rohár; +Cc: linux-kernel, linux-input, Dmitry Torokhov
In-Reply-To: <201309151553.34000@pali>
On Sun, 15 Sep 2013, Pali Rohár wrote:
> I do not know where to ask this question, but I think that kernel
> developers could help me.
>
> I have notebook with one special button on keyboard which is
> designed for turning ambient light sensor on and off. By default
> pressing button do nothing (I can turn ambient light sensor on/off
> via sysfs platform wmi module). Button press is reported by
> kernel input device AT Translated Set 2 keyboard and reports it
> as button "touchpad off".
>
> Of course "touchpad off" is incorrect and I'd like to ask which
> kernel key or button from /usr/include/linux/input.h should be
> mapped for my ambient light sensor button? Is there already some?
> And what is strategy for allocating KEY_* and BTN_* numbers?
This is maintained by Dmitry, so he's the one to answer this. I am adding
him to CC.
> I'd like to know this, so udev could have correct DMI keymap
> hooks and other userspace programs can understand ambient light
> sensor button correctly.
--
Jiri Kosina
SUSE Labs
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH] HID: i2c-hid: disable interrupt on suspend
From: Mika Westerberg @ 2013-11-13 11:34 UTC (permalink / raw)
To: Jiri Kosina
Cc: Benjamin Tissoires, Jean Delvare, linux-input, linux-kernel,
Mika Westerberg, Jerome Blin
When an I2C HID device is powered of during system sleep, as a result of
removing its power resources (by the ACPI core) the interrupt line might go
low as well. This results inadvertent interrupt and wakes the system from
sleep immediately.
To prevent this we disable the device interrupt in the drivers suspend
method and enable it on resume. The device can still wake the system up if
it is wake capable (this also means that not all of its power will be
removed to keep the interrupt line high).
Reported-by: Jerome Blin <jerome.blin@intel.com>
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
---
drivers/hid/i2c-hid/i2c-hid.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c
index c1336193b04b..dc8b575477b4 100644
--- a/drivers/hid/i2c-hid/i2c-hid.c
+++ b/drivers/hid/i2c-hid/i2c-hid.c
@@ -1073,6 +1073,7 @@ static int i2c_hid_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
+ disable_irq(client->irq);
if (device_may_wakeup(&client->dev))
enable_irq_wake(client->irq);
@@ -1087,6 +1088,7 @@ static int i2c_hid_resume(struct device *dev)
int ret;
struct i2c_client *client = to_i2c_client(dev);
+ enable_irq(client->irq);
ret = i2c_hid_hwreset(client);
if (ret)
return ret;
--
1.8.4.3
^ permalink raw reply related
* Re: input question: ambient light sensor button
From: Dmitry Torokhov @ 2013-11-13 16:28 UTC (permalink / raw)
To: Jiri Kosina; +Cc: Pali Rohár, linux-kernel, linux-input
In-Reply-To: <alpine.LNX.2.00.1311131146410.22940@pobox.suse.cz>
On Wed, Nov 13, 2013 at 11:47:18AM +0100, Jiri Kosina wrote:
> On Sun, 15 Sep 2013, Pali Rohár wrote:
>
> > I do not know where to ask this question, but I think that kernel
> > developers could help me.
> >
> > I have notebook with one special button on keyboard which is
> > designed for turning ambient light sensor on and off. By default
> > pressing button do nothing (I can turn ambient light sensor on/off
> > via sysfs platform wmi module). Button press is reported by
> > kernel input device AT Translated Set 2 keyboard and reports it
> > as button "touchpad off".
> >
> > Of course "touchpad off" is incorrect and I'd like to ask which
> > kernel key or button from /usr/include/linux/input.h should be
> > mapped for my ambient light sensor button? Is there already some?
> > And what is strategy for allocating KEY_* and BTN_* numbers?
>
> This is maintained by Dmitry, so he's the one to answer this. I am adding
> him to CC.
I guess we need patch adding
#define KEY_ALS_TOGGLE 0x230
Thanks.
--
Dmitry
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH] input synaptics-rmi4: Fix camel case in comments.
From: Christopher Heiny @ 2013-11-13 21:15 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Linux Input, Christopher Heiny, Andrew Duggan, Vincent Huang,
Vivian Ly, Daniel Rosenberg
Trivial change to make variable names in a comment match those in the code.
Signed-off-by: Christopher Heiny <cheiny@synaptics.com>
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
include/linux/rmi.h | 25 ++++++++++++++++++-------
1 file changed, 18 insertions(+), 7 deletions(-)
diff --git a/include/linux/rmi.h b/include/linux/rmi.h
index 01f2f13..dc94dc1 100644
--- a/include/linux/rmi.h
+++ b/include/linux/rmi.h
@@ -9,8 +9,19 @@
#ifndef _RMI_H
#define _RMI_H
-
+#include <linux/kernel.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/list.h>
+#include <linux/lockdep.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/stat.h>
#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/debugfs.h>
enum rmi_attn_polarity {
RMI_ATTN_ACTIVE_LOW = 0,
@@ -22,16 +33,16 @@ enum rmi_attn_polarity {
* @swap_axes: set to TRUE if desired to swap x- and y-axis
* @flip_x: set to TRUE if desired to flip direction on x-axis
* @flip_y: set to TRUE if desired to flip direction on y-axis
- * @clip_X_low - reported X coordinates below this setting will be clipped to
+ * @clip_x_low - reported X coordinates below this setting will be clipped to
* the specified value
- * @clip_X_high - reported X coordinates above this setting will be clipped to
+ * @clip_x_high - reported X coordinates above this setting will be clipped to
* the specified value
- * @clip_Y_low - reported Y coordinates below this setting will be clipped to
+ * @clip_y_low - reported Y coordinates below this setting will be clipped to
* the specified value
- * @clip_Y_high - reported Y coordinates above this setting will be clipped to
+ * @clip_y_high - reported Y coordinates above this setting will be clipped to
* the specified value
- * @offset_X - this value will be added to all reported X coordinates
- * @offset_Y - this value will be added to all reported Y coordinates
+ * @offset_x - this value will be added to all reported X coordinates
+ * @offset_y - this value will be added to all reported Y coordinates
* @rel_report_enabled - if set to true, the relative reporting will be
* automatically enabled for this sensor.
*/
^ permalink raw reply related
* [RESEND] [PATCH] input synaptics-rmi4: Fix camel case in comments.
From: Christopher Heiny @ 2013-11-13 23:02 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Linux Input, Christopher Heiny, Andrew Duggan, Vincent Huang,
Vivian Ly, Daniel Rosenberg, Jean Delvare, Joerie de Gram,
Linus Walleij
[Sorry if this is a duplicate - vger.kernel.org has bounced previous attempts.]
Trivial change to make variable names in a comment match those in the code.
Signed-off-by: Christopher Heiny <cheiny@synaptics.com>
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
include/linux/rmi.h | 25 ++++++++++++++++++-------
1 file changed, 18 insertions(+), 7 deletions(-)
diff --git a/include/linux/rmi.h b/include/linux/rmi.h
index 01f2f13..dc94dc1 100644
--- a/include/linux/rmi.h
+++ b/include/linux/rmi.h
@@ -9,8 +9,19 @@
#ifndef _RMI_H
#define _RMI_H
-
+#include <linux/kernel.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/list.h>
+#include <linux/lockdep.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/stat.h>
#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/debugfs.h>
enum rmi_attn_polarity {
RMI_ATTN_ACTIVE_LOW = 0,
@@ -22,16 +33,16 @@ enum rmi_attn_polarity {
* @swap_axes: set to TRUE if desired to swap x- and y-axis
* @flip_x: set to TRUE if desired to flip direction on x-axis
* @flip_y: set to TRUE if desired to flip direction on y-axis
- * @clip_X_low - reported X coordinates below this setting will be clipped to
+ * @clip_x_low - reported X coordinates below this setting will be clipped to
* the specified value
- * @clip_X_high - reported X coordinates above this setting will be clipped to
+ * @clip_x_high - reported X coordinates above this setting will be clipped to
* the specified value
- * @clip_Y_low - reported Y coordinates below this setting will be clipped to
+ * @clip_y_low - reported Y coordinates below this setting will be clipped to
* the specified value
- * @clip_Y_high - reported Y coordinates above this setting will be clipped to
+ * @clip_y_high - reported Y coordinates above this setting will be clipped to
* the specified value
- * @offset_X - this value will be added to all reported X coordinates
- * @offset_Y - this value will be added to all reported Y coordinates
+ * @offset_x - this value will be added to all reported X coordinates
+ * @offset_y - this value will be added to all reported Y coordinates
* @rel_report_enabled - if set to true, the relative reporting will be
* automatically enabled for this sensor.
*/
^ permalink raw reply related
* [PATCH 00/04] input: RMI4 Synaptics RMI4 Touchscreen Driver
From: Christopher Heiny @ 2013-11-13 23:39 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Linux Input, Christopher Heiny, Andrew Duggan, Vincent Huang,
Vivian Ly, Daniel Rosenberg, Jean Delvare, Joerie de Gram,
Linus Walleij
This patchset implements changes to the synaptics-rmi4 branch of
Dmitry's input tree. The base for the patchset is Dmitry's commit
4a695a01fba9bf467b3b52e124ccee6cef73b323 from 2013-01-31.
Overall this patchset implements the following changes with respect to
the Dmitry's 2013-01-31 commit:
* Refactors the transport layer (rmi_i2c) to be named appropriately.
* Eliminates packed struct bitfields, replacing them with masks
and shifts. This should make the various register definitions
endian-independent.
* Removed most or all of the sysfs and debugfs support from the driver core
and function drivers. These features are still critical during platform
development, particularly on embedded systems, so there are hooks that allow
custom modules that support these control and debug capabilities. One result
of this is that several .c files have a corresponding .h file (for example,
rmi_f01.c has a corresponding rmi_f01.h). Also, a rmi_control.h file is
added to provide general definitions for control/debug modules.
* Fixes a number of bugs in the baseline commit.
* Trivial - added an rmi_version.h file, which lets the version be easily
tweaked using a script.
We've broken this patch into 6 parts, as follows:
01 - core sensor and bus implementation
02 - I2C physical layer driver
03..04 - drivers for individual RMI functions
Hopefully this is the last time we'll have wide-ranging structural changes in
the driver code, and future patchsets can be much smaller and confined to
one or two areas of interest. (yeah, I've said that before...)
Comments and other feedback on this driver are welcomed.
Christopher Heiny and the Synaptics RMI4 driver team
Signed-off-by: Christopher Heiny <cheiny@synaptics.com>
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: Jean Delvare <khali@linux-fr.org>
Cc: Linus Walleij <linus.walleij@stericsson.com>
Cc: Joerie de Gram <j.de.gram@gmail.com>
---
^ permalink raw reply
* [PATCH 01/04] input: RMI4 core files
From: Christopher Heiny @ 2013-11-13 23:39 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Linux Input, Christopher Heiny, Andrew Duggan, Vincent Huang,
Vivian Ly, Daniel Rosenberg, Jean Delvare, Joerie de Gram,
Linus Walleij
In-Reply-To: <1384385972-1686-1-git-send-email-cheiny@synaptics.com>
In addition to the changes described in part 0/5, this implements the following:
* reorders declarations in rmi_bus.c to group related items near each other
(for instance, things relating to function drivers and devices are now
located together).
* fixes some bugs in the ATTN gpio initialization code.
* adds rmi_control.h, for use by control/debug modules.
* adds rmi_version.h.
Signed-off-by: Christopher Heiny <cheiny@synaptics.com>
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: Linus Walleij <linus.walleij@stericsson.com>
Cc: Joeri de Gram <j.de.gram@gmail.com>
---
drivers/input/rmi4/rmi_bus.c | 397 +++++++++++--------
drivers/input/rmi4/rmi_bus.h | 146 +++----
drivers/input/rmi4/rmi_control.h | 58 +++
drivers/input/rmi4/rmi_driver.c | 818 +++++++++++++++++++--------------------
drivers/input/rmi4/rmi_driver.h | 97 ++---
drivers/input/rmi4/rmi_version.h | 16 +
6 files changed, 827 insertions(+), 705 deletions(-)
diff --git a/drivers/input/rmi4/rmi_bus.c b/drivers/input/rmi4/rmi_bus.c
index 88f60ca..5711866 100644
--- a/drivers/input/rmi4/rmi_bus.c
+++ b/drivers/input/rmi4/rmi_bus.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2012 Synaptics Incorporated
+ * Copyright (c) 2011-2013 Synaptics Incorporated
* Copyright (c) 2011 Unixphere
*
* This program is free software; you can redistribute it and/or modify it
@@ -16,61 +16,15 @@
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/debugfs.h>
+
#include "rmi_bus.h"
+#include "rmi_control.h"
#include "rmi_driver.h"
-static int rmi_function_match(struct device *dev, struct device_driver *drv)
-{
- struct rmi_function_handler *handler = to_rmi_function_handler(drv);
- struct rmi_function *fn = to_rmi_function(dev);
-
- return fn->fd.function_number == handler->func;
-}
-
-static int rmi_bus_match(struct device *dev, struct device_driver *drv)
-{
- bool physical = rmi_is_physical_device(dev);
-
- /* First see if types are not compatible */
- if (physical != rmi_is_physical_driver(drv))
- return 0;
-
- return physical || rmi_function_match(dev, drv);
-}
-
-struct bus_type rmi_bus_type = {
- .match = rmi_bus_match,
- .name = "rmi",
-};
+DEFINE_MUTEX(rmi_bus_mutex);
#ifdef CONFIG_RMI4_DEBUG
-
-static struct dentry *rmi_debugfs_root;
-
-static void rmi_bus_setup_debugfs(void)
-{
- rmi_debugfs_root = debugfs_create_dir(rmi_bus_type.name, NULL);
- if (!rmi_debugfs_root)
- pr_err("%s: Failed to create debugfs root\n",
- __func__);
-}
-
-static void rmi_bus_teardown_debugfs(void)
-{
- if (rmi_debugfs_root)
- debugfs_remove_recursive(rmi_debugfs_root);
-}
-
-#else
-
-static void rmi_bus_setup_debugfs(void)
-{
-}
-
-static void rmi_bus_teardown_debugfs(void)
-{
-}
-
+static struct dentry *rmi_bus_debugfs_root;
#endif
@@ -85,29 +39,23 @@ static void rmi_bus_teardown_debugfs(void)
static void rmi_release_device(struct device *dev)
{
struct rmi_device *rmi_dev = to_rmi_device(dev);
-
kfree(rmi_dev);
}
-/* Device type for physical RMI devices */
struct device_type rmi_device_type = {
.name = "rmi_sensor",
.release = rmi_release_device,
};
-
-bool rmi_is_physical_device(struct device *dev)
-{
- return dev->type == &rmi_device_type;
-}
+EXPORT_SYMBOL_GPL(rmi_device_type);
#if CONFIG_RMI4_DEBUG
static void rmi_physical_setup_debugfs(struct rmi_device *rmi_dev)
{
rmi_dev->debugfs_root = debugfs_create_dir(dev_name(&rmi_dev->dev),
- rmi_debugfs_root);
+ rmi_bus_debugfs_root);
if (!rmi_dev->debugfs_root)
- dev_warn(&rmi_dev->dev, "Failed to create debugfs root.\n");
+ dev_warn(&rmi_dev->dev, "Failed to create sensor debugfs root.\n");
}
static void rmi_physical_teardown_debugfs(struct rmi_device *rmi_dev)
@@ -118,7 +66,7 @@ static void rmi_physical_teardown_debugfs(struct rmi_device *rmi_dev)
#else
-static void rmi_physocal_setup_debugfs(struct rmi_device *rmi_dev)
+static void rmi_physical_setup_debugfs(struct rmi_device *rmi_dev)
{
}
@@ -128,91 +76,100 @@ static void rmi_physical_teardown_debugfs(struct rmi_device *rmi_dev)
#endif
-
/**
- * rmi_register_physical_device - register a physical device connection on the RMI
- * bus. Physical drivers provide communication from the devices on the bus to
- * the RMI4 sensor on a bus such as SPI, I2C, and so on.
+ * rmi_register_transport_device - register a transport connection on the RMI
+ * bus. Transport drivers provide communication with an RMI4 devices residing
+ * on a bus such as SPI, I2C, and so on.
*
- * @phys: the physical device to register
+ * @transport: the device to register
*/
-int rmi_register_physical_device(struct rmi_phys_device *phys)
+int rmi_register_transport_device(struct rmi_transport_device *xport)
{
- static atomic_t physical_device_count = ATOMIC_INIT(0);
- struct rmi_device_platform_data *pdata = phys->dev->platform_data;
+ static atomic_t transport_dev_count = ATOMIC_INIT(0);
+ struct rmi_device_platform_data *pdata = xport->dev->platform_data;
struct rmi_device *rmi_dev;
int error;
if (!pdata) {
- dev_err(phys->dev, "no platform data!\n");
+ dev_err(xport->dev, "no platform data!\n");
return -EINVAL;
}
- rmi_dev = devm_kzalloc(phys->dev,
+ rmi_dev = devm_kzalloc(xport->dev,
sizeof(struct rmi_device), GFP_KERNEL);
if (!rmi_dev)
return -ENOMEM;
- rmi_dev->phys = phys;
- rmi_dev->number = atomic_inc_return(&physical_device_count) - 1;
+ rmi_dev->xport = xport;
+ rmi_dev->number = atomic_inc_return(&transport_dev_count) - 1;
dev_set_name(&rmi_dev->dev, "sensor%02d", rmi_dev->number);
rmi_dev->dev.bus = &rmi_bus_type;
rmi_dev->dev.type = &rmi_device_type;
- phys->rmi_dev = rmi_dev;
+ xport->rmi_dev = rmi_dev;
+
+ rmi_physical_setup_debugfs(rmi_dev);
error = device_register(&rmi_dev->dev);
if (error)
return error;
- rmi_physical_setup_debugfs(rmi_dev);
-
- dev_dbg(phys->dev, "%s: Registered %s as %s.\n", __func__,
+ dev_dbg(xport->dev, "%s: Registered %s as %s.\n", __func__,
pdata->sensor_name, dev_name(&rmi_dev->dev));
return 0;
}
-EXPORT_SYMBOL(rmi_register_physical_device);
+EXPORT_SYMBOL_GPL(rmi_register_transport_device);
/**
- * rmi_unregister_physical_device - unregister a physical device connection
- * @phys: the physical driver to unregister
+ * rmi_unregister_transport_device - unregister a transport connection
+ * @xport: the connection to unregister
*
*/
-void rmi_unregister_physical_device(struct rmi_phys_device *phys)
+void rmi_unregister_transport_device(struct rmi_transport_device *xport)
{
- struct rmi_device *rmi_dev = phys->rmi_dev;
+ struct rmi_device *rmi_dev = xport->rmi_dev;
rmi_physical_teardown_debugfs(rmi_dev);
+
device_unregister(&rmi_dev->dev);
}
-EXPORT_SYMBOL(rmi_unregister_physical_device);
+EXPORT_SYMBOL_GPL(rmi_unregister_transport_device);
-/*
- * RMI Function devices and their handlers
- */
+static bool rmi_is_physical_driver(struct device_driver *drv)
+{
+ return drv == &rmi_physical_driver.driver;
+}
-static void rmi_release_function(struct device *dev)
+static int rmi_physical_remove(struct device *dev)
{
- struct rmi_function *fn = to_rmi_function(dev);
+ struct rmi_driver *driver;
+ struct rmi_device *rmi_dev = to_rmi_device(dev);
- kfree(fn);
+ driver = to_rmi_driver(dev->driver);
+
+ if (driver->remove)
+ return driver->remove(rmi_dev);
+ return 0;
}
-/* Device type for RMI Function devices */
-struct device_type rmi_function_type = {
- .name = "rmi_function",
- .release = rmi_release_function,
-};
+/* Function specific stuff */
-bool rmi_is_function_device(struct device *dev)
+static void rmi_release_function_dev(struct device *dev)
{
- return dev->type == &rmi_function_type;
+ struct rmi_function *fn = to_rmi_function(dev);
+ kfree(fn);
}
+struct device_type rmi_function_type = {
+ .name = "rmi_function",
+ .release = rmi_release_function_dev,
+};
+EXPORT_SYMBOL_GPL(rmi_function_type);
+
#if CONFIG_RMI4_DEBUG
static void rmi_function_setup_debugfs(struct rmi_function *fn)
@@ -244,119 +201,235 @@ static void rmi_function_teardown_debugfs(struct rmi_function *fn)
#endif
-int rmi_register_function(struct rmi_function *fn)
+static int rmi_function_match(struct device *dev, struct device_driver *drv)
{
- struct rmi_device *rmi_dev = fn->rmi_dev;
- int error;
+ struct rmi_function_driver *fn_drv = to_rmi_function_driver(drv);
+ struct rmi_function *fn = to_rmi_function(dev);
- dev_set_name(&fn->dev, "%s.fn%02x",
- dev_name(&rmi_dev->dev), fn->fd.function_number);
+ return fn->fd.function_number == fn_drv->func;
+}
- fn->dev.parent = &rmi_dev->dev;
- fn->dev.type = &rmi_function_type;
- fn->dev.bus = &rmi_bus_type;
+static int rmi_function_probe(struct device *dev)
+{
+ struct rmi_function_driver *fn_drv;
+ struct rmi_function *fn = to_rmi_function(dev);
- error = device_register(&fn->dev);
- if (error) {
- dev_err(&rmi_dev->dev,
- "Failed device_register function device %s\n",
- dev_name(&fn->dev));
- }
+ fn_drv = to_rmi_function_driver(dev->driver);
- dev_dbg(&rmi_dev->dev, "Registered F%02X.\n", fn->fd.function_number);
+ if (fn_drv->probe)
+ return fn_drv->probe(fn);
- rmi_function_setup_debugfs(fn);
return 0;
}
-void rmi_unregister_function(struct rmi_function *fn)
+static int rmi_function_remove(struct device *dev)
{
- rmi_function_teardown_debugfs(fn);
- device_unregister(&fn->dev);
+ struct rmi_function_driver *fn_drv;
+ struct rmi_function *fn = to_rmi_function(dev);
+
+ fn_drv = to_rmi_function_driver(dev->driver);
+
+ if (fn_drv->remove)
+ return fn_drv->remove(fn);
+
+ return 0;
}
-static int rmi_function_probe(struct device *dev)
+int rmi_register_function_dev(struct rmi_function *fn)
{
- struct rmi_function *fn = to_rmi_function(dev);
- struct rmi_function_handler *handler =
- to_rmi_function_handler(dev->driver);
+ struct rmi_device *rmi_dev = fn->rmi_dev;
int error;
- if (handler->probe) {
- error = handler->probe(fn);
+ dev_set_name(&fn->dev, "%s.fn%02x", dev_name(&rmi_dev->dev),
+ fn->fd.function_number);
+
+ fn->dev.parent = &rmi_dev->dev;
+ fn->dev.type = &rmi_function_type;
+ fn->dev.bus = &rmi_bus_type;
+
+ error = device_register(&fn->dev);
+ if (error) {
+ dev_err(&rmi_dev->dev, "Failed device register function device %s.\n",
+ dev_name(&fn->dev));
return error;
}
+ dev_dbg(&rmi_dev->dev, "Registered F%02X.\n",
+ fn->fd.function_number);
+
+ rmi_function_setup_debugfs(fn);
return 0;
}
-static int rmi_function_remove(struct device *dev)
+void rmi_unregister_function_dev(struct rmi_function *fn)
{
- struct rmi_function *fn = to_rmi_function(dev);
- struct rmi_function_handler *handler =
- to_rmi_function_handler(dev->driver);
-
- if (handler->remove)
- handler->remove(fn);
-
- return 0;
+ rmi_function_teardown_debugfs(fn);
+ device_unregister(&fn->dev);
}
/**
- * rmi_register_function_handler - register a handler for an RMI function
- * @handler: RMI handler that should be registered.
- * @module: pointer to module that implements the handler
- * @mod_name: name of the module implementing the handler
+ * rmi_register_function_driver - register a driver for an RMI function
+ * @fn_drv: RMI driver that should be registered.
+ * @module: pointer to module that implements the driver
+ * @mod_name: name of the module implementing the driver
*
- * This function performs additional setup of RMI function handler and
+ * This function performs additional setup of RMI function driver and
* registers it with the RMI core so that it can be bound to
* RMI function devices.
*/
-int __rmi_register_function_handler(struct rmi_function_handler *handler,
- struct module *owner,
- const char *mod_name)
+int __rmi_register_function_driver(struct rmi_function_driver *fn_drv,
+ struct module *owner,
+ const char *mod_name)
{
- struct device_driver *driver = &handler->driver;
+ struct device_driver *driver = &fn_drv->driver;
int error;
driver->bus = &rmi_bus_type;
driver->owner = owner;
driver->mod_name = mod_name;
driver->probe = rmi_function_probe;
- driver->remove = rmi_function_remove;
- error = driver_register(&handler->driver);
+ error = driver_register(&fn_drv->driver);
if (error) {
pr_err("driver_register() failed for %s, error: %d\n",
- handler->driver.name, error);
+ fn_drv->driver.name, error);
return error;
}
return 0;
}
-EXPORT_SYMBOL(__rmi_register_function_handler);
+EXPORT_SYMBOL_GPL(__rmi_register_function_driver);
/**
- * rmi_unregister_function_handler - unregister given RMI function handler
- * @handler: RMI handler that should be unregistered.
+ * rmi_unregister_function_driver - unregister given RMI function driver
+ * @fn_drv: RMI driver that should be unregistered.
*
- * This function unregisters given function handler from RMI core which
+ * This function unregisters given function driver from RMI core which
* causes it to be unbound from the function devices.
*/
-void rmi_unregister_function_handler(struct rmi_function_handler *handler)
+void rmi_unregister_function_driver(struct rmi_function_driver *fn_drv)
{
- driver_unregister(&handler->driver);
+ driver_unregister(&fn_drv->driver);
}
-EXPORT_SYMBOL(rmi_unregister_function_handler);
+EXPORT_SYMBOL_GPL(rmi_unregister_function_driver);
-/*
- * Bus registration and tear-down
+/* Bus specific stuff */
+
+static int rmi_bus_match(struct device *dev, struct device_driver *drv)
+{
+ bool sensor = rmi_is_physical_device(dev);
+
+ /* First see if types are not compatible.
+ */
+ if (sensor != rmi_is_physical_driver(drv))
+ return 0;
+
+ return sensor || rmi_function_match(dev, drv);
+}
+
+static int rmi_bus_remove(struct device *dev)
+{
+ if (rmi_is_function_device(dev))
+ return rmi_function_remove(dev);
+ else if (rmi_is_physical_device(dev))
+ return rmi_physical_remove(dev);
+ return -EINVAL;
+}
+
+#ifdef CONFIG_PM
+static int rmi_bus_suspend(struct device *dev)
+{
+ struct device_driver *driver = dev->driver;
+ const struct dev_pm_ops *pm;
+
+ if (!driver)
+ return 0;
+
+ pm = driver->pm;
+ if (pm && pm->suspend)
+ return pm->suspend(dev);
+ if (driver->suspend)
+ return driver->suspend(dev, PMSG_SUSPEND);
+
+ return 0;
+}
+
+static int rmi_bus_resume(struct device *dev)
+{
+ struct device_driver *driver = dev->driver;
+ const struct dev_pm_ops *pm;
+
+ if (!driver)
+ return 0;
+
+ pm = driver->pm;
+ if (pm && pm->resume)
+ return pm->resume(dev);
+ if (driver->resume)
+ return driver->resume(dev);
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(rmi_bus_pm_ops,
+ rmi_bus_suspend, rmi_bus_resume);
+
+struct bus_type rmi_bus_type = {
+ .name = "rmi",
+ .match = rmi_bus_match,
+ .remove = rmi_bus_remove,
+ .pm = &rmi_bus_pm_ops,
+};
+EXPORT_SYMBOL_GPL(rmi_bus_type);
+
+/**
+ * rmi_for_each_dev - provides a way for other parts of the system to enumerate
+ * the devices on the RMI bus.
+ *
+ * @data - will be passed into the callback function.
+ * @func - will be called for each device.
*/
+int rmi_for_each_dev(void *data, int (*func)(struct device *dev, void *data))
+{
+ int retval;
+ mutex_lock(&rmi_bus_mutex);
+ retval = bus_for_each_dev(&rmi_bus_type, NULL, data, func);
+ mutex_unlock(&rmi_bus_mutex);
+ return retval;
+}
+EXPORT_SYMBOL_GPL(rmi_for_each_dev);
+
+#ifdef CONFIG_RMI4_DEBUG
+static void rmi_bus_setup_debugfs(void)
+{
+ rmi_bus_debugfs_root = debugfs_create_dir(rmi_bus_type.name, NULL);
+ if (!rmi_bus_debugfs_root)
+ pr_err("%s: Failed to create bus debugfs root.\n",
+ __func__);
+}
+
+static void rmi_bus_teardown_debugfs(void)
+{
+ if (rmi_bus_debugfs_root)
+ debugfs_remove_recursive(rmi_bus_debugfs_root);
+}
+#else
+static void rmi_bus_setup_debugfs(void)
+{
+}
+
+static void rmi_bus_teardown_debugfs(void)
+{
+}
+#endif
static int __init rmi_bus_init(void)
{
int error;
+ mutex_init(&rmi_bus_mutex);
+
error = bus_register(&rmi_bus_type);
if (error) {
pr_err("%s: error registering the RMI bus: %d\n",
@@ -364,31 +437,30 @@ static int __init rmi_bus_init(void)
return error;
}
- error = rmi_register_f01_handler();
+ rmi_bus_setup_debugfs();
+
+ error = rmi_register_function_driver(&rmi_f01_driver);
if (error) {
- pr_err("%s: error registering the RMI F01 handler: %d\n",
+ pr_err("%s: error registering the RMI F01 driver: %d\n",
__func__, error);
goto err_unregister_bus;
}
- error = rmi_register_physical_driver();
+ error = rmi_register_sensor_driver();
if (error) {
- pr_err("%s: error registering the RMI physical driver: %d\n",
+ pr_err("%s: error registering the RMI sensor driver: %d\n",
__func__, error);
goto err_unregister_f01;
}
- rmi_bus_setup_debugfs();
-
return 0;
err_unregister_f01:
- rmi_unregister_f01_handler();
+ rmi_unregister_function_driver(&rmi_f01_driver);
err_unregister_bus:
bus_unregister(&rmi_bus_type);
return error;
}
-module_init(rmi_bus_init);
static void __exit rmi_bus_exit(void)
{
@@ -396,12 +468,13 @@ static void __exit rmi_bus_exit(void)
* We should only ever get here if all drivers are unloaded, so
* all we have to do at this point is unregister ourselves.
*/
-
rmi_bus_teardown_debugfs();
- rmi_unregister_physical_driver();
- rmi_unregister_f01_handler();
+ rmi_unregister_sensor_driver();
+ rmi_unregister_function_driver(&rmi_f01_driver);
bus_unregister(&rmi_bus_type);
}
+
+module_init(rmi_bus_init);
module_exit(rmi_bus_exit);
MODULE_AUTHOR("Christopher Heiny <cheiny@synaptics.com");
diff --git a/drivers/input/rmi4/rmi_bus.h b/drivers/input/rmi4/rmi_bus.h
index 33e8f1b..85b0c8e 100644
--- a/drivers/input/rmi4/rmi_bus.h
+++ b/drivers/input/rmi4/rmi_bus.h
@@ -22,6 +22,19 @@
#include <linux/debugfs.h>
#include <linux/rmi.h>
+extern struct bus_type rmi_bus_type;
+
+extern struct device_type rmi_function_type;
+
+#define rmi_is_function_device(dev) \
+ (dev->type == &rmi_function_type)
+
+
+extern struct device_type rmi_device_type;
+
+#define rmi_is_physical_device(dev) \
+ (dev->type == &rmi_device_type)
+
/* Permissions for sysfs attributes. Since the permissions policy will change
* on a global basis in the future, rather than edit all sysfs attrs everywhere
@@ -33,14 +46,12 @@
#define RMI_RW_ATTR (S_IRUGO | S_IWUGO)
#define RMI_WO_ATTR S_IWUGO
-struct rmi_device;
-
/**
- * struct rmi_function - represents the implementation of an RMI4
- * function for a particular device (basically, a driver for that RMI4 function)
+ * struct rmi_function - represents an a particular RMI4 function on a given
+ * RMI4 sensor.
*
* @fd: The function descriptor of the RMI function
- * @rmi_dev: Pointer to the RMI device associated with this function container
+ * @rmi_dev: Pointer to the RMI device associated with this function device
* @dev: The device associated with this particular function.
*
* @num_of_irqs: The number of irqs needed by this function
@@ -49,10 +60,12 @@ struct rmi_device;
* interrupt handling.
* @data: Private data pointer
*
- * @node: entry in physical device list of functions
+ * @list: Used to create a list of function devices.
* @debugfs_root: used during debugging
+ *
*/
struct rmi_function {
+
struct rmi_function_descriptor fd;
struct rmi_device *rmi_dev;
struct device dev;
@@ -62,22 +75,17 @@ struct rmi_function {
void *data;
struct list_head node;
-#ifdef CONFIG_RMI4_DEBUG
struct dentry *debugfs_root;
-#endif
};
-#define to_rmi_function(d) container_of(d, struct rmi_function, dev)
-
-bool rmi_is_function_device(struct device *dev);
-
-int __must_check rmi_register_function(struct rmi_function *);
-void rmi_unregister_function(struct rmi_function *);
+#define to_rmi_function(d) \
+ container_of(d, struct rmi_function, dev)
/**
- * struct rmi_function_handler - driver routines for a particular RMI function.
+ * struct rmi_function_driver - driver routines for a particular RMI function.
*
* @func: The RMI function number
+ * @probe: Called when the handler is successfully matched to a function device.
* @reset: Called when a reset of the touch sensor is detected. The routine
* should perform any out-of-the-ordinary reset handling that might be
* necessary. Restoring of touch sensor configuration registers should be
@@ -87,34 +95,32 @@ void rmi_unregister_function(struct rmi_function *);
* configuration settings to the device.
* @attention: Called when the IRQ(s) for the function are set by the touch
* sensor.
- * @suspend: Should perform any required operations to suspend the particular
- * function.
- * @resume: Should perform any required operations to resume the particular
- * function.
*
* All callbacks are expected to return 0 on success, error code on failure.
*/
-struct rmi_function_handler {
+struct rmi_function_driver {
struct device_driver driver;
u8 func;
-
int (*probe)(struct rmi_function *fn);
- void (*remove)(struct rmi_function *fn);
+ int (*remove)(struct rmi_function *fn);
int (*config)(struct rmi_function *fn);
int (*reset)(struct rmi_function *fn);
int (*attention)(struct rmi_function *fn, unsigned long *irq_bits);
};
-#define to_rmi_function_handler(d) \
- container_of(d, struct rmi_function_handler, driver)
+#define to_rmi_function_driver(d) \
+ container_of(d, struct rmi_function_driver, driver)
-int __must_check __rmi_register_function_handler(struct rmi_function_handler *,
- struct module *, const char *);
-#define rmi_register_function_handler(handler) \
- __rmi_register_function_handler(handler, THIS_MODULE, KBUILD_MODNAME)
+int __must_check __rmi_register_function_driver(struct rmi_function_driver *,
+ struct module *, const char *);
+#define rmi_register_function_driver(handler) \
+ __rmi_register_function_driver(handler, THIS_MODULE, KBUILD_MODNAME)
-void rmi_unregister_function_handler(struct rmi_function_handler *);
+void rmi_unregister_function_driver(struct rmi_function_driver *);
+
+int __must_check rmi_register_function_dev(struct rmi_function *);
+void rmi_unregister_function_dev(struct rmi_function *);
/**
* struct rmi_driver - driver for an RMI4 sensor on the RMI bus.
@@ -135,19 +141,22 @@ struct rmi_driver {
int (*irq_handler)(struct rmi_device *rmi_dev, int irq);
int (*reset_handler)(struct rmi_device *rmi_dev);
int (*store_irq_mask)(struct rmi_device *rmi_dev,
- unsigned long *new_interupts);
+ unsigned long *new_interupts);
int (*restore_irq_mask)(struct rmi_device *rmi_dev);
int (*store_productid)(struct rmi_device *rmi_dev);
int (*set_input_params)(struct rmi_device *rmi_dev,
- struct input_dev *input);
+ struct input_dev *input);
+ int (*enable)(struct rmi_device *rmi_dev);
+ void (*disable)(struct rmi_device *rmi_dev);
+ int (*remove)(struct rmi_device *rmi_dev);
void *data;
};
#define to_rmi_driver(d) \
- container_of(d, struct rmi_driver, driver);
+ container_of(d, struct rmi_driver, driver)
-/** struct rmi_phys_info - diagnostic information about the RMI physical
- * device, used in the phys debugfs file.
+/** struct rmi_transport_info - diagnostic information about the RMI transport,
+ * used in the transport-info debugfs file.
*
* @proto String indicating the protocol being used.
* @tx_count Number of transmit operations.
@@ -158,7 +167,7 @@ struct rmi_driver {
* @rx_errs Number of errors encountered during receive operations.
* @att_count Number of times ATTN assertions have been handled.
*/
-struct rmi_phys_info {
+struct rmi_transport_info {
char *proto;
long tx_count;
long tx_bytes;
@@ -169,7 +178,7 @@ struct rmi_phys_info {
};
/**
- * struct rmi_phys_device - represent an RMI physical device
+ * struct rmi_transport_device - represent an RMI transport conncection
*
* @dev: Pointer to the communication device, e.g. i2c or spi
* @rmi_dev: Pointer to the RMI device
@@ -181,28 +190,28 @@ struct rmi_phys_info {
* handling
* @data: Private data pointer
*
- * The RMI physical device implements the glue between different communication
- * buses such as I2C and SPI.
+ * The RMI transport device implements the glue between different communication
+ * buses such as I2C and SPI and the physical device on the RMI bus.
*
*/
-struct rmi_phys_device {
+struct rmi_transport_device {
struct device *dev;
struct rmi_device *rmi_dev;
- int (*write_block)(struct rmi_phys_device *phys, u16 addr,
+ int (*write_block)(struct rmi_transport_device *xport, u16 addr,
const void *buf, const int len);
- int (*read_block)(struct rmi_phys_device *phys, u16 addr,
+ int (*read_block)(struct rmi_transport_device *xport, u16 addr,
void *buf, const int len);
- int (*enable_device) (struct rmi_phys_device *phys);
- void (*disable_device) (struct rmi_phys_device *phys);
+ int (*enable_device) (struct rmi_transport_device *xport);
+ void (*disable_device) (struct rmi_transport_device *xport);
irqreturn_t (*irq_thread)(int irq, void *p);
irqreturn_t (*hard_irq)(int irq, void *p);
void *data;
- struct rmi_phys_info info;
+ struct rmi_transport_info info;
};
/**
@@ -211,7 +220,7 @@ struct rmi_phys_device {
* @dev: The device created for the RMI bus
* @number: Unique number for the device on the bus.
* @driver: Pointer to associated driver
- * @phys: Pointer to the physical interface
+ * @xport: Pointer to the transport interface
* @debugfs_root: base for this particular sensor device.
*
*/
@@ -220,17 +229,15 @@ struct rmi_device {
int number;
struct rmi_driver *driver;
- struct rmi_phys_device *phys;
+ struct rmi_transport_device *xport;
-#ifdef CONFIG_RMI4_DEBUG
struct dentry *debugfs_root;
-#endif
+ int interrupt_restore_block_flag;
+
};
#define to_rmi_device(d) container_of(d, struct rmi_device, dev)
-#define to_rmi_platform_data(d) ((d)->phys->dev->platform_data)
-
-bool rmi_is_physical_device(struct device *dev);
+#define to_rmi_platform_data(d) ((d)->xport->dev->platform_data)
/**
* rmi_read - read a single byte
@@ -238,12 +245,12 @@ bool rmi_is_physical_device(struct device *dev);
* @addr: The address to read from
* @buf: The read buffer
*
- * Reads a byte of data using the underlaying physical protocol in to buf. It
+ * Reads a byte of data using the underlying transport into buf. It
* returns zero or a negative error code.
*/
static inline int rmi_read(struct rmi_device *d, u16 addr, void *buf)
{
- return d->phys->read_block(d->phys, addr, buf, 1);
+ return d->xport->read_block(d->xport, addr, buf, 1);
}
/**
@@ -253,13 +260,13 @@ static inline int rmi_read(struct rmi_device *d, u16 addr, void *buf)
* @buf: The read buffer
* @len: Length of the read buffer
*
- * Reads a block of byte data using the underlaying physical protocol in to buf.
+ * Reads a block of byte data using the underlying transport into buf.
* It returns the amount of bytes read or a negative error code.
*/
static inline int rmi_read_block(struct rmi_device *d, u16 addr, void *buf,
const int len)
{
- return d->phys->read_block(d->phys, addr, buf, len);
+ return d->xport->read_block(d->xport, addr, buf, len);
}
/**
@@ -268,12 +275,12 @@ static inline int rmi_read_block(struct rmi_device *d, u16 addr, void *buf,
* @addr: The address to write to
* @data: The data to write
*
- * Writes a byte from buf using the underlaying physical protocol. It
+ * Writes a byte from buf using the underlying transport. It
* returns zero or a negative error code.
*/
static inline int rmi_write(struct rmi_device *d, u16 addr, const u8 data)
{
- return d->phys->write_block(d->phys, addr, &data, 1);
+ return d->xport->write_block(d->xport, addr, &data, 1);
}
/**
@@ -283,34 +290,31 @@ static inline int rmi_write(struct rmi_device *d, u16 addr, const u8 data)
* @buf: The write buffer
* @len: Length of the write buffer
*
- * Writes a block of byte data from buf using the underlaying physical protocol.
+ * Writes a block of byte data from buf using the underlying transport.
* It returns the amount of bytes written or a negative error code.
*/
static inline int rmi_write_block(struct rmi_device *d, u16 addr,
const void *buf, const int len)
{
- return d->phys->write_block(d->phys, addr, buf, len);
+ return d->xport->write_block(d->xport, addr, buf, len);
}
-int rmi_register_physical_device(struct rmi_phys_device *phys);
-void rmi_unregister_physical_device(struct rmi_phys_device *phys);
+int rmi_register_transport_device(struct rmi_transport_device *xport);
+void rmi_unregister_transport_device(struct rmi_transport_device *xport);
int rmi_for_each_dev(void *data, int (*func)(struct device *dev, void *data));
/**
- * module_rmi_driver() - Helper macro for registering a function driver
- * @__rmi_driver: rmi_function_handler struct
+ * module_rmi_function_driver() - Helper macro for registering a function driver
+ * @__rmi_driver: rmi_function_driver struct
*
- * Helper macro for RMI4 function drivers which do not do anything special
- * in module init/exit. This eliminates a lot of boilerplate. Each module
+ * Helper macro for RMI4 function drivers which do not do anything special in
+ * module init/exit. This eliminates a lot of boilerplate. Each module
* may only use this macro once, and calling it replaces module_init()
* and module_exit().
*/
-#define module_rmi_driver(__rmi_driver) \
+#define module_rmi_function_driver(__rmi_driver) \
module_driver(__rmi_driver, \
- rmi_register_function_handler, \
- rmi_unregister_function_handler)
-
-
-extern struct bus_type rmi_bus_type;
+ rmi_register_function_driver, \
+ rmi_unregister_function_driver)
#endif
diff --git a/drivers/input/rmi4/rmi_control.h b/drivers/input/rmi4/rmi_control.h
new file mode 100644
index 0000000..f8b616e
--- /dev/null
+++ b/drivers/input/rmi4/rmi_control.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2013 Synaptics Incorporated
+ *
+ * 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.
+ */
+
+#ifndef RMI_CONTROL_H
+#define RMI_CONTROL_H
+
+#include <linux/device.h>
+#include <linux/list.h>
+
+
+#define GROUP(_attrs) { \
+ .attrs = _attrs, \
+}
+
+#define attrify(nm) (&dev_attr_##nm.attr)
+
+struct rmi_control_handler_data {
+ struct device *dev;
+ struct list_head list;
+};
+
+/** Information relating to control/debug handling implementations.
+ *
+ * @name - useful for diagnostics
+ * @dev_type - the type of device the handler is interested in.
+ * @function_id - the RMI4 function ID it is interested in (ignored if 0 or
+ * dev_type == rmi_device_type);
+ * @attach - called if a device appears on the bus that matches the parameters
+ * of this handler.
+ * @remove - called when the device disappears from the bus.
+ *
+ * @notifier - used by the control/debug system to accept notifications for
+ * this handler.
+ * @list - used by the control/debug system to keep track of handlers.
+ */
+struct rmi_control_handler {
+ char name[32];
+ struct device_type *dev_type;
+ u8 function_id;
+
+ struct rmi_control_handler_data * (*attach) (struct device *dev,
+ void *data);
+ int (*remove) (struct rmi_control_handler_data *hdata);
+
+ struct notifier_block notifier;
+ struct list_head list;
+};
+
+
+int rmi_register_control_handler(struct rmi_control_handler *handler);
+void rmi_unregister_control_handler(struct rmi_control_handler *handler);
+
+#endif
diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c
index 5cf7b33..cafe2dc 100644
--- a/drivers/input/rmi4/rmi_driver.c
+++ b/drivers/input/rmi4/rmi_driver.c
@@ -4,9 +4,10 @@
*
* This driver provides the core support for a single RMI4-based device.
*
- * The RMI4 specification can be found here:
- *
- * http://www.synaptics.com/sites/default/files/511-000136-01-Rev-E-RMI4%20Intrfacing%20Guide.pdf
+ * The RMI4 specification can be found here (URL split after files/ for
+ * style reasons):
+ * http://www.synaptics.com/sites/default/files/
+ * 511-000136-01-Rev-E-RMI4%20Intrfacing%20Guide.pdf
*
* 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
@@ -27,75 +28,31 @@
#include <linux/rmi.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
-#include <uapi/linux/input.h>
+
#include "rmi_bus.h"
#include "rmi_driver.h"
+#include "rmi_f01.h"
#define HAS_NONSTANDARD_PDT_MASK 0x40
#define RMI4_MAX_PAGE 0xff
#define RMI4_PAGE_SIZE 0x100
-#define RMI_DEVICE_RESET_CMD 0x01
-#define DEFAULT_RESET_DELAY_MS 100
-
#define DEFAULT_POLL_INTERVAL_MS 13
#define IRQ_DEBUG(data) (IS_ENABLED(CONFIG_RMI4_DEBUG) && data->irq_debug)
-#ifdef CONFIG_RMI4_DEBUG
-static void rmi_driver_setup_debugfs(struct rmi_device *rmi_dev)
-{
- struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
- struct rmi_phys_info *info = &rmi_dev->phys->info;
-
- if (!rmi_dev->debugfs_root)
- return;
-
- if (!debugfs_create_u32_array("transport_stats", RMI_RO_ATTR,
- rmi_dev->debugfs_root,
- (u32 *)&info->tx_count, 6))
- dev_warn(&rmi_dev->dev,
- "Failed to create debugfs transport_stats\n");
-
- if (!debugfs_create_bool("irq_debug", RMI_RW_ATTR,
- rmi_dev->debugfs_root,
- &data->irq_debug))
- dev_warn(&rmi_dev->dev, "Failed to create debugfs irq_debug\n");
-
- if (!debugfs_create_u32("attn_count", RMI_RO_ATTR,
- rmi_dev->debugfs_root,
- &data->attn_count))
- dev_warn(&rmi_dev->dev,
- "Failed to create debugfs attn_count\n");
-}
-
-static void rmi_driver_teardown_debugfs(struct rmi_device *rmi_dev)
-{
- debugfs_remove_recursive(rmi_dev->debugfs_root);
-}
-
-#else
-static inline void rmi_driver_setup_debugfs(struct rmi_device *rmi_dev)
-{
-}
-
-static inline rmi_driver_teardown_debugfs(struct rmi_device *rmi_dev)
-{
-}
-#endif
-
-static irqreturn_t rmi_irq_thread(int irq, void *p)
+static irqreturn_t rmi_irq_thread(int irq, void *ptr)
{
- struct rmi_phys_device *phys = p;
- struct rmi_device *rmi_dev = phys->rmi_dev;
+ struct rmi_transport_device *xport = ptr;
+ struct rmi_device *rmi_dev = xport->rmi_dev;
struct rmi_driver *driver = rmi_dev->driver;
- struct rmi_device_platform_data *pdata = phys->dev->platform_data;
+ struct rmi_device_platform_data *pdata = xport->dev->platform_data;
struct rmi_driver_data *data;
data = dev_get_drvdata(&rmi_dev->dev);
if (IRQ_DEBUG(data))
- dev_dbg(phys->dev, "ATTN gpio, value: %d.\n",
+ dev_dbg(xport->dev, "ATTN gpio, value: %d.\n",
gpio_get_value(pdata->attn_gpio));
if (gpio_get_value(pdata->attn_gpio) == pdata->attn_polarity) {
@@ -137,7 +94,6 @@ static int enable_polling(struct rmi_device *rmi_dev)
{
struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
- dev_dbg(&rmi_dev->dev, "Polling enabled.\n");
INIT_WORK(&data->poll_work, rmi_poll_work);
hrtimer_init(&data->poll_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
data->poll_timer.function = rmi_poll_timer;
@@ -150,7 +106,6 @@ static void disable_polling(struct rmi_device *rmi_dev)
{
struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
- dev_dbg(&rmi_dev->dev, "Polling disabled.\n");
hrtimer_cancel(&data->poll_timer);
cancel_work_sync(&data->poll_work);
}
@@ -165,12 +120,12 @@ static void disable_sensor(struct rmi_device *rmi_dev)
if (!data->irq)
disable_polling(rmi_dev);
- if (rmi_dev->phys->disable_device)
- rmi_dev->phys->disable_device(rmi_dev->phys);
+ if (rmi_dev->xport->disable_device)
+ rmi_dev->xport->disable_device(rmi_dev->xport);
if (data->irq) {
disable_irq(data->irq);
- free_irq(data->irq, rmi_dev->phys);
+ free_irq(data->irq, rmi_dev->xport);
}
data->enabled = false;
@@ -179,27 +134,28 @@ static void disable_sensor(struct rmi_device *rmi_dev)
static int enable_sensor(struct rmi_device *rmi_dev)
{
struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
- struct rmi_phys_device *rmi_phys;
+ struct rmi_transport_device *rmi_transport;
int retval = 0;
struct rmi_device_platform_data *pdata = to_rmi_platform_data(rmi_dev);
if (data->enabled)
return 0;
- if (rmi_dev->phys->enable_device) {
- retval = rmi_dev->phys->enable_device(rmi_dev->phys);
+ if (rmi_dev->xport->enable_device) {
+ retval = rmi_dev->xport->enable_device(rmi_dev->xport);
if (retval)
return retval;
}
- rmi_phys = rmi_dev->phys;
+ rmi_transport = rmi_dev->xport;
if (data->irq) {
retval = request_threaded_irq(data->irq,
- rmi_phys->hard_irq ? rmi_phys->hard_irq : NULL,
- rmi_phys->irq_thread ?
- rmi_phys->irq_thread : rmi_irq_thread,
- data->irq_flags,
- dev_name(&rmi_dev->dev), rmi_phys);
+ rmi_transport->hard_irq ?
+ rmi_transport->hard_irq : NULL,
+ rmi_transport->irq_thread ?
+ rmi_transport->irq_thread : rmi_irq_thread,
+ data->irq_flags,
+ dev_name(&rmi_dev->dev), rmi_transport);
if (retval)
return retval;
} else {
@@ -210,155 +166,39 @@ static int enable_sensor(struct rmi_device *rmi_dev)
data->enabled = true;
- if (!pdata->level_triggered &&
+ if (pdata->attn_gpio && !pdata->level_triggered &&
gpio_get_value(pdata->attn_gpio) == pdata->attn_polarity)
retval = process_interrupt_requests(rmi_dev);
return retval;
}
-/* sysfs show and store fns for driver attributes */
-
-static ssize_t rmi_driver_bsr_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct rmi_device *rmi_dev;
- struct rmi_driver_data *data;
- rmi_dev = to_rmi_device(dev);
- data = dev_get_drvdata(&rmi_dev->dev);
-
- return snprintf(buf, PAGE_SIZE, "%u\n", data->bsr);
-}
-
-static ssize_t rmi_driver_bsr_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- int retval;
- unsigned long val;
- struct rmi_device *rmi_dev;
- struct rmi_driver_data *data;
-
- rmi_dev = to_rmi_device(dev);
- data = dev_get_drvdata(&rmi_dev->dev);
-
- /* need to convert the string data to an actual value */
- retval = strict_strtoul(buf, 10, &val);
- if (retval < 0 || val > 255) {
- dev_err(dev, "Invalid value '%s' written to BSR.\n", buf);
- return -EINVAL;
- }
-
- retval = rmi_write(rmi_dev, BSR_LOCATION, (u8)val);
- if (retval < 0) {
- dev_err(dev, "%s : failed to write bsr %lu to %#06x\n",
- __func__, val, BSR_LOCATION);
- return retval;
- }
-
- data->bsr = val;
-
- return count;
-}
-
-static DEVICE_ATTR(bsr, RMI_RW_ATTR, rmi_driver_bsr_show, rmi_driver_bsr_store);
-
-static ssize_t rmi_driver_enabled_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct rmi_device *rmi_dev = to_rmi_device(dev);
- struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
-
- return snprintf(buf, PAGE_SIZE, "%u\n", data->enabled);
-}
-
-static ssize_t rmi_driver_enabled_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct rmi_device *rmi_dev = to_rmi_device(dev);
- int retval;
- int new_value;
-
- if (sysfs_streq(buf, "0"))
- new_value = false;
- else if (sysfs_streq(buf, "1"))
- new_value = true;
- else
- return -EINVAL;
-
- if (new_value) {
- retval = enable_sensor(rmi_dev);
- if (retval) {
- dev_err(dev, "Failed to enable sensor, code=%d.\n",
- retval);
- return -EIO;
- }
- } else {
- disable_sensor(rmi_dev);
- }
-
- return count;
-}
-
-/** This sysfs attribute is deprecated, and will be removed in a future release.
- */
-static DEVICE_ATTR(enabled, RMI_RW_ATTR,
- rmi_driver_enabled_show, rmi_driver_enabled_store);
-
-static umode_t rmi_driver_attr_visible(struct kobject *kobj,
- struct attribute *attr, int n)
-{
- struct device *dev = kobj_to_dev(kobj);
- struct rmi_device *rmi_dev = to_rmi_device(dev);
- struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
- umode_t mode = attr->mode;
-
- if (attr == &dev_attr_bsr.attr) {
- if (!data->pdt_props.has_bsr)
- mode = 0;
- }
-
- return mode;
-}
-
-static struct attribute *rmi_driver_attrs[] = {
- &dev_attr_bsr.attr,
- &dev_attr_enabled.attr,
- NULL
-};
-
-static struct attribute_group rmi_driver_attr_group = {
- .is_visible = rmi_driver_attr_visible,
- .attrs = rmi_driver_attrs,
-};
-
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);
- data->f01_container = NULL;
+ data->f01_dev = NULL;
- /* Doing it in the reverse order so F01 will be removed last */
+ /* Do this in reverse order so F01 will be removed last. */
list_for_each_entry_safe_reverse(fn, tmp,
- &data->function_list, node) {
+ &data->function_list, node) {
list_del(&fn->node);
- rmi_unregister_function(fn);
+ rmi_unregister_function_dev(fn);
}
}
static int reset_one_function(struct rmi_function *fn)
{
- struct rmi_function_handler *fh;
+ struct rmi_function_driver *fn_drv;
int retval = 0;
if (!fn || !fn->dev.driver)
return 0;
- fh = to_rmi_function_handler(fn->dev.driver);
- if (fh->reset) {
- retval = fh->reset(fn);
+ fn_drv = to_rmi_function_driver(fn->dev.driver);
+ if (fn_drv->reset) {
+ retval = fn_drv->reset(fn);
if (retval < 0)
dev_err(&fn->dev, "Reset failed with code %d.\n",
retval);
@@ -369,15 +209,15 @@ static int reset_one_function(struct rmi_function *fn)
static int configure_one_function(struct rmi_function *fn)
{
- struct rmi_function_handler *fh;
+ struct rmi_function_driver *fn_drv;
int retval = 0;
if (!fn || !fn->dev.driver)
return 0;
- fh = to_rmi_function_handler(fn->dev.driver);
- if (fh->config) {
- retval = fh->config(fn);
+ fn_drv = to_rmi_function_driver(fn->dev.driver);
+ if (fn_drv->config) {
+ retval = fn_drv->config(fn);
if (retval < 0)
dev_err(&fn->dev, "Config failed with code %d.\n",
retval);
@@ -392,6 +232,9 @@ static int rmi_driver_process_reset_requests(struct rmi_device *rmi_dev)
struct rmi_function *entry;
int retval;
+ if (list_empty(&data->function_list))
+ return 0;
+
list_for_each_entry(entry, &data->function_list, node) {
retval = reset_one_function(entry);
if (retval < 0)
@@ -407,6 +250,9 @@ static int rmi_driver_process_config_requests(struct rmi_device *rmi_dev)
struct rmi_function *entry;
int retval;
+ if (list_empty(&data->function_list))
+ return 0;
+
list_for_each_entry(entry, &data->function_list, node) {
retval = configure_one_function(entry);
if (retval < 0)
@@ -419,18 +265,18 @@ static int rmi_driver_process_config_requests(struct rmi_device *rmi_dev)
static void process_one_interrupt(struct rmi_function *fn,
unsigned long *irq_status, struct rmi_driver_data *data)
{
- struct rmi_function_handler *fh;
+ struct rmi_function_driver *fn_drv;
DECLARE_BITMAP(irq_bits, data->num_of_irq_regs);
if (!fn || !fn->dev.driver)
return;
- fh = to_rmi_function_handler(fn->dev.driver);
- if (fn->irq_mask && fh->attention) {
+ fn_drv = to_rmi_function_driver(fn->dev.driver);
+ if (fn->irq_mask && fn_drv->attention) {
bitmap_and(irq_bits, irq_status, fn->irq_mask,
data->irq_count);
if (!bitmap_empty(irq_bits, data->irq_count))
- fh->attention(fn, irq_bits);
+ fn_drv->attention(fn, irq_bits);
}
}
@@ -442,7 +288,7 @@ static int process_interrupt_requests(struct rmi_device *rmi_dev)
int error;
error = rmi_read_block(rmi_dev,
- data->f01_container->fd.data_base_addr + 1,
+ data->f01_dev->fd.data_base_addr + 1,
data->irq_status, data->num_of_irq_regs);
if (error < 0) {
dev_err(dev, "Failed to read irqs, code=%d\n", error);
@@ -466,8 +312,7 @@ static int process_interrupt_requests(struct rmi_device *rmi_dev)
*/
list_for_each_entry(entry, &data->function_list, node) {
if (entry->irq_mask)
- process_one_interrupt(entry, data->irq_status,
- data);
+ process_one_interrupt(entry, data->irq_status, data);
}
return 0;
@@ -483,9 +328,12 @@ static int process_interrupt_requests(struct rmi_device *rmi_dev)
static int rmi_driver_set_input_params(struct rmi_device *rmi_dev,
struct input_dev *input)
{
- // FIXME: set up parent
+ struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
+
input->name = SYNAPTICS_INPUT_DEVICE_NAME;
input->id.vendor = SYNAPTICS_VENDOR_ID;
+ input->id.product = data->board;
+ input->id.version = data->rev;
input->id.bustype = BUS_RMI;
return 0;
}
@@ -506,7 +354,7 @@ static int rmi_driver_irq_save(struct rmi_device *rmi_dev,
if (!data->irq_stored) {
/* Save current enabled interrupts */
retval = rmi_read_block(rmi_dev,
- data->f01_container->fd.control_base_addr+1,
+ data->f01_dev->fd.control_base_addr+1,
data->irq_mask_store, data->num_of_irq_regs);
if (retval < 0) {
dev_err(dev, "%s: Failed to read enabled interrupts!",
@@ -520,7 +368,7 @@ static int rmi_driver_irq_save(struct rmi_device *rmi_dev,
* to identify them.
*/
retval = rmi_write_block(rmi_dev,
- data->f01_container->fd.control_base_addr+1,
+ data->f01_dev->fd.control_base_addr+1,
new_ints, data->num_of_irq_regs);
if (retval < 0) {
dev_err(dev, "%s: Failed to change enabled interrupts!",
@@ -549,7 +397,7 @@ static int rmi_driver_irq_restore(struct rmi_device *rmi_dev)
if (data->irq_stored) {
retval = rmi_write_block(rmi_dev,
- data->f01_container->fd.control_base_addr+1,
+ data->f01_dev->fd.control_base_addr+1,
data->irq_mask_store, data->num_of_irq_regs);
if (retval < 0) {
dev_err(dev, "%s: Failed to write enabled interupts!",
@@ -578,7 +426,7 @@ static int rmi_driver_irq_handler(struct rmi_device *rmi_dev, int irq)
/* Can get called before the driver is fully ready to deal with
* interrupts.
*/
- if (!data || !data->f01_container) {
+ if (!data || !data->f01_dev) {
dev_dbg(&rmi_dev->dev,
"Not ready to handle interrupts yet!\n");
return 0;
@@ -595,9 +443,8 @@ static int rmi_driver_reset_handler(struct rmi_device *rmi_dev)
/* Can get called before the driver is fully ready to deal with
* this situation.
*/
- if (!data || !data->f01_container) {
- dev_warn(&rmi_dev->dev,
- "Not ready to handle reset yet!\n");
+ if (!data || !data->f01_dev) {
+ dev_warn(&rmi_dev->dev, "Not ready to handle reset yet!\n");
return 0;
}
@@ -632,17 +479,42 @@ int rmi_driver_irq_get_mask(struct rmi_device *rmi_dev,
BITS_TO_LONGS(data->irq_count)*sizeof(unsigned long),
GFP_KERNEL);
- if (fn->irq_mask) {
- for (i = 0; i < fn->num_of_irqs; i++)
- set_bit(fn->irq_pos+i, fn->irq_mask);
- return 0;
- } else
+ if (!fn->irq_mask)
return -ENOMEM;
+
+ for (i = 0; i < fn->num_of_irqs; i++)
+ set_bit(fn->irq_pos+i, fn->irq_mask);
+ return 0;
}
-static void rmi_driver_copy_pdt_to_fd(struct pdt_entry *pdt,
- struct rmi_function_descriptor *fd,
- u16 page_start)
+int rmi_read_pdt_entry(struct rmi_device *rmi_dev, struct pdt_entry *entry,
+ u16 pdt_address)
+{
+ u8 buf[RMI_PDT_ENTRY_SIZE];
+ int error;
+
+ error = rmi_read_block(rmi_dev, pdt_address, buf, RMI_PDT_ENTRY_SIZE);
+ if (error < 0) {
+ dev_err(&rmi_dev->dev, "Read PDT entry at %#06x failed, code: %d.\n",
+ pdt_address, error);
+ return error;
+ }
+
+ entry->query_base_addr = buf[0];
+ entry->command_base_addr = buf[1];
+ entry->control_base_addr = buf[2];
+ entry->data_base_addr = buf[3];
+ entry->interrupt_source_count = buf[4] & RMI_PDT_INT_SOURCE_COUNT_MASK;
+ entry->function_version = (buf[4] & RMI_PDT_FUNCTION_VERSION_MASK) >> 5;
+ entry->function_number = buf[5];
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rmi_read_pdt_entry);
+
+static void copy_pdt_entry_to_fd(struct pdt_entry *pdt,
+ struct rmi_function_descriptor *fd,
+ u16 page_start)
{
fd->query_base_addr = pdt->query_base_addr + page_start;
fd->command_base_addr = pdt->command_base_addr + page_start;
@@ -653,89 +525,190 @@ static void rmi_driver_copy_pdt_to_fd(struct pdt_entry *pdt,
fd->function_version = pdt->function_version;
}
-static int create_function(struct rmi_device *rmi_dev,
+static int create_function_dev(struct rmi_device *rmi_dev,
struct pdt_entry *pdt,
int *current_irq_count,
u16 page_start)
{
- struct device *dev = &rmi_dev->dev;
struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
- struct rmi_device_platform_data *pdata = to_rmi_platform_data(rmi_dev);
- struct rmi_function *fn;
- int error;
+ struct rmi_function *fn = NULL;
+ int retval = 0;
+ struct device *dev = &rmi_dev->dev;
+ struct rmi_device_platform_data *pdata;
- dev_dbg(dev, "Initializing F%02X for %s.\n",
- pdt->function_number, pdata->sensor_name);
+ pdata = to_rmi_platform_data(rmi_dev);
+
+ dev_dbg(dev, "Initializing F%02X device for %s.\n",
+ pdt->function_number, pdata->sensor_name);
fn = kzalloc(sizeof(struct rmi_function), GFP_KERNEL);
if (!fn) {
- dev_err(dev, "Failed to allocate memory for F%02X\n",
+ dev_err(dev, "Failed to allocate F%02X device.\n",
pdt->function_number);
return -ENOMEM;
}
INIT_LIST_HEAD(&fn->node);
+ copy_pdt_entry_to_fd(pdt, &fn->fd, page_start);
fn->rmi_dev = rmi_dev;
fn->num_of_irqs = pdt->interrupt_source_count;
-
fn->irq_pos = *current_irq_count;
*current_irq_count += fn->num_of_irqs;
- rmi_driver_copy_pdt_to_fd(pdt, &fn->fd, page_start);
+ retval = rmi_driver_irq_get_mask(rmi_dev, fn);
+ if (retval < 0) {
+ dev_err(dev, "%s: Failed to create irq_mask for F%02X.\n",
+ __func__, pdt->function_number);
+ return retval;
+ }
- error = rmi_register_function(fn);
- if (error)
+ retval = rmi_register_function_dev(fn);
+ if (retval < 0) {
+ dev_err(dev, "Failed to register F%02X device.\n",
+ pdt->function_number);
goto err_free_mem;
+ }
- list_add_tail(&fn->node, &data->function_list);
+ /* we need to ensure that F01 is at the head of the list.
+ */
+ if (pdt->function_number == 0x01) {
+ list_add(&fn->node, &data->function_list);
+ data->f01_dev = fn;
+ } else
+ list_add_tail(&fn->node, &data->function_list);
return 0;
-
err_free_mem:
kfree(fn);
- return error;
+ return retval;
}
/*
- * Scan the PDT for F01 so we can force a reset before anything else
- * is done. This forces the sensor into a known state, and also
- * forces application of any pending updates from reflashing the
- * firmware or configuration.
- *
- * At this time, we also reflash the device if (a) in kernel reflashing is
+ * Once we find F01, we need to see if we're in bootloader mode. If we are,
+ * we'll stop scanning the PDT with the current page (usually 0x00 in that
+ * case).
+ */
+static void check_bootloader_mode(struct rmi_device *rmi_dev,
+ struct pdt_entry *pdt,
+ u16 page_start)
+{
+ struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
+ u8 device_status;
+ int retval = 0;
+
+ retval = rmi_read(rmi_dev, pdt->data_base_addr + page_start,
+ &device_status);
+ if (retval < 0) {
+ dev_err(&rmi_dev->dev, "Failed to read device status.\n");
+ return;
+ }
+ data->f01_bootloader_mode = RMI_F01_STATUS_BOOTLOADER(device_status);
+ if (RMI_F01_STATUS_BOOTLOADER(device_status))
+ dev_warn(&rmi_dev->dev,
+ "WARNING: RMI4 device is in bootloader mode!\n");
+
+}
+
+/*
+ * We also reflash the device if (a) in kernel reflashing is
* enabled, and (b) the reflash module decides it requires reflashing.
*
* We have to do this before actually building the PDT because the reflash
* might cause various registers to move around.
*/
-static int reset_and_reflash(struct rmi_device *rmi_dev)
+static int rmi_device_reflash(struct rmi_device *rmi_dev)
{
struct pdt_entry pdt_entry;
int page;
struct device *dev = &rmi_dev->dev;
- bool done = false;
+ bool done;
bool has_f01 = false;
+ bool has_f34 = false;
+ struct pdt_entry f34_pdt, f01_pdt;
int i;
int retval;
- const struct rmi_device_platform_data *pdata = to_rmi_platform_data(rmi_dev);
-
- dev_dbg(dev, "Initial reset.\n");
+ struct rmi_device_platform_data *pdata;
+ struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
- for (page = 0; (page <= RMI4_MAX_PAGE) && !done; page++) {
+ pdata = to_rmi_platform_data(rmi_dev);
+ data->f01_bootloader_mode = false;
+ for (page = 0; (page <= RMI4_MAX_PAGE); page++) {
u16 page_start = RMI4_PAGE_SIZE * page;
u16 pdt_start = page_start + PDT_START_SCAN_LOCATION;
u16 pdt_end = page_start + PDT_END_SCAN_LOCATION;
-
done = true;
- for (i = pdt_start; i >= pdt_end; i -= sizeof(pdt_entry)) {
- retval = rmi_read_block(rmi_dev, i, &pdt_entry,
- sizeof(pdt_entry));
- if (retval != sizeof(pdt_entry)) {
- dev_err(dev, "Read PDT entry at %#06x failed, code = %d.\n",
- i, retval);
+ for (i = pdt_start; i >= pdt_end ; i -= RMI_PDT_ENTRY_SIZE) {
+ retval = rmi_read_pdt_entry(rmi_dev, &pdt_entry, i);
+ if (retval < 0)
return retval;
+
+ if (RMI4_END_OF_PDT(pdt_entry.function_number))
+ break;
+ done = false;
+ if (pdt_entry.function_number == 0x01) {
+ memcpy(&f01_pdt, &pdt_entry, sizeof(pdt_entry));
+ has_f01 = true;
+ check_bootloader_mode(rmi_dev, &pdt_entry,
+ page_start);
+ } else if (pdt_entry.function_number == 0x34) {
+ memcpy(&f34_pdt, &pdt_entry, sizeof(pdt_entry));
+ has_f34 = true;
+ }
+
+ if (has_f01 && has_f34) {
+ done = true;
+ break;
}
+ }
+
+ if (data->f01_bootloader_mode || done)
+ break;
+ }
+
+ if (!has_f01) {
+ dev_warn(dev, "WARNING: Failed to find F01 for initial reflash.\n");
+ return -ENODEV;
+ }
+
+#ifdef CONFIG_RMI4_FWLIB
+ if (has_f34)
+ rmi4_fw_update(rmi_dev, &f01_pdt, &f34_pdt);
+ else
+ dev_warn(dev, "WARNING: No F34 , firmware update will not be done.\n");
+#endif
+
+ return 0;
+}
+
+/*
+ * Scan the PDT for F01 so we can force a reset before anything else
+ * is done. This forces the sensor into a known state, and also
+ * forces application of any pending updates from reflashing the
+ * firmware or configuration.
+ *
+ */
+static int rmi_device_reset(struct rmi_device *rmi_dev)
+{
+ struct pdt_entry pdt_entry;
+ int page;
+ struct device *dev = &rmi_dev->dev;
+ int i;
+ int error;
+ bool done = false;
+ struct rmi_device_platform_data *pdata;
+
+ pdata = to_rmi_platform_data(rmi_dev);
+ for (page = 0; (page <= RMI4_MAX_PAGE) && !done; page++) {
+ u16 page_start = RMI4_PAGE_SIZE * page;
+ u16 pdt_start = page_start + PDT_START_SCAN_LOCATION;
+ u16 pdt_end = page_start + PDT_END_SCAN_LOCATION;
+ done = true;
+
+ for (i = pdt_start; i >= pdt_end; i -= RMI_PDT_ENTRY_SIZE) {
+ error = rmi_read_pdt_entry(rmi_dev, &pdt_entry, i);
+ if (error < 0)
+ return error;
if (RMI4_END_OF_PDT(pdt_entry.function_number))
break;
@@ -744,28 +717,64 @@ static int reset_and_reflash(struct rmi_device *rmi_dev)
if (pdt_entry.function_number == 0x01) {
u16 cmd_addr = page_start +
pdt_entry.command_base_addr;
- u8 cmd_buf = RMI_DEVICE_RESET_CMD;
- retval = rmi_write_block(rmi_dev, cmd_addr,
- &cmd_buf, 1);
- if (retval < 0) {
+ u8 cmd = RMI_F01_CMD_DEVICE_RESET;
+ error = rmi_write_block(rmi_dev, cmd_addr,
+ &cmd, sizeof(cmd));
+ if (error < 0) {
dev_err(dev, "Initial reset failed. Code = %d.\n",
- retval);
- return retval;
+ error);
+ return error;
}
- mdelay(pdata->reset_delay_ms);
- done = true;
- has_f01 = true;
- break;
+ msleep(pdata->reset_delay_ms);
+ return 0;
}
}
}
- if (!has_f01) {
- dev_warn(dev, "WARNING: Failed to find F01 for initial reset.\n");
- return -ENODEV;
+ return -ENODEV;
+}
+
+static int rmi_count_irqs(struct rmi_device *rmi_dev)
+{
+ struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
+ struct pdt_entry pdt_entry;
+ int page;
+ int irq_count = 0;
+ bool done = false;
+ int i;
+ int retval;
+
+ mutex_lock(&data->pdt_mutex);
+
+ for (page = 0; (page <= RMI4_MAX_PAGE) && !done; page++) {
+ u16 page_start = RMI4_PAGE_SIZE * page;
+ u16 pdt_start = page_start + PDT_START_SCAN_LOCATION;
+ u16 pdt_end = page_start + PDT_END_SCAN_LOCATION;
+
+ done = true;
+ for (i = pdt_start; i >= pdt_end; i -= RMI_PDT_ENTRY_SIZE) {
+ retval = rmi_read_pdt_entry(rmi_dev, &pdt_entry, i);
+ if (retval < 0)
+ goto error_exit;
+
+ if (RMI4_END_OF_PDT(pdt_entry.function_number))
+ break;
+ irq_count += pdt_entry.interrupt_source_count;
+ done = false;
+
+ if (pdt_entry.function_number == 0x01)
+ check_bootloader_mode(rmi_dev, &pdt_entry,
+ page_start);
+ }
+ done = done || data->f01_bootloader_mode;
}
+ data->irq_count = irq_count;
+ data->num_of_irq_regs = (irq_count + 7) / 8;
+ retval = 0;
- return 0;
+error_exit:
+ mutex_unlock(&data->pdt_mutex);
+ return retval;
}
static int rmi_scan_pdt(struct rmi_device *rmi_dev)
@@ -790,33 +799,30 @@ static int rmi_scan_pdt(struct rmi_device *rmi_dev)
u16 pdt_end = page_start + PDT_END_SCAN_LOCATION;
done = true;
- for (i = pdt_start; i >= pdt_end; i -= sizeof(pdt_entry)) {
- retval = rmi_read_block(rmi_dev, i, &pdt_entry,
- sizeof(pdt_entry));
- if (retval != sizeof(pdt_entry)) {
- dev_err(dev, "Read of PDT entry at %#06x failed.\n",
- i);
+ for (i = pdt_start; i >= pdt_end; i -= RMI_PDT_ENTRY_SIZE) {
+ retval = rmi_read_pdt_entry(rmi_dev, &pdt_entry, i);
+ if (retval < 0)
goto error_exit;
- }
if (RMI4_END_OF_PDT(pdt_entry.function_number))
break;
- dev_dbg(dev, "Found F%02X on page %#04x\n",
+ dev_dbg(dev, "Found F%02X on page %#04x.\n",
pdt_entry.function_number, page);
done = false;
- // XXX need to make sure we create F01 first...
- retval = create_function(rmi_dev,
- &pdt_entry, &irq_count, page_start);
+ if (pdt_entry.function_number == 0x01)
+ check_bootloader_mode(rmi_dev, &pdt_entry,
+ page_start);
+
+ retval = create_function_dev(rmi_dev,
+ &pdt_entry, &irq_count, page_start);
if (retval)
goto error_exit;
}
done = done || data->f01_bootloader_mode;
}
- data->irq_count = irq_count;
- data->num_of_irq_regs = (irq_count + 7) / 8;
dev_dbg(dev, "%s: Done with PDT scan.\n", __func__);
retval = 0;
@@ -825,8 +831,6 @@ error_exit:
return retval;
}
-#if 0
-// XXX is this crap needed with F01 always present?
static int f01_notifier_call(struct notifier_block *nb,
unsigned long action, void *data)
{
@@ -842,11 +846,9 @@ static int f01_notifier_call(struct notifier_block *nb,
switch (action) {
case BUS_NOTIFY_BOUND_DRIVER:
- dev_dbg(dev, "%s: F01 driver bound.\n", __func__);
enable_sensor(fn->rmi_dev);
break;
case BUS_NOTIFY_UNBIND_DRIVER:
- dev_dbg(dev, "%s: F01 driver going away.\n", __func__);
disable_sensor(fn->rmi_dev);
break;
}
@@ -856,16 +858,13 @@ static int f01_notifier_call(struct notifier_block *nb,
static struct notifier_block rmi_bus_notifier = {
.notifier_call = f01_notifier_call,
};
-#endif
#ifdef CONFIG_PM_SLEEP
static int rmi_driver_suspend(struct device *dev)
{
- struct rmi_driver_data *data;
- int retval = 0;
struct rmi_device *rmi_dev = to_rmi_device(dev);
-
- data = dev_get_drvdata(&rmi_dev->dev);
+ struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
+ int retval = 0;
mutex_lock(&data->suspend_mutex);
@@ -877,13 +876,6 @@ static int rmi_driver_suspend(struct device *dev)
disable_sensor(rmi_dev);
-#if 0
- /** Do it backwards so F01 comes last. */
- list_for_each_entry_reverse(entry, &data->function_list, node)
- if (suspend_one_device(entry) < 0)
- goto exit;
-#endif
-
if (data->post_suspend)
retval = data->post_suspend(data->pm_data);
@@ -894,11 +886,10 @@ exit:
static int rmi_driver_resume(struct device *dev)
{
- struct rmi_driver_data *data;
- int retval = 0;
struct rmi_device *rmi_dev = to_rmi_device(dev);
+ struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
+ int retval = 0;
- data = dev_get_drvdata(&rmi_dev->dev);
mutex_lock(&data->suspend_mutex);
if (data->pre_resume) {
@@ -907,14 +898,6 @@ static int rmi_driver_resume(struct device *dev)
goto exit;
}
-#if 0
- /** Do it forwards, so F01 comes first. */
- list_for_each_entry(entry, &data->function_list, node) {
- if (resume_one_device(entry) < 0)
- goto exit;
- }
-#endif
-
retval = enable_sensor(rmi_dev);
if (retval)
goto exit;
@@ -923,47 +906,38 @@ static int rmi_driver_resume(struct device *dev)
if (data->post_resume) {
retval = data->post_resume(data->pm_data);
if (retval)
- goto exit;
+ dev_err(&rmi_dev->dev, "Post resume failed with %d.\n",
+ retval);
}
- data->suspended = false;
exit:
mutex_unlock(&data->suspend_mutex);
return retval;
}
-#endif /* CONFIG_PM */
-static SIMPLE_DEV_PM_OPS(rmi_driver_pm, rmi_driver_suspend, rmi_driver_resume);
+#endif /* CONFIG_PM_SLEEP */
-static int rmi_driver_remove(struct device *dev)
+static int rmi_driver_remove(struct rmi_device *rmi_dev)
{
- struct rmi_device *rmi_dev = to_rmi_device(dev);
-
- rmi_driver_teardown_debugfs(rmi_dev);
- sysfs_remove_group(&dev->kobj, &rmi_driver_attr_group);
-
disable_sensor(rmi_dev);
- rmi_free_function_list(rmi_dev);
+ rmi_free_function_list(rmi_dev);
return 0;
}
+static const char *GPIO_LABEL = "attn";
+
static int rmi_driver_probe(struct device *dev)
{
struct rmi_driver *rmi_driver;
struct rmi_driver_data *data = NULL;
- struct rmi_function *fn;
struct rmi_device_platform_data *pdata;
int retval = 0;
struct rmi_device *rmi_dev;
- dev_dbg(dev, "%s: Starting probe.\n", __func__);
-
- if (!rmi_is_physical_device(dev)) {
- dev_dbg(dev, "Not a sensor device.\n");
+ if (!rmi_is_physical_device(dev))
return -ENODEV;
- }
rmi_dev = to_rmi_device(dev);
rmi_driver = to_rmi_driver(dev->driver);
@@ -998,31 +972,13 @@ static int rmi_driver_probe(struct device *dev)
*/
if (!pdata->reset_delay_ms)
pdata->reset_delay_ms = DEFAULT_RESET_DELAY_MS;
- retval = reset_and_reflash(rmi_dev);
+ retval = rmi_device_reset(rmi_dev);
if (retval)
dev_warn(dev, "RMI initial reset failed! Continuing in spite of this.\n");
- retval = rmi_scan_pdt(rmi_dev);
- if (retval) {
- dev_err(dev, "PDT scan for %s failed with code %d.\n",
- pdata->sensor_name, retval);
- goto err_free_data;
- }
-
- if (!data->f01_container) {
- dev_err(dev, "missing F01 container!\n");
- retval = -EINVAL;
- goto err_free_data;
- }
-
- list_for_each_entry(fn, &data->function_list, node) {
- retval = rmi_driver_irq_get_mask(rmi_dev, fn);
- if (retval < 0) {
- dev_err(dev, "%s: Failed to create irq_mask.\n",
- __func__);
- goto err_free_data;
- }
- }
+ retval = rmi_device_reflash(rmi_dev);
+ if (retval)
+ dev_warn(dev, "RMI reflash failed! Continuing in spite of this.\n");
retval = rmi_read(rmi_dev, PDT_PROPERTIES_LOCATION, &data->pdt_props);
if (retval < 0) {
@@ -1033,6 +989,31 @@ static int rmi_driver_probe(struct device *dev)
PDT_PROPERTIES_LOCATION);
}
+ if (pdata->attn_gpio) {
+ data->irq = gpio_to_irq(pdata->attn_gpio);
+ if (pdata->level_triggered) {
+ data->irq_flags = IRQF_ONESHOT |
+ ((pdata->attn_polarity == RMI_ATTN_ACTIVE_HIGH)
+ ? IRQF_TRIGGER_HIGH : IRQF_TRIGGER_LOW);
+ } else {
+ data->irq_flags =
+ (pdata->attn_polarity == RMI_ATTN_ACTIVE_HIGH)
+ ? IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING;
+ }
+ dev_dbg(dev, "Mapped IRQ %d for GPIO %d.\n",
+ data->irq, pdata->attn_gpio);
+ } else
+ data->poll_interval = ktime_set(0,
+ (pdata->poll_interval_ms ? pdata->poll_interval_ms :
+ DEFAULT_POLL_INTERVAL_MS) * 1000 * 1000);
+
+ retval = rmi_count_irqs(rmi_dev);
+ if (retval) {
+ dev_err(dev, "IRQ counting for %s failed with code %d.\n",
+ pdata->sensor_name, retval);
+ goto err_free_data;
+ }
+
mutex_init(&data->irq_mutex);
data->irq_status = devm_kzalloc(dev,
BITS_TO_LONGS(data->irq_count)*sizeof(unsigned long),
@@ -1043,8 +1024,7 @@ static int rmi_driver_probe(struct device *dev)
goto err_free_data;
}
- data->current_irq_mask = devm_kzalloc(dev,
- data->num_of_irq_regs,
+ data->current_irq_mask = devm_kzalloc(dev, data->num_of_irq_regs,
GFP_KERNEL);
if (!data->current_irq_mask) {
dev_err(dev, "Failed to allocate current_irq_mask.\n");
@@ -1052,15 +1032,6 @@ static int rmi_driver_probe(struct device *dev)
goto err_free_data;
}
- 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_free_data;
- }
-
data->irq_mask_store = devm_kzalloc(dev,
BITS_TO_LONGS(data->irq_count)*sizeof(unsigned long),
GFP_KERNEL);
@@ -1069,6 +1040,29 @@ static int rmi_driver_probe(struct device *dev)
retval = -ENOMEM;
goto err_free_data;
}
+
+ retval = rmi_scan_pdt(rmi_dev);
+ if (retval) {
+ dev_err(dev, "PDT scan for %s failed with code %d.\n",
+ pdata->sensor_name, retval);
+ goto err_free_data;
+ }
+
+ if (!data->f01_dev) {
+ dev_err(dev, "missing F01 device!\n");
+ retval = -EINVAL;
+ goto err_free_data;
+ }
+
+ retval = rmi_read_block(rmi_dev,
+ data->f01_dev->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_free_data;
+ }
+
if (IS_ENABLED(CONFIG_PM)) {
data->pm_data = pdata->pm_data;
data->pre_suspend = pdata->pre_suspend;
@@ -1079,50 +1073,32 @@ static int rmi_driver_probe(struct device *dev)
mutex_init(&data->suspend_mutex);
}
- retval = sysfs_create_group(&dev->kobj, &rmi_driver_attr_group);
- if (retval < 0) {
- dev_err(dev, "%s: Failed to create sysfs group\n", __func__);
- goto err_free_data;
- }
-
- rmi_driver_setup_debugfs(rmi_dev);
-
- if (pdata->attn_gpio) {
- data->irq = gpio_to_irq(pdata->attn_gpio);
- if (pdata->level_triggered) {
- data->irq_flags = IRQF_ONESHOT |
- ((pdata->attn_polarity == RMI_ATTN_ACTIVE_HIGH)
- ? IRQF_TRIGGER_HIGH : IRQF_TRIGGER_LOW);
- } else {
- data->irq_flags =
- (pdata->attn_polarity == RMI_ATTN_ACTIVE_HIGH)
- ? IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING;
- }
- } else
- data->poll_interval = ktime_set(0,
- (pdata->poll_interval_ms ? pdata->poll_interval_ms :
- DEFAULT_POLL_INTERVAL_MS) * 1000);
-
- if (data->f01_container->dev.driver) {
+ if (data->f01_dev->dev.driver) {
/* Driver already bound, so enable ATTN now. */
enable_sensor(rmi_dev);
}
if (IS_ENABLED(CONFIG_RMI4_DEV) && pdata->attn_gpio) {
- retval = gpio_export(pdata->attn_gpio, false);
- if (retval) {
- dev_warn(dev, "WARNING: Failed to export ATTN gpio!\n");
- retval = 0;
- } else {
- retval = gpio_export_link(dev,
- "attn", pdata->attn_gpio);
- if (retval) {
- dev_warn(dev,
- "WARNING: Failed to symlink ATTN gpio!\n");
- retval = 0;
- } else {
- dev_info(dev, "Exported ATTN GPIO %d.",
- pdata->attn_gpio);
+ retval = gpio_request(pdata->attn_gpio, GPIO_LABEL);
+ if (retval)
+ dev_warn(dev, "WARNING: Failed to request ATTN gpio %d, code=%d.\n",
+ pdata->attn_gpio, retval);
+ else {
+ retval = gpio_export(pdata->attn_gpio, false);
+ if (retval)
+ dev_warn(dev, "WARNING: Failed to export ATTN gpio %d, code=%d!\n",
+ pdata->attn_gpio, retval);
+ else {
+ retval = gpio_export_link(dev,
+ "attn", pdata->attn_gpio);
+ if (retval) {
+ dev_warn(dev,
+ "WARNING: Failed to symlink ATTN gpio!\n");
+ retval = 0;
+ } else {
+ dev_info(dev, "Exported ATTN GPIO %d.",
+ pdata->attn_gpio);
+ }
}
}
}
@@ -1130,45 +1106,57 @@ static int rmi_driver_probe(struct device *dev)
return 0;
err_free_data:
+ rmi_free_function_list(rmi_dev);
return retval;
}
+static UNIVERSAL_DEV_PM_OPS(rmi_driver_pm, rmi_driver_suspend,
+ rmi_driver_resume, NULL);
+
struct rmi_driver rmi_physical_driver = {
.driver = {
- .owner = THIS_MODULE,
- .name = "rmi_physical",
- .bus = &rmi_bus_type,
- .pm = &rmi_driver_pm,
- .probe = rmi_driver_probe,
- .remove = rmi_driver_remove,
+ .owner = THIS_MODULE,
+ .name = "rmi_physical",
+ .bus = &rmi_bus_type,
+ .pm = &rmi_driver_pm,
+ .probe = rmi_driver_probe,
},
.irq_handler = rmi_driver_irq_handler,
.reset_handler = rmi_driver_reset_handler,
.store_irq_mask = rmi_driver_irq_save,
.restore_irq_mask = rmi_driver_irq_restore,
.set_input_params = rmi_driver_set_input_params,
+ .enable = enable_sensor,
+ .disable = disable_sensor,
+ .remove = rmi_driver_remove,
};
-bool rmi_is_physical_driver(struct device_driver *drv)
+int __init rmi_register_sensor_driver(void)
{
- return drv == &rmi_physical_driver.driver;
-}
-
-int __init rmi_register_physical_driver(void)
-{
- int error;
+ int retval;
- error = driver_register(&rmi_physical_driver.driver);
- if (error) {
+ retval = driver_register(&rmi_physical_driver.driver);
+ if (retval) {
pr_err("%s: driver register failed, code=%d.\n", __func__,
- error);
- return error;
+ retval);
+ return retval;
}
+ /* Ask the bus to let us know when drivers are bound to devices. */
+ retval = bus_register_notifier(&rmi_bus_type, &rmi_bus_notifier);
+ if (retval) {
+ pr_err("%s: failed to register bus notifier, code=%d.\n",
+ __func__, retval);
+ return retval;
+ }
+
+ pr_debug("%s: sensor driver registered.\n", __func__);
+
return 0;
}
-void __exit rmi_unregister_physical_driver(void)
+void __exit rmi_unregister_sensor_driver(void)
{
+ bus_unregister_notifier(&rmi_bus_type, &rmi_bus_notifier);
driver_unregister(&rmi_physical_driver.driver);
}
diff --git a/drivers/input/rmi4/rmi_driver.h b/drivers/input/rmi4/rmi_driver.h
index f8d87e9..c873526 100644
--- a/drivers/input/rmi4/rmi_driver.h
+++ b/drivers/input/rmi4/rmi_driver.h
@@ -13,38 +13,31 @@
#include <linux/ctype.h>
#include <linux/hrtimer.h>
#include <linux/ktime.h>
-#include "rmi_bus.h"
+#include <linux/rmi.h>
-#define RMI_DRIVER_VERSION "1.6"
+#include "rmi_bus.h"
+#include "rmi_version.h"
#define SYNAPTICS_INPUT_DEVICE_NAME "Synaptics RMI4 Touch Sensor"
#define SYNAPTICS_VENDOR_ID 0x06cb
-#define GROUP(_attrs) { \
- .attrs = _attrs, \
-}
-#define attrify(nm) (&dev_attr_##nm.attr)
+#define DEFAULT_RESET_DELAY_MS 100
#define PDT_PROPERTIES_LOCATION 0x00EF
#define BSR_LOCATION 0x00FE
-struct pdt_properties {
- u8 reserved_1:6;
- u8 has_bsr:1;
- u8 reserved_2:1;
-} __attribute__((__packed__));
+#define RMI_PDT_PROPS_HAS_BSR 0x02
struct rmi_driver_data {
struct list_head function_list;
-
struct rmi_device *rmi_dev;
- struct rmi_function *f01_container;
+ struct rmi_function *f01_dev;
bool f01_bootloader_mode;
u32 attn_count;
- u32 irq_debug; /* Should be bool, but debugfs wants u32 */
+ u32 irq_debug;
int irq;
int irq_flags;
int num_of_irq_regs;
@@ -59,11 +52,13 @@ struct rmi_driver_data {
struct hrtimer poll_timer;
struct work_struct poll_work;
ktime_t poll_interval;
-
struct mutex pdt_mutex;
- struct pdt_properties pdt_props;
+ u8 pdt_props;
u8 bsr;
+ int board;
+ int rev;
+
bool enabled;
#ifdef CONFIG_PM
bool suspended;
@@ -76,54 +71,42 @@ struct rmi_driver_data {
int (*post_resume) (const void *pm_data);
#endif
-#ifdef CONFIG_RMI4_DEBUG
- struct dentry *debugfs_delay;
- struct dentry *debugfs_phys;
- struct dentry *debugfs_reg_ctl;
- struct dentry *debugfs_reg;
- struct dentry *debugfs_irq;
- struct dentry *debugfs_attn_count;
- u16 reg_debug_addr;
- u8 reg_debug_size;
-#endif
-
void *data;
};
+
+#define RMI_PDT_ENTRY_SIZE 6
+#define RMI_PDT_FUNCTION_VERSION_MASK 0x60
+#define RMI_PDT_INT_SOURCE_COUNT_MASK 0x07
+
#define PDT_START_SCAN_LOCATION 0x00e9
#define PDT_END_SCAN_LOCATION 0x0005
#define RMI4_END_OF_PDT(id) ((id) == 0x00 || (id) == 0xff)
struct pdt_entry {
- u8 query_base_addr:8;
- u8 command_base_addr:8;
- u8 control_base_addr:8;
- u8 data_base_addr:8;
- u8 interrupt_source_count:3;
- u8 bits3and4:2;
- u8 function_version:2;
- u8 bit7:1;
- u8 function_number:8;
-} __attribute__((__packed__));
-
-static inline void copy_pdt_entry_to_fd(struct pdt_entry *pdt,
- struct rmi_function_descriptor *fd,
- u16 page_start)
-{
- fd->query_base_addr = pdt->query_base_addr + page_start;
- fd->command_base_addr = pdt->command_base_addr + page_start;
- fd->control_base_addr = pdt->control_base_addr + page_start;
- fd->data_base_addr = pdt->data_base_addr + page_start;
- fd->function_number = pdt->function_number;
- fd->interrupt_source_count = pdt->interrupt_source_count;
- fd->function_version = pdt->function_version;
-}
-
-bool rmi_is_physical_driver(struct device_driver *);
-int rmi_register_physical_driver(void);
-void rmi_unregister_physical_driver(void);
-
-int rmi_register_f01_handler(void);
-void rmi_unregister_f01_handler(void);
+ u8 query_base_addr;
+ u8 command_base_addr;
+ u8 control_base_addr;
+ u8 data_base_addr;
+ u8 interrupt_source_count;
+ u8 function_version;
+ u8 function_number;
+};
+
+int rmi_read_pdt_entry(struct rmi_device *rmi_dev, struct pdt_entry *entry,
+ u16 pdt_address);
+
+#ifdef CONFIG_RMI4_FWLIB
+extern void rmi4_fw_update(struct rmi_device *rmi_dev,
+ struct pdt_entry *f01_pdt, struct pdt_entry *f34_pdt);
+#else
+#define rmi4_fw_update(rmi_dev, f01_pdt, f34_pdt) 0
+#endif
+
+extern struct rmi_driver rmi_physical_driver;
+extern struct rmi_function_driver rmi_f01_driver;
+
+int rmi_register_sensor_driver(void);
+void rmi_unregister_sensor_driver(void);
#endif
diff --git a/drivers/input/rmi4/rmi_version.h b/drivers/input/rmi4/rmi_version.h
new file mode 100644
index 0000000..e205627
--- /dev/null
+++ b/drivers/input/rmi4/rmi_version.h
@@ -0,0 +1,16 @@
+#ifndef RMI_VERSION_H
+#define RMI_VERSION_H
+
+#define RMI_VERSION_MAJOR "1"
+#define RMI_VERSION_MINOR "8"
+#define RMI_VERSION_SUBMINOR "7"
+
+#define RMI_VERSION_BRANCH "master"
+#define RMI_EXTRA_NUMBER "1"
+#define RMI_EXTRA_STRING "master.0"
+
+#define RMI_DRIVER_VERSION RMI_VERSION_MAJOR "." \
+ RMI_VERSION_MINOR "." RMI_VERSION_SUBMINOR "-" \
+ RMI_EXTRA_STRING
+
+#endif
^ permalink raw reply related
* [PATCH 02/04] input synaptics-rmi4: I2C transport layer
From: Christopher Heiny @ 2013-11-13 23:39 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Linux Input, Christopher Heiny, Andrew Duggan, Vincent Huang,
Vivian Ly, Daniel Rosenberg, Jean Delvare, Joerie de Gram,
Linus Walleij
In-Reply-To: <1384385972-1686-1-git-send-email-cheiny@synaptics.com>
Implements renaming from "physical" to "transport", as described in part 00/05
of this patch set.
Signed-off-by: Christopher Heiny <cheiny@synaptics.com>
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: Linus Walleij <linus.walleij@stericsson.com>
Cc: Joeri de Gram <j.de.gram@gmail.com>
Acked-by: Jean Delvare <khali@linux-fr.org>
---
drivers/input/rmi4/rmi_i2c.c | 133 ++++++++++++++++++++-----------------------
1 file changed, 62 insertions(+), 71 deletions(-)
diff --git a/drivers/input/rmi4/rmi_i2c.c b/drivers/input/rmi4/rmi_i2c.c
index f3bef04..4299a60 100644
--- a/drivers/input/rmi4/rmi_i2c.c
+++ b/drivers/input/rmi4/rmi_i2c.c
@@ -28,7 +28,7 @@
*
* @page_mutex: Locks current page to avoid changing pages in unexpected ways.
* @page: Keeps track of the current virtual page
- * @phys: Pointer to the physical interface
+ * @xport: Pointer to the transport interface
*
* @tx_buf: Buffer used for transmitting data to the sensor over i2c.
* @tx_buf_size: Size of the buffer
@@ -37,11 +37,12 @@
*
* @comms_debug: Latest data read/written for debugging I2C communications
* @debugfs_comms: Debugfs file for debugging I2C communications
+ *
*/
struct rmi_i2c_data {
struct mutex page_mutex;
int page;
- struct rmi_phys_device *phys;
+ struct rmi_transport_device *xport;
u8 *tx_buf;
int tx_buf_size;
@@ -64,8 +65,7 @@ static int setup_debugfs(struct rmi_device *rmi_dev, struct rmi_i2c_data *data)
data->debugfs_comms = debugfs_create_bool("comms_debug", RMI_RW_ATTR,
rmi_dev->debugfs_root, &data->comms_debug);
if (!data->debugfs_comms || IS_ERR(data->debugfs_comms)) {
- dev_warn(&rmi_dev->dev,
- "Failed to create debugfs comms_debug.\n");
+ dev_warn(&rmi_dev->dev, "Failed to create debugfs comms_debug.\n");
data->debugfs_comms = NULL;
}
@@ -77,19 +77,9 @@ static void teardown_debugfs(struct rmi_i2c_data *data)
if (data->debugfs_comms)
debugfs_remove(data->debugfs_comms);
}
-
#else
-
-static inline int setup_debugfs(struct rmi_device *rmi_dev,
- struct rmi_i2c_data *data)
-{
- return 0;
-}
-
-static inline void teardown_debugfs(struct rmi_i2c_data *data)
-{
-}
-
+#define setup_debugfs(rmi_dev, data) 0
+#define teardown_debugfs(data)
#endif
#define COMMS_DEBUG(data) (IS_ENABLED(CONFIG_RMI4_DEBUG) && data->comms_debug)
@@ -97,14 +87,14 @@ static inline void teardown_debugfs(struct rmi_i2c_data *data)
#define RMI_PAGE_SELECT_REGISTER 0xff
#define RMI_I2C_PAGE(addr) (((addr) >> 8) & 0xff)
-static char *phys_proto_name = "i2c";
+static char *transport_protocol_name = "i2c";
/*
* rmi_set_page - Set RMI page
- * @phys: The pointer to the rmi_phys_device struct
+ * @xport: The pointer to the rmi_transport_device struct
* @page: The new page address.
*
- * RMI devices have 16-bit addressing, but some of the physical
+ * RMI devices have 16-bit addressing, but some of the transport
* implementations (like SMBus) only have 8-bit addressing. So RMI implements
* a page address at 0xff of every page so we can reliable page addresses
* every 256 registers.
@@ -113,21 +103,21 @@ static char *phys_proto_name = "i2c";
*
* Returns zero on success, non-zero on failure.
*/
-static int rmi_set_page(struct rmi_phys_device *phys, u8 page)
+static int rmi_set_page(struct rmi_transport_device *xport, u8 page)
{
- struct i2c_client *client = to_i2c_client(phys->dev);
- struct rmi_i2c_data *data = phys->data;
+ struct i2c_client *client = to_i2c_client(xport->dev);
+ struct rmi_i2c_data *data = xport->data;
u8 txbuf[2] = {RMI_PAGE_SELECT_REGISTER, page};
int retval;
if (COMMS_DEBUG(data))
dev_dbg(&client->dev, "writes 3 bytes: %02x %02x\n",
txbuf[0], txbuf[1]);
- phys->info.tx_count++;
- phys->info.tx_bytes += sizeof(txbuf);
+ xport->info.tx_count++;
+ xport->info.tx_bytes += sizeof(txbuf);
retval = i2c_master_send(client, txbuf, sizeof(txbuf));
if (retval != sizeof(txbuf)) {
- phys->info.tx_errs++;
+ xport->info.tx_errs++;
dev_err(&client->dev,
"%s: set page failed: %d.", __func__, retval);
return (retval < 0) ? retval : -EIO;
@@ -157,18 +147,18 @@ static int copy_to_debug_buf(struct device *dev, struct rmi_i2c_data *data,
temp = data->debug_buf;
for (i = 0; i < len; i++) {
- n = sprintf(temp, " %02x", buf[i]);
+ n = snprintf(temp, 3, " %02x", buf[i]);
temp += n;
}
return 0;
}
-static int rmi_i2c_write_block(struct rmi_phys_device *phys, u16 addr,
+static int rmi_i2c_write_block(struct rmi_transport_device *xport, u16 addr,
const void *buf, const int len)
{
- struct i2c_client *client = to_i2c_client(phys->dev);
- struct rmi_i2c_data *data = phys->data;
+ struct i2c_client *client = to_i2c_client(xport->dev);
+ struct rmi_i2c_data *data = xport->data;
int retval;
int tx_size = len + 1;
@@ -190,7 +180,7 @@ static int rmi_i2c_write_block(struct rmi_phys_device *phys, u16 addr,
memcpy(data->tx_buf + 1, buf, len);
if (RMI_I2C_PAGE(addr) != data->page) {
- retval = rmi_set_page(phys, RMI_I2C_PAGE(addr));
+ retval = rmi_set_page(xport, RMI_I2C_PAGE(addr));
if (retval < 0)
goto exit;
}
@@ -202,11 +192,11 @@ static int rmi_i2c_write_block(struct rmi_phys_device *phys, u16 addr,
len, addr, data->debug_buf);
}
- phys->info.tx_count++;
- phys->info.tx_bytes += tx_size;
+ xport->info.tx_count++;
+ xport->info.tx_bytes += tx_size;
retval = i2c_master_send(client, data->tx_buf, tx_size);
if (retval < 0)
- phys->info.tx_errs++;
+ xport->info.tx_errs++;
else
retval--; /* don't count the address byte */
@@ -216,18 +206,18 @@ exit:
}
-static int rmi_i2c_read_block(struct rmi_phys_device *phys, u16 addr,
+static int rmi_i2c_read_block(struct rmi_transport_device *xport, u16 addr,
void *buf, const int len)
{
- struct i2c_client *client = to_i2c_client(phys->dev);
- struct rmi_i2c_data *data = phys->data;
+ struct i2c_client *client = to_i2c_client(xport->dev);
+ struct rmi_i2c_data *data = xport->data;
u8 txbuf[1] = {addr & 0xff};
int retval;
mutex_lock(&data->page_mutex);
if (RMI_I2C_PAGE(addr) != data->page) {
- retval = rmi_set_page(phys, RMI_I2C_PAGE(addr));
+ retval = rmi_set_page(xport, RMI_I2C_PAGE(addr));
if (retval < 0)
goto exit;
}
@@ -235,21 +225,21 @@ static int rmi_i2c_read_block(struct rmi_phys_device *phys, u16 addr,
if (COMMS_DEBUG(data))
dev_dbg(&client->dev, "writes 1 bytes: %02x\n", txbuf[0]);
- phys->info.tx_count++;
- phys->info.tx_bytes += sizeof(txbuf);
+ xport->info.tx_count++;
+ xport->info.tx_bytes += sizeof(txbuf);
retval = i2c_master_send(client, txbuf, sizeof(txbuf));
if (retval != sizeof(txbuf)) {
- phys->info.tx_errs++;
+ xport->info.tx_errs++;
retval = (retval < 0) ? retval : -EIO;
goto exit;
}
retval = i2c_master_recv(client, (u8 *) buf, len);
- phys->info.rx_count++;
- phys->info.rx_bytes += len;
+ xport->info.rx_count++;
+ xport->info.rx_bytes += len;
if (retval < 0)
- phys->info.rx_errs++;
+ xport->info.rx_errs++;
else if (COMMS_DEBUG(data)) {
int rc = copy_to_debug_buf(&client->dev, data, (u8 *) buf, len);
if (!rc)
@@ -263,9 +253,9 @@ exit:
}
static int rmi_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+ const struct i2c_device_id *id)
{
- struct rmi_phys_device *rmi_phys;
+ struct rmi_transport_device *rmi_transport;
struct rmi_i2c_data *data;
struct rmi_device_platform_data *pdata = client->dev.platform_data;
int retval;
@@ -274,32 +264,33 @@ static int rmi_i2c_probe(struct i2c_client *client,
dev_err(&client->dev, "no platform data\n");
return -EINVAL;
}
- dev_info(&client->dev, "Probing %s at %#02x (IRQ %d).\n",
+ dev_dbg(&client->dev, "Probing %s at %#02x (GPIO %d).\n",
pdata->sensor_name ? pdata->sensor_name : "-no name-",
client->addr, pdata->attn_gpio);
+ retval = i2c_check_functionality(client->adapter, I2C_FUNC_I2C);
+ if (!retval) {
+ dev_err(&client->dev, "i2c_check_functionality error %d.\n",
+ retval);
+ return retval;
+ }
+
if (pdata->gpio_config) {
- dev_dbg(&client->dev, "Configuring GPIOs.\n");
retval = pdata->gpio_config(pdata->gpio_data, true);
if (retval < 0) {
dev_err(&client->dev, "Failed to configure GPIOs, code: %d.\n",
retval);
return retval;
}
+ msleep(pdata->reset_delay_ms ?
+ pdata->reset_delay_ms : DEFAULT_RESET_DELAY_MS);
dev_info(&client->dev, "Done with GPIO configuration.\n");
}
- retval = i2c_check_functionality(client->adapter, I2C_FUNC_I2C);
- if (!retval) {
- dev_err(&client->dev, "i2c_check_functionality error %d.\n",
- retval);
- return retval;
- }
-
- rmi_phys = devm_kzalloc(&client->dev, sizeof(struct rmi_phys_device),
- GFP_KERNEL);
+ rmi_transport = devm_kzalloc(&client->dev,
+ sizeof(struct rmi_transport_device), GFP_KERNEL);
- if (!rmi_phys)
+ if (!rmi_transport)
return -ENOMEM;
data = devm_kzalloc(&client->dev, sizeof(struct rmi_i2c_data),
@@ -307,35 +298,35 @@ static int rmi_i2c_probe(struct i2c_client *client,
if (!data)
return -ENOMEM;
- data->phys = rmi_phys;
+ data->xport = rmi_transport;
- rmi_phys->data = data;
- rmi_phys->dev = &client->dev;
+ rmi_transport->data = data;
+ rmi_transport->dev = &client->dev;
- rmi_phys->write_block = rmi_i2c_write_block;
- rmi_phys->read_block = rmi_i2c_read_block;
- rmi_phys->info.proto = phys_proto_name;
+ rmi_transport->write_block = rmi_i2c_write_block;
+ rmi_transport->read_block = rmi_i2c_read_block;
+ rmi_transport->info.proto = transport_protocol_name;
mutex_init(&data->page_mutex);
/* Setting the page to zero will (a) make sure the PSR is in a
* known state, and (b) make sure we can talk to the device.
*/
- retval = rmi_set_page(rmi_phys, 0);
+ retval = rmi_set_page(rmi_transport, 0);
if (retval) {
dev_err(&client->dev, "Failed to set page select to 0.\n");
return retval;
}
- retval = rmi_register_physical_device(rmi_phys);
+ retval = rmi_register_transport_device(rmi_transport);
if (retval) {
- dev_err(&client->dev, "Failed to register physical driver at 0x%.2X.\n",
+ dev_err(&client->dev, "Failed to register transport at 0x%.2X.\n",
client->addr);
goto err_gpio;
}
- i2c_set_clientdata(client, rmi_phys);
+ i2c_set_clientdata(client, rmi_transport);
- retval = setup_debugfs(rmi_phys->rmi_dev, data);
+ retval = setup_debugfs(rmi_transport->rmi_dev, data);
if (retval < 0)
dev_warn(&client->dev, "Failed to setup debugfs. Code: %d.\n",
retval);
@@ -352,12 +343,12 @@ err_gpio:
static int rmi_i2c_remove(struct i2c_client *client)
{
- struct rmi_phys_device *phys = i2c_get_clientdata(client);
+ struct rmi_transport_device *xport = i2c_get_clientdata(client);
struct rmi_device_platform_data *pd = client->dev.platform_data;
- teardown_debugfs(phys->data);
+ teardown_debugfs(xport->data);
- rmi_unregister_physical_device(phys);
+ rmi_unregister_transport_device(xport);
if (pd->gpio_config)
pd->gpio_config(&pd->gpio_data, false);
^ permalink raw reply related
* [PATCH 03/04] input synaptics-rmi4: RMI4 F01 device control
From: Christopher Heiny @ 2013-11-13 23:39 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Linux Input, Christopher Heiny, Andrew Duggan, Vincent Huang,
Vivian Ly, Daniel Rosenberg, Jean Delvare, Joerie de Gram,
Linus Walleij
In-Reply-To: <1384385972-1686-1-git-send-email-cheiny@synaptics.com>
* eliminate packed struct bitfield definitions.
* removes sysfs/debugfs from the core functionality.
* refactors register definitions into rmi_f01.h for use by external modules
implementing sysfs/debugfs control and debug functions.
* adds query register parsing to extract the touch sensor firmare build ID.
Signed-off-by: Christopher Heiny <cheiny@synaptics.com>
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: Linus Walleij <linus.walleij@stericsson.com>
Cc: Joeri de Gram <j.de.gram@gmail.com>
---
drivers/input/rmi4/rmi_f01.c | 1314 ++++++++++--------------------------------
drivers/input/rmi4/rmi_f01.h | 269 +++++++++
2 files changed, 568 insertions(+), 1015 deletions(-)
diff --git a/drivers/input/rmi4/rmi_f01.c b/drivers/input/rmi4/rmi_f01.c
index fe26869..7172ac6 100644
--- a/drivers/input/rmi4/rmi_f01.c
+++ b/drivers/input/rmi4/rmi_f01.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2012 Synaptics Incorporated
+ * Copyright (c) 2011-2013 Synaptics Incorporated
* Copyright (c) 2011 Unixphere
*
* This program is free software; you can redistribute it and/or modify it
@@ -8,919 +8,18 @@
*/
#include <linux/kernel.h>
-#include <linux/debugfs.h>
#include <linux/kconfig.h>
#include <linux/rmi.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
-#include "rmi_driver.h"
-
-#define RMI_PRODUCT_ID_LENGTH 10
-#define RMI_PRODUCT_INFO_LENGTH 2
-
-#define RMI_DATE_CODE_LENGTH 3
-
-#define PRODUCT_ID_OFFSET 0x10
-#define PRODUCT_INFO_OFFSET 0x1E
-
-
-/* Force a firmware reset of the sensor */
-#define RMI_F01_CMD_DEVICE_RESET 1
-
-/* Various F01_RMI_QueryX bits */
-
-#define RMI_F01_QRY1_CUSTOM_MAP (1 << 0)
-#define RMI_F01_QRY1_NON_COMPLIANT (1 << 1)
-#define RMI_F01_QRY1_HAS_LTS (1 << 2)
-#define RMI_F01_QRY1_HAS_SENSOR_ID (1 << 3)
-#define RMI_F01_QRY1_HAS_CHARGER_INP (1 << 4)
-#define RMI_F01_QRY1_HAS_ADJ_DOZE (1 << 5)
-#define RMI_F01_QRY1_HAS_ADJ_DOZE_HOFF (1 << 6)
-#define RMI_F01_QRY1_HAS_PROPS_2 (1 << 7)
-
-#define RMI_F01_QRY5_YEAR_MASK 0x1f
-#define RMI_F01_QRY6_MONTH_MASK 0x0f
-#define RMI_F01_QRY7_DAY_MASK 0x1f
-
-#define RMI_F01_QRY2_PRODINFO_MASK 0x7f
-
-#define RMI_F01_BASIC_QUERY_LEN 21 /* From Query 00 through 20 */
-
-struct f01_basic_properties {
- u8 manufacturer_id;
- bool has_lts;
- bool has_adjustable_doze;
- bool has_adjustable_doze_holdoff;
- char dom[9]; /* YYYYMMDD + '\0' */
- u8 product_id[RMI_PRODUCT_ID_LENGTH + 1];
- u16 productinfo;
-};
-
-/* F01 device status bits */
-
-/* Most recent device status event */
-#define RMI_F01_STATUS_CODE(status) ((status) & 0x0f)
-/* Indicates that flash programming is enabled (bootloader mode). */
-#define RMI_F01_STATUS_BOOTLOADER(status) (!!((status) & 0x40))
-/* The device has lost its configuration for some reason. */
-#define RMI_F01_STATUS_UNCONFIGURED(status) (!!((status) & 0x80))
-
-/* Control register bits */
-
-/*
- * Sleep mode controls power management on the device and affects all
- * functions of the device.
- */
-#define RMI_F01_CTRL0_SLEEP_MODE_MASK 0x03
-
-#define RMI_SLEEP_MODE_NORMAL 0x00
-#define RMI_SLEEP_MODE_SENSOR_SLEEP 0x01
-#define RMI_SLEEP_MODE_RESERVED0 0x02
-#define RMI_SLEEP_MODE_RESERVED1 0x03
-
-#define RMI_IS_VALID_SLEEPMODE(mode) \
- (mode >= RMI_SLEEP_MODE_NORMAL && mode <= RMI_SLEEP_MODE_RESERVED1)
-
-/*
- * This bit disables whatever sleep mode may be selected by the sleep_mode
- * field and forces the device to run at full power without sleeping.
- */
-#define RMI_F01_CRTL0_NOSLEEP_BIT (1 << 2)
-
-/*
- * When this bit is set, the touch controller employs a noise-filtering
- * algorithm designed for use with a connected battery charger.
- */
-#define RMI_F01_CRTL0_CHARGER_BIT (1 << 5)
-
-/*
- * Sets the report rate for the device. The effect of this setting is
- * highly product dependent. Check the spec sheet for your particular
- * touch sensor.
- */
-#define RMI_F01_CRTL0_REPORTRATE_BIT (1 << 6)
-
-/*
- * Written by the host as an indicator that the device has been
- * successfully configured.
- */
-#define RMI_F01_CRTL0_CONFIGURED_BIT (1 << 7)
-
-/**
- * @ctrl0 - see the bit definitions above.
- * @interrupt_enable - A mask of per-function interrupts on the touch sensor.
- * @doze_interval - controls the interval between checks for finger presence
- * when the touch sensor is in doze mode, in units of 10ms.
- * @wakeup_threshold - controls the capacitance threshold at which the touch
- * sensor will decide to wake up from that low power state.
- * @doze_holdoff - controls how long the touch sensor waits after the last
- * finger lifts before entering the doze state, in units of 100ms.
- */
-struct f01_device_control {
- u8 ctrl0;
- u8 *interrupt_enable;
- u8 doze_interval;
- u8 wakeup_threshold;
- u8 doze_holdoff;
-};
-
-struct f01_data {
- struct f01_basic_properties properties;
-
- struct f01_device_control device_control;
- struct mutex control_mutex;
-
- u8 device_status;
-
- u16 interrupt_enable_addr;
- u16 doze_interval_addr;
- u16 wakeup_threshold_addr;
- u16 doze_holdoff_addr;
- int irq_count;
- int num_of_irq_regs;
-
-#ifdef CONFIG_PM
- bool suspended;
- bool old_nosleep;
-#endif
-
-#ifdef CONFIG_RMI4_DEBUG
- struct dentry *debugfs_interrupt_enable;
-#endif
-};
-
-#ifdef CONFIG_RMI4_DEBUG
-struct f01_debugfs_data {
- bool done;
- struct rmi_function *fn;
-};
-
-static int f01_debug_open(struct inode *inodep, struct file *filp)
-{
- struct f01_debugfs_data *data;
- struct rmi_function *fn = inodep->i_private;
-
- data = kzalloc(sizeof(struct f01_debugfs_data), GFP_KERNEL);
- if (!data)
- return -ENOMEM;
-
- data->fn = fn;
- filp->private_data = data;
- return 0;
-}
-
-static int f01_debug_release(struct inode *inodep, struct file *filp)
-{
- kfree(filp->private_data);
- return 0;
-}
-
-static ssize_t interrupt_enable_read(struct file *filp, char __user *buffer,
- size_t size, loff_t *offset) {
- int i;
- int len;
- int total_len = 0;
- char local_buf[size]; // FIXME!!!! XXX arbitrary size array on stack
- char *current_buf = local_buf;
- struct f01_debugfs_data *data = filp->private_data;
- struct f01_data *f01 = data->fn->data;
-
- if (data->done)
- return 0;
-
- data->done = 1;
-
- /* loop through each irq value and copy its
- * string representation into buf */
- for (i = 0; i < f01->irq_count; i++) {
- int irq_reg;
- int irq_shift;
- int interrupt_enable;
-
- irq_reg = i / 8;
- irq_shift = i % 8;
- interrupt_enable =
- ((f01->device_control.interrupt_enable[irq_reg]
- >> irq_shift) & 0x01);
-
- /* get next irq value and write it to buf */
- len = snprintf(current_buf, size - total_len,
- "%u ", interrupt_enable);
- /* bump up ptr to next location in buf if the
- * snprintf was valid. Otherwise issue an error
- * and return. */
- if (len > 0) {
- current_buf += len;
- total_len += len;
- } else {
- dev_err(&data->fn->dev, "Failed to build interrupt_enable buffer, code = %d.\n",
- len);
- return snprintf(local_buf, size, "unknown\n");
- }
- }
- len = snprintf(current_buf, size - total_len, "\n");
- if (len > 0)
- total_len += len;
- else
- dev_warn(&data->fn->dev, "%s: Failed to append carriage return.\n",
- __func__);
-
- if (copy_to_user(buffer, local_buf, total_len))
- return -EFAULT;
-
- return total_len;
-}
-
-static ssize_t interrupt_enable_write(struct file *filp,
- const char __user *buffer, size_t size, loff_t *offset) {
- int retval;
- char buf[size];
- char *local_buf = buf;
- int i;
- int irq_count = 0;
- int irq_reg = 0;
- struct f01_debugfs_data *data = filp->private_data;
- struct f01_data *f01 = data->fn->data;
-
- retval = copy_from_user(buf, buffer, size);
- if (retval)
- return -EFAULT;
-
- for (i = 0; i < f01->irq_count && *local_buf != 0;
- i++, local_buf += 2) {
- int irq_shift;
- int interrupt_enable;
- int result;
-
- irq_reg = i / 8;
- irq_shift = i % 8;
-
- /* get next interrupt mapping value and store and bump up to
- * point to next item in local_buf */
- result = sscanf(local_buf, "%u", &interrupt_enable);
- if ((result != 1) ||
- (interrupt_enable != 0 && interrupt_enable != 1)) {
- dev_err(&data->fn->dev, "Interrupt enable[%d] is not a valid value 0x%x.\n",
- i, interrupt_enable);
- return -EINVAL;
- }
- if (interrupt_enable == 0) {
- f01->device_control.interrupt_enable[irq_reg] &=
- (1 << irq_shift) ^ 0xFF;
- } else
- f01->device_control.interrupt_enable[irq_reg] |=
- (1 << irq_shift);
- irq_count++;
- }
-
- /* Make sure the irq count matches */
- if (irq_count != f01->irq_count) {
- dev_err(&data->fn->dev, "Interrupt enable count of %d doesn't match device count of %d.\n",
- irq_count, f01->irq_count);
- return -EINVAL;
- }
-
- /* write back to the control register */
- retval = rmi_write_block(data->fn->rmi_dev, f01->interrupt_enable_addr,
- f01->device_control.interrupt_enable,
- f01->num_of_irq_regs);
- if (retval < 0) {
- dev_err(&data->fn->dev, "Could not write interrupt_enable mask to %#06x\n",
- f01->interrupt_enable_addr);
- return retval;
- }
-
- return size;
-}
-
-static const struct file_operations interrupt_enable_fops = {
- .owner = THIS_MODULE,
- .open = f01_debug_open,
- .release = f01_debug_release,
- .read = interrupt_enable_read,
- .write = interrupt_enable_write,
-};
-
-static int setup_debugfs(struct rmi_function *fn)
-{
- struct f01_data *data = fn->data;
-
- if (!fn->debugfs_root)
- return -ENODEV;
-
- data->debugfs_interrupt_enable = debugfs_create_file("interrupt_enable",
- RMI_RW_ATTR, fn->debugfs_root, fn, &interrupt_enable_fops);
- if (!data->debugfs_interrupt_enable)
- dev_warn(&fn->dev,
- "Failed to create debugfs interrupt_enable.\n");
-
- return 0;
-}
-
-static void teardown_debugfs(struct f01_data *f01)
-{
- if (f01->debugfs_interrupt_enable)
- debugfs_remove(f01->debugfs_interrupt_enable);
-}
-
-#else
-
-static inline int setup_debugfs(struct rmi_function *fn)
-{
- return 0;
-}
-
-static inline void teardown_debugfs(struct f01_data *f01)
-{
-}
-
-#endif
-
-static ssize_t rmi_fn_01_productinfo_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct rmi_function *fn = to_rmi_function(dev);
- struct f01_data *data = fn->data;
-
- return snprintf(buf, PAGE_SIZE, "0x%04x\n",
- data->properties.productinfo);
-}
-
-static ssize_t rmi_fn_01_productid_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct rmi_function *fn = to_rmi_function(dev);
- struct f01_data *data = fn->data;
-
- return snprintf(buf, PAGE_SIZE, "%s\n", data->properties.product_id);
-}
-
-static ssize_t rmi_fn_01_manufacturer_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct rmi_function *fn = to_rmi_function(dev);
- struct f01_data *data = fn->data;
-
- return snprintf(buf, PAGE_SIZE, "0x%02x\n",
- data->properties.manufacturer_id);
-}
-
-static ssize_t rmi_fn_01_datecode_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct rmi_function *fn = to_rmi_function(dev);
- struct f01_data *data = fn->data;
-
- return snprintf(buf, PAGE_SIZE, "%s\n", data->properties.dom);
-}
-
-static ssize_t rmi_fn_01_reset_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct rmi_function *fn = to_rmi_function(dev);
- unsigned int reset;
- int error;
-
- if (sscanf(buf, "%u", &reset) != 1)
- return -EINVAL;
- if (reset < 0 || reset > 1)
- return -EINVAL;
-
- /* Per spec, 0 has no effect, so we skip it entirely. */
- if (reset) {
- /* Command register always reads as 0, so just use a local. */
- u8 command = RMI_F01_CMD_DEVICE_RESET;
-
- error = rmi_write_block(fn->rmi_dev, fn->fd.command_base_addr,
- &command, sizeof(command));
- if (error < 0) {
- dev_err(dev, "Failed to issue reset command, code = %d.",
- error);
- return error;
- }
- }
-
- return count;
-}
-
-static ssize_t rmi_fn_01_sleepmode_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct rmi_function *fn = to_rmi_function(dev);
- struct f01_data *data = fn->data;
- unsigned int value = data->device_control.ctrl0 &
- RMI_F01_CTRL0_SLEEP_MODE_MASK;
-
- return snprintf(buf, PAGE_SIZE, "%d\n", value);
-}
-
-static ssize_t rmi_fn_01_sleepmode_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct rmi_function *fn = to_rmi_function(dev);
- struct f01_data *data = fn->data;
- unsigned long new_value;
- int retval;
-
- retval = strict_strtoul(buf, 10, &new_value);
- if (retval < 0 || !RMI_IS_VALID_SLEEPMODE(new_value)) {
- dev_err(dev, "%s: Invalid sleep mode %s.", __func__, buf);
- return -EINVAL;
- }
-
- retval = mutex_lock_interruptible(&data->control_mutex);
- if (retval)
- return retval;
-
- dev_dbg(dev, "Setting sleep mode to %ld.", new_value);
-
- data->device_control.ctrl0 &= ~RMI_F01_CTRL0_SLEEP_MODE_MASK;
- data->device_control.ctrl0 |= new_value;
-
- retval = rmi_write_block(fn->rmi_dev, fn->fd.control_base_addr,
- &data->device_control.ctrl0,
- sizeof(data->device_control.ctrl0));
- if (retval >= 0)
- retval = count;
- else
- dev_err(dev, "Failed to write sleep mode, code %d.\n", retval);
-
- mutex_unlock(&data->control_mutex);
- return retval;
-}
-
-static ssize_t rmi_fn_01_nosleep_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct rmi_function *fn = to_rmi_function(dev);
- struct f01_data *data = fn->data;
- unsigned int value = !!(data->device_control.ctrl0 &
- RMI_F01_CRTL0_NOSLEEP_BIT);
-
- return snprintf(buf, PAGE_SIZE, "%d\n", value);
-}
-
-static ssize_t rmi_fn_01_nosleep_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct rmi_function *fn = to_rmi_function(dev);
- struct f01_data *data = fn->data;
- unsigned long new_value;
- int retval;
-
- retval = strict_strtoul(buf, 10, &new_value);
- if (retval < 0 || new_value > 1) {
- dev_err(dev, "%s: Invalid nosleep bit %s.", __func__, buf);
- return -EINVAL;
- }
-
- retval = mutex_lock_interruptible(&data->control_mutex);
- if (retval)
- return retval;
-
- if (new_value)
- data->device_control.ctrl0 |= RMI_F01_CRTL0_NOSLEEP_BIT;
- else
- data->device_control.ctrl0 &= ~RMI_F01_CRTL0_NOSLEEP_BIT;
-
- retval = rmi_write_block(fn->rmi_dev, fn->fd.control_base_addr,
- &data->device_control.ctrl0,
- sizeof(data->device_control.ctrl0));
- if (retval >= 0)
- retval = count;
- else
- dev_err(dev, "Failed to write nosleep bit.\n");
-
- mutex_unlock(&data->control_mutex);
- return retval;
-}
-
-static ssize_t rmi_fn_01_chargerinput_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct rmi_function *fn = to_rmi_function(dev);
- struct f01_data *data = fn->data;
- unsigned int value = !!(data->device_control.ctrl0 &
- RMI_F01_CRTL0_CHARGER_BIT);
-
- return snprintf(buf, PAGE_SIZE, "%d\n", value);
-}
-
-static ssize_t rmi_fn_01_chargerinput_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct rmi_function *fn = to_rmi_function(dev);
- struct f01_data *data = fn->data;
- unsigned long new_value;
- int retval;
-
- retval = strict_strtoul(buf, 10, &new_value);
- if (retval < 0 || new_value > 1) {
- dev_err(dev, "%s: Invalid chargerinput bit %s.", __func__, buf);
- return -EINVAL;
- }
-
- retval = mutex_lock_interruptible(&data->control_mutex);
- if (retval)
- return retval;
-
- if (new_value)
- data->device_control.ctrl0 |= RMI_F01_CRTL0_CHARGER_BIT;
- else
- data->device_control.ctrl0 &= ~RMI_F01_CRTL0_CHARGER_BIT;
-
- retval = rmi_write_block(fn->rmi_dev, fn->fd.control_base_addr,
- &data->device_control.ctrl0,
- sizeof(data->device_control.ctrl0));
- if (retval >= 0)
- retval = count;
- else
- dev_err(dev, "Failed to write chargerinput bit.\n");
-
- mutex_unlock(&data->control_mutex);
- return retval;
-}
-
-static ssize_t rmi_fn_01_reportrate_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct rmi_function *fn = to_rmi_function(dev);
- struct f01_data *data = fn->data;
- int value = !!(data->device_control.ctrl0 &
- RMI_F01_CRTL0_REPORTRATE_BIT);
-
- return snprintf(buf, PAGE_SIZE, "%d\n", value);
-}
-
-static ssize_t rmi_fn_01_reportrate_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct rmi_function *fn = to_rmi_function(dev);
- struct f01_data *data = fn->data;
- unsigned long new_value;
- int retval;
-
- retval = strict_strtoul(buf, 10, &new_value);
- if (retval < 0 || new_value > 1) {
- dev_err(dev, "%s: Invalid reportrate bit %s.", __func__, buf);
- return -EINVAL;
- }
-
- retval = mutex_lock_interruptible(&data->control_mutex);
- if (retval)
- return retval;
-
- if (new_value)
- data->device_control.ctrl0 |= RMI_F01_CRTL0_REPORTRATE_BIT;
- else
- data->device_control.ctrl0 &= ~RMI_F01_CRTL0_REPORTRATE_BIT;
-
- retval = rmi_write_block(fn->rmi_dev, fn->fd.control_base_addr,
- &data->device_control.ctrl0,
- sizeof(data->device_control.ctrl0));
- if (retval >= 0)
- retval = count;
- else
- dev_err(dev, "Failed to write reportrate bit.\n");
-
- mutex_unlock(&data->control_mutex);
- return retval;
-}
-
-static ssize_t rmi_fn_01_interrupt_enable_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct rmi_function *fn = to_rmi_function(dev);
- struct f01_data *data = fn->data;
- int i, len, total_len = 0;
- char *current_buf = buf;
-
- /* loop through each irq value and copy its
- * string representation into buf */
- for (i = 0; i < data->irq_count; i++) {
- int irq_reg;
- int irq_shift;
- int interrupt_enable;
-
- irq_reg = i / 8;
- irq_shift = i % 8;
- interrupt_enable =
- ((data->device_control.interrupt_enable[irq_reg]
- >> irq_shift) & 0x01);
-
- /* get next irq value and write it to buf */
- len = snprintf(current_buf, PAGE_SIZE - total_len,
- "%u ", interrupt_enable);
- /* bump up ptr to next location in buf if the
- * snprintf was valid. Otherwise issue an error
- * and return. */
- if (len > 0) {
- current_buf += len;
- total_len += len;
- } else {
- dev_err(dev, "Failed to build interrupt_enable buffer, code = %d.\n",
- len);
- return snprintf(buf, PAGE_SIZE, "unknown\n");
- }
- }
- len = snprintf(current_buf, PAGE_SIZE - total_len, "\n");
- if (len > 0)
- total_len += len;
- else
- dev_warn(dev, "%s: Failed to append carriage return.\n",
- __func__);
- return total_len;
-
-}
-
-static ssize_t rmi_fn_01_doze_interval_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct rmi_function *fn = to_rmi_function(dev);
- struct f01_data *data = fn->data;
-
- return snprintf(buf, PAGE_SIZE, "%d\n",
- data->device_control.doze_interval);
-
-}
-
-static ssize_t rmi_fn_01_doze_interval_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct rmi_function *fn = to_rmi_function(dev);
- struct f01_data *data = fn->data;
- unsigned long new_value;
- int retval;
- u16 ctrl_base_addr;
-
- retval = strict_strtoul(buf, 10, &new_value);
- if (retval < 0 || new_value > 255) {
- dev_err(dev, "%s: Invalid doze interval %s.", __func__, buf);
- return -EINVAL;
- }
-
- retval = mutex_lock_interruptible(&data->control_mutex);
- if (retval)
- return retval;
-
- data->device_control.doze_interval = new_value;
- ctrl_base_addr = fn->fd.control_base_addr + sizeof(u8) +
- (sizeof(u8)*(data->num_of_irq_regs));
- dev_dbg(dev, "doze_interval store address %x, value %d",
- ctrl_base_addr, data->device_control.doze_interval);
-
- retval = rmi_write_block(fn->rmi_dev, data->doze_interval_addr,
- &data->device_control.doze_interval,
- sizeof(u8));
- if (retval >= 0)
- retval = count;
- else
- dev_err(dev, "Failed to write doze interval.\n");
-
- mutex_unlock(&data->control_mutex);
- return retval;
-}
-static ssize_t rmi_fn_01_wakeup_threshold_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct rmi_function *fn = to_rmi_function(dev);
- struct f01_data *data = fn->data;
-
- return snprintf(buf, PAGE_SIZE, "%d\n",
- data->device_control.wakeup_threshold);
-}
-
-static ssize_t rmi_fn_01_wakeup_threshold_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct rmi_function *fn = to_rmi_function(dev);
- struct f01_data *data = fn->data;
- unsigned long new_value;
- int retval;
-
- retval = strict_strtoul(buf, 10, &new_value);
- if (retval < 0 || new_value > 255) {
- dev_err(dev, "%s: Invalid wakeup threshold %s.", __func__, buf);
- return -EINVAL;
- }
-
- retval = mutex_lock_interruptible(&data->control_mutex);
- if (retval)
- return retval;
-
- data->device_control.doze_interval = new_value;
- retval = rmi_write_block(fn->rmi_dev, data->wakeup_threshold_addr,
- &data->device_control.wakeup_threshold,
- sizeof(u8));
- if (retval >= 0)
- retval = count;
- else
- dev_err(dev, "Failed to write wakeup threshold.\n");
-
- mutex_unlock(&data->control_mutex);
- return retval;
-}
-
-static ssize_t rmi_fn_01_doze_holdoff_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct rmi_function *fn = to_rmi_function(dev);
- struct f01_data *data = fn->data;
-
- return snprintf(buf, PAGE_SIZE, "%d\n",
- data->device_control.doze_holdoff);
-
-}
-
-static ssize_t rmi_fn_01_doze_holdoff_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct rmi_function *fn = to_rmi_function(dev);
- struct f01_data *data = fn->data;
- unsigned long new_value;
- int retval;
-
- retval = strict_strtoul(buf, 10, &new_value);
- if (retval < 0 || new_value > 255) {
- dev_err(dev, "%s: Invalid doze holdoff %s.", __func__, buf);
- return -EINVAL;
- }
-
- retval = mutex_lock_interruptible(&data->control_mutex);
- if (retval)
- return retval;
-
- data->device_control.doze_interval = new_value;
- retval = rmi_write_block(fn->rmi_dev, data->doze_holdoff_addr,
- &data->device_control.doze_holdoff,
- sizeof(u8));
- if (retval >= 0)
- retval = count;
- else
- dev_err(dev, "Failed to write doze holdoff.\n");
-
- mutex_unlock(&data->control_mutex);
- return retval;
-}
-
-static ssize_t rmi_fn_01_configured_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct rmi_function *fn = to_rmi_function(dev);
- struct f01_data *data = fn->data;
- unsigned int value = !!(data->device_control.ctrl0 &
- RMI_F01_CRTL0_CONFIGURED_BIT);
-
- return snprintf(buf, PAGE_SIZE, "%d\n", value);
-}
-
-static ssize_t rmi_fn_01_unconfigured_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct rmi_function *fn = to_rmi_function(dev);
- struct f01_data *data = fn->data;
-
- return snprintf(buf, PAGE_SIZE, "%d\n",
- RMI_F01_STATUS_UNCONFIGURED(data->device_status));
-}
-
-static ssize_t rmi_fn_01_flashprog_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct rmi_function *fn = to_rmi_function(dev);
- struct f01_data *data = fn->data;
-
- return snprintf(buf, PAGE_SIZE, "%d\n",
- RMI_F01_STATUS_BOOTLOADER(data->device_status));
-}
-
-static ssize_t rmi_fn_01_statuscode_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct rmi_function *fn = to_rmi_function(dev);
- struct f01_data *data = fn->data;
-
- return snprintf(buf, PAGE_SIZE, "0x%02x\n",
- RMI_F01_STATUS_CODE(data->device_status));
-}
-
-#define RMI_F01_ATTR(_name) \
- DEVICE_ATTR(_name, RMI_RW_ATTR, \
- rmi_fn_01_##_name##_show, \
- rmi_fn_01_##_name##_store)
-
-#define RMI_F01_RO_ATTR(_name) \
- DEVICE_ATTR(_name, RMI_RO_ATTR, \
- rmi_fn_01_##_name##_show, \
- NULL)
-
-#define RMI_F01_WO_ATTR(_name) \
- DEVICE_ATTR(_name, RMI_RO_ATTR, \
- NULL, \
- rmi_fn_01_##_name##_store)
-
-
-static RMI_F01_RO_ATTR(productinfo);
-static RMI_F01_RO_ATTR(productid);
-static RMI_F01_RO_ATTR(manufacturer);
-static RMI_F01_RO_ATTR(datecode);
-
-/* Control register access */
-static RMI_F01_ATTR(sleepmode);
-static RMI_F01_ATTR(nosleep);
-static RMI_F01_ATTR(chargerinput);
-static RMI_F01_ATTR(reportrate);
-
-/*
- * We don't want arbitrary callers changing the interrupt enable mask,
- * so it's read only.
- */
-static RMI_F01_RO_ATTR(interrupt_enable);
-static RMI_F01_ATTR(doze_interval);
-static RMI_F01_ATTR(wakeup_threshold);
-static RMI_F01_ATTR(doze_holdoff);
-
-/*
- * We make 'configured' RO, since the driver uses that to look for
- * resets. We don't want someone faking us out by changing that
- * bit.
- */
-static RMI_F01_RO_ATTR(configured);
-
-/* Command register access. */
-static RMI_F01_WO_ATTR(reset);
-
-/* Status register access. */
-static RMI_F01_RO_ATTR(unconfigured);
-static RMI_F01_RO_ATTR(flashprog);
-static RMI_F01_RO_ATTR(statuscode);
-
-static struct attribute *rmi_fn_01_attrs[] = {
- &dev_attr_productinfo.attr,
- &dev_attr_productid.attr,
- &dev_attr_manufacturer.attr,
- &dev_attr_datecode.attr,
- &dev_attr_sleepmode.attr,
- &dev_attr_nosleep.attr,
- &dev_attr_chargerinput.attr,
- &dev_attr_reportrate.attr,
- &dev_attr_interrupt_enable.attr,
- &dev_attr_doze_interval.attr,
- &dev_attr_wakeup_threshold.attr,
- &dev_attr_doze_holdoff.attr,
- &dev_attr_configured.attr,
- &dev_attr_reset.attr,
- &dev_attr_unconfigured.attr,
- &dev_attr_flashprog.attr,
- &dev_attr_statuscode.attr,
- NULL
-};
-
-static umode_t rmi_fn_01_attr_visible(struct kobject *kobj,
- struct attribute *attr, int n)
-{
- struct device *dev = kobj_to_dev(kobj);
- struct rmi_function *fn = to_rmi_function(dev);
- struct f01_data *data = fn->data;
- umode_t mode = attr->mode;
-
- if (attr == &dev_attr_doze_interval.attr) {
- if (!data->properties.has_lts)
- mode = 0;
- } else if (attr == &dev_attr_wakeup_threshold.attr) {
- if (!data->properties.has_adjustable_doze)
- mode = 0;
- } else if (attr == &dev_attr_doze_holdoff.attr) {
- if (!data->properties.has_adjustable_doze_holdoff)
- mode = 0;
- }
-
- return mode;
-}
+#include "rmi_driver.h"
+#include "rmi_f01.h"
-static struct attribute_group rmi_fn_01_attr_group = {
- .is_visible = rmi_fn_01_attr_visible,
- .attrs = rmi_fn_01_attrs,
-};
+#define FUNCTION_NUMBER 0x01
static int rmi_f01_alloc_memory(struct rmi_function *fn,
- int num_of_irq_regs)
+ int num_of_irq_regs)
{
struct f01_data *f01;
@@ -942,24 +41,57 @@ static int rmi_f01_alloc_memory(struct rmi_function *fn,
return 0;
}
+static void get_board_and_rev(struct rmi_function *fn,
+ struct rmi_driver_data *driver_data)
+{
+ struct f01_data *data = fn->data;
+ int retval;
+ int board = 0, rev = 0;
+ int i;
+ static const char * const pattern[] = {
+ "tm%4d-%d", "s%4d-%d", "s%4d-ver%1d", "s%4d_ver%1d"};
+ u8 product_id[RMI_PRODUCT_ID_LENGTH+1];
+
+ for (i = 0; i < strlen(data->product_id); i++)
+ product_id[i] = tolower(data->product_id[i]);
+ product_id[i] = '\0';
+
+ for (i = 0; i < ARRAY_SIZE(pattern); i++) {
+ retval = sscanf(product_id, pattern[i], &board, &rev);
+ if (retval)
+ break;
+ }
+
+ /* save board and rev data in the rmi_driver_data */
+ driver_data->board = board;
+ driver_data->rev = rev;
+ dev_dbg(&fn->dev, "From product ID %s, set board: %d rev: %d\n",
+ product_id, driver_data->board, driver_data->rev);
+}
+
+#define PACKAGE_ID_BYTES 4
+#define BUILD_ID_BYTES 3
+
static int rmi_f01_initialize(struct rmi_function *fn)
{
u8 temp;
+ int i;
int error;
- u16 ctrl_base_addr;
+ u16 query_addr = fn->fd.query_base_addr;
+ u16 prod_info_addr;
+ u8 info_buf[4];
+ u16 ctrl_base_addr = fn->fd.control_base_addr;
struct rmi_device *rmi_dev = fn->rmi_dev;
struct rmi_driver_data *driver_data = dev_get_drvdata(&rmi_dev->dev);
struct f01_data *data = fn->data;
struct rmi_device_platform_data *pdata = to_rmi_platform_data(rmi_dev);
u8 basic_query[RMI_F01_BASIC_QUERY_LEN];
+ struct f01_basic_properties *props = &data->properties;
mutex_init(&data->control_mutex);
- /*
- * Set the configured bit and (optionally) other important stuff
- * in the device control register.
- */
- ctrl_base_addr = fn->fd.control_base_addr;
+ /* Set the configured bit and (optionally) other important stuff
+ * in the device control register. */
error = rmi_read_block(rmi_dev, fn->fd.control_base_addr,
&data->device_control.ctrl0,
sizeof(data->device_control.ctrl0));
@@ -978,8 +110,7 @@ static int rmi_f01_initialize(struct rmi_function *fn)
break;
}
- /*
- * Sleep mode might be set as a hangover from a system crash or
+ /* Sleep mode might be set as a hangover from a system crash or
* reboot without power cycle. If so, clear it so the sensor
* is certain to function.
*/
@@ -990,11 +121,16 @@ static int rmi_f01_initialize(struct rmi_function *fn)
data->device_control.ctrl0 &= ~RMI_F01_CTRL0_SLEEP_MODE_MASK;
}
+ /* Set this to indicate that we've initialized the sensor. This will
+ * CLEAR the unconfigured bit in the status registers. If we ever
+ * see unconfigured become set again, we'll know that the sensor has
+ * reset for some reason.
+ */
data->device_control.ctrl0 |= RMI_F01_CRTL0_CONFIGURED_BIT;
error = rmi_write_block(rmi_dev, fn->fd.control_base_addr,
- &data->device_control.ctrl0,
- sizeof(data->device_control.ctrl0));
+ &data->device_control.ctrl0,
+ sizeof(data->device_control.ctrl0));
if (error < 0) {
dev_err(&fn->dev, "Failed to write F01 control.\n");
return error;
@@ -1006,14 +142,12 @@ static int rmi_f01_initialize(struct rmi_function *fn)
data->interrupt_enable_addr = ctrl_base_addr;
error = rmi_read_block(rmi_dev, ctrl_base_addr,
- data->device_control.interrupt_enable,
- sizeof(u8) * (data->num_of_irq_regs));
+ data->device_control.interrupt_enable,
+ sizeof(u8)*(data->num_of_irq_regs));
if (error < 0) {
- dev_err(&fn->dev,
- "Failed to read F01 control interrupt enable register.\n");
+ dev_err(&fn->dev, "Failed to read F01 control interrupt enable register.\n");
goto error_exit;
}
-
ctrl_base_addr += data->num_of_irq_regs;
/* dummy read in order to clear irqs */
@@ -1023,43 +157,226 @@ static int rmi_f01_initialize(struct rmi_function *fn)
return error;
}
+ /* read queries */
error = rmi_read_block(rmi_dev, fn->fd.query_base_addr,
- basic_query, sizeof(basic_query));
+ basic_query, sizeof(basic_query));
if (error < 0) {
dev_err(&fn->dev, "Failed to read device query registers.\n");
return error;
}
/* Now parse what we got */
- data->properties.manufacturer_id = basic_query[0];
+ props->manufacturer_id = basic_query[0];
- data->properties.has_lts = basic_query[1] & RMI_F01_QRY1_HAS_LTS;
- data->properties.has_adjustable_doze =
+ props->has_lts = basic_query[1] & RMI_F01_QRY1_HAS_LTS;
+ props->has_sensor_id =
+ !!(basic_query[1] & RMI_F01_QRY1_HAS_SENSOR_ID);
+ props->has_adjustable_doze =
basic_query[1] & RMI_F01_QRY1_HAS_ADJ_DOZE;
- data->properties.has_adjustable_doze_holdoff =
+ props->has_adjustable_doze_holdoff =
basic_query[1] & RMI_F01_QRY1_HAS_ADJ_DOZE_HOFF;
+ props->has_query42 = basic_query[1] & RMI_F01_QRY1_HAS_PROPS_2;
+
+ snprintf(props->dom, sizeof(props->dom), "20%02d/%02d/%02d",
+ basic_query[5] & RMI_F01_QRY5_YEAR_MASK,
+ basic_query[6] & RMI_F01_QRY6_MONTH_MASK,
+ basic_query[7] & RMI_F01_QRY7_DAY_MASK);
+
+ memcpy(props->product_id, &basic_query[11], RMI_PRODUCT_ID_LENGTH);
+ props->product_id[RMI_PRODUCT_ID_LENGTH] = '\0';
+ query_addr += 11;
+
+ error = rmi_read_block(rmi_dev, query_addr, data->product_id,
+ RMI_PRODUCT_ID_LENGTH);
+ if (error < 0) {
+ dev_err(&fn->dev, "Failed to read product ID.\n");
+ return error;
+ }
+ data->product_id[RMI_PRODUCT_ID_LENGTH] = '\0';
+ get_board_and_rev(fn, driver_data);
+ dev_info(&fn->dev, "found RMI device, manufacturer: %s, product: %s, date: %s\n",
+ props->manufacturer_id == 1 ?
+ "synaptics" : "unknown", data->product_id, props->dom);
+
+ /* We'll come back and use this later, depending on some other query
+ * bits.
+ */
+ prod_info_addr = query_addr + 6;
+
+ query_addr += RMI_PRODUCT_ID_LENGTH;
+ if (props->has_lts) {
+ error = rmi_read(rmi_dev, query_addr, info_buf);
+ if (error < 0) {
+ dev_err(&fn->dev, "Failed to read LTS info.\n");
+ return error;
+ }
+ props->slave_asic_rows = info_buf[0] &
+ RMI_F01_QRY21_SLAVE_ROWS_MASK;
+ props->slave_asic_columns = (info_buf[1] &
+ RMI_F01_QRY21_SLAVE_COLUMNS_MASK) >> 3;
+ query_addr++;
+ }
+
+ if (props->has_sensor_id) {
+ error = rmi_read(rmi_dev, query_addr, &props->sensor_id);
+ if (error < 0) {
+ dev_err(&fn->dev, "Failed to read sensor ID.\n");
+ return error;
+ }
+ query_addr++;
+ }
+
+ /* Maybe skip a block of undefined LTS registers. */
+ if (props->has_lts)
+ query_addr += RMI_F01_LTS_RESERVED_SIZE;
+
+ if (props->has_query42) {
+ error = rmi_read(rmi_dev, query_addr, info_buf);
+ if (error < 0) {
+ dev_err(&fn->dev, "Failed to read additional properties.\n");
+ return error;
+ }
+ props->has_ds4_queries = info_buf[0] &
+ RMI_F01_QRY42_DS4_QUERIES;
+ props->has_multi_physical = info_buf[0] &
+ RMI_F01_QRY42_MULTI_PHYS;
+ props->has_guest = info_buf[0] & RMI_F01_QRY42_GUEST;
+ props->has_swr = info_buf[0] & RMI_F01_QRY42_SWR;
+ props->has_nominal_report_rate = info_buf[0] &
+ RMI_F01_QRY42_NOMINAL_REPORT;
+ props->has_recalibration_interval = info_buf[0] &
+ RMI_F01_QRY42_RECAL_INTERVAL;
+ query_addr++;
+ }
+
+ if (props->has_ds4_queries) {
+ error = rmi_read(rmi_dev, query_addr, &props->ds4_query_length);
+ if (error < 0) {
+ dev_err(&fn->dev, "Failed to read DS4 query length size.\n");
+ return error;
+ }
+ query_addr++;
+ }
- snprintf(data->properties.dom, sizeof(data->properties.dom),
- "20%02x%02x%02x",
- basic_query[5] & RMI_F01_QRY5_YEAR_MASK,
- basic_query[6] & RMI_F01_QRY6_MONTH_MASK,
- basic_query[7] & RMI_F01_QRY7_DAY_MASK);
+ for (i = 1; i <= props->ds4_query_length; i++) {
+ u8 val;
+ error = rmi_read(rmi_dev, query_addr, &val);
+ query_addr++;
+ if (error < 0) {
+ dev_err(&fn->dev, "Failed to read F01_RMI_QUERY43.%02d, code: %d.\n",
+ i, error);
+ continue;
+ }
+ switch (i) {
+ case 1:
+ props->has_package_id_query = val &
+ RMI_F01_QRY43_01_PACKAGE_ID;
+ props->has_build_id_query = val &
+ RMI_F01_QRY43_01_BUILD_ID;
+ props->has_reset_query = val & RMI_F01_QRY43_01_RESET;
+ props->has_maskrev_query = val &
+ RMI_F01_QRY43_01_PACKAGE_ID;
+ break;
+ case 2:
+ props->has_i2c_control = val & RMI_F01_QRY43_02_I2C_CTL;
+ props->has_spi_control = val & RMI_F01_QRY43_02_SPI_CTL;
+ props->has_attn_control = val &
+ RMI_F01_QRY43_02_ATTN_CTL;
+ props->has_win8_vendor_info = val &
+ RMI_F01_QRY43_02_WIN8;
+ props->has_timestamp = val & RMI_F01_QRY43_02_TIMESTAMP;
+ break;
+ case 3:
+ props->has_tool_id_query = val &
+ RMI_F01_QRY43_03_TOOL_ID;
+ props->has_fw_revision_query = val &
+ RMI_F01_QRY43_03_FW_REVISION;
+ break;
+ default:
+ dev_warn(&fn->dev, "No handling for F01_RMI_QUERY43.%02d.\n",
+ i);
+ }
+ }
- memcpy(data->properties.product_id, &basic_query[11],
- RMI_PRODUCT_ID_LENGTH);
- data->properties.product_id[RMI_PRODUCT_ID_LENGTH] = '\0';
+ /* If present, the ASIC package ID registers are overlaid on the
+ * product ID. Go back to the right address (saved previously) and
+ * read them.
+ */
+ if (props->has_package_id_query) {
+ error = rmi_read_block(rmi_dev, prod_info_addr, info_buf,
+ PACKAGE_ID_BYTES);
+ if (error < 0)
+ dev_warn(&fn->dev, "Failed to read package ID.\n");
+ else {
+ u16 *val = (u16 *)info_buf;
+ data->package_id = le16_to_cpu(*val);
+ val = (u16 *)(info_buf + 2);
+ data->package_rev = le16_to_cpu(*val);
+ }
+ }
+ prod_info_addr++;
- data->properties.productinfo =
- ((basic_query[2] & RMI_F01_QRY2_PRODINFO_MASK) << 7) |
- (basic_query[3] & RMI_F01_QRY2_PRODINFO_MASK);
+ /* The firmware build id (if present) is similarly overlaid on product
+ * ID registers. Go back again and read that data.
+ */
+ if (props->has_build_id_query) {
+ error = rmi_read_block(rmi_dev, prod_info_addr, info_buf,
+ BUILD_ID_BYTES);
+ if (error < 0)
+ dev_warn(&fn->dev, "Failed to read FW build ID.\n");
+ else {
+ u16 *val = (u16 *)info_buf;
+ data->build_id = le16_to_cpu(*val);
+ data->build_id += info_buf[2] * 65536;
+ dev_info(&fn->dev, "FW build ID: %#08x (%u).\n",
+ data->build_id, data->build_id);
+ }
+ }
- dev_info(&fn->dev, "found RMI device, manufacturer: %s, product: %s\n",
- data->properties.manufacturer_id == 1 ?
- "synaptics" : "unknown",
- data->properties.product_id);
+ if (props->has_reset_query) {
+ u8 val;
+ error = rmi_read(rmi_dev, query_addr, &val);
+ query_addr++;
+ if (error < 0)
+ dev_warn(&fn->dev, "Failed to read F01_RMI_QUERY44, code: %d.\n",
+ error);
+ else {
+ props->reset_enabled = val & RMI_F01_QRY44_RST_ENABLED;
+ props->reset_polarity = val &
+ RMI_F01_QRY44_RST_POLARITY;
+ props->pullup_enabled = val &
+ RMI_F01_QRY44_PULLUP_ENABLED;
+ props->reset_pin = (val &
+ RMI_F01_QRY44_RST_PIN_MASK) >> 4;
+ }
+ }
+
+ if (props->has_tool_id_query) {
+ error = rmi_read_block(rmi_dev, query_addr, props->tool_id,
+ RMI_TOOL_ID_LENGTH);
+ if (error < 0)
+ dev_warn(&fn->dev, "Failed to read F01_RMI_QUERY45, code: %d.\n",
+ error);
+ /* This is a so-called "packet register", so address map
+ * increments only by one. */
+ query_addr++;
+ props->tool_id[RMI_TOOL_ID_LENGTH] = '\0';
+ }
+
+ if (props->has_fw_revision_query) {
+ error = rmi_read_block(rmi_dev, query_addr, props->fw_revision,
+ RMI_FW_REVISION_LENGTH);
+ if (error < 0)
+ dev_warn(&fn->dev, "Failed to read F01_RMI_QUERY46, code: %d.\n",
+ error);
+ /* This is a so-called "packet register", so address map
+ * increments only by one. */
+ query_addr++;
+ props->tool_id[RMI_FW_REVISION_LENGTH] = '\0';
+ }
/* read control register */
- if (data->properties.has_adjustable_doze) {
+ if (props->has_adjustable_doze) {
data->doze_interval_addr = ctrl_base_addr;
ctrl_base_addr++;
@@ -1103,7 +420,7 @@ static int rmi_f01_initialize(struct rmi_function *fn)
}
}
- if (data->properties.has_adjustable_doze_holdoff) {
+ if (props->has_adjustable_doze_holdoff) {
data->doze_holdoff_addr = ctrl_base_addr;
ctrl_base_addr++;
@@ -1133,27 +450,20 @@ static int rmi_f01_initialize(struct rmi_function *fn)
goto error_exit;
}
- driver_data->f01_bootloader_mode =
- RMI_F01_STATUS_BOOTLOADER(data->device_status);
- if (driver_data->f01_bootloader_mode)
- dev_warn(&rmi_dev->dev,
- "WARNING: RMI4 device is in bootloader mode!\n");
-
-
if (RMI_F01_STATUS_UNCONFIGURED(data->device_status)) {
- dev_err(&fn->dev,
- "Device was reset during configuration process, status: %#02x!\n",
- RMI_F01_STATUS_CODE(data->device_status));
+ dev_err(&fn->dev, "Device reset during configuration process, status: %#02x!\n",
+ RMI_F01_STATUS_CODE(data->device_status));
error = -EINVAL;
goto error_exit;
}
- error = setup_debugfs(fn);
- if (error)
- dev_warn(&fn->dev, "Failed to setup debugfs, error: %d.\n",
- error);
+ driver_data->f01_bootloader_mode =
+ RMI_F01_STATUS_BOOTLOADER(data->device_status);
+ if (RMI_F01_STATUS_BOOTLOADER(data->device_status))
+ dev_warn(&rmi_dev->dev,
+ "WARNING: RMI4 device is in bootloader mode!\n");
- return 0;
+ return error;
error_exit:
kfree(data);
@@ -1166,36 +476,33 @@ static int rmi_f01_config(struct rmi_function *fn)
int retval;
retval = rmi_write_block(fn->rmi_dev, fn->fd.control_base_addr,
- &data->device_control.ctrl0,
- sizeof(data->device_control.ctrl0));
+ &data->device_control.ctrl0,
+ sizeof(data->device_control.ctrl0));
if (retval < 0) {
dev_err(&fn->dev, "Failed to write device_control.reg.\n");
return retval;
}
retval = rmi_write_block(fn->rmi_dev, data->interrupt_enable_addr,
- data->device_control.interrupt_enable,
- sizeof(u8) * data->num_of_irq_regs);
+ data->device_control.interrupt_enable,
+ sizeof(u8)*(data->num_of_irq_regs));
if (retval < 0) {
dev_err(&fn->dev, "Failed to write interrupt enable.\n");
return retval;
}
- if (data->properties.has_lts) {
- retval = rmi_write_block(fn->rmi_dev, data->doze_interval_addr,
- &data->device_control.doze_interval,
- sizeof(u8));
+
+ if (data->properties.has_adjustable_doze) {
+ retval = rmi_write(fn->rmi_dev,
+ data->doze_interval_addr,
+ data->device_control.doze_interval);
if (retval < 0) {
dev_err(&fn->dev, "Failed to write doze interval.\n");
return retval;
}
- }
-
- if (data->properties.has_adjustable_doze) {
- retval = rmi_write_block(fn->rmi_dev,
- data->wakeup_threshold_addr,
- &data->device_control.wakeup_threshold,
- sizeof(u8));
+ retval = rmi_write(
+ fn->rmi_dev, data->wakeup_threshold_addr,
+ data->device_control.wakeup_threshold);
if (retval < 0) {
dev_err(&fn->dev, "Failed to write wakeup threshold.\n");
return retval;
@@ -1203,9 +510,9 @@ static int rmi_f01_config(struct rmi_function *fn)
}
if (data->properties.has_adjustable_doze_holdoff) {
- retval = rmi_write_block(fn->rmi_dev, data->doze_holdoff_addr,
- &data->device_control.doze_holdoff,
- sizeof(u8));
+ retval = rmi_write(fn->rmi_dev,
+ data->doze_holdoff_addr,
+ data->device_control.doze_holdoff);
if (retval < 0) {
dev_err(&fn->dev, "Failed to write doze holdoff.\n");
return retval;
@@ -1221,51 +528,40 @@ static int rmi_f01_probe(struct rmi_function *fn)
int error;
error = rmi_f01_alloc_memory(fn, driver_data->num_of_irq_regs);
- if (error)
+ if (error < 0)
return error;
error = rmi_f01_initialize(fn);
- if (error)
- return error;
-
- error = sysfs_create_group(&fn->dev.kobj, &rmi_fn_01_attr_group);
- if (error)
+ if (error < 0)
return error;
return 0;
}
-static void rmi_f01_remove(struct rmi_function *fn)
-{
- teardown_debugfs(fn->data);
- sysfs_remove_group(&fn->dev.kobj, &rmi_fn_01_attr_group);
-}
-
#ifdef CONFIG_PM_SLEEP
static int rmi_f01_suspend(struct device *dev)
{
struct rmi_function *fn = to_rmi_function(dev);
struct rmi_device *rmi_dev = fn->rmi_dev;
struct f01_data *data = fn->data;
- int error;
+ int error = 0;
data->old_nosleep = data->device_control.ctrl0 &
- RMI_F01_CRTL0_NOSLEEP_BIT;
+ RMI_F01_CRTL0_NOSLEEP_BIT;
data->device_control.ctrl0 &= ~RMI_F01_CRTL0_NOSLEEP_BIT;
data->device_control.ctrl0 &= ~RMI_F01_CTRL0_SLEEP_MODE_MASK;
data->device_control.ctrl0 |= RMI_SLEEP_MODE_SENSOR_SLEEP;
error = rmi_write_block(rmi_dev,
- fn->fd.control_base_addr,
- &data->device_control.ctrl0,
- sizeof(data->device_control.ctrl0));
+ fn->fd.control_base_addr,
+ &data->device_control.ctrl0,
+ sizeof(data->device_control.ctrl0));
if (error < 0) {
dev_err(&fn->dev, "Failed to write sleep mode. Code: %d.\n",
error);
if (data->old_nosleep)
- data->device_control.ctrl0 |=
- RMI_F01_CRTL0_NOSLEEP_BIT;
+ data->device_control.ctrl0 |= RMI_F01_CRTL0_NOSLEEP_BIT;
data->device_control.ctrl0 &= ~RMI_F01_CTRL0_SLEEP_MODE_MASK;
data->device_control.ctrl0 |= RMI_SLEEP_MODE_NORMAL;
return error;
@@ -1289,7 +585,7 @@ static int rmi_f01_resume(struct device *dev)
error = rmi_write_block(rmi_dev, fn->fd.control_base_addr,
&data->device_control.ctrl0,
- sizeof(data->device_control.ctrl0));
+ sizeof(data->device_control.ctrl0));
if (error < 0) {
dev_err(&fn->dev,
"Failed to restore normal operation. Code: %d.\n",
@@ -1304,7 +600,7 @@ static int rmi_f01_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(rmi_f01_pm_ops, rmi_f01_suspend, rmi_f01_resume);
static int rmi_f01_attention(struct rmi_function *fn,
- unsigned long *irq_bits)
+ unsigned long *irq_bits)
{
struct rmi_device *rmi_dev = fn->rmi_dev;
struct f01_data *data = fn->data;
@@ -1317,7 +613,6 @@ static int rmi_f01_attention(struct rmi_function *fn,
retval);
return retval;
}
-
if (RMI_F01_STATUS_UNCONFIGURED(data->device_status)) {
dev_warn(&fn->dev, "Device reset detected.\n");
retval = rmi_dev->driver->reset_handler(rmi_dev);
@@ -1327,29 +622,18 @@ static int rmi_f01_attention(struct rmi_function *fn,
return 0;
}
-static struct rmi_function_handler rmi_f01_handler = {
+struct rmi_function_driver rmi_f01_driver = {
.driver = {
.name = "rmi_f01",
.pm = &rmi_f01_pm_ops,
/*
- * Do not allow user unbinding F01 as it is critical
+ * Do not allow user unbinding of F01 as it is a critical
* function.
*/
.suppress_bind_attrs = true,
},
- .func = 0x01,
- .probe = rmi_f01_probe,
- .remove = rmi_f01_remove,
- .config = rmi_f01_config,
- .attention = rmi_f01_attention,
+ .func = FUNCTION_NUMBER,
+ .probe = rmi_f01_probe,
+ .config = rmi_f01_config,
+ .attention = rmi_f01_attention,
};
-
-int __init rmi_register_f01_handler(void)
-{
- return rmi_register_function_handler(&rmi_f01_handler);
-}
-
-void rmi_unregister_f01_handler(void)
-{
- rmi_unregister_function_handler(&rmi_f01_handler);
-}
diff --git a/drivers/input/rmi4/rmi_f01.h b/drivers/input/rmi4/rmi_f01.h
new file mode 100644
index 0000000..bfd0dcf
--- /dev/null
+++ b/drivers/input/rmi4/rmi_f01.h
@@ -0,0 +1,269 @@
+/*
+ * Copyright (c) 2012 Synaptics Incorporated
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#ifndef _RMI_F01_H
+#define _RMI_F01_H
+
+#define RMI_PRODUCT_ID_LENGTH 10
+
+#define RMI_DATE_CODE_LENGTH 3
+
+/* Force a firmware reset of the sensor */
+#define RMI_F01_CMD_DEVICE_RESET 1
+
+#define F01_SERIALIZATION_SIZE 7
+
+/* Various F01_RMI_QueryX bits */
+
+#define RMI_F01_QRY1_CUSTOM_MAP (1 << 0)
+#define RMI_F01_QRY1_NON_COMPLIANT (1 << 1)
+#define RMI_F01_QRY1_HAS_LTS (1 << 2)
+#define RMI_F01_QRY1_HAS_SENSOR_ID (1 << 3)
+#define RMI_F01_QRY1_HAS_CHARGER_INP (1 << 4)
+#define RMI_F01_QRY1_HAS_ADJ_DOZE (1 << 5)
+#define RMI_F01_QRY1_HAS_ADJ_DOZE_HOFF (1 << 6)
+#define RMI_F01_QRY1_HAS_PROPS_2 (1 << 7)
+
+#define RMI_F01_QRY5_YEAR_MASK 0x1f
+#define RMI_F01_QRY6_MONTH_MASK 0x0f
+#define RMI_F01_QRY7_DAY_MASK 0x1f
+
+#define RMI_F01_QRY2_PRODINFO_MASK 0x7f
+
+#define RMI_F01_BASIC_QUERY_LEN 21 /* From Query 00 through 20 */
+
+#define RMI_F01_QRY21_SLAVE_ROWS_MASK 0x07
+#define RMI_F01_QRY21_SLAVE_COLUMNS_MASK 0x38
+
+#define RMI_F01_LTS_RESERVED_SIZE 19
+
+#define RMI_F01_QRY42_DS4_QUERIES (1 << 0)
+#define RMI_F01_QRY42_MULTI_PHYS (1 << 1)
+#define RMI_F01_QRY42_GUEST (1 << 2)
+#define RMI_F01_QRY42_SWR (1 << 3)
+#define RMI_F01_QRY42_NOMINAL_REPORT (1 << 4)
+#define RMI_F01_QRY42_RECAL_INTERVAL (1 << 5)
+
+#define RMI_F01_QRY43_01_PACKAGE_ID (1 << 0)
+#define RMI_F01_QRY43_01_BUILD_ID (1 << 1)
+#define RMI_F01_QRY43_01_RESET (1 << 2)
+#define RMI_F01_QRY43_01_MASK_REV (1 << 3)
+
+#define RMI_F01_QRY43_02_I2C_CTL (1 << 0)
+#define RMI_F01_QRY43_02_SPI_CTL (1 << 1)
+#define RMI_F01_QRY43_02_ATTN_CTL (1 << 2)
+#define RMI_F01_QRY43_02_WIN8 (1 << 3)
+#define RMI_F01_QRY43_02_TIMESTAMP (1 << 4)
+
+#define RMI_F01_QRY43_03_TOOL_ID (1 << 0)
+#define RMI_F01_QRY43_03_FW_REVISION (1 << 1)
+
+#define RMI_F01_QRY44_RST_ENABLED (1 << 0)
+#define RMI_F01_QRY44_RST_POLARITY (1 << 1)
+#define RMI_F01_QRY44_PULLUP_ENABLED (1 << 2)
+#define RMI_F01_QRY44_RST_PIN_MASK 0xF0
+
+#define RMI_TOOL_ID_LENGTH 16
+#define RMI_FW_REVISION_LENGTH 16
+
+struct f01_basic_properties {
+ u8 manufacturer_id;
+ bool has_lts;
+ bool has_sensor_id;
+ bool has_adjustable_doze;
+ bool has_adjustable_doze_holdoff;
+ bool has_query42;
+ char dom[11]; /* YYYY/MM/DD + '\0' */
+ u8 product_id[RMI_PRODUCT_ID_LENGTH + 1];
+ u16 productinfo;
+
+ /* These are meaningful only if has_lts is true. */
+ u8 slave_asic_rows;
+ u8 slave_asic_columns;
+
+ /* This is meaningful only if has_sensor_id is true. */
+ u8 sensor_id;
+
+ /* These are meaningful only if has_query42 is true. */
+ bool has_ds4_queries;
+ bool has_multi_physical;
+ bool has_guest;
+ bool has_swr;
+ bool has_nominal_report_rate;
+ bool has_recalibration_interval;
+
+ /* Tells how many of the Query43.xx registers are present.
+ */
+ u8 ds4_query_length;
+
+ /* Query 43.1 */
+ bool has_package_id_query;
+ bool has_build_id_query;
+ bool has_reset_query;
+ bool has_maskrev_query;
+
+ /* Query 43.2 */
+ bool has_i2c_control;
+ bool has_spi_control;
+ bool has_attn_control;
+ bool has_win8_vendor_info;
+ bool has_timestamp;
+
+ /* Query 43.3 */
+ bool has_tool_id_query;
+ bool has_fw_revision_query;
+
+ /* Query 44 */
+ bool reset_enabled;
+ bool reset_polarity;
+ bool pullup_enabled;
+ u8 reset_pin;
+
+ /* Query 45 */
+ char tool_id[RMI_TOOL_ID_LENGTH + 1];
+
+ /* Query 46 */
+ char fw_revision[RMI_FW_REVISION_LENGTH + 1];
+};
+
+/** The status code field reports the most recent device status event.
+ * @no_error - should be self explanatory.
+ * @reset_occurred - no other event was seen since the last reset.
+ * @invalid_config - general device configuration has a problem.
+ * @device_failure - general device hardware failure.
+ * @config_crc - configuration failed memory self check.
+ * @firmware_crc - firmware failed memory self check.
+ * @crc_in_progress - bootloader is currently testing config and fw areas.
+ */
+enum rmi_device_status {
+ no_error = 0x00,
+ reset_occurred = 0x01,
+ invalid_config = 0x02,
+ device_failure = 0x03,
+ config_crc = 0x04,
+ firmware_crc = 0x05,
+ crc_in_progress = 0x06
+};
+
+
+/* F01 device status bits */
+
+/* Most recent device status event */
+#define RMI_F01_STATUS_CODE(status) ((status) & 0x0f)
+/* Indicates that flash programming is enabled (bootloader mode). */
+#define RMI_F01_STATUS_BOOTLOADER(status) (!!((status) & 0x40))
+/* The device has lost its configuration for some reason. */
+#define RMI_F01_STATUS_UNCONFIGURED(status) (!!((status) & 0x80))
+
+
+
+/* Control register bits */
+
+/*
+* Sleep mode controls power management on the device and affects all
+* functions of the device.
+*/
+#define RMI_F01_CTRL0_SLEEP_MODE_MASK 0x03
+
+#define RMI_SLEEP_MODE_NORMAL 0x00
+#define RMI_SLEEP_MODE_SENSOR_SLEEP 0x01
+#define RMI_SLEEP_MODE_RESERVED0 0x02
+#define RMI_SLEEP_MODE_RESERVED1 0x03
+
+#define RMI_IS_VALID_SLEEPMODE(mode) \
+(mode >= RMI_SLEEP_MODE_NORMAL && mode <= RMI_SLEEP_MODE_RESERVED1)
+
+/*
+ * This bit disables whatever sleep mode may be selected by the sleep_mode
+ * field and forces the device to run at full power without sleeping.
+ */
+#define RMI_F01_CRTL0_NOSLEEP_BIT (1 << 2)
+
+/*
+ * When this bit is set, the touch controller employs a noise-filtering
+ * algorithm designed for use with a connected battery charger.
+ */
+#define RMI_F01_CRTL0_CHARGER_BIT (1 << 5)
+
+/*
+ * Sets the report rate for the device. The effect of this setting is
+ * highly product dependent. Check the spec sheet for your particular
+ * touch sensor.
+ */
+#define RMI_F01_CRTL0_REPORTRATE_BIT (1 << 6)
+
+/*
+ * Written by the host as an indicator that the device has been
+ * successfully configured.
+ */
+#define RMI_F01_CRTL0_CONFIGURED_BIT (1 << 7)
+
+/**
+ * @ctrl0 - see documentation in rmi_f01.h.
+ * @interrupt_enable - A mask of per-function interrupts on the touch sensor.
+ * @doze_interval - controls the interval between checks for finger presence
+ * when the touch sensor is in doze mode, in units of 10ms.
+ * @wakeup_threshold - controls the capacitance threshold at which the touch
+ * sensor will decide to wake up from that low power state.
+ * @doze_holdoff - controls how long the touch sensor waits after the last
+ * finger lifts before entering the doze state, in units of 100ms.
+ */
+struct f01_device_control {
+ u8 ctrl0;
+ u8 *interrupt_enable;
+ u8 doze_interval;
+ u8 wakeup_threshold;
+ u8 doze_holdoff;
+};
+
+
+/*
+ *
+ * @serialization - 7 bytes of device serialization data. The meaning of
+ * these bytes varies from product to product, consult your product spec sheet.
+ */
+struct f01_data {
+ struct f01_device_control device_control;
+ struct mutex control_mutex;
+
+ u8 device_status;
+
+ struct f01_basic_properties properties;
+ u8 serialization[F01_SERIALIZATION_SIZE];
+ u8 product_id[RMI_PRODUCT_ID_LENGTH+1];
+
+ u16 package_id;
+ u16 package_rev;
+ u32 build_id;
+
+ u16 interrupt_enable_addr;
+ u16 doze_interval_addr;
+ u16 wakeup_threshold_addr;
+ u16 doze_holdoff_addr;
+
+ int irq_count;
+ int num_of_irq_regs;
+
+#ifdef CONFIG_PM
+ bool suspended;
+ bool old_nosleep;
+#endif
+};
+
+#endif
^ permalink raw reply related
* [PATCH 04/04] input synaptics-rmi4: RMI4 F11 2D sensing
From: Christopher Heiny @ 2013-11-13 23:39 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Linux Input, Christopher Heiny, Andrew Duggan, Vincent Huang,
Vivian Ly, Daniel Rosenberg, Jean Delvare, Joerie de Gram,
Linus Walleij
In-Reply-To: <1384385972-1686-1-git-send-email-cheiny@synaptics.com>
* eliminate packed struct bitfield definitions.
* removes sysfs/debugfs implementations.
* refactors register definitions into rmi_f11.h for use by external modules
implementing sysfs/debugfs control and debug functions.
Signed-off-by: Christopher Heiny <cheiny@synaptics.com>
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: Linus Walleij <linus.walleij@stericsson.com>
Cc: Joeri de Gram <j.de.gram@gmail.com>
---
drivers/input/rmi4/rmi_f11.c | 1788 ++++++++----------------------------------
drivers/input/rmi4/rmi_f11.h | 547 +++++++++++++
2 files changed, 874 insertions(+), 1461 deletions(-)
diff --git a/drivers/input/rmi4/rmi_f11.c b/drivers/input/rmi4/rmi_f11.c
index 017c8ff..83a699d 100644
--- a/drivers/input/rmi4/rmi_f11.c
+++ b/drivers/input/rmi4/rmi_f11.c
@@ -8,19 +8,22 @@
*/
#define FUNCTION_DATA f11_data
+#define FUNCTION_NUMBER 0x11
#include <linux/kernel.h>
-#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/fs.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/kconfig.h>
#include <linux/rmi.h>
#include <linux/slab.h>
+#include <linux/uaccess.h>
+
#include "rmi_driver.h"
+#include "rmi_f11.h"
-#define F11_MAX_NUM_OF_SENSORS 8
#define F11_MAX_NUM_OF_FINGERS 10
#define F11_MAX_NUM_OF_TOUCH_SHAPES 16
@@ -38,968 +41,21 @@
#define DEFAULT_MAX_ABS_MT_ORIENTATION 1
#define DEFAULT_MIN_ABS_MT_TRACKING_ID 1
#define DEFAULT_MAX_ABS_MT_TRACKING_ID 10
-#define NAME_BUFFER_SIZE 256
-#define FUNCTION_NUMBER 0x11
-
-/** A note about RMI4 F11 register structure.
- *
- * There may be one or more individual 2D touch surfaces associated with an
- * instance for F11. For example, a handheld device might have a touchscreen
- * display on the front, and a touchpad on the back. F11 represents these touch
- * surfaces as individual sensors, up to 7 on a given RMI4 device.
- *
- * The properties for
- * a given sensor are described by its query registers. The number of query
- * registers and the layout of their contents are described by the F11 device
- * queries as well as the per-sensor query information. The query registers
- * for sensor[n+1] immediately follow those for sensor[n], so the start address
- * of the sensor[n+1] queries can only be computed if you know the size of the
- * sensor[n] queries. Because each of the sensors may have different
- * properties, the size of the query registers for each sensor must be
- * calculated on a sensor by sensor basis.
- *
- * Similarly, each sensor has control registers that govern its behavior. The
- * size and layout of the control registers for a given sensor can be determined
- * by parsing that sensors query registers. The control registers for
- * sensor[n+1] immediately follow those for sensor[n], so you can only know
- * the start address for the sensor[n+1] controls if you know the size (and
- * location) of the sensor[n] controls.
- *
- * And in a likewise fashion, each sensor has data registers where it reports
- * its touch data and other interesting stuff. The size and layout of a
- * sensors data registers must be determined by parsing its query registers.
- * The data registers for sensor[n+1] immediately follow those for sensor[n],
- * so you can only know the start address for the sensor[n+1] controls if you
- * know the size (and location) of the sensor[n] controls.
- *
- * The short story is that we need to read and parse a lot of query
- * registers in order to determine the attributes of a sensor[0]. Then
- * we need to use that data to compute the size of the control and data
- * registers for sensor[0]. Once we have that figured out, we can then do
- * the same thing for each subsequent sensor.
- *
- * The end result is that we have a number of structs that aren't used to
- * directly generate the input events, but their size, location and contents
- * are critical to determining where the data we are interested in lives.
- *
- * At this time, the driver does not yet comprehend all possible F11
- * configuration options, but it should be sufficient to cover 99% of RMI4 F11
- * devices currently in the field.
- */
-
-/**
- * @rezero - writing 1 to this will cause the sensor to calibrate to the
- * current capacitive state.
- */
-struct f11_2d_commands {
- u8 rezero:1;
- u8 reserved:7;
-} __attribute__((__packed__));
-
-/** This query is always present, and is on a per device basis. All other
- * queries are on a per-sensor basis.
- *
- * @nbr_of_sensors - the number of 2D sensors on the touch device.
- * @has_query9 - indicates the F11_2D_Query9 register exists.
- * @has_query11 - indicates the F11_2D_Query11 register exists.
- * @has_query12 - indicates the F11_2D_Query12 register exists.
- */
-struct f11_2d_device_query {
- u8 nbr_of_sensors:3;
- u8 has_query9:1;
- u8 has_query11:1;
- u8 has_query12:1;
- u8 has_query27:1;
- u8 has_query28:1;
-} __attribute__((__packed__));
-
-/** Query registers 1 through 4 are always present.
- * @number_of_fingers - describes the maximum number of fingers the 2-D sensor
- * supports.
- * @has_rel - the sensor supports relative motion reporting.
- * @has_abs - the sensor supports absolute poition reporting.
- * @has_gestures - the sensor supports gesture reporting.
- * @has_sensitivity_adjust - the sensor supports a global sensitivity
- * adjustment.
- * @configurable - the sensor supports various configuration options.
- * @num_of_x_electrodes - the maximum number of electrodes the 2-D sensor
- * supports on the X axis.
- * @num_of_y_electrodes - the maximum number of electrodes the 2-D sensor
- * supports on the Y axis.
- * @max_electrodes - the total number of X and Y electrodes that may be
- * configured.
- */
-struct f11_2d_sensor_info {
- /* query1 */
- u8 number_of_fingers:3;
- u8 has_rel:1;
- u8 has_abs:1;
- u8 has_gestures:1;
- u8 has_sensitivity_adjust:1;
- u8 configurable:1;
- /* query2 */
- u8 num_of_x_electrodes:7;
- u8 reserved_1:1;
- /* query3 */
- u8 num_of_y_electrodes:7;
- u8 reserved_2:1;
- /* query4 */
- u8 max_electrodes:7;
- u8 reserved_3:1;
-} __attribute__((__packed__));
-
-/** Query 5 - this is present if the has_abs bit is set.
- *
- * @abs_data_size - describes the format of data reported by the absolute
- * data source. Only one format (the kind used here) is supported at this
- * time.
- * @has_anchored_finger - then the sensor supports the high-precision second
- * finger tracking provided by the manual tracking and motion sensitivity
- * options.
- * @has_adjust_hyst - the difference between the finger release threshold and
- * the touch threshold.
- * @has_dribble - the sensor supports the generation of dribble interrupts,
- * which may be enabled or disabled with the dribble control bit.
- * @has_bending_correction - Bending related data registers 28 and 36, and
- * control register 52..57 are present.
- * @has_large_object_suppression - control register 58 and data register 28
- * exist.
- * @has_jitter_filter - query 13 and control 73..76 exist.
- */
-struct f11_2d_abs_info {
- u8 abs_data_size:2;
- u8 has_anchored_finger:1;
- u8 has_adj_hyst:1;
- u8 has_dribble:1;
- u8 has_bending_correction:1;
- u8 has_large_object_suppression:1;
- u8 has_jitter_filter:1;
-} __attribute__((__packed__));
-
-/** Gesture information queries 7 and 8 are present if has_gestures bit is set.
- *
- * @has_single_tap - a basic single-tap gesture is supported.
- * @has_tap_n_hold - tap-and-hold gesture is supported.
- * @has_double_tap - double-tap gesture is supported.
- * @has_early_tap - early tap is supported and reported as soon as the finger
- * lifts for any tap event that could be interpreted as either a single tap
- * or as the first tap of a double-tap or tap-and-hold gesture.
- * @has_flick - flick detection is supported.
- * @has_press - press gesture reporting is supported.
- * @has_pinch - pinch gesture detection is supported.
- * @has_palm_det - the 2-D sensor notifies the host whenever a large conductive
- * object such as a palm or a cheek touches the 2-D sensor.
- * @has_rotate - rotation gesture detection is supported.
- * @has_touch_shapes - TouchShapes are supported. A TouchShape is a fixed
- * rectangular area on the sensor that behaves like a capacitive button.
- * @has_scroll_zones - scrolling areas near the sensor edges are supported.
- * @has_individual_scroll_zones - if 1, then 4 scroll zones are supported;
- * if 0, then only two are supported.
- * @has_multi_finger_scroll - the multifinger_scrolling bit will be set when
- * more than one finger is involved in a scrolling action.
- */
-struct f11_2d_gesture_info {
- u8 has_single_tap:1;
- u8 has_tap_n_hold:1;
- u8 has_double_tap:1;
- u8 has_early_tap:1;
- u8 has_flick:1;
- u8 has_press:1;
- u8 has_pinch:1;
- u8 has_chiral:1;
-
- u8 has_palm_det:1;
- u8 has_rotate:1;
- u8 has_touch_shapes:1;
- u8 has_scroll_zones:1;
- u8 has_individual_scroll_zones:1;
- u8 has_multi_finger_scroll:1;
- u8 has_mf_edge_motion:1;
- u8 has_mf_scroll_inertia:1;
-} __attribute__((__packed__));
-
-/** Utility for checking bytes in the gesture info registers. This is done
- * often enough that we put it here to declutter the conditionals.
- */
-static bool has_gesture_bits(const struct f11_2d_gesture_info *info,
- const u8 byte) {
- return ((u8 *) info)[byte] != 0;
-}
-
-/**
- * @has_pen - detection of a stylus is supported and registers F11_2D_Ctrl20
- * and F11_2D_Ctrl21 exist.
- * @has_proximity - detection of fingers near the sensor is supported and
- * registers F11_2D_Ctrl22 through F11_2D_Ctrl26 exist.
- * @has_palm_det_sensitivity - the sensor supports the palm detect sensitivity
- * feature and register F11_2D_Ctrl27 exists.
- * @has_two_pen_thresholds - is has_pen is also set, then F11_2D_Ctrl35 exists.
- * @has_contact_geometry - the sensor supports the use of contact geometry to
- * map absolute X and Y target positions and registers F11_2D_Data18.* through
- * F11_2D_Data27 exist.
- */
-struct f11_2d_query9 {
- u8 has_pen:1;
- u8 has_proximity:1;
- u8 has_palm_det_sensitivity:1;
- u8 has_suppress_on_palm_detect:1;
- u8 has_two_pen_thresholds:1;
- u8 has_contact_geometry:1;
- u8 has_pen_hover_discrimination:1;
- u8 has_pen_filters:1;
-} __attribute__((__packed__));
-
-/** Touch shape info (query 10) is present if has_touch_shapes is set.
- *
- * @nbr_touch_shapes - the total number of touch shapes supported.
- */
-struct f11_2d_ts_info {
- u8 nbr_touch_shapes:5;
- u8 reserved:3;
-} __attribute__((__packed__));
-
-/** Query 11 is present if the has_query11 bit is set in query 0.
- *
- * @has_z_tuning - if set, the sensor supports Z tuning and registers
- * F11_2D_Ctrl29 through F11_2D_Ctrl33 exist.
- * @has_algorithm_selection - controls choice of noise suppression algorithm
- * @has_w_tuning - the sensor supports Wx and Wy scaling and registers
- * F11_2D_Ctrl36 through F11_2D_Ctrl39 exist.
- * @has_pitch_info - the X and Y pitches of the sensor electrodes can be
- * configured and registers F11_2D_Ctrl40 and F11_2D_Ctrl41 exist.
- * @has_finger_size - the default finger width settings for the
- * sensor can be configured and registers F11_2D_Ctrl42 through F11_2D_Ctrl44
- * exist.
- * @has_segmentation_aggressiveness - the sensor’s ability to distinguish
- * multiple objects close together can be configured and register F11_2D_Ctrl45
- * exists.
- * @has_XY_clip - the inactive outside borders of the sensor can be
- * configured and registers F11_2D_Ctrl46 through F11_2D_Ctrl49 exist.
- * @has_drumming_filter - the sensor can be configured to distinguish
- * between a fast flick and a quick drumming movement and registers
- * F11_2D_Ctrl50 and F11_2D_Ctrl51 exist.
- */
-struct f11_2d_query11 {
- u8 has_z_tuning:1;
- u8 has_algorithm_selection:1;
- u8 has_w_tuning:1;
- u8 has_pitch_info:1;
- u8 has_finger_size:1;
- u8 has_segmentation_aggressiveness:1;
- u8 has_XY_clip:1;
- u8 has_drumming_filter:1;
-} __attribute__((__packed__));
-
-/**
- * @has_gapless_finger - control registers relating to gapless finger are
- * present.
- * @has_gapless_finger_tuning - additional control and data registers relating
- * to gapless finger are present.
- * @has_8bit_w - larger W value reporting is supported.
- * @has_adjustable_mapping - TBD
- * @has_info2 - the general info query14 is present
- * @has_physical_props - additional queries describing the physical properties
- * of the sensor are present.
- * @has_finger_limit - indicates that F11 Ctrl 80 exists.
- * @has_linear_coeff - indicates that F11 Ctrl 81 exists.
- */
-struct f11_2d_query12 {
- u8 has_gapless_finger:1;
- u8 has_gapless_finger_tuning:1;
- u8 has_8bit_w:1;
- u8 has_adjustable_mapping:1;
- u8 has_info2:1;
- u8 has_physical_props:1;
- u8 has_finger_limit:1;
- u8 has_linear_coeff_2:1;
-} __attribute__((__packed__));
-
-/** This register is present if Query 5's has_jitter_filter bit is set.
- * @jitter_window_size - used by Design Studio 4.
- * @jitter_filter_type - used by Design Studio 4.
- */
-struct f11_2d_query13 {
- u8 jtter_window_size:5;
- u8 jitter_filter_type:2;
- u8 reserved:1;
-} __attribute__((__packed__));
-
-/** This register is present if query 12's has_general_info2 flag is set.
- *
- * @light_control - Indicates what light/led control features are present, if
- * any.
- * @is_clear - if set, this is a clear sensor (indicating direct pointing
- * application), otherwise it's opaque (indicating indirect pointing).
- * @clickpad_props - specifies if this is a clickpad, and if so what sort of
- * mechanism it uses
- * @mouse_buttons - specifies the number of mouse buttons present (if any).
- * @has_advanced_gestures - advanced driver gestures are supported.
- */
-struct f11_2d_query14 {
- u8 light_control:2;
- u8 is_clear:1;
- u8 clickpad_props:2;
- u8 mouse_buttons:2;
- u8 has_advanced_gestures:1;
-} __attribute__((__packed__));
-
-#define F11_LIGHT_CTL_NONE 0x00
-#define F11_LUXPAD 0x01
-#define F11_DUAL_MODE 0x02
-
-#define F11_NOT_CLICKPAD 0x00
-#define F11_HINGED_CLICKPAD 0x01
-#define F11_UNIFORM_CLICKPAD 0x02
-
-/** See notes above for information about specific query register sets.
- */
-struct f11_2d_sensor_queries {
- struct f11_2d_sensor_info info;
- struct f11_2d_abs_info abs_info;
- u8 f11_2d_query6;
- struct f11_2d_gesture_info gesture_info;
- struct f11_2d_query9 query9;
- struct f11_2d_ts_info ts_info;
- struct f11_2d_query11 features_1;
- struct f11_2d_query12 features_2;
- struct f11_2d_query13 jitter_filter;
- struct f11_2d_query14 info_2;
-};
-
-/**
- * @reporting_mode - controls how often finger position data is reported.
- * @abs_pos_filt - when set, enables various noise and jitter filtering
- * algorithms for absolute reports.
- * @rel_pos_filt - when set, enables various noise and jitter filtering
- * algorithms for relative reports.
- * @rel_ballistics - enables ballistics processing for the relative finger
- * motion on the 2-D sensor.
- * @dribble - enables the dribbling feature.
- * @report_beyond_clip - when this is set, fingers outside the active area
- * specified by the x_clip and y_clip registers will be reported, but with
- * reported finger position clipped to the edge of the active area.
- * @palm_detect_thresh - the threshold at which a wide finger is considered a
- * palm. A value of 0 inhibits palm detection.
- * @motion_sensitivity - specifies the threshold an anchored finger must move
- * before it is considered no longer anchored. High values mean more
- * sensitivity.
- * @man_track_en - for anchored finger tracking, whether the host (1) or the
- * device (0) determines which finger is the tracked finger.
- * @man_tracked_finger - when man_track_en is 1, specifies whether finger 0 or
- * finger 1 is the tracked finger.
- * @delta_x_threshold - 2-D position update interrupts are inhibited unless
- * the finger moves more than a certain threshold distance along the X axis.
- * @delta_y_threshold - 2-D position update interrupts are inhibited unless
- * the finger moves more than a certain threshold distance along the Y axis.
- * @velocity - When rel_ballistics is set, this register defines the
- * velocity ballistic parameter applied to all relative motion events.
- * @acceleration - When rel_ballistics is set, this register defines the
- * acceleration ballistic parameter applied to all relative motion events.
- * @sensor_max_x_pos - the maximum X coordinate reported by the sensor.
- * @sensor_max_y_pos - the maximum Y coordinate reported by the sensor.
- */
-struct f11_2d_ctrl0_9 {
- /* F11_2D_Ctrl0 */
- u8 reporting_mode:3;
- u8 abs_pos_filt:1;
- u8 rel_pos_filt:1;
- u8 rel_ballistics:1;
- u8 dribble:1;
- u8 report_beyond_clip:1;
- /* F11_2D_Ctrl1 */
- u8 palm_detect_thres:4;
- u8 motion_sensitivity:2;
- u8 man_track_en:1;
- u8 man_tracked_finger:1;
- /* F11_2D_Ctrl2 and 3 */
- u8 delta_x_threshold:8;
- u8 delta_y_threshold:8;
- /* F11_2D_Ctrl4 and 5 */
- u8 velocity:8;
- u8 acceleration:8;
- /* F11_2D_Ctrl6 thru 9 */
- u16 sensor_max_x_pos:12;
- u8 ctrl7_reserved:4;
- u16 sensor_max_y_pos:12;
- u8 ctrl9_reserved:4;
-} __attribute__((__packed__));
-
-/**
- * @single_tap_int_enable - enable tap gesture recognition.
- * @tap_n_hold_int_enable - enable tap-and-hold gesture recognition.
- * @double_tap_int_enable - enable double-tap gesture recognition.
- * @early_tap_int_enable - enable early tap notification.
- * @flick_int_enable - enable flick detection.
- * @press_int_enable - enable press gesture recognition.
- * @pinch_int_enable - enable pinch detection.
- */
-struct f11_2d_ctrl10 {
- u8 single_tap_int_enable:1;
- u8 tap_n_hold_int_enable:1;
- u8 double_tap_int_enable:1;
- u8 early_tap_int_enable:1;
- u8 flick_int_enable:1;
- u8 press_int_enable:1;
- u8 pinch_int_enable:1;
- u8 reserved:1;
-} __attribute__((__packed__));
-
-/**
- * @palm_detect_int_enable - enable palm detection feature.
- * @rotate_int_enable - enable rotate gesture detection.
- * @touch_shape_int_enable - enable the TouchShape feature.
- * @scroll_zone_int_enable - enable scroll zone reporting.
- * @multi_finger_scroll_int_enable - enable the multfinger scroll feature.
- */
-struct f11_2d_ctrl11 {
- u8 palm_detect_int_enable:1;
- u8 rotate_int_enable:1;
- u8 touch_shape_int_enable:1;
- u8 scroll_zone_int_enable:1;
- u8 multi_finger_scroll_int_enable:1;
- u8 reserved:3;
-} __attribute__((__packed__));
-
-/**
- * @sens_adjustment - allows a host to alter the overall sensitivity of a
- * 2-D sensor. A positive value in this register will make the sensor more
- * sensitive than the factory defaults, and a negative value will make it
- * less sensitive.
- * @hyst_adjustment - increase the touch/no-touch hysteresis by 2 Z-units for
- * each one unit increment in this setting.
- */
-struct f11_2d_ctrl14 {
- s8 sens_adjustment:5;
- u8 hyst_adjustment:3;
-} __attribute__((__packed__));
-
-/**
- * @max_tap_time - the maximum duration of a tap, in 10-millisecond units.
- */
-struct f11_2d_ctrl15 {
- u8 max_tap_time:8;
-} __attribute__((__packed__));
-
-/**
- * @min_press_time - The minimum duration required for stationary finger(s) to
- * generate a press gesture, in 10-millisecond units.
- */
-struct f11_2d_ctrl16 {
- u8 min_press_time:8;
-} __attribute__((__packed__));
-
-/**
- * @max_tap_distance - Determines the maximum finger movement allowed during
- * a tap, in 0.1-millimeter units.
- */
-struct f11_2d_ctrl17 {
- u8 max_tap_distance:8;
-} __attribute__((__packed__));
-
-/**
- * @min_flick_distance - the minimum finger movement for a flick gesture,
- * in 1-millimeter units.
- * @min_flick_speed - the minimum finger speed for a flick gesture, in
- * 10-millimeter/second units.
- */
-struct f11_2d_ctrl18_19 {
- u8 min_flick_distance:8;
- u8 min_flick_speed:8;
-} __attribute__((__packed__));
-
-/**
- * @pen_detect_enable - enable reporting of stylus activity.
- * @pen_jitter_filter_enable - Setting this enables the stylus anti-jitter
- * filter.
- * @pen_z_threshold - This is the stylus-detection lower threshold. Smaller
- * values result in higher sensitivity.
- */
-struct f11_2d_ctrl20_21 {
- u8 pen_detect_enable:1;
- u8 pen_jitter_filter_enable:1;
- u8 ctrl20_reserved:6;
- u8 pen_z_threshold:8;
-} __attribute__((__packed__));
-
-/**
- * These are not accessible through sysfs yet.
- *
- * @proximity_detect_int_en - enable proximity detection feature.
- * @proximity_jitter_filter_en - enables an anti-jitter filter on proximity
- * data.
- * @proximity_detection_z_threshold - the threshold for finger-proximity
- * detection.
- * @proximity_delta_x_threshold - In reduced-reporting modes, this is the
- * threshold for proximate-finger movement in the direction parallel to the
- * X-axis.
- * @proximity_delta_y_threshold - In reduced-reporting modes, this is the
- * threshold for proximate-finger movement in the direction parallel to the
- * Y-axis.
- * * @proximity_delta_Z_threshold - In reduced-reporting modes, this is the
- * threshold for proximate-finger movement in the direction parallel to the
- * Z-axis.
- */
-struct f11_2d_ctrl22_26 {
- /* control 22 */
- u8 proximity_detect_int_en:1;
- u8 proximity_jitter_filter_en:1;
- u8 f11_2d_ctrl6_b3__7:6;
-
- /* control 23 */
- u8 proximity_detection_z_threshold;
-
- /* control 24 */
- u8 proximity_delta_x_threshold;
-
- /* control 25 */
- u8 proximity_delta_y_threshold;
-
- /* control 26 */
- u8 proximity_delta_z_threshold;
-} __attribute__((__packed__));
-
-/**
- * @palm_detecy_sensitivity - When this value is small, smaller objects will
- * be identified as palms; when this value is large, only larger objects will
- * be identified as palms. 0 represents the factory default.
- * @suppress_on_palm_detect - when set, all F11 interrupts except palm_detect
- * are suppressed while a palm is detected.
- */
-struct f11_2d_ctrl27 {
- s8 palm_detect_sensitivity:4;
- u8 suppress_on_palm_detect:1;
- u8 f11_2d_ctrl27_b5__7:3;
-} __attribute__((__packed__));
-
-/**
- * @multi_finger_scroll_mode - allows choice of multi-finger scroll mode and
- * determines whether and how X or Y displacements are reported.
- * @edge_motion_en - enables the edge_motion feature.
- * @multi_finger_scroll_momentum - controls the length of time that scrolling
- * continues after fingers have been lifted.
- */
-struct f11_2d_ctrl28 {
- u8 multi_finger_scroll_mode:2;
- u8 edge_motion_en:1;
- u8 f11_2d_ctrl28b_3:1;
- u8 multi_finger_scroll_momentum:4;
-} __attribute__((__packed__));
-
-/**
- * @z_touch_threshold - Specifies the finger-arrival Z threshold. Large values
- * may cause smaller fingers to be rejected.
- * @z_touch_hysteresis - Specifies the difference between the finger-arrival
- * Z threshold and the finger-departure Z threshold.
- */
-struct f11_2d_ctrl29_30 {
- u8 z_touch_threshold;
- u8 z_touch_hysteresis;
-} __attribute__((__packed__));
-
-
-struct f11_2d_ctrl {
- struct f11_2d_ctrl0_9 *ctrl0_9;
- u16 ctrl0_9_address;
- struct f11_2d_ctrl10 *ctrl10;
- struct f11_2d_ctrl11 *ctrl11;
- u8 ctrl12_size;
- struct f11_2d_ctrl14 *ctrl14;
- struct f11_2d_ctrl15 *ctrl15;
- struct f11_2d_ctrl16 *ctrl16;
- struct f11_2d_ctrl17 *ctrl17;
- struct f11_2d_ctrl18_19 *ctrl18_19;
- struct f11_2d_ctrl20_21 *ctrl20_21;
- struct f11_2d_ctrl22_26 *ctrl22_26;
- struct f11_2d_ctrl27 *ctrl27;
- struct f11_2d_ctrl28 *ctrl28;
- struct f11_2d_ctrl29_30 *ctrl29_30;
-};
-
-/**
- * @x_msb - top 8 bits of X finger position.
- * @y_msb - top 8 bits of Y finger position.
- * @x_lsb - bottom 4 bits of X finger position.
- * @y_lsb - bottom 4 bits of Y finger position.
- * @w_y - contact patch width along Y axis.
- * @w_x - contact patch width along X axis.
- * @z - finger Z value (proxy for pressure).
- */
-struct f11_2d_data_1_5 {
- u8 x_msb;
- u8 y_msb;
- u8 x_lsb:4;
- u8 y_lsb:4;
- u8 w_y:4;
- u8 w_x:4;
- u8 z;
-} __attribute__((__packed__));
-
-/**
- * @delta_x - relative motion along X axis.
- * @delta_y - relative motion along Y axis.
- */
-struct f11_2d_data_6_7 {
- s8 delta_x;
- s8 delta_y;
-} __attribute__((__packed__));
-
-/**
- * @single_tap - a single tap was recognized.
- * @tap_and_hold - a tap-and-hold gesture was recognized.
- * @double_tap - a double tap gesture was recognized.
- * @early_tap - a tap gesture might be happening.
- * @flick - a flick gesture was detected.
- * @press - a press gesture was recognized.
- * @pinch - a pinch gesture was detected.
- */
-struct f11_2d_data_8 {
- bool single_tap:1;
- bool tap_and_hold:1;
- bool double_tap:1;
- bool early_tap:1;
- bool flick:1;
- bool press:1;
- bool pinch:1;
-} __attribute__((__packed__));
-
-/**
- * @palm_detect - a palm or other large object is in contact with the sensor.
- * @rotate - a rotate gesture was detected.
- * @shape - a TouchShape has been activated.
- * @scrollzone - scrolling data is available.
- * @finger_count - number of fingers involved in the reported gesture.
- */
-struct f11_2d_data_9 {
- bool palm_detect:1;
- bool rotate:1;
- bool shape:1;
- bool scrollzone:1;
- u8 finger_count:3;
-} __attribute__((__packed__));
-
-/**
- * @pinch_motion - when a pinch gesture is detected, this is the change in
- * distance between the two fingers since this register was last read.
- */
-struct f11_2d_data_10 {
- s8 pinch_motion;
-} __attribute__((__packed__));
-
-/**
- * @x_flick_dist - when a flick gesture is detected, the distance of flick
- * gesture in X direction.
- * @y_flick_dist - when a flick gesture is detected, the distance of flick
- * gesture in Y direction.
- * @flick_time - the total time of the flick gesture, in 10ms units.
- */
-struct f11_2d_data_10_12 {
- s8 x_flick_dist;
- s8 y_flick_dist;
- u8 flick_time;
-} __attribute__((__packed__));
-
-/**
- * @motion - when a rotate gesture is detected, the accumulated distance
- * of the rotate motion. Clockwise motion is positive and counterclockwise
- * motion is negative.
- * @finger_separation - when a rotate gesture is detected, the distance
- * between the fingers.
- */
-struct f11_2d_data_11_12 {
- s8 motion;
- u8 finger_separation;
-} __attribute__((__packed__));
-
-/**
- * @shape_n - a bitmask of the currently activate TouchShapes (if any).
- */
-struct f11_2d_data_13 {
- u8 shape_n;
-} __attribute__((__packed__));
-
-/**
- * @horizontal - chiral scrolling distance in the X direction.
- * @vertical - chiral scrolling distance in the Y direction.
- */
-struct f11_2d_data_14_15 {
- s8 horizontal;
- s8 vertical;
-} __attribute__((__packed__));
-
-/**
- * @x_low - scroll zone motion along the lower edge of the sensor.
- * @y_right - scroll zone motion along the right edge of the sensor.
- * @x_upper - scroll zone motion along the upper edge of the sensor.
- * @y_left - scroll zone motion along the left edge of the sensor.
- */
-struct f11_2d_data_14_17 {
- s8 x_low;
- s8 y_right;
- s8 x_upper;
- s8 y_left;
-} __attribute__((__packed__));
-
-struct f11_2d_data {
- u8 *f_state;
- const struct f11_2d_data_1_5 *abs_pos;
- const struct f11_2d_data_6_7 *rel_pos;
- const struct f11_2d_data_8 *gest_1;
- const struct f11_2d_data_9 *gest_2;
- const struct f11_2d_data_10 *pinch;
- const struct f11_2d_data_10_12 *flick;
- const struct f11_2d_data_11_12 *rotate;
- const struct f11_2d_data_13 *shapes;
- const struct f11_2d_data_14_15 *multi_scroll;
- const struct f11_2d_data_14_17 *scroll_zones;
-};
-
-/**
- * @axis_align - controls parameters that are useful in system prototyping
- * and bring up.
- * @sens_query - query registers for this particular sensor.
- * @data - the data reported by this sensor, mapped into a collection of
- * structs.
- * @max_x - The maximum X coordinate that will be reported by this sensor.
- * @max_y - The maximum Y coordinate that will be reported by this sensor.
- * @nbr_fingers - How many fingers can this sensor report?
- * @data_pkt - buffer for data reported by this sensor.
- * @pkt_size - number of bytes in that buffer.
- * @sensor_index - identifies this particular 2D touch sensor
- * @type_a - some early RMI4 2D sensors do not reliably track the finger
- * position when two fingers are on the device. When this is true, we
- * assume we have one of those sensors and report events appropriately.
- * @sensor_type - indicates whether we're touchscreen or touchpad.
- * @input - input device for absolute pointing stream
- * @mouse_input - input device for relative pointing stream.
- * @input_phys - buffer for the absolute phys name for this sensor.
- * @input_phys_mouse - buffer for the relative phys name for this sensor.
- */
-struct f11_2d_sensor {
- struct rmi_f11_2d_axis_alignment axis_align;
- struct f11_2d_sensor_queries sens_query;
- struct f11_2d_data data;
- u16 max_x;
- u16 max_y;
- u8 nbr_fingers;
- u8 *data_pkt;
- int pkt_size;
- u8 sensor_index;
- u32 type_a; /* boolean but debugfs API requires u32 */
- enum rmi_f11_sensor_type sensor_type;
- struct input_dev *input;
- struct input_dev *mouse_input;
- struct rmi_function *fn;
- char input_phys[NAME_BUFFER_SIZE];
- char input_phys_mouse[NAME_BUFFER_SIZE];
-};
-
-/** Data pertaining to F11 in general. For per-sensor data, see struct
- * f11_2d_sensor.
- *
- * @dev_query - F11 device specific query registers.
- * @dev_controls - F11 device specific control registers.
- * @dev_controls_mutex - lock for the control registers.
- * @rezero_wait_ms - if nonzero, upon resume we will wait this many
- * milliseconds before rezeroing the sensor(s). This is useful in systems with
- * poor electrical behavior on resume, where the initial calibration of the
- * sensor(s) coming out of sleep state may be bogus.
- * @sensors - per sensor data structures.
- * @debugfs_rezero_wait - allows control of the rezero_wait value. Useful
- * during system prototyping.
- */
-struct f11_data {
- struct f11_2d_device_query dev_query;
- struct f11_2d_ctrl dev_controls;
- struct mutex dev_controls_mutex;
- u16 rezero_wait_ms;
- struct f11_2d_sensor sensors[F11_MAX_NUM_OF_SENSORS];
-};
enum finger_state_values {
F11_NO_FINGER = 0x00,
F11_PRESENT = 0x01,
F11_INACCURATE = 0x02,
- F11_RESERVED = 0x03
+ F11_PRODUCT_SPECIFIC = 0x03
};
-static ssize_t rmi_f11_rezero_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct rmi_function *fn = to_rmi_function(dev);
- unsigned int rezero;
- int error;
-
- error = kstrtouint(buf, 0, &rezero);
- if (error)
- return error;
-
- if (rezero > 1)
- return -ERANGE;
-
- /* Per spec, 0 has no effect, so we skip it entirely. */
- if (rezero) {
- /* Command register always reads as 0, so just use a local. */
- struct f11_2d_commands commands = {
- .rezero = true,
- };
-
- error = rmi_write_block(fn->rmi_dev, fn->fd.command_base_addr,
- &commands, sizeof(commands));
- if (error < 0) {
- dev_err(dev,
- "%s: failed to issue rezero command, error = %d.",
- __func__, error);
- return error;
- }
- }
-
- return count;
-}
-
-static DEVICE_ATTR(rezero, RMI_WO_ATTR, NULL, rmi_f11_rezero_store);
-
-static struct attribute *rmi_f11_attrs[] = {
- &dev_attr_rezero.attr,
- NULL
-};
-
-static struct attribute_group rmi_f11_attr_group = {
- .attrs = rmi_f11_attrs,
-};
-
-#ifdef CONFIG_RMI4_DEBUG
-static void rmi_f11_setup_sensor_debugfs(struct f11_2d_sensor *sensor)
-{
- struct rmi_function *fn = sensor->fn;
- struct dentry *sensor_root;
- char dirname[sizeof("sensorNNN")];
-
- if (!fn->debugfs_root)
- return;
-
- snprintf(dirname, sizeof(dirname), "input%3u", sensor->sensor_index);
- sensor_root = debugfs_create_dir(dirname, fn->debugfs_root);
- if (!sensor_root) {
- dev_warn(&fn->dev,
- "Failed to create debugfs directory %s for sensor %d\n",
- dirname, sensor->sensor_index);
- return;
- }
-
- if (!debugfs_create_bool("type_a", RMI_RW_ATTR, sensor_root,
- &sensor->type_a))
- dev_warn(&fn->dev,
- "Failed to create debugfs type_a for sensor %d.\n",
- sensor->sensor_index);
-
- if (!debugfs_create_u16("max_x", RMI_RW_ATTR, sensor_root,
- &sensor->max_x))
- dev_warn(&fn->dev,
- "Failed to create debugfs max_x for sensor %d.\n",
- sensor->sensor_index);
-
- if (!debugfs_create_u16("max_xy", RMI_RW_ATTR, sensor_root,
- &sensor->max_y))
- dev_warn(&fn->dev,
- "Failed to create debugfs max_y for sensor %d.\n",
- sensor->sensor_index);
-
- if (!debugfs_create_bool("flip_x", RMI_RW_ATTR, sensor_root,
- &sensor->axis_align.flip_x))
- dev_warn(&fn->dev,
- "Failed to create debugfs flip_x for sensor %d.\n",
- sensor->sensor_index);
-
- if (!debugfs_create_bool("flip_y", RMI_RW_ATTR, sensor_root,
- &sensor->axis_align.flip_y))
- dev_warn(&fn->dev,
- "Failed to create debugfs flip_y for sensor %d.\n",
- sensor->sensor_index);
-
- if (!debugfs_create_u16("clip_x_low", RMI_RW_ATTR, sensor_root,
- &sensor->axis_align.clip_x_low))
- dev_warn(&fn->dev,
- "Failed to create debugfs clip_x_low for sensor %d.\n",
- sensor->sensor_index);
-
- if (!debugfs_create_u16("clip_x_high", RMI_RW_ATTR, sensor_root,
- &sensor->axis_align.clip_x_high))
- dev_warn(&fn->dev,
- "Failed to create debugfs clip_x_high for sensor %d.\n",
- sensor->sensor_index);
-
- if (!debugfs_create_u16("clip_y_low", RMI_RW_ATTR, sensor_root,
- &sensor->axis_align.clip_y_low))
- dev_warn(&fn->dev,
- "Failed to create debugfs clip_y_low for sensor %d.\n",
- sensor->sensor_index);
-
- if (!debugfs_create_u16("clip_y_high", RMI_RW_ATTR, sensor_root,
- &sensor->axis_align.clip_y_high))
- dev_warn(&fn->dev,
- "Failed to create debugfs clip_y_high for sensor %d.\n",
- sensor->sensor_index);
-
- if (!debugfs_create_u8("delta_x_threshold", RMI_RW_ATTR, sensor_root,
- &sensor->axis_align.delta_x_threshold))
- dev_warn(&fn->dev,
- "Failed to create debugfs delta_x_threshold for sensor %d.\n",
- sensor->sensor_index);
-
- if (!debugfs_create_u8("delta_y_threshold", RMI_RW_ATTR, sensor_root,
- &sensor->axis_align.delta_y_threshold))
- dev_warn(&fn->dev,
- "Failed to create debugfs delta_y_threshold for sensor %d.\n",
- sensor->sensor_index);
-
- if (!debugfs_create_u16("offset_x", RMI_RW_ATTR, sensor_root,
- &sensor->axis_align.offset_x))
- dev_warn(&fn->dev,
- "Failed to create debugfs offset_x for sensor %d.\n",
- sensor->sensor_index);
-
- if (!debugfs_create_u16("offset_x", RMI_RW_ATTR, sensor_root,
- &sensor->axis_align.offset_x))
- dev_warn(&fn->dev,
- "Failed to create debugfs offset_y for sensor %d.\n",
- sensor->sensor_index);
-
- if (!debugfs_create_bool("swap", RMI_RW_ATTR, sensor_root,
- &sensor->axis_align.swap_axes))
- dev_warn(&fn->dev,
- "Failed to create debugfs swap for sensor %d.\n",
- sensor->sensor_index);
-}
-
-static void rmi_f11_setup_debugfs(struct rmi_function *fn)
-{
- struct f11_data *f11 = fn->data;
-
- if (fn->debugfs_root)
- if (!debugfs_create_u16("rezero_wait", RMI_RW_ATTR,
- fn->debugfs_root,
- &f11->rezero_wait_ms))
- dev_warn(&fn->dev,
- "Failed to create debugfs rezero_wait.\n");
-}
-#else
-static inline void rmi_f11_setup_sensor_debugfs(struct f11_2d_sensor *sensor)
-{
-}
-static inline void rmi_f11_setup_debugfs(struct rmi_function *fn)
-{
-}
-#endif
-/* End adding debugfs */
-
/** F11_INACCURATE state is overloaded to indicate pen present. */
#define F11_PEN F11_INACCURATE
static int get_tool_type(struct f11_2d_sensor *sensor, u8 finger_state)
{
if (IS_ENABLED(CONFIG_RMI4_F11_PEN) &&
- sensor->sens_query.query9.has_pen &&
+ sensor->sens_query.has_pen &&
finger_state == F11_PEN)
return MT_TOOL_PEN;
return MT_TOOL_FINGER;
@@ -1012,8 +68,8 @@ static void rmi_f11_rel_pos_report(struct f11_2d_sensor *sensor, u8 n_finger)
s8 x, y;
s8 temp;
- x = data->rel_pos[n_finger].delta_x;
- y = data->rel_pos[n_finger].delta_y;
+ x = data->rel_pos[n_finger * 2];
+ y = data->rel_pos[n_finger * 2 + 1];
x = min(F11_REL_POS_MAX, max(F11_REL_POS_MIN, (int)x));
y = min(F11_REL_POS_MAX, max(F11_REL_POS_MIN, (int)y));
@@ -1044,19 +100,23 @@ static void rmi_f11_abs_pos_report(struct f11_data *f11,
struct f11_2d_data *data = &sensor->data;
struct rmi_f11_2d_axis_alignment *axis_align = &sensor->axis_align;
u16 x, y, z;
- int w_x, w_y, w_max, w_min, orient;
+ u16 w_x, w_y, w_max, w_min;
+ int orient;
int temp;
+ u8 abs_base = n_finger * RMI_F11_ABS_BYTES;
+
+ x = y = z = w_x = w_y = w_min = w_max = orient = 0;
if (finger_state) {
- x = ((data->abs_pos[n_finger].x_msb << 4) |
- data->abs_pos[n_finger].x_lsb);
- y = ((data->abs_pos[n_finger].y_msb << 4) |
- data->abs_pos[n_finger].y_lsb);
- z = data->abs_pos[n_finger].z;
- w_x = data->abs_pos[n_finger].w_x;
- w_y = data->abs_pos[n_finger].w_y;
+ x = (data->abs_pos[abs_base] << 4) |
+ (data->abs_pos[abs_base + 2] & 0x0F);
+ y = (data->abs_pos[abs_base + 1] << 4) |
+ (data->abs_pos[abs_base + 2] >> 4);
+ w_x = data->abs_pos[abs_base + 3] & 0x0F;
+ w_y = data->abs_pos[abs_base + 3] >> 4;
w_max = max(w_x, w_y);
w_min = min(w_x, w_y);
+ z = data->abs_pos[abs_base + 4];
if (axis_align->swap_axes) {
temp = x;
@@ -1099,8 +159,8 @@ static void rmi_f11_abs_pos_report(struct f11_data *f11,
* fingers. */
if (IS_ENABLED(CONFIG_RMI4_F11_PEN) &&
get_tool_type(sensor, finger_state) == MT_TOOL_PEN) {
- w_max = max(1, w_max);
- w_min = max(1, w_min);
+ w_max = max_t(u16, 1, w_max);
+ w_min = max_t(u16, 1, w_min);
}
if (sensor->type_a) {
@@ -1138,12 +198,10 @@ static void rmi_f11_finger_handler(struct f11_data *f11,
u8 i;
for (i = 0, finger_pressed_count = 0; i < sensor->nbr_fingers; i++) {
- /* Possible of having 4 fingers per f_statet register */
+ /* Possible of having 4 fingers per f_state register */
finger_state = (f_state[i / 4] >> (2 * (i % 4))) &
FINGER_STATE_MASK;
- if (finger_state == F11_RESERVED) {
- pr_err("%s: Invalid finger state[%d]:0x%02x.", __func__,
- i, finger_state);
+ if (finger_state == F11_PRODUCT_SPECIFIC) {
continue;
} else if ((finger_state == F11_PRESENT) ||
(finger_state == F11_INACCURATE)) {
@@ -1156,7 +214,9 @@ static void rmi_f11_finger_handler(struct f11_data *f11,
if (sensor->data.rel_pos)
rmi_f11_rel_pos_report(sensor, i);
}
- input_mt_sync(sensor->input);
+
+ input_report_key(sensor->input, BTN_TOUCH, finger_pressed_count);
+
input_sync(sensor->input);
}
@@ -1166,38 +226,36 @@ static int f11_2d_construct_data(struct f11_2d_sensor *sensor)
struct f11_2d_data *data = &sensor->data;
int i;
- sensor->nbr_fingers = (query->info.number_of_fingers == 5 ? 10 :
- query->info.number_of_fingers + 1);
+ sensor->nbr_fingers = (query->nr_fingers == 5 ? 10 :
+ query->nr_fingers + 1);
sensor->pkt_size = DIV_ROUND_UP(sensor->nbr_fingers, 4);
- if (query->info.has_abs)
+ if (query->has_abs)
sensor->pkt_size += (sensor->nbr_fingers * 5);
- if (query->info.has_rel)
+ if (query->has_rel)
sensor->pkt_size += (sensor->nbr_fingers * 2);
/* Check if F11_2D_Query7 is non-zero */
- if (has_gesture_bits(&query->gesture_info, 0))
+ if (query->query7_nonzero)
sensor->pkt_size += sizeof(u8);
/* Check if F11_2D_Query7 or F11_2D_Query8 is non-zero */
- if (has_gesture_bits(&query->gesture_info, 0) ||
- has_gesture_bits(&query->gesture_info, 1))
+ if (query->query7_nonzero || query->query8_nonzero)
sensor->pkt_size += sizeof(u8);
- if (query->gesture_info.has_pinch || query->gesture_info.has_flick
- || query->gesture_info.has_rotate) {
+ if (query->has_pinch || query->has_flick || query->has_rotate) {
sensor->pkt_size += 3;
- if (!query->gesture_info.has_flick)
+ if (!query->has_flick)
sensor->pkt_size--;
- if (!query->gesture_info.has_rotate)
+ if (!query->has_rotate)
sensor->pkt_size--;
}
- if (query->gesture_info.has_touch_shapes)
+ if (query->has_touch_shapes)
sensor->pkt_size +=
- DIV_ROUND_UP(query->ts_info.nbr_touch_shapes + 1, 8);
+ DIV_ROUND_UP(query->nr_touch_shapes + 1, 8);
sensor->data_pkt = kzalloc(sensor->pkt_size, GFP_KERNEL);
if (!sensor->data_pkt)
@@ -1206,272 +264,65 @@ static int f11_2d_construct_data(struct f11_2d_sensor *sensor)
data->f_state = sensor->data_pkt;
i = DIV_ROUND_UP(sensor->nbr_fingers, 4);
- if (query->info.has_abs) {
- data->abs_pos = (struct f11_2d_data_1_5 *)
- &sensor->data_pkt[i];
- i += (sensor->nbr_fingers * 5);
+ if (query->has_abs) {
+ data->abs_pos = &sensor->data_pkt[i];
+ i += (sensor->nbr_fingers * RMI_F11_ABS_BYTES);
}
- if (query->info.has_rel) {
- data->rel_pos = (struct f11_2d_data_6_7 *)
- &sensor->data_pkt[i];
- i += (sensor->nbr_fingers * 2);
+ if (query->has_rel) {
+ data->rel_pos = &sensor->data_pkt[i];
+ i += (sensor->nbr_fingers * RMI_F11_REL_BYTES);
}
- if (has_gesture_bits(&query->gesture_info, 0)) {
- data->gest_1 = (struct f11_2d_data_8 *)&sensor->data_pkt[i];
+ if (query->query7_nonzero) {
+ data->gest_1 = &sensor->data_pkt[i];
i++;
}
- if (has_gesture_bits(&query->gesture_info, 0) ||
- has_gesture_bits(&query->gesture_info, 1)) {
- data->gest_2 = (struct f11_2d_data_9 *)&sensor->data_pkt[i];
+ if (query->query7_nonzero || query->query8_nonzero) {
+ data->gest_2 = &sensor->data_pkt[i];
i++;
}
- if (query->gesture_info.has_pinch) {
- data->pinch = (struct f11_2d_data_10 *)&sensor->data_pkt[i];
+ if (query->has_pinch) {
+ data->pinch = &sensor->data_pkt[i];
i++;
}
- if (query->gesture_info.has_flick) {
- if (query->gesture_info.has_pinch) {
- data->flick = (struct f11_2d_data_10_12 *)data->pinch;
+ if (query->has_flick) {
+ if (query->has_pinch) {
+ data->flick = data->pinch;
i += 2;
} else {
- data->flick = (struct f11_2d_data_10_12 *)
- &sensor->data_pkt[i];
+ data->flick = &sensor->data_pkt[i];
i += 3;
}
}
- if (query->gesture_info.has_rotate) {
- if (query->gesture_info.has_flick) {
- data->rotate = (struct f11_2d_data_11_12 *)
- (data->flick + 1);
+ if (query->has_rotate) {
+ if (query->has_flick) {
+ data->rotate = data->flick + 1;
} else {
- data->rotate = (struct f11_2d_data_11_12 *)
- &sensor->data_pkt[i];
+ data->rotate = &sensor->data_pkt[i];
i += 2;
}
}
- if (query->gesture_info.has_touch_shapes)
- data->shapes = (struct f11_2d_data_13 *)&sensor->data_pkt[i];
-
return 0;
}
static int f11_read_control_regs(struct rmi_function *fn,
struct f11_2d_ctrl *ctrl, u16 ctrl_base_addr) {
struct rmi_device *rmi_dev = fn->rmi_dev;
- u16 read_address = ctrl_base_addr;
- int error = 0;
+ int error;
- ctrl->ctrl0_9_address = read_address;
- error = rmi_read_block(rmi_dev, read_address, ctrl->ctrl0_9,
- sizeof(*ctrl->ctrl0_9));
+ ctrl->ctrl0_9_address = ctrl_base_addr;
+ error = rmi_read_block(rmi_dev, ctrl_base_addr, ctrl->ctrl0_9,
+ RMI_F11_CTRL_REG_COUNT);
if (error < 0) {
dev_err(&fn->dev, "Failed to read ctrl0, code: %d.\n", error);
return error;
}
- read_address += sizeof(*ctrl->ctrl0_9);
-
- if (ctrl->ctrl10) {
- error = rmi_read_block(rmi_dev, read_address,
- ctrl->ctrl10, sizeof(*ctrl->ctrl10));
- if (error < 0) {
- dev_err(&fn->dev,
- "Failed to read ctrl10, code: %d.\n", error);
- return error;
- }
- read_address += sizeof(*ctrl->ctrl10);
- }
-
- if (ctrl->ctrl11) {
- error = rmi_read_block(rmi_dev, read_address,
- ctrl->ctrl11, sizeof(*ctrl->ctrl11));
- if (error < 0) {
- dev_err(&fn->dev,
- "Failed to read ctrl11, code: %d.\n", error);
- return error;
- }
- read_address += sizeof(*ctrl->ctrl11);
- }
-
- if (ctrl->ctrl14) {
- error = rmi_read_block(rmi_dev, read_address,
- ctrl->ctrl14, sizeof(*ctrl->ctrl14));
- if (error < 0) {
- dev_err(&fn->dev,
- "Failed to read ctrl14, code: %d.\n", error);
- return error;
- }
- read_address += sizeof(*ctrl->ctrl14);
- }
-
- if (ctrl->ctrl15) {
- error = rmi_read_block(rmi_dev, read_address,
- ctrl->ctrl15, sizeof(*ctrl->ctrl15));
- if (error < 0) {
- dev_err(&fn->dev,
- "Failed to read ctrl15, code: %d.\n", error);
- return error;
- }
- read_address += sizeof(*ctrl->ctrl15);
- }
-
- if (ctrl->ctrl16) {
- error = rmi_read_block(rmi_dev, read_address,
- ctrl->ctrl16, sizeof(*ctrl->ctrl16));
- if (error < 0) {
- dev_err(&fn->dev,
- "Failed to read ctrl16, code: %d.\n", error);
- return error;
- }
- read_address += sizeof(*ctrl->ctrl16);
- }
-
- if (ctrl->ctrl17) {
- error = rmi_read_block(rmi_dev, read_address,
- ctrl->ctrl17, sizeof(*ctrl->ctrl17));
- if (error < 0) {
- dev_err(&fn->dev,
- "Failed to read ctrl17, code: %d.\n", error);
- return error;
- }
- read_address += sizeof(*ctrl->ctrl17);
- }
-
- if (ctrl->ctrl18_19) {
- error = rmi_read_block(rmi_dev, read_address,
- ctrl->ctrl18_19, sizeof(*ctrl->ctrl18_19));
- if (error < 0) {
- dev_err(&fn->dev,
- "Failed to read ctrl18_19, code: %d.\n", error);
- return error;
- }
- read_address += sizeof(*ctrl->ctrl18_19);
- }
-
- if (ctrl->ctrl20_21) {
- error = rmi_read_block(rmi_dev, read_address,
- ctrl->ctrl20_21, sizeof(*ctrl->ctrl20_21));
- if (error < 0) {
- dev_err(&fn->dev,
- "Failed to read ctrl20_21, code: %d.\n", error);
- return error;
- }
- read_address += sizeof(*ctrl->ctrl20_21);
- }
-
- if (ctrl->ctrl22_26) {
- error = rmi_read_block(rmi_dev, read_address,
- ctrl->ctrl22_26, sizeof(*ctrl->ctrl22_26));
- if (error < 0) {
- dev_err(&fn->dev,
- "Failed to read ctrl22_26, code: %d.\n", error);
- return error;
- }
- read_address += sizeof(*ctrl->ctrl22_26);
- }
-
- if (ctrl->ctrl27) {
- error = rmi_read_block(rmi_dev, read_address,
- ctrl->ctrl27, sizeof(*ctrl->ctrl27));
- if (error < 0) {
- dev_err(&fn->dev,
- "Failed to read ctrl27, code: %d.\n", error);
- return error;
- }
- read_address += sizeof(*ctrl->ctrl27);
- }
-
- if (ctrl->ctrl28) {
- error = rmi_read_block(rmi_dev, read_address,
- ctrl->ctrl28, sizeof(*ctrl->ctrl28));
- if (error < 0) {
- dev_err(&fn->dev,
- "Failed to read ctrl28, code: %d.\n", error);
- return error;
- }
- read_address += sizeof(*ctrl->ctrl28);
- }
-
- if (ctrl->ctrl29_30) {
- error = rmi_read_block(rmi_dev, read_address,
- ctrl->ctrl29_30, sizeof(*ctrl->ctrl29_30));
- if (error < 0) {
- dev_err(&fn->dev,
- "Failed to read ctrl29_30, code: %d.\n", error);
- return error;
- }
- read_address += sizeof(*ctrl->ctrl29_30);
- }
- return 0;
-}
-
-static int f11_allocate_control_regs(struct rmi_function *fn,
- struct f11_2d_device_query *device_query,
- struct f11_2d_sensor_queries *sensor_query,
- struct f11_2d_ctrl *ctrl,
- u16 ctrl_base_addr) {
-
- ctrl->ctrl0_9 = devm_kzalloc(&fn->dev, sizeof(struct f11_2d_ctrl0_9),
- GFP_KERNEL);
- if (!ctrl->ctrl0_9)
- return -ENOMEM;
- if (has_gesture_bits(&sensor_query->gesture_info, 0)) {
- ctrl->ctrl10 = devm_kzalloc(&fn->dev,
- sizeof(struct f11_2d_ctrl10), GFP_KERNEL);
- if (!ctrl->ctrl10)
- return -ENOMEM;
- }
-
- if (has_gesture_bits(&sensor_query->gesture_info, 1)) {
- ctrl->ctrl11 = devm_kzalloc(&fn->dev,
- sizeof(struct f11_2d_ctrl11), GFP_KERNEL);
- if (!ctrl->ctrl11)
- return -ENOMEM;
- }
-
- if (device_query->has_query9 && sensor_query->query9.has_pen) {
- ctrl->ctrl20_21 = devm_kzalloc(&fn->dev,
- sizeof(struct f11_2d_ctrl20_21), GFP_KERNEL);
- if (!ctrl->ctrl20_21)
- return -ENOMEM;
- }
-
- if (device_query->has_query9 && sensor_query->query9.has_proximity) {
- ctrl->ctrl22_26 = devm_kzalloc(&fn->dev,
- sizeof(struct f11_2d_ctrl22_26), GFP_KERNEL);
- if (!ctrl->ctrl22_26)
- return -ENOMEM;
- }
-
- if (device_query->has_query9 &&
- (sensor_query->query9.has_palm_det_sensitivity ||
- sensor_query->query9.has_suppress_on_palm_detect)) {
- ctrl->ctrl27 = devm_kzalloc(&fn->dev,
- sizeof(struct f11_2d_ctrl27), GFP_KERNEL);
- if (!ctrl->ctrl27)
- return -ENOMEM;
- }
-
- if (sensor_query->gesture_info.has_multi_finger_scroll) {
- ctrl->ctrl28 = devm_kzalloc(&fn->dev,
- sizeof(struct f11_2d_ctrl28), GFP_KERNEL);
- if (!ctrl->ctrl28)
- return -ENOMEM;
- }
-
- if (device_query->has_query11 &&
- sensor_query->features_1.has_z_tuning) {
- ctrl->ctrl29_30 = devm_kzalloc(&fn->dev,
- sizeof(struct f11_2d_ctrl29_30), GFP_KERNEL);
- if (!ctrl->ctrl29_30)
- return -ENOMEM;
- }
return 0;
}
@@ -1482,139 +333,70 @@ static int f11_write_control_regs(struct rmi_function *fn,
u16 ctrl_base_addr)
{
struct rmi_device *rmi_dev = fn->rmi_dev;
- u16 write_address = ctrl_base_addr;
int error;
- error = rmi_write_block(rmi_dev, write_address,
- ctrl->ctrl0_9,
- sizeof(*ctrl->ctrl0_9));
+ error = rmi_write_block(rmi_dev, ctrl_base_addr, ctrl->ctrl0_9,
+ RMI_F11_CTRL_REG_COUNT);
if (error < 0)
return error;
- write_address += sizeof(ctrl->ctrl0_9);
-
- if (ctrl->ctrl10) {
- error = rmi_write_block(rmi_dev, write_address,
- ctrl->ctrl10, sizeof(*ctrl->ctrl10));
- if (error < 0)
- return error;
- write_address++;
- }
-
- if (ctrl->ctrl11) {
- error = rmi_write_block(rmi_dev, write_address,
- ctrl->ctrl11, sizeof(*ctrl->ctrl11));
- if (error < 0)
- return error;
- write_address++;
- }
-
- if (ctrl->ctrl14) {
- error = rmi_write_block(rmi_dev, write_address,
- ctrl->ctrl14, sizeof(ctrl->ctrl14));
- if (error < 0)
- return error;
- write_address += sizeof(*ctrl->ctrl15);
- }
-
- if (ctrl->ctrl15) {
- error = rmi_write_block(rmi_dev, write_address,
- ctrl->ctrl15, sizeof(*ctrl->ctrl15));
- if (error < 0)
- return error;
- write_address += sizeof(*ctrl->ctrl15);
- }
-
- if (ctrl->ctrl16) {
- error = rmi_write_block(rmi_dev, write_address,
- ctrl->ctrl16, sizeof(*ctrl->ctrl16));
- if (error < 0)
- return error;
- write_address += sizeof(*ctrl->ctrl16);
- }
-
- if (ctrl->ctrl17) {
- error = rmi_write_block(rmi_dev, write_address,
- ctrl->ctrl17, sizeof(*ctrl->ctrl17));
- if (error < 0)
- return error;
- write_address += sizeof(*ctrl->ctrl17);
- }
-
- if (ctrl->ctrl18_19) {
- error = rmi_write_block(rmi_dev, write_address,
- ctrl->ctrl18_19, sizeof(*ctrl->ctrl18_19));
- if (error < 0)
- return error;
- write_address += sizeof(*ctrl->ctrl18_19);
- }
-
- if (ctrl->ctrl20_21) {
- error = rmi_write_block(rmi_dev, write_address,
- ctrl->ctrl20_21, sizeof(*ctrl->ctrl20_21));
- if (error < 0)
- return error;
- write_address += sizeof(*ctrl->ctrl20_21);
- }
-
- if (ctrl->ctrl22_26) {
- error = rmi_write_block(rmi_dev, write_address,
- ctrl->ctrl22_26, sizeof(*ctrl->ctrl22_26));
- if (error < 0)
- return error;
- write_address += sizeof(*ctrl->ctrl22_26);
- }
-
- if (ctrl->ctrl27) {
- error = rmi_write_block(rmi_dev, write_address,
- ctrl->ctrl27, sizeof(*ctrl->ctrl27));
- if (error < 0)
- return error;
- write_address += sizeof(*ctrl->ctrl27);
- }
-
- if (ctrl->ctrl28) {
- error = rmi_write_block(rmi_dev, write_address,
- ctrl->ctrl28, sizeof(*ctrl->ctrl28));
- if (error < 0)
- return error;
- write_address += sizeof(*ctrl->ctrl28);
- }
-
- if (ctrl->ctrl29_30) {
- error = rmi_write_block(rmi_dev, write_address,
- ctrl->ctrl29_30,
- sizeof(struct f11_2d_ctrl29_30));
- if (error < 0)
- return error;
- write_address += sizeof(struct f11_2d_ctrl29_30);
- }
return 0;
}
static int rmi_f11_get_query_parameters(struct rmi_device *rmi_dev,
- struct f11_2d_device_query *dev_query,
+ struct f11_data *f11,
struct f11_2d_sensor_queries *sensor_query,
u16 query_base_addr)
{
int query_size;
int rc;
+ u8 query_buf[RMI_F11_QUERY_SIZE];
- rc = rmi_read_block(rmi_dev, query_base_addr,
- &sensor_query->info, sizeof(sensor_query->info));
+ rc = rmi_read_block(rmi_dev, query_base_addr, query_buf,
+ RMI_F11_QUERY_SIZE);
if (rc < 0)
return rc;
- query_size = sizeof(sensor_query->info);
- if (sensor_query->info.has_abs) {
- rc = rmi_read(rmi_dev, query_base_addr + query_size,
- &sensor_query->abs_info);
+ sensor_query->nr_fingers = query_buf[0] & RMI_F11_NR_FINGERS_MASK;
+ sensor_query->has_rel = !!(query_buf[0] & RMI_F11_HAS_REL);
+ sensor_query->has_abs = !!(query_buf[0] & RMI_F11_HAS_ABS);
+ sensor_query->has_gestures = !!(query_buf[0] & RMI_F11_HAS_GESTURES);
+ sensor_query->has_sensitivity_adjust =
+ !!(query_buf[0] && RMI_F11_HAS_SENSITIVITY_ADJ);
+ sensor_query->configurable = !!(query_buf[0] & RMI_F11_CONFIGURABLE);
+
+ sensor_query->nr_x_electrodes =
+ query_buf[1] & RMI_F11_NR_ELECTRODES_MASK;
+ sensor_query->nr_y_electrodes =
+ query_buf[2] & RMI_F11_NR_ELECTRODES_MASK;
+ sensor_query->max_electrodes =
+ query_buf[3] & RMI_F11_NR_ELECTRODES_MASK;
+
+ query_size = RMI_F11_QUERY_SIZE;
+
+ if (sensor_query->has_abs) {
+ rc = rmi_read(rmi_dev, query_base_addr + query_size, query_buf);
if (rc < 0)
return rc;
+
+ sensor_query->abs_data_size =
+ query_buf[0] & RMI_F11_ABS_DATA_SIZE_MASK;
+ sensor_query->has_anchored_finger =
+ !!(query_buf[0] & RMI_F11_HAS_ANCHORED_FINGER);
+ sensor_query->has_adj_hyst =
+ !!(query_buf[0] & RMI_F11_HAS_ADJ_HYST);
+ sensor_query->has_dribble =
+ !!(query_buf[0] & RMI_F11_HAS_DRIBBLE);
+ sensor_query->has_bending_correction =
+ !!(query_buf[0] & RMI_F11_HAS_BENDING_CORRECTION);
+ sensor_query->has_large_object_suppression =
+ !!(query_buf[0] && RMI_F11_HAS_LARGE_OBJECT_SUPPRESSION);
+ sensor_query->has_jitter_filter =
+ !!(query_buf[0] & RMI_F11_HAS_JITTER_FILTER);
query_size++;
}
- if (sensor_query->info.has_rel) {
+ if (sensor_query->has_rel) {
rc = rmi_read(rmi_dev, query_base_addr + query_size,
&sensor_query->f11_2d_query6);
if (rc < 0)
@@ -1622,67 +404,173 @@ static int rmi_f11_get_query_parameters(struct rmi_device *rmi_dev,
query_size++;
}
- if (sensor_query->info.has_gestures) {
+ if (sensor_query->has_gestures) {
rc = rmi_read_block(rmi_dev, query_base_addr + query_size,
- &sensor_query->gesture_info,
- sizeof(sensor_query->gesture_info));
+ query_buf, RMI_F11_QUERY_GESTURE_SIZE);
if (rc < 0)
return rc;
- query_size += sizeof(sensor_query->gesture_info);
- }
- if (dev_query->has_query9) {
- rc = rmi_read_block(rmi_dev, query_base_addr + query_size,
- &sensor_query->query9,
- sizeof(sensor_query->query9));
+ sensor_query->has_single_tap =
+ !!(query_buf[0] & RMI_F11_HAS_SINGLE_TAP);
+ sensor_query->has_tap_n_hold =
+ !!(query_buf[0] & RMI_F11_HAS_TAP_AND_HOLD);
+ sensor_query->has_double_tap =
+ !!(query_buf[0] & RMI_F11_HAS_DOUBLE_TAP);
+ sensor_query->has_early_tap =
+ !!(query_buf[0] & RMI_F11_HAS_EARLY_TAP);
+ sensor_query->has_flick =
+ !!(query_buf[0] & RMI_F11_HAS_FLICK);
+ sensor_query->has_press =
+ !!(query_buf[0] & RMI_F11_HAS_PRESS);
+ sensor_query->has_pinch =
+ !!(query_buf[0] & RMI_F11_HAS_PINCH);
+ sensor_query->has_chiral =
+ !!(query_buf[0] & RMI_F11_HAS_CHIRAL);
+
+ /* query 8 */
+ sensor_query->has_palm_det =
+ !!(query_buf[1] & RMI_F11_HAS_PALM_DET);
+ sensor_query->has_rotate =
+ !!(query_buf[1] & RMI_F11_HAS_ROTATE);
+ sensor_query->has_touch_shapes =
+ !!(query_buf[1] & RMI_F11_HAS_TOUCH_SHAPES);
+ sensor_query->has_scroll_zones =
+ !!(query_buf[1] & RMI_F11_HAS_SCROLL_ZONES);
+ sensor_query->has_individual_scroll_zones =
+ !!(query_buf[1] & RMI_F11_HAS_INDIVIDUAL_SCROLL_ZONES);
+ sensor_query->has_mf_scroll =
+ !!(query_buf[1] & RMI_F11_HAS_MF_SCROLL);
+ sensor_query->has_mf_edge_motion =
+ !!(query_buf[1] & RMI_F11_HAS_MF_EDGE_MOTION);
+ sensor_query->has_mf_scroll_inertia =
+ !!(query_buf[1] & RMI_F11_HAS_MF_SCROLL_INERTIA);
+
+ sensor_query->query7_nonzero = !!(query_buf[0]);
+ sensor_query->query8_nonzero = !!(query_buf[1]);
+
+ query_size += 2;
+ }
+
+ if (f11->has_query9) {
+ rc = rmi_read(rmi_dev, query_base_addr + query_size, query_buf);
if (rc < 0)
return rc;
- query_size += sizeof(sensor_query->query9);
+
+ sensor_query->has_pen =
+ !!(query_buf[0] & RMI_F11_HAS_PEN);
+ sensor_query->has_proximity =
+ !!(query_buf[0] & RMI_F11_HAS_PROXIMITY);
+ sensor_query->has_palm_det_sensitivity =
+ !!(query_buf[0] & RMI_F11_HAS_PALM_DET_SENSITIVITY);
+ sensor_query->has_suppress_on_palm_detect =
+ !!(query_buf[0] & RMI_F11_HAS_SUPPRESS_ON_PALM_DETECT);
+ sensor_query->has_two_pen_thresholds =
+ !!(query_buf[0] & RMI_F11_HAS_TWO_PEN_THRESHOLDS);
+ sensor_query->has_contact_geometry =
+ !!(query_buf[0] & RMI_F11_HAS_CONTACT_GEOMETRY);
+ sensor_query->has_pen_hover_discrimination =
+ !!(query_buf[0] & RMI_F11_HAS_PEN_HOVER_DISCRIMINATION);
+ sensor_query->has_pen_filters =
+ !!(query_buf[0] & RMI_F11_HAS_PEN_FILTERS);
+
+ query_size++;
}
- if (sensor_query->gesture_info.has_touch_shapes) {
- rc = rmi_read_block(rmi_dev, query_base_addr + query_size,
- &sensor_query->ts_info,
- sizeof(sensor_query->ts_info));
+ if (sensor_query->has_touch_shapes) {
+ rc = rmi_read(rmi_dev, query_base_addr + query_size, query_buf);
if (rc < 0)
return rc;
- query_size += sizeof(sensor_query->ts_info);
+
+ sensor_query->nr_touch_shapes = query_buf[0] &
+ RMI_F11_NR_TOUCH_SHAPES_MASK;
+
+ query_size++;
}
- if (dev_query->has_query11) {
- rc = rmi_read_block(rmi_dev, query_base_addr + query_size,
- &sensor_query->features_1,
- sizeof(sensor_query->features_1));
+ if (f11->has_query11) {
+ rc = rmi_read(rmi_dev, query_base_addr + query_size, query_buf);
if (rc < 0)
return rc;
- query_size += sizeof(sensor_query->features_1);
+
+ sensor_query->has_z_tuning =
+ !!(query_buf[0] & RMI_F11_HAS_Z_TUNING);
+ sensor_query->has_algorithm_selection =
+ !!(query_buf[0] & RMI_F11_HAS_ALGORITHM_SELECTION);
+ sensor_query->has_w_tuning =
+ !!(query_buf[0] & RMI_F11_HAS_W_TUNING);
+ sensor_query->has_pitch_info =
+ !!(query_buf[0] & RMI_F11_HAS_PITCH_INFO);
+ sensor_query->has_finger_size =
+ !!(query_buf[0] & RMI_F11_HAS_FINGER_SIZE);
+ sensor_query->has_segmentation_aggressiveness =
+ !!(query_buf[0] &
+ RMI_F11_HAS_SEGMENTATION_AGGRESSIVENESS);
+ sensor_query->has_XY_clip =
+ !!(query_buf[0] & RMI_F11_HAS_XY_CLIP);
+ sensor_query->has_drumming_filter =
+ !!(query_buf[0] & RMI_F11_HAS_DRUMMING_FILTER);
+
+ query_size++;
}
- if (dev_query->has_query12) {
- rc = rmi_read_block(rmi_dev, query_base_addr + query_size,
- &sensor_query->features_2,
- sizeof(sensor_query->features_2));
+ if (f11->has_query12) {
+ rc = rmi_read(rmi_dev, query_base_addr + query_size, query_buf);
if (rc < 0)
return rc;
- query_size += sizeof(sensor_query->features_2);
+
+ sensor_query->has_gapless_finger =
+ !!(query_buf[0] & RMI_F11_HAS_GAPLESS_FINGER);
+ sensor_query->has_gapless_finger_tuning =
+ !!(query_buf[0] & RMI_F11_HAS_GAPLESS_FINGER_TUNING);
+ sensor_query->has_8bit_w =
+ !!(query_buf[0] & RMI_F11_HAS_8BIT_W);
+ sensor_query->has_adjustable_mapping =
+ !!(query_buf[0] & RMI_F11_HAS_ADJUSTABLE_MAPPING);
+ sensor_query->has_info2 =
+ !!(query_buf[0] & RMI_F11_HAS_INFO2);
+ sensor_query->has_physical_props =
+ !!(query_buf[0] & RMI_F11_HAS_PHYSICAL_PROPS);
+ sensor_query->has_finger_limit =
+ !!(query_buf[0] & RMI_F11_HAS_FINGER_LIMIT);
+ sensor_query->has_linear_coeff_2 =
+ !!(query_buf[0] & RMI_F11_HAS_LINEAR_COEFF);
+
+ query_size++;
}
- if (sensor_query->abs_info.has_jitter_filter) {
- rc = rmi_read_block(rmi_dev, query_base_addr + query_size,
- &sensor_query->jitter_filter,
- sizeof(sensor_query->jitter_filter));
+ if (sensor_query->has_jitter_filter) {
+ rc = rmi_read(rmi_dev, query_base_addr + query_size, query_buf);
if (rc < 0)
return rc;
- query_size += sizeof(sensor_query->jitter_filter);
+
+ sensor_query->jitter_window_size = query_buf[0] &
+ RMI_F11_JITTER_WINDOW_MASK;
+ sensor_query->jitter_filter_type = (query_buf[0] &
+ RMI_F11_JITTER_FILTER_MASK) >>
+ RMI_F11_JITTER_FILTER_SHIFT;
+
+ query_size++;
}
- if (dev_query->has_query12 && sensor_query->features_2.has_info2) {
- rc = rmi_read_block(rmi_dev, query_base_addr + query_size,
- &sensor_query->info_2,
- sizeof(sensor_query->info_2));
+ if (f11->has_query12 && sensor_query->has_info2) {
+ rc = rmi_read(rmi_dev, query_base_addr + query_size, query_buf);
if (rc < 0)
return rc;
- query_size += sizeof(sensor_query->info_2);
+
+ sensor_query->light_control =
+ query_buf[0] & RMI_F11_LIGHT_CONTROL_MASK;
+ sensor_query->is_clear =
+ !!(query_buf[0] & RMI_F11_IS_CLEAR);
+ sensor_query->clickpad_props =
+ (query_buf[0] & RMI_F11_CLICKPAD_PROPS_MASK) >>
+ RMI_F11_CLICKPAD_PROPS_SHIFT;
+ sensor_query->mouse_buttons =
+ (query_buf[0] & RMI_F11_MOUSE_BUTTONS_MASK) >>
+ RMI_F11_MOUSE_BUTTONS_SHIFT;
+ sensor_query->has_advanced_gestures =
+ !!(query_buf[0] & RMI_F11_HAS_ADVANCED_GESTURES);
+
+ query_size++;
}
return query_size;
@@ -1696,10 +584,15 @@ static void f11_set_abs_params(struct rmi_function *fn, int index)
struct f11_data *f11 = fn->data;
struct f11_2d_sensor *sensor = &f11->sensors[index];
struct input_dev *input = sensor->input;
- u16 device_x_max =
- f11->dev_controls.ctrl0_9->sensor_max_x_pos;
- u16 device_y_max =
- f11->dev_controls.ctrl0_9->sensor_max_y_pos;
+ /* These two lines are not doing what we want them to. So we use
+ * some shifts instead.
+ int device_x_max = le16_to_cpu(*(f11->dev_controls.ctrl0_9 + 6));
+ int device_y_max = le16_to_cpu(*(f11->dev_controls.ctrl0_9 + 8));
+ */
+ u16 device_x_max = f11->dev_controls.ctrl0_9[6] |
+ ((f11->dev_controls.ctrl0_9[7] & 0x0F) << 8);
+ u16 device_y_max = f11->dev_controls.ctrl0_9[8] |
+ ((f11->dev_controls.ctrl0_9[9] & 0x0F) << 8);
u16 x_min, x_max, y_min, y_max;
unsigned int input_flags;
@@ -1707,8 +600,8 @@ static void f11_set_abs_params(struct rmi_function *fn, int index)
* as a touchpad in the platform data
*/
if (sensor->sensor_type == rmi_f11_sensor_touchpad ||
- (sensor->sens_query.features_2.has_info2 &&
- !sensor->sens_query.info_2.is_clear))
+ (sensor->sens_query.has_info2 &&
+ !sensor->sens_query.is_clear))
input_flags = INPUT_PROP_POINTER;
else
input_flags = INPUT_PROP_DIRECT;
@@ -1724,21 +617,16 @@ static void f11_set_abs_params(struct rmi_function *fn, int index)
*/
x_min = sensor->axis_align.clip_x_low;
if (sensor->axis_align.clip_x_high)
- x_max = min(device_x_max,
- sensor->axis_align.clip_x_high);
+ x_max = min(device_x_max, sensor->axis_align.clip_x_high);
else
x_max = device_x_max;
y_min = sensor->axis_align.clip_y_low;
if (sensor->axis_align.clip_y_high)
- y_max = min(device_y_max,
- sensor->axis_align.clip_y_high);
+ y_max = min(device_y_max, sensor->axis_align.clip_y_high);
else
y_max = device_y_max;
- dev_dbg(&fn->dev, "Set ranges X=[%d..%d] Y=[%d..%d].",
- x_min, x_max, y_min, y_max);
-
input_set_abs_params(input, ABS_MT_PRESSURE, 0,
DEFAULT_MAX_ABS_MT_PRESSURE, 0, 0);
input_set_abs_params(input, ABS_MT_TOUCH_MAJOR,
@@ -1756,9 +644,8 @@ static void f11_set_abs_params(struct rmi_function *fn, int index)
input_set_abs_params(input, ABS_MT_POSITION_Y,
y_min, y_max, 0, 0);
if (!sensor->type_a)
- input_mt_init_slots(input, sensor->nbr_fingers, input_flags);
- if (IS_ENABLED(CONFIG_RMI4_F11_PEN) &&
- sensor->sens_query.query9.has_pen)
+ input_mt_init_slots(input, sensor->nbr_fingers, 0);
+ if (IS_ENABLED(CONFIG_RMI4_F11_PEN) && sensor->sens_query.has_pen)
input_set_abs_params(input, ABS_MT_TOOL_TYPE,
0, MT_TOOL_MAX, 0, 0);
else
@@ -1778,13 +665,8 @@ static int rmi_f11_initialize(struct rmi_function *fn)
int rc;
int i;
struct rmi_device_platform_data *pdata = to_rmi_platform_data(rmi_dev);
+ u8 buf;
- dev_dbg(&fn->dev, "Initializing F11 values for %s.\n",
- pdata->sensor_name);
-
- /*
- ** init instance data, fill in values and create any sysfs files
- */
f11 = devm_kzalloc(&fn->dev, sizeof(struct f11_data), GFP_KERNEL);
if (!f11)
return -ENOMEM;
@@ -1795,32 +677,30 @@ static int rmi_f11_initialize(struct rmi_function *fn)
query_base_addr = fn->fd.query_base_addr;
control_base_addr = fn->fd.control_base_addr;
- rc = rmi_read(rmi_dev, query_base_addr, &f11->dev_query);
+ rc = rmi_read(rmi_dev, query_base_addr, &buf);
if (rc < 0)
return rc;
+ f11->nr_sensors = buf & RMI_F11_NR_SENSORS_MASK;
+ f11->has_query9 = !!(buf & RMI_F11_HAS_QUERY9);
+ f11->has_query11 = !!(buf & RMI_F11_HAS_QUERY11);
+ f11->has_query12 = !!(buf & RMI_F11_HAS_QUERY12);
+ f11->has_query27 = !!(buf & RMI_F11_HAS_QUERY27);
+ f11->has_query28 = !!(buf & RMI_F11_HAS_QUERY28);
+
query_offset = (query_base_addr + 1);
/* Increase with one since number of sensors is zero based */
- for (i = 0; i < (f11->dev_query.nbr_of_sensors + 1); i++) {
+ for (i = 0; i < (f11->nr_sensors + 1); i++) {
struct f11_2d_sensor *sensor = &f11->sensors[i];
sensor->sensor_index = i;
sensor->fn = fn;
- rc = rmi_f11_get_query_parameters(rmi_dev, &f11->dev_query,
+ rc = rmi_f11_get_query_parameters(rmi_dev, f11,
&sensor->sens_query, query_offset);
if (rc < 0)
return rc;
query_offset += rc;
- rc = f11_allocate_control_regs(fn,
- &f11->dev_query, &sensor->sens_query,
- &f11->dev_controls, control_base_addr);
- if (rc < 0) {
- dev_err(&fn->dev,
- "Failed to allocate F11 control params.\n");
- return rc;
- }
-
rc = f11_read_control_regs(fn, &f11->dev_controls,
control_base_addr);
if (rc < 0) {
@@ -1863,12 +743,11 @@ static int rmi_f11_initialize(struct rmi_function *fn)
ctrl = &f11->dev_controls;
if (sensor->axis_align.delta_x_threshold) {
- ctrl->ctrl0_9->delta_x_threshold =
+ ctrl->ctrl0_9[RMI_F11_DELTA_X_THRESHOLD] =
sensor->axis_align.delta_x_threshold;
- rc = rmi_write_block(rmi_dev,
- ctrl->ctrl0_9_address,
- ctrl->ctrl0_9,
- sizeof(*ctrl->ctrl0_9));
+ rc = rmi_write_block(rmi_dev, ctrl->ctrl0_9_address,
+ ctrl->ctrl0_9,
+ RMI_F11_CTRL_REG_COUNT);
if (rc < 0)
dev_warn(&fn->dev, "Failed to write to delta_x_threshold %d. Code: %d.\n",
i, rc);
@@ -1876,22 +755,16 @@ static int rmi_f11_initialize(struct rmi_function *fn)
}
if (sensor->axis_align.delta_y_threshold) {
- ctrl->ctrl0_9->delta_y_threshold =
+ ctrl->ctrl0_9[RMI_F11_DELTA_Y_THRESHOLD] =
sensor->axis_align.delta_y_threshold;
- rc = rmi_write_block(rmi_dev,
- ctrl->ctrl0_9_address,
- ctrl->ctrl0_9,
- sizeof(*ctrl->ctrl0_9));
+ rc = rmi_write_block(rmi_dev, ctrl->ctrl0_9_address,
+ ctrl->ctrl0_9, RMI_F11_CTRL_REG_COUNT);
if (rc < 0)
dev_warn(&fn->dev, "Failed to write to delta_y_threshold %d. Code: %d.\n",
i, rc);
}
-
- rmi_f11_setup_sensor_debugfs(sensor);
}
- rmi_f11_setup_debugfs(fn);
-
mutex_init(&f11->dev_controls_mutex);
return 0;
}
@@ -1907,8 +780,12 @@ static int rmi_f11_register_devices(struct rmi_function *fn)
int sensors_itertd = 0;
int i;
int rc;
+ int board, version;
+
+ board = driver_data->board;
+ version = driver_data->rev;
- for (i = 0; i < (f11->dev_query.nbr_of_sensors + 1); i++) {
+ for (i = 0; i < (f11->nr_sensors + 1); i++) {
struct f11_2d_sensor *sensor = &f11->sensors[i];
sensors_itertd = i;
input_dev = input_allocate_device();
@@ -1927,8 +804,8 @@ static int rmi_f11_register_devices(struct rmi_function *fn)
goto error_unregister;
}
}
- sprintf(sensor->input_phys, "%s.abs%d/input0",
- dev_name(&fn->dev), i);
+ snprintf(sensor->input_phys, NAME_BUFFER_SIZE,
+ "%s.abs%d/input0", dev_name(&fn->dev), i);
input_dev->phys = sensor->input_phys;
input_dev->dev.parent = &rmi_dev->dev;
input_set_drvdata(input_dev, f11);
@@ -1939,7 +816,7 @@ static int rmi_f11_register_devices(struct rmi_function *fn)
f11_set_abs_params(fn, i);
- if (sensor->sens_query.info.has_rel) {
+ if (sensor->sens_query.has_rel) {
set_bit(EV_REL, input_dev->evbit);
set_bit(REL_X, input_dev->relbit);
set_bit(REL_Y, input_dev->relbit);
@@ -1951,7 +828,7 @@ static int rmi_f11_register_devices(struct rmi_function *fn)
goto error_unregister;
}
- if (sensor->sens_query.info.has_rel) {
+ if (sensor->sens_query.has_rel) {
/*create input device for mouse events */
input_dev_mouse = input_allocate_device();
if (!input_dev_mouse) {
@@ -1964,14 +841,13 @@ static int rmi_f11_register_devices(struct rmi_function *fn)
rc = driver->set_input_params(rmi_dev,
input_dev_mouse);
if (rc < 0) {
- dev_err(&fn->dev,
- "%s: Error in setting input device.\n",
+ dev_err(&fn->dev, "%s: Error in setting input device.\n",
__func__);
goto error_unregister;
}
}
- sprintf(sensor->input_phys_mouse, "%s.rel%d/input0",
- dev_name(&fn->dev), i);
+ snprintf(sensor->input_phys_mouse, NAME_BUFFER_SIZE,
+ "%s.rel%d/input0", dev_name(&fn->dev), i);
set_bit(EV_REL, input_dev_mouse->evbit);
set_bit(REL_X, input_dev_mouse->relbit);
set_bit(REL_Y, input_dev_mouse->relbit);
@@ -2018,7 +894,7 @@ static void rmi_f11_free_devices(struct rmi_function *fn)
struct f11_data *f11 = fn->data;
int i;
- for (i = 0; i < (f11->dev_query.nbr_of_sensors + 1); i++) {
+ for (i = 0; i < (f11->nr_sensors + 1); i++) {
if (f11->sensors[i].input)
input_unregister_device(f11->sensors[i].input);
if (f11->sensors[i].mouse_input)
@@ -2032,9 +908,9 @@ static int rmi_f11_config(struct rmi_function *fn)
int i;
int rc;
- for (i = 0; i < (f11->dev_query.nbr_of_sensors + 1); i++) {
+ for (i = 0; i < (f11->nr_sensors + 1); i++) {
rc = f11_write_control_regs(fn, &f11->sensors[i].sens_query,
- &f11->dev_controls, fn->fd.query_base_addr);
+ &f11->dev_controls, fn->fd.query_base_addr);
if (rc < 0)
return rc;
}
@@ -2052,7 +928,9 @@ int rmi_f11_attention(struct rmi_function *fn,
int error;
int i;
- for (i = 0; i < f11->dev_query.nbr_of_sensors + 1; i++) {
+ f11->report_count++;
+
+ for (i = 0; i < f11->nr_sensors + 1; i++) {
error = rmi_read_block(rmi_dev,
data_base_addr + data_base_addr_offset,
f11->sensors[i].data_pkt,
@@ -2067,79 +945,67 @@ int rmi_f11_attention(struct rmi_function *fn,
return 0;
}
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_PM
static int rmi_f11_resume(struct device *dev)
{
struct rmi_function *fn = to_rmi_function(dev);
struct rmi_device *rmi_dev = fn->rmi_dev;
struct f11_data *data = fn->data;
- /* Command register always reads as 0, so we can just use a local. */
- struct f11_2d_commands commands = {
- .rezero = true,
- };
- int error;
+ int retval = 0;
dev_dbg(&fn->dev, "Resuming...\n");
if (!data->rezero_wait_ms)
return 0;
- mdelay(data->rezero_wait_ms);
+ msleep(data->rezero_wait_ms);
- error = rmi_write_block(rmi_dev, fn->fd.command_base_addr,
- &commands, sizeof(commands));
- if (error < 0) {
- dev_err(&fn->dev,
- "%s: failed to issue rezero command, error = %d.",
- __func__, error);
- return error;
+ retval = rmi_write(rmi_dev, fn->fd.command_base_addr, RMI_F11_REZERO);
+ if (retval < 0) {
+ dev_err(&fn->dev, "%s: failed to issue rezero command, error = %d.",
+ __func__, retval);
+ return retval;
}
- return 0;
+ return retval;
}
#endif /* CONFIG_PM_SLEEP */
static SIMPLE_DEV_PM_OPS(rmi_f11_pm_ops, NULL, rmi_f11_resume);
-static int rmi_f11_probe(struct rmi_function *fn)
+static int rmi_f11_remove(struct rmi_function *fn)
{
- int error;
-
- error = rmi_f11_initialize(fn);
- if (error)
- return error;
-
- error = rmi_f11_register_devices(fn);
- if (error)
- return error;
-
- error = sysfs_create_group(&fn->dev.kobj, &rmi_f11_attr_group);
- if (error)
- return error;
-
+ rmi_f11_free_devices(fn);
return 0;
}
-static void rmi_f11_remove(struct rmi_function *fn)
+static int rmi_f11_probe(struct rmi_function *fn)
{
- debugfs_remove_recursive(fn->debugfs_root);
- sysfs_remove_group(&fn->dev.kobj, &rmi_f11_attr_group);
+ int rc;
- rmi_f11_free_devices(fn);
+ rc = rmi_f11_initialize(fn);
+ if (rc < 0)
+ return rc;
+
+ rc = rmi_f11_register_devices(fn);
+ if (rc < 0)
+ return rc;
+
+ return 0;
}
-static struct rmi_function_handler rmi_f11_handler = {
+static struct rmi_function_driver function_driver = {
.driver = {
- .name = "rmi_f11",
- .pm = &rmi_f11_pm_ops,
+ .name = "rmi_f11",
+ .pm = &rmi_f11_pm_ops,
},
- .func = 0x11,
- .probe = rmi_f11_probe,
- .remove = rmi_f11_remove,
- .config = rmi_f11_config,
- .attention = rmi_f11_attention,
+ .func = FUNCTION_NUMBER,
+ .probe = rmi_f11_probe,
+ .remove = rmi_f11_remove,
+ .config = rmi_f11_config,
+ .attention = rmi_f11_attention,
};
-module_rmi_driver(rmi_f11_handler);
+module_rmi_function_driver(function_driver);
MODULE_AUTHOR("Christopher Heiny <cheiny@synaptics.com");
MODULE_DESCRIPTION("RMI F11 module");
diff --git a/drivers/input/rmi4/rmi_f11.h b/drivers/input/rmi4/rmi_f11.h
new file mode 100644
index 0000000..35467e2
--- /dev/null
+++ b/drivers/input/rmi4/rmi_f11.h
@@ -0,0 +1,547 @@
+/*
+ * Copyright (c) 2013 Synaptics Incorporated
+ *
+ * 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.
+ */
+
+#ifndef RMI_F11_CONTROL_H
+#define RMI_F11_CONTROL_H
+
+#define F11_MAX_NUM_OF_SENSORS 8
+
+#define NAME_BUFFER_SIZE 256
+
+/** A note about RMI4 F11 register structure.
+ *
+ * There may be one or more individual 2D touch surfaces associated with an
+ * instance for F11. For example, a handheld device might have a touchscreen
+ * display on the front, and a touchpad on the back. F11 represents these touch
+ * surfaces as individual sensors, up to 7 on a given RMI4 device.
+ *
+ * The properties for
+ * a given sensor are described by its query registers. The number of query
+ * registers and the layout of their contents are described by the F11 device
+ * queries as well as the per-sensor query information. The query registers
+ * for sensor[n+1] immediately follow those for sensor[n], so the start address
+ * of the sensor[n+1] queries can only be computed if you know the size of the
+ * sensor[n] queries. Because each of the sensors may have different
+ * properties, the size of the query registers for each sensor must be
+ * calculated on a sensor by sensor basis.
+ *
+ * Similarly, each sensor has control registers that govern its behavior. The
+ * size and layout of the control registers for a given sensor can be determined
+ * by parsing that sensors query registers. The control registers for
+ * sensor[n+1] immediately follow those for sensor[n], so you can only know
+ * the start address for the sensor[n+1] controls if you know the size (and
+ * location) of the sensor[n] controls.
+ *
+ * And in a likewise fashion, each sensor has data registers where it reports
+ * its touch data and other interesting stuff. The size and layout of a
+ * sensors data registers must be determined by parsing its query registers.
+ * The data registers for sensor[n+1] immediately follow those for sensor[n],
+ * so you can only know the start address for the sensor[n+1] controls if you
+ * know the size (and location) of the sensor[n] controls.
+ *
+ * The short story is that we need to read and parse a lot of query
+ * registers in order to determine the attributes of a sensor[0]. Then
+ * we need to use that data to compute the size of the control and data
+ * registers for sensor[0]. Once we have that figured out, we can then do
+ * the same thing for each subsequent sensor.
+ *
+ * The end result is that we have a number of structs that aren't used to
+ * directly generate the input events, but their size, location and contents
+ * are critical to determining where the data we are interested in lives.
+ *
+ * At this time, the driver does not yet comprehend all possible F11
+ * configuration options, but it should be sufficient to cover 99% of RMI4 F11
+ * devices currently in the field.
+ */
+
+/**
+ * @rezero - writing this to the F11 command register will cause the sensor to
+ * calibrate to the current capacitive state.
+ */
+#define RMI_F11_REZERO 0x01
+
+/** Nr sensors will be going away in the near future, but for now we still
+ * need to worry about it.
+ */
+#define RMI_F11_NR_SENSORS_MASK 0x07
+#define RMI_F11_HAS_QUERY9 (1 << 3)
+#define RMI_F11_HAS_QUERY11 (1 << 4)
+#define RMI_F11_HAS_QUERY12 (1 << 5)
+#define RMI_F11_HAS_QUERY27 (1 << 6)
+#define RMI_F11_HAS_QUERY28 (1 << 7)
+
+/** Defs for Query 1 */
+
+#define RMI_F11_NR_FINGERS_MASK 0x07
+#define RMI_F11_HAS_REL (1 << 3)
+#define RMI_F11_HAS_ABS (1 << 4)
+#define RMI_F11_HAS_GESTURES (1 << 5)
+#define RMI_F11_HAS_SENSITIVITY_ADJ (1 << 6)
+#define RMI_F11_CONFIGURABLE (1 << 7)
+
+/** Defs for Query 2, 3, and 4. */
+#define RMI_F11_NR_ELECTRODES_MASK 0x7F
+
+/** Defs for Query 5 */
+
+#define RMI_F11_ABS_DATA_SIZE_MASK 0x03
+#define RMI_F11_HAS_ANCHORED_FINGER (1 << 2)
+#define RMI_F11_HAS_ADJ_HYST (1 << 3)
+#define RMI_F11_HAS_DRIBBLE (1 << 4)
+#define RMI_F11_HAS_BENDING_CORRECTION (1 << 5)
+#define RMI_F11_HAS_LARGE_OBJECT_SUPPRESSION (1 << 6)
+#define RMI_F11_HAS_JITTER_FILTER (1 << 7)
+
+/** Defs for Query 7 */
+#define RMI_F11_HAS_SINGLE_TAP (1 << 0)
+#define RMI_F11_HAS_TAP_AND_HOLD (1 << 1)
+#define RMI_F11_HAS_DOUBLE_TAP (1 << 2)
+#define RMI_F11_HAS_EARLY_TAP (1 << 3)
+#define RMI_F11_HAS_FLICK (1 << 4)
+#define RMI_F11_HAS_PRESS (1 << 5)
+#define RMI_F11_HAS_PINCH (1 << 6)
+#define RMI_F11_HAS_CHIRAL (1 << 7)
+
+/** Defs for Query 8 */
+#define RMI_F11_HAS_PALM_DET (1 << 0)
+#define RMI_F11_HAS_ROTATE (1 << 1)
+#define RMI_F11_HAS_TOUCH_SHAPES (1 << 2)
+#define RMI_F11_HAS_SCROLL_ZONES (1 << 3)
+#define RMI_F11_HAS_INDIVIDUAL_SCROLL_ZONES (1 << 4)
+#define RMI_F11_HAS_MF_SCROLL (1 << 5)
+#define RMI_F11_HAS_MF_EDGE_MOTION (1 << 6)
+#define RMI_F11_HAS_MF_SCROLL_INERTIA (1 << 7)
+
+/** Defs for Query 9. */
+#define RMI_F11_HAS_PEN (1 << 0)
+#define RMI_F11_HAS_PROXIMITY (1 << 1)
+#define RMI_F11_HAS_PALM_DET_SENSITIVITY (1 << 2)
+#define RMI_F11_HAS_SUPPRESS_ON_PALM_DETECT (1 << 3)
+#define RMI_F11_HAS_TWO_PEN_THRESHOLDS (1 << 4)
+#define RMI_F11_HAS_CONTACT_GEOMETRY (1 << 5)
+#define RMI_F11_HAS_PEN_HOVER_DISCRIMINATION (1 << 6)
+#define RMI_F11_HAS_PEN_FILTERS (1 << 7)
+
+/** Defs for Query 10. */
+#define RMI_F11_NR_TOUCH_SHAPES_MASK 0x1F
+
+/** Defs for Query 11 */
+
+#define RMI_F11_HAS_Z_TUNING (1 << 0)
+#define RMI_F11_HAS_ALGORITHM_SELECTION (1 << 1)
+#define RMI_F11_HAS_W_TUNING (1 << 2)
+#define RMI_F11_HAS_PITCH_INFO (1 << 3)
+#define RMI_F11_HAS_FINGER_SIZE (1 << 4)
+#define RMI_F11_HAS_SEGMENTATION_AGGRESSIVENESS (1 << 5)
+#define RMI_F11_HAS_XY_CLIP (1 << 6)
+#define RMI_F11_HAS_DRUMMING_FILTER (1 << 7)
+
+/** Defs for Query 12. */
+
+#define RMI_F11_HAS_GAPLESS_FINGER (1 << 0)
+#define RMI_F11_HAS_GAPLESS_FINGER_TUNING (1 << 1)
+#define RMI_F11_HAS_8BIT_W (1 << 2)
+#define RMI_F11_HAS_ADJUSTABLE_MAPPING (1 << 3)
+#define RMI_F11_HAS_INFO2 (1 << 4)
+#define RMI_F11_HAS_PHYSICAL_PROPS (1 << 5)
+#define RMI_F11_HAS_FINGER_LIMIT (1 << 6)
+#define RMI_F11_HAS_LINEAR_COEFF (1 << 7)
+
+/** Defs for Query 13. */
+
+#define RMI_F11_JITTER_WINDOW_MASK 0x1F
+#define RMI_F11_JITTER_FILTER_MASK 0x60
+#define RMI_F11_JITTER_FILTER_SHIFT 5
+
+/** Defs for Query 14. */
+#define RMI_F11_LIGHT_CONTROL_MASK 0x03
+#define RMI_F11_IS_CLEAR (1 << 2)
+#define RMI_F11_CLICKPAD_PROPS_MASK 0x18
+#define RMI_F11_CLICKPAD_PROPS_SHIFT 3
+#define RMI_F11_MOUSE_BUTTONS_MASK 0x60
+#define RMI_F11_MOUSE_BUTTONS_SHIFT 5
+#define RMI_F11_HAS_ADVANCED_GESTURES (1 << 7)
+
+#define RMI_F11_QUERY_SIZE 4
+#define RMI_F11_QUERY_GESTURE_SIZE 2
+
+#define F11_LIGHT_CTL_NONE 0x00
+#define F11_LUXPAD 0x01
+#define F11_DUAL_MODE 0x02
+
+#define F11_NOT_CLICKPAD 0x00
+#define F11_HINGED_CLICKPAD 0x01
+#define F11_UNIFORM_CLICKPAD 0x02
+
+/**
+ * Query registers 1 through 4 are always present.
+ *
+ * @nr_fingers - describes the maximum number of fingers the 2-D sensor
+ * supports.
+ * @has_rel - the sensor supports relative motion reporting.
+ * @has_abs - the sensor supports absolute poition reporting.
+ * @has_gestures - the sensor supports gesture reporting.
+ * @has_sensitivity_adjust - the sensor supports a global sensitivity
+ * adjustment.
+ * @configurable - the sensor supports various configuration options.
+ * @num_of_x_electrodes - the maximum number of electrodes the 2-D sensor
+ * supports on the X axis.
+ * @num_of_y_electrodes - the maximum number of electrodes the 2-D sensor
+ * supports on the Y axis.
+ * @max_electrodes - the total number of X and Y electrodes that may be
+ * configured.
+ *
+ * Query 5 is present if the has_abs bit is set.
+ *
+ * @abs_data_size - describes the format of data reported by the absolute
+ * data source. Only one format (the kind used here) is supported at this
+ * time.
+ * @has_anchored_finger - then the sensor supports the high-precision second
+ * finger tracking provided by the manual tracking and motion sensitivity
+ * options.
+ * @has_adjust_hyst - the difference between the finger release threshold and
+ * the touch threshold.
+ * @has_dribble - the sensor supports the generation of dribble interrupts,
+ * which may be enabled or disabled with the dribble control bit.
+ * @has_bending_correction - Bending related data registers 28 and 36, and
+ * control register 52..57 are present.
+ * @has_large_object_suppression - control register 58 and data register 28
+ * exist.
+ * @has_jitter_filter - query 13 and control 73..76 exist.
+ *
+ * Gesture information queries 7 and 8 are present if has_gestures bit is set.
+ *
+ * @has_single_tap - a basic single-tap gesture is supported.
+ * @has_tap_n_hold - tap-and-hold gesture is supported.
+ * @has_double_tap - double-tap gesture is supported.
+ * @has_early_tap - early tap is supported and reported as soon as the finger
+ * lifts for any tap event that could be interpreted as either a single tap
+ * or as the first tap of a double-tap or tap-and-hold gesture.
+ * @has_flick - flick detection is supported.
+ * @has_press - press gesture reporting is supported.
+ * @has_pinch - pinch gesture detection is supported.
+ * @has_palm_det - the 2-D sensor notifies the host whenever a large conductive
+ * object such as a palm or a cheek touches the 2-D sensor.
+ * @has_rotate - rotation gesture detection is supported.
+ * @has_touch_shapes - TouchShapes are supported. A TouchShape is a fixed
+ * rectangular area on the sensor that behaves like a capacitive button.
+ * @has_scroll_zones - scrolling areas near the sensor edges are supported.
+ * @has_individual_scroll_zones - if 1, then 4 scroll zones are supported;
+ * if 0, then only two are supported.
+ * @has_mf_scroll - the multifinger_scrolling bit will be set when
+ * more than one finger is involved in a scrolling action.
+ *
+ * Convenience for checking bytes in the gesture info registers. This is done
+ * often enough that we put it here to declutter the conditionals
+ *
+ * @query7_nonzero - true if none of the query 7 bits are set
+ * @query8_nonzero - true if none of the query 8 bits are set
+ *
+ * Query 9 is present if the has_query9 is set.
+ *
+ * @has_pen - detection of a stylus is supported and registers F11_2D_Ctrl20
+ * and F11_2D_Ctrl21 exist.
+ * @has_proximity - detection of fingers near the sensor is supported and
+ * registers F11_2D_Ctrl22 through F11_2D_Ctrl26 exist.
+ * @has_palm_det_sensitivity - the sensor supports the palm detect sensitivity
+ * feature and register F11_2D_Ctrl27 exists.
+ * @has_two_pen_thresholds - is has_pen is also set, then F11_2D_Ctrl35 exists.
+ * @has_contact_geometry - the sensor supports the use of contact geometry to
+ * map absolute X and Y target positions and registers F11_2D_Data18
+ * through F11_2D_Data27 exist.
+ *
+ * Touch shape info (query 10) is present if has_touch_shapes is set.
+ *
+ * @nr_touch_shapes - the total number of touch shapes supported.
+ *
+ * Query 11 is present if the has_query11 bit is set in query 0.
+ *
+ * @has_z_tuning - if set, the sensor supports Z tuning and registers
+ * F11_2D_Ctrl29 through F11_2D_Ctrl33 exist.
+ * @has_algorithm_selection - controls choice of noise suppression algorithm
+ * @has_w_tuning - the sensor supports Wx and Wy scaling and registers
+ * F11_2D_Ctrl36 through F11_2D_Ctrl39 exist.
+ * @has_pitch_info - the X and Y pitches of the sensor electrodes can be
+ * configured and registers F11_2D_Ctrl40 and F11_2D_Ctrl41 exist.
+ * @has_finger_size - the default finger width settings for the
+ * sensor can be configured and registers F11_2D_Ctrl42 through F11_2D_Ctrl44
+ * exist.
+ * @has_segmentation_aggressiveness - the sensor’s ability to distinguish
+ * multiple objects close together can be configured and register F11_2D_Ctrl45
+ * exists.
+ * @has_XY_clip - the inactive outside borders of the sensor can be
+ * configured and registers F11_2D_Ctrl46 through F11_2D_Ctrl49 exist.
+ * @has_drumming_filter - the sensor can be configured to distinguish
+ * between a fast flick and a quick drumming movement and registers
+ * F11_2D_Ctrl50 and F11_2D_Ctrl51 exist.
+ *
+ * Query 12 is present if hasQuery12 bit is set.
+ *
+ * @has_gapless_finger - control registers relating to gapless finger are
+ * present.
+ * @has_gapless_finger_tuning - additional control and data registers relating
+ * to gapless finger are present.
+ * @has_8bit_w - larger W value reporting is supported.
+ * @has_adjustable_mapping - TBD
+ * @has_info2 - the general info query14 is present
+ * @has_physical_props - additional queries describing the physical properties
+ * of the sensor are present.
+ * @has_finger_limit - indicates that F11 Ctrl 80 exists.
+ * @has_linear_coeff - indicates that F11 Ctrl 81 exists.
+ *
+ * Query 13 is present if Query 5's has_jitter_filter bit is set.
+ * @jitter_window_size - used by Design Studio 4.
+ * @jitter_filter_type - used by Design Studio 4.
+ *
+ * Query 14 is present if query 12's has_general_info2 flag is set.
+ *
+ * @light_control - Indicates what light/led control features are present, if
+ * any.
+ * @is_clear - if set, this is a clear sensor (indicating direct pointing
+ * application), otherwise it's opaque (indicating indirect pointing).
+ * @clickpad_props - specifies if this is a clickpad, and if so what sort of
+ * mechanism it uses
+ * @mouse_buttons - specifies the number of mouse buttons present (if any).
+ * @has_advanced_gestures - advanced driver gestures are supported.
+ */
+struct f11_2d_sensor_queries {
+ /* query1 */
+ u8 nr_fingers;
+ bool has_rel;
+ bool has_abs;
+ bool has_gestures;
+ bool has_sensitivity_adjust;
+ bool configurable;
+
+ /* query2 */
+ u8 nr_x_electrodes;
+
+ /* query3 */
+ u8 nr_y_electrodes;
+
+ /* query4 */
+ u8 max_electrodes;
+
+ /* query5 */
+ u8 abs_data_size;
+ bool has_anchored_finger;
+ bool has_adj_hyst;
+ bool has_dribble;
+ bool has_bending_correction;
+ bool has_large_object_suppression;
+ bool has_jitter_filter;
+
+ u8 f11_2d_query6;
+
+ /* query 7 */
+ bool has_single_tap;
+ bool has_tap_n_hold;
+ bool has_double_tap;
+ bool has_early_tap;
+ bool has_flick;
+ bool has_press;
+ bool has_pinch;
+ bool has_chiral;
+
+ bool query7_nonzero;
+
+ /* query 8 */
+ bool has_palm_det;
+ bool has_rotate;
+ bool has_touch_shapes;
+ bool has_scroll_zones;
+ bool has_individual_scroll_zones;
+ bool has_mf_scroll;
+ bool has_mf_edge_motion;
+ bool has_mf_scroll_inertia;
+
+ bool query8_nonzero;
+
+ /* Query 9 */
+ bool has_pen;
+ bool has_proximity;
+ bool has_palm_det_sensitivity;
+ bool has_suppress_on_palm_detect;
+ bool has_two_pen_thresholds;
+ bool has_contact_geometry;
+ bool has_pen_hover_discrimination;
+ bool has_pen_filters;
+
+ /* Query 10 */
+ u8 nr_touch_shapes;
+
+ /* Query 11. */
+ bool has_z_tuning;
+ bool has_algorithm_selection;
+ bool has_w_tuning;
+ bool has_pitch_info;
+ bool has_finger_size;
+ bool has_segmentation_aggressiveness;
+ bool has_XY_clip;
+ bool has_drumming_filter;
+
+ /* Query 12 */
+ bool has_gapless_finger;
+ bool has_gapless_finger_tuning;
+ bool has_8bit_w;
+ bool has_adjustable_mapping;
+ bool has_info2;
+ bool has_physical_props;
+ bool has_finger_limit;
+ bool has_linear_coeff_2;
+
+ /* Query 13 */
+ u8 jitter_window_size;
+ u8 jitter_filter_type;
+
+ /* Query 14 */
+ u8 light_control;
+ bool is_clear;
+ u8 clickpad_props;
+ u8 mouse_buttons;
+ bool has_advanced_gestures;
+};
+
+/* Defs for Ctrl0. */
+#define RMI_F11_REPORT_MODE_MASK 0x07
+#define RMI_F11_ABS_POS_FILT (1 << 3)
+#define RMI_F11_REL_POS_FILT (1 << 4)
+#define RMI_F11_REL_BALLISTICS (1 << 5)
+#define RMI_F11_DRIBBLE (1 << 6)
+#define RMI_F11_REPORT_BEYOND_CLIP (1 << 7)
+
+/* Defs for Ctrl1. */
+#define RMI_F11_PALM_DETECT_THRESH_MASK 0x0F
+#define RMI_F11_MOTION_SENSITIVITY_MASK 0x30
+#define RMI_F11_MANUAL_TRACKING (1 << 6)
+#define RMI_F11_MANUAL_TRACKED_FINGER (1 << 7)
+
+#define RMI_F11_DELTA_X_THRESHOLD 2
+#define RMI_F11_DELTA_Y_THRESHOLD 3
+
+#define RMI_F11_CTRL_REG_COUNT 10
+
+struct f11_2d_ctrl {
+ u8 ctrl0_9[RMI_F11_CTRL_REG_COUNT];
+ u16 ctrl0_9_address;
+};
+
+#define RMI_F11_ABS_BYTES 5
+#define RMI_F11_REL_BYTES 2
+
+/* Defs for Data 8 */
+
+#define RMI_F11_SINGLE_TAP (1 << 0)
+#define RMI_F11_TAP_AND_HOLD (1 << 1)
+#define RMI_F11_DOUBLE_TAP (1 << 2)
+#define RMI_F11_EARLY_TAP (1 << 3)
+#define RMI_F11_FLICK (1 << 4)
+#define RMI_F11_PRESS (1 << 5)
+#define RMI_F11_PINCH (1 << 6)
+
+/* Defs for Data 9 */
+
+#define RMI_F11_PALM_DETECT (1 << 0)
+#define RMI_F11_ROTATE (1 << 1)
+#define RMI_F11_SHAPE (1 << 2)
+#define RMI_F11_SCROLLZONE (1 << 3)
+#define RMI_F11_GESTURE_FINGER_COUNT_MASK 0x70
+
+/** Handy pointers into our data buffer.
+ *
+ * @f_state - start of finger state registers.
+ * @abs_pos - start of absolute position registers (if present).
+ * @rel_pos - start of relative data registers (if present).
+ * @gest_1 - gesture flags (if present).
+ * @gest_2 - gesture flags & finger count (if present).
+ * @pinch - pinch motion register (if present).
+ * @flick - flick distance X & Y, flick time (if present).
+ * @rotate - rotate motion and finger separation.
+ * @multi_scroll - chiral deltas for X and Y (if present).
+ * @scroll_zones - scroll deltas for 4 regions (if present).
+ */
+struct f11_2d_data {
+ u8 *f_state;
+ u8 *abs_pos;
+ s8 *rel_pos;
+ u8 *gest_1;
+ u8 *gest_2;
+ s8 *pinch;
+ u8 *flick;
+ u8 *rotate;
+ s8 *multi_scroll;
+ s8 *scroll_zones;
+};
+
+/**
+ * @axis_align - controls parameters that are useful in system prototyping
+ * and bring up.
+ * @sens_query - query registers for this particular sensor.
+ * @data - the data reported by this sensor, mapped into a collection of
+ * structs.
+ * @max_x - The maximum X coordinate that will be reported by this sensor.
+ * @max_y - The maximum Y coordinate that will be reported by this sensor.
+ * @nbr_fingers - How many fingers can this sensor report?
+ * @data_pkt - buffer for data reported by this sensor.
+ * @pkt_size - number of bytes in that buffer.
+ * @sensor_index - identifies this particular 2D touch sensor
+ * @type_a - some early RMI4 2D sensors do not reliably track the finger
+ * position when two fingers are on the device. When this is true, we
+ * assume we have one of those sensors and report events appropriately.
+ * @sensor_type - indicates whether we're touchscreen or touchpad.
+ * @input - input device for absolute pointing stream
+ * @mouse_input - input device for relative pointing stream.
+ * @input_phys - buffer for the absolute phys name for this sensor.
+ * @input_phys_mouse - buffer for the relative phys name for this sensor.
+ */
+struct f11_2d_sensor {
+ struct rmi_f11_2d_axis_alignment axis_align;
+ struct f11_2d_sensor_queries sens_query;
+ struct f11_2d_data data;
+ u16 max_x;
+ u16 max_y;
+ u8 nbr_fingers;
+ u8 *data_pkt;
+ int pkt_size;
+ u8 sensor_index;
+ u8 *button_map;
+ u32 type_a;
+ enum rmi_f11_sensor_type sensor_type;
+ struct input_dev *input;
+ struct input_dev *mouse_input;
+ struct rmi_function *fn;
+ char input_phys[NAME_BUFFER_SIZE];
+ char input_phys_mouse[NAME_BUFFER_SIZE];
+};
+
+/** Data pertaining to F11 in general. For per-sensor data, see struct
+ * f11_2d_sensor.
+ *
+ * @dev_query - F11 device specific query registers.
+ * @dev_controls - F11 device specific control registers.
+ * @dev_controls_mutex - lock for the control registers.
+ * @rezero_wait_ms - if nonzero, upon resume we will wait this many
+ * milliseconds before rezeroing the sensor(s). This is useful in systems with
+ * poor electrical behavior on resume, where the initial calibration of the
+ * sensor(s) coming out of sleep state may be bogus.
+ * @sensors - per sensor data structures.
+ */
+struct f11_data {
+ u8 nr_sensors;
+ bool has_query9;
+ bool has_query11;
+ bool has_query12;
+ bool has_query27;
+ bool has_query28;
+ struct f11_2d_ctrl dev_controls;
+ struct mutex dev_controls_mutex;
+ u16 rezero_wait_ms;
+ u64 report_count;
+ struct f11_2d_sensor sensors[F11_MAX_NUM_OF_SENSORS];
+};
+#endif
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* Re: [PATCH v2] input: ti_am33x_tsc: make the documentation for the ti,wire-config parameter clear
From: Grant Likely @ 2013-11-14 1:56 UTC (permalink / raw)
To: Kumar Gala, Sebastian Andrzej Siewior
Cc: Dmitry Torokhov, linux-input, Felipe Balbi, Rob Herring,
devicetree, o2g.org.ru
In-Reply-To: <15DA7589-35BD-4B24-B8A1-D44429ACC888@codeaurora.org>
On Tue, 12 Nov 2013 12:26:14 -0600, Kumar Gala <galak@codeaurora.org> wrote:
>
> On Nov 12, 2013, at 11:40 AM, Sebastian Andrzej Siewior <bigeasy@linutronix.de> wrote:
>
> > The document says "first four bits" and means the upper nibble. Most
> > people would probably agree that the first four bits are bits 0â¦3 and
> > that is the lower nibble.
> > This patch updates the documentation so it is clear what is meant.
> >
> > Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> > ---
> > v1â¦v2:
> > - use most/least significant instead of upper/ lower nibble
> > - add an example.
> >
> > .../devicetree/bindings/input/touchscreen/ti-tsc-adc.txt | 13 ++++++++-----
> > 1 file changed, 8 insertions(+), 5 deletions(-)
>
> Thanks
>
> Acked-by: Kumar Gala <galak@codeaurora.org>
Kumar, for patches like this, do you want to put them into a git tree
instead of acking? It will help spread the load.
g.
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [patch] Input: hp_sdc_rtc - unlock on error in hp_sdc_rtc_read_i8042timer()
From: Dan Carpenter @ 2013-11-14 8:18 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: Helge Deller, David Howells, linux-input, kernel-janitors
The transaction task here is hp_sdc_tasklet() and it releases the lock.
The problem is if we aren't able to queue the transaction then we need
to release the lock ourselves.
Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
diff --git a/drivers/input/misc/hp_sdc_rtc.c b/drivers/input/misc/hp_sdc_rtc.c
index 86b8228..45e0e3e 100644
--- a/drivers/input/misc/hp_sdc_rtc.c
+++ b/drivers/input/misc/hp_sdc_rtc.c
@@ -180,7 +180,10 @@ static int64_t hp_sdc_rtc_read_i8042timer (uint8_t loadcmd, int numreg)
if (WARN_ON(down_interruptible(&i8042tregs)))
return -1;
- if (hp_sdc_enqueue_transaction(&t)) return -1;
+ if (hp_sdc_enqueue_transaction(&t)) {
+ up(&i8042tregs);
+ return -1;
+ }
/* Sleep until results come back. */
if (WARN_ON(down_interruptible(&i8042tregs)))
^ permalink raw reply related
* Re: [PATCH 1/2] input: touchscreen: fix spelling mistake in TSC/ADC DT binding
From: Mark Rutland @ 2013-11-14 11:19 UTC (permalink / raw)
To: Felipe Balbi
Cc: Sebastian Andrzej Siewior, dmitry.torokhov@gmail.com,
rob.herring@calxeda.com, Pawel Moll, swarren@wwwdotorg.org,
ijc+devicetree@hellion.org.uk, rob@landley.net,
bcousson@baylibre.com, Tony Lindgren, devicetree@vger.kernel.org,
Linux OMAP Mailing List, linux-input@vger.kernel.org
In-Reply-To: <20131022120253.GD9340@gimli>
On Tue, Oct 22, 2013 at 01:02:53PM +0100, Felipe Balbi wrote:
> Hi,
>
> On Tue, Oct 22, 2013 at 10:42:00AM +0200, Sebastian Andrzej Siewior wrote:
> > On 10/21/2013 10:13 PM, Felipe Balbi wrote:
> > > diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c
> > > index e1c5300..b61df9d 100644
> > > --- a/drivers/input/touchscreen/ti_am335x_tsc.c
> > > +++ b/drivers/input/touchscreen/ti_am335x_tsc.c
> > > @@ -348,9 +348,16 @@ static int titsc_parse_dt(struct platform_device *pdev,
> > > if (err < 0)
> > > return err;
> > >
> > > - err = of_property_read_u32(node, "ti,coordiante-readouts",
> > > + /*
> > > + * try with new binding first. If it fails, still try with
> > > + * bogus, miss-spelled version.
> > > + */
> > > + err = of_property_read_u32(node, "ti,coordinate-readouts",
> > > &ts_dev->coordinate_readouts);
> > > if (err < 0)
> > > + err = of_property_read_u32(node, "ti,coordiante-readouts",
> > > + &ts_dev->coordinate_readouts);
> > > + if (err < 0)
> > > return err;
> >
> > Thanks, very good. Do we keep this fallback for ever or just for a year
> > or two?
>
> That's for DT maintainers to decide but considering DT is an ABI, I
> guess we need to keep for 30 years or so :-p
We keep it as long as we have to. If no-one's relying on the typo by the
next merge window, I see no reason we'd have to keep support for the
typo beyond that. If someone's shipped a device with a dtb with the typo
hard-coded into some ROM, that's another matter...
It might be worth printing a warning in the case of the typo'd version,
suggesting correcting the DT. That will encourage anyone with a broken
dt to get a fixed one.
Mark.
^ permalink raw reply
* Re: input question: ambient light sensor button
From: Pali Rohár @ 2013-11-14 12:02 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: Jiri Kosina, linux-kernel, linux-input
In-Reply-To: <20131113162840.GB11657@core.coreip.homeip.net>
[-- Attachment #1: Type: Text/Plain, Size: 1246 bytes --]
On Wednesday 13 November 2013 17:28:40 Dmitry Torokhov wrote:
> On Wed, Nov 13, 2013 at 11:47:18AM +0100, Jiri Kosina wrote:
> > On Sun, 15 Sep 2013, Pali Rohár wrote:
> > > I do not know where to ask this question, but I think that
> > > kernel developers could help me.
> > >
> > > I have notebook with one special button on keyboard which
> > > is designed for turning ambient light sensor on and off.
> > > By default pressing button do nothing (I can turn ambient
> > > light sensor on/off via sysfs platform wmi module).
> > > Button press is reported by kernel input device AT
> > > Translated Set 2 keyboard and reports it as button
> > > "touchpad off".
> > >
> > > Of course "touchpad off" is incorrect and I'd like to ask
> > > which kernel key or button from
> > > /usr/include/linux/input.h should be mapped for my
> > > ambient light sensor button? Is there already some? And
> > > what is strategy for allocating KEY_* and BTN_* numbers?
> >
> > This is maintained by Dmitry, so he's the one to answer
> > this. I am adding him to CC.
>
> I guess we need patch adding
>
> #define KEY_ALS_TOGGLE 0x230
>
> Thanks.
So there is no good key for als yet?
--
Pali Rohár
pali.rohar@gmail.com
[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply
* Re: [PATCH] Input: don't push static constants on stack for %*ph
From: Andy Shevchenko @ 2013-11-14 15:07 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: linux-input
In-Reply-To: <1378291309-13869-1-git-send-email-andriy.shevchenko@linux.intel.com>
On Wed, 2013-09-04 at 13:41 +0300, Andy Shevchenko wrote:
> There is no need to pass constants via stack. The width may be explicitly
> specified in the format.
Any comments on this so far?
>
> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> ---
> drivers/input/mouse/hgpk.c | 7 +++----
> drivers/input/touchscreen/atmel_mxt_ts.c | 4 ++--
> 2 files changed, 5 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/input/mouse/hgpk.c b/drivers/input/mouse/hgpk.c
> index 62be888..27909a1 100644
> --- a/drivers/input/mouse/hgpk.c
> +++ b/drivers/input/mouse/hgpk.c
> @@ -333,9 +333,8 @@ static bool hgpk_is_byte_valid(struct psmouse *psmouse, unsigned char *packet)
> }
>
> if (!valid)
> - psmouse_dbg(psmouse,
> - "bad data, mode %d (%d) %*ph\n",
> - priv->mode, pktcnt, 6, psmouse->packet);
> + psmouse_dbg(psmouse, "bad data, mode %d (%d) %6ph\n",
> + priv->mode, pktcnt, psmouse->packet);
>
> return valid;
> }
> @@ -1027,7 +1026,7 @@ static enum hgpk_model_t hgpk_get_model(struct psmouse *psmouse)
> return -EIO;
> }
>
> - psmouse_dbg(psmouse, "ID: %*ph\n", 3, param);
> + psmouse_dbg(psmouse, "ID: %3ph\n", param);
>
> /* HGPK signature: 0x67, 0x00, 0x<model> */
> if (param[0] != 0x67 || param[1] != 0x00)
> diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
> index 59aa240..dd44ebf 100644
> --- a/drivers/input/touchscreen/atmel_mxt_ts.c
> +++ b/drivers/input/touchscreen/atmel_mxt_ts.c
> @@ -331,8 +331,8 @@ static bool mxt_object_writable(unsigned int type)
> static void mxt_dump_message(struct device *dev,
> struct mxt_message *message)
> {
> - dev_dbg(dev, "reportid: %u\tmessage: %*ph\n",
> - message->reportid, 7, message->message);
> + dev_dbg(dev, "reportid: %u\tmessage: %7ph\n",
> + message->reportid, message->message);
> }
>
> static int mxt_check_bootloader(struct i2c_client *client,
--
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy
^ permalink raw reply
* Re: [PATCH 1/2] input: touchscreen: fix spelling mistake in TSC/ADC DT binding
From: Felipe Balbi @ 2013-11-14 15:54 UTC (permalink / raw)
To: Mark Rutland
Cc: Felipe Balbi, Sebastian Andrzej Siewior,
dmitry.torokhov@gmail.com, rob.herring@calxeda.com, Pawel Moll,
swarren@wwwdotorg.org, ijc+devicetree@hellion.org.uk,
rob@landley.net, bcousson@baylibre.com, Tony Lindgren,
devicetree@vger.kernel.org, Linux OMAP Mailing List,
linux-input@vger.kernel.org
In-Reply-To: <20131114111958.GG16396@e106331-lin.cambridge.arm.com>
[-- Attachment #1: Type: text/plain, Size: 1608 bytes --]
HI,
On Thu, Nov 14, 2013 at 11:19:59AM +0000, Mark Rutland wrote:
> > On Tue, Oct 22, 2013 at 10:42:00AM +0200, Sebastian Andrzej Siewior wrote:
> > > On 10/21/2013 10:13 PM, Felipe Balbi wrote:
> > > > diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c
> > > > index e1c5300..b61df9d 100644
> > > > --- a/drivers/input/touchscreen/ti_am335x_tsc.c
> > > > +++ b/drivers/input/touchscreen/ti_am335x_tsc.c
> > > > @@ -348,9 +348,16 @@ static int titsc_parse_dt(struct platform_device *pdev,
> > > > if (err < 0)
> > > > return err;
> > > >
> > > > - err = of_property_read_u32(node, "ti,coordiante-readouts",
> > > > + /*
> > > > + * try with new binding first. If it fails, still try with
> > > > + * bogus, miss-spelled version.
> > > > + */
> > > > + err = of_property_read_u32(node, "ti,coordinate-readouts",
> > > > &ts_dev->coordinate_readouts);
> > > > if (err < 0)
> > > > + err = of_property_read_u32(node, "ti,coordiante-readouts",
> > > > + &ts_dev->coordinate_readouts);
> > > > + if (err < 0)
> > > > return err;
> > >
> > > Thanks, very good. Do we keep this fallback for ever or just for a year
> > > or two?
> >
> > That's for DT maintainers to decide but considering DT is an ABI, I
> > guess we need to keep for 30 years or so :-p
>
> We keep it as long as we have to. If no-one's relying on the typo by the
> next merge window, I see no reason we'd have to keep support for the
and how could you know that ? considering it's an ABI, how could you
ever know that ?
--
balbi
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* Re: [PATCH] Input: clarify gamepad API ABS values
From: Antonio Ospite @ 2013-11-14 17:07 UTC (permalink / raw)
To: David Herrmann; +Cc: linux-input, Dmitry Torokhov
In-Reply-To: <1380806829-11824-1-git-send-email-dh.herrmann@gmail.com>
On Thu, 3 Oct 2013 15:27:09 +0200
David Herrmann <dh.herrmann@gmail.com> wrote:
> It wasn't really clear from the gamepad-API description how ABS values are
> mapped exactly. Clarify that negative is left/up and positive is
> right/down.
I was just going to ask that, thanks.
Has this patch picked up?
> ... Unfortunately, this means I screwed up the Wii U ProController
> ABI. Anyhow, this just means we continue to have 0 compatible gamepad
> drivers in the kernel. User-space needs to fix them up, anyway, as all
> other gamepads are also incompatible.
>
I know it is not really relevant and you won't fix the kernel interface
anyway, but I was just curios: is there any known userspace using the
gamepad API?
Another question is below.
> Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
> ---
> Documentation/input/gamepad.txt | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/Documentation/input/gamepad.txt b/Documentation/input/gamepad.txt
> index 8002c89..31bb6a4 100644
> --- a/Documentation/input/gamepad.txt
> +++ b/Documentation/input/gamepad.txt
> @@ -122,12 +122,14 @@ D-Pad:
> BTN_DPAD_*
> Analog buttons are reported as:
> ABS_HAT0X and ABS_HAT0Y
> + (for ABS values negative is left/up, positive is right/down)
>
Does that mean that analog D-Pad Left and D-Pad Right are supposed to be
described as a single axis (ABS_HAT0X), even if in the input report
they come as two different fields (non adjacent even)? And same for
analog Up/Down?
JFYI on the PS3 controller it is possible to have values from analog
D-Pad Left and analog D-Pad Right at the same time, even if it is
mechanically unlikely.
> Analog-Sticks:
> The left analog-stick is reported as ABS_X, ABS_Y. The right analog stick is
> reported as ABS_RX, ABS_RY. Zero, one or two sticks may be present.
> If analog-sticks provide digital buttons, they are mapped accordingly as
> BTN_THUMBL (first/left) and BTN_THUMBR (second/right).
> + (for ABS values negative is left/up, positive is right/down)
>
> Triggers:
> Trigger buttons can be available as digital or analog buttons or both. User-
> @@ -138,6 +140,7 @@ Triggers:
> ABS_HAT2X (right/ZR) and BTN_TL2 or ABS_HAT2Y (left/ZL).
> If only one trigger-button combination is present (upper+lower), they are
> reported as "right" triggers (BTN_TR/ABS_HAT1X).
> + (ABS trigger values start at 0, pressure is reported as positive values)
>
What about analog Action-Pad buttons?
Do you suggest any mapping for them?
> Menu-Pad:
> Menu buttons are always digital and are mapped according to their location
Thanks,
Antonio
--
Antonio Ospite
http://ao2.it
A: Because it messes up the order in which people normally read text.
See http://en.wikipedia.org/wiki/Posting_style
Q: Why is top-posting such a bad thing?
^ permalink raw reply
* Re: [PATCH] Input: clarify gamepad API ABS values
From: David Herrmann @ 2013-11-14 17:22 UTC (permalink / raw)
To: Antonio Ospite; +Cc: open list:HID CORE LAYER, Dmitry Torokhov
In-Reply-To: <20131114180720.fece45888942c29d5865073e@studenti.unina.it>
Hi
On Thu, Nov 14, 2013 at 6:07 PM, Antonio Ospite
<ospite@studenti.unina.it> wrote:
> On Thu, 3 Oct 2013 15:27:09 +0200
> David Herrmann <dh.herrmann@gmail.com> wrote:
>
>> It wasn't really clear from the gamepad-API description how ABS values are
>> mapped exactly. Clarify that negative is left/up and positive is
>> right/down.
>
> I was just going to ask that, thanks.
> Has this patch picked up?
Yepp, already applied by Dmitry to input-next.
>> ... Unfortunately, this means I screwed up the Wii U ProController
>> ABI. Anyhow, this just means we continue to have 0 compatible gamepad
>> drivers in the kernel. User-space needs to fix them up, anyway, as all
>> other gamepads are also incompatible.
>>
>
> I know it is not really relevant and you won't fix the kernel interface
> anyway, but I was just curios: is there any known userspace using the
> gamepad API?
The xwiimote userspace-drivers use it, other than that it is hard to
tell.. I looked at a lot of games and applications and they all just
contain a bunch of hacks and per-driver-mappings. I cannot really tell
whether anyone uses it, yet (there's isn't really a reason to use it
as only the wiimote kernel drivers comply to it).
However, I hope we can make all new drivers adhere these rules so
user-space no longer has to guess the mappings.
> Another question is below.
>
>> Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
>> ---
>> Documentation/input/gamepad.txt | 3 +++
>> 1 file changed, 3 insertions(+)
>>
>> diff --git a/Documentation/input/gamepad.txt b/Documentation/input/gamepad.txt
>> index 8002c89..31bb6a4 100644
>> --- a/Documentation/input/gamepad.txt
>> +++ b/Documentation/input/gamepad.txt
>> @@ -122,12 +122,14 @@ D-Pad:
>> BTN_DPAD_*
>> Analog buttons are reported as:
>> ABS_HAT0X and ABS_HAT0Y
>> + (for ABS values negative is left/up, positive is right/down)
>>
>
> Does that mean that analog D-Pad Left and D-Pad Right are supposed to be
> described as a single axis (ABS_HAT0X), even if in the input report
> they come as two different fields (non adjacent even)? And same for
> analog Up/Down?
>
> JFYI on the PS3 controller it is possible to have values from analog
> D-Pad Left and analog D-Pad Right at the same time, even if it is
> mechanically unlikely.
Yes, it's a single axis. It's called a D-Pad (Direction-Pad) so it is
supposed to give information about a direction. This somehow excludes
reporting information for left/right separately, right?
I didn't know there are actually devices reporting this separately, so
I never considered that during the development of the API.
Fortunately, the drivers which follow this spec all use digital DPADs,
so we can easily change it now.
What exactly does the PS3 controller return? Is it
pressure-information for the dpad? I'm open to change this to report 4
ABS values, but I'm not sure that we want that. From a user-space
perspective I want to get 2 values, not 4. I wouldn't even know what
to do with 4 dpad-values. So why not convert that in the kernel to:
x = x1 - x0;
y = y1 - y0;
This gives you proper x/y DPAD values from 4 pressure inputs.
But I'm open for suggestions..
>> Analog-Sticks:
>> The left analog-stick is reported as ABS_X, ABS_Y. The right analog stick is
>> reported as ABS_RX, ABS_RY. Zero, one or two sticks may be present.
>> If analog-sticks provide digital buttons, they are mapped accordingly as
>> BTN_THUMBL (first/left) and BTN_THUMBR (second/right).
>> + (for ABS values negative is left/up, positive is right/down)
>>
>> Triggers:
>> Trigger buttons can be available as digital or analog buttons or both. User-
>> @@ -138,6 +140,7 @@ Triggers:
>> ABS_HAT2X (right/ZR) and BTN_TL2 or ABS_HAT2Y (left/ZL).
>> If only one trigger-button combination is present (upper+lower), they are
>> reported as "right" triggers (BTN_TR/ABS_HAT1X).
>> + (ABS trigger values start at 0, pressure is reported as positive values)
>>
>
> What about analog Action-Pad buttons?
> Do you suggest any mapping for them?
Do we have devices which report analog action-pad values? If there
are, we can introduce new ABS_* bits for them (the current ones really
don't fit). This requires the ABS2 patches which are currently pending
on the list, though.
And again, what information do these action-pads provide? Pressure?
Thanks
David
^ permalink raw reply
* Re: [PATCH] Input: clarify gamepad API ABS values
From: simon @ 2013-11-14 17:43 UTC (permalink / raw)
To: Antonio Ospite; +Cc: David Herrmann, linux-input, Dmitry Torokhov
In-Reply-To: <20131114180720.fece45888942c29d5865073e@studenti.unina.it>
>> ... Unfortunately, this means I screwed up the Wii U ProController
>> ABI. Anyhow, this just means we continue to have 0 compatible gamepad
>> drivers in the kernel. User-space needs to fix them up, anyway, as all
>> other gamepads are also incompatible.
>>
>
> I know it is not really relevant and you won't fix the kernel interface
> anyway, but I was just curios: is there any known userspace using the
> gamepad API?
SDL are talking about 'fixing things'.... just in-case we're breaking it
(again) for them
http://lists.libsdl.org/pipermail/sdl-libsdl.org/2013-November/091850.html
Simon
^ permalink raw reply
* Re: [PATCH] Input: clarify gamepad API ABS values
From: Antonio Ospite @ 2013-11-14 22:53 UTC (permalink / raw)
To: David Herrmann; +Cc: open list:HID CORE LAYER, Dmitry Torokhov
In-Reply-To: <CANq1E4Q-yPVh7ah-SMGb--VCJA97c2yCLSGQakFzGWWQydo7jw@mail.gmail.com>
On Thu, 14 Nov 2013 18:22:28 +0100
David Herrmann <dh.herrmann@gmail.com> wrote:
> On Thu, Nov 14, 2013 at 6:07 PM, Antonio Ospite
> <ospite@studenti.unina.it> wrote:
[...]
> > I know it is not really relevant and you won't fix the kernel interface
> > anyway, but I was just curios: is there any known userspace using the
> > gamepad API?
>
> The xwiimote userspace-drivers use it, other than that it is hard to
> tell.. I looked at a lot of games and applications and they all just
> contain a bunch of hacks and per-driver-mappings. I cannot really tell
> whether anyone uses it, yet (there's isn't really a reason to use it
> as only the wiimote kernel drivers comply to it).
>
> However, I hope we can make all new drivers adhere these rules so
> user-space no longer has to guess the mappings.
>
I am going to adopt the gamepad API for the PS3 controller as well,
motivating the change with the current utterly broken status of
the mapping from the evdev point of view.
I have reasons to believe that any existing linux software targeting the
PS3 controller is just parsing the hidraw data itself, the joystick
interface is not completely usable either in the current status.
> > Another question is below.
> >
> >> Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
> >> ---
> >> Documentation/input/gamepad.txt | 3 +++
> >> 1 file changed, 3 insertions(+)
> >>
> >> diff --git a/Documentation/input/gamepad.txt b/Documentation/input/gamepad.txt
> >> index 8002c89..31bb6a4 100644
> >> --- a/Documentation/input/gamepad.txt
> >> +++ b/Documentation/input/gamepad.txt
> >> @@ -122,12 +122,14 @@ D-Pad:
> >> BTN_DPAD_*
> >> Analog buttons are reported as:
> >> ABS_HAT0X and ABS_HAT0Y
> >> + (for ABS values negative is left/up, positive is right/down)
> >>
> >
> > Does that mean that analog D-Pad Left and D-Pad Right are supposed to be
> > described as a single axis (ABS_HAT0X), even if in the input report
> > they come as two different fields (non adjacent even)? And same for
> > analog Up/Down?
> >
> > JFYI on the PS3 controller it is possible to have values from analog
> > D-Pad Left and analog D-Pad Right at the same time, even if it is
> > mechanically unlikely.
>
> Yes, it's a single axis. It's called a D-Pad (Direction-Pad) so it is
> supposed to give information about a direction. This somehow excludes
> reporting information for left/right separately, right?
>
Mathematically, yes, but I am still not completely sure that being so
strict is convenient in this case: when describing the _digital_ D-Pad
we mention "4 buttons" and then "four directions", and indeed hardware
generally exposes all four directional buttons independently (even if
opposed ones are not supposed to be pressed at the same time, they still
might); so it could make sense to use the same scheme for _analog_
D-Pad axes too: four independent analog D-Pad axes.
Again, JFYI the PS3 controller allows to press even _digital_ D-Pad
Left and Right at the same time even if this is mechanically trickier
to achieve than the correspondent analog events.
> I didn't know there are actually devices reporting this separately, so
> I never considered that during the development of the API.
> Fortunately, the drivers which follow this spec all use digital DPADs,
> so we can easily change it now.
>
I'd say we change it. But maybe it's better to hear from someone more
into games.
> What exactly does the PS3 controller return? Is it
> pressure-information for the dpad?
Yes it is, 4 pressure values form 0 to 255, one for each "direction".
>I'm open to change this to report 4
> ABS values, but I'm not sure that we want that. From a user-space
> perspective I want to get 2 values, not 4. I wouldn't even know what
> to do with 4 dpad-values. So why not convert that in the kernel to:
> x = x1 - x0;
> y = y1 - y0;
> This gives you proper x/y DPAD values from 4 pressure inputs.
>
> But I'm open for suggestions..
If I have to, I'll do that conversion; I just don't know yet how to
prepare for this scenario at the HID descriptor level.
In my driver I'd like to just fixup the whole HID descriptor and then
simply remap the keycodes, I'd like to avoid parsing the raw data
explicitly in C.
[...]
> >
> > What about analog Action-Pad buttons?
> > Do you suggest any mapping for them?
>
> Do we have devices which report analog action-pad values? If there
> are, we can introduce new ABS_* bits for them (the current ones really
> don't fit). This requires the ABS2 patches which are currently pending
> on the list, though.
>
> And again, what information do these action-pads provide? Pressure?
The PS3 controller reports a pressure value from 0 to 255 for each of
the Action-Pad buttons.
I am writing some documentation of the input report of the PS3
controller, I'll post it here soon.
Thanks,
Antonio
--
Antonio Ospite
http://ao2.it
A: Because it messes up the order in which people normally read text.
See http://en.wikipedia.org/wiki/Posting_style
Q: Why is top-posting such a bad thing?
^ permalink raw reply
* [git pull] Input updates for 3.13-rc0
From: Dmitry Torokhov @ 2013-11-15 2:01 UTC (permalink / raw)
To: Linus Torvalds; +Cc: linux-kernel, linux-input
[-- Attachment #1: Type: text/plain, Size: 7251 bytes --]
Hi Linus,
Please pull from:
git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git for-linus
or
master.kernel.org:/pub/scm/linux/kernel/git/dtor/input.git for-linus
to receive updates for the input subsystem. You will get an new drivers
for Hyper-V synthetic keyboard and for Neonode zForce touchscreens, plus
a bunch of driver fixes and cleanups.
Please note that you will get a small conflict in
arch/arm/boot/dts/am335x-evmsk.dts but that shoudl be easily resolvable.
Changelog:
---------
Dan Carpenter (1):
Input: tnetv107x-keypad - make irqs signed for error handling
Daniel Stone (1):
Input: evdev - fall back to vmalloc for client event buffer
David Herrmann (1):
Input: clarify gamepad API ABS values
Dmitry Torokhov (1):
Revert "Input: ALPS - add support for model found on Dell XT2"
Duan Jiong (1):
Input: cyttsp4 - replace IS_ERR and PTR_ERR with PTR_ERR_OR_ZERO
Felipe Balbi (2):
Input: ti_am335x_tsc - fix spelling mistake in TSC/ADC DT binding
arm: dts: am335x sk: add touchscreen support
Geyslan G. Bem (1):
Input: cypress_ps2 - remove useless cast
Heiko Stübner (1):
Input: add driver for Neonode zForce based touchscreens
Jason Gerecke (2):
Input: wacom - support EMR and MFT sensors of Cintiq Companion Hybrid
Input: wacom - send proper tablet state info when pen leaves proximity
Jingoo Han (1):
Input: cypress_ps2 - remove casting the return value which is a void pointer
Joseph Salisbury (1):
Input: cypress_ps2 - do not consider data bad if palm is detected
K. Y. Srinivasan (1):
Input: add a driver to support Hyper-V synthetic keyboard
Kang Hu (1):
Input: remove a redundant max() call
Laurent Pinchart (1):
Input: sh_keysc - enable the driver on all ARM platforms
Majunath Goudar (1):
Input: fix PWM-related undefined reference errors
Ping Cheng (4):
Input: wacom - testing result shows get_report is unnecessary.
Input: wacom - LED is only supported through digitizer interface
Input: wacom - add support for three new Intuos Pro devices
Input: wacom - not all multi-interface devices support touch
Ryan Mallon (1):
Input: uinput - support injecting multiple events in one write() call
Sachin Kamat (20):
Input: cobalt_btns - remove redundant dev_set_drvdata
Input: htcpen - remove redundant dev_set_drvdata
Input: rb532_button - remove redundant dev_set_drvdata
Input: cyttsp4_core - remove redundant dev_set_drvdata
Input: ad714x-spi - remove redundant spi_set_drvdata
Input: ad7877 - remove redundant spi_set_drvdata
Input: ad7879-spi - remove redundant spi_set_drvdata
Input: tsc2005 - remove redundant spi_set_drvdata
Input: lpc32xx-keys - remove redundant of_match_ptr
Input: nspire-keypad - remove redundant of_match_ptr
Input: tegra-kbc - remove redundant of_match_ptr
Input: sirfsoc-onkey - remove redundant of_match_ptr
Input: egalax_ts - remove redundant of_match_ptr
Input: ti_am335x_tsc - remove redundant of_match_ptr
Input: gpio_keys - include linux/of.h header
Input: gpio_keys_polled - include linux/of.h header
Input: pxa27x_keypad - include linux/of.h header
Input: pwm-beeper - include linux/of.h header
Input: rotary_encoder - include linux/of.h header
Input: st1232 - include linux/of.h header
Tom Gundersen (3):
Input: i8042 - add PNP modaliases
Input: allow deselecting serio drivers even without CONFIG_EXPERT
Input: mousedev - allow disabling even without CONFIG_EXPERT
Wei Yongjun (3):
Input: nspire-keypad - add missing clk_disable_unprepare() on error path
Input: mpu3050 - add missing i2c_set_clientdata() in mpu3050_probe()
Input: mma8450 - add missing i2c_set_clientdata() in mma8450_probe()
Yunkang Tang (1):
Input: ALPS - change secondary device's name
Diffstat:
--------
.../bindings/input/touchscreen/ti-tsc-adc.txt | 2 +-
Documentation/input/gamepad.txt | 3 +
arch/arm/boot/dts/am335x-evm.dts | 2 +-
arch/arm/boot/dts/am335x-evmsk.dts | 10 +
drivers/input/Kconfig | 2 +-
drivers/input/evdev.c | 16 +-
drivers/input/input.c | 2 +-
drivers/input/keyboard/Kconfig | 6 +-
drivers/input/keyboard/gpio_keys.c | 1 +
drivers/input/keyboard/gpio_keys_polled.c | 1 +
drivers/input/keyboard/lpc32xx-keys.c | 2 +-
drivers/input/keyboard/nspire-keypad.c | 6 +-
drivers/input/keyboard/pxa27x_keypad.c | 1 +
drivers/input/keyboard/tegra-kbc.c | 2 +-
drivers/input/keyboard/tnetv107x-keypad.c | 4 +-
drivers/input/misc/Kconfig | 4 +-
drivers/input/misc/ad714x-spi.c | 1 -
drivers/input/misc/cobalt_btns.c | 2 -
drivers/input/misc/mma8450.c | 4 +-
drivers/input/misc/mpu3050.c | 1 +
drivers/input/misc/pwm-beeper.c | 1 +
drivers/input/misc/rb532_button.c | 1 -
drivers/input/misc/rotary_encoder.c | 1 +
drivers/input/misc/sirfsoc-onkey.c | 2 +-
drivers/input/misc/uinput.c | 26 +-
drivers/input/mouse/alps.c | 3 +-
drivers/input/mouse/cypress_ps2.c | 29 +-
drivers/input/serio/Kconfig | 16 +-
drivers/input/serio/Makefile | 1 +
drivers/input/serio/hyperv-keyboard.c | 437 +++++++++++
drivers/input/serio/i8042-x86ia64io.h | 2 +
drivers/input/tablet/wacom_sys.c | 96 ++-
drivers/input/tablet/wacom_wac.c | 114 ++-
drivers/input/tablet/wacom_wac.h | 8 +-
drivers/input/touchscreen/Kconfig | 13 +
drivers/input/touchscreen/Makefile | 1 +
drivers/input/touchscreen/ad7877.c | 2 -
drivers/input/touchscreen/ad7879-spi.c | 1 -
drivers/input/touchscreen/cyttsp4_core.c | 2 -
drivers/input/touchscreen/cyttsp4_spi.c | 5 +-
drivers/input/touchscreen/egalax_ts.c | 2 +-
drivers/input/touchscreen/htcpen.c | 2 -
drivers/input/touchscreen/st1232.c | 1 +
drivers/input/touchscreen/ti_am335x_tsc.c | 11 +-
drivers/input/touchscreen/tsc2005.c | 2 -
drivers/input/touchscreen/zforce_ts.c | 836 +++++++++++++++++++++
include/linux/platform_data/zforce_ts.h | 26 +
47 files changed, 1585 insertions(+), 128 deletions(-)
create mode 100644 drivers/input/serio/hyperv-keyboard.c
create mode 100644 drivers/input/touchscreen/zforce_ts.c
create mode 100644 include/linux/platform_data/zforce_ts.h
--
Dmitry
[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* Re: [PATCH 04/13] Input: add motion-tracking ABS_* bits and docs
From: Antonio Ospite @ 2013-11-15 10:11 UTC (permalink / raw)
To: David Herrmann
Cc: linux-input, Dmitry Torokhov, Jiri Kosina, Peter Hutterer,
Benjamin Tissoires
In-Reply-To: <1383336984-26601-5-git-send-email-dh.herrmann@gmail.com>
On Fri, 1 Nov 2013 21:16:15 +0100
David Herrmann <dh.herrmann@gmail.com> wrote:
> Motion sensors are getting quite common in mobile devices. To avoid
> returning accelerometer data via ABS_X/Y/Z and irritating the Xorg
> mouse-driver, this adds separate ABS_* bits for that.
>
> This is needed if gaming devices want to report their normal data plus
> accelerometer/gyro data. Usually, ABS_X/Y are already used by analog
> sticks, so need separate definitions, anyway.
>
> Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
Hi, what's the status of this patch?
I cannot see it in Dmitry's repository, David maybe you have another
repository I can pull from?
Thanks,
Antonio
--
Antonio Ospite
http://ao2.it
A: Because it messes up the order in which people normally read text.
See http://en.wikipedia.org/wiki/Posting_style
Q: Why is top-posting such a bad thing?
^ permalink raw reply
* Re: [PATCH 04/13] Input: add motion-tracking ABS_* bits and docs
From: David Herrmann @ 2013-11-15 10:17 UTC (permalink / raw)
To: Antonio Ospite
Cc: open list:HID CORE LAYER, Dmitry Torokhov, Jiri Kosina,
Peter Hutterer, Benjamin Tissoires
In-Reply-To: <20131115111135.1548dc0a4effdad8f672ff24@studenti.unina.it>
Hi Antonio
On Fri, Nov 15, 2013 at 11:11 AM, Antonio Ospite
<ospite@studenti.unina.it> wrote:
> On Fri, 1 Nov 2013 21:16:15 +0100
> David Herrmann <dh.herrmann@gmail.com> wrote:
>
>> Motion sensors are getting quite common in mobile devices. To avoid
>> returning accelerometer data via ABS_X/Y/Z and irritating the Xorg
>> mouse-driver, this adds separate ABS_* bits for that.
>>
>> This is needed if gaming devices want to report their normal data plus
>> accelerometer/gyro data. Usually, ABS_X/Y are already used by analog
>> sticks, so need separate definitions, anyway.
>>
>> Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
>
> Hi, what's the status of this patch?
> I cannot see it in Dmitry's repository, David maybe you have another
> repository I can pull from?
Please see patch 1/13 and 2/13. They fix the kernel ABI to support new
ABS_* bits (the current ABI is broken in that regard). As this is
quite critical and caused breaks during the last merge-window, we
haven't merged it yet. I hope to get it into 3.14, though. The current
patches seem fine and work for me. I will try to get the user-space
part working in the next weeks.
Any help is welcome!
Thanks
David
^ permalink raw reply
* [PATCH v2] Input:Add support for DualPoint device on Dell XT2 model
From: Yunkang Tang @ 2013-11-15 14:11 UTC (permalink / raw)
To: dmitry.torokhov, cernekee, dturvene
Cc: linux-input, ndevos, jclift, yunkang.tang
Hi all,
Here is the 2nd version for supporting DualPoint device on Dell XT2 model
Changelist:
- Bugfix for trackpoint's behavior was abnormal in v1.
[Root Cause]
Because of the special MPU controller being used in this DualPoint device,
when sending ALPS magic know command, not only touchpad but also trackpoint
received the commands. This would cause trackpoint also enter an unexpected
raw mode. Unfortunately, trackpoint's raw raw packet has the same check bit
as touchpad's but with different packet format. And this would cause
trackpoint's abnormal behavior.
[Solution]
1. Define a new ALPS_PROTO_V6 macro for this device.
2. Add new initialization logic.
3. Add new packet process logic.
# Touchpad's dimension is 2047*1535.
SelfTest:
1. Move on touchpad -- OK
2. Vertical/Horizontal wheel on touchpad -- OK
3. Tap / Tap and drag on touchpad -- OK
4. Click with touchpad's L/R button -- OK
5. Move on touchpad with pressing touchpad's button -- OK
6. Move on trackpoint -- OK
7. Click with trackpoint's L/R button -- OK
8. Move on trackpoint with pressing trackpoint's button -- OK
9. Move cursor with both touchpad and trackpoint -- OK
10. Move on touchpad with pressing trackpoint's button -- OK
11. Move on trackpoint with pressing touchpad's button -- OK
Thanks
Signed-off-by: Yunkang Tang <yunkang.tang@cn.alps.com>
---
drivers/input/mouse/alps.c | 206 ++++++++++++++++++++++++++++++++++++++++++++-
drivers/input/mouse/alps.h | 1 +
2 files changed, 204 insertions(+), 3 deletions(-)
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index ca7a26f..5cf62e3 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -70,6 +70,25 @@ static const struct alps_nibble_commands alps_v4_nibble_commands[] = {
{ PSMOUSE_CMD_SETSCALE11, 0x00 }, /* f */
};
+static const struct alps_nibble_commands alps_v6_nibble_commands[] = {
+ { PSMOUSE_CMD_ENABLE, 0x00 }, /* 0 */
+ { PSMOUSE_CMD_SETRATE, 0x0a }, /* 1 */
+ { PSMOUSE_CMD_SETRATE, 0x14 }, /* 2 */
+ { PSMOUSE_CMD_SETRATE, 0x28 }, /* 3 */
+ { PSMOUSE_CMD_SETRATE, 0x3c }, /* 4 */
+ { PSMOUSE_CMD_SETRATE, 0x50 }, /* 5 */
+ { PSMOUSE_CMD_SETRATE, 0x64 }, /* 6 */
+ { PSMOUSE_CMD_SETRATE, 0xc8 }, /* 7 */
+ { PSMOUSE_CMD_GETID, 0x00 }, /* 8 */
+ { PSMOUSE_CMD_GETINFO, 0x00 }, /* 9 */
+ { PSMOUSE_CMD_SETRES, 0x00 }, /* a */
+ { PSMOUSE_CMD_SETRES, 0x01 }, /* b */
+ { PSMOUSE_CMD_SETRES, 0x02 }, /* c */
+ { PSMOUSE_CMD_SETRES, 0x03 }, /* d */
+ { PSMOUSE_CMD_SETSCALE21, 0x00 }, /* e */
+ { PSMOUSE_CMD_SETSCALE11, 0x00 }, /* f */
+};
+
#define ALPS_DUALPOINT 0x02 /* touchpad has trackstick */
#define ALPS_PASS 0x04 /* device has a pass-through port */
@@ -103,6 +122,7 @@ static const struct alps_model_info alps_model_data[] = {
/* Dell Latitude E5500, E6400, E6500, Precision M4400 */
{ { 0x62, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xcf, 0xcf,
ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED },
+ { { 0x73, 0x00, 0x14 }, 0x00, ALPS_PROTO_V6, 0xff, 0xff, ALPS_DUALPOINT }, /* Dell XT2 */
{ { 0x73, 0x02, 0x50 }, 0x00, ALPS_PROTO_V2, 0xcf, 0xcf, ALPS_FOUR_BUTTONS }, /* Dell Vostro 1400 */
{ { 0x52, 0x01, 0x14 }, 0x00, ALPS_PROTO_V2, 0xff, 0xff,
ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, /* Toshiba Tecra A11-11L */
@@ -645,6 +665,76 @@ static void alps_process_packet_v3(struct psmouse *psmouse)
alps_process_touchpad_packet_v3(psmouse);
}
+static void alps_process_packet_v6(struct psmouse *psmouse)
+{
+ struct alps_data *priv = psmouse->private;
+ unsigned char *packet = psmouse->packet;
+ struct input_dev *dev = psmouse->dev;
+ struct input_dev *dev2 = priv->dev2;
+ int x, y, z, left, right, middle;
+
+ /*
+ * We can use Byte5 to distinguish if the packet is from Touchpad
+ * or Trackpoint.
+ * Touchpad: 0 - 0x7E
+ * Trackpoint: 0x7F
+ */
+ if (packet[5] == 0x7F) {
+ /* It should be a DualPoint when received Trackpoint packet */
+ if (!(priv->flags & ALPS_DUALPOINT))
+ return;
+
+ /* Trackpoint packet */
+ x = packet[1] | ((packet[3] & 0x20) << 2);
+ y = packet[2] | ((packet[3] & 0x40) << 1);
+ z = packet[4];
+ left = packet[3] & 0x01;
+ right = packet[3] & 0x02;
+ middle = packet[3] & 0x04;
+
+ /* To prevent the cursor jump when finger lifted */
+ if (x == 0x7F && y == 0x7F && z == 0x7F)
+ x = y = z = 0;
+
+ /* Divide 4 since trackpoint's speed is too fast */
+ input_report_rel(dev2, REL_X, (char)x / 4);
+ input_report_rel(dev2, REL_Y, -((char)y / 4));
+
+ input_report_key(dev2, BTN_LEFT, left);
+ input_report_key(dev2, BTN_RIGHT, right);
+ input_report_key(dev2, BTN_MIDDLE, middle);
+
+ input_sync(dev2);
+ return;
+ }
+
+ /* Touchpad packet */
+ x = packet[1] | ((packet[3] & 0x78) << 4);
+ y = packet[2] | ((packet[4] & 0x78) << 4);
+ z = packet[5];
+ left = packet[3] & 0x01;
+ right = packet[3] & 0x02;
+
+ if (z > 30)
+ input_report_key(dev, BTN_TOUCH, 1);
+ if (z < 25)
+ input_report_key(dev, BTN_TOUCH, 0);
+
+ if (z > 0) {
+ input_report_abs(dev, ABS_X, x);
+ input_report_abs(dev, ABS_Y, y);
+ }
+
+ input_report_abs(dev, ABS_PRESSURE, z);
+ input_report_key(dev, BTN_TOOL_FINGER, z > 0);
+
+ /* v6 touchpad does not have middle button */
+ input_report_key(dev, BTN_LEFT, left);
+ input_report_key(dev, BTN_RIGHT, right);
+
+ input_sync(dev);
+}
+
static void alps_process_packet_v4(struct psmouse *psmouse)
{
struct alps_data *priv = psmouse->private;
@@ -897,7 +987,7 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
}
/* Bytes 2 - pktsize should have 0 in the highest bit */
- if (priv->proto_version != ALPS_PROTO_V5 &&
+ if ((priv->proto_version < ALPS_PROTO_V5) &&
psmouse->pktcnt >= 2 && psmouse->pktcnt <= psmouse->pktsize &&
(psmouse->packet[psmouse->pktcnt - 1] & 0x80)) {
psmouse_dbg(psmouse, "refusing packet[%i] = %x\n",
@@ -1085,6 +1175,80 @@ static int alps_absolute_mode_v1_v2(struct psmouse *psmouse)
return ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETPOLL);
}
+static int alps_monitor_mode_send_word(struct psmouse *psmouse, u16 word)
+{
+ int i, nibble;
+
+ /*
+ * b0-b11 are valid bits, send sequence is inverse.
+ * e.g. when word = 0x0123, nibble send sequence is 3, 2, 1
+ */
+ for (i = 0; i <= 8; i += 4) {
+ nibble = (word >> i) & 0xf;
+ if (alps_command_mode_send_nibble(psmouse, nibble))
+ return -1;
+ }
+
+ return 0;
+}
+
+static int alps_monitor_mode_write_reg(struct psmouse *psmouse,
+ u16 addr, u16 value)
+{
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+
+ /* 0x0A0 is the command to write the word */
+ if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE) ||
+ alps_monitor_mode_send_word(psmouse, 0x0A0) ||
+ alps_monitor_mode_send_word(psmouse, addr) ||
+ alps_monitor_mode_send_word(psmouse, value) ||
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE))
+ return -1;
+
+ return 0;
+}
+
+static int alps_monitor_mode(struct psmouse *psmouse, bool enable)
+{
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+
+ if (enable) {
+ /* EC E9 F5 F5 E7 E6 E7 E9 to enter monitor mode */
+ if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) ||
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_GETINFO) ||
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_GETINFO))
+ return -1;
+ } else {
+ /* EC to exit monitor mode */
+ if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP))
+ return -1;
+ }
+
+ return 0;
+}
+
+static int alps_absolute_mode_v6(struct psmouse *psmouse)
+{
+ u16 reg_val = 0x181;
+ int ret = -1;
+
+ /* enter monitor mode, to write the register */
+ if (alps_monitor_mode(psmouse, true))
+ return -1;
+
+ ret = alps_monitor_mode_write_reg(psmouse, 0x000, reg_val);
+
+ if (alps_monitor_mode(psmouse, false))
+ ret = -1;
+
+ return ret;
+}
+
static int alps_get_status(struct psmouse *psmouse, char *param)
{
/* Get status: 0xF5 0xF5 0xF5 0xE9 */
@@ -1189,6 +1353,32 @@ static int alps_hw_init_v1_v2(struct psmouse *psmouse)
return 0;
}
+static int alps_hw_init_v6(struct psmouse *psmouse)
+{
+ unsigned char param[2] = {0xC8, 0x14};
+
+ /* Enter passthrough mode to let trackpoint enter 6byte raw mode */
+ if (alps_passthrough_mode_v2(psmouse, true))
+ return -1;
+
+ if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
+ ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
+ ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
+ ps2_command(&psmouse->ps2dev, ¶m[0], PSMOUSE_CMD_SETRATE) ||
+ ps2_command(&psmouse->ps2dev, ¶m[1], PSMOUSE_CMD_SETRATE))
+ return -1;
+
+ if (alps_passthrough_mode_v2(psmouse, false))
+ return -1;
+
+ if (alps_absolute_mode_v6(psmouse)) {
+ psmouse_err(psmouse, "Failed to enable absolute mode\n");
+ return -1;
+ }
+
+ return 0;
+}
+
/*
* Enable or disable passthrough mode to the trackstick.
*/
@@ -1553,6 +1743,8 @@ static void alps_set_defaults(struct alps_data *priv)
priv->hw_init = alps_hw_init_v1_v2;
priv->process_packet = alps_process_packet_v1_v2;
priv->set_abs_params = alps_set_abs_params_st;
+ priv->x_max = 1023;
+ priv->y_max = 767;
break;
case ALPS_PROTO_V3:
priv->hw_init = alps_hw_init_v3;
@@ -1584,6 +1776,14 @@ static void alps_set_defaults(struct alps_data *priv)
priv->x_bits = 23;
priv->y_bits = 12;
break;
+ case ALPS_PROTO_V6:
+ priv->hw_init = alps_hw_init_v6;
+ priv->process_packet = alps_process_packet_v6;
+ priv->set_abs_params = alps_set_abs_params_st;
+ priv->nibble_commands = alps_v6_nibble_commands;
+ priv->x_max = 2047;
+ priv->y_max = 1535;
+ break;
}
}
@@ -1705,8 +1905,8 @@ static void alps_disconnect(struct psmouse *psmouse)
static void alps_set_abs_params_st(struct alps_data *priv,
struct input_dev *dev1)
{
- input_set_abs_params(dev1, ABS_X, 0, 1023, 0, 0);
- input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0);
+ input_set_abs_params(dev1, ABS_X, 0, priv->x_max, 0, 0);
+ input_set_abs_params(dev1, ABS_Y, 0, priv->y_max, 0, 0);
}
static void alps_set_abs_params_mt(struct alps_data *priv,
diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
index eee5985..704f0f9 100644
--- a/drivers/input/mouse/alps.h
+++ b/drivers/input/mouse/alps.h
@@ -17,6 +17,7 @@
#define ALPS_PROTO_V3 3
#define ALPS_PROTO_V4 4
#define ALPS_PROTO_V5 5
+#define ALPS_PROTO_V6 6
/**
* struct alps_model_info - touchpad ID table
--
1.8.1.2
^ permalink raw reply related
* Re: [PATCH 1/2] input: touchscreen: fix spelling mistake in TSC/ADC DT binding
From: Mark Rutland @ 2013-11-15 15:55 UTC (permalink / raw)
To: Felipe Balbi
Cc: Sebastian Andrzej Siewior, dmitry.torokhov@gmail.com,
rob.herring@calxeda.com, Pawel Moll, swarren@wwwdotorg.org,
ijc+devicetree@hellion.org.uk, rob@landley.net,
bcousson@baylibre.com, Tony Lindgren, devicetree@vger.kernel.org,
Linux OMAP Mailing List, linux-input@vger.kernel.org
In-Reply-To: <20131114155404.GE15835@saruman.home>
On Thu, Nov 14, 2013 at 03:54:04PM +0000, Felipe Balbi wrote:
> HI,
>
> On Thu, Nov 14, 2013 at 11:19:59AM +0000, Mark Rutland wrote:
> > > On Tue, Oct 22, 2013 at 10:42:00AM +0200, Sebastian Andrzej Siewior wrote:
> > > > On 10/21/2013 10:13 PM, Felipe Balbi wrote:
> > > > > diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c
> > > > > index e1c5300..b61df9d 100644
> > > > > --- a/drivers/input/touchscreen/ti_am335x_tsc.c
> > > > > +++ b/drivers/input/touchscreen/ti_am335x_tsc.c
> > > > > @@ -348,9 +348,16 @@ static int titsc_parse_dt(struct platform_device *pdev,
> > > > > if (err < 0)
> > > > > return err;
> > > > >
> > > > > - err = of_property_read_u32(node, "ti,coordiante-readouts",
> > > > > + /*
> > > > > + * try with new binding first. If it fails, still try with
> > > > > + * bogus, miss-spelled version.
> > > > > + */
> > > > > + err = of_property_read_u32(node, "ti,coordinate-readouts",
> > > > > &ts_dev->coordinate_readouts);
> > > > > if (err < 0)
> > > > > + err = of_property_read_u32(node, "ti,coordiante-readouts",
> > > > > + &ts_dev->coordinate_readouts);
> > > > > + if (err < 0)
> > > > > return err;
> > > >
> > > > Thanks, very good. Do we keep this fallback for ever or just for a year
> > > > or two?
> > >
> > > That's for DT maintainers to decide but considering DT is an ABI, I
> > > guess we need to keep for 30 years or so :-p
> >
> > We keep it as long as we have to. If no-one's relying on the typo by the
> > next merge window, I see no reason we'd have to keep support for the
>
> and how could you know that ? considering it's an ABI, how could you
> ever know that ?
If you know that the only user of a binding is a dts for a particular
product that you're in charge of, then you'd know the set of kernel +
dtb combinations out there, and can judge.
If a bug is found in a driver such that it hasn't worked for a number of
releases, and no-one's complained, the binding is clearly not in use and
thus support for it can be removed.
If maintaining compatibility becomes too hard, and all users are happy
to migrate to a newer dtb, then it's not necessary to maintain
compatiblity for the old binding.
While we can't always remove existing bindings, there are cases where
it's possible and appropriate. However, we should strive for
compatibility for as long a term as possible.
Thanks,
Mark.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox