rtc: armada38x: Align RTC set time procedure with the official errata
According to the Armada38x functional errata FE-3124064, writing to the RTC TIME register may fail. As a workaround, after writing to RTC TIME register, issue a dummy write of 0x0 twice to the RTC Status register. This is the updated implementation of the Errata that eliminates the need of the long 100ms delay during the RTC set time procedure. [gregory.clement@free-electrons.com]: removed the mutex and use the spinlock again Signed-off-by: Nadav Haklai <nadavh@marvell.com> Reviewed-by: Neta Zur Hershkovits <neta@marvell.com> Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com> Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
This commit is contained in:
parent
efbbb4fd6b
commit
0c6e718389
|
@ -40,13 +40,6 @@ struct armada38x_rtc {
|
||||||
void __iomem *regs;
|
void __iomem *regs;
|
||||||
void __iomem *regs_soc;
|
void __iomem *regs_soc;
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
/*
|
|
||||||
* While setting the time, the RTC TIME register should not be
|
|
||||||
* accessed. Setting the RTC time involves sleeping during
|
|
||||||
* 100ms, so a mutex instead of a spinlock is used to protect
|
|
||||||
* it
|
|
||||||
*/
|
|
||||||
struct mutex mutex_time;
|
|
||||||
int irq;
|
int irq;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -64,9 +57,9 @@ static void rtc_delayed_write(u32 val, struct armada38x_rtc *rtc, int offset)
|
||||||
static int armada38x_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
static int armada38x_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||||
{
|
{
|
||||||
struct armada38x_rtc *rtc = dev_get_drvdata(dev);
|
struct armada38x_rtc *rtc = dev_get_drvdata(dev);
|
||||||
unsigned long time, time_check;
|
unsigned long time, time_check, flags;
|
||||||
|
|
||||||
mutex_lock(&rtc->mutex_time);
|
spin_lock_irqsave(&rtc->lock, flags);
|
||||||
time = readl(rtc->regs + RTC_TIME);
|
time = readl(rtc->regs + RTC_TIME);
|
||||||
/*
|
/*
|
||||||
* WA for failing time set attempts. As stated in HW ERRATA if
|
* WA for failing time set attempts. As stated in HW ERRATA if
|
||||||
|
@ -77,7 +70,7 @@ static int armada38x_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||||
if ((time_check - time) > 1)
|
if ((time_check - time) > 1)
|
||||||
time_check = readl(rtc->regs + RTC_TIME);
|
time_check = readl(rtc->regs + RTC_TIME);
|
||||||
|
|
||||||
mutex_unlock(&rtc->mutex_time);
|
spin_unlock_irqrestore(&rtc->lock, flags);
|
||||||
|
|
||||||
rtc_time_to_tm(time_check, tm);
|
rtc_time_to_tm(time_check, tm);
|
||||||
|
|
||||||
|
@ -88,23 +81,23 @@ static int armada38x_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||||
{
|
{
|
||||||
struct armada38x_rtc *rtc = dev_get_drvdata(dev);
|
struct armada38x_rtc *rtc = dev_get_drvdata(dev);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
unsigned long time;
|
unsigned long time, flags;
|
||||||
|
|
||||||
ret = rtc_tm_to_time(tm, &time);
|
ret = rtc_tm_to_time(tm, &time);
|
||||||
|
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
/*
|
/*
|
||||||
* Setting the RTC time not always succeeds. According to the
|
* According to errata FE-3124064, Write to RTC TIME register
|
||||||
* errata we need to first write on the status register and
|
* may fail. As a workaround, after writing to RTC TIME
|
||||||
* then wait for 100ms before writing to the time register to be
|
* register, issue a dummy write of 0x0 twice to RTC Status
|
||||||
* sure that the data will be taken into account.
|
* register.
|
||||||
*/
|
*/
|
||||||
mutex_lock(&rtc->mutex_time);
|
spin_lock_irqsave(&rtc->lock, flags);
|
||||||
rtc_delayed_write(0, rtc, RTC_STATUS);
|
|
||||||
msleep(100);
|
|
||||||
rtc_delayed_write(time, rtc, RTC_TIME);
|
rtc_delayed_write(time, rtc, RTC_TIME);
|
||||||
mutex_unlock(&rtc->mutex_time);
|
rtc_delayed_write(0, rtc, RTC_STATUS);
|
||||||
|
rtc_delayed_write(0, rtc, RTC_STATUS);
|
||||||
|
spin_unlock_irqrestore(&rtc->lock, flags);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -229,7 +222,6 @@ static __init int armada38x_rtc_probe(struct platform_device *pdev)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
spin_lock_init(&rtc->lock);
|
spin_lock_init(&rtc->lock);
|
||||||
mutex_init(&rtc->mutex_time);
|
|
||||||
|
|
||||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rtc");
|
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rtc");
|
||||||
rtc->regs = devm_ioremap_resource(&pdev->dev, res);
|
rtc->regs = devm_ioremap_resource(&pdev->dev, res);
|
||||||
|
|
Loading…
Reference in New Issue