18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (C) 2014-2017 Broadcom 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or 58c2ecf20Sopenharmony_ci * modify it under the terms of the GNU General Public License as 68c2ecf20Sopenharmony_ci * published by the Free Software Foundation version 2. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * This program is distributed "as is" WITHOUT ANY WARRANTY of any 98c2ecf20Sopenharmony_ci * kind, whether express or implied; without even the implied warranty 108c2ecf20Sopenharmony_ci * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 118c2ecf20Sopenharmony_ci * GNU General Public License for more details. 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci/* 158c2ecf20Sopenharmony_ci * This file contains the Broadcom Northstar Plus (NSP) GPIO driver that 168c2ecf20Sopenharmony_ci * supports the chipCommonA GPIO controller. Basic PINCONF such as bias, 178c2ecf20Sopenharmony_ci * pull up/down, slew and drive strength are also supported in this driver. 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * Pins from the chipCommonA GPIO can be individually muxed to GPIO function, 208c2ecf20Sopenharmony_ci * through the interaction with the NSP IOMUX controller. 218c2ecf20Sopenharmony_ci */ 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include <linux/gpio/driver.h> 248c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 258c2ecf20Sopenharmony_ci#include <linux/io.h> 268c2ecf20Sopenharmony_ci#include <linux/ioport.h> 278c2ecf20Sopenharmony_ci#include <linux/kernel.h> 288c2ecf20Sopenharmony_ci#include <linux/of_address.h> 298c2ecf20Sopenharmony_ci#include <linux/of_device.h> 308c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 318c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinconf.h> 328c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinconf-generic.h> 338c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinctrl.h> 348c2ecf20Sopenharmony_ci#include <linux/slab.h> 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#include "../pinctrl-utils.h" 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#define NSP_CHIP_A_INT_STATUS 0x00 398c2ecf20Sopenharmony_ci#define NSP_CHIP_A_INT_MASK 0x04 408c2ecf20Sopenharmony_ci#define NSP_GPIO_DATA_IN 0x40 418c2ecf20Sopenharmony_ci#define NSP_GPIO_DATA_OUT 0x44 428c2ecf20Sopenharmony_ci#define NSP_GPIO_OUT_EN 0x48 438c2ecf20Sopenharmony_ci#define NSP_GPIO_INT_POLARITY 0x50 448c2ecf20Sopenharmony_ci#define NSP_GPIO_INT_MASK 0x54 458c2ecf20Sopenharmony_ci#define NSP_GPIO_EVENT 0x58 468c2ecf20Sopenharmony_ci#define NSP_GPIO_EVENT_INT_MASK 0x5c 478c2ecf20Sopenharmony_ci#define NSP_GPIO_EVENT_INT_POLARITY 0x64 488c2ecf20Sopenharmony_ci#define NSP_CHIP_A_GPIO_INT_BIT 0x01 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci/* I/O parameters offset for chipcommon A GPIO */ 518c2ecf20Sopenharmony_ci#define NSP_GPIO_DRV_CTRL 0x00 528c2ecf20Sopenharmony_ci#define NSP_GPIO_HYSTERESIS_EN 0x10 538c2ecf20Sopenharmony_ci#define NSP_GPIO_SLEW_RATE_EN 0x14 548c2ecf20Sopenharmony_ci#define NSP_PULL_UP_EN 0x18 558c2ecf20Sopenharmony_ci#define NSP_PULL_DOWN_EN 0x1c 568c2ecf20Sopenharmony_ci#define GPIO_DRV_STRENGTH_BITS 0x03 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/* 598c2ecf20Sopenharmony_ci * nsp GPIO core 608c2ecf20Sopenharmony_ci * 618c2ecf20Sopenharmony_ci * @dev: pointer to device 628c2ecf20Sopenharmony_ci * @base: I/O register base for nsp GPIO controller 638c2ecf20Sopenharmony_ci * @io_ctrl: I/O register base for PINCONF support outside the GPIO block 648c2ecf20Sopenharmony_ci * @gc: GPIO chip 658c2ecf20Sopenharmony_ci * @pctl: pointer to pinctrl_dev 668c2ecf20Sopenharmony_ci * @pctldesc: pinctrl descriptor 678c2ecf20Sopenharmony_ci * @lock: lock to protect access to I/O registers 688c2ecf20Sopenharmony_ci */ 698c2ecf20Sopenharmony_cistruct nsp_gpio { 708c2ecf20Sopenharmony_ci struct device *dev; 718c2ecf20Sopenharmony_ci void __iomem *base; 728c2ecf20Sopenharmony_ci void __iomem *io_ctrl; 738c2ecf20Sopenharmony_ci struct irq_chip irqchip; 748c2ecf20Sopenharmony_ci struct gpio_chip gc; 758c2ecf20Sopenharmony_ci struct pinctrl_dev *pctl; 768c2ecf20Sopenharmony_ci struct pinctrl_desc pctldesc; 778c2ecf20Sopenharmony_ci raw_spinlock_t lock; 788c2ecf20Sopenharmony_ci}; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cienum base_type { 818c2ecf20Sopenharmony_ci REG, 828c2ecf20Sopenharmony_ci IO_CTRL 838c2ecf20Sopenharmony_ci}; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci/* 868c2ecf20Sopenharmony_ci * Mapping from PINCONF pins to GPIO pins is 1-to-1 878c2ecf20Sopenharmony_ci */ 888c2ecf20Sopenharmony_cistatic inline unsigned nsp_pin_to_gpio(unsigned pin) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci return pin; 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci/* 948c2ecf20Sopenharmony_ci * nsp_set_bit - set or clear one bit (corresponding to the GPIO pin) in a 958c2ecf20Sopenharmony_ci * nsp GPIO register 968c2ecf20Sopenharmony_ci * 978c2ecf20Sopenharmony_ci * @nsp_gpio: nsp GPIO device 988c2ecf20Sopenharmony_ci * @base_type: reg base to modify 998c2ecf20Sopenharmony_ci * @reg: register offset 1008c2ecf20Sopenharmony_ci * @gpio: GPIO pin 1018c2ecf20Sopenharmony_ci * @set: set or clear 1028c2ecf20Sopenharmony_ci */ 1038c2ecf20Sopenharmony_cistatic inline void nsp_set_bit(struct nsp_gpio *chip, enum base_type address, 1048c2ecf20Sopenharmony_ci unsigned int reg, unsigned gpio, bool set) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci u32 val; 1078c2ecf20Sopenharmony_ci void __iomem *base_address; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci if (address == IO_CTRL) 1108c2ecf20Sopenharmony_ci base_address = chip->io_ctrl; 1118c2ecf20Sopenharmony_ci else 1128c2ecf20Sopenharmony_ci base_address = chip->base; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci val = readl(base_address + reg); 1158c2ecf20Sopenharmony_ci if (set) 1168c2ecf20Sopenharmony_ci val |= BIT(gpio); 1178c2ecf20Sopenharmony_ci else 1188c2ecf20Sopenharmony_ci val &= ~BIT(gpio); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci writel(val, base_address + reg); 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci/* 1248c2ecf20Sopenharmony_ci * nsp_get_bit - get one bit (corresponding to the GPIO pin) in a 1258c2ecf20Sopenharmony_ci * nsp GPIO register 1268c2ecf20Sopenharmony_ci */ 1278c2ecf20Sopenharmony_cistatic inline bool nsp_get_bit(struct nsp_gpio *chip, enum base_type address, 1288c2ecf20Sopenharmony_ci unsigned int reg, unsigned gpio) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci if (address == IO_CTRL) 1318c2ecf20Sopenharmony_ci return !!(readl(chip->io_ctrl + reg) & BIT(gpio)); 1328c2ecf20Sopenharmony_ci else 1338c2ecf20Sopenharmony_ci return !!(readl(chip->base + reg) & BIT(gpio)); 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic irqreturn_t nsp_gpio_irq_handler(int irq, void *data) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci struct gpio_chip *gc = (struct gpio_chip *)data; 1398c2ecf20Sopenharmony_ci struct nsp_gpio *chip = gpiochip_get_data(gc); 1408c2ecf20Sopenharmony_ci int bit; 1418c2ecf20Sopenharmony_ci unsigned long int_bits = 0; 1428c2ecf20Sopenharmony_ci u32 int_status; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci /* go through the entire GPIOs and handle all interrupts */ 1458c2ecf20Sopenharmony_ci int_status = readl(chip->base + NSP_CHIP_A_INT_STATUS); 1468c2ecf20Sopenharmony_ci if (int_status & NSP_CHIP_A_GPIO_INT_BIT) { 1478c2ecf20Sopenharmony_ci unsigned int event, level; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci /* Get level and edge interrupts */ 1508c2ecf20Sopenharmony_ci event = readl(chip->base + NSP_GPIO_EVENT_INT_MASK) & 1518c2ecf20Sopenharmony_ci readl(chip->base + NSP_GPIO_EVENT); 1528c2ecf20Sopenharmony_ci level = readl(chip->base + NSP_GPIO_DATA_IN) ^ 1538c2ecf20Sopenharmony_ci readl(chip->base + NSP_GPIO_INT_POLARITY); 1548c2ecf20Sopenharmony_ci level &= readl(chip->base + NSP_GPIO_INT_MASK); 1558c2ecf20Sopenharmony_ci int_bits = level | event; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci for_each_set_bit(bit, &int_bits, gc->ngpio) 1588c2ecf20Sopenharmony_ci generic_handle_irq( 1598c2ecf20Sopenharmony_ci irq_linear_revmap(gc->irq.domain, bit)); 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci return int_bits ? IRQ_HANDLED : IRQ_NONE; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic void nsp_gpio_irq_ack(struct irq_data *d) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 1688c2ecf20Sopenharmony_ci struct nsp_gpio *chip = gpiochip_get_data(gc); 1698c2ecf20Sopenharmony_ci unsigned gpio = d->hwirq; 1708c2ecf20Sopenharmony_ci u32 val = BIT(gpio); 1718c2ecf20Sopenharmony_ci u32 trigger_type; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci trigger_type = irq_get_trigger_type(d->irq); 1748c2ecf20Sopenharmony_ci if (trigger_type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) 1758c2ecf20Sopenharmony_ci writel(val, chip->base + NSP_GPIO_EVENT); 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci/* 1798c2ecf20Sopenharmony_ci * nsp_gpio_irq_set_mask - mask/unmask a GPIO interrupt 1808c2ecf20Sopenharmony_ci * 1818c2ecf20Sopenharmony_ci * @d: IRQ chip data 1828c2ecf20Sopenharmony_ci * @unmask: mask/unmask GPIO interrupt 1838c2ecf20Sopenharmony_ci */ 1848c2ecf20Sopenharmony_cistatic void nsp_gpio_irq_set_mask(struct irq_data *d, bool unmask) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 1878c2ecf20Sopenharmony_ci struct nsp_gpio *chip = gpiochip_get_data(gc); 1888c2ecf20Sopenharmony_ci unsigned gpio = d->hwirq; 1898c2ecf20Sopenharmony_ci u32 trigger_type; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci trigger_type = irq_get_trigger_type(d->irq); 1928c2ecf20Sopenharmony_ci if (trigger_type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) 1938c2ecf20Sopenharmony_ci nsp_set_bit(chip, REG, NSP_GPIO_EVENT_INT_MASK, gpio, unmask); 1948c2ecf20Sopenharmony_ci else 1958c2ecf20Sopenharmony_ci nsp_set_bit(chip, REG, NSP_GPIO_INT_MASK, gpio, unmask); 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_cistatic void nsp_gpio_irq_mask(struct irq_data *d) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 2018c2ecf20Sopenharmony_ci struct nsp_gpio *chip = gpiochip_get_data(gc); 2028c2ecf20Sopenharmony_ci unsigned long flags; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&chip->lock, flags); 2058c2ecf20Sopenharmony_ci nsp_gpio_irq_set_mask(d, false); 2068c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&chip->lock, flags); 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistatic void nsp_gpio_irq_unmask(struct irq_data *d) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 2128c2ecf20Sopenharmony_ci struct nsp_gpio *chip = gpiochip_get_data(gc); 2138c2ecf20Sopenharmony_ci unsigned long flags; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&chip->lock, flags); 2168c2ecf20Sopenharmony_ci nsp_gpio_irq_set_mask(d, true); 2178c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&chip->lock, flags); 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic int nsp_gpio_irq_set_type(struct irq_data *d, unsigned int type) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 2238c2ecf20Sopenharmony_ci struct nsp_gpio *chip = gpiochip_get_data(gc); 2248c2ecf20Sopenharmony_ci unsigned gpio = d->hwirq; 2258c2ecf20Sopenharmony_ci bool level_low; 2268c2ecf20Sopenharmony_ci bool falling; 2278c2ecf20Sopenharmony_ci unsigned long flags; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&chip->lock, flags); 2308c2ecf20Sopenharmony_ci falling = nsp_get_bit(chip, REG, NSP_GPIO_EVENT_INT_POLARITY, gpio); 2318c2ecf20Sopenharmony_ci level_low = nsp_get_bit(chip, REG, NSP_GPIO_INT_POLARITY, gpio); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci switch (type & IRQ_TYPE_SENSE_MASK) { 2348c2ecf20Sopenharmony_ci case IRQ_TYPE_EDGE_RISING: 2358c2ecf20Sopenharmony_ci falling = false; 2368c2ecf20Sopenharmony_ci break; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci case IRQ_TYPE_EDGE_FALLING: 2398c2ecf20Sopenharmony_ci falling = true; 2408c2ecf20Sopenharmony_ci break; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci case IRQ_TYPE_LEVEL_HIGH: 2438c2ecf20Sopenharmony_ci level_low = false; 2448c2ecf20Sopenharmony_ci break; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci case IRQ_TYPE_LEVEL_LOW: 2478c2ecf20Sopenharmony_ci level_low = true; 2488c2ecf20Sopenharmony_ci break; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci default: 2518c2ecf20Sopenharmony_ci dev_err(chip->dev, "invalid GPIO IRQ type 0x%x\n", 2528c2ecf20Sopenharmony_ci type); 2538c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&chip->lock, flags); 2548c2ecf20Sopenharmony_ci return -EINVAL; 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci nsp_set_bit(chip, REG, NSP_GPIO_EVENT_INT_POLARITY, gpio, falling); 2588c2ecf20Sopenharmony_ci nsp_set_bit(chip, REG, NSP_GPIO_INT_POLARITY, gpio, level_low); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci if (type & IRQ_TYPE_EDGE_BOTH) 2618c2ecf20Sopenharmony_ci irq_set_handler_locked(d, handle_edge_irq); 2628c2ecf20Sopenharmony_ci else 2638c2ecf20Sopenharmony_ci irq_set_handler_locked(d, handle_level_irq); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&chip->lock, flags); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci dev_dbg(chip->dev, "gpio:%u level_low:%s falling:%s\n", gpio, 2688c2ecf20Sopenharmony_ci level_low ? "true" : "false", falling ? "true" : "false"); 2698c2ecf20Sopenharmony_ci return 0; 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_cistatic int nsp_gpio_direction_input(struct gpio_chip *gc, unsigned gpio) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci struct nsp_gpio *chip = gpiochip_get_data(gc); 2758c2ecf20Sopenharmony_ci unsigned long flags; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&chip->lock, flags); 2788c2ecf20Sopenharmony_ci nsp_set_bit(chip, REG, NSP_GPIO_OUT_EN, gpio, false); 2798c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&chip->lock, flags); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci dev_dbg(chip->dev, "gpio:%u set input\n", gpio); 2828c2ecf20Sopenharmony_ci return 0; 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic int nsp_gpio_direction_output(struct gpio_chip *gc, unsigned gpio, 2868c2ecf20Sopenharmony_ci int val) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci struct nsp_gpio *chip = gpiochip_get_data(gc); 2898c2ecf20Sopenharmony_ci unsigned long flags; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&chip->lock, flags); 2928c2ecf20Sopenharmony_ci nsp_set_bit(chip, REG, NSP_GPIO_OUT_EN, gpio, true); 2938c2ecf20Sopenharmony_ci nsp_set_bit(chip, REG, NSP_GPIO_DATA_OUT, gpio, !!(val)); 2948c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&chip->lock, flags); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci dev_dbg(chip->dev, "gpio:%u set output, value:%d\n", gpio, val); 2978c2ecf20Sopenharmony_ci return 0; 2988c2ecf20Sopenharmony_ci} 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_cistatic int nsp_gpio_get_direction(struct gpio_chip *gc, unsigned gpio) 3018c2ecf20Sopenharmony_ci{ 3028c2ecf20Sopenharmony_ci struct nsp_gpio *chip = gpiochip_get_data(gc); 3038c2ecf20Sopenharmony_ci unsigned long flags; 3048c2ecf20Sopenharmony_ci int val; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&chip->lock, flags); 3078c2ecf20Sopenharmony_ci val = nsp_get_bit(chip, REG, NSP_GPIO_OUT_EN, gpio); 3088c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&chip->lock, flags); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci return !val; 3118c2ecf20Sopenharmony_ci} 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_cistatic void nsp_gpio_set(struct gpio_chip *gc, unsigned gpio, int val) 3148c2ecf20Sopenharmony_ci{ 3158c2ecf20Sopenharmony_ci struct nsp_gpio *chip = gpiochip_get_data(gc); 3168c2ecf20Sopenharmony_ci unsigned long flags; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&chip->lock, flags); 3198c2ecf20Sopenharmony_ci nsp_set_bit(chip, REG, NSP_GPIO_DATA_OUT, gpio, !!(val)); 3208c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&chip->lock, flags); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci dev_dbg(chip->dev, "gpio:%u set, value:%d\n", gpio, val); 3238c2ecf20Sopenharmony_ci} 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cistatic int nsp_gpio_get(struct gpio_chip *gc, unsigned gpio) 3268c2ecf20Sopenharmony_ci{ 3278c2ecf20Sopenharmony_ci struct nsp_gpio *chip = gpiochip_get_data(gc); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci return !!(readl(chip->base + NSP_GPIO_DATA_IN) & BIT(gpio)); 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_cistatic int nsp_get_groups_count(struct pinctrl_dev *pctldev) 3338c2ecf20Sopenharmony_ci{ 3348c2ecf20Sopenharmony_ci return 1; 3358c2ecf20Sopenharmony_ci} 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci/* 3388c2ecf20Sopenharmony_ci * Only one group: "gpio_grp", since this local pinctrl device only performs 3398c2ecf20Sopenharmony_ci * GPIO specific PINCONF configurations 3408c2ecf20Sopenharmony_ci */ 3418c2ecf20Sopenharmony_cistatic const char *nsp_get_group_name(struct pinctrl_dev *pctldev, 3428c2ecf20Sopenharmony_ci unsigned selector) 3438c2ecf20Sopenharmony_ci{ 3448c2ecf20Sopenharmony_ci return "gpio_grp"; 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cistatic const struct pinctrl_ops nsp_pctrl_ops = { 3488c2ecf20Sopenharmony_ci .get_groups_count = nsp_get_groups_count, 3498c2ecf20Sopenharmony_ci .get_group_name = nsp_get_group_name, 3508c2ecf20Sopenharmony_ci .dt_node_to_map = pinconf_generic_dt_node_to_map_pin, 3518c2ecf20Sopenharmony_ci .dt_free_map = pinctrl_utils_free_map, 3528c2ecf20Sopenharmony_ci}; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic int nsp_gpio_set_slew(struct nsp_gpio *chip, unsigned gpio, u32 slew) 3558c2ecf20Sopenharmony_ci{ 3568c2ecf20Sopenharmony_ci if (slew) 3578c2ecf20Sopenharmony_ci nsp_set_bit(chip, IO_CTRL, NSP_GPIO_SLEW_RATE_EN, gpio, true); 3588c2ecf20Sopenharmony_ci else 3598c2ecf20Sopenharmony_ci nsp_set_bit(chip, IO_CTRL, NSP_GPIO_SLEW_RATE_EN, gpio, false); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci return 0; 3628c2ecf20Sopenharmony_ci} 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_cistatic int nsp_gpio_set_pull(struct nsp_gpio *chip, unsigned gpio, 3658c2ecf20Sopenharmony_ci bool pull_up, bool pull_down) 3668c2ecf20Sopenharmony_ci{ 3678c2ecf20Sopenharmony_ci unsigned long flags; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&chip->lock, flags); 3708c2ecf20Sopenharmony_ci nsp_set_bit(chip, IO_CTRL, NSP_PULL_DOWN_EN, gpio, pull_down); 3718c2ecf20Sopenharmony_ci nsp_set_bit(chip, IO_CTRL, NSP_PULL_UP_EN, gpio, pull_up); 3728c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&chip->lock, flags); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci dev_dbg(chip->dev, "gpio:%u set pullup:%d pulldown: %d\n", 3758c2ecf20Sopenharmony_ci gpio, pull_up, pull_down); 3768c2ecf20Sopenharmony_ci return 0; 3778c2ecf20Sopenharmony_ci} 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_cistatic void nsp_gpio_get_pull(struct nsp_gpio *chip, unsigned gpio, 3808c2ecf20Sopenharmony_ci bool *pull_up, bool *pull_down) 3818c2ecf20Sopenharmony_ci{ 3828c2ecf20Sopenharmony_ci unsigned long flags; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&chip->lock, flags); 3858c2ecf20Sopenharmony_ci *pull_up = nsp_get_bit(chip, IO_CTRL, NSP_PULL_UP_EN, gpio); 3868c2ecf20Sopenharmony_ci *pull_down = nsp_get_bit(chip, IO_CTRL, NSP_PULL_DOWN_EN, gpio); 3878c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&chip->lock, flags); 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_cistatic int nsp_gpio_set_strength(struct nsp_gpio *chip, unsigned gpio, 3918c2ecf20Sopenharmony_ci u32 strength) 3928c2ecf20Sopenharmony_ci{ 3938c2ecf20Sopenharmony_ci u32 offset, shift, i; 3948c2ecf20Sopenharmony_ci u32 val; 3958c2ecf20Sopenharmony_ci unsigned long flags; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci /* make sure drive strength is supported */ 3988c2ecf20Sopenharmony_ci if (strength < 2 || strength > 16 || (strength % 2)) 3998c2ecf20Sopenharmony_ci return -ENOTSUPP; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci shift = gpio; 4028c2ecf20Sopenharmony_ci offset = NSP_GPIO_DRV_CTRL; 4038c2ecf20Sopenharmony_ci dev_dbg(chip->dev, "gpio:%u set drive strength:%d mA\n", gpio, 4048c2ecf20Sopenharmony_ci strength); 4058c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&chip->lock, flags); 4068c2ecf20Sopenharmony_ci strength = (strength / 2) - 1; 4078c2ecf20Sopenharmony_ci for (i = GPIO_DRV_STRENGTH_BITS; i > 0; i--) { 4088c2ecf20Sopenharmony_ci val = readl(chip->io_ctrl + offset); 4098c2ecf20Sopenharmony_ci val &= ~BIT(shift); 4108c2ecf20Sopenharmony_ci val |= ((strength >> (i-1)) & 0x1) << shift; 4118c2ecf20Sopenharmony_ci writel(val, chip->io_ctrl + offset); 4128c2ecf20Sopenharmony_ci offset += 4; 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&chip->lock, flags); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci return 0; 4178c2ecf20Sopenharmony_ci} 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_cistatic int nsp_gpio_get_strength(struct nsp_gpio *chip, unsigned gpio, 4208c2ecf20Sopenharmony_ci u16 *strength) 4218c2ecf20Sopenharmony_ci{ 4228c2ecf20Sopenharmony_ci unsigned int offset, shift; 4238c2ecf20Sopenharmony_ci u32 val; 4248c2ecf20Sopenharmony_ci unsigned long flags; 4258c2ecf20Sopenharmony_ci int i; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci offset = NSP_GPIO_DRV_CTRL; 4288c2ecf20Sopenharmony_ci shift = gpio; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&chip->lock, flags); 4318c2ecf20Sopenharmony_ci *strength = 0; 4328c2ecf20Sopenharmony_ci for (i = (GPIO_DRV_STRENGTH_BITS - 1); i >= 0; i--) { 4338c2ecf20Sopenharmony_ci val = readl(chip->io_ctrl + offset) & BIT(shift); 4348c2ecf20Sopenharmony_ci val >>= shift; 4358c2ecf20Sopenharmony_ci *strength += (val << i); 4368c2ecf20Sopenharmony_ci offset += 4; 4378c2ecf20Sopenharmony_ci } 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci /* convert to mA */ 4408c2ecf20Sopenharmony_ci *strength = (*strength + 1) * 2; 4418c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&chip->lock, flags); 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci return 0; 4448c2ecf20Sopenharmony_ci} 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_cistatic int nsp_pin_config_group_get(struct pinctrl_dev *pctldev, 4478c2ecf20Sopenharmony_ci unsigned selector, 4488c2ecf20Sopenharmony_ci unsigned long *config) 4498c2ecf20Sopenharmony_ci{ 4508c2ecf20Sopenharmony_ci return 0; 4518c2ecf20Sopenharmony_ci} 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_cistatic int nsp_pin_config_group_set(struct pinctrl_dev *pctldev, 4548c2ecf20Sopenharmony_ci unsigned selector, 4558c2ecf20Sopenharmony_ci unsigned long *configs, unsigned num_configs) 4568c2ecf20Sopenharmony_ci{ 4578c2ecf20Sopenharmony_ci return 0; 4588c2ecf20Sopenharmony_ci} 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_cistatic int nsp_pin_config_get(struct pinctrl_dev *pctldev, unsigned pin, 4618c2ecf20Sopenharmony_ci unsigned long *config) 4628c2ecf20Sopenharmony_ci{ 4638c2ecf20Sopenharmony_ci struct nsp_gpio *chip = pinctrl_dev_get_drvdata(pctldev); 4648c2ecf20Sopenharmony_ci enum pin_config_param param = pinconf_to_config_param(*config); 4658c2ecf20Sopenharmony_ci unsigned int gpio; 4668c2ecf20Sopenharmony_ci u16 arg = 0; 4678c2ecf20Sopenharmony_ci bool pull_up, pull_down; 4688c2ecf20Sopenharmony_ci int ret; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci gpio = nsp_pin_to_gpio(pin); 4718c2ecf20Sopenharmony_ci switch (param) { 4728c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_DISABLE: 4738c2ecf20Sopenharmony_ci nsp_gpio_get_pull(chip, gpio, &pull_up, &pull_down); 4748c2ecf20Sopenharmony_ci if ((pull_up == false) && (pull_down == false)) 4758c2ecf20Sopenharmony_ci return 0; 4768c2ecf20Sopenharmony_ci else 4778c2ecf20Sopenharmony_ci return -EINVAL; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_UP: 4808c2ecf20Sopenharmony_ci nsp_gpio_get_pull(chip, gpio, &pull_up, &pull_down); 4818c2ecf20Sopenharmony_ci if (pull_up) 4828c2ecf20Sopenharmony_ci return 0; 4838c2ecf20Sopenharmony_ci else 4848c2ecf20Sopenharmony_ci return -EINVAL; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_DOWN: 4878c2ecf20Sopenharmony_ci nsp_gpio_get_pull(chip, gpio, &pull_up, &pull_down); 4888c2ecf20Sopenharmony_ci if (pull_down) 4898c2ecf20Sopenharmony_ci return 0; 4908c2ecf20Sopenharmony_ci else 4918c2ecf20Sopenharmony_ci return -EINVAL; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci case PIN_CONFIG_DRIVE_STRENGTH: 4948c2ecf20Sopenharmony_ci ret = nsp_gpio_get_strength(chip, gpio, &arg); 4958c2ecf20Sopenharmony_ci if (ret) 4968c2ecf20Sopenharmony_ci return ret; 4978c2ecf20Sopenharmony_ci *config = pinconf_to_config_packed(param, arg); 4988c2ecf20Sopenharmony_ci return 0; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci default: 5018c2ecf20Sopenharmony_ci return -ENOTSUPP; 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci} 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_cistatic int nsp_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin, 5068c2ecf20Sopenharmony_ci unsigned long *configs, unsigned num_configs) 5078c2ecf20Sopenharmony_ci{ 5088c2ecf20Sopenharmony_ci struct nsp_gpio *chip = pinctrl_dev_get_drvdata(pctldev); 5098c2ecf20Sopenharmony_ci enum pin_config_param param; 5108c2ecf20Sopenharmony_ci u32 arg; 5118c2ecf20Sopenharmony_ci unsigned int i, gpio; 5128c2ecf20Sopenharmony_ci int ret = -ENOTSUPP; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci gpio = nsp_pin_to_gpio(pin); 5158c2ecf20Sopenharmony_ci for (i = 0; i < num_configs; i++) { 5168c2ecf20Sopenharmony_ci param = pinconf_to_config_param(configs[i]); 5178c2ecf20Sopenharmony_ci arg = pinconf_to_config_argument(configs[i]); 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci switch (param) { 5208c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_DISABLE: 5218c2ecf20Sopenharmony_ci ret = nsp_gpio_set_pull(chip, gpio, false, false); 5228c2ecf20Sopenharmony_ci if (ret < 0) 5238c2ecf20Sopenharmony_ci goto out; 5248c2ecf20Sopenharmony_ci break; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_UP: 5278c2ecf20Sopenharmony_ci ret = nsp_gpio_set_pull(chip, gpio, true, false); 5288c2ecf20Sopenharmony_ci if (ret < 0) 5298c2ecf20Sopenharmony_ci goto out; 5308c2ecf20Sopenharmony_ci break; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_DOWN: 5338c2ecf20Sopenharmony_ci ret = nsp_gpio_set_pull(chip, gpio, false, true); 5348c2ecf20Sopenharmony_ci if (ret < 0) 5358c2ecf20Sopenharmony_ci goto out; 5368c2ecf20Sopenharmony_ci break; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci case PIN_CONFIG_DRIVE_STRENGTH: 5398c2ecf20Sopenharmony_ci ret = nsp_gpio_set_strength(chip, gpio, arg); 5408c2ecf20Sopenharmony_ci if (ret < 0) 5418c2ecf20Sopenharmony_ci goto out; 5428c2ecf20Sopenharmony_ci break; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci case PIN_CONFIG_SLEW_RATE: 5458c2ecf20Sopenharmony_ci ret = nsp_gpio_set_slew(chip, gpio, arg); 5468c2ecf20Sopenharmony_ci if (ret < 0) 5478c2ecf20Sopenharmony_ci goto out; 5488c2ecf20Sopenharmony_ci break; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci default: 5518c2ecf20Sopenharmony_ci dev_err(chip->dev, "invalid configuration\n"); 5528c2ecf20Sopenharmony_ci return -ENOTSUPP; 5538c2ecf20Sopenharmony_ci } 5548c2ecf20Sopenharmony_ci } 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ciout: 5578c2ecf20Sopenharmony_ci return ret; 5588c2ecf20Sopenharmony_ci} 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_cistatic const struct pinconf_ops nsp_pconf_ops = { 5618c2ecf20Sopenharmony_ci .is_generic = true, 5628c2ecf20Sopenharmony_ci .pin_config_get = nsp_pin_config_get, 5638c2ecf20Sopenharmony_ci .pin_config_set = nsp_pin_config_set, 5648c2ecf20Sopenharmony_ci .pin_config_group_get = nsp_pin_config_group_get, 5658c2ecf20Sopenharmony_ci .pin_config_group_set = nsp_pin_config_group_set, 5668c2ecf20Sopenharmony_ci}; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci/* 5698c2ecf20Sopenharmony_ci * NSP GPIO controller supports some PINCONF related configurations such as 5708c2ecf20Sopenharmony_ci * pull up, pull down, slew and drive strength, when the pin is configured 5718c2ecf20Sopenharmony_ci * to GPIO. 5728c2ecf20Sopenharmony_ci * 5738c2ecf20Sopenharmony_ci * Here a local pinctrl device is created with simple 1-to-1 pin mapping to the 5748c2ecf20Sopenharmony_ci * local GPIO pins 5758c2ecf20Sopenharmony_ci */ 5768c2ecf20Sopenharmony_cistatic int nsp_gpio_register_pinconf(struct nsp_gpio *chip) 5778c2ecf20Sopenharmony_ci{ 5788c2ecf20Sopenharmony_ci struct pinctrl_desc *pctldesc = &chip->pctldesc; 5798c2ecf20Sopenharmony_ci struct pinctrl_pin_desc *pins; 5808c2ecf20Sopenharmony_ci struct gpio_chip *gc = &chip->gc; 5818c2ecf20Sopenharmony_ci int i; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci pins = devm_kcalloc(chip->dev, gc->ngpio, sizeof(*pins), GFP_KERNEL); 5848c2ecf20Sopenharmony_ci if (!pins) 5858c2ecf20Sopenharmony_ci return -ENOMEM; 5868c2ecf20Sopenharmony_ci for (i = 0; i < gc->ngpio; i++) { 5878c2ecf20Sopenharmony_ci pins[i].number = i; 5888c2ecf20Sopenharmony_ci pins[i].name = devm_kasprintf(chip->dev, GFP_KERNEL, 5898c2ecf20Sopenharmony_ci "gpio-%d", i); 5908c2ecf20Sopenharmony_ci if (!pins[i].name) 5918c2ecf20Sopenharmony_ci return -ENOMEM; 5928c2ecf20Sopenharmony_ci } 5938c2ecf20Sopenharmony_ci pctldesc->name = dev_name(chip->dev); 5948c2ecf20Sopenharmony_ci pctldesc->pctlops = &nsp_pctrl_ops; 5958c2ecf20Sopenharmony_ci pctldesc->pins = pins; 5968c2ecf20Sopenharmony_ci pctldesc->npins = gc->ngpio; 5978c2ecf20Sopenharmony_ci pctldesc->confops = &nsp_pconf_ops; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci chip->pctl = devm_pinctrl_register(chip->dev, pctldesc, chip); 6008c2ecf20Sopenharmony_ci if (IS_ERR(chip->pctl)) { 6018c2ecf20Sopenharmony_ci dev_err(chip->dev, "unable to register pinctrl device\n"); 6028c2ecf20Sopenharmony_ci return PTR_ERR(chip->pctl); 6038c2ecf20Sopenharmony_ci } 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci return 0; 6068c2ecf20Sopenharmony_ci} 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_cistatic const struct of_device_id nsp_gpio_of_match[] = { 6098c2ecf20Sopenharmony_ci {.compatible = "brcm,nsp-gpio-a",}, 6108c2ecf20Sopenharmony_ci {} 6118c2ecf20Sopenharmony_ci}; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_cistatic int nsp_gpio_probe(struct platform_device *pdev) 6148c2ecf20Sopenharmony_ci{ 6158c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 6168c2ecf20Sopenharmony_ci struct nsp_gpio *chip; 6178c2ecf20Sopenharmony_ci struct gpio_chip *gc; 6188c2ecf20Sopenharmony_ci u32 val; 6198c2ecf20Sopenharmony_ci int irq, ret; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci if (of_property_read_u32(pdev->dev.of_node, "ngpios", &val)) { 6228c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Missing ngpios OF property\n"); 6238c2ecf20Sopenharmony_ci return -ENODEV; 6248c2ecf20Sopenharmony_ci } 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); 6278c2ecf20Sopenharmony_ci if (!chip) 6288c2ecf20Sopenharmony_ci return -ENOMEM; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci chip->dev = dev; 6318c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, chip); 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci chip->base = devm_platform_ioremap_resource(pdev, 0); 6348c2ecf20Sopenharmony_ci if (IS_ERR(chip->base)) { 6358c2ecf20Sopenharmony_ci dev_err(dev, "unable to map I/O memory\n"); 6368c2ecf20Sopenharmony_ci return PTR_ERR(chip->base); 6378c2ecf20Sopenharmony_ci } 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci chip->io_ctrl = devm_platform_ioremap_resource(pdev, 1); 6408c2ecf20Sopenharmony_ci if (IS_ERR(chip->io_ctrl)) { 6418c2ecf20Sopenharmony_ci dev_err(dev, "unable to map I/O memory\n"); 6428c2ecf20Sopenharmony_ci return PTR_ERR(chip->io_ctrl); 6438c2ecf20Sopenharmony_ci } 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci raw_spin_lock_init(&chip->lock); 6468c2ecf20Sopenharmony_ci gc = &chip->gc; 6478c2ecf20Sopenharmony_ci gc->base = -1; 6488c2ecf20Sopenharmony_ci gc->can_sleep = false; 6498c2ecf20Sopenharmony_ci gc->ngpio = val; 6508c2ecf20Sopenharmony_ci gc->label = dev_name(dev); 6518c2ecf20Sopenharmony_ci gc->parent = dev; 6528c2ecf20Sopenharmony_ci gc->of_node = dev->of_node; 6538c2ecf20Sopenharmony_ci gc->request = gpiochip_generic_request; 6548c2ecf20Sopenharmony_ci gc->free = gpiochip_generic_free; 6558c2ecf20Sopenharmony_ci gc->direction_input = nsp_gpio_direction_input; 6568c2ecf20Sopenharmony_ci gc->direction_output = nsp_gpio_direction_output; 6578c2ecf20Sopenharmony_ci gc->get_direction = nsp_gpio_get_direction; 6588c2ecf20Sopenharmony_ci gc->set = nsp_gpio_set; 6598c2ecf20Sopenharmony_ci gc->get = nsp_gpio_get; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci /* optional GPIO interrupt support */ 6628c2ecf20Sopenharmony_ci irq = platform_get_irq(pdev, 0); 6638c2ecf20Sopenharmony_ci if (irq > 0) { 6648c2ecf20Sopenharmony_ci struct gpio_irq_chip *girq; 6658c2ecf20Sopenharmony_ci struct irq_chip *irqc; 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci irqc = &chip->irqchip; 6688c2ecf20Sopenharmony_ci irqc->name = "gpio-a"; 6698c2ecf20Sopenharmony_ci irqc->irq_ack = nsp_gpio_irq_ack; 6708c2ecf20Sopenharmony_ci irqc->irq_mask = nsp_gpio_irq_mask; 6718c2ecf20Sopenharmony_ci irqc->irq_unmask = nsp_gpio_irq_unmask; 6728c2ecf20Sopenharmony_ci irqc->irq_set_type = nsp_gpio_irq_set_type; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci val = readl(chip->base + NSP_CHIP_A_INT_MASK); 6758c2ecf20Sopenharmony_ci val = val | NSP_CHIP_A_GPIO_INT_BIT; 6768c2ecf20Sopenharmony_ci writel(val, (chip->base + NSP_CHIP_A_INT_MASK)); 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci /* Install ISR for this GPIO controller. */ 6798c2ecf20Sopenharmony_ci ret = devm_request_irq(dev, irq, nsp_gpio_irq_handler, 6808c2ecf20Sopenharmony_ci IRQF_SHARED, "gpio-a", &chip->gc); 6818c2ecf20Sopenharmony_ci if (ret) { 6828c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Unable to request IRQ%d: %d\n", 6838c2ecf20Sopenharmony_ci irq, ret); 6848c2ecf20Sopenharmony_ci return ret; 6858c2ecf20Sopenharmony_ci } 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci girq = &chip->gc.irq; 6888c2ecf20Sopenharmony_ci girq->chip = irqc; 6898c2ecf20Sopenharmony_ci /* This will let us handle the parent IRQ in the driver */ 6908c2ecf20Sopenharmony_ci girq->parent_handler = NULL; 6918c2ecf20Sopenharmony_ci girq->num_parents = 0; 6928c2ecf20Sopenharmony_ci girq->parents = NULL; 6938c2ecf20Sopenharmony_ci girq->default_type = IRQ_TYPE_NONE; 6948c2ecf20Sopenharmony_ci girq->handler = handle_bad_irq; 6958c2ecf20Sopenharmony_ci } 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci ret = devm_gpiochip_add_data(dev, gc, chip); 6988c2ecf20Sopenharmony_ci if (ret < 0) { 6998c2ecf20Sopenharmony_ci dev_err(dev, "unable to add GPIO chip\n"); 7008c2ecf20Sopenharmony_ci return ret; 7018c2ecf20Sopenharmony_ci } 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci ret = nsp_gpio_register_pinconf(chip); 7048c2ecf20Sopenharmony_ci if (ret) { 7058c2ecf20Sopenharmony_ci dev_err(dev, "unable to register pinconf\n"); 7068c2ecf20Sopenharmony_ci return ret; 7078c2ecf20Sopenharmony_ci } 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci return 0; 7108c2ecf20Sopenharmony_ci} 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_cistatic struct platform_driver nsp_gpio_driver = { 7138c2ecf20Sopenharmony_ci .driver = { 7148c2ecf20Sopenharmony_ci .name = "nsp-gpio-a", 7158c2ecf20Sopenharmony_ci .of_match_table = nsp_gpio_of_match, 7168c2ecf20Sopenharmony_ci }, 7178c2ecf20Sopenharmony_ci .probe = nsp_gpio_probe, 7188c2ecf20Sopenharmony_ci}; 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_cistatic int __init nsp_gpio_init(void) 7218c2ecf20Sopenharmony_ci{ 7228c2ecf20Sopenharmony_ci return platform_driver_register(&nsp_gpio_driver); 7238c2ecf20Sopenharmony_ci} 7248c2ecf20Sopenharmony_ciarch_initcall_sync(nsp_gpio_init); 725