Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0dd52d0d authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input:
  Input: add driver for Atmel AT42QT2160 Sensor Chip
  Input: max7359 - use threaded IRQs
  Input: add driver for Maxim MAX7359 key switch controller
  Input: add driver for ADP5588 QWERTY I2C Keypad
  Input: add touchscreen driver for MELFAS MCS-5000 controller
  Input: add driver for OpenCores Keyboard Controller
  Input: dm355evm_keys - remove dm355evm_keys_hardirq
  Input: synaptics_i2c - switch to using __cancel_delayed_work()
  Input: ad7879 - add support for AD7889
  Input: atkbd - rely on input core to restore state on resume
  Input: add generic suspend and resume for input devices
  Input: libps2 - additional locking for i8042 ports
parents c37efa93 fde11323
Loading
Loading
Loading
Loading
+63 −1
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@
 */

#include <linux/init.h>
#include <linux/types.h>
#include <linux/input.h>
#include <linux/module.h>
#include <linux/random.h>
@@ -514,7 +515,7 @@ static void input_disconnect_device(struct input_dev *dev)
	 * that there are no threads in the middle of input_open_device()
	 */
	mutex_lock(&dev->mutex);
	dev->going_away = 1;
	dev->going_away = true;
	mutex_unlock(&dev->mutex);

	spin_lock_irq(&dev->event_lock);
@@ -1259,10 +1260,71 @@ static int input_dev_uevent(struct device *device, struct kobj_uevent_env *env)
	return 0;
}

#define INPUT_DO_TOGGLE(dev, type, bits, on)			\
	do {							\
		int i;						\
		if (!test_bit(EV_##type, dev->evbit))		\
			break;					\
		for (i = 0; i < type##_MAX; i++) {		\
			if (!test_bit(i, dev->bits##bit) ||	\
			    !test_bit(i, dev->bits))		\
				continue;			\
			dev->event(dev, EV_##type, i, on);	\
		}						\
	} while (0)

static void input_dev_reset(struct input_dev *dev, bool activate)
{
	if (!dev->event)
		return;

	INPUT_DO_TOGGLE(dev, LED, led, activate);
	INPUT_DO_TOGGLE(dev, SND, snd, activate);

	if (activate && test_bit(EV_REP, dev->evbit)) {
		dev->event(dev, EV_REP, REP_PERIOD, dev->rep[REP_PERIOD]);
		dev->event(dev, EV_REP, REP_DELAY, dev->rep[REP_DELAY]);
	}
}

#ifdef CONFIG_PM
static int input_dev_suspend(struct device *dev)
{
	struct input_dev *input_dev = to_input_dev(dev);

	mutex_lock(&input_dev->mutex);
	input_dev_reset(input_dev, false);
	mutex_unlock(&input_dev->mutex);

	return 0;
}

static int input_dev_resume(struct device *dev)
{
	struct input_dev *input_dev = to_input_dev(dev);

	mutex_lock(&input_dev->mutex);
	input_dev_reset(input_dev, true);
	mutex_unlock(&input_dev->mutex);

	return 0;
}

static const struct dev_pm_ops input_dev_pm_ops = {
	.suspend	= input_dev_suspend,
	.resume		= input_dev_resume,
	.poweroff	= input_dev_suspend,
	.restore	= input_dev_resume,
};
#endif /* CONFIG_PM */

static struct device_type input_dev_type = {
	.groups		= input_dev_attr_groups,
	.release	= input_dev_release,
	.uevent		= input_dev_uevent,
#ifdef CONFIG_PM
	.pm		= &input_dev_pm_ops,
#endif
};

static char *input_devnode(struct device *dev, mode_t *mode)
+40 −0
Original line number Diff line number Diff line
@@ -24,6 +24,16 @@ config KEYBOARD_AAED2000
	  To compile this driver as a module, choose M here: the
	  module will be called aaed2000_kbd.

config KEYBOARD_ADP5588
	tristate "ADP5588 I2C QWERTY Keypad and IO Expander"
	depends on I2C
	help
	  Say Y here if you want to use a ADP5588 attached to your
	  system I2C bus.

	  To compile this driver as a module, choose M here: the
	  module will be called adp5588-keys.

config KEYBOARD_AMIGA
	tristate "Amiga keyboard"
	depends on AMIGA
@@ -104,6 +114,16 @@ config KEYBOARD_ATKBD_RDI_KEYCODES
	  right-hand column will be interpreted as the key shown in the
	  left-hand column.

config QT2160
	tristate "Atmel AT42QT2160 Touch Sensor Chip"
	depends on I2C && EXPERIMENTAL
	help
	  If you say yes here you get support for Atmel AT42QT2160 Touch
	  Sensor chip as a keyboard input.

	  This driver can also be built as a module. If so, the module
	  will be called qt2160.

config KEYBOARD_BFIN
	tristate "Blackfin BF54x keypad support"
	depends on (BF54x && !BF544)
@@ -251,6 +271,17 @@ config KEYBOARD_MAPLE
	  To compile this driver as a module, choose M here: the
	  module will be called maple_keyb.

config KEYBOARD_MAX7359
	tristate "Maxim MAX7359 Key Switch Controller"
	depends on I2C
	help
	  If you say yes here you get support for the Maxim MAX7359 Key
	  Switch Controller chip. This providers microprocessors with
	  management of up to 64 key switches

	  To compile this driver as a module, choose M here: the
	  module will be called max7359_keypad.

config KEYBOARD_NEWTON
	tristate "Newton keyboard"
	select SERIO
@@ -260,6 +291,15 @@ config KEYBOARD_NEWTON
	  To compile this driver as a module, choose M here: the
	  module will be called newtonkbd.

config KEYBOARD_OPENCORES
	tristate "OpenCores Keyboard Controller"
	help
	  Say Y here if you want to use the OpenCores Keyboard Controller
	  http://www.opencores.org/project,keyboardcontroller

	  To compile this driver as a module, choose M here; the
	  module will be called opencores-kbd.

config KEYBOARD_PXA27x
	tristate "PXA27x/PXA3xx keypad support"
	depends on PXA27x || PXA3xx
+4 −0
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
# Each configuration option enables a list of files.

obj-$(CONFIG_KEYBOARD_AAED2000)		+= aaed2000_kbd.o
obj-$(CONFIG_KEYBOARD_ADP5588)		+= adp5588-keys.o
obj-$(CONFIG_KEYBOARD_AMIGA)		+= amikbd.o
obj-$(CONFIG_KEYBOARD_ATARI)		+= atakbd.o
obj-$(CONFIG_KEYBOARD_ATKBD)		+= atkbd.o
@@ -21,10 +22,13 @@ obj-$(CONFIG_KEYBOARD_LM8323) += lm8323.o
obj-$(CONFIG_KEYBOARD_LOCOMO)		+= locomokbd.o
obj-$(CONFIG_KEYBOARD_MAPLE)		+= maple_keyb.o
obj-$(CONFIG_KEYBOARD_MATRIX)		+= matrix_keypad.o
obj-$(CONFIG_KEYBOARD_MAX7359)		+= max7359_keypad.o
obj-$(CONFIG_KEYBOARD_NEWTON)		+= newtonkbd.o
obj-$(CONFIG_KEYBOARD_OMAP)		+= omap-keypad.o
obj-$(CONFIG_KEYBOARD_OPENCORES)	+= opencores-kbd.o
obj-$(CONFIG_KEYBOARD_PXA27x)		+= pxa27x_keypad.o
obj-$(CONFIG_KEYBOARD_PXA930_ROTARY)	+= pxa930_rotary.o
obj-$(CONFIG_KEYBOARD_QT2160)		+= qt2160.o
obj-$(CONFIG_KEYBOARD_SH_KEYSC)		+= sh_keysc.o
obj-$(CONFIG_KEYBOARD_SPITZ)		+= spitzkbd.o
obj-$(CONFIG_KEYBOARD_STOWAWAY)		+= stowaway.o
+361 −0
Original line number Diff line number Diff line
/*
 * File: drivers/input/keyboard/adp5588_keys.c
 * Description:  keypad driver for ADP5588 I2C QWERTY Keypad and IO Expander
 * Bugs: Enter bugs at http://blackfin.uclinux.org/
 *
 * Copyright (C) 2008-2009 Analog Devices Inc.
 * Licensed under the GPL-2 or later.
 */

#include <linux/module.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/workqueue.h>
#include <linux/errno.h>
#include <linux/pm.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/i2c.h>

#include <linux/i2c/adp5588.h>

 /* Configuration Register1 */
#define AUTO_INC	(1 << 7)
#define GPIEM_CFG	(1 << 6)
#define OVR_FLOW_M	(1 << 5)
#define INT_CFG		(1 << 4)
#define OVR_FLOW_IEN	(1 << 3)
#define K_LCK_IM	(1 << 2)
#define GPI_IEN		(1 << 1)
#define KE_IEN		(1 << 0)

/* Interrupt Status Register */
#define CMP2_INT	(1 << 5)
#define CMP1_INT	(1 << 4)
#define OVR_FLOW_INT	(1 << 3)
#define K_LCK_INT	(1 << 2)
#define GPI_INT		(1 << 1)
#define KE_INT		(1 << 0)

/* Key Lock and Event Counter Register */
#define K_LCK_EN	(1 << 6)
#define LCK21		0x30
#define KEC		0xF

/* Key Event Register xy */
#define KEY_EV_PRESSED		(1 << 7)
#define KEY_EV_MASK		(0x7F)

#define KP_SEL(x)		(0xFFFF >> (16 - x))	/* 2^x-1 */

#define KEYP_MAX_EVENT		10

/*
 * Early pre 4.0 Silicon required to delay readout by at least 25ms,
 * since the Event Counter Register updated 25ms after the interrupt
 * asserted.
 */
#define WA_DELAYED_READOUT_REVID(rev)		((rev) < 4)

struct adp5588_kpad {
	struct i2c_client *client;
	struct input_dev *input;
	struct delayed_work work;
	unsigned long delay;
	unsigned short keycode[ADP5588_KEYMAPSIZE];
};

static int adp5588_read(struct i2c_client *client, u8 reg)
{
	int ret = i2c_smbus_read_byte_data(client, reg);

	if (ret < 0)
		dev_err(&client->dev, "Read Error\n");

	return ret;
}

static int adp5588_write(struct i2c_client *client, u8 reg, u8 val)
{
	return i2c_smbus_write_byte_data(client, reg, val);
}

static void adp5588_work(struct work_struct *work)
{
	struct adp5588_kpad *kpad = container_of(work,
						struct adp5588_kpad, work.work);
	struct i2c_client *client = kpad->client;
	int i, key, status, ev_cnt;

	status = adp5588_read(client, INT_STAT);

	if (status & OVR_FLOW_INT)	/* Unlikely and should never happen */
		dev_err(&client->dev, "Event Overflow Error\n");

	if (status & KE_INT) {
		ev_cnt = adp5588_read(client, KEY_LCK_EC_STAT) & KEC;
		if (ev_cnt) {
			for (i = 0; i < ev_cnt; i++) {
				key = adp5588_read(client, Key_EVENTA + i);
				input_report_key(kpad->input,
					kpad->keycode[(key & KEY_EV_MASK) - 1],
					key & KEY_EV_PRESSED);
			}
			input_sync(kpad->input);
		}
	}
	adp5588_write(client, INT_STAT, status); /* Status is W1C */
}

static irqreturn_t adp5588_irq(int irq, void *handle)
{
	struct adp5588_kpad *kpad = handle;

	/*
	 * use keventd context to read the event fifo registers
	 * Schedule readout at least 25ms after notification for
	 * REVID < 4
	 */

	schedule_delayed_work(&kpad->work, kpad->delay);

	return IRQ_HANDLED;
}

static int __devinit adp5588_setup(struct i2c_client *client)
{
	struct adp5588_kpad_platform_data *pdata = client->dev.platform_data;
	int i, ret;

	ret = adp5588_write(client, KP_GPIO1, KP_SEL(pdata->rows));
	ret |= adp5588_write(client, KP_GPIO2, KP_SEL(pdata->cols) & 0xFF);
	ret |= adp5588_write(client, KP_GPIO3, KP_SEL(pdata->cols) >> 8);

	if (pdata->en_keylock) {
		ret |= adp5588_write(client, UNLOCK1, pdata->unlock_key1);
		ret |= adp5588_write(client, UNLOCK2, pdata->unlock_key2);
		ret |= adp5588_write(client, KEY_LCK_EC_STAT, K_LCK_EN);
	}

	for (i = 0; i < KEYP_MAX_EVENT; i++)
		ret |= adp5588_read(client, Key_EVENTA);

	ret |= adp5588_write(client, INT_STAT, CMP2_INT | CMP1_INT |
					OVR_FLOW_INT | K_LCK_INT |
					GPI_INT | KE_INT); /* Status is W1C */

	ret |= adp5588_write(client, CFG, INT_CFG | OVR_FLOW_IEN | KE_IEN);

	if (ret < 0) {
		dev_err(&client->dev, "Write Error\n");
		return ret;
	}

	return 0;
}

static int __devinit adp5588_probe(struct i2c_client *client,
					const struct i2c_device_id *id)
{
	struct adp5588_kpad *kpad;
	struct adp5588_kpad_platform_data *pdata = client->dev.platform_data;
	struct input_dev *input;
	unsigned int revid;
	int ret, i;
	int error;

	if (!i2c_check_functionality(client->adapter,
					I2C_FUNC_SMBUS_BYTE_DATA)) {
		dev_err(&client->dev, "SMBUS Byte Data not Supported\n");
		return -EIO;
	}

	if (!pdata) {
		dev_err(&client->dev, "no platform data?\n");
		return -EINVAL;
	}

	if (!pdata->rows || !pdata->cols || !pdata->keymap) {
		dev_err(&client->dev, "no rows, cols or keymap from pdata\n");
		return -EINVAL;
	}

	if (pdata->keymapsize != ADP5588_KEYMAPSIZE) {
		dev_err(&client->dev, "invalid keymapsize\n");
		return -EINVAL;
	}

	if (!client->irq) {
		dev_err(&client->dev, "no IRQ?\n");
		return -EINVAL;
	}

	kpad = kzalloc(sizeof(*kpad), GFP_KERNEL);
	input = input_allocate_device();
	if (!kpad || !input) {
		error = -ENOMEM;
		goto err_free_mem;
	}

	kpad->client = client;
	kpad->input = input;
	INIT_DELAYED_WORK(&kpad->work, adp5588_work);

	ret = adp5588_read(client, DEV_ID);
	if (ret < 0) {
		error = ret;
		goto err_free_mem;
	}

	revid = (u8) ret & ADP5588_DEVICE_ID_MASK;
	if (WA_DELAYED_READOUT_REVID(revid))
		kpad->delay = msecs_to_jiffies(30);

	input->name = client->name;
	input->phys = "adp5588-keys/input0";
	input->dev.parent = &client->dev;

	input_set_drvdata(input, kpad);

	input->id.bustype = BUS_I2C;
	input->id.vendor = 0x0001;
	input->id.product = 0x0001;
	input->id.version = revid;

	input->keycodesize = sizeof(kpad->keycode[0]);
	input->keycodemax = pdata->keymapsize;
	input->keycode = kpad->keycode;

	memcpy(kpad->keycode, pdata->keymap,
		pdata->keymapsize * input->keycodesize);

	/* setup input device */
	__set_bit(EV_KEY, input->evbit);

	if (pdata->repeat)
		__set_bit(EV_REP, input->evbit);

	for (i = 0; i < input->keycodemax; i++)
		__set_bit(kpad->keycode[i] & KEY_MAX, input->keybit);
	__clear_bit(KEY_RESERVED, input->keybit);

	error = input_register_device(input);
	if (error) {
		dev_err(&client->dev, "unable to register input device\n");
		goto err_free_mem;
	}

	error = request_irq(client->irq, adp5588_irq,
			    IRQF_TRIGGER_FALLING | IRQF_DISABLED,
			    client->dev.driver->name, kpad);
	if (error) {
		dev_err(&client->dev, "irq %d busy?\n", client->irq);
		goto err_unreg_dev;
	}

	error = adp5588_setup(client);
	if (error)
		goto err_free_irq;

	device_init_wakeup(&client->dev, 1);
	i2c_set_clientdata(client, kpad);

	dev_info(&client->dev, "Rev.%d keypad, irq %d\n", revid, client->irq);
	return 0;

 err_free_irq:
	free_irq(client->irq, kpad);
 err_unreg_dev:
	input_unregister_device(input);
	input = NULL;
 err_free_mem:
	input_free_device(input);
	kfree(kpad);

	return error;
}

static int __devexit adp5588_remove(struct i2c_client *client)
{
	struct adp5588_kpad *kpad = i2c_get_clientdata(client);

	adp5588_write(client, CFG, 0);
	free_irq(client->irq, kpad);
	cancel_delayed_work_sync(&kpad->work);
	input_unregister_device(kpad->input);
	i2c_set_clientdata(client, NULL);
	kfree(kpad);

	return 0;
}

#ifdef CONFIG_PM
static int adp5588_suspend(struct device *dev)
{
	struct adp5588_kpad *kpad = dev_get_drvdata(dev);
	struct i2c_client *client = kpad->client;

	disable_irq(client->irq);
	cancel_delayed_work_sync(&kpad->work);

	if (device_may_wakeup(&client->dev))
		enable_irq_wake(client->irq);

	return 0;
}

static int adp5588_resume(struct device *dev)
{
	struct adp5588_kpad *kpad = dev_get_drvdata(dev);
	struct i2c_client *client = kpad->client;

	if (device_may_wakeup(&client->dev))
		disable_irq_wake(client->irq);

	enable_irq(client->irq);

	return 0;
}

static struct dev_pm_ops adp5588_dev_pm_ops = {
	.suspend = adp5588_suspend,
	.resume  = adp5588_resume,
};
#endif

static const struct i2c_device_id adp5588_id[] = {
	{ KBUILD_MODNAME, 0 },
	{ }
};
MODULE_DEVICE_TABLE(i2c, adp5588_id);

static struct i2c_driver adp5588_driver = {
	.driver = {
		.name = KBUILD_MODNAME,
#ifdef CONFIG_PM
		.pm   = &adp5588_dev_pm_ops,
#endif
	},
	.probe    = adp5588_probe,
	.remove   = __devexit_p(adp5588_remove),
	.id_table = adp5588_id,
};

static int __init adp5588_init(void)
{
	return i2c_add_driver(&adp5588_driver);
}
module_init(adp5588_init);

static void __exit adp5588_exit(void)
{
	i2c_del_driver(&adp5588_driver);
}
module_exit(adp5588_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("ADP5588 Keypad driver");
MODULE_ALIAS("platform:adp5588-keys");
+0 −25
Original line number Diff line number Diff line
@@ -773,23 +773,6 @@ static int atkbd_select_set(struct atkbd *atkbd, int target_set, int allow_extra
static int atkbd_activate(struct atkbd *atkbd)
{
	struct ps2dev *ps2dev = &atkbd->ps2dev;
	unsigned char param[1];

/*
 * Set the LEDs to a defined state.
 */

	param[0] = 0;
	if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS))
		return -1;

/*
 * Set autorepeat to fastest possible.
 */

	param[0] = 0;
	if (ps2_command(ps2dev, param, ATKBD_CMD_SETREP))
		return -1;

/*
 * Enable the keyboard to receive keystrokes.
@@ -1158,14 +1141,6 @@ static int atkbd_reconnect(struct serio *serio)
			return -1;

		atkbd_activate(atkbd);

/*
 * Restore repeat rate and LEDs (that were reset by atkbd_activate)
 * to pre-resume state
 */
		if (!atkbd->softrepeat)
			atkbd_set_repeat_rate(atkbd);
		atkbd_set_leds(atkbd);
	}

	atkbd_enable(atkbd);
Loading