blob: fc08577cdd6c9295932789adcc66c4bebfd92a5a [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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>
Tim Schmielau4e57b682005-10-30 15:03:48 -080015#include <linux/string.h>
Tim Schmielaude259682006-01-08 01:02:05 -080016#include <linux/slab.h>
Russell Kingd052d1b2005-10-29 19:07:23 +010017#include <linux/platform_device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include <asm/io.h>
19#include <asm/hardware/scoop.h>
20
Richard Purdie7ea3bbb2006-04-18 23:18:53 +010021/* 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
Linus Torvalds1da177e2005-04-16 15:20:36 -070033struct scoop_dev {
Dmitry Baryshkov2f8c5142008-04-09 22:43:37 +010034 void __iomem *base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070035 spinlock_t scoop_lock;
Richard Purdie7c398982005-10-10 10:20:06 +010036 unsigned short suspend_clr;
37 unsigned short suspend_set;
Linus Torvalds1da177e2005-04-16 15:20:36 -070038 u32 scoop_gpwr;
39};
40
41void reset_scoop(struct device *dev)
42{
43 struct scoop_dev *sdev = dev_get_drvdata(dev);
44
Dmitry Baryshkovc353faa2008-04-09 23:05:09 +010045 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);
Linus Torvalds1da177e2005-04-16 15:20:36 -070052}
53
54unsigned 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);
Dmitry Baryshkovc353faa2008-04-09 23:05:09 +010061 gpio_bit = ioread16(sdev->base + SCOOP_GPWR) | bit;
62 iowrite16(gpio_bit, sdev->base + SCOOP_GPWR);
Linus Torvalds1da177e2005-04-16 15:20:36 -070063 spin_unlock_irqrestore(&sdev->scoop_lock, flag);
64
65 return gpio_bit;
66}
67
68unsigned 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);
Dmitry Baryshkovc353faa2008-04-09 23:05:09 +010075 gpio_bit = ioread16(sdev->base + SCOOP_GPWR) & ~bit;
76 iowrite16(gpio_bit, sdev->base + SCOOP_GPWR);
Linus Torvalds1da177e2005-04-16 15:20:36 -070077 spin_unlock_irqrestore(&sdev->scoop_lock, flag);
78
79 return gpio_bit;
80}
81
82EXPORT_SYMBOL(set_scoop_gpio);
83EXPORT_SYMBOL(reset_scoop_gpio);
84
85unsigned short read_scoop_reg(struct device *dev, unsigned short reg)
86{
87 struct scoop_dev *sdev = dev_get_drvdata(dev);
Dmitry Baryshkovc353faa2008-04-09 23:05:09 +010088 return ioread16(sdev->base + reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -070089}
90
91void write_scoop_reg(struct device *dev, unsigned short reg, unsigned short data)
92{
93 struct scoop_dev *sdev = dev_get_drvdata(dev);
Dmitry Baryshkovc353faa2008-04-09 23:05:09 +010094 iowrite16(data, sdev->base + reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -070095}
96
97EXPORT_SYMBOL(reset_scoop);
98EXPORT_SYMBOL(read_scoop_reg);
99EXPORT_SYMBOL(write_scoop_reg);
100
Richard Purdie7c398982005-10-10 10:20:06 +0100101static void check_scoop_reg(struct scoop_dev *sdev)
102{
103 unsigned short mcr;
104
Dmitry Baryshkovc353faa2008-04-09 23:05:09 +0100105 mcr = ioread16(sdev->base + SCOOP_MCR);
Richard Purdie7c398982005-10-10 10:20:06 +0100106 if ((mcr & 0x100) == 0)
Dmitry Baryshkovc353faa2008-04-09 23:05:09 +0100107 iowrite16(0x0101, sdev->base + SCOOP_MCR);
Richard Purdie7c398982005-10-10 10:20:06 +0100108}
109
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110#ifdef CONFIG_PM
Russell King3ae5eae2005-11-09 22:32:44 +0000111static int scoop_suspend(struct platform_device *dev, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112{
Russell King3ae5eae2005-11-09 22:32:44 +0000113 struct scoop_dev *sdev = platform_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114
Russell King9480e302005-10-28 09:52:56 -0700115 check_scoop_reg(sdev);
Dmitry Baryshkovc353faa2008-04-09 23:05:09 +0100116 sdev->scoop_gpwr = ioread16(sdev->base + SCOOP_GPWR);
117 iowrite16((sdev->scoop_gpwr & ~sdev->suspend_clr) | sdev->suspend_set, sdev->base + SCOOP_GPWR);
Russell King9480e302005-10-28 09:52:56 -0700118
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119 return 0;
120}
121
Russell King3ae5eae2005-11-09 22:32:44 +0000122static int scoop_resume(struct platform_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123{
Russell King3ae5eae2005-11-09 22:32:44 +0000124 struct scoop_dev *sdev = platform_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125
Russell King9480e302005-10-28 09:52:56 -0700126 check_scoop_reg(sdev);
Dmitry Baryshkovc353faa2008-04-09 23:05:09 +0100127 iowrite16(sdev->scoop_gpwr, sdev->base + SCOOP_GPWR);
Russell King9480e302005-10-28 09:52:56 -0700128
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 return 0;
130}
131#else
132#define scoop_suspend NULL
133#define scoop_resume NULL
134#endif
135
Dmitry Baryshkov2f8c5142008-04-09 22:43:37 +0100136static int __devinit scoop_probe(struct platform_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137{
138 struct scoop_dev *devptr;
139 struct scoop_config *inf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
141
142 if (!mem)
143 return -EINVAL;
144
Russell Kingd2a02b92006-03-20 19:46:41 +0000145 devptr = kzalloc(sizeof(struct scoop_dev), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 if (!devptr)
Russell Kingd2a02b92006-03-20 19:46:41 +0000147 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 spin_lock_init(&devptr->scoop_lock);
150
Russell King3ae5eae2005-11-09 22:32:44 +0000151 inf = pdev->dev.platform_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 devptr->base = ioremap(mem->start, mem->end - mem->start + 1);
153
154 if (!devptr->base) {
155 kfree(devptr);
156 return -ENOMEM;
157 }
158
Russell King3ae5eae2005-11-09 22:32:44 +0000159 platform_set_drvdata(pdev, devptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160
Dmitry Baryshkov2f8c5142008-04-09 22:43:37 +0100161 printk("Sharp Scoop Device found at 0x%08x -> 0x%8p\n",(unsigned int)mem->start, devptr->base);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162
Dmitry Baryshkovc353faa2008-04-09 23:05:09 +0100163 iowrite16(0x0140, devptr->base + SCOOP_MCR);
Pavel Machekc35bf4a2005-11-12 20:25:25 +0000164 reset_scoop(&pdev->dev);
Dmitry Baryshkovc353faa2008-04-09 23:05:09 +0100165 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);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168
Richard Purdie7c398982005-10-10 10:20:06 +0100169 devptr->suspend_clr = inf->suspend_clr;
170 devptr->suspend_set = inf->suspend_set;
171
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 return 0;
173}
174
Dmitry Baryshkov2f8c5142008-04-09 22:43:37 +0100175static int __devexit scoop_remove(struct platform_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176{
Russell King3ae5eae2005-11-09 22:32:44 +0000177 struct scoop_dev *sdev = platform_get_drvdata(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 if (sdev) {
179 iounmap(sdev->base);
180 kfree(sdev);
Russell King3ae5eae2005-11-09 22:32:44 +0000181 platform_set_drvdata(pdev, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 }
183 return 0;
184}
185
Russell King3ae5eae2005-11-09 22:32:44 +0000186static struct platform_driver scoop_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 .probe = scoop_probe,
Dmitry Baryshkov2f8c5142008-04-09 22:43:37 +0100188 .remove = __devexit_p(scoop_remove),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 .suspend = scoop_suspend,
190 .resume = scoop_resume,
Russell King3ae5eae2005-11-09 22:32:44 +0000191 .driver = {
192 .name = "sharp-scoop",
193 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194};
195
Dmitry Baryshkov2f8c5142008-04-09 22:43:37 +0100196static int __init scoop_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197{
Russell King3ae5eae2005-11-09 22:32:44 +0000198 return platform_driver_register(&scoop_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199}
200
201subsys_initcall(scoop_init);