예제 #1
0
static int set_rtc_mmss(unsigned long nowtime)
{
	int retval = 0;
	int real_seconds, real_minutes, cmos_minutes;
	int i;

	/* gets recalled with irq locally disabled */
	spin_lock(&rtc_lock);
	for (i = 0 ; i < 1000000 ; i++)	/* may take up to 1 second... */
		if (!(ctrl_inb(RTC_CTL) & RTC_BUSY))
			break;
	cmos_minutes = (ctrl_inb(RTC_MIN1) & 0xf) + (ctrl_inb(RTC_MIN10) & 0xf) * 10;
	real_seconds = nowtime % 60;
	real_minutes = nowtime / 60;
	if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
		real_minutes += 30;		/* correct for half hour time zone */
	real_minutes %= 60;

	if (abs(real_minutes - cmos_minutes) < 30) {
		BIN_TO_BCD(real_seconds);
		BIN_TO_BCD(real_minutes);
		ctrl_outb(real_seconds % 10, RTC_SEC1);
		ctrl_outb(real_seconds / 10, RTC_SEC10);
		ctrl_outb(real_minutes % 10, RTC_MIN1);
		ctrl_outb(real_minutes / 10, RTC_MIN10);
	} else {
		printk(KERN_WARNING
		       "set_rtc_mmss: can't update from %d to %d\n",
		       cmos_minutes, real_minutes);
		retval = -1;
	}
	spin_unlock(&rtc_lock);

	return retval;
}
예제 #2
0
파일: rtc.c 프로젝트: 274914765/C
/*
 * In order to set the CMOS clock precisely, set_rtc_mmss has to be called 500
 * ms after the second nowtime has started, because when nowtime is written
 * into the registers of the CMOS clock, it will jump to the next second
 * precisely 500 ms later.  Check the Motorola MC146818A or Dallas DS12887 data
 * sheet for details.
 *
 * BUG: This routine does not handle hour overflow properly; it just
 *      sets the minutes. Usually you'll only notice that after reboot!
 */
static int set_rtc_mmss(unsigned long nowtime)
{
    unsigned char save_control, save_freq_select;
    int retval = 0;
    int real_seconds, real_minutes, cmos_minutes;

    /* gets recalled with irq locally disabled */
    spin_lock(&rtc_lock);
    save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being
                        * set */
    CMOS_WRITE(save_control | RTC_SET, RTC_CONTROL);

    save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset
                            * prescaler */
    CMOS_WRITE(save_freq_select | RTC_DIV_RESET2, RTC_FREQ_SELECT);

    cmos_minutes = CMOS_READ(RTC_MINUTES);
    if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
        BCD_TO_BIN(cmos_minutes);

    /*
     * since we're only adjusting minutes and seconds,
     * don't interfere with hour overflow. This avoids
     * messing with unknown time zones but requires your
     * RTC not to be off by more than 15 minutes
     */
    real_seconds = nowtime % 60;
    real_minutes = nowtime / 60;
    if (((abs(real_minutes - cmos_minutes) + 15) / 30) & 1)
        /* correct for half hour time zone */
        real_minutes += 30;
    real_minutes %= 60;

    if (abs(real_minutes - cmos_minutes) < 30) {
        if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
            BIN_TO_BCD(real_seconds);
            BIN_TO_BCD(real_minutes);
        }
        CMOS_WRITE(real_seconds, RTC_SECONDS);
        CMOS_WRITE(real_minutes, RTC_MINUTES);
    } else {
        printk(KERN_WARNING
               "set_rtc_mmss: can't update from %d to %d\n",
               cmos_minutes, real_minutes);
        retval = -1;
    }

    /* The following flags have to be released exactly in this order,
     * otherwise the DS12887 (popular MC146818A clone with integrated
     * battery and quartz) will not reset the oscillator and will not
     * update precisely 500 ms later. You won't find this mentioned in
     * the Dallas Semiconductor data sheets, but who believes data
     * sheets anyway ...                           -- Markus Kuhn
     */
    CMOS_WRITE(save_control, RTC_CONTROL);
    CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
    spin_unlock(&rtc_lock);

    return retval;
}
예제 #3
0
static unsigned char ps2_rtc_read_data(unsigned long addr)
{
	struct timeval tv;
	unsigned char res;

	if (13 < addr) {
		DPRINT("RTC: read rtc[%11s(%ld)]=0(ignored)\n", "???", addr);
		return (0);
	}

	do_gettimeofday(&tv);
	mkdate(tv.tv_sec,
	       &regs[RTC_YEAR], &regs[RTC_MONTH], &regs[RTC_DAY_OF_MONTH],
	       &regs[RTC_HOURS], &regs[RTC_MINUTES], &regs[RTC_SECONDS],
	       &regs[RTC_DAY_OF_WEEK]);

	regs[RTC_YEAR] -= 1952; /* Digital UNIX epoch */
	regs[RTC_YEAR] %= 100;
	res = (regs[addr] & 0xff);

	if (regs[RTC_CONTROL] & RTC_DM_BINARY) {
		DPRINT(" read rtc[%11s(%2ld)]=%d\n",
		       reg_names[addr], addr, res);
	} else {
		BIN_TO_BCD(res);
		DPRINT(" read rtc[%11s(%2ld)]=0x%02x\n",
		       reg_names[addr], addr, res);
	}

	return (res);
}
static int set_rtc_mmss(unsigned long nowtime)
{
	int retval = 0;
	int real_seconds, real_minutes, cmos_minutes;
	struct m48t35_rtc *rtc;
	nasid_t nid;

	rtc = (struct m48t35_rtc *)
	(KL_CONFIG_CH_CONS_INFO(master_nasid)->memory_base + IOC3_BYTEBUS_DEV0);

	spin_lock(&rtc_lock);
	rtc->control |= M48T35_RTC_READ;
	cmos_minutes = rtc->min;
	BCD_TO_BIN(cmos_minutes);
	rtc->control &= ~M48T35_RTC_READ;

	/*
	 * Since we're only adjusting minutes and seconds, don't interfere with
	 * hour overflow. This avoids messing with unknown time zones but
	 * requires your RTC not to be off by more than 15 minutes
	 */
	real_seconds = nowtime % 60;
	real_minutes = nowtime / 60;
	if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
		real_minutes += 30;	/* correct for half hour time zone */
	real_minutes %= 60;

	if (abs(real_minutes - cmos_minutes) < 30) {
		BIN_TO_BCD(real_seconds);
		BIN_TO_BCD(real_minutes);
		rtc->control |= M48T35_RTC_SET;
		rtc->sec = real_seconds;
		rtc->min = real_minutes;
		rtc->control &= ~M48T35_RTC_SET;
	} else {
		printk(KERN_WARNING
		       "set_rtc_mmss: can't update from %d to %d\n",
		       cmos_minutes, real_minutes);
		retval = -1;
	}
	spin_unlock(&rtc_lock);

	return retval;
}
예제 #5
0
파일: time.c 프로젝트: TKr/Wive-ng-rt8186
/*
 * In order to set the CMOS clock precisely, set_rtc_mmss has to be
 * called 500 ms after the second nowtime has started, because when
 * nowtime is written into the registers of the CMOS clock, it will
 * jump to the next second precisely 500 ms later. Check the Motorola
 * MC146818A or Dallas DS12887 data sheet for details.
 *
 * BUG: This routine does not handle hour overflow properly; it just
 *      sets the minutes. Usually you'll only notice that after reboot!
 */
int set_rtc_mmss(unsigned long nowtime)
{
	int retval = 0;
	int real_seconds, real_minutes, cmos_minutes;

	cmos_minutes = xicor_read(X1241REG_MN);
	BCD_TO_BIN(cmos_minutes);

	/*
	 * since we're only adjusting minutes and seconds,
	 * don't interfere with hour overflow. This avoids
	 * messing with unknown time zones but requires your
	 * RTC not to be off by more than 15 minutes
	 */
	real_seconds = nowtime % 60;
	real_minutes = nowtime / 60;
	if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
		real_minutes += 30;		/* correct for half hour time zone */
	real_minutes %= 60;

	/* unlock writes to the CCR */
	xicor_write(X1241REG_SR, X1241REG_SR_WEL);
	xicor_write(X1241REG_SR, X1241REG_SR_WEL | X1241REG_SR_RWEL);

	if (abs(real_minutes - cmos_minutes) < 30) {
		BIN_TO_BCD(real_seconds);
		BIN_TO_BCD(real_minutes);
		xicor_write(X1241REG_SC, real_seconds);
		xicor_write(X1241REG_MN, real_minutes);
	} else {
		printk(KERN_WARNING
		       "set_rtc_mmss: can't update from %d to %d\n",
		       cmos_minutes, real_minutes);
		retval = -1;
	}

	xicor_write(X1241REG_SR, 0);

	printk("set_rtc_mmss: %02d:%02d\n", real_minutes, real_seconds);

	return retval;
}
예제 #6
0
__prep
int mk48t59_set_rtc_time(unsigned long nowtime)
{
	unsigned char save_control;
	struct rtc_time tm;


	to_tm(nowtime, &tm);

	/* tell the clock it's being written */
	save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA);
	
	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA,
			     (save_control | MK48T59_RTC_CA_WRITE));

        tm.tm_year = (tm.tm_year - 1900) % 100;
	BIN_TO_BCD(tm.tm_sec);
	BIN_TO_BCD(tm.tm_min);
	BIN_TO_BCD(tm.tm_hour);
	BIN_TO_BCD(tm.tm_mon);
	BIN_TO_BCD(tm.tm_mday);
	BIN_TO_BCD(tm.tm_year);

	ppc_md.nvram_write_val(MK48T59_RTC_SECONDS,      tm.tm_sec);
	ppc_md.nvram_write_val(MK48T59_RTC_MINUTES,      tm.tm_min);
	ppc_md.nvram_write_val(MK48T59_RTC_HOURS,        tm.tm_hour);
	ppc_md.nvram_write_val(MK48T59_RTC_MONTH,        tm.tm_mon);
	ppc_md.nvram_write_val(MK48T59_RTC_DAY_OF_MONTH, tm.tm_mday);
	ppc_md.nvram_write_val(MK48T59_RTC_YEAR,         tm.tm_year);
	
	/* Turn off the write bit. */
	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control);

	return 0;
}
예제 #7
0
파일: time.c 프로젝트: sarnobat/knoppix
int set_rtc_mmss(unsigned long nowtime)
{
	int retval = 0;
	int real_seconds, real_minutes, cmos_minutes;

	printk("set_rtc_mmss(%lu)\n", nowtime);

	if(!have_rtc)
		return 0;

	cmos_minutes = CMOS_READ(RTC_MINUTES);
	BCD_TO_BIN(cmos_minutes);

	/*
	 * since we're only adjusting minutes and seconds,
	 * don't interfere with hour overflow. This avoids
	 * messing with unknown time zones but requires your
	 * RTC not to be off by more than 15 minutes
	 */
	real_seconds = nowtime % 60;
	real_minutes = nowtime / 60;
	if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
		real_minutes += 30;		/* correct for half hour time zone */
	real_minutes %= 60;

	if (abs(real_minutes - cmos_minutes) < 30) {
		BIN_TO_BCD(real_seconds);
		BIN_TO_BCD(real_minutes);
		CMOS_WRITE(real_seconds,RTC_SECONDS);
		CMOS_WRITE(real_minutes,RTC_MINUTES);
	} else {
		printk(KERN_WARNING
		       "set_rtc_mmss: can't update from %d to %d\n",
		       cmos_minutes, real_minutes);
		retval = -1;
	}

	return retval;
}
예제 #8
0
void tm_binary_to_bcd(struct tm *tm)
{
	BIN_TO_BCD(tm->tm_sec);	
	BIN_TO_BCD(tm->tm_min);	
	BIN_TO_BCD(tm->tm_hour);	
	tm->tm_hour = tm->tm_hour|0x80;
	BIN_TO_BCD(tm->tm_mday);	
	BIN_TO_BCD(tm->tm_mon);	
	BIN_TO_BCD(tm->tm_year);	
	BIN_TO_BCD(tm->tm_wday);	

}
예제 #9
0
파일: time.c 프로젝트: TitaniumBoy/lin
int atari_tt_set_clock_mmss (unsigned long nowtime)
{
    int retval = 0;
    short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
    unsigned char save_control, save_freq_select, rtc_minutes;

    save_control = RTC_READ (RTC_CONTROL); /* tell the clock it's being set */
    RTC_WRITE (RTC_CONTROL, save_control | RTC_SET);

    save_freq_select = RTC_READ (RTC_FREQ_SELECT); /* stop and reset prescaler */
    RTC_WRITE (RTC_FREQ_SELECT, save_freq_select | RTC_DIV_RESET2);

    rtc_minutes = RTC_READ (RTC_MINUTES);
    if (!(save_control & RTC_DM_BINARY))
        BCD_TO_BIN (rtc_minutes);

    /* Since we're only adjusting minutes and seconds, don't interfere
       with hour overflow.  This avoids messing with unknown time zones
       but requires your RTC not to be off by more than 30 minutes.  */
    if ((rtc_minutes < real_minutes
         ? real_minutes - rtc_minutes
         : rtc_minutes - real_minutes) < 30)
        {
            if (!(save_control & RTC_DM_BINARY))
                {
                    BIN_TO_BCD (real_seconds);
                    BIN_TO_BCD (real_minutes);
                }
            RTC_WRITE (RTC_SECONDS, real_seconds);
            RTC_WRITE (RTC_MINUTES, real_minutes);
        }
    else
        retval = -1;

    RTC_WRITE (RTC_FREQ_SELECT, save_freq_select);
    RTC_WRITE (RTC_CONTROL, save_control);
    return retval;
}
예제 #10
0
파일: pcf8563.c 프로젝트: postgetme/crco
INT8S pcf8563_write(TIME* ptime)
{
	INT8U setbuf[7];
	INT8U mode,sub_addr,year;
	
	if(NULL == ptime){
		return -1;
	}

	setbuf[0] = BIN_TO_BCD(ptime->second);
	setbuf[1] = BIN_TO_BCD(ptime->minute);
	setbuf[2] = BIN_TO_BCD(ptime->hour);
	setbuf[3] = BIN_TO_BCD(ptime->day);
	setbuf[4] = BIN_TO_BCD(ptime->week);

	// еп╤ойю╪м
	if(ptime->year >= 2000)
	{
		year =  ptime->year - 2000;
		setbuf[5] = BIN_TO_BCD(ptime->month);
		setbuf[6] = BIN_TO_BCD(year);
	}
	else
	{
		year = 	ptime->year - 1900;
		setbuf[5] = BIN_TO_BCD(ptime->month) | 0x80;
		setbuf[6] = BIN_TO_BCD(year);
	}

	mode = 1;
	sub_addr = 0x02;
	if(ISendStr(PCF8563_I2C_PORT, 0xA2, sub_addr, mode, (INT8U *)setbuf, 7) == false){
		return -1;	
	}

	RTC_START();

	return 0;
}
int xicor_set_time(unsigned long t)
{
	struct rtc_time tm;
	int tmp;

	to_tm(t, &tm);

	/* unlock writes to the CCR */
	xicor_write(X1241REG_SR, X1241REG_SR_WEL);
	xicor_write(X1241REG_SR, X1241REG_SR_WEL | X1241REG_SR_RWEL);

	/* trivial ones */
	BIN_TO_BCD(tm.tm_sec);
	xicor_write(X1241REG_SC, tm.tm_sec);

	BIN_TO_BCD(tm.tm_min);
	xicor_write(X1241REG_MN, tm.tm_min);

	BIN_TO_BCD(tm.tm_mday);
	xicor_write(X1241REG_DT, tm.tm_mday);

	/* tm_mon starts from 0, *ick* */
	tm.tm_mon ++;
	BIN_TO_BCD(tm.tm_mon);
	xicor_write(X1241REG_MO, tm.tm_mon);

	/* year is split */
	tmp = tm.tm_year / 100;
	tm.tm_year %= 100;
	xicor_write(X1241REG_YR, tm.tm_year);
	xicor_write(X1241REG_Y2K, tmp);

	/* hour is the most tricky one */
	tmp = xicor_read(X1241REG_HR);
	if (tmp & X1241REG_HR_MIL) {
		/* 24 hour format */
		BIN_TO_BCD(tm.tm_hour);
		tmp = (tmp & ~0x3f) | (tm.tm_hour & 0x3f);
	} else {
		/* 12 hour format, with 0x2 for pm */
		tmp = tmp & ~0x3f;
		if (tm.tm_hour >= 12) {
			tmp |= 0x20;
			tm.tm_hour -= 12;
		}
		BIN_TO_BCD(tm.tm_hour);
		tmp |= tm.tm_hour;
	}
	xicor_write(X1241REG_HR, tmp);

	xicor_write(X1241REG_SR, 0);

	return 0;
}
예제 #12
0
int
todc_set_rtc_time(unsigned long nowtime)
{
	struct rtc_time	tm;
	u_char		save_control, save_freq_select = 0;

	spin_lock(&rtc_lock);
	to_tm(nowtime, &tm);

	save_control = todc_read_val(todc_info->control_a);

	/* Assuming MK48T59_RTC_CA_WRITE & RTC_SET are equal */
	todc_write_val(todc_info->control_a,
			       (save_control | todc_info->enable_write));
	save_control &= ~(todc_info->enable_write); /* in case it was set */

	if (todc_info->rtc_type == TODC_TYPE_MC146818) {
		save_freq_select = todc_read_val(todc_info->RTC_FREQ_SELECT);
		todc_write_val(todc_info->RTC_FREQ_SELECT,
				       save_freq_select | RTC_DIV_RESET2);
	}


        tm.tm_year = (tm.tm_year - 1900) % 100;

	if ((todc_info->rtc_type != TODC_TYPE_MC146818) ||
	    ((save_control & RTC_DM_BINARY) == 0) ||
	    RTC_ALWAYS_BCD) {

		BIN_TO_BCD(tm.tm_sec);
		BIN_TO_BCD(tm.tm_min);
		BIN_TO_BCD(tm.tm_hour);
		BIN_TO_BCD(tm.tm_mon);
		BIN_TO_BCD(tm.tm_mday);
		BIN_TO_BCD(tm.tm_year);
	}

	todc_write_val(todc_info->seconds,      tm.tm_sec);
	todc_write_val(todc_info->minutes,      tm.tm_min);
	todc_write_val(todc_info->hours,        tm.tm_hour);
	todc_write_val(todc_info->month,        tm.tm_mon);
	todc_write_val(todc_info->day_of_month, tm.tm_mday);
	todc_write_val(todc_info->year,         tm.tm_year);

	todc_write_val(todc_info->control_a, save_control);

	if (todc_info->rtc_type == TODC_TYPE_MC146818) {
		todc_write_val(todc_info->RTC_FREQ_SELECT, save_freq_select);
	}
	spin_unlock(&rtc_lock);

	return 0;
}
예제 #13
0
static int
rtc8564_set_datetime(struct i2c_client *client, struct rtc_tm *dt, int datetoo)
{
	int ret, len = 5;
	unsigned char buf[15];

	_DBG(1, "client=%p, dt=%p", client, dt);

	if (!dt)
		return -EINVAL;

	_DBGRTCTM(2, *dt);

	buf[RTC8564_REG_CTRL1] = CTRL1(client) | RTC8564_CTRL1_STOP;
	buf[RTC8564_REG_CTRL2] = CTRL2(client);
	buf[RTC8564_REG_SEC] = BIN_TO_BCD(dt->secs);
	buf[RTC8564_REG_MIN] = BIN_TO_BCD(dt->mins);
	buf[RTC8564_REG_HR] = BIN_TO_BCD(dt->hours);

	if (datetoo) {
		len += 5;
		buf[RTC8564_REG_DAY] = BIN_TO_BCD(dt->mday);
		buf[RTC8564_REG_WDAY] = BIN_TO_BCD(dt->wday);
		buf[RTC8564_REG_MON_CENT] = BIN_TO_BCD(dt->mon) & 0x1f;
		/* century stored in minute alarm reg */
		buf[RTC8564_REG_YEAR] = BIN_TO_BCD(dt->year % 100);
		buf[RTC8564_REG_AL_MIN] = BIN_TO_BCD(dt->year / 100);
	}

	ret = rtc8564_write(client, 0, buf, len);
	if (ret) {
		_DBG(1, "error writing data! %d", ret);
	}

	buf[RTC8564_REG_CTRL1] = CTRL1(client);
	ret = rtc8564_write(client, 0, buf, 1);
	if (ret) {
		_DBG(1, "error writing data! %d", ret);
	}

	return ret;
}
예제 #14
0
파일: s3c2410-rtc.c 프로젝트: mglz/Drv
static int set_rtc_time(int alm, struct rtc_time *rtc_tm)
{
    unsigned char year, mon, day, hour, min, sec;

    if (rtc_tm->tm_year < (RTC_LEAP_YEAR - 1900)) {
        /* The year must be higher or equal than 2000 */
        return -EINVAL;
    }

    year = (rtc_tm->tm_year + 1900) - RTC_LEAP_YEAR;
    mon = rtc_tm->tm_mon + 1; /* tm_mon starts at zero */
    day = rtc_tm->tm_mday;
    hour = rtc_tm->tm_hour;
    min = rtc_tm->tm_min;
    sec = rtc_tm->tm_sec;

    BIN_TO_BCD(sec);
    BIN_TO_BCD(min);
    BIN_TO_BCD(hour);
    BIN_TO_BCD(day);
    BIN_TO_BCD(mon);
    BIN_TO_BCD(year);

    spin_lock_irq(&rtc_lock);
    /* Enable RTC control */
    RTCCON |= RTCCON_EN;

    if (alm) {
        ALMSEC = sec & Msk_RTCSEC;
        ALMMIN = min & Msk_RTCMIN;
        ALMHOUR = hour & Msk_RTCHOUR;
        ALMDAY = day & Msk_RTCDAY;
        ALMMON = mon & Msk_RTCMON;
        ALMYEAR = year & Msk_RTCYEAR;
    }
    else {
        BCDSEC = sec & Msk_RTCSEC;
        BCDMIN = min & Msk_RTCMIN;
        BCDHOUR = hour & Msk_RTCHOUR;
        //BCDDAY = day & Msk_RTCDAY;
        BCDDATE = day & Msk_RTCDAY;
        BCDMON = mon & Msk_RTCMON;
        BCDYEAR = year & Msk_RTCYEAR;
    }

    /* Disable RTC control */
    RTCCON &= ~RTCCON_EN;
    spin_unlock_irq(&rtc_lock);

    return 0;
}
예제 #15
0
int maple_set_rtc_time(struct rtc_time *tm)
{
	unsigned char save_control, save_freq_select;
	int sec, min, hour, mon, mday, year;

	spin_lock(&rtc_lock);

	save_control = maple_clock_read(RTC_CONTROL); /* tell the clock it's being set */

	maple_clock_write((save_control|RTC_SET), RTC_CONTROL);

	save_freq_select = maple_clock_read(RTC_FREQ_SELECT); /* stop and reset prescaler */

	maple_clock_write((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);

	sec = tm->tm_sec;
	min = tm->tm_min;
	hour = tm->tm_hour;
	mon = tm->tm_mon;
	mday = tm->tm_mday;
	year = tm->tm_year;

	if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
		BIN_TO_BCD(sec);
		BIN_TO_BCD(min);
		BIN_TO_BCD(hour);
		BIN_TO_BCD(mon);
		BIN_TO_BCD(mday);
		BIN_TO_BCD(year);
	}
	maple_clock_write(sec, RTC_SECONDS);
	maple_clock_write(min, RTC_MINUTES);
	maple_clock_write(hour, RTC_HOURS);
	maple_clock_write(mon, RTC_MONTH);
	maple_clock_write(mday, RTC_DAY_OF_MONTH);
	maple_clock_write(year, RTC_YEAR);

	/* The following flags have to be released exactly in this order,
	 * otherwise the DS12887 (popular MC146818A clone with integrated
	 * battery and quartz) will not reset the oscillator and will not
	 * update precisely 500 ms later. You won't find this mentioned in
	 * the Dallas Semiconductor data sheets, but who believes data
	 * sheets anyway ...                           -- Markus Kuhn
	 */
	maple_clock_write(save_control, RTC_CONTROL);
	maple_clock_write(save_freq_select, RTC_FREQ_SELECT);

	spin_unlock(&rtc_lock);

	return 0;
}
예제 #16
0
/*==========================================================================
 FUNCTION:DS3231 driver
 PURPOSE:
 ---------------------------------------------------------------------------*/
bool Crtc::setDate(u16 year, u08 mon, u08 day, u08 hour, u08 min) {
	u08 buf[8];
	/* select address 0x00 */
	buf[0] = 0x00;

	buf[1] = (BIN_TO_BCD (0)) | 0x80; //sec
	buf[2] = (BIN_TO_BCD (min)) & 0x7F;
	buf[3] = (BIN_TO_BCD (hour)) & 0x3F;// 00-->23
	buf[4] = 0xFF; // VBATEN - BIT3 VBAT = BIT4
	buf[5] = (BIN_TO_BCD (day)) & 0x3F; //1--31/30
	buf[6] = BIN_TO_BCD (mon) & 0x1F; //1--12
	buf[7] = BIN_TO_BCD (year-2000); //00 -- 99
	i2c->masterSend(rtc_id, 8, buf);
	return true;
}
예제 #17
0
bool Crtc::setDate(sRtcTime* time) {
	u08 buf[8];
	/* select address 0x00 */
	buf[0] = 0x00;

	buf[1] = (BIN_TO_BCD (time->sec)) | 0x80; //sec
	buf[2] = (BIN_TO_BCD (time->min)) & 0x7F;
	buf[3] = (BIN_TO_BCD (time->hour)) & 0x3F;// 00-->23
	buf[4] = 7; //1-7 wday
	buf[5] = (BIN_TO_BCD (time->day)) & 0x3F; //1--31/30
	buf[6] = BIN_TO_BCD (time->mon) & 0x1F; //1--12
	buf[7] = BIN_TO_BCD (time->year-2000); //00 -- 99
	i2c->masterSend(rtc_id, 8, buf);
	return true;
}
예제 #18
0
/*
 * Set the hardware clock. -- Cort
 */
__prep
int mc146818_set_rtc_time(unsigned long nowtime)
{
	unsigned char save_control, save_freq_select;
	struct rtc_time tm;

	spin_lock(&rtc_lock);
	to_tm(nowtime, &tm);

	/* tell the clock it's being set */
	save_control = CMOS_READ(RTC_CONTROL);

	CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);

	/* stop and reset prescaler */
	save_freq_select = CMOS_READ(RTC_FREQ_SELECT);

	CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);

        tm.tm_year = (tm.tm_year - 1900) % 100;
	if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
		BIN_TO_BCD(tm.tm_sec);
		BIN_TO_BCD(tm.tm_min);
		BIN_TO_BCD(tm.tm_hour);
		BIN_TO_BCD(tm.tm_mon);
		BIN_TO_BCD(tm.tm_mday);
		BIN_TO_BCD(tm.tm_year);
	}
	CMOS_WRITE(tm.tm_sec,  RTC_SECONDS);
	CMOS_WRITE(tm.tm_min,  RTC_MINUTES);
	CMOS_WRITE(tm.tm_hour, RTC_HOURS);
	CMOS_WRITE(tm.tm_mon,  RTC_MONTH);
	CMOS_WRITE(tm.tm_mday, RTC_DAY_OF_MONTH);
	CMOS_WRITE(tm.tm_year, RTC_YEAR);

	/* The following flags have to be released exactly in this order,
	 * otherwise the DS12887 (popular MC146818A clone with integrated
	 * battery and quartz) will not reset the oscillator and will not
	 * update precisely 500 ms later. You won't find this mentioned in
	 * the Dallas Semiconductor data sheets, but who believes data
	 * sheets anyway ...                           -- Markus Kuhn
	 */
	CMOS_WRITE(save_control,     RTC_CONTROL);
	CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
	spin_unlock(&rtc_lock);

	return 0;
}
예제 #19
0
/**	Запись внутренних регистров.
 *
 * 	Проводится проверка корректности адреса. Выход за максимальный или
 *	минимальный адреса считается ошибкой.
 *
 *	Доступные адреса для записи:
 *	- ADR_YEAR Установка года.
 *	- ADR_MONTH Установка месяца.
 *	- ADR_DAY Установка дня.
 *	- ADR_HOUR Установка часа.
 *	- ADR_MINUTE Установка минут.
 *	- ADR_SECOND Установка секунд.
 *	- ADR_JRN_EVT_NUM Выбор номера записи журнала событий.
 *	- ADR_JRN_PRM_NUM Выбор номера записи журнала приемника.
 *	- ADR JRN_PRD_NUM Выбор номера записи журнала передатчика.
 *	- ADR_JRN_DEF_NUM Выбор номера записи журнала защиты.
 *	- ADR_IND_COM_PRM_16 Сброс индикации всех команд приемника и передатчика.
 *	- ADR_IND_COM_PRM_32 Сброс индикации всех команд приемника и передатчика.
 *	- ADR_IND_COM_PRD_16 Сброс индикации всех команд приемника и передатчика.
 *	- ADR_IND_COM_PRD_32 Сброс индикации всех команд приемника и передатчика.
 *
 *	Сброс индикации осуществляется записью 0 в любой из регистров индикации.
 *	Запись всех регистров времени должна осуществляется одной командой.
 *	В момент записи регистра ADR_SECOND команда на изменение времени помещается
 *	в буфер отправки в БСП.
 *
 *
 *	@param adr Адрес регистра.
 *	@param val Состояние регистра.
 * 	@retval CHECK_ERR_NO Ошибок при считывании регистра не возникло.
 * 	@retval CHECK_ERR_ADR Недопустимый адрес регистра.
 *	@retval CHECK_ERR_DEVICE Возникла внутренняя ошибка.
 */
TProtocolModbus::CHECK_ERR TProtocolPcM::writeRegister(uint16_t adr, uint16_t val) {

	if ((adr <= ADR_REG_MIN	) || (adr >= ADR_REG_MAX))
		return CHECK_ERR_ADR;

	if (adr == ADR_JRN_EVT_NUM) {
		sParam_->jrnEntry.setNumEntry(val);
		sParam_->txComBuf.setInt16(sParam_->jrnEntry.getEntryAdress());
		sParam_->txComBuf.addFastCom(GB_COM_GET_JRN_ENTRY);
	} else if (adr == ADR_JRN_PRM_NUM) {
		sParam_->jrnEntry.setNumEntry(val);
		sParam_->txComBuf.setInt16(sParam_->jrnEntry.getEntryAdress());
		sParam_->txComBuf.addFastCom(GB_COM_PRM_GET_JRN_ENTRY);
	} else if (adr == ADR_JRN_PRD_NUM) {
		sParam_->jrnEntry.setNumEntry(val);
		sParam_->txComBuf.setInt16(sParam_->jrnEntry.getEntryAdress());
		sParam_->txComBuf.addFastCom(GB_COM_PRD_GET_JRN_ENTRY);
	} else if (adr == ADR_JRN_DEF_NUM) {
		sParam_->jrnEntry.setNumEntry(val);
		sParam_->txComBuf.setInt16(sParam_->jrnEntry.getEntryAdress());
		sParam_->txComBuf.addFastCom(GB_COM_DEF_GET_JRN_ENTRY);
	} else if ((adr >= ADR_IND_COM_PRM_16) && (adr <= ADR_IND_COM_PRD_32)) {
		if (val == 0) {
			sParam_->txComBuf.addFastCom(GB_COM_PRM_RES_IND);
		}
	} else if ((adr >= ADR_YEAR) && (adr <= ADR_SECOND)) {
		if (adr == ADR_YEAR) {
			val = BIN_TO_BCD(val);
		} else if (adr == ADR_MONTH) {
			val = ((val >= 1) && (val <= 12)) ? BIN_TO_BCD(val) : 1;
		} else if (adr ==  ADR_DAY) {
			val = ((val >= 1) && (val <= 31)) ? BIN_TO_BCD(val) : 1;
		} else if (adr == ADR_HOUR) {
			val = (val <= 23) ? BIN_TO_BCD(val) : 1;
		} else if (adr == ADR_MINUTE) {
			val = (val <= 59) ? BIN_TO_BCD(val) : 1;
		} else if (adr == ADR_SECOND) {
			val = (val <= 59) ? BIN_TO_BCD(val) : 1;
			sParam_->txComBuf.addFastCom(GB_COM_SET_TIME);
			sParam_->txComBuf.setInt8(1, 8);
		}
		sParam_->txComBuf.setInt8(val, adr - ADR_YEAR);
	}

	return CHECK_ERR_NO;
}
예제 #20
0
static int
ds1307_set_datetime(struct i2c_client *client, struct rtc_time *dt, int datetoo)
{
	unsigned char buf[8];
	int ret, len = 4;

	if( rtc_debug > 2)
	{
		printk("ds1307_set_datetime: tm_year = %d\n", dt->tm_year);
		printk("ds1307_set_datetime: tm_mon  = %d\n", dt->tm_mon);
		printk("ds1307_set_datetime: tm_mday = %d\n", dt->tm_mday);
		printk("ds1307_set_datetime: tm_hour = %d\n", dt->tm_hour);
		printk("ds1307_set_datetime: tm_min  = %d\n", dt->tm_min);
		printk("ds1307_set_datetime: tm_sec  = %d\n", dt->tm_sec);
	}

	buf[0] = 0;	/* register address on DS1307 */
	buf[1] = (BIN_TO_BCD(dt->tm_sec));
	buf[2] = (BIN_TO_BCD(dt->tm_min));
	buf[3] = (BIN_TO_BCD(dt->tm_hour));

	if (datetoo) {
		len = 8;
		/* we skip buf[4] as we don't use day-of-week. */
		buf[5] = (BIN_TO_BCD(dt->tm_mday));
		buf[6] = (BIN_TO_BCD(dt->tm_mon + 1));
		/* The year only ranges from 0-99, we are being passed an offset from 1900,
		 * and the chip calulates leap years based on 2000, thus we adjust by 100.
		 */
		buf[7] = (BIN_TO_BCD(dt->tm_year - 100));
	}
	ret = i2c_master_send(client, (char *)buf, len);
	if (ret == len)
		ret = 0;
	else
		printk("ds1307_set_datetime(), i2c_master_send() returned %d\n",ret);


	return ret;
}
예제 #21
0
/*
 * ioctl calls for this driver. Why return -ENOTTY upon error? Because
 * POSIX says so!
 */
int
pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{
	/* Some sanity checks. */
	if (_IOC_TYPE(cmd) != RTC_MAGIC)
		return -ENOTTY;

	if (_IOC_NR(cmd) > RTC_MAX_IOCTL)
		return -ENOTTY;

	switch (cmd) {
		case RTC_RD_TIME:
			{
				struct rtc_time tm;

				get_rtc_time(&tm);

				if (copy_to_user((struct rtc_time *) arg, &tm, sizeof(struct rtc_time))) {
					return -EFAULT;
				}

				return 0;
			}
			break;
		case RTC_SET_TIME:
			{
#ifdef CONFIG_ETRAX_RTC_READONLY
				return -EPERM;
#else
				int leap;
				int century;
				struct rtc_time tm;

				memset(&tm, 0, sizeof (struct rtc_time));
				if (!capable(CAP_SYS_TIME))
					return -EPERM;

				if (copy_from_user(&tm, (struct rtc_time *) arg, sizeof(struct rtc_time)))
					return -EFAULT;

				/* Convert from struct tm to struct rtc_time. */
				tm.tm_year += 1900;
				tm.tm_mon += 1;
				
				leap = ((tm.tm_mon == 2) && ((tm.tm_year % 4) == 0)) ? 1 : 0;

				/* Perform some sanity checks. */
				if ((tm.tm_year < 1970) ||
				    (tm.tm_mon > 12) ||
				    (tm.tm_mday == 0) ||
				    (tm.tm_mday > days_in_month[tm.tm_mon] + leap) ||
				    (tm.tm_hour >= 24) ||
				    (tm.tm_min >= 60) ||
				    (tm.tm_sec >= 60))
					return -EINVAL;

				century = (tm.tm_year >= 2000) ? 0x80 : 0;
				tm.tm_year = tm.tm_year % 100;

				BIN_TO_BCD(tm.tm_year);
				BIN_TO_BCD(tm.tm_mday);
				BIN_TO_BCD(tm.tm_hour);
				BIN_TO_BCD(tm.tm_min);
				BIN_TO_BCD(tm.tm_sec);
				tm.tm_mon |= century;
				
				rtc_write(RTC_YEAR, tm.tm_year);
				rtc_write(RTC_MONTH, tm.tm_mon);
				rtc_write(RTC_DAY_OF_MONTH, tm.tm_mday);
				rtc_write(RTC_HOURS, tm.tm_hour);
				rtc_write(RTC_MINUTES, tm.tm_min);
				rtc_write(RTC_SECONDS, tm.tm_sec);

				return 0;
#endif /* !CONFIG_ETRAX_RTC_READONLY */
			}

		case RTC_VLOW_RD:
		{
			int vl_bit = 0;

			if (rtc_read(RTC_SECONDS) & 0x80) {
				vl_bit = 1;
				printk(KERN_WARNING "%s: RTC Voltage Low - reliable "
				       "date/time information is no longer guaranteed!\n",
				       PCF8563_NAME);
			}
			if (copy_to_user((int *) arg, &vl_bit, sizeof(int)))
				return -EFAULT;

			return 0;
		}

		case RTC_VLOW_SET:
		{
			/* Clear the VL bit in the seconds register */
			int ret = rtc_read(RTC_SECONDS);

			rtc_write(RTC_SECONDS, (ret & 0x7F));

			return 0;
		}

		default:
				return -ENOTTY;
	}

	return 0;
}
예제 #22
0
int sm_osl_proc_write_alarm (
	struct file *file,
	const char *buffer,
	unsigned long count,
	void *data)
{
	char buf[30];
	char *str = buf;
	u32 sec,min,hr;
	u32 day,mo,yr;
	int adjust = 0;
	unsigned char rtc_control;
	int error = -EINVAL;

	if (count > sizeof(buf) - 1) return -EINVAL;
	
	if (copy_from_user(str,buffer,count)) return -EFAULT;

	str[count] = '\0';
	/* check for time adjustment */
	if (str[0] == '+') {
		str++;
		adjust = 1;
	}

	if ((error = get_date_field(&str,&yr)))  goto out;
	if ((error = get_date_field(&str,&mo)))  goto out;
	if ((error = get_date_field(&str,&day))) goto out;
	if ((error = get_date_field(&str,&hr)))  goto out;
	if ((error = get_date_field(&str,&min))) goto out;
	if ((error = get_date_field(&str,&sec))) goto out;


	if (sec > 59) {
		min += 1;
		sec -= 60;
	}
	if (min > 59) {
		hr += 1;
		min -= 60;
	} 
	if (hr > 23) {
		day += 1;
		hr -= 24;
	}
	if (day > 31) { 
		mo += 1;
		day -= 31;
	}
	if (mo > 12) {
		yr += 1;
		mo -= 12;
	}

	spin_lock_irq(&rtc_lock);
	rtc_control = CMOS_READ(RTC_CONTROL);
	if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
		BIN_TO_BCD(yr);
		BIN_TO_BCD(mo);
		BIN_TO_BCD(day);
		BIN_TO_BCD(hr);
		BIN_TO_BCD(min);
		BIN_TO_BCD(sec);
	}

	if (adjust) {
		yr  += CMOS_READ(RTC_YEAR);
		mo  += CMOS_READ(RTC_MONTH);
		day += CMOS_READ(RTC_DAY_OF_MONTH);
		hr  += CMOS_READ(RTC_HOURS);
		min += CMOS_READ(RTC_MINUTES);
		sec += CMOS_READ(RTC_SECONDS);
	}
	spin_unlock_irq(&rtc_lock);

	if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
		BCD_TO_BIN(yr);
		BCD_TO_BIN(mo);
		BCD_TO_BIN(day);
		BCD_TO_BIN(hr);
		BCD_TO_BIN(min);
		BCD_TO_BIN(sec);
	}

	if (sec > 59) {
		min++;
		sec -= 60;
	}
	if (min > 59) {
		hr++;
		min -= 60;
	}
	if (hr > 23) {
		day++;
		hr -= 24;
	}
	if (day > 31) {
		mo++;
		day -= 31;
	}
	if (mo > 12) {
		yr++;
		mo -= 12;
	}
	if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
		BIN_TO_BCD(yr);
		BIN_TO_BCD(mo);
		BIN_TO_BCD(day);
		BIN_TO_BCD(hr);
		BIN_TO_BCD(min);
		BIN_TO_BCD(sec);
	}

	spin_lock_irq(&rtc_lock);
	/* write the fields the rtc knows about */
	CMOS_WRITE(hr,RTC_HOURS_ALARM);
	CMOS_WRITE(min,RTC_MINUTES_ALARM);
	CMOS_WRITE(sec,RTC_SECONDS_ALARM);

	/* If the system supports an enhanced alarm, it will have non-zero
	 * offsets into the CMOS RAM here.
	 * Which for some reason are pointing to the RTC area of memory.
	 */
#if 0
	if (acpi_gbl_FADT->day_alrm) CMOS_WRITE(day,acpi_gbl_FADT->day_alrm);
	if (acpi_gbl_FADT->mon_alrm) CMOS_WRITE(mo,acpi_gbl_FADT->mon_alrm);
	if (acpi_gbl_FADT->century)  CMOS_WRITE(yr / 100,acpi_gbl_FADT->century);
#endif
	/* enable the rtc alarm interrupt */
	if (!(rtc_control & RTC_AIE)) {
		rtc_control |= RTC_AIE;
		CMOS_WRITE(rtc_control,RTC_CONTROL);
		CMOS_READ(RTC_INTR_FLAGS);
	}

	/* unlock the lock on the rtc now that we're done with it */
	spin_unlock_irq(&rtc_lock);

	acpi_hw_register_bit_access(ACPI_WRITE,ACPI_MTX_LOCK, RTC_EN, 1);

	file->f_pos += count;

	error = 0;
 out:
	return error ? error : count;
}
예제 #23
0
파일: interrupts.c 프로젝트: bilboed/wine
/**********************************************************************
 *         DOSVM_Int1aHandler
 *
 * Handler for int 1ah.
 */
static void WINAPI DOSVM_Int1aHandler( CONTEXT86 *context )
{
    switch(AH_reg(context))
    {
    case 0x00: /* GET SYSTEM TIME */
        {
            BIOSDATA *data = DOSVM_BiosData();
            SET_CX( context, HIWORD(data->Ticks) );
            SET_DX( context, LOWORD(data->Ticks) );
            SET_AL( context, 0 ); /* FIXME: midnight flag is unsupported */
            TRACE( "GET SYSTEM TIME - ticks=%d\n", data->Ticks );
        }
        break;

    case 0x01: /* SET SYSTEM TIME */
        FIXME( "SET SYSTEM TIME - not allowed\n" );
        break;

    case 0x02: /* GET REAL-TIME CLOCK TIME */
        TRACE( "GET REAL-TIME CLOCK TIME\n" );
        {
            SYSTEMTIME systime;
            GetLocalTime( &systime );
            SET_CH( context, BIN_TO_BCD(systime.wHour) );
            SET_CL( context, BIN_TO_BCD(systime.wMinute) );
            SET_DH( context, BIN_TO_BCD(systime.wSecond) );
            SET_DL( context, 0 ); /* FIXME: assume no daylight saving */
            RESET_CFLAG(context);
        }
        break;

    case 0x03: /* SET REAL-TIME CLOCK TIME */
        FIXME( "SET REAL-TIME CLOCK TIME - not allowed\n" );
        break;

    case 0x04: /* GET REAL-TIME CLOCK DATE */
        TRACE( "GET REAL-TIME CLOCK DATE\n" );
        {
            SYSTEMTIME systime;
            GetLocalTime( &systime );
            SET_CH( context, BIN_TO_BCD(systime.wYear / 100) );
            SET_CL( context, BIN_TO_BCD(systime.wYear % 100) );
            SET_DH( context, BIN_TO_BCD(systime.wMonth) );
            SET_DL( context, BIN_TO_BCD(systime.wDay) );
            RESET_CFLAG(context);
        }
        break;

    case 0x05: /* SET REAL-TIME CLOCK DATE */
        FIXME( "SET REAL-TIME CLOCK DATE - not allowed\n" );
        break;

    case 0x06: /* SET ALARM */
        FIXME( "SET ALARM - unimplemented\n" );
        break;

    case 0x07: /* CANCEL ALARM */
        FIXME( "CANCEL ALARM - unimplemented\n" );
        break;

    case 0x08: /* SET RTC ACTIVATED POWER ON MODE */
    case 0x09: /* READ RTC ALARM TIME AND STATUS */
    case 0x0a: /* READ SYSTEM-TIMER DAY COUNTER */
    case 0x0b: /* SET SYSTEM-TIMER DAY COUNTER */
    case 0x0c: /* SET RTC DATE/TIME ACTIVATED POWER-ON MODE */
    case 0x0d: /* RESET RTC DATE/TIME ACTIVATED POWER-ON MODE */
    case 0x0e: /* GET RTC DATE/TIME ALARM AND STATUS */
    case 0x0f: /* INITIALIZE REAL-TIME CLOCK */
        INT_BARF( context, 0x1a );
        break;

    case 0xb0:
        if (CX_reg(context) == 0x4d52 &&
            DX_reg(context) == 0x4349 &&
            AL_reg(context) == 0x01)
        {
            /*
             * Microsoft Real-Time Compression Interface (MRCI).
             * Ignoring this call indicates MRCI is not supported.
             */
            TRACE( "Microsoft Real-Time Compression Interface - not supported\n" );
        }
        else
        {
            INT_BARF(context, 0x1a);
        }
        break;

    default:
        INT_BARF( context, 0x1a );
    }
}
예제 #24
0
static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
		     unsigned long arg)
{

	struct rtc_time wtime;

	switch (cmd) {
	case RTC_RD_TIME:	/* Read the time/date from RTC	*/
	{
		get_rtc_time(&wtime);
		break;
	}
	case RTC_SET_TIME:	/* Set the RTC */
	{
		struct rtc_time rtc_tm;
		unsigned char mon, day, hrs, min, sec, leap_yr;
		unsigned int yrs;
		unsigned long flags;

		if (!capable(CAP_SYS_TIME))
			return -EACCES;

		if (copy_from_user(&rtc_tm, (struct rtc_time*)arg,
				   sizeof(struct rtc_time)))
			return -EFAULT;

		yrs = rtc_tm.tm_year + 1900;
		mon = rtc_tm.tm_mon + 1;   /* tm_mon starts at zero */
		day = rtc_tm.tm_mday;
		hrs = rtc_tm.tm_hour;
		min = rtc_tm.tm_min;
		sec = rtc_tm.tm_sec;

		if (yrs < 1970)
			return -EINVAL;

		leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400));

		if ((mon > 12) || (day == 0))
			return -EINVAL;

		if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr)))
			return -EINVAL;

		if ((hrs >= 24) || (min >= 60) || (sec >= 60))
			return -EINVAL;

		if ((yrs -= epoch) > 255)    /* They are unsigned */
			return -EINVAL;

		save_flags(flags);
		cli();
		if (yrs > 169) {
			restore_flags(flags);
			return -EINVAL;
		}
		if (yrs >= 100)
			yrs -= 100;

		BIN_TO_BCD(sec);
		BIN_TO_BCD(min);
		BIN_TO_BCD(hrs);
		BIN_TO_BCD(day);
		BIN_TO_BCD(mon);
		BIN_TO_BCD(yrs);

		rtc->control &= ~M48T35_RTC_SET;
		rtc->year = yrs;
		rtc->month = mon;
		rtc->date = day;
		rtc->hour = hrs;
		rtc->min = min;
		rtc->sec = sec;
		rtc->control &= ~M48T35_RTC_SET;

		restore_flags(flags);
		return 0;
	}
	default:
		return -EINVAL;
	}
	return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0;
}
예제 #25
0
static int
acpi_system_write_alarm (
	struct file		*file,
	const char		*buffer,
	unsigned long		count,
	void			*data)
{
	int			result = 0;
	char			alarm_string[30] = {'\0'};
	char			*p = alarm_string;
	u32			sec, min, hr, day, mo, yr;
	int			adjust = 0;
	unsigned char		rtc_control = 0;

	ACPI_FUNCTION_TRACE("acpi_system_write_alarm");

	if (count > sizeof(alarm_string) - 1)
		return_VALUE(-EINVAL);
	
	if (copy_from_user(alarm_string, buffer, count))
		return_VALUE(-EFAULT);

	alarm_string[count] = '\0';

	/* check for time adjustment */
	if (alarm_string[0] == '+') {
		p++;
		adjust = 1;
	}

	if ((result = get_date_field(&p, &yr)))
		goto end;
	if ((result = get_date_field(&p, &mo)))
		goto end;
	if ((result = get_date_field(&p, &day)))
		goto end;
	if ((result = get_date_field(&p, &hr)))
		goto end;
	if ((result = get_date_field(&p, &min)))
		goto end;
	if ((result = get_date_field(&p, &sec)))
		goto end;

	if (sec > 59) {
		min += 1;
		sec -= 60;
	}
	if (min > 59) {
		hr += 1;
		min -= 60;
	}
	if (hr > 23) {
		day += 1;
		hr -= 24;
	}
	if (day > 31) {
		mo += 1;
		day -= 31;
	}
	if (mo > 12) {
		yr += 1;
		mo -= 12;
	}

	spin_lock_irq(&rtc_lock);

	rtc_control = CMOS_READ(RTC_CONTROL);
	if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
		BIN_TO_BCD(yr);
		BIN_TO_BCD(mo);
		BIN_TO_BCD(day);
		BIN_TO_BCD(hr);
		BIN_TO_BCD(min);
		BIN_TO_BCD(sec);
	}

	if (adjust) {
		yr  += CMOS_READ(RTC_YEAR);
		mo  += CMOS_READ(RTC_MONTH);
		day += CMOS_READ(RTC_DAY_OF_MONTH);
		hr  += CMOS_READ(RTC_HOURS);
		min += CMOS_READ(RTC_MINUTES);
		sec += CMOS_READ(RTC_SECONDS);
	}

	spin_unlock_irq(&rtc_lock);

	if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
		BCD_TO_BIN(yr);
		BCD_TO_BIN(mo);
		BCD_TO_BIN(day);
		BCD_TO_BIN(hr);
		BCD_TO_BIN(min);
		BCD_TO_BIN(sec);
	}

	if (sec > 59) {
		min++;
		sec -= 60;
	}
	if (min > 59) {
		hr++;
		min -= 60;
	}
	if (hr > 23) {
		day++;
		hr -= 24;
	}
	if (day > 31) {
		mo++;
		day -= 31;
	}
	if (mo > 12) {
		yr++;
		mo -= 12;
	}
	if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
		BIN_TO_BCD(yr);
		BIN_TO_BCD(mo);
		BIN_TO_BCD(day);
		BIN_TO_BCD(hr);
		BIN_TO_BCD(min);
		BIN_TO_BCD(sec);
	}

	spin_lock_irq(&rtc_lock);

	/* write the fields the rtc knows about */
	CMOS_WRITE(hr, RTC_HOURS_ALARM);
	CMOS_WRITE(min, RTC_MINUTES_ALARM);
	CMOS_WRITE(sec, RTC_SECONDS_ALARM);

	/*
	 * If the system supports an enhanced alarm it will have non-zero
	 * offsets into the CMOS RAM here -- which for some reason are pointing
	 * to the RTC area of memory.
	 */
#if 0
	if (acpi_gbl_FADT->day_alrm)
		CMOS_WRITE(day, acpi_gbl_FADT->day_alrm);
	if (acpi_gbl_FADT->mon_alrm)
		CMOS_WRITE(mo, acpi_gbl_FADT->mon_alrm);
	if (acpi_gbl_FADT->century)
		CMOS_WRITE(yr/100, acpi_gbl_FADT->century);
#endif
	/* enable the rtc alarm interrupt */
	if (!(rtc_control & RTC_AIE)) {
		rtc_control |= RTC_AIE;
		CMOS_WRITE(rtc_control,RTC_CONTROL);
		CMOS_READ(RTC_INTR_FLAGS);
	}

	spin_unlock_irq(&rtc_lock);

	acpi_set_register(ACPI_BITREG_RT_CLOCK_ENABLE, 1, ACPI_MTX_LOCK);

	file->f_pos += count;

	result = 0;
end:
	return_VALUE(result ? result : count);
}
예제 #26
0
static void am_or_pm(struct device *dev)
{
	char rtcdata [9];
	struct rtc_time tm, time, temp;
	unsigned char mon, day, hrs, min, sec;
	unsigned char yr_low, yr_high;
	unsigned int yrs;

	evm_read_time(dev, &tm);

	temp = tm;

	yrs = temp.tm_year + 1900;
	yr_high = yrs / 100;
	yr_low = yrs % 100;

	mon = temp.tm_mon + 1;
	day = temp.tm_mday;
	min = 59;
	sec = 59;
	hrs = 11;

	rtcdata [0] = 9;
	rtcdata [1] = 0;
	rtcdata [2] = BIN_TO_BCD(yr_low);
	rtcdata [3] = BIN_TO_BCD(yr_high);
	mon--;
	rtcdata [4] = BIN_TO_BCD(mon);
	rtcdata [5] = BIN_TO_BCD(day);
	rtcdata [6] = BIN_TO_BCD(hrs);
	rtcdata [7] = BIN_TO_BCD(min);
	rtcdata [8] = BIN_TO_BCD(sec);
	davinci_i2c_write(9, rtcdata, 0x23);
	msleep(1);
	msleep(1000);
	evm_read_time(dev, &time);

	if (time.tm_mday == temp.tm_mday)
		am = 1;
	else
		am = 0;

	davinci_i2c_write(9, rtcdata, 0x23);
	msleep(1);
	msleep(1000);

	yrs = tm.tm_year + 1900;
	yr_high = yrs / 100;
	yr_low = yrs % 100;

	mon = tm.tm_mon + 1;
	day = tm.tm_mday;
	min = tm.tm_min;
	hrs = tm.tm_hour;

	if (tm.tm_sec < 58)
		sec = tm.tm_sec + 2;
	else
		sec = 59;

	davinci_i2c_write(9, rtcdata, 0x23);
	msleep(1);
}
예제 #27
0
static int evm_set_time(struct device *dev, struct rtc_time *tm)
{
	char rtcdata [9];
	char ampmdata [9];
	unsigned char mon, day, hrs = 0, min, sec, leap_yr;
	unsigned char yr_low, yr_high;
	unsigned int yrs;

	am_or_pm(dev);

	yrs = tm->tm_year + 1900;
	yr_high = yrs / 100;
	yr_low = yrs % 100;

	mon = tm->tm_mon;
	hrs = tm->tm_hour;
	day = tm->tm_mday;
	min = tm->tm_min;
	sec = tm->tm_sec;

        leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400));

	if (am == 1 && tm->tm_hour <= 12) {
		hrs = tm->tm_hour;
		if (tm->tm_hour == 0)
			hrs = tm->tm_hour + 12;

	} else if ((am == 1 && tm->tm_hour > 12)
			|| (am == 0 && tm->tm_hour < 12)) {
		unsigned char mon1 = mon, day1 = day, hrs1 = 11;
		unsigned char min1 = 59, sec1 = 59;
		unsigned char yr_low1 = yr_low, yr_high1 = yr_high;

		ampmdata [0] = 9;
		ampmdata [1] = 0;
		ampmdata [2] = BIN_TO_BCD(yr_low1);
		ampmdata [3] = BIN_TO_BCD(yr_high1);
		ampmdata [4] = BIN_TO_BCD(mon1);
		ampmdata [5] = BIN_TO_BCD(day1);
		ampmdata [6] = BIN_TO_BCD(hrs1);
		ampmdata [7] = BIN_TO_BCD(min1);
		ampmdata [8] = BIN_TO_BCD(sec1);
		davinci_i2c_write(9, ampmdata, 0x23);
		msleep(1);
		msleep(1000);
		am = (am == 1) ? 0 : 1;

		if (!am)
			hrs = tm->tm_hour - 12;
		else if (tm->tm_hour == 0)
			hrs = tm->tm_hour + 12;

	} else if (am == 0 && tm->tm_hour > 12)
		hrs = tm->tm_hour - 12;

	rtcdata [0] = 9;
	rtcdata [1] = 0;
	rtcdata [2] = BIN_TO_BCD(yr_low);
	rtcdata [3] = BIN_TO_BCD(yr_high);
	rtcdata [4] = BIN_TO_BCD(mon);
	rtcdata [5] = BIN_TO_BCD(day);
	rtcdata [6] = BIN_TO_BCD(hrs);
	rtcdata [7] = BIN_TO_BCD(min);
	rtcdata [8] = BIN_TO_BCD(sec);

	davinci_i2c_write(9, rtcdata, 0x23);
	msleep(1);

	return 0;
}
예제 #28
0
파일: time.c 프로젝트: TitaniumBoy/lin
int atari_tt_hwclk( int op, struct hwclk_time *t )
{
    int sec=0, min=0, hour=0, day=0, mon=0, year=0, wday=0; 
    unsigned long 	flags;
    unsigned char	ctrl;
    int pm = 0;

    ctrl = RTC_READ(RTC_CONTROL); /* control registers are
                                   * independent from the UIP */

    if (op) {
        /* write: prepare values */
        
        sec  = t->sec;
        min  = t->min;
        hour = t->hour;
        day  = t->day;
        mon  = t->mon + 1;
        year = t->year - atari_rtc_year_offset;
        wday = t->wday + (t->wday >= 0);
        
        if (!(ctrl & RTC_24H)) {
	    if (hour > 11) {
		pm = 0x80;
		if (hour != 12)
		    hour -= 12;
	    }
	    else if (hour == 0)
		hour = 12;
        }
        
        if (!(ctrl & RTC_DM_BINARY)) {
            BIN_TO_BCD(sec);
            BIN_TO_BCD(min);
            BIN_TO_BCD(hour);
            BIN_TO_BCD(day);
            BIN_TO_BCD(mon);
            BIN_TO_BCD(year);
            if (wday >= 0) BIN_TO_BCD(wday);
        }
    }
    
    /* Reading/writing the clock registers is a bit critical due to
     * the regular update cycle of the RTC. While an update is in
     * progress, registers 0..9 shouldn't be touched.
     * The problem is solved like that: If an update is currently in
     * progress (the UIP bit is set), the process sleeps for a while
     * (50ms). This really should be enough, since the update cycle
     * normally needs 2 ms.
     * If the UIP bit reads as 0, we have at least 244 usecs until the
     * update starts. This should be enough... But to be sure,
     * additionally the RTC_SET bit is set to prevent an update cycle.
     */

    while( RTC_READ(RTC_FREQ_SELECT) & RTC_UIP ) {
        current->state = TASK_INTERRUPTIBLE;
        schedule_timeout(HWCLK_POLL_INTERVAL);
    }

    save_flags(flags);
    cli();
    RTC_WRITE( RTC_CONTROL, ctrl | RTC_SET );
    if (!op) {
        sec  = RTC_READ( RTC_SECONDS );
        min  = RTC_READ( RTC_MINUTES );
        hour = RTC_READ( RTC_HOURS );
        day  = RTC_READ( RTC_DAY_OF_MONTH );
        mon  = RTC_READ( RTC_MONTH );
        year = RTC_READ( RTC_YEAR );
        wday = RTC_READ( RTC_DAY_OF_WEEK );
    }
    else {
        RTC_WRITE( RTC_SECONDS, sec );
        RTC_WRITE( RTC_MINUTES, min );
        RTC_WRITE( RTC_HOURS, hour + pm);
        RTC_WRITE( RTC_DAY_OF_MONTH, day );
        RTC_WRITE( RTC_MONTH, mon );
        RTC_WRITE( RTC_YEAR, year );
        if (wday >= 0) RTC_WRITE( RTC_DAY_OF_WEEK, wday );
    }
    RTC_WRITE( RTC_CONTROL, ctrl & ~RTC_SET );
    restore_flags(flags);

    if (!op) {
        /* read: adjust values */
        
        if (hour & 0x80) {
	    hour &= ~0x80;
	    pm = 1;
	}

	if (!(ctrl & RTC_DM_BINARY)) {
            BCD_TO_BIN(sec);
            BCD_TO_BIN(min);
            BCD_TO_BIN(hour);
            BCD_TO_BIN(day);
            BCD_TO_BIN(mon);
            BCD_TO_BIN(year);
            BCD_TO_BIN(wday);
        }

        if (!(ctrl & RTC_24H)) {
	    if (!pm && hour == 12)
		hour = 0;
	    else if (pm && hour != 12)
		hour += 12;
        }

        t->sec  = sec;
        t->min  = min;
        t->hour = hour;
        t->day  = day;
        t->mon  = mon - 1;
        t->year = year + atari_rtc_year_offset;
        t->wday = wday - 1;
    }

    return( 0 );
}
예제 #29
0
static int
rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
	  unsigned long arg) 
{
	unsigned long flags;

	switch(cmd) {
		case RTC_RD_TIME:	/* read the time/date from RTC	*/
		{
			struct rtc_time rtc_tm;
						
			memset(&rtc_tm, 0, sizeof (struct rtc_time));
			get_rtc_time(&rtc_tm);						
			if (copy_to_user((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time)))
				return -EFAULT;	
			return 0;
		}

		case RTC_SET_TIME:	/* set the RTC */
		{
			struct rtc_time rtc_tm;
			unsigned char mon, day, hrs, min, sec, leap_yr;
			unsigned int yrs;

			if (!capable(CAP_SYS_TIME))
				return -EPERM;

			if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time)))
				return -EFAULT;

			yrs = rtc_tm.tm_year + 1900;
			mon = rtc_tm.tm_mon + 1;   /* tm_mon starts at zero */
			day = rtc_tm.tm_mday;
			hrs = rtc_tm.tm_hour;
			min = rtc_tm.tm_min;
			sec = rtc_tm.tm_sec;
			
			
			if ((yrs < 1970) || (yrs > 2069))
				return -EINVAL;

			leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400));

			if ((mon > 12) || (day == 0))
				return -EINVAL;

			if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr)))
				return -EINVAL;
			
			if ((hrs >= 24) || (min >= 60) || (sec >= 60))
				return -EINVAL;

			if (yrs >= 2000)
				yrs -= 2000;	/* RTC (0, 1, ... 69) */
			else
				yrs -= 1900;	/* RTC (70, 71, ... 99) */

			BIN_TO_BCD(sec);
			BIN_TO_BCD(min);
			BIN_TO_BCD(hrs);
			BIN_TO_BCD(day);
			BIN_TO_BCD(mon);
			BIN_TO_BCD(yrs);

			local_irq_save(flags);
			CMOS_WRITE(yrs, RTC_YEAR);
			CMOS_WRITE(mon, RTC_MONTH);
			CMOS_WRITE(day, RTC_DAY_OF_MONTH);
			CMOS_WRITE(hrs, RTC_HOURS);
			CMOS_WRITE(min, RTC_MINUTES);
			CMOS_WRITE(sec, RTC_SECONDS);
			local_irq_restore(flags);

			/* Notice that at this point, the RTC is updated but
			 * the kernel is still running with the old time.
			 * You need to set that separately with settimeofday
			 * or adjtimex.
			 */
			return 0;
		}

		case RTC_SET_CHARGE: /* set the RTC TRICKLE CHARGE register */
		{
			int tcs_val;

			if (!capable(CAP_SYS_TIME))
				return -EPERM;
			
			if(copy_from_user(&tcs_val, (int*)arg, sizeof(int)))
				return -EFAULT;

			tcs_val = RTC_TCR_PATTERN | (tcs_val & 0x0F);
			ds1302_writereg(RTC_TRICKLECHARGER, tcs_val);
			return 0;
		}
		case RTC_VLOW_RD:
		{
			/* TODO:
			 * Implement voltage low detection support
			 */
			printk(KERN_WARNING "DS1302: RTC Voltage Low detection"
			       " is not supported\n");
			return 0;
		}
		case RTC_VLOW_SET:
		{
			/* TODO:
			 * Nothing to do since Voltage Low detection is not supported
			 */
			return 0;
		}
		default:
			return -ENOIOCTLCMD;
	}
}
예제 #30
0
static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
		     unsigned long arg)
{
	struct rtc_time wtime; 

#if RTC_IRQ
	if (rtc_has_irq == 0) {
		switch (cmd) {
		case RTC_AIE_OFF:
		case RTC_AIE_ON:
		case RTC_PIE_OFF:
		case RTC_PIE_ON:
		case RTC_UIE_OFF:
		case RTC_UIE_ON:
		case RTC_IRQP_READ:
		case RTC_IRQP_SET:
			return -EINVAL;
		};
	}
#endif

	switch (cmd) {
#if RTC_IRQ
	case RTC_AIE_OFF:	/* Mask alarm int. enab. bit	*/
	{
		mask_rtc_irq_bit(RTC_AIE);
		return 0;
	}
	case RTC_AIE_ON:	/* Allow alarm interrupts.	*/
	{
		set_rtc_irq_bit(RTC_AIE);
		return 0;
	}
	case RTC_PIE_OFF:	/* Mask periodic int. enab. bit	*/
	{
		mask_rtc_irq_bit(RTC_PIE);
		if (rtc_status & RTC_TIMER_ON) {
			spin_lock_irq (&rtc_lock);
			rtc_status &= ~RTC_TIMER_ON;
			del_timer(&rtc_irq_timer);
			spin_unlock_irq (&rtc_lock);
		}
		return 0;
	}
	case RTC_PIE_ON:	/* Allow periodic ints		*/
	{

		/*
		 * We don't really want Joe User enabling more
		 * than 64Hz of interrupts on a multi-user machine.
		 */
		if ((rtc_freq > rtc_max_user_freq) && 
		    (!capable(CAP_SYS_RESOURCE)))
			return -EACCES;

		if (!(rtc_status & RTC_TIMER_ON)) {
			spin_lock_irq (&rtc_lock);
			rtc_irq_timer.expires = jiffies + HZ/rtc_freq + 2*HZ/100;
			add_timer(&rtc_irq_timer);
			rtc_status |= RTC_TIMER_ON;
			spin_unlock_irq (&rtc_lock);
		}
		set_rtc_irq_bit(RTC_PIE);
		return 0;
	}
	case RTC_UIE_OFF:	/* Mask ints from RTC updates.	*/
	{
		mask_rtc_irq_bit(RTC_UIE);
		return 0;
	}
	case RTC_UIE_ON:	/* Allow ints for RTC updates.	*/
	{
		set_rtc_irq_bit(RTC_UIE);
		return 0;
	}
#endif
	case RTC_ALM_READ:	/* Read the present alarm time */
	{
		/*
		 * This returns a struct rtc_time. Reading >= 0xc0
		 * means "don't care" or "match all". Only the tm_hour,
		 * tm_min, and tm_sec values are filled in.
		 */
		memset(&wtime, 0, sizeof(struct rtc_time));
		get_rtc_alm_time(&wtime);
		break; 
	}
	case RTC_ALM_SET:	/* Store a time into the alarm */
	{
		/*
		 * This expects a struct rtc_time. Writing 0xff means
		 * "don't care" or "match all". Only the tm_hour,
		 * tm_min and tm_sec are used.
		 */
		unsigned char hrs, min, sec;
		struct rtc_time alm_tm;

		if (copy_from_user(&alm_tm, (struct rtc_time*)arg,
				   sizeof(struct rtc_time)))
			return -EFAULT;

		hrs = alm_tm.tm_hour;
		min = alm_tm.tm_min;
		sec = alm_tm.tm_sec;

		spin_lock_irq(&rtc_lock);
		if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) ||
		    RTC_ALWAYS_BCD)
		{
			if (sec < 60) BIN_TO_BCD(sec);
			else sec = 0xff;

			if (min < 60) BIN_TO_BCD(min);
			else min = 0xff;

			if (hrs < 24) BIN_TO_BCD(hrs);
			else hrs = 0xff;
		}
		CMOS_WRITE(hrs, RTC_HOURS_ALARM);
		CMOS_WRITE(min, RTC_MINUTES_ALARM);
		CMOS_WRITE(sec, RTC_SECONDS_ALARM);
		spin_unlock_irq(&rtc_lock);

		return 0;
	}
	case RTC_RD_TIME:	/* Read the time/date from RTC	*/
	{
		memset(&wtime, 0, sizeof(struct rtc_time));
		get_rtc_time(&wtime);
		break;
	}
	case RTC_SET_TIME:	/* Set the RTC */
	{
		struct rtc_time rtc_tm;
		unsigned char mon, day, hrs, min, sec, leap_yr;
		unsigned char save_control, save_freq_select;
		unsigned int yrs;
#ifdef CONFIG_DECSTATION
		unsigned int real_yrs;
#endif

		if (!capable(CAP_SYS_TIME))
			return -EACCES;

		if (copy_from_user(&rtc_tm, (struct rtc_time*)arg,
				   sizeof(struct rtc_time)))
			return -EFAULT;

		yrs = rtc_tm.tm_year + 1900;
		mon = rtc_tm.tm_mon + 1;   /* tm_mon starts at zero */
		day = rtc_tm.tm_mday;
		hrs = rtc_tm.tm_hour;
		min = rtc_tm.tm_min;
		sec = rtc_tm.tm_sec;

		if (yrs < 1970)
			return -EINVAL;

		leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400));

		if ((mon > 12) || (day == 0))
			return -EINVAL;

		if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr)))
			return -EINVAL;
			
		if ((hrs >= 24) || (min >= 60) || (sec >= 60))
			return -EINVAL;

		if ((yrs -= epoch) > 255)    /* They are unsigned */
			return -EINVAL;

		spin_lock_irq(&rtc_lock);
#ifdef CONFIG_DECSTATION
		real_yrs = yrs;
		yrs = 72;

		/*
		 * We want to keep the year set to 73 until March
		 * for non-leap years, so that Feb, 29th is handled
		 * correctly.
		 */
		if (!leap_yr && mon < 3) {
			real_yrs--;
			yrs = 73;
		}
#endif
		/* These limits and adjustments are independant of
		 * whether the chip is in binary mode or not.
		 */
		if (yrs > 169) {
			spin_unlock_irq(&rtc_lock);
			return -EINVAL;
		}
		if (yrs >= 100)
			yrs -= 100;

		if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY)
		    || RTC_ALWAYS_BCD) {
			BIN_TO_BCD(sec);
			BIN_TO_BCD(min);
			BIN_TO_BCD(hrs);
			BIN_TO_BCD(day);
			BIN_TO_BCD(mon);
			BIN_TO_BCD(yrs);
		}

		save_control = CMOS_READ(RTC_CONTROL);
		CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
		save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
		CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);

#ifdef CONFIG_DECSTATION
		CMOS_WRITE(real_yrs, RTC_DEC_YEAR);
#endif
		CMOS_WRITE(yrs, RTC_YEAR);
		CMOS_WRITE(mon, RTC_MONTH);
		CMOS_WRITE(day, RTC_DAY_OF_MONTH);
		CMOS_WRITE(hrs, RTC_HOURS);
		CMOS_WRITE(min, RTC_MINUTES);
		CMOS_WRITE(sec, RTC_SECONDS);

		CMOS_WRITE(save_control, RTC_CONTROL);
		CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);

		spin_unlock_irq(&rtc_lock);
		return 0;
	}
#if RTC_IRQ
	case RTC_IRQP_READ:	/* Read the periodic IRQ rate.	*/
	{
		return put_user(rtc_freq, (unsigned long *)arg);
	}
	case RTC_IRQP_SET:	/* Set periodic IRQ rate.	*/
	{
		int tmp = 0;
		unsigned char val;

		/* 
		 * The max we can do is 8192Hz.
		 */
		if ((arg < 2) || (arg > 8192))
			return -EINVAL;
		/*
		 * We don't really want Joe User generating more
		 * than 64Hz of interrupts on a multi-user machine.
		 */
		if ((arg > rtc_max_user_freq) && (!capable(CAP_SYS_RESOURCE)))
			return -EACCES;

		while (arg > (1<<tmp))
			tmp++;

		/*
		 * Check that the input was really a power of 2.
		 */
		if (arg != (1<<tmp))
			return -EINVAL;

		spin_lock_irq(&rtc_lock);
		rtc_freq = arg;

		val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0;
		val |= (16 - tmp);
		CMOS_WRITE(val, RTC_FREQ_SELECT);
		spin_unlock_irq(&rtc_lock);
		return 0;
	}
#endif
	case RTC_EPOCH_READ:	/* Read the epoch.	*/
	{
		return put_user (epoch, (unsigned long *)arg);
	}
	case RTC_EPOCH_SET:	/* Set the epoch.	*/
	{
		/* 
		 * There were no RTC clocks before 1900.
		 */
		if (arg < 1900)
			return -EINVAL;

		if (!capable(CAP_SYS_TIME))
			return -EACCES;

		epoch = arg;
		return 0;
	}
	default:
		return -EINVAL;
	}
	return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0;
}