170 lines · 4.6 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-only/* * Driver for simulating a mouse on GPIO lines. * * Copyright (C) 2007 Atmel Corporation * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org> */ #include <linux/module.h>#include <linux/platform_device.h>#include <linux/input.h>#include <linux/gpio/consumer.h>#include <linux/property.h>#include <linux/of.h> /** * struct gpio_mouse * @scan_ms: the scan interval in milliseconds. * @up: GPIO line for up value. * @down: GPIO line for down value. * @left: GPIO line for left value. * @right: GPIO line for right value. * @bleft: GPIO line for left button. * @bmiddle: GPIO line for middle button. * @bright: GPIO line for right button. * * This struct must be added to the platform_device in the board code. * It is used by the gpio_mouse driver to setup GPIO lines and to * calculate mouse movement. */struct gpio_mouse {	u32 scan_ms;	struct gpio_desc *up;	struct gpio_desc *down;	struct gpio_desc *left;	struct gpio_desc *right;	struct gpio_desc *bleft;	struct gpio_desc *bmiddle;	struct gpio_desc *bright;}; /* * Timer function which is run every scan_ms ms when the device is opened. * The dev input variable is set to the input_dev pointer. */static void gpio_mouse_scan(struct input_dev *input){	struct gpio_mouse *gpio = input_get_drvdata(input);	int x, y; 	if (gpio->bleft)		input_report_key(input, BTN_LEFT,				 gpiod_get_value(gpio->bleft));	if (gpio->bmiddle)		input_report_key(input, BTN_MIDDLE,				 gpiod_get_value(gpio->bmiddle));	if (gpio->bright)		input_report_key(input, BTN_RIGHT,				 gpiod_get_value(gpio->bright)); 	x = gpiod_get_value(gpio->right) - gpiod_get_value(gpio->left);	y = gpiod_get_value(gpio->down) - gpiod_get_value(gpio->up); 	input_report_rel(input, REL_X, x);	input_report_rel(input, REL_Y, y);	input_sync(input);} static int gpio_mouse_probe(struct platform_device *pdev){	struct device *dev = &pdev->dev;	struct gpio_mouse *gmouse;	struct input_dev *input;	int error; 	gmouse = devm_kzalloc(dev, sizeof(*gmouse), GFP_KERNEL);	if (!gmouse)		return -ENOMEM; 	/* Assign some default scanning time */	error = device_property_read_u32(dev, "scan-interval-ms",					 &gmouse->scan_ms);	if (error || gmouse->scan_ms == 0) {		dev_warn(dev, "invalid scan time, set to 50 ms\n");		gmouse->scan_ms = 50;	} 	gmouse->up = devm_gpiod_get(dev, "up", GPIOD_IN);	if (IS_ERR(gmouse->up))		return PTR_ERR(gmouse->up);	gmouse->down = devm_gpiod_get(dev, "down", GPIOD_IN);	if (IS_ERR(gmouse->down))		return PTR_ERR(gmouse->down);	gmouse->left = devm_gpiod_get(dev, "left", GPIOD_IN);	if (IS_ERR(gmouse->left))		return PTR_ERR(gmouse->left);	gmouse->right = devm_gpiod_get(dev, "right", GPIOD_IN);	if (IS_ERR(gmouse->right))		return PTR_ERR(gmouse->right); 	gmouse->bleft = devm_gpiod_get_optional(dev, "button-left", GPIOD_IN);	if (IS_ERR(gmouse->bleft))		return PTR_ERR(gmouse->bleft);	gmouse->bmiddle = devm_gpiod_get_optional(dev, "button-middle",						  GPIOD_IN);	if (IS_ERR(gmouse->bmiddle))		return PTR_ERR(gmouse->bmiddle);	gmouse->bright = devm_gpiod_get_optional(dev, "button-right",						 GPIOD_IN);	if (IS_ERR(gmouse->bright))		return PTR_ERR(gmouse->bright); 	input = devm_input_allocate_device(dev);	if (!input)		return -ENOMEM; 	input->name = pdev->name;	input->id.bustype = BUS_HOST; 	input_set_drvdata(input, gmouse); 	input_set_capability(input, EV_REL, REL_X);	input_set_capability(input, EV_REL, REL_Y);	if (gmouse->bleft)		input_set_capability(input, EV_KEY, BTN_LEFT);	if (gmouse->bmiddle)		input_set_capability(input, EV_KEY, BTN_MIDDLE);	if (gmouse->bright)		input_set_capability(input, EV_KEY, BTN_RIGHT); 	error = input_setup_polling(input, gpio_mouse_scan);	if (error)		return error; 	input_set_poll_interval(input, gmouse->scan_ms); 	error = input_register_device(input);	if (error) {		dev_err(dev, "could not register input device\n");		return error;	} 	dev_dbg(dev, "%d ms scan time, buttons: %s%s%s\n",		gmouse->scan_ms,		gmouse->bleft ? "" : "left ",		gmouse->bmiddle ? "" : "middle ",		gmouse->bright ? "" : "right"); 	return 0;} static const struct of_device_id gpio_mouse_of_match[] = {	{ .compatible = "gpio-mouse", },	{ },};MODULE_DEVICE_TABLE(of, gpio_mouse_of_match); static struct platform_driver gpio_mouse_device_driver = {	.probe		= gpio_mouse_probe,	.driver		= {		.name	= "gpio_mouse",		.of_match_table = gpio_mouse_of_match,	}};module_platform_driver(gpio_mouse_device_driver); MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>");MODULE_DESCRIPTION("GPIO mouse driver");MODULE_LICENSE("GPL");MODULE_ALIAS("platform:gpio_mouse"); /* work with hotplug and coldplug */