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