All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] rtc: add mxc driver for i.MX53
@ 2017-11-28  7:39 ` linux-kernel-dev
  0 siblings, 0 replies; 43+ messages in thread
From: linux-kernel-dev @ 2017-11-28  7:39 UTC (permalink / raw)
  To: Alessandro Zummo, Alexandre Belloni
  Cc: Patrick Bruenn, Rob Herring, Mark Rutland,
	open list:REAL TIME CLOCK (RTC) SUBSYSTEM,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	open list, Fabio Estevam, Juergen Borleis, Noel Vellemans,
	Shawn Guo, Sascha Hauer, Russell King,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE

From: Patrick Bruenn <p.bruenn@beckhoff.com>

Neither rtc-imxdi nor rtc-mxc are compatible with i.MX53.
Add a modernized version of mxc_v2 from here:
http://git.freescale.com/git/cgit.cgi/imx/linux-2.6-imx.git/tree/drivers/rtc/rtc-mxc_v2.c?h=imx_2.6.35_11.09.01

Changes to that version:
- updated to v4.15-rc1
- removed ioctl()
- removed proc()
- removed manual(redundant) enable_irq flag

Signed-off-by: Patrick Bruenn <p.bruenn@beckhoff.com>

---

Open issues:
- driver naming, should it be merged with rtc-mxc.c ?
- document DT binding "fsl,imx53-rtc" accordingly
- Should unused defines be removed or kept for someone else to be
  useful?
- Is the use of __raw_readl/writel() correct? Should it be replaced with
  readl/writel()?
- suspend/resume() seems different to existing rtc-mxc.c, should I apply
  the pattern from rtc-mxc.c?
- On Shawns tree imx53.dtsi has been reverted already[1][2]. Should I split
  the imx53.dtsi change into a separate patch based on his tree? Or can
  we still stop the full revert and just remove the imx25-rtc compatible?
  I am not in a hurry, so we could just wait until the revert landed in
  Linus tree. Whatever you think is best.

[1] https://www.spinics.net/lists/arm-kernel/msg617113.html
[2] commit ee76f7729babd2700afd6f3874449d8084dd85ea

To: Alessandro Zummo <a.zummo@towertech.it>
To: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com> (maintainer:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS)
Cc: linux-rtc@vger.kernel.org (open list:REAL TIME CLOCK (RTC) SUBSYSTEM)
Cc: devicetree@vger.kernel.org (open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS)
Cc: linux-kernel@vger.kernel.org (open list)
Cc: Fabio Estevam <fabio.estevam@nxp.com>
Cc: Juergen Borleis <jbe@pengutronix.de>
Cc: Noel Vellemans <Noel.Vellemans@visionbms.com>
Cc: Shawn Guo <shawnguo@kernel.org>
Cc: Sascha Hauer <kernel@pengutronix.de> (maintainer:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE)
Cc: Russell King <linux@armlinux.org.uk> (maintainer:ARM PORT)
Cc: linux-arm-kernel@lists.infradead.org (moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE)
---
 arch/arm/boot/dts/imx53.dtsi |   2 +-
 drivers/rtc/Makefile         |   1 +
 drivers/rtc/rtc-mxc_v2.c     | 531 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 533 insertions(+), 1 deletion(-)
 create mode 100644 drivers/rtc/rtc-mxc_v2.c

diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi
index 589a67c5f796..3d1a55e11ea8 100644
--- a/arch/arm/boot/dts/imx53.dtsi
+++ b/arch/arm/boot/dts/imx53.dtsi
@@ -434,7 +434,7 @@
 			};
 
 			srtc: srtc@53fa4000 {
-				compatible = "fsl,imx53-rtc", "fsl,imx25-rtc";
+				compatible = "fsl,imx53-rtc";
 				reg = <0x53fa4000 0x4000>;
 				interrupts = <24>;
 				interrupt-parent = <&tzic>;
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index f2f50c11dc38..fb3dc458c185 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -106,6 +106,7 @@ obj-$(CONFIG_RTC_DRV_MT6397)	+= rtc-mt6397.o
 obj-$(CONFIG_RTC_DRV_MT7622)	+= rtc-mt7622.o
 obj-$(CONFIG_RTC_DRV_MV)	+= rtc-mv.o
 obj-$(CONFIG_RTC_DRV_MXC)	+= rtc-mxc.o
+obj-$(CONFIG_RTC_DRV_MXC)	+= rtc-mxc_v2.o
 obj-$(CONFIG_RTC_DRV_NUC900)	+= rtc-nuc900.o
 obj-$(CONFIG_RTC_DRV_OMAP)	+= rtc-omap.o
 obj-$(CONFIG_RTC_DRV_OPAL)	+= rtc-opal.o
diff --git a/drivers/rtc/rtc-mxc_v2.c b/drivers/rtc/rtc-mxc_v2.c
new file mode 100644
index 000000000000..5049b521b38e
--- /dev/null
+++ b/drivers/rtc/rtc-mxc_v2.c
@@ -0,0 +1,531 @@
+/*
+ * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+/*
+ * Implementation based on rtc-ds1553.c
+ */
+
+/*!
+ * @defgroup RTC Real Time Clock (RTC) Driver for i.MX53
+ */
+/*!
+ * @file rtc-mxc_v2.c
+ * @brief Real Time Clock interface
+ *
+ * This file contains Real Time Clock interface for Linux.
+ *
+ * @ingroup RTC
+ */
+
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/rtc.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+//#include <linux/mxc_srtc.h>
+#define RTC_READ_TIME_47BIT	_IOR('p', 0x20, unsigned long long)
+/* blocks until LPSCMR is set, returns difference */
+#define RTC_WAIT_TIME_SET	_IOR('p', 0x21, int64_t)
+
+#define SRTC_LPSCLR_LLPSC_LSH	17	/* start bit for LSB time value */
+
+#define SRTC_LPPDR_INIT       0x41736166	/* init for glitch detect */
+
+#define SRTC_LPCR_SWR_LP      (1 << 0)	/* lp software reset */
+#define SRTC_LPCR_EN_LP       (1 << 3)	/* lp enable */
+#define SRTC_LPCR_WAE         (1 << 4)	/* lp wakeup alarm enable */
+#define SRTC_LPCR_SAE         (1 << 5)	/* lp security alarm enable */
+#define SRTC_LPCR_SI          (1 << 6)	/* lp security interrupt enable */
+#define SRTC_LPCR_ALP         (1 << 7)	/* lp alarm flag */
+#define SRTC_LPCR_LTC         (1 << 8)	/* lp lock time counter */
+#define SRTC_LPCR_LMC         (1 << 9)	/* lp lock monotonic counter */
+#define SRTC_LPCR_SV          (1 << 10)	/* lp security violation */
+#define SRTC_LPCR_NSA         (1 << 11)	/* lp non secure access */
+#define SRTC_LPCR_NVEIE       (1 << 12)	/* lp non valid state exit int en */
+#define SRTC_LPCR_IEIE        (1 << 13)	/* lp init state exit int enable */
+#define SRTC_LPCR_NVE         (1 << 14)	/* lp non valid state exit bit */
+#define SRTC_LPCR_IE          (1 << 15)	/* lp init state exit bit */
+
+#define SRTC_LPCR_ALL_INT_EN (SRTC_LPCR_WAE | SRTC_LPCR_SAE | \
+			      SRTC_LPCR_SI | SRTC_LPCR_ALP | \
+			      SRTC_LPCR_NVEIE | SRTC_LPCR_IEIE)
+
+#define SRTC_LPSR_TRI         (1 << 0)	/* lp time read invalidate */
+#define SRTC_LPSR_PGD         (1 << 1)	/* lp power supply glitc detected */
+#define SRTC_LPSR_CTD         (1 << 2)	/* lp clock tampering detected */
+#define SRTC_LPSR_ALP         (1 << 3)	/* lp alarm flag */
+#define SRTC_LPSR_MR          (1 << 4)	/* lp monotonic counter rollover */
+#define SRTC_LPSR_TR          (1 << 5)	/* lp time rollover */
+#define SRTC_LPSR_EAD         (1 << 6)	/* lp external alarm detected */
+#define SRTC_LPSR_IT0         (1 << 7)	/* lp IIM throttle */
+#define SRTC_LPSR_IT1         (1 << 8)
+#define SRTC_LPSR_IT2         (1 << 9)
+#define SRTC_LPSR_SM0         (1 << 10)	/* lp security mode */
+#define SRTC_LPSR_SM1         (1 << 11)
+#define SRTC_LPSR_STATE_LP0   (1 << 12)	/* lp state */
+#define SRTC_LPSR_STATE_LP1   (1 << 13)
+#define SRTC_LPSR_NVES        (1 << 14)	/* lp non-valid state exit status */
+#define SRTC_LPSR_IES         (1 << 15)	/* lp init state exit status */
+
+#define MAX_PIE_NUM     15
+#define MAX_PIE_FREQ    32768
+#define MIN_PIE_FREQ	1
+
+#define SRTC_PI0         (1 << 0)
+#define SRTC_PI1         (1 << 1)
+#define SRTC_PI2         (1 << 2)
+#define SRTC_PI3         (1 << 3)
+#define SRTC_PI4         (1 << 4)
+#define SRTC_PI5         (1 << 5)
+#define SRTC_PI6         (1 << 6)
+#define SRTC_PI7         (1 << 7)
+#define SRTC_PI8         (1 << 8)
+#define SRTC_PI9         (1 << 9)
+#define SRTC_PI10        (1 << 10)
+#define SRTC_PI11        (1 << 11)
+#define SRTC_PI12        (1 << 12)
+#define SRTC_PI13        (1 << 13)
+#define SRTC_PI14        (1 << 14)
+#define SRTC_PI15        (1 << 15)
+
+#define PIT_ALL_ON      (SRTC_PI1 | SRTC_PI2 | SRTC_PI3 | \
+			SRTC_PI4 | SRTC_PI5 | SRTC_PI6 | SRTC_PI7 | \
+			SRTC_PI8 | SRTC_PI9 | SRTC_PI10 | SRTC_PI11 | \
+			SRTC_PI12 | SRTC_PI13 | SRTC_PI14 | SRTC_PI15)
+
+#define SRTC_SWR_HP      (1 << 0)	/* hp software reset */
+#define SRTC_EN_HP       (1 << 3)	/* hp enable */
+#define SRTC_TS          (1 << 4)	/* time synchronize hp with lp */
+
+#define SRTC_IE_AHP      (1 << 16)	/* Alarm HP Interrupt Enable bit */
+#define SRTC_IE_WDHP     (1 << 18)	/* Write Done HP Interrupt Enable bit */
+#define SRTC_IE_WDLP     (1 << 19)	/* Write Done LP Interrupt Enable bit */
+
+#define SRTC_ISR_AHP     (1 << 16)	/* interrupt status: alarm hp */
+#define SRTC_ISR_WDHP    (1 << 18)	/* interrupt status: write done hp */
+#define SRTC_ISR_WDLP    (1 << 19)	/* interrupt status: write done lp */
+#define SRTC_ISR_WPHP    (1 << 20)	/* interrupt status: write pending hp */
+#define SRTC_ISR_WPLP    (1 << 21)	/* interrupt status: write pending lp */
+
+#define SRTC_LPSCMR	0x00	/* LP Secure Counter MSB Reg */
+#define SRTC_LPSCLR	0x04	/* LP Secure Counter LSB Reg */
+#define SRTC_LPSAR	0x08	/* LP Secure Alarm Reg */
+#define SRTC_LPSMCR	0x0C	/* LP Secure Monotonic Counter Reg */
+#define SRTC_LPCR	0x10	/* LP Control Reg */
+#define SRTC_LPSR	0x14	/* LP Status Reg */
+#define SRTC_LPPDR	0x18	/* LP Power Supply Glitch Detector Reg */
+#define SRTC_LPGR	0x1C	/* LP General Purpose Reg */
+#define SRTC_HPCMR	0x20	/* HP Counter MSB Reg */
+#define SRTC_HPCLR	0x24	/* HP Counter LSB Reg */
+#define SRTC_HPAMR	0x28	/* HP Alarm MSB Reg */
+#define SRTC_HPALR	0x2C	/* HP Alarm LSB Reg */
+#define SRTC_HPCR	0x30	/* HP Control Reg */
+#define SRTC_HPISR	0x34	/* HP Interrupt Status Reg */
+#define SRTC_HPIENR	0x38	/* HP Interrupt Enable Reg */
+
+#define SRTC_SECMODE_MASK	0x3	/* the mask of SRTC security mode */
+#define SRTC_SECMODE_LOW	0x0	/* Low Security */
+#define SRTC_SECMODE_MED	0x1	/* Medium Security */
+#define SRTC_SECMODE_HIGH	0x2	/* High Security */
+#define SRTC_SECMODE_RESERVED	0x3	/* Reserved */
+
+struct rtc_drv_data {
+	struct rtc_device *rtc;
+	void __iomem *ioaddr;
+	int irq;
+	struct clk *clk;
+};
+
+static DEFINE_SPINLOCK(rtc_lock);
+
+/*!
+ * This function does write synchronization for writes to the lp srtc block.
+ * To take care of the asynchronous CKIL clock, all writes from the IP domain
+ * will be synchronized to the CKIL domain.
+ */
+static inline void rtc_write_sync_lp(void __iomem *ioaddr)
+{
+	unsigned int i, count;
+	/* Wait for 3 CKIL cycles */
+	for (i = 0; i < 3; i++) {
+		count = readl(ioaddr + SRTC_LPSCLR);
+		while ((readl(ioaddr + SRTC_LPSCLR)) == count)
+			;
+	}
+}
+
+/*!
+ * This function updates the RTC alarm registers and then clears all the
+ * interrupt status bits.
+ *
+ * @param  alrm         the new alarm value to be updated in the RTC
+ *
+ * @return  0 if successful; non-zero otherwise.
+ */
+static int rtc_update_alarm(struct device *dev, struct rtc_time *alrm)
+{
+	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
+	void __iomem *ioaddr = pdata->ioaddr;
+	struct rtc_time alarm_tm, now_tm;
+	unsigned long now, time;
+	int ret;
+
+	now = __raw_readl(ioaddr + SRTC_LPSCMR);
+	rtc_time_to_tm(now, &now_tm);
+
+	alarm_tm.tm_year = now_tm.tm_year;
+	alarm_tm.tm_mon = now_tm.tm_mon;
+	alarm_tm.tm_mday = now_tm.tm_mday;
+
+	alarm_tm.tm_hour = alrm->tm_hour;
+	alarm_tm.tm_min = alrm->tm_min;
+	alarm_tm.tm_sec = alrm->tm_sec;
+
+	rtc_tm_to_time(&now_tm, &now);
+	rtc_tm_to_time(&alarm_tm, &time);
+
+	if (time < now) {
+		time += 60 * 60 * 24;
+		rtc_time_to_tm(time, &alarm_tm);
+	}
+	ret = rtc_tm_to_time(&alarm_tm, &time);
+
+	__raw_writel(time, ioaddr + SRTC_LPSAR);
+
+	/* clear alarm interrupt status bit */
+	__raw_writel(SRTC_LPSR_ALP, ioaddr + SRTC_LPSR);
+
+	return ret;
+}
+
+/*!
+ * This function is the RTC interrupt service routine.
+ *
+ * @param  irq          RTC IRQ number
+ * @param  dev_id       device ID which is not used
+ *
+ * @return IRQ_HANDLED as defined in the include/linux/interrupt.h file.
+ */
+static irqreturn_t mxc_rtc_interrupt(int irq, void *dev_id)
+{
+	struct platform_device *pdev = dev_id;
+	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
+	void __iomem *ioaddr = pdata->ioaddr;
+	u32 lp_status, lp_cr;
+	u32 events = 0;
+
+	lp_status = __raw_readl(ioaddr + SRTC_LPSR);
+	lp_cr = __raw_readl(ioaddr + SRTC_LPCR);
+
+	/* update irq data & counter */
+	if (lp_status & SRTC_LPSR_ALP) {
+		if (lp_cr & SRTC_LPCR_ALP)
+			events |= (RTC_AF | RTC_IRQF);
+
+		/* disable further lp alarm interrupts */
+		lp_cr &= ~(SRTC_LPCR_ALP | SRTC_LPCR_WAE);
+	}
+
+	/* Update interrupt enables */
+	__raw_writel(lp_cr, ioaddr + SRTC_LPCR);
+
+	/* clear interrupt status */
+	__raw_writel(lp_status, ioaddr + SRTC_LPSR);
+
+	rtc_write_sync_lp(ioaddr);
+	rtc_update_irq(pdata->rtc, 1, events);
+	return IRQ_HANDLED;
+}
+
+/*!
+ * This function reads the current RTC time into tm in Gregorian date.
+ *
+ * @param  tm           contains the RTC time value upon return
+ *
+ * @return  0 if successful; non-zero otherwise.
+ */
+static int mxc_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
+	time_t now = readl(pdata->ioaddr + SRTC_LPSCMR);
+
+	rtc_time_to_tm(now, tm);
+	return rtc_valid_tm(tm);
+}
+
+/*!
+ * This function sets the internal RTC time based on tm in Gregorian date.
+ *
+ * @param  tm           the time value to be set in the RTC
+ *
+ * @return  0 if successful; non-zero otherwise.
+ */
+static int mxc_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
+	time64_t time = rtc_tm_to_time64(tm);
+
+	if (time > UINT_MAX) {
+		dev_warn(dev, "time_t has overflow\n");
+	}
+
+	writel(time, pdata->ioaddr + SRTC_LPSCMR);
+	rtc_write_sync_lp(pdata->ioaddr);
+	return 0;
+}
+
+/*!
+ * This function reads the current alarm value into the passed in \b alrm
+ * argument. It updates the \b alrm's pending field value based on the whether
+ * an alarm interrupt occurs or not.
+ *
+ * @param  alrm         contains the RTC alarm value upon return
+ *
+ * @return  0 if successful; non-zero otherwise.
+ */
+static int mxc_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
+	void __iomem *ioaddr = pdata->ioaddr;
+
+	rtc_time_to_tm(__raw_readl(ioaddr + SRTC_LPSAR), &alrm->time);
+	alrm->pending =
+	    ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_ALP) != 0) ? 1 : 0;
+
+	return 0;
+}
+
+static int mxc_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
+{
+	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
+	unsigned long lock_flags = 0;
+	u32 lp_cr;
+
+	spin_lock_irqsave(&rtc_lock, lock_flags);
+	lp_cr = __raw_readl(pdata->ioaddr + SRTC_LPCR);
+
+	if (enable)
+		lp_cr |= (SRTC_LPCR_ALP | SRTC_LPCR_WAE);
+	else
+		lp_cr &= ~(SRTC_LPCR_ALP | SRTC_LPCR_WAE);
+
+	__raw_writel(lp_cr, pdata->ioaddr + SRTC_LPCR);
+	spin_unlock_irqrestore(&rtc_lock, lock_flags);
+	return 0;
+}
+
+/*!
+ * This function sets the RTC alarm based on passed in alrm.
+ *
+ * @param  alrm         the alarm value to be set in the RTC
+ *
+ * @return  0 if successful; non-zero otherwise.
+ */
+static int mxc_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
+	void __iomem *ioaddr = pdata->ioaddr;
+	int ret;
+
+	ret = rtc_update_alarm(dev, &alrm->time);
+	if (!ret)
+		mxc_rtc_alarm_irq_enable(dev, alrm->enabled);
+
+	rtc_write_sync_lp(ioaddr);
+	return ret;
+}
+
+/*!
+ * The RTC driver structure
+ */
+static const struct rtc_class_ops mxc_rtc_ops = {
+	.read_time = mxc_rtc_read_time,
+	.set_time = mxc_rtc_set_time,
+	.read_alarm = mxc_rtc_read_alarm,
+	.set_alarm = mxc_rtc_set_alarm,
+	.alarm_irq_enable = mxc_rtc_alarm_irq_enable,
+};
+
+/*! MXC RTC Power management control */
+static int mxc_rtc_probe(struct platform_device *pdev)
+{
+	struct timespec tv;
+	struct resource *res;
+	struct rtc_drv_data *pdata = NULL;
+	void __iomem *ioaddr;
+	int ret = 0;
+
+	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	pdata->ioaddr = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(pdata->ioaddr))
+		return PTR_ERR(pdata->ioaddr);
+
+	ioaddr = pdata->ioaddr;
+
+	pdata->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(pdata->clk)) {
+		dev_err(&pdev->dev, "unable to get rtc clock!\n");
+		return PTR_ERR(pdata->clk);
+	}
+	ret = clk_prepare_enable(pdata->clk);
+	if (ret)
+		return ret;
+
+	/* Configure and enable the RTC */
+	pdata->irq = platform_get_irq(pdev, 0);
+	if (pdata->irq >= 0
+	    && devm_request_irq(&pdev->dev, pdata->irq, mxc_rtc_interrupt,
+				IRQF_SHARED, pdev->name, pdev) < 0) {
+		dev_warn(&pdev->dev, "interrupt not available.\n");
+		pdata->irq = -1;
+	}
+
+	if (pdata->irq >= 0)
+		device_init_wakeup(&pdev->dev, 1);
+
+	/* initialize glitch detect */
+	__raw_writel(SRTC_LPPDR_INIT, ioaddr + SRTC_LPPDR);
+	udelay(100);
+
+	/* clear lp interrupt status */
+	__raw_writel(0xFFFFFFFF, ioaddr + SRTC_LPSR);
+	udelay(100);
+
+	/* move out of init state */
+	__raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NSA), ioaddr + SRTC_LPCR);
+
+	udelay(100);
+
+	while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_IES) == 0)
+		;
+
+	/* move out of non-valid state */
+	__raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NVE | SRTC_LPCR_NSA |
+		      SRTC_LPCR_EN_LP), ioaddr + SRTC_LPCR);
+
+	udelay(100);
+
+	while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_NVES) == 0)
+		;
+
+	__raw_writel(0xFFFFFFFF, ioaddr + SRTC_LPSR);
+	udelay(100);
+
+	platform_set_drvdata(pdev, pdata);
+	pdata->rtc =
+	    devm_rtc_device_register(&pdev->dev, pdev->name, &mxc_rtc_ops,
+				     THIS_MODULE);
+	if (IS_ERR(pdata->rtc)) {
+		ret = PTR_ERR(pdata->rtc);
+		goto exit_put_clk;
+	}
+
+	tv.tv_nsec = 0;
+	tv.tv_sec = __raw_readl(ioaddr + SRTC_LPSCMR);
+
+	/* By default, devices should wakeup if they can */
+	/* So srtc is set as "should wakeup" as it can */
+	device_init_wakeup(&pdev->dev, 1);
+
+	return ret;
+
+exit_put_clk:
+	clk_disable_unprepare(pdata->clk);
+	return ret;
+}
+
+static int __exit mxc_rtc_remove(struct platform_device *pdev)
+{
+	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
+
+	clk_disable_unprepare(pdata->clk);
+	return 0;
+}
+
+/*!
+ * This function is called to save the system time delta relative to
+ * the MXC RTC when enterring a low power state. This time delta is
+ * then used on resume to adjust the system time to account for time
+ * loss while suspended.
+ *
+ * @param   pdev  not used
+ * @param   state Power state to enter.
+ *
+ * @return  The function always returns 0.
+ */
+static int mxc_rtc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
+
+	if (device_may_wakeup(&pdev->dev))
+		enable_irq_wake(pdata->irq);
+
+	return 0;
+}
+
+/*!
+ * This function is called to correct the system time based on the
+ * current MXC RTC time relative to the time delta saved during
+ * suspend.
+ *
+ * @param   pdev  not used
+ *
+ * @return  The function always returns 0.
+ */
+static int mxc_rtc_resume(struct platform_device *pdev)
+{
+	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
+
+	if (device_may_wakeup(&pdev->dev))
+		disable_irq_wake(pdata->irq);
+
+	return 0;
+}
+
+static const struct of_device_id mxc_ids[] = {
+	{.compatible = "fsl,imx53-rtc",},
+	{}
+};
+
+/*!
+ * Contains pointers to the power management callback functions.
+ */
+static struct platform_driver mxc_rtc_driver = {
+	.driver = {
+		   .name = "mxc_rtc_v8",
+		   .of_match_table = mxc_ids,
+		   },
+	.probe = mxc_rtc_probe,
+	.remove = mxc_rtc_remove,
+	.suspend = mxc_rtc_suspend,
+	.resume = mxc_rtc_resume,
+};
+
+module_platform_driver(mxc_rtc_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("Realtime Clock Driver (RTC)");
+MODULE_LICENSE("GPL");
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH] rtc: add mxc driver for i.MX53
@ 2017-11-28  7:39 ` linux-kernel-dev
  0 siblings, 0 replies; 43+ messages in thread
From: linux-kernel-dev @ 2017-11-28  7:39 UTC (permalink / raw)
  To: Alessandro Zummo, Alexandre Belloni
  Cc: Patrick Bruenn, Rob Herring, Mark Rutland,
	open list:REAL TIME CLOCK (RTC) SUBSYSTEM,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	open list, Fabio Estevam, Juergen Borleis, Noel Vellemans,
	Shawn Guo, Sascha Hauer, Russell King,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE

From: Patrick Bruenn <p.bruenn@beckhoff.com>

Neither rtc-imxdi nor rtc-mxc are compatible with i.MX53.
Add a modernized version of mxc_v2 from here:
http://git.freescale.com/git/cgit.cgi/imx/linux-2.6-imx.git/tree/drivers/rtc/rtc-mxc_v2.c?h=imx_2.6.35_11.09.01

Changes to that version:
- updated to v4.15-rc1
- removed ioctl()
- removed proc()
- removed manual(redundant) enable_irq flag

Signed-off-by: Patrick Bruenn <p.bruenn@beckhoff.com>

---

Open issues:
- driver naming, should it be merged with rtc-mxc.c ?
- document DT binding "fsl,imx53-rtc" accordingly
- Should unused defines be removed or kept for someone else to be
  useful?
- Is the use of __raw_readl/writel() correct? Should it be replaced with
  readl/writel()?
- suspend/resume() seems different to existing rtc-mxc.c, should I apply
  the pattern from rtc-mxc.c?
- On Shawns tree imx53.dtsi has been reverted already[1][2]. Should I split
  the imx53.dtsi change into a separate patch based on his tree? Or can
  we still stop the full revert and just remove the imx25-rtc compatible?
  I am not in a hurry, so we could just wait until the revert landed in
  Linus tree. Whatever you think is best.

[1] https://www.spinics.net/lists/arm-kernel/msg617113.html
[2] commit ee76f7729babd2700afd6f3874449d8084dd85ea

To: Alessandro Zummo <a.zummo@towertech.it>
To: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com> (maintainer:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS)
Cc: linux-rtc@vger.kernel.org (open list:REAL TIME CLOCK (RTC) SUBSYSTEM)
Cc: devicetree@vger.kernel.org (open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS)
Cc: linux-kernel@vger.kernel.org (open list)
Cc: Fabio Estevam <fabio.estevam@nxp.com>
Cc: Juergen Borleis <jbe@pengutronix.de>
Cc: Noel Vellemans <Noel.Vellemans@visionbms.com>
Cc: Shawn Guo <shawnguo@kernel.org>
Cc: Sascha Hauer <kernel@pengutronix.de> (maintainer:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE)
Cc: Russell King <linux@armlinux.org.uk> (maintainer:ARM PORT)
Cc: linux-arm-kernel@lists.infradead.org (moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE)
---
 arch/arm/boot/dts/imx53.dtsi |   2 +-
 drivers/rtc/Makefile         |   1 +
 drivers/rtc/rtc-mxc_v2.c     | 531 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 533 insertions(+), 1 deletion(-)
 create mode 100644 drivers/rtc/rtc-mxc_v2.c

diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi
index 589a67c5f796..3d1a55e11ea8 100644
--- a/arch/arm/boot/dts/imx53.dtsi
+++ b/arch/arm/boot/dts/imx53.dtsi
@@ -434,7 +434,7 @@
 			};
 
 			srtc: srtc@53fa4000 {
-				compatible = "fsl,imx53-rtc", "fsl,imx25-rtc";
+				compatible = "fsl,imx53-rtc";
 				reg = <0x53fa4000 0x4000>;
 				interrupts = <24>;
 				interrupt-parent = <&tzic>;
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index f2f50c11dc38..fb3dc458c185 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -106,6 +106,7 @@ obj-$(CONFIG_RTC_DRV_MT6397)	+= rtc-mt6397.o
 obj-$(CONFIG_RTC_DRV_MT7622)	+= rtc-mt7622.o
 obj-$(CONFIG_RTC_DRV_MV)	+= rtc-mv.o
 obj-$(CONFIG_RTC_DRV_MXC)	+= rtc-mxc.o
+obj-$(CONFIG_RTC_DRV_MXC)	+= rtc-mxc_v2.o
 obj-$(CONFIG_RTC_DRV_NUC900)	+= rtc-nuc900.o
 obj-$(CONFIG_RTC_DRV_OMAP)	+= rtc-omap.o
 obj-$(CONFIG_RTC_DRV_OPAL)	+= rtc-opal.o
diff --git a/drivers/rtc/rtc-mxc_v2.c b/drivers/rtc/rtc-mxc_v2.c
new file mode 100644
index 000000000000..5049b521b38e
--- /dev/null
+++ b/drivers/rtc/rtc-mxc_v2.c
@@ -0,0 +1,531 @@
+/*
+ * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+/*
+ * Implementation based on rtc-ds1553.c
+ */
+
+/*!
+ * @defgroup RTC Real Time Clock (RTC) Driver for i.MX53
+ */
+/*!
+ * @file rtc-mxc_v2.c
+ * @brief Real Time Clock interface
+ *
+ * This file contains Real Time Clock interface for Linux.
+ *
+ * @ingroup RTC
+ */
+
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/rtc.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+//#include <linux/mxc_srtc.h>
+#define RTC_READ_TIME_47BIT	_IOR('p', 0x20, unsigned long long)
+/* blocks until LPSCMR is set, returns difference */
+#define RTC_WAIT_TIME_SET	_IOR('p', 0x21, int64_t)
+
+#define SRTC_LPSCLR_LLPSC_LSH	17	/* start bit for LSB time value */
+
+#define SRTC_LPPDR_INIT       0x41736166	/* init for glitch detect */
+
+#define SRTC_LPCR_SWR_LP      (1 << 0)	/* lp software reset */
+#define SRTC_LPCR_EN_LP       (1 << 3)	/* lp enable */
+#define SRTC_LPCR_WAE         (1 << 4)	/* lp wakeup alarm enable */
+#define SRTC_LPCR_SAE         (1 << 5)	/* lp security alarm enable */
+#define SRTC_LPCR_SI          (1 << 6)	/* lp security interrupt enable */
+#define SRTC_LPCR_ALP         (1 << 7)	/* lp alarm flag */
+#define SRTC_LPCR_LTC         (1 << 8)	/* lp lock time counter */
+#define SRTC_LPCR_LMC         (1 << 9)	/* lp lock monotonic counter */
+#define SRTC_LPCR_SV          (1 << 10)	/* lp security violation */
+#define SRTC_LPCR_NSA         (1 << 11)	/* lp non secure access */
+#define SRTC_LPCR_NVEIE       (1 << 12)	/* lp non valid state exit int en */
+#define SRTC_LPCR_IEIE        (1 << 13)	/* lp init state exit int enable */
+#define SRTC_LPCR_NVE         (1 << 14)	/* lp non valid state exit bit */
+#define SRTC_LPCR_IE          (1 << 15)	/* lp init state exit bit */
+
+#define SRTC_LPCR_ALL_INT_EN (SRTC_LPCR_WAE | SRTC_LPCR_SAE | \
+			      SRTC_LPCR_SI | SRTC_LPCR_ALP | \
+			      SRTC_LPCR_NVEIE | SRTC_LPCR_IEIE)
+
+#define SRTC_LPSR_TRI         (1 << 0)	/* lp time read invalidate */
+#define SRTC_LPSR_PGD         (1 << 1)	/* lp power supply glitc detected */
+#define SRTC_LPSR_CTD         (1 << 2)	/* lp clock tampering detected */
+#define SRTC_LPSR_ALP         (1 << 3)	/* lp alarm flag */
+#define SRTC_LPSR_MR          (1 << 4)	/* lp monotonic counter rollover */
+#define SRTC_LPSR_TR          (1 << 5)	/* lp time rollover */
+#define SRTC_LPSR_EAD         (1 << 6)	/* lp external alarm detected */
+#define SRTC_LPSR_IT0         (1 << 7)	/* lp IIM throttle */
+#define SRTC_LPSR_IT1         (1 << 8)
+#define SRTC_LPSR_IT2         (1 << 9)
+#define SRTC_LPSR_SM0         (1 << 10)	/* lp security mode */
+#define SRTC_LPSR_SM1         (1 << 11)
+#define SRTC_LPSR_STATE_LP0   (1 << 12)	/* lp state */
+#define SRTC_LPSR_STATE_LP1   (1 << 13)
+#define SRTC_LPSR_NVES        (1 << 14)	/* lp non-valid state exit status */
+#define SRTC_LPSR_IES         (1 << 15)	/* lp init state exit status */
+
+#define MAX_PIE_NUM     15
+#define MAX_PIE_FREQ    32768
+#define MIN_PIE_FREQ	1
+
+#define SRTC_PI0         (1 << 0)
+#define SRTC_PI1         (1 << 1)
+#define SRTC_PI2         (1 << 2)
+#define SRTC_PI3         (1 << 3)
+#define SRTC_PI4         (1 << 4)
+#define SRTC_PI5         (1 << 5)
+#define SRTC_PI6         (1 << 6)
+#define SRTC_PI7         (1 << 7)
+#define SRTC_PI8         (1 << 8)
+#define SRTC_PI9         (1 << 9)
+#define SRTC_PI10        (1 << 10)
+#define SRTC_PI11        (1 << 11)
+#define SRTC_PI12        (1 << 12)
+#define SRTC_PI13        (1 << 13)
+#define SRTC_PI14        (1 << 14)
+#define SRTC_PI15        (1 << 15)
+
+#define PIT_ALL_ON      (SRTC_PI1 | SRTC_PI2 | SRTC_PI3 | \
+			SRTC_PI4 | SRTC_PI5 | SRTC_PI6 | SRTC_PI7 | \
+			SRTC_PI8 | SRTC_PI9 | SRTC_PI10 | SRTC_PI11 | \
+			SRTC_PI12 | SRTC_PI13 | SRTC_PI14 | SRTC_PI15)
+
+#define SRTC_SWR_HP      (1 << 0)	/* hp software reset */
+#define SRTC_EN_HP       (1 << 3)	/* hp enable */
+#define SRTC_TS          (1 << 4)	/* time synchronize hp with lp */
+
+#define SRTC_IE_AHP      (1 << 16)	/* Alarm HP Interrupt Enable bit */
+#define SRTC_IE_WDHP     (1 << 18)	/* Write Done HP Interrupt Enable bit */
+#define SRTC_IE_WDLP     (1 << 19)	/* Write Done LP Interrupt Enable bit */
+
+#define SRTC_ISR_AHP     (1 << 16)	/* interrupt status: alarm hp */
+#define SRTC_ISR_WDHP    (1 << 18)	/* interrupt status: write done hp */
+#define SRTC_ISR_WDLP    (1 << 19)	/* interrupt status: write done lp */
+#define SRTC_ISR_WPHP    (1 << 20)	/* interrupt status: write pending hp */
+#define SRTC_ISR_WPLP    (1 << 21)	/* interrupt status: write pending lp */
+
+#define SRTC_LPSCMR	0x00	/* LP Secure Counter MSB Reg */
+#define SRTC_LPSCLR	0x04	/* LP Secure Counter LSB Reg */
+#define SRTC_LPSAR	0x08	/* LP Secure Alarm Reg */
+#define SRTC_LPSMCR	0x0C	/* LP Secure Monotonic Counter Reg */
+#define SRTC_LPCR	0x10	/* LP Control Reg */
+#define SRTC_LPSR	0x14	/* LP Status Reg */
+#define SRTC_LPPDR	0x18	/* LP Power Supply Glitch Detector Reg */
+#define SRTC_LPGR	0x1C	/* LP General Purpose Reg */
+#define SRTC_HPCMR	0x20	/* HP Counter MSB Reg */
+#define SRTC_HPCLR	0x24	/* HP Counter LSB Reg */
+#define SRTC_HPAMR	0x28	/* HP Alarm MSB Reg */
+#define SRTC_HPALR	0x2C	/* HP Alarm LSB Reg */
+#define SRTC_HPCR	0x30	/* HP Control Reg */
+#define SRTC_HPISR	0x34	/* HP Interrupt Status Reg */
+#define SRTC_HPIENR	0x38	/* HP Interrupt Enable Reg */
+
+#define SRTC_SECMODE_MASK	0x3	/* the mask of SRTC security mode */
+#define SRTC_SECMODE_LOW	0x0	/* Low Security */
+#define SRTC_SECMODE_MED	0x1	/* Medium Security */
+#define SRTC_SECMODE_HIGH	0x2	/* High Security */
+#define SRTC_SECMODE_RESERVED	0x3	/* Reserved */
+
+struct rtc_drv_data {
+	struct rtc_device *rtc;
+	void __iomem *ioaddr;
+	int irq;
+	struct clk *clk;
+};
+
+static DEFINE_SPINLOCK(rtc_lock);
+
+/*!
+ * This function does write synchronization for writes to the lp srtc block.
+ * To take care of the asynchronous CKIL clock, all writes from the IP domain
+ * will be synchronized to the CKIL domain.
+ */
+static inline void rtc_write_sync_lp(void __iomem *ioaddr)
+{
+	unsigned int i, count;
+	/* Wait for 3 CKIL cycles */
+	for (i = 0; i < 3; i++) {
+		count = readl(ioaddr + SRTC_LPSCLR);
+		while ((readl(ioaddr + SRTC_LPSCLR)) == count)
+			;
+	}
+}
+
+/*!
+ * This function updates the RTC alarm registers and then clears all the
+ * interrupt status bits.
+ *
+ * @param  alrm         the new alarm value to be updated in the RTC
+ *
+ * @return  0 if successful; non-zero otherwise.
+ */
+static int rtc_update_alarm(struct device *dev, struct rtc_time *alrm)
+{
+	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
+	void __iomem *ioaddr = pdata->ioaddr;
+	struct rtc_time alarm_tm, now_tm;
+	unsigned long now, time;
+	int ret;
+
+	now = __raw_readl(ioaddr + SRTC_LPSCMR);
+	rtc_time_to_tm(now, &now_tm);
+
+	alarm_tm.tm_year = now_tm.tm_year;
+	alarm_tm.tm_mon = now_tm.tm_mon;
+	alarm_tm.tm_mday = now_tm.tm_mday;
+
+	alarm_tm.tm_hour = alrm->tm_hour;
+	alarm_tm.tm_min = alrm->tm_min;
+	alarm_tm.tm_sec = alrm->tm_sec;
+
+	rtc_tm_to_time(&now_tm, &now);
+	rtc_tm_to_time(&alarm_tm, &time);
+
+	if (time < now) {
+		time += 60 * 60 * 24;
+		rtc_time_to_tm(time, &alarm_tm);
+	}
+	ret = rtc_tm_to_time(&alarm_tm, &time);
+
+	__raw_writel(time, ioaddr + SRTC_LPSAR);
+
+	/* clear alarm interrupt status bit */
+	__raw_writel(SRTC_LPSR_ALP, ioaddr + SRTC_LPSR);
+
+	return ret;
+}
+
+/*!
+ * This function is the RTC interrupt service routine.
+ *
+ * @param  irq          RTC IRQ number
+ * @param  dev_id       device ID which is not used
+ *
+ * @return IRQ_HANDLED as defined in the include/linux/interrupt.h file.
+ */
+static irqreturn_t mxc_rtc_interrupt(int irq, void *dev_id)
+{
+	struct platform_device *pdev = dev_id;
+	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
+	void __iomem *ioaddr = pdata->ioaddr;
+	u32 lp_status, lp_cr;
+	u32 events = 0;
+
+	lp_status = __raw_readl(ioaddr + SRTC_LPSR);
+	lp_cr = __raw_readl(ioaddr + SRTC_LPCR);
+
+	/* update irq data & counter */
+	if (lp_status & SRTC_LPSR_ALP) {
+		if (lp_cr & SRTC_LPCR_ALP)
+			events |= (RTC_AF | RTC_IRQF);
+
+		/* disable further lp alarm interrupts */
+		lp_cr &= ~(SRTC_LPCR_ALP | SRTC_LPCR_WAE);
+	}
+
+	/* Update interrupt enables */
+	__raw_writel(lp_cr, ioaddr + SRTC_LPCR);
+
+	/* clear interrupt status */
+	__raw_writel(lp_status, ioaddr + SRTC_LPSR);
+
+	rtc_write_sync_lp(ioaddr);
+	rtc_update_irq(pdata->rtc, 1, events);
+	return IRQ_HANDLED;
+}
+
+/*!
+ * This function reads the current RTC time into tm in Gregorian date.
+ *
+ * @param  tm           contains the RTC time value upon return
+ *
+ * @return  0 if successful; non-zero otherwise.
+ */
+static int mxc_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
+	time_t now = readl(pdata->ioaddr + SRTC_LPSCMR);
+
+	rtc_time_to_tm(now, tm);
+	return rtc_valid_tm(tm);
+}
+
+/*!
+ * This function sets the internal RTC time based on tm in Gregorian date.
+ *
+ * @param  tm           the time value to be set in the RTC
+ *
+ * @return  0 if successful; non-zero otherwise.
+ */
+static int mxc_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
+	time64_t time = rtc_tm_to_time64(tm);
+
+	if (time > UINT_MAX) {
+		dev_warn(dev, "time_t has overflow\n");
+	}
+
+	writel(time, pdata->ioaddr + SRTC_LPSCMR);
+	rtc_write_sync_lp(pdata->ioaddr);
+	return 0;
+}
+
+/*!
+ * This function reads the current alarm value into the passed in \b alrm
+ * argument. It updates the \b alrm's pending field value based on the whether
+ * an alarm interrupt occurs or not.
+ *
+ * @param  alrm         contains the RTC alarm value upon return
+ *
+ * @return  0 if successful; non-zero otherwise.
+ */
+static int mxc_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
+	void __iomem *ioaddr = pdata->ioaddr;
+
+	rtc_time_to_tm(__raw_readl(ioaddr + SRTC_LPSAR), &alrm->time);
+	alrm->pending =
+	    ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_ALP) != 0) ? 1 : 0;
+
+	return 0;
+}
+
+static int mxc_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
+{
+	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
+	unsigned long lock_flags = 0;
+	u32 lp_cr;
+
+	spin_lock_irqsave(&rtc_lock, lock_flags);
+	lp_cr = __raw_readl(pdata->ioaddr + SRTC_LPCR);
+
+	if (enable)
+		lp_cr |= (SRTC_LPCR_ALP | SRTC_LPCR_WAE);
+	else
+		lp_cr &= ~(SRTC_LPCR_ALP | SRTC_LPCR_WAE);
+
+	__raw_writel(lp_cr, pdata->ioaddr + SRTC_LPCR);
+	spin_unlock_irqrestore(&rtc_lock, lock_flags);
+	return 0;
+}
+
+/*!
+ * This function sets the RTC alarm based on passed in alrm.
+ *
+ * @param  alrm         the alarm value to be set in the RTC
+ *
+ * @return  0 if successful; non-zero otherwise.
+ */
+static int mxc_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
+	void __iomem *ioaddr = pdata->ioaddr;
+	int ret;
+
+	ret = rtc_update_alarm(dev, &alrm->time);
+	if (!ret)
+		mxc_rtc_alarm_irq_enable(dev, alrm->enabled);
+
+	rtc_write_sync_lp(ioaddr);
+	return ret;
+}
+
+/*!
+ * The RTC driver structure
+ */
+static const struct rtc_class_ops mxc_rtc_ops = {
+	.read_time = mxc_rtc_read_time,
+	.set_time = mxc_rtc_set_time,
+	.read_alarm = mxc_rtc_read_alarm,
+	.set_alarm = mxc_rtc_set_alarm,
+	.alarm_irq_enable = mxc_rtc_alarm_irq_enable,
+};
+
+/*! MXC RTC Power management control */
+static int mxc_rtc_probe(struct platform_device *pdev)
+{
+	struct timespec tv;
+	struct resource *res;
+	struct rtc_drv_data *pdata = NULL;
+	void __iomem *ioaddr;
+	int ret = 0;
+
+	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	pdata->ioaddr = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(pdata->ioaddr))
+		return PTR_ERR(pdata->ioaddr);
+
+	ioaddr = pdata->ioaddr;
+
+	pdata->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(pdata->clk)) {
+		dev_err(&pdev->dev, "unable to get rtc clock!\n");
+		return PTR_ERR(pdata->clk);
+	}
+	ret = clk_prepare_enable(pdata->clk);
+	if (ret)
+		return ret;
+
+	/* Configure and enable the RTC */
+	pdata->irq = platform_get_irq(pdev, 0);
+	if (pdata->irq >= 0
+	    && devm_request_irq(&pdev->dev, pdata->irq, mxc_rtc_interrupt,
+				IRQF_SHARED, pdev->name, pdev) < 0) {
+		dev_warn(&pdev->dev, "interrupt not available.\n");
+		pdata->irq = -1;
+	}
+
+	if (pdata->irq >= 0)
+		device_init_wakeup(&pdev->dev, 1);
+
+	/* initialize glitch detect */
+	__raw_writel(SRTC_LPPDR_INIT, ioaddr + SRTC_LPPDR);
+	udelay(100);
+
+	/* clear lp interrupt status */
+	__raw_writel(0xFFFFFFFF, ioaddr + SRTC_LPSR);
+	udelay(100);
+
+	/* move out of init state */
+	__raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NSA), ioaddr + SRTC_LPCR);
+
+	udelay(100);
+
+	while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_IES) == 0)
+		;
+
+	/* move out of non-valid state */
+	__raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NVE | SRTC_LPCR_NSA |
+		      SRTC_LPCR_EN_LP), ioaddr + SRTC_LPCR);
+
+	udelay(100);
+
+	while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_NVES) == 0)
+		;
+
+	__raw_writel(0xFFFFFFFF, ioaddr + SRTC_LPSR);
+	udelay(100);
+
+	platform_set_drvdata(pdev, pdata);
+	pdata->rtc =
+	    devm_rtc_device_register(&pdev->dev, pdev->name, &mxc_rtc_ops,
+				     THIS_MODULE);
+	if (IS_ERR(pdata->rtc)) {
+		ret = PTR_ERR(pdata->rtc);
+		goto exit_put_clk;
+	}
+
+	tv.tv_nsec = 0;
+	tv.tv_sec = __raw_readl(ioaddr + SRTC_LPSCMR);
+
+	/* By default, devices should wakeup if they can */
+	/* So srtc is set as "should wakeup" as it can */
+	device_init_wakeup(&pdev->dev, 1);
+
+	return ret;
+
+exit_put_clk:
+	clk_disable_unprepare(pdata->clk);
+	return ret;
+}
+
+static int __exit mxc_rtc_remove(struct platform_device *pdev)
+{
+	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
+
+	clk_disable_unprepare(pdata->clk);
+	return 0;
+}
+
+/*!
+ * This function is called to save the system time delta relative to
+ * the MXC RTC when enterring a low power state. This time delta is
+ * then used on resume to adjust the system time to account for time
+ * loss while suspended.
+ *
+ * @param   pdev  not used
+ * @param   state Power state to enter.
+ *
+ * @return  The function always returns 0.
+ */
+static int mxc_rtc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
+
+	if (device_may_wakeup(&pdev->dev))
+		enable_irq_wake(pdata->irq);
+
+	return 0;
+}
+
+/*!
+ * This function is called to correct the system time based on the
+ * current MXC RTC time relative to the time delta saved during
+ * suspend.
+ *
+ * @param   pdev  not used
+ *
+ * @return  The function always returns 0.
+ */
+static int mxc_rtc_resume(struct platform_device *pdev)
+{
+	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
+
+	if (device_may_wakeup(&pdev->dev))
+		disable_irq_wake(pdata->irq);
+
+	return 0;
+}
+
+static const struct of_device_id mxc_ids[] = {
+	{.compatible = "fsl,imx53-rtc",},
+	{}
+};
+
+/*!
+ * Contains pointers to the power management callback functions.
+ */
+static struct platform_driver mxc_rtc_driver = {
+	.driver = {
+		   .name = "mxc_rtc_v8",
+		   .of_match_table = mxc_ids,
+		   },
+	.probe = mxc_rtc_probe,
+	.remove = mxc_rtc_remove,
+	.suspend = mxc_rtc_suspend,
+	.resume = mxc_rtc_resume,
+};
+
+module_platform_driver(mxc_rtc_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("Realtime Clock Driver (RTC)");
+MODULE_LICENSE("GPL");
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH] rtc: add mxc driver for i.MX53
@ 2017-11-28  7:39 ` linux-kernel-dev
  0 siblings, 0 replies; 43+ messages in thread
From: linux-kernel-dev @ 2017-11-28  7:39 UTC (permalink / raw)
  To: Alessandro Zummo, Alexandre Belloni
  Cc: Mark Rutland, open list:REAL TIME CLOCK (RTC) SUBSYSTEM,
	Patrick Bruenn,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	open list, Russell King, Noel Vellemans, Rob Herring,
	Sascha Hauer, Fabio Estevam, Shawn Guo,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE

From: Patrick Bruenn <p.bruenn@beckhoff.com>

Neither rtc-imxdi nor rtc-mxc are compatible with i.MX53.
Add a modernized version of mxc_v2 from here:
http://git.freescale.com/git/cgit.cgi/imx/linux-2.6-imx.git/tree/drivers/rtc/rtc-mxc_v2.c?h=imx_2.6.35_11.09.01

Changes to that version:
- updated to v4.15-rc1
- removed ioctl()
- removed proc()
- removed manual(redundant) enable_irq flag

Signed-off-by: Patrick Bruenn <p.bruenn@beckhoff.com>

---

Open issues:
- driver naming, should it be merged with rtc-mxc.c ?
- document DT binding "fsl,imx53-rtc" accordingly
- Should unused defines be removed or kept for someone else to be
  useful?
- Is the use of __raw_readl/writel() correct? Should it be replaced with
  readl/writel()?
- suspend/resume() seems different to existing rtc-mxc.c, should I apply
  the pattern from rtc-mxc.c?
- On Shawns tree imx53.dtsi has been reverted already[1][2]. Should I split
  the imx53.dtsi change into a separate patch based on his tree? Or can
  we still stop the full revert and just remove the imx25-rtc compatible?
  I am not in a hurry, so we could just wait until the revert landed in
  Linus tree. Whatever you think is best.

[1] https://www.spinics.net/lists/arm-kernel/msg617113.html
[2] commit ee76f7729babd2700afd6f3874449d8084dd85ea

To: Alessandro Zummo <a.zummo@towertech.it>
To: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com> (maintainer:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS)
Cc: linux-rtc@vger.kernel.org (open list:REAL TIME CLOCK (RTC) SUBSYSTEM)
Cc: devicetree@vger.kernel.org (open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS)
Cc: linux-kernel@vger.kernel.org (open list)
Cc: Fabio Estevam <fabio.estevam@nxp.com>
Cc: Juergen Borleis <jbe@pengutronix.de>
Cc: Noel Vellemans <Noel.Vellemans@visionbms.com>
Cc: Shawn Guo <shawnguo@kernel.org>
Cc: Sascha Hauer <kernel@pengutronix.de> (maintainer:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE)
Cc: Russell King <linux@armlinux.org.uk> (maintainer:ARM PORT)
Cc: linux-arm-kernel@lists.infradead.org (moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE)
---
 arch/arm/boot/dts/imx53.dtsi |   2 +-
 drivers/rtc/Makefile         |   1 +
 drivers/rtc/rtc-mxc_v2.c     | 531 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 533 insertions(+), 1 deletion(-)
 create mode 100644 drivers/rtc/rtc-mxc_v2.c

diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi
index 589a67c5f796..3d1a55e11ea8 100644
--- a/arch/arm/boot/dts/imx53.dtsi
+++ b/arch/arm/boot/dts/imx53.dtsi
@@ -434,7 +434,7 @@
 			};
 
 			srtc: srtc@53fa4000 {
-				compatible = "fsl,imx53-rtc", "fsl,imx25-rtc";
+				compatible = "fsl,imx53-rtc";
 				reg = <0x53fa4000 0x4000>;
 				interrupts = <24>;
 				interrupt-parent = <&tzic>;
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index f2f50c11dc38..fb3dc458c185 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -106,6 +106,7 @@ obj-$(CONFIG_RTC_DRV_MT6397)	+= rtc-mt6397.o
 obj-$(CONFIG_RTC_DRV_MT7622)	+= rtc-mt7622.o
 obj-$(CONFIG_RTC_DRV_MV)	+= rtc-mv.o
 obj-$(CONFIG_RTC_DRV_MXC)	+= rtc-mxc.o
+obj-$(CONFIG_RTC_DRV_MXC)	+= rtc-mxc_v2.o
 obj-$(CONFIG_RTC_DRV_NUC900)	+= rtc-nuc900.o
 obj-$(CONFIG_RTC_DRV_OMAP)	+= rtc-omap.o
 obj-$(CONFIG_RTC_DRV_OPAL)	+= rtc-opal.o
diff --git a/drivers/rtc/rtc-mxc_v2.c b/drivers/rtc/rtc-mxc_v2.c
new file mode 100644
index 000000000000..5049b521b38e
--- /dev/null
+++ b/drivers/rtc/rtc-mxc_v2.c
@@ -0,0 +1,531 @@
+/*
+ * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+/*
+ * Implementation based on rtc-ds1553.c
+ */
+
+/*!
+ * @defgroup RTC Real Time Clock (RTC) Driver for i.MX53
+ */
+/*!
+ * @file rtc-mxc_v2.c
+ * @brief Real Time Clock interface
+ *
+ * This file contains Real Time Clock interface for Linux.
+ *
+ * @ingroup RTC
+ */
+
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/rtc.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+//#include <linux/mxc_srtc.h>
+#define RTC_READ_TIME_47BIT	_IOR('p', 0x20, unsigned long long)
+/* blocks until LPSCMR is set, returns difference */
+#define RTC_WAIT_TIME_SET	_IOR('p', 0x21, int64_t)
+
+#define SRTC_LPSCLR_LLPSC_LSH	17	/* start bit for LSB time value */
+
+#define SRTC_LPPDR_INIT       0x41736166	/* init for glitch detect */
+
+#define SRTC_LPCR_SWR_LP      (1 << 0)	/* lp software reset */
+#define SRTC_LPCR_EN_LP       (1 << 3)	/* lp enable */
+#define SRTC_LPCR_WAE         (1 << 4)	/* lp wakeup alarm enable */
+#define SRTC_LPCR_SAE         (1 << 5)	/* lp security alarm enable */
+#define SRTC_LPCR_SI          (1 << 6)	/* lp security interrupt enable */
+#define SRTC_LPCR_ALP         (1 << 7)	/* lp alarm flag */
+#define SRTC_LPCR_LTC         (1 << 8)	/* lp lock time counter */
+#define SRTC_LPCR_LMC         (1 << 9)	/* lp lock monotonic counter */
+#define SRTC_LPCR_SV          (1 << 10)	/* lp security violation */
+#define SRTC_LPCR_NSA         (1 << 11)	/* lp non secure access */
+#define SRTC_LPCR_NVEIE       (1 << 12)	/* lp non valid state exit int en */
+#define SRTC_LPCR_IEIE        (1 << 13)	/* lp init state exit int enable */
+#define SRTC_LPCR_NVE         (1 << 14)	/* lp non valid state exit bit */
+#define SRTC_LPCR_IE          (1 << 15)	/* lp init state exit bit */
+
+#define SRTC_LPCR_ALL_INT_EN (SRTC_LPCR_WAE | SRTC_LPCR_SAE | \
+			      SRTC_LPCR_SI | SRTC_LPCR_ALP | \
+			      SRTC_LPCR_NVEIE | SRTC_LPCR_IEIE)
+
+#define SRTC_LPSR_TRI         (1 << 0)	/* lp time read invalidate */
+#define SRTC_LPSR_PGD         (1 << 1)	/* lp power supply glitc detected */
+#define SRTC_LPSR_CTD         (1 << 2)	/* lp clock tampering detected */
+#define SRTC_LPSR_ALP         (1 << 3)	/* lp alarm flag */
+#define SRTC_LPSR_MR          (1 << 4)	/* lp monotonic counter rollover */
+#define SRTC_LPSR_TR          (1 << 5)	/* lp time rollover */
+#define SRTC_LPSR_EAD         (1 << 6)	/* lp external alarm detected */
+#define SRTC_LPSR_IT0         (1 << 7)	/* lp IIM throttle */
+#define SRTC_LPSR_IT1         (1 << 8)
+#define SRTC_LPSR_IT2         (1 << 9)
+#define SRTC_LPSR_SM0         (1 << 10)	/* lp security mode */
+#define SRTC_LPSR_SM1         (1 << 11)
+#define SRTC_LPSR_STATE_LP0   (1 << 12)	/* lp state */
+#define SRTC_LPSR_STATE_LP1   (1 << 13)
+#define SRTC_LPSR_NVES        (1 << 14)	/* lp non-valid state exit status */
+#define SRTC_LPSR_IES         (1 << 15)	/* lp init state exit status */
+
+#define MAX_PIE_NUM     15
+#define MAX_PIE_FREQ    32768
+#define MIN_PIE_FREQ	1
+
+#define SRTC_PI0         (1 << 0)
+#define SRTC_PI1         (1 << 1)
+#define SRTC_PI2         (1 << 2)
+#define SRTC_PI3         (1 << 3)
+#define SRTC_PI4         (1 << 4)
+#define SRTC_PI5         (1 << 5)
+#define SRTC_PI6         (1 << 6)
+#define SRTC_PI7         (1 << 7)
+#define SRTC_PI8         (1 << 8)
+#define SRTC_PI9         (1 << 9)
+#define SRTC_PI10        (1 << 10)
+#define SRTC_PI11        (1 << 11)
+#define SRTC_PI12        (1 << 12)
+#define SRTC_PI13        (1 << 13)
+#define SRTC_PI14        (1 << 14)
+#define SRTC_PI15        (1 << 15)
+
+#define PIT_ALL_ON      (SRTC_PI1 | SRTC_PI2 | SRTC_PI3 | \
+			SRTC_PI4 | SRTC_PI5 | SRTC_PI6 | SRTC_PI7 | \
+			SRTC_PI8 | SRTC_PI9 | SRTC_PI10 | SRTC_PI11 | \
+			SRTC_PI12 | SRTC_PI13 | SRTC_PI14 | SRTC_PI15)
+
+#define SRTC_SWR_HP      (1 << 0)	/* hp software reset */
+#define SRTC_EN_HP       (1 << 3)	/* hp enable */
+#define SRTC_TS          (1 << 4)	/* time synchronize hp with lp */
+
+#define SRTC_IE_AHP      (1 << 16)	/* Alarm HP Interrupt Enable bit */
+#define SRTC_IE_WDHP     (1 << 18)	/* Write Done HP Interrupt Enable bit */
+#define SRTC_IE_WDLP     (1 << 19)	/* Write Done LP Interrupt Enable bit */
+
+#define SRTC_ISR_AHP     (1 << 16)	/* interrupt status: alarm hp */
+#define SRTC_ISR_WDHP    (1 << 18)	/* interrupt status: write done hp */
+#define SRTC_ISR_WDLP    (1 << 19)	/* interrupt status: write done lp */
+#define SRTC_ISR_WPHP    (1 << 20)	/* interrupt status: write pending hp */
+#define SRTC_ISR_WPLP    (1 << 21)	/* interrupt status: write pending lp */
+
+#define SRTC_LPSCMR	0x00	/* LP Secure Counter MSB Reg */
+#define SRTC_LPSCLR	0x04	/* LP Secure Counter LSB Reg */
+#define SRTC_LPSAR	0x08	/* LP Secure Alarm Reg */
+#define SRTC_LPSMCR	0x0C	/* LP Secure Monotonic Counter Reg */
+#define SRTC_LPCR	0x10	/* LP Control Reg */
+#define SRTC_LPSR	0x14	/* LP Status Reg */
+#define SRTC_LPPDR	0x18	/* LP Power Supply Glitch Detector Reg */
+#define SRTC_LPGR	0x1C	/* LP General Purpose Reg */
+#define SRTC_HPCMR	0x20	/* HP Counter MSB Reg */
+#define SRTC_HPCLR	0x24	/* HP Counter LSB Reg */
+#define SRTC_HPAMR	0x28	/* HP Alarm MSB Reg */
+#define SRTC_HPALR	0x2C	/* HP Alarm LSB Reg */
+#define SRTC_HPCR	0x30	/* HP Control Reg */
+#define SRTC_HPISR	0x34	/* HP Interrupt Status Reg */
+#define SRTC_HPIENR	0x38	/* HP Interrupt Enable Reg */
+
+#define SRTC_SECMODE_MASK	0x3	/* the mask of SRTC security mode */
+#define SRTC_SECMODE_LOW	0x0	/* Low Security */
+#define SRTC_SECMODE_MED	0x1	/* Medium Security */
+#define SRTC_SECMODE_HIGH	0x2	/* High Security */
+#define SRTC_SECMODE_RESERVED	0x3	/* Reserved */
+
+struct rtc_drv_data {
+	struct rtc_device *rtc;
+	void __iomem *ioaddr;
+	int irq;
+	struct clk *clk;
+};
+
+static DEFINE_SPINLOCK(rtc_lock);
+
+/*!
+ * This function does write synchronization for writes to the lp srtc block.
+ * To take care of the asynchronous CKIL clock, all writes from the IP domain
+ * will be synchronized to the CKIL domain.
+ */
+static inline void rtc_write_sync_lp(void __iomem *ioaddr)
+{
+	unsigned int i, count;
+	/* Wait for 3 CKIL cycles */
+	for (i = 0; i < 3; i++) {
+		count = readl(ioaddr + SRTC_LPSCLR);
+		while ((readl(ioaddr + SRTC_LPSCLR)) == count)
+			;
+	}
+}
+
+/*!
+ * This function updates the RTC alarm registers and then clears all the
+ * interrupt status bits.
+ *
+ * @param  alrm         the new alarm value to be updated in the RTC
+ *
+ * @return  0 if successful; non-zero otherwise.
+ */
+static int rtc_update_alarm(struct device *dev, struct rtc_time *alrm)
+{
+	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
+	void __iomem *ioaddr = pdata->ioaddr;
+	struct rtc_time alarm_tm, now_tm;
+	unsigned long now, time;
+	int ret;
+
+	now = __raw_readl(ioaddr + SRTC_LPSCMR);
+	rtc_time_to_tm(now, &now_tm);
+
+	alarm_tm.tm_year = now_tm.tm_year;
+	alarm_tm.tm_mon = now_tm.tm_mon;
+	alarm_tm.tm_mday = now_tm.tm_mday;
+
+	alarm_tm.tm_hour = alrm->tm_hour;
+	alarm_tm.tm_min = alrm->tm_min;
+	alarm_tm.tm_sec = alrm->tm_sec;
+
+	rtc_tm_to_time(&now_tm, &now);
+	rtc_tm_to_time(&alarm_tm, &time);
+
+	if (time < now) {
+		time += 60 * 60 * 24;
+		rtc_time_to_tm(time, &alarm_tm);
+	}
+	ret = rtc_tm_to_time(&alarm_tm, &time);
+
+	__raw_writel(time, ioaddr + SRTC_LPSAR);
+
+	/* clear alarm interrupt status bit */
+	__raw_writel(SRTC_LPSR_ALP, ioaddr + SRTC_LPSR);
+
+	return ret;
+}
+
+/*!
+ * This function is the RTC interrupt service routine.
+ *
+ * @param  irq          RTC IRQ number
+ * @param  dev_id       device ID which is not used
+ *
+ * @return IRQ_HANDLED as defined in the include/linux/interrupt.h file.
+ */
+static irqreturn_t mxc_rtc_interrupt(int irq, void *dev_id)
+{
+	struct platform_device *pdev = dev_id;
+	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
+	void __iomem *ioaddr = pdata->ioaddr;
+	u32 lp_status, lp_cr;
+	u32 events = 0;
+
+	lp_status = __raw_readl(ioaddr + SRTC_LPSR);
+	lp_cr = __raw_readl(ioaddr + SRTC_LPCR);
+
+	/* update irq data & counter */
+	if (lp_status & SRTC_LPSR_ALP) {
+		if (lp_cr & SRTC_LPCR_ALP)
+			events |= (RTC_AF | RTC_IRQF);
+
+		/* disable further lp alarm interrupts */
+		lp_cr &= ~(SRTC_LPCR_ALP | SRTC_LPCR_WAE);
+	}
+
+	/* Update interrupt enables */
+	__raw_writel(lp_cr, ioaddr + SRTC_LPCR);
+
+	/* clear interrupt status */
+	__raw_writel(lp_status, ioaddr + SRTC_LPSR);
+
+	rtc_write_sync_lp(ioaddr);
+	rtc_update_irq(pdata->rtc, 1, events);
+	return IRQ_HANDLED;
+}
+
+/*!
+ * This function reads the current RTC time into tm in Gregorian date.
+ *
+ * @param  tm           contains the RTC time value upon return
+ *
+ * @return  0 if successful; non-zero otherwise.
+ */
+static int mxc_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
+	time_t now = readl(pdata->ioaddr + SRTC_LPSCMR);
+
+	rtc_time_to_tm(now, tm);
+	return rtc_valid_tm(tm);
+}
+
+/*!
+ * This function sets the internal RTC time based on tm in Gregorian date.
+ *
+ * @param  tm           the time value to be set in the RTC
+ *
+ * @return  0 if successful; non-zero otherwise.
+ */
+static int mxc_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
+	time64_t time = rtc_tm_to_time64(tm);
+
+	if (time > UINT_MAX) {
+		dev_warn(dev, "time_t has overflow\n");
+	}
+
+	writel(time, pdata->ioaddr + SRTC_LPSCMR);
+	rtc_write_sync_lp(pdata->ioaddr);
+	return 0;
+}
+
+/*!
+ * This function reads the current alarm value into the passed in \b alrm
+ * argument. It updates the \b alrm's pending field value based on the whether
+ * an alarm interrupt occurs or not.
+ *
+ * @param  alrm         contains the RTC alarm value upon return
+ *
+ * @return  0 if successful; non-zero otherwise.
+ */
+static int mxc_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
+	void __iomem *ioaddr = pdata->ioaddr;
+
+	rtc_time_to_tm(__raw_readl(ioaddr + SRTC_LPSAR), &alrm->time);
+	alrm->pending =
+	    ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_ALP) != 0) ? 1 : 0;
+
+	return 0;
+}
+
+static int mxc_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
+{
+	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
+	unsigned long lock_flags = 0;
+	u32 lp_cr;
+
+	spin_lock_irqsave(&rtc_lock, lock_flags);
+	lp_cr = __raw_readl(pdata->ioaddr + SRTC_LPCR);
+
+	if (enable)
+		lp_cr |= (SRTC_LPCR_ALP | SRTC_LPCR_WAE);
+	else
+		lp_cr &= ~(SRTC_LPCR_ALP | SRTC_LPCR_WAE);
+
+	__raw_writel(lp_cr, pdata->ioaddr + SRTC_LPCR);
+	spin_unlock_irqrestore(&rtc_lock, lock_flags);
+	return 0;
+}
+
+/*!
+ * This function sets the RTC alarm based on passed in alrm.
+ *
+ * @param  alrm         the alarm value to be set in the RTC
+ *
+ * @return  0 if successful; non-zero otherwise.
+ */
+static int mxc_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
+	void __iomem *ioaddr = pdata->ioaddr;
+	int ret;
+
+	ret = rtc_update_alarm(dev, &alrm->time);
+	if (!ret)
+		mxc_rtc_alarm_irq_enable(dev, alrm->enabled);
+
+	rtc_write_sync_lp(ioaddr);
+	return ret;
+}
+
+/*!
+ * The RTC driver structure
+ */
+static const struct rtc_class_ops mxc_rtc_ops = {
+	.read_time = mxc_rtc_read_time,
+	.set_time = mxc_rtc_set_time,
+	.read_alarm = mxc_rtc_read_alarm,
+	.set_alarm = mxc_rtc_set_alarm,
+	.alarm_irq_enable = mxc_rtc_alarm_irq_enable,
+};
+
+/*! MXC RTC Power management control */
+static int mxc_rtc_probe(struct platform_device *pdev)
+{
+	struct timespec tv;
+	struct resource *res;
+	struct rtc_drv_data *pdata = NULL;
+	void __iomem *ioaddr;
+	int ret = 0;
+
+	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	pdata->ioaddr = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(pdata->ioaddr))
+		return PTR_ERR(pdata->ioaddr);
+
+	ioaddr = pdata->ioaddr;
+
+	pdata->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(pdata->clk)) {
+		dev_err(&pdev->dev, "unable to get rtc clock!\n");
+		return PTR_ERR(pdata->clk);
+	}
+	ret = clk_prepare_enable(pdata->clk);
+	if (ret)
+		return ret;
+
+	/* Configure and enable the RTC */
+	pdata->irq = platform_get_irq(pdev, 0);
+	if (pdata->irq >= 0
+	    && devm_request_irq(&pdev->dev, pdata->irq, mxc_rtc_interrupt,
+				IRQF_SHARED, pdev->name, pdev) < 0) {
+		dev_warn(&pdev->dev, "interrupt not available.\n");
+		pdata->irq = -1;
+	}
+
+	if (pdata->irq >= 0)
+		device_init_wakeup(&pdev->dev, 1);
+
+	/* initialize glitch detect */
+	__raw_writel(SRTC_LPPDR_INIT, ioaddr + SRTC_LPPDR);
+	udelay(100);
+
+	/* clear lp interrupt status */
+	__raw_writel(0xFFFFFFFF, ioaddr + SRTC_LPSR);
+	udelay(100);
+
+	/* move out of init state */
+	__raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NSA), ioaddr + SRTC_LPCR);
+
+	udelay(100);
+
+	while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_IES) == 0)
+		;
+
+	/* move out of non-valid state */
+	__raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NVE | SRTC_LPCR_NSA |
+		      SRTC_LPCR_EN_LP), ioaddr + SRTC_LPCR);
+
+	udelay(100);
+
+	while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_NVES) == 0)
+		;
+
+	__raw_writel(0xFFFFFFFF, ioaddr + SRTC_LPSR);
+	udelay(100);
+
+	platform_set_drvdata(pdev, pdata);
+	pdata->rtc =
+	    devm_rtc_device_register(&pdev->dev, pdev->name, &mxc_rtc_ops,
+				     THIS_MODULE);
+	if (IS_ERR(pdata->rtc)) {
+		ret = PTR_ERR(pdata->rtc);
+		goto exit_put_clk;
+	}
+
+	tv.tv_nsec = 0;
+	tv.tv_sec = __raw_readl(ioaddr + SRTC_LPSCMR);
+
+	/* By default, devices should wakeup if they can */
+	/* So srtc is set as "should wakeup" as it can */
+	device_init_wakeup(&pdev->dev, 1);
+
+	return ret;
+
+exit_put_clk:
+	clk_disable_unprepare(pdata->clk);
+	return ret;
+}
+
+static int __exit mxc_rtc_remove(struct platform_device *pdev)
+{
+	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
+
+	clk_disable_unprepare(pdata->clk);
+	return 0;
+}
+
+/*!
+ * This function is called to save the system time delta relative to
+ * the MXC RTC when enterring a low power state. This time delta is
+ * then used on resume to adjust the system time to account for time
+ * loss while suspended.
+ *
+ * @param   pdev  not used
+ * @param   state Power state to enter.
+ *
+ * @return  The function always returns 0.
+ */
+static int mxc_rtc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
+
+	if (device_may_wakeup(&pdev->dev))
+		enable_irq_wake(pdata->irq);
+
+	return 0;
+}
+
+/*!
+ * This function is called to correct the system time based on the
+ * current MXC RTC time relative to the time delta saved during
+ * suspend.
+ *
+ * @param   pdev  not used
+ *
+ * @return  The function always returns 0.
+ */
+static int mxc_rtc_resume(struct platform_device *pdev)
+{
+	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
+
+	if (device_may_wakeup(&pdev->dev))
+		disable_irq_wake(pdata->irq);
+
+	return 0;
+}
+
+static const struct of_device_id mxc_ids[] = {
+	{.compatible = "fsl,imx53-rtc",},
+	{}
+};
+
+/*!
+ * Contains pointers to the power management callback functions.
+ */
+static struct platform_driver mxc_rtc_driver = {
+	.driver = {
+		   .name = "mxc_rtc_v8",
+		   .of_match_table = mxc_ids,
+		   },
+	.probe = mxc_rtc_probe,
+	.remove = mxc_rtc_remove,
+	.suspend = mxc_rtc_suspend,
+	.resume = mxc_rtc_resume,
+};
+
+module_platform_driver(mxc_rtc_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("Realtime Clock Driver (RTC)");
+MODULE_LICENSE("GPL");
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH] rtc: add mxc driver for i.MX53
@ 2017-11-28  7:39 ` linux-kernel-dev
  0 siblings, 0 replies; 43+ messages in thread
From: linux-kernel-dev at beckhoff.com @ 2017-11-28  7:39 UTC (permalink / raw)
  To: linux-arm-kernel

From: Patrick Bruenn <p.bruenn@beckhoff.com>

Neither rtc-imxdi nor rtc-mxc are compatible with i.MX53.
Add a modernized version of mxc_v2 from here:
http://git.freescale.com/git/cgit.cgi/imx/linux-2.6-imx.git/tree/drivers/rtc/rtc-mxc_v2.c?h=imx_2.6.35_11.09.01

Changes to that version:
- updated to v4.15-rc1
- removed ioctl()
- removed proc()
- removed manual(redundant) enable_irq flag

Signed-off-by: Patrick Bruenn <p.bruenn@beckhoff.com>

---

Open issues:
- driver naming, should it be merged with rtc-mxc.c ?
- document DT binding "fsl,imx53-rtc" accordingly
- Should unused defines be removed or kept for someone else to be
  useful?
- Is the use of __raw_readl/writel() correct? Should it be replaced with
  readl/writel()?
- suspend/resume() seems different to existing rtc-mxc.c, should I apply
  the pattern from rtc-mxc.c?
- On Shawns tree imx53.dtsi has been reverted already[1][2]. Should I split
  the imx53.dtsi change into a separate patch based on his tree? Or can
  we still stop the full revert and just remove the imx25-rtc compatible?
  I am not in a hurry, so we could just wait until the revert landed in
  Linus tree. Whatever you think is best.

[1] https://www.spinics.net/lists/arm-kernel/msg617113.html
[2] commit ee76f7729babd2700afd6f3874449d8084dd85ea

To: Alessandro Zummo <a.zummo@towertech.it>
To: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com> (maintainer:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS)
Cc: linux-rtc at vger.kernel.org (open list:REAL TIME CLOCK (RTC) SUBSYSTEM)
Cc: devicetree at vger.kernel.org (open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS)
Cc: linux-kernel at vger.kernel.org (open list)
Cc: Fabio Estevam <fabio.estevam@nxp.com>
Cc: Juergen Borleis <jbe@pengutronix.de>
Cc: Noel Vellemans <Noel.Vellemans@visionbms.com>
Cc: Shawn Guo <shawnguo@kernel.org>
Cc: Sascha Hauer <kernel@pengutronix.de> (maintainer:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE)
Cc: Russell King <linux@armlinux.org.uk> (maintainer:ARM PORT)
Cc: linux-arm-kernel at lists.infradead.org (moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE)
---
 arch/arm/boot/dts/imx53.dtsi |   2 +-
 drivers/rtc/Makefile         |   1 +
 drivers/rtc/rtc-mxc_v2.c     | 531 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 533 insertions(+), 1 deletion(-)
 create mode 100644 drivers/rtc/rtc-mxc_v2.c

diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi
index 589a67c5f796..3d1a55e11ea8 100644
--- a/arch/arm/boot/dts/imx53.dtsi
+++ b/arch/arm/boot/dts/imx53.dtsi
@@ -434,7 +434,7 @@
 			};
 
 			srtc: srtc at 53fa4000 {
-				compatible = "fsl,imx53-rtc", "fsl,imx25-rtc";
+				compatible = "fsl,imx53-rtc";
 				reg = <0x53fa4000 0x4000>;
 				interrupts = <24>;
 				interrupt-parent = <&tzic>;
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index f2f50c11dc38..fb3dc458c185 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -106,6 +106,7 @@ obj-$(CONFIG_RTC_DRV_MT6397)	+= rtc-mt6397.o
 obj-$(CONFIG_RTC_DRV_MT7622)	+= rtc-mt7622.o
 obj-$(CONFIG_RTC_DRV_MV)	+= rtc-mv.o
 obj-$(CONFIG_RTC_DRV_MXC)	+= rtc-mxc.o
+obj-$(CONFIG_RTC_DRV_MXC)	+= rtc-mxc_v2.o
 obj-$(CONFIG_RTC_DRV_NUC900)	+= rtc-nuc900.o
 obj-$(CONFIG_RTC_DRV_OMAP)	+= rtc-omap.o
 obj-$(CONFIG_RTC_DRV_OPAL)	+= rtc-opal.o
diff --git a/drivers/rtc/rtc-mxc_v2.c b/drivers/rtc/rtc-mxc_v2.c
new file mode 100644
index 000000000000..5049b521b38e
--- /dev/null
+++ b/drivers/rtc/rtc-mxc_v2.c
@@ -0,0 +1,531 @@
+/*
+ * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+/*
+ * Implementation based on rtc-ds1553.c
+ */
+
+/*!
+ * @defgroup RTC Real Time Clock (RTC) Driver for i.MX53
+ */
+/*!
+ * @file rtc-mxc_v2.c
+ * @brief Real Time Clock interface
+ *
+ * This file contains Real Time Clock interface for Linux.
+ *
+ * @ingroup RTC
+ */
+
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/rtc.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+//#include <linux/mxc_srtc.h>
+#define RTC_READ_TIME_47BIT	_IOR('p', 0x20, unsigned long long)
+/* blocks until LPSCMR is set, returns difference */
+#define RTC_WAIT_TIME_SET	_IOR('p', 0x21, int64_t)
+
+#define SRTC_LPSCLR_LLPSC_LSH	17	/* start bit for LSB time value */
+
+#define SRTC_LPPDR_INIT       0x41736166	/* init for glitch detect */
+
+#define SRTC_LPCR_SWR_LP      (1 << 0)	/* lp software reset */
+#define SRTC_LPCR_EN_LP       (1 << 3)	/* lp enable */
+#define SRTC_LPCR_WAE         (1 << 4)	/* lp wakeup alarm enable */
+#define SRTC_LPCR_SAE         (1 << 5)	/* lp security alarm enable */
+#define SRTC_LPCR_SI          (1 << 6)	/* lp security interrupt enable */
+#define SRTC_LPCR_ALP         (1 << 7)	/* lp alarm flag */
+#define SRTC_LPCR_LTC         (1 << 8)	/* lp lock time counter */
+#define SRTC_LPCR_LMC         (1 << 9)	/* lp lock monotonic counter */
+#define SRTC_LPCR_SV          (1 << 10)	/* lp security violation */
+#define SRTC_LPCR_NSA         (1 << 11)	/* lp non secure access */
+#define SRTC_LPCR_NVEIE       (1 << 12)	/* lp non valid state exit int en */
+#define SRTC_LPCR_IEIE        (1 << 13)	/* lp init state exit int enable */
+#define SRTC_LPCR_NVE         (1 << 14)	/* lp non valid state exit bit */
+#define SRTC_LPCR_IE          (1 << 15)	/* lp init state exit bit */
+
+#define SRTC_LPCR_ALL_INT_EN (SRTC_LPCR_WAE | SRTC_LPCR_SAE | \
+			      SRTC_LPCR_SI | SRTC_LPCR_ALP | \
+			      SRTC_LPCR_NVEIE | SRTC_LPCR_IEIE)
+
+#define SRTC_LPSR_TRI         (1 << 0)	/* lp time read invalidate */
+#define SRTC_LPSR_PGD         (1 << 1)	/* lp power supply glitc detected */
+#define SRTC_LPSR_CTD         (1 << 2)	/* lp clock tampering detected */
+#define SRTC_LPSR_ALP         (1 << 3)	/* lp alarm flag */
+#define SRTC_LPSR_MR          (1 << 4)	/* lp monotonic counter rollover */
+#define SRTC_LPSR_TR          (1 << 5)	/* lp time rollover */
+#define SRTC_LPSR_EAD         (1 << 6)	/* lp external alarm detected */
+#define SRTC_LPSR_IT0         (1 << 7)	/* lp IIM throttle */
+#define SRTC_LPSR_IT1         (1 << 8)
+#define SRTC_LPSR_IT2         (1 << 9)
+#define SRTC_LPSR_SM0         (1 << 10)	/* lp security mode */
+#define SRTC_LPSR_SM1         (1 << 11)
+#define SRTC_LPSR_STATE_LP0   (1 << 12)	/* lp state */
+#define SRTC_LPSR_STATE_LP1   (1 << 13)
+#define SRTC_LPSR_NVES        (1 << 14)	/* lp non-valid state exit status */
+#define SRTC_LPSR_IES         (1 << 15)	/* lp init state exit status */
+
+#define MAX_PIE_NUM     15
+#define MAX_PIE_FREQ    32768
+#define MIN_PIE_FREQ	1
+
+#define SRTC_PI0         (1 << 0)
+#define SRTC_PI1         (1 << 1)
+#define SRTC_PI2         (1 << 2)
+#define SRTC_PI3         (1 << 3)
+#define SRTC_PI4         (1 << 4)
+#define SRTC_PI5         (1 << 5)
+#define SRTC_PI6         (1 << 6)
+#define SRTC_PI7         (1 << 7)
+#define SRTC_PI8         (1 << 8)
+#define SRTC_PI9         (1 << 9)
+#define SRTC_PI10        (1 << 10)
+#define SRTC_PI11        (1 << 11)
+#define SRTC_PI12        (1 << 12)
+#define SRTC_PI13        (1 << 13)
+#define SRTC_PI14        (1 << 14)
+#define SRTC_PI15        (1 << 15)
+
+#define PIT_ALL_ON      (SRTC_PI1 | SRTC_PI2 | SRTC_PI3 | \
+			SRTC_PI4 | SRTC_PI5 | SRTC_PI6 | SRTC_PI7 | \
+			SRTC_PI8 | SRTC_PI9 | SRTC_PI10 | SRTC_PI11 | \
+			SRTC_PI12 | SRTC_PI13 | SRTC_PI14 | SRTC_PI15)
+
+#define SRTC_SWR_HP      (1 << 0)	/* hp software reset */
+#define SRTC_EN_HP       (1 << 3)	/* hp enable */
+#define SRTC_TS          (1 << 4)	/* time synchronize hp with lp */
+
+#define SRTC_IE_AHP      (1 << 16)	/* Alarm HP Interrupt Enable bit */
+#define SRTC_IE_WDHP     (1 << 18)	/* Write Done HP Interrupt Enable bit */
+#define SRTC_IE_WDLP     (1 << 19)	/* Write Done LP Interrupt Enable bit */
+
+#define SRTC_ISR_AHP     (1 << 16)	/* interrupt status: alarm hp */
+#define SRTC_ISR_WDHP    (1 << 18)	/* interrupt status: write done hp */
+#define SRTC_ISR_WDLP    (1 << 19)	/* interrupt status: write done lp */
+#define SRTC_ISR_WPHP    (1 << 20)	/* interrupt status: write pending hp */
+#define SRTC_ISR_WPLP    (1 << 21)	/* interrupt status: write pending lp */
+
+#define SRTC_LPSCMR	0x00	/* LP Secure Counter MSB Reg */
+#define SRTC_LPSCLR	0x04	/* LP Secure Counter LSB Reg */
+#define SRTC_LPSAR	0x08	/* LP Secure Alarm Reg */
+#define SRTC_LPSMCR	0x0C	/* LP Secure Monotonic Counter Reg */
+#define SRTC_LPCR	0x10	/* LP Control Reg */
+#define SRTC_LPSR	0x14	/* LP Status Reg */
+#define SRTC_LPPDR	0x18	/* LP Power Supply Glitch Detector Reg */
+#define SRTC_LPGR	0x1C	/* LP General Purpose Reg */
+#define SRTC_HPCMR	0x20	/* HP Counter MSB Reg */
+#define SRTC_HPCLR	0x24	/* HP Counter LSB Reg */
+#define SRTC_HPAMR	0x28	/* HP Alarm MSB Reg */
+#define SRTC_HPALR	0x2C	/* HP Alarm LSB Reg */
+#define SRTC_HPCR	0x30	/* HP Control Reg */
+#define SRTC_HPISR	0x34	/* HP Interrupt Status Reg */
+#define SRTC_HPIENR	0x38	/* HP Interrupt Enable Reg */
+
+#define SRTC_SECMODE_MASK	0x3	/* the mask of SRTC security mode */
+#define SRTC_SECMODE_LOW	0x0	/* Low Security */
+#define SRTC_SECMODE_MED	0x1	/* Medium Security */
+#define SRTC_SECMODE_HIGH	0x2	/* High Security */
+#define SRTC_SECMODE_RESERVED	0x3	/* Reserved */
+
+struct rtc_drv_data {
+	struct rtc_device *rtc;
+	void __iomem *ioaddr;
+	int irq;
+	struct clk *clk;
+};
+
+static DEFINE_SPINLOCK(rtc_lock);
+
+/*!
+ * This function does write synchronization for writes to the lp srtc block.
+ * To take care of the asynchronous CKIL clock, all writes from the IP domain
+ * will be synchronized to the CKIL domain.
+ */
+static inline void rtc_write_sync_lp(void __iomem *ioaddr)
+{
+	unsigned int i, count;
+	/* Wait for 3 CKIL cycles */
+	for (i = 0; i < 3; i++) {
+		count = readl(ioaddr + SRTC_LPSCLR);
+		while ((readl(ioaddr + SRTC_LPSCLR)) == count)
+			;
+	}
+}
+
+/*!
+ * This function updates the RTC alarm registers and then clears all the
+ * interrupt status bits.
+ *
+ * @param  alrm         the new alarm value to be updated in the RTC
+ *
+ * @return  0 if successful; non-zero otherwise.
+ */
+static int rtc_update_alarm(struct device *dev, struct rtc_time *alrm)
+{
+	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
+	void __iomem *ioaddr = pdata->ioaddr;
+	struct rtc_time alarm_tm, now_tm;
+	unsigned long now, time;
+	int ret;
+
+	now = __raw_readl(ioaddr + SRTC_LPSCMR);
+	rtc_time_to_tm(now, &now_tm);
+
+	alarm_tm.tm_year = now_tm.tm_year;
+	alarm_tm.tm_mon = now_tm.tm_mon;
+	alarm_tm.tm_mday = now_tm.tm_mday;
+
+	alarm_tm.tm_hour = alrm->tm_hour;
+	alarm_tm.tm_min = alrm->tm_min;
+	alarm_tm.tm_sec = alrm->tm_sec;
+
+	rtc_tm_to_time(&now_tm, &now);
+	rtc_tm_to_time(&alarm_tm, &time);
+
+	if (time < now) {
+		time += 60 * 60 * 24;
+		rtc_time_to_tm(time, &alarm_tm);
+	}
+	ret = rtc_tm_to_time(&alarm_tm, &time);
+
+	__raw_writel(time, ioaddr + SRTC_LPSAR);
+
+	/* clear alarm interrupt status bit */
+	__raw_writel(SRTC_LPSR_ALP, ioaddr + SRTC_LPSR);
+
+	return ret;
+}
+
+/*!
+ * This function is the RTC interrupt service routine.
+ *
+ * @param  irq          RTC IRQ number
+ * @param  dev_id       device ID which is not used
+ *
+ * @return IRQ_HANDLED as defined in the include/linux/interrupt.h file.
+ */
+static irqreturn_t mxc_rtc_interrupt(int irq, void *dev_id)
+{
+	struct platform_device *pdev = dev_id;
+	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
+	void __iomem *ioaddr = pdata->ioaddr;
+	u32 lp_status, lp_cr;
+	u32 events = 0;
+
+	lp_status = __raw_readl(ioaddr + SRTC_LPSR);
+	lp_cr = __raw_readl(ioaddr + SRTC_LPCR);
+
+	/* update irq data & counter */
+	if (lp_status & SRTC_LPSR_ALP) {
+		if (lp_cr & SRTC_LPCR_ALP)
+			events |= (RTC_AF | RTC_IRQF);
+
+		/* disable further lp alarm interrupts */
+		lp_cr &= ~(SRTC_LPCR_ALP | SRTC_LPCR_WAE);
+	}
+
+	/* Update interrupt enables */
+	__raw_writel(lp_cr, ioaddr + SRTC_LPCR);
+
+	/* clear interrupt status */
+	__raw_writel(lp_status, ioaddr + SRTC_LPSR);
+
+	rtc_write_sync_lp(ioaddr);
+	rtc_update_irq(pdata->rtc, 1, events);
+	return IRQ_HANDLED;
+}
+
+/*!
+ * This function reads the current RTC time into tm in Gregorian date.
+ *
+ * @param  tm           contains the RTC time value upon return
+ *
+ * @return  0 if successful; non-zero otherwise.
+ */
+static int mxc_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
+	time_t now = readl(pdata->ioaddr + SRTC_LPSCMR);
+
+	rtc_time_to_tm(now, tm);
+	return rtc_valid_tm(tm);
+}
+
+/*!
+ * This function sets the internal RTC time based on tm in Gregorian date.
+ *
+ * @param  tm           the time value to be set in the RTC
+ *
+ * @return  0 if successful; non-zero otherwise.
+ */
+static int mxc_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
+	time64_t time = rtc_tm_to_time64(tm);
+
+	if (time > UINT_MAX) {
+		dev_warn(dev, "time_t has overflow\n");
+	}
+
+	writel(time, pdata->ioaddr + SRTC_LPSCMR);
+	rtc_write_sync_lp(pdata->ioaddr);
+	return 0;
+}
+
+/*!
+ * This function reads the current alarm value into the passed in \b alrm
+ * argument. It updates the \b alrm's pending field value based on the whether
+ * an alarm interrupt occurs or not.
+ *
+ * @param  alrm         contains the RTC alarm value upon return
+ *
+ * @return  0 if successful; non-zero otherwise.
+ */
+static int mxc_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
+	void __iomem *ioaddr = pdata->ioaddr;
+
+	rtc_time_to_tm(__raw_readl(ioaddr + SRTC_LPSAR), &alrm->time);
+	alrm->pending =
+	    ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_ALP) != 0) ? 1 : 0;
+
+	return 0;
+}
+
+static int mxc_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
+{
+	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
+	unsigned long lock_flags = 0;
+	u32 lp_cr;
+
+	spin_lock_irqsave(&rtc_lock, lock_flags);
+	lp_cr = __raw_readl(pdata->ioaddr + SRTC_LPCR);
+
+	if (enable)
+		lp_cr |= (SRTC_LPCR_ALP | SRTC_LPCR_WAE);
+	else
+		lp_cr &= ~(SRTC_LPCR_ALP | SRTC_LPCR_WAE);
+
+	__raw_writel(lp_cr, pdata->ioaddr + SRTC_LPCR);
+	spin_unlock_irqrestore(&rtc_lock, lock_flags);
+	return 0;
+}
+
+/*!
+ * This function sets the RTC alarm based on passed in alrm.
+ *
+ * @param  alrm         the alarm value to be set in the RTC
+ *
+ * @return  0 if successful; non-zero otherwise.
+ */
+static int mxc_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
+	void __iomem *ioaddr = pdata->ioaddr;
+	int ret;
+
+	ret = rtc_update_alarm(dev, &alrm->time);
+	if (!ret)
+		mxc_rtc_alarm_irq_enable(dev, alrm->enabled);
+
+	rtc_write_sync_lp(ioaddr);
+	return ret;
+}
+
+/*!
+ * The RTC driver structure
+ */
+static const struct rtc_class_ops mxc_rtc_ops = {
+	.read_time = mxc_rtc_read_time,
+	.set_time = mxc_rtc_set_time,
+	.read_alarm = mxc_rtc_read_alarm,
+	.set_alarm = mxc_rtc_set_alarm,
+	.alarm_irq_enable = mxc_rtc_alarm_irq_enable,
+};
+
+/*! MXC RTC Power management control */
+static int mxc_rtc_probe(struct platform_device *pdev)
+{
+	struct timespec tv;
+	struct resource *res;
+	struct rtc_drv_data *pdata = NULL;
+	void __iomem *ioaddr;
+	int ret = 0;
+
+	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	pdata->ioaddr = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(pdata->ioaddr))
+		return PTR_ERR(pdata->ioaddr);
+
+	ioaddr = pdata->ioaddr;
+
+	pdata->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(pdata->clk)) {
+		dev_err(&pdev->dev, "unable to get rtc clock!\n");
+		return PTR_ERR(pdata->clk);
+	}
+	ret = clk_prepare_enable(pdata->clk);
+	if (ret)
+		return ret;
+
+	/* Configure and enable the RTC */
+	pdata->irq = platform_get_irq(pdev, 0);
+	if (pdata->irq >= 0
+	    && devm_request_irq(&pdev->dev, pdata->irq, mxc_rtc_interrupt,
+				IRQF_SHARED, pdev->name, pdev) < 0) {
+		dev_warn(&pdev->dev, "interrupt not available.\n");
+		pdata->irq = -1;
+	}
+
+	if (pdata->irq >= 0)
+		device_init_wakeup(&pdev->dev, 1);
+
+	/* initialize glitch detect */
+	__raw_writel(SRTC_LPPDR_INIT, ioaddr + SRTC_LPPDR);
+	udelay(100);
+
+	/* clear lp interrupt status */
+	__raw_writel(0xFFFFFFFF, ioaddr + SRTC_LPSR);
+	udelay(100);
+
+	/* move out of init state */
+	__raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NSA), ioaddr + SRTC_LPCR);
+
+	udelay(100);
+
+	while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_IES) == 0)
+		;
+
+	/* move out of non-valid state */
+	__raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NVE | SRTC_LPCR_NSA |
+		      SRTC_LPCR_EN_LP), ioaddr + SRTC_LPCR);
+
+	udelay(100);
+
+	while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_NVES) == 0)
+		;
+
+	__raw_writel(0xFFFFFFFF, ioaddr + SRTC_LPSR);
+	udelay(100);
+
+	platform_set_drvdata(pdev, pdata);
+	pdata->rtc =
+	    devm_rtc_device_register(&pdev->dev, pdev->name, &mxc_rtc_ops,
+				     THIS_MODULE);
+	if (IS_ERR(pdata->rtc)) {
+		ret = PTR_ERR(pdata->rtc);
+		goto exit_put_clk;
+	}
+
+	tv.tv_nsec = 0;
+	tv.tv_sec = __raw_readl(ioaddr + SRTC_LPSCMR);
+
+	/* By default, devices should wakeup if they can */
+	/* So srtc is set as "should wakeup" as it can */
+	device_init_wakeup(&pdev->dev, 1);
+
+	return ret;
+
+exit_put_clk:
+	clk_disable_unprepare(pdata->clk);
+	return ret;
+}
+
+static int __exit mxc_rtc_remove(struct platform_device *pdev)
+{
+	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
+
+	clk_disable_unprepare(pdata->clk);
+	return 0;
+}
+
+/*!
+ * This function is called to save the system time delta relative to
+ * the MXC RTC when enterring a low power state. This time delta is
+ * then used on resume to adjust the system time to account for time
+ * loss while suspended.
+ *
+ * @param   pdev  not used
+ * @param   state Power state to enter.
+ *
+ * @return  The function always returns 0.
+ */
+static int mxc_rtc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
+
+	if (device_may_wakeup(&pdev->dev))
+		enable_irq_wake(pdata->irq);
+
+	return 0;
+}
+
+/*!
+ * This function is called to correct the system time based on the
+ * current MXC RTC time relative to the time delta saved during
+ * suspend.
+ *
+ * @param   pdev  not used
+ *
+ * @return  The function always returns 0.
+ */
+static int mxc_rtc_resume(struct platform_device *pdev)
+{
+	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
+
+	if (device_may_wakeup(&pdev->dev))
+		disable_irq_wake(pdata->irq);
+
+	return 0;
+}
+
+static const struct of_device_id mxc_ids[] = {
+	{.compatible = "fsl,imx53-rtc",},
+	{}
+};
+
+/*!
+ * Contains pointers to the power management callback functions.
+ */
+static struct platform_driver mxc_rtc_driver = {
+	.driver = {
+		   .name = "mxc_rtc_v8",
+		   .of_match_table = mxc_ids,
+		   },
+	.probe = mxc_rtc_probe,
+	.remove = mxc_rtc_remove,
+	.suspend = mxc_rtc_suspend,
+	.resume = mxc_rtc_resume,
+};
+
+module_platform_driver(mxc_rtc_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("Realtime Clock Driver (RTC)");
+MODULE_LICENSE("GPL");
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* Re: [PATCH] rtc: add mxc driver for i.MX53
  2017-11-28  7:39 ` linux-kernel-dev
  (?)
  (?)
@ 2017-11-29 22:11   ` Alexandre Belloni
  -1 siblings, 0 replies; 43+ messages in thread
From: Alexandre Belloni @ 2017-11-29 22:11 UTC (permalink / raw)
  To: linux-kernel-dev
  Cc: Alessandro Zummo, Patrick Bruenn, Rob Herring, Mark Rutland,
	open list:REAL TIME CLOCK (RTC) SUBSYSTEM,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	open list, Fabio Estevam, Juergen Borleis, Noel Vellemans,
	Shawn Guo, Sascha Hauer, Russell King,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE

Hi,

A really quick review:

On 28/11/2017 at 08:39:27 +0100, linux-kernel-dev@beckhoff.com wrote:
> From: Patrick Bruenn <p.bruenn@beckhoff.com>
> 
> Neither rtc-imxdi nor rtc-mxc are compatible with i.MX53.
> Add a modernized version of mxc_v2 from here:
> http://git.freescale.com/git/cgit.cgi/imx/linux-2.6-imx.git/tree/drivers/rtc/rtc-mxc_v2.c?h=imx_2.6.35_11.09.01
> 
> Changes to that version:
> - updated to v4.15-rc1
> - removed ioctl()
> - removed proc()
> - removed manual(redundant) enable_irq flag
> 

I'd say this doesn't add much information as this link is probably bound
to die at some point (especially seeing the NXP/Qualcomm/Broadcom
story).

> Signed-off-by: Patrick Bruenn <p.bruenn@beckhoff.com>
> 
> ---
> 
> Open issues:
> - driver naming, should it be merged with rtc-mxc.c ?

This seems different enough to be a separate driver.

> - document DT binding "fsl,imx53-rtc" accordingly

Yes, this has to be documented in a previous patch

> - Should unused defines be removed or kept for someone else to be
>   useful?

I don't care much, either are fine but the less lines, the easier the
reviews.

> - Is the use of __raw_readl/writel() correct? Should it be replaced with
>   readl/writel()?

The __raw version will not work if someone is running a BE kernel so
they should be moved to the _relaxed version or the usual readl/writel.

> - suspend/resume() seems different to existing rtc-mxc.c, should I apply
>   the pattern from rtc-mxc.c?

If you mean using SIMPLE_DEV_PM_OPS, yes, you should do that.

> - On Shawns tree imx53.dtsi has been reverted already[1][2]. Should I split
>   the imx53.dtsi change into a separate patch based on his tree? Or can
>   we still stop the full revert and just remove the imx25-rtc compatible?
>   I am not in a hurry, so we could just wait until the revert landed in
>   Linus tree. Whatever you think is best.
> 

I'm not taking DT changes through the RTC tree so it should be in a
separate patch that will go through Shawn's tree

You should also use checkpatch --strict, most of the warnings are
correct.


> [1] https://www.spinics.net/lists/arm-kernel/msg617113.html
> [2] commit ee76f7729babd2700afd6f3874449d8084dd85ea
> 
> To: Alessandro Zummo <a.zummo@towertech.it>
> To: Alexandre Belloni <alexandre.belloni@free-electrons.com>
> Cc: Rob Herring <robh+dt@kernel.org>
> Cc: Mark Rutland <mark.rutland@arm.com> (maintainer:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS)
> Cc: linux-rtc@vger.kernel.org (open list:REAL TIME CLOCK (RTC) SUBSYSTEM)
> Cc: devicetree@vger.kernel.org (open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS)
> Cc: linux-kernel@vger.kernel.org (open list)
> Cc: Fabio Estevam <fabio.estevam@nxp.com>
> Cc: Juergen Borleis <jbe@pengutronix.de>
> Cc: Noel Vellemans <Noel.Vellemans@visionbms.com>
> Cc: Shawn Guo <shawnguo@kernel.org>
> Cc: Sascha Hauer <kernel@pengutronix.de> (maintainer:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE)
> Cc: Russell King <linux@armlinux.org.uk> (maintainer:ARM PORT)
> Cc: linux-arm-kernel@lists.infradead.org (moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE)
> ---
>  arch/arm/boot/dts/imx53.dtsi |   2 +-
>  drivers/rtc/Makefile         |   1 +
>  drivers/rtc/rtc-mxc_v2.c     | 531 +++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 533 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/rtc/rtc-mxc_v2.c
> 
> diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi
> index 589a67c5f796..3d1a55e11ea8 100644
> --- a/arch/arm/boot/dts/imx53.dtsi
> +++ b/arch/arm/boot/dts/imx53.dtsi
> @@ -434,7 +434,7 @@
>  			};
>  
>  			srtc: srtc@53fa4000 {
> -				compatible = "fsl,imx53-rtc", "fsl,imx25-rtc";
> +				compatible = "fsl,imx53-rtc";
>  				reg = <0x53fa4000 0x4000>;
>  				interrupts = <24>;
>  				interrupt-parent = <&tzic>;
> diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
> index f2f50c11dc38..fb3dc458c185 100644
> --- a/drivers/rtc/Makefile
> +++ b/drivers/rtc/Makefile
> @@ -106,6 +106,7 @@ obj-$(CONFIG_RTC_DRV_MT6397)	+= rtc-mt6397.o
>  obj-$(CONFIG_RTC_DRV_MT7622)	+= rtc-mt7622.o
>  obj-$(CONFIG_RTC_DRV_MV)	+= rtc-mv.o
>  obj-$(CONFIG_RTC_DRV_MXC)	+= rtc-mxc.o
> +obj-$(CONFIG_RTC_DRV_MXC)	+= rtc-mxc_v2.o

This definitively needs a different Kconfig symbol.

>  obj-$(CONFIG_RTC_DRV_NUC900)	+= rtc-nuc900.o
>  obj-$(CONFIG_RTC_DRV_OMAP)	+= rtc-omap.o
>  obj-$(CONFIG_RTC_DRV_OPAL)	+= rtc-opal.o
> diff --git a/drivers/rtc/rtc-mxc_v2.c b/drivers/rtc/rtc-mxc_v2.c
> new file mode 100644
> index 000000000000..5049b521b38e
> --- /dev/null
> +++ b/drivers/rtc/rtc-mxc_v2.c
> @@ -0,0 +1,531 @@

I think SPDX identifier will soon be required on new files, please add
one.

> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights Reserved.
> + */
> +
> +/*
> + * The code contained herein is licensed under the GNU General Public
> + * License. You may obtain a copy of the GNU General Public License
> + * Version 2 or later at the following locations:
> + *
> + * http://www.opensource.org/licenses/gpl-license.html
> + * http://www.gnu.org/copyleft/gpl.html
> + */
> +/*
> + * Implementation based on rtc-ds1553.c
> + */
> +
> +/*!
> + * @defgroup RTC Real Time Clock (RTC) Driver for i.MX53
> + */
> +/*!
> + * @file rtc-mxc_v2.c
> + * @brief Real Time Clock interface
> + *
> + * This file contains Real Time Clock interface for Linux.
> + *
> + * @ingroup RTC
> + */
> +

Is that comment really useful?

> +#include <linux/slab.h>
> +#include <linux/delay.h>
> +#include <linux/rtc.h>
> +#include <linux/module.h>
> +#include <linux/fs.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/platform_device.h>
> +#include <linux/clk.h>
> +#include <linux/device.h>
> +#include <linux/uaccess.h>
> +#include <linux/io.h>

This should be in alphabetical order

> +//#include <linux/mxc_srtc.h>

This is not useful

> +#define RTC_READ_TIME_47BIT	_IOR('p', 0x20, unsigned long long)
> +/* blocks until LPSCMR is set, returns difference */
> +#define RTC_WAIT_TIME_SET	_IOR('p', 0x21, int64_t)
> +

Those ioctls are not used.

> +#define SRTC_LPSCLR_LLPSC_LSH	17	/* start bit for LSB time value */
> +
> +#define SRTC_LPPDR_INIT       0x41736166	/* init for glitch detect */
> +
> +#define SRTC_LPCR_SWR_LP      (1 << 0)	/* lp software reset */
> +#define SRTC_LPCR_EN_LP       (1 << 3)	/* lp enable */
> +#define SRTC_LPCR_WAE         (1 << 4)	/* lp wakeup alarm enable */
> +#define SRTC_LPCR_SAE         (1 << 5)	/* lp security alarm enable */
> +#define SRTC_LPCR_SI          (1 << 6)	/* lp security interrupt enable */
> +#define SRTC_LPCR_ALP         (1 << 7)	/* lp alarm flag */
> +#define SRTC_LPCR_LTC         (1 << 8)	/* lp lock time counter */
> +#define SRTC_LPCR_LMC         (1 << 9)	/* lp lock monotonic counter */
> +#define SRTC_LPCR_SV          (1 << 10)	/* lp security violation */
> +#define SRTC_LPCR_NSA         (1 << 11)	/* lp non secure access */
> +#define SRTC_LPCR_NVEIE       (1 << 12)	/* lp non valid state exit int en */
> +#define SRTC_LPCR_IEIE        (1 << 13)	/* lp init state exit int enable */
> +#define SRTC_LPCR_NVE         (1 << 14)	/* lp non valid state exit bit */
> +#define SRTC_LPCR_IE          (1 << 15)	/* lp init state exit bit */
> +
> +#define SRTC_LPCR_ALL_INT_EN (SRTC_LPCR_WAE | SRTC_LPCR_SAE | \
> +			      SRTC_LPCR_SI | SRTC_LPCR_ALP | \
> +			      SRTC_LPCR_NVEIE | SRTC_LPCR_IEIE)
> +
> +#define SRTC_LPSR_TRI         (1 << 0)	/* lp time read invalidate */
> +#define SRTC_LPSR_PGD         (1 << 1)	/* lp power supply glitc detected */
> +#define SRTC_LPSR_CTD         (1 << 2)	/* lp clock tampering detected */
> +#define SRTC_LPSR_ALP         (1 << 3)	/* lp alarm flag */
> +#define SRTC_LPSR_MR          (1 << 4)	/* lp monotonic counter rollover */
> +#define SRTC_LPSR_TR          (1 << 5)	/* lp time rollover */
> +#define SRTC_LPSR_EAD         (1 << 6)	/* lp external alarm detected */
> +#define SRTC_LPSR_IT0         (1 << 7)	/* lp IIM throttle */
> +#define SRTC_LPSR_IT1         (1 << 8)
> +#define SRTC_LPSR_IT2         (1 << 9)
> +#define SRTC_LPSR_SM0         (1 << 10)	/* lp security mode */
> +#define SRTC_LPSR_SM1         (1 << 11)
> +#define SRTC_LPSR_STATE_LP0   (1 << 12)	/* lp state */
> +#define SRTC_LPSR_STATE_LP1   (1 << 13)
> +#define SRTC_LPSR_NVES        (1 << 14)	/* lp non-valid state exit status */
> +#define SRTC_LPSR_IES         (1 << 15)	/* lp init state exit status */
> +
> +#define MAX_PIE_NUM     15
> +#define MAX_PIE_FREQ    32768
> +#define MIN_PIE_FREQ	1
> +
> +#define SRTC_PI0         (1 << 0)
> +#define SRTC_PI1         (1 << 1)
> +#define SRTC_PI2         (1 << 2)
> +#define SRTC_PI3         (1 << 3)
> +#define SRTC_PI4         (1 << 4)
> +#define SRTC_PI5         (1 << 5)
> +#define SRTC_PI6         (1 << 6)
> +#define SRTC_PI7         (1 << 7)
> +#define SRTC_PI8         (1 << 8)
> +#define SRTC_PI9         (1 << 9)
> +#define SRTC_PI10        (1 << 10)
> +#define SRTC_PI11        (1 << 11)
> +#define SRTC_PI12        (1 << 12)
> +#define SRTC_PI13        (1 << 13)
> +#define SRTC_PI14        (1 << 14)
> +#define SRTC_PI15        (1 << 15)
> +
> +#define PIT_ALL_ON      (SRTC_PI1 | SRTC_PI2 | SRTC_PI3 | \
> +			SRTC_PI4 | SRTC_PI5 | SRTC_PI6 | SRTC_PI7 | \
> +			SRTC_PI8 | SRTC_PI9 | SRTC_PI10 | SRTC_PI11 | \
> +			SRTC_PI12 | SRTC_PI13 | SRTC_PI14 | SRTC_PI15)
> +
> +#define SRTC_SWR_HP      (1 << 0)	/* hp software reset */
> +#define SRTC_EN_HP       (1 << 3)	/* hp enable */
> +#define SRTC_TS          (1 << 4)	/* time synchronize hp with lp */
> +
> +#define SRTC_IE_AHP      (1 << 16)	/* Alarm HP Interrupt Enable bit */
> +#define SRTC_IE_WDHP     (1 << 18)	/* Write Done HP Interrupt Enable bit */
> +#define SRTC_IE_WDLP     (1 << 19)	/* Write Done LP Interrupt Enable bit */
> +
> +#define SRTC_ISR_AHP     (1 << 16)	/* interrupt status: alarm hp */
> +#define SRTC_ISR_WDHP    (1 << 18)	/* interrupt status: write done hp */
> +#define SRTC_ISR_WDLP    (1 << 19)	/* interrupt status: write done lp */
> +#define SRTC_ISR_WPHP    (1 << 20)	/* interrupt status: write pending hp */
> +#define SRTC_ISR_WPLP    (1 << 21)	/* interrupt status: write pending lp */
> +
> +#define SRTC_LPSCMR	0x00	/* LP Secure Counter MSB Reg */
> +#define SRTC_LPSCLR	0x04	/* LP Secure Counter LSB Reg */
> +#define SRTC_LPSAR	0x08	/* LP Secure Alarm Reg */
> +#define SRTC_LPSMCR	0x0C	/* LP Secure Monotonic Counter Reg */
> +#define SRTC_LPCR	0x10	/* LP Control Reg */
> +#define SRTC_LPSR	0x14	/* LP Status Reg */
> +#define SRTC_LPPDR	0x18	/* LP Power Supply Glitch Detector Reg */
> +#define SRTC_LPGR	0x1C	/* LP General Purpose Reg */
> +#define SRTC_HPCMR	0x20	/* HP Counter MSB Reg */
> +#define SRTC_HPCLR	0x24	/* HP Counter LSB Reg */
> +#define SRTC_HPAMR	0x28	/* HP Alarm MSB Reg */
> +#define SRTC_HPALR	0x2C	/* HP Alarm LSB Reg */
> +#define SRTC_HPCR	0x30	/* HP Control Reg */
> +#define SRTC_HPISR	0x34	/* HP Interrupt Status Reg */
> +#define SRTC_HPIENR	0x38	/* HP Interrupt Enable Reg */
> +
> +#define SRTC_SECMODE_MASK	0x3	/* the mask of SRTC security mode */
> +#define SRTC_SECMODE_LOW	0x0	/* Low Security */
> +#define SRTC_SECMODE_MED	0x1	/* Medium Security */
> +#define SRTC_SECMODE_HIGH	0x2	/* High Security */
> +#define SRTC_SECMODE_RESERVED	0x3	/* Reserved */
> +
> +struct rtc_drv_data {
> +	struct rtc_device *rtc;
> +	void __iomem *ioaddr;
> +	int irq;
> +	struct clk *clk;
> +};
> +
> +static DEFINE_SPINLOCK(rtc_lock);
> +

Shouldn't that lock be part of rtc_drv_data?

> +/*!
> + * This function does write synchronization for writes to the lp srtc block.
> + * To take care of the asynchronous CKIL clock, all writes from the IP domain
> + * will be synchronized to the CKIL domain.
> + */
> +static inline void rtc_write_sync_lp(void __iomem *ioaddr)
> +{
> +	unsigned int i, count;
> +	/* Wait for 3 CKIL cycles */
> +	for (i = 0; i < 3; i++) {
> +		count = readl(ioaddr + SRTC_LPSCLR);
> +		while ((readl(ioaddr + SRTC_LPSCLR)) == count)
> +			;
> +	}
> +}
> +
> +/*!
> + * This function updates the RTC alarm registers and then clears all the
> + * interrupt status bits.
> + *
> + * @param  alrm         the new alarm value to be updated in the RTC
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int rtc_update_alarm(struct device *dev, struct rtc_time *alrm)
> +{
> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	void __iomem *ioaddr = pdata->ioaddr;
> +	struct rtc_time alarm_tm, now_tm;
> +	unsigned long now, time;
> +	int ret;
> +
> +	now = __raw_readl(ioaddr + SRTC_LPSCMR);
> +	rtc_time_to_tm(now, &now_tm);
> +
> +	alarm_tm.tm_year = now_tm.tm_year;
> +	alarm_tm.tm_mon = now_tm.tm_mon;
> +	alarm_tm.tm_mday = now_tm.tm_mday;
> +
> +	alarm_tm.tm_hour = alrm->tm_hour;
> +	alarm_tm.tm_min = alrm->tm_min;
> +	alarm_tm.tm_sec = alrm->tm_sec;
> +
> +	rtc_tm_to_time(&now_tm, &now);
> +	rtc_tm_to_time(&alarm_tm, &time);
> +
> +	if (time < now) {
> +		time += 60 * 60 * 24;
> +		rtc_time_to_tm(time, &alarm_tm);
> +	}
> +	ret = rtc_tm_to_time(&alarm_tm, &time);
> +
> +	__raw_writel(time, ioaddr + SRTC_LPSAR);
> +
> +	/* clear alarm interrupt status bit */
> +	__raw_writel(SRTC_LPSR_ALP, ioaddr + SRTC_LPSR);
> +
> +	return ret;
> +}
> +
> +/*!
> + * This function is the RTC interrupt service routine.
> + *
> + * @param  irq          RTC IRQ number
> + * @param  dev_id       device ID which is not used
> + *
> + * @return IRQ_HANDLED as defined in the include/linux/interrupt.h file.
> + */
> +static irqreturn_t mxc_rtc_interrupt(int irq, void *dev_id)
> +{
> +	struct platform_device *pdev = dev_id;
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +	void __iomem *ioaddr = pdata->ioaddr;
> +	u32 lp_status, lp_cr;
> +	u32 events = 0;
> +
> +	lp_status = __raw_readl(ioaddr + SRTC_LPSR);
> +	lp_cr = __raw_readl(ioaddr + SRTC_LPCR);
> +
> +	/* update irq data & counter */
> +	if (lp_status & SRTC_LPSR_ALP) {
> +		if (lp_cr & SRTC_LPCR_ALP)
> +			events |= (RTC_AF | RTC_IRQF);
> +
> +		/* disable further lp alarm interrupts */
> +		lp_cr &= ~(SRTC_LPCR_ALP | SRTC_LPCR_WAE);
> +	}
> +
> +	/* Update interrupt enables */
> +	__raw_writel(lp_cr, ioaddr + SRTC_LPCR);
> +
> +	/* clear interrupt status */
> +	__raw_writel(lp_status, ioaddr + SRTC_LPSR);
> +
> +	rtc_write_sync_lp(ioaddr);
> +	rtc_update_irq(pdata->rtc, 1, events);
> +	return IRQ_HANDLED;
> +}
> +
> +/*!
> + * This function reads the current RTC time into tm in Gregorian date.
> + *
> + * @param  tm           contains the RTC time value upon return
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int mxc_rtc_read_time(struct device *dev, struct rtc_time *tm)
> +{
> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	time_t now = readl(pdata->ioaddr + SRTC_LPSCMR);
> +
> +	rtc_time_to_tm(now, tm);
> +	return rtc_valid_tm(tm);
> +}
> +
> +/*!
> + * This function sets the internal RTC time based on tm in Gregorian date.
> + *
> + * @param  tm           the time value to be set in the RTC
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int mxc_rtc_set_time(struct device *dev, struct rtc_time *tm)
> +{
> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	time64_t time = rtc_tm_to_time64(tm);
> +
> +	if (time > UINT_MAX) {
> +		dev_warn(dev, "time_t has overflow\n");
> +	}
> +
> +	writel(time, pdata->ioaddr + SRTC_LPSCMR);
> +	rtc_write_sync_lp(pdata->ioaddr);
> +	return 0;
> +}
> +
> +/*!
> + * This function reads the current alarm value into the passed in \b alrm
> + * argument. It updates the \b alrm's pending field value based on the whether
> + * an alarm interrupt occurs or not.
> + *
> + * @param  alrm         contains the RTC alarm value upon return
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int mxc_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
> +{
> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	void __iomem *ioaddr = pdata->ioaddr;
> +
> +	rtc_time_to_tm(__raw_readl(ioaddr + SRTC_LPSAR), &alrm->time);
> +	alrm->pending =
> +	    ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_ALP) != 0) ? 1 : 0;
> +
> +	return 0;
> +}
> +
> +static int mxc_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
> +{
> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	unsigned long lock_flags = 0;
> +	u32 lp_cr;
> +
> +	spin_lock_irqsave(&rtc_lock, lock_flags);
> +	lp_cr = __raw_readl(pdata->ioaddr + SRTC_LPCR);
> +
> +	if (enable)
> +		lp_cr |= (SRTC_LPCR_ALP | SRTC_LPCR_WAE);
> +	else
> +		lp_cr &= ~(SRTC_LPCR_ALP | SRTC_LPCR_WAE);
> +
> +	__raw_writel(lp_cr, pdata->ioaddr + SRTC_LPCR);
> +	spin_unlock_irqrestore(&rtc_lock, lock_flags);
> +	return 0;
> +}
> +
> +/*!
> + * This function sets the RTC alarm based on passed in alrm.
> + *
> + * @param  alrm         the alarm value to be set in the RTC
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int mxc_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
> +{
> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	void __iomem *ioaddr = pdata->ioaddr;
> +	int ret;
> +
> +	ret = rtc_update_alarm(dev, &alrm->time);
> +	if (!ret)
> +		mxc_rtc_alarm_irq_enable(dev, alrm->enabled);
> +
> +	rtc_write_sync_lp(ioaddr);
> +	return ret;
> +}
> +
> +/*!
> + * The RTC driver structure
> + */
> +static const struct rtc_class_ops mxc_rtc_ops = {
> +	.read_time = mxc_rtc_read_time,
> +	.set_time = mxc_rtc_set_time,
> +	.read_alarm = mxc_rtc_read_alarm,
> +	.set_alarm = mxc_rtc_set_alarm,
> +	.alarm_irq_enable = mxc_rtc_alarm_irq_enable,
> +};
> +
> +/*! MXC RTC Power management control */

This comment is probably wrong ;)

> +static int mxc_rtc_probe(struct platform_device *pdev)
> +{
> +	struct timespec tv;
> +	struct resource *res;
> +	struct rtc_drv_data *pdata = NULL;
> +	void __iomem *ioaddr;
> +	int ret = 0;
> +
> +	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
> +	if (!pdata)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res)
> +		return -ENODEV;
> +
> +	pdata->ioaddr = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(pdata->ioaddr))
> +		return PTR_ERR(pdata->ioaddr);
> +
> +	ioaddr = pdata->ioaddr;
> +
> +	pdata->clk = devm_clk_get(&pdev->dev, NULL);
> +	if (IS_ERR(pdata->clk)) {
> +		dev_err(&pdev->dev, "unable to get rtc clock!\n");
> +		return PTR_ERR(pdata->clk);
> +	}
> +	ret = clk_prepare_enable(pdata->clk);
> +	if (ret)
> +		return ret;
> +
> +	/* Configure and enable the RTC */
> +	pdata->irq = platform_get_irq(pdev, 0);
> +	if (pdata->irq >= 0
> +	    && devm_request_irq(&pdev->dev, pdata->irq, mxc_rtc_interrupt,
> +				IRQF_SHARED, pdev->name, pdev) < 0) {
> +		dev_warn(&pdev->dev, "interrupt not available.\n");
> +		pdata->irq = -1;
> +	}
> +
> +	if (pdata->irq >= 0)
> +		device_init_wakeup(&pdev->dev, 1);
> +
> +	/* initialize glitch detect */
> +	__raw_writel(SRTC_LPPDR_INIT, ioaddr + SRTC_LPPDR);
> +	udelay(100);
> +
> +	/* clear lp interrupt status */
> +	__raw_writel(0xFFFFFFFF, ioaddr + SRTC_LPSR);
> +	udelay(100);
> +
> +	/* move out of init state */
> +	__raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NSA), ioaddr + SRTC_LPCR);
> +
> +	udelay(100);
> +
> +	while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_IES) == 0)
> +		;
> +
> +	/* move out of non-valid state */
> +	__raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NVE | SRTC_LPCR_NSA |
> +		      SRTC_LPCR_EN_LP), ioaddr + SRTC_LPCR);
> +
> +	udelay(100);
> +
> +	while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_NVES) == 0)
> +		;
> +
> +	__raw_writel(0xFFFFFFFF, ioaddr + SRTC_LPSR);
> +	udelay(100);
> +
> +	platform_set_drvdata(pdev, pdata);
> +	pdata->rtc =
> +	    devm_rtc_device_register(&pdev->dev, pdev->name, &mxc_rtc_ops,
> +				     THIS_MODULE);
> +	if (IS_ERR(pdata->rtc)) {
> +		ret = PTR_ERR(pdata->rtc);
> +		goto exit_put_clk;
> +	}
> +
> +	tv.tv_nsec = 0;
> +	tv.tv_sec = __raw_readl(ioaddr + SRTC_LPSCMR);
> +
> +	/* By default, devices should wakeup if they can */
> +	/* So srtc is set as "should wakeup" as it can */
That comment is not formatted correctly.

> +	device_init_wakeup(&pdev->dev, 1);
> +
> +	return ret;

For clarity, this has to return 0.

> +
> +exit_put_clk:
> +	clk_disable_unprepare(pdata->clk);
> +	return ret;
> +}
> +
> +static int __exit mxc_rtc_remove(struct platform_device *pdev)
> +{
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +
> +	clk_disable_unprepare(pdata->clk);
> +	return 0;
> +}
> +
> +/*!
> + * This function is called to save the system time delta relative to
> + * the MXC RTC when enterring a low power state. This time delta is
> + * then used on resume to adjust the system time to account for time
> + * loss while suspended.
> + *
> + * @param   pdev  not used
> + * @param   state Power state to enter.
> + *
> + * @return  The function always returns 0.
> + */
> +static int mxc_rtc_suspend(struct platform_device *pdev, pm_message_t state)
> +{
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +
> +	if (device_may_wakeup(&pdev->dev))
> +		enable_irq_wake(pdata->irq);
> +
> +	return 0;
> +}
> +
> +/*!
> + * This function is called to correct the system time based on the
> + * current MXC RTC time relative to the time delta saved during
> + * suspend.
> + *
> + * @param   pdev  not used
> + *
> + * @return  The function always returns 0.
> + */
> +static int mxc_rtc_resume(struct platform_device *pdev)
> +{
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +
> +	if (device_may_wakeup(&pdev->dev))
> +		disable_irq_wake(pdata->irq);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id mxc_ids[] = {
> +	{.compatible = "fsl,imx53-rtc",},
> +	{}
> +};
> +
> +/*!
> + * Contains pointers to the power management callback functions.
> + */
> +static struct platform_driver mxc_rtc_driver = {
> +	.driver = {
> +		   .name = "mxc_rtc_v8",

Isn't it weird to have v8 here when the file is named v2?

> +		   .of_match_table = mxc_ids,
> +		   },
> +	.probe = mxc_rtc_probe,
> +	.remove = mxc_rtc_remove,
> +	.suspend = mxc_rtc_suspend,
> +	.resume = mxc_rtc_resume,
> +};
> +
> +module_platform_driver(mxc_rtc_driver);
> +
> +MODULE_AUTHOR("Freescale Semiconductor, Inc.");
> +MODULE_DESCRIPTION("Realtime Clock Driver (RTC)");
> +MODULE_LICENSE("GPL");
> -- 
> 2.11.0
> 
> 

-- 
Alexandre Belloni, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] rtc: add mxc driver for i.MX53
@ 2017-11-29 22:11   ` Alexandre Belloni
  0 siblings, 0 replies; 43+ messages in thread
From: Alexandre Belloni @ 2017-11-29 22:11 UTC (permalink / raw)
  To: linux-kernel-dev
  Cc: Alessandro Zummo, Patrick Bruenn, Rob Herring, Mark Rutland,
	open list:REAL TIME CLOCK (RTC) SUBSYSTEM,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	open list, Fabio Estevam, Juergen Borleis, Noel Vellemans,
	Shawn Guo, Sascha Hauer, Russell King,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE

Hi,

A really quick review:

On 28/11/2017 at 08:39:27 +0100, linux-kernel-dev@beckhoff.com wrote:
> From: Patrick Bruenn <p.bruenn@beckhoff.com>
> 
> Neither rtc-imxdi nor rtc-mxc are compatible with i.MX53.
> Add a modernized version of mxc_v2 from here:
> http://git.freescale.com/git/cgit.cgi/imx/linux-2.6-imx.git/tree/drivers/rtc/rtc-mxc_v2.c?h=imx_2.6.35_11.09.01
> 
> Changes to that version:
> - updated to v4.15-rc1
> - removed ioctl()
> - removed proc()
> - removed manual(redundant) enable_irq flag
> 

I'd say this doesn't add much information as this link is probably bound
to die at some point (especially seeing the NXP/Qualcomm/Broadcom
story).

> Signed-off-by: Patrick Bruenn <p.bruenn@beckhoff.com>
> 
> ---
> 
> Open issues:
> - driver naming, should it be merged with rtc-mxc.c ?

This seems different enough to be a separate driver.

> - document DT binding "fsl,imx53-rtc" accordingly

Yes, this has to be documented in a previous patch

> - Should unused defines be removed or kept for someone else to be
>   useful?

I don't care much, either are fine but the less lines, the easier the
reviews.

> - Is the use of __raw_readl/writel() correct? Should it be replaced with
>   readl/writel()?

The __raw version will not work if someone is running a BE kernel so
they should be moved to the _relaxed version or the usual readl/writel.

> - suspend/resume() seems different to existing rtc-mxc.c, should I apply
>   the pattern from rtc-mxc.c?

If you mean using SIMPLE_DEV_PM_OPS, yes, you should do that.

> - On Shawns tree imx53.dtsi has been reverted already[1][2]. Should I split
>   the imx53.dtsi change into a separate patch based on his tree? Or can
>   we still stop the full revert and just remove the imx25-rtc compatible?
>   I am not in a hurry, so we could just wait until the revert landed in
>   Linus tree. Whatever you think is best.
> 

I'm not taking DT changes through the RTC tree so it should be in a
separate patch that will go through Shawn's tree

You should also use checkpatch --strict, most of the warnings are
correct.


> [1] https://www.spinics.net/lists/arm-kernel/msg617113.html
> [2] commit ee76f7729babd2700afd6f3874449d8084dd85ea
> 
> To: Alessandro Zummo <a.zummo@towertech.it>
> To: Alexandre Belloni <alexandre.belloni@free-electrons.com>
> Cc: Rob Herring <robh+dt@kernel.org>
> Cc: Mark Rutland <mark.rutland@arm.com> (maintainer:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS)
> Cc: linux-rtc@vger.kernel.org (open list:REAL TIME CLOCK (RTC) SUBSYSTEM)
> Cc: devicetree@vger.kernel.org (open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS)
> Cc: linux-kernel@vger.kernel.org (open list)
> Cc: Fabio Estevam <fabio.estevam@nxp.com>
> Cc: Juergen Borleis <jbe@pengutronix.de>
> Cc: Noel Vellemans <Noel.Vellemans@visionbms.com>
> Cc: Shawn Guo <shawnguo@kernel.org>
> Cc: Sascha Hauer <kernel@pengutronix.de> (maintainer:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE)
> Cc: Russell King <linux@armlinux.org.uk> (maintainer:ARM PORT)
> Cc: linux-arm-kernel@lists.infradead.org (moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE)
> ---
>  arch/arm/boot/dts/imx53.dtsi |   2 +-
>  drivers/rtc/Makefile         |   1 +
>  drivers/rtc/rtc-mxc_v2.c     | 531 +++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 533 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/rtc/rtc-mxc_v2.c
> 
> diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi
> index 589a67c5f796..3d1a55e11ea8 100644
> --- a/arch/arm/boot/dts/imx53.dtsi
> +++ b/arch/arm/boot/dts/imx53.dtsi
> @@ -434,7 +434,7 @@
>  			};
>  
>  			srtc: srtc@53fa4000 {
> -				compatible = "fsl,imx53-rtc", "fsl,imx25-rtc";
> +				compatible = "fsl,imx53-rtc";
>  				reg = <0x53fa4000 0x4000>;
>  				interrupts = <24>;
>  				interrupt-parent = <&tzic>;
> diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
> index f2f50c11dc38..fb3dc458c185 100644
> --- a/drivers/rtc/Makefile
> +++ b/drivers/rtc/Makefile
> @@ -106,6 +106,7 @@ obj-$(CONFIG_RTC_DRV_MT6397)	+= rtc-mt6397.o
>  obj-$(CONFIG_RTC_DRV_MT7622)	+= rtc-mt7622.o
>  obj-$(CONFIG_RTC_DRV_MV)	+= rtc-mv.o
>  obj-$(CONFIG_RTC_DRV_MXC)	+= rtc-mxc.o
> +obj-$(CONFIG_RTC_DRV_MXC)	+= rtc-mxc_v2.o

This definitively needs a different Kconfig symbol.

>  obj-$(CONFIG_RTC_DRV_NUC900)	+= rtc-nuc900.o
>  obj-$(CONFIG_RTC_DRV_OMAP)	+= rtc-omap.o
>  obj-$(CONFIG_RTC_DRV_OPAL)	+= rtc-opal.o
> diff --git a/drivers/rtc/rtc-mxc_v2.c b/drivers/rtc/rtc-mxc_v2.c
> new file mode 100644
> index 000000000000..5049b521b38e
> --- /dev/null
> +++ b/drivers/rtc/rtc-mxc_v2.c
> @@ -0,0 +1,531 @@

I think SPDX identifier will soon be required on new files, please add
one.

> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights Reserved.
> + */
> +
> +/*
> + * The code contained herein is licensed under the GNU General Public
> + * License. You may obtain a copy of the GNU General Public License
> + * Version 2 or later at the following locations:
> + *
> + * http://www.opensource.org/licenses/gpl-license.html
> + * http://www.gnu.org/copyleft/gpl.html
> + */
> +/*
> + * Implementation based on rtc-ds1553.c
> + */
> +
> +/*!
> + * @defgroup RTC Real Time Clock (RTC) Driver for i.MX53
> + */
> +/*!
> + * @file rtc-mxc_v2.c
> + * @brief Real Time Clock interface
> + *
> + * This file contains Real Time Clock interface for Linux.
> + *
> + * @ingroup RTC
> + */
> +

Is that comment really useful?

> +#include <linux/slab.h>
> +#include <linux/delay.h>
> +#include <linux/rtc.h>
> +#include <linux/module.h>
> +#include <linux/fs.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/platform_device.h>
> +#include <linux/clk.h>
> +#include <linux/device.h>
> +#include <linux/uaccess.h>
> +#include <linux/io.h>

This should be in alphabetical order

> +//#include <linux/mxc_srtc.h>

This is not useful

> +#define RTC_READ_TIME_47BIT	_IOR('p', 0x20, unsigned long long)
> +/* blocks until LPSCMR is set, returns difference */
> +#define RTC_WAIT_TIME_SET	_IOR('p', 0x21, int64_t)
> +

Those ioctls are not used.

> +#define SRTC_LPSCLR_LLPSC_LSH	17	/* start bit for LSB time value */
> +
> +#define SRTC_LPPDR_INIT       0x41736166	/* init for glitch detect */
> +
> +#define SRTC_LPCR_SWR_LP      (1 << 0)	/* lp software reset */
> +#define SRTC_LPCR_EN_LP       (1 << 3)	/* lp enable */
> +#define SRTC_LPCR_WAE         (1 << 4)	/* lp wakeup alarm enable */
> +#define SRTC_LPCR_SAE         (1 << 5)	/* lp security alarm enable */
> +#define SRTC_LPCR_SI          (1 << 6)	/* lp security interrupt enable */
> +#define SRTC_LPCR_ALP         (1 << 7)	/* lp alarm flag */
> +#define SRTC_LPCR_LTC         (1 << 8)	/* lp lock time counter */
> +#define SRTC_LPCR_LMC         (1 << 9)	/* lp lock monotonic counter */
> +#define SRTC_LPCR_SV          (1 << 10)	/* lp security violation */
> +#define SRTC_LPCR_NSA         (1 << 11)	/* lp non secure access */
> +#define SRTC_LPCR_NVEIE       (1 << 12)	/* lp non valid state exit int en */
> +#define SRTC_LPCR_IEIE        (1 << 13)	/* lp init state exit int enable */
> +#define SRTC_LPCR_NVE         (1 << 14)	/* lp non valid state exit bit */
> +#define SRTC_LPCR_IE          (1 << 15)	/* lp init state exit bit */
> +
> +#define SRTC_LPCR_ALL_INT_EN (SRTC_LPCR_WAE | SRTC_LPCR_SAE | \
> +			      SRTC_LPCR_SI | SRTC_LPCR_ALP | \
> +			      SRTC_LPCR_NVEIE | SRTC_LPCR_IEIE)
> +
> +#define SRTC_LPSR_TRI         (1 << 0)	/* lp time read invalidate */
> +#define SRTC_LPSR_PGD         (1 << 1)	/* lp power supply glitc detected */
> +#define SRTC_LPSR_CTD         (1 << 2)	/* lp clock tampering detected */
> +#define SRTC_LPSR_ALP         (1 << 3)	/* lp alarm flag */
> +#define SRTC_LPSR_MR          (1 << 4)	/* lp monotonic counter rollover */
> +#define SRTC_LPSR_TR          (1 << 5)	/* lp time rollover */
> +#define SRTC_LPSR_EAD         (1 << 6)	/* lp external alarm detected */
> +#define SRTC_LPSR_IT0         (1 << 7)	/* lp IIM throttle */
> +#define SRTC_LPSR_IT1         (1 << 8)
> +#define SRTC_LPSR_IT2         (1 << 9)
> +#define SRTC_LPSR_SM0         (1 << 10)	/* lp security mode */
> +#define SRTC_LPSR_SM1         (1 << 11)
> +#define SRTC_LPSR_STATE_LP0   (1 << 12)	/* lp state */
> +#define SRTC_LPSR_STATE_LP1   (1 << 13)
> +#define SRTC_LPSR_NVES        (1 << 14)	/* lp non-valid state exit status */
> +#define SRTC_LPSR_IES         (1 << 15)	/* lp init state exit status */
> +
> +#define MAX_PIE_NUM     15
> +#define MAX_PIE_FREQ    32768
> +#define MIN_PIE_FREQ	1
> +
> +#define SRTC_PI0         (1 << 0)
> +#define SRTC_PI1         (1 << 1)
> +#define SRTC_PI2         (1 << 2)
> +#define SRTC_PI3         (1 << 3)
> +#define SRTC_PI4         (1 << 4)
> +#define SRTC_PI5         (1 << 5)
> +#define SRTC_PI6         (1 << 6)
> +#define SRTC_PI7         (1 << 7)
> +#define SRTC_PI8         (1 << 8)
> +#define SRTC_PI9         (1 << 9)
> +#define SRTC_PI10        (1 << 10)
> +#define SRTC_PI11        (1 << 11)
> +#define SRTC_PI12        (1 << 12)
> +#define SRTC_PI13        (1 << 13)
> +#define SRTC_PI14        (1 << 14)
> +#define SRTC_PI15        (1 << 15)
> +
> +#define PIT_ALL_ON      (SRTC_PI1 | SRTC_PI2 | SRTC_PI3 | \
> +			SRTC_PI4 | SRTC_PI5 | SRTC_PI6 | SRTC_PI7 | \
> +			SRTC_PI8 | SRTC_PI9 | SRTC_PI10 | SRTC_PI11 | \
> +			SRTC_PI12 | SRTC_PI13 | SRTC_PI14 | SRTC_PI15)
> +
> +#define SRTC_SWR_HP      (1 << 0)	/* hp software reset */
> +#define SRTC_EN_HP       (1 << 3)	/* hp enable */
> +#define SRTC_TS          (1 << 4)	/* time synchronize hp with lp */
> +
> +#define SRTC_IE_AHP      (1 << 16)	/* Alarm HP Interrupt Enable bit */
> +#define SRTC_IE_WDHP     (1 << 18)	/* Write Done HP Interrupt Enable bit */
> +#define SRTC_IE_WDLP     (1 << 19)	/* Write Done LP Interrupt Enable bit */
> +
> +#define SRTC_ISR_AHP     (1 << 16)	/* interrupt status: alarm hp */
> +#define SRTC_ISR_WDHP    (1 << 18)	/* interrupt status: write done hp */
> +#define SRTC_ISR_WDLP    (1 << 19)	/* interrupt status: write done lp */
> +#define SRTC_ISR_WPHP    (1 << 20)	/* interrupt status: write pending hp */
> +#define SRTC_ISR_WPLP    (1 << 21)	/* interrupt status: write pending lp */
> +
> +#define SRTC_LPSCMR	0x00	/* LP Secure Counter MSB Reg */
> +#define SRTC_LPSCLR	0x04	/* LP Secure Counter LSB Reg */
> +#define SRTC_LPSAR	0x08	/* LP Secure Alarm Reg */
> +#define SRTC_LPSMCR	0x0C	/* LP Secure Monotonic Counter Reg */
> +#define SRTC_LPCR	0x10	/* LP Control Reg */
> +#define SRTC_LPSR	0x14	/* LP Status Reg */
> +#define SRTC_LPPDR	0x18	/* LP Power Supply Glitch Detector Reg */
> +#define SRTC_LPGR	0x1C	/* LP General Purpose Reg */
> +#define SRTC_HPCMR	0x20	/* HP Counter MSB Reg */
> +#define SRTC_HPCLR	0x24	/* HP Counter LSB Reg */
> +#define SRTC_HPAMR	0x28	/* HP Alarm MSB Reg */
> +#define SRTC_HPALR	0x2C	/* HP Alarm LSB Reg */
> +#define SRTC_HPCR	0x30	/* HP Control Reg */
> +#define SRTC_HPISR	0x34	/* HP Interrupt Status Reg */
> +#define SRTC_HPIENR	0x38	/* HP Interrupt Enable Reg */
> +
> +#define SRTC_SECMODE_MASK	0x3	/* the mask of SRTC security mode */
> +#define SRTC_SECMODE_LOW	0x0	/* Low Security */
> +#define SRTC_SECMODE_MED	0x1	/* Medium Security */
> +#define SRTC_SECMODE_HIGH	0x2	/* High Security */
> +#define SRTC_SECMODE_RESERVED	0x3	/* Reserved */
> +
> +struct rtc_drv_data {
> +	struct rtc_device *rtc;
> +	void __iomem *ioaddr;
> +	int irq;
> +	struct clk *clk;
> +};
> +
> +static DEFINE_SPINLOCK(rtc_lock);
> +

Shouldn't that lock be part of rtc_drv_data?

> +/*!
> + * This function does write synchronization for writes to the lp srtc block.
> + * To take care of the asynchronous CKIL clock, all writes from the IP domain
> + * will be synchronized to the CKIL domain.
> + */
> +static inline void rtc_write_sync_lp(void __iomem *ioaddr)
> +{
> +	unsigned int i, count;
> +	/* Wait for 3 CKIL cycles */
> +	for (i = 0; i < 3; i++) {
> +		count = readl(ioaddr + SRTC_LPSCLR);
> +		while ((readl(ioaddr + SRTC_LPSCLR)) == count)
> +			;
> +	}
> +}
> +
> +/*!
> + * This function updates the RTC alarm registers and then clears all the
> + * interrupt status bits.
> + *
> + * @param  alrm         the new alarm value to be updated in the RTC
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int rtc_update_alarm(struct device *dev, struct rtc_time *alrm)
> +{
> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	void __iomem *ioaddr = pdata->ioaddr;
> +	struct rtc_time alarm_tm, now_tm;
> +	unsigned long now, time;
> +	int ret;
> +
> +	now = __raw_readl(ioaddr + SRTC_LPSCMR);
> +	rtc_time_to_tm(now, &now_tm);
> +
> +	alarm_tm.tm_year = now_tm.tm_year;
> +	alarm_tm.tm_mon = now_tm.tm_mon;
> +	alarm_tm.tm_mday = now_tm.tm_mday;
> +
> +	alarm_tm.tm_hour = alrm->tm_hour;
> +	alarm_tm.tm_min = alrm->tm_min;
> +	alarm_tm.tm_sec = alrm->tm_sec;
> +
> +	rtc_tm_to_time(&now_tm, &now);
> +	rtc_tm_to_time(&alarm_tm, &time);
> +
> +	if (time < now) {
> +		time += 60 * 60 * 24;
> +		rtc_time_to_tm(time, &alarm_tm);
> +	}
> +	ret = rtc_tm_to_time(&alarm_tm, &time);
> +
> +	__raw_writel(time, ioaddr + SRTC_LPSAR);
> +
> +	/* clear alarm interrupt status bit */
> +	__raw_writel(SRTC_LPSR_ALP, ioaddr + SRTC_LPSR);
> +
> +	return ret;
> +}
> +
> +/*!
> + * This function is the RTC interrupt service routine.
> + *
> + * @param  irq          RTC IRQ number
> + * @param  dev_id       device ID which is not used
> + *
> + * @return IRQ_HANDLED as defined in the include/linux/interrupt.h file.
> + */
> +static irqreturn_t mxc_rtc_interrupt(int irq, void *dev_id)
> +{
> +	struct platform_device *pdev = dev_id;
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +	void __iomem *ioaddr = pdata->ioaddr;
> +	u32 lp_status, lp_cr;
> +	u32 events = 0;
> +
> +	lp_status = __raw_readl(ioaddr + SRTC_LPSR);
> +	lp_cr = __raw_readl(ioaddr + SRTC_LPCR);
> +
> +	/* update irq data & counter */
> +	if (lp_status & SRTC_LPSR_ALP) {
> +		if (lp_cr & SRTC_LPCR_ALP)
> +			events |= (RTC_AF | RTC_IRQF);
> +
> +		/* disable further lp alarm interrupts */
> +		lp_cr &= ~(SRTC_LPCR_ALP | SRTC_LPCR_WAE);
> +	}
> +
> +	/* Update interrupt enables */
> +	__raw_writel(lp_cr, ioaddr + SRTC_LPCR);
> +
> +	/* clear interrupt status */
> +	__raw_writel(lp_status, ioaddr + SRTC_LPSR);
> +
> +	rtc_write_sync_lp(ioaddr);
> +	rtc_update_irq(pdata->rtc, 1, events);
> +	return IRQ_HANDLED;
> +}
> +
> +/*!
> + * This function reads the current RTC time into tm in Gregorian date.
> + *
> + * @param  tm           contains the RTC time value upon return
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int mxc_rtc_read_time(struct device *dev, struct rtc_time *tm)
> +{
> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	time_t now = readl(pdata->ioaddr + SRTC_LPSCMR);
> +
> +	rtc_time_to_tm(now, tm);
> +	return rtc_valid_tm(tm);
> +}
> +
> +/*!
> + * This function sets the internal RTC time based on tm in Gregorian date.
> + *
> + * @param  tm           the time value to be set in the RTC
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int mxc_rtc_set_time(struct device *dev, struct rtc_time *tm)
> +{
> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	time64_t time = rtc_tm_to_time64(tm);
> +
> +	if (time > UINT_MAX) {
> +		dev_warn(dev, "time_t has overflow\n");
> +	}
> +
> +	writel(time, pdata->ioaddr + SRTC_LPSCMR);
> +	rtc_write_sync_lp(pdata->ioaddr);
> +	return 0;
> +}
> +
> +/*!
> + * This function reads the current alarm value into the passed in \b alrm
> + * argument. It updates the \b alrm's pending field value based on the whether
> + * an alarm interrupt occurs or not.
> + *
> + * @param  alrm         contains the RTC alarm value upon return
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int mxc_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
> +{
> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	void __iomem *ioaddr = pdata->ioaddr;
> +
> +	rtc_time_to_tm(__raw_readl(ioaddr + SRTC_LPSAR), &alrm->time);
> +	alrm->pending =
> +	    ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_ALP) != 0) ? 1 : 0;
> +
> +	return 0;
> +}
> +
> +static int mxc_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
> +{
> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	unsigned long lock_flags = 0;
> +	u32 lp_cr;
> +
> +	spin_lock_irqsave(&rtc_lock, lock_flags);
> +	lp_cr = __raw_readl(pdata->ioaddr + SRTC_LPCR);
> +
> +	if (enable)
> +		lp_cr |= (SRTC_LPCR_ALP | SRTC_LPCR_WAE);
> +	else
> +		lp_cr &= ~(SRTC_LPCR_ALP | SRTC_LPCR_WAE);
> +
> +	__raw_writel(lp_cr, pdata->ioaddr + SRTC_LPCR);
> +	spin_unlock_irqrestore(&rtc_lock, lock_flags);
> +	return 0;
> +}
> +
> +/*!
> + * This function sets the RTC alarm based on passed in alrm.
> + *
> + * @param  alrm         the alarm value to be set in the RTC
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int mxc_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
> +{
> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	void __iomem *ioaddr = pdata->ioaddr;
> +	int ret;
> +
> +	ret = rtc_update_alarm(dev, &alrm->time);
> +	if (!ret)
> +		mxc_rtc_alarm_irq_enable(dev, alrm->enabled);
> +
> +	rtc_write_sync_lp(ioaddr);
> +	return ret;
> +}
> +
> +/*!
> + * The RTC driver structure
> + */
> +static const struct rtc_class_ops mxc_rtc_ops = {
> +	.read_time = mxc_rtc_read_time,
> +	.set_time = mxc_rtc_set_time,
> +	.read_alarm = mxc_rtc_read_alarm,
> +	.set_alarm = mxc_rtc_set_alarm,
> +	.alarm_irq_enable = mxc_rtc_alarm_irq_enable,
> +};
> +
> +/*! MXC RTC Power management control */

This comment is probably wrong ;)

> +static int mxc_rtc_probe(struct platform_device *pdev)
> +{
> +	struct timespec tv;
> +	struct resource *res;
> +	struct rtc_drv_data *pdata = NULL;
> +	void __iomem *ioaddr;
> +	int ret = 0;
> +
> +	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
> +	if (!pdata)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res)
> +		return -ENODEV;
> +
> +	pdata->ioaddr = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(pdata->ioaddr))
> +		return PTR_ERR(pdata->ioaddr);
> +
> +	ioaddr = pdata->ioaddr;
> +
> +	pdata->clk = devm_clk_get(&pdev->dev, NULL);
> +	if (IS_ERR(pdata->clk)) {
> +		dev_err(&pdev->dev, "unable to get rtc clock!\n");
> +		return PTR_ERR(pdata->clk);
> +	}
> +	ret = clk_prepare_enable(pdata->clk);
> +	if (ret)
> +		return ret;
> +
> +	/* Configure and enable the RTC */
> +	pdata->irq = platform_get_irq(pdev, 0);
> +	if (pdata->irq >= 0
> +	    && devm_request_irq(&pdev->dev, pdata->irq, mxc_rtc_interrupt,
> +				IRQF_SHARED, pdev->name, pdev) < 0) {
> +		dev_warn(&pdev->dev, "interrupt not available.\n");
> +		pdata->irq = -1;
> +	}
> +
> +	if (pdata->irq >= 0)
> +		device_init_wakeup(&pdev->dev, 1);
> +
> +	/* initialize glitch detect */
> +	__raw_writel(SRTC_LPPDR_INIT, ioaddr + SRTC_LPPDR);
> +	udelay(100);
> +
> +	/* clear lp interrupt status */
> +	__raw_writel(0xFFFFFFFF, ioaddr + SRTC_LPSR);
> +	udelay(100);
> +
> +	/* move out of init state */
> +	__raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NSA), ioaddr + SRTC_LPCR);
> +
> +	udelay(100);
> +
> +	while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_IES) == 0)
> +		;
> +
> +	/* move out of non-valid state */
> +	__raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NVE | SRTC_LPCR_NSA |
> +		      SRTC_LPCR_EN_LP), ioaddr + SRTC_LPCR);
> +
> +	udelay(100);
> +
> +	while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_NVES) == 0)
> +		;
> +
> +	__raw_writel(0xFFFFFFFF, ioaddr + SRTC_LPSR);
> +	udelay(100);
> +
> +	platform_set_drvdata(pdev, pdata);
> +	pdata->rtc =
> +	    devm_rtc_device_register(&pdev->dev, pdev->name, &mxc_rtc_ops,
> +				     THIS_MODULE);
> +	if (IS_ERR(pdata->rtc)) {
> +		ret = PTR_ERR(pdata->rtc);
> +		goto exit_put_clk;
> +	}
> +
> +	tv.tv_nsec = 0;
> +	tv.tv_sec = __raw_readl(ioaddr + SRTC_LPSCMR);
> +
> +	/* By default, devices should wakeup if they can */
> +	/* So srtc is set as "should wakeup" as it can */
That comment is not formatted correctly.

> +	device_init_wakeup(&pdev->dev, 1);
> +
> +	return ret;

For clarity, this has to return 0.

> +
> +exit_put_clk:
> +	clk_disable_unprepare(pdata->clk);
> +	return ret;
> +}
> +
> +static int __exit mxc_rtc_remove(struct platform_device *pdev)
> +{
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +
> +	clk_disable_unprepare(pdata->clk);
> +	return 0;
> +}
> +
> +/*!
> + * This function is called to save the system time delta relative to
> + * the MXC RTC when enterring a low power state. This time delta is
> + * then used on resume to adjust the system time to account for time
> + * loss while suspended.
> + *
> + * @param   pdev  not used
> + * @param   state Power state to enter.
> + *
> + * @return  The function always returns 0.
> + */
> +static int mxc_rtc_suspend(struct platform_device *pdev, pm_message_t state)
> +{
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +
> +	if (device_may_wakeup(&pdev->dev))
> +		enable_irq_wake(pdata->irq);
> +
> +	return 0;
> +}
> +
> +/*!
> + * This function is called to correct the system time based on the
> + * current MXC RTC time relative to the time delta saved during
> + * suspend.
> + *
> + * @param   pdev  not used
> + *
> + * @return  The function always returns 0.
> + */
> +static int mxc_rtc_resume(struct platform_device *pdev)
> +{
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +
> +	if (device_may_wakeup(&pdev->dev))
> +		disable_irq_wake(pdata->irq);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id mxc_ids[] = {
> +	{.compatible = "fsl,imx53-rtc",},
> +	{}
> +};
> +
> +/*!
> + * Contains pointers to the power management callback functions.
> + */
> +static struct platform_driver mxc_rtc_driver = {
> +	.driver = {
> +		   .name = "mxc_rtc_v8",

Isn't it weird to have v8 here when the file is named v2?

> +		   .of_match_table = mxc_ids,
> +		   },
> +	.probe = mxc_rtc_probe,
> +	.remove = mxc_rtc_remove,
> +	.suspend = mxc_rtc_suspend,
> +	.resume = mxc_rtc_resume,
> +};
> +
> +module_platform_driver(mxc_rtc_driver);
> +
> +MODULE_AUTHOR("Freescale Semiconductor, Inc.");
> +MODULE_DESCRIPTION("Realtime Clock Driver (RTC)");
> +MODULE_LICENSE("GPL");
> -- 
> 2.11.0
> 
> 

-- 
Alexandre Belloni, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] rtc: add mxc driver for i.MX53
@ 2017-11-29 22:11   ` Alexandre Belloni
  0 siblings, 0 replies; 43+ messages in thread
From: Alexandre Belloni @ 2017-11-29 22:11 UTC (permalink / raw)
  To: linux-kernel-dev-QonKdJ6Bx35Wk0Htik3J/w
  Cc: Alessandro Zummo, Patrick Bruenn, Rob Herring, Mark Rutland,
	open list:REAL TIME CLOCK (RTC) SUBSYSTEM,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	open list, Fabio Estevam, Juergen Borleis, Noel Vellemans,
	Shawn Guo, Sascha Hauer, Russell King,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE

Hi,

A really quick review:

On 28/11/2017 at 08:39:27 +0100, linux-kernel-dev-QonKdJ6Bx35Wk0Htik3J/w@public.gmane.org wrote:
> From: Patrick Bruenn <p.bruenn-QonKdJ6Bx35Wk0Htik3J/w@public.gmane.org>
> 
> Neither rtc-imxdi nor rtc-mxc are compatible with i.MX53.
> Add a modernized version of mxc_v2 from here:
> http://git.freescale.com/git/cgit.cgi/imx/linux-2.6-imx.git/tree/drivers/rtc/rtc-mxc_v2.c?h=imx_2.6.35_11.09.01
> 
> Changes to that version:
> - updated to v4.15-rc1
> - removed ioctl()
> - removed proc()
> - removed manual(redundant) enable_irq flag
> 

I'd say this doesn't add much information as this link is probably bound
to die at some point (especially seeing the NXP/Qualcomm/Broadcom
story).

> Signed-off-by: Patrick Bruenn <p.bruenn-QonKdJ6Bx35Wk0Htik3J/w@public.gmane.org>
> 
> ---
> 
> Open issues:
> - driver naming, should it be merged with rtc-mxc.c ?

This seems different enough to be a separate driver.

> - document DT binding "fsl,imx53-rtc" accordingly

Yes, this has to be documented in a previous patch

> - Should unused defines be removed or kept for someone else to be
>   useful?

I don't care much, either are fine but the less lines, the easier the
reviews.

> - Is the use of __raw_readl/writel() correct? Should it be replaced with
>   readl/writel()?

The __raw version will not work if someone is running a BE kernel so
they should be moved to the _relaxed version or the usual readl/writel.

> - suspend/resume() seems different to existing rtc-mxc.c, should I apply
>   the pattern from rtc-mxc.c?

If you mean using SIMPLE_DEV_PM_OPS, yes, you should do that.

> - On Shawns tree imx53.dtsi has been reverted already[1][2]. Should I split
>   the imx53.dtsi change into a separate patch based on his tree? Or can
>   we still stop the full revert and just remove the imx25-rtc compatible?
>   I am not in a hurry, so we could just wait until the revert landed in
>   Linus tree. Whatever you think is best.
> 

I'm not taking DT changes through the RTC tree so it should be in a
separate patch that will go through Shawn's tree

You should also use checkpatch --strict, most of the warnings are
correct.


> [1] https://www.spinics.net/lists/arm-kernel/msg617113.html
> [2] commit ee76f7729babd2700afd6f3874449d8084dd85ea
> 
> To: Alessandro Zummo <a.zummo-BfzFCNDTiLLj+vYz1yj4TQ@public.gmane.org>
> To: Alexandre Belloni <alexandre.belloni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> Cc: Rob Herring <robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> Cc: Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org> (maintainer:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS)
> Cc: linux-rtc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org (open list:REAL TIME CLOCK (RTC) SUBSYSTEM)
> Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org (open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS)
> Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org (open list)
> Cc: Fabio Estevam <fabio.estevam-3arQi8VN3Tc@public.gmane.org>
> Cc: Juergen Borleis <jbe-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
> Cc: Noel Vellemans <Noel.Vellemans-8UENEgx6w+makBO8gow8eQ@public.gmane.org>
> Cc: Shawn Guo <shawnguo-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> Cc: Sascha Hauer <kernel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org> (maintainer:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE)
> Cc: Russell King <linux-I+IVW8TIWO2tmTQ+vhA3Yw@public.gmane.org> (maintainer:ARM PORT)
> Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org (moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE)
> ---
>  arch/arm/boot/dts/imx53.dtsi |   2 +-
>  drivers/rtc/Makefile         |   1 +
>  drivers/rtc/rtc-mxc_v2.c     | 531 +++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 533 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/rtc/rtc-mxc_v2.c
> 
> diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi
> index 589a67c5f796..3d1a55e11ea8 100644
> --- a/arch/arm/boot/dts/imx53.dtsi
> +++ b/arch/arm/boot/dts/imx53.dtsi
> @@ -434,7 +434,7 @@
>  			};
>  
>  			srtc: srtc@53fa4000 {
> -				compatible = "fsl,imx53-rtc", "fsl,imx25-rtc";
> +				compatible = "fsl,imx53-rtc";
>  				reg = <0x53fa4000 0x4000>;
>  				interrupts = <24>;
>  				interrupt-parent = <&tzic>;
> diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
> index f2f50c11dc38..fb3dc458c185 100644
> --- a/drivers/rtc/Makefile
> +++ b/drivers/rtc/Makefile
> @@ -106,6 +106,7 @@ obj-$(CONFIG_RTC_DRV_MT6397)	+= rtc-mt6397.o
>  obj-$(CONFIG_RTC_DRV_MT7622)	+= rtc-mt7622.o
>  obj-$(CONFIG_RTC_DRV_MV)	+= rtc-mv.o
>  obj-$(CONFIG_RTC_DRV_MXC)	+= rtc-mxc.o
> +obj-$(CONFIG_RTC_DRV_MXC)	+= rtc-mxc_v2.o

This definitively needs a different Kconfig symbol.

>  obj-$(CONFIG_RTC_DRV_NUC900)	+= rtc-nuc900.o
>  obj-$(CONFIG_RTC_DRV_OMAP)	+= rtc-omap.o
>  obj-$(CONFIG_RTC_DRV_OPAL)	+= rtc-opal.o
> diff --git a/drivers/rtc/rtc-mxc_v2.c b/drivers/rtc/rtc-mxc_v2.c
> new file mode 100644
> index 000000000000..5049b521b38e
> --- /dev/null
> +++ b/drivers/rtc/rtc-mxc_v2.c
> @@ -0,0 +1,531 @@

I think SPDX identifier will soon be required on new files, please add
one.

> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights Reserved.
> + */
> +
> +/*
> + * The code contained herein is licensed under the GNU General Public
> + * License. You may obtain a copy of the GNU General Public License
> + * Version 2 or later at the following locations:
> + *
> + * http://www.opensource.org/licenses/gpl-license.html
> + * http://www.gnu.org/copyleft/gpl.html
> + */
> +/*
> + * Implementation based on rtc-ds1553.c
> + */
> +
> +/*!
> + * @defgroup RTC Real Time Clock (RTC) Driver for i.MX53
> + */
> +/*!
> + * @file rtc-mxc_v2.c
> + * @brief Real Time Clock interface
> + *
> + * This file contains Real Time Clock interface for Linux.
> + *
> + * @ingroup RTC
> + */
> +

Is that comment really useful?

> +#include <linux/slab.h>
> +#include <linux/delay.h>
> +#include <linux/rtc.h>
> +#include <linux/module.h>
> +#include <linux/fs.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/platform_device.h>
> +#include <linux/clk.h>
> +#include <linux/device.h>
> +#include <linux/uaccess.h>
> +#include <linux/io.h>

This should be in alphabetical order

> +//#include <linux/mxc_srtc.h>

This is not useful

> +#define RTC_READ_TIME_47BIT	_IOR('p', 0x20, unsigned long long)
> +/* blocks until LPSCMR is set, returns difference */
> +#define RTC_WAIT_TIME_SET	_IOR('p', 0x21, int64_t)
> +

Those ioctls are not used.

> +#define SRTC_LPSCLR_LLPSC_LSH	17	/* start bit for LSB time value */
> +
> +#define SRTC_LPPDR_INIT       0x41736166	/* init for glitch detect */
> +
> +#define SRTC_LPCR_SWR_LP      (1 << 0)	/* lp software reset */
> +#define SRTC_LPCR_EN_LP       (1 << 3)	/* lp enable */
> +#define SRTC_LPCR_WAE         (1 << 4)	/* lp wakeup alarm enable */
> +#define SRTC_LPCR_SAE         (1 << 5)	/* lp security alarm enable */
> +#define SRTC_LPCR_SI          (1 << 6)	/* lp security interrupt enable */
> +#define SRTC_LPCR_ALP         (1 << 7)	/* lp alarm flag */
> +#define SRTC_LPCR_LTC         (1 << 8)	/* lp lock time counter */
> +#define SRTC_LPCR_LMC         (1 << 9)	/* lp lock monotonic counter */
> +#define SRTC_LPCR_SV          (1 << 10)	/* lp security violation */
> +#define SRTC_LPCR_NSA         (1 << 11)	/* lp non secure access */
> +#define SRTC_LPCR_NVEIE       (1 << 12)	/* lp non valid state exit int en */
> +#define SRTC_LPCR_IEIE        (1 << 13)	/* lp init state exit int enable */
> +#define SRTC_LPCR_NVE         (1 << 14)	/* lp non valid state exit bit */
> +#define SRTC_LPCR_IE          (1 << 15)	/* lp init state exit bit */
> +
> +#define SRTC_LPCR_ALL_INT_EN (SRTC_LPCR_WAE | SRTC_LPCR_SAE | \
> +			      SRTC_LPCR_SI | SRTC_LPCR_ALP | \
> +			      SRTC_LPCR_NVEIE | SRTC_LPCR_IEIE)
> +
> +#define SRTC_LPSR_TRI         (1 << 0)	/* lp time read invalidate */
> +#define SRTC_LPSR_PGD         (1 << 1)	/* lp power supply glitc detected */
> +#define SRTC_LPSR_CTD         (1 << 2)	/* lp clock tampering detected */
> +#define SRTC_LPSR_ALP         (1 << 3)	/* lp alarm flag */
> +#define SRTC_LPSR_MR          (1 << 4)	/* lp monotonic counter rollover */
> +#define SRTC_LPSR_TR          (1 << 5)	/* lp time rollover */
> +#define SRTC_LPSR_EAD         (1 << 6)	/* lp external alarm detected */
> +#define SRTC_LPSR_IT0         (1 << 7)	/* lp IIM throttle */
> +#define SRTC_LPSR_IT1         (1 << 8)
> +#define SRTC_LPSR_IT2         (1 << 9)
> +#define SRTC_LPSR_SM0         (1 << 10)	/* lp security mode */
> +#define SRTC_LPSR_SM1         (1 << 11)
> +#define SRTC_LPSR_STATE_LP0   (1 << 12)	/* lp state */
> +#define SRTC_LPSR_STATE_LP1   (1 << 13)
> +#define SRTC_LPSR_NVES        (1 << 14)	/* lp non-valid state exit status */
> +#define SRTC_LPSR_IES         (1 << 15)	/* lp init state exit status */
> +
> +#define MAX_PIE_NUM     15
> +#define MAX_PIE_FREQ    32768
> +#define MIN_PIE_FREQ	1
> +
> +#define SRTC_PI0         (1 << 0)
> +#define SRTC_PI1         (1 << 1)
> +#define SRTC_PI2         (1 << 2)
> +#define SRTC_PI3         (1 << 3)
> +#define SRTC_PI4         (1 << 4)
> +#define SRTC_PI5         (1 << 5)
> +#define SRTC_PI6         (1 << 6)
> +#define SRTC_PI7         (1 << 7)
> +#define SRTC_PI8         (1 << 8)
> +#define SRTC_PI9         (1 << 9)
> +#define SRTC_PI10        (1 << 10)
> +#define SRTC_PI11        (1 << 11)
> +#define SRTC_PI12        (1 << 12)
> +#define SRTC_PI13        (1 << 13)
> +#define SRTC_PI14        (1 << 14)
> +#define SRTC_PI15        (1 << 15)
> +
> +#define PIT_ALL_ON      (SRTC_PI1 | SRTC_PI2 | SRTC_PI3 | \
> +			SRTC_PI4 | SRTC_PI5 | SRTC_PI6 | SRTC_PI7 | \
> +			SRTC_PI8 | SRTC_PI9 | SRTC_PI10 | SRTC_PI11 | \
> +			SRTC_PI12 | SRTC_PI13 | SRTC_PI14 | SRTC_PI15)
> +
> +#define SRTC_SWR_HP      (1 << 0)	/* hp software reset */
> +#define SRTC_EN_HP       (1 << 3)	/* hp enable */
> +#define SRTC_TS          (1 << 4)	/* time synchronize hp with lp */
> +
> +#define SRTC_IE_AHP      (1 << 16)	/* Alarm HP Interrupt Enable bit */
> +#define SRTC_IE_WDHP     (1 << 18)	/* Write Done HP Interrupt Enable bit */
> +#define SRTC_IE_WDLP     (1 << 19)	/* Write Done LP Interrupt Enable bit */
> +
> +#define SRTC_ISR_AHP     (1 << 16)	/* interrupt status: alarm hp */
> +#define SRTC_ISR_WDHP    (1 << 18)	/* interrupt status: write done hp */
> +#define SRTC_ISR_WDLP    (1 << 19)	/* interrupt status: write done lp */
> +#define SRTC_ISR_WPHP    (1 << 20)	/* interrupt status: write pending hp */
> +#define SRTC_ISR_WPLP    (1 << 21)	/* interrupt status: write pending lp */
> +
> +#define SRTC_LPSCMR	0x00	/* LP Secure Counter MSB Reg */
> +#define SRTC_LPSCLR	0x04	/* LP Secure Counter LSB Reg */
> +#define SRTC_LPSAR	0x08	/* LP Secure Alarm Reg */
> +#define SRTC_LPSMCR	0x0C	/* LP Secure Monotonic Counter Reg */
> +#define SRTC_LPCR	0x10	/* LP Control Reg */
> +#define SRTC_LPSR	0x14	/* LP Status Reg */
> +#define SRTC_LPPDR	0x18	/* LP Power Supply Glitch Detector Reg */
> +#define SRTC_LPGR	0x1C	/* LP General Purpose Reg */
> +#define SRTC_HPCMR	0x20	/* HP Counter MSB Reg */
> +#define SRTC_HPCLR	0x24	/* HP Counter LSB Reg */
> +#define SRTC_HPAMR	0x28	/* HP Alarm MSB Reg */
> +#define SRTC_HPALR	0x2C	/* HP Alarm LSB Reg */
> +#define SRTC_HPCR	0x30	/* HP Control Reg */
> +#define SRTC_HPISR	0x34	/* HP Interrupt Status Reg */
> +#define SRTC_HPIENR	0x38	/* HP Interrupt Enable Reg */
> +
> +#define SRTC_SECMODE_MASK	0x3	/* the mask of SRTC security mode */
> +#define SRTC_SECMODE_LOW	0x0	/* Low Security */
> +#define SRTC_SECMODE_MED	0x1	/* Medium Security */
> +#define SRTC_SECMODE_HIGH	0x2	/* High Security */
> +#define SRTC_SECMODE_RESERVED	0x3	/* Reserved */
> +
> +struct rtc_drv_data {
> +	struct rtc_device *rtc;
> +	void __iomem *ioaddr;
> +	int irq;
> +	struct clk *clk;
> +};
> +
> +static DEFINE_SPINLOCK(rtc_lock);
> +

Shouldn't that lock be part of rtc_drv_data?

> +/*!
> + * This function does write synchronization for writes to the lp srtc block.
> + * To take care of the asynchronous CKIL clock, all writes from the IP domain
> + * will be synchronized to the CKIL domain.
> + */
> +static inline void rtc_write_sync_lp(void __iomem *ioaddr)
> +{
> +	unsigned int i, count;
> +	/* Wait for 3 CKIL cycles */
> +	for (i = 0; i < 3; i++) {
> +		count = readl(ioaddr + SRTC_LPSCLR);
> +		while ((readl(ioaddr + SRTC_LPSCLR)) == count)
> +			;
> +	}
> +}
> +
> +/*!
> + * This function updates the RTC alarm registers and then clears all the
> + * interrupt status bits.
> + *
> + * @param  alrm         the new alarm value to be updated in the RTC
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int rtc_update_alarm(struct device *dev, struct rtc_time *alrm)
> +{
> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	void __iomem *ioaddr = pdata->ioaddr;
> +	struct rtc_time alarm_tm, now_tm;
> +	unsigned long now, time;
> +	int ret;
> +
> +	now = __raw_readl(ioaddr + SRTC_LPSCMR);
> +	rtc_time_to_tm(now, &now_tm);
> +
> +	alarm_tm.tm_year = now_tm.tm_year;
> +	alarm_tm.tm_mon = now_tm.tm_mon;
> +	alarm_tm.tm_mday = now_tm.tm_mday;
> +
> +	alarm_tm.tm_hour = alrm->tm_hour;
> +	alarm_tm.tm_min = alrm->tm_min;
> +	alarm_tm.tm_sec = alrm->tm_sec;
> +
> +	rtc_tm_to_time(&now_tm, &now);
> +	rtc_tm_to_time(&alarm_tm, &time);
> +
> +	if (time < now) {
> +		time += 60 * 60 * 24;
> +		rtc_time_to_tm(time, &alarm_tm);
> +	}
> +	ret = rtc_tm_to_time(&alarm_tm, &time);
> +
> +	__raw_writel(time, ioaddr + SRTC_LPSAR);
> +
> +	/* clear alarm interrupt status bit */
> +	__raw_writel(SRTC_LPSR_ALP, ioaddr + SRTC_LPSR);
> +
> +	return ret;
> +}
> +
> +/*!
> + * This function is the RTC interrupt service routine.
> + *
> + * @param  irq          RTC IRQ number
> + * @param  dev_id       device ID which is not used
> + *
> + * @return IRQ_HANDLED as defined in the include/linux/interrupt.h file.
> + */
> +static irqreturn_t mxc_rtc_interrupt(int irq, void *dev_id)
> +{
> +	struct platform_device *pdev = dev_id;
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +	void __iomem *ioaddr = pdata->ioaddr;
> +	u32 lp_status, lp_cr;
> +	u32 events = 0;
> +
> +	lp_status = __raw_readl(ioaddr + SRTC_LPSR);
> +	lp_cr = __raw_readl(ioaddr + SRTC_LPCR);
> +
> +	/* update irq data & counter */
> +	if (lp_status & SRTC_LPSR_ALP) {
> +		if (lp_cr & SRTC_LPCR_ALP)
> +			events |= (RTC_AF | RTC_IRQF);
> +
> +		/* disable further lp alarm interrupts */
> +		lp_cr &= ~(SRTC_LPCR_ALP | SRTC_LPCR_WAE);
> +	}
> +
> +	/* Update interrupt enables */
> +	__raw_writel(lp_cr, ioaddr + SRTC_LPCR);
> +
> +	/* clear interrupt status */
> +	__raw_writel(lp_status, ioaddr + SRTC_LPSR);
> +
> +	rtc_write_sync_lp(ioaddr);
> +	rtc_update_irq(pdata->rtc, 1, events);
> +	return IRQ_HANDLED;
> +}
> +
> +/*!
> + * This function reads the current RTC time into tm in Gregorian date.
> + *
> + * @param  tm           contains the RTC time value upon return
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int mxc_rtc_read_time(struct device *dev, struct rtc_time *tm)
> +{
> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	time_t now = readl(pdata->ioaddr + SRTC_LPSCMR);
> +
> +	rtc_time_to_tm(now, tm);
> +	return rtc_valid_tm(tm);
> +}
> +
> +/*!
> + * This function sets the internal RTC time based on tm in Gregorian date.
> + *
> + * @param  tm           the time value to be set in the RTC
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int mxc_rtc_set_time(struct device *dev, struct rtc_time *tm)
> +{
> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	time64_t time = rtc_tm_to_time64(tm);
> +
> +	if (time > UINT_MAX) {
> +		dev_warn(dev, "time_t has overflow\n");
> +	}
> +
> +	writel(time, pdata->ioaddr + SRTC_LPSCMR);
> +	rtc_write_sync_lp(pdata->ioaddr);
> +	return 0;
> +}
> +
> +/*!
> + * This function reads the current alarm value into the passed in \b alrm
> + * argument. It updates the \b alrm's pending field value based on the whether
> + * an alarm interrupt occurs or not.
> + *
> + * @param  alrm         contains the RTC alarm value upon return
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int mxc_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
> +{
> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	void __iomem *ioaddr = pdata->ioaddr;
> +
> +	rtc_time_to_tm(__raw_readl(ioaddr + SRTC_LPSAR), &alrm->time);
> +	alrm->pending =
> +	    ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_ALP) != 0) ? 1 : 0;
> +
> +	return 0;
> +}
> +
> +static int mxc_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
> +{
> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	unsigned long lock_flags = 0;
> +	u32 lp_cr;
> +
> +	spin_lock_irqsave(&rtc_lock, lock_flags);
> +	lp_cr = __raw_readl(pdata->ioaddr + SRTC_LPCR);
> +
> +	if (enable)
> +		lp_cr |= (SRTC_LPCR_ALP | SRTC_LPCR_WAE);
> +	else
> +		lp_cr &= ~(SRTC_LPCR_ALP | SRTC_LPCR_WAE);
> +
> +	__raw_writel(lp_cr, pdata->ioaddr + SRTC_LPCR);
> +	spin_unlock_irqrestore(&rtc_lock, lock_flags);
> +	return 0;
> +}
> +
> +/*!
> + * This function sets the RTC alarm based on passed in alrm.
> + *
> + * @param  alrm         the alarm value to be set in the RTC
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int mxc_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
> +{
> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	void __iomem *ioaddr = pdata->ioaddr;
> +	int ret;
> +
> +	ret = rtc_update_alarm(dev, &alrm->time);
> +	if (!ret)
> +		mxc_rtc_alarm_irq_enable(dev, alrm->enabled);
> +
> +	rtc_write_sync_lp(ioaddr);
> +	return ret;
> +}
> +
> +/*!
> + * The RTC driver structure
> + */
> +static const struct rtc_class_ops mxc_rtc_ops = {
> +	.read_time = mxc_rtc_read_time,
> +	.set_time = mxc_rtc_set_time,
> +	.read_alarm = mxc_rtc_read_alarm,
> +	.set_alarm = mxc_rtc_set_alarm,
> +	.alarm_irq_enable = mxc_rtc_alarm_irq_enable,
> +};
> +
> +/*! MXC RTC Power management control */

This comment is probably wrong ;)

> +static int mxc_rtc_probe(struct platform_device *pdev)
> +{
> +	struct timespec tv;
> +	struct resource *res;
> +	struct rtc_drv_data *pdata = NULL;
> +	void __iomem *ioaddr;
> +	int ret = 0;
> +
> +	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
> +	if (!pdata)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res)
> +		return -ENODEV;
> +
> +	pdata->ioaddr = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(pdata->ioaddr))
> +		return PTR_ERR(pdata->ioaddr);
> +
> +	ioaddr = pdata->ioaddr;
> +
> +	pdata->clk = devm_clk_get(&pdev->dev, NULL);
> +	if (IS_ERR(pdata->clk)) {
> +		dev_err(&pdev->dev, "unable to get rtc clock!\n");
> +		return PTR_ERR(pdata->clk);
> +	}
> +	ret = clk_prepare_enable(pdata->clk);
> +	if (ret)
> +		return ret;
> +
> +	/* Configure and enable the RTC */
> +	pdata->irq = platform_get_irq(pdev, 0);
> +	if (pdata->irq >= 0
> +	    && devm_request_irq(&pdev->dev, pdata->irq, mxc_rtc_interrupt,
> +				IRQF_SHARED, pdev->name, pdev) < 0) {
> +		dev_warn(&pdev->dev, "interrupt not available.\n");
> +		pdata->irq = -1;
> +	}
> +
> +	if (pdata->irq >= 0)
> +		device_init_wakeup(&pdev->dev, 1);
> +
> +	/* initialize glitch detect */
> +	__raw_writel(SRTC_LPPDR_INIT, ioaddr + SRTC_LPPDR);
> +	udelay(100);
> +
> +	/* clear lp interrupt status */
> +	__raw_writel(0xFFFFFFFF, ioaddr + SRTC_LPSR);
> +	udelay(100);
> +
> +	/* move out of init state */
> +	__raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NSA), ioaddr + SRTC_LPCR);
> +
> +	udelay(100);
> +
> +	while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_IES) == 0)
> +		;
> +
> +	/* move out of non-valid state */
> +	__raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NVE | SRTC_LPCR_NSA |
> +		      SRTC_LPCR_EN_LP), ioaddr + SRTC_LPCR);
> +
> +	udelay(100);
> +
> +	while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_NVES) == 0)
> +		;
> +
> +	__raw_writel(0xFFFFFFFF, ioaddr + SRTC_LPSR);
> +	udelay(100);
> +
> +	platform_set_drvdata(pdev, pdata);
> +	pdata->rtc =
> +	    devm_rtc_device_register(&pdev->dev, pdev->name, &mxc_rtc_ops,
> +				     THIS_MODULE);
> +	if (IS_ERR(pdata->rtc)) {
> +		ret = PTR_ERR(pdata->rtc);
> +		goto exit_put_clk;
> +	}
> +
> +	tv.tv_nsec = 0;
> +	tv.tv_sec = __raw_readl(ioaddr + SRTC_LPSCMR);
> +
> +	/* By default, devices should wakeup if they can */
> +	/* So srtc is set as "should wakeup" as it can */
That comment is not formatted correctly.

> +	device_init_wakeup(&pdev->dev, 1);
> +
> +	return ret;

For clarity, this has to return 0.

> +
> +exit_put_clk:
> +	clk_disable_unprepare(pdata->clk);
> +	return ret;
> +}
> +
> +static int __exit mxc_rtc_remove(struct platform_device *pdev)
> +{
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +
> +	clk_disable_unprepare(pdata->clk);
> +	return 0;
> +}
> +
> +/*!
> + * This function is called to save the system time delta relative to
> + * the MXC RTC when enterring a low power state. This time delta is
> + * then used on resume to adjust the system time to account for time
> + * loss while suspended.
> + *
> + * @param   pdev  not used
> + * @param   state Power state to enter.
> + *
> + * @return  The function always returns 0.
> + */
> +static int mxc_rtc_suspend(struct platform_device *pdev, pm_message_t state)
> +{
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +
> +	if (device_may_wakeup(&pdev->dev))
> +		enable_irq_wake(pdata->irq);
> +
> +	return 0;
> +}
> +
> +/*!
> + * This function is called to correct the system time based on the
> + * current MXC RTC time relative to the time delta saved during
> + * suspend.
> + *
> + * @param   pdev  not used
> + *
> + * @return  The function always returns 0.
> + */
> +static int mxc_rtc_resume(struct platform_device *pdev)
> +{
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +
> +	if (device_may_wakeup(&pdev->dev))
> +		disable_irq_wake(pdata->irq);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id mxc_ids[] = {
> +	{.compatible = "fsl,imx53-rtc",},
> +	{}
> +};
> +
> +/*!
> + * Contains pointers to the power management callback functions.
> + */
> +static struct platform_driver mxc_rtc_driver = {
> +	.driver = {
> +		   .name = "mxc_rtc_v8",

Isn't it weird to have v8 here when the file is named v2?

> +		   .of_match_table = mxc_ids,
> +		   },
> +	.probe = mxc_rtc_probe,
> +	.remove = mxc_rtc_remove,
> +	.suspend = mxc_rtc_suspend,
> +	.resume = mxc_rtc_resume,
> +};
> +
> +module_platform_driver(mxc_rtc_driver);
> +
> +MODULE_AUTHOR("Freescale Semiconductor, Inc.");
> +MODULE_DESCRIPTION("Realtime Clock Driver (RTC)");
> +MODULE_LICENSE("GPL");
> -- 
> 2.11.0
> 
> 

-- 
Alexandre Belloni, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH] rtc: add mxc driver for i.MX53
@ 2017-11-29 22:11   ` Alexandre Belloni
  0 siblings, 0 replies; 43+ messages in thread
From: Alexandre Belloni @ 2017-11-29 22:11 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

A really quick review:

On 28/11/2017 at 08:39:27 +0100, linux-kernel-dev at beckhoff.com wrote:
> From: Patrick Bruenn <p.bruenn@beckhoff.com>
> 
> Neither rtc-imxdi nor rtc-mxc are compatible with i.MX53.
> Add a modernized version of mxc_v2 from here:
> http://git.freescale.com/git/cgit.cgi/imx/linux-2.6-imx.git/tree/drivers/rtc/rtc-mxc_v2.c?h=imx_2.6.35_11.09.01
> 
> Changes to that version:
> - updated to v4.15-rc1
> - removed ioctl()
> - removed proc()
> - removed manual(redundant) enable_irq flag
> 

I'd say this doesn't add much information as this link is probably bound
to die at some point (especially seeing the NXP/Qualcomm/Broadcom
story).

> Signed-off-by: Patrick Bruenn <p.bruenn@beckhoff.com>
> 
> ---
> 
> Open issues:
> - driver naming, should it be merged with rtc-mxc.c ?

This seems different enough to be a separate driver.

> - document DT binding "fsl,imx53-rtc" accordingly

Yes, this has to be documented in a previous patch

> - Should unused defines be removed or kept for someone else to be
>   useful?

I don't care much, either are fine but the less lines, the easier the
reviews.

> - Is the use of __raw_readl/writel() correct? Should it be replaced with
>   readl/writel()?

The __raw version will not work if someone is running a BE kernel so
they should be moved to the _relaxed version or the usual readl/writel.

> - suspend/resume() seems different to existing rtc-mxc.c, should I apply
>   the pattern from rtc-mxc.c?

If you mean using SIMPLE_DEV_PM_OPS, yes, you should do that.

> - On Shawns tree imx53.dtsi has been reverted already[1][2]. Should I split
>   the imx53.dtsi change into a separate patch based on his tree? Or can
>   we still stop the full revert and just remove the imx25-rtc compatible?
>   I am not in a hurry, so we could just wait until the revert landed in
>   Linus tree. Whatever you think is best.
> 

I'm not taking DT changes through the RTC tree so it should be in a
separate patch that will go through Shawn's tree

You should also use checkpatch --strict, most of the warnings are
correct.


> [1] https://www.spinics.net/lists/arm-kernel/msg617113.html
> [2] commit ee76f7729babd2700afd6f3874449d8084dd85ea
> 
> To: Alessandro Zummo <a.zummo@towertech.it>
> To: Alexandre Belloni <alexandre.belloni@free-electrons.com>
> Cc: Rob Herring <robh+dt@kernel.org>
> Cc: Mark Rutland <mark.rutland@arm.com> (maintainer:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS)
> Cc: linux-rtc at vger.kernel.org (open list:REAL TIME CLOCK (RTC) SUBSYSTEM)
> Cc: devicetree at vger.kernel.org (open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS)
> Cc: linux-kernel at vger.kernel.org (open list)
> Cc: Fabio Estevam <fabio.estevam@nxp.com>
> Cc: Juergen Borleis <jbe@pengutronix.de>
> Cc: Noel Vellemans <Noel.Vellemans@visionbms.com>
> Cc: Shawn Guo <shawnguo@kernel.org>
> Cc: Sascha Hauer <kernel@pengutronix.de> (maintainer:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE)
> Cc: Russell King <linux@armlinux.org.uk> (maintainer:ARM PORT)
> Cc: linux-arm-kernel at lists.infradead.org (moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE)
> ---
>  arch/arm/boot/dts/imx53.dtsi |   2 +-
>  drivers/rtc/Makefile         |   1 +
>  drivers/rtc/rtc-mxc_v2.c     | 531 +++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 533 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/rtc/rtc-mxc_v2.c
> 
> diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi
> index 589a67c5f796..3d1a55e11ea8 100644
> --- a/arch/arm/boot/dts/imx53.dtsi
> +++ b/arch/arm/boot/dts/imx53.dtsi
> @@ -434,7 +434,7 @@
>  			};
>  
>  			srtc: srtc at 53fa4000 {
> -				compatible = "fsl,imx53-rtc", "fsl,imx25-rtc";
> +				compatible = "fsl,imx53-rtc";
>  				reg = <0x53fa4000 0x4000>;
>  				interrupts = <24>;
>  				interrupt-parent = <&tzic>;
> diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
> index f2f50c11dc38..fb3dc458c185 100644
> --- a/drivers/rtc/Makefile
> +++ b/drivers/rtc/Makefile
> @@ -106,6 +106,7 @@ obj-$(CONFIG_RTC_DRV_MT6397)	+= rtc-mt6397.o
>  obj-$(CONFIG_RTC_DRV_MT7622)	+= rtc-mt7622.o
>  obj-$(CONFIG_RTC_DRV_MV)	+= rtc-mv.o
>  obj-$(CONFIG_RTC_DRV_MXC)	+= rtc-mxc.o
> +obj-$(CONFIG_RTC_DRV_MXC)	+= rtc-mxc_v2.o

This definitively needs a different Kconfig symbol.

>  obj-$(CONFIG_RTC_DRV_NUC900)	+= rtc-nuc900.o
>  obj-$(CONFIG_RTC_DRV_OMAP)	+= rtc-omap.o
>  obj-$(CONFIG_RTC_DRV_OPAL)	+= rtc-opal.o
> diff --git a/drivers/rtc/rtc-mxc_v2.c b/drivers/rtc/rtc-mxc_v2.c
> new file mode 100644
> index 000000000000..5049b521b38e
> --- /dev/null
> +++ b/drivers/rtc/rtc-mxc_v2.c
> @@ -0,0 +1,531 @@

I think SPDX identifier will soon be required on new files, please add
one.

> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights Reserved.
> + */
> +
> +/*
> + * The code contained herein is licensed under the GNU General Public
> + * License. You may obtain a copy of the GNU General Public License
> + * Version 2 or later at the following locations:
> + *
> + * http://www.opensource.org/licenses/gpl-license.html
> + * http://www.gnu.org/copyleft/gpl.html
> + */
> +/*
> + * Implementation based on rtc-ds1553.c
> + */
> +
> +/*!
> + * @defgroup RTC Real Time Clock (RTC) Driver for i.MX53
> + */
> +/*!
> + * @file rtc-mxc_v2.c
> + * @brief Real Time Clock interface
> + *
> + * This file contains Real Time Clock interface for Linux.
> + *
> + * @ingroup RTC
> + */
> +

Is that comment really useful?

> +#include <linux/slab.h>
> +#include <linux/delay.h>
> +#include <linux/rtc.h>
> +#include <linux/module.h>
> +#include <linux/fs.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/platform_device.h>
> +#include <linux/clk.h>
> +#include <linux/device.h>
> +#include <linux/uaccess.h>
> +#include <linux/io.h>

This should be in alphabetical order

> +//#include <linux/mxc_srtc.h>

This is not useful

> +#define RTC_READ_TIME_47BIT	_IOR('p', 0x20, unsigned long long)
> +/* blocks until LPSCMR is set, returns difference */
> +#define RTC_WAIT_TIME_SET	_IOR('p', 0x21, int64_t)
> +

Those ioctls are not used.

> +#define SRTC_LPSCLR_LLPSC_LSH	17	/* start bit for LSB time value */
> +
> +#define SRTC_LPPDR_INIT       0x41736166	/* init for glitch detect */
> +
> +#define SRTC_LPCR_SWR_LP      (1 << 0)	/* lp software reset */
> +#define SRTC_LPCR_EN_LP       (1 << 3)	/* lp enable */
> +#define SRTC_LPCR_WAE         (1 << 4)	/* lp wakeup alarm enable */
> +#define SRTC_LPCR_SAE         (1 << 5)	/* lp security alarm enable */
> +#define SRTC_LPCR_SI          (1 << 6)	/* lp security interrupt enable */
> +#define SRTC_LPCR_ALP         (1 << 7)	/* lp alarm flag */
> +#define SRTC_LPCR_LTC         (1 << 8)	/* lp lock time counter */
> +#define SRTC_LPCR_LMC         (1 << 9)	/* lp lock monotonic counter */
> +#define SRTC_LPCR_SV          (1 << 10)	/* lp security violation */
> +#define SRTC_LPCR_NSA         (1 << 11)	/* lp non secure access */
> +#define SRTC_LPCR_NVEIE       (1 << 12)	/* lp non valid state exit int en */
> +#define SRTC_LPCR_IEIE        (1 << 13)	/* lp init state exit int enable */
> +#define SRTC_LPCR_NVE         (1 << 14)	/* lp non valid state exit bit */
> +#define SRTC_LPCR_IE          (1 << 15)	/* lp init state exit bit */
> +
> +#define SRTC_LPCR_ALL_INT_EN (SRTC_LPCR_WAE | SRTC_LPCR_SAE | \
> +			      SRTC_LPCR_SI | SRTC_LPCR_ALP | \
> +			      SRTC_LPCR_NVEIE | SRTC_LPCR_IEIE)
> +
> +#define SRTC_LPSR_TRI         (1 << 0)	/* lp time read invalidate */
> +#define SRTC_LPSR_PGD         (1 << 1)	/* lp power supply glitc detected */
> +#define SRTC_LPSR_CTD         (1 << 2)	/* lp clock tampering detected */
> +#define SRTC_LPSR_ALP         (1 << 3)	/* lp alarm flag */
> +#define SRTC_LPSR_MR          (1 << 4)	/* lp monotonic counter rollover */
> +#define SRTC_LPSR_TR          (1 << 5)	/* lp time rollover */
> +#define SRTC_LPSR_EAD         (1 << 6)	/* lp external alarm detected */
> +#define SRTC_LPSR_IT0         (1 << 7)	/* lp IIM throttle */
> +#define SRTC_LPSR_IT1         (1 << 8)
> +#define SRTC_LPSR_IT2         (1 << 9)
> +#define SRTC_LPSR_SM0         (1 << 10)	/* lp security mode */
> +#define SRTC_LPSR_SM1         (1 << 11)
> +#define SRTC_LPSR_STATE_LP0   (1 << 12)	/* lp state */
> +#define SRTC_LPSR_STATE_LP1   (1 << 13)
> +#define SRTC_LPSR_NVES        (1 << 14)	/* lp non-valid state exit status */
> +#define SRTC_LPSR_IES         (1 << 15)	/* lp init state exit status */
> +
> +#define MAX_PIE_NUM     15
> +#define MAX_PIE_FREQ    32768
> +#define MIN_PIE_FREQ	1
> +
> +#define SRTC_PI0         (1 << 0)
> +#define SRTC_PI1         (1 << 1)
> +#define SRTC_PI2         (1 << 2)
> +#define SRTC_PI3         (1 << 3)
> +#define SRTC_PI4         (1 << 4)
> +#define SRTC_PI5         (1 << 5)
> +#define SRTC_PI6         (1 << 6)
> +#define SRTC_PI7         (1 << 7)
> +#define SRTC_PI8         (1 << 8)
> +#define SRTC_PI9         (1 << 9)
> +#define SRTC_PI10        (1 << 10)
> +#define SRTC_PI11        (1 << 11)
> +#define SRTC_PI12        (1 << 12)
> +#define SRTC_PI13        (1 << 13)
> +#define SRTC_PI14        (1 << 14)
> +#define SRTC_PI15        (1 << 15)
> +
> +#define PIT_ALL_ON      (SRTC_PI1 | SRTC_PI2 | SRTC_PI3 | \
> +			SRTC_PI4 | SRTC_PI5 | SRTC_PI6 | SRTC_PI7 | \
> +			SRTC_PI8 | SRTC_PI9 | SRTC_PI10 | SRTC_PI11 | \
> +			SRTC_PI12 | SRTC_PI13 | SRTC_PI14 | SRTC_PI15)
> +
> +#define SRTC_SWR_HP      (1 << 0)	/* hp software reset */
> +#define SRTC_EN_HP       (1 << 3)	/* hp enable */
> +#define SRTC_TS          (1 << 4)	/* time synchronize hp with lp */
> +
> +#define SRTC_IE_AHP      (1 << 16)	/* Alarm HP Interrupt Enable bit */
> +#define SRTC_IE_WDHP     (1 << 18)	/* Write Done HP Interrupt Enable bit */
> +#define SRTC_IE_WDLP     (1 << 19)	/* Write Done LP Interrupt Enable bit */
> +
> +#define SRTC_ISR_AHP     (1 << 16)	/* interrupt status: alarm hp */
> +#define SRTC_ISR_WDHP    (1 << 18)	/* interrupt status: write done hp */
> +#define SRTC_ISR_WDLP    (1 << 19)	/* interrupt status: write done lp */
> +#define SRTC_ISR_WPHP    (1 << 20)	/* interrupt status: write pending hp */
> +#define SRTC_ISR_WPLP    (1 << 21)	/* interrupt status: write pending lp */
> +
> +#define SRTC_LPSCMR	0x00	/* LP Secure Counter MSB Reg */
> +#define SRTC_LPSCLR	0x04	/* LP Secure Counter LSB Reg */
> +#define SRTC_LPSAR	0x08	/* LP Secure Alarm Reg */
> +#define SRTC_LPSMCR	0x0C	/* LP Secure Monotonic Counter Reg */
> +#define SRTC_LPCR	0x10	/* LP Control Reg */
> +#define SRTC_LPSR	0x14	/* LP Status Reg */
> +#define SRTC_LPPDR	0x18	/* LP Power Supply Glitch Detector Reg */
> +#define SRTC_LPGR	0x1C	/* LP General Purpose Reg */
> +#define SRTC_HPCMR	0x20	/* HP Counter MSB Reg */
> +#define SRTC_HPCLR	0x24	/* HP Counter LSB Reg */
> +#define SRTC_HPAMR	0x28	/* HP Alarm MSB Reg */
> +#define SRTC_HPALR	0x2C	/* HP Alarm LSB Reg */
> +#define SRTC_HPCR	0x30	/* HP Control Reg */
> +#define SRTC_HPISR	0x34	/* HP Interrupt Status Reg */
> +#define SRTC_HPIENR	0x38	/* HP Interrupt Enable Reg */
> +
> +#define SRTC_SECMODE_MASK	0x3	/* the mask of SRTC security mode */
> +#define SRTC_SECMODE_LOW	0x0	/* Low Security */
> +#define SRTC_SECMODE_MED	0x1	/* Medium Security */
> +#define SRTC_SECMODE_HIGH	0x2	/* High Security */
> +#define SRTC_SECMODE_RESERVED	0x3	/* Reserved */
> +
> +struct rtc_drv_data {
> +	struct rtc_device *rtc;
> +	void __iomem *ioaddr;
> +	int irq;
> +	struct clk *clk;
> +};
> +
> +static DEFINE_SPINLOCK(rtc_lock);
> +

Shouldn't that lock be part of rtc_drv_data?

> +/*!
> + * This function does write synchronization for writes to the lp srtc block.
> + * To take care of the asynchronous CKIL clock, all writes from the IP domain
> + * will be synchronized to the CKIL domain.
> + */
> +static inline void rtc_write_sync_lp(void __iomem *ioaddr)
> +{
> +	unsigned int i, count;
> +	/* Wait for 3 CKIL cycles */
> +	for (i = 0; i < 3; i++) {
> +		count = readl(ioaddr + SRTC_LPSCLR);
> +		while ((readl(ioaddr + SRTC_LPSCLR)) == count)
> +			;
> +	}
> +}
> +
> +/*!
> + * This function updates the RTC alarm registers and then clears all the
> + * interrupt status bits.
> + *
> + * @param  alrm         the new alarm value to be updated in the RTC
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int rtc_update_alarm(struct device *dev, struct rtc_time *alrm)
> +{
> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	void __iomem *ioaddr = pdata->ioaddr;
> +	struct rtc_time alarm_tm, now_tm;
> +	unsigned long now, time;
> +	int ret;
> +
> +	now = __raw_readl(ioaddr + SRTC_LPSCMR);
> +	rtc_time_to_tm(now, &now_tm);
> +
> +	alarm_tm.tm_year = now_tm.tm_year;
> +	alarm_tm.tm_mon = now_tm.tm_mon;
> +	alarm_tm.tm_mday = now_tm.tm_mday;
> +
> +	alarm_tm.tm_hour = alrm->tm_hour;
> +	alarm_tm.tm_min = alrm->tm_min;
> +	alarm_tm.tm_sec = alrm->tm_sec;
> +
> +	rtc_tm_to_time(&now_tm, &now);
> +	rtc_tm_to_time(&alarm_tm, &time);
> +
> +	if (time < now) {
> +		time += 60 * 60 * 24;
> +		rtc_time_to_tm(time, &alarm_tm);
> +	}
> +	ret = rtc_tm_to_time(&alarm_tm, &time);
> +
> +	__raw_writel(time, ioaddr + SRTC_LPSAR);
> +
> +	/* clear alarm interrupt status bit */
> +	__raw_writel(SRTC_LPSR_ALP, ioaddr + SRTC_LPSR);
> +
> +	return ret;
> +}
> +
> +/*!
> + * This function is the RTC interrupt service routine.
> + *
> + * @param  irq          RTC IRQ number
> + * @param  dev_id       device ID which is not used
> + *
> + * @return IRQ_HANDLED as defined in the include/linux/interrupt.h file.
> + */
> +static irqreturn_t mxc_rtc_interrupt(int irq, void *dev_id)
> +{
> +	struct platform_device *pdev = dev_id;
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +	void __iomem *ioaddr = pdata->ioaddr;
> +	u32 lp_status, lp_cr;
> +	u32 events = 0;
> +
> +	lp_status = __raw_readl(ioaddr + SRTC_LPSR);
> +	lp_cr = __raw_readl(ioaddr + SRTC_LPCR);
> +
> +	/* update irq data & counter */
> +	if (lp_status & SRTC_LPSR_ALP) {
> +		if (lp_cr & SRTC_LPCR_ALP)
> +			events |= (RTC_AF | RTC_IRQF);
> +
> +		/* disable further lp alarm interrupts */
> +		lp_cr &= ~(SRTC_LPCR_ALP | SRTC_LPCR_WAE);
> +	}
> +
> +	/* Update interrupt enables */
> +	__raw_writel(lp_cr, ioaddr + SRTC_LPCR);
> +
> +	/* clear interrupt status */
> +	__raw_writel(lp_status, ioaddr + SRTC_LPSR);
> +
> +	rtc_write_sync_lp(ioaddr);
> +	rtc_update_irq(pdata->rtc, 1, events);
> +	return IRQ_HANDLED;
> +}
> +
> +/*!
> + * This function reads the current RTC time into tm in Gregorian date.
> + *
> + * @param  tm           contains the RTC time value upon return
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int mxc_rtc_read_time(struct device *dev, struct rtc_time *tm)
> +{
> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	time_t now = readl(pdata->ioaddr + SRTC_LPSCMR);
> +
> +	rtc_time_to_tm(now, tm);
> +	return rtc_valid_tm(tm);
> +}
> +
> +/*!
> + * This function sets the internal RTC time based on tm in Gregorian date.
> + *
> + * @param  tm           the time value to be set in the RTC
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int mxc_rtc_set_time(struct device *dev, struct rtc_time *tm)
> +{
> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	time64_t time = rtc_tm_to_time64(tm);
> +
> +	if (time > UINT_MAX) {
> +		dev_warn(dev, "time_t has overflow\n");
> +	}
> +
> +	writel(time, pdata->ioaddr + SRTC_LPSCMR);
> +	rtc_write_sync_lp(pdata->ioaddr);
> +	return 0;
> +}
> +
> +/*!
> + * This function reads the current alarm value into the passed in \b alrm
> + * argument. It updates the \b alrm's pending field value based on the whether
> + * an alarm interrupt occurs or not.
> + *
> + * @param  alrm         contains the RTC alarm value upon return
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int mxc_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
> +{
> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	void __iomem *ioaddr = pdata->ioaddr;
> +
> +	rtc_time_to_tm(__raw_readl(ioaddr + SRTC_LPSAR), &alrm->time);
> +	alrm->pending =
> +	    ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_ALP) != 0) ? 1 : 0;
> +
> +	return 0;
> +}
> +
> +static int mxc_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
> +{
> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	unsigned long lock_flags = 0;
> +	u32 lp_cr;
> +
> +	spin_lock_irqsave(&rtc_lock, lock_flags);
> +	lp_cr = __raw_readl(pdata->ioaddr + SRTC_LPCR);
> +
> +	if (enable)
> +		lp_cr |= (SRTC_LPCR_ALP | SRTC_LPCR_WAE);
> +	else
> +		lp_cr &= ~(SRTC_LPCR_ALP | SRTC_LPCR_WAE);
> +
> +	__raw_writel(lp_cr, pdata->ioaddr + SRTC_LPCR);
> +	spin_unlock_irqrestore(&rtc_lock, lock_flags);
> +	return 0;
> +}
> +
> +/*!
> + * This function sets the RTC alarm based on passed in alrm.
> + *
> + * @param  alrm         the alarm value to be set in the RTC
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int mxc_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
> +{
> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	void __iomem *ioaddr = pdata->ioaddr;
> +	int ret;
> +
> +	ret = rtc_update_alarm(dev, &alrm->time);
> +	if (!ret)
> +		mxc_rtc_alarm_irq_enable(dev, alrm->enabled);
> +
> +	rtc_write_sync_lp(ioaddr);
> +	return ret;
> +}
> +
> +/*!
> + * The RTC driver structure
> + */
> +static const struct rtc_class_ops mxc_rtc_ops = {
> +	.read_time = mxc_rtc_read_time,
> +	.set_time = mxc_rtc_set_time,
> +	.read_alarm = mxc_rtc_read_alarm,
> +	.set_alarm = mxc_rtc_set_alarm,
> +	.alarm_irq_enable = mxc_rtc_alarm_irq_enable,
> +};
> +
> +/*! MXC RTC Power management control */

This comment is probably wrong ;)

> +static int mxc_rtc_probe(struct platform_device *pdev)
> +{
> +	struct timespec tv;
> +	struct resource *res;
> +	struct rtc_drv_data *pdata = NULL;
> +	void __iomem *ioaddr;
> +	int ret = 0;
> +
> +	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
> +	if (!pdata)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res)
> +		return -ENODEV;
> +
> +	pdata->ioaddr = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(pdata->ioaddr))
> +		return PTR_ERR(pdata->ioaddr);
> +
> +	ioaddr = pdata->ioaddr;
> +
> +	pdata->clk = devm_clk_get(&pdev->dev, NULL);
> +	if (IS_ERR(pdata->clk)) {
> +		dev_err(&pdev->dev, "unable to get rtc clock!\n");
> +		return PTR_ERR(pdata->clk);
> +	}
> +	ret = clk_prepare_enable(pdata->clk);
> +	if (ret)
> +		return ret;
> +
> +	/* Configure and enable the RTC */
> +	pdata->irq = platform_get_irq(pdev, 0);
> +	if (pdata->irq >= 0
> +	    && devm_request_irq(&pdev->dev, pdata->irq, mxc_rtc_interrupt,
> +				IRQF_SHARED, pdev->name, pdev) < 0) {
> +		dev_warn(&pdev->dev, "interrupt not available.\n");
> +		pdata->irq = -1;
> +	}
> +
> +	if (pdata->irq >= 0)
> +		device_init_wakeup(&pdev->dev, 1);
> +
> +	/* initialize glitch detect */
> +	__raw_writel(SRTC_LPPDR_INIT, ioaddr + SRTC_LPPDR);
> +	udelay(100);
> +
> +	/* clear lp interrupt status */
> +	__raw_writel(0xFFFFFFFF, ioaddr + SRTC_LPSR);
> +	udelay(100);
> +
> +	/* move out of init state */
> +	__raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NSA), ioaddr + SRTC_LPCR);
> +
> +	udelay(100);
> +
> +	while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_IES) == 0)
> +		;
> +
> +	/* move out of non-valid state */
> +	__raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NVE | SRTC_LPCR_NSA |
> +		      SRTC_LPCR_EN_LP), ioaddr + SRTC_LPCR);
> +
> +	udelay(100);
> +
> +	while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_NVES) == 0)
> +		;
> +
> +	__raw_writel(0xFFFFFFFF, ioaddr + SRTC_LPSR);
> +	udelay(100);
> +
> +	platform_set_drvdata(pdev, pdata);
> +	pdata->rtc =
> +	    devm_rtc_device_register(&pdev->dev, pdev->name, &mxc_rtc_ops,
> +				     THIS_MODULE);
> +	if (IS_ERR(pdata->rtc)) {
> +		ret = PTR_ERR(pdata->rtc);
> +		goto exit_put_clk;
> +	}
> +
> +	tv.tv_nsec = 0;
> +	tv.tv_sec = __raw_readl(ioaddr + SRTC_LPSCMR);
> +
> +	/* By default, devices should wakeup if they can */
> +	/* So srtc is set as "should wakeup" as it can */
That comment is not formatted correctly.

> +	device_init_wakeup(&pdev->dev, 1);
> +
> +	return ret;

For clarity, this has to return 0.

> +
> +exit_put_clk:
> +	clk_disable_unprepare(pdata->clk);
> +	return ret;
> +}
> +
> +static int __exit mxc_rtc_remove(struct platform_device *pdev)
> +{
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +
> +	clk_disable_unprepare(pdata->clk);
> +	return 0;
> +}
> +
> +/*!
> + * This function is called to save the system time delta relative to
> + * the MXC RTC when enterring a low power state. This time delta is
> + * then used on resume to adjust the system time to account for time
> + * loss while suspended.
> + *
> + * @param   pdev  not used
> + * @param   state Power state to enter.
> + *
> + * @return  The function always returns 0.
> + */
> +static int mxc_rtc_suspend(struct platform_device *pdev, pm_message_t state)
> +{
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +
> +	if (device_may_wakeup(&pdev->dev))
> +		enable_irq_wake(pdata->irq);
> +
> +	return 0;
> +}
> +
> +/*!
> + * This function is called to correct the system time based on the
> + * current MXC RTC time relative to the time delta saved during
> + * suspend.
> + *
> + * @param   pdev  not used
> + *
> + * @return  The function always returns 0.
> + */
> +static int mxc_rtc_resume(struct platform_device *pdev)
> +{
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +
> +	if (device_may_wakeup(&pdev->dev))
> +		disable_irq_wake(pdata->irq);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id mxc_ids[] = {
> +	{.compatible = "fsl,imx53-rtc",},
> +	{}
> +};
> +
> +/*!
> + * Contains pointers to the power management callback functions.
> + */
> +static struct platform_driver mxc_rtc_driver = {
> +	.driver = {
> +		   .name = "mxc_rtc_v8",

Isn't it weird to have v8 here when the file is named v2?

> +		   .of_match_table = mxc_ids,
> +		   },
> +	.probe = mxc_rtc_probe,
> +	.remove = mxc_rtc_remove,
> +	.suspend = mxc_rtc_suspend,
> +	.resume = mxc_rtc_resume,
> +};
> +
> +module_platform_driver(mxc_rtc_driver);
> +
> +MODULE_AUTHOR("Freescale Semiconductor, Inc.");
> +MODULE_DESCRIPTION("Realtime Clock Driver (RTC)");
> +MODULE_LICENSE("GPL");
> -- 
> 2.11.0
> 
> 

-- 
Alexandre Belloni, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] rtc: add mxc driver for i.MX53
  2017-11-29 22:11   ` Alexandre Belloni
  (?)
@ 2017-11-30  8:18     ` Philippe Ombredanne
  -1 siblings, 0 replies; 43+ messages in thread
From: Philippe Ombredanne @ 2017-11-30  8:18 UTC (permalink / raw)
  To: Alexandre Belloni
  Cc: linux-kernel-dev, Alessandro Zummo, Patrick Bruenn, Rob Herring,
	Mark Rutland, open list:REAL TIME CLOCK (RTC) SUBSYSTEM,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	open list, Fabio Estevam, Juergen Borleis, Noel Vellemans,
	Shawn Guo, Sascha Hauer, Russell King,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE

On Wed, Nov 29, 2017 at 11:11 PM, Alexandre Belloni
<alexandre.belloni@free-electrons.com> wrote:
> On 28/11/2017 at 08:39:27 +0100, linux-kernel-dev@beckhoff.com wrote:
>> From: Patrick Bruenn <p.bruenn@beckhoff.com>
[]
>> diff --git a/drivers/rtc/rtc-mxc_v2.c b/drivers/rtc/rtc-mxc_v2.c
>> new file mode 100644
>> index 000000000000..5049b521b38e
>> --- /dev/null
>> +++ b/drivers/rtc/rtc-mxc_v2.c
>> @@ -0,0 +1,531 @@
>
> I think SPDX identifier will soon be required on new files, please add
> one.
>
>> +/*
>> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights Reserved.
>> + */
>> +
>> +/*
>> + * The code contained herein is licensed under the GNU General Public
>> + * License. You may obtain a copy of the GNU General Public License
>> + * Version 2 or later at the following locations:
>> + *
>> + * http://www.opensource.org/licenses/gpl-license.html
>> + * http://www.gnu.org/copyleft/gpl.html
>> + */

Exactly!
And while you are it , you could replace the boilerplate license text
with the SPDX id.
-- 
Cordially
Philippe Ombredanne

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] rtc: add mxc driver for i.MX53
@ 2017-11-30  8:18     ` Philippe Ombredanne
  0 siblings, 0 replies; 43+ messages in thread
From: Philippe Ombredanne @ 2017-11-30  8:18 UTC (permalink / raw)
  To: Alexandre Belloni
  Cc: linux-kernel-dev, Alessandro Zummo, Patrick Bruenn, Rob Herring,
	Mark Rutland, open list:REAL TIME CLOCK (RTC) SUBSYSTEM,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	open list, Fabio Estevam, Juergen Borleis, Noel Vellemans,
	Shawn Guo, Sascha Hauer, Russell King,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE

On Wed, Nov 29, 2017 at 11:11 PM, Alexandre Belloni
<alexandre.belloni@free-electrons.com> wrote:
> On 28/11/2017 at 08:39:27 +0100, linux-kernel-dev@beckhoff.com wrote:
>> From: Patrick Bruenn <p.bruenn@beckhoff.com>
[]
>> diff --git a/drivers/rtc/rtc-mxc_v2.c b/drivers/rtc/rtc-mxc_v2.c
>> new file mode 100644
>> index 000000000000..5049b521b38e
>> --- /dev/null
>> +++ b/drivers/rtc/rtc-mxc_v2.c
>> @@ -0,0 +1,531 @@
>
> I think SPDX identifier will soon be required on new files, please add
> one.
>
>> +/*
>> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights Reserved.
>> + */
>> +
>> +/*
>> + * The code contained herein is licensed under the GNU General Public
>> + * License. You may obtain a copy of the GNU General Public License
>> + * Version 2 or later at the following locations:
>> + *
>> + * http://www.opensource.org/licenses/gpl-license.html
>> + * http://www.gnu.org/copyleft/gpl.html
>> + */

Exactly!
And while you are it , you could replace the boilerplate license text
with the SPDX id.
-- 
Cordially
Philippe Ombredanne

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH] rtc: add mxc driver for i.MX53
@ 2017-11-30  8:18     ` Philippe Ombredanne
  0 siblings, 0 replies; 43+ messages in thread
From: Philippe Ombredanne @ 2017-11-30  8:18 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Nov 29, 2017 at 11:11 PM, Alexandre Belloni
<alexandre.belloni@free-electrons.com> wrote:
> On 28/11/2017 at 08:39:27 +0100, linux-kernel-dev at beckhoff.com wrote:
>> From: Patrick Bruenn <p.bruenn@beckhoff.com>
[]
>> diff --git a/drivers/rtc/rtc-mxc_v2.c b/drivers/rtc/rtc-mxc_v2.c
>> new file mode 100644
>> index 000000000000..5049b521b38e
>> --- /dev/null
>> +++ b/drivers/rtc/rtc-mxc_v2.c
>> @@ -0,0 +1,531 @@
>
> I think SPDX identifier will soon be required on new files, please add
> one.
>
>> +/*
>> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights Reserved.
>> + */
>> +
>> +/*
>> + * The code contained herein is licensed under the GNU General Public
>> + * License. You may obtain a copy of the GNU General Public License
>> + * Version 2 or later at the following locations:
>> + *
>> + * http://www.opensource.org/licenses/gpl-license.html
>> + * http://www.gnu.org/copyleft/gpl.html
>> + */

Exactly!
And while you are it , you could replace the boilerplate license text
with the SPDX id.
-- 
Cordially
Philippe Ombredanne

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] rtc: add mxc driver for i.MX53
  2017-11-28  7:39 ` linux-kernel-dev
  (?)
  (?)
@ 2017-11-30  9:50   ` Sascha Hauer
  -1 siblings, 0 replies; 43+ messages in thread
From: Sascha Hauer @ 2017-11-30  9:50 UTC (permalink / raw)
  To: linux-kernel-dev
  Cc: Alessandro Zummo, Alexandre Belloni, Mark Rutland,
	open list:REAL TIME CLOCK (RTC) SUBSYSTEM, Patrick Bruenn,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Juergen Borleis, open list, Russell King, Noel Vellemans,
	Rob Herring, Sascha Hauer, Fabio Estevam, Shawn Guo,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE

On Tue, Nov 28, 2017 at 08:39:27AM +0100, linux-kernel-dev@beckhoff.com wrote:
> From: Patrick Bruenn <p.bruenn@beckhoff.com>
> 
> Neither rtc-imxdi nor rtc-mxc are compatible with i.MX53.
> Add a modernized version of mxc_v2 from here:
> http://git.freescale.com/git/cgit.cgi/imx/linux-2.6-imx.git/tree/drivers/rtc/rtc-mxc_v2.c?h=imx_2.6.35_11.09.01
> 
> Changes to that version:
> - updated to v4.15-rc1
> - removed ioctl()
> - removed proc()
> - removed manual(redundant) enable_irq flag
> 
> Signed-off-by: Patrick Bruenn <p.bruenn@beckhoff.com>
> 
> ---
> 
> Open issues:
> - driver naming, should it be merged with rtc-mxc.c ?
> - document DT binding "fsl,imx53-rtc" accordingly
> - Should unused defines be removed or kept for someone else to be
>   useful?
> - Is the use of __raw_readl/writel() correct? Should it be replaced with
>   readl/writel()?
> - suspend/resume() seems different to existing rtc-mxc.c, should I apply
>   the pattern from rtc-mxc.c?
> - On Shawns tree imx53.dtsi has been reverted already[1][2]. Should I split
>   the imx53.dtsi change into a separate patch based on his tree? Or can
>   we still stop the full revert and just remove the imx25-rtc compatible?
>   I am not in a hurry, so we could just wait until the revert landed in
>   Linus tree. Whatever you think is best.
> 
> [1] https://www.spinics.net/lists/arm-kernel/msg617113.html
> [2] commit ee76f7729babd2700afd6f3874449d8084dd85ea
> 
> To: Alessandro Zummo <a.zummo@towertech.it>
> To: Alexandre Belloni <alexandre.belloni@free-electrons.com>
> Cc: Rob Herring <robh+dt@kernel.org>
> Cc: Mark Rutland <mark.rutland@arm.com> (maintainer:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS)
> Cc: linux-rtc@vger.kernel.org (open list:REAL TIME CLOCK (RTC) SUBSYSTEM)
> Cc: devicetree@vger.kernel.org (open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS)
> Cc: linux-kernel@vger.kernel.org (open list)
> Cc: Fabio Estevam <fabio.estevam@nxp.com>
> Cc: Juergen Borleis <jbe@pengutronix.de>
> Cc: Noel Vellemans <Noel.Vellemans@visionbms.com>
> Cc: Shawn Guo <shawnguo@kernel.org>
> Cc: Sascha Hauer <kernel@pengutronix.de> (maintainer:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE)
> Cc: Russell King <linux@armlinux.org.uk> (maintainer:ARM PORT)
> Cc: linux-arm-kernel@lists.infradead.org (moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE)
> ---
>  arch/arm/boot/dts/imx53.dtsi |   2 +-
>  drivers/rtc/Makefile         |   1 +
>  drivers/rtc/rtc-mxc_v2.c     | 531 +++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 533 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/rtc/rtc-mxc_v2.c
> 
> diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi
> index 589a67c5f796..3d1a55e11ea8 100644
> --- a/arch/arm/boot/dts/imx53.dtsi
> +++ b/arch/arm/boot/dts/imx53.dtsi
> @@ -434,7 +434,7 @@
>  			};
>  
>  			srtc: srtc@53fa4000 {
> -				compatible = "fsl,imx53-rtc", "fsl,imx25-rtc";
> +				compatible = "fsl,imx53-rtc";
>  				reg = <0x53fa4000 0x4000>;
>  				interrupts = <24>;
>  				interrupt-parent = <&tzic>;
> diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
> index f2f50c11dc38..fb3dc458c185 100644
> --- a/drivers/rtc/Makefile
> +++ b/drivers/rtc/Makefile
> @@ -106,6 +106,7 @@ obj-$(CONFIG_RTC_DRV_MT6397)	+= rtc-mt6397.o
>  obj-$(CONFIG_RTC_DRV_MT7622)	+= rtc-mt7622.o
>  obj-$(CONFIG_RTC_DRV_MV)	+= rtc-mv.o
>  obj-$(CONFIG_RTC_DRV_MXC)	+= rtc-mxc.o
> +obj-$(CONFIG_RTC_DRV_MXC)	+= rtc-mxc_v2.o
>  obj-$(CONFIG_RTC_DRV_NUC900)	+= rtc-nuc900.o
>  obj-$(CONFIG_RTC_DRV_OMAP)	+= rtc-omap.o
>  obj-$(CONFIG_RTC_DRV_OPAL)	+= rtc-opal.o
> diff --git a/drivers/rtc/rtc-mxc_v2.c b/drivers/rtc/rtc-mxc_v2.c
> new file mode 100644
> index 000000000000..5049b521b38e
> --- /dev/null
> +++ b/drivers/rtc/rtc-mxc_v2.c
> @@ -0,0 +1,531 @@
> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights Reserved.
> + */
> +
> +/*
> + * The code contained herein is licensed under the GNU General Public
> + * License. You may obtain a copy of the GNU General Public License
> + * Version 2 or later at the following locations:
> + *
> + * http://www.opensource.org/licenses/gpl-license.html
> + * http://www.gnu.org/copyleft/gpl.html
> + */
> +/*
> + * Implementation based on rtc-ds1553.c
> + */
> +
> +/*!
> + * @defgroup RTC Real Time Clock (RTC) Driver for i.MX53
> + */
> +/*!
> + * @file rtc-mxc_v2.c
> + * @brief Real Time Clock interface
> + *
> + * This file contains Real Time Clock interface for Linux.
> + *
> + * @ingroup RTC
> + */
> +
> +#include <linux/slab.h>
> +#include <linux/delay.h>
> +#include <linux/rtc.h>
> +#include <linux/module.h>
> +#include <linux/fs.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/platform_device.h>
> +#include <linux/clk.h>
> +#include <linux/device.h>
> +#include <linux/uaccess.h>
> +#include <linux/io.h>
> +//#include <linux/mxc_srtc.h>
> +#define RTC_READ_TIME_47BIT	_IOR('p', 0x20, unsigned long long)
> +/* blocks until LPSCMR is set, returns difference */
> +#define RTC_WAIT_TIME_SET	_IOR('p', 0x21, int64_t)
> +
> +#define SRTC_LPSCLR_LLPSC_LSH	17	/* start bit for LSB time value */
> +
> +#define SRTC_LPPDR_INIT       0x41736166	/* init for glitch detect */
> +
> +#define SRTC_LPCR_SWR_LP      (1 << 0)	/* lp software reset */
> +#define SRTC_LPCR_EN_LP       (1 << 3)	/* lp enable */
> +#define SRTC_LPCR_WAE         (1 << 4)	/* lp wakeup alarm enable */
> +#define SRTC_LPCR_SAE         (1 << 5)	/* lp security alarm enable */
> +#define SRTC_LPCR_SI          (1 << 6)	/* lp security interrupt enable */
> +#define SRTC_LPCR_ALP         (1 << 7)	/* lp alarm flag */
> +#define SRTC_LPCR_LTC         (1 << 8)	/* lp lock time counter */
> +#define SRTC_LPCR_LMC         (1 << 9)	/* lp lock monotonic counter */
> +#define SRTC_LPCR_SV          (1 << 10)	/* lp security violation */
> +#define SRTC_LPCR_NSA         (1 << 11)	/* lp non secure access */
> +#define SRTC_LPCR_NVEIE       (1 << 12)	/* lp non valid state exit int en */
> +#define SRTC_LPCR_IEIE        (1 << 13)	/* lp init state exit int enable */
> +#define SRTC_LPCR_NVE         (1 << 14)	/* lp non valid state exit bit */
> +#define SRTC_LPCR_IE          (1 << 15)	/* lp init state exit bit */
> +
> +#define SRTC_LPCR_ALL_INT_EN (SRTC_LPCR_WAE | SRTC_LPCR_SAE | \
> +			      SRTC_LPCR_SI | SRTC_LPCR_ALP | \
> +			      SRTC_LPCR_NVEIE | SRTC_LPCR_IEIE)
> +
> +#define SRTC_LPSR_TRI         (1 << 0)	/* lp time read invalidate */
> +#define SRTC_LPSR_PGD         (1 << 1)	/* lp power supply glitc detected */
> +#define SRTC_LPSR_CTD         (1 << 2)	/* lp clock tampering detected */
> +#define SRTC_LPSR_ALP         (1 << 3)	/* lp alarm flag */
> +#define SRTC_LPSR_MR          (1 << 4)	/* lp monotonic counter rollover */
> +#define SRTC_LPSR_TR          (1 << 5)	/* lp time rollover */
> +#define SRTC_LPSR_EAD         (1 << 6)	/* lp external alarm detected */
> +#define SRTC_LPSR_IT0         (1 << 7)	/* lp IIM throttle */
> +#define SRTC_LPSR_IT1         (1 << 8)
> +#define SRTC_LPSR_IT2         (1 << 9)
> +#define SRTC_LPSR_SM0         (1 << 10)	/* lp security mode */
> +#define SRTC_LPSR_SM1         (1 << 11)
> +#define SRTC_LPSR_STATE_LP0   (1 << 12)	/* lp state */
> +#define SRTC_LPSR_STATE_LP1   (1 << 13)
> +#define SRTC_LPSR_NVES        (1 << 14)	/* lp non-valid state exit status */
> +#define SRTC_LPSR_IES         (1 << 15)	/* lp init state exit status */
> +
> +#define MAX_PIE_NUM     15
> +#define MAX_PIE_FREQ    32768
> +#define MIN_PIE_FREQ	1
> +
> +#define SRTC_PI0         (1 << 0)
> +#define SRTC_PI1         (1 << 1)
> +#define SRTC_PI2         (1 << 2)
> +#define SRTC_PI3         (1 << 3)
> +#define SRTC_PI4         (1 << 4)
> +#define SRTC_PI5         (1 << 5)
> +#define SRTC_PI6         (1 << 6)
> +#define SRTC_PI7         (1 << 7)
> +#define SRTC_PI8         (1 << 8)
> +#define SRTC_PI9         (1 << 9)
> +#define SRTC_PI10        (1 << 10)
> +#define SRTC_PI11        (1 << 11)
> +#define SRTC_PI12        (1 << 12)
> +#define SRTC_PI13        (1 << 13)
> +#define SRTC_PI14        (1 << 14)
> +#define SRTC_PI15        (1 << 15)
> +
> +#define PIT_ALL_ON      (SRTC_PI1 | SRTC_PI2 | SRTC_PI3 | \
> +			SRTC_PI4 | SRTC_PI5 | SRTC_PI6 | SRTC_PI7 | \
> +			SRTC_PI8 | SRTC_PI9 | SRTC_PI10 | SRTC_PI11 | \
> +			SRTC_PI12 | SRTC_PI13 | SRTC_PI14 | SRTC_PI15)
> +
> +#define SRTC_SWR_HP      (1 << 0)	/* hp software reset */
> +#define SRTC_EN_HP       (1 << 3)	/* hp enable */
> +#define SRTC_TS          (1 << 4)	/* time synchronize hp with lp */
> +
> +#define SRTC_IE_AHP      (1 << 16)	/* Alarm HP Interrupt Enable bit */
> +#define SRTC_IE_WDHP     (1 << 18)	/* Write Done HP Interrupt Enable bit */
> +#define SRTC_IE_WDLP     (1 << 19)	/* Write Done LP Interrupt Enable bit */
> +
> +#define SRTC_ISR_AHP     (1 << 16)	/* interrupt status: alarm hp */
> +#define SRTC_ISR_WDHP    (1 << 18)	/* interrupt status: write done hp */
> +#define SRTC_ISR_WDLP    (1 << 19)	/* interrupt status: write done lp */
> +#define SRTC_ISR_WPHP    (1 << 20)	/* interrupt status: write pending hp */
> +#define SRTC_ISR_WPLP    (1 << 21)	/* interrupt status: write pending lp */
> +
> +#define SRTC_LPSCMR	0x00	/* LP Secure Counter MSB Reg */
> +#define SRTC_LPSCLR	0x04	/* LP Secure Counter LSB Reg */
> +#define SRTC_LPSAR	0x08	/* LP Secure Alarm Reg */
> +#define SRTC_LPSMCR	0x0C	/* LP Secure Monotonic Counter Reg */
> +#define SRTC_LPCR	0x10	/* LP Control Reg */
> +#define SRTC_LPSR	0x14	/* LP Status Reg */
> +#define SRTC_LPPDR	0x18	/* LP Power Supply Glitch Detector Reg */
> +#define SRTC_LPGR	0x1C	/* LP General Purpose Reg */
> +#define SRTC_HPCMR	0x20	/* HP Counter MSB Reg */
> +#define SRTC_HPCLR	0x24	/* HP Counter LSB Reg */
> +#define SRTC_HPAMR	0x28	/* HP Alarm MSB Reg */
> +#define SRTC_HPALR	0x2C	/* HP Alarm LSB Reg */
> +#define SRTC_HPCR	0x30	/* HP Control Reg */
> +#define SRTC_HPISR	0x34	/* HP Interrupt Status Reg */
> +#define SRTC_HPIENR	0x38	/* HP Interrupt Enable Reg */
> +
> +#define SRTC_SECMODE_MASK	0x3	/* the mask of SRTC security mode */
> +#define SRTC_SECMODE_LOW	0x0	/* Low Security */
> +#define SRTC_SECMODE_MED	0x1	/* Medium Security */
> +#define SRTC_SECMODE_HIGH	0x2	/* High Security */
> +#define SRTC_SECMODE_RESERVED	0x3	/* Reserved */
> +
> +struct rtc_drv_data {
> +	struct rtc_device *rtc;
> +	void __iomem *ioaddr;
> +	int irq;
> +	struct clk *clk;
> +};
> +
> +static DEFINE_SPINLOCK(rtc_lock);

The lock should be a member of your driver data struct.

> +
> +/*!
> + * This function does write synchronization for writes to the lp srtc block.
> + * To take care of the asynchronous CKIL clock, all writes from the IP domain
> + * will be synchronized to the CKIL domain.
> + */

Please drop this exclamation mark at the beginning of comments. If
anything, use kerneldoc style for the function descriptions.

> +static inline void rtc_write_sync_lp(void __iomem *ioaddr)
> +{
> +	unsigned int i, count;
> +	/* Wait for 3 CKIL cycles */
> +	for (i = 0; i < 3; i++) {
> +		count = readl(ioaddr + SRTC_LPSCLR);
> +		while ((readl(ioaddr + SRTC_LPSCLR)) == count)
> +			;

This becomes an infinite loop when the hardware is not working as
expected. You should avoid that.

> +	}
> +}
> +
> +/*!
> + * This function updates the RTC alarm registers and then clears all the
> + * interrupt status bits.
> + *
> + * @param  alrm         the new alarm value to be updated in the RTC
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int rtc_update_alarm(struct device *dev, struct rtc_time *alrm)
> +{

mxc_rtc_update_alarm please like the other device specific functions
please. Same for rtc_write_sync_lp().

> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	void __iomem *ioaddr = pdata->ioaddr;
> +	struct rtc_time alarm_tm, now_tm;
> +	unsigned long now, time;
> +	int ret;
> +
> +	now = __raw_readl(ioaddr + SRTC_LPSCMR);
> +	rtc_time_to_tm(now, &now_tm);
> +
> +	alarm_tm.tm_year = now_tm.tm_year;
> +	alarm_tm.tm_mon = now_tm.tm_mon;
> +	alarm_tm.tm_mday = now_tm.tm_mday;
> +
> +	alarm_tm.tm_hour = alrm->tm_hour;
> +	alarm_tm.tm_min = alrm->tm_min;
> +	alarm_tm.tm_sec = alrm->tm_sec;
> +
> +	rtc_tm_to_time(&now_tm, &now);
> +	rtc_tm_to_time(&alarm_tm, &time);
> +
> +	if (time < now) {
> +		time += 60 * 60 * 24;
> +		rtc_time_to_tm(time, &alarm_tm);
> +	}
> +	ret = rtc_tm_to_time(&alarm_tm, &time);
> +
> +	__raw_writel(time, ioaddr + SRTC_LPSAR);
> +
> +	/* clear alarm interrupt status bit */
> +	__raw_writel(SRTC_LPSR_ALP, ioaddr + SRTC_LPSR);
> +
> +	return ret;
> +}
> +
> +/*!
> + * This function is the RTC interrupt service routine.
> + *
> + * @param  irq          RTC IRQ number
> + * @param  dev_id       device ID which is not used
> + *
> + * @return IRQ_HANDLED as defined in the include/linux/interrupt.h file.
> + */
> +static irqreturn_t mxc_rtc_interrupt(int irq, void *dev_id)
> +{
> +	struct platform_device *pdev = dev_id;
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +	void __iomem *ioaddr = pdata->ioaddr;
> +	u32 lp_status, lp_cr;
> +	u32 events = 0;
> +
> +	lp_status = __raw_readl(ioaddr + SRTC_LPSR);
> +	lp_cr = __raw_readl(ioaddr + SRTC_LPCR);
> +
> +	/* update irq data & counter */
> +	if (lp_status & SRTC_LPSR_ALP) {
> +		if (lp_cr & SRTC_LPCR_ALP)
> +			events |= (RTC_AF | RTC_IRQF);
> +
> +		/* disable further lp alarm interrupts */
> +		lp_cr &= ~(SRTC_LPCR_ALP | SRTC_LPCR_WAE);
> +	}
> +
> +	/* Update interrupt enables */
> +	__raw_writel(lp_cr, ioaddr + SRTC_LPCR);
> +
> +	/* clear interrupt status */
> +	__raw_writel(lp_status, ioaddr + SRTC_LPSR);
> +
> +	rtc_write_sync_lp(ioaddr);
> +	rtc_update_irq(pdata->rtc, 1, events);
> +	return IRQ_HANDLED;
> +}

What about locking? You lock the read/modify/write operation of the LPCR
register below, and so you should do here.

> +
> +/*!
> + * This function reads the current RTC time into tm in Gregorian date.
> + *
> + * @param  tm           contains the RTC time value upon return
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int mxc_rtc_read_time(struct device *dev, struct rtc_time *tm)
> +{
> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	time_t now = readl(pdata->ioaddr + SRTC_LPSCMR);
> +
> +	rtc_time_to_tm(now, tm);
> +	return rtc_valid_tm(tm);
> +}
> +
> +/*!
> + * This function sets the internal RTC time based on tm in Gregorian date.
> + *
> + * @param  tm           the time value to be set in the RTC
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int mxc_rtc_set_time(struct device *dev, struct rtc_time *tm)
> +{
> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	time64_t time = rtc_tm_to_time64(tm);
> +
> +	if (time > UINT_MAX) {
> +		dev_warn(dev, "time_t has overflow\n");
> +	}

SIGH. Who builds such a RTC in the 21st century?

Shouldn't this return an error?

> +
> +	writel(time, pdata->ioaddr + SRTC_LPSCMR);
> +	rtc_write_sync_lp(pdata->ioaddr);
> +	return 0;
> +}
> +
> +/*!
> + * This function reads the current alarm value into the passed in \b alrm
> + * argument. It updates the \b alrm's pending field value based on the whether
> + * an alarm interrupt occurs or not.
> + *
> + * @param  alrm         contains the RTC alarm value upon return
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int mxc_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
> +{
> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	void __iomem *ioaddr = pdata->ioaddr;
> +
> +	rtc_time_to_tm(__raw_readl(ioaddr + SRTC_LPSAR), &alrm->time);
> +	alrm->pending =
> +	    ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_ALP) != 0) ? 1 : 0;

if/else would be much easier to read here.

> +
> +	return 0;
> +}
> +
> +static int mxc_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
> +{
> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	unsigned long lock_flags = 0;
> +	u32 lp_cr;
> +
> +	spin_lock_irqsave(&rtc_lock, lock_flags);
> +	lp_cr = __raw_readl(pdata->ioaddr + SRTC_LPCR);
> +
> +	if (enable)
> +		lp_cr |= (SRTC_LPCR_ALP | SRTC_LPCR_WAE);
> +	else
> +		lp_cr &= ~(SRTC_LPCR_ALP | SRTC_LPCR_WAE);
> +
> +	__raw_writel(lp_cr, pdata->ioaddr + SRTC_LPCR);
> +	spin_unlock_irqrestore(&rtc_lock, lock_flags);
> +	return 0;
> +}
> +
> +/*!
> + * This function sets the RTC alarm based on passed in alrm.
> + *
> + * @param  alrm         the alarm value to be set in the RTC
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int mxc_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
> +{
> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	void __iomem *ioaddr = pdata->ioaddr;
> +	int ret;
> +
> +	ret = rtc_update_alarm(dev, &alrm->time);
> +	if (!ret)
> +		mxc_rtc_alarm_irq_enable(dev, alrm->enabled);
> +
> +	rtc_write_sync_lp(ioaddr);
> +	return ret;
> +}
> +
> +/*!
> + * The RTC driver structure
> + */
> +static const struct rtc_class_ops mxc_rtc_ops = {
> +	.read_time = mxc_rtc_read_time,
> +	.set_time = mxc_rtc_set_time,
> +	.read_alarm = mxc_rtc_read_alarm,
> +	.set_alarm = mxc_rtc_set_alarm,
> +	.alarm_irq_enable = mxc_rtc_alarm_irq_enable,
> +};
> +
> +/*! MXC RTC Power management control */
> +static int mxc_rtc_probe(struct platform_device *pdev)
> +{
> +	struct timespec tv;
> +	struct resource *res;
> +	struct rtc_drv_data *pdata = NULL;

No need to initialize.

> +	void __iomem *ioaddr;
> +	int ret = 0;
> +
> +	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
> +	if (!pdata)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res)
> +		return -ENODEV;
> +
> +	pdata->ioaddr = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(pdata->ioaddr))
> +		return PTR_ERR(pdata->ioaddr);
> +
> +	ioaddr = pdata->ioaddr;
> +
> +	pdata->clk = devm_clk_get(&pdev->dev, NULL);
> +	if (IS_ERR(pdata->clk)) {
> +		dev_err(&pdev->dev, "unable to get rtc clock!\n");
> +		return PTR_ERR(pdata->clk);
> +	}
> +	ret = clk_prepare_enable(pdata->clk);
> +	if (ret)
> +		return ret;
> +
> +	/* Configure and enable the RTC */
> +	pdata->irq = platform_get_irq(pdev, 0);
> +	if (pdata->irq >= 0
> +	    && devm_request_irq(&pdev->dev, pdata->irq, mxc_rtc_interrupt,
> +				IRQF_SHARED, pdev->name, pdev) < 0) {
> +		dev_warn(&pdev->dev, "interrupt not available.\n");
> +		pdata->irq = -1;
> +	}

I would just make the interrupt mandatory. I see no valid reason why it
shouldn't be available and it makes your driver logic simpler when you
can just assume it's available.

> +
> +	if (pdata->irq >= 0)
> +		device_init_wakeup(&pdev->dev, 1);
> +
> +	/* initialize glitch detect */
> +	__raw_writel(SRTC_LPPDR_INIT, ioaddr + SRTC_LPPDR);
> +	udelay(100);
> +
> +	/* clear lp interrupt status */
> +	__raw_writel(0xFFFFFFFF, ioaddr + SRTC_LPSR);
> +	udelay(100);
> +
> +	/* move out of init state */
> +	__raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NSA), ioaddr + SRTC_LPCR);
> +
> +	udelay(100);
> +
> +	while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_IES) == 0)
> +		;
> +
> +	/* move out of non-valid state */
> +	__raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NVE | SRTC_LPCR_NSA |
> +		      SRTC_LPCR_EN_LP), ioaddr + SRTC_LPCR);
> +
> +	udelay(100);

Where do all these udelay() come from? Are they really needed?

> +
> +	while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_NVES) == 0)
> +		;
> +
> +	__raw_writel(0xFFFFFFFF, ioaddr + SRTC_LPSR);
> +	udelay(100);
> +
> +	platform_set_drvdata(pdev, pdata);
> +	pdata->rtc =
> +	    devm_rtc_device_register(&pdev->dev, pdev->name, &mxc_rtc_ops,
> +				     THIS_MODULE);
> +	if (IS_ERR(pdata->rtc)) {
> +		ret = PTR_ERR(pdata->rtc);
> +		goto exit_put_clk;
> +	}
> +
> +	tv.tv_nsec = 0;
> +	tv.tv_sec = __raw_readl(ioaddr + SRTC_LPSCMR);

Why this? tv is set but unused.

> +
> +	/* By default, devices should wakeup if they can */
> +	/* So srtc is set as "should wakeup" as it can */
> +	device_init_wakeup(&pdev->dev, 1);

Why is this done twice, one time only when we have a valid irq? This
looks fishy.

> +
> +	return ret;
> +
> +exit_put_clk:
> +	clk_disable_unprepare(pdata->clk);
> +	return ret;
> +}
> +
> +static int __exit mxc_rtc_remove(struct platform_device *pdev)
> +{
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +
> +	clk_disable_unprepare(pdata->clk);
> +	return 0;
> +}
> +
> +/*!
> + * This function is called to save the system time delta relative to
> + * the MXC RTC when enterring a low power state. This time delta is
> + * then used on resume to adjust the system time to account for time
> + * loss while suspended.
> + *
> + * @param   pdev  not used

Not true.

> + * @param   state Power state to enter.
> + *
> + * @return  The function always returns 0.
> + */
> +static int mxc_rtc_suspend(struct platform_device *pdev, pm_message_t state)
> +{
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +
> +	if (device_may_wakeup(&pdev->dev))
> +		enable_irq_wake(pdata->irq);
> +
> +	return 0;
> +}
> +
> +/*!
> + * This function is called to correct the system time based on the
> + * current MXC RTC time relative to the time delta saved during
> + * suspend.
> + *
> + * @param   pdev  not used

Not true.

> + *
> + * @return  The function always returns 0.
> + */
> +static int mxc_rtc_resume(struct platform_device *pdev)
> +{
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +
> +	if (device_may_wakeup(&pdev->dev))
> +		disable_irq_wake(pdata->irq);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id mxc_ids[] = {
> +	{.compatible = "fsl,imx53-rtc",},
> +	{}
> +};
> +
> +/*!
> + * Contains pointers to the power management callback functions.

True, but doesn't contain any useful information.

> + */
> +static struct platform_driver mxc_rtc_driver = {
> +	.driver = {
> +		   .name = "mxc_rtc_v8",
> +		   .of_match_table = mxc_ids,
> +		   },

Indentation is broken here.

> +	.probe = mxc_rtc_probe,
> +	.remove = mxc_rtc_remove,
> +	.suspend = mxc_rtc_suspend,
> +	.resume = mxc_rtc_resume,
> +};
> +
> +module_platform_driver(mxc_rtc_driver);
> +
> +MODULE_AUTHOR("Freescale Semiconductor, Inc.");
> +MODULE_DESCRIPTION("Realtime Clock Driver (RTC)");
> +MODULE_LICENSE("GPL");

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] rtc: add mxc driver for i.MX53
@ 2017-11-30  9:50   ` Sascha Hauer
  0 siblings, 0 replies; 43+ messages in thread
From: Sascha Hauer @ 2017-11-30  9:50 UTC (permalink / raw)
  To: linux-kernel-dev
  Cc: Alessandro Zummo, Alexandre Belloni, Mark Rutland,
	open list:REAL TIME CLOCK (RTC) SUBSYSTEM, Patrick Bruenn,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Juergen Borleis, open list, Russell King, Noel Vellemans,
	Rob Herring, Sascha Hauer, Fabio Estevam, Shawn Guo,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE

On Tue, Nov 28, 2017 at 08:39:27AM +0100, linux-kernel-dev@beckhoff.com wrote:
> From: Patrick Bruenn <p.bruenn@beckhoff.com>
> 
> Neither rtc-imxdi nor rtc-mxc are compatible with i.MX53.
> Add a modernized version of mxc_v2 from here:
> http://git.freescale.com/git/cgit.cgi/imx/linux-2.6-imx.git/tree/drivers/rtc/rtc-mxc_v2.c?h=imx_2.6.35_11.09.01
> 
> Changes to that version:
> - updated to v4.15-rc1
> - removed ioctl()
> - removed proc()
> - removed manual(redundant) enable_irq flag
> 
> Signed-off-by: Patrick Bruenn <p.bruenn@beckhoff.com>
> 
> ---
> 
> Open issues:
> - driver naming, should it be merged with rtc-mxc.c ?
> - document DT binding "fsl,imx53-rtc" accordingly
> - Should unused defines be removed or kept for someone else to be
>   useful?
> - Is the use of __raw_readl/writel() correct? Should it be replaced with
>   readl/writel()?
> - suspend/resume() seems different to existing rtc-mxc.c, should I apply
>   the pattern from rtc-mxc.c?
> - On Shawns tree imx53.dtsi has been reverted already[1][2]. Should I split
>   the imx53.dtsi change into a separate patch based on his tree? Or can
>   we still stop the full revert and just remove the imx25-rtc compatible?
>   I am not in a hurry, so we could just wait until the revert landed in
>   Linus tree. Whatever you think is best.
> 
> [1] https://www.spinics.net/lists/arm-kernel/msg617113.html
> [2] commit ee76f7729babd2700afd6f3874449d8084dd85ea
> 
> To: Alessandro Zummo <a.zummo@towertech.it>
> To: Alexandre Belloni <alexandre.belloni@free-electrons.com>
> Cc: Rob Herring <robh+dt@kernel.org>
> Cc: Mark Rutland <mark.rutland@arm.com> (maintainer:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS)
> Cc: linux-rtc@vger.kernel.org (open list:REAL TIME CLOCK (RTC) SUBSYSTEM)
> Cc: devicetree@vger.kernel.org (open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS)
> Cc: linux-kernel@vger.kernel.org (open list)
> Cc: Fabio Estevam <fabio.estevam@nxp.com>
> Cc: Juergen Borleis <jbe@pengutronix.de>
> Cc: Noel Vellemans <Noel.Vellemans@visionbms.com>
> Cc: Shawn Guo <shawnguo@kernel.org>
> Cc: Sascha Hauer <kernel@pengutronix.de> (maintainer:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE)
> Cc: Russell King <linux@armlinux.org.uk> (maintainer:ARM PORT)
> Cc: linux-arm-kernel@lists.infradead.org (moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE)
> ---
>  arch/arm/boot/dts/imx53.dtsi |   2 +-
>  drivers/rtc/Makefile         |   1 +
>  drivers/rtc/rtc-mxc_v2.c     | 531 +++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 533 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/rtc/rtc-mxc_v2.c
> 
> diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi
> index 589a67c5f796..3d1a55e11ea8 100644
> --- a/arch/arm/boot/dts/imx53.dtsi
> +++ b/arch/arm/boot/dts/imx53.dtsi
> @@ -434,7 +434,7 @@
>  			};
>  
>  			srtc: srtc@53fa4000 {
> -				compatible = "fsl,imx53-rtc", "fsl,imx25-rtc";
> +				compatible = "fsl,imx53-rtc";
>  				reg = <0x53fa4000 0x4000>;
>  				interrupts = <24>;
>  				interrupt-parent = <&tzic>;
> diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
> index f2f50c11dc38..fb3dc458c185 100644
> --- a/drivers/rtc/Makefile
> +++ b/drivers/rtc/Makefile
> @@ -106,6 +106,7 @@ obj-$(CONFIG_RTC_DRV_MT6397)	+= rtc-mt6397.o
>  obj-$(CONFIG_RTC_DRV_MT7622)	+= rtc-mt7622.o
>  obj-$(CONFIG_RTC_DRV_MV)	+= rtc-mv.o
>  obj-$(CONFIG_RTC_DRV_MXC)	+= rtc-mxc.o
> +obj-$(CONFIG_RTC_DRV_MXC)	+= rtc-mxc_v2.o
>  obj-$(CONFIG_RTC_DRV_NUC900)	+= rtc-nuc900.o
>  obj-$(CONFIG_RTC_DRV_OMAP)	+= rtc-omap.o
>  obj-$(CONFIG_RTC_DRV_OPAL)	+= rtc-opal.o
> diff --git a/drivers/rtc/rtc-mxc_v2.c b/drivers/rtc/rtc-mxc_v2.c
> new file mode 100644
> index 000000000000..5049b521b38e
> --- /dev/null
> +++ b/drivers/rtc/rtc-mxc_v2.c
> @@ -0,0 +1,531 @@
> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights Reserved.
> + */
> +
> +/*
> + * The code contained herein is licensed under the GNU General Public
> + * License. You may obtain a copy of the GNU General Public License
> + * Version 2 or later at the following locations:
> + *
> + * http://www.opensource.org/licenses/gpl-license.html
> + * http://www.gnu.org/copyleft/gpl.html
> + */
> +/*
> + * Implementation based on rtc-ds1553.c
> + */
> +
> +/*!
> + * @defgroup RTC Real Time Clock (RTC) Driver for i.MX53
> + */
> +/*!
> + * @file rtc-mxc_v2.c
> + * @brief Real Time Clock interface
> + *
> + * This file contains Real Time Clock interface for Linux.
> + *
> + * @ingroup RTC
> + */
> +
> +#include <linux/slab.h>
> +#include <linux/delay.h>
> +#include <linux/rtc.h>
> +#include <linux/module.h>
> +#include <linux/fs.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/platform_device.h>
> +#include <linux/clk.h>
> +#include <linux/device.h>
> +#include <linux/uaccess.h>
> +#include <linux/io.h>
> +//#include <linux/mxc_srtc.h>
> +#define RTC_READ_TIME_47BIT	_IOR('p', 0x20, unsigned long long)
> +/* blocks until LPSCMR is set, returns difference */
> +#define RTC_WAIT_TIME_SET	_IOR('p', 0x21, int64_t)
> +
> +#define SRTC_LPSCLR_LLPSC_LSH	17	/* start bit for LSB time value */
> +
> +#define SRTC_LPPDR_INIT       0x41736166	/* init for glitch detect */
> +
> +#define SRTC_LPCR_SWR_LP      (1 << 0)	/* lp software reset */
> +#define SRTC_LPCR_EN_LP       (1 << 3)	/* lp enable */
> +#define SRTC_LPCR_WAE         (1 << 4)	/* lp wakeup alarm enable */
> +#define SRTC_LPCR_SAE         (1 << 5)	/* lp security alarm enable */
> +#define SRTC_LPCR_SI          (1 << 6)	/* lp security interrupt enable */
> +#define SRTC_LPCR_ALP         (1 << 7)	/* lp alarm flag */
> +#define SRTC_LPCR_LTC         (1 << 8)	/* lp lock time counter */
> +#define SRTC_LPCR_LMC         (1 << 9)	/* lp lock monotonic counter */
> +#define SRTC_LPCR_SV          (1 << 10)	/* lp security violation */
> +#define SRTC_LPCR_NSA         (1 << 11)	/* lp non secure access */
> +#define SRTC_LPCR_NVEIE       (1 << 12)	/* lp non valid state exit int en */
> +#define SRTC_LPCR_IEIE        (1 << 13)	/* lp init state exit int enable */
> +#define SRTC_LPCR_NVE         (1 << 14)	/* lp non valid state exit bit */
> +#define SRTC_LPCR_IE          (1 << 15)	/* lp init state exit bit */
> +
> +#define SRTC_LPCR_ALL_INT_EN (SRTC_LPCR_WAE | SRTC_LPCR_SAE | \
> +			      SRTC_LPCR_SI | SRTC_LPCR_ALP | \
> +			      SRTC_LPCR_NVEIE | SRTC_LPCR_IEIE)
> +
> +#define SRTC_LPSR_TRI         (1 << 0)	/* lp time read invalidate */
> +#define SRTC_LPSR_PGD         (1 << 1)	/* lp power supply glitc detected */
> +#define SRTC_LPSR_CTD         (1 << 2)	/* lp clock tampering detected */
> +#define SRTC_LPSR_ALP         (1 << 3)	/* lp alarm flag */
> +#define SRTC_LPSR_MR          (1 << 4)	/* lp monotonic counter rollover */
> +#define SRTC_LPSR_TR          (1 << 5)	/* lp time rollover */
> +#define SRTC_LPSR_EAD         (1 << 6)	/* lp external alarm detected */
> +#define SRTC_LPSR_IT0         (1 << 7)	/* lp IIM throttle */
> +#define SRTC_LPSR_IT1         (1 << 8)
> +#define SRTC_LPSR_IT2         (1 << 9)
> +#define SRTC_LPSR_SM0         (1 << 10)	/* lp security mode */
> +#define SRTC_LPSR_SM1         (1 << 11)
> +#define SRTC_LPSR_STATE_LP0   (1 << 12)	/* lp state */
> +#define SRTC_LPSR_STATE_LP1   (1 << 13)
> +#define SRTC_LPSR_NVES        (1 << 14)	/* lp non-valid state exit status */
> +#define SRTC_LPSR_IES         (1 << 15)	/* lp init state exit status */
> +
> +#define MAX_PIE_NUM     15
> +#define MAX_PIE_FREQ    32768
> +#define MIN_PIE_FREQ	1
> +
> +#define SRTC_PI0         (1 << 0)
> +#define SRTC_PI1         (1 << 1)
> +#define SRTC_PI2         (1 << 2)
> +#define SRTC_PI3         (1 << 3)
> +#define SRTC_PI4         (1 << 4)
> +#define SRTC_PI5         (1 << 5)
> +#define SRTC_PI6         (1 << 6)
> +#define SRTC_PI7         (1 << 7)
> +#define SRTC_PI8         (1 << 8)
> +#define SRTC_PI9         (1 << 9)
> +#define SRTC_PI10        (1 << 10)
> +#define SRTC_PI11        (1 << 11)
> +#define SRTC_PI12        (1 << 12)
> +#define SRTC_PI13        (1 << 13)
> +#define SRTC_PI14        (1 << 14)
> +#define SRTC_PI15        (1 << 15)
> +
> +#define PIT_ALL_ON      (SRTC_PI1 | SRTC_PI2 | SRTC_PI3 | \
> +			SRTC_PI4 | SRTC_PI5 | SRTC_PI6 | SRTC_PI7 | \
> +			SRTC_PI8 | SRTC_PI9 | SRTC_PI10 | SRTC_PI11 | \
> +			SRTC_PI12 | SRTC_PI13 | SRTC_PI14 | SRTC_PI15)
> +
> +#define SRTC_SWR_HP      (1 << 0)	/* hp software reset */
> +#define SRTC_EN_HP       (1 << 3)	/* hp enable */
> +#define SRTC_TS          (1 << 4)	/* time synchronize hp with lp */
> +
> +#define SRTC_IE_AHP      (1 << 16)	/* Alarm HP Interrupt Enable bit */
> +#define SRTC_IE_WDHP     (1 << 18)	/* Write Done HP Interrupt Enable bit */
> +#define SRTC_IE_WDLP     (1 << 19)	/* Write Done LP Interrupt Enable bit */
> +
> +#define SRTC_ISR_AHP     (1 << 16)	/* interrupt status: alarm hp */
> +#define SRTC_ISR_WDHP    (1 << 18)	/* interrupt status: write done hp */
> +#define SRTC_ISR_WDLP    (1 << 19)	/* interrupt status: write done lp */
> +#define SRTC_ISR_WPHP    (1 << 20)	/* interrupt status: write pending hp */
> +#define SRTC_ISR_WPLP    (1 << 21)	/* interrupt status: write pending lp */
> +
> +#define SRTC_LPSCMR	0x00	/* LP Secure Counter MSB Reg */
> +#define SRTC_LPSCLR	0x04	/* LP Secure Counter LSB Reg */
> +#define SRTC_LPSAR	0x08	/* LP Secure Alarm Reg */
> +#define SRTC_LPSMCR	0x0C	/* LP Secure Monotonic Counter Reg */
> +#define SRTC_LPCR	0x10	/* LP Control Reg */
> +#define SRTC_LPSR	0x14	/* LP Status Reg */
> +#define SRTC_LPPDR	0x18	/* LP Power Supply Glitch Detector Reg */
> +#define SRTC_LPGR	0x1C	/* LP General Purpose Reg */
> +#define SRTC_HPCMR	0x20	/* HP Counter MSB Reg */
> +#define SRTC_HPCLR	0x24	/* HP Counter LSB Reg */
> +#define SRTC_HPAMR	0x28	/* HP Alarm MSB Reg */
> +#define SRTC_HPALR	0x2C	/* HP Alarm LSB Reg */
> +#define SRTC_HPCR	0x30	/* HP Control Reg */
> +#define SRTC_HPISR	0x34	/* HP Interrupt Status Reg */
> +#define SRTC_HPIENR	0x38	/* HP Interrupt Enable Reg */
> +
> +#define SRTC_SECMODE_MASK	0x3	/* the mask of SRTC security mode */
> +#define SRTC_SECMODE_LOW	0x0	/* Low Security */
> +#define SRTC_SECMODE_MED	0x1	/* Medium Security */
> +#define SRTC_SECMODE_HIGH	0x2	/* High Security */
> +#define SRTC_SECMODE_RESERVED	0x3	/* Reserved */
> +
> +struct rtc_drv_data {
> +	struct rtc_device *rtc;
> +	void __iomem *ioaddr;
> +	int irq;
> +	struct clk *clk;
> +};
> +
> +static DEFINE_SPINLOCK(rtc_lock);

The lock should be a member of your driver data struct.

> +
> +/*!
> + * This function does write synchronization for writes to the lp srtc block.
> + * To take care of the asynchronous CKIL clock, all writes from the IP domain
> + * will be synchronized to the CKIL domain.
> + */

Please drop this exclamation mark at the beginning of comments. If
anything, use kerneldoc style for the function descriptions.

> +static inline void rtc_write_sync_lp(void __iomem *ioaddr)
> +{
> +	unsigned int i, count;
> +	/* Wait for 3 CKIL cycles */
> +	for (i = 0; i < 3; i++) {
> +		count = readl(ioaddr + SRTC_LPSCLR);
> +		while ((readl(ioaddr + SRTC_LPSCLR)) == count)
> +			;

This becomes an infinite loop when the hardware is not working as
expected. You should avoid that.

> +	}
> +}
> +
> +/*!
> + * This function updates the RTC alarm registers and then clears all the
> + * interrupt status bits.
> + *
> + * @param  alrm         the new alarm value to be updated in the RTC
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int rtc_update_alarm(struct device *dev, struct rtc_time *alrm)
> +{

mxc_rtc_update_alarm please like the other device specific functions
please. Same for rtc_write_sync_lp().

> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	void __iomem *ioaddr = pdata->ioaddr;
> +	struct rtc_time alarm_tm, now_tm;
> +	unsigned long now, time;
> +	int ret;
> +
> +	now = __raw_readl(ioaddr + SRTC_LPSCMR);
> +	rtc_time_to_tm(now, &now_tm);
> +
> +	alarm_tm.tm_year = now_tm.tm_year;
> +	alarm_tm.tm_mon = now_tm.tm_mon;
> +	alarm_tm.tm_mday = now_tm.tm_mday;
> +
> +	alarm_tm.tm_hour = alrm->tm_hour;
> +	alarm_tm.tm_min = alrm->tm_min;
> +	alarm_tm.tm_sec = alrm->tm_sec;
> +
> +	rtc_tm_to_time(&now_tm, &now);
> +	rtc_tm_to_time(&alarm_tm, &time);
> +
> +	if (time < now) {
> +		time += 60 * 60 * 24;
> +		rtc_time_to_tm(time, &alarm_tm);
> +	}
> +	ret = rtc_tm_to_time(&alarm_tm, &time);
> +
> +	__raw_writel(time, ioaddr + SRTC_LPSAR);
> +
> +	/* clear alarm interrupt status bit */
> +	__raw_writel(SRTC_LPSR_ALP, ioaddr + SRTC_LPSR);
> +
> +	return ret;
> +}
> +
> +/*!
> + * This function is the RTC interrupt service routine.
> + *
> + * @param  irq          RTC IRQ number
> + * @param  dev_id       device ID which is not used
> + *
> + * @return IRQ_HANDLED as defined in the include/linux/interrupt.h file.
> + */
> +static irqreturn_t mxc_rtc_interrupt(int irq, void *dev_id)
> +{
> +	struct platform_device *pdev = dev_id;
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +	void __iomem *ioaddr = pdata->ioaddr;
> +	u32 lp_status, lp_cr;
> +	u32 events = 0;
> +
> +	lp_status = __raw_readl(ioaddr + SRTC_LPSR);
> +	lp_cr = __raw_readl(ioaddr + SRTC_LPCR);
> +
> +	/* update irq data & counter */
> +	if (lp_status & SRTC_LPSR_ALP) {
> +		if (lp_cr & SRTC_LPCR_ALP)
> +			events |= (RTC_AF | RTC_IRQF);
> +
> +		/* disable further lp alarm interrupts */
> +		lp_cr &= ~(SRTC_LPCR_ALP | SRTC_LPCR_WAE);
> +	}
> +
> +	/* Update interrupt enables */
> +	__raw_writel(lp_cr, ioaddr + SRTC_LPCR);
> +
> +	/* clear interrupt status */
> +	__raw_writel(lp_status, ioaddr + SRTC_LPSR);
> +
> +	rtc_write_sync_lp(ioaddr);
> +	rtc_update_irq(pdata->rtc, 1, events);
> +	return IRQ_HANDLED;
> +}

What about locking? You lock the read/modify/write operation of the LPCR
register below, and so you should do here.

> +
> +/*!
> + * This function reads the current RTC time into tm in Gregorian date.
> + *
> + * @param  tm           contains the RTC time value upon return
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int mxc_rtc_read_time(struct device *dev, struct rtc_time *tm)
> +{
> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	time_t now = readl(pdata->ioaddr + SRTC_LPSCMR);
> +
> +	rtc_time_to_tm(now, tm);
> +	return rtc_valid_tm(tm);
> +}
> +
> +/*!
> + * This function sets the internal RTC time based on tm in Gregorian date.
> + *
> + * @param  tm           the time value to be set in the RTC
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int mxc_rtc_set_time(struct device *dev, struct rtc_time *tm)
> +{
> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	time64_t time = rtc_tm_to_time64(tm);
> +
> +	if (time > UINT_MAX) {
> +		dev_warn(dev, "time_t has overflow\n");
> +	}

SIGH. Who builds such a RTC in the 21st century?

Shouldn't this return an error?

> +
> +	writel(time, pdata->ioaddr + SRTC_LPSCMR);
> +	rtc_write_sync_lp(pdata->ioaddr);
> +	return 0;
> +}
> +
> +/*!
> + * This function reads the current alarm value into the passed in \b alrm
> + * argument. It updates the \b alrm's pending field value based on the whether
> + * an alarm interrupt occurs or not.
> + *
> + * @param  alrm         contains the RTC alarm value upon return
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int mxc_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
> +{
> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	void __iomem *ioaddr = pdata->ioaddr;
> +
> +	rtc_time_to_tm(__raw_readl(ioaddr + SRTC_LPSAR), &alrm->time);
> +	alrm->pending =
> +	    ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_ALP) != 0) ? 1 : 0;

if/else would be much easier to read here.

> +
> +	return 0;
> +}
> +
> +static int mxc_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
> +{
> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	unsigned long lock_flags = 0;
> +	u32 lp_cr;
> +
> +	spin_lock_irqsave(&rtc_lock, lock_flags);
> +	lp_cr = __raw_readl(pdata->ioaddr + SRTC_LPCR);
> +
> +	if (enable)
> +		lp_cr |= (SRTC_LPCR_ALP | SRTC_LPCR_WAE);
> +	else
> +		lp_cr &= ~(SRTC_LPCR_ALP | SRTC_LPCR_WAE);
> +
> +	__raw_writel(lp_cr, pdata->ioaddr + SRTC_LPCR);
> +	spin_unlock_irqrestore(&rtc_lock, lock_flags);
> +	return 0;
> +}
> +
> +/*!
> + * This function sets the RTC alarm based on passed in alrm.
> + *
> + * @param  alrm         the alarm value to be set in the RTC
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int mxc_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
> +{
> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	void __iomem *ioaddr = pdata->ioaddr;
> +	int ret;
> +
> +	ret = rtc_update_alarm(dev, &alrm->time);
> +	if (!ret)
> +		mxc_rtc_alarm_irq_enable(dev, alrm->enabled);
> +
> +	rtc_write_sync_lp(ioaddr);
> +	return ret;
> +}
> +
> +/*!
> + * The RTC driver structure
> + */
> +static const struct rtc_class_ops mxc_rtc_ops = {
> +	.read_time = mxc_rtc_read_time,
> +	.set_time = mxc_rtc_set_time,
> +	.read_alarm = mxc_rtc_read_alarm,
> +	.set_alarm = mxc_rtc_set_alarm,
> +	.alarm_irq_enable = mxc_rtc_alarm_irq_enable,
> +};
> +
> +/*! MXC RTC Power management control */
> +static int mxc_rtc_probe(struct platform_device *pdev)
> +{
> +	struct timespec tv;
> +	struct resource *res;
> +	struct rtc_drv_data *pdata = NULL;

No need to initialize.

> +	void __iomem *ioaddr;
> +	int ret = 0;
> +
> +	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
> +	if (!pdata)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res)
> +		return -ENODEV;
> +
> +	pdata->ioaddr = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(pdata->ioaddr))
> +		return PTR_ERR(pdata->ioaddr);
> +
> +	ioaddr = pdata->ioaddr;
> +
> +	pdata->clk = devm_clk_get(&pdev->dev, NULL);
> +	if (IS_ERR(pdata->clk)) {
> +		dev_err(&pdev->dev, "unable to get rtc clock!\n");
> +		return PTR_ERR(pdata->clk);
> +	}
> +	ret = clk_prepare_enable(pdata->clk);
> +	if (ret)
> +		return ret;
> +
> +	/* Configure and enable the RTC */
> +	pdata->irq = platform_get_irq(pdev, 0);
> +	if (pdata->irq >= 0
> +	    && devm_request_irq(&pdev->dev, pdata->irq, mxc_rtc_interrupt,
> +				IRQF_SHARED, pdev->name, pdev) < 0) {
> +		dev_warn(&pdev->dev, "interrupt not available.\n");
> +		pdata->irq = -1;
> +	}

I would just make the interrupt mandatory. I see no valid reason why it
shouldn't be available and it makes your driver logic simpler when you
can just assume it's available.

> +
> +	if (pdata->irq >= 0)
> +		device_init_wakeup(&pdev->dev, 1);
> +
> +	/* initialize glitch detect */
> +	__raw_writel(SRTC_LPPDR_INIT, ioaddr + SRTC_LPPDR);
> +	udelay(100);
> +
> +	/* clear lp interrupt status */
> +	__raw_writel(0xFFFFFFFF, ioaddr + SRTC_LPSR);
> +	udelay(100);
> +
> +	/* move out of init state */
> +	__raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NSA), ioaddr + SRTC_LPCR);
> +
> +	udelay(100);
> +
> +	while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_IES) == 0)
> +		;
> +
> +	/* move out of non-valid state */
> +	__raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NVE | SRTC_LPCR_NSA |
> +		      SRTC_LPCR_EN_LP), ioaddr + SRTC_LPCR);
> +
> +	udelay(100);

Where do all these udelay() come from? Are they really needed?

> +
> +	while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_NVES) == 0)
> +		;
> +
> +	__raw_writel(0xFFFFFFFF, ioaddr + SRTC_LPSR);
> +	udelay(100);
> +
> +	platform_set_drvdata(pdev, pdata);
> +	pdata->rtc =
> +	    devm_rtc_device_register(&pdev->dev, pdev->name, &mxc_rtc_ops,
> +				     THIS_MODULE);
> +	if (IS_ERR(pdata->rtc)) {
> +		ret = PTR_ERR(pdata->rtc);
> +		goto exit_put_clk;
> +	}
> +
> +	tv.tv_nsec = 0;
> +	tv.tv_sec = __raw_readl(ioaddr + SRTC_LPSCMR);

Why this? tv is set but unused.

> +
> +	/* By default, devices should wakeup if they can */
> +	/* So srtc is set as "should wakeup" as it can */
> +	device_init_wakeup(&pdev->dev, 1);

Why is this done twice, one time only when we have a valid irq? This
looks fishy.

> +
> +	return ret;
> +
> +exit_put_clk:
> +	clk_disable_unprepare(pdata->clk);
> +	return ret;
> +}
> +
> +static int __exit mxc_rtc_remove(struct platform_device *pdev)
> +{
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +
> +	clk_disable_unprepare(pdata->clk);
> +	return 0;
> +}
> +
> +/*!
> + * This function is called to save the system time delta relative to
> + * the MXC RTC when enterring a low power state. This time delta is
> + * then used on resume to adjust the system time to account for time
> + * loss while suspended.
> + *
> + * @param   pdev  not used

Not true.

> + * @param   state Power state to enter.
> + *
> + * @return  The function always returns 0.
> + */
> +static int mxc_rtc_suspend(struct platform_device *pdev, pm_message_t state)
> +{
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +
> +	if (device_may_wakeup(&pdev->dev))
> +		enable_irq_wake(pdata->irq);
> +
> +	return 0;
> +}
> +
> +/*!
> + * This function is called to correct the system time based on the
> + * current MXC RTC time relative to the time delta saved during
> + * suspend.
> + *
> + * @param   pdev  not used

Not true.

> + *
> + * @return  The function always returns 0.
> + */
> +static int mxc_rtc_resume(struct platform_device *pdev)
> +{
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +
> +	if (device_may_wakeup(&pdev->dev))
> +		disable_irq_wake(pdata->irq);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id mxc_ids[] = {
> +	{.compatible = "fsl,imx53-rtc",},
> +	{}
> +};
> +
> +/*!
> + * Contains pointers to the power management callback functions.

True, but doesn't contain any useful information.

> + */
> +static struct platform_driver mxc_rtc_driver = {
> +	.driver = {
> +		   .name = "mxc_rtc_v8",
> +		   .of_match_table = mxc_ids,
> +		   },

Indentation is broken here.

> +	.probe = mxc_rtc_probe,
> +	.remove = mxc_rtc_remove,
> +	.suspend = mxc_rtc_suspend,
> +	.resume = mxc_rtc_resume,
> +};
> +
> +module_platform_driver(mxc_rtc_driver);
> +
> +MODULE_AUTHOR("Freescale Semiconductor, Inc.");
> +MODULE_DESCRIPTION("Realtime Clock Driver (RTC)");
> +MODULE_LICENSE("GPL");

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] rtc: add mxc driver for i.MX53
@ 2017-11-30  9:50   ` Sascha Hauer
  0 siblings, 0 replies; 43+ messages in thread
From: Sascha Hauer @ 2017-11-30  9:50 UTC (permalink / raw)
  To: linux-kernel-dev-QonKdJ6Bx35Wk0Htik3J/w
  Cc: Alessandro Zummo, Alexandre Belloni, Mark Rutland,
	open list:REAL TIME CLOCK (RTC) SUBSYSTEM, Patrick Bruenn,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Juergen Borleis, open list, Russell King, Noel Vellemans,
	Rob Herring, Sascha Hauer, Fabio Estevam, Shawn Guo,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE

On Tue, Nov 28, 2017 at 08:39:27AM +0100, linux-kernel-dev-QonKdJ6Bx35Wk0Htik3J/w@public.gmane.org wrote:
> From: Patrick Bruenn <p.bruenn-QonKdJ6Bx35Wk0Htik3J/w@public.gmane.org>
> 
> Neither rtc-imxdi nor rtc-mxc are compatible with i.MX53.
> Add a modernized version of mxc_v2 from here:
> http://git.freescale.com/git/cgit.cgi/imx/linux-2.6-imx.git/tree/drivers/rtc/rtc-mxc_v2.c?h=imx_2.6.35_11.09.01
> 
> Changes to that version:
> - updated to v4.15-rc1
> - removed ioctl()
> - removed proc()
> - removed manual(redundant) enable_irq flag
> 
> Signed-off-by: Patrick Bruenn <p.bruenn-QonKdJ6Bx35Wk0Htik3J/w@public.gmane.org>
> 
> ---
> 
> Open issues:
> - driver naming, should it be merged with rtc-mxc.c ?
> - document DT binding "fsl,imx53-rtc" accordingly
> - Should unused defines be removed or kept for someone else to be
>   useful?
> - Is the use of __raw_readl/writel() correct? Should it be replaced with
>   readl/writel()?
> - suspend/resume() seems different to existing rtc-mxc.c, should I apply
>   the pattern from rtc-mxc.c?
> - On Shawns tree imx53.dtsi has been reverted already[1][2]. Should I split
>   the imx53.dtsi change into a separate patch based on his tree? Or can
>   we still stop the full revert and just remove the imx25-rtc compatible?
>   I am not in a hurry, so we could just wait until the revert landed in
>   Linus tree. Whatever you think is best.
> 
> [1] https://www.spinics.net/lists/arm-kernel/msg617113.html
> [2] commit ee76f7729babd2700afd6f3874449d8084dd85ea
> 
> To: Alessandro Zummo <a.zummo-BfzFCNDTiLLj+vYz1yj4TQ@public.gmane.org>
> To: Alexandre Belloni <alexandre.belloni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> Cc: Rob Herring <robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> Cc: Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org> (maintainer:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS)
> Cc: linux-rtc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org (open list:REAL TIME CLOCK (RTC) SUBSYSTEM)
> Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org (open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS)
> Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org (open list)
> Cc: Fabio Estevam <fabio.estevam-3arQi8VN3Tc@public.gmane.org>
> Cc: Juergen Borleis <jbe-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
> Cc: Noel Vellemans <Noel.Vellemans-8UENEgx6w+makBO8gow8eQ@public.gmane.org>
> Cc: Shawn Guo <shawnguo-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> Cc: Sascha Hauer <kernel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org> (maintainer:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE)
> Cc: Russell King <linux-I+IVW8TIWO2tmTQ+vhA3Yw@public.gmane.org> (maintainer:ARM PORT)
> Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org (moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE)
> ---
>  arch/arm/boot/dts/imx53.dtsi |   2 +-
>  drivers/rtc/Makefile         |   1 +
>  drivers/rtc/rtc-mxc_v2.c     | 531 +++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 533 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/rtc/rtc-mxc_v2.c
> 
> diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi
> index 589a67c5f796..3d1a55e11ea8 100644
> --- a/arch/arm/boot/dts/imx53.dtsi
> +++ b/arch/arm/boot/dts/imx53.dtsi
> @@ -434,7 +434,7 @@
>  			};
>  
>  			srtc: srtc@53fa4000 {
> -				compatible = "fsl,imx53-rtc", "fsl,imx25-rtc";
> +				compatible = "fsl,imx53-rtc";
>  				reg = <0x53fa4000 0x4000>;
>  				interrupts = <24>;
>  				interrupt-parent = <&tzic>;
> diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
> index f2f50c11dc38..fb3dc458c185 100644
> --- a/drivers/rtc/Makefile
> +++ b/drivers/rtc/Makefile
> @@ -106,6 +106,7 @@ obj-$(CONFIG_RTC_DRV_MT6397)	+= rtc-mt6397.o
>  obj-$(CONFIG_RTC_DRV_MT7622)	+= rtc-mt7622.o
>  obj-$(CONFIG_RTC_DRV_MV)	+= rtc-mv.o
>  obj-$(CONFIG_RTC_DRV_MXC)	+= rtc-mxc.o
> +obj-$(CONFIG_RTC_DRV_MXC)	+= rtc-mxc_v2.o
>  obj-$(CONFIG_RTC_DRV_NUC900)	+= rtc-nuc900.o
>  obj-$(CONFIG_RTC_DRV_OMAP)	+= rtc-omap.o
>  obj-$(CONFIG_RTC_DRV_OPAL)	+= rtc-opal.o
> diff --git a/drivers/rtc/rtc-mxc_v2.c b/drivers/rtc/rtc-mxc_v2.c
> new file mode 100644
> index 000000000000..5049b521b38e
> --- /dev/null
> +++ b/drivers/rtc/rtc-mxc_v2.c
> @@ -0,0 +1,531 @@
> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights Reserved.
> + */
> +
> +/*
> + * The code contained herein is licensed under the GNU General Public
> + * License. You may obtain a copy of the GNU General Public License
> + * Version 2 or later at the following locations:
> + *
> + * http://www.opensource.org/licenses/gpl-license.html
> + * http://www.gnu.org/copyleft/gpl.html
> + */
> +/*
> + * Implementation based on rtc-ds1553.c
> + */
> +
> +/*!
> + * @defgroup RTC Real Time Clock (RTC) Driver for i.MX53
> + */
> +/*!
> + * @file rtc-mxc_v2.c
> + * @brief Real Time Clock interface
> + *
> + * This file contains Real Time Clock interface for Linux.
> + *
> + * @ingroup RTC
> + */
> +
> +#include <linux/slab.h>
> +#include <linux/delay.h>
> +#include <linux/rtc.h>
> +#include <linux/module.h>
> +#include <linux/fs.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/platform_device.h>
> +#include <linux/clk.h>
> +#include <linux/device.h>
> +#include <linux/uaccess.h>
> +#include <linux/io.h>
> +//#include <linux/mxc_srtc.h>
> +#define RTC_READ_TIME_47BIT	_IOR('p', 0x20, unsigned long long)
> +/* blocks until LPSCMR is set, returns difference */
> +#define RTC_WAIT_TIME_SET	_IOR('p', 0x21, int64_t)
> +
> +#define SRTC_LPSCLR_LLPSC_LSH	17	/* start bit for LSB time value */
> +
> +#define SRTC_LPPDR_INIT       0x41736166	/* init for glitch detect */
> +
> +#define SRTC_LPCR_SWR_LP      (1 << 0)	/* lp software reset */
> +#define SRTC_LPCR_EN_LP       (1 << 3)	/* lp enable */
> +#define SRTC_LPCR_WAE         (1 << 4)	/* lp wakeup alarm enable */
> +#define SRTC_LPCR_SAE         (1 << 5)	/* lp security alarm enable */
> +#define SRTC_LPCR_SI          (1 << 6)	/* lp security interrupt enable */
> +#define SRTC_LPCR_ALP         (1 << 7)	/* lp alarm flag */
> +#define SRTC_LPCR_LTC         (1 << 8)	/* lp lock time counter */
> +#define SRTC_LPCR_LMC         (1 << 9)	/* lp lock monotonic counter */
> +#define SRTC_LPCR_SV          (1 << 10)	/* lp security violation */
> +#define SRTC_LPCR_NSA         (1 << 11)	/* lp non secure access */
> +#define SRTC_LPCR_NVEIE       (1 << 12)	/* lp non valid state exit int en */
> +#define SRTC_LPCR_IEIE        (1 << 13)	/* lp init state exit int enable */
> +#define SRTC_LPCR_NVE         (1 << 14)	/* lp non valid state exit bit */
> +#define SRTC_LPCR_IE          (1 << 15)	/* lp init state exit bit */
> +
> +#define SRTC_LPCR_ALL_INT_EN (SRTC_LPCR_WAE | SRTC_LPCR_SAE | \
> +			      SRTC_LPCR_SI | SRTC_LPCR_ALP | \
> +			      SRTC_LPCR_NVEIE | SRTC_LPCR_IEIE)
> +
> +#define SRTC_LPSR_TRI         (1 << 0)	/* lp time read invalidate */
> +#define SRTC_LPSR_PGD         (1 << 1)	/* lp power supply glitc detected */
> +#define SRTC_LPSR_CTD         (1 << 2)	/* lp clock tampering detected */
> +#define SRTC_LPSR_ALP         (1 << 3)	/* lp alarm flag */
> +#define SRTC_LPSR_MR          (1 << 4)	/* lp monotonic counter rollover */
> +#define SRTC_LPSR_TR          (1 << 5)	/* lp time rollover */
> +#define SRTC_LPSR_EAD         (1 << 6)	/* lp external alarm detected */
> +#define SRTC_LPSR_IT0         (1 << 7)	/* lp IIM throttle */
> +#define SRTC_LPSR_IT1         (1 << 8)
> +#define SRTC_LPSR_IT2         (1 << 9)
> +#define SRTC_LPSR_SM0         (1 << 10)	/* lp security mode */
> +#define SRTC_LPSR_SM1         (1 << 11)
> +#define SRTC_LPSR_STATE_LP0   (1 << 12)	/* lp state */
> +#define SRTC_LPSR_STATE_LP1   (1 << 13)
> +#define SRTC_LPSR_NVES        (1 << 14)	/* lp non-valid state exit status */
> +#define SRTC_LPSR_IES         (1 << 15)	/* lp init state exit status */
> +
> +#define MAX_PIE_NUM     15
> +#define MAX_PIE_FREQ    32768
> +#define MIN_PIE_FREQ	1
> +
> +#define SRTC_PI0         (1 << 0)
> +#define SRTC_PI1         (1 << 1)
> +#define SRTC_PI2         (1 << 2)
> +#define SRTC_PI3         (1 << 3)
> +#define SRTC_PI4         (1 << 4)
> +#define SRTC_PI5         (1 << 5)
> +#define SRTC_PI6         (1 << 6)
> +#define SRTC_PI7         (1 << 7)
> +#define SRTC_PI8         (1 << 8)
> +#define SRTC_PI9         (1 << 9)
> +#define SRTC_PI10        (1 << 10)
> +#define SRTC_PI11        (1 << 11)
> +#define SRTC_PI12        (1 << 12)
> +#define SRTC_PI13        (1 << 13)
> +#define SRTC_PI14        (1 << 14)
> +#define SRTC_PI15        (1 << 15)
> +
> +#define PIT_ALL_ON      (SRTC_PI1 | SRTC_PI2 | SRTC_PI3 | \
> +			SRTC_PI4 | SRTC_PI5 | SRTC_PI6 | SRTC_PI7 | \
> +			SRTC_PI8 | SRTC_PI9 | SRTC_PI10 | SRTC_PI11 | \
> +			SRTC_PI12 | SRTC_PI13 | SRTC_PI14 | SRTC_PI15)
> +
> +#define SRTC_SWR_HP      (1 << 0)	/* hp software reset */
> +#define SRTC_EN_HP       (1 << 3)	/* hp enable */
> +#define SRTC_TS          (1 << 4)	/* time synchronize hp with lp */
> +
> +#define SRTC_IE_AHP      (1 << 16)	/* Alarm HP Interrupt Enable bit */
> +#define SRTC_IE_WDHP     (1 << 18)	/* Write Done HP Interrupt Enable bit */
> +#define SRTC_IE_WDLP     (1 << 19)	/* Write Done LP Interrupt Enable bit */
> +
> +#define SRTC_ISR_AHP     (1 << 16)	/* interrupt status: alarm hp */
> +#define SRTC_ISR_WDHP    (1 << 18)	/* interrupt status: write done hp */
> +#define SRTC_ISR_WDLP    (1 << 19)	/* interrupt status: write done lp */
> +#define SRTC_ISR_WPHP    (1 << 20)	/* interrupt status: write pending hp */
> +#define SRTC_ISR_WPLP    (1 << 21)	/* interrupt status: write pending lp */
> +
> +#define SRTC_LPSCMR	0x00	/* LP Secure Counter MSB Reg */
> +#define SRTC_LPSCLR	0x04	/* LP Secure Counter LSB Reg */
> +#define SRTC_LPSAR	0x08	/* LP Secure Alarm Reg */
> +#define SRTC_LPSMCR	0x0C	/* LP Secure Monotonic Counter Reg */
> +#define SRTC_LPCR	0x10	/* LP Control Reg */
> +#define SRTC_LPSR	0x14	/* LP Status Reg */
> +#define SRTC_LPPDR	0x18	/* LP Power Supply Glitch Detector Reg */
> +#define SRTC_LPGR	0x1C	/* LP General Purpose Reg */
> +#define SRTC_HPCMR	0x20	/* HP Counter MSB Reg */
> +#define SRTC_HPCLR	0x24	/* HP Counter LSB Reg */
> +#define SRTC_HPAMR	0x28	/* HP Alarm MSB Reg */
> +#define SRTC_HPALR	0x2C	/* HP Alarm LSB Reg */
> +#define SRTC_HPCR	0x30	/* HP Control Reg */
> +#define SRTC_HPISR	0x34	/* HP Interrupt Status Reg */
> +#define SRTC_HPIENR	0x38	/* HP Interrupt Enable Reg */
> +
> +#define SRTC_SECMODE_MASK	0x3	/* the mask of SRTC security mode */
> +#define SRTC_SECMODE_LOW	0x0	/* Low Security */
> +#define SRTC_SECMODE_MED	0x1	/* Medium Security */
> +#define SRTC_SECMODE_HIGH	0x2	/* High Security */
> +#define SRTC_SECMODE_RESERVED	0x3	/* Reserved */
> +
> +struct rtc_drv_data {
> +	struct rtc_device *rtc;
> +	void __iomem *ioaddr;
> +	int irq;
> +	struct clk *clk;
> +};
> +
> +static DEFINE_SPINLOCK(rtc_lock);

The lock should be a member of your driver data struct.

> +
> +/*!
> + * This function does write synchronization for writes to the lp srtc block.
> + * To take care of the asynchronous CKIL clock, all writes from the IP domain
> + * will be synchronized to the CKIL domain.
> + */

Please drop this exclamation mark at the beginning of comments. If
anything, use kerneldoc style for the function descriptions.

> +static inline void rtc_write_sync_lp(void __iomem *ioaddr)
> +{
> +	unsigned int i, count;
> +	/* Wait for 3 CKIL cycles */
> +	for (i = 0; i < 3; i++) {
> +		count = readl(ioaddr + SRTC_LPSCLR);
> +		while ((readl(ioaddr + SRTC_LPSCLR)) == count)
> +			;

This becomes an infinite loop when the hardware is not working as
expected. You should avoid that.

> +	}
> +}
> +
> +/*!
> + * This function updates the RTC alarm registers and then clears all the
> + * interrupt status bits.
> + *
> + * @param  alrm         the new alarm value to be updated in the RTC
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int rtc_update_alarm(struct device *dev, struct rtc_time *alrm)
> +{

mxc_rtc_update_alarm please like the other device specific functions
please. Same for rtc_write_sync_lp().

> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	void __iomem *ioaddr = pdata->ioaddr;
> +	struct rtc_time alarm_tm, now_tm;
> +	unsigned long now, time;
> +	int ret;
> +
> +	now = __raw_readl(ioaddr + SRTC_LPSCMR);
> +	rtc_time_to_tm(now, &now_tm);
> +
> +	alarm_tm.tm_year = now_tm.tm_year;
> +	alarm_tm.tm_mon = now_tm.tm_mon;
> +	alarm_tm.tm_mday = now_tm.tm_mday;
> +
> +	alarm_tm.tm_hour = alrm->tm_hour;
> +	alarm_tm.tm_min = alrm->tm_min;
> +	alarm_tm.tm_sec = alrm->tm_sec;
> +
> +	rtc_tm_to_time(&now_tm, &now);
> +	rtc_tm_to_time(&alarm_tm, &time);
> +
> +	if (time < now) {
> +		time += 60 * 60 * 24;
> +		rtc_time_to_tm(time, &alarm_tm);
> +	}
> +	ret = rtc_tm_to_time(&alarm_tm, &time);
> +
> +	__raw_writel(time, ioaddr + SRTC_LPSAR);
> +
> +	/* clear alarm interrupt status bit */
> +	__raw_writel(SRTC_LPSR_ALP, ioaddr + SRTC_LPSR);
> +
> +	return ret;
> +}
> +
> +/*!
> + * This function is the RTC interrupt service routine.
> + *
> + * @param  irq          RTC IRQ number
> + * @param  dev_id       device ID which is not used
> + *
> + * @return IRQ_HANDLED as defined in the include/linux/interrupt.h file.
> + */
> +static irqreturn_t mxc_rtc_interrupt(int irq, void *dev_id)
> +{
> +	struct platform_device *pdev = dev_id;
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +	void __iomem *ioaddr = pdata->ioaddr;
> +	u32 lp_status, lp_cr;
> +	u32 events = 0;
> +
> +	lp_status = __raw_readl(ioaddr + SRTC_LPSR);
> +	lp_cr = __raw_readl(ioaddr + SRTC_LPCR);
> +
> +	/* update irq data & counter */
> +	if (lp_status & SRTC_LPSR_ALP) {
> +		if (lp_cr & SRTC_LPCR_ALP)
> +			events |= (RTC_AF | RTC_IRQF);
> +
> +		/* disable further lp alarm interrupts */
> +		lp_cr &= ~(SRTC_LPCR_ALP | SRTC_LPCR_WAE);
> +	}
> +
> +	/* Update interrupt enables */
> +	__raw_writel(lp_cr, ioaddr + SRTC_LPCR);
> +
> +	/* clear interrupt status */
> +	__raw_writel(lp_status, ioaddr + SRTC_LPSR);
> +
> +	rtc_write_sync_lp(ioaddr);
> +	rtc_update_irq(pdata->rtc, 1, events);
> +	return IRQ_HANDLED;
> +}

What about locking? You lock the read/modify/write operation of the LPCR
register below, and so you should do here.

> +
> +/*!
> + * This function reads the current RTC time into tm in Gregorian date.
> + *
> + * @param  tm           contains the RTC time value upon return
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int mxc_rtc_read_time(struct device *dev, struct rtc_time *tm)
> +{
> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	time_t now = readl(pdata->ioaddr + SRTC_LPSCMR);
> +
> +	rtc_time_to_tm(now, tm);
> +	return rtc_valid_tm(tm);
> +}
> +
> +/*!
> + * This function sets the internal RTC time based on tm in Gregorian date.
> + *
> + * @param  tm           the time value to be set in the RTC
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int mxc_rtc_set_time(struct device *dev, struct rtc_time *tm)
> +{
> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	time64_t time = rtc_tm_to_time64(tm);
> +
> +	if (time > UINT_MAX) {
> +		dev_warn(dev, "time_t has overflow\n");
> +	}

SIGH. Who builds such a RTC in the 21st century?

Shouldn't this return an error?

> +
> +	writel(time, pdata->ioaddr + SRTC_LPSCMR);
> +	rtc_write_sync_lp(pdata->ioaddr);
> +	return 0;
> +}
> +
> +/*!
> + * This function reads the current alarm value into the passed in \b alrm
> + * argument. It updates the \b alrm's pending field value based on the whether
> + * an alarm interrupt occurs or not.
> + *
> + * @param  alrm         contains the RTC alarm value upon return
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int mxc_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
> +{
> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	void __iomem *ioaddr = pdata->ioaddr;
> +
> +	rtc_time_to_tm(__raw_readl(ioaddr + SRTC_LPSAR), &alrm->time);
> +	alrm->pending =
> +	    ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_ALP) != 0) ? 1 : 0;

if/else would be much easier to read here.

> +
> +	return 0;
> +}
> +
> +static int mxc_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
> +{
> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	unsigned long lock_flags = 0;
> +	u32 lp_cr;
> +
> +	spin_lock_irqsave(&rtc_lock, lock_flags);
> +	lp_cr = __raw_readl(pdata->ioaddr + SRTC_LPCR);
> +
> +	if (enable)
> +		lp_cr |= (SRTC_LPCR_ALP | SRTC_LPCR_WAE);
> +	else
> +		lp_cr &= ~(SRTC_LPCR_ALP | SRTC_LPCR_WAE);
> +
> +	__raw_writel(lp_cr, pdata->ioaddr + SRTC_LPCR);
> +	spin_unlock_irqrestore(&rtc_lock, lock_flags);
> +	return 0;
> +}
> +
> +/*!
> + * This function sets the RTC alarm based on passed in alrm.
> + *
> + * @param  alrm         the alarm value to be set in the RTC
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int mxc_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
> +{
> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	void __iomem *ioaddr = pdata->ioaddr;
> +	int ret;
> +
> +	ret = rtc_update_alarm(dev, &alrm->time);
> +	if (!ret)
> +		mxc_rtc_alarm_irq_enable(dev, alrm->enabled);
> +
> +	rtc_write_sync_lp(ioaddr);
> +	return ret;
> +}
> +
> +/*!
> + * The RTC driver structure
> + */
> +static const struct rtc_class_ops mxc_rtc_ops = {
> +	.read_time = mxc_rtc_read_time,
> +	.set_time = mxc_rtc_set_time,
> +	.read_alarm = mxc_rtc_read_alarm,
> +	.set_alarm = mxc_rtc_set_alarm,
> +	.alarm_irq_enable = mxc_rtc_alarm_irq_enable,
> +};
> +
> +/*! MXC RTC Power management control */
> +static int mxc_rtc_probe(struct platform_device *pdev)
> +{
> +	struct timespec tv;
> +	struct resource *res;
> +	struct rtc_drv_data *pdata = NULL;

No need to initialize.

> +	void __iomem *ioaddr;
> +	int ret = 0;
> +
> +	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
> +	if (!pdata)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res)
> +		return -ENODEV;
> +
> +	pdata->ioaddr = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(pdata->ioaddr))
> +		return PTR_ERR(pdata->ioaddr);
> +
> +	ioaddr = pdata->ioaddr;
> +
> +	pdata->clk = devm_clk_get(&pdev->dev, NULL);
> +	if (IS_ERR(pdata->clk)) {
> +		dev_err(&pdev->dev, "unable to get rtc clock!\n");
> +		return PTR_ERR(pdata->clk);
> +	}
> +	ret = clk_prepare_enable(pdata->clk);
> +	if (ret)
> +		return ret;
> +
> +	/* Configure and enable the RTC */
> +	pdata->irq = platform_get_irq(pdev, 0);
> +	if (pdata->irq >= 0
> +	    && devm_request_irq(&pdev->dev, pdata->irq, mxc_rtc_interrupt,
> +				IRQF_SHARED, pdev->name, pdev) < 0) {
> +		dev_warn(&pdev->dev, "interrupt not available.\n");
> +		pdata->irq = -1;
> +	}

I would just make the interrupt mandatory. I see no valid reason why it
shouldn't be available and it makes your driver logic simpler when you
can just assume it's available.

> +
> +	if (pdata->irq >= 0)
> +		device_init_wakeup(&pdev->dev, 1);
> +
> +	/* initialize glitch detect */
> +	__raw_writel(SRTC_LPPDR_INIT, ioaddr + SRTC_LPPDR);
> +	udelay(100);
> +
> +	/* clear lp interrupt status */
> +	__raw_writel(0xFFFFFFFF, ioaddr + SRTC_LPSR);
> +	udelay(100);
> +
> +	/* move out of init state */
> +	__raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NSA), ioaddr + SRTC_LPCR);
> +
> +	udelay(100);
> +
> +	while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_IES) == 0)
> +		;
> +
> +	/* move out of non-valid state */
> +	__raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NVE | SRTC_LPCR_NSA |
> +		      SRTC_LPCR_EN_LP), ioaddr + SRTC_LPCR);
> +
> +	udelay(100);

Where do all these udelay() come from? Are they really needed?

> +
> +	while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_NVES) == 0)
> +		;
> +
> +	__raw_writel(0xFFFFFFFF, ioaddr + SRTC_LPSR);
> +	udelay(100);
> +
> +	platform_set_drvdata(pdev, pdata);
> +	pdata->rtc =
> +	    devm_rtc_device_register(&pdev->dev, pdev->name, &mxc_rtc_ops,
> +				     THIS_MODULE);
> +	if (IS_ERR(pdata->rtc)) {
> +		ret = PTR_ERR(pdata->rtc);
> +		goto exit_put_clk;
> +	}
> +
> +	tv.tv_nsec = 0;
> +	tv.tv_sec = __raw_readl(ioaddr + SRTC_LPSCMR);

Why this? tv is set but unused.

> +
> +	/* By default, devices should wakeup if they can */
> +	/* So srtc is set as "should wakeup" as it can */
> +	device_init_wakeup(&pdev->dev, 1);

Why is this done twice, one time only when we have a valid irq? This
looks fishy.

> +
> +	return ret;
> +
> +exit_put_clk:
> +	clk_disable_unprepare(pdata->clk);
> +	return ret;
> +}
> +
> +static int __exit mxc_rtc_remove(struct platform_device *pdev)
> +{
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +
> +	clk_disable_unprepare(pdata->clk);
> +	return 0;
> +}
> +
> +/*!
> + * This function is called to save the system time delta relative to
> + * the MXC RTC when enterring a low power state. This time delta is
> + * then used on resume to adjust the system time to account for time
> + * loss while suspended.
> + *
> + * @param   pdev  not used

Not true.

> + * @param   state Power state to enter.
> + *
> + * @return  The function always returns 0.
> + */
> +static int mxc_rtc_suspend(struct platform_device *pdev, pm_message_t state)
> +{
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +
> +	if (device_may_wakeup(&pdev->dev))
> +		enable_irq_wake(pdata->irq);
> +
> +	return 0;
> +}
> +
> +/*!
> + * This function is called to correct the system time based on the
> + * current MXC RTC time relative to the time delta saved during
> + * suspend.
> + *
> + * @param   pdev  not used

Not true.

> + *
> + * @return  The function always returns 0.
> + */
> +static int mxc_rtc_resume(struct platform_device *pdev)
> +{
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +
> +	if (device_may_wakeup(&pdev->dev))
> +		disable_irq_wake(pdata->irq);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id mxc_ids[] = {
> +	{.compatible = "fsl,imx53-rtc",},
> +	{}
> +};
> +
> +/*!
> + * Contains pointers to the power management callback functions.

True, but doesn't contain any useful information.

> + */
> +static struct platform_driver mxc_rtc_driver = {
> +	.driver = {
> +		   .name = "mxc_rtc_v8",
> +		   .of_match_table = mxc_ids,
> +		   },

Indentation is broken here.

> +	.probe = mxc_rtc_probe,
> +	.remove = mxc_rtc_remove,
> +	.suspend = mxc_rtc_suspend,
> +	.resume = mxc_rtc_resume,
> +};
> +
> +module_platform_driver(mxc_rtc_driver);
> +
> +MODULE_AUTHOR("Freescale Semiconductor, Inc.");
> +MODULE_DESCRIPTION("Realtime Clock Driver (RTC)");
> +MODULE_LICENSE("GPL");

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH] rtc: add mxc driver for i.MX53
@ 2017-11-30  9:50   ` Sascha Hauer
  0 siblings, 0 replies; 43+ messages in thread
From: Sascha Hauer @ 2017-11-30  9:50 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Nov 28, 2017 at 08:39:27AM +0100, linux-kernel-dev at beckhoff.com wrote:
> From: Patrick Bruenn <p.bruenn@beckhoff.com>
> 
> Neither rtc-imxdi nor rtc-mxc are compatible with i.MX53.
> Add a modernized version of mxc_v2 from here:
> http://git.freescale.com/git/cgit.cgi/imx/linux-2.6-imx.git/tree/drivers/rtc/rtc-mxc_v2.c?h=imx_2.6.35_11.09.01
> 
> Changes to that version:
> - updated to v4.15-rc1
> - removed ioctl()
> - removed proc()
> - removed manual(redundant) enable_irq flag
> 
> Signed-off-by: Patrick Bruenn <p.bruenn@beckhoff.com>
> 
> ---
> 
> Open issues:
> - driver naming, should it be merged with rtc-mxc.c ?
> - document DT binding "fsl,imx53-rtc" accordingly
> - Should unused defines be removed or kept for someone else to be
>   useful?
> - Is the use of __raw_readl/writel() correct? Should it be replaced with
>   readl/writel()?
> - suspend/resume() seems different to existing rtc-mxc.c, should I apply
>   the pattern from rtc-mxc.c?
> - On Shawns tree imx53.dtsi has been reverted already[1][2]. Should I split
>   the imx53.dtsi change into a separate patch based on his tree? Or can
>   we still stop the full revert and just remove the imx25-rtc compatible?
>   I am not in a hurry, so we could just wait until the revert landed in
>   Linus tree. Whatever you think is best.
> 
> [1] https://www.spinics.net/lists/arm-kernel/msg617113.html
> [2] commit ee76f7729babd2700afd6f3874449d8084dd85ea
> 
> To: Alessandro Zummo <a.zummo@towertech.it>
> To: Alexandre Belloni <alexandre.belloni@free-electrons.com>
> Cc: Rob Herring <robh+dt@kernel.org>
> Cc: Mark Rutland <mark.rutland@arm.com> (maintainer:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS)
> Cc: linux-rtc at vger.kernel.org (open list:REAL TIME CLOCK (RTC) SUBSYSTEM)
> Cc: devicetree at vger.kernel.org (open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS)
> Cc: linux-kernel at vger.kernel.org (open list)
> Cc: Fabio Estevam <fabio.estevam@nxp.com>
> Cc: Juergen Borleis <jbe@pengutronix.de>
> Cc: Noel Vellemans <Noel.Vellemans@visionbms.com>
> Cc: Shawn Guo <shawnguo@kernel.org>
> Cc: Sascha Hauer <kernel@pengutronix.de> (maintainer:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE)
> Cc: Russell King <linux@armlinux.org.uk> (maintainer:ARM PORT)
> Cc: linux-arm-kernel at lists.infradead.org (moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE)
> ---
>  arch/arm/boot/dts/imx53.dtsi |   2 +-
>  drivers/rtc/Makefile         |   1 +
>  drivers/rtc/rtc-mxc_v2.c     | 531 +++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 533 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/rtc/rtc-mxc_v2.c
> 
> diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi
> index 589a67c5f796..3d1a55e11ea8 100644
> --- a/arch/arm/boot/dts/imx53.dtsi
> +++ b/arch/arm/boot/dts/imx53.dtsi
> @@ -434,7 +434,7 @@
>  			};
>  
>  			srtc: srtc at 53fa4000 {
> -				compatible = "fsl,imx53-rtc", "fsl,imx25-rtc";
> +				compatible = "fsl,imx53-rtc";
>  				reg = <0x53fa4000 0x4000>;
>  				interrupts = <24>;
>  				interrupt-parent = <&tzic>;
> diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
> index f2f50c11dc38..fb3dc458c185 100644
> --- a/drivers/rtc/Makefile
> +++ b/drivers/rtc/Makefile
> @@ -106,6 +106,7 @@ obj-$(CONFIG_RTC_DRV_MT6397)	+= rtc-mt6397.o
>  obj-$(CONFIG_RTC_DRV_MT7622)	+= rtc-mt7622.o
>  obj-$(CONFIG_RTC_DRV_MV)	+= rtc-mv.o
>  obj-$(CONFIG_RTC_DRV_MXC)	+= rtc-mxc.o
> +obj-$(CONFIG_RTC_DRV_MXC)	+= rtc-mxc_v2.o
>  obj-$(CONFIG_RTC_DRV_NUC900)	+= rtc-nuc900.o
>  obj-$(CONFIG_RTC_DRV_OMAP)	+= rtc-omap.o
>  obj-$(CONFIG_RTC_DRV_OPAL)	+= rtc-opal.o
> diff --git a/drivers/rtc/rtc-mxc_v2.c b/drivers/rtc/rtc-mxc_v2.c
> new file mode 100644
> index 000000000000..5049b521b38e
> --- /dev/null
> +++ b/drivers/rtc/rtc-mxc_v2.c
> @@ -0,0 +1,531 @@
> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights Reserved.
> + */
> +
> +/*
> + * The code contained herein is licensed under the GNU General Public
> + * License. You may obtain a copy of the GNU General Public License
> + * Version 2 or later at the following locations:
> + *
> + * http://www.opensource.org/licenses/gpl-license.html
> + * http://www.gnu.org/copyleft/gpl.html
> + */
> +/*
> + * Implementation based on rtc-ds1553.c
> + */
> +
> +/*!
> + * @defgroup RTC Real Time Clock (RTC) Driver for i.MX53
> + */
> +/*!
> + * @file rtc-mxc_v2.c
> + * @brief Real Time Clock interface
> + *
> + * This file contains Real Time Clock interface for Linux.
> + *
> + * @ingroup RTC
> + */
> +
> +#include <linux/slab.h>
> +#include <linux/delay.h>
> +#include <linux/rtc.h>
> +#include <linux/module.h>
> +#include <linux/fs.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/platform_device.h>
> +#include <linux/clk.h>
> +#include <linux/device.h>
> +#include <linux/uaccess.h>
> +#include <linux/io.h>
> +//#include <linux/mxc_srtc.h>
> +#define RTC_READ_TIME_47BIT	_IOR('p', 0x20, unsigned long long)
> +/* blocks until LPSCMR is set, returns difference */
> +#define RTC_WAIT_TIME_SET	_IOR('p', 0x21, int64_t)
> +
> +#define SRTC_LPSCLR_LLPSC_LSH	17	/* start bit for LSB time value */
> +
> +#define SRTC_LPPDR_INIT       0x41736166	/* init for glitch detect */
> +
> +#define SRTC_LPCR_SWR_LP      (1 << 0)	/* lp software reset */
> +#define SRTC_LPCR_EN_LP       (1 << 3)	/* lp enable */
> +#define SRTC_LPCR_WAE         (1 << 4)	/* lp wakeup alarm enable */
> +#define SRTC_LPCR_SAE         (1 << 5)	/* lp security alarm enable */
> +#define SRTC_LPCR_SI          (1 << 6)	/* lp security interrupt enable */
> +#define SRTC_LPCR_ALP         (1 << 7)	/* lp alarm flag */
> +#define SRTC_LPCR_LTC         (1 << 8)	/* lp lock time counter */
> +#define SRTC_LPCR_LMC         (1 << 9)	/* lp lock monotonic counter */
> +#define SRTC_LPCR_SV          (1 << 10)	/* lp security violation */
> +#define SRTC_LPCR_NSA         (1 << 11)	/* lp non secure access */
> +#define SRTC_LPCR_NVEIE       (1 << 12)	/* lp non valid state exit int en */
> +#define SRTC_LPCR_IEIE        (1 << 13)	/* lp init state exit int enable */
> +#define SRTC_LPCR_NVE         (1 << 14)	/* lp non valid state exit bit */
> +#define SRTC_LPCR_IE          (1 << 15)	/* lp init state exit bit */
> +
> +#define SRTC_LPCR_ALL_INT_EN (SRTC_LPCR_WAE | SRTC_LPCR_SAE | \
> +			      SRTC_LPCR_SI | SRTC_LPCR_ALP | \
> +			      SRTC_LPCR_NVEIE | SRTC_LPCR_IEIE)
> +
> +#define SRTC_LPSR_TRI         (1 << 0)	/* lp time read invalidate */
> +#define SRTC_LPSR_PGD         (1 << 1)	/* lp power supply glitc detected */
> +#define SRTC_LPSR_CTD         (1 << 2)	/* lp clock tampering detected */
> +#define SRTC_LPSR_ALP         (1 << 3)	/* lp alarm flag */
> +#define SRTC_LPSR_MR          (1 << 4)	/* lp monotonic counter rollover */
> +#define SRTC_LPSR_TR          (1 << 5)	/* lp time rollover */
> +#define SRTC_LPSR_EAD         (1 << 6)	/* lp external alarm detected */
> +#define SRTC_LPSR_IT0         (1 << 7)	/* lp IIM throttle */
> +#define SRTC_LPSR_IT1         (1 << 8)
> +#define SRTC_LPSR_IT2         (1 << 9)
> +#define SRTC_LPSR_SM0         (1 << 10)	/* lp security mode */
> +#define SRTC_LPSR_SM1         (1 << 11)
> +#define SRTC_LPSR_STATE_LP0   (1 << 12)	/* lp state */
> +#define SRTC_LPSR_STATE_LP1   (1 << 13)
> +#define SRTC_LPSR_NVES        (1 << 14)	/* lp non-valid state exit status */
> +#define SRTC_LPSR_IES         (1 << 15)	/* lp init state exit status */
> +
> +#define MAX_PIE_NUM     15
> +#define MAX_PIE_FREQ    32768
> +#define MIN_PIE_FREQ	1
> +
> +#define SRTC_PI0         (1 << 0)
> +#define SRTC_PI1         (1 << 1)
> +#define SRTC_PI2         (1 << 2)
> +#define SRTC_PI3         (1 << 3)
> +#define SRTC_PI4         (1 << 4)
> +#define SRTC_PI5         (1 << 5)
> +#define SRTC_PI6         (1 << 6)
> +#define SRTC_PI7         (1 << 7)
> +#define SRTC_PI8         (1 << 8)
> +#define SRTC_PI9         (1 << 9)
> +#define SRTC_PI10        (1 << 10)
> +#define SRTC_PI11        (1 << 11)
> +#define SRTC_PI12        (1 << 12)
> +#define SRTC_PI13        (1 << 13)
> +#define SRTC_PI14        (1 << 14)
> +#define SRTC_PI15        (1 << 15)
> +
> +#define PIT_ALL_ON      (SRTC_PI1 | SRTC_PI2 | SRTC_PI3 | \
> +			SRTC_PI4 | SRTC_PI5 | SRTC_PI6 | SRTC_PI7 | \
> +			SRTC_PI8 | SRTC_PI9 | SRTC_PI10 | SRTC_PI11 | \
> +			SRTC_PI12 | SRTC_PI13 | SRTC_PI14 | SRTC_PI15)
> +
> +#define SRTC_SWR_HP      (1 << 0)	/* hp software reset */
> +#define SRTC_EN_HP       (1 << 3)	/* hp enable */
> +#define SRTC_TS          (1 << 4)	/* time synchronize hp with lp */
> +
> +#define SRTC_IE_AHP      (1 << 16)	/* Alarm HP Interrupt Enable bit */
> +#define SRTC_IE_WDHP     (1 << 18)	/* Write Done HP Interrupt Enable bit */
> +#define SRTC_IE_WDLP     (1 << 19)	/* Write Done LP Interrupt Enable bit */
> +
> +#define SRTC_ISR_AHP     (1 << 16)	/* interrupt status: alarm hp */
> +#define SRTC_ISR_WDHP    (1 << 18)	/* interrupt status: write done hp */
> +#define SRTC_ISR_WDLP    (1 << 19)	/* interrupt status: write done lp */
> +#define SRTC_ISR_WPHP    (1 << 20)	/* interrupt status: write pending hp */
> +#define SRTC_ISR_WPLP    (1 << 21)	/* interrupt status: write pending lp */
> +
> +#define SRTC_LPSCMR	0x00	/* LP Secure Counter MSB Reg */
> +#define SRTC_LPSCLR	0x04	/* LP Secure Counter LSB Reg */
> +#define SRTC_LPSAR	0x08	/* LP Secure Alarm Reg */
> +#define SRTC_LPSMCR	0x0C	/* LP Secure Monotonic Counter Reg */
> +#define SRTC_LPCR	0x10	/* LP Control Reg */
> +#define SRTC_LPSR	0x14	/* LP Status Reg */
> +#define SRTC_LPPDR	0x18	/* LP Power Supply Glitch Detector Reg */
> +#define SRTC_LPGR	0x1C	/* LP General Purpose Reg */
> +#define SRTC_HPCMR	0x20	/* HP Counter MSB Reg */
> +#define SRTC_HPCLR	0x24	/* HP Counter LSB Reg */
> +#define SRTC_HPAMR	0x28	/* HP Alarm MSB Reg */
> +#define SRTC_HPALR	0x2C	/* HP Alarm LSB Reg */
> +#define SRTC_HPCR	0x30	/* HP Control Reg */
> +#define SRTC_HPISR	0x34	/* HP Interrupt Status Reg */
> +#define SRTC_HPIENR	0x38	/* HP Interrupt Enable Reg */
> +
> +#define SRTC_SECMODE_MASK	0x3	/* the mask of SRTC security mode */
> +#define SRTC_SECMODE_LOW	0x0	/* Low Security */
> +#define SRTC_SECMODE_MED	0x1	/* Medium Security */
> +#define SRTC_SECMODE_HIGH	0x2	/* High Security */
> +#define SRTC_SECMODE_RESERVED	0x3	/* Reserved */
> +
> +struct rtc_drv_data {
> +	struct rtc_device *rtc;
> +	void __iomem *ioaddr;
> +	int irq;
> +	struct clk *clk;
> +};
> +
> +static DEFINE_SPINLOCK(rtc_lock);

The lock should be a member of your driver data struct.

> +
> +/*!
> + * This function does write synchronization for writes to the lp srtc block.
> + * To take care of the asynchronous CKIL clock, all writes from the IP domain
> + * will be synchronized to the CKIL domain.
> + */

Please drop this exclamation mark at the beginning of comments. If
anything, use kerneldoc style for the function descriptions.

> +static inline void rtc_write_sync_lp(void __iomem *ioaddr)
> +{
> +	unsigned int i, count;
> +	/* Wait for 3 CKIL cycles */
> +	for (i = 0; i < 3; i++) {
> +		count = readl(ioaddr + SRTC_LPSCLR);
> +		while ((readl(ioaddr + SRTC_LPSCLR)) == count)
> +			;

This becomes an infinite loop when the hardware is not working as
expected. You should avoid that.

> +	}
> +}
> +
> +/*!
> + * This function updates the RTC alarm registers and then clears all the
> + * interrupt status bits.
> + *
> + * @param  alrm         the new alarm value to be updated in the RTC
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int rtc_update_alarm(struct device *dev, struct rtc_time *alrm)
> +{

mxc_rtc_update_alarm please like the other device specific functions
please. Same for rtc_write_sync_lp().

> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	void __iomem *ioaddr = pdata->ioaddr;
> +	struct rtc_time alarm_tm, now_tm;
> +	unsigned long now, time;
> +	int ret;
> +
> +	now = __raw_readl(ioaddr + SRTC_LPSCMR);
> +	rtc_time_to_tm(now, &now_tm);
> +
> +	alarm_tm.tm_year = now_tm.tm_year;
> +	alarm_tm.tm_mon = now_tm.tm_mon;
> +	alarm_tm.tm_mday = now_tm.tm_mday;
> +
> +	alarm_tm.tm_hour = alrm->tm_hour;
> +	alarm_tm.tm_min = alrm->tm_min;
> +	alarm_tm.tm_sec = alrm->tm_sec;
> +
> +	rtc_tm_to_time(&now_tm, &now);
> +	rtc_tm_to_time(&alarm_tm, &time);
> +
> +	if (time < now) {
> +		time += 60 * 60 * 24;
> +		rtc_time_to_tm(time, &alarm_tm);
> +	}
> +	ret = rtc_tm_to_time(&alarm_tm, &time);
> +
> +	__raw_writel(time, ioaddr + SRTC_LPSAR);
> +
> +	/* clear alarm interrupt status bit */
> +	__raw_writel(SRTC_LPSR_ALP, ioaddr + SRTC_LPSR);
> +
> +	return ret;
> +}
> +
> +/*!
> + * This function is the RTC interrupt service routine.
> + *
> + * @param  irq          RTC IRQ number
> + * @param  dev_id       device ID which is not used
> + *
> + * @return IRQ_HANDLED as defined in the include/linux/interrupt.h file.
> + */
> +static irqreturn_t mxc_rtc_interrupt(int irq, void *dev_id)
> +{
> +	struct platform_device *pdev = dev_id;
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +	void __iomem *ioaddr = pdata->ioaddr;
> +	u32 lp_status, lp_cr;
> +	u32 events = 0;
> +
> +	lp_status = __raw_readl(ioaddr + SRTC_LPSR);
> +	lp_cr = __raw_readl(ioaddr + SRTC_LPCR);
> +
> +	/* update irq data & counter */
> +	if (lp_status & SRTC_LPSR_ALP) {
> +		if (lp_cr & SRTC_LPCR_ALP)
> +			events |= (RTC_AF | RTC_IRQF);
> +
> +		/* disable further lp alarm interrupts */
> +		lp_cr &= ~(SRTC_LPCR_ALP | SRTC_LPCR_WAE);
> +	}
> +
> +	/* Update interrupt enables */
> +	__raw_writel(lp_cr, ioaddr + SRTC_LPCR);
> +
> +	/* clear interrupt status */
> +	__raw_writel(lp_status, ioaddr + SRTC_LPSR);
> +
> +	rtc_write_sync_lp(ioaddr);
> +	rtc_update_irq(pdata->rtc, 1, events);
> +	return IRQ_HANDLED;
> +}

What about locking? You lock the read/modify/write operation of the LPCR
register below, and so you should do here.

> +
> +/*!
> + * This function reads the current RTC time into tm in Gregorian date.
> + *
> + * @param  tm           contains the RTC time value upon return
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int mxc_rtc_read_time(struct device *dev, struct rtc_time *tm)
> +{
> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	time_t now = readl(pdata->ioaddr + SRTC_LPSCMR);
> +
> +	rtc_time_to_tm(now, tm);
> +	return rtc_valid_tm(tm);
> +}
> +
> +/*!
> + * This function sets the internal RTC time based on tm in Gregorian date.
> + *
> + * @param  tm           the time value to be set in the RTC
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int mxc_rtc_set_time(struct device *dev, struct rtc_time *tm)
> +{
> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	time64_t time = rtc_tm_to_time64(tm);
> +
> +	if (time > UINT_MAX) {
> +		dev_warn(dev, "time_t has overflow\n");
> +	}

SIGH. Who builds such a RTC in the 21st century?

Shouldn't this return an error?

> +
> +	writel(time, pdata->ioaddr + SRTC_LPSCMR);
> +	rtc_write_sync_lp(pdata->ioaddr);
> +	return 0;
> +}
> +
> +/*!
> + * This function reads the current alarm value into the passed in \b alrm
> + * argument. It updates the \b alrm's pending field value based on the whether
> + * an alarm interrupt occurs or not.
> + *
> + * @param  alrm         contains the RTC alarm value upon return
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int mxc_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
> +{
> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	void __iomem *ioaddr = pdata->ioaddr;
> +
> +	rtc_time_to_tm(__raw_readl(ioaddr + SRTC_LPSAR), &alrm->time);
> +	alrm->pending =
> +	    ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_ALP) != 0) ? 1 : 0;

if/else would be much easier to read here.

> +
> +	return 0;
> +}
> +
> +static int mxc_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
> +{
> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	unsigned long lock_flags = 0;
> +	u32 lp_cr;
> +
> +	spin_lock_irqsave(&rtc_lock, lock_flags);
> +	lp_cr = __raw_readl(pdata->ioaddr + SRTC_LPCR);
> +
> +	if (enable)
> +		lp_cr |= (SRTC_LPCR_ALP | SRTC_LPCR_WAE);
> +	else
> +		lp_cr &= ~(SRTC_LPCR_ALP | SRTC_LPCR_WAE);
> +
> +	__raw_writel(lp_cr, pdata->ioaddr + SRTC_LPCR);
> +	spin_unlock_irqrestore(&rtc_lock, lock_flags);
> +	return 0;
> +}
> +
> +/*!
> + * This function sets the RTC alarm based on passed in alrm.
> + *
> + * @param  alrm         the alarm value to be set in the RTC
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int mxc_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
> +{
> +	struct rtc_drv_data *pdata = dev_get_drvdata(dev);
> +	void __iomem *ioaddr = pdata->ioaddr;
> +	int ret;
> +
> +	ret = rtc_update_alarm(dev, &alrm->time);
> +	if (!ret)
> +		mxc_rtc_alarm_irq_enable(dev, alrm->enabled);
> +
> +	rtc_write_sync_lp(ioaddr);
> +	return ret;
> +}
> +
> +/*!
> + * The RTC driver structure
> + */
> +static const struct rtc_class_ops mxc_rtc_ops = {
> +	.read_time = mxc_rtc_read_time,
> +	.set_time = mxc_rtc_set_time,
> +	.read_alarm = mxc_rtc_read_alarm,
> +	.set_alarm = mxc_rtc_set_alarm,
> +	.alarm_irq_enable = mxc_rtc_alarm_irq_enable,
> +};
> +
> +/*! MXC RTC Power management control */
> +static int mxc_rtc_probe(struct platform_device *pdev)
> +{
> +	struct timespec tv;
> +	struct resource *res;
> +	struct rtc_drv_data *pdata = NULL;

No need to initialize.

> +	void __iomem *ioaddr;
> +	int ret = 0;
> +
> +	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
> +	if (!pdata)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res)
> +		return -ENODEV;
> +
> +	pdata->ioaddr = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(pdata->ioaddr))
> +		return PTR_ERR(pdata->ioaddr);
> +
> +	ioaddr = pdata->ioaddr;
> +
> +	pdata->clk = devm_clk_get(&pdev->dev, NULL);
> +	if (IS_ERR(pdata->clk)) {
> +		dev_err(&pdev->dev, "unable to get rtc clock!\n");
> +		return PTR_ERR(pdata->clk);
> +	}
> +	ret = clk_prepare_enable(pdata->clk);
> +	if (ret)
> +		return ret;
> +
> +	/* Configure and enable the RTC */
> +	pdata->irq = platform_get_irq(pdev, 0);
> +	if (pdata->irq >= 0
> +	    && devm_request_irq(&pdev->dev, pdata->irq, mxc_rtc_interrupt,
> +				IRQF_SHARED, pdev->name, pdev) < 0) {
> +		dev_warn(&pdev->dev, "interrupt not available.\n");
> +		pdata->irq = -1;
> +	}

I would just make the interrupt mandatory. I see no valid reason why it
shouldn't be available and it makes your driver logic simpler when you
can just assume it's available.

> +
> +	if (pdata->irq >= 0)
> +		device_init_wakeup(&pdev->dev, 1);
> +
> +	/* initialize glitch detect */
> +	__raw_writel(SRTC_LPPDR_INIT, ioaddr + SRTC_LPPDR);
> +	udelay(100);
> +
> +	/* clear lp interrupt status */
> +	__raw_writel(0xFFFFFFFF, ioaddr + SRTC_LPSR);
> +	udelay(100);
> +
> +	/* move out of init state */
> +	__raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NSA), ioaddr + SRTC_LPCR);
> +
> +	udelay(100);
> +
> +	while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_IES) == 0)
> +		;
> +
> +	/* move out of non-valid state */
> +	__raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NVE | SRTC_LPCR_NSA |
> +		      SRTC_LPCR_EN_LP), ioaddr + SRTC_LPCR);
> +
> +	udelay(100);

Where do all these udelay() come from? Are they really needed?

> +
> +	while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_NVES) == 0)
> +		;
> +
> +	__raw_writel(0xFFFFFFFF, ioaddr + SRTC_LPSR);
> +	udelay(100);
> +
> +	platform_set_drvdata(pdev, pdata);
> +	pdata->rtc =
> +	    devm_rtc_device_register(&pdev->dev, pdev->name, &mxc_rtc_ops,
> +				     THIS_MODULE);
> +	if (IS_ERR(pdata->rtc)) {
> +		ret = PTR_ERR(pdata->rtc);
> +		goto exit_put_clk;
> +	}
> +
> +	tv.tv_nsec = 0;
> +	tv.tv_sec = __raw_readl(ioaddr + SRTC_LPSCMR);

Why this? tv is set but unused.

> +
> +	/* By default, devices should wakeup if they can */
> +	/* So srtc is set as "should wakeup" as it can */
> +	device_init_wakeup(&pdev->dev, 1);

Why is this done twice, one time only when we have a valid irq? This
looks fishy.

> +
> +	return ret;
> +
> +exit_put_clk:
> +	clk_disable_unprepare(pdata->clk);
> +	return ret;
> +}
> +
> +static int __exit mxc_rtc_remove(struct platform_device *pdev)
> +{
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +
> +	clk_disable_unprepare(pdata->clk);
> +	return 0;
> +}
> +
> +/*!
> + * This function is called to save the system time delta relative to
> + * the MXC RTC when enterring a low power state. This time delta is
> + * then used on resume to adjust the system time to account for time
> + * loss while suspended.
> + *
> + * @param   pdev  not used

Not true.

> + * @param   state Power state to enter.
> + *
> + * @return  The function always returns 0.
> + */
> +static int mxc_rtc_suspend(struct platform_device *pdev, pm_message_t state)
> +{
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +
> +	if (device_may_wakeup(&pdev->dev))
> +		enable_irq_wake(pdata->irq);
> +
> +	return 0;
> +}
> +
> +/*!
> + * This function is called to correct the system time based on the
> + * current MXC RTC time relative to the time delta saved during
> + * suspend.
> + *
> + * @param   pdev  not used

Not true.

> + *
> + * @return  The function always returns 0.
> + */
> +static int mxc_rtc_resume(struct platform_device *pdev)
> +{
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +
> +	if (device_may_wakeup(&pdev->dev))
> +		disable_irq_wake(pdata->irq);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id mxc_ids[] = {
> +	{.compatible = "fsl,imx53-rtc",},
> +	{}
> +};
> +
> +/*!
> + * Contains pointers to the power management callback functions.

True, but doesn't contain any useful information.

> + */
> +static struct platform_driver mxc_rtc_driver = {
> +	.driver = {
> +		   .name = "mxc_rtc_v8",
> +		   .of_match_table = mxc_ids,
> +		   },

Indentation is broken here.

> +	.probe = mxc_rtc_probe,
> +	.remove = mxc_rtc_remove,
> +	.suspend = mxc_rtc_suspend,
> +	.resume = mxc_rtc_resume,
> +};
> +
> +module_platform_driver(mxc_rtc_driver);
> +
> +MODULE_AUTHOR("Freescale Semiconductor, Inc.");
> +MODULE_DESCRIPTION("Realtime Clock Driver (RTC)");
> +MODULE_LICENSE("GPL");

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] rtc: add mxc driver for i.MX53
  2017-11-30  9:50   ` Sascha Hauer
  (?)
  (?)
@ 2017-11-30 10:53     ` Lothar Waßmann
  -1 siblings, 0 replies; 43+ messages in thread
From: Lothar Waßmann @ 2017-11-30 10:53 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: linux-kernel-dev, Mark Rutland, Alessandro Zummo, Patrick Bruenn,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	open list, Rob Herring, Russell King, Noel Vellemans,
	Alexandre Belloni, Sascha Hauer, Fabio Estevam, Shawn Guo,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
	open list:REAL TIME CLOCK (RTC) SUBSYSTEM

Hi,

On Thu, 30 Nov 2017 10:50:47 +0100 Sascha Hauer wrote:
> On Tue, Nov 28, 2017 at 08:39:27AM +0100, linux-kernel-dev@beckhoff.com wrote:
[...]
> > +/*! MXC RTC Power management control */
> > +static int mxc_rtc_probe(struct platform_device *pdev)
> > +{
> > +	struct timespec tv;
> > +	struct resource *res;
> > +	struct rtc_drv_data *pdata = NULL;
> 
> No need to initialize.
> 
> > +	void __iomem *ioaddr;
> > +	int ret = 0;
>
Same here.


Lothar Waßmann

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] rtc: add mxc driver for i.MX53
@ 2017-11-30 10:53     ` Lothar Waßmann
  0 siblings, 0 replies; 43+ messages in thread
From: Lothar Waßmann @ 2017-11-30 10:53 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: linux-kernel-dev, Mark Rutland, Alessandro Zummo, Patrick Bruenn,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	open list, Rob Herring, Russell King, Noel Vellemans,
	Alexandre Belloni, Sascha Hauer, Fabio Estevam, Shawn Guo,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
	open list:REAL TIME CLOCK (RTC) SUBSYSTEM

Hi,

On Thu, 30 Nov 2017 10:50:47 +0100 Sascha Hauer wrote:
> On Tue, Nov 28, 2017 at 08:39:27AM +0100, linux-kernel-dev@beckhoff.com wrote:
[...]
> > +/*! MXC RTC Power management control */
> > +static int mxc_rtc_probe(struct platform_device *pdev)
> > +{
> > +	struct timespec tv;
> > +	struct resource *res;
> > +	struct rtc_drv_data *pdata = NULL;
> 
> No need to initialize.
> 
> > +	void __iomem *ioaddr;
> > +	int ret = 0;
>
Same here.


Lothar Waßmann

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] rtc: add mxc driver for i.MX53
@ 2017-11-30 10:53     ` Lothar Waßmann
  0 siblings, 0 replies; 43+ messages in thread
From: Lothar Waßmann @ 2017-11-30 10:53 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: linux-kernel-dev-QonKdJ6Bx35Wk0Htik3J/w, Mark Rutland,
	Alessandro Zummo, Patrick Bruenn,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	open list, Rob Herring, Russell King, Noel Vellemans,
	Alexandre Belloni, Sascha Hauer, Fabio Estevam, Shawn Guo,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
	open list:REAL TIME CLOCK (RTC) SUBSYSTEM

Hi,

On Thu, 30 Nov 2017 10:50:47 +0100 Sascha Hauer wrote:
> On Tue, Nov 28, 2017 at 08:39:27AM +0100, linux-kernel-dev-QonKdJ6Bx35Wk0Htik3J/w@public.gmane.org wrote:
[...]
> > +/*! MXC RTC Power management control */
> > +static int mxc_rtc_probe(struct platform_device *pdev)
> > +{
> > +	struct timespec tv;
> > +	struct resource *res;
> > +	struct rtc_drv_data *pdata = NULL;
> 
> No need to initialize.
> 
> > +	void __iomem *ioaddr;
> > +	int ret = 0;
>
Same here.


Lothar Waßmann
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH] rtc: add mxc driver for i.MX53
@ 2017-11-30 10:53     ` Lothar Waßmann
  0 siblings, 0 replies; 43+ messages in thread
From: Lothar Waßmann @ 2017-11-30 10:53 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On Thu, 30 Nov 2017 10:50:47 +0100 Sascha Hauer wrote:
> On Tue, Nov 28, 2017 at 08:39:27AM +0100, linux-kernel-dev at beckhoff.com wrote:
[...]
> > +/*! MXC RTC Power management control */
> > +static int mxc_rtc_probe(struct platform_device *pdev)
> > +{
> > +	struct timespec tv;
> > +	struct resource *res;
> > +	struct rtc_drv_data *pdata = NULL;
> 
> No need to initialize.
> 
> > +	void __iomem *ioaddr;
> > +	int ret = 0;
>
Same here.


Lothar Wa?mann

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] rtc: add mxc driver for i.MX53
  2017-11-28  7:39 ` linux-kernel-dev
  (?)
  (?)
@ 2017-11-30 11:21   ` Lothar Waßmann
  -1 siblings, 0 replies; 43+ messages in thread
From: Lothar Waßmann @ 2017-11-30 11:21 UTC (permalink / raw)
  To: linux-kernel-dev
  Cc: Alessandro Zummo, Alexandre Belloni, Mark Rutland,
	open list:REAL TIME CLOCK (RTC) SUBSYSTEM, Patrick Bruenn,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	open list, Russell King, Noel Vellemans, Rob Herring,
	Sascha Hauer, Fabio Estevam, Shawn Guo,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE

Hi,

On Tue, 28 Nov 2017 08:39:27 +0100 linux-kernel-dev@beckhoff.com wrote:
> From: Patrick Bruenn <p.bruenn@beckhoff.com>
[...]
> +/*!
> + * This function is the RTC interrupt service routine.
> + *
> + * @param  irq          RTC IRQ number
> + * @param  dev_id       device ID which is not used
> + *
> + * @return IRQ_HANDLED as defined in the include/linux/interrupt.h file.
> + */
> +static irqreturn_t mxc_rtc_interrupt(int irq, void *dev_id)
> +{
> +	struct platform_device *pdev = dev_id;
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +	void __iomem *ioaddr = pdata->ioaddr;
> +	u32 lp_status, lp_cr;
> +	u32 events = 0;
> +
> +	lp_status = __raw_readl(ioaddr + SRTC_LPSR);
> +	lp_cr = __raw_readl(ioaddr + SRTC_LPCR);
> +
> +	/* update irq data & counter */
> +	if (lp_status & SRTC_LPSR_ALP) {
> +		if (lp_cr & SRTC_LPCR_ALP)
> +			events |= (RTC_AF | RTC_IRQF);
> +
> +		/* disable further lp alarm interrupts */
> +		lp_cr &= ~(SRTC_LPCR_ALP | SRTC_LPCR_WAE);
> +	}
> +
> +	/* Update interrupt enables */
> +	__raw_writel(lp_cr, ioaddr + SRTC_LPCR);
> +
> +	/* clear interrupt status */
> +	__raw_writel(lp_status, ioaddr + SRTC_LPSR);
> +
> +	rtc_write_sync_lp(ioaddr);
> +	rtc_update_irq(pdata->rtc, 1, events);
> +	return IRQ_HANDLED;
> +}
> +
see comment below...

> +/*! MXC RTC Power management control */
> +static int mxc_rtc_probe(struct platform_device *pdev)
> +{
> +	struct timespec tv;
> +	struct resource *res;
> +	struct rtc_drv_data *pdata = NULL;
> +	void __iomem *ioaddr;
> +	int ret = 0;
> +
> +	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
> +	if (!pdata)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res)
> +		return -ENODEV;
> +
> +	pdata->ioaddr = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(pdata->ioaddr))
> +		return PTR_ERR(pdata->ioaddr);
> +
> +	ioaddr = pdata->ioaddr;
> +
> +	pdata->clk = devm_clk_get(&pdev->dev, NULL);
> +	if (IS_ERR(pdata->clk)) {
> +		dev_err(&pdev->dev, "unable to get rtc clock!\n");
> +		return PTR_ERR(pdata->clk);
> +	}
> +	ret = clk_prepare_enable(pdata->clk);
> +	if (ret)
> +		return ret;
>
Is it really necessary to have the clock enabled all the time, or
should it be enabled/disabled for the register accesses only?

> +	/* Configure and enable the RTC */
> +	pdata->irq = platform_get_irq(pdev, 0);
> +	if (pdata->irq >= 0
> +	    && devm_request_irq(&pdev->dev, pdata->irq, mxc_rtc_interrupt,
> +				IRQF_SHARED, pdev->name, pdev) < 0) {
>
If requesting an IRQ with the IRQF_SHARED flag, the interrupt handler
must check whether it was responsible for the IRQ and return IRQ_NONE
if that is not the case to allow some other interrupt handler to jump
in. But AFAICS the RTC IRQ is not shared with any other device, so
requesting the IRQ with IRQF_SHARED is invalid here!

> +		dev_warn(&pdev->dev, "interrupt not available.\n");
> +		pdata->irq = -1;
> +	}
> +
> +	if (pdata->irq >= 0)
> +		device_init_wakeup(&pdev->dev, 1);
> +
> +	/* initialize glitch detect */
> +	__raw_writel(SRTC_LPPDR_INIT, ioaddr + SRTC_LPPDR);
> +	udelay(100);
> +
> +	/* clear lp interrupt status */
> +	__raw_writel(0xFFFFFFFF, ioaddr + SRTC_LPSR);
> +	udelay(100);
> +
> +	/* move out of init state */
> +	__raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NSA), ioaddr + SRTC_LPCR);
> +
> +	udelay(100);
> +
> +	while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_IES) == 0)
> +		;
>
Loops polling for the change of HW controlled bits should have a
timeout, to prevent locking up when the hardware misbehaves.

> +	/* move out of non-valid state */
> +	__raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NVE | SRTC_LPCR_NSA |
> +		      SRTC_LPCR_EN_LP), ioaddr + SRTC_LPCR);
> +
> +	udelay(100);
> +
> +	while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_NVES) == 0)
> +		;
>
dto.

> +	__raw_writel(0xFFFFFFFF, ioaddr + SRTC_LPSR);
> +	udelay(100);
> +
> +	platform_set_drvdata(pdev, pdata);
>
The IRQ handler uses platform_get_drvdata(), so this has to be done
BEFORE registering the interrupt handler.

> +	pdata->rtc =
> +	    devm_rtc_device_register(&pdev->dev, pdev->name, &mxc_rtc_ops,
> +				     THIS_MODULE);
> +	if (IS_ERR(pdata->rtc)) {
> +		ret = PTR_ERR(pdata->rtc);
> +		goto exit_put_clk;
> +	}
> +
> +	tv.tv_nsec = 0;
> +	tv.tv_sec = __raw_readl(ioaddr + SRTC_LPSCMR);
> +
> +	/* By default, devices should wakeup if they can */
> +	/* So srtc is set as "should wakeup" as it can */
>
multi line comment style?

> +	device_init_wakeup(&pdev->dev, 1);
> +
> +	return ret;
> +
> +exit_put_clk:
> +	clk_disable_unprepare(pdata->clk);
> +	return ret;
> +}
> +
> +static int __exit mxc_rtc_remove(struct platform_device *pdev)
> +{
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +
> +	clk_disable_unprepare(pdata->clk);
> +	return 0;
> +}
> +
> +/*!
> + * This function is called to save the system time delta relative to
> + * the MXC RTC when enterring a low power state. This time delta is
> + * then used on resume to adjust the system time to account for time
> + * loss while suspended.
> + *
> + * @param   pdev  not used
> + * @param   state Power state to enter.
> + *
> + * @return  The function always returns 0.
> + */
> +static int mxc_rtc_suspend(struct platform_device *pdev, pm_message_t state)
> +{
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +
> +	if (device_may_wakeup(&pdev->dev))
> +		enable_irq_wake(pdata->irq);
> +
> +	return 0;
> +}
> +
> +/*!
> + * This function is called to correct the system time based on the
> + * current MXC RTC time relative to the time delta saved during
> + * suspend.
> + *
> + * @param   pdev  not used
> + *
> + * @return  The function always returns 0.
> + */
> +static int mxc_rtc_resume(struct platform_device *pdev)
> +{
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +
> +	if (device_may_wakeup(&pdev->dev))
> +		disable_irq_wake(pdata->irq);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id mxc_ids[] = {
> +	{.compatible = "fsl,imx53-rtc",},
>
missing spaces after '{' and before '}'


Lothar Waßmann

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] rtc: add mxc driver for i.MX53
@ 2017-11-30 11:21   ` Lothar Waßmann
  0 siblings, 0 replies; 43+ messages in thread
From: Lothar Waßmann @ 2017-11-30 11:21 UTC (permalink / raw)
  To: linux-kernel-dev
  Cc: Alessandro Zummo, Alexandre Belloni, Mark Rutland,
	open list:REAL TIME CLOCK (RTC) SUBSYSTEM, Patrick Bruenn,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	open list, Russell King, Noel Vellemans, Rob Herring,
	Sascha Hauer, Fabio Estevam, Shawn Guo,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE

Hi,

On Tue, 28 Nov 2017 08:39:27 +0100 linux-kernel-dev@beckhoff.com wrote:
> From: Patrick Bruenn <p.bruenn@beckhoff.com>
[...]
> +/*!
> + * This function is the RTC interrupt service routine.
> + *
> + * @param  irq          RTC IRQ number
> + * @param  dev_id       device ID which is not used
> + *
> + * @return IRQ_HANDLED as defined in the include/linux/interrupt.h file.
> + */
> +static irqreturn_t mxc_rtc_interrupt(int irq, void *dev_id)
> +{
> +	struct platform_device *pdev = dev_id;
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +	void __iomem *ioaddr = pdata->ioaddr;
> +	u32 lp_status, lp_cr;
> +	u32 events = 0;
> +
> +	lp_status = __raw_readl(ioaddr + SRTC_LPSR);
> +	lp_cr = __raw_readl(ioaddr + SRTC_LPCR);
> +
> +	/* update irq data & counter */
> +	if (lp_status & SRTC_LPSR_ALP) {
> +		if (lp_cr & SRTC_LPCR_ALP)
> +			events |= (RTC_AF | RTC_IRQF);
> +
> +		/* disable further lp alarm interrupts */
> +		lp_cr &= ~(SRTC_LPCR_ALP | SRTC_LPCR_WAE);
> +	}
> +
> +	/* Update interrupt enables */
> +	__raw_writel(lp_cr, ioaddr + SRTC_LPCR);
> +
> +	/* clear interrupt status */
> +	__raw_writel(lp_status, ioaddr + SRTC_LPSR);
> +
> +	rtc_write_sync_lp(ioaddr);
> +	rtc_update_irq(pdata->rtc, 1, events);
> +	return IRQ_HANDLED;
> +}
> +
see comment below...

> +/*! MXC RTC Power management control */
> +static int mxc_rtc_probe(struct platform_device *pdev)
> +{
> +	struct timespec tv;
> +	struct resource *res;
> +	struct rtc_drv_data *pdata = NULL;
> +	void __iomem *ioaddr;
> +	int ret = 0;
> +
> +	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
> +	if (!pdata)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res)
> +		return -ENODEV;
> +
> +	pdata->ioaddr = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(pdata->ioaddr))
> +		return PTR_ERR(pdata->ioaddr);
> +
> +	ioaddr = pdata->ioaddr;
> +
> +	pdata->clk = devm_clk_get(&pdev->dev, NULL);
> +	if (IS_ERR(pdata->clk)) {
> +		dev_err(&pdev->dev, "unable to get rtc clock!\n");
> +		return PTR_ERR(pdata->clk);
> +	}
> +	ret = clk_prepare_enable(pdata->clk);
> +	if (ret)
> +		return ret;
>
Is it really necessary to have the clock enabled all the time, or
should it be enabled/disabled for the register accesses only?

> +	/* Configure and enable the RTC */
> +	pdata->irq = platform_get_irq(pdev, 0);
> +	if (pdata->irq >= 0
> +	    && devm_request_irq(&pdev->dev, pdata->irq, mxc_rtc_interrupt,
> +				IRQF_SHARED, pdev->name, pdev) < 0) {
>
If requesting an IRQ with the IRQF_SHARED flag, the interrupt handler
must check whether it was responsible for the IRQ and return IRQ_NONE
if that is not the case to allow some other interrupt handler to jump
in. But AFAICS the RTC IRQ is not shared with any other device, so
requesting the IRQ with IRQF_SHARED is invalid here!

> +		dev_warn(&pdev->dev, "interrupt not available.\n");
> +		pdata->irq = -1;
> +	}
> +
> +	if (pdata->irq >= 0)
> +		device_init_wakeup(&pdev->dev, 1);
> +
> +	/* initialize glitch detect */
> +	__raw_writel(SRTC_LPPDR_INIT, ioaddr + SRTC_LPPDR);
> +	udelay(100);
> +
> +	/* clear lp interrupt status */
> +	__raw_writel(0xFFFFFFFF, ioaddr + SRTC_LPSR);
> +	udelay(100);
> +
> +	/* move out of init state */
> +	__raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NSA), ioaddr + SRTC_LPCR);
> +
> +	udelay(100);
> +
> +	while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_IES) == 0)
> +		;
>
Loops polling for the change of HW controlled bits should have a
timeout, to prevent locking up when the hardware misbehaves.

> +	/* move out of non-valid state */
> +	__raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NVE | SRTC_LPCR_NSA |
> +		      SRTC_LPCR_EN_LP), ioaddr + SRTC_LPCR);
> +
> +	udelay(100);
> +
> +	while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_NVES) == 0)
> +		;
>
dto.

> +	__raw_writel(0xFFFFFFFF, ioaddr + SRTC_LPSR);
> +	udelay(100);
> +
> +	platform_set_drvdata(pdev, pdata);
>
The IRQ handler uses platform_get_drvdata(), so this has to be done
BEFORE registering the interrupt handler.

> +	pdata->rtc =
> +	    devm_rtc_device_register(&pdev->dev, pdev->name, &mxc_rtc_ops,
> +				     THIS_MODULE);
> +	if (IS_ERR(pdata->rtc)) {
> +		ret = PTR_ERR(pdata->rtc);
> +		goto exit_put_clk;
> +	}
> +
> +	tv.tv_nsec = 0;
> +	tv.tv_sec = __raw_readl(ioaddr + SRTC_LPSCMR);
> +
> +	/* By default, devices should wakeup if they can */
> +	/* So srtc is set as "should wakeup" as it can */
>
multi line comment style?

> +	device_init_wakeup(&pdev->dev, 1);
> +
> +	return ret;
> +
> +exit_put_clk:
> +	clk_disable_unprepare(pdata->clk);
> +	return ret;
> +}
> +
> +static int __exit mxc_rtc_remove(struct platform_device *pdev)
> +{
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +
> +	clk_disable_unprepare(pdata->clk);
> +	return 0;
> +}
> +
> +/*!
> + * This function is called to save the system time delta relative to
> + * the MXC RTC when enterring a low power state. This time delta is
> + * then used on resume to adjust the system time to account for time
> + * loss while suspended.
> + *
> + * @param   pdev  not used
> + * @param   state Power state to enter.
> + *
> + * @return  The function always returns 0.
> + */
> +static int mxc_rtc_suspend(struct platform_device *pdev, pm_message_t state)
> +{
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +
> +	if (device_may_wakeup(&pdev->dev))
> +		enable_irq_wake(pdata->irq);
> +
> +	return 0;
> +}
> +
> +/*!
> + * This function is called to correct the system time based on the
> + * current MXC RTC time relative to the time delta saved during
> + * suspend.
> + *
> + * @param   pdev  not used
> + *
> + * @return  The function always returns 0.
> + */
> +static int mxc_rtc_resume(struct platform_device *pdev)
> +{
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +
> +	if (device_may_wakeup(&pdev->dev))
> +		disable_irq_wake(pdata->irq);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id mxc_ids[] = {
> +	{.compatible = "fsl,imx53-rtc",},
>
missing spaces after '{' and before '}'


Lothar Waßmann

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] rtc: add mxc driver for i.MX53
@ 2017-11-30 11:21   ` Lothar Waßmann
  0 siblings, 0 replies; 43+ messages in thread
From: Lothar Waßmann @ 2017-11-30 11:21 UTC (permalink / raw)
  To: linux-kernel-dev-QonKdJ6Bx35Wk0Htik3J/w
  Cc: Alessandro Zummo, Alexandre Belloni, Mark Rutland,
	open list:REAL TIME CLOCK (RTC) SUBSYSTEM, Patrick Bruenn,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	open list, Russell King, Noel Vellemans, Rob Herring,
	Sascha Hauer, Fabio Estevam, Shawn Guo,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE

Hi,

On Tue, 28 Nov 2017 08:39:27 +0100 linux-kernel-dev-QonKdJ6Bx35Wk0Htik3J/w@public.gmane.org wrote:
> From: Patrick Bruenn <p.bruenn-QonKdJ6Bx35Wk0Htik3J/w@public.gmane.org>
[...]
> +/*!
> + * This function is the RTC interrupt service routine.
> + *
> + * @param  irq          RTC IRQ number
> + * @param  dev_id       device ID which is not used
> + *
> + * @return IRQ_HANDLED as defined in the include/linux/interrupt.h file.
> + */
> +static irqreturn_t mxc_rtc_interrupt(int irq, void *dev_id)
> +{
> +	struct platform_device *pdev = dev_id;
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +	void __iomem *ioaddr = pdata->ioaddr;
> +	u32 lp_status, lp_cr;
> +	u32 events = 0;
> +
> +	lp_status = __raw_readl(ioaddr + SRTC_LPSR);
> +	lp_cr = __raw_readl(ioaddr + SRTC_LPCR);
> +
> +	/* update irq data & counter */
> +	if (lp_status & SRTC_LPSR_ALP) {
> +		if (lp_cr & SRTC_LPCR_ALP)
> +			events |= (RTC_AF | RTC_IRQF);
> +
> +		/* disable further lp alarm interrupts */
> +		lp_cr &= ~(SRTC_LPCR_ALP | SRTC_LPCR_WAE);
> +	}
> +
> +	/* Update interrupt enables */
> +	__raw_writel(lp_cr, ioaddr + SRTC_LPCR);
> +
> +	/* clear interrupt status */
> +	__raw_writel(lp_status, ioaddr + SRTC_LPSR);
> +
> +	rtc_write_sync_lp(ioaddr);
> +	rtc_update_irq(pdata->rtc, 1, events);
> +	return IRQ_HANDLED;
> +}
> +
see comment below...

> +/*! MXC RTC Power management control */
> +static int mxc_rtc_probe(struct platform_device *pdev)
> +{
> +	struct timespec tv;
> +	struct resource *res;
> +	struct rtc_drv_data *pdata = NULL;
> +	void __iomem *ioaddr;
> +	int ret = 0;
> +
> +	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
> +	if (!pdata)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res)
> +		return -ENODEV;
> +
> +	pdata->ioaddr = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(pdata->ioaddr))
> +		return PTR_ERR(pdata->ioaddr);
> +
> +	ioaddr = pdata->ioaddr;
> +
> +	pdata->clk = devm_clk_get(&pdev->dev, NULL);
> +	if (IS_ERR(pdata->clk)) {
> +		dev_err(&pdev->dev, "unable to get rtc clock!\n");
> +		return PTR_ERR(pdata->clk);
> +	}
> +	ret = clk_prepare_enable(pdata->clk);
> +	if (ret)
> +		return ret;
>
Is it really necessary to have the clock enabled all the time, or
should it be enabled/disabled for the register accesses only?

> +	/* Configure and enable the RTC */
> +	pdata->irq = platform_get_irq(pdev, 0);
> +	if (pdata->irq >= 0
> +	    && devm_request_irq(&pdev->dev, pdata->irq, mxc_rtc_interrupt,
> +				IRQF_SHARED, pdev->name, pdev) < 0) {
>
If requesting an IRQ with the IRQF_SHARED flag, the interrupt handler
must check whether it was responsible for the IRQ and return IRQ_NONE
if that is not the case to allow some other interrupt handler to jump
in. But AFAICS the RTC IRQ is not shared with any other device, so
requesting the IRQ with IRQF_SHARED is invalid here!

> +		dev_warn(&pdev->dev, "interrupt not available.\n");
> +		pdata->irq = -1;
> +	}
> +
> +	if (pdata->irq >= 0)
> +		device_init_wakeup(&pdev->dev, 1);
> +
> +	/* initialize glitch detect */
> +	__raw_writel(SRTC_LPPDR_INIT, ioaddr + SRTC_LPPDR);
> +	udelay(100);
> +
> +	/* clear lp interrupt status */
> +	__raw_writel(0xFFFFFFFF, ioaddr + SRTC_LPSR);
> +	udelay(100);
> +
> +	/* move out of init state */
> +	__raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NSA), ioaddr + SRTC_LPCR);
> +
> +	udelay(100);
> +
> +	while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_IES) == 0)
> +		;
>
Loops polling for the change of HW controlled bits should have a
timeout, to prevent locking up when the hardware misbehaves.

> +	/* move out of non-valid state */
> +	__raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NVE | SRTC_LPCR_NSA |
> +		      SRTC_LPCR_EN_LP), ioaddr + SRTC_LPCR);
> +
> +	udelay(100);
> +
> +	while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_NVES) == 0)
> +		;
>
dto.

> +	__raw_writel(0xFFFFFFFF, ioaddr + SRTC_LPSR);
> +	udelay(100);
> +
> +	platform_set_drvdata(pdev, pdata);
>
The IRQ handler uses platform_get_drvdata(), so this has to be done
BEFORE registering the interrupt handler.

> +	pdata->rtc =
> +	    devm_rtc_device_register(&pdev->dev, pdev->name, &mxc_rtc_ops,
> +				     THIS_MODULE);
> +	if (IS_ERR(pdata->rtc)) {
> +		ret = PTR_ERR(pdata->rtc);
> +		goto exit_put_clk;
> +	}
> +
> +	tv.tv_nsec = 0;
> +	tv.tv_sec = __raw_readl(ioaddr + SRTC_LPSCMR);
> +
> +	/* By default, devices should wakeup if they can */
> +	/* So srtc is set as "should wakeup" as it can */
>
multi line comment style?

> +	device_init_wakeup(&pdev->dev, 1);
> +
> +	return ret;
> +
> +exit_put_clk:
> +	clk_disable_unprepare(pdata->clk);
> +	return ret;
> +}
> +
> +static int __exit mxc_rtc_remove(struct platform_device *pdev)
> +{
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +
> +	clk_disable_unprepare(pdata->clk);
> +	return 0;
> +}
> +
> +/*!
> + * This function is called to save the system time delta relative to
> + * the MXC RTC when enterring a low power state. This time delta is
> + * then used on resume to adjust the system time to account for time
> + * loss while suspended.
> + *
> + * @param   pdev  not used
> + * @param   state Power state to enter.
> + *
> + * @return  The function always returns 0.
> + */
> +static int mxc_rtc_suspend(struct platform_device *pdev, pm_message_t state)
> +{
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +
> +	if (device_may_wakeup(&pdev->dev))
> +		enable_irq_wake(pdata->irq);
> +
> +	return 0;
> +}
> +
> +/*!
> + * This function is called to correct the system time based on the
> + * current MXC RTC time relative to the time delta saved during
> + * suspend.
> + *
> + * @param   pdev  not used
> + *
> + * @return  The function always returns 0.
> + */
> +static int mxc_rtc_resume(struct platform_device *pdev)
> +{
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +
> +	if (device_may_wakeup(&pdev->dev))
> +		disable_irq_wake(pdata->irq);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id mxc_ids[] = {
> +	{.compatible = "fsl,imx53-rtc",},
>
missing spaces after '{' and before '}'


Lothar Waßmann
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH] rtc: add mxc driver for i.MX53
@ 2017-11-30 11:21   ` Lothar Waßmann
  0 siblings, 0 replies; 43+ messages in thread
From: Lothar Waßmann @ 2017-11-30 11:21 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On Tue, 28 Nov 2017 08:39:27 +0100 linux-kernel-dev at beckhoff.com wrote:
> From: Patrick Bruenn <p.bruenn@beckhoff.com>
[...]
> +/*!
> + * This function is the RTC interrupt service routine.
> + *
> + * @param  irq          RTC IRQ number
> + * @param  dev_id       device ID which is not used
> + *
> + * @return IRQ_HANDLED as defined in the include/linux/interrupt.h file.
> + */
> +static irqreturn_t mxc_rtc_interrupt(int irq, void *dev_id)
> +{
> +	struct platform_device *pdev = dev_id;
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +	void __iomem *ioaddr = pdata->ioaddr;
> +	u32 lp_status, lp_cr;
> +	u32 events = 0;
> +
> +	lp_status = __raw_readl(ioaddr + SRTC_LPSR);
> +	lp_cr = __raw_readl(ioaddr + SRTC_LPCR);
> +
> +	/* update irq data & counter */
> +	if (lp_status & SRTC_LPSR_ALP) {
> +		if (lp_cr & SRTC_LPCR_ALP)
> +			events |= (RTC_AF | RTC_IRQF);
> +
> +		/* disable further lp alarm interrupts */
> +		lp_cr &= ~(SRTC_LPCR_ALP | SRTC_LPCR_WAE);
> +	}
> +
> +	/* Update interrupt enables */
> +	__raw_writel(lp_cr, ioaddr + SRTC_LPCR);
> +
> +	/* clear interrupt status */
> +	__raw_writel(lp_status, ioaddr + SRTC_LPSR);
> +
> +	rtc_write_sync_lp(ioaddr);
> +	rtc_update_irq(pdata->rtc, 1, events);
> +	return IRQ_HANDLED;
> +}
> +
see comment below...

> +/*! MXC RTC Power management control */
> +static int mxc_rtc_probe(struct platform_device *pdev)
> +{
> +	struct timespec tv;
> +	struct resource *res;
> +	struct rtc_drv_data *pdata = NULL;
> +	void __iomem *ioaddr;
> +	int ret = 0;
> +
> +	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
> +	if (!pdata)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res)
> +		return -ENODEV;
> +
> +	pdata->ioaddr = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(pdata->ioaddr))
> +		return PTR_ERR(pdata->ioaddr);
> +
> +	ioaddr = pdata->ioaddr;
> +
> +	pdata->clk = devm_clk_get(&pdev->dev, NULL);
> +	if (IS_ERR(pdata->clk)) {
> +		dev_err(&pdev->dev, "unable to get rtc clock!\n");
> +		return PTR_ERR(pdata->clk);
> +	}
> +	ret = clk_prepare_enable(pdata->clk);
> +	if (ret)
> +		return ret;
>
Is it really necessary to have the clock enabled all the time, or
should it be enabled/disabled for the register accesses only?

> +	/* Configure and enable the RTC */
> +	pdata->irq = platform_get_irq(pdev, 0);
> +	if (pdata->irq >= 0
> +	    && devm_request_irq(&pdev->dev, pdata->irq, mxc_rtc_interrupt,
> +				IRQF_SHARED, pdev->name, pdev) < 0) {
>
If requesting an IRQ with the IRQF_SHARED flag, the interrupt handler
must check whether it was responsible for the IRQ and return IRQ_NONE
if that is not the case to allow some other interrupt handler to jump
in. But AFAICS the RTC IRQ is not shared with any other device, so
requesting the IRQ with IRQF_SHARED is invalid here!

> +		dev_warn(&pdev->dev, "interrupt not available.\n");
> +		pdata->irq = -1;
> +	}
> +
> +	if (pdata->irq >= 0)
> +		device_init_wakeup(&pdev->dev, 1);
> +
> +	/* initialize glitch detect */
> +	__raw_writel(SRTC_LPPDR_INIT, ioaddr + SRTC_LPPDR);
> +	udelay(100);
> +
> +	/* clear lp interrupt status */
> +	__raw_writel(0xFFFFFFFF, ioaddr + SRTC_LPSR);
> +	udelay(100);
> +
> +	/* move out of init state */
> +	__raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NSA), ioaddr + SRTC_LPCR);
> +
> +	udelay(100);
> +
> +	while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_IES) == 0)
> +		;
>
Loops polling for the change of HW controlled bits should have a
timeout, to prevent locking up when the hardware misbehaves.

> +	/* move out of non-valid state */
> +	__raw_writel((SRTC_LPCR_IE | SRTC_LPCR_NVE | SRTC_LPCR_NSA |
> +		      SRTC_LPCR_EN_LP), ioaddr + SRTC_LPCR);
> +
> +	udelay(100);
> +
> +	while ((__raw_readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_NVES) == 0)
> +		;
>
dto.

> +	__raw_writel(0xFFFFFFFF, ioaddr + SRTC_LPSR);
> +	udelay(100);
> +
> +	platform_set_drvdata(pdev, pdata);
>
The IRQ handler uses platform_get_drvdata(), so this has to be done
BEFORE registering the interrupt handler.

> +	pdata->rtc =
> +	    devm_rtc_device_register(&pdev->dev, pdev->name, &mxc_rtc_ops,
> +				     THIS_MODULE);
> +	if (IS_ERR(pdata->rtc)) {
> +		ret = PTR_ERR(pdata->rtc);
> +		goto exit_put_clk;
> +	}
> +
> +	tv.tv_nsec = 0;
> +	tv.tv_sec = __raw_readl(ioaddr + SRTC_LPSCMR);
> +
> +	/* By default, devices should wakeup if they can */
> +	/* So srtc is set as "should wakeup" as it can */
>
multi line comment style?

> +	device_init_wakeup(&pdev->dev, 1);
> +
> +	return ret;
> +
> +exit_put_clk:
> +	clk_disable_unprepare(pdata->clk);
> +	return ret;
> +}
> +
> +static int __exit mxc_rtc_remove(struct platform_device *pdev)
> +{
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +
> +	clk_disable_unprepare(pdata->clk);
> +	return 0;
> +}
> +
> +/*!
> + * This function is called to save the system time delta relative to
> + * the MXC RTC when enterring a low power state. This time delta is
> + * then used on resume to adjust the system time to account for time
> + * loss while suspended.
> + *
> + * @param   pdev  not used
> + * @param   state Power state to enter.
> + *
> + * @return  The function always returns 0.
> + */
> +static int mxc_rtc_suspend(struct platform_device *pdev, pm_message_t state)
> +{
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +
> +	if (device_may_wakeup(&pdev->dev))
> +		enable_irq_wake(pdata->irq);
> +
> +	return 0;
> +}
> +
> +/*!
> + * This function is called to correct the system time based on the
> + * current MXC RTC time relative to the time delta saved during
> + * suspend.
> + *
> + * @param   pdev  not used
> + *
> + * @return  The function always returns 0.
> + */
> +static int mxc_rtc_resume(struct platform_device *pdev)
> +{
> +	struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
> +
> +	if (device_may_wakeup(&pdev->dev))
> +		disable_irq_wake(pdata->irq);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id mxc_ids[] = {
> +	{.compatible = "fsl,imx53-rtc",},
>
missing spaces after '{' and before '}'


Lothar Wa?mann

^ permalink raw reply	[flat|nested] 43+ messages in thread

* RE: [PATCH] rtc: add mxc driver for i.MX53
  2017-11-30  8:18     ` Philippe Ombredanne
  (?)
  (?)
@ 2017-11-30 13:36       ` Patrick Brünn
  -1 siblings, 0 replies; 43+ messages in thread
From: Patrick Brünn @ 2017-11-30 13:36 UTC (permalink / raw)
  To: Philippe Ombredanne, Greg Kroah-Hartman
  Cc: linux-kernel-dev, Alessandro Zummo, Alexandre Belloni,
	Rob Herring, Mark Rutland,
	open list:REAL TIME CLOCK (RTC) SUBSYSTEM,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	open list, Fabio Estevam, Juergen Borleis, Noel Vellemans,
	Shawn Guo, Sascha Hauer, Russell King,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE

>From: Philippe Ombredanne [mailto:pombredanne@nexb.com]
>Sent: Donnerstag, 30. November 2017 09:18
>>
>>> +/*
>>> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
>Reserved.
>>> + */
>>> +
>>> +/*
>>> + * The code contained herein is licensed under the GNU General Public
>>> + * License. You may obtain a copy of the GNU General Public License
>>> + * Version 2 or later at the following locations:
>>> + *
>>> + * http://www.opensource.org/licenses/gpl-license.html
>>> + * http://www.gnu.org/copyleft/gpl.html
>>> + */
>
>Exactly!
>And while you are it , you could replace the boilerplate license text
>with the SPDX id.
>--

How would a perfect header look like?
Looking at :
git show b24413180f5600bcb3bb70fbed5cf186b60864bd -- drivers/
and:
git grep SPDX -- Documentation/

it could be:
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
+ */
or:
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
+ */

Personally I would prefer:
+/*
+ * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */

So, is there any guideline?

To be clear: I don't want to waste anyone's time on this. But as SPDX
was intended for automation, I think it might be good to try having
some common pattern here.
I don't want to start a discussion, so in case there is no guideline I will
just take the /* SPDX */ in firstline version.

Regards, Patrick

Beckhoff Automation GmbH & Co. KG | Managing Director: Dipl. Phys. Hans Beckhoff
Registered office: Verl, Germany | Register court: Guetersloh HRA 7075

^ permalink raw reply	[flat|nested] 43+ messages in thread

* RE: [PATCH] rtc: add mxc driver for i.MX53
@ 2017-11-30 13:36       ` Patrick Brünn
  0 siblings, 0 replies; 43+ messages in thread
From: Patrick Brünn @ 2017-11-30 13:36 UTC (permalink / raw)
  To: Philippe Ombredanne, Greg Kroah-Hartman
  Cc: linux-kernel-dev, Alessandro Zummo, Alexandre Belloni,
	Rob Herring, Mark Rutland,
	open list:REAL TIME CLOCK (RTC) SUBSYSTEM,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	open list, Fabio Estevam, Juergen Borleis, Noel Vellemans,
	Shawn Guo, Sascha Hauer, Russell King,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE

PkZyb206IFBoaWxpcHBlIE9tYnJlZGFubmUgW21haWx0bzpwb21icmVkYW5uZUBuZXhiLmNvbV0N
Cj5TZW50OiBEb25uZXJzdGFnLCAzMC4gTm92ZW1iZXIgMjAxNyAwOToxOA0KPj4NCj4+PiArLyoN
Cj4+PiArICogQ29weXJpZ2h0IChDKSAyMDA0LTIwMTEgRnJlZXNjYWxlIFNlbWljb25kdWN0b3Is
IEluYy4gQWxsIFJpZ2h0cw0KPlJlc2VydmVkLg0KPj4+ICsgKi8NCj4+PiArDQo+Pj4gKy8qDQo+
Pj4gKyAqIFRoZSBjb2RlIGNvbnRhaW5lZCBoZXJlaW4gaXMgbGljZW5zZWQgdW5kZXIgdGhlIEdO
VSBHZW5lcmFsIFB1YmxpYw0KPj4+ICsgKiBMaWNlbnNlLiBZb3UgbWF5IG9idGFpbiBhIGNvcHkg
b2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlDQo+Pj4gKyAqIFZlcnNpb24gMiBvciBs
YXRlciBhdCB0aGUgZm9sbG93aW5nIGxvY2F0aW9uczoNCj4+PiArICoNCj4+PiArICogaHR0cDov
L3d3dy5vcGVuc291cmNlLm9yZy9saWNlbnNlcy9ncGwtbGljZW5zZS5odG1sDQo+Pj4gKyAqIGh0
dHA6Ly93d3cuZ251Lm9yZy9jb3B5bGVmdC9ncGwuaHRtbA0KPj4+ICsgKi8NCj4NCj5FeGFjdGx5
IQ0KPkFuZCB3aGlsZSB5b3UgYXJlIGl0ICwgeW91IGNvdWxkIHJlcGxhY2UgdGhlIGJvaWxlcnBs
YXRlIGxpY2Vuc2UgdGV4dA0KPndpdGggdGhlIFNQRFggaWQuDQo+LS0NCg0KSG93IHdvdWxkIGEg
cGVyZmVjdCBoZWFkZXIgbG9vayBsaWtlPw0KTG9va2luZyBhdCA6DQpnaXQgc2hvdyBiMjQ0MTMx
ODBmNTYwMGJjYjNiYjcwZmJlZDVjZjE4NmI2MDg2NGJkIC0tIGRyaXZlcnMvDQphbmQ6DQpnaXQg
Z3JlcCBTUERYIC0tIERvY3VtZW50YXRpb24vDQoNCml0IGNvdWxkIGJlOg0KKy8qIFNQRFgtTGlj
ZW5zZS1JZGVudGlmaWVyOiBHUEwtMi4wICovDQorLyoNCisgKiBDb3B5cmlnaHQgKEMpIDIwMDQt
MjAxMSBGcmVlc2NhbGUgU2VtaWNvbmR1Y3RvciwgSW5jLiBBbGwgUmlnaHRzDQorICovDQpvcjoN
CisvLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogR1BMLTIuMA0KKy8qDQorICogQ29weXJpZ2h0
IChDKSAyMDA0LTIwMTEgRnJlZXNjYWxlIFNlbWljb25kdWN0b3IsIEluYy4gQWxsIFJpZ2h0cw0K
KyAqLw0KDQpQZXJzb25hbGx5IEkgd291bGQgcHJlZmVyOg0KKy8qDQorICogQ29weXJpZ2h0IChD
KSAyMDA0LTIwMTEgRnJlZXNjYWxlIFNlbWljb25kdWN0b3IsIEluYy4gQWxsIFJpZ2h0cw0KKyAq
DQorICogU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEdQTC0yLjANCisgKi8NCg0KU28sIGlzIHRo
ZXJlIGFueSBndWlkZWxpbmU/DQoNClRvIGJlIGNsZWFyOiBJIGRvbid0IHdhbnQgdG8gd2FzdGUg
YW55b25lJ3MgdGltZSBvbiB0aGlzLiBCdXQgYXMgU1BEWA0Kd2FzIGludGVuZGVkIGZvciBhdXRv
bWF0aW9uLCBJIHRoaW5rIGl0IG1pZ2h0IGJlIGdvb2QgdG8gdHJ5IGhhdmluZw0Kc29tZSBjb21t
b24gcGF0dGVybiBoZXJlLg0KSSBkb24ndCB3YW50IHRvIHN0YXJ0IGEgZGlzY3Vzc2lvbiwgc28g
aW4gY2FzZSB0aGVyZSBpcyBubyBndWlkZWxpbmUgSSB3aWxsDQpqdXN0IHRha2UgdGhlIC8qIFNQ
RFggKi8gaW4gZmlyc3RsaW5lIHZlcnNpb24uDQoNClJlZ2FyZHMsIFBhdHJpY2sNCg0KQmVja2hv
ZmYgQXV0b21hdGlvbiBHbWJIICYgQ28uIEtHIHwgTWFuYWdpbmcgRGlyZWN0b3I6IERpcGwuIFBo
eXMuIEhhbnMgQmVja2hvZmYNClJlZ2lzdGVyZWQgb2ZmaWNlOiBWZXJsLCBHZXJtYW55IHwgUmVn
aXN0ZXIgY291cnQ6IEd1ZXRlcnNsb2ggSFJBIDcwNzUNCg0KDQo=

^ permalink raw reply	[flat|nested] 43+ messages in thread

* RE: [PATCH] rtc: add mxc driver for i.MX53
@ 2017-11-30 13:36       ` Patrick Brünn
  0 siblings, 0 replies; 43+ messages in thread
From: Patrick Brünn @ 2017-11-30 13:36 UTC (permalink / raw)
  To: Philippe Ombredanne, Greg Kroah-Hartman
  Cc: linux-kernel-dev, Alessandro Zummo, Alexandre Belloni,
	Rob Herring, Mark Rutland,
	open list:REAL TIME CLOCK (RTC) SUBSYSTEM,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	open list, Fabio Estevam, Juergen Borleis, Noel Vellemans,
	Shawn Guo, Sascha Hauer, Russell King,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE

>From: Philippe Ombredanne [mailto:pombredanne@nexb.com]
>Sent: Donnerstag, 30. November 2017 09:18
>>
>>> +/*
>>> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
>Reserved.
>>> + */
>>> +
>>> +/*
>>> + * The code contained herein is licensed under the GNU General Public
>>> + * License. You may obtain a copy of the GNU General Public License
>>> + * Version 2 or later at the following locations:
>>> + *
>>> + * http://www.opensource.org/licenses/gpl-license.html
>>> + * http://www.gnu.org/copyleft/gpl.html
>>> + */
>
>Exactly!
>And while you are it , you could replace the boilerplate license text
>with the SPDX id.
>--

How would a perfect header look like?
Looking at :
git show b24413180f5600bcb3bb70fbed5cf186b60864bd -- drivers/
and:
git grep SPDX -- Documentation/

it could be:
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
+ */
or:
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
+ */

Personally I would prefer:
+/*
+ * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */

So, is there any guideline?

To be clear: I don't want to waste anyone's time on this. But as SPDX
was intended for automation, I think it might be good to try having
some common pattern here.
I don't want to start a discussion, so in case there is no guideline I will
just take the /* SPDX */ in firstline version.

Regards, Patrick

Beckhoff Automation GmbH & Co. KG | Managing Director: Dipl. Phys. Hans Beckhoff
Registered office: Verl, Germany | Register court: Guetersloh HRA 7075



^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH] rtc: add mxc driver for i.MX53
@ 2017-11-30 13:36       ` Patrick Brünn
  0 siblings, 0 replies; 43+ messages in thread
From: Patrick Brünn @ 2017-11-30 13:36 UTC (permalink / raw)
  To: linux-arm-kernel

>From: Philippe Ombredanne [mailto:pombredanne at nexb.com]
>Sent: Donnerstag, 30. November 2017 09:18
>>
>>> +/*
>>> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
>Reserved.
>>> + */
>>> +
>>> +/*
>>> + * The code contained herein is licensed under the GNU General Public
>>> + * License. You may obtain a copy of the GNU General Public License
>>> + * Version 2 or later at the following locations:
>>> + *
>>> + * http://www.opensource.org/licenses/gpl-license.html
>>> + * http://www.gnu.org/copyleft/gpl.html
>>> + */
>
>Exactly!
>And while you are it , you could replace the boilerplate license text
>with the SPDX id.
>--

How would a perfect header look like?
Looking at :
git show b24413180f5600bcb3bb70fbed5cf186b60864bd -- drivers/
and:
git grep SPDX -- Documentation/

it could be:
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
+ */
or:
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
+ */

Personally I would prefer:
+/*
+ * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */

So, is there any guideline?

To be clear: I don't want to waste anyone's time on this. But as SPDX
was intended for automation, I think it might be good to try having
some common pattern here.
I don't want to start a discussion, so in case there is no guideline I will
just take the /* SPDX */ in firstline version.

Regards, Patrick

Beckhoff Automation GmbH & Co. KG | Managing Director: Dipl. Phys. Hans Beckhoff
Registered office: Verl, Germany | Register court: Guetersloh HRA 7075

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] rtc: add mxc driver for i.MX53
  2017-11-30 13:36       ` Patrick Brünn
  (?)
  (?)
@ 2017-11-30 13:42         ` Alexandre Belloni
  -1 siblings, 0 replies; 43+ messages in thread
From: Alexandre Belloni @ 2017-11-30 13:42 UTC (permalink / raw)
  To: Patrick Brünn
  Cc: Philippe Ombredanne, Greg Kroah-Hartman, linux-kernel-dev,
	Alessandro Zummo, Rob Herring, Mark Rutland,
	open list:REAL TIME CLOCK (RTC) SUBSYSTEM,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	open list, Fabio Estevam, Juergen Borleis, Noel Vellemans,
	Shawn Guo, Sascha Hauer, Russell King,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE

Hi,

On 30/11/2017 at 13:36:22 +0000, Patrick Brünn wrote:
> >From: Philippe Ombredanne [mailto:pombredanne@nexb.com]
> >Sent: Donnerstag, 30. November 2017 09:18
> >>
> >>> +/*
> >>> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
> >Reserved.
> >>> + */
> >>> +
> >>> +/*
> >>> + * The code contained herein is licensed under the GNU General Public
> >>> + * License. You may obtain a copy of the GNU General Public License
> >>> + * Version 2 or later at the following locations:
> >>> + *
> >>> + * http://www.opensource.org/licenses/gpl-license.html
> >>> + * http://www.gnu.org/copyleft/gpl.html
> >>> + */
> >
> >Exactly!
> >And while you are it , you could replace the boilerplate license text
> >with the SPDX id.
> >--
> 
> How would a perfect header look like?
> Looking at :
> git show b24413180f5600bcb3bb70fbed5cf186b60864bd -- drivers/
> and:
> git grep SPDX -- Documentation/
> 
> it could be:
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
> + */
> or:
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
> + */
> 
> Personally I would prefer:
> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
> + *
> + * SPDX-License-Identifier: GPL-2.0
> + */
> 
> So, is there any guideline?
> 

I'm quoting LWN here:

"For normal C source files, the string will be a comment using the "//"
syntax; header files, instead, use traditional (/* */) comments for
reasons related to tooling."

> To be clear: I don't want to waste anyone's time on this. But as SPDX
> was intended for automation, I think it might be good to try having
> some common pattern here.
> I don't want to start a discussion, so in case there is no guideline I will
> just take the /* SPDX */ in firstline version.

-- 
Alexandre Belloni, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] rtc: add mxc driver for i.MX53
@ 2017-11-30 13:42         ` Alexandre Belloni
  0 siblings, 0 replies; 43+ messages in thread
From: Alexandre Belloni @ 2017-11-30 13:42 UTC (permalink / raw)
  To: Patrick Brünn
  Cc: Philippe Ombredanne, Greg Kroah-Hartman, linux-kernel-dev,
	Alessandro Zummo, Rob Herring, Mark Rutland,
	open list:REAL TIME CLOCK (RTC) SUBSYSTEM,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	open list, Fabio Estevam, Juergen Borleis, Noel Vellemans,
	Shawn Guo, Sascha Hauer, Russell King,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE

Hi,

On 30/11/2017 at 13:36:22 +0000, Patrick Brünn wrote:
> >From: Philippe Ombredanne [mailto:pombredanne@nexb.com]
> >Sent: Donnerstag, 30. November 2017 09:18
> >>
> >>> +/*
> >>> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
> >Reserved.
> >>> + */
> >>> +
> >>> +/*
> >>> + * The code contained herein is licensed under the GNU General Public
> >>> + * License. You may obtain a copy of the GNU General Public License
> >>> + * Version 2 or later at the following locations:
> >>> + *
> >>> + * http://www.opensource.org/licenses/gpl-license.html
> >>> + * http://www.gnu.org/copyleft/gpl.html
> >>> + */
> >
> >Exactly!
> >And while you are it , you could replace the boilerplate license text
> >with the SPDX id.
> >--
> 
> How would a perfect header look like?
> Looking at :
> git show b24413180f5600bcb3bb70fbed5cf186b60864bd -- drivers/
> and:
> git grep SPDX -- Documentation/
> 
> it could be:
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
> + */
> or:
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
> + */
> 
> Personally I would prefer:
> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
> + *
> + * SPDX-License-Identifier: GPL-2.0
> + */
> 
> So, is there any guideline?
> 

I'm quoting LWN here:

"For normal C source files, the string will be a comment using the "//"
syntax; header files, instead, use traditional (/* */) comments for
reasons related to tooling."

> To be clear: I don't want to waste anyone's time on this. But as SPDX
> was intended for automation, I think it might be good to try having
> some common pattern here.
> I don't want to start a discussion, so in case there is no guideline I will
> just take the /* SPDX */ in firstline version.

-- 
Alexandre Belloni, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] rtc: add mxc driver for i.MX53
@ 2017-11-30 13:42         ` Alexandre Belloni
  0 siblings, 0 replies; 43+ messages in thread
From: Alexandre Belloni @ 2017-11-30 13:42 UTC (permalink / raw)
  To: Patrick Brünn
  Cc: Philippe Ombredanne, Greg Kroah-Hartman, linux-kernel-dev,
	Alessandro Zummo, Rob Herring, Mark Rutland,
	open list:REAL TIME CLOCK (RTC) SUBSYSTEM,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	open list, Fabio Estevam, Juergen Borleis, Noel Vellemans,
	Shawn Guo, Sascha Hauer, Russell King, ARM/FREESCALE

Hi,

On 30/11/2017 at 13:36:22 +0000, Patrick Brünn wrote:
> >From: Philippe Ombredanne [mailto:pombredanne@nexb.com]
> >Sent: Donnerstag, 30. November 2017 09:18
> >>
> >>> +/*
> >>> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
> >Reserved.
> >>> + */
> >>> +
> >>> +/*
> >>> + * The code contained herein is licensed under the GNU General Public
> >>> + * License. You may obtain a copy of the GNU General Public License
> >>> + * Version 2 or later at the following locations:
> >>> + *
> >>> + * http://www.opensource.org/licenses/gpl-license.html
> >>> + * http://www.gnu.org/copyleft/gpl.html
> >>> + */
> >
> >Exactly!
> >And while you are it , you could replace the boilerplate license text
> >with the SPDX id.
> >--
> 
> How would a perfect header look like?
> Looking at :
> git show b24413180f5600bcb3bb70fbed5cf186b60864bd -- drivers/
> and:
> git grep SPDX -- Documentation/
> 
> it could be:
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
> + */
> or:
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
> + */
> 
> Personally I would prefer:
> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
> + *
> + * SPDX-License-Identifier: GPL-2.0
> + */
> 
> So, is there any guideline?
> 

I'm quoting LWN here:

"For normal C source files, the string will be a comment using the "//"
syntax; header files, instead, use traditional (/* */) comments for
reasons related to tooling."

> To be clear: I don't want to waste anyone's time on this. But as SPDX
> was intended for automation, I think it might be good to try having
> some common pattern here.
> I don't want to start a discussion, so in case there is no guideline I will
> just take the /* SPDX */ in firstline version.

-- 
Alexandre Belloni, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH] rtc: add mxc driver for i.MX53
@ 2017-11-30 13:42         ` Alexandre Belloni
  0 siblings, 0 replies; 43+ messages in thread
From: Alexandre Belloni @ 2017-11-30 13:42 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 30/11/2017 at 13:36:22 +0000, Patrick Br?nn wrote:
> >From: Philippe Ombredanne [mailto:pombredanne at nexb.com]
> >Sent: Donnerstag, 30. November 2017 09:18
> >>
> >>> +/*
> >>> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
> >Reserved.
> >>> + */
> >>> +
> >>> +/*
> >>> + * The code contained herein is licensed under the GNU General Public
> >>> + * License. You may obtain a copy of the GNU General Public License
> >>> + * Version 2 or later at the following locations:
> >>> + *
> >>> + * http://www.opensource.org/licenses/gpl-license.html
> >>> + * http://www.gnu.org/copyleft/gpl.html
> >>> + */
> >
> >Exactly!
> >And while you are it , you could replace the boilerplate license text
> >with the SPDX id.
> >--
> 
> How would a perfect header look like?
> Looking at :
> git show b24413180f5600bcb3bb70fbed5cf186b60864bd -- drivers/
> and:
> git grep SPDX -- Documentation/
> 
> it could be:
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
> + */
> or:
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
> + */
> 
> Personally I would prefer:
> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
> + *
> + * SPDX-License-Identifier: GPL-2.0
> + */
> 
> So, is there any guideline?
> 

I'm quoting LWN here:

"For normal C source files, the string will be a comment using the "//"
syntax; header files, instead, use traditional (/* */) comments for
reasons related to tooling."

> To be clear: I don't want to waste anyone's time on this. But as SPDX
> was intended for automation, I think it might be good to try having
> some common pattern here.
> I don't want to start a discussion, so in case there is no guideline I will
> just take the /* SPDX */ in firstline version.

-- 
Alexandre Belloni, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] rtc: add mxc driver for i.MX53
  2017-11-30 13:36       ` Patrick Brünn
  (?)
  (?)
@ 2017-11-30 14:00         ` Philippe Ombredanne
  -1 siblings, 0 replies; 43+ messages in thread
From: Philippe Ombredanne @ 2017-11-30 14:00 UTC (permalink / raw)
  To: Patrick Brünn, Thomas Gleixner
  Cc: Greg Kroah-Hartman, linux-kernel-dev, Alessandro Zummo,
	Alexandre Belloni, Rob Herring, Mark Rutland,
	open list:REAL TIME CLOCK (RTC) SUBSYSTEM,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	open list, Fabio Estevam, Juergen Borleis, Noel Vellemans,
	Shawn Guo, Sascha Hauer, Russell King,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE

On Thu, Nov 30, 2017 at 2:36 PM, Patrick Brünn <P.Bruenn@beckhoff.com> wrote:
>>From: Philippe Ombredanne [mailto:pombredanne@nexb.com]
>>Sent: Donnerstag, 30. November 2017 09:18
>>>
>>>> +/*
>>>> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
>>Reserved.
>>>> + */
>>>> +
>>>> +/*
>>>> + * The code contained herein is licensed under the GNU General Public
>>>> + * License. You may obtain a copy of the GNU General Public License
>>>> + * Version 2 or later at the following locations:
>>>> + *
>>>> + * http://www.opensource.org/licenses/gpl-license.html
>>>> + * http://www.gnu.org/copyleft/gpl.html
>>>> + */
>>
>>Exactly!
>>And while you are it , you could replace the boilerplate license text
>>with the SPDX id.
>>--
>
> How would a perfect header look like?
> Looking at :
> git show b24413180f5600bcb3bb70fbed5cf186b60864bd -- drivers/
> and:
> git grep SPDX -- Documentation/
>
> it could be:
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
> + */
> or:
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
> + */
>
> Personally I would prefer:
> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
> + *
> + * SPDX-License-Identifier: GPL-2.0
> + */
>
> So, is there any guideline?
>
> To be clear: I don't want to waste anyone's time on this. But as SPDX
> was intended for automation, I think it might be good to try having
> some common pattern here.
> I don't want to start a discussion, so in case there is no guideline I will
> just take the /* SPDX */ in firstline version.

Patrick:

There are several threads on the topic explaining why: Linus made it
clear that he wants this, and on the first line:

> +// SPDX-License-Identifier: GPL-2.0


Thomas:
I tend to prefer as Linus pointed the // style throughout when there
is only a license and copyright involved. Here this would mean:

> +// SPDX-License-Identifier: GPL-2.0
> +// Copyright (c) 2004-2011 Freescale Semiconductor, Inc. All Rights Reserved.

What's you take since you wrote the doc for this? And is there still
some updates needed for this since your last patch set?


Patrick:
Side note a trailing  "All Rights Reserved." in a copyright statement
is never needed, even though customarily cargo culted by everyone,
including me.
Started in 1910, it become fully obsolete in 2000 thanks to Nicaragua
[1] signing the Berne convention.

[1] https://en.wikipedia.org/wiki/All_rights_reserved
-- 
Cordially
Philippe Ombredanne

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] rtc: add mxc driver for i.MX53
@ 2017-11-30 14:00         ` Philippe Ombredanne
  0 siblings, 0 replies; 43+ messages in thread
From: Philippe Ombredanne @ 2017-11-30 14:00 UTC (permalink / raw)
  To: Patrick Brünn, Thomas Gleixner
  Cc: Greg Kroah-Hartman, linux-kernel-dev, Alessandro Zummo,
	Alexandre Belloni, Rob Herring, Mark Rutland,
	open list:REAL TIME CLOCK (RTC) SUBSYSTEM,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	open list, Fabio Estevam, Juergen Borleis, Noel Vellemans,
	Shawn Guo, Sascha Hauer, Russell King,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE

On Thu, Nov 30, 2017 at 2:36 PM, Patrick Br=C3=BCnn <P.Bruenn@beckhoff.com>=
 wrote:
>>From: Philippe Ombredanne [mailto:pombredanne@nexb.com]
>>Sent: Donnerstag, 30. November 2017 09:18
>>>
>>>> +/*
>>>> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
>>Reserved.
>>>> + */
>>>> +
>>>> +/*
>>>> + * The code contained herein is licensed under the GNU General Public
>>>> + * License. You may obtain a copy of the GNU General Public License
>>>> + * Version 2 or later at the following locations:
>>>> + *
>>>> + * http://www.opensource.org/licenses/gpl-license.html
>>>> + * http://www.gnu.org/copyleft/gpl.html
>>>> + */
>>
>>Exactly!
>>And while you are it , you could replace the boilerplate license text
>>with the SPDX id.
>>--
>
> How would a perfect header look like?
> Looking at :
> git show b24413180f5600bcb3bb70fbed5cf186b60864bd -- drivers/
> and:
> git grep SPDX -- Documentation/
>
> it could be:
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
> + */
> or:
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
> + */
>
> Personally I would prefer:
> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
> + *
> + * SPDX-License-Identifier: GPL-2.0
> + */
>
> So, is there any guideline?
>
> To be clear: I don't want to waste anyone's time on this. But as SPDX
> was intended for automation, I think it might be good to try having
> some common pattern here.
> I don't want to start a discussion, so in case there is no guideline I wi=
ll
> just take the /* SPDX */ in firstline version.

Patrick:

There are several threads on the topic explaining why: Linus made it
clear that he wants this, and on the first line:

> +// SPDX-License-Identifier: GPL-2.0


Thomas:
I tend to prefer as Linus pointed the // style throughout when there
is only a license and copyright involved. Here this would mean:

> +// SPDX-License-Identifier: GPL-2.0
> +// Copyright (c) 2004-2011 Freescale Semiconductor, Inc. All Rights Rese=
rved.

What's you take since you wrote the doc for this? And is there still
some updates needed for this since your last patch set?


Patrick:
Side note a trailing  "All Rights Reserved." in a copyright statement
is never needed, even though customarily cargo culted by everyone,
including me.
Started in 1910, it become fully obsolete in 2000 thanks to Nicaragua
[1] signing the Berne convention.

[1] https://en.wikipedia.org/wiki/All_rights_reserved
--=20
Cordially
Philippe Ombredanne

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] rtc: add mxc driver for i.MX53
@ 2017-11-30 14:00         ` Philippe Ombredanne
  0 siblings, 0 replies; 43+ messages in thread
From: Philippe Ombredanne @ 2017-11-30 14:00 UTC (permalink / raw)
  To: Patrick Brünn, Thomas Gleixner
  Cc: Greg Kroah-Hartman, linux-kernel-dev, Alessandro Zummo,
	Alexandre Belloni, Rob Herring, Mark Rutland,
	open list:REAL TIME CLOCK (RTC) SUBSYSTEM,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	open list, Fabio Estevam, Juergen Borleis, Noel Vellemans,
	Shawn Guo, Sascha Hauer, Russell King, ARM/FREESCALE

On Thu, Nov 30, 2017 at 2:36 PM, Patrick Brünn <P.Bruenn-QonKdJ6Bx35Wk0Htik3J/w@public.gmane.org> wrote:
>>From: Philippe Ombredanne [mailto:pombredanne-od1rfyK75/E@public.gmane.org]
>>Sent: Donnerstag, 30. November 2017 09:18
>>>
>>>> +/*
>>>> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
>>Reserved.
>>>> + */
>>>> +
>>>> +/*
>>>> + * The code contained herein is licensed under the GNU General Public
>>>> + * License. You may obtain a copy of the GNU General Public License
>>>> + * Version 2 or later at the following locations:
>>>> + *
>>>> + * http://www.opensource.org/licenses/gpl-license.html
>>>> + * http://www.gnu.org/copyleft/gpl.html
>>>> + */
>>
>>Exactly!
>>And while you are it , you could replace the boilerplate license text
>>with the SPDX id.
>>--
>
> How would a perfect header look like?
> Looking at :
> git show b24413180f5600bcb3bb70fbed5cf186b60864bd -- drivers/
> and:
> git grep SPDX -- Documentation/
>
> it could be:
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
> + */
> or:
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
> + */
>
> Personally I would prefer:
> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
> + *
> + * SPDX-License-Identifier: GPL-2.0
> + */
>
> So, is there any guideline?
>
> To be clear: I don't want to waste anyone's time on this. But as SPDX
> was intended for automation, I think it might be good to try having
> some common pattern here.
> I don't want to start a discussion, so in case there is no guideline I will
> just take the /* SPDX */ in firstline version.

Patrick:

There are several threads on the topic explaining why: Linus made it
clear that he wants this, and on the first line:

> +// SPDX-License-Identifier: GPL-2.0


Thomas:
I tend to prefer as Linus pointed the // style throughout when there
is only a license and copyright involved. Here this would mean:

> +// SPDX-License-Identifier: GPL-2.0
> +// Copyright (c) 2004-2011 Freescale Semiconductor, Inc. All Rights Reserved.

What's you take since you wrote the doc for this? And is there still
some updates needed for this since your last patch set?


Patrick:
Side note a trailing  "All Rights Reserved." in a copyright statement
is never needed, even though customarily cargo culted by everyone,
including me.
Started in 1910, it become fully obsolete in 2000 thanks to Nicaragua
[1] signing the Berne convention.

[1] https://en.wikipedia.org/wiki/All_rights_reserved
-- 
Cordially
Philippe Ombredanne
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH] rtc: add mxc driver for i.MX53
@ 2017-11-30 14:00         ` Philippe Ombredanne
  0 siblings, 0 replies; 43+ messages in thread
From: Philippe Ombredanne @ 2017-11-30 14:00 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Nov 30, 2017 at 2:36 PM, Patrick Br?nn <P.Bruenn@beckhoff.com> wrote:
>>From: Philippe Ombredanne [mailto:pombredanne at nexb.com]
>>Sent: Donnerstag, 30. November 2017 09:18
>>>
>>>> +/*
>>>> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
>>Reserved.
>>>> + */
>>>> +
>>>> +/*
>>>> + * The code contained herein is licensed under the GNU General Public
>>>> + * License. You may obtain a copy of the GNU General Public License
>>>> + * Version 2 or later at the following locations:
>>>> + *
>>>> + * http://www.opensource.org/licenses/gpl-license.html
>>>> + * http://www.gnu.org/copyleft/gpl.html
>>>> + */
>>
>>Exactly!
>>And while you are it , you could replace the boilerplate license text
>>with the SPDX id.
>>--
>
> How would a perfect header look like?
> Looking at :
> git show b24413180f5600bcb3bb70fbed5cf186b60864bd -- drivers/
> and:
> git grep SPDX -- Documentation/
>
> it could be:
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
> + */
> or:
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
> + */
>
> Personally I would prefer:
> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
> + *
> + * SPDX-License-Identifier: GPL-2.0
> + */
>
> So, is there any guideline?
>
> To be clear: I don't want to waste anyone's time on this. But as SPDX
> was intended for automation, I think it might be good to try having
> some common pattern here.
> I don't want to start a discussion, so in case there is no guideline I will
> just take the /* SPDX */ in firstline version.

Patrick:

There are several threads on the topic explaining why: Linus made it
clear that he wants this, and on the first line:

> +// SPDX-License-Identifier: GPL-2.0


Thomas:
I tend to prefer as Linus pointed the // style throughout when there
is only a license and copyright involved. Here this would mean:

> +// SPDX-License-Identifier: GPL-2.0
> +// Copyright (c) 2004-2011 Freescale Semiconductor, Inc. All Rights Reserved.

What's you take since you wrote the doc for this? And is there still
some updates needed for this since your last patch set?


Patrick:
Side note a trailing  "All Rights Reserved." in a copyright statement
is never needed, even though customarily cargo culted by everyone,
including me.
Started in 1910, it become fully obsolete in 2000 thanks to Nicaragua
[1] signing the Berne convention.

[1] https://en.wikipedia.org/wiki/All_rights_reserved
-- 
Cordially
Philippe Ombredanne

^ permalink raw reply	[flat|nested] 43+ messages in thread

* RE: [PATCH] rtc: add mxc driver for i.MX53
  2017-11-30 14:00         ` Philippe Ombredanne
  (?)
  (?)
@ 2017-11-30 14:24           ` Patrick Brünn
  -1 siblings, 0 replies; 43+ messages in thread
From: Patrick Brünn @ 2017-11-30 14:24 UTC (permalink / raw)
  To: Philippe Ombredanne, Thomas Gleixner
  Cc: Greg Kroah-Hartman, linux-kernel-dev, Alessandro Zummo,
	Alexandre Belloni, Rob Herring, Mark Rutland,
	open list:REAL TIME CLOCK (RTC) SUBSYSTEM,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	open list, Fabio Estevam, Juergen Borleis, Noel Vellemans,
	Shawn Guo, Sascha Hauer, Russell King,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE

>From: Philippe Ombredanne [mailto:pombredanne@nexb.com]
>Sent: Donnerstag, 30. November 2017 15:00
>On Thu, Nov 30, 2017 at 2:36 PM, Patrick Brünn <P.Bruenn@beckhoff.com>
>wrote:
>
>Thomas:
>I tend to prefer as Linus pointed the // style throughout when there
>is only a license and copyright involved. Here this would mean:
>
>> +// SPDX-License-Identifier: GPL-2.0
>> +// Copyright (c) 2004-2011 Freescale Semiconductor, Inc. All Rights
>Reserved.
>
>What's you take since you wrote the doc for this? And is there still
>some updates needed for this since your last patch set?
>
While looking closer into different files I think it would become multiline again:
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Real Time Clock (RTC) Driver for i.MX53
+ * Copyright (c) 2004-2011 Freescale Semiconductor, Inc.
+ * Copyright (c) 2017 Beckhoff Automation GmbH & Co. KG
+ */

>
>Patrick:
>Side note a trailing  "All Rights Reserved." in a copyright statement
>is never needed, even though customarily cargo culted by everyone,
>including me.
>Started in 1910, it become fully obsolete in 2000 thanks to Nicaragua
>[1] signing the Berne convention.
>
>[1] https://en.wikipedia.org/wiki/All_rights_reserved
Interessting. I just kept it because it was in the original file from freescale.
But with this background, I think it's fine to drop it, now.

Thanks,
Patrick
Beckhoff Automation GmbH & Co. KG | Managing Director: Dipl. Phys. Hans Beckhoff
Registered office: Verl, Germany | Register court: Guetersloh HRA 7075

^ permalink raw reply	[flat|nested] 43+ messages in thread

* RE: [PATCH] rtc: add mxc driver for i.MX53
@ 2017-11-30 14:24           ` Patrick Brünn
  0 siblings, 0 replies; 43+ messages in thread
From: Patrick Brünn @ 2017-11-30 14:24 UTC (permalink / raw)
  To: Philippe Ombredanne, Thomas Gleixner
  Cc: Greg Kroah-Hartman, linux-kernel-dev, Alessandro Zummo,
	Alexandre Belloni, Rob Herring, Mark Rutland,
	open list:REAL TIME CLOCK (RTC) SUBSYSTEM,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	open list, Fabio Estevam, Juergen Borleis, Noel Vellemans,
	Shawn Guo, Sascha Hauer, Russell King,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE

PkZyb206IFBoaWxpcHBlIE9tYnJlZGFubmUgW21haWx0bzpwb21icmVkYW5uZUBuZXhiLmNvbV0N
Cj5TZW50OiBEb25uZXJzdGFnLCAzMC4gTm92ZW1iZXIgMjAxNyAxNTowMA0KPk9uIFRodSwgTm92
IDMwLCAyMDE3IGF0IDI6MzYgUE0sIFBhdHJpY2sgQnLDvG5uIDxQLkJydWVubkBiZWNraG9mZi5j
b20+DQo+d3JvdGU6DQo+DQo+VGhvbWFzOg0KPkkgdGVuZCB0byBwcmVmZXIgYXMgTGludXMgcG9p
bnRlZCB0aGUgLy8gc3R5bGUgdGhyb3VnaG91dCB3aGVuIHRoZXJlDQo+aXMgb25seSBhIGxpY2Vu
c2UgYW5kIGNvcHlyaWdodCBpbnZvbHZlZC4gSGVyZSB0aGlzIHdvdWxkIG1lYW46DQo+DQo+PiAr
Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEdQTC0yLjANCj4+ICsvLyBDb3B5cmlnaHQgKGMp
IDIwMDQtMjAxMSBGcmVlc2NhbGUgU2VtaWNvbmR1Y3RvciwgSW5jLiBBbGwgUmlnaHRzDQo+UmVz
ZXJ2ZWQuDQo+DQo+V2hhdCdzIHlvdSB0YWtlIHNpbmNlIHlvdSB3cm90ZSB0aGUgZG9jIGZvciB0
aGlzPyBBbmQgaXMgdGhlcmUgc3RpbGwNCj5zb21lIHVwZGF0ZXMgbmVlZGVkIGZvciB0aGlzIHNp
bmNlIHlvdXIgbGFzdCBwYXRjaCBzZXQ/DQo+DQpXaGlsZSBsb29raW5nIGNsb3NlciBpbnRvIGRp
ZmZlcmVudCBmaWxlcyBJIHRoaW5rIGl0IHdvdWxkIGJlY29tZSBtdWx0aWxpbmUgYWdhaW46DQor
Ly8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEdQTC0yLjANCisvKg0KKyAqIFJlYWwgVGltZSBD
bG9jayAoUlRDKSBEcml2ZXIgZm9yIGkuTVg1Mw0KKyAqIENvcHlyaWdodCAoYykgMjAwNC0yMDEx
IEZyZWVzY2FsZSBTZW1pY29uZHVjdG9yLCBJbmMuDQorICogQ29weXJpZ2h0IChjKSAyMDE3IEJl
Y2tob2ZmIEF1dG9tYXRpb24gR21iSCAmIENvLiBLRw0KKyAqLw0KDQo+DQo+UGF0cmljazoNCj5T
aWRlIG5vdGUgYSB0cmFpbGluZyAgIkFsbCBSaWdodHMgUmVzZXJ2ZWQuIiBpbiBhIGNvcHlyaWdo
dCBzdGF0ZW1lbnQNCj5pcyBuZXZlciBuZWVkZWQsIGV2ZW4gdGhvdWdoIGN1c3RvbWFyaWx5IGNh
cmdvIGN1bHRlZCBieSBldmVyeW9uZSwNCj5pbmNsdWRpbmcgbWUuDQo+U3RhcnRlZCBpbiAxOTEw
LCBpdCBiZWNvbWUgZnVsbHkgb2Jzb2xldGUgaW4gMjAwMCB0aGFua3MgdG8gTmljYXJhZ3VhDQo+
WzFdIHNpZ25pbmcgdGhlIEJlcm5lIGNvbnZlbnRpb24uDQo+DQo+WzFdIGh0dHBzOi8vZW4ud2lr
aXBlZGlhLm9yZy93aWtpL0FsbF9yaWdodHNfcmVzZXJ2ZWQNCkludGVyZXNzdGluZy4gSSBqdXN0
IGtlcHQgaXQgYmVjYXVzZSBpdCB3YXMgaW4gdGhlIG9yaWdpbmFsIGZpbGUgZnJvbSBmcmVlc2Nh
bGUuDQpCdXQgd2l0aCB0aGlzIGJhY2tncm91bmQsIEkgdGhpbmsgaXQncyBmaW5lIHRvIGRyb3Ag
aXQsIG5vdy4NCg0KVGhhbmtzLA0KUGF0cmljaw0KQmVja2hvZmYgQXV0b21hdGlvbiBHbWJIICYg
Q28uIEtHIHwgTWFuYWdpbmcgRGlyZWN0b3I6IERpcGwuIFBoeXMuIEhhbnMgQmVja2hvZmYNClJl
Z2lzdGVyZWQgb2ZmaWNlOiBWZXJsLCBHZXJtYW55IHwgUmVnaXN0ZXIgY291cnQ6IEd1ZXRlcnNs
b2ggSFJBIDcwNzUNCg0KDQo=

^ permalink raw reply	[flat|nested] 43+ messages in thread

* RE: [PATCH] rtc: add mxc driver for i.MX53
@ 2017-11-30 14:24           ` Patrick Brünn
  0 siblings, 0 replies; 43+ messages in thread
From: Patrick Brünn @ 2017-11-30 14:24 UTC (permalink / raw)
  To: Philippe Ombredanne, Thomas Gleixner
  Cc: Greg Kroah-Hartman, linux-kernel-dev, Alessandro Zummo,
	Alexandre Belloni, Rob Herring, Mark Rutland,
	open list:REAL TIME CLOCK (RTC) SUBSYSTEM,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	open list, Fabio Estevam, Juergen Borleis, Noel Vellemans,
	Shawn Guo, Sascha Hauer, Russell King, ARM/FREESCALE

>From: Philippe Ombredanne [mailto:pombredanne@nexb.com]
>Sent: Donnerstag, 30. November 2017 15:00
>On Thu, Nov 30, 2017 at 2:36 PM, Patrick Brünn <P.Bruenn@beckhoff.com>
>wrote:
>
>Thomas:
>I tend to prefer as Linus pointed the // style throughout when there
>is only a license and copyright involved. Here this would mean:
>
>> +// SPDX-License-Identifier: GPL-2.0
>> +// Copyright (c) 2004-2011 Freescale Semiconductor, Inc. All Rights
>Reserved.
>
>What's you take since you wrote the doc for this? And is there still
>some updates needed for this since your last patch set?
>
While looking closer into different files I think it would become multiline again:
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Real Time Clock (RTC) Driver for i.MX53
+ * Copyright (c) 2004-2011 Freescale Semiconductor, Inc.
+ * Copyright (c) 2017 Beckhoff Automation GmbH & Co. KG
+ */

>
>Patrick:
>Side note a trailing  "All Rights Reserved." in a copyright statement
>is never needed, even though customarily cargo culted by everyone,
>including me.
>Started in 1910, it become fully obsolete in 2000 thanks to Nicaragua
>[1] signing the Berne convention.
>
>[1] https://en.wikipedia.org/wiki/All_rights_reserved
Interessting. I just kept it because it was in the original file from freescale.
But with this background, I think it's fine to drop it, now.

Thanks,
Patrick
Beckhoff Automation GmbH & Co. KG | Managing Director: Dipl. Phys. Hans Beckhoff
Registered office: Verl, Germany | Register court: Guetersloh HRA 7075



^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH] rtc: add mxc driver for i.MX53
@ 2017-11-30 14:24           ` Patrick Brünn
  0 siblings, 0 replies; 43+ messages in thread
From: Patrick Brünn @ 2017-11-30 14:24 UTC (permalink / raw)
  To: linux-arm-kernel

>From: Philippe Ombredanne [mailto:pombredanne at nexb.com]
>Sent: Donnerstag, 30. November 2017 15:00
>On Thu, Nov 30, 2017 at 2:36 PM, Patrick Br?nn <P.Bruenn@beckhoff.com>
>wrote:
>
>Thomas:
>I tend to prefer as Linus pointed the // style throughout when there
>is only a license and copyright involved. Here this would mean:
>
>> +// SPDX-License-Identifier: GPL-2.0
>> +// Copyright (c) 2004-2011 Freescale Semiconductor, Inc. All Rights
>Reserved.
>
>What's you take since you wrote the doc for this? And is there still
>some updates needed for this since your last patch set?
>
While looking closer into different files I think it would become multiline again:
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Real Time Clock (RTC) Driver for i.MX53
+ * Copyright (c) 2004-2011 Freescale Semiconductor, Inc.
+ * Copyright (c) 2017 Beckhoff Automation GmbH & Co. KG
+ */

>
>Patrick:
>Side note a trailing  "All Rights Reserved." in a copyright statement
>is never needed, even though customarily cargo culted by everyone,
>including me.
>Started in 1910, it become fully obsolete in 2000 thanks to Nicaragua
>[1] signing the Berne convention.
>
>[1] https://en.wikipedia.org/wiki/All_rights_reserved
Interessting. I just kept it because it was in the original file from freescale.
But with this background, I think it's fine to drop it, now.

Thanks,
Patrick
Beckhoff Automation GmbH & Co. KG | Managing Director: Dipl. Phys. Hans Beckhoff
Registered office: Verl, Germany | Register court: Guetersloh HRA 7075

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] rtc: add mxc driver for i.MX53
  2017-11-30 13:36       ` Patrick Brünn
  (?)
  (?)
@ 2017-11-30 14:27         ` Russell King - ARM Linux
  -1 siblings, 0 replies; 43+ messages in thread
From: Russell King - ARM Linux @ 2017-11-30 14:27 UTC (permalink / raw)
  To: Patrick Brünn
  Cc: Philippe Ombredanne, Greg Kroah-Hartman, linux-kernel-dev,
	Alessandro Zummo, Alexandre Belloni, Rob Herring, Mark Rutland,
	open list:REAL TIME CLOCK (RTC) SUBSYSTEM,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	open list, Fabio Estevam, Juergen Borleis, Noel Vellemans,
	Shawn Guo, Sascha Hauer,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE

On Thu, Nov 30, 2017 at 01:36:22PM +0000, Patrick Brünn wrote:
> >From: Philippe Ombredanne [mailto:pombredanne@nexb.com]
> >Sent: Donnerstag, 30. November 2017 09:18
> >>
> >>> +/*
> >>> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
> >Reserved.
> >>> + */
> >>> +
> >>> +/*
> >>> + * The code contained herein is licensed under the GNU General Public
> >>> + * License. You may obtain a copy of the GNU General Public License
> >>> + * Version 2 or later at the following locations:
> >>> + *
> >>> + * http://www.opensource.org/licenses/gpl-license.html
> >>> + * http://www.gnu.org/copyleft/gpl.html
> >>> + */
> >
> >Exactly!
> >And while you are it , you could replace the boilerplate license text
> >with the SPDX id.
> >--
> 
> How would a perfect header look like?
> Looking at :
> git show b24413180f5600bcb3bb70fbed5cf186b60864bd -- drivers/
> and:
> git grep SPDX -- Documentation/
> 
> it could be:
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
> + */
> or:
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
> + */
> 
> Personally I would prefer:
> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
> + *
> + * SPDX-License-Identifier: GPL-2.0
> + */
> 
> So, is there any guideline?

There's been lots of discussion about this, but Linus T has set the
requirements.

>From Thomas' patches adding documentation for this:

+1. Placement:
+
+   The SPDX license identifier in kernel files shall be added at the first
+   possible line in a file which can contain a comment.  For the majority
+   or files this is the first line, except for scripts which require the
+   '#!PATH_TO_INTERPRETER' in the first line.  For those scripts the SPDX
+   identifier goes into the second line.
+
+|
+
+2. Style:
+
+   The SPDX license identifier is added in form of a comment.  The comment
+   style depends on the file type:
+
+   ::
+
+      C source:   // SPDX-License-Identifier: <SPDX License Expression>
+      C header:   /* SPDX-License-Identifier: <SPDX License Expression> */
+      ASM:        /* SPDX-License-Identifier: <SPDX License Expression> */
+      scripts:    # SPDX-License-Identifier: <SPDX License Expression>
+      .rst:      .. SPDX-License-Identifier: <SPDX License Expression>
+
+   If a specific tool cannot handle the standard comment style, then the
+   appropriate comment mechanism which the tool accepts shall be used. This
+   is the reason for having the "/\* \*/" style comment in C header
+   files. There was build breakage observed with generated .lds files where
+   'ld' failed to parse the C++ comment. This has been fixed by now, but
+   there are still older assembler tools which cannot handle C++ style
+   comments.

There is additional information in Thomas' patch about the SPDX
identifiers, how to deal with multi-licensed files, etc.  It's
well worth reading before throwing a SPDX tag on a file to make
sure you get the correct tag(s) and expressions.

It's a fixed format.  Tabs and additional spaces that are not in
the format are bad news.

The idea here is (as detailed by Linus) to be able to grep for
the SPDX identifiers using standard Unix tools, sort then and
then eliminate duplicates.  If someone decides to use a tab
after the SPDX-Identifier: rather than a space, then it messes
up "uniq"'s ability to get rid of the duplicates.

As I say, the documentation is there to help people get this right,
so it's well worth reading.  I don't think it's in mainline yet.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] rtc: add mxc driver for i.MX53
@ 2017-11-30 14:27         ` Russell King - ARM Linux
  0 siblings, 0 replies; 43+ messages in thread
From: Russell King - ARM Linux @ 2017-11-30 14:27 UTC (permalink / raw)
  To: Patrick Brünn
  Cc: Philippe Ombredanne, Greg Kroah-Hartman, linux-kernel-dev,
	Alessandro Zummo, Alexandre Belloni, Rob Herring, Mark Rutland,
	open list:REAL TIME CLOCK (RTC) SUBSYSTEM,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	open list, Fabio Estevam, Juergen Borleis, Noel Vellemans,
	Shawn Guo, Sascha Hauer,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE

On Thu, Nov 30, 2017 at 01:36:22PM +0000, Patrick Brünn wrote:
> >From: Philippe Ombredanne [mailto:pombredanne@nexb.com]
> >Sent: Donnerstag, 30. November 2017 09:18
> >>
> >>> +/*
> >>> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
> >Reserved.
> >>> + */
> >>> +
> >>> +/*
> >>> + * The code contained herein is licensed under the GNU General Public
> >>> + * License. You may obtain a copy of the GNU General Public License
> >>> + * Version 2 or later at the following locations:
> >>> + *
> >>> + * http://www.opensource.org/licenses/gpl-license.html
> >>> + * http://www.gnu.org/copyleft/gpl.html
> >>> + */
> >
> >Exactly!
> >And while you are it , you could replace the boilerplate license text
> >with the SPDX id.
> >--
> 
> How would a perfect header look like?
> Looking at :
> git show b24413180f5600bcb3bb70fbed5cf186b60864bd -- drivers/
> and:
> git grep SPDX -- Documentation/
> 
> it could be:
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
> + */
> or:
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
> + */
> 
> Personally I would prefer:
> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
> + *
> + * SPDX-License-Identifier: GPL-2.0
> + */
> 
> So, is there any guideline?

There's been lots of discussion about this, but Linus T has set the
requirements.

>From Thomas' patches adding documentation for this:

+1. Placement:
+
+   The SPDX license identifier in kernel files shall be added at the first
+   possible line in a file which can contain a comment.  For the majority
+   or files this is the first line, except for scripts which require the
+   '#!PATH_TO_INTERPRETER' in the first line.  For those scripts the SPDX
+   identifier goes into the second line.
+
+|
+
+2. Style:
+
+   The SPDX license identifier is added in form of a comment.  The comment
+   style depends on the file type:
+
+   ::
+
+      C source:   // SPDX-License-Identifier: <SPDX License Expression>
+      C header:   /* SPDX-License-Identifier: <SPDX License Expression> */
+      ASM:        /* SPDX-License-Identifier: <SPDX License Expression> */
+      scripts:    # SPDX-License-Identifier: <SPDX License Expression>
+      .rst:      .. SPDX-License-Identifier: <SPDX License Expression>
+
+   If a specific tool cannot handle the standard comment style, then the
+   appropriate comment mechanism which the tool accepts shall be used. This
+   is the reason for having the "/\* \*/" style comment in C header
+   files. There was build breakage observed with generated .lds files where
+   'ld' failed to parse the C++ comment. This has been fixed by now, but
+   there are still older assembler tools which cannot handle C++ style
+   comments.

There is additional information in Thomas' patch about the SPDX
identifiers, how to deal with multi-licensed files, etc.  It's
well worth reading before throwing a SPDX tag on a file to make
sure you get the correct tag(s) and expressions.

It's a fixed format.  Tabs and additional spaces that are not in
the format are bad news.

The idea here is (as detailed by Linus) to be able to grep for
the SPDX identifiers using standard Unix tools, sort then and
then eliminate duplicates.  If someone decides to use a tab
after the SPDX-Identifier: rather than a space, then it messes
up "uniq"'s ability to get rid of the duplicates.

As I say, the documentation is there to help people get this right,
so it's well worth reading.  I don't think it's in mainline yet.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH] rtc: add mxc driver for i.MX53
@ 2017-11-30 14:27         ` Russell King - ARM Linux
  0 siblings, 0 replies; 43+ messages in thread
From: Russell King - ARM Linux @ 2017-11-30 14:27 UTC (permalink / raw)
  To: Patrick Brünn
  Cc: Philippe Ombredanne, Greg Kroah-Hartman, linux-kernel-dev,
	Alessandro Zummo, Alexandre Belloni, Rob Herring, Mark Rutland,
	open list:REAL TIME CLOCK (RTC) SUBSYSTEM,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	open list, Fabio Estevam, Juergen Borleis, Noel Vellemans,
	Shawn Guo, Sascha Hauer, ARM/FREESCALE

On Thu, Nov 30, 2017 at 01:36:22PM +0000, Patrick Brünn wrote:
> >From: Philippe Ombredanne [mailto:pombredanne@nexb.com]
> >Sent: Donnerstag, 30. November 2017 09:18
> >>
> >>> +/*
> >>> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
> >Reserved.
> >>> + */
> >>> +
> >>> +/*
> >>> + * The code contained herein is licensed under the GNU General Public
> >>> + * License. You may obtain a copy of the GNU General Public License
> >>> + * Version 2 or later at the following locations:
> >>> + *
> >>> + * http://www.opensource.org/licenses/gpl-license.html
> >>> + * http://www.gnu.org/copyleft/gpl.html
> >>> + */
> >
> >Exactly!
> >And while you are it , you could replace the boilerplate license text
> >with the SPDX id.
> >--
> 
> How would a perfect header look like?
> Looking at :
> git show b24413180f5600bcb3bb70fbed5cf186b60864bd -- drivers/
> and:
> git grep SPDX -- Documentation/
> 
> it could be:
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
> + */
> or:
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
> + */
> 
> Personally I would prefer:
> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
> + *
> + * SPDX-License-Identifier: GPL-2.0
> + */
> 
> So, is there any guideline?

There's been lots of discussion about this, but Linus T has set the
requirements.

>From Thomas' patches adding documentation for this:

+1. Placement:
+
+   The SPDX license identifier in kernel files shall be added at the first
+   possible line in a file which can contain a comment.  For the majority
+   or files this is the first line, except for scripts which require the
+   '#!PATH_TO_INTERPRETER' in the first line.  For those scripts the SPDX
+   identifier goes into the second line.
+
+|
+
+2. Style:
+
+   The SPDX license identifier is added in form of a comment.  The comment
+   style depends on the file type:
+
+   ::
+
+      C source:   // SPDX-License-Identifier: <SPDX License Expression>
+      C header:   /* SPDX-License-Identifier: <SPDX License Expression> */
+      ASM:        /* SPDX-License-Identifier: <SPDX License Expression> */
+      scripts:    # SPDX-License-Identifier: <SPDX License Expression>
+      .rst:      .. SPDX-License-Identifier: <SPDX License Expression>
+
+   If a specific tool cannot handle the standard comment style, then the
+   appropriate comment mechanism which the tool accepts shall be used. This
+   is the reason for having the "/\* \*/" style comment in C header
+   files. There was build breakage observed with generated .lds files where
+   'ld' failed to parse the C++ comment. This has been fixed by now, but
+   there are still older assembler tools which cannot handle C++ style
+   comments.

There is additional information in Thomas' patch about the SPDX
identifiers, how to deal with multi-licensed files, etc.  It's
well worth reading before throwing a SPDX tag on a file to make
sure you get the correct tag(s) and expressions.

It's a fixed format.  Tabs and additional spaces that are not in
the format are bad news.

The idea here is (as detailed by Linus) to be able to grep for
the SPDX identifiers using standard Unix tools, sort then and
then eliminate duplicates.  If someone decides to use a tab
after the SPDX-Identifier: rather than a space, then it messes
up "uniq"'s ability to get rid of the duplicates.

As I say, the documentation is there to help people get this right,
so it's well worth reading.  I don't think it's in mainline yet.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH] rtc: add mxc driver for i.MX53
@ 2017-11-30 14:27         ` Russell King - ARM Linux
  0 siblings, 0 replies; 43+ messages in thread
From: Russell King - ARM Linux @ 2017-11-30 14:27 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Nov 30, 2017 at 01:36:22PM +0000, Patrick Br?nn wrote:
> >From: Philippe Ombredanne [mailto:pombredanne at nexb.com]
> >Sent: Donnerstag, 30. November 2017 09:18
> >>
> >>> +/*
> >>> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
> >Reserved.
> >>> + */
> >>> +
> >>> +/*
> >>> + * The code contained herein is licensed under the GNU General Public
> >>> + * License. You may obtain a copy of the GNU General Public License
> >>> + * Version 2 or later at the following locations:
> >>> + *
> >>> + * http://www.opensource.org/licenses/gpl-license.html
> >>> + * http://www.gnu.org/copyleft/gpl.html
> >>> + */
> >
> >Exactly!
> >And while you are it , you could replace the boilerplate license text
> >with the SPDX id.
> >--
> 
> How would a perfect header look like?
> Looking at :
> git show b24413180f5600bcb3bb70fbed5cf186b60864bd -- drivers/
> and:
> git grep SPDX -- Documentation/
> 
> it could be:
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
> + */
> or:
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
> + */
> 
> Personally I would prefer:
> +/*
> + * Copyright (C) 2004-2011 Freescale Semiconductor, Inc. All Rights
> + *
> + * SPDX-License-Identifier: GPL-2.0
> + */
> 
> So, is there any guideline?

There's been lots of discussion about this, but Linus T has set the
requirements.

>From Thomas' patches adding documentation for this:

+1. Placement:
+
+   The SPDX license identifier in kernel files shall be added at the first
+   possible line in a file which can contain a comment.  For the majority
+   or files this is the first line, except for scripts which require the
+   '#!PATH_TO_INTERPRETER' in the first line.  For those scripts the SPDX
+   identifier goes into the second line.
+
+|
+
+2. Style:
+
+   The SPDX license identifier is added in form of a comment.  The comment
+   style depends on the file type:
+
+   ::
+
+      C source:   // SPDX-License-Identifier: <SPDX License Expression>
+      C header:   /* SPDX-License-Identifier: <SPDX License Expression> */
+      ASM:        /* SPDX-License-Identifier: <SPDX License Expression> */
+      scripts:    # SPDX-License-Identifier: <SPDX License Expression>
+      .rst:      .. SPDX-License-Identifier: <SPDX License Expression>
+
+   If a specific tool cannot handle the standard comment style, then the
+   appropriate comment mechanism which the tool accepts shall be used. This
+   is the reason for having the "/\* \*/" style comment in C header
+   files. There was build breakage observed with generated .lds files where
+   'ld' failed to parse the C++ comment. This has been fixed by now, but
+   there are still older assembler tools which cannot handle C++ style
+   comments.

There is additional information in Thomas' patch about the SPDX
identifiers, how to deal with multi-licensed files, etc.  It's
well worth reading before throwing a SPDX tag on a file to make
sure you get the correct tag(s) and expressions.

It's a fixed format.  Tabs and additional spaces that are not in
the format are bad news.

The idea here is (as detailed by Linus) to be able to grep for
the SPDX identifiers using standard Unix tools, sort then and
then eliminate duplicates.  If someone decides to use a tab
after the SPDX-Identifier: rather than a space, then it messes
up "uniq"'s ability to get rid of the duplicates.

As I say, the documentation is there to help people get this right,
so it's well worth reading.  I don't think it's in mainline yet.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 8.8Mbps down 630kbps up
According to speedtest.net: 8.21Mbps down 510kbps up

^ permalink raw reply	[flat|nested] 43+ messages in thread

end of thread, other threads:[~2017-11-30 14:28 UTC | newest]

Thread overview: 43+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-11-28  7:39 [PATCH] rtc: add mxc driver for i.MX53 linux-kernel-dev
2017-11-28  7:39 ` linux-kernel-dev at beckhoff.com
2017-11-28  7:39 ` linux-kernel-dev
2017-11-28  7:39 ` linux-kernel-dev
2017-11-29 22:11 ` Alexandre Belloni
2017-11-29 22:11   ` Alexandre Belloni
2017-11-29 22:11   ` Alexandre Belloni
2017-11-29 22:11   ` Alexandre Belloni
2017-11-30  8:18   ` Philippe Ombredanne
2017-11-30  8:18     ` Philippe Ombredanne
2017-11-30  8:18     ` Philippe Ombredanne
2017-11-30 13:36     ` Patrick Brünn
2017-11-30 13:36       ` Patrick Brünn
2017-11-30 13:36       ` Patrick Brünn
2017-11-30 13:36       ` Patrick Brünn
2017-11-30 13:42       ` Alexandre Belloni
2017-11-30 13:42         ` Alexandre Belloni
2017-11-30 13:42         ` Alexandre Belloni
2017-11-30 13:42         ` Alexandre Belloni
2017-11-30 14:00       ` Philippe Ombredanne
2017-11-30 14:00         ` Philippe Ombredanne
2017-11-30 14:00         ` Philippe Ombredanne
2017-11-30 14:00         ` Philippe Ombredanne
2017-11-30 14:24         ` Patrick Brünn
2017-11-30 14:24           ` Patrick Brünn
2017-11-30 14:24           ` Patrick Brünn
2017-11-30 14:24           ` Patrick Brünn
2017-11-30 14:27       ` Russell King - ARM Linux
2017-11-30 14:27         ` Russell King - ARM Linux
2017-11-30 14:27         ` Russell King - ARM Linux
2017-11-30 14:27         ` Russell King - ARM Linux
2017-11-30  9:50 ` Sascha Hauer
2017-11-30  9:50   ` Sascha Hauer
2017-11-30  9:50   ` Sascha Hauer
2017-11-30  9:50   ` Sascha Hauer
2017-11-30 10:53   ` Lothar Waßmann
2017-11-30 10:53     ` Lothar Waßmann
2017-11-30 10:53     ` Lothar Waßmann
2017-11-30 10:53     ` Lothar Waßmann
2017-11-30 11:21 ` Lothar Waßmann
2017-11-30 11:21   ` Lothar Waßmann
2017-11-30 11:21   ` Lothar Waßmann
2017-11-30 11:21   ` Lothar Waßmann

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.