Merge tag 'pinctrl-v4.19-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 14 Aug 2018 19:31:27 +0000 (12:31 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 14 Aug 2018 19:31:27 +0000 (12:31 -0700)
Pull pin control updates from Linus Walleij:
 "This is the bulk of pin control changes for v4.19:

  Core changes:

   - Augment pinctrl_generic_add_group() and pinmux_generic_add_function()
     to return the selector for the added group/function to the caller
     and augment (hopefully) all drivers to handle this

  New subdrivers:

   - Qualcomm PM8998 and PM8005 are supported in the SPMI pin control
     and GPIO driver

   - Intel Ice Lake PCH (platform controller hub) support

   - NXP (ex Freescale) i.MX8MQ support

   - Berlin AS370 support

  Improvements to drivers:

   - Support interrupts on the Ocelot pin controller

   - Add SPI pins to the Uniphier driver

   - Define a GPIO compatible per SoC in the Tegra driver

   - Push Tegra initialization down in the initlevels

   - Support external wakeup interrupts on the Exynos

   - Add generic clocks pins to the meson driver

   - Add USB and HSCIF pins for some Renesas PFC chips

   - Suspend/resume support in the armada-37xx

   - Interrupt support for the Actions Semiconductor S900 also known as
     "owl"

   - Correct the pin ordering in Cedarfork

   - Debugfs output for INTF in the mcp23s08 driver

   - Avoid divisions in context save/restore in pinctrl-single

  The rest is minor bug fixes or cleanups"

* tag 'pinctrl-v4.19-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl: (69 commits)
  pinctrl: nomadik: silence uninitialized variable warning
  pinctrl: axp209: Fix NULL pointer dereference after allocation
  pinctrl: samsung: Remove duplicated "wakeup" in printk
  pinctrl: ocelot: add support for interrupt controller
  pinctrl: intel: Don't shadow error code of gpiochip_lock_as_irq()
  pinctrl: berlin: fix 'pctrl->functions' allocation in berlin_pinctrl_build_state
  gpio: tegra: Move driver registration to subsys_init level
  pinctrl: tegra: Move drivers registration to arch_init level
  pinctrl: baytrail: actually print the apparently misconfigured pin
  MAINTAINERS: Replace Heikki as maintainer of Intel pinctrl
  pinctrl: freescale: off by one in imx1_pinconf_group_dbg_show()
  pinctrl: uniphier: add spi pin-mux settings
  pinctrl: cannonlake: Fix community ordering for H variant
  pinctrl: tegra: define GPIO compatible node per SoC
  pinctrl: intel: Do pin translation when lock IRQ
  pinctrl: imx: off by one in imx_pinconf_group_dbg_show()
  pinctrl: mediatek: include chained_irq.h header
  pinctrl/amd: only handle irq if it is pending and unmasked
  pinctrl/amd: fix gpio irq level in debugfs
  pinctrl: stm32: add syscfg mask parameter
  ...

1  2 
MAINTAINERS
drivers/pinctrl/actions/pinctrl-owl.c
drivers/pinctrl/mediatek/pinctrl-mt7622.c
drivers/pinctrl/pinctrl-single.c

diff --combined MAINTAINERS
index 78608226c30a502290c7891bc7bb0d0e7bd9863b,6fcf510e77a1dba6c8c56f7a34191cefcea82572..fefe315dc6b4d60012ccf32f2bfc8a37ca9ba968
@@@ -581,7 -581,7 +581,7 @@@ W: https://www.infradead.org/~dhowells/
  
  AGPGART DRIVER
  M:    David Airlie <airlied@linux.ie>
 -T:    git git://people.freedesktop.org/~airlied/linux (part of drm maint)
 +T:    git git://anongit.freedesktop.org/drm/drm
  S:    Maintained
  F:    drivers/char/agp/
  F:    include/linux/agp*
@@@ -2523,7 -2523,7 +2523,7 @@@ S:      Supporte
  F:    drivers/scsi/esas2r
  
  ATUSB IEEE 802.15.4 RADIO DRIVER
 -M:    Stefan Schmidt <stefan@osg.samsung.com>
 +M:    Stefan Schmidt <stefan@datenfreihafen.org>
  L:    linux-wpan@vger.kernel.org
  S:    Maintained
  F:    drivers/net/ieee802154/atusb.c
@@@ -2971,13 -2971,9 +2971,13 @@@ N:    bcm585
  N:    bcm586*
  N:    bcm88312
  N:    hr2
 -F:    arch/arm64/boot/dts/broadcom/ns2*
 +N:    stingray
 +F:    arch/arm64/boot/dts/broadcom/northstar2/*
 +F:    arch/arm64/boot/dts/broadcom/stingray/*
  F:    drivers/clk/bcm/clk-ns*
 +F:    drivers/clk/bcm/clk-sr*
  F:    drivers/pinctrl/bcm/pinctrl-ns*
 +F:    include/dt-bindings/clock/bcm-sr*
  
  BROADCOM KONA GPIO DRIVER
  M:    Ray Jui <rjui@broadcom.com>
@@@ -4364,7 -4360,12 +4364,7 @@@ L:     iommu@lists.linux-foundation.or
  T:    git git://git.infradead.org/users/hch/dma-mapping.git
  W:    http://git.infradead.org/users/hch/dma-mapping.git
  S:    Supported
 -F:    lib/dma-debug.c
 -F:    lib/dma-direct.c
 -F:    lib/dma-noncoherent.c
 -F:    lib/dma-virt.c
 -F:    drivers/base/dma-mapping.c
 -F:    drivers/base/dma-coherent.c
 +F:    kernel/dma/
  F:    include/asm-generic/dma-mapping.h
  F:    include/linux/dma-direct.h
  F:    include/linux/dma-mapping.h
@@@ -4460,7 -4461,6 +4460,7 @@@ F:      Documentation/blockdev/drbd
  
  DRIVER CORE, KOBJECTS, DEBUGFS AND SYSFS
  M:    Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 +R:    "Rafael J. Wysocki" <rafael@kernel.org>
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git
  S:    Supported
  F:    Documentation/kobject.txt
@@@ -4631,7 -4631,7 +4631,7 @@@ F:      include/uapi/drm/vmwgfx_drm.
  DRM DRIVERS
  M:    David Airlie <airlied@linux.ie>
  L:    dri-devel@lists.freedesktop.org
 -T:    git git://people.freedesktop.org/~airlied/linux
 +T:    git git://anongit.freedesktop.org/drm/drm
  B:    https://bugs.freedesktop.org/
  C:    irc://chat.freenode.net/dri-devel
  S:    Maintained
@@@ -5444,7 -5444,6 +5444,7 @@@ F:      drivers/iommu/exynos-iommu.
  
  EZchip NPS platform support
  M:    Vineet Gupta <vgupta@synopsys.com>
 +M:    Ofer Levi <oferle@mellanox.com>
  S:    Supported
  F:    arch/arc/plat-eznps
  F:    arch/arc/boot/dts/eznps.dts
@@@ -5675,7 -5674,7 +5675,7 @@@ F:      drivers/crypto/caam
  F:    Documentation/devicetree/bindings/crypto/fsl-sec4.txt
  
  FREESCALE DIU FRAMEBUFFER DRIVER
 -M:    Timur Tabi <timur@tabi.org>
 +M:    Timur Tabi <timur@kernel.org>
  L:    linux-fbdev@vger.kernel.org
  S:    Maintained
  F:    drivers/video/fbdev/fsl-diu-fb.*
@@@ -5775,7 -5774,7 +5775,7 @@@ S:      Maintaine
  F:    drivers/net/wan/fsl_ucc_hdlc*
  
  FREESCALE QUICC ENGINE UCC UART DRIVER
 -M:    Timur Tabi <timur@tabi.org>
 +M:    Timur Tabi <timur@kernel.org>
  L:    linuxppc-dev@lists.ozlabs.org
  S:    Maintained
  F:    drivers/tty/serial/ucc_uart.c
@@@ -5791,6 -5790,7 +5791,6 @@@ F:      include/linux/fsl
  
  FREESCALE SOC FS_ENET DRIVER
  M:    Pantelis Antoniou <pantelis.antoniou@gmail.com>
 -M:    Vitaly Bordug <vbordug@ru.mvista.com>
  L:    linuxppc-dev@lists.ozlabs.org
  L:    netdev@vger.kernel.org
  S:    Maintained
@@@ -5798,7 -5798,7 +5798,7 @@@ F:      drivers/net/ethernet/freescale/fs_en
  F:    include/linux/fs_enet_pd.h
  
  FREESCALE SOC SOUND DRIVERS
 -M:    Timur Tabi <timur@tabi.org>
 +M:    Timur Tabi <timur@kernel.org>
  M:    Nicolin Chen <nicoleotsuka@gmail.com>
  M:    Xiubo Li <Xiubo.Lee@gmail.com>
  R:    Fabio Estevam <fabio.estevam@nxp.com>
@@@ -5930,7 -5930,7 +5930,7 @@@ F:      Documentation/dev-tools/gcov.rs
  
  GDB KERNEL DEBUGGING HELPER SCRIPTS
  M:    Jan Kiszka <jan.kiszka@siemens.com>
 -M:    Kieran Bingham <kieran@bingham.xyz>
 +M:    Kieran Bingham <kbingham@kernel.org>
  S:    Supported
  F:    scripts/gdb/
  
@@@ -6909,7 -6909,7 +6909,7 @@@ F:      drivers/clk/clk-versaclock5.
  
  IEEE 802.15.4 SUBSYSTEM
  M:    Alexander Aring <alex.aring@gmail.com>
 -M:    Stefan Schmidt <stefan@osg.samsung.com>
 +M:    Stefan Schmidt <stefan@datenfreihafen.org>
  L:    linux-wpan@vger.kernel.org
  W:    http://wpan.cakelab.org/
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/sschmidt/wpan.git
@@@ -7096,7 -7096,6 +7096,7 @@@ F:      include/uapi/linux/input.
  F:    include/uapi/linux/input-event-codes.h
  F:    include/linux/input/
  F:    Documentation/devicetree/bindings/input/
 +F:    Documentation/devicetree/bindings/serio/
  F:    Documentation/input/
  
  INPUT MULTITOUCH (MT) PROTOCOL
@@@ -7986,7 -7985,7 +7986,7 @@@ F:      lib/test_kmod.
  F:    tools/testing/selftests/kmod/
  
  KPROBES
 -M:    Ananth N Mavinakayanahalli <ananth@linux.vnet.ibm.com>
 +M:    Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com>
  M:    Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
  M:    "David S. Miller" <davem@davemloft.net>
  M:    Masami Hiramatsu <mhiramat@kernel.org>
@@@ -8317,16 -8316,10 +8317,16 @@@ M:   Jade Alglave <j.alglave@ucl.ac.uk
  M:    Luc Maranget <luc.maranget@inria.fr>
  M:    "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
  R:    Akira Yokosawa <akiyks@gmail.com>
 +R:    Daniel Lustig <dlustig@nvidia.com>
  L:    linux-kernel@vger.kernel.org
 +L:    linux-arch@vger.kernel.org
  S:    Supported
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git
  F:    tools/memory-model/
 +F:    Documentation/atomic_bitops.txt
 +F:    Documentation/atomic_t.txt
 +F:    Documentation/core-api/atomic_ops.rst
 +F:    Documentation/core-api/refcount-vs-atomic.rst
  F:    Documentation/memory-barriers.txt
  
  LINUX SECURITY MODULE (LSM) FRAMEWORK
@@@ -8636,7 -8629,7 +8636,7 @@@ MARVELL MWIFIEX WIRELESS DRIVE
  M:    Amitkumar Karwar <amitkarwar@gmail.com>
  M:    Nishant Sarmukadam <nishants@marvell.com>
  M:    Ganapathi Bhat <gbhat@marvell.com>
 -M:    Xinming Hu <huxm@marvell.com>
 +M:    Xinming Hu <huxinming820@gmail.com>
  L:    linux-wireless@vger.kernel.org
  S:    Maintained
  F:    drivers/net/wireless/marvell/mwifiex/
@@@ -9082,7 -9075,7 +9082,7 @@@ S:      Maintaine
  F:    drivers/usb/mtu3/
  
  MEGACHIPS STDPXXXX-GE-B850V3-FW LVDS/DP++ BRIDGES
 -M:    Peter Senna Tschudin <peter.senna@collabora.com>
 +M:    Peter Senna Tschudin <peter.senna@gmail.com>
  M:    Martin Donnelly <martin.donnelly@ge.com>
  M:    Martyn Welch <martyn.welch@collabora.co.uk>
  S:    Maintained
@@@ -9353,6 -9346,7 +9353,6 @@@ F:      drivers/media/platform/atmel/atmel-i
  F:    devicetree/bindings/media/atmel-isc.txt
  
  MICROCHIP / ATMEL NAND DRIVER
 -M:    Wenyou Yang <wenyou.yang@microchip.com>
  M:    Josh Wu <rainyfeeling@outlook.com>
  L:    linux-mtd@lists.infradead.org
  S:    Supported
@@@ -9762,11 -9756,6 +9762,11 @@@ L:    linux-scsi@vger.kernel.or
  S:    Maintained
  F:    drivers/scsi/NCR_D700.*
  
 +NCSI LIBRARY:
 +M:    Samuel Mendoza-Jonas <sam@mendozajonas.com>
 +S:    Maintained
 +F:    net/ncsi/
 +
  NCT6775 HARDWARE MONITOR DRIVER
  M:    Guenter Roeck <linux@roeck-us.net>
  L:    linux-hwmon@vger.kernel.org
@@@ -9893,7 -9882,6 +9893,7 @@@ M:      Andrew Lunn <andrew@lunn.ch
  M:    Vivien Didelot <vivien.didelot@savoirfairelinux.com>
  M:    Florian Fainelli <f.fainelli@gmail.com>
  S:    Maintained
 +F:    Documentation/devicetree/bindings/net/dsa/
  F:    net/dsa/
  F:    include/net/dsa.h
  F:    include/linux/dsa/
@@@ -10220,13 -10208,11 +10220,13 @@@ F:        sound/soc/codecs/sgtl5000
  
  NXP TDA998X DRM DRIVER
  M:    Russell King <linux@armlinux.org.uk>
 -S:    Supported
 +S:    Maintained
  T:    git git://git.armlinux.org.uk/~rmk/linux-arm.git drm-tda998x-devel
  T:    git git://git.armlinux.org.uk/~rmk/linux-arm.git drm-tda998x-fixes
  F:    drivers/gpu/drm/i2c/tda998x_drv.c
  F:    include/drm/i2c/tda998x.h
 +F:    include/dt-bindings/display/tda998x.h
 +K:    "nxp,tda998x"
  
  NXP TFA9879 DRIVER
  M:    Peter Rosin <peda@axentia.se>
@@@ -11263,7 -11249,7 +11263,7 @@@ F:   Documentation/devicetree/bindings/pi
  
  PIN CONTROLLER - INTEL
  M:    Mika Westerberg <mika.westerberg@linux.intel.com>
- M:    Heikki Krogerus <heikki.krogerus@linux.intel.com>
+ M:    Andy Shevchenko <andriy.shevchenko@linux.intel.com>
  S:    Maintained
  F:    drivers/pinctrl/intel/
  
@@@ -11490,15 -11476,6 +11490,15 @@@ W: http://wireless.kernel.org/en/users/
  S:    Obsolete
  F:    drivers/net/wireless/intersil/prism54/
  
 +PROC FILESYSTEM
 +R:    Alexey Dobriyan <adobriyan@gmail.com>
 +L:    linux-kernel@vger.kernel.org
 +L:    linux-fsdevel@vger.kernel.org
 +S:    Maintained
 +F:    fs/proc/
 +F:    include/linux/proc_fs.h
 +F:    tools/testing/selftests/proc/
 +
  PROC SYSCTL
  M:    "Luis R. Rodriguez" <mcgrof@kernel.org>
  M:    Kees Cook <keescook@chromium.org>
@@@ -11831,9 -11808,9 +11831,9 @@@ F:  Documentation/devicetree/bindings/o
  F:  drivers/cpufreq/qcom-cpufreq-kryo.c
  
  QUALCOMM EMAC GIGABIT ETHERNET DRIVER
 -M:    Timur Tabi <timur@codeaurora.org>
 +M:    Timur Tabi <timur@kernel.org>
  L:    netdev@vger.kernel.org
 -S:    Supported
 +S:    Maintained
  F:    drivers/net/ethernet/qualcomm/emac/
  
  QUALCOMM HEXAGON ARCHITECTURE
@@@ -11844,7 -11821,7 +11844,7 @@@ S:   Supporte
  F:    arch/hexagon/
  
  QUALCOMM HIDMA DRIVER
 -M:    Sinan Kaya <okaya@codeaurora.org>
 +M:    Sinan Kaya <okaya@kernel.org>
  L:    linux-arm-kernel@lists.infradead.org
  L:    linux-arm-msm@vger.kernel.org
  L:    dmaengine@vger.kernel.org
@@@ -12044,9 -12021,9 +12044,9 @@@ T:   git git://git.kernel.org/pub/scm/lin
  F:    Documentation/RCU/
  X:    Documentation/RCU/torture.txt
  F:    include/linux/rcu*
 -X:    include/linux/srcu.h
 +X:    include/linux/srcu*.h
  F:    kernel/rcu/
 -X:    kernel/torture.c
 +X:    kernel/rcu/srcu*.c
  
  REAL TIME CLOCK (RTC) SUBSYSTEM
  M:    Alessandro Zummo <a.zummo@towertech.it>
@@@ -12407,6 -12384,7 +12407,6 @@@ F:   drivers/pci/hotplug/s390_pci_hpc.
  
  S390 VFIO-CCW DRIVER
  M:    Cornelia Huck <cohuck@redhat.com>
 -M:    Dong Jia Shi <bjsdjshi@linux.ibm.com>
  M:    Halil Pasic <pasic@linux.ibm.com>
  L:    linux-s390@vger.kernel.org
  L:    kvm@vger.kernel.org
@@@ -13082,8 -13060,8 +13082,8 @@@ L:   linux-kernel@vger.kernel.or
  W:    http://www.rdrop.com/users/paulmck/RCU/
  S:    Supported
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git
 -F:    include/linux/srcu.h
 -F:    kernel/rcu/srcu.c
 +F:    include/linux/srcu*.h
 +F:    kernel/rcu/srcu*.c
  
  SERIAL LOW-POWER INTER-CHIP MEDIA BUS (SLIMbus)
  M:    Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
@@@ -13670,7 -13648,7 +13670,7 @@@ M:   Konrad Rzeszutek Wilk <konrad.wilk@o
  L:    iommu@lists.linux-foundation.org
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/konrad/swiotlb.git
  S:    Supported
 -F:    lib/swiotlb.c
 +F:    kernel/dma/swiotlb.c
  F:    arch/*/kernel/pci-swiotlb.c
  F:    include/linux/swiotlb.h
  
@@@ -14062,13 -14040,6 +14062,13 @@@ M: Laxman Dewangan <ldewangan@nvidia.co
  S:    Supported
  F:    drivers/input/keyboard/tegra-kbc.c
  
 +TEGRA NAND DRIVER
 +M:    Stefan Agner <stefan@agner.ch>
 +M:    Lucas Stach <dev@lynxeye.de>
 +S:    Maintained
 +F:    Documentation/devicetree/bindings/mtd/nvidia-tegra20-nand.txt
 +F:    drivers/mtd/nand/raw/tegra_nand.c
 +
  TEGRA PWM DRIVER
  M:    Thierry Reding <thierry.reding@gmail.com>
  S:    Supported
@@@ -14449,7 -14420,6 +14449,7 @@@ T:   git git://git.kernel.org/pub/scm/lin
  F:    Documentation/RCU/torture.txt
  F:    kernel/torture.c
  F:    kernel/rcu/rcutorture.c
 +F:    kernel/rcu/rcuperf.c
  F:    kernel/locking/locktorture.c
  
  TOSHIBA ACPI EXTRAS DRIVER
@@@ -15602,17 -15572,9 +15602,17 @@@ M: x86@kernel.or
  L:    linux-kernel@vger.kernel.org
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86/core
  S:    Maintained
 +F:    Documentation/devicetree/bindings/x86/
  F:    Documentation/x86/
  F:    arch/x86/
  
 +X86 ENTRY CODE
 +M:    Andy Lutomirski <luto@kernel.org>
 +L:    linux-kernel@vger.kernel.org
 +T:    git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86/asm
 +S:    Maintained
 +F:    arch/x86/entry/
 +
  X86 MCE INFRASTRUCTURE
  M:    Tony Luck <tony.luck@intel.com>
  M:    Borislav Petkov <bp@alien8.de>
@@@ -15635,7 -15597,7 +15635,7 @@@ F:   drivers/platform/x86
  F:    drivers/platform/olpc/
  
  X86 VDSO
 -M:    Andy Lutomirski <luto@amacapital.net>
 +M:    Andy Lutomirski <luto@kernel.org>
  L:    linux-kernel@vger.kernel.org
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86/vdso
  S:    Maintained
index b5c880b50bb371f5fb5eeddcd0799cd9d7057289,6b89b2b4131691de37c9c81a2239561228de9581..9d18c02f192b3ef8cc5e5ea4b109458ce28744de
@@@ -13,6 -13,7 +13,7 @@@
  #include <linux/err.h>
  #include <linux/gpio/driver.h>
  #include <linux/io.h>
+ #include <linux/irq.h>
  #include <linux/module.h>
  #include <linux/of.h>
  #include <linux/platform_device.h>
@@@ -45,6 -46,9 +46,9 @@@ struct owl_pinctrl 
        struct clk *clk;
        const struct owl_pinctrl_soc_data *soc;
        void __iomem *base;
+       struct irq_chip irq_chip;
+       unsigned int num_irq;
+       unsigned int *irq;
  };
  
  static void owl_update_bits(void __iomem *base, u32 mask, u32 val)
@@@ -333,7 -337,7 +337,7 @@@ static int owl_pin_config_set(struct pi
        unsigned long flags;
        unsigned int param;
        u32 reg, bit, width, arg;
 -      int ret, i;
 +      int ret = 0, i;
  
        info = &pctrl->soc->padinfo[pin];
  
@@@ -701,10 -705,213 +705,213 @@@ static int owl_gpio_direction_output(st
        return 0;
  }
  
+ static void irq_set_type(struct owl_pinctrl *pctrl, int gpio, unsigned int type)
+ {
+       const struct owl_gpio_port *port;
+       void __iomem *gpio_base;
+       unsigned long flags;
+       unsigned int offset, value, irq_type = 0;
+       switch (type) {
+       case IRQ_TYPE_EDGE_BOTH:
+               /*
+                * Since the hardware doesn't support interrupts on both edges,
+                * emulate it in the software by setting the single edge
+                * interrupt and switching to the opposite edge while ACKing
+                * the interrupt
+                */
+               if (owl_gpio_get(&pctrl->chip, gpio))
+                       irq_type = OWL_GPIO_INT_EDGE_FALLING;
+               else
+                       irq_type = OWL_GPIO_INT_EDGE_RISING;
+               break;
+       case IRQ_TYPE_EDGE_RISING:
+               irq_type = OWL_GPIO_INT_EDGE_RISING;
+               break;
+       case IRQ_TYPE_EDGE_FALLING:
+               irq_type = OWL_GPIO_INT_EDGE_FALLING;
+               break;
+       case IRQ_TYPE_LEVEL_HIGH:
+               irq_type = OWL_GPIO_INT_LEVEL_HIGH;
+               break;
+       case IRQ_TYPE_LEVEL_LOW:
+               irq_type = OWL_GPIO_INT_LEVEL_LOW;
+               break;
+       default:
+               break;
+       }
+       port = owl_gpio_get_port(pctrl, &gpio);
+       if (WARN_ON(port == NULL))
+               return;
+       gpio_base = pctrl->base + port->offset;
+       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       offset = (gpio < 16) ? 4 : 0;
+       value = readl_relaxed(gpio_base + port->intc_type + offset);
+       value &= ~(OWL_GPIO_INT_MASK << ((gpio % 16) * 2));
+       value |= irq_type << ((gpio % 16) * 2);
+       writel_relaxed(value, gpio_base + port->intc_type + offset);
+       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+ }
+ static void owl_gpio_irq_mask(struct irq_data *data)
+ {
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
+       struct owl_pinctrl *pctrl = gpiochip_get_data(gc);
+       const struct owl_gpio_port *port;
+       void __iomem *gpio_base;
+       unsigned long flags;
+       unsigned int gpio = data->hwirq;
+       u32 val;
+       port = owl_gpio_get_port(pctrl, &gpio);
+       if (WARN_ON(port == NULL))
+               return;
+       gpio_base = pctrl->base + port->offset;
+       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       owl_gpio_update_reg(gpio_base + port->intc_msk, gpio, false);
+       /* disable port interrupt if no interrupt pending bit is active */
+       val = readl_relaxed(gpio_base + port->intc_msk);
+       if (val == 0)
+               owl_gpio_update_reg(gpio_base + port->intc_ctl,
+                                       OWL_GPIO_CTLR_ENABLE, false);
+       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+ }
+ static void owl_gpio_irq_unmask(struct irq_data *data)
+ {
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
+       struct owl_pinctrl *pctrl = gpiochip_get_data(gc);
+       const struct owl_gpio_port *port;
+       void __iomem *gpio_base;
+       unsigned long flags;
+       unsigned int gpio = data->hwirq;
+       u32 value;
+       port = owl_gpio_get_port(pctrl, &gpio);
+       if (WARN_ON(port == NULL))
+               return;
+       gpio_base = pctrl->base + port->offset;
+       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       /* enable port interrupt */
+       value = readl_relaxed(gpio_base + port->intc_ctl);
+       value |= BIT(OWL_GPIO_CTLR_ENABLE) | BIT(OWL_GPIO_CTLR_SAMPLE_CLK_24M);
+       writel_relaxed(value, gpio_base + port->intc_ctl);
+       /* enable GPIO interrupt */
+       owl_gpio_update_reg(gpio_base + port->intc_msk, gpio, true);
+       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+ }
+ static void owl_gpio_irq_ack(struct irq_data *data)
+ {
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
+       struct owl_pinctrl *pctrl = gpiochip_get_data(gc);
+       const struct owl_gpio_port *port;
+       void __iomem *gpio_base;
+       unsigned long flags;
+       unsigned int gpio = data->hwirq;
+       /*
+        * Switch the interrupt edge to the opposite edge of the interrupt
+        * which got triggered for the case of emulating both edges
+        */
+       if (irqd_get_trigger_type(data) == IRQ_TYPE_EDGE_BOTH) {
+               if (owl_gpio_get(gc, gpio))
+                       irq_set_type(pctrl, gpio, IRQ_TYPE_EDGE_FALLING);
+               else
+                       irq_set_type(pctrl, gpio, IRQ_TYPE_EDGE_RISING);
+       }
+       port = owl_gpio_get_port(pctrl, &gpio);
+       if (WARN_ON(port == NULL))
+               return;
+       gpio_base = pctrl->base + port->offset;
+       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       owl_gpio_update_reg(gpio_base + port->intc_ctl,
+                               OWL_GPIO_CTLR_PENDING, true);
+       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+ }
+ static int owl_gpio_irq_set_type(struct irq_data *data, unsigned int type)
+ {
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
+       struct owl_pinctrl *pctrl = gpiochip_get_data(gc);
+       if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
+               irq_set_handler_locked(data, handle_level_irq);
+       else
+               irq_set_handler_locked(data, handle_edge_irq);
+       irq_set_type(pctrl, data->hwirq, type);
+       return 0;
+ }
+ static void owl_gpio_irq_handler(struct irq_desc *desc)
+ {
+       struct owl_pinctrl *pctrl = irq_desc_get_handler_data(desc);
+       struct irq_chip *chip = irq_desc_get_chip(desc);
+       struct irq_domain *domain = pctrl->chip.irq.domain;
+       unsigned int parent = irq_desc_get_irq(desc);
+       const struct owl_gpio_port *port;
+       void __iomem *base;
+       unsigned int pin, irq, offset = 0, i;
+       unsigned long pending_irq;
+       chained_irq_enter(chip, desc);
+       for (i = 0; i < pctrl->soc->nports; i++) {
+               port = &pctrl->soc->ports[i];
+               base = pctrl->base + port->offset;
+               /* skip ports that are not associated with this irq */
+               if (parent != pctrl->irq[i])
+                       goto skip;
+               pending_irq = readl_relaxed(base + port->intc_pd);
+               for_each_set_bit(pin, &pending_irq, port->pins) {
+                       irq = irq_find_mapping(domain, offset + pin);
+                       generic_handle_irq(irq);
+                       /* clear pending interrupt */
+                       owl_gpio_update_reg(base + port->intc_pd, pin, true);
+               }
+ skip:
+               offset += port->pins;
+       }
+       chained_irq_exit(chip, desc);
+ }
  static int owl_gpio_init(struct owl_pinctrl *pctrl)
  {
        struct gpio_chip *chip;
-       int ret;
+       struct gpio_irq_chip *gpio_irq;
+       int ret, i, j, offset;
  
        chip = &pctrl->chip;
        chip->base = -1;
        chip->owner = THIS_MODULE;
        chip->of_node = pctrl->dev->of_node;
  
+       pctrl->irq_chip.name = chip->of_node->name;
+       pctrl->irq_chip.irq_ack = owl_gpio_irq_ack;
+       pctrl->irq_chip.irq_mask = owl_gpio_irq_mask;
+       pctrl->irq_chip.irq_unmask = owl_gpio_irq_unmask;
+       pctrl->irq_chip.irq_set_type = owl_gpio_irq_set_type;
+       gpio_irq = &chip->irq;
+       gpio_irq->chip = &pctrl->irq_chip;
+       gpio_irq->handler = handle_simple_irq;
+       gpio_irq->default_type = IRQ_TYPE_NONE;
+       gpio_irq->parent_handler = owl_gpio_irq_handler;
+       gpio_irq->parent_handler_data = pctrl;
+       gpio_irq->num_parents = pctrl->num_irq;
+       gpio_irq->parents = pctrl->irq;
+       gpio_irq->map = devm_kcalloc(pctrl->dev, chip->ngpio,
+                               sizeof(*gpio_irq->map), GFP_KERNEL);
+       if (!gpio_irq->map)
+               return -ENOMEM;
+       for (i = 0, offset = 0; i < pctrl->soc->nports; i++) {
+               const struct owl_gpio_port *port = &pctrl->soc->ports[i];
+               for (j = 0; j < port->pins; j++)
+                       gpio_irq->map[offset + j] = gpio_irq->parents[i];
+               offset += port->pins;
+       }
        ret = gpiochip_add_data(&pctrl->chip, pctrl);
        if (ret) {
                dev_err(pctrl->dev, "failed to register gpiochip\n");
@@@ -728,7 -964,7 +964,7 @@@ int owl_pinctrl_probe(struct platform_d
  {
        struct resource *res;
        struct owl_pinctrl *pctrl;
-       int ret;
+       int ret, i;
  
        pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL);
        if (!pctrl)
                                        &owl_pinctrl_desc, pctrl);
        if (IS_ERR(pctrl->pctrldev)) {
                dev_err(&pdev->dev, "could not register Actions OWL pinmux driver\n");
-               return PTR_ERR(pctrl->pctrldev);
+               ret = PTR_ERR(pctrl->pctrldev);
+               goto err_exit;
+       }
+       ret = platform_irq_count(pdev);
+       if (ret < 0)
+               goto err_exit;
+       pctrl->num_irq = ret;
+       pctrl->irq = devm_kcalloc(&pdev->dev, pctrl->num_irq,
+                                       sizeof(*pctrl->irq), GFP_KERNEL);
+       if (!pctrl->irq) {
+               ret = -ENOMEM;
+               goto err_exit;
+       }
+       for (i = 0; i < pctrl->num_irq ; i++) {
+               ret = platform_get_irq(pdev, i);
+               if (ret < 0)
+                       goto err_exit;
+               pctrl->irq[i] = ret;
        }
  
        ret = owl_gpio_init(pctrl);
        if (ret)
-               return ret;
+               goto err_exit;
  
        platform_set_drvdata(pdev, pctrl);
  
        return 0;
+ err_exit:
+       clk_disable_unprepare(pctrl->clk);
+       return ret;
  }
index 4c4740ffeb9ca0807f63d77271ad619407155c3b,26bc13bda09bdb3113dfffa09305aa56f8e60b8d..6f931b85701b5f772f6dbd5ec24d2f02dd91fd4c
@@@ -1263,6 -1263,7 +1263,7 @@@ static int mtk_pinconf_set(struct pinct
                                               MTK_DISABLE);
                        if (err)
                                goto err;
+                       /* else: fall through */
                case PIN_CONFIG_INPUT_ENABLE:
                case PIN_CONFIG_SLEW_RATE:
                        reg = (param == PIN_CONFIG_SLEW_RATE) ?
@@@ -1424,7 -1425,7 +1425,7 @@@ static struct pinctrl_desc mtk_desc = 
  
  static int mtk_gpio_get(struct gpio_chip *chip, unsigned int gpio)
  {
 -      struct mtk_pinctrl *hw = dev_get_drvdata(chip->parent);
 +      struct mtk_pinctrl *hw = gpiochip_get_data(chip);
        int value, err;
  
        err = mtk_hw_get_value(hw, gpio, PINCTRL_PIN_REG_DI, &value);
  
  static void mtk_gpio_set(struct gpio_chip *chip, unsigned int gpio, int value)
  {
 -      struct mtk_pinctrl *hw = dev_get_drvdata(chip->parent);
 +      struct mtk_pinctrl *hw = gpiochip_get_data(chip);
  
        mtk_hw_set_value(hw, gpio, PINCTRL_PIN_REG_DO, !!value);
  }
@@@ -1459,9 -1460,6 +1460,9 @@@ static int mtk_gpio_to_irq(struct gpio_
        struct mtk_pinctrl *hw = gpiochip_get_data(chip);
        unsigned long eint_n;
  
 +      if (!hw->eint)
 +              return -ENOTSUPP;
 +
        eint_n = offset;
  
        return mtk_eint_find_irq(hw->eint, eint_n);
@@@ -1474,8 -1472,7 +1475,8 @@@ static int mtk_gpio_set_config(struct g
        unsigned long eint_n;
        u32 debounce;
  
 -      if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
 +      if (!hw->eint ||
 +          pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
                return -ENOTSUPP;
  
        debounce = pinconf_to_config_argument(config);
@@@ -1508,20 -1505,11 +1509,20 @@@ static int mtk_build_gpiochip(struct mt
        if (ret < 0)
                return ret;
  
 -      ret = gpiochip_add_pin_range(chip, dev_name(hw->dev), 0, 0,
 -                                   chip->ngpio);
 -      if (ret < 0) {
 -              gpiochip_remove(chip);
 -              return ret;
 +      /* Just for backward compatible for these old pinctrl nodes without
 +       * "gpio-ranges" property. Otherwise, called directly from a
 +       * DeviceTree-supported pinctrl driver is DEPRECATED.
 +       * Please see Section 2.1 of
 +       * Documentation/devicetree/bindings/gpio/gpio.txt on how to
 +       * bind pinctrl and gpio drivers via the "gpio-ranges" property.
 +       */
 +      if (!of_find_property(np, "gpio-ranges", NULL)) {
 +              ret = gpiochip_add_pin_range(chip, dev_name(hw->dev), 0, 0,
 +                                           chip->ngpio);
 +              if (ret < 0) {
 +                      gpiochip_remove(chip);
 +                      return ret;
 +              }
        }
  
        return 0;
@@@ -1537,7 -1525,7 +1538,7 @@@ static int mtk_build_groups(struct mtk_
                err = pinctrl_generic_add_group(hw->pctrl, group->name,
                                                group->pins, group->num_pins,
                                                group->data);
-               if (err) {
+               if (err < 0) {
                        dev_err(hw->dev, "Failed to register group %s\n",
                                group->name);
                        return err;
@@@ -1558,7 -1546,7 +1559,7 @@@ static int mtk_build_functions(struct m
                                                  func->group_names,
                                                  func->num_group_names,
                                                  func->data);
-               if (err) {
+               if (err < 0) {
                        dev_err(hw->dev, "Failed to register function %s\n",
                                func->name);
                        return err;
@@@ -1704,16 -1692,15 +1705,16 @@@ static int mtk_pinctrl_probe(struct pla
        mtk_desc.custom_conf_items = mtk_conf_items;
  #endif
  
 -      hw->pctrl = devm_pinctrl_register(&pdev->dev, &mtk_desc, hw);
 -      if (IS_ERR(hw->pctrl))
 -              return PTR_ERR(hw->pctrl);
 +      err = devm_pinctrl_register_and_init(&pdev->dev, &mtk_desc, hw,
 +                                           &hw->pctrl);
 +      if (err)
 +              return err;
  
        /* Setup groups descriptions per SoC types */
        err = mtk_build_groups(hw);
        if (err) {
                dev_err(&pdev->dev, "Failed to build groups\n");
 -              return 0;
 +              return err;
        }
  
        /* Setup functions descriptions per SoC types */
                return err;
        }
  
 -      err = mtk_build_gpiochip(hw, pdev->dev.of_node);
 -      if (err) {
 -              dev_err(&pdev->dev, "Failed to add gpio_chip\n");
 +      /* For able to make pinctrl_claim_hogs, we must not enable pinctrl
 +       * until all groups and functions are being added one.
 +       */
 +      err = pinctrl_enable(hw->pctrl);
 +      if (err)
                return err;
 -      }
  
        err = mtk_build_eint(hw, pdev);
        if (err)
                dev_warn(&pdev->dev,
                         "Failed to add EINT, but pinctrl still can work\n");
  
 +      /* Build gpiochip should be after pinctrl_enable is done */
 +      err = mtk_build_gpiochip(hw, pdev->dev.of_node);
 +      if (err) {
 +              dev_err(&pdev->dev, "Failed to add gpio_chip\n");
 +              return err;
 +      }
 +
        platform_set_drvdata(pdev, hw);
  
        return 0;
index e5647dac0818d46353629a543733fe0af804210b,9fa2f54bb1a3cec73370d96c53db235e9b4c4df7..7ec72ff2419a025ce72d86bacad93cd0584a8dfd
@@@ -747,38 -747,44 +747,44 @@@ static int pcs_allocate_pin_table(struc
  /**
   * pcs_add_function() - adds a new function to the function list
   * @pcs: pcs driver instance
-  * @np: device node of the mux entry
+  * @fcn: new function allocated
   * @name: name of the function
   * @vals: array of mux register value pairs used by the function
   * @nvals: number of mux register value pairs
   * @pgnames: array of pingroup names for the function
   * @npgnames: number of pingroup names
+  *
+  * Caller must take care of locking.
   */
- static struct pcs_function *pcs_add_function(struct pcs_device *pcs,
-                                       struct device_node *np,
-                                       const char *name,
-                                       struct pcs_func_vals *vals,
-                                       unsigned nvals,
-                                       const char **pgnames,
-                                       unsigned npgnames)
+ static int pcs_add_function(struct pcs_device *pcs,
+                           struct pcs_function **fcn,
+                           const char *name,
+                           struct pcs_func_vals *vals,
+                           unsigned int nvals,
+                           const char **pgnames,
+                           unsigned int npgnames)
  {
        struct pcs_function *function;
-       int res;
+       int selector;
  
        function = devm_kzalloc(pcs->dev, sizeof(*function), GFP_KERNEL);
        if (!function)
-               return NULL;
+               return -ENOMEM;
  
        function->vals = vals;
        function->nvals = nvals;
  
-       res = pinmux_generic_add_function(pcs->pctl, name,
-                                         pgnames, npgnames,
-                                         function);
-       if (res)
-               return NULL;
+       selector = pinmux_generic_add_function(pcs->pctl, name,
+                                              pgnames, npgnames,
+                                              function);
+       if (selector < 0) {
+               devm_kfree(pcs->dev, function);
+               *fcn = NULL;
+       } else {
+               *fcn = function;
+       }
  
-       return function;
+       return selector;
  }
  
  /**
@@@ -979,8 -985,8 +985,8 @@@ static int pcs_parse_one_pinctrl_entry(
  {
        const char *name = "pinctrl-single,pins";
        struct pcs_func_vals *vals;
-       int rows, *pins, found = 0, res = -ENOMEM, i;
-       struct pcs_function *function;
+       int rows, *pins, found = 0, res = -ENOMEM, i, fsel, gsel;
+       struct pcs_function *function = NULL;
  
        rows = pinctrl_count_index_with_args(np, name);
        if (rows <= 0) {
        }
  
        pgnames[0] = np->name;
-       function = pcs_add_function(pcs, np, np->name, vals, found, pgnames, 1);
-       if (!function) {
-               res = -ENOMEM;
+       mutex_lock(&pcs->mutex);
+       fsel = pcs_add_function(pcs, &function, np->name, vals, found,
+                               pgnames, 1);
+       if (fsel < 0) {
+               res = fsel;
                goto free_pins;
        }
  
-       res = pinctrl_generic_add_group(pcs->pctl, np->name, pins, found, pcs);
-       if (res < 0)
+       gsel = pinctrl_generic_add_group(pcs->pctl, np->name, pins, found, pcs);
+       if (gsel < 0) {
+               res = gsel;
                goto free_function;
+       }
  
        (*map)->type = PIN_MAP_TYPE_MUX_GROUP;
        (*map)->data.mux.group = np->name;
        (*map)->data.mux.function = np->name;
  
-       if (PCS_HAS_PINCONF) {
+       if (PCS_HAS_PINCONF && function) {
                res = pcs_parse_pinconf(pcs, np, function, map);
                if (res)
                        goto free_pingroups;
        } else {
                *num_maps = 1;
        }
+       mutex_unlock(&pcs->mutex);
        return 0;
  
  free_pingroups:
-       pinctrl_generic_remove_last_group(pcs->pctl);
+       pinctrl_generic_remove_group(pcs->pctl, gsel);
        *num_maps = 1;
  free_function:
-       pinmux_generic_remove_last_function(pcs->pctl);
+       pinmux_generic_remove_function(pcs->pctl, fsel);
  free_pins:
+       mutex_unlock(&pcs->mutex);
        devm_kfree(pcs->dev, pins);
  
  free_vals:
@@@ -1077,9 -1089,9 +1089,9 @@@ static int pcs_parse_bits_in_pinctrl_en
  {
        const char *name = "pinctrl-single,bits";
        struct pcs_func_vals *vals;
-       int rows, *pins, found = 0, res = -ENOMEM, i;
+       int rows, *pins, found = 0, res = -ENOMEM, i, fsel, gsel;
        int npins_in_row;
-       struct pcs_function *function;
+       struct pcs_function *function = NULL;
  
        rows = pinctrl_count_index_with_args(np, name);
        if (rows <= 0) {
        }
  
        pgnames[0] = np->name;
-       function = pcs_add_function(pcs, np, np->name, vals, found, pgnames, 1);
-       if (!function) {
-               res = -ENOMEM;
+       mutex_lock(&pcs->mutex);
+       fsel = pcs_add_function(pcs, &function, np->name, vals, found,
+                               pgnames, 1);
+       if (fsel < 0) {
+               res = fsel;
                goto free_pins;
        }
  
-       res = pinctrl_generic_add_group(pcs->pctl, np->name, pins, found, pcs);
-       if (res < 0)
+       gsel = pinctrl_generic_add_group(pcs->pctl, np->name, pins, found, pcs);
+       if (gsel < 0) {
+               res = gsel;
                goto free_function;
+       }
  
        (*map)->type = PIN_MAP_TYPE_MUX_GROUP;
        (*map)->data.mux.group = np->name;
        }
  
        *num_maps = 1;
+       mutex_unlock(&pcs->mutex);
        return 0;
  
  free_pingroups:
-       pinctrl_generic_remove_last_group(pcs->pctl);
+       pinctrl_generic_remove_group(pcs->pctl, gsel);
        *num_maps = 1;
  free_function:
-       pinmux_generic_remove_last_function(pcs->pctl);
+       pinmux_generic_remove_function(pcs->pctl, fsel);
  free_pins:
+       mutex_unlock(&pcs->mutex);
        devm_kfree(pcs->dev, pins);
  
  free_vals:
@@@ -1590,27 -1609,24 +1609,27 @@@ static int pcs_save_context(struct pcs_
  
        mux_bytes = pcs->width / BITS_PER_BYTE;
  
 -      if (!pcs->saved_vals)
 +      if (!pcs->saved_vals) {
                pcs->saved_vals = devm_kzalloc(pcs->dev, pcs->size, GFP_ATOMIC);
 +              if (!pcs->saved_vals)
 +                      return -ENOMEM;
 +      }
  
        switch (pcs->width) {
        case 64:
-               regsl = (u64 *)pcs->saved_vals;
-               for (i = 0; i < pcs->size / mux_bytes; i++)
-                       regsl[i] = pcs->read(pcs->base + i * mux_bytes);
+               regsl = pcs->saved_vals;
+               for (i = 0; i < pcs->size; i += mux_bytes)
+                       *regsl++ = pcs->read(pcs->base + i);
                break;
        case 32:
-               regsw = (u32 *)pcs->saved_vals;
-               for (i = 0; i < pcs->size / mux_bytes; i++)
-                       regsw[i] = pcs->read(pcs->base + i * mux_bytes);
+               regsw = pcs->saved_vals;
+               for (i = 0; i < pcs->size; i += mux_bytes)
+                       *regsw++ = pcs->read(pcs->base + i);
                break;
        case 16:
-               regshw = (u16 *)pcs->saved_vals;
-               for (i = 0; i < pcs->size / mux_bytes; i++)
-                       regshw[i] = pcs->read(pcs->base + i * mux_bytes);
+               regshw = pcs->saved_vals;
+               for (i = 0; i < pcs->size; i += mux_bytes)
+                       *regshw++ = pcs->read(pcs->base + i);
                break;
        }
  
@@@ -1628,19 -1644,19 +1647,19 @@@ static void pcs_restore_context(struct 
  
        switch (pcs->width) {
        case 64:
-               regsl = (u64 *)pcs->saved_vals;
-               for (i = 0; i < pcs->size / mux_bytes; i++)
-                       pcs->write(regsl[i], pcs->base + i * mux_bytes);
+               regsl = pcs->saved_vals;
+               for (i = 0; i < pcs->size; i += mux_bytes)
+                       pcs->write(*regsl++, pcs->base + i);
                break;
        case 32:
-               regsw = (u32 *)pcs->saved_vals;
-               for (i = 0; i < pcs->size / mux_bytes; i++)
-                       pcs->write(regsw[i], pcs->base + i * mux_bytes);
+               regsw = pcs->saved_vals;
+               for (i = 0; i < pcs->size; i += mux_bytes)
+                       pcs->write(*regsw++, pcs->base + i);
                break;
        case 16:
-               regshw = (u16 *)pcs->saved_vals;
-               for (i = 0; i < pcs->size / mux_bytes; i++)
-                       pcs->write(regshw[i], pcs->base + i * mux_bytes);
+               regshw = pcs->saved_vals;
+               for (i = 0; i < pcs->size; i += mux_bytes)
+                       pcs->write(*regshw++, pcs->base + i);
                break;
        }
  }
@@@ -1654,13 -1670,8 +1673,13 @@@ static int pinctrl_single_suspend(struc
        if (!pcs)
                return -EINVAL;
  
 -      if (pcs->flags & PCS_CONTEXT_LOSS_OFF)
 -              pcs_save_context(pcs);
 +      if (pcs->flags & PCS_CONTEXT_LOSS_OFF) {
 +              int ret;
 +
 +              ret = pcs_save_context(pcs);
 +              if (ret < 0)
 +                      return ret;
 +      }
  
        return pinctrl_force_sleep(pcs->pctl);
  }