19caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan/*
29caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan * Toumaz Xenif TZ1090 GPIO handling.
39caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan *
49caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan * Copyright (C) 2008-2013 Imagination Technologies Ltd.
59caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan *
69caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan *  Based on ARM PXA code and others.
79caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan *
89caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan * This program is free software; you can redistribute it and/or modify
99caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan * it under the terms of the GNU General Public License version 2 as
109caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan * published by the Free Software Foundation.
119caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan */
129caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
139caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan#include <linux/bitops.h>
149caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan#include <linux/export.h>
159caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan#include <linux/gpio.h>
169caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan#include <linux/interrupt.h>
179caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan#include <linux/io.h>
189caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan#include <linux/irq.h>
199caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan#include <linux/irqdomain.h>
209caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan#include <linux/kernel.h>
219caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan#include <linux/of_irq.h>
229caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan#include <linux/pinctrl/consumer.h>
239caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan#include <linux/platform_device.h>
249caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan#include <linux/slab.h>
259caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan#include <linux/syscore_ops.h>
269caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan#include <asm/global_lock.h>
279caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
289caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan/* Register offsets from bank base address */
299caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan#define REG_GPIO_DIR		0x00
309caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan#define REG_GPIO_IRQ_PLRT	0x20
319caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan#define REG_GPIO_IRQ_TYPE	0x30
329caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan#define REG_GPIO_IRQ_EN		0x40
339caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan#define REG_GPIO_IRQ_STS	0x50
349caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan#define REG_GPIO_BIT_EN		0x60
359caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan#define REG_GPIO_DIN		0x70
369caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan#define REG_GPIO_DOUT		0x80
379caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
389caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan/* REG_GPIO_IRQ_PLRT */
399caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan#define REG_GPIO_IRQ_PLRT_LOW	0
409caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan#define REG_GPIO_IRQ_PLRT_HIGH	1
419caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
429caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan/* REG_GPIO_IRQ_TYPE */
439caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan#define REG_GPIO_IRQ_TYPE_LEVEL	0
449caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan#define REG_GPIO_IRQ_TYPE_EDGE	1
459caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
469caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan/**
479caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan * struct tz1090_gpio_bank - GPIO bank private data
489caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan * @chip:	Generic GPIO chip for GPIO bank
499caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan * @domain:	IRQ domain for GPIO bank (may be NULL)
509caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan * @reg:	Base of registers, offset for this GPIO bank
519caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan * @irq:	IRQ number for GPIO bank
529caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan * @label:	Debug GPIO bank label, used for storage of chip->label
539caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan *
549caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan * This is the main private data for a GPIO bank. It encapsulates a gpio_chip,
559caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan * and the callbacks for the gpio_chip can access the private data with the
569caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan * to_bank() macro below.
579caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan */
589caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hoganstruct tz1090_gpio_bank {
599caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	struct gpio_chip chip;
609caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	struct irq_domain *domain;
619caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	void __iomem *reg;
629caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	int irq;
639caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	char label[16];
649caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan};
659caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan#define to_bank(c)	container_of(c, struct tz1090_gpio_bank, chip)
669caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
679caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan/**
689caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan * struct tz1090_gpio - Overall GPIO device private data
699caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan * @dev:	Device (from platform device)
709caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan * @reg:	Base of GPIO registers
719caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan *
729caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan * Represents the overall GPIO device. This structure is actually only
739caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan * temporary, and used during init.
749caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan */
759caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hoganstruct tz1090_gpio {
769caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	struct device *dev;
779caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	void __iomem *reg;
789caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan};
799caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
809caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan/**
819caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan * struct tz1090_gpio_bank_info - Temporary registration info for GPIO bank
829caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan * @priv:	Overall GPIO device private data
839caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan * @node:	Device tree node specific to this GPIO bank
849caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan * @index:	Index of bank in range 0-2
859caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan */
869caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hoganstruct tz1090_gpio_bank_info {
879caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	struct tz1090_gpio *priv;
889caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	struct device_node *node;
899caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	unsigned int index;
909caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan};
919caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
929caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan/* Convenience register accessors */
939caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hoganstatic inline void tz1090_gpio_write(struct tz1090_gpio_bank *bank,
949caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan			      unsigned int reg_offs, u32 data)
959caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan{
969caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	iowrite32(data, bank->reg + reg_offs);
979caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan}
989caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
999caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hoganstatic inline u32 tz1090_gpio_read(struct tz1090_gpio_bank *bank,
1009caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan			    unsigned int reg_offs)
1019caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan{
1029caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	return ioread32(bank->reg + reg_offs);
1039caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan}
1049caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
1059caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan/* caller must hold LOCK2 */
1069caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hoganstatic inline void _tz1090_gpio_clear_bit(struct tz1090_gpio_bank *bank,
1079caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan					  unsigned int reg_offs,
1089caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan					  unsigned int offset)
1099caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan{
1109caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	u32 value;
1119caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
1129caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	value = tz1090_gpio_read(bank, reg_offs);
1139caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	value &= ~BIT(offset);
1149caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	tz1090_gpio_write(bank, reg_offs, value);
1159caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan}
1169caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
1179caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hoganstatic void tz1090_gpio_clear_bit(struct tz1090_gpio_bank *bank,
1189caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan				  unsigned int reg_offs,
1199caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan				  unsigned int offset)
1209caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan{
1219caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	int lstat;
1229caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
1239caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	__global_lock2(lstat);
1249caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	_tz1090_gpio_clear_bit(bank, reg_offs, offset);
1259caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	__global_unlock2(lstat);
1269caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan}
1279caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
1289caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan/* caller must hold LOCK2 */
1299caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hoganstatic inline void _tz1090_gpio_set_bit(struct tz1090_gpio_bank *bank,
1309caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan					unsigned int reg_offs,
1319caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan					unsigned int offset)
1329caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan{
1339caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	u32 value;
1349caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
1359caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	value = tz1090_gpio_read(bank, reg_offs);
1369caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	value |= BIT(offset);
1379caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	tz1090_gpio_write(bank, reg_offs, value);
1389caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan}
1399caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
1409caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hoganstatic void tz1090_gpio_set_bit(struct tz1090_gpio_bank *bank,
1419caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan				unsigned int reg_offs,
1429caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan				unsigned int offset)
1439caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan{
1449caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	int lstat;
1459caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
1469caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	__global_lock2(lstat);
1479caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	_tz1090_gpio_set_bit(bank, reg_offs, offset);
1489caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	__global_unlock2(lstat);
1499caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan}
1509caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
1519caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan/* caller must hold LOCK2 */
1529caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hoganstatic inline void _tz1090_gpio_mod_bit(struct tz1090_gpio_bank *bank,
1539caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan					unsigned int reg_offs,
1549caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan					unsigned int offset,
1559caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan					bool val)
1569caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan{
1579caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	u32 value;
1589caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
1599caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	value = tz1090_gpio_read(bank, reg_offs);
1609caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	value &= ~BIT(offset);
1619caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	if (val)
1629caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		value |= BIT(offset);
1639caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	tz1090_gpio_write(bank, reg_offs, value);
1649caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan}
1659caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
1669caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hoganstatic void tz1090_gpio_mod_bit(struct tz1090_gpio_bank *bank,
1679caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan				unsigned int reg_offs,
1689caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan				unsigned int offset,
1699caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan				bool val)
1709caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan{
1719caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	int lstat;
1729caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
1739caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	__global_lock2(lstat);
1749caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	_tz1090_gpio_mod_bit(bank, reg_offs, offset, val);
1759caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	__global_unlock2(lstat);
1769caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan}
1779caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
1789caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hoganstatic inline int tz1090_gpio_read_bit(struct tz1090_gpio_bank *bank,
1799caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan				       unsigned int reg_offs,
1809caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan				       unsigned int offset)
1819caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan{
1829caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	return tz1090_gpio_read(bank, reg_offs) & BIT(offset);
1839caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan}
1849caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
1859caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan/* GPIO chip callbacks */
1869caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
1879caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hoganstatic int tz1090_gpio_direction_input(struct gpio_chip *chip,
1889caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan				       unsigned int offset)
1899caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan{
1909caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	struct tz1090_gpio_bank *bank = to_bank(chip);
1919caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	tz1090_gpio_set_bit(bank, REG_GPIO_DIR, offset);
1929caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
1939caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	return 0;
1949caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan}
1959caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
1969caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hoganstatic int tz1090_gpio_direction_output(struct gpio_chip *chip,
1979caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan					unsigned int offset, int output_value)
1989caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan{
1999caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	struct tz1090_gpio_bank *bank = to_bank(chip);
2009caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	int lstat;
2019caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
2029caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	__global_lock2(lstat);
2039caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	_tz1090_gpio_mod_bit(bank, REG_GPIO_DOUT, offset, output_value);
2049caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	_tz1090_gpio_clear_bit(bank, REG_GPIO_DIR, offset);
2059caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	__global_unlock2(lstat);
2069caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
2079caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	return 0;
2089caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan}
2099caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
2109caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan/*
2119caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan * Return GPIO level
2129caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan */
2139caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hoganstatic int tz1090_gpio_get(struct gpio_chip *chip, unsigned int offset)
2149caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan{
2159caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	struct tz1090_gpio_bank *bank = to_bank(chip);
2169caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
2179caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	return tz1090_gpio_read_bit(bank, REG_GPIO_DIN, offset);
2189caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan}
2199caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
2209caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan/*
2219caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan * Set output GPIO level
2229caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan */
2239caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hoganstatic void tz1090_gpio_set(struct gpio_chip *chip, unsigned int offset,
2249caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan			    int output_value)
2259caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan{
2269caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	struct tz1090_gpio_bank *bank = to_bank(chip);
2279caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
2289caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	tz1090_gpio_mod_bit(bank, REG_GPIO_DOUT, offset, output_value);
2299caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan}
2309caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
2319caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hoganstatic int tz1090_gpio_request(struct gpio_chip *chip, unsigned int offset)
2329caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan{
2339caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	struct tz1090_gpio_bank *bank = to_bank(chip);
2349caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	int ret;
2359caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
2369caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	ret = pinctrl_request_gpio(chip->base + offset);
2379caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	if (ret)
2389caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		return ret;
2399caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
2409caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	tz1090_gpio_set_bit(bank, REG_GPIO_DIR, offset);
2419caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	tz1090_gpio_set_bit(bank, REG_GPIO_BIT_EN, offset);
2429caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
2439caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	return 0;
2449caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan}
2459caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
2469caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hoganstatic void tz1090_gpio_free(struct gpio_chip *chip, unsigned int offset)
2479caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan{
2489caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	struct tz1090_gpio_bank *bank = to_bank(chip);
2499caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
2509caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	pinctrl_free_gpio(chip->base + offset);
2519caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
2529caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	tz1090_gpio_clear_bit(bank, REG_GPIO_BIT_EN, offset);
2539caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan}
2549caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
2559caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hoganstatic int tz1090_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
2569caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan{
2579caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	struct tz1090_gpio_bank *bank = to_bank(chip);
2589caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
2599caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	if (!bank->domain)
2609caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		return -EINVAL;
2619caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
2629caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	return irq_create_mapping(bank->domain, offset);
2639caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan}
2649caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
2659caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan/* IRQ chip handlers */
2669caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
2679caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan/* Get TZ1090 GPIO chip from irq data provided to generic IRQ callbacks */
2689caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hoganstatic inline struct tz1090_gpio_bank *irqd_to_gpio_bank(struct irq_data *data)
2699caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan{
2709caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	return (struct tz1090_gpio_bank *)data->domain->host_data;
2719caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan}
2729caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
2739caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hoganstatic void tz1090_gpio_irq_polarity(struct tz1090_gpio_bank *bank,
2749caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan				     unsigned int offset, unsigned int polarity)
2759caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan{
2769caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	tz1090_gpio_mod_bit(bank, REG_GPIO_IRQ_PLRT, offset, polarity);
2779caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan}
2789caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
2799caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hoganstatic void tz1090_gpio_irq_type(struct tz1090_gpio_bank *bank,
2809caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan				 unsigned int offset, unsigned int type)
2819caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan{
2829caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	tz1090_gpio_mod_bit(bank, REG_GPIO_IRQ_TYPE, offset, type);
2839caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan}
2849caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
2859caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan/* set polarity to trigger on next edge, whether rising or falling */
2869caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hoganstatic void tz1090_gpio_irq_next_edge(struct tz1090_gpio_bank *bank,
2879caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan				      unsigned int offset)
2889caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan{
2899caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	unsigned int value_p, value_i;
2909caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	int lstat;
2919caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
2929caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	/*
2939caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	 * Set the GPIO's interrupt polarity to the opposite of the current
2949caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	 * input value so that the next edge triggers an interrupt.
2959caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	 */
2969caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	__global_lock2(lstat);
2979caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	value_i = ~tz1090_gpio_read(bank, REG_GPIO_DIN);
2989caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	value_p = tz1090_gpio_read(bank, REG_GPIO_IRQ_PLRT);
2999caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	value_p &= ~BIT(offset);
3009caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	value_p |= value_i & BIT(offset);
3019caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	tz1090_gpio_write(bank, REG_GPIO_IRQ_PLRT, value_p);
3029caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	__global_unlock2(lstat);
3039caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan}
3049caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
3059caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hoganstatic unsigned int gpio_startup_irq(struct irq_data *data)
3069caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan{
3079caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	/*
3089caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	 * This warning indicates that the type of the irq hasn't been set
3099caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	 * before enabling the irq. This would normally be done by passing some
3109caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	 * trigger flags to request_irq().
3119caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	 */
31204777396d8d183f3f3edd3872eb8bf50dd458b82James Hogan	WARN(irqd_get_trigger_type(data) == IRQ_TYPE_NONE,
3139caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		"irq type not set before enabling gpio irq %d", data->irq);
3149caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
31504777396d8d183f3f3edd3872eb8bf50dd458b82James Hogan	irq_gc_ack_clr_bit(data);
31604777396d8d183f3f3edd3872eb8bf50dd458b82James Hogan	irq_gc_mask_set_bit(data);
3179caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	return 0;
3189caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan}
3199caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
3209caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hoganstatic int gpio_set_irq_type(struct irq_data *data, unsigned int flow_type)
3219caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan{
3229caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	struct tz1090_gpio_bank *bank = irqd_to_gpio_bank(data);
3239caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	unsigned int type;
3249caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	unsigned int polarity;
3259caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
3269caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	switch (flow_type) {
3279caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	case IRQ_TYPE_EDGE_BOTH:
3289caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		type = REG_GPIO_IRQ_TYPE_EDGE;
3299caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		polarity = REG_GPIO_IRQ_PLRT_LOW;
3309caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		break;
3319caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	case IRQ_TYPE_EDGE_RISING:
3329caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		type = REG_GPIO_IRQ_TYPE_EDGE;
3339caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		polarity = REG_GPIO_IRQ_PLRT_HIGH;
3349caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		break;
3359caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	case IRQ_TYPE_EDGE_FALLING:
3369caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		type = REG_GPIO_IRQ_TYPE_EDGE;
3379caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		polarity = REG_GPIO_IRQ_PLRT_LOW;
3389caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		break;
3399caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	case IRQ_TYPE_LEVEL_HIGH:
3409caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		type = REG_GPIO_IRQ_TYPE_LEVEL;
3419caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		polarity = REG_GPIO_IRQ_PLRT_HIGH;
3429caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		break;
3439caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	case IRQ_TYPE_LEVEL_LOW:
3449caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		type = REG_GPIO_IRQ_TYPE_LEVEL;
3459caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		polarity = REG_GPIO_IRQ_PLRT_LOW;
3469caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		break;
3479caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	default:
3489caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		return -EINVAL;
3499caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	}
3509caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
3519caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	tz1090_gpio_irq_type(bank, data->hwirq, type);
35204777396d8d183f3f3edd3872eb8bf50dd458b82James Hogan	irq_setup_alt_chip(data, flow_type);
3539caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
3549caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	if (flow_type == IRQ_TYPE_EDGE_BOTH)
3559caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		tz1090_gpio_irq_next_edge(bank, data->hwirq);
3569caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	else
3579caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		tz1090_gpio_irq_polarity(bank, data->hwirq, polarity);
3589caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
3599caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	return 0;
3609caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan}
3619caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
3629caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan#ifdef CONFIG_SUSPEND
3639caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hoganstatic int gpio_set_irq_wake(struct irq_data *data, unsigned int on)
3649caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan{
3659caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	struct tz1090_gpio_bank *bank = irqd_to_gpio_bank(data);
3669caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
3679caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan#ifdef CONFIG_PM_DEBUG
3689caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	pr_info("irq_wake irq%d state:%d\n", data->irq, on);
3699caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan#endif
3709caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
3719caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	/* wake on gpio block interrupt */
3729caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	return irq_set_irq_wake(bank->irq, on);
3739caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan}
3749caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan#else
3759caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan#define gpio_set_irq_wake NULL
3769caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan#endif
3779caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
3789caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hoganstatic void tz1090_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
3799caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan{
3809caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	irq_hw_number_t hw;
3819caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	unsigned int irq_stat, irq_no;
3829caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	struct tz1090_gpio_bank *bank;
3839caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	struct irq_desc *child_desc;
3849caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
3859caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	bank = (struct tz1090_gpio_bank *)irq_desc_get_handler_data(desc);
3869caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	irq_stat = tz1090_gpio_read(bank, REG_GPIO_DIR) &
3879caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		   tz1090_gpio_read(bank, REG_GPIO_IRQ_STS) &
3889caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		   tz1090_gpio_read(bank, REG_GPIO_IRQ_EN) &
3899caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		   0x3FFFFFFF; /* 30 bits only */
3909caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
3919caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	for (hw = 0; irq_stat; irq_stat >>= 1, ++hw) {
3929caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		if (!(irq_stat & 1))
3939caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan			continue;
3949caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
3959caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		irq_no = irq_linear_revmap(bank->domain, hw);
3969caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		child_desc = irq_to_desc(irq_no);
3979caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
3989caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		/* Toggle edge for pin with both edges triggering enabled */
3999caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		if (irqd_get_trigger_type(&child_desc->irq_data)
4009caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan				== IRQ_TYPE_EDGE_BOTH)
4019caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan			tz1090_gpio_irq_next_edge(bank, hw);
4029caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
4039caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		generic_handle_irq_desc(irq_no, child_desc);
4049caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	}
4059caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan}
4069caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
4079caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hoganstatic int tz1090_gpio_bank_probe(struct tz1090_gpio_bank_info *info)
4089caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan{
4099caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	struct device_node *np = info->node;
4109caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	struct device *dev = info->priv->dev;
4119caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	struct tz1090_gpio_bank *bank;
41204777396d8d183f3f3edd3872eb8bf50dd458b82James Hogan	struct irq_chip_generic *gc;
41304777396d8d183f3f3edd3872eb8bf50dd458b82James Hogan	int err;
4149caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
4159caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	bank = devm_kzalloc(dev, sizeof(*bank), GFP_KERNEL);
4169caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	if (!bank) {
4179caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		dev_err(dev, "unable to allocate driver data\n");
4189caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		return -ENOMEM;
4199caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	}
4209caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
4219caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	/* Offset the main registers to the first register in this bank */
4229caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	bank->reg = info->priv->reg + info->index * 4;
4239caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
4249caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	/* Set up GPIO chip */
4259caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	snprintf(bank->label, sizeof(bank->label), "tz1090-gpio-%u",
4269caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		 info->index);
4279caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	bank->chip.label		= bank->label;
4289caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	bank->chip.dev			= dev;
4299caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	bank->chip.direction_input	= tz1090_gpio_direction_input;
4309caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	bank->chip.direction_output	= tz1090_gpio_direction_output;
4319caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	bank->chip.get			= tz1090_gpio_get;
4329caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	bank->chip.set			= tz1090_gpio_set;
4339caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	bank->chip.free			= tz1090_gpio_free;
4349caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	bank->chip.request		= tz1090_gpio_request;
4359caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	bank->chip.to_irq		= tz1090_gpio_to_irq;
4369caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	bank->chip.of_node		= np;
4379caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
4389caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	/* GPIO numbering from 0 */
4399caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	bank->chip.base			= info->index * 30;
4409caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	bank->chip.ngpio		= 30;
4419caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
4429caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	/* Add the GPIO bank */
4439caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	gpiochip_add(&bank->chip);
4449caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
4459caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	/* Get the GPIO bank IRQ if provided */
4469caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	bank->irq = irq_of_parse_and_map(np, 0);
4479caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
4489caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	/* The interrupt is optional (it may be used by another core on chip) */
4499caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	if (bank->irq < 0) {
4509caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		dev_info(dev, "IRQ not provided for bank %u, IRQs disabled\n",
4519caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan			 info->index);
4529caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		return 0;
4539caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	}
4549caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
4559caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	dev_info(dev, "Setting up IRQs for GPIO bank %u\n",
4569caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		 info->index);
4579caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
4589caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	/*
4599caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	 * Initialise all interrupts to disabled so we don't get
4609caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	 * spurious ones on a dirty boot and hit the BUG_ON in the
4619caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	 * handler.
4629caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	 */
4639caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	tz1090_gpio_write(bank, REG_GPIO_IRQ_EN, 0);
4649caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
4659caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	/* Add a virtual IRQ for each GPIO */
4669caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	bank->domain = irq_domain_add_linear(np,
4679caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan					     bank->chip.ngpio,
46804777396d8d183f3f3edd3872eb8bf50dd458b82James Hogan					     &irq_generic_chip_ops,
4699caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan					     bank);
4709caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
47104777396d8d183f3f3edd3872eb8bf50dd458b82James Hogan	/* Set up a generic irq chip with 2 chip types (level and edge) */
47204777396d8d183f3f3edd3872eb8bf50dd458b82James Hogan	err = irq_alloc_domain_generic_chips(bank->domain, bank->chip.ngpio, 2,
47304777396d8d183f3f3edd3872eb8bf50dd458b82James Hogan					     bank->label, handle_bad_irq, 0, 0,
47404777396d8d183f3f3edd3872eb8bf50dd458b82James Hogan					     IRQ_GC_INIT_NESTED_LOCK);
47504777396d8d183f3f3edd3872eb8bf50dd458b82James Hogan	if (err) {
47604777396d8d183f3f3edd3872eb8bf50dd458b82James Hogan		dev_info(dev,
47704777396d8d183f3f3edd3872eb8bf50dd458b82James Hogan			 "irq_alloc_domain_generic_chips failed for bank %u, IRQs disabled\n",
47804777396d8d183f3f3edd3872eb8bf50dd458b82James Hogan			 info->index);
47904777396d8d183f3f3edd3872eb8bf50dd458b82James Hogan		irq_domain_remove(bank->domain);
48004777396d8d183f3f3edd3872eb8bf50dd458b82James Hogan		return 0;
48104777396d8d183f3f3edd3872eb8bf50dd458b82James Hogan	}
48204777396d8d183f3f3edd3872eb8bf50dd458b82James Hogan
48304777396d8d183f3f3edd3872eb8bf50dd458b82James Hogan	gc = irq_get_domain_generic_chip(bank->domain, 0);
48404777396d8d183f3f3edd3872eb8bf50dd458b82James Hogan	gc->reg_base	= bank->reg;
48504777396d8d183f3f3edd3872eb8bf50dd458b82James Hogan
48604777396d8d183f3f3edd3872eb8bf50dd458b82James Hogan	/* level chip type */
48704777396d8d183f3f3edd3872eb8bf50dd458b82James Hogan	gc->chip_types[0].type			= IRQ_TYPE_LEVEL_MASK;
48804777396d8d183f3f3edd3872eb8bf50dd458b82James Hogan	gc->chip_types[0].handler		= handle_level_irq;
48904777396d8d183f3f3edd3872eb8bf50dd458b82James Hogan	gc->chip_types[0].regs.ack		= REG_GPIO_IRQ_STS;
49004777396d8d183f3f3edd3872eb8bf50dd458b82James Hogan	gc->chip_types[0].regs.mask		= REG_GPIO_IRQ_EN;
491d3e144532703fe2454b56eddb56f30d2d620187bJames Hogan	gc->chip_types[0].chip.irq_startup	= gpio_startup_irq;
492d3e144532703fe2454b56eddb56f30d2d620187bJames Hogan	gc->chip_types[0].chip.irq_ack		= irq_gc_ack_clr_bit;
493d3e144532703fe2454b56eddb56f30d2d620187bJames Hogan	gc->chip_types[0].chip.irq_mask		= irq_gc_mask_clr_bit;
494d3e144532703fe2454b56eddb56f30d2d620187bJames Hogan	gc->chip_types[0].chip.irq_unmask	= irq_gc_mask_set_bit;
495d3e144532703fe2454b56eddb56f30d2d620187bJames Hogan	gc->chip_types[0].chip.irq_set_type	= gpio_set_irq_type;
496d3e144532703fe2454b56eddb56f30d2d620187bJames Hogan	gc->chip_types[0].chip.irq_set_wake	= gpio_set_irq_wake;
497d3e144532703fe2454b56eddb56f30d2d620187bJames Hogan	gc->chip_types[0].chip.flags		= IRQCHIP_MASK_ON_SUSPEND;
49804777396d8d183f3f3edd3872eb8bf50dd458b82James Hogan
49904777396d8d183f3f3edd3872eb8bf50dd458b82James Hogan	/* edge chip type */
50004777396d8d183f3f3edd3872eb8bf50dd458b82James Hogan	gc->chip_types[1].type			= IRQ_TYPE_EDGE_BOTH;
50104777396d8d183f3f3edd3872eb8bf50dd458b82James Hogan	gc->chip_types[1].handler		= handle_edge_irq;
50204777396d8d183f3f3edd3872eb8bf50dd458b82James Hogan	gc->chip_types[1].regs.ack		= REG_GPIO_IRQ_STS;
50304777396d8d183f3f3edd3872eb8bf50dd458b82James Hogan	gc->chip_types[1].regs.mask		= REG_GPIO_IRQ_EN;
504d3e144532703fe2454b56eddb56f30d2d620187bJames Hogan	gc->chip_types[1].chip.irq_startup	= gpio_startup_irq;
505d3e144532703fe2454b56eddb56f30d2d620187bJames Hogan	gc->chip_types[1].chip.irq_ack		= irq_gc_ack_clr_bit;
506d3e144532703fe2454b56eddb56f30d2d620187bJames Hogan	gc->chip_types[1].chip.irq_mask		= irq_gc_mask_clr_bit;
507d3e144532703fe2454b56eddb56f30d2d620187bJames Hogan	gc->chip_types[1].chip.irq_unmask	= irq_gc_mask_set_bit;
508d3e144532703fe2454b56eddb56f30d2d620187bJames Hogan	gc->chip_types[1].chip.irq_set_type	= gpio_set_irq_type;
509d3e144532703fe2454b56eddb56f30d2d620187bJames Hogan	gc->chip_types[1].chip.irq_set_wake	= gpio_set_irq_wake;
510d3e144532703fe2454b56eddb56f30d2d620187bJames Hogan	gc->chip_types[1].chip.flags		= IRQCHIP_MASK_ON_SUSPEND;
51104777396d8d183f3f3edd3872eb8bf50dd458b82James Hogan
5129caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	/* Setup chained handler for this GPIO bank */
5139caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	irq_set_handler_data(bank->irq, bank);
5149caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	irq_set_chained_handler(bank->irq, tz1090_gpio_irq_handler);
5159caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
5169caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	return 0;
5179caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan}
5189caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
5199caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hoganstatic void tz1090_gpio_register_banks(struct tz1090_gpio *priv)
5209caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan{
5219caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	struct device_node *np = priv->dev->of_node;
5229caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	struct device_node *node;
5239caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
5249caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	for_each_available_child_of_node(np, node) {
5259caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		struct tz1090_gpio_bank_info info;
5269caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		u32 addr;
5279caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		int ret;
5289caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
5299caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		ret = of_property_read_u32(node, "reg", &addr);
5309caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		if (ret) {
5319caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan			dev_err(priv->dev, "invalid reg on %s\n",
5329caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan				node->full_name);
5339caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan			continue;
5349caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		}
5359caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		if (addr >= 3) {
5369caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan			dev_err(priv->dev, "index %u in %s out of range\n",
5379caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan				addr, node->full_name);
5389caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan			continue;
5399caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		}
5409caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
5419caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		info.index = addr;
5429caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		info.node = of_node_get(node);
5439caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		info.priv = priv;
5449caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
5459caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		ret = tz1090_gpio_bank_probe(&info);
5469caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		if (ret) {
5479caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan			dev_err(priv->dev, "failure registering %s\n",
5489caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan				node->full_name);
5499caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan			of_node_put(node);
5509caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan			continue;
5519caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		}
5529caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	}
5539caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan}
5549caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
5559caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hoganstatic int tz1090_gpio_probe(struct platform_device *pdev)
5569caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan{
5579caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	struct device_node *np = pdev->dev.of_node;
5589caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	struct resource *res_regs;
5599caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	struct tz1090_gpio priv;
5609caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
5619caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	if (!np) {
5629caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		dev_err(&pdev->dev, "must be instantiated via devicetree\n");
5639caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		return -ENOENT;
5649caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	}
5659caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
5669caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	res_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
5679caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	if (!res_regs) {
5689caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		dev_err(&pdev->dev, "cannot find registers resource\n");
5699caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		return -ENOENT;
5709caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	}
5719caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
5729caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	priv.dev = &pdev->dev;
5739caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
5749caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	/* Ioremap the registers */
5759caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	priv.reg = devm_ioremap(&pdev->dev, res_regs->start,
5769caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan				 res_regs->end - res_regs->start);
5779caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	if (!priv.reg) {
5789caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		dev_err(&pdev->dev, "unable to ioremap registers\n");
5799caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		return -ENOMEM;
5809caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	}
5819caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
5829caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	/* Look for banks */
5839caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	tz1090_gpio_register_banks(&priv);
5849caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
5859caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	return 0;
5869caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan}
5879caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
5889caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hoganstatic struct of_device_id tz1090_gpio_of_match[] = {
5899caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	{ .compatible = "img,tz1090-gpio" },
5909caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	{ },
5919caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan};
5929caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
5939caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hoganstatic struct platform_driver tz1090_gpio_driver = {
5949caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	.driver = {
5959caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		.name		= "tz1090-gpio",
5969caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		.owner		= THIS_MODULE,
5979caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan		.of_match_table	= tz1090_gpio_of_match,
5989caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	},
5999caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	.probe		= tz1090_gpio_probe,
6009caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan};
6019caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan
6029caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hoganstatic int __init tz1090_gpio_init(void)
6039caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan{
6049caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan	return platform_driver_register(&tz1090_gpio_driver);
6059caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogan}
6069caf1f2202da2affedf0c9e3c1ccda8ea6d353e1James Hogansubsys_initcall(tz1090_gpio_init);
607