18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Xilinx gpio driver for xps/axi_gpio IP.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright 2008 - 2013 Xilinx, Inc.
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/bitops.h>
98c2ecf20Sopenharmony_ci#include <linux/init.h>
108c2ecf20Sopenharmony_ci#include <linux/errno.h>
118c2ecf20Sopenharmony_ci#include <linux/module.h>
128c2ecf20Sopenharmony_ci#include <linux/of_device.h>
138c2ecf20Sopenharmony_ci#include <linux/of_platform.h>
148c2ecf20Sopenharmony_ci#include <linux/io.h>
158c2ecf20Sopenharmony_ci#include <linux/gpio/driver.h>
168c2ecf20Sopenharmony_ci#include <linux/slab.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci/* Register Offset Definitions */
198c2ecf20Sopenharmony_ci#define XGPIO_DATA_OFFSET   (0x0)	/* Data register  */
208c2ecf20Sopenharmony_ci#define XGPIO_TRI_OFFSET    (0x4)	/* I/O direction register  */
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#define XGPIO_CHANNEL_OFFSET	0x8
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci/* Read/Write access to the GPIO registers */
258c2ecf20Sopenharmony_ci#if defined(CONFIG_ARCH_ZYNQ) || defined(CONFIG_X86)
268c2ecf20Sopenharmony_ci# define xgpio_readreg(offset)		readl(offset)
278c2ecf20Sopenharmony_ci# define xgpio_writereg(offset, val)	writel(val, offset)
288c2ecf20Sopenharmony_ci#else
298c2ecf20Sopenharmony_ci# define xgpio_readreg(offset)		__raw_readl(offset)
308c2ecf20Sopenharmony_ci# define xgpio_writereg(offset, val)	__raw_writel(val, offset)
318c2ecf20Sopenharmony_ci#endif
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci/**
348c2ecf20Sopenharmony_ci * struct xgpio_instance - Stores information about GPIO device
358c2ecf20Sopenharmony_ci * @gc: GPIO chip
368c2ecf20Sopenharmony_ci * @regs: register block
378c2ecf20Sopenharmony_ci * @gpio_width: GPIO width for every channel
388c2ecf20Sopenharmony_ci * @gpio_state: GPIO state shadow register
398c2ecf20Sopenharmony_ci * @gpio_dir: GPIO direction shadow register
408c2ecf20Sopenharmony_ci * @gpio_lock: Lock used for synchronization
418c2ecf20Sopenharmony_ci */
428c2ecf20Sopenharmony_cistruct xgpio_instance {
438c2ecf20Sopenharmony_ci	struct gpio_chip gc;
448c2ecf20Sopenharmony_ci	void __iomem *regs;
458c2ecf20Sopenharmony_ci	unsigned int gpio_width[2];
468c2ecf20Sopenharmony_ci	u32 gpio_state[2];
478c2ecf20Sopenharmony_ci	u32 gpio_dir[2];
488c2ecf20Sopenharmony_ci	spinlock_t gpio_lock[2];
498c2ecf20Sopenharmony_ci};
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cistatic inline int xgpio_index(struct xgpio_instance *chip, int gpio)
528c2ecf20Sopenharmony_ci{
538c2ecf20Sopenharmony_ci	if (gpio >= chip->gpio_width[0])
548c2ecf20Sopenharmony_ci		return 1;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	return 0;
578c2ecf20Sopenharmony_ci}
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistatic inline int xgpio_regoffset(struct xgpio_instance *chip, int gpio)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	if (xgpio_index(chip, gpio))
628c2ecf20Sopenharmony_ci		return XGPIO_CHANNEL_OFFSET;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	return 0;
658c2ecf20Sopenharmony_ci}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistatic inline int xgpio_offset(struct xgpio_instance *chip, int gpio)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	if (xgpio_index(chip, gpio))
708c2ecf20Sopenharmony_ci		return gpio - chip->gpio_width[0];
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	return gpio;
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci/**
768c2ecf20Sopenharmony_ci * xgpio_get - Read the specified signal of the GPIO device.
778c2ecf20Sopenharmony_ci * @gc:     Pointer to gpio_chip device structure.
788c2ecf20Sopenharmony_ci * @gpio:   GPIO signal number.
798c2ecf20Sopenharmony_ci *
808c2ecf20Sopenharmony_ci * This function reads the specified signal of the GPIO device.
818c2ecf20Sopenharmony_ci *
828c2ecf20Sopenharmony_ci * Return:
838c2ecf20Sopenharmony_ci * 0 if direction of GPIO signals is set as input otherwise it
848c2ecf20Sopenharmony_ci * returns negative error value.
858c2ecf20Sopenharmony_ci */
868c2ecf20Sopenharmony_cistatic int xgpio_get(struct gpio_chip *gc, unsigned int gpio)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	struct xgpio_instance *chip = gpiochip_get_data(gc);
898c2ecf20Sopenharmony_ci	u32 val;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	val = xgpio_readreg(chip->regs + XGPIO_DATA_OFFSET +
928c2ecf20Sopenharmony_ci			    xgpio_regoffset(chip, gpio));
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	return !!(val & BIT(xgpio_offset(chip, gpio)));
958c2ecf20Sopenharmony_ci}
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci/**
988c2ecf20Sopenharmony_ci * xgpio_set - Write the specified signal of the GPIO device.
998c2ecf20Sopenharmony_ci * @gc:     Pointer to gpio_chip device structure.
1008c2ecf20Sopenharmony_ci * @gpio:   GPIO signal number.
1018c2ecf20Sopenharmony_ci * @val:    Value to be written to specified signal.
1028c2ecf20Sopenharmony_ci *
1038c2ecf20Sopenharmony_ci * This function writes the specified value in to the specified signal of the
1048c2ecf20Sopenharmony_ci * GPIO device.
1058c2ecf20Sopenharmony_ci */
1068c2ecf20Sopenharmony_cistatic void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
1078c2ecf20Sopenharmony_ci{
1088c2ecf20Sopenharmony_ci	unsigned long flags;
1098c2ecf20Sopenharmony_ci	struct xgpio_instance *chip = gpiochip_get_data(gc);
1108c2ecf20Sopenharmony_ci	int index =  xgpio_index(chip, gpio);
1118c2ecf20Sopenharmony_ci	int offset =  xgpio_offset(chip, gpio);
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	spin_lock_irqsave(&chip->gpio_lock[index], flags);
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	/* Write to GPIO signal and set its direction to output */
1168c2ecf20Sopenharmony_ci	if (val)
1178c2ecf20Sopenharmony_ci		chip->gpio_state[index] |= BIT(offset);
1188c2ecf20Sopenharmony_ci	else
1198c2ecf20Sopenharmony_ci		chip->gpio_state[index] &= ~BIT(offset);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET +
1228c2ecf20Sopenharmony_ci		       xgpio_regoffset(chip, gpio), chip->gpio_state[index]);
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci/**
1288c2ecf20Sopenharmony_ci * xgpio_set_multiple - Write the specified signals of the GPIO device.
1298c2ecf20Sopenharmony_ci * @gc:     Pointer to gpio_chip device structure.
1308c2ecf20Sopenharmony_ci * @mask:   Mask of the GPIOS to modify.
1318c2ecf20Sopenharmony_ci * @bits:   Value to be wrote on each GPIO
1328c2ecf20Sopenharmony_ci *
1338c2ecf20Sopenharmony_ci * This function writes the specified values into the specified signals of the
1348c2ecf20Sopenharmony_ci * GPIO devices.
1358c2ecf20Sopenharmony_ci */
1368c2ecf20Sopenharmony_cistatic void xgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask,
1378c2ecf20Sopenharmony_ci			       unsigned long *bits)
1388c2ecf20Sopenharmony_ci{
1398c2ecf20Sopenharmony_ci	unsigned long flags;
1408c2ecf20Sopenharmony_ci	struct xgpio_instance *chip = gpiochip_get_data(gc);
1418c2ecf20Sopenharmony_ci	int index = xgpio_index(chip, 0);
1428c2ecf20Sopenharmony_ci	int offset, i;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	spin_lock_irqsave(&chip->gpio_lock[index], flags);
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	/* Write to GPIO signals */
1478c2ecf20Sopenharmony_ci	for (i = 0; i < gc->ngpio; i++) {
1488c2ecf20Sopenharmony_ci		if (*mask == 0)
1498c2ecf20Sopenharmony_ci			break;
1508c2ecf20Sopenharmony_ci		/* Once finished with an index write it out to the register */
1518c2ecf20Sopenharmony_ci		if (index !=  xgpio_index(chip, i)) {
1528c2ecf20Sopenharmony_ci			xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET +
1538c2ecf20Sopenharmony_ci				       index * XGPIO_CHANNEL_OFFSET,
1548c2ecf20Sopenharmony_ci				       chip->gpio_state[index]);
1558c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
1568c2ecf20Sopenharmony_ci			index =  xgpio_index(chip, i);
1578c2ecf20Sopenharmony_ci			spin_lock_irqsave(&chip->gpio_lock[index], flags);
1588c2ecf20Sopenharmony_ci		}
1598c2ecf20Sopenharmony_ci		if (__test_and_clear_bit(i, mask)) {
1608c2ecf20Sopenharmony_ci			offset =  xgpio_offset(chip, i);
1618c2ecf20Sopenharmony_ci			if (test_bit(i, bits))
1628c2ecf20Sopenharmony_ci				chip->gpio_state[index] |= BIT(offset);
1638c2ecf20Sopenharmony_ci			else
1648c2ecf20Sopenharmony_ci				chip->gpio_state[index] &= ~BIT(offset);
1658c2ecf20Sopenharmony_ci		}
1668c2ecf20Sopenharmony_ci	}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET +
1698c2ecf20Sopenharmony_ci		       index * XGPIO_CHANNEL_OFFSET, chip->gpio_state[index]);
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
1728c2ecf20Sopenharmony_ci}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci/**
1758c2ecf20Sopenharmony_ci * xgpio_dir_in - Set the direction of the specified GPIO signal as input.
1768c2ecf20Sopenharmony_ci * @gc:     Pointer to gpio_chip device structure.
1778c2ecf20Sopenharmony_ci * @gpio:   GPIO signal number.
1788c2ecf20Sopenharmony_ci *
1798c2ecf20Sopenharmony_ci * Return:
1808c2ecf20Sopenharmony_ci * 0 - if direction of GPIO signals is set as input
1818c2ecf20Sopenharmony_ci * otherwise it returns negative error value.
1828c2ecf20Sopenharmony_ci */
1838c2ecf20Sopenharmony_cistatic int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
1848c2ecf20Sopenharmony_ci{
1858c2ecf20Sopenharmony_ci	unsigned long flags;
1868c2ecf20Sopenharmony_ci	struct xgpio_instance *chip = gpiochip_get_data(gc);
1878c2ecf20Sopenharmony_ci	int index =  xgpio_index(chip, gpio);
1888c2ecf20Sopenharmony_ci	int offset =  xgpio_offset(chip, gpio);
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	spin_lock_irqsave(&chip->gpio_lock[index], flags);
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	/* Set the GPIO bit in shadow register and set direction as input */
1938c2ecf20Sopenharmony_ci	chip->gpio_dir[index] |= BIT(offset);
1948c2ecf20Sopenharmony_ci	xgpio_writereg(chip->regs + XGPIO_TRI_OFFSET +
1958c2ecf20Sopenharmony_ci		       xgpio_regoffset(chip, gpio), chip->gpio_dir[index]);
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	return 0;
2008c2ecf20Sopenharmony_ci}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci/**
2038c2ecf20Sopenharmony_ci * xgpio_dir_out - Set the direction of the specified GPIO signal as output.
2048c2ecf20Sopenharmony_ci * @gc:     Pointer to gpio_chip device structure.
2058c2ecf20Sopenharmony_ci * @gpio:   GPIO signal number.
2068c2ecf20Sopenharmony_ci * @val:    Value to be written to specified signal.
2078c2ecf20Sopenharmony_ci *
2088c2ecf20Sopenharmony_ci * This function sets the direction of specified GPIO signal as output.
2098c2ecf20Sopenharmony_ci *
2108c2ecf20Sopenharmony_ci * Return:
2118c2ecf20Sopenharmony_ci * If all GPIO signals of GPIO chip is configured as input then it returns
2128c2ecf20Sopenharmony_ci * error otherwise it returns 0.
2138c2ecf20Sopenharmony_ci */
2148c2ecf20Sopenharmony_cistatic int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
2158c2ecf20Sopenharmony_ci{
2168c2ecf20Sopenharmony_ci	unsigned long flags;
2178c2ecf20Sopenharmony_ci	struct xgpio_instance *chip = gpiochip_get_data(gc);
2188c2ecf20Sopenharmony_ci	int index =  xgpio_index(chip, gpio);
2198c2ecf20Sopenharmony_ci	int offset =  xgpio_offset(chip, gpio);
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	spin_lock_irqsave(&chip->gpio_lock[index], flags);
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	/* Write state of GPIO signal */
2248c2ecf20Sopenharmony_ci	if (val)
2258c2ecf20Sopenharmony_ci		chip->gpio_state[index] |= BIT(offset);
2268c2ecf20Sopenharmony_ci	else
2278c2ecf20Sopenharmony_ci		chip->gpio_state[index] &= ~BIT(offset);
2288c2ecf20Sopenharmony_ci	xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET +
2298c2ecf20Sopenharmony_ci			xgpio_regoffset(chip, gpio), chip->gpio_state[index]);
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	/* Clear the GPIO bit in shadow register and set direction as output */
2328c2ecf20Sopenharmony_ci	chip->gpio_dir[index] &= ~BIT(offset);
2338c2ecf20Sopenharmony_ci	xgpio_writereg(chip->regs + XGPIO_TRI_OFFSET +
2348c2ecf20Sopenharmony_ci			xgpio_regoffset(chip, gpio), chip->gpio_dir[index]);
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	return 0;
2398c2ecf20Sopenharmony_ci}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci/**
2428c2ecf20Sopenharmony_ci * xgpio_save_regs - Set initial values of GPIO pins
2438c2ecf20Sopenharmony_ci * @chip: Pointer to GPIO instance
2448c2ecf20Sopenharmony_ci */
2458c2ecf20Sopenharmony_cistatic void xgpio_save_regs(struct xgpio_instance *chip)
2468c2ecf20Sopenharmony_ci{
2478c2ecf20Sopenharmony_ci	xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET,	chip->gpio_state[0]);
2488c2ecf20Sopenharmony_ci	xgpio_writereg(chip->regs + XGPIO_TRI_OFFSET, chip->gpio_dir[0]);
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	if (!chip->gpio_width[1])
2518c2ecf20Sopenharmony_ci		return;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET + XGPIO_CHANNEL_OFFSET,
2548c2ecf20Sopenharmony_ci		       chip->gpio_state[1]);
2558c2ecf20Sopenharmony_ci	xgpio_writereg(chip->regs + XGPIO_TRI_OFFSET + XGPIO_CHANNEL_OFFSET,
2568c2ecf20Sopenharmony_ci		       chip->gpio_dir[1]);
2578c2ecf20Sopenharmony_ci}
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci/**
2608c2ecf20Sopenharmony_ci * xgpio_of_probe - Probe method for the GPIO device.
2618c2ecf20Sopenharmony_ci * @pdev: pointer to the platform device
2628c2ecf20Sopenharmony_ci *
2638c2ecf20Sopenharmony_ci * Return:
2648c2ecf20Sopenharmony_ci * It returns 0, if the driver is bound to the GPIO device, or
2658c2ecf20Sopenharmony_ci * a negative value if there is an error.
2668c2ecf20Sopenharmony_ci */
2678c2ecf20Sopenharmony_cistatic int xgpio_probe(struct platform_device *pdev)
2688c2ecf20Sopenharmony_ci{
2698c2ecf20Sopenharmony_ci	struct xgpio_instance *chip;
2708c2ecf20Sopenharmony_ci	int status = 0;
2718c2ecf20Sopenharmony_ci	struct device_node *np = pdev->dev.of_node;
2728c2ecf20Sopenharmony_ci	u32 is_dual;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
2758c2ecf20Sopenharmony_ci	if (!chip)
2768c2ecf20Sopenharmony_ci		return -ENOMEM;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, chip);
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	/* Update GPIO state shadow register with default value */
2818c2ecf20Sopenharmony_ci	of_property_read_u32(np, "xlnx,dout-default", &chip->gpio_state[0]);
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	/* Update GPIO direction shadow register with default value */
2848c2ecf20Sopenharmony_ci	if (of_property_read_u32(np, "xlnx,tri-default", &chip->gpio_dir[0]))
2858c2ecf20Sopenharmony_ci		chip->gpio_dir[0] = 0xFFFFFFFF;
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	/*
2888c2ecf20Sopenharmony_ci	 * Check device node and parent device node for device width
2898c2ecf20Sopenharmony_ci	 * and assume default width of 32
2908c2ecf20Sopenharmony_ci	 */
2918c2ecf20Sopenharmony_ci	if (of_property_read_u32(np, "xlnx,gpio-width", &chip->gpio_width[0]))
2928c2ecf20Sopenharmony_ci		chip->gpio_width[0] = 32;
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	spin_lock_init(&chip->gpio_lock[0]);
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	if (of_property_read_u32(np, "xlnx,is-dual", &is_dual))
2978c2ecf20Sopenharmony_ci		is_dual = 0;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	if (is_dual) {
3008c2ecf20Sopenharmony_ci		/* Update GPIO state shadow register with default value */
3018c2ecf20Sopenharmony_ci		of_property_read_u32(np, "xlnx,dout-default-2",
3028c2ecf20Sopenharmony_ci				     &chip->gpio_state[1]);
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci		/* Update GPIO direction shadow register with default value */
3058c2ecf20Sopenharmony_ci		if (of_property_read_u32(np, "xlnx,tri-default-2",
3068c2ecf20Sopenharmony_ci					 &chip->gpio_dir[1]))
3078c2ecf20Sopenharmony_ci			chip->gpio_dir[1] = 0xFFFFFFFF;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci		/*
3108c2ecf20Sopenharmony_ci		 * Check device node and parent device node for device width
3118c2ecf20Sopenharmony_ci		 * and assume default width of 32
3128c2ecf20Sopenharmony_ci		 */
3138c2ecf20Sopenharmony_ci		if (of_property_read_u32(np, "xlnx,gpio2-width",
3148c2ecf20Sopenharmony_ci					 &chip->gpio_width[1]))
3158c2ecf20Sopenharmony_ci			chip->gpio_width[1] = 32;
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci		spin_lock_init(&chip->gpio_lock[1]);
3188c2ecf20Sopenharmony_ci	}
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	chip->gc.base = -1;
3218c2ecf20Sopenharmony_ci	chip->gc.ngpio = chip->gpio_width[0] + chip->gpio_width[1];
3228c2ecf20Sopenharmony_ci	chip->gc.parent = &pdev->dev;
3238c2ecf20Sopenharmony_ci	chip->gc.direction_input = xgpio_dir_in;
3248c2ecf20Sopenharmony_ci	chip->gc.direction_output = xgpio_dir_out;
3258c2ecf20Sopenharmony_ci	chip->gc.get = xgpio_get;
3268c2ecf20Sopenharmony_ci	chip->gc.set = xgpio_set;
3278c2ecf20Sopenharmony_ci	chip->gc.set_multiple = xgpio_set_multiple;
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	chip->gc.label = dev_name(&pdev->dev);
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	chip->regs = devm_platform_ioremap_resource(pdev, 0);
3328c2ecf20Sopenharmony_ci	if (IS_ERR(chip->regs)) {
3338c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "failed to ioremap memory resource\n");
3348c2ecf20Sopenharmony_ci		return PTR_ERR(chip->regs);
3358c2ecf20Sopenharmony_ci	}
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	xgpio_save_regs(chip);
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	status = devm_gpiochip_add_data(&pdev->dev, &chip->gc, chip);
3408c2ecf20Sopenharmony_ci	if (status) {
3418c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "failed to add GPIO chip\n");
3428c2ecf20Sopenharmony_ci		return status;
3438c2ecf20Sopenharmony_ci	}
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	return 0;
3468c2ecf20Sopenharmony_ci}
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_cistatic const struct of_device_id xgpio_of_match[] = {
3498c2ecf20Sopenharmony_ci	{ .compatible = "xlnx,xps-gpio-1.00.a", },
3508c2ecf20Sopenharmony_ci	{ /* end of list */ },
3518c2ecf20Sopenharmony_ci};
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, xgpio_of_match);
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_cistatic struct platform_driver xgpio_plat_driver = {
3568c2ecf20Sopenharmony_ci	.probe		= xgpio_probe,
3578c2ecf20Sopenharmony_ci	.driver		= {
3588c2ecf20Sopenharmony_ci			.name = "gpio-xilinx",
3598c2ecf20Sopenharmony_ci			.of_match_table	= xgpio_of_match,
3608c2ecf20Sopenharmony_ci	},
3618c2ecf20Sopenharmony_ci};
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_cistatic int __init xgpio_init(void)
3648c2ecf20Sopenharmony_ci{
3658c2ecf20Sopenharmony_ci	return platform_driver_register(&xgpio_plat_driver);
3668c2ecf20Sopenharmony_ci}
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_cisubsys_initcall(xgpio_init);
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_cistatic void __exit xgpio_exit(void)
3718c2ecf20Sopenharmony_ci{
3728c2ecf20Sopenharmony_ci	platform_driver_unregister(&xgpio_plat_driver);
3738c2ecf20Sopenharmony_ci}
3748c2ecf20Sopenharmony_cimodule_exit(xgpio_exit);
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ciMODULE_AUTHOR("Xilinx, Inc.");
3778c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Xilinx GPIO driver");
3788c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
379