Root/
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 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 | return 0; |
351 | |
352 | release_region: |
353 | release_region(res->start, resource_size(res)); |
354 | done: |
355 | return err; |
356 | } |
357 | |
358 | static int cs5535_gpio_remove(struct platform_device *pdev) |
359 | { |
360 | struct resource *r; |
361 | int err; |
362 | |
363 | err = gpiochip_remove(&cs5535_gpio_chip.chip); |
364 | if (err) { |
365 | /* uhh? */ |
366 | dev_err(&pdev->dev, "unable to remove gpio_chip?\n"); |
367 | return err; |
368 | } |
369 | |
370 | r = platform_get_resource(pdev, IORESOURCE_IO, 0); |
371 | release_region(r->start, resource_size(r)); |
372 | return 0; |
373 | } |
374 | |
375 | static struct platform_driver cs5535_gpio_driver = { |
376 | .driver = { |
377 | .name = DRV_NAME, |
378 | .owner = THIS_MODULE, |
379 | }, |
380 | .probe = cs5535_gpio_probe, |
381 | .remove = cs5535_gpio_remove, |
382 | }; |
383 | |
384 | module_platform_driver(cs5535_gpio_driver); |
385 | |
386 | MODULE_AUTHOR("Andres Salomon <dilinger@queued.net>"); |
387 | MODULE_DESCRIPTION("AMD CS5535/CS5536 GPIO driver"); |
388 | MODULE_LICENSE("GPL"); |
389 | MODULE_ALIAS("platform:" DRV_NAME); |
390 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9