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