aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pinctrl
diff options
context:
space:
mode:
authorRichard Genoud <richard.genoud@gmail.com>2013-03-25 10:47:22 -0400
committerLinus Walleij <linus.walleij@linaro.org>2013-03-27 18:17:12 -0400
commit3102a76cfbf9ac4ae0cf54c7452f7ba4292a4760 (patch)
treec7ae2486f3c0cd31476546993906de4f9b199315 /drivers/pinctrl
parentd3cee8305b48316ea416a73c763be3cb04bbc82b (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.c28
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
959unapply_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 }
975reapply_old_state:
976 /* FIXME: re-enable old setting */
977 return ret;
956} 978}
957 979
958/** 980/**