xref: /linux/arch/arm/common/scoop.c (revision c353faa4b2abd8d5142640b880532c97a0807460)
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);
202