162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Xilinx Zynq GPIO device driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2009 - 2014 Xilinx, Inc. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/bitops.h> 962306a36Sopenharmony_ci#include <linux/clk.h> 1062306a36Sopenharmony_ci#include <linux/gpio/driver.h> 1162306a36Sopenharmony_ci#include <linux/init.h> 1262306a36Sopenharmony_ci#include <linux/interrupt.h> 1362306a36Sopenharmony_ci#include <linux/spinlock.h> 1462306a36Sopenharmony_ci#include <linux/io.h> 1562306a36Sopenharmony_ci#include <linux/module.h> 1662306a36Sopenharmony_ci#include <linux/platform_device.h> 1762306a36Sopenharmony_ci#include <linux/pm_runtime.h> 1862306a36Sopenharmony_ci#include <linux/of.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define DRIVER_NAME "zynq-gpio" 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci/* Maximum banks */ 2362306a36Sopenharmony_ci#define ZYNQ_GPIO_MAX_BANK 4 2462306a36Sopenharmony_ci#define ZYNQMP_GPIO_MAX_BANK 6 2562306a36Sopenharmony_ci#define VERSAL_GPIO_MAX_BANK 4 2662306a36Sopenharmony_ci#define PMC_GPIO_MAX_BANK 5 2762306a36Sopenharmony_ci#define VERSAL_UNUSED_BANKS 2 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define ZYNQ_GPIO_BANK0_NGPIO 32 3062306a36Sopenharmony_ci#define ZYNQ_GPIO_BANK1_NGPIO 22 3162306a36Sopenharmony_ci#define ZYNQ_GPIO_BANK2_NGPIO 32 3262306a36Sopenharmony_ci#define ZYNQ_GPIO_BANK3_NGPIO 32 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#define ZYNQMP_GPIO_BANK0_NGPIO 26 3562306a36Sopenharmony_ci#define ZYNQMP_GPIO_BANK1_NGPIO 26 3662306a36Sopenharmony_ci#define ZYNQMP_GPIO_BANK2_NGPIO 26 3762306a36Sopenharmony_ci#define ZYNQMP_GPIO_BANK3_NGPIO 32 3862306a36Sopenharmony_ci#define ZYNQMP_GPIO_BANK4_NGPIO 32 3962306a36Sopenharmony_ci#define ZYNQMP_GPIO_BANK5_NGPIO 32 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#define ZYNQ_GPIO_NR_GPIOS 118 4262306a36Sopenharmony_ci#define ZYNQMP_GPIO_NR_GPIOS 174 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#define ZYNQ_GPIO_BANK0_PIN_MIN(str) 0 4562306a36Sopenharmony_ci#define ZYNQ_GPIO_BANK0_PIN_MAX(str) (ZYNQ_GPIO_BANK0_PIN_MIN(str) + \ 4662306a36Sopenharmony_ci ZYNQ##str##_GPIO_BANK0_NGPIO - 1) 4762306a36Sopenharmony_ci#define ZYNQ_GPIO_BANK1_PIN_MIN(str) (ZYNQ_GPIO_BANK0_PIN_MAX(str) + 1) 4862306a36Sopenharmony_ci#define ZYNQ_GPIO_BANK1_PIN_MAX(str) (ZYNQ_GPIO_BANK1_PIN_MIN(str) + \ 4962306a36Sopenharmony_ci ZYNQ##str##_GPIO_BANK1_NGPIO - 1) 5062306a36Sopenharmony_ci#define ZYNQ_GPIO_BANK2_PIN_MIN(str) (ZYNQ_GPIO_BANK1_PIN_MAX(str) + 1) 5162306a36Sopenharmony_ci#define ZYNQ_GPIO_BANK2_PIN_MAX(str) (ZYNQ_GPIO_BANK2_PIN_MIN(str) + \ 5262306a36Sopenharmony_ci ZYNQ##str##_GPIO_BANK2_NGPIO - 1) 5362306a36Sopenharmony_ci#define ZYNQ_GPIO_BANK3_PIN_MIN(str) (ZYNQ_GPIO_BANK2_PIN_MAX(str) + 1) 5462306a36Sopenharmony_ci#define ZYNQ_GPIO_BANK3_PIN_MAX(str) (ZYNQ_GPIO_BANK3_PIN_MIN(str) + \ 5562306a36Sopenharmony_ci ZYNQ##str##_GPIO_BANK3_NGPIO - 1) 5662306a36Sopenharmony_ci#define ZYNQ_GPIO_BANK4_PIN_MIN(str) (ZYNQ_GPIO_BANK3_PIN_MAX(str) + 1) 5762306a36Sopenharmony_ci#define ZYNQ_GPIO_BANK4_PIN_MAX(str) (ZYNQ_GPIO_BANK4_PIN_MIN(str) + \ 5862306a36Sopenharmony_ci ZYNQ##str##_GPIO_BANK4_NGPIO - 1) 5962306a36Sopenharmony_ci#define ZYNQ_GPIO_BANK5_PIN_MIN(str) (ZYNQ_GPIO_BANK4_PIN_MAX(str) + 1) 6062306a36Sopenharmony_ci#define ZYNQ_GPIO_BANK5_PIN_MAX(str) (ZYNQ_GPIO_BANK5_PIN_MIN(str) + \ 6162306a36Sopenharmony_ci ZYNQ##str##_GPIO_BANK5_NGPIO - 1) 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci/* Register offsets for the GPIO device */ 6462306a36Sopenharmony_ci/* LSW Mask & Data -WO */ 6562306a36Sopenharmony_ci#define ZYNQ_GPIO_DATA_LSW_OFFSET(BANK) (0x000 + (8 * BANK)) 6662306a36Sopenharmony_ci/* MSW Mask & Data -WO */ 6762306a36Sopenharmony_ci#define ZYNQ_GPIO_DATA_MSW_OFFSET(BANK) (0x004 + (8 * BANK)) 6862306a36Sopenharmony_ci/* Data Register-RW */ 6962306a36Sopenharmony_ci#define ZYNQ_GPIO_DATA_OFFSET(BANK) (0x040 + (4 * BANK)) 7062306a36Sopenharmony_ci#define ZYNQ_GPIO_DATA_RO_OFFSET(BANK) (0x060 + (4 * BANK)) 7162306a36Sopenharmony_ci/* Direction mode reg-RW */ 7262306a36Sopenharmony_ci#define ZYNQ_GPIO_DIRM_OFFSET(BANK) (0x204 + (0x40 * BANK)) 7362306a36Sopenharmony_ci/* Output enable reg-RW */ 7462306a36Sopenharmony_ci#define ZYNQ_GPIO_OUTEN_OFFSET(BANK) (0x208 + (0x40 * BANK)) 7562306a36Sopenharmony_ci/* Interrupt mask reg-RO */ 7662306a36Sopenharmony_ci#define ZYNQ_GPIO_INTMASK_OFFSET(BANK) (0x20C + (0x40 * BANK)) 7762306a36Sopenharmony_ci/* Interrupt enable reg-WO */ 7862306a36Sopenharmony_ci#define ZYNQ_GPIO_INTEN_OFFSET(BANK) (0x210 + (0x40 * BANK)) 7962306a36Sopenharmony_ci/* Interrupt disable reg-WO */ 8062306a36Sopenharmony_ci#define ZYNQ_GPIO_INTDIS_OFFSET(BANK) (0x214 + (0x40 * BANK)) 8162306a36Sopenharmony_ci/* Interrupt status reg-RO */ 8262306a36Sopenharmony_ci#define ZYNQ_GPIO_INTSTS_OFFSET(BANK) (0x218 + (0x40 * BANK)) 8362306a36Sopenharmony_ci/* Interrupt type reg-RW */ 8462306a36Sopenharmony_ci#define ZYNQ_GPIO_INTTYPE_OFFSET(BANK) (0x21C + (0x40 * BANK)) 8562306a36Sopenharmony_ci/* Interrupt polarity reg-RW */ 8662306a36Sopenharmony_ci#define ZYNQ_GPIO_INTPOL_OFFSET(BANK) (0x220 + (0x40 * BANK)) 8762306a36Sopenharmony_ci/* Interrupt on any, reg-RW */ 8862306a36Sopenharmony_ci#define ZYNQ_GPIO_INTANY_OFFSET(BANK) (0x224 + (0x40 * BANK)) 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci/* Disable all interrupts mask */ 9162306a36Sopenharmony_ci#define ZYNQ_GPIO_IXR_DISABLE_ALL 0xFFFFFFFF 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci/* Mid pin number of a bank */ 9462306a36Sopenharmony_ci#define ZYNQ_GPIO_MID_PIN_NUM 16 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci/* GPIO upper 16 bit mask */ 9762306a36Sopenharmony_ci#define ZYNQ_GPIO_UPPER_MASK 0xFFFF0000 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci/* set to differentiate zynq from zynqmp, 0=zynqmp, 1=zynq */ 10062306a36Sopenharmony_ci#define ZYNQ_GPIO_QUIRK_IS_ZYNQ BIT(0) 10162306a36Sopenharmony_ci#define GPIO_QUIRK_DATA_RO_BUG BIT(1) 10262306a36Sopenharmony_ci#define GPIO_QUIRK_VERSAL BIT(2) 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistruct gpio_regs { 10562306a36Sopenharmony_ci u32 datamsw[ZYNQMP_GPIO_MAX_BANK]; 10662306a36Sopenharmony_ci u32 datalsw[ZYNQMP_GPIO_MAX_BANK]; 10762306a36Sopenharmony_ci u32 dirm[ZYNQMP_GPIO_MAX_BANK]; 10862306a36Sopenharmony_ci u32 outen[ZYNQMP_GPIO_MAX_BANK]; 10962306a36Sopenharmony_ci u32 int_en[ZYNQMP_GPIO_MAX_BANK]; 11062306a36Sopenharmony_ci u32 int_dis[ZYNQMP_GPIO_MAX_BANK]; 11162306a36Sopenharmony_ci u32 int_type[ZYNQMP_GPIO_MAX_BANK]; 11262306a36Sopenharmony_ci u32 int_polarity[ZYNQMP_GPIO_MAX_BANK]; 11362306a36Sopenharmony_ci u32 int_any[ZYNQMP_GPIO_MAX_BANK]; 11462306a36Sopenharmony_ci}; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci/** 11762306a36Sopenharmony_ci * struct zynq_gpio - gpio device private data structure 11862306a36Sopenharmony_ci * @chip: instance of the gpio_chip 11962306a36Sopenharmony_ci * @base_addr: base address of the GPIO device 12062306a36Sopenharmony_ci * @clk: clock resource for this controller 12162306a36Sopenharmony_ci * @irq: interrupt for the GPIO device 12262306a36Sopenharmony_ci * @p_data: pointer to platform data 12362306a36Sopenharmony_ci * @context: context registers 12462306a36Sopenharmony_ci * @dirlock: lock used for direction in/out synchronization 12562306a36Sopenharmony_ci */ 12662306a36Sopenharmony_cistruct zynq_gpio { 12762306a36Sopenharmony_ci struct gpio_chip chip; 12862306a36Sopenharmony_ci void __iomem *base_addr; 12962306a36Sopenharmony_ci struct clk *clk; 13062306a36Sopenharmony_ci int irq; 13162306a36Sopenharmony_ci const struct zynq_platform_data *p_data; 13262306a36Sopenharmony_ci struct gpio_regs context; 13362306a36Sopenharmony_ci spinlock_t dirlock; /* lock */ 13462306a36Sopenharmony_ci}; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci/** 13762306a36Sopenharmony_ci * struct zynq_platform_data - zynq gpio platform data structure 13862306a36Sopenharmony_ci * @label: string to store in gpio->label 13962306a36Sopenharmony_ci * @quirks: Flags is used to identify the platform 14062306a36Sopenharmony_ci * @ngpio: max number of gpio pins 14162306a36Sopenharmony_ci * @max_bank: maximum number of gpio banks 14262306a36Sopenharmony_ci * @bank_min: this array represents bank's min pin 14362306a36Sopenharmony_ci * @bank_max: this array represents bank's max pin 14462306a36Sopenharmony_ci */ 14562306a36Sopenharmony_cistruct zynq_platform_data { 14662306a36Sopenharmony_ci const char *label; 14762306a36Sopenharmony_ci u32 quirks; 14862306a36Sopenharmony_ci u16 ngpio; 14962306a36Sopenharmony_ci int max_bank; 15062306a36Sopenharmony_ci int bank_min[ZYNQMP_GPIO_MAX_BANK]; 15162306a36Sopenharmony_ci int bank_max[ZYNQMP_GPIO_MAX_BANK]; 15262306a36Sopenharmony_ci}; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cistatic const struct irq_chip zynq_gpio_level_irqchip; 15562306a36Sopenharmony_cistatic const struct irq_chip zynq_gpio_edge_irqchip; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci/** 15862306a36Sopenharmony_ci * zynq_gpio_is_zynq - test if HW is zynq or zynqmp 15962306a36Sopenharmony_ci * @gpio: Pointer to driver data struct 16062306a36Sopenharmony_ci * 16162306a36Sopenharmony_ci * Return: 0 if zynqmp, 1 if zynq. 16262306a36Sopenharmony_ci */ 16362306a36Sopenharmony_cistatic int zynq_gpio_is_zynq(struct zynq_gpio *gpio) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci return !!(gpio->p_data->quirks & ZYNQ_GPIO_QUIRK_IS_ZYNQ); 16662306a36Sopenharmony_ci} 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci/** 16962306a36Sopenharmony_ci * gpio_data_ro_bug - test if HW bug exists or not 17062306a36Sopenharmony_ci * @gpio: Pointer to driver data struct 17162306a36Sopenharmony_ci * 17262306a36Sopenharmony_ci * Return: 0 if bug doesnot exist, 1 if bug exists. 17362306a36Sopenharmony_ci */ 17462306a36Sopenharmony_cistatic int gpio_data_ro_bug(struct zynq_gpio *gpio) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci return !!(gpio->p_data->quirks & GPIO_QUIRK_DATA_RO_BUG); 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci/** 18062306a36Sopenharmony_ci * zynq_gpio_get_bank_pin - Get the bank number and pin number within that bank 18162306a36Sopenharmony_ci * for a given pin in the GPIO device 18262306a36Sopenharmony_ci * @pin_num: gpio pin number within the device 18362306a36Sopenharmony_ci * @bank_num: an output parameter used to return the bank number of the gpio 18462306a36Sopenharmony_ci * pin 18562306a36Sopenharmony_ci * @bank_pin_num: an output parameter used to return pin number within a bank 18662306a36Sopenharmony_ci * for the given gpio pin 18762306a36Sopenharmony_ci * @gpio: gpio device data structure 18862306a36Sopenharmony_ci * 18962306a36Sopenharmony_ci * Returns the bank number and pin offset within the bank. 19062306a36Sopenharmony_ci */ 19162306a36Sopenharmony_cistatic inline void zynq_gpio_get_bank_pin(unsigned int pin_num, 19262306a36Sopenharmony_ci unsigned int *bank_num, 19362306a36Sopenharmony_ci unsigned int *bank_pin_num, 19462306a36Sopenharmony_ci struct zynq_gpio *gpio) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci int bank; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci for (bank = 0; bank < gpio->p_data->max_bank; bank++) { 19962306a36Sopenharmony_ci if ((pin_num >= gpio->p_data->bank_min[bank]) && 20062306a36Sopenharmony_ci (pin_num <= gpio->p_data->bank_max[bank])) { 20162306a36Sopenharmony_ci *bank_num = bank; 20262306a36Sopenharmony_ci *bank_pin_num = pin_num - 20362306a36Sopenharmony_ci gpio->p_data->bank_min[bank]; 20462306a36Sopenharmony_ci return; 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci if (gpio->p_data->quirks & GPIO_QUIRK_VERSAL) 20762306a36Sopenharmony_ci bank = bank + VERSAL_UNUSED_BANKS; 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci /* default */ 21162306a36Sopenharmony_ci WARN(true, "invalid GPIO pin number: %u", pin_num); 21262306a36Sopenharmony_ci *bank_num = 0; 21362306a36Sopenharmony_ci *bank_pin_num = 0; 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci/** 21762306a36Sopenharmony_ci * zynq_gpio_get_value - Get the state of the specified pin of GPIO device 21862306a36Sopenharmony_ci * @chip: gpio_chip instance to be worked on 21962306a36Sopenharmony_ci * @pin: gpio pin number within the device 22062306a36Sopenharmony_ci * 22162306a36Sopenharmony_ci * This function reads the state of the specified pin of the GPIO device. 22262306a36Sopenharmony_ci * 22362306a36Sopenharmony_ci * Return: 0 if the pin is low, 1 if pin is high. 22462306a36Sopenharmony_ci */ 22562306a36Sopenharmony_cistatic int zynq_gpio_get_value(struct gpio_chip *chip, unsigned int pin) 22662306a36Sopenharmony_ci{ 22762306a36Sopenharmony_ci u32 data; 22862306a36Sopenharmony_ci unsigned int bank_num, bank_pin_num; 22962306a36Sopenharmony_ci struct zynq_gpio *gpio = gpiochip_get_data(chip); 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio); 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci if (gpio_data_ro_bug(gpio)) { 23462306a36Sopenharmony_ci if (zynq_gpio_is_zynq(gpio)) { 23562306a36Sopenharmony_ci if (bank_num <= 1) { 23662306a36Sopenharmony_ci data = readl_relaxed(gpio->base_addr + 23762306a36Sopenharmony_ci ZYNQ_GPIO_DATA_RO_OFFSET(bank_num)); 23862306a36Sopenharmony_ci } else { 23962306a36Sopenharmony_ci data = readl_relaxed(gpio->base_addr + 24062306a36Sopenharmony_ci ZYNQ_GPIO_DATA_OFFSET(bank_num)); 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci } else { 24362306a36Sopenharmony_ci if (bank_num <= 2) { 24462306a36Sopenharmony_ci data = readl_relaxed(gpio->base_addr + 24562306a36Sopenharmony_ci ZYNQ_GPIO_DATA_RO_OFFSET(bank_num)); 24662306a36Sopenharmony_ci } else { 24762306a36Sopenharmony_ci data = readl_relaxed(gpio->base_addr + 24862306a36Sopenharmony_ci ZYNQ_GPIO_DATA_OFFSET(bank_num)); 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci } 25162306a36Sopenharmony_ci } else { 25262306a36Sopenharmony_ci data = readl_relaxed(gpio->base_addr + 25362306a36Sopenharmony_ci ZYNQ_GPIO_DATA_RO_OFFSET(bank_num)); 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci return (data >> bank_pin_num) & 1; 25662306a36Sopenharmony_ci} 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci/** 25962306a36Sopenharmony_ci * zynq_gpio_set_value - Modify the state of the pin with specified value 26062306a36Sopenharmony_ci * @chip: gpio_chip instance to be worked on 26162306a36Sopenharmony_ci * @pin: gpio pin number within the device 26262306a36Sopenharmony_ci * @state: value used to modify the state of the specified pin 26362306a36Sopenharmony_ci * 26462306a36Sopenharmony_ci * This function calculates the register offset (i.e to lower 16 bits or 26562306a36Sopenharmony_ci * upper 16 bits) based on the given pin number and sets the state of a 26662306a36Sopenharmony_ci * gpio pin to the specified value. The state is either 0 or non-zero. 26762306a36Sopenharmony_ci */ 26862306a36Sopenharmony_cistatic void zynq_gpio_set_value(struct gpio_chip *chip, unsigned int pin, 26962306a36Sopenharmony_ci int state) 27062306a36Sopenharmony_ci{ 27162306a36Sopenharmony_ci unsigned int reg_offset, bank_num, bank_pin_num; 27262306a36Sopenharmony_ci struct zynq_gpio *gpio = gpiochip_get_data(chip); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio); 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci if (bank_pin_num >= ZYNQ_GPIO_MID_PIN_NUM) { 27762306a36Sopenharmony_ci /* only 16 data bits in bit maskable reg */ 27862306a36Sopenharmony_ci bank_pin_num -= ZYNQ_GPIO_MID_PIN_NUM; 27962306a36Sopenharmony_ci reg_offset = ZYNQ_GPIO_DATA_MSW_OFFSET(bank_num); 28062306a36Sopenharmony_ci } else { 28162306a36Sopenharmony_ci reg_offset = ZYNQ_GPIO_DATA_LSW_OFFSET(bank_num); 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci /* 28562306a36Sopenharmony_ci * get the 32 bit value to be written to the mask/data register where 28662306a36Sopenharmony_ci * the upper 16 bits is the mask and lower 16 bits is the data 28762306a36Sopenharmony_ci */ 28862306a36Sopenharmony_ci state = !!state; 28962306a36Sopenharmony_ci state = ~(1 << (bank_pin_num + ZYNQ_GPIO_MID_PIN_NUM)) & 29062306a36Sopenharmony_ci ((state << bank_pin_num) | ZYNQ_GPIO_UPPER_MASK); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci writel_relaxed(state, gpio->base_addr + reg_offset); 29362306a36Sopenharmony_ci} 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci/** 29662306a36Sopenharmony_ci * zynq_gpio_dir_in - Set the direction of the specified GPIO pin as input 29762306a36Sopenharmony_ci * @chip: gpio_chip instance to be worked on 29862306a36Sopenharmony_ci * @pin: gpio pin number within the device 29962306a36Sopenharmony_ci * 30062306a36Sopenharmony_ci * This function uses the read-modify-write sequence to set the direction of 30162306a36Sopenharmony_ci * the gpio pin as input. 30262306a36Sopenharmony_ci * 30362306a36Sopenharmony_ci * Return: 0 always 30462306a36Sopenharmony_ci */ 30562306a36Sopenharmony_cistatic int zynq_gpio_dir_in(struct gpio_chip *chip, unsigned int pin) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci u32 reg; 30862306a36Sopenharmony_ci unsigned int bank_num, bank_pin_num; 30962306a36Sopenharmony_ci unsigned long flags; 31062306a36Sopenharmony_ci struct zynq_gpio *gpio = gpiochip_get_data(chip); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci /* 31562306a36Sopenharmony_ci * On zynq bank 0 pins 7 and 8 are special and cannot be used 31662306a36Sopenharmony_ci * as inputs. 31762306a36Sopenharmony_ci */ 31862306a36Sopenharmony_ci if (zynq_gpio_is_zynq(gpio) && bank_num == 0 && 31962306a36Sopenharmony_ci (bank_pin_num == 7 || bank_pin_num == 8)) 32062306a36Sopenharmony_ci return -EINVAL; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci /* clear the bit in direction mode reg to set the pin as input */ 32362306a36Sopenharmony_ci spin_lock_irqsave(&gpio->dirlock, flags); 32462306a36Sopenharmony_ci reg = readl_relaxed(gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num)); 32562306a36Sopenharmony_ci reg &= ~BIT(bank_pin_num); 32662306a36Sopenharmony_ci writel_relaxed(reg, gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num)); 32762306a36Sopenharmony_ci spin_unlock_irqrestore(&gpio->dirlock, flags); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci return 0; 33062306a36Sopenharmony_ci} 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci/** 33362306a36Sopenharmony_ci * zynq_gpio_dir_out - Set the direction of the specified GPIO pin as output 33462306a36Sopenharmony_ci * @chip: gpio_chip instance to be worked on 33562306a36Sopenharmony_ci * @pin: gpio pin number within the device 33662306a36Sopenharmony_ci * @state: value to be written to specified pin 33762306a36Sopenharmony_ci * 33862306a36Sopenharmony_ci * This function sets the direction of specified GPIO pin as output, configures 33962306a36Sopenharmony_ci * the Output Enable register for the pin and uses zynq_gpio_set to set 34062306a36Sopenharmony_ci * the state of the pin to the value specified. 34162306a36Sopenharmony_ci * 34262306a36Sopenharmony_ci * Return: 0 always 34362306a36Sopenharmony_ci */ 34462306a36Sopenharmony_cistatic int zynq_gpio_dir_out(struct gpio_chip *chip, unsigned int pin, 34562306a36Sopenharmony_ci int state) 34662306a36Sopenharmony_ci{ 34762306a36Sopenharmony_ci u32 reg; 34862306a36Sopenharmony_ci unsigned int bank_num, bank_pin_num; 34962306a36Sopenharmony_ci unsigned long flags; 35062306a36Sopenharmony_ci struct zynq_gpio *gpio = gpiochip_get_data(chip); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci /* set the GPIO pin as output */ 35562306a36Sopenharmony_ci spin_lock_irqsave(&gpio->dirlock, flags); 35662306a36Sopenharmony_ci reg = readl_relaxed(gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num)); 35762306a36Sopenharmony_ci reg |= BIT(bank_pin_num); 35862306a36Sopenharmony_ci writel_relaxed(reg, gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num)); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci /* configure the output enable reg for the pin */ 36162306a36Sopenharmony_ci reg = readl_relaxed(gpio->base_addr + ZYNQ_GPIO_OUTEN_OFFSET(bank_num)); 36262306a36Sopenharmony_ci reg |= BIT(bank_pin_num); 36362306a36Sopenharmony_ci writel_relaxed(reg, gpio->base_addr + ZYNQ_GPIO_OUTEN_OFFSET(bank_num)); 36462306a36Sopenharmony_ci spin_unlock_irqrestore(&gpio->dirlock, flags); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci /* set the state of the pin */ 36762306a36Sopenharmony_ci zynq_gpio_set_value(chip, pin, state); 36862306a36Sopenharmony_ci return 0; 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci/** 37262306a36Sopenharmony_ci * zynq_gpio_get_direction - Read the direction of the specified GPIO pin 37362306a36Sopenharmony_ci * @chip: gpio_chip instance to be worked on 37462306a36Sopenharmony_ci * @pin: gpio pin number within the device 37562306a36Sopenharmony_ci * 37662306a36Sopenharmony_ci * This function returns the direction of the specified GPIO. 37762306a36Sopenharmony_ci * 37862306a36Sopenharmony_ci * Return: GPIO_LINE_DIRECTION_OUT or GPIO_LINE_DIRECTION_IN 37962306a36Sopenharmony_ci */ 38062306a36Sopenharmony_cistatic int zynq_gpio_get_direction(struct gpio_chip *chip, unsigned int pin) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci u32 reg; 38362306a36Sopenharmony_ci unsigned int bank_num, bank_pin_num; 38462306a36Sopenharmony_ci struct zynq_gpio *gpio = gpiochip_get_data(chip); 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num, gpio); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci reg = readl_relaxed(gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num)); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci if (reg & BIT(bank_pin_num)) 39162306a36Sopenharmony_ci return GPIO_LINE_DIRECTION_OUT; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci return GPIO_LINE_DIRECTION_IN; 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci/** 39762306a36Sopenharmony_ci * zynq_gpio_irq_mask - Disable the interrupts for a gpio pin 39862306a36Sopenharmony_ci * @irq_data: per irq and chip data passed down to chip functions 39962306a36Sopenharmony_ci * 40062306a36Sopenharmony_ci * This function calculates gpio pin number from irq number and sets the 40162306a36Sopenharmony_ci * bit in the Interrupt Disable register of the corresponding bank to disable 40262306a36Sopenharmony_ci * interrupts for that pin. 40362306a36Sopenharmony_ci */ 40462306a36Sopenharmony_cistatic void zynq_gpio_irq_mask(struct irq_data *irq_data) 40562306a36Sopenharmony_ci{ 40662306a36Sopenharmony_ci unsigned int device_pin_num, bank_num, bank_pin_num; 40762306a36Sopenharmony_ci const unsigned long offset = irqd_to_hwirq(irq_data); 40862306a36Sopenharmony_ci struct gpio_chip *chip = irq_data_get_irq_chip_data(irq_data); 40962306a36Sopenharmony_ci struct zynq_gpio *gpio = 41062306a36Sopenharmony_ci gpiochip_get_data(irq_data_get_irq_chip_data(irq_data)); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci gpiochip_disable_irq(chip, offset); 41362306a36Sopenharmony_ci device_pin_num = irq_data->hwirq; 41462306a36Sopenharmony_ci zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num, gpio); 41562306a36Sopenharmony_ci writel_relaxed(BIT(bank_pin_num), 41662306a36Sopenharmony_ci gpio->base_addr + ZYNQ_GPIO_INTDIS_OFFSET(bank_num)); 41762306a36Sopenharmony_ci} 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci/** 42062306a36Sopenharmony_ci * zynq_gpio_irq_unmask - Enable the interrupts for a gpio pin 42162306a36Sopenharmony_ci * @irq_data: irq data containing irq number of gpio pin for the interrupt 42262306a36Sopenharmony_ci * to enable 42362306a36Sopenharmony_ci * 42462306a36Sopenharmony_ci * This function calculates the gpio pin number from irq number and sets the 42562306a36Sopenharmony_ci * bit in the Interrupt Enable register of the corresponding bank to enable 42662306a36Sopenharmony_ci * interrupts for that pin. 42762306a36Sopenharmony_ci */ 42862306a36Sopenharmony_cistatic void zynq_gpio_irq_unmask(struct irq_data *irq_data) 42962306a36Sopenharmony_ci{ 43062306a36Sopenharmony_ci unsigned int device_pin_num, bank_num, bank_pin_num; 43162306a36Sopenharmony_ci const unsigned long offset = irqd_to_hwirq(irq_data); 43262306a36Sopenharmony_ci struct gpio_chip *chip = irq_data_get_irq_chip_data(irq_data); 43362306a36Sopenharmony_ci struct zynq_gpio *gpio = 43462306a36Sopenharmony_ci gpiochip_get_data(irq_data_get_irq_chip_data(irq_data)); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci gpiochip_enable_irq(chip, offset); 43762306a36Sopenharmony_ci device_pin_num = irq_data->hwirq; 43862306a36Sopenharmony_ci zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num, gpio); 43962306a36Sopenharmony_ci writel_relaxed(BIT(bank_pin_num), 44062306a36Sopenharmony_ci gpio->base_addr + ZYNQ_GPIO_INTEN_OFFSET(bank_num)); 44162306a36Sopenharmony_ci} 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci/** 44462306a36Sopenharmony_ci * zynq_gpio_irq_ack - Acknowledge the interrupt of a gpio pin 44562306a36Sopenharmony_ci * @irq_data: irq data containing irq number of gpio pin for the interrupt 44662306a36Sopenharmony_ci * to ack 44762306a36Sopenharmony_ci * 44862306a36Sopenharmony_ci * This function calculates gpio pin number from irq number and sets the bit 44962306a36Sopenharmony_ci * in the Interrupt Status Register of the corresponding bank, to ACK the irq. 45062306a36Sopenharmony_ci */ 45162306a36Sopenharmony_cistatic void zynq_gpio_irq_ack(struct irq_data *irq_data) 45262306a36Sopenharmony_ci{ 45362306a36Sopenharmony_ci unsigned int device_pin_num, bank_num, bank_pin_num; 45462306a36Sopenharmony_ci struct zynq_gpio *gpio = 45562306a36Sopenharmony_ci gpiochip_get_data(irq_data_get_irq_chip_data(irq_data)); 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci device_pin_num = irq_data->hwirq; 45862306a36Sopenharmony_ci zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num, gpio); 45962306a36Sopenharmony_ci writel_relaxed(BIT(bank_pin_num), 46062306a36Sopenharmony_ci gpio->base_addr + ZYNQ_GPIO_INTSTS_OFFSET(bank_num)); 46162306a36Sopenharmony_ci} 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci/** 46462306a36Sopenharmony_ci * zynq_gpio_irq_enable - Enable the interrupts for a gpio pin 46562306a36Sopenharmony_ci * @irq_data: irq data containing irq number of gpio pin for the interrupt 46662306a36Sopenharmony_ci * to enable 46762306a36Sopenharmony_ci * 46862306a36Sopenharmony_ci * Clears the INTSTS bit and unmasks the given interrupt. 46962306a36Sopenharmony_ci */ 47062306a36Sopenharmony_cistatic void zynq_gpio_irq_enable(struct irq_data *irq_data) 47162306a36Sopenharmony_ci{ 47262306a36Sopenharmony_ci /* 47362306a36Sopenharmony_ci * The Zynq GPIO controller does not disable interrupt detection when 47462306a36Sopenharmony_ci * the interrupt is masked and only disables the propagation of the 47562306a36Sopenharmony_ci * interrupt. This means when the controller detects an interrupt 47662306a36Sopenharmony_ci * condition while the interrupt is logically disabled it will propagate 47762306a36Sopenharmony_ci * that interrupt event once the interrupt is enabled. This will cause 47862306a36Sopenharmony_ci * the interrupt consumer to see spurious interrupts to prevent this 47962306a36Sopenharmony_ci * first make sure that the interrupt is not asserted and then enable 48062306a36Sopenharmony_ci * it. 48162306a36Sopenharmony_ci */ 48262306a36Sopenharmony_ci zynq_gpio_irq_ack(irq_data); 48362306a36Sopenharmony_ci zynq_gpio_irq_unmask(irq_data); 48462306a36Sopenharmony_ci} 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci/** 48762306a36Sopenharmony_ci * zynq_gpio_set_irq_type - Set the irq type for a gpio pin 48862306a36Sopenharmony_ci * @irq_data: irq data containing irq number of gpio pin 48962306a36Sopenharmony_ci * @type: interrupt type that is to be set for the gpio pin 49062306a36Sopenharmony_ci * 49162306a36Sopenharmony_ci * This function gets the gpio pin number and its bank from the gpio pin number 49262306a36Sopenharmony_ci * and configures the INT_TYPE, INT_POLARITY and INT_ANY registers. 49362306a36Sopenharmony_ci * 49462306a36Sopenharmony_ci * Return: 0, negative error otherwise. 49562306a36Sopenharmony_ci * TYPE-EDGE_RISING, INT_TYPE - 1, INT_POLARITY - 1, INT_ANY - 0; 49662306a36Sopenharmony_ci * TYPE-EDGE_FALLING, INT_TYPE - 1, INT_POLARITY - 0, INT_ANY - 0; 49762306a36Sopenharmony_ci * TYPE-EDGE_BOTH, INT_TYPE - 1, INT_POLARITY - NA, INT_ANY - 1; 49862306a36Sopenharmony_ci * TYPE-LEVEL_HIGH, INT_TYPE - 0, INT_POLARITY - 1, INT_ANY - NA; 49962306a36Sopenharmony_ci * TYPE-LEVEL_LOW, INT_TYPE - 0, INT_POLARITY - 0, INT_ANY - NA 50062306a36Sopenharmony_ci */ 50162306a36Sopenharmony_cistatic int zynq_gpio_set_irq_type(struct irq_data *irq_data, unsigned int type) 50262306a36Sopenharmony_ci{ 50362306a36Sopenharmony_ci u32 int_type, int_pol, int_any; 50462306a36Sopenharmony_ci unsigned int device_pin_num, bank_num, bank_pin_num; 50562306a36Sopenharmony_ci struct zynq_gpio *gpio = 50662306a36Sopenharmony_ci gpiochip_get_data(irq_data_get_irq_chip_data(irq_data)); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci device_pin_num = irq_data->hwirq; 50962306a36Sopenharmony_ci zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num, gpio); 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci int_type = readl_relaxed(gpio->base_addr + 51262306a36Sopenharmony_ci ZYNQ_GPIO_INTTYPE_OFFSET(bank_num)); 51362306a36Sopenharmony_ci int_pol = readl_relaxed(gpio->base_addr + 51462306a36Sopenharmony_ci ZYNQ_GPIO_INTPOL_OFFSET(bank_num)); 51562306a36Sopenharmony_ci int_any = readl_relaxed(gpio->base_addr + 51662306a36Sopenharmony_ci ZYNQ_GPIO_INTANY_OFFSET(bank_num)); 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci /* 51962306a36Sopenharmony_ci * based on the type requested, configure the INT_TYPE, INT_POLARITY 52062306a36Sopenharmony_ci * and INT_ANY registers 52162306a36Sopenharmony_ci */ 52262306a36Sopenharmony_ci switch (type) { 52362306a36Sopenharmony_ci case IRQ_TYPE_EDGE_RISING: 52462306a36Sopenharmony_ci int_type |= BIT(bank_pin_num); 52562306a36Sopenharmony_ci int_pol |= BIT(bank_pin_num); 52662306a36Sopenharmony_ci int_any &= ~BIT(bank_pin_num); 52762306a36Sopenharmony_ci break; 52862306a36Sopenharmony_ci case IRQ_TYPE_EDGE_FALLING: 52962306a36Sopenharmony_ci int_type |= BIT(bank_pin_num); 53062306a36Sopenharmony_ci int_pol &= ~BIT(bank_pin_num); 53162306a36Sopenharmony_ci int_any &= ~BIT(bank_pin_num); 53262306a36Sopenharmony_ci break; 53362306a36Sopenharmony_ci case IRQ_TYPE_EDGE_BOTH: 53462306a36Sopenharmony_ci int_type |= BIT(bank_pin_num); 53562306a36Sopenharmony_ci int_any |= BIT(bank_pin_num); 53662306a36Sopenharmony_ci break; 53762306a36Sopenharmony_ci case IRQ_TYPE_LEVEL_HIGH: 53862306a36Sopenharmony_ci int_type &= ~BIT(bank_pin_num); 53962306a36Sopenharmony_ci int_pol |= BIT(bank_pin_num); 54062306a36Sopenharmony_ci break; 54162306a36Sopenharmony_ci case IRQ_TYPE_LEVEL_LOW: 54262306a36Sopenharmony_ci int_type &= ~BIT(bank_pin_num); 54362306a36Sopenharmony_ci int_pol &= ~BIT(bank_pin_num); 54462306a36Sopenharmony_ci break; 54562306a36Sopenharmony_ci default: 54662306a36Sopenharmony_ci return -EINVAL; 54762306a36Sopenharmony_ci } 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci writel_relaxed(int_type, 55062306a36Sopenharmony_ci gpio->base_addr + ZYNQ_GPIO_INTTYPE_OFFSET(bank_num)); 55162306a36Sopenharmony_ci writel_relaxed(int_pol, 55262306a36Sopenharmony_ci gpio->base_addr + ZYNQ_GPIO_INTPOL_OFFSET(bank_num)); 55362306a36Sopenharmony_ci writel_relaxed(int_any, 55462306a36Sopenharmony_ci gpio->base_addr + ZYNQ_GPIO_INTANY_OFFSET(bank_num)); 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci if (type & IRQ_TYPE_LEVEL_MASK) 55762306a36Sopenharmony_ci irq_set_chip_handler_name_locked(irq_data, 55862306a36Sopenharmony_ci &zynq_gpio_level_irqchip, 55962306a36Sopenharmony_ci handle_fasteoi_irq, NULL); 56062306a36Sopenharmony_ci else 56162306a36Sopenharmony_ci irq_set_chip_handler_name_locked(irq_data, 56262306a36Sopenharmony_ci &zynq_gpio_edge_irqchip, 56362306a36Sopenharmony_ci handle_level_irq, NULL); 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci return 0; 56662306a36Sopenharmony_ci} 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_cistatic int zynq_gpio_set_wake(struct irq_data *data, unsigned int on) 56962306a36Sopenharmony_ci{ 57062306a36Sopenharmony_ci struct zynq_gpio *gpio = 57162306a36Sopenharmony_ci gpiochip_get_data(irq_data_get_irq_chip_data(data)); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci irq_set_irq_wake(gpio->irq, on); 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci return 0; 57662306a36Sopenharmony_ci} 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_cistatic int zynq_gpio_irq_reqres(struct irq_data *d) 57962306a36Sopenharmony_ci{ 58062306a36Sopenharmony_ci struct gpio_chip *chip = irq_data_get_irq_chip_data(d); 58162306a36Sopenharmony_ci int ret; 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci ret = pm_runtime_resume_and_get(chip->parent); 58462306a36Sopenharmony_ci if (ret < 0) 58562306a36Sopenharmony_ci return ret; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci return gpiochip_reqres_irq(chip, d->hwirq); 58862306a36Sopenharmony_ci} 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_cistatic void zynq_gpio_irq_relres(struct irq_data *d) 59162306a36Sopenharmony_ci{ 59262306a36Sopenharmony_ci struct gpio_chip *chip = irq_data_get_irq_chip_data(d); 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci gpiochip_relres_irq(chip, d->hwirq); 59562306a36Sopenharmony_ci pm_runtime_put(chip->parent); 59662306a36Sopenharmony_ci} 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci/* irq chip descriptor */ 59962306a36Sopenharmony_cistatic const struct irq_chip zynq_gpio_level_irqchip = { 60062306a36Sopenharmony_ci .name = DRIVER_NAME, 60162306a36Sopenharmony_ci .irq_enable = zynq_gpio_irq_enable, 60262306a36Sopenharmony_ci .irq_eoi = zynq_gpio_irq_ack, 60362306a36Sopenharmony_ci .irq_mask = zynq_gpio_irq_mask, 60462306a36Sopenharmony_ci .irq_unmask = zynq_gpio_irq_unmask, 60562306a36Sopenharmony_ci .irq_set_type = zynq_gpio_set_irq_type, 60662306a36Sopenharmony_ci .irq_set_wake = zynq_gpio_set_wake, 60762306a36Sopenharmony_ci .irq_request_resources = zynq_gpio_irq_reqres, 60862306a36Sopenharmony_ci .irq_release_resources = zynq_gpio_irq_relres, 60962306a36Sopenharmony_ci .flags = IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED | 61062306a36Sopenharmony_ci IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_IMMUTABLE, 61162306a36Sopenharmony_ci}; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_cistatic const struct irq_chip zynq_gpio_edge_irqchip = { 61462306a36Sopenharmony_ci .name = DRIVER_NAME, 61562306a36Sopenharmony_ci .irq_enable = zynq_gpio_irq_enable, 61662306a36Sopenharmony_ci .irq_ack = zynq_gpio_irq_ack, 61762306a36Sopenharmony_ci .irq_mask = zynq_gpio_irq_mask, 61862306a36Sopenharmony_ci .irq_unmask = zynq_gpio_irq_unmask, 61962306a36Sopenharmony_ci .irq_set_type = zynq_gpio_set_irq_type, 62062306a36Sopenharmony_ci .irq_set_wake = zynq_gpio_set_wake, 62162306a36Sopenharmony_ci .irq_request_resources = zynq_gpio_irq_reqres, 62262306a36Sopenharmony_ci .irq_release_resources = zynq_gpio_irq_relres, 62362306a36Sopenharmony_ci .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_IMMUTABLE, 62462306a36Sopenharmony_ci}; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_cistatic void zynq_gpio_handle_bank_irq(struct zynq_gpio *gpio, 62762306a36Sopenharmony_ci unsigned int bank_num, 62862306a36Sopenharmony_ci unsigned long pending) 62962306a36Sopenharmony_ci{ 63062306a36Sopenharmony_ci unsigned int bank_offset = gpio->p_data->bank_min[bank_num]; 63162306a36Sopenharmony_ci struct irq_domain *irqdomain = gpio->chip.irq.domain; 63262306a36Sopenharmony_ci int offset; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci if (!pending) 63562306a36Sopenharmony_ci return; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci for_each_set_bit(offset, &pending, 32) 63862306a36Sopenharmony_ci generic_handle_domain_irq(irqdomain, offset + bank_offset); 63962306a36Sopenharmony_ci} 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci/** 64262306a36Sopenharmony_ci * zynq_gpio_irqhandler - IRQ handler for the gpio banks of a gpio device 64362306a36Sopenharmony_ci * @desc: irq descriptor instance of the 'irq' 64462306a36Sopenharmony_ci * 64562306a36Sopenharmony_ci * This function reads the Interrupt Status Register of each bank to get the 64662306a36Sopenharmony_ci * gpio pin number which has triggered an interrupt. It then acks the triggered 64762306a36Sopenharmony_ci * interrupt and calls the pin specific handler set by the higher layer 64862306a36Sopenharmony_ci * application for that pin. 64962306a36Sopenharmony_ci * Note: A bug is reported if no handler is set for the gpio pin. 65062306a36Sopenharmony_ci */ 65162306a36Sopenharmony_cistatic void zynq_gpio_irqhandler(struct irq_desc *desc) 65262306a36Sopenharmony_ci{ 65362306a36Sopenharmony_ci u32 int_sts, int_enb; 65462306a36Sopenharmony_ci unsigned int bank_num; 65562306a36Sopenharmony_ci struct zynq_gpio *gpio = 65662306a36Sopenharmony_ci gpiochip_get_data(irq_desc_get_handler_data(desc)); 65762306a36Sopenharmony_ci struct irq_chip *irqchip = irq_desc_get_chip(desc); 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci chained_irq_enter(irqchip, desc); 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci for (bank_num = 0; bank_num < gpio->p_data->max_bank; bank_num++) { 66262306a36Sopenharmony_ci int_sts = readl_relaxed(gpio->base_addr + 66362306a36Sopenharmony_ci ZYNQ_GPIO_INTSTS_OFFSET(bank_num)); 66462306a36Sopenharmony_ci int_enb = readl_relaxed(gpio->base_addr + 66562306a36Sopenharmony_ci ZYNQ_GPIO_INTMASK_OFFSET(bank_num)); 66662306a36Sopenharmony_ci zynq_gpio_handle_bank_irq(gpio, bank_num, int_sts & ~int_enb); 66762306a36Sopenharmony_ci if (gpio->p_data->quirks & GPIO_QUIRK_VERSAL) 66862306a36Sopenharmony_ci bank_num = bank_num + VERSAL_UNUSED_BANKS; 66962306a36Sopenharmony_ci } 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci chained_irq_exit(irqchip, desc); 67262306a36Sopenharmony_ci} 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_cistatic void zynq_gpio_save_context(struct zynq_gpio *gpio) 67562306a36Sopenharmony_ci{ 67662306a36Sopenharmony_ci unsigned int bank_num; 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci for (bank_num = 0; bank_num < gpio->p_data->max_bank; bank_num++) { 67962306a36Sopenharmony_ci gpio->context.datalsw[bank_num] = 68062306a36Sopenharmony_ci readl_relaxed(gpio->base_addr + 68162306a36Sopenharmony_ci ZYNQ_GPIO_DATA_LSW_OFFSET(bank_num)); 68262306a36Sopenharmony_ci gpio->context.datamsw[bank_num] = 68362306a36Sopenharmony_ci readl_relaxed(gpio->base_addr + 68462306a36Sopenharmony_ci ZYNQ_GPIO_DATA_MSW_OFFSET(bank_num)); 68562306a36Sopenharmony_ci gpio->context.dirm[bank_num] = readl_relaxed(gpio->base_addr + 68662306a36Sopenharmony_ci ZYNQ_GPIO_DIRM_OFFSET(bank_num)); 68762306a36Sopenharmony_ci gpio->context.int_en[bank_num] = readl_relaxed(gpio->base_addr + 68862306a36Sopenharmony_ci ZYNQ_GPIO_INTMASK_OFFSET(bank_num)); 68962306a36Sopenharmony_ci gpio->context.int_type[bank_num] = 69062306a36Sopenharmony_ci readl_relaxed(gpio->base_addr + 69162306a36Sopenharmony_ci ZYNQ_GPIO_INTTYPE_OFFSET(bank_num)); 69262306a36Sopenharmony_ci gpio->context.int_polarity[bank_num] = 69362306a36Sopenharmony_ci readl_relaxed(gpio->base_addr + 69462306a36Sopenharmony_ci ZYNQ_GPIO_INTPOL_OFFSET(bank_num)); 69562306a36Sopenharmony_ci gpio->context.int_any[bank_num] = 69662306a36Sopenharmony_ci readl_relaxed(gpio->base_addr + 69762306a36Sopenharmony_ci ZYNQ_GPIO_INTANY_OFFSET(bank_num)); 69862306a36Sopenharmony_ci if (gpio->p_data->quirks & GPIO_QUIRK_VERSAL) 69962306a36Sopenharmony_ci bank_num = bank_num + VERSAL_UNUSED_BANKS; 70062306a36Sopenharmony_ci } 70162306a36Sopenharmony_ci} 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_cistatic void zynq_gpio_restore_context(struct zynq_gpio *gpio) 70462306a36Sopenharmony_ci{ 70562306a36Sopenharmony_ci unsigned int bank_num; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci for (bank_num = 0; bank_num < gpio->p_data->max_bank; bank_num++) { 70862306a36Sopenharmony_ci writel_relaxed(ZYNQ_GPIO_IXR_DISABLE_ALL, gpio->base_addr + 70962306a36Sopenharmony_ci ZYNQ_GPIO_INTDIS_OFFSET(bank_num)); 71062306a36Sopenharmony_ci writel_relaxed(gpio->context.datalsw[bank_num], 71162306a36Sopenharmony_ci gpio->base_addr + 71262306a36Sopenharmony_ci ZYNQ_GPIO_DATA_LSW_OFFSET(bank_num)); 71362306a36Sopenharmony_ci writel_relaxed(gpio->context.datamsw[bank_num], 71462306a36Sopenharmony_ci gpio->base_addr + 71562306a36Sopenharmony_ci ZYNQ_GPIO_DATA_MSW_OFFSET(bank_num)); 71662306a36Sopenharmony_ci writel_relaxed(gpio->context.dirm[bank_num], 71762306a36Sopenharmony_ci gpio->base_addr + 71862306a36Sopenharmony_ci ZYNQ_GPIO_DIRM_OFFSET(bank_num)); 71962306a36Sopenharmony_ci writel_relaxed(gpio->context.int_type[bank_num], 72062306a36Sopenharmony_ci gpio->base_addr + 72162306a36Sopenharmony_ci ZYNQ_GPIO_INTTYPE_OFFSET(bank_num)); 72262306a36Sopenharmony_ci writel_relaxed(gpio->context.int_polarity[bank_num], 72362306a36Sopenharmony_ci gpio->base_addr + 72462306a36Sopenharmony_ci ZYNQ_GPIO_INTPOL_OFFSET(bank_num)); 72562306a36Sopenharmony_ci writel_relaxed(gpio->context.int_any[bank_num], 72662306a36Sopenharmony_ci gpio->base_addr + 72762306a36Sopenharmony_ci ZYNQ_GPIO_INTANY_OFFSET(bank_num)); 72862306a36Sopenharmony_ci writel_relaxed(~(gpio->context.int_en[bank_num]), 72962306a36Sopenharmony_ci gpio->base_addr + 73062306a36Sopenharmony_ci ZYNQ_GPIO_INTEN_OFFSET(bank_num)); 73162306a36Sopenharmony_ci if (gpio->p_data->quirks & GPIO_QUIRK_VERSAL) 73262306a36Sopenharmony_ci bank_num = bank_num + VERSAL_UNUSED_BANKS; 73362306a36Sopenharmony_ci } 73462306a36Sopenharmony_ci} 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_cistatic int __maybe_unused zynq_gpio_suspend(struct device *dev) 73762306a36Sopenharmony_ci{ 73862306a36Sopenharmony_ci struct zynq_gpio *gpio = dev_get_drvdata(dev); 73962306a36Sopenharmony_ci struct irq_data *data = irq_get_irq_data(gpio->irq); 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci if (!data) { 74262306a36Sopenharmony_ci dev_err(dev, "irq_get_irq_data() failed\n"); 74362306a36Sopenharmony_ci return -EINVAL; 74462306a36Sopenharmony_ci } 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci if (!device_may_wakeup(dev)) 74762306a36Sopenharmony_ci disable_irq(gpio->irq); 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci if (!irqd_is_wakeup_set(data)) { 75062306a36Sopenharmony_ci zynq_gpio_save_context(gpio); 75162306a36Sopenharmony_ci return pm_runtime_force_suspend(dev); 75262306a36Sopenharmony_ci } 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci return 0; 75562306a36Sopenharmony_ci} 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_cistatic int __maybe_unused zynq_gpio_resume(struct device *dev) 75862306a36Sopenharmony_ci{ 75962306a36Sopenharmony_ci struct zynq_gpio *gpio = dev_get_drvdata(dev); 76062306a36Sopenharmony_ci struct irq_data *data = irq_get_irq_data(gpio->irq); 76162306a36Sopenharmony_ci int ret; 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci if (!data) { 76462306a36Sopenharmony_ci dev_err(dev, "irq_get_irq_data() failed\n"); 76562306a36Sopenharmony_ci return -EINVAL; 76662306a36Sopenharmony_ci } 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci if (!device_may_wakeup(dev)) 76962306a36Sopenharmony_ci enable_irq(gpio->irq); 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci if (!irqd_is_wakeup_set(data)) { 77262306a36Sopenharmony_ci ret = pm_runtime_force_resume(dev); 77362306a36Sopenharmony_ci zynq_gpio_restore_context(gpio); 77462306a36Sopenharmony_ci return ret; 77562306a36Sopenharmony_ci } 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci return 0; 77862306a36Sopenharmony_ci} 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_cistatic int __maybe_unused zynq_gpio_runtime_suspend(struct device *dev) 78162306a36Sopenharmony_ci{ 78262306a36Sopenharmony_ci struct zynq_gpio *gpio = dev_get_drvdata(dev); 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci clk_disable_unprepare(gpio->clk); 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci return 0; 78762306a36Sopenharmony_ci} 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_cistatic int __maybe_unused zynq_gpio_runtime_resume(struct device *dev) 79062306a36Sopenharmony_ci{ 79162306a36Sopenharmony_ci struct zynq_gpio *gpio = dev_get_drvdata(dev); 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci return clk_prepare_enable(gpio->clk); 79462306a36Sopenharmony_ci} 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_cistatic int zynq_gpio_request(struct gpio_chip *chip, unsigned int offset) 79762306a36Sopenharmony_ci{ 79862306a36Sopenharmony_ci int ret; 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci ret = pm_runtime_get_sync(chip->parent); 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci /* 80362306a36Sopenharmony_ci * If the device is already active pm_runtime_get() will return 1 on 80462306a36Sopenharmony_ci * success, but gpio_request still needs to return 0. 80562306a36Sopenharmony_ci */ 80662306a36Sopenharmony_ci return ret < 0 ? ret : 0; 80762306a36Sopenharmony_ci} 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_cistatic void zynq_gpio_free(struct gpio_chip *chip, unsigned int offset) 81062306a36Sopenharmony_ci{ 81162306a36Sopenharmony_ci pm_runtime_put(chip->parent); 81262306a36Sopenharmony_ci} 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_cistatic const struct dev_pm_ops zynq_gpio_dev_pm_ops = { 81562306a36Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(zynq_gpio_suspend, zynq_gpio_resume) 81662306a36Sopenharmony_ci SET_RUNTIME_PM_OPS(zynq_gpio_runtime_suspend, 81762306a36Sopenharmony_ci zynq_gpio_runtime_resume, NULL) 81862306a36Sopenharmony_ci}; 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_cistatic const struct zynq_platform_data versal_gpio_def = { 82162306a36Sopenharmony_ci .label = "versal_gpio", 82262306a36Sopenharmony_ci .quirks = GPIO_QUIRK_VERSAL, 82362306a36Sopenharmony_ci .ngpio = 58, 82462306a36Sopenharmony_ci .max_bank = VERSAL_GPIO_MAX_BANK, 82562306a36Sopenharmony_ci .bank_min[0] = 0, 82662306a36Sopenharmony_ci .bank_max[0] = 25, /* 0 to 25 are connected to MIOs (26 pins) */ 82762306a36Sopenharmony_ci .bank_min[3] = 26, 82862306a36Sopenharmony_ci .bank_max[3] = 57, /* Bank 3 is connected to FMIOs (32 pins) */ 82962306a36Sopenharmony_ci}; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_cistatic const struct zynq_platform_data pmc_gpio_def = { 83262306a36Sopenharmony_ci .label = "pmc_gpio", 83362306a36Sopenharmony_ci .ngpio = 116, 83462306a36Sopenharmony_ci .max_bank = PMC_GPIO_MAX_BANK, 83562306a36Sopenharmony_ci .bank_min[0] = 0, 83662306a36Sopenharmony_ci .bank_max[0] = 25, /* 0 to 25 are connected to MIOs (26 pins) */ 83762306a36Sopenharmony_ci .bank_min[1] = 26, 83862306a36Sopenharmony_ci .bank_max[1] = 51, /* Bank 1 are connected to MIOs (26 pins) */ 83962306a36Sopenharmony_ci .bank_min[3] = 52, 84062306a36Sopenharmony_ci .bank_max[3] = 83, /* Bank 3 is connected to EMIOs (32 pins) */ 84162306a36Sopenharmony_ci .bank_min[4] = 84, 84262306a36Sopenharmony_ci .bank_max[4] = 115, /* Bank 4 is connected to EMIOs (32 pins) */ 84362306a36Sopenharmony_ci}; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_cistatic const struct zynq_platform_data zynqmp_gpio_def = { 84662306a36Sopenharmony_ci .label = "zynqmp_gpio", 84762306a36Sopenharmony_ci .quirks = GPIO_QUIRK_DATA_RO_BUG, 84862306a36Sopenharmony_ci .ngpio = ZYNQMP_GPIO_NR_GPIOS, 84962306a36Sopenharmony_ci .max_bank = ZYNQMP_GPIO_MAX_BANK, 85062306a36Sopenharmony_ci .bank_min[0] = ZYNQ_GPIO_BANK0_PIN_MIN(MP), 85162306a36Sopenharmony_ci .bank_max[0] = ZYNQ_GPIO_BANK0_PIN_MAX(MP), 85262306a36Sopenharmony_ci .bank_min[1] = ZYNQ_GPIO_BANK1_PIN_MIN(MP), 85362306a36Sopenharmony_ci .bank_max[1] = ZYNQ_GPIO_BANK1_PIN_MAX(MP), 85462306a36Sopenharmony_ci .bank_min[2] = ZYNQ_GPIO_BANK2_PIN_MIN(MP), 85562306a36Sopenharmony_ci .bank_max[2] = ZYNQ_GPIO_BANK2_PIN_MAX(MP), 85662306a36Sopenharmony_ci .bank_min[3] = ZYNQ_GPIO_BANK3_PIN_MIN(MP), 85762306a36Sopenharmony_ci .bank_max[3] = ZYNQ_GPIO_BANK3_PIN_MAX(MP), 85862306a36Sopenharmony_ci .bank_min[4] = ZYNQ_GPIO_BANK4_PIN_MIN(MP), 85962306a36Sopenharmony_ci .bank_max[4] = ZYNQ_GPIO_BANK4_PIN_MAX(MP), 86062306a36Sopenharmony_ci .bank_min[5] = ZYNQ_GPIO_BANK5_PIN_MIN(MP), 86162306a36Sopenharmony_ci .bank_max[5] = ZYNQ_GPIO_BANK5_PIN_MAX(MP), 86262306a36Sopenharmony_ci}; 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_cistatic const struct zynq_platform_data zynq_gpio_def = { 86562306a36Sopenharmony_ci .label = "zynq_gpio", 86662306a36Sopenharmony_ci .quirks = ZYNQ_GPIO_QUIRK_IS_ZYNQ | GPIO_QUIRK_DATA_RO_BUG, 86762306a36Sopenharmony_ci .ngpio = ZYNQ_GPIO_NR_GPIOS, 86862306a36Sopenharmony_ci .max_bank = ZYNQ_GPIO_MAX_BANK, 86962306a36Sopenharmony_ci .bank_min[0] = ZYNQ_GPIO_BANK0_PIN_MIN(), 87062306a36Sopenharmony_ci .bank_max[0] = ZYNQ_GPIO_BANK0_PIN_MAX(), 87162306a36Sopenharmony_ci .bank_min[1] = ZYNQ_GPIO_BANK1_PIN_MIN(), 87262306a36Sopenharmony_ci .bank_max[1] = ZYNQ_GPIO_BANK1_PIN_MAX(), 87362306a36Sopenharmony_ci .bank_min[2] = ZYNQ_GPIO_BANK2_PIN_MIN(), 87462306a36Sopenharmony_ci .bank_max[2] = ZYNQ_GPIO_BANK2_PIN_MAX(), 87562306a36Sopenharmony_ci .bank_min[3] = ZYNQ_GPIO_BANK3_PIN_MIN(), 87662306a36Sopenharmony_ci .bank_max[3] = ZYNQ_GPIO_BANK3_PIN_MAX(), 87762306a36Sopenharmony_ci}; 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_cistatic const struct of_device_id zynq_gpio_of_match[] = { 88062306a36Sopenharmony_ci { .compatible = "xlnx,zynq-gpio-1.0", .data = &zynq_gpio_def }, 88162306a36Sopenharmony_ci { .compatible = "xlnx,zynqmp-gpio-1.0", .data = &zynqmp_gpio_def }, 88262306a36Sopenharmony_ci { .compatible = "xlnx,versal-gpio-1.0", .data = &versal_gpio_def }, 88362306a36Sopenharmony_ci { .compatible = "xlnx,pmc-gpio-1.0", .data = &pmc_gpio_def }, 88462306a36Sopenharmony_ci { /* end of table */ } 88562306a36Sopenharmony_ci}; 88662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, zynq_gpio_of_match); 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci/** 88962306a36Sopenharmony_ci * zynq_gpio_probe - Initialization method for a zynq_gpio device 89062306a36Sopenharmony_ci * @pdev: platform device instance 89162306a36Sopenharmony_ci * 89262306a36Sopenharmony_ci * This function allocates memory resources for the gpio device and registers 89362306a36Sopenharmony_ci * all the banks of the device. It will also set up interrupts for the gpio 89462306a36Sopenharmony_ci * pins. 89562306a36Sopenharmony_ci * Note: Interrupts are disabled for all the banks during initialization. 89662306a36Sopenharmony_ci * 89762306a36Sopenharmony_ci * Return: 0 on success, negative error otherwise. 89862306a36Sopenharmony_ci */ 89962306a36Sopenharmony_cistatic int zynq_gpio_probe(struct platform_device *pdev) 90062306a36Sopenharmony_ci{ 90162306a36Sopenharmony_ci int ret, bank_num; 90262306a36Sopenharmony_ci struct zynq_gpio *gpio; 90362306a36Sopenharmony_ci struct gpio_chip *chip; 90462306a36Sopenharmony_ci struct gpio_irq_chip *girq; 90562306a36Sopenharmony_ci const struct of_device_id *match; 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); 90862306a36Sopenharmony_ci if (!gpio) 90962306a36Sopenharmony_ci return -ENOMEM; 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci match = of_match_node(zynq_gpio_of_match, pdev->dev.of_node); 91262306a36Sopenharmony_ci if (!match) { 91362306a36Sopenharmony_ci dev_err(&pdev->dev, "of_match_node() failed\n"); 91462306a36Sopenharmony_ci return -EINVAL; 91562306a36Sopenharmony_ci } 91662306a36Sopenharmony_ci gpio->p_data = match->data; 91762306a36Sopenharmony_ci platform_set_drvdata(pdev, gpio); 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci gpio->base_addr = devm_platform_ioremap_resource(pdev, 0); 92062306a36Sopenharmony_ci if (IS_ERR(gpio->base_addr)) 92162306a36Sopenharmony_ci return PTR_ERR(gpio->base_addr); 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci gpio->irq = platform_get_irq(pdev, 0); 92462306a36Sopenharmony_ci if (gpio->irq < 0) 92562306a36Sopenharmony_ci return gpio->irq; 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci /* configure the gpio chip */ 92862306a36Sopenharmony_ci chip = &gpio->chip; 92962306a36Sopenharmony_ci chip->label = gpio->p_data->label; 93062306a36Sopenharmony_ci chip->owner = THIS_MODULE; 93162306a36Sopenharmony_ci chip->parent = &pdev->dev; 93262306a36Sopenharmony_ci chip->get = zynq_gpio_get_value; 93362306a36Sopenharmony_ci chip->set = zynq_gpio_set_value; 93462306a36Sopenharmony_ci chip->request = zynq_gpio_request; 93562306a36Sopenharmony_ci chip->free = zynq_gpio_free; 93662306a36Sopenharmony_ci chip->direction_input = zynq_gpio_dir_in; 93762306a36Sopenharmony_ci chip->direction_output = zynq_gpio_dir_out; 93862306a36Sopenharmony_ci chip->get_direction = zynq_gpio_get_direction; 93962306a36Sopenharmony_ci chip->base = of_alias_get_id(pdev->dev.of_node, "gpio"); 94062306a36Sopenharmony_ci chip->ngpio = gpio->p_data->ngpio; 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci /* Retrieve GPIO clock */ 94362306a36Sopenharmony_ci gpio->clk = devm_clk_get(&pdev->dev, NULL); 94462306a36Sopenharmony_ci if (IS_ERR(gpio->clk)) 94562306a36Sopenharmony_ci return dev_err_probe(&pdev->dev, PTR_ERR(gpio->clk), "input clock not found.\n"); 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci ret = clk_prepare_enable(gpio->clk); 94862306a36Sopenharmony_ci if (ret) { 94962306a36Sopenharmony_ci dev_err(&pdev->dev, "Unable to enable clock.\n"); 95062306a36Sopenharmony_ci return ret; 95162306a36Sopenharmony_ci } 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci spin_lock_init(&gpio->dirlock); 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci pm_runtime_set_active(&pdev->dev); 95662306a36Sopenharmony_ci pm_runtime_enable(&pdev->dev); 95762306a36Sopenharmony_ci ret = pm_runtime_resume_and_get(&pdev->dev); 95862306a36Sopenharmony_ci if (ret < 0) 95962306a36Sopenharmony_ci goto err_pm_dis; 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci /* disable interrupts for all banks */ 96262306a36Sopenharmony_ci for (bank_num = 0; bank_num < gpio->p_data->max_bank; bank_num++) { 96362306a36Sopenharmony_ci writel_relaxed(ZYNQ_GPIO_IXR_DISABLE_ALL, gpio->base_addr + 96462306a36Sopenharmony_ci ZYNQ_GPIO_INTDIS_OFFSET(bank_num)); 96562306a36Sopenharmony_ci if (gpio->p_data->quirks & GPIO_QUIRK_VERSAL) 96662306a36Sopenharmony_ci bank_num = bank_num + VERSAL_UNUSED_BANKS; 96762306a36Sopenharmony_ci } 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci /* Set up the GPIO irqchip */ 97062306a36Sopenharmony_ci girq = &chip->irq; 97162306a36Sopenharmony_ci gpio_irq_chip_set_chip(girq, &zynq_gpio_edge_irqchip); 97262306a36Sopenharmony_ci girq->parent_handler = zynq_gpio_irqhandler; 97362306a36Sopenharmony_ci girq->num_parents = 1; 97462306a36Sopenharmony_ci girq->parents = devm_kcalloc(&pdev->dev, 1, 97562306a36Sopenharmony_ci sizeof(*girq->parents), 97662306a36Sopenharmony_ci GFP_KERNEL); 97762306a36Sopenharmony_ci if (!girq->parents) { 97862306a36Sopenharmony_ci ret = -ENOMEM; 97962306a36Sopenharmony_ci goto err_pm_put; 98062306a36Sopenharmony_ci } 98162306a36Sopenharmony_ci girq->parents[0] = gpio->irq; 98262306a36Sopenharmony_ci girq->default_type = IRQ_TYPE_NONE; 98362306a36Sopenharmony_ci girq->handler = handle_level_irq; 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci /* report a bug if gpio chip registration fails */ 98662306a36Sopenharmony_ci ret = gpiochip_add_data(chip, gpio); 98762306a36Sopenharmony_ci if (ret) { 98862306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to add gpio chip\n"); 98962306a36Sopenharmony_ci goto err_pm_put; 99062306a36Sopenharmony_ci } 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci irq_set_status_flags(gpio->irq, IRQ_DISABLE_UNLAZY); 99362306a36Sopenharmony_ci device_init_wakeup(&pdev->dev, 1); 99462306a36Sopenharmony_ci pm_runtime_put(&pdev->dev); 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci return 0; 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_cierr_pm_put: 99962306a36Sopenharmony_ci pm_runtime_put(&pdev->dev); 100062306a36Sopenharmony_cierr_pm_dis: 100162306a36Sopenharmony_ci pm_runtime_disable(&pdev->dev); 100262306a36Sopenharmony_ci clk_disable_unprepare(gpio->clk); 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci return ret; 100562306a36Sopenharmony_ci} 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci/** 100862306a36Sopenharmony_ci * zynq_gpio_remove - Driver removal function 100962306a36Sopenharmony_ci * @pdev: platform device instance 101062306a36Sopenharmony_ci * 101162306a36Sopenharmony_ci * Return: 0 always 101262306a36Sopenharmony_ci */ 101362306a36Sopenharmony_cistatic int zynq_gpio_remove(struct platform_device *pdev) 101462306a36Sopenharmony_ci{ 101562306a36Sopenharmony_ci struct zynq_gpio *gpio = platform_get_drvdata(pdev); 101662306a36Sopenharmony_ci int ret; 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci ret = pm_runtime_get_sync(&pdev->dev); 101962306a36Sopenharmony_ci if (ret < 0) 102062306a36Sopenharmony_ci dev_warn(&pdev->dev, "pm_runtime_get_sync() Failed\n"); 102162306a36Sopenharmony_ci gpiochip_remove(&gpio->chip); 102262306a36Sopenharmony_ci clk_disable_unprepare(gpio->clk); 102362306a36Sopenharmony_ci device_set_wakeup_capable(&pdev->dev, 0); 102462306a36Sopenharmony_ci pm_runtime_disable(&pdev->dev); 102562306a36Sopenharmony_ci return 0; 102662306a36Sopenharmony_ci} 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_cistatic struct platform_driver zynq_gpio_driver = { 102962306a36Sopenharmony_ci .driver = { 103062306a36Sopenharmony_ci .name = DRIVER_NAME, 103162306a36Sopenharmony_ci .pm = &zynq_gpio_dev_pm_ops, 103262306a36Sopenharmony_ci .of_match_table = zynq_gpio_of_match, 103362306a36Sopenharmony_ci }, 103462306a36Sopenharmony_ci .probe = zynq_gpio_probe, 103562306a36Sopenharmony_ci .remove = zynq_gpio_remove, 103662306a36Sopenharmony_ci}; 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_cimodule_platform_driver(zynq_gpio_driver); 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ciMODULE_AUTHOR("Xilinx Inc."); 104162306a36Sopenharmony_ciMODULE_DESCRIPTION("Zynq GPIO driver"); 104262306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 1043