pinctrl: iproc-gpio: Fix incorrect pinconf configurations
authorLi Jin <li.jin@broadcom.com>
Thu, 29 Aug 2019 04:52:27 +0000 (10:22 +0530)
committerLinus Walleij <linus.walleij@linaro.org>
Wed, 11 Sep 2019 09:33:48 +0000 (10:33 +0100)
Fix drive strength for AON/CRMU controller; fix pull-up/down setting
for CCM/CDRU controller.

Fixes: 616043d58a89 ("pinctrl: Rename gpio driver from cygnus to iproc")
Signed-off-by: Li Jin <li.jin@broadcom.com>
Link: https://lore.kernel.org/r/1567054348-19685-2-git-send-email-srinath.mannam@broadcom.com
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
drivers/pinctrl/bcm/pinctrl-iproc-gpio.c

index a6edeb9..7c2f91c 100644 (file)
 /* drive strength control for ASIU GPIO */
 #define IPROC_GPIO_ASIU_DRV0_CTRL_OFFSET 0x58
 
-/* drive strength control for CCM/CRMU (AON) GPIO */
-#define IPROC_GPIO_DRV0_CTRL_OFFSET  0x00
+/* pinconf for CCM GPIO */
+#define IPROC_GPIO_PULL_DN_OFFSET   0x10
+#define IPROC_GPIO_PULL_UP_OFFSET   0x14
+
+/* pinconf for CRMU(aon) GPIO and CCM GPIO*/
+#define IPROC_GPIO_DRV_CTRL_OFFSET  0x00
 
 #define GPIO_BANK_SIZE 0x200
 #define NGPIOS_PER_BANK 32
@@ -76,6 +80,12 @@ enum iproc_pinconf_param {
        IPROC_PINCON_MAX,
 };
 
+enum iproc_pinconf_ctrl_type {
+       IOCTRL_TYPE_AON = 1,
+       IOCTRL_TYPE_CDRU,
+       IOCTRL_TYPE_INVALID,
+};
+
 /*
  * Iproc GPIO core
  *
@@ -100,6 +110,7 @@ struct iproc_gpio {
 
        void __iomem *base;
        void __iomem *io_ctrl;
+       enum iproc_pinconf_ctrl_type io_ctrl_type;
 
        raw_spinlock_t lock;
 
@@ -461,20 +472,44 @@ static const struct pinctrl_ops iproc_pctrl_ops = {
 static int iproc_gpio_set_pull(struct iproc_gpio *chip, unsigned gpio,
                                bool disable, bool pull_up)
 {
+       void __iomem *base;
        unsigned long flags;
+       unsigned int shift;
+       u32 val_1, val_2;
 
        raw_spin_lock_irqsave(&chip->lock, flags);
-
-       if (disable) {
-               iproc_set_bit(chip, IPROC_GPIO_RES_EN_OFFSET, gpio, false);
+       if (chip->io_ctrl_type == IOCTRL_TYPE_CDRU) {
+               base = chip->io_ctrl;
+               shift = IPROC_GPIO_SHIFT(gpio);
+
+               val_1 = readl(base + IPROC_GPIO_PULL_UP_OFFSET);
+               val_2 = readl(base + IPROC_GPIO_PULL_DN_OFFSET);
+               if (disable) {
+                       /* no pull-up or pull-down */
+                       val_1 &= ~BIT(shift);
+                       val_2 &= ~BIT(shift);
+               } else if (pull_up) {
+                       val_1 |= BIT(shift);
+                       val_2 &= ~BIT(shift);
+               } else {
+                       val_1 &= ~BIT(shift);
+                       val_2 |= BIT(shift);
+               }
+               writel(val_1, base + IPROC_GPIO_PULL_UP_OFFSET);
+               writel(val_2, base + IPROC_GPIO_PULL_DN_OFFSET);
        } else {
-               iproc_set_bit(chip, IPROC_GPIO_PAD_RES_OFFSET, gpio,
-                              pull_up);
-               iproc_set_bit(chip, IPROC_GPIO_RES_EN_OFFSET, gpio, true);
+               if (disable) {
+                       iproc_set_bit(chip, IPROC_GPIO_RES_EN_OFFSET, gpio,
+                                     false);
+               } else {
+                       iproc_set_bit(chip, IPROC_GPIO_PAD_RES_OFFSET, gpio,
+                                     pull_up);
+                       iproc_set_bit(chip, IPROC_GPIO_RES_EN_OFFSET, gpio,
+                                     true);
+               }
        }
 
        raw_spin_unlock_irqrestore(&chip->lock, flags);
-
        dev_dbg(chip->dev, "gpio:%u set pullup:%d\n", gpio, pull_up);
 
        return 0;
@@ -483,14 +518,35 @@ static int iproc_gpio_set_pull(struct iproc_gpio *chip, unsigned gpio,
 static void iproc_gpio_get_pull(struct iproc_gpio *chip, unsigned gpio,
                                 bool *disable, bool *pull_up)
 {
+       void __iomem *base;
        unsigned long flags;
+       unsigned int shift;
+       u32 val_1, val_2;
 
        raw_spin_lock_irqsave(&chip->lock, flags);
-       *disable = !iproc_get_bit(chip, IPROC_GPIO_RES_EN_OFFSET, gpio);
-       *pull_up = iproc_get_bit(chip, IPROC_GPIO_PAD_RES_OFFSET, gpio);
+       if (chip->io_ctrl_type == IOCTRL_TYPE_CDRU) {
+               base = chip->io_ctrl;
+               shift = IPROC_GPIO_SHIFT(gpio);
+
+               val_1 = readl(base + IPROC_GPIO_PULL_UP_OFFSET) & BIT(shift);
+               val_2 = readl(base + IPROC_GPIO_PULL_DN_OFFSET) & BIT(shift);
+
+               *pull_up = val_1 ? true : false;
+               *disable = (val_1 | val_2) ? false : true;
+
+       } else {
+               *disable = !iproc_get_bit(chip, IPROC_GPIO_RES_EN_OFFSET, gpio);
+               *pull_up = iproc_get_bit(chip, IPROC_GPIO_PAD_RES_OFFSET, gpio);
+       }
        raw_spin_unlock_irqrestore(&chip->lock, flags);
 }
 
+#define DRV_STRENGTH_OFFSET(gpio, bit, type)  ((type) == IOCTRL_TYPE_AON ? \
+       ((2 - (bit)) * 4 + IPROC_GPIO_DRV_CTRL_OFFSET) : \
+       ((type) == IOCTRL_TYPE_CDRU) ? \
+       ((bit) * 4 + IPROC_GPIO_DRV_CTRL_OFFSET) : \
+       ((bit) * 4 + IPROC_GPIO_REG(gpio, IPROC_GPIO_ASIU_DRV0_CTRL_OFFSET)))
+
 static int iproc_gpio_set_strength(struct iproc_gpio *chip, unsigned gpio,
                                    unsigned strength)
 {
@@ -505,11 +561,8 @@ static int iproc_gpio_set_strength(struct iproc_gpio *chip, unsigned gpio,
 
        if (chip->io_ctrl) {
                base = chip->io_ctrl;
-               offset = IPROC_GPIO_DRV0_CTRL_OFFSET;
        } else {
                base = chip->base;
-               offset = IPROC_GPIO_REG(gpio,
-                                        IPROC_GPIO_ASIU_DRV0_CTRL_OFFSET);
        }
 
        shift = IPROC_GPIO_SHIFT(gpio);
@@ -520,11 +573,11 @@ static int iproc_gpio_set_strength(struct iproc_gpio *chip, unsigned gpio,
        raw_spin_lock_irqsave(&chip->lock, flags);
        strength = (strength / 2) - 1;
        for (i = 0; i < GPIO_DRV_STRENGTH_BITS; i++) {
+               offset = DRV_STRENGTH_OFFSET(gpio, i, chip->io_ctrl_type);
                val = readl(base + offset);
                val &= ~BIT(shift);
                val |= ((strength >> i) & 0x1) << shift;
                writel(val, base + offset);
-               offset += 4;
        }
        raw_spin_unlock_irqrestore(&chip->lock, flags);
 
@@ -541,11 +594,8 @@ static int iproc_gpio_get_strength(struct iproc_gpio *chip, unsigned gpio,
 
        if (chip->io_ctrl) {
                base = chip->io_ctrl;
-               offset = IPROC_GPIO_DRV0_CTRL_OFFSET;
        } else {
                base = chip->base;
-               offset = IPROC_GPIO_REG(gpio,
-                                        IPROC_GPIO_ASIU_DRV0_CTRL_OFFSET);
        }
 
        shift = IPROC_GPIO_SHIFT(gpio);
@@ -553,10 +603,10 @@ static int iproc_gpio_get_strength(struct iproc_gpio *chip, unsigned gpio,
        raw_spin_lock_irqsave(&chip->lock, flags);
        *strength = 0;
        for (i = 0; i < GPIO_DRV_STRENGTH_BITS; i++) {
+               offset = DRV_STRENGTH_OFFSET(gpio, i, chip->io_ctrl_type);
                val = readl(base + offset) & BIT(shift);
                val >>= shift;
                *strength += (val << i);
-               offset += 4;
        }
 
        /* convert to mA */
@@ -734,6 +784,7 @@ static int iproc_gpio_probe(struct platform_device *pdev)
        u32 ngpios, pinconf_disable_mask = 0;
        int irq, ret;
        bool no_pinconf = false;
+       enum iproc_pinconf_ctrl_type io_ctrl_type = IOCTRL_TYPE_INVALID;
 
        /* NSP does not support drive strength config */
        if (of_device_is_compatible(dev->of_node, "brcm,iproc-nsp-gpio"))
@@ -764,8 +815,15 @@ static int iproc_gpio_probe(struct platform_device *pdev)
                        dev_err(dev, "unable to map I/O memory\n");
                        return PTR_ERR(chip->io_ctrl);
                }
+               if (of_device_is_compatible(dev->of_node,
+                                           "brcm,cygnus-ccm-gpio"))
+                       io_ctrl_type = IOCTRL_TYPE_CDRU;
+               else
+                       io_ctrl_type = IOCTRL_TYPE_AON;
        }
 
+       chip->io_ctrl_type = io_ctrl_type;
+
        if (of_property_read_u32(dev->of_node, "ngpios", &ngpios)) {
                dev_err(&pdev->dev, "missing ngpios DT property\n");
                return -ENODEV;