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

Archive Download this file



interactive