rtc-cros-ec.c (10044B)
1// SPDX-License-Identifier: GPL-2.0 2// RTC driver for ChromeOS Embedded Controller. 3// 4// Copyright (C) 2017 Google, Inc. 5// Author: Stephen Barber <smbarber@chromium.org> 6 7#include <linux/kernel.h> 8#include <linux/module.h> 9#include <linux/platform_data/cros_ec_commands.h> 10#include <linux/platform_data/cros_ec_proto.h> 11#include <linux/platform_device.h> 12#include <linux/rtc.h> 13#include <linux/slab.h> 14 15#define DRV_NAME "cros-ec-rtc" 16 17/** 18 * struct cros_ec_rtc - Driver data for EC RTC 19 * 20 * @cros_ec: Pointer to EC device 21 * @rtc: Pointer to RTC device 22 * @notifier: Notifier info for responding to EC events 23 * @saved_alarm: Alarm to restore when interrupts are reenabled 24 */ 25struct cros_ec_rtc { 26 struct cros_ec_device *cros_ec; 27 struct rtc_device *rtc; 28 struct notifier_block notifier; 29 u32 saved_alarm; 30}; 31 32static int cros_ec_rtc_get(struct cros_ec_device *cros_ec, u32 command, 33 u32 *response) 34{ 35 int ret; 36 struct { 37 struct cros_ec_command msg; 38 struct ec_response_rtc data; 39 } __packed msg; 40 41 memset(&msg, 0, sizeof(msg)); 42 msg.msg.command = command; 43 msg.msg.insize = sizeof(msg.data); 44 45 ret = cros_ec_cmd_xfer_status(cros_ec, &msg.msg); 46 if (ret < 0) { 47 dev_err(cros_ec->dev, 48 "error getting %s from EC: %d\n", 49 command == EC_CMD_RTC_GET_VALUE ? "time" : "alarm", 50 ret); 51 return ret; 52 } 53 54 *response = msg.data.time; 55 56 return 0; 57} 58 59static int cros_ec_rtc_set(struct cros_ec_device *cros_ec, u32 command, 60 u32 param) 61{ 62 int ret = 0; 63 struct { 64 struct cros_ec_command msg; 65 struct ec_response_rtc data; 66 } __packed msg; 67 68 memset(&msg, 0, sizeof(msg)); 69 msg.msg.command = command; 70 msg.msg.outsize = sizeof(msg.data); 71 msg.data.time = param; 72 73 ret = cros_ec_cmd_xfer_status(cros_ec, &msg.msg); 74 if (ret < 0) { 75 dev_err(cros_ec->dev, "error setting %s on EC: %d\n", 76 command == EC_CMD_RTC_SET_VALUE ? "time" : "alarm", 77 ret); 78 return ret; 79 } 80 81 return 0; 82} 83 84/* Read the current time from the EC. */ 85static int cros_ec_rtc_read_time(struct device *dev, struct rtc_time *tm) 86{ 87 struct cros_ec_rtc *cros_ec_rtc = dev_get_drvdata(dev); 88 struct cros_ec_device *cros_ec = cros_ec_rtc->cros_ec; 89 int ret; 90 u32 time; 91 92 ret = cros_ec_rtc_get(cros_ec, EC_CMD_RTC_GET_VALUE, &time); 93 if (ret) { 94 dev_err(dev, "error getting time: %d\n", ret); 95 return ret; 96 } 97 98 rtc_time64_to_tm(time, tm); 99 100 return 0; 101} 102 103/* Set the current EC time. */ 104static int cros_ec_rtc_set_time(struct device *dev, struct rtc_time *tm) 105{ 106 struct cros_ec_rtc *cros_ec_rtc = dev_get_drvdata(dev); 107 struct cros_ec_device *cros_ec = cros_ec_rtc->cros_ec; 108 int ret; 109 time64_t time = rtc_tm_to_time64(tm); 110 111 ret = cros_ec_rtc_set(cros_ec, EC_CMD_RTC_SET_VALUE, (u32)time); 112 if (ret < 0) { 113 dev_err(dev, "error setting time: %d\n", ret); 114 return ret; 115 } 116 117 return 0; 118} 119 120/* Read alarm time from RTC. */ 121static int cros_ec_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) 122{ 123 struct cros_ec_rtc *cros_ec_rtc = dev_get_drvdata(dev); 124 struct cros_ec_device *cros_ec = cros_ec_rtc->cros_ec; 125 int ret; 126 u32 current_time, alarm_offset; 127 128 /* 129 * The EC host command for getting the alarm is relative (i.e. 5 130 * seconds from now) whereas rtc_wkalrm is absolute. Get the current 131 * RTC time first so we can calculate the relative time. 132 */ 133 ret = cros_ec_rtc_get(cros_ec, EC_CMD_RTC_GET_VALUE, ¤t_time); 134 if (ret < 0) { 135 dev_err(dev, "error getting time: %d\n", ret); 136 return ret; 137 } 138 139 ret = cros_ec_rtc_get(cros_ec, EC_CMD_RTC_GET_ALARM, &alarm_offset); 140 if (ret < 0) { 141 dev_err(dev, "error getting alarm: %d\n", ret); 142 return ret; 143 } 144 145 rtc_time64_to_tm(current_time + alarm_offset, &alrm->time); 146 147 return 0; 148} 149 150/* Set the EC's RTC alarm. */ 151static int cros_ec_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) 152{ 153 struct cros_ec_rtc *cros_ec_rtc = dev_get_drvdata(dev); 154 struct cros_ec_device *cros_ec = cros_ec_rtc->cros_ec; 155 int ret; 156 time64_t alarm_time; 157 u32 current_time, alarm_offset; 158 159 /* 160 * The EC host command for setting the alarm is relative 161 * (i.e. 5 seconds from now) whereas rtc_wkalrm is absolute. 162 * Get the current RTC time first so we can calculate the 163 * relative time. 164 */ 165 ret = cros_ec_rtc_get(cros_ec, EC_CMD_RTC_GET_VALUE, ¤t_time); 166 if (ret < 0) { 167 dev_err(dev, "error getting time: %d\n", ret); 168 return ret; 169 } 170 171 alarm_time = rtc_tm_to_time64(&alrm->time); 172 173 if (alarm_time < 0 || alarm_time > U32_MAX) 174 return -EINVAL; 175 176 if (!alrm->enabled) { 177 /* 178 * If the alarm is being disabled, send an alarm 179 * clear command. 180 */ 181 alarm_offset = EC_RTC_ALARM_CLEAR; 182 cros_ec_rtc->saved_alarm = (u32)alarm_time; 183 } else { 184 /* Don't set an alarm in the past. */ 185 if ((u32)alarm_time <= current_time) 186 return -ETIME; 187 188 alarm_offset = (u32)alarm_time - current_time; 189 } 190 191 ret = cros_ec_rtc_set(cros_ec, EC_CMD_RTC_SET_ALARM, alarm_offset); 192 if (ret < 0) { 193 dev_err(dev, "error setting alarm: %d\n", ret); 194 return ret; 195 } 196 197 return 0; 198} 199 200static int cros_ec_rtc_alarm_irq_enable(struct device *dev, 201 unsigned int enabled) 202{ 203 struct cros_ec_rtc *cros_ec_rtc = dev_get_drvdata(dev); 204 struct cros_ec_device *cros_ec = cros_ec_rtc->cros_ec; 205 int ret; 206 u32 current_time, alarm_offset, alarm_value; 207 208 ret = cros_ec_rtc_get(cros_ec, EC_CMD_RTC_GET_VALUE, ¤t_time); 209 if (ret < 0) { 210 dev_err(dev, "error getting time: %d\n", ret); 211 return ret; 212 } 213 214 if (enabled) { 215 /* Restore saved alarm if it's still in the future. */ 216 if (cros_ec_rtc->saved_alarm < current_time) 217 alarm_offset = EC_RTC_ALARM_CLEAR; 218 else 219 alarm_offset = cros_ec_rtc->saved_alarm - current_time; 220 221 ret = cros_ec_rtc_set(cros_ec, EC_CMD_RTC_SET_ALARM, 222 alarm_offset); 223 if (ret < 0) { 224 dev_err(dev, "error restoring alarm: %d\n", ret); 225 return ret; 226 } 227 } else { 228 /* Disable alarm, saving the old alarm value. */ 229 ret = cros_ec_rtc_get(cros_ec, EC_CMD_RTC_GET_ALARM, 230 &alarm_offset); 231 if (ret < 0) { 232 dev_err(dev, "error saving alarm: %d\n", ret); 233 return ret; 234 } 235 236 alarm_value = current_time + alarm_offset; 237 238 /* 239 * If the current EC alarm is already past, we don't want 240 * to set an alarm when we go through the alarm irq enable 241 * path. 242 */ 243 if (alarm_value < current_time) 244 cros_ec_rtc->saved_alarm = EC_RTC_ALARM_CLEAR; 245 else 246 cros_ec_rtc->saved_alarm = alarm_value; 247 248 alarm_offset = EC_RTC_ALARM_CLEAR; 249 ret = cros_ec_rtc_set(cros_ec, EC_CMD_RTC_SET_ALARM, 250 alarm_offset); 251 if (ret < 0) { 252 dev_err(dev, "error disabling alarm: %d\n", ret); 253 return ret; 254 } 255 } 256 257 return 0; 258} 259 260static int cros_ec_rtc_event(struct notifier_block *nb, 261 unsigned long queued_during_suspend, 262 void *_notify) 263{ 264 struct cros_ec_rtc *cros_ec_rtc; 265 struct rtc_device *rtc; 266 struct cros_ec_device *cros_ec; 267 u32 host_event; 268 269 cros_ec_rtc = container_of(nb, struct cros_ec_rtc, notifier); 270 rtc = cros_ec_rtc->rtc; 271 cros_ec = cros_ec_rtc->cros_ec; 272 273 host_event = cros_ec_get_host_event(cros_ec); 274 if (host_event & EC_HOST_EVENT_MASK(EC_HOST_EVENT_RTC)) { 275 rtc_update_irq(rtc, 1, RTC_IRQF | RTC_AF); 276 return NOTIFY_OK; 277 } else { 278 return NOTIFY_DONE; 279 } 280} 281 282static const struct rtc_class_ops cros_ec_rtc_ops = { 283 .read_time = cros_ec_rtc_read_time, 284 .set_time = cros_ec_rtc_set_time, 285 .read_alarm = cros_ec_rtc_read_alarm, 286 .set_alarm = cros_ec_rtc_set_alarm, 287 .alarm_irq_enable = cros_ec_rtc_alarm_irq_enable, 288}; 289 290#ifdef CONFIG_PM_SLEEP 291static int cros_ec_rtc_suspend(struct device *dev) 292{ 293 struct platform_device *pdev = to_platform_device(dev); 294 struct cros_ec_rtc *cros_ec_rtc = dev_get_drvdata(&pdev->dev); 295 296 if (device_may_wakeup(dev)) 297 return enable_irq_wake(cros_ec_rtc->cros_ec->irq); 298 299 return 0; 300} 301 302static int cros_ec_rtc_resume(struct device *dev) 303{ 304 struct platform_device *pdev = to_platform_device(dev); 305 struct cros_ec_rtc *cros_ec_rtc = dev_get_drvdata(&pdev->dev); 306 307 if (device_may_wakeup(dev)) 308 return disable_irq_wake(cros_ec_rtc->cros_ec->irq); 309 310 return 0; 311} 312#endif 313 314static SIMPLE_DEV_PM_OPS(cros_ec_rtc_pm_ops, cros_ec_rtc_suspend, 315 cros_ec_rtc_resume); 316 317static int cros_ec_rtc_probe(struct platform_device *pdev) 318{ 319 struct cros_ec_dev *ec_dev = dev_get_drvdata(pdev->dev.parent); 320 struct cros_ec_device *cros_ec = ec_dev->ec_dev; 321 struct cros_ec_rtc *cros_ec_rtc; 322 struct rtc_time tm; 323 int ret; 324 325 cros_ec_rtc = devm_kzalloc(&pdev->dev, sizeof(*cros_ec_rtc), 326 GFP_KERNEL); 327 if (!cros_ec_rtc) 328 return -ENOMEM; 329 330 platform_set_drvdata(pdev, cros_ec_rtc); 331 cros_ec_rtc->cros_ec = cros_ec; 332 333 /* Get initial time */ 334 ret = cros_ec_rtc_read_time(&pdev->dev, &tm); 335 if (ret) { 336 dev_err(&pdev->dev, "failed to read RTC time\n"); 337 return ret; 338 } 339 340 ret = device_init_wakeup(&pdev->dev, 1); 341 if (ret) { 342 dev_err(&pdev->dev, "failed to initialize wakeup\n"); 343 return ret; 344 } 345 346 cros_ec_rtc->rtc = devm_rtc_allocate_device(&pdev->dev); 347 if (IS_ERR(cros_ec_rtc->rtc)) 348 return PTR_ERR(cros_ec_rtc->rtc); 349 350 cros_ec_rtc->rtc->ops = &cros_ec_rtc_ops; 351 cros_ec_rtc->rtc->range_max = U32_MAX; 352 353 ret = devm_rtc_register_device(cros_ec_rtc->rtc); 354 if (ret) 355 return ret; 356 357 /* Get RTC events from the EC. */ 358 cros_ec_rtc->notifier.notifier_call = cros_ec_rtc_event; 359 ret = blocking_notifier_chain_register(&cros_ec->event_notifier, 360 &cros_ec_rtc->notifier); 361 if (ret) { 362 dev_err(&pdev->dev, "failed to register notifier\n"); 363 return ret; 364 } 365 366 return 0; 367} 368 369static int cros_ec_rtc_remove(struct platform_device *pdev) 370{ 371 struct cros_ec_rtc *cros_ec_rtc = platform_get_drvdata(pdev); 372 struct device *dev = &pdev->dev; 373 int ret; 374 375 ret = blocking_notifier_chain_unregister( 376 &cros_ec_rtc->cros_ec->event_notifier, 377 &cros_ec_rtc->notifier); 378 if (ret) { 379 dev_err(dev, "failed to unregister notifier\n"); 380 return ret; 381 } 382 383 return 0; 384} 385 386static struct platform_driver cros_ec_rtc_driver = { 387 .probe = cros_ec_rtc_probe, 388 .remove = cros_ec_rtc_remove, 389 .driver = { 390 .name = DRV_NAME, 391 .pm = &cros_ec_rtc_pm_ops, 392 }, 393}; 394 395module_platform_driver(cros_ec_rtc_driver); 396 397MODULE_DESCRIPTION("RTC driver for Chrome OS ECs"); 398MODULE_AUTHOR("Stephen Barber <smbarber@chromium.org>"); 399MODULE_LICENSE("GPL v2"); 400MODULE_ALIAS("platform:" DRV_NAME);