RE: [PATCH 06/12] rtc: renesas-rtca3: Add driver for RTCA-3 available on Renesas RZ/G3S SoC

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Claudiu,

Thanks for the patch.

> -----Original Message-----
> From: Claudiu <claudiu.beznea@xxxxxxxxx>
> Sent: Friday, June 14, 2024 8:19 AM
> Subject: [PATCH 06/12] rtc: renesas-rtca3: Add driver for RTCA-3 available on Renesas RZ/G3S SoC
> 
> From: Claudiu Beznea <claudiu.beznea.uj@xxxxxxxxxxxxxx>
> 
> The RTC IP (RTCA-3) available on the Renesas RZ/G3S SoC has calendar count mode and binary count
> mode (selectable though RCR2.CNTMD) capabilities, alarm capabilities, clock error correction
> capabilities. It can generate alarm, period, carry interrupts.
> 
> Add a driver for RTCA-3 IP. The driver implements calendar count mode (as the conversion b/w RTC
> and system time is simpler, done with bcd2bin(), bin2bcd()), read and set time, read and set alarm,
> read and set an offset.
> 
> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@xxxxxxxxxxxxxx>
> ---
>  MAINTAINERS                     |   8 +
>  drivers/rtc/Kconfig             |  10 +
>  drivers/rtc/Makefile            |   1 +
>  drivers/rtc/rtc-renesas-rtca3.c | 891 ++++++++++++++++++++++++++++++++
>  4 files changed, 910 insertions(+)
>  create mode 100644 drivers/rtc/rtc-renesas-rtca3.c
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 670b8201973b..0b4bf350c416 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -19173,6 +19173,14 @@ S:	Supported
>  F:	Documentation/devicetree/bindings/timer/renesas,rz-mtu3.yaml
>  F:	drivers/counter/rz-mtu3-cnt.c
> 
> +RENESAS RZ/G3S RTC DRIVER
Maybe make it generic "RENESAS RTCA3 RTC DRIVER" as it is an IP
can be used in future SoCs??

> +M:	Claudiu Beznea <claudiu.beznea.uj@xxxxxxxxxxxxxx>
> +L:	linux-rtc@xxxxxxxxxxxxxxx
> +L:	linux-renesas-soc@xxxxxxxxxxxxxxx
> +S:	Supported
> +F:	Documentation/devicetree/bindings/rtc/renesas,rzg3s-rtc.yaml
Make generic name "renesas,rtca3-rtc.yaml??

Cheers,
Biju

> +F:	drivers/rtc/rtc-renesas-rtca3.c
> +
>  RENESAS RZ/N1 A5PSW SWITCH DRIVER
>  M:	Clément Léger <clement.leger@xxxxxxxxxxx>
>  L:	linux-renesas-soc@xxxxxxxxxxxxxxx
> diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 2a95b05982ad..3b29b35e48e0 100644
> --- a/drivers/rtc/Kconfig
> +++ b/drivers/rtc/Kconfig
> @@ -1978,6 +1978,16 @@ config RTC_DRV_MA35D1
>  	   This driver can also be built as a module, if so, the module
>  	   will be called "rtc-ma35d1".
> 
> +config RTC_DRV_RENESAS_RTCA3
> +	tristate "Renesas RTCA-3 RTC"
> +	depends on ARCH_RENESAS
> +	help
> +	  If you say yes here you get support for the Renesas RTCA-3 RTC
> +	  available on the Renesas RZ/G3S SoC.
> +
> +	  This driver can also be built as a module, if so, the module
> +	  will be called "rtc-rtca3".
> +
>  comment "HID Sensor RTC drivers"
> 
>  config RTC_DRV_HID_SENSOR_TIME
> diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 3004e372f25f..52844f13b247 100644
> --- a/drivers/rtc/Makefile
> +++ b/drivers/rtc/Makefile
> @@ -157,6 +157,7 @@ obj-$(CONFIG_RTC_DRV_RX8025)	+= rtc-rx8025.o
>  obj-$(CONFIG_RTC_DRV_RX8111)	+= rtc-rx8111.o
>  obj-$(CONFIG_RTC_DRV_RX8581)	+= rtc-rx8581.o
>  obj-$(CONFIG_RTC_DRV_RZN1)	+= rtc-rzn1.o
> +obj-$(CONFIG_RTC_DRV_RENESAS_RTCA3)	+= rtc-renesas-rtca3.o
>  obj-$(CONFIG_RTC_DRV_S35390A)	+= rtc-s35390a.o
>  obj-$(CONFIG_RTC_DRV_S3C)	+= rtc-s3c.o
>  obj-$(CONFIG_RTC_DRV_S5M)	+= rtc-s5m.o
> diff --git a/drivers/rtc/rtc-renesas-rtca3.c b/drivers/rtc/rtc-renesas-rtca3.c new file mode 100644
> index 000000000000..e2edf12d0c54
> --- /dev/null
> +++ b/drivers/rtc/rtc-renesas-rtca3.c
> @@ -0,0 +1,891 @@
> +// 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/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/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
> + * @clk: RTC clock
> + * @rtc_dev: RTC device
> + * @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 clk *clk;
> +	struct rtc_device *rtc_dev;
> +	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;
> +
> +	spin_lock(&priv->lock);
> +	pending = rtca3_alarm_handler_helper(priv);
> +	spin_unlock(&priv->lock);
> +
> +	return IRQ_RETVAL(pending);
> +}
> +
> +static irqreturn_t rtca3_periodic_handler(int irq, void *dev_id) {
> +	struct rtca3_priv *priv = dev_id;
> +	u8 val, pending;
> +
> +	spin_lock(&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);
> +			}
> +		}
> +	}
> +
> +	spin_unlock(&priv->lock);
> +
> +	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;
> +	unsigned long flags;
> +	u8 trials = 0;
> +	int ret = 0;
> +	u32 year100;
> +	u16 year;
> +
> +	spin_lock_irqsave(&priv->lock, flags);
> +
> +	tmp = readb(priv->base + RTCA3_RCR2);
> +	if (!(tmp & RTCA3_RCR2_START)) {
> +		ret = -EINVAL;
> +		goto unlock;
> +	}
> +
> +	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) {
> +		ret = -ETIMEDOUT;
> +		goto unlock;
> +	}
> +
> +	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));
> +	if (hour & RTCA3_RHRCNT_PM)
> +		tm->tm_hour += 12;
> +	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;
> +
> +unlock:
> +	spin_unlock_irqrestore(&priv->lock, flags);
> +
> +	return ret;
> +}
> +
> +static int rtca3_set_time(struct device *dev, struct rtc_time *tm) {
> +	struct rtca3_priv *priv = dev_get_drvdata(dev);
> +	unsigned long flags;
> +	u8 rcr2, tmp;
> +	int ret;
> +
> +	spin_lock_irqsave(&priv->lock, flags);
> +
> +	/* 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)
> +		goto unlock;
> +
> +	/* Update time. */
> +	writeb(bin2bcd(tm->tm_sec), priv->base + RTCA3_RSECCNT);
> +	writeb(bin2bcd(tm->tm_min), priv->base + RTCA3_RMINCNT);
> +	if (tm->tm_hour > 12)
> +		writeb(RTCA3_RHRCNT_PM | bin2bcd(tm->tm_hour - 12), priv->base + RTCA3_RHRCNT);
> +	else
> +		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);
> +	ret = readb_poll_timeout_atomic(priv->base + RTCA3_RCR2, tmp,
> +					(tmp & RTCA3_RCR2_START),
> +					10, RTCA3_DEFAULT_TIMEOUT_US);
> +
> +unlock:
> +	spin_unlock_irqrestore(&priv->lock, flags);
> +
> +	return ret;
> +}
> +
> +static int rtca3_alarm_irq_enable_helper(struct rtca3_priv *priv,
> +					 unsigned int enabled)
> +{
> +	u8 tmp, mask;
> +
> +	if (enabled) {
> +		rtca3_byte_update_bits(priv, RTCA3_RSR, RTCA3_RSR_AF, 0);
> +		mask = RTCA3_RCR1_AIE;
> +	} else {
> +		mask = 0;
> +	}
> +
> +	rtca3_byte_update_bits(priv, RTCA3_RCR1, RTCA3_RCR1_AIE, mask);
> +	return readb_poll_timeout_atomic(priv->base + RTCA3_RCR1, tmp,
> +					 ((tmp & RTCA3_RCR1_AIE) == mask),
> +					 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);
> +	unsigned long flags;
> +	int ret;
> +
> +	spin_lock_irqsave(&priv->lock, flags);
> +	ret = rtca3_alarm_irq_enable_helper(priv, enabled);
> +	spin_unlock_irqrestore(&priv->lock, flags);
> +
> +	return ret;
> +}
> +
> +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;
> +	unsigned long flags;
> +	u32 year100;
> +	u16 year;
> +
> +	spin_lock_irqsave(&priv->lock, flags);
> +
> +	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));
> +	if (hour & RTCA3_RHRAR_PM)
> +		tm->tm_hour += 12;
> +	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);
> +
> +	spin_unlock_irqrestore(&priv->lock, flags);
> +
> +	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;
> +	unsigned long flags;
> +	u8 rcr1, tmp;
> +	int ret;
> +
> +	spin_lock_irqsave(&priv->lock, flags);
> +
> +	tmp = readb(priv->base + RTCA3_RCR2);
> +	if (!(tmp & RTCA3_RCR2_START)) {
> +		ret = -EPERM;
> +		goto unlock;
> +	}
> +
> +	/* 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)
> +		goto unlock;
> +
> +	/* 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);
> +	if (tm->tm_hour > 12) {
> +		writeb(RTCA3_AR_ENB | RTCA3_RHRAR_PM | bin2bcd(tm->tm_hour - 12),
> +		       priv->base + RTCA3_RHRAR);
> +	} else {
> +		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);
> +
> +	spin_unlock_irqrestore(&priv->lock, flags);
> +
> +	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;
> +	}
> +
> +	spin_lock_irqsave(&priv->lock, flags);
> +
> +	ret = rtca3_alarm_irq_enable_helper(priv, wkalrm->enabled);
> +	atomic_set(&priv->alrm_sstep, RTCA3_ALRM_SSTEP_DONE);
> +
> +unlock:
> +	spin_unlock_irqrestore(&priv->lock, flags);
> +
> +	return ret;
> +
> +setup_failed:
> +	spin_lock_irqsave(&priv->lock, flags);
> +	/*
> +	 * 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);
> +	spin_unlock_irqrestore(&priv->lock, flags);
> +
> +	return ret;
> +}
> +
> +static int rtca3_read_offset(struct device *dev, long *offset) {
> +	struct rtca3_priv *priv = dev_get_drvdata(dev);
> +	u8 val, radj, cycles;
> +	unsigned long flags;
> +	u32 ppb_per_cycle;
> +
> +	spin_lock_irqsave(&priv->lock, flags);
> +	radj = readb(priv->base + RTCA3_RADJ);
> +	val = readb(priv->base + RTCA3_RCR2);
> +	spin_unlock_irqrestore(&priv->lock, flags);
> +
> +	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;
> +	unsigned long flags;
> +	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);
> +
> +	spin_lock_irqsave(&priv->lock, flags);
> +
> +	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)
> +			goto unlock;
> +
> +		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)
> +			goto unlock;
> +	}
> +
> +	writeb(radj, priv->base + RTCA3_RADJ);
> +	ret = readb_poll_timeout_atomic(priv->base + RTCA3_RADJ, tmp, (tmp == radj),
> +					10, RTCA3_DEFAULT_TIMEOUT_US);
> +unlock:
> +	spin_unlock_irqrestore(&priv->lock, flags);
> +
> +	return ret;
> +}
> +
> +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 rtca3_priv *priv) {
> +	unsigned long osc32k_rate;
> +	u8 pes, tmp, mask;
> +	u32 sleep_us;
> +	int ret;
> +
> +	osc32k_rate = clk_get_rate(priv->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);
> +
> +	/* Disable alarm and carry interrupts. */
> +	mask = RTCA3_RCR1_AIE | RTCA3_RCR1_CIE;
> +	rtca3_byte_update_bits(priv, RTCA3_RCR1, mask, 0);
> +	ret = readb_poll_timeout(priv->base + RTCA3_RCR1, tmp, !(tmp & mask),
> +				 10, RTCA3_DEFAULT_TIMEOUT_US);
> +	if (ret)
> +		return ret;
> +
> +	/*
> +	 * Stop the RTC and set to 12 hours mode and calendar count mode.
> +	 * RCR2.START initial value is undefined so we need to stop here
> +	 * all the time.
> +	 */
> +	mask = RTCA3_RCR2_START | RTCA3_RCR2_HR24 | 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;
> +
> +	/* Execute reset and wait for reset and calendar count mode to be applied. */
> +	mask = RTCA3_RCR2_RESET | RTCA3_RCR2_CNTMD;
> +	writeb(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;
> +	writeb(RTCA3_RCR2_START | RTCA3_RCR2_AADJE, 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. */
> +	pes = FIELD_PREP(RTCA3_RCR1_PES, RTCA3_RCR1_PES_1_64_SEC);
> +	rtca3_byte_update_bits(priv, RTCA3_RCR1, RTCA3_RCR1_PES, pes);
> +	return readb_poll_timeout(priv->base + RTCA3_RCR1, tmp, ((tmp & RTCA3_RCR1_PES) == pes),
> +				  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 int rtca3_probe(struct platform_device *pdev) {
> +	struct device *dev = &pdev->dev;
> +	struct rtca3_priv *priv;
> +	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);
> +
> +	priv->clk = devm_clk_get_enabled(dev, "counter");
> +	if (IS_ERR(priv->clk))
> +		return PTR_ERR(priv->clk);
> +
> +	platform_set_drvdata(pdev, priv);
> +
> +	spin_lock_init(&priv->lock);
> +	atomic_set(&priv->alrm_sstep, RTCA3_ALRM_SSTEP_DONE);
> +	init_completion(&priv->set_alarm_completion);
> +
> +	ret = rtca3_initial_setup(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, 1);
> +
> +	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->max_user_freq = 256;
> +	priv->rtc_dev->range_min = mktime64(1999, 1, 1, 0, 0, 0);
> +	priv->rtc_dev->range_max = mktime64(2098, 12, 31, 23, 59, 59);
> +
> +	return devm_rtc_register_device(priv->rtc_dev);
> +}
> +
> +static void rtca3_remove(struct platform_device *pdev) {
> +	struct rtca3_priv *priv = platform_get_drvdata(pdev);
> +	u8 tmp, mask = RTCA3_RCR1_AIE | RTCA3_RCR1_PIE;
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&priv->lock, flags);
> +
> +	/* Disable alarm, periodic interrupt. */
> +	rtca3_byte_update_bits(priv, RTCA3_RCR1, mask, 0);
> +	readb_poll_timeout_atomic(priv->base + RTCA3_RCR1, tmp, !(tmp & mask),
> +				  10, RTCA3_IRQSET_TIMEOUT_US);
> +
> +	spin_unlock_irqrestore(&priv->lock, flags); }
> +
> +static int __maybe_unused 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;
> +	unsigned long flags;
> +	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.
> +	 */
> +
> +	spin_lock_irqsave(&priv->lock, flags);
> +	pending = rtca3_alarm_handler_helper(priv);
> +	if (!pending)
> +		rtc_update_irq(priv->rtc_dev, 1, RTC_AF | RTC_IRQF);
> +	spin_unlock_irqrestore(&priv->lock, flags);
> +
> +	return 0;
> +}
> +
> +static int __maybe_unused 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 SIMPLE_DEV_PM_OPS(rtca3_pm_ops, rtca3_suspend, rtca3_resume);
> +
> +static const struct of_device_id rtca3_of_match[] = {
> +	{ .compatible = "renesas,rzg3s-rtc", },
> +	{ /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, rtca3_of_match);
> +
> +static struct platform_driver rtca3_platform_driver = {
> +	.driver = {
> +		.name = "rtc-rtca3",
> +		.pm = &rtca3_pm_ops,
> +		.of_match_table = rtca3_of_match,
> +	},
> +	.probe = rtca3_probe,
> +	.remove_new = rtca3_remove,
> +};
> +module_platform_driver(rtca3_platform_driver);
> +
> +MODULE_DESCRIPTION("Renesas RTCA-3 RTC driver"); MODULE_AUTHOR("Claudiu
> +Beznea <claudiu.beznea.uj@xxxxxxxxxxxxxx>");
> +MODULE_LICENSE("GPL");
> --
> 2.39.2
> 





[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]


  Powered by Linux