blob: 0fdbe94f24a3a0f320266d6505a3062e1aa5f6cd [file] [log] [blame]
Andres Salomon5f0a96b2009-12-14 18:00:32 -08001/*
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
Tobias Mueller1ea3fa72009-12-14 18:00:35 -080022/*
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
Andres Salomon5f0a96b2009-12-14 18:00:32 -080045static 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
59static void __cs5535_gpio_set(struct cs5535_gpio_chip *chip, unsigned offset,
60 unsigned int reg)
61{
62 if (offset < 16)
63 /* low bank register */
64 outl(1 << offset, chip->base + reg);
65 else
66 /* high bank register */
67 outl(1 << (offset - 16), chip->base + 0x80 + reg);
68}
69
70void cs5535_gpio_set(unsigned offset, unsigned int reg)
71{
72 struct cs5535_gpio_chip *chip = &cs5535_gpio_chip;
73 unsigned long flags;
74
75 spin_lock_irqsave(&chip->lock, flags);
76 __cs5535_gpio_set(chip, offset, reg);
77 spin_unlock_irqrestore(&chip->lock, flags);
78}
79EXPORT_SYMBOL_GPL(cs5535_gpio_set);
80
81static void __cs5535_gpio_clear(struct cs5535_gpio_chip *chip, unsigned offset,
82 unsigned int reg)
83{
84 if (offset < 16)
85 /* low bank register */
86 outl(1 << (offset + 16), chip->base + reg);
87 else
88 /* high bank register */
89 outl(1 << offset, chip->base + 0x80 + reg);
90}
91
92void cs5535_gpio_clear(unsigned offset, unsigned int reg)
93{
94 struct cs5535_gpio_chip *chip = &cs5535_gpio_chip;
95 unsigned long flags;
96
97 spin_lock_irqsave(&chip->lock, flags);
98 __cs5535_gpio_clear(chip, offset, reg);
99 spin_unlock_irqrestore(&chip->lock, flags);
100}
101EXPORT_SYMBOL_GPL(cs5535_gpio_clear);
102
103int cs5535_gpio_isset(unsigned offset, unsigned int reg)
104{
105 struct cs5535_gpio_chip *chip = &cs5535_gpio_chip;
106 unsigned long flags;
107 long val;
108
109 spin_lock_irqsave(&chip->lock, flags);
110 if (offset < 16)
111 /* low bank register */
112 val = inl(chip->base + reg);
113 else {
114 /* high bank register */
115 val = inl(chip->base + 0x80 + reg);
116 offset -= 16;
117 }
118 spin_unlock_irqrestore(&chip->lock, flags);
119
120 return (val & (1 << offset)) ? 1 : 0;
121}
122EXPORT_SYMBOL_GPL(cs5535_gpio_isset);
123
124/*
125 * Generic gpio_chip API support.
126 */
127
Tobias Mueller1ea3fa72009-12-14 18:00:35 -0800128static int chip_gpio_request(struct gpio_chip *c, unsigned offset)
129{
130 struct cs5535_gpio_chip *chip = (struct cs5535_gpio_chip *) c;
131 unsigned long flags;
132
133 spin_lock_irqsave(&chip->lock, flags);
134
135 /* check if this pin is available */
136 if ((mask & (1 << offset)) == 0) {
137 dev_info(&chip->pdev->dev,
138 "pin %u is not available (check mask)\n", offset);
139 spin_unlock_irqrestore(&chip->lock, flags);
140 return -EINVAL;
141 }
142
143 /* disable output aux 1 & 2 on this pin */
144 __cs5535_gpio_clear(chip, offset, GPIO_OUTPUT_AUX1);
145 __cs5535_gpio_clear(chip, offset, GPIO_OUTPUT_AUX2);
146
147 /* disable input aux 1 on this pin */
148 __cs5535_gpio_clear(chip, offset, GPIO_INPUT_AUX1);
149
150 spin_unlock_irqrestore(&chip->lock, flags);
151
152 return 0;
153}
154
Andres Salomon5f0a96b2009-12-14 18:00:32 -0800155static int chip_gpio_get(struct gpio_chip *chip, unsigned offset)
156{
157 return cs5535_gpio_isset(offset, GPIO_OUTPUT_VAL);
158}
159
160static void chip_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
161{
162 if (val)
163 cs5535_gpio_set(offset, GPIO_OUTPUT_VAL);
164 else
165 cs5535_gpio_clear(offset, GPIO_OUTPUT_VAL);
166}
167
168static int chip_direction_input(struct gpio_chip *c, unsigned offset)
169{
170 struct cs5535_gpio_chip *chip = (struct cs5535_gpio_chip *) c;
171 unsigned long flags;
172
173 spin_lock_irqsave(&chip->lock, flags);
174 __cs5535_gpio_set(chip, offset, GPIO_INPUT_ENABLE);
175 spin_unlock_irqrestore(&chip->lock, flags);
176
177 return 0;
178}
179
180static int chip_direction_output(struct gpio_chip *c, unsigned offset, int val)
181{
182 struct cs5535_gpio_chip *chip = (struct cs5535_gpio_chip *) c;
183 unsigned long flags;
184
185 spin_lock_irqsave(&chip->lock, flags);
186
187 __cs5535_gpio_set(chip, offset, GPIO_OUTPUT_ENABLE);
188 if (val)
189 __cs5535_gpio_set(chip, offset, GPIO_OUTPUT_VAL);
190 else
191 __cs5535_gpio_clear(chip, offset, GPIO_OUTPUT_VAL);
192
193 spin_unlock_irqrestore(&chip->lock, flags);
194
195 return 0;
196}
197
Tobias Mueller1ea3fa72009-12-14 18:00:35 -0800198static char *cs5535_gpio_names[] = {
199 "GPIO0", "GPIO1", "GPIO2", "GPIO3",
200 "GPIO4", "GPIO5", "GPIO6", "GPIO7",
201 "GPIO8", "GPIO9", "GPIO10", "GPIO11",
202 "GPIO12", "GPIO13", "GPIO14", "GPIO15",
203 "GPIO16", "GPIO17", "GPIO18", "GPIO19",
204 "GPIO20", "GPIO21", "GPIO22", NULL,
205 "GPIO24", "GPIO25", "GPIO26", "GPIO27",
206 "GPIO28", NULL, NULL, NULL,
207};
208
Andres Salomon5f0a96b2009-12-14 18:00:32 -0800209static struct cs5535_gpio_chip cs5535_gpio_chip = {
210 .chip = {
211 .owner = THIS_MODULE,
212 .label = DRV_NAME,
213
214 .base = 0,
Tobias Mueller1ea3fa72009-12-14 18:00:35 -0800215 .ngpio = 32,
216 .names = cs5535_gpio_names,
217 .request = chip_gpio_request,
Andres Salomon5f0a96b2009-12-14 18:00:32 -0800218
219 .get = chip_gpio_get,
220 .set = chip_gpio_set,
221
222 .direction_input = chip_direction_input,
223 .direction_output = chip_direction_output,
224 },
225};
226
227static int __init cs5535_gpio_probe(struct pci_dev *pdev,
228 const struct pci_device_id *pci_id)
229{
230 int err;
Tobias Mueller1ea3fa72009-12-14 18:00:35 -0800231 ulong mask_orig = mask;
Andres Salomon5f0a96b2009-12-14 18:00:32 -0800232
233 /* There are two ways to get the GPIO base address; one is by
234 * fetching it from MSR_LBAR_GPIO, the other is by reading the
235 * PCI BAR info. The latter method is easier (especially across
236 * different architectures), so we'll stick with that for now. If
237 * it turns out to be unreliable in the face of crappy BIOSes, we
238 * can always go back to using MSRs.. */
239
240 err = pci_enable_device_io(pdev);
241 if (err) {
242 dev_err(&pdev->dev, "can't enable device IO\n");
243 goto done;
244 }
245
246 err = pci_request_region(pdev, GPIO_BAR, DRV_NAME);
247 if (err) {
248 dev_err(&pdev->dev, "can't alloc PCI BAR #%d\n", GPIO_BAR);
249 goto done;
250 }
251
252 /* set up the driver-specific struct */
253 cs5535_gpio_chip.base = pci_resource_start(pdev, GPIO_BAR);
254 cs5535_gpio_chip.pdev = pdev;
255 spin_lock_init(&cs5535_gpio_chip.lock);
256
257 dev_info(&pdev->dev, "allocated PCI BAR #%d: base 0x%llx\n", GPIO_BAR,
258 (unsigned long long) cs5535_gpio_chip.base);
259
Tobias Mueller1ea3fa72009-12-14 18:00:35 -0800260 /* mask out reserved pins */
261 mask &= 0x1F7FFFFF;
262
263 /* do not allow pin 28, Power Button, as there's special handling
264 * in the PMC needed. (note 12, p. 48) */
265 mask &= ~(1 << 28);
266
267 if (mask_orig != mask)
268 dev_info(&pdev->dev, "mask changed from 0x%08lX to 0x%08lX\n",
269 mask_orig, mask);
270
Andres Salomon5f0a96b2009-12-14 18:00:32 -0800271 /* finally, register with the generic GPIO API */
272 err = gpiochip_add(&cs5535_gpio_chip.chip);
Tobias Mueller1ea3fa72009-12-14 18:00:35 -0800273 if (err)
Andres Salomon5f0a96b2009-12-14 18:00:32 -0800274 goto release_region;
Andres Salomon5f0a96b2009-12-14 18:00:32 -0800275
Tobias Mueller1ea3fa72009-12-14 18:00:35 -0800276 dev_info(&pdev->dev, DRV_NAME ": GPIO support successfully loaded.\n");
Andres Salomon5f0a96b2009-12-14 18:00:32 -0800277 return 0;
278
279release_region:
280 pci_release_region(pdev, GPIO_BAR);
281done:
282 return err;
283}
284
285static void __exit cs5535_gpio_remove(struct pci_dev *pdev)
286{
287 int err;
288
289 err = gpiochip_remove(&cs5535_gpio_chip.chip);
290 if (err) {
291 /* uhh? */
292 dev_err(&pdev->dev, "unable to remove gpio_chip?\n");
293 }
294 pci_release_region(pdev, GPIO_BAR);
295}
296
297static struct pci_device_id cs5535_gpio_pci_tbl[] = {
298 { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) },
299 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) },
300 { 0, },
301};
302MODULE_DEVICE_TABLE(pci, cs5535_gpio_pci_tbl);
303
304/*
305 * We can't use the standard PCI driver registration stuff here, since
306 * that allows only one driver to bind to each PCI device (and we want
307 * multiple drivers to be able to bind to the device). Instead, manually
308 * scan for the PCI device, request a single region, and keep track of the
309 * devices that we're using.
310 */
311
312static int __init cs5535_gpio_scan_pci(void)
313{
314 struct pci_dev *pdev;
315 int err = -ENODEV;
316 int i;
317
318 for (i = 0; i < ARRAY_SIZE(cs5535_gpio_pci_tbl); i++) {
319 pdev = pci_get_device(cs5535_gpio_pci_tbl[i].vendor,
320 cs5535_gpio_pci_tbl[i].device, NULL);
321 if (pdev) {
322 err = cs5535_gpio_probe(pdev, &cs5535_gpio_pci_tbl[i]);
323 if (err)
324 pci_dev_put(pdev);
325
326 /* we only support a single CS5535/6 southbridge */
327 break;
328 }
329 }
330
331 return err;
332}
333
334static void __exit cs5535_gpio_free_pci(void)
335{
336 cs5535_gpio_remove(cs5535_gpio_chip.pdev);
337 pci_dev_put(cs5535_gpio_chip.pdev);
338}
339
340static int __init cs5535_gpio_init(void)
341{
342 return cs5535_gpio_scan_pci();
343}
344
345static void __exit cs5535_gpio_exit(void)
346{
347 cs5535_gpio_free_pci();
348}
349
350module_init(cs5535_gpio_init);
351module_exit(cs5535_gpio_exit);
352
353MODULE_AUTHOR("Andres Salomon <dilinger@collabora.co.uk>");
354MODULE_DESCRIPTION("AMD CS5535/CS5536 GPIO driver");
355MODULE_LICENSE("GPL");