summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2018-06-13 01:24:36 +0200
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2018-06-13 01:24:36 +0200
commit01f7e67a053f7f5696fbdefe2b066303469b6db5 (patch)
treeaebc19aad8327cd0408de71d0621fea43589ed75
parentInput: silead - add MSSL0002 ACPI HID (diff)
parentInput: do not assign new tracking ID when changing tool type (diff)
downloadlinux-01f7e67a053f7f5696fbdefe2b066303469b6db5.tar.xz
linux-01f7e67a053f7f5696fbdefe2b066303469b6db5.zip
Merge branch 'next' into for-linus
Prepare second round of input updates for 4.18 merge window.
-rw-r--r--Documentation/devicetree/bindings/input/sprd,sc27xx-vibra.txt23
-rw-r--r--drivers/input/input-mt.c12
-rw-r--r--drivers/input/keyboard/goldfish_events.c9
-rw-r--r--drivers/input/misc/Kconfig10
-rw-r--r--drivers/input/misc/Makefile1
-rw-r--r--drivers/input/misc/sc27xx-vibra.c154
-rw-r--r--drivers/input/rmi4/Kconfig1
-rw-r--r--drivers/input/rmi4/rmi_2d_sensor.c34
-rw-r--r--drivers/input/rmi4/rmi_bus.c50
-rw-r--r--drivers/input/rmi4/rmi_bus.h10
-rw-r--r--drivers/input/rmi4/rmi_driver.c52
-rw-r--r--drivers/input/rmi4/rmi_f01.c10
-rw-r--r--drivers/input/rmi4/rmi_f03.c9
-rw-r--r--drivers/input/rmi4/rmi_f11.c42
-rw-r--r--drivers/input/rmi4/rmi_f12.c8
-rw-r--r--drivers/input/rmi4/rmi_f30.c9
-rw-r--r--drivers/input/rmi4/rmi_f34.c5
-rw-r--r--drivers/input/rmi4/rmi_f54.c6
-rw-r--r--include/linux/input/mt.h2
-rw-r--r--include/linux/rmi.h2
20 files changed, 337 insertions, 112 deletions
diff --git a/Documentation/devicetree/bindings/input/sprd,sc27xx-vibra.txt b/Documentation/devicetree/bindings/input/sprd,sc27xx-vibra.txt
new file mode 100644
index 000000000000..f2ec0d4f2dff
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/sprd,sc27xx-vibra.txt
@@ -0,0 +1,23 @@
+Spreadtrum SC27xx PMIC Vibrator
+
+Required properties:
+- compatible: should be "sprd,sc2731-vibrator".
+- reg: address of vibrator control register.
+
+Example :
+
+ sc2731_pmic: pmic@0 {
+ compatible = "sprd,sc2731";
+ reg = <0>;
+ spi-max-frequency = <26000000>;
+ interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ vibrator@eb4 {
+ compatible = "sprd,sc2731-vibrator";
+ reg = <0xeb4>;
+ };
+ };
diff --git a/drivers/input/input-mt.c b/drivers/input/input-mt.c
index a1bbec9cda8d..4a69716e5461 100644
--- a/drivers/input/input-mt.c
+++ b/drivers/input/input-mt.c
@@ -131,8 +131,10 @@ EXPORT_SYMBOL(input_mt_destroy_slots);
* inactive, or if the tool type is changed, a new tracking id is
* assigned to the slot. The tool type is only reported if the
* corresponding absbit field is set.
+ *
+ * Returns true if contact is active.
*/
-void input_mt_report_slot_state(struct input_dev *dev,
+bool input_mt_report_slot_state(struct input_dev *dev,
unsigned int tool_type, bool active)
{
struct input_mt *mt = dev->mt;
@@ -140,22 +142,24 @@ void input_mt_report_slot_state(struct input_dev *dev,
int id;
if (!mt)
- return;
+ return false;
slot = &mt->slots[mt->slot];
slot->frame = mt->frame;
if (!active) {
input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
- return;
+ return false;
}
id = input_mt_get_value(slot, ABS_MT_TRACKING_ID);
- if (id < 0 || input_mt_get_value(slot, ABS_MT_TOOL_TYPE) != tool_type)
+ if (id < 0)
id = input_mt_new_trkid(mt);
input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, id);
input_event(dev, EV_ABS, ABS_MT_TOOL_TYPE, tool_type);
+
+ return true;
}
EXPORT_SYMBOL(input_mt_report_slot_state);
diff --git a/drivers/input/keyboard/goldfish_events.c b/drivers/input/keyboard/goldfish_events.c
index f6e643b589b6..e8dae6195b30 100644
--- a/drivers/input/keyboard/goldfish_events.c
+++ b/drivers/input/keyboard/goldfish_events.c
@@ -45,7 +45,7 @@ struct event_dev {
static irqreturn_t events_interrupt(int irq, void *dev_id)
{
struct event_dev *edev = dev_id;
- unsigned type, code, value;
+ unsigned int type, code, value;
type = __raw_readl(edev->addr + REG_READ);
code = __raw_readl(edev->addr + REG_READ);
@@ -57,7 +57,7 @@ static irqreturn_t events_interrupt(int irq, void *dev_id)
}
static void events_import_bits(struct event_dev *edev,
- unsigned long bits[], unsigned type, size_t count)
+ unsigned long bits[], unsigned int type, size_t count)
{
void __iomem *addr = edev->addr;
int i, j;
@@ -99,6 +99,7 @@ static void events_import_abs_params(struct event_dev *edev)
for (j = 0; j < ARRAY_SIZE(val); j++) {
int offset = (i * ARRAY_SIZE(val) + j) * sizeof(u32);
+
val[j] = __raw_readl(edev->addr + REG_DATA + offset);
}
@@ -112,7 +113,7 @@ static int events_probe(struct platform_device *pdev)
struct input_dev *input_dev;
struct event_dev *edev;
struct resource *res;
- unsigned keymapnamelen;
+ unsigned int keymapnamelen;
void __iomem *addr;
int irq;
int i;
@@ -150,7 +151,7 @@ static int events_probe(struct platform_device *pdev)
for (i = 0; i < keymapnamelen; i++)
edev->name[i] = __raw_readb(edev->addr + REG_DATA + i);
- pr_debug("events_probe() keymap=%s\n", edev->name);
+ pr_debug("%s: keymap=%s\n", __func__, edev->name);
input_dev->name = edev->name;
input_dev->id.bustype = BUS_HOST;
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 572b15fa18c2..c761c0c4f2b8 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -841,4 +841,14 @@ config INPUT_RAVE_SP_PWRBUTTON
To compile this driver as a module, choose M here: the
module will be called rave-sp-pwrbutton.
+config INPUT_SC27XX_VIBRA
+ tristate "Spreadtrum sc27xx vibrator support"
+ depends on MFD_SC27XX_PMIC || COMPILE_TEST
+ select INPUT_FF_MEMLESS
+ help
+ This option enables support for Spreadtrum sc27xx vibrator driver.
+
+ To compile this driver as a module, choose M here. The module will
+ be called sc27xx_vibra.
+
endif
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 72cde28649e2..9d0f9d1ff68f 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -66,6 +66,7 @@ obj-$(CONFIG_INPUT_RETU_PWRBUTTON) += retu-pwrbutton.o
obj-$(CONFIG_INPUT_AXP20X_PEK) += axp20x-pek.o
obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o
obj-$(CONFIG_INPUT_RK805_PWRKEY) += rk805-pwrkey.o
+obj-$(CONFIG_INPUT_SC27XX_VIBRA) += sc27xx-vibra.o
obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o
obj-$(CONFIG_INPUT_SIRFSOC_ONKEY) += sirfsoc-onkey.o
obj-$(CONFIG_INPUT_SOC_BUTTON_ARRAY) += soc_button_array.o
diff --git a/drivers/input/misc/sc27xx-vibra.c b/drivers/input/misc/sc27xx-vibra.c
new file mode 100644
index 000000000000..295251abbdac
--- /dev/null
+++ b/drivers/input/misc/sc27xx-vibra.c
@@ -0,0 +1,154 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Spreadtrum Communications Inc.
+ */
+
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/input.h>
+#include <linux/workqueue.h>
+
+#define CUR_DRV_CAL_SEL GENMASK(13, 12)
+#define SLP_LDOVIBR_PD_EN BIT(9)
+#define LDO_VIBR_PD BIT(8)
+
+struct vibra_info {
+ struct input_dev *input_dev;
+ struct work_struct play_work;
+ struct regmap *regmap;
+ u32 base;
+ u32 strength;
+ bool enabled;
+};
+
+static void sc27xx_vibra_set(struct vibra_info *info, bool on)
+{
+ if (on) {
+ regmap_update_bits(info->regmap, info->base, LDO_VIBR_PD, 0);
+ regmap_update_bits(info->regmap, info->base,
+ SLP_LDOVIBR_PD_EN, 0);
+ info->enabled = true;
+ } else {
+ regmap_update_bits(info->regmap, info->base, LDO_VIBR_PD,
+ LDO_VIBR_PD);
+ regmap_update_bits(info->regmap, info->base,
+ SLP_LDOVIBR_PD_EN, SLP_LDOVIBR_PD_EN);
+ info->enabled = false;
+ }
+}
+
+static int sc27xx_vibra_hw_init(struct vibra_info *info)
+{
+ return regmap_update_bits(info->regmap, info->base, CUR_DRV_CAL_SEL, 0);
+}
+
+static void sc27xx_vibra_play_work(struct work_struct *work)
+{
+ struct vibra_info *info = container_of(work, struct vibra_info,
+ play_work);
+
+ if (info->strength && !info->enabled)
+ sc27xx_vibra_set(info, true);
+ else if (info->strength == 0 && info->enabled)
+ sc27xx_vibra_set(info, false);
+}
+
+static int sc27xx_vibra_play(struct input_dev *input, void *data,
+ struct ff_effect *effect)
+{
+ struct vibra_info *info = input_get_drvdata(input);
+
+ info->strength = effect->u.rumble.weak_magnitude;
+ schedule_work(&info->play_work);
+
+ return 0;
+}
+
+static void sc27xx_vibra_close(struct input_dev *input)
+{
+ struct vibra_info *info = input_get_drvdata(input);
+
+ cancel_work_sync(&info->play_work);
+ if (info->enabled)
+ sc27xx_vibra_set(info, false);
+}
+
+static int sc27xx_vibra_probe(struct platform_device *pdev)
+{
+ struct vibra_info *info;
+ int error;
+
+ info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ info->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+ if (!info->regmap) {
+ dev_err(&pdev->dev, "failed to get vibrator regmap.\n");
+ return -ENODEV;
+ }
+
+ error = device_property_read_u32(&pdev->dev, "reg", &info->base);
+ if (error) {
+ dev_err(&pdev->dev, "failed to get vibrator base address.\n");
+ return error;
+ }
+
+ info->input_dev = devm_input_allocate_device(&pdev->dev);
+ if (!info->input_dev) {
+ dev_err(&pdev->dev, "failed to allocate input device.\n");
+ return -ENOMEM;
+ }
+
+ info->input_dev->name = "sc27xx:vibrator";
+ info->input_dev->id.version = 0;
+ info->input_dev->close = sc27xx_vibra_close;
+
+ input_set_drvdata(info->input_dev, info);
+ input_set_capability(info->input_dev, EV_FF, FF_RUMBLE);
+ INIT_WORK(&info->play_work, sc27xx_vibra_play_work);
+ info->enabled = false;
+
+ error = sc27xx_vibra_hw_init(info);
+ if (error) {
+ dev_err(&pdev->dev, "failed to initialize the vibrator.\n");
+ return error;
+ }
+
+ error = input_ff_create_memless(info->input_dev, NULL,
+ sc27xx_vibra_play);
+ if (error) {
+ dev_err(&pdev->dev, "failed to register vibrator to FF.\n");
+ return error;
+ }
+
+ error = input_register_device(info->input_dev);
+ if (error) {
+ dev_err(&pdev->dev, "failed to register input device.\n");
+ return error;
+ }
+
+ return 0;
+}
+
+static const struct of_device_id sc27xx_vibra_of_match[] = {
+ { .compatible = "sprd,sc2731-vibrator", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, sc27xx_vibra_of_match);
+
+static struct platform_driver sc27xx_vibra_driver = {
+ .driver = {
+ .name = "sc27xx-vibrator",
+ .of_match_table = sc27xx_vibra_of_match,
+ },
+ .probe = sc27xx_vibra_probe,
+};
+
+module_platform_driver(sc27xx_vibra_driver);
+
+MODULE_DESCRIPTION("Spreadtrum SC27xx Vibrator Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Xiaotong Lu <xiaotong.lu@spreadtrum.com>");
diff --git a/drivers/input/rmi4/Kconfig b/drivers/input/rmi4/Kconfig
index 7172b88cd064..fad2eae4a118 100644
--- a/drivers/input/rmi4/Kconfig
+++ b/drivers/input/rmi4/Kconfig
@@ -3,6 +3,7 @@
#
config RMI4_CORE
tristate "Synaptics RMI4 bus support"
+ select IRQ_DOMAIN
help
Say Y here if you want to support the Synaptics RMI4 bus. This is
required for all RMI4 device support.
diff --git a/drivers/input/rmi4/rmi_2d_sensor.c b/drivers/input/rmi4/rmi_2d_sensor.c
index 8bb866c7b985..8eeffa066022 100644
--- a/drivers/input/rmi4/rmi_2d_sensor.c
+++ b/drivers/input/rmi4/rmi_2d_sensor.c
@@ -32,15 +32,15 @@ void rmi_2d_sensor_abs_process(struct rmi_2d_sensor *sensor,
if (obj->type == RMI_2D_OBJECT_NONE)
return;
- if (axis_align->swap_axes)
- swap(obj->x, obj->y);
-
if (axis_align->flip_x)
obj->x = sensor->max_x - obj->x;
if (axis_align->flip_y)
obj->y = sensor->max_y - obj->y;
+ if (axis_align->swap_axes)
+ swap(obj->x, obj->y);
+
/*
* Here checking if X offset or y offset are specified is
* redundant. We just add the offsets or clip the values.
@@ -120,15 +120,15 @@ void rmi_2d_sensor_rel_report(struct rmi_2d_sensor *sensor, int x, int y)
x = min(RMI_2D_REL_POS_MAX, max(RMI_2D_REL_POS_MIN, (int)x));
y = min(RMI_2D_REL_POS_MAX, max(RMI_2D_REL_POS_MIN, (int)y));
- if (axis_align->swap_axes)
- swap(x, y);
-
if (axis_align->flip_x)
x = min(RMI_2D_REL_POS_MAX, -x);
if (axis_align->flip_y)
y = min(RMI_2D_REL_POS_MAX, -y);
+ if (axis_align->swap_axes)
+ swap(x, y);
+
if (x || y) {
input_report_rel(sensor->input, REL_X, x);
input_report_rel(sensor->input, REL_Y, y);
@@ -141,17 +141,10 @@ static void rmi_2d_sensor_set_input_params(struct rmi_2d_sensor *sensor)
struct input_dev *input = sensor->input;
int res_x;
int res_y;
+ int max_x, max_y;
int input_flags = 0;
if (sensor->report_abs) {
- if (sensor->axis_align.swap_axes) {
- swap(sensor->max_x, sensor->max_y);
- swap(sensor->axis_align.clip_x_low,
- sensor->axis_align.clip_y_low);
- swap(sensor->axis_align.clip_x_high,
- sensor->axis_align.clip_y_high);
- }
-
sensor->min_x = sensor->axis_align.clip_x_low;
if (sensor->axis_align.clip_x_high)
sensor->max_x = min(sensor->max_x,
@@ -163,14 +156,19 @@ static void rmi_2d_sensor_set_input_params(struct rmi_2d_sensor *sensor)
sensor->axis_align.clip_y_high);
set_bit(EV_ABS, input->evbit);
- input_set_abs_params(input, ABS_MT_POSITION_X, 0, sensor->max_x,
- 0, 0);
- input_set_abs_params(input, ABS_MT_POSITION_Y, 0, sensor->max_y,
- 0, 0);
+
+ max_x = sensor->max_x;
+ max_y = sensor->max_y;
+ if (sensor->axis_align.swap_axes)
+ swap(max_x, max_y);
+ input_set_abs_params(input, ABS_MT_POSITION_X, 0, max_x, 0, 0);
+ input_set_abs_params(input, ABS_MT_POSITION_Y, 0, max_y, 0, 0);
if (sensor->x_mm && sensor->y_mm) {
res_x = (sensor->max_x - sensor->min_x) / sensor->x_mm;
res_y = (sensor->max_y - sensor->min_y) / sensor->y_mm;
+ if (sensor->axis_align.swap_axes)
+ swap(res_x, res_y);
input_abs_set_res(input, ABS_X, res_x);
input_abs_set_res(input, ABS_Y, res_y);
diff --git a/drivers/input/rmi4/rmi_bus.c b/drivers/input/rmi4/rmi_bus.c
index c5fa53adba8d..bd0d5ff01b08 100644
--- a/drivers/input/rmi4/rmi_bus.c
+++ b/drivers/input/rmi4/rmi_bus.c
@@ -9,6 +9,8 @@
#include <linux/kernel.h>
#include <linux/device.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
#include <linux/list.h>
#include <linux/pm.h>
#include <linux/rmi.h>
@@ -167,6 +169,39 @@ static inline void rmi_function_of_probe(struct rmi_function *fn)
{}
#endif
+static struct irq_chip rmi_irq_chip = {
+ .name = "rmi4",
+};
+
+static int rmi_create_function_irq(struct rmi_function *fn,
+ struct rmi_function_handler *handler)
+{
+ struct rmi_driver_data *drvdata = dev_get_drvdata(&fn->rmi_dev->dev);
+ int i, error;
+
+ for (i = 0; i < fn->num_of_irqs; i++) {
+ set_bit(fn->irq_pos + i, fn->irq_mask);
+
+ fn->irq[i] = irq_create_mapping(drvdata->irqdomain,
+ fn->irq_pos + i);
+
+ irq_set_chip_data(fn->irq[i], fn);
+ irq_set_chip_and_handler(fn->irq[i], &rmi_irq_chip,
+ handle_simple_irq);
+ irq_set_nested_thread(fn->irq[i], 1);
+
+ error = devm_request_threaded_irq(&fn->dev, fn->irq[i], NULL,
+ handler->attention, IRQF_ONESHOT,
+ dev_name(&fn->dev), fn);
+ if (error) {
+ dev_err(&fn->dev, "Error %d registering IRQ\n", error);
+ return error;
+ }
+ }
+
+ return 0;
+}
+
static int rmi_function_probe(struct device *dev)
{
struct rmi_function *fn = to_rmi_function(dev);
@@ -178,7 +213,14 @@ static int rmi_function_probe(struct device *dev)
if (handler->probe) {
error = handler->probe(fn);
- return error;
+ if (error)
+ return error;
+ }
+
+ if (fn->num_of_irqs && handler->attention) {
+ error = rmi_create_function_irq(fn, handler);
+ if (error)
+ return error;
}
return 0;
@@ -230,12 +272,18 @@ err_put_device:
void rmi_unregister_function(struct rmi_function *fn)
{
+ int i;
+
rmi_dbg(RMI_DEBUG_CORE, &fn->dev, "Unregistering F%02X.\n",
fn->fd.function_number);
device_del(&fn->dev);
of_node_put(fn->dev.of_node);
put_device(&fn->dev);
+
+ for (i = 0; i < fn->num_of_irqs; i++)
+ irq_dispose_mapping(fn->irq[i]);
+
}
/**
diff --git a/drivers/input/rmi4/rmi_bus.h b/drivers/input/rmi4/rmi_bus.h
index b7625a9ac66a..96383eab41ba 100644
--- a/drivers/input/rmi4/rmi_bus.h
+++ b/drivers/input/rmi4/rmi_bus.h
@@ -14,6 +14,12 @@
struct rmi_device;
+/*
+ * The interrupt source count in the function descriptor can represent up to
+ * 6 interrupt sources in the normal manner.
+ */
+#define RMI_FN_MAX_IRQS 6
+
/**
* struct rmi_function - represents the implementation of an RMI4
* function for a particular device (basically, a driver for that RMI4 function)
@@ -26,6 +32,7 @@ struct rmi_device;
* @irq_pos: The position in the irq bitfield this function holds
* @irq_mask: For convenience, can be used to mask IRQ bits off during ATTN
* interrupt handling.
+ * @irqs: assigned virq numbers (up to num_of_irqs)
*
* @node: entry in device's list of functions
*/
@@ -36,6 +43,7 @@ struct rmi_function {
struct list_head node;
unsigned int num_of_irqs;
+ int irq[RMI_FN_MAX_IRQS];
unsigned int irq_pos;
unsigned long irq_mask[];
};
@@ -76,7 +84,7 @@ struct rmi_function_handler {
void (*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);
+ irqreturn_t (*attention)(int irq, void *ctx);
int (*suspend)(struct rmi_function *fn);
int (*resume)(struct rmi_function *fn);
};
diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c
index f5954981e9ee..cb6d983e8033 100644
--- a/drivers/input/rmi4/rmi_driver.c
+++ b/drivers/input/rmi4/rmi_driver.c
@@ -21,6 +21,7 @@
#include <linux/pm.h>
#include <linux/slab.h>
#include <linux/of.h>
+#include <linux/irqdomain.h>
#include <uapi/linux/input.h>
#include <linux/rmi.h>
#include "rmi_bus.h"
@@ -127,28 +128,11 @@ static int rmi_driver_process_config_requests(struct rmi_device *rmi_dev)
return 0;
}
-static void process_one_interrupt(struct rmi_driver_data *data,
- struct rmi_function *fn)
-{
- struct rmi_function_handler *fh;
-
- if (!fn || !fn->dev.driver)
- return;
-
- fh = to_rmi_function_handler(fn->dev.driver);
- if (fh->attention) {
- bitmap_and(data->fn_irq_bits, data->irq_status, fn->irq_mask,
- data->irq_count);
- if (!bitmap_empty(data->fn_irq_bits, data->irq_count))
- fh->attention(fn, data->fn_irq_bits);
- }
-}
-
static int rmi_process_interrupt_requests(struct rmi_device *rmi_dev)
{
struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
struct device *dev = &rmi_dev->dev;
- struct rmi_function *entry;
+ int i;
int error;
if (!data)
@@ -173,16 +157,8 @@ static int rmi_process_interrupt_requests(struct rmi_device *rmi_dev)
*/
mutex_unlock(&data->irq_mutex);
- /*
- * It would be nice to be able to use irq_chip to handle these
- * nested IRQs. Unfortunately, most of the current customers for
- * this driver are using older kernels (3.0.x) that don't support
- * the features required for that. Once they've shifted to more
- * recent kernels (say, 3.3 and higher), this should be switched to
- * use irq_chip.
- */
- list_for_each_entry(entry, &data->function_list, node)
- process_one_interrupt(data, entry);
+ for_each_set_bit(i, data->irq_status, data->irq_count)
+ handle_nested_irq(irq_find_mapping(data->irqdomain, i));
if (data->input)
input_sync(data->input);
@@ -1000,9 +976,13 @@ EXPORT_SYMBOL_GPL(rmi_driver_resume);
static int rmi_driver_remove(struct device *dev)
{
struct rmi_device *rmi_dev = to_rmi_device(dev);
+ struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
rmi_disable_irq(rmi_dev, false);
+ irq_domain_remove(data->irqdomain);
+ data->irqdomain = NULL;
+
rmi_f34_remove_sysfs(rmi_dev);
rmi_free_function_list(rmi_dev);
@@ -1034,7 +1014,8 @@ int rmi_probe_interrupts(struct rmi_driver_data *data)
{
struct rmi_device *rmi_dev = data->rmi_dev;
struct device *dev = &rmi_dev->dev;
- int irq_count;
+ struct fwnode_handle *fwnode = rmi_dev->xport->dev->fwnode;
+ int irq_count = 0;
size_t size;
int retval;
@@ -1045,7 +1026,6 @@ int rmi_probe_interrupts(struct rmi_driver_data *data)
* being accessed.
*/
rmi_dbg(RMI_DEBUG_CORE, dev, "%s: Counting IRQs.\n", __func__);
- irq_count = 0;
data->bootloader_mode = false;
retval = rmi_scan_pdt(rmi_dev, &irq_count, rmi_count_irqs);
@@ -1057,6 +1037,15 @@ int rmi_probe_interrupts(struct rmi_driver_data *data)
if (data->bootloader_mode)
dev_warn(dev, "Device in bootloader mode.\n");
+ /* Allocate and register a linear revmap irq_domain */
+ data->irqdomain = irq_domain_create_linear(fwnode, irq_count,
+ &irq_domain_simple_ops,
+ data);
+ if (!data->irqdomain) {
+ dev_err(&rmi_dev->dev, "Failed to create IRQ domain\n");
+ return -ENOMEM;
+ }
+
data->irq_count = irq_count;
data->num_of_irq_regs = (data->irq_count + 7) / 8;
@@ -1079,10 +1068,9 @@ int rmi_init_functions(struct rmi_driver_data *data)
{
struct rmi_device *rmi_dev = data->rmi_dev;
struct device *dev = &rmi_dev->dev;
- int irq_count;
+ int irq_count = 0;
int retval;
- irq_count = 0;
rmi_dbg(RMI_DEBUG_CORE, dev, "%s: Creating functions.\n", __func__);
retval = rmi_scan_pdt(rmi_dev, &irq_count, rmi_create_function);
if (retval < 0) {
diff --git a/drivers/input/rmi4/rmi_f01.c b/drivers/input/rmi4/rmi_f01.c
index 8a07ae147df6..4edaa14fe878 100644
--- a/drivers/input/rmi4/rmi_f01.c
+++ b/drivers/input/rmi4/rmi_f01.c
@@ -681,9 +681,9 @@ static int rmi_f01_resume(struct rmi_function *fn)
return 0;
}
-static int rmi_f01_attention(struct rmi_function *fn,
- unsigned long *irq_bits)
+static irqreturn_t rmi_f01_attention(int irq, void *ctx)
{
+ struct rmi_function *fn = ctx;
struct rmi_device *rmi_dev = fn->rmi_dev;
int error;
u8 device_status;
@@ -692,7 +692,7 @@ static int rmi_f01_attention(struct rmi_function *fn,
if (error) {
dev_err(&fn->dev,
"Failed to read device status: %d.\n", error);
- return error;
+ return IRQ_RETVAL(error);
}
if (RMI_F01_STATUS_BOOTLOADER(device_status))
@@ -704,11 +704,11 @@ static int rmi_f01_attention(struct rmi_function *fn,
error = rmi_dev->driver->reset_handler(rmi_dev);
if (error) {
dev_err(&fn->dev, "Device reset failed: %d\n", error);
- return error;
+ return IRQ_RETVAL(error);
}
}
- return 0;
+ return IRQ_HANDLED;
}
struct rmi_function_handler rmi_f01_handler = {
diff --git a/drivers/input/rmi4/rmi_f03.c b/drivers/input/rmi4/rmi_f03.c
index 88822196d6b7..aaa1edc95522 100644
--- a/drivers/input/rmi4/rmi_f03.c
+++ b/drivers/input/rmi4/rmi_f03.c
@@ -244,8 +244,9 @@ static int rmi_f03_config(struct rmi_function *fn)
return 0;
}
-static int rmi_f03_attention(struct rmi_function *fn, unsigned long *irq_bits)
+static irqreturn_t rmi_f03_attention(int irq, void *ctx)
{
+ struct rmi_function *fn = ctx;
struct rmi_device *rmi_dev = fn->rmi_dev;
struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
struct f03_data *f03 = dev_get_drvdata(&fn->dev);
@@ -262,7 +263,7 @@ static int rmi_f03_attention(struct rmi_function *fn, unsigned long *irq_bits)
/* First grab the data passed by the transport device */
if (drvdata->attn_data.size < ob_len) {
dev_warn(&fn->dev, "F03 interrupted, but data is missing!\n");
- return 0;
+ return IRQ_HANDLED;
}
memcpy(obs, drvdata->attn_data.data, ob_len);
@@ -277,7 +278,7 @@ static int rmi_f03_attention(struct rmi_function *fn, unsigned long *irq_bits)
"%s: Failed to read F03 output buffers: %d\n",
__func__, error);
serio_interrupt(f03->serio, 0, SERIO_TIMEOUT);
- return error;
+ return IRQ_RETVAL(error);
}
}
@@ -303,7 +304,7 @@ static int rmi_f03_attention(struct rmi_function *fn, unsigned long *irq_bits)
serio_interrupt(f03->serio, ob_data, serio_flags);
}
- return 0;
+ return IRQ_HANDLED;
}
static void rmi_f03_remove(struct rmi_function *fn)
diff --git a/drivers/input/rmi4/rmi_f11.c b/drivers/input/rmi4/rmi_f11.c
index bc5e37f30ac1..5f2e1ef5accc 100644
--- a/drivers/input/rmi4/rmi_f11.c
+++ b/drivers/input/rmi4/rmi_f11.c
@@ -570,9 +570,7 @@ static inline u8 rmi_f11_parse_finger_state(const u8 *f_state, u8 n_finger)
}
static void rmi_f11_finger_handler(struct f11_data *f11,
- struct rmi_2d_sensor *sensor,
- unsigned long *irq_bits, int num_irq_regs,
- int size)
+ struct rmi_2d_sensor *sensor, int size)
{
const u8 *f_state = f11->data.f_state;
u8 finger_state;
@@ -581,12 +579,7 @@ static void rmi_f11_finger_handler(struct f11_data *f11,
int rel_fingers;
int abs_size = sensor->nbr_fingers * RMI_F11_ABS_BYTES;
- int abs_bits = bitmap_and(f11->result_bits, irq_bits, f11->abs_mask,
- num_irq_regs * 8);
- int rel_bits = bitmap_and(f11->result_bits, irq_bits, f11->rel_mask,
- num_irq_regs * 8);
-
- if (abs_bits) {
+ if (sensor->report_abs) {
if (abs_size > size)
abs_fingers = size / RMI_F11_ABS_BYTES;
else
@@ -604,19 +597,7 @@ static void rmi_f11_finger_handler(struct f11_data *f11,
rmi_f11_abs_pos_process(f11, sensor, &sensor->objs[i],
finger_state, i);
}
- }
- if (rel_bits) {
- if ((abs_size + sensor->nbr_fingers * RMI_F11_REL_BYTES) > size)
- rel_fingers = (size - abs_size) / RMI_F11_REL_BYTES;
- else
- rel_fingers = sensor->nbr_fingers;
-
- for (i = 0; i < rel_fingers; i++)
- rmi_f11_rel_pos_report(f11, i);
- }
-
- if (abs_bits) {
/*
* the absolute part is made in 2 parts to allow the kernel
* tracking to take place.
@@ -638,7 +619,16 @@ static void rmi_f11_finger_handler(struct f11_data *f11,
}
input_mt_sync_frame(sensor->input);
+ } else if (sensor->report_rel) {
+ if ((abs_size + sensor->nbr_fingers * RMI_F11_REL_BYTES) > size)
+ rel_fingers = (size - abs_size) / RMI_F11_REL_BYTES;
+ else
+ rel_fingers = sensor->nbr_fingers;
+
+ for (i = 0; i < rel_fingers; i++)
+ rmi_f11_rel_pos_report(f11, i);
}
+
}
static int f11_2d_construct_data(struct f11_data *f11)
@@ -1275,8 +1265,9 @@ static int rmi_f11_config(struct rmi_function *fn)
return 0;
}
-static int rmi_f11_attention(struct rmi_function *fn, unsigned long *irq_bits)
+static irqreturn_t rmi_f11_attention(int irq, void *ctx)
{
+ struct rmi_function *fn = ctx;
struct rmi_device *rmi_dev = fn->rmi_dev;
struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
struct f11_data *f11 = dev_get_drvdata(&fn->dev);
@@ -1302,13 +1293,12 @@ static int rmi_f11_attention(struct rmi_function *fn, unsigned long *irq_bits)
data_base_addr, f11->sensor.data_pkt,
f11->sensor.pkt_size);
if (error < 0)
- return error;
+ return IRQ_RETVAL(error);
}
- rmi_f11_finger_handler(f11, &f11->sensor, irq_bits,
- drvdata->num_of_irq_regs, valid_bytes);
+ rmi_f11_finger_handler(f11, &f11->sensor, valid_bytes);
- return 0;
+ return IRQ_HANDLED;
}
static int rmi_f11_resume(struct rmi_function *fn)
diff --git a/drivers/input/rmi4/rmi_f12.c b/drivers/input/rmi4/rmi_f12.c
index 8b0db086d68a..e226def74d82 100644
--- a/drivers/input/rmi4/rmi_f12.c
+++ b/drivers/input/rmi4/rmi_f12.c
@@ -197,10 +197,10 @@ static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1, int size)
rmi_2d_sensor_abs_report(sensor, &sensor->objs[i], i);
}
-static int rmi_f12_attention(struct rmi_function *fn,
- unsigned long *irq_nr_regs)
+static irqreturn_t rmi_f12_attention(int irq, void *ctx)
{
int retval;
+ struct rmi_function *fn = ctx;
struct rmi_device *rmi_dev = fn->rmi_dev;
struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
struct f12_data *f12 = dev_get_drvdata(&fn->dev);
@@ -222,7 +222,7 @@ static int rmi_f12_attention(struct rmi_function *fn,
if (retval < 0) {
dev_err(&fn->dev, "Failed to read object data. Code: %d.\n",
retval);
- return retval;
+ return IRQ_RETVAL(retval);
}
}
@@ -232,7 +232,7 @@ static int rmi_f12_attention(struct rmi_function *fn,
input_mt_sync_frame(sensor->input);
- return 0;
+ return IRQ_HANDLED;
}
static int rmi_f12_write_control_regs(struct rmi_function *fn)
diff --git a/drivers/input/rmi4/rmi_f30.c b/drivers/input/rmi4/rmi_f30.c
index 82e0f0d43d55..5e3ed5ac0c3e 100644
--- a/drivers/input/rmi4/rmi_f30.c
+++ b/drivers/input/rmi4/rmi_f30.c
@@ -122,8 +122,9 @@ static void rmi_f30_report_button(struct rmi_function *fn,
}
}
-static int rmi_f30_attention(struct rmi_function *fn, unsigned long *irq_bits)
+static irqreturn_t rmi_f30_attention(int irq, void *ctx)
{
+ struct rmi_function *fn = ctx;
struct f30_data *f30 = dev_get_drvdata(&fn->dev);
struct rmi_driver_data *drvdata = dev_get_drvdata(&fn->rmi_dev->dev);
int error;
@@ -134,7 +135,7 @@ static int rmi_f30_attention(struct rmi_function *fn, unsigned long *irq_bits)
if (drvdata->attn_data.size < f30->register_count) {
dev_warn(&fn->dev,
"F30 interrupted, but data is missing\n");
- return 0;
+ return IRQ_HANDLED;
}
memcpy(f30->data_regs, drvdata->attn_data.data,
f30->register_count);
@@ -147,7 +148,7 @@ static int rmi_f30_attention(struct rmi_function *fn, unsigned long *irq_bits)
dev_err(&fn->dev,
"%s: Failed to read F30 data registers: %d\n",
__func__, error);
- return error;
+ return IRQ_RETVAL(error);
}
}
@@ -159,7 +160,7 @@ static int rmi_f30_attention(struct rmi_function *fn, unsigned long *irq_bits)
rmi_f03_commit_buttons(f30->f03);
}
- return 0;
+ return IRQ_HANDLED;
}
static int rmi_f30_config(struct rmi_function *fn)
diff --git a/drivers/input/rmi4/rmi_f34.c b/drivers/input/rmi4/rmi_f34.c
index f1f5ac539d5d..87a7d4ba382d 100644
--- a/drivers/input/rmi4/rmi_f34.c
+++ b/drivers/input/rmi4/rmi_f34.c
@@ -100,8 +100,9 @@ static int rmi_f34_command(struct f34_data *f34, u8 command,
return 0;
}
-static int rmi_f34_attention(struct rmi_function *fn, unsigned long *irq_bits)
+static irqreturn_t rmi_f34_attention(int irq, void *ctx)
{
+ struct rmi_function *fn = ctx;
struct f34_data *f34 = dev_get_drvdata(&fn->dev);
int ret;
u8 status;
@@ -126,7 +127,7 @@ static int rmi_f34_attention(struct rmi_function *fn, unsigned long *irq_bits)
complete(&f34->v7.cmd_done);
}
- return 0;
+ return IRQ_HANDLED;
}
static int rmi_f34_write_blocks(struct f34_data *f34, const void *data,
diff --git a/drivers/input/rmi4/rmi_f54.c b/drivers/input/rmi4/rmi_f54.c
index 5343f2c08f15..98a935efec8e 100644
--- a/drivers/input/rmi4/rmi_f54.c
+++ b/drivers/input/rmi4/rmi_f54.c
@@ -610,11 +610,6 @@ error:
mutex_unlock(&f54->data_mutex);
}
-static int rmi_f54_attention(struct rmi_function *fn, unsigned long *irqbits)
-{
- return 0;
-}
-
static int rmi_f54_config(struct rmi_function *fn)
{
struct rmi_driver *drv = fn->rmi_dev->driver;
@@ -756,6 +751,5 @@ struct rmi_function_handler rmi_f54_handler = {
.func = 0x54,
.probe = rmi_f54_probe,
.config = rmi_f54_config,
- .attention = rmi_f54_attention,
.remove = rmi_f54_remove,
};
diff --git a/include/linux/input/mt.h b/include/linux/input/mt.h
index d7188de4db96..3f4bf60b0bb5 100644
--- a/include/linux/input/mt.h
+++ b/include/linux/input/mt.h
@@ -100,7 +100,7 @@ static inline bool input_is_mt_axis(int axis)
return axis == ABS_MT_SLOT || input_is_mt_value(axis);
}
-void input_mt_report_slot_state(struct input_dev *dev,
+bool input_mt_report_slot_state(struct input_dev *dev,
unsigned int tool_type, bool active);
void input_mt_report_finger_count(struct input_dev *dev, int count);
diff --git a/include/linux/rmi.h b/include/linux/rmi.h
index 64125443f8a6..5ef5c7c412a7 100644
--- a/include/linux/rmi.h
+++ b/include/linux/rmi.h
@@ -354,6 +354,8 @@ struct rmi_driver_data {
struct mutex irq_mutex;
struct input_dev *input;
+ struct irq_domain *irqdomain;
+
u8 pdt_props;
u8 num_rx_electrodes;