]> Git Repo - linux.git/commitdiff
Merge tag 'gpio-v5.9-2' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux...
authorLinus Torvalds <[email protected]>
Fri, 2 Oct 2020 16:51:42 +0000 (09:51 -0700)
committerLinus Torvalds <[email protected]>
Fri, 2 Oct 2020 16:51:42 +0000 (09:51 -0700)
Pull GPIO fixes from Linus Walleij:
 "Some late GPIO fixes for the v5.9 series:

   - Fix compiler warnings on the OMAP when PM is disabled

   - Clear the interrupt when setting edge sensitivity on the Spreadtrum
     driver.

   - Fix up spurious interrupts on the TC35894.

   - Support threaded interrupts on the Siox controller.

   - Fix resource leaks on the mockup driver.

   - Fix line event handling in syscall compatible mode for the
     character device.

   - Fix an unitialized variable in the PCA953A driver.

   - Fix access to all GPIO IRQs on the Aspeed AST2600.

   - Fix line direction on the AMD FCH driver.

   - Use the bitmap API instead of compiler intrinsics for bit
     manipulation in the PCA953x driver"

* tag 'gpio-v5.9-2' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio:
  gpio: pca953x: Correctly initialize registers 6 and 7 for PCA957x
  gpio: pca953x: Use bitmap API over implicit GCC extension
  gpio: amd-fch: correct logic of GPIO_LINE_DIRECTION
  gpio: aspeed: fix ast2600 bank properties
  gpio/aspeed-sgpio: don't enable all interrupts by default
  gpio/aspeed-sgpio: enable access to all 80 input & output sgpios
  gpio: pca953x: Fix uninitialized pending variable
  gpiolib: Fix line event handling in syscall compatible mode
  gpio: mockup: fix resource leak in error path
  gpio: siox: explicitly support only threaded irqs
  gpio: tc35894: fix up tc35894 interrupt configuration
  gpio: sprd: Clear interrupt when setting the type as edge
  gpio: omap: Fix warnings if PM is disabled

1  2 
drivers/gpio/gpio-aspeed-sgpio.c
drivers/gpio/gpio-aspeed.c

index 3aa45934d60c4184a5159894d2c1631c37f427d7,a0eb00c024f62d12d331764b7676b7e70dbc896f..64e54f8c30d2d6f4371d8f1fc6ce16d54b4abae0
  #include <linux/spinlock.h>
  #include <linux/string.h>
  
- #define MAX_NR_SGPIO                  80
+ /*
+  * MAX_NR_HW_GPIO represents the number of actual hardware-supported GPIOs (ie,
+  * slots within the clocked serial GPIO data). Since each HW GPIO is both an
+  * input and an output, we provide MAX_NR_HW_GPIO * 2 lines on our gpiochip
+  * device.
+  *
+  * We use SGPIO_OUTPUT_OFFSET to define the split between the inputs and
+  * outputs; the inputs start at line 0, the outputs start at OUTPUT_OFFSET.
+  */
+ #define MAX_NR_HW_SGPIO                       80
+ #define SGPIO_OUTPUT_OFFSET           MAX_NR_HW_SGPIO
  
  #define ASPEED_SGPIO_CTRL             0x54
  
@@@ -30,8 -40,8 +40,8 @@@ struct aspeed_sgpio 
        struct clk *pclk;
        spinlock_t lock;
        void __iomem *base;
-       uint32_t dir_in[3];
        int irq;
+       int n_sgpio;
  };
  
  struct aspeed_sgpio_bank {
@@@ -111,31 -121,69 +121,69 @@@ static void __iomem *bank_reg(struct as
        }
  }
  
- #define GPIO_BANK(x)    ((x) >> 5)
- #define GPIO_OFFSET(x)  ((x) & 0x1f)
+ #define GPIO_BANK(x)    ((x % SGPIO_OUTPUT_OFFSET) >> 5)
+ #define GPIO_OFFSET(x)  ((x % SGPIO_OUTPUT_OFFSET) & 0x1f)
  #define GPIO_BIT(x)     BIT(GPIO_OFFSET(x))
  
  static const struct aspeed_sgpio_bank *to_bank(unsigned int offset)
  {
-       unsigned int bank = GPIO_BANK(offset);
+       unsigned int bank;
+       bank = GPIO_BANK(offset);
  
        WARN_ON(bank >= ARRAY_SIZE(aspeed_sgpio_banks));
        return &aspeed_sgpio_banks[bank];
  }
  
+ static int aspeed_sgpio_init_valid_mask(struct gpio_chip *gc,
+               unsigned long *valid_mask, unsigned int ngpios)
+ {
+       struct aspeed_sgpio *sgpio = gpiochip_get_data(gc);
+       int n = sgpio->n_sgpio;
+       int c = SGPIO_OUTPUT_OFFSET - n;
+       WARN_ON(ngpios < MAX_NR_HW_SGPIO * 2);
+       /* input GPIOs in the lower range */
+       bitmap_set(valid_mask, 0, n);
+       bitmap_clear(valid_mask, n, c);
+       /* output GPIOS above SGPIO_OUTPUT_OFFSET */
+       bitmap_set(valid_mask, SGPIO_OUTPUT_OFFSET, n);
+       bitmap_clear(valid_mask, SGPIO_OUTPUT_OFFSET + n, c);
+       return 0;
+ }
+ static void aspeed_sgpio_irq_init_valid_mask(struct gpio_chip *gc,
+               unsigned long *valid_mask, unsigned int ngpios)
+ {
+       struct aspeed_sgpio *sgpio = gpiochip_get_data(gc);
+       int n = sgpio->n_sgpio;
+       WARN_ON(ngpios < MAX_NR_HW_SGPIO * 2);
+       /* input GPIOs in the lower range */
+       bitmap_set(valid_mask, 0, n);
+       bitmap_clear(valid_mask, n, ngpios - n);
+ }
+ static bool aspeed_sgpio_is_input(unsigned int offset)
+ {
+       return offset < SGPIO_OUTPUT_OFFSET;
+ }
  static int aspeed_sgpio_get(struct gpio_chip *gc, unsigned int offset)
  {
        struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
        const struct aspeed_sgpio_bank *bank = to_bank(offset);
        unsigned long flags;
        enum aspeed_sgpio_reg reg;
-       bool is_input;
        int rc = 0;
  
        spin_lock_irqsave(&gpio->lock, flags);
  
-       is_input = gpio->dir_in[GPIO_BANK(offset)] & GPIO_BIT(offset);
-       reg = is_input ? reg_val : reg_rdata;
+       reg = aspeed_sgpio_is_input(offset) ? reg_val : reg_rdata;
        rc = !!(ioread32(bank_reg(gpio, bank, reg)) & GPIO_BIT(offset));
  
        spin_unlock_irqrestore(&gpio->lock, flags);
        return rc;
  }
  
- static void sgpio_set_value(struct gpio_chip *gc, unsigned int offset, int val)
+ static int sgpio_set_value(struct gpio_chip *gc, unsigned int offset, int val)
  {
        struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
        const struct aspeed_sgpio_bank *bank = to_bank(offset);
-       void __iomem *addr;
+       void __iomem *addr_r, *addr_w;
        u32 reg = 0;
  
-       addr = bank_reg(gpio, bank, reg_val);
-       reg = ioread32(addr);
+       if (aspeed_sgpio_is_input(offset))
+               return -EINVAL;
+       /* Since this is an output, read the cached value from rdata, then
+        * update val. */
+       addr_r = bank_reg(gpio, bank, reg_rdata);
+       addr_w = bank_reg(gpio, bank, reg_val);
+       reg = ioread32(addr_r);
  
        if (val)
                reg |= GPIO_BIT(offset);
        else
                reg &= ~GPIO_BIT(offset);
  
-       iowrite32(reg, addr);
+       iowrite32(reg, addr_w);
+       return 0;
  }
  
  static void aspeed_sgpio_set(struct gpio_chip *gc, unsigned int offset, int val)
  
  static int aspeed_sgpio_dir_in(struct gpio_chip *gc, unsigned int offset)
  {
-       struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
-       unsigned long flags;
-       spin_lock_irqsave(&gpio->lock, flags);
-       gpio->dir_in[GPIO_BANK(offset)] |= GPIO_BIT(offset);
-       spin_unlock_irqrestore(&gpio->lock, flags);
-       return 0;
+       return aspeed_sgpio_is_input(offset) ? 0 : -EINVAL;
  }
  
  static int aspeed_sgpio_dir_out(struct gpio_chip *gc, unsigned int offset, int val)
  {
        struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
        unsigned long flags;
+       int rc;
  
-       spin_lock_irqsave(&gpio->lock, flags);
-       gpio->dir_in[GPIO_BANK(offset)] &= ~GPIO_BIT(offset);
-       sgpio_set_value(gc, offset, val);
+       /* No special action is required for setting the direction; we'll
+        * error-out in sgpio_set_value if this isn't an output GPIO */
  
+       spin_lock_irqsave(&gpio->lock, flags);
+       rc = sgpio_set_value(gc, offset, val);
        spin_unlock_irqrestore(&gpio->lock, flags);
  
-       return 0;
+       return rc;
  }
  
  static int aspeed_sgpio_get_direction(struct gpio_chip *gc, unsigned int offset)
  {
-       int dir_status;
-       struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
-       unsigned long flags;
-       spin_lock_irqsave(&gpio->lock, flags);
-       dir_status = gpio->dir_in[GPIO_BANK(offset)] & GPIO_BIT(offset);
-       spin_unlock_irqrestore(&gpio->lock, flags);
-       return dir_status;
+       return !!aspeed_sgpio_is_input(offset);
  }
  
  static void irqd_to_aspeed_sgpio_data(struct irq_data *d,
@@@ -303,16 -345,16 +345,16 @@@ static int aspeed_sgpio_set_type(struc
        switch (type & IRQ_TYPE_SENSE_MASK) {
        case IRQ_TYPE_EDGE_BOTH:
                type2 |= bit;
 -              /* fall through */
 +              fallthrough;
        case IRQ_TYPE_EDGE_RISING:
                type0 |= bit;
 -              /* fall through */
 +              fallthrough;
        case IRQ_TYPE_EDGE_FALLING:
                handler = handle_edge_irq;
                break;
        case IRQ_TYPE_LEVEL_HIGH:
                type0 |= bit;
 -              /* fall through */
 +              fallthrough;
        case IRQ_TYPE_LEVEL_LOW:
                type1 |= bit;
                handler = handle_level_irq;
@@@ -402,6 -444,7 +444,7 @@@ static int aspeed_sgpio_setup_irqs(stru
  
        irq = &gpio->chip.irq;
        irq->chip = &aspeed_sgpio_irqchip;
+       irq->init_valid_mask = aspeed_sgpio_irq_init_valid_mask;
        irq->handler = handle_bad_irq;
        irq->default_type = IRQ_TYPE_NONE;
        irq->parent_handler = aspeed_sgpio_irq_handler;
        irq->parents = &gpio->irq;
        irq->num_parents = 1;
  
-       /* set IRQ settings and Enable Interrupt */
+       /* Apply default IRQ settings */
        for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) {
                bank = &aspeed_sgpio_banks[i];
                /* set falling or level-low irq */
                iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type0));
                /* trigger type is edge */
                iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type1));
-               /* dual edge trigger mode. */
-               iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_type2));
-               /* enable irq */
-               iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_enable));
+               /* single edge trigger */
+               iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type2));
        }
  
        return 0;
@@@ -452,11 -493,12 +493,12 @@@ static int __init aspeed_sgpio_probe(st
        if (rc < 0) {
                dev_err(&pdev->dev, "Could not read ngpios property\n");
                return -EINVAL;
-       } else if (nr_gpios > MAX_NR_SGPIO) {
+       } else if (nr_gpios > MAX_NR_HW_SGPIO) {
                dev_err(&pdev->dev, "Number of GPIOs exceeds the maximum of %d: %d\n",
-                       MAX_NR_SGPIO, nr_gpios);
+                       MAX_NR_HW_SGPIO, nr_gpios);
                return -EINVAL;
        }
+       gpio->n_sgpio = nr_gpios;
  
        rc = of_property_read_u32(pdev->dev.of_node, "bus-frequency", &sgpio_freq);
        if (rc < 0) {
        spin_lock_init(&gpio->lock);
  
        gpio->chip.parent = &pdev->dev;
-       gpio->chip.ngpio = nr_gpios;
+       gpio->chip.ngpio = MAX_NR_HW_SGPIO * 2;
+       gpio->chip.init_valid_mask = aspeed_sgpio_init_valid_mask;
        gpio->chip.direction_input = aspeed_sgpio_dir_in;
        gpio->chip.direction_output = aspeed_sgpio_dir_out;
        gpio->chip.get_direction = aspeed_sgpio_get_direction;
        gpio->chip.label = dev_name(&pdev->dev);
        gpio->chip.base = -1;
  
-       /* set all SGPIO pins as input (1). */
-       memset(gpio->dir_in, 0xff, sizeof(gpio->dir_in));
        aspeed_sgpio_setup_irqs(gpio, pdev);
  
        rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
index bf08b4561f3616b53cd957231fffa1486dfefbe9,d07bf2c3f1369bbe4b4d45c9bdcbe421c65b604c..e44d5de2a1201a1ecce4d6d9985c473dcc071a26
@@@ -611,16 -611,16 +611,16 @@@ static int aspeed_gpio_set_type(struct 
        switch (type & IRQ_TYPE_SENSE_MASK) {
        case IRQ_TYPE_EDGE_BOTH:
                type2 |= bit;
 -              /* fall through */
 +              fallthrough;
        case IRQ_TYPE_EDGE_RISING:
                type0 |= bit;
 -              /* fall through */
 +              fallthrough;
        case IRQ_TYPE_EDGE_FALLING:
                handler = handle_edge_irq;
                break;
        case IRQ_TYPE_LEVEL_HIGH:
                type0 |= bit;
 -              /* fall through */
 +              fallthrough;
        case IRQ_TYPE_LEVEL_LOW:
                type1 |= bit;
                handler = handle_level_irq;
@@@ -1114,8 -1114,8 +1114,8 @@@ static const struct aspeed_gpio_config 
  
  static const struct aspeed_bank_props ast2600_bank_props[] = {
        /*     input      output   */
-       {5, 0xffffffff,  0x0000ffff}, /* U/V/W/X */
-       {6, 0xffff0000,  0x0fff0000}, /* Y/Z */
+       {5, 0xffffffff,  0xffffff00}, /* U/V/W/X */
+       {6, 0x0000ffff,  0x0000ffff}, /* Y/Z */
        { },
  };
  
This page took 0.074938 seconds and 4 git commands to generate.