Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * linux/drivers/input/serio/ambakmi.c | |
3 | * | |
4 | * Copyright (C) 2000-2003 Deep Blue Solutions Ltd. | |
5 | * Copyright (C) 2002 Russell King. | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License as published by | |
9 | * the Free Software Foundation; either version 2 of the License, or | |
10 | * (at your option) any later version. | |
11 | */ | |
12 | #include <linux/module.h> | |
13 | #include <linux/init.h> | |
14 | #include <linux/serio.h> | |
15 | #include <linux/errno.h> | |
16 | #include <linux/interrupt.h> | |
17 | #include <linux/ioport.h> | |
18 | #include <linux/device.h> | |
19 | #include <linux/delay.h> | |
20 | #include <linux/slab.h> | |
21 | #include <linux/err.h> | |
a62c80e5 RK |
22 | #include <linux/amba/bus.h> |
23 | #include <linux/amba/kmi.h> | |
f8ce2547 | 24 | #include <linux/clk.h> |
1da177e4 LT |
25 | |
26 | #include <asm/io.h> | |
27 | #include <asm/irq.h> | |
1da177e4 LT |
28 | |
29 | #define KMI_BASE (kmi->base) | |
30 | ||
31 | struct amba_kmi_port { | |
32 | struct serio *io; | |
33 | struct clk *clk; | |
34 | void __iomem *base; | |
35 | unsigned int irq; | |
36 | unsigned int divisor; | |
37 | unsigned int open; | |
38 | }; | |
39 | ||
7d12e780 | 40 | static irqreturn_t amba_kmi_int(int irq, void *dev_id) |
1da177e4 LT |
41 | { |
42 | struct amba_kmi_port *kmi = dev_id; | |
43 | unsigned int status = readb(KMIIR); | |
44 | int handled = IRQ_NONE; | |
45 | ||
46 | while (status & KMIIR_RXINTR) { | |
7d12e780 | 47 | serio_interrupt(kmi->io, readb(KMIDATA), 0); |
1da177e4 LT |
48 | status = readb(KMIIR); |
49 | handled = IRQ_HANDLED; | |
50 | } | |
51 | ||
52 | return handled; | |
53 | } | |
54 | ||
55 | static int amba_kmi_write(struct serio *io, unsigned char val) | |
56 | { | |
57 | struct amba_kmi_port *kmi = io->port_data; | |
58 | unsigned int timeleft = 10000; /* timeout in 100ms */ | |
59 | ||
4ab73761 | 60 | while ((readb(KMISTAT) & KMISTAT_TXEMPTY) == 0 && --timeleft) |
1da177e4 LT |
61 | udelay(10); |
62 | ||
63 | if (timeleft) | |
64 | writeb(val, KMIDATA); | |
65 | ||
66 | return timeleft ? 0 : SERIO_TIMEOUT; | |
67 | } | |
68 | ||
69 | static int amba_kmi_open(struct serio *io) | |
70 | { | |
71 | struct amba_kmi_port *kmi = io->port_data; | |
72 | unsigned int divisor; | |
73 | int ret; | |
74 | ||
59d1f5c4 | 75 | ret = clk_prepare_enable(kmi->clk); |
1da177e4 | 76 | if (ret) |
a8d3584a | 77 | goto out; |
1da177e4 LT |
78 | |
79 | divisor = clk_get_rate(kmi->clk) / 8000000 - 1; | |
80 | writeb(divisor, KMICLKDIV); | |
81 | writeb(KMICR_EN, KMICR); | |
82 | ||
83 | ret = request_irq(kmi->irq, amba_kmi_int, 0, "kmi-pl050", kmi); | |
84 | if (ret) { | |
85 | printk(KERN_ERR "kmi: failed to claim IRQ%d\n", kmi->irq); | |
86 | writeb(0, KMICR); | |
87 | goto clk_disable; | |
88 | } | |
89 | ||
90 | writeb(KMICR_EN | KMICR_RXINTREN, KMICR); | |
91 | ||
92 | return 0; | |
93 | ||
94 | clk_disable: | |
59d1f5c4 | 95 | clk_disable_unprepare(kmi->clk); |
1da177e4 LT |
96 | out: |
97 | return ret; | |
98 | } | |
99 | ||
100 | static void amba_kmi_close(struct serio *io) | |
101 | { | |
102 | struct amba_kmi_port *kmi = io->port_data; | |
103 | ||
104 | writeb(0, KMICR); | |
105 | ||
106 | free_irq(kmi->irq, kmi); | |
59d1f5c4 | 107 | clk_disable_unprepare(kmi->clk); |
1da177e4 LT |
108 | } |
109 | ||
aa25afad RK |
110 | static int __devinit amba_kmi_probe(struct amba_device *dev, |
111 | const struct amba_id *id) | |
1da177e4 LT |
112 | { |
113 | struct amba_kmi_port *kmi; | |
114 | struct serio *io; | |
115 | int ret; | |
116 | ||
117 | ret = amba_request_regions(dev, NULL); | |
118 | if (ret) | |
119 | return ret; | |
120 | ||
dd00cc48 YP |
121 | kmi = kzalloc(sizeof(struct amba_kmi_port), GFP_KERNEL); |
122 | io = kzalloc(sizeof(struct serio), GFP_KERNEL); | |
1da177e4 LT |
123 | if (!kmi || !io) { |
124 | ret = -ENOMEM; | |
125 | goto out; | |
126 | } | |
127 | ||
1da177e4 LT |
128 | |
129 | io->id.type = SERIO_8042; | |
130 | io->write = amba_kmi_write; | |
131 | io->open = amba_kmi_open; | |
132 | io->close = amba_kmi_close; | |
4e8718a1 KS |
133 | strlcpy(io->name, dev_name(&dev->dev), sizeof(io->name)); |
134 | strlcpy(io->phys, dev_name(&dev->dev), sizeof(io->phys)); | |
1da177e4 LT |
135 | io->port_data = kmi; |
136 | io->dev.parent = &dev->dev; | |
137 | ||
266429df | 138 | kmi->io = io; |
dc890c2d | 139 | kmi->base = ioremap(dev->res.start, resource_size(&dev->res)); |
1da177e4 LT |
140 | if (!kmi->base) { |
141 | ret = -ENOMEM; | |
142 | goto out; | |
143 | } | |
144 | ||
145 | kmi->clk = clk_get(&dev->dev, "KMIREFCLK"); | |
146 | if (IS_ERR(kmi->clk)) { | |
147 | ret = PTR_ERR(kmi->clk); | |
148 | goto unmap; | |
149 | } | |
150 | ||
151 | kmi->irq = dev->irq[0]; | |
152 | amba_set_drvdata(dev, kmi); | |
153 | ||
154 | serio_register_port(kmi->io); | |
155 | return 0; | |
156 | ||
157 | unmap: | |
158 | iounmap(kmi->base); | |
159 | out: | |
160 | kfree(kmi); | |
161 | kfree(io); | |
162 | amba_release_regions(dev); | |
163 | return ret; | |
164 | } | |
165 | ||
266429df | 166 | static int __devexit amba_kmi_remove(struct amba_device *dev) |
1da177e4 LT |
167 | { |
168 | struct amba_kmi_port *kmi = amba_get_drvdata(dev); | |
169 | ||
170 | amba_set_drvdata(dev, NULL); | |
171 | ||
172 | serio_unregister_port(kmi->io); | |
173 | clk_put(kmi->clk); | |
174 | iounmap(kmi->base); | |
175 | kfree(kmi); | |
176 | amba_release_regions(dev); | |
177 | return 0; | |
178 | } | |
179 | ||
180 | static int amba_kmi_resume(struct amba_device *dev) | |
181 | { | |
182 | struct amba_kmi_port *kmi = amba_get_drvdata(dev); | |
183 | ||
184 | /* kick the serio layer to rescan this port */ | |
185 | serio_reconnect(kmi->io); | |
186 | ||
187 | return 0; | |
188 | } | |
189 | ||
190 | static struct amba_id amba_kmi_idtable[] = { | |
191 | { | |
192 | .id = 0x00041050, | |
193 | .mask = 0x000fffff, | |
194 | }, | |
195 | { 0, 0 } | |
196 | }; | |
197 | ||
2dfff235 DM |
198 | MODULE_DEVICE_TABLE(amba, amba_kmi_idtable); |
199 | ||
1da177e4 LT |
200 | static struct amba_driver ambakmi_driver = { |
201 | .drv = { | |
202 | .name = "kmi-pl050", | |
898d1053 | 203 | .owner = THIS_MODULE, |
1da177e4 LT |
204 | }, |
205 | .id_table = amba_kmi_idtable, | |
206 | .probe = amba_kmi_probe, | |
266429df | 207 | .remove = __devexit_p(amba_kmi_remove), |
1da177e4 LT |
208 | .resume = amba_kmi_resume, |
209 | }; | |
210 | ||
9e5ed094 | 211 | module_amba_driver(ambakmi_driver); |
1da177e4 LT |
212 | |
213 | MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>"); | |
214 | MODULE_DESCRIPTION("AMBA KMI controller driver"); | |
215 | MODULE_LICENSE("GPL"); |