X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Finput%2Fserio%2Fambakmi.c;h=3df5eedf8f31fe06a4347a37dcdff8c1f2e9ad6c;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=df6183954a7028e6386c6a035be8b4eae364cfea;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c index df6183954..3df5eedf8 100644 --- a/drivers/input/serio/ambakmi.c +++ b/drivers/input/serio/ambakmi.c @@ -18,18 +18,20 @@ #include #include #include +#include +#include +#include +#include #include #include -#include -#include #define KMI_BASE (kmi->base) struct amba_kmi_port { - struct serio io; - struct amba_kmi_port *next; - unsigned char *base; + struct serio *io; + struct clk *clk; + void __iomem *base; unsigned int irq; unsigned int divisor; unsigned int open; @@ -42,7 +44,7 @@ static irqreturn_t amba_kmi_int(int irq, void *dev_id, struct pt_regs *regs) int handled = IRQ_NONE; while (status & KMIIR_RXINTR) { - serio_interrupt(&kmi->io, readb(KMIDATA), 0, regs); + serio_interrupt(kmi->io, readb(KMIDATA), 0, regs); status = readb(KMIIR); handled = IRQ_HANDLED; } @@ -52,7 +54,7 @@ static irqreturn_t amba_kmi_int(int irq, void *dev_id, struct pt_regs *regs) static int amba_kmi_write(struct serio *io, unsigned char val) { - struct amba_kmi_port *kmi = io->driver; + struct amba_kmi_port *kmi = io->port_data; unsigned int timeleft = 10000; /* timeout in 100ms */ while ((readb(KMISTAT) & KMISTAT_TXEMPTY) == 0 && timeleft--) @@ -66,36 +68,49 @@ static int amba_kmi_write(struct serio *io, unsigned char val) static int amba_kmi_open(struct serio *io) { - struct amba_kmi_port *kmi = io->driver; + struct amba_kmi_port *kmi = io->port_data; + unsigned int divisor; int ret; - writeb(kmi->divisor, KMICLKDIV); + ret = clk_enable(kmi->clk); + if (ret) + goto out; + + divisor = clk_get_rate(kmi->clk) / 8000000 - 1; + writeb(divisor, KMICLKDIV); writeb(KMICR_EN, KMICR); ret = request_irq(kmi->irq, amba_kmi_int, 0, "kmi-pl050", kmi); if (ret) { printk(KERN_ERR "kmi: failed to claim IRQ%d\n", kmi->irq); writeb(0, KMICR); - return ret; + goto clk_disable; } writeb(KMICR_EN | KMICR_RXINTREN, KMICR); return 0; + + clk_disable: + clk_disable(kmi->clk); + out: + return ret; } static void amba_kmi_close(struct serio *io) { - struct amba_kmi_port *kmi = io->driver; + struct amba_kmi_port *kmi = io->port_data; writeb(0, KMICR); free_irq(kmi->irq, kmi); + clk_disable(kmi->clk); } static int amba_kmi_probe(struct amba_device *dev, void *id) { struct amba_kmi_port *kmi; + struct serio *io; int ret; ret = amba_request_regions(dev, NULL); @@ -103,37 +118,48 @@ static int amba_kmi_probe(struct amba_device *dev, void *id) return ret; kmi = kmalloc(sizeof(struct amba_kmi_port), GFP_KERNEL); - if (!kmi) { + io = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (!kmi || !io) { ret = -ENOMEM; goto out; } memset(kmi, 0, sizeof(struct amba_kmi_port)); - - kmi->io.type = SERIO_8042; - kmi->io.write = amba_kmi_write; - kmi->io.open = amba_kmi_open; - kmi->io.close = amba_kmi_close; - kmi->io.name = dev->dev.bus_id; - kmi->io.phys = dev->dev.bus_id; - kmi->io.driver = kmi; - + memset(io, 0, sizeof(struct serio)); + + io->id.type = SERIO_8042; + io->write = amba_kmi_write; + io->open = amba_kmi_open; + io->close = amba_kmi_close; + strlcpy(io->name, dev->dev.bus_id, sizeof(io->name)); + strlcpy(io->phys, dev->dev.bus_id, sizeof(io->phys)); + io->port_data = kmi; + io->dev.parent = &dev->dev; + + kmi->io = io; kmi->base = ioremap(dev->res.start, KMI_SIZE); if (!kmi->base) { ret = -ENOMEM; goto out; } - kmi->irq = dev->irq[0]; - kmi->divisor = 24 / 8 - 1; + kmi->clk = clk_get(&dev->dev, "KMIREFCLK"); + if (IS_ERR(kmi->clk)) { + ret = PTR_ERR(kmi->clk); + goto unmap; + } + kmi->irq = dev->irq[0]; amba_set_drvdata(dev, kmi); - serio_register_port(&kmi->io); + serio_register_port(kmi->io); return 0; + unmap: + iounmap(kmi->base); out: kfree(kmi); + kfree(io); amba_release_regions(dev); return ret; } @@ -144,7 +170,8 @@ static int amba_kmi_remove(struct amba_device *dev) amba_set_drvdata(dev, NULL); - serio_unregister_port(&kmi->io); + serio_unregister_port(kmi->io); + clk_put(kmi->clk); iounmap(kmi->base); kfree(kmi); amba_release_regions(dev); @@ -156,7 +183,7 @@ static int amba_kmi_resume(struct amba_device *dev) struct amba_kmi_port *kmi = amba_get_drvdata(dev); /* kick the serio layer to rescan this port */ - serio_rescan(&kmi->io); + serio_reconnect(kmi->io); return 0; } @@ -186,7 +213,7 @@ static int __init amba_kmi_init(void) static void __exit amba_kmi_exit(void) { - return amba_driver_unregister(&ambakmi_driver); + amba_driver_unregister(&ambakmi_driver); } module_init(amba_kmi_init);