summaryrefslogtreecommitdiffstats
path: root/bsps/powerpc/gen5200/rtc/pcf8563.c
diff options
context:
space:
mode:
Diffstat (limited to 'bsps/powerpc/gen5200/rtc/pcf8563.c')
-rw-r--r--bsps/powerpc/gen5200/rtc/pcf8563.c228
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
+};