static struct irq_chip sunxi_pinctrl_edge_irq_chip;
 static struct irq_chip sunxi_pinctrl_level_irq_chip;
 
+/*
+ * The sunXi PIO registers are organized as a series of banks, with registers
+ * for each bank in the following order:
+ *  - Mux config
+ *  - Data value
+ *  - Drive level
+ *  - Pull direction
+ *
+ * Multiple consecutive registers are used for fields wider than one bit.
+ *
+ * The following functions calculate the register and the bit offset to access.
+ * They take a pin number which is relative to the start of the current device.
+ */
+static void sunxi_mux_reg(u32 pin, u32 *reg, u32 *shift, u32 *mask)
+{
+       u32 bank   = pin / PINS_PER_BANK;
+       u32 offset = pin % PINS_PER_BANK * MUX_FIELD_WIDTH;
+
+       *reg   = bank * BANK_MEM_SIZE + MUX_REGS_OFFSET +
+                offset / BITS_PER_TYPE(u32) * sizeof(u32);
+       *shift = offset % BITS_PER_TYPE(u32);
+       *mask  = (BIT(MUX_FIELD_WIDTH) - 1) << *shift;
+}
+
+static void sunxi_data_reg(u32 pin, u32 *reg, u32 *shift, u32 *mask)
+{
+       u32 bank   = pin / PINS_PER_BANK;
+       u32 offset = pin % PINS_PER_BANK * DATA_FIELD_WIDTH;
+
+       *reg   = bank * BANK_MEM_SIZE + DATA_REGS_OFFSET +
+                offset / BITS_PER_TYPE(u32) * sizeof(u32);
+       *shift = offset % BITS_PER_TYPE(u32);
+       *mask  = (BIT(DATA_FIELD_WIDTH) - 1) << *shift;
+}
+
+static void sunxi_dlevel_reg(u32 pin, u32 *reg, u32 *shift, u32 *mask)
+{
+       u32 bank   = pin / PINS_PER_BANK;
+       u32 offset = pin % PINS_PER_BANK * DLEVEL_FIELD_WIDTH;
+
+       *reg   = bank * BANK_MEM_SIZE + DLEVEL_REGS_OFFSET +
+                offset / BITS_PER_TYPE(u32) * sizeof(u32);
+       *shift = offset % BITS_PER_TYPE(u32);
+       *mask  = (BIT(DLEVEL_FIELD_WIDTH) - 1) << *shift;
+}
+
+static void sunxi_pull_reg(u32 pin, u32 *reg, u32 *shift, u32 *mask)
+{
+       u32 bank   = pin / PINS_PER_BANK;
+       u32 offset = pin % PINS_PER_BANK * PULL_FIELD_WIDTH;
+
+       *reg   = bank * BANK_MEM_SIZE + PULL_REGS_OFFSET +
+                offset / BITS_PER_TYPE(u32) * sizeof(u32);
+       *shift = offset % BITS_PER_TYPE(u32);
+       *mask  = (BIT(PULL_FIELD_WIDTH) - 1) << *shift;
+}
+
 static struct sunxi_pinctrl_group *
 sunxi_pinctrl_find_group_by_name(struct sunxi_pinctrl *pctl, const char *group)
 {
 };
 
 static int sunxi_pconf_reg(unsigned pin, enum pin_config_param param,
-                          u32 *offset, u32 *shift, u32 *mask)
+                          u32 *reg, u32 *shift, u32 *mask)
 {
        switch (param) {
        case PIN_CONFIG_DRIVE_STRENGTH:
-               *offset = sunxi_dlevel_reg(pin);
-               *shift = sunxi_dlevel_offset(pin);
-               *mask = DLEVEL_PINS_MASK;
+               sunxi_dlevel_reg(pin, reg, shift, mask);
                break;
 
        case PIN_CONFIG_BIAS_PULL_UP:
        case PIN_CONFIG_BIAS_PULL_DOWN:
        case PIN_CONFIG_BIAS_DISABLE:
-               *offset = sunxi_pull_reg(pin);
-               *shift = sunxi_pull_offset(pin);
-               *mask = PULL_PINS_MASK;
+               sunxi_pull_reg(pin, reg, shift, mask);
                break;
 
        default:
 {
        struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
        enum pin_config_param param = pinconf_to_config_param(*config);
-       u32 offset, shift, mask, val;
+       u32 reg, shift, mask, val;
        u16 arg;
        int ret;
 
        pin -= pctl->desc->pin_base;
 
-       ret = sunxi_pconf_reg(pin, param, &offset, &shift, &mask);
+       ret = sunxi_pconf_reg(pin, param, ®, &shift, &mask);
        if (ret < 0)
                return ret;
 
-       val = (readl(pctl->membase + offset) >> shift) & mask;
+       val = (readl(pctl->membase + reg) & mask) >> shift;
 
        switch (pinconf_to_config_param(*config)) {
        case PIN_CONFIG_DRIVE_STRENGTH:
        int i;
 
        for (i = 0; i < num_configs; i++) {
+               u32 arg, reg, shift, mask, val;
                enum pin_config_param param;
                unsigned long flags;
-               u32 offset, shift, mask, reg;
-               u32 arg, val;
                int ret;
 
                param = pinconf_to_config_param(configs[i]);
                arg = pinconf_to_config_argument(configs[i]);
 
-               ret = sunxi_pconf_reg(pin, param, &offset, &shift, &mask);
+               ret = sunxi_pconf_reg(pin, param, ®, &shift, &mask);
                if (ret < 0)
                        return ret;
 
                }
 
                raw_spin_lock_irqsave(&pctl->lock, flags);
-               reg = readl(pctl->membase + offset);
-               reg &= ~(mask << shift);
-               writel(reg | val << shift, pctl->membase + offset);
+               writel((readl(pctl->membase + reg) & ~mask) | val << shift,
+                      pctl->membase + reg);
                raw_spin_unlock_irqrestore(&pctl->lock, flags);
        } /* for each config */
 
                                 u8 config)
 {
        struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+       u32 reg, shift, mask;
        unsigned long flags;
-       u32 val, mask;
+
+       pin -= pctl->desc->pin_base;
+       sunxi_mux_reg(pin, ®, &shift, &mask);
 
        raw_spin_lock_irqsave(&pctl->lock, flags);
 
-       pin -= pctl->desc->pin_base;
-       val = readl(pctl->membase + sunxi_mux_reg(pin));
-       mask = MUX_PINS_MASK << sunxi_mux_offset(pin);
-       writel((val & ~mask) | config << sunxi_mux_offset(pin),
-               pctl->membase + sunxi_mux_reg(pin));
+       writel((readl(pctl->membase + reg) & ~mask) | config << shift,
+              pctl->membase + reg);
 
        raw_spin_unlock_irqrestore(&pctl->lock, flags);
 }
 static int sunxi_pinctrl_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
        struct sunxi_pinctrl *pctl = gpiochip_get_data(chip);
-       u32 reg = sunxi_data_reg(offset);
-       u8 index = sunxi_data_offset(offset);
        bool set_mux = pctl->desc->irq_read_needs_mux &&
                gpiochip_line_is_irq(chip, offset);
        u32 pin = offset + chip->base;
-       u32 val;
+       u32 reg, shift, mask, val;
+
+       sunxi_data_reg(offset, ®, &shift, &mask);
 
        if (set_mux)
                sunxi_pmx_set(pctl->pctl_dev, pin, SUN4I_FUNC_INPUT);
 
-       val = (readl(pctl->membase + reg) >> index) & DATA_PINS_MASK;
+       val = (readl(pctl->membase + reg) & mask) >> shift;
 
        if (set_mux)
                sunxi_pmx_set(pctl->pctl_dev, pin, SUN4I_FUNC_IRQ);
 
-       return !!val;
+       return val;
 }
 
 static void sunxi_pinctrl_gpio_set(struct gpio_chip *chip,
                                unsigned offset, int value)
 {
        struct sunxi_pinctrl *pctl = gpiochip_get_data(chip);
-       u32 reg = sunxi_data_reg(offset);
-       u8 index = sunxi_data_offset(offset);
+       u32 reg, shift, mask, val;
        unsigned long flags;
-       u32 regval;
+
+       sunxi_data_reg(offset, ®, &shift, &mask);
 
        raw_spin_lock_irqsave(&pctl->lock, flags);
 
-       regval = readl(pctl->membase + reg);
+       val = readl(pctl->membase + reg);
 
        if (value)
-               regval |= BIT(index);
+               val |= mask;
        else
-               regval &= ~(BIT(index));
+               val &= ~mask;
 
-       writel(regval, pctl->membase + reg);
+       writel(val, pctl->membase + reg);
 
        raw_spin_unlock_irqrestore(&pctl->lock, flags);
 }
 
 
 #define BANK_MEM_SIZE          0x24
 #define MUX_REGS_OFFSET                0x0
+#define MUX_FIELD_WIDTH                4
 #define DATA_REGS_OFFSET       0x10
+#define DATA_FIELD_WIDTH       1
 #define DLEVEL_REGS_OFFSET     0x14
+#define DLEVEL_FIELD_WIDTH     2
 #define PULL_REGS_OFFSET       0x1c
+#define PULL_FIELD_WIDTH       2
 
 #define PINS_PER_BANK          32
-#define MUX_PINS_PER_REG       8
-#define MUX_PINS_BITS          4
-#define MUX_PINS_MASK          0x0f
-#define DATA_PINS_PER_REG      32
-#define DATA_PINS_BITS         1
-#define DATA_PINS_MASK         0x01
-#define DLEVEL_PINS_PER_REG    16
-#define DLEVEL_PINS_BITS       2
-#define DLEVEL_PINS_MASK       0x03
-#define PULL_PINS_PER_REG      16
-#define PULL_PINS_BITS         2
-#define PULL_PINS_MASK         0x03
 
 #define IRQ_PER_BANK           32
 
                .irqnum = _irq,                                 \
        }
 
-/*
- * The sunXi PIO registers are organized as is:
- * 0x00 - 0x0c Muxing values.
- *             8 pins per register, each pin having a 4bits value
- * 0x10                Pin values
- *             32 bits per register, each pin corresponding to one bit
- * 0x14 - 0x18 Drive level
- *             16 pins per register, each pin having a 2bits value
- * 0x1c - 0x20 Pull-Up values
- *             16 pins per register, each pin having a 2bits value
- *
- * This is for the first bank. Each bank will have the same layout,
- * with an offset being a multiple of 0x24.
- *
- * The following functions calculate from the pin number the register
- * and the bit offset that we should access.
- */
-static inline u32 sunxi_mux_reg(u16 pin)
-{
-       u8 bank = pin / PINS_PER_BANK;
-       u32 offset = bank * BANK_MEM_SIZE;
-       offset += MUX_REGS_OFFSET;
-       offset += pin % PINS_PER_BANK / MUX_PINS_PER_REG * 0x04;
-       return round_down(offset, 4);
-}
-
-static inline u32 sunxi_mux_offset(u16 pin)
-{
-       u32 pin_num = pin % MUX_PINS_PER_REG;
-       return pin_num * MUX_PINS_BITS;
-}
-
-static inline u32 sunxi_data_reg(u16 pin)
-{
-       u8 bank = pin / PINS_PER_BANK;
-       u32 offset = bank * BANK_MEM_SIZE;
-       offset += DATA_REGS_OFFSET;
-       offset += pin % PINS_PER_BANK / DATA_PINS_PER_REG * 0x04;
-       return round_down(offset, 4);
-}
-
-static inline u32 sunxi_data_offset(u16 pin)
-{
-       u32 pin_num = pin % DATA_PINS_PER_REG;
-       return pin_num * DATA_PINS_BITS;
-}
-
-static inline u32 sunxi_dlevel_reg(u16 pin)
-{
-       u8 bank = pin / PINS_PER_BANK;
-       u32 offset = bank * BANK_MEM_SIZE;
-       offset += DLEVEL_REGS_OFFSET;
-       offset += pin % PINS_PER_BANK / DLEVEL_PINS_PER_REG * 0x04;
-       return round_down(offset, 4);
-}
-
-static inline u32 sunxi_dlevel_offset(u16 pin)
-{
-       u32 pin_num = pin % DLEVEL_PINS_PER_REG;
-       return pin_num * DLEVEL_PINS_BITS;
-}
-
-static inline u32 sunxi_pull_reg(u16 pin)
-{
-       u8 bank = pin / PINS_PER_BANK;
-       u32 offset = bank * BANK_MEM_SIZE;
-       offset += PULL_REGS_OFFSET;
-       offset += pin % PINS_PER_BANK / PULL_PINS_PER_REG * 0x04;
-       return round_down(offset, 4);
-}
-
-static inline u32 sunxi_pull_offset(u16 pin)
-{
-       u32 pin_num = pin % PULL_PINS_PER_REG;
-       return pin_num * PULL_PINS_BITS;
-}
-
 static inline u32 sunxi_irq_hw_bank_num(const struct sunxi_pinctrl_desc *desc, u8 bank)
 {
        if (!desc->irq_bank_map)