Re: [PATCH v8 2/2] rtc: sophgo: add rtc support for Sophgo CV1800 SoC

From: Inochi Amaoto
Date: Wed May 01 2024 - 03:43:33 EST


On Wed, May 01, 2024 at 01:03:58PM GMT, Jingbao Qiu wrote:
> Hi, Inochi
>
> On Wed, May 1, 2024 at 10:19 AM Inochi Amaoto <inochiama@xxxxxxxxxxx> wrote:
> >
> > On Sun, Feb 04, 2024 at 12:41:43PM GMT, Jingbao Qiu wrote:
> > > Implement the RTC driver for CV1800, which able to provide time alarm.
> > >
> > > Signed-off-by: Jingbao Qiu <qiujingbao.dlmu@xxxxxxxxx>
> > > ---
> > > drivers/rtc/Kconfig | 10 ++
> > > drivers/rtc/Makefile | 1 +
> > > drivers/rtc/rtc-cv1800.c | 244 +++++++++++++++++++++++++++++++++++++++
> > > 3 files changed, 255 insertions(+)
> > > create mode 100644 drivers/rtc/rtc-cv1800.c
> > >
> > > diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
> > > index e37a4341f442..3c6ed45a3b03 100644
> > > --- a/drivers/rtc/Kconfig
> > > +++ b/drivers/rtc/Kconfig
> > > @@ -1128,6 +1128,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_CV1800
> > > + tristate "Sophgo CV1800 RTC"
> > > + depends on ARCH_SOPHGO || COMPILE_TEST
> > > + help
> > > + If you say yes here you get support the RTC driver
> > > + for Sophgo CV1800 chip.
> > > +
> > > + This driver can also be built as a module.If so, the
> > > + module will be called rtc-cv1800.
> > > +
> > > config RTC_DRV_DA9052
> > > tristate "Dialog DA9052/DA9053 RTC"
> > > depends on PMIC_DA9052
> > > diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
> > > index 6efff381c484..4efdd2d1e963 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_CV1800) += rtc-cv1800.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-cv1800.c b/drivers/rtc/rtc-cv1800.c
> > > new file mode 100644
> > > index 000000000000..60a7192659f5
> > > --- /dev/null
> > > +++ b/drivers/rtc/rtc-cv1800.c
> > > @@ -0,0 +1,244 @@
> > > +// SPDX-License-Identifier: GPL-2.0-only
> > > +/*
> > > + * rtc-cv1800.c: RTC driver for Sophgo cv1800 RTC
> > > + *
> > > + * Author: Jingbao Qiu <qiujingbao.dlmu@xxxxxxxxx>
> > > + */
> > > +
> > > +#include <linux/clk.h>
> > > +#include <linux/irq.h>
> > > +#include <linux/kernel.h>
> > > +#include <linux/module.h>
> > > +#include <linux/of.h>
> > > +#include <linux/platform_device.h>
> > > +#include <linux/regmap.h>
> > > +#include <linux/rtc.h>
> > > +
> > > +#define CTRL 0x08
> > > +#define ANA_CALIB 0x1000
> > > +#define SEC_PULSE_GEN 0x1004
> > > +#define ALARM_TIME 0x1008
> > > +#define ALARM_ENABLE 0x100C
> > > +#define SET_SEC_CNTR_VAL 0x1010
> > > +#define SET_SEC_CNTR_TRIG 0x1014
> > > +#define SEC_CNTR_VAL 0x1018
> > > +#define APB_RDATA_SEL 0x103C
> > > +#define POR_DB_MAGIC_KEY 0x1068
> > > +#define EN_PWR_WAKEUP 0x10BC
> > > +
> > > +/*
> > > + * When in VDDBKUP domain, this MACRO register
> > > + * does not power down
> > > + */
> > > +#define MACRO_DA_CLEAR_ALL 0x1480
> > > +#define MACRO_DA_SOC_READY 0x148C
> > > +#define MACRO_RO_T 0x14A8
> > > +#define MACRO_RG_SET_T 0x1498
> > > +
> > > +#define CTRL_MODE_MASK BIT(10)
> > > +#define CTRL_MODE_OSC32K 0x00UL
> > > +#define CTRL_MODE_XTAL32K BIT(0)
> > > +#define REG_ENABLE_FUN BIT(0)
> > > +#define REG_DISABLE_FUN 0x00UL
> > > +#define ALARM_ENABLE_MASK BIT(0)
> > > +#define SET_SEC_CNTR_VAL_INIT (BIT(28) || BIT(29))
> > > +#define SEC_PULSE_SEL_INNER BIT(31)
> > > +#define SEC_PULSE_GEN_SEL_MASK GENMASK(30, 0)
> > > +#define CALIB_SEL_FTUNE_MASK GENMASK(30, 0)
> > > +#define CALIB_SEL_FTUNE_INNER 0x00UL
> > > +
> > > +struct cv1800_rtc_priv {
> > > + struct rtc_device *rtc_dev;
> > > + struct regmap *rtc_map;
> > > + struct clk *clk;
> > > + int irq;
> > > +};
> > > +
> > > +static const struct regmap_config cv1800_rtc_regmap_config = {
> > > + .reg_bits = 32,
> > > + .val_bits = 32,
> > > + .reg_stride = 4,
> > > +};
> > > +
> > > +static int cv1800_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
> > > +{
> > > + struct cv1800_rtc_priv *info = dev_get_drvdata(dev);
> > > +
> > > + regmap_write(info->rtc_map, ALARM_ENABLE, enabled);
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +static int cv1800_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
> > > +{
> > > + struct cv1800_rtc_priv *info = dev_get_drvdata(dev);
> > > + unsigned long alarm_time;
> > > +
> > > + alarm_time = rtc_tm_to_time64(&alrm->time);
> > > +
> > > + cv1800_rtc_alarm_irq_enable(dev, REG_DISABLE_FUN);
> > > +
> > > + regmap_write(info->rtc_map, ALARM_TIME, alarm_time);
> > > +
> > > + cv1800_rtc_alarm_irq_enable(dev, alrm->enabled);
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +static int cv1800_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
> > > +{
> > > + struct cv1800_rtc_priv *info = dev_get_drvdata(dev);
> > > + u32 enabled;
> > > + u32 time;
> > > +
> > > + regmap_read(info->rtc_map, ALARM_ENABLE, &enabled);
> > > +
> > > + alarm->enabled = enabled & ALARM_ENABLE_MASK;
> > > +
> > > + regmap_read(info->rtc_map, ALARM_TIME, &time);
> > > +
> > > + rtc_time64_to_tm(time, &alarm->time);
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +static void rtc_enable_sec_counter(struct cv1800_rtc_priv *info)
> > > +{
> > > + u32 sec_ro_t;
> > > + u32 sec;
> > > +
> > > + /* select inner sec pulse */
> > > + regmap_update_bits(info->rtc_map, SEC_PULSE_GEN,
> > > + (u32)(~SEC_PULSE_GEN_SEL_MASK),
> > > + (u32)(~SEC_PULSE_SEL_INNER));
> > > +
> > > + regmap_update_bits(info->rtc_map, ANA_CALIB,
> > > + (u32)(~CALIB_SEL_FTUNE_MASK),
> > > + CALIB_SEL_FTUNE_INNER);
> > > +
> > > + sec = SET_SEC_CNTR_VAL_INIT;
> > > +
> > > + /* load from MACRO register */
> > > + regmap_read(info->rtc_map, MACRO_RO_T, &sec_ro_t);
> > > + if (sec_ro_t > (SET_SEC_CNTR_VAL_INIT))
> > > + sec = sec_ro_t;
> > > +
> > > + regmap_write(info->rtc_map, SET_SEC_CNTR_VAL, sec);
> > > + regmap_write(info->rtc_map, SET_SEC_CNTR_TRIG, REG_ENABLE_FUN);
> > > +}
> > > +
> > > +static int cv1800_rtc_read_time(struct device *dev, struct rtc_time *tm)
> > > +{
> > > + struct cv1800_rtc_priv *info = dev_get_drvdata(dev);
> > > + u32 sec;
> > > +
> > > + regmap_read(info->rtc_map, SEC_CNTR_VAL, &sec);
> > > +
> > > + rtc_time64_to_tm(sec, tm);
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +static int cv1800_rtc_set_time(struct device *dev, struct rtc_time *tm)
> > > +{
> > > + struct cv1800_rtc_priv *info = dev_get_drvdata(dev);
> > > + unsigned long sec;
> > > +
> > > + sec = rtc_tm_to_time64(tm);
> > > +
> > > + regmap_write(info->rtc_map, SET_SEC_CNTR_VAL, sec);
> > > + regmap_write(info->rtc_map, SET_SEC_CNTR_TRIG, REG_ENABLE_FUN);
> > > +
> > > + regmap_write(info->rtc_map, MACRO_RG_SET_T, sec);
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +static irqreturn_t cv1800_rtc_irq_handler(int irq, void *dev_id)
> > > +{
> > > + struct rtc_device *rtc = dev_id;
> > > +
> > > + rtc_update_irq(rtc, 1, RTC_IRQF | RTC_AF);
> > > +
> > > + return IRQ_HANDLED;
> > > +}
> > > +
> > > +static const struct rtc_class_ops cv1800_rtc_ops = {
> > > + .read_time = cv1800_rtc_read_time,
> > > + .set_time = cv1800_rtc_set_time,
> > > + .read_alarm = cv1800_rtc_read_alarm,
> > > + .set_alarm = cv1800_rtc_set_alarm,
> > > + .alarm_irq_enable = cv1800_rtc_alarm_irq_enable,
> > > +};
> > > +
> > > +static int cv1800_rtc_probe(struct platform_device *pdev)
> > > +{
> > > + struct cv1800_rtc_priv *rtc;
> > > + u32 ctrl_val;
> > > + void __iomem *base;
> > > + int ret;
> > > +
> > > + rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
> > > + if (!rtc)
> > > + return -ENOMEM;
> > > +
> > > + base = devm_platform_ioremap_resource(pdev, 0);
> > > + if (IS_ERR(base))
> > > + return PTR_ERR(base);
> > > +
> > > + rtc->rtc_map = devm_regmap_init_mmio(&pdev->dev, base,
> > > + &cv1800_rtc_regmap_config);
> > > + if (IS_ERR(rtc->rtc_map))
> > > + return PTR_ERR(rtc->rtc_map);
> > > +
> > > + rtc->irq = platform_get_irq(pdev, 0);
> > > + if (rtc->irq < 0)
> > > + return rtc->irq;
> > > +
> > > + ret = devm_request_irq(&pdev->dev, rtc->irq, cv1800_rtc_irq_handler,
> > > + IRQF_TRIGGER_HIGH, "alarm", &pdev->dev);
> > > + if (ret)
> > > + return dev_err_probe(&pdev->dev, ret,
> > > + "cannot register interrupt handler\n");
> > > +
> > > + rtc->clk = devm_clk_get_enabled(&pdev->dev, NULL);
> > > + if (IS_ERR(rtc->clk))
> > > + return dev_err_probe(&pdev->dev, PTR_ERR(rtc->clk),
> > > + "clk not found\n");
> > > +
> > > + rtc->rtc_dev = devm_rtc_allocate_device(&pdev->dev);
> > > + if (IS_ERR(rtc->rtc_dev))
> > > + return PTR_ERR(rtc->rtc_dev);
> > > +
> > > + platform_set_drvdata(pdev, rtc);
> > > +
> > > + rtc->rtc_dev->ops = &cv1800_rtc_ops;
> > > + rtc->rtc_dev->range_max = U32_MAX;
> > > +
> >
> > > + regmap_read(rtc->rtc_map, CTRL, &ctrl_val);
> > > + ctrl_val &= CTRL_MODE_MASK;
> > > +
> > > + if (ctrl_val == CTRL_MODE_OSC32K)
> > > + rtc_enable_sec_counter(rtc);
> > > +
> >
> > use (ctrl_val & CTRL_MODE_OSC32K).
> >
> > Another thing is that I do not think is a good way to let the
> > rtc driver access RTC_CTRL area directly. You have already
> > know there is a 8051 device in the 0x05025000. It is necessary
> > to make some room for this device. Maybe you want to implement
> > them all in the rtc driver? If so, I do think it is a bad idea.
>
>
> Do you mean that RTC drivers should not directly access the 0x05025000 address?
> Because there is an 8051 subsystem on this address.

Yes. At least we need some mechanism to share these address between
this devices.

> Firstly, I do not intend to implement 8051 in the RTC driver,
> but the 8051 subsystem is located within a module independently
> powered by the RTC.
> So if we want to implement the 8051 subsystem in the future, it can be
> used as a node in RTC? I'm not sure.

Yes, this is what I care about.

> Then, Alexandre told me that there are operations related to PM in
> RTC, such as the following files.
> This matches the description of address 0x05025000.
>
> drivers/rtc/rtc jz4740. c
>

I do not think this is something related to the PM. 8051 is more
like remoteproc. So it is necessary to arrange them carefully.

> >
> > > + return devm_rtc_register_device(rtc->rtc_dev);
> > > +}
> > > +
> > > +static const struct of_device_id cv1800_dt_ids[] = {
> > > + { .compatible = "sophgo,cv1800-rtc" },
> > > + { /* sentinel */ },
> > > +};
> > > +MODULE_DEVICE_TABLE(of, cv1800_dt_ids);
> > > +
> > > +static struct platform_driver cv1800_rtc_driver = {
> > > + .driver = {
> > > + .name = "sophgo-cv1800-rtc",
> > > + .of_match_table = cv1800_dt_ids,
> > > + },
> > > + .probe = cv1800_rtc_probe,
> > > +};
> > > +
> > > +module_platform_driver(cv1800_rtc_driver);
> > > +MODULE_AUTHOR("Jingbao Qiu");
> > > +MODULE_DESCRIPTION("Sophgo cv1800 RTC Driver");
> > > +MODULE_LICENSE("GPL");
> > > --
> > > 2.25.1
> > >