]> Git Repo - J-linux.git/commitdiff
Merge tag 'gpio-updates-for-v6.6' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <[email protected]>
Tue, 29 Aug 2023 17:21:56 +0000 (10:21 -0700)
committerLinus Torvalds <[email protected]>
Tue, 29 Aug 2023 17:21:56 +0000 (10:21 -0700)
Pull gpio updates from Bartosz Golaszewski:
 "We have a lot of code refactoring using common helpers and ended up
  removing more lines then we're adding this release cycle.

  Nothing really stands out, just small updates all over the place.

  Core GPIOLIB updates:
   - wake-up poll() in user-space on device unbind
   - improve fwnode usage
   - interrupt domain handling improvements
   - correctly handle the ngpios property in gpio-mmio

  Driver cleanups:
   - remove unneeded calls to platform_set_drvdata() all around the
     place
   - remove unneeded of_match_ptr() expansions whenever a driver depends
     on CONFIG_OF
   - remove redundant calls to dev_err_probe() from gpio-omap and
     gpio-davinci

  Driver improvements:
   - use autopointers and guards from cleanup.h in gpio-sim
   - shrink code in gpio-sim using some common helpers
   - convert the idio family of drivers to using gpio-regmap
   - convert gpio-ws16c48 to using gpio-regmap
   - use devres to simplify code in gpio-pisosr and gpio-mxc
   - update gpio-sifive: support IRQ wake, improve interrupt handling,
     allow building as module
   - make gpio-ge and gpio-bcm-kona OF-independent (plus some minor
     tweaks)
   - add support for new models in gpio-pca953x and gpio-ds4520
   - add runtime PM support to gpio-mxc
   - fix a build warning in gpio-mxs
   - add support for adding pin ranges to gpio-mlxbf3
   - add counter/timer support to gpio-104-dio-48e
   - switch to dynamic GPIO base allocation in gpio-vf610
   - minor oneliners here and there

  Device-tree bindings updates:
   - enable the gpio-line-names property in snps,dw-apb and STMPE GPIO
   - document new models in fsl-imx-gpio, ds4520 and pca95xx
   - convert the bindings for brcm,kona-gpio to YAML"

* tag 'gpio-updates-for-v6.6' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux: (94 commits)
  gpio: pca953x: add support for TCA9538
  dt-bindings: gpio: pca95xx: document new tca9538 chip
  gpio: pca953x: Use i2c_get_match_data()
  gpio: mlxbf3: use capital "OR" for multiple licenses in SPDX
  gpio: pcf857x: Extend match data support for OF tables
  gpio: vf610: switch to dynamic allocat GPIO base
  gpiolib: provide and use gpiod_line_state_notify()
  gpio: cdev: wake up lineevent poll() on device unbind
  gpio: cdev: wake up linereq poll() on device unbind
  gpio: cdev: wake up chardev poll() on device unbind
  gpiolib: add a second blocking notifier to struct gpio_device
  gpio: cdev: open-code to_gpio_chardev_data()
  gpiolib: rename the gpio_device notifier
  gpio: mlxbf3: Support add_pin_ranges()
  gpio: mxc: Use helper function devm_clk_get_optional_enabled()
  gpio: pca9570: fix kerneldoc
  gpio: sim: simplify code with cleanup helpers
  gpio: sim: replace memmove() + strstrip() with skip_spaces() + strim()
  gpio: sim: simplify gpio_sim_device_config_live_store()
  gpio: mxc: release the parent IRQ in runtime suspend
  ...

1  2 
MAINTAINERS
drivers/gpio/gpio-sim.c
drivers/gpio/gpio-ws16c48.c
drivers/gpio/gpiolib-of.c
drivers/gpio/gpiolib.c

diff --combined MAINTAINERS
index 657bd6cad820f27e3491523b183d573fe9330451,e423e15f48f1c8c8f7c7496fd120b5552d2c102e..a9f7c7eea41d470564c0b9f27b57f7ea1f049603
@@@ -1865,11 -1865,9 +1865,11 @@@ M:    Martin Povišer <[email protected]
  L:    [email protected]
  L:    [email protected] (moderated for non-subscribers)
  S:    Maintained
 +F:    Documentation/devicetree/bindings/sound/adi,ssm3515.yaml
  F:    Documentation/devicetree/bindings/sound/apple,*
  F:    sound/soc/apple/*
  F:    sound/soc/codecs/cs42l83-i2c.c
 +F:    sound/soc/codecs/ssm3515.c
  
  ARM/APPLE MACHINE SUPPORT
  M:    Hector Martin <[email protected]>
@@@ -2339,7 -2337,7 +2339,7 @@@ F:      drivers/phy/mediatek
  ARM/MICROCHIP (ARM64) SoC support
  M:    Conor Dooley <[email protected]>
  M:    Nicolas Ferre <[email protected]>
 -M:    Claudiu Beznea <claudiu.beznea@microchip.com>
 +M:    Claudiu Beznea <claudiu.beznea@tuxon.dev>
  L:    [email protected] (moderated for non-subscribers)
  S:    Supported
  T:    git https://git.kernel.org/pub/scm/linux/kernel/git/at91/linux.git
@@@ -2348,7 -2346,7 +2348,7 @@@ F:      arch/arm64/boot/dts/microchip
  ARM/Microchip (AT91) SoC support
  M:    Nicolas Ferre <[email protected]>
  M:    Alexandre Belloni <[email protected]>
 -M:    Claudiu Beznea <claudiu.beznea@microchip.com>
 +M:    Claudiu Beznea <claudiu.beznea@tuxon.dev>
  L:    [email protected] (moderated for non-subscribers)
  S:    Supported
  W:    http://www.linux4sam.org
@@@ -3250,7 -3248,7 +3250,7 @@@ F:      include/uapi/linux/atm
  
  ATMEL MACB ETHERNET DRIVER
  M:    Nicolas Ferre <[email protected]>
 -M:    Claudiu Beznea <claudiu.beznea@microchip.com>
 +M:    Claudiu Beznea <claudiu.beznea@tuxon.dev>
  S:    Supported
  F:    drivers/net/ethernet/cadence/
  
@@@ -3262,8 -3260,9 +3262,8 @@@ F:      Documentation/devicetree/bindings/in
  F:    drivers/input/touchscreen/atmel_mxt_ts.c
  
  ATMEL WIRELESS DRIVER
 -M:    Simon Kelley <[email protected]>
  L:    [email protected]
 -S:    Maintained
 +S:    Orphan
  W:    http://www.thekelleys.org.uk/atmel
  W:    http://atmelwlandriver.sourceforge.net/
  F:    drivers/net/wireless/atmel/atmel*
@@@ -3393,7 -3392,7 +3393,7 @@@ F:      drivers/media/radio/radio-aztech
  B43 WIRELESS DRIVER
  L:    [email protected]
  L:    [email protected]
 -S:    Odd Fixes
 +S:    Orphan
  W:    https://wireless.wiki.kernel.org/en/users/Drivers/b43
  F:    drivers/net/wireless/broadcom/b43/
  
@@@ -4122,13 -4121,6 +4122,13 @@@ F:    Documentation/devicetree/bindings/sp
  F:    drivers/spi/spi-bcm63xx-hsspi.c
  F:    drivers/spi/spi-bcmbca-hsspi.c
  
 +BROADCOM BCM6348/BCM6358 SPI controller DRIVER
 +M:    Jonas Gorski <[email protected]>
 +L:    [email protected]
 +S:    Odd Fixes
 +F:    Documentation/devicetree/bindings/spi/brcm,bcm63xx-spi.yaml
 +F:    drivers/spi/spi-bcm63xx.c
 +
  BROADCOM ETHERNET PHY DRIVERS
  M:    Florian Fainelli <[email protected]>
  R:    Broadcom internal kernel review list <[email protected]>
@@@ -4195,7 -4187,7 +4195,7 @@@ BROADCOM KONA GPIO DRIVE
  M:    Ray Jui <[email protected]>
  R:    Broadcom internal kernel review list <[email protected]>
  S:    Supported
- F:    Documentation/devicetree/bindings/gpio/brcm,kona-gpio.txt
+ F:    Documentation/devicetree/bindings/gpio/brcm,kona-gpio.yaml
  F:    drivers/gpio/gpio-bcm-kona.c
  
  BROADCOM MPI3 STORAGE CONTROLLER DRIVER
@@@ -4462,6 -4454,7 +4462,6 @@@ CADENCE USB3 DRD IP DRIVE
  M:    Peter Chen <[email protected]>
  M:    Pawel Laszczak <[email protected]>
  R:    Roger Quadros <[email protected]>
 -R:    Aswath Govindraju <[email protected]>
  L:    [email protected]
  S:    Maintained
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/peter.chen/usb.git
@@@ -4819,7 -4812,6 +4819,7 @@@ F:      drivers/input/touchscreen/chipone_ic
  
  CHROME HARDWARE PLATFORM SUPPORT
  M:    Benson Leung <[email protected]>
 +M:    Tzung-Bi Shih <[email protected]>
  L:    [email protected]
  S:    Maintained
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/chrome-platform/linux.git
@@@ -4887,11 -4879,7 +4887,11 @@@ L:    [email protected] (moderat
  L:    [email protected]
  S:    Maintained
  F:    Documentation/devicetree/bindings/sound/cirrus,cs*
 +F:    drivers/mfd/cs42l43*
 +F:    drivers/pinctrl/cirrus/pinctrl-cs42l43*
 +F:    drivers/spi/spi-cs42l43*
  F:    include/dt-bindings/sound/cs*
 +F:    include/linux/mfd/cs42l43*
  F:    include/sound/cs*
  F:    sound/pci/hda/cs*
  F:    sound/pci/hda/hda_cs_dsp_ctl.*
@@@ -5152,12 -5140,10 +5152,12 @@@ S:   Maintaine
  F:    include/linux/compiler_attributes.h
  
  COMPUTE EXPRESS LINK (CXL)
 +M:    Davidlohr Bueso <[email protected]>
 +M:    Jonathan Cameron <[email protected]>
 +M:    Dave Jiang <[email protected]>
  M:    Alison Schofield <[email protected]>
  M:    Vishal Verma <[email protected]>
  M:    Ira Weiny <[email protected]>
 -M:    Ben Widawsky <[email protected]>
  M:    Dan Williams <[email protected]>
  L:    [email protected]
  S:    Maintained
@@@ -5466,7 -5452,8 +5466,7 @@@ F:      Documentation/devicetree/bindings/ne
  F:    drivers/net/can/ctucanfd/
  
  CW1200 WLAN driver
 -M:    Solomon Peachy <[email protected]>
 -S:    Maintained
 +S:    Orphan
  F:    drivers/net/wireless/st/cw1200/
  
  CX18 VIDEO4LINUX DRIVER
@@@ -6014,7 -6001,7 +6014,7 @@@ F:      Documentation/devicetree/bindings/mf
  F:    Documentation/devicetree/bindings/mfd/dlg,da90*.yaml
  F:    Documentation/devicetree/bindings/regulator/da92*.txt
  F:    Documentation/devicetree/bindings/regulator/dlg,da9*.yaml
 -F:    Documentation/devicetree/bindings/regulator/slg51000.txt
 +F:    Documentation/devicetree/bindings/regulator/dlg,slg51000.yaml
  F:    Documentation/devicetree/bindings/sound/da[79]*.txt
  F:    Documentation/devicetree/bindings/thermal/da90??-thermal.txt
  F:    Documentation/devicetree/bindings/watchdog/da90??-wdt.txt
@@@ -8685,11 -8672,8 +8685,11 @@@ S:    Maintaine
  F:    drivers/input/touchscreen/resistive-adc-touch.c
  
  GENERIC STRING LIBRARY
 +M:    Kees Cook <[email protected]>
  R:    Andy Shevchenko <[email protected]>
 -S:    Maintained
 +L:    [email protected]
 +S:    Supported
 +T:    git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/hardening
  F:    include/linux/string.h
  F:    include/linux/string_choices.h
  F:    include/linux/string_helpers.h
@@@ -8774,15 -8758,6 +8774,15 @@@ S:    Supporte
  F:    Documentation/networking/device_drivers/ethernet/google/gve.rst
  F:    drivers/net/ethernet/google
  
 +GOOGLE FIRMWARE DRIVERS
 +M:    Tzung-Bi Shih <[email protected]>
 +R:    Brian Norris <[email protected]>
 +R:    Julius Werner <[email protected]>
 +L:    [email protected]
 +S:    Maintained
 +T:    git git://git.kernel.org/pub/scm/linux/kernel/git/chrome-platform/linux.git
 +F:    drivers/firmware/google/
 +
  GPD POCKET FAN DRIVER
  M:    Hans de Goede <[email protected]>
  L:    [email protected]
@@@ -8826,7 -8801,6 +8826,7 @@@ R:      Michael Walle <[email protected]
  S:    Maintained
  F:    drivers/gpio/gpio-regmap.c
  F:    include/linux/gpio/regmap.h
 +K:    (devm_)?gpio_regmap_(un)?register
  
  GPIO SUBSYSTEM
  M:    Linus Walleij <[email protected]>
@@@ -9320,7 -9294,7 +9320,7 @@@ F:      drivers/crypto/hisilicon/hpre/hpre_c
  F:    drivers/crypto/hisilicon/hpre/hpre_main.c
  
  HISILICON HNS3 PMU DRIVER
 -M:    Guangbin Huang <huangguangbin2@huawei.com>
 +M:    Jijie Shao <shaojijie@huawei.com>
  S:    Supported
  F:    Documentation/admin-guide/perf/hns3-pmu.rst
  F:    drivers/perf/hisilicon/hns3_pmu.c
@@@ -9358,7 -9332,7 +9358,7 @@@ F:      Documentation/devicetree/bindings/ne
  F:    drivers/net/ethernet/hisilicon/
  
  HISILICON PMU DRIVER
 -M:    Shaokun Zhang <zhangshaokun@hisilicon.com>
 +M:    Yicong Yang <yangyicong@hisilicon.com>
  M:    Jonathan Cameron <[email protected]>
  S:    Supported
  W:    http://www.hisilicon.com
@@@ -9390,6 -9364,7 +9390,6 @@@ F:      drivers/crypto/hisilicon/sgl.
  F:    include/linux/hisi_acc_qm.h
  
  HISILICON ROCE DRIVER
 -M:    Haoyue Xu <[email protected]>
  M:    Junxian Huang <[email protected]>
  L:    [email protected]
  S:    Maintained
@@@ -9509,12 -9484,6 +9509,12 @@@ S:    Maintaine
  W:    http://artax.karlin.mff.cuni.cz/~mikulas/vyplody/hpfs/index-e.cgi
  F:    fs/hpfs/
  
 +HS3001 Hardware Temperature and Humidity Sensor
 +M:    Andre Werner <[email protected]>
 +L:    [email protected]
 +S:    Maintained
 +F:    drivers/hwmon/hs3001.c
 +
  HSI SUBSYSTEM
  M:    Sebastian Reichel <[email protected]>
  S:    Maintained
@@@ -9680,7 -9649,6 +9680,7 @@@ F:      tools/hv
  
  HYPERBUS SUPPORT
  M:    Vignesh Raghavendra <[email protected]>
 +R:    Tudor Ambarus <[email protected]>
  L:    [email protected]
  S:    Supported
  Q:    http://patchwork.ozlabs.org/project/linux-mtd/list/
@@@ -11404,8 -11372,6 +11404,8 @@@ T:   git git://git.kernel.org/pub/scm/lin
  F:    Documentation/dev-tools/kunit/
  F:    include/kunit/
  F:    lib/kunit/
 +F:    rust/kernel/kunit.rs
 +F:    scripts/rustdoc_test_*
  F:    tools/testing/kunit/
  
  KERNEL USERMODE HELPER
@@@ -12292,16 -12258,6 +12292,16 @@@ F: Documentation/devicetree/bindings/cl
  F:    drivers/clk/clk-loongson2.c
  F:    include/dt-bindings/clock/loongson,ls2k-clk.h
  
 +LOONGSON SPI DRIVER
 +M:    Yinbo Zhu <[email protected]>
 +L:    [email protected]
 +S:    Maintained
 +F:    Documentation/devicetree/bindings/spi/loongson,ls2k-spi.yaml
 +F:    drivers/spi/spi-loongson-core.c
 +F:    drivers/spi/spi-loongson-pci.c
 +F:    drivers/spi/spi-loongson-plat.c
 +F:    drivers/spi/spi-loongson.h
 +
  LOONGSON-2 SOC SERIES GUTS DRIVER
  M:    Yinbo Zhu <[email protected]>
  L:    [email protected]
@@@ -12512,7 -12468,6 +12512,7 @@@ F:   net/mctp
  
  MAPLE TREE
  M:    Liam R. Howlett <[email protected]>
 +L:    [email protected]
  L:    [email protected]
  S:    Supported
  F:    Documentation/core-api/maple_tree.rst
@@@ -12624,14 -12579,18 +12624,14 @@@ F:        Documentation/devicetree/bindings/ne
  F:    drivers/net/ethernet/marvell/mvpp2/
  
  MARVELL MWIFIEX WIRELESS DRIVER
 -M:    Amitkumar Karwar <[email protected]>
 -M:    Ganapathi Bhat <[email protected]>
 -M:    Sharvari Harisangam <[email protected]>
 -M:    Xinming Hu <[email protected]>
 +M:    Brian Norris <[email protected]>
  L:    [email protected]
 -S:    Maintained
 +S:    Odd Fixes
  F:    drivers/net/wireless/marvell/mwifiex/
  
  MARVELL MWL8K WIRELESS DRIVER
 -M:    Lennert Buytenhek <[email protected]>
  L:    [email protected]
 -S:    Odd Fixes
 +S:    Orphan
  F:    drivers/net/wireless/marvell/mwl8k.c
  
  MARVELL NAND CONTROLLER DRIVER
@@@ -13819,7 -13778,7 +13819,7 @@@ F:   Documentation/devicetree/bindings/se
  F:    drivers/spi/spi-at91-usart.c
  
  MICROCHIP AUDIO ASOC DRIVERS
 -M:    Claudiu Beznea <claudiu.beznea@microchip.com>
 +M:    Claudiu Beznea <claudiu.beznea@tuxon.dev>
  L:    [email protected] (moderated for non-subscribers)
  S:    Supported
  F:    Documentation/devicetree/bindings/sound/atmel*
@@@ -13842,7 -13801,7 +13842,7 @@@ S:   Maintaine
  F:    drivers/crypto/atmel-ecc.*
  
  MICROCHIP EIC DRIVER
 -M:    Claudiu Beznea <claudiu.beznea@microchip.com>
 +M:    Claudiu Beznea <claudiu.beznea@tuxon.dev>
  L:    [email protected] (moderated for non-subscribers)
  S:    Supported
  F:    Documentation/devicetree/bindings/interrupt-controller/microchip,sama7g5-eic.yaml
@@@ -13915,7 -13874,7 +13915,7 @@@ F:   drivers/video/fbdev/atmel_lcdfb.
  F:    include/video/atmel_lcdc.h
  
  MICROCHIP MCP16502 PMIC DRIVER
 -M:    Claudiu Beznea <claudiu.beznea@microchip.com>
 +M:    Claudiu Beznea <claudiu.beznea@tuxon.dev>
  L:    [email protected] (moderated for non-subscribers)
  S:    Supported
  F:    Documentation/devicetree/bindings/regulator/mcp16502-regulator.txt
@@@ -13942,7 -13901,7 +13942,7 @@@ F:   Documentation/devicetree/bindings/mt
  F:    drivers/mtd/nand/raw/atmel/*
  
  MICROCHIP OTPC DRIVER
 -M:    Claudiu Beznea <claudiu.beznea@microchip.com>
 +M:    Claudiu Beznea <claudiu.beznea@tuxon.dev>
  L:    [email protected] (moderated for non-subscribers)
  S:    Supported
  F:    Documentation/devicetree/bindings/nvmem/microchip,sama7g5-otpc.yaml
@@@ -13981,7 -13940,7 +13981,7 @@@ F:   Documentation/devicetree/bindings/fp
  F:    drivers/fpga/microchip-spi.c
  
  MICROCHIP PWM DRIVER
 -M:    Claudiu Beznea <claudiu.beznea@microchip.com>
 +M:    Claudiu Beznea <claudiu.beznea@tuxon.dev>
  L:    [email protected] (moderated for non-subscribers)
  L:    [email protected]
  S:    Supported
@@@ -13997,7 -13956,7 +13997,7 @@@ F:   drivers/iio/adc/at91-sama5d2_adc.
  F:    include/dt-bindings/iio/adc/at91-sama5d2_adc.h
  
  MICROCHIP SAMA5D2-COMPATIBLE SHUTDOWN CONTROLLER
 -M:    Claudiu Beznea <claudiu.beznea@microchip.com>
 +M:    Claudiu Beznea <claudiu.beznea@tuxon.dev>
  S:    Supported
  F:    Documentation/devicetree/bindings/power/reset/atmel,sama5d2-shdwc.yaml
  F:    drivers/power/reset/at91-sama5d2_shdwc.c
@@@ -14009,12 -13968,12 +14009,12 @@@ T:        git https://git.kernel.org/pub/scm/l
  F:    drivers/soc/microchip/
  
  MICROCHIP SPI DRIVER
 -M:    Tudor Ambarus <[email protected]>
 +M:    Ryan Wanner <[email protected]>
  S:    Supported
  F:    drivers/spi/spi-atmel.*
  
  MICROCHIP SSC DRIVER
 -M:    Claudiu Beznea <claudiu.beznea@microchip.com>
 +M:    Claudiu Beznea <claudiu.beznea@tuxon.dev>
  L:    [email protected] (moderated for non-subscribers)
  S:    Supported
  F:    Documentation/devicetree/bindings/misc/atmel-ssc.txt
@@@ -14043,7 -14002,7 +14043,7 @@@ F:   drivers/usb/gadget/udc/atmel_usba_ud
  
  MICROCHIP WILC1000 WIFI DRIVER
  M:    Ajay Singh <[email protected]>
 -M:    Claudiu Beznea <claudiu.beznea@microchip.com>
 +M:    Claudiu Beznea <claudiu.beznea@tuxon.dev>
  L:    [email protected]
  S:    Supported
  F:    drivers/net/wireless/microchip/wilc1000/
@@@ -14835,16 -14794,6 +14835,16 @@@ F: net/netfilter/xt_CONNSECMARK.
  F:    net/netfilter/xt_SECMARK.c
  F:    net/netlabel/
  
 +NETWORKING [MACSEC]
 +M:    Sabrina Dubroca <[email protected]>
 +L:    [email protected]
 +S:    Maintained
 +F:    drivers/net/macsec.c
 +F:    include/net/macsec.h
 +F:    include/uapi/linux/if_macsec.h
 +K:    macsec
 +K:    \bmdo_
 +
  NETWORKING [MPTCP]
  M:    Matthieu Baerts <[email protected]>
  M:    Mat Martineau <[email protected]>
@@@ -15030,7 -14979,6 +15030,7 @@@ F:   include/linux/power/bq27xxx_battery.
  
  NOLIBC HEADER FILE
  M:    Willy Tarreau <[email protected]>
 +M:    Thomas Weißschuh <[email protected]>
  S:    Maintained
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/wtarreau/nolibc.git
  F:    tools/include/nolibc/
@@@ -16337,7 -16285,6 +16337,7 @@@ F:   drivers/pci/controller/dwc/pci-exyno
  PCI DRIVER FOR SYNOPSYS DESIGNWARE
  M:    Jingoo Han <[email protected]>
  M:    Gustavo Pimentel <[email protected]>
 +M:    Manivannan Sadhasivam <[email protected]>
  L:    [email protected]
  S:    Maintained
  F:    Documentation/devicetree/bindings/pci/snps,dw-pcie-ep.yaml
@@@ -17090,7 -17037,6 +17090,7 @@@ F:   drivers/net/ppp/pptp.
  PRESSURE STALL INFORMATION (PSI)
  M:    Johannes Weiner <[email protected]>
  M:    Suren Baghdasaryan <[email protected]>
 +R:    Peter Ziljstra <[email protected]>
  S:    Maintained
  F:    include/linux/psi*
  F:    kernel/sched/psi.c
@@@ -17490,7 -17436,6 +17490,7 @@@ F:   drivers/media/tuners/qt1010
  
  QUALCOMM ATH12K WIRELESS DRIVER
  M:    Kalle Valo <[email protected]>
 +M:    Jeff Johnson <[email protected]>
  L:    [email protected]
  S:    Supported
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
@@@ -17498,7 -17443,6 +17498,7 @@@ F:   drivers/net/wireless/ath/ath12k
  
  QUALCOMM ATHEROS ATH10K WIRELESS DRIVER
  M:    Kalle Valo <[email protected]>
 +M:    Jeff Johnson <[email protected]>
  L:    [email protected]
  S:    Supported
  W:    https://wireless.wiki.kernel.org/en/users/Drivers/ath10k
@@@ -17508,7 -17452,6 +17508,7 @@@ F:   drivers/net/wireless/ath/ath10k
  
  QUALCOMM ATHEROS ATH11K WIRELESS DRIVER
  M:    Kalle Valo <[email protected]>
 +M:    Jeff Johnson <[email protected]>
  L:    [email protected]
  S:    Supported
  W:    https://wireless.wiki.kernel.org/en/users/Drivers/ath11k
@@@ -17600,7 -17543,6 +17600,7 @@@ QUALCOMM ETHQOS ETHERNET DRIVE
  M:    Vinod Koul <[email protected]>
  R:    Bhupesh Sharma <[email protected]>
  L:    [email protected]
 +L:    [email protected]
  S:    Maintained
  F:    Documentation/devicetree/bindings/net/qcom,ethqos.yaml
  F:    drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
@@@ -18029,7 -17971,7 +18029,7 @@@ T:   git git://git.kernel.org/pub/scm/lin
  F:    drivers/net/wireless/realtek/rtlwifi/
  
  REALTEK WIRELESS DRIVER (rtw88)
 -M:    Yan-Hsuan Chuang <tony0620emma@gmail.com>
 +M:    Ping-Ke Shih <pkshih@realtek.com>
  L:    [email protected]
  S:    Maintained
  F:    drivers/net/wireless/realtek/rtw88/
@@@ -18554,14 -18496,17 +18554,14 @@@ RTL8180 WIRELESS DRIVE
  L:    [email protected]
  S:    Orphan
  W:    https://wireless.wiki.kernel.org/
 -T:    git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
  F:    drivers/net/wireless/realtek/rtl818x/rtl8180/
  
  RTL8187 WIRELESS DRIVER
 -M:    Herton Ronaldo Krzesinski <[email protected]>
 -M:    Hin-Tak Leung <[email protected]>
 +M:    Hin-Tak Leung <[email protected]>
  M:    Larry Finger <[email protected]>
  L:    [email protected]
  S:    Maintained
  W:    https://wireless.wiki.kernel.org/
 -T:    git git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-testing.git
  F:    drivers/net/wireless/realtek/rtl818x/rtl8187/
  
  RTL8XXXU WIRELESS DRIVER (rtl8xxxu)
@@@ -18597,8 -18542,6 +18597,8 @@@ R:   Boqun Feng <[email protected]
  R:    Gary Guo <[email protected]>
  R:    Björn Roy Baron <[email protected]>
  R:    Benno Lossin <[email protected]>
 +R:    Andreas Hindborg <[email protected]>
 +R:    Alice Ryhl <[email protected]>
  L:    [email protected]
  S:    Supported
  W:    https://github.com/Rust-for-Linux/linux
  S:    Supported
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux.git
  F:    Documentation/driver-api/s390-drivers.rst
 -F:    Documentation/s390/
 +F:    Documentation/arch/s390/
  F:    arch/s390/
  F:    drivers/s390/
  F:    drivers/watchdog/diag288_wdt.c
@@@ -18701,7 -18644,7 +18701,7 @@@ M:   Niklas Schnelle <[email protected].
  M:    Gerald Schaefer <[email protected]>
  L:    [email protected]
  S:    Supported
 -F:    Documentation/s390/pci.rst
 +F:    Documentation/arch/s390/pci.rst
  F:    arch/s390/pci/
  F:    drivers/pci/hotplug/s390_pci_hpc.c
  
@@@ -18718,7 -18661,7 +18718,7 @@@ M:   Halil Pasic <[email protected]
  M:    Jason Herne <[email protected]>
  L:    [email protected]
  S:    Supported
 -F:    Documentation/s390/vfio-ap*
 +F:    Documentation/arch/s390/vfio-ap*
  F:    drivers/s390/crypto/vfio_ap*
  
  S390 VFIO-CCW DRIVER
@@@ -18728,7 -18671,7 +18728,7 @@@ R:   Halil Pasic <[email protected]
  L:    [email protected]
  L:    [email protected]
  S:    Supported
 -F:    Documentation/s390/vfio-ccw.rst
 +F:    Documentation/arch/s390/vfio-ccw.rst
  F:    drivers/s390/cio/vfio_ccw*
  F:    include/uapi/linux/vfio_ccw.h
  
@@@ -19270,6 -19213,13 +19270,6 @@@ F:  Documentation/devicetree/bindings/se
  F:    drivers/tty/serdev/
  F:    include/linux/serdev.h
  
 -SERIAL DRIVERS
 -M:    Greg Kroah-Hartman <[email protected]>
 -L:    [email protected]
 -S:    Maintained
 -F:    Documentation/devicetree/bindings/serial/
 -F:    drivers/tty/serial/
 -
  SERIAL IR RECEIVER
  M:    Sean Young <[email protected]>
  L:    [email protected]
@@@ -19321,6 -19271,7 +19321,6 @@@ F:   drivers/misc/sgi-gru
  SGI XP/XPC/XPNET DRIVER
  M:    Robin Holt <[email protected]>
  M:    Steve Wahl <[email protected]>
 -R:    Mike Travis <[email protected]>
  S:    Maintained
  F:    drivers/misc/sgi-xp/
  
@@@ -19631,6 -19582,13 +19631,6 @@@ M:  Nicolas Pitre <[email protected]
  S:    Odd Fixes
  F:    drivers/net/ethernet/smsc/smc91x.*
  
 -SMM665 HARDWARE MONITOR DRIVER
 -M:    Guenter Roeck <[email protected]>
 -L:    [email protected]
 -S:    Maintained
 -F:    Documentation/hwmon/smm665.rst
 -F:    drivers/hwmon/smm665.c
 -
  SMSC EMC2103 HARDWARE MONITOR DRIVER
  M:    Steve Glendinning <[email protected]>
  L:    [email protected]
@@@ -20432,6 -20390,7 +20432,6 @@@ F:   drivers/pwm/pwm-stm32
  F:    include/linux/*/stm32-*tim*
  
  STMMAC ETHERNET DRIVER
 -M:    Giuseppe Cavallaro <[email protected]>
  M:    Alexandre Torgue <[email protected]>
  M:    Jose Abreu <[email protected]>
  L:    [email protected]
@@@ -21090,39 -21049,6 +21090,39 @@@ S: Maintaine
  F:    Documentation/devicetree/bindings/sound/davinci-mcasp-audio.yaml
  F:    sound/soc/ti/
  
 +TEXAS INSTRUMENTS AUDIO (ASoC/HDA) DRIVERS
 +M:    Shenghao Ding <[email protected]>
 +M:    Kevin Lu <[email protected]>
 +M:    Baojun Xu <[email protected]>
 +L:    [email protected] (moderated for non-subscribers)
 +S:    Maintained
 +F:    Documentation/devicetree/bindings/sound/tas2552.txt
 +F:    Documentation/devicetree/bindings/sound/tas2562.yaml
 +F:    Documentation/devicetree/bindings/sound/tas2770.yaml
 +F:    Documentation/devicetree/bindings/sound/tas27xx.yaml
 +F:    Documentation/devicetree/bindings/sound/ti,pcm1681.txt
 +F:    Documentation/devicetree/bindings/sound/ti,pcm3168a.yaml
 +F:    Documentation/devicetree/bindings/sound/ti,tlv320*.yaml
 +F:    Documentation/devicetree/bindings/sound/tlv320adcx140.yaml
 +F:    Documentation/devicetree/bindings/sound/tlv320aic31xx.txt
 +F:    Documentation/devicetree/bindings/sound/tpa6130a2.txt
 +F:    include/sound/tas2*.h
 +F:    include/sound/tlv320*.h
 +F:    include/sound/tpa6130a2-plat.h
 +F:    sound/pci/hda/tas2781_hda_i2c.c
 +F:    sound/soc/codecs/pcm1681.c
 +F:    sound/soc/codecs/pcm1789*.*
 +F:    sound/soc/codecs/pcm179x*.*
 +F:    sound/soc/codecs/pcm186x*.*
 +F:    sound/soc/codecs/pcm3008.*
 +F:    sound/soc/codecs/pcm3060*.*
 +F:    sound/soc/codecs/pcm3168a*.*
 +F:    sound/soc/codecs/pcm5102a.c
 +F:    sound/soc/codecs/pcm512x*.*
 +F:    sound/soc/codecs/tas2*.*
 +F:    sound/soc/codecs/tlv320*.*
 +F:    sound/soc/codecs/tpa6130a2.*
 +
  TEXAS INSTRUMENTS DMA DRIVERS
  M:    Peter Ujfalusi <[email protected]>
  L:    [email protected]
@@@ -21699,16 -21625,14 +21699,16 @@@ W:        https://github.com/srcres258/linux-d
  T:    git git://github.com/srcres258/linux-doc.git doc-zh-tw
  F:    Documentation/translations/zh_TW/
  
 -TTY LAYER
 +TTY LAYER AND SERIAL DRIVERS
  M:    Greg Kroah-Hartman <[email protected]>
  M:    Jiri Slaby <[email protected]>
 +L:    [email protected]
 +L:    [email protected]
  S:    Supported
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git
 +F:    Documentation/devicetree/bindings/serial/
  F:    Documentation/driver-api/serial/
  F:    drivers/tty/
 -F:    drivers/tty/serial/serial_core.c
  F:    include/linux/selection.h
  F:    include/linux/serial.h
  F:    include/linux/serial_core.h
@@@ -21737,14 -21661,11 +21737,14 @@@ S:        Orpha
  F:    drivers/net/ethernet/dec/tulip/
  
  TUN/TAP driver
 -M:    Maxim Krasnyansky <[email protected]>
 +M:    Willem de Bruijn <[email protected]>
 +M:    Jason Wang <[email protected]>
  S:    Maintained
  W:    http://vtun.sourceforge.net/tun
  F:    Documentation/networking/tuntap.rst
  F:    arch/um/os-Linux/drivers/
 +F:    drivers/net/tap.c
 +F:    drivers/net/tun.c
  
  TURBOCHANNEL SUBSYSTEM
  M:    "Maciej W. Rozycki" <[email protected]>
@@@ -21967,8 -21888,9 +21967,8 @@@ S:   Maintaine
  F:    drivers/usb/misc/apple-mfi-fastcharge.c
  
  USB AR5523 WIRELESS DRIVER
 -M:    Pontus Fuchs <[email protected]>
  L:    [email protected]
 -S:    Maintained
 +S:    Orphan
  F:    drivers/net/wireless/ath/ar5523/
  
  USB ATTACHED SCSI
@@@ -22245,8 -22167,9 +22245,8 @@@ F:   drivers/usb/gadget/legacy/webcam.
  F:    include/uapi/linux/usb/g_uvc.h
  
  USB WIRELESS RNDIS DRIVER (rndis_wlan)
 -M:    Jussi Kivilinna <[email protected]>
  L:    [email protected]
 -S:    Maintained
 +S:    Orphan
  F:    drivers/net/wireless/legacy/rndis_wlan.c
  
  USB XHCI DRIVER
  S:    Maintained
  F:    drivers/block/virtio_blk.c
  F:    drivers/scsi/virtio_scsi.c
 -F:    drivers/vhost/scsi.c
  F:    include/uapi/linux/virtio_blk.h
  F:    include/uapi/linux/virtio_scsi.h
  
@@@ -22633,16 -22557,6 +22633,16 @@@ F: include/linux/vhost_iotlb.
  F:    include/uapi/linux/vhost.h
  F:    kernel/vhost_task.c
  
 +VIRTIO HOST (VHOST-SCSI)
 +M:    "Michael S. Tsirkin" <[email protected]>
 +M:    Jason Wang <[email protected]>
 +M:    Mike Christie <[email protected]>
 +R:    Paolo Bonzini <[email protected]>
 +R:    Stefan Hajnoczi <[email protected]>
 +L:    [email protected]
 +S:    Maintained
 +F:    drivers/vhost/scsi.c
 +
  VIRTIO I2C DRIVER
  M:    Conghui Chen <[email protected]>
  M:    Viresh Kumar <[email protected]>
@@@ -23030,7 -22944,7 +23030,7 @@@ F:   drivers/input/misc/wistron_btns.
  
  WL3501 WIRELESS PCMCIA CARD DRIVER
  L:    [email protected]
 -S:    Odd fixes
 +S:    Orphan
  F:    drivers/net/wireless/legacy/wl3501*
  
  WMI BINARY MOF DRIVER
@@@ -23210,8 -23124,7 +23210,8 @@@ F:   arch/x86/platfor
  
  X86 PLATFORM UV HPE SUPERDOME FLEX
  M:    Steve Wahl <[email protected]>
 -R:    Mike Travis <[email protected]>
 +R:    Justin Ernst <[email protected]>
 +R:    Kyle Meyer <[email protected]>
  R:    Dimitri Sivanich <[email protected]>
  R:    Russ Anderson <[email protected]>
  S:    Supported
@@@ -23602,8 -23515,11 +23602,8 @@@ S:  Maintaine
  F:    mm/zbud.c
  
  ZD1211RW WIRELESS DRIVER
 -M:    Ulrich Kunitz <[email protected]>
  L:    [email protected]
 -L:    [email protected] (subscribers-only)
 -S:    Maintained
 -W:    http://zd1211.ath.cx/wiki/DriverRewrite
 +S:    Orphan
  F:    drivers/net/wireless/zydas/zd1211rw/
  
  ZD1301 MEDIA DRIVER
diff --combined drivers/gpio/gpio-sim.c
index 533d815725794a18cdde25ebabdd6fb4fba13332,141249f2bf40146cc5368a739706380df660fa55..271db3639a78209e00d45d558d6354bb0161e27f
@@@ -8,6 -8,7 +8,7 @@@
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  
  #include <linux/bitmap.h>
+ #include <linux/cleanup.h>
  #include <linux/completion.h>
  #include <linux/configfs.h>
  #include <linux/device.h>
@@@ -68,7 -69,7 +69,7 @@@ static int gpio_sim_apply_pull(struct g
        gc = &chip->gc;
        desc = &gc->gpiodev->descs[offset];
  
-       mutex_lock(&chip->lock);
+       guard(mutex)(&chip->lock);
  
        if (test_bit(FLAG_REQUESTED, &desc->flags) &&
            !test_bit(FLAG_IS_OUT, &desc->flags)) {
@@@ -104,29 -105,24 +105,24 @@@ set_value
  
  set_pull:
        __assign_bit(offset, chip->pull_map, value);
-       mutex_unlock(&chip->lock);
        return 0;
  }
  
  static int gpio_sim_get(struct gpio_chip *gc, unsigned int offset)
  {
        struct gpio_sim_chip *chip = gpiochip_get_data(gc);
-       int ret;
  
-       mutex_lock(&chip->lock);
-       ret = !!test_bit(offset, chip->value_map);
-       mutex_unlock(&chip->lock);
+       guard(mutex)(&chip->lock);
  
-       return ret;
+       return !!test_bit(offset, chip->value_map);
  }
  
  static void gpio_sim_set(struct gpio_chip *gc, unsigned int offset, int value)
  {
        struct gpio_sim_chip *chip = gpiochip_get_data(gc);
  
-       mutex_lock(&chip->lock);
-       __assign_bit(offset, chip->value_map, value);
-       mutex_unlock(&chip->lock);
+       scoped_guard(mutex, &chip->lock)
+               __assign_bit(offset, chip->value_map, value);
  }
  
  static int gpio_sim_get_multiple(struct gpio_chip *gc,
  {
        struct gpio_sim_chip *chip = gpiochip_get_data(gc);
  
-       mutex_lock(&chip->lock);
-       bitmap_replace(bits, bits, chip->value_map, mask, gc->ngpio);
-       mutex_unlock(&chip->lock);
+       scoped_guard(mutex, &chip->lock)
+               bitmap_replace(bits, bits, chip->value_map, mask, gc->ngpio);
  
        return 0;
  }
@@@ -146,9 -141,9 +141,9 @@@ static void gpio_sim_set_multiple(struc
  {
        struct gpio_sim_chip *chip = gpiochip_get_data(gc);
  
-       mutex_lock(&chip->lock);
-       bitmap_replace(chip->value_map, chip->value_map, bits, mask, gc->ngpio);
-       mutex_unlock(&chip->lock);
+       scoped_guard(mutex, &chip->lock)
+               bitmap_replace(chip->value_map, chip->value_map, bits, mask,
+                              gc->ngpio);
  }
  
  static int gpio_sim_direction_output(struct gpio_chip *gc,
  {
        struct gpio_sim_chip *chip = gpiochip_get_data(gc);
  
-       mutex_lock(&chip->lock);
-       __clear_bit(offset, chip->direction_map);
-       __assign_bit(offset, chip->value_map, value);
-       mutex_unlock(&chip->lock);
+       scoped_guard(mutex, &chip->lock) {
+               __clear_bit(offset, chip->direction_map);
+               __assign_bit(offset, chip->value_map, value);
+       }
  
        return 0;
  }
@@@ -168,9 -163,8 +163,8 @@@ static int gpio_sim_direction_input(str
  {
        struct gpio_sim_chip *chip = gpiochip_get_data(gc);
  
-       mutex_lock(&chip->lock);
-       __set_bit(offset, chip->direction_map);
-       mutex_unlock(&chip->lock);
+       scoped_guard(mutex, &chip->lock)
+               __set_bit(offset, chip->direction_map);
  
        return 0;
  }
@@@ -180,9 -174,8 +174,8 @@@ static int gpio_sim_get_direction(struc
        struct gpio_sim_chip *chip = gpiochip_get_data(gc);
        int direction;
  
-       mutex_lock(&chip->lock);
-       direction = !!test_bit(offset, chip->direction_map);
-       mutex_unlock(&chip->lock);
+       scoped_guard(mutex, &chip->lock)
+               direction = !!test_bit(offset, chip->direction_map);
  
        return direction ? GPIO_LINE_DIRECTION_IN : GPIO_LINE_DIRECTION_OUT;
  }
@@@ -215,9 -208,9 +208,9 @@@ static void gpio_sim_free(struct gpio_c
  {
        struct gpio_sim_chip *chip = gpiochip_get_data(gc);
  
-       mutex_lock(&chip->lock);
-       __assign_bit(offset, chip->value_map, !!test_bit(offset, chip->pull_map));
-       mutex_unlock(&chip->lock);
+       scoped_guard(mutex, &chip->lock)
+               __assign_bit(offset, chip->value_map,
+                            !!test_bit(offset, chip->pull_map));
  }
  
  static ssize_t gpio_sim_sysfs_val_show(struct device *dev,
        struct gpio_sim_chip *chip = dev_get_drvdata(dev);
        int val;
  
-       mutex_lock(&chip->lock);
-       val = !!test_bit(line_attr->offset, chip->value_map);
-       mutex_unlock(&chip->lock);
+       scoped_guard(mutex, &chip->lock)
+               val = !!test_bit(line_attr->offset, chip->value_map);
  
        return sysfs_emit(buf, "%d\n", val);
  }
@@@ -258,9 -250,8 +250,8 @@@ static ssize_t gpio_sim_sysfs_pull_show
        struct gpio_sim_chip *chip = dev_get_drvdata(dev);
        int pull;
  
-       mutex_lock(&chip->lock);
-       pull = !!test_bit(line_attr->offset, chip->pull_map);
-       mutex_unlock(&chip->lock);
+       scoped_guard(mutex, &chip->lock)
+               pull = !!test_bit(line_attr->offset, chip->pull_map);
  
        return sysfs_emit(buf, "%s\n", gpio_sim_sysfs_pull_strings[pull]);
  }
@@@ -291,15 -282,6 +282,15 @@@ static void gpio_sim_mutex_destroy(voi
        mutex_destroy(lock);
  }
  
 +static void gpio_sim_dispose_mappings(void *data)
 +{
 +      struct gpio_sim_chip *chip = data;
 +      unsigned int i;
 +
 +      for (i = 0; i < chip->gc.ngpio; i++)
 +              irq_dispose_mapping(irq_find_mapping(chip->irq_sim, i));
 +}
 +
  static void gpio_sim_sysfs_remove(void *data)
  {
        struct gpio_sim_chip *chip = data;
@@@ -411,14 -393,10 +402,14 @@@ static int gpio_sim_add_bank(struct fwn
        if (!chip->pull_map)
                return -ENOMEM;
  
 -      chip->irq_sim = devm_irq_domain_create_sim(dev, NULL, num_lines);
 +      chip->irq_sim = devm_irq_domain_create_sim(dev, swnode, num_lines);
        if (IS_ERR(chip->irq_sim))
                return PTR_ERR(chip->irq_sim);
  
 +      ret = devm_add_action_or_reset(dev, gpio_sim_dispose_mappings, chip);
 +      if (ret)
 +              return ret;
 +
        mutex_init(&chip->lock);
        ret = devm_add_action_or_reset(dev, gpio_sim_mutex_destroy,
                                       &chip->lock);
        gc->set_config = gpio_sim_set_config;
        gc->to_irq = gpio_sim_to_irq;
        gc->free = gpio_sim_free;
 +      gc->can_sleep = true;
  
        ret = devm_gpiochip_add_data(dev, gc, chip);
        if (ret)
@@@ -502,7 -479,7 +493,7 @@@ struct gpio_sim_device 
         * This structure however can be modified by callbacks of different
         * attributes so we need another lock.
         *
-        * We use this lock fo protecting all data structures owned by this
+        * We use this lock for protecting all data structures owned by this
         * object too.
         */
        struct mutex lock;
@@@ -656,16 -633,13 +647,13 @@@ static bool gpio_sim_device_is_live_unl
  
  static char *gpio_sim_strdup_trimmed(const char *str, size_t count)
  {
-       char *dup, *trimmed;
+       char *trimmed;
  
-       dup = kstrndup(str, count, GFP_KERNEL);
-       if (!dup)
+       trimmed = kstrndup(skip_spaces(str), count, GFP_KERNEL);
+       if (!trimmed)
                return NULL;
  
-       trimmed = strstrip(dup);
-       memmove(dup, trimmed, strlen(trimmed) + 1);
-       return dup;
+       return strim(trimmed);
  }
  
  static ssize_t gpio_sim_device_config_dev_name_show(struct config_item *item,
  {
        struct gpio_sim_device *dev = to_gpio_sim_device(item);
        struct platform_device *pdev;
-       int ret;
  
-       mutex_lock(&dev->lock);
+       guard(mutex)(&dev->lock);
        pdev = dev->pdev;
        if (pdev)
-               ret = sprintf(page, "%s\n", dev_name(&pdev->dev));
-       else
-               ret = sprintf(page, "gpio-sim.%d\n", dev->id);
-       mutex_unlock(&dev->lock);
+               return sprintf(page, "%s\n", dev_name(&pdev->dev));
  
-       return ret;
+       return sprintf(page, "gpio-sim.%d\n", dev->id);
  }
  
  CONFIGFS_ATTR_RO(gpio_sim_device_config_, dev_name);
@@@ -694,9 -665,8 +679,8 @@@ gpio_sim_device_config_live_show(struc
        struct gpio_sim_device *dev = to_gpio_sim_device(item);
        bool live;
  
-       mutex_lock(&dev->lock);
-       live = gpio_sim_device_is_live_unlocked(dev);
-       mutex_unlock(&dev->lock);
+       scoped_guard(mutex, &dev->lock)
+               live = gpio_sim_device_is_live_unlocked(dev);
  
        return sprintf(page, "%c\n", live ? '1' : '0');
  }
@@@ -851,8 -821,7 +835,7 @@@ gpio_sim_make_bank_swnode(struct gpio_s
  {
        struct property_entry properties[GPIO_SIM_PROP_MAX];
        unsigned int prop_idx = 0, line_names_size = 0;
-       struct fwnode_handle *swnode;
-       char **line_names;
+       char **line_names __free(kfree) = NULL;
  
        memset(properties, 0, sizeof(properties));
  
                                                "gpio-line-names",
                                                line_names, line_names_size);
  
-       swnode = fwnode_create_software_node(properties, parent);
-       kfree(line_names);
-       return swnode;
+       return fwnode_create_software_node(properties, parent);
  }
  
  static void gpio_sim_remove_swnode_recursive(struct fwnode_handle *swnode)
@@@ -998,18 -965,15 +979,15 @@@ gpio_sim_device_config_live_store(struc
        if (ret)
                return ret;
  
-       mutex_lock(&dev->lock);
+       guard(mutex)(&dev->lock);
  
-       if ((!live && !gpio_sim_device_is_live_unlocked(dev)) ||
-           (live && gpio_sim_device_is_live_unlocked(dev)))
+       if (live == gpio_sim_device_is_live_unlocked(dev))
                ret = -EPERM;
        else if (live)
                ret = gpio_sim_device_activate_unlocked(dev);
        else
                gpio_sim_device_deactivate_unlocked(dev);
  
-       mutex_unlock(&dev->lock);
        return ret ?: count;
  }
  
@@@ -1046,17 -1010,14 +1024,14 @@@ static ssize_t gpio_sim_bank_config_chi
        struct gpio_sim_bank *bank = to_gpio_sim_bank(item);
        struct gpio_sim_device *dev = gpio_sim_bank_get_device(bank);
        struct gpio_sim_chip_name_ctx ctx = { bank->swnode, page };
-       int ret;
  
-       mutex_lock(&dev->lock);
+       guard(mutex)(&dev->lock);
        if (gpio_sim_device_is_live_unlocked(dev))
-               ret = device_for_each_child(&dev->pdev->dev, &ctx,
-                                           gpio_sim_emit_chip_name);
-       else
-               ret = sprintf(page, "none\n");
-       mutex_unlock(&dev->lock);
+               return device_for_each_child(&dev->pdev->dev, &ctx,
+                                            gpio_sim_emit_chip_name);
  
-       return ret;
+       return sprintf(page, "none\n");
  }
  
  CONFIGFS_ATTR_RO(gpio_sim_bank_config_, chip_name);
@@@ -1066,13 -1027,10 +1041,10 @@@ gpio_sim_bank_config_label_show(struct 
  {
        struct gpio_sim_bank *bank = to_gpio_sim_bank(item);
        struct gpio_sim_device *dev = gpio_sim_bank_get_device(bank);
-       int ret;
  
-       mutex_lock(&dev->lock);
-       ret = sprintf(page, "%s\n", bank->label ?: "");
-       mutex_unlock(&dev->lock);
+       guard(mutex)(&dev->lock);
  
-       return ret;
+       return sprintf(page, "%s\n", bank->label ?: "");
  }
  
  static ssize_t gpio_sim_bank_config_label_store(struct config_item *item,
        struct gpio_sim_device *dev = gpio_sim_bank_get_device(bank);
        char *trimmed;
  
-       mutex_lock(&dev->lock);
+       guard(mutex)(&dev->lock);
  
-       if (gpio_sim_device_is_live_unlocked(dev)) {
-               mutex_unlock(&dev->lock);
+       if (gpio_sim_device_is_live_unlocked(dev))
                return -EBUSY;
-       }
  
        trimmed = gpio_sim_strdup_trimmed(page, count);
-       if (!trimmed) {
-               mutex_unlock(&dev->lock);
+       if (!trimmed)
                return -ENOMEM;
-       }
  
        kfree(bank->label);
        bank->label = trimmed;
  
-       mutex_unlock(&dev->lock);
        return count;
  }
  
@@@ -1109,13 -1062,10 +1076,10 @@@ gpio_sim_bank_config_num_lines_show(str
  {
        struct gpio_sim_bank *bank = to_gpio_sim_bank(item);
        struct gpio_sim_device *dev = gpio_sim_bank_get_device(bank);
-       int ret;
  
-       mutex_lock(&dev->lock);
-       ret = sprintf(page, "%u\n", bank->num_lines);
-       mutex_unlock(&dev->lock);
+       guard(mutex)(&dev->lock);
  
-       return ret;
+       return sprintf(page, "%u\n", bank->num_lines);
  }
  
  static ssize_t
@@@ -1134,16 -1084,13 +1098,13 @@@ gpio_sim_bank_config_num_lines_store(st
        if (num_lines == 0)
                return -EINVAL;
  
-       mutex_lock(&dev->lock);
+       guard(mutex)(&dev->lock);
  
-       if (gpio_sim_device_is_live_unlocked(dev)) {
-               mutex_unlock(&dev->lock);
+       if (gpio_sim_device_is_live_unlocked(dev))
                return -EBUSY;
-       }
  
        bank->num_lines = num_lines;
  
-       mutex_unlock(&dev->lock);
        return count;
  }
  
@@@ -1161,13 -1108,10 +1122,10 @@@ gpio_sim_line_config_name_show(struct c
  {
        struct gpio_sim_line *line = to_gpio_sim_line(item);
        struct gpio_sim_device *dev = gpio_sim_line_get_device(line);
-       int ret;
  
-       mutex_lock(&dev->lock);
-       ret = sprintf(page, "%s\n", line->name ?: "");
-       mutex_unlock(&dev->lock);
+       guard(mutex)(&dev->lock);
  
-       return ret;
+       return sprintf(page, "%s\n", line->name ?: "");
  }
  
  static ssize_t gpio_sim_line_config_name_store(struct config_item *item,
        struct gpio_sim_device *dev = gpio_sim_line_get_device(line);
        char *trimmed;
  
-       mutex_lock(&dev->lock);
+       guard(mutex)(&dev->lock);
  
-       if (gpio_sim_device_is_live_unlocked(dev)) {
-               mutex_unlock(&dev->lock);
+       if (gpio_sim_device_is_live_unlocked(dev))
                return -EBUSY;
-       }
  
        trimmed = gpio_sim_strdup_trimmed(page, count);
-       if (!trimmed) {
-               mutex_unlock(&dev->lock);
+       if (!trimmed)
                return -ENOMEM;
-       }
  
        kfree(line->name);
        line->name = trimmed;
  
-       mutex_unlock(&dev->lock);
        return count;
  }
  
@@@ -1210,13 -1148,10 +1162,10 @@@ static ssize_t gpio_sim_hog_config_name
  {
        struct gpio_sim_hog *hog = to_gpio_sim_hog(item);
        struct gpio_sim_device *dev = gpio_sim_hog_get_device(hog);
-       int ret;
  
-       mutex_lock(&dev->lock);
-       ret = sprintf(page, "%s\n", hog->name ?: "");
-       mutex_unlock(&dev->lock);
+       guard(mutex)(&dev->lock);
  
-       return ret;
+       return sprintf(page, "%s\n", hog->name ?: "");
  }
  
  static ssize_t gpio_sim_hog_config_name_store(struct config_item *item,
        struct gpio_sim_device *dev = gpio_sim_hog_get_device(hog);
        char *trimmed;
  
-       mutex_lock(&dev->lock);
+       guard(mutex)(&dev->lock);
  
-       if (gpio_sim_device_is_live_unlocked(dev)) {
-               mutex_unlock(&dev->lock);
+       if (gpio_sim_device_is_live_unlocked(dev))
                return -EBUSY;
-       }
  
        trimmed = gpio_sim_strdup_trimmed(page, count);
-       if (!trimmed) {
-               mutex_unlock(&dev->lock);
+       if (!trimmed)
                return -ENOMEM;
-       }
  
        kfree(hog->name);
        hog->name = trimmed;
  
-       mutex_unlock(&dev->lock);
        return count;
  }
  
@@@ -1257,9 -1186,8 +1200,8 @@@ static ssize_t gpio_sim_hog_config_dire
        char *repr;
        int dir;
  
-       mutex_lock(&dev->lock);
-       dir = hog->dir;
-       mutex_unlock(&dev->lock);
+       scoped_guard(mutex, &dev->lock)
+               dir = hog->dir;
  
        switch (dir) {
        case GPIOD_IN:
@@@ -1286,42 -1214,24 +1228,24 @@@ gpio_sim_hog_config_direction_store(str
  {
        struct gpio_sim_hog *hog = to_gpio_sim_hog(item);
        struct gpio_sim_device *dev = gpio_sim_hog_get_device(hog);
-       char *trimmed;
        int dir;
  
-       mutex_lock(&dev->lock);
+       guard(mutex)(&dev->lock);
  
-       if (gpio_sim_device_is_live_unlocked(dev)) {
-               mutex_unlock(&dev->lock);
+       if (gpio_sim_device_is_live_unlocked(dev))
                return -EBUSY;
-       }
  
-       trimmed = gpio_sim_strdup_trimmed(page, count);
-       if (!trimmed) {
-               mutex_unlock(&dev->lock);
-               return -ENOMEM;
-       }
-       if (strcmp(trimmed, "input") == 0)
+       if (sysfs_streq(page, "input"))
                dir = GPIOD_IN;
-       else if (strcmp(trimmed, "output-high") == 0)
+       else if (sysfs_streq(page, "output-high"))
                dir = GPIOD_OUT_HIGH;
-       else if (strcmp(trimmed, "output-low") == 0)
+       else if (sysfs_streq(page, "output-low"))
                dir = GPIOD_OUT_LOW;
        else
-               dir = -EINVAL;
-       kfree(trimmed);
-       if (dir < 0) {
-               mutex_unlock(&dev->lock);
-               return dir;
-       }
+               return -EINVAL;
  
        hog->dir = dir;
  
-       mutex_unlock(&dev->lock);
        return count;
  }
  
@@@ -1339,9 -1249,8 +1263,8 @@@ static void gpio_sim_hog_config_item_re
        struct gpio_sim_line *line = hog->parent;
        struct gpio_sim_device *dev = gpio_sim_hog_get_device(hog);
  
-       mutex_lock(&dev->lock);
-       line->hog = NULL;
-       mutex_unlock(&dev->lock);
+       scoped_guard(mutex, &dev->lock)
+               line->hog = NULL;
  
        kfree(hog->name);
        kfree(hog);
@@@ -1367,13 -1276,11 +1290,11 @@@ gpio_sim_line_config_make_hog_item(stru
        if (strcmp(name, "hog") != 0)
                return ERR_PTR(-EINVAL);
  
-       mutex_lock(&dev->lock);
+       guard(mutex)(&dev->lock);
  
        hog = kzalloc(sizeof(*hog), GFP_KERNEL);
-       if (!hog) {
-               mutex_unlock(&dev->lock);
+       if (!hog)
                return ERR_PTR(-ENOMEM);
-       }
  
        config_item_init_type_name(&hog->item, name,
                                   &gpio_sim_hog_config_type);
        hog->parent = line;
        line->hog = hog;
  
-       mutex_unlock(&dev->lock);
        return &hog->item;
  }
  
@@@ -1393,9 -1298,8 +1312,8 @@@ static void gpio_sim_line_config_group_
        struct gpio_sim_line *line = to_gpio_sim_line(item);
        struct gpio_sim_device *dev = gpio_sim_line_get_device(line);
  
-       mutex_lock(&dev->lock);
-       list_del(&line->siblings);
-       mutex_unlock(&dev->lock);
+       scoped_guard(mutex, &dev->lock)
+               list_del(&line->siblings);
  
        kfree(line->name);
        kfree(line);
@@@ -1430,18 -1334,14 +1348,14 @@@ gpio_sim_bank_config_make_line_group(st
        if (ret != 1 || nchar != strlen(name))
                return ERR_PTR(-EINVAL);
  
-       mutex_lock(&dev->lock);
+       guard(mutex)(&dev->lock);
  
-       if (gpio_sim_device_is_live_unlocked(dev)) {
-               mutex_unlock(&dev->lock);
+       if (gpio_sim_device_is_live_unlocked(dev))
                return ERR_PTR(-EBUSY);
-       }
  
        line = kzalloc(sizeof(*line), GFP_KERNEL);
-       if (!line) {
-               mutex_unlock(&dev->lock);
+       if (!line)
                return ERR_PTR(-ENOMEM);
-       }
  
        config_group_init_type_name(&line->group, name,
                                    &gpio_sim_line_config_type);
        line->offset = offset;
        list_add_tail(&line->siblings, &bank->line_list);
  
-       mutex_unlock(&dev->lock);
        return &line->group;
  }
  
@@@ -1460,9 -1358,8 +1372,8 @@@ static void gpio_sim_bank_config_group_
        struct gpio_sim_bank *bank = to_gpio_sim_bank(item);
        struct gpio_sim_device *dev = gpio_sim_bank_get_device(bank);
  
-       mutex_lock(&dev->lock);
-       list_del(&bank->siblings);
-       mutex_unlock(&dev->lock);
+       scoped_guard(mutex, &dev->lock)
+               list_del(&bank->siblings);
  
        kfree(bank->label);
        kfree(bank);
@@@ -1490,18 -1387,14 +1401,14 @@@ gpio_sim_device_config_make_bank_group(
        struct gpio_sim_device *dev = to_gpio_sim_device(&group->cg_item);
        struct gpio_sim_bank *bank;
  
-       mutex_lock(&dev->lock);
+       guard(mutex)(&dev->lock);
  
-       if (gpio_sim_device_is_live_unlocked(dev)) {
-               mutex_unlock(&dev->lock);
+       if (gpio_sim_device_is_live_unlocked(dev))
                return ERR_PTR(-EBUSY);
-       }
  
        bank = kzalloc(sizeof(*bank), GFP_KERNEL);
-       if (!bank) {
-               mutex_unlock(&dev->lock);
+       if (!bank)
                return ERR_PTR(-ENOMEM);
-       }
  
        config_group_init_type_name(&bank->group, name,
                                    &gpio_sim_bank_config_group_type);
        INIT_LIST_HEAD(&bank->line_list);
        list_add_tail(&bank->siblings, &dev->bank_list);
  
-       mutex_unlock(&dev->lock);
        return &bank->group;
  }
  
@@@ -1519,10 -1410,10 +1424,10 @@@ static void gpio_sim_device_config_grou
  {
        struct gpio_sim_device *dev = to_gpio_sim_device(item);
  
-       mutex_lock(&dev->lock);
-       if (gpio_sim_device_is_live_unlocked(dev))
-               gpio_sim_device_deactivate_unlocked(dev);
-       mutex_unlock(&dev->lock);
+       scoped_guard(mutex, &dev->lock) {
+               if (gpio_sim_device_is_live_unlocked(dev))
+                       gpio_sim_device_deactivate_unlocked(dev);
+       }
  
        mutex_destroy(&dev->lock);
        ida_free(&gpio_sim_ida, dev->id);
@@@ -1547,7 -1438,7 +1452,7 @@@ static const struct config_item_type gp
  static struct config_group *
  gpio_sim_config_make_device_group(struct config_group *group, const char *name)
  {
-       struct gpio_sim_device *dev;
+       struct gpio_sim_device *dev __free(kfree) = NULL;
        int id;
  
        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
                return ERR_PTR(-ENOMEM);
  
        id = ida_alloc(&gpio_sim_ida, GFP_KERNEL);
-       if (id < 0) {
-               kfree(dev);
+       if (id < 0)
                return ERR_PTR(id);
-       }
  
        config_group_init_type_name(&dev->group, name,
                                    &gpio_sim_device_config_group_type);
        dev->bus_notifier.notifier_call = gpio_sim_bus_notifier_call;
        init_completion(&dev->probe_completion);
  
-       return &dev->group;
+       return &no_free_ptr(dev)->group;
  }
  
  static struct configfs_group_operations gpio_sim_config_group_ops = {
index afb42a8e916fe11e9e0cb50e60d7d35c783386e6,701847508e94b691f3ba238d5791ce19261f750e..6289b0510cf2b261a0e00f1d536d0b7ff82ea798
@@@ -3,22 -3,21 +3,21 @@@
   * GPIO driver for the WinSystems WS16C48
   * Copyright (C) 2016 William Breathitt Gray
   */
- #include <linux/bitmap.h>
+ #include <linux/bitfield.h>
+ #include <linux/bits.h>
  #include <linux/device.h>
- #include <linux/errno.h>
- #include <linux/gpio/driver.h>
- #include <linux/io.h>
- #include <linux/ioport.h>
- #include <linux/interrupt.h>
- #include <linux/irqdesc.h>
+ #include <linux/err.h>
+ #include <linux/gpio/regmap.h>
+ #include <linux/irq.h>
  #include <linux/isa.h>
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/moduleparam.h>
  #include <linux/spinlock.h>
+ #include <linux/regmap.h>
  #include <linux/types.h>
  
 -#define WS16C48_EXTENT 10
 +#define WS16C48_EXTENT 11
  #define MAX_NUM_WS16C48 max_num_isa_dev(WS16C48_EXTENT)
  
  static unsigned int base[MAX_NUM_WS16C48];
@@@ -31,371 -30,178 +30,178 @@@ static unsigned int num_irq
  module_param_hw_array(irq, uint, irq, &num_irq, 0);
  MODULE_PARM_DESC(irq, "WinSystems WS16C48 interrupt line numbers");
  
- /**
-  * struct ws16c48_reg - device register structure
-  * @port:             Port 0 through 5 I/O
-  * @int_pending:      Interrupt Pending
-  * @page_lock:                Register page (Bits 7-6) and I/O port lock (Bits 5-0)
-  * @pol_enab_int_id:  Interrupt polarity, enable, and ID
-  */
- struct ws16c48_reg {
-       u8 port[6];
-       u8 int_pending;
-       u8 page_lock;
-       u8 pol_enab_int_id[3];
+ #define WS16C48_DAT_BASE 0x0
+ #define WS16C48_PAGE_LOCK 0x7
+ #define WS16C48_PAGE_BASE 0x8
+ #define WS16C48_POL WS16C48_PAGE_BASE
+ #define WS16C48_ENAB WS16C48_PAGE_BASE
+ #define WS16C48_INT_ID WS16C48_PAGE_BASE
+ #define PAGE_LOCK_PAGE_FIELD GENMASK(7, 6)
+ #define POL_PAGE u8_encode_bits(1, PAGE_LOCK_PAGE_FIELD)
+ #define ENAB_PAGE u8_encode_bits(2, PAGE_LOCK_PAGE_FIELD)
+ #define INT_ID_PAGE u8_encode_bits(3, PAGE_LOCK_PAGE_FIELD)
+ static const struct regmap_range ws16c48_wr_ranges[] = {
+       regmap_reg_range(0x0, 0x5), regmap_reg_range(0x7, 0xA),
+ };
+ static const struct regmap_range ws16c48_rd_ranges[] = {
+       regmap_reg_range(0x0, 0xA),
+ };
+ static const struct regmap_range ws16c48_volatile_ranges[] = {
+       regmap_reg_range(0x0, 0x6), regmap_reg_range(0x8, 0xA),
+ };
+ static const struct regmap_access_table ws16c48_wr_table = {
+       .yes_ranges = ws16c48_wr_ranges,
+       .n_yes_ranges = ARRAY_SIZE(ws16c48_wr_ranges),
+ };
+ static const struct regmap_access_table ws16c48_rd_table = {
+       .yes_ranges = ws16c48_rd_ranges,
+       .n_yes_ranges = ARRAY_SIZE(ws16c48_rd_ranges),
+ };
+ static const struct regmap_access_table ws16c48_volatile_table = {
+       .yes_ranges = ws16c48_volatile_ranges,
+       .n_yes_ranges = ARRAY_SIZE(ws16c48_volatile_ranges),
+ };
+ static const struct regmap_config ws16c48_regmap_config = {
+       .reg_bits = 8,
+       .reg_stride = 1,
+       .val_bits = 8,
+       .io_port = true,
+       .wr_table = &ws16c48_wr_table,
+       .rd_table = &ws16c48_rd_table,
+       .volatile_table = &ws16c48_volatile_table,
+       .cache_type = REGCACHE_FLAT,
+       .use_raw_spinlock = true,
+ };
+ #define WS16C48_NGPIO_PER_REG 8
+ #define WS16C48_REGMAP_IRQ(_id)                                                       \
+       [_id] = {                                                               \
+               .reg_offset = (_id) / WS16C48_NGPIO_PER_REG,                    \
+               .mask = BIT((_id) % WS16C48_NGPIO_PER_REG),                     \
+               .type = {                                                       \
+                       .type_reg_offset = (_id) / WS16C48_NGPIO_PER_REG,       \
+                       .types_supported = IRQ_TYPE_EDGE_BOTH,                  \
+               },                                                              \
+       }
+ /* Only the first 24 lines (Port 0-2) support interrupts */
+ #define WS16C48_NUM_IRQS 24
+ static const struct regmap_irq ws16c48_regmap_irqs[WS16C48_NUM_IRQS] = {
+       WS16C48_REGMAP_IRQ(0), WS16C48_REGMAP_IRQ(1), WS16C48_REGMAP_IRQ(2), /* 0-2 */
+       WS16C48_REGMAP_IRQ(3), WS16C48_REGMAP_IRQ(4), WS16C48_REGMAP_IRQ(5), /* 3-5 */
+       WS16C48_REGMAP_IRQ(6), WS16C48_REGMAP_IRQ(7), WS16C48_REGMAP_IRQ(8), /* 6-8 */
+       WS16C48_REGMAP_IRQ(9), WS16C48_REGMAP_IRQ(10), WS16C48_REGMAP_IRQ(11), /* 9-11 */
+       WS16C48_REGMAP_IRQ(12), WS16C48_REGMAP_IRQ(13), WS16C48_REGMAP_IRQ(14), /* 12-14 */
+       WS16C48_REGMAP_IRQ(15), WS16C48_REGMAP_IRQ(16), WS16C48_REGMAP_IRQ(17), /* 15-17 */
+       WS16C48_REGMAP_IRQ(18), WS16C48_REGMAP_IRQ(19), WS16C48_REGMAP_IRQ(20), /* 18-20 */
+       WS16C48_REGMAP_IRQ(21), WS16C48_REGMAP_IRQ(22), WS16C48_REGMAP_IRQ(23), /* 21-23 */
  };
  
  /**
   * struct ws16c48_gpio - GPIO device private data structure
-  * @chip:     instance of the gpio_chip
-  * @io_state: bit I/O state (whether bit is set to input or output)
-  * @out_state:        output bits state
+  * @map:      regmap for the device
   * @lock:     synchronization lock to prevent I/O race conditions
   * @irq_mask: I/O bits affected by interrupts
-  * @flow_mask:        IRQ flow type mask for the respective I/O bits
-  * @reg:      I/O address offset for the device registers
   */
  struct ws16c48_gpio {
-       struct gpio_chip chip;
-       unsigned char io_state[6];
-       unsigned char out_state[6];
+       struct regmap *map;
        raw_spinlock_t lock;
-       unsigned long irq_mask;
-       unsigned long flow_mask;
-       struct ws16c48_reg __iomem *reg;
+       u8 irq_mask[WS16C48_NUM_IRQS / WS16C48_NGPIO_PER_REG];
  };
  
- static int ws16c48_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
+ static int ws16c48_handle_pre_irq(void *const irq_drv_data) __acquires(&ws16c48gpio->lock)
  {
-       struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
-       const unsigned port = offset / 8;
-       const unsigned mask = BIT(offset % 8);
+       struct ws16c48_gpio *const ws16c48gpio = irq_drv_data;
  
-       if (ws16c48gpio->io_state[port] & mask)
-               return GPIO_LINE_DIRECTION_IN;
-       return GPIO_LINE_DIRECTION_OUT;
- }
- static int ws16c48_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
- {
-       struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
-       const unsigned port = offset / 8;
-       const unsigned mask = BIT(offset % 8);
-       unsigned long flags;
-       raw_spin_lock_irqsave(&ws16c48gpio->lock, flags);
-       ws16c48gpio->io_state[port] |= mask;
-       ws16c48gpio->out_state[port] &= ~mask;
-       iowrite8(ws16c48gpio->out_state[port], ws16c48gpio->reg->port + port);
-       raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
+       /* Lock to prevent Page/Lock register change while we handle IRQ */
+       raw_spin_lock(&ws16c48gpio->lock);
  
        return 0;
  }
  
- static int ws16c48_gpio_direction_output(struct gpio_chip *chip,
-       unsigned offset, int value)
+ static int ws16c48_handle_post_irq(void *const irq_drv_data) __releases(&ws16c48gpio->lock)
  {
-       struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
-       const unsigned port = offset / 8;
-       const unsigned mask = BIT(offset % 8);
-       unsigned long flags;
-       raw_spin_lock_irqsave(&ws16c48gpio->lock, flags);
+       struct ws16c48_gpio *const ws16c48gpio = irq_drv_data;
  
-       ws16c48gpio->io_state[port] &= ~mask;
-       if (value)
-               ws16c48gpio->out_state[port] |= mask;
-       else
-               ws16c48gpio->out_state[port] &= ~mask;
-       iowrite8(ws16c48gpio->out_state[port], ws16c48gpio->reg->port + port);
-       raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
+       raw_spin_unlock(&ws16c48gpio->lock);
  
        return 0;
  }
  
- static int ws16c48_gpio_get(struct gpio_chip *chip, unsigned offset)
- {
-       struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
-       const unsigned port = offset / 8;
-       const unsigned mask = BIT(offset % 8);
-       unsigned long flags;
-       unsigned port_state;
-       raw_spin_lock_irqsave(&ws16c48gpio->lock, flags);
-       /* ensure that GPIO is set for input */
-       if (!(ws16c48gpio->io_state[port] & mask)) {
-               raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
-               return -EINVAL;
-       }
-       port_state = ioread8(ws16c48gpio->reg->port + port);
-       raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
-       return !!(port_state & mask);
- }
- static int ws16c48_gpio_get_multiple(struct gpio_chip *chip,
-       unsigned long *mask, unsigned long *bits)
- {
-       struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
-       unsigned long offset;
-       unsigned long gpio_mask;
-       size_t index;
-       u8 __iomem *port_addr;
-       unsigned long port_state;
-       /* clear bits array to a clean slate */
-       bitmap_zero(bits, chip->ngpio);
-       for_each_set_clump8(offset, gpio_mask, mask, chip->ngpio) {
-               index = offset / 8;
-               port_addr = ws16c48gpio->reg->port + index;
-               port_state = ioread8(port_addr) & gpio_mask;
-               bitmap_set_value8(bits, port_state, offset);
-       }
-       return 0;
- }
- static void ws16c48_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
- {
-       struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
-       const unsigned port = offset / 8;
-       const unsigned mask = BIT(offset % 8);
-       unsigned long flags;
-       raw_spin_lock_irqsave(&ws16c48gpio->lock, flags);
-       /* ensure that GPIO is set for output */
-       if (ws16c48gpio->io_state[port] & mask) {
-               raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
-               return;
-       }
-       if (value)
-               ws16c48gpio->out_state[port] |= mask;
-       else
-               ws16c48gpio->out_state[port] &= ~mask;
-       iowrite8(ws16c48gpio->out_state[port], ws16c48gpio->reg->port + port);
-       raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
- }
- static void ws16c48_gpio_set_multiple(struct gpio_chip *chip,
-       unsigned long *mask, unsigned long *bits)
- {
-       struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
-       unsigned long offset;
-       unsigned long gpio_mask;
-       size_t index;
-       u8 __iomem *port_addr;
-       unsigned long bitmask;
-       unsigned long flags;
-       for_each_set_clump8(offset, gpio_mask, mask, chip->ngpio) {
-               index = offset / 8;
-               port_addr = ws16c48gpio->reg->port + index;
-               /* mask out GPIO configured for input */
-               gpio_mask &= ~ws16c48gpio->io_state[index];
-               bitmask = bitmap_get_value8(bits, offset) & gpio_mask;
-               raw_spin_lock_irqsave(&ws16c48gpio->lock, flags);
-               /* update output state data and set device gpio register */
-               ws16c48gpio->out_state[index] &= ~gpio_mask;
-               ws16c48gpio->out_state[index] |= bitmask;
-               iowrite8(ws16c48gpio->out_state[index], port_addr);
-               raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
-       }
- }
- static void ws16c48_irq_ack(struct irq_data *data)
+ static int ws16c48_handle_mask_sync(const int index, const unsigned int mask_buf_def,
+                                   const unsigned int mask_buf, void *const irq_drv_data)
  {
-       struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
-       struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
-       const unsigned long offset = irqd_to_hwirq(data);
-       const unsigned port = offset / 8;
-       const unsigned mask = BIT(offset % 8);
+       struct ws16c48_gpio *const ws16c48gpio = irq_drv_data;
        unsigned long flags;
-       unsigned port_state;
-       /* only the first 3 ports support interrupts */
-       if (port > 2)
-               return;
+       int ret = 0;
  
        raw_spin_lock_irqsave(&ws16c48gpio->lock, flags);
  
-       port_state = ws16c48gpio->irq_mask >> (8*port);
+       /* exit early if no change since the last mask sync */
+       if (mask_buf == ws16c48gpio->irq_mask[index])
+               goto exit_unlock;
+       ws16c48gpio->irq_mask[index] = mask_buf;
  
-       /* Select Register Page 2; Unlock all I/O ports */
-       iowrite8(0x80, &ws16c48gpio->reg->page_lock);
+       ret = regmap_write(ws16c48gpio->map, WS16C48_PAGE_LOCK, ENAB_PAGE);
+       if (ret)
+               goto exit_unlock;
  
-       /* Clear pending interrupt */
-       iowrite8(port_state & ~mask, ws16c48gpio->reg->pol_enab_int_id + port);
-       iowrite8(port_state | mask, ws16c48gpio->reg->pol_enab_int_id + port);
+       /* Update ENAB register (inverted mask) */
+       ret = regmap_write(ws16c48gpio->map, WS16C48_ENAB + index, ~mask_buf);
+       if (ret)
+               goto exit_unlock;
  
-       /* Select Register Page 3; Unlock all I/O ports */
-       iowrite8(0xC0, &ws16c48gpio->reg->page_lock);
+       ret = regmap_write(ws16c48gpio->map, WS16C48_PAGE_LOCK, INT_ID_PAGE);
+       if (ret)
+               goto exit_unlock;
  
+ exit_unlock:
        raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
- }
- static void ws16c48_irq_mask(struct irq_data *data)
- {
-       struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
-       struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
-       const unsigned long offset = irqd_to_hwirq(data);
-       const unsigned long mask = BIT(offset);
-       const unsigned port = offset / 8;
-       unsigned long flags;
-       unsigned long port_state;
-       /* only the first 3 ports support interrupts */
-       if (port > 2)
-               return;
-       raw_spin_lock_irqsave(&ws16c48gpio->lock, flags);
  
-       ws16c48gpio->irq_mask &= ~mask;
-       gpiochip_disable_irq(chip, offset);
-       port_state = ws16c48gpio->irq_mask >> (8 * port);
-       /* Select Register Page 2; Unlock all I/O ports */
-       iowrite8(0x80, &ws16c48gpio->reg->page_lock);
-       /* Disable interrupt */
-       iowrite8(port_state, ws16c48gpio->reg->pol_enab_int_id + port);
-       /* Select Register Page 3; Unlock all I/O ports */
-       iowrite8(0xC0, &ws16c48gpio->reg->page_lock);
-       raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
+       return ret;
  }
  
- static void ws16c48_irq_unmask(struct irq_data *data)
+ static int ws16c48_set_type_config(unsigned int **const buf, const unsigned int type,
+                                  const struct regmap_irq *const irq_data, const int idx,
+                                  void *const irq_drv_data)
  {
-       struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
-       struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
-       const unsigned long offset = irqd_to_hwirq(data);
-       const unsigned long mask = BIT(offset);
-       const unsigned port = offset / 8;
+       struct ws16c48_gpio *const ws16c48gpio = irq_drv_data;
+       unsigned int polarity;
        unsigned long flags;
-       unsigned long port_state;
-       /* only the first 3 ports support interrupts */
-       if (port > 2)
-               return;
-       raw_spin_lock_irqsave(&ws16c48gpio->lock, flags);
-       gpiochip_enable_irq(chip, offset);
-       ws16c48gpio->irq_mask |= mask;
-       port_state = ws16c48gpio->irq_mask >> (8 * port);
-       /* Select Register Page 2; Unlock all I/O ports */
-       iowrite8(0x80, &ws16c48gpio->reg->page_lock);
-       /* Enable interrupt */
-       iowrite8(port_state, ws16c48gpio->reg->pol_enab_int_id + port);
-       /* Select Register Page 3; Unlock all I/O ports */
-       iowrite8(0xC0, &ws16c48gpio->reg->page_lock);
-       raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
- }
+       int ret;
  
- static int ws16c48_irq_set_type(struct irq_data *data, unsigned flow_type)
- {
-       struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
-       struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
-       const unsigned long offset = irqd_to_hwirq(data);
-       const unsigned long mask = BIT(offset);
-       const unsigned port = offset / 8;
-       unsigned long flags;
-       unsigned long port_state;
-       /* only the first 3 ports support interrupts */
-       if (port > 2)
-               return -EINVAL;
-       raw_spin_lock_irqsave(&ws16c48gpio->lock, flags);
-       switch (flow_type) {
-       case IRQ_TYPE_NONE:
-               break;
+       switch (type) {
        case IRQ_TYPE_EDGE_RISING:
-               ws16c48gpio->flow_mask |= mask;
+               polarity = irq_data->mask;
                break;
        case IRQ_TYPE_EDGE_FALLING:
-               ws16c48gpio->flow_mask &= ~mask;
+               polarity = 0;
                break;
        default:
-               raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
                return -EINVAL;
        }
  
-       port_state = ws16c48gpio->flow_mask >> (8 * port);
+       raw_spin_lock_irqsave(&ws16c48gpio->lock, flags);
  
-       /* Select Register Page 1; Unlock all I/O ports */
-       iowrite8(0x40, &ws16c48gpio->reg->page_lock);
+       ret = regmap_write(ws16c48gpio->map, WS16C48_PAGE_LOCK, POL_PAGE);
+       if (ret)
+               goto exit_unlock;
  
        /* Set interrupt polarity */
-       iowrite8(port_state, ws16c48gpio->reg->pol_enab_int_id + port);
+       ret = regmap_update_bits(ws16c48gpio->map, WS16C48_POL + idx, irq_data->mask, polarity);
+       if (ret)
+               goto exit_unlock;
  
-       /* Select Register Page 3; Unlock all I/O ports */
-       iowrite8(0xC0, &ws16c48gpio->reg->page_lock);
+       ret = regmap_write(ws16c48gpio->map, WS16C48_PAGE_LOCK, INT_ID_PAGE);
+       if (ret)
+               goto exit_unlock;
  
+ exit_unlock:
        raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags);
  
-       return 0;
- }
- static const struct irq_chip ws16c48_irqchip = {
-       .name = "ws16c48",
-       .irq_ack = ws16c48_irq_ack,
-       .irq_mask = ws16c48_irq_mask,
-       .irq_unmask = ws16c48_irq_unmask,
-       .irq_set_type = ws16c48_irq_set_type,
-       .flags = IRQCHIP_IMMUTABLE,
-       GPIOCHIP_IRQ_RESOURCE_HELPERS,
- };
- static irqreturn_t ws16c48_irq_handler(int irq, void *dev_id)
- {
-       struct ws16c48_gpio *const ws16c48gpio = dev_id;
-       struct gpio_chip *const chip = &ws16c48gpio->chip;
-       struct ws16c48_reg __iomem *const reg = ws16c48gpio->reg;
-       unsigned long int_pending;
-       unsigned long port;
-       unsigned long int_id;
-       unsigned long gpio;
-       int_pending = ioread8(&reg->int_pending) & 0x7;
-       if (!int_pending)
-               return IRQ_NONE;
-       /* loop until all pending interrupts are handled */
-       do {
-               for_each_set_bit(port, &int_pending, 3) {
-                       int_id = ioread8(reg->pol_enab_int_id + port);
-                       for_each_set_bit(gpio, &int_id, 8)
-                               generic_handle_domain_irq(chip->irq.domain,
-                                                         gpio + 8*port);
-               }
-               int_pending = ioread8(&reg->int_pending) & 0x7;
-       } while (int_pending);
-       return IRQ_HANDLED;
+       return ret;
  }
  
  #define WS16C48_NGPIO 48
@@@ -414,30 -220,37 +220,37 @@@ static const char *ws16c48_names[WS16C4
        "Port 5 Bit 4", "Port 5 Bit 5", "Port 5 Bit 6", "Port 5 Bit 7"
  };
  
- static int ws16c48_irq_init_hw(struct gpio_chip *gc)
+ static int ws16c48_irq_init_hw(struct regmap *const map)
  {
-       struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(gc);
+       int err;
  
-       /* Select Register Page 2; Unlock all I/O ports */
-       iowrite8(0x80, &ws16c48gpio->reg->page_lock);
+       err = regmap_write(map, WS16C48_PAGE_LOCK, ENAB_PAGE);
+       if (err)
+               return err;
  
        /* Disable interrupts for all lines */
-       iowrite8(0, &ws16c48gpio->reg->pol_enab_int_id[0]);
-       iowrite8(0, &ws16c48gpio->reg->pol_enab_int_id[1]);
-       iowrite8(0, &ws16c48gpio->reg->pol_enab_int_id[2]);
-       /* Select Register Page 3; Unlock all I/O ports */
-       iowrite8(0xC0, &ws16c48gpio->reg->page_lock);
+       err = regmap_write(map, WS16C48_ENAB + 0, 0x00);
+       if (err)
+               return err;
+       err = regmap_write(map, WS16C48_ENAB + 1, 0x00);
+       if (err)
+               return err;
+       err = regmap_write(map, WS16C48_ENAB + 2, 0x00);
+       if (err)
+               return err;
  
-       return 0;
+       return regmap_write(map, WS16C48_PAGE_LOCK, INT_ID_PAGE);
  }
  
  static int ws16c48_probe(struct device *dev, unsigned int id)
  {
        struct ws16c48_gpio *ws16c48gpio;
        const char *const name = dev_name(dev);
-       struct gpio_irq_chip *girq;
        int err;
+       struct gpio_regmap_config gpio_config = {};
+       void __iomem *regs;
+       struct regmap_irq_chip *chip;
+       struct regmap_irq_chip_data *chip_data;
  
        ws16c48gpio = devm_kzalloc(dev, sizeof(*ws16c48gpio), GFP_KERNEL);
        if (!ws16c48gpio)
                return -EBUSY;
        }
  
-       ws16c48gpio->reg = devm_ioport_map(dev, base[id], WS16C48_EXTENT);
-       if (!ws16c48gpio->reg)
+       regs = devm_ioport_map(dev, base[id], WS16C48_EXTENT);
+       if (!regs)
                return -ENOMEM;
  
-       ws16c48gpio->chip.label = name;
-       ws16c48gpio->chip.parent = dev;
-       ws16c48gpio->chip.owner = THIS_MODULE;
-       ws16c48gpio->chip.base = -1;
-       ws16c48gpio->chip.ngpio = WS16C48_NGPIO;
-       ws16c48gpio->chip.names = ws16c48_names;
-       ws16c48gpio->chip.get_direction = ws16c48_gpio_get_direction;
-       ws16c48gpio->chip.direction_input = ws16c48_gpio_direction_input;
-       ws16c48gpio->chip.direction_output = ws16c48_gpio_direction_output;
-       ws16c48gpio->chip.get = ws16c48_gpio_get;
-       ws16c48gpio->chip.get_multiple = ws16c48_gpio_get_multiple;
-       ws16c48gpio->chip.set = ws16c48_gpio_set;
-       ws16c48gpio->chip.set_multiple = ws16c48_gpio_set_multiple;
-       girq = &ws16c48gpio->chip.irq;
-       gpio_irq_chip_set_chip(girq, &ws16c48_irqchip);
-       /* This will let us handle the parent IRQ in the driver */
-       girq->parent_handler = NULL;
-       girq->num_parents = 0;
-       girq->parents = NULL;
-       girq->default_type = IRQ_TYPE_NONE;
-       girq->handler = handle_edge_irq;
-       girq->init_hw = ws16c48_irq_init_hw;
+       ws16c48gpio->map = devm_regmap_init_mmio(dev, regs, &ws16c48_regmap_config);
+       if (IS_ERR(ws16c48gpio->map))
+               return dev_err_probe(dev, PTR_ERR(ws16c48gpio->map),
+                                    "Unable to initialize register map\n");
  
-       raw_spin_lock_init(&ws16c48gpio->lock);
+       chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
+       if (!chip)
+               return -ENOMEM;
  
-       err = devm_gpiochip_add_data(dev, &ws16c48gpio->chip, ws16c48gpio);
-       if (err) {
-               dev_err(dev, "GPIO registering failed (%d)\n", err);
-               return err;
-       }
+       chip->name = name;
+       chip->status_base = WS16C48_INT_ID;
+       chip->mask_base = WS16C48_ENAB;
+       chip->ack_base = WS16C48_INT_ID;
+       chip->num_regs = 3;
+       chip->irqs = ws16c48_regmap_irqs;
+       chip->num_irqs = ARRAY_SIZE(ws16c48_regmap_irqs);
+       chip->handle_pre_irq = ws16c48_handle_pre_irq;
+       chip->handle_post_irq = ws16c48_handle_post_irq;
+       chip->handle_mask_sync = ws16c48_handle_mask_sync;
+       chip->set_type_config = ws16c48_set_type_config;
+       chip->irq_drv_data = ws16c48gpio;
  
-       err = devm_request_irq(dev, irq[id], ws16c48_irq_handler, IRQF_SHARED,
-               name, ws16c48gpio);
-       if (err) {
-               dev_err(dev, "IRQ handler registering failed (%d)\n", err);
+       raw_spin_lock_init(&ws16c48gpio->lock);
+       /* Initialize to prevent spurious interrupts before we're ready */
+       err = ws16c48_irq_init_hw(ws16c48gpio->map);
+       if (err)
                return err;
-       }
  
-       return 0;
+       err = devm_regmap_add_irq_chip(dev, ws16c48gpio->map, irq[id], 0, 0, chip, &chip_data);
+       if (err)
+               return dev_err_probe(dev, err, "IRQ registration failed\n");
+       gpio_config.parent = dev;
+       gpio_config.regmap = ws16c48gpio->map;
+       gpio_config.ngpio = WS16C48_NGPIO;
+       gpio_config.names = ws16c48_names;
+       gpio_config.reg_dat_base = GPIO_REGMAP_ADDR(WS16C48_DAT_BASE);
+       gpio_config.reg_set_base = GPIO_REGMAP_ADDR(WS16C48_DAT_BASE);
+       /* Setting a GPIO to 0 allows it to be used as an input */
+       gpio_config.reg_dir_out_base = GPIO_REGMAP_ADDR(WS16C48_DAT_BASE);
+       gpio_config.ngpio_per_reg = WS16C48_NGPIO_PER_REG;
+       gpio_config.irq_domain = regmap_irq_get_domain(chip_data);
+       return PTR_ERR_OR_ZERO(devm_gpio_regmap_register(dev, &gpio_config));
  }
  
  static struct isa_driver ws16c48_driver = {
index 9694eb5afa21668cfe913e95e42200e5387bdc8a,5fde5a3f51182ab0b7caa7a1b997c584039f52b1..531faabead0f40feb60e583f33b7e0bbfa70e0e3
@@@ -209,8 -209,6 +209,8 @@@ static void of_gpio_set_polarity_by_pro
                                             const char *propname,
                                             enum of_gpio_flags *flags)
  {
 +      const struct device_node *np_compat = np;
 +      const struct device_node *np_propname = np;
        static const struct {
                const char *compatible;
                const char *gpio_propname;
  #if IS_ENABLED(CONFIG_REGULATOR_GPIO)
                { "regulator-gpio",    "enable-gpio",  "enable-active-high" },
                { "regulator-gpio",    "enable-gpios", "enable-active-high" },
 +#endif
 +#if IS_ENABLED(CONFIG_MMC_ATMELMCI)
 +              { "atmel,hsmci",       "cd-gpios",     "cd-inverted" },
  #endif
        };
        unsigned int i;
        bool active_high;
  
 +#if IS_ENABLED(CONFIG_MMC_ATMELMCI)
 +      /*
 +       * The Atmel HSMCI has compatible property in the parent node and
 +       * gpio property in a child node
 +       */
 +      if (of_device_is_compatible(np->parent, "atmel,hsmci")) {
 +              np_compat = np->parent;
 +              np_propname = np;
 +      }
 +#endif
 +
        for (i = 0; i < ARRAY_SIZE(gpios); i++) {
 -              if (of_device_is_compatible(np, gpios[i].compatible) &&
 +              if (of_device_is_compatible(np_compat, gpios[i].compatible) &&
                    !strcmp(propname, gpios[i].gpio_propname)) {
 -                      active_high = of_property_read_bool(np,
 +                      active_high = of_property_read_bool(np_propname,
                                                gpios[i].polarity_propname);
                        of_gpio_quirk_polarity(np, active_high, flags);
                        break;
@@@ -1094,16 -1078,16 +1094,16 @@@ int of_gpiochip_add(struct gpio_chip *c
        if (ret)
                return ret;
  
-       fwnode_handle_get(chip->fwnode);
+       of_node_get(np);
  
        ret = of_gpiochip_scan_gpios(chip);
        if (ret)
-               fwnode_handle_put(chip->fwnode);
+               of_node_put(np);
  
        return ret;
  }
  
  void of_gpiochip_remove(struct gpio_chip *chip)
  {
-       fwnode_handle_put(chip->fwnode);
+       of_node_put(dev_of_node(&chip->gpiodev->dev));
  }
diff --combined drivers/gpio/gpiolib.c
index 76e0c38026c3e94b87566a35eb98b6bc40fb2061,810bc09467a95ed3919fd0d916d868cece520384..40a0022ea719097da383cd9c0589edd3b7dd821b
@@@ -700,6 -700,40 +700,40 @@@ void *gpiochip_get_data(struct gpio_chi
  }
  EXPORT_SYMBOL_GPL(gpiochip_get_data);
  
+ int gpiochip_get_ngpios(struct gpio_chip *gc, struct device *dev)
+ {
+       u32 ngpios = gc->ngpio;
+       int ret;
+       if (ngpios == 0) {
+               ret = device_property_read_u32(dev, "ngpios", &ngpios);
+               if (ret == -ENODATA)
+                       /*
+                        * -ENODATA means that there is no property found and
+                        * we want to issue the error message to the user.
+                        * Besides that, we want to return different error code
+                        * to state that supplied value is not valid.
+                        */
+                       ngpios = 0;
+               else if (ret)
+                       return ret;
+               gc->ngpio = ngpios;
+       }
+       if (gc->ngpio == 0) {
+               chip_err(gc, "tried to insert a GPIO chip with zero lines\n");
+               return -EINVAL;
+       }
+       if (gc->ngpio > FASTPATH_NGPIO)
+               chip_warn(gc, "line cnt %u is greater than fast path cnt %u\n",
+                       gc->ngpio, FASTPATH_NGPIO);
+       return 0;
+ }
+ EXPORT_SYMBOL_GPL(gpiochip_get_ngpios);
  int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
                               struct lock_class_key *lock_key,
                               struct lock_class_key *request_key)
        struct gpio_device *gdev;
        unsigned long flags;
        unsigned int i;
-       u32 ngpios = 0;
        int base = 0;
        int ret = 0;
  
-       /*
-        * If the calling driver did not initialize firmware node, do it here
-        * using the parent device, if any.
-        */
-       if (!gc->fwnode && gc->parent)
-               gc->fwnode = dev_fwnode(gc->parent);
        /*
         * First: allocate and populate the internal stat container, and
         * set up the struct device.
        gc->gpiodev = gdev;
        gpiochip_set_data(gc, data);
  
-       device_set_node(&gdev->dev, gc->fwnode);
+       /*
+        * If the calling driver did not initialize firmware node,
+        * do it here using the parent device, if any.
+        */
+       if (gc->fwnode)
+               device_set_node(&gdev->dev, gc->fwnode);
+       else if (gc->parent)
+               device_set_node(&gdev->dev, dev_fwnode(gc->parent));
  
        gdev->id = ida_alloc(&gpio_ida, GFP_KERNEL);
        if (gdev->id < 0) {
        else
                gdev->owner = THIS_MODULE;
  
-       /*
-        * Try the device properties if the driver didn't supply the number
-        * of GPIO lines.
-        */
-       ngpios = gc->ngpio;
-       if (ngpios == 0) {
-               ret = device_property_read_u32(&gdev->dev, "ngpios", &ngpios);
-               if (ret == -ENODATA)
-                       /*
-                        * -ENODATA means that there is no property found and
-                        * we want to issue the error message to the user.
-                        * Besides that, we want to return different error code
-                        * to state that supplied value is not valid.
-                        */
-                       ngpios = 0;
-               else if (ret)
-                       goto err_free_dev_name;
-               gc->ngpio = ngpios;
-       }
-       if (gc->ngpio == 0) {
-               chip_err(gc, "tried to insert a GPIO chip with zero lines\n");
-               ret = -EINVAL;
+       ret = gpiochip_get_ngpios(gc, &gdev->dev);
+       if (ret)
                goto err_free_dev_name;
-       }
-       if (gc->ngpio > FASTPATH_NGPIO)
-               chip_warn(gc, "line cnt %u is greater than fast path cnt %u\n",
-                         gc->ngpio, FASTPATH_NGPIO);
  
        gdev->descs = kcalloc(gc->ngpio, sizeof(*gdev->descs), GFP_KERNEL);
        if (!gdev->descs) {
  
        spin_unlock_irqrestore(&gpio_lock, flags);
  
-       BLOCKING_INIT_NOTIFIER_HEAD(&gdev->notifier);
+       BLOCKING_INIT_NOTIFIER_HEAD(&gdev->line_state_notifier);
+       BLOCKING_INIT_NOTIFIER_HEAD(&gdev->device_notifier);
        init_rwsem(&gdev->sem);
  
  #ifdef CONFIG_PINCTRL
@@@ -947,7 -954,7 +954,7 @@@ err_print_message
        /* failures here can mean systems won't boot... */
        if (ret != -EPROBE_DEFER) {
                pr_err("%s: GPIOs %d..%d (%s) failed to register, %d\n", __func__,
-                      base, base + (int)ngpios - 1,
+                      base, base + (int)gc->ngpio - 1,
                       gc->label ? : "generic", ret);
        }
        return ret;
@@@ -1292,12 -1299,14 +1299,14 @@@ static void gpiochip_hierarchy_setup_do
                ops->free = irq_domain_free_irqs_common;
  }
  
- static int gpiochip_hierarchy_add_domain(struct gpio_chip *gc)
+ static struct irq_domain *gpiochip_hierarchy_create_domain(struct gpio_chip *gc)
  {
+       struct irq_domain *domain;
        if (!gc->irq.child_to_parent_hwirq ||
            !gc->irq.fwnode) {
                chip_err(gc, "missing irqdomain vital data\n");
-               return -EINVAL;
+               return ERR_PTR(-EINVAL);
        }
  
        if (!gc->irq.child_offset_to_irq)
  
        gpiochip_hierarchy_setup_domain_ops(&gc->irq.child_irq_domain_ops);
  
-       gc->irq.domain = irq_domain_create_hierarchy(
+       domain = irq_domain_create_hierarchy(
                gc->irq.parent_domain,
                0,
                gc->ngpio,
                &gc->irq.child_irq_domain_ops,
                gc);
  
-       if (!gc->irq.domain)
-               return -ENOMEM;
+       if (!domain)
+               return ERR_PTR(-ENOMEM);
  
        gpiochip_set_hierarchical_irqchip(gc, gc->irq.chip);
  
-       return 0;
+       return domain;
  }
  
  static bool gpiochip_hierarchy_is_hierarchical(struct gpio_chip *gc)
@@@ -1366,9 -1375,9 +1375,9 @@@ EXPORT_SYMBOL_GPL(gpiochip_populate_par
  
  #else
  
- static int gpiochip_hierarchy_add_domain(struct gpio_chip *gc)
+ static struct irq_domain *gpiochip_hierarchy_create_domain(struct gpio_chip *gc)
  {
-       return -EINVAL;
+       return ERR_PTR(-EINVAL);
  }
  
  static bool gpiochip_hierarchy_is_hierarchical(struct gpio_chip *gc)
@@@ -1445,6 -1454,19 +1454,19 @@@ static const struct irq_domain_ops gpio
        .xlate  = irq_domain_xlate_twocell,
  };
  
+ static struct irq_domain *gpiochip_simple_create_domain(struct gpio_chip *gc)
+ {
+       struct fwnode_handle *fwnode = dev_fwnode(&gc->gpiodev->dev);
+       struct irq_domain *domain;
+       domain = irq_domain_create_simple(fwnode, gc->ngpio, gc->irq.first,
+                                         &gpiochip_domain_ops, gc);
+       if (!domain)
+               return ERR_PTR(-EINVAL);
+       return domain;
+ }
  /*
   * TODO: move these activate/deactivate in under the hierarchicial
   * irqchip implementation as static once SPMI and SSBI (all external
@@@ -1623,6 -1645,31 +1645,31 @@@ static void gpiochip_set_irq_hooks(stru
        }
  }
  
+ static int gpiochip_irqchip_add_allocated_domain(struct gpio_chip *gc,
+                                                struct irq_domain *domain,
+                                                bool allocated_externally)
+ {
+       if (!domain)
+               return -EINVAL;
+       if (gc->to_irq)
+               chip_warn(gc, "to_irq is redefined in %s and you shouldn't rely on it\n", __func__);
+       gc->to_irq = gpiochip_to_irq;
+       gc->irq.domain = domain;
+       gc->irq.domain_is_allocated_externally = allocated_externally;
+       /*
+        * Using barrier() here to prevent compiler from reordering
+        * gc->irq.initialized before adding irqdomain.
+        */
+       barrier();
+       gc->irq.initialized = true;
+       return 0;
+ }
  /**
   * gpiochip_add_irqchip() - adds an IRQ chip to a GPIO chip
   * @gc: the GPIO chip to add the IRQ chip to
@@@ -1635,8 -1682,10 +1682,10 @@@ static int gpiochip_add_irqchip(struct 
  {
        struct fwnode_handle *fwnode = dev_fwnode(&gc->gpiodev->dev);
        struct irq_chip *irqchip = gc->irq.chip;
+       struct irq_domain *domain;
        unsigned int type;
        unsigned int i;
+       int ret;
  
        if (!irqchip)
                return 0;
                 "%pfw: Ignoring %u default trigger\n", fwnode, type))
                type = IRQ_TYPE_NONE;
  
-       if (gc->to_irq)
-               chip_warn(gc, "to_irq is redefined in %s and you shouldn't rely on it\n", __func__);
-       gc->to_irq = gpiochip_to_irq;
        gc->irq.default_type = type;
        gc->irq.lock_key = lock_key;
        gc->irq.request_key = request_key;
  
        /* If a parent irqdomain is provided, let's build a hierarchy */
        if (gpiochip_hierarchy_is_hierarchical(gc)) {
-               int ret = gpiochip_hierarchy_add_domain(gc);
-               if (ret)
-                       return ret;
+               domain = gpiochip_hierarchy_create_domain(gc);
        } else {
-               gc->irq.domain = irq_domain_create_simple(fwnode,
-                       gc->ngpio,
-                       gc->irq.first,
-                       &gpiochip_domain_ops,
-                       gc);
-               if (!gc->irq.domain)
-                       return -EINVAL;
+               domain = gpiochip_simple_create_domain(gc);
        }
+       if (IS_ERR(domain))
+               return PTR_ERR(domain);
  
        if (gc->irq.parent_handler) {
                for (i = 0; i < gc->irq.num_parents; i++) {
  
        gpiochip_set_irq_hooks(gc);
  
-       /*
-        * Using barrier() here to prevent compiler from reordering
-        * gc->irq.initialized before initialization of above
-        * GPIO chip irq members.
-        */
-       barrier();
-       gc->irq.initialized = true;
+       ret = gpiochip_irqchip_add_allocated_domain(gc, domain, false);
+       if (ret)
+               return ret;
  
        acpi_gpiochip_request_interrupts(gc);
  
@@@ -1780,22 -1814,7 +1814,7 @@@ static void gpiochip_irqchip_remove(str
  int gpiochip_irqchip_add_domain(struct gpio_chip *gc,
                                struct irq_domain *domain)
  {
-       if (!domain)
-               return -EINVAL;
-       gc->to_irq = gpiochip_to_irq;
-       gc->irq.domain = domain;
-       gc->irq.domain_is_allocated_externally = true;
-       /*
-        * Using barrier() here to prevent compiler from reordering
-        * gc->irq.initialized before adding irqdomain.
-        */
-       barrier();
-       gc->irq.initialized = true;
-       return 0;
+       return gpiochip_irqchip_add_allocated_domain(gc, domain, true);
  }
  EXPORT_SYMBOL_GPL(gpiochip_irqchip_add_domain);
  
@@@ -2159,26 -2178,19 +2178,25 @@@ static bool gpiod_free_commit(struct gp
        }
  
        spin_unlock_irqrestore(&gpio_lock, flags);
-       blocking_notifier_call_chain(&desc->gdev->notifier,
-                                    GPIOLINE_CHANGED_RELEASED, desc);
+       gpiod_line_state_notify(desc, GPIOLINE_CHANGED_RELEASED);
  
        return ret;
  }
  
  void gpiod_free(struct gpio_desc *desc)
  {
 -      if (desc && desc->gdev && gpiod_free_commit(desc)) {
 -              module_put(desc->gdev->owner);
 -              gpio_device_put(desc->gdev);
 -      } else {
 +      /*
 +       * We must not use VALIDATE_DESC_VOID() as the underlying gdev->chip
 +       * may already be NULL but we still want to put the references.
 +       */
 +      if (!desc)
 +              return;
 +
 +      if (!gpiod_free_commit(desc))
                WARN_ON(extra_checks);
 -      }
 +
 +      module_put(desc->gdev->owner);
 +      gpio_device_put(desc->gdev);
  }
  
  /**
@@@ -3728,6 -3740,12 +3746,12 @@@ int gpiod_set_array_value_cansleep(unsi
  }
  EXPORT_SYMBOL_GPL(gpiod_set_array_value_cansleep);
  
+ void gpiod_line_state_notify(struct gpio_desc *desc, unsigned long action)
+ {
+       blocking_notifier_call_chain(&desc->gdev->line_state_notifier,
+                                    action, desc);
+ }
  /**
   * gpiod_add_lookup_table() - register GPIO device consumers
   * @table: table of consumers to register
@@@ -3995,8 -4013,7 +4019,7 @@@ static struct gpio_desc *gpiod_find_and
                return ERR_PTR(ret);
        }
  
-       blocking_notifier_call_chain(&desc->gdev->notifier,
-                                    GPIOLINE_CHANGED_REQUESTED, desc);
+       gpiod_line_state_notify(desc, GPIOLINE_CHANGED_REQUESTED);
  
        return desc;
  }
This page took 0.2314 seconds and 4 git commands to generate.