Modified: trunk/drivers/input/misc/Kconfig (8732 => 8733)
--- trunk/drivers/input/misc/Kconfig 2010-05-21 07:05:32 UTC (rev 8732)
+++ trunk/drivers/input/misc/Kconfig 2010-05-21 07:05:59 UTC (rev 8733)
@@ -277,6 +277,16 @@
Say Y to include support for delivering PMU events via input
layer on NXP PCF50633.
+config INPUT_PCF8574
+ tristate "PCF8574 Keypad input device"
+ depends on I2C && EXPERIMENTAL
+ help
+ Say Y here if you want to support a keypad connetced via I2C
+ with a PCF8574.
+
+ To compile this driver as a module, choose M here: the
+ module will be called pcf8574_keypad.
+
config INPUT_GPIO_ROTARY_ENCODER
tristate "Rotary encoders connected to GPIO pins"
depends on GPIOLIB && GENERIC_GPIO
@@ -407,14 +417,4 @@
To compile this driver as a module, choose M here: the
module will be called adxl34x-spi.
-config INPUT_PCF8574
- tristate "PCF8574 Keypad input device"
- depends on I2C && EXPERIMENTAL
- help
- Say Y here if you want to support a keypad connetced via I2C
- with a PCF8574.
-
- To compile this driver as a module, choose M here: the
- module will be called pcf8574_keypad.
-
endif
Modified: trunk/drivers/input/misc/pcf8574_keypad.c (8732 => 8733)
--- trunk/drivers/input/misc/pcf8574_keypad.c 2010-05-21 07:05:32 UTC (rev 8732)
+++ trunk/drivers/input/misc/pcf8574_keypad.c 2010-05-21 07:05:59 UTC (rev 8733)
@@ -11,6 +11,7 @@
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
+#include <linux/slab.h>
#include <linux/workqueue.h>
#define DRV_NAME "pcf8574_keypad"
@@ -36,65 +37,48 @@
};
struct kp_data {
- unsigned char btncode[17];
+ unsigned short btncode[ARRAY_SIZE(pcf8574_kp_btncode)];
struct input_dev *idev;
struct i2c_client *client;
char name[64];
char phys[32];
unsigned char laststate;
- unsigned char statechanged;
- unsigned long events_sent;
- struct work_struct pcf8574_kp_work;
};
static short read_state(struct kp_data *lp)
{
unsigned char x, y, a, b;
- if (lp->client) {
- i2c_smbus_write_byte(lp->client, 240);
- x = 0xF & (~(i2c_smbus_read_byte(lp->client) >> 4));
+ i2c_smbus_write_byte(lp->client, 240);
+ x = 0xF & (~(i2c_smbus_read_byte(lp->client) >> 4));
- i2c_smbus_write_byte(lp->client, 15);
- y = 0xF & (~i2c_smbus_read_byte(lp->client));
+ i2c_smbus_write_byte(lp->client, 15);
+ y = 0xF & (~i2c_smbus_read_byte(lp->client));
- for (a = 0; x > 0; a++)
- x = x >> 1;
- for (b = 0; y > 0; b++)
- y = y >> 1;
+ for (a = 0; x > 0; a++)
+ x = x >> 1;
+ for (b = 0; y > 0; b++)
+ y = y >> 1;
- return ((a - 1) * 4) + b;
- }
-
- return -1;
+ return ((a - 1) * 4) + b;
}
-static void check_and_notify(struct work_struct *work)
+static irqreturn_t pcf8574_kp_irq_handler(int irq, void *dev_id)
{
- struct kp_data *lp =
- container_of(work, struct kp_data, pcf8574_kp_work);
+ struct kp_data *lp = dev_id;
unsigned char nextstate = read_state(lp);
- lp->statechanged = lp->laststate ^ nextstate;
+ if (lp->laststate != nextstate) {
+ int key_down = nextstate <= ARRAY_SIZE(lp->btncode);
+ unsigned short keycode = key_down ?
+ lp->btncode[nextstate] : lp->btncode[lp->laststate];
- if (lp->statechanged)
- input_report_key(lp->idev,
- nextstate > 17 ? lp->btncode[lp->laststate] :
- lp->btncode[nextstate],
- nextstate > 17 ? 0 : 1);
- lp->laststate = nextstate;
+ input_report_key(lp->idev, keycode, key_down);
+ input_sync(lp->idev);
- input_sync(lp->idev);
- enable_irq(lp->client->irq);
-}
+ lp->laststate = nextstate;
+ }
-static irqreturn_t pcf8574_kp_irq_handler(int irq, void *dev_id)
-{
- struct kp_data *lp = dev_id;
-
- disable_irq_nosync(lp->client->irq);
- schedule_work(&lp->pcf8574_kp_work);
-
return IRQ_HANDLED;
}
@@ -112,7 +96,6 @@
lp = kzalloc(sizeof(*lp), GFP_KERNEL);
if (!lp)
return -ENOMEM;
- lp->client = client;
idev = input_allocate_device();
if (!idev) {
@@ -122,20 +105,18 @@
}
lp->idev = idev;
- memcpy(lp->btncode, pcf8574_kp_btncode, sizeof(pcf8574_kp_btncode));
+ lp->client = client;
- idev->evbit[0] = 0;
-
- idev->evbit[0] |= BIT_MASK(EV_KEY);
+ idev->evbit[0] = BIT_MASK(EV_KEY);
idev->keycode = lp->btncode;
- idev->keycodesize = sizeof(pcf8574_kp_btncode);
- idev->keycodemax = ARRAY_SIZE(pcf8574_kp_btncode);
+ idev->keycodesize = sizeof(lp->btncode[0]);
+ idev->keycodemax = ARRAY_SIZE(lp->btncode);
- for (i = 0; i < ARRAY_SIZE(pcf8574_kp_btncode); ++i)
+ for (i = 0; i < ARRAY_SIZE(pcf8574_kp_btncode); i++) {
+ lp->btncode[i] = pcf8574_kp_btncode[i];
__set_bit(lp->btncode[i] & KEY_MAX, idev->keybit);
+ }
- __clear_bit(KEY_RESERVED, idev->keybit);
-
sprintf(lp->name, DRV_NAME);
sprintf(lp->phys, "kp_data/input0");
@@ -154,22 +135,17 @@
goto fail_register;
}
- lp->statechanged = 0x0;
-
lp->laststate = read_state(lp);
- /* Set up our workqueue. */
- INIT_WORK(&lp->pcf8574_kp_work, check_and_notify);
-
- i2c_set_clientdata(client, lp);
-
- ret = request_irq(client->irq, pcf8574_kp_irq_handler,
- IRQF_TRIGGER_LOW, DRV_NAME, lp);
+ ret = request_threaded_irq(client->irq, NULL, pcf8574_kp_irq_handler,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ DRV_NAME, lp);
if (ret) {
dev_err(&client->dev, "IRQ %d is not free\n", client->irq);
goto fail_irq;
}
+ i2c_set_clientdata(client, lp);
return 0;
fail_irq:
@@ -187,10 +163,8 @@
{
struct kp_data *lp = i2c_get_clientdata(client);
- if (client->irq > 0)
- free_irq(client->irq, lp);
+ free_irq(client->irq, lp);
- input_set_drvdata(lp->idev, NULL);
input_unregister_device(lp->idev);
kfree(lp);
@@ -203,12 +177,14 @@
static int pcf8574_kp_resume(struct i2c_client *client)
{
enable_irq(client->irq);
+
return 0;
}
static int pcf8574_kp_suspend(struct i2c_client *client, pm_message_t mesg)
{
disable_irq(client->irq);
+
return 0;
}
#else
@@ -225,7 +201,7 @@
static struct i2c_driver pcf8574_kp_driver = {
.driver = {
.name = DRV_NAME,
- .owner = THIS_MODULE
+ .owner = THIS_MODULE,
},
.probe = pcf8574_kp_probe,
.remove = __devexit_p(pcf8574_kp_remove),