diff options
-rw-r--r-- | drivers/pinctrl/pinctrl-exynos.c | 11 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-samsung.c | 24 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-samsung.h | 2 |
3 files changed, 37 insertions, 0 deletions
diff --git a/drivers/pinctrl/pinctrl-exynos.c b/drivers/pinctrl/pinctrl-exynos.c index 538b9ddaadf7..cf7700ed57b8 100644 --- a/drivers/pinctrl/pinctrl-exynos.c +++ b/drivers/pinctrl/pinctrl-exynos.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/of_irq.h> | 26 | #include <linux/of_irq.h> |
27 | #include <linux/io.h> | 27 | #include <linux/io.h> |
28 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
29 | #include <linux/spinlock.h> | ||
29 | #include <linux/err.h> | 30 | #include <linux/err.h> |
30 | 31 | ||
31 | #include <asm/mach/irq.h> | 32 | #include <asm/mach/irq.h> |
@@ -81,6 +82,7 @@ static int exynos_gpio_irq_set_type(struct irq_data *irqd, unsigned int type) | |||
81 | unsigned int shift = EXYNOS_EINT_CON_LEN * pin; | 82 | unsigned int shift = EXYNOS_EINT_CON_LEN * pin; |
82 | unsigned int con, trig_type; | 83 | unsigned int con, trig_type; |
83 | unsigned long reg_con = ctrl->geint_con + bank->eint_offset; | 84 | unsigned long reg_con = ctrl->geint_con + bank->eint_offset; |
85 | unsigned long flags; | ||
84 | unsigned int mask; | 86 | unsigned int mask; |
85 | 87 | ||
86 | switch (type) { | 88 | switch (type) { |
@@ -118,11 +120,15 @@ static int exynos_gpio_irq_set_type(struct irq_data *irqd, unsigned int type) | |||
118 | shift = pin * bank->func_width; | 120 | shift = pin * bank->func_width; |
119 | mask = (1 << bank->func_width) - 1; | 121 | mask = (1 << bank->func_width) - 1; |
120 | 122 | ||
123 | spin_lock_irqsave(&bank->slock, flags); | ||
124 | |||
121 | con = readl(d->virt_base + reg_con); | 125 | con = readl(d->virt_base + reg_con); |
122 | con &= ~(mask << shift); | 126 | con &= ~(mask << shift); |
123 | con |= EXYNOS_EINT_FUNC << shift; | 127 | con |= EXYNOS_EINT_FUNC << shift; |
124 | writel(con, d->virt_base + reg_con); | 128 | writel(con, d->virt_base + reg_con); |
125 | 129 | ||
130 | spin_unlock_irqrestore(&bank->slock, flags); | ||
131 | |||
126 | return 0; | 132 | return 0; |
127 | } | 133 | } |
128 | 134 | ||
@@ -258,6 +264,7 @@ static int exynos_wkup_irq_set_type(struct irq_data *irqd, unsigned int type) | |||
258 | unsigned long reg_con = d->ctrl->weint_con + bank->eint_offset; | 264 | unsigned long reg_con = d->ctrl->weint_con + bank->eint_offset; |
259 | unsigned long shift = EXYNOS_EINT_CON_LEN * pin; | 265 | unsigned long shift = EXYNOS_EINT_CON_LEN * pin; |
260 | unsigned long con, trig_type; | 266 | unsigned long con, trig_type; |
267 | unsigned long flags; | ||
261 | unsigned int mask; | 268 | unsigned int mask; |
262 | 269 | ||
263 | switch (type) { | 270 | switch (type) { |
@@ -295,11 +302,15 @@ static int exynos_wkup_irq_set_type(struct irq_data *irqd, unsigned int type) | |||
295 | shift = pin * bank->func_width; | 302 | shift = pin * bank->func_width; |
296 | mask = (1 << bank->func_width) - 1; | 303 | mask = (1 << bank->func_width) - 1; |
297 | 304 | ||
305 | spin_lock_irqsave(&bank->slock, flags); | ||
306 | |||
298 | con = readl(d->virt_base + reg_con); | 307 | con = readl(d->virt_base + reg_con); |
299 | con &= ~(mask << shift); | 308 | con &= ~(mask << shift); |
300 | con |= EXYNOS_EINT_FUNC << shift; | 309 | con |= EXYNOS_EINT_FUNC << shift; |
301 | writel(con, d->virt_base + reg_con); | 310 | writel(con, d->virt_base + reg_con); |
302 | 311 | ||
312 | spin_unlock_irqrestore(&bank->slock, flags); | ||
313 | |||
303 | return 0; | 314 | return 0; |
304 | } | 315 | } |
305 | 316 | ||
diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c index 3475b92b24a4..b1d4ac8d36f8 100644 --- a/drivers/pinctrl/pinctrl-samsung.c +++ b/drivers/pinctrl/pinctrl-samsung.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/err.h> | 27 | #include <linux/err.h> |
28 | #include <linux/gpio.h> | 28 | #include <linux/gpio.h> |
29 | #include <linux/irqdomain.h> | 29 | #include <linux/irqdomain.h> |
30 | #include <linux/spinlock.h> | ||
30 | 31 | ||
31 | #include "core.h" | 32 | #include "core.h" |
32 | #include "pinctrl-samsung.h" | 33 | #include "pinctrl-samsung.h" |
@@ -289,6 +290,7 @@ static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector, | |||
289 | struct samsung_pin_bank *bank; | 290 | struct samsung_pin_bank *bank; |
290 | void __iomem *reg; | 291 | void __iomem *reg; |
291 | u32 mask, shift, data, pin_offset, cnt; | 292 | u32 mask, shift, data, pin_offset, cnt; |
293 | unsigned long flags; | ||
292 | 294 | ||
293 | drvdata = pinctrl_dev_get_drvdata(pctldev); | 295 | drvdata = pinctrl_dev_get_drvdata(pctldev); |
294 | pins = drvdata->pin_groups[group].pins; | 296 | pins = drvdata->pin_groups[group].pins; |
@@ -303,11 +305,15 @@ static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector, | |||
303 | mask = (1 << bank->func_width) - 1; | 305 | mask = (1 << bank->func_width) - 1; |
304 | shift = pin_offset * bank->func_width; | 306 | shift = pin_offset * bank->func_width; |
305 | 307 | ||
308 | spin_lock_irqsave(&bank->slock, flags); | ||
309 | |||
306 | data = readl(reg); | 310 | data = readl(reg); |
307 | data &= ~(mask << shift); | 311 | data &= ~(mask << shift); |
308 | if (enable) | 312 | if (enable) |
309 | data |= drvdata->pin_groups[group].func << shift; | 313 | data |= drvdata->pin_groups[group].func << shift; |
310 | writel(data, reg); | 314 | writel(data, reg); |
315 | |||
316 | spin_unlock_irqrestore(&bank->slock, flags); | ||
311 | } | 317 | } |
312 | } | 318 | } |
313 | 319 | ||
@@ -338,6 +344,7 @@ static int samsung_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev, | |||
338 | struct samsung_pinctrl_drv_data *drvdata; | 344 | struct samsung_pinctrl_drv_data *drvdata; |
339 | void __iomem *reg; | 345 | void __iomem *reg; |
340 | u32 data, pin_offset, mask, shift; | 346 | u32 data, pin_offset, mask, shift; |
347 | unsigned long flags; | ||
341 | 348 | ||
342 | bank = gc_to_pin_bank(range->gc); | 349 | bank = gc_to_pin_bank(range->gc); |
343 | drvdata = pinctrl_dev_get_drvdata(pctldev); | 350 | drvdata = pinctrl_dev_get_drvdata(pctldev); |
@@ -348,11 +355,16 @@ static int samsung_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev, | |||
348 | mask = (1 << bank->func_width) - 1; | 355 | mask = (1 << bank->func_width) - 1; |
349 | shift = pin_offset * bank->func_width; | 356 | shift = pin_offset * bank->func_width; |
350 | 357 | ||
358 | spin_lock_irqsave(&bank->slock, flags); | ||
359 | |||
351 | data = readl(reg); | 360 | data = readl(reg); |
352 | data &= ~(mask << shift); | 361 | data &= ~(mask << shift); |
353 | if (!input) | 362 | if (!input) |
354 | data |= FUNC_OUTPUT << shift; | 363 | data |= FUNC_OUTPUT << shift; |
355 | writel(data, reg); | 364 | writel(data, reg); |
365 | |||
366 | spin_unlock_irqrestore(&bank->slock, flags); | ||
367 | |||
356 | return 0; | 368 | return 0; |
357 | } | 369 | } |
358 | 370 | ||
@@ -376,6 +388,7 @@ static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin, | |||
376 | enum pincfg_type cfg_type = PINCFG_UNPACK_TYPE(*config); | 388 | enum pincfg_type cfg_type = PINCFG_UNPACK_TYPE(*config); |
377 | u32 data, width, pin_offset, mask, shift; | 389 | u32 data, width, pin_offset, mask, shift; |
378 | u32 cfg_value, cfg_reg; | 390 | u32 cfg_value, cfg_reg; |
391 | unsigned long flags; | ||
379 | 392 | ||
380 | drvdata = pinctrl_dev_get_drvdata(pctldev); | 393 | drvdata = pinctrl_dev_get_drvdata(pctldev); |
381 | pin_to_reg_bank(drvdata, pin - drvdata->ctrl->base, ®_base, | 394 | 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, | |||
406 | if (!width) | 419 | if (!width) |
407 | return -EINVAL; | 420 | return -EINVAL; |
408 | 421 | ||
422 | spin_lock_irqsave(&bank->slock, flags); | ||
423 | |||
409 | mask = (1 << width) - 1; | 424 | mask = (1 << width) - 1; |
410 | shift = pin_offset * width; | 425 | shift = pin_offset * width; |
411 | data = readl(reg_base + cfg_reg); | 426 | data = readl(reg_base + cfg_reg); |
@@ -420,6 +435,9 @@ static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin, | |||
420 | data &= mask; | 435 | data &= mask; |
421 | *config = PINCFG_PACK(cfg_type, data); | 436 | *config = PINCFG_PACK(cfg_type, data); |
422 | } | 437 | } |
438 | |||
439 | spin_unlock_irqrestore(&bank->slock, flags); | ||
440 | |||
423 | return 0; | 441 | return 0; |
424 | } | 442 | } |
425 | 443 | ||
@@ -479,16 +497,21 @@ static const struct pinconf_ops samsung_pinconf_ops = { | |||
479 | static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value) | 497 | static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value) |
480 | { | 498 | { |
481 | struct samsung_pin_bank *bank = gc_to_pin_bank(gc); | 499 | struct samsung_pin_bank *bank = gc_to_pin_bank(gc); |
500 | unsigned long flags; | ||
482 | void __iomem *reg; | 501 | void __iomem *reg; |
483 | u32 data; | 502 | u32 data; |
484 | 503 | ||
485 | reg = bank->drvdata->virt_base + bank->pctl_offset; | 504 | reg = bank->drvdata->virt_base + bank->pctl_offset; |
486 | 505 | ||
506 | spin_lock_irqsave(&bank->slock, flags); | ||
507 | |||
487 | data = readl(reg + DAT_REG); | 508 | data = readl(reg + DAT_REG); |
488 | data &= ~(1 << offset); | 509 | data &= ~(1 << offset); |
489 | if (value) | 510 | if (value) |
490 | data |= 1 << offset; | 511 | data |= 1 << offset; |
491 | writel(data, reg + DAT_REG); | 512 | writel(data, reg + DAT_REG); |
513 | |||
514 | spin_unlock_irqrestore(&bank->slock, flags); | ||
492 | } | 515 | } |
493 | 516 | ||
494 | /* gpiolib gpio_get callback function */ | 517 | /* gpiolib gpio_get callback function */ |
@@ -859,6 +882,7 @@ static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data( | |||
859 | 882 | ||
860 | bank = ctrl->pin_banks; | 883 | bank = ctrl->pin_banks; |
861 | for (i = 0; i < ctrl->nr_banks; ++i, ++bank) { | 884 | for (i = 0; i < ctrl->nr_banks; ++i, ++bank) { |
885 | spin_lock_init(&bank->slock); | ||
862 | bank->drvdata = d; | 886 | bank->drvdata = d; |
863 | bank->pin_base = ctrl->nr_pins; | 887 | bank->pin_base = ctrl->nr_pins; |
864 | ctrl->nr_pins += bank->nr_pins; | 888 | ctrl->nr_pins += bank->nr_pins; |
diff --git a/drivers/pinctrl/pinctrl-samsung.h b/drivers/pinctrl/pinctrl-samsung.h index e2d4e67f7e88..b9dbe7949fab 100644 --- a/drivers/pinctrl/pinctrl-samsung.h +++ b/drivers/pinctrl/pinctrl-samsung.h | |||
@@ -119,6 +119,7 @@ struct samsung_pinctrl_drv_data; | |||
119 | * @irq_domain: IRQ domain of the bank. | 119 | * @irq_domain: IRQ domain of the bank. |
120 | * @gpio_chip: GPIO chip of the bank. | 120 | * @gpio_chip: GPIO chip of the bank. |
121 | * @grange: linux gpio pin range supported by this bank. | 121 | * @grange: linux gpio pin range supported by this bank. |
122 | * @slock: spinlock protecting bank registers | ||
122 | */ | 123 | */ |
123 | struct samsung_pin_bank { | 124 | struct samsung_pin_bank { |
124 | u32 pctl_offset; | 125 | u32 pctl_offset; |
@@ -137,6 +138,7 @@ struct samsung_pin_bank { | |||
137 | struct irq_domain *irq_domain; | 138 | struct irq_domain *irq_domain; |
138 | struct gpio_chip gpio_chip; | 139 | struct gpio_chip gpio_chip; |
139 | struct pinctrl_gpio_range grange; | 140 | struct pinctrl_gpio_range grange; |
141 | spinlock_t slock; | ||
140 | }; | 142 | }; |
141 | 143 | ||
142 | /** | 144 | /** |