Modified: trunk/drivers/input/misc/twi_keypad.c (3943 => 3944)
--- trunk/drivers/input/misc/twi_keypad.c 2007-11-27 08:43:44 UTC (rev 3943)
+++ trunk/drivers/input/misc/twi_keypad.c 2007-11-27 13:06:28 UTC (rev 3944)
@@ -1,23 +1,23 @@
/************************************************************
*
-* Copyright (C) 2006, Analog Devices. All Rights Reserved
+* Copyright (C) 2006-2007, Analog Devices. All Rights Reserved
*
* FILE twi_keypad.c
* PROGRAMMER(S): Michael Hennerich (Analog Devices Inc.)
-* <[EMAIL PROTECTED]>
+* <[EMAIL PROTECTED]>
*
-* $Id$
*
* DATE OF CREATION: Feb. 24th 2006
*
* SYNOPSIS:
*
-* DESCRIPTION: TWI Driver for an 4x4 Keybaord Matrix connected to
-* a PCF8574 I2C IO expander
-* CAUTION:
+* DESCRIPTION: TWI Driver for an 4x4 Keybaord Matrix connected to
+* a PCF8574 I2C IO expander
+* CAUTION:
**************************************************************
* MODIFICATION HISTORY:
-* 24.02.2006 11:00 twi_keypad.c Created. (Michael Hennerich)
+* 24.02.2006 twi_keypad.c Created. (Michael Hennerich)
+* 27.11.2007 twi_keypad.c cleanup (Michael Hennerich)
************************************************************
*
* This program is free software; you can distribute it and/or modify it
@@ -47,83 +47,69 @@
#include <linux/i2c.h>
#include <linux/workqueue.h>
-MODULE_AUTHOR ("Michael Hennerich <[EMAIL PROTECTED]>");
-MODULE_DESCRIPTION ("TWI Keypad input driver");
-MODULE_LICENSE ("GPL");
+MODULE_AUTHOR("Michael Hennerich <[EMAIL PROTECTED]>");
+MODULE_DESCRIPTION("TWI Keypad input driver");
+MODULE_LICENSE("GPL");
#undef SENDASCII
-#undef DEBUG
-//#define DEBUG
-#ifdef DEBUG
-#define DPRINTK(x...) printk(x)
-#else
-#define DPRINTK(x...) do { } while (0)
-#endif
-
#define BUTTONS 16
#ifdef SENDASCII
static unsigned char twi_keypad_btncode[BUTTONS + 1] = {
- [0] = KEY_RESERVED,
- [1] = 'd',
- [2] = '#',
- [3] = '0',
- [4] = '*',
- [5] = 'c',
- [6] = '9',
- [7] = '8',
- [8] = '7',
- [9] = 'b',
- [10] = '6',
- [11] = '5',
- [12] = '4',
- [13] = 'a',
- [14] = '3',
- [15] = '2',
- [16] = '1'
+ [0] = KEY_RESERVED,
+ [1] = 'd',
+ [2] = '#',
+ [3] = '0',
+ [4] = '*',
+ [5] = 'c',
+ [6] = '9',
+ [7] = '8',
+ [8] = '7',
+ [9] = 'b',
+ [10] = '6',
+ [11] = '5',
+ [12] = '4',
+ [13] = 'a',
+ [14] = '3',
+ [15] = '2',
+ [16] = '1'
};
#else
static unsigned char twi_keypad_btncode[BUTTONS + 1] = {
- [0] = KEY_RESERVED,
- [1] = KEY_ENTER,
- [2] = KEY_BACKSLASH,
- [3] = KEY_0,
- [4] = KEY_RIGHTBRACE,
- [5] = KEY_C,
- [6] = KEY_9,
- [7] = KEY_8,
- [8] = KEY_7,
- [9] = KEY_B,
- [10] = KEY_6,
- [11] = KEY_5,
- [12] = KEY_4,
- [13] = KEY_A,
- [14] = KEY_3,
- [15] = KEY_2,
- [16] = KEY_1
+ [0] = KEY_RESERVED,
+ [1] = KEY_ENTER,
+ [2] = KEY_BACKSLASH,
+ [3] = KEY_0,
+ [4] = KEY_RIGHTBRACE,
+ [5] = KEY_C,
+ [6] = KEY_9,
+ [7] = KEY_8,
+ [8] = KEY_7,
+ [9] = KEY_B,
+ [10] = KEY_6,
+ [11] = KEY_5,
+ [12] = KEY_4,
+ [13] = KEY_A,
+ [14] = KEY_3,
+ [15] = KEY_2,
+ [16] = KEY_1
};
-
#endif
-
-struct TWIKeypad
-{
-
- unsigned char *btncode;
- struct input_dev *dev;
- char name[64];
- char phys[32];
- unsigned char laststate;
- unsigned char statechanged;
- unsigned long irq_handled;
- unsigned long events_sended;
- unsigned long events_processed;
- struct workqueue_struct *twi_keypad_workqueue;
- struct work_struct twi_keypad_work;
+struct twikeypad {
+ unsigned char *btncode;
+ struct input_dev *idev;
+ char name[64];
+ char phys[32];
+ unsigned char laststate;
+ unsigned char statechanged;
+ unsigned long irq_handled;
+ unsigned long events_sended;
+ unsigned long events_processed;
+ struct work_struct twi_keypad_work;
};
-
#define PCF8574_KP_DRV_NAME "pcf8574_kp"
static struct i2c_driver pcf8574_kp_driver;
static struct i2c_client *pcf8574_kp_client;
@@ -132,249 +118,213 @@
static unsigned short normal_addr[] = { 0x27, I2C_CLIENT_END };
static struct i2c_client_address_data addr_data = {
- .normal_i2c = normal_addr,
- .probe = ignore,
- .ignore = ignore,
+ .normal_i2c = normal_addr,
+ .probe = ignore,
+ .ignore = ignore,
};
-static irqreturn_t twi_keypad_irq_handler (int irq, void *dev_id);
-static short read_state (struct TWIKeypad *TWIKeypad);
-
-static int
-pcf8574_kp_probe (struct i2c_adapter *adap, int addr, int kind)
+static short read_state(struct twikeypad *lp)
{
- struct i2c_client *client;
- int rc;
+ unsigned char x, y, a, b;
- client = kmalloc (sizeof (struct i2c_client), GFP_KERNEL);
- if (!client)
- return -ENOMEM;
+ if (pcf8574_kp_client) {
+ i2c_smbus_write_byte(pcf8574_kp_client, 240);
+ x = 0xF & (~(i2c_smbus_read_byte(pcf8574_kp_client) >> 4));
- memset (client, 0, sizeof (struct i2c_client));
- strncpy (client->name, PCF8574_KP_DRV_NAME, I2C_NAME_SIZE);
- client->addr = addr;
- client->adapter = adap;
- client->driver = &pcf8574_kp_driver;
+ i2c_smbus_write_byte(pcf8574_kp_client, 15);
+ y = 0xF & (~i2c_smbus_read_byte(pcf8574_kp_client));
- if ((rc = i2c_attach_client (client)) != 0)
- {
- kfree (client);
- printk ("i2c_attach_client fail: %d\n", rc);
- return rc;
- }
+ for (a = 0; x > 0; a++)
+ x = x >> 1;
+ for (b = 0; y > 0; b++)
+ y = y >> 1;
- pcf8574_kp_client = client;
+ return (((a - 1) * 4) + b);
+ }
- if(i2c_smbus_write_byte (pcf8574_kp_client, 240)<0) {
- printk("in keypad probe: write fail\n");
- return -1;
- }
-
- return 0;
+ return -1;
}
-static int
-pcf8574_kp_attach (struct i2c_adapter *adap)
+static void check_and_notify(struct work_struct *work)
{
- if (adap->algo->functionality)
- return i2c_probe (adap, &addr_data, pcf8574_kp_probe);
- else
- return pcf8574_kp_probe (adap, 0x27, 0);
-}
+ struct twikeypad *lp =
+ container_of(work, struct twikeypad, twi_keypad_work);
+ unsigned char nextstate = read_state(lp);
-static int
-pcf8574_kp_detach_client (struct i2c_client *client)
-{
- int rc;
- if ((rc = i2c_detach_client (client)) == 0)
- kfree (i2c_get_clientdata (client));
- return rc;
-}
+ pr_debug("%s\n", __FUNCTION__);
+ lp->statechanged = lp->laststate ^ nextstate;
-static struct i2c_driver pcf8574_kp_driver = {
- .driver = {
- .name = PCF8574_KP_DRV_NAME,
- },
- .id = 0x65,
- .attach_adapter = pcf8574_kp_attach,
- .detach_client = pcf8574_kp_detach_client,
-};
+ if (lp->statechanged) {
+ input_report_key(lp->idev,
+ nextstate > 17 ? lp->btncode[lp->laststate] :
+ lp->btncode[nextstate],
+ nextstate > 17 ? 0 : 1);
+ lp->events_sended++;
+ }
+ lp->laststate = nextstate;
+ input_sync(lp->idev);
+ enable_irq(CONFIG_BFIN_TWIKEYPAD_IRQ_PFX);
-static short
-read_state (struct TWIKeypad *TWIKeypad)
+}
+
+static irqreturn_t twi_keypad_irq_handler(int irq, void *dev_id)
{
- unsigned char x, y, a, b;
+ struct twikeypad *lp = dev_id;
- if (pcf8574_kp_client)
- {
- i2c_smbus_write_byte (pcf8574_kp_client, 240);
- x = 0xF & (~(i2c_smbus_read_byte (pcf8574_kp_client) >> 4));
+ pr_debug("%s\n", __FUNCTION__);
+ disable_irq(CONFIG_BFIN_TWIKEYPAD_IRQ_PFX);
+ schedule_work(&lp->twi_keypad_work);
- i2c_smbus_write_byte (pcf8574_kp_client, 15);
- y = 0xF & (~i2c_smbus_read_byte (pcf8574_kp_client));
+ return IRQ_HANDLED;
+}
- for (a = 0; x > 0; a++)
- x = x >> 1;
- for (b = 0; y > 0; b++)
- y = y >> 1;
+static int init_twikeypad(struct i2c_client *client)
+{
+ int i, ret;
+ struct input_dev *idev;
+ struct twikeypad *lp;
- return (((a - 1) * 4) + b);
+ lp = kzalloc(sizeof(struct twikeypad), GFP_KERNEL);
+ idev = input_allocate_device();
- }
+ if (!idev || !lp) {
+ ret = -ENOMEM;
+ goto fail;
+ }
- return -1;
+ if (request_irq(CONFIG_BFIN_TWIKEYPAD_IRQ_PFX, twi_keypad_irq_handler,
+ IRQF_TRIGGER_LOW, PCF8574_KP_DRV_NAME, lp)) {
-}
+ printk(KERN_WARNING "twikeypad: IRQ %d is not free.\n",
+ CONFIG_BFIN_TWIKEYPAD_IRQ_PFX);
+ ret = -EBUSY;
+ goto fail;
+ }
+ i2c_set_clientdata(client, lp);
-static void
-check_and_notify (struct work_struct *work)
-{
- struct TWIKeypad *TWIKeypad = container_of(work, struct TWIKeypad, twi_keypad_work);
- unsigned char nextstate = read_state (TWIKeypad);
- TWIKeypad->statechanged = TWIKeypad->laststate ^ nextstate;
+ lp->idev = idev;
+ lp->btncode = twi_keypad_btncode;
- if (TWIKeypad->statechanged)
- {
- input_report_key (TWIKeypad->dev,
- nextstate >
- 17 ? TWIKeypad->btncode[TWIKeypad->
- laststate] : TWIKeypad->
- btncode[nextstate], nextstate > 17 ? 0 : 1);
+ idev->evbit[0] = 0;
- TWIKeypad->events_sended++;
- }
+ idev->evbit[0] |= BIT(EV_KEY);
+ idev->keycode = lp->btncode;
+ idev->keycodesize = sizeof(twi_keypad_btncode);
+ idev->keycodemax = ARRAY_SIZE(twi_keypad_btncode);
- TWIKeypad->laststate = nextstate;
- input_sync (TWIKeypad->dev);
+ for (i = 0; i <= BUTTONS; i++)
+ set_bit(lp->btncode[i], idev->keybit);
- enable_irq(CONFIG_BFIN_TWIKEYPAD_IRQ_PFX);
-}
+ sprintf(lp->name, "BF5xx twikeypad");
+ sprintf(lp->phys, "twikeypad/input0");
-static irqreturn_t
-twi_keypad_irq_handler (int irq, void *dev_id)
-{
- disable_irq(CONFIG_BFIN_TWIKEYPAD_IRQ_PFX);
- // queue_work(twi_keypad_workqueue, &twi_keypad_work);
+ idev->name = lp->name;
+ idev->phys = lp->phys;
+ idev->id.bustype = BUS_I2C;
+ idev->id.vendor = 0x0001;
+ idev->id.product = 0x0001;
+ idev->id.version = 0x0100;
- DPRINTK ("twi_keypad_irq_handler \n");
- return IRQ_HANDLED;
-}
+ input_register_device(lp->idev);
-#if 0
-/*
- * sunkbd_event() handles events from the input module.
- */
+ lp->statechanged = 0x0;
-static int
-twi_keypad_dev_event (struct input_dev *dev, unsigned int type,
- unsigned int code, int value)
-{
- struct TWIKeypad *TWIKeypad = (struct TWIKeypad *) dev->private;
- int i;
+ lp->laststate = read_state(lp);
+ /* Set up our workqueue. */
+ INIT_WORK(&lp->twi_keypad_work, check_and_notify);
- switch (type)
- {
+ printk(KERN_INFO "input: %s at %s IRQ %d\n", lp->name, lp->phys,
+ CONFIG_BFIN_TWIKEYPAD_IRQ_PFX);
- case EV_LED:
+ return 0;
- case EV_SND:
+fail:
+ input_free_device(idev);
+ kfree(lp);
+ i2c_set_clientdata(client, NULL);
- break;
- }
-
- return 0;
+ return -1;
}
-#endif
-
-static int __init
-twi_keypad_init (void)
+static int pcf8574_kp_probe(struct i2c_adapter *adap, int addr, int kind)
{
-// struct TWIKeypad *TWIKeypad = &chip;
- int i;
+ struct i2c_client *client;
+ int rc;
- struct input_dev *input_dev;
- struct TWIKeypad *TWIKeypad;
+ client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ if (!client)
+ return -ENOMEM;
- i2c_add_driver (&pcf8574_kp_driver);
+ memset(client, 0, sizeof(struct i2c_client));
+ strncpy(client->name, PCF8574_KP_DRV_NAME, I2C_NAME_SIZE);
+ client->addr = addr;
+ client->adapter = adap;
+ client->driver = &pcf8574_kp_driver;
- TWIKeypad = kzalloc(sizeof(struct TWIKeypad), GFP_KERNEL);
+ rc = i2c_attach_client(client);
- input_dev = input_allocate_device();
- if (!input_dev)
- goto fail;
-
- if (request_irq
- (CONFIG_BFIN_TWIKEYPAD_IRQ_PFX, twi_keypad_irq_handler, IRQF_TRIGGER_LOW, "TWIKeypad",
- twi_keypad_irq_handler)) {
-
- printk (KERN_WARNING "TWIKeypad: IRQ %d is not free.\n", CONFIG_BFIN_TWIKEYPAD_IRQ_PFX);
- return -EIO;
+ if (rc != 0) {
+ kfree(client);
+ printk(KERN_WARNING"i2c_attach_client fail: %d\n", rc);
+ return rc;
}
-
- TWIKeypad->dev = input_dev;
- TWIKeypad->btncode = twi_keypad_btncode;
- input_dev->evbit[0] = 0;
+ pcf8574_kp_client = client;
- input_dev->evbit[0] |= BIT (EV_KEY);
- input_dev->keycode = TWIKeypad->btncode;
- input_dev->keycodesize = sizeof (twi_keypad_btncode);
- input_dev->keycodemax = ARRAY_SIZE (twi_keypad_btncode);
+ if (i2c_smbus_write_byte(pcf8574_kp_client, 240) < 0) {
+ printk(KERN_WARNING"in keypad probe: write fail\n");
+ return -1;
+ }
- for (i = 0; i <= BUTTONS; i++)
- {
- set_bit (TWIKeypad->btncode[i], input_dev->keybit);
- }
-
- sprintf (TWIKeypad->name, "BF5xx TWIKeypad");
- sprintf (TWIKeypad->phys, "twikeypad/input0");
+ return init_twikeypad(client);
+}
- input_dev->name = TWIKeypad->name;
- input_dev->phys = TWIKeypad->phys;
- input_dev->id.bustype = BUS_I2C;
- input_dev->id.vendor = 0x0001;
- input_dev->id.product = 0x0001;
- input_dev->id.version = 0x0100;
+static int pcf8574_kp_attach(struct i2c_adapter *adap)
+{
+ if (adap->algo->functionality)
+ return i2c_probe(adap, &addr_data, pcf8574_kp_probe);
+ else
+ return pcf8574_kp_probe(adap, 0x27, 0);
+}
- input_register_device (TWIKeypad->dev);
+static int pcf8574_kp_detach_client(struct i2c_client *client)
+{
+ struct twikeypad *lp = i2c_get_clientdata(client);
+ int rc;
- printk (KERN_INFO "input: %s at %s\n", TWIKeypad->name,
- TWIKeypad->phys);
+ free_irq(CONFIG_BFIN_TWIKEYPAD_IRQ_PFX, lp);
+ input_unregister_device(lp->idev);
+ kfree(lp);
- TWIKeypad->statechanged = 0x0;
+ rc = i2c_detach_client(client);
+ if (rc == 0)
+ kfree(i2c_get_clientdata(client));
+ return rc;
+}
- TWIKeypad->laststate = read_state (TWIKeypad);
- DPRINTK ("twikeypad: Keypad driver for bf5xx IRQ %d\n", IRQ_PROG_INTA);
+static struct i2c_driver pcf8574_kp_driver = {
+ .driver = {
+ .name = PCF8574_KP_DRV_NAME,
+ },
+ .id = 0x65,
+ .attach_adapter = pcf8574_kp_attach,
+ .detach_client = pcf8574_kp_detach_client,
+};
- /* Set up our workqueue. */
- INIT_WORK(&TWIKeypad->twi_keypad_work, check_and_notify);
- TWIKeypad->twi_keypad_workqueue = create_singlethread_workqueue("twi_keypad");
-
- return 0;
-
-fail:
- input_free_device(input_dev);
- i2c_del_driver (&pcf8574_kp_driver);
- kfree(TWIKeypad);
-
- return 0;
-
+static int __init twi_keypad_init(void)
+{
+ return i2c_add_driver(&pcf8574_kp_driver);
}
-void __exit
-twi_keypad_exit (void)
+void __exit twi_keypad_exit(void)
{
-
- free_irq (CONFIG_BFIN_TWIKEYPAD_IRQ_PFX, twi_keypad_irq_handler);
- i2c_del_driver (&pcf8574_kp_driver);
-
+ i2c_del_driver(&pcf8574_kp_driver);
}
-module_init (twi_keypad_init);
-module_exit (twi_keypad_exit);
+module_init(twi_keypad_init);
+module_exit(twi_keypad_exit);