xref: /openbmc/linux/arch/arm/common/scoop.c (revision 64c70b1c)
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 #define SCOOP_REG(d,adr) (*(volatile unsigned short*)(d +(adr)))
34 
35 struct  scoop_dev {
36 	void  *base;
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 	SCOOP_REG(sdev->base,SCOOP_MCR) = 0x0100;  // 00
48 	SCOOP_REG(sdev->base,SCOOP_CDR) = 0x0000;  // 04
49 	SCOOP_REG(sdev->base,SCOOP_CCR) = 0x0000;  // 10
50 	SCOOP_REG(sdev->base,SCOOP_IMR) = 0x0000;  // 18
51 	SCOOP_REG(sdev->base,SCOOP_IRM) = 0x00FF;  // 14
52 	SCOOP_REG(sdev->base,SCOOP_ISR) = 0x0000;  // 1C
53 	SCOOP_REG(sdev->base,SCOOP_IRM) = 0x0000;
54 }
55 
56 unsigned short set_scoop_gpio(struct device *dev, unsigned short bit)
57 {
58 	unsigned short gpio_bit;
59 	unsigned long flag;
60 	struct scoop_dev *sdev = dev_get_drvdata(dev);
61 
62 	spin_lock_irqsave(&sdev->scoop_lock, flag);
63 	gpio_bit = SCOOP_REG(sdev->base, SCOOP_GPWR) | bit;
64 	SCOOP_REG(sdev->base, SCOOP_GPWR) = gpio_bit;
65 	spin_unlock_irqrestore(&sdev->scoop_lock, flag);
66 
67 	return gpio_bit;
68 }
69 
70 unsigned short reset_scoop_gpio(struct device *dev, unsigned short bit)
71 {
72 	unsigned short gpio_bit;
73 	unsigned long flag;
74 	struct scoop_dev *sdev = dev_get_drvdata(dev);
75 
76 	spin_lock_irqsave(&sdev->scoop_lock, flag);
77 	gpio_bit = SCOOP_REG(sdev->base, SCOOP_GPWR) & ~bit;
78 	SCOOP_REG(sdev->base,SCOOP_GPWR) = gpio_bit;
79 	spin_unlock_irqrestore(&sdev->scoop_lock, flag);
80 
81 	return gpio_bit;
82 }
83 
84 EXPORT_SYMBOL(set_scoop_gpio);
85 EXPORT_SYMBOL(reset_scoop_gpio);
86 
87 unsigned short read_scoop_reg(struct device *dev, unsigned short reg)
88 {
89 	struct scoop_dev *sdev = dev_get_drvdata(dev);
90 	return SCOOP_REG(sdev->base,reg);
91 }
92 
93 void write_scoop_reg(struct device *dev, unsigned short reg, unsigned short data)
94 {
95 	struct scoop_dev *sdev = dev_get_drvdata(dev);
96 	SCOOP_REG(sdev->base,reg)=data;
97 }
98 
99 EXPORT_SYMBOL(reset_scoop);
100 EXPORT_SYMBOL(read_scoop_reg);
101 EXPORT_SYMBOL(write_scoop_reg);
102 
103 static void check_scoop_reg(struct scoop_dev *sdev)
104 {
105 	unsigned short mcr;
106 
107 	mcr = SCOOP_REG(sdev->base, SCOOP_MCR);
108 	if ((mcr & 0x100) == 0)
109 		SCOOP_REG(sdev->base, SCOOP_MCR) = 0x0101;
110 }
111 
112 #ifdef CONFIG_PM
113 static int scoop_suspend(struct platform_device *dev, pm_message_t state)
114 {
115 	struct scoop_dev *sdev = platform_get_drvdata(dev);
116 
117 	check_scoop_reg(sdev);
118 	sdev->scoop_gpwr = SCOOP_REG(sdev->base, SCOOP_GPWR);
119 	SCOOP_REG(sdev->base, SCOOP_GPWR) = (sdev->scoop_gpwr & ~sdev->suspend_clr) | sdev->suspend_set;
120 
121 	return 0;
122 }
123 
124 static int scoop_resume(struct platform_device *dev)
125 {
126 	struct scoop_dev *sdev = platform_get_drvdata(dev);
127 
128 	check_scoop_reg(sdev);
129 	SCOOP_REG(sdev->base,SCOOP_GPWR) = sdev->scoop_gpwr;
130 
131 	return 0;
132 }
133 #else
134 #define scoop_suspend	NULL
135 #define scoop_resume	NULL
136 #endif
137 
138 int __init scoop_probe(struct platform_device *pdev)
139 {
140 	struct scoop_dev *devptr;
141 	struct scoop_config *inf;
142 	struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
143 
144 	if (!mem)
145 		return -EINVAL;
146 
147 	devptr = kzalloc(sizeof(struct scoop_dev), GFP_KERNEL);
148 	if (!devptr)
149 		return -ENOMEM;
150 
151 	spin_lock_init(&devptr->scoop_lock);
152 
153 	inf = pdev->dev.platform_data;
154 	devptr->base = ioremap(mem->start, mem->end - mem->start + 1);
155 
156 	if (!devptr->base) {
157 		kfree(devptr);
158 		return -ENOMEM;
159 	}
160 
161 	platform_set_drvdata(pdev, devptr);
162 
163 	printk("Sharp Scoop Device found at 0x%08x -> 0x%08x\n",(unsigned int)mem->start,(unsigned int)devptr->base);
164 
165 	SCOOP_REG(devptr->base, SCOOP_MCR) = 0x0140;
166 	reset_scoop(&pdev->dev);
167 	SCOOP_REG(devptr->base, SCOOP_CPR) = 0x0000;
168 	SCOOP_REG(devptr->base, SCOOP_GPCR) = inf->io_dir & 0xffff;
169 	SCOOP_REG(devptr->base, SCOOP_GPWR) = inf->io_out & 0xffff;
170 
171 	devptr->suspend_clr = inf->suspend_clr;
172 	devptr->suspend_set = inf->suspend_set;
173 
174 	return 0;
175 }
176 
177 static int scoop_remove(struct platform_device *pdev)
178 {
179 	struct scoop_dev *sdev = platform_get_drvdata(pdev);
180 	if (sdev) {
181 		iounmap(sdev->base);
182 		kfree(sdev);
183 		platform_set_drvdata(pdev, NULL);
184 	}
185 	return 0;
186 }
187 
188 static struct platform_driver scoop_driver = {
189 	.probe		= scoop_probe,
190 	.remove 	= scoop_remove,
191 	.suspend	= scoop_suspend,
192 	.resume		= scoop_resume,
193 	.driver		= {
194 		.name	= "sharp-scoop",
195 	},
196 };
197 
198 int __init scoop_init(void)
199 {
200 	return platform_driver_register(&scoop_driver);
201 }
202 
203 subsys_initcall(scoop_init);
204