summaryrefslogtreecommitdiffstats
path: root/drivers/input
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2013-02-19 22:05:39 -0800
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2013-02-19 22:05:39 -0800
commit2d9f0d964be94fd51c7303288c6f9c88bf2381fe (patch)
tree2631c3e82abc145a6e9c8e2c18687833c71de012 /drivers/input
parent9937c026820baabd1e908a9c1e6bdc846293000a (diff)
parent005a69d632cd8694061c2dd27492fe874780b5ee (diff)
Merge branch 'next' into for-linus
Prepare first set of updates for 3.9 merge window.
Diffstat (limited to 'drivers/input')
-rw-r--r--drivers/input/Kconfig2
-rw-r--r--drivers/input/input-mt.c1
-rw-r--r--drivers/input/joystick/walkera0701.c82
-rw-r--r--drivers/input/keyboard/Kconfig16
-rw-r--r--drivers/input/keyboard/Makefile1
-rw-r--r--drivers/input/keyboard/atkbd.c74
-rw-r--r--drivers/input/keyboard/goldfish_events.c194
-rw-r--r--drivers/input/keyboard/imx_keypad.c43
-rw-r--r--drivers/input/keyboard/qt2160.c141
-rw-r--r--drivers/input/keyboard/tegra-kbc.c478
-rw-r--r--drivers/input/misc/adxl34x.c7
-rw-r--r--drivers/input/misc/bma150.c14
-rw-r--r--drivers/input/misc/twl4030-vibra.c45
-rw-r--r--drivers/input/misc/twl6040-vibra.c100
-rw-r--r--drivers/input/misc/wm831x-on.c4
-rw-r--r--drivers/input/mouse/Kconfig22
-rw-r--r--drivers/input/mouse/Makefile2
-rw-r--r--drivers/input/mouse/alps.c773
-rw-r--r--drivers/input/mouse/alps.h145
-rw-r--r--drivers/input/mouse/cyapa.c973
-rw-r--r--drivers/input/mouse/cypress_ps2.c725
-rw-r--r--drivers/input/mouse/cypress_ps2.h191
-rw-r--r--drivers/input/mouse/psmouse-base.c32
-rw-r--r--drivers/input/mouse/psmouse.h1
-rw-r--r--drivers/input/mouse/synaptics.c32
-rw-r--r--drivers/input/serio/Kconfig1
-rw-r--r--drivers/input/tablet/wacom_wac.c192
-rw-r--r--drivers/input/tablet/wacom_wac.h2
-rw-r--r--drivers/input/touchscreen/Kconfig2
-rw-r--r--drivers/input/touchscreen/cyttsp_spi.c1
-rw-r--r--drivers/input/touchscreen/mms114.c54
-rw-r--r--drivers/input/touchscreen/stmpe-ts.c2
-rw-r--r--drivers/input/touchscreen/tsc2005.c1
-rw-r--r--drivers/input/touchscreen/wm831x-ts.c4
34 files changed, 3314 insertions, 1043 deletions
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index 55f7e57d4e42..38b523a1ece0 100644
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -3,7 +3,7 @@
#
menu "Input device support"
- depends on !S390 && !UML
+ depends on !UML
config INPUT
tristate "Generic input layer (needed for keyboard, mouse, ...)" if EXPERT
diff --git a/drivers/input/input-mt.c b/drivers/input/input-mt.c
index c2f436ce7f5b..53eaf89f2db5 100644
--- a/drivers/input/input-mt.c
+++ b/drivers/input/input-mt.c
@@ -18,6 +18,7 @@ static void copy_abs(struct input_dev *dev, unsigned int dst, unsigned int src)
{
if (dev->absinfo && test_bit(src, dev->absbit)) {
dev->absinfo[dst] = dev->absinfo[src];
+ dev->absinfo[dst].fuzz = 0;
dev->absbit[BIT_WORD(dst)] |= BIT_MASK(dst);
}
}
diff --git a/drivers/input/joystick/walkera0701.c b/drivers/input/joystick/walkera0701.c
index f8f892b076e8..b76ac580703c 100644
--- a/drivers/input/joystick/walkera0701.c
+++ b/drivers/input/joystick/walkera0701.c
@@ -12,7 +12,7 @@
* the Free Software Foundation.
*/
-/* #define WK0701_DEBUG */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#define RESERVE 20000
#define SYNC_PULSE 1306000
@@ -67,6 +67,7 @@ static inline void walkera0701_parse_frame(struct walkera_dev *w)
{
int i;
int val1, val2, val3, val4, val5, val6, val7, val8;
+ int magic, magic_bit;
int crc1, crc2;
for (crc1 = crc2 = i = 0; i < 10; i++) {
@@ -102,17 +103,12 @@ static inline void walkera0701_parse_frame(struct walkera_dev *w)
val8 = (w->buf[18] & 1) << 8 | (w->buf[19] << 4) | w->buf[20];
val8 *= (w->buf[18] & 2) - 1; /*sign */
-#ifdef WK0701_DEBUG
- {
- int magic, magic_bit;
- magic = (w->buf[21] << 4) | w->buf[22];
- magic_bit = (w->buf[24] & 8) >> 3;
- printk(KERN_DEBUG
- "walkera0701: %4d %4d %4d %4d %4d %4d %4d %4d (magic %2x %d)\n",
- val1, val2, val3, val4, val5, val6, val7, val8, magic,
- magic_bit);
- }
-#endif
+ magic = (w->buf[21] << 4) | w->buf[22];
+ magic_bit = (w->buf[24] & 8) >> 3;
+ pr_debug("%4d %4d %4d %4d %4d %4d %4d %4d (magic %2x %d)\n",
+ val1, val2, val3, val4, val5, val6, val7, val8,
+ magic, magic_bit);
+
input_report_abs(w->input_dev, ABS_X, val2);
input_report_abs(w->input_dev, ABS_Y, val1);
input_report_abs(w->input_dev, ABS_Z, val6);
@@ -187,6 +183,9 @@ static int walkera0701_open(struct input_dev *dev)
{
struct walkera_dev *w = input_get_drvdata(dev);
+ if (parport_claim(w->pardevice))
+ return -EBUSY;
+
parport_enable_irq(w->parport);
return 0;
}
@@ -197,40 +196,51 @@ static void walkera0701_close(struct input_dev *dev)
parport_disable_irq(w->parport);
hrtimer_cancel(&w->timer);
+
+ parport_release(w->pardevice);
}
static int walkera0701_connect(struct walkera_dev *w, int parport)
{
- int err = -ENODEV;
+ int error;
w->parport = parport_find_number(parport);
- if (w->parport == NULL)
+ if (!w->parport) {
+ pr_err("parport %d does not exist\n", parport);
return -ENODEV;
+ }
if (w->parport->irq == -1) {
- printk(KERN_ERR "walkera0701: parport without interrupt\n");
- goto init_err;
+ pr_err("parport %d does not have interrupt assigned\n",
+ parport);
+ error = -EINVAL;
+ goto err_put_parport;
}
- err = -EBUSY;
w->pardevice = parport_register_device(w->parport, "walkera0701",
NULL, NULL, walkera0701_irq_handler,
PARPORT_DEV_EXCL, w);
- if (!w->pardevice)
- goto init_err;
-
- if (parport_negotiate(w->pardevice->port, IEEE1284_MODE_COMPAT))
- goto init_err1;
+ if (!w->pardevice) {
+ pr_err("failed to register parport device\n");
+ error = -EIO;
+ goto err_put_parport;
+ }
- if (parport_claim(w->pardevice))
- goto init_err1;
+ if (parport_negotiate(w->pardevice->port, IEEE1284_MODE_COMPAT)) {
+ pr_err("failed to negotiate parport mode\n");
+ error = -EIO;
+ goto err_unregister_device;
+ }
hrtimer_init(&w->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
w->timer.function = timer_handler;
w->input_dev = input_allocate_device();
- if (!w->input_dev)
- goto init_err2;
+ if (!w->input_dev) {
+ pr_err("failed to allocate input device\n");
+ error = -ENOMEM;
+ goto err_unregister_device;
+ }
input_set_drvdata(w->input_dev, w);
w->input_dev->name = "Walkera WK-0701 TX";
@@ -241,6 +251,7 @@ static int walkera0701_connect(struct walkera_dev *w, int parport)
w->input_dev->id.vendor = 0x0001;
w->input_dev->id.product = 0x0001;
w->input_dev->id.version = 0x0100;
+ w->input_dev->dev.parent = w->parport->dev;
w->input_dev->open = walkera0701_open;
w->input_dev->close = walkera0701_close;
@@ -254,27 +265,26 @@ static int walkera0701_connect(struct walkera_dev *w, int parport)
input_set_abs_params(w->input_dev, ABS_RUDDER, -512, 512, 0, 0);
input_set_abs_params(w->input_dev, ABS_MISC, -512, 512, 0, 0);
- err = input_register_device(w->input_dev);
- if (err)
- goto init_err3;
+ error = input_register_device(w->input_dev);
+ if (error) {
+ pr_err("failed to register input device\n");
+ goto err_free_input_dev;
+ }
return 0;
- init_err3:
+err_free_input_dev:
input_free_device(w->input_dev);
- init_err2:
- parport_release(w->pardevice);
- init_err1:
+err_unregister_device:
parport_unregister_device(w->pardevice);
- init_err:
+err_put_parport:
parport_put_port(w->parport);
- return err;
+ return error;
}
static void walkera0701_disconnect(struct walkera_dev *w)
{
input_unregister_device(w->input_dev);
- parport_release(w->pardevice);
parport_unregister_device(w->pardevice);
parport_put_port(w->parport);
}
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index 48309641b1b2..992137cf3a64 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -224,7 +224,7 @@ config KEYBOARD_TCA6416
config KEYBOARD_TCA8418
tristate "TCA8418 Keypad Support"
- depends on I2C
+ depends on I2C && GENERIC_HARDIRQS
select INPUT_MATRIXKMAP
help
This driver implements basic keypad functionality
@@ -303,7 +303,7 @@ config KEYBOARD_HP7XX
config KEYBOARD_LM8323
tristate "LM8323 keypad chip"
- depends on I2C
+ depends on I2C && GENERIC_HARDIRQS
depends on LEDS_CLASS
help
If you say yes here you get support for the National Semiconductor
@@ -420,7 +420,7 @@ config KEYBOARD_NOMADIK
config KEYBOARD_TEGRA
tristate "NVIDIA Tegra internal matrix keyboard controller support"
- depends on ARCH_TEGRA
+ depends on ARCH_TEGRA && OF
select INPUT_MATRIXKMAP
help
Say Y here if you want to use a matrix keyboard connected directly
@@ -479,6 +479,16 @@ config KEYBOARD_SAMSUNG
To compile this driver as a module, choose M here: the
module will be called samsung-keypad.
+config KEYBOARD_GOLDFISH_EVENTS
+ depends on GOLDFISH
+ tristate "Generic Input Event device for Goldfish"
+ help
+ Say Y here to get an input event device for the Goldfish virtual
+ device emulator.
+
+ To compile this driver as a module, choose M here: the
+ module will be called goldfish-events.
+
config KEYBOARD_STOWAWAY
tristate "Stowaway keyboard"
select SERIO
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 44e76002f54b..49b16453d00e 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o
obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o
obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o
obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o
+obj-$(CONFIG_KEYBOARD_GOLDFISH_EVENTS) += goldfish_events.o
obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o
obj-$(CONFIG_KEYBOARD_GPIO_POLLED) += gpio_keys_polled.o
obj-$(CONFIG_KEYBOARD_TCA6416) += tca6416-keypad.o
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index add5ffd9fe26..2626773ff29b 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -676,6 +676,39 @@ static inline void atkbd_disable(struct atkbd *atkbd)
serio_continue_rx(atkbd->ps2dev.serio);
}
+static int atkbd_activate(struct atkbd *atkbd)
+{
+ struct ps2dev *ps2dev = &atkbd->ps2dev;
+
+/*
+ * Enable the keyboard to receive keystrokes.
+ */
+
+ if (ps2_command(ps2dev, NULL, ATKBD_CMD_ENABLE)) {
+ dev_err(&ps2dev->serio->dev,
+ "Failed to enable keyboard on %s\n",
+ ps2dev->serio->phys);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * atkbd_deactivate() resets and disables the keyboard from sending
+ * keystrokes.
+ */
+
+static void atkbd_deactivate(struct atkbd *atkbd)
+{
+ struct ps2dev *ps2dev = &atkbd->ps2dev;
+
+ if (ps2_command(ps2dev, NULL, ATKBD_CMD_RESET_DIS))
+ dev_err(&ps2dev->serio->dev,
+ "Failed to deactivate keyboard on %s\n",
+ ps2dev->serio->phys);
+}
+
/*
* atkbd_probe() probes for an AT keyboard on a serio port.
*/
@@ -726,11 +759,17 @@ static int atkbd_probe(struct atkbd *atkbd)
if (atkbd->id == 0xaca1 && atkbd->translated) {
dev_err(&ps2dev->serio->dev,
- "NCD terminal keyboards are only supported on non-translating controlelrs. "
+ "NCD terminal keyboards are only supported on non-translating controllers. "
"Use i8042.direct=1 to disable translation.\n");
return -1;
}
+/*
+ * Make sure nothing is coming from the keyboard and disturbs our
+ * internal state.
+ */
+ atkbd_deactivate(atkbd);
+
return 0;
}
@@ -825,24 +864,6 @@ static int atkbd_reset_state(struct atkbd *atkbd)
return 0;
}
-static int atkbd_activate(struct atkbd *atkbd)
-{
- struct ps2dev *ps2dev = &atkbd->ps2dev;
-
-/*
- * Enable the keyboard to receive keystrokes.
- */
-
- if (ps2_command(ps2dev, NULL, ATKBD_CMD_ENABLE)) {
- dev_err(&ps2dev->serio->dev,
- "Failed to enable keyboard on %s\n",
- ps2dev->serio->phys);
- return -1;
- }
-
- return 0;
-}
-
/*
* atkbd_cleanup() restores the keyboard state so that BIOS is happy after a
* reboot.
@@ -1150,7 +1171,6 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv)
atkbd->set = atkbd_select_set(atkbd, atkbd_set, atkbd_extra);
atkbd_reset_state(atkbd);
- atkbd_activate(atkbd);
} else {
atkbd->set = 2;
@@ -1165,6 +1185,8 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv)
goto fail3;
atkbd_enable(atkbd);
+ if (serio->write)
+ atkbd_activate(atkbd);
err = input_register_device(atkbd->dev);
if (err)
@@ -1208,8 +1230,6 @@ static int atkbd_reconnect(struct serio *serio)
if (atkbd->set != atkbd_select_set(atkbd, atkbd->set, atkbd->extra))
goto out;
- atkbd_activate(atkbd);
-
/*
* Restore LED state and repeat rate. While input core
* will do this for us at resume time reconnect may happen
@@ -1223,7 +1243,17 @@ static int atkbd_reconnect(struct serio *serio)
}
+ /*
+ * Reset our state machine in case reconnect happened in the middle
+ * of multi-byte scancode.
+ */
+ atkbd->xl_bit = 0;
+ atkbd->emul = 0;
+
atkbd_enable(atkbd);
+ if (atkbd->write)
+ atkbd_activate(atkbd);
+
retval = 0;
out:
diff --git a/drivers/input/keyboard/goldfish_events.c b/drivers/input/keyboard/goldfish_events.c
new file mode 100644
index 000000000000..9f60a2ec88db
--- /dev/null
+++ b/drivers/input/keyboard/goldfish_events.c
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (C) 2012 Intel, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/types.h>
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+
+enum {
+ REG_READ = 0x00,
+ REG_SET_PAGE = 0x00,
+ REG_LEN = 0x04,
+ REG_DATA = 0x08,
+
+ PAGE_NAME = 0x00000,
+ PAGE_EVBITS = 0x10000,
+ PAGE_ABSDATA = 0x20000 | EV_ABS,
+};
+
+struct event_dev {
+ struct input_dev *input;
+ int irq;
+ void __iomem *addr;
+ char name[0];
+};
+
+static irqreturn_t events_interrupt(int irq, void *dev_id)
+{
+ struct event_dev *edev = dev_id;
+ unsigned type, code, value;
+
+ type = __raw_readl(edev->addr + REG_READ);
+ code = __raw_readl(edev->addr + REG_READ);
+ value = __raw_readl(edev->addr + REG_READ);
+
+ input_event(edev->input, type, code, value);
+ input_sync(edev->input);
+ return IRQ_HANDLED;
+}
+
+static void events_import_bits(struct event_dev *edev,
+ unsigned long bits[], unsigned type, size_t count)
+{
+ void __iomem *addr = edev->addr;
+ int i, j;
+ size_t size;
+ uint8_t val;
+
+ __raw_writel(PAGE_EVBITS | type, addr + REG_SET_PAGE);
+
+ size = __raw_readl(addr + REG_LEN) * 8;
+ if (size < count)
+ count = size;
+
+ addr += REG_DATA;
+ for (i = 0; i < count; i += 8) {
+ val = __raw_readb(addr++);
+ for (j = 0; j < 8; j++)
+ if (val & 1 << j)
+ set_bit(i + j, bits);
+ }
+}
+
+static void events_import_abs_params(struct event_dev *edev)
+{
+ struct input_dev *input_dev = edev->input;
+ void __iomem *addr = edev->addr;
+ u32 val[4];
+ int count;
+ int i, j;
+
+ __raw_writel(PAGE_ABSDATA, addr + REG_SET_PAGE);
+
+ count = __raw_readl(addr + REG_LEN) / sizeof(val);
+ if (count > ABS_MAX)
+ count = ABS_MAX;
+
+ for (i = 0; i < count; i++) {
+ if (!test_bit(i, input_dev->absbit))
+ continue;
+
+ 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);
+ }
+
+ input_set_abs_params(input_dev, i,
+ val[0], val[1], val[2], val[3]);
+ }
+}
+
+static int events_probe(struct platform_device *pdev)
+{
+ struct input_dev *input_dev;
+ struct event_dev *edev;
+ struct resource *res;
+ unsigned keymapnamelen;
+ void __iomem *addr;
+ int irq;
+ int i;
+ int error;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return -EINVAL;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -EINVAL;
+
+ addr = devm_ioremap(&pdev->dev, res->start, 4096);
+ if (!addr)
+ return -ENOMEM;
+
+ __raw_writel(PAGE_NAME, addr + REG_SET_PAGE);
+ keymapnamelen = __raw_readl(addr + REG_LEN);
+
+ edev = devm_kzalloc(&pdev->dev,
+ sizeof(struct event_dev) + keymapnamelen + 1,
+ GFP_KERNEL);
+ if (!edev)
+ return -ENOMEM;
+
+ input_dev = devm_input_allocate_device(&pdev->dev);
+ if (!input_dev)
+ return -ENOMEM;
+
+ edev->input = input_dev;
+ edev->addr = addr;
+ edev->irq = irq;
+
+ 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);
+
+ input_dev->name = edev->name;
+ input_dev->id.bustype = BUS_HOST;
+
+ events_import_bits(edev, input_dev->evbit, EV_SYN, EV_MAX);
+ events_import_bits(edev, input_dev->keybit, EV_KEY, KEY_MAX);
+ events_import_bits(edev, input_dev->relbit, EV_REL, REL_MAX);
+ events_import_bits(edev, input_dev->absbit, EV_ABS, ABS_MAX);
+ events_import_bits(edev, input_dev->mscbit, EV_MSC, MSC_MAX);
+ events_import_bits(edev, input_dev->ledbit, EV_LED, LED_MAX);
+ events_import_bits(edev, input_dev->sndbit, EV_SND, SND_MAX);
+ events_import_bits(edev, input_dev->ffbit, EV_FF, FF_MAX);
+ events_import_bits(edev, input_dev->swbit, EV_SW, SW_MAX);
+
+ events_import_abs_params(edev);
+
+ error = devm_request_irq(&pdev->dev, edev->irq, events_interrupt, 0,
+ "goldfish-events-keypad", edev);
+ if (error)
+ return error;
+
+ error = input_register_device(input_dev);
+ if (error)
+ return error;
+
+ return 0;
+}
+
+static struct platform_driver events_driver = {
+ .probe = events_probe,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "goldfish_events",
+ },
+};
+
+module_platform_driver(events_driver);
+
+MODULE_AUTHOR("Brian Swetland");
+MODULE_DESCRIPTION("Goldfish Event Device");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c
index 6d150e3e1f55..98f9113251d2 100644
--- a/drivers/input/keyboard/imx_keypad.c
+++ b/drivers/input/keyboard/imx_keypad.c
@@ -20,6 +20,7 @@
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/timer.h>
@@ -414,15 +415,23 @@ open_err:
return -EIO;
}
+#ifdef CONFIG_OF
+static struct of_device_id imx_keypad_of_match[] = {
+ { .compatible = "fsl,imx21-kpp", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_keypad_of_match);
+#endif
+
static int imx_keypad_probe(struct platform_device *pdev)
{
const struct matrix_keymap_data *keymap_data = pdev->dev.platform_data;
struct imx_keypad *keypad;
struct input_dev *input_dev;
struct resource *res;
- int irq, error, i;
+ int irq, error, i, row, col;
- if (keymap_data == NULL) {
+ if (!keymap_data && !pdev->dev.of_node) {
dev_err(&pdev->dev, "no keymap defined\n");
return -EINVAL;
}
@@ -480,22 +489,6 @@ static int imx_keypad_probe(struct platform_device *pdev)
goto failed_unmap;
}
- /* Search for rows and cols enabled */
- for (i = 0; i < keymap_data->keymap_size; i++) {
- keypad->rows_en_mask |= 1 << KEY_ROW(keymap_data->keymap[i]);
- keypad->cols_en_mask |= 1 << KEY_COL(keymap_data->keymap[i]);
- }
-
- if (keypad->rows_en_mask > ((1 << MAX_MATRIX_KEY_ROWS) - 1) ||
- keypad->cols_en_mask > ((1 << MAX_MATRIX_KEY_COLS) - 1)) {
- dev_err(&pdev->dev,
- "invalid key data (too many rows or colums)\n");
- error = -EINVAL;
- goto failed_clock_put;
- }
- dev_dbg(&pdev->dev, "enabled rows mask: %x\n", keypad->rows_en_mask);
- dev_dbg(&pdev->dev, "enabled cols mask: %x\n", keypad->cols_en_mask);
-
/* Init the Input device */
input_dev->name = pdev->name;
input_dev->id.bustype = BUS_HOST;
@@ -512,6 +505,19 @@ static int imx_keypad_probe(struct platform_device *pdev)
goto failed_clock_put;
}
+ /* Search for rows and cols enabled */
+ for (row = 0; row < MAX_MATRIX_KEY_ROWS; row++) {
+ for (col = 0; col < MAX_MATRIX_KEY_COLS; col++) {
+ i = MATRIX_SCAN_CODE(row, col, MATRIX_ROW_SHIFT);
+ if (keypad->keycodes[i] != KEY_RESERVED) {
+ keypad->rows_en_mask |= 1 << row;
+ keypad->cols_en_mask |= 1 << col;
+ }
+ }
+ }
+ dev_dbg(&pdev->dev, "enabled rows mask: %x\n", keypad->rows_en_mask);
+ dev_dbg(&pdev->dev, "enabled cols mask: %x\n", keypad->cols_en_mask);
+
__set_bit(EV_REP, input_dev->evbit);
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
input_set_drvdata(input_dev, keypad);
@@ -631,6 +637,7 @@ static struct platform_driver imx_keypad_driver = {
.name = "imx-keypad",
.owner = THIS_MODULE,
.pm = &imx_kbd_pm_ops,
+ .of_match_table = of_match_ptr(imx_keypad_of_match),
},
.probe = imx_keypad_probe,
.remove = imx_keypad_remove,
diff --git a/drivers/input/keyboard/qt2160.c b/drivers/input/keyboard/qt2160.c
index 3dc2b0f27b0c..1c0ddad0a1cc 100644
--- a/drivers/input/keyboard/qt2160.c
+++ b/drivers/input/keyboard/qt2160.c
@@ -20,6 +20,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/leds.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
@@ -39,6 +40,11 @@
#define QT2160_CMD_GPIOS 6
#define QT2160_CMD_SUBVER 7
#define QT2160_CMD_CALIBRATE 10
+#define QT2160_CMD_DRIVE_X 70
+#define QT2160_CMD_PWMEN_X 74
+#define QT2160_CMD_PWM_DUTY 76
+
+#define QT2160_NUM_LEDS_X 8
#define QT2160_CYCLE_INTERVAL (2*HZ)
@@ -49,6 +55,17 @@ static unsigned char qt2160_key2code[] = {
KEY_C, KEY_D, KEY_E, KEY_F,
};
+#ifdef CONFIG_LEDS_CLASS
+struct qt2160_led {
+ struct qt2160_data *qt2160;
+ struct led_classdev cdev;
+ struct work_struct work;
+ char name[32];
+ int id;
+ enum led_brightness new_brightness;
+};
+#endif
+
struct qt2160_data {
struct i2c_client *client;
struct input_dev *input;
@@ -56,8 +73,61 @@ struct qt2160_data {
spinlock_t lock; /* Protects canceling/rescheduling of dwork */
unsigned short keycodes[ARRAY_SIZE(qt2160_key2code)];
u16 key_matrix;
+#ifdef CONFIG_LEDS_CLASS
+ struct qt2160_led leds[QT2160_NUM_LEDS_X];
+ struct mutex led_lock;
+#endif
};
+static int qt2160_read(struct i2c_client *client, u8 reg);
+static int qt2160_write(struct i2c_client *client, u8 reg, u8 data);
+
+#ifdef CONFIG_LEDS_CLASS
+
+static void qt2160_led_work(struct work_struct *work)
+{
+ struct qt2160_led *led = container_of(work, struct qt2160_led, work);
+ struct qt2160_data *qt2160 = led->qt2160;
+ struct i2c_client *client = qt2160->client;
+ int value = led->new_brightness;
+ u32 drive, pwmen;
+
+ mutex_lock(&qt2160->led_lock);
+
+ drive = qt2160_read(client, QT2160_CMD_DRIVE_X);
+ pwmen = qt2160_read(client, QT2160_CMD_PWMEN_X);
+ if (value != LED_OFF) {
+ drive |= (1 << led->id);
+ pwmen |= (1 << led->id);
+
+ } else {
+ drive &= ~(1 << led->id);
+ pwmen &= ~(1 << led->id);
+ }
+ qt2160_write(client, QT2160_CMD_DRIVE_X, drive);
+ qt2160_write(client, QT2160_CMD_PWMEN_X, pwmen);
+
+ /*
+ * Changing this register will change the brightness
+ * of every LED in the qt2160. It's a HW limitation.
+ */
+ if (value != LED_OFF)
+ qt2160_write(client, QT2160_CMD_PWM_DUTY, value);
+
+ mutex_unlock(&qt2160->led_lock);
+}
+
+static void qt2160_led_set(struct led_classdev *cdev,
+ enum led_brightness value)
+{
+ struct qt2160_led *led = container_of(cdev, struct qt2160_led, cdev);
+
+ led->new_brightness = value;
+ schedule_work(&led->work);
+}
+
+#endif /* CONFIG_LEDS_CLASS */
+
static int qt2160_read_block(struct i2c_client *client,
u8 inireg, u8 *buffer, unsigned int count)
{
@@ -216,6 +286,63 @@ static int qt2160_write(struct i2c_client *client, u8 reg, u8 data)
return ret;
}
+#ifdef CONFIG_LEDS_CLASS
+
+static int qt2160_register_leds(struct qt2160_data *qt2160)
+{
+ struct i2c_client *client = qt2160->client;
+ int ret;
+ int i;
+
+ mutex_init(&qt2160->led_lock);
+
+ for (i = 0; i < QT2160_NUM_LEDS_X; i++) {
+ struct qt2160_led *led = &qt2160->leds[i];
+
+ snprintf(led->name, sizeof(led->name), "qt2160:x%d", i);
+ led->cdev.name = led->name;
+ led->cdev.brightness_set = qt2160_led_set;
+ led->cdev.brightness = LED_OFF;
+ led->id = i;
+ led->qt2160 = qt2160;
+
+ INIT_WORK(&led->work, qt2160_led_work);
+
+ ret = led_classdev_register(&client->dev, &led->cdev);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* Tur off LEDs */
+ qt2160_write(client, QT2160_CMD_DRIVE_X, 0);
+ qt2160_write(client, QT2160_CMD_PWMEN_X, 0);
+ qt2160_write(client, QT2160_CMD_PWM_DUTY, 0);
+
+ return 0;
+}
+
+static void qt2160_unregister_leds(struct qt2160_data *qt2160)
+{
+ int i;
+
+ for (i = 0; i < QT2160_NUM_LEDS_X; i++) {
+ led_classdev_unregister(&qt2160->leds[i].cdev);
+ cancel_work_sync(&qt2160->leds[i].work);
+ }
+}
+
+#else
+
+static inline int qt2160_register_leds(struct qt2160_data *qt2160)
+{
+ return 0;
+}
+
+static inline void qt2160_unregister_leds(struct qt2160_data *qt2160)
+{
+}
+
+#endif
static bool qt2160_identify(struct i2c_client *client)
{
@@ -249,7 +376,7 @@ static bool qt2160_identify(struct i2c_client *client)
}
static int qt2160_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+ const struct i2c_device_id *id)
{
struct qt2160_data *qt2160;
struct input_dev *input;
@@ -314,11 +441,17 @@ static int qt2160_probe(struct i2c_client *client,
}
}
+ error = qt2160_register_leds(qt2160);
+ if (error) {
+ dev_err(&client->dev, "Failed to register leds\n");
+ goto err_free_irq;