--- linuxppc_2_4_ORI/drivers/char/rtc_5xxx.c 1970-01-01 01:00:00.000000000 +0100 +++ linuxppc_2_4_devel/drivers/char/rtc_5xxx.c 2007-11-23 11:04:46.000000000 +0100 @@ -0,0 +1,212 @@ +/* + * MPC5xxx Real Time Clock Driver + * + * (c) Copyright 2005 + * Stefan Strobl, GERSYS GmbH + * + * based on /driver/char/rtc_8xx.c: + * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu) + * + * and on the u-boot source /rtc/mpc5xxx.c: + * (C) Copyright 2004 + * Reinhard Meyer, EMK Elektronik GmbH + * r.meyer@emk-elektronik.de + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef DEBUG +#ifdef DEBUG +# define dprintk(fmt,args...) printk(fmt, ##args) +#else +# define dprintk(fmt,args...) +#endif + +static int rtc_busy = 0; + +/* Retrieve the current date and time from the real time clock. */ +void get_rtc_time(struct rtc_time *t) +{ + struct mpc5xxx_rtc_u32 *rtc = (struct mpc5xxx_rtc_u32 *)(MPC5xxx_RTC); + unsigned long time, date, time2; + unsigned long flags; + + save_flags(flags); + cli(); + + /* read twice to avoid getting a funny time when the second is just changing */ + do { + time = rtc->ctr; + date = rtc->cdr; + time2 = rtc->ctr; + } while (time != time2); + + restore_flags(flags); + + t->tm_year = (date & 0xfff) - 1900; + t->tm_mon = ((date >> 24) & 0x0f) - 1; + t->tm_mday = (date >> 16) & 0x1f; + t->tm_wday = ((date >> 21) & 0x07); + /* sunday is 7 in 5200 but 0 in rtc_time */ + if (t->tm_wday == 7) + t->tm_wday = 0; + t->tm_hour = (time >> 16) & 0x1f; + t->tm_min = (time >> 8) & 0x3f; + t->tm_sec = time & 0x3f; + + dprintk(KERN_INFO "rtc_5xxx.c: get_rtc_time(): %04d-%02d-%02d (wday=%d) %02d:%02d:%02d\n", + t->tm_year +1900, t->tm_mon +1, t->tm_mday, t->tm_wday +1, + t->tm_hour, t->tm_min, t->tm_sec); + +} + +/* Set the current date and time in the real time clock. */ +void set_rtc_time(struct rtc_time *t) +{ + struct mpc5xxx_rtc_u32 *rtc = (struct mpc5xxx_rtc_u32 *)(MPC5xxx_RTC); + unsigned long time, date, year; + unsigned long flags; + + dprintk(KERN_INFO "rtc_5xxx.c: set_rtc_time(): %04d-%02d-%02d (wday=%d) %02d:%02d:%02d\n", + t->tm_year +1900, t->tm_mon +1, t->tm_mday, t->tm_wday +1, + t->tm_hour, t->tm_min, t->tm_sec); + + time = (t->tm_hour << 16) | (t->tm_min << 8) | t->tm_sec; + date = ((t->tm_mon +1) << 16) | t->tm_mday; + if (t->tm_wday == 0) + date |= (7 << 8); + else + date |= (t->tm_wday << 8); + year = t->tm_year +1900; + + /* mask unwanted bits that might show up when rtc_time is corrupt */ + time &= 0x001f3f3f; + date &= 0x001f071f; + year &= 0x00000fff; + + save_flags(flags); + cli(); + + /* pause and set the RTC */ + rtc->nysr = year; + rtc->dsr = date | MPC5xxx_RTC_PAUSE; + udelay (1000); + rtc->dsr = date | MPC5xxx_RTC_PAUSE | MPC5xxx_RTC_SET; + udelay (1000); + rtc->dsr = date | MPC5xxx_RTC_PAUSE; + udelay (1000); + rtc->dsr = date; + udelay (1000); + + rtc->tsr = time | MPC5xxx_RTC_PAUSE; + udelay (1000); + rtc->tsr = time | MPC5xxx_RTC_PAUSE | MPC5xxx_RTC_SET; + udelay (1000); + rtc->tsr = time | MPC5xxx_RTC_PAUSE; + udelay (1000); + rtc->tsr = time; + udelay (1000); + + restore_flags(flags); +} + +static loff_t rtc_lseek(struct file *file, loff_t offset, int origin) +{ + return -ESPIPE; +} + +static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct rtc_time rtc_tm; + + switch (cmd) + { + case RTC_RD_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: + if (!capable(CAP_SYS_TIME)) + return -EPERM; + + if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time))) + return -EFAULT; + + set_rtc_time(&rtc_tm); + + return 0; + + default: + return -EINVAL; + } +} + +static int rtc_open(struct inode *inode, struct file *file) +{ + if (rtc_busy) + return -EBUSY; + + rtc_busy = 1; + + MOD_INC_USE_COUNT; + + return 0; +} + +static int rtc_release(struct inode *inode, struct file *file) +{ + MOD_DEC_USE_COUNT; + rtc_busy = 0; + return 0; +} + +static struct file_operations rtc_fops = { + owner: THIS_MODULE, + llseek: rtc_lseek, + ioctl: rtc_ioctl, + open: rtc_open, + release: rtc_release +}; + +static struct miscdevice rtc_dev = { RTC_MINOR, "rtc", &rtc_fops }; + +EXPORT_NO_SYMBOLS; + +static int __init rtc_init(void) +{ + int error; + + error = misc_register(&rtc_dev); + if (error) { + printk(KERN_ERR "rtc: unable to get misc minor\n"); + return error; + } + + return 0; +} + +static void __exit rtc_exit(void) +{ + misc_deregister(&rtc_dev); +} + +module_init(rtc_init); +module_exit(rtc_exit); + +MODULE_LICENSE("GPL"); --- linuxppc_2_4_ORI/drivers/char/Makefile 2007-11-26 13:31:40.000000000 +0100 +++ linuxppc_2_4_devel/drivers/char/Makefile 2007-11-22 12:01:20.000000000 +0100 @@ -308,6 +308,7 @@ obj-$(CONFIG_RTC) += rtc.o obj-$(CONFIG_GEN_RTC) += genrtc.o obj-$(CONFIG_EFI_RTC) += efirtc.o obj-$(CONFIG_RTC_8XX) += rtc_8xx.o +obj-$(CONFIG_RTC_5XXX) += rtc_5xxx.o obj-$(CONFIG_SGI_DS1286) += ds1286.o obj-$(CONFIG_MIPS_RTC) += mips_rtc.o obj-$(CONFIG_SGI_IP27_RTC) += ip27-rtc.o --- linuxppc_2_4_ORI/include/asm-ppc/mpc5xxx.h 2007-11-26 13:31:54.000000000 +0100 +++ linuxppc_2_4_devel/include/asm-ppc/mpc5xxx.h 2007-11-26 16:11:13.246536737 +0100 @@ -230,6 +230,10 @@ #define MPC5xxx_I2C_IF 0x02 /* I2Cn Interrupt */ #define MPC5xxx_I2C_RXAK 0x01 /* Receive ack */ +/* RTC command values */ +#define MPC5xxx_RTC_SET 0x02000000 +#define MPC5xxx_RTC_PAUSE 0x01000000 + /* Programmable Serial Controller (PSC) status register bits */ #define MPC5xxx_PSC_SR_CDE 0x0080 #define MPC5xxx_PSC_SR_RXRDY 0x0100 @@ -609,6 +613,18 @@ struct mpc5xxx_rtc { volatile u16 reserved2; }; +struct mpc5xxx_rtc_u32 { + volatile u32 tsr; /* RTC + 0x00: Time Set Register */ + volatile u32 dsr; /* RTC + 0x04: Date Set Register */ + volatile u32 nysr; /* RTC + 0x08: New Year and Stopwatch */ + volatile u32 aier; /* RTC + 0x0c: Alarm and Interrupt Enable */ + volatile u32 ctr; /* RTC + 0x10: Current Time Register */ + volatile u32 cdr; /* RTC + 0x14: Current Date Register */ + volatile u32 asir; /* RTC + 0x18: Alarm and Stopwatch Int */ + volatile u32 piber; /* RTC + 0x1c: Periodic Int and Bus Error */ + volatile u32 trdr; /* RTC + 0x20: Test/Devides Register */ +}; + struct mpc5xxx_gpio { volatile u32 port_config; /* GPIO + 0x00 */ volatile u32 simple_gpioe; /* GPIO + 0x04 */ @@ -958,6 +974,8 @@ void mpc5xxx_pci_init_windows(u8 win0_ct #include #elif defined(CONFIG_UC101) #include +#elif defined(CONFIG_BC3450) +#include #endif #endif /* __ASSEMBLY__ */ --- linuxppc_2_4_ORI/Documentation/Configure.help 2007-11-26 13:31:38.000000000 +0100 +++ linuxppc_2_4_TEST/Documentation/Configure.help 2007-11-26 18:36:45.615386590 +0100 @@ -20914,6 +20914,12 @@ CONFIG_RTC The module is called rtc.o. If you want to compile it as a module, say M here and read . +5xxx Real Time Clock +CONFIG_RTC_5XXX + If you say Y here and create a character special file /dev/rtc with + major number 10 and minor number 135 using mknod ("man mknod"), you + will get access to the buit in Real Time Clock of your MPC5200. + Generic MIPS RTC Support CONFIG_MIPS_RTC