xref: /linux/drivers/gpio/gpio-mmio.c (revision e9f4d569fb897e77200cd431f3aab138c3c733e6)
1*e9f4d569SChristian Lamparter /*
2*e9f4d569SChristian Lamparter  * Generic driver for memory-mapped GPIO controllers.
3*e9f4d569SChristian Lamparter  *
4*e9f4d569SChristian Lamparter  * Copyright 2008 MontaVista Software, Inc.
5*e9f4d569SChristian Lamparter  * Copyright 2008,2010 Anton Vorontsov <cbouatmailru@gmail.com>
6*e9f4d569SChristian Lamparter  *
7*e9f4d569SChristian Lamparter  * This program is free software; you can redistribute  it and/or modify it
8*e9f4d569SChristian Lamparter  * under  the terms of  the GNU General  Public License as published by the
9*e9f4d569SChristian Lamparter  * Free Software Foundation;  either version 2 of the  License, or (at your
10*e9f4d569SChristian Lamparter  * option) any later version.
11*e9f4d569SChristian Lamparter  *
12*e9f4d569SChristian Lamparter  * ....``.```~~~~````.`.`.`.`.```````'',,,.........`````......`.......
13*e9f4d569SChristian Lamparter  * ...``                                                         ```````..
14*e9f4d569SChristian Lamparter  * ..The simplest form of a GPIO controller that the driver supports is``
15*e9f4d569SChristian Lamparter  *  `.just a single "data" register, where GPIO state can be read and/or `
16*e9f4d569SChristian Lamparter  *    `,..written. ,,..``~~~~ .....``.`.`.~~.```.`.........``````.```````
17*e9f4d569SChristian Lamparter  *        `````````
18*e9f4d569SChristian Lamparter                                     ___
19*e9f4d569SChristian Lamparter _/~~|___/~|   . ```~~~~~~       ___/___\___     ,~.`.`.`.`````.~~...,,,,...
20*e9f4d569SChristian Lamparter __________|~$@~~~        %~    /o*o*o*o*o*o\   .. Implementing such a GPIO .
21*e9f4d569SChristian Lamparter o        `                     ~~~~\___/~~~~    ` controller in FPGA is ,.`
22*e9f4d569SChristian Lamparter                                                  `....trivial..'~`.```.```
23*e9f4d569SChristian Lamparter  *                                                    ```````
24*e9f4d569SChristian Lamparter  *  .```````~~~~`..`.``.``.
25*e9f4d569SChristian Lamparter  * .  The driver supports  `...       ,..```.`~~~```````````````....````.``,,
26*e9f4d569SChristian Lamparter  * .   big-endian notation, just`.  .. A bit more sophisticated controllers ,
27*e9f4d569SChristian Lamparter  *  . register the device with -be`. .with a pair of set/clear-bit registers ,
28*e9f4d569SChristian Lamparter  *   `.. suffix.  ```~~`````....`.`   . affecting the data register and the .`
29*e9f4d569SChristian Lamparter  *     ``.`.``...```                  ```.. output pins are also supported.`
30*e9f4d569SChristian Lamparter  *                        ^^             `````.`````````.,``~``~``~~``````
31*e9f4d569SChristian Lamparter  *                                                   .                  ^^
32*e9f4d569SChristian Lamparter  *   ,..`.`.`...````````````......`.`.`.`.`.`..`.`.`..
33*e9f4d569SChristian Lamparter  * .. The expectation is that in at least some cases .    ,-~~~-,
34*e9f4d569SChristian Lamparter  *  .this will be used with roll-your-own ASIC/FPGA .`     \   /
35*e9f4d569SChristian Lamparter  *  .logic in Verilog or VHDL. ~~~`````````..`````~~`       \ /
36*e9f4d569SChristian Lamparter  *  ..````````......```````````                             \o_
37*e9f4d569SChristian Lamparter  *                                                           |
38*e9f4d569SChristian Lamparter  *                              ^^                          / \
39*e9f4d569SChristian Lamparter  *
40*e9f4d569SChristian Lamparter  *           ...`````~~`.....``.`..........``````.`.``.```........``.
41*e9f4d569SChristian Lamparter  *            `  8, 16, 32 and 64 bits registers are supported, and``.
42*e9f4d569SChristian Lamparter  *            . the number of GPIOs is determined by the width of   ~
43*e9f4d569SChristian Lamparter  *             .. the registers. ,............```.`.`..`.`.~~~.`.`.`~
44*e9f4d569SChristian Lamparter  *               `.......````.```
45*e9f4d569SChristian Lamparter  */
46*e9f4d569SChristian Lamparter 
47*e9f4d569SChristian Lamparter #include <linux/init.h>
48*e9f4d569SChristian Lamparter #include <linux/err.h>
49*e9f4d569SChristian Lamparter #include <linux/bug.h>
50*e9f4d569SChristian Lamparter #include <linux/kernel.h>
51*e9f4d569SChristian Lamparter #include <linux/module.h>
52*e9f4d569SChristian Lamparter #include <linux/spinlock.h>
53*e9f4d569SChristian Lamparter #include <linux/compiler.h>
54*e9f4d569SChristian Lamparter #include <linux/types.h>
55*e9f4d569SChristian Lamparter #include <linux/errno.h>
56*e9f4d569SChristian Lamparter #include <linux/log2.h>
57*e9f4d569SChristian Lamparter #include <linux/ioport.h>
58*e9f4d569SChristian Lamparter #include <linux/io.h>
59*e9f4d569SChristian Lamparter #include <linux/gpio/driver.h>
60*e9f4d569SChristian Lamparter #include <linux/slab.h>
61*e9f4d569SChristian Lamparter #include <linux/bitops.h>
62*e9f4d569SChristian Lamparter #include <linux/platform_device.h>
63*e9f4d569SChristian Lamparter #include <linux/mod_devicetable.h>
64*e9f4d569SChristian Lamparter 
65*e9f4d569SChristian Lamparter static void bgpio_write8(void __iomem *reg, unsigned long data)
66*e9f4d569SChristian Lamparter {
67*e9f4d569SChristian Lamparter 	writeb(data, reg);
68*e9f4d569SChristian Lamparter }
69*e9f4d569SChristian Lamparter 
70*e9f4d569SChristian Lamparter static unsigned long bgpio_read8(void __iomem *reg)
71*e9f4d569SChristian Lamparter {
72*e9f4d569SChristian Lamparter 	return readb(reg);
73*e9f4d569SChristian Lamparter }
74*e9f4d569SChristian Lamparter 
75*e9f4d569SChristian Lamparter static void bgpio_write16(void __iomem *reg, unsigned long data)
76*e9f4d569SChristian Lamparter {
77*e9f4d569SChristian Lamparter 	writew(data, reg);
78*e9f4d569SChristian Lamparter }
79*e9f4d569SChristian Lamparter 
80*e9f4d569SChristian Lamparter static unsigned long bgpio_read16(void __iomem *reg)
81*e9f4d569SChristian Lamparter {
82*e9f4d569SChristian Lamparter 	return readw(reg);
83*e9f4d569SChristian Lamparter }
84*e9f4d569SChristian Lamparter 
85*e9f4d569SChristian Lamparter static void bgpio_write32(void __iomem *reg, unsigned long data)
86*e9f4d569SChristian Lamparter {
87*e9f4d569SChristian Lamparter 	writel(data, reg);
88*e9f4d569SChristian Lamparter }
89*e9f4d569SChristian Lamparter 
90*e9f4d569SChristian Lamparter static unsigned long bgpio_read32(void __iomem *reg)
91*e9f4d569SChristian Lamparter {
92*e9f4d569SChristian Lamparter 	return readl(reg);
93*e9f4d569SChristian Lamparter }
94*e9f4d569SChristian Lamparter 
95*e9f4d569SChristian Lamparter #if BITS_PER_LONG >= 64
96*e9f4d569SChristian Lamparter static void bgpio_write64(void __iomem *reg, unsigned long data)
97*e9f4d569SChristian Lamparter {
98*e9f4d569SChristian Lamparter 	writeq(data, reg);
99*e9f4d569SChristian Lamparter }
100*e9f4d569SChristian Lamparter 
101*e9f4d569SChristian Lamparter static unsigned long bgpio_read64(void __iomem *reg)
102*e9f4d569SChristian Lamparter {
103*e9f4d569SChristian Lamparter 	return readq(reg);
104*e9f4d569SChristian Lamparter }
105*e9f4d569SChristian Lamparter #endif /* BITS_PER_LONG >= 64 */
106*e9f4d569SChristian Lamparter 
107*e9f4d569SChristian Lamparter static void bgpio_write16be(void __iomem *reg, unsigned long data)
108*e9f4d569SChristian Lamparter {
109*e9f4d569SChristian Lamparter 	iowrite16be(data, reg);
110*e9f4d569SChristian Lamparter }
111*e9f4d569SChristian Lamparter 
112*e9f4d569SChristian Lamparter static unsigned long bgpio_read16be(void __iomem *reg)
113*e9f4d569SChristian Lamparter {
114*e9f4d569SChristian Lamparter 	return ioread16be(reg);
115*e9f4d569SChristian Lamparter }
116*e9f4d569SChristian Lamparter 
117*e9f4d569SChristian Lamparter static void bgpio_write32be(void __iomem *reg, unsigned long data)
118*e9f4d569SChristian Lamparter {
119*e9f4d569SChristian Lamparter 	iowrite32be(data, reg);
120*e9f4d569SChristian Lamparter }
121*e9f4d569SChristian Lamparter 
122*e9f4d569SChristian Lamparter static unsigned long bgpio_read32be(void __iomem *reg)
123*e9f4d569SChristian Lamparter {
124*e9f4d569SChristian Lamparter 	return ioread32be(reg);
125*e9f4d569SChristian Lamparter }
126*e9f4d569SChristian Lamparter 
127*e9f4d569SChristian Lamparter static unsigned long bgpio_pin2mask(struct gpio_chip *gc, unsigned int pin)
128*e9f4d569SChristian Lamparter {
129*e9f4d569SChristian Lamparter 	return BIT(pin);
130*e9f4d569SChristian Lamparter }
131*e9f4d569SChristian Lamparter 
132*e9f4d569SChristian Lamparter static unsigned long bgpio_pin2mask_be(struct gpio_chip *gc,
133*e9f4d569SChristian Lamparter 				       unsigned int pin)
134*e9f4d569SChristian Lamparter {
135*e9f4d569SChristian Lamparter 	return BIT(gc->bgpio_bits - 1 - pin);
136*e9f4d569SChristian Lamparter }
137*e9f4d569SChristian Lamparter 
138*e9f4d569SChristian Lamparter static int bgpio_get_set(struct gpio_chip *gc, unsigned int gpio)
139*e9f4d569SChristian Lamparter {
140*e9f4d569SChristian Lamparter 	unsigned long pinmask = gc->pin2mask(gc, gpio);
141*e9f4d569SChristian Lamparter 
142*e9f4d569SChristian Lamparter 	if (gc->bgpio_dir & pinmask)
143*e9f4d569SChristian Lamparter 		return !!(gc->read_reg(gc->reg_set) & pinmask);
144*e9f4d569SChristian Lamparter 	else
145*e9f4d569SChristian Lamparter 		return !!(gc->read_reg(gc->reg_dat) & pinmask);
146*e9f4d569SChristian Lamparter }
147*e9f4d569SChristian Lamparter 
148*e9f4d569SChristian Lamparter static int bgpio_get(struct gpio_chip *gc, unsigned int gpio)
149*e9f4d569SChristian Lamparter {
150*e9f4d569SChristian Lamparter 	return !!(gc->read_reg(gc->reg_dat) & gc->pin2mask(gc, gpio));
151*e9f4d569SChristian Lamparter }
152*e9f4d569SChristian Lamparter 
153*e9f4d569SChristian Lamparter static void bgpio_set_none(struct gpio_chip *gc, unsigned int gpio, int val)
154*e9f4d569SChristian Lamparter {
155*e9f4d569SChristian Lamparter }
156*e9f4d569SChristian Lamparter 
157*e9f4d569SChristian Lamparter static void bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
158*e9f4d569SChristian Lamparter {
159*e9f4d569SChristian Lamparter 	unsigned long mask = gc->pin2mask(gc, gpio);
160*e9f4d569SChristian Lamparter 	unsigned long flags;
161*e9f4d569SChristian Lamparter 
162*e9f4d569SChristian Lamparter 	spin_lock_irqsave(&gc->bgpio_lock, flags);
163*e9f4d569SChristian Lamparter 
164*e9f4d569SChristian Lamparter 	if (val)
165*e9f4d569SChristian Lamparter 		gc->bgpio_data |= mask;
166*e9f4d569SChristian Lamparter 	else
167*e9f4d569SChristian Lamparter 		gc->bgpio_data &= ~mask;
168*e9f4d569SChristian Lamparter 
169*e9f4d569SChristian Lamparter 	gc->write_reg(gc->reg_dat, gc->bgpio_data);
170*e9f4d569SChristian Lamparter 
171*e9f4d569SChristian Lamparter 	spin_unlock_irqrestore(&gc->bgpio_lock, flags);
172*e9f4d569SChristian Lamparter }
173*e9f4d569SChristian Lamparter 
174*e9f4d569SChristian Lamparter static void bgpio_set_with_clear(struct gpio_chip *gc, unsigned int gpio,
175*e9f4d569SChristian Lamparter 				 int val)
176*e9f4d569SChristian Lamparter {
177*e9f4d569SChristian Lamparter 	unsigned long mask = gc->pin2mask(gc, gpio);
178*e9f4d569SChristian Lamparter 
179*e9f4d569SChristian Lamparter 	if (val)
180*e9f4d569SChristian Lamparter 		gc->write_reg(gc->reg_set, mask);
181*e9f4d569SChristian Lamparter 	else
182*e9f4d569SChristian Lamparter 		gc->write_reg(gc->reg_clr, mask);
183*e9f4d569SChristian Lamparter }
184*e9f4d569SChristian Lamparter 
185*e9f4d569SChristian Lamparter static void bgpio_set_set(struct gpio_chip *gc, unsigned int gpio, int val)
186*e9f4d569SChristian Lamparter {
187*e9f4d569SChristian Lamparter 	unsigned long mask = gc->pin2mask(gc, gpio);
188*e9f4d569SChristian Lamparter 	unsigned long flags;
189*e9f4d569SChristian Lamparter 
190*e9f4d569SChristian Lamparter 	spin_lock_irqsave(&gc->bgpio_lock, flags);
191*e9f4d569SChristian Lamparter 
192*e9f4d569SChristian Lamparter 	if (val)
193*e9f4d569SChristian Lamparter 		gc->bgpio_data |= mask;
194*e9f4d569SChristian Lamparter 	else
195*e9f4d569SChristian Lamparter 		gc->bgpio_data &= ~mask;
196*e9f4d569SChristian Lamparter 
197*e9f4d569SChristian Lamparter 	gc->write_reg(gc->reg_set, gc->bgpio_data);
198*e9f4d569SChristian Lamparter 
199*e9f4d569SChristian Lamparter 	spin_unlock_irqrestore(&gc->bgpio_lock, flags);
200*e9f4d569SChristian Lamparter }
201*e9f4d569SChristian Lamparter 
202*e9f4d569SChristian Lamparter static void bgpio_multiple_get_masks(struct gpio_chip *gc,
203*e9f4d569SChristian Lamparter 				     unsigned long *mask, unsigned long *bits,
204*e9f4d569SChristian Lamparter 				     unsigned long *set_mask,
205*e9f4d569SChristian Lamparter 				     unsigned long *clear_mask)
206*e9f4d569SChristian Lamparter {
207*e9f4d569SChristian Lamparter 	int i;
208*e9f4d569SChristian Lamparter 
209*e9f4d569SChristian Lamparter 	*set_mask = 0;
210*e9f4d569SChristian Lamparter 	*clear_mask = 0;
211*e9f4d569SChristian Lamparter 
212*e9f4d569SChristian Lamparter 	for (i = 0; i < gc->bgpio_bits; i++) {
213*e9f4d569SChristian Lamparter 		if (*mask == 0)
214*e9f4d569SChristian Lamparter 			break;
215*e9f4d569SChristian Lamparter 		if (__test_and_clear_bit(i, mask)) {
216*e9f4d569SChristian Lamparter 			if (test_bit(i, bits))
217*e9f4d569SChristian Lamparter 				*set_mask |= gc->pin2mask(gc, i);
218*e9f4d569SChristian Lamparter 			else
219*e9f4d569SChristian Lamparter 				*clear_mask |= gc->pin2mask(gc, i);
220*e9f4d569SChristian Lamparter 		}
221*e9f4d569SChristian Lamparter 	}
222*e9f4d569SChristian Lamparter }
223*e9f4d569SChristian Lamparter 
224*e9f4d569SChristian Lamparter static void bgpio_set_multiple_single_reg(struct gpio_chip *gc,
225*e9f4d569SChristian Lamparter 					  unsigned long *mask,
226*e9f4d569SChristian Lamparter 					  unsigned long *bits,
227*e9f4d569SChristian Lamparter 					  void __iomem *reg)
228*e9f4d569SChristian Lamparter {
229*e9f4d569SChristian Lamparter 	unsigned long flags;
230*e9f4d569SChristian Lamparter 	unsigned long set_mask, clear_mask;
231*e9f4d569SChristian Lamparter 
232*e9f4d569SChristian Lamparter 	spin_lock_irqsave(&gc->bgpio_lock, flags);
233*e9f4d569SChristian Lamparter 
234*e9f4d569SChristian Lamparter 	bgpio_multiple_get_masks(gc, mask, bits, &set_mask, &clear_mask);
235*e9f4d569SChristian Lamparter 
236*e9f4d569SChristian Lamparter 	gc->bgpio_data |= set_mask;
237*e9f4d569SChristian Lamparter 	gc->bgpio_data &= ~clear_mask;
238*e9f4d569SChristian Lamparter 
239*e9f4d569SChristian Lamparter 	gc->write_reg(reg, gc->bgpio_data);
240*e9f4d569SChristian Lamparter 
241*e9f4d569SChristian Lamparter 	spin_unlock_irqrestore(&gc->bgpio_lock, flags);
242*e9f4d569SChristian Lamparter }
243*e9f4d569SChristian Lamparter 
244*e9f4d569SChristian Lamparter static void bgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask,
245*e9f4d569SChristian Lamparter 			       unsigned long *bits)
246*e9f4d569SChristian Lamparter {
247*e9f4d569SChristian Lamparter 	bgpio_set_multiple_single_reg(gc, mask, bits, gc->reg_dat);
248*e9f4d569SChristian Lamparter }
249*e9f4d569SChristian Lamparter 
250*e9f4d569SChristian Lamparter static void bgpio_set_multiple_set(struct gpio_chip *gc, unsigned long *mask,
251*e9f4d569SChristian Lamparter 				   unsigned long *bits)
252*e9f4d569SChristian Lamparter {
253*e9f4d569SChristian Lamparter 	bgpio_set_multiple_single_reg(gc, mask, bits, gc->reg_set);
254*e9f4d569SChristian Lamparter }
255*e9f4d569SChristian Lamparter 
256*e9f4d569SChristian Lamparter static void bgpio_set_multiple_with_clear(struct gpio_chip *gc,
257*e9f4d569SChristian Lamparter 					  unsigned long *mask,
258*e9f4d569SChristian Lamparter 					  unsigned long *bits)
259*e9f4d569SChristian Lamparter {
260*e9f4d569SChristian Lamparter 	unsigned long set_mask, clear_mask;
261*e9f4d569SChristian Lamparter 
262*e9f4d569SChristian Lamparter 	bgpio_multiple_get_masks(gc, mask, bits, &set_mask, &clear_mask);
263*e9f4d569SChristian Lamparter 
264*e9f4d569SChristian Lamparter 	if (set_mask)
265*e9f4d569SChristian Lamparter 		gc->write_reg(gc->reg_set, set_mask);
266*e9f4d569SChristian Lamparter 	if (clear_mask)
267*e9f4d569SChristian Lamparter 		gc->write_reg(gc->reg_clr, clear_mask);
268*e9f4d569SChristian Lamparter }
269*e9f4d569SChristian Lamparter 
270*e9f4d569SChristian Lamparter static int bgpio_simple_dir_in(struct gpio_chip *gc, unsigned int gpio)
271*e9f4d569SChristian Lamparter {
272*e9f4d569SChristian Lamparter 	return 0;
273*e9f4d569SChristian Lamparter }
274*e9f4d569SChristian Lamparter 
275*e9f4d569SChristian Lamparter static int bgpio_dir_out_err(struct gpio_chip *gc, unsigned int gpio,
276*e9f4d569SChristian Lamparter 				int val)
277*e9f4d569SChristian Lamparter {
278*e9f4d569SChristian Lamparter 	return -EINVAL;
279*e9f4d569SChristian Lamparter }
280*e9f4d569SChristian Lamparter 
281*e9f4d569SChristian Lamparter static int bgpio_simple_dir_out(struct gpio_chip *gc, unsigned int gpio,
282*e9f4d569SChristian Lamparter 				int val)
283*e9f4d569SChristian Lamparter {
284*e9f4d569SChristian Lamparter 	gc->set(gc, gpio, val);
285*e9f4d569SChristian Lamparter 
286*e9f4d569SChristian Lamparter 	return 0;
287*e9f4d569SChristian Lamparter }
288*e9f4d569SChristian Lamparter 
289*e9f4d569SChristian Lamparter static int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
290*e9f4d569SChristian Lamparter {
291*e9f4d569SChristian Lamparter 	unsigned long flags;
292*e9f4d569SChristian Lamparter 
293*e9f4d569SChristian Lamparter 	spin_lock_irqsave(&gc->bgpio_lock, flags);
294*e9f4d569SChristian Lamparter 
295*e9f4d569SChristian Lamparter 	gc->bgpio_dir &= ~gc->pin2mask(gc, gpio);
296*e9f4d569SChristian Lamparter 	gc->write_reg(gc->reg_dir, gc->bgpio_dir);
297*e9f4d569SChristian Lamparter 
298*e9f4d569SChristian Lamparter 	spin_unlock_irqrestore(&gc->bgpio_lock, flags);
299*e9f4d569SChristian Lamparter 
300*e9f4d569SChristian Lamparter 	return 0;
301*e9f4d569SChristian Lamparter }
302*e9f4d569SChristian Lamparter 
303*e9f4d569SChristian Lamparter static int bgpio_get_dir(struct gpio_chip *gc, unsigned int gpio)
304*e9f4d569SChristian Lamparter {
305*e9f4d569SChristian Lamparter 	/* Return 0 if output, 1 of input */
306*e9f4d569SChristian Lamparter 	return !(gc->read_reg(gc->reg_dir) & gc->pin2mask(gc, gpio));
307*e9f4d569SChristian Lamparter }
308*e9f4d569SChristian Lamparter 
309*e9f4d569SChristian Lamparter static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
310*e9f4d569SChristian Lamparter {
311*e9f4d569SChristian Lamparter 	unsigned long flags;
312*e9f4d569SChristian Lamparter 
313*e9f4d569SChristian Lamparter 	gc->set(gc, gpio, val);
314*e9f4d569SChristian Lamparter 
315*e9f4d569SChristian Lamparter 	spin_lock_irqsave(&gc->bgpio_lock, flags);
316*e9f4d569SChristian Lamparter 
317*e9f4d569SChristian Lamparter 	gc->bgpio_dir |= gc->pin2mask(gc, gpio);
318*e9f4d569SChristian Lamparter 	gc->write_reg(gc->reg_dir, gc->bgpio_dir);
319*e9f4d569SChristian Lamparter 
320*e9f4d569SChristian Lamparter 	spin_unlock_irqrestore(&gc->bgpio_lock, flags);
321*e9f4d569SChristian Lamparter 
322*e9f4d569SChristian Lamparter 	return 0;
323*e9f4d569SChristian Lamparter }
324*e9f4d569SChristian Lamparter 
325*e9f4d569SChristian Lamparter static int bgpio_dir_in_inv(struct gpio_chip *gc, unsigned int gpio)
326*e9f4d569SChristian Lamparter {
327*e9f4d569SChristian Lamparter 	unsigned long flags;
328*e9f4d569SChristian Lamparter 
329*e9f4d569SChristian Lamparter 	spin_lock_irqsave(&gc->bgpio_lock, flags);
330*e9f4d569SChristian Lamparter 
331*e9f4d569SChristian Lamparter 	gc->bgpio_dir |= gc->pin2mask(gc, gpio);
332*e9f4d569SChristian Lamparter 	gc->write_reg(gc->reg_dir, gc->bgpio_dir);
333*e9f4d569SChristian Lamparter 
334*e9f4d569SChristian Lamparter 	spin_unlock_irqrestore(&gc->bgpio_lock, flags);
335*e9f4d569SChristian Lamparter 
336*e9f4d569SChristian Lamparter 	return 0;
337*e9f4d569SChristian Lamparter }
338*e9f4d569SChristian Lamparter 
339*e9f4d569SChristian Lamparter static int bgpio_dir_out_inv(struct gpio_chip *gc, unsigned int gpio, int val)
340*e9f4d569SChristian Lamparter {
341*e9f4d569SChristian Lamparter 	unsigned long flags;
342*e9f4d569SChristian Lamparter 
343*e9f4d569SChristian Lamparter 	gc->set(gc, gpio, val);
344*e9f4d569SChristian Lamparter 
345*e9f4d569SChristian Lamparter 	spin_lock_irqsave(&gc->bgpio_lock, flags);
346*e9f4d569SChristian Lamparter 
347*e9f4d569SChristian Lamparter 	gc->bgpio_dir &= ~gc->pin2mask(gc, gpio);
348*e9f4d569SChristian Lamparter 	gc->write_reg(gc->reg_dir, gc->bgpio_dir);
349*e9f4d569SChristian Lamparter 
350*e9f4d569SChristian Lamparter 	spin_unlock_irqrestore(&gc->bgpio_lock, flags);
351*e9f4d569SChristian Lamparter 
352*e9f4d569SChristian Lamparter 	return 0;
353*e9f4d569SChristian Lamparter }
354*e9f4d569SChristian Lamparter 
355*e9f4d569SChristian Lamparter static int bgpio_get_dir_inv(struct gpio_chip *gc, unsigned int gpio)
356*e9f4d569SChristian Lamparter {
357*e9f4d569SChristian Lamparter 	/* Return 0 if output, 1 if input */
358*e9f4d569SChristian Lamparter 	return !!(gc->read_reg(gc->reg_dir) & gc->pin2mask(gc, gpio));
359*e9f4d569SChristian Lamparter }
360*e9f4d569SChristian Lamparter 
361*e9f4d569SChristian Lamparter static int bgpio_setup_accessors(struct device *dev,
362*e9f4d569SChristian Lamparter 				 struct gpio_chip *gc,
363*e9f4d569SChristian Lamparter 				 bool bit_be,
364*e9f4d569SChristian Lamparter 				 bool byte_be)
365*e9f4d569SChristian Lamparter {
366*e9f4d569SChristian Lamparter 
367*e9f4d569SChristian Lamparter 	switch (gc->bgpio_bits) {
368*e9f4d569SChristian Lamparter 	case 8:
369*e9f4d569SChristian Lamparter 		gc->read_reg	= bgpio_read8;
370*e9f4d569SChristian Lamparter 		gc->write_reg	= bgpio_write8;
371*e9f4d569SChristian Lamparter 		break;
372*e9f4d569SChristian Lamparter 	case 16:
373*e9f4d569SChristian Lamparter 		if (byte_be) {
374*e9f4d569SChristian Lamparter 			gc->read_reg	= bgpio_read16be;
375*e9f4d569SChristian Lamparter 			gc->write_reg	= bgpio_write16be;
376*e9f4d569SChristian Lamparter 		} else {
377*e9f4d569SChristian Lamparter 			gc->read_reg	= bgpio_read16;
378*e9f4d569SChristian Lamparter 			gc->write_reg	= bgpio_write16;
379*e9f4d569SChristian Lamparter 		}
380*e9f4d569SChristian Lamparter 		break;
381*e9f4d569SChristian Lamparter 	case 32:
382*e9f4d569SChristian Lamparter 		if (byte_be) {
383*e9f4d569SChristian Lamparter 			gc->read_reg	= bgpio_read32be;
384*e9f4d569SChristian Lamparter 			gc->write_reg	= bgpio_write32be;
385*e9f4d569SChristian Lamparter 		} else {
386*e9f4d569SChristian Lamparter 			gc->read_reg	= bgpio_read32;
387*e9f4d569SChristian Lamparter 			gc->write_reg	= bgpio_write32;
388*e9f4d569SChristian Lamparter 		}
389*e9f4d569SChristian Lamparter 		break;
390*e9f4d569SChristian Lamparter #if BITS_PER_LONG >= 64
391*e9f4d569SChristian Lamparter 	case 64:
392*e9f4d569SChristian Lamparter 		if (byte_be) {
393*e9f4d569SChristian Lamparter 			dev_err(dev,
394*e9f4d569SChristian Lamparter 				"64 bit big endian byte order unsupported\n");
395*e9f4d569SChristian Lamparter 			return -EINVAL;
396*e9f4d569SChristian Lamparter 		} else {
397*e9f4d569SChristian Lamparter 			gc->read_reg	= bgpio_read64;
398*e9f4d569SChristian Lamparter 			gc->write_reg	= bgpio_write64;
399*e9f4d569SChristian Lamparter 		}
400*e9f4d569SChristian Lamparter 		break;
401*e9f4d569SChristian Lamparter #endif /* BITS_PER_LONG >= 64 */
402*e9f4d569SChristian Lamparter 	default:
403*e9f4d569SChristian Lamparter 		dev_err(dev, "unsupported data width %u bits\n", gc->bgpio_bits);
404*e9f4d569SChristian Lamparter 		return -EINVAL;
405*e9f4d569SChristian Lamparter 	}
406*e9f4d569SChristian Lamparter 
407*e9f4d569SChristian Lamparter 	gc->pin2mask = bit_be ? bgpio_pin2mask_be : bgpio_pin2mask;
408*e9f4d569SChristian Lamparter 
409*e9f4d569SChristian Lamparter 	return 0;
410*e9f4d569SChristian Lamparter }
411*e9f4d569SChristian Lamparter 
412*e9f4d569SChristian Lamparter /*
413*e9f4d569SChristian Lamparter  * Create the device and allocate the resources.  For setting GPIO's there are
414*e9f4d569SChristian Lamparter  * three supported configurations:
415*e9f4d569SChristian Lamparter  *
416*e9f4d569SChristian Lamparter  *	- single input/output register resource (named "dat").
417*e9f4d569SChristian Lamparter  *	- set/clear pair (named "set" and "clr").
418*e9f4d569SChristian Lamparter  *	- single output register resource and single input resource ("set" and
419*e9f4d569SChristian Lamparter  *	dat").
420*e9f4d569SChristian Lamparter  *
421*e9f4d569SChristian Lamparter  * For the single output register, this drives a 1 by setting a bit and a zero
422*e9f4d569SChristian Lamparter  * by clearing a bit.  For the set clr pair, this drives a 1 by setting a bit
423*e9f4d569SChristian Lamparter  * in the set register and clears it by setting a bit in the clear register.
424*e9f4d569SChristian Lamparter  * The configuration is detected by which resources are present.
425*e9f4d569SChristian Lamparter  *
426*e9f4d569SChristian Lamparter  * For setting the GPIO direction, there are three supported configurations:
427*e9f4d569SChristian Lamparter  *
428*e9f4d569SChristian Lamparter  *	- simple bidirection GPIO that requires no configuration.
429*e9f4d569SChristian Lamparter  *	- an output direction register (named "dirout") where a 1 bit
430*e9f4d569SChristian Lamparter  *	indicates the GPIO is an output.
431*e9f4d569SChristian Lamparter  *	- an input direction register (named "dirin") where a 1 bit indicates
432*e9f4d569SChristian Lamparter  *	the GPIO is an input.
433*e9f4d569SChristian Lamparter  */
434*e9f4d569SChristian Lamparter static int bgpio_setup_io(struct gpio_chip *gc,
435*e9f4d569SChristian Lamparter 			  void __iomem *dat,
436*e9f4d569SChristian Lamparter 			  void __iomem *set,
437*e9f4d569SChristian Lamparter 			  void __iomem *clr,
438*e9f4d569SChristian Lamparter 			  unsigned long flags)
439*e9f4d569SChristian Lamparter {
440*e9f4d569SChristian Lamparter 
441*e9f4d569SChristian Lamparter 	gc->reg_dat = dat;
442*e9f4d569SChristian Lamparter 	if (!gc->reg_dat)
443*e9f4d569SChristian Lamparter 		return -EINVAL;
444*e9f4d569SChristian Lamparter 
445*e9f4d569SChristian Lamparter 	if (set && clr) {
446*e9f4d569SChristian Lamparter 		gc->reg_set = set;
447*e9f4d569SChristian Lamparter 		gc->reg_clr = clr;
448*e9f4d569SChristian Lamparter 		gc->set = bgpio_set_with_clear;
449*e9f4d569SChristian Lamparter 		gc->set_multiple = bgpio_set_multiple_with_clear;
450*e9f4d569SChristian Lamparter 	} else if (set && !clr) {
451*e9f4d569SChristian Lamparter 		gc->reg_set = set;
452*e9f4d569SChristian Lamparter 		gc->set = bgpio_set_set;
453*e9f4d569SChristian Lamparter 		gc->set_multiple = bgpio_set_multiple_set;
454*e9f4d569SChristian Lamparter 	} else if (flags & BGPIOF_NO_OUTPUT) {
455*e9f4d569SChristian Lamparter 		gc->set = bgpio_set_none;
456*e9f4d569SChristian Lamparter 		gc->set_multiple = NULL;
457*e9f4d569SChristian Lamparter 	} else {
458*e9f4d569SChristian Lamparter 		gc->set = bgpio_set;
459*e9f4d569SChristian Lamparter 		gc->set_multiple = bgpio_set_multiple;
460*e9f4d569SChristian Lamparter 	}
461*e9f4d569SChristian Lamparter 
462*e9f4d569SChristian Lamparter 	if (!(flags & BGPIOF_UNREADABLE_REG_SET) &&
463*e9f4d569SChristian Lamparter 	    (flags & BGPIOF_READ_OUTPUT_REG_SET))
464*e9f4d569SChristian Lamparter 		gc->get = bgpio_get_set;
465*e9f4d569SChristian Lamparter 	else
466*e9f4d569SChristian Lamparter 		gc->get = bgpio_get;
467*e9f4d569SChristian Lamparter 
468*e9f4d569SChristian Lamparter 	return 0;
469*e9f4d569SChristian Lamparter }
470*e9f4d569SChristian Lamparter 
471*e9f4d569SChristian Lamparter static int bgpio_setup_direction(struct gpio_chip *gc,
472*e9f4d569SChristian Lamparter 				 void __iomem *dirout,
473*e9f4d569SChristian Lamparter 				 void __iomem *dirin,
474*e9f4d569SChristian Lamparter 				 unsigned long flags)
475*e9f4d569SChristian Lamparter {
476*e9f4d569SChristian Lamparter 	if (dirout && dirin) {
477*e9f4d569SChristian Lamparter 		return -EINVAL;
478*e9f4d569SChristian Lamparter 	} else if (dirout) {
479*e9f4d569SChristian Lamparter 		gc->reg_dir = dirout;
480*e9f4d569SChristian Lamparter 		gc->direction_output = bgpio_dir_out;
481*e9f4d569SChristian Lamparter 		gc->direction_input = bgpio_dir_in;
482*e9f4d569SChristian Lamparter 		gc->get_direction = bgpio_get_dir;
483*e9f4d569SChristian Lamparter 	} else if (dirin) {
484*e9f4d569SChristian Lamparter 		gc->reg_dir = dirin;
485*e9f4d569SChristian Lamparter 		gc->direction_output = bgpio_dir_out_inv;
486*e9f4d569SChristian Lamparter 		gc->direction_input = bgpio_dir_in_inv;
487*e9f4d569SChristian Lamparter 		gc->get_direction = bgpio_get_dir_inv;
488*e9f4d569SChristian Lamparter 	} else {
489*e9f4d569SChristian Lamparter 		if (flags & BGPIOF_NO_OUTPUT)
490*e9f4d569SChristian Lamparter 			gc->direction_output = bgpio_dir_out_err;
491*e9f4d569SChristian Lamparter 		else
492*e9f4d569SChristian Lamparter 			gc->direction_output = bgpio_simple_dir_out;
493*e9f4d569SChristian Lamparter 		gc->direction_input = bgpio_simple_dir_in;
494*e9f4d569SChristian Lamparter 	}
495*e9f4d569SChristian Lamparter 
496*e9f4d569SChristian Lamparter 	return 0;
497*e9f4d569SChristian Lamparter }
498*e9f4d569SChristian Lamparter 
499*e9f4d569SChristian Lamparter static int bgpio_request(struct gpio_chip *chip, unsigned gpio_pin)
500*e9f4d569SChristian Lamparter {
501*e9f4d569SChristian Lamparter 	if (gpio_pin < chip->ngpio)
502*e9f4d569SChristian Lamparter 		return 0;
503*e9f4d569SChristian Lamparter 
504*e9f4d569SChristian Lamparter 	return -EINVAL;
505*e9f4d569SChristian Lamparter }
506*e9f4d569SChristian Lamparter 
507*e9f4d569SChristian Lamparter int bgpio_init(struct gpio_chip *gc, struct device *dev,
508*e9f4d569SChristian Lamparter 	       unsigned long sz, void __iomem *dat, void __iomem *set,
509*e9f4d569SChristian Lamparter 	       void __iomem *clr, void __iomem *dirout, void __iomem *dirin,
510*e9f4d569SChristian Lamparter 	       unsigned long flags)
511*e9f4d569SChristian Lamparter {
512*e9f4d569SChristian Lamparter 	int ret;
513*e9f4d569SChristian Lamparter 
514*e9f4d569SChristian Lamparter 	if (!is_power_of_2(sz))
515*e9f4d569SChristian Lamparter 		return -EINVAL;
516*e9f4d569SChristian Lamparter 
517*e9f4d569SChristian Lamparter 	gc->bgpio_bits = sz * 8;
518*e9f4d569SChristian Lamparter 	if (gc->bgpio_bits > BITS_PER_LONG)
519*e9f4d569SChristian Lamparter 		return -EINVAL;
520*e9f4d569SChristian Lamparter 
521*e9f4d569SChristian Lamparter 	spin_lock_init(&gc->bgpio_lock);
522*e9f4d569SChristian Lamparter 	gc->parent = dev;
523*e9f4d569SChristian Lamparter 	gc->label = dev_name(dev);
524*e9f4d569SChristian Lamparter 	gc->base = -1;
525*e9f4d569SChristian Lamparter 	gc->ngpio = gc->bgpio_bits;
526*e9f4d569SChristian Lamparter 	gc->request = bgpio_request;
527*e9f4d569SChristian Lamparter 
528*e9f4d569SChristian Lamparter 	ret = bgpio_setup_io(gc, dat, set, clr, flags);
529*e9f4d569SChristian Lamparter 	if (ret)
530*e9f4d569SChristian Lamparter 		return ret;
531*e9f4d569SChristian Lamparter 
532*e9f4d569SChristian Lamparter 	ret = bgpio_setup_accessors(dev, gc, flags & BGPIOF_BIG_ENDIAN,
533*e9f4d569SChristian Lamparter 				    flags & BGPIOF_BIG_ENDIAN_BYTE_ORDER);
534*e9f4d569SChristian Lamparter 	if (ret)
535*e9f4d569SChristian Lamparter 		return ret;
536*e9f4d569SChristian Lamparter 
537*e9f4d569SChristian Lamparter 	ret = bgpio_setup_direction(gc, dirout, dirin, flags);
538*e9f4d569SChristian Lamparter 	if (ret)
539*e9f4d569SChristian Lamparter 		return ret;
540*e9f4d569SChristian Lamparter 
541*e9f4d569SChristian Lamparter 	gc->bgpio_data = gc->read_reg(gc->reg_dat);
542*e9f4d569SChristian Lamparter 	if (gc->set == bgpio_set_set &&
543*e9f4d569SChristian Lamparter 			!(flags & BGPIOF_UNREADABLE_REG_SET))
544*e9f4d569SChristian Lamparter 		gc->bgpio_data = gc->read_reg(gc->reg_set);
545*e9f4d569SChristian Lamparter 	if (gc->reg_dir && !(flags & BGPIOF_UNREADABLE_REG_DIR))
546*e9f4d569SChristian Lamparter 		gc->bgpio_dir = gc->read_reg(gc->reg_dir);
547*e9f4d569SChristian Lamparter 
548*e9f4d569SChristian Lamparter 	return ret;
549*e9f4d569SChristian Lamparter }
550*e9f4d569SChristian Lamparter EXPORT_SYMBOL_GPL(bgpio_init);
551*e9f4d569SChristian Lamparter 
552*e9f4d569SChristian Lamparter #if IS_ENABLED(CONFIG_GPIO_GENERIC_PLATFORM)
553*e9f4d569SChristian Lamparter 
554*e9f4d569SChristian Lamparter static void __iomem *bgpio_map(struct platform_device *pdev,
555*e9f4d569SChristian Lamparter 			       const char *name,
556*e9f4d569SChristian Lamparter 			       resource_size_t sane_sz)
557*e9f4d569SChristian Lamparter {
558*e9f4d569SChristian Lamparter 	struct resource *r;
559*e9f4d569SChristian Lamparter 	resource_size_t sz;
560*e9f4d569SChristian Lamparter 
561*e9f4d569SChristian Lamparter 	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
562*e9f4d569SChristian Lamparter 	if (!r)
563*e9f4d569SChristian Lamparter 		return NULL;
564*e9f4d569SChristian Lamparter 
565*e9f4d569SChristian Lamparter 	sz = resource_size(r);
566*e9f4d569SChristian Lamparter 	if (sz != sane_sz)
567*e9f4d569SChristian Lamparter 		return IOMEM_ERR_PTR(-EINVAL);
568*e9f4d569SChristian Lamparter 
569*e9f4d569SChristian Lamparter 	return devm_ioremap_resource(&pdev->dev, r);
570*e9f4d569SChristian Lamparter }
571*e9f4d569SChristian Lamparter 
572*e9f4d569SChristian Lamparter static int bgpio_pdev_probe(struct platform_device *pdev)
573*e9f4d569SChristian Lamparter {
574*e9f4d569SChristian Lamparter 	struct device *dev = &pdev->dev;
575*e9f4d569SChristian Lamparter 	struct resource *r;
576*e9f4d569SChristian Lamparter 	void __iomem *dat;
577*e9f4d569SChristian Lamparter 	void __iomem *set;
578*e9f4d569SChristian Lamparter 	void __iomem *clr;
579*e9f4d569SChristian Lamparter 	void __iomem *dirout;
580*e9f4d569SChristian Lamparter 	void __iomem *dirin;
581*e9f4d569SChristian Lamparter 	unsigned long sz;
582*e9f4d569SChristian Lamparter 	unsigned long flags = pdev->id_entry->driver_data;
583*e9f4d569SChristian Lamparter 	int err;
584*e9f4d569SChristian Lamparter 	struct gpio_chip *gc;
585*e9f4d569SChristian Lamparter 	struct bgpio_pdata *pdata = dev_get_platdata(dev);
586*e9f4d569SChristian Lamparter 
587*e9f4d569SChristian Lamparter 	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat");
588*e9f4d569SChristian Lamparter 	if (!r)
589*e9f4d569SChristian Lamparter 		return -EINVAL;
590*e9f4d569SChristian Lamparter 
591*e9f4d569SChristian Lamparter 	sz = resource_size(r);
592*e9f4d569SChristian Lamparter 
593*e9f4d569SChristian Lamparter 	dat = bgpio_map(pdev, "dat", sz);
594*e9f4d569SChristian Lamparter 	if (IS_ERR(dat))
595*e9f4d569SChristian Lamparter 		return PTR_ERR(dat);
596*e9f4d569SChristian Lamparter 
597*e9f4d569SChristian Lamparter 	set = bgpio_map(pdev, "set", sz);
598*e9f4d569SChristian Lamparter 	if (IS_ERR(set))
599*e9f4d569SChristian Lamparter 		return PTR_ERR(set);
600*e9f4d569SChristian Lamparter 
601*e9f4d569SChristian Lamparter 	clr = bgpio_map(pdev, "clr", sz);
602*e9f4d569SChristian Lamparter 	if (IS_ERR(clr))
603*e9f4d569SChristian Lamparter 		return PTR_ERR(clr);
604*e9f4d569SChristian Lamparter 
605*e9f4d569SChristian Lamparter 	dirout = bgpio_map(pdev, "dirout", sz);
606*e9f4d569SChristian Lamparter 	if (IS_ERR(dirout))
607*e9f4d569SChristian Lamparter 		return PTR_ERR(dirout);
608*e9f4d569SChristian Lamparter 
609*e9f4d569SChristian Lamparter 	dirin = bgpio_map(pdev, "dirin", sz);
610*e9f4d569SChristian Lamparter 	if (IS_ERR(dirin))
611*e9f4d569SChristian Lamparter 		return PTR_ERR(dirin);
612*e9f4d569SChristian Lamparter 
613*e9f4d569SChristian Lamparter 	gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL);
614*e9f4d569SChristian Lamparter 	if (!gc)
615*e9f4d569SChristian Lamparter 		return -ENOMEM;
616*e9f4d569SChristian Lamparter 
617*e9f4d569SChristian Lamparter 	err = bgpio_init(gc, dev, sz, dat, set, clr, dirout, dirin, flags);
618*e9f4d569SChristian Lamparter 	if (err)
619*e9f4d569SChristian Lamparter 		return err;
620*e9f4d569SChristian Lamparter 
621*e9f4d569SChristian Lamparter 	if (pdata) {
622*e9f4d569SChristian Lamparter 		if (pdata->label)
623*e9f4d569SChristian Lamparter 			gc->label = pdata->label;
624*e9f4d569SChristian Lamparter 		gc->base = pdata->base;
625*e9f4d569SChristian Lamparter 		if (pdata->ngpio > 0)
626*e9f4d569SChristian Lamparter 			gc->ngpio = pdata->ngpio;
627*e9f4d569SChristian Lamparter 	}
628*e9f4d569SChristian Lamparter 
629*e9f4d569SChristian Lamparter 	platform_set_drvdata(pdev, gc);
630*e9f4d569SChristian Lamparter 
631*e9f4d569SChristian Lamparter 	return devm_gpiochip_add_data(&pdev->dev, gc, NULL);
632*e9f4d569SChristian Lamparter }
633*e9f4d569SChristian Lamparter 
634*e9f4d569SChristian Lamparter static const struct platform_device_id bgpio_id_table[] = {
635*e9f4d569SChristian Lamparter 	{
636*e9f4d569SChristian Lamparter 		.name		= "basic-mmio-gpio",
637*e9f4d569SChristian Lamparter 		.driver_data	= 0,
638*e9f4d569SChristian Lamparter 	}, {
639*e9f4d569SChristian Lamparter 		.name		= "basic-mmio-gpio-be",
640*e9f4d569SChristian Lamparter 		.driver_data	= BGPIOF_BIG_ENDIAN,
641*e9f4d569SChristian Lamparter 	},
642*e9f4d569SChristian Lamparter 	{ }
643*e9f4d569SChristian Lamparter };
644*e9f4d569SChristian Lamparter MODULE_DEVICE_TABLE(platform, bgpio_id_table);
645*e9f4d569SChristian Lamparter 
646*e9f4d569SChristian Lamparter static struct platform_driver bgpio_driver = {
647*e9f4d569SChristian Lamparter 	.driver = {
648*e9f4d569SChristian Lamparter 		.name = "basic-mmio-gpio",
649*e9f4d569SChristian Lamparter 	},
650*e9f4d569SChristian Lamparter 	.id_table = bgpio_id_table,
651*e9f4d569SChristian Lamparter 	.probe = bgpio_pdev_probe,
652*e9f4d569SChristian Lamparter };
653*e9f4d569SChristian Lamparter 
654*e9f4d569SChristian Lamparter module_platform_driver(bgpio_driver);
655*e9f4d569SChristian Lamparter 
656*e9f4d569SChristian Lamparter #endif /* CONFIG_GPIO_GENERIC_PLATFORM */
657*e9f4d569SChristian Lamparter 
658*e9f4d569SChristian Lamparter MODULE_DESCRIPTION("Driver for basic memory-mapped GPIO controllers");
659*e9f4d569SChristian Lamparter MODULE_AUTHOR("Anton Vorontsov <cbouatmailru@gmail.com>");
660*e9f4d569SChristian Lamparter MODULE_LICENSE("GPL");
661