diff options
Diffstat (limited to 'drivers/pinctrl/core.c')
-rw-r--r-- | drivers/pinctrl/core.c | 92 |
1 files changed, 66 insertions, 26 deletions
diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index b3eec63c00ba..73b78d6eac67 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -1256,6 +1256,20 @@ static void pinctrl_link_add(struct pinctrl_dev *pctldev, DL_FLAG_AUTOREMOVE_CONSUMER); } +static void pinctrl_cond_disable_mux_setting(struct pinctrl_state *state, + struct pinctrl_setting *target_setting) +{ + struct pinctrl_setting *setting; + + list_for_each_entry(setting, &state->settings, node) { + if (target_setting && (&setting->node == &target_setting->node)) + break; + + if (setting->type == PIN_MAP_TYPE_MUX_GROUP) + pinmux_disable_setting(setting); + } +} + /** * pinctrl_commit_state() - select/activate/program a pinctrl state to HW * @p: the pinctrl handle for the device that requests configuration @@ -1263,7 +1277,7 @@ static void pinctrl_link_add(struct pinctrl_dev *pctldev, */ static int pinctrl_commit_state(struct pinctrl *p, struct pinctrl_state *state) { - struct pinctrl_setting *setting, *setting2; + struct pinctrl_setting *setting; struct pinctrl_state *old_state = READ_ONCE(p->state); int ret; @@ -1274,11 +1288,7 @@ static int pinctrl_commit_state(struct pinctrl *p, struct pinctrl_state *state) * still owned by the new state will be re-acquired by the call * to pinmux_enable_setting() in the loop below. */ - list_for_each_entry(setting, &old_state->settings, node) { - if (setting->type != PIN_MAP_TYPE_MUX_GROUP) - continue; - pinmux_disable_setting(setting); - } + pinctrl_cond_disable_mux_setting(old_state, NULL); } p->state = NULL; @@ -1322,7 +1332,7 @@ static int pinctrl_commit_state(struct pinctrl *p, struct pinctrl_state *state) } if (ret < 0) { - goto unapply_new_state; + goto unapply_mux_setting; } /* Do not link hogs (circular dependency) */ @@ -1334,23 +1344,23 @@ static int pinctrl_commit_state(struct pinctrl *p, struct pinctrl_state *state) return 0; +unapply_mux_setting: + pinctrl_cond_disable_mux_setting(state, NULL); + goto restore_old_state; + unapply_new_state: dev_err(p->dev, "Error applying setting, reverse things back\n"); - list_for_each_entry(setting2, &state->settings, node) { - if (&setting2->node == &setting->node) - break; - /* - * All we can do here is pinmux_disable_setting. - * That means that some pins are muxed differently now - * than they were before applying the setting (We can't - * "unmux a pin"!), but it's not a big deal since the pins - * are free to be muxed by another apply_setting. - */ - if (setting2->type == PIN_MAP_TYPE_MUX_GROUP) - pinmux_disable_setting(setting2); - } + /* + * All we can do here is pinmux_disable_setting. + * That means that some pins are muxed differently now + * than they were before applying the setting (We can't + * "unmux a pin"!), but it's not a big deal since the pins + * are free to be muxed by another apply_setting. + */ + pinctrl_cond_disable_mux_setting(state, setting); +restore_old_state: /* There's no infinite recursive loop here because p->state is NULL */ if (old_state) pinctrl_select_state(p, old_state); @@ -1520,6 +1530,35 @@ void pinctrl_unregister_mappings(const struct pinctrl_map *map) } EXPORT_SYMBOL_GPL(pinctrl_unregister_mappings); +static void devm_pinctrl_unregister_mappings(void *maps) +{ + pinctrl_unregister_mappings(maps); +} + +/** + * devm_pinctrl_register_mappings() - Resource managed pinctrl_register_mappings() + * @dev: device for which mappings are registered + * @maps: the pincontrol mappings table to register. Note the pinctrl-core + * keeps a reference to the passed in maps, so they should _not_ be + * marked with __initdata. + * @num_maps: the number of maps in the mapping table + * + * Returns: 0 on success, or negative errno on failure. + */ +int devm_pinctrl_register_mappings(struct device *dev, + const struct pinctrl_map *maps, + unsigned int num_maps) +{ + int ret; + + ret = pinctrl_register_mappings(maps, num_maps); + if (ret) + return ret; + + return devm_add_action_or_reset(dev, devm_pinctrl_unregister_mappings, (void *)maps); +} +EXPORT_SYMBOL_GPL(devm_pinctrl_register_mappings); + /** * pinctrl_force_sleep() - turn a given controller device into sleep state * @pctldev: pin controller device @@ -2023,7 +2062,7 @@ static int pinctrl_check_ops(struct pinctrl_dev *pctldev) * @driver_data: private pin controller data for this pin controller */ static struct pinctrl_dev * -pinctrl_init_controller(struct pinctrl_desc *pctldesc, struct device *dev, +pinctrl_init_controller(const struct pinctrl_desc *pctldesc, struct device *dev, void *driver_data) { struct pinctrl_dev *pctldev; @@ -2093,7 +2132,8 @@ out_err: return ERR_PTR(ret); } -static void pinctrl_uninit_controller(struct pinctrl_dev *pctldev, struct pinctrl_desc *pctldesc) +static void pinctrl_uninit_controller(struct pinctrl_dev *pctldev, + const struct pinctrl_desc *pctldesc) { pinctrl_free_pindescs(pctldev, pctldesc->pins, pctldesc->npins); @@ -2170,7 +2210,7 @@ EXPORT_SYMBOL_GPL(pinctrl_enable); * struct pinctrl_dev handle. To avoid issues later on, please use the * new pinctrl_register_and_init() below instead. */ -struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc, +struct pinctrl_dev *pinctrl_register(const struct pinctrl_desc *pctldesc, struct device *dev, void *driver_data) { struct pinctrl_dev *pctldev; @@ -2200,7 +2240,7 @@ EXPORT_SYMBOL_GPL(pinctrl_register); * Note that pinctrl_enable() still needs to be manually called after * this once the driver is ready. */ -int pinctrl_register_and_init(struct pinctrl_desc *pctldesc, +int pinctrl_register_and_init(const struct pinctrl_desc *pctldesc, struct device *dev, void *driver_data, struct pinctrl_dev **pctldev) { @@ -2291,7 +2331,7 @@ static int devm_pinctrl_dev_match(struct device *dev, void *res, void *data) * The pinctrl device will be automatically released when the device is unbound. */ struct pinctrl_dev *devm_pinctrl_register(struct device *dev, - struct pinctrl_desc *pctldesc, + const struct pinctrl_desc *pctldesc, void *driver_data) { struct pinctrl_dev **ptr, *pctldev; @@ -2325,7 +2365,7 @@ EXPORT_SYMBOL_GPL(devm_pinctrl_register); * The pinctrl device will be automatically released when the device is unbound. */ int devm_pinctrl_register_and_init(struct device *dev, - struct pinctrl_desc *pctldesc, + const struct pinctrl_desc *pctldesc, void *driver_data, struct pinctrl_dev **pctldev) { |