xref: /linux/drivers/gpio/gpio-xilinx.c (revision 0230a41ed6a818675c0166d506c3c9386af20986)
16e75fc04SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2c103de24SGrant Likely /*
374600ee0SMichal Simek  * Xilinx gpio driver for xps/axi_gpio IP.
4c103de24SGrant Likely  *
574600ee0SMichal Simek  * Copyright 2008 - 2013 Xilinx, Inc.
6c103de24SGrant Likely  */
7c103de24SGrant Likely 
874600ee0SMichal Simek #include <linux/bitops.h>
965bbe531SSrinivas Neeli #include <linux/clk.h>
10c103de24SGrant Likely #include <linux/errno.h>
118c669fe6SSrinivas Neeli #include <linux/gpio/driver.h>
128c669fe6SSrinivas Neeli #include <linux/init.h>
138c669fe6SSrinivas Neeli #include <linux/io.h>
14bb207ef1SPaul Gortmaker #include <linux/module.h>
15c103de24SGrant Likely #include <linux/of_device.h>
16c103de24SGrant Likely #include <linux/of_platform.h>
17c103de24SGrant Likely #include <linux/slab.h>
18c103de24SGrant Likely 
19c103de24SGrant Likely /* Register Offset Definitions */
20c103de24SGrant Likely #define XGPIO_DATA_OFFSET   (0x0)	/* Data register  */
21c103de24SGrant Likely #define XGPIO_TRI_OFFSET    (0x4)	/* I/O direction register  */
22c103de24SGrant Likely 
2374600ee0SMichal Simek #define XGPIO_CHANNEL_OFFSET	0x8
2474600ee0SMichal Simek 
2574600ee0SMichal Simek /* Read/Write access to the GPIO registers */
26c54c58baSRicardo Ribalda Delgado #if defined(CONFIG_ARCH_ZYNQ) || defined(CONFIG_X86)
27cc090d61SMichal Simek # define xgpio_readreg(offset)		readl(offset)
28cc090d61SMichal Simek # define xgpio_writereg(offset, val)	writel(val, offset)
29cc090d61SMichal Simek #else
30cc090d61SMichal Simek # define xgpio_readreg(offset)		__raw_readl(offset)
31cc090d61SMichal Simek # define xgpio_writereg(offset, val)	__raw_writel(val, offset)
32cc090d61SMichal Simek #endif
3374600ee0SMichal Simek 
3474600ee0SMichal Simek /**
3574600ee0SMichal Simek  * struct xgpio_instance - Stores information about GPIO device
361ebd0687SRobert Hancock  * @gc: GPIO chip
371ebd0687SRobert Hancock  * @regs: register block
383c1b5c9bSMichal Simek  * @gpio_width: GPIO width for every channel
394ae798faSRicardo Ribalda Delgado  * @gpio_state: GPIO state shadow register
404ae798faSRicardo Ribalda Delgado  * @gpio_dir: GPIO direction shadow register
414ae798faSRicardo Ribalda Delgado  * @gpio_lock: Lock used for synchronization
4265bbe531SSrinivas Neeli  * @clk: clock resource for this driver
4374600ee0SMichal Simek  */
44c103de24SGrant Likely struct xgpio_instance {
451ebd0687SRobert Hancock 	struct gpio_chip gc;
461ebd0687SRobert Hancock 	void __iomem *regs;
471d6902d3SRicardo Ribalda Delgado 	unsigned int gpio_width[2];
481d6902d3SRicardo Ribalda Delgado 	u32 gpio_state[2];
491d6902d3SRicardo Ribalda Delgado 	u32 gpio_dir[2];
501d6902d3SRicardo Ribalda Delgado 	spinlock_t gpio_lock[2];
5165bbe531SSrinivas Neeli 	struct clk *clk;
52749564ffSRicardo Ribalda Delgado };
53749564ffSRicardo Ribalda Delgado 
541d6902d3SRicardo Ribalda Delgado static inline int xgpio_index(struct xgpio_instance *chip, int gpio)
551d6902d3SRicardo Ribalda Delgado {
561d6902d3SRicardo Ribalda Delgado 	if (gpio >= chip->gpio_width[0])
571d6902d3SRicardo Ribalda Delgado 		return 1;
581d6902d3SRicardo Ribalda Delgado 
591d6902d3SRicardo Ribalda Delgado 	return 0;
601d6902d3SRicardo Ribalda Delgado }
611d6902d3SRicardo Ribalda Delgado 
621d6902d3SRicardo Ribalda Delgado static inline int xgpio_regoffset(struct xgpio_instance *chip, int gpio)
631d6902d3SRicardo Ribalda Delgado {
641d6902d3SRicardo Ribalda Delgado 	if (xgpio_index(chip, gpio))
651d6902d3SRicardo Ribalda Delgado 		return XGPIO_CHANNEL_OFFSET;
661d6902d3SRicardo Ribalda Delgado 
671d6902d3SRicardo Ribalda Delgado 	return 0;
681d6902d3SRicardo Ribalda Delgado }
691d6902d3SRicardo Ribalda Delgado 
701d6902d3SRicardo Ribalda Delgado static inline int xgpio_offset(struct xgpio_instance *chip, int gpio)
711d6902d3SRicardo Ribalda Delgado {
721d6902d3SRicardo Ribalda Delgado 	if (xgpio_index(chip, gpio))
731d6902d3SRicardo Ribalda Delgado 		return gpio - chip->gpio_width[0];
741d6902d3SRicardo Ribalda Delgado 
751d6902d3SRicardo Ribalda Delgado 	return gpio;
761d6902d3SRicardo Ribalda Delgado }
77c103de24SGrant Likely 
78c103de24SGrant Likely /**
79c103de24SGrant Likely  * xgpio_get - Read the specified signal of the GPIO device.
80c103de24SGrant Likely  * @gc:     Pointer to gpio_chip device structure.
81c103de24SGrant Likely  * @gpio:   GPIO signal number.
82c103de24SGrant Likely  *
834ae798faSRicardo Ribalda Delgado  * This function reads the specified signal of the GPIO device.
844ae798faSRicardo Ribalda Delgado  *
854ae798faSRicardo Ribalda Delgado  * Return:
864ae798faSRicardo Ribalda Delgado  * 0 if direction of GPIO signals is set as input otherwise it
874ae798faSRicardo Ribalda Delgado  * returns negative error value.
88c103de24SGrant Likely  */
89c103de24SGrant Likely static int xgpio_get(struct gpio_chip *gc, unsigned int gpio)
90c103de24SGrant Likely {
91097d88e9SLinus Walleij 	struct xgpio_instance *chip = gpiochip_get_data(gc);
921d6902d3SRicardo Ribalda Delgado 	u32 val;
93c103de24SGrant Likely 
941ebd0687SRobert Hancock 	val = xgpio_readreg(chip->regs + XGPIO_DATA_OFFSET +
951d6902d3SRicardo Ribalda Delgado 			    xgpio_regoffset(chip, gpio));
961d6902d3SRicardo Ribalda Delgado 
971d6902d3SRicardo Ribalda Delgado 	return !!(val & BIT(xgpio_offset(chip, gpio)));
98c103de24SGrant Likely }
99c103de24SGrant Likely 
100c103de24SGrant Likely /**
101c103de24SGrant Likely  * xgpio_set - Write the specified signal of the GPIO device.
102c103de24SGrant Likely  * @gc:     Pointer to gpio_chip device structure.
103c103de24SGrant Likely  * @gpio:   GPIO signal number.
104c103de24SGrant Likely  * @val:    Value to be written to specified signal.
105c103de24SGrant Likely  *
106c103de24SGrant Likely  * This function writes the specified value in to the specified signal of the
107c103de24SGrant Likely  * GPIO device.
108c103de24SGrant Likely  */
109c103de24SGrant Likely static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
110c103de24SGrant Likely {
111c103de24SGrant Likely 	unsigned long flags;
112097d88e9SLinus Walleij 	struct xgpio_instance *chip = gpiochip_get_data(gc);
1131d6902d3SRicardo Ribalda Delgado 	int index =  xgpio_index(chip, gpio);
1141d6902d3SRicardo Ribalda Delgado 	int offset =  xgpio_offset(chip, gpio);
115c103de24SGrant Likely 
1161d6902d3SRicardo Ribalda Delgado 	spin_lock_irqsave(&chip->gpio_lock[index], flags);
117c103de24SGrant Likely 
118c103de24SGrant Likely 	/* Write to GPIO signal and set its direction to output */
119c103de24SGrant Likely 	if (val)
1201d6902d3SRicardo Ribalda Delgado 		chip->gpio_state[index] |= BIT(offset);
121c103de24SGrant Likely 	else
1221d6902d3SRicardo Ribalda Delgado 		chip->gpio_state[index] &= ~BIT(offset);
12374600ee0SMichal Simek 
1241ebd0687SRobert Hancock 	xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET +
1251d6902d3SRicardo Ribalda Delgado 		       xgpio_regoffset(chip, gpio), chip->gpio_state[index]);
126c103de24SGrant Likely 
1271d6902d3SRicardo Ribalda Delgado 	spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
128c103de24SGrant Likely }
129c103de24SGrant Likely 
130c103de24SGrant Likely /**
1318e7c1b80SIban Rodriguez  * xgpio_set_multiple - Write the specified signals of the GPIO device.
1328e7c1b80SIban Rodriguez  * @gc:     Pointer to gpio_chip device structure.
1338e7c1b80SIban Rodriguez  * @mask:   Mask of the GPIOS to modify.
1348e7c1b80SIban Rodriguez  * @bits:   Value to be wrote on each GPIO
1358e7c1b80SIban Rodriguez  *
1368e7c1b80SIban Rodriguez  * This function writes the specified values into the specified signals of the
1378e7c1b80SIban Rodriguez  * GPIO devices.
1388e7c1b80SIban Rodriguez  */
1398e7c1b80SIban Rodriguez static void xgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask,
1408e7c1b80SIban Rodriguez 			       unsigned long *bits)
1418e7c1b80SIban Rodriguez {
1428e7c1b80SIban Rodriguez 	unsigned long flags;
1438e7c1b80SIban Rodriguez 	struct xgpio_instance *chip = gpiochip_get_data(gc);
1448e7c1b80SIban Rodriguez 	int index = xgpio_index(chip, 0);
1458e7c1b80SIban Rodriguez 	int offset, i;
1468e7c1b80SIban Rodriguez 
1478e7c1b80SIban Rodriguez 	spin_lock_irqsave(&chip->gpio_lock[index], flags);
1488e7c1b80SIban Rodriguez 
1498e7c1b80SIban Rodriguez 	/* Write to GPIO signals */
1508e7c1b80SIban Rodriguez 	for (i = 0; i < gc->ngpio; i++) {
1518e7c1b80SIban Rodriguez 		if (*mask == 0)
1528e7c1b80SIban Rodriguez 			break;
153c3afa804SPaul Thomas 		/* Once finished with an index write it out to the register */
1548e7c1b80SIban Rodriguez 		if (index !=  xgpio_index(chip, i)) {
1551ebd0687SRobert Hancock 			xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET +
156c3afa804SPaul Thomas 				       index * XGPIO_CHANNEL_OFFSET,
1578e7c1b80SIban Rodriguez 				       chip->gpio_state[index]);
1588e7c1b80SIban Rodriguez 			spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
1598e7c1b80SIban Rodriguez 			index =  xgpio_index(chip, i);
1608e7c1b80SIban Rodriguez 			spin_lock_irqsave(&chip->gpio_lock[index], flags);
1618e7c1b80SIban Rodriguez 		}
1628e7c1b80SIban Rodriguez 		if (__test_and_clear_bit(i, mask)) {
1638e7c1b80SIban Rodriguez 			offset =  xgpio_offset(chip, i);
1648e7c1b80SIban Rodriguez 			if (test_bit(i, bits))
1658e7c1b80SIban Rodriguez 				chip->gpio_state[index] |= BIT(offset);
1668e7c1b80SIban Rodriguez 			else
1678e7c1b80SIban Rodriguez 				chip->gpio_state[index] &= ~BIT(offset);
1688e7c1b80SIban Rodriguez 		}
1698e7c1b80SIban Rodriguez 	}
1708e7c1b80SIban Rodriguez 
1711ebd0687SRobert Hancock 	xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET +
172c3afa804SPaul Thomas 		       index * XGPIO_CHANNEL_OFFSET, chip->gpio_state[index]);
1738e7c1b80SIban Rodriguez 
1748e7c1b80SIban Rodriguez 	spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
1758e7c1b80SIban Rodriguez }
1768e7c1b80SIban Rodriguez 
1778e7c1b80SIban Rodriguez /**
178c103de24SGrant Likely  * xgpio_dir_in - Set the direction of the specified GPIO signal as input.
179c103de24SGrant Likely  * @gc:     Pointer to gpio_chip device structure.
180c103de24SGrant Likely  * @gpio:   GPIO signal number.
181c103de24SGrant Likely  *
1824ae798faSRicardo Ribalda Delgado  * Return:
1834ae798faSRicardo Ribalda Delgado  * 0 - if direction of GPIO signals is set as input
1844ae798faSRicardo Ribalda Delgado  * otherwise it returns negative error value.
185c103de24SGrant Likely  */
186c103de24SGrant Likely static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
187c103de24SGrant Likely {
188c103de24SGrant Likely 	unsigned long flags;
189097d88e9SLinus Walleij 	struct xgpio_instance *chip = gpiochip_get_data(gc);
1901d6902d3SRicardo Ribalda Delgado 	int index =  xgpio_index(chip, gpio);
1911d6902d3SRicardo Ribalda Delgado 	int offset =  xgpio_offset(chip, gpio);
192c103de24SGrant Likely 
1931d6902d3SRicardo Ribalda Delgado 	spin_lock_irqsave(&chip->gpio_lock[index], flags);
194c103de24SGrant Likely 
195c103de24SGrant Likely 	/* Set the GPIO bit in shadow register and set direction as input */
1961d6902d3SRicardo Ribalda Delgado 	chip->gpio_dir[index] |= BIT(offset);
1971ebd0687SRobert Hancock 	xgpio_writereg(chip->regs + XGPIO_TRI_OFFSET +
1981d6902d3SRicardo Ribalda Delgado 		       xgpio_regoffset(chip, gpio), chip->gpio_dir[index]);
199c103de24SGrant Likely 
2001d6902d3SRicardo Ribalda Delgado 	spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
201c103de24SGrant Likely 
202c103de24SGrant Likely 	return 0;
203c103de24SGrant Likely }
204c103de24SGrant Likely 
205c103de24SGrant Likely /**
206c103de24SGrant Likely  * xgpio_dir_out - Set the direction of the specified GPIO signal as output.
207c103de24SGrant Likely  * @gc:     Pointer to gpio_chip device structure.
208c103de24SGrant Likely  * @gpio:   GPIO signal number.
209c103de24SGrant Likely  * @val:    Value to be written to specified signal.
210c103de24SGrant Likely  *
2114ae798faSRicardo Ribalda Delgado  * This function sets the direction of specified GPIO signal as output.
2124ae798faSRicardo Ribalda Delgado  *
2134ae798faSRicardo Ribalda Delgado  * Return:
2144ae798faSRicardo Ribalda Delgado  * If all GPIO signals of GPIO chip is configured as input then it returns
215c103de24SGrant Likely  * error otherwise it returns 0.
216c103de24SGrant Likely  */
217c103de24SGrant Likely static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
218c103de24SGrant Likely {
219c103de24SGrant Likely 	unsigned long flags;
220097d88e9SLinus Walleij 	struct xgpio_instance *chip = gpiochip_get_data(gc);
2211d6902d3SRicardo Ribalda Delgado 	int index =  xgpio_index(chip, gpio);
2221d6902d3SRicardo Ribalda Delgado 	int offset =  xgpio_offset(chip, gpio);
223c103de24SGrant Likely 
2241d6902d3SRicardo Ribalda Delgado 	spin_lock_irqsave(&chip->gpio_lock[index], flags);
225c103de24SGrant Likely 
226c103de24SGrant Likely 	/* Write state of GPIO signal */
227c103de24SGrant Likely 	if (val)
2281d6902d3SRicardo Ribalda Delgado 		chip->gpio_state[index] |= BIT(offset);
229c103de24SGrant Likely 	else
2301d6902d3SRicardo Ribalda Delgado 		chip->gpio_state[index] &= ~BIT(offset);
2311ebd0687SRobert Hancock 	xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET +
2321d6902d3SRicardo Ribalda Delgado 			xgpio_regoffset(chip, gpio), chip->gpio_state[index]);
233c103de24SGrant Likely 
234c103de24SGrant Likely 	/* Clear the GPIO bit in shadow register and set direction as output */
2351d6902d3SRicardo Ribalda Delgado 	chip->gpio_dir[index] &= ~BIT(offset);
2361ebd0687SRobert Hancock 	xgpio_writereg(chip->regs + XGPIO_TRI_OFFSET +
2371d6902d3SRicardo Ribalda Delgado 			xgpio_regoffset(chip, gpio), chip->gpio_dir[index]);
238c103de24SGrant Likely 
2391d6902d3SRicardo Ribalda Delgado 	spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
240c103de24SGrant Likely 
241c103de24SGrant Likely 	return 0;
242c103de24SGrant Likely }
243c103de24SGrant Likely 
244c103de24SGrant Likely /**
245c103de24SGrant Likely  * xgpio_save_regs - Set initial values of GPIO pins
2461ebd0687SRobert Hancock  * @chip: Pointer to GPIO instance
247c103de24SGrant Likely  */
2481ebd0687SRobert Hancock static void xgpio_save_regs(struct xgpio_instance *chip)
249c103de24SGrant Likely {
2501ebd0687SRobert Hancock 	xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET,	chip->gpio_state[0]);
2511ebd0687SRobert Hancock 	xgpio_writereg(chip->regs + XGPIO_TRI_OFFSET, chip->gpio_dir[0]);
2521d6902d3SRicardo Ribalda Delgado 
2531d6902d3SRicardo Ribalda Delgado 	if (!chip->gpio_width[1])
2541d6902d3SRicardo Ribalda Delgado 		return;
2551d6902d3SRicardo Ribalda Delgado 
2561ebd0687SRobert Hancock 	xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET + XGPIO_CHANNEL_OFFSET,
2571d6902d3SRicardo Ribalda Delgado 		       chip->gpio_state[1]);
2581ebd0687SRobert Hancock 	xgpio_writereg(chip->regs + XGPIO_TRI_OFFSET + XGPIO_CHANNEL_OFFSET,
2591d6902d3SRicardo Ribalda Delgado 		       chip->gpio_dir[1]);
260c103de24SGrant Likely }
261c103de24SGrant Likely 
262c103de24SGrant Likely /**
263*0230a41eSSrinivas Neeli  * xgpio_remove - Remove method for the GPIO device.
264*0230a41eSSrinivas Neeli  * @pdev: pointer to the platform device
265*0230a41eSSrinivas Neeli  *
266*0230a41eSSrinivas Neeli  * This function remove gpiochips and frees all the allocated resources.
267*0230a41eSSrinivas Neeli  *
268*0230a41eSSrinivas Neeli  * Return: 0 always
269*0230a41eSSrinivas Neeli  */
270*0230a41eSSrinivas Neeli static int xgpio_remove(struct platform_device *pdev)
271*0230a41eSSrinivas Neeli {
272*0230a41eSSrinivas Neeli 	struct xgpio_instance *gpio = platform_get_drvdata(pdev);
273*0230a41eSSrinivas Neeli 
274*0230a41eSSrinivas Neeli 	clk_disable_unprepare(gpio->clk);
275*0230a41eSSrinivas Neeli 
276*0230a41eSSrinivas Neeli 	return 0;
277*0230a41eSSrinivas Neeli }
278*0230a41eSSrinivas Neeli 
279*0230a41eSSrinivas Neeli /**
280c103de24SGrant Likely  * xgpio_of_probe - Probe method for the GPIO device.
281749564ffSRicardo Ribalda Delgado  * @pdev: pointer to the platform device
282c103de24SGrant Likely  *
2834ae798faSRicardo Ribalda Delgado  * Return:
2844ae798faSRicardo Ribalda Delgado  * It returns 0, if the driver is bound to the GPIO device, or
2854ae798faSRicardo Ribalda Delgado  * a negative value if there is an error.
286c103de24SGrant Likely  */
287749564ffSRicardo Ribalda Delgado static int xgpio_probe(struct platform_device *pdev)
288c103de24SGrant Likely {
289c103de24SGrant Likely 	struct xgpio_instance *chip;
290c103de24SGrant Likely 	int status = 0;
291749564ffSRicardo Ribalda Delgado 	struct device_node *np = pdev->dev.of_node;
2921d6902d3SRicardo Ribalda Delgado 	u32 is_dual;
293c103de24SGrant Likely 
2941d6902d3SRicardo Ribalda Delgado 	chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
2951d6902d3SRicardo Ribalda Delgado 	if (!chip)
296c103de24SGrant Likely 		return -ENOMEM;
297c103de24SGrant Likely 
2981d6902d3SRicardo Ribalda Delgado 	platform_set_drvdata(pdev, chip);
299749564ffSRicardo Ribalda Delgado 
300c103de24SGrant Likely 	/* Update GPIO state shadow register with default value */
3011d6902d3SRicardo Ribalda Delgado 	of_property_read_u32(np, "xlnx,dout-default", &chip->gpio_state[0]);
302c103de24SGrant Likely 
303c103de24SGrant Likely 	/* Update GPIO direction shadow register with default value */
3041d6902d3SRicardo Ribalda Delgado 	if (of_property_read_u32(np, "xlnx,tri-default", &chip->gpio_dir[0]))
3051d6902d3SRicardo Ribalda Delgado 		chip->gpio_dir[0] = 0xFFFFFFFF;
3066f8bf500SMichal Simek 
3071b4c5a6eSGernot Vormayr 	/*
3081b4c5a6eSGernot Vormayr 	 * Check device node and parent device node for device width
3091b4c5a6eSGernot Vormayr 	 * and assume default width of 32
3101b4c5a6eSGernot Vormayr 	 */
3111d6902d3SRicardo Ribalda Delgado 	if (of_property_read_u32(np, "xlnx,gpio-width", &chip->gpio_width[0]))
3121d6902d3SRicardo Ribalda Delgado 		chip->gpio_width[0] = 32;
313c103de24SGrant Likely 
3141d6902d3SRicardo Ribalda Delgado 	spin_lock_init(&chip->gpio_lock[0]);
315c103de24SGrant Likely 
3161d6902d3SRicardo Ribalda Delgado 	if (of_property_read_u32(np, "xlnx,is-dual", &is_dual))
3171d6902d3SRicardo Ribalda Delgado 		is_dual = 0;
3181d6902d3SRicardo Ribalda Delgado 
3191d6902d3SRicardo Ribalda Delgado 	if (is_dual) {
3201d6902d3SRicardo Ribalda Delgado 		/* Update GPIO state shadow register with default value */
3211d6902d3SRicardo Ribalda Delgado 		of_property_read_u32(np, "xlnx,dout-default-2",
3221d6902d3SRicardo Ribalda Delgado 				     &chip->gpio_state[1]);
3231d6902d3SRicardo Ribalda Delgado 
3241d6902d3SRicardo Ribalda Delgado 		/* Update GPIO direction shadow register with default value */
3251d6902d3SRicardo Ribalda Delgado 		if (of_property_read_u32(np, "xlnx,tri-default-2",
3261d6902d3SRicardo Ribalda Delgado 					 &chip->gpio_dir[1]))
3271d6902d3SRicardo Ribalda Delgado 			chip->gpio_dir[1] = 0xFFFFFFFF;
3281d6902d3SRicardo Ribalda Delgado 
3291d6902d3SRicardo Ribalda Delgado 		/*
3301d6902d3SRicardo Ribalda Delgado 		 * Check device node and parent device node for device width
3311d6902d3SRicardo Ribalda Delgado 		 * and assume default width of 32
3321d6902d3SRicardo Ribalda Delgado 		 */
3331d6902d3SRicardo Ribalda Delgado 		if (of_property_read_u32(np, "xlnx,gpio2-width",
3341d6902d3SRicardo Ribalda Delgado 					 &chip->gpio_width[1]))
3351d6902d3SRicardo Ribalda Delgado 			chip->gpio_width[1] = 32;
3361d6902d3SRicardo Ribalda Delgado 
3371d6902d3SRicardo Ribalda Delgado 		spin_lock_init(&chip->gpio_lock[1]);
3381d6902d3SRicardo Ribalda Delgado 	}
3391d6902d3SRicardo Ribalda Delgado 
3401ebd0687SRobert Hancock 	chip->gc.base = -1;
3411ebd0687SRobert Hancock 	chip->gc.ngpio = chip->gpio_width[0] + chip->gpio_width[1];
3421ebd0687SRobert Hancock 	chip->gc.parent = &pdev->dev;
3431ebd0687SRobert Hancock 	chip->gc.direction_input = xgpio_dir_in;
3441ebd0687SRobert Hancock 	chip->gc.direction_output = xgpio_dir_out;
3451ebd0687SRobert Hancock 	chip->gc.get = xgpio_get;
3461ebd0687SRobert Hancock 	chip->gc.set = xgpio_set;
3471ebd0687SRobert Hancock 	chip->gc.set_multiple = xgpio_set_multiple;
348c103de24SGrant Likely 
3491ebd0687SRobert Hancock 	chip->gc.label = dev_name(&pdev->dev);
350c103de24SGrant Likely 
3511ebd0687SRobert Hancock 	chip->regs = devm_platform_ioremap_resource(pdev, 0);
3521ebd0687SRobert Hancock 	if (IS_ERR(chip->regs)) {
3531ebd0687SRobert Hancock 		dev_err(&pdev->dev, "failed to ioremap memory resource\n");
3541ebd0687SRobert Hancock 		return PTR_ERR(chip->regs);
3551ebd0687SRobert Hancock 	}
3561ebd0687SRobert Hancock 
35765bbe531SSrinivas Neeli 	chip->clk = devm_clk_get_optional(&pdev->dev, NULL);
35865bbe531SSrinivas Neeli 	if (IS_ERR(chip->clk)) {
35965bbe531SSrinivas Neeli 		if (PTR_ERR(chip->clk) != -EPROBE_DEFER)
36065bbe531SSrinivas Neeli 			dev_dbg(&pdev->dev, "Input clock not found\n");
36165bbe531SSrinivas Neeli 		return PTR_ERR(chip->clk);
36265bbe531SSrinivas Neeli 	}
36365bbe531SSrinivas Neeli 
36465bbe531SSrinivas Neeli 	status = clk_prepare_enable(chip->clk);
36565bbe531SSrinivas Neeli 	if (status < 0) {
36665bbe531SSrinivas Neeli 		dev_err(&pdev->dev, "Failed to prepare clk\n");
36765bbe531SSrinivas Neeli 		return status;
36865bbe531SSrinivas Neeli 	}
36965bbe531SSrinivas Neeli 
3701ebd0687SRobert Hancock 	xgpio_save_regs(chip);
3711ebd0687SRobert Hancock 
3721ebd0687SRobert Hancock 	status = devm_gpiochip_add_data(&pdev->dev, &chip->gc, chip);
373c103de24SGrant Likely 	if (status) {
3741ebd0687SRobert Hancock 		dev_err(&pdev->dev, "failed to add GPIO chip\n");
37565bbe531SSrinivas Neeli 		clk_disable_unprepare(chip->clk);
376c103de24SGrant Likely 		return status;
377c103de24SGrant Likely 	}
37874600ee0SMichal Simek 
379c103de24SGrant Likely 	return 0;
380c103de24SGrant Likely }
381c103de24SGrant Likely 
3829992bc95SJingoo Han static const struct of_device_id xgpio_of_match[] = {
383c103de24SGrant Likely 	{ .compatible = "xlnx,xps-gpio-1.00.a", },
384c103de24SGrant Likely 	{ /* end of list */ },
385c103de24SGrant Likely };
386c103de24SGrant Likely 
387749564ffSRicardo Ribalda Delgado MODULE_DEVICE_TABLE(of, xgpio_of_match);
388749564ffSRicardo Ribalda Delgado 
389749564ffSRicardo Ribalda Delgado static struct platform_driver xgpio_plat_driver = {
390749564ffSRicardo Ribalda Delgado 	.probe		= xgpio_probe,
391*0230a41eSSrinivas Neeli 	.remove		= xgpio_remove,
392749564ffSRicardo Ribalda Delgado 	.driver		= {
393749564ffSRicardo Ribalda Delgado 			.name = "gpio-xilinx",
394749564ffSRicardo Ribalda Delgado 			.of_match_table	= xgpio_of_match,
395749564ffSRicardo Ribalda Delgado 	},
396749564ffSRicardo Ribalda Delgado };
397749564ffSRicardo Ribalda Delgado 
398c103de24SGrant Likely static int __init xgpio_init(void)
399c103de24SGrant Likely {
400749564ffSRicardo Ribalda Delgado 	return platform_driver_register(&xgpio_plat_driver);
401c103de24SGrant Likely }
402c103de24SGrant Likely 
403c103de24SGrant Likely subsys_initcall(xgpio_init);
404749564ffSRicardo Ribalda Delgado 
405749564ffSRicardo Ribalda Delgado static void __exit xgpio_exit(void)
406749564ffSRicardo Ribalda Delgado {
407749564ffSRicardo Ribalda Delgado 	platform_driver_unregister(&xgpio_plat_driver);
408749564ffSRicardo Ribalda Delgado }
409749564ffSRicardo Ribalda Delgado module_exit(xgpio_exit);
410c103de24SGrant Likely 
411c103de24SGrant Likely MODULE_AUTHOR("Xilinx, Inc.");
412c103de24SGrant Likely MODULE_DESCRIPTION("Xilinx GPIO driver");
413c103de24SGrant Likely MODULE_LICENSE("GPL");
414