diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index b7a6bab4ac01436e782e9236f6d87a6d513df03c..118c4975c777543bfd22368b41eec50ffcef026a 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -220,6 +220,9 @@ static int pinctrl_register_one_pin(struct pinctrl_dev *pctldev, /* Set owner */ pindesc->pctldev = pctldev; +#ifdef CONFIG_PINMUX + mutex_init(&pindesc->mux_lock); +#endif /* Copy basic pin info */ if (pin->name) { diff --git a/drivers/pinctrl/core.h b/drivers/pinctrl/core.h index 840103c40c14ad6a6b5965c9d4ec516ef97707f9..f5e4ca19c17b20a3eeb64ebb7218f1f11d543bfd 100644 --- a/drivers/pinctrl/core.h +++ b/drivers/pinctrl/core.h @@ -167,6 +167,7 @@ struct pin_desc { const char *mux_owner; const struct pinctrl_setting_mux *mux_setting; const char *gpio_owner; + struct mutex mux_lock; #endif }; diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c index bab888fe3f8e32f0148c7719a183a8d81056f0c8..bfab925dbf0424ab6135997f9d57d149d4136ed8 100644 --- a/drivers/pinctrl/pinmux.c +++ b/drivers/pinctrl/pinmux.c @@ -27,6 +27,7 @@ #include #include "core.h" #include "pinmux.h" +#include int pinmux_check_ops(struct pinctrl_dev *pctldev) { @@ -89,9 +90,11 @@ bool pinmux_can_be_used_for_gpio(struct pinctrl_dev *pctldev, unsigned pin) if (!desc || !ops) return true; + mutex_lock(&desc->mux_lock); if (ops->strict && desc->mux_usecount) return false; + mutex_unlock(&desc->mux_lock); return !(ops->strict && !!desc->gpio_owner); } @@ -123,6 +126,7 @@ static int pin_request(struct pinctrl_dev *pctldev, dev_dbg(pctldev->dev, "request pin %d (%s) for %s\n", pin, desc->name, owner); + mutex_lock(&desc->mux_lock); if ((!gpio_range || ops->strict) && desc->mux_usecount && strcmp(desc->mux_owner, owner)) { dev_err(pctldev->dev, @@ -147,6 +151,7 @@ static int pin_request(struct pinctrl_dev *pctldev, desc->mux_owner = owner; } + mutex_unlock(&desc->mux_lock); /* Let each pin increase references to this module */ if (!try_module_get(pctldev->owner)) { @@ -176,6 +181,7 @@ static int pin_request(struct pinctrl_dev *pctldev, out_free_pin: if (status) { + mutex_lock(&desc->mux_lock); if (gpio_range) { desc->gpio_owner = NULL; } else { @@ -183,6 +189,7 @@ static int pin_request(struct pinctrl_dev *pctldev, if (!desc->mux_usecount) desc->mux_owner = NULL; } + mutex_unlock(&desc->mux_lock); } out: if (status) @@ -237,6 +244,7 @@ static const char *pin_free(struct pinctrl_dev *pctldev, int pin, else if (ops->free) ops->free(pctldev, pin); + mutex_lock(&desc->mux_lock); if (gpio_range) { owner = desc->gpio_owner; desc->gpio_owner = NULL; @@ -245,6 +253,7 @@ static const char *pin_free(struct pinctrl_dev *pctldev, int pin, desc->mux_owner = NULL; desc->mux_setting = NULL; } + mutex_unlock(&desc->mux_lock); module_put(pctldev->owner); @@ -457,7 +466,9 @@ int pinmux_enable_setting(const struct pinctrl_setting *setting) pins[i]); continue; } + mutex_lock(&desc->mux_lock); desc->mux_setting = &(setting->data.mux); + mutex_unlock(&desc->mux_lock); } ret = ops->set_mux(pctldev, setting->data.mux.func, @@ -471,8 +482,11 @@ int pinmux_enable_setting(const struct pinctrl_setting *setting) err_set_mux: for (i = 0; i < num_pins; i++) { desc = pin_desc_get(pctldev, pins[i]); - if (desc) + if (desc) { + mutex_lock(&desc->mux_lock); desc->mux_setting = NULL; + mutex_unlock(&desc->mux_lock); + } } err_pin_request: /* On error release all taken pins */ @@ -491,6 +505,7 @@ void pinmux_disable_setting(const struct pinctrl_setting *setting) unsigned num_pins = 0; int i; struct pin_desc *desc; + bool is_equal; if (pctlops->get_group_pins) ret = pctlops->get_group_pins(pctldev, setting->data.mux.group, @@ -516,7 +531,11 @@ void pinmux_disable_setting(const struct pinctrl_setting *setting) pins[i]); continue; } - if (desc->mux_setting == &(setting->data.mux)) { + mutex_lock(&desc->mux_lock); + is_equal = (desc->mux_setting == &(setting->data.mux)); + mutex_unlock(&desc->mux_lock); + + if (is_equal) { pin_free(pctldev, pins[i], NULL); } else { const char *gname; @@ -608,6 +627,7 @@ static int pinmux_pins_show(struct seq_file *s, void *what) if (desc == NULL) continue; + mutex_lock(&desc->mux_lock); if (desc->mux_owner && !strcmp(desc->mux_owner, pinctrl_dev_get_name(pctldev))) is_hog = true; @@ -642,6 +662,7 @@ static int pinmux_pins_show(struct seq_file *s, void *what) desc->mux_setting->group)); else seq_putc(s, '\n'); + mutex_unlock(&desc->mux_lock); } mutex_unlock(&pctldev->mutex);