From: Alexandre Belloni <alexandre.belloni@bootlin.com>
To: Shubhi Garg <shgarg@nvidia.com>
Cc: lee@kernel.org, thierry.reding@gmail.com, jonathanh@nvidia.com,
devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-tegra@vger.kernel.org
Subject: Re: [PATCH 4/5] rtc: nvvrs: add NVIDIA VRS PSEQ RTC device driver
Date: Wed, 16 Apr 2025 16:20:13 +0200 [thread overview]
Message-ID: <2025041613211528675cb8@mail.local> (raw)
In-Reply-To: <20250416120619.483793-5-shgarg@nvidia.com>
Hello,
On 16/04/2025 12:06:18+0000, Shubhi Garg wrote:
> Add support for NVIDIA VRS (Voltage Regulator Specification) Power
> Sequencer RTC device driver. This RTC can be used to get/set system
> time, retain system time across boot, wake system from suspend and
> shutdown state.
>
> Signed-off-by: Shubhi Garg <shgarg@nvidia.com>
> ---
> drivers/rtc/Kconfig | 10 +
> drivers/rtc/Makefile | 1 +
> drivers/rtc/rtc-nvidia-vrs-pseq.c | 559 ++++++++++++++++++++++++++++++
> 3 files changed, 570 insertions(+)
> create mode 100644 drivers/rtc/rtc-nvidia-vrs-pseq.c
>
> diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
> index 838bdc138ffe..3b6dc27a50af 100644
> --- a/drivers/rtc/Kconfig
> +++ b/drivers/rtc/Kconfig
> @@ -406,6 +406,16 @@ config RTC_DRV_MAX77686
> This driver can also be built as a module. If so, the module
> will be called rtc-max77686.
>
> +config RTC_DRV_NVVRS_PSEQ
> + tristate "NVIDIA VRS Power Sequencer RTC device"
> + depends on MFD_NVVRS_PSEQ
> + help
> + If you say yes here you will get support for the battery backed RTC device
> + of NVIDIA VRS Power Sequencer. The RTC is connected via I2C interface and
> + supports alarm functionality.
> + This driver can also be built as a module. If so, the module will be called
> + rtc-nvidia-vrs-pseq.
> +
> config RTC_DRV_NCT3018Y
> tristate "Nuvoton NCT3018Y"
> depends on OF
> diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
> index 31473b3276d9..543c5a9fe851 100644
> --- a/drivers/rtc/Makefile
> +++ b/drivers/rtc/Makefile
> @@ -119,6 +119,7 @@ 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_NTXEC) += rtc-ntxec.o
> +obj-$(CONFIG_RTC_DRV_NVVRS_PSEQ)+= rtc-nvidia-vrs-pseq.o
> obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o
> obj-$(CONFIG_RTC_DRV_OPAL) += rtc-opal.o
> obj-$(CONFIG_RTC_DRV_OPTEE) += rtc-optee.o
> diff --git a/drivers/rtc/rtc-nvidia-vrs-pseq.c b/drivers/rtc/rtc-nvidia-vrs-pseq.c
> new file mode 100644
> index 000000000000..1a4194e4edf4
> --- /dev/null
> +++ b/drivers/rtc/rtc-nvidia-vrs-pseq.c
> @@ -0,0 +1,559 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
How old is this driver actually, it uses decades old APIs :)
> + *
> + * RTC driver for NVIDIA Voltage Regulator Power Sequencer
> + *
> + */
> +
> +#include <linux/i2c.h>
> +#include <linux/init.h>
> +#include <linux/slab.h>
> +#include <linux/rtc.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/platform_device.h>
> +#include <linux/of_device.h>
> +#include <linux/mfd/nvidia-vrs-pseq.h>
> +#include <linux/irqdomain.h>
> +#include <linux/regmap.h>
> +#include <linux/bits.h>
> +
> +#define ALARM_RESET_VAL 0xFFFFFFFF /* Alarm reset/disable value */
> +#define NVVRS_INT_RTC_INDEX 0 /* Only one RTC interrupt register */
> +#define REG_LEN_IN_BYTES 4
> +
> +struct nvvrs_rtc_info {
> + struct device *dev;
> + struct i2c_client *client;
> + struct rtc_device *rtc_dev;
> + struct regmap *regmap;
So you have a regmap but never use it?
> + struct regmap_irq_chip_data *rtc_irq_data;
> + /* Mutex to protect RTC operations */
> + struct mutex lock;
This lock is useless, simply use rtc_lock/rtc_unlock in your irq handler
> + unsigned int rtc_irq;
> + /* Registers offset to I2C addresses map */
> + const u8 *map;
I don't get how this indirection is useful
> + /* RTC IRQ CHIP */
> + const struct regmap_irq_chip *rtc_irq_chip;
> +};
> +
> +/* RTC Registers offsets */
> +enum nvvrs_rtc_reg_offset {
> + RTC_T3 = 0,
> + RTC_T2,
> + RTC_T1,
> + RTC_T0,
> + RTC_A3,
> + RTC_A2,
> + RTC_A1,
> + RTC_A0,
> + CTL1_REG,
> + CTL2_REG,
> + RTC_END,
> +};
> +
> +static const struct regmap_irq nvvrs_rtc_irq[] = {
> + REGMAP_IRQ_REG(NVVRS_INT_RTC_INDEX, 0, NVVRS_PSEQ_INT_SRC1_RTC_MASK),
> +};
> +
> +static const struct regmap_irq_chip nvvrs_rtc_irq_chip = {
> + .name = "nvvrs-rtc",
> + .status_base = NVVRS_PSEQ_REG_INT_SRC1,
> + .num_regs = 1,
> + .irqs = nvvrs_rtc_irq,
> + .num_irqs = ARRAY_SIZE(nvvrs_rtc_irq),
> +};
> +
> +static const u8 rtc_map[RTC_END] = {
> + [RTC_T3] = NVVRS_PSEQ_REG_RTC_T3,
> + [RTC_T2] = NVVRS_PSEQ_REG_RTC_T2,
> + [RTC_T1] = NVVRS_PSEQ_REG_RTC_T1,
> + [RTC_T0] = NVVRS_PSEQ_REG_RTC_T0,
> + [RTC_A3] = NVVRS_PSEQ_REG_RTC_A3,
> + [RTC_A2] = NVVRS_PSEQ_REG_RTC_A2,
> + [RTC_A1] = NVVRS_PSEQ_REG_RTC_A1,
> + [RTC_A0] = NVVRS_PSEQ_REG_RTC_A0,
> + [CTL1_REG] = NVVRS_PSEQ_REG_CTL_1,
> + [CTL2_REG] = NVVRS_PSEQ_REG_CTL_2,
> +};
> +
> +static int nvvrs_update_bits(struct nvvrs_rtc_info *info, u8 reg,
> + u8 mask, u8 value)
> +{
> + int ret;
> + u8 val;
> +
> + ret = i2c_smbus_read_byte_data(info->client, reg);
> + if (ret < 0) {
> + dev_err(info->dev, "Failed to read reg:0x%02x ret:(%d)\n",
> + reg, ret);
The driver is too verbose, you have plenty of dev_err that are very
unlikely to happen and that have no impact on the user actions but those
strings will always be bloating the kernel.
> + return ret;
> + }
> + val = (u8)ret;
> + val &= ~mask;
> + val |= (value & mask);
> +
> + ret = i2c_smbus_write_byte_data(info->client, reg, val);
> + if (ret < 0)
> + dev_err(info->dev, "Failed to write reg:0x%02x val:0x%02x ret:(%d)\n",
> + reg, val, ret);
> +
> + return ret;
> +}
> +
> +static int nvvrs_rtc_update_alarm_reg(struct i2c_client *client,
> + struct nvvrs_rtc_info *info, u8 *time)
> +{
> + int ret;
> +
> + ret = i2c_smbus_write_byte_data(client, info->map[RTC_A3], time[3]);
> + if (ret < 0) {
> + dev_err(info->dev, "Failed to write alarm reg: 0x%02x ret:(%d)\n",
> + info->map[RTC_A3], ret);
> + goto out;
> + }
> +
> + ret = i2c_smbus_write_byte_data(client, info->map[RTC_A2], time[2]);
> + if (ret < 0) {
> + dev_err(info->dev, "Failed to write alarm reg: 0x%02x ret:(%d)\n",
> + info->map[RTC_A2], ret);
> + goto out;
> + }
> +
> + ret = i2c_smbus_write_byte_data(client, info->map[RTC_A1], time[1]);
> + if (ret < 0) {
> + dev_err(info->dev, "Failed to write alarm reg: 0x%02x ret:(%d)\n",
> + info->map[RTC_A1], ret);
> + goto out;
> + }
> +
> + ret = i2c_smbus_write_byte_data(client, info->map[RTC_A0], time[0]);
> + if (ret < 0) {
> + dev_err(info->dev, "Failed to write alarm reg: 0x%02x ret:(%d)\n",
> + info->map[RTC_A0], ret);
> + goto out;
> + }
> +
> +out:
> + return ret;
> +}
> +
> +static int nvvrs_rtc_enable_alarm(struct nvvrs_rtc_info *info)
> +{
> + int ret;
> +
> + /* Set RTC_WAKE bit for autonomous wake from sleep */
> + ret = nvvrs_update_bits(info, info->map[CTL2_REG],
> + NVVRS_PSEQ_REG_CTL_2_RTC_WAKE,
> + NVVRS_PSEQ_REG_CTL_2_RTC_WAKE);
> + if (ret < 0) {
> + dev_err(info->dev, "Failed to set RTC_WAKE bit (%d)\n", ret);
> + return ret;
> + }
> +
> + /* Set RTC_PU bit for autonomous wake from shutdown */
> + ret = nvvrs_update_bits(info, info->map[CTL2_REG],
> + NVVRS_PSEQ_REG_CTL_2_RTC_PU,
> + NVVRS_PSEQ_REG_CTL_2_RTC_PU);
> + if (ret < 0) {
> + dev_err(info->dev, "Failed to set RTC_PU bit (%d)\n", ret);
> + return ret;
> + }
> +
> + return ret;
> +}
> +
> +static int nvvrs_rtc_disable_alarm(struct nvvrs_rtc_info *info)
> +{
> + struct i2c_client *client = info->client;
> + u8 val[REG_LEN_IN_BYTES];
> + int ret;
> +
> + /* Clear RTC_WAKE bit */
> + ret = nvvrs_update_bits(info, info->map[CTL2_REG],
> + NVVRS_PSEQ_REG_CTL_2_RTC_WAKE, 0);
> + if (ret < 0) {
> + dev_err(info->dev, "Failed to clear RTC_WAKE bit (%d)\n", ret);
> + goto out;
> + }
> +
> + /* Clear RTC_PU bit */
> + ret = nvvrs_update_bits(info, info->map[CTL2_REG],
> + NVVRS_PSEQ_REG_CTL_2_RTC_PU, 0);
> + if (ret < 0) {
> + dev_err(info->dev, "Failed to clear RTC_PU bit (%d)\n", ret);
> + goto out;
> + }
> +
> + /* Write ALARM_RESET_VAL in RTC Alarm register to disable alarm */
> + val[0] = 0xff;
> + val[1] = 0xff;
> + val[2] = 0xff;
> + val[3] = 0xff;
> +
> + ret = nvvrs_rtc_update_alarm_reg(client, info, val);
> + if (ret < 0) {
> + dev_err(info->dev, "Failed to disable Alarm (%d)\n", ret);
> + goto out;
> + }
> +out:
> + return ret;
> +}
> +
> +static irqreturn_t nvvrs_rtc_irq_handler(int irq, void *data)
> +{
> + struct nvvrs_rtc_info *info = data;
> +
> + dev_dbg(info->dev, "RTC alarm IRQ: %d\n", irq);
> +
> + rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_AF);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static int nvvrs_rtc_read_time(struct device *dev, struct rtc_time *tm)
> +{
> + struct nvvrs_rtc_info *info = dev_get_drvdata(dev);
> + struct i2c_client *client = info->client;
> + time64_t secs = 0;
> + int ret;
> + u8 val;
> +
> + mutex_lock(&info->lock);
> +
> + /* Multi-byte transfers are not supported with PEC enabled */
> + /* Read MSB first to avoid coherency issues */
> + ret = i2c_smbus_read_byte_data(client, info->map[RTC_T3]);
> + if (ret < 0) {
> + dev_err(info->dev, "Failed to read time reg:0x%02x ret:(%d)\n",
> + info->map[RTC_T3], ret);
> + goto out;
> + }
> + val = (u8)ret;
> + secs |= (time64_t)val << 24;
> +
> + ret = i2c_smbus_read_byte_data(client, info->map[RTC_T2]);
> + if (ret < 0) {
> + dev_err(info->dev, "Failed to read time reg:0x%02x ret:(%d)\n",
> + info->map[RTC_T2], ret);
> + goto out;
> + }
> + val = (u8)ret;
> + secs |= (time64_t)val << 16;
> +
> + ret = i2c_smbus_read_byte_data(client, info->map[RTC_T1]);
> + if (ret < 0) {
> + dev_err(info->dev, "Failed to read time reg:0x%02x ret:(%d)\n",
> + info->map[RTC_T1], ret);
> + goto out;
> + }
> + val = (u8)ret;
> + secs |= (time64_t)val << 8;
> +
> + ret = i2c_smbus_read_byte_data(client, info->map[RTC_T0]);
> + if (ret < 0) {
> + dev_err(info->dev, "Failed to read time reg:0x%02x ret:(%d)\n",
> + info->map[RTC_T0], ret);
> + goto out;
> + }
> + val = (u8)ret;
> + secs |= val;
> +
> + rtc_time64_to_tm(secs, tm);
> +out:
> + mutex_unlock(&info->lock);
> + return ret;
> +}
> +
> +static int nvvrs_rtc_set_time(struct device *dev, struct rtc_time *tm)
> +{
> + struct nvvrs_rtc_info *info = dev_get_drvdata(dev);
> + struct i2c_client *client = info->client;
> + u8 time[REG_LEN_IN_BYTES];
> + time64_t secs;
> + int ret;
> +
> + mutex_lock(&info->lock);
> +
> + secs = rtc_tm_to_time64(tm);
> + time[0] = secs & 0xff;
> + time[1] = (secs >> 8) & 0xff;
> + time[2] = (secs >> 16) & 0xff;
> + time[3] = (secs >> 24) & 0xff;
> +
> + ret = i2c_smbus_write_byte_data(client, info->map[RTC_T3], time[3]);
> + if (ret < 0) {
> + dev_err(info->dev, "Failed to write time reg: 0x%02x ret:(%d)\n",
> + info->map[RTC_T3], ret);
> + goto out;
> + }
> +
> + ret = i2c_smbus_write_byte_data(client, info->map[RTC_T2], time[2]);
> + if (ret < 0) {
> + dev_err(info->dev, "Failed to write time reg: 0x%02x ret:(%d)\n",
> + info->map[RTC_T2], ret);
> + goto out;
> + }
> +
> + ret = i2c_smbus_write_byte_data(client, info->map[RTC_T1], time[1]);
> + if (ret < 0) {
> + dev_err(info->dev, "Failed to write time reg: 0x%02x ret:(%d)\n",
> + info->map[RTC_T1], ret);
> + goto out;
> + }
> +
> + ret = i2c_smbus_write_byte_data(client, info->map[RTC_T0], time[0]);
> + if (ret < 0) {
> + dev_err(info->dev, "Failed to write time reg: 0x%02x ret:(%d)\n",
> + info->map[RTC_T0], ret);
> + goto out;
> + }
> +
> +out:
> + mutex_unlock(&info->lock);
> + return ret;
> +}
> +
> +static int nvvrs_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
> +{
> + struct nvvrs_rtc_info *info = dev_get_drvdata(dev);
> + struct i2c_client *client = info->client;
> + time64_t alarm_val = 0;
> + int ret;
> + u8 val;
> +
> + mutex_lock(&info->lock);
> +
> + /* Multi-byte transfers are not supported with PEC enabled */
> + ret = i2c_smbus_read_byte_data(client, info->map[RTC_A3]);
> + if (ret < 0) {
> + dev_err(info->dev, "Failed to read alarm reg:0x%02x ret:(%d)\n",
> + info->map[RTC_A3], ret);
> + goto out;
> + }
> + val = (u8)ret;
> + alarm_val |= (time64_t)val << 24;
> +
> + ret = i2c_smbus_read_byte_data(client, info->map[RTC_A2]);
> + if (ret < 0) {
> + dev_err(info->dev, "Failed to read alarm reg:0x%02x ret:(%d)\n",
> + info->map[RTC_A2], ret);
> + goto out;
> + }
> + val = (u8)ret;
> + alarm_val |= (time64_t)val << 16;
> +
> + ret = i2c_smbus_read_byte_data(client, info->map[RTC_A1]);
> + if (ret < 0) {
> + dev_err(info->dev, "Failed to read alarm reg:0x%02x ret:(%d)\n",
> + info->map[RTC_A1], ret);
> + goto out;
> + }
> + val = (u8)ret;
> + alarm_val |= (time64_t)val << 8;
> +
> + ret = i2c_smbus_read_byte_data(client, info->map[RTC_A0]);
> + if (ret < 0) {
> + dev_err(info->dev, "Failed to read alarm reg:0x%02x ret:(%d)\n",
> + info->map[RTC_A0], ret);
> + goto out;
> + }
> + val = (u8)ret;
> + alarm_val |= val;
> +
> + if (alarm_val == ALARM_RESET_VAL)
> + alrm->enabled = 0;
> + else
> + alrm->enabled = 1;
> +
> + rtc_time64_to_tm(alarm_val, &alrm->time);
> +out:
> + mutex_unlock(&info->lock);
> + return ret;
> +}
> +
> +static int nvvrs_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
> +{
> + struct nvvrs_rtc_info *info = dev_get_drvdata(dev);
> + struct i2c_client *client = info->client;
> + u8 time[REG_LEN_IN_BYTES];
> + time64_t secs;
> + int ret;
> +
> + mutex_lock(&info->lock);
> +
> + ret = nvvrs_rtc_enable_alarm(info);
> + if (ret < 0) {
> + dev_err(info->dev, "Failed to enable alarm! (%d)\n", ret);
> + goto out;
> + }
> +
> + secs = rtc_tm_to_time64(&alrm->time);
> + time[0] = secs & 0xff;
> + time[1] = (secs >> 8) & 0xff;
> + time[2] = (secs >> 16) & 0xff;
> + time[3] = (secs >> 24) & 0xff;
> +
> + ret = nvvrs_rtc_update_alarm_reg(client, info, time);
> +
> + alrm->enabled = 1;
> +out:
> + mutex_unlock(&info->lock);
> + return ret;
> +}
> +
> +static int nvvrs_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
> +{
> + struct nvvrs_rtc_info *info = dev_get_drvdata(dev);
> + int ret = 0;
> +
> + mutex_lock(&info->lock);
> + if (enabled)
> + ret = nvvrs_rtc_enable_alarm(info);
> + else
> + ret = nvvrs_rtc_disable_alarm(info);
> +
> + mutex_unlock(&info->lock);
> + return ret;
> +}
> +
> +static const struct rtc_class_ops nvvrs_rtc_ops = {
> + .read_time = nvvrs_rtc_read_time,
> + .set_time = nvvrs_rtc_set_time,
> + .read_alarm = nvvrs_rtc_read_alarm,
> + .set_alarm = nvvrs_rtc_set_alarm,
> + .alarm_irq_enable = nvvrs_rtc_alarm_irq_enable,
> +};
> +
> +static int nvvrs_rtc_probe(struct platform_device *pdev)
> +{
> + struct nvvrs_rtc_info *info;
> + struct device *parent;
> + struct i2c_client *client;
> + int ret;
> +
> + info = devm_kzalloc(&pdev->dev, sizeof(struct nvvrs_rtc_info), GFP_KERNEL);
> + if (!info)
> + return -ENOMEM;
> +
> + ret = platform_get_irq(pdev, 0);
> + if (ret < 0) {
> + dev_err(&pdev->dev, "Failed to get irq\n");
> + return ret;
> + }
> + info->rtc_irq = ret;
> +
> + mutex_init(&info->lock);
> + info->dev = &pdev->dev;
> + parent = info->dev->parent;
> + client = to_i2c_client(parent);
> + client->flags |= I2C_CLIENT_PEC;
> + i2c_set_clientdata(client, info);
> + info->client = client;
> + info->map = rtc_map;
> + info->rtc_irq_chip = &nvvrs_rtc_irq_chip;
> + platform_set_drvdata(pdev, info);
> +
> + /* Initialize regmap */
> + info->regmap = dev_get_regmap(parent, NULL);
> + if (!info->regmap) {
> + dev_err(info->dev, "Failed to get RTC regmap\n");
> + return -ENODEV;
> + }
> +
> + /* RTC as a wakeup source */
> + device_init_wakeup(info->dev, 1);
> +
> + /* Register RTC device */
> + info->rtc_dev = devm_rtc_device_register(info->dev, "nvvrs-rtc",
> + &nvvrs_rtc_ops, THIS_MODULE);
You must use devm_rtc_allocate_device and devm_rtc_register_device,
devm_rtc_allocate_device is deprecated.
You must also set range_min and range_max.
> +
> + if (IS_ERR(info->rtc_dev)) {
> + ret = PTR_ERR(info->rtc_dev);
> + dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
> + return ret;
> + }
> +
> + ret = request_threaded_irq(info->rtc_irq, NULL, nvvrs_rtc_irq_handler, 0,
> + "rtc-alarm", info);
Why don't you use the devm_ version and drop nvvrs_rtc_remove() ?
> + if (ret < 0)
> + dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n",
> + info->rtc_irq, ret);
It is not allowed to fail after registering an rtc_device
> +
> + return ret;
> +}
> +
> +static void nvvrs_rtc_remove(struct platform_device *pdev)
> +{
> + struct nvvrs_rtc_info *info = platform_get_drvdata(pdev);
> +
> + free_irq(info->rtc_irq, info);
> +}
> +
> +#ifdef CONFIG_PM_SLEEP
> +static int nvvrs_rtc_suspend(struct device *dev)
> +{
> + struct nvvrs_rtc_info *info = dev_get_drvdata(dev);
> + int ret = 0;
> +
> + if (device_may_wakeup(dev)) {
> + /* Set RTC_WAKE bit for auto wake system from suspend state */
> + ret = nvvrs_update_bits(info, info->map[CTL2_REG],
> + NVVRS_PSEQ_REG_CTL_2_RTC_WAKE,
> + NVVRS_PSEQ_REG_CTL_2_RTC_WAKE);
> + if (ret < 0) {
> + dev_err(info->dev, "Failed to set RTC_WAKE bit (%d)\n", ret);
> + return ret;
> + }
> +
> + ret = enable_irq_wake(info->rtc_irq);
> + }
> +
> + return ret;
> +}
> +
> +static int nvvrs_rtc_resume(struct device *dev)
> +{
> + struct nvvrs_rtc_info *info = dev_get_drvdata(dev);
> + int ret;
> +
> + if (device_may_wakeup(dev)) {
> + /* Clear FORCE_ACT bit */
> + ret = nvvrs_update_bits(info, info->map[CTL1_REG],
> + NVVRS_PSEQ_REG_CTL_1_FORCE_ACT, 0);
> + if (ret < 0) {
> + dev_err(info->dev, "Failed to clear FORCE_ACT bit (%d)\n", ret);
> + return ret;
> + }
> +
> + return disable_irq_wake(info->rtc_irq);
> + }
> +
> + return 0;
> +}
> +
> +#endif
> +static SIMPLE_DEV_PM_OPS(nvvrs_rtc_pm_ops, nvvrs_rtc_suspend, nvvrs_rtc_resume);
> +
> +static const struct platform_device_id nvvrs_rtc_id[] = {
> + { "nvvrs-pseq-rtc", },
> + { },
> +};
> +MODULE_DEVICE_TABLE(platform, nvvrs_rtc_id);
> +
> +static struct platform_driver nvvrs_rtc_driver = {
> + .driver = {
> + .name = "nvvrs-pseq-rtc",
> + .pm = &nvvrs_rtc_pm_ops,
> + },
> + .probe = nvvrs_rtc_probe,
> + .remove = nvvrs_rtc_remove,
> + .id_table = nvvrs_rtc_id,
> +};
> +
> +module_platform_driver(nvvrs_rtc_driver);
> +
> +MODULE_AUTHOR("Shubhi Garg <shgarg@nvidia.com>");
> +MODULE_DESCRIPTION("NVVRS PSEQ RTC driver");
> +MODULE_LICENSE("GPL");
> --
> 2.25.1
>
--
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
next prev parent reply other threads:[~2025-04-16 14:20 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-04-16 12:06 [PATCH 0/5] Add NVIDIA VRS PSEQ support Shubhi Garg
2025-04-16 12:06 ` [PATCH 1/5] dt-bindings: mfd: add bindings for NVIDIA VRS PSEQ Shubhi Garg
2025-04-21 22:02 ` Rob Herring
2025-04-21 22:03 ` Rob Herring
2025-04-16 12:06 ` [PATCH 2/5] arm64: tegra: Add device-tree node for NVVRS PSEQ Shubhi Garg
2025-04-17 5:25 ` Krzysztof Kozlowski
2025-04-16 12:06 ` [PATCH 3/5] mfd: nvvrs: add NVVRS PSEQ MFD driver Shubhi Garg
2025-04-17 5:26 ` Krzysztof Kozlowski
2025-04-16 12:06 ` [PATCH 4/5] rtc: nvvrs: add NVIDIA VRS PSEQ RTC device driver Shubhi Garg
2025-04-16 14:20 ` Alexandre Belloni [this message]
2025-04-16 12:06 ` [PATCH 5/5] arm64: defconfig: enable NVIDIA VRS PSEQ Shubhi Garg
2025-04-17 5:28 ` Krzysztof Kozlowski
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=2025041613211528675cb8@mail.local \
--to=alexandre.belloni@bootlin.com \
--cc=devicetree@vger.kernel.org \
--cc=jonathanh@nvidia.com \
--cc=lee@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-tegra@vger.kernel.org \
--cc=shgarg@nvidia.com \
--cc=thierry.reding@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.