sunxi: Backport patches needed for A64
[openwrt/openwrt.git] / target / linux / sunxi / patches-4.9 / 0038-pinctrl-sunxi-Add-support-for-fetching-pinconf-setti.patch
1 From c5fda170e87a4bdaeb278f7e50f7a1f654e94eb5 Mon Sep 17 00:00:00 2001
2 From: Chen-Yu Tsai <wens@csie.org>
3 Date: Fri, 11 Nov 2016 17:50:35 +0800
4 Subject: pinctrl: sunxi: Add support for fetching pinconf settings from
5 hardware
6
7 The sunxi pinctrl driver only caches whatever pinconf setting was last
8 set on a given pingroup. This is not particularly helpful, nor is it
9 correct.
10
11 Fix this by actually reading the hardware registers and returning
12 the correct results or error codes. Also filter out unsupported
13 pinconf settings. Since this driver has a peculiar setup of 1 pin
14 per group, we can support both pin and pingroup pinconf setting
15 read back with the same code. The sunxi_pconf_reg helper and code
16 structure is inspired by pinctrl-msm.
17
18 With this done we can also claim to support generic pinconf, by
19 setting .is_generic = true in pinconf_ops.
20
21 Also remove the cached config value. The behavior of this was never
22 correct, as it only cached 1 setting instead of all of them. Since
23 we can now read back settings directly from the hardware, it is no
24 longer required.
25
26 Signed-off-by: Chen-Yu Tsai <wens@csie.org>
27 Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
28 Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
29 ---
30 drivers/pinctrl/sunxi/pinctrl-sunxi.c | 86 +++++++++++++++++++++++++++++++++--
31 drivers/pinctrl/sunxi/pinctrl-sunxi.h | 1 -
32 2 files changed, 81 insertions(+), 6 deletions(-)
33
34 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
35 +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
36 @@ -438,15 +438,91 @@ static const struct pinctrl_ops sunxi_pc
37 .get_group_pins = sunxi_pctrl_get_group_pins,
38 };
39
40 +static int sunxi_pconf_reg(unsigned pin, enum pin_config_param param,
41 + u32 *offset, u32 *shift, u32 *mask)
42 +{
43 + switch (param) {
44 + case PIN_CONFIG_DRIVE_STRENGTH:
45 + *offset = sunxi_dlevel_reg(pin);
46 + *shift = sunxi_dlevel_offset(pin);
47 + *mask = DLEVEL_PINS_MASK;
48 + break;
49 +
50 + case PIN_CONFIG_BIAS_PULL_UP:
51 + case PIN_CONFIG_BIAS_PULL_DOWN:
52 + case PIN_CONFIG_BIAS_DISABLE:
53 + *offset = sunxi_pull_reg(pin);
54 + *shift = sunxi_pull_offset(pin);
55 + *mask = PULL_PINS_MASK;
56 + break;
57 +
58 + default:
59 + return -ENOTSUPP;
60 + }
61 +
62 + return 0;
63 +}
64 +
65 +static int sunxi_pconf_get(struct pinctrl_dev *pctldev, unsigned pin,
66 + unsigned long *config)
67 +{
68 + struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
69 + enum pin_config_param param = pinconf_to_config_param(*config);
70 + u32 offset, shift, mask, val;
71 + u16 arg;
72 + int ret;
73 +
74 + pin -= pctl->desc->pin_base;
75 +
76 + ret = sunxi_pconf_reg(pin, param, &offset, &shift, &mask);
77 + if (ret < 0)
78 + return ret;
79 +
80 + val = (readl(pctl->membase + offset) >> shift) & mask;
81 +
82 + switch (pinconf_to_config_param(*config)) {
83 + case PIN_CONFIG_DRIVE_STRENGTH:
84 + arg = (val + 1) * 10;
85 + break;
86 +
87 + case PIN_CONFIG_BIAS_PULL_UP:
88 + if (val != SUN4I_PINCTRL_PULL_UP)
89 + return -EINVAL;
90 + arg = 1; /* hardware is weak pull-up */
91 + break;
92 +
93 + case PIN_CONFIG_BIAS_PULL_DOWN:
94 + if (val != SUN4I_PINCTRL_PULL_DOWN)
95 + return -EINVAL;
96 + arg = 1; /* hardware is weak pull-down */
97 + break;
98 +
99 + case PIN_CONFIG_BIAS_DISABLE:
100 + if (val != SUN4I_PINCTRL_NO_PULL)
101 + return -EINVAL;
102 + arg = 0;
103 + break;
104 +
105 + default:
106 + /* sunxi_pconf_reg should catch anything unsupported */
107 + WARN_ON(1);
108 + return -ENOTSUPP;
109 + }
110 +
111 + *config = pinconf_to_config_packed(param, arg);
112 +
113 + return 0;
114 +}
115 +
116 static int sunxi_pconf_group_get(struct pinctrl_dev *pctldev,
117 unsigned group,
118 unsigned long *config)
119 {
120 struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
121 + struct sunxi_pinctrl_group *g = &pctl->groups[group];
122
123 - *config = pctl->groups[group].config;
124 -
125 - return 0;
126 + /* We only support 1 pin per group. Chain it to the pin callback */
127 + return sunxi_pconf_get(pctldev, g->pin, config);
128 }
129
130 static int sunxi_pconf_group_set(struct pinctrl_dev *pctldev,
131 @@ -508,8 +584,6 @@ static int sunxi_pconf_group_set(struct
132 default:
133 break;
134 }
135 - /* cache the config value */
136 - g->config = configs[i];
137 } /* for each config */
138
139 spin_unlock_irqrestore(&pctl->lock, flags);
140 @@ -518,6 +592,8 @@ static int sunxi_pconf_group_set(struct
141 }
142
143 static const struct pinconf_ops sunxi_pconf_ops = {
144 + .is_generic = true,
145 + .pin_config_get = sunxi_pconf_get,
146 .pin_config_group_get = sunxi_pconf_group_get,
147 .pin_config_group_set = sunxi_pconf_group_set,
148 };
149 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.h
150 +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.h
151 @@ -109,7 +109,6 @@ struct sunxi_pinctrl_function {
152
153 struct sunxi_pinctrl_group {
154 const char *name;
155 - unsigned long config;
156 unsigned pin;
157 };
158