162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci// Copyright (C) 2014-2017 Broadcom 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci/* 562306a36Sopenharmony_ci * This file contains the Broadcom Northstar Plus (NSP) GPIO driver that 662306a36Sopenharmony_ci * supports the chipCommonA GPIO controller. Basic PINCONF such as bias, 762306a36Sopenharmony_ci * pull up/down, slew and drive strength are also supported in this driver. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Pins from the chipCommonA GPIO can be individually muxed to GPIO function, 1062306a36Sopenharmony_ci * through the interaction with the NSP IOMUX controller. 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/gpio/driver.h> 1462306a36Sopenharmony_ci#include <linux/interrupt.h> 1562306a36Sopenharmony_ci#include <linux/io.h> 1662306a36Sopenharmony_ci#include <linux/ioport.h> 1762306a36Sopenharmony_ci#include <linux/kernel.h> 1862306a36Sopenharmony_ci#include <linux/of.h> 1962306a36Sopenharmony_ci#include <linux/pinctrl/pinconf.h> 2062306a36Sopenharmony_ci#include <linux/pinctrl/pinconf-generic.h> 2162306a36Sopenharmony_ci#include <linux/pinctrl/pinctrl.h> 2262306a36Sopenharmony_ci#include <linux/platform_device.h> 2362306a36Sopenharmony_ci#include <linux/slab.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#include "../pinctrl-utils.h" 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define NSP_CHIP_A_INT_STATUS 0x00 2862306a36Sopenharmony_ci#define NSP_CHIP_A_INT_MASK 0x04 2962306a36Sopenharmony_ci#define NSP_GPIO_DATA_IN 0x40 3062306a36Sopenharmony_ci#define NSP_GPIO_DATA_OUT 0x44 3162306a36Sopenharmony_ci#define NSP_GPIO_OUT_EN 0x48 3262306a36Sopenharmony_ci#define NSP_GPIO_INT_POLARITY 0x50 3362306a36Sopenharmony_ci#define NSP_GPIO_INT_MASK 0x54 3462306a36Sopenharmony_ci#define NSP_GPIO_EVENT 0x58 3562306a36Sopenharmony_ci#define NSP_GPIO_EVENT_INT_MASK 0x5c 3662306a36Sopenharmony_ci#define NSP_GPIO_EVENT_INT_POLARITY 0x64 3762306a36Sopenharmony_ci#define NSP_CHIP_A_GPIO_INT_BIT 0x01 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci/* I/O parameters offset for chipcommon A GPIO */ 4062306a36Sopenharmony_ci#define NSP_GPIO_DRV_CTRL 0x00 4162306a36Sopenharmony_ci#define NSP_GPIO_HYSTERESIS_EN 0x10 4262306a36Sopenharmony_ci#define NSP_GPIO_SLEW_RATE_EN 0x14 4362306a36Sopenharmony_ci#define NSP_PULL_UP_EN 0x18 4462306a36Sopenharmony_ci#define NSP_PULL_DOWN_EN 0x1c 4562306a36Sopenharmony_ci#define GPIO_DRV_STRENGTH_BITS 0x03 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci/* 4862306a36Sopenharmony_ci * nsp GPIO core 4962306a36Sopenharmony_ci * 5062306a36Sopenharmony_ci * @dev: pointer to device 5162306a36Sopenharmony_ci * @base: I/O register base for nsp GPIO controller 5262306a36Sopenharmony_ci * @io_ctrl: I/O register base for PINCONF support outside the GPIO block 5362306a36Sopenharmony_ci * @gc: GPIO chip 5462306a36Sopenharmony_ci * @pctl: pointer to pinctrl_dev 5562306a36Sopenharmony_ci * @pctldesc: pinctrl descriptor 5662306a36Sopenharmony_ci * @lock: lock to protect access to I/O registers 5762306a36Sopenharmony_ci */ 5862306a36Sopenharmony_cistruct nsp_gpio { 5962306a36Sopenharmony_ci struct device *dev; 6062306a36Sopenharmony_ci void __iomem *base; 6162306a36Sopenharmony_ci void __iomem *io_ctrl; 6262306a36Sopenharmony_ci struct gpio_chip gc; 6362306a36Sopenharmony_ci struct pinctrl_dev *pctl; 6462306a36Sopenharmony_ci struct pinctrl_desc pctldesc; 6562306a36Sopenharmony_ci raw_spinlock_t lock; 6662306a36Sopenharmony_ci}; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cienum base_type { 6962306a36Sopenharmony_ci REG, 7062306a36Sopenharmony_ci IO_CTRL 7162306a36Sopenharmony_ci}; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci/* 7462306a36Sopenharmony_ci * Mapping from PINCONF pins to GPIO pins is 1-to-1 7562306a36Sopenharmony_ci */ 7662306a36Sopenharmony_cistatic inline unsigned nsp_pin_to_gpio(unsigned pin) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci return pin; 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci/* 8262306a36Sopenharmony_ci * nsp_set_bit - set or clear one bit (corresponding to the GPIO pin) in a 8362306a36Sopenharmony_ci * nsp GPIO register 8462306a36Sopenharmony_ci * 8562306a36Sopenharmony_ci * @nsp_gpio: nsp GPIO device 8662306a36Sopenharmony_ci * @base_type: reg base to modify 8762306a36Sopenharmony_ci * @reg: register offset 8862306a36Sopenharmony_ci * @gpio: GPIO pin 8962306a36Sopenharmony_ci * @set: set or clear 9062306a36Sopenharmony_ci */ 9162306a36Sopenharmony_cistatic inline void nsp_set_bit(struct nsp_gpio *chip, enum base_type address, 9262306a36Sopenharmony_ci unsigned int reg, unsigned gpio, bool set) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci u32 val; 9562306a36Sopenharmony_ci void __iomem *base_address; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci if (address == IO_CTRL) 9862306a36Sopenharmony_ci base_address = chip->io_ctrl; 9962306a36Sopenharmony_ci else 10062306a36Sopenharmony_ci base_address = chip->base; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci val = readl(base_address + reg); 10362306a36Sopenharmony_ci if (set) 10462306a36Sopenharmony_ci val |= BIT(gpio); 10562306a36Sopenharmony_ci else 10662306a36Sopenharmony_ci val &= ~BIT(gpio); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci writel(val, base_address + reg); 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci/* 11262306a36Sopenharmony_ci * nsp_get_bit - get one bit (corresponding to the GPIO pin) in a 11362306a36Sopenharmony_ci * nsp GPIO register 11462306a36Sopenharmony_ci */ 11562306a36Sopenharmony_cistatic inline bool nsp_get_bit(struct nsp_gpio *chip, enum base_type address, 11662306a36Sopenharmony_ci unsigned int reg, unsigned gpio) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci if (address == IO_CTRL) 11962306a36Sopenharmony_ci return !!(readl(chip->io_ctrl + reg) & BIT(gpio)); 12062306a36Sopenharmony_ci else 12162306a36Sopenharmony_ci return !!(readl(chip->base + reg) & BIT(gpio)); 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic irqreturn_t nsp_gpio_irq_handler(int irq, void *data) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci struct gpio_chip *gc = (struct gpio_chip *)data; 12762306a36Sopenharmony_ci struct nsp_gpio *chip = gpiochip_get_data(gc); 12862306a36Sopenharmony_ci int bit; 12962306a36Sopenharmony_ci unsigned long int_bits = 0; 13062306a36Sopenharmony_ci u32 int_status; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci /* go through the entire GPIOs and handle all interrupts */ 13362306a36Sopenharmony_ci int_status = readl(chip->base + NSP_CHIP_A_INT_STATUS); 13462306a36Sopenharmony_ci if (int_status & NSP_CHIP_A_GPIO_INT_BIT) { 13562306a36Sopenharmony_ci unsigned int event, level; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci /* Get level and edge interrupts */ 13862306a36Sopenharmony_ci event = readl(chip->base + NSP_GPIO_EVENT_INT_MASK) & 13962306a36Sopenharmony_ci readl(chip->base + NSP_GPIO_EVENT); 14062306a36Sopenharmony_ci level = readl(chip->base + NSP_GPIO_DATA_IN) ^ 14162306a36Sopenharmony_ci readl(chip->base + NSP_GPIO_INT_POLARITY); 14262306a36Sopenharmony_ci level &= readl(chip->base + NSP_GPIO_INT_MASK); 14362306a36Sopenharmony_ci int_bits = level | event; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci for_each_set_bit(bit, &int_bits, gc->ngpio) 14662306a36Sopenharmony_ci generic_handle_domain_irq(gc->irq.domain, bit); 14762306a36Sopenharmony_ci } 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci return int_bits ? IRQ_HANDLED : IRQ_NONE; 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistatic void nsp_gpio_irq_ack(struct irq_data *d) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 15562306a36Sopenharmony_ci struct nsp_gpio *chip = gpiochip_get_data(gc); 15662306a36Sopenharmony_ci unsigned gpio = d->hwirq; 15762306a36Sopenharmony_ci u32 val = BIT(gpio); 15862306a36Sopenharmony_ci u32 trigger_type; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci trigger_type = irq_get_trigger_type(d->irq); 16162306a36Sopenharmony_ci if (trigger_type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) 16262306a36Sopenharmony_ci writel(val, chip->base + NSP_GPIO_EVENT); 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci/* 16662306a36Sopenharmony_ci * nsp_gpio_irq_set_mask - mask/unmask a GPIO interrupt 16762306a36Sopenharmony_ci * 16862306a36Sopenharmony_ci * @d: IRQ chip data 16962306a36Sopenharmony_ci * @unmask: mask/unmask GPIO interrupt 17062306a36Sopenharmony_ci */ 17162306a36Sopenharmony_cistatic void nsp_gpio_irq_set_mask(struct irq_data *d, bool unmask) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 17462306a36Sopenharmony_ci struct nsp_gpio *chip = gpiochip_get_data(gc); 17562306a36Sopenharmony_ci unsigned gpio = d->hwirq; 17662306a36Sopenharmony_ci u32 trigger_type; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci trigger_type = irq_get_trigger_type(d->irq); 17962306a36Sopenharmony_ci if (trigger_type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) 18062306a36Sopenharmony_ci nsp_set_bit(chip, REG, NSP_GPIO_EVENT_INT_MASK, gpio, unmask); 18162306a36Sopenharmony_ci else 18262306a36Sopenharmony_ci nsp_set_bit(chip, REG, NSP_GPIO_INT_MASK, gpio, unmask); 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic void nsp_gpio_irq_mask(struct irq_data *d) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 18862306a36Sopenharmony_ci struct nsp_gpio *chip = gpiochip_get_data(gc); 18962306a36Sopenharmony_ci unsigned long flags; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci raw_spin_lock_irqsave(&chip->lock, flags); 19262306a36Sopenharmony_ci nsp_gpio_irq_set_mask(d, false); 19362306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&chip->lock, flags); 19462306a36Sopenharmony_ci gpiochip_disable_irq(gc, irqd_to_hwirq(d)); 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_cistatic void nsp_gpio_irq_unmask(struct irq_data *d) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 20062306a36Sopenharmony_ci struct nsp_gpio *chip = gpiochip_get_data(gc); 20162306a36Sopenharmony_ci unsigned long flags; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci gpiochip_enable_irq(gc, irqd_to_hwirq(d)); 20462306a36Sopenharmony_ci raw_spin_lock_irqsave(&chip->lock, flags); 20562306a36Sopenharmony_ci nsp_gpio_irq_set_mask(d, true); 20662306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&chip->lock, flags); 20762306a36Sopenharmony_ci} 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_cistatic int nsp_gpio_irq_set_type(struct irq_data *d, unsigned int type) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 21262306a36Sopenharmony_ci struct nsp_gpio *chip = gpiochip_get_data(gc); 21362306a36Sopenharmony_ci unsigned gpio = d->hwirq; 21462306a36Sopenharmony_ci bool level_low; 21562306a36Sopenharmony_ci bool falling; 21662306a36Sopenharmony_ci unsigned long flags; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci raw_spin_lock_irqsave(&chip->lock, flags); 21962306a36Sopenharmony_ci falling = nsp_get_bit(chip, REG, NSP_GPIO_EVENT_INT_POLARITY, gpio); 22062306a36Sopenharmony_ci level_low = nsp_get_bit(chip, REG, NSP_GPIO_INT_POLARITY, gpio); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci switch (type & IRQ_TYPE_SENSE_MASK) { 22362306a36Sopenharmony_ci case IRQ_TYPE_EDGE_RISING: 22462306a36Sopenharmony_ci falling = false; 22562306a36Sopenharmony_ci break; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci case IRQ_TYPE_EDGE_FALLING: 22862306a36Sopenharmony_ci falling = true; 22962306a36Sopenharmony_ci break; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci case IRQ_TYPE_LEVEL_HIGH: 23262306a36Sopenharmony_ci level_low = false; 23362306a36Sopenharmony_ci break; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci case IRQ_TYPE_LEVEL_LOW: 23662306a36Sopenharmony_ci level_low = true; 23762306a36Sopenharmony_ci break; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci default: 24062306a36Sopenharmony_ci dev_err(chip->dev, "invalid GPIO IRQ type 0x%x\n", 24162306a36Sopenharmony_ci type); 24262306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&chip->lock, flags); 24362306a36Sopenharmony_ci return -EINVAL; 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci nsp_set_bit(chip, REG, NSP_GPIO_EVENT_INT_POLARITY, gpio, falling); 24762306a36Sopenharmony_ci nsp_set_bit(chip, REG, NSP_GPIO_INT_POLARITY, gpio, level_low); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci if (type & IRQ_TYPE_EDGE_BOTH) 25062306a36Sopenharmony_ci irq_set_handler_locked(d, handle_edge_irq); 25162306a36Sopenharmony_ci else 25262306a36Sopenharmony_ci irq_set_handler_locked(d, handle_level_irq); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&chip->lock, flags); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci dev_dbg(chip->dev, "gpio:%u level_low:%s falling:%s\n", gpio, 25762306a36Sopenharmony_ci level_low ? "true" : "false", falling ? "true" : "false"); 25862306a36Sopenharmony_ci return 0; 25962306a36Sopenharmony_ci} 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_cistatic const struct irq_chip nsp_gpio_irq_chip = { 26262306a36Sopenharmony_ci .name = "gpio-a", 26362306a36Sopenharmony_ci .irq_ack = nsp_gpio_irq_ack, 26462306a36Sopenharmony_ci .irq_mask = nsp_gpio_irq_mask, 26562306a36Sopenharmony_ci .irq_unmask = nsp_gpio_irq_unmask, 26662306a36Sopenharmony_ci .irq_set_type = nsp_gpio_irq_set_type, 26762306a36Sopenharmony_ci .flags = IRQCHIP_IMMUTABLE, 26862306a36Sopenharmony_ci GPIOCHIP_IRQ_RESOURCE_HELPERS, 26962306a36Sopenharmony_ci}; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_cistatic int nsp_gpio_direction_input(struct gpio_chip *gc, unsigned gpio) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci struct nsp_gpio *chip = gpiochip_get_data(gc); 27462306a36Sopenharmony_ci unsigned long flags; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci raw_spin_lock_irqsave(&chip->lock, flags); 27762306a36Sopenharmony_ci nsp_set_bit(chip, REG, NSP_GPIO_OUT_EN, gpio, false); 27862306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&chip->lock, flags); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci dev_dbg(chip->dev, "gpio:%u set input\n", gpio); 28162306a36Sopenharmony_ci return 0; 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_cistatic int nsp_gpio_direction_output(struct gpio_chip *gc, unsigned gpio, 28562306a36Sopenharmony_ci int val) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci struct nsp_gpio *chip = gpiochip_get_data(gc); 28862306a36Sopenharmony_ci unsigned long flags; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci raw_spin_lock_irqsave(&chip->lock, flags); 29162306a36Sopenharmony_ci nsp_set_bit(chip, REG, NSP_GPIO_OUT_EN, gpio, true); 29262306a36Sopenharmony_ci nsp_set_bit(chip, REG, NSP_GPIO_DATA_OUT, gpio, !!(val)); 29362306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&chip->lock, flags); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci dev_dbg(chip->dev, "gpio:%u set output, value:%d\n", gpio, val); 29662306a36Sopenharmony_ci return 0; 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cistatic int nsp_gpio_get_direction(struct gpio_chip *gc, unsigned gpio) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci struct nsp_gpio *chip = gpiochip_get_data(gc); 30262306a36Sopenharmony_ci unsigned long flags; 30362306a36Sopenharmony_ci int val; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci raw_spin_lock_irqsave(&chip->lock, flags); 30662306a36Sopenharmony_ci val = nsp_get_bit(chip, REG, NSP_GPIO_OUT_EN, gpio); 30762306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&chip->lock, flags); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci return !val; 31062306a36Sopenharmony_ci} 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_cistatic void nsp_gpio_set(struct gpio_chip *gc, unsigned gpio, int val) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci struct nsp_gpio *chip = gpiochip_get_data(gc); 31562306a36Sopenharmony_ci unsigned long flags; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci raw_spin_lock_irqsave(&chip->lock, flags); 31862306a36Sopenharmony_ci nsp_set_bit(chip, REG, NSP_GPIO_DATA_OUT, gpio, !!(val)); 31962306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&chip->lock, flags); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci dev_dbg(chip->dev, "gpio:%u set, value:%d\n", gpio, val); 32262306a36Sopenharmony_ci} 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_cistatic int nsp_gpio_get(struct gpio_chip *gc, unsigned gpio) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci struct nsp_gpio *chip = gpiochip_get_data(gc); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci return !!(readl(chip->base + NSP_GPIO_DATA_IN) & BIT(gpio)); 32962306a36Sopenharmony_ci} 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_cistatic int nsp_get_groups_count(struct pinctrl_dev *pctldev) 33262306a36Sopenharmony_ci{ 33362306a36Sopenharmony_ci return 1; 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci/* 33762306a36Sopenharmony_ci * Only one group: "gpio_grp", since this local pinctrl device only performs 33862306a36Sopenharmony_ci * GPIO specific PINCONF configurations 33962306a36Sopenharmony_ci */ 34062306a36Sopenharmony_cistatic const char *nsp_get_group_name(struct pinctrl_dev *pctldev, 34162306a36Sopenharmony_ci unsigned selector) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci return "gpio_grp"; 34462306a36Sopenharmony_ci} 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_cistatic const struct pinctrl_ops nsp_pctrl_ops = { 34762306a36Sopenharmony_ci .get_groups_count = nsp_get_groups_count, 34862306a36Sopenharmony_ci .get_group_name = nsp_get_group_name, 34962306a36Sopenharmony_ci .dt_node_to_map = pinconf_generic_dt_node_to_map_pin, 35062306a36Sopenharmony_ci .dt_free_map = pinctrl_utils_free_map, 35162306a36Sopenharmony_ci}; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_cistatic int nsp_gpio_set_slew(struct nsp_gpio *chip, unsigned gpio, u32 slew) 35462306a36Sopenharmony_ci{ 35562306a36Sopenharmony_ci if (slew) 35662306a36Sopenharmony_ci nsp_set_bit(chip, IO_CTRL, NSP_GPIO_SLEW_RATE_EN, gpio, true); 35762306a36Sopenharmony_ci else 35862306a36Sopenharmony_ci nsp_set_bit(chip, IO_CTRL, NSP_GPIO_SLEW_RATE_EN, gpio, false); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci return 0; 36162306a36Sopenharmony_ci} 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_cistatic int nsp_gpio_set_pull(struct nsp_gpio *chip, unsigned gpio, 36462306a36Sopenharmony_ci bool pull_up, bool pull_down) 36562306a36Sopenharmony_ci{ 36662306a36Sopenharmony_ci unsigned long flags; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci raw_spin_lock_irqsave(&chip->lock, flags); 36962306a36Sopenharmony_ci nsp_set_bit(chip, IO_CTRL, NSP_PULL_DOWN_EN, gpio, pull_down); 37062306a36Sopenharmony_ci nsp_set_bit(chip, IO_CTRL, NSP_PULL_UP_EN, gpio, pull_up); 37162306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&chip->lock, flags); 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci dev_dbg(chip->dev, "gpio:%u set pullup:%d pulldown: %d\n", 37462306a36Sopenharmony_ci gpio, pull_up, pull_down); 37562306a36Sopenharmony_ci return 0; 37662306a36Sopenharmony_ci} 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_cistatic void nsp_gpio_get_pull(struct nsp_gpio *chip, unsigned gpio, 37962306a36Sopenharmony_ci bool *pull_up, bool *pull_down) 38062306a36Sopenharmony_ci{ 38162306a36Sopenharmony_ci unsigned long flags; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci raw_spin_lock_irqsave(&chip->lock, flags); 38462306a36Sopenharmony_ci *pull_up = nsp_get_bit(chip, IO_CTRL, NSP_PULL_UP_EN, gpio); 38562306a36Sopenharmony_ci *pull_down = nsp_get_bit(chip, IO_CTRL, NSP_PULL_DOWN_EN, gpio); 38662306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&chip->lock, flags); 38762306a36Sopenharmony_ci} 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_cistatic int nsp_gpio_set_strength(struct nsp_gpio *chip, unsigned gpio, 39062306a36Sopenharmony_ci u32 strength) 39162306a36Sopenharmony_ci{ 39262306a36Sopenharmony_ci u32 offset, shift, i; 39362306a36Sopenharmony_ci u32 val; 39462306a36Sopenharmony_ci unsigned long flags; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci /* make sure drive strength is supported */ 39762306a36Sopenharmony_ci if (strength < 2 || strength > 16 || (strength % 2)) 39862306a36Sopenharmony_ci return -ENOTSUPP; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci shift = gpio; 40162306a36Sopenharmony_ci offset = NSP_GPIO_DRV_CTRL; 40262306a36Sopenharmony_ci dev_dbg(chip->dev, "gpio:%u set drive strength:%d mA\n", gpio, 40362306a36Sopenharmony_ci strength); 40462306a36Sopenharmony_ci raw_spin_lock_irqsave(&chip->lock, flags); 40562306a36Sopenharmony_ci strength = (strength / 2) - 1; 40662306a36Sopenharmony_ci for (i = GPIO_DRV_STRENGTH_BITS; i > 0; i--) { 40762306a36Sopenharmony_ci val = readl(chip->io_ctrl + offset); 40862306a36Sopenharmony_ci val &= ~BIT(shift); 40962306a36Sopenharmony_ci val |= ((strength >> (i-1)) & 0x1) << shift; 41062306a36Sopenharmony_ci writel(val, chip->io_ctrl + offset); 41162306a36Sopenharmony_ci offset += 4; 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&chip->lock, flags); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci return 0; 41662306a36Sopenharmony_ci} 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_cistatic int nsp_gpio_get_strength(struct nsp_gpio *chip, unsigned gpio, 41962306a36Sopenharmony_ci u16 *strength) 42062306a36Sopenharmony_ci{ 42162306a36Sopenharmony_ci unsigned int offset, shift; 42262306a36Sopenharmony_ci u32 val; 42362306a36Sopenharmony_ci unsigned long flags; 42462306a36Sopenharmony_ci int i; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci offset = NSP_GPIO_DRV_CTRL; 42762306a36Sopenharmony_ci shift = gpio; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci raw_spin_lock_irqsave(&chip->lock, flags); 43062306a36Sopenharmony_ci *strength = 0; 43162306a36Sopenharmony_ci for (i = (GPIO_DRV_STRENGTH_BITS - 1); i >= 0; i--) { 43262306a36Sopenharmony_ci val = readl(chip->io_ctrl + offset) & BIT(shift); 43362306a36Sopenharmony_ci val >>= shift; 43462306a36Sopenharmony_ci *strength += (val << i); 43562306a36Sopenharmony_ci offset += 4; 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci /* convert to mA */ 43962306a36Sopenharmony_ci *strength = (*strength + 1) * 2; 44062306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&chip->lock, flags); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci return 0; 44362306a36Sopenharmony_ci} 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_cistatic int nsp_pin_config_group_get(struct pinctrl_dev *pctldev, 44662306a36Sopenharmony_ci unsigned selector, 44762306a36Sopenharmony_ci unsigned long *config) 44862306a36Sopenharmony_ci{ 44962306a36Sopenharmony_ci return 0; 45062306a36Sopenharmony_ci} 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_cistatic int nsp_pin_config_group_set(struct pinctrl_dev *pctldev, 45362306a36Sopenharmony_ci unsigned selector, 45462306a36Sopenharmony_ci unsigned long *configs, unsigned num_configs) 45562306a36Sopenharmony_ci{ 45662306a36Sopenharmony_ci return 0; 45762306a36Sopenharmony_ci} 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_cistatic int nsp_pin_config_get(struct pinctrl_dev *pctldev, unsigned pin, 46062306a36Sopenharmony_ci unsigned long *config) 46162306a36Sopenharmony_ci{ 46262306a36Sopenharmony_ci struct nsp_gpio *chip = pinctrl_dev_get_drvdata(pctldev); 46362306a36Sopenharmony_ci enum pin_config_param param = pinconf_to_config_param(*config); 46462306a36Sopenharmony_ci unsigned int gpio; 46562306a36Sopenharmony_ci u16 arg = 0; 46662306a36Sopenharmony_ci bool pull_up, pull_down; 46762306a36Sopenharmony_ci int ret; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci gpio = nsp_pin_to_gpio(pin); 47062306a36Sopenharmony_ci switch (param) { 47162306a36Sopenharmony_ci case PIN_CONFIG_BIAS_DISABLE: 47262306a36Sopenharmony_ci nsp_gpio_get_pull(chip, gpio, &pull_up, &pull_down); 47362306a36Sopenharmony_ci if ((pull_up == false) && (pull_down == false)) 47462306a36Sopenharmony_ci return 0; 47562306a36Sopenharmony_ci else 47662306a36Sopenharmony_ci return -EINVAL; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_UP: 47962306a36Sopenharmony_ci nsp_gpio_get_pull(chip, gpio, &pull_up, &pull_down); 48062306a36Sopenharmony_ci if (pull_up) 48162306a36Sopenharmony_ci return 0; 48262306a36Sopenharmony_ci else 48362306a36Sopenharmony_ci return -EINVAL; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_DOWN: 48662306a36Sopenharmony_ci nsp_gpio_get_pull(chip, gpio, &pull_up, &pull_down); 48762306a36Sopenharmony_ci if (pull_down) 48862306a36Sopenharmony_ci return 0; 48962306a36Sopenharmony_ci else 49062306a36Sopenharmony_ci return -EINVAL; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci case PIN_CONFIG_DRIVE_STRENGTH: 49362306a36Sopenharmony_ci ret = nsp_gpio_get_strength(chip, gpio, &arg); 49462306a36Sopenharmony_ci if (ret) 49562306a36Sopenharmony_ci return ret; 49662306a36Sopenharmony_ci *config = pinconf_to_config_packed(param, arg); 49762306a36Sopenharmony_ci return 0; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci default: 50062306a36Sopenharmony_ci return -ENOTSUPP; 50162306a36Sopenharmony_ci } 50262306a36Sopenharmony_ci} 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_cistatic int nsp_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin, 50562306a36Sopenharmony_ci unsigned long *configs, unsigned num_configs) 50662306a36Sopenharmony_ci{ 50762306a36Sopenharmony_ci struct nsp_gpio *chip = pinctrl_dev_get_drvdata(pctldev); 50862306a36Sopenharmony_ci enum pin_config_param param; 50962306a36Sopenharmony_ci u32 arg; 51062306a36Sopenharmony_ci unsigned int i, gpio; 51162306a36Sopenharmony_ci int ret = -ENOTSUPP; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci gpio = nsp_pin_to_gpio(pin); 51462306a36Sopenharmony_ci for (i = 0; i < num_configs; i++) { 51562306a36Sopenharmony_ci param = pinconf_to_config_param(configs[i]); 51662306a36Sopenharmony_ci arg = pinconf_to_config_argument(configs[i]); 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci switch (param) { 51962306a36Sopenharmony_ci case PIN_CONFIG_BIAS_DISABLE: 52062306a36Sopenharmony_ci ret = nsp_gpio_set_pull(chip, gpio, false, false); 52162306a36Sopenharmony_ci if (ret < 0) 52262306a36Sopenharmony_ci goto out; 52362306a36Sopenharmony_ci break; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_UP: 52662306a36Sopenharmony_ci ret = nsp_gpio_set_pull(chip, gpio, true, false); 52762306a36Sopenharmony_ci if (ret < 0) 52862306a36Sopenharmony_ci goto out; 52962306a36Sopenharmony_ci break; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_DOWN: 53262306a36Sopenharmony_ci ret = nsp_gpio_set_pull(chip, gpio, false, true); 53362306a36Sopenharmony_ci if (ret < 0) 53462306a36Sopenharmony_ci goto out; 53562306a36Sopenharmony_ci break; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci case PIN_CONFIG_DRIVE_STRENGTH: 53862306a36Sopenharmony_ci ret = nsp_gpio_set_strength(chip, gpio, arg); 53962306a36Sopenharmony_ci if (ret < 0) 54062306a36Sopenharmony_ci goto out; 54162306a36Sopenharmony_ci break; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci case PIN_CONFIG_SLEW_RATE: 54462306a36Sopenharmony_ci ret = nsp_gpio_set_slew(chip, gpio, arg); 54562306a36Sopenharmony_ci if (ret < 0) 54662306a36Sopenharmony_ci goto out; 54762306a36Sopenharmony_ci break; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci default: 55062306a36Sopenharmony_ci dev_err(chip->dev, "invalid configuration\n"); 55162306a36Sopenharmony_ci return -ENOTSUPP; 55262306a36Sopenharmony_ci } 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ciout: 55662306a36Sopenharmony_ci return ret; 55762306a36Sopenharmony_ci} 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_cistatic const struct pinconf_ops nsp_pconf_ops = { 56062306a36Sopenharmony_ci .is_generic = true, 56162306a36Sopenharmony_ci .pin_config_get = nsp_pin_config_get, 56262306a36Sopenharmony_ci .pin_config_set = nsp_pin_config_set, 56362306a36Sopenharmony_ci .pin_config_group_get = nsp_pin_config_group_get, 56462306a36Sopenharmony_ci .pin_config_group_set = nsp_pin_config_group_set, 56562306a36Sopenharmony_ci}; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci/* 56862306a36Sopenharmony_ci * NSP GPIO controller supports some PINCONF related configurations such as 56962306a36Sopenharmony_ci * pull up, pull down, slew and drive strength, when the pin is configured 57062306a36Sopenharmony_ci * to GPIO. 57162306a36Sopenharmony_ci * 57262306a36Sopenharmony_ci * Here a local pinctrl device is created with simple 1-to-1 pin mapping to the 57362306a36Sopenharmony_ci * local GPIO pins 57462306a36Sopenharmony_ci */ 57562306a36Sopenharmony_cistatic int nsp_gpio_register_pinconf(struct nsp_gpio *chip) 57662306a36Sopenharmony_ci{ 57762306a36Sopenharmony_ci struct pinctrl_desc *pctldesc = &chip->pctldesc; 57862306a36Sopenharmony_ci struct pinctrl_pin_desc *pins; 57962306a36Sopenharmony_ci struct gpio_chip *gc = &chip->gc; 58062306a36Sopenharmony_ci int i; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci pins = devm_kcalloc(chip->dev, gc->ngpio, sizeof(*pins), GFP_KERNEL); 58362306a36Sopenharmony_ci if (!pins) 58462306a36Sopenharmony_ci return -ENOMEM; 58562306a36Sopenharmony_ci for (i = 0; i < gc->ngpio; i++) { 58662306a36Sopenharmony_ci pins[i].number = i; 58762306a36Sopenharmony_ci pins[i].name = devm_kasprintf(chip->dev, GFP_KERNEL, 58862306a36Sopenharmony_ci "gpio-%d", i); 58962306a36Sopenharmony_ci if (!pins[i].name) 59062306a36Sopenharmony_ci return -ENOMEM; 59162306a36Sopenharmony_ci } 59262306a36Sopenharmony_ci pctldesc->name = dev_name(chip->dev); 59362306a36Sopenharmony_ci pctldesc->pctlops = &nsp_pctrl_ops; 59462306a36Sopenharmony_ci pctldesc->pins = pins; 59562306a36Sopenharmony_ci pctldesc->npins = gc->ngpio; 59662306a36Sopenharmony_ci pctldesc->confops = &nsp_pconf_ops; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci chip->pctl = devm_pinctrl_register(chip->dev, pctldesc, chip); 59962306a36Sopenharmony_ci if (IS_ERR(chip->pctl)) { 60062306a36Sopenharmony_ci dev_err(chip->dev, "unable to register pinctrl device\n"); 60162306a36Sopenharmony_ci return PTR_ERR(chip->pctl); 60262306a36Sopenharmony_ci } 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci return 0; 60562306a36Sopenharmony_ci} 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_cistatic const struct of_device_id nsp_gpio_of_match[] = { 60862306a36Sopenharmony_ci {.compatible = "brcm,nsp-gpio-a",}, 60962306a36Sopenharmony_ci {} 61062306a36Sopenharmony_ci}; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_cistatic int nsp_gpio_probe(struct platform_device *pdev) 61362306a36Sopenharmony_ci{ 61462306a36Sopenharmony_ci struct device *dev = &pdev->dev; 61562306a36Sopenharmony_ci struct nsp_gpio *chip; 61662306a36Sopenharmony_ci struct gpio_chip *gc; 61762306a36Sopenharmony_ci u32 val; 61862306a36Sopenharmony_ci int irq, ret; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci if (of_property_read_u32(pdev->dev.of_node, "ngpios", &val)) { 62162306a36Sopenharmony_ci dev_err(&pdev->dev, "Missing ngpios OF property\n"); 62262306a36Sopenharmony_ci return -ENODEV; 62362306a36Sopenharmony_ci } 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); 62662306a36Sopenharmony_ci if (!chip) 62762306a36Sopenharmony_ci return -ENOMEM; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci chip->dev = dev; 63062306a36Sopenharmony_ci platform_set_drvdata(pdev, chip); 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci chip->base = devm_platform_ioremap_resource(pdev, 0); 63362306a36Sopenharmony_ci if (IS_ERR(chip->base)) { 63462306a36Sopenharmony_ci dev_err(dev, "unable to map I/O memory\n"); 63562306a36Sopenharmony_ci return PTR_ERR(chip->base); 63662306a36Sopenharmony_ci } 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci chip->io_ctrl = devm_platform_ioremap_resource(pdev, 1); 63962306a36Sopenharmony_ci if (IS_ERR(chip->io_ctrl)) { 64062306a36Sopenharmony_ci dev_err(dev, "unable to map I/O memory\n"); 64162306a36Sopenharmony_ci return PTR_ERR(chip->io_ctrl); 64262306a36Sopenharmony_ci } 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci raw_spin_lock_init(&chip->lock); 64562306a36Sopenharmony_ci gc = &chip->gc; 64662306a36Sopenharmony_ci gc->base = -1; 64762306a36Sopenharmony_ci gc->can_sleep = false; 64862306a36Sopenharmony_ci gc->ngpio = val; 64962306a36Sopenharmony_ci gc->label = dev_name(dev); 65062306a36Sopenharmony_ci gc->parent = dev; 65162306a36Sopenharmony_ci gc->request = gpiochip_generic_request; 65262306a36Sopenharmony_ci gc->free = gpiochip_generic_free; 65362306a36Sopenharmony_ci gc->direction_input = nsp_gpio_direction_input; 65462306a36Sopenharmony_ci gc->direction_output = nsp_gpio_direction_output; 65562306a36Sopenharmony_ci gc->get_direction = nsp_gpio_get_direction; 65662306a36Sopenharmony_ci gc->set = nsp_gpio_set; 65762306a36Sopenharmony_ci gc->get = nsp_gpio_get; 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci /* optional GPIO interrupt support */ 66062306a36Sopenharmony_ci irq = platform_get_irq(pdev, 0); 66162306a36Sopenharmony_ci if (irq > 0) { 66262306a36Sopenharmony_ci struct gpio_irq_chip *girq; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci val = readl(chip->base + NSP_CHIP_A_INT_MASK); 66562306a36Sopenharmony_ci val = val | NSP_CHIP_A_GPIO_INT_BIT; 66662306a36Sopenharmony_ci writel(val, (chip->base + NSP_CHIP_A_INT_MASK)); 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci /* Install ISR for this GPIO controller. */ 66962306a36Sopenharmony_ci ret = devm_request_irq(dev, irq, nsp_gpio_irq_handler, 67062306a36Sopenharmony_ci IRQF_SHARED, "gpio-a", &chip->gc); 67162306a36Sopenharmony_ci if (ret) { 67262306a36Sopenharmony_ci dev_err(&pdev->dev, "Unable to request IRQ%d: %d\n", 67362306a36Sopenharmony_ci irq, ret); 67462306a36Sopenharmony_ci return ret; 67562306a36Sopenharmony_ci } 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci girq = &chip->gc.irq; 67862306a36Sopenharmony_ci gpio_irq_chip_set_chip(girq, &nsp_gpio_irq_chip); 67962306a36Sopenharmony_ci /* This will let us handle the parent IRQ in the driver */ 68062306a36Sopenharmony_ci girq->parent_handler = NULL; 68162306a36Sopenharmony_ci girq->num_parents = 0; 68262306a36Sopenharmony_ci girq->parents = NULL; 68362306a36Sopenharmony_ci girq->default_type = IRQ_TYPE_NONE; 68462306a36Sopenharmony_ci girq->handler = handle_bad_irq; 68562306a36Sopenharmony_ci } 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci ret = devm_gpiochip_add_data(dev, gc, chip); 68862306a36Sopenharmony_ci if (ret < 0) 68962306a36Sopenharmony_ci return dev_err_probe(dev, ret, "unable to add GPIO chip\n"); 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci ret = nsp_gpio_register_pinconf(chip); 69262306a36Sopenharmony_ci if (ret) { 69362306a36Sopenharmony_ci dev_err(dev, "unable to register pinconf\n"); 69462306a36Sopenharmony_ci return ret; 69562306a36Sopenharmony_ci } 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci return 0; 69862306a36Sopenharmony_ci} 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_cistatic struct platform_driver nsp_gpio_driver = { 70162306a36Sopenharmony_ci .driver = { 70262306a36Sopenharmony_ci .name = "nsp-gpio-a", 70362306a36Sopenharmony_ci .of_match_table = nsp_gpio_of_match, 70462306a36Sopenharmony_ci }, 70562306a36Sopenharmony_ci .probe = nsp_gpio_probe, 70662306a36Sopenharmony_ci}; 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_cistatic int __init nsp_gpio_init(void) 70962306a36Sopenharmony_ci{ 71062306a36Sopenharmony_ci return platform_driver_register(&nsp_gpio_driver); 71162306a36Sopenharmony_ci} 71262306a36Sopenharmony_ciarch_initcall_sync(nsp_gpio_init); 713