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