1*5f565502SHans-Christian Egtvedt /* 2*5f565502SHans-Christian Egtvedt * Driver for simulating a mouse on GPIO lines. 3*5f565502SHans-Christian Egtvedt * 4*5f565502SHans-Christian Egtvedt * Copyright (C) 2007 Atmel Corporation 5*5f565502SHans-Christian Egtvedt * 6*5f565502SHans-Christian Egtvedt * This program is free software; you can redistribute it and/or modify 7*5f565502SHans-Christian Egtvedt * it under the terms of the GNU General Public License version 2 as 8*5f565502SHans-Christian Egtvedt * published by the Free Software Foundation. 9*5f565502SHans-Christian Egtvedt */ 10*5f565502SHans-Christian Egtvedt 11*5f565502SHans-Christian Egtvedt #include <linux/init.h> 12*5f565502SHans-Christian Egtvedt #include <linux/version.h> 13*5f565502SHans-Christian Egtvedt #include <linux/module.h> 14*5f565502SHans-Christian Egtvedt #include <linux/platform_device.h> 15*5f565502SHans-Christian Egtvedt #include <linux/input-polldev.h> 16*5f565502SHans-Christian Egtvedt #include <linux/gpio_mouse.h> 17*5f565502SHans-Christian Egtvedt 18*5f565502SHans-Christian Egtvedt #include <asm/gpio.h> 19*5f565502SHans-Christian Egtvedt 20*5f565502SHans-Christian Egtvedt /* 21*5f565502SHans-Christian Egtvedt * Timer function which is run every scan_ms ms when the device is opened. 22*5f565502SHans-Christian Egtvedt * The dev input varaible is set to the the input_dev pointer. 23*5f565502SHans-Christian Egtvedt */ 24*5f565502SHans-Christian Egtvedt static void gpio_mouse_scan(struct input_polled_dev *dev) 25*5f565502SHans-Christian Egtvedt { 26*5f565502SHans-Christian Egtvedt struct gpio_mouse_platform_data *gpio = dev->private; 27*5f565502SHans-Christian Egtvedt struct input_dev *input = dev->input; 28*5f565502SHans-Christian Egtvedt int x, y; 29*5f565502SHans-Christian Egtvedt 30*5f565502SHans-Christian Egtvedt if (gpio->bleft >= 0) 31*5f565502SHans-Christian Egtvedt input_report_key(input, BTN_LEFT, 32*5f565502SHans-Christian Egtvedt gpio_get_value(gpio->bleft) ^ gpio->polarity); 33*5f565502SHans-Christian Egtvedt if (gpio->bmiddle >= 0) 34*5f565502SHans-Christian Egtvedt input_report_key(input, BTN_MIDDLE, 35*5f565502SHans-Christian Egtvedt gpio_get_value(gpio->bmiddle) ^ gpio->polarity); 36*5f565502SHans-Christian Egtvedt if (gpio->bright >= 0) 37*5f565502SHans-Christian Egtvedt input_report_key(input, BTN_RIGHT, 38*5f565502SHans-Christian Egtvedt gpio_get_value(gpio->bright) ^ gpio->polarity); 39*5f565502SHans-Christian Egtvedt 40*5f565502SHans-Christian Egtvedt x = (gpio_get_value(gpio->right) ^ gpio->polarity) 41*5f565502SHans-Christian Egtvedt - (gpio_get_value(gpio->left) ^ gpio->polarity); 42*5f565502SHans-Christian Egtvedt y = (gpio_get_value(gpio->down) ^ gpio->polarity) 43*5f565502SHans-Christian Egtvedt - (gpio_get_value(gpio->up) ^ gpio->polarity); 44*5f565502SHans-Christian Egtvedt 45*5f565502SHans-Christian Egtvedt input_report_rel(input, REL_X, x); 46*5f565502SHans-Christian Egtvedt input_report_rel(input, REL_Y, y); 47*5f565502SHans-Christian Egtvedt input_sync(input); 48*5f565502SHans-Christian Egtvedt } 49*5f565502SHans-Christian Egtvedt 50*5f565502SHans-Christian Egtvedt static int __init gpio_mouse_probe(struct platform_device *pdev) 51*5f565502SHans-Christian Egtvedt { 52*5f565502SHans-Christian Egtvedt struct gpio_mouse_platform_data *pdata = pdev->dev.platform_data; 53*5f565502SHans-Christian Egtvedt struct input_polled_dev *input_poll; 54*5f565502SHans-Christian Egtvedt struct input_dev *input; 55*5f565502SHans-Christian Egtvedt int pin, i; 56*5f565502SHans-Christian Egtvedt int error; 57*5f565502SHans-Christian Egtvedt 58*5f565502SHans-Christian Egtvedt if (!pdata) { 59*5f565502SHans-Christian Egtvedt dev_err(&pdev->dev, "no platform data\n"); 60*5f565502SHans-Christian Egtvedt error = -ENXIO; 61*5f565502SHans-Christian Egtvedt goto out; 62*5f565502SHans-Christian Egtvedt } 63*5f565502SHans-Christian Egtvedt 64*5f565502SHans-Christian Egtvedt if (pdata->scan_ms < 0) { 65*5f565502SHans-Christian Egtvedt dev_err(&pdev->dev, "invalid scan time\n"); 66*5f565502SHans-Christian Egtvedt error = -EINVAL; 67*5f565502SHans-Christian Egtvedt goto out; 68*5f565502SHans-Christian Egtvedt } 69*5f565502SHans-Christian Egtvedt 70*5f565502SHans-Christian Egtvedt for (i = 0; i < GPIO_MOUSE_PIN_MAX; i++) { 71*5f565502SHans-Christian Egtvedt pin = pdata->pins[i]; 72*5f565502SHans-Christian Egtvedt 73*5f565502SHans-Christian Egtvedt if (pin < 0) { 74*5f565502SHans-Christian Egtvedt 75*5f565502SHans-Christian Egtvedt if (i <= GPIO_MOUSE_PIN_RIGHT) { 76*5f565502SHans-Christian Egtvedt /* Mouse direction is required. */ 77*5f565502SHans-Christian Egtvedt dev_err(&pdev->dev, 78*5f565502SHans-Christian Egtvedt "missing GPIO for directions\n"); 79*5f565502SHans-Christian Egtvedt error = -EINVAL; 80*5f565502SHans-Christian Egtvedt goto out_free_gpios; 81*5f565502SHans-Christian Egtvedt } 82*5f565502SHans-Christian Egtvedt 83*5f565502SHans-Christian Egtvedt if (i == GPIO_MOUSE_PIN_BLEFT) 84*5f565502SHans-Christian Egtvedt dev_dbg(&pdev->dev, "no left button defined\n"); 85*5f565502SHans-Christian Egtvedt 86*5f565502SHans-Christian Egtvedt } else { 87*5f565502SHans-Christian Egtvedt error = gpio_request(pin, "gpio_mouse"); 88*5f565502SHans-Christian Egtvedt if (error) { 89*5f565502SHans-Christian Egtvedt dev_err(&pdev->dev, "fail %d pin (%d idx)\n", 90*5f565502SHans-Christian Egtvedt pin, i); 91*5f565502SHans-Christian Egtvedt goto out_free_gpios; 92*5f565502SHans-Christian Egtvedt } 93*5f565502SHans-Christian Egtvedt 94*5f565502SHans-Christian Egtvedt gpio_direction_input(pin); 95*5f565502SHans-Christian Egtvedt } 96*5f565502SHans-Christian Egtvedt } 97*5f565502SHans-Christian Egtvedt 98*5f565502SHans-Christian Egtvedt input_poll = input_allocate_polled_device(); 99*5f565502SHans-Christian Egtvedt if (!input_poll) { 100*5f565502SHans-Christian Egtvedt dev_err(&pdev->dev, "not enough memory for input device\n"); 101*5f565502SHans-Christian Egtvedt error = -ENOMEM; 102*5f565502SHans-Christian Egtvedt goto out_free_gpios; 103*5f565502SHans-Christian Egtvedt } 104*5f565502SHans-Christian Egtvedt 105*5f565502SHans-Christian Egtvedt platform_set_drvdata(pdev, input_poll); 106*5f565502SHans-Christian Egtvedt 107*5f565502SHans-Christian Egtvedt /* set input-polldev handlers */ 108*5f565502SHans-Christian Egtvedt input_poll->private = pdata; 109*5f565502SHans-Christian Egtvedt input_poll->poll = gpio_mouse_scan; 110*5f565502SHans-Christian Egtvedt input_poll->poll_interval = pdata->scan_ms; 111*5f565502SHans-Christian Egtvedt 112*5f565502SHans-Christian Egtvedt input = input_poll->input; 113*5f565502SHans-Christian Egtvedt input->name = pdev->name; 114*5f565502SHans-Christian Egtvedt input->id.bustype = BUS_HOST; 115*5f565502SHans-Christian Egtvedt input->dev.parent = &pdev->dev; 116*5f565502SHans-Christian Egtvedt 117*5f565502SHans-Christian Egtvedt input_set_capability(input, EV_REL, REL_X); 118*5f565502SHans-Christian Egtvedt input_set_capability(input, EV_REL, REL_Y); 119*5f565502SHans-Christian Egtvedt if (pdata->bleft >= 0) 120*5f565502SHans-Christian Egtvedt input_set_capability(input, EV_KEY, BTN_LEFT); 121*5f565502SHans-Christian Egtvedt if (pdata->bmiddle >= 0) 122*5f565502SHans-Christian Egtvedt input_set_capability(input, EV_KEY, BTN_MIDDLE); 123*5f565502SHans-Christian Egtvedt if (pdata->bright >= 0) 124*5f565502SHans-Christian Egtvedt input_set_capability(input, EV_KEY, BTN_RIGHT); 125*5f565502SHans-Christian Egtvedt 126*5f565502SHans-Christian Egtvedt error = input_register_polled_device(input_poll); 127*5f565502SHans-Christian Egtvedt if (error) { 128*5f565502SHans-Christian Egtvedt dev_err(&pdev->dev, "could not register input device\n"); 129*5f565502SHans-Christian Egtvedt goto out_free_polldev; 130*5f565502SHans-Christian Egtvedt } 131*5f565502SHans-Christian Egtvedt 132*5f565502SHans-Christian Egtvedt dev_dbg(&pdev->dev, "%d ms scan time, buttons: %s%s%s\n", 133*5f565502SHans-Christian Egtvedt pdata->scan_ms, 134*5f565502SHans-Christian Egtvedt pdata->bleft < 0 ? "" : "left ", 135*5f565502SHans-Christian Egtvedt pdata->bmiddle < 0 ? "" : "middle ", 136*5f565502SHans-Christian Egtvedt pdata->bright < 0 ? "" : "right"); 137*5f565502SHans-Christian Egtvedt 138*5f565502SHans-Christian Egtvedt return 0; 139*5f565502SHans-Christian Egtvedt 140*5f565502SHans-Christian Egtvedt out_free_polldev: 141*5f565502SHans-Christian Egtvedt input_free_polled_device(input_poll); 142*5f565502SHans-Christian Egtvedt platform_set_drvdata(pdev, NULL); 143*5f565502SHans-Christian Egtvedt 144*5f565502SHans-Christian Egtvedt out_free_gpios: 145*5f565502SHans-Christian Egtvedt while (--i >= 0) { 146*5f565502SHans-Christian Egtvedt pin = pdata->pins[i]; 147*5f565502SHans-Christian Egtvedt if (pin) 148*5f565502SHans-Christian Egtvedt gpio_free(pin); 149*5f565502SHans-Christian Egtvedt } 150*5f565502SHans-Christian Egtvedt out: 151*5f565502SHans-Christian Egtvedt return error; 152*5f565502SHans-Christian Egtvedt } 153*5f565502SHans-Christian Egtvedt 154*5f565502SHans-Christian Egtvedt static int __devexit gpio_mouse_remove(struct platform_device *pdev) 155*5f565502SHans-Christian Egtvedt { 156*5f565502SHans-Christian Egtvedt struct input_polled_dev *input = platform_get_drvdata(pdev); 157*5f565502SHans-Christian Egtvedt struct gpio_mouse_platform_data *pdata = input->private; 158*5f565502SHans-Christian Egtvedt int pin, i; 159*5f565502SHans-Christian Egtvedt 160*5f565502SHans-Christian Egtvedt input_unregister_polled_device(input); 161*5f565502SHans-Christian Egtvedt input_free_polled_device(input); 162*5f565502SHans-Christian Egtvedt 163*5f565502SHans-Christian Egtvedt for (i = 0; i < GPIO_MOUSE_PIN_MAX; i++) { 164*5f565502SHans-Christian Egtvedt pin = pdata->pins[i]; 165*5f565502SHans-Christian Egtvedt if (pin >= 0) 166*5f565502SHans-Christian Egtvedt gpio_free(pin); 167*5f565502SHans-Christian Egtvedt } 168*5f565502SHans-Christian Egtvedt 169*5f565502SHans-Christian Egtvedt platform_set_drvdata(pdev, NULL); 170*5f565502SHans-Christian Egtvedt 171*5f565502SHans-Christian Egtvedt return 0; 172*5f565502SHans-Christian Egtvedt } 173*5f565502SHans-Christian Egtvedt 174*5f565502SHans-Christian Egtvedt struct platform_driver gpio_mouse_device_driver = { 175*5f565502SHans-Christian Egtvedt .remove = __devexit_p(gpio_mouse_remove), 176*5f565502SHans-Christian Egtvedt .driver = { 177*5f565502SHans-Christian Egtvedt .name = "gpio_mouse", 178*5f565502SHans-Christian Egtvedt } 179*5f565502SHans-Christian Egtvedt }; 180*5f565502SHans-Christian Egtvedt 181*5f565502SHans-Christian Egtvedt static int __init gpio_mouse_init(void) 182*5f565502SHans-Christian Egtvedt { 183*5f565502SHans-Christian Egtvedt return platform_driver_probe(&gpio_mouse_device_driver, 184*5f565502SHans-Christian Egtvedt gpio_mouse_probe); 185*5f565502SHans-Christian Egtvedt } 186*5f565502SHans-Christian Egtvedt module_init(gpio_mouse_init); 187*5f565502SHans-Christian Egtvedt 188*5f565502SHans-Christian Egtvedt static void __exit gpio_mouse_exit(void) 189*5f565502SHans-Christian Egtvedt { 190*5f565502SHans-Christian Egtvedt platform_driver_unregister(&gpio_mouse_device_driver); 191*5f565502SHans-Christian Egtvedt } 192*5f565502SHans-Christian Egtvedt module_exit(gpio_mouse_exit); 193*5f565502SHans-Christian Egtvedt 194*5f565502SHans-Christian Egtvedt MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>"); 195*5f565502SHans-Christian Egtvedt MODULE_DESCRIPTION("GPIO mouse driver"); 196*5f565502SHans-Christian Egtvedt MODULE_LICENSE("GPL"); 197