aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTomasz Figa <tomasz.figa@gmail.com>2013-03-18 17:31:50 -0400
committerLinus Walleij <linus.walleij@linaro.org>2013-04-09 03:36:42 -0400
commit198469504ac77ee04fe0f185bd668e1909aaba5f (patch)
treeba3530c083d886bbfe4ce4be55b1e10c197ad50f
parent6a7b3e970426f4bc2a8d52f81a4fda6595a9f052 (diff)
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>
-rw-r--r--drivers/pinctrl/pinctrl-exynos.c11
-rw-r--r--drivers/pinctrl/pinctrl-samsung.c24
-rw-r--r--drivers/pinctrl/pinctrl-samsung.h2
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, &reg_base, 394 pin_to_reg_bank(drvdata, pin - drvdata->ctrl->base, &reg_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 = {
479static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value) 497static 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 */
123struct samsung_pin_bank { 124struct 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/**