diff options
author | Grant Likely <grant.likely@secretlab.ca> | 2011-06-04 20:38:28 -0400 |
---|---|---|
committer | Grant Likely <grant.likely@secretlab.ca> | 2011-06-06 12:10:11 -0400 |
commit | c103de240439dfee24ac50eb99c8be3a30d13323 (patch) | |
tree | 014eeda779510d7d3dfabd1183ce7f1a288d367b /drivers/gpio/cs5535-gpio.c | |
parent | 8c31b1635b91e48f867e010cd7bcd06393e5858a (diff) |
gpio: reorganize drivers
Sort the gpio makefile and enforce the naming convention gpio-*.c for
gpio drivers.
v2: cleaned up filenames in Kconfig and comment blocks
v3: fixup use of BASIC_MMIO to GENERIC_GPIO for mxc
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Diffstat (limited to 'drivers/gpio/cs5535-gpio.c')
-rw-r--r-- | drivers/gpio/cs5535-gpio.c | 401 |
1 files changed, 0 insertions, 401 deletions
diff --git a/drivers/gpio/cs5535-gpio.c b/drivers/gpio/cs5535-gpio.c deleted file mode 100644 index 6e16cba56ad2..000000000000 --- a/drivers/gpio/cs5535-gpio.c +++ /dev/null | |||
@@ -1,401 +0,0 @@ | |||
1 | /* | ||
2 | * AMD CS5535/CS5536 GPIO driver | ||
3 | * Copyright (C) 2006 Advanced Micro Devices, Inc. | ||
4 | * Copyright (C) 2007-2009 Andres Salomon <dilinger@collabora.co.uk> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of version 2 of the GNU General Public License | ||
8 | * as published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/spinlock.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | #include <linux/gpio.h> | ||
16 | #include <linux/io.h> | ||
17 | #include <linux/cs5535.h> | ||
18 | #include <asm/msr.h> | ||
19 | |||
20 | #define DRV_NAME "cs5535-gpio" | ||
21 | |||
22 | /* | ||
23 | * Some GPIO pins | ||
24 | * 31-29,23 : reserved (always mask out) | ||
25 | * 28 : Power Button | ||
26 | * 26 : PME# | ||
27 | * 22-16 : LPC | ||
28 | * 14,15 : SMBus | ||
29 | * 9,8 : UART1 | ||
30 | * 7 : PCI INTB | ||
31 | * 3,4 : UART2/DDC | ||
32 | * 2 : IDE_IRQ0 | ||
33 | * 1 : AC_BEEP | ||
34 | * 0 : PCI INTA | ||
35 | * | ||
36 | * If a mask was not specified, allow all except | ||
37 | * reserved and Power Button | ||
38 | */ | ||
39 | #define GPIO_DEFAULT_MASK 0x0F7FFFFF | ||
40 | |||
41 | static ulong mask = GPIO_DEFAULT_MASK; | ||
42 | module_param_named(mask, mask, ulong, 0444); | ||
43 | MODULE_PARM_DESC(mask, "GPIO channel mask."); | ||
44 | |||
45 | static struct cs5535_gpio_chip { | ||
46 | struct gpio_chip chip; | ||
47 | resource_size_t base; | ||
48 | |||
49 | struct platform_device *pdev; | ||
50 | spinlock_t lock; | ||
51 | } cs5535_gpio_chip; | ||
52 | |||
53 | /* | ||
54 | * The CS5535/CS5536 GPIOs support a number of extra features not defined | ||
55 | * by the gpio_chip API, so these are exported. For a full list of the | ||
56 | * registers, see include/linux/cs5535.h. | ||
57 | */ | ||
58 | |||
59 | static void errata_outl(struct cs5535_gpio_chip *chip, u32 val, | ||
60 | unsigned int reg) | ||
61 | { | ||
62 | unsigned long addr = chip->base + 0x80 + reg; | ||
63 | |||
64 | /* | ||
65 | * According to the CS5536 errata (#36), after suspend | ||
66 | * a write to the high bank GPIO register will clear all | ||
67 | * non-selected bits; the recommended workaround is a | ||
68 | * read-modify-write operation. | ||
69 | * | ||
70 | * Don't apply this errata to the edge status GPIOs, as writing | ||
71 | * to their lower bits will clear them. | ||
72 | */ | ||
73 | if (reg != GPIO_POSITIVE_EDGE_STS && reg != GPIO_NEGATIVE_EDGE_STS) { | ||
74 | if (val & 0xffff) | ||
75 | val |= (inl(addr) & 0xffff); /* ignore the high bits */ | ||
76 | else | ||
77 | val |= (inl(addr) ^ (val >> 16)); | ||
78 | } | ||
79 | outl(val, addr); | ||
80 | } | ||
81 | |||
82 | static void __cs5535_gpio_set(struct cs5535_gpio_chip *chip, unsigned offset, | ||
83 | unsigned int reg) | ||
84 | { | ||
85 | if (offset < 16) | ||
86 | /* low bank register */ | ||
87 | outl(1 << offset, chip->base + reg); | ||
88 | else | ||
89 | /* high bank register */ | ||
90 | errata_outl(chip, 1 << (offset - 16), reg); | ||
91 | } | ||
92 | |||
93 | void cs5535_gpio_set(unsigned offset, unsigned int reg) | ||
94 | { | ||
95 | struct cs5535_gpio_chip *chip = &cs5535_gpio_chip; | ||
96 | unsigned long flags; | ||
97 | |||
98 | spin_lock_irqsave(&chip->lock, flags); | ||
99 | __cs5535_gpio_set(chip, offset, reg); | ||
100 | spin_unlock_irqrestore(&chip->lock, flags); | ||
101 | } | ||
102 | EXPORT_SYMBOL_GPL(cs5535_gpio_set); | ||
103 | |||
104 | static void __cs5535_gpio_clear(struct cs5535_gpio_chip *chip, unsigned offset, | ||
105 | unsigned int reg) | ||
106 | { | ||
107 | if (offset < 16) | ||
108 | /* low bank register */ | ||
109 | outl(1 << (offset + 16), chip->base + reg); | ||
110 | else | ||
111 | /* high bank register */ | ||
112 | errata_outl(chip, 1 << offset, reg); | ||
113 | } | ||
114 | |||
115 | void cs5535_gpio_clear(unsigned offset, unsigned int reg) | ||
116 | { | ||
117 | struct cs5535_gpio_chip *chip = &cs5535_gpio_chip; | ||
118 | unsigned long flags; | ||
119 | |||
120 | spin_lock_irqsave(&chip->lock, flags); | ||
121 | __cs5535_gpio_clear(chip, offset, reg); | ||
122 | spin_unlock_irqrestore(&chip->lock, flags); | ||
123 | } | ||
124 | EXPORT_SYMBOL_GPL(cs5535_gpio_clear); | ||
125 | |||
126 | int cs5535_gpio_isset(unsigned offset, unsigned int reg) | ||
127 | { | ||
128 | struct cs5535_gpio_chip *chip = &cs5535_gpio_chip; | ||
129 | unsigned long flags; | ||
130 | long val; | ||
131 | |||
132 | spin_lock_irqsave(&chip->lock, flags); | ||
133 | if (offset < 16) | ||
134 | /* low bank register */ | ||
135 | val = inl(chip->base + reg); | ||
136 | else { | ||
137 | /* high bank register */ | ||
138 | val = inl(chip->base + 0x80 + reg); | ||
139 | offset -= 16; | ||
140 | } | ||
141 | spin_unlock_irqrestore(&chip->lock, flags); | ||
142 | |||
143 | return (val & (1 << offset)) ? 1 : 0; | ||
144 | } | ||
145 | EXPORT_SYMBOL_GPL(cs5535_gpio_isset); | ||
146 | |||
147 | int cs5535_gpio_set_irq(unsigned group, unsigned irq) | ||
148 | { | ||
149 | uint32_t lo, hi; | ||
150 | |||
151 | if (group > 7 || irq > 15) | ||
152 | return -EINVAL; | ||
153 | |||
154 | rdmsr(MSR_PIC_ZSEL_HIGH, lo, hi); | ||
155 | |||
156 | lo &= ~(0xF << (group * 4)); | ||
157 | lo |= (irq & 0xF) << (group * 4); | ||
158 | |||
159 | wrmsr(MSR_PIC_ZSEL_HIGH, lo, hi); | ||
160 | return 0; | ||
161 | } | ||
162 | EXPORT_SYMBOL_GPL(cs5535_gpio_set_irq); | ||
163 | |||
164 | void cs5535_gpio_setup_event(unsigned offset, int pair, int pme) | ||
165 | { | ||
166 | struct cs5535_gpio_chip *chip = &cs5535_gpio_chip; | ||
167 | uint32_t shift = (offset % 8) * 4; | ||
168 | unsigned long flags; | ||
169 | uint32_t val; | ||
170 | |||
171 | if (offset >= 24) | ||
172 | offset = GPIO_MAP_W; | ||
173 | else if (offset >= 16) | ||
174 | offset = GPIO_MAP_Z; | ||
175 | else if (offset >= 8) | ||
176 | offset = GPIO_MAP_Y; | ||
177 | else | ||
178 | offset = GPIO_MAP_X; | ||
179 | |||
180 | spin_lock_irqsave(&chip->lock, flags); | ||
181 | val = inl(chip->base + offset); | ||
182 | |||
183 | /* Clear whatever was there before */ | ||
184 | val &= ~(0xF << shift); | ||
185 | |||
186 | /* Set the new value */ | ||
187 | val |= ((pair & 7) << shift); | ||
188 | |||
189 | /* Set the PME bit if this is a PME event */ | ||
190 | if (pme) | ||
191 | val |= (1 << (shift + 3)); | ||
192 | |||
193 | outl(val, chip->base + offset); | ||
194 | spin_unlock_irqrestore(&chip->lock, flags); | ||
195 | } | ||
196 | EXPORT_SYMBOL_GPL(cs5535_gpio_setup_event); | ||
197 | |||
198 | /* | ||
199 | * Generic gpio_chip API support. | ||
200 | */ | ||
201 | |||
202 | static int chip_gpio_request(struct gpio_chip *c, unsigned offset) | ||
203 | { | ||
204 | struct cs5535_gpio_chip *chip = (struct cs5535_gpio_chip *) c; | ||
205 | unsigned long flags; | ||
206 | |||
207 | spin_lock_irqsave(&chip->lock, flags); | ||
208 | |||
209 | /* check if this pin is available */ | ||
210 | if ((mask & (1 << offset)) == 0) { | ||
211 | dev_info(&chip->pdev->dev, | ||
212 | "pin %u is not available (check mask)\n", offset); | ||
213 | spin_unlock_irqrestore(&chip->lock, flags); | ||
214 | return -EINVAL; | ||
215 | } | ||
216 | |||
217 | /* disable output aux 1 & 2 on this pin */ | ||
218 | __cs5535_gpio_clear(chip, offset, GPIO_OUTPUT_AUX1); | ||
219 | __cs5535_gpio_clear(chip, offset, GPIO_OUTPUT_AUX2); | ||
220 | |||
221 | /* disable input aux 1 on this pin */ | ||
222 | __cs5535_gpio_clear(chip, offset, GPIO_INPUT_AUX1); | ||
223 | |||
224 | spin_unlock_irqrestore(&chip->lock, flags); | ||
225 | |||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | static int chip_gpio_get(struct gpio_chip *chip, unsigned offset) | ||
230 | { | ||
231 | return cs5535_gpio_isset(offset, GPIO_READ_BACK); | ||
232 | } | ||
233 | |||
234 | static void chip_gpio_set(struct gpio_chip *chip, unsigned offset, int val) | ||
235 | { | ||
236 | if (val) | ||
237 | cs5535_gpio_set(offset, GPIO_OUTPUT_VAL); | ||
238 | else | ||
239 | cs5535_gpio_clear(offset, GPIO_OUTPUT_VAL); | ||
240 | } | ||
241 | |||
242 | static int chip_direction_input(struct gpio_chip *c, unsigned offset) | ||
243 | { | ||
244 | struct cs5535_gpio_chip *chip = (struct cs5535_gpio_chip *) c; | ||
245 | unsigned long flags; | ||
246 | |||
247 | spin_lock_irqsave(&chip->lock, flags); | ||
248 | __cs5535_gpio_set(chip, offset, GPIO_INPUT_ENABLE); | ||
249 | __cs5535_gpio_clear(chip, offset, GPIO_OUTPUT_ENABLE); | ||
250 | spin_unlock_irqrestore(&chip->lock, flags); | ||
251 | |||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | static int chip_direction_output(struct gpio_chip *c, unsigned offset, int val) | ||
256 | { | ||
257 | struct cs5535_gpio_chip *chip = (struct cs5535_gpio_chip *) c; | ||
258 | unsigned long flags; | ||
259 | |||
260 | spin_lock_irqsave(&chip->lock, flags); | ||
261 | |||
262 | __cs5535_gpio_set(chip, offset, GPIO_INPUT_ENABLE); | ||
263 | __cs5535_gpio_set(chip, offset, GPIO_OUTPUT_ENABLE); | ||
264 | if (val) | ||
265 | __cs5535_gpio_set(chip, offset, GPIO_OUTPUT_VAL); | ||
266 | else | ||
267 | __cs5535_gpio_clear(chip, offset, GPIO_OUTPUT_VAL); | ||
268 | |||
269 | spin_unlock_irqrestore(&chip->lock, flags); | ||
270 | |||
271 | return 0; | ||
272 | } | ||
273 | |||
274 | static const char * const cs5535_gpio_names[] = { | ||
275 | "GPIO0", "GPIO1", "GPIO2", "GPIO3", | ||
276 | "GPIO4", "GPIO5", "GPIO6", "GPIO7", | ||
277 | "GPIO8", "GPIO9", "GPIO10", "GPIO11", | ||
278 | "GPIO12", "GPIO13", "GPIO14", "GPIO15", | ||
279 | "GPIO16", "GPIO17", "GPIO18", "GPIO19", | ||
280 | "GPIO20", "GPIO21", "GPIO22", NULL, | ||
281 | "GPIO24", "GPIO25", "GPIO26", "GPIO27", | ||
282 | "GPIO28", NULL, NULL, NULL, | ||
283 | }; | ||
284 | |||
285 | static struct cs5535_gpio_chip cs5535_gpio_chip = { | ||
286 | .chip = { | ||
287 | .owner = THIS_MODULE, | ||
288 | .label = DRV_NAME, | ||
289 | |||
290 | .base = 0, | ||
291 | .ngpio = 32, | ||
292 | .names = cs5535_gpio_names, | ||
293 | .request = chip_gpio_request, | ||
294 | |||
295 | .get = chip_gpio_get, | ||
296 | .set = chip_gpio_set, | ||
297 | |||
298 | .direction_input = chip_direction_input, | ||
299 | .direction_output = chip_direction_output, | ||
300 | }, | ||
301 | }; | ||
302 | |||
303 | static int __devinit cs5535_gpio_probe(struct platform_device *pdev) | ||
304 | { | ||
305 | struct resource *res; | ||
306 | int err = -EIO; | ||
307 | ulong mask_orig = mask; | ||
308 | |||
309 | /* There are two ways to get the GPIO base address; one is by | ||
310 | * fetching it from MSR_LBAR_GPIO, the other is by reading the | ||
311 | * PCI BAR info. The latter method is easier (especially across | ||
312 | * different architectures), so we'll stick with that for now. If | ||
313 | * it turns out to be unreliable in the face of crappy BIOSes, we | ||
314 | * can always go back to using MSRs.. */ | ||
315 | |||
316 | res = platform_get_resource(pdev, IORESOURCE_IO, 0); | ||
317 | if (!res) { | ||
318 | dev_err(&pdev->dev, "can't fetch device resource info\n"); | ||
319 | goto done; | ||
320 | } | ||
321 | |||
322 | if (!request_region(res->start, resource_size(res), pdev->name)) { | ||
323 | dev_err(&pdev->dev, "can't request region\n"); | ||
324 | goto done; | ||
325 | } | ||
326 | |||
327 | /* set up the driver-specific struct */ | ||
328 | cs5535_gpio_chip.base = res->start; | ||
329 | cs5535_gpio_chip.pdev = pdev; | ||
330 | spin_lock_init(&cs5535_gpio_chip.lock); | ||
331 | |||
332 | dev_info(&pdev->dev, "reserved resource region %pR\n", res); | ||
333 | |||
334 | /* mask out reserved pins */ | ||
335 | mask &= 0x1F7FFFFF; | ||
336 | |||
337 | /* do not allow pin 28, Power Button, as there's special handling | ||
338 | * in the PMC needed. (note 12, p. 48) */ | ||
339 | mask &= ~(1 << 28); | ||
340 | |||
341 | if (mask_orig != mask) | ||
342 | dev_info(&pdev->dev, "mask changed from 0x%08lX to 0x%08lX\n", | ||
343 | mask_orig, mask); | ||
344 | |||
345 | /* finally, register with the generic GPIO API */ | ||
346 | err = gpiochip_add(&cs5535_gpio_chip.chip); | ||
347 | if (err) | ||
348 | goto release_region; | ||
349 | |||
350 | dev_info(&pdev->dev, "GPIO support successfully loaded.\n"); | ||
351 | return 0; | ||
352 | |||
353 | release_region: | ||
354 | release_region(res->start, resource_size(res)); | ||
355 | done: | ||
356 | return err; | ||
357 | } | ||
358 | |||
359 | static int __devexit cs5535_gpio_remove(struct platform_device *pdev) | ||
360 | { | ||
361 | struct resource *r; | ||
362 | int err; | ||
363 | |||
364 | err = gpiochip_remove(&cs5535_gpio_chip.chip); | ||
365 | if (err) { | ||
366 | /* uhh? */ | ||
367 | dev_err(&pdev->dev, "unable to remove gpio_chip?\n"); | ||
368 | return err; | ||
369 | } | ||
370 | |||
371 | r = platform_get_resource(pdev, IORESOURCE_IO, 0); | ||
372 | release_region(r->start, resource_size(r)); | ||
373 | return 0; | ||
374 | } | ||
375 | |||
376 | static struct platform_driver cs5535_gpio_driver = { | ||
377 | .driver = { | ||
378 | .name = DRV_NAME, | ||
379 | .owner = THIS_MODULE, | ||
380 | }, | ||
381 | .probe = cs5535_gpio_probe, | ||
382 | .remove = __devexit_p(cs5535_gpio_remove), | ||
383 | }; | ||
384 | |||
385 | static int __init cs5535_gpio_init(void) | ||
386 | { | ||
387 | return platform_driver_register(&cs5535_gpio_driver); | ||
388 | } | ||
389 | |||
390 | static void __exit cs5535_gpio_exit(void) | ||
391 | { | ||
392 | platform_driver_unregister(&cs5535_gpio_driver); | ||
393 | } | ||
394 | |||
395 | module_init(cs5535_gpio_init); | ||
396 | module_exit(cs5535_gpio_exit); | ||
397 | |||
398 | MODULE_AUTHOR("Andres Salomon <dilinger@queued.net>"); | ||
399 | MODULE_DESCRIPTION("AMD CS5535/CS5536 GPIO driver"); | ||
400 | MODULE_LICENSE("GPL"); | ||
401 | MODULE_ALIAS("platform:" DRV_NAME); | ||