summaryrefslogtreecommitdiff
path: root/target/linux/sunxi/patches-4.9/0039-pinctrl-sunxi-Make-sunxi_pconf_group_set-use-sunxi_p.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/sunxi/patches-4.9/0039-pinctrl-sunxi-Make-sunxi_pconf_group_set-use-sunxi_p.patch')
-rw-r--r--target/linux/sunxi/patches-4.9/0039-pinctrl-sunxi-Make-sunxi_pconf_group_set-use-sunxi_p.patch122
1 files changed, 122 insertions, 0 deletions
diff --git a/target/linux/sunxi/patches-4.9/0039-pinctrl-sunxi-Make-sunxi_pconf_group_set-use-sunxi_p.patch b/target/linux/sunxi/patches-4.9/0039-pinctrl-sunxi-Make-sunxi_pconf_group_set-use-sunxi_p.patch
new file mode 100644
index 0000000..7555933
--- /dev/null
+++ b/target/linux/sunxi/patches-4.9/0039-pinctrl-sunxi-Make-sunxi_pconf_group_set-use-sunxi_p.patch
@@ -0,0 +1,122 @@
+From 51814827190214986c452a166718bf12d32211c7 Mon Sep 17 00:00:00 2001
+From: Chen-Yu Tsai <wens@csie.org>
+Date: Fri, 11 Nov 2016 17:50:36 +0800
+Subject: 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>
+---
+ drivers/pinctrl/sunxi/pinctrl-sunxi.c | 64 +++++++++++++++++------------------
+ 1 file changed, 32 insertions(+), 32 deletions(-)
+
+--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
++++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+@@ -532,23 +532,27 @@ static int sunxi_pconf_group_set(struct
+ {
+ 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
+ * 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;
+ }