2020-06-20 22:45:40

by J. Neuschäfer

[permalink] [raw]
Subject: [RFC PATCH 08/10] rtc: New driver for RTC in Netronix embedded controller

With this driver, mainline Linux can keep its time and date in sync with
the vendor kernel.

Advanced functionality like alarm and automatic power-on is not yet
supported.

Signed-off-by: Jonathan Neuschäfer <[email protected]>
---
drivers/rtc/Kconfig | 4 ++
drivers/rtc/Makefile | 1 +
drivers/rtc/rtc-ntxec.c | 115 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 120 insertions(+)
create mode 100644 drivers/rtc/rtc-ntxec.c

diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index b54d87d45c89b..2310d08933f9c 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -1300,6 +1300,10 @@ config RTC_DRV_CROS_EC
This driver can also be built as a module. If so, the module
will be called rtc-cros-ec.

+config RTC_DRV_NTXEC
+ tristate "Netronix embedded controller RTC driver"
+ depends on MFD_NTXEC
+
comment "on-CPU RTC drivers"

config RTC_DRV_ASM9260
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 0721752c6ed4c..8653d04aefa99 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -111,6 +111,7 @@ 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_V2) += rtc-mxc_v2.o
+obj-$(CONFIG_RTC_DRV_NTXEC) += rtc-ntxec.o
obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o
obj-$(CONFIG_RTC_DRV_OPAL) += rtc-opal.o
obj-$(CONFIG_RTC_DRV_PALMAS) += rtc-palmas.o
diff --git a/drivers/rtc/rtc-ntxec.c b/drivers/rtc/rtc-ntxec.c
new file mode 100644
index 0000000000000..44d5a5eedb597
--- /dev/null
+++ b/drivers/rtc/rtc-ntxec.c
@@ -0,0 +1,115 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright 2020 Jonathan Neuschäfer
+
+#include <linux/rtc.h>
+#include <linux/mfd/ntxec.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+
+struct ntxec_rtc {
+ struct device *dev;
+ struct ntxec *ec;
+};
+
+#define NTXEC_WRITE_YEAR 0x10
+#define NTXEC_WRITE_MONTH 0x11
+#define NTXEC_WRITE_DAY 0x12
+#define NTXEC_WRITE_HOUR 0x13
+#define NTXEC_WRITE_MINUTE 0x14
+#define NTXEC_WRITE_SECOND 0x15
+
+#define NTXEC_READ_YM 0x20
+#define NTXEC_READ_DH 0x21
+#define NTXEC_READ_MS 0x22
+
+
+static int ntxec_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct ntxec_rtc *rtc = dev_get_drvdata(dev);
+ int res;
+
+ res = ntxec_read16(rtc->ec, NTXEC_READ_YM);
+ if (res < 0)
+ return res;
+
+ tm->tm_year = (res >> 8) + 100;
+ tm->tm_mon = (res & 0xff) - 1;
+
+ res = ntxec_read16(rtc->ec, NTXEC_READ_DH);
+ if (res < 0)
+ return res;
+
+ tm->tm_mday = res >> 8;
+ tm->tm_hour = res & 0xff;
+
+ res = ntxec_read16(rtc->ec, NTXEC_READ_MS);
+ if (res < 0)
+ return res;
+
+ tm->tm_min = res >> 8;
+ tm->tm_sec = res & 0xff;
+
+ return 0;
+}
+
+static int ntxec_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct ntxec_rtc *rtc = dev_get_drvdata(dev);
+ int res = 0;
+
+ res |= ntxec_write8(rtc->ec, NTXEC_WRITE_YEAR, tm->tm_year - 100);
+ res |= ntxec_write8(rtc->ec, NTXEC_WRITE_MONTH, tm->tm_mon + 1);
+ res |= ntxec_write8(rtc->ec, NTXEC_WRITE_DAY, tm->tm_mday);
+ res |= ntxec_write8(rtc->ec, NTXEC_WRITE_HOUR, tm->tm_hour);
+ res |= ntxec_write8(rtc->ec, NTXEC_WRITE_MINUTE, tm->tm_min);
+ res |= ntxec_write8(rtc->ec, NTXEC_WRITE_SECOND, tm->tm_sec);
+
+ return (res < 0)? -EIO : 0;
+}
+
+static const struct rtc_class_ops ntxec_rtc_ops = {
+ .read_time = ntxec_read_time,
+ .set_time = ntxec_set_time,
+};
+
+static int ntxec_rtc_probe(struct platform_device *pdev)
+{
+ struct rtc_device *rtcdev;
+ struct ntxec_rtc *rtc;
+
+ rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
+ if (!rtc)
+ return -ENOMEM;
+
+ rtc->dev = &pdev->dev;
+ rtc->ec = dev_get_drvdata(pdev->dev.parent);
+ platform_set_drvdata(pdev, rtc);
+
+ rtcdev = devm_rtc_device_register(&pdev->dev, "ntxec-rtc",
+ &ntxec_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtcdev))
+ return PTR_ERR(rtc);
+
+ return 0;
+}
+
+static const struct of_device_id ntxec_rtc_of_match[] = {
+ { .compatible = "netronix,ntxec-rtc" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, ntxec_rtc_of_match);
+
+static struct platform_driver ntxec_rtc_driver = {
+ .driver = {
+ .name = "ntxec-rtc",
+ .of_match_table = ntxec_rtc_of_match,
+ },
+ .probe = ntxec_rtc_probe,
+};
+module_platform_driver(ntxec_rtc_driver);
+
+MODULE_AUTHOR("Jonathan Neuschäfer <[email protected]>");
+MODULE_DESCRIPTION("RTC driver for Netronix EC");
+MODULE_LICENSE("GPL");
--
2.27.0


2020-06-21 00:13:42

by Alexandre Belloni

[permalink] [raw]
Subject: Re: [RFC PATCH 08/10] rtc: New driver for RTC in Netronix embedded controller

On 21/06/2020 00:42:19+0200, Jonathan Neusch?fer wrote:
> With this driver, mainline Linux can keep its time and date in sync with
> the vendor kernel.
>
> Advanced functionality like alarm and automatic power-on is not yet
> supported.
>

Please report the results of rtctest (from the kernel tree) and
rtc-range
(https://git.kernel.org/pub/scm/linux/kernel/git/abelloni/rtc-tools.git/tree/rtc-range.c)

> Signed-off-by: Jonathan Neusch?fer <[email protected]>
> ---
> drivers/rtc/Kconfig | 4 ++
> drivers/rtc/Makefile | 1 +
> drivers/rtc/rtc-ntxec.c | 115 ++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 120 insertions(+)
> create mode 100644 drivers/rtc/rtc-ntxec.c
>
> diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
> index b54d87d45c89b..2310d08933f9c 100644
> --- a/drivers/rtc/Kconfig
> +++ b/drivers/rtc/Kconfig
> @@ -1300,6 +1300,10 @@ config RTC_DRV_CROS_EC
> This driver can also be built as a module. If so, the module
> will be called rtc-cros-ec.
>
> +config RTC_DRV_NTXEC
> + tristate "Netronix embedded controller RTC driver"
> + depends on MFD_NTXEC
> +

This should get an help section.


> comment "on-CPU RTC drivers"
>
> config RTC_DRV_ASM9260
> diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
> index 0721752c6ed4c..8653d04aefa99 100644
> --- a/drivers/rtc/Makefile
> +++ b/drivers/rtc/Makefile
> @@ -111,6 +111,7 @@ 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_V2) += rtc-mxc_v2.o
> +obj-$(CONFIG_RTC_DRV_NTXEC) += rtc-ntxec.o
> obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o
> obj-$(CONFIG_RTC_DRV_OPAL) += rtc-opal.o
> obj-$(CONFIG_RTC_DRV_PALMAS) += rtc-palmas.o
> diff --git a/drivers/rtc/rtc-ntxec.c b/drivers/rtc/rtc-ntxec.c
> new file mode 100644
> index 0000000000000..44d5a5eedb597
> --- /dev/null
> +++ b/drivers/rtc/rtc-ntxec.c
> @@ -0,0 +1,115 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +// Copyright 2020 Jonathan Neusch?fer
> +
> +#include <linux/rtc.h>
> +#include <linux/mfd/ntxec.h>
> +#include <linux/platform_device.h>
> +#include <linux/types.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>

Please sort the includes.

> +
> +struct ntxec_rtc {
> + struct device *dev;
> + struct ntxec *ec;
> +};
> +
> +#define NTXEC_WRITE_YEAR 0x10
> +#define NTXEC_WRITE_MONTH 0x11
> +#define NTXEC_WRITE_DAY 0x12
> +#define NTXEC_WRITE_HOUR 0x13
> +#define NTXEC_WRITE_MINUTE 0x14
> +#define NTXEC_WRITE_SECOND 0x15
> +
> +#define NTXEC_READ_YM 0x20
> +#define NTXEC_READ_DH 0x21
> +#define NTXEC_READ_MS 0x22
> +
> +
> +static int ntxec_read_time(struct device *dev, struct rtc_time *tm)
> +{
> + struct ntxec_rtc *rtc = dev_get_drvdata(dev);
> + int res;
> +
> + res = ntxec_read16(rtc->ec, NTXEC_READ_YM);
> + if (res < 0)
> + return res;
> +
> + tm->tm_year = (res >> 8) + 100;
> + tm->tm_mon = (res & 0xff) - 1;
> +
> + res = ntxec_read16(rtc->ec, NTXEC_READ_DH);
> + if (res < 0)
> + return res;
> +
> + tm->tm_mday = res >> 8;
> + tm->tm_hour = res & 0xff;
> +
> + res = ntxec_read16(rtc->ec, NTXEC_READ_MS);
> + if (res < 0)
> + return res;
> +
> + tm->tm_min = res >> 8;
> + tm->tm_sec = res & 0xff;
> +
> + return 0;
> +}
> +
> +static int ntxec_set_time(struct device *dev, struct rtc_time *tm)
> +{
> + struct ntxec_rtc *rtc = dev_get_drvdata(dev);
> + int res = 0;
> +
> + res |= ntxec_write8(rtc->ec, NTXEC_WRITE_YEAR, tm->tm_year - 100);
> + res |= ntxec_write8(rtc->ec, NTXEC_WRITE_MONTH, tm->tm_mon + 1);
> + res |= ntxec_write8(rtc->ec, NTXEC_WRITE_DAY, tm->tm_mday);
> + res |= ntxec_write8(rtc->ec, NTXEC_WRITE_HOUR, tm->tm_hour);
> + res |= ntxec_write8(rtc->ec, NTXEC_WRITE_MINUTE, tm->tm_min);
> + res |= ntxec_write8(rtc->ec, NTXEC_WRITE_SECOND, tm->tm_sec);
> +
> + return (res < 0)? -EIO : 0;
> +}
> +
> +static const struct rtc_class_ops ntxec_rtc_ops = {
> + .read_time = ntxec_read_time,
> + .set_time = ntxec_set_time,
> +};
> +
> +static int ntxec_rtc_probe(struct platform_device *pdev)
> +{
> + struct rtc_device *rtcdev;
> + struct ntxec_rtc *rtc;
> +
> + rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
> + if (!rtc)
> + return -ENOMEM;
> +
> + rtc->dev = &pdev->dev;
> + rtc->ec = dev_get_drvdata(pdev->dev.parent);
> + platform_set_drvdata(pdev, rtc);
> +
> + rtcdev = devm_rtc_device_register(&pdev->dev, "ntxec-rtc",
> + &ntxec_rtc_ops, THIS_MODULE);

Please use devm_rtc_allocate_device and rtc_register_device. Also, set
the supported range (->range_min and ->range_max).


--
Alexandre Belloni, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

2020-07-04 19:27:16

by J. Neuschäfer

[permalink] [raw]
Subject: Re: [RFC PATCH 08/10] rtc: New driver for RTC in Netronix embedded controller

Hi,

On Sun, Jun 21, 2020 at 02:11:06AM +0200, Alexandre Belloni wrote:
> On 21/06/2020 00:42:19+0200, Jonathan Neuschäfer wrote:
> > With this driver, mainline Linux can keep its time and date in sync with
> > the vendor kernel.
> >
> > Advanced functionality like alarm and automatic power-on is not yet
> > supported.
> >
>
> Please report the results of rtctest (from the kernel tree) [...]

# ./rtctest
[==========] Running 7 tests from 2 test cases.
[ RUN ] rtc.date_read
../../tools/testing/selftests/rtc/rtctest.c:49:date_read:Current RTC date/time is 11/04/2006 23:11:23.
[ OK ] rtc.date_read
[ RUN ] rtc.uie_read
[ 180.651355] random: crng init done
uie_read: Test terminated by timeout
[ FAIL ] rtc.uie_read
[ RUN ] rtc.uie_select
../../tools/testing/selftests/rtc/rtctest.c:98:uie_select:Expected 0 (0) != rc (0)
uie_select: Test terminated by assertion
[ FAIL ] rtc.uie_select
[ RUN ] rtc.alarm_alm_set
../../tools/testing/selftests/rtc/rtctest.c:129:alarm_alm_set:skip alarms are not supported.
[ OK ] rtc.alarm_alm_set
[ RUN ] rtc.alarm_wkalm_set
../../tools/testing/selftests/rtc/rtctest.c:185:alarm_wkalm_set:skip alarms are not supported.
[ OK ] rtc.alarm_wkalm_set
[ RUN ] rtc.alarm_alm_set_minute
../../tools/testing/selftests/rtc/rtctest.c:231:alarm_alm_set_minute:skip alarms are not supported.
[ OK ] rtc.alarm_alm_set_minute
[ RUN ] rtc.alarm_wkalm_set_minute
../../tools/testing/selftests/rtc/rtctest.c:287:alarm_wkalm_set_minute:skip alarms are not supported.
[ OK ] rtc.alarm_wkalm_set_minute
[==========] 5 / 7 tests passed.
[ FAILED ]

> [...] and rtc-range
> (https://git.kernel.org/pub/scm/linux/kernel/git/abelloni/rtc-tools.git/tree/rtc-range.c)

# ./rtc-range

Testing 1970-01-01 00:00:00.
KO Read back 2226-01-01 00:01:00.

Testing 2000-02-28 23:59:59.
KO Read back 2000-02-28 23:28:23.

Testing 2020-02-28 23:59:59.
KO Read back 2020-02-28 23:28:23.

Testing 2038-01-19 03:14:07.
KO Read back 2038-01-19 03:19:03.

Testing 2069-12-31 23:59:59.
KO Read back 2069-12-31 23:31:23.

Testing 2079-12-31 23:59:59.
KO Read back 2079-12-31 23:31:23.

Testing 2099-12-31 23:59:59.
KO Read back 2099-12-31 23:31:23.

Testing 2255-12-31 23:59:59.
KO Read back 2255-12-31 23:31:23.

Testing 2100-02-28 23:59:59.
KO Read back 2100-02-28 23:28:23.

Testing 2106-02-07 06:28:15.
KO Read back 2106-02-07 06:07:06.

Testing 2262-04-11 23:47:16.
KO Read back 2006-04-11 23:11:23.


Something is very wrong here.

I'll try to fix the failures in rtctest and the problems in rtc-range
before version 2 of the patchset.

(The 2255 date was my addition, because I suspect this to be the upper
limit of the RTC's range.)


[...]
> > +config RTC_DRV_NTXEC
> > + tristate "Netronix embedded controller RTC driver"
> > + depends on MFD_NTXEC
> > +
>
> This should get an help section.

Ok, I'll add one.


[...]
> > +#include <linux/rtc.h>
> > +#include <linux/mfd/ntxec.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/types.h>
> > +#include <linux/module.h>
> > +#include <linux/of_device.h>
>
> Please sort the includes.

Will do.


[...]
> > + rtcdev = devm_rtc_device_register(&pdev->dev, "ntxec-rtc",
> > + &ntxec_rtc_ops, THIS_MODULE);
>
> Please use devm_rtc_allocate_device and rtc_register_device. Also, set
> the supported range (->range_min and ->range_max).

Ok, will do.


Thanks for the review and the testing tips.
Jonathan Neuschäfer


Attachments:
(No filename) (3.64 kB)
signature.asc (849.00 B)
Download all attachments