linux/drivers/input/misc/atmel_captouch.c
<<
>>
Prefs
   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 */
  76struct 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 */
  91static 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 */
 136static 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
 165out:
 166        return IRQ_HANDLED;
 167}
 168
 169/*
 170 * Probe function to setup the device, input system and interrupt
 171 */
 172static 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
 195        err = atmel_read(capdev, REG_KEY_STATE,
 196                            &capdev->prev_btn, sizeof(capdev->prev_btn));
 197        if (err) {
 198                dev_err(dev, "failed to read initial button state: %d\n", err);
 199                return err;
 200        }
 201
 202        capdev->input = devm_input_allocate_device(dev);
 203        if (!capdev->input) {
 204                dev_err(dev, "failed to allocate input device\n");
 205                return -ENOMEM;
 206        }
 207
 208        capdev->input->id.bustype = BUS_I2C;
 209        capdev->input->id.product = 0x880A;
 210        capdev->input->id.version = 0;
 211        capdev->input->name = "ATMegaXX Capacitive Button Controller";
 212        __set_bit(EV_KEY, capdev->input->evbit);
 213
 214        node = dev->of_node;
 215        if (!node) {
 216                dev_err(dev, "failed to find matching node in device tree\n");
 217                return -EINVAL;
 218        }
 219
 220        if (of_property_read_bool(node, "autorepeat"))
 221                __set_bit(EV_REP, capdev->input->evbit);
 222
 223        capdev->num_btn = of_property_count_u32_elems(node, "linux,keymap");
 224        if (capdev->num_btn > MAX_NUM_OF_BUTTONS)
 225                capdev->num_btn = MAX_NUM_OF_BUTTONS;
 226
 227        err = of_property_read_u32_array(node, "linux,keycodes",
 228                                         capdev->keycodes,
 229                                         capdev->num_btn);
 230        if (err) {
 231                dev_err(dev,
 232                        "failed to read linux,keycode property: %d\n", err);
 233                return err;
 234        }
 235
 236        for (i = 0; i < capdev->num_btn; i++)
 237                __set_bit(capdev->keycodes[i], capdev->input->keybit);
 238
 239        capdev->input->keycode = capdev->keycodes;
 240        capdev->input->keycodesize = sizeof(capdev->keycodes[0]);
 241        capdev->input->keycodemax = capdev->num_btn;
 242
 243        err = input_register_device(capdev->input);
 244        if (err)
 245                return err;
 246
 247        err = devm_request_threaded_irq(dev, client->irq,
 248                                        NULL, atmel_captouch_isr,
 249                                        IRQF_ONESHOT,
 250                                        "atmel_captouch", capdev);
 251        if (err) {
 252                dev_err(dev, "failed to request irq %d: %d\n",
 253                        client->irq, err);
 254                return err;
 255        }
 256
 257        return 0;
 258}
 259
 260#ifdef CONFIG_OF
 261static const struct of_device_id atmel_captouch_of_id[] = {
 262        {
 263                .compatible = "atmel,captouch",
 264        },
 265        { /* sentinel */ }
 266};
 267MODULE_DEVICE_TABLE(of, atmel_captouch_of_id);
 268#endif
 269
 270static const struct i2c_device_id atmel_captouch_id[] = {
 271        { "atmel_captouch", 0 },
 272        { }
 273};
 274MODULE_DEVICE_TABLE(i2c, atmel_captouch_id);
 275
 276static struct i2c_driver atmel_captouch_driver = {
 277        .probe          = atmel_captouch_probe,
 278        .id_table       = atmel_captouch_id,
 279        .driver         = {
 280                .name   = "atmel_captouch",
 281                .of_match_table = of_match_ptr(atmel_captouch_of_id),
 282        },
 283};
 284module_i2c_driver(atmel_captouch_driver);
 285
 286/* Module information */
 287MODULE_AUTHOR("Hung-yu Wu <hywu@google.com>");
 288MODULE_DESCRIPTION("Atmel ATmegaXX Capacitance Touch Sensor I2C Driver");
 289MODULE_LICENSE("GPL v2");
 290