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