pinctrl: sunxi: Make sunxi_pconf_group_set use sunxi_pconf_reg helper

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>
This commit is contained in:
Chen-Yu Tsai 2016-11-11 17:50:36 +08:00 committed by Linus Walleij
parent c5fda170e8
commit 5181482719

View 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;
}