1b91c4be7SBryan Wu /* 2b91c4be7SBryan Wu * Driver for a keypad w/16 buttons connected to a PCF8574 I2C I/O expander 3b91c4be7SBryan Wu * 4b91c4be7SBryan Wu * Copyright 2005-2008 Analog Devices Inc. 5b91c4be7SBryan Wu * 6b91c4be7SBryan Wu * Licensed under the GPL-2 or later. 7b91c4be7SBryan Wu */ 8b91c4be7SBryan Wu 9b91c4be7SBryan Wu #include <linux/module.h> 10b91c4be7SBryan Wu #include <linux/init.h> 11b91c4be7SBryan Wu #include <linux/input.h> 12b91c4be7SBryan Wu #include <linux/interrupt.h> 13b91c4be7SBryan Wu #include <linux/i2c.h> 14b91c4be7SBryan Wu #include <linux/slab.h> 15b91c4be7SBryan Wu #include <linux/workqueue.h> 16b91c4be7SBryan Wu 17b91c4be7SBryan Wu #define DRV_NAME "pcf8574_keypad" 18b91c4be7SBryan Wu 19b91c4be7SBryan Wu static const unsigned char pcf8574_kp_btncode[] = { 20b91c4be7SBryan Wu [0] = KEY_RESERVED, 21b91c4be7SBryan Wu [1] = KEY_ENTER, 22b91c4be7SBryan Wu [2] = KEY_BACKSLASH, 23b91c4be7SBryan Wu [3] = KEY_0, 24b91c4be7SBryan Wu [4] = KEY_RIGHTBRACE, 25b91c4be7SBryan Wu [5] = KEY_C, 26b91c4be7SBryan Wu [6] = KEY_9, 27b91c4be7SBryan Wu [7] = KEY_8, 28b91c4be7SBryan Wu [8] = KEY_7, 29b91c4be7SBryan Wu [9] = KEY_B, 30b91c4be7SBryan Wu [10] = KEY_6, 31b91c4be7SBryan Wu [11] = KEY_5, 32b91c4be7SBryan Wu [12] = KEY_4, 33b91c4be7SBryan Wu [13] = KEY_A, 34b91c4be7SBryan Wu [14] = KEY_3, 35b91c4be7SBryan Wu [15] = KEY_2, 36b91c4be7SBryan Wu [16] = KEY_1 37b91c4be7SBryan Wu }; 38b91c4be7SBryan Wu 39b91c4be7SBryan Wu struct kp_data { 40b91c4be7SBryan Wu unsigned short btncode[ARRAY_SIZE(pcf8574_kp_btncode)]; 41b91c4be7SBryan Wu struct input_dev *idev; 42b91c4be7SBryan Wu struct i2c_client *client; 43b91c4be7SBryan Wu char name[64]; 44b91c4be7SBryan Wu char phys[32]; 45b91c4be7SBryan Wu unsigned char laststate; 46b91c4be7SBryan Wu }; 47b91c4be7SBryan Wu 48b91c4be7SBryan Wu static short read_state(struct kp_data *lp) 49b91c4be7SBryan Wu { 50b91c4be7SBryan Wu unsigned char x, y, a, b; 51b91c4be7SBryan Wu 52b91c4be7SBryan Wu i2c_smbus_write_byte(lp->client, 240); 53b91c4be7SBryan Wu x = 0xF & (~(i2c_smbus_read_byte(lp->client) >> 4)); 54b91c4be7SBryan Wu 55b91c4be7SBryan Wu i2c_smbus_write_byte(lp->client, 15); 56b91c4be7SBryan Wu y = 0xF & (~i2c_smbus_read_byte(lp->client)); 57b91c4be7SBryan Wu 58b91c4be7SBryan Wu for (a = 0; x > 0; a++) 59b91c4be7SBryan Wu x = x >> 1; 60b91c4be7SBryan Wu for (b = 0; y > 0; b++) 61b91c4be7SBryan Wu y = y >> 1; 62b91c4be7SBryan Wu 63b91c4be7SBryan Wu return ((a - 1) * 4) + b; 64b91c4be7SBryan Wu } 65b91c4be7SBryan Wu 66b91c4be7SBryan Wu static irqreturn_t pcf8574_kp_irq_handler(int irq, void *dev_id) 67b91c4be7SBryan Wu { 68b91c4be7SBryan Wu struct kp_data *lp = dev_id; 69b91c4be7SBryan Wu unsigned char nextstate = read_state(lp); 70b91c4be7SBryan Wu 71b91c4be7SBryan Wu if (lp->laststate != nextstate) { 72*0b75f775SDan Carpenter int key_down = nextstate < ARRAY_SIZE(lp->btncode); 73b91c4be7SBryan Wu unsigned short keycode = key_down ? 74b91c4be7SBryan Wu lp->btncode[nextstate] : lp->btncode[lp->laststate]; 75b91c4be7SBryan Wu 76b91c4be7SBryan Wu input_report_key(lp->idev, keycode, key_down); 77b91c4be7SBryan Wu input_sync(lp->idev); 78b91c4be7SBryan Wu 79b91c4be7SBryan Wu lp->laststate = nextstate; 80b91c4be7SBryan Wu } 81b91c4be7SBryan Wu 82b91c4be7SBryan Wu return IRQ_HANDLED; 83b91c4be7SBryan Wu } 84b91c4be7SBryan Wu 85b91c4be7SBryan Wu static int __devinit pcf8574_kp_probe(struct i2c_client *client, const struct i2c_device_id *id) 86b91c4be7SBryan Wu { 87b91c4be7SBryan Wu int i, ret; 88b91c4be7SBryan Wu struct input_dev *idev; 89b91c4be7SBryan Wu struct kp_data *lp; 90b91c4be7SBryan Wu 91b91c4be7SBryan Wu if (i2c_smbus_write_byte(client, 240) < 0) { 92b91c4be7SBryan Wu dev_err(&client->dev, "probe: write fail\n"); 93b91c4be7SBryan Wu return -ENODEV; 94b91c4be7SBryan Wu } 95b91c4be7SBryan Wu 96b91c4be7SBryan Wu lp = kzalloc(sizeof(*lp), GFP_KERNEL); 97b91c4be7SBryan Wu if (!lp) 98b91c4be7SBryan Wu return -ENOMEM; 99b91c4be7SBryan Wu 100b91c4be7SBryan Wu idev = input_allocate_device(); 101b91c4be7SBryan Wu if (!idev) { 102b91c4be7SBryan Wu dev_err(&client->dev, "Can't allocate input device\n"); 103b91c4be7SBryan Wu ret = -ENOMEM; 104b91c4be7SBryan Wu goto fail_allocate; 105b91c4be7SBryan Wu } 106b91c4be7SBryan Wu 107b91c4be7SBryan Wu lp->idev = idev; 108b91c4be7SBryan Wu lp->client = client; 109b91c4be7SBryan Wu 110b91c4be7SBryan Wu idev->evbit[0] = BIT_MASK(EV_KEY); 111b91c4be7SBryan Wu idev->keycode = lp->btncode; 112b91c4be7SBryan Wu idev->keycodesize = sizeof(lp->btncode[0]); 113b91c4be7SBryan Wu idev->keycodemax = ARRAY_SIZE(lp->btncode); 114b91c4be7SBryan Wu 115b91c4be7SBryan Wu for (i = 0; i < ARRAY_SIZE(pcf8574_kp_btncode); i++) { 116b91c4be7SBryan Wu lp->btncode[i] = pcf8574_kp_btncode[i]; 117b91c4be7SBryan Wu __set_bit(lp->btncode[i] & KEY_MAX, idev->keybit); 118b91c4be7SBryan Wu } 119b91c4be7SBryan Wu 120b91c4be7SBryan Wu sprintf(lp->name, DRV_NAME); 121b91c4be7SBryan Wu sprintf(lp->phys, "kp_data/input0"); 122b91c4be7SBryan Wu 123b91c4be7SBryan Wu idev->name = lp->name; 124b91c4be7SBryan Wu idev->phys = lp->phys; 125b91c4be7SBryan Wu idev->id.bustype = BUS_I2C; 126b91c4be7SBryan Wu idev->id.vendor = 0x0001; 127b91c4be7SBryan Wu idev->id.product = 0x0001; 128b91c4be7SBryan Wu idev->id.version = 0x0100; 129b91c4be7SBryan Wu 130b91c4be7SBryan Wu input_set_drvdata(idev, lp); 131b91c4be7SBryan Wu 132b91c4be7SBryan Wu ret = input_register_device(idev); 133b91c4be7SBryan Wu if (ret) { 134b91c4be7SBryan Wu dev_err(&client->dev, "input_register_device() failed\n"); 135b91c4be7SBryan Wu goto fail_register; 136b91c4be7SBryan Wu } 137b91c4be7SBryan Wu 138b91c4be7SBryan Wu lp->laststate = read_state(lp); 139b91c4be7SBryan Wu 140b91c4be7SBryan Wu ret = request_threaded_irq(client->irq, NULL, pcf8574_kp_irq_handler, 141b91c4be7SBryan Wu IRQF_TRIGGER_LOW | IRQF_ONESHOT, 142b91c4be7SBryan Wu DRV_NAME, lp); 143b91c4be7SBryan Wu if (ret) { 144b91c4be7SBryan Wu dev_err(&client->dev, "IRQ %d is not free\n", client->irq); 145b91c4be7SBryan Wu goto fail_irq; 146b91c4be7SBryan Wu } 147b91c4be7SBryan Wu 148b91c4be7SBryan Wu i2c_set_clientdata(client, lp); 149b91c4be7SBryan Wu return 0; 150b91c4be7SBryan Wu 151b91c4be7SBryan Wu fail_irq: 152b91c4be7SBryan Wu input_unregister_device(idev); 153b91c4be7SBryan Wu fail_register: 154b91c4be7SBryan Wu input_set_drvdata(idev, NULL); 155b91c4be7SBryan Wu input_free_device(idev); 156b91c4be7SBryan Wu fail_allocate: 157b91c4be7SBryan Wu kfree(lp); 158b91c4be7SBryan Wu 159b91c4be7SBryan Wu return ret; 160b91c4be7SBryan Wu } 161b91c4be7SBryan Wu 162b91c4be7SBryan Wu static int __devexit pcf8574_kp_remove(struct i2c_client *client) 163b91c4be7SBryan Wu { 164b91c4be7SBryan Wu struct kp_data *lp = i2c_get_clientdata(client); 165b91c4be7SBryan Wu 166b91c4be7SBryan Wu free_irq(client->irq, lp); 167b91c4be7SBryan Wu 168b91c4be7SBryan Wu input_unregister_device(lp->idev); 169b91c4be7SBryan Wu kfree(lp); 170b91c4be7SBryan Wu 171b91c4be7SBryan Wu i2c_set_clientdata(client, NULL); 172b91c4be7SBryan Wu 173b91c4be7SBryan Wu return 0; 174b91c4be7SBryan Wu } 175b91c4be7SBryan Wu 176b91c4be7SBryan Wu #ifdef CONFIG_PM 177b91c4be7SBryan Wu static int pcf8574_kp_resume(struct i2c_client *client) 178b91c4be7SBryan Wu { 179b91c4be7SBryan Wu enable_irq(client->irq); 180b91c4be7SBryan Wu 181b91c4be7SBryan Wu return 0; 182b91c4be7SBryan Wu } 183b91c4be7SBryan Wu 184b91c4be7SBryan Wu static int pcf8574_kp_suspend(struct i2c_client *client, pm_message_t mesg) 185b91c4be7SBryan Wu { 186b91c4be7SBryan Wu disable_irq(client->irq); 187b91c4be7SBryan Wu 188b91c4be7SBryan Wu return 0; 189b91c4be7SBryan Wu } 190b91c4be7SBryan Wu #else 191b91c4be7SBryan Wu # define pcf8574_kp_resume NULL 192b91c4be7SBryan Wu # define pcf8574_kp_suspend NULL 193b91c4be7SBryan Wu #endif 194b91c4be7SBryan Wu 195b91c4be7SBryan Wu static const struct i2c_device_id pcf8574_kp_id[] = { 196b91c4be7SBryan Wu { DRV_NAME, 0 }, 197b91c4be7SBryan Wu { } 198b91c4be7SBryan Wu }; 199b91c4be7SBryan Wu MODULE_DEVICE_TABLE(i2c, pcf8574_kp_id); 200b91c4be7SBryan Wu 201b91c4be7SBryan Wu static struct i2c_driver pcf8574_kp_driver = { 202b91c4be7SBryan Wu .driver = { 203b91c4be7SBryan Wu .name = DRV_NAME, 204b91c4be7SBryan Wu .owner = THIS_MODULE, 205b91c4be7SBryan Wu }, 206b91c4be7SBryan Wu .probe = pcf8574_kp_probe, 207b91c4be7SBryan Wu .remove = __devexit_p(pcf8574_kp_remove), 208b91c4be7SBryan Wu .suspend = pcf8574_kp_suspend, 209b91c4be7SBryan Wu .resume = pcf8574_kp_resume, 210b91c4be7SBryan Wu .id_table = pcf8574_kp_id, 211b91c4be7SBryan Wu }; 212b91c4be7SBryan Wu 213b91c4be7SBryan Wu static int __init pcf8574_kp_init(void) 214b91c4be7SBryan Wu { 215b91c4be7SBryan Wu return i2c_add_driver(&pcf8574_kp_driver); 216b91c4be7SBryan Wu } 217b91c4be7SBryan Wu module_init(pcf8574_kp_init); 218b91c4be7SBryan Wu 219b91c4be7SBryan Wu static void __exit pcf8574_kp_exit(void) 220b91c4be7SBryan Wu { 221b91c4be7SBryan Wu i2c_del_driver(&pcf8574_kp_driver); 222b91c4be7SBryan Wu } 223b91c4be7SBryan Wu module_exit(pcf8574_kp_exit); 224b91c4be7SBryan Wu 225b91c4be7SBryan Wu MODULE_AUTHOR("Michael Hennerich"); 226b91c4be7SBryan Wu MODULE_DESCRIPTION("Keypad input driver for 16 keys connected to PCF8574"); 227b91c4be7SBryan Wu MODULE_LICENSE("GPL"); 228