drivers/rtc/rtc-rk808.c

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

File Facts

System
Linux kernel
Corpus path
drivers/rtc/rtc-rk808.c
Extension
.c
Size
13135 bytes
Lines
461
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 rk_rtc_compat_reg {
	unsigned int ctrl_reg;
	unsigned int status_reg;
	unsigned int alarm_seconds_reg;
	unsigned int int_reg;
	unsigned int seconds_reg;
};

struct rk808_rtc {
	struct regmap *regmap;
	struct rtc_device *rtc;
	struct rk_rtc_compat_reg *creg;
	int irq;
};

/*
 * The Rockchip calendar used by the RK808 counts November with 31 days. We use
 * these translation functions to convert its dates to/from the Gregorian
 * calendar used by the rest of the world. We arbitrarily define Jan 1st, 2016
 * as the day when both calendars were in sync, and treat all other dates
 * relative to that.
 * NOTE: Other system software (e.g. firmware) that reads the same hardware must
 * implement this exact same conversion algorithm, with the same anchor date.
 */
static time64_t nov2dec_transitions(struct rtc_time *tm)
{
	return (tm->tm_year + 1900) - 2016 + (tm->tm_mon + 1 > 11 ? 1 : 0);
}

static void rockchip_to_gregorian(struct rtc_time *tm)
{
	/* If it's Nov 31st, rtc_tm_to_time64() will count that like Dec 1st */
	time64_t time = rtc_tm_to_time64(tm);
	rtc_time64_to_tm(time + nov2dec_transitions(tm) * 86400, tm);
}

static void gregorian_to_rockchip(struct rtc_time *tm)
{
	time64_t extra_days = nov2dec_transitions(tm);
	time64_t time = rtc_tm_to_time64(tm);
	rtc_time64_to_tm(time - extra_days * 86400, tm);

	/* Compensate if we went back over Nov 31st (will work up to 2381) */
	if (nov2dec_transitions(tm) < extra_days) {
		if (tm->tm_mon + 1 == 11)
			tm->tm_mday++;	/* This may result in 31! */
		else
			rtc_time64_to_tm(time - (extra_days - 1) * 86400, tm);
	}
}

/* Read current time and date in RTC */
static int rk808_rtc_readtime(struct device *dev, struct rtc_time *tm)
{
	struct rk808_rtc *rk808_rtc = dev_get_drvdata(dev);
	u8 rtc_data[NUM_TIME_REGS];
	int ret;

	/* Force an update of the shadowed registers right now */
	ret = regmap_update_bits(rk808_rtc->regmap, rk808_rtc->creg->ctrl_reg,
				 BIT_RTC_CTRL_REG_RTC_GET_TIME,
				 BIT_RTC_CTRL_REG_RTC_GET_TIME);
	if (ret) {
		dev_err(dev, "Failed to update bits rtc_ctrl: %d\n", ret);
		return ret;
	}

	/*
	 * After we set the GET_TIME bit, the rtc time can't be read
	 * immediately. So we should wait up to 31.25 us, about one cycle of
	 * 32khz. If we clear the GET_TIME bit here, the time of i2c transfer
	 * certainly more than 31.25us: 16 * 2.5us at 400kHz bus frequency.
	 */
	ret = regmap_update_bits(rk808_rtc->regmap, rk808_rtc->creg->ctrl_reg,
				 BIT_RTC_CTRL_REG_RTC_GET_TIME,
				 0);
	if (ret) {
		dev_err(dev, "Failed to update bits rtc_ctrl: %d\n", ret);
		return ret;
	}

	ret = regmap_bulk_read(rk808_rtc->regmap, rk808_rtc->creg->seconds_reg,
			       rtc_data, NUM_TIME_REGS);
	if (ret) {
		dev_err(dev, "Failed to bulk read rtc_data: %d\n", ret);
		return ret;
	}

	tm->tm_sec = bcd2bin(rtc_data[0] & SECONDS_REG_MSK);
	tm->tm_min = bcd2bin(rtc_data[1] & MINUTES_REG_MAK);

Annotation

Implementation Notes