18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Hampshire serial touchscreen driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2010 Adam Bennett 68c2ecf20Sopenharmony_ci * Based on the dynapro driver (c) Tias Guns 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci/* 118c2ecf20Sopenharmony_ci * 2010/04/08 Adam Bennett <abennett72@gmail.com> 128c2ecf20Sopenharmony_ci * Copied dynapro.c and edited for Hampshire 4-byte protocol 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <linux/errno.h> 168c2ecf20Sopenharmony_ci#include <linux/kernel.h> 178c2ecf20Sopenharmony_ci#include <linux/module.h> 188c2ecf20Sopenharmony_ci#include <linux/slab.h> 198c2ecf20Sopenharmony_ci#include <linux/input.h> 208c2ecf20Sopenharmony_ci#include <linux/serio.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define DRIVER_DESC "Hampshire serial touchscreen driver" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ciMODULE_AUTHOR("Adam Bennett <abennett72@gmail.com>"); 258c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC); 268c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* 298c2ecf20Sopenharmony_ci * Definitions & global arrays. 308c2ecf20Sopenharmony_ci */ 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define HAMPSHIRE_FORMAT_TOUCH_BIT 0x40 338c2ecf20Sopenharmony_ci#define HAMPSHIRE_FORMAT_LENGTH 4 348c2ecf20Sopenharmony_ci#define HAMPSHIRE_RESPONSE_BEGIN_BYTE 0x80 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define HAMPSHIRE_MIN_XC 0 378c2ecf20Sopenharmony_ci#define HAMPSHIRE_MAX_XC 0x1000 388c2ecf20Sopenharmony_ci#define HAMPSHIRE_MIN_YC 0 398c2ecf20Sopenharmony_ci#define HAMPSHIRE_MAX_YC 0x1000 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#define HAMPSHIRE_GET_XC(data) (((data[3] & 0x0c) >> 2) | (data[1] << 2) | ((data[0] & 0x38) << 6)) 428c2ecf20Sopenharmony_ci#define HAMPSHIRE_GET_YC(data) ((data[3] & 0x03) | (data[2] << 2) | ((data[0] & 0x07) << 9)) 438c2ecf20Sopenharmony_ci#define HAMPSHIRE_GET_TOUCHED(data) (HAMPSHIRE_FORMAT_TOUCH_BIT & data[0]) 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/* 468c2ecf20Sopenharmony_ci * Per-touchscreen data. 478c2ecf20Sopenharmony_ci */ 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistruct hampshire { 508c2ecf20Sopenharmony_ci struct input_dev *dev; 518c2ecf20Sopenharmony_ci struct serio *serio; 528c2ecf20Sopenharmony_ci int idx; 538c2ecf20Sopenharmony_ci unsigned char data[HAMPSHIRE_FORMAT_LENGTH]; 548c2ecf20Sopenharmony_ci char phys[32]; 558c2ecf20Sopenharmony_ci}; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic void hampshire_process_data(struct hampshire *phampshire) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci struct input_dev *dev = phampshire->dev; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci if (HAMPSHIRE_FORMAT_LENGTH == ++phampshire->idx) { 628c2ecf20Sopenharmony_ci input_report_abs(dev, ABS_X, HAMPSHIRE_GET_XC(phampshire->data)); 638c2ecf20Sopenharmony_ci input_report_abs(dev, ABS_Y, HAMPSHIRE_GET_YC(phampshire->data)); 648c2ecf20Sopenharmony_ci input_report_key(dev, BTN_TOUCH, 658c2ecf20Sopenharmony_ci HAMPSHIRE_GET_TOUCHED(phampshire->data)); 668c2ecf20Sopenharmony_ci input_sync(dev); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci phampshire->idx = 0; 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic irqreturn_t hampshire_interrupt(struct serio *serio, 738c2ecf20Sopenharmony_ci unsigned char data, unsigned int flags) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci struct hampshire *phampshire = serio_get_drvdata(serio); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci phampshire->data[phampshire->idx] = data; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci if (HAMPSHIRE_RESPONSE_BEGIN_BYTE & phampshire->data[0]) 808c2ecf20Sopenharmony_ci hampshire_process_data(phampshire); 818c2ecf20Sopenharmony_ci else 828c2ecf20Sopenharmony_ci dev_dbg(&serio->dev, "unknown/unsynchronized data: %x\n", 838c2ecf20Sopenharmony_ci phampshire->data[0]); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci return IRQ_HANDLED; 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic void hampshire_disconnect(struct serio *serio) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci struct hampshire *phampshire = serio_get_drvdata(serio); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci input_get_device(phampshire->dev); 938c2ecf20Sopenharmony_ci input_unregister_device(phampshire->dev); 948c2ecf20Sopenharmony_ci serio_close(serio); 958c2ecf20Sopenharmony_ci serio_set_drvdata(serio, NULL); 968c2ecf20Sopenharmony_ci input_put_device(phampshire->dev); 978c2ecf20Sopenharmony_ci kfree(phampshire); 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci/* 1018c2ecf20Sopenharmony_ci * hampshire_connect() is the routine that is called when someone adds a 1028c2ecf20Sopenharmony_ci * new serio device that supports hampshire protocol and registers it as 1038c2ecf20Sopenharmony_ci * an input device. This is usually accomplished using inputattach. 1048c2ecf20Sopenharmony_ci */ 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic int hampshire_connect(struct serio *serio, struct serio_driver *drv) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci struct hampshire *phampshire; 1098c2ecf20Sopenharmony_ci struct input_dev *input_dev; 1108c2ecf20Sopenharmony_ci int err; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci phampshire = kzalloc(sizeof(struct hampshire), GFP_KERNEL); 1138c2ecf20Sopenharmony_ci input_dev = input_allocate_device(); 1148c2ecf20Sopenharmony_ci if (!phampshire || !input_dev) { 1158c2ecf20Sopenharmony_ci err = -ENOMEM; 1168c2ecf20Sopenharmony_ci goto fail1; 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci phampshire->serio = serio; 1208c2ecf20Sopenharmony_ci phampshire->dev = input_dev; 1218c2ecf20Sopenharmony_ci snprintf(phampshire->phys, sizeof(phampshire->phys), 1228c2ecf20Sopenharmony_ci "%s/input0", serio->phys); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci input_dev->name = "Hampshire Serial TouchScreen"; 1258c2ecf20Sopenharmony_ci input_dev->phys = phampshire->phys; 1268c2ecf20Sopenharmony_ci input_dev->id.bustype = BUS_RS232; 1278c2ecf20Sopenharmony_ci input_dev->id.vendor = SERIO_HAMPSHIRE; 1288c2ecf20Sopenharmony_ci input_dev->id.product = 0; 1298c2ecf20Sopenharmony_ci input_dev->id.version = 0x0001; 1308c2ecf20Sopenharmony_ci input_dev->dev.parent = &serio->dev; 1318c2ecf20Sopenharmony_ci input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); 1328c2ecf20Sopenharmony_ci input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); 1338c2ecf20Sopenharmony_ci input_set_abs_params(phampshire->dev, ABS_X, 1348c2ecf20Sopenharmony_ci HAMPSHIRE_MIN_XC, HAMPSHIRE_MAX_XC, 0, 0); 1358c2ecf20Sopenharmony_ci input_set_abs_params(phampshire->dev, ABS_Y, 1368c2ecf20Sopenharmony_ci HAMPSHIRE_MIN_YC, HAMPSHIRE_MAX_YC, 0, 0); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci serio_set_drvdata(serio, phampshire); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci err = serio_open(serio, drv); 1418c2ecf20Sopenharmony_ci if (err) 1428c2ecf20Sopenharmony_ci goto fail2; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci err = input_register_device(phampshire->dev); 1458c2ecf20Sopenharmony_ci if (err) 1468c2ecf20Sopenharmony_ci goto fail3; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci return 0; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci fail3: serio_close(serio); 1518c2ecf20Sopenharmony_ci fail2: serio_set_drvdata(serio, NULL); 1528c2ecf20Sopenharmony_ci fail1: input_free_device(input_dev); 1538c2ecf20Sopenharmony_ci kfree(phampshire); 1548c2ecf20Sopenharmony_ci return err; 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci/* 1588c2ecf20Sopenharmony_ci * The serio driver structure. 1598c2ecf20Sopenharmony_ci */ 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistatic const struct serio_device_id hampshire_serio_ids[] = { 1628c2ecf20Sopenharmony_ci { 1638c2ecf20Sopenharmony_ci .type = SERIO_RS232, 1648c2ecf20Sopenharmony_ci .proto = SERIO_HAMPSHIRE, 1658c2ecf20Sopenharmony_ci .id = SERIO_ANY, 1668c2ecf20Sopenharmony_ci .extra = SERIO_ANY, 1678c2ecf20Sopenharmony_ci }, 1688c2ecf20Sopenharmony_ci { 0 } 1698c2ecf20Sopenharmony_ci}; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(serio, hampshire_serio_ids); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic struct serio_driver hampshire_drv = { 1748c2ecf20Sopenharmony_ci .driver = { 1758c2ecf20Sopenharmony_ci .name = "hampshire", 1768c2ecf20Sopenharmony_ci }, 1778c2ecf20Sopenharmony_ci .description = DRIVER_DESC, 1788c2ecf20Sopenharmony_ci .id_table = hampshire_serio_ids, 1798c2ecf20Sopenharmony_ci .interrupt = hampshire_interrupt, 1808c2ecf20Sopenharmony_ci .connect = hampshire_connect, 1818c2ecf20Sopenharmony_ci .disconnect = hampshire_disconnect, 1828c2ecf20Sopenharmony_ci}; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cimodule_serio_driver(hampshire_drv); 185