gpio: omap: Add get/set_multiple() callbacks
authorJanusz Krzysztofik <jmkrzyszt@gmail.com>
Wed, 18 Jul 2018 23:57:08 +0000 (01:57 +0200)
committerLinus Walleij <linus.walleij@linaro.org>
Mon, 6 Aug 2018 21:46:55 +0000 (23:46 +0200)
This should make applications utilizing whole banks work faster.

Signed-off-by: Janusz Krzysztofik <jmkrzyszt@gmail.com>
Acked-by: Grygorii Strashko <grygorii.strashko@ti.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
drivers/gpio/gpio-omap.c

index d1afedf4dcbf0203005f1eb783a3468b0d77afe2..e81008678a38f5c36987b37a83bac80ccaccae8a 100644 (file)
@@ -77,6 +77,8 @@ struct gpio_bank {
        bool workaround_enabled;
 
        void (*set_dataout)(struct gpio_bank *bank, unsigned gpio, int enable);
+       void (*set_dataout_multiple)(struct gpio_bank *bank,
+                                    unsigned long *mask, unsigned long *bits);
        int (*get_context_loss_count)(struct device *dev);
 
        struct omap_gpio_reg_offs *regs;
@@ -161,6 +163,51 @@ static int omap_get_gpio_dataout(struct gpio_bank *bank, int offset)
        return (readl_relaxed(reg) & (BIT(offset))) != 0;
 }
 
+/* set multiple data out values using dedicate set/clear register */
+static void omap_set_gpio_dataout_reg_multiple(struct gpio_bank *bank,
+                                              unsigned long *mask,
+                                              unsigned long *bits)
+{
+       void __iomem *reg = bank->base;
+       u32 l;
+
+       l = *bits & *mask;
+       writel_relaxed(l, reg + bank->regs->set_dataout);
+       bank->context.dataout |= l;
+
+       l = ~*bits & *mask;
+       writel_relaxed(l, reg + bank->regs->clr_dataout);
+       bank->context.dataout &= ~l;
+}
+
+/* set multiple data out values using mask register */
+static void omap_set_gpio_dataout_mask_multiple(struct gpio_bank *bank,
+                                               unsigned long *mask,
+                                               unsigned long *bits)
+{
+       void __iomem *reg = bank->base + bank->regs->dataout;
+       u32 l = (readl_relaxed(reg) & ~*mask) | (*bits & *mask);
+
+       writel_relaxed(l, reg);
+       bank->context.dataout = l;
+}
+
+static unsigned long omap_get_gpio_datain_multiple(struct gpio_bank *bank,
+                                             unsigned long *mask)
+{
+       void __iomem *reg = bank->base + bank->regs->datain;
+
+       return readl_relaxed(reg) & *mask;
+}
+
+static unsigned long omap_get_gpio_dataout_multiple(struct gpio_bank *bank,
+                                              unsigned long *mask)
+{
+       void __iomem *reg = bank->base + bank->regs->dataout;
+
+       return readl_relaxed(reg) & *mask;
+}
+
 static inline void omap_gpio_rmw(void __iomem *base, u32 reg, u32 mask, bool set)
 {
        int l = readl_relaxed(base + reg);
@@ -968,6 +1015,26 @@ static int omap_gpio_output(struct gpio_chip *chip, unsigned offset, int value)
        return 0;
 }
 
+static int omap_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
+                                 unsigned long *bits)
+{
+       struct gpio_bank *bank = gpiochip_get_data(chip);
+       void __iomem *reg = bank->base + bank->regs->direction;
+       unsigned long in = readl_relaxed(reg), l;
+
+       *bits = 0;
+
+       l = in & *mask;
+       if (l)
+               *bits |= omap_get_gpio_datain_multiple(bank, &l);
+
+       l = ~in & *mask;
+       if (l)
+               *bits |= omap_get_gpio_dataout_multiple(bank, &l);
+
+       return 0;
+}
+
 static int omap_gpio_debounce(struct gpio_chip *chip, unsigned offset,
                              unsigned debounce)
 {
@@ -1012,6 +1079,17 @@ static void omap_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
        raw_spin_unlock_irqrestore(&bank->lock, flags);
 }
 
+static void omap_gpio_set_multiple(struct gpio_chip *chip, unsigned long *mask,
+                                  unsigned long *bits)
+{
+       struct gpio_bank *bank = gpiochip_get_data(chip);
+       unsigned long flags;
+
+       raw_spin_lock_irqsave(&bank->lock, flags);
+       bank->set_dataout_multiple(bank, mask, bits);
+       raw_spin_unlock_irqrestore(&bank->lock, flags);
+}
+
 /*---------------------------------------------------------------------*/
 
 static void omap_gpio_show_rev(struct gpio_bank *bank)
@@ -1073,9 +1151,11 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
        bank->chip.get_direction = omap_gpio_get_direction;
        bank->chip.direction_input = omap_gpio_input;
        bank->chip.get = omap_gpio_get;
+       bank->chip.get_multiple = omap_gpio_get_multiple;
        bank->chip.direction_output = omap_gpio_output;
        bank->chip.set_config = omap_gpio_set_config;
        bank->chip.set = omap_gpio_set;
+       bank->chip.set_multiple = omap_gpio_set_multiple;
        if (bank->is_mpuio) {
                bank->chip.label = "mpuio";
                if (bank->regs->wkup_en)
@@ -1209,10 +1289,14 @@ static int omap_gpio_probe(struct platform_device *pdev)
                                pdata->get_context_loss_count;
        }
 
-       if (bank->regs->set_dataout && bank->regs->clr_dataout)
+       if (bank->regs->set_dataout && bank->regs->clr_dataout) {
                bank->set_dataout = omap_set_gpio_dataout_reg;
-       else
+               bank->set_dataout_multiple = omap_set_gpio_dataout_reg_multiple;
+       } else {
                bank->set_dataout = omap_set_gpio_dataout_mask;
+               bank->set_dataout_multiple =
+                               omap_set_gpio_dataout_mask_multiple;
+       }
 
        raw_spin_lock_init(&bank->lock);
        raw_spin_lock_init(&bank->wa_lock);