Merge branch 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-block.git] / arch / arm / common / scoop.c
CommitLineData
d2912cb1 1// SPDX-License-Identifier: GPL-2.0-only
1da177e4
LT
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
1da177e4
LT
8 */
9
10#include <linux/device.h>
2f8163ba 11#include <linux/gpio.h>
4e57b681 12#include <linux/string.h>
de25968c 13#include <linux/slab.h>
d052d1be 14#include <linux/platform_device.h>
dc28094b 15#include <linux/export.h>
fced80c7 16#include <linux/io.h>
1da177e4
LT
17#include <asm/hardware/scoop.h>
18
7ea3bbbc
RP
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*/
28struct scoop_pcmcia_config *platform_scoop_config;
29EXPORT_SYMBOL(platform_scoop_config);
30
1da177e4 31struct scoop_dev {
2f8c5149 32 void __iomem *base;
b43a9e60 33 struct gpio_chip gpio;
1da177e4 34 spinlock_t scoop_lock;
7c398988
RP
35 unsigned short suspend_clr;
36 unsigned short suspend_set;
1da177e4
LT
37 u32 scoop_gpwr;
38};
39
40void reset_scoop(struct device *dev)
41{
42 struct scoop_dev *sdev = dev_get_drvdata(dev);
43
aa88bc0a
HS
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 */
c353faa4 50 iowrite16(0x0000, sdev->base + SCOOP_IRM);
1da177e4
LT
51}
52
b43a9e60
DB
53static 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
66static void scoop_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
67{
050c5429 68 struct scoop_dev *sdev = gpiochip_get_data(chip);
b43a9e60
DB
69 unsigned long flags;
70
71 spin_lock_irqsave(&sdev->scoop_lock, flags);
72
73 __scoop_gpio_set(sdev, offset, value);
74
75 spin_unlock_irqrestore(&sdev->scoop_lock, flags);
76}
77
78static int scoop_gpio_get(struct gpio_chip *chip, unsigned offset)
79{
050c5429 80 struct scoop_dev *sdev = gpiochip_get_data(chip);
b43a9e60 81
af901ca1 82 /* XXX: I'm unsure, but it seems so */
86d5e657 83 return !!(ioread16(sdev->base + SCOOP_GPRR) & (1 << (offset + 1)));
b43a9e60
DB
84}
85
86static int scoop_gpio_direction_input(struct gpio_chip *chip,
87 unsigned offset)
88{
050c5429 89 struct scoop_dev *sdev = gpiochip_get_data(chip);
b43a9e60
DB
90 unsigned long flags;
91 unsigned short gpcr;
92
93 spin_lock_irqsave(&sdev->scoop_lock, flags);
94
95 gpcr = ioread16(sdev->base + SCOOP_GPCR);
96 gpcr &= ~(1 << (offset + 1));
97 iowrite16(gpcr, sdev->base + SCOOP_GPCR);
98
99 spin_unlock_irqrestore(&sdev->scoop_lock, flags);
100
101 return 0;
102}
103
104static int scoop_gpio_direction_output(struct gpio_chip *chip,
105 unsigned offset, int value)
106{
050c5429 107 struct scoop_dev *sdev = gpiochip_get_data(chip);
b43a9e60
DB
108 unsigned long flags;
109 unsigned short gpcr;
110
111 spin_lock_irqsave(&sdev->scoop_lock, flags);
112
113 __scoop_gpio_set(sdev, offset, value);
114
115 gpcr = ioread16(sdev->base + SCOOP_GPCR);
116 gpcr |= 1 << (offset + 1);
117 iowrite16(gpcr, sdev->base + SCOOP_GPCR);
118
119 spin_unlock_irqrestore(&sdev->scoop_lock, flags);
120
121 return 0;
122}
123
1da177e4
LT
124unsigned short read_scoop_reg(struct device *dev, unsigned short reg)
125{
126 struct scoop_dev *sdev = dev_get_drvdata(dev);
c353faa4 127 return ioread16(sdev->base + reg);
1da177e4
LT
128}
129
130void write_scoop_reg(struct device *dev, unsigned short reg, unsigned short data)
131{
132 struct scoop_dev *sdev = dev_get_drvdata(dev);
c353faa4 133 iowrite16(data, sdev->base + reg);
1da177e4
LT
134}
135
136EXPORT_SYMBOL(reset_scoop);
137EXPORT_SYMBOL(read_scoop_reg);
138EXPORT_SYMBOL(write_scoop_reg);
139
cfab57e0 140#ifdef CONFIG_PM
7c398988
RP
141static void check_scoop_reg(struct scoop_dev *sdev)
142{
143 unsigned short mcr;
144
c353faa4 145 mcr = ioread16(sdev->base + SCOOP_MCR);
7c398988 146 if ((mcr & 0x100) == 0)
c353faa4 147 iowrite16(0x0101, sdev->base + SCOOP_MCR);
7c398988
RP
148}
149
3ae5eaec 150static int scoop_suspend(struct platform_device *dev, pm_message_t state)
1da177e4 151{
3ae5eaec 152 struct scoop_dev *sdev = platform_get_drvdata(dev);
9480e307
RK
153
154 check_scoop_reg(sdev);
c353faa4
DB
155 sdev->scoop_gpwr = ioread16(sdev->base + SCOOP_GPWR);
156 iowrite16((sdev->scoop_gpwr & ~sdev->suspend_clr) | sdev->suspend_set, sdev->base + SCOOP_GPWR);
1da177e4 157
1da177e4
LT
158 return 0;
159}
160
3ae5eaec 161static int scoop_resume(struct platform_device *dev)
1da177e4 162{
3ae5eaec 163 struct scoop_dev *sdev = platform_get_drvdata(dev);
9480e307
RK
164
165 check_scoop_reg(sdev);
c353faa4 166 iowrite16(sdev->scoop_gpwr, sdev->base + SCOOP_GPWR);
1da177e4 167
1da177e4
LT
168 return 0;
169}
170#else
171#define scoop_suspend NULL
172#define scoop_resume NULL
173#endif
174
351a102d 175static int scoop_probe(struct platform_device *pdev)
1da177e4
LT
176{
177 struct scoop_dev *devptr;
178 struct scoop_config *inf;
1da177e4 179 struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
b43a9e60 180 int ret;
1da177e4
LT
181
182 if (!mem)
183 return -EINVAL;
184
d2a02b93 185 devptr = kzalloc(sizeof(struct scoop_dev), GFP_KERNEL);
1da177e4 186 if (!devptr)
d2a02b93 187 return -ENOMEM;
1da177e4 188
1da177e4
LT
189 spin_lock_init(&devptr->scoop_lock);
190
3ae5eaec 191 inf = pdev->dev.platform_data;
28f65c11 192 devptr->base = ioremap(mem->start, resource_size(mem));
1da177e4
LT
193
194 if (!devptr->base) {
b43a9e60
DB
195 ret = -ENOMEM;
196 goto err_ioremap;
1da177e4
LT
197 }
198
3ae5eaec 199 platform_set_drvdata(pdev, devptr);
1da177e4 200
2f8c5149 201 printk("Sharp Scoop Device found at 0x%08x -> 0x%8p\n",(unsigned int)mem->start, devptr->base);
1da177e4 202
c353faa4 203 iowrite16(0x0140, devptr->base + SCOOP_MCR);
c35bf4a5 204 reset_scoop(&pdev->dev);
c353faa4
DB
205 iowrite16(0x0000, devptr->base + SCOOP_CPR);
206 iowrite16(inf->io_dir & 0xffff, devptr->base + SCOOP_GPCR);
207 iowrite16(inf->io_out & 0xffff, devptr->base + SCOOP_GPWR);
1da177e4 208
7c398988
RP
209 devptr->suspend_clr = inf->suspend_clr;
210 devptr->suspend_set = inf->suspend_set;
211
b43a9e60
DB
212 devptr->gpio.base = -1;
213
214 if (inf->gpio_base != 0) {
3f978704 215 devptr->gpio.label = dev_name(&pdev->dev);
b43a9e60
DB
216 devptr->gpio.base = inf->gpio_base;
217 devptr->gpio.ngpio = 12; /* PA11 = 0, PA12 = 1, etc. up to PA22 = 11 */
218 devptr->gpio.set = scoop_gpio_set;
219 devptr->gpio.get = scoop_gpio_get;
220 devptr->gpio.direction_input = scoop_gpio_direction_input;
221 devptr->gpio.direction_output = scoop_gpio_direction_output;
222
050c5429 223 ret = gpiochip_add_data(&devptr->gpio, devptr);
b43a9e60
DB
224 if (ret)
225 goto err_gpio;
226 }
227
1da177e4 228 return 0;
b43a9e60 229
b43a9e60
DB
230err_gpio:
231 platform_set_drvdata(pdev, NULL);
232err_ioremap:
233 iounmap(devptr->base);
234 kfree(devptr);
235
236 return ret;
1da177e4
LT
237}
238
351a102d 239static int scoop_remove(struct platform_device *pdev)
1da177e4 240{
3ae5eaec 241 struct scoop_dev *sdev = platform_get_drvdata(pdev);
b43a9e60
DB
242
243 if (!sdev)
244 return -EINVAL;
245
88d5e520 246 if (sdev->gpio.base != -1)
247 gpiochip_remove(&sdev->gpio);
b43a9e60
DB
248
249 platform_set_drvdata(pdev, NULL);
250 iounmap(sdev->base);
251 kfree(sdev);
252
1da177e4
LT
253 return 0;
254}
255
3ae5eaec 256static struct platform_driver scoop_driver = {
1da177e4 257 .probe = scoop_probe,
351a102d 258 .remove = scoop_remove,
1da177e4
LT
259 .suspend = scoop_suspend,
260 .resume = scoop_resume,
3ae5eaec
RK
261 .driver = {
262 .name = "sharp-scoop",
263 },
1da177e4
LT
264};
265
2f8c5149 266static int __init scoop_init(void)
1da177e4 267{
3ae5eaec 268 return platform_driver_register(&scoop_driver);
1da177e4
LT
269}
270
271subsys_initcall(scoop_init);