diff options
Diffstat (limited to 'bsps/powerpc/gen5200/rtc/pcf8563.c')
-rw-r--r-- | bsps/powerpc/gen5200/rtc/pcf8563.c | 228 |
1 files changed, 228 insertions, 0 deletions
diff --git a/bsps/powerpc/gen5200/rtc/pcf8563.c b/bsps/powerpc/gen5200/rtc/pcf8563.c new file mode 100644 index 0000000000..e41e3b48d2 --- /dev/null +++ b/bsps/powerpc/gen5200/rtc/pcf8563.c @@ -0,0 +1,228 @@ +/*===============================================================*\ +| Project: RTEMS generic MPC5200 BSP | ++-----------------------------------------------------------------+ +| Partially based on the code references which are named below. | +| Adaptions, modifications, enhancements and any recent parts of | +| the code are: | +| Copyright (c) 2005 | +| Embedded Brains GmbH | +| Obere Lagerstr. 30 | +| D-82178 Puchheim | +| Germany | +| rtems@embedded-brains.de | ++-----------------------------------------------------------------+ +| The license and distribution terms for this file may be | +| found in the file LICENSE in this distribution or at | +| | +| http://www.rtems.org/license/LICENSE. | +| | ++-----------------------------------------------------------------+ +| this file contains the tod driver for a Philips pcf8563 I2C RTC | +\*===============================================================*/ +/* + * This file interfaces with the real-time clock found in a + * Philips PCF8563 serial real-time clock chip. + * This RTC have I2C bus interface. BSP have to provide I2C bus primitives + * to make this driver working. getRegister and setRegister primitives is + * not used here to avoid multiple transactions over I2C bus (each transaction + * require significant time and error when date/time information red may + * occurs). ulControlPort contains I2C bus number; ulDataPort contains + * RTC I2C device address. + * + * Based on a ds1307 driver from: + * + * Copyright (C) 2000 OKTET Ltd., St.-Petersburg, Russia + * Author: Victor V. Vengerov <vvv@oktet.ru> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * + * http://www.rtems.org/license/LICENSE. + */ + +#include <rtems.h> +#include <bsp/fatal.h> +#include <bsp/i2c.h> +#include <libchip/rtc.h> +#include <string.h> +#include "pcf8563.h" + +/* Convert from/to Binary-Coded Decimal representation */ +#define From_BCD( _x ) ((((_x) >> 4) * 10) + ((_x) & 0x0F)) +#define To_BCD( _x ) ((((_x) / 10) << 4) + ((_x) % 10)) + +/* pcf8563_initialize -- + * Initialize PCF8563 real-time clock chip. If RTC is halted, this + * function resume counting. + * + * PARAMETERS: + * minor -- minor RTC device number + */ +static void +pcf8563_initialize(int minor) +{ + i2c_message_status status; + int try; + uint8_t ctrl1; + i2c_bus_number bus; + i2c_address addr; + + bus = RTC_Table[minor].ulCtrlPort1; + addr = RTC_Table[minor].ulDataPort; + + /* Read SECONDS register */ + try = 0; + do { + status = i2c_wbrd(bus, addr, PCF8563_CONTROL1_ADR, + &ctrl1, sizeof(ctrl1)); + try++; + } while ((status != I2C_SUCCESSFUL) && (try < 15)); + + /* If clock is halted, reset and start the clock */ + if ((ctrl1 & PCF8563_CONTROL1_STOP) != 0) + { + uint8_t start[8]; + memset(start, 0, sizeof(start)); + start[0] = PCF8563_CONTROL1_ADR; + try = 0; + do { + status = i2c_write(bus, addr, start, 2); + } while ((status != I2C_SUCCESSFUL) && (try < 15)); + } +} + +/* pcf8563_get_time -- + * read current time from PCF8563 real-time clock chip and convert it + * to the rtems_time_of_day structure. + * + * PARAMETERS: + * minor -- minor RTC device number + * time -- place to put return value (date and time) + * + * RETURNS: + * 0, if time obtained successfully + * -1, if error occured + */ +static int +pcf8563_get_time(int minor, rtems_time_of_day *time) +{ + i2c_bus_number bus; + i2c_address addr; + uint8_t info[10]; + uint32_t v1, v2; + i2c_message_status status; + int try; + + if (time == NULL) + return -1; + + bus = RTC_Table[minor].ulCtrlPort1; + addr = RTC_Table[minor].ulDataPort; + + memset(time, 0, sizeof(rtems_time_of_day)); + try = 0; + do { + status = i2c_wbrd(bus, addr, PCF8563_SECOND_ADR, info, sizeof(info)); + try++; + } while ((status != I2C_SUCCESSFUL) && (try < 10)); + + if (status != I2C_SUCCESSFUL) + { + return -1; + } + + v1 = info[PCF8563_YEAR_ADR-PCF8563_SECOND_ADR]; + v2 = From_BCD(v1); + if ((info[PCF8563_MONTH_ADR-PCF8563_SECOND_ADR] + & PCF8563_MONTH_CENTURY) == 0) { + time->year = 1900 + v2; + } + else { + time->year = 2000 + v2; + } + + v1 = info[PCF8563_MONTH_ADR-PCF8563_SECOND_ADR] & PCF8563_MONTH_MASK; + time->month = From_BCD(v1); + + v1 = info[PCF8563_DAY_ADR-PCF8563_SECOND_ADR] & PCF8563_DAY_MASK; + time->day = From_BCD(v1); + + v1 = info[PCF8563_HOUR_ADR-PCF8563_SECOND_ADR] & PCF8563_HOUR_MASK; + time->hour = From_BCD(v1); + + v1 = info[PCF8563_MINUTE_ADR-PCF8563_SECOND_ADR] & PCF8563_MINUTE_MASK; + time->minute = From_BCD(v1); + + v1 = info[PCF8563_SECOND_ADR-PCF8563_SECOND_ADR] & PCF8563_SECOND_MASK; + time->second = From_BCD(v1); + + return 0; +} + +/* pcf8563_set_time -- + * set time to the PCF8563 real-time clock chip + * + * PARAMETERS: + * minor -- minor RTC device number + * time -- new date and time to be written to PCF8563 + * + * RETURNS: + * 0, if time obtained successfully + * -1, if error occured + */ +static int +pcf8563_set_time(int minor, const rtems_time_of_day *time) +{ + i2c_bus_number bus; + i2c_address addr; + uint8_t info[8]; + i2c_message_status status; + int try; + + if (time == NULL) + return -1; + + bus = RTC_Table[minor].ulCtrlPort1; + addr = RTC_Table[minor].ulDataPort; + + if ((time->year >= 2100) || (time->year < 1900)) { + bsp_fatal(MPC5200_FATAL_PCF8563_INVALID_YEAR); + } + info[0] = PCF8563_SECOND_ADR; + info[1 + PCF8563_YEAR_ADR -PCF8563_SECOND_ADR] = To_BCD(time->year % 100); + info[1 + PCF8563_MONTH_ADR -PCF8563_SECOND_ADR] = To_BCD(time->month); + info[1 + PCF8563_DAY_ADR -PCF8563_SECOND_ADR] = To_BCD(time->day); + info[1 + PCF8563_HOUR_ADR -PCF8563_SECOND_ADR] = To_BCD(time->hour); + info[1 + PCF8563_MINUTE_ADR-PCF8563_SECOND_ADR] = To_BCD(time->minute); + info[1 + PCF8563_SECOND_ADR-PCF8563_SECOND_ADR] = To_BCD(time->second); + /* Do not set day of week */ + info[1 + PCF8563_DAY_OF_WEEK_ADR-PCF8563_SECOND_ADR] = 1; + + /* + * add century info + */ + if (time->year >= 2000) { + info[1 + PCF8563_MONTH_ADR -PCF8563_SECOND_ADR] |= PCF8563_MONTH_CENTURY; + } + /* + * send to device + */ + try = 0; + do { + status = i2c_write(bus, addr, info,sizeof(info)); + try++; + } while ((status != I2C_SUCCESSFUL) && (try < 10)); + + if (status != I2C_SUCCESSFUL) + return -1; + else + return 0; +} + +/* Driver function table */ + +rtc_fns pcf8563_fns = { + pcf8563_initialize, + pcf8563_get_time, + pcf8563_set_time +}; |