drivers/rtc/rtc-cadence.c

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

File Facts

System
Linux kernel
Corpus path
drivers/rtc/rtc-cadence.c
Extension
.c
Size
10628 bytes
Lines
413
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 cdns_rtc {
	struct rtc_device *rtc_dev;
	struct clk *pclk;
	struct clk *ref_clk;
	void __iomem *regs;
	int irq;
};

static void cdns_rtc_set_enabled(struct cdns_rtc *crtc, bool enabled)
{
	u32 reg = enabled ? 0x0 : CDNS_RTC_CTLR_TIME_CAL;

	writel(reg, crtc->regs + CDNS_RTC_CTLR);
}

static bool cdns_rtc_get_enabled(struct cdns_rtc *crtc)
{
	return !(readl(crtc->regs + CDNS_RTC_CTLR) & CDNS_RTC_CTLR_TIME_CAL);
}

static irqreturn_t cdns_rtc_irq_handler(int irq, void *id)
{
	struct device *dev = id;
	struct cdns_rtc *crtc = dev_get_drvdata(dev);

	/* Reading the register clears it */
	if (!(readl(crtc->regs + CDNS_RTC_EFLR) & CDNS_RTC_AEI_ALRM))
		return IRQ_NONE;

	rtc_update_irq(crtc->rtc_dev, 1, RTC_IRQF | RTC_AF);
	return IRQ_HANDLED;
}

static u32 cdns_rtc_time2reg(struct rtc_time *tm)
{
	return FIELD_PREP(CDNS_RTC_TIME_S,  bin2bcd(tm->tm_sec))
	     | FIELD_PREP(CDNS_RTC_TIME_M,  bin2bcd(tm->tm_min))
	     | FIELD_PREP(CDNS_RTC_TIME_HR, bin2bcd(tm->tm_hour));
}

static void cdns_rtc_reg2time(u32 reg, struct rtc_time *tm)
{
	tm->tm_sec  = bcd2bin(FIELD_GET(CDNS_RTC_TIME_S, reg));
	tm->tm_min  = bcd2bin(FIELD_GET(CDNS_RTC_TIME_M, reg));
	tm->tm_hour = bcd2bin(FIELD_GET(CDNS_RTC_TIME_HR, reg));
}

static int cdns_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
	struct cdns_rtc *crtc = dev_get_drvdata(dev);
	u32 reg;

	/* If the RTC is disabled, assume the values are invalid */
	if (!cdns_rtc_get_enabled(crtc))
		return -EINVAL;

	cdns_rtc_set_enabled(crtc, false);

	reg = readl(crtc->regs + CDNS_RTC_TIMR);
	cdns_rtc_reg2time(reg, tm);

	reg = readl(crtc->regs + CDNS_RTC_CALR);
	tm->tm_mday = bcd2bin(FIELD_GET(CDNS_RTC_CAL_D, reg));
	tm->tm_mon  = bcd2bin(FIELD_GET(CDNS_RTC_CAL_M, reg)) - 1;
	tm->tm_year = bcd2bin(FIELD_GET(CDNS_RTC_CAL_Y, reg))
		    + bcd2bin(FIELD_GET(CDNS_RTC_CAL_C, reg)) * 100 - 1900;
	tm->tm_wday = bcd2bin(FIELD_GET(CDNS_RTC_CAL_DAY, reg)) - 1;

	cdns_rtc_set_enabled(crtc, true);
	return 0;
}

static int cdns_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
	struct cdns_rtc *crtc = dev_get_drvdata(dev);
	u32 timr, calr, stsr;
	int ret = -EIO;
	int year = tm->tm_year + 1900;
	int tries;

	cdns_rtc_set_enabled(crtc, false);

	timr = cdns_rtc_time2reg(tm);

	calr = FIELD_PREP(CDNS_RTC_CAL_D, bin2bcd(tm->tm_mday))
	     | FIELD_PREP(CDNS_RTC_CAL_M, bin2bcd(tm->tm_mon + 1))
	     | FIELD_PREP(CDNS_RTC_CAL_Y, bin2bcd(year % 100))
	     | FIELD_PREP(CDNS_RTC_CAL_C, bin2bcd(year / 100))
	     | FIELD_PREP(CDNS_RTC_CAL_DAY, tm->tm_wday + 1);

Annotation

Implementation Notes