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