Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.11-rc3 537 lines 13 kB view raw
1/* 2 * rtc-mrst.c: Driver for Moorestown virtual RTC 3 * 4 * (C) Copyright 2009 Intel Corporation 5 * Author: Jacob Pan (jacob.jun.pan@intel.com) 6 * Feng Tang (feng.tang@intel.com) 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License 10 * as published by the Free Software Foundation; version 2 11 * of the License. 12 * 13 * Note: 14 * VRTC is emulated by system controller firmware, the real HW 15 * RTC is located in the PMIC device. SCU FW shadows PMIC RTC 16 * in a memory mapped IO space that is visible to the host IA 17 * processor. 18 * 19 * This driver is based upon drivers/rtc/rtc-cmos.c 20 */ 21 22/* 23 * Note: 24 * * vRTC only supports binary mode and 24H mode 25 * * vRTC only support PIE and AIE, no UIE, and its PIE only happens 26 * at 23:59:59pm everyday, no support for adjustable frequency 27 * * Alarm function is also limited to hr/min/sec. 28 */ 29 30#include <linux/mod_devicetable.h> 31#include <linux/platform_device.h> 32#include <linux/interrupt.h> 33#include <linux/spinlock.h> 34#include <linux/kernel.h> 35#include <linux/mc146818rtc.h> 36#include <linux/module.h> 37#include <linux/init.h> 38#include <linux/sfi.h> 39 40#include <asm/intel_scu_ipc.h> 41#include <asm/intel-mid.h> 42#include <asm/intel_mid_vrtc.h> 43 44struct mrst_rtc { 45 struct rtc_device *rtc; 46 struct device *dev; 47 int irq; 48 struct resource *iomem; 49 50 u8 enabled_wake; 51 u8 suspend_ctrl; 52}; 53 54static const char driver_name[] = "rtc_mrst"; 55 56#define RTC_IRQMASK (RTC_PF | RTC_AF) 57 58static inline int is_intr(u8 rtc_intr) 59{ 60 if (!(rtc_intr & RTC_IRQF)) 61 return 0; 62 return rtc_intr & RTC_IRQMASK; 63} 64 65static inline unsigned char vrtc_is_updating(void) 66{ 67 unsigned char uip; 68 unsigned long flags; 69 70 spin_lock_irqsave(&rtc_lock, flags); 71 uip = (vrtc_cmos_read(RTC_FREQ_SELECT) & RTC_UIP); 72 spin_unlock_irqrestore(&rtc_lock, flags); 73 return uip; 74} 75 76/* 77 * rtc_time's year contains the increment over 1900, but vRTC's YEAR 78 * register can't be programmed to value larger than 0x64, so vRTC 79 * driver chose to use 1972 (1970 is UNIX time start point) as the base, 80 * and does the translation at read/write time. 81 * 82 * Why not just use 1970 as the offset? it's because using 1972 will 83 * make it consistent in leap year setting for both vrtc and low-level 84 * physical rtc devices. Then why not use 1960 as the offset? If we use 85 * 1960, for a device's first use, its YEAR register is 0 and the system 86 * year will be parsed as 1960 which is not a valid UNIX time and will 87 * cause many applications to fail mysteriously. 88 */ 89static int mrst_read_time(struct device *dev, struct rtc_time *time) 90{ 91 unsigned long flags; 92 93 if (vrtc_is_updating()) 94 mdelay(20); 95 96 spin_lock_irqsave(&rtc_lock, flags); 97 time->tm_sec = vrtc_cmos_read(RTC_SECONDS); 98 time->tm_min = vrtc_cmos_read(RTC_MINUTES); 99 time->tm_hour = vrtc_cmos_read(RTC_HOURS); 100 time->tm_mday = vrtc_cmos_read(RTC_DAY_OF_MONTH); 101 time->tm_mon = vrtc_cmos_read(RTC_MONTH); 102 time->tm_year = vrtc_cmos_read(RTC_YEAR); 103 spin_unlock_irqrestore(&rtc_lock, flags); 104 105 /* Adjust for the 1972/1900 */ 106 time->tm_year += 72; 107 time->tm_mon--; 108 return rtc_valid_tm(time); 109} 110 111static int mrst_set_time(struct device *dev, struct rtc_time *time) 112{ 113 int ret; 114 unsigned long flags; 115 unsigned char mon, day, hrs, min, sec; 116 unsigned int yrs; 117 118 yrs = time->tm_year; 119 mon = time->tm_mon + 1; /* tm_mon starts at zero */ 120 day = time->tm_mday; 121 hrs = time->tm_hour; 122 min = time->tm_min; 123 sec = time->tm_sec; 124 125 if (yrs < 72 || yrs > 138) 126 return -EINVAL; 127 yrs -= 72; 128 129 spin_lock_irqsave(&rtc_lock, flags); 130 131 vrtc_cmos_write(yrs, RTC_YEAR); 132 vrtc_cmos_write(mon, RTC_MONTH); 133 vrtc_cmos_write(day, RTC_DAY_OF_MONTH); 134 vrtc_cmos_write(hrs, RTC_HOURS); 135 vrtc_cmos_write(min, RTC_MINUTES); 136 vrtc_cmos_write(sec, RTC_SECONDS); 137 138 spin_unlock_irqrestore(&rtc_lock, flags); 139 140 ret = intel_scu_ipc_simple_command(IPCMSG_VRTC, IPC_CMD_VRTC_SETTIME); 141 return ret; 142} 143 144static int mrst_read_alarm(struct device *dev, struct rtc_wkalrm *t) 145{ 146 struct mrst_rtc *mrst = dev_get_drvdata(dev); 147 unsigned char rtc_control; 148 149 if (mrst->irq <= 0) 150 return -EIO; 151 152 /* vRTC only supports binary mode */ 153 spin_lock_irq(&rtc_lock); 154 t->time.tm_sec = vrtc_cmos_read(RTC_SECONDS_ALARM); 155 t->time.tm_min = vrtc_cmos_read(RTC_MINUTES_ALARM); 156 t->time.tm_hour = vrtc_cmos_read(RTC_HOURS_ALARM); 157 158 rtc_control = vrtc_cmos_read(RTC_CONTROL); 159 spin_unlock_irq(&rtc_lock); 160 161 t->enabled = !!(rtc_control & RTC_AIE); 162 t->pending = 0; 163 164 return 0; 165} 166 167static void mrst_checkintr(struct mrst_rtc *mrst, unsigned char rtc_control) 168{ 169 unsigned char rtc_intr; 170 171 /* 172 * NOTE after changing RTC_xIE bits we always read INTR_FLAGS; 173 * allegedly some older rtcs need that to handle irqs properly 174 */ 175 rtc_intr = vrtc_cmos_read(RTC_INTR_FLAGS); 176 rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF; 177 if (is_intr(rtc_intr)) 178 rtc_update_irq(mrst->rtc, 1, rtc_intr); 179} 180 181static void mrst_irq_enable(struct mrst_rtc *mrst, unsigned char mask) 182{ 183 unsigned char rtc_control; 184 185 /* 186 * Flush any pending IRQ status, notably for update irqs, 187 * before we enable new IRQs 188 */ 189 rtc_control = vrtc_cmos_read(RTC_CONTROL); 190 mrst_checkintr(mrst, rtc_control); 191 192 rtc_control |= mask; 193 vrtc_cmos_write(rtc_control, RTC_CONTROL); 194 195 mrst_checkintr(mrst, rtc_control); 196} 197 198static void mrst_irq_disable(struct mrst_rtc *mrst, unsigned char mask) 199{ 200 unsigned char rtc_control; 201 202 rtc_control = vrtc_cmos_read(RTC_CONTROL); 203 rtc_control &= ~mask; 204 vrtc_cmos_write(rtc_control, RTC_CONTROL); 205 mrst_checkintr(mrst, rtc_control); 206} 207 208static int mrst_set_alarm(struct device *dev, struct rtc_wkalrm *t) 209{ 210 struct mrst_rtc *mrst = dev_get_drvdata(dev); 211 unsigned char hrs, min, sec; 212 int ret = 0; 213 214 if (!mrst->irq) 215 return -EIO; 216 217 hrs = t->time.tm_hour; 218 min = t->time.tm_min; 219 sec = t->time.tm_sec; 220 221 spin_lock_irq(&rtc_lock); 222 /* Next rtc irq must not be from previous alarm setting */ 223 mrst_irq_disable(mrst, RTC_AIE); 224 225 /* Update alarm */ 226 vrtc_cmos_write(hrs, RTC_HOURS_ALARM); 227 vrtc_cmos_write(min, RTC_MINUTES_ALARM); 228 vrtc_cmos_write(sec, RTC_SECONDS_ALARM); 229 230 spin_unlock_irq(&rtc_lock); 231 232 ret = intel_scu_ipc_simple_command(IPCMSG_VRTC, IPC_CMD_VRTC_SETALARM); 233 if (ret) 234 return ret; 235 236 spin_lock_irq(&rtc_lock); 237 if (t->enabled) 238 mrst_irq_enable(mrst, RTC_AIE); 239 240 spin_unlock_irq(&rtc_lock); 241 242 return 0; 243} 244 245/* Currently, the vRTC doesn't support UIE ON/OFF */ 246static int mrst_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) 247{ 248 struct mrst_rtc *mrst = dev_get_drvdata(dev); 249 unsigned long flags; 250 251 spin_lock_irqsave(&rtc_lock, flags); 252 if (enabled) 253 mrst_irq_enable(mrst, RTC_AIE); 254 else 255 mrst_irq_disable(mrst, RTC_AIE); 256 spin_unlock_irqrestore(&rtc_lock, flags); 257 return 0; 258} 259 260 261#if IS_ENABLED(CONFIG_RTC_INTF_PROC) 262 263static int mrst_procfs(struct device *dev, struct seq_file *seq) 264{ 265 unsigned char rtc_control, valid; 266 267 spin_lock_irq(&rtc_lock); 268 rtc_control = vrtc_cmos_read(RTC_CONTROL); 269 valid = vrtc_cmos_read(RTC_VALID); 270 spin_unlock_irq(&rtc_lock); 271 272 seq_printf(seq, 273 "periodic_IRQ\t: %s\n" 274 "alarm\t\t: %s\n" 275 "BCD\t\t: no\n" 276 "periodic_freq\t: daily (not adjustable)\n", 277 (rtc_control & RTC_PIE) ? "on" : "off", 278 (rtc_control & RTC_AIE) ? "on" : "off"); 279 280 return 0; 281} 282 283#else 284#define mrst_procfs NULL 285#endif 286 287static const struct rtc_class_ops mrst_rtc_ops = { 288 .read_time = mrst_read_time, 289 .set_time = mrst_set_time, 290 .read_alarm = mrst_read_alarm, 291 .set_alarm = mrst_set_alarm, 292 .proc = mrst_procfs, 293 .alarm_irq_enable = mrst_rtc_alarm_irq_enable, 294}; 295 296static struct mrst_rtc mrst_rtc; 297 298/* 299 * When vRTC IRQ is captured by SCU FW, FW will clear the AIE bit in 300 * Reg B, so no need for this driver to clear it 301 */ 302static irqreturn_t mrst_rtc_irq(int irq, void *p) 303{ 304 u8 irqstat; 305 306 spin_lock(&rtc_lock); 307 /* This read will clear all IRQ flags inside Reg C */ 308 irqstat = vrtc_cmos_read(RTC_INTR_FLAGS); 309 spin_unlock(&rtc_lock); 310 311 irqstat &= RTC_IRQMASK | RTC_IRQF; 312 if (is_intr(irqstat)) { 313 rtc_update_irq(p, 1, irqstat); 314 return IRQ_HANDLED; 315 } 316 return IRQ_NONE; 317} 318 319static int vrtc_mrst_do_probe(struct device *dev, struct resource *iomem, 320 int rtc_irq) 321{ 322 int retval = 0; 323 unsigned char rtc_control; 324 325 /* There can be only one ... */ 326 if (mrst_rtc.dev) 327 return -EBUSY; 328 329 if (!iomem) 330 return -ENODEV; 331 332 iomem = request_mem_region(iomem->start, resource_size(iomem), 333 driver_name); 334 if (!iomem) { 335 dev_dbg(dev, "i/o mem already in use.\n"); 336 return -EBUSY; 337 } 338 339 mrst_rtc.irq = rtc_irq; 340 mrst_rtc.iomem = iomem; 341 mrst_rtc.dev = dev; 342 dev_set_drvdata(dev, &mrst_rtc); 343 344 mrst_rtc.rtc = rtc_device_register(driver_name, dev, 345 &mrst_rtc_ops, THIS_MODULE); 346 if (IS_ERR(mrst_rtc.rtc)) { 347 retval = PTR_ERR(mrst_rtc.rtc); 348 goto cleanup0; 349 } 350 351 rename_region(iomem, dev_name(&mrst_rtc.rtc->dev)); 352 353 spin_lock_irq(&rtc_lock); 354 mrst_irq_disable(&mrst_rtc, RTC_PIE | RTC_AIE); 355 rtc_control = vrtc_cmos_read(RTC_CONTROL); 356 spin_unlock_irq(&rtc_lock); 357 358 if (!(rtc_control & RTC_24H) || (rtc_control & (RTC_DM_BINARY))) 359 dev_dbg(dev, "TODO: support more than 24-hr BCD mode\n"); 360 361 if (rtc_irq) { 362 retval = request_irq(rtc_irq, mrst_rtc_irq, 363 0, dev_name(&mrst_rtc.rtc->dev), 364 mrst_rtc.rtc); 365 if (retval < 0) { 366 dev_dbg(dev, "IRQ %d is already in use, err %d\n", 367 rtc_irq, retval); 368 goto cleanup1; 369 } 370 } 371 dev_dbg(dev, "initialised\n"); 372 return 0; 373 374cleanup1: 375 rtc_device_unregister(mrst_rtc.rtc); 376cleanup0: 377 mrst_rtc.dev = NULL; 378 release_mem_region(iomem->start, resource_size(iomem)); 379 dev_err(dev, "rtc-mrst: unable to initialise\n"); 380 return retval; 381} 382 383static void rtc_mrst_do_shutdown(void) 384{ 385 spin_lock_irq(&rtc_lock); 386 mrst_irq_disable(&mrst_rtc, RTC_IRQMASK); 387 spin_unlock_irq(&rtc_lock); 388} 389 390static void rtc_mrst_do_remove(struct device *dev) 391{ 392 struct mrst_rtc *mrst = dev_get_drvdata(dev); 393 struct resource *iomem; 394 395 rtc_mrst_do_shutdown(); 396 397 if (mrst->irq) 398 free_irq(mrst->irq, mrst->rtc); 399 400 rtc_device_unregister(mrst->rtc); 401 mrst->rtc = NULL; 402 403 iomem = mrst->iomem; 404 release_mem_region(iomem->start, resource_size(iomem)); 405 mrst->iomem = NULL; 406 407 mrst->dev = NULL; 408} 409 410#ifdef CONFIG_PM_SLEEP 411static int mrst_suspend(struct device *dev) 412{ 413 struct mrst_rtc *mrst = dev_get_drvdata(dev); 414 unsigned char tmp; 415 416 /* Only the alarm might be a wakeup event source */ 417 spin_lock_irq(&rtc_lock); 418 mrst->suspend_ctrl = tmp = vrtc_cmos_read(RTC_CONTROL); 419 if (tmp & (RTC_PIE | RTC_AIE)) { 420 unsigned char mask; 421 422 if (device_may_wakeup(dev)) 423 mask = RTC_IRQMASK & ~RTC_AIE; 424 else 425 mask = RTC_IRQMASK; 426 tmp &= ~mask; 427 vrtc_cmos_write(tmp, RTC_CONTROL); 428 429 mrst_checkintr(mrst, tmp); 430 } 431 spin_unlock_irq(&rtc_lock); 432 433 if (tmp & RTC_AIE) { 434 mrst->enabled_wake = 1; 435 enable_irq_wake(mrst->irq); 436 } 437 438 dev_dbg(&mrst_rtc.rtc->dev, "suspend%s, ctrl %02x\n", 439 (tmp & RTC_AIE) ? ", alarm may wake" : "", 440 tmp); 441 442 return 0; 443} 444 445/* 446 * We want RTC alarms to wake us from the deep power saving state 447 */ 448static inline int mrst_poweroff(struct device *dev) 449{ 450 return mrst_suspend(dev); 451} 452 453static int mrst_resume(struct device *dev) 454{ 455 struct mrst_rtc *mrst = dev_get_drvdata(dev); 456 unsigned char tmp = mrst->suspend_ctrl; 457 458 /* Re-enable any irqs previously active */ 459 if (tmp & RTC_IRQMASK) { 460 unsigned char mask; 461 462 if (mrst->enabled_wake) { 463 disable_irq_wake(mrst->irq); 464 mrst->enabled_wake = 0; 465 } 466 467 spin_lock_irq(&rtc_lock); 468 do { 469 vrtc_cmos_write(tmp, RTC_CONTROL); 470 471 mask = vrtc_cmos_read(RTC_INTR_FLAGS); 472 mask &= (tmp & RTC_IRQMASK) | RTC_IRQF; 473 if (!is_intr(mask)) 474 break; 475 476 rtc_update_irq(mrst->rtc, 1, mask); 477 tmp &= ~RTC_AIE; 478 } while (mask & RTC_AIE); 479 spin_unlock_irq(&rtc_lock); 480 } 481 482 dev_dbg(&mrst_rtc.rtc->dev, "resume, ctrl %02x\n", tmp); 483 484 return 0; 485} 486 487static SIMPLE_DEV_PM_OPS(mrst_pm_ops, mrst_suspend, mrst_resume); 488#define MRST_PM_OPS (&mrst_pm_ops) 489 490#else 491#define MRST_PM_OPS NULL 492 493static inline int mrst_poweroff(struct device *dev) 494{ 495 return -ENOSYS; 496} 497 498#endif 499 500static int vrtc_mrst_platform_probe(struct platform_device *pdev) 501{ 502 return vrtc_mrst_do_probe(&pdev->dev, 503 platform_get_resource(pdev, IORESOURCE_MEM, 0), 504 platform_get_irq(pdev, 0)); 505} 506 507static int vrtc_mrst_platform_remove(struct platform_device *pdev) 508{ 509 rtc_mrst_do_remove(&pdev->dev); 510 return 0; 511} 512 513static void vrtc_mrst_platform_shutdown(struct platform_device *pdev) 514{ 515 if (system_state == SYSTEM_POWER_OFF && !mrst_poweroff(&pdev->dev)) 516 return; 517 518 rtc_mrst_do_shutdown(); 519} 520 521MODULE_ALIAS("platform:vrtc_mrst"); 522 523static struct platform_driver vrtc_mrst_platform_driver = { 524 .probe = vrtc_mrst_platform_probe, 525 .remove = vrtc_mrst_platform_remove, 526 .shutdown = vrtc_mrst_platform_shutdown, 527 .driver = { 528 .name = driver_name, 529 .pm = MRST_PM_OPS, 530 } 531}; 532 533module_platform_driver(vrtc_mrst_platform_driver); 534 535MODULE_AUTHOR("Jacob Pan; Feng Tang"); 536MODULE_DESCRIPTION("Driver for Moorestown virtual RTC"); 537MODULE_LICENSE("GPL");