aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-08-21 19:33:37 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-08-21 19:33:37 -0400
commitda2ad2a2c31fb07a6405e2e6706be171c5a41bc7 (patch)
tree64b0573cfd8c3c037a7c74a09595a2997e3e1a50
parentfd3930f70c8d14008f3377d51ce039806dfc542e (diff)
parent1bee963db9dd82e12566bdae6710defb1206b38b (diff)
Merge tag 'pinctrl-for-v3.11-3' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl
Pull pinctrl fixes from Linus Walleij: "Fixes for the sunxi (AllWinner) pin control driver. This was a new driver in this merge window, so some post-merge hardening is happening" [ I had completely missed this pull request for some reason, it was sent over a week ago but my mailbox is chaotic ] * tag 'pinctrl-for-v3.11-3' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl: pinctrl: sunxi: Add spinlocks pinctrl: sunxi: Fix gpio_set behaviour pinctrl: sunxi: Read register before writing to it in irq_set_type
-rw-r--r--drivers/pinctrl/pinctrl-sunxi.c66
-rw-r--r--drivers/pinctrl/pinctrl-sunxi.h2
2 files changed, 64 insertions, 4 deletions
diff --git a/drivers/pinctrl/pinctrl-sunxi.c b/drivers/pinctrl/pinctrl-sunxi.c
index c47fd1e5450b..94716c779800 100644
--- a/drivers/pinctrl/pinctrl-sunxi.c
+++ b/drivers/pinctrl/pinctrl-sunxi.c
@@ -278,6 +278,7 @@ static int sunxi_pconf_group_set(struct pinctrl_dev *pctldev,
278{ 278{
279 struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 279 struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
280 struct sunxi_pinctrl_group *g = &pctl->groups[group]; 280 struct sunxi_pinctrl_group *g = &pctl->groups[group];
281 unsigned long flags;
281 u32 val, mask; 282 u32 val, mask;
282 u16 strength; 283 u16 strength;
283 u8 dlevel; 284 u8 dlevel;
@@ -295,22 +296,35 @@ static int sunxi_pconf_group_set(struct pinctrl_dev *pctldev,
295 * 3: 40mA 296 * 3: 40mA
296 */ 297 */
297 dlevel = strength / 10 - 1; 298 dlevel = strength / 10 - 1;
299
300 spin_lock_irqsave(&pctl->lock, flags);
301
298 val = readl(pctl->membase + sunxi_dlevel_reg(g->pin)); 302 val = readl(pctl->membase + sunxi_dlevel_reg(g->pin));
299 mask = DLEVEL_PINS_MASK << sunxi_dlevel_offset(g->pin); 303 mask = DLEVEL_PINS_MASK << sunxi_dlevel_offset(g->pin);
300 writel((val & ~mask) | dlevel << sunxi_dlevel_offset(g->pin), 304 writel((val & ~mask) | dlevel << sunxi_dlevel_offset(g->pin),
301 pctl->membase + sunxi_dlevel_reg(g->pin)); 305 pctl->membase + sunxi_dlevel_reg(g->pin));
306
307 spin_unlock_irqrestore(&pctl->lock, flags);
302 break; 308 break;
303 case PIN_CONFIG_BIAS_PULL_UP: 309 case PIN_CONFIG_BIAS_PULL_UP:
310 spin_lock_irqsave(&pctl->lock, flags);
311
304 val = readl(pctl->membase + sunxi_pull_reg(g->pin)); 312 val = readl(pctl->membase + sunxi_pull_reg(g->pin));
305 mask = PULL_PINS_MASK << sunxi_pull_offset(g->pin); 313 mask = PULL_PINS_MASK << sunxi_pull_offset(g->pin);
306 writel((val & ~mask) | 1 << sunxi_pull_offset(g->pin), 314 writel((val & ~mask) | 1 << sunxi_pull_offset(g->pin),
307 pctl->membase + sunxi_pull_reg(g->pin)); 315 pctl->membase + sunxi_pull_reg(g->pin));
316
317 spin_unlock_irqrestore(&pctl->lock, flags);
308 break; 318 break;
309 case PIN_CONFIG_BIAS_PULL_DOWN: 319 case PIN_CONFIG_BIAS_PULL_DOWN:
320 spin_lock_irqsave(&pctl->lock, flags);
321
310 val = readl(pctl->membase + sunxi_pull_reg(g->pin)); 322 val = readl(pctl->membase + sunxi_pull_reg(g->pin));
311 mask = PULL_PINS_MASK << sunxi_pull_offset(g->pin); 323 mask = PULL_PINS_MASK << sunxi_pull_offset(g->pin);
312 writel((val & ~mask) | 2 << sunxi_pull_offset(g->pin), 324 writel((val & ~mask) | 2 << sunxi_pull_offset(g->pin),
313 pctl->membase + sunxi_pull_reg(g->pin)); 325 pctl->membase + sunxi_pull_reg(g->pin));
326
327 spin_unlock_irqrestore(&pctl->lock, flags);
314 break; 328 break;
315 default: 329 default:
316 break; 330 break;
@@ -360,11 +374,17 @@ static void sunxi_pmx_set(struct pinctrl_dev *pctldev,
360 u8 config) 374 u8 config)
361{ 375{
362 struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 376 struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
377 unsigned long flags;
378 u32 val, mask;
379
380 spin_lock_irqsave(&pctl->lock, flags);
363 381
364 u32 val = readl(pctl->membase + sunxi_mux_reg(pin)); 382 val = readl(pctl->membase + sunxi_mux_reg(pin));
365 u32 mask = MUX_PINS_MASK << sunxi_mux_offset(pin); 383 mask = MUX_PINS_MASK << sunxi_mux_offset(pin);
366 writel((val & ~mask) | config << sunxi_mux_offset(pin), 384 writel((val & ~mask) | config << sunxi_mux_offset(pin),
367 pctl->membase + sunxi_mux_reg(pin)); 385 pctl->membase + sunxi_mux_reg(pin));
386
387 spin_unlock_irqrestore(&pctl->lock, flags);
368} 388}
369 389
370static int sunxi_pmx_enable(struct pinctrl_dev *pctldev, 390static int sunxi_pmx_enable(struct pinctrl_dev *pctldev,
@@ -464,8 +484,21 @@ static void sunxi_pinctrl_gpio_set(struct gpio_chip *chip,
464 struct sunxi_pinctrl *pctl = dev_get_drvdata(chip->dev); 484 struct sunxi_pinctrl *pctl = dev_get_drvdata(chip->dev);
465 u32 reg = sunxi_data_reg(offset); 485 u32 reg = sunxi_data_reg(offset);
466 u8 index = sunxi_data_offset(offset); 486 u8 index = sunxi_data_offset(offset);
487 unsigned long flags;
488 u32 regval;
489
490 spin_lock_irqsave(&pctl->lock, flags);
491
492 regval = readl(pctl->membase + reg);
467 493
468 writel((value & DATA_PINS_MASK) << index, pctl->membase + reg); 494 if (value)
495 regval |= BIT(index);
496 else
497 regval &= ~(BIT(index));
498
499 writel(regval, pctl->membase + reg);
500
501 spin_unlock_irqrestore(&pctl->lock, flags);
469} 502}
470 503
471static int sunxi_pinctrl_gpio_of_xlate(struct gpio_chip *gc, 504static int sunxi_pinctrl_gpio_of_xlate(struct gpio_chip *gc,
@@ -526,6 +559,8 @@ static int sunxi_pinctrl_irq_set_type(struct irq_data *d,
526 struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); 559 struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
527 u32 reg = sunxi_irq_cfg_reg(d->hwirq); 560 u32 reg = sunxi_irq_cfg_reg(d->hwirq);
528 u8 index = sunxi_irq_cfg_offset(d->hwirq); 561 u8 index = sunxi_irq_cfg_offset(d->hwirq);
562 unsigned long flags;
563 u32 regval;
529 u8 mode; 564 u8 mode;
530 565
531 switch (type) { 566 switch (type) {
@@ -548,7 +583,13 @@ static int sunxi_pinctrl_irq_set_type(struct irq_data *d,
548 return -EINVAL; 583 return -EINVAL;
549 } 584 }
550 585
551 writel((mode & IRQ_CFG_IRQ_MASK) << index, pctl->membase + reg); 586 spin_lock_irqsave(&pctl->lock, flags);
587
588 regval = readl(pctl->membase + reg);
589 regval &= ~IRQ_CFG_IRQ_MASK;
590 writel(regval | (mode << index), pctl->membase + reg);
591
592 spin_unlock_irqrestore(&pctl->lock, flags);
552 593
553 return 0; 594 return 0;
554} 595}
@@ -560,14 +601,19 @@ static void sunxi_pinctrl_irq_mask_ack(struct irq_data *d)
560 u8 ctrl_idx = sunxi_irq_ctrl_offset(d->hwirq); 601 u8 ctrl_idx = sunxi_irq_ctrl_offset(d->hwirq);
561 u32 status_reg = sunxi_irq_status_reg(d->hwirq); 602 u32 status_reg = sunxi_irq_status_reg(d->hwirq);
562 u8 status_idx = sunxi_irq_status_offset(d->hwirq); 603 u8 status_idx = sunxi_irq_status_offset(d->hwirq);
604 unsigned long flags;
563 u32 val; 605 u32 val;
564 606
607 spin_lock_irqsave(&pctl->lock, flags);
608
565 /* Mask the IRQ */ 609 /* Mask the IRQ */
566 val = readl(pctl->membase + ctrl_reg); 610 val = readl(pctl->membase + ctrl_reg);
567 writel(val & ~(1 << ctrl_idx), pctl->membase + ctrl_reg); 611 writel(val & ~(1 << ctrl_idx), pctl->membase + ctrl_reg);
568 612
569 /* Clear the IRQ */ 613 /* Clear the IRQ */
570 writel(1 << status_idx, pctl->membase + status_reg); 614 writel(1 << status_idx, pctl->membase + status_reg);
615
616 spin_unlock_irqrestore(&pctl->lock, flags);
571} 617}
572 618
573static void sunxi_pinctrl_irq_mask(struct irq_data *d) 619static void sunxi_pinctrl_irq_mask(struct irq_data *d)
@@ -575,11 +621,16 @@ static void sunxi_pinctrl_irq_mask(struct irq_data *d)
575 struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); 621 struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
576 u32 reg = sunxi_irq_ctrl_reg(d->hwirq); 622 u32 reg = sunxi_irq_ctrl_reg(d->hwirq);
577 u8 idx = sunxi_irq_ctrl_offset(d->hwirq); 623 u8 idx = sunxi_irq_ctrl_offset(d->hwirq);
624 unsigned long flags;
578 u32 val; 625 u32 val;
579 626
627 spin_lock_irqsave(&pctl->lock, flags);
628
580 /* Mask the IRQ */ 629 /* Mask the IRQ */
581 val = readl(pctl->membase + reg); 630 val = readl(pctl->membase + reg);
582 writel(val & ~(1 << idx), pctl->membase + reg); 631 writel(val & ~(1 << idx), pctl->membase + reg);
632
633 spin_unlock_irqrestore(&pctl->lock, flags);
583} 634}
584 635
585static void sunxi_pinctrl_irq_unmask(struct irq_data *d) 636static void sunxi_pinctrl_irq_unmask(struct irq_data *d)
@@ -588,6 +639,7 @@ static void sunxi_pinctrl_irq_unmask(struct irq_data *d)
588 struct sunxi_desc_function *func; 639 struct sunxi_desc_function *func;
589 u32 reg = sunxi_irq_ctrl_reg(d->hwirq); 640 u32 reg = sunxi_irq_ctrl_reg(d->hwirq);
590 u8 idx = sunxi_irq_ctrl_offset(d->hwirq); 641 u8 idx = sunxi_irq_ctrl_offset(d->hwirq);
642 unsigned long flags;
591 u32 val; 643 u32 val;
592 644
593 func = sunxi_pinctrl_desc_find_function_by_pin(pctl, 645 func = sunxi_pinctrl_desc_find_function_by_pin(pctl,
@@ -597,9 +649,13 @@ static void sunxi_pinctrl_irq_unmask(struct irq_data *d)
597 /* Change muxing to INT mode */ 649 /* Change muxing to INT mode */
598 sunxi_pmx_set(pctl->pctl_dev, pctl->irq_array[d->hwirq], func->muxval); 650 sunxi_pmx_set(pctl->pctl_dev, pctl->irq_array[d->hwirq], func->muxval);
599 651
652 spin_lock_irqsave(&pctl->lock, flags);
653
600 /* Unmask the IRQ */ 654 /* Unmask the IRQ */
601 val = readl(pctl->membase + reg); 655 val = readl(pctl->membase + reg);
602 writel(val | (1 << idx), pctl->membase + reg); 656 writel(val | (1 << idx), pctl->membase + reg);
657
658 spin_unlock_irqrestore(&pctl->lock, flags);
603} 659}
604 660
605static struct irq_chip sunxi_pinctrl_irq_chip = { 661static struct irq_chip sunxi_pinctrl_irq_chip = {
@@ -752,6 +808,8 @@ static int sunxi_pinctrl_probe(struct platform_device *pdev)
752 return -ENOMEM; 808 return -ENOMEM;
753 platform_set_drvdata(pdev, pctl); 809 platform_set_drvdata(pdev, pctl);
754 810
811 spin_lock_init(&pctl->lock);
812
755 pctl->membase = of_iomap(node, 0); 813 pctl->membase = of_iomap(node, 0);
756 if (!pctl->membase) 814 if (!pctl->membase)
757 return -ENOMEM; 815 return -ENOMEM;
diff --git a/drivers/pinctrl/pinctrl-sunxi.h b/drivers/pinctrl/pinctrl-sunxi.h
index d68047d8f699..01c494f8a14f 100644
--- a/drivers/pinctrl/pinctrl-sunxi.h
+++ b/drivers/pinctrl/pinctrl-sunxi.h
@@ -14,6 +14,7 @@
14#define __PINCTRL_SUNXI_H 14#define __PINCTRL_SUNXI_H
15 15
16#include <linux/kernel.h> 16#include <linux/kernel.h>
17#include <linux/spinlock.h>
17 18
18#define PA_BASE 0 19#define PA_BASE 0
19#define PB_BASE 32 20#define PB_BASE 32
@@ -407,6 +408,7 @@ struct sunxi_pinctrl {
407 unsigned ngroups; 408 unsigned ngroups;
408 int irq; 409 int irq;
409 int irq_array[SUNXI_IRQ_NUMBER]; 410 int irq_array[SUNXI_IRQ_NUMBER];
411 spinlock_t lock;
410 struct pinctrl_dev *pctl_dev; 412 struct pinctrl_dev *pctl_dev;
411}; 413};
412 414