pinctrl: samsung: Protect bank registers with a spinlock

Certain pin control registers can be accessed from different contexts,
i.e. pinctrl, gpio and irq functions. This makes the locking provided by
pin control core insufficient.

This patch adds necessary locking using a per bank spinlock as it was
done in the old Samsung GPIO driver.

Signed-off-by: Tomasz Figa <tomasz.figa@gmail.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
diff --git a/drivers/pinctrl/pinctrl-exynos.c b/drivers/pinctrl/pinctrl-exynos.c
index 538b9dd..cf7700e 100644
--- a/drivers/pinctrl/pinctrl-exynos.c
+++ b/drivers/pinctrl/pinctrl-exynos.c
@@ -26,6 +26,7 @@
 #include <linux/of_irq.h>
 #include <linux/io.h>
 #include <linux/slab.h>
+#include <linux/spinlock.h>
 #include <linux/err.h>
 
 #include <asm/mach/irq.h>
@@ -81,6 +82,7 @@
 	unsigned int shift = EXYNOS_EINT_CON_LEN * pin;
 	unsigned int con, trig_type;
 	unsigned long reg_con = ctrl->geint_con + bank->eint_offset;
+	unsigned long flags;
 	unsigned int mask;
 
 	switch (type) {
@@ -118,11 +120,15 @@
 	shift = pin * bank->func_width;
 	mask = (1 << bank->func_width) - 1;
 
+	spin_lock_irqsave(&bank->slock, flags);
+
 	con = readl(d->virt_base + reg_con);
 	con &= ~(mask << shift);
 	con |= EXYNOS_EINT_FUNC << shift;
 	writel(con, d->virt_base + reg_con);
 
+	spin_unlock_irqrestore(&bank->slock, flags);
+
 	return 0;
 }
 
@@ -258,6 +264,7 @@
 	unsigned long reg_con = d->ctrl->weint_con + bank->eint_offset;
 	unsigned long shift = EXYNOS_EINT_CON_LEN * pin;
 	unsigned long con, trig_type;
+	unsigned long flags;
 	unsigned int mask;
 
 	switch (type) {
@@ -295,11 +302,15 @@
 	shift = pin * bank->func_width;
 	mask = (1 << bank->func_width) - 1;
 
+	spin_lock_irqsave(&bank->slock, flags);
+
 	con = readl(d->virt_base + reg_con);
 	con &= ~(mask << shift);
 	con |= EXYNOS_EINT_FUNC << shift;
 	writel(con, d->virt_base + reg_con);
 
+	spin_unlock_irqrestore(&bank->slock, flags);
+
 	return 0;
 }