34a422794d
This backports multiple patches from kernel 4.10 which are adding missing support for the A64 and the pine64 board. These are the device tree files, the pinctlk and the clock driver. Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
158 lines
4.5 KiB
Diff
158 lines
4.5 KiB
Diff
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;
|
|
};
|
|
|