Linux 2.6.25-rc7
[deliverable/linux.git] / arch / arm / common / scoop.c
CommitLineData
1da177e4
LT
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>
4e57b681 15#include <linux/string.h>
de25968c 16#include <linux/slab.h>
d052d1be 17#include <linux/platform_device.h>
1da177e4
LT
18#include <asm/io.h>
19#include <asm/hardware/scoop.h>
20
7ea3bbbc
RP
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*/
30struct scoop_pcmcia_config *platform_scoop_config;
31EXPORT_SYMBOL(platform_scoop_config);
32
1da177e4
LT
33#define SCOOP_REG(d,adr) (*(volatile unsigned short*)(d +(adr)))
34
35struct scoop_dev {
36 void *base;
37 spinlock_t scoop_lock;
7c398988
RP
38 unsigned short suspend_clr;
39 unsigned short suspend_set;
1da177e4
LT
40 u32 scoop_gpwr;
41};
42
43void 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
1da177e4
LT
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
56unsigned 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
70unsigned 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
84EXPORT_SYMBOL(set_scoop_gpio);
85EXPORT_SYMBOL(reset_scoop_gpio);
86
87unsigned 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
93void 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
99EXPORT_SYMBOL(reset_scoop);
100EXPORT_SYMBOL(read_scoop_reg);
101EXPORT_SYMBOL(write_scoop_reg);
102
7c398988
RP
103static 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
1da177e4 112#ifdef CONFIG_PM
3ae5eaec 113static int scoop_suspend(struct platform_device *dev, pm_message_t state)
1da177e4 114{
3ae5eaec 115 struct scoop_dev *sdev = platform_get_drvdata(dev);
9480e307
RK
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;
1da177e4 120
1da177e4
LT
121 return 0;
122}
123
3ae5eaec 124static int scoop_resume(struct platform_device *dev)
1da177e4 125{
3ae5eaec 126 struct scoop_dev *sdev = platform_get_drvdata(dev);
9480e307
RK
127
128 check_scoop_reg(sdev);
129 SCOOP_REG(sdev->base,SCOOP_GPWR) = sdev->scoop_gpwr;
1da177e4 130
1da177e4
LT
131 return 0;
132}
133#else
134#define scoop_suspend NULL
135#define scoop_resume NULL
136#endif
137
3ae5eaec 138int __init scoop_probe(struct platform_device *pdev)
1da177e4
LT
139{
140 struct scoop_dev *devptr;
141 struct scoop_config *inf;
1da177e4
LT
142 struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
143
144 if (!mem)
145 return -EINVAL;
146
d2a02b93 147 devptr = kzalloc(sizeof(struct scoop_dev), GFP_KERNEL);
1da177e4 148 if (!devptr)
d2a02b93 149 return -ENOMEM;
1da177e4 150
1da177e4
LT
151 spin_lock_init(&devptr->scoop_lock);
152
3ae5eaec 153 inf = pdev->dev.platform_data;
1da177e4
LT
154 devptr->base = ioremap(mem->start, mem->end - mem->start + 1);
155
156 if (!devptr->base) {
157 kfree(devptr);
158 return -ENOMEM;
159 }
160
3ae5eaec 161 platform_set_drvdata(pdev, devptr);
1da177e4
LT
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;
c35bf4a5 166 reset_scoop(&pdev->dev);
945b9579 167 SCOOP_REG(devptr->base, SCOOP_CPR) = 0x0000;
1da177e4
LT
168 SCOOP_REG(devptr->base, SCOOP_GPCR) = inf->io_dir & 0xffff;
169 SCOOP_REG(devptr->base, SCOOP_GPWR) = inf->io_out & 0xffff;
170
7c398988
RP
171 devptr->suspend_clr = inf->suspend_clr;
172 devptr->suspend_set = inf->suspend_set;
173
1da177e4
LT
174 return 0;
175}
176
3ae5eaec 177static int scoop_remove(struct platform_device *pdev)
1da177e4 178{
3ae5eaec 179 struct scoop_dev *sdev = platform_get_drvdata(pdev);
1da177e4
LT
180 if (sdev) {
181 iounmap(sdev->base);
182 kfree(sdev);
3ae5eaec 183 platform_set_drvdata(pdev, NULL);
1da177e4
LT
184 }
185 return 0;
186}
187
3ae5eaec 188static struct platform_driver scoop_driver = {
1da177e4
LT
189 .probe = scoop_probe,
190 .remove = scoop_remove,
191 .suspend = scoop_suspend,
192 .resume = scoop_resume,
3ae5eaec
RK
193 .driver = {
194 .name = "sharp-scoop",
195 },
1da177e4
LT
196};
197
198int __init scoop_init(void)
199{
3ae5eaec 200 return platform_driver_register(&scoop_driver);
1da177e4
LT
201}
202
203subsys_initcall(scoop_init);
This page took 0.424514 seconds and 5 git commands to generate.