/* * linux/drivers/char/rtc.c * * Copyright (C) 2004 Texas Instruments Inc * * ---------------------------------------------------------------------------- * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * ---------------------------------------------------------------------------- Modifications: ver. 1.0: Jan 2006, Swaminathan S - */ #include #include #include #include #include #include #include #include #include #include static unsigned char am; static int _rtc_read_time(struct rtc_time *tm); static int _rtc_set_time(struct rtc_time *tm); static void am_or_pm (void); static struct rtc_ops davinci_rtc_ops = { .owner = THIS_MODULE, .read_time = _rtc_read_time, .set_time = _rtc_set_time, }; static unsigned long epoch = 1900; /* year corresponding to 0x00 */ static const unsigned char days_in_mo[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; static int _rtc_read_time(struct rtc_time *tm) { char rtcdata [9] = { 2, 1, 0, 0, 0, 0, 0, 0, 0 }; davinci_i2c_write (2, rtcdata, 0x23); udelay (1000); davinci_i2c_read (9, rtcdata, 0x23); udelay (1000); tm->tm_year = BCD_TO_BIN (rtcdata[3]) * 100 + BCD_TO_BIN (rtcdata[2]) - 1900; tm->tm_mon = BCD_TO_BIN (rtcdata[4]); tm->tm_mday = BCD_TO_BIN (rtcdata[5]); tm->tm_hour = BCD_TO_BIN (rtcdata[6]); tm->tm_min = BCD_TO_BIN (rtcdata[7]); tm->tm_sec = BCD_TO_BIN (rtcdata[8]); return 0; } static int _rtc_set_time(struct rtc_time *tm) { char rtcdata [9]; char ampmdata [9]; struct timespec tv; unsigned char mon, day, hrs = 0, min, sec, leap_yr; unsigned char yr_low, yr_high; unsigned int yrs; am_or_pm (); 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; if (yrs < 1970 || yrs > 2037) return -EINVAL; leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); if ((mon > 11) || (day == 0)) return -EINVAL; if (day > (days_in_mo[mon] + ((mon == 1) && leap_yr))) return -EINVAL; if ((hrs >= 24) || (min >= 60) || (sec >= 60)) return -EINVAL; if ((yrs -= epoch) > 255) { /* They are unsigned */ return -EINVAL; } 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, 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); udelay (1000); mdelay (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); udelay (1000); tv.tv_nsec = 0; tv.tv_sec = mktime (tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec+2); do_settimeofday (&tv); return 0; } static void am_or_pm (void) { 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; _rtc_read_time (&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); udelay (1000); mdelay (1000); _rtc_read_time (&time); if (time.tm_mday == temp.tm_mday) am = 1; else am = 0; davinci_i2c_write (9, rtcdata, 0x23); udelay (1000); mdelay (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); udelay (1000); } static int __init davinci_rtc_init(void) { struct timespec tv; struct rtc_time tm; register_rtc (&davinci_rtc_ops); am_or_pm (); _rtc_read_time (&tm); tv.tv_nsec = 0; tv.tv_sec = mktime (tm.tm_year + 1900, tm.tm_mon + 1 , tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); do_settimeofday (&tv); return 0; } module_init(davinci_rtc_init);