1 /* 2 * Atmel Atmegaxx Capacitive Touch Button Driver 3 * 4 * Copyright (C) 2016 Google, inc. 5 * 6 * This software is licensed under the terms of the GNU General Public 7 * License version 2, as published by the Free Software Foundation, and 8 * may be copied, distributed, and modified under those terms. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 */ 15 16 /* 17 * It's irrelevant that the HW used to develop captouch driver is based 18 * on Atmega88PA part and uses QtouchADC parts for sensing touch. 19 * Calling this driver "captouch" is an arbitrary way to distinguish 20 * the protocol this driver supported by other atmel/qtouch drivers. 21 * 22 * Captouch driver supports a newer/different version of the I2C 23 * registers/commands than the qt1070.c driver. 24 * Don't let the similarity of the general driver structure fool you. 25 * 26 * For raw i2c access from userspace, use i2cset/i2cget 27 * to poke at /dev/i2c-N devices. 28 */ 29 30 #include <linux/device.h> 31 #include <linux/kernel.h> 32 #include <linux/module.h> 33 #include <linux/init.h> 34 #include <linux/i2c.h> 35 #include <linux/input.h> 36 #include <linux/interrupt.h> 37 #include <linux/slab.h> 38 39 /* Maximum number of buttons supported */ 40 #define MAX_NUM_OF_BUTTONS 8 41 42 /* Registers */ 43 #define REG_KEY1_THRESHOLD 0x02 44 #define REG_KEY2_THRESHOLD 0x03 45 #define REG_KEY3_THRESHOLD 0x04 46 #define REG_KEY4_THRESHOLD 0x05 47 48 #define REG_KEY1_REF_H 0x20 49 #define REG_KEY1_REF_L 0x21 50 #define REG_KEY2_REF_H 0x22 51 #define REG_KEY2_REF_L 0x23 52 #define REG_KEY3_REF_H 0x24 53 #define REG_KEY3_REF_L 0x25 54 #define REG_KEY4_REF_H 0x26 55 #define REG_KEY4_REF_L 0x27 56 57 #define REG_KEY1_DLT_H 0x30 58 #define REG_KEY1_DLT_L 0x31 59 #define REG_KEY2_DLT_H 0x32 60 #define REG_KEY2_DLT_L 0x33 61 #define REG_KEY3_DLT_H 0x34 62 #define REG_KEY3_DLT_L 0x35 63 #define REG_KEY4_DLT_H 0x36 64 #define REG_KEY4_DLT_L 0x37 65 66 #define REG_KEY_STATE 0x3C 67 68 /* 69 * @i2c_client: I2C slave device client pointer 70 * @input: Input device pointer 71 * @num_btn: Number of buttons 72 * @keycodes: map of button# to KeyCode 73 * @prev_btn: Previous key state to detect button "press" or "release" 74 * @xfer_buf: I2C transfer buffer 75 */ 76 struct atmel_captouch_device { 77 struct i2c_client *client; 78 struct input_dev *input; 79 u32 num_btn; 80 u32 keycodes[MAX_NUM_OF_BUTTONS]; 81 u8 prev_btn; 82 u8 xfer_buf[8] ____cacheline_aligned; 83 }; 84 85 /* 86 * Read from I2C slave device 87 * The protocol is that the client has to provide both the register address 88 * and the length, and while reading back the device would prepend the data 89 * with address and length for verification. 90 */ 91 static int atmel_read(struct atmel_captouch_device *capdev, 92 u8 reg, u8 *data, size_t len) 93 { 94 struct i2c_client *client = capdev->client; 95 struct device *dev = &client->dev; 96 struct i2c_msg msg[2]; 97 int err; 98 99 if (len > sizeof(capdev->xfer_buf) - 2) 100 return -EINVAL; 101 102 capdev->xfer_buf[0] = reg; 103 capdev->xfer_buf[1] = len; 104 105 msg[0].addr = client->addr; 106 msg[0].flags = 0; 107 msg[0].buf = capdev->xfer_buf; 108 msg[0].len = 2; 109 110 msg[1].addr = client->addr; 111 msg[1].flags = I2C_M_RD; 112 msg[1].buf = capdev->xfer_buf; 113 msg[1].len = len + 2; 114 115 err = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); 116 if (err != ARRAY_SIZE(msg)) 117 return err < 0 ? err : -EIO; 118 119 if (capdev->xfer_buf[0] != reg) { 120 dev_err(dev, 121 "I2C read error: register address does not match (%#02x vs %02x)\n", 122 capdev->xfer_buf[0], reg); 123 return -ECOMM; 124 } 125 126 memcpy(data, &capdev->xfer_buf[2], len); 127 128 return 0; 129 } 130 131 /* 132 * Handle interrupt and report the key changes to the input system. 133 * Multi-touch can be supported; however, it really depends on whether 134 * the device can multi-touch. 135 */ 136 static irqreturn_t atmel_captouch_isr(int irq, void *data) 137 { 138 struct atmel_captouch_device *capdev = data; 139 struct device *dev = &capdev->client->dev; 140 int error; 141 int i; 142 u8 new_btn; 143 u8 changed_btn; 144 145 error = atmel_read(capdev, REG_KEY_STATE, &new_btn, 1); 146 if (error) { 147 dev_err(dev, "failed to read button state: %d\n", error); 148 goto out; 149 } 150 151 dev_dbg(dev, "%s: button state %#02x\n", __func__, new_btn); 152 153 changed_btn = new_btn ^ capdev->prev_btn; 154 capdev->prev_btn = new_btn; 155 156 for (i = 0; i < capdev->num_btn; i++) { 157 if (changed_btn & BIT(i)) 158 input_report_key(capdev->input, 159 capdev->keycodes[i], 160 new_btn & BIT(i)); 161 } 162 163 input_sync(capdev->input); 164 165 out: 166 return IRQ_HANDLED; 167 } 168 169 /* 170 * Probe function to setup the device, input system and interrupt 171 */ 172 static int atmel_captouch_probe(struct i2c_client *client, 173 const struct i2c_device_id *id) 174 { 175 struct atmel_captouch_device *capdev; 176 struct device *dev = &client->dev; 177 struct device_node *node; 178 int i; 179 int err; 180 181 if (!i2c_check_functionality(client->adapter, 182 I2C_FUNC_SMBUS_BYTE_DATA | 183 I2C_FUNC_SMBUS_WORD_DATA | 184 I2C_FUNC_SMBUS_I2C_BLOCK)) { 185 dev_err(dev, "needed i2c functionality is not supported\n"); 186 return -EINVAL; 187 } 188 189 capdev = devm_kzalloc(dev, sizeof(*capdev), GFP_KERNEL); 190 if (!capdev) 191 return -ENOMEM; 192 193 capdev->client = client; 194 i2c_set_clientdata(client, capdev); 195 196 err = atmel_read(capdev, REG_KEY_STATE, 197 &capdev->prev_btn, sizeof(capdev->prev_btn)); 198 if (err) { 199 dev_err(dev, "failed to read initial button state: %d\n", err); 200 return err; 201 } 202 203 capdev->input = devm_input_allocate_device(dev); 204 if (!capdev->input) { 205 dev_err(dev, "failed to allocate input device\n"); 206 return -ENOMEM; 207 } 208 209 capdev->input->id.bustype = BUS_I2C; 210 capdev->input->id.product = 0x880A; 211 capdev->input->id.version = 0; 212 capdev->input->name = "ATMegaXX Capacitive Button Controller"; 213 __set_bit(EV_KEY, capdev->input->evbit); 214 215 node = dev->of_node; 216 if (!node) { 217 dev_err(dev, "failed to find matching node in device tree\n"); 218 return -EINVAL; 219 } 220 221 if (of_property_read_bool(node, "autorepeat")) 222 __set_bit(EV_REP, capdev->input->evbit); 223 224 capdev->num_btn = of_property_count_u32_elems(node, "linux,keymap"); 225 if (capdev->num_btn > MAX_NUM_OF_BUTTONS) 226 capdev->num_btn = MAX_NUM_OF_BUTTONS; 227 228 err = of_property_read_u32_array(node, "linux,keycodes", 229 capdev->keycodes, 230 capdev->num_btn); 231 if (err) { 232 dev_err(dev, 233 "failed to read linux,keycode property: %d\n", err); 234 return err; 235 } 236 237 for (i = 0; i < capdev->num_btn; i++) 238 __set_bit(capdev->keycodes[i], capdev->input->keybit); 239 240 capdev->input->keycode = capdev->keycodes; 241 capdev->input->keycodesize = sizeof(capdev->keycodes[0]); 242 capdev->input->keycodemax = capdev->num_btn; 243 244 err = input_register_device(capdev->input); 245 if (err) 246 return err; 247 248 err = devm_request_threaded_irq(dev, client->irq, 249 NULL, atmel_captouch_isr, 250 IRQF_ONESHOT, 251 "atmel_captouch", capdev); 252 if (err) { 253 dev_err(dev, "failed to request irq %d: %d\n", 254 client->irq, err); 255 return err; 256 } 257 258 return 0; 259 } 260 261 #ifdef CONFIG_OF 262 static const struct of_device_id atmel_captouch_of_id[] = { 263 { 264 .compatible = "atmel,captouch", 265 }, 266 { /* sentinel */ } 267 }; 268 MODULE_DEVICE_TABLE(of, atmel_captouch_of_id); 269 #endif 270 271 static const struct i2c_device_id atmel_captouch_id[] = { 272 { "atmel_captouch", 0 }, 273 { } 274 }; 275 MODULE_DEVICE_TABLE(i2c, atmel_captouch_id); 276 277 static struct i2c_driver atmel_captouch_driver = { 278 .probe = atmel_captouch_probe, 279 .id_table = atmel_captouch_id, 280 .driver = { 281 .name = "atmel_captouch", 282 .of_match_table = of_match_ptr(atmel_captouch_of_id), 283 }, 284 }; 285 module_i2c_driver(atmel_captouch_driver); 286 287 /* Module information */ 288 MODULE_AUTHOR("Hung-yu Wu <hywu@google.com>"); 289 MODULE_DESCRIPTION("Atmel ATmegaXX Capacitance Touch Sensor I2C Driver"); 290 MODULE_LICENSE("GPL v2"); 291