Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6
[linux-2.6.git] / arch / arm / common / scoop.c
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);