pinctrl-adi2.c revision b81e57e6ac35242ba59206b303ba6c7585764ee1
1e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang/* 2e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * Pinctrl Driver for ADI GPIO2 controller 3e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * 4e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * Copyright 2007-2013 Analog Devices Inc. 5e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * 6e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * Licensed under the GPLv2 or later 7e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang */ 8e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 9e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#include <linux/bitops.h> 10e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#include <linux/delay.h> 11e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#include <linux/module.h> 12e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#include <linux/err.h> 13e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#include <linux/debugfs.h> 14e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#include <linux/seq_file.h> 15e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#include <linux/irq.h> 16e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#include <linux/platform_data/pinctrl-adi2.h> 17e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#include <linux/irqdomain.h> 18e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#include <linux/irqchip/chained_irq.h> 19e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#include <linux/pinctrl/pinctrl.h> 20e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#include <linux/pinctrl/pinmux.h> 21e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#include <linux/pinctrl/consumer.h> 22e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#include <linux/pinctrl/machine.h> 23e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#include <linux/syscore_ops.h> 24e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#include <linux/gpio.h> 25e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#include <asm/portmux.h> 26e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#include "pinctrl-adi2.h" 27e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#include "core.h" 28e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 29e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang/* 30e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic ZhangAccording to the BF54x HRM, pint means "pin interrupt". 31e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhanghttp://www.analog.com/static/imported-files/processor_manuals/ADSP-BF54x_hwr_rev1.2.pdf 32e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 33e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic ZhangADSP-BF54x processor Blackfin processors have four SIC interrupt chan- 34e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangnels dedicated to pin interrupt purposes. These channels are managed by 35e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangfour hardware blocks, called PINT0, PINT1, PINT2, and PINT3. Every PINTx 36e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangblock can sense to up to 32 pins. While PINT0 and PINT1 can sense the 37e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangpins of port A and port B, PINT2 and PINT3 manage all the pins from port 38e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic ZhangC to port J as shown in Figure 9-2. 39e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 40e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangn BF54x HRM: 41e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic ZhangThe ten GPIO ports are subdivided into 8-bit half ports, resulting in lower and 42e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangupper half 8-bit units. The PINTx_ASSIGN registers control the 8-bit multi- 43e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangplexers shown in Figure 9-3. Lower half units of eight pins can be 44e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangforwarded to either byte 0 or byte 2 of either associated PINTx block. 45e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic ZhangUpper half units can be forwarded to either byte 1 or byte 3 of the pin 46e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhanginterrupt blocks, without further restrictions. 47e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 48e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic ZhangAll MMR registers in the pin interrupt module are 32 bits wide. To simply the 49e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangmapping logic, this driver only maps a 16-bit gpio port to the upper or lower 50e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang16 bits of a PINTx block. You can find the Figure 9-3 on page 583. 51e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 52e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic ZhangEach IRQ domain is binding to a GPIO bank device. 2 GPIO bank devices can map 53e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangto one PINT device. Two in "struct gpio_pint" are used to ease the PINT 54e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhanginterrupt handler. 55e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 56e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic ZhangThe GPIO bank mapping to the lower 16 bits of the PINT device set its IRQ 57e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangdomain pointer in domain[0]. The IRQ domain pointer of the other bank is set 58e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangto domain[1]. PINT interrupt handler adi_gpio_handle_pint_irq() finds out 59e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangthe current domain pointer according to whether the interrupt request mask 60e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangis in lower 16 bits (domain[0]) or upper 16bits (domain[1]). 61e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 62e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic ZhangA PINT device is not part of a GPIO port device in Blackfin. Multiple GPIO 63e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangport devices can be mapped to the same PINT device. 64e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 65e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang*/ 66e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 67e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic LIST_HEAD(adi_pint_list); 68e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic LIST_HEAD(adi_gpio_port_list); 69e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 70e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#define DRIVER_NAME "pinctrl-adi2" 71e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 72e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#define PINT_HI_OFFSET 16 73e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 74e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang/** 75e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * struct gpio_port_saved - GPIO port registers that should be saved between 76e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * power suspend and resume operations. 77e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * 78e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @fer: PORTx_FER register 79e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @data: PORTx_DATA register 80e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @dir: PORTx_DIR register 81e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @inen: PORTx_INEN register 82e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @mux: PORTx_MUX register 83e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang */ 84e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstruct gpio_port_saved { 85e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang u16 fer; 86e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang u16 data; 87e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang u16 dir; 88e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang u16 inen; 89e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang u32 mux; 90e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}; 91e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 921e6f8e3c92fbbcd5bcca860c4db4eef2052aa79fSonic Zhang/* 931e6f8e3c92fbbcd5bcca860c4db4eef2052aa79fSonic Zhang * struct gpio_pint_saved - PINT registers saved in PM operations 941e6f8e3c92fbbcd5bcca860c4db4eef2052aa79fSonic Zhang * 951e6f8e3c92fbbcd5bcca860c4db4eef2052aa79fSonic Zhang * @assign: ASSIGN register 961e6f8e3c92fbbcd5bcca860c4db4eef2052aa79fSonic Zhang * @edge_set: EDGE_SET register 971e6f8e3c92fbbcd5bcca860c4db4eef2052aa79fSonic Zhang * @invert_set: INVERT_SET register 981e6f8e3c92fbbcd5bcca860c4db4eef2052aa79fSonic Zhang */ 991e6f8e3c92fbbcd5bcca860c4db4eef2052aa79fSonic Zhangstruct gpio_pint_saved { 1001e6f8e3c92fbbcd5bcca860c4db4eef2052aa79fSonic Zhang u32 assign; 1011e6f8e3c92fbbcd5bcca860c4db4eef2052aa79fSonic Zhang u32 edge_set; 1021e6f8e3c92fbbcd5bcca860c4db4eef2052aa79fSonic Zhang u32 invert_set; 1031e6f8e3c92fbbcd5bcca860c4db4eef2052aa79fSonic Zhang}; 1041e6f8e3c92fbbcd5bcca860c4db4eef2052aa79fSonic Zhang 105e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang/** 106e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * struct gpio_pint - Pin interrupt controller device. Multiple ADI GPIO 107e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * banks can be mapped into one Pin interrupt controller. 108e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * 109e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @node: All gpio_pint instances are added to a global list. 110e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @base: PINT device register base address 111e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @irq: IRQ of the PINT device, it is the parent IRQ of all 112e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * GPIO IRQs mapping to this device. 113e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @domain: [0] irq domain of the gpio port, whose hardware interrupts are 114e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * mapping to the low 16-bit of the pint registers. 115e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * [1] irq domain of the gpio port, whose hardware interrupts are 116e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * mapping to the high 16-bit of the pint registers. 117e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @regs: address pointer to the PINT device 118e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @map_count: No more than 2 GPIO banks can be mapped to this PINT device. 119e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @lock: This lock make sure the irq_chip operations to one PINT device 120e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * for different GPIO interrrupts are atomic. 121e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @pint_map_port: Set up the mapping between one PINT device and 122e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * multiple GPIO banks. 123e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang */ 124e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstruct gpio_pint { 125e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct list_head node; 126e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang void __iomem *base; 127e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang int irq; 128e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct irq_domain *domain[2]; 129e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_pint_regs *regs; 1301e6f8e3c92fbbcd5bcca860c4db4eef2052aa79fSonic Zhang struct gpio_pint_saved saved_data; 131e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang int map_count; 132e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang spinlock_t lock; 133e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 134e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang int (*pint_map_port)(struct gpio_pint *pint, bool assign, 135e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang u8 map, struct irq_domain *domain); 136e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}; 137e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 138e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang/** 139e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * ADI pin controller 140e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * 141e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @dev: a pointer back to containing device 142e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @pctl: the pinctrl device 143e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @soc: SoC data for this specific chip 144e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang */ 145e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstruct adi_pinctrl { 146e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct device *dev; 147e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct pinctrl_dev *pctl; 148e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang const struct adi_pinctrl_soc_data *soc; 149e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}; 150e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 151e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang/** 152e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * struct gpio_port - GPIO bank device. Multiple ADI GPIO banks can be mapped 153e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * into one pin interrupt controller. 154e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * 155e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @node: All gpio_port instances are added to a list. 156e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @base: GPIO bank device register base address 157e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @irq_base: base IRQ of the GPIO bank device 158e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @width: PIN number of the GPIO bank device 159e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @regs: address pointer to the GPIO bank device 160e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @saved_data: registers that should be saved between PM operations. 161e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @dev: device structure of this GPIO bank 162e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @pint: GPIO PINT device that this GPIO bank mapped to 163e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @pint_map: GIOP bank mapping code in PINT device 164e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @pint_assign: The 32-bit PINT registers can be divided into 2 parts. A 165e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * GPIO bank can be mapped into either low 16 bits[0] or high 16 166e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * bits[1] of each PINT register. 167e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @lock: This lock make sure the irq_chip operations to one PINT device 168e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * for different GPIO interrrupts are atomic. 169e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @chip: abstract a GPIO controller 170e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @domain: The irq domain owned by the GPIO port. 171e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @rsvmap: Reservation map array for each pin in the GPIO bank 172e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang */ 173e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstruct gpio_port { 174e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct list_head node; 175e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang void __iomem *base; 176b4eef7b22544d46d918696253e9086975dc6f8b0Sonic Zhang int irq_base; 177e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang unsigned int width; 178e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_port_t *regs; 179e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_port_saved saved_data; 180e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct device *dev; 181e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 182e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_pint *pint; 183e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang u8 pint_map; 184e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang bool pint_assign; 185e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 186e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang spinlock_t lock; 187e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_chip chip; 188e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct irq_domain *domain; 189e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}; 190e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 191e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic inline u8 pin_to_offset(struct pinctrl_gpio_range *range, unsigned pin) 192e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 193e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return pin - range->pin_base; 194e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 195e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 196e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic inline u32 hwirq_to_pintbit(struct gpio_port *port, int hwirq) 197e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 198e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return port->pint_assign ? BIT(hwirq) << PINT_HI_OFFSET : BIT(hwirq); 199e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 200e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 201e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic struct gpio_pint *find_gpio_pint(unsigned id) 202e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 203e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_pint *pint; 204e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang int i = 0; 205e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 206e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang list_for_each_entry(pint, &adi_pint_list, node) { 207e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (id == i) 208e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return pint; 209e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang i++; 210e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang } 211e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 212e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return NULL; 213e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 214e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 215e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic inline void port_setup(struct gpio_port *port, unsigned offset, 216e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang bool use_for_gpio) 217e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 218e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_port_t *regs = port->regs; 219e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 220e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (use_for_gpio) 221e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang writew(readw(®s->port_fer) & ~BIT(offset), 222e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang ®s->port_fer); 223e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang else 224e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang writew(readw(®s->port_fer) | BIT(offset), ®s->port_fer); 225e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 226e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 227e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic inline void portmux_setup(struct gpio_port *port, unsigned offset, 228e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang unsigned short function) 229e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 230e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_port_t *regs = port->regs; 231e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang u32 pmux; 232e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 233e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang pmux = readl(®s->port_mux); 234e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 235e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang /* The function field of each pin has 2 consecutive bits in 236e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * the mux register. 237e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang */ 238e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang pmux &= ~(0x3 << (2 * offset)); 239e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang pmux |= (function & 0x3) << (2 * offset); 240e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 241e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang writel(pmux, ®s->port_mux); 242e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 243e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 244e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic inline u16 get_portmux(struct gpio_port *port, unsigned offset) 245e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 246e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_port_t *regs = port->regs; 247e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang u32 pmux = readl(®s->port_mux); 248e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 249e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang /* The function field of each pin has 2 consecutive bits in 250e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * the mux register. 251e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang */ 252e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return pmux >> (2 * offset) & 0x3; 253e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 254e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 255e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic void adi_gpio_ack_irq(struct irq_data *d) 256e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 257e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang unsigned long flags; 258e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_port *port = irq_data_get_irq_chip_data(d); 259e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_pint_regs *regs = port->pint->regs; 260e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang unsigned pintbit = hwirq_to_pintbit(port, d->hwirq); 261e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 262e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang spin_lock_irqsave(&port->lock, flags); 263010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang spin_lock(&port->pint->lock); 264e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 265e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (irqd_get_trigger_type(d) == IRQ_TYPE_EDGE_BOTH) { 266e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (readl(®s->invert_set) & pintbit) 267e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang writel(pintbit, ®s->invert_clear); 268e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang else 269e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang writel(pintbit, ®s->invert_set); 270e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang } 271e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 272e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang writel(pintbit, ®s->request); 273e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 274010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang spin_unlock(&port->pint->lock); 275e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang spin_unlock_irqrestore(&port->lock, flags); 276e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 277e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 278e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic void adi_gpio_mask_ack_irq(struct irq_data *d) 279e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 280e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang unsigned long flags; 281e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_port *port = irq_data_get_irq_chip_data(d); 282e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_pint_regs *regs = port->pint->regs; 283e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang unsigned pintbit = hwirq_to_pintbit(port, d->hwirq); 284e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 285e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang spin_lock_irqsave(&port->lock, flags); 286010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang spin_lock(&port->pint->lock); 287e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 288e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (irqd_get_trigger_type(d) == IRQ_TYPE_EDGE_BOTH) { 289e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (readl(®s->invert_set) & pintbit) 290e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang writel(pintbit, ®s->invert_clear); 291e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang else 292e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang writel(pintbit, ®s->invert_set); 293e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang } 294e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 295e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang writel(pintbit, ®s->request); 296e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang writel(pintbit, ®s->mask_clear); 297e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 298010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang spin_unlock(&port->pint->lock); 299e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang spin_unlock_irqrestore(&port->lock, flags); 300e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 301e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 302e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic void adi_gpio_mask_irq(struct irq_data *d) 303e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 304e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang unsigned long flags; 305e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_port *port = irq_data_get_irq_chip_data(d); 306e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_pint_regs *regs = port->pint->regs; 307e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 308e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang spin_lock_irqsave(&port->lock, flags); 309010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang spin_lock(&port->pint->lock); 310e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 311e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang writel(hwirq_to_pintbit(port, d->hwirq), ®s->mask_clear); 312e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 313010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang spin_unlock(&port->pint->lock); 314e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang spin_unlock_irqrestore(&port->lock, flags); 315e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 316e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 317e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic void adi_gpio_unmask_irq(struct irq_data *d) 318e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 319e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang unsigned long flags; 320e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_port *port = irq_data_get_irq_chip_data(d); 321e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_pint_regs *regs = port->pint->regs; 322e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 323e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang spin_lock_irqsave(&port->lock, flags); 324010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang spin_lock(&port->pint->lock); 325e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 326e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang writel(hwirq_to_pintbit(port, d->hwirq), ®s->mask_set); 327e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 328010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang spin_unlock(&port->pint->lock); 329e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang spin_unlock_irqrestore(&port->lock, flags); 330e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 331e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 332e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic unsigned int adi_gpio_irq_startup(struct irq_data *d) 333e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 334e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang unsigned long flags; 335e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_port *port = irq_data_get_irq_chip_data(d); 336010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang struct gpio_pint_regs *regs; 337e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 338e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (!port) { 339010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang pr_err("GPIO IRQ %d :Not exist\n", d->irq); 340e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return -ENODEV; 341e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang } 342e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 343010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang regs = port->pint->regs; 344010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang 345e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang spin_lock_irqsave(&port->lock, flags); 346010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang spin_lock(&port->pint->lock); 347e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 348e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang port_setup(port, d->hwirq, true); 349e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang writew(BIT(d->hwirq), &port->regs->dir_clear); 350e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang writew(readw(&port->regs->inen) | BIT(d->hwirq), &port->regs->inen); 351e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 352e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang writel(hwirq_to_pintbit(port, d->hwirq), ®s->mask_set); 353e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 354010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang spin_unlock(&port->pint->lock); 355e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang spin_unlock_irqrestore(&port->lock, flags); 356e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 357e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return 0; 358e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 359e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 360e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic void adi_gpio_irq_shutdown(struct irq_data *d) 361e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 362e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang unsigned long flags; 363e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_port *port = irq_data_get_irq_chip_data(d); 364e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_pint_regs *regs = port->pint->regs; 365e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 366e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang spin_lock_irqsave(&port->lock, flags); 367010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang spin_lock(&port->pint->lock); 368e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 369e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang writel(hwirq_to_pintbit(port, d->hwirq), ®s->mask_clear); 370e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 371010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang spin_unlock(&port->pint->lock); 372e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang spin_unlock_irqrestore(&port->lock, flags); 373e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 374e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 375e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_gpio_irq_type(struct irq_data *d, unsigned int type) 376e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 377e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang unsigned long flags; 378e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_port *port = irq_data_get_irq_chip_data(d); 379010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang struct gpio_pint_regs *pint_regs; 380e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang unsigned pintmask; 381e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang unsigned int irq = d->irq; 382e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang int ret = 0; 383e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang char buf[16]; 384e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 385e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (!port) { 386010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang pr_err("GPIO IRQ %d :Not exist\n", d->irq); 387e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return -ENODEV; 388e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang } 389e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 390010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang pint_regs = port->pint->regs; 391010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang 392e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang pintmask = hwirq_to_pintbit(port, d->hwirq); 393e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 394e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang spin_lock_irqsave(&port->lock, flags); 395010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang spin_lock(&port->pint->lock); 396e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 397e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang /* In case of interrupt autodetect, set irq type to edge sensitive. */ 398e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (type == IRQ_TYPE_PROBE) 399e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; 400e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 401e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING | 402e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) { 403e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang snprintf(buf, 16, "gpio-irq%d", irq); 404e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang port_setup(port, d->hwirq, true); 405e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang } else 406e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang goto out; 407e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 408e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang /* The GPIO interrupt is triggered only when its input value 409e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * transfer from 0 to 1. So, invert the input value if the 410e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * irq type is low or falling 411e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang */ 412e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if ((type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW))) 413e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang writel(pintmask, &pint_regs->invert_set); 414e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang else 415e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang writel(pintmask, &pint_regs->invert_clear); 416e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 417e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang /* In edge sensitive case, if the input value of the requested irq 418e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * is already 1, invert it. 419e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang */ 420e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) { 421e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (gpio_get_value(port->chip.base + d->hwirq)) 422e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang writel(pintmask, &pint_regs->invert_set); 423e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang else 424e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang writel(pintmask, &pint_regs->invert_clear); 425e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang } 426e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 427e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) { 428e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang writel(pintmask, &pint_regs->edge_set); 429e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang __irq_set_handler_locked(irq, handle_edge_irq); 430e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang } else { 431e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang writel(pintmask, &pint_regs->edge_clear); 432e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang __irq_set_handler_locked(irq, handle_level_irq); 433e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang } 434e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 435e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangout: 436010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang spin_unlock(&port->pint->lock); 437e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang spin_unlock_irqrestore(&port->lock, flags); 438e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 439e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return ret; 440e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 441e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 442e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#ifdef CONFIG_PM 443e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_gpio_set_wake(struct irq_data *d, unsigned int state) 444e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 445e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_port *port = irq_data_get_irq_chip_data(d); 446e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 447e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (!port || !port->pint || port->pint->irq != d->irq) 448e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return -EINVAL; 449e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 450e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#ifndef SEC_GCTL 451e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang adi_internal_set_wake(port->pint->irq, state); 452e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#endif 453e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 454e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return 0; 455e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 456e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 457e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_pint_suspend(void) 458e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 459e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_pint *pint; 460e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 461e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang list_for_each_entry(pint, &adi_pint_list, node) { 462e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang writel(0xffffffff, &pint->regs->mask_clear); 463e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang pint->saved_data.assign = readl(&pint->regs->assign); 464e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang pint->saved_data.edge_set = readl(&pint->regs->edge_set); 465e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang pint->saved_data.invert_set = readl(&pint->regs->invert_set); 466e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang } 467e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 468e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return 0; 469e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 470e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 471e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic void adi_pint_resume(void) 472e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 473e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_pint *pint; 474e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 475e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang list_for_each_entry(pint, &adi_pint_list, node) { 476e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang writel(pint->saved_data.assign, &pint->regs->assign); 477e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang writel(pint->saved_data.edge_set, &pint->regs->edge_set); 478e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang writel(pint->saved_data.invert_set, &pint->regs->invert_set); 479e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang } 480e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 481e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 482e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_gpio_suspend(void) 483e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 484e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_port *port; 485e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 486e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang list_for_each_entry(port, &adi_gpio_port_list, node) { 487e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang port->saved_data.fer = readw(&port->regs->port_fer); 488e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang port->saved_data.mux = readl(&port->regs->port_mux); 489e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang port->saved_data.data = readw(&port->regs->data); 490e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang port->saved_data.inen = readw(&port->regs->inen); 491e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang port->saved_data.dir = readw(&port->regs->dir_set); 492e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang } 493e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 494e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return adi_pint_suspend(); 495e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 496e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 497e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic void adi_gpio_resume(void) 498e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 499e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_port *port; 500e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 501e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang adi_pint_resume(); 502e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 503e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang list_for_each_entry(port, &adi_gpio_port_list, node) { 504e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang writel(port->saved_data.mux, &port->regs->port_mux); 505e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang writew(port->saved_data.fer, &port->regs->port_fer); 506e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang writew(port->saved_data.inen, &port->regs->inen); 507e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang writew(port->saved_data.data & port->saved_data.dir, 508e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang &port->regs->data_set); 509e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang writew(port->saved_data.dir, &port->regs->dir_set); 510e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang } 511e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 512e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 513e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 514e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic struct syscore_ops gpio_pm_syscore_ops = { 515e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang .suspend = adi_gpio_suspend, 516e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang .resume = adi_gpio_resume, 517e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}; 518e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#else /* CONFIG_PM */ 519e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#define adi_gpio_set_wake NULL 520e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#endif /* CONFIG_PM */ 521e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 522e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#ifdef CONFIG_IRQ_PREFLOW_FASTEOI 523e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic inline void preflow_handler(struct irq_desc *desc) 524e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 525e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (desc->preflow_handler) 526e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang desc->preflow_handler(&desc->irq_data); 527e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 528e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#else 529e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic inline void preflow_handler(struct irq_desc *desc) { } 530e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#endif 531e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 532e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic void adi_gpio_handle_pint_irq(unsigned int inta_irq, 533e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct irq_desc *desc) 534e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 535e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang u32 request; 536e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang u32 level_mask, hwirq; 537e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang bool umask = false; 538e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_pint *pint = irq_desc_get_handler_data(desc); 539e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct irq_chip *chip = irq_desc_get_chip(desc); 540e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_pint_regs *regs = pint->regs; 541e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct irq_domain *domain; 542e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 543e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang preflow_handler(desc); 544e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang chained_irq_enter(chip, desc); 545e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 546e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang request = readl(®s->request); 547e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang level_mask = readl(®s->edge_set) & request; 548e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 549e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang hwirq = 0; 550e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang domain = pint->domain[0]; 551e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang while (request) { 552e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang /* domain pointer need to be changed only once at IRQ 16 when 553e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * we go through IRQ requests from bit 0 to bit 31. 554e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang */ 555e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (hwirq == PINT_HI_OFFSET) 556e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang domain = pint->domain[1]; 557e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 558e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (request & 1) { 559e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (level_mask & BIT(hwirq)) { 560e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang umask = true; 561e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang chained_irq_exit(chip, desc); 562e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang } 563e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang generic_handle_irq(irq_find_mapping(domain, 564e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang hwirq % PINT_HI_OFFSET)); 565e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang } 566e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 567e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang hwirq++; 568e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang request >>= 1; 569e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang } 570e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 571e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (!umask) 572e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang chained_irq_exit(chip, desc); 573e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 574e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 575e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic struct irq_chip adi_gpio_irqchip = { 576e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang .name = "GPIO", 577e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang .irq_ack = adi_gpio_ack_irq, 578e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang .irq_mask = adi_gpio_mask_irq, 579e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang .irq_mask_ack = adi_gpio_mask_ack_irq, 580e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang .irq_unmask = adi_gpio_unmask_irq, 581e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang .irq_disable = adi_gpio_mask_irq, 582e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang .irq_enable = adi_gpio_unmask_irq, 583e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang .irq_set_type = adi_gpio_irq_type, 584e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang .irq_startup = adi_gpio_irq_startup, 585e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang .irq_shutdown = adi_gpio_irq_shutdown, 586e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang .irq_set_wake = adi_gpio_set_wake, 587e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}; 588e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 589e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_get_groups_count(struct pinctrl_dev *pctldev) 590e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 591e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct adi_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev); 592e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 593e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return pinctrl->soc->ngroups; 594e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 595e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 596e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic const char *adi_get_group_name(struct pinctrl_dev *pctldev, 597e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang unsigned selector) 598e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 599e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct adi_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev); 600e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 601e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return pinctrl->soc->groups[selector].name; 602e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 603e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 604e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector, 605e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang const unsigned **pins, 606e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang unsigned *num_pins) 607e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 608e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct adi_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev); 609e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 610e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang *pins = pinctrl->soc->groups[selector].pins; 611e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang *num_pins = pinctrl->soc->groups[selector].num; 612e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return 0; 613e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 614e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 615e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic struct pinctrl_ops adi_pctrl_ops = { 616e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang .get_groups_count = adi_get_groups_count, 617e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang .get_group_name = adi_get_group_name, 618e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang .get_group_pins = adi_get_group_pins, 619e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}; 620e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 621e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_pinmux_enable(struct pinctrl_dev *pctldev, unsigned selector, 622e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang unsigned group) 623e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 624e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct adi_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev); 625e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_port *port; 626e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct pinctrl_gpio_range *range; 627e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang unsigned long flags; 628e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang unsigned short *mux, pin; 629e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 630e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang mux = (unsigned short *)pinctrl->soc->functions[selector].mux; 631e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 632e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang while (*mux) { 633e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang pin = P_IDENT(*mux); 634e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 635e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang range = pinctrl_find_gpio_range_from_pin(pctldev, pin); 636e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (range == NULL) /* should not happen */ 637e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return -ENODEV; 638e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 639e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang port = container_of(range->gc, struct gpio_port, chip); 640e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 641e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang spin_lock_irqsave(&port->lock, flags); 642e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 643e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang portmux_setup(port, pin_to_offset(range, pin), 644b81e57e6ac35242ba59206b303ba6c7585764ee1Sonic Zhang P_FUNCT2MUX(*mux)); 645e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang port_setup(port, pin_to_offset(range, pin), false); 646e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang mux++; 647e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 648e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang spin_unlock_irqrestore(&port->lock, flags); 649e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang } 650e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 651e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return 0; 652e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 653e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 654e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic void adi_pinmux_disable(struct pinctrl_dev *pctldev, unsigned selector, 655e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang unsigned group) 656e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 657e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct adi_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev); 658e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_port *port; 659e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct pinctrl_gpio_range *range; 660e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang unsigned long flags; 661e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang unsigned short *mux, pin; 662e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 663e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang mux = (unsigned short *)pinctrl->soc->functions[selector].mux; 664e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 665e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang while (*mux) { 666e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang pin = P_IDENT(*mux); 667e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 668e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang range = pinctrl_find_gpio_range_from_pin(pctldev, pin); 669e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (range == NULL) /* should not happen */ 670e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return; 671e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 672e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang port = container_of(range->gc, struct gpio_port, chip); 673e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 674e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang spin_lock_irqsave(&port->lock, flags); 675e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 676e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang port_setup(port, pin_to_offset(range, pin), true); 677e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang mux++; 678e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 679e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang spin_unlock_irqrestore(&port->lock, flags); 680e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang } 681e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 682e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 683e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_pinmux_get_funcs_count(struct pinctrl_dev *pctldev) 684e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 685e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct adi_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev); 686e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 687e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return pinctrl->soc->nfunctions; 688e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 689e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 690e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic const char *adi_pinmux_get_func_name(struct pinctrl_dev *pctldev, 691e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang unsigned selector) 692e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 693e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct adi_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev); 694e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 695e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return pinctrl->soc->functions[selector].name; 696e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 697e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 698e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_pinmux_get_groups(struct pinctrl_dev *pctldev, unsigned selector, 699e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang const char * const **groups, 700e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang unsigned * const num_groups) 701e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 702e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct adi_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev); 703e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 704e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang *groups = pinctrl->soc->functions[selector].groups; 705e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang *num_groups = pinctrl->soc->functions[selector].num_groups; 706e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return 0; 707e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 708e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 709e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_pinmux_request_gpio(struct pinctrl_dev *pctldev, 710e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct pinctrl_gpio_range *range, unsigned pin) 711e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 712e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_port *port; 713e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang unsigned long flags; 714e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang u8 offset; 715e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 716e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang port = container_of(range->gc, struct gpio_port, chip); 717e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang offset = pin_to_offset(range, pin); 718e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 719e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang spin_lock_irqsave(&port->lock, flags); 720e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 721e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang port_setup(port, offset, true); 722e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 723e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang spin_unlock_irqrestore(&port->lock, flags); 724e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 725e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return 0; 726e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 727e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 728e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic struct pinmux_ops adi_pinmux_ops = { 729e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang .enable = adi_pinmux_enable, 730e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang .disable = adi_pinmux_disable, 731e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang .get_functions_count = adi_pinmux_get_funcs_count, 732e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang .get_function_name = adi_pinmux_get_func_name, 733e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang .get_function_groups = adi_pinmux_get_groups, 734e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang .gpio_request_enable = adi_pinmux_request_gpio, 735e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}; 736e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 737e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 738e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic struct pinctrl_desc adi_pinmux_desc = { 739e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang .name = DRIVER_NAME, 740e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang .pctlops = &adi_pctrl_ops, 741e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang .pmxops = &adi_pinmux_ops, 742e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang .owner = THIS_MODULE, 743e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}; 744e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 745e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_gpio_request(struct gpio_chip *chip, unsigned offset) 746e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 747e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return pinctrl_request_gpio(chip->base + offset); 748e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 749e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 750e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic void adi_gpio_free(struct gpio_chip *chip, unsigned offset) 751e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 752e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang pinctrl_free_gpio(chip->base + offset); 753e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 754e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 755e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_gpio_direction_input(struct gpio_chip *chip, unsigned offset) 756e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 757e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_port *port; 758e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang unsigned long flags; 759e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 760e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang port = container_of(chip, struct gpio_port, chip); 761e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 762e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang spin_lock_irqsave(&port->lock, flags); 763e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 764e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang writew(BIT(offset), &port->regs->dir_clear); 765e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang writew(readw(&port->regs->inen) | BIT(offset), &port->regs->inen); 766e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 767e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang spin_unlock_irqrestore(&port->lock, flags); 768e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 769e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return 0; 770e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 771e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 772e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic void adi_gpio_set_value(struct gpio_chip *chip, unsigned offset, 773e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang int value) 774e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 775e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_port *port = container_of(chip, struct gpio_port, chip); 776e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_port_t *regs = port->regs; 777e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang unsigned long flags; 778e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 779e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang spin_lock_irqsave(&port->lock, flags); 780e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 781e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (value) 782d3224ed140dc440c43e1da607b7685635e8064a6Sonic Zhang writew(BIT(offset), ®s->data_set); 783e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang else 784d3224ed140dc440c43e1da607b7685635e8064a6Sonic Zhang writew(BIT(offset), ®s->data_clear); 785e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 786e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang spin_unlock_irqrestore(&port->lock, flags); 787e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 788e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 789e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_gpio_direction_output(struct gpio_chip *chip, unsigned offset, 790e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang int value) 791e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 792e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_port *port = container_of(chip, struct gpio_port, chip); 793e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_port_t *regs = port->regs; 794e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang unsigned long flags; 795e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 796e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang spin_lock_irqsave(&port->lock, flags); 797e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 798d3224ed140dc440c43e1da607b7685635e8064a6Sonic Zhang writew(readw(®s->inen) & ~BIT(offset), ®s->inen); 799d3224ed140dc440c43e1da607b7685635e8064a6Sonic Zhang if (value) 800d3224ed140dc440c43e1da607b7685635e8064a6Sonic Zhang writew(BIT(offset), ®s->data_set); 801d3224ed140dc440c43e1da607b7685635e8064a6Sonic Zhang else 802d3224ed140dc440c43e1da607b7685635e8064a6Sonic Zhang writew(BIT(offset), ®s->data_clear); 803d3224ed140dc440c43e1da607b7685635e8064a6Sonic Zhang writew(BIT(offset), ®s->dir_set); 804e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 805e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang spin_unlock_irqrestore(&port->lock, flags); 806e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 807e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return 0; 808e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 809e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 810e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_gpio_get_value(struct gpio_chip *chip, unsigned offset) 811e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 812e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_port *port = container_of(chip, struct gpio_port, chip); 813e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_port_t *regs = port->regs; 814e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang unsigned long flags; 815e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang int ret; 816e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 817e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang spin_lock_irqsave(&port->lock, flags); 818e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 819e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang ret = !!(readw(®s->data) & BIT(offset)); 820e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 821e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang spin_unlock_irqrestore(&port->lock, flags); 822e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 823e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return ret; 824e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 825e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 826e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_gpio_to_irq(struct gpio_chip *chip, unsigned offset) 827e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 828e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_port *port = container_of(chip, struct gpio_port, chip); 829e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 830e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (port->irq_base >= 0) 831e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return irq_find_mapping(port->domain, offset); 832e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang else 833e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return irq_create_mapping(port->domain, offset); 834e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 835e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 836e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_pint_map_port(struct gpio_pint *pint, bool assign, u8 map, 837e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct irq_domain *domain) 838e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 839e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_pint_regs *regs = pint->regs; 840e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang u32 map_mask; 841e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 842e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (pint->map_count > 1) 843e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return -EINVAL; 844e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 845e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang pint->map_count++; 846e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 847e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang /* The map_mask of each gpio port is a 16-bit duplicate 848e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * of the 8-bit map. It can be set to either high 16 bits or low 849e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * 16 bits of the pint assignment register. 850e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang */ 851e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang map_mask = (map << 8) | map; 852e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (assign) { 853e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang map_mask <<= PINT_HI_OFFSET; 854e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang writel((readl(®s->assign) & 0xFFFF) | map_mask, 855e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang ®s->assign); 856e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang } else 857e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang writel((readl(®s->assign) & 0xFFFF0000) | map_mask, 858e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang ®s->assign); 859e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 860e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang pint->domain[assign] = domain; 861e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 862e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return 0; 863e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 864e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 865e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_gpio_pint_probe(struct platform_device *pdev) 866e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 867e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct device *dev = &pdev->dev; 868e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct resource *res; 869e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_pint *pint; 870e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 871e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang pint = devm_kzalloc(dev, sizeof(struct gpio_pint), GFP_KERNEL); 872e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (!pint) { 873e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang dev_err(dev, "Memory alloc failed\n"); 874e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return -ENOMEM; 875e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang } 876e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 877e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 878c8690d6d2957ed060c1cba4cde3ec41e3829651bAxel Lin pint->base = devm_ioremap_resource(dev, res); 879c8690d6d2957ed060c1cba4cde3ec41e3829651bAxel Lin if (IS_ERR(pint->base)) 880c8690d6d2957ed060c1cba4cde3ec41e3829651bAxel Lin return PTR_ERR(pint->base); 881e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 882e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang pint->regs = (struct gpio_pint_regs *)pint->base; 883e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 884e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 885e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (!res) { 886e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang dev_err(dev, "Invalid IRQ resource\n"); 887e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return -ENODEV; 888e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang } 889e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 890e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang spin_lock_init(&pint->lock); 891e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 892e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang pint->irq = res->start; 893e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang pint->pint_map_port = adi_pint_map_port; 894e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang platform_set_drvdata(pdev, pint); 895e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 896e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang irq_set_chained_handler(pint->irq, adi_gpio_handle_pint_irq); 897e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang irq_set_handler_data(pint->irq, pint); 898e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 899e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang list_add_tail(&pint->node, &adi_pint_list); 900e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 901e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return 0; 902e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 903e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 904e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_gpio_pint_remove(struct platform_device *pdev) 905e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 906e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_pint *pint = platform_get_drvdata(pdev); 907e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 908e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang list_del(&pint->node); 909e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang irq_set_handler(pint->irq, handle_simple_irq); 910e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 911e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return 0; 912e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 913e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 914e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_gpio_irq_map(struct irq_domain *d, unsigned int irq, 915e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang irq_hw_number_t hwirq) 916e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 917e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_port *port = d->host_data; 918e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 919e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (!port) 920e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return -EINVAL; 921e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 922e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang irq_set_chip_data(irq, port); 923e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang irq_set_chip_and_handler(irq, &adi_gpio_irqchip, 924e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang handle_level_irq); 925e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 926e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return 0; 927e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 928e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 929e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangconst struct irq_domain_ops adi_gpio_irq_domain_ops = { 930e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang .map = adi_gpio_irq_map, 931e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang .xlate = irq_domain_xlate_onecell, 932e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}; 933e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 934e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_gpio_init_int(struct gpio_port *port) 935e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 936e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct device_node *node = port->dev->of_node; 937e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_pint *pint = port->pint; 938e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang int ret; 939e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 940e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang port->domain = irq_domain_add_linear(node, port->width, 941e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang &adi_gpio_irq_domain_ops, port); 942e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (!port->domain) { 943e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang dev_err(port->dev, "Failed to create irqdomain\n"); 944e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return -ENOSYS; 945e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang } 946e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 947e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang /* According to BF54x and BF60x HRM, pin interrupt devices are not 948e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * part of the GPIO port device. in GPIO interrupt mode, the GPIO 949e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * pins of multiple port devices can be routed into one pin interrupt 950e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * device. The mapping can be configured by setting pint assignment 951e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * register with the mapping value of different GPIO port. This is 952e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * done via function pint_map_port(). 953e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang */ 954e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang ret = pint->pint_map_port(port->pint, port->pint_assign, 955e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang port->pint_map, port->domain); 956e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (ret) 957e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return ret; 958e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 959e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (port->irq_base >= 0) { 960e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang ret = irq_create_strict_mappings(port->domain, port->irq_base, 961e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 0, port->width); 962e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (ret) { 963e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang dev_err(port->dev, "Couldn't associate to domain\n"); 964e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return ret; 965e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang } 966e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang } 967e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 968e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return 0; 969e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 970e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 971e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#define DEVNAME_SIZE 16 972e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 973e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_gpio_probe(struct platform_device *pdev) 974e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 975e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct device *dev = &pdev->dev; 976e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang const struct adi_pinctrl_gpio_platform_data *pdata; 977e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct resource *res; 978e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_port *port; 979e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang char pinctrl_devname[DEVNAME_SIZE]; 980e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang static int gpio; 981e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang int ret = 0, ret1; 982e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 983e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang pdata = dev->platform_data; 984e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (!pdata) 985e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return -EINVAL; 986e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 987e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang port = devm_kzalloc(dev, sizeof(struct gpio_port), GFP_KERNEL); 988e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (!port) { 989e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang dev_err(dev, "Memory alloc failed\n"); 990e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return -ENOMEM; 991e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang } 992e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 993e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 994c8690d6d2957ed060c1cba4cde3ec41e3829651bAxel Lin port->base = devm_ioremap_resource(dev, res); 995c8690d6d2957ed060c1cba4cde3ec41e3829651bAxel Lin if (IS_ERR(port->base)) 996c8690d6d2957ed060c1cba4cde3ec41e3829651bAxel Lin return PTR_ERR(port->base); 997e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 998e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 999e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (!res) 1000e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang port->irq_base = -1; 1001e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang else 1002e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang port->irq_base = res->start; 1003e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 1004e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang port->width = pdata->port_width; 1005e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang port->dev = dev; 1006e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang port->regs = (struct gpio_port_t *)port->base; 1007e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang port->pint_assign = pdata->pint_assign; 1008e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang port->pint_map = pdata->pint_map; 1009e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 1010e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang port->pint = find_gpio_pint(pdata->pint_id); 1011e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (port->pint) { 1012e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang ret = adi_gpio_init_int(port); 1013e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (ret) 1014e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return ret; 1015e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang } 1016e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 1017e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang spin_lock_init(&port->lock); 1018e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 1019e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang platform_set_drvdata(pdev, port); 1020e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 1021e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang port->chip.label = "adi-gpio"; 1022e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang port->chip.direction_input = adi_gpio_direction_input; 1023e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang port->chip.get = adi_gpio_get_value; 1024e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang port->chip.direction_output = adi_gpio_direction_output; 1025e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang port->chip.set = adi_gpio_set_value; 1026e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang port->chip.request = adi_gpio_request; 1027e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang port->chip.free = adi_gpio_free; 1028e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang port->chip.to_irq = adi_gpio_to_irq; 1029e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (pdata->port_gpio_base > 0) 1030e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang port->chip.base = pdata->port_gpio_base; 1031e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang else 1032e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang port->chip.base = gpio; 1033e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang port->chip.ngpio = port->width; 1034e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang gpio = port->chip.base + port->width; 1035e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 1036e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang ret = gpiochip_add(&port->chip); 1037e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (ret) { 1038e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang dev_err(&pdev->dev, "Fail to add GPIO chip.\n"); 1039e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang goto out_remove_domain; 1040e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang } 1041e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 1042e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang /* Add gpio pin range */ 1043e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang snprintf(pinctrl_devname, DEVNAME_SIZE, "pinctrl-adi2.%d", 1044e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang pdata->pinctrl_id); 1045e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang pinctrl_devname[DEVNAME_SIZE - 1] = 0; 1046e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang ret = gpiochip_add_pin_range(&port->chip, pinctrl_devname, 1047e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 0, pdata->port_pin_base, port->width); 1048e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (ret) { 1049e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang dev_err(&pdev->dev, "Fail to add pin range to %s.\n", 1050e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang pinctrl_devname); 1051e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang goto out_remove_gpiochip; 1052e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang } 1053e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 1054e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang list_add_tail(&port->node, &adi_gpio_port_list); 1055e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 1056e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return 0; 1057e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 1058e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangout_remove_gpiochip: 1059e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang ret1 = gpiochip_remove(&port->chip); 1060e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangout_remove_domain: 1061e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (port->pint) 1062e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang irq_domain_remove(port->domain); 1063e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 1064e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return ret; 1065e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 1066e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 1067e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_gpio_remove(struct platform_device *pdev) 1068e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 1069e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct gpio_port *port = platform_get_drvdata(pdev); 1070e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang int ret; 1071e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang u8 offset; 1072e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 1073e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang list_del(&port->node); 1074e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang gpiochip_remove_pin_ranges(&port->chip); 1075e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang ret = gpiochip_remove(&port->chip); 1076e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (port->pint) { 1077e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang for (offset = 0; offset < port->width; offset++) 1078e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang irq_dispose_mapping(irq_find_mapping(port->domain, 1079e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang offset)); 1080e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang irq_domain_remove(port->domain); 1081e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang } 1082e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 1083e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return ret; 1084e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 1085e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 1086e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_pinctrl_probe(struct platform_device *pdev) 1087e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 1088e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct adi_pinctrl *pinctrl; 1089e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 1090e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang pinctrl = devm_kzalloc(&pdev->dev, sizeof(*pinctrl), GFP_KERNEL); 1091e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (!pinctrl) 1092e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return -ENOMEM; 1093e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 1094e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang pinctrl->dev = &pdev->dev; 1095e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 1096e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang adi_pinctrl_soc_init(&pinctrl->soc); 1097e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 1098e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang adi_pinmux_desc.pins = pinctrl->soc->pins; 1099e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang adi_pinmux_desc.npins = pinctrl->soc->npins; 1100e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 1101e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang /* Now register the pin controller and all pins it handles */ 1102e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang pinctrl->pctl = pinctrl_register(&adi_pinmux_desc, &pdev->dev, pinctrl); 1103e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (!pinctrl->pctl) { 1104e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang dev_err(&pdev->dev, "could not register pinctrl ADI2 driver\n"); 1105e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return -EINVAL; 1106e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang } 1107e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 1108e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang platform_set_drvdata(pdev, pinctrl); 1109e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 1110e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return 0; 1111e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 1112e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 1113e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_pinctrl_remove(struct platform_device *pdev) 1114e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 1115e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang struct adi_pinctrl *pinctrl = platform_get_drvdata(pdev); 1116e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 1117e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang pinctrl_unregister(pinctrl->pctl); 1118e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 1119e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return 0; 1120e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 1121e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 1122e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic struct platform_driver adi_pinctrl_driver = { 1123e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang .probe = adi_pinctrl_probe, 1124e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang .remove = adi_pinctrl_remove, 1125e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang .driver = { 1126e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang .name = DRIVER_NAME, 1127e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang }, 1128e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}; 1129e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 1130e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic struct platform_driver adi_gpio_pint_driver = { 1131e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang .probe = adi_gpio_pint_probe, 1132e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang .remove = adi_gpio_pint_remove, 1133e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang .driver = { 1134e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang .name = "adi-gpio-pint", 1135e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang }, 1136e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}; 1137e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 1138e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic struct platform_driver adi_gpio_driver = { 1139e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang .probe = adi_gpio_probe, 1140e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang .remove = adi_gpio_remove, 1141e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang .driver = { 1142e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang .name = "adi-gpio", 1143e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang }, 1144e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}; 1145e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 1146e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int __init adi_pinctrl_setup(void) 1147e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{ 1148e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang int ret; 1149e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 1150e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang ret = platform_driver_register(&adi_pinctrl_driver); 1151e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (ret) 1152e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return ret; 1153e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 1154e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang ret = platform_driver_register(&adi_gpio_pint_driver); 1155e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (ret) 1156e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang goto pint_error; 1157e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 1158e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang ret = platform_driver_register(&adi_gpio_driver); 1159e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang if (ret) 1160e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang goto gpio_error; 1161e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 1162e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#ifdef CONFIG_PM 1163e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang register_syscore_ops(&gpio_pm_syscore_ops); 1164e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#endif 1165e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return ret; 1166e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhanggpio_error: 1167e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang platform_driver_unregister(&adi_gpio_pint_driver); 1168e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangpint_error: 1169e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang platform_driver_unregister(&adi_pinctrl_driver); 1170e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 1171e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang return ret; 1172e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang} 1173e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangarch_initcall(adi_pinctrl_setup); 1174e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang 1175e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic ZhangMODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>"); 1176e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic ZhangMODULE_DESCRIPTION("ADI gpio2 pin control driver"); 1177e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic ZhangMODULE_LICENSE("GPL"); 1178