Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/arm/common/scoop.c
26292 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* Support code for the SCOOP interface found on various Sharp PDAs
4
*
5
* Copyright (c) 2004 Richard Purdie
6
*
7
* Based on code written by Sharp/Lineo for 2.4 kernels
8
*/
9
10
#include <linux/device.h>
11
#include <linux/gpio/driver.h>
12
#include <linux/string.h>
13
#include <linux/slab.h>
14
#include <linux/platform_device.h>
15
#include <linux/export.h>
16
#include <linux/io.h>
17
#include <asm/hardware/scoop.h>
18
19
/* PCMCIA to Scoop linkage
20
21
There is no easy way to link multiple scoop devices into one
22
single entity for the pxa2xx_pcmcia device so this structure
23
is used which is setup by the platform code.
24
25
This file is never modular so this symbol is always
26
accessile to the board support files.
27
*/
28
struct scoop_pcmcia_config *platform_scoop_config;
29
EXPORT_SYMBOL(platform_scoop_config);
30
31
struct scoop_dev {
32
void __iomem *base;
33
struct gpio_chip gpio;
34
spinlock_t scoop_lock;
35
unsigned short suspend_clr;
36
unsigned short suspend_set;
37
u32 scoop_gpwr;
38
};
39
40
void reset_scoop(struct device *dev)
41
{
42
struct scoop_dev *sdev = dev_get_drvdata(dev);
43
44
iowrite16(0x0100, sdev->base + SCOOP_MCR); /* 00 */
45
iowrite16(0x0000, sdev->base + SCOOP_CDR); /* 04 */
46
iowrite16(0x0000, sdev->base + SCOOP_CCR); /* 10 */
47
iowrite16(0x0000, sdev->base + SCOOP_IMR); /* 18 */
48
iowrite16(0x00FF, sdev->base + SCOOP_IRM); /* 14 */
49
iowrite16(0x0000, sdev->base + SCOOP_ISR); /* 1C */
50
iowrite16(0x0000, sdev->base + SCOOP_IRM);
51
}
52
53
static void __scoop_gpio_set(struct scoop_dev *sdev,
54
unsigned offset, int value)
55
{
56
unsigned short gpwr;
57
58
gpwr = ioread16(sdev->base + SCOOP_GPWR);
59
if (value)
60
gpwr |= 1 << (offset + 1);
61
else
62
gpwr &= ~(1 << (offset + 1));
63
iowrite16(gpwr, sdev->base + SCOOP_GPWR);
64
}
65
66
static int scoop_gpio_set(struct gpio_chip *chip, unsigned int offset,
67
int value)
68
{
69
struct scoop_dev *sdev = gpiochip_get_data(chip);
70
unsigned long flags;
71
72
spin_lock_irqsave(&sdev->scoop_lock, flags);
73
74
__scoop_gpio_set(sdev, offset, value);
75
76
spin_unlock_irqrestore(&sdev->scoop_lock, flags);
77
78
return 0;
79
}
80
81
static int scoop_gpio_get(struct gpio_chip *chip, unsigned offset)
82
{
83
struct scoop_dev *sdev = gpiochip_get_data(chip);
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 = gpiochip_get_data(chip);
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 = gpiochip_get_data(chip);
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 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
185
if (!mem)
186
return -EINVAL;
187
188
devptr = kzalloc(sizeof(struct scoop_dev), GFP_KERNEL);
189
if (!devptr)
190
return -ENOMEM;
191
192
spin_lock_init(&devptr->scoop_lock);
193
194
inf = pdev->dev.platform_data;
195
devptr->base = ioremap(mem->start, resource_size(mem));
196
197
if (!devptr->base) {
198
ret = -ENOMEM;
199
goto err_ioremap;
200
}
201
202
platform_set_drvdata(pdev, devptr);
203
204
printk("Sharp Scoop Device found at 0x%08x -> 0x%8p\n",(unsigned int)mem->start, devptr->base);
205
206
iowrite16(0x0140, devptr->base + SCOOP_MCR);
207
reset_scoop(&pdev->dev);
208
iowrite16(0x0000, devptr->base + SCOOP_CPR);
209
iowrite16(inf->io_dir & 0xffff, devptr->base + SCOOP_GPCR);
210
iowrite16(inf->io_out & 0xffff, devptr->base + SCOOP_GPWR);
211
212
devptr->suspend_clr = inf->suspend_clr;
213
devptr->suspend_set = inf->suspend_set;
214
215
devptr->gpio.base = -1;
216
217
if (inf->gpio_base != 0) {
218
devptr->gpio.label = dev_name(&pdev->dev);
219
devptr->gpio.base = inf->gpio_base;
220
devptr->gpio.ngpio = 12; /* PA11 = 0, PA12 = 1, etc. up to PA22 = 11 */
221
devptr->gpio.set = scoop_gpio_set;
222
devptr->gpio.get = scoop_gpio_get;
223
devptr->gpio.direction_input = scoop_gpio_direction_input;
224
devptr->gpio.direction_output = scoop_gpio_direction_output;
225
226
ret = gpiochip_add_data(&devptr->gpio, devptr);
227
if (ret)
228
goto err_gpio;
229
}
230
231
return 0;
232
233
err_gpio:
234
platform_set_drvdata(pdev, NULL);
235
err_ioremap:
236
iounmap(devptr->base);
237
kfree(devptr);
238
239
return ret;
240
}
241
242
static void scoop_remove(struct platform_device *pdev)
243
{
244
struct scoop_dev *sdev = platform_get_drvdata(pdev);
245
246
if (sdev->gpio.base != -1)
247
gpiochip_remove(&sdev->gpio);
248
249
platform_set_drvdata(pdev, NULL);
250
iounmap(sdev->base);
251
kfree(sdev);
252
}
253
254
static struct platform_driver scoop_driver = {
255
.probe = scoop_probe,
256
.remove = scoop_remove,
257
.suspend = scoop_suspend,
258
.resume = scoop_resume,
259
.driver = {
260
.name = "sharp-scoop",
261
},
262
};
263
264
static int __init scoop_init(void)
265
{
266
return platform_driver_register(&scoop_driver);
267
}
268
269
subsys_initcall(scoop_init);
270
271