OSDN Git Service

Merge tag 'v3.19-rc5' into devel
authorLinus Walleij <linus.walleij@linaro.org>
Tue, 20 Jan 2015 10:03:07 +0000 (11:03 +0100)
committerLinus Walleij <linus.walleij@linaro.org>
Tue, 20 Jan 2015 10:03:07 +0000 (11:03 +0100)
Linux 3.19-rc5

1  2 
drivers/gpio/gpio-dln2.c
drivers/gpio/gpio-grgpio.c

diff --combined drivers/gpio/gpio-dln2.c
  
  #define DLN2_GPIO_MAX_PINS 32
  
- struct dln2_irq_work {
-       struct work_struct work;
-       struct dln2_gpio *dln2;
-       int pin;
-       int type;
- };
  struct dln2_gpio {
        struct platform_device *pdev;
        struct gpio_chip gpio;
         */
        DECLARE_BITMAP(output_enabled, DLN2_GPIO_MAX_PINS);
  
-       DECLARE_BITMAP(irqs_masked, DLN2_GPIO_MAX_PINS);
-       DECLARE_BITMAP(irqs_enabled, DLN2_GPIO_MAX_PINS);
-       DECLARE_BITMAP(irqs_pending, DLN2_GPIO_MAX_PINS);
-       struct dln2_irq_work *irq_work;
+       /* active IRQs - not synced to hardware */
+       DECLARE_BITMAP(unmasked_irqs, DLN2_GPIO_MAX_PINS);
+       /* active IRQS - synced to hardware */
+       DECLARE_BITMAP(enabled_irqs, DLN2_GPIO_MAX_PINS);
+       int irq_type[DLN2_GPIO_MAX_PINS];
+       struct mutex irq_lock;
  };
  
  struct dln2_gpio_pin {
@@@ -141,16 -136,16 +136,16 @@@ static int dln2_gpio_pin_get_out_val(st
        return !!ret;
  }
  
- static void dln2_gpio_pin_set_out_val(struct dln2_gpio *dln2,
-                                     unsigned int pin, int value)
+ static int dln2_gpio_pin_set_out_val(struct dln2_gpio *dln2,
+                                    unsigned int pin, int value)
  {
        struct dln2_gpio_pin_val req = {
                .pin = cpu_to_le16(pin),
                .value = value,
        };
  
-       dln2_transfer_tx(dln2->pdev, DLN2_GPIO_PIN_SET_OUT_VAL, &req,
-                        sizeof(req));
+       return dln2_transfer_tx(dln2->pdev, DLN2_GPIO_PIN_SET_OUT_VAL, &req,
+                               sizeof(req));
  }
  
  #define DLN2_GPIO_DIRECTION_IN                0
@@@ -267,6 -262,13 +262,13 @@@ static int dln2_gpio_direction_input(st
  static int dln2_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
                                      int value)
  {
+       struct dln2_gpio *dln2 = container_of(chip, struct dln2_gpio, gpio);
+       int ret;
+       ret = dln2_gpio_pin_set_out_val(dln2, offset, value);
+       if (ret < 0)
+               return ret;
        return dln2_gpio_set_direction(chip, offset, DLN2_GPIO_DIRECTION_OUT);
  }
  
@@@ -297,36 -299,13 +299,13 @@@ static int dln2_gpio_set_event_cfg(stru
                                &req, sizeof(req));
  }
  
- static void dln2_irq_work(struct work_struct *w)
- {
-       struct dln2_irq_work *iw = container_of(w, struct dln2_irq_work, work);
-       struct dln2_gpio *dln2 = iw->dln2;
-       u8 type = iw->type & DLN2_GPIO_EVENT_MASK;
-       if (test_bit(iw->pin, dln2->irqs_enabled))
-               dln2_gpio_set_event_cfg(dln2, iw->pin, type, 0);
-       else
-               dln2_gpio_set_event_cfg(dln2, iw->pin, DLN2_GPIO_EVENT_NONE, 0);
- }
- static void dln2_irq_enable(struct irq_data *irqd)
- {
-       struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
-       struct dln2_gpio *dln2 = container_of(gc, struct dln2_gpio, gpio);
-       int pin = irqd_to_hwirq(irqd);
-       set_bit(pin, dln2->irqs_enabled);
-       schedule_work(&dln2->irq_work[pin].work);
- }
- static void dln2_irq_disable(struct irq_data *irqd)
+ static void dln2_irq_unmask(struct irq_data *irqd)
  {
        struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
        struct dln2_gpio *dln2 = container_of(gc, struct dln2_gpio, gpio);
        int pin = irqd_to_hwirq(irqd);
  
-       clear_bit(pin, dln2->irqs_enabled);
-       schedule_work(&dln2->irq_work[pin].work);
+       set_bit(pin, dln2->unmasked_irqs);
  }
  
  static void dln2_irq_mask(struct irq_data *irqd)
        struct dln2_gpio *dln2 = container_of(gc, struct dln2_gpio, gpio);
        int pin = irqd_to_hwirq(irqd);
  
-       set_bit(pin, dln2->irqs_masked);
- }
- static void dln2_irq_unmask(struct irq_data *irqd)
- {
-       struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
-       struct dln2_gpio *dln2 = container_of(gc, struct dln2_gpio, gpio);
-       struct device *dev = dln2->gpio.dev;
-       int pin = irqd_to_hwirq(irqd);
-       if (test_and_clear_bit(pin, dln2->irqs_pending)) {
-               int irq;
-               irq = irq_find_mapping(dln2->gpio.irqdomain, pin);
-               if (!irq) {
-                       dev_err(dev, "pin %d not mapped to IRQ\n", pin);
-                       return;
-               }
-               generic_handle_irq(irq);
-       }
+       clear_bit(pin, dln2->unmasked_irqs);
  }
  
  static int dln2_irq_set_type(struct irq_data *irqd, unsigned type)
  
        switch (type) {
        case IRQ_TYPE_LEVEL_HIGH:
-               dln2->irq_work[pin].type = DLN2_GPIO_EVENT_LVL_HIGH;
+               dln2->irq_type[pin] = DLN2_GPIO_EVENT_LVL_HIGH;
                break;
        case IRQ_TYPE_LEVEL_LOW:
-               dln2->irq_work[pin].type = DLN2_GPIO_EVENT_LVL_LOW;
+               dln2->irq_type[pin] = DLN2_GPIO_EVENT_LVL_LOW;
                break;
        case IRQ_TYPE_EDGE_BOTH:
-               dln2->irq_work[pin].type = DLN2_GPIO_EVENT_CHANGE;
+               dln2->irq_type[pin] = DLN2_GPIO_EVENT_CHANGE;
                break;
        case IRQ_TYPE_EDGE_RISING:
-               dln2->irq_work[pin].type = DLN2_GPIO_EVENT_CHANGE_RISING;
+               dln2->irq_type[pin] = DLN2_GPIO_EVENT_CHANGE_RISING;
                break;
        case IRQ_TYPE_EDGE_FALLING:
-               dln2->irq_work[pin].type = DLN2_GPIO_EVENT_CHANGE_FALLING;
+               dln2->irq_type[pin] = DLN2_GPIO_EVENT_CHANGE_FALLING;
                break;
        default:
                return -EINVAL;
        return 0;
  }
  
+ static void dln2_irq_bus_lock(struct irq_data *irqd)
+ {
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+       struct dln2_gpio *dln2 = container_of(gc, struct dln2_gpio, gpio);
+       mutex_lock(&dln2->irq_lock);
+ }
+ static void dln2_irq_bus_unlock(struct irq_data *irqd)
+ {
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+       struct dln2_gpio *dln2 = container_of(gc, struct dln2_gpio, gpio);
+       int pin = irqd_to_hwirq(irqd);
+       int enabled, unmasked;
+       unsigned type;
+       int ret;
+       enabled = test_bit(pin, dln2->enabled_irqs);
+       unmasked = test_bit(pin, dln2->unmasked_irqs);
+       if (enabled != unmasked) {
+               if (unmasked) {
+                       type = dln2->irq_type[pin] & DLN2_GPIO_EVENT_MASK;
+                       set_bit(pin, dln2->enabled_irqs);
+               } else {
+                       type = DLN2_GPIO_EVENT_NONE;
+                       clear_bit(pin, dln2->enabled_irqs);
+               }
+               ret = dln2_gpio_set_event_cfg(dln2, pin, type, 0);
+               if (ret)
+                       dev_err(dln2->gpio.dev, "failed to set event\n");
+       }
+       mutex_unlock(&dln2->irq_lock);
+ }
  static struct irq_chip dln2_gpio_irqchip = {
        .name = "dln2-irq",
-       .irq_enable = dln2_irq_enable,
-       .irq_disable = dln2_irq_disable,
        .irq_mask = dln2_irq_mask,
        .irq_unmask = dln2_irq_unmask,
        .irq_set_type = dln2_irq_set_type,
+       .irq_bus_lock = dln2_irq_bus_lock,
+       .irq_bus_sync_unlock = dln2_irq_bus_unlock,
  };
  
  static void dln2_gpio_event(struct platform_device *pdev, u16 echo,
                            const void *data, int len)
  {
        int pin, irq;
 +
        const struct {
                __le16 count;
                __u8 type;
                return;
        }
  
-       if (!test_bit(pin, dln2->irqs_enabled))
-               return;
-       if (test_bit(pin, dln2->irqs_masked)) {
-               set_bit(pin, dln2->irqs_pending);
-               return;
-       }
-       switch (dln2->irq_work[pin].type) {
+       switch (dln2->irq_type[pin]) {
        case DLN2_GPIO_EVENT_CHANGE_RISING:
                if (event->value)
                        generic_handle_irq(irq);
@@@ -452,7 -440,7 +441,7 @@@ static int dln2_gpio_probe(struct platf
        struct dln2_gpio *dln2;
        struct device *dev = &pdev->dev;
        int pins;
-       int i, ret;
+       int ret;
  
        pins = dln2_gpio_get_pin_count(pdev);
        if (pins < 0) {
        if (!dln2)
                return -ENOMEM;
  
-       dln2->irq_work = devm_kcalloc(&pdev->dev, pins,
-                                     sizeof(struct dln2_irq_work), GFP_KERNEL);
-       if (!dln2->irq_work)
-               return -ENOMEM;
-       for (i = 0; i < pins; i++) {
-               INIT_WORK(&dln2->irq_work[i].work, dln2_irq_work);
-               dln2->irq_work[i].pin = i;
-               dln2->irq_work[i].dln2 = dln2;
-       }
+       mutex_init(&dln2->irq_lock);
  
        dln2->pdev = pdev;
  
@@@ -530,11 -510,8 +511,8 @@@ out
  static int dln2_gpio_remove(struct platform_device *pdev)
  {
        struct dln2_gpio *dln2 = platform_get_drvdata(pdev);
-       int i;
  
        dln2_unregister_event_cb(pdev, DLN2_GPIO_CONDITION_MET_EV);
-       for (i = 0; i < dln2->gpio.ngpio; i++)
-               flush_work(&dln2->irq_work[i].work);
        gpiochip_remove(&dln2->gpio);
  
        return 0;
@@@ -121,7 -121,7 +121,7 @@@ static int grgpio_to_irq(struct gpio_ch
  {
        struct grgpio_priv *priv = grgpio_gc_to_priv(gc);
  
 -      if (offset > gc->ngpio)
 +      if (offset >= gc->ngpio)
                return -ENXIO;
  
        if (priv->lirqs[offset].index < 0)
@@@ -441,7 -441,8 +441,8 @@@ static int grgpio_probe(struct platform
        err = gpiochip_add(gc);
        if (err) {
                dev_err(&ofdev->dev, "Could not add gpiochip\n");
-               irq_domain_remove(priv->domain);
+               if (priv->domain)
+                       irq_domain_remove(priv->domain);
                return err;
        }