mcs_touchkey.c (6935B)
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");