diff options
Diffstat (limited to 'drivers/pinctrl')
-rw-r--r-- | drivers/pinctrl/pinctrl-samsung.c | 613 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-samsung.h | 1 |
2 files changed, 362 insertions, 252 deletions
diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c index a09d8209ac2c..b7de66c3b51d 100644 --- a/drivers/pinctrl/pinctrl-samsung.c +++ b/drivers/pinctrl/pinctrl-samsung.c | |||
@@ -40,9 +40,9 @@ | |||
40 | 40 | ||
41 | /* list of all possible config options supported */ | 41 | /* list of all possible config options supported */ |
42 | static struct pin_config { | 42 | static struct pin_config { |
43 | char *prop_cfg; | 43 | const char *property; |
44 | unsigned int cfg_type; | 44 | enum pincfg_type param; |
45 | } pcfgs[] = { | 45 | } cfg_params[] = { |
46 | { "samsung,pin-pud", PINCFG_TYPE_PUD }, | 46 | { "samsung,pin-pud", PINCFG_TYPE_PUD }, |
47 | { "samsung,pin-drv", PINCFG_TYPE_DRV }, | 47 | { "samsung,pin-drv", PINCFG_TYPE_DRV }, |
48 | { "samsung,pin-con-pdn", PINCFG_TYPE_CON_PDN }, | 48 | { "samsung,pin-con-pdn", PINCFG_TYPE_CON_PDN }, |
@@ -59,163 +59,242 @@ static inline struct samsung_pin_bank *gc_to_pin_bank(struct gpio_chip *gc) | |||
59 | return container_of(gc, struct samsung_pin_bank, gpio_chip); | 59 | return container_of(gc, struct samsung_pin_bank, gpio_chip); |
60 | } | 60 | } |
61 | 61 | ||
62 | /* check if the selector is a valid pin group selector */ | ||
63 | static int samsung_get_group_count(struct pinctrl_dev *pctldev) | 62 | static int samsung_get_group_count(struct pinctrl_dev *pctldev) |
64 | { | 63 | { |
65 | struct samsung_pinctrl_drv_data *drvdata; | 64 | struct samsung_pinctrl_drv_data *pmx = pinctrl_dev_get_drvdata(pctldev); |
66 | 65 | ||
67 | drvdata = pinctrl_dev_get_drvdata(pctldev); | 66 | return pmx->nr_groups; |
68 | return drvdata->nr_groups; | ||
69 | } | 67 | } |
70 | 68 | ||
71 | /* return the name of the group selected by the group selector */ | ||
72 | static const char *samsung_get_group_name(struct pinctrl_dev *pctldev, | 69 | static const char *samsung_get_group_name(struct pinctrl_dev *pctldev, |
73 | unsigned selector) | 70 | unsigned group) |
74 | { | 71 | { |
75 | struct samsung_pinctrl_drv_data *drvdata; | 72 | struct samsung_pinctrl_drv_data *pmx = pinctrl_dev_get_drvdata(pctldev); |
76 | 73 | ||
77 | drvdata = pinctrl_dev_get_drvdata(pctldev); | 74 | return pmx->pin_groups[group].name; |
78 | return drvdata->pin_groups[selector].name; | ||
79 | } | 75 | } |
80 | 76 | ||
81 | /* return the pin numbers associated with the specified group */ | ||
82 | static int samsung_get_group_pins(struct pinctrl_dev *pctldev, | 77 | static int samsung_get_group_pins(struct pinctrl_dev *pctldev, |
83 | unsigned selector, const unsigned **pins, unsigned *num_pins) | 78 | unsigned group, |
79 | const unsigned **pins, | ||
80 | unsigned *num_pins) | ||
84 | { | 81 | { |
85 | struct samsung_pinctrl_drv_data *drvdata; | 82 | struct samsung_pinctrl_drv_data *pmx = pinctrl_dev_get_drvdata(pctldev); |
83 | |||
84 | *pins = pmx->pin_groups[group].pins; | ||
85 | *num_pins = pmx->pin_groups[group].num_pins; | ||
86 | 86 | ||
87 | drvdata = pinctrl_dev_get_drvdata(pctldev); | ||
88 | *pins = drvdata->pin_groups[selector].pins; | ||
89 | *num_pins = drvdata->pin_groups[selector].num_pins; | ||
90 | return 0; | 87 | return 0; |
91 | } | 88 | } |
92 | 89 | ||
93 | /* create pinctrl_map entries by parsing device tree nodes */ | 90 | static int reserve_map(struct device *dev, struct pinctrl_map **map, |
94 | static int samsung_dt_node_to_map(struct pinctrl_dev *pctldev, | 91 | unsigned *reserved_maps, unsigned *num_maps, |
95 | struct device_node *np, struct pinctrl_map **maps, | 92 | unsigned reserve) |
96 | unsigned *nmaps) | ||
97 | { | 93 | { |
98 | struct device *dev = pctldev->dev; | 94 | unsigned old_num = *reserved_maps; |
99 | struct pinctrl_map *map; | 95 | unsigned new_num = *num_maps + reserve; |
100 | unsigned long *cfg = NULL; | 96 | struct pinctrl_map *new_map; |
101 | char *gname, *fname; | ||
102 | int cfg_cnt = 0, map_cnt = 0, idx = 0; | ||
103 | |||
104 | /* count the number of config options specfied in the node */ | ||
105 | for (idx = 0; idx < ARRAY_SIZE(pcfgs); idx++) { | ||
106 | if (of_find_property(np, pcfgs[idx].prop_cfg, NULL)) | ||
107 | cfg_cnt++; | ||
108 | } | ||
109 | 97 | ||
110 | /* | 98 | if (old_num >= new_num) |
111 | * Find out the number of map entries to create. All the config options | 99 | return 0; |
112 | * can be accomadated into a single config map entry. | ||
113 | */ | ||
114 | if (cfg_cnt) | ||
115 | map_cnt = 1; | ||
116 | if (of_find_property(np, "samsung,pin-function", NULL)) | ||
117 | map_cnt++; | ||
118 | if (!map_cnt) { | ||
119 | dev_err(dev, "node %s does not have either config or function " | ||
120 | "configurations\n", np->name); | ||
121 | return -EINVAL; | ||
122 | } | ||
123 | 100 | ||
124 | /* Allocate memory for pin-map entries */ | 101 | new_map = krealloc(*map, sizeof(*new_map) * new_num, GFP_KERNEL); |
125 | map = kzalloc(sizeof(*map) * map_cnt, GFP_KERNEL); | 102 | if (!new_map) { |
126 | if (!map) { | 103 | dev_err(dev, "krealloc(map) failed\n"); |
127 | dev_err(dev, "could not alloc memory for pin-maps\n"); | ||
128 | return -ENOMEM; | 104 | return -ENOMEM; |
129 | } | 105 | } |
130 | *nmaps = 0; | ||
131 | 106 | ||
132 | /* | 107 | memset(new_map + old_num, 0, (new_num - old_num) * sizeof(*new_map)); |
133 | * Allocate memory for pin group name. The pin group name is derived | 108 | |
134 | * from the node name from which these map entries are be created. | 109 | *map = new_map; |
135 | */ | 110 | *reserved_maps = new_num; |
136 | gname = kzalloc(strlen(np->name) + GSUFFIX_LEN, GFP_KERNEL); | 111 | |
137 | if (!gname) { | 112 | return 0; |
138 | dev_err(dev, "failed to alloc memory for group name\n"); | 113 | } |
139 | goto free_map; | 114 | |
115 | static int add_map_mux(struct pinctrl_map **map, unsigned *reserved_maps, | ||
116 | unsigned *num_maps, const char *group, | ||
117 | const char *function) | ||
118 | { | ||
119 | if (WARN_ON(*num_maps == *reserved_maps)) | ||
120 | return -ENOSPC; | ||
121 | |||
122 | (*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP; | ||
123 | (*map)[*num_maps].data.mux.group = group; | ||
124 | (*map)[*num_maps].data.mux.function = function; | ||
125 | (*num_maps)++; | ||
126 | |||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | static int add_map_configs(struct device *dev, struct pinctrl_map **map, | ||
131 | unsigned *reserved_maps, unsigned *num_maps, | ||
132 | const char *group, unsigned long *configs, | ||
133 | unsigned num_configs) | ||
134 | { | ||
135 | unsigned long *dup_configs; | ||
136 | |||
137 | if (WARN_ON(*num_maps == *reserved_maps)) | ||
138 | return -ENOSPC; | ||
139 | |||
140 | dup_configs = kmemdup(configs, num_configs * sizeof(*dup_configs), | ||
141 | GFP_KERNEL); | ||
142 | if (!dup_configs) { | ||
143 | dev_err(dev, "kmemdup(configs) failed\n"); | ||
144 | return -ENOMEM; | ||
140 | } | 145 | } |
141 | sprintf(gname, "%s%s", np->name, GROUP_SUFFIX); | ||
142 | 146 | ||
143 | /* | 147 | (*map)[*num_maps].type = PIN_MAP_TYPE_CONFIGS_GROUP; |
144 | * don't have config options? then skip over to creating function | 148 | (*map)[*num_maps].data.configs.group_or_pin = group; |
145 | * map entries. | 149 | (*map)[*num_maps].data.configs.configs = dup_configs; |
146 | */ | 150 | (*map)[*num_maps].data.configs.num_configs = num_configs; |
147 | if (!cfg_cnt) | 151 | (*num_maps)++; |
148 | goto skip_cfgs; | 152 | |
149 | 153 | return 0; | |
150 | /* Allocate memory for config entries */ | 154 | } |
151 | cfg = kzalloc(sizeof(*cfg) * cfg_cnt, GFP_KERNEL); | 155 | |
152 | if (!cfg) { | 156 | static int add_config(struct device *dev, unsigned long **configs, |
153 | dev_err(dev, "failed to alloc memory for configs\n"); | 157 | unsigned *num_configs, unsigned long config) |
154 | goto free_gname; | 158 | { |
159 | unsigned old_num = *num_configs; | ||
160 | unsigned new_num = old_num + 1; | ||
161 | unsigned long *new_configs; | ||
162 | |||
163 | new_configs = krealloc(*configs, sizeof(*new_configs) * new_num, | ||
164 | GFP_KERNEL); | ||
165 | if (!new_configs) { | ||
166 | dev_err(dev, "krealloc(configs) failed\n"); | ||
167 | return -ENOMEM; | ||
155 | } | 168 | } |
156 | 169 | ||
157 | /* Prepare a list of config settings */ | 170 | new_configs[old_num] = config; |
158 | for (idx = 0, cfg_cnt = 0; idx < ARRAY_SIZE(pcfgs); idx++) { | 171 | |
159 | u32 value; | 172 | *configs = new_configs; |
160 | if (!of_property_read_u32(np, pcfgs[idx].prop_cfg, &value)) | 173 | *num_configs = new_num; |
161 | cfg[cfg_cnt++] = | 174 | |
162 | PINCFG_PACK(pcfgs[idx].cfg_type, value); | 175 | return 0; |
176 | } | ||
177 | |||
178 | static void samsung_dt_free_map(struct pinctrl_dev *pctldev, | ||
179 | struct pinctrl_map *map, | ||
180 | unsigned num_maps) | ||
181 | { | ||
182 | int i; | ||
183 | |||
184 | for (i = 0; i < num_maps; i++) | ||
185 | if (map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP) | ||
186 | kfree(map[i].data.configs.configs); | ||
187 | |||
188 | kfree(map); | ||
189 | } | ||
190 | |||
191 | static int samsung_dt_subnode_to_map(struct samsung_pinctrl_drv_data *drvdata, | ||
192 | struct device *dev, | ||
193 | struct device_node *np, | ||
194 | struct pinctrl_map **map, | ||
195 | unsigned *reserved_maps, | ||
196 | unsigned *num_maps) | ||
197 | { | ||
198 | int ret, i; | ||
199 | u32 val; | ||
200 | unsigned long config; | ||
201 | unsigned long *configs = NULL; | ||
202 | unsigned num_configs = 0; | ||
203 | unsigned reserve; | ||
204 | struct property *prop; | ||
205 | const char *group; | ||
206 | bool has_func = false; | ||
207 | |||
208 | ret = of_property_read_u32(np, "samsung,pin-function", &val); | ||
209 | if (!ret) | ||
210 | has_func = true; | ||
211 | |||
212 | for (i = 0; i < ARRAY_SIZE(cfg_params); i++) { | ||
213 | ret = of_property_read_u32(np, cfg_params[i].property, &val); | ||
214 | if (!ret) { | ||
215 | config = PINCFG_PACK(cfg_params[i].param, val); | ||
216 | ret = add_config(dev, &configs, &num_configs, config); | ||
217 | if (ret < 0) | ||
218 | goto exit; | ||
219 | /* EINVAL=missing, which is fine since it's optional */ | ||
220 | } else if (ret != -EINVAL) { | ||
221 | dev_err(dev, "could not parse property %s\n", | ||
222 | cfg_params[i].property); | ||
223 | } | ||
163 | } | 224 | } |
164 | 225 | ||
165 | /* create the config map entry */ | 226 | reserve = 0; |
166 | map[*nmaps].data.configs.group_or_pin = gname; | 227 | if (has_func) |
167 | map[*nmaps].data.configs.configs = cfg; | 228 | reserve++; |
168 | map[*nmaps].data.configs.num_configs = cfg_cnt; | 229 | if (num_configs) |
169 | map[*nmaps].type = PIN_MAP_TYPE_CONFIGS_GROUP; | 230 | reserve++; |
170 | *nmaps += 1; | 231 | ret = of_property_count_strings(np, "samsung,pins"); |
171 | 232 | if (ret < 0) { | |
172 | skip_cfgs: | 233 | dev_err(dev, "could not parse property samsung,pins\n"); |
173 | /* create the function map entry */ | 234 | goto exit; |
174 | if (of_find_property(np, "samsung,pin-function", NULL)) { | 235 | } |
175 | fname = kzalloc(strlen(np->name) + FSUFFIX_LEN, GFP_KERNEL); | 236 | reserve *= ret; |
176 | if (!fname) { | 237 | |
177 | dev_err(dev, "failed to alloc memory for func name\n"); | 238 | ret = reserve_map(dev, map, reserved_maps, num_maps, reserve); |
178 | goto free_cfg; | 239 | if (ret < 0) |
240 | goto exit; | ||
241 | |||
242 | of_property_for_each_string(np, "samsung,pins", prop, group) { | ||
243 | if (has_func) { | ||
244 | ret = add_map_mux(map, reserved_maps, | ||
245 | num_maps, group, np->full_name); | ||
246 | if (ret < 0) | ||
247 | goto exit; | ||
179 | } | 248 | } |
180 | sprintf(fname, "%s%s", np->name, FUNCTION_SUFFIX); | ||
181 | 249 | ||
182 | map[*nmaps].data.mux.group = gname; | 250 | if (num_configs) { |
183 | map[*nmaps].data.mux.function = fname; | 251 | ret = add_map_configs(dev, map, reserved_maps, |
184 | map[*nmaps].type = PIN_MAP_TYPE_MUX_GROUP; | 252 | num_maps, group, configs, |
185 | *nmaps += 1; | 253 | num_configs); |
254 | if (ret < 0) | ||
255 | goto exit; | ||
256 | } | ||
186 | } | 257 | } |
187 | 258 | ||
188 | *maps = map; | 259 | ret = 0; |
189 | return 0; | ||
190 | 260 | ||
191 | free_cfg: | 261 | exit: |
192 | kfree(cfg); | 262 | kfree(configs); |
193 | free_gname: | 263 | return ret; |
194 | kfree(gname); | ||
195 | free_map: | ||
196 | kfree(map); | ||
197 | return -ENOMEM; | ||
198 | } | 264 | } |
199 | 265 | ||
200 | /* free the memory allocated to hold the pin-map table */ | 266 | static int samsung_dt_node_to_map(struct pinctrl_dev *pctldev, |
201 | static void samsung_dt_free_map(struct pinctrl_dev *pctldev, | 267 | struct device_node *np_config, |
202 | struct pinctrl_map *map, unsigned num_maps) | 268 | struct pinctrl_map **map, |
269 | unsigned *num_maps) | ||
203 | { | 270 | { |
204 | int idx; | 271 | struct samsung_pinctrl_drv_data *drvdata; |
205 | 272 | unsigned reserved_maps; | |
206 | for (idx = 0; idx < num_maps; idx++) { | 273 | struct device_node *np; |
207 | if (map[idx].type == PIN_MAP_TYPE_MUX_GROUP) { | 274 | int ret; |
208 | kfree(map[idx].data.mux.function); | 275 | |
209 | if (!idx) | 276 | drvdata = pinctrl_dev_get_drvdata(pctldev); |
210 | kfree(map[idx].data.mux.group); | 277 | |
211 | } else if (map->type == PIN_MAP_TYPE_CONFIGS_GROUP) { | 278 | reserved_maps = 0; |
212 | kfree(map[idx].data.configs.configs); | 279 | *map = NULL; |
213 | if (!idx) | 280 | *num_maps = 0; |
214 | kfree(map[idx].data.configs.group_or_pin); | 281 | |
282 | if (!of_get_child_count(np_config)) | ||
283 | return samsung_dt_subnode_to_map(drvdata, pctldev->dev, | ||
284 | np_config, map, | ||
285 | &reserved_maps, | ||
286 | num_maps); | ||
287 | |||
288 | for_each_child_of_node(np_config, np) { | ||
289 | ret = samsung_dt_subnode_to_map(drvdata, pctldev->dev, np, map, | ||
290 | &reserved_maps, num_maps); | ||
291 | if (ret < 0) { | ||
292 | samsung_dt_free_map(pctldev, *map, *num_maps); | ||
293 | return ret; | ||
215 | } | 294 | } |
216 | }; | 295 | } |
217 | 296 | ||
218 | kfree(map); | 297 | return 0; |
219 | } | 298 | } |
220 | 299 | ||
221 | /* list of pinctrl callbacks for the pinctrl core */ | 300 | /* list of pinctrl callbacks for the pinctrl core */ |
@@ -286,43 +365,38 @@ static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector, | |||
286 | unsigned group, bool enable) | 365 | unsigned group, bool enable) |
287 | { | 366 | { |
288 | struct samsung_pinctrl_drv_data *drvdata; | 367 | struct samsung_pinctrl_drv_data *drvdata; |
289 | const unsigned int *pins; | 368 | struct samsung_pin_bank_type *type; |
290 | struct samsung_pin_bank *bank; | 369 | struct samsung_pin_bank *bank; |
291 | void __iomem *reg; | 370 | void __iomem *reg; |
292 | u32 mask, shift, data, pin_offset, cnt; | 371 | u32 mask, shift, data, pin_offset; |
293 | unsigned long flags; | 372 | unsigned long flags; |
373 | const struct samsung_pmx_func *func; | ||
374 | const struct samsung_pin_group *grp; | ||
294 | 375 | ||
295 | drvdata = pinctrl_dev_get_drvdata(pctldev); | 376 | drvdata = pinctrl_dev_get_drvdata(pctldev); |
296 | pins = drvdata->pin_groups[group].pins; | 377 | func = &drvdata->pmx_functions[selector]; |
378 | grp = &drvdata->pin_groups[group]; | ||
297 | 379 | ||
298 | /* | 380 | pin_to_reg_bank(drvdata, grp->pins[0] - drvdata->ctrl->base, |
299 | * for each pin in the pin group selected, program the correspoding pin | 381 | ®, &pin_offset, &bank); |
300 | * pin function number in the config register. | 382 | type = bank->type; |
301 | */ | 383 | mask = (1 << type->fld_width[PINCFG_TYPE_FUNC]) - 1; |
302 | for (cnt = 0; cnt < drvdata->pin_groups[group].num_pins; cnt++) { | 384 | shift = pin_offset * type->fld_width[PINCFG_TYPE_FUNC]; |
303 | struct samsung_pin_bank_type *type; | 385 | if (shift >= 32) { |
304 | 386 | /* Some banks have two config registers */ | |
305 | pin_to_reg_bank(drvdata, pins[cnt] - drvdata->ctrl->base, | 387 | shift -= 32; |
306 | ®, &pin_offset, &bank); | 388 | reg += 4; |
307 | type = bank->type; | 389 | } |
308 | mask = (1 << type->fld_width[PINCFG_TYPE_FUNC]) - 1; | ||
309 | shift = pin_offset * type->fld_width[PINCFG_TYPE_FUNC]; | ||
310 | if (shift >= 32) { | ||
311 | /* Some banks have two config registers */ | ||
312 | shift -= 32; | ||
313 | reg += 4; | ||
314 | } | ||
315 | 390 | ||
316 | spin_lock_irqsave(&bank->slock, flags); | 391 | spin_lock_irqsave(&bank->slock, flags); |
317 | 392 | ||
318 | data = readl(reg + type->reg_offset[PINCFG_TYPE_FUNC]); | 393 | data = readl(reg + type->reg_offset[PINCFG_TYPE_FUNC]); |
319 | data &= ~(mask << shift); | 394 | data &= ~(mask << shift); |
320 | if (enable) | 395 | if (enable) |
321 | data |= drvdata->pin_groups[group].func << shift; | 396 | data |= func->val << shift; |
322 | writel(data, reg + type->reg_offset[PINCFG_TYPE_FUNC]); | 397 | writel(data, reg + type->reg_offset[PINCFG_TYPE_FUNC]); |
323 | 398 | ||
324 | spin_unlock_irqrestore(&bank->slock, flags); | 399 | spin_unlock_irqrestore(&bank->slock, flags); |
325 | } | ||
326 | } | 400 | } |
327 | 401 | ||
328 | /* enable a specified pinmux by writing to registers */ | 402 | /* enable a specified pinmux by writing to registers */ |
@@ -559,87 +633,115 @@ static int samsung_gpio_to_irq(struct gpio_chip *gc, unsigned offset) | |||
559 | return (virq) ? : -ENXIO; | 633 | return (virq) ? : -ENXIO; |
560 | } | 634 | } |
561 | 635 | ||
562 | /* | 636 | static struct samsung_pin_group *samsung_pinctrl_create_groups( |
563 | * Parse the pin names listed in the 'samsung,pins' property and convert it | 637 | struct device *dev, |
564 | * into a list of gpio numbers are create a pin group from it. | 638 | struct samsung_pinctrl_drv_data *drvdata, |
565 | */ | 639 | unsigned int *cnt) |
566 | static int samsung_pinctrl_parse_dt_pins(struct platform_device *pdev, | ||
567 | struct device_node *cfg_np, | ||
568 | struct pinctrl_desc *pctl, | ||
569 | unsigned int **pin_list, | ||
570 | unsigned int *npins) | ||
571 | { | 640 | { |
572 | struct device *dev = &pdev->dev; | 641 | struct pinctrl_desc *ctrldesc = &drvdata->pctl; |
573 | struct property *prop; | 642 | struct samsung_pin_group *groups, *grp; |
574 | struct pinctrl_pin_desc const *pdesc = pctl->pins; | 643 | const struct pinctrl_pin_desc *pdesc; |
575 | unsigned int idx = 0, cnt; | 644 | int i; |
576 | const char *pin_name; | 645 | |
646 | groups = devm_kzalloc(dev, ctrldesc->npins * sizeof(*groups), | ||
647 | GFP_KERNEL); | ||
648 | if (!groups) | ||
649 | return ERR_PTR(-EINVAL); | ||
650 | grp = groups; | ||
651 | |||
652 | pdesc = ctrldesc->pins; | ||
653 | for (i = 0; i < ctrldesc->npins; ++i, ++pdesc, ++grp) { | ||
654 | grp->name = pdesc->name; | ||
655 | grp->pins = &pdesc->number; | ||
656 | grp->num_pins = 1; | ||
657 | } | ||
658 | |||
659 | *cnt = ctrldesc->npins; | ||
660 | return groups; | ||
661 | } | ||
577 | 662 | ||
578 | *npins = of_property_count_strings(cfg_np, "samsung,pins"); | 663 | static int samsung_pinctrl_create_function(struct device *dev, |
579 | if (IS_ERR_VALUE(*npins)) { | 664 | struct samsung_pinctrl_drv_data *drvdata, |
580 | dev_err(dev, "invalid pin list in %s node", cfg_np->name); | 665 | struct device_node *func_np, |
666 | struct samsung_pmx_func *func) | ||
667 | { | ||
668 | int npins; | ||
669 | int ret; | ||
670 | int i; | ||
671 | |||
672 | if (of_property_read_u32(func_np, "samsung,pin-function", &func->val)) | ||
673 | return 0; | ||
674 | |||
675 | npins = of_property_count_strings(func_np, "samsung,pins"); | ||
676 | if (npins < 1) { | ||
677 | dev_err(dev, "invalid pin list in %s node", func_np->name); | ||
581 | return -EINVAL; | 678 | return -EINVAL; |
582 | } | 679 | } |
583 | 680 | ||
584 | *pin_list = devm_kzalloc(dev, *npins * sizeof(**pin_list), GFP_KERNEL); | 681 | func->name = func_np->full_name; |
585 | if (!*pin_list) { | 682 | |
586 | dev_err(dev, "failed to allocate memory for pin list\n"); | 683 | func->groups = devm_kzalloc(dev, npins * sizeof(char *), GFP_KERNEL); |
684 | if (!func->groups) | ||
587 | return -ENOMEM; | 685 | return -ENOMEM; |
588 | } | ||
589 | 686 | ||
590 | of_property_for_each_string(cfg_np, "samsung,pins", prop, pin_name) { | 687 | for (i = 0; i < npins; ++i) { |
591 | for (cnt = 0; cnt < pctl->npins; cnt++) { | 688 | const char *gname; |
592 | if (pdesc[cnt].name) { | 689 | |
593 | if (!strcmp(pin_name, pdesc[cnt].name)) { | 690 | ret = of_property_read_string_index(func_np, "samsung,pins", |
594 | (*pin_list)[idx++] = pdesc[cnt].number; | 691 | i, &gname); |
595 | break; | 692 | if (ret) { |
596 | } | 693 | dev_err(dev, |
597 | } | 694 | "failed to read pin name %d from %s node\n", |
598 | } | 695 | i, func_np->name); |
599 | if (cnt == pctl->npins) { | 696 | return ret; |
600 | dev_err(dev, "pin %s not valid in %s node\n", | ||
601 | pin_name, cfg_np->name); | ||
602 | devm_kfree(dev, *pin_list); | ||
603 | return -EINVAL; | ||
604 | } | 697 | } |
698 | |||
699 | func->groups[i] = gname; | ||
605 | } | 700 | } |
606 | 701 | ||
607 | return 0; | 702 | func->num_groups = npins; |
703 | return 1; | ||
608 | } | 704 | } |
609 | 705 | ||
610 | /* | 706 | static struct samsung_pmx_func *samsung_pinctrl_create_functions( |
611 | * Parse the information about all the available pin groups and pin functions | 707 | struct device *dev, |
612 | * from device node of the pin-controller. A pin group is formed with all | 708 | struct samsung_pinctrl_drv_data *drvdata, |
613 | * the pins listed in the "samsung,pins" property. | 709 | unsigned int *cnt) |
614 | */ | ||
615 | static int samsung_pinctrl_parse_dt(struct platform_device *pdev, | ||
616 | struct samsung_pinctrl_drv_data *drvdata) | ||
617 | { | 710 | { |
618 | struct device *dev = &pdev->dev; | 711 | struct samsung_pmx_func *functions, *func; |
619 | struct device_node *dev_np = dev->of_node; | 712 | struct device_node *dev_np = dev->of_node; |
620 | struct device_node *cfg_np; | 713 | struct device_node *cfg_np; |
621 | struct samsung_pin_group *groups, *grp; | 714 | unsigned int func_cnt = 0; |
622 | struct samsung_pmx_func *functions, *func; | ||
623 | unsigned *pin_list; | ||
624 | unsigned int npins, grp_cnt, func_idx = 0; | ||
625 | char *gname, *fname; | ||
626 | int ret; | 715 | int ret; |
627 | 716 | ||
628 | grp_cnt = of_get_child_count(dev_np); | 717 | /* |
629 | if (!grp_cnt) | 718 | * Iterate over all the child nodes of the pin controller node |
630 | return -EINVAL; | 719 | * and create pin groups and pin function lists. |
720 | */ | ||
721 | for_each_child_of_node(dev_np, cfg_np) { | ||
722 | struct device_node *func_np; | ||
631 | 723 | ||
632 | groups = devm_kzalloc(dev, grp_cnt * sizeof(*groups), GFP_KERNEL); | 724 | if (!of_get_child_count(cfg_np)) { |
633 | if (!groups) { | 725 | if (!of_find_property(cfg_np, |
634 | dev_err(dev, "failed allocate memory for ping group list\n"); | 726 | "samsung,pin-function", NULL)) |
635 | return -EINVAL; | 727 | continue; |
728 | ++func_cnt; | ||
729 | continue; | ||
730 | } | ||
731 | |||
732 | for_each_child_of_node(cfg_np, func_np) { | ||
733 | if (!of_find_property(func_np, | ||
734 | "samsung,pin-function", NULL)) | ||
735 | continue; | ||
736 | ++func_cnt; | ||
737 | } | ||
636 | } | 738 | } |
637 | grp = groups; | ||
638 | 739 | ||
639 | functions = devm_kzalloc(dev, grp_cnt * sizeof(*functions), GFP_KERNEL); | 740 | functions = devm_kzalloc(dev, func_cnt * sizeof(*functions), |
741 | GFP_KERNEL); | ||
640 | if (!functions) { | 742 | if (!functions) { |
641 | dev_err(dev, "failed to allocate memory for function list\n"); | 743 | dev_err(dev, "failed to allocate memory for function list\n"); |
642 | return -EINVAL; | 744 | return ERR_PTR(-EINVAL); |
643 | } | 745 | } |
644 | func = functions; | 746 | func = functions; |
645 | 747 | ||
@@ -647,61 +749,68 @@ static int samsung_pinctrl_parse_dt(struct platform_device *pdev, | |||
647 | * Iterate over all the child nodes of the pin controller node | 749 | * Iterate over all the child nodes of the pin controller node |
648 | * and create pin groups and pin function lists. | 750 | * and create pin groups and pin function lists. |
649 | */ | 751 | */ |
752 | func_cnt = 0; | ||
650 | for_each_child_of_node(dev_np, cfg_np) { | 753 | for_each_child_of_node(dev_np, cfg_np) { |
651 | u32 function; | 754 | struct device_node *func_np; |
652 | if (!of_find_property(cfg_np, "samsung,pins", NULL)) | 755 | |
756 | if (!of_get_child_count(cfg_np)) { | ||
757 | ret = samsung_pinctrl_create_function(dev, drvdata, | ||
758 | cfg_np, func); | ||
759 | if (ret < 0) | ||
760 | return ERR_PTR(ret); | ||
761 | if (ret > 0) { | ||
762 | ++func; | ||
763 | ++func_cnt; | ||
764 | } | ||
653 | continue; | 765 | continue; |
766 | } | ||
654 | 767 | ||
655 | ret = samsung_pinctrl_parse_dt_pins(pdev, cfg_np, | 768 | for_each_child_of_node(cfg_np, func_np) { |
656 | &drvdata->pctl, &pin_list, &npins); | 769 | ret = samsung_pinctrl_create_function(dev, drvdata, |
657 | if (ret) | 770 | func_np, func); |
658 | return ret; | 771 | if (ret < 0) |
659 | 772 | return ERR_PTR(ret); | |
660 | /* derive pin group name from the node name */ | 773 | if (ret > 0) { |
661 | gname = devm_kzalloc(dev, strlen(cfg_np->name) + GSUFFIX_LEN, | 774 | ++func; |
662 | GFP_KERNEL); | 775 | ++func_cnt; |
663 | if (!gname) { | 776 | } |
664 | dev_err(dev, "failed to alloc memory for group name\n"); | ||
665 | return -ENOMEM; | ||
666 | } | 777 | } |
667 | sprintf(gname, "%s%s", cfg_np->name, GROUP_SUFFIX); | 778 | } |
668 | 779 | ||
669 | grp->name = gname; | 780 | *cnt = func_cnt; |
670 | grp->pins = pin_list; | 781 | return functions; |
671 | grp->num_pins = npins; | 782 | } |
672 | of_property_read_u32(cfg_np, "samsung,pin-function", &function); | ||
673 | grp->func = function; | ||
674 | grp++; | ||
675 | 783 | ||
676 | if (!of_find_property(cfg_np, "samsung,pin-function", NULL)) | 784 | /* |
677 | continue; | 785 | * Parse the information about all the available pin groups and pin functions |
786 | * from device node of the pin-controller. A pin group is formed with all | ||
787 | * the pins listed in the "samsung,pins" property. | ||
788 | */ | ||
678 | 789 | ||
679 | /* derive function name from the node name */ | 790 | static int samsung_pinctrl_parse_dt(struct platform_device *pdev, |
680 | fname = devm_kzalloc(dev, strlen(cfg_np->name) + FSUFFIX_LEN, | 791 | struct samsung_pinctrl_drv_data *drvdata) |
681 | GFP_KERNEL); | 792 | { |
682 | if (!fname) { | 793 | struct device *dev = &pdev->dev; |
683 | dev_err(dev, "failed to alloc memory for func name\n"); | 794 | struct samsung_pin_group *groups; |
684 | return -ENOMEM; | 795 | struct samsung_pmx_func *functions; |
685 | } | 796 | unsigned int grp_cnt = 0, func_cnt = 0; |
686 | sprintf(fname, "%s%s", cfg_np->name, FUNCTION_SUFFIX); | 797 | |
687 | 798 | groups = samsung_pinctrl_create_groups(dev, drvdata, &grp_cnt); | |
688 | func->name = fname; | 799 | if (IS_ERR(groups)) { |
689 | func->groups = devm_kzalloc(dev, sizeof(char *), GFP_KERNEL); | 800 | dev_err(dev, "failed to parse pin groups\n"); |
690 | if (!func->groups) { | 801 | return PTR_ERR(groups); |
691 | dev_err(dev, "failed to alloc memory for group list " | 802 | } |
692 | "in pin function"); | 803 | |
693 | return -ENOMEM; | 804 | functions = samsung_pinctrl_create_functions(dev, drvdata, &func_cnt); |
694 | } | 805 | if (IS_ERR(functions)) { |
695 | func->groups[0] = gname; | 806 | dev_err(dev, "failed to parse pin functions\n"); |
696 | func->num_groups = 1; | 807 | return PTR_ERR(groups); |
697 | func++; | ||
698 | func_idx++; | ||
699 | } | 808 | } |
700 | 809 | ||
701 | drvdata->pin_groups = groups; | 810 | drvdata->pin_groups = groups; |
702 | drvdata->nr_groups = grp_cnt; | 811 | drvdata->nr_groups = grp_cnt; |
703 | drvdata->pmx_functions = functions; | 812 | drvdata->pmx_functions = functions; |
704 | drvdata->nr_functions = func_idx; | 813 | drvdata->nr_functions = func_cnt; |
705 | 814 | ||
706 | return 0; | 815 | return 0; |
707 | } | 816 | } |
diff --git a/drivers/pinctrl/pinctrl-samsung.h b/drivers/pinctrl/pinctrl-samsung.h index e2dce4731a01..2b882320e8e9 100644 --- a/drivers/pinctrl/pinctrl-samsung.h +++ b/drivers/pinctrl/pinctrl-samsung.h | |||
@@ -231,6 +231,7 @@ struct samsung_pmx_func { | |||
231 | const char *name; | 231 | const char *name; |
232 | const char **groups; | 232 | const char **groups; |
233 | u8 num_groups; | 233 | u8 num_groups; |
234 | u32 val; | ||
234 | }; | 235 | }; |
235 | 236 | ||
236 | /* list of all exported SoC specific data */ | 237 | /* list of all exported SoC specific data */ |