Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
scoop.c
Go to the documentation of this file.
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/gpio.h>
16 #include <linux/string.h>
17 #include <linux/slab.h>
18 #include <linux/platform_device.h>
19 #include <linux/export.h>
20 #include <linux/io.h>
21 #include <asm/hardware/scoop.h>
22 
23 /* PCMCIA to Scoop linkage
24 
25  There is no easy way to link multiple scoop devices into one
26  single entity for the pxa2xx_pcmcia device so this structure
27  is used which is setup by the platform code.
28 
29  This file is never modular so this symbol is always
30  accessile to the board support files.
31 */
33 EXPORT_SYMBOL(platform_scoop_config);
34 
35 struct scoop_dev {
36  void __iomem *base;
37  struct gpio_chip gpio;
39  unsigned short suspend_clr;
40  unsigned short suspend_set;
42 };
43 
44 void reset_scoop(struct device *dev)
45 {
46  struct scoop_dev *sdev = dev_get_drvdata(dev);
47 
48  iowrite16(0x0100, sdev->base + SCOOP_MCR); /* 00 */
49  iowrite16(0x0000, sdev->base + SCOOP_CDR); /* 04 */
50  iowrite16(0x0000, sdev->base + SCOOP_CCR); /* 10 */
51  iowrite16(0x0000, sdev->base + SCOOP_IMR); /* 18 */
52  iowrite16(0x00FF, sdev->base + SCOOP_IRM); /* 14 */
53  iowrite16(0x0000, sdev->base + SCOOP_ISR); /* 1C */
54  iowrite16(0x0000, sdev->base + SCOOP_IRM);
55 }
56 
57 static void __scoop_gpio_set(struct scoop_dev *sdev,
58  unsigned offset, int value)
59 {
60  unsigned short gpwr;
61 
62  gpwr = ioread16(sdev->base + SCOOP_GPWR);
63  if (value)
64  gpwr |= 1 << (offset + 1);
65  else
66  gpwr &= ~(1 << (offset + 1));
67  iowrite16(gpwr, sdev->base + SCOOP_GPWR);
68 }
69 
70 static void scoop_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
71 {
72  struct scoop_dev *sdev = container_of(chip, struct scoop_dev, gpio);
73  unsigned long flags;
74 
75  spin_lock_irqsave(&sdev->scoop_lock, flags);
76 
77  __scoop_gpio_set(sdev, offset, value);
78 
79  spin_unlock_irqrestore(&sdev->scoop_lock, flags);
80 }
81 
82 static int scoop_gpio_get(struct gpio_chip *chip, unsigned offset)
83 {
84  struct scoop_dev *sdev = container_of(chip, struct scoop_dev, gpio);
85 
86  /* XXX: I'm unsure, but it seems so */
87  return ioread16(sdev->base + SCOOP_GPRR) & (1 << (offset + 1));
88 }
89 
90 static int scoop_gpio_direction_input(struct gpio_chip *chip,
91  unsigned offset)
92 {
93  struct scoop_dev *sdev = container_of(chip, struct scoop_dev, gpio);
94  unsigned long flags;
95  unsigned short gpcr;
96 
97  spin_lock_irqsave(&sdev->scoop_lock, flags);
98 
99  gpcr = ioread16(sdev->base + SCOOP_GPCR);
100  gpcr &= ~(1 << (offset + 1));
101  iowrite16(gpcr, sdev->base + SCOOP_GPCR);
102 
103  spin_unlock_irqrestore(&sdev->scoop_lock, flags);
104 
105  return 0;
106 }
107 
108 static int scoop_gpio_direction_output(struct gpio_chip *chip,
109  unsigned offset, int value)
110 {
111  struct scoop_dev *sdev = container_of(chip, struct scoop_dev, gpio);
112  unsigned long flags;
113  unsigned short gpcr;
114 
115  spin_lock_irqsave(&sdev->scoop_lock, flags);
116 
117  __scoop_gpio_set(sdev, offset, value);
118 
119  gpcr = ioread16(sdev->base + SCOOP_GPCR);
120  gpcr |= 1 << (offset + 1);
121  iowrite16(gpcr, sdev->base + SCOOP_GPCR);
122 
123  spin_unlock_irqrestore(&sdev->scoop_lock, flags);
124 
125  return 0;
126 }
127 
128 unsigned short read_scoop_reg(struct device *dev, unsigned short reg)
129 {
130  struct scoop_dev *sdev = dev_get_drvdata(dev);
131  return ioread16(sdev->base + reg);
132 }
133 
134 void write_scoop_reg(struct device *dev, unsigned short reg, unsigned short data)
135 {
136  struct scoop_dev *sdev = dev_get_drvdata(dev);
137  iowrite16(data, sdev->base + reg);
138 }
139 
143 
144 #ifdef CONFIG_PM
145 static void check_scoop_reg(struct scoop_dev *sdev)
146 {
147  unsigned short mcr;
148 
149  mcr = ioread16(sdev->base + SCOOP_MCR);
150  if ((mcr & 0x100) == 0)
151  iowrite16(0x0101, sdev->base + SCOOP_MCR);
152 }
153 
155 {
156  struct scoop_dev *sdev = platform_get_drvdata(dev);
157 
158  check_scoop_reg(sdev);
159  sdev->scoop_gpwr = ioread16(sdev->base + SCOOP_GPWR);
160  iowrite16((sdev->scoop_gpwr & ~sdev->suspend_clr) | sdev->suspend_set, sdev->base + SCOOP_GPWR);
161 
162  return 0;
163 }
164 
165 static int scoop_resume(struct platform_device *dev)
166 {
167  struct scoop_dev *sdev = platform_get_drvdata(dev);
168 
169  check_scoop_reg(sdev);
170  iowrite16(sdev->scoop_gpwr, sdev->base + SCOOP_GPWR);
171 
172  return 0;
173 }
174 #else
175 #define scoop_suspend NULL
176 #define scoop_resume NULL
177 #endif
178 
179 static int __devinit scoop_probe(struct platform_device *pdev)
180 {
181  struct scoop_dev *devptr;
182  struct scoop_config *inf;
183  struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
184  int ret;
185  int temp;
186 
187  if (!mem)
188  return -EINVAL;
189 
190  devptr = kzalloc(sizeof(struct scoop_dev), GFP_KERNEL);
191  if (!devptr)
192  return -ENOMEM;
193 
194  spin_lock_init(&devptr->scoop_lock);
195 
196  inf = pdev->dev.platform_data;
197  devptr->base = ioremap(mem->start, resource_size(mem));
198 
199  if (!devptr->base) {
200  ret = -ENOMEM;
201  goto err_ioremap;
202  }
203 
204  platform_set_drvdata(pdev, devptr);
205 
206  printk("Sharp Scoop Device found at 0x%08x -> 0x%8p\n",(unsigned int)mem->start, devptr->base);
207 
208  iowrite16(0x0140, devptr->base + SCOOP_MCR);
209  reset_scoop(&pdev->dev);
210  iowrite16(0x0000, devptr->base + SCOOP_CPR);
211  iowrite16(inf->io_dir & 0xffff, devptr->base + SCOOP_GPCR);
212  iowrite16(inf->io_out & 0xffff, devptr->base + SCOOP_GPWR);
213 
214  devptr->suspend_clr = inf->suspend_clr;
215  devptr->suspend_set = inf->suspend_set;
216 
217  devptr->gpio.base = -1;
218 
219  if (inf->gpio_base != 0) {
220  devptr->gpio.label = dev_name(&pdev->dev);
221  devptr->gpio.base = inf->gpio_base;
222  devptr->gpio.ngpio = 12; /* PA11 = 0, PA12 = 1, etc. up to PA22 = 11 */
223  devptr->gpio.set = scoop_gpio_set;
224  devptr->gpio.get = scoop_gpio_get;
225  devptr->gpio.direction_input = scoop_gpio_direction_input;
226  devptr->gpio.direction_output = scoop_gpio_direction_output;
227 
228  ret = gpiochip_add(&devptr->gpio);
229  if (ret)
230  goto err_gpio;
231  }
232 
233  return 0;
234 
235  if (devptr->gpio.base != -1)
236  temp = gpiochip_remove(&devptr->gpio);
237 err_gpio:
238  platform_set_drvdata(pdev, NULL);
239 err_ioremap:
240  iounmap(devptr->base);
241  kfree(devptr);
242 
243  return ret;
244 }
245 
246 static int __devexit scoop_remove(struct platform_device *pdev)
247 {
248  struct scoop_dev *sdev = platform_get_drvdata(pdev);
249  int ret;
250 
251  if (!sdev)
252  return -EINVAL;
253 
254  if (sdev->gpio.base != -1) {
255  ret = gpiochip_remove(&sdev->gpio);
256  if (ret) {
257  dev_err(&pdev->dev, "Can't remove gpio chip: %d\n", ret);
258  return ret;
259  }
260  }
261 
262  platform_set_drvdata(pdev, NULL);
263  iounmap(sdev->base);
264  kfree(sdev);
265 
266  return 0;
267 }
268 
269 static struct platform_driver scoop_driver = {
270  .probe = scoop_probe,
271  .remove = __devexit_p(scoop_remove),
272  .suspend = scoop_suspend,
273  .resume = scoop_resume,
274  .driver = {
275  .name = "sharp-scoop",
276  },
277 };
278 
279 static int __init scoop_init(void)
280 {
281  return platform_driver_register(&scoop_driver);
282 }
283 
284 subsys_initcall(scoop_init);