1 /* 2 * TM2 touchkey device driver 3 * 4 * Copyright 2005 Phil Blundell 5 * Copyright 2016 Samsung Electronics Co., Ltd. 6 * 7 * Author: Beomho Seo <beomho.seo@samsung.com> 8 * Author: Jaechul Lee <jcsing.lee@samsung.com> 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License version 2 as 12 * published by the Free Software Foundation. 13 */ 14 15 #include <linux/bitops.h> 16 #include <linux/delay.h> 17 #include <linux/device.h> 18 #include <linux/i2c.h> 19 #include <linux/input.h> 20 #include <linux/interrupt.h> 21 #include <linux/irq.h> 22 #include <linux/leds.h> 23 #include <linux/module.h> 24 #include <linux/of.h> 25 #include <linux/pm.h> 26 #include <linux/regulator/consumer.h> 27 28 #define TM2_TOUCHKEY_DEV_NAME "tm2-touchkey" 29 #define TM2_TOUCHKEY_KEYCODE_REG 0x03 30 #define TM2_TOUCHKEY_BASE_REG 0x00 31 #define TM2_TOUCHKEY_CMD_LED_ON 0x10 32 #define TM2_TOUCHKEY_CMD_LED_OFF 0x20 33 #define TM2_TOUCHKEY_BIT_PRESS_EV BIT(3) 34 #define TM2_TOUCHKEY_BIT_KEYCODE GENMASK(2, 0) 35 #define TM2_TOUCHKEY_LED_VOLTAGE_MIN 2500000 36 #define TM2_TOUCHKEY_LED_VOLTAGE_MAX 3300000 37 38 enum { 39 TM2_TOUCHKEY_KEY_MENU = 0x1, 40 TM2_TOUCHKEY_KEY_BACK, 41 }; 42 43 struct tm2_touchkey_data { 44 struct i2c_client *client; 45 struct input_dev *input_dev; 46 struct led_classdev led_dev; 47 struct regulator *vdd; 48 struct regulator_bulk_data regulators[2]; 49 }; 50 51 static void tm2_touchkey_led_brightness_set(struct led_classdev *led_dev, 52 enum led_brightness brightness) 53 { 54 struct tm2_touchkey_data *touchkey = 55 container_of(led_dev, struct tm2_touchkey_data, led_dev); 56 u32 volt; 57 u8 data; 58 59 if (brightness == LED_OFF) { 60 volt = TM2_TOUCHKEY_LED_VOLTAGE_MIN; 61 data = TM2_TOUCHKEY_CMD_LED_OFF; 62 } else { 63 volt = TM2_TOUCHKEY_LED_VOLTAGE_MAX; 64 data = TM2_TOUCHKEY_CMD_LED_ON; 65 } 66 67 regulator_set_voltage(touchkey->vdd, volt, volt); 68 i2c_smbus_write_byte_data(touchkey->client, 69 TM2_TOUCHKEY_BASE_REG, data); 70 } 71 72 static int tm2_touchkey_power_enable(struct tm2_touchkey_data *touchkey) 73 { 74 int error; 75 76 error = regulator_bulk_enable(ARRAY_SIZE(touchkey->regulators), 77 touchkey->regulators); 78 if (error) 79 return error; 80 81 /* waiting for device initialization, at least 150ms */ 82 msleep(150); 83 84 return 0; 85 } 86 87 static void tm2_touchkey_power_disable(void *data) 88 { 89 struct tm2_touchkey_data *touchkey = data; 90 91 regulator_bulk_disable(ARRAY_SIZE(touchkey->regulators), 92 touchkey->regulators); 93 } 94 95 static irqreturn_t tm2_touchkey_irq_handler(int irq, void *devid) 96 { 97 struct tm2_touchkey_data *touchkey = devid; 98 int data; 99 int key; 100 101 data = i2c_smbus_read_byte_data(touchkey->client, 102 TM2_TOUCHKEY_KEYCODE_REG); 103 if (data < 0) { 104 dev_err(&touchkey->client->dev, 105 "failed to read i2c data: %d\n", data); 106 goto out; 107 } 108 109 switch (data & TM2_TOUCHKEY_BIT_KEYCODE) { 110 case TM2_TOUCHKEY_KEY_MENU: 111 key = KEY_PHONE; 112 break; 113 114 case TM2_TOUCHKEY_KEY_BACK: 115 key = KEY_BACK; 116 break; 117 118 default: 119 dev_warn(&touchkey->client->dev, 120 "unhandled keycode, data %#02x\n", data); 121 goto out; 122 } 123 124 if (data & TM2_TOUCHKEY_BIT_PRESS_EV) { 125 input_report_key(touchkey->input_dev, KEY_PHONE, 0); 126 input_report_key(touchkey->input_dev, KEY_BACK, 0); 127 } else { 128 input_report_key(touchkey->input_dev, key, 1); 129 } 130 131 input_sync(touchkey->input_dev); 132 133 out: 134 return IRQ_HANDLED; 135 } 136 137 static int tm2_touchkey_probe(struct i2c_client *client, 138 const struct i2c_device_id *id) 139 { 140 struct tm2_touchkey_data *touchkey; 141 int error; 142 143 if (!i2c_check_functionality(client->adapter, 144 I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA)) { 145 dev_err(&client->dev, "incompatible I2C adapter\n"); 146 return -EIO; 147 } 148 149 touchkey = devm_kzalloc(&client->dev, sizeof(*touchkey), GFP_KERNEL); 150 if (!touchkey) 151 return -ENOMEM; 152 153 touchkey->client = client; 154 i2c_set_clientdata(client, touchkey); 155 156 touchkey->regulators[0].supply = "vcc"; 157 touchkey->regulators[1].supply = "vdd"; 158 error = devm_regulator_bulk_get(&client->dev, 159 ARRAY_SIZE(touchkey->regulators), 160 touchkey->regulators); 161 if (error) { 162 dev_err(&client->dev, "failed to get regulators: %d\n", error); 163 return error; 164 } 165 166 /* Save VDD for easy access */ 167 touchkey->vdd = touchkey->regulators[1].consumer; 168 169 error = tm2_touchkey_power_enable(touchkey); 170 if (error) { 171 dev_err(&client->dev, "failed to power up device: %d\n", error); 172 return error; 173 } 174 175 error = devm_add_action_or_reset(&client->dev, 176 tm2_touchkey_power_disable, touchkey); 177 if (error) { 178 dev_err(&client->dev, 179 "failed to install poweroff handler: %d\n", error); 180 return error; 181 } 182 183 /* input device */ 184 touchkey->input_dev = devm_input_allocate_device(&client->dev); 185 if (!touchkey->input_dev) { 186 dev_err(&client->dev, "failed to allocate input device\n"); 187 return -ENOMEM; 188 } 189 190 touchkey->input_dev->name = TM2_TOUCHKEY_DEV_NAME; 191 touchkey->input_dev->id.bustype = BUS_I2C; 192 193 input_set_capability(touchkey->input_dev, EV_KEY, KEY_PHONE); 194 input_set_capability(touchkey->input_dev, EV_KEY, KEY_BACK); 195 196 error = input_register_device(touchkey->input_dev); 197 if (error) { 198 dev_err(&client->dev, 199 "failed to register input device: %d\n", error); 200 return error; 201 } 202 203 error = devm_request_threaded_irq(&client->dev, client->irq, 204 NULL, tm2_touchkey_irq_handler, 205 IRQF_ONESHOT, 206 TM2_TOUCHKEY_DEV_NAME, touchkey); 207 if (error) { 208 dev_err(&client->dev, 209 "failed to request threaded irq: %d\n", error); 210 return error; 211 } 212 213 /* led device */ 214 touchkey->led_dev.name = TM2_TOUCHKEY_DEV_NAME; 215 touchkey->led_dev.brightness = LED_FULL; 216 touchkey->led_dev.max_brightness = LED_FULL; 217 touchkey->led_dev.brightness_set = tm2_touchkey_led_brightness_set; 218 219 error = devm_led_classdev_register(&client->dev, &touchkey->led_dev); 220 if (error) { 221 dev_err(&client->dev, 222 "failed to register touchkey led: %d\n", error); 223 return error; 224 } 225 226 return 0; 227 } 228 229 static int __maybe_unused tm2_touchkey_suspend(struct device *dev) 230 { 231 struct i2c_client *client = to_i2c_client(dev); 232 struct tm2_touchkey_data *touchkey = i2c_get_clientdata(client); 233 234 disable_irq(client->irq); 235 tm2_touchkey_power_disable(touchkey); 236 237 return 0; 238 } 239 240 static int __maybe_unused tm2_touchkey_resume(struct device *dev) 241 { 242 struct i2c_client *client = to_i2c_client(dev); 243 struct tm2_touchkey_data *touchkey = i2c_get_clientdata(client); 244 int ret; 245 246 enable_irq(client->irq); 247 248 ret = tm2_touchkey_power_enable(touchkey); 249 if (ret) 250 dev_err(dev, "failed to enable power: %d\n", ret); 251 252 return ret; 253 } 254 255 static SIMPLE_DEV_PM_OPS(tm2_touchkey_pm_ops, 256 tm2_touchkey_suspend, tm2_touchkey_resume); 257 258 static const struct i2c_device_id tm2_touchkey_id_table[] = { 259 { TM2_TOUCHKEY_DEV_NAME, 0 }, 260 { }, 261 }; 262 MODULE_DEVICE_TABLE(i2c, tm2_touchkey_id_table); 263 264 static const struct of_device_id tm2_touchkey_of_match[] = { 265 { .compatible = "cypress,tm2-touchkey", }, 266 { }, 267 }; 268 MODULE_DEVICE_TABLE(of, tm2_touchkey_of_match); 269 270 static struct i2c_driver tm2_touchkey_driver = { 271 .driver = { 272 .name = TM2_TOUCHKEY_DEV_NAME, 273 .pm = &tm2_touchkey_pm_ops, 274 .of_match_table = of_match_ptr(tm2_touchkey_of_match), 275 }, 276 .probe = tm2_touchkey_probe, 277 .id_table = tm2_touchkey_id_table, 278 }; 279 module_i2c_driver(tm2_touchkey_driver); 280 281 MODULE_AUTHOR("Beomho Seo <beomho.seo@samsung.com>"); 282 MODULE_AUTHOR("Jaechul Lee <jcsing.lee@samsung.com>"); 283 MODULE_DESCRIPTION("Samsung touchkey driver"); 284 MODULE_LICENSE("GPL v2"); 285