1*422b552dSJavier Herrero /* 2*422b552dSJavier Herrero * OpenCores Keyboard Controller Driver 3*422b552dSJavier Herrero * http://www.opencores.org/project,keyboardcontroller 4*422b552dSJavier Herrero * 5*422b552dSJavier Herrero * Copyright 2007-2009 HV Sistemas S.L. 6*422b552dSJavier Herrero * 7*422b552dSJavier Herrero * Licensed under the GPL-2 or later. 8*422b552dSJavier Herrero */ 9*422b552dSJavier Herrero 10*422b552dSJavier Herrero #include <linux/input.h> 11*422b552dSJavier Herrero #include <linux/interrupt.h> 12*422b552dSJavier Herrero #include <linux/io.h> 13*422b552dSJavier Herrero #include <linux/ioport.h> 14*422b552dSJavier Herrero #include <linux/kernel.h> 15*422b552dSJavier Herrero #include <linux/module.h> 16*422b552dSJavier Herrero #include <linux/platform_device.h> 17*422b552dSJavier Herrero 18*422b552dSJavier Herrero struct opencores_kbd { 19*422b552dSJavier Herrero struct input_dev *input; 20*422b552dSJavier Herrero struct resource *addr_res; 21*422b552dSJavier Herrero void __iomem *addr; 22*422b552dSJavier Herrero int irq; 23*422b552dSJavier Herrero unsigned short keycodes[128]; 24*422b552dSJavier Herrero }; 25*422b552dSJavier Herrero 26*422b552dSJavier Herrero static irqreturn_t opencores_kbd_isr(int irq, void *dev_id) 27*422b552dSJavier Herrero { 28*422b552dSJavier Herrero struct opencores_kbd *opencores_kbd = dev_id; 29*422b552dSJavier Herrero struct input_dev *input = opencores_kbd->input; 30*422b552dSJavier Herrero unsigned char c; 31*422b552dSJavier Herrero 32*422b552dSJavier Herrero c = readb(opencores_kbd->addr); 33*422b552dSJavier Herrero input_report_key(input, c & 0x7f, c & 0x80 ? 0 : 1); 34*422b552dSJavier Herrero input_sync(input); 35*422b552dSJavier Herrero 36*422b552dSJavier Herrero return IRQ_HANDLED; 37*422b552dSJavier Herrero } 38*422b552dSJavier Herrero 39*422b552dSJavier Herrero static int __devinit opencores_kbd_probe(struct platform_device *pdev) 40*422b552dSJavier Herrero { 41*422b552dSJavier Herrero struct input_dev *input; 42*422b552dSJavier Herrero struct opencores_kbd *opencores_kbd; 43*422b552dSJavier Herrero struct resource *res; 44*422b552dSJavier Herrero int irq, i, error; 45*422b552dSJavier Herrero 46*422b552dSJavier Herrero res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 47*422b552dSJavier Herrero if (!res) { 48*422b552dSJavier Herrero dev_err(&pdev->dev, "missing board memory resource\n"); 49*422b552dSJavier Herrero return -EINVAL; 50*422b552dSJavier Herrero } 51*422b552dSJavier Herrero 52*422b552dSJavier Herrero irq = platform_get_irq(pdev, 0); 53*422b552dSJavier Herrero if (irq < 0) { 54*422b552dSJavier Herrero dev_err(&pdev->dev, "missing board IRQ resource\n"); 55*422b552dSJavier Herrero return -EINVAL; 56*422b552dSJavier Herrero } 57*422b552dSJavier Herrero 58*422b552dSJavier Herrero opencores_kbd = kzalloc(sizeof(*opencores_kbd), GFP_KERNEL); 59*422b552dSJavier Herrero input = input_allocate_device(); 60*422b552dSJavier Herrero if (!opencores_kbd || !input) { 61*422b552dSJavier Herrero dev_err(&pdev->dev, "failed to allocate device structures\n"); 62*422b552dSJavier Herrero error = -ENOMEM; 63*422b552dSJavier Herrero goto err_free_mem; 64*422b552dSJavier Herrero } 65*422b552dSJavier Herrero 66*422b552dSJavier Herrero opencores_kbd->addr_res = res; 67*422b552dSJavier Herrero res = request_mem_region(res->start, resource_size(res), pdev->name); 68*422b552dSJavier Herrero if (!res) { 69*422b552dSJavier Herrero dev_err(&pdev->dev, "failed to request I/O memory\n"); 70*422b552dSJavier Herrero error = -EBUSY; 71*422b552dSJavier Herrero goto err_free_mem; 72*422b552dSJavier Herrero } 73*422b552dSJavier Herrero 74*422b552dSJavier Herrero opencores_kbd->addr = ioremap(res->start, resource_size(res)); 75*422b552dSJavier Herrero if (!opencores_kbd->addr) { 76*422b552dSJavier Herrero dev_err(&pdev->dev, "failed to remap I/O memory\n"); 77*422b552dSJavier Herrero error = -ENXIO; 78*422b552dSJavier Herrero goto err_rel_mem; 79*422b552dSJavier Herrero } 80*422b552dSJavier Herrero 81*422b552dSJavier Herrero opencores_kbd->input = input; 82*422b552dSJavier Herrero opencores_kbd->irq = irq; 83*422b552dSJavier Herrero 84*422b552dSJavier Herrero input->name = pdev->name; 85*422b552dSJavier Herrero input->phys = "opencores-kbd/input0"; 86*422b552dSJavier Herrero input->dev.parent = &pdev->dev; 87*422b552dSJavier Herrero 88*422b552dSJavier Herrero input_set_drvdata(input, opencores_kbd); 89*422b552dSJavier Herrero 90*422b552dSJavier Herrero input->id.bustype = BUS_HOST; 91*422b552dSJavier Herrero input->id.vendor = 0x0001; 92*422b552dSJavier Herrero input->id.product = 0x0001; 93*422b552dSJavier Herrero input->id.version = 0x0100; 94*422b552dSJavier Herrero 95*422b552dSJavier Herrero input->keycode = opencores_kbd->keycodes; 96*422b552dSJavier Herrero input->keycodesize = sizeof(opencores_kbd->keycodes[0]); 97*422b552dSJavier Herrero input->keycodemax = ARRAY_SIZE(opencores_kbd->keycodes); 98*422b552dSJavier Herrero 99*422b552dSJavier Herrero __set_bit(EV_KEY, input->evbit); 100*422b552dSJavier Herrero 101*422b552dSJavier Herrero for (i = 0; i < ARRAY_SIZE(opencores_kbd->keycodes); i++) { 102*422b552dSJavier Herrero /* 103*422b552dSJavier Herrero * OpenCores controller happens to have scancodes match 104*422b552dSJavier Herrero * our KEY_* definitions. 105*422b552dSJavier Herrero */ 106*422b552dSJavier Herrero opencores_kbd->keycodes[i] = i; 107*422b552dSJavier Herrero __set_bit(opencores_kbd->keycodes[i], input->keybit); 108*422b552dSJavier Herrero } 109*422b552dSJavier Herrero __clear_bit(KEY_RESERVED, input->keybit); 110*422b552dSJavier Herrero 111*422b552dSJavier Herrero error = request_irq(irq, &opencores_kbd_isr, 112*422b552dSJavier Herrero IRQF_TRIGGER_RISING, pdev->name, opencores_kbd); 113*422b552dSJavier Herrero if (error) { 114*422b552dSJavier Herrero dev_err(&pdev->dev, "unable to claim irq %d\n", irq); 115*422b552dSJavier Herrero goto err_unmap_mem; 116*422b552dSJavier Herrero } 117*422b552dSJavier Herrero 118*422b552dSJavier Herrero error = input_register_device(input); 119*422b552dSJavier Herrero if (error) { 120*422b552dSJavier Herrero dev_err(&pdev->dev, "unable to register input device\n"); 121*422b552dSJavier Herrero goto err_free_irq; 122*422b552dSJavier Herrero } 123*422b552dSJavier Herrero 124*422b552dSJavier Herrero platform_set_drvdata(pdev, opencores_kbd); 125*422b552dSJavier Herrero 126*422b552dSJavier Herrero return 0; 127*422b552dSJavier Herrero 128*422b552dSJavier Herrero err_free_irq: 129*422b552dSJavier Herrero free_irq(irq, opencores_kbd); 130*422b552dSJavier Herrero err_unmap_mem: 131*422b552dSJavier Herrero iounmap(opencores_kbd->addr); 132*422b552dSJavier Herrero err_rel_mem: 133*422b552dSJavier Herrero release_mem_region(res->start, resource_size(res)); 134*422b552dSJavier Herrero err_free_mem: 135*422b552dSJavier Herrero input_free_device(input); 136*422b552dSJavier Herrero kfree(opencores_kbd); 137*422b552dSJavier Herrero 138*422b552dSJavier Herrero return error; 139*422b552dSJavier Herrero } 140*422b552dSJavier Herrero 141*422b552dSJavier Herrero static int __devexit opencores_kbd_remove(struct platform_device *pdev) 142*422b552dSJavier Herrero { 143*422b552dSJavier Herrero struct opencores_kbd *opencores_kbd = platform_get_drvdata(pdev); 144*422b552dSJavier Herrero 145*422b552dSJavier Herrero free_irq(opencores_kbd->irq, opencores_kbd); 146*422b552dSJavier Herrero 147*422b552dSJavier Herrero iounmap(opencores_kbd->addr); 148*422b552dSJavier Herrero release_mem_region(opencores_kbd->addr_res->start, 149*422b552dSJavier Herrero resource_size(opencores_kbd->addr_res)); 150*422b552dSJavier Herrero input_unregister_device(opencores_kbd->input); 151*422b552dSJavier Herrero kfree(opencores_kbd); 152*422b552dSJavier Herrero 153*422b552dSJavier Herrero platform_set_drvdata(pdev, NULL); 154*422b552dSJavier Herrero 155*422b552dSJavier Herrero return 0; 156*422b552dSJavier Herrero } 157*422b552dSJavier Herrero 158*422b552dSJavier Herrero static struct platform_driver opencores_kbd_device_driver = { 159*422b552dSJavier Herrero .probe = opencores_kbd_probe, 160*422b552dSJavier Herrero .remove = __devexit_p(opencores_kbd_remove), 161*422b552dSJavier Herrero .driver = { 162*422b552dSJavier Herrero .name = "opencores-kbd", 163*422b552dSJavier Herrero }, 164*422b552dSJavier Herrero }; 165*422b552dSJavier Herrero 166*422b552dSJavier Herrero static int __init opencores_kbd_init(void) 167*422b552dSJavier Herrero { 168*422b552dSJavier Herrero return platform_driver_register(&opencores_kbd_device_driver); 169*422b552dSJavier Herrero } 170*422b552dSJavier Herrero module_init(opencores_kbd_init); 171*422b552dSJavier Herrero 172*422b552dSJavier Herrero static void __exit opencores_kbd_exit(void) 173*422b552dSJavier Herrero { 174*422b552dSJavier Herrero platform_driver_unregister(&opencores_kbd_device_driver); 175*422b552dSJavier Herrero } 176*422b552dSJavier Herrero module_exit(opencores_kbd_exit); 177*422b552dSJavier Herrero 178*422b552dSJavier Herrero MODULE_LICENSE("GPL"); 179*422b552dSJavier Herrero MODULE_AUTHOR("Javier Herrero <jherrero@hvsistemas.es>"); 180*422b552dSJavier Herrero MODULE_DESCRIPTION("Keyboard driver for OpenCores Keyboard Controller"); 181