diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-05-21 10:42:11 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-05-21 10:42:11 -0700 |
commit | 63d222b9d277c4d7bf08afd1631a7f8e327a825c (patch) | |
tree | 5a7167eebe02730c62b3137c9b9e89fa45329db7 /drivers/rtc/rtc-zynqmp.c | |
parent | 10cd7158042bf9c949c19dbf0c7ee600d198ed39 (diff) | |
parent | b9ba1eb0336877b9b83556fd30d2becda110fd8c (diff) |
Merge tag 'rtc-4.7' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux
Pull RTC updates from Alexandre Belloni:
"Subsystem wide cleanups:
- Use IS_ENABLED() instead of checking for built-in or module
- remove useless DRV_VERSION
- remove CLK_IS_ROOT
- remove UIE signaling
Drivers:
- ds1302: rewritten to be a proper SPI device driver
- m41t80: huge cleanup, alarm, wakelarm ans oscialltor failure
detection support
- rv3029: switch to regmap to handle rv3049, alarm support, fixes
- zynqmp: enable switching to battery power, fixes
- small fixes for at91sam9, da9053, ds1307, ds1685, ds3232, r2025,
sa1100, snvs, stmp3xxx, tps6586x"
* tag 'rtc-4.7' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: (40 commits)
rtc: tps6586x: rename so module can be autoloaded
rtc: rv3029: hide unused i2c device table
rtc: rs5c372: r2025: fix check for 'oscillator halted' condition
rtc: rv3029: add alarm IRQ
rtc: rv3029: fix set_time function
rtc: rv3029: fix alarm support
rtc: rv3029: Remove some checks and warnings
rtc: rv3029: Add support of RV3049
rtc: rv3029: convert to use regmap
rtc: rv3029: remove 'i2c' in functions names
rtc: stmp3xxx: print message on error
rtc: Use IS_ENABLED() instead of checking for built-in or module
rtc: ds3232: fix call trace when rtc->ops_lock is used as NULL
rtc: snvs: return error in case enable_irq_wake fails
rtc: zynqmp: Update seconds time programming logic
rtc: sa1100: DT spelling s/interrupt-name/interrupt-names/
rtc: mc13xxx: remove UIE signaling
rtc: mxc: remove UIE signaling
rtc: ds1307: Remove CLK_IS_ROOT
rtc: hym8563: Remove CLK_IS_ROOT
...
Diffstat (limited to 'drivers/rtc/rtc-zynqmp.c')
-rw-r--r-- | drivers/rtc/rtc-zynqmp.c | 74 |
1 files changed, 61 insertions, 13 deletions
diff --git a/drivers/rtc/rtc-zynqmp.c b/drivers/rtc/rtc-zynqmp.c index 8b28762f06df..da18a8ae3c1d 100644 --- a/drivers/rtc/rtc-zynqmp.c +++ b/drivers/rtc/rtc-zynqmp.c @@ -45,6 +45,7 @@ #define RTC_INT_SEC BIT(0) #define RTC_INT_ALRM BIT(1) #define RTC_OSC_EN BIT(24) +#define RTC_BATT_EN BIT(31) #define RTC_CALIB_DEF 0x198233 #define RTC_CALIB_MASK 0x1FFFFF @@ -55,6 +56,7 @@ struct xlnx_rtc_dev { void __iomem *reg_base; int alarm_irq; int sec_irq; + int calibval; }; static int xlnx_rtc_set_time(struct device *dev, struct rtc_time *tm) @@ -62,21 +64,63 @@ static int xlnx_rtc_set_time(struct device *dev, struct rtc_time *tm) struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev); unsigned long new_time; - new_time = rtc_tm_to_time64(tm); + /* + * The value written will be updated after 1 sec into the + * seconds read register, so we need to program time +1 sec + * to get the correct time on read. + */ + new_time = rtc_tm_to_time64(tm) + 1; if (new_time > RTC_SEC_MAX_VAL) return -EINVAL; + /* + * Writing into calibration register will clear the Tick Counter and + * force the next second to be signaled exactly in 1 second period + */ + xrtcdev->calibval &= RTC_CALIB_MASK; + writel(xrtcdev->calibval, (xrtcdev->reg_base + RTC_CALIB_WR)); + writel(new_time, xrtcdev->reg_base + RTC_SET_TM_WR); + /* + * Clear the rtc interrupt status register after setting the + * time. During a read_time function, the code should read the + * RTC_INT_STATUS register and if bit 0 is still 0, it means + * that one second has not elapsed yet since RTC was set and + * the current time should be read from SET_TIME_READ register; + * otherwise, CURRENT_TIME register is read to report the time + */ + writel(RTC_INT_SEC, xrtcdev->reg_base + RTC_INT_STS); + return 0; } static int xlnx_rtc_read_time(struct device *dev, struct rtc_time *tm) { + u32 status; + unsigned long read_time; struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev); - rtc_time64_to_tm(readl(xrtcdev->reg_base + RTC_CUR_TM), tm); + status = readl(xrtcdev->reg_base + RTC_INT_STS); + + if (status & RTC_INT_SEC) { + /* + * RTC has updated the CURRENT_TIME with the time written into + * SET_TIME_WRITE register. + */ + rtc_time64_to_tm(readl(xrtcdev->reg_base + RTC_CUR_TM), tm); + } else { + /* + * Time written in SET_TIME_WRITE has not yet updated into + * the seconds read register, so read the time from the + * SET_TIME_WRITE instead of CURRENT_TIME register. + * Since we add +1 sec while writing, we need to -1 sec while + * reading. + */ + read_time = readl(xrtcdev->reg_base + RTC_SET_TM_RD) - 1; + rtc_time64_to_tm(read_time, tm); + } return rtc_valid_tm(tm); } @@ -120,16 +164,23 @@ static int xlnx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) return 0; } -static void xlnx_init_rtc(struct xlnx_rtc_dev *xrtcdev, u32 calibval) +static void xlnx_init_rtc(struct xlnx_rtc_dev *xrtcdev) { + u32 rtc_ctrl; + + /* Enable RTC switch to battery when VCC_PSAUX is not available */ + rtc_ctrl = readl(xrtcdev->reg_base + RTC_CTRL); + rtc_ctrl |= RTC_BATT_EN; + writel(rtc_ctrl, xrtcdev->reg_base + RTC_CTRL); + /* * Based on crystal freq of 33.330 KHz * set the seconds counter and enable, set fractions counter * to default value suggested as per design spec * to correct RTC delay in frequency over period of time. */ - calibval &= RTC_CALIB_MASK; - writel(calibval, (xrtcdev->reg_base + RTC_CALIB_WR)); + xrtcdev->calibval &= RTC_CALIB_MASK; + writel(xrtcdev->calibval, (xrtcdev->reg_base + RTC_CALIB_WR)); } static const struct rtc_class_ops xlnx_rtc_ops = { @@ -150,11 +201,9 @@ static irqreturn_t xlnx_rtc_interrupt(int irq, void *id) if (!(status & (RTC_INT_SEC | RTC_INT_ALRM))) return IRQ_NONE; - /* Clear interrupt */ - writel(status, xrtcdev->reg_base + RTC_INT_STS); + /* Clear RTC_INT_ALRM interrupt only */ + writel(RTC_INT_ALRM, xrtcdev->reg_base + RTC_INT_STS); - if (status & RTC_INT_SEC) - rtc_update_irq(xrtcdev->rtc, 1, RTC_IRQF | RTC_UF); if (status & RTC_INT_ALRM) rtc_update_irq(xrtcdev->rtc, 1, RTC_IRQF | RTC_AF); @@ -166,7 +215,6 @@ static int xlnx_rtc_probe(struct platform_device *pdev) struct xlnx_rtc_dev *xrtcdev; struct resource *res; int ret; - unsigned int calibvalue; xrtcdev = devm_kzalloc(&pdev->dev, sizeof(*xrtcdev), GFP_KERNEL); if (!xrtcdev) @@ -207,11 +255,11 @@ static int xlnx_rtc_probe(struct platform_device *pdev) } ret = of_property_read_u32(pdev->dev.of_node, "calibration", - &calibvalue); + &xrtcdev->calibval); if (ret) - calibvalue = RTC_CALIB_DEF; + xrtcdev->calibval = RTC_CALIB_DEF; - xlnx_init_rtc(xrtcdev, calibvalue); + xlnx_init_rtc(xrtcdev); device_init_wakeup(&pdev->dev, 1); |