v1.5 branch refresh based upon upstream master @ c8677ca89e53e3be7988d54280fce166cc894a7e
[librecmc/librecmc.git] / target / linux / sunxi / patches-4.9 / 0030-pinctrl-sunxi-Rework-the-pin-config-building-code.patch
1 From f233dbca6227703eaae2f67d6d9c79819773f16b Mon Sep 17 00:00:00 2001
2 From: Maxime Ripard <maxime.ripard@free-electrons.com>
3 Date: Tue, 11 Oct 2016 17:45:59 +0200
4 Subject: pinctrl: sunxi: Rework the pin config building code
5
6 In order to support more easily the generic pinctrl properties, rework the
7 pinctrl maps configuration and split it into several sub-functions.
8
9 One of the side-effects from that rework is that we only parse the pin
10 configuration once, since it's going to be common to every pin, instead of
11 having to parsing once for each pin.
12
13 Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
14 Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
15 ---
16  drivers/pinctrl/sunxi/pinctrl-sunxi.c | 178 +++++++++++++++++++++++++---------
17  1 file changed, 130 insertions(+), 48 deletions(-)
18
19 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
20 +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
21 @@ -145,6 +145,110 @@ static int sunxi_pctrl_get_group_pins(st
22         return 0;
23  }
24  
25 +static bool sunxi_pctrl_has_bias_prop(struct device_node *node)
26 +{
27 +       return of_find_property(node, "allwinner,pull", NULL);
28 +}
29 +
30 +static bool sunxi_pctrl_has_drive_prop(struct device_node *node)
31 +{
32 +       return of_find_property(node, "allwinner,drive", NULL);
33 +}
34 +
35 +static int sunxi_pctrl_parse_bias_prop(struct device_node *node)
36 +{
37 +       u32 val;
38 +
39 +       if (of_property_read_u32(node, "allwinner,pull", &val))
40 +               return -EINVAL;
41 +
42 +       switch (val) {
43 +       case 1:
44 +               return PIN_CONFIG_BIAS_PULL_UP;
45 +       case 2:
46 +               return PIN_CONFIG_BIAS_PULL_DOWN;
47 +       }
48 +
49 +       return -EINVAL;
50 +}
51 +
52 +static int sunxi_pctrl_parse_drive_prop(struct device_node *node)
53 +{
54 +       u32 val;
55 +
56 +       if (of_property_read_u32(node, "allwinner,drive", &val))
57 +               return -EINVAL;
58 +
59 +       return (val + 1) * 10;
60 +}
61 +
62 +static const char *sunxi_pctrl_parse_function_prop(struct device_node *node)
63 +{
64 +       const char *function;
65 +       int ret;
66 +
67 +       ret = of_property_read_string(node, "allwinner,function", &function);
68 +       if (!ret)
69 +               return function;
70 +
71 +       return NULL;
72 +}
73 +
74 +static const char *sunxi_pctrl_find_pins_prop(struct device_node *node,
75 +                                             int *npins)
76 +{
77 +       int count;
78 +
79 +       count = of_property_count_strings(node, "allwinner,pins");
80 +       if (count > 0) {
81 +               *npins = count;
82 +               return "allwinner,pins";
83 +       }
84 +
85 +       return NULL;
86 +}
87 +
88 +static unsigned long *sunxi_pctrl_build_pin_config(struct device_node *node,
89 +                                                  unsigned int *len)
90 +{
91 +       unsigned long *pinconfig;
92 +       unsigned int configlen = 0, idx = 0;
93 +
94 +       if (sunxi_pctrl_has_drive_prop(node))
95 +               configlen++;
96 +       if (sunxi_pctrl_has_bias_prop(node))
97 +               configlen++;
98 +
99 +       pinconfig = kzalloc(configlen * sizeof(*pinconfig), GFP_KERNEL);
100 +       if (!pinconfig)
101 +               return NULL;
102 +
103 +       if (sunxi_pctrl_has_drive_prop(node)) {
104 +               int drive = sunxi_pctrl_parse_drive_prop(node);
105 +               if (drive < 0)
106 +                       goto err_free;
107 +
108 +               pinconfig[idx++] = pinconf_to_config_packed(PIN_CONFIG_DRIVE_STRENGTH,
109 +                                                         drive);
110 +       }
111 +
112 +       if (sunxi_pctrl_has_bias_prop(node)) {
113 +               int pull = sunxi_pctrl_parse_bias_prop(node);
114 +               if (pull < 0)
115 +                       goto err_free;
116 +
117 +               pinconfig[idx++] = pinconf_to_config_packed(pull, 0);
118 +       }
119 +
120 +
121 +       *len = configlen;
122 +       return pinconfig;
123 +
124 +err_free:
125 +       kfree(pinconfig);
126 +       return NULL;
127 +}
128 +
129  static int sunxi_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
130                                       struct device_node *node,
131                                       struct pinctrl_map **map,
132 @@ -153,38 +257,45 @@ static int sunxi_pctrl_dt_node_to_map(st
133         struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
134         unsigned long *pinconfig;
135         struct property *prop;
136 -       const char *function;
137 +       const char *function, *pin_prop;
138         const char *group;
139 -       int ret, nmaps, i = 0;
140 -       u32 val;
141 +       int ret, npins, nmaps, configlen = 0, i = 0;
142  
143         *map = NULL;
144         *num_maps = 0;
145  
146 -       ret = of_property_read_string(node, "allwinner,function", &function);
147 -       if (ret) {
148 -               dev_err(pctl->dev,
149 -                       "missing allwinner,function property in node %s\n",
150 +       function = sunxi_pctrl_parse_function_prop(node);
151 +       if (!function) {
152 +               dev_err(pctl->dev, "missing function property in node %s\n",
153                         node->name);
154                 return -EINVAL;
155         }
156  
157 -       nmaps = of_property_count_strings(node, "allwinner,pins") * 2;
158 -       if (nmaps < 0) {
159 -               dev_err(pctl->dev,
160 -                       "missing allwinner,pins property in node %s\n",
161 +       pin_prop = sunxi_pctrl_find_pins_prop(node, &npins);
162 +       if (!pin_prop) {
163 +               dev_err(pctl->dev, "missing pins property in node %s\n",
164                         node->name);
165                 return -EINVAL;
166         }
167  
168 +       /*
169 +        * We have two maps for each pin: one for the function, one
170 +        * for the configuration (bias, strength, etc)
171 +        */
172 +       nmaps = npins * 2;
173         *map = kmalloc(nmaps * sizeof(struct pinctrl_map), GFP_KERNEL);
174         if (!*map)
175                 return -ENOMEM;
176  
177 -       of_property_for_each_string(node, "allwinner,pins", prop, group) {
178 +       pinconfig = sunxi_pctrl_build_pin_config(node, &configlen);
179 +       if (!pinconfig) {
180 +               ret = -EINVAL;
181 +               goto err_free_map;
182 +       }
183 +
184 +       of_property_for_each_string(node, pin_prop, prop, group) {
185                 struct sunxi_pinctrl_group *grp =
186                         sunxi_pinctrl_find_group_by_name(pctl, group);
187 -               int j = 0, configlen = 0;
188  
189                 if (!grp) {
190                         dev_err(pctl->dev, "unknown pin %s", group);
191 @@ -207,34 +318,6 @@ static int sunxi_pctrl_dt_node_to_map(st
192  
193                 (*map)[i].type = PIN_MAP_TYPE_CONFIGS_GROUP;
194                 (*map)[i].data.configs.group_or_pin = group;
195 -
196 -               if (of_find_property(node, "allwinner,drive", NULL))
197 -                       configlen++;
198 -               if (of_find_property(node, "allwinner,pull", NULL))
199 -                       configlen++;
200 -
201 -               pinconfig = kzalloc(configlen * sizeof(*pinconfig), GFP_KERNEL);
202 -               if (!pinconfig) {
203 -                       kfree(*map);
204 -                       return -ENOMEM;
205 -               }
206 -
207 -               if (!of_property_read_u32(node, "allwinner,drive", &val)) {
208 -                       u16 strength = (val + 1) * 10;
209 -                       pinconfig[j++] =
210 -                               pinconf_to_config_packed(PIN_CONFIG_DRIVE_STRENGTH,
211 -                                                        strength);
212 -               }
213 -
214 -               if (!of_property_read_u32(node, "allwinner,pull", &val)) {
215 -                       enum pin_config_param pull = PIN_CONFIG_END;
216 -                       if (val == 1)
217 -                               pull = PIN_CONFIG_BIAS_PULL_UP;
218 -                       else if (val == 2)
219 -                               pull = PIN_CONFIG_BIAS_PULL_DOWN;
220 -                       pinconfig[j++] = pinconf_to_config_packed(pull, 0);
221 -               }
222 -
223                 (*map)[i].data.configs.configs = pinconfig;
224                 (*map)[i].data.configs.num_configs = configlen;
225  
226 @@ -244,19 +327,18 @@ static int sunxi_pctrl_dt_node_to_map(st
227         *num_maps = nmaps;
228  
229         return 0;
230 +
231 +err_free_map:
232 +       kfree(map);
233 +       return ret;
234  }
235  
236  static void sunxi_pctrl_dt_free_map(struct pinctrl_dev *pctldev,
237                                     struct pinctrl_map *map,
238                                     unsigned num_maps)
239  {
240 -       int i;
241 -
242 -       for (i = 0; i < num_maps; i++) {
243 -               if (map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP)
244 -                       kfree(map[i].data.configs.configs);
245 -       }
246 -
247 +       /* All the maps have the same pin config, free only the first one */
248 +       kfree(map[0].data.configs.configs);
249         kfree(map);
250  }
251