Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:53

0001 /*
0002  * RTEMS generic MPC5200 BSP
0003  *
0004  * This file contains the tod driver for a Philips pcf8563 I2C RTC.
0005  *
0006  * This file interfaces with the real-time clock found in a
0007  * Philips PCF8563 serial real-time clock chip.
0008  * This RTC have I2C bus interface. BSP have to provide I2C bus primitives
0009  * to make this driver working. getRegister and setRegister primitives is
0010  * not used here to avoid multiple transactions over I2C bus (each transaction
0011  * require significant time and error when date/time information red may
0012  * occurs). ulControlPort contains I2C bus number; ulDataPort contains
0013  * RTC I2C device address.
0014  *
0015  * Based on a ds1307 driver.
0016  */
0017 
0018 /*
0019  * Copyright (C) 2000 OKTET Ltd., St.-Petersburg, Russia
0020  * Author: Victor V. Vengerov <vvv@oktet.ru>
0021  * Copyright (c) 2005 embedded brains GmbH & Co. KG
0022  *
0023  * The license and distribution terms for this file may be
0024  * found in the file LICENSE in this distribution or at
0025  *
0026  * http://www.rtems.org/license/LICENSE.
0027  */
0028 
0029 #include <rtems.h>
0030 #include <bsp/fatal.h>
0031 #include <bsp/i2c.h>
0032 #include <libchip/rtc.h>
0033 #include <string.h>
0034 #include "pcf8563.h"
0035 
0036 /* Convert from/to Binary-Coded Decimal representation */
0037 #define From_BCD( _x ) ((((_x) >> 4) * 10) + ((_x) & 0x0F))
0038 #define To_BCD( _x )   ((((_x) / 10) << 4) + ((_x) % 10))
0039 
0040 /* pcf8563_initialize --
0041  *     Initialize PCF8563 real-time clock chip. If RTC is halted, this
0042  *     function resume counting.
0043  *
0044  * PARAMETERS:
0045  *     minor -- minor RTC device number
0046  */
0047 static void
0048 pcf8563_initialize(int minor)
0049 {
0050     i2c_message_status status;
0051     int try;
0052     uint8_t         ctrl1;
0053     i2c_bus_number bus;
0054     i2c_address addr;
0055 
0056     bus = RTC_Table[minor].ulCtrlPort1;
0057     addr = RTC_Table[minor].ulDataPort;
0058 
0059     /* Read SECONDS register */
0060     try = 0;
0061     do {
0062         status = i2c_wbrd(bus, addr, PCF8563_CONTROL1_ADR,
0063               &ctrl1, sizeof(ctrl1));
0064         try++;
0065     } while ((status != I2C_SUCCESSFUL) && (try < 15));
0066 
0067     /* If clock is halted, reset and start the clock */
0068     if ((ctrl1 & PCF8563_CONTROL1_STOP) != 0)
0069     {
0070         uint8_t         start[8];
0071         memset(start, 0, sizeof(start));
0072         start[0] = PCF8563_CONTROL1_ADR;
0073         try = 0;
0074         do {
0075             status = i2c_write(bus, addr, start, 2);
0076         } while ((status != I2C_SUCCESSFUL) && (try < 15));
0077     }
0078 }
0079 
0080 /* pcf8563_get_time --
0081  *     read current time from PCF8563 real-time clock chip and convert it
0082  *     to the rtems_time_of_day structure.
0083  *
0084  * PARAMETERS:
0085  *     minor -- minor RTC device number
0086  *     time -- place to put return value (date and time)
0087  *
0088  * RETURNS:
0089  *     0, if time obtained successfully
0090  *     -1, if error occured
0091  */
0092 static int
0093 pcf8563_get_time(int minor, rtems_time_of_day *time)
0094 {
0095     i2c_bus_number bus;
0096     i2c_address addr;
0097     uint8_t         info[10];
0098     uint32_t         v1, v2;
0099     i2c_message_status status;
0100     int try;
0101 
0102     if (time == NULL)
0103         return -1;
0104 
0105     bus = RTC_Table[minor].ulCtrlPort1;
0106     addr = RTC_Table[minor].ulDataPort;
0107 
0108     memset(time, 0, sizeof(rtems_time_of_day));
0109     try = 0;
0110     do {
0111         status = i2c_wbrd(bus, addr, PCF8563_SECOND_ADR, info, sizeof(info));
0112         try++;
0113     } while ((status != I2C_SUCCESSFUL) && (try < 10));
0114 
0115     if (status != I2C_SUCCESSFUL)
0116     {
0117         return -1;
0118     }
0119 
0120     v1 = info[PCF8563_YEAR_ADR-PCF8563_SECOND_ADR];
0121     v2 = From_BCD(v1);
0122     if ((info[PCF8563_MONTH_ADR-PCF8563_SECOND_ADR]
0123      & PCF8563_MONTH_CENTURY) == 0) {
0124       time->year = 1900 + v2;
0125     }
0126     else {
0127       time->year = 2000 + v2;
0128     }
0129 
0130     v1 = info[PCF8563_MONTH_ADR-PCF8563_SECOND_ADR] & PCF8563_MONTH_MASK;
0131     time->month = From_BCD(v1);
0132 
0133     v1 = info[PCF8563_DAY_ADR-PCF8563_SECOND_ADR] & PCF8563_DAY_MASK;
0134     time->day = From_BCD(v1);
0135 
0136     v1 = info[PCF8563_HOUR_ADR-PCF8563_SECOND_ADR] & PCF8563_HOUR_MASK;
0137     time->hour = From_BCD(v1);
0138 
0139     v1 = info[PCF8563_MINUTE_ADR-PCF8563_SECOND_ADR] & PCF8563_MINUTE_MASK;
0140     time->minute = From_BCD(v1);
0141 
0142     v1 = info[PCF8563_SECOND_ADR-PCF8563_SECOND_ADR] & PCF8563_SECOND_MASK;
0143     time->second = From_BCD(v1);
0144 
0145     return 0;
0146 }
0147 
0148 /* pcf8563_set_time --
0149  *     set time to the PCF8563 real-time clock chip
0150  *
0151  * PARAMETERS:
0152  *     minor -- minor RTC device number
0153  *     time -- new date and time to be written to PCF8563
0154  *
0155  * RETURNS:
0156  *     0, if time obtained successfully
0157  *     -1, if error occured
0158  */
0159 static int
0160 pcf8563_set_time(int minor, const rtems_time_of_day *time)
0161 {
0162     i2c_bus_number bus;
0163     i2c_address addr;
0164     uint8_t         info[8];
0165     i2c_message_status status;
0166     int try;
0167 
0168     if (time == NULL)
0169         return -1;
0170 
0171     bus = RTC_Table[minor].ulCtrlPort1;
0172     addr = RTC_Table[minor].ulDataPort;
0173 
0174     if ((time->year >= 2100) || (time->year <  1900)) {
0175       bsp_fatal(MPC5200_FATAL_PCF8563_INVALID_YEAR);
0176     }
0177     info[0] = PCF8563_SECOND_ADR;
0178     info[1 + PCF8563_YEAR_ADR  -PCF8563_SECOND_ADR] = To_BCD(time->year % 100);
0179     info[1 + PCF8563_MONTH_ADR -PCF8563_SECOND_ADR] = To_BCD(time->month);
0180     info[1 + PCF8563_DAY_ADR   -PCF8563_SECOND_ADR] = To_BCD(time->day);
0181     info[1 + PCF8563_HOUR_ADR  -PCF8563_SECOND_ADR] = To_BCD(time->hour);
0182     info[1 + PCF8563_MINUTE_ADR-PCF8563_SECOND_ADR] = To_BCD(time->minute);
0183     info[1 + PCF8563_SECOND_ADR-PCF8563_SECOND_ADR] = To_BCD(time->second);
0184     /* Do not set day of week */
0185     info[1 + PCF8563_DAY_OF_WEEK_ADR-PCF8563_SECOND_ADR] = 1;
0186 
0187     /*
0188      * add century info
0189      */
0190     if (time->year >= 2000) {
0191       info[1 + PCF8563_MONTH_ADR -PCF8563_SECOND_ADR] |= PCF8563_MONTH_CENTURY;
0192     }
0193     /*
0194      * send to device
0195      */
0196     try = 0;
0197     do {
0198         status = i2c_write(bus, addr, info,sizeof(info));
0199         try++;
0200     } while ((status != I2C_SUCCESSFUL) && (try < 10));
0201 
0202     if (status != I2C_SUCCESSFUL)
0203         return -1;
0204     else
0205         return 0;
0206 }
0207 
0208 /* Driver function table */
0209 
0210 rtc_fns pcf8563_fns = {
0211     pcf8563_initialize,
0212     pcf8563_get_time,
0213     pcf8563_set_time
0214 };