|
@@ -27,6 +27,7 @@
|
|
|
#include <linux/err.h>
|
|
|
#include <linux/gpio.h>
|
|
|
#include <linux/irqdomain.h>
|
|
|
+#include <linux/spinlock.h>
|
|
|
|
|
|
#include "core.h"
|
|
|
#include "pinctrl-samsung.h"
|
|
@@ -289,6 +290,7 @@ static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector,
|
|
|
struct samsung_pin_bank *bank;
|
|
|
void __iomem *reg;
|
|
|
u32 mask, shift, data, pin_offset, cnt;
|
|
|
+ unsigned long flags;
|
|
|
|
|
|
drvdata = pinctrl_dev_get_drvdata(pctldev);
|
|
|
pins = drvdata->pin_groups[group].pins;
|
|
@@ -303,11 +305,15 @@ static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector,
|
|
|
mask = (1 << bank->func_width) - 1;
|
|
|
shift = pin_offset * bank->func_width;
|
|
|
|
|
|
+ spin_lock_irqsave(&bank->slock, flags);
|
|
|
+
|
|
|
data = readl(reg);
|
|
|
data &= ~(mask << shift);
|
|
|
if (enable)
|
|
|
data |= drvdata->pin_groups[group].func << shift;
|
|
|
writel(data, reg);
|
|
|
+
|
|
|
+ spin_unlock_irqrestore(&bank->slock, flags);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -338,6 +344,7 @@ static int samsung_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev,
|
|
|
struct samsung_pinctrl_drv_data *drvdata;
|
|
|
void __iomem *reg;
|
|
|
u32 data, pin_offset, mask, shift;
|
|
|
+ unsigned long flags;
|
|
|
|
|
|
bank = gc_to_pin_bank(range->gc);
|
|
|
drvdata = pinctrl_dev_get_drvdata(pctldev);
|
|
@@ -348,11 +355,16 @@ static int samsung_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev,
|
|
|
mask = (1 << bank->func_width) - 1;
|
|
|
shift = pin_offset * bank->func_width;
|
|
|
|
|
|
+ spin_lock_irqsave(&bank->slock, flags);
|
|
|
+
|
|
|
data = readl(reg);
|
|
|
data &= ~(mask << shift);
|
|
|
if (!input)
|
|
|
data |= FUNC_OUTPUT << shift;
|
|
|
writel(data, reg);
|
|
|
+
|
|
|
+ spin_unlock_irqrestore(&bank->slock, flags);
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -376,6 +388,7 @@ static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin,
|
|
|
enum pincfg_type cfg_type = PINCFG_UNPACK_TYPE(*config);
|
|
|
u32 data, width, pin_offset, mask, shift;
|
|
|
u32 cfg_value, cfg_reg;
|
|
|
+ unsigned long flags;
|
|
|
|
|
|
drvdata = pinctrl_dev_get_drvdata(pctldev);
|
|
|
pin_to_reg_bank(drvdata, pin - drvdata->ctrl->base, ®_base,
|
|
@@ -406,6 +419,8 @@ static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin,
|
|
|
if (!width)
|
|
|
return -EINVAL;
|
|
|
|
|
|
+ spin_lock_irqsave(&bank->slock, flags);
|
|
|
+
|
|
|
mask = (1 << width) - 1;
|
|
|
shift = pin_offset * width;
|
|
|
data = readl(reg_base + cfg_reg);
|
|
@@ -420,6 +435,9 @@ static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin,
|
|
|
data &= mask;
|
|
|
*config = PINCFG_PACK(cfg_type, data);
|
|
|
}
|
|
|
+
|
|
|
+ spin_unlock_irqrestore(&bank->slock, flags);
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -479,16 +497,21 @@ static const struct pinconf_ops samsung_pinconf_ops = {
|
|
|
static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
|
|
|
{
|
|
|
struct samsung_pin_bank *bank = gc_to_pin_bank(gc);
|
|
|
+ unsigned long flags;
|
|
|
void __iomem *reg;
|
|
|
u32 data;
|
|
|
|
|
|
reg = bank->drvdata->virt_base + bank->pctl_offset;
|
|
|
|
|
|
+ spin_lock_irqsave(&bank->slock, flags);
|
|
|
+
|
|
|
data = readl(reg + DAT_REG);
|
|
|
data &= ~(1 << offset);
|
|
|
if (value)
|
|
|
data |= 1 << offset;
|
|
|
writel(data, reg + DAT_REG);
|
|
|
+
|
|
|
+ spin_unlock_irqrestore(&bank->slock, flags);
|
|
|
}
|
|
|
|
|
|
/* gpiolib gpio_get callback function */
|
|
@@ -859,6 +882,7 @@ static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data(
|
|
|
|
|
|
bank = ctrl->pin_banks;
|
|
|
for (i = 0; i < ctrl->nr_banks; ++i, ++bank) {
|
|
|
+ spin_lock_init(&bank->slock);
|
|
|
bank->drvdata = d;
|
|
|
bank->pin_base = ctrl->nr_pins;
|
|
|
ctrl->nr_pins += bank->nr_pins;
|