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