fc08577cdd6c9295932789adcc66c4bebfd92a5a
[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 <asm/io.h>
19 #include <asm/hardware/scoop.h>
20
21 /* PCMCIA to Scoop linkage
22
23    There is no easy way to link multiple scoop devices into one
24    single entity for the pxa2xx_pcmcia device so this structure
25    is used which is setup by the platform code.
26
27    This file is never modular so this symbol is always
28    accessile to the board support files.
29 */
30 struct scoop_pcmcia_config *platform_scoop_config;
31 EXPORT_SYMBOL(platform_scoop_config);
32
33 struct  scoop_dev {
34         void __iomem *base;
35         spinlock_t scoop_lock;
36         unsigned short suspend_clr;
37         unsigned short suspend_set;
38         u32 scoop_gpwr;
39 };
40
41 void reset_scoop(struct device *dev)
42 {
43         struct scoop_dev *sdev = dev_get_drvdata(dev);
44
45         iowrite16(0x0100, sdev->base + SCOOP_MCR);  // 00
46         iowrite16(0x0000, sdev->base + SCOOP_CDR);  // 04
47         iowrite16(0x0000, sdev->base + SCOOP_CCR);  // 10
48         iowrite16(0x0000, sdev->base + SCOOP_IMR);  // 18
49         iowrite16(0x00FF, sdev->base + SCOOP_IRM);  // 14
50         iowrite16(0x0000, sdev->base + SCOOP_ISR);  // 1C
51         iowrite16(0x0000, sdev->base + SCOOP_IRM);
52 }
53
54 unsigned short set_scoop_gpio(struct device *dev, unsigned short bit)
55 {
56         unsigned short gpio_bit;
57         unsigned long flag;
58         struct scoop_dev *sdev = dev_get_drvdata(dev);
59
60         spin_lock_irqsave(&sdev->scoop_lock, flag);
61         gpio_bit = ioread16(sdev->base + SCOOP_GPWR) | bit;
62         iowrite16(gpio_bit, sdev->base + SCOOP_GPWR);
63         spin_unlock_irqrestore(&sdev->scoop_lock, flag);
64
65         return gpio_bit;
66 }
67
68 unsigned short reset_scoop_gpio(struct device *dev, unsigned short bit)
69 {
70         unsigned short gpio_bit;
71         unsigned long flag;
72         struct scoop_dev *sdev = dev_get_drvdata(dev);
73
74         spin_lock_irqsave(&sdev->scoop_lock, flag);
75         gpio_bit = ioread16(sdev->base + SCOOP_GPWR) & ~bit;
76         iowrite16(gpio_bit, sdev->base + SCOOP_GPWR);
77         spin_unlock_irqrestore(&sdev->scoop_lock, flag);
78
79         return gpio_bit;
80 }
81
82 EXPORT_SYMBOL(set_scoop_gpio);
83 EXPORT_SYMBOL(reset_scoop_gpio);
84
85 unsigned short read_scoop_reg(struct device *dev, unsigned short reg)
86 {
87         struct scoop_dev *sdev = dev_get_drvdata(dev);
88         return ioread16(sdev->base + reg);
89 }
90
91 void write_scoop_reg(struct device *dev, unsigned short reg, unsigned short data)
92 {
93         struct scoop_dev *sdev = dev_get_drvdata(dev);
94         iowrite16(data, sdev->base + reg);
95 }
96
97 EXPORT_SYMBOL(reset_scoop);
98 EXPORT_SYMBOL(read_scoop_reg);
99 EXPORT_SYMBOL(write_scoop_reg);
100
101 static void check_scoop_reg(struct scoop_dev *sdev)
102 {
103         unsigned short mcr;
104
105         mcr = ioread16(sdev->base + SCOOP_MCR);
106         if ((mcr & 0x100) == 0)
107                 iowrite16(0x0101, sdev->base + SCOOP_MCR);
108 }
109
110 #ifdef CONFIG_PM
111 static int scoop_suspend(struct platform_device *dev, pm_message_t state)
112 {
113         struct scoop_dev *sdev = platform_get_drvdata(dev);
114
115         check_scoop_reg(sdev);
116         sdev->scoop_gpwr = ioread16(sdev->base + SCOOP_GPWR);
117         iowrite16((sdev->scoop_gpwr & ~sdev->suspend_clr) | sdev->suspend_set, sdev->base + SCOOP_GPWR);
118
119         return 0;
120 }
121
122 static int scoop_resume(struct platform_device *dev)
123 {
124         struct scoop_dev *sdev = platform_get_drvdata(dev);
125
126         check_scoop_reg(sdev);
127         iowrite16(sdev->scoop_gpwr, sdev->base + SCOOP_GPWR);
128
129         return 0;
130 }
131 #else
132 #define scoop_suspend   NULL
133 #define scoop_resume    NULL
134 #endif
135
136 static int __devinit scoop_probe(struct platform_device *pdev)
137 {
138         struct scoop_dev *devptr;
139         struct scoop_config *inf;
140         struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
141
142         if (!mem)
143                 return -EINVAL;
144
145         devptr = kzalloc(sizeof(struct scoop_dev), GFP_KERNEL);
146         if (!devptr)
147                 return -ENOMEM;
148
149         spin_lock_init(&devptr->scoop_lock);
150
151         inf = pdev->dev.platform_data;
152         devptr->base = ioremap(mem->start, mem->end - mem->start + 1);
153
154         if (!devptr->base) {
155                 kfree(devptr);
156                 return -ENOMEM;
157         }
158
159         platform_set_drvdata(pdev, devptr);
160
161         printk("Sharp Scoop Device found at 0x%08x -> 0x%8p\n",(unsigned int)mem->start, devptr->base);
162
163         iowrite16(0x0140, devptr->base + SCOOP_MCR);
164         reset_scoop(&pdev->dev);
165         iowrite16(0x0000, devptr->base + SCOOP_CPR);
166         iowrite16(inf->io_dir & 0xffff, devptr->base + SCOOP_GPCR);
167         iowrite16(inf->io_out & 0xffff, devptr->base + SCOOP_GPWR);
168
169         devptr->suspend_clr = inf->suspend_clr;
170         devptr->suspend_set = inf->suspend_set;
171
172         return 0;
173 }
174
175 static int __devexit scoop_remove(struct platform_device *pdev)
176 {
177         struct scoop_dev *sdev = platform_get_drvdata(pdev);
178         if (sdev) {
179                 iounmap(sdev->base);
180                 kfree(sdev);
181                 platform_set_drvdata(pdev, NULL);
182         }
183         return 0;
184 }
185
186 static struct platform_driver scoop_driver = {
187         .probe          = scoop_probe,
188         .remove         = __devexit_p(scoop_remove),
189         .suspend        = scoop_suspend,
190         .resume         = scoop_resume,
191         .driver         = {
192                 .name   = "sharp-scoop",
193         },
194 };
195
196 static int __init scoop_init(void)
197 {
198         return platform_driver_register(&scoop_driver);
199 }
200
201 subsys_initcall(scoop_init);