drivers/rtc/rtc-mpfs.c

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

File Facts

System
Linux kernel
Corpus path
drivers/rtc/rtc-mpfs.c
Extension
.c
Size
8021 bytes
Lines
298
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 mpfs_rtc_dev {
	struct rtc_device *rtc;
	void __iomem *base;
};

static void mpfs_rtc_start(struct mpfs_rtc_dev *rtcdev)
{
	u32 ctrl;

	ctrl = readl(rtcdev->base + CONTROL_REG);
	ctrl &= ~CONTROL_STOP_BIT;
	ctrl |= CONTROL_START_BIT;
	writel(ctrl, rtcdev->base + CONTROL_REG);
}

static void mpfs_rtc_clear_irq(struct mpfs_rtc_dev *rtcdev)
{
	u32 val = readl(rtcdev->base + CONTROL_REG);

	val &= ~(CONTROL_ALARM_ON_BIT | CONTROL_STOP_BIT);
	val |= CONTROL_ALARM_OFF_BIT;
	writel(val, rtcdev->base + CONTROL_REG);
	/*
	 * Ensure that the posted write to the CONTROL_REG register completed before
	 * returning from this function. Not doing this may result in the interrupt
	 * only being cleared some time after this function returns.
	 */
	(void)readl(rtcdev->base + CONTROL_REG);
}

static int mpfs_rtc_readtime(struct device *dev, struct rtc_time *tm)
{
	struct mpfs_rtc_dev *rtcdev = dev_get_drvdata(dev);
	u64 time;

	time = readl(rtcdev->base + DATETIME_LOWER_REG);
	time |= ((u64)readl(rtcdev->base + DATETIME_UPPER_REG) & DATETIME_UPPER_MASK) << 32;
	rtc_time64_to_tm(time, tm);

	return 0;
}

static int mpfs_rtc_settime(struct device *dev, struct rtc_time *tm)
{
	struct mpfs_rtc_dev *rtcdev = dev_get_drvdata(dev);
	u32 ctrl, prog;
	u64 time;
	int ret;

	time = rtc_tm_to_time64(tm);

	writel((u32)time, rtcdev->base + DATETIME_LOWER_REG);
	writel((u32)(time >> 32) & DATETIME_UPPER_MASK, rtcdev->base + DATETIME_UPPER_REG);

	ctrl = readl(rtcdev->base + CONTROL_REG);
	ctrl &= ~CONTROL_STOP_BIT;
	ctrl |= CONTROL_UPLOAD_BIT;
	writel(ctrl, rtcdev->base + CONTROL_REG);

	ret = read_poll_timeout(readl, prog, prog & CONTROL_UPLOAD_BIT, 0, UPLOAD_TIMEOUT_US,
				false, rtcdev->base + CONTROL_REG);
	if (ret) {
		dev_err(dev, "timed out uploading time to rtc");
		return ret;
	}
	mpfs_rtc_start(rtcdev);

	return 0;
}

static int mpfs_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
{
	struct mpfs_rtc_dev *rtcdev = dev_get_drvdata(dev);
	u32 mode = readl(rtcdev->base + MODE_REG);
	u64 time;

	alrm->enabled = mode & MODE_WAKE_EN;

	time = (u64)readl(rtcdev->base + ALARM_LOWER_REG) << 32;
	time |= (readl(rtcdev->base + ALARM_UPPER_REG) & ALARM_UPPER_MASK);
	rtc_time64_to_tm(time, &alrm->time);

	return 0;
}

static int mpfs_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
{
	struct mpfs_rtc_dev *rtcdev = dev_get_drvdata(dev);
	u32 mode, ctrl;
	u64 time;

Annotation

Implementation Notes