]> Git Repo - J-linux.git/commitdiff
Merge tag 'gpio-updates-for-v6.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <[email protected]>
Sat, 8 Oct 2022 16:46:29 +0000 (09:46 -0700)
committerLinus Torvalds <[email protected]>
Sat, 8 Oct 2022 16:46:29 +0000 (09:46 -0700)
Pull gpio updates from Bartosz Golaszewski:
 "We have a single new driver, support for a bunch of new models,
  improvements in drivers and core gpiolib code as well device-tree
  bindings changes.

  Summary:

  New driver:
   - IMX System Controller Unit GPIOs

  GPIO core:
   - add fdinfo output for the GPIO character device file descriptors
     (allows user-space to determine which processes own which GPIO
     lines)
   - improvements to OF GPIO code
   - new quirk for Asus UM325UAZ in gpiolib-acpi
   - new quirk for Freescale SPI in gpiolib-of

  Driver improvements:
   - add a new macro that reduces the amount of boilerplate code in ISA
     drivers and use it in relevant drivers
   - support two new models in gpio-pca953x
   - support new model in gpio-f7188x
   - convert more drivers to use immutable irq chips
   - other minor tweaks

  Device-tree bindings:
   - add DT bindings for gpio-imx-scu
   - convert Xilinx GPIO bindings to YAML
   - reference the properties from the SPI peripheral device-tree
     bindings instead of providing custom ones in the GPIO controller
     document
   - add parsing of GPIO hog nodes to the DT bindings for gpio-mpfs-gpio
   - relax the node name requirements in gpio-stmpe
   - add new models for gpio-rcar and gpio-pxa95xx
   - add a new vendor prefix: Diodes (for Diodes, Inc.)

  Misc:
   - pulled in the immutable branch from the x86 platform drivers tree
     including support for a new simatic board that depends on GPIO
     changes"

* tag 'gpio-updates-for-v6.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux: (36 commits)
  gpio: tc3589x: Make irqchip immutable
  gpiolib: cdev: add fdinfo output for line request file descriptors
  gpio: twl4030: Reorder functions which allows to drop a forward declaraion
  gpiolib: fix OOB access in quirk callbacks
  gpiolib: of: factor out conversion from OF flags
  gpiolib: rework quirk handling in of_find_gpio()
  gpiolib: of: make Freescale SPI quirk similar to all others
  gpiolib: of: do not ignore requested index when applying quirks
  gpio: ws16c48: Ensure number of irq matches number of base
  gpio: 104-idio-16: Ensure number of irq matches number of base
  gpio: 104-idi-48: Ensure number of irq matches number of base
  gpio: 104-dio-48e: Ensure number of irq matches number of base
  counter: 104-quad-8: Ensure number of irq matches number of base
  isa: Introduce the module_isa_driver_with_irq helper macro
  gpio: pca953x: Add support for PCAL6534
  gpio: pca953x: Swap if statements to save later complexity
  gpio: pca953x: Fix pca953x_gpio_set_pull_up_down()
  dt-bindings: gpio: pca95xx: add entry for pcal6534 and PI4IOE5V6534Q
  dt-bindings: vendor-prefixes: add Diodes
  gpio: mt7621: Switch to use platform_get_irq() function
  ...

1  2 
Documentation/devicetree/bindings/vendor-prefixes.yaml
drivers/counter/104-quad-8.c
drivers/gpio/gpio-104-dio-48e.c
drivers/gpio/gpio-104-idi-48.c
drivers/gpio/gpio-104-idio-16.c
drivers/gpio/gpio-mt7621.c
drivers/gpio/gpio-pca953x.c
drivers/gpio/gpio-rockchip.c
drivers/gpio/gpio-ws16c48.c
drivers/gpio/gpiolib-cdev.c

index 48b65069e6f2fed1a746f399714f20628958ce13,7ee9b7692ed176dfb09a7d42f5c605701712f51c..6e323a380294adef8592cdb4b4dfd956f87b3eb5
@@@ -105,8 -105,6 +105,8 @@@ patternProperties
      description: AMS-Taos Inc.
    "^analogix,.*":
      description: Analogix Semiconductor, Inc.
 +  "^anbernic,.*":
 +    description: Anbernic
    "^andestech,.*":
      description: Andes Technology Corporation
    "^anvo,.*":
      description: Digi International Inc.
    "^digilent,.*":
      description: Diglent, Inc.
+   "^diodes,.*":
+     description: Diodes, Inc.
    "^dioo,.*":
      description: Dioo Microcircuit Co., Ltd
    "^dlc,.*":
      description: MELFAS Inc.
    "^mellanox,.*":
      description: Mellanox Technologies
 +  "^memsensing,.*":
 +    description: MEMSensing Microsystems Co., Ltd.
    "^memsic,.*":
      description: MEMSIC Inc.
    "^menlo,.*":
      description: Cisco Meraki, LLC
    "^merrii,.*":
      description: Merrii Technology Co., Ltd.
 +  "^methode,.*":
 +    description: Methode Electronics, Inc.
    "^micrel,.*":
      description: Micrel Inc.
    "^microchip,.*":
      description: MNT Research GmbH
    "^modtronix,.*":
      description: Modtronix Engineering
 +  "^moortec,.*":
 +    description: Moortec Semiconductor Ltd.
    "^mosaixtech,.*":
      description: Mosaix Technologies, Inc.
    "^motorola,.*":
      description: On Tat Industrial Company
    "^opalkelly,.*":
      description: Opal Kelly Incorporated
 +  "^openailab,.*":
 +    description: openailab.com
    "^opencores,.*":
      description: OpenCores.org
    "^openembed,.*":
index 1188673d8521cee8aca1ef48c39febdbf5c65aec,3f8d1910a9bbe515d51b3047f9e9a3915cc275aa..77a863b7eefeac1a3fbd1d005e57eb508aadb604
@@@ -28,7 -28,8 +28,8 @@@ module_param_hw_array(base, uint, iopor
  MODULE_PARM_DESC(base, "ACCES 104-QUAD-8 base addresses");
  
  static unsigned int irq[max_num_isa_dev(QUAD8_EXTENT)];
- module_param_hw_array(irq, uint, irq, NULL, 0);
+ static unsigned int num_irq;
+ module_param_hw_array(irq, uint, irq, &num_irq, 0);
  MODULE_PARM_DESC(irq, "ACCES 104-QUAD-8 interrupt line numbers");
  
  #define QUAD8_NUM_COUNTERS 8
@@@ -449,9 -450,6 +450,9 @@@ static int quad8_events_configure(struc
                        return -EINVAL;
                }
  
 +              /* Enable IRQ line */
 +              irq_enabled |= BIT(event_node->channel);
 +
                /* Skip configuration if it is the same as previously set */
                if (priv->irq_trigger[event_node->channel] == next_irq_trigger)
                        continue;
                          priv->irq_trigger[event_node->channel] << 3;
                iowrite8(QUAD8_CTR_IOR | ior_cfg,
                         &priv->reg->channel[event_node->channel].control);
 -
 -              /* Enable IRQ line */
 -              irq_enabled |= BIT(event_node->channel);
        }
  
        iowrite8(irq_enabled, &priv->reg->index_interrupt);
@@@ -549,32 -550,6 +550,32 @@@ static int quad8_index_polarity_set(str
        return 0;
  }
  
 +static int quad8_polarity_read(struct counter_device *counter,
 +                             struct counter_signal *signal,
 +                             enum counter_signal_polarity *polarity)
 +{
 +      int err;
 +      u32 index_polarity;
 +
 +      err = quad8_index_polarity_get(counter, signal, &index_polarity);
 +      if (err)
 +              return err;
 +
 +      *polarity = (index_polarity) ? COUNTER_SIGNAL_POLARITY_POSITIVE :
 +              COUNTER_SIGNAL_POLARITY_NEGATIVE;
 +
 +      return 0;
 +}
 +
 +static int quad8_polarity_write(struct counter_device *counter,
 +                              struct counter_signal *signal,
 +                              enum counter_signal_polarity polarity)
 +{
 +      const u32 pol = (polarity == COUNTER_SIGNAL_POLARITY_POSITIVE) ? 1 : 0;
 +
 +      return quad8_index_polarity_set(counter, signal, pol);
 +}
 +
  static const char *const quad8_synchronous_modes[] = {
        "non-synchronous",
        "synchronous"
@@@ -1003,13 -978,6 +1004,13 @@@ static struct counter_comp quad8_signal
                               quad8_signal_fck_prescaler_write)
  };
  
 +static const enum counter_signal_polarity quad8_polarities[] = {
 +      COUNTER_SIGNAL_POLARITY_POSITIVE,
 +      COUNTER_SIGNAL_POLARITY_NEGATIVE,
 +};
 +
 +static DEFINE_COUNTER_AVAILABLE(quad8_polarity_available, quad8_polarities);
 +
  static DEFINE_COUNTER_ENUM(quad8_index_pol_enum, quad8_index_polarity_modes);
  static DEFINE_COUNTER_ENUM(quad8_synch_mode_enum, quad8_synchronous_modes);
  
@@@ -1017,8 -985,6 +1018,8 @@@ static struct counter_comp quad8_index_
        COUNTER_COMP_SIGNAL_ENUM("index_polarity", quad8_index_polarity_get,
                                 quad8_index_polarity_set,
                                 quad8_index_pol_enum),
 +      COUNTER_COMP_POLARITY(quad8_polarity_read, quad8_polarity_write,
 +                            quad8_polarity_available),
        COUNTER_COMP_SIGNAL_ENUM("synchronous_mode", quad8_synchronous_mode_get,
                                 quad8_synchronous_mode_set,
                                 quad8_synch_mode_enum),
@@@ -1271,9 -1237,8 +1272,9 @@@ static struct isa_driver quad8_driver 
        }
  };
  
- module_isa_driver(quad8_driver, num_quad8);
+ module_isa_driver_with_irq(quad8_driver, num_quad8, num_irq);
  
  MODULE_AUTHOR("William Breathitt Gray <[email protected]>");
  MODULE_DESCRIPTION("ACCES 104-QUAD-8 driver");
  MODULE_LICENSE("GPL v2");
 +MODULE_IMPORT_NS(COUNTER);
index 74cc71bb39846ae0bb657b236a0ee57607f280fe,8b5172802188974282de2e00b2bd23c8bd0ce9f0..7b8829c8e4231313ef98a9310e55c69b55c9ec92
@@@ -34,7 -34,8 +34,8 @@@ module_param_hw_array(base, uint, iopor
  MODULE_PARM_DESC(base, "ACCES 104-DIO-48E base addresses");
  
  static unsigned int irq[MAX_NUM_DIO48E];
- module_param_hw_array(irq, uint, irq, NULL, 0);
+ static unsigned int num_irq;
+ module_param_hw_array(irq, uint, irq, &num_irq, 0);
  MODULE_PARM_DESC(irq, "ACCES 104-DIO-48E interrupt line numbers");
  
  #define DIO48E_NUM_PPI 2
@@@ -164,7 -165,6 +165,7 @@@ static void dio48e_irq_mask(struct irq_
                dio48egpio->irq_mask &= ~BIT(0);
        else
                dio48egpio->irq_mask &= ~BIT(1);
 +      gpiochip_disable_irq(chip, offset);
  
        if (!dio48egpio->irq_mask)
                /* disable interrupts */
@@@ -192,7 -192,6 +193,7 @@@ static void dio48e_irq_unmask(struct ir
                iowrite8(0x00, &dio48egpio->reg->enable_interrupt);
        }
  
 +      gpiochip_enable_irq(chip, offset);
        if (offset == 19)
                dio48egpio->irq_mask |= BIT(0);
        else
@@@ -215,14 -214,12 +216,14 @@@ static int dio48e_irq_set_type(struct i
        return 0;
  }
  
 -static struct irq_chip dio48e_irqchip = {
 +static const struct irq_chip dio48e_irqchip = {
        .name = "104-dio-48e",
        .irq_ack = dio48e_irq_ack,
        .irq_mask = dio48e_irq_mask,
        .irq_unmask = dio48e_irq_unmask,
 -      .irq_set_type = dio48e_irq_set_type
 +      .irq_set_type = dio48e_irq_set_type,
 +      .flags = IRQCHIP_IMMUTABLE,
 +      GPIOCHIP_IRQ_RESOURCE_HELPERS,
  };
  
  static irqreturn_t dio48e_irq_handler(int irq, void *dev_id)
@@@ -326,7 -323,7 +327,7 @@@ static int dio48e_probe(struct device *
        dio48egpio->chip.set_multiple = dio48e_gpio_set_multiple;
  
        girq = &dio48egpio->chip.irq;
 -      girq->chip = &dio48e_irqchip;
 +      gpio_irq_chip_set_chip(girq, &dio48e_irqchip);
        /* This will let us handle the parent IRQ in the driver */
        girq->parent_handler = NULL;
        girq->num_parents = 0;
@@@ -362,7 -359,7 +363,7 @@@ static struct isa_driver dio48e_driver 
                .name = "104-dio-48e"
        },
  };
- module_isa_driver(dio48e_driver, num_dio48e);
+ module_isa_driver_with_irq(dio48e_driver, num_dio48e, num_irq);
  
  MODULE_AUTHOR("William Breathitt Gray <[email protected]>");
  MODULE_DESCRIPTION("ACCES 104-DIO-48E GPIO driver");
index 3286b914a2cfadd4b7c0b15c3f0b6992bcdfc95d,2b0256eefb703c2f406446b974331d8f06c33ccd..c5e231fde1affa3377864cbd8cead383068c4a06
@@@ -34,7 -34,8 +34,8 @@@ module_param_hw_array(base, uint, iopor
  MODULE_PARM_DESC(base, "ACCES 104-IDI-48 base addresses");
  
  static unsigned int irq[MAX_NUM_IDI_48];
- module_param_hw_array(irq, uint, irq, NULL, 0);
+ static unsigned int num_irq;
+ module_param_hw_array(irq, uint, irq, &num_irq, 0);
  MODULE_PARM_DESC(irq, "ACCES 104-IDI-48 interrupt line numbers");
  
  /**
@@@ -113,7 -114,6 +114,7 @@@ static void idi_48_irq_mask(struct irq_
        spin_lock_irqsave(&idi48gpio->lock, flags);
  
        idi48gpio->irq_mask[boundary] &= ~mask;
 +      gpiochip_disable_irq(chip, offset);
  
        /* Exit early if there are still input lines with IRQ unmasked */
        if (idi48gpio->irq_mask[boundary])
@@@ -141,7 -141,6 +142,7 @@@ static void idi_48_irq_unmask(struct ir
  
        prev_irq_mask = idi48gpio->irq_mask[boundary];
  
 +      gpiochip_enable_irq(chip, offset);
        idi48gpio->irq_mask[boundary] |= mask;
  
        /* Exit early if IRQ was already unmasked for this boundary */
@@@ -166,14 -165,12 +167,14 @@@ static int idi_48_irq_set_type(struct i
        return 0;
  }
  
 -static struct irq_chip idi_48_irqchip = {
 +static const struct irq_chip idi_48_irqchip = {
        .name = "104-idi-48",
        .irq_ack = idi_48_irq_ack,
        .irq_mask = idi_48_irq_mask,
        .irq_unmask = idi_48_irq_unmask,
 -      .irq_set_type = idi_48_irq_set_type
 +      .irq_set_type = idi_48_irq_set_type,
 +      .flags = IRQCHIP_IMMUTABLE,
 +      GPIOCHIP_IRQ_RESOURCE_HELPERS,
  };
  
  static irqreturn_t idi_48_irq_handler(int irq, void *dev_id)
@@@ -271,7 -268,7 +272,7 @@@ static int idi_48_probe(struct device *
        idi48gpio->chip.get_multiple = idi_48_gpio_get_multiple;
  
        girq = &idi48gpio->chip.irq;
 -      girq->chip = &idi_48_irqchip;
 +      gpio_irq_chip_set_chip(girq, &idi_48_irqchip);
        /* This will let us handle the parent IRQ in the driver */
        girq->parent_handler = NULL;
        girq->num_parents = 0;
@@@ -304,7 -301,7 +305,7 @@@ static struct isa_driver idi_48_driver 
                .name = "104-idi-48"
        },
  };
- module_isa_driver(idi_48_driver, num_idi_48);
+ module_isa_driver_with_irq(idi_48_driver, num_idi_48, num_irq);
  
  MODULE_AUTHOR("William Breathitt Gray <[email protected]>");
  MODULE_DESCRIPTION("ACCES 104-IDI-48 GPIO driver");
index 4756e583f223df654d2dd045f55501b16ba2e96b,73d95b55a8c5b820701c647339957e3faa37d23d..718bd54e2a25511da21604e0b3942d98fda278b0
@@@ -30,7 -30,8 +30,8 @@@ module_param_hw_array(base, uint, iopor
  MODULE_PARM_DESC(base, "ACCES 104-IDIO-16 base addresses");
  
  static unsigned int irq[MAX_NUM_IDIO_16];
- module_param_hw_array(irq, uint, irq, NULL, 0);
+ static unsigned int num_irq;
+ module_param_hw_array(irq, uint, irq, &num_irq, 0);
  MODULE_PARM_DESC(irq, "ACCES 104-IDIO-16 interrupt line numbers");
  
  /**
@@@ -174,11 -175,10 +175,11 @@@ static void idio_16_irq_mask(struct irq
  {
        struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
        struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
 -      const unsigned long mask = BIT(irqd_to_hwirq(data));
 +      const unsigned long offset = irqd_to_hwirq(data);
        unsigned long flags;
  
 -      idio16gpio->irq_mask &= ~mask;
 +      idio16gpio->irq_mask &= ~BIT(offset);
 +      gpiochip_disable_irq(chip, offset);
  
        if (!idio16gpio->irq_mask) {
                raw_spin_lock_irqsave(&idio16gpio->lock, flags);
@@@ -193,12 -193,11 +194,12 @@@ static void idio_16_irq_unmask(struct i
  {
        struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
        struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
 -      const unsigned long mask = BIT(irqd_to_hwirq(data));
 +      const unsigned long offset = irqd_to_hwirq(data);
        const unsigned long prev_irq_mask = idio16gpio->irq_mask;
        unsigned long flags;
  
 -      idio16gpio->irq_mask |= mask;
 +      gpiochip_enable_irq(chip, offset);
 +      idio16gpio->irq_mask |= BIT(offset);
  
        if (!prev_irq_mask) {
                raw_spin_lock_irqsave(&idio16gpio->lock, flags);
@@@ -219,14 -218,12 +220,14 @@@ static int idio_16_irq_set_type(struct 
        return 0;
  }
  
 -static struct irq_chip idio_16_irqchip = {
 +static const struct irq_chip idio_16_irqchip = {
        .name = "104-idio-16",
        .irq_ack = idio_16_irq_ack,
        .irq_mask = idio_16_irq_mask,
        .irq_unmask = idio_16_irq_unmask,
 -      .irq_set_type = idio_16_irq_set_type
 +      .irq_set_type = idio_16_irq_set_type,
 +      .flags = IRQCHIP_IMMUTABLE,
 +      GPIOCHIP_IRQ_RESOURCE_HELPERS,
  };
  
  static irqreturn_t idio_16_irq_handler(int irq, void *dev_id)
@@@ -303,7 -300,7 +304,7 @@@ static int idio_16_probe(struct device 
        idio16gpio->out_state = 0xFFFF;
  
        girq = &idio16gpio->chip.irq;
 -      girq->chip = &idio_16_irqchip;
 +      gpio_irq_chip_set_chip(girq, &idio_16_irqchip);
        /* This will let us handle the parent IRQ in the driver */
        girq->parent_handler = NULL;
        girq->num_parents = 0;
@@@ -337,7 -334,7 +338,7 @@@ static struct isa_driver idio_16_drive
        },
  };
  
- module_isa_driver(idio_16_driver, num_idio_16);
+ module_isa_driver_with_irq(idio_16_driver, num_idio_16, num_irq);
  
  MODULE_AUTHOR("William Breathitt Gray <[email protected]>");
  MODULE_DESCRIPTION("ACCES 104-IDIO-16 GPIO driver");
index f163f5ca857beb24d7c3eafffef482a6bb9def6b,340d17a5b6ec939b285004743558afe6f887fdae..93facbebb80efadbdd3fb4500e0db14936287f1a
@@@ -9,7 -9,6 +9,6 @@@
  #include <linux/interrupt.h>
  #include <linux/io.h>
  #include <linux/module.h>
- #include <linux/of_irq.h>
  #include <linux/platform_device.h>
  #include <linux/spinlock.h>
  
@@@ -112,8 -111,6 +111,8 @@@ mediatek_gpio_irq_unmask(struct irq_dat
        unsigned long flags;
        u32 rise, fall, high, low;
  
 +      gpiochip_enable_irq(gc, d->hwirq);
 +
        spin_lock_irqsave(&rg->lock, flags);
        rise = mtk_gpio_r32(rg, GPIO_REG_REDGE);
        fall = mtk_gpio_r32(rg, GPIO_REG_FEDGE);
@@@ -145,8 -142,6 +144,8 @@@ mediatek_gpio_irq_mask(struct irq_data 
        mtk_gpio_w32(rg, GPIO_REG_HLVL, high & ~BIT(pin));
        mtk_gpio_w32(rg, GPIO_REG_LLVL, low & ~BIT(pin));
        spin_unlock_irqrestore(&rg->lock, flags);
 +
 +      gpiochip_disable_irq(gc, d->hwirq);
  }
  
  static int
@@@ -208,16 -203,6 +207,16 @@@ mediatek_gpio_xlate(struct gpio_chip *c
        return gpio % MTK_BANK_WIDTH;
  }
  
 +static const struct irq_chip mt7621_irq_chip = {
 +      .name           = "mt7621-gpio",
 +      .irq_mask_ack   = mediatek_gpio_irq_mask,
 +      .irq_mask       = mediatek_gpio_irq_mask,
 +      .irq_unmask     = mediatek_gpio_irq_unmask,
 +      .irq_set_type   = mediatek_gpio_irq_type,
 +      .flags          = IRQCHIP_IMMUTABLE,
 +      GPIOCHIP_IRQ_RESOURCE_HELPERS,
 +};
 +
  static int
  mediatek_gpio_bank_probe(struct device *dev, int bank)
  {
                return -ENOMEM;
  
        rg->chip.offset = bank * MTK_BANK_WIDTH;
 -      rg->irq_chip.name = dev_name(dev);
 -      rg->irq_chip.irq_unmask = mediatek_gpio_irq_unmask;
 -      rg->irq_chip.irq_mask = mediatek_gpio_irq_mask;
 -      rg->irq_chip.irq_mask_ack = mediatek_gpio_irq_mask;
 -      rg->irq_chip.irq_set_type = mediatek_gpio_irq_type;
  
        if (mtk->gpio_irq) {
                struct gpio_irq_chip *girq;
                }
  
                girq = &rg->chip.irq;
 -              girq->chip = &rg->irq_chip;
 +              gpio_irq_chip_set_chip(girq, &mt7621_irq_chip);
                /* This will let us handle the parent IRQ in the driver */
                girq->parent_handler = NULL;
                girq->num_parents = 0;
@@@ -299,7 -289,6 +298,6 @@@ static in
  mediatek_gpio_probe(struct platform_device *pdev)
  {
        struct device *dev = &pdev->dev;
-       struct device_node *np = dev->of_node;
        struct mtk *mtk;
        int i;
        int ret;
        if (IS_ERR(mtk->base))
                return PTR_ERR(mtk->base);
  
-       mtk->gpio_irq = irq_of_parse_and_map(np, 0);
+       mtk->gpio_irq = platform_get_irq(pdev, 0);
+       if (mtk->gpio_irq < 0)
+               return mtk->gpio_irq;
        mtk->dev = dev;
        platform_set_drvdata(pdev, mtk);
  
index cf9bf3fcaee2653e586b2b2e29e655b4a27465b5,61e874c0cde436817bc7f0c5868dfd2f20f3a6c9..ebe1943b85dd99f77a7c8883c2759ef666abc703
@@@ -66,6 -66,7 +66,7 @@@
  #define PCA_LATCH_INT         (PCA_PCAL | PCA_INT)
  #define PCA953X_TYPE          BIT(12)
  #define PCA957X_TYPE          BIT(13)
+ #define PCAL653X_TYPE         BIT(14)
  #define PCA_TYPE_MASK         GENMASK(15, 12)
  
  #define PCA_CHIP_TYPE(x)      ((x) & PCA_TYPE_MASK)
@@@ -89,8 -90,10 +90,10 @@@ static const struct i2c_device_id pca95
        { "pca9575", 16 | PCA957X_TYPE | PCA_INT, },
        { "pca9698", 40 | PCA953X_TYPE, },
  
+       { "pcal6408", 8 | PCA953X_TYPE | PCA_LATCH_INT, },
        { "pcal6416", 16 | PCA953X_TYPE | PCA_LATCH_INT, },
        { "pcal6524", 24 | PCA953X_TYPE | PCA_LATCH_INT, },
+       { "pcal6534", 34 | PCAL653X_TYPE | PCA_LATCH_INT, },
        { "pcal9535", 16 | PCA953X_TYPE | PCA_LATCH_INT, },
        { "pcal9554b", 8  | PCA953X_TYPE | PCA_LATCH_INT, },
        { "pcal9555a", 16 | PCA953X_TYPE | PCA_LATCH_INT, },
@@@ -211,6 -214,10 +214,10 @@@ struct pca953x_chip 
        struct regulator *regulator;
  
        const struct pca953x_reg_config *regs;
+       u8 (*recalc_addr)(struct pca953x_chip *chip, int reg, int off);
+       bool (*check_reg)(struct pca953x_chip *chip, unsigned int reg,
+                         u32 checkbank);
  };
  
  static int pca953x_bank_shift(struct pca953x_chip *chip)
@@@ -288,18 -295,67 +295,67 @@@ static bool pca953x_check_register(stru
        return true;
  }
  
+ /*
+  * Unfortunately, whilst the PCAL6534 chip (and compatibles) broadly follow the
+  * same register layout as the PCAL6524, the spacing of the registers has been
+  * fundamentally altered by compacting them and thus does not obey the same
+  * rules, including being able to use bit shifting to determine bank. These
+  * chips hence need special handling here.
+  */
+ static bool pcal6534_check_register(struct pca953x_chip *chip, unsigned int reg,
+                                   u32 checkbank)
+ {
+       int bank;
+       int offset;
+       if (reg >= 0x30) {
+               /*
+                * Reserved block between 14h and 2Fh does not align on
+                * expected bank boundaries like other devices.
+                */
+               int temp = reg - 0x30;
+               bank = temp / NBANK(chip);
+               offset = temp - (bank * NBANK(chip));
+               bank += 8;
+       } else if (reg >= 0x54) {
+               /*
+                * Handle lack of reserved registers after output port
+                * configuration register to form a bank.
+                */
+               int temp = reg - 0x54;
+               bank = temp / NBANK(chip);
+               offset = temp - (bank * NBANK(chip));
+               bank += 16;
+       } else {
+               bank = reg / NBANK(chip);
+               offset = reg - (bank * NBANK(chip));
+       }
+       /* Register is not in the matching bank. */
+       if (!(BIT(bank) & checkbank))
+               return false;
+       /* Register is not within allowed range of bank. */
+       if (offset >= NBANK(chip))
+               return false;
+       return true;
+ }
  static bool pca953x_readable_register(struct device *dev, unsigned int reg)
  {
        struct pca953x_chip *chip = dev_get_drvdata(dev);
        u32 bank;
  
-       if (PCA_CHIP_TYPE(chip->driver_data) == PCA953X_TYPE) {
-               bank = PCA953x_BANK_INPUT | PCA953x_BANK_OUTPUT |
-                      PCA953x_BANK_POLARITY | PCA953x_BANK_CONFIG;
-       } else {
+       if (PCA_CHIP_TYPE(chip->driver_data) == PCA957X_TYPE) {
                bank = PCA957x_BANK_INPUT | PCA957x_BANK_OUTPUT |
                       PCA957x_BANK_POLARITY | PCA957x_BANK_CONFIG |
                       PCA957x_BANK_BUSHOLD;
+       } else {
+               bank = PCA953x_BANK_INPUT | PCA953x_BANK_OUTPUT |
+                      PCA953x_BANK_POLARITY | PCA953x_BANK_CONFIG;
        }
  
        if (chip->driver_data & PCA_PCAL) {
                        PCAL9xxx_BANK_IRQ_STAT;
        }
  
-       return pca953x_check_register(chip, reg, bank);
+       return chip->check_reg(chip, reg, bank);
  }
  
  static bool pca953x_writeable_register(struct device *dev, unsigned int reg)
        struct pca953x_chip *chip = dev_get_drvdata(dev);
        u32 bank;
  
-       if (PCA_CHIP_TYPE(chip->driver_data) == PCA953X_TYPE) {
-               bank = PCA953x_BANK_OUTPUT | PCA953x_BANK_POLARITY |
-                       PCA953x_BANK_CONFIG;
-       } else {
+       if (PCA_CHIP_TYPE(chip->driver_data) == PCA957X_TYPE) {
                bank = PCA957x_BANK_OUTPUT | PCA957x_BANK_POLARITY |
                        PCA957x_BANK_CONFIG | PCA957x_BANK_BUSHOLD;
+       } else {
+               bank = PCA953x_BANK_OUTPUT | PCA953x_BANK_POLARITY |
+                       PCA953x_BANK_CONFIG;
        }
  
        if (chip->driver_data & PCA_PCAL)
                bank |= PCAL9xxx_BANK_IN_LATCH | PCAL9xxx_BANK_PULL_EN |
                        PCAL9xxx_BANK_PULL_SEL | PCAL9xxx_BANK_IRQ_MASK;
  
-       return pca953x_check_register(chip, reg, bank);
+       return chip->check_reg(chip, reg, bank);
  }
  
  static bool pca953x_volatile_register(struct device *dev, unsigned int reg)
        struct pca953x_chip *chip = dev_get_drvdata(dev);
        u32 bank;
  
-       if (PCA_CHIP_TYPE(chip->driver_data) == PCA953X_TYPE)
-               bank = PCA953x_BANK_INPUT;
-       else
+       if (PCA_CHIP_TYPE(chip->driver_data) == PCA957X_TYPE)
                bank = PCA957x_BANK_INPUT;
+       else
+               bank = PCA953x_BANK_INPUT;
  
        if (chip->driver_data & PCA_PCAL)
                bank |= PCAL9xxx_BANK_IRQ_STAT;
  
-       return pca953x_check_register(chip, reg, bank);
+       return chip->check_reg(chip, reg, bank);
  }
  
  static const struct regmap_config pca953x_i2c_regmap = {
@@@ -389,9 -445,42 +445,42 @@@ static u8 pca953x_recalc_addr(struct pc
        return regaddr;
  }
  
+ /*
+  * The PCAL6534 and compatible chips have altered bank alignment that doesn't
+  * fit within the bit shifting scheme used for other devices.
+  */
+ static u8 pcal6534_recalc_addr(struct pca953x_chip *chip, int reg, int off)
+ {
+       int addr;
+       int pinctrl;
+       addr = (reg & PCAL_GPIO_MASK) * NBANK(chip);
+       switch (reg) {
+       case PCAL953X_OUT_STRENGTH:
+       case PCAL953X_IN_LATCH:
+       case PCAL953X_PULL_EN:
+       case PCAL953X_PULL_SEL:
+       case PCAL953X_INT_MASK:
+       case PCAL953X_INT_STAT:
+       case PCAL953X_OUT_CONF:
+               pinctrl = ((reg & PCAL_PINCTRL_MASK) >> 1) + 0x20;
+               break;
+       case PCAL6524_INT_EDGE:
+       case PCAL6524_INT_CLR:
+       case PCAL6524_IN_STATUS:
+       case PCAL6524_OUT_INDCONF:
+       case PCAL6524_DEBOUNCE:
+               pinctrl = ((reg & PCAL_PINCTRL_MASK) >> 1) + 0x1c;
+               break;
+       }
+       return pinctrl + addr + (off / BANK_SZ);
+ }
  static int pca953x_write_regs(struct pca953x_chip *chip, int reg, unsigned long *val)
  {
-       u8 regaddr = pca953x_recalc_addr(chip, reg, 0);
+       u8 regaddr = chip->recalc_addr(chip, reg, 0);
        u8 value[MAX_BANK];
        int i, ret;
  
  
  static int pca953x_read_regs(struct pca953x_chip *chip, int reg, unsigned long *val)
  {
-       u8 regaddr = pca953x_recalc_addr(chip, reg, 0);
+       u8 regaddr = chip->recalc_addr(chip, reg, 0);
        u8 value[MAX_BANK];
        int i, ret;
  
  static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
  {
        struct pca953x_chip *chip = gpiochip_get_data(gc);
-       u8 dirreg = pca953x_recalc_addr(chip, chip->regs->direction, off);
+       u8 dirreg = chip->recalc_addr(chip, chip->regs->direction, off);
        u8 bit = BIT(off % BANK_SZ);
        int ret;
  
@@@ -442,8 -531,8 +531,8 @@@ static int pca953x_gpio_direction_outpu
                unsigned off, int val)
  {
        struct pca953x_chip *chip = gpiochip_get_data(gc);
-       u8 dirreg = pca953x_recalc_addr(chip, chip->regs->direction, off);
-       u8 outreg = pca953x_recalc_addr(chip, chip->regs->output, off);
+       u8 dirreg = chip->recalc_addr(chip, chip->regs->direction, off);
+       u8 outreg = chip->recalc_addr(chip, chip->regs->output, off);
        u8 bit = BIT(off % BANK_SZ);
        int ret;
  
@@@ -463,7 -552,7 +552,7 @@@ exit
  static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
  {
        struct pca953x_chip *chip = gpiochip_get_data(gc);
-       u8 inreg = pca953x_recalc_addr(chip, chip->regs->input, off);
+       u8 inreg = chip->recalc_addr(chip, chip->regs->input, off);
        u8 bit = BIT(off % BANK_SZ);
        u32 reg_val;
        int ret;
  static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
  {
        struct pca953x_chip *chip = gpiochip_get_data(gc);
-       u8 outreg = pca953x_recalc_addr(chip, chip->regs->output, off);
+       u8 outreg = chip->recalc_addr(chip, chip->regs->output, off);
        u8 bit = BIT(off % BANK_SZ);
  
        mutex_lock(&chip->i2c_lock);
  static int pca953x_gpio_get_direction(struct gpio_chip *gc, unsigned off)
  {
        struct pca953x_chip *chip = gpiochip_get_data(gc);
-       u8 dirreg = pca953x_recalc_addr(chip, chip->regs->direction, off);
+       u8 dirreg = chip->recalc_addr(chip, chip->regs->direction, off);
        u8 bit = BIT(off % BANK_SZ);
        u32 reg_val;
        int ret;
@@@ -548,8 -637,10 +637,10 @@@ static int pca953x_gpio_set_pull_up_dow
                                         unsigned int offset,
                                         unsigned long config)
  {
-       u8 pull_en_reg = pca953x_recalc_addr(chip, PCAL953X_PULL_EN, offset);
-       u8 pull_sel_reg = pca953x_recalc_addr(chip, PCAL953X_PULL_SEL, offset);
+       enum pin_config_param param = pinconf_to_config_param(config);
+       u8 pull_en_reg = chip->recalc_addr(chip, PCAL953X_PULL_EN, offset);
+       u8 pull_sel_reg = chip->recalc_addr(chip, PCAL953X_PULL_SEL, offset);
        u8 bit = BIT(offset % BANK_SZ);
        int ret;
  
        mutex_lock(&chip->i2c_lock);
  
        /* Configure pull-up/pull-down */
-       if (config == PIN_CONFIG_BIAS_PULL_UP)
+       if (param == PIN_CONFIG_BIAS_PULL_UP)
                ret = regmap_write_bits(chip->regmap, pull_sel_reg, bit, bit);
-       else if (config == PIN_CONFIG_BIAS_PULL_DOWN)
+       else if (param == PIN_CONFIG_BIAS_PULL_DOWN)
                ret = regmap_write_bits(chip->regmap, pull_sel_reg, bit, 0);
        else
                ret = 0;
                goto exit;
  
        /* Disable/Enable pull-up/pull-down */
-       if (config == PIN_CONFIG_BIAS_DISABLE)
+       if (param == PIN_CONFIG_BIAS_DISABLE)
                ret = regmap_write_bits(chip->regmap, pull_en_reg, bit, 0);
        else
                ret = regmap_write_bits(chip->regmap, pull_en_reg, bit, bit);
@@@ -912,13 -1003,13 +1003,13 @@@ static int device_pca95xx_init(struct p
        u8 regaddr;
        int ret;
  
-       regaddr = pca953x_recalc_addr(chip, chip->regs->output, 0);
+       regaddr = chip->recalc_addr(chip, chip->regs->output, 0);
        ret = regcache_sync_region(chip->regmap, regaddr,
                                   regaddr + NBANK(chip) - 1);
        if (ret)
                goto out;
  
-       regaddr = pca953x_recalc_addr(chip, chip->regs->direction, 0);
+       regaddr = chip->recalc_addr(chip, chip->regs->direction, 0);
        ret = regcache_sync_region(chip->regmap, regaddr,
                                   regaddr + NBANK(chip) - 1);
        if (ret)
@@@ -1037,6 -1128,14 +1128,14 @@@ static int pca953x_probe(struct i2c_cli
                regmap_config = &pca953x_i2c_regmap;
        }
  
+       if (PCA_CHIP_TYPE(chip->driver_data) == PCAL653X_TYPE) {
+               chip->recalc_addr = pcal6534_recalc_addr;
+               chip->check_reg = pcal6534_check_register;
+       } else {
+               chip->recalc_addr = pca953x_recalc_addr;
+               chip->check_reg = pca953x_check_register;
+       }
        chip->regmap = devm_regmap_init_i2c(client, regmap_config);
        if (IS_ERR(chip->regmap)) {
                ret = PTR_ERR(chip->regmap);
        /* initialize cached registers from their original values.
         * we can't share this chip with another i2c master.
         */
-       if (PCA_CHIP_TYPE(chip->driver_data) == PCA953X_TYPE) {
-               chip->regs = &pca953x_regs;
-               ret = device_pca95xx_init(chip, invert);
-       } else {
+       if (PCA_CHIP_TYPE(chip->driver_data) == PCA957X_TYPE) {
                chip->regs = &pca957x_regs;
                ret = device_pca957x_init(chip, invert);
+       } else {
+               chip->regs = &pca953x_regs;
+               ret = device_pca95xx_init(chip, invert);
        }
        if (ret)
                goto err_exit;
@@@ -1101,17 -1199,24 +1199,17 @@@ err_exit
        return ret;
  }
  
 -static int pca953x_remove(struct i2c_client *client)
 +static void pca953x_remove(struct i2c_client *client)
  {
        struct pca953x_platform_data *pdata = dev_get_platdata(&client->dev);
        struct pca953x_chip *chip = i2c_get_clientdata(client);
 -      int ret;
  
        if (pdata && pdata->teardown) {
 -              ret = pdata->teardown(client, chip->gpio_chip.base,
 -                                    chip->gpio_chip.ngpio, pdata->context);
 -              if (ret < 0)
 -                      dev_err(&client->dev, "teardown failed, %d\n", ret);
 -      } else {
 -              ret = 0;
 +              pdata->teardown(client, chip->gpio_chip.base,
 +                              chip->gpio_chip.ngpio, pdata->context);
        }
  
        regulator_disable(chip->regulator);
 -
 -      return ret;
  }
  
  #ifdef CONFIG_PM_SLEEP
@@@ -1125,14 -1230,14 +1223,14 @@@ static int pca953x_regcache_sync(struc
         * The ordering between direction and output is important,
         * sync these registers first and only then sync the rest.
         */
-       regaddr = pca953x_recalc_addr(chip, chip->regs->direction, 0);
+       regaddr = chip->recalc_addr(chip, chip->regs->direction, 0);
        ret = regcache_sync_region(chip->regmap, regaddr, regaddr + NBANK(chip) - 1);
        if (ret) {
                dev_err(dev, "Failed to sync GPIO dir registers: %d\n", ret);
                return ret;
        }
  
-       regaddr = pca953x_recalc_addr(chip, chip->regs->output, 0);
+       regaddr = chip->recalc_addr(chip, chip->regs->output, 0);
        ret = regcache_sync_region(chip->regmap, regaddr, regaddr + NBANK(chip) - 1);
        if (ret) {
                dev_err(dev, "Failed to sync GPIO out registers: %d\n", ret);
  
  #ifdef CONFIG_GPIO_PCA953X_IRQ
        if (chip->driver_data & PCA_PCAL) {
-               regaddr = pca953x_recalc_addr(chip, PCAL953X_IN_LATCH, 0);
+               regaddr = chip->recalc_addr(chip, PCAL953X_IN_LATCH, 0);
                ret = regcache_sync_region(chip->regmap, regaddr,
                                           regaddr + NBANK(chip) - 1);
                if (ret) {
                        return ret;
                }
  
-               regaddr = pca953x_recalc_addr(chip, PCAL953X_INT_MASK, 0);
+               regaddr = chip->recalc_addr(chip, PCAL953X_INT_MASK, 0);
                ret = regcache_sync_region(chip->regmap, regaddr,
                                           regaddr + NBANK(chip) - 1);
                if (ret) {
@@@ -1168,9 -1273,7 +1266,9 @@@ static int pca953x_suspend(struct devic
  {
        struct pca953x_chip *chip = dev_get_drvdata(dev);
  
 +      mutex_lock(&chip->i2c_lock);
        regcache_cache_only(chip->regmap, true);
 +      mutex_unlock(&chip->i2c_lock);
  
        if (atomic_read(&chip->wakeup_path))
                device_set_wakeup_path(dev);
@@@ -1193,17 -1296,13 +1291,17 @@@ static int pca953x_resume(struct devic
                }
        }
  
 +      mutex_lock(&chip->i2c_lock);
        regcache_cache_only(chip->regmap, false);
        regcache_mark_dirty(chip->regmap);
        ret = pca953x_regcache_sync(dev);
 -      if (ret)
 +      if (ret) {
 +              mutex_unlock(&chip->i2c_lock);
                return ret;
 +      }
  
        ret = regcache_sync(chip->regmap);
 +      mutex_unlock(&chip->i2c_lock);
        if (ret) {
                dev_err(dev, "Failed to restore register map: %d\n", ret);
                return ret;
  #endif
  
  /* convenience to stop overlong match-table lines */
+ #define OF_653X(__nrgpio, __int) ((void *)(__nrgpio | PCAL653X_TYPE | __int))
  #define OF_953X(__nrgpio, __int) (void *)(__nrgpio | PCA953X_TYPE | __int)
  #define OF_957X(__nrgpio, __int) (void *)(__nrgpio | PCA957X_TYPE | __int)
  
@@@ -1236,8 -1336,10 +1335,10 @@@ static const struct of_device_id pca953
        { .compatible = "nxp,pca9575", .data = OF_957X(16, PCA_INT), },
        { .compatible = "nxp,pca9698", .data = OF_953X(40, 0), },
  
+       { .compatible = "nxp,pcal6408", .data = OF_953X(8, PCA_LATCH_INT), },
        { .compatible = "nxp,pcal6416", .data = OF_953X(16, PCA_LATCH_INT), },
        { .compatible = "nxp,pcal6524", .data = OF_953X(24, PCA_LATCH_INT), },
+       { .compatible = "nxp,pcal6534", .data = OF_653X(34, PCA_LATCH_INT), },
        { .compatible = "nxp,pcal9535", .data = OF_953X(16, PCA_LATCH_INT), },
        { .compatible = "nxp,pcal9554b", .data = OF_953X( 8, PCA_LATCH_INT), },
        { .compatible = "nxp,pcal9555a", .data = OF_953X(16, PCA_LATCH_INT), },
index bb50335239ac804e615f045c8e029290d2973fb0,ebb50c25a461c54b0422cbdecca9f779c4d107e5..6765477edb064c106213f5808402667a93f01fcd
@@@ -325,26 -325,15 +325,15 @@@ static void rockchip_irq_demux(struct i
  {
        struct irq_chip *chip = irq_desc_get_chip(desc);
        struct rockchip_pin_bank *bank = irq_desc_get_handler_data(desc);
-       u32 pend;
+       unsigned long pending;
+       unsigned int irq;
  
        dev_dbg(bank->dev, "got irq for bank %s\n", bank->name);
  
        chained_irq_enter(chip, desc);
  
-       pend = readl_relaxed(bank->reg_base + bank->gpio_regs->int_status);
-       while (pend) {
-               unsigned int irq, virq;
-               irq = __ffs(pend);
-               pend &= ~BIT(irq);
-               virq = irq_find_mapping(bank->domain, irq);
-               if (!virq) {
-                       dev_err(bank->dev, "unmapped irq %d\n", irq);
-                       continue;
-               }
+       pending = readl_relaxed(bank->reg_base + bank->gpio_regs->int_status);
+       for_each_set_bit(irq, &pending, 32) {
                dev_dbg(bank->dev, "handling irq %d\n", irq);
  
                /*
                        } while ((data & BIT(irq)) != (data_old & BIT(irq)));
                }
  
-               generic_handle_irq(virq);
+               generic_handle_domain_irq(bank->domain, irq);
        }
  
        chained_irq_exit(chip, desc);
@@@ -419,11 -408,11 +408,11 @@@ static int rockchip_irq_set_type(struc
                        goto out;
                } else {
                        bank->toggle_edge_mode |= mask;
 -                      level |= mask;
 +                      level &= ~mask;
  
                        /*
                         * Determine gpio state. If 1 next interrupt should be
 -                       * falling otherwise rising.
 +                       * low otherwise high.
                         */
                        data = readl(bank->reg_base + bank->gpio_regs->ext_port);
                        if (data & mask)
index 59fb10641598df1b0a9e8049d8fa9d0832542fa0,88410da91aafa7ddc1ec9cf3ae706f6af7a6c916..e73885a4dc32871ed634dc9548b1f63fd3ca5ed8
@@@ -27,7 -27,8 +27,8 @@@ module_param_hw_array(base, uint, iopor
  MODULE_PARM_DESC(base, "WinSystems WS16C48 base addresses");
  
  static unsigned int irq[MAX_NUM_WS16C48];
- module_param_hw_array(irq, uint, irq, NULL, 0);
+ static unsigned int num_irq;
+ module_param_hw_array(irq, uint, irq, &num_irq, 0);
  MODULE_PARM_DESC(irq, "WinSystems WS16C48 interrupt line numbers");
  
  /**
@@@ -265,7 -266,6 +266,7 @@@ static void ws16c48_irq_mask(struct irq
        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 */
@@@ -296,7 -296,6 +297,7 @@@ static void ws16c48_irq_unmask(struct i
  
        raw_spin_lock_irqsave(&ws16c48gpio->lock, flags);
  
 +      gpiochip_enable_irq(chip, offset);
        ws16c48gpio->irq_mask |= mask;
        port_state = ws16c48gpio->irq_mask >> (8 * port);
  
@@@ -358,14 -357,12 +359,14 @@@ static int ws16c48_irq_set_type(struct 
        return 0;
  }
  
 -static struct irq_chip ws16c48_irqchip = {
 +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
 +      .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)
@@@ -467,7 -464,7 +468,7 @@@ static int ws16c48_probe(struct device 
        ws16c48gpio->chip.set_multiple = ws16c48_gpio_set_multiple;
  
        girq = &ws16c48gpio->chip.irq;
 -      girq->chip = &ws16c48_irqchip;
 +      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;
@@@ -501,7 -498,7 +502,7 @@@ static struct isa_driver ws16c48_drive
        },
  };
  
- module_isa_driver(ws16c48_driver, num_ws16c48);
+ module_isa_driver_with_irq(ws16c48_driver, num_ws16c48, num_irq);
  
  MODULE_AUTHOR("William Breathitt Gray <[email protected]>");
  MODULE_DESCRIPTION("WinSystems WS16C48 GPIO driver");
index 92f185575e941f438b8ed6f0b35e8c54ca497402,01c15e9e6896ba9f1073cc1b253ff95a50b1948f..0cb6b468f364f99c6ff4ed0e68b2718c52e74201
@@@ -1497,6 -1497,21 +1497,21 @@@ static int linereq_release(struct inod
        return 0;
  }
  
+ #ifdef CONFIG_PROC_FS
+ static void linereq_show_fdinfo(struct seq_file *out, struct file *file)
+ {
+       struct linereq *lr = file->private_data;
+       struct device *dev = &lr->gdev->dev;
+       u16 i;
+       seq_printf(out, "gpio-chip:\t%s\n", dev_name(dev));
+       for (i = 0; i < lr->num_lines; i++)
+               seq_printf(out, "gpio-line:\t%d\n",
+                          gpio_chip_hwgpio(lr->lines[i].desc));
+ }
+ #endif
  static const struct file_operations line_fileops = {
        .release = linereq_release,
        .read = linereq_read,
  #ifdef CONFIG_COMPAT
        .compat_ioctl = linereq_ioctl_compat,
  #endif
+ #ifdef CONFIG_PROC_FS
+       .show_fdinfo = linereq_show_fdinfo,
+ #endif
  };
  
  static int linereq_create(struct gpio_device *gdev, void __user *ip)
@@@ -1986,6 -2004,7 +2004,6 @@@ static int lineevent_create(struct gpio
                ret = -ENODEV;
                goto out_free_le;
        }
 -      le->irq = irq;
  
        if (eflags & GPIOEVENT_REQUEST_RISING_EDGE)
                irqflags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ?
        init_waitqueue_head(&le->wait);
  
        /* Request a thread to read the events */
 -      ret = request_threaded_irq(le->irq,
 +      ret = request_threaded_irq(irq,
                                   lineevent_irq_handler,
                                   lineevent_irq_thread,
                                   irqflags,
        if (ret)
                goto out_free_le;
  
 +      le->irq = irq;
 +
        fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC);
        if (fd < 0) {
                ret = fd;
This page took 0.129038 seconds and 4 git commands to generate.