All of lore.kernel.org
 help / color / mirror / Atom feed
From: Alexandre Belloni <alexandre.belloni@bootlin.com>
To: Ming Yu <a0282524688@gmail.com>
Cc: tmyu0@nuvoton.com, lee@kernel.org, linus.walleij@linaro.org,
	brgl@bgdev.pl, andi.shyti@kernel.org, mkl@pengutronix.de,
	mailhol.vincent@wanadoo.fr, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, wim@linux-watchdog.org, linux@roeck-us.net,
	jdelvare@suse.com, linux-kernel@vger.kernel.org,
	linux-gpio@vger.kernel.org, linux-i2c@vger.kernel.org,
	linux-can@vger.kernel.org, netdev@vger.kernel.org,
	linux-watchdog@vger.kernel.org, linux-hwmon@vger.kernel.org,
	linux-rtc@vger.kernel.org, linux-usb@vger.kernel.org
Subject: Re: [PATCH v7 7/7] rtc: Add Nuvoton NCT6694 RTC support
Date: Tue, 8 Apr 2025 14:54:56 +0200	[thread overview]
Message-ID: <202504081254567e7facbc@mail.local> (raw)
In-Reply-To: <20250207074502.1055111-8-a0282524688@gmail.com>

On 07/02/2025 15:45:02+0800, Ming Yu wrote:
> This driver supports RTC functionality for NCT6694 MFD device
> based on USB interface.
> 
> Signed-off-by: Ming Yu <a0282524688@gmail.com>
Acked-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
> ---
>  MAINTAINERS               |   1 +
>  drivers/rtc/Kconfig       |  10 ++
>  drivers/rtc/Makefile      |   1 +
>  drivers/rtc/rtc-nct6694.c | 286 ++++++++++++++++++++++++++++++++++++++
>  4 files changed, 298 insertions(+)
>  create mode 100644 drivers/rtc/rtc-nct6694.c
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index a9eda4530b07..7eba4ffdc877 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -16927,6 +16927,7 @@ F:	drivers/hwmon/nct6694-hwmon.c
>  F:	drivers/i2c/busses/i2c-nct6694.c
>  F:	drivers/mfd/nct6694.c
>  F:	drivers/net/can/usb/nct6694_canfd.c
> +F:	drivers/rtc/rtc-nct6694.c
>  F:	drivers/watchdog/nct6694_wdt.c
>  F:	include/linux/mfd/nct6694.h
>  
> diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
> index 0bbbf778ecfa..248425bf26f3 100644
> --- a/drivers/rtc/Kconfig
> +++ b/drivers/rtc/Kconfig
> @@ -416,6 +416,16 @@ config RTC_DRV_NCT3018Y
>  	   This driver can also be built as a module, if so, the module will be
>  	   called "rtc-nct3018y".
>  
> +config RTC_DRV_NCT6694
> +	tristate "Nuvoton NCT6694 RTC support"
> +	depends on MFD_NCT6694
> +	help
> +	  If you say yes to this option, support will be included for Nuvoton
> +	  NCT6694, a USB device to RTC.
> +
> +	  This driver can also be built as a module. If so, the module will
> +	  be called rtc-nct6694.
> +
>  config RTC_DRV_RK808
>  	tristate "Rockchip RK805/RK808/RK809/RK817/RK818 RTC"
>  	depends on MFD_RK8XX
> diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
> index 489b4ab07068..d0d6f4a4972e 100644
> --- a/drivers/rtc/Makefile
> +++ b/drivers/rtc/Makefile
> @@ -118,6 +118,7 @@ obj-$(CONFIG_RTC_DRV_MXC)	+= rtc-mxc.o
>  obj-$(CONFIG_RTC_DRV_MXC_V2)	+= rtc-mxc_v2.o
>  obj-$(CONFIG_RTC_DRV_GAMECUBE)	+= rtc-gamecube.o
>  obj-$(CONFIG_RTC_DRV_NCT3018Y)	+= rtc-nct3018y.o
> +obj-$(CONFIG_RTC_DRV_NCT6694)	+= rtc-nct6694.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
> diff --git a/drivers/rtc/rtc-nct6694.c b/drivers/rtc/rtc-nct6694.c
> new file mode 100644
> index 000000000000..892674d453d1
> --- /dev/null
> +++ b/drivers/rtc/rtc-nct6694.c
> @@ -0,0 +1,286 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Nuvoton NCT6694 RTC driver based on USB interface.
> + *
> + * Copyright (C) 2024 Nuvoton Technology Corp.
> + */
> +
> +#include <linux/bcd.h>
> +#include <linux/irqdomain.h>
> +#include <linux/kernel.h>
> +#include <linux/mfd/core.h>
> +#include <linux/mfd/nct6694.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/rtc.h>
> +#include <linux/slab.h>
> +
> +/*
> + * USB command module type for NCT6694 RTC controller.
> + * This defines the module type used for communication with the NCT6694
> + * RTC controller over the USB interface.
> + */
> +#define NCT6694_RTC_MOD		0x08
> +
> +/* Command 00h - RTC Time */
> +#define NCT6694_RTC_TIME	0x0000
> +#define NCT6694_RTC_TIME_SEL	0x00
> +
> +/* Command 01h - RTC Alarm */
> +#define NCT6694_RTC_ALARM	0x01
> +#define NCT6694_RTC_ALARM_SEL	0x00
> +
> +/* Command 02h - RTC Status */
> +#define NCT6694_RTC_STATUS	0x02
> +#define NCT6694_RTC_STATUS_SEL	0x00
> +
> +#define NCT6694_RTC_IRQ_INT_EN	BIT(0)	/* Transmit a USB INT-in when RTC alarm */
> +#define NCT6694_RTC_IRQ_GPO_EN	BIT(5)	/* Trigger a GPO Low Pulse when RTC alarm */
> +
> +#define NCT6694_RTC_IRQ_EN	(NCT6694_RTC_IRQ_INT_EN | NCT6694_RTC_IRQ_GPO_EN)
> +#define NCT6694_RTC_IRQ_STS	BIT(0)	/* Write 1 clear IRQ status */
> +
> +struct __packed nct6694_rtc_time {
> +	u8 sec;
> +	u8 min;
> +	u8 hour;
> +	u8 week;
> +	u8 day;
> +	u8 month;
> +	u8 year;
> +};
> +
> +struct __packed nct6694_rtc_alarm {
> +	u8 sec;
> +	u8 min;
> +	u8 hour;
> +	u8 alarm_en;
> +	u8 alarm_pend;
> +};
> +
> +struct __packed nct6694_rtc_status {
> +	u8 irq_en;
> +	u8 irq_pend;
> +};
> +
> +union __packed nct6694_rtc_msg {
> +	struct nct6694_rtc_time time;
> +	struct nct6694_rtc_alarm alarm;
> +	struct nct6694_rtc_status sts;
> +};
> +
> +struct nct6694_rtc_data {
> +	struct nct6694 *nct6694;
> +	struct rtc_device *rtc;
> +	union nct6694_rtc_msg *msg;
> +};
> +
> +static int nct6694_rtc_read_time(struct device *dev, struct rtc_time *tm)
> +{
> +	struct nct6694_rtc_data *data = dev_get_drvdata(dev);
> +	struct nct6694_rtc_time *time = &data->msg->time;
> +	static const struct nct6694_cmd_header cmd_hd = {
> +		.mod = NCT6694_RTC_MOD,
> +		.cmd = NCT6694_RTC_TIME,
> +		.sel = NCT6694_RTC_TIME_SEL,
> +		.len = cpu_to_le16(sizeof(*time))
> +	};
> +	int ret;
> +
> +	ret = nct6694_read_msg(data->nct6694, &cmd_hd, time);
> +	if (ret)
> +		return ret;
> +
> +	tm->tm_sec = bcd2bin(time->sec);		/* tm_sec expect 0 ~ 59 */
> +	tm->tm_min = bcd2bin(time->min);		/* tm_min expect 0 ~ 59 */
> +	tm->tm_hour = bcd2bin(time->hour);		/* tm_hour expect 0 ~ 23 */
> +	tm->tm_wday = bcd2bin(time->week) - 1;		/* tm_wday expect 0 ~ 6 */
> +	tm->tm_mday = bcd2bin(time->day);		/* tm_mday expect 1 ~ 31 */
> +	tm->tm_mon = bcd2bin(time->month) - 1;		/* tm_month expect 0 ~ 11 */
> +	tm->tm_year = bcd2bin(time->year) + 100;	/* tm_year expect since 1900 */
> +
> +	return ret;
> +}
> +
> +static int nct6694_rtc_set_time(struct device *dev, struct rtc_time *tm)
> +{
> +	struct nct6694_rtc_data *data = dev_get_drvdata(dev);
> +	struct nct6694_rtc_time *time = &data->msg->time;
> +	static const struct nct6694_cmd_header cmd_hd = {
> +		.mod = NCT6694_RTC_MOD,
> +		.cmd = NCT6694_RTC_TIME,
> +		.sel = NCT6694_RTC_TIME_SEL,
> +		.len = cpu_to_le16(sizeof(*time))
> +	};
> +
> +	time->sec = bin2bcd(tm->tm_sec);
> +	time->min = bin2bcd(tm->tm_min);
> +	time->hour = bin2bcd(tm->tm_hour);
> +	time->week = bin2bcd(tm->tm_wday + 1);
> +	time->day = bin2bcd(tm->tm_mday);
> +	time->month = bin2bcd(tm->tm_mon + 1);
> +	time->year = bin2bcd(tm->tm_year - 100);
> +
> +	return nct6694_write_msg(data->nct6694, &cmd_hd, time);
> +}
> +
> +static int nct6694_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
> +{
> +	struct nct6694_rtc_data *data = dev_get_drvdata(dev);
> +	struct nct6694_rtc_alarm *alarm = &data->msg->alarm;
> +	static const struct nct6694_cmd_header cmd_hd = {
> +		.mod = NCT6694_RTC_MOD,
> +		.cmd = NCT6694_RTC_ALARM,
> +		.sel = NCT6694_RTC_ALARM_SEL,
> +		.len = cpu_to_le16(sizeof(*alarm))
> +	};
> +	int ret;
> +
> +	ret = nct6694_read_msg(data->nct6694, &cmd_hd, alarm);
> +	if (ret)
> +		return ret;
> +
> +	alrm->time.tm_sec = bcd2bin(alarm->sec);
> +	alrm->time.tm_min = bcd2bin(alarm->min);
> +	alrm->time.tm_hour = bcd2bin(alarm->hour);
> +	alrm->enabled = alarm->alarm_en;
> +	alrm->pending = alarm->alarm_pend;
> +
> +	return ret;
> +}
> +
> +static int nct6694_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
> +{
> +	struct nct6694_rtc_data *data = dev_get_drvdata(dev);
> +	struct nct6694_rtc_alarm *alarm = &data->msg->alarm;
> +	static const struct nct6694_cmd_header cmd_hd = {
> +		.mod = NCT6694_RTC_MOD,
> +		.cmd = NCT6694_RTC_ALARM,
> +		.sel = NCT6694_RTC_ALARM_SEL,
> +		.len = cpu_to_le16(sizeof(*alarm))
> +	};
> +
> +	alarm->sec = bin2bcd(alrm->time.tm_sec);
> +	alarm->min = bin2bcd(alrm->time.tm_min);
> +	alarm->hour = bin2bcd(alrm->time.tm_hour);
> +	alarm->alarm_en = alrm->enabled ? NCT6694_RTC_IRQ_EN : 0;
> +	alarm->alarm_pend = 0;
> +
> +	return nct6694_write_msg(data->nct6694, &cmd_hd, alarm);
> +}
> +
> +static int nct6694_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
> +{
> +	struct nct6694_rtc_data *data = dev_get_drvdata(dev);
> +	struct nct6694_rtc_status *sts = &data->msg->sts;
> +	static const struct nct6694_cmd_header cmd_hd = {
> +		.mod = NCT6694_RTC_MOD,
> +		.cmd = NCT6694_RTC_STATUS,
> +		.sel = NCT6694_RTC_STATUS_SEL,
> +		.len = cpu_to_le16(sizeof(*sts))
> +	};
> +
> +	if (enabled)
> +		sts->irq_en |= NCT6694_RTC_IRQ_EN;
> +	else
> +		sts->irq_en &= ~NCT6694_RTC_IRQ_EN;
> +
> +	sts->irq_pend = 0;
> +
> +	return nct6694_write_msg(data->nct6694, &cmd_hd, sts);
> +}
> +
> +static const struct rtc_class_ops nct6694_rtc_ops = {
> +	.read_time = nct6694_rtc_read_time,
> +	.set_time = nct6694_rtc_set_time,
> +	.read_alarm = nct6694_rtc_read_alarm,
> +	.set_alarm = nct6694_rtc_set_alarm,
> +	.alarm_irq_enable = nct6694_rtc_alarm_irq_enable,
> +};
> +
> +static irqreturn_t nct6694_irq(int irq, void *dev_id)
> +{
> +	struct nct6694_rtc_data *data = dev_id;
> +	struct nct6694_rtc_status *sts = &data->msg->sts;
> +	static const struct nct6694_cmd_header cmd_hd = {
> +		.mod = NCT6694_RTC_MOD,
> +		.cmd = NCT6694_RTC_STATUS,
> +		.sel = NCT6694_RTC_STATUS_SEL,
> +		.len = cpu_to_le16(sizeof(*sts))
> +	};
> +	int ret;
> +
> +	rtc_lock(data->rtc);
> +
> +	sts->irq_en = NCT6694_RTC_IRQ_EN;
> +	sts->irq_pend = NCT6694_RTC_IRQ_STS;
> +	ret = nct6694_write_msg(data->nct6694, &cmd_hd, sts);
> +	if (ret) {
> +		rtc_unlock(data->rtc);
> +		return IRQ_NONE;
> +	}
> +
> +	rtc_update_irq(data->rtc, 1, RTC_IRQF | RTC_AF);
> +
> +	rtc_unlock(data->rtc);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int nct6694_rtc_probe(struct platform_device *pdev)
> +{
> +	struct nct6694_rtc_data *data;
> +	struct nct6694 *nct6694 = dev_get_drvdata(pdev->dev.parent);
> +	int ret, irq;
> +
> +	irq = irq_create_mapping(nct6694->domain, NCT6694_IRQ_RTC);
> +	if (!irq)
> +		return -EINVAL;
> +
> +	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
> +	if (!data)
> +		return -ENOMEM;
> +
> +	data->msg = devm_kzalloc(&pdev->dev, sizeof(union nct6694_rtc_msg),
> +				 GFP_KERNEL);
> +	if (!data->msg)
> +		return -ENOMEM;
> +
> +	data->rtc = devm_rtc_allocate_device(&pdev->dev);
> +	if (IS_ERR(data->rtc))
> +		return PTR_ERR(data->rtc);
> +
> +	data->nct6694 = nct6694;
> +	data->rtc->ops = &nct6694_rtc_ops;
> +	data->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
> +	data->rtc->range_max = RTC_TIMESTAMP_END_2099;
> +
> +	platform_set_drvdata(pdev, data);
> +
> +	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
> +					nct6694_irq, IRQF_ONESHOT,
> +					"rtc-nct6694", data);
> +	if (ret < 0)
> +		return dev_err_probe(&pdev->dev, ret, "Failed to request irq\n");
> +
> +	ret = devm_rtc_register_device(data->rtc);
> +	if (ret)
> +		return ret;
> +
> +	device_init_wakeup(&pdev->dev, true);
> +	return 0;
> +}
> +
> +static struct platform_driver nct6694_rtc_driver = {
> +	.driver = {
> +		.name	= "rtc-nct6694",
> +	},
> +	.probe		= nct6694_rtc_probe,
> +};
> +
> +module_platform_driver(nct6694_rtc_driver);
> +
> +MODULE_DESCRIPTION("USB-RTC driver for NCT6694");
> +MODULE_AUTHOR("Ming Yu <tmyu0@nuvoton.com>");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS("platform:nct6694-rtc");
> -- 
> 2.34.1
> 

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

      reply	other threads:[~2025-04-08 12:55 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-02-07  7:44 [PATCH v7 0/7] Add Nuvoton NCT6694 MFD drivers Ming Yu
2025-02-07  7:44 ` [PATCH v7 1/7] mfd: Add core driver for Nuvoton NCT6694 Ming Yu
2025-02-07 18:36   ` Christophe JAILLET
2025-02-12  2:20     ` Ming Yu
2025-02-07  7:44 ` [PATCH v7 2/7] gpio: Add Nuvoton NCT6694 GPIO support Ming Yu
2025-02-07  7:44 ` [PATCH v7 3/7] i2c: Add Nuvoton NCT6694 I2C support Ming Yu
2025-02-07 19:06   ` Christophe JAILLET
2025-02-12  2:25     ` Ming Yu
2025-02-07  7:44 ` [PATCH v7 4/7] can: Add Nuvoton NCT6694 CANFD support Ming Yu
2025-02-07 12:15   ` Marc Kleine-Budde
2025-02-07 15:00     ` Vincent Mailhol
2025-02-07 15:51       ` Marc Kleine-Budde
2025-02-12  2:58       ` Ming Yu
2025-02-12  2:49     ` Ming Yu
2025-02-28 10:34       ` Marc Kleine-Budde
2025-02-21  8:01     ` Ming Yu
2025-02-21  8:08       ` Marc Kleine-Budde
2025-02-21  8:52         ` Ming Yu
2025-02-07 19:17   ` Christophe JAILLET
2025-02-12  2:59     ` Ming Yu
2025-02-07  7:45 ` [PATCH v7 5/7] watchdog: Add Nuvoton NCT6694 WDT support Ming Yu
2025-02-07 20:30   ` Christophe JAILLET
2025-02-12  2:27     ` Ming Yu
2025-02-07  7:45 ` [PATCH v7 6/7] hwmon: Add Nuvoton NCT6694 HWMON support Ming Yu
2025-02-07  7:45 ` [PATCH v7 7/7] rtc: Add Nuvoton NCT6694 RTC support Ming Yu
2025-04-08 12:54   ` Alexandre Belloni [this message]

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=202504081254567e7facbc@mail.local \
    --to=alexandre.belloni@bootlin.com \
    --cc=a0282524688@gmail.com \
    --cc=andi.shyti@kernel.org \
    --cc=andrew+netdev@lunn.ch \
    --cc=brgl@bgdev.pl \
    --cc=davem@davemloft.net \
    --cc=edumazet@google.com \
    --cc=jdelvare@suse.com \
    --cc=kuba@kernel.org \
    --cc=lee@kernel.org \
    --cc=linus.walleij@linaro.org \
    --cc=linux-can@vger.kernel.org \
    --cc=linux-gpio@vger.kernel.org \
    --cc=linux-hwmon@vger.kernel.org \
    --cc=linux-i2c@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-rtc@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=linux-watchdog@vger.kernel.org \
    --cc=linux@roeck-us.net \
    --cc=mailhol.vincent@wanadoo.fr \
    --cc=mkl@pengutronix.de \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=tmyu0@nuvoton.com \
    --cc=wim@linux-watchdog.org \
    /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.