mirror of
https://github.com/torvalds/linux.git
synced 2024-11-01 01:31:44 +00:00
Fixes for the sunxi (AllWinner) pin control driver.
This was a new driver in this merge window, so some post-merge hardening is happening. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.13 (GNU/Linux) iQIcBAABAgAGBQJSCdCbAAoJEEEQszewGV1z5VIP/2BVZyUoh4bCY4ZnuacfhArI y83blSEfyvMAfjJfoE2a3vQBLMQpz50IhxDZ2jWIORKUVgCpcuz7FLQge+fW7YRH KmDjbRXaeEG2EkPCUT3xSaQx3sOgFnS5fVxa3rMgZKyfnHTQjRC654XDg0O8Ar4Q yiYF5BerI+k7jAA+MRUGjz7h23McEcsxf7e/mINbbzFSMdUcYDWYu/VZaM2tU1eL XzbG51T0jJi2NPeaezgTp9wDUV338DyYqLkJZ5ForvrvZ42g2Sm2n5w3rXV1XlEM zPFjJ0JxwW0YIut/wvXTMto0l+M1I+PdYqEJ8x/3gMA7OmQt2ustBLc/bTYmB7W9 VR9J7UKmxjYCfN3SQmfYyokyKWF72ELO3C107JBo/KeVaCasjEKF1gxSHGo2d+QI 6a5TjKbna+fh9XOVXASqJtIL7rI/6q+UIoZh/M5ENBK+7D5sk3dYvCrW60zg1gVj KVode0v1Uo48Xub902d68L2lmx/rt6RxHVYSd7atagGTMIpadwU0TrnDGP1IbgWc zuhnE+7+uGrVR63xK7MIuKJxA0CxbM6qWiSNB/6OqVaKi9t/NexhB9ujId4bTro2 IyNDIC2Bj+BjdDm8oQxxBUUP/ozNNg2C45Zo9D39/22BIlIlYhNvUNqoXK5N3rhM gTBeSX7bZSUFYXXOPb+j =fGdI -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
da2ad2a2c3
@ -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_group *g = &pctl->groups[group];
|
||||
unsigned long flags;
|
||||
u32 val, mask;
|
||||
u16 strength;
|
||||
u8 dlevel;
|
||||
@ -295,22 +296,35 @@ static int sunxi_pconf_group_set(struct pinctrl_dev *pctldev,
|
||||
* 3: 40mA
|
||||
*/
|
||||
dlevel = strength / 10 - 1;
|
||||
|
||||
spin_lock_irqsave(&pctl->lock, flags);
|
||||
|
||||
val = readl(pctl->membase + sunxi_dlevel_reg(g->pin));
|
||||
mask = DLEVEL_PINS_MASK << sunxi_dlevel_offset(g->pin);
|
||||
writel((val & ~mask) | dlevel << sunxi_dlevel_offset(g->pin),
|
||||
pctl->membase + sunxi_dlevel_reg(g->pin));
|
||||
|
||||
spin_unlock_irqrestore(&pctl->lock, flags);
|
||||
break;
|
||||
case PIN_CONFIG_BIAS_PULL_UP:
|
||||
spin_lock_irqsave(&pctl->lock, flags);
|
||||
|
||||
val = readl(pctl->membase + sunxi_pull_reg(g->pin));
|
||||
mask = PULL_PINS_MASK << sunxi_pull_offset(g->pin);
|
||||
writel((val & ~mask) | 1 << sunxi_pull_offset(g->pin),
|
||||
pctl->membase + sunxi_pull_reg(g->pin));
|
||||
|
||||
spin_unlock_irqrestore(&pctl->lock, flags);
|
||||
break;
|
||||
case PIN_CONFIG_BIAS_PULL_DOWN:
|
||||
spin_lock_irqsave(&pctl->lock, flags);
|
||||
|
||||
val = readl(pctl->membase + sunxi_pull_reg(g->pin));
|
||||
mask = PULL_PINS_MASK << sunxi_pull_offset(g->pin);
|
||||
writel((val & ~mask) | 2 << sunxi_pull_offset(g->pin),
|
||||
pctl->membase + sunxi_pull_reg(g->pin));
|
||||
|
||||
spin_unlock_irqrestore(&pctl->lock, flags);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -360,11 +374,17 @@ static void sunxi_pmx_set(struct pinctrl_dev *pctldev,
|
||||
u8 config)
|
||||
{
|
||||
struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
|
||||
unsigned long flags;
|
||||
u32 val, mask;
|
||||
|
||||
u32 val = readl(pctl->membase + sunxi_mux_reg(pin));
|
||||
u32 mask = MUX_PINS_MASK << sunxi_mux_offset(pin);
|
||||
spin_lock_irqsave(&pctl->lock, flags);
|
||||
|
||||
val = readl(pctl->membase + sunxi_mux_reg(pin));
|
||||
mask = MUX_PINS_MASK << sunxi_mux_offset(pin);
|
||||
writel((val & ~mask) | config << sunxi_mux_offset(pin),
|
||||
pctl->membase + sunxi_mux_reg(pin));
|
||||
|
||||
spin_unlock_irqrestore(&pctl->lock, flags);
|
||||
}
|
||||
|
||||
static int sunxi_pmx_enable(struct pinctrl_dev *pctldev,
|
||||
@ -464,8 +484,21 @@ static void sunxi_pinctrl_gpio_set(struct gpio_chip *chip,
|
||||
struct sunxi_pinctrl *pctl = dev_get_drvdata(chip->dev);
|
||||
u32 reg = sunxi_data_reg(offset);
|
||||
u8 index = sunxi_data_offset(offset);
|
||||
unsigned long flags;
|
||||
u32 regval;
|
||||
|
||||
writel((value & DATA_PINS_MASK) << index, pctl->membase + reg);
|
||||
spin_lock_irqsave(&pctl->lock, flags);
|
||||
|
||||
regval = readl(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,
|
||||
@ -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);
|
||||
u32 reg = sunxi_irq_cfg_reg(d->hwirq);
|
||||
u8 index = sunxi_irq_cfg_offset(d->hwirq);
|
||||
unsigned long flags;
|
||||
u32 regval;
|
||||
u8 mode;
|
||||
|
||||
switch (type) {
|
||||
@ -548,7 +583,13 @@ static int sunxi_pinctrl_irq_set_type(struct irq_data *d,
|
||||
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;
|
||||
}
|
||||
@ -560,14 +601,19 @@ static void sunxi_pinctrl_irq_mask_ack(struct irq_data *d)
|
||||
u8 ctrl_idx = sunxi_irq_ctrl_offset(d->hwirq);
|
||||
u32 status_reg = sunxi_irq_status_reg(d->hwirq);
|
||||
u8 status_idx = sunxi_irq_status_offset(d->hwirq);
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&pctl->lock, flags);
|
||||
|
||||
/* Mask the IRQ */
|
||||
val = readl(pctl->membase + ctrl_reg);
|
||||
writel(val & ~(1 << ctrl_idx), pctl->membase + ctrl_reg);
|
||||
|
||||
/* Clear the IRQ */
|
||||
writel(1 << status_idx, pctl->membase + status_reg);
|
||||
|
||||
spin_unlock_irqrestore(&pctl->lock, flags);
|
||||
}
|
||||
|
||||
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);
|
||||
u32 reg = sunxi_irq_ctrl_reg(d->hwirq);
|
||||
u8 idx = sunxi_irq_ctrl_offset(d->hwirq);
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&pctl->lock, flags);
|
||||
|
||||
/* Mask the IRQ */
|
||||
val = readl(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)
|
||||
@ -588,6 +639,7 @@ static void sunxi_pinctrl_irq_unmask(struct irq_data *d)
|
||||
struct sunxi_desc_function *func;
|
||||
u32 reg = sunxi_irq_ctrl_reg(d->hwirq);
|
||||
u8 idx = sunxi_irq_ctrl_offset(d->hwirq);
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
func = sunxi_pinctrl_desc_find_function_by_pin(pctl,
|
||||
@ -597,9 +649,13 @@ static void sunxi_pinctrl_irq_unmask(struct irq_data *d)
|
||||
/* Change muxing to INT mode */
|
||||
sunxi_pmx_set(pctl->pctl_dev, pctl->irq_array[d->hwirq], func->muxval);
|
||||
|
||||
spin_lock_irqsave(&pctl->lock, flags);
|
||||
|
||||
/* Unmask the IRQ */
|
||||
val = readl(pctl->membase + reg);
|
||||
writel(val | (1 << idx), pctl->membase + reg);
|
||||
|
||||
spin_unlock_irqrestore(&pctl->lock, flags);
|
||||
}
|
||||
|
||||
static struct irq_chip sunxi_pinctrl_irq_chip = {
|
||||
@ -752,6 +808,8 @@ static int sunxi_pinctrl_probe(struct platform_device *pdev)
|
||||
return -ENOMEM;
|
||||
platform_set_drvdata(pdev, pctl);
|
||||
|
||||
spin_lock_init(&pctl->lock);
|
||||
|
||||
pctl->membase = of_iomap(node, 0);
|
||||
if (!pctl->membase)
|
||||
return -ENOMEM;
|
||||
|
@ -14,6 +14,7 @@
|
||||
#define __PINCTRL_SUNXI_H
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#define PA_BASE 0
|
||||
#define PB_BASE 32
|
||||
@ -407,6 +408,7 @@ struct sunxi_pinctrl {
|
||||
unsigned ngroups;
|
||||
int irq;
|
||||
int irq_array[SUNXI_IRQ_NUMBER];
|
||||
spinlock_t lock;
|
||||
struct pinctrl_dev *pctl_dev;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user