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