xref: /linux/drivers/input/touchscreen/fujitsu_ts.c (revision d2912cb15bdda8ba4a5dd73396ad62641af2f520)
1*d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
285f202d5SDmitry Torokhov /*
385f202d5SDmitry Torokhov  * Fujitsu serial touchscreen driver
485f202d5SDmitry Torokhov  *
585f202d5SDmitry Torokhov  * Copyright (c) Dmitry Torokhov <dtor@mail.ru>
685f202d5SDmitry Torokhov  */
785f202d5SDmitry Torokhov 
885f202d5SDmitry Torokhov 
985f202d5SDmitry Torokhov #include <linux/errno.h>
1085f202d5SDmitry Torokhov #include <linux/kernel.h>
1185f202d5SDmitry Torokhov #include <linux/module.h>
1285f202d5SDmitry Torokhov #include <linux/slab.h>
1385f202d5SDmitry Torokhov #include <linux/input.h>
1485f202d5SDmitry Torokhov #include <linux/serio.h>
1585f202d5SDmitry Torokhov 
1685f202d5SDmitry Torokhov #define DRIVER_DESC	"Fujitsu serial touchscreen driver"
1785f202d5SDmitry Torokhov 
1885f202d5SDmitry Torokhov MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
1985f202d5SDmitry Torokhov MODULE_DESCRIPTION(DRIVER_DESC);
2085f202d5SDmitry Torokhov MODULE_LICENSE("GPL");
2185f202d5SDmitry Torokhov 
2285f202d5SDmitry Torokhov #define FUJITSU_LENGTH 5
2385f202d5SDmitry Torokhov 
2485f202d5SDmitry Torokhov /*
2585f202d5SDmitry Torokhov  * Per-touchscreen data.
2685f202d5SDmitry Torokhov  */
2785f202d5SDmitry Torokhov struct fujitsu {
2885f202d5SDmitry Torokhov 	struct input_dev *dev;
2985f202d5SDmitry Torokhov 	struct serio *serio;
3085f202d5SDmitry Torokhov 	int idx;
3185f202d5SDmitry Torokhov 	unsigned char data[FUJITSU_LENGTH];
3285f202d5SDmitry Torokhov 	char phys[32];
3385f202d5SDmitry Torokhov };
3485f202d5SDmitry Torokhov 
3585f202d5SDmitry Torokhov /*
3685f202d5SDmitry Torokhov  * Decode serial data (5 bytes per packet)
3785f202d5SDmitry Torokhov  * First byte
3885f202d5SDmitry Torokhov  * 1 C 0 0 R S S S
3985f202d5SDmitry Torokhov  * Where C is 1 while in calibration mode (which we don't use)
4085f202d5SDmitry Torokhov  * R is 1 when no coordinate corection was done.
4185f202d5SDmitry Torokhov  * S are button state
4285f202d5SDmitry Torokhov  */
4385f202d5SDmitry Torokhov static irqreturn_t fujitsu_interrupt(struct serio *serio,
4485f202d5SDmitry Torokhov 				     unsigned char data, unsigned int flags)
4585f202d5SDmitry Torokhov {
4685f202d5SDmitry Torokhov 	struct fujitsu *fujitsu = serio_get_drvdata(serio);
4785f202d5SDmitry Torokhov 	struct input_dev *dev = fujitsu->dev;
4885f202d5SDmitry Torokhov 
4985f202d5SDmitry Torokhov 	if (fujitsu->idx == 0) {
5085f202d5SDmitry Torokhov 		/* resync skip until start of frame */
5185f202d5SDmitry Torokhov 		if ((data & 0xf0) != 0x80)
5285f202d5SDmitry Torokhov 			return IRQ_HANDLED;
5385f202d5SDmitry Torokhov 	} else {
5485f202d5SDmitry Torokhov 		/* resync skip garbage */
5585f202d5SDmitry Torokhov 		if (data & 0x80) {
5685f202d5SDmitry Torokhov 			fujitsu->idx = 0;
5785f202d5SDmitry Torokhov 			return IRQ_HANDLED;
5885f202d5SDmitry Torokhov 		}
5985f202d5SDmitry Torokhov 	}
6085f202d5SDmitry Torokhov 
6185f202d5SDmitry Torokhov 	fujitsu->data[fujitsu->idx++] = data;
6285f202d5SDmitry Torokhov 	if (fujitsu->idx == FUJITSU_LENGTH) {
6385f202d5SDmitry Torokhov 		input_report_abs(dev, ABS_X,
6485f202d5SDmitry Torokhov 				 (fujitsu->data[2] << 7) | fujitsu->data[1]);
6585f202d5SDmitry Torokhov 		input_report_abs(dev, ABS_Y,
6685f202d5SDmitry Torokhov 				 (fujitsu->data[4] << 7) | fujitsu->data[3]);
6785f202d5SDmitry Torokhov 		input_report_key(dev, BTN_TOUCH,
6885f202d5SDmitry Torokhov 				 (fujitsu->data[0] & 0x03) != 2);
6985f202d5SDmitry Torokhov 		input_sync(dev);
7085f202d5SDmitry Torokhov 		fujitsu->idx = 0;
7185f202d5SDmitry Torokhov 	}
7285f202d5SDmitry Torokhov 
7385f202d5SDmitry Torokhov 	return IRQ_HANDLED;
7485f202d5SDmitry Torokhov }
7585f202d5SDmitry Torokhov 
7685f202d5SDmitry Torokhov /*
7785f202d5SDmitry Torokhov  * fujitsu_disconnect() is the opposite of fujitsu_connect()
7885f202d5SDmitry Torokhov  */
7985f202d5SDmitry Torokhov static void fujitsu_disconnect(struct serio *serio)
8085f202d5SDmitry Torokhov {
8185f202d5SDmitry Torokhov 	struct fujitsu *fujitsu = serio_get_drvdata(serio);
8285f202d5SDmitry Torokhov 
8385f202d5SDmitry Torokhov 	input_get_device(fujitsu->dev);
8485f202d5SDmitry Torokhov 	input_unregister_device(fujitsu->dev);
8585f202d5SDmitry Torokhov 	serio_close(serio);
8685f202d5SDmitry Torokhov 	serio_set_drvdata(serio, NULL);
8785f202d5SDmitry Torokhov 	input_put_device(fujitsu->dev);
8885f202d5SDmitry Torokhov 	kfree(fujitsu);
8985f202d5SDmitry Torokhov }
9085f202d5SDmitry Torokhov 
9185f202d5SDmitry Torokhov /*
9285f202d5SDmitry Torokhov  * fujitsu_connect() is the routine that is called when someone adds a
9385f202d5SDmitry Torokhov  * new serio device that supports the Fujitsu protocol and registers it
9485f202d5SDmitry Torokhov  * as input device.
9585f202d5SDmitry Torokhov  */
9685f202d5SDmitry Torokhov static int fujitsu_connect(struct serio *serio, struct serio_driver *drv)
9785f202d5SDmitry Torokhov {
9885f202d5SDmitry Torokhov 	struct fujitsu *fujitsu;
9985f202d5SDmitry Torokhov 	struct input_dev *input_dev;
10085f202d5SDmitry Torokhov 	int err;
10185f202d5SDmitry Torokhov 
10285f202d5SDmitry Torokhov 	fujitsu = kzalloc(sizeof(struct fujitsu), GFP_KERNEL);
10385f202d5SDmitry Torokhov 	input_dev = input_allocate_device();
10485f202d5SDmitry Torokhov 	if (!fujitsu || !input_dev) {
10585f202d5SDmitry Torokhov 		err = -ENOMEM;
10685f202d5SDmitry Torokhov 		goto fail1;
10785f202d5SDmitry Torokhov 	}
10885f202d5SDmitry Torokhov 
10985f202d5SDmitry Torokhov 	fujitsu->serio = serio;
11085f202d5SDmitry Torokhov 	fujitsu->dev = input_dev;
11185f202d5SDmitry Torokhov 	snprintf(fujitsu->phys, sizeof(fujitsu->phys),
11285f202d5SDmitry Torokhov 		 "%s/input0", serio->phys);
11385f202d5SDmitry Torokhov 
11485f202d5SDmitry Torokhov 	input_dev->name = "Fujitsu Serial Touchscreen";
11585f202d5SDmitry Torokhov 	input_dev->phys = fujitsu->phys;
11685f202d5SDmitry Torokhov 	input_dev->id.bustype = BUS_RS232;
11785f202d5SDmitry Torokhov 	input_dev->id.vendor = SERIO_FUJITSU;
11885f202d5SDmitry Torokhov 	input_dev->id.product = 0;
11985f202d5SDmitry Torokhov 	input_dev->id.version = 0x0100;
1207b19ada2SJiri Slaby 	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
1217b19ada2SJiri Slaby 	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
12285f202d5SDmitry Torokhov 
12385f202d5SDmitry Torokhov 	input_set_abs_params(input_dev, ABS_X, 0, 4096, 0, 0);
12485f202d5SDmitry Torokhov 	input_set_abs_params(input_dev, ABS_Y, 0, 4096, 0, 0);
12585f202d5SDmitry Torokhov 	serio_set_drvdata(serio, fujitsu);
12685f202d5SDmitry Torokhov 
12785f202d5SDmitry Torokhov 	err = serio_open(serio, drv);
12885f202d5SDmitry Torokhov 	if (err)
12985f202d5SDmitry Torokhov 		goto fail2;
13085f202d5SDmitry Torokhov 
13185f202d5SDmitry Torokhov 	err = input_register_device(fujitsu->dev);
13285f202d5SDmitry Torokhov 	if (err)
13385f202d5SDmitry Torokhov 		goto fail3;
13485f202d5SDmitry Torokhov 
13585f202d5SDmitry Torokhov 	return 0;
13685f202d5SDmitry Torokhov 
13785f202d5SDmitry Torokhov  fail3:
13885f202d5SDmitry Torokhov 	serio_close(serio);
13985f202d5SDmitry Torokhov  fail2:
14085f202d5SDmitry Torokhov 	serio_set_drvdata(serio, NULL);
14185f202d5SDmitry Torokhov  fail1:
14285f202d5SDmitry Torokhov 	input_free_device(input_dev);
14385f202d5SDmitry Torokhov 	kfree(fujitsu);
14485f202d5SDmitry Torokhov 	return err;
14585f202d5SDmitry Torokhov }
14685f202d5SDmitry Torokhov 
14785f202d5SDmitry Torokhov /*
14885f202d5SDmitry Torokhov  * The serio driver structure.
14985f202d5SDmitry Torokhov  */
1500e2ba64eSArvind Yadav static const struct serio_device_id fujitsu_serio_ids[] = {
15185f202d5SDmitry Torokhov 	{
15285f202d5SDmitry Torokhov 		.type	= SERIO_RS232,
15385f202d5SDmitry Torokhov 		.proto	= SERIO_FUJITSU,
15485f202d5SDmitry Torokhov 		.id	= SERIO_ANY,
15585f202d5SDmitry Torokhov 		.extra	= SERIO_ANY,
15685f202d5SDmitry Torokhov 	},
15785f202d5SDmitry Torokhov 	{ 0 }
15885f202d5SDmitry Torokhov };
15985f202d5SDmitry Torokhov 
16085f202d5SDmitry Torokhov MODULE_DEVICE_TABLE(serio, fujitsu_serio_ids);
16185f202d5SDmitry Torokhov 
16285f202d5SDmitry Torokhov static struct serio_driver fujitsu_drv = {
16385f202d5SDmitry Torokhov 	.driver		= {
16485f202d5SDmitry Torokhov 		.name	= "fujitsu_ts",
16585f202d5SDmitry Torokhov 	},
16685f202d5SDmitry Torokhov 	.description	= DRIVER_DESC,
16785f202d5SDmitry Torokhov 	.id_table	= fujitsu_serio_ids,
16885f202d5SDmitry Torokhov 	.interrupt	= fujitsu_interrupt,
16985f202d5SDmitry Torokhov 	.connect	= fujitsu_connect,
17085f202d5SDmitry Torokhov 	.disconnect	= fujitsu_disconnect,
17185f202d5SDmitry Torokhov };
17285f202d5SDmitry Torokhov 
17365ac9f7aSAxel Lin module_serio_driver(fujitsu_drv);
174