Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/arm/common/scoop.c
10817 views
1
/*
2
* Support code for the SCOOP interface found on various Sharp PDAs
3
*
4
* Copyright (c) 2004 Richard Purdie
5
*
6
* Based on code written by Sharp/Lineo for 2.4 kernels
7
*
8
* This program is free software; you can redistribute it and/or modify
9
* it under the terms of the GNU General Public License version 2 as
10
* published by the Free Software Foundation.
11
*
12
*/
13
14
#include <linux/device.h>
15
#include <linux/string.h>
16
#include <linux/slab.h>
17
#include <linux/platform_device.h>
18
#include <linux/io.h>
19
#include <asm/gpio.h>
20
#include <asm/hardware/scoop.h>
21
22
/* PCMCIA to Scoop linkage
23
24
There is no easy way to link multiple scoop devices into one
25
single entity for the pxa2xx_pcmcia device so this structure
26
is used which is setup by the platform code.
27
28
This file is never modular so this symbol is always
29
accessile to the board support files.
30
*/
31
struct scoop_pcmcia_config *platform_scoop_config;
32
EXPORT_SYMBOL(platform_scoop_config);
33
34
struct scoop_dev {
35
void __iomem *base;
36
struct gpio_chip gpio;
37
spinlock_t scoop_lock;
38
unsigned short suspend_clr;
39
unsigned short suspend_set;
40
u32 scoop_gpwr;
41
};
42
43
void reset_scoop(struct device *dev)
44
{
45
struct scoop_dev *sdev = dev_get_drvdata(dev);
46
47
iowrite16(0x0100, sdev->base + SCOOP_MCR); /* 00 */
48
iowrite16(0x0000, sdev->base + SCOOP_CDR); /* 04 */
49
iowrite16(0x0000, sdev->base + SCOOP_CCR); /* 10 */
50
iowrite16(0x0000, sdev->base + SCOOP_IMR); /* 18 */
51
iowrite16(0x00FF, sdev->base + SCOOP_IRM); /* 14 */
52
iowrite16(0x0000, sdev->base + SCOOP_ISR); /* 1C */
53
iowrite16(0x0000, sdev->base + SCOOP_IRM);
54
}
55
56
static void __scoop_gpio_set(struct scoop_dev *sdev,
57
unsigned offset, int value)
58
{
59
unsigned short gpwr;
60
61
gpwr = ioread16(sdev->base + SCOOP_GPWR);
62
if (value)
63
gpwr |= 1 << (offset + 1);
64
else
65
gpwr &= ~(1 << (offset + 1));
66
iowrite16(gpwr, sdev->base + SCOOP_GPWR);
67
}
68
69
static void scoop_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
70
{
71
struct scoop_dev *sdev = container_of(chip, struct scoop_dev, gpio);
72
unsigned long flags;
73
74
spin_lock_irqsave(&sdev->scoop_lock, flags);
75
76
__scoop_gpio_set(sdev, offset, value);
77
78
spin_unlock_irqrestore(&sdev->scoop_lock, flags);
79
}
80
81
static int scoop_gpio_get(struct gpio_chip *chip, unsigned offset)
82
{
83
struct scoop_dev *sdev = container_of(chip, struct scoop_dev, gpio);
84
85
/* XXX: I'm unsure, but it seems so */
86
return ioread16(sdev->base + SCOOP_GPRR) & (1 << (offset + 1));
87
}
88
89
static int scoop_gpio_direction_input(struct gpio_chip *chip,
90
unsigned offset)
91
{
92
struct scoop_dev *sdev = container_of(chip, struct scoop_dev, gpio);
93
unsigned long flags;
94
unsigned short gpcr;
95
96
spin_lock_irqsave(&sdev->scoop_lock, flags);
97
98
gpcr = ioread16(sdev->base + SCOOP_GPCR);
99
gpcr &= ~(1 << (offset + 1));
100
iowrite16(gpcr, sdev->base + SCOOP_GPCR);
101
102
spin_unlock_irqrestore(&sdev->scoop_lock, flags);
103
104
return 0;
105
}
106
107
static int scoop_gpio_direction_output(struct gpio_chip *chip,
108
unsigned offset, int value)
109
{
110
struct scoop_dev *sdev = container_of(chip, struct scoop_dev, gpio);
111
unsigned long flags;
112
unsigned short gpcr;
113
114
spin_lock_irqsave(&sdev->scoop_lock, flags);
115
116
__scoop_gpio_set(sdev, offset, value);
117
118
gpcr = ioread16(sdev->base + SCOOP_GPCR);
119
gpcr |= 1 << (offset + 1);
120
iowrite16(gpcr, sdev->base + SCOOP_GPCR);
121
122
spin_unlock_irqrestore(&sdev->scoop_lock, flags);
123
124
return 0;
125
}
126
127
unsigned short read_scoop_reg(struct device *dev, unsigned short reg)
128
{
129
struct scoop_dev *sdev = dev_get_drvdata(dev);
130
return ioread16(sdev->base + reg);
131
}
132
133
void write_scoop_reg(struct device *dev, unsigned short reg, unsigned short data)
134
{
135
struct scoop_dev *sdev = dev_get_drvdata(dev);
136
iowrite16(data, sdev->base + reg);
137
}
138
139
EXPORT_SYMBOL(reset_scoop);
140
EXPORT_SYMBOL(read_scoop_reg);
141
EXPORT_SYMBOL(write_scoop_reg);
142
143
#ifdef CONFIG_PM
144
static void check_scoop_reg(struct scoop_dev *sdev)
145
{
146
unsigned short mcr;
147
148
mcr = ioread16(sdev->base + SCOOP_MCR);
149
if ((mcr & 0x100) == 0)
150
iowrite16(0x0101, sdev->base + SCOOP_MCR);
151
}
152
153
static int scoop_suspend(struct platform_device *dev, pm_message_t state)
154
{
155
struct scoop_dev *sdev = platform_get_drvdata(dev);
156
157
check_scoop_reg(sdev);
158
sdev->scoop_gpwr = ioread16(sdev->base + SCOOP_GPWR);
159
iowrite16((sdev->scoop_gpwr & ~sdev->suspend_clr) | sdev->suspend_set, sdev->base + SCOOP_GPWR);
160
161
return 0;
162
}
163
164
static int scoop_resume(struct platform_device *dev)
165
{
166
struct scoop_dev *sdev = platform_get_drvdata(dev);
167
168
check_scoop_reg(sdev);
169
iowrite16(sdev->scoop_gpwr, sdev->base + SCOOP_GPWR);
170
171
return 0;
172
}
173
#else
174
#define scoop_suspend NULL
175
#define scoop_resume NULL
176
#endif
177
178
static int __devinit scoop_probe(struct platform_device *pdev)
179
{
180
struct scoop_dev *devptr;
181
struct scoop_config *inf;
182
struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
183
int ret;
184
int temp;
185
186
if (!mem)
187
return -EINVAL;
188
189
devptr = kzalloc(sizeof(struct scoop_dev), GFP_KERNEL);
190
if (!devptr)
191
return -ENOMEM;
192
193
spin_lock_init(&devptr->scoop_lock);
194
195
inf = pdev->dev.platform_data;
196
devptr->base = ioremap(mem->start, mem->end - mem->start + 1);
197
198
if (!devptr->base) {
199
ret = -ENOMEM;
200
goto err_ioremap;
201
}
202
203
platform_set_drvdata(pdev, devptr);
204
205
printk("Sharp Scoop Device found at 0x%08x -> 0x%8p\n",(unsigned int)mem->start, devptr->base);
206
207
iowrite16(0x0140, devptr->base + SCOOP_MCR);
208
reset_scoop(&pdev->dev);
209
iowrite16(0x0000, devptr->base + SCOOP_CPR);
210
iowrite16(inf->io_dir & 0xffff, devptr->base + SCOOP_GPCR);
211
iowrite16(inf->io_out & 0xffff, devptr->base + SCOOP_GPWR);
212
213
devptr->suspend_clr = inf->suspend_clr;
214
devptr->suspend_set = inf->suspend_set;
215
216
devptr->gpio.base = -1;
217
218
if (inf->gpio_base != 0) {
219
devptr->gpio.label = dev_name(&pdev->dev);
220
devptr->gpio.base = inf->gpio_base;
221
devptr->gpio.ngpio = 12; /* PA11 = 0, PA12 = 1, etc. up to PA22 = 11 */
222
devptr->gpio.set = scoop_gpio_set;
223
devptr->gpio.get = scoop_gpio_get;
224
devptr->gpio.direction_input = scoop_gpio_direction_input;
225
devptr->gpio.direction_output = scoop_gpio_direction_output;
226
227
ret = gpiochip_add(&devptr->gpio);
228
if (ret)
229
goto err_gpio;
230
}
231
232
return 0;
233
234
if (devptr->gpio.base != -1)
235
temp = gpiochip_remove(&devptr->gpio);
236
err_gpio:
237
platform_set_drvdata(pdev, NULL);
238
err_ioremap:
239
iounmap(devptr->base);
240
kfree(devptr);
241
242
return ret;
243
}
244
245
static int __devexit scoop_remove(struct platform_device *pdev)
246
{
247
struct scoop_dev *sdev = platform_get_drvdata(pdev);
248
int ret;
249
250
if (!sdev)
251
return -EINVAL;
252
253
if (sdev->gpio.base != -1) {
254
ret = gpiochip_remove(&sdev->gpio);
255
if (ret) {
256
dev_err(&pdev->dev, "Can't remove gpio chip: %d\n", ret);
257
return ret;
258
}
259
}
260
261
platform_set_drvdata(pdev, NULL);
262
iounmap(sdev->base);
263
kfree(sdev);
264
265
return 0;
266
}
267
268
static struct platform_driver scoop_driver = {
269
.probe = scoop_probe,
270
.remove = __devexit_p(scoop_remove),
271
.suspend = scoop_suspend,
272
.resume = scoop_resume,
273
.driver = {
274
.name = "sharp-scoop",
275
},
276
};
277
278
static int __init scoop_init(void)
279
{
280
return platform_driver_register(&scoop_driver);
281
}
282
283
subsys_initcall(scoop_init);
284
285