These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / gpio / gpio-pcf857x.c
index 945f0cd..1d4d9bc 100644 (file)
@@ -88,9 +88,10 @@ struct pcf857x {
        struct gpio_chip        chip;
        struct i2c_client       *client;
        struct mutex            lock;           /* protect 'out' */
-       spinlock_t              slock;          /* protect irq demux */
        unsigned                out;            /* software latch */
        unsigned                status;         /* current status */
+       unsigned int            irq_parent;
+       unsigned                irq_enabled;    /* enabled irqs */
 
        int (*write)(struct i2c_client *client, unsigned data);
        int (*read)(struct i2c_client *client);
@@ -183,23 +184,21 @@ static void pcf857x_set(struct gpio_chip *chip, unsigned offset, int value)
 static irqreturn_t pcf857x_irq(int irq, void *data)
 {
        struct pcf857x  *gpio = data;
-       unsigned long change, i, status, flags;
+       unsigned long change, i, status;
 
        status = gpio->read(gpio->client);
 
-       spin_lock_irqsave(&gpio->slock, flags);
-
        /*
         * call the interrupt handler iff gpio is used as
         * interrupt source, just to avoid bad irqs
         */
+       mutex_lock(&gpio->lock);
+       change = (gpio->status ^ status) & gpio->irq_enabled;
+       gpio->status = status;
+       mutex_unlock(&gpio->lock);
 
-       change = (gpio->status ^ status);
        for_each_set_bit(i, &change, gpio->chip.ngpio)
                handle_nested_irq(irq_find_mapping(gpio->chip.irqdomain, i));
-       gpio->status = status;
-
-       spin_unlock_irqrestore(&gpio->slock, flags);
 
        return IRQ_HANDLED;
 }
@@ -209,29 +208,62 @@ static irqreturn_t pcf857x_irq(int irq, void *data)
  */
 static void noop(struct irq_data *data) { }
 
-static unsigned int noop_ret(struct irq_data *data)
+static int pcf857x_irq_set_wake(struct irq_data *data, unsigned int on)
 {
-       return 0;
+       struct pcf857x *gpio = irq_data_get_irq_chip_data(data);
+
+       int error = 0;
+
+       if (gpio->irq_parent) {
+               error = irq_set_irq_wake(gpio->irq_parent, on);
+               if (error) {
+                       dev_dbg(&gpio->client->dev,
+                               "irq %u doesn't support irq_set_wake\n",
+                               gpio->irq_parent);
+                       gpio->irq_parent = 0;
+               }
+       }
+       return error;
 }
 
-static int pcf857x_irq_set_wake(struct irq_data *data, unsigned int on)
+static void pcf857x_irq_enable(struct irq_data *data)
 {
        struct pcf857x *gpio = irq_data_get_irq_chip_data(data);
 
-       irq_set_irq_wake(gpio->client->irq, on);
-       return 0;
+       gpio->irq_enabled |= (1 << data->hwirq);
+}
+
+static void pcf857x_irq_disable(struct irq_data *data)
+{
+       struct pcf857x *gpio = irq_data_get_irq_chip_data(data);
+
+       gpio->irq_enabled &= ~(1 << data->hwirq);
+}
+
+static void pcf857x_irq_bus_lock(struct irq_data *data)
+{
+       struct pcf857x *gpio = irq_data_get_irq_chip_data(data);
+
+       mutex_lock(&gpio->lock);
+}
+
+static void pcf857x_irq_bus_sync_unlock(struct irq_data *data)
+{
+       struct pcf857x *gpio = irq_data_get_irq_chip_data(data);
+
+       mutex_unlock(&gpio->lock);
 }
 
 static struct irq_chip pcf857x_irq_chip = {
        .name           = "pcf857x",
-       .irq_startup    = noop_ret,
-       .irq_shutdown   = noop,
-       .irq_enable     = noop,
-       .irq_disable    = noop,
+       .irq_enable     = pcf857x_irq_enable,
+       .irq_disable    = pcf857x_irq_disable,
        .irq_ack        = noop,
        .irq_mask       = noop,
        .irq_unmask     = noop,
        .irq_set_wake   = pcf857x_irq_set_wake,
+       .irq_bus_lock           = pcf857x_irq_bus_lock,
+       .irq_bus_sync_unlock    = pcf857x_irq_bus_sync_unlock,
 };
 
 /*-------------------------------------------------------------------------*/
@@ -258,7 +290,6 @@ static int pcf857x_probe(struct i2c_client *client,
                return -ENOMEM;
 
        mutex_init(&gpio->lock);
-       spin_lock_init(&gpio->slock);
 
        gpio->chip.base                 = pdata ? pdata->gpio_base : -1;
        gpio->chip.can_sleep            = true;
@@ -364,6 +395,7 @@ static int pcf857x_probe(struct i2c_client *client,
 
                gpiochip_set_chained_irqchip(&gpio->chip, &pcf857x_irq_chip,
                                             client->irq, NULL);
+               gpio->irq_parent = client->irq;
        }
 
        /* Let platform code set up the GPIOs and their users.