From 581d6d8f483696ff164f52a71beb43a87b718592 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Wed, 13 Apr 2022 18:17:30 -0500 Subject: rtc: sun6i: Add NVMEM provider The sun6i RTC provides 32 bytes of general-purpose data registers. They can be used to save data in the always-on RTC power domain. The registers are writable via 32-bit MMIO accesses only. Expose them with a NVMEM provider so they can be used by other drivers. Signed-off-by: Samuel Holland Acked-by: Jernej Skrabec Signed-off-by: Alexandre Belloni Link: https://lore.kernel.org/r/20220413231731.56709-1-samuel@sholland.org --- drivers/rtc/rtc-sun6i.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'drivers/rtc/rtc-sun6i.c') diff --git a/drivers/rtc/rtc-sun6i.c b/drivers/rtc/rtc-sun6i.c index 5b3e4da63406..755aeb82a285 100644 --- a/drivers/rtc/rtc-sun6i.c +++ b/drivers/rtc/rtc-sun6i.c @@ -71,6 +71,10 @@ #define SUN6I_LOSC_OUT_GATING 0x0060 #define SUN6I_LOSC_OUT_GATING_EN_OFFSET 0 +/* General-purpose data */ +#define SUN6I_GP_DATA 0x0100 +#define SUN6I_GP_DATA_SIZE 0x20 + /* * Get date values */ @@ -662,6 +666,39 @@ static const struct rtc_class_ops sun6i_rtc_ops = { .alarm_irq_enable = sun6i_rtc_alarm_irq_enable }; +static int sun6i_rtc_nvmem_read(void *priv, unsigned int offset, void *_val, size_t bytes) +{ + struct sun6i_rtc_dev *chip = priv; + u32 *val = _val; + int i; + + for (i = 0; i < bytes / 4; ++i) + val[i] = readl(chip->base + SUN6I_GP_DATA + offset + 4 * i); + + return 0; +} + +static int sun6i_rtc_nvmem_write(void *priv, unsigned int offset, void *_val, size_t bytes) +{ + struct sun6i_rtc_dev *chip = priv; + u32 *val = _val; + int i; + + for (i = 0; i < bytes / 4; ++i) + writel(val[i], chip->base + SUN6I_GP_DATA + offset + 4 * i); + + return 0; +} + +static struct nvmem_config sun6i_rtc_nvmem_cfg = { + .type = NVMEM_TYPE_BATTERY_BACKED, + .reg_read = sun6i_rtc_nvmem_read, + .reg_write = sun6i_rtc_nvmem_write, + .size = SUN6I_GP_DATA_SIZE, + .word_size = 4, + .stride = 4, +}; + #ifdef CONFIG_PM_SLEEP /* Enable IRQ wake on suspend, to wake up from RTC. */ static int sun6i_rtc_suspend(struct device *dev) @@ -795,6 +832,11 @@ static int sun6i_rtc_probe(struct platform_device *pdev) if (ret) return ret; + sun6i_rtc_nvmem_cfg.priv = chip; + ret = devm_rtc_nvmem_register(chip->rtc, &sun6i_rtc_nvmem_cfg); + if (ret) + return ret; + dev_info(&pdev->dev, "RTC enabled\n"); return 0; -- cgit v1.2.3