diff options
author | Steffen Sledz <sledz@dresearch.de> | 2009-12-02 10:09:56 +0100 |
---|---|---|
committer | Steffen Sledz <sledz@dresearch.de> | 2009-12-02 10:37:51 +0100 |
commit | 30a4b103d2588d27cdd6642e1ab7699f7d374479 (patch) | |
tree | 226f14bcc4996f9e0bc25989271e0cea08828610 /recipes/linux/linux-2.6.24/hipox | |
parent | 5d76cdd2b8a9251b0405bb4fd28673df9d887535 (diff) |
linux-2.6.24: use rtc-drbcc at hipox machine
Signed-off-by: Steffen Sledz <sledz@dresearch.de>
Diffstat (limited to 'recipes/linux/linux-2.6.24/hipox')
-rw-r--r-- | recipes/linux/linux-2.6.24/hipox/defconfig | 9 | ||||
-rw-r--r-- | recipes/linux/linux-2.6.24/hipox/hipox-rtc.patch | 650 |
2 files changed, 656 insertions, 3 deletions
diff --git a/recipes/linux/linux-2.6.24/hipox/defconfig b/recipes/linux/linux-2.6.24/hipox/defconfig index f2ef01afad..94a50dcd78 100644 --- a/recipes/linux/linux-2.6.24/hipox/defconfig +++ b/recipes/linux/linux-2.6.24/hipox/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Linux kernel version: 2.6.24.4 -# Fri Nov 27 16:35:59 2009 +# Tue Dec 1 12:22:00 2009 # CONFIG_ARM=y CONFIG_SYS_SUPPORTS_APM_EMULATION=y @@ -203,7 +203,7 @@ CONFIG_ARCH_HIPOX_NUM_GMAC_DESCRIPTORS=192 CONFIG_ARCH_HIPOX_MAX_SATA_SG_ENTRIES=256 CONFIG_TACHO_THERM_AND_FAN=m # CONFIG_GPIO_TEST is not set -CONFIG_HIPOX_RTC=y +# CONFIG_HIPOX_RTC is not set # CONFIG_I2S is not set # CONFIG_DPE_TEST is not set # CONFIG_HIPOX_INSTRUMENT_COPIES is not set @@ -1085,7 +1085,7 @@ CONFIG_RTC_INTF_DEV=y # # I2C RTC drivers # -CONFIG_RTC_DRV_DS1307=y +# CONFIG_RTC_DRV_DS1307 is not set # CONFIG_RTC_DRV_DS1374 is not set # CONFIG_RTC_DRV_DS1672 is not set # CONFIG_RTC_DRV_MAX6900 is not set @@ -1104,6 +1104,9 @@ CONFIG_RTC_DRV_DS1307=y # Platform RTC drivers # # CONFIG_RTC_DRV_CMOS is not set +CONFIG_RTC_DRV_DRBCC=y +CONFIG_RTC_DRV_DRBCC_DEVPATH="/dev/ttyS0" +CONFIG_RTC_DRV_DRBCC_BAUD=921600 # CONFIG_RTC_DRV_DS1553 is not set # CONFIG_RTC_DRV_STK17TA8 is not set # CONFIG_RTC_DRV_DS1742 is not set diff --git a/recipes/linux/linux-2.6.24/hipox/hipox-rtc.patch b/recipes/linux/linux-2.6.24/hipox/hipox-rtc.patch new file mode 100644 index 0000000000..32093b57b0 --- /dev/null +++ b/recipes/linux/linux-2.6.24/hipox/hipox-rtc.patch @@ -0,0 +1,650 @@ +diff -Nurd linux-2.6.24.orig//drivers/rtc/Kconfig linux-2.6.24/drivers/rtc/Kconfig +--- linux-2.6.24.orig//drivers/rtc/Kconfig 2009-12-01 12:31:46.000000000 +0100 ++++ linux-2.6.24/drivers/rtc/Kconfig 2009-12-01 12:32:21.000000000 +0100 +@@ -296,6 +296,31 @@ + This driver can also be built as a module. If so, the module + will be called rtc-cmos. + ++config RTC_DRV_DRBCC ++ tristate "RTC via HIPOX BCTRL" ++ depends on MACH_HIPOX ++ help ++ Say "yes" here to get support for the real time clock ++ found on HIPOX system. ++ ++ This driver can also be built as a module. If so, the module ++ will be called rtc-drbcc. ++ ++config RTC_DRV_DRBCC_DEVPATH ++ string "Serial device to connect with BCTRL" ++ depends on RTC_DRV_DRBCC ++ default "/dev/ttyS0" ++ help ++ Serial device to connect with BCTRL ++ found on HIPOX system. ++ ++config RTC_DRV_DRBCC_BAUD ++ int "Baud rate for BCTRL serial port (integer)" ++ depends on RTC_DRV_DRBCC ++ default 921600 ++ help ++ Baud rate for BCTRL serial port. ++ + config RTC_DRV_DS1216 + tristate "Dallas DS1216" + depends on SNI_RM +diff -Nurd linux-2.6.24.orig//drivers/rtc/Makefile linux-2.6.24/drivers/rtc/Makefile +--- linux-2.6.24.orig//drivers/rtc/Makefile 2009-12-01 12:31:46.000000000 +0100 ++++ linux-2.6.24/drivers/rtc/Makefile 2009-12-01 12:32:25.000000000 +0100 +@@ -21,6 +21,7 @@ + obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o + obj-$(CONFIG_RTC_DRV_BFIN) += rtc-bfin.o + obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o ++obj-$(CONFIG_RTC_DRV_DRBCC) += rtc-drbcc.o + obj-$(CONFIG_RTC_DRV_DS1216) += rtc-ds1216.o + obj-$(CONFIG_RTC_DRV_DS1307) += rtc-ds1307.o + obj-$(CONFIG_RTC_DRV_DS1374) += rtc-ds1374.o +diff -Nurd linux-2.6.24.orig//drivers/rtc/rtc-drbcc.c linux-2.6.24/drivers/rtc/rtc-drbcc.c +--- linux-2.6.24.orig//drivers/rtc/rtc-drbcc.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.24/drivers/rtc/rtc-drbcc.c 2009-12-01 12:32:29.000000000 +0100 +@@ -0,0 +1,600 @@ ++/* Editor hints for vim ++ * vim:set ts=4 sw=4 noexpandtab: ++ * ++ * HydraIP DRBCC RTC driver ++ * Copyright (C) 2009 DResearch Digital Media Systems ++ * Author: Steffen Sledz <sledz@dresearch.de> ++ * ++ * For usage of filp_open, vfs_read, ..._ioctl & Co. e.g. see : ++ * - http://www.linuxquestions.org/questions/programming-9/accessing-tty-in-kernel-space-596538/ ++ * - http://www.linux.it/~rubini/docs/ksys/ksys.html ++ * ++ * $Id: rtc-drbcc.c 2276 2009-12-02 08:28:25Z sledz $ ++ */ ++ ++#include <linux/module.h> ++#include <linux/err.h> ++#include <linux/rtc.h> ++#include <linux/platform_device.h> ++#include <linux/termios.h> ++#include <linux/bcd.h> ++ ++#define MODULE_NAME "rtc-drbcc" ++ ++/* ++ * Set this to zero to remove all the debug statements via ++ * dead code elimination ++ */ ++#define DEBUGGING 1 ++ ++#if DEBUGGING ++static unsigned int rtc_debug = DEBUGGING; ++#else ++#define rtc_debug 0 /* gcc will remove all the debug code for us */ ++#endif ++ ++#define PDEBUG(lvl, fmt, args...) if(rtc_debug >= (lvl)) { printk(KERN_DEBUG MODULE_NAME "[%s] " fmt "\n" , __FUNCTION__, ## args); } ++#define PINFO(fmt, args...) printk(KERN_INFO MODULE_NAME "[%s] " fmt "\n" , __FUNCTION__, ## args); ++#define PERROR(fmt, args...) printk(KERN_ERR MODULE_NAME "[%s] " fmt "\n" , __FUNCTION__, ## args); ++ ++#define START 0xFA ++#define STOP 0xFB ++ ++#define lo8(x) ((x) & 0xFF) ++#define hi8(x) ((x) >> 8) ++ ++/* ++ * Driver parameters ++ */ ++static int debug = 0; ++ ++#ifdef CONFIG_RTC_DRV_DRBCC_DEVPATH ++static char devpath[256] = CONFIG_RTC_DRV_DRBCC_DEVPATH; ++#else ++static char devpath[256] = "/dev/ttyS0"; ++#endif // CONFIG_RTC_DRV_DRBCC_DEVPATH ++ ++#ifdef CONFIG_RTC_DRV_DRBCC_BAUD ++static int baud = CONFIG_RTC_DRV_DRBCC_BAUD; ++#else ++static int baud = 921600; ++#endif // CONFIG_RTC_DRV_DRBCC_BAUD ++ ++module_param(debug, int, 0); ++module_param_string(devpath, devpath, sizeof(devpath), 0); ++module_param(baud, int, 0); ++#if DEBUGGING ++MODULE_PARM_DESC(debug, "debug level (0-6)"); ++#else ++MODULE_PARM_DESC(debug, "(ignored)"); ++#endif ++MODULE_PARM_DESC(devpath, "Serial device to connect with BCTRL (default: /dev/ttyS0)"); ++MODULE_PARM_DESC(baud, "Baud rate for BCTRL serial port (default: 921600)"); ++ ++static struct platform_device *rtc_drbcc0 = NULL; ++ ++static uint8_t myackbit = 0x80; ++ ++/* ++ * drbcc commands (see drbcc_ll.h) ++ */ ++#define RTC_DRBCC_ACK 0x00 ++#define RTC_DRBCC_SYNC 0x01 ++#define RTC_DRBCC_REQ_RTC_READ 0x05 ++#define RTC_DRBCC_IND_RTC_READ 0x06 ++#define RTC_DRBCC_REQ_RTC_SET 0x07 ++ ++static uint16_t rtc_drbcc_crc_ccitt_update(uint16_t crc, uint8_t data) ++{ ++ data ^= lo8 (crc); ++ data ^= data << 4; ++ ++ return ((((uint16_t)data << 8) | hi8 (crc)) ^ (uint8_t)(data >> 4) ++ ^ ((uint16_t)data << 3)); ++} ++ ++static int rtc_drbcc_bctrl_write_cmd(struct file* filp, const uint8_t msgid, const uint8_t* data, size_t len) ++{ ++ size_t buflen = 1+1+len+2+1; /* start char, msgid, data, crc, stop char */ ++ uint8_t buf[buflen]; ++ unsigned i; ++ uint16_t crc = 0xffff; ++ ssize_t nwritten; ++ loff_t offset_tmp = 0; ++ ++ buf[0] = START; ++ buf[1] = msgid; ++ crc = rtc_drbcc_crc_ccitt_update(crc, buf[1]); ++ if(data && (len > 0)) ++ { ++ for(i = 0; i < len; i++) ++ { ++ buf[2+i] = data[i]; ++ crc = rtc_drbcc_crc_ccitt_update(crc, buf[2+i]); ++ } ++ } ++ buf[buflen-3] = lo8(crc); ++ buf[buflen-2] = hi8(crc); ++ buf[buflen-1] = STOP; ++ ++ PDEBUG(1, "vfs_write %d bytes to descriptor %p", buflen, filp); ++ nwritten = vfs_write(filp, (char __user *)buf, buflen, &offset_tmp); ++ PDEBUG(1, "%d of %d bytes written", nwritten, buflen); ++ for(i = 0; i < nwritten; i++) ++ { ++ PDEBUG(2, ">%02X>", buf[i]); ++ } ++ ++ return (nwritten == buflen) ? 0 : -EIO; ++} ++ ++/* ++ * read at least len bytes into data or timeout, ++ * skip all bytes up to a valid start char ++ */ ++static int rtc_drbcc_bctrl_read_answer(struct file* filp, uint8_t* data, size_t len, unsigned timeout /* jiffies */) ++{ ++ static uint8_t rbuf[1024]; /* should be enough for or messages */ ++ static uint8_t* pos = rbuf; ++ uint8_t* tpos; ++ loff_t offset_tmp = 0; ++ ssize_t nread; ++ int ret = 0; ++ ++ if(len > sizeof(rbuf)) ++ { ++ PERROR("can't read that much bytes at once"); ++ ret = -EIO; ++ } ++ ++ PDEBUG(9, "rbuf=%p pos=%p pos-rbuf=%d len=%d", rbuf, pos, pos-rbuf, len); ++ if((ret == 0) && (tpos = memchr(rbuf, START, pos-rbuf))) ++ { ++ if(tpos != rbuf) ++ { ++ PDEBUG(9, "rbuf=%p pos=%p tpos=%p pos-rbuf=%d len=%d", rbuf, pos, tpos, pos-rbuf, len); ++ /* skip bytes up to start char */ ++ PDEBUG(9, "move %d bytes from %p to %p", pos-tpos, tpos, rbuf); ++ memmove(rbuf, tpos, pos-tpos); ++ pos -= tpos-rbuf; ++ } ++ } ++ ++ while((ret == 0) && (timeout > 0) && ((pos - rbuf) < len)) ++ { ++ timeout--; ++ ++ /* wait a jiffy */ ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(1); ++ ++ PDEBUG(1, "vfs_read %d bytes from descriptor %p to pos %p", rbuf+sizeof(rbuf)-pos, filp, pos); ++ nread = vfs_read(filp, (char __user *)pos, rbuf+sizeof(rbuf)-pos, &offset_tmp); ++ if(nread > 0) ++ { ++ unsigned i; ++ PDEBUG(1, "%d bytes read", nread); ++ for(i = 0; i < nread; i++) ++ { ++ PDEBUG(2, "<%02X<", pos[i]); ++ } ++ pos += nread; ++ } ++ else if((nread == -EAGAIN) || (nread == 0)) ++ { ++ // wait and try again ++ } ++ else ++ { ++ PERROR("vfs_read returned error %d", nread); ++ ret = -EIO; ++ } ++ ++ if((ret == 0) && (tpos = memchr(rbuf, START, pos-rbuf))) ++ { ++ if(tpos != rbuf) ++ { ++ PDEBUG(9, "rbuf=%p pos=%p tpos=%p pos-rbuf=%d len=%d", rbuf, pos, tpos, pos-rbuf, len); ++ /* skip bytes up to start char */ ++ PDEBUG(9, "move %d bytes from %p to %p", pos-tpos, tpos, rbuf); ++ memmove(rbuf, tpos, pos-tpos); ++ pos -= tpos-rbuf; ++ } ++ } ++ } ++ ++ if(rbuf[0] != START) ++ { ++ PERROR("missing start character"); ++ ret = -EIO; ++ } ++ ++ if(pos-rbuf < len) ++ { ++ PERROR("not enough data"); ++ ret = -EIO; ++ } ++ ++ if(rbuf[len-1] != STOP) ++ { ++ PERROR("missing stop character %d 0x%02X", len-1, rbuf[len-1]); ++ ret = -EIO; ++ } ++ ++ // TODO: check crc ++ ++ if(ret == 0) ++ { ++ memcpy(data, rbuf, len); ++ memmove(rbuf, rbuf+len, pos-rbuf-len); ++ pos -= len; ++ } ++ ++ PDEBUG(1, "return %d", ret); ++ return ret; ++} ++ ++static int rtc_drbcc_bctrl_check_answer(struct file* filp, const uint8_t msgid, uint8_t* returned_ackbit, uint8_t* data, size_t len, unsigned timeout /* jiffies */) ++{ ++ uint8_t rbuf[1+1+len+2+1]; /* start char, msgid, data, crc, stop char */ ++ int ret; ++ ++ ret = rtc_drbcc_bctrl_read_answer(filp, rbuf, sizeof(rbuf), timeout); ++ if(ret == 0) ++ { ++ unsigned i; ++ PDEBUG(1, "got %d bytes", sizeof(rbuf)); ++ for(i = 0; i < sizeof(rbuf); i++) ++ { ++ PDEBUG(2, "[%02X]", rbuf[i]); ++ } ++ ++ if((rbuf[1] & 0x7F) != msgid) ++ { ++ PERROR("wrong msgid 0x%02X instead of 0x%02X", rbuf[1] & 0x7F, msgid); ++ ret = -EIO; ++ } ++ PDEBUG(1, "valid answer found"); ++ memcpy(data, rbuf+2, len); ++ *returned_ackbit = rbuf[1] & 0x80; ++ } ++ ++ PDEBUG(1, "return %d", ret); ++ return ret; ++} ++ ++static int rtc_drbcc_set_termios(struct file *filp) ++{ ++ struct termios tios; ++ struct inode dummy; ++ speed_t speed = B921600; ++ int ret = 0; ++ ++ /* get terminal interface settings */ ++ ret = filp->f_op->ioctl(&dummy, filp, TCGETS, (unsigned long)&tios); ++ if(ret == 0) ++ { ++ ++ PDEBUG(6, "old tios.c_iflag=0x%08X", tios.c_iflag); ++ PDEBUG(6, "old tios.c_oflag=0x%08X", tios.c_oflag); ++ PDEBUG(6, "old tios.c_cflag=0x%08X", tios.c_cflag); ++ PDEBUG(6, "old tios.c_lflag=0x%08X", tios.c_lflag); ++ PDEBUG(6, "old tios.c_line=0x%02X", tios.c_line); ++ ++ /* set terminal raw like cfmakeraw does (see manpage) */ ++ tios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); ++ tios.c_oflag &= ~OPOST; ++ tios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); ++ tios.c_cflag &= ~(CSIZE | PARENB); ++ tios.c_cflag |= CS8; ++ ++ /* set baud rate like cfsetospeed does (see glibc sources) */ ++#ifdef _HAVE_STRUCT_TERMIOS_C_OSPEED ++ tios.c_ospeed = speed; ++#endif ++ tios.c_cflag &= ~(CBAUD | CBAUDEX); ++ tios.c_cflag |= speed; ++ ++ /* set 1 stop bit */ ++ tios.c_cflag &= ~CSTOPB; ++ ++ PDEBUG(6, "new tios.c_iflag=0x%08X", tios.c_iflag); ++ PDEBUG(6, "new tios.c_oflag=0x%08X", tios.c_oflag); ++ PDEBUG(6, "new tios.c_cflag=0x%08X", tios.c_cflag); ++ PDEBUG(6, "new tios.c_lflag=0x%08X", tios.c_lflag); ++ PDEBUG(6, "new tios.c_line=0x%02X", tios.c_line); ++ ++ /* set new terminal interface settings */ ++ ret = filp->f_op->ioctl(&dummy, filp, TCSETS, (unsigned long)&tios); ++ } ++ PDEBUG(1, "return %d", ret); ++ return ret; ++} ++ ++static int rtc_drbcc_read_time(struct device *dev, ++ struct rtc_time *tm) ++{ ++ uint8_t remoteackbit = 0x00; ++ struct file *filp; ++ mm_segment_t old_fs; ++ int ret = 0; ++ uint8_t rtcstr[8]; /* for RTC_READ: <sec> <min> <hour> <day> <date> <month> <year> <epoch> */ ++ ++ old_fs = get_fs(); ++ set_fs(KERNEL_DS); ++ ++ PDEBUG(1, "opening %s", devpath); ++ filp = filp_open(devpath, O_RDWR | O_NOCTTY | O_NONBLOCK | O_NDELAY, 0); ++ if (IS_ERR(filp)) { ++ PERROR("unable to open serial device to BCTRL: %s", devpath); ++ ret = PTR_ERR(filp); ++ goto end2; ++ } ++ PDEBUG(1, "%s opened at descriptor %p", devpath, filp); ++ ++ ret = rtc_drbcc_set_termios(filp); ++ if(ret) { goto end1; } ++ ++ PDEBUG(1, "send sync"); ++ ret = rtc_drbcc_bctrl_write_cmd(filp, RTC_DRBCC_SYNC | myackbit, NULL, 0); ++ if(ret) { goto end1; } ++ ++ PDEBUG(1, "wait ack"); ++ ret = rtc_drbcc_bctrl_check_answer(filp, RTC_DRBCC_ACK, &remoteackbit, NULL, 0, 100); ++ if(ret) { goto end1; } ++ myackbit ^= 0x80; /* toggle ACK bit */ ++ ++ PDEBUG(1, "send rtc request"); ++ ret = rtc_drbcc_bctrl_write_cmd(filp, RTC_DRBCC_REQ_RTC_READ | myackbit, NULL, 0); ++ if(ret) { goto end1; } ++ ++ PDEBUG(1, "wait ack"); ++ ret = rtc_drbcc_bctrl_check_answer(filp, RTC_DRBCC_ACK, &remoteackbit, NULL, 0, 100); ++ if(ret) { goto end1; } ++ myackbit ^= 0x80; /* toggle ACK bit */ ++ ++ PDEBUG(1, "wait rtc response"); ++ ret = rtc_drbcc_bctrl_check_answer(filp, RTC_DRBCC_IND_RTC_READ, &remoteackbit, rtcstr, sizeof(rtcstr), 1000); ++ if(ret) { goto end1; } ++ ++ PDEBUG(1, "send ack"); ++ ret = rtc_drbcc_bctrl_write_cmd(filp, RTC_DRBCC_ACK | remoteackbit, NULL, 0); ++ if(ret) { goto end1; } ++ ++ /* <sec> <min> <hour> <day> <date> <month> <year> <epoch> */ ++ PDEBUG(1, "read time %02X %02X %02X %02X %02X %02X %02X %02X", ++ rtcstr[0], rtcstr[1], rtcstr[2], rtcstr[3], ++ rtcstr[4], rtcstr[5], rtcstr[6], rtcstr[7]); ++ tm->tm_sec = BCD2BIN(rtcstr[0]); ++ tm->tm_min = BCD2BIN(rtcstr[1]); ++ tm->tm_hour = BCD2BIN(rtcstr[2]); ++ tm->tm_wday = BCD2BIN(rtcstr[3]) - 1; ++ tm->tm_mday = BCD2BIN(rtcstr[4]); ++ tm->tm_mon = BCD2BIN(rtcstr[5]) - 1; ++ tm->tm_year = BCD2BIN(rtcstr[6]) + 100; ++ PDEBUG(1, "secs=%d, mins=%d, hours=%d, mday=%d, mon=%d, year=%d, wday=%d", ++ tm->tm_sec, tm->tm_min, ++ tm->tm_hour, tm->tm_mday, ++ tm->tm_mon, tm->tm_year, tm->tm_wday); ++ ++ end1: ++ filp_close(filp, current->files); ++ end2: ++ set_fs(old_fs); ++ ++ PDEBUG(1, "return %d", ret); ++ return ret; ++} ++ ++static int rtc_drbcc_set_time(struct device *dev, ++ struct rtc_time *tm) ++{ ++ uint8_t remoteackbit = 0x00; ++ struct file *filp; ++ mm_segment_t old_fs; ++ int ret = 0; ++ uint8_t newrtcstr[7]; /* for RTC_SET: <sec> <min> <hour> <day> <date> <month> <year> */ ++ uint8_t rtcstr[8]; /* for RTC_READ: <sec> <min> <hour> <day> <date> <month> <year> <epoch> */ ++ ++ old_fs = get_fs(); ++ set_fs(KERNEL_DS); ++ ++ PDEBUG(1, "opening %s", devpath); ++ filp = filp_open(devpath, O_RDWR | O_NOCTTY | O_NONBLOCK | O_NDELAY, 0); ++ if (IS_ERR(filp)) { ++ PERROR("unable to open serial device to BCTRL: %s", devpath); ++ ret = PTR_ERR(filp); ++ goto end2; ++ } ++ PDEBUG(1, "%s opened at descriptor %p", devpath, filp); ++ ++ ret = rtc_drbcc_set_termios(filp); ++ if(ret) { goto end1; } ++ ++ PDEBUG(1, "send sync"); ++ ret = rtc_drbcc_bctrl_write_cmd(filp, RTC_DRBCC_SYNC | myackbit, NULL, 0); ++ if(ret) { goto end1; } ++ ++ PDEBUG(1, "wait ack"); ++ ret = rtc_drbcc_bctrl_check_answer(filp, RTC_DRBCC_ACK, &remoteackbit, NULL, 0, 100); ++ if(ret) { goto end1; } ++ myackbit ^= 0x80; /* toggle ACK bit */ ++ ++ /* <sec> <min> <hour> <day> <date> <month> <year> */ ++ PDEBUG(1, "secs=%d, mins=%d, hours=%d, mday=%d, mon=%d, year=%d, wday=%d", ++ tm->tm_sec, tm->tm_min, ++ tm->tm_hour, tm->tm_mday, ++ tm->tm_mon, tm->tm_year, tm->tm_wday); ++ newrtcstr[0] = BIN2BCD(tm->tm_sec); ++ newrtcstr[1] = BIN2BCD(tm->tm_min); ++ newrtcstr[2] = BIN2BCD(tm->tm_hour); ++ newrtcstr[3] = BIN2BCD(tm->tm_wday + 1); ++ newrtcstr[4] = BIN2BCD(tm->tm_mday); ++ newrtcstr[5] = BIN2BCD(tm->tm_mon + 1); ++ newrtcstr[6] = BIN2BCD(tm->tm_year - 100); ++ PDEBUG(1, "set time %02X %02X %02X %02X %02X %02X %02X", ++ newrtcstr[0], newrtcstr[1], newrtcstr[2], newrtcstr[3], ++ newrtcstr[4], newrtcstr[5], newrtcstr[6]); ++ ++ PDEBUG(1, "send setrtc request"); ++ ret = rtc_drbcc_bctrl_write_cmd(filp, RTC_DRBCC_REQ_RTC_SET | myackbit, newrtcstr, sizeof(newrtcstr)); ++ if(ret) { goto end1; } ++ ++ PDEBUG(1, "wait ack"); ++ ret = rtc_drbcc_bctrl_check_answer(filp, RTC_DRBCC_ACK, &remoteackbit, NULL, 0, 100); ++ if(ret) { goto end1; } ++ myackbit ^= 0x80; /* toggle ACK bit */ ++ ++ PDEBUG(1, "wait rtc response"); ++ ret = rtc_drbcc_bctrl_check_answer(filp, RTC_DRBCC_IND_RTC_READ, &remoteackbit, rtcstr, sizeof(rtcstr), 1000); ++ if(ret) { goto end1; } ++ ++ PDEBUG(1, "send ack"); ++ ret = rtc_drbcc_bctrl_write_cmd(filp, RTC_DRBCC_ACK | remoteackbit, NULL, 0); ++ if(ret) { goto end1; } ++ ++ /* <sec> <min> <hour> <day> <date> <month> <year> <epoch> */ ++ PDEBUG(1, "read time %02X %02X %02X %02X %02X %02X %02X %02X", ++ rtcstr[0], rtcstr[1], rtcstr[2], rtcstr[3], ++ rtcstr[4], rtcstr[5], rtcstr[6], rtcstr[7]); ++ ++ end1: ++ filp_close(filp, current->files); ++ end2: ++ set_fs(old_fs); ++ ++ PDEBUG(1, "return %d", ret); ++ return ret; ++} ++ ++static int rtc_drbcc_proc(struct device *dev, struct seq_file *seq) ++{ ++ struct platform_device *plat_dev = to_platform_device(dev); ++ ++ seq_printf(seq, "%s\t: yes\n", MODULE_NAME); ++ seq_printf(seq, "id\t\t: %d\n", plat_dev->id); ++ ++ return 0; ++} ++ ++static int rtc_drbcc_ioctl(struct device *dev, unsigned int cmd, ++ unsigned long arg) ++{ ++ switch (cmd) { ++ default: ++ return -ENOIOCTLCMD; ++ } ++ return 0; ++} ++ ++static const struct rtc_class_ops rtc_drbcc_ops = { ++ .proc = rtc_drbcc_proc, ++ .read_time = rtc_drbcc_read_time, ++ .set_time = rtc_drbcc_set_time, ++ .ioctl = rtc_drbcc_ioctl, ++}; ++ ++static int rtc_drbcc_probe(struct platform_device *plat_dev) ++{ ++ int err; ++ struct rtc_device *rtc; ++ ++ PDEBUG(1, "register device"); ++ rtc = rtc_device_register(MODULE_NAME, &plat_dev->dev, &rtc_drbcc_ops, THIS_MODULE); ++ if (IS_ERR(rtc)) { ++ err = PTR_ERR(rtc); ++ return err; ++ } ++ ++#if 0 ++ err = device_create_file(&plat_dev->dev, &dev_attr_irq); ++ if (err) ++ goto err; ++#endif ++ platform_set_drvdata(plat_dev, rtc); ++ ++ return 0; ++ ++//err: ++ rtc_device_unregister(rtc); ++ return err; ++} ++ ++static int __devexit rtc_drbcc_remove(struct platform_device *plat_dev) ++{ ++ struct rtc_device *rtc = platform_get_drvdata(plat_dev); ++ ++ PDEBUG(1, "unregister device"); ++ rtc_device_unregister(rtc); ++#if 0 ++ device_remove_file(&plat_dev->dev, &dev_attr_irq); ++#endif ++ return 0; ++} ++ ++static struct platform_driver rtc_drbcc_drv = { ++ .probe = rtc_drbcc_probe, ++ .remove = __devexit_p(rtc_drbcc_remove), ++ .driver = { ++ .name = MODULE_NAME, ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static int __init rtc_drbcc_init(void) ++{ ++ int err; ++ ++#if DEBUGGING ++ rtc_debug = debug; ++#else ++ debug = 0; ++#endif ++ ++ PDEBUG(1, "debug=%d devpath=%s baud=%d", debug, devpath, baud); ++ if ((err = platform_driver_register(&rtc_drbcc_drv))) ++ return err; ++ ++ if ((rtc_drbcc0 = platform_device_alloc(MODULE_NAME, 0)) == NULL) { ++ err = -ENOMEM; ++ goto exit_driver_unregister; ++ } ++ ++ if ((err = platform_device_add(rtc_drbcc0))) ++ goto exit_device_unregister; ++ ++ return 0; ++ ++exit_device_unregister: ++ platform_device_unregister(rtc_drbcc0); ++ ++ platform_device_put(rtc_drbcc0); ++ ++exit_driver_unregister: ++ platform_driver_unregister(&rtc_drbcc_drv); ++ return err; ++} ++ ++static void __exit rtc_drbcc_exit(void) ++{ ++ platform_device_unregister(rtc_drbcc0); ++ platform_driver_unregister(&rtc_drbcc_drv); ++} ++ ++MODULE_AUTHOR("Steffen Sledz <sledz@dresearch.de>"); ++MODULE_DESCRIPTION("HydraIP DRBCC RTC driver"); ++MODULE_LICENSE("GPL"); ++ ++module_init(rtc_drbcc_init); ++module_exit(rtc_drbcc_exit); ++ ++/* Editor hints for emacs ++ * ++ * Local Variables: ++ * mode:c ++ * c-basic-offset:4 ++ * indent-tabs-mode:t ++ * tab-width:4 ++ * End: ++ * ++ * NO CODE BELOW THIS! */ |