10146f26145af75d53e12dbf23a36996aff373680Feng Tang/* 20146f26145af75d53e12dbf23a36996aff373680Feng Tang * rtc-mrst.c: Driver for Moorestown virtual RTC 30146f26145af75d53e12dbf23a36996aff373680Feng Tang * 40146f26145af75d53e12dbf23a36996aff373680Feng Tang * (C) Copyright 2009 Intel Corporation 50146f26145af75d53e12dbf23a36996aff373680Feng Tang * Author: Jacob Pan (jacob.jun.pan@intel.com) 60146f26145af75d53e12dbf23a36996aff373680Feng Tang * Feng Tang (feng.tang@intel.com) 70146f26145af75d53e12dbf23a36996aff373680Feng Tang * 80146f26145af75d53e12dbf23a36996aff373680Feng Tang * This program is free software; you can redistribute it and/or 90146f26145af75d53e12dbf23a36996aff373680Feng Tang * modify it under the terms of the GNU General Public License 100146f26145af75d53e12dbf23a36996aff373680Feng Tang * as published by the Free Software Foundation; version 2 110146f26145af75d53e12dbf23a36996aff373680Feng Tang * of the License. 120146f26145af75d53e12dbf23a36996aff373680Feng Tang * 130146f26145af75d53e12dbf23a36996aff373680Feng Tang * Note: 140146f26145af75d53e12dbf23a36996aff373680Feng Tang * VRTC is emulated by system controller firmware, the real HW 150146f26145af75d53e12dbf23a36996aff373680Feng Tang * RTC is located in the PMIC device. SCU FW shadows PMIC RTC 160146f26145af75d53e12dbf23a36996aff373680Feng Tang * in a memory mapped IO space that is visible to the host IA 170146f26145af75d53e12dbf23a36996aff373680Feng Tang * processor. 180146f26145af75d53e12dbf23a36996aff373680Feng Tang * 190146f26145af75d53e12dbf23a36996aff373680Feng Tang * This driver is based upon drivers/rtc/rtc-cmos.c 200146f26145af75d53e12dbf23a36996aff373680Feng Tang */ 210146f26145af75d53e12dbf23a36996aff373680Feng Tang 220146f26145af75d53e12dbf23a36996aff373680Feng Tang/* 230146f26145af75d53e12dbf23a36996aff373680Feng Tang * Note: 240146f26145af75d53e12dbf23a36996aff373680Feng Tang * * vRTC only supports binary mode and 24H mode 250146f26145af75d53e12dbf23a36996aff373680Feng Tang * * vRTC only support PIE and AIE, no UIE, and its PIE only happens 260146f26145af75d53e12dbf23a36996aff373680Feng Tang * at 23:59:59pm everyday, no support for adjustable frequency 270146f26145af75d53e12dbf23a36996aff373680Feng Tang * * Alarm function is also limited to hr/min/sec. 280146f26145af75d53e12dbf23a36996aff373680Feng Tang */ 290146f26145af75d53e12dbf23a36996aff373680Feng Tang 300146f26145af75d53e12dbf23a36996aff373680Feng Tang#include <linux/mod_devicetable.h> 310146f26145af75d53e12dbf23a36996aff373680Feng Tang#include <linux/platform_device.h> 320146f26145af75d53e12dbf23a36996aff373680Feng Tang#include <linux/interrupt.h> 330146f26145af75d53e12dbf23a36996aff373680Feng Tang#include <linux/spinlock.h> 340146f26145af75d53e12dbf23a36996aff373680Feng Tang#include <linux/kernel.h> 350146f26145af75d53e12dbf23a36996aff373680Feng Tang#include <linux/module.h> 360146f26145af75d53e12dbf23a36996aff373680Feng Tang#include <linux/init.h> 370146f26145af75d53e12dbf23a36996aff373680Feng Tang#include <linux/sfi.h> 380146f26145af75d53e12dbf23a36996aff373680Feng Tang 390146f26145af75d53e12dbf23a36996aff373680Feng Tang#include <asm-generic/rtc.h> 400146f26145af75d53e12dbf23a36996aff373680Feng Tang#include <asm/intel_scu_ipc.h> 4105454c26eb3587b56abc5eb139797ac5afb6d77aKuppuswamy Sathyanarayanan#include <asm/intel-mid.h> 4205454c26eb3587b56abc5eb139797ac5afb6d77aKuppuswamy Sathyanarayanan#include <asm/intel_mid_vrtc.h> 430146f26145af75d53e12dbf23a36996aff373680Feng Tang 440146f26145af75d53e12dbf23a36996aff373680Feng Tangstruct mrst_rtc { 450146f26145af75d53e12dbf23a36996aff373680Feng Tang struct rtc_device *rtc; 460146f26145af75d53e12dbf23a36996aff373680Feng Tang struct device *dev; 470146f26145af75d53e12dbf23a36996aff373680Feng Tang int irq; 480146f26145af75d53e12dbf23a36996aff373680Feng Tang struct resource *iomem; 490146f26145af75d53e12dbf23a36996aff373680Feng Tang 500146f26145af75d53e12dbf23a36996aff373680Feng Tang u8 enabled_wake; 510146f26145af75d53e12dbf23a36996aff373680Feng Tang u8 suspend_ctrl; 520146f26145af75d53e12dbf23a36996aff373680Feng Tang}; 530146f26145af75d53e12dbf23a36996aff373680Feng Tang 540146f26145af75d53e12dbf23a36996aff373680Feng Tangstatic const char driver_name[] = "rtc_mrst"; 550146f26145af75d53e12dbf23a36996aff373680Feng Tang 560146f26145af75d53e12dbf23a36996aff373680Feng Tang#define RTC_IRQMASK (RTC_PF | RTC_AF) 570146f26145af75d53e12dbf23a36996aff373680Feng Tang 580146f26145af75d53e12dbf23a36996aff373680Feng Tangstatic inline int is_intr(u8 rtc_intr) 590146f26145af75d53e12dbf23a36996aff373680Feng Tang{ 600146f26145af75d53e12dbf23a36996aff373680Feng Tang if (!(rtc_intr & RTC_IRQF)) 610146f26145af75d53e12dbf23a36996aff373680Feng Tang return 0; 620146f26145af75d53e12dbf23a36996aff373680Feng Tang return rtc_intr & RTC_IRQMASK; 630146f26145af75d53e12dbf23a36996aff373680Feng Tang} 640146f26145af75d53e12dbf23a36996aff373680Feng Tang 65168202c7bf89d7a2abaf8deaf4bbed18a1f7b3a3Feng Tangstatic inline unsigned char vrtc_is_updating(void) 66168202c7bf89d7a2abaf8deaf4bbed18a1f7b3a3Feng Tang{ 67168202c7bf89d7a2abaf8deaf4bbed18a1f7b3a3Feng Tang unsigned char uip; 68168202c7bf89d7a2abaf8deaf4bbed18a1f7b3a3Feng Tang unsigned long flags; 69168202c7bf89d7a2abaf8deaf4bbed18a1f7b3a3Feng Tang 70168202c7bf89d7a2abaf8deaf4bbed18a1f7b3a3Feng Tang spin_lock_irqsave(&rtc_lock, flags); 71168202c7bf89d7a2abaf8deaf4bbed18a1f7b3a3Feng Tang uip = (vrtc_cmos_read(RTC_FREQ_SELECT) & RTC_UIP); 72168202c7bf89d7a2abaf8deaf4bbed18a1f7b3a3Feng Tang spin_unlock_irqrestore(&rtc_lock, flags); 73168202c7bf89d7a2abaf8deaf4bbed18a1f7b3a3Feng Tang return uip; 74168202c7bf89d7a2abaf8deaf4bbed18a1f7b3a3Feng Tang} 75168202c7bf89d7a2abaf8deaf4bbed18a1f7b3a3Feng Tang 760146f26145af75d53e12dbf23a36996aff373680Feng Tang/* 770146f26145af75d53e12dbf23a36996aff373680Feng Tang * rtc_time's year contains the increment over 1900, but vRTC's YEAR 780146f26145af75d53e12dbf23a36996aff373680Feng Tang * register can't be programmed to value larger than 0x64, so vRTC 7957e6319dd61d5ca10fe8dd57bcce8c0e2c480799Feng Tang * driver chose to use 1972 (1970 is UNIX time start point) as the base, 80d3e1884bc585a43674d2cb0d3f0aeeb0ae43bc04Feng Tang * and does the translation at read/write time. 81d3e1884bc585a43674d2cb0d3f0aeeb0ae43bc04Feng Tang * 8257e6319dd61d5ca10fe8dd57bcce8c0e2c480799Feng Tang * Why not just use 1970 as the offset? it's because using 1972 will 83d3e1884bc585a43674d2cb0d3f0aeeb0ae43bc04Feng Tang * make it consistent in leap year setting for both vrtc and low-level 8457e6319dd61d5ca10fe8dd57bcce8c0e2c480799Feng Tang * physical rtc devices. Then why not use 1960 as the offset? If we use 8557e6319dd61d5ca10fe8dd57bcce8c0e2c480799Feng Tang * 1960, for a device's first use, its YEAR register is 0 and the system 8657e6319dd61d5ca10fe8dd57bcce8c0e2c480799Feng Tang * year will be parsed as 1960 which is not a valid UNIX time and will 8757e6319dd61d5ca10fe8dd57bcce8c0e2c480799Feng Tang * cause many applications to fail mysteriously. 880146f26145af75d53e12dbf23a36996aff373680Feng Tang */ 890146f26145af75d53e12dbf23a36996aff373680Feng Tangstatic int mrst_read_time(struct device *dev, struct rtc_time *time) 900146f26145af75d53e12dbf23a36996aff373680Feng Tang{ 910146f26145af75d53e12dbf23a36996aff373680Feng Tang unsigned long flags; 920146f26145af75d53e12dbf23a36996aff373680Feng Tang 93168202c7bf89d7a2abaf8deaf4bbed18a1f7b3a3Feng Tang if (vrtc_is_updating()) 940146f26145af75d53e12dbf23a36996aff373680Feng Tang mdelay(20); 950146f26145af75d53e12dbf23a36996aff373680Feng Tang 960146f26145af75d53e12dbf23a36996aff373680Feng Tang spin_lock_irqsave(&rtc_lock, flags); 970146f26145af75d53e12dbf23a36996aff373680Feng Tang time->tm_sec = vrtc_cmos_read(RTC_SECONDS); 980146f26145af75d53e12dbf23a36996aff373680Feng Tang time->tm_min = vrtc_cmos_read(RTC_MINUTES); 990146f26145af75d53e12dbf23a36996aff373680Feng Tang time->tm_hour = vrtc_cmos_read(RTC_HOURS); 1000146f26145af75d53e12dbf23a36996aff373680Feng Tang time->tm_mday = vrtc_cmos_read(RTC_DAY_OF_MONTH); 1010146f26145af75d53e12dbf23a36996aff373680Feng Tang time->tm_mon = vrtc_cmos_read(RTC_MONTH); 1020146f26145af75d53e12dbf23a36996aff373680Feng Tang time->tm_year = vrtc_cmos_read(RTC_YEAR); 1030146f26145af75d53e12dbf23a36996aff373680Feng Tang spin_unlock_irqrestore(&rtc_lock, flags); 1040146f26145af75d53e12dbf23a36996aff373680Feng Tang 10557e6319dd61d5ca10fe8dd57bcce8c0e2c480799Feng Tang /* Adjust for the 1972/1900 */ 10657e6319dd61d5ca10fe8dd57bcce8c0e2c480799Feng Tang time->tm_year += 72; 1070146f26145af75d53e12dbf23a36996aff373680Feng Tang time->tm_mon--; 10857e6319dd61d5ca10fe8dd57bcce8c0e2c480799Feng Tang return rtc_valid_tm(time); 1090146f26145af75d53e12dbf23a36996aff373680Feng Tang} 1100146f26145af75d53e12dbf23a36996aff373680Feng Tang 1110146f26145af75d53e12dbf23a36996aff373680Feng Tangstatic int mrst_set_time(struct device *dev, struct rtc_time *time) 1120146f26145af75d53e12dbf23a36996aff373680Feng Tang{ 1130146f26145af75d53e12dbf23a36996aff373680Feng Tang int ret; 1140146f26145af75d53e12dbf23a36996aff373680Feng Tang unsigned long flags; 1150146f26145af75d53e12dbf23a36996aff373680Feng Tang unsigned char mon, day, hrs, min, sec; 1160146f26145af75d53e12dbf23a36996aff373680Feng Tang unsigned int yrs; 1170146f26145af75d53e12dbf23a36996aff373680Feng Tang 1180146f26145af75d53e12dbf23a36996aff373680Feng Tang yrs = time->tm_year; 1190146f26145af75d53e12dbf23a36996aff373680Feng Tang mon = time->tm_mon + 1; /* tm_mon starts at zero */ 1200146f26145af75d53e12dbf23a36996aff373680Feng Tang day = time->tm_mday; 1210146f26145af75d53e12dbf23a36996aff373680Feng Tang hrs = time->tm_hour; 1220146f26145af75d53e12dbf23a36996aff373680Feng Tang min = time->tm_min; 1230146f26145af75d53e12dbf23a36996aff373680Feng Tang sec = time->tm_sec; 1240146f26145af75d53e12dbf23a36996aff373680Feng Tang 12557e6319dd61d5ca10fe8dd57bcce8c0e2c480799Feng Tang if (yrs < 72 || yrs > 138) 1260146f26145af75d53e12dbf23a36996aff373680Feng Tang return -EINVAL; 12757e6319dd61d5ca10fe8dd57bcce8c0e2c480799Feng Tang yrs -= 72; 1280146f26145af75d53e12dbf23a36996aff373680Feng Tang 1290146f26145af75d53e12dbf23a36996aff373680Feng Tang spin_lock_irqsave(&rtc_lock, flags); 1300146f26145af75d53e12dbf23a36996aff373680Feng Tang 1310146f26145af75d53e12dbf23a36996aff373680Feng Tang vrtc_cmos_write(yrs, RTC_YEAR); 1320146f26145af75d53e12dbf23a36996aff373680Feng Tang vrtc_cmos_write(mon, RTC_MONTH); 1330146f26145af75d53e12dbf23a36996aff373680Feng Tang vrtc_cmos_write(day, RTC_DAY_OF_MONTH); 1340146f26145af75d53e12dbf23a36996aff373680Feng Tang vrtc_cmos_write(hrs, RTC_HOURS); 1350146f26145af75d53e12dbf23a36996aff373680Feng Tang vrtc_cmos_write(min, RTC_MINUTES); 1360146f26145af75d53e12dbf23a36996aff373680Feng Tang vrtc_cmos_write(sec, RTC_SECONDS); 1370146f26145af75d53e12dbf23a36996aff373680Feng Tang 1380146f26145af75d53e12dbf23a36996aff373680Feng Tang spin_unlock_irqrestore(&rtc_lock, flags); 1390146f26145af75d53e12dbf23a36996aff373680Feng Tang 1400146f26145af75d53e12dbf23a36996aff373680Feng Tang ret = intel_scu_ipc_simple_command(IPCMSG_VRTC, IPC_CMD_VRTC_SETTIME); 1410146f26145af75d53e12dbf23a36996aff373680Feng Tang return ret; 1420146f26145af75d53e12dbf23a36996aff373680Feng Tang} 1430146f26145af75d53e12dbf23a36996aff373680Feng Tang 1440146f26145af75d53e12dbf23a36996aff373680Feng Tangstatic int mrst_read_alarm(struct device *dev, struct rtc_wkalrm *t) 1450146f26145af75d53e12dbf23a36996aff373680Feng Tang{ 1460146f26145af75d53e12dbf23a36996aff373680Feng Tang struct mrst_rtc *mrst = dev_get_drvdata(dev); 1470146f26145af75d53e12dbf23a36996aff373680Feng Tang unsigned char rtc_control; 1480146f26145af75d53e12dbf23a36996aff373680Feng Tang 1490146f26145af75d53e12dbf23a36996aff373680Feng Tang if (mrst->irq <= 0) 1500146f26145af75d53e12dbf23a36996aff373680Feng Tang return -EIO; 1510146f26145af75d53e12dbf23a36996aff373680Feng Tang 1520146f26145af75d53e12dbf23a36996aff373680Feng Tang /* Basic alarms only support hour, minute, and seconds fields. 1530146f26145af75d53e12dbf23a36996aff373680Feng Tang * Some also support day and month, for alarms up to a year in 1540146f26145af75d53e12dbf23a36996aff373680Feng Tang * the future. 1550146f26145af75d53e12dbf23a36996aff373680Feng Tang */ 1560146f26145af75d53e12dbf23a36996aff373680Feng Tang t->time.tm_mday = -1; 1570146f26145af75d53e12dbf23a36996aff373680Feng Tang t->time.tm_mon = -1; 1580146f26145af75d53e12dbf23a36996aff373680Feng Tang t->time.tm_year = -1; 1590146f26145af75d53e12dbf23a36996aff373680Feng Tang 1600146f26145af75d53e12dbf23a36996aff373680Feng Tang /* vRTC only supports binary mode */ 1610146f26145af75d53e12dbf23a36996aff373680Feng Tang spin_lock_irq(&rtc_lock); 1620146f26145af75d53e12dbf23a36996aff373680Feng Tang t->time.tm_sec = vrtc_cmos_read(RTC_SECONDS_ALARM); 1630146f26145af75d53e12dbf23a36996aff373680Feng Tang t->time.tm_min = vrtc_cmos_read(RTC_MINUTES_ALARM); 1640146f26145af75d53e12dbf23a36996aff373680Feng Tang t->time.tm_hour = vrtc_cmos_read(RTC_HOURS_ALARM); 1650146f26145af75d53e12dbf23a36996aff373680Feng Tang 1660146f26145af75d53e12dbf23a36996aff373680Feng Tang rtc_control = vrtc_cmos_read(RTC_CONTROL); 1670146f26145af75d53e12dbf23a36996aff373680Feng Tang spin_unlock_irq(&rtc_lock); 1680146f26145af75d53e12dbf23a36996aff373680Feng Tang 1690146f26145af75d53e12dbf23a36996aff373680Feng Tang t->enabled = !!(rtc_control & RTC_AIE); 1700146f26145af75d53e12dbf23a36996aff373680Feng Tang t->pending = 0; 1710146f26145af75d53e12dbf23a36996aff373680Feng Tang 1720146f26145af75d53e12dbf23a36996aff373680Feng Tang return 0; 1730146f26145af75d53e12dbf23a36996aff373680Feng Tang} 1740146f26145af75d53e12dbf23a36996aff373680Feng Tang 1750146f26145af75d53e12dbf23a36996aff373680Feng Tangstatic void mrst_checkintr(struct mrst_rtc *mrst, unsigned char rtc_control) 1760146f26145af75d53e12dbf23a36996aff373680Feng Tang{ 1770146f26145af75d53e12dbf23a36996aff373680Feng Tang unsigned char rtc_intr; 1780146f26145af75d53e12dbf23a36996aff373680Feng Tang 1790146f26145af75d53e12dbf23a36996aff373680Feng Tang /* 1800146f26145af75d53e12dbf23a36996aff373680Feng Tang * NOTE after changing RTC_xIE bits we always read INTR_FLAGS; 1810146f26145af75d53e12dbf23a36996aff373680Feng Tang * allegedly some older rtcs need that to handle irqs properly 1820146f26145af75d53e12dbf23a36996aff373680Feng Tang */ 1830146f26145af75d53e12dbf23a36996aff373680Feng Tang rtc_intr = vrtc_cmos_read(RTC_INTR_FLAGS); 1840146f26145af75d53e12dbf23a36996aff373680Feng Tang rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF; 1850146f26145af75d53e12dbf23a36996aff373680Feng Tang if (is_intr(rtc_intr)) 1860146f26145af75d53e12dbf23a36996aff373680Feng Tang rtc_update_irq(mrst->rtc, 1, rtc_intr); 1870146f26145af75d53e12dbf23a36996aff373680Feng Tang} 1880146f26145af75d53e12dbf23a36996aff373680Feng Tang 1890146f26145af75d53e12dbf23a36996aff373680Feng Tangstatic void mrst_irq_enable(struct mrst_rtc *mrst, unsigned char mask) 1900146f26145af75d53e12dbf23a36996aff373680Feng Tang{ 1910146f26145af75d53e12dbf23a36996aff373680Feng Tang unsigned char rtc_control; 1920146f26145af75d53e12dbf23a36996aff373680Feng Tang 1930146f26145af75d53e12dbf23a36996aff373680Feng Tang /* 1940146f26145af75d53e12dbf23a36996aff373680Feng Tang * Flush any pending IRQ status, notably for update irqs, 1950146f26145af75d53e12dbf23a36996aff373680Feng Tang * before we enable new IRQs 1960146f26145af75d53e12dbf23a36996aff373680Feng Tang */ 1970146f26145af75d53e12dbf23a36996aff373680Feng Tang rtc_control = vrtc_cmos_read(RTC_CONTROL); 1980146f26145af75d53e12dbf23a36996aff373680Feng Tang mrst_checkintr(mrst, rtc_control); 1990146f26145af75d53e12dbf23a36996aff373680Feng Tang 2000146f26145af75d53e12dbf23a36996aff373680Feng Tang rtc_control |= mask; 2010146f26145af75d53e12dbf23a36996aff373680Feng Tang vrtc_cmos_write(rtc_control, RTC_CONTROL); 2020146f26145af75d53e12dbf23a36996aff373680Feng Tang 2030146f26145af75d53e12dbf23a36996aff373680Feng Tang mrst_checkintr(mrst, rtc_control); 2040146f26145af75d53e12dbf23a36996aff373680Feng Tang} 2050146f26145af75d53e12dbf23a36996aff373680Feng Tang 2060146f26145af75d53e12dbf23a36996aff373680Feng Tangstatic void mrst_irq_disable(struct mrst_rtc *mrst, unsigned char mask) 2070146f26145af75d53e12dbf23a36996aff373680Feng Tang{ 2080146f26145af75d53e12dbf23a36996aff373680Feng Tang unsigned char rtc_control; 2090146f26145af75d53e12dbf23a36996aff373680Feng Tang 2100146f26145af75d53e12dbf23a36996aff373680Feng Tang rtc_control = vrtc_cmos_read(RTC_CONTROL); 2110146f26145af75d53e12dbf23a36996aff373680Feng Tang rtc_control &= ~mask; 2120146f26145af75d53e12dbf23a36996aff373680Feng Tang vrtc_cmos_write(rtc_control, RTC_CONTROL); 2130146f26145af75d53e12dbf23a36996aff373680Feng Tang mrst_checkintr(mrst, rtc_control); 2140146f26145af75d53e12dbf23a36996aff373680Feng Tang} 2150146f26145af75d53e12dbf23a36996aff373680Feng Tang 2160146f26145af75d53e12dbf23a36996aff373680Feng Tangstatic int mrst_set_alarm(struct device *dev, struct rtc_wkalrm *t) 2170146f26145af75d53e12dbf23a36996aff373680Feng Tang{ 2180146f26145af75d53e12dbf23a36996aff373680Feng Tang struct mrst_rtc *mrst = dev_get_drvdata(dev); 2190146f26145af75d53e12dbf23a36996aff373680Feng Tang unsigned char hrs, min, sec; 2200146f26145af75d53e12dbf23a36996aff373680Feng Tang int ret = 0; 2210146f26145af75d53e12dbf23a36996aff373680Feng Tang 2220146f26145af75d53e12dbf23a36996aff373680Feng Tang if (!mrst->irq) 2230146f26145af75d53e12dbf23a36996aff373680Feng Tang return -EIO; 2240146f26145af75d53e12dbf23a36996aff373680Feng Tang 2250146f26145af75d53e12dbf23a36996aff373680Feng Tang hrs = t->time.tm_hour; 2260146f26145af75d53e12dbf23a36996aff373680Feng Tang min = t->time.tm_min; 2270146f26145af75d53e12dbf23a36996aff373680Feng Tang sec = t->time.tm_sec; 2280146f26145af75d53e12dbf23a36996aff373680Feng Tang 2290146f26145af75d53e12dbf23a36996aff373680Feng Tang spin_lock_irq(&rtc_lock); 2300146f26145af75d53e12dbf23a36996aff373680Feng Tang /* Next rtc irq must not be from previous alarm setting */ 2310146f26145af75d53e12dbf23a36996aff373680Feng Tang mrst_irq_disable(mrst, RTC_AIE); 2320146f26145af75d53e12dbf23a36996aff373680Feng Tang 2330146f26145af75d53e12dbf23a36996aff373680Feng Tang /* Update alarm */ 2340146f26145af75d53e12dbf23a36996aff373680Feng Tang vrtc_cmos_write(hrs, RTC_HOURS_ALARM); 2350146f26145af75d53e12dbf23a36996aff373680Feng Tang vrtc_cmos_write(min, RTC_MINUTES_ALARM); 2360146f26145af75d53e12dbf23a36996aff373680Feng Tang vrtc_cmos_write(sec, RTC_SECONDS_ALARM); 2370146f26145af75d53e12dbf23a36996aff373680Feng Tang 2380146f26145af75d53e12dbf23a36996aff373680Feng Tang spin_unlock_irq(&rtc_lock); 2390146f26145af75d53e12dbf23a36996aff373680Feng Tang 2400146f26145af75d53e12dbf23a36996aff373680Feng Tang ret = intel_scu_ipc_simple_command(IPCMSG_VRTC, IPC_CMD_VRTC_SETALARM); 2410146f26145af75d53e12dbf23a36996aff373680Feng Tang if (ret) 2420146f26145af75d53e12dbf23a36996aff373680Feng Tang return ret; 2430146f26145af75d53e12dbf23a36996aff373680Feng Tang 2440146f26145af75d53e12dbf23a36996aff373680Feng Tang spin_lock_irq(&rtc_lock); 2450146f26145af75d53e12dbf23a36996aff373680Feng Tang if (t->enabled) 2460146f26145af75d53e12dbf23a36996aff373680Feng Tang mrst_irq_enable(mrst, RTC_AIE); 2470146f26145af75d53e12dbf23a36996aff373680Feng Tang 2480146f26145af75d53e12dbf23a36996aff373680Feng Tang spin_unlock_irq(&rtc_lock); 2490146f26145af75d53e12dbf23a36996aff373680Feng Tang 2500146f26145af75d53e12dbf23a36996aff373680Feng Tang return 0; 2510146f26145af75d53e12dbf23a36996aff373680Feng Tang} 2520146f26145af75d53e12dbf23a36996aff373680Feng Tang 2530146f26145af75d53e12dbf23a36996aff373680Feng Tang/* Currently, the vRTC doesn't support UIE ON/OFF */ 25416380c153a69c3784d2afaddfe0a22f353046cf6John Stultzstatic int mrst_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) 2550146f26145af75d53e12dbf23a36996aff373680Feng Tang{ 2560146f26145af75d53e12dbf23a36996aff373680Feng Tang struct mrst_rtc *mrst = dev_get_drvdata(dev); 2570146f26145af75d53e12dbf23a36996aff373680Feng Tang unsigned long flags; 2580146f26145af75d53e12dbf23a36996aff373680Feng Tang 2590146f26145af75d53e12dbf23a36996aff373680Feng Tang spin_lock_irqsave(&rtc_lock, flags); 26016380c153a69c3784d2afaddfe0a22f353046cf6John Stultz if (enabled) 2610146f26145af75d53e12dbf23a36996aff373680Feng Tang mrst_irq_enable(mrst, RTC_AIE); 26216380c153a69c3784d2afaddfe0a22f353046cf6John Stultz else 26316380c153a69c3784d2afaddfe0a22f353046cf6John Stultz mrst_irq_disable(mrst, RTC_AIE); 2640146f26145af75d53e12dbf23a36996aff373680Feng Tang spin_unlock_irqrestore(&rtc_lock, flags); 2650146f26145af75d53e12dbf23a36996aff373680Feng Tang return 0; 2660146f26145af75d53e12dbf23a36996aff373680Feng Tang} 2670146f26145af75d53e12dbf23a36996aff373680Feng Tang 2680146f26145af75d53e12dbf23a36996aff373680Feng Tang 2690146f26145af75d53e12dbf23a36996aff373680Feng Tang#if defined(CONFIG_RTC_INTF_PROC) || defined(CONFIG_RTC_INTF_PROC_MODULE) 2700146f26145af75d53e12dbf23a36996aff373680Feng Tang 2710146f26145af75d53e12dbf23a36996aff373680Feng Tangstatic int mrst_procfs(struct device *dev, struct seq_file *seq) 2720146f26145af75d53e12dbf23a36996aff373680Feng Tang{ 2730146f26145af75d53e12dbf23a36996aff373680Feng Tang unsigned char rtc_control, valid; 2740146f26145af75d53e12dbf23a36996aff373680Feng Tang 2750146f26145af75d53e12dbf23a36996aff373680Feng Tang spin_lock_irq(&rtc_lock); 2760146f26145af75d53e12dbf23a36996aff373680Feng Tang rtc_control = vrtc_cmos_read(RTC_CONTROL); 2770146f26145af75d53e12dbf23a36996aff373680Feng Tang valid = vrtc_cmos_read(RTC_VALID); 2780146f26145af75d53e12dbf23a36996aff373680Feng Tang spin_unlock_irq(&rtc_lock); 2790146f26145af75d53e12dbf23a36996aff373680Feng Tang 2800146f26145af75d53e12dbf23a36996aff373680Feng Tang return seq_printf(seq, 2810146f26145af75d53e12dbf23a36996aff373680Feng Tang "periodic_IRQ\t: %s\n" 2820146f26145af75d53e12dbf23a36996aff373680Feng Tang "alarm\t\t: %s\n" 2830146f26145af75d53e12dbf23a36996aff373680Feng Tang "BCD\t\t: no\n" 2840146f26145af75d53e12dbf23a36996aff373680Feng Tang "periodic_freq\t: daily (not adjustable)\n", 2850146f26145af75d53e12dbf23a36996aff373680Feng Tang (rtc_control & RTC_PIE) ? "on" : "off", 2860146f26145af75d53e12dbf23a36996aff373680Feng Tang (rtc_control & RTC_AIE) ? "on" : "off"); 2870146f26145af75d53e12dbf23a36996aff373680Feng Tang} 2880146f26145af75d53e12dbf23a36996aff373680Feng Tang 2890146f26145af75d53e12dbf23a36996aff373680Feng Tang#else 2900146f26145af75d53e12dbf23a36996aff373680Feng Tang#define mrst_procfs NULL 2910146f26145af75d53e12dbf23a36996aff373680Feng Tang#endif 2920146f26145af75d53e12dbf23a36996aff373680Feng Tang 2930146f26145af75d53e12dbf23a36996aff373680Feng Tangstatic const struct rtc_class_ops mrst_rtc_ops = { 2940146f26145af75d53e12dbf23a36996aff373680Feng Tang .read_time = mrst_read_time, 2950146f26145af75d53e12dbf23a36996aff373680Feng Tang .set_time = mrst_set_time, 2960146f26145af75d53e12dbf23a36996aff373680Feng Tang .read_alarm = mrst_read_alarm, 2970146f26145af75d53e12dbf23a36996aff373680Feng Tang .set_alarm = mrst_set_alarm, 2980146f26145af75d53e12dbf23a36996aff373680Feng Tang .proc = mrst_procfs, 29916380c153a69c3784d2afaddfe0a22f353046cf6John Stultz .alarm_irq_enable = mrst_rtc_alarm_irq_enable, 3000146f26145af75d53e12dbf23a36996aff373680Feng Tang}; 3010146f26145af75d53e12dbf23a36996aff373680Feng Tang 3020146f26145af75d53e12dbf23a36996aff373680Feng Tangstatic struct mrst_rtc mrst_rtc; 3030146f26145af75d53e12dbf23a36996aff373680Feng Tang 3040146f26145af75d53e12dbf23a36996aff373680Feng Tang/* 3050146f26145af75d53e12dbf23a36996aff373680Feng Tang * When vRTC IRQ is captured by SCU FW, FW will clear the AIE bit in 3060146f26145af75d53e12dbf23a36996aff373680Feng Tang * Reg B, so no need for this driver to clear it 3070146f26145af75d53e12dbf23a36996aff373680Feng Tang */ 3080146f26145af75d53e12dbf23a36996aff373680Feng Tangstatic irqreturn_t mrst_rtc_irq(int irq, void *p) 3090146f26145af75d53e12dbf23a36996aff373680Feng Tang{ 3100146f26145af75d53e12dbf23a36996aff373680Feng Tang u8 irqstat; 3110146f26145af75d53e12dbf23a36996aff373680Feng Tang 3120146f26145af75d53e12dbf23a36996aff373680Feng Tang spin_lock(&rtc_lock); 3130146f26145af75d53e12dbf23a36996aff373680Feng Tang /* This read will clear all IRQ flags inside Reg C */ 3140146f26145af75d53e12dbf23a36996aff373680Feng Tang irqstat = vrtc_cmos_read(RTC_INTR_FLAGS); 3150146f26145af75d53e12dbf23a36996aff373680Feng Tang spin_unlock(&rtc_lock); 3160146f26145af75d53e12dbf23a36996aff373680Feng Tang 3170146f26145af75d53e12dbf23a36996aff373680Feng Tang irqstat &= RTC_IRQMASK | RTC_IRQF; 3180146f26145af75d53e12dbf23a36996aff373680Feng Tang if (is_intr(irqstat)) { 3190146f26145af75d53e12dbf23a36996aff373680Feng Tang rtc_update_irq(p, 1, irqstat); 3200146f26145af75d53e12dbf23a36996aff373680Feng Tang return IRQ_HANDLED; 3210146f26145af75d53e12dbf23a36996aff373680Feng Tang } 3220146f26145af75d53e12dbf23a36996aff373680Feng Tang return IRQ_NONE; 3230146f26145af75d53e12dbf23a36996aff373680Feng Tang} 3240146f26145af75d53e12dbf23a36996aff373680Feng Tang 3255a167f4543e45d45c5672a5cd6cb8ba5ddf4f3eaGreg Kroah-Hartmanstatic int vrtc_mrst_do_probe(struct device *dev, struct resource *iomem, 3265a167f4543e45d45c5672a5cd6cb8ba5ddf4f3eaGreg Kroah-Hartman int rtc_irq) 3270146f26145af75d53e12dbf23a36996aff373680Feng Tang{ 3280146f26145af75d53e12dbf23a36996aff373680Feng Tang int retval = 0; 3290146f26145af75d53e12dbf23a36996aff373680Feng Tang unsigned char rtc_control; 3300146f26145af75d53e12dbf23a36996aff373680Feng Tang 3310146f26145af75d53e12dbf23a36996aff373680Feng Tang /* There can be only one ... */ 3320146f26145af75d53e12dbf23a36996aff373680Feng Tang if (mrst_rtc.dev) 3330146f26145af75d53e12dbf23a36996aff373680Feng Tang return -EBUSY; 3340146f26145af75d53e12dbf23a36996aff373680Feng Tang 3350146f26145af75d53e12dbf23a36996aff373680Feng Tang if (!iomem) 3360146f26145af75d53e12dbf23a36996aff373680Feng Tang return -ENODEV; 3370146f26145af75d53e12dbf23a36996aff373680Feng Tang 33828f65c11f2ffb3957259dece647a24f8ad2e241bJoe Perches iomem = request_mem_region(iomem->start, resource_size(iomem), 33928f65c11f2ffb3957259dece647a24f8ad2e241bJoe Perches driver_name); 3400146f26145af75d53e12dbf23a36996aff373680Feng Tang if (!iomem) { 3410146f26145af75d53e12dbf23a36996aff373680Feng Tang dev_dbg(dev, "i/o mem already in use.\n"); 3420146f26145af75d53e12dbf23a36996aff373680Feng Tang return -EBUSY; 3430146f26145af75d53e12dbf23a36996aff373680Feng Tang } 3440146f26145af75d53e12dbf23a36996aff373680Feng Tang 3450146f26145af75d53e12dbf23a36996aff373680Feng Tang mrst_rtc.irq = rtc_irq; 3460146f26145af75d53e12dbf23a36996aff373680Feng Tang mrst_rtc.iomem = iomem; 347de97a21a23dda34f1754a748560dede139e6bfc2Feng Tang mrst_rtc.dev = dev; 348de97a21a23dda34f1754a748560dede139e6bfc2Feng Tang dev_set_drvdata(dev, &mrst_rtc); 3490146f26145af75d53e12dbf23a36996aff373680Feng Tang 3500146f26145af75d53e12dbf23a36996aff373680Feng Tang mrst_rtc.rtc = rtc_device_register(driver_name, dev, 3510146f26145af75d53e12dbf23a36996aff373680Feng Tang &mrst_rtc_ops, THIS_MODULE); 3520146f26145af75d53e12dbf23a36996aff373680Feng Tang if (IS_ERR(mrst_rtc.rtc)) { 3530146f26145af75d53e12dbf23a36996aff373680Feng Tang retval = PTR_ERR(mrst_rtc.rtc); 3540146f26145af75d53e12dbf23a36996aff373680Feng Tang goto cleanup0; 3550146f26145af75d53e12dbf23a36996aff373680Feng Tang } 3560146f26145af75d53e12dbf23a36996aff373680Feng Tang 3570146f26145af75d53e12dbf23a36996aff373680Feng Tang rename_region(iomem, dev_name(&mrst_rtc.rtc->dev)); 3580146f26145af75d53e12dbf23a36996aff373680Feng Tang 3590146f26145af75d53e12dbf23a36996aff373680Feng Tang spin_lock_irq(&rtc_lock); 3600146f26145af75d53e12dbf23a36996aff373680Feng Tang mrst_irq_disable(&mrst_rtc, RTC_PIE | RTC_AIE); 3610146f26145af75d53e12dbf23a36996aff373680Feng Tang rtc_control = vrtc_cmos_read(RTC_CONTROL); 3620146f26145af75d53e12dbf23a36996aff373680Feng Tang spin_unlock_irq(&rtc_lock); 3630146f26145af75d53e12dbf23a36996aff373680Feng Tang 3640146f26145af75d53e12dbf23a36996aff373680Feng Tang if (!(rtc_control & RTC_24H) || (rtc_control & (RTC_DM_BINARY))) 3650146f26145af75d53e12dbf23a36996aff373680Feng Tang dev_dbg(dev, "TODO: support more than 24-hr BCD mode\n"); 3660146f26145af75d53e12dbf23a36996aff373680Feng Tang 3670146f26145af75d53e12dbf23a36996aff373680Feng Tang if (rtc_irq) { 3680146f26145af75d53e12dbf23a36996aff373680Feng Tang retval = request_irq(rtc_irq, mrst_rtc_irq, 3692f6e5f9458646263d3d9ffadd5e11e3d8d15a7d0Yong Zhang 0, dev_name(&mrst_rtc.rtc->dev), 3700146f26145af75d53e12dbf23a36996aff373680Feng Tang mrst_rtc.rtc); 3710146f26145af75d53e12dbf23a36996aff373680Feng Tang if (retval < 0) { 3720146f26145af75d53e12dbf23a36996aff373680Feng Tang dev_dbg(dev, "IRQ %d is already in use, err %d\n", 3730146f26145af75d53e12dbf23a36996aff373680Feng Tang rtc_irq, retval); 3740146f26145af75d53e12dbf23a36996aff373680Feng Tang goto cleanup1; 3750146f26145af75d53e12dbf23a36996aff373680Feng Tang } 3760146f26145af75d53e12dbf23a36996aff373680Feng Tang } 3770146f26145af75d53e12dbf23a36996aff373680Feng Tang dev_dbg(dev, "initialised\n"); 3780146f26145af75d53e12dbf23a36996aff373680Feng Tang return 0; 3790146f26145af75d53e12dbf23a36996aff373680Feng Tang 3800146f26145af75d53e12dbf23a36996aff373680Feng Tangcleanup1: 3810146f26145af75d53e12dbf23a36996aff373680Feng Tang rtc_device_unregister(mrst_rtc.rtc); 3820146f26145af75d53e12dbf23a36996aff373680Feng Tangcleanup0: 383de97a21a23dda34f1754a748560dede139e6bfc2Feng Tang mrst_rtc.dev = NULL; 384c258f9a0aab09366070f3c9283070edead23d4cfJulia Lawall release_mem_region(iomem->start, resource_size(iomem)); 3850146f26145af75d53e12dbf23a36996aff373680Feng Tang dev_err(dev, "rtc-mrst: unable to initialise\n"); 3860146f26145af75d53e12dbf23a36996aff373680Feng Tang return retval; 3870146f26145af75d53e12dbf23a36996aff373680Feng Tang} 3880146f26145af75d53e12dbf23a36996aff373680Feng Tang 3890146f26145af75d53e12dbf23a36996aff373680Feng Tangstatic void rtc_mrst_do_shutdown(void) 3900146f26145af75d53e12dbf23a36996aff373680Feng Tang{ 3910146f26145af75d53e12dbf23a36996aff373680Feng Tang spin_lock_irq(&rtc_lock); 3920146f26145af75d53e12dbf23a36996aff373680Feng Tang mrst_irq_disable(&mrst_rtc, RTC_IRQMASK); 3930146f26145af75d53e12dbf23a36996aff373680Feng Tang spin_unlock_irq(&rtc_lock); 3940146f26145af75d53e12dbf23a36996aff373680Feng Tang} 3950146f26145af75d53e12dbf23a36996aff373680Feng Tang 3965a167f4543e45d45c5672a5cd6cb8ba5ddf4f3eaGreg Kroah-Hartmanstatic void rtc_mrst_do_remove(struct device *dev) 3970146f26145af75d53e12dbf23a36996aff373680Feng Tang{ 3980146f26145af75d53e12dbf23a36996aff373680Feng Tang struct mrst_rtc *mrst = dev_get_drvdata(dev); 3990146f26145af75d53e12dbf23a36996aff373680Feng Tang struct resource *iomem; 4000146f26145af75d53e12dbf23a36996aff373680Feng Tang 4010146f26145af75d53e12dbf23a36996aff373680Feng Tang rtc_mrst_do_shutdown(); 4020146f26145af75d53e12dbf23a36996aff373680Feng Tang 4030146f26145af75d53e12dbf23a36996aff373680Feng Tang if (mrst->irq) 4040146f26145af75d53e12dbf23a36996aff373680Feng Tang free_irq(mrst->irq, mrst->rtc); 4050146f26145af75d53e12dbf23a36996aff373680Feng Tang 4060146f26145af75d53e12dbf23a36996aff373680Feng Tang rtc_device_unregister(mrst->rtc); 4070146f26145af75d53e12dbf23a36996aff373680Feng Tang mrst->rtc = NULL; 4080146f26145af75d53e12dbf23a36996aff373680Feng Tang 4090146f26145af75d53e12dbf23a36996aff373680Feng Tang iomem = mrst->iomem; 410c258f9a0aab09366070f3c9283070edead23d4cfJulia Lawall release_mem_region(iomem->start, resource_size(iomem)); 4110146f26145af75d53e12dbf23a36996aff373680Feng Tang mrst->iomem = NULL; 4120146f26145af75d53e12dbf23a36996aff373680Feng Tang 4130146f26145af75d53e12dbf23a36996aff373680Feng Tang mrst->dev = NULL; 4140146f26145af75d53e12dbf23a36996aff373680Feng Tang} 4150146f26145af75d53e12dbf23a36996aff373680Feng Tang 4160146f26145af75d53e12dbf23a36996aff373680Feng Tang#ifdef CONFIG_PM 4170146f26145af75d53e12dbf23a36996aff373680Feng Tangstatic int mrst_suspend(struct device *dev, pm_message_t mesg) 4180146f26145af75d53e12dbf23a36996aff373680Feng Tang{ 4190146f26145af75d53e12dbf23a36996aff373680Feng Tang struct mrst_rtc *mrst = dev_get_drvdata(dev); 4200146f26145af75d53e12dbf23a36996aff373680Feng Tang unsigned char tmp; 4210146f26145af75d53e12dbf23a36996aff373680Feng Tang 4220146f26145af75d53e12dbf23a36996aff373680Feng Tang /* Only the alarm might be a wakeup event source */ 4230146f26145af75d53e12dbf23a36996aff373680Feng Tang spin_lock_irq(&rtc_lock); 4240146f26145af75d53e12dbf23a36996aff373680Feng Tang mrst->suspend_ctrl = tmp = vrtc_cmos_read(RTC_CONTROL); 4250146f26145af75d53e12dbf23a36996aff373680Feng Tang if (tmp & (RTC_PIE | RTC_AIE)) { 4260146f26145af75d53e12dbf23a36996aff373680Feng Tang unsigned char mask; 4270146f26145af75d53e12dbf23a36996aff373680Feng Tang 4280146f26145af75d53e12dbf23a36996aff373680Feng Tang if (device_may_wakeup(dev)) 4290146f26145af75d53e12dbf23a36996aff373680Feng Tang mask = RTC_IRQMASK & ~RTC_AIE; 4300146f26145af75d53e12dbf23a36996aff373680Feng Tang else 4310146f26145af75d53e12dbf23a36996aff373680Feng Tang mask = RTC_IRQMASK; 4320146f26145af75d53e12dbf23a36996aff373680Feng Tang tmp &= ~mask; 4330146f26145af75d53e12dbf23a36996aff373680Feng Tang vrtc_cmos_write(tmp, RTC_CONTROL); 4340146f26145af75d53e12dbf23a36996aff373680Feng Tang 4350146f26145af75d53e12dbf23a36996aff373680Feng Tang mrst_checkintr(mrst, tmp); 4360146f26145af75d53e12dbf23a36996aff373680Feng Tang } 4370146f26145af75d53e12dbf23a36996aff373680Feng Tang spin_unlock_irq(&rtc_lock); 4380146f26145af75d53e12dbf23a36996aff373680Feng Tang 4390146f26145af75d53e12dbf23a36996aff373680Feng Tang if (tmp & RTC_AIE) { 4400146f26145af75d53e12dbf23a36996aff373680Feng Tang mrst->enabled_wake = 1; 4410146f26145af75d53e12dbf23a36996aff373680Feng Tang enable_irq_wake(mrst->irq); 4420146f26145af75d53e12dbf23a36996aff373680Feng Tang } 4430146f26145af75d53e12dbf23a36996aff373680Feng Tang 4440146f26145af75d53e12dbf23a36996aff373680Feng Tang dev_dbg(&mrst_rtc.rtc->dev, "suspend%s, ctrl %02x\n", 4450146f26145af75d53e12dbf23a36996aff373680Feng Tang (tmp & RTC_AIE) ? ", alarm may wake" : "", 4460146f26145af75d53e12dbf23a36996aff373680Feng Tang tmp); 4470146f26145af75d53e12dbf23a36996aff373680Feng Tang 4480146f26145af75d53e12dbf23a36996aff373680Feng Tang return 0; 4490146f26145af75d53e12dbf23a36996aff373680Feng Tang} 4500146f26145af75d53e12dbf23a36996aff373680Feng Tang 4510146f26145af75d53e12dbf23a36996aff373680Feng Tang/* 4520146f26145af75d53e12dbf23a36996aff373680Feng Tang * We want RTC alarms to wake us from the deep power saving state 4530146f26145af75d53e12dbf23a36996aff373680Feng Tang */ 4540146f26145af75d53e12dbf23a36996aff373680Feng Tangstatic inline int mrst_poweroff(struct device *dev) 4550146f26145af75d53e12dbf23a36996aff373680Feng Tang{ 4560146f26145af75d53e12dbf23a36996aff373680Feng Tang return mrst_suspend(dev, PMSG_HIBERNATE); 4570146f26145af75d53e12dbf23a36996aff373680Feng Tang} 4580146f26145af75d53e12dbf23a36996aff373680Feng Tang 4590146f26145af75d53e12dbf23a36996aff373680Feng Tangstatic int mrst_resume(struct device *dev) 4600146f26145af75d53e12dbf23a36996aff373680Feng Tang{ 4610146f26145af75d53e12dbf23a36996aff373680Feng Tang struct mrst_rtc *mrst = dev_get_drvdata(dev); 4620146f26145af75d53e12dbf23a36996aff373680Feng Tang unsigned char tmp = mrst->suspend_ctrl; 4630146f26145af75d53e12dbf23a36996aff373680Feng Tang 4640146f26145af75d53e12dbf23a36996aff373680Feng Tang /* Re-enable any irqs previously active */ 4650146f26145af75d53e12dbf23a36996aff373680Feng Tang if (tmp & RTC_IRQMASK) { 4660146f26145af75d53e12dbf23a36996aff373680Feng Tang unsigned char mask; 4670146f26145af75d53e12dbf23a36996aff373680Feng Tang 4680146f26145af75d53e12dbf23a36996aff373680Feng Tang if (mrst->enabled_wake) { 4690146f26145af75d53e12dbf23a36996aff373680Feng Tang disable_irq_wake(mrst->irq); 4700146f26145af75d53e12dbf23a36996aff373680Feng Tang mrst->enabled_wake = 0; 4710146f26145af75d53e12dbf23a36996aff373680Feng Tang } 4720146f26145af75d53e12dbf23a36996aff373680Feng Tang 4730146f26145af75d53e12dbf23a36996aff373680Feng Tang spin_lock_irq(&rtc_lock); 4740146f26145af75d53e12dbf23a36996aff373680Feng Tang do { 4750146f26145af75d53e12dbf23a36996aff373680Feng Tang vrtc_cmos_write(tmp, RTC_CONTROL); 4760146f26145af75d53e12dbf23a36996aff373680Feng Tang 4770146f26145af75d53e12dbf23a36996aff373680Feng Tang mask = vrtc_cmos_read(RTC_INTR_FLAGS); 4780146f26145af75d53e12dbf23a36996aff373680Feng Tang mask &= (tmp & RTC_IRQMASK) | RTC_IRQF; 4790146f26145af75d53e12dbf23a36996aff373680Feng Tang if (!is_intr(mask)) 4800146f26145af75d53e12dbf23a36996aff373680Feng Tang break; 4810146f26145af75d53e12dbf23a36996aff373680Feng Tang 4820146f26145af75d53e12dbf23a36996aff373680Feng Tang rtc_update_irq(mrst->rtc, 1, mask); 4830146f26145af75d53e12dbf23a36996aff373680Feng Tang tmp &= ~RTC_AIE; 4840146f26145af75d53e12dbf23a36996aff373680Feng Tang } while (mask & RTC_AIE); 4850146f26145af75d53e12dbf23a36996aff373680Feng Tang spin_unlock_irq(&rtc_lock); 4860146f26145af75d53e12dbf23a36996aff373680Feng Tang } 4870146f26145af75d53e12dbf23a36996aff373680Feng Tang 4880146f26145af75d53e12dbf23a36996aff373680Feng Tang dev_dbg(&mrst_rtc.rtc->dev, "resume, ctrl %02x\n", tmp); 4890146f26145af75d53e12dbf23a36996aff373680Feng Tang 4900146f26145af75d53e12dbf23a36996aff373680Feng Tang return 0; 4910146f26145af75d53e12dbf23a36996aff373680Feng Tang} 4920146f26145af75d53e12dbf23a36996aff373680Feng Tang 4930146f26145af75d53e12dbf23a36996aff373680Feng Tang#else 4940146f26145af75d53e12dbf23a36996aff373680Feng Tang#define mrst_suspend NULL 4950146f26145af75d53e12dbf23a36996aff373680Feng Tang#define mrst_resume NULL 4960146f26145af75d53e12dbf23a36996aff373680Feng Tang 4970146f26145af75d53e12dbf23a36996aff373680Feng Tangstatic inline int mrst_poweroff(struct device *dev) 4980146f26145af75d53e12dbf23a36996aff373680Feng Tang{ 4990146f26145af75d53e12dbf23a36996aff373680Feng Tang return -ENOSYS; 5000146f26145af75d53e12dbf23a36996aff373680Feng Tang} 5010146f26145af75d53e12dbf23a36996aff373680Feng Tang 5020146f26145af75d53e12dbf23a36996aff373680Feng Tang#endif 5030146f26145af75d53e12dbf23a36996aff373680Feng Tang 5045a167f4543e45d45c5672a5cd6cb8ba5ddf4f3eaGreg Kroah-Hartmanstatic int vrtc_mrst_platform_probe(struct platform_device *pdev) 5050146f26145af75d53e12dbf23a36996aff373680Feng Tang{ 5060146f26145af75d53e12dbf23a36996aff373680Feng Tang return vrtc_mrst_do_probe(&pdev->dev, 5070146f26145af75d53e12dbf23a36996aff373680Feng Tang platform_get_resource(pdev, IORESOURCE_MEM, 0), 5080146f26145af75d53e12dbf23a36996aff373680Feng Tang platform_get_irq(pdev, 0)); 5090146f26145af75d53e12dbf23a36996aff373680Feng Tang} 5100146f26145af75d53e12dbf23a36996aff373680Feng Tang 5115a167f4543e45d45c5672a5cd6cb8ba5ddf4f3eaGreg Kroah-Hartmanstatic int vrtc_mrst_platform_remove(struct platform_device *pdev) 5120146f26145af75d53e12dbf23a36996aff373680Feng Tang{ 5130146f26145af75d53e12dbf23a36996aff373680Feng Tang rtc_mrst_do_remove(&pdev->dev); 5140146f26145af75d53e12dbf23a36996aff373680Feng Tang return 0; 5150146f26145af75d53e12dbf23a36996aff373680Feng Tang} 5160146f26145af75d53e12dbf23a36996aff373680Feng Tang 5170146f26145af75d53e12dbf23a36996aff373680Feng Tangstatic void vrtc_mrst_platform_shutdown(struct platform_device *pdev) 5180146f26145af75d53e12dbf23a36996aff373680Feng Tang{ 5190146f26145af75d53e12dbf23a36996aff373680Feng Tang if (system_state == SYSTEM_POWER_OFF && !mrst_poweroff(&pdev->dev)) 5200146f26145af75d53e12dbf23a36996aff373680Feng Tang return; 5210146f26145af75d53e12dbf23a36996aff373680Feng Tang 5220146f26145af75d53e12dbf23a36996aff373680Feng Tang rtc_mrst_do_shutdown(); 5230146f26145af75d53e12dbf23a36996aff373680Feng Tang} 5240146f26145af75d53e12dbf23a36996aff373680Feng Tang 5250146f26145af75d53e12dbf23a36996aff373680Feng TangMODULE_ALIAS("platform:vrtc_mrst"); 5260146f26145af75d53e12dbf23a36996aff373680Feng Tang 5270146f26145af75d53e12dbf23a36996aff373680Feng Tangstatic struct platform_driver vrtc_mrst_platform_driver = { 5280146f26145af75d53e12dbf23a36996aff373680Feng Tang .probe = vrtc_mrst_platform_probe, 5295a167f4543e45d45c5672a5cd6cb8ba5ddf4f3eaGreg Kroah-Hartman .remove = vrtc_mrst_platform_remove, 5300146f26145af75d53e12dbf23a36996aff373680Feng Tang .shutdown = vrtc_mrst_platform_shutdown, 5310146f26145af75d53e12dbf23a36996aff373680Feng Tang .driver = { 5320146f26145af75d53e12dbf23a36996aff373680Feng Tang .name = (char *) driver_name, 5330146f26145af75d53e12dbf23a36996aff373680Feng Tang .suspend = mrst_suspend, 5340146f26145af75d53e12dbf23a36996aff373680Feng Tang .resume = mrst_resume, 5350146f26145af75d53e12dbf23a36996aff373680Feng Tang } 5360146f26145af75d53e12dbf23a36996aff373680Feng Tang}; 5370146f26145af75d53e12dbf23a36996aff373680Feng Tang 5380c4eae66591a292fee70051ea363a8d27aa54102Axel Linmodule_platform_driver(vrtc_mrst_platform_driver); 5390146f26145af75d53e12dbf23a36996aff373680Feng Tang 5400146f26145af75d53e12dbf23a36996aff373680Feng TangMODULE_AUTHOR("Jacob Pan; Feng Tang"); 5410146f26145af75d53e12dbf23a36996aff373680Feng TangMODULE_DESCRIPTION("Driver for Moorestown virtual RTC"); 5420146f26145af75d53e12dbf23a36996aff373680Feng TangMODULE_LICENSE("GPL"); 543