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

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

 



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
> > >




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


  Powered by Linux