v1.5 branch refresh based upon upstream master @ c8677ca89e53e3be7988d54280fce166cc894a7e
[librecmc/librecmc.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