linux/drivers/input/keyboard/mcs_touchkey.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Touchkey driver for MELFAS MCS5000/5080 controller
   4 *
   5 * Copyright (C) 2010 Samsung Electronics Co.Ltd
   6 * Author: HeungJun Kim <riverful.kim@samsung.com>
   7 * Author: Joonyoung Shim <jy0922.shim@samsung.com>
   8 */
   9
  10#include <linux/module.h>
  11#include <linux/i2c.h>
  12#include <linux/interrupt.h>
  13#include <linux/input.h>
  14#include <linux/irq.h>
  15#include <linux/slab.h>
  16#include <linux/platform_data/mcs.h>
  17#include <linux/pm.h>
  18
  19/* MCS5000 Touchkey */
  20#define MCS5000_TOUCHKEY_STATUS         0x04
  21#define MCS5000_TOUCHKEY_STATUS_PRESS   7
  22#define MCS5000_TOUCHKEY_FW             0x0a
  23#define MCS5000_TOUCHKEY_BASE_VAL       0x61
  24
  25/* MCS5080 Touchkey */
  26#define MCS5080_TOUCHKEY_STATUS         0x00
  27#define MCS5080_TOUCHKEY_STATUS_PRESS   3
  28#define MCS5080_TOUCHKEY_FW             0x01
  29#define MCS5080_TOUCHKEY_BASE_VAL       0x1
  30
  31enum mcs_touchkey_type {
  32        MCS5000_TOUCHKEY,
  33        MCS5080_TOUCHKEY,
  34};
  35
  36struct mcs_touchkey_chip {
  37        unsigned int status_reg;
  38        unsigned int pressbit;
  39        unsigned int press_invert;
  40        unsigned int baseval;
  41};
  42
  43struct mcs_touchkey_data {
  44        void (*poweron)(bool);
  45
  46        struct i2c_client *client;
  47        struct input_dev *input_dev;
  48        struct mcs_touchkey_chip chip;
  49        unsigned int key_code;
  50        unsigned int key_val;
  51        unsigned short keycodes[];
  52};
  53
  54static irqreturn_t mcs_touchkey_interrupt(int irq, void *dev_id)
  55{
  56        struct mcs_touchkey_data *data = dev_id;
  57        struct mcs_touchkey_chip *chip = &data->chip;
  58        struct i2c_client *client = data->client;
  59        struct input_dev *input = data->input_dev;
  60        unsigned int key_val;
  61        unsigned int pressed;
  62        int val;
  63
  64        val = i2c_smbus_read_byte_data(client, chip->status_reg);
  65        if (val < 0) {
  66                dev_err(&client->dev, "i2c read error [%d]\n", val);
  67                goto out;
  68        }
  69
  70        pressed = (val & (1 << chip->pressbit)) >> chip->pressbit;
  71        if (chip->press_invert)
  72                pressed ^= chip->press_invert;
  73
  74        /* key_val is 0 when released, so we should use key_val of press. */
  75        if (pressed) {
  76                key_val = val & (0xff >> (8 - chip->pressbit));
  77                if (!key_val)
  78                        goto out;
  79                key_val -= chip->baseval;
  80                data->key_code = data->keycodes[key_val];
  81                data->key_val = key_val;
  82        }
  83
  84        input_event(input, EV_MSC, MSC_SCAN, data->key_val);
  85        input_report_key(input, data->key_code, pressed);
  86        input_sync(input);
  87
  88        dev_dbg(&client->dev, "key %d %d %s\n", data->key_val, data->key_code,
  89                pressed ? "pressed" : "released");
  90
  91 out:
  92        return IRQ_HANDLED;
  93}
  94
  95static int mcs_touchkey_probe(struct i2c_client *client,
  96                const struct i2c_device_id *id)
  97{
  98        const struct mcs_platform_data *pdata;
  99        struct mcs_touchkey_data *data;
 100        struct input_dev *input_dev;
 101        unsigned int fw_reg;
 102        int fw_ver;
 103        int error;
 104        int i;
 105
 106        pdata = dev_get_platdata(&client->dev);
 107        if (!pdata) {
 108                dev_err(&client->dev, "no platform data defined\n");
 109                return -EINVAL;
 110        }
 111
 112        data = kzalloc(struct_size(data, keycodes, pdata->key_maxval + 1),
 113                       GFP_KERNEL);
 114        input_dev = input_allocate_device();
 115        if (!data || !input_dev) {
 116                dev_err(&client->dev, "Failed to allocate memory\n");
 117                error = -ENOMEM;
 118                goto err_free_mem;
 119        }
 120
 121        data->client = client;
 122        data->input_dev = input_dev;
 123
 124        if (id->driver_data == MCS5000_TOUCHKEY) {
 125                data->chip.status_reg = MCS5000_TOUCHKEY_STATUS;
 126                data->chip.pressbit = MCS5000_TOUCHKEY_STATUS_PRESS;
 127                data->chip.baseval = MCS5000_TOUCHKEY_BASE_VAL;
 128                fw_reg = MCS5000_TOUCHKEY_FW;
 129        } else {
 130                data->chip.status_reg = MCS5080_TOUCHKEY_STATUS;
 131                data->chip.pressbit = MCS5080_TOUCHKEY_STATUS_PRESS;
 132                data->chip.press_invert = 1;
 133                data->chip.baseval = MCS5080_TOUCHKEY_BASE_VAL;
 134                fw_reg = MCS5080_TOUCHKEY_FW;
 135        }
 136
 137        fw_ver = i2c_smbus_read_byte_data(client, fw_reg);
 138        if (fw_ver < 0) {
 139                error = fw_ver;
 140                dev_err(&client->dev, "i2c read error[%d]\n", error);
 141                goto err_free_mem;
 142        }
 143        dev_info(&client->dev, "Firmware version: %d\n", fw_ver);
 144
 145        input_dev->name = "MELFAS MCS Touchkey";
 146        input_dev->id.bustype = BUS_I2C;
 147        input_dev->dev.parent = &client->dev;
 148        input_dev->evbit[0] = BIT_MASK(EV_KEY);
 149        if (!pdata->no_autorepeat)
 150                input_dev->evbit[0] |= BIT_MASK(EV_REP);
 151        input_dev->keycode = data->keycodes;
 152        input_dev->keycodesize = sizeof(data->keycodes[0]);
 153        input_dev->keycodemax = pdata->key_maxval + 1;
 154
 155        for (i = 0; i < pdata->keymap_size; i++) {
 156                unsigned int val = MCS_KEY_VAL(pdata->keymap[i]);
 157                unsigned int code = MCS_KEY_CODE(pdata->keymap[i]);
 158
 159                data->keycodes[val] = code;
 160                __set_bit(code, input_dev->keybit);
 161        }
 162
 163        input_set_capability(input_dev, EV_MSC, MSC_SCAN);
 164        input_set_drvdata(input_dev, data);
 165
 166        if (pdata->cfg_pin)
 167                pdata->cfg_pin();
 168
 169        if (pdata->poweron) {
 170                data->poweron = pdata->poweron;
 171                data->poweron(true);
 172        }
 173
 174        error = request_threaded_irq(client->irq, NULL, mcs_touchkey_interrupt,
 175                                     IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
 176                                     client->dev.driver->name, data);
 177        if (error) {
 178                dev_err(&client->dev, "Failed to register interrupt\n");
 179                goto err_free_mem;
 180        }
 181
 182        error = input_register_device(input_dev);
 183        if (error)
 184                goto err_free_irq;
 185
 186        i2c_set_clientdata(client, data);
 187        return 0;
 188
 189err_free_irq:
 190        free_irq(client->irq, data);
 191err_free_mem:
 192        input_free_device(input_dev);
 193        kfree(data);
 194        return error;
 195}
 196
 197static int mcs_touchkey_remove(struct i2c_client *client)
 198{
 199        struct mcs_touchkey_data *data = i2c_get_clientdata(client);
 200
 201        free_irq(client->irq, data);
 202        if (data->poweron)
 203                data->poweron(false);
 204        input_unregister_device(data->input_dev);
 205        kfree(data);
 206
 207        return 0;
 208}
 209
 210static void mcs_touchkey_shutdown(struct i2c_client *client)
 211{
 212        struct mcs_touchkey_data *data = i2c_get_clientdata(client);
 213
 214        if (data->poweron)
 215                data->poweron(false);
 216}
 217
 218#ifdef CONFIG_PM_SLEEP
 219static int mcs_touchkey_suspend(struct device *dev)
 220{
 221        struct mcs_touchkey_data *data = dev_get_drvdata(dev);
 222        struct i2c_client *client = data->client;
 223
 224        /* Disable the work */
 225        disable_irq(client->irq);
 226
 227        /* Finally turn off the power */
 228        if (data->poweron)
 229                data->poweron(false);
 230
 231        return 0;
 232}
 233
 234static int mcs_touchkey_resume(struct device *dev)
 235{
 236        struct mcs_touchkey_data *data = dev_get_drvdata(dev);
 237        struct i2c_client *client = data->client;
 238
 239        /* Enable the device first */
 240        if (data->poweron)
 241                data->poweron(true);
 242
 243        /* Enable irq again */
 244        enable_irq(client->irq);
 245
 246        return 0;
 247}
 248#endif
 249
 250static SIMPLE_DEV_PM_OPS(mcs_touchkey_pm_ops,
 251                         mcs_touchkey_suspend, mcs_touchkey_resume);
 252
 253static const struct i2c_device_id mcs_touchkey_id[] = {
 254        { "mcs5000_touchkey", MCS5000_TOUCHKEY },
 255        { "mcs5080_touchkey", MCS5080_TOUCHKEY },
 256        { }
 257};
 258MODULE_DEVICE_TABLE(i2c, mcs_touchkey_id);
 259
 260static struct i2c_driver mcs_touchkey_driver = {
 261        .driver = {
 262                .name   = "mcs_touchkey",
 263                .pm     = &mcs_touchkey_pm_ops,
 264        },
 265        .probe          = mcs_touchkey_probe,
 266        .remove         = mcs_touchkey_remove,
 267        .shutdown       = mcs_touchkey_shutdown,
 268        .id_table       = mcs_touchkey_id,
 269};
 270
 271module_i2c_driver(mcs_touchkey_driver);
 272
 273/* Module information */
 274MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
 275MODULE_AUTHOR("HeungJun Kim <riverful.kim@samsung.com>");
 276MODULE_DESCRIPTION("Touchkey driver for MELFAS MCS5000/5080 controller");
 277MODULE_LICENSE("GPL");
 278