Merge branch 'for-2638/i2c/nomadik' into for-linus/i2c-2638
[deliverable/linux.git] / drivers / gpio / cs5535-gpio.c
CommitLineData
5f0a96b0
AS
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/pci.h>
15#include <linux/gpio.h>
16#include <linux/io.h>
17#include <linux/cs5535.h>
18
19#define DRV_NAME "cs5535-gpio"
20#define GPIO_BAR 1
21
1ea3fa7b
TM
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
41static ulong mask = GPIO_DEFAULT_MASK;
42module_param_named(mask, mask, ulong, 0444);
43MODULE_PARM_DESC(mask, "GPIO channel mask.");
44
5f0a96b0
AS
45static struct cs5535_gpio_chip {
46 struct gpio_chip chip;
47 resource_size_t base;
48
49 struct pci_dev *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
00185165
AS
59static void errata_outl(struct cs5535_gpio_chip *chip, u32 val,
60 unsigned int reg)
853ff883 61{
00185165
AS
62 unsigned long addr = chip->base + 0x80 + reg;
63
853ff883
AS
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.
00185165
AS
69 *
70 * Don't apply this errata to the edge status GPIOs, as writing
71 * to their lower bits will clear them.
853ff883 72 */
44658a11
AS
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 }
853ff883
AS
79 outl(val, addr);
80}
81
5f0a96b0
AS
82static 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 */
00185165 90 errata_outl(chip, 1 << (offset - 16), reg);
5f0a96b0
AS
91}
92
93void 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}
102EXPORT_SYMBOL_GPL(cs5535_gpio_set);
103
104static 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 */
00185165 112 errata_outl(chip, 1 << offset, reg);
5f0a96b0
AS
113}
114
115void 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}
124EXPORT_SYMBOL_GPL(cs5535_gpio_clear);
125
126int 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}
145EXPORT_SYMBOL_GPL(cs5535_gpio_isset);
146
147/*
148 * Generic gpio_chip API support.
149 */
150
1ea3fa7b
TM
151static int chip_gpio_request(struct gpio_chip *c, unsigned offset)
152{
153 struct cs5535_gpio_chip *chip = (struct cs5535_gpio_chip *) c;
154 unsigned long flags;
155
156 spin_lock_irqsave(&chip->lock, flags);
157
158 /* check if this pin is available */
159 if ((mask & (1 << offset)) == 0) {
160 dev_info(&chip->pdev->dev,
161 "pin %u is not available (check mask)\n", offset);
162 spin_unlock_irqrestore(&chip->lock, flags);
163 return -EINVAL;
164 }
165
166 /* disable output aux 1 & 2 on this pin */
167 __cs5535_gpio_clear(chip, offset, GPIO_OUTPUT_AUX1);
168 __cs5535_gpio_clear(chip, offset, GPIO_OUTPUT_AUX2);
169
170 /* disable input aux 1 on this pin */
171 __cs5535_gpio_clear(chip, offset, GPIO_INPUT_AUX1);
172
173 spin_unlock_irqrestore(&chip->lock, flags);
174
175 return 0;
176}
177
5f0a96b0
AS
178static int chip_gpio_get(struct gpio_chip *chip, unsigned offset)
179{
a8a5164c 180 return cs5535_gpio_isset(offset, GPIO_READ_BACK);
5f0a96b0
AS
181}
182
183static void chip_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
184{
185 if (val)
186 cs5535_gpio_set(offset, GPIO_OUTPUT_VAL);
187 else
188 cs5535_gpio_clear(offset, GPIO_OUTPUT_VAL);
189}
190
191static int chip_direction_input(struct gpio_chip *c, unsigned offset)
192{
193 struct cs5535_gpio_chip *chip = (struct cs5535_gpio_chip *) c;
194 unsigned long flags;
195
196 spin_lock_irqsave(&chip->lock, flags);
197 __cs5535_gpio_set(chip, offset, GPIO_INPUT_ENABLE);
a8a5164c 198 __cs5535_gpio_clear(chip, offset, GPIO_OUTPUT_ENABLE);
5f0a96b0
AS
199 spin_unlock_irqrestore(&chip->lock, flags);
200
201 return 0;
202}
203
204static int chip_direction_output(struct gpio_chip *c, unsigned offset, int val)
205{
206 struct cs5535_gpio_chip *chip = (struct cs5535_gpio_chip *) c;
207 unsigned long flags;
208
209 spin_lock_irqsave(&chip->lock, flags);
210
a8a5164c 211 __cs5535_gpio_set(chip, offset, GPIO_INPUT_ENABLE);
5f0a96b0
AS
212 __cs5535_gpio_set(chip, offset, GPIO_OUTPUT_ENABLE);
213 if (val)
214 __cs5535_gpio_set(chip, offset, GPIO_OUTPUT_VAL);
215 else
216 __cs5535_gpio_clear(chip, offset, GPIO_OUTPUT_VAL);
217
218 spin_unlock_irqrestore(&chip->lock, flags);
219
220 return 0;
221}
222
62154991 223static const char * const cs5535_gpio_names[] = {
1ea3fa7b
TM
224 "GPIO0", "GPIO1", "GPIO2", "GPIO3",
225 "GPIO4", "GPIO5", "GPIO6", "GPIO7",
226 "GPIO8", "GPIO9", "GPIO10", "GPIO11",
227 "GPIO12", "GPIO13", "GPIO14", "GPIO15",
228 "GPIO16", "GPIO17", "GPIO18", "GPIO19",
229 "GPIO20", "GPIO21", "GPIO22", NULL,
230 "GPIO24", "GPIO25", "GPIO26", "GPIO27",
231 "GPIO28", NULL, NULL, NULL,
232};
233
5f0a96b0
AS
234static struct cs5535_gpio_chip cs5535_gpio_chip = {
235 .chip = {
236 .owner = THIS_MODULE,
237 .label = DRV_NAME,
238
239 .base = 0,
1ea3fa7b
TM
240 .ngpio = 32,
241 .names = cs5535_gpio_names,
242 .request = chip_gpio_request,
5f0a96b0
AS
243
244 .get = chip_gpio_get,
245 .set = chip_gpio_set,
246
247 .direction_input = chip_direction_input,
248 .direction_output = chip_direction_output,
249 },
250};
251
252static int __init cs5535_gpio_probe(struct pci_dev *pdev,
253 const struct pci_device_id *pci_id)
254{
255 int err;
1ea3fa7b 256 ulong mask_orig = mask;
5f0a96b0
AS
257
258 /* There are two ways to get the GPIO base address; one is by
259 * fetching it from MSR_LBAR_GPIO, the other is by reading the
260 * PCI BAR info. The latter method is easier (especially across
261 * different architectures), so we'll stick with that for now. If
262 * it turns out to be unreliable in the face of crappy BIOSes, we
263 * can always go back to using MSRs.. */
264
265 err = pci_enable_device_io(pdev);
266 if (err) {
267 dev_err(&pdev->dev, "can't enable device IO\n");
268 goto done;
269 }
270
271 err = pci_request_region(pdev, GPIO_BAR, DRV_NAME);
272 if (err) {
273 dev_err(&pdev->dev, "can't alloc PCI BAR #%d\n", GPIO_BAR);
274 goto done;
275 }
276
277 /* set up the driver-specific struct */
278 cs5535_gpio_chip.base = pci_resource_start(pdev, GPIO_BAR);
279 cs5535_gpio_chip.pdev = pdev;
280 spin_lock_init(&cs5535_gpio_chip.lock);
281
282 dev_info(&pdev->dev, "allocated PCI BAR #%d: base 0x%llx\n", GPIO_BAR,
283 (unsigned long long) cs5535_gpio_chip.base);
284
1ea3fa7b
TM
285 /* mask out reserved pins */
286 mask &= 0x1F7FFFFF;
287
288 /* do not allow pin 28, Power Button, as there's special handling
289 * in the PMC needed. (note 12, p. 48) */
290 mask &= ~(1 << 28);
291
292 if (mask_orig != mask)
293 dev_info(&pdev->dev, "mask changed from 0x%08lX to 0x%08lX\n",
294 mask_orig, mask);
295
5f0a96b0
AS
296 /* finally, register with the generic GPIO API */
297 err = gpiochip_add(&cs5535_gpio_chip.chip);
1ea3fa7b 298 if (err)
5f0a96b0 299 goto release_region;
5f0a96b0 300
1ea3fa7b 301 dev_info(&pdev->dev, DRV_NAME ": GPIO support successfully loaded.\n");
5f0a96b0
AS
302 return 0;
303
304release_region:
305 pci_release_region(pdev, GPIO_BAR);
306done:
307 return err;
308}
309
310static void __exit cs5535_gpio_remove(struct pci_dev *pdev)
311{
312 int err;
313
314 err = gpiochip_remove(&cs5535_gpio_chip.chip);
315 if (err) {
316 /* uhh? */
317 dev_err(&pdev->dev, "unable to remove gpio_chip?\n");
318 }
319 pci_release_region(pdev, GPIO_BAR);
320}
321
322static struct pci_device_id cs5535_gpio_pci_tbl[] = {
323 { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) },
324 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) },
325 { 0, },
326};
327MODULE_DEVICE_TABLE(pci, cs5535_gpio_pci_tbl);
328
329/*
330 * We can't use the standard PCI driver registration stuff here, since
331 * that allows only one driver to bind to each PCI device (and we want
332 * multiple drivers to be able to bind to the device). Instead, manually
333 * scan for the PCI device, request a single region, and keep track of the
334 * devices that we're using.
335 */
336
337static int __init cs5535_gpio_scan_pci(void)
338{
339 struct pci_dev *pdev;
340 int err = -ENODEV;
341 int i;
342
343 for (i = 0; i < ARRAY_SIZE(cs5535_gpio_pci_tbl); i++) {
344 pdev = pci_get_device(cs5535_gpio_pci_tbl[i].vendor,
345 cs5535_gpio_pci_tbl[i].device, NULL);
346 if (pdev) {
347 err = cs5535_gpio_probe(pdev, &cs5535_gpio_pci_tbl[i]);
348 if (err)
349 pci_dev_put(pdev);
350
351 /* we only support a single CS5535/6 southbridge */
352 break;
353 }
354 }
355
356 return err;
357}
358
359static void __exit cs5535_gpio_free_pci(void)
360{
361 cs5535_gpio_remove(cs5535_gpio_chip.pdev);
362 pci_dev_put(cs5535_gpio_chip.pdev);
363}
364
365static int __init cs5535_gpio_init(void)
366{
367 return cs5535_gpio_scan_pci();
368}
369
370static void __exit cs5535_gpio_exit(void)
371{
372 cs5535_gpio_free_pci();
373}
374
375module_init(cs5535_gpio_init);
376module_exit(cs5535_gpio_exit);
377
d45840d9 378MODULE_AUTHOR("Andres Salomon <dilinger@queued.net>");
5f0a96b0
AS
379MODULE_DESCRIPTION("AMD CS5535/CS5536 GPIO driver");
380MODULE_LICENSE("GPL");
This page took 0.106072 seconds and 5 git commands to generate.