diff options
| author | Denis Carikli <denis@eukrea.com> | 2013-11-19 14:56:04 -0500 |
|---|---|---|
| committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2013-11-25 21:27:53 -0500 |
| commit | 07f9e5cf8e4154ad17b92ad288be0f04fa0cb94f (patch) | |
| tree | 2369ad48e65fb898bc57858a6ab36f13a2125e41 /drivers/input | |
| parent | bd77c321945f652f6225847a8405f469601cd02c (diff) | |
Input: tsc2007 - add device tree support.
Signed-off-by: Denis Carikli <denis@eukrea.com>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Diffstat (limited to 'drivers/input')
| -rw-r--r-- | drivers/input/touchscreen/tsc2007.c | 173 |
1 files changed, 133 insertions, 40 deletions
diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c index 0b67ba476b4c..88b150a0b8ee 100644 --- a/drivers/input/touchscreen/tsc2007.c +++ b/drivers/input/touchscreen/tsc2007.c | |||
| @@ -26,6 +26,9 @@ | |||
| 26 | #include <linux/interrupt.h> | 26 | #include <linux/interrupt.h> |
| 27 | #include <linux/i2c.h> | 27 | #include <linux/i2c.h> |
| 28 | #include <linux/i2c/tsc2007.h> | 28 | #include <linux/i2c/tsc2007.h> |
| 29 | #include <linux/of_device.h> | ||
| 30 | #include <linux/of.h> | ||
| 31 | #include <linux/of_gpio.h> | ||
| 29 | 32 | ||
| 30 | #define TSC2007_MEASURE_TEMP0 (0x0 << 4) | 33 | #define TSC2007_MEASURE_TEMP0 (0x0 << 4) |
| 31 | #define TSC2007_MEASURE_AUX (0x2 << 4) | 34 | #define TSC2007_MEASURE_AUX (0x2 << 4) |
| @@ -74,13 +77,17 @@ struct tsc2007 { | |||
| 74 | u16 max_rt; | 77 | u16 max_rt; |
| 75 | unsigned long poll_delay; | 78 | unsigned long poll_delay; |
| 76 | unsigned long poll_period; | 79 | unsigned long poll_period; |
| 80 | int fuzzx; | ||
| 81 | int fuzzy; | ||
| 82 | int fuzzz; | ||
| 77 | 83 | ||
| 84 | unsigned gpio; | ||
| 78 | int irq; | 85 | int irq; |
| 79 | 86 | ||
| 80 | wait_queue_head_t wait; | 87 | wait_queue_head_t wait; |
| 81 | bool stopped; | 88 | bool stopped; |
| 82 | 89 | ||
| 83 | int (*get_pendown_state)(void); | 90 | int (*get_pendown_state)(struct device *); |
| 84 | void (*clear_penirq)(void); | 91 | void (*clear_penirq)(void); |
| 85 | }; | 92 | }; |
| 86 | 93 | ||
| @@ -161,7 +168,7 @@ static bool tsc2007_is_pen_down(struct tsc2007 *ts) | |||
| 161 | if (!ts->get_pendown_state) | 168 | if (!ts->get_pendown_state) |
| 162 | return true; | 169 | return true; |
| 163 | 170 | ||
| 164 | return ts->get_pendown_state(); | 171 | return ts->get_pendown_state(&ts->client->dev); |
| 165 | } | 172 | } |
| 166 | 173 | ||
| 167 | static irqreturn_t tsc2007_soft_irq(int irq, void *handle) | 174 | static irqreturn_t tsc2007_soft_irq(int irq, void *handle) |
| @@ -178,7 +185,7 @@ static irqreturn_t tsc2007_soft_irq(int irq, void *handle) | |||
| 178 | 185 | ||
| 179 | rt = tsc2007_calculate_pressure(ts, &tc); | 186 | rt = tsc2007_calculate_pressure(ts, &tc); |
| 180 | 187 | ||
| 181 | if (rt == 0 && !ts->get_pendown_state) { | 188 | if (!rt && !ts->get_pendown_state) { |
| 182 | /* | 189 | /* |
| 183 | * If pressure reported is 0 and we don't have | 190 | * If pressure reported is 0 and we don't have |
| 184 | * callback to check pendown state, we have to | 191 | * callback to check pendown state, we have to |
| @@ -228,7 +235,7 @@ static irqreturn_t tsc2007_hard_irq(int irq, void *handle) | |||
| 228 | { | 235 | { |
| 229 | struct tsc2007 *ts = handle; | 236 | struct tsc2007 *ts = handle; |
| 230 | 237 | ||
| 231 | if (!ts->get_pendown_state || likely(ts->get_pendown_state())) | 238 | if (tsc2007_is_pen_down(ts)) |
| 232 | return IRQ_WAKE_THREAD; | 239 | return IRQ_WAKE_THREAD; |
| 233 | 240 | ||
| 234 | if (ts->clear_penirq) | 241 | if (ts->clear_penirq) |
| @@ -273,35 +280,74 @@ static void tsc2007_close(struct input_dev *input_dev) | |||
| 273 | tsc2007_stop(ts); | 280 | tsc2007_stop(ts); |
| 274 | } | 281 | } |
| 275 | 282 | ||
| 276 | static int tsc2007_probe(struct i2c_client *client, | 283 | #ifdef CONFIG_OF |
| 277 | const struct i2c_device_id *id) | 284 | static int tsc2007_get_pendown_state_gpio(struct device *dev) |
| 278 | { | 285 | { |
| 279 | struct tsc2007 *ts; | 286 | struct i2c_client *client = to_i2c_client(dev); |
| 280 | struct tsc2007_platform_data *pdata = client->dev.platform_data; | 287 | struct tsc2007 *ts = i2c_get_clientdata(client); |
| 281 | struct input_dev *input_dev; | 288 | |
| 282 | int err; | 289 | return !gpio_get_value(ts->gpio); |
| 290 | } | ||
| 291 | |||
| 292 | static int tsc2007_probe_dt(struct i2c_client *client, struct tsc2007 *ts) | ||
| 293 | { | ||
| 294 | struct device_node *np = client->dev.of_node; | ||
| 295 | u32 val32; | ||
| 296 | u64 val64; | ||
| 283 | 297 | ||
| 284 | if (!pdata) { | 298 | if (!np) { |
| 285 | dev_err(&client->dev, "platform data is required!\n"); | 299 | dev_err(&client->dev, "missing device tree data\n"); |
| 286 | return -EINVAL; | 300 | return -EINVAL; |
| 287 | } | 301 | } |
| 288 | 302 | ||
| 289 | if (!i2c_check_functionality(client->adapter, | 303 | if (!of_property_read_u32(np, "ti,max-rt", &val32)) |
| 290 | I2C_FUNC_SMBUS_READ_WORD_DATA)) | 304 | ts->max_rt = val32; |
| 291 | return -EIO; | 305 | else |
| 306 | ts->max_rt = MAX_12BIT; | ||
| 292 | 307 | ||
| 293 | ts = kzalloc(sizeof(struct tsc2007), GFP_KERNEL); | 308 | if (!of_property_read_u32(np, "ti,fuzzx", &val32)) |
| 294 | input_dev = input_allocate_device(); | 309 | ts->fuzzx = val32; |
| 295 | if (!ts || !input_dev) { | 310 | |
| 296 | err = -ENOMEM; | 311 | if (!of_property_read_u32(np, "ti,fuzzy", &val32)) |
| 297 | goto err_free_mem; | 312 | ts->fuzzy = val32; |
| 313 | |||
| 314 | if (!of_property_read_u32(np, "ti,fuzzz", &val32)) | ||
| 315 | ts->fuzzz = val32; | ||
| 316 | |||
| 317 | if (!of_property_read_u64(np, "ti,poll-period", &val64)) | ||
| 318 | ts->poll_period = val64; | ||
| 319 | else | ||
| 320 | ts->poll_period = 1; | ||
| 321 | |||
| 322 | if (!of_property_read_u32(np, "ti,x-plate-ohms", &val32)) { | ||
| 323 | ts->x_plate_ohms = val32; | ||
| 324 | } else { | ||
| 325 | dev_err(&client->dev, "missing ti,x-plate-ohms devicetree property."); | ||
| 326 | return -EINVAL; | ||
| 298 | } | 327 | } |
| 299 | 328 | ||
| 300 | ts->client = client; | 329 | ts->gpio = of_get_gpio(np, 0); |
| 301 | ts->irq = client->irq; | 330 | if (gpio_is_valid(ts->gpio)) |
| 302 | ts->input = input_dev; | 331 | ts->get_pendown_state = tsc2007_get_pendown_state_gpio; |
| 303 | init_waitqueue_head(&ts->wait); | 332 | else |
| 333 | dev_warn(&client->dev, | ||
| 334 | "GPIO not specified in DT (of_get_gpio returned %d)\n", | ||
| 335 | ts->gpio); | ||
| 304 | 336 | ||
| 337 | return 0; | ||
| 338 | } | ||
| 339 | #else | ||
| 340 | static int tsc2007_probe_dt(struct i2c_client *client, struct tsc2007 *ts) | ||
| 341 | { | ||
| 342 | dev_err(&client->dev, "platform data is required!\n"); | ||
| 343 | return -EINVAL; | ||
| 344 | } | ||
| 345 | #endif | ||
| 346 | |||
| 347 | static int tsc2007_probe_pdev(struct i2c_client *client, struct tsc2007 *ts, | ||
| 348 | const struct tsc2007_platform_data *pdata, | ||
| 349 | const struct i2c_device_id *id) | ||
| 350 | { | ||
| 305 | ts->model = pdata->model; | 351 | ts->model = pdata->model; |
| 306 | ts->x_plate_ohms = pdata->x_plate_ohms; | 352 | ts->x_plate_ohms = pdata->x_plate_ohms; |
| 307 | ts->max_rt = pdata->max_rt ? : MAX_12BIT; | 353 | ts->max_rt = pdata->max_rt ? : MAX_12BIT; |
| @@ -309,13 +355,54 @@ static int tsc2007_probe(struct i2c_client *client, | |||
| 309 | ts->poll_period = pdata->poll_period ? : 1; | 355 | ts->poll_period = pdata->poll_period ? : 1; |
| 310 | ts->get_pendown_state = pdata->get_pendown_state; | 356 | ts->get_pendown_state = pdata->get_pendown_state; |
| 311 | ts->clear_penirq = pdata->clear_penirq; | 357 | ts->clear_penirq = pdata->clear_penirq; |
| 358 | ts->fuzzx = pdata->fuzzx; | ||
| 359 | ts->fuzzy = pdata->fuzzy; | ||
| 360 | ts->fuzzz = pdata->fuzzz; | ||
| 312 | 361 | ||
| 313 | if (pdata->x_plate_ohms == 0) { | 362 | if (pdata->x_plate_ohms == 0) { |
| 314 | dev_err(&client->dev, "x_plate_ohms is not set up in platform data"); | 363 | dev_err(&client->dev, "x_plate_ohms is not set up in platform data"); |
| 315 | err = -EINVAL; | 364 | return -EINVAL; |
| 316 | goto err_free_mem; | ||
| 317 | } | 365 | } |
| 318 | 366 | ||
| 367 | return 0; | ||
| 368 | } | ||
| 369 | |||
| 370 | static int tsc2007_probe(struct i2c_client *client, | ||
| 371 | const struct i2c_device_id *id) | ||
| 372 | { | ||
| 373 | const struct tsc2007_platform_data *pdata = dev_get_platdata(&client->dev); | ||
| 374 | struct tsc2007 *ts; | ||
| 375 | struct input_dev *input_dev; | ||
| 376 | int err; | ||
| 377 | |||
| 378 | if (!i2c_check_functionality(client->adapter, | ||
| 379 | I2C_FUNC_SMBUS_READ_WORD_DATA)) | ||
| 380 | return -EIO; | ||
| 381 | |||
| 382 | ts = devm_kzalloc(&client->dev, sizeof(struct tsc2007), GFP_KERNEL); | ||
| 383 | if (!ts) | ||
| 384 | return -ENOMEM; | ||
| 385 | |||
| 386 | if (pdata) | ||
| 387 | err = tsc2007_probe_pdev(client, ts, pdata, id); | ||
| 388 | else | ||
| 389 | err = tsc2007_probe_dt(client, ts); | ||
| 390 | if (err) | ||
| 391 | return err; | ||
| 392 | |||
| 393 | input_dev = input_allocate_device(); | ||
| 394 | if (!input_dev) { | ||
| 395 | err = -ENOMEM; | ||
| 396 | goto err_free_input; | ||
| 397 | }; | ||
| 398 | |||
| 399 | i2c_set_clientdata(client, ts); | ||
| 400 | |||
| 401 | ts->client = client; | ||
| 402 | ts->irq = client->irq; | ||
| 403 | ts->input = input_dev; | ||
| 404 | init_waitqueue_head(&ts->wait); | ||
| 405 | |||
| 319 | snprintf(ts->phys, sizeof(ts->phys), | 406 | snprintf(ts->phys, sizeof(ts->phys), |
| 320 | "%s/input0", dev_name(&client->dev)); | 407 | "%s/input0", dev_name(&client->dev)); |
| 321 | 408 | ||
| @@ -331,19 +418,19 @@ static int tsc2007_probe(struct i2c_client *client, | |||
| 331 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); | 418 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); |
| 332 | input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); | 419 | input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); |
| 333 | 420 | ||
| 334 | input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, pdata->fuzzx, 0); | 421 | input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, ts->fuzzx, 0); |
| 335 | input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, pdata->fuzzy, 0); | 422 | input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, ts->fuzzy, 0); |
| 336 | input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, | 423 | input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, |
| 337 | pdata->fuzzz, 0); | 424 | ts->fuzzz, 0); |
| 338 | 425 | ||
| 339 | if (pdata->init_platform_hw) | 426 | if (pdata && pdata->init_platform_hw) |
| 340 | pdata->init_platform_hw(); | 427 | pdata->init_platform_hw(); |
| 341 | 428 | ||
| 342 | err = request_threaded_irq(ts->irq, tsc2007_hard_irq, tsc2007_soft_irq, | 429 | err = request_threaded_irq(ts->irq, tsc2007_hard_irq, tsc2007_soft_irq, |
| 343 | IRQF_ONESHOT, client->dev.driver->name, ts); | 430 | IRQF_ONESHOT, client->dev.driver->name, ts); |
| 344 | if (err < 0) { | 431 | if (err < 0) { |
| 345 | dev_err(&client->dev, "irq %d busy?\n", ts->irq); | 432 | dev_err(&client->dev, "irq %d busy?\n", ts->irq); |
| 346 | goto err_free_mem; | 433 | goto err_free_input; |
| 347 | } | 434 | } |
| 348 | 435 | ||
| 349 | tsc2007_stop(ts); | 436 | tsc2007_stop(ts); |
| @@ -352,28 +439,25 @@ static int tsc2007_probe(struct i2c_client *client, | |||
| 352 | if (err) | 439 | if (err) |
| 353 | goto err_free_irq; | 440 | goto err_free_irq; |
| 354 | 441 | ||
| 355 | i2c_set_clientdata(client, ts); | ||
| 356 | |||
| 357 | return 0; | 442 | return 0; |
| 358 | 443 | ||
| 359 | err_free_irq: | 444 | err_free_irq: |
| 360 | free_irq(ts->irq, ts); | 445 | free_irq(ts->irq, ts); |
| 361 | if (pdata->exit_platform_hw) | 446 | if (pdata && pdata->exit_platform_hw) |
| 362 | pdata->exit_platform_hw(); | 447 | pdata->exit_platform_hw(); |
| 363 | err_free_mem: | 448 | err_free_input: |
| 364 | input_free_device(input_dev); | 449 | input_free_device(input_dev); |
| 365 | kfree(ts); | ||
| 366 | return err; | 450 | return err; |
| 367 | } | 451 | } |
| 368 | 452 | ||
| 369 | static int tsc2007_remove(struct i2c_client *client) | 453 | static int tsc2007_remove(struct i2c_client *client) |
| 370 | { | 454 | { |
| 371 | struct tsc2007 *ts = i2c_get_clientdata(client); | 455 | const struct tsc2007_platform_data *pdata = dev_get_platdata(&client->dev); |
| 372 | struct tsc2007_platform_data *pdata = client->dev.platform_data; | 456 | struct tsc2007 *ts = i2c_get_clientdata(client); |
| 373 | 457 | ||
| 374 | free_irq(ts->irq, ts); | 458 | free_irq(ts->irq, ts); |
| 375 | 459 | ||
| 376 | if (pdata->exit_platform_hw) | 460 | if (pdata && pdata->exit_platform_hw) |
| 377 | pdata->exit_platform_hw(); | 461 | pdata->exit_platform_hw(); |
| 378 | 462 | ||
| 379 | input_unregister_device(ts->input); | 463 | input_unregister_device(ts->input); |
| @@ -389,10 +473,19 @@ static const struct i2c_device_id tsc2007_idtable[] = { | |||
| 389 | 473 | ||
| 390 | MODULE_DEVICE_TABLE(i2c, tsc2007_idtable); | 474 | MODULE_DEVICE_TABLE(i2c, tsc2007_idtable); |
| 391 | 475 | ||
| 476 | #ifdef CONFIG_OF | ||
| 477 | static const struct of_device_id tsc2007_of_match[] = { | ||
| 478 | { .compatible = "ti,tsc2007" }, | ||
| 479 | { /* sentinel */ } | ||
| 480 | }; | ||
| 481 | MODULE_DEVICE_TABLE(of, tsc2007_of_match); | ||
| 482 | #endif | ||
| 483 | |||
| 392 | static struct i2c_driver tsc2007_driver = { | 484 | static struct i2c_driver tsc2007_driver = { |
| 393 | .driver = { | 485 | .driver = { |
| 394 | .owner = THIS_MODULE, | 486 | .owner = THIS_MODULE, |
| 395 | .name = "tsc2007" | 487 | .name = "tsc2007", |
| 488 | .of_match_table = of_match_ptr(tsc2007_of_match), | ||
| 396 | }, | 489 | }, |
| 397 | .id_table = tsc2007_idtable, | 490 | .id_table = tsc2007_idtable, |
| 398 | .probe = tsc2007_probe, | 491 | .probe = tsc2007_probe, |
