]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/pinctrl/pinctrl-rockchip.c
pinctrl: aspeed: Add core pinconf support
[karo-tx-linux.git] / drivers / pinctrl / pinctrl-rockchip.c
index 7813599e43fac80634061b00d0dbb32f5ea829f6..f141aa0430b15159111868ad96abd4c658e88ca0 100644 (file)
@@ -59,7 +59,7 @@
 #define GPIO_LS_SYNC           0x60
 
 enum rockchip_pinctrl_type {
-       RK1108,
+       RV1108,
        RK2928,
        RK3066B,
        RK3188,
@@ -75,6 +75,8 @@ enum rockchip_pinctrl_type {
 #define IOMUX_WIDTH_4BIT       BIT(1)
 #define IOMUX_SOURCE_PMU       BIT(2)
 #define IOMUX_UNROUTED         BIT(3)
+#define IOMUX_WIDTH_3BIT       BIT(4)
+#define IOMUX_RECALCED         BIT(5)
 
 /**
  * @type: iomux variant using IOMUX_* constants
@@ -141,6 +143,9 @@ struct rockchip_drv {
  * @gpio_chip: gpiolib chip
  * @grange: gpio range
  * @slock: spinlock for the gpio bank
+ * @irq_lock: bus lock for irq chip
+ * @new_irqs: newly configured irqs which must be muxed as GPIOs in
+ *     irq_bus_sync_unlock()
  */
 struct rockchip_pin_bank {
        void __iomem                    *reg_base;
@@ -161,8 +166,10 @@ struct rockchip_pin_bank {
        struct irq_domain               *domain;
        struct gpio_chip                gpio_chip;
        struct pinctrl_gpio_range       grange;
-       spinlock_t                      slock;
+       raw_spinlock_t                  slock;
        u32                             toggle_edge_mode;
+       struct mutex                    irq_lock;
+       u32                             new_irqs;
 };
 
 #define PIN_BANK(id, pins, label)                      \
@@ -304,6 +311,11 @@ struct rockchip_pin_ctrl {
        void    (*drv_calc_reg)(struct rockchip_pin_bank *bank,
                                    int pin_num, struct regmap **regmap,
                                    int *reg, u8 *bit);
+       void    (*iomux_recalc)(u8 bank_num, int pin, int *reg,
+                               u8 *bit, int *mask);
+       int     (*schmitt_calc_reg)(struct rockchip_pin_bank *bank,
+                                   int pin_num, struct regmap **regmap,
+                                   int *reg, u8 *bit);
 };
 
 struct rockchip_pin_config {
@@ -355,6 +367,22 @@ struct rockchip_pinctrl {
        unsigned int                    nfunctions;
 };
 
+/**
+ * struct rockchip_mux_recalced_data: represent a pin iomux data.
+ * @num: bank number.
+ * @pin: pin number.
+ * @bit: index at register.
+ * @reg: register offset.
+ * @mask: mask bit
+ */
+struct rockchip_mux_recalced_data {
+       u8 num;
+       u8 pin;
+       u8 reg;
+       u8 bit;
+       u8 mask;
+};
+
 static struct regmap_config rockchip_regmap_config = {
        .reg_bits = 32,
        .val_bits = 32,
@@ -514,13 +542,57 @@ static const struct pinctrl_ops rockchip_pctrl_ops = {
  * Hardware access
  */
 
+static const struct rockchip_mux_recalced_data rk3328_mux_recalced_data[] = {
+       {
+               .num = 2,
+               .pin = 12,
+               .reg = 0x24,
+               .bit = 8,
+               .mask = 0x3
+       }, {
+               .num = 2,
+               .pin = 15,
+               .reg = 0x28,
+               .bit = 0,
+               .mask = 0x7
+       }, {
+               .num = 2,
+               .pin = 23,
+               .reg = 0x30,
+               .bit = 14,
+               .mask = 0x3
+       },
+};
+
+static void rk3328_recalc_mux(u8 bank_num, int pin, int *reg,
+                             u8 *bit, int *mask)
+{
+       const struct rockchip_mux_recalced_data *data = NULL;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(rk3328_mux_recalced_data); i++)
+               if (rk3328_mux_recalced_data[i].num == bank_num &&
+                   rk3328_mux_recalced_data[i].pin == pin) {
+                       data = &rk3328_mux_recalced_data[i];
+                       break;
+               }
+
+       if (!data)
+               return;
+
+       *reg = data->reg;
+       *mask = data->mask;
+       *bit = data->bit;
+}
+
 static int rockchip_get_mux(struct rockchip_pin_bank *bank, int pin)
 {
        struct rockchip_pinctrl *info = bank->drvdata;
+       struct rockchip_pin_ctrl *ctrl = info->ctrl;
        int iomux_num = (pin / 8);
        struct regmap *regmap;
        unsigned int val;
-       int reg, ret, mask;
+       int reg, ret, mask, mux_type;
        u8 bit;
 
        if (iomux_num > 3)
@@ -538,16 +610,26 @@ static int rockchip_get_mux(struct rockchip_pin_bank *bank, int pin)
                                ? info->regmap_pmu : info->regmap_base;
 
        /* get basic quadrupel of mux registers and the correct reg inside */
-       mask = (bank->iomux[iomux_num].type & IOMUX_WIDTH_4BIT) ? 0xf : 0x3;
+       mux_type = bank->iomux[iomux_num].type;
        reg = bank->iomux[iomux_num].offset;
-       if (bank->iomux[iomux_num].type & IOMUX_WIDTH_4BIT) {
+       if (mux_type & IOMUX_WIDTH_4BIT) {
                if ((pin % 8) >= 4)
                        reg += 0x4;
                bit = (pin % 4) * 4;
+               mask = 0xf;
+       } else if (mux_type & IOMUX_WIDTH_3BIT) {
+               if ((pin % 8) >= 5)
+                       reg += 0x4;
+               bit = (pin % 8 % 5) * 3;
+               mask = 0x7;
        } else {
                bit = (pin % 8) * 2;
+               mask = 0x3;
        }
 
+       if (ctrl->iomux_recalc && (mux_type & IOMUX_RECALCED))
+               ctrl->iomux_recalc(bank->bank_num, pin, &reg, &bit, &mask);
+
        ret = regmap_read(regmap, reg, &val);
        if (ret)
                return ret;
@@ -555,6 +637,31 @@ static int rockchip_get_mux(struct rockchip_pin_bank *bank, int pin)
        return ((val >> bit) & mask);
 }
 
+static int rockchip_verify_mux(struct rockchip_pin_bank *bank,
+                              int pin, int mux)
+{
+       struct rockchip_pinctrl *info = bank->drvdata;
+       int iomux_num = (pin / 8);
+
+       if (iomux_num > 3)
+               return -EINVAL;
+
+       if (bank->iomux[iomux_num].type & IOMUX_UNROUTED) {
+               dev_err(info->dev, "pin %d is unrouted\n", pin);
+               return -EINVAL;
+       }
+
+       if (bank->iomux[iomux_num].type & IOMUX_GPIO_ONLY) {
+               if (mux != RK_FUNC_GPIO) {
+                       dev_err(info->dev,
+                               "pin %d only supports a gpio mux\n", pin);
+                       return -ENOTSUPP;
+               }
+       }
+
+       return 0;
+}
+
 /*
  * Set a new mux function for a pin.
  *
@@ -571,30 +678,19 @@ static int rockchip_get_mux(struct rockchip_pin_bank *bank, int pin)
 static int rockchip_set_mux(struct rockchip_pin_bank *bank, int pin, int mux)
 {
        struct rockchip_pinctrl *info = bank->drvdata;
+       struct rockchip_pin_ctrl *ctrl = info->ctrl;
        int iomux_num = (pin / 8);
        struct regmap *regmap;
-       int reg, ret, mask;
-       unsigned long flags;
+       int reg, ret, mask, mux_type;
        u8 bit;
        u32 data, rmask;
 
-       if (iomux_num > 3)
-               return -EINVAL;
-
-       if (bank->iomux[iomux_num].type & IOMUX_UNROUTED) {
-               dev_err(info->dev, "pin %d is unrouted\n", pin);
-               return -EINVAL;
-       }
+       ret = rockchip_verify_mux(bank, pin, mux);
+       if (ret < 0)
+               return ret;
 
-       if (bank->iomux[iomux_num].type & IOMUX_GPIO_ONLY) {
-               if (mux != RK_FUNC_GPIO) {
-                       dev_err(info->dev,
-                               "pin %d only supports a gpio mux\n", pin);
-                       return -ENOTSUPP;
-               } else {
-                       return 0;
-               }
-       }
+       if (bank->iomux[iomux_num].type & IOMUX_GPIO_ONLY)
+               return 0;
 
        dev_dbg(info->dev, "setting mux of GPIO%d-%d to %d\n",
                                                bank->bank_num, pin, mux);
@@ -603,35 +699,41 @@ static int rockchip_set_mux(struct rockchip_pin_bank *bank, int pin, int mux)
                                ? info->regmap_pmu : info->regmap_base;
 
        /* get basic quadrupel of mux registers and the correct reg inside */
-       mask = (bank->iomux[iomux_num].type & IOMUX_WIDTH_4BIT) ? 0xf : 0x3;
+       mux_type = bank->iomux[iomux_num].type;
        reg = bank->iomux[iomux_num].offset;
-       if (bank->iomux[iomux_num].type & IOMUX_WIDTH_4BIT) {
+       if (mux_type & IOMUX_WIDTH_4BIT) {
                if ((pin % 8) >= 4)
                        reg += 0x4;
                bit = (pin % 4) * 4;
+               mask = 0xf;
+       } else if (mux_type & IOMUX_WIDTH_3BIT) {
+               if ((pin % 8) >= 5)
+                       reg += 0x4;
+               bit = (pin % 8 % 5) * 3;
+               mask = 0x7;
        } else {
                bit = (pin % 8) * 2;
+               mask = 0x3;
        }
 
-       spin_lock_irqsave(&bank->slock, flags);
+       if (ctrl->iomux_recalc && (mux_type & IOMUX_RECALCED))
+               ctrl->iomux_recalc(bank->bank_num, pin, &reg, &bit, &mask);
 
        data = (mask << (bit + 16));
        rmask = data | (data >> 16);
        data |= (mux & mask) << bit;
        ret = regmap_update_bits(regmap, reg, rmask, data);
 
-       spin_unlock_irqrestore(&bank->slock, flags);
-
        return ret;
 }
 
-#define RK1108_PULL_PMU_OFFSET         0x10
-#define RK1108_PULL_OFFSET             0x110
-#define RK1108_PULL_PINS_PER_REG       8
-#define RK1108_PULL_BITS_PER_PIN       2
-#define RK1108_PULL_BANK_STRIDE                16
+#define RV1108_PULL_PMU_OFFSET         0x10
+#define RV1108_PULL_OFFSET             0x110
+#define RV1108_PULL_PINS_PER_REG       8
+#define RV1108_PULL_BITS_PER_PIN       2
+#define RV1108_PULL_BANK_STRIDE                16
 
-static void rk1108_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
+static void rv1108_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
                                         int pin_num, struct regmap **regmap,
                                         int *reg, u8 *bit)
 {
@@ -640,27 +742,27 @@ static void rk1108_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
        /* The first 24 pins of the first bank are located in PMU */
        if (bank->bank_num == 0) {
                *regmap = info->regmap_pmu;
-               *reg = RK1108_PULL_PMU_OFFSET;
+               *reg = RV1108_PULL_PMU_OFFSET;
        } else {
-               *reg = RK1108_PULL_OFFSET;
+               *reg = RV1108_PULL_OFFSET;
                *regmap = info->regmap_base;
                /* correct the offset, as we're starting with the 2nd bank */
                *reg -= 0x10;
-               *reg += bank->bank_num * RK1108_PULL_BANK_STRIDE;
+               *reg += bank->bank_num * RV1108_PULL_BANK_STRIDE;
        }
 
-       *reg += ((pin_num / RK1108_PULL_PINS_PER_REG) * 4);
-       *bit = (pin_num % RK1108_PULL_PINS_PER_REG);
-       *bit *= RK1108_PULL_BITS_PER_PIN;
+       *reg += ((pin_num / RV1108_PULL_PINS_PER_REG) * 4);
+       *bit = (pin_num % RV1108_PULL_PINS_PER_REG);
+       *bit *= RV1108_PULL_BITS_PER_PIN;
 }
 
-#define RK1108_DRV_PMU_OFFSET          0x20
-#define RK1108_DRV_GRF_OFFSET          0x210
-#define RK1108_DRV_BITS_PER_PIN                2
-#define RK1108_DRV_PINS_PER_REG                8
-#define RK1108_DRV_BANK_STRIDE         16
+#define RV1108_DRV_PMU_OFFSET          0x20
+#define RV1108_DRV_GRF_OFFSET          0x210
+#define RV1108_DRV_BITS_PER_PIN                2
+#define RV1108_DRV_PINS_PER_REG                8
+#define RV1108_DRV_BANK_STRIDE         16
 
-static void rk1108_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank,
+static void rv1108_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank,
                                        int pin_num, struct regmap **regmap,
                                        int *reg, u8 *bit)
 {
@@ -669,19 +771,19 @@ static void rk1108_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank,
        /* The first 24 pins of the first bank are located in PMU */
        if (bank->bank_num == 0) {
                *regmap = info->regmap_pmu;
-               *reg = RK1108_DRV_PMU_OFFSET;
+               *reg = RV1108_DRV_PMU_OFFSET;
        } else {
                *regmap = info->regmap_base;
-               *reg = RK1108_DRV_GRF_OFFSET;
+               *reg = RV1108_DRV_GRF_OFFSET;
 
                /* correct the offset, as we're starting with the 2nd bank */
                *reg -= 0x10;
-               *reg += bank->bank_num * RK1108_DRV_BANK_STRIDE;
+               *reg += bank->bank_num * RV1108_DRV_BANK_STRIDE;
        }
 
-       *reg += ((pin_num / RK1108_DRV_PINS_PER_REG) * 4);
-       *bit = pin_num % RK1108_DRV_PINS_PER_REG;
-       *bit *= RK1108_DRV_BITS_PER_PIN;
+       *reg += ((pin_num / RV1108_DRV_PINS_PER_REG) * 4);
+       *bit = pin_num % RV1108_DRV_PINS_PER_REG;
+       *bit *= RV1108_DRV_BITS_PER_PIN;
 }
 
 #define RK2928_PULL_OFFSET             0x118
@@ -1047,7 +1149,6 @@ static int rockchip_set_drive_perpin(struct rockchip_pin_bank *bank,
        struct rockchip_pinctrl *info = bank->drvdata;
        struct rockchip_pin_ctrl *ctrl = info->ctrl;
        struct regmap *regmap;
-       unsigned long flags;
        int reg, ret, i;
        u32 data, rmask, rmask_bits, temp;
        u8 bit;
@@ -1075,8 +1176,6 @@ static int rockchip_set_drive_perpin(struct rockchip_pin_bank *bank,
                return ret;
        }
 
-       spin_lock_irqsave(&bank->slock, flags);
-
        switch (drv_type) {
        case DRV_TYPE_IO_1V8_3V0_AUTO:
        case DRV_TYPE_IO_3V3_ONLY:
@@ -1097,17 +1196,14 @@ static int rockchip_set_drive_perpin(struct rockchip_pin_bank *bank,
                        rmask = BIT(15) | BIT(31);
                        data |= BIT(31);
                        ret = regmap_update_bits(regmap, reg, rmask, data);
-                       if (ret) {
-                               spin_unlock_irqrestore(&bank->slock, flags);
+                       if (ret)
                                return ret;
-                       }
 
                        rmask = 0x3 | (0x3 << 16);
                        temp |= (0x3 << 16);
                        reg += 0x4;
                        ret = regmap_update_bits(regmap, reg, rmask, temp);
 
-                       spin_unlock_irqrestore(&bank->slock, flags);
                        return ret;
                case 18 ... 21:
                        /* setting fully enclosed in the second register */
@@ -1115,7 +1211,6 @@ static int rockchip_set_drive_perpin(struct rockchip_pin_bank *bank,
                        bit -= 16;
                        break;
                default:
-                       spin_unlock_irqrestore(&bank->slock, flags);
                        dev_err(info->dev, "unsupported bit: %d for pinctrl drive type: %d\n",
                                bit, drv_type);
                        return -EINVAL;
@@ -1127,7 +1222,6 @@ static int rockchip_set_drive_perpin(struct rockchip_pin_bank *bank,
                rmask_bits = RK3288_DRV_BITS_PER_PIN;
                break;
        default:
-               spin_unlock_irqrestore(&bank->slock, flags);
                dev_err(info->dev, "unsupported pinctrl drive type: %d\n",
                        drv_type);
                return -EINVAL;
@@ -1139,7 +1233,6 @@ static int rockchip_set_drive_perpin(struct rockchip_pin_bank *bank,
        data |= (ret << bit);
 
        ret = regmap_update_bits(regmap, reg, rmask, data);
-       spin_unlock_irqrestore(&bank->slock, flags);
 
        return ret;
 }
@@ -1183,7 +1276,7 @@ static int rockchip_get_pull(struct rockchip_pin_bank *bank, int pin_num)
                return !(data & BIT(bit))
                                ? PIN_CONFIG_BIAS_PULL_PIN_DEFAULT
                                : PIN_CONFIG_BIAS_DISABLE;
-       case RK1108:
+       case RV1108:
        case RK3188:
        case RK3288:
        case RK3368:
@@ -1206,7 +1299,6 @@ static int rockchip_set_pull(struct rockchip_pin_bank *bank,
        struct rockchip_pin_ctrl *ctrl = info->ctrl;
        struct regmap *regmap;
        int reg, ret, i, pull_type;
-       unsigned long flags;
        u8 bit;
        u32 data, rmask;
 
@@ -1221,16 +1313,12 @@ static int rockchip_set_pull(struct rockchip_pin_bank *bank,
 
        switch (ctrl->type) {
        case RK2928:
-               spin_lock_irqsave(&bank->slock, flags);
-
                data = BIT(bit + 16);
                if (pull == PIN_CONFIG_BIAS_DISABLE)
                        data |= BIT(bit);
                ret = regmap_write(regmap, reg, data);
-
-               spin_unlock_irqrestore(&bank->slock, flags);
                break;
-       case RK1108:
+       case RV1108:
        case RK3188:
        case RK3288:
        case RK3368:
@@ -1251,16 +1339,12 @@ static int rockchip_set_pull(struct rockchip_pin_bank *bank,
                        return ret;
                }
 
-               spin_lock_irqsave(&bank->slock, flags);
-
                /* enable the write to the equivalent lower bits */
                data = ((1 << RK3188_PULL_BITS_PER_PIN) - 1) << (bit + 16);
                rmask = data | (data >> 16);
                data |= (ret << bit);
 
                ret = regmap_update_bits(regmap, reg, rmask, data);
-
-               spin_unlock_irqrestore(&bank->slock, flags);
                break;
        default:
                dev_err(info->dev, "unsupported pinctrl type\n");
@@ -1270,6 +1354,73 @@ static int rockchip_set_pull(struct rockchip_pin_bank *bank,
        return ret;
 }
 
+#define RK3328_SCHMITT_BITS_PER_PIN            1
+#define RK3328_SCHMITT_PINS_PER_REG            16
+#define RK3328_SCHMITT_BANK_STRIDE             8
+#define RK3328_SCHMITT_GRF_OFFSET              0x380
+
+static int rk3328_calc_schmitt_reg_and_bit(struct rockchip_pin_bank *bank,
+                                          int pin_num,
+                                          struct regmap **regmap,
+                                          int *reg, u8 *bit)
+{
+       struct rockchip_pinctrl *info = bank->drvdata;
+
+       *regmap = info->regmap_base;
+       *reg = RK3328_SCHMITT_GRF_OFFSET;
+
+       *reg += bank->bank_num * RK3328_SCHMITT_BANK_STRIDE;
+       *reg += ((pin_num / RK3328_SCHMITT_PINS_PER_REG) * 4);
+       *bit = pin_num % RK3328_SCHMITT_PINS_PER_REG;
+
+       return 0;
+}
+
+static int rockchip_get_schmitt(struct rockchip_pin_bank *bank, int pin_num)
+{
+       struct rockchip_pinctrl *info = bank->drvdata;
+       struct rockchip_pin_ctrl *ctrl = info->ctrl;
+       struct regmap *regmap;
+       int reg, ret;
+       u8 bit;
+       u32 data;
+
+       ret = ctrl->schmitt_calc_reg(bank, pin_num, &regmap, &reg, &bit);
+       if (ret)
+               return ret;
+
+       ret = regmap_read(regmap, reg, &data);
+       if (ret)
+               return ret;
+
+       data >>= bit;
+       return data & 0x1;
+}
+
+static int rockchip_set_schmitt(struct rockchip_pin_bank *bank,
+                               int pin_num, int enable)
+{
+       struct rockchip_pinctrl *info = bank->drvdata;
+       struct rockchip_pin_ctrl *ctrl = info->ctrl;
+       struct regmap *regmap;
+       int reg, ret;
+       u8 bit;
+       u32 data, rmask;
+
+       dev_dbg(info->dev, "setting input schmitt of GPIO%d-%d to %d\n",
+               bank->bank_num, pin_num, enable);
+
+       ret = ctrl->schmitt_calc_reg(bank, pin_num, &regmap, &reg, &bit);
+       if (ret)
+               return ret;
+
+       /* enable the write to the equivalent lower bits */
+       data = BIT(bit + 16) | (enable << bit);
+       rmask = BIT(bit + 16) | BIT(bit);
+
+       return regmap_update_bits(regmap, reg, rmask, data);
+}
+
 /*
  * Pinmux_ops handling
  */
@@ -1366,7 +1517,7 @@ static int _rockchip_pmx_gpio_set_direction(struct gpio_chip *chip,
                return ret;
 
        clk_enable(bank->clk);
-       spin_lock_irqsave(&bank->slock, flags);
+       raw_spin_lock_irqsave(&bank->slock, flags);
 
        data = readl_relaxed(bank->reg_base + GPIO_SWPORT_DDR);
        /* set bit to 1 for output, 0 for input */
@@ -1376,7 +1527,7 @@ static int _rockchip_pmx_gpio_set_direction(struct gpio_chip *chip,
                data &= ~BIT(pin);
        writel_relaxed(data, bank->reg_base + GPIO_SWPORT_DDR);
 
-       spin_unlock_irqrestore(&bank->slock, flags);
+       raw_spin_unlock_irqrestore(&bank->slock, flags);
        clk_disable(bank->clk);
 
        return 0;
@@ -1420,7 +1571,7 @@ static bool rockchip_pinconf_pull_valid(struct rockchip_pin_ctrl *ctrl,
                                        pull == PIN_CONFIG_BIAS_DISABLE);
        case RK3066B:
                return pull ? false : true;
-       case RK1108:
+       case RV1108:
        case RK3188:
        case RK3288:
        case RK3368:
@@ -1489,6 +1640,15 @@ static int rockchip_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
                        if (rc < 0)
                                return rc;
                        break;
+               case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+                       if (!info->ctrl->schmitt_calc_reg)
+                               return -ENOTSUPP;
+
+                       rc = rockchip_set_schmitt(bank,
+                                                 pin - bank->pin_base, arg);
+                       if (rc < 0)
+                               return rc;
+                       break;
                default:
                        return -ENOTSUPP;
                        break;
@@ -1547,6 +1707,16 @@ static int rockchip_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin,
                if (rc < 0)
                        return rc;
 
+               arg = rc;
+               break;
+       case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+               if (!info->ctrl->schmitt_calc_reg)
+                       return -ENOTSUPP;
+
+               rc = rockchip_get_schmitt(bank, pin - bank->pin_base);
+               if (rc < 0)
+                       return rc;
+
                arg = rc;
                break;
        default:
@@ -1807,7 +1977,7 @@ static void rockchip_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
        u32 data;
 
        clk_enable(bank->clk);
-       spin_lock_irqsave(&bank->slock, flags);
+       raw_spin_lock_irqsave(&bank->slock, flags);
 
        data = readl(reg);
        data &= ~BIT(offset);
@@ -1815,7 +1985,7 @@ static void rockchip_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
                data |= BIT(offset);
        writel(data, reg);
 
-       spin_unlock_irqrestore(&bank->slock, flags);
+       raw_spin_unlock_irqrestore(&bank->slock, flags);
        clk_disable(bank->clk);
 }
 
@@ -1927,7 +2097,7 @@ static void rockchip_irq_demux(struct irq_desc *desc)
 
                        data = readl_relaxed(bank->reg_base + GPIO_EXT_PORT);
                        do {
-                               spin_lock_irqsave(&bank->slock, flags);
+                               raw_spin_lock_irqsave(&bank->slock, flags);
 
                                polarity = readl_relaxed(bank->reg_base +
                                                         GPIO_INT_POLARITY);
@@ -1938,7 +2108,7 @@ static void rockchip_irq_demux(struct irq_desc *desc)
                                writel(polarity,
                                       bank->reg_base + GPIO_INT_POLARITY);
 
-                               spin_unlock_irqrestore(&bank->slock, flags);
+                               raw_spin_unlock_irqrestore(&bank->slock, flags);
 
                                data_old = data;
                                data = readl_relaxed(bank->reg_base +
@@ -1964,25 +2134,26 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type)
        int ret;
 
        /* make sure the pin is configured as gpio input */
-       ret = rockchip_set_mux(bank, d->hwirq, RK_FUNC_GPIO);
+       ret = rockchip_verify_mux(bank, d->hwirq, RK_FUNC_GPIO);
        if (ret < 0)
                return ret;
 
-       clk_enable(bank->clk);
-       spin_lock_irqsave(&bank->slock, flags);
+       bank->new_irqs |= mask;
+
+       raw_spin_lock_irqsave(&bank->slock, flags);
 
        data = readl_relaxed(bank->reg_base + GPIO_SWPORT_DDR);
        data &= ~mask;
        writel_relaxed(data, bank->reg_base + GPIO_SWPORT_DDR);
 
-       spin_unlock_irqrestore(&bank->slock, flags);
+       raw_spin_unlock_irqrestore(&bank->slock, flags);
 
        if (type & IRQ_TYPE_EDGE_BOTH)
                irq_set_handler_locked(d, handle_edge_irq);
        else
                irq_set_handler_locked(d, handle_level_irq);
 
-       spin_lock_irqsave(&bank->slock, flags);
+       raw_spin_lock_irqsave(&bank->slock, flags);
        irq_gc_lock(gc);
 
        level = readl_relaxed(gc->reg_base + GPIO_INTTYPE_LEVEL);
@@ -2025,8 +2196,7 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type)
                break;
        default:
                irq_gc_unlock(gc);
-               spin_unlock_irqrestore(&bank->slock, flags);
-               clk_disable(bank->clk);
+               raw_spin_unlock_irqrestore(&bank->slock, flags);
                return -EINVAL;
        }
 
@@ -2034,8 +2204,7 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type)
        writel_relaxed(polarity, gc->reg_base + GPIO_INT_POLARITY);
 
        irq_gc_unlock(gc);
-       spin_unlock_irqrestore(&bank->slock, flags);
-       clk_disable(bank->clk);
+       raw_spin_unlock_irqrestore(&bank->slock, flags);
 
        return 0;
 }
@@ -2061,7 +2230,7 @@ static void rockchip_irq_resume(struct irq_data *d)
        clk_disable(bank->clk);
 }
 
-static void rockchip_irq_gc_mask_clr_bit(struct irq_data *d)
+static void rockchip_irq_enable(struct irq_data *d)
 {
        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
        struct rockchip_pin_bank *bank = gc->private;
@@ -2070,7 +2239,7 @@ static void rockchip_irq_gc_mask_clr_bit(struct irq_data *d)
        irq_gc_mask_clr_bit(d);
 }
 
-static void rockchip_irq_gc_mask_set_bit(struct irq_data *d)
+static void rockchip_irq_disable(struct irq_data *d)
 {
        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
        struct rockchip_pin_bank *bank = gc->private;
@@ -2079,6 +2248,34 @@ static void rockchip_irq_gc_mask_set_bit(struct irq_data *d)
        clk_disable(bank->clk);
 }
 
+static void rockchip_irq_bus_lock(struct irq_data *d)
+{
+       struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+       struct rockchip_pin_bank *bank = gc->private;
+
+       clk_enable(bank->clk);
+       mutex_lock(&bank->irq_lock);
+}
+
+static void rockchip_irq_bus_sync_unlock(struct irq_data *d)
+{
+       struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+       struct rockchip_pin_bank *bank = gc->private;
+
+       while (bank->new_irqs) {
+               unsigned int irq = __ffs(bank->new_irqs);
+               int ret;
+
+               ret = rockchip_set_mux(bank, irq, RK_FUNC_GPIO);
+               WARN_ON(ret < 0);
+
+               bank->new_irqs &= ~BIT(irq);
+       }
+
+       mutex_unlock(&bank->irq_lock);
+       clk_disable(bank->clk);
+}
+
 static int rockchip_interrupts_register(struct platform_device *pdev,
                                                struct rockchip_pinctrl *info)
 {
@@ -2137,13 +2334,17 @@ static int rockchip_interrupts_register(struct platform_device *pdev,
                gc->chip_types[0].regs.mask = GPIO_INTMASK;
                gc->chip_types[0].regs.ack = GPIO_PORTS_EOI;
                gc->chip_types[0].chip.irq_ack = irq_gc_ack_set_bit;
-               gc->chip_types[0].chip.irq_mask = rockchip_irq_gc_mask_set_bit;
-               gc->chip_types[0].chip.irq_unmask =
-                                                 rockchip_irq_gc_mask_clr_bit;
+               gc->chip_types[0].chip.irq_mask = irq_gc_mask_set_bit;
+               gc->chip_types[0].chip.irq_unmask = irq_gc_mask_clr_bit;
+               gc->chip_types[0].chip.irq_enable = rockchip_irq_enable;
+               gc->chip_types[0].chip.irq_disable = rockchip_irq_disable;
                gc->chip_types[0].chip.irq_set_wake = irq_gc_set_wake;
                gc->chip_types[0].chip.irq_suspend = rockchip_irq_suspend;
                gc->chip_types[0].chip.irq_resume = rockchip_irq_resume;
                gc->chip_types[0].chip.irq_set_type = rockchip_irq_set_type;
+               gc->chip_types[0].chip.irq_bus_lock = rockchip_irq_bus_lock;
+               gc->chip_types[0].chip.irq_bus_sync_unlock =
+                                               rockchip_irq_bus_sync_unlock;
                gc->wake_enabled = IRQ_MSK(bank->nr_pins);
 
                irq_set_chained_handler_and_data(bank->irq,
@@ -2316,7 +2517,8 @@ static struct rockchip_pin_ctrl *rockchip_pinctrl_get_soc_data(
        for (i = 0; i < ctrl->nr_banks; ++i, ++bank) {
                int bank_pins = 0;
 
-               spin_lock_init(&bank->slock);
+               raw_spin_lock_init(&bank->slock);
+               mutex_init(&bank->irq_lock);
                bank->drvdata = d;
                bank->pin_base = ctrl->nr_pins;
                ctrl->nr_pins += bank->nr_pins;
@@ -2359,7 +2561,8 @@ static struct rockchip_pin_ctrl *rockchip_pinctrl_get_soc_data(
                         * Increase offset according to iomux width.
                         * 4bit iomux'es are spread over two registers.
                         */
-                       inc = (iom->type & IOMUX_WIDTH_4BIT) ? 8 : 4;
+                       inc = (iom->type & (IOMUX_WIDTH_4BIT |
+                                           IOMUX_WIDTH_3BIT)) ? 8 : 4;
                        if (iom->type & IOMUX_SOURCE_PMU)
                                pmu_offs += inc;
                        else
@@ -2518,7 +2721,7 @@ static int rockchip_pinctrl_probe(struct platform_device *pdev)
        return 0;
 }
 
-static struct rockchip_pin_bank rk1108_pin_banks[] = {
+static struct rockchip_pin_bank rv1108_pin_banks[] = {
        PIN_BANK_IOMUX_FLAGS(0, 32, "gpio0", IOMUX_SOURCE_PMU,
                                             IOMUX_SOURCE_PMU,
                                             IOMUX_SOURCE_PMU,
@@ -2528,15 +2731,15 @@ static struct rockchip_pin_bank rk1108_pin_banks[] = {
        PIN_BANK_IOMUX_FLAGS(3, 32, "gpio3", 0, 0, 0, 0),
 };
 
-static struct rockchip_pin_ctrl rk1108_pin_ctrl = {
-       .pin_banks              = rk1108_pin_banks,
-       .nr_banks               = ARRAY_SIZE(rk1108_pin_banks),
-       .label                  = "RK1108-GPIO",
-       .type                   = RK1108,
+static struct rockchip_pin_ctrl rv1108_pin_ctrl = {
+       .pin_banks              = rv1108_pin_banks,
+       .nr_banks               = ARRAY_SIZE(rv1108_pin_banks),
+       .label                  = "RV1108-GPIO",
+       .type                   = RV1108,
        .grf_mux_offset         = 0x10,
        .pmu_mux_offset         = 0x0,
-       .pull_calc_reg          = rk1108_calc_pull_reg_and_bit,
-       .drv_calc_reg           = rk1108_calc_drv_reg_and_bit,
+       .pull_calc_reg          = rv1108_calc_pull_reg_and_bit,
+       .drv_calc_reg           = rv1108_calc_drv_reg_and_bit,
 };
 
 static struct rockchip_pin_bank rk2928_pin_banks[] = {
@@ -2679,6 +2882,32 @@ static struct rockchip_pin_ctrl rk3288_pin_ctrl = {
                .drv_calc_reg           = rk3288_calc_drv_reg_and_bit,
 };
 
+static struct rockchip_pin_bank rk3328_pin_banks[] = {
+       PIN_BANK_IOMUX_FLAGS(0, 32, "gpio0", 0, 0, 0, 0),
+       PIN_BANK_IOMUX_FLAGS(1, 32, "gpio1", 0, 0, 0, 0),
+       PIN_BANK_IOMUX_FLAGS(2, 32, "gpio2", 0,
+                            IOMUX_WIDTH_3BIT | IOMUX_RECALCED,
+                            IOMUX_WIDTH_3BIT | IOMUX_RECALCED,
+                            0),
+       PIN_BANK_IOMUX_FLAGS(3, 32, "gpio3",
+                            IOMUX_WIDTH_3BIT,
+                            IOMUX_WIDTH_3BIT | IOMUX_RECALCED,
+                            0,
+                            0),
+};
+
+static struct rockchip_pin_ctrl rk3328_pin_ctrl = {
+               .pin_banks              = rk3328_pin_banks,
+               .nr_banks               = ARRAY_SIZE(rk3328_pin_banks),
+               .label                  = "RK3328-GPIO",
+               .type                   = RK3288,
+               .grf_mux_offset         = 0x0,
+               .pull_calc_reg          = rk3228_calc_pull_reg_and_bit,
+               .drv_calc_reg           = rk3228_calc_drv_reg_and_bit,
+               .iomux_recalc           = rk3328_recalc_mux,
+               .schmitt_calc_reg       = rk3328_calc_schmitt_reg_and_bit,
+};
+
 static struct rockchip_pin_bank rk3368_pin_banks[] = {
        PIN_BANK_IOMUX_FLAGS(0, 32, "gpio0", IOMUX_SOURCE_PMU,
                                             IOMUX_SOURCE_PMU,
@@ -2768,8 +2997,8 @@ static struct rockchip_pin_ctrl rk3399_pin_ctrl = {
 };
 
 static const struct of_device_id rockchip_pinctrl_dt_match[] = {
-       { .compatible = "rockchip,rk1108-pinctrl",
-               .data = (void *)&rk1108_pin_ctrl },
+       { .compatible = "rockchip,rv1108-pinctrl",
+               .data = (void *)&rv1108_pin_ctrl },
        { .compatible = "rockchip,rk2928-pinctrl",
                .data = (void *)&rk2928_pin_ctrl },
        { .compatible = "rockchip,rk3036-pinctrl",
@@ -2784,6 +3013,8 @@ static const struct of_device_id rockchip_pinctrl_dt_match[] = {
                .data = (void *)&rk3228_pin_ctrl },
        { .compatible = "rockchip,rk3288-pinctrl",
                .data = (void *)&rk3288_pin_ctrl },
+       { .compatible = "rockchip,rk3328-pinctrl",
+               .data = (void *)&rk3328_pin_ctrl },
        { .compatible = "rockchip,rk3368-pinctrl",
                .data = (void *)&rk3368_pin_ctrl },
        { .compatible = "rockchip,rk3399-pinctrl",