aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/sunxi/patches-4.9/0038-pinctrl-sunxi-Add-support-for-fetching-pinconf-setti.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/sunxi/patches-4.9/0038-pinctrl-sunxi-Add-support-for-fetching-pinconf-setti.patch')
-rw-r--r--target/linux/sunxi/patches-4.9/0038-pinctrl-sunxi-Add-support-for-fetching-pinconf-setti.patch158
1 files changed, 158 insertions, 0 deletions
diff --git a/target/linux/sunxi/patches-4.9/0038-pinctrl-sunxi-Add-support-for-fetching-pinconf-setti.patch b/target/linux/sunxi/patches-4.9/0038-pinctrl-sunxi-Add-support-for-fetching-pinconf-setti.patch
new file mode 100644
index 0000000000..d7972197ff
--- /dev/null
+++ b/target/linux/sunxi/patches-4.9/0038-pinctrl-sunxi-Add-support-for-fetching-pinconf-setti.patch
@@ -0,0 +1,158 @@
+From c5fda170e87a4bdaeb278f7e50f7a1f654e94eb5 Mon Sep 17 00:00:00 2001
+From: Chen-Yu Tsai <wens@csie.org>
+Date: Fri, 11 Nov 2016 17:50:35 +0800
+Subject: pinctrl: sunxi: Add support for fetching pinconf settings from
+ hardware
+
+The sunxi pinctrl driver only caches whatever pinconf setting was last
+set on a given pingroup. This is not particularly helpful, nor is it
+correct.
+
+Fix this by actually reading the hardware registers and returning
+the correct results or error codes. Also filter out unsupported
+pinconf settings. Since this driver has a peculiar setup of 1 pin
+per group, we can support both pin and pingroup pinconf setting
+read back with the same code. The sunxi_pconf_reg helper and code
+structure is inspired by pinctrl-msm.
+
+With this done we can also claim to support generic pinconf, by
+setting .is_generic = true in pinconf_ops.
+
+Also remove the cached config value. The behavior of this was never
+correct, as it only cached 1 setting instead of all of them. Since
+we can now read back settings directly from the hardware, it is no
+longer required.
+
+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 | 86 +++++++++++++++++++++++++++++++++--
+ drivers/pinctrl/sunxi/pinctrl-sunxi.h | 1 -
+ 2 files changed, 81 insertions(+), 6 deletions(-)
+
+--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
++++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+@@ -438,15 +438,91 @@ static const struct pinctrl_ops sunxi_pc
+ .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)
++{
++ switch (param) {
++ case PIN_CONFIG_DRIVE_STRENGTH:
++ *offset = sunxi_dlevel_reg(pin);
++ *shift = sunxi_dlevel_offset(pin);
++ *mask = DLEVEL_PINS_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;
++ break;
++
++ default:
++ return -ENOTSUPP;
++ }
++
++ return 0;
++}
++
++static int sunxi_pconf_get(struct pinctrl_dev *pctldev, unsigned pin,
++ unsigned long *config)
++{
++ struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
++ enum pin_config_param param = pinconf_to_config_param(*config);
++ u32 offset, shift, mask, val;
++ u16 arg;
++ int ret;
++
++ pin -= pctl->desc->pin_base;
++
++ ret = sunxi_pconf_reg(pin, param, &offset, &shift, &mask);
++ if (ret < 0)
++ return ret;
++
++ val = (readl(pctl->membase + offset) >> shift) & mask;
++
++ switch (pinconf_to_config_param(*config)) {
++ case PIN_CONFIG_DRIVE_STRENGTH:
++ arg = (val + 1) * 10;
++ break;
++
++ case PIN_CONFIG_BIAS_PULL_UP:
++ if (val != SUN4I_PINCTRL_PULL_UP)
++ return -EINVAL;
++ arg = 1; /* hardware is weak pull-up */
++ break;
++
++ case PIN_CONFIG_BIAS_PULL_DOWN:
++ if (val != SUN4I_PINCTRL_PULL_DOWN)
++ return -EINVAL;
++ arg = 1; /* hardware is weak pull-down */
++ break;
++
++ case PIN_CONFIG_BIAS_DISABLE:
++ if (val != SUN4I_PINCTRL_NO_PULL)
++ return -EINVAL;
++ arg = 0;
++ break;
++
++ default:
++ /* sunxi_pconf_reg should catch anything unsupported */
++ WARN_ON(1);
++ return -ENOTSUPP;
++ }
++
++ *config = pinconf_to_config_packed(param, arg);
++
++ return 0;
++}
++
+ static int sunxi_pconf_group_get(struct pinctrl_dev *pctldev,
+ unsigned group,
+ unsigned long *config)
+ {
+ struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
++ struct sunxi_pinctrl_group *g = &pctl->groups[group];
+
+- *config = pctl->groups[group].config;
+-
+- return 0;
++ /* We only support 1 pin per group. Chain it to the pin callback */
++ return sunxi_pconf_get(pctldev, g->pin, config);
+ }
+
+ static int sunxi_pconf_group_set(struct pinctrl_dev *pctldev,
+@@ -508,8 +584,6 @@ static int sunxi_pconf_group_set(struct
+ default:
+ break;
+ }
+- /* cache the config value */
+- g->config = configs[i];
+ } /* for each config */
+
+ spin_unlock_irqrestore(&pctl->lock, flags);
+@@ -518,6 +592,8 @@ static int sunxi_pconf_group_set(struct
+ }
+
+ static const struct pinconf_ops sunxi_pconf_ops = {
++ .is_generic = true,
++ .pin_config_get = sunxi_pconf_get,
+ .pin_config_group_get = sunxi_pconf_group_get,
+ .pin_config_group_set = sunxi_pconf_group_set,
+ };
+--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.h
++++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.h
+@@ -109,7 +109,6 @@ struct sunxi_pinctrl_function {
+
+ struct sunxi_pinctrl_group {
+ const char *name;
+- unsigned long config;
+ unsigned pin;
+ };
+