uboot/drivers/rtc/pt7c4338.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright 2010 Freescale Semiconductor, Inc.
   4 * Copyright 2020 NXP
   5 *
   6 * Author:      Priyanka Jain <Priyanka.Jain@freescale.com>
   7 */
   8
   9/*
  10 * This file provides Date & Time support (no alarms) for PT7C4338 chip.
  11 *
  12 * This file is based on drivers/rtc/ds1337.c
  13 *
  14 * PT7C4338 chip is manufactured by Pericom Technology Inc.
  15 * It is a serial real-time clock which provides
  16 * 1)Low-power clock/calendar.
  17 * 2)Programmable square-wave output.
  18 * It has 56 bytes of nonvolatile RAM.
  19 */
  20
  21#include <common.h>
  22#include <command.h>
  23#include <dm.h>
  24#include <log.h>
  25#include <rtc.h>
  26#include <i2c.h>
  27
  28/* RTC register addresses */
  29#define RTC_SEC_REG_ADDR        0x0
  30#define RTC_MIN_REG_ADDR        0x1
  31#define RTC_HR_REG_ADDR         0x2
  32#define RTC_DAY_REG_ADDR        0x3
  33#define RTC_DATE_REG_ADDR       0x4
  34#define RTC_MON_REG_ADDR        0x5
  35#define RTC_YR_REG_ADDR         0x6
  36#define RTC_CTL_STAT_REG_ADDR   0x7
  37
  38/* RTC second register address bit */
  39#define RTC_SEC_BIT_CH          0x80    /* Clock Halt (in Register 0) */
  40
  41/* RTC control and status register bits */
  42#define RTC_CTL_STAT_BIT_RS0    0x1     /* Rate select 0 */
  43#define RTC_CTL_STAT_BIT_RS1    0x2     /* Rate select 1 */
  44#define RTC_CTL_STAT_BIT_SQWE   0x10    /* Square Wave Enable */
  45#define RTC_CTL_STAT_BIT_OSF    0x20    /* Oscillator Stop Flag */
  46#define RTC_CTL_STAT_BIT_OUT    0x80    /* Output Level Control */
  47
  48/* RTC reset value */
  49#define RTC_PT7C4338_RESET_VAL \
  50        (RTC_CTL_STAT_BIT_RS0 | RTC_CTL_STAT_BIT_RS1 | RTC_CTL_STAT_BIT_OUT)
  51
  52#if !CONFIG_IS_ENABLED(DM_RTC)
  53/****** Helper functions ****************************************/
  54static u8 rtc_read(u8 reg)
  55{
  56        return i2c_reg_read(CONFIG_SYS_I2C_RTC_ADDR, reg);
  57}
  58
  59static void rtc_write(u8 reg, u8 val)
  60{
  61        i2c_reg_write(CONFIG_SYS_I2C_RTC_ADDR, reg, val);
  62}
  63/****************************************************************/
  64
  65/* Get the current time from the RTC */
  66int rtc_get(struct rtc_time *tmp)
  67{
  68        int ret = 0;
  69        u8 sec, min, hour, mday, wday, mon, year, ctl_stat;
  70
  71        ctl_stat = rtc_read(RTC_CTL_STAT_REG_ADDR);
  72        sec = rtc_read(RTC_SEC_REG_ADDR);
  73        min = rtc_read(RTC_MIN_REG_ADDR);
  74        hour = rtc_read(RTC_HR_REG_ADDR);
  75        wday = rtc_read(RTC_DAY_REG_ADDR);
  76        mday = rtc_read(RTC_DATE_REG_ADDR);
  77        mon = rtc_read(RTC_MON_REG_ADDR);
  78        year = rtc_read(RTC_YR_REG_ADDR);
  79        debug("Get RTC year: %02x mon: %02x mday: %02x wday: %02x "
  80                "hr: %02x min: %02x sec: %02x control_status: %02x\n",
  81                year, mon, mday, wday, hour, min, sec, ctl_stat);
  82
  83        if (ctl_stat & RTC_CTL_STAT_BIT_OSF) {
  84                printf("### Warning: RTC oscillator has stopped\n");
  85                /* clear the OSF flag */
  86                rtc_write(RTC_CTL_STAT_REG_ADDR,
  87                        rtc_read(RTC_CTL_STAT_REG_ADDR)\
  88                        & ~RTC_CTL_STAT_BIT_OSF);
  89                ret = -1;
  90        }
  91
  92        tmp->tm_sec = bcd2bin(sec & 0x7F);
  93        tmp->tm_min = bcd2bin(min & 0x7F);
  94        tmp->tm_hour = bcd2bin(hour & 0x3F);
  95        tmp->tm_mday = bcd2bin(mday & 0x3F);
  96        tmp->tm_mon = bcd2bin(mon & 0x1F);
  97        tmp->tm_year = bcd2bin(year) + 2000;
  98        tmp->tm_wday = bcd2bin((wday - 1) & 0x07);
  99        tmp->tm_yday = 0;
 100        tmp->tm_isdst = 0;
 101        debug("Get DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",
 102                tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
 103                tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
 104
 105        return ret;
 106}
 107
 108/* Set the RTC */
 109int rtc_set(struct rtc_time *tmp)
 110{
 111        debug("Set DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",
 112                tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
 113                tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
 114
 115        rtc_write(RTC_YR_REG_ADDR, bin2bcd(tmp->tm_year % 100));
 116        rtc_write(RTC_MON_REG_ADDR, bin2bcd(tmp->tm_mon));
 117        rtc_write(RTC_DAY_REG_ADDR, bin2bcd(tmp->tm_wday + 1));
 118        rtc_write(RTC_DATE_REG_ADDR, bin2bcd(tmp->tm_mday));
 119        rtc_write(RTC_HR_REG_ADDR, bin2bcd(tmp->tm_hour));
 120        rtc_write(RTC_MIN_REG_ADDR, bin2bcd(tmp->tm_min));
 121        rtc_write(RTC_SEC_REG_ADDR, bin2bcd(tmp->tm_sec));
 122
 123        return 0;
 124}
 125
 126/* Reset the RTC */
 127void rtc_reset(void)
 128{
 129        rtc_write(RTC_SEC_REG_ADDR, 0x00);      /* clearing Clock Halt  */
 130        rtc_write(RTC_CTL_STAT_REG_ADDR, RTC_PT7C4338_RESET_VAL);
 131}
 132#else
 133static u8 rtc_read(struct udevice *dev, u8 reg)
 134{
 135        return dm_i2c_reg_read(dev, reg);
 136}
 137
 138static void rtc_write(struct udevice *dev, u8 reg, u8 val)
 139{
 140        dm_i2c_reg_write(dev, reg, val);
 141}
 142
 143static int pt7c4338_rtc_get(struct udevice *dev, struct rtc_time *tmp)
 144{
 145        int ret = 0;
 146        u8 sec, min, hour, mday, wday, mon, year, ctl_stat;
 147
 148        ctl_stat = rtc_read(dev, RTC_CTL_STAT_REG_ADDR);
 149        sec = rtc_read(dev, RTC_SEC_REG_ADDR);
 150        min = rtc_read(dev, RTC_MIN_REG_ADDR);
 151        hour = rtc_read(dev, RTC_HR_REG_ADDR);
 152        wday = rtc_read(dev, RTC_DAY_REG_ADDR);
 153        mday = rtc_read(dev, RTC_DATE_REG_ADDR);
 154        mon = rtc_read(dev, RTC_MON_REG_ADDR);
 155        year = rtc_read(dev, RTC_YR_REG_ADDR);
 156        debug("Get RTC year: %02x mon: %02x mday: %02x wday: %02x\n",
 157              year, mon, mday, wday);
 158        debug("hr: %02x min: %02x sec: %02x control_status: %02x\n",
 159              hour, min, sec, ctl_stat);
 160
 161        if (ctl_stat & RTC_CTL_STAT_BIT_OSF) {
 162                printf("### Warning: RTC oscillator has stopped\n");
 163                /* clear the OSF flag */
 164                rtc_write(dev, RTC_CTL_STAT_REG_ADDR,
 165                          rtc_read(dev,
 166                                   RTC_CTL_STAT_REG_ADDR)
 167                                   & ~RTC_CTL_STAT_BIT_OSF);
 168                ret = -1;
 169        }
 170
 171        tmp->tm_sec = bcd2bin(sec & 0x7F);
 172        tmp->tm_min = bcd2bin(min & 0x7F);
 173        tmp->tm_hour = bcd2bin(hour & 0x3F);
 174        tmp->tm_mday = bcd2bin(mday & 0x3F);
 175        tmp->tm_mon = bcd2bin(mon & 0x1F);
 176        tmp->tm_year = bcd2bin(year) + 2000;
 177        tmp->tm_wday = bcd2bin((wday - 1) & 0x07);
 178        tmp->tm_yday = 0;
 179        tmp->tm_isdst = 0;
 180        debug("Get DATE: %4d-%02d-%02d [wday=%d]  TIME: %2d:%02d:%02d\n",
 181              tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
 182              tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
 183
 184        return ret;
 185}
 186
 187static int pt7c4338_rtc_set(struct udevice *dev, const struct rtc_time *tmp)
 188{
 189        debug("Set DATE: %4d-%02d-%02d [wday=%d]  TIME: %2d:%02d:%02d\n",
 190              tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
 191              tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
 192
 193        rtc_write(dev, RTC_YR_REG_ADDR, bin2bcd(tmp->tm_year % 100));
 194        rtc_write(dev, RTC_MON_REG_ADDR, bin2bcd(tmp->tm_mon));
 195        rtc_write(dev, RTC_DAY_REG_ADDR, bin2bcd(tmp->tm_wday + 1));
 196        rtc_write(dev, RTC_DATE_REG_ADDR, bin2bcd(tmp->tm_mday));
 197        rtc_write(dev, RTC_HR_REG_ADDR, bin2bcd(tmp->tm_hour));
 198        rtc_write(dev, RTC_MIN_REG_ADDR, bin2bcd(tmp->tm_min));
 199        rtc_write(dev, RTC_SEC_REG_ADDR, bin2bcd(tmp->tm_sec));
 200
 201        return 0;
 202}
 203
 204static int pt7c4338_rtc_reset(struct udevice *dev)
 205{
 206        rtc_write(dev, RTC_SEC_REG_ADDR, 0x00); /* clearing Clock Halt  */
 207        rtc_write(dev, RTC_CTL_STAT_REG_ADDR, RTC_PT7C4338_RESET_VAL);
 208        return 0;
 209}
 210
 211static const struct rtc_ops pt7c4338_rtc_ops = {
 212        .get = pt7c4338_rtc_get,
 213        .set = pt7c4338_rtc_set,
 214        .reset = pt7c4338_rtc_reset,
 215};
 216
 217static const struct udevice_id pt7c4338_rtc_ids[] = {
 218        { .compatible = "pericom,pt7c4338" },
 219        { }
 220};
 221
 222U_BOOT_DRIVER(rtc_pt7c4338) = {
 223        .name   = "rtc-pt7c4338",
 224        .id     = UCLASS_RTC,
 225        .of_match = pt7c4338_rtc_ids,
 226        .ops    = &pt7c4338_rtc_ops,
 227};
 228#endif
 229