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 49f348f329SDmitry Torokhov static void micro_ts_toggle_receive(struct touchscreen_data *ts, bool enable) 50f348f329SDmitry Torokhov { 51f348f329SDmitry Torokhov struct ipaq_micro *micro = ts->micro; 52f348f329SDmitry Torokhov 53f348f329SDmitry Torokhov spin_lock_irq(µ->lock); 54f348f329SDmitry Torokhov 55f348f329SDmitry Torokhov if (enable) { 56f348f329SDmitry Torokhov micro->ts = micro_ts_receive; 57f348f329SDmitry Torokhov micro->ts_data = ts; 58f348f329SDmitry Torokhov } else { 59f348f329SDmitry Torokhov micro->ts = NULL; 60f348f329SDmitry Torokhov micro->ts_data = NULL; 61f348f329SDmitry Torokhov } 62f348f329SDmitry Torokhov 63f348f329SDmitry Torokhov spin_unlock_irq(&ts->micro->lock); 64f348f329SDmitry Torokhov } 65f348f329SDmitry Torokhov 66f348f329SDmitry Torokhov static int micro_ts_open(struct input_dev *input) 67f348f329SDmitry Torokhov { 68f348f329SDmitry Torokhov struct touchscreen_data *ts = input_get_drvdata(input); 69f348f329SDmitry Torokhov 70f348f329SDmitry Torokhov micro_ts_toggle_receive(ts, true); 71f348f329SDmitry Torokhov 72f348f329SDmitry Torokhov return 0; 73f348f329SDmitry Torokhov } 74f348f329SDmitry Torokhov 75f348f329SDmitry Torokhov static void micro_ts_close(struct input_dev *input) 76f348f329SDmitry Torokhov { 77f348f329SDmitry Torokhov struct touchscreen_data *ts = input_get_drvdata(input); 78f348f329SDmitry Torokhov 79f348f329SDmitry Torokhov micro_ts_toggle_receive(ts, false); 80f348f329SDmitry Torokhov } 81f348f329SDmitry Torokhov 823ea7e551SDmitry Artamonow static int micro_ts_probe(struct platform_device *pdev) 833ea7e551SDmitry Artamonow { 84f348f329SDmitry Torokhov struct ipaq_micro *micro = dev_get_drvdata(pdev->dev.parent); 853ea7e551SDmitry Artamonow struct touchscreen_data *ts; 86f348f329SDmitry Torokhov int error; 873ea7e551SDmitry Artamonow 883ea7e551SDmitry Artamonow ts = devm_kzalloc(&pdev->dev, sizeof(*ts), GFP_KERNEL); 893ea7e551SDmitry Artamonow if (!ts) 903ea7e551SDmitry Artamonow return -ENOMEM; 913ea7e551SDmitry Artamonow 92f348f329SDmitry Torokhov ts->micro = micro; 933ea7e551SDmitry Artamonow 943ea7e551SDmitry Artamonow ts->input = devm_input_allocate_device(&pdev->dev); 953ea7e551SDmitry Artamonow if (!ts->input) { 963ea7e551SDmitry Artamonow dev_err(&pdev->dev, "failed to allocate input device\n"); 973ea7e551SDmitry Artamonow return -ENOMEM; 983ea7e551SDmitry Artamonow } 993ea7e551SDmitry Artamonow 100f348f329SDmitry Torokhov ts->input->name = "ipaq micro ts"; 101f348f329SDmitry Torokhov ts->input->open = micro_ts_open; 102f348f329SDmitry Torokhov ts->input->close = micro_ts_close; 103f348f329SDmitry Torokhov 104f348f329SDmitry Torokhov input_set_drvdata(ts->input, ts); 105f348f329SDmitry Torokhov 1063ea7e551SDmitry Artamonow input_set_capability(ts->input, EV_KEY, BTN_TOUCH); 1073ea7e551SDmitry Artamonow input_set_capability(ts->input, EV_ABS, ABS_X); 1083ea7e551SDmitry Artamonow input_set_capability(ts->input, EV_ABS, ABS_Y); 1093ea7e551SDmitry Artamonow input_set_abs_params(ts->input, ABS_X, 0, 1023, 0, 0); 1103ea7e551SDmitry Artamonow input_set_abs_params(ts->input, ABS_Y, 0, 1023, 0, 0); 1113ea7e551SDmitry Artamonow 112f348f329SDmitry Torokhov error = input_register_device(ts->input); 113f348f329SDmitry Torokhov if (error) { 1143ea7e551SDmitry Artamonow dev_err(&pdev->dev, "error registering touch input\n"); 115f348f329SDmitry Torokhov return error; 1163ea7e551SDmitry Artamonow } 1173ea7e551SDmitry Artamonow 118f348f329SDmitry Torokhov platform_set_drvdata(pdev, ts); 1193ea7e551SDmitry Artamonow 1203ea7e551SDmitry Artamonow dev_info(&pdev->dev, "iPAQ micro touchscreen\n"); 1213ea7e551SDmitry Artamonow 1223ea7e551SDmitry Artamonow return 0; 1233ea7e551SDmitry Artamonow } 1243ea7e551SDmitry Artamonow 1253ea7e551SDmitry Artamonow #ifdef CONFIG_PM_SLEEP 1263ea7e551SDmitry Artamonow static int micro_ts_suspend(struct device *dev) 1273ea7e551SDmitry Artamonow { 1283ea7e551SDmitry Artamonow struct touchscreen_data *ts = dev_get_drvdata(dev); 1293ea7e551SDmitry Artamonow 130f348f329SDmitry Torokhov micro_ts_toggle_receive(ts, false); 131f348f329SDmitry Torokhov 1323ea7e551SDmitry Artamonow return 0; 1333ea7e551SDmitry Artamonow } 1343ea7e551SDmitry Artamonow 1353ea7e551SDmitry Artamonow static int micro_ts_resume(struct device *dev) 1363ea7e551SDmitry Artamonow { 1373ea7e551SDmitry Artamonow struct touchscreen_data *ts = dev_get_drvdata(dev); 138f348f329SDmitry Torokhov struct input_dev *input = ts->input; 1393ea7e551SDmitry Artamonow 140f348f329SDmitry Torokhov mutex_lock(&input->mutex); 141f348f329SDmitry Torokhov 142f348f329SDmitry Torokhov if (input->users) 143f348f329SDmitry Torokhov micro_ts_toggle_receive(ts, true); 144f348f329SDmitry Torokhov 145f348f329SDmitry Torokhov mutex_unlock(&input->mutex); 146f348f329SDmitry Torokhov 1473ea7e551SDmitry Artamonow return 0; 1483ea7e551SDmitry Artamonow } 1493ea7e551SDmitry Artamonow #endif 1503ea7e551SDmitry Artamonow 1513ea7e551SDmitry Artamonow static const struct dev_pm_ops micro_ts_dev_pm_ops = { 1523ea7e551SDmitry Artamonow SET_SYSTEM_SLEEP_PM_OPS(micro_ts_suspend, micro_ts_resume) 1533ea7e551SDmitry Artamonow }; 1543ea7e551SDmitry Artamonow 1553ea7e551SDmitry Artamonow static struct platform_driver micro_ts_device_driver = { 1563ea7e551SDmitry Artamonow .driver = { 1573ea7e551SDmitry Artamonow .name = "ipaq-micro-ts", 1583ea7e551SDmitry Artamonow .pm = µ_ts_dev_pm_ops, 1593ea7e551SDmitry Artamonow }, 1603ea7e551SDmitry Artamonow .probe = micro_ts_probe, 1613ea7e551SDmitry Artamonow }; 1623ea7e551SDmitry Artamonow module_platform_driver(micro_ts_device_driver); 1633ea7e551SDmitry Artamonow 1643ea7e551SDmitry Artamonow MODULE_LICENSE("GPL"); 1653ea7e551SDmitry Artamonow MODULE_DESCRIPTION("driver for iPAQ Atmel micro touchscreen"); 1663ea7e551SDmitry Artamonow MODULE_ALIAS("platform:ipaq-micro-ts"); 167