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