1*78a56aabSPhil Blundell /* 2*78a56aabSPhil Blundell * Driver for keys on GPIO lines capable of generating interrupts. 3*78a56aabSPhil Blundell * 4*78a56aabSPhil Blundell * Copyright 2005 Phil Blundell 5*78a56aabSPhil Blundell * 6*78a56aabSPhil Blundell * This program is free software; you can redistribute it and/or modify 7*78a56aabSPhil Blundell * it under the terms of the GNU General Public License version 2 as 8*78a56aabSPhil Blundell * published by the Free Software Foundation. 9*78a56aabSPhil Blundell */ 10*78a56aabSPhil Blundell 11*78a56aabSPhil Blundell #include <linux/module.h> 12*78a56aabSPhil Blundell #include <linux/version.h> 13*78a56aabSPhil Blundell 14*78a56aabSPhil Blundell #include <linux/init.h> 15*78a56aabSPhil Blundell #include <linux/fs.h> 16*78a56aabSPhil Blundell #include <linux/interrupt.h> 17*78a56aabSPhil Blundell #include <linux/irq.h> 18*78a56aabSPhil Blundell #include <linux/sched.h> 19*78a56aabSPhil Blundell #include <linux/pm.h> 20*78a56aabSPhil Blundell #include <linux/sysctl.h> 21*78a56aabSPhil Blundell #include <linux/proc_fs.h> 22*78a56aabSPhil Blundell #include <linux/delay.h> 23*78a56aabSPhil Blundell #include <linux/platform_device.h> 24*78a56aabSPhil Blundell #include <linux/input.h> 25*78a56aabSPhil Blundell #include <linux/irq.h> 26*78a56aabSPhil Blundell 27*78a56aabSPhil Blundell #include <asm/arch/pxa-regs.h> 28*78a56aabSPhil Blundell #include <asm/arch/hardware.h> 29*78a56aabSPhil Blundell 30*78a56aabSPhil Blundell #include <asm/hardware/gpio_keys.h> 31*78a56aabSPhil Blundell 32*78a56aabSPhil Blundell static irqreturn_t gpio_keys_isr(int irq, void *dev_id) 33*78a56aabSPhil Blundell { 34*78a56aabSPhil Blundell int i; 35*78a56aabSPhil Blundell struct platform_device *pdev = dev_id; 36*78a56aabSPhil Blundell struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; 37*78a56aabSPhil Blundell struct input_dev *input = platform_get_drvdata(pdev); 38*78a56aabSPhil Blundell 39*78a56aabSPhil Blundell for (i = 0; i < pdata->nbuttons; i++) { 40*78a56aabSPhil Blundell int gpio = pdata->buttons[i].gpio; 41*78a56aabSPhil Blundell if (irq == IRQ_GPIO(gpio)) { 42*78a56aabSPhil Blundell int state = ((GPLR(gpio) & GPIO_bit(gpio)) ? 1 : 0) ^ (pdata->buttons[i].active_low); 43*78a56aabSPhil Blundell 44*78a56aabSPhil Blundell input_report_key(input, pdata->buttons[i].keycode, state); 45*78a56aabSPhil Blundell input_sync(input); 46*78a56aabSPhil Blundell } 47*78a56aabSPhil Blundell } 48*78a56aabSPhil Blundell 49*78a56aabSPhil Blundell return IRQ_HANDLED; 50*78a56aabSPhil Blundell } 51*78a56aabSPhil Blundell 52*78a56aabSPhil Blundell static int __devinit gpio_keys_probe(struct platform_device *pdev) 53*78a56aabSPhil Blundell { 54*78a56aabSPhil Blundell struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; 55*78a56aabSPhil Blundell struct input_dev *input; 56*78a56aabSPhil Blundell int i, error; 57*78a56aabSPhil Blundell 58*78a56aabSPhil Blundell input = input_allocate_device(); 59*78a56aabSPhil Blundell if (!input) 60*78a56aabSPhil Blundell return -ENOMEM; 61*78a56aabSPhil Blundell 62*78a56aabSPhil Blundell platform_set_drvdata(pdev, input); 63*78a56aabSPhil Blundell 64*78a56aabSPhil Blundell input->evbit[0] = BIT(EV_KEY); 65*78a56aabSPhil Blundell 66*78a56aabSPhil Blundell input->name = pdev->name; 67*78a56aabSPhil Blundell input->phys = "gpio-keys/input0"; 68*78a56aabSPhil Blundell input->cdev.dev = &pdev->dev; 69*78a56aabSPhil Blundell input->private = pdata; 70*78a56aabSPhil Blundell 71*78a56aabSPhil Blundell input->id.bustype = BUS_HOST; 72*78a56aabSPhil Blundell input->id.vendor = 0x0001; 73*78a56aabSPhil Blundell input->id.product = 0x0001; 74*78a56aabSPhil Blundell input->id.version = 0x0100; 75*78a56aabSPhil Blundell 76*78a56aabSPhil Blundell for (i = 0; i < pdata->nbuttons; i++) { 77*78a56aabSPhil Blundell int code = pdata->buttons[i].keycode; 78*78a56aabSPhil Blundell int irq = IRQ_GPIO(pdata->buttons[i].gpio); 79*78a56aabSPhil Blundell 80*78a56aabSPhil Blundell set_irq_type(irq, IRQ_TYPE_EDGE_BOTH); 81*78a56aabSPhil Blundell error = request_irq(irq, gpio_keys_isr, SA_SAMPLE_RANDOM, 82*78a56aabSPhil Blundell pdata->buttons[i].desc ? pdata->buttons[i].desc : "gpio_keys", 83*78a56aabSPhil Blundell pdev); 84*78a56aabSPhil Blundell if (error) { 85*78a56aabSPhil Blundell printk(KERN_ERR "gpio-keys: unable to claim irq %d; error %d\n", irq, ret); 86*78a56aabSPhil Blundell goto fail; 87*78a56aabSPhil Blundell } 88*78a56aabSPhil Blundell set_bit(code, input->keybit); 89*78a56aabSPhil Blundell } 90*78a56aabSPhil Blundell 91*78a56aabSPhil Blundell error = input_register_device(input); 92*78a56aabSPhil Blundell if (error) { 93*78a56aabSPhil Blundell printk(KERN_ERR "Unable to register gpio-keys input device\n"); 94*78a56aabSPhil Blundell goto fail; 95*78a56aabSPhil Blundell } 96*78a56aabSPhil Blundell 97*78a56aabSPhil Blundell return 0; 98*78a56aabSPhil Blundell 99*78a56aabSPhil Blundell fail: 100*78a56aabSPhil Blundell for (i = i - 1; i >= 0; i--) 101*78a56aabSPhil Blundell free_irq(IRQ_GPIO(pdata->buttons[i].gpio), pdev); 102*78a56aabSPhil Blundell 103*78a56aabSPhil Blundell input_free_device(input); 104*78a56aabSPhil Blundell 105*78a56aabSPhil Blundell return error; 106*78a56aabSPhil Blundell } 107*78a56aabSPhil Blundell 108*78a56aabSPhil Blundell static int __devexit gpio_keys_remove(struct platform_device *pdev) 109*78a56aabSPhil Blundell { 110*78a56aabSPhil Blundell struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; 111*78a56aabSPhil Blundell struct input_dev *input = platform_get_drvdata(pdev); 112*78a56aabSPhil Blundell int i; 113*78a56aabSPhil Blundell 114*78a56aabSPhil Blundell for (i = 0; i < pdata->nbuttons; i++) { 115*78a56aabSPhil Blundell int irq = IRQ_GPIO(pdata->buttons[i].gpio); 116*78a56aabSPhil Blundell free_irq(irq, pdev); 117*78a56aabSPhil Blundell } 118*78a56aabSPhil Blundell 119*78a56aabSPhil Blundell input_unregister_device(input); 120*78a56aabSPhil Blundell 121*78a56aabSPhil Blundell return 0; 122*78a56aabSPhil Blundell } 123*78a56aabSPhil Blundell 124*78a56aabSPhil Blundell struct platform_driver gpio_keys_device_driver = { 125*78a56aabSPhil Blundell .probe = gpio_keys_probe, 126*78a56aabSPhil Blundell .remove = __devexit_p(gpio_keys_remove), 127*78a56aabSPhil Blundell .driver = { 128*78a56aabSPhil Blundell .name = "gpio-keys", 129*78a56aabSPhil Blundell } 130*78a56aabSPhil Blundell }; 131*78a56aabSPhil Blundell 132*78a56aabSPhil Blundell static int __init gpio_keys_init(void) 133*78a56aabSPhil Blundell { 134*78a56aabSPhil Blundell return platform_driver_register(&gpio_keys_device_driver); 135*78a56aabSPhil Blundell } 136*78a56aabSPhil Blundell 137*78a56aabSPhil Blundell static void __exit gpio_keys_exit(void) 138*78a56aabSPhil Blundell { 139*78a56aabSPhil Blundell platform_driver_unregister(&gpio_keys_device_driver); 140*78a56aabSPhil Blundell } 141*78a56aabSPhil Blundell 142*78a56aabSPhil Blundell module_init(gpio_keys_init); 143*78a56aabSPhil Blundell module_exit(gpio_keys_exit); 144*78a56aabSPhil Blundell 145*78a56aabSPhil Blundell MODULE_LICENSE("GPL"); 146*78a56aabSPhil Blundell MODULE_AUTHOR("Phil Blundell <pb@handhelds.org>"); 147*78a56aabSPhil Blundell MODULE_DESCRIPTION("Keyboard driver for CPU GPIOs"); 148