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/of_device.h> 26 #include <linux/pm.h> 27 #include <linux/regulator/consumer.h> 28 29 #define TM2_TOUCHKEY_DEV_NAME "tm2-touchkey" 30 31 #define ARIES_TOUCHKEY_CMD_LED_ON 0x1 32 #define ARIES_TOUCHKEY_CMD_LED_OFF 0x2 33 #define TM2_TOUCHKEY_CMD_LED_ON 0x10 34 #define TM2_TOUCHKEY_CMD_LED_OFF 0x20 35 #define TM2_TOUCHKEY_BIT_PRESS_EV BIT(3) 36 #define TM2_TOUCHKEY_BIT_KEYCODE GENMASK(2, 0) 37 #define TM2_TOUCHKEY_LED_VOLTAGE_MIN 2500000 38 #define TM2_TOUCHKEY_LED_VOLTAGE_MAX 3300000 39 40 struct touchkey_variant { 41 u8 keycode_reg; 42 u8 base_reg; 43 u8 cmd_led_on; 44 u8 cmd_led_off; 45 bool no_reg; 46 bool fixed_regulator; 47 }; 48 49 struct tm2_touchkey_data { 50 struct i2c_client *client; 51 struct input_dev *input_dev; 52 struct led_classdev led_dev; 53 struct regulator *vdd; 54 struct regulator_bulk_data regulators[2]; 55 const struct touchkey_variant *variant; 56 u32 keycodes[4]; 57 int num_keycodes; 58 }; 59 60 static const struct touchkey_variant tm2_touchkey_variant = { 61 .keycode_reg = 0x03, 62 .base_reg = 0x00, 63 .cmd_led_on = TM2_TOUCHKEY_CMD_LED_ON, 64 .cmd_led_off = TM2_TOUCHKEY_CMD_LED_OFF, 65 }; 66 67 static const struct touchkey_variant midas_touchkey_variant = { 68 .keycode_reg = 0x00, 69 .base_reg = 0x00, 70 .cmd_led_on = TM2_TOUCHKEY_CMD_LED_ON, 71 .cmd_led_off = TM2_TOUCHKEY_CMD_LED_OFF, 72 }; 73 74 static struct touchkey_variant aries_touchkey_variant = { 75 .no_reg = true, 76 .fixed_regulator = true, 77 .cmd_led_on = ARIES_TOUCHKEY_CMD_LED_ON, 78 .cmd_led_off = ARIES_TOUCHKEY_CMD_LED_OFF, 79 }; 80 81 static int tm2_touchkey_led_brightness_set(struct led_classdev *led_dev, 82 enum led_brightness brightness) 83 { 84 struct tm2_touchkey_data *touchkey = 85 container_of(led_dev, struct tm2_touchkey_data, led_dev); 86 u32 volt; 87 u8 data; 88 89 if (brightness == LED_OFF) { 90 volt = TM2_TOUCHKEY_LED_VOLTAGE_MIN; 91 data = touchkey->variant->cmd_led_off; 92 } else { 93 volt = TM2_TOUCHKEY_LED_VOLTAGE_MAX; 94 data = touchkey->variant->cmd_led_on; 95 } 96 97 if (!touchkey->variant->fixed_regulator) 98 regulator_set_voltage(touchkey->vdd, volt, volt); 99 100 return touchkey->variant->no_reg ? 101 i2c_smbus_write_byte(touchkey->client, data) : 102 i2c_smbus_write_byte_data(touchkey->client, 103 touchkey->variant->base_reg, data); 104 } 105 106 static int tm2_touchkey_power_enable(struct tm2_touchkey_data *touchkey) 107 { 108 int error; 109 110 error = regulator_bulk_enable(ARRAY_SIZE(touchkey->regulators), 111 touchkey->regulators); 112 if (error) 113 return error; 114 115 /* waiting for device initialization, at least 150ms */ 116 msleep(150); 117 118 return 0; 119 } 120 121 static void tm2_touchkey_power_disable(void *data) 122 { 123 struct tm2_touchkey_data *touchkey = data; 124 125 regulator_bulk_disable(ARRAY_SIZE(touchkey->regulators), 126 touchkey->regulators); 127 } 128 129 static irqreturn_t tm2_touchkey_irq_handler(int irq, void *devid) 130 { 131 struct tm2_touchkey_data *touchkey = devid; 132 int data; 133 int index; 134 int i; 135 136 if (touchkey->variant->no_reg) 137 data = i2c_smbus_read_byte(touchkey->client); 138 else 139 data = i2c_smbus_read_byte_data(touchkey->client, 140 touchkey->variant->keycode_reg); 141 if (data < 0) { 142 dev_err(&touchkey->client->dev, 143 "failed to read i2c data: %d\n", data); 144 goto out; 145 } 146 147 index = (data & TM2_TOUCHKEY_BIT_KEYCODE) - 1; 148 if (index < 0 || index >= touchkey->num_keycodes) { 149 dev_warn(&touchkey->client->dev, 150 "invalid keycode index %d\n", index); 151 goto out; 152 } 153 154 if (data & TM2_TOUCHKEY_BIT_PRESS_EV) { 155 for (i = 0; i < touchkey->num_keycodes; i++) 156 input_report_key(touchkey->input_dev, 157 touchkey->keycodes[i], 0); 158 } else { 159 input_report_key(touchkey->input_dev, 160 touchkey->keycodes[index], 1); 161 } 162 163 input_sync(touchkey->input_dev); 164 165 out: 166 if (touchkey->variant->fixed_regulator && 167 data & TM2_TOUCHKEY_BIT_PRESS_EV) { 168 /* touch turns backlight on, so make sure we're in sync */ 169 if (touchkey->led_dev.brightness == LED_OFF) 170 tm2_touchkey_led_brightness_set(&touchkey->led_dev, 171 LED_OFF); 172 } 173 174 return IRQ_HANDLED; 175 } 176 177 static int tm2_touchkey_probe(struct i2c_client *client, 178 const struct i2c_device_id *id) 179 { 180 struct device_node *np = client->dev.of_node; 181 struct tm2_touchkey_data *touchkey; 182 int error; 183 int i; 184 185 if (!i2c_check_functionality(client->adapter, 186 I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA)) { 187 dev_err(&client->dev, "incompatible I2C adapter\n"); 188 return -EIO; 189 } 190 191 touchkey = devm_kzalloc(&client->dev, sizeof(*touchkey), GFP_KERNEL); 192 if (!touchkey) 193 return -ENOMEM; 194 195 touchkey->client = client; 196 i2c_set_clientdata(client, touchkey); 197 198 touchkey->variant = of_device_get_match_data(&client->dev); 199 200 touchkey->regulators[0].supply = "vcc"; 201 touchkey->regulators[1].supply = "vdd"; 202 error = devm_regulator_bulk_get(&client->dev, 203 ARRAY_SIZE(touchkey->regulators), 204 touchkey->regulators); 205 if (error) { 206 dev_err(&client->dev, "failed to get regulators: %d\n", error); 207 return error; 208 } 209 210 /* Save VDD for easy access */ 211 touchkey->vdd = touchkey->regulators[1].consumer; 212 213 touchkey->num_keycodes = of_property_read_variable_u32_array(np, 214 "linux,keycodes", touchkey->keycodes, 0, 215 ARRAY_SIZE(touchkey->keycodes)); 216 if (touchkey->num_keycodes <= 0) { 217 /* default keycodes */ 218 touchkey->keycodes[0] = KEY_PHONE; 219 touchkey->keycodes[1] = KEY_BACK; 220 touchkey->num_keycodes = 2; 221 } 222 223 error = tm2_touchkey_power_enable(touchkey); 224 if (error) { 225 dev_err(&client->dev, "failed to power up device: %d\n", error); 226 return error; 227 } 228 229 error = devm_add_action_or_reset(&client->dev, 230 tm2_touchkey_power_disable, touchkey); 231 if (error) { 232 dev_err(&client->dev, 233 "failed to install poweroff handler: %d\n", error); 234 return error; 235 } 236 237 /* input device */ 238 touchkey->input_dev = devm_input_allocate_device(&client->dev); 239 if (!touchkey->input_dev) { 240 dev_err(&client->dev, "failed to allocate input device\n"); 241 return -ENOMEM; 242 } 243 244 touchkey->input_dev->name = TM2_TOUCHKEY_DEV_NAME; 245 touchkey->input_dev->id.bustype = BUS_I2C; 246 247 for (i = 0; i < touchkey->num_keycodes; i++) 248 input_set_capability(touchkey->input_dev, EV_KEY, 249 touchkey->keycodes[i]); 250 251 error = input_register_device(touchkey->input_dev); 252 if (error) { 253 dev_err(&client->dev, 254 "failed to register input device: %d\n", error); 255 return error; 256 } 257 258 error = devm_request_threaded_irq(&client->dev, client->irq, 259 NULL, tm2_touchkey_irq_handler, 260 IRQF_ONESHOT, 261 TM2_TOUCHKEY_DEV_NAME, touchkey); 262 if (error) { 263 dev_err(&client->dev, 264 "failed to request threaded irq: %d\n", error); 265 return error; 266 } 267 268 /* led device */ 269 touchkey->led_dev.name = TM2_TOUCHKEY_DEV_NAME; 270 touchkey->led_dev.brightness = LED_ON; 271 touchkey->led_dev.max_brightness = LED_ON; 272 touchkey->led_dev.brightness_set_blocking = 273 tm2_touchkey_led_brightness_set; 274 275 error = devm_led_classdev_register(&client->dev, &touchkey->led_dev); 276 if (error) { 277 dev_err(&client->dev, 278 "failed to register touchkey led: %d\n", error); 279 return error; 280 } 281 282 if (touchkey->variant->fixed_regulator) 283 tm2_touchkey_led_brightness_set(&touchkey->led_dev, LED_ON); 284 285 return 0; 286 } 287 288 static int __maybe_unused tm2_touchkey_suspend(struct device *dev) 289 { 290 struct i2c_client *client = to_i2c_client(dev); 291 struct tm2_touchkey_data *touchkey = i2c_get_clientdata(client); 292 293 disable_irq(client->irq); 294 tm2_touchkey_power_disable(touchkey); 295 296 return 0; 297 } 298 299 static int __maybe_unused tm2_touchkey_resume(struct device *dev) 300 { 301 struct i2c_client *client = to_i2c_client(dev); 302 struct tm2_touchkey_data *touchkey = i2c_get_clientdata(client); 303 int ret; 304 305 enable_irq(client->irq); 306 307 ret = tm2_touchkey_power_enable(touchkey); 308 if (ret) 309 dev_err(dev, "failed to enable power: %d\n", ret); 310 311 return ret; 312 } 313 314 static SIMPLE_DEV_PM_OPS(tm2_touchkey_pm_ops, 315 tm2_touchkey_suspend, tm2_touchkey_resume); 316 317 static const struct i2c_device_id tm2_touchkey_id_table[] = { 318 { TM2_TOUCHKEY_DEV_NAME, 0 }, 319 { }, 320 }; 321 MODULE_DEVICE_TABLE(i2c, tm2_touchkey_id_table); 322 323 static const struct of_device_id tm2_touchkey_of_match[] = { 324 { 325 .compatible = "cypress,tm2-touchkey", 326 .data = &tm2_touchkey_variant, 327 }, { 328 .compatible = "cypress,midas-touchkey", 329 .data = &midas_touchkey_variant, 330 }, { 331 .compatible = "cypress,aries-touchkey", 332 .data = &aries_touchkey_variant, 333 }, 334 { }, 335 }; 336 MODULE_DEVICE_TABLE(of, tm2_touchkey_of_match); 337 338 static struct i2c_driver tm2_touchkey_driver = { 339 .driver = { 340 .name = TM2_TOUCHKEY_DEV_NAME, 341 .pm = &tm2_touchkey_pm_ops, 342 .of_match_table = of_match_ptr(tm2_touchkey_of_match), 343 }, 344 .probe = tm2_touchkey_probe, 345 .id_table = tm2_touchkey_id_table, 346 }; 347 module_i2c_driver(tm2_touchkey_driver); 348 349 MODULE_AUTHOR("Beomho Seo <beomho.seo@samsung.com>"); 350 MODULE_AUTHOR("Jaechul Lee <jcsing.lee@samsung.com>"); 351 MODULE_DESCRIPTION("Samsung touchkey driver"); 352 MODULE_LICENSE("GPL v2"); 353