162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Xilinx gpio driver for xps/axi_gpio IP. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2008 - 2013 Xilinx, Inc. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/bitmap.h> 962306a36Sopenharmony_ci#include <linux/bitops.h> 1062306a36Sopenharmony_ci#include <linux/clk.h> 1162306a36Sopenharmony_ci#include <linux/errno.h> 1262306a36Sopenharmony_ci#include <linux/gpio/driver.h> 1362306a36Sopenharmony_ci#include <linux/init.h> 1462306a36Sopenharmony_ci#include <linux/interrupt.h> 1562306a36Sopenharmony_ci#include <linux/io.h> 1662306a36Sopenharmony_ci#include <linux/irq.h> 1762306a36Sopenharmony_ci#include <linux/module.h> 1862306a36Sopenharmony_ci#include <linux/of.h> 1962306a36Sopenharmony_ci#include <linux/platform_device.h> 2062306a36Sopenharmony_ci#include <linux/pm_runtime.h> 2162306a36Sopenharmony_ci#include <linux/slab.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/* Register Offset Definitions */ 2462306a36Sopenharmony_ci#define XGPIO_DATA_OFFSET (0x0) /* Data register */ 2562306a36Sopenharmony_ci#define XGPIO_TRI_OFFSET (0x4) /* I/O direction register */ 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define XGPIO_CHANNEL0_OFFSET 0x0 2862306a36Sopenharmony_ci#define XGPIO_CHANNEL1_OFFSET 0x8 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#define XGPIO_GIER_OFFSET 0x11c /* Global Interrupt Enable */ 3162306a36Sopenharmony_ci#define XGPIO_GIER_IE BIT(31) 3262306a36Sopenharmony_ci#define XGPIO_IPISR_OFFSET 0x120 /* IP Interrupt Status */ 3362306a36Sopenharmony_ci#define XGPIO_IPIER_OFFSET 0x128 /* IP Interrupt Enable */ 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/* Read/Write access to the GPIO registers */ 3662306a36Sopenharmony_ci#if defined(CONFIG_ARCH_ZYNQ) || defined(CONFIG_X86) 3762306a36Sopenharmony_ci# define xgpio_readreg(offset) readl(offset) 3862306a36Sopenharmony_ci# define xgpio_writereg(offset, val) writel(val, offset) 3962306a36Sopenharmony_ci#else 4062306a36Sopenharmony_ci# define xgpio_readreg(offset) __raw_readl(offset) 4162306a36Sopenharmony_ci# define xgpio_writereg(offset, val) __raw_writel(val, offset) 4262306a36Sopenharmony_ci#endif 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/** 4562306a36Sopenharmony_ci * struct xgpio_instance - Stores information about GPIO device 4662306a36Sopenharmony_ci * @gc: GPIO chip 4762306a36Sopenharmony_ci * @regs: register block 4862306a36Sopenharmony_ci * @hw_map: GPIO pin mapping on hardware side 4962306a36Sopenharmony_ci * @sw_map: GPIO pin mapping on software side 5062306a36Sopenharmony_ci * @state: GPIO write state shadow register 5162306a36Sopenharmony_ci * @last_irq_read: GPIO read state register from last interrupt 5262306a36Sopenharmony_ci * @dir: GPIO direction shadow register 5362306a36Sopenharmony_ci * @gpio_lock: Lock used for synchronization 5462306a36Sopenharmony_ci * @irq: IRQ used by GPIO device 5562306a36Sopenharmony_ci * @irqchip: IRQ chip 5662306a36Sopenharmony_ci * @enable: GPIO IRQ enable/disable bitfield 5762306a36Sopenharmony_ci * @rising_edge: GPIO IRQ rising edge enable/disable bitfield 5862306a36Sopenharmony_ci * @falling_edge: GPIO IRQ falling edge enable/disable bitfield 5962306a36Sopenharmony_ci * @clk: clock resource for this driver 6062306a36Sopenharmony_ci */ 6162306a36Sopenharmony_cistruct xgpio_instance { 6262306a36Sopenharmony_ci struct gpio_chip gc; 6362306a36Sopenharmony_ci void __iomem *regs; 6462306a36Sopenharmony_ci DECLARE_BITMAP(hw_map, 64); 6562306a36Sopenharmony_ci DECLARE_BITMAP(sw_map, 64); 6662306a36Sopenharmony_ci DECLARE_BITMAP(state, 64); 6762306a36Sopenharmony_ci DECLARE_BITMAP(last_irq_read, 64); 6862306a36Sopenharmony_ci DECLARE_BITMAP(dir, 64); 6962306a36Sopenharmony_ci spinlock_t gpio_lock; /* For serializing operations */ 7062306a36Sopenharmony_ci int irq; 7162306a36Sopenharmony_ci DECLARE_BITMAP(enable, 64); 7262306a36Sopenharmony_ci DECLARE_BITMAP(rising_edge, 64); 7362306a36Sopenharmony_ci DECLARE_BITMAP(falling_edge, 64); 7462306a36Sopenharmony_ci struct clk *clk; 7562306a36Sopenharmony_ci}; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic inline int xgpio_from_bit(struct xgpio_instance *chip, int bit) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci return bitmap_bitremap(bit, chip->hw_map, chip->sw_map, 64); 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic inline int xgpio_to_bit(struct xgpio_instance *chip, int gpio) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci return bitmap_bitremap(gpio, chip->sw_map, chip->hw_map, 64); 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic inline u32 xgpio_get_value32(const unsigned long *map, int bit) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci const size_t index = BIT_WORD(bit); 9062306a36Sopenharmony_ci const unsigned long offset = (bit % BITS_PER_LONG) & BIT(5); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci return (map[index] >> offset) & 0xFFFFFFFFul; 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic inline void xgpio_set_value32(unsigned long *map, int bit, u32 v) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci const size_t index = BIT_WORD(bit); 9862306a36Sopenharmony_ci const unsigned long offset = (bit % BITS_PER_LONG) & BIT(5); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci map[index] &= ~(0xFFFFFFFFul << offset); 10162306a36Sopenharmony_ci map[index] |= (unsigned long)v << offset; 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic inline int xgpio_regoffset(struct xgpio_instance *chip, int ch) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci switch (ch) { 10762306a36Sopenharmony_ci case 0: 10862306a36Sopenharmony_ci return XGPIO_CHANNEL0_OFFSET; 10962306a36Sopenharmony_ci case 1: 11062306a36Sopenharmony_ci return XGPIO_CHANNEL1_OFFSET; 11162306a36Sopenharmony_ci default: 11262306a36Sopenharmony_ci return -EINVAL; 11362306a36Sopenharmony_ci } 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic void xgpio_read_ch(struct xgpio_instance *chip, int reg, int bit, unsigned long *a) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci void __iomem *addr = chip->regs + reg + xgpio_regoffset(chip, bit / 32); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci xgpio_set_value32(a, bit, xgpio_readreg(addr)); 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic void xgpio_write_ch(struct xgpio_instance *chip, int reg, int bit, unsigned long *a) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci void __iomem *addr = chip->regs + reg + xgpio_regoffset(chip, bit / 32); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci xgpio_writereg(addr, xgpio_get_value32(a, bit)); 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic void xgpio_read_ch_all(struct xgpio_instance *chip, int reg, unsigned long *a) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci int bit, lastbit = xgpio_to_bit(chip, chip->gc.ngpio - 1); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci for (bit = 0; bit <= lastbit ; bit += 32) 13562306a36Sopenharmony_ci xgpio_read_ch(chip, reg, bit, a); 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic void xgpio_write_ch_all(struct xgpio_instance *chip, int reg, unsigned long *a) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci int bit, lastbit = xgpio_to_bit(chip, chip->gc.ngpio - 1); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci for (bit = 0; bit <= lastbit ; bit += 32) 14362306a36Sopenharmony_ci xgpio_write_ch(chip, reg, bit, a); 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci/** 14762306a36Sopenharmony_ci * xgpio_get - Read the specified signal of the GPIO device. 14862306a36Sopenharmony_ci * @gc: Pointer to gpio_chip device structure. 14962306a36Sopenharmony_ci * @gpio: GPIO signal number. 15062306a36Sopenharmony_ci * 15162306a36Sopenharmony_ci * This function reads the specified signal of the GPIO device. 15262306a36Sopenharmony_ci * 15362306a36Sopenharmony_ci * Return: 15462306a36Sopenharmony_ci * 0 if direction of GPIO signals is set as input otherwise it 15562306a36Sopenharmony_ci * returns negative error value. 15662306a36Sopenharmony_ci */ 15762306a36Sopenharmony_cistatic int xgpio_get(struct gpio_chip *gc, unsigned int gpio) 15862306a36Sopenharmony_ci{ 15962306a36Sopenharmony_ci struct xgpio_instance *chip = gpiochip_get_data(gc); 16062306a36Sopenharmony_ci int bit = xgpio_to_bit(chip, gpio); 16162306a36Sopenharmony_ci DECLARE_BITMAP(state, 64); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci xgpio_read_ch(chip, XGPIO_DATA_OFFSET, bit, state); 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci return test_bit(bit, state); 16662306a36Sopenharmony_ci} 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci/** 16962306a36Sopenharmony_ci * xgpio_set - Write the specified signal of the GPIO device. 17062306a36Sopenharmony_ci * @gc: Pointer to gpio_chip device structure. 17162306a36Sopenharmony_ci * @gpio: GPIO signal number. 17262306a36Sopenharmony_ci * @val: Value to be written to specified signal. 17362306a36Sopenharmony_ci * 17462306a36Sopenharmony_ci * This function writes the specified value in to the specified signal of the 17562306a36Sopenharmony_ci * GPIO device. 17662306a36Sopenharmony_ci */ 17762306a36Sopenharmony_cistatic void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci unsigned long flags; 18062306a36Sopenharmony_ci struct xgpio_instance *chip = gpiochip_get_data(gc); 18162306a36Sopenharmony_ci int bit = xgpio_to_bit(chip, gpio); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci spin_lock_irqsave(&chip->gpio_lock, flags); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci /* Write to GPIO signal and set its direction to output */ 18662306a36Sopenharmony_ci __assign_bit(bit, chip->state, val); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci xgpio_write_ch(chip, XGPIO_DATA_OFFSET, bit, chip->state); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci spin_unlock_irqrestore(&chip->gpio_lock, flags); 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci/** 19462306a36Sopenharmony_ci * xgpio_set_multiple - Write the specified signals of the GPIO device. 19562306a36Sopenharmony_ci * @gc: Pointer to gpio_chip device structure. 19662306a36Sopenharmony_ci * @mask: Mask of the GPIOS to modify. 19762306a36Sopenharmony_ci * @bits: Value to be wrote on each GPIO 19862306a36Sopenharmony_ci * 19962306a36Sopenharmony_ci * This function writes the specified values into the specified signals of the 20062306a36Sopenharmony_ci * GPIO devices. 20162306a36Sopenharmony_ci */ 20262306a36Sopenharmony_cistatic void xgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask, 20362306a36Sopenharmony_ci unsigned long *bits) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci DECLARE_BITMAP(hw_mask, 64); 20662306a36Sopenharmony_ci DECLARE_BITMAP(hw_bits, 64); 20762306a36Sopenharmony_ci DECLARE_BITMAP(state, 64); 20862306a36Sopenharmony_ci unsigned long flags; 20962306a36Sopenharmony_ci struct xgpio_instance *chip = gpiochip_get_data(gc); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci bitmap_remap(hw_mask, mask, chip->sw_map, chip->hw_map, 64); 21262306a36Sopenharmony_ci bitmap_remap(hw_bits, bits, chip->sw_map, chip->hw_map, 64); 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci spin_lock_irqsave(&chip->gpio_lock, flags); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci bitmap_replace(state, chip->state, hw_bits, hw_mask, 64); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci xgpio_write_ch_all(chip, XGPIO_DATA_OFFSET, state); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci bitmap_copy(chip->state, state, 64); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci spin_unlock_irqrestore(&chip->gpio_lock, flags); 22362306a36Sopenharmony_ci} 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci/** 22662306a36Sopenharmony_ci * xgpio_dir_in - Set the direction of the specified GPIO signal as input. 22762306a36Sopenharmony_ci * @gc: Pointer to gpio_chip device structure. 22862306a36Sopenharmony_ci * @gpio: GPIO signal number. 22962306a36Sopenharmony_ci * 23062306a36Sopenharmony_ci * Return: 23162306a36Sopenharmony_ci * 0 - if direction of GPIO signals is set as input 23262306a36Sopenharmony_ci * otherwise it returns negative error value. 23362306a36Sopenharmony_ci */ 23462306a36Sopenharmony_cistatic int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci unsigned long flags; 23762306a36Sopenharmony_ci struct xgpio_instance *chip = gpiochip_get_data(gc); 23862306a36Sopenharmony_ci int bit = xgpio_to_bit(chip, gpio); 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci spin_lock_irqsave(&chip->gpio_lock, flags); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci /* Set the GPIO bit in shadow register and set direction as input */ 24362306a36Sopenharmony_ci __set_bit(bit, chip->dir); 24462306a36Sopenharmony_ci xgpio_write_ch(chip, XGPIO_TRI_OFFSET, bit, chip->dir); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci spin_unlock_irqrestore(&chip->gpio_lock, flags); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci return 0; 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci/** 25262306a36Sopenharmony_ci * xgpio_dir_out - Set the direction of the specified GPIO signal as output. 25362306a36Sopenharmony_ci * @gc: Pointer to gpio_chip device structure. 25462306a36Sopenharmony_ci * @gpio: GPIO signal number. 25562306a36Sopenharmony_ci * @val: Value to be written to specified signal. 25662306a36Sopenharmony_ci * 25762306a36Sopenharmony_ci * This function sets the direction of specified GPIO signal as output. 25862306a36Sopenharmony_ci * 25962306a36Sopenharmony_ci * Return: 26062306a36Sopenharmony_ci * If all GPIO signals of GPIO chip is configured as input then it returns 26162306a36Sopenharmony_ci * error otherwise it returns 0. 26262306a36Sopenharmony_ci */ 26362306a36Sopenharmony_cistatic int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci unsigned long flags; 26662306a36Sopenharmony_ci struct xgpio_instance *chip = gpiochip_get_data(gc); 26762306a36Sopenharmony_ci int bit = xgpio_to_bit(chip, gpio); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci spin_lock_irqsave(&chip->gpio_lock, flags); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci /* Write state of GPIO signal */ 27262306a36Sopenharmony_ci __assign_bit(bit, chip->state, val); 27362306a36Sopenharmony_ci xgpio_write_ch(chip, XGPIO_DATA_OFFSET, bit, chip->state); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci /* Clear the GPIO bit in shadow register and set direction as output */ 27662306a36Sopenharmony_ci __clear_bit(bit, chip->dir); 27762306a36Sopenharmony_ci xgpio_write_ch(chip, XGPIO_TRI_OFFSET, bit, chip->dir); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci spin_unlock_irqrestore(&chip->gpio_lock, flags); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci return 0; 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci/** 28562306a36Sopenharmony_ci * xgpio_save_regs - Set initial values of GPIO pins 28662306a36Sopenharmony_ci * @chip: Pointer to GPIO instance 28762306a36Sopenharmony_ci */ 28862306a36Sopenharmony_cistatic void xgpio_save_regs(struct xgpio_instance *chip) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci xgpio_write_ch_all(chip, XGPIO_DATA_OFFSET, chip->state); 29162306a36Sopenharmony_ci xgpio_write_ch_all(chip, XGPIO_TRI_OFFSET, chip->dir); 29262306a36Sopenharmony_ci} 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_cistatic int xgpio_request(struct gpio_chip *chip, unsigned int offset) 29562306a36Sopenharmony_ci{ 29662306a36Sopenharmony_ci int ret; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci ret = pm_runtime_get_sync(chip->parent); 29962306a36Sopenharmony_ci /* 30062306a36Sopenharmony_ci * If the device is already active pm_runtime_get() will return 1 on 30162306a36Sopenharmony_ci * success, but gpio_request still needs to return 0. 30262306a36Sopenharmony_ci */ 30362306a36Sopenharmony_ci return ret < 0 ? ret : 0; 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_cistatic void xgpio_free(struct gpio_chip *chip, unsigned int offset) 30762306a36Sopenharmony_ci{ 30862306a36Sopenharmony_ci pm_runtime_put(chip->parent); 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_cistatic int __maybe_unused xgpio_suspend(struct device *dev) 31262306a36Sopenharmony_ci{ 31362306a36Sopenharmony_ci struct xgpio_instance *gpio = dev_get_drvdata(dev); 31462306a36Sopenharmony_ci struct irq_data *data = irq_get_irq_data(gpio->irq); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci if (!data) { 31762306a36Sopenharmony_ci dev_dbg(dev, "IRQ not connected\n"); 31862306a36Sopenharmony_ci return pm_runtime_force_suspend(dev); 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci if (!irqd_is_wakeup_set(data)) 32262306a36Sopenharmony_ci return pm_runtime_force_suspend(dev); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci return 0; 32562306a36Sopenharmony_ci} 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci/** 32862306a36Sopenharmony_ci * xgpio_remove - Remove method for the GPIO device. 32962306a36Sopenharmony_ci * @pdev: pointer to the platform device 33062306a36Sopenharmony_ci * 33162306a36Sopenharmony_ci * This function remove gpiochips and frees all the allocated resources. 33262306a36Sopenharmony_ci * 33362306a36Sopenharmony_ci * Return: 0 always 33462306a36Sopenharmony_ci */ 33562306a36Sopenharmony_cistatic int xgpio_remove(struct platform_device *pdev) 33662306a36Sopenharmony_ci{ 33762306a36Sopenharmony_ci struct xgpio_instance *gpio = platform_get_drvdata(pdev); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci pm_runtime_get_sync(&pdev->dev); 34062306a36Sopenharmony_ci pm_runtime_put_noidle(&pdev->dev); 34162306a36Sopenharmony_ci pm_runtime_disable(&pdev->dev); 34262306a36Sopenharmony_ci clk_disable_unprepare(gpio->clk); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci return 0; 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci/** 34862306a36Sopenharmony_ci * xgpio_irq_ack - Acknowledge a child GPIO interrupt. 34962306a36Sopenharmony_ci * @irq_data: per IRQ and chip data passed down to chip functions 35062306a36Sopenharmony_ci * This currently does nothing, but irq_ack is unconditionally called by 35162306a36Sopenharmony_ci * handle_edge_irq and therefore must be defined. 35262306a36Sopenharmony_ci */ 35362306a36Sopenharmony_cistatic void xgpio_irq_ack(struct irq_data *irq_data) 35462306a36Sopenharmony_ci{ 35562306a36Sopenharmony_ci} 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_cistatic int __maybe_unused xgpio_resume(struct device *dev) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci struct xgpio_instance *gpio = dev_get_drvdata(dev); 36062306a36Sopenharmony_ci struct irq_data *data = irq_get_irq_data(gpio->irq); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci if (!data) { 36362306a36Sopenharmony_ci dev_dbg(dev, "IRQ not connected\n"); 36462306a36Sopenharmony_ci return pm_runtime_force_resume(dev); 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci if (!irqd_is_wakeup_set(data)) 36862306a36Sopenharmony_ci return pm_runtime_force_resume(dev); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci return 0; 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_cistatic int __maybe_unused xgpio_runtime_suspend(struct device *dev) 37462306a36Sopenharmony_ci{ 37562306a36Sopenharmony_ci struct xgpio_instance *gpio = dev_get_drvdata(dev); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci clk_disable(gpio->clk); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci return 0; 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_cistatic int __maybe_unused xgpio_runtime_resume(struct device *dev) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci struct xgpio_instance *gpio = dev_get_drvdata(dev); 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci return clk_enable(gpio->clk); 38762306a36Sopenharmony_ci} 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_cistatic const struct dev_pm_ops xgpio_dev_pm_ops = { 39062306a36Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(xgpio_suspend, xgpio_resume) 39162306a36Sopenharmony_ci SET_RUNTIME_PM_OPS(xgpio_runtime_suspend, 39262306a36Sopenharmony_ci xgpio_runtime_resume, NULL) 39362306a36Sopenharmony_ci}; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci/** 39662306a36Sopenharmony_ci * xgpio_irq_mask - Write the specified signal of the GPIO device. 39762306a36Sopenharmony_ci * @irq_data: per IRQ and chip data passed down to chip functions 39862306a36Sopenharmony_ci */ 39962306a36Sopenharmony_cistatic void xgpio_irq_mask(struct irq_data *irq_data) 40062306a36Sopenharmony_ci{ 40162306a36Sopenharmony_ci unsigned long flags; 40262306a36Sopenharmony_ci struct xgpio_instance *chip = irq_data_get_irq_chip_data(irq_data); 40362306a36Sopenharmony_ci int irq_offset = irqd_to_hwirq(irq_data); 40462306a36Sopenharmony_ci int bit = xgpio_to_bit(chip, irq_offset); 40562306a36Sopenharmony_ci u32 mask = BIT(bit / 32), temp; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci spin_lock_irqsave(&chip->gpio_lock, flags); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci __clear_bit(bit, chip->enable); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci if (xgpio_get_value32(chip->enable, bit) == 0) { 41262306a36Sopenharmony_ci /* Disable per channel interrupt */ 41362306a36Sopenharmony_ci temp = xgpio_readreg(chip->regs + XGPIO_IPIER_OFFSET); 41462306a36Sopenharmony_ci temp &= ~mask; 41562306a36Sopenharmony_ci xgpio_writereg(chip->regs + XGPIO_IPIER_OFFSET, temp); 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci spin_unlock_irqrestore(&chip->gpio_lock, flags); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci gpiochip_disable_irq(&chip->gc, irq_offset); 42062306a36Sopenharmony_ci} 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci/** 42362306a36Sopenharmony_ci * xgpio_irq_unmask - Write the specified signal of the GPIO device. 42462306a36Sopenharmony_ci * @irq_data: per IRQ and chip data passed down to chip functions 42562306a36Sopenharmony_ci */ 42662306a36Sopenharmony_cistatic void xgpio_irq_unmask(struct irq_data *irq_data) 42762306a36Sopenharmony_ci{ 42862306a36Sopenharmony_ci unsigned long flags; 42962306a36Sopenharmony_ci struct xgpio_instance *chip = irq_data_get_irq_chip_data(irq_data); 43062306a36Sopenharmony_ci int irq_offset = irqd_to_hwirq(irq_data); 43162306a36Sopenharmony_ci int bit = xgpio_to_bit(chip, irq_offset); 43262306a36Sopenharmony_ci u32 old_enable = xgpio_get_value32(chip->enable, bit); 43362306a36Sopenharmony_ci u32 mask = BIT(bit / 32), val; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci gpiochip_enable_irq(&chip->gc, irq_offset); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci spin_lock_irqsave(&chip->gpio_lock, flags); 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci __set_bit(bit, chip->enable); 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci if (old_enable == 0) { 44262306a36Sopenharmony_ci /* Clear any existing per-channel interrupts */ 44362306a36Sopenharmony_ci val = xgpio_readreg(chip->regs + XGPIO_IPISR_OFFSET); 44462306a36Sopenharmony_ci val &= mask; 44562306a36Sopenharmony_ci xgpio_writereg(chip->regs + XGPIO_IPISR_OFFSET, val); 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci /* Update GPIO IRQ read data before enabling interrupt*/ 44862306a36Sopenharmony_ci xgpio_read_ch(chip, XGPIO_DATA_OFFSET, bit, chip->last_irq_read); 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci /* Enable per channel interrupt */ 45162306a36Sopenharmony_ci val = xgpio_readreg(chip->regs + XGPIO_IPIER_OFFSET); 45262306a36Sopenharmony_ci val |= mask; 45362306a36Sopenharmony_ci xgpio_writereg(chip->regs + XGPIO_IPIER_OFFSET, val); 45462306a36Sopenharmony_ci } 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci spin_unlock_irqrestore(&chip->gpio_lock, flags); 45762306a36Sopenharmony_ci} 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci/** 46062306a36Sopenharmony_ci * xgpio_set_irq_type - Write the specified signal of the GPIO device. 46162306a36Sopenharmony_ci * @irq_data: Per IRQ and chip data passed down to chip functions 46262306a36Sopenharmony_ci * @type: Interrupt type that is to be set for the gpio pin 46362306a36Sopenharmony_ci * 46462306a36Sopenharmony_ci * Return: 46562306a36Sopenharmony_ci * 0 if interrupt type is supported otherwise -EINVAL 46662306a36Sopenharmony_ci */ 46762306a36Sopenharmony_cistatic int xgpio_set_irq_type(struct irq_data *irq_data, unsigned int type) 46862306a36Sopenharmony_ci{ 46962306a36Sopenharmony_ci struct xgpio_instance *chip = irq_data_get_irq_chip_data(irq_data); 47062306a36Sopenharmony_ci int irq_offset = irqd_to_hwirq(irq_data); 47162306a36Sopenharmony_ci int bit = xgpio_to_bit(chip, irq_offset); 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci /* 47462306a36Sopenharmony_ci * The Xilinx GPIO hardware provides a single interrupt status 47562306a36Sopenharmony_ci * indication for any state change in a given GPIO channel (bank). 47662306a36Sopenharmony_ci * Therefore, only rising edge or falling edge triggers are 47762306a36Sopenharmony_ci * supported. 47862306a36Sopenharmony_ci */ 47962306a36Sopenharmony_ci switch (type & IRQ_TYPE_SENSE_MASK) { 48062306a36Sopenharmony_ci case IRQ_TYPE_EDGE_BOTH: 48162306a36Sopenharmony_ci __set_bit(bit, chip->rising_edge); 48262306a36Sopenharmony_ci __set_bit(bit, chip->falling_edge); 48362306a36Sopenharmony_ci break; 48462306a36Sopenharmony_ci case IRQ_TYPE_EDGE_RISING: 48562306a36Sopenharmony_ci __set_bit(bit, chip->rising_edge); 48662306a36Sopenharmony_ci __clear_bit(bit, chip->falling_edge); 48762306a36Sopenharmony_ci break; 48862306a36Sopenharmony_ci case IRQ_TYPE_EDGE_FALLING: 48962306a36Sopenharmony_ci __clear_bit(bit, chip->rising_edge); 49062306a36Sopenharmony_ci __set_bit(bit, chip->falling_edge); 49162306a36Sopenharmony_ci break; 49262306a36Sopenharmony_ci default: 49362306a36Sopenharmony_ci return -EINVAL; 49462306a36Sopenharmony_ci } 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci irq_set_handler_locked(irq_data, handle_edge_irq); 49762306a36Sopenharmony_ci return 0; 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci/** 50162306a36Sopenharmony_ci * xgpio_irqhandler - Gpio interrupt service routine 50262306a36Sopenharmony_ci * @desc: Pointer to interrupt description 50362306a36Sopenharmony_ci */ 50462306a36Sopenharmony_cistatic void xgpio_irqhandler(struct irq_desc *desc) 50562306a36Sopenharmony_ci{ 50662306a36Sopenharmony_ci struct xgpio_instance *chip = irq_desc_get_handler_data(desc); 50762306a36Sopenharmony_ci struct gpio_chip *gc = &chip->gc; 50862306a36Sopenharmony_ci struct irq_chip *irqchip = irq_desc_get_chip(desc); 50962306a36Sopenharmony_ci DECLARE_BITMAP(rising, 64); 51062306a36Sopenharmony_ci DECLARE_BITMAP(falling, 64); 51162306a36Sopenharmony_ci DECLARE_BITMAP(all, 64); 51262306a36Sopenharmony_ci int irq_offset; 51362306a36Sopenharmony_ci u32 status; 51462306a36Sopenharmony_ci u32 bit; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci status = xgpio_readreg(chip->regs + XGPIO_IPISR_OFFSET); 51762306a36Sopenharmony_ci xgpio_writereg(chip->regs + XGPIO_IPISR_OFFSET, status); 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci chained_irq_enter(irqchip, desc); 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci spin_lock(&chip->gpio_lock); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci xgpio_read_ch_all(chip, XGPIO_DATA_OFFSET, all); 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci bitmap_complement(rising, chip->last_irq_read, 64); 52662306a36Sopenharmony_ci bitmap_and(rising, rising, all, 64); 52762306a36Sopenharmony_ci bitmap_and(rising, rising, chip->enable, 64); 52862306a36Sopenharmony_ci bitmap_and(rising, rising, chip->rising_edge, 64); 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci bitmap_complement(falling, all, 64); 53162306a36Sopenharmony_ci bitmap_and(falling, falling, chip->last_irq_read, 64); 53262306a36Sopenharmony_ci bitmap_and(falling, falling, chip->enable, 64); 53362306a36Sopenharmony_ci bitmap_and(falling, falling, chip->falling_edge, 64); 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci bitmap_copy(chip->last_irq_read, all, 64); 53662306a36Sopenharmony_ci bitmap_or(all, rising, falling, 64); 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci spin_unlock(&chip->gpio_lock); 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci dev_dbg(gc->parent, "IRQ rising %*pb falling %*pb\n", 64, rising, 64, falling); 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci for_each_set_bit(bit, all, 64) { 54362306a36Sopenharmony_ci irq_offset = xgpio_from_bit(chip, bit); 54462306a36Sopenharmony_ci generic_handle_domain_irq(gc->irq.domain, irq_offset); 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci chained_irq_exit(irqchip, desc); 54862306a36Sopenharmony_ci} 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_cistatic const struct irq_chip xgpio_irq_chip = { 55162306a36Sopenharmony_ci .name = "gpio-xilinx", 55262306a36Sopenharmony_ci .irq_ack = xgpio_irq_ack, 55362306a36Sopenharmony_ci .irq_mask = xgpio_irq_mask, 55462306a36Sopenharmony_ci .irq_unmask = xgpio_irq_unmask, 55562306a36Sopenharmony_ci .irq_set_type = xgpio_set_irq_type, 55662306a36Sopenharmony_ci .flags = IRQCHIP_IMMUTABLE, 55762306a36Sopenharmony_ci GPIOCHIP_IRQ_RESOURCE_HELPERS, 55862306a36Sopenharmony_ci}; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci/** 56162306a36Sopenharmony_ci * xgpio_probe - Probe method for the GPIO device. 56262306a36Sopenharmony_ci * @pdev: pointer to the platform device 56362306a36Sopenharmony_ci * 56462306a36Sopenharmony_ci * Return: 56562306a36Sopenharmony_ci * It returns 0, if the driver is bound to the GPIO device, or 56662306a36Sopenharmony_ci * a negative value if there is an error. 56762306a36Sopenharmony_ci */ 56862306a36Sopenharmony_cistatic int xgpio_probe(struct platform_device *pdev) 56962306a36Sopenharmony_ci{ 57062306a36Sopenharmony_ci struct xgpio_instance *chip; 57162306a36Sopenharmony_ci int status = 0; 57262306a36Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 57362306a36Sopenharmony_ci u32 is_dual = 0; 57462306a36Sopenharmony_ci u32 width[2]; 57562306a36Sopenharmony_ci u32 state[2]; 57662306a36Sopenharmony_ci u32 dir[2]; 57762306a36Sopenharmony_ci struct gpio_irq_chip *girq; 57862306a36Sopenharmony_ci u32 temp; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); 58162306a36Sopenharmony_ci if (!chip) 58262306a36Sopenharmony_ci return -ENOMEM; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci platform_set_drvdata(pdev, chip); 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci /* First, check if the device is dual-channel */ 58762306a36Sopenharmony_ci of_property_read_u32(np, "xlnx,is-dual", &is_dual); 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci /* Setup defaults */ 59062306a36Sopenharmony_ci memset32(width, 0, ARRAY_SIZE(width)); 59162306a36Sopenharmony_ci memset32(state, 0, ARRAY_SIZE(state)); 59262306a36Sopenharmony_ci memset32(dir, 0xFFFFFFFF, ARRAY_SIZE(dir)); 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci /* Update GPIO state shadow register with default value */ 59562306a36Sopenharmony_ci of_property_read_u32(np, "xlnx,dout-default", &state[0]); 59662306a36Sopenharmony_ci of_property_read_u32(np, "xlnx,dout-default-2", &state[1]); 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci bitmap_from_arr32(chip->state, state, 64); 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci /* Update GPIO direction shadow register with default value */ 60162306a36Sopenharmony_ci of_property_read_u32(np, "xlnx,tri-default", &dir[0]); 60262306a36Sopenharmony_ci of_property_read_u32(np, "xlnx,tri-default-2", &dir[1]); 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci bitmap_from_arr32(chip->dir, dir, 64); 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci /* 60762306a36Sopenharmony_ci * Check device node and parent device node for device width 60862306a36Sopenharmony_ci * and assume default width of 32 60962306a36Sopenharmony_ci */ 61062306a36Sopenharmony_ci if (of_property_read_u32(np, "xlnx,gpio-width", &width[0])) 61162306a36Sopenharmony_ci width[0] = 32; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci if (width[0] > 32) 61462306a36Sopenharmony_ci return -EINVAL; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci if (is_dual && of_property_read_u32(np, "xlnx,gpio2-width", &width[1])) 61762306a36Sopenharmony_ci width[1] = 32; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci if (width[1] > 32) 62062306a36Sopenharmony_ci return -EINVAL; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci /* Setup software pin mapping */ 62362306a36Sopenharmony_ci bitmap_set(chip->sw_map, 0, width[0] + width[1]); 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci /* Setup hardware pin mapping */ 62662306a36Sopenharmony_ci bitmap_set(chip->hw_map, 0, width[0]); 62762306a36Sopenharmony_ci bitmap_set(chip->hw_map, 32, width[1]); 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci spin_lock_init(&chip->gpio_lock); 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci chip->gc.base = -1; 63262306a36Sopenharmony_ci chip->gc.ngpio = bitmap_weight(chip->hw_map, 64); 63362306a36Sopenharmony_ci chip->gc.parent = &pdev->dev; 63462306a36Sopenharmony_ci chip->gc.direction_input = xgpio_dir_in; 63562306a36Sopenharmony_ci chip->gc.direction_output = xgpio_dir_out; 63662306a36Sopenharmony_ci chip->gc.get = xgpio_get; 63762306a36Sopenharmony_ci chip->gc.set = xgpio_set; 63862306a36Sopenharmony_ci chip->gc.request = xgpio_request; 63962306a36Sopenharmony_ci chip->gc.free = xgpio_free; 64062306a36Sopenharmony_ci chip->gc.set_multiple = xgpio_set_multiple; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci chip->gc.label = dev_name(&pdev->dev); 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci chip->regs = devm_platform_ioremap_resource(pdev, 0); 64562306a36Sopenharmony_ci if (IS_ERR(chip->regs)) { 64662306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to ioremap memory resource\n"); 64762306a36Sopenharmony_ci return PTR_ERR(chip->regs); 64862306a36Sopenharmony_ci } 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci chip->clk = devm_clk_get_optional(&pdev->dev, NULL); 65162306a36Sopenharmony_ci if (IS_ERR(chip->clk)) 65262306a36Sopenharmony_ci return dev_err_probe(&pdev->dev, PTR_ERR(chip->clk), "input clock not found.\n"); 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci status = clk_prepare_enable(chip->clk); 65562306a36Sopenharmony_ci if (status < 0) { 65662306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to prepare clk\n"); 65762306a36Sopenharmony_ci return status; 65862306a36Sopenharmony_ci } 65962306a36Sopenharmony_ci pm_runtime_get_noresume(&pdev->dev); 66062306a36Sopenharmony_ci pm_runtime_set_active(&pdev->dev); 66162306a36Sopenharmony_ci pm_runtime_enable(&pdev->dev); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci xgpio_save_regs(chip); 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci chip->irq = platform_get_irq_optional(pdev, 0); 66662306a36Sopenharmony_ci if (chip->irq <= 0) 66762306a36Sopenharmony_ci goto skip_irq; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci /* Disable per-channel interrupts */ 67062306a36Sopenharmony_ci xgpio_writereg(chip->regs + XGPIO_IPIER_OFFSET, 0); 67162306a36Sopenharmony_ci /* Clear any existing per-channel interrupts */ 67262306a36Sopenharmony_ci temp = xgpio_readreg(chip->regs + XGPIO_IPISR_OFFSET); 67362306a36Sopenharmony_ci xgpio_writereg(chip->regs + XGPIO_IPISR_OFFSET, temp); 67462306a36Sopenharmony_ci /* Enable global interrupts */ 67562306a36Sopenharmony_ci xgpio_writereg(chip->regs + XGPIO_GIER_OFFSET, XGPIO_GIER_IE); 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci girq = &chip->gc.irq; 67862306a36Sopenharmony_ci gpio_irq_chip_set_chip(girq, &xgpio_irq_chip); 67962306a36Sopenharmony_ci girq->parent_handler = xgpio_irqhandler; 68062306a36Sopenharmony_ci girq->num_parents = 1; 68162306a36Sopenharmony_ci girq->parents = devm_kcalloc(&pdev->dev, 1, 68262306a36Sopenharmony_ci sizeof(*girq->parents), 68362306a36Sopenharmony_ci GFP_KERNEL); 68462306a36Sopenharmony_ci if (!girq->parents) { 68562306a36Sopenharmony_ci status = -ENOMEM; 68662306a36Sopenharmony_ci goto err_pm_put; 68762306a36Sopenharmony_ci } 68862306a36Sopenharmony_ci girq->parents[0] = chip->irq; 68962306a36Sopenharmony_ci girq->default_type = IRQ_TYPE_NONE; 69062306a36Sopenharmony_ci girq->handler = handle_bad_irq; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ciskip_irq: 69362306a36Sopenharmony_ci status = devm_gpiochip_add_data(&pdev->dev, &chip->gc, chip); 69462306a36Sopenharmony_ci if (status) { 69562306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to add GPIO chip\n"); 69662306a36Sopenharmony_ci goto err_pm_put; 69762306a36Sopenharmony_ci } 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci pm_runtime_put(&pdev->dev); 70062306a36Sopenharmony_ci return 0; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_cierr_pm_put: 70362306a36Sopenharmony_ci pm_runtime_disable(&pdev->dev); 70462306a36Sopenharmony_ci pm_runtime_put_noidle(&pdev->dev); 70562306a36Sopenharmony_ci clk_disable_unprepare(chip->clk); 70662306a36Sopenharmony_ci return status; 70762306a36Sopenharmony_ci} 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_cistatic const struct of_device_id xgpio_of_match[] = { 71062306a36Sopenharmony_ci { .compatible = "xlnx,xps-gpio-1.00.a", }, 71162306a36Sopenharmony_ci { /* end of list */ }, 71262306a36Sopenharmony_ci}; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, xgpio_of_match); 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_cistatic struct platform_driver xgpio_plat_driver = { 71762306a36Sopenharmony_ci .probe = xgpio_probe, 71862306a36Sopenharmony_ci .remove = xgpio_remove, 71962306a36Sopenharmony_ci .driver = { 72062306a36Sopenharmony_ci .name = "gpio-xilinx", 72162306a36Sopenharmony_ci .of_match_table = xgpio_of_match, 72262306a36Sopenharmony_ci .pm = &xgpio_dev_pm_ops, 72362306a36Sopenharmony_ci }, 72462306a36Sopenharmony_ci}; 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_cistatic int __init xgpio_init(void) 72762306a36Sopenharmony_ci{ 72862306a36Sopenharmony_ci return platform_driver_register(&xgpio_plat_driver); 72962306a36Sopenharmony_ci} 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_cisubsys_initcall(xgpio_init); 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_cistatic void __exit xgpio_exit(void) 73462306a36Sopenharmony_ci{ 73562306a36Sopenharmony_ci platform_driver_unregister(&xgpio_plat_driver); 73662306a36Sopenharmony_ci} 73762306a36Sopenharmony_cimodule_exit(xgpio_exit); 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ciMODULE_AUTHOR("Xilinx, Inc."); 74062306a36Sopenharmony_ciMODULE_DESCRIPTION("Xilinx GPIO driver"); 74162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 742