| // SPDX-License-Identifier: GPL-2.0 | |
| /* | |
| * On-Chip RTC Support available on RZ/G3S SoC | |
| * | |
| * Copyright (C) 2024 Renesas Electronics Corp. | |
| */ | |
| #include <linux/bcd.h> | |
| #include <linux/bitfield.h> | |
| #include <linux/cleanup.h> | |
| #include <linux/clk.h> | |
| #include <linux/completion.h> | |
| #include <linux/delay.h> | |
| #include <linux/iopoll.h> | |
| #include <linux/interrupt.h> | |
| #include <linux/jiffies.h> | |
| #include <linux/of.h> | |
| #include <linux/platform_device.h> | |
| #include <linux/pm_runtime.h> | |
| #include <linux/reset.h> | |
| #include <linux/rtc.h> | |
| /* Counter registers. */ | |
| #define RTCA3_RSECCNT 0x2 | |
| #define RTCA3_RSECCNT_SEC GENMASK(6, 0) | |
| #define RTCA3_RMINCNT 0x4 | |
| #define RTCA3_RMINCNT_MIN GENMASK(6, 0) | |
| #define RTCA3_RHRCNT 0x6 | |
| #define RTCA3_RHRCNT_HR GENMASK(5, 0) | |
| #define RTCA3_RHRCNT_PM BIT(6) | |
| #define RTCA3_RWKCNT 0x8 | |
| #define RTCA3_RWKCNT_WK GENMASK(2, 0) | |
| #define RTCA3_RDAYCNT 0xa | |
| #define RTCA3_RDAYCNT_DAY GENMASK(5, 0) | |
| #define RTCA3_RMONCNT 0xc | |
| #define RTCA3_RMONCNT_MONTH GENMASK(4, 0) | |
| #define RTCA3_RYRCNT 0xe | |
| #define RTCA3_RYRCNT_YEAR GENMASK(7, 0) | |
| /* Alarm registers. */ | |
| #define RTCA3_RSECAR 0x10 | |
| #define RTCA3_RSECAR_SEC GENMASK(6, 0) | |
| #define RTCA3_RMINAR 0x12 | |
| #define RTCA3_RMINAR_MIN GENMASK(6, 0) | |
| #define RTCA3_RHRAR 0x14 | |
| #define RTCA3_RHRAR_HR GENMASK(5, 0) | |
| #define RTCA3_RHRAR_PM BIT(6) | |
| #define RTCA3_RWKAR 0x16 | |
| #define RTCA3_RWKAR_DAYW GENMASK(2, 0) | |
| #define RTCA3_RDAYAR 0x18 | |
| #define RTCA3_RDAYAR_DATE GENMASK(5, 0) | |
| #define RTCA3_RMONAR 0x1a | |
| #define RTCA3_RMONAR_MON GENMASK(4, 0) | |
| #define RTCA3_RYRAR 0x1c | |
| #define RTCA3_RYRAR_YR GENMASK(7, 0) | |
| #define RTCA3_RYRAREN 0x1e | |
| /* Alarm enable bit (for all alarm registers). */ | |
| #define RTCA3_AR_ENB BIT(7) | |
| /* Control registers. */ | |
| #define RTCA3_RCR1 0x22 | |
| #define RTCA3_RCR1_AIE BIT(0) | |
| #define RTCA3_RCR1_CIE BIT(1) | |
| #define RTCA3_RCR1_PIE BIT(2) | |
| #define RTCA3_RCR1_PES GENMASK(7, 4) | |
| #define RTCA3_RCR1_PES_1_64_SEC 0x8 | |
| #define RTCA3_RCR2 0x24 | |
| #define RTCA3_RCR2_START BIT(0) | |
| #define RTCA3_RCR2_RESET BIT(1) | |
| #define RTCA3_RCR2_AADJE BIT(4) | |
| #define RTCA3_RCR2_ADJP BIT(5) | |
| #define RTCA3_RCR2_HR24 BIT(6) | |
| #define RTCA3_RCR2_CNTMD BIT(7) | |
| #define RTCA3_RSR 0x20 | |
| #define RTCA3_RSR_AF BIT(0) | |
| #define RTCA3_RSR_CF BIT(1) | |
| #define RTCA3_RSR_PF BIT(2) | |
| #define RTCA3_RADJ 0x2e | |
| #define RTCA3_RADJ_ADJ GENMASK(5, 0) | |
| #define RTCA3_RADJ_ADJ_MAX 0x3f | |
| #define RTCA3_RADJ_PMADJ GENMASK(7, 6) | |
| #define RTCA3_RADJ_PMADJ_NONE 0 | |
| #define RTCA3_RADJ_PMADJ_ADD 1 | |
| #define RTCA3_RADJ_PMADJ_SUB 2 | |
| /* Polling operation timeouts. */ | |
| #define RTCA3_DEFAULT_TIMEOUT_US 150 | |
| #define RTCA3_IRQSET_TIMEOUT_US 5000 | |
| #define RTCA3_START_TIMEOUT_US 150000 | |
| #define RTCA3_RESET_TIMEOUT_US 200000 | |
| /** | |
| * enum rtca3_alrm_set_step - RTCA3 alarm set steps | |
| * @RTCA3_ALRM_SSTEP_DONE: alarm setup done step | |
| * @RTCA3_ALRM_SSTEP_IRQ: two 1/64 periodic IRQs were generated step | |
| * @RTCA3_ALRM_SSTEP_INIT: alarm setup initialization step | |
| */ | |
| enum rtca3_alrm_set_step { | |
| RTCA3_ALRM_SSTEP_DONE = 0, | |
| RTCA3_ALRM_SSTEP_IRQ = 1, | |
| RTCA3_ALRM_SSTEP_INIT = 3, | |
| }; | |
| /** | |
| * struct rtca3_ppb_per_cycle - PPB per cycle | |
| * @ten_sec: PPB per cycle in 10 seconds adjutment mode | |
| * @sixty_sec: PPB per cycle in 60 seconds adjustment mode | |
| */ | |
| struct rtca3_ppb_per_cycle { | |
| int ten_sec; | |
| int sixty_sec; | |
| }; | |
| /** | |
| * struct rtca3_priv - RTCA3 private data structure | |
| * @base: base address | |
| * @rtc_dev: RTC device | |
| * @rstc: reset control | |
| * @set_alarm_completion: alarm setup completion | |
| * @alrm_sstep: alarm setup step (see enum rtca3_alrm_set_step) | |
| * @lock: device lock | |
| * @ppb: ppb per cycle for each the available adjustment modes | |
| * @wakeup_irq: wakeup IRQ | |
| */ | |
| struct rtca3_priv { | |
| void __iomem *base; | |
| struct rtc_device *rtc_dev; | |
| struct reset_control *rstc; | |
| struct completion set_alarm_completion; | |
| atomic_t alrm_sstep; | |
| spinlock_t lock; | |
| struct rtca3_ppb_per_cycle ppb; | |
| int wakeup_irq; | |
| }; | |
| static void rtca3_byte_update_bits(struct rtca3_priv *priv, u8 off, u8 mask, u8 val) | |
| { | |
| u8 tmp; | |
| tmp = readb(priv->base + off); | |
| tmp &= ~mask; | |
| tmp |= (val & mask); | |
| writeb(tmp, priv->base + off); | |
| } | |
| static u8 rtca3_alarm_handler_helper(struct rtca3_priv *priv) | |
| { | |
| u8 val, pending; | |
| val = readb(priv->base + RTCA3_RSR); | |
| pending = val & RTCA3_RSR_AF; | |
| writeb(val & ~pending, priv->base + RTCA3_RSR); | |
| if (pending) | |
| rtc_update_irq(priv->rtc_dev, 1, RTC_AF | RTC_IRQF); | |
| return pending; | |
| } | |
| static irqreturn_t rtca3_alarm_handler(int irq, void *dev_id) | |
| { | |
| struct rtca3_priv *priv = dev_id; | |
| u8 pending; | |
| guard(spinlock)(&priv->lock); | |
| pending = rtca3_alarm_handler_helper(priv); | |
| return IRQ_RETVAL(pending); | |
| } | |
| static irqreturn_t rtca3_periodic_handler(int irq, void *dev_id) | |
| { | |
| struct rtca3_priv *priv = dev_id; | |
| u8 val, pending; | |
| guard(spinlock)(&priv->lock); | |
| val = readb(priv->base + RTCA3_RSR); | |
| pending = val & RTCA3_RSR_PF; | |
| if (pending) { | |
| writeb(val & ~pending, priv->base + RTCA3_RSR); | |
| if (atomic_read(&priv->alrm_sstep) > RTCA3_ALRM_SSTEP_IRQ) { | |
| /* Alarm setup in progress. */ | |
| atomic_dec(&priv->alrm_sstep); | |
| if (atomic_read(&priv->alrm_sstep) == RTCA3_ALRM_SSTEP_IRQ) { | |
| /* | |
| * We got 2 * 1/64 periodic interrupts. Disable | |
| * interrupt and let alarm setup continue. | |
| */ | |
| rtca3_byte_update_bits(priv, RTCA3_RCR1, | |
| RTCA3_RCR1_PIE, 0); | |
| readb_poll_timeout_atomic(priv->base + RTCA3_RCR1, val, | |
| !(val & RTCA3_RCR1_PIE), | |
| 10, RTCA3_DEFAULT_TIMEOUT_US); | |
| complete(&priv->set_alarm_completion); | |
| } | |
| } | |
| } | |
| return IRQ_RETVAL(pending); | |
| } | |
| static void rtca3_prepare_cntalrm_regs_for_read(struct rtca3_priv *priv, bool cnt) | |
| { | |
| /* Offset b/w time and alarm registers. */ | |
| u8 offset = cnt ? 0 : 0xe; | |
| /* | |
| * According to HW manual (section 22.6.4. Notes on writing to and | |
| * reading from registers) after writing to count registers, alarm | |
| * registers, year alarm enable register, bits RCR2.AADJE, AADJP, | |
| * and HR24 register, we need to do 3 empty reads before being | |
| * able to fetch the registers content. | |
| */ | |
| for (u8 i = 0; i < 3; i++) { | |
| readb(priv->base + RTCA3_RSECCNT + offset); | |
| readb(priv->base + RTCA3_RMINCNT + offset); | |
| readb(priv->base + RTCA3_RHRCNT + offset); | |
| readb(priv->base + RTCA3_RWKCNT + offset); | |
| readb(priv->base + RTCA3_RDAYCNT + offset); | |
| readw(priv->base + RTCA3_RYRCNT + offset); | |
| if (!cnt) | |
| readb(priv->base + RTCA3_RYRAREN); | |
| } | |
| } | |
| static int rtca3_read_time(struct device *dev, struct rtc_time *tm) | |
| { | |
| struct rtca3_priv *priv = dev_get_drvdata(dev); | |
| u8 sec, min, hour, wday, mday, month, tmp; | |
| u8 trials = 0; | |
| u32 year100; | |
| u16 year; | |
| guard(spinlock_irqsave)(&priv->lock); | |
| tmp = readb(priv->base + RTCA3_RCR2); | |
| if (!(tmp & RTCA3_RCR2_START)) | |
| return -EINVAL; | |
| do { | |
| /* Clear carry interrupt. */ | |
| rtca3_byte_update_bits(priv, RTCA3_RSR, RTCA3_RSR_CF, 0); | |
| /* Read counters. */ | |
| sec = readb(priv->base + RTCA3_RSECCNT); | |
| min = readb(priv->base + RTCA3_RMINCNT); | |
| hour = readb(priv->base + RTCA3_RHRCNT); | |
| wday = readb(priv->base + RTCA3_RWKCNT); | |
| mday = readb(priv->base + RTCA3_RDAYCNT); | |
| month = readb(priv->base + RTCA3_RMONCNT); | |
| year = readw(priv->base + RTCA3_RYRCNT); | |
| tmp = readb(priv->base + RTCA3_RSR); | |
| /* | |
| * We cannot generate carries due to reading 64Hz counter as | |
| * the driver doesn't implement carry, thus, carries will be | |
| * generated once per seconds. Add a timeout of 5 trials here | |
| * to avoid infinite loop, if any. | |
| */ | |
| } while ((tmp & RTCA3_RSR_CF) && ++trials < 5); | |
| if (trials >= 5) | |
| return -ETIMEDOUT; | |
| tm->tm_sec = bcd2bin(FIELD_GET(RTCA3_RSECCNT_SEC, sec)); | |
| tm->tm_min = bcd2bin(FIELD_GET(RTCA3_RMINCNT_MIN, min)); | |
| tm->tm_hour = bcd2bin(FIELD_GET(RTCA3_RHRCNT_HR, hour)); | |
| tm->tm_wday = bcd2bin(FIELD_GET(RTCA3_RWKCNT_WK, wday)); | |
| tm->tm_mday = bcd2bin(FIELD_GET(RTCA3_RDAYCNT_DAY, mday)); | |
| tm->tm_mon = bcd2bin(FIELD_GET(RTCA3_RMONCNT_MONTH, month)) - 1; | |
| year = FIELD_GET(RTCA3_RYRCNT_YEAR, year); | |
| year100 = bcd2bin((year == 0x99) ? 0x19 : 0x20); | |
| tm->tm_year = (year100 * 100 + bcd2bin(year)) - 1900; | |
| return 0; | |
| } | |
| static int rtca3_set_time(struct device *dev, struct rtc_time *tm) | |
| { | |
| struct rtca3_priv *priv = dev_get_drvdata(dev); | |
| u8 rcr2, tmp; | |
| int ret; | |
| guard(spinlock_irqsave)(&priv->lock); | |
| /* Stop the RTC. */ | |
| rcr2 = readb(priv->base + RTCA3_RCR2); | |
| writeb(rcr2 & ~RTCA3_RCR2_START, priv->base + RTCA3_RCR2); | |
| ret = readb_poll_timeout_atomic(priv->base + RTCA3_RCR2, tmp, | |
| !(tmp & RTCA3_RCR2_START), | |
| 10, RTCA3_DEFAULT_TIMEOUT_US); | |
| if (ret) | |
| return ret; | |
| /* Update time. */ | |
| writeb(bin2bcd(tm->tm_sec), priv->base + RTCA3_RSECCNT); | |
| writeb(bin2bcd(tm->tm_min), priv->base + RTCA3_RMINCNT); | |
| writeb(bin2bcd(tm->tm_hour), priv->base + RTCA3_RHRCNT); | |
| writeb(bin2bcd(tm->tm_wday), priv->base + RTCA3_RWKCNT); | |
| writeb(bin2bcd(tm->tm_mday), priv->base + RTCA3_RDAYCNT); | |
| writeb(bin2bcd(tm->tm_mon + 1), priv->base + RTCA3_RMONCNT); | |
| writew(bin2bcd(tm->tm_year % 100), priv->base + RTCA3_RYRCNT); | |
| /* Make sure we can read back the counters. */ | |
| rtca3_prepare_cntalrm_regs_for_read(priv, true); | |
| /* Start RTC. */ | |
| writeb(rcr2 | RTCA3_RCR2_START, priv->base + RTCA3_RCR2); | |
| return readb_poll_timeout_atomic(priv->base + RTCA3_RCR2, tmp, | |
| (tmp & RTCA3_RCR2_START), | |
| 10, RTCA3_DEFAULT_TIMEOUT_US); | |
| } | |
| static int rtca3_alarm_irq_set_helper(struct rtca3_priv *priv, | |
| u8 interrupts, | |
| unsigned int enabled) | |
| { | |
| u8 tmp, val; | |
| if (enabled) { | |
| /* | |
| * AIE, CIE, PIE bit indexes in RSR corresponds with | |
| * those on RCR1. Same interrupts mask can be used. | |
| */ | |
| rtca3_byte_update_bits(priv, RTCA3_RSR, interrupts, 0); | |
| val = interrupts; | |
| } else { | |
| val = 0; | |
| } | |
| rtca3_byte_update_bits(priv, RTCA3_RCR1, interrupts, val); | |
| return readb_poll_timeout_atomic(priv->base + RTCA3_RCR1, tmp, | |
| ((tmp & interrupts) == val), | |
| 10, RTCA3_IRQSET_TIMEOUT_US); | |
| } | |
| static int rtca3_alarm_irq_enable(struct device *dev, unsigned int enabled) | |
| { | |
| struct rtca3_priv *priv = dev_get_drvdata(dev); | |
| guard(spinlock_irqsave)(&priv->lock); | |
| return rtca3_alarm_irq_set_helper(priv, RTCA3_RCR1_AIE, enabled); | |
| } | |
| static int rtca3_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) | |
| { | |
| struct rtca3_priv *priv = dev_get_drvdata(dev); | |
| u8 sec, min, hour, wday, mday, month; | |
| struct rtc_time *tm = &wkalrm->time; | |
| u32 year100; | |
| u16 year; | |
| guard(spinlock_irqsave)(&priv->lock); | |
| sec = readb(priv->base + RTCA3_RSECAR); | |
| min = readb(priv->base + RTCA3_RMINAR); | |
| hour = readb(priv->base + RTCA3_RHRAR); | |
| wday = readb(priv->base + RTCA3_RWKAR); | |
| mday = readb(priv->base + RTCA3_RDAYAR); | |
| month = readb(priv->base + RTCA3_RMONAR); | |
| year = readw(priv->base + RTCA3_RYRAR); | |
| tm->tm_sec = bcd2bin(FIELD_GET(RTCA3_RSECAR_SEC, sec)); | |
| tm->tm_min = bcd2bin(FIELD_GET(RTCA3_RMINAR_MIN, min)); | |
| tm->tm_hour = bcd2bin(FIELD_GET(RTCA3_RHRAR_HR, hour)); | |
| tm->tm_wday = bcd2bin(FIELD_GET(RTCA3_RWKAR_DAYW, wday)); | |
| tm->tm_mday = bcd2bin(FIELD_GET(RTCA3_RDAYAR_DATE, mday)); | |
| tm->tm_mon = bcd2bin(FIELD_GET(RTCA3_RMONAR_MON, month)) - 1; | |
| year = FIELD_GET(RTCA3_RYRAR_YR, year); | |
| year100 = bcd2bin((year == 0x99) ? 0x19 : 0x20); | |
| tm->tm_year = (year100 * 100 + bcd2bin(year)) - 1900; | |
| wkalrm->enabled = !!(readb(priv->base + RTCA3_RCR1) & RTCA3_RCR1_AIE); | |
| return 0; | |
| } | |
| static int rtca3_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) | |
| { | |
| struct rtca3_priv *priv = dev_get_drvdata(dev); | |
| struct rtc_time *tm = &wkalrm->time; | |
| u8 rcr1, tmp; | |
| int ret; | |
| scoped_guard(spinlock_irqsave, &priv->lock) { | |
| tmp = readb(priv->base + RTCA3_RCR2); | |
| if (!(tmp & RTCA3_RCR2_START)) | |
| return -EPERM; | |
| /* Disable AIE to prevent false interrupts. */ | |
| rcr1 = readb(priv->base + RTCA3_RCR1); | |
| rcr1 &= ~RTCA3_RCR1_AIE; | |
| writeb(rcr1, priv->base + RTCA3_RCR1); | |
| ret = readb_poll_timeout_atomic(priv->base + RTCA3_RCR1, tmp, | |
| !(tmp & RTCA3_RCR1_AIE), | |
| 10, RTCA3_DEFAULT_TIMEOUT_US); | |
| if (ret) | |
| return ret; | |
| /* Set the time and enable the alarm. */ | |
| writeb(RTCA3_AR_ENB | bin2bcd(tm->tm_sec), priv->base + RTCA3_RSECAR); | |
| writeb(RTCA3_AR_ENB | bin2bcd(tm->tm_min), priv->base + RTCA3_RMINAR); | |
| writeb(RTCA3_AR_ENB | bin2bcd(tm->tm_hour), priv->base + RTCA3_RHRAR); | |
| writeb(RTCA3_AR_ENB | bin2bcd(tm->tm_wday), priv->base + RTCA3_RWKAR); | |
| writeb(RTCA3_AR_ENB | bin2bcd(tm->tm_mday), priv->base + RTCA3_RDAYAR); | |
| writeb(RTCA3_AR_ENB | bin2bcd(tm->tm_mon + 1), priv->base + RTCA3_RMONAR); | |
| writew(bin2bcd(tm->tm_year % 100), priv->base + RTCA3_RYRAR); | |
| writeb(RTCA3_AR_ENB, priv->base + RTCA3_RYRAREN); | |
| /* Make sure we can read back the counters. */ | |
| rtca3_prepare_cntalrm_regs_for_read(priv, false); | |
| /* Need to wait for 2 * 1/64 periodic interrupts to be generated. */ | |
| atomic_set(&priv->alrm_sstep, RTCA3_ALRM_SSTEP_INIT); | |
| reinit_completion(&priv->set_alarm_completion); | |
| /* Enable periodic interrupt. */ | |
| rcr1 |= RTCA3_RCR1_PIE; | |
| writeb(rcr1, priv->base + RTCA3_RCR1); | |
| ret = readb_poll_timeout_atomic(priv->base + RTCA3_RCR1, tmp, | |
| (tmp & RTCA3_RCR1_PIE), | |
| 10, RTCA3_IRQSET_TIMEOUT_US); | |
| } | |
| if (ret) | |
| goto setup_failed; | |
| /* Wait for the 2 * 1/64 periodic interrupts. */ | |
| ret = wait_for_completion_interruptible_timeout(&priv->set_alarm_completion, | |
| msecs_to_jiffies(500)); | |
| if (ret <= 0) { | |
| ret = -ETIMEDOUT; | |
| goto setup_failed; | |
| } | |
| scoped_guard(spinlock_irqsave, &priv->lock) { | |
| ret = rtca3_alarm_irq_set_helper(priv, RTCA3_RCR1_AIE, wkalrm->enabled); | |
| atomic_set(&priv->alrm_sstep, RTCA3_ALRM_SSTEP_DONE); | |
| } | |
| return ret; | |
| setup_failed: | |
| scoped_guard(spinlock_irqsave, &priv->lock) { | |
| /* | |
| * Disable PIE to avoid interrupt storm in case HW needed more than | |
| * specified timeout for setup. | |
| */ | |
| writeb(rcr1 & ~RTCA3_RCR1_PIE, priv->base + RTCA3_RCR1); | |
| readb_poll_timeout_atomic(priv->base + RTCA3_RCR1, tmp, !(tmp & ~RTCA3_RCR1_PIE), | |
| 10, RTCA3_DEFAULT_TIMEOUT_US); | |
| atomic_set(&priv->alrm_sstep, RTCA3_ALRM_SSTEP_DONE); | |
| } | |
| return ret; | |
| } | |
| static int rtca3_read_offset(struct device *dev, long *offset) | |
| { | |
| struct rtca3_priv *priv = dev_get_drvdata(dev); | |
| u8 val, radj, cycles; | |
| u32 ppb_per_cycle; | |
| scoped_guard(spinlock_irqsave, &priv->lock) { | |
| radj = readb(priv->base + RTCA3_RADJ); | |
| val = readb(priv->base + RTCA3_RCR2); | |
| } | |
| cycles = FIELD_GET(RTCA3_RADJ_ADJ, radj); | |
| if (!cycles) { | |
| *offset = 0; | |
| return 0; | |
| } | |
| if (val & RTCA3_RCR2_ADJP) | |
| ppb_per_cycle = priv->ppb.ten_sec; | |
| else | |
| ppb_per_cycle = priv->ppb.sixty_sec; | |
| *offset = cycles * ppb_per_cycle; | |
| val = FIELD_GET(RTCA3_RADJ_PMADJ, radj); | |
| if (val == RTCA3_RADJ_PMADJ_SUB) | |
| *offset = -(*offset); | |
| return 0; | |
| } | |
| static int rtca3_set_offset(struct device *dev, long offset) | |
| { | |
| struct rtca3_priv *priv = dev_get_drvdata(dev); | |
| int cycles, cycles10, cycles60; | |
| u8 radj, adjp, tmp; | |
| int ret; | |
| /* | |
| * Automatic time error adjustment could be set at intervals of 10 | |
| * or 60 seconds. | |
| */ | |
| cycles10 = DIV_ROUND_CLOSEST(offset, priv->ppb.ten_sec); | |
| cycles60 = DIV_ROUND_CLOSEST(offset, priv->ppb.sixty_sec); | |
| /* We can set b/w 1 and 63 clock cycles. */ | |
| if (cycles60 >= -RTCA3_RADJ_ADJ_MAX && | |
| cycles60 <= RTCA3_RADJ_ADJ_MAX) { | |
| cycles = cycles60; | |
| adjp = 0; | |
| } else if (cycles10 >= -RTCA3_RADJ_ADJ_MAX && | |
| cycles10 <= RTCA3_RADJ_ADJ_MAX) { | |
| cycles = cycles10; | |
| adjp = RTCA3_RCR2_ADJP; | |
| } else { | |
| return -ERANGE; | |
| } | |
| radj = FIELD_PREP(RTCA3_RADJ_ADJ, abs(cycles)); | |
| if (!cycles) | |
| radj |= FIELD_PREP(RTCA3_RADJ_PMADJ, RTCA3_RADJ_PMADJ_NONE); | |
| else if (cycles > 0) | |
| radj |= FIELD_PREP(RTCA3_RADJ_PMADJ, RTCA3_RADJ_PMADJ_ADD); | |
| else | |
| radj |= FIELD_PREP(RTCA3_RADJ_PMADJ, RTCA3_RADJ_PMADJ_SUB); | |
| guard(spinlock_irqsave)(&priv->lock); | |
| tmp = readb(priv->base + RTCA3_RCR2); | |
| if ((tmp & RTCA3_RCR2_ADJP) != adjp) { | |
| /* RADJ.PMADJ need to be set to zero before setting RCR2.ADJP. */ | |
| writeb(0, priv->base + RTCA3_RADJ); | |
| ret = readb_poll_timeout_atomic(priv->base + RTCA3_RADJ, tmp, !tmp, | |
| 10, RTCA3_DEFAULT_TIMEOUT_US); | |
| if (ret) | |
| return ret; | |
| rtca3_byte_update_bits(priv, RTCA3_RCR2, RTCA3_RCR2_ADJP, adjp); | |
| ret = readb_poll_timeout_atomic(priv->base + RTCA3_RCR2, tmp, | |
| ((tmp & RTCA3_RCR2_ADJP) == adjp), | |
| 10, RTCA3_DEFAULT_TIMEOUT_US); | |
| if (ret) | |
| return ret; | |
| } | |
| writeb(radj, priv->base + RTCA3_RADJ); | |
| return readb_poll_timeout_atomic(priv->base + RTCA3_RADJ, tmp, (tmp == radj), | |
| 10, RTCA3_DEFAULT_TIMEOUT_US); | |
| } | |
| static const struct rtc_class_ops rtca3_ops = { | |
| .read_time = rtca3_read_time, | |
| .set_time = rtca3_set_time, | |
| .read_alarm = rtca3_read_alarm, | |
| .set_alarm = rtca3_set_alarm, | |
| .alarm_irq_enable = rtca3_alarm_irq_enable, | |
| .set_offset = rtca3_set_offset, | |
| .read_offset = rtca3_read_offset, | |
| }; | |
| static int rtca3_initial_setup(struct clk *clk, struct rtca3_priv *priv) | |
| { | |
| unsigned long osc32k_rate; | |
| u8 val, tmp, mask; | |
| u32 sleep_us; | |
| int ret; | |
| osc32k_rate = clk_get_rate(clk); | |
| if (!osc32k_rate) | |
| return -EINVAL; | |
| sleep_us = DIV_ROUND_UP_ULL(1000000ULL, osc32k_rate) * 6; | |
| priv->ppb.ten_sec = DIV_ROUND_CLOSEST_ULL(1000000000ULL, (osc32k_rate * 10)); | |
| priv->ppb.sixty_sec = DIV_ROUND_CLOSEST_ULL(1000000000ULL, (osc32k_rate * 60)); | |
| /* | |
| * According to HW manual (section 22.4.2. Clock and count mode setting procedure) | |
| * we need to wait at least 6 cycles of the 32KHz clock after clock was enabled. | |
| */ | |
| usleep_range(sleep_us, sleep_us + 10); | |
| mask = RTCA3_RCR2_START | RTCA3_RCR2_HR24; | |
| val = readb(priv->base + RTCA3_RCR2); | |
| /* Only disable the interrupts if already started in 24 hours and calendar count mode. */ | |
| if ((val & mask) == mask) { | |
| /* Disable all interrupts. */ | |
| mask = RTCA3_RCR1_AIE | RTCA3_RCR1_CIE | RTCA3_RCR1_PIE; | |
| return rtca3_alarm_irq_set_helper(priv, mask, 0); | |
| } | |
| /* Reconfigure the RTC in 24 hours and calendar count mode. */ | |
| mask = RTCA3_RCR2_START | RTCA3_RCR2_CNTMD; | |
| writeb(0, priv->base + RTCA3_RCR2); | |
| ret = readb_poll_timeout(priv->base + RTCA3_RCR2, tmp, !(tmp & mask), | |
| 10, RTCA3_DEFAULT_TIMEOUT_US); | |
| if (ret) | |
| return ret; | |
| /* | |
| * Set 24 hours mode. According to HW manual (section 22.3.19. RTC Control | |
| * Register 2) this needs to be done separate from stop operation. | |
| */ | |
| mask = RTCA3_RCR2_HR24; | |
| val = RTCA3_RCR2_HR24; | |
| writeb(val, priv->base + RTCA3_RCR2); | |
| ret = readb_poll_timeout(priv->base + RTCA3_RCR2, tmp, (tmp & mask), | |
| 10, RTCA3_DEFAULT_TIMEOUT_US); | |
| if (ret) | |
| return ret; | |
| /* Execute reset. */ | |
| mask = RTCA3_RCR2_RESET; | |
| writeb(val | RTCA3_RCR2_RESET, priv->base + RTCA3_RCR2); | |
| ret = readb_poll_timeout(priv->base + RTCA3_RCR2, tmp, !(tmp & mask), | |
| 10, RTCA3_RESET_TIMEOUT_US); | |
| if (ret) | |
| return ret; | |
| /* | |
| * According to HW manual (section 22.6.3. Notes on writing to and reading | |
| * from registers) after reset we need to wait 6 clock cycles before | |
| * writing to RTC registers. | |
| */ | |
| usleep_range(sleep_us, sleep_us + 10); | |
| /* Set no adjustment. */ | |
| writeb(0, priv->base + RTCA3_RADJ); | |
| ret = readb_poll_timeout(priv->base + RTCA3_RADJ, tmp, !tmp, 10, | |
| RTCA3_DEFAULT_TIMEOUT_US); | |
| /* Start the RTC and enable automatic time error adjustment. */ | |
| mask = RTCA3_RCR2_START | RTCA3_RCR2_AADJE; | |
| val |= RTCA3_RCR2_START | RTCA3_RCR2_AADJE; | |
| writeb(val, priv->base + RTCA3_RCR2); | |
| ret = readb_poll_timeout(priv->base + RTCA3_RCR2, tmp, ((tmp & mask) == mask), | |
| 10, RTCA3_START_TIMEOUT_US); | |
| if (ret) | |
| return ret; | |
| /* | |
| * According to HW manual (section 22.6.4. Notes on writing to and reading | |
| * from registers) we need to wait 1/128 seconds while the clock is operating | |
| * (RCR2.START bit = 1) to be able to read the counters after a return from | |
| * reset. | |
| */ | |
| usleep_range(8000, 9000); | |
| /* Set period interrupt to 1/64 seconds. It is necessary for alarm setup. */ | |
| val = FIELD_PREP(RTCA3_RCR1_PES, RTCA3_RCR1_PES_1_64_SEC); | |
| rtca3_byte_update_bits(priv, RTCA3_RCR1, RTCA3_RCR1_PES, val); | |
| return readb_poll_timeout(priv->base + RTCA3_RCR1, tmp, ((tmp & RTCA3_RCR1_PES) == val), | |
| 10, RTCA3_DEFAULT_TIMEOUT_US); | |
| } | |
| static int rtca3_request_irqs(struct platform_device *pdev, struct rtca3_priv *priv) | |
| { | |
| struct device *dev = &pdev->dev; | |
| int ret, irq; | |
| irq = platform_get_irq_byname(pdev, "alarm"); | |
| if (irq < 0) | |
| return dev_err_probe(dev, irq, "Failed to get alarm IRQ!\n"); | |
| ret = devm_request_irq(dev, irq, rtca3_alarm_handler, 0, "rtca3-alarm", priv); | |
| if (ret) | |
| return dev_err_probe(dev, ret, "Failed to request alarm IRQ!\n"); | |
| priv->wakeup_irq = irq; | |
| irq = platform_get_irq_byname(pdev, "period"); | |
| if (irq < 0) | |
| return dev_err_probe(dev, irq, "Failed to get period IRQ!\n"); | |
| ret = devm_request_irq(dev, irq, rtca3_periodic_handler, 0, "rtca3-period", priv); | |
| if (ret) | |
| return dev_err_probe(dev, ret, "Failed to request period IRQ!\n"); | |
| /* | |
| * Driver doesn't implement carry handler. Just get the IRQ here | |
| * for backward compatibility, in case carry support will be added later. | |
| */ | |
| irq = platform_get_irq_byname(pdev, "carry"); | |
| if (irq < 0) | |
| return dev_err_probe(dev, irq, "Failed to get carry IRQ!\n"); | |
| return 0; | |
| } | |
| static void rtca3_action(void *data) | |
| { | |
| struct device *dev = data; | |
| struct rtca3_priv *priv = dev_get_drvdata(dev); | |
| int ret; | |
| ret = reset_control_assert(priv->rstc); | |
| if (ret) | |
| dev_err(dev, "Failed to de-assert reset!"); | |
| ret = pm_runtime_put_sync(dev); | |
| if (ret < 0) | |
| dev_err(dev, "Failed to runtime suspend!"); | |
| } | |
| static int rtca3_probe(struct platform_device *pdev) | |
| { | |
| struct device *dev = &pdev->dev; | |
| struct rtca3_priv *priv; | |
| struct clk *clk; | |
| int ret; | |
| priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | |
| if (!priv) | |
| return -ENOMEM; | |
| priv->base = devm_platform_ioremap_resource(pdev, 0); | |
| if (IS_ERR(priv->base)) | |
| return PTR_ERR(priv->base); | |
| ret = devm_pm_runtime_enable(dev); | |
| if (ret) | |
| return ret; | |
| priv->rstc = devm_reset_control_array_get_shared(dev); | |
| if (IS_ERR(priv->rstc)) | |
| return PTR_ERR(priv->rstc); | |
| ret = pm_runtime_resume_and_get(dev); | |
| if (ret) | |
| return ret; | |
| ret = reset_control_deassert(priv->rstc); | |
| if (ret) { | |
| pm_runtime_put_sync(dev); | |
| return ret; | |
| } | |
| dev_set_drvdata(dev, priv); | |
| ret = devm_add_action_or_reset(dev, rtca3_action, dev); | |
| if (ret) | |
| return ret; | |
| /* | |
| * This must be an always-on clock to keep the RTC running even after | |
| * driver is unbinded. | |
| */ | |
| clk = devm_clk_get_enabled(dev, "counter"); | |
| if (IS_ERR(clk)) | |
| return PTR_ERR(clk); | |
| spin_lock_init(&priv->lock); | |
| atomic_set(&priv->alrm_sstep, RTCA3_ALRM_SSTEP_DONE); | |
| init_completion(&priv->set_alarm_completion); | |
| ret = rtca3_initial_setup(clk, priv); | |
| if (ret) | |
| return dev_err_probe(dev, ret, "Failed to setup the RTC!\n"); | |
| ret = rtca3_request_irqs(pdev, priv); | |
| if (ret) | |
| return ret; | |
| device_init_wakeup(&pdev->dev, true); | |
| priv->rtc_dev = devm_rtc_allocate_device(&pdev->dev); | |
| if (IS_ERR(priv->rtc_dev)) | |
| return PTR_ERR(priv->rtc_dev); | |
| priv->rtc_dev->ops = &rtca3_ops; | |
| priv->rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_2000; | |
| priv->rtc_dev->range_max = RTC_TIMESTAMP_END_2099; | |
| return devm_rtc_register_device(priv->rtc_dev); | |
| } | |
| static void rtca3_remove(struct platform_device *pdev) | |
| { | |
| struct rtca3_priv *priv = platform_get_drvdata(pdev); | |
| guard(spinlock_irqsave)(&priv->lock); | |
| /* | |
| * Disable alarm, periodic interrupts. The RTC device cannot | |
| * power up the system. | |
| */ | |
| rtca3_alarm_irq_set_helper(priv, RTCA3_RCR1_AIE | RTCA3_RCR1_PIE, 0); | |
| } | |
| static int rtca3_suspend(struct device *dev) | |
| { | |
| struct rtca3_priv *priv = dev_get_drvdata(dev); | |
| if (!device_may_wakeup(dev)) | |
| return 0; | |
| /* Alarm setup in progress. */ | |
| if (atomic_read(&priv->alrm_sstep) != RTCA3_ALRM_SSTEP_DONE) | |
| return -EBUSY; | |
| enable_irq_wake(priv->wakeup_irq); | |
| return 0; | |
| } | |
| static int rtca3_clean_alarm(struct rtca3_priv *priv) | |
| { | |
| struct rtc_device *rtc_dev = priv->rtc_dev; | |
| time64_t alarm_time, now; | |
| struct rtc_wkalrm alarm; | |
| struct rtc_time tm; | |
| u8 pending; | |
| int ret; | |
| ret = rtc_read_alarm(rtc_dev, &alarm); | |
| if (ret) | |
| return ret; | |
| if (!alarm.enabled) | |
| return 0; | |
| ret = rtc_read_time(rtc_dev, &tm); | |
| if (ret) | |
| return ret; | |
| alarm_time = rtc_tm_to_time64(&alarm.time); | |
| now = rtc_tm_to_time64(&tm); | |
| if (alarm_time >= now) | |
| return 0; | |
| /* | |
| * Heuristically, it has been determined that when returning from deep | |
| * sleep state the RTCA3_RSR.AF is zero even though the alarm expired. | |
| * Call again the rtc_update_irq() if alarm helper detects this. | |
| */ | |
| guard(spinlock_irqsave)(&priv->lock); | |
| pending = rtca3_alarm_handler_helper(priv); | |
| if (!pending) | |
| rtc_update_irq(priv->rtc_dev, 1, RTC_AF | RTC_IRQF); | |
| return 0; | |
| } | |
| static int rtca3_resume(struct device *dev) | |
| { | |
| struct rtca3_priv *priv = dev_get_drvdata(dev); | |
| if (!device_may_wakeup(dev)) | |
| return 0; | |
| disable_irq_wake(priv->wakeup_irq); | |
| /* | |
| * According to the HW manual (section 22.6.4 Notes on writing to | |
| * and reading from registers) we need to wait 1/128 seconds while | |
| * RCR2.START = 1 to be able to read the counters after a return from low | |
| * power consumption state. | |
| */ | |
| mdelay(8); | |
| /* | |
| * The alarm cannot wake the system from deep sleep states. In case | |
| * we return from deep sleep states and the alarm expired we need | |
| * to disable it to avoid failures when setting another alarm. | |
| */ | |
| return rtca3_clean_alarm(priv); | |
| } | |
| static DEFINE_SIMPLE_DEV_PM_OPS(rtca3_pm_ops, rtca3_suspend, rtca3_resume); | |
| static const struct of_device_id rtca3_of_match[] = { | |
| { .compatible = "renesas,rz-rtca3", }, | |
| { /* sentinel */ } | |
| }; | |
| MODULE_DEVICE_TABLE(of, rtca3_of_match); | |
| static struct platform_driver rtca3_platform_driver = { | |
| .driver = { | |
| .name = "rtc-rtca3", | |
| .pm = pm_ptr(&rtca3_pm_ops), | |
| .of_match_table = rtca3_of_match, | |
| }, | |
| .probe = rtca3_probe, | |
| .remove = rtca3_remove, | |
| }; | |
| module_platform_driver(rtca3_platform_driver); | |
| MODULE_DESCRIPTION("Renesas RTCA-3 RTC driver"); | |
| MODULE_AUTHOR("Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>"); | |
| MODULE_LICENSE("GPL"); |