Merge tag 'pinctrl-v6.0-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw...
[linux-2.6-microblaze.git] / drivers / pinctrl / sunxi / pinctrl-sunxi.c
index dd92840..6c04027 100644 (file)
@@ -46,6 +46,67 @@ static struct lock_class_key sunxi_pinctrl_irq_request_class;
 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(const struct sunxi_pinctrl *pctl,
+                         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 * pctl->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(const struct sunxi_pinctrl *pctl,
+                          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 * pctl->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(const struct sunxi_pinctrl *pctl,
+                            u32 pin, u32 *reg, u32 *shift, u32 *mask)
+{
+       u32 bank   = pin / PINS_PER_BANK;
+       u32 offset = pin % PINS_PER_BANK * pctl->dlevel_field_width;
+
+       *reg   = bank * pctl->bank_mem_size + DLEVEL_REGS_OFFSET +
+                offset / BITS_PER_TYPE(u32) * sizeof(u32);
+       *shift = offset % BITS_PER_TYPE(u32);
+       *mask  = (BIT(pctl->dlevel_field_width) - 1) << *shift;
+}
+
+static void sunxi_pull_reg(const struct sunxi_pinctrl *pctl,
+                          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 * pctl->bank_mem_size + pctl->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)
 {
@@ -451,22 +512,19 @@ static const struct pinctrl_ops sunxi_pctrl_ops = {
        .get_group_pins         = sunxi_pctrl_get_group_pins,
 };
 
-static int sunxi_pconf_reg(unsigned pin, enum pin_config_param param,
-                          u32 *offset, u32 *shift, u32 *mask)
+static int sunxi_pconf_reg(const struct sunxi_pinctrl *pctl,
+                          u32 pin, enum pin_config_param param,
+                          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(pctl, 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(pctl, pin, reg, shift, mask);
                break;
 
        default:
@@ -481,17 +539,17 @@ static int sunxi_pconf_get(struct pinctrl_dev *pctldev, unsigned pin,
 {
        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(pctl, pin, param, &reg, &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:
@@ -547,16 +605,15 @@ static int sunxi_pconf_set(struct pinctrl_dev *pctldev, unsigned pin,
        pin -= pctl->desc->pin_base;
 
        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(pctl, pin, param, &reg, &shift, &mask);
                if (ret < 0)
                        return ret;
 
@@ -593,9 +650,8 @@ static int sunxi_pconf_set(struct pinctrl_dev *pctldev, unsigned pin,
                }
 
                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 */
 
@@ -624,7 +680,7 @@ static int sunxi_pinctrl_set_io_bias_cfg(struct sunxi_pinctrl *pctl,
                                         unsigned pin,
                                         struct regulator *supply)
 {
-       unsigned short bank = pin / PINS_PER_BANK;
+       unsigned short bank;
        unsigned long flags;
        u32 val, reg;
        int uV;
@@ -640,6 +696,9 @@ static int sunxi_pinctrl_set_io_bias_cfg(struct sunxi_pinctrl *pctl,
        if (uV == 0)
                return 0;
 
+       pin -= pctl->desc->pin_base;
+       bank = pin / PINS_PER_BANK;
+
        switch (pctl->desc->io_bias_cfg_variant) {
        case BIAS_VOLTAGE_GRP_CONFIG:
                /*
@@ -657,12 +716,20 @@ static int sunxi_pinctrl_set_io_bias_cfg(struct sunxi_pinctrl *pctl,
                else
                        val = 0xD; /* 3.3V */
 
-               pin -= pctl->desc->pin_base;
-
                reg = readl(pctl->membase + sunxi_grp_config_reg(pin));
                reg &= ~IO_BIAS_MASK;
                writel(reg | val, pctl->membase + sunxi_grp_config_reg(pin));
                return 0;
+       case BIAS_VOLTAGE_PIO_POW_MODE_CTL:
+               val = uV > 1800000 && uV <= 2500000 ? BIT(bank) : 0;
+
+               raw_spin_lock_irqsave(&pctl->lock, flags);
+               reg = readl(pctl->membase + PIO_POW_MOD_CTL_REG);
+               reg &= ~BIT(bank);
+               writel(reg | val, pctl->membase + PIO_POW_MOD_CTL_REG);
+               raw_spin_unlock_irqrestore(&pctl->lock, flags);
+
+               fallthrough;
        case BIAS_VOLTAGE_PIO_POW_MODE_SEL:
                val = uV <= 1800000 ? 1 : 0;
 
@@ -710,16 +777,16 @@ static void sunxi_pmx_set(struct pinctrl_dev *pctldev,
                                 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(pctl, pin, &reg, &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);
 }
@@ -852,43 +919,43 @@ static int sunxi_pinctrl_gpio_direction_input(struct gpio_chip *chip,
 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(pctl, offset, &reg, &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(pctl, offset, &reg, &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);
 }
@@ -1232,11 +1299,11 @@ static int sunxi_pinctrl_build_state(struct platform_device *pdev)
 
        /*
         * Find an upper bound for the maximum number of functions: in
-        * the worst case we have gpio_in, gpio_out, irq and up to four
+        * the worst case we have gpio_in, gpio_out, irq and up to seven
         * special functions per pin, plus one entry for the sentinel.
         * We'll reallocate that later anyway.
         */
-       pctl->functions = kcalloc(4 * pctl->ngroups + 4,
+       pctl->functions = kcalloc(7 * pctl->ngroups + 4,
                                  sizeof(*pctl->functions),
                                  GFP_KERNEL);
        if (!pctl->functions)
@@ -1429,6 +1496,15 @@ int sunxi_pinctrl_init_with_variant(struct platform_device *pdev,
        pctl->dev = &pdev->dev;
        pctl->desc = desc;
        pctl->variant = variant;
+       if (pctl->variant >= PINCTRL_SUN20I_D1) {
+               pctl->bank_mem_size = D1_BANK_MEM_SIZE;
+               pctl->pull_regs_offset = D1_PULL_REGS_OFFSET;
+               pctl->dlevel_field_width = D1_DLEVEL_FIELD_WIDTH;
+       } else {
+               pctl->bank_mem_size = BANK_MEM_SIZE;
+               pctl->pull_regs_offset = PULL_REGS_OFFSET;
+               pctl->dlevel_field_width = DLEVEL_FIELD_WIDTH;
+       }
 
        pctl->irq_array = devm_kcalloc(&pdev->dev,
                                       IRQ_PER_BANK * pctl->desc->irq_banks,