diff options
author | Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> | 2013-06-17 14:50:03 -0400 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2013-06-18 04:57:59 -0400 |
commit | 12f3ad8df7f58c61ff16ea851541583693d965e1 (patch) | |
tree | 8842483822ff6fd4c60b769088452e7d113b47bb /drivers/pinctrl/sh-pfc/pinctrl.c | |
parent | fe1c9a822ce72c6ec8476a2501c412265ee2172c (diff) |
sh-pfc: Add pinconf support to DT bindings
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Acked-by: Heiko Stuebner <heiko@sntech.de>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/pinctrl/sh-pfc/pinctrl.c')
-rw-r--r-- | drivers/pinctrl/sh-pfc/pinctrl.c | 109 |
1 files changed, 97 insertions, 12 deletions
diff --git a/drivers/pinctrl/sh-pfc/pinctrl.c b/drivers/pinctrl/sh-pfc/pinctrl.c index 7e32bb8c08dd..2cf23476adf8 100644 --- a/drivers/pinctrl/sh-pfc/pinctrl.c +++ b/drivers/pinctrl/sh-pfc/pinctrl.c | |||
@@ -74,6 +74,27 @@ static void sh_pfc_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, | |||
74 | seq_printf(s, "%s", DRV_NAME); | 74 | seq_printf(s, "%s", DRV_NAME); |
75 | } | 75 | } |
76 | 76 | ||
77 | static int sh_pfc_map_add_config(struct pinctrl_map *map, | ||
78 | const char *group_or_pin, | ||
79 | enum pinctrl_map_type type, | ||
80 | unsigned long *configs, | ||
81 | unsigned int num_configs) | ||
82 | { | ||
83 | unsigned long *cfgs; | ||
84 | |||
85 | cfgs = kmemdup(configs, num_configs * sizeof(*cfgs), | ||
86 | GFP_KERNEL); | ||
87 | if (cfgs == NULL) | ||
88 | return -ENOMEM; | ||
89 | |||
90 | map->type = type; | ||
91 | map->data.configs.group_or_pin = group_or_pin; | ||
92 | map->data.configs.configs = cfgs; | ||
93 | map->data.configs.num_configs = num_configs; | ||
94 | |||
95 | return 0; | ||
96 | } | ||
97 | |||
77 | static int sh_pfc_dt_subnode_to_map(struct device *dev, struct device_node *np, | 98 | static int sh_pfc_dt_subnode_to_map(struct device *dev, struct device_node *np, |
78 | struct pinctrl_map **map, | 99 | struct pinctrl_map **map, |
79 | unsigned int *num_maps, unsigned int *index) | 100 | unsigned int *num_maps, unsigned int *index) |
@@ -81,9 +102,14 @@ static int sh_pfc_dt_subnode_to_map(struct device *dev, struct device_node *np, | |||
81 | struct pinctrl_map *maps = *map; | 102 | struct pinctrl_map *maps = *map; |
82 | unsigned int nmaps = *num_maps; | 103 | unsigned int nmaps = *num_maps; |
83 | unsigned int idx = *index; | 104 | unsigned int idx = *index; |
105 | unsigned int num_configs; | ||
84 | const char *function = NULL; | 106 | const char *function = NULL; |
107 | unsigned long *configs; | ||
85 | struct property *prop; | 108 | struct property *prop; |
109 | unsigned int num_groups; | ||
110 | unsigned int num_pins; | ||
86 | const char *group; | 111 | const char *group; |
112 | const char *pin; | ||
87 | int ret; | 113 | int ret; |
88 | 114 | ||
89 | /* Parse the function and configuration properties. At least a function | 115 | /* Parse the function and configuration properties. At least a function |
@@ -95,25 +121,47 @@ static int sh_pfc_dt_subnode_to_map(struct device *dev, struct device_node *np, | |||
95 | return ret; | 121 | return ret; |
96 | } | 122 | } |
97 | 123 | ||
98 | if (!function) { | 124 | ret = pinconf_generic_parse_dt_config(np, &configs, &num_configs); |
99 | dev_err(dev, "DT node must contain at least one function\n"); | 125 | if (ret < 0) |
126 | return ret; | ||
127 | |||
128 | if (!function && num_configs == 0) { | ||
129 | dev_err(dev, | ||
130 | "DT node must contain at least a function or config\n"); | ||
100 | goto done; | 131 | goto done; |
101 | } | 132 | } |
102 | 133 | ||
103 | /* Count the number of groups and reallocate mappings. */ | 134 | /* Count the number of pins and groups and reallocate mappings. */ |
135 | ret = of_property_count_strings(np, "renesas,pins"); | ||
136 | if (ret == -EINVAL) { | ||
137 | num_pins = 0; | ||
138 | } else if (ret < 0) { | ||
139 | dev_err(dev, "Invalid pins list in DT\n"); | ||
140 | goto done; | ||
141 | } else { | ||
142 | num_pins = ret; | ||
143 | } | ||
144 | |||
104 | ret = of_property_count_strings(np, "renesas,groups"); | 145 | ret = of_property_count_strings(np, "renesas,groups"); |
105 | if (ret < 0 && ret != -EINVAL) { | 146 | if (ret == -EINVAL) { |
147 | num_groups = 0; | ||
148 | } else if (ret < 0) { | ||
106 | dev_err(dev, "Invalid pin groups list in DT\n"); | 149 | dev_err(dev, "Invalid pin groups list in DT\n"); |
107 | goto done; | 150 | goto done; |
151 | } else { | ||
152 | num_groups = ret; | ||
108 | } | 153 | } |
109 | 154 | ||
110 | if (!ret) { | 155 | if (!num_pins && !num_groups) { |
111 | dev_err(dev, "No group provided in DT node\n"); | 156 | dev_err(dev, "No pin or group provided in DT node\n"); |
112 | ret = -ENODEV; | 157 | ret = -ENODEV; |
113 | goto done; | 158 | goto done; |
114 | } | 159 | } |
115 | 160 | ||
116 | nmaps += ret; | 161 | if (function) |
162 | nmaps += num_groups; | ||
163 | if (configs) | ||
164 | nmaps += num_pins + num_groups; | ||
117 | 165 | ||
118 | maps = krealloc(maps, sizeof(*maps) * nmaps, GFP_KERNEL); | 166 | maps = krealloc(maps, sizeof(*maps) * nmaps, GFP_KERNEL); |
119 | if (maps == NULL) { | 167 | if (maps == NULL) { |
@@ -126,22 +174,59 @@ static int sh_pfc_dt_subnode_to_map(struct device *dev, struct device_node *np, | |||
126 | 174 | ||
127 | /* Iterate over pins and groups and create the mappings. */ | 175 | /* Iterate over pins and groups and create the mappings. */ |
128 | of_property_for_each_string(np, "renesas,groups", prop, group) { | 176 | of_property_for_each_string(np, "renesas,groups", prop, group) { |
129 | maps[idx].type = PIN_MAP_TYPE_MUX_GROUP; | 177 | if (function) { |
130 | maps[idx].data.mux.group = group; | 178 | maps[idx].type = PIN_MAP_TYPE_MUX_GROUP; |
131 | maps[idx].data.mux.function = function; | 179 | maps[idx].data.mux.group = group; |
132 | idx++; | 180 | maps[idx].data.mux.function = function; |
181 | idx++; | ||
182 | } | ||
183 | |||
184 | if (configs) { | ||
185 | ret = sh_pfc_map_add_config(&maps[idx], group, | ||
186 | PIN_MAP_TYPE_CONFIGS_GROUP, | ||
187 | configs, num_configs); | ||
188 | if (ret < 0) | ||
189 | goto done; | ||
190 | |||
191 | idx++; | ||
192 | } | ||
133 | } | 193 | } |
134 | 194 | ||
135 | ret = 0; | 195 | if (!configs) { |
196 | ret = 0; | ||
197 | goto done; | ||
198 | } | ||
199 | |||
200 | of_property_for_each_string(np, "renesas,pins", prop, pin) { | ||
201 | ret = sh_pfc_map_add_config(&maps[idx], pin, | ||
202 | PIN_MAP_TYPE_CONFIGS_PIN, | ||
203 | configs, num_configs); | ||
204 | if (ret < 0) | ||
205 | goto done; | ||
206 | |||
207 | idx++; | ||
208 | } | ||
136 | 209 | ||
137 | done: | 210 | done: |
138 | *index = idx; | 211 | *index = idx; |
212 | kfree(configs); | ||
139 | return ret; | 213 | return ret; |
140 | } | 214 | } |
141 | 215 | ||
142 | static void sh_pfc_dt_free_map(struct pinctrl_dev *pctldev, | 216 | static void sh_pfc_dt_free_map(struct pinctrl_dev *pctldev, |
143 | struct pinctrl_map *map, unsigned num_maps) | 217 | struct pinctrl_map *map, unsigned num_maps) |
144 | { | 218 | { |
219 | unsigned int i; | ||
220 | |||
221 | if (map == NULL) | ||
222 | return; | ||
223 | |||
224 | for (i = 0; i < num_maps; ++i) { | ||
225 | if (map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP || | ||
226 | map[i].type == PIN_MAP_TYPE_CONFIGS_PIN) | ||
227 | kfree(map[i].data.configs.configs); | ||
228 | } | ||
229 | |||
145 | kfree(map); | 230 | kfree(map); |
146 | } | 231 | } |
147 | 232 | ||