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