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