diff --git a/bsps/include/libchip/ds1375-rtc.h b/bsps/include/libchip/ds1375-rtc.h index a5be96293f..dd1775578f 100644 --- a/bsps/include/libchip/ds1375-rtc.h +++ b/bsps/include/libchip/ds1375-rtc.h @@ -52,45 +52,34 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { #endif -extern rtc_fns rtc_ds1375_fns; - -bool -rtc_ds1375_device_probe( int minor ); - -uint32_t -rtc_ds1375_get_register( uintptr_t port, uint8_t reg ); - -void -rtc_ds1375_set_register( uintptr_t port, uint8_t reg, uint32_t value ); +int +rtc_ds1375_hw_init(struct i2c_rtc_base *base); /* - * 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" - * - * NOTE: The i2c bus driver must already be up and 'i2cname' already - * be available when this ENTRY is registered or initialized. - * - * If you want to allow applications to add the RTC driver to - * the configuration table then the i2c subsystem must be - * initialized by the BSP from the predriver_hook. + * BSP must supply the ds1375_rtc_ctx argument, which is i2c_rtc_base* + * Use with the DS1375_RTC_INITIALIZER macro: + * struct i2c_rtc_base ctx = DS1375_RTC_INITIALIZER("/dev/i2c0", 0x68); + * ... + * DS1375_RTC_TBL_ENTRY("/dev/rtc", &ctx) */ -#define DS1375_RTC_TBL_ENTRY(i2cname) \ -{ \ - sDeviceName: "/dev/rtc", \ - deviceType: RTC_CUSTOM, \ - pDeviceFns: &rtc_ds1375_fns, \ - deviceProbe: rtc_ds1375_device_probe, \ - ulCtrlPort1: (uintptr_t)(i2cname), \ - ulDataPort: 0, \ - getRegister: rtc_ds1375_get_register, \ - setRegister: rtc_ds1375_set_register, \ -} + #define DS1375_RTC_TBL_ENTRY(dev_name, ds1375_rtc_ctx) \ + I2C_RTC_TBL_ENTRY(dev_name, ds1375_rtc_ctx) + +#define DS1375_RTC_INITIALIZER(i2c_path, i2c_address) \ + I2C_RTC_INITIALIZER( \ + i2c_path, \ + i2c_address, \ + 0, \ + I2C_RTC_ORDER_sec_min_hour_wkday_day_month_year, \ + "ds1375", \ + rtc_ds1375_hw_init) + #ifdef __cplusplus } diff --git a/bsps/powerpc/mvme3100/rtc/todcfg.c b/bsps/powerpc/mvme3100/rtc/todcfg.c index 3fdf3e38ae..61fe96c647 100644 --- a/bsps/powerpc/mvme3100/rtc/todcfg.c +++ b/bsps/powerpc/mvme3100/rtc/todcfg.c @@ -13,10 +13,13 @@ #include #include #include +#include + +static struct i2c_rtc_base ds1375_ctx = DS1375_RTC_INITIALIZER("/dev/i2c0", 0x68); /* The following table configures the RTC drivers used in this BSP */ rtc_tbl RTC_Table[] = { - DS1375_RTC_TBL_ENTRY(BSP_I2C_DS1375_RAW_DEV_NAME), + DS1375_RTC_TBL_ENTRY("/dev/rtc", &ds1375_ctx), }; /* Some information used by the RTC driver */ diff --git a/bsps/shared/dev/rtc/ds1375.c b/bsps/shared/dev/rtc/ds1375.c index e51744355f..00da16ec67 100644 --- a/bsps/shared/dev/rtc/ds1375.c +++ b/bsps/shared/dev/rtc/ds1375.c @@ -46,7 +46,9 @@ * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 */ -/* This driver uses the file-system interface to the i2c bus */ +/** + * Modified to use i2c-rtc driver by J. Lorelli + */ #include /* write, read, close */ @@ -59,45 +61,7 @@ #include #include -#include -#include -#include -#include - - -#define STATIC static -#undef DEBUG - -/* The RTC driver routines are possibly called during - * system initialization -- that would be prior to opening - * the console. At this point it is not safe to use stdio - * (printf, perror etc.). - * Our file descriptors may even be 0..2 - */ -#define STDIOSAFE(fmt,args...) \ - do { \ - if ( _System_state_Is_up( _System_state_Get() ) ) { \ - fprintf(stderr,fmt,args); \ - } else { \ - printk(fmt,args); \ - } \ - } while (0) - - -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 ) ) ); -} +#include /* * Register Definitions and Access Macros @@ -107,47 +71,6 @@ STATIC uint8_t ds1375_bin2bcd(uint8_t x) * 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 @@ -162,301 +85,21 @@ STATIC uint8_t ds1375_bin2bcd(uint8_t x) #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, - const 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; -} - +/* Initialize the hardware */ int -ds1375_set_time_tst( const char *datstr, rtems_time_of_day *prt ) +rtc_ds1375_hw_init(struct i2c_rtc_base *base) { -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; + uint8_t cr; + int r = i2c_rtc_read(base, DS1375_CR_REG, &cr, 1); + if (r != 0) + return r; + + /* make sure clock is enabled */ + if (!(cr & DS1375_CR_ECLK)) { + cr |= DS1375_CR_ECLK; + r = i2c_rtc_write(base, DS1375_CR_REG, &cr, 1); + if (r != 0) + return r; + } + return 0; } - -#endif - - -uint32_t -rtc_ds1375_get_register( uintptr_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( uintptr_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 ); - } - -} - -bool rtc_ds1375_device_probe( - int minor -) -{ - int fd; - - if ( ( fd = getfd( minor ) ) < 0 ) { - STDIOSAFE( "ds1375_probe (open): %s\n", strerror( errno ) ); - return false; - } - - /* Try to set file pointer */ - if ( 0 != wr_bytes( fd, DS1375_SEC_REG, 0, 0 ) ) { - STDIOSAFE( "ds1375_probe (wr_bytes): %s\n", strerror( errno ) ); - close( fd ); - return false; - } - - if ( close( fd ) ) { - STDIOSAFE( "ds1375_probe (close): %s\n", strerror( errno ) ); - return false; - } - - return true; -} - -rtc_fns rtc_ds1375_fns = { - .deviceInitialize = ds1375_initialize, - .deviceGetTime = ds1375_get_time, - .deviceSetTime = ds1375_set_time, -};