pcf8574_keypad.c 4.6 KB

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