| 1 | |
| 2 | |
| 3 | * TSC2004/TSC2005 touchscreen driver core
|
| 4 | *
|
| 5 | * Copyright (C) 2006-2010 Nokia Corporation
|
| 6 | * Copyright (C) 2015 QWERTY Embedded Design
|
| 7 | * Copyright (C) 2015 EMAC Inc.
|
| 8 | *
|
| 9 | * Author: Lauri Leukkunen <[email protected]>
|
| 10 | * based on TSC2301 driver by Klaus K. Pedersen <[email protected]>
|
| 11 |
|
| 12 |
|
| 13 | #include <linux/export.h>
|
| 14 | #include <linux/kernel.h>
|
| 15 | #include <linux/module.h>
|
| 16 | #include <linux/input.h>
|
| 17 | #include <linux/input/touchscreen.h>
|
| 18 | #include <linux/interrupt.h>
|
| 19 | #include <linux/delay.h>
|
| 20 | #include <linux/pm.h>
|
| 21 | #include <linux/of.h>
|
| 22 | #include <linux/regulator/consumer.h>
|
| 23 | #include <linux/regmap.h>
|
| 24 | #include <linux/gpio/consumer.h>
|
| 25 | #include "tsc200x-core.h"
|
| 26 |
|
| 27 | |
| 28 | * The touchscreen interface operates as follows:
|
| 29 | *
|
| 30 | * 1) Pen is pressed against the touchscreen.
|
| 31 | * 2) TSC200X performs AD conversion.
|
| 32 | * 3) After the conversion is done TSC200X drives DAV line down.
|
| 33 | * 4) GPIO IRQ is received and tsc200x_irq_thread() is scheduled.
|
| 34 | * 5) tsc200x_irq_thread() queues up a transfer to fetch the x, y, z1, z2
|
| 35 | * values.
|
| 36 | * 6) tsc200x_irq_thread() reports coordinates to input layer and sets up
|
| 37 | * tsc200x_penup_timer() to be called after TSC200X_PENUP_TIME_MS (40ms).
|
| 38 | * 7) When the penup timer expires, there have not been touch or DAV interrupts
|
| 39 | * during the last 40ms which means the pen has been lifted.
|
| 40 | *
|
| 41 | * ESD recovery via a hardware reset is done if the TSC200X doesn't respond
|
| 42 | * after a configurable period (in ms) of activity. If esd_timeout is 0, the
|
| 43 | * watchdog is disabled.
|
| 44 |
|
| 45 |
|
| 46 | static const struct regmap_range tsc200x_writable_ranges[] = {
|
| 47 | regmap_reg_range(TSC200X_REG_AUX_HIGH, TSC200X_REG_CFR2),
|
| 48 | };
|
| 49 |
|
| 50 | static const struct regmap_access_table tsc200x_writable_table = {
|
| 51 | .yes_ranges = tsc200x_writable_ranges,
|
| 52 | .n_yes_ranges = ARRAY_SIZE(tsc200x_writable_ranges),
|
| 53 | };
|
| 54 |
|
| 55 | const struct regmap_config tsc200x_regmap_config = {
|
| 56 | .reg_bits = 8,
|
| 57 | .val_bits = 16,
|
| 58 | .reg_stride = 0x08,
|
| 59 | .max_register = 0x78,
|
| 60 | .read_flag_mask = TSC200X_REG_READ,
|
| 61 | .write_flag_mask = TSC200X_REG_PND0,
|
| 62 | .wr_table = &tsc200x_writable_table,
|
| 63 | .use_single_read = true,
|
| 64 | .use_single_write = true,
|
| 65 | };
|
| 66 | EXPORT_SYMBOL_GPL(tsc200x_regmap_config);
|
| 67 |
|
| 68 | struct tsc200x_data {
|
| 69 | u16 x;
|
| 70 | u16 y;
|
| 71 | u16 z1;
|
| 72 | u16 z2;
|
| 73 | } __packed;
|
| 74 | #define TSC200X_DATA_REGS 4
|
| 75 |
|
| 76 | struct tsc200x {
|
| 77 | struct device *dev;
|
| 78 | struct regmap *regmap;
|
| 79 | __u16 bustype;
|
| 80 |
|
| 81 | struct input_dev *idev;
|
| 82 | char phys[32];
|
| 83 |
|
| 84 | struct mutex mutex;
|
| 85 |
|
| 86 |
|
| 87 | int in_x;
|
| 88 | int in_y;
|
| 89 | int in_z1;
|
| 90 | int in_z2;
|
| 91 |
|
| 92 | struct touchscreen_properties prop;
|
| 93 |
|
| 94 | spinlock_t lock;
|
| 95 | struct timer_list penup_timer;
|
| 96 |
|
| 97 | unsigned int esd_timeout;
|
| 98 | struct delayed_work esd_work;
|
| 99 | unsigned long last_valid_interrupt;
|
| 100 |
|
| 101 | unsigned int x_plate_ohm;
|
| 102 |
|
| 103 | bool opened;
|
| 104 | bool suspended;
|
| 105 |
|
| 106 | bool pen_down;
|
| 107 |
|
| 108 | struct gpio_desc *reset_gpio;
|
| 109 | int (*tsc200x_cmd)(struct device *dev, u8 cmd);
|
| 110 |
|
| 111 | int irq;
|
| 112 | bool wake_irq_enabled;
|
| 113 | };
|
| 114 |
|
| 115 | static void tsc200x_update_pen_state(struct tsc200x *ts,
|
| 116 | int x, int y, int pressure)
|
| 117 | {
|
| 118 | if (pressure) {
|
| 119 | touchscreen_report_pos(ts->idev, &ts->prop, x, y, false);
|
| 120 | input_report_abs(ts->idev, ABS_PRESSURE, pressure);
|
| 121 | if (!ts->pen_down) {
|
| 122 | input_report_key(ts->idev, BTN_TOUCH, !!pressure);
|
| 123 | ts->pen_down = true;
|
| 124 | }
|
| 125 | } else {
|
| 126 | input_report_abs(ts->idev, ABS_PRESSURE, 0);
|
| 127 | if (ts->pen_down) {
|
| 128 | input_report_key(ts->idev, BTN_TOUCH, 0);
|
| 129 | ts->pen_down = false;
|
| 130 | }
|
| 131 | }
|
| 132 | input_sync(ts->idev);
|
| 133 | dev_dbg(ts->dev, "point(%4d,%4d), pressure (%4d)\n", x, y,
|
| 134 | pressure);
|
| 135 | }
|
| 136 |
|
| 137 | static irqreturn_t tsc200x_irq_thread(int irq, void *_ts)
|
| 138 | {
|
| 139 | struct tsc200x *ts = _ts;
|
| 140 | unsigned int pressure;
|
| 141 | struct tsc200x_data tsdata;
|
| 142 | int error;
|
| 143 |
|
| 144 |
|
| 145 | error = regmap_bulk_read(ts->regmap, TSC200X_REG_X, &tsdata,
|
| 146 | TSC200X_DATA_REGS);
|
| 147 | if (unlikely(error))
|
| 148 | goto out;
|
| 149 |
|
| 150 |
|
| 151 | if (unlikely(tsdata.x > MAX_12BIT || tsdata.y > MAX_12BIT))
|
| 152 | goto out;
|
| 153 |
|
| 154 |
|
| 155 | if (unlikely(tsdata.z1 == 0 || tsdata.z2 > MAX_12BIT))
|
| 156 | goto out;
|
| 157 | if (unlikely(tsdata.z1 >= tsdata.z2))
|
| 158 | goto out;
|
| 159 |
|
| 160 | |
| 161 | * Skip point if this is a pen down with the exact same values as
|
| 162 | * the value before pen-up - that implies SPI fed us stale data
|
| 163 |
|
| 164 | if (!ts->pen_down &&
|
| 165 | ts->in_x == tsdata.x && ts->in_y == tsdata.y &&
|
| 166 | ts->in_z1 == tsdata.z1 && ts->in_z2 == tsdata.z2) {
|
| 167 | goto out;
|
| 168 | }
|
| 169 |
|
| 170 | |
| 171 | * At this point we are happy we have a valid and useful reading.
|
| 172 | * Remember it for later comparisons. We may now begin downsampling.
|
| 173 |
|
| 174 | ts->in_x = tsdata.x;
|
| 175 | ts->in_y = tsdata.y;
|
| 176 | ts->in_z1 = tsdata.z1;
|
| 177 | ts->in_z2 = tsdata.z2;
|
| 178 |
|
| 179 |
|
| 180 | pressure = tsdata.x * (tsdata.z2 - tsdata.z1) / tsdata.z1;
|
| 181 | pressure = pressure * ts->x_plate_ohm / 4096;
|
| 182 | if (unlikely(pressure > MAX_12BIT))
|
| 183 | goto out;
|
| 184 |
|
| 185 | scoped_guard(spinlock_irqsave, &ts->lock) {
|
| 186 | tsc200x_update_pen_state(ts, tsdata.x, tsdata.y, pressure);
|
| 187 | mod_timer(&ts->penup_timer,
|
| 188 | jiffies + msecs_to_jiffies(TSC200X_PENUP_TIME_MS));
|
| 189 | }
|
| 190 |
|
| 191 | ts->last_valid_interrupt = jiffies;
|
| 192 | out:
|
| 193 | return IRQ_HANDLED;
|
| 194 | }
|
| 195 |
|
| 196 | static void tsc200x_penup_timer(struct timer_list *t)
|
| 197 | {
|
| 198 | struct tsc200x *ts = timer_container_of(ts, t, penup_timer);
|
| 199 |
|
| 200 | guard(spinlock_irqsave)(&ts->lock);
|
| 201 | tsc200x_update_pen_state(ts, 0, 0, 0);
|
| 202 | }
|
| 203 |
|
| 204 | static void tsc200x_start_scan(struct tsc200x *ts)
|
| 205 | {
|
| 206 | regmap_write(ts->regmap, TSC200X_REG_CFR0, TSC200X_CFR0_INITVALUE);
|
| 207 | regmap_write(ts->regmap, TSC200X_REG_CFR1, TSC200X_CFR1_INITVALUE);
|
| 208 | regmap_write(ts->regmap, TSC200X_REG_CFR2, TSC200X_CFR2_INITVALUE);
|
| 209 | ts->tsc200x_cmd(ts->dev, TSC200X_CMD_NORMAL);
|
| 210 | }
|
| 211 |
|
| 212 | static void tsc200x_stop_scan(struct tsc200x *ts)
|
| 213 | {
|
| 214 | ts->tsc200x_cmd(ts->dev, TSC200X_CMD_STOP);
|
| 215 | }
|
| 216 |
|
| 217 | static void tsc200x_reset(struct tsc200x *ts)
|
| 218 | {
|
| 219 | if (ts->reset_gpio) {
|
| 220 | gpiod_set_value_cansleep(ts->reset_gpio, 1);
|
| 221 | usleep_range(100, 500);
|
| 222 | gpiod_set_value_cansleep(ts->reset_gpio, 0);
|
| 223 | }
|
| 224 | }
|
| 225 |
|
| 226 |
|
| 227 | static void __tsc200x_disable(struct tsc200x *ts)
|
| 228 | {
|
| 229 | tsc200x_stop_scan(ts);
|
| 230 |
|
| 231 | guard(disable_irq)(&ts->irq);
|
| 232 |
|
| 233 | timer_delete_sync(&ts->penup_timer);
|
| 234 | cancel_delayed_work_sync(&ts->esd_work);
|
| 235 | }
|
| 236 |
|
| 237 |
|
| 238 | static void __tsc200x_enable(struct tsc200x *ts)
|
| 239 | {
|
| 240 | tsc200x_start_scan(ts);
|
| 241 |
|
| 242 | if (ts->esd_timeout && ts->reset_gpio) {
|
| 243 | ts->last_valid_interrupt = jiffies;
|
| 244 | schedule_delayed_work(&ts->esd_work,
|
| 245 | round_jiffies_relative(
|
| 246 | msecs_to_jiffies(ts->esd_timeout)));
|
| 247 | }
|
| 248 | }
|
| 249 |
|
| 250 | |
| 251 | * Test TSC200X communications via temp high register.
|
| 252 |
|
| 253 | static int tsc200x_do_selftest(struct tsc200x *ts)
|
| 254 | {
|
| 255 | unsigned int temp_high_orig;
|
| 256 | unsigned int temp_high_test;
|
| 257 | unsigned int temp_high;
|
| 258 | int error;
|
| 259 |
|
| 260 | error = regmap_read(ts->regmap, TSC200X_REG_TEMP_HIGH, &temp_high_orig);
|
| 261 | if (error) {
|
| 262 | dev_warn(ts->dev, "selftest failed: read error %d\n", error);
|
| 263 | return error;
|
| 264 | }
|
| 265 |
|
| 266 | temp_high_test = (temp_high_orig - 1) & MAX_12BIT;
|
| 267 |
|
| 268 | error = regmap_write(ts->regmap, TSC200X_REG_TEMP_HIGH, temp_high_test);
|
| 269 | if (error) {
|
| 270 | dev_warn(ts->dev, "selftest failed: write error %d\n", error);
|
| 271 | return error;
|
| 272 | }
|
| 273 |
|
| 274 | error = regmap_read(ts->regmap, TSC200X_REG_TEMP_HIGH, &temp_high);
|
| 275 | if (error) {
|
| 276 | dev_warn(ts->dev,
|
| 277 | "selftest failed: read error %d after write\n", error);
|
| 278 | return error;
|
| 279 | }
|
| 280 |
|
| 281 |
|
| 282 | tsc200x_reset(ts);
|
| 283 |
|
| 284 | if (temp_high != temp_high_test) {
|
| 285 | dev_warn(ts->dev, "selftest failed: %d != %d\n",
|
| 286 | temp_high, temp_high_test);
|
| 287 | return -EINVAL;
|
| 288 | }
|
| 289 |
|
| 290 |
|
| 291 | error = regmap_read(ts->regmap, TSC200X_REG_TEMP_HIGH, &temp_high);
|
| 292 | if (error) {
|
| 293 | dev_warn(ts->dev,
|
| 294 | "selftest failed: read error %d after reset\n", error);
|
| 295 | return error;
|
| 296 | }
|
| 297 |
|
| 298 | if (temp_high != temp_high_orig) {
|
| 299 | dev_warn(ts->dev, "selftest failed after reset: %d != %d\n",
|
| 300 | temp_high, temp_high_orig);
|
| 301 | return -EINVAL;
|
| 302 | }
|
| 303 |
|
| 304 | return 0;
|
| 305 | }
|
| 306 |
|
| 307 | static ssize_t tsc200x_selftest_show(struct device *dev,
|
| 308 | struct device_attribute *attr,
|
| 309 | char *buf)
|
| 310 | {
|
| 311 | struct tsc200x *ts = dev_get_drvdata(dev);
|
| 312 | int error;
|
| 313 |
|
| 314 | scoped_guard(mutex, &ts->mutex) {
|
| 315 | __tsc200x_disable(ts);
|
| 316 |
|
| 317 | error = tsc200x_do_selftest(ts);
|
| 318 |
|
| 319 | __tsc200x_enable(ts);
|
| 320 | }
|
| 321 |
|
| 322 | return sprintf(buf, "%d\n", !error);
|
| 323 | }
|
| 324 |
|
| 325 | static DEVICE_ATTR(selftest, S_IRUGO, tsc200x_selftest_show, NULL);
|
| 326 |
|
| 327 | static struct attribute *tsc200x_attrs[] = {
|
| 328 | &dev_attr_selftest.attr,
|
| 329 | NULL
|
| 330 | };
|
| 331 |
|
| 332 | static umode_t tsc200x_attr_is_visible(struct kobject *kobj,
|
| 333 | struct attribute *attr, int n)
|
| 334 | {
|
| 335 | struct device *dev = kobj_to_dev(kobj);
|
| 336 | struct tsc200x *ts = dev_get_drvdata(dev);
|
| 337 | umode_t mode = attr->mode;
|
| 338 |
|
| 339 | if (attr == &dev_attr_selftest.attr) {
|
| 340 | if (!ts->reset_gpio)
|
| 341 | mode = 0;
|
| 342 | }
|
| 343 |
|
| 344 | return mode;
|
| 345 | }
|
| 346 |
|
| 347 | static const struct attribute_group tsc200x_attr_group = {
|
| 348 | .is_visible = tsc200x_attr_is_visible,
|
| 349 | .attrs = tsc200x_attrs,
|
| 350 | };
|
| 351 |
|
| 352 | const struct attribute_group *tsc200x_groups[] = {
|
| 353 | &tsc200x_attr_group,
|
| 354 | NULL
|
| 355 | };
|
| 356 | EXPORT_SYMBOL_GPL(tsc200x_groups);
|
| 357 |
|
| 358 | static void tsc200x_esd_work(struct work_struct *work)
|
| 359 | {
|
| 360 | struct tsc200x *ts = container_of(work, struct tsc200x, esd_work.work);
|
| 361 | int error;
|
| 362 | unsigned int r;
|
| 363 |
|
| 364 | |
| 365 | * If the mutex is taken, it means that disable or enable is in
|
| 366 | * progress. In that case just reschedule the work. If the work
|
| 367 | * is not needed, it will be canceled by disable.
|
| 368 |
|
| 369 | scoped_guard(mutex_try, &ts->mutex) {
|
| 370 | if (time_is_after_jiffies(ts->last_valid_interrupt +
|
| 371 | msecs_to_jiffies(ts->esd_timeout)))
|
| 372 | break;
|
| 373 |
|
| 374 | |
| 375 | * We should be able to read register without disabling
|
| 376 | * interrupts.
|
| 377 |
|
| 378 | error = regmap_read(ts->regmap, TSC200X_REG_CFR0, &r);
|
| 379 | if (!error &&
|
| 380 | !((r ^ TSC200X_CFR0_INITVALUE) & TSC200X_CFR0_RW_MASK)) {
|
| 381 | break;
|
| 382 | }
|
| 383 |
|
| 384 | |
| 385 | * If we could not read our known value from configuration
|
| 386 | * register 0 then we should reset the controller as if from
|
| 387 | * power-up and start scanning again.
|
| 388 |
|
| 389 | dev_info(ts->dev, "TSC200X not responding - resetting\n");
|
| 390 |
|
| 391 | scoped_guard(disable_irq, &ts->irq) {
|
| 392 | timer_delete_sync(&ts->penup_timer);
|
| 393 | tsc200x_update_pen_state(ts, 0, 0, 0);
|
| 394 | tsc200x_reset(ts);
|
| 395 | }
|
| 396 |
|
| 397 | tsc200x_start_scan(ts);
|
| 398 | }
|
| 399 |
|
| 400 |
|
| 401 | schedule_delayed_work(&ts->esd_work,
|
| 402 | round_jiffies_relative(
|
| 403 | msecs_to_jiffies(ts->esd_timeout)));
|
| 404 | }
|
| 405 |
|
| 406 | static int tsc200x_open(struct input_dev *input)
|
| 407 | {
|
| 408 | struct tsc200x *ts = input_get_drvdata(input);
|
| 409 |
|
| 410 | guard(mutex)(&ts->mutex);
|
| 411 |
|
| 412 | if (!ts->suspended)
|
| 413 | __tsc200x_enable(ts);
|
| 414 |
|
| 415 | ts->opened = true;
|
| 416 |
|
| 417 | return 0;
|
| 418 | }
|
| 419 |
|
| 420 | static void tsc200x_close(struct input_dev *input)
|
| 421 | {
|
| 422 | struct tsc200x *ts = input_get_drvdata(input);
|
| 423 |
|
| 424 | guard(mutex)(&ts->mutex);
|
| 425 |
|
| 426 | if (!ts->suspended)
|
| 427 | __tsc200x_disable(ts);
|
| 428 |
|
| 429 | ts->opened = false;
|
| 430 | }
|
| 431 |
|
| 432 | int tsc200x_probe(struct device *dev, int irq, const struct input_id *tsc_id,
|
| 433 | struct regmap *regmap,
|
| 434 | int (*tsc200x_cmd)(struct device *dev, u8 cmd))
|
| 435 | {
|
| 436 | struct tsc200x *ts;
|
| 437 | struct input_dev *input_dev;
|
| 438 | u32 x_plate_ohm;
|
| 439 | u32 esd_timeout;
|
| 440 | int error;
|
| 441 |
|
| 442 | if (irq <= 0) {
|
| 443 | dev_err(dev, "no irq\n");
|
| 444 | return -ENODEV;
|
| 445 | }
|
| 446 |
|
| 447 | if (IS_ERR(regmap))
|
| 448 | return PTR_ERR(regmap);
|
| 449 |
|
| 450 | if (!tsc200x_cmd) {
|
| 451 | dev_err(dev, "no cmd function\n");
|
| 452 | return -ENODEV;
|
| 453 | }
|
| 454 |
|
| 455 | ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL);
|
| 456 | if (!ts)
|
| 457 | return -ENOMEM;
|
| 458 |
|
| 459 | input_dev = devm_input_allocate_device(dev);
|
| 460 | if (!input_dev)
|
| 461 | return -ENOMEM;
|
| 462 |
|
| 463 | ts->irq = irq;
|
| 464 | ts->dev = dev;
|
| 465 | ts->idev = input_dev;
|
| 466 | ts->regmap = regmap;
|
| 467 | ts->tsc200x_cmd = tsc200x_cmd;
|
| 468 |
|
| 469 | error = device_property_read_u32(dev, "ti,x-plate-ohms", &x_plate_ohm);
|
| 470 | ts->x_plate_ohm = error ? TSC200X_DEF_RESISTOR : x_plate_ohm;
|
| 471 |
|
| 472 | error = device_property_read_u32(dev, "ti,esd-recovery-timeout-ms",
|
| 473 | &esd_timeout);
|
| 474 | ts->esd_timeout = error ? 0 : esd_timeout;
|
| 475 |
|
| 476 | mutex_init(&ts->mutex);
|
| 477 |
|
| 478 | spin_lock_init(&ts->lock);
|
| 479 | timer_setup(&ts->penup_timer, tsc200x_penup_timer, 0);
|
| 480 |
|
| 481 | INIT_DELAYED_WORK(&ts->esd_work, tsc200x_esd_work);
|
| 482 |
|
| 483 | snprintf(ts->phys, sizeof(ts->phys),
|
| 484 | "%s/input-ts", dev_name(dev));
|
| 485 |
|
| 486 | if (tsc_id->product == 2004) {
|
| 487 | input_dev->name = "TSC200X touchscreen";
|
| 488 | } else {
|
| 489 | input_dev->name = devm_kasprintf(dev, GFP_KERNEL,
|
| 490 | "TSC%04d touchscreen",
|
| 491 | tsc_id->product);
|
| 492 | if (!input_dev->name)
|
| 493 | return -ENOMEM;
|
| 494 | }
|
| 495 |
|
| 496 | input_dev->phys = ts->phys;
|
| 497 | input_dev->id = *tsc_id;
|
| 498 |
|
| 499 | input_dev->open = tsc200x_open;
|
| 500 | input_dev->close = tsc200x_close;
|
| 501 |
|
| 502 | input_set_drvdata(input_dev, ts);
|
| 503 |
|
| 504 | __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
|
| 505 | input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
|
| 506 |
|
| 507 | input_set_abs_params(input_dev, ABS_X,
|
| 508 | 0, MAX_12BIT, TSC200X_DEF_X_FUZZ, 0);
|
| 509 | input_set_abs_params(input_dev, ABS_Y,
|
| 510 | 0, MAX_12BIT, TSC200X_DEF_Y_FUZZ, 0);
|
| 511 | input_set_abs_params(input_dev, ABS_PRESSURE,
|
| 512 | 0, MAX_12BIT, TSC200X_DEF_P_FUZZ, 0);
|
| 513 |
|
| 514 | touchscreen_parse_properties(input_dev, false, &ts->prop);
|
| 515 |
|
| 516 | ts->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
|
| 517 | error = PTR_ERR_OR_ZERO(ts->reset_gpio);
|
| 518 | if (error) {
|
| 519 | dev_err(dev, "error acquiring reset gpio: %d\n", error);
|
| 520 | return error;
|
| 521 | }
|
| 522 |
|
| 523 | error = devm_regulator_get_enable(dev, "vio");
|
| 524 | if (error) {
|
| 525 | dev_err(dev, "error acquiring vio regulator: %d\n", error);
|
| 526 | return error;
|
| 527 | }
|
| 528 |
|
| 529 | tsc200x_reset(ts);
|
| 530 |
|
| 531 |
|
| 532 | tsc200x_stop_scan(ts);
|
| 533 |
|
| 534 | error = devm_request_threaded_irq(dev, irq, NULL, tsc200x_irq_thread,
|
| 535 | IRQF_ONESHOT, "tsc200x", ts);
|
| 536 | if (error) {
|
| 537 | dev_err(dev, "Failed to request irq, err: %d\n", error);
|
| 538 | return error;
|
| 539 | }
|
| 540 |
|
| 541 | dev_set_drvdata(dev, ts);
|
| 542 |
|
| 543 | error = input_register_device(ts->idev);
|
| 544 | if (error) {
|
| 545 | dev_err(dev,
|
| 546 | "Failed to register input device, err: %d\n", error);
|
| 547 | return error;
|
| 548 | }
|
| 549 |
|
| 550 | device_init_wakeup(dev,
|
| 551 | device_property_read_bool(dev, "wakeup-source"));
|
| 552 |
|
| 553 | return 0;
|
| 554 | }
|
| 555 | EXPORT_SYMBOL_GPL(tsc200x_probe);
|
| 556 |
|
| 557 | static int tsc200x_suspend(struct device *dev)
|
| 558 | {
|
| 559 | struct tsc200x *ts = dev_get_drvdata(dev);
|
| 560 |
|
| 561 | guard(mutex)(&ts->mutex);
|
| 562 |
|
| 563 | if (!ts->suspended && ts->opened)
|
| 564 | __tsc200x_disable(ts);
|
| 565 |
|
| 566 | ts->suspended = true;
|
| 567 |
|
| 568 | if (device_may_wakeup(dev))
|
| 569 | ts->wake_irq_enabled = enable_irq_wake(ts->irq) == 0;
|
| 570 |
|
| 571 | return 0;
|
| 572 | }
|
| 573 |
|
| 574 | static int tsc200x_resume(struct device *dev)
|
| 575 | {
|
| 576 | struct tsc200x *ts = dev_get_drvdata(dev);
|
| 577 |
|
| 578 | guard(mutex)(&ts->mutex);
|
| 579 |
|
| 580 | if (ts->wake_irq_enabled) {
|
| 581 | disable_irq_wake(ts->irq);
|
| 582 | ts->wake_irq_enabled = false;
|
| 583 | }
|
| 584 |
|
| 585 | if (ts->suspended && ts->opened)
|
| 586 | __tsc200x_enable(ts);
|
| 587 |
|
| 588 | ts->suspended = false;
|
| 589 |
|
| 590 | return 0;
|
| 591 | }
|
| 592 |
|
| 593 | EXPORT_GPL_SIMPLE_DEV_PM_OPS(tsc200x_pm_ops, tsc200x_suspend, tsc200x_resume);
|
| 594 |
|
| 595 | MODULE_AUTHOR("Lauri Leukkunen <[email protected]>");
|
| 596 | MODULE_DESCRIPTION("TSC200x Touchscreen Driver Core");
|
| 597 | MODULE_LICENSE("GPL");
|