drivers/rtc/rtc-wm831x.c

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

File Facts

System
Linux kernel
Corpus path
drivers/rtc/rtc-wm831x.c
Extension
.c
Size
12600 bytes
Lines
476
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 wm831x_rtc {
	struct wm831x *wm831x;
	struct rtc_device *rtc;
	unsigned int alarm_enabled:1;
};

static void wm831x_rtc_add_randomness(struct wm831x *wm831x)
{
	int ret;
	u16 reg;

	/*
	 * The write counter contains a pseudo-random number which is
	 * regenerated every time we set the RTC so it should be a
	 * useful per-system source of entropy.
	 */
	ret = wm831x_reg_read(wm831x, WM831X_RTC_WRITE_COUNTER);
	if (ret >= 0) {
		reg = ret;
		add_device_randomness(&reg, sizeof(reg));
	} else {
		dev_warn(wm831x->dev, "Failed to read RTC write counter: %d\n",
			 ret);
	}
}

/*
 * Read current time and date in RTC
 */
static int wm831x_rtc_readtime(struct device *dev, struct rtc_time *tm)
{
	struct wm831x_rtc *wm831x_rtc = dev_get_drvdata(dev);
	struct wm831x *wm831x = wm831x_rtc->wm831x;
	u16 time1[2], time2[2];
	int ret;
	int count = 0;

	/* Has the RTC been programmed? */
	ret = wm831x_reg_read(wm831x, WM831X_RTC_CONTROL);
	if (ret < 0) {
		dev_err(dev, "Failed to read RTC control: %d\n", ret);
		return ret;
	}
	if (!(ret & WM831X_RTC_VALID)) {
		dev_dbg(dev, "RTC not yet configured\n");
		return -EINVAL;
	}

	/* Read twice to make sure we don't read a corrupt, partially
	 * incremented, value.
	 */
	do {
		ret = wm831x_bulk_read(wm831x, WM831X_RTC_TIME_1,
				       2, time1);
		if (ret != 0)
			continue;

		ret = wm831x_bulk_read(wm831x, WM831X_RTC_TIME_1,
				       2, time2);
		if (ret != 0)
			continue;

		if (memcmp(time1, time2, sizeof(time1)) == 0) {
			u32 time = (time1[0] << 16) | time1[1];

			rtc_time64_to_tm(time, tm);
			return 0;
		}

	} while (++count < WM831X_GET_TIME_RETRIES);

	dev_err(dev, "Timed out reading current time\n");

	return -EIO;
}

/*
 * Set current time and date in RTC
 */
static int wm831x_rtc_settime(struct device *dev, struct rtc_time *tm)
{
	struct wm831x_rtc *wm831x_rtc = dev_get_drvdata(dev);
	struct wm831x *wm831x = wm831x_rtc->wm831x;
	struct rtc_time new_tm;
	unsigned long time, new_time;
	int ret;
	int count = 0;

	time = rtc_tm_to_time64(tm);

Annotation

Implementation Notes