summaryrefslogtreecommitdiffstats
path: root/c/src/libchip
diff options
context:
space:
mode:
authorTill Straumann <strauman@slac.stanford.edu>2007-11-20 20:16:43 +0000
committerTill Straumann <strauman@slac.stanford.edu>2007-11-20 20:16:43 +0000
commit381a2f18fc2007b6c48d7fd7d2dc2214696c5299 (patch)
treeac231aeb904a7da87b4cbc8ad48a201808b43983 /c/src/libchip
parent2007-11-17 Till Straumann <strauman@slac.stanford.edu> (diff)
downloadrtems-381a2f18fc2007b6c48d7fd7d2dc2214696c5299.tar.bz2
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.
Diffstat (limited to 'c/src/libchip')
-rw-r--r--c/src/libchip/Makefile.am4
-rw-r--r--c/src/libchip/preinstall.am4
-rw-r--r--c/src/libchip/rtc/ds1375-rtc.h91
-rw-r--r--c/src/libchip/rtc/ds1375.c425
4 files changed, 522 insertions, 2 deletions
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,
+};