drivers/rtc/rtc-spacemit-p1.c

Source file repositories/reference/linux-study-clean/drivers/rtc/rtc-spacemit-p1.c

File Facts

System
Linux kernel
Corpus path
drivers/rtc/rtc-spacemit-p1.c
Extension
.c
Size
4337 bytes
Lines
168
Domain
Driver Families
Bucket
drivers/rtc
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

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;

Annotation

Implementation Notes