diff options
-rw-r--r-- | c/src/ChangeLog | 6 | ||||
-rw-r--r-- | c/src/libchip/Makefile.am | 4 | ||||
-rw-r--r-- | c/src/libchip/preinstall.am | 4 | ||||
-rw-r--r-- | c/src/libchip/rtc/ds1375-rtc.h | 91 | ||||
-rw-r--r-- | c/src/libchip/rtc/ds1375.c | 425 |
5 files changed, 528 insertions, 2 deletions
diff --git a/c/src/ChangeLog b/c/src/ChangeLog index c9a803db16..af7578edda 100644 --- a/c/src/ChangeLog +++ b/c/src/ChangeLog @@ -1,3 +1,9 @@ +2007-11-20 Till Straumann <strauman@slac.stanford.edu> + + * libchip/rtc/ds1375.c, libchip/rtc/ds1375-rtc.h, + * libchip/Makefile.am, libchip/preinstall.am: + added new driver for Maxim DS1375 i2c RTC. + 2007-09-26 Thomas Doerfler <Thomas.Doerfler@embedded-brains.de> * libchip/i2c/spi-flash-m25p40.c: diff --git a/c/src/libchip/Makefile.am b/c/src/libchip/Makefile.am index fb633d2837..5cfca33da7 100644 --- a/c/src/libchip/Makefile.am +++ b/c/src/libchip/Makefile.am @@ -49,14 +49,14 @@ EXTRA_DIST += network/README network/README.cs8900 network/README.dec21140 \ # rtc if LIBCHIP include_libchip_HEADERS += rtc/rtc.h rtc/icm7170.h rtc/m48t08.h \ - rtc/mc146818a.h + rtc/mc146818a.h rtc/ds1375-rtc.h noinst_LIBRARIES += librtcio.a librtcio_a_CPPFLAGS = $(AM_CPPFLAGS) librtcio_a_SOURCES = rtc/rtcprobe.c rtc/icm7170.c rtc/icm7170_reg.c \ rtc/icm7170_reg2.c rtc/icm7170_reg4.c rtc/icm7170_reg8.c rtc/m48t08.c \ rtc/m48t08_reg.c rtc/m48t08_reg2.c rtc/m48t08_reg4.c rtc/m48t08_reg8.c \ - rtc/mc146818a.c rtc/mc146818a_ioreg.c + rtc/mc146818a.c rtc/mc146818a_ioreg.c rtc/ds1375.c endif EXTRA_DIST += rtc/README.ds1643 rtc/README.icm7170 rtc/README.m48t08 \ diff --git a/c/src/libchip/preinstall.am b/c/src/libchip/preinstall.am index 0eec432aaf..d24155a266 100644 --- a/c/src/libchip/preinstall.am +++ b/c/src/libchip/preinstall.am @@ -106,6 +106,10 @@ PREINSTALL_FILES += $(PROJECT_INCLUDE)/libchip/m48t08.h $(PROJECT_INCLUDE)/libchip/mc146818a.h: rtc/mc146818a.h $(PROJECT_INCLUDE)/libchip/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/libchip/mc146818a.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/libchip/mc146818a.h + +$(PROJECT_INCLUDE)/libchip/ds1375-rtc.h: rtc/ds1375-rtc.h $(PROJECT_INCLUDE)/libchip/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/libchip/ds1375-rtc.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/libchip/ds1375-rtc.h endif if LIBCHIP $(PROJECT_INCLUDE)/libchip/i2c-ds1621.h: i2c/i2c-ds1621.h $(PROJECT_INCLUDE)/libchip/$(dirstamp) diff --git a/c/src/libchip/rtc/ds1375-rtc.h b/c/src/libchip/rtc/ds1375-rtc.h new file mode 100644 index 0000000000..d1d68a96ac --- /dev/null +++ b/c/src/libchip/rtc/ds1375-rtc.h @@ -0,0 +1,91 @@ +#ifndef DS1375_I2C_RTC_H +#define DS1375_I2C_RTC_H +/* Driver for the Maxim 1375 i2c RTC (TOD only; very simple...) */ + +/* + * Authorship + * ---------- + * This software was created by + * + * Till Straumann <strauman@slac.stanford.edu>, 2005-2007, + * Stanford Linear Accelerator Center, Stanford University. + * + * Acknowledgement of sponsorship + * ------------------------------ + * The software was produced by + * the Stanford Linear Accelerator Center, Stanford University, + * under Contract DE-AC03-76SFO0515 with the Department of Energy. + * + * Government disclaimer of liability + * ---------------------------------- + * Neither the United States nor the United States Department of Energy, + * nor any of their employees, makes any warranty, express or implied, or + * assumes any legal liability or responsibility for the accuracy, + * completeness, or usefulness of any data, apparatus, product, or process + * disclosed, or represents that its use would not infringe privately owned + * rights. + * + * Stanford disclaimer of liability + * -------------------------------- + * Stanford University makes no representations or warranties, express or + * implied, nor assumes any liability for the use of this software. + * + * Stanford disclaimer of copyright + * -------------------------------- + * Stanford University, owner of the copyright, hereby disclaims its + * copyright and all other rights in this software. Hence, anyone may + * freely use it for any purpose without restriction. + * + * Maintenance of notices + * ---------------------- + * In the interest of clarity regarding the origin and status of this + * SLAC software, this and all the preceding Stanford University notices + * are to remain affixed to any copy or derivative of this software made + * or distributed by the recipient and are to be affixed to any copy of + * software made or distributed by the recipient that contains a copy or + * derivative of this software. + * + * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 + */ + +#include <rtems.h> +#include <libchip/rtc.h> +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +extern rtc_fns rtc_ds1375_fns; + +boolean +rtc_ds1375_device_probe( int minor ); + +uint32_t +rtc_ds1375_get_register( uint32_t port, uint8_t reg ); + +void +rtc_ds1375_set_register( uint32_t port, uint8_t reg, uint32_t value ); + +/* + * BSP must supply string constant argument 'i2cname' which matches + * the registered device name of the raw i2c device (created with mknod). + * E.g., "/dev/i2c.ds1375-raw" + */ +#define DS1375_RTC_TBL_ENTRY(i2cname) \ +{ \ + sDeviceName: "/dev/rtc", \ + deviceType: RTC_CUSTOM, \ + pDeviceFns: &rtc_ds1375_fns, \ + deviceProbe: rtc_ds1375_device_probe, \ + ulCtrlPort1: (uint32_t)(i2cname), \ + ulDataPort: 0, \ + getRegister: rtc_ds1375_get_register, \ + setRegister: rtc_ds1375_set_register, \ +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/c/src/libchip/rtc/ds1375.c b/c/src/libchip/rtc/ds1375.c new file mode 100644 index 0000000000..3afd966946 --- /dev/null +++ b/c/src/libchip/rtc/ds1375.c @@ -0,0 +1,425 @@ +/* Driver for the Maxim 1375 i2c RTC (TOD only; very simple...) */ + +/* + * Authorship + * ---------- + * This software was created by + * + * Till Straumann <strauman@slac.stanford.edu>, 2005-2007, + * Stanford Linear Accelerator Center, Stanford University. + * + * Acknowledgement of sponsorship + * ------------------------------ + * The software was produced by + * the Stanford Linear Accelerator Center, Stanford University, + * under Contract DE-AC03-76SFO0515 with the Department of Energy. + * + * Government disclaimer of liability + * ---------------------------------- + * Neither the United States nor the United States Department of Energy, + * nor any of their employees, makes any warranty, express or implied, or + * assumes any legal liability or responsibility for the accuracy, + * completeness, or usefulness of any data, apparatus, product, or process + * disclosed, or represents that its use would not infringe privately owned + * rights. + * + * Stanford disclaimer of liability + * -------------------------------- + * Stanford University makes no representations or warranties, express or + * implied, nor assumes any liability for the use of this software. + * + * Stanford disclaimer of copyright + * -------------------------------- + * Stanford University, owner of the copyright, hereby disclaims its + * copyright and all other rights in this software. Hence, anyone may + * freely use it for any purpose without restriction. + * + * Maintenance of notices + * ---------------------- + * In the interest of clarity regarding the origin and status of this + * SLAC software, this and all the preceding Stanford University notices + * are to remain affixed to any copy or derivative of this software made + * or distributed by the recipient and are to be affixed to any copy of + * software made or distributed by the recipient that contains a copy or + * derivative of this software. + * + * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 + */ + +/* This driver uses the file-system interface to the i2c bus */ + +#include <rtems.h> +#include <rtems/rtc.h> +#include <libchip/rtc.h> +#include <libchip/ds1375-rtc.h> + +#include <sys/fcntl.h> +#include <stdio.h> +#include <inttypes.h> + + +#define STATIC static +#undef DEBUG + +STATIC uint8_t ds1375_bcd2bin(uint8_t x) +{ +uint8_t h = x & 0xf0; + + /* 8*hi + 2*hi + lo */ + return ( h >> 1 ) + ( h >> 3 ) + ( x & 0xf ); +} + +STATIC uint8_t ds1375_bin2bcd(uint8_t x) +{ +uint8_t h = x/10; + + return ( h << 4 ) + ( x - ( ( h << 3 ) + ( h << 1 ) ) ); +} + +/* + * Register Definitions and Access Macros + * + * The xxx_REG macros are offsets into the register files + * The xxx_OFF macros are offsets into a in-memory buffer + * starting at the seconds (for the 1375 both, + * _REG and _OFF happen to be identical). + */ + + +#define DS1375_SEC_REG 0x0 +#define DS1375_SEC_OFF (DS1375_SEC_REG-DS1375_SEC_REG) +/* Extract seconds and convert to binary */ +#define DS1375_SEC(x) ds1375_bcd2bin( ((x)[DS1375_SEC_OFF]) & 0x7f ) + +#define DS1375_MIN_REG 0x1 +#define DS1375_MIN_OFF (DS1375_MIN_REG-DS1375_SEC_REG) +/* Extract minutes and convert to binary */ +#define DS1375_MIN(x) ds1375_bcd2bin( ((x)[DS1375_MIN_OFF]) & 0x7f ) + +#define DS1375_HR_REG 0x2 +#define DS1375_HR_OFF (DS1375_HR_REG-DS1375_SEC_REG) +#define DS1375_HR_1224 (1<<6) +#define DS1375_HR_AMPM (1<<5) +/* Are hours in AM/PM representation ? */ +#define DS1375_IS_AMPM(x) (DS1375_HR_1224 & ((x)[DS1375_HR_OFF])) +/* Are we PM ? */ +#define DS1375_IS_PM(x) (DS1375_HR_AMPM & ((x)[DS1375_HR_OFF])) +/* Extract hours (12h mode) and convert to binary */ +#define DS1375_HR_12(x) ds1375_bcd2bin( ((x)[DS1375_HR_OFF]) & 0x1f ) +/* Extract hours (24h mode) and convert to binary */ +#define DS1375_HR_24(x) ds1375_bcd2bin( ((x)[DS1375_HR_OFF]) & 0x3f ) + +#define DS1375_DAY_REG 0x3 +#define DS1375_DAY_OFF (DS1375_DAY_REG-DS1375_SEC_REG) +#define DS1375_DAT_REG 0x4 +#define DS1375_DAT_OFF (DS1375_DAT_REG-DS1375_SEC_REG) +/* Extract date and convert to binary */ +#define DS1375_DAT(x) ds1375_bcd2bin( ((x)[DS1375_DAT_OFF]) & 0x3f ) +#define DS1375_MON_REG 0x5 +#define DS1375_MON_OFF (DS1375_MON_REG-DS1375_SEC_REG) +#define DS1375_MON_CTRY (1<<7) +/* Is century bit set ? */ +#define DS1375_IS_CTRY(x) (((x)[DS1375_MON_OFF]) & DS1375_MON_CTRY) +/* Extract month and convert to binary */ +#define DS1375_MON(x) ds1375_bcd2bin( ((x)[DS1375_MON_OFF]) & 0x1f ) + +#define DS1375_YR_REG 0x6 +#define DS1375_YR_OFF (DS1375_YR_REG-DS1375_SEC_REG) +/* Extract year and convert to binary */ +#define DS1375_YR(x) ds1375_bcd2bin( ((x)[DS1375_YR_OFF]) & 0xff ) + +/* CR Register and bit definitions */ +#define DS1375_CR_REG 0xe +#define DS1375_CR_ECLK (1<<7) +#define DS1375_CR_CLKSEL1 (1<<6) +#define DS1375_CR_CLKSEL0 (1<<5) +#define DS1375_CR_RS2 (1<<4) +#define DS1375_CR_RS1 (1<<3) +#define DS1375_CR_INTCN (1<<2) +#define DS1375_CR_A2IE (1<<1) +#define DS1375_CR_A1IE (1<<0) + +#define DS1375_CSR_REG 0xf + +/* User SRAM (8 bytes) */ +#define DS1375_RAM 0x10 /* start of 8 bytes user ram */ + +/* Access Primitives */ + +STATIC int +rd_bytes( int fd, uint32_t off, uint8_t *buf, int len ) +{ +uint8_t ptr = off; + + return 1 == write( fd, &ptr, 1 ) && len == read( fd, buf, len ) ? 0 : -1; +} + +STATIC int +wr_bytes( int fd, uint32_t off, uint8_t *buf, int len ) +{ +uint8_t d[ len + 1 ]; + + /* Must not break up writing of the register pointer and + * the data to-be-written into multiple write() calls + * because every 'write()' operation sends START and + * the chip interprets the first byte after START as + * the register pointer. + */ + + d[0] = off; + memcpy( d + 1, buf, len ); + + return len + 1 == write( fd, d, len + 1 ) ? 0 : -1; +} + +/* Helpers */ + +static int +getfd( int minor ) +{ + return open( (const char *)RTC_Table[minor].ulCtrlPort1, O_RDWR ); +} + +/* Driver Access Functions */ + +STATIC void +ds1375_initialize( int minor ) +{ +int fd; +uint8_t cr; + + if ( ( fd = getfd( minor ) ) >= 0 ) { + if ( 0 == rd_bytes( fd, DS1375_CR_REG, &cr, 1 ) ) { + /* make sure clock is enabled */ + if ( ! ( DS1375_CR_ECLK & cr ) ) { + cr |= DS1375_CR_ECLK; + wr_bytes( fd, DS1375_CR_REG, &cr, 1 ); + } + } + close( fd ); + } + +} + +STATIC int +ds1375_get_time( int minor, rtems_time_of_day *time ) +{ +int rval = -1; +int fd; +uint8_t buf[DS1375_YR_REG + 1 - DS1375_SEC_REG]; + + if ( time && ( ( fd = getfd( minor ) ) >= 0 ) ) { + if ( 0 == rd_bytes( fd, DS1375_SEC_REG, buf, sizeof(buf) ) ) { + time->year = DS1375_IS_CTRY( buf ) ? 2000 : 1900; + time->year += DS1375_YR ( buf ); + time->month = DS1375_MON( buf ); + time->day = DS1375_DAT( buf ); /* DAY is weekday */ + + if ( DS1375_IS_AMPM( buf ) ) { + time->hour = DS1375_HR_12 ( buf ); + if ( DS1375_IS_PM( buf ) ) + time->hour += 12; + } else { + time->hour = DS1375_HR_24 ( buf ); + } + + time->minute = DS1375_MIN( buf ); + time->second = DS1375_SEC( buf ); + time->ticks = 0; + rval = 0; + } + close( fd ); + } + return rval; +} + +STATIC int +ds1375_set_time( int minor, rtems_time_of_day *time ) +{ +int rval = -1; +int fd = -1; +time_t secs; +struct tm tm; +uint8_t buf[DS1375_YR_REG + 1 - DS1375_SEC_REG]; +uint8_t cr = 0xff; + /* + * The clock hardware maintains the day-of-week as a separate counter + * so we must compute it ourselves (rtems_time_of_day doesn't come + * with a day of week). + */ + secs = _TOD_To_seconds( time ); + /* we're only interested in tm_wday... */ + gmtime_r( &secs, &tm ); + + buf[DS1375_SEC_OFF] = ds1375_bin2bcd( time->second ); + buf[DS1375_MIN_OFF] = ds1375_bin2bcd( time->minute ); + /* bin2bcd(hour) implicitly selects 24h mode since ms-bit is clear */ + buf[DS1375_HR_OFF] = ds1375_bin2bcd( time->hour ); + buf[DS1375_DAY_OFF] = tm.tm_wday + 1; + buf[DS1375_DAT_OFF] = ds1375_bin2bcd( time->day ); + buf[DS1375_MON_OFF] = ds1375_bin2bcd( time->month ); + + if ( time->year >= 2000 ) { + buf[DS1375_YR_OFF] = ds1375_bin2bcd( time->year - 2000 ); + buf[DS1375_MON_OFF] |= DS1375_MON_CTRY; + } else { + buf[DS1375_YR_OFF] = ds1375_bin2bcd( time->year - 1900 ); + } + + /* + * Stop clock; update registers and restart. This is slightly + * slower than just writing everyting but if we did that we + * could get inconsistent registers if this routine would not + * complete in less than 1s (says the datasheet) and we don't + * know if we are going to be pre-empted for some time... + */ + if ( ( fd = getfd( minor ) ) < 0 ) { + goto cleanup; + } + + if ( rd_bytes( fd, DS1375_CR_REG, &cr, 1 ) ) + goto cleanup; + + cr &= ~DS1375_CR_ECLK; + + /* This stops the clock */ + if ( wr_bytes( fd, DS1375_CR_REG, &cr, 1 ) ) + goto cleanup; + + /* write new contents */ + if ( wr_bytes( fd, DS1375_SEC_REG, buf, sizeof(buf) ) ) + goto cleanup; + + rval = 0; + +cleanup: + if ( fd >= 0 ) { + if ( ! ( DS1375_CR_ECLK & cr ) ) { + /* start clock; this handles some cases of failure + * after stopping the clock by restarting it again + */ + cr |= DS1375_CR_ECLK; + if ( wr_bytes( fd, DS1375_CR_REG, &cr, 1 ) ) + rval = -1; + } + close( fd ); + } + return rval; +} + +/* Debugging / Testing */ + +#ifdef DEBUG + +/* Don't forget to set "TZ" when using these test routines */ + +/* What is rtems_time_of_day good for ? Why not use std types ? */ + +uint32_t +ds1375_get_time_tst() +{ +rtems_time_of_day rtod; +time_t secs; + + ds1375_get_time( 0, &rtod ); + secs = _TOD_To_seconds( &rtod ); + printf( "%s\n", ctime( &secs ) ); + return secs; +} + +int +ds1375_set_time_tst( const char *datstr, rtems_time_of_day *prt ) +{ +struct tm tm; +time_t secs; +rtems_time_of_day rt; + + if ( !datstr ) + return -1; + + if ( ! strptime( datstr, "%Y-%m-%d/%T", &tm ) ) + return -2; + + if ( ! prt ) + prt = &rt; + + secs = mktime( &tm ); + + /* convert to UTC */ + gmtime_r( &secs, &tm ); + + printf("Y: %"PRIu32" ", (prt->year = tm.tm_year + 1900) ); + printf("M: %"PRIu32" ", (prt->month = tm.tm_mon + 1) ); + printf("D: %"PRIu32" ", (prt->day = tm.tm_mday ) ); + printf("h: %"PRIu32" ", (prt->hour = tm.tm_hour ) ); + printf("m: %"PRIu32" ", (prt->minute = tm.tm_min ) ); + printf("s: %"PRIu32"\n", (prt->second = tm.tm_sec ) ); + prt->ticks = 0; + + return ( prt == &rt ) ? ds1375_set_time( 0, &rt ) : 0; +} + +#endif + + +uint32_t +rtc_ds1375_get_register( uint32_t port, uint8_t reg ) +{ +int fd; +uint8_t v; +uint32_t rval = -1; + + if ( ( fd = open( (const char*)port, O_RDWR ) ) >= 0 ) { + + if ( 0 == rd_bytes( fd, reg, &v, 1 ) ) { + rval = v; + } + close( fd ); + } + + return rval; +} + +void +rtc_ds1375_set_register( uint32_t port, uint8_t reg, uint32_t value ) +{ +int fd; +uint8_t v = value; + + if ( ( fd = open( (const char*)port, O_RDWR ) ) >= 0 ) { + wr_bytes( fd, reg, &v, 1 ); + close( fd ); + } + +} + +boolean +rtc_ds1375_device_probe( int minor ) +{ +int fd; + + if ( ( fd = getfd( minor ) ) < 0 ) { + perror("ds1375_probe (open)"); + return FALSE; + } + + /* Try to set file pointer */ + if ( 0 != wr_bytes( fd, DS1375_SEC_REG, 0, 0 ) ) { + perror( "ds1375_probe (wr_bytes)" ); + close( fd ); + return FALSE; + } + + if ( close( fd ) ) { + perror( "ds1375_probe (close)" ); + return FALSE; + } + + return TRUE; +} + +rtc_fns rtc_ds1375_fns = { + deviceInitialize: ds1375_initialize, + deviceGetTime: ds1375_get_time, + deviceSetTime: ds1375_set_time, +}; |