pinctrl: sunxi: Make sunxi_pconf_group_set use sunxi_pconf_reg helper
authorChen-Yu Tsai <wens@csie.org>
Fri, 11 Nov 2016 09:50:36 +0000 (17:50 +0800)
committerLinus Walleij <linus.walleij@linaro.org>
Tue, 15 Nov 2016 09:21:49 +0000 (10:21 +0100)
The sunxi_pconf_reg helper introduced in the last patch gives us the
chance to rework sunxi_pconf_group_set to have it match the structure
of sunxi_pconf_(group_)get and make it easier to understand.

For each config to set, it:

    1. checks if the parameter is supported.
    2. checks if the argument is within limits.
    3. converts argument to the register value.
    4. writes to the register with spinlock held.

As a result the function now blocks unsupported config parameters,
instead of silently ignoring them.

Signed-off-by: Chen-Yu Tsai <wens@csie.org>
Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
drivers/pinctrl/sunxi/pinctrl-sunxi.c

index ed71bff39869ec716a2a3f5d29572216c77c9740..fa11a3100346a81226965fcb077368ffb2808d31 100644 (file)
@@ -532,23 +532,27 @@ static int sunxi_pconf_group_set(struct pinctrl_dev *pctldev,
 {
        struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
        struct sunxi_pinctrl_group *g = &pctl->groups[group];
-       unsigned long flags;
        unsigned pin = g->pin - pctl->desc->pin_base;
-       u32 val, mask;
-       u16 strength;
-       u8 dlevel;
        int i;
 
-       spin_lock_irqsave(&pctl->lock, flags);
-
        for (i = 0; i < num_configs; i++) {
-               switch (pinconf_to_config_param(configs[i])) {
+               enum pin_config_param param;
+               unsigned long flags;
+               u32 offset, shift, mask, reg;
+               u16 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);
+               if (ret < 0)
+                       return ret;
+
+               switch (param) {
                case PIN_CONFIG_DRIVE_STRENGTH:
-                       strength = pinconf_to_config_argument(configs[i]);
-                       if (strength > 40) {
-                               spin_unlock_irqrestore(&pctl->lock, flags);
+                       if (arg < 10 || arg > 40)
                                return -EINVAL;
-                       }
                        /*
                         * We convert from mA to what the register expects:
                         *   0: 10mA
@@ -556,37 +560,33 @@ static int sunxi_pconf_group_set(struct pinctrl_dev *pctldev,
                         *   2: 30mA
                         *   3: 40mA
                         */
-                       dlevel = strength / 10 - 1;
-                       val = readl(pctl->membase + sunxi_dlevel_reg(pin));
-                       mask = DLEVEL_PINS_MASK << sunxi_dlevel_offset(pin);
-                       writel((val & ~mask)
-                               | dlevel << sunxi_dlevel_offset(pin),
-                               pctl->membase + sunxi_dlevel_reg(pin));
+                       val = arg / 10 - 1;
                        break;
                case PIN_CONFIG_BIAS_DISABLE:
-                       val = readl(pctl->membase + sunxi_pull_reg(pin));
-                       mask = PULL_PINS_MASK << sunxi_pull_offset(pin);
-                       writel((val & ~mask),
-                              pctl->membase + sunxi_pull_reg(pin));
+                       val = 0;
                        break;
                case PIN_CONFIG_BIAS_PULL_UP:
-                       val = readl(pctl->membase + sunxi_pull_reg(pin));
-                       mask = PULL_PINS_MASK << sunxi_pull_offset(pin);
-                       writel((val & ~mask) | 1 << sunxi_pull_offset(pin),
-                               pctl->membase + sunxi_pull_reg(pin));
+                       if (arg == 0)
+                               return -EINVAL;
+                       val = 1;
                        break;
                case PIN_CONFIG_BIAS_PULL_DOWN:
-                       val = readl(pctl->membase + sunxi_pull_reg(pin));
-                       mask = PULL_PINS_MASK << sunxi_pull_offset(pin);
-                       writel((val & ~mask) | 2 << sunxi_pull_offset(pin),
-                               pctl->membase + sunxi_pull_reg(pin));
+                       if (arg == 0)
+                               return -EINVAL;
+                       val = 2;
                        break;
                default:
-                       break;
+                       /* sunxi_pconf_reg should catch anything unsupported */
+                       WARN_ON(1);
+                       return -ENOTSUPP;
                }
-       } /* for each config */
 
-       spin_unlock_irqrestore(&pctl->lock, flags);
+               spin_lock_irqsave(&pctl->lock, flags);
+               reg = readl(pctl->membase + offset);
+               reg &= ~(mask << shift);
+               writel(reg | val << shift, pctl->membase + offset);
+               spin_unlock_irqrestore(&pctl->lock, flags);
+       } /* for each config */
 
        return 0;
 }