Commit da2ad2a2 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'pinctrl-for-v3.11-3' of...

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
parents fd3930f7 1bee963d
...@@ -278,6 +278,7 @@ static int sunxi_pconf_group_set(struct pinctrl_dev *pctldev, ...@@ -278,6 +278,7 @@ static int sunxi_pconf_group_set(struct pinctrl_dev *pctldev,
{ {
struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
struct sunxi_pinctrl_group *g = &pctl->groups[group]; struct sunxi_pinctrl_group *g = &pctl->groups[group];
unsigned long flags;
u32 val, mask; u32 val, mask;
u16 strength; u16 strength;
u8 dlevel; u8 dlevel;
...@@ -295,22 +296,35 @@ static int sunxi_pconf_group_set(struct pinctrl_dev *pctldev, ...@@ -295,22 +296,35 @@ static int sunxi_pconf_group_set(struct pinctrl_dev *pctldev,
* 3: 40mA * 3: 40mA
*/ */
dlevel = strength / 10 - 1; dlevel = strength / 10 - 1;
spin_lock_irqsave(&pctl->lock, flags);
val = readl(pctl->membase + sunxi_dlevel_reg(g->pin)); val = readl(pctl->membase + sunxi_dlevel_reg(g->pin));
mask = DLEVEL_PINS_MASK << sunxi_dlevel_offset(g->pin); mask = DLEVEL_PINS_MASK << sunxi_dlevel_offset(g->pin);
writel((val & ~mask) | dlevel << sunxi_dlevel_offset(g->pin), writel((val & ~mask) | dlevel << sunxi_dlevel_offset(g->pin),
pctl->membase + sunxi_dlevel_reg(g->pin)); pctl->membase + sunxi_dlevel_reg(g->pin));
spin_unlock_irqrestore(&pctl->lock, flags);
break; break;
case PIN_CONFIG_BIAS_PULL_UP: case PIN_CONFIG_BIAS_PULL_UP:
spin_lock_irqsave(&pctl->lock, flags);
val = readl(pctl->membase + sunxi_pull_reg(g->pin)); val = readl(pctl->membase + sunxi_pull_reg(g->pin));
mask = PULL_PINS_MASK << sunxi_pull_offset(g->pin); mask = PULL_PINS_MASK << sunxi_pull_offset(g->pin);
writel((val & ~mask) | 1 << sunxi_pull_offset(g->pin), writel((val & ~mask) | 1 << sunxi_pull_offset(g->pin),
pctl->membase + sunxi_pull_reg(g->pin)); pctl->membase + sunxi_pull_reg(g->pin));
spin_unlock_irqrestore(&pctl->lock, flags);
break; break;
case PIN_CONFIG_BIAS_PULL_DOWN: case PIN_CONFIG_BIAS_PULL_DOWN:
spin_lock_irqsave(&pctl->lock, flags);
val = readl(pctl->membase + sunxi_pull_reg(g->pin)); val = readl(pctl->membase + sunxi_pull_reg(g->pin));
mask = PULL_PINS_MASK << sunxi_pull_offset(g->pin); mask = PULL_PINS_MASK << sunxi_pull_offset(g->pin);
writel((val & ~mask) | 2 << sunxi_pull_offset(g->pin), writel((val & ~mask) | 2 << sunxi_pull_offset(g->pin),
pctl->membase + sunxi_pull_reg(g->pin)); pctl->membase + sunxi_pull_reg(g->pin));
spin_unlock_irqrestore(&pctl->lock, flags);
break; break;
default: default:
break; break;
...@@ -360,11 +374,17 @@ static void sunxi_pmx_set(struct pinctrl_dev *pctldev, ...@@ -360,11 +374,17 @@ static void sunxi_pmx_set(struct pinctrl_dev *pctldev,
u8 config) u8 config)
{ {
struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
unsigned long flags;
u32 val, mask;
spin_lock_irqsave(&pctl->lock, flags);
u32 val = readl(pctl->membase + sunxi_mux_reg(pin)); val = readl(pctl->membase + sunxi_mux_reg(pin));
u32 mask = MUX_PINS_MASK << sunxi_mux_offset(pin); mask = MUX_PINS_MASK << sunxi_mux_offset(pin);
writel((val & ~mask) | config << sunxi_mux_offset(pin), writel((val & ~mask) | config << sunxi_mux_offset(pin),
pctl->membase + sunxi_mux_reg(pin)); pctl->membase + sunxi_mux_reg(pin));
spin_unlock_irqrestore(&pctl->lock, flags);
} }
static int sunxi_pmx_enable(struct pinctrl_dev *pctldev, static int sunxi_pmx_enable(struct pinctrl_dev *pctldev,
...@@ -464,8 +484,21 @@ static void sunxi_pinctrl_gpio_set(struct gpio_chip *chip, ...@@ -464,8 +484,21 @@ static void sunxi_pinctrl_gpio_set(struct gpio_chip *chip,
struct sunxi_pinctrl *pctl = dev_get_drvdata(chip->dev); struct sunxi_pinctrl *pctl = dev_get_drvdata(chip->dev);
u32 reg = sunxi_data_reg(offset); u32 reg = sunxi_data_reg(offset);
u8 index = sunxi_data_offset(offset); u8 index = sunxi_data_offset(offset);
unsigned long flags;
u32 regval;
spin_lock_irqsave(&pctl->lock, flags);
regval = readl(pctl->membase + reg);
writel((value & DATA_PINS_MASK) << index, pctl->membase + reg); if (value)
regval |= BIT(index);
else
regval &= ~(BIT(index));
writel(regval, pctl->membase + reg);
spin_unlock_irqrestore(&pctl->lock, flags);
} }
static int sunxi_pinctrl_gpio_of_xlate(struct gpio_chip *gc, static 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,6 +559,8 @@ static int sunxi_pinctrl_irq_set_type(struct irq_data *d,
struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
u32 reg = sunxi_irq_cfg_reg(d->hwirq); u32 reg = sunxi_irq_cfg_reg(d->hwirq);
u8 index = sunxi_irq_cfg_offset(d->hwirq); u8 index = sunxi_irq_cfg_offset(d->hwirq);
unsigned long flags;
u32 regval;
u8 mode; u8 mode;
switch (type) { switch (type) {
...@@ -548,7 +583,13 @@ static int sunxi_pinctrl_irq_set_type(struct irq_data *d, ...@@ -548,7 +583,13 @@ static int sunxi_pinctrl_irq_set_type(struct irq_data *d,
return -EINVAL; return -EINVAL;
} }
writel((mode & IRQ_CFG_IRQ_MASK) << index, pctl->membase + reg); spin_lock_irqsave(&pctl->lock, flags);
regval = readl(pctl->membase + reg);
regval &= ~IRQ_CFG_IRQ_MASK;
writel(regval | (mode << index), pctl->membase + reg);
spin_unlock_irqrestore(&pctl->lock, flags);
return 0; return 0;
} }
...@@ -560,14 +601,19 @@ static void sunxi_pinctrl_irq_mask_ack(struct irq_data *d) ...@@ -560,14 +601,19 @@ static void sunxi_pinctrl_irq_mask_ack(struct irq_data *d)
u8 ctrl_idx = sunxi_irq_ctrl_offset(d->hwirq); u8 ctrl_idx = sunxi_irq_ctrl_offset(d->hwirq);
u32 status_reg = sunxi_irq_status_reg(d->hwirq); u32 status_reg = sunxi_irq_status_reg(d->hwirq);
u8 status_idx = sunxi_irq_status_offset(d->hwirq); u8 status_idx = sunxi_irq_status_offset(d->hwirq);
unsigned long flags;
u32 val; u32 val;
spin_lock_irqsave(&pctl->lock, flags);
/* Mask the IRQ */ /* Mask the IRQ */
val = readl(pctl->membase + ctrl_reg); val = readl(pctl->membase + ctrl_reg);
writel(val & ~(1 << ctrl_idx), pctl->membase + ctrl_reg); writel(val & ~(1 << ctrl_idx), pctl->membase + ctrl_reg);
/* Clear the IRQ */ /* Clear the IRQ */
writel(1 << status_idx, pctl->membase + status_reg); writel(1 << status_idx, pctl->membase + status_reg);
spin_unlock_irqrestore(&pctl->lock, flags);
} }
static void sunxi_pinctrl_irq_mask(struct irq_data *d) static void sunxi_pinctrl_irq_mask(struct irq_data *d)
...@@ -575,11 +621,16 @@ static void sunxi_pinctrl_irq_mask(struct irq_data *d) ...@@ -575,11 +621,16 @@ static void sunxi_pinctrl_irq_mask(struct irq_data *d)
struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
u32 reg = sunxi_irq_ctrl_reg(d->hwirq); u32 reg = sunxi_irq_ctrl_reg(d->hwirq);
u8 idx = sunxi_irq_ctrl_offset(d->hwirq); u8 idx = sunxi_irq_ctrl_offset(d->hwirq);
unsigned long flags;
u32 val; u32 val;
spin_lock_irqsave(&pctl->lock, flags);
/* Mask the IRQ */ /* Mask the IRQ */
val = readl(pctl->membase + reg); val = readl(pctl->membase + reg);
writel(val & ~(1 << idx), pctl->membase + reg); writel(val & ~(1 << idx), pctl->membase + reg);
spin_unlock_irqrestore(&pctl->lock, flags);
} }
static void sunxi_pinctrl_irq_unmask(struct irq_data *d) static void sunxi_pinctrl_irq_unmask(struct irq_data *d)
...@@ -588,6 +639,7 @@ static void sunxi_pinctrl_irq_unmask(struct irq_data *d) ...@@ -588,6 +639,7 @@ static void sunxi_pinctrl_irq_unmask(struct irq_data *d)
struct sunxi_desc_function *func; struct sunxi_desc_function *func;
u32 reg = sunxi_irq_ctrl_reg(d->hwirq); u32 reg = sunxi_irq_ctrl_reg(d->hwirq);
u8 idx = sunxi_irq_ctrl_offset(d->hwirq); u8 idx = sunxi_irq_ctrl_offset(d->hwirq);
unsigned long flags;
u32 val; u32 val;
func = sunxi_pinctrl_desc_find_function_by_pin(pctl, func = sunxi_pinctrl_desc_find_function_by_pin(pctl,
...@@ -597,9 +649,13 @@ static void sunxi_pinctrl_irq_unmask(struct irq_data *d) ...@@ -597,9 +649,13 @@ static void sunxi_pinctrl_irq_unmask(struct irq_data *d)
/* Change muxing to INT mode */ /* Change muxing to INT mode */
sunxi_pmx_set(pctl->pctl_dev, pctl->irq_array[d->hwirq], func->muxval); sunxi_pmx_set(pctl->pctl_dev, pctl->irq_array[d->hwirq], func->muxval);
spin_lock_irqsave(&pctl->lock, flags);
/* Unmask the IRQ */ /* Unmask the IRQ */
val = readl(pctl->membase + reg); val = readl(pctl->membase + reg);
writel(val | (1 << idx), pctl->membase + reg); writel(val | (1 << idx), pctl->membase + reg);
spin_unlock_irqrestore(&pctl->lock, flags);
} }
static struct irq_chip sunxi_pinctrl_irq_chip = { static struct irq_chip sunxi_pinctrl_irq_chip = {
...@@ -752,6 +808,8 @@ static int sunxi_pinctrl_probe(struct platform_device *pdev) ...@@ -752,6 +808,8 @@ static int sunxi_pinctrl_probe(struct platform_device *pdev)
return -ENOMEM; return -ENOMEM;
platform_set_drvdata(pdev, pctl); platform_set_drvdata(pdev, pctl);
spin_lock_init(&pctl->lock);
pctl->membase = of_iomap(node, 0); pctl->membase = of_iomap(node, 0);
if (!pctl->membase) if (!pctl->membase)
return -ENOMEM; return -ENOMEM;
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#define __PINCTRL_SUNXI_H #define __PINCTRL_SUNXI_H
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/spinlock.h>
#define PA_BASE 0 #define PA_BASE 0
#define PB_BASE 32 #define PB_BASE 32
...@@ -407,6 +408,7 @@ struct sunxi_pinctrl { ...@@ -407,6 +408,7 @@ struct sunxi_pinctrl {
unsigned ngroups; unsigned ngroups;
int irq; int irq;
int irq_array[SUNXI_IRQ_NUMBER]; int irq_array[SUNXI_IRQ_NUMBER];
spinlock_t lock;
struct pinctrl_dev *pctl_dev; struct pinctrl_dev *pctl_dev;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment