drivers/rtc/rtc-rzn1.c

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

File Facts

System
Linux kernel
Corpus path
drivers/rtc/rtc-rzn1.c
Extension
.c
Size
13384 bytes
Lines
519
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 rzn1_rtc {
	struct rtc_device *rtcdev;
	void __iomem *base;
	/*
	 * Protects access to RZN1_RTC_CTL1 reg. rtc_lock with threaded_irqs
	 * would introduce race conditions when switching interrupts because
	 * of potential sleeps
	 */
	spinlock_t ctl1_access_lock;
	struct rtc_time tm_alarm;
};

static void rzn1_rtc_get_time_snapshot(struct rzn1_rtc *rtc, struct rtc_time *tm)
{
	u32 val;

	val = readl(rtc->base + RZN1_RTC_TIMEC);
	tm->tm_sec = bcd2bin(val);
	tm->tm_min = bcd2bin(val >> RZN1_RTC_TIME_MIN_SHIFT);
	tm->tm_hour = bcd2bin(val >> RZN1_RTC_TIME_HOUR_SHIFT);

	val = readl(rtc->base + RZN1_RTC_CALC);
	tm->tm_wday = val & 0x0f;
	tm->tm_mday = bcd2bin(val >> RZN1_RTC_CAL_DAY_SHIFT);
	tm->tm_mon = bcd2bin(val >> RZN1_RTC_CAL_MON_SHIFT) - 1;
	tm->tm_year = bcd2bin(val >> RZN1_RTC_CAL_YEAR_SHIFT) + 100;
}

static int rzn1_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
	struct rzn1_rtc *rtc = dev_get_drvdata(dev);
	u32 val, secs;

	/*
	 * The RTC was not started or is stopped and thus does not carry the
	 * proper time/date.
	 */
	val = readl(rtc->base + RZN1_RTC_CTL2);
	if (val & RZN1_RTC_CTL2_STOPPED)
		return -EINVAL;

	rzn1_rtc_get_time_snapshot(rtc, tm);
	secs = readl(rtc->base + RZN1_RTC_SECC);
	if (tm->tm_sec != bcd2bin(secs))
		rzn1_rtc_get_time_snapshot(rtc, tm);

	return 0;
}

static int rzn1_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
	struct rzn1_rtc *rtc = dev_get_drvdata(dev);
	u32 val;
	int ret;

	val = readl(rtc->base + RZN1_RTC_CTL2);
	if (!(val & RZN1_RTC_CTL2_STOPPED)) {
		/* Hold the counter if it was counting up */
		writel(RZN1_RTC_CTL2_WAIT, rtc->base + RZN1_RTC_CTL2);

		/* Wait for the counter to stop: two 32k clock cycles */
		usleep_range(61, 100);
		ret = readl_poll_timeout(rtc->base + RZN1_RTC_CTL2, val,
					 val & RZN1_RTC_CTL2_WST, 0, 100);
		if (ret)
			return ret;
	}

	val = bin2bcd(tm->tm_sec);
	val |= bin2bcd(tm->tm_min) << RZN1_RTC_TIME_MIN_SHIFT;
	val |= bin2bcd(tm->tm_hour) << RZN1_RTC_TIME_HOUR_SHIFT;
	writel(val, rtc->base + RZN1_RTC_TIME);

	val = tm->tm_wday;
	val |= bin2bcd(tm->tm_mday) << RZN1_RTC_CAL_DAY_SHIFT;
	val |= bin2bcd(tm->tm_mon + 1) << RZN1_RTC_CAL_MON_SHIFT;
	val |= bin2bcd(tm->tm_year - 100) << RZN1_RTC_CAL_YEAR_SHIFT;
	writel(val, rtc->base + RZN1_RTC_CAL);

	writel(0, rtc->base + RZN1_RTC_CTL2);

	return 0;
}

static irqreturn_t rzn1_rtc_alarm_irq(int irq, void *dev_id)
{
	struct rzn1_rtc *rtc = dev_id;
	u32 ctl1, set_irq_bits = 0;

	if (rtc->tm_alarm.tm_sec == 0)

Annotation

Implementation Notes