diff options
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.patch | 158 |
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 0000000..d797219 --- /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; + }; + |