xref: /openbmc/linux/arch/arm/common/scoop.c (revision 384740dc)
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/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 usure,  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 set_scoop_gpio(struct device *dev, unsigned short bit)
128 {
129 	unsigned short gpio_bit;
130 	unsigned long flag;
131 	struct scoop_dev *sdev = dev_get_drvdata(dev);
132 
133 	spin_lock_irqsave(&sdev->scoop_lock, flag);
134 	gpio_bit = ioread16(sdev->base + SCOOP_GPWR) | bit;
135 	iowrite16(gpio_bit, sdev->base + SCOOP_GPWR);
136 	spin_unlock_irqrestore(&sdev->scoop_lock, flag);
137 
138 	return gpio_bit;
139 }
140 
141 unsigned short reset_scoop_gpio(struct device *dev, unsigned short bit)
142 {
143 	unsigned short gpio_bit;
144 	unsigned long flag;
145 	struct scoop_dev *sdev = dev_get_drvdata(dev);
146 
147 	spin_lock_irqsave(&sdev->scoop_lock, flag);
148 	gpio_bit = ioread16(sdev->base + SCOOP_GPWR) & ~bit;
149 	iowrite16(gpio_bit, sdev->base + SCOOP_GPWR);
150 	spin_unlock_irqrestore(&sdev->scoop_lock, flag);
151 
152 	return gpio_bit;
153 }
154 
155 EXPORT_SYMBOL(set_scoop_gpio);
156 EXPORT_SYMBOL(reset_scoop_gpio);
157 
158 unsigned short read_scoop_reg(struct device *dev, unsigned short reg)
159 {
160 	struct scoop_dev *sdev = dev_get_drvdata(dev);
161 	return ioread16(sdev->base + reg);
162 }
163 
164 void write_scoop_reg(struct device *dev, unsigned short reg, unsigned short data)
165 {
166 	struct scoop_dev *sdev = dev_get_drvdata(dev);
167 	iowrite16(data, sdev->base + reg);
168 }
169 
170 EXPORT_SYMBOL(reset_scoop);
171 EXPORT_SYMBOL(read_scoop_reg);
172 EXPORT_SYMBOL(write_scoop_reg);
173 
174 static void check_scoop_reg(struct scoop_dev *sdev)
175 {
176 	unsigned short mcr;
177 
178 	mcr = ioread16(sdev->base + SCOOP_MCR);
179 	if ((mcr & 0x100) == 0)
180 		iowrite16(0x0101, sdev->base + SCOOP_MCR);
181 }
182 
183 #ifdef CONFIG_PM
184 static int scoop_suspend(struct platform_device *dev, pm_message_t state)
185 {
186 	struct scoop_dev *sdev = platform_get_drvdata(dev);
187 
188 	check_scoop_reg(sdev);
189 	sdev->scoop_gpwr = ioread16(sdev->base + SCOOP_GPWR);
190 	iowrite16((sdev->scoop_gpwr & ~sdev->suspend_clr) | sdev->suspend_set, sdev->base + SCOOP_GPWR);
191 
192 	return 0;
193 }
194 
195 static int scoop_resume(struct platform_device *dev)
196 {
197 	struct scoop_dev *sdev = platform_get_drvdata(dev);
198 
199 	check_scoop_reg(sdev);
200 	iowrite16(sdev->scoop_gpwr, sdev->base + SCOOP_GPWR);
201 
202 	return 0;
203 }
204 #else
205 #define scoop_suspend	NULL
206 #define scoop_resume	NULL
207 #endif
208 
209 static int __devinit scoop_probe(struct platform_device *pdev)
210 {
211 	struct scoop_dev *devptr;
212 	struct scoop_config *inf;
213 	struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
214 	int ret;
215 	int temp;
216 
217 	if (!mem)
218 		return -EINVAL;
219 
220 	devptr = kzalloc(sizeof(struct scoop_dev), GFP_KERNEL);
221 	if (!devptr)
222 		return -ENOMEM;
223 
224 	spin_lock_init(&devptr->scoop_lock);
225 
226 	inf = pdev->dev.platform_data;
227 	devptr->base = ioremap(mem->start, mem->end - mem->start + 1);
228 
229 	if (!devptr->base) {
230 		ret = -ENOMEM;
231 		goto err_ioremap;
232 	}
233 
234 	platform_set_drvdata(pdev, devptr);
235 
236 	printk("Sharp Scoop Device found at 0x%08x -> 0x%8p\n",(unsigned int)mem->start, devptr->base);
237 
238 	iowrite16(0x0140, devptr->base + SCOOP_MCR);
239 	reset_scoop(&pdev->dev);
240 	iowrite16(0x0000, devptr->base + SCOOP_CPR);
241 	iowrite16(inf->io_dir & 0xffff, devptr->base + SCOOP_GPCR);
242 	iowrite16(inf->io_out & 0xffff, devptr->base + SCOOP_GPWR);
243 
244 	devptr->suspend_clr = inf->suspend_clr;
245 	devptr->suspend_set = inf->suspend_set;
246 
247 	devptr->gpio.base = -1;
248 
249 	if (inf->gpio_base != 0) {
250 		devptr->gpio.label = dev_name(&pdev->dev);
251 		devptr->gpio.base = inf->gpio_base;
252 		devptr->gpio.ngpio = 12; /* PA11 = 0, PA12 = 1, etc. up to PA22 = 11 */
253 		devptr->gpio.set = scoop_gpio_set;
254 		devptr->gpio.get = scoop_gpio_get;
255 		devptr->gpio.direction_input = scoop_gpio_direction_input;
256 		devptr->gpio.direction_output = scoop_gpio_direction_output;
257 
258 		ret = gpiochip_add(&devptr->gpio);
259 		if (ret)
260 			goto err_gpio;
261 	}
262 
263 	return 0;
264 
265 	if (devptr->gpio.base != -1)
266 		temp = gpiochip_remove(&devptr->gpio);
267 err_gpio:
268 	platform_set_drvdata(pdev, NULL);
269 err_ioremap:
270 	iounmap(devptr->base);
271 	kfree(devptr);
272 
273 	return ret;
274 }
275 
276 static int __devexit scoop_remove(struct platform_device *pdev)
277 {
278 	struct scoop_dev *sdev = platform_get_drvdata(pdev);
279 	int ret;
280 
281 	if (!sdev)
282 		return -EINVAL;
283 
284 	if (sdev->gpio.base != -1) {
285 		ret = gpiochip_remove(&sdev->gpio);
286 		if (ret) {
287 			dev_err(&pdev->dev, "Can't remove gpio chip: %d\n", ret);
288 			return ret;
289 		}
290 	}
291 
292 	platform_set_drvdata(pdev, NULL);
293 	iounmap(sdev->base);
294 	kfree(sdev);
295 
296 	return 0;
297 }
298 
299 static struct platform_driver scoop_driver = {
300 	.probe		= scoop_probe,
301 	.remove		= __devexit_p(scoop_remove),
302 	.suspend	= scoop_suspend,
303 	.resume		= scoop_resume,
304 	.driver		= {
305 		.name	= "sharp-scoop",
306 	},
307 };
308 
309 static int __init scoop_init(void)
310 {
311 	return platform_driver_register(&scoop_driver);
312 }
313 
314 subsys_initcall(scoop_init);
315