Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/input/serio/ambakmi.c
15111 views
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>
22
#include <linux/amba/bus.h>
23
#include <linux/amba/kmi.h>
24
#include <linux/clk.h>
25
26
#include <asm/io.h>
27
#include <asm/irq.h>
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
40
static irqreturn_t amba_kmi_int(int irq, void *dev_id)
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) {
47
serio_interrupt(kmi->io, readb(KMIDATA), 0);
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
60
while ((readb(KMISTAT) & KMISTAT_TXEMPTY) == 0 && --timeleft)
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
75
ret = clk_enable(kmi->clk);
76
if (ret)
77
goto out;
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:
95
clk_disable(kmi->clk);
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);
107
clk_disable(kmi->clk);
108
}
109
110
static int __devinit amba_kmi_probe(struct amba_device *dev,
111
const struct amba_id *id)
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
121
kmi = kzalloc(sizeof(struct amba_kmi_port), GFP_KERNEL);
122
io = kzalloc(sizeof(struct serio), GFP_KERNEL);
123
if (!kmi || !io) {
124
ret = -ENOMEM;
125
goto out;
126
}
127
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;
133
strlcpy(io->name, dev_name(&dev->dev), sizeof(io->name));
134
strlcpy(io->phys, dev_name(&dev->dev), sizeof(io->phys));
135
io->port_data = kmi;
136
io->dev.parent = &dev->dev;
137
138
kmi->io = io;
139
kmi->base = ioremap(dev->res.start, resource_size(&dev->res));
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
166
static int __devexit amba_kmi_remove(struct amba_device *dev)
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
198
static struct amba_driver ambakmi_driver = {
199
.drv = {
200
.name = "kmi-pl050",
201
.owner = THIS_MODULE,
202
},
203
.id_table = amba_kmi_idtable,
204
.probe = amba_kmi_probe,
205
.remove = __devexit_p(amba_kmi_remove),
206
.resume = amba_kmi_resume,
207
};
208
209
static int __init amba_kmi_init(void)
210
{
211
return amba_driver_register(&ambakmi_driver);
212
}
213
214
static void __exit amba_kmi_exit(void)
215
{
216
amba_driver_unregister(&ambakmi_driver);
217
}
218
219
module_init(amba_kmi_init);
220
module_exit(amba_kmi_exit);
221
222
MODULE_AUTHOR("Russell King <[email protected]>");
223
MODULE_DESCRIPTION("AMBA KMI controller driver");
224
MODULE_LICENSE("GPL");
225
226