All of lore.kernel.org
 help / color / mirror / Atom feed
From: Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
To: Romain Perier <romain.perier@gmail.com>
Cc: Alessandro Zummo <a.zummo@towertech.it>,
	Alexandre Belloni <alexandre.belloni@bootlin.com>,
	Daniel Palmer <daniel@0x0f.com>, Rob Herring <robh+dt@kernel.org>,
	linux-rtc@vger.kernel.org, devicetree@vger.kernel.org,
	Linux Kernel Mailing List <linux-kernel@vger.kernel.org>,
	linux ARM <linux-arm-kernel@lists.infradead.org>
Subject: Re: [PATCH v3 2/3] rtc: Add support for the MSTAR MSC313 RTC
Date: Mon, 23 Aug 2021 16:28:52 +0900	[thread overview]
Message-ID: <CABMQnVJwFf4nX6ApdobBnwfzmWSsYHcabFqZd8rUQw=T7V=vcA@mail.gmail.com> (raw)
In-Reply-To: <20210819170301.10520-3-romain.perier@gmail.com>

Hi!

2021年8月20日(金) 2:03 Romain Perier <romain.perier@gmail.com>:
>
> From: Daniel Palmer <daniel@0x0f.com>
>
> This adds support for the RTC block on the Mstar MSC313e SoCs and newer.
>
> Signed-off-by: Daniel Palmer <daniel@0x0f.com>
> Co-developed-by: Romain Perier <romain.perier@gmail.com>
> Signed-off-by: Romain Perier <romain.perier@gmail.com>
> ---
>  MAINTAINERS              |   1 +
>  drivers/rtc/Kconfig      |  10 ++
>  drivers/rtc/Makefile     |   1 +
>  drivers/rtc/rtc-msc313.c | 258 +++++++++++++++++++++++++++++++++++++++
>  4 files changed, 270 insertions(+)
>  create mode 100644 drivers/rtc/rtc-msc313.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index fd25e4ecf0b9..ebacdd5e8878 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -2220,6 +2220,7 @@ F:        arch/arm/boot/dts/mstar-*
>  F:     arch/arm/mach-mstar/
>  F:     drivers/clk/mstar/
>  F:     drivers/gpio/gpio-msc313.c
> +F:     drivers/rtc/rtc-msc313.c
>  F:     drivers/watchdog/msc313e_wdt.c
>  F:     include/dt-bindings/clock/mstar-*
>  F:     include/dt-bindings/gpio/msc313-gpio.h
> diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
> index 12153d5801ce..9ce4baab5fcf 100644
> --- a/drivers/rtc/Kconfig
> +++ b/drivers/rtc/Kconfig
> @@ -1925,4 +1925,14 @@ config RTC_DRV_WILCO_EC
>           This can also be built as a module. If so, the module will
>           be named "rtc_wilco_ec".
>
> +config RTC_DRV_MSC313
> +       tristate "MStar MSC313 RTC"
> +        depends on ARCH_MSTARV7 || COMPILE_TEST
> +       help
> +         If you say yes here you get support for the Mstar MSC313e On-Chip
> +         Real Time Clock.
> +
> +         This driver can also be built as a module, if so, the module
> +         will be called "rtc-msc313".
> +
>  endif # RTC_CLASS
> diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
> index 2dd0dd956b0e..5efda8a60cee 100644
> --- a/drivers/rtc/Makefile
> +++ b/drivers/rtc/Makefile
> @@ -101,6 +101,7 @@ obj-$(CONFIG_RTC_DRV_MCP795)        += rtc-mcp795.o
>  obj-$(CONFIG_RTC_DRV_MESON)    += rtc-meson.o
>  obj-$(CONFIG_RTC_DRV_MOXART)   += rtc-moxart.o
>  obj-$(CONFIG_RTC_DRV_MPC5121)  += rtc-mpc5121.o
> +obj-$(CONFIG_RTC_DRV_MSC313)   += rtc-msc313.o
>  obj-$(CONFIG_RTC_DRV_MSM6242)  += rtc-msm6242.o
>  obj-$(CONFIG_RTC_DRV_MT2712)   += rtc-mt2712.o
>  obj-$(CONFIG_RTC_DRV_MT6397)   += rtc-mt6397.o
> diff --git a/drivers/rtc/rtc-msc313.c b/drivers/rtc/rtc-msc313.c
> new file mode 100644
> index 000000000000..8cf5d5fb298f
> --- /dev/null
> +++ b/drivers/rtc/rtc-msc313.c
> @@ -0,0 +1,258 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Real time clocks driver for MStar/SigmaStar ARMv7 SoCs.
> + * Based on "Real Time Clock driver for msb252x." that was contained
> + * in various MStar kernels.
> + *
> + * (C) 2019 Daniel Palmer
> + * (C) 2021 Romain Perier
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/module.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/platform_device.h>
> +#include <linux/rtc.h>
> +
> +/* Registers */
> +#define REG_RTC_CTRL           0x00
> +#define REG_RTC_FREQ_CW_L      0x04
> +#define REG_RTC_FREQ_CW_H      0x08
> +#define REG_RTC_LOAD_VAL_L     0x0C
> +#define REG_RTC_LOAD_VAL_H     0x10
> +#define REG_RTC_MATCH_VAL_L    0x14
> +#define REG_RTC_MATCH_VAL_H    0x18
> +#define REG_RTC_STATUS_INT     0x1C
> +#define REG_RTC_CNT_VAL_L      0x20
> +#define REG_RTC_CNT_VAL_H      0x24
> +
> +/* Control bits for REG_RTC_CTRL */
> +#define SOFT_RSTZ_BIT          BIT(0)
> +#define CNT_EN_BIT             BIT(1)
> +#define WRAP_EN_BIT            BIT(2)
> +#define LOAD_EN_BIT            BIT(3)
> +#define READ_EN_BIT            BIT(4)
> +#define INT_MASK_BIT           BIT(5)
> +#define INT_FORCE_BIT          BIT(6)
> +#define INT_CLEAR_BIT          BIT(7)
> +
> +/* Control bits for REG_RTC_STATUS_INT */
> +#define RAW_INT_BIT            BIT(0)
> +#define ALM_INT_BIT            BIT(1)
> +
> +struct msc313_rtc {
> +       struct rtc_device *rtc_dev;
> +       void __iomem *rtc_base;
> +       struct clk *clk;

The clk variable is only used in msc313_rtc_probe(). Therefore, it is
not necessary to have it in this structure.

> +};
> +
> +static int msc313_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
> +{
> +       struct msc313_rtc *priv = dev_get_drvdata(dev);
> +       unsigned long seconds;
> +
> +       seconds = readw(priv->rtc_base + REG_RTC_MATCH_VAL_L)
> +                       | (readw(priv->rtc_base + REG_RTC_MATCH_VAL_H) << 16);
> +
> +       rtc_time64_to_tm(seconds, &alarm->time);
> +
> +       if (!(readw(priv->rtc_base + REG_RTC_CTRL) & INT_MASK_BIT))
> +               alarm->enabled = 1;
> +
> +       return 0;
> +}
> +
> +static int msc313_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
> +{
> +       struct msc313_rtc *priv = dev_get_drvdata(dev);
> +       u16 reg;
> +
> +       reg = readw(priv->rtc_base + REG_RTC_CTRL);
> +       if (enabled)
> +               reg &= ~INT_MASK_BIT;
> +       else
> +               reg |= INT_MASK_BIT;
> +       writew(reg, priv->rtc_base + REG_RTC_CTRL);
> +       return 0;
> +}
> +
> +static int msc313_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
> +{
> +       struct msc313_rtc *priv = dev_get_drvdata(dev);
> +       unsigned long seconds;
> +
> +       seconds = rtc_tm_to_time64(&alarm->time);
> +       writew((seconds & 0xFFFF), priv->rtc_base + REG_RTC_MATCH_VAL_L);
> +       writew((seconds >> 16) & 0xFFFF, priv->rtc_base + REG_RTC_MATCH_VAL_H);
> +
> +       msc313_rtc_alarm_irq_enable(dev, alarm->enabled);
> +
> +       return 0;
> +}
> +
> +static bool msc313_rtc_get_enabled(struct msc313_rtc *priv)
> +{
> +       return readw(priv->rtc_base + REG_RTC_CTRL) & CNT_EN_BIT;
> +}
> +
> +static void msc313_rtc_set_enabled(struct msc313_rtc *priv)
> +{
> +       u16 reg;
> +
> +       reg = readw(priv->rtc_base + REG_RTC_CTRL);
> +       reg |= CNT_EN_BIT;
> +       writew(reg, priv->rtc_base + REG_RTC_CTRL);
> +}
> +
> +static int msc313_rtc_read_time(struct device *dev, struct rtc_time *tm)
> +{
> +       struct msc313_rtc *priv = dev_get_drvdata(dev);
> +       u32 seconds;
> +       u16 reg;
> +
> +       if (!msc313_rtc_get_enabled(priv))
> +               return -EINVAL;
> +
> +       reg = readw(priv->rtc_base + REG_RTC_CTRL);
> +       writew(reg | READ_EN_BIT, priv->rtc_base + REG_RTC_CTRL);
> +
> +       /* Wait for HW latch done */
> +       while (readw(priv->rtc_base + REG_RTC_CTRL) & READ_EN_BIT)
> +               udelay(1);
> +
> +       seconds = readw(priv->rtc_base + REG_RTC_CNT_VAL_L)
> +                       | (readw(priv->rtc_base + REG_RTC_CNT_VAL_H) << 16);
> +
> +       rtc_time64_to_tm(seconds, tm);
> +
> +       return 0;
> +}
> +
> +static int msc313_rtc_set_time(struct device *dev, struct rtc_time *tm)
> +{
> +       struct msc313_rtc *priv = dev_get_drvdata(dev);
> +       unsigned long seconds;
> +       u16 reg;
> +
> +       seconds = rtc_tm_to_time64(tm);
> +       writew(seconds & 0xFFFF, priv->rtc_base + REG_RTC_LOAD_VAL_L);
> +       writew((seconds >> 16) & 0xFFFF, priv->rtc_base + REG_RTC_LOAD_VAL_H);
> +
> +       /* Enable load for loading value into internal RTC counter */
> +       reg = readw(priv->rtc_base + REG_RTC_CTRL);
> +       writew(reg | LOAD_EN_BIT, priv->rtc_base + REG_RTC_CTRL);
> +
> +       /* Wait for HW latch done */
> +       while (readw(priv->rtc_base + REG_RTC_CTRL) & LOAD_EN_BIT)
> +               udelay(1);
> +       msc313_rtc_set_enabled(priv);
> +       return 0;
> +}
> +
> +static const struct rtc_class_ops msc313_rtc_ops = {
> +       .read_time = msc313_rtc_read_time,
> +       .set_time = msc313_rtc_set_time,
> +       .read_alarm = msc313_rtc_read_alarm,
> +       .set_alarm = msc313_rtc_set_alarm,
> +       .alarm_irq_enable = msc313_rtc_alarm_irq_enable,
> +};
> +
> +static irqreturn_t msc313_rtc_interrupt(s32 irq, void *dev_id)
> +{
> +       struct msc313_rtc *priv = dev_get_drvdata(dev_id);
> +       u16 reg;
> +
> +       reg = readw(priv->rtc_base + REG_RTC_STATUS_INT);
> +       if (!(reg & ALM_INT_BIT))
> +               return IRQ_NONE;
> +
> +       reg = readw(priv->rtc_base + REG_RTC_CTRL);
> +       reg |= INT_CLEAR_BIT;
> +       reg &= ~INT_FORCE_BIT;
> +       writew(reg, priv->rtc_base + REG_RTC_CTRL);
> +
> +       rtc_update_irq(priv->rtc_dev, 1, RTC_IRQF | RTC_AF);
> +
> +       return IRQ_HANDLED;
> +}
> +
> +static int msc313_rtc_probe(struct platform_device *pdev)
> +{
> +       struct device *dev = &pdev->dev;
> +       struct msc313_rtc *priv;
> +       int ret;
> +       int irq;
> +       unsigned long rate;

Please use reverse christmas tree ordering for local variable.

> +
> +       priv = devm_kzalloc(&pdev->dev, sizeof(struct msc313_rtc), GFP_KERNEL);
> +       if (!priv)
> +               return -ENOMEM;
> +
> +       priv->rtc_base = devm_platform_ioremap_resource(pdev, 0);
> +       if (IS_ERR(priv->rtc_base))
> +               return PTR_ERR(priv->rtc_base);
> +
> +       irq = platform_get_irq(pdev, 0);
> +       if (irq < 0)
> +               return -EINVAL;
> +
> +       priv->rtc_dev = devm_rtc_allocate_device(dev);
> +       if (IS_ERR(priv->rtc_dev))
> +               return PTR_ERR(priv->rtc_dev);
> +
> +       priv->rtc_dev->ops = &msc313_rtc_ops;
> +       priv->rtc_dev->range_max = U32_MAX;
> +
> +       ret = devm_request_irq(dev, irq, msc313_rtc_interrupt, IRQF_SHARED,
> +                              dev_name(&pdev->dev), &pdev->dev);
> +       if (ret) {
> +               dev_err(dev, "Could not request IRQ\n");
> +               return ret;
> +       }
> +
> +       priv->clk = devm_clk_get(dev, NULL);
> +       if (IS_ERR(priv->clk)) {
> +               dev_err(dev, "No input reference clock\n");
> +               return PTR_ERR(priv->clk);
> +       }
> +
> +       ret = clk_prepare_enable(priv->clk);
> +       if (ret) {
> +               dev_err(dev, "Failed to enable the reference clock, %d\n", ret);
> +               return ret;
> +       }
> +
> +       ret = devm_add_action_or_reset(dev, (void (*) (void *))clk_disable_unprepare, priv->clk);
> +       if (ret)
> +               return ret;
> +
> +       rate = clk_get_rate(priv->clk);
> +       writew(rate & 0xFFFF, priv->rtc_base + REG_RTC_FREQ_CW_L);
> +       writew((rate >> 16) & 0xFFFF, priv->rtc_base + REG_RTC_FREQ_CW_H);
> +
> +       platform_set_drvdata(pdev, priv);
> +
> +       return devm_rtc_register_device(priv->rtc_dev);
> +}
> +
> +static const struct of_device_id msc313_rtc_of_match_table[] = {
> +       { .compatible = "mstar,msc313-rtc" },
> +       { }
> +};
> +MODULE_DEVICE_TABLE(of, ms_rtc_of_match_table);

msc313_rtc_of_match_table ?

> +
> +static struct platform_driver msc313_rtc_driver = {
> +       .probe = msc313_rtc_probe,
> +       .driver = {
> +               .name = "msc313-rtc",
> +               .of_match_table = msc313_rtc_of_match_table,
> +       },
> +};
> +
> +module_platform_driver(msc313_rtc_driver);
> +
> +MODULE_AUTHOR("Daniel Palmer <daniel@thingy.jp>");
> +MODULE_AUTHOR("Romain Perier <romain.perier@gmail.com>");
> +MODULE_DESCRIPTION("MStar RTC Driver");
> +MODULE_LICENSE("GPL v2");
> --
> 2.30.2
>

Best regards,
  Nobuhiro

-- 
Nobuhiro Iwamatsu
   iwamatsu at {nigauri.org / debian.org / kernel.org}
   GPG ID: 40AD1FA6

WARNING: multiple messages have this Message-ID (diff)
From: Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
To: Romain Perier <romain.perier@gmail.com>
Cc: Alessandro Zummo <a.zummo@towertech.it>,
	Alexandre Belloni <alexandre.belloni@bootlin.com>,
	 Daniel Palmer <daniel@0x0f.com>,
	Rob Herring <robh+dt@kernel.org>,
	linux-rtc@vger.kernel.org, devicetree@vger.kernel.org,
	 Linux Kernel Mailing List <linux-kernel@vger.kernel.org>,
	 linux ARM <linux-arm-kernel@lists.infradead.org>
Subject: Re: [PATCH v3 2/3] rtc: Add support for the MSTAR MSC313 RTC
Date: Mon, 23 Aug 2021 16:28:52 +0900	[thread overview]
Message-ID: <CABMQnVJwFf4nX6ApdobBnwfzmWSsYHcabFqZd8rUQw=T7V=vcA@mail.gmail.com> (raw)
In-Reply-To: <20210819170301.10520-3-romain.perier@gmail.com>

Hi!

2021年8月20日(金) 2:03 Romain Perier <romain.perier@gmail.com>:
>
> From: Daniel Palmer <daniel@0x0f.com>
>
> This adds support for the RTC block on the Mstar MSC313e SoCs and newer.
>
> Signed-off-by: Daniel Palmer <daniel@0x0f.com>
> Co-developed-by: Romain Perier <romain.perier@gmail.com>
> Signed-off-by: Romain Perier <romain.perier@gmail.com>
> ---
>  MAINTAINERS              |   1 +
>  drivers/rtc/Kconfig      |  10 ++
>  drivers/rtc/Makefile     |   1 +
>  drivers/rtc/rtc-msc313.c | 258 +++++++++++++++++++++++++++++++++++++++
>  4 files changed, 270 insertions(+)
>  create mode 100644 drivers/rtc/rtc-msc313.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index fd25e4ecf0b9..ebacdd5e8878 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -2220,6 +2220,7 @@ F:        arch/arm/boot/dts/mstar-*
>  F:     arch/arm/mach-mstar/
>  F:     drivers/clk/mstar/
>  F:     drivers/gpio/gpio-msc313.c
> +F:     drivers/rtc/rtc-msc313.c
>  F:     drivers/watchdog/msc313e_wdt.c
>  F:     include/dt-bindings/clock/mstar-*
>  F:     include/dt-bindings/gpio/msc313-gpio.h
> diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
> index 12153d5801ce..9ce4baab5fcf 100644
> --- a/drivers/rtc/Kconfig
> +++ b/drivers/rtc/Kconfig
> @@ -1925,4 +1925,14 @@ config RTC_DRV_WILCO_EC
>           This can also be built as a module. If so, the module will
>           be named "rtc_wilco_ec".
>
> +config RTC_DRV_MSC313
> +       tristate "MStar MSC313 RTC"
> +        depends on ARCH_MSTARV7 || COMPILE_TEST
> +       help
> +         If you say yes here you get support for the Mstar MSC313e On-Chip
> +         Real Time Clock.
> +
> +         This driver can also be built as a module, if so, the module
> +         will be called "rtc-msc313".
> +
>  endif # RTC_CLASS
> diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
> index 2dd0dd956b0e..5efda8a60cee 100644
> --- a/drivers/rtc/Makefile
> +++ b/drivers/rtc/Makefile
> @@ -101,6 +101,7 @@ obj-$(CONFIG_RTC_DRV_MCP795)        += rtc-mcp795.o
>  obj-$(CONFIG_RTC_DRV_MESON)    += rtc-meson.o
>  obj-$(CONFIG_RTC_DRV_MOXART)   += rtc-moxart.o
>  obj-$(CONFIG_RTC_DRV_MPC5121)  += rtc-mpc5121.o
> +obj-$(CONFIG_RTC_DRV_MSC313)   += rtc-msc313.o
>  obj-$(CONFIG_RTC_DRV_MSM6242)  += rtc-msm6242.o
>  obj-$(CONFIG_RTC_DRV_MT2712)   += rtc-mt2712.o
>  obj-$(CONFIG_RTC_DRV_MT6397)   += rtc-mt6397.o
> diff --git a/drivers/rtc/rtc-msc313.c b/drivers/rtc/rtc-msc313.c
> new file mode 100644
> index 000000000000..8cf5d5fb298f
> --- /dev/null
> +++ b/drivers/rtc/rtc-msc313.c
> @@ -0,0 +1,258 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Real time clocks driver for MStar/SigmaStar ARMv7 SoCs.
> + * Based on "Real Time Clock driver for msb252x." that was contained
> + * in various MStar kernels.
> + *
> + * (C) 2019 Daniel Palmer
> + * (C) 2021 Romain Perier
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/module.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/platform_device.h>
> +#include <linux/rtc.h>
> +
> +/* Registers */
> +#define REG_RTC_CTRL           0x00
> +#define REG_RTC_FREQ_CW_L      0x04
> +#define REG_RTC_FREQ_CW_H      0x08
> +#define REG_RTC_LOAD_VAL_L     0x0C
> +#define REG_RTC_LOAD_VAL_H     0x10
> +#define REG_RTC_MATCH_VAL_L    0x14
> +#define REG_RTC_MATCH_VAL_H    0x18
> +#define REG_RTC_STATUS_INT     0x1C
> +#define REG_RTC_CNT_VAL_L      0x20
> +#define REG_RTC_CNT_VAL_H      0x24
> +
> +/* Control bits for REG_RTC_CTRL */
> +#define SOFT_RSTZ_BIT          BIT(0)
> +#define CNT_EN_BIT             BIT(1)
> +#define WRAP_EN_BIT            BIT(2)
> +#define LOAD_EN_BIT            BIT(3)
> +#define READ_EN_BIT            BIT(4)
> +#define INT_MASK_BIT           BIT(5)
> +#define INT_FORCE_BIT          BIT(6)
> +#define INT_CLEAR_BIT          BIT(7)
> +
> +/* Control bits for REG_RTC_STATUS_INT */
> +#define RAW_INT_BIT            BIT(0)
> +#define ALM_INT_BIT            BIT(1)
> +
> +struct msc313_rtc {
> +       struct rtc_device *rtc_dev;
> +       void __iomem *rtc_base;
> +       struct clk *clk;

The clk variable is only used in msc313_rtc_probe(). Therefore, it is
not necessary to have it in this structure.

> +};
> +
> +static int msc313_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
> +{
> +       struct msc313_rtc *priv = dev_get_drvdata(dev);
> +       unsigned long seconds;
> +
> +       seconds = readw(priv->rtc_base + REG_RTC_MATCH_VAL_L)
> +                       | (readw(priv->rtc_base + REG_RTC_MATCH_VAL_H) << 16);
> +
> +       rtc_time64_to_tm(seconds, &alarm->time);
> +
> +       if (!(readw(priv->rtc_base + REG_RTC_CTRL) & INT_MASK_BIT))
> +               alarm->enabled = 1;
> +
> +       return 0;
> +}
> +
> +static int msc313_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
> +{
> +       struct msc313_rtc *priv = dev_get_drvdata(dev);
> +       u16 reg;
> +
> +       reg = readw(priv->rtc_base + REG_RTC_CTRL);
> +       if (enabled)
> +               reg &= ~INT_MASK_BIT;
> +       else
> +               reg |= INT_MASK_BIT;
> +       writew(reg, priv->rtc_base + REG_RTC_CTRL);
> +       return 0;
> +}
> +
> +static int msc313_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
> +{
> +       struct msc313_rtc *priv = dev_get_drvdata(dev);
> +       unsigned long seconds;
> +
> +       seconds = rtc_tm_to_time64(&alarm->time);
> +       writew((seconds & 0xFFFF), priv->rtc_base + REG_RTC_MATCH_VAL_L);
> +       writew((seconds >> 16) & 0xFFFF, priv->rtc_base + REG_RTC_MATCH_VAL_H);
> +
> +       msc313_rtc_alarm_irq_enable(dev, alarm->enabled);
> +
> +       return 0;
> +}
> +
> +static bool msc313_rtc_get_enabled(struct msc313_rtc *priv)
> +{
> +       return readw(priv->rtc_base + REG_RTC_CTRL) & CNT_EN_BIT;
> +}
> +
> +static void msc313_rtc_set_enabled(struct msc313_rtc *priv)
> +{
> +       u16 reg;
> +
> +       reg = readw(priv->rtc_base + REG_RTC_CTRL);
> +       reg |= CNT_EN_BIT;
> +       writew(reg, priv->rtc_base + REG_RTC_CTRL);
> +}
> +
> +static int msc313_rtc_read_time(struct device *dev, struct rtc_time *tm)
> +{
> +       struct msc313_rtc *priv = dev_get_drvdata(dev);
> +       u32 seconds;
> +       u16 reg;
> +
> +       if (!msc313_rtc_get_enabled(priv))
> +               return -EINVAL;
> +
> +       reg = readw(priv->rtc_base + REG_RTC_CTRL);
> +       writew(reg | READ_EN_BIT, priv->rtc_base + REG_RTC_CTRL);
> +
> +       /* Wait for HW latch done */
> +       while (readw(priv->rtc_base + REG_RTC_CTRL) & READ_EN_BIT)
> +               udelay(1);
> +
> +       seconds = readw(priv->rtc_base + REG_RTC_CNT_VAL_L)
> +                       | (readw(priv->rtc_base + REG_RTC_CNT_VAL_H) << 16);
> +
> +       rtc_time64_to_tm(seconds, tm);
> +
> +       return 0;
> +}
> +
> +static int msc313_rtc_set_time(struct device *dev, struct rtc_time *tm)
> +{
> +       struct msc313_rtc *priv = dev_get_drvdata(dev);
> +       unsigned long seconds;
> +       u16 reg;
> +
> +       seconds = rtc_tm_to_time64(tm);
> +       writew(seconds & 0xFFFF, priv->rtc_base + REG_RTC_LOAD_VAL_L);
> +       writew((seconds >> 16) & 0xFFFF, priv->rtc_base + REG_RTC_LOAD_VAL_H);
> +
> +       /* Enable load for loading value into internal RTC counter */
> +       reg = readw(priv->rtc_base + REG_RTC_CTRL);
> +       writew(reg | LOAD_EN_BIT, priv->rtc_base + REG_RTC_CTRL);
> +
> +       /* Wait for HW latch done */
> +       while (readw(priv->rtc_base + REG_RTC_CTRL) & LOAD_EN_BIT)
> +               udelay(1);
> +       msc313_rtc_set_enabled(priv);
> +       return 0;
> +}
> +
> +static const struct rtc_class_ops msc313_rtc_ops = {
> +       .read_time = msc313_rtc_read_time,
> +       .set_time = msc313_rtc_set_time,
> +       .read_alarm = msc313_rtc_read_alarm,
> +       .set_alarm = msc313_rtc_set_alarm,
> +       .alarm_irq_enable = msc313_rtc_alarm_irq_enable,
> +};
> +
> +static irqreturn_t msc313_rtc_interrupt(s32 irq, void *dev_id)
> +{
> +       struct msc313_rtc *priv = dev_get_drvdata(dev_id);
> +       u16 reg;
> +
> +       reg = readw(priv->rtc_base + REG_RTC_STATUS_INT);
> +       if (!(reg & ALM_INT_BIT))
> +               return IRQ_NONE;
> +
> +       reg = readw(priv->rtc_base + REG_RTC_CTRL);
> +       reg |= INT_CLEAR_BIT;
> +       reg &= ~INT_FORCE_BIT;
> +       writew(reg, priv->rtc_base + REG_RTC_CTRL);
> +
> +       rtc_update_irq(priv->rtc_dev, 1, RTC_IRQF | RTC_AF);
> +
> +       return IRQ_HANDLED;
> +}
> +
> +static int msc313_rtc_probe(struct platform_device *pdev)
> +{
> +       struct device *dev = &pdev->dev;
> +       struct msc313_rtc *priv;
> +       int ret;
> +       int irq;
> +       unsigned long rate;

Please use reverse christmas tree ordering for local variable.

> +
> +       priv = devm_kzalloc(&pdev->dev, sizeof(struct msc313_rtc), GFP_KERNEL);
> +       if (!priv)
> +               return -ENOMEM;
> +
> +       priv->rtc_base = devm_platform_ioremap_resource(pdev, 0);
> +       if (IS_ERR(priv->rtc_base))
> +               return PTR_ERR(priv->rtc_base);
> +
> +       irq = platform_get_irq(pdev, 0);
> +       if (irq < 0)
> +               return -EINVAL;
> +
> +       priv->rtc_dev = devm_rtc_allocate_device(dev);
> +       if (IS_ERR(priv->rtc_dev))
> +               return PTR_ERR(priv->rtc_dev);
> +
> +       priv->rtc_dev->ops = &msc313_rtc_ops;
> +       priv->rtc_dev->range_max = U32_MAX;
> +
> +       ret = devm_request_irq(dev, irq, msc313_rtc_interrupt, IRQF_SHARED,
> +                              dev_name(&pdev->dev), &pdev->dev);
> +       if (ret) {
> +               dev_err(dev, "Could not request IRQ\n");
> +               return ret;
> +       }
> +
> +       priv->clk = devm_clk_get(dev, NULL);
> +       if (IS_ERR(priv->clk)) {
> +               dev_err(dev, "No input reference clock\n");
> +               return PTR_ERR(priv->clk);
> +       }
> +
> +       ret = clk_prepare_enable(priv->clk);
> +       if (ret) {
> +               dev_err(dev, "Failed to enable the reference clock, %d\n", ret);
> +               return ret;
> +       }
> +
> +       ret = devm_add_action_or_reset(dev, (void (*) (void *))clk_disable_unprepare, priv->clk);
> +       if (ret)
> +               return ret;
> +
> +       rate = clk_get_rate(priv->clk);
> +       writew(rate & 0xFFFF, priv->rtc_base + REG_RTC_FREQ_CW_L);
> +       writew((rate >> 16) & 0xFFFF, priv->rtc_base + REG_RTC_FREQ_CW_H);
> +
> +       platform_set_drvdata(pdev, priv);
> +
> +       return devm_rtc_register_device(priv->rtc_dev);
> +}
> +
> +static const struct of_device_id msc313_rtc_of_match_table[] = {
> +       { .compatible = "mstar,msc313-rtc" },
> +       { }
> +};
> +MODULE_DEVICE_TABLE(of, ms_rtc_of_match_table);

msc313_rtc_of_match_table ?

> +
> +static struct platform_driver msc313_rtc_driver = {
> +       .probe = msc313_rtc_probe,
> +       .driver = {
> +               .name = "msc313-rtc",
> +               .of_match_table = msc313_rtc_of_match_table,
> +       },
> +};
> +
> +module_platform_driver(msc313_rtc_driver);
> +
> +MODULE_AUTHOR("Daniel Palmer <daniel@thingy.jp>");
> +MODULE_AUTHOR("Romain Perier <romain.perier@gmail.com>");
> +MODULE_DESCRIPTION("MStar RTC Driver");
> +MODULE_LICENSE("GPL v2");
> --
> 2.30.2
>

Best regards,
  Nobuhiro

-- 
Nobuhiro Iwamatsu
   iwamatsu at {nigauri.org / debian.org / kernel.org}
   GPG ID: 40AD1FA6

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

  reply	other threads:[~2021-08-23  7:29 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-08-19 17:02 [PATCH v3 0/3] Add RTC for MStar SoCs Romain Perier
2021-08-19 17:02 ` Romain Perier
2021-08-19 17:02 ` [PATCH v3 1/3] dt-bindings: rtc: Add Mstar MSC313e RTC devicetree bindings documentation Romain Perier
2021-08-19 17:02   ` Romain Perier
2021-08-19 17:03 ` [PATCH v3 2/3] rtc: Add support for the MSTAR MSC313 RTC Romain Perier
2021-08-19 17:03   ` Romain Perier
2021-08-23  7:28   ` Nobuhiro Iwamatsu [this message]
2021-08-23  7:28     ` Nobuhiro Iwamatsu
2021-08-19 17:03 ` [PATCH v3 3/3] ARM: dts: mstar: Add rtc device node Romain Perier
2021-08-19 17:03   ` Romain Perier

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='CABMQnVJwFf4nX6ApdobBnwfzmWSsYHcabFqZd8rUQw=T7V=vcA@mail.gmail.com' \
    --to=iwamatsu@nigauri.org \
    --cc=a.zummo@towertech.it \
    --cc=alexandre.belloni@bootlin.com \
    --cc=daniel@0x0f.com \
    --cc=devicetree@vger.kernel.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-rtc@vger.kernel.org \
    --cc=robh+dt@kernel.org \
    --cc=romain.perier@gmail.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.