13ea7e551SDmitry Artamonow /* 23ea7e551SDmitry Artamonow * This program is free software; you can redistribute it and/or modify 33ea7e551SDmitry Artamonow * it under the terms of the GNU General Public License version 2 as 43ea7e551SDmitry Artamonow * published by the Free Software Foundation. 53ea7e551SDmitry Artamonow * 63ea7e551SDmitry Artamonow * h3600 atmel micro companion support, touchscreen subdevice 73ea7e551SDmitry Artamonow * Author : Alessandro Gardich <gremlin@gremlin.it> 83ea7e551SDmitry Artamonow * Author : Dmitry Artamonow <mad_soft@inbox.ru> 93ea7e551SDmitry Artamonow * Author : Linus Walleij <linus.walleij@linaro.org> 103ea7e551SDmitry Artamonow * 113ea7e551SDmitry Artamonow */ 123ea7e551SDmitry Artamonow 133ea7e551SDmitry Artamonow #include <asm/byteorder.h> 143ea7e551SDmitry Artamonow #include <linux/module.h> 153ea7e551SDmitry Artamonow #include <linux/init.h> 163ea7e551SDmitry Artamonow #include <linux/interrupt.h> 173ea7e551SDmitry Artamonow #include <linux/pm.h> 183ea7e551SDmitry Artamonow #include <linux/delay.h> 193ea7e551SDmitry Artamonow #include <linux/device.h> 203ea7e551SDmitry Artamonow #include <linux/input.h> 213ea7e551SDmitry Artamonow #include <linux/platform_device.h> 223ea7e551SDmitry Artamonow #include <linux/slab.h> 233ea7e551SDmitry Artamonow #include <linux/mfd/ipaq-micro.h> 243ea7e551SDmitry Artamonow 253ea7e551SDmitry Artamonow struct touchscreen_data { 263ea7e551SDmitry Artamonow struct input_dev *input; 273ea7e551SDmitry Artamonow struct ipaq_micro *micro; 283ea7e551SDmitry Artamonow }; 293ea7e551SDmitry Artamonow 303ea7e551SDmitry Artamonow static void micro_ts_receive(void *data, int len, unsigned char *msg) 313ea7e551SDmitry Artamonow { 323ea7e551SDmitry Artamonow struct touchscreen_data *ts = data; 333ea7e551SDmitry Artamonow 343ea7e551SDmitry Artamonow if (len == 4) { 353ea7e551SDmitry Artamonow input_report_abs(ts->input, ABS_X, 363ea7e551SDmitry Artamonow be16_to_cpup((__be16 *) &msg[2])); 373ea7e551SDmitry Artamonow input_report_abs(ts->input, ABS_Y, 383ea7e551SDmitry Artamonow be16_to_cpup((__be16 *) &msg[0])); 393ea7e551SDmitry Artamonow input_report_key(ts->input, BTN_TOUCH, 1); 403ea7e551SDmitry Artamonow input_sync(ts->input); 413ea7e551SDmitry Artamonow } else if (len == 0) { 423ea7e551SDmitry Artamonow input_report_abs(ts->input, ABS_X, 0); 433ea7e551SDmitry Artamonow input_report_abs(ts->input, ABS_Y, 0); 443ea7e551SDmitry Artamonow input_report_key(ts->input, BTN_TOUCH, 0); 453ea7e551SDmitry Artamonow input_sync(ts->input); 463ea7e551SDmitry Artamonow } 473ea7e551SDmitry Artamonow } 483ea7e551SDmitry Artamonow 493ea7e551SDmitry Artamonow static int micro_ts_probe(struct platform_device *pdev) 503ea7e551SDmitry Artamonow { 513ea7e551SDmitry Artamonow struct touchscreen_data *ts; 523ea7e551SDmitry Artamonow int ret; 533ea7e551SDmitry Artamonow 543ea7e551SDmitry Artamonow ts = devm_kzalloc(&pdev->dev, sizeof(*ts), GFP_KERNEL); 553ea7e551SDmitry Artamonow if (!ts) 563ea7e551SDmitry Artamonow return -ENOMEM; 573ea7e551SDmitry Artamonow ts->micro = dev_get_drvdata(pdev->dev.parent); 583ea7e551SDmitry Artamonow 593ea7e551SDmitry Artamonow platform_set_drvdata(pdev, ts); 603ea7e551SDmitry Artamonow 613ea7e551SDmitry Artamonow ts->input = devm_input_allocate_device(&pdev->dev); 623ea7e551SDmitry Artamonow if (!ts->input) { 633ea7e551SDmitry Artamonow dev_err(&pdev->dev, "failed to allocate input device\n"); 643ea7e551SDmitry Artamonow return -ENOMEM; 653ea7e551SDmitry Artamonow } 663ea7e551SDmitry Artamonow 673ea7e551SDmitry Artamonow input_set_capability(ts->input, EV_KEY, BTN_TOUCH); 683ea7e551SDmitry Artamonow input_set_capability(ts->input, EV_ABS, ABS_X); 693ea7e551SDmitry Artamonow input_set_capability(ts->input, EV_ABS, ABS_Y); 703ea7e551SDmitry Artamonow input_set_abs_params(ts->input, ABS_X, 0, 1023, 0, 0); 713ea7e551SDmitry Artamonow input_set_abs_params(ts->input, ABS_Y, 0, 1023, 0, 0); 723ea7e551SDmitry Artamonow 733ea7e551SDmitry Artamonow ts->input->name = "ipaq micro ts"; 743ea7e551SDmitry Artamonow 753ea7e551SDmitry Artamonow ret = input_register_device(ts->input); 763ea7e551SDmitry Artamonow if (ret) { 773ea7e551SDmitry Artamonow dev_err(&pdev->dev, "error registering touch input\n"); 783ea7e551SDmitry Artamonow return ret; 793ea7e551SDmitry Artamonow } 803ea7e551SDmitry Artamonow 813ea7e551SDmitry Artamonow spin_lock_irq(&ts->micro->lock); 823ea7e551SDmitry Artamonow ts->micro->ts = micro_ts_receive; 833ea7e551SDmitry Artamonow ts->micro->ts_data = ts; 843ea7e551SDmitry Artamonow spin_unlock_irq(&ts->micro->lock); 853ea7e551SDmitry Artamonow 863ea7e551SDmitry Artamonow dev_info(&pdev->dev, "iPAQ micro touchscreen\n"); 873ea7e551SDmitry Artamonow return 0; 883ea7e551SDmitry Artamonow } 893ea7e551SDmitry Artamonow 903ea7e551SDmitry Artamonow static int micro_ts_remove(struct platform_device *pdev) 913ea7e551SDmitry Artamonow { 923ea7e551SDmitry Artamonow struct touchscreen_data *ts = platform_get_drvdata(pdev); 933ea7e551SDmitry Artamonow 943ea7e551SDmitry Artamonow spin_lock_irq(&ts->micro->lock); 953ea7e551SDmitry Artamonow ts->micro->ts = NULL; 963ea7e551SDmitry Artamonow ts->micro->ts_data = NULL; 973ea7e551SDmitry Artamonow spin_unlock_irq(&ts->micro->lock); 983ea7e551SDmitry Artamonow 993ea7e551SDmitry Artamonow return 0; 1003ea7e551SDmitry Artamonow } 1013ea7e551SDmitry Artamonow 1023ea7e551SDmitry Artamonow #ifdef CONFIG_PM_SLEEP 1033ea7e551SDmitry Artamonow static int micro_ts_suspend(struct device *dev) 1043ea7e551SDmitry Artamonow { 1053ea7e551SDmitry Artamonow struct touchscreen_data *ts = dev_get_drvdata(dev); 1063ea7e551SDmitry Artamonow 1073ea7e551SDmitry Artamonow spin_lock_irq(&ts->micro->lock); 1083ea7e551SDmitry Artamonow ts->micro->ts = NULL; 1093ea7e551SDmitry Artamonow ts->micro->ts_data = NULL; 1103ea7e551SDmitry Artamonow spin_unlock_irq(&ts->micro->lock); 1113ea7e551SDmitry Artamonow return 0; 1123ea7e551SDmitry Artamonow } 1133ea7e551SDmitry Artamonow 1143ea7e551SDmitry Artamonow static int micro_ts_resume(struct device *dev) 1153ea7e551SDmitry Artamonow { 1163ea7e551SDmitry Artamonow struct touchscreen_data *ts = dev_get_drvdata(dev); 1173ea7e551SDmitry Artamonow 1183ea7e551SDmitry Artamonow spin_lock_irq(&ts->micro->lock); 1193ea7e551SDmitry Artamonow ts->micro->ts = micro_ts_receive; 1203ea7e551SDmitry Artamonow ts->micro->ts_data = ts; 1213ea7e551SDmitry Artamonow spin_unlock_irq(&ts->micro->lock); 1223ea7e551SDmitry Artamonow return 0; 1233ea7e551SDmitry Artamonow } 1243ea7e551SDmitry Artamonow #endif 1253ea7e551SDmitry Artamonow 1263ea7e551SDmitry Artamonow static const struct dev_pm_ops micro_ts_dev_pm_ops = { 1273ea7e551SDmitry Artamonow SET_SYSTEM_SLEEP_PM_OPS(micro_ts_suspend, micro_ts_resume) 1283ea7e551SDmitry Artamonow }; 1293ea7e551SDmitry Artamonow 1303ea7e551SDmitry Artamonow static struct platform_driver micro_ts_device_driver = { 1313ea7e551SDmitry Artamonow .driver = { 1323ea7e551SDmitry Artamonow .name = "ipaq-micro-ts", 1333ea7e551SDmitry Artamonow .pm = µ_ts_dev_pm_ops, 1343ea7e551SDmitry Artamonow }, 1353ea7e551SDmitry Artamonow .probe = micro_ts_probe, 1363ea7e551SDmitry Artamonow .remove = micro_ts_remove, 1373ea7e551SDmitry Artamonow }; 1383ea7e551SDmitry Artamonow module_platform_driver(micro_ts_device_driver); 1393ea7e551SDmitry Artamonow 1403ea7e551SDmitry Artamonow MODULE_LICENSE("GPL"); 1413ea7e551SDmitry Artamonow MODULE_DESCRIPTION("driver for iPAQ Atmel micro touchscreen"); 1423ea7e551SDmitry Artamonow MODULE_ALIAS("platform:ipaq-micro-ts"); 143