diff options
author | Stephen Warren <swarren@nvidia.com> | 2012-03-02 15:05:48 -0500 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2012-03-05 05:25:11 -0500 |
commit | 1e2082b520721734c358f776d34a069867214c8e (patch) | |
tree | 4d11e15a4127ad69faf7555864480a6fafe5422c /drivers/pinctrl/pinconf.c | |
parent | 6e5e959dde0d92d177f035652aeaa77f9330c9c6 (diff) |
pinctrl: enhance mapping table to support pin config operations
The pinctrl mapping table can now contain entries to:
* Set the mux function of a pin group
* Apply a set of pin config options to a pin or a group
This allows pinctrl_select_state() to apply pin configs settings as well
as mux settings.
v3: Fix find_pinctrl() to iterate over the correct list.
s/_MUX_CONFIGS_/_CONFIGS_/ in mapping table macros.
Fix documentation to use correct mapping table macro.
v2: Added numerous extra PIN_MAP_*() special-case macros.
Fixed kerneldoc typo. Delete pinctrl_get_pin_id() and
replace it with pin_get_from_name(). Various minor fixes.
Updates due to rebase.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Acked-by: Dong Aisheng <dong.aisheng@linaro.org>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/pinctrl/pinconf.c')
-rw-r--r-- | drivers/pinctrl/pinconf.c | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/drivers/pinctrl/pinconf.c b/drivers/pinctrl/pinconf.c index e0a453790a40..84869f28b101 100644 --- a/drivers/pinctrl/pinconf.c +++ b/drivers/pinctrl/pinconf.c | |||
@@ -36,6 +36,24 @@ int pinconf_check_ops(struct pinctrl_dev *pctldev) | |||
36 | return 0; | 36 | return 0; |
37 | } | 37 | } |
38 | 38 | ||
39 | int pinconf_validate_map(struct pinctrl_map const *map, int i) | ||
40 | { | ||
41 | if (!map->data.configs.group_or_pin) { | ||
42 | pr_err("failed to register map %s (%d): no group/pin given\n", | ||
43 | map->name, i); | ||
44 | return -EINVAL; | ||
45 | } | ||
46 | |||
47 | if (map->data.configs.num_configs && | ||
48 | !map->data.configs.configs) { | ||
49 | pr_err("failed to register map %s (%d): no configs ptr given\n", | ||
50 | map->name, i); | ||
51 | return -EINVAL; | ||
52 | } | ||
53 | |||
54 | return 0; | ||
55 | } | ||
56 | |||
39 | static int pin_config_get_for_pin(struct pinctrl_dev *pctldev, unsigned pin, | 57 | static int pin_config_get_for_pin(struct pinctrl_dev *pctldev, unsigned pin, |
40 | unsigned long *config) | 58 | unsigned long *config) |
41 | { | 59 | { |
@@ -260,8 +278,155 @@ unlock: | |||
260 | } | 278 | } |
261 | EXPORT_SYMBOL(pin_config_group_set); | 279 | EXPORT_SYMBOL(pin_config_group_set); |
262 | 280 | ||
281 | int pinconf_map_to_setting(struct pinctrl_map const *map, | ||
282 | struct pinctrl_setting *setting) | ||
283 | { | ||
284 | struct pinctrl_dev *pctldev = setting->pctldev; | ||
285 | |||
286 | switch (setting->type) { | ||
287 | case PIN_MAP_TYPE_CONFIGS_PIN: | ||
288 | setting->data.configs.group_or_pin = | ||
289 | pin_get_from_name(pctldev, | ||
290 | map->data.configs.group_or_pin); | ||
291 | if (setting->data.configs.group_or_pin < 0) | ||
292 | return setting->data.configs.group_or_pin; | ||
293 | break; | ||
294 | case PIN_MAP_TYPE_CONFIGS_GROUP: | ||
295 | setting->data.configs.group_or_pin = | ||
296 | pinctrl_get_group_selector(pctldev, | ||
297 | map->data.configs.group_or_pin); | ||
298 | if (setting->data.configs.group_or_pin < 0) | ||
299 | return setting->data.configs.group_or_pin; | ||
300 | break; | ||
301 | default: | ||
302 | return -EINVAL; | ||
303 | } | ||
304 | |||
305 | setting->data.configs.num_configs = map->data.configs.num_configs; | ||
306 | setting->data.configs.configs = map->data.configs.configs; | ||
307 | |||
308 | return 0; | ||
309 | } | ||
310 | |||
311 | void pinconf_free_setting(struct pinctrl_setting const *setting) | ||
312 | { | ||
313 | } | ||
314 | |||
315 | int pinconf_apply_setting(struct pinctrl_setting const *setting) | ||
316 | { | ||
317 | struct pinctrl_dev *pctldev = setting->pctldev; | ||
318 | const struct pinconf_ops *ops = pctldev->desc->confops; | ||
319 | int i, ret; | ||
320 | |||
321 | if (!ops) { | ||
322 | dev_err(pctldev->dev, "missing confops\n"); | ||
323 | return -EINVAL; | ||
324 | } | ||
325 | |||
326 | switch (setting->type) { | ||
327 | case PIN_MAP_TYPE_CONFIGS_PIN: | ||
328 | if (!ops->pin_config_set) { | ||
329 | dev_err(pctldev->dev, "missing pin_config_set op\n"); | ||
330 | return -EINVAL; | ||
331 | } | ||
332 | for (i = 0; i < setting->data.configs.num_configs; i++) { | ||
333 | ret = ops->pin_config_set(pctldev, | ||
334 | setting->data.configs.group_or_pin, | ||
335 | setting->data.configs.configs[i]); | ||
336 | if (ret < 0) { | ||
337 | dev_err(pctldev->dev, | ||
338 | "pin_config_set op failed for pin %d config %08lx\n", | ||
339 | setting->data.configs.group_or_pin, | ||
340 | setting->data.configs.configs[i]); | ||
341 | return ret; | ||
342 | } | ||
343 | } | ||
344 | break; | ||
345 | case PIN_MAP_TYPE_CONFIGS_GROUP: | ||
346 | if (!ops->pin_config_group_set) { | ||
347 | dev_err(pctldev->dev, | ||
348 | "missing pin_config_group_set op\n"); | ||
349 | return -EINVAL; | ||
350 | } | ||
351 | for (i = 0; i < setting->data.configs.num_configs; i++) { | ||
352 | ret = ops->pin_config_group_set(pctldev, | ||
353 | setting->data.configs.group_or_pin, | ||
354 | setting->data.configs.configs[i]); | ||
355 | if (ret < 0) { | ||
356 | dev_err(pctldev->dev, | ||
357 | "pin_config_group_set op failed for group %d config %08lx\n", | ||
358 | setting->data.configs.group_or_pin, | ||
359 | setting->data.configs.configs[i]); | ||
360 | return ret; | ||
361 | } | ||
362 | } | ||
363 | break; | ||
364 | default: | ||
365 | return -EINVAL; | ||
366 | } | ||
367 | |||
368 | return 0; | ||
369 | } | ||
370 | |||
263 | #ifdef CONFIG_DEBUG_FS | 371 | #ifdef CONFIG_DEBUG_FS |
264 | 372 | ||
373 | void pinconf_show_map(struct seq_file *s, struct pinctrl_map const *map) | ||
374 | { | ||
375 | int i; | ||
376 | |||
377 | switch (map->type) { | ||
378 | case PIN_MAP_TYPE_CONFIGS_PIN: | ||
379 | seq_printf(s, "pin "); | ||
380 | break; | ||
381 | case PIN_MAP_TYPE_CONFIGS_GROUP: | ||
382 | seq_printf(s, "group "); | ||
383 | break; | ||
384 | default: | ||
385 | break; | ||
386 | } | ||
387 | |||
388 | seq_printf(s, "%s\n", map->data.configs.group_or_pin); | ||
389 | |||
390 | for (i = 0; i < map->data.configs.num_configs; i++) | ||
391 | seq_printf(s, "config %08lx\n", map->data.configs.configs[i]); | ||
392 | } | ||
393 | |||
394 | void pinconf_show_setting(struct seq_file *s, | ||
395 | struct pinctrl_setting const *setting) | ||
396 | { | ||
397 | struct pinctrl_dev *pctldev = setting->pctldev; | ||
398 | const struct pinctrl_ops *pctlops = pctldev->desc->pctlops; | ||
399 | struct pin_desc *desc; | ||
400 | int i; | ||
401 | |||
402 | switch (setting->type) { | ||
403 | case PIN_MAP_TYPE_CONFIGS_PIN: | ||
404 | desc = pin_desc_get(setting->pctldev, | ||
405 | setting->data.configs.group_or_pin); | ||
406 | seq_printf(s, "pin %s (%d)", | ||
407 | desc->name ? desc->name : "unnamed", | ||
408 | setting->data.configs.group_or_pin); | ||
409 | break; | ||
410 | case PIN_MAP_TYPE_CONFIGS_GROUP: | ||
411 | seq_printf(s, "group %s (%d)", | ||
412 | pctlops->get_group_name(pctldev, | ||
413 | setting->data.configs.group_or_pin), | ||
414 | setting->data.configs.group_or_pin); | ||
415 | break; | ||
416 | default: | ||
417 | break; | ||
418 | } | ||
419 | |||
420 | /* | ||
421 | * FIXME: We should really get the pin controler to dump the config | ||
422 | * values, so they can be decoded to something meaningful. | ||
423 | */ | ||
424 | for (i = 0; i < setting->data.configs.num_configs; i++) | ||
425 | seq_printf(s, " %08lx", setting->data.configs.configs[i]); | ||
426 | |||
427 | seq_printf(s, "\n"); | ||
428 | } | ||
429 | |||
265 | static void pinconf_dump_pin(struct pinctrl_dev *pctldev, | 430 | static void pinconf_dump_pin(struct pinctrl_dev *pctldev, |
266 | struct seq_file *s, int pin) | 431 | struct seq_file *s, int pin) |
267 | { | 432 | { |