diff options
author | Richard Genoud <richard.genoud@gmail.com> | 2013-03-25 10:47:22 -0400 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2013-03-27 18:17:12 -0400 |
commit | 3102a76cfbf9ac4ae0cf54c7452f7ba4292a4760 (patch) | |
tree | c7ae2486f3c0cd31476546993906de4f9b199315 /drivers/pinctrl | |
parent | d3cee8305b48316ea416a73c763be3cb04bbc82b (diff) |
pinctrl: disable and free setting in select_state in case of error
If enabling a pin fails in pinctrl_select_state_locked(), all the
previous enabled pins have to be disabled to get back to the previous
state.
Signed-off-by: Richard Genoud <richard.genoud@gmail.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/pinctrl')
-rw-r--r-- | drivers/pinctrl/core.c | 28 |
1 files changed, 25 insertions, 3 deletions
diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index 971234599d72..09f79f251800 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c | |||
@@ -930,7 +930,7 @@ static int pinctrl_select_state_locked(struct pinctrl *p, | |||
930 | } | 930 | } |
931 | } | 931 | } |
932 | 932 | ||
933 | p->state = state; | 933 | p->state = NULL; |
934 | 934 | ||
935 | /* Apply all the settings for the new state */ | 935 | /* Apply all the settings for the new state */ |
936 | list_for_each_entry(setting, &state->settings, node) { | 936 | list_for_each_entry(setting, &state->settings, node) { |
@@ -946,13 +946,35 @@ static int pinctrl_select_state_locked(struct pinctrl *p, | |||
946 | ret = -EINVAL; | 946 | ret = -EINVAL; |
947 | break; | 947 | break; |
948 | } | 948 | } |
949 | |||
949 | if (ret < 0) { | 950 | if (ret < 0) { |
950 | /* FIXME: Difficult to return to prev state */ | 951 | goto unapply_new_state; |
951 | return ret; | ||
952 | } | 952 | } |
953 | } | 953 | } |
954 | 954 | ||
955 | p->state = state; | ||
956 | |||
955 | return 0; | 957 | return 0; |
958 | |||
959 | unapply_new_state: | ||
960 | pr_info("Error applying setting, reverse things back\n"); | ||
961 | |||
962 | /* | ||
963 | * If the loop stopped on the 1st entry, nothing has been enabled, | ||
964 | * so jump directly to the 2nd phase | ||
965 | */ | ||
966 | if (list_entry(&setting->node, typeof(*setting), node) == | ||
967 | list_first_entry(&state->settings, typeof(*setting), node)) | ||
968 | goto reapply_old_state; | ||
969 | |||
970 | list_for_each_entry(setting2, &state->settings, node) { | ||
971 | if (&setting2->node == &setting->node) | ||
972 | break; | ||
973 | pinctrl_free_setting(true, setting2); | ||
974 | } | ||
975 | reapply_old_state: | ||
976 | /* FIXME: re-enable old setting */ | ||
977 | return ret; | ||
956 | } | 978 | } |
957 | 979 | ||
958 | /** | 980 | /** |