All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jingbao Qiu <qiujingbao.dlmu@gmail.com>
To: a.zummo@towertech.it, alexandre.belloni@bootlin.com,
	krzysztof.kozlowski+dt@linaro.org, chao.wei@sophgo.com,
	unicorn_wang@outlook.com, conor+dt@kernel.org,
	robh+dt@kernel.org, conor@kernel.org, paul.walmsley@sifive.com,
	palmer@dabbelt.com, aou@eecs.berkeley.edu
Cc: linux-rtc@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org,
	Jingbao Qiu <qiujingbao.dlmu@gmail.com>
Subject: [PATCH 2/3] rtc: add rtc controller support for Sophgo CV1800B SoC
Date: Tue, 21 Nov 2023 17:46:41 +0800	[thread overview]
Message-ID: <20231121094642.2973795-3-qiujingbao.dlmu@gmail.com> (raw)
In-Reply-To: <20231121094642.2973795-1-qiujingbao.dlmu@gmail.com>

Implement the RTC driver for CV1800B, which able to provide time and
alarm functionality.

Signed-off-by: Jingbao Qiu <qiujingbao.dlmu@gmail.com>
---
 drivers/rtc/Kconfig       |  10 ++
 drivers/rtc/Makefile      |   1 +
 drivers/rtc/rtc-cv1800b.c | 293 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 304 insertions(+)
 create mode 100644 drivers/rtc/rtc-cv1800b.c

diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 3814e0845e77..2089cceea38c 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -1103,6 +1103,16 @@ config RTC_DRV_DS2404
 	  This driver can also be built as a module. If so, the module
 	  will be called rtc-ds2404.
 
+config RTC_DRV_CV1800B
+	tristate "Sophgo CV1800B RTC"
+	depends on ARCH_SOPHGO || COMPILE_TEST
+	help
+	  If you say yes here you will get support for the
+	  RTC of the Sophgo CV1800B SOC.
+
+	  This depend on ARCH_SOPHGO and COMPILE_TEST. Please
+	  first config that.
+
 config RTC_DRV_DA9052
 	tristate "Dialog DA9052/DA9053 RTC"
 	depends on PMIC_DA9052
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 7b03c3abfd78..3717d7ec8a4e 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_RTC_DRV_CADENCE)	+= rtc-cadence.o
 obj-$(CONFIG_RTC_DRV_CMOS)	+= rtc-cmos.o
 obj-$(CONFIG_RTC_DRV_CPCAP)	+= rtc-cpcap.o
 obj-$(CONFIG_RTC_DRV_CROS_EC)	+= rtc-cros-ec.o
+obj-$(CONFIG_RTC_DRV_CV1800B)	+= rtc-cv1800b.o
 obj-$(CONFIG_RTC_DRV_DA9052)	+= rtc-da9052.o
 obj-$(CONFIG_RTC_DRV_DA9055)	+= rtc-da9055.o
 obj-$(CONFIG_RTC_DRV_DA9063)	+= rtc-da9063.o
diff --git a/drivers/rtc/rtc-cv1800b.c b/drivers/rtc/rtc-cv1800b.c
new file mode 100644
index 000000000000..d56132de30bb
--- /dev/null
+++ b/drivers/rtc/rtc-cv1800b.c
@@ -0,0 +1,293 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * rtc-cv1800b.c: RTC driver for Sophgo CV1800B RTC
+ *
+ * Author: Jingbao Qiu <qiujingbao.dlmu@gmail.com>
+ */
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+
+#define RTC_ANA_CALIB                 0x000
+#define RTC_SEC_PULSE_GEN             0x004
+#define RTC_ALARM_TIME                0x008
+#define RTC_ALARM_ENABLE              0x00c
+#define RTC_SET_SEC_CNTR_VALUE        0x010
+#define RTC_SET_SEC_CNTR_TRIG         0x014
+#define RTC_SEC_CNTR_VALUE            0x018
+#define RTC_INFO0                     0x01c
+#define RTC_INFO1                     0x020
+#define RTC_INFO2                     0x024
+#define RTC_INFO3                     0x028
+#define RTC_NOPOR_INFO0               0x02c
+#define RTC_NOPOR_INFO1               0x030
+#define RTC_NOPOR_INFO2               0x034
+#define RTC_NOPOR_INFO3               0x038
+#define RTC_DB_PWR_VBAT_DET           0x040
+#define RTC_DB_BUTTON1                0x048
+#define RTC_DB_PWR_ON                 0x04c
+#define RTC_7SEC_RESET                0x050
+#define RTC_THM_SHDN_AUTO_REBOOT      0x064
+#define RTC_POR_DB_MAGIC_KEY          0x068
+#define RTC_DB_SEL_PWR                0x06c
+#define RTC_UP_SEQ0                   0x070
+#define RTC_UP_SEQ1                   0x074
+#define RTC_UP_SEQ2                   0x078
+#define RTC_UP_SEQ3                   0x07c
+#define RTC_UP_IF_EN                  0x080
+#define RTC_UP_RSTN                   0x084
+#define RTC_UP_MAX                    0x088
+#define RTC_DN_SEQ0                   0x090
+#define RTC_DN_SEQ1                   0x094
+#define RTC_DN_SEQ2                   0x098
+#define RTC_DN_SEQ3                   0x09c
+#define RTC_DN_IF_EN                  0x0a0
+#define RTC_DN_RSTN                   0x0a4
+#define RTC_DN_MAX                    0x0a8
+#define RTC_PWR_CYC_MAX               0x0b0
+#define RTC_WARM_RST_MAX              0x0b4
+#define RTC_EN_7SEC_RST               0x0b8
+#define RTC_EN_PWR_WAKEUP             0x0bc
+#define RTC_EN_SHDN_REQ               0x0c0
+#define RTC_EN_THM_SHDN               0x0c4
+#define RTC_EN_PWR_CYC_REQ            0x0c8
+#define RTC_EN_WARM_RST_REQ           0x0cc
+#define RTC_EN_PWR_VBAT_DET           0x0d0
+#define FSM_STATE                     0x0d4
+#define RTC_EN_WDG_RST_REQ            0x0e0
+#define RTC_EN_SUSPEND_REQ            0x0e4
+#define RTC_DB_REQ_WDG_RST            0x0e8
+#define RTC_DB_REQ_SUSPEND            0x0ec
+#define RTC_PG_REG                    0x0f0
+#define RTC_ST_ON_REASON              0x0f8
+#define RTC_ST_OFF_REASON             0x0fc
+#define RTC_EN_WAKEUP_REQ             0x120
+#define RTC_PWR_WAKEUP_POLARITY       0x128
+#define RTC_DB_SEL_REQ                0x130
+#define RTC_PWR_DET_SEL               0x140
+
+#define REG_DISABLE_FUN               0x00UL
+#define REG_ENABLE_FUN                BIT(0)
+#define ACTIVATE_RTC_POR_DB_MAGIC_KEY 0x5af0
+#define INIT_LOAD_TIME                0xff
+
+struct cv1800b_rtc_priv {
+	struct rtc_device *rtc_dev;
+	void __iomem *core_map;
+	struct clk *clk;
+	int irq;
+};
+
+static int cv1800b_rtc_alarm_irq_enable(struct device *dev,
+					unsigned int enabled)
+{
+	struct cv1800b_rtc_priv *data = dev_get_drvdata(dev);
+
+	if (enabled)
+		writel_relaxed(REG_ENABLE_FUN, data->core_map + RTC_ALARM_ENABLE);
+	else
+		writel_relaxed(REG_DISABLE_FUN,
+			       data->core_map + RTC_ALARM_ENABLE);
+
+	return 0;
+}
+
+static int cv1800b_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct cv1800b_rtc_priv *data = dev_get_drvdata(dev);
+	unsigned long time = rtc_tm_to_time64(&alrm->time);
+
+	writel_relaxed(time, data->core_map + RTC_ALARM_TIME);
+
+	cv1800b_rtc_alarm_irq_enable(dev, 1);
+
+	return 0;
+}
+
+static int cv1800b_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	u32 alrm_time, now_time;
+	struct cv1800b_rtc_priv *data = dev_get_drvdata(dev);
+
+	alrm_time = readl(data->core_map + RTC_ALARM_TIME);
+	now_time = readl(data->core_map + RTC_SEC_CNTR_VALUE);
+	rtc_time64_to_tm(alrm_time, &alrm->time);
+	alrm->pending = now_time > alrm_time ? 1 : 0;
+	alrm->enabled = readl(data->core_map + RTC_ALARM_ENABLE);
+
+	return 0;
+}
+
+static int cv1800b_rtc_softinit(struct cv1800b_rtc_priv *dev)
+{
+	u32 timeout = 20;
+
+	writel(ACTIVATE_RTC_POR_DB_MAGIC_KEY,
+	       dev->core_map + RTC_POR_DB_MAGIC_KEY);
+	writel(INIT_LOAD_TIME, dev->core_map + RTC_SET_SEC_CNTR_VALUE);
+	writel(REG_DISABLE_FUN, dev->core_map + RTC_SET_SEC_CNTR_TRIG);
+
+	while (readl(dev->core_map + RTC_SEC_CNTR_VALUE) == INIT_LOAD_TIME
+	       && timeout--)
+		udelay(5);
+
+	if (!timeout)
+		return -1;
+	return 0;
+}
+
+static int cv1800b_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	struct cv1800b_rtc_priv *data = dev_get_drvdata(dev);
+	u32 time = 0;
+
+	if (!data)
+		return -1;
+
+	time = readl_relaxed(data->core_map + RTC_SEC_CNTR_VALUE);
+	rtc_time64_to_tm(time, tm);
+
+	return 0;
+}
+
+static int cv1800b_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	unsigned long time = rtc_tm_to_time64(tm);
+	struct cv1800b_rtc_priv *data = dev_get_drvdata(dev);
+
+	if (!data)
+		return -1;
+
+	writel(time, data->core_map + RTC_SET_SEC_CNTR_VALUE);
+	writel(REG_ENABLE_FUN, data->core_map + RTC_SET_SEC_CNTR_TRIG);
+
+	return 0;
+}
+
+static irqreturn_t cv1800b_rtc_irq_handler(int irq, void *dev_id)
+{
+	struct device *dev = dev_id;
+	struct cv1800b_rtc_priv *data = dev_get_drvdata(dev);
+
+	if (!data)
+		return -1;
+	writel(REG_DISABLE_FUN, data->core_map + RTC_ALARM_ENABLE);
+
+	return IRQ_HANDLED;
+}
+
+static const struct rtc_class_ops cv800b_rtc_ops = {
+	.read_time = cv1800b_rtc_read_time,
+	.set_time = cv1800b_rtc_set_time,
+	.read_alarm = cv1800b_rtc_read_alarm,
+	.set_alarm = cv1800b_rtc_set_alarm,
+	.alarm_irq_enable = cv1800b_rtc_alarm_irq_enable,
+};
+
+static int cv1800b_rtc_probe(struct platform_device *pdev)
+{
+	struct cv1800b_rtc_priv *rtc;
+	struct resource *res;
+	int ret;
+
+	rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
+	if (!rtc)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		ret = -ENODEV;
+		goto err;
+	}
+
+	rtc->core_map = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(rtc->core_map)) {
+		ret = PTR_ERR(rtc->core_map);
+		goto err;
+	}
+
+	rtc->irq = platform_get_irq(pdev, 0);
+	platform_set_drvdata(pdev, rtc);
+	if (rtc->irq < 0) {
+		ret = -EINVAL;
+		goto err;
+	}
+
+	ret =
+	    devm_request_irq(&pdev->dev, rtc->irq, cv1800b_rtc_irq_handler,
+			     IRQF_SHARED, "rtc alarm", &pdev->dev);
+	if (ret)
+		goto err;
+
+	rtc->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(rtc->clk)) {
+		dev_err(&pdev->dev, "no clock");
+		ret = PTR_ERR(rtc->clk);
+		goto err;
+	}
+	ret = clk_prepare_enable(rtc->clk);
+	if (ret)
+		goto err;
+	ret = cv1800b_rtc_softinit(rtc);
+	if (ret)
+		goto err;
+	cv1800b_rtc_alarm_irq_enable(&pdev->dev, 1);
+	rtc->rtc_dev = devm_rtc_allocate_device(&pdev->dev);
+	if (IS_ERR(rtc->rtc_dev)) {
+		ret = PTR_ERR(rtc->rtc_dev);
+		goto err;
+	}
+	rtc->rtc_dev->range_max = U32_MAX;
+	rtc->rtc_dev->ops = &cv800b_rtc_ops;
+
+	return rtc_register_device(rtc->rtc_dev);
+err:
+	return dev_err_probe(&pdev->dev, ret, "Failed to init cv1800b rtc\n");
+}
+
+static int __maybe_unused cv1800b_rtc_suspend_noirq(struct device *dev)
+{
+	struct cv1800b_rtc_priv *data = dev_get_drvdata(dev);
+
+	clk_disable_unprepare(data->clk);
+
+	return 0;
+}
+
+static int __maybe_unused cv1800b_rtc_resume_noirq(struct device *dev)
+{
+	struct cv1800b_rtc_priv *data = dev_get_drvdata(dev);
+
+	clk_prepare_enable(data->clk);
+
+	return 0;
+}
+
+static const struct dev_pm_ops cv1800b_rtc_pm_ops = {
+	SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(cv1800b_rtc_suspend_noirq,
+				      cv1800b_rtc_resume_noirq)
+};
+
+static const struct of_device_id cv1800b_dt_ids[] = {
+	{ .compatible = "sophgo,cv800b-rtc" },
+	{ /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, cv1800b_dt_ids);
+
+static struct platform_driver cv1800b_rtc_driver = {
+	.driver = {
+		   .name = "sophgo-cv800b-rtc",
+		   .pm = &cv1800b_rtc_pm_ops,
+		   .of_match_table = cv1800b_dt_ids,
+		    },
+	.probe = cv1800b_rtc_probe,
+};
+
+module_platform_driver(cv1800b_rtc_driver);
+MODULE_AUTHOR("Jingbao Qiu");
+MODULE_DESCRIPTION("Sophgo CV1800B RTC Driver");
+MODULE_LICENSE("GPL");
-- 
2.25.1


  parent reply	other threads:[~2023-11-21  9:47 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-11-21  9:46 [PATCH 0/3] riscv: sophgo: add rtc support for CV1800B Jingbao Qiu
2023-11-21  9:46 ` [PATCH 1/3] dt-bindings: rtc: add binding for Sophgo CV1800B rtc controller Jingbao Qiu
2023-11-21  9:57   ` Krzysztof Kozlowski
2023-11-28 13:20     ` jingbao qiu
2023-11-21 10:37   ` Rob Herring
2023-11-21  9:46 ` Jingbao Qiu [this message]
2023-11-21 10:01   ` [PATCH 2/3] rtc: add rtc controller support for Sophgo CV1800B SoC Krzysztof Kozlowski
2023-11-28 13:22     ` jingbao qiu
2023-11-28 13:59       ` Krzysztof Kozlowski
2023-11-28 14:34         ` jingbao qiu
2023-11-28 23:01       ` Alexandre Belloni
2023-11-21 17:58   ` kernel test robot
2023-11-21 22:52   ` kernel test robot
2023-11-21  9:46 ` [PATCH 3/3] riscv: dts: sophgo: add rtc dt node for CV1800B Jingbao Qiu
2023-11-21 10:00   ` Krzysztof Kozlowski
2023-11-28 13:23     ` jingbao qiu

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20231121094642.2973795-3-qiujingbao.dlmu@gmail.com \
    --to=qiujingbao.dlmu@gmail.com \
    --cc=a.zummo@towertech.it \
    --cc=alexandre.belloni@bootlin.com \
    --cc=aou@eecs.berkeley.edu \
    --cc=chao.wei@sophgo.com \
    --cc=conor+dt@kernel.org \
    --cc=conor@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=krzysztof.kozlowski+dt@linaro.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-rtc@vger.kernel.org \
    --cc=palmer@dabbelt.com \
    --cc=paul.walmsley@sifive.com \
    --cc=robh+dt@kernel.org \
    --cc=unicorn_wang@outlook.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.