|  | // SPDX-License-Identifier: GPL-2.0 | 
|  | /* | 
|  | * Driver for the RTC found in the SpacemiT P1 PMIC | 
|  | * | 
|  | * Copyright (C) 2025 by RISCstar Solutions Corporation.  All rights reserved. | 
|  | */ | 
|  |  | 
|  | #include <linux/bits.h> | 
|  | #include <linux/device.h> | 
|  | #include <linux/module.h> | 
|  | #include <linux/platform_device.h> | 
|  | #include <linux/regmap.h> | 
|  | #include <linux/rtc.h> | 
|  |  | 
|  | #define MOD_NAME	"spacemit-p1-rtc" | 
|  |  | 
|  | /* | 
|  | * Six consecutive 1-byte registers hold the seconds, minutes, hours, | 
|  | * day-of-month, month, and year (respectively). | 
|  | * | 
|  | * The range of values in these registers is: | 
|  | *    seconds	0-59 | 
|  | *    minutes	0-59 | 
|  | *    hours	0-59 | 
|  | *    day	0-30 (struct tm is 1-31) | 
|  | *    month	0-11 | 
|  | *    year	years since 2000 (struct tm is since 1900) | 
|  | * | 
|  | * Note that the day and month must be converted after reading and | 
|  | * before writing. | 
|  | */ | 
|  | #define RTC_TIME		0x0d	/* Offset of the seconds register */ | 
|  |  | 
|  | #define RTC_CTRL		0x1d | 
|  | #define RTC_EN		BIT(2) | 
|  |  | 
|  | /* Number of attempts to read a consistent time stamp before giving up */ | 
|  | #define RTC_READ_TRIES		20	/* At least 1 */ | 
|  |  | 
|  | struct p1_rtc { | 
|  | struct regmap *regmap; | 
|  | struct rtc_device *rtc; | 
|  | }; | 
|  |  | 
|  | /* | 
|  | * The P1 hardware documentation states that the register values are | 
|  | * latched to ensure a consistent time snapshot within the registers, | 
|  | * but these are in fact unstable due to a bug in the hardware design. | 
|  | * So we loop until we get two identical readings. | 
|  | */ | 
|  | static int p1_rtc_read_time(struct device *dev, struct rtc_time *t) | 
|  | { | 
|  | struct p1_rtc *p1 = dev_get_drvdata(dev); | 
|  | struct regmap *regmap = p1->regmap; | 
|  | u32 count = RTC_READ_TRIES; | 
|  | u8 seconds; | 
|  | u8 time[6]; | 
|  | int ret; | 
|  |  | 
|  | if (!regmap_test_bits(regmap, RTC_CTRL, RTC_EN)) | 
|  | return -EINVAL;		/* RTC is disabled */ | 
|  |  | 
|  | ret = regmap_bulk_read(regmap, RTC_TIME, time, sizeof(time)); | 
|  | if (ret) | 
|  | return ret; | 
|  |  | 
|  | do { | 
|  | seconds = time[0]; | 
|  | ret = regmap_bulk_read(regmap, RTC_TIME, time, sizeof(time)); | 
|  | if (ret) | 
|  | return ret; | 
|  | } while (time[0] != seconds && --count); | 
|  |  | 
|  | if (!count) | 
|  | return -EIO;		/* Unable to get a consistent result */ | 
|  |  | 
|  | t->tm_sec = time[0] & GENMASK(5, 0); | 
|  | t->tm_min = time[1] & GENMASK(5, 0); | 
|  | t->tm_hour = time[2] & GENMASK(4, 0); | 
|  | t->tm_mday = (time[3] & GENMASK(4, 0)) + 1; | 
|  | t->tm_mon = time[4] & GENMASK(3, 0); | 
|  | t->tm_year = (time[5] & GENMASK(5, 0)) + 100; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * The P1 hardware documentation states that values in the registers are | 
|  | * latched so when written they represent a consistent time snapshot. | 
|  | * Nevertheless, this is not guaranteed by the implementation, so we must | 
|  | * disable the RTC while updating it. | 
|  | */ | 
|  | static int p1_rtc_set_time(struct device *dev, struct rtc_time *t) | 
|  | { | 
|  | struct p1_rtc *p1 = dev_get_drvdata(dev); | 
|  | struct regmap *regmap = p1->regmap; | 
|  | u8 time[6]; | 
|  | int ret; | 
|  |  | 
|  | time[0] = t->tm_sec; | 
|  | time[1] = t->tm_min; | 
|  | time[2] = t->tm_hour; | 
|  | time[3] = t->tm_mday - 1; | 
|  | time[4] = t->tm_mon; | 
|  | time[5] = t->tm_year - 100; | 
|  |  | 
|  | /* Disable the RTC to update; re-enable again when done */ | 
|  | ret = regmap_clear_bits(regmap, RTC_CTRL, RTC_EN); | 
|  | if (ret) | 
|  | return ret; | 
|  |  | 
|  | /* If something goes wrong, leave the RTC disabled */ | 
|  | ret = regmap_bulk_write(regmap, RTC_TIME, time, sizeof(time)); | 
|  | if (ret) | 
|  | return ret; | 
|  |  | 
|  | return regmap_set_bits(regmap, RTC_CTRL, RTC_EN); | 
|  | } | 
|  |  | 
|  | static const struct rtc_class_ops p1_rtc_class_ops = { | 
|  | .read_time = p1_rtc_read_time, | 
|  | .set_time = p1_rtc_set_time, | 
|  | }; | 
|  |  | 
|  | static int p1_rtc_probe(struct platform_device *pdev) | 
|  | { | 
|  | struct device *dev = &pdev->dev; | 
|  | struct rtc_device *rtc; | 
|  | struct p1_rtc *p1; | 
|  |  | 
|  | p1 = devm_kzalloc(dev, sizeof(*p1), GFP_KERNEL); | 
|  | if (!p1) | 
|  | return -ENOMEM; | 
|  | dev_set_drvdata(dev, p1); | 
|  |  | 
|  | p1->regmap = dev_get_regmap(dev->parent, NULL); | 
|  | if (!p1->regmap) | 
|  | return dev_err_probe(dev, -ENODEV, "failed to get regmap\n"); | 
|  |  | 
|  | rtc = devm_rtc_allocate_device(dev); | 
|  | if (IS_ERR(rtc)) | 
|  | return dev_err_probe(dev, PTR_ERR(rtc), | 
|  | "error allocating device\n"); | 
|  | p1->rtc = rtc; | 
|  |  | 
|  | rtc->ops = &p1_rtc_class_ops; | 
|  | rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; | 
|  | rtc->range_max = RTC_TIMESTAMP_END_2063; | 
|  |  | 
|  | clear_bit(RTC_FEATURE_ALARM, rtc->features); | 
|  | clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->features); | 
|  |  | 
|  | return devm_rtc_register_device(rtc); | 
|  | } | 
|  |  | 
|  | static struct platform_driver p1_rtc_driver = { | 
|  | .probe = p1_rtc_probe, | 
|  | .driver = { | 
|  | .name = MOD_NAME, | 
|  | }, | 
|  | }; | 
|  |  | 
|  | module_platform_driver(p1_rtc_driver); | 
|  |  | 
|  | MODULE_DESCRIPTION("SpacemiT P1 RTC driver"); | 
|  | MODULE_LICENSE("GPL"); | 
|  | MODULE_ALIAS("platform:" MOD_NAME); |