rtc: sun6i: Add some locking
commit a9422a19ce270a22fc520f2278fb7e80c58be508 upstream. Some registers have a read-modify-write access pattern that are not atomic. Add some locking to prevent from concurrent accesses. Acked-by: Chen-Yu Tsai <wens@csie.org> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
a0378b5bfc
commit
ee360e99da
1 changed files with 15 additions and 2 deletions
|
@ -114,13 +114,17 @@ struct sun6i_rtc_dev {
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
int irq;
|
int irq;
|
||||||
unsigned long alarm;
|
unsigned long alarm;
|
||||||
|
|
||||||
|
spinlock_t lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
static irqreturn_t sun6i_rtc_alarmirq(int irq, void *id)
|
static irqreturn_t sun6i_rtc_alarmirq(int irq, void *id)
|
||||||
{
|
{
|
||||||
struct sun6i_rtc_dev *chip = (struct sun6i_rtc_dev *) id;
|
struct sun6i_rtc_dev *chip = (struct sun6i_rtc_dev *) id;
|
||||||
|
irqreturn_t ret = IRQ_NONE;
|
||||||
u32 val;
|
u32 val;
|
||||||
|
|
||||||
|
spin_lock(&chip->lock);
|
||||||
val = readl(chip->base + SUN6I_ALRM_IRQ_STA);
|
val = readl(chip->base + SUN6I_ALRM_IRQ_STA);
|
||||||
|
|
||||||
if (val & SUN6I_ALRM_IRQ_STA_CNT_IRQ_PEND) {
|
if (val & SUN6I_ALRM_IRQ_STA_CNT_IRQ_PEND) {
|
||||||
|
@ -129,10 +133,11 @@ static irqreturn_t sun6i_rtc_alarmirq(int irq, void *id)
|
||||||
|
|
||||||
rtc_update_irq(chip->rtc, 1, RTC_AF | RTC_IRQF);
|
rtc_update_irq(chip->rtc, 1, RTC_AF | RTC_IRQF);
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
ret = IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
spin_unlock(&chip->lock);
|
||||||
|
|
||||||
return IRQ_NONE;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sun6i_rtc_setaie(int to, struct sun6i_rtc_dev *chip)
|
static void sun6i_rtc_setaie(int to, struct sun6i_rtc_dev *chip)
|
||||||
|
@ -140,6 +145,7 @@ static void sun6i_rtc_setaie(int to, struct sun6i_rtc_dev *chip)
|
||||||
u32 alrm_val = 0;
|
u32 alrm_val = 0;
|
||||||
u32 alrm_irq_val = 0;
|
u32 alrm_irq_val = 0;
|
||||||
u32 alrm_wake_val = 0;
|
u32 alrm_wake_val = 0;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
if (to) {
|
if (to) {
|
||||||
alrm_val = SUN6I_ALRM_EN_CNT_EN;
|
alrm_val = SUN6I_ALRM_EN_CNT_EN;
|
||||||
|
@ -150,9 +156,11 @@ static void sun6i_rtc_setaie(int to, struct sun6i_rtc_dev *chip)
|
||||||
chip->base + SUN6I_ALRM_IRQ_STA);
|
chip->base + SUN6I_ALRM_IRQ_STA);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spin_lock_irqsave(&chip->lock, flags);
|
||||||
writel(alrm_val, chip->base + SUN6I_ALRM_EN);
|
writel(alrm_val, chip->base + SUN6I_ALRM_EN);
|
||||||
writel(alrm_irq_val, chip->base + SUN6I_ALRM_IRQ_EN);
|
writel(alrm_irq_val, chip->base + SUN6I_ALRM_IRQ_EN);
|
||||||
writel(alrm_wake_val, chip->base + SUN6I_ALARM_CONFIG);
|
writel(alrm_wake_val, chip->base + SUN6I_ALARM_CONFIG);
|
||||||
|
spin_unlock_irqrestore(&chip->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sun6i_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
|
static int sun6i_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
|
||||||
|
@ -191,11 +199,15 @@ static int sun6i_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
|
||||||
static int sun6i_rtc_getalarm(struct device *dev, struct rtc_wkalrm *wkalrm)
|
static int sun6i_rtc_getalarm(struct device *dev, struct rtc_wkalrm *wkalrm)
|
||||||
{
|
{
|
||||||
struct sun6i_rtc_dev *chip = dev_get_drvdata(dev);
|
struct sun6i_rtc_dev *chip = dev_get_drvdata(dev);
|
||||||
|
unsigned long flags;
|
||||||
u32 alrm_st;
|
u32 alrm_st;
|
||||||
u32 alrm_en;
|
u32 alrm_en;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&chip->lock, flags);
|
||||||
alrm_en = readl(chip->base + SUN6I_ALRM_IRQ_EN);
|
alrm_en = readl(chip->base + SUN6I_ALRM_IRQ_EN);
|
||||||
alrm_st = readl(chip->base + SUN6I_ALRM_IRQ_STA);
|
alrm_st = readl(chip->base + SUN6I_ALRM_IRQ_STA);
|
||||||
|
spin_unlock_irqrestore(&chip->lock, flags);
|
||||||
|
|
||||||
wkalrm->enabled = !!(alrm_en & SUN6I_ALRM_EN_CNT_EN);
|
wkalrm->enabled = !!(alrm_en & SUN6I_ALRM_EN_CNT_EN);
|
||||||
wkalrm->pending = !!(alrm_st & SUN6I_ALRM_EN_CNT_EN);
|
wkalrm->pending = !!(alrm_st & SUN6I_ALRM_EN_CNT_EN);
|
||||||
rtc_time_to_tm(chip->alarm, &wkalrm->time);
|
rtc_time_to_tm(chip->alarm, &wkalrm->time);
|
||||||
|
@ -356,6 +368,7 @@ static int sun6i_rtc_probe(struct platform_device *pdev)
|
||||||
chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
|
chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
|
||||||
if (!chip)
|
if (!chip)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
spin_lock_init(&chip->lock);
|
||||||
|
|
||||||
platform_set_drvdata(pdev, chip);
|
platform_set_drvdata(pdev, chip);
|
||||||
chip->dev = &pdev->dev;
|
chip->dev = &pdev->dev;
|
||||||
|
|
Loading…
Add table
Reference in a new issue