staticvoid 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(®, sizeof(reg));
} else {
dev_warn(wm831x->dev, "Failed to read RTC write counter: %d\n",
ret);
}
}
/* * Read current time and date in RTC
*/ staticint 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
*/ staticint 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; unsignedlong time, new_time; int ret; int count = 0;
time = rtc_tm_to_time64(tm);
ret = wm831x_reg_write(wm831x, WM831X_RTC_TIME_1,
(time >> 16) & 0xffff); if (ret < 0) {
dev_err(dev, "Failed to write TIME_1: %d\n", ret); return ret;
}
ret = wm831x_reg_write(wm831x, WM831X_RTC_TIME_2, time & 0xffff); if (ret < 0) {
dev_err(dev, "Failed to write TIME_2: %d\n", ret); return ret;
}
/* Wait for the update to complete - should happen first time * round but be conservative.
*/ do {
msleep(1);
ret = wm831x_reg_read(wm831x, WM831X_RTC_CONTROL); if (ret < 0)
ret = WM831X_RTC_SYNC_BUSY;
} while (!(ret & WM831X_RTC_SYNC_BUSY) &&
++count < WM831X_SET_TIME_RETRIES);
if (ret & WM831X_RTC_SYNC_BUSY) {
dev_err(dev, "Timed out writing RTC update\n"); return -EIO;
}
/* Check that the update was accepted; security features may * have caused the update to be ignored.
*/
ret = wm831x_rtc_readtime(dev, &new_tm); if (ret < 0) return ret;
new_time = rtc_tm_to_time64(&new_tm);
/* Allow a second of change in case of tick */ if (new_time - time > 1) {
dev_err(dev, "RTC update not permitted by hardware\n"); return -EPERM;
}
return 0;
}
/* * Read alarm time and date in RTC
*/ staticint wm831x_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
{ struct wm831x_rtc *wm831x_rtc = dev_get_drvdata(dev); int ret;
u16 data[2];
u32 time;
ret = wm831x_bulk_read(wm831x_rtc->wm831x, WM831X_RTC_ALARM_1,
2, data); if (ret != 0) {
dev_err(dev, "Failed to read alarm time: %d\n", ret); return ret;
}
time = (data[0] << 16) | data[1];
rtc_time64_to_tm(time, &alrm->time);
ret = wm831x_reg_read(wm831x_rtc->wm831x, WM831X_RTC_CONTROL); if (ret < 0) {
dev_err(dev, "Failed to read RTC control: %d\n", ret); return ret;
}
#ifdef CONFIG_PM /* Turn off the alarm if it should not be a wake source. */ staticint wm831x_rtc_suspend(struct device *dev)
{ struct wm831x_rtc *wm831x_rtc = dev_get_drvdata(dev); int ret, enable;
ret = wm831x_set_bits(wm831x_rtc->wm831x, WM831X_RTC_CONTROL,
WM831X_RTC_ALM_ENA, enable); if (ret != 0)
dev_err(dev, "Failed to update RTC alarm: %d\n", ret);
return 0;
}
/* Enable the alarm if it should be enabled (in case it was disabled to * prevent use as a wake source).
*/ staticint wm831x_rtc_resume(struct device *dev)
{ struct wm831x_rtc *wm831x_rtc = dev_get_drvdata(dev); int ret;
if (wm831x_rtc->alarm_enabled) {
ret = wm831x_rtc_start_alarm(wm831x_rtc); if (ret != 0)
dev_err(dev, "Failed to restart RTC alarm: %d\n", ret);
}
return 0;
}
/* Unconditionally disable the alarm */ staticint wm831x_rtc_freeze(struct device *dev)
{ struct wm831x_rtc *wm831x_rtc = dev_get_drvdata(dev); int ret;
ret = wm831x_set_bits(wm831x_rtc->wm831x, WM831X_RTC_CONTROL,
WM831X_RTC_ALM_ENA, 0); if (ret != 0)
dev_err(dev, "Failed to stop RTC alarm: %d\n", ret);
MODULE_AUTHOR("Mark Brown ");
MODULE_DESCRIPTION("RTC driver for the WM831x series PMICs");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:wm831x-rtc");
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.