ret = cros_ec_cmd_xfer_status(cros_ec, msg); if (ret < 0) return ret; return 0;
}
/* Read the current time from the EC. */ staticint cros_ec_rtc_read_time(struct device *dev, struct rtc_time *tm)
{ struct cros_ec_rtc *cros_ec_rtc = dev_get_drvdata(dev); struct cros_ec_device *cros_ec = cros_ec_rtc->cros_ec; int ret;
u32 time;
ret = cros_ec_rtc_get(cros_ec, EC_CMD_RTC_GET_VALUE, &time); if (ret) {
dev_err(dev, "error getting time: %d\n", ret); return ret;
}
rtc_time64_to_tm(time, tm);
return 0;
}
/* Set the current EC time. */ staticint cros_ec_rtc_set_time(struct device *dev, struct rtc_time *tm)
{ struct cros_ec_rtc *cros_ec_rtc = dev_get_drvdata(dev); struct cros_ec_device *cros_ec = cros_ec_rtc->cros_ec; int ret;
time64_t time = rtc_tm_to_time64(tm);
ret = cros_ec_rtc_set(cros_ec, EC_CMD_RTC_SET_VALUE, (u32)time); if (ret < 0) {
dev_err(dev, "error setting time: %d\n", ret); return ret;
}
return 0;
}
/* Read alarm time from RTC. */ staticint cros_ec_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{ struct cros_ec_rtc *cros_ec_rtc = dev_get_drvdata(dev); struct cros_ec_device *cros_ec = cros_ec_rtc->cros_ec; int ret;
u32 current_time, alarm_offset;
/* * The EC host command for getting the alarm is relative (i.e. 5 * seconds from now) whereas rtc_wkalrm is absolute. Get the current * RTC time first so we can calculate the relative time.
*/
ret = cros_ec_rtc_get(cros_ec, EC_CMD_RTC_GET_VALUE, ¤t_time); if (ret < 0) {
dev_err(dev, "error getting time: %d\n", ret); return ret;
}
ret = cros_ec_rtc_get(cros_ec, EC_CMD_RTC_GET_ALARM, &alarm_offset); if (ret < 0) {
dev_err(dev, "error getting alarm: %d\n", ret); return ret;
}
/* * The EC host command for setting the alarm is relative * (i.e. 5 seconds from now) whereas rtc_wkalrm is absolute. * Get the current RTC time first so we can calculate the * relative time.
*/
ret = cros_ec_rtc_get(cros_ec, EC_CMD_RTC_GET_VALUE, ¤t_time); if (ret < 0) {
dev_err(dev, "error getting time: %d\n", ret); return ret;
}
alarm_time = rtc_tm_to_time64(&alrm->time);
if (alarm_time < 0 || alarm_time > U32_MAX) return -EINVAL;
if (!alrm->enabled) { /* * If the alarm is being disabled, send an alarm * clear command.
*/
alarm_offset = EC_RTC_ALARM_CLEAR;
cros_ec_rtc->saved_alarm = (u32)alarm_time;
} else { /* Don't set an alarm in the past. */ if ((u32)alarm_time <= current_time) return -ETIME;
alarm_offset = (u32)alarm_time - current_time;
}
ret = cros_ec_rtc_set(cros_ec, EC_CMD_RTC_SET_ALARM, alarm_offset); if (ret < 0) {
dev_err(dev, "error setting alarm in %u seconds: %d\n",
alarm_offset, ret); /* * The EC code returns -EINVAL if the alarm time is too * far in the future. Convert it to the expected error code.
*/ if (ret == -EINVAL)
ret = -ERANGE; return ret;
}
ret = cros_ec_rtc_get(cros_ec, EC_CMD_RTC_GET_VALUE, ¤t_time); if (ret < 0) {
dev_err(dev, "error getting time: %d\n", ret); return ret;
}
if (enabled) { /* Restore saved alarm if it's still in the future. */ if (cros_ec_rtc->saved_alarm < current_time)
alarm_offset = EC_RTC_ALARM_CLEAR; else
alarm_offset = cros_ec_rtc->saved_alarm - current_time;
ret = cros_ec_rtc_set(cros_ec, EC_CMD_RTC_SET_ALARM,
alarm_offset); if (ret < 0) {
dev_err(dev, "error restoring alarm: %d\n", ret); return ret;
}
} else { /* Disable alarm, saving the old alarm value. */
ret = cros_ec_rtc_get(cros_ec, EC_CMD_RTC_GET_ALARM,
&alarm_offset); if (ret < 0) {
dev_err(dev, "error saving alarm: %d\n", ret); return ret;
}
alarm_value = current_time + alarm_offset;
/* * If the current EC alarm is already past, we don't want * to set an alarm when we go through the alarm irq enable * path.
*/ if (alarm_value < current_time)
cros_ec_rtc->saved_alarm = EC_RTC_ALARM_CLEAR; else
cros_ec_rtc->saved_alarm = alarm_value;
/* * The RTC on some older Chromebooks can only handle alarms less than * 24 hours in the future. The only way to find out is to try to set an * alarm further in the future. If that fails, assume that the RTC * connected to the EC can only handle less than 24 hours of alarm * window.
*/
ret = cros_ec_rtc_set(cros_ec, EC_CMD_RTC_SET_ALARM, SECS_PER_DAY * 2); if (ret == -EINVAL)
cros_ec_rtc->rtc->alarm_offset_max = SECS_PER_DAY - 1;
ret = devm_rtc_register_device(cros_ec_rtc->rtc); if (ret) return ret;
/* Get RTC events from the EC. */
cros_ec_rtc->notifier.notifier_call = cros_ec_rtc_event;
ret = blocking_notifier_chain_register(&cros_ec->event_notifier,
&cros_ec_rtc->notifier); if (ret) {
dev_err(&pdev->dev, "failed to register notifier\n"); return ret;
}
ret = blocking_notifier_chain_unregister(
&cros_ec_rtc->cros_ec->event_notifier,
&cros_ec_rtc->notifier); if (ret)
dev_err(dev, "failed to unregister notifier\n");
}
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.