summaryrefslogtreecommitdiff
path: root/drivers/rtc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/rtc')
-rw-r--r--drivers/rtc/Kconfig7
-rw-r--r--drivers/rtc/ds1307.c158
-rw-r--r--drivers/rtc/goldfish_rtc.c16
-rw-r--r--drivers/rtc/i2c_rtc_emul.c2
-rw-r--r--drivers/rtc/m41t62.c4
-rw-r--r--drivers/rtc/mcfrtc.c2
-rw-r--r--drivers/rtc/pcf85063.c134
-rw-r--r--drivers/rtc/sandbox_rtc.c2
8 files changed, 149 insertions, 176 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 65d9bf533cb..6fb3019a644 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -44,8 +44,8 @@ config VPL_DM_RTC
config RTC_ENABLE_32KHZ_OUTPUT
bool "Enable RTC 32Khz output"
help
- Some real-time clocks support the output of 32kHz square waves (such as ds3231),
- the config symbol choose Real Time Clock device 32Khz output feature.
+ Some real-time clocks support the output of 32kHz square waves (such as ds3231),
+ the config symbol choose Real Time Clock device 32Khz output feature.
config RTC_ARMADA38X
bool "Enable Armada 38x Marvell SoC RTC"
@@ -163,6 +163,9 @@ config RTC_PCF85063
help
If you say yes here you get support for the NXP PCF85063 RTC
and compatible chips.
+ Support for the following chip features is currently not implemented:
+ - NVMEM device for RAM register
+ - CLKOUT generation
config RTC_PCF8563
bool "Philips PCF8563"
diff --git a/drivers/rtc/ds1307.c b/drivers/rtc/ds1307.c
index 04921099101..4176ab3701e 100644
--- a/drivers/rtc/ds1307.c
+++ b/drivers/rtc/ds1307.c
@@ -68,157 +68,6 @@ enum ds_type {
#define MCP7941X_BIT_ST 0x80
#define MCP7941X_BIT_VBATEN 0x08
-#ifndef CONFIG_DM_RTC
-
-/*---------------------------------------------------------------------*/
-#undef DEBUG_RTC
-
-#ifdef DEBUG_RTC
-#define DEBUGR(fmt, args...) printf(fmt, ##args)
-#else
-#define DEBUGR(fmt, args...)
-#endif
-/*---------------------------------------------------------------------*/
-
-#ifndef CFG_SYS_I2C_RTC_ADDR
-# define CFG_SYS_I2C_RTC_ADDR 0x68
-#endif
-
-#if defined(CONFIG_RTC_DS1307) && (CONFIG_SYS_I2C_SPEED > 100000)
-# error The DS1307 is specified only up to 100kHz!
-#endif
-
-static uchar rtc_read (uchar reg);
-static void rtc_write (uchar reg, uchar val);
-
-/*
- * Get the current time from the RTC
- */
-int rtc_get (struct rtc_time *tmp)
-{
- int rel = 0;
- uchar sec, min, hour, mday, wday, mon, year;
-
-#ifdef CONFIG_RTC_MCP79411
-read_rtc:
-#endif
- sec = rtc_read (RTC_SEC_REG_ADDR);
- min = rtc_read (RTC_MIN_REG_ADDR);
- hour = rtc_read (RTC_HR_REG_ADDR);
- wday = rtc_read (RTC_DAY_REG_ADDR);
- mday = rtc_read (RTC_DATE_REG_ADDR);
- mon = rtc_read (RTC_MON_REG_ADDR);
- year = rtc_read (RTC_YR_REG_ADDR);
-
- DEBUGR ("Get RTC year: %02x mon: %02x mday: %02x wday: %02x "
- "hr: %02x min: %02x sec: %02x\n",
- year, mon, mday, wday, hour, min, sec);
-
-#ifdef CONFIG_RTC_DS1307
- if (sec & RTC_SEC_BIT_CH) {
- printf ("### Warning: RTC oscillator has stopped\n");
- /* clear the CH flag */
- rtc_write (RTC_SEC_REG_ADDR,
- rtc_read (RTC_SEC_REG_ADDR) & ~RTC_SEC_BIT_CH);
- rel = -1;
- }
-#endif
-
-#ifdef CONFIG_RTC_MCP79411
- /* make sure that the backup battery is enabled */
- if (!(wday & MCP7941X_BIT_VBATEN)) {
- rtc_write(RTC_DAY_REG_ADDR,
- wday | MCP7941X_BIT_VBATEN);
- }
-
- /* clock halted? turn it on, so clock can tick. */
- if (!(sec & MCP7941X_BIT_ST)) {
- rtc_write(RTC_SEC_REG_ADDR, MCP7941X_BIT_ST);
- printf("Started RTC\n");
- goto read_rtc;
- }
-#endif
-
- tmp->tm_sec = bcd2bin (sec & 0x7F);
- tmp->tm_min = bcd2bin (min & 0x7F);
- tmp->tm_hour = bcd2bin (hour & 0x3F);
- tmp->tm_mday = bcd2bin (mday & 0x3F);
- tmp->tm_mon = bcd2bin (mon & 0x1F);
- tmp->tm_year = bcd2bin (year) + ( bcd2bin (year) >= 70 ? 1900 : 2000);
- tmp->tm_wday = bcd2bin ((wday - 1) & 0x07);
- tmp->tm_yday = 0;
- tmp->tm_isdst= 0;
-
- DEBUGR ("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
- tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
- tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
-
- return rel;
-}
-
-/*
- * Set the RTC
- */
-int rtc_set (struct rtc_time *tmp)
-{
- DEBUGR ("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
- tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
- tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
-
- if (tmp->tm_year < 1970 || tmp->tm_year > 2069)
- printf("WARNING: year should be between 1970 and 2069!\n");
-
- rtc_write (RTC_YR_REG_ADDR, bin2bcd (tmp->tm_year % 100));
- rtc_write (RTC_MON_REG_ADDR, bin2bcd (tmp->tm_mon));
-#ifdef CONFIG_RTC_MCP79411
- rtc_write (RTC_DAY_REG_ADDR,
- bin2bcd (tmp->tm_wday + 1) | MCP7941X_BIT_VBATEN);
-#else
- rtc_write (RTC_DAY_REG_ADDR, bin2bcd (tmp->tm_wday + 1));
-#endif
- rtc_write (RTC_DATE_REG_ADDR, bin2bcd (tmp->tm_mday));
- rtc_write (RTC_HR_REG_ADDR, bin2bcd (tmp->tm_hour));
- rtc_write (RTC_MIN_REG_ADDR, bin2bcd (tmp->tm_min));
-#ifdef CONFIG_RTC_MCP79411
- rtc_write (RTC_SEC_REG_ADDR, bin2bcd (tmp->tm_sec) | MCP7941X_BIT_ST);
-#else
- rtc_write (RTC_SEC_REG_ADDR, bin2bcd (tmp->tm_sec));
-#endif
-
- return 0;
-}
-
-/*
- * Reset the RTC. We setting the date back to 1970-01-01.
- * We also enable the oscillator output on the SQW/OUT pin and program
- * it for 32,768 Hz output. Note that according to the datasheet, turning
- * on the square wave output increases the current drain on the backup
- * battery to something between 480nA and 800nA.
- */
-void rtc_reset (void)
-{
- rtc_write (RTC_SEC_REG_ADDR, 0x00); /* clearing Clock Halt */
- rtc_write (RTC_CTL_REG_ADDR, RTC_CTL_BIT_SQWE | RTC_CTL_BIT_RS1 | RTC_CTL_BIT_RS0);
-}
-
-/*
- * Helper functions
- */
-
-static
-uchar rtc_read (uchar reg)
-{
- return (i2c_reg_read (CFG_SYS_I2C_RTC_ADDR, reg));
-}
-
-static void rtc_write (uchar reg, uchar val)
-{
- i2c_reg_write (CFG_SYS_I2C_RTC_ADDR, reg, val);
-}
-
-#endif /* !CONFIG_DM_RTC */
-
-#ifdef CONFIG_DM_RTC
static int ds1307_rtc_set(struct udevice *dev, const struct rtc_time *tm)
{
int ret;
@@ -267,9 +116,9 @@ static int ds1307_rtc_get(struct udevice *dev, struct rtc_time *tm)
if (ret < 0)
return ret;
- if (type == ds_1337 || type == ds_1340) {
- uint reg = (type == ds_1337) ? DS1337_STAT_REG_ADDR :
- DS1340_STAT_REG_ADDR;
+ if (type == ds_1337 || type == ds_1339 || type == ds_1340) {
+ uint reg = (type == ds_1340) ? DS1340_STAT_REG_ADDR :
+ DS1337_STAT_REG_ADDR;
int status = dm_i2c_reg_read(dev, reg);
if (status >= 0 && (status & RTC_STAT_BIT_OSF)) {
@@ -366,4 +215,3 @@ U_BOOT_DRIVER(rtc_ds1307) = {
.of_match = ds1307_rtc_ids,
.ops = &ds1307_rtc_ops,
};
-#endif /* CONFIG_DM_RTC */
diff --git a/drivers/rtc/goldfish_rtc.c b/drivers/rtc/goldfish_rtc.c
index d2991ca6719..652eec7dd0c 100644
--- a/drivers/rtc/goldfish_rtc.c
+++ b/drivers/rtc/goldfish_rtc.c
@@ -40,8 +40,8 @@ static int goldfish_rtc_get(struct udevice *dev, struct rtc_time *time)
u64 time_low;
u64 now;
- time_low = ioread32(base + GOLDFISH_TIME_LOW);
- time_high = ioread32(base + GOLDFISH_TIME_HIGH);
+ time_low = __raw_readl(base + GOLDFISH_TIME_LOW);
+ time_high = __raw_readl(base + GOLDFISH_TIME_HIGH);
now = (time_high << 32) | time_low;
do_div(now, 1000000000U);
@@ -62,8 +62,8 @@ static int goldfish_rtc_set(struct udevice *dev, const struct rtc_time *time)
return -EINVAL;
now = rtc_mktime(time) * 1000000000ULL;
- iowrite32(now >> 32, base + GOLDFISH_TIME_HIGH);
- iowrite32(now, base + GOLDFISH_TIME_LOW);
+ __raw_writel(now >> 32, base + GOLDFISH_TIME_HIGH);
+ __raw_writel(now, base + GOLDFISH_TIME_LOW);
if (time->tm_isdst > 0)
priv->isdst = 1;
@@ -80,9 +80,13 @@ static int goldfish_rtc_of_to_plat(struct udevice *dev)
struct goldfish_rtc_plat *plat = dev_get_plat(dev);
fdt_addr_t addr;
+ plat->reg = 0;
+
addr = dev_read_addr(dev);
- if (addr != FDT_ADDR_T_NONE)
- plat->reg = addr;
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ plat->reg = addr;
return 0;
}
diff --git a/drivers/rtc/i2c_rtc_emul.c b/drivers/rtc/i2c_rtc_emul.c
index ea11c72c964..41bdf275f1e 100644
--- a/drivers/rtc/i2c_rtc_emul.c
+++ b/drivers/rtc/i2c_rtc_emul.c
@@ -191,7 +191,7 @@ static int sandbox_i2c_rtc_xfer(struct udevice *emul, struct i2c_msg *msg,
return 0;
}
-struct dm_i2c_ops sandbox_i2c_rtc_emul_ops = {
+static const struct dm_i2c_ops sandbox_i2c_rtc_emul_ops = {
.xfer = sandbox_i2c_rtc_xfer,
};
diff --git a/drivers/rtc/m41t62.c b/drivers/rtc/m41t62.c
index 7bfea9e0b31..b3734baf63e 100644
--- a/drivers/rtc/m41t62.c
+++ b/drivers/rtc/m41t62.c
@@ -66,7 +66,7 @@ static void m41t62_update_rtc_time(struct rtc_time *tm, u8 *buf)
{
debug("%s: raw read data - sec=%02x, min=%02x, hr=%02x, "
"mday=%02x, mon=%02x, year=%02x, wday=%02x, y2k=%02x\n",
- __FUNCTION__,
+ __func__,
buf[0], buf[1], buf[2], buf[3],
buf[4], buf[5], buf[6], buf[7]);
@@ -83,7 +83,7 @@ static void m41t62_update_rtc_time(struct rtc_time *tm, u8 *buf)
debug("%s: tm is secs=%d, mins=%d, hours=%d, "
"mday=%d, mon=%d, year=%d, wday=%d\n",
- __FUNCTION__,
+ __func__,
tm->tm_sec, tm->tm_min, tm->tm_hour,
tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
}
diff --git a/drivers/rtc/mcfrtc.c b/drivers/rtc/mcfrtc.c
index 9708971c5c4..23ffb2b31a1 100644
--- a/drivers/rtc/mcfrtc.c
+++ b/drivers/rtc/mcfrtc.c
@@ -73,7 +73,7 @@ int rtc_set(struct rtc_time *tmp)
days += month_days[i];
if (i == 1)
- days += isleap(i);
+ days += isleap(tmp->tm_year);
}
days += tmp->tm_mday - 1;
diff --git a/drivers/rtc/pcf85063.c b/drivers/rtc/pcf85063.c
index 737d4547aca..421c42c0b81 100644
--- a/drivers/rtc/pcf85063.c
+++ b/drivers/rtc/pcf85063.c
@@ -11,11 +11,33 @@
#include <dm/device_compat.h>
#define PCF85063_REG_CTRL1 0x00 /* status */
-#define PCF85063_REG_CTRL1_SR 0x58
+#define PCF85063_REG_CTRL1_CAP_SEL BIT(0)
+#define PCF85063_REG_CTRL1_STOP BIT(5)
+#define PCF85063_REG_CTRL1_EXT_TEST BIT(7)
+#define PCF85063_REG_CTRL1_SWR 0x58 /* Software reset command */
+
+#define PCF85063_REG_CTRL2 0x01
+#define PCF85063_CTRL2_AF BIT(6)
+#define PCF85063_CTRL2_AIE BIT(7)
+
+#define PCF85063_REG_OFFSET 0x02
+#define PCF85063_OFFSET_SIGN_BIT 6 /* 2's complement sign bit */
+#define PCF85063_OFFSET_MODE BIT(7)
+#define PCF85063_OFFSET_STEP0 4340
+#define PCF85063_OFFSET_STEP1 4069
+
+#define PCF85063_REG_CLKO_F_MASK 0x07 /* frequency mask */
+#define PCF85063_REG_CLKO_F_32768HZ 0x00
+#define PCF85063_REG_CLKO_F_OFF 0x07
+
+#define PCF85063_REG_RAM 0x03
#define PCF85063_REG_SC 0x04 /* datetime */
#define PCF85063_REG_SC_OS 0x80
+#define PCF85063_REG_ALM_S 0x0b
+#define PCF85063_AEN BIT(7)
+
static int pcf85063_get_time(struct udevice *dev, struct rtc_time *tm)
{
u8 regs[7];
@@ -35,7 +57,9 @@ static int pcf85063_get_time(struct udevice *dev, struct rtc_time *tm)
tm->tm_hour = bcd2bin(regs[2] & 0x3f);
tm->tm_mday = bcd2bin(regs[3] & 0x3f);
tm->tm_wday = regs[4] & 0x07;
- tm->tm_mon = bcd2bin(regs[5] & 0x1f) - 1;
+ /* rtc register and rtc_time spec uses 1 - 12 */
+ tm->tm_mon = bcd2bin(regs[5] & 0x1f);
+ /* adjust rtc_time (years since 0) to match register spec */
tm->tm_year = bcd2bin(regs[6]) + 2000;
return 0;
@@ -44,40 +68,102 @@ static int pcf85063_get_time(struct udevice *dev, struct rtc_time *tm)
static int pcf85063_set_time(struct udevice *dev, const struct rtc_time *tm)
{
u8 regs[7];
+ int rc;
if (tm->tm_year < 2000 || tm->tm_year > 2099) {
dev_err(dev, "Year must be between 2000 and 2099.\n");
return -EINVAL;
}
- regs[0] = bin2bcd(tm->tm_sec);
+ /*
+ * to accurately set the time, reset the divider chain and keep it in
+ * reset state until all time/date registers are written
+ */
+ rc = dm_i2c_reg_clrset(dev, PCF85063_REG_CTRL1,
+ PCF85063_REG_CTRL1_EXT_TEST |
+ PCF85063_REG_CTRL1_STOP,
+ PCF85063_REG_CTRL1_STOP);
+
+ if (rc)
+ return rc;
+
+ /* hours, minutes and seconds */
+ regs[0] = bin2bcd(tm->tm_sec) & (~PCF85063_REG_SC_OS);
+
regs[1] = bin2bcd(tm->tm_min);
regs[2] = bin2bcd(tm->tm_hour);
+
+ /* Day of month, 1 - 31 */
regs[3] = bin2bcd(tm->tm_mday);
- regs[4] = tm->tm_wday;
- regs[5] = bin2bcd(tm->tm_mon + 1);
+
+ /* Day of week 0 - 6 */
+ regs[4] = tm->tm_wday & 0x07;
+
+ /* rtc register and rtc_time spec uses 1 - 12 */
+ regs[5] = bin2bcd(tm->tm_mon);
+ /* adjust register to match rtc_time spec */
regs[6] = bin2bcd(tm->tm_year % 100);
- return dm_i2c_write(dev, PCF85063_REG_SC, regs, sizeof(regs));
+ rc = dm_i2c_write(dev, PCF85063_REG_SC, regs, sizeof(regs));
+ if (rc)
+ return rc;
+
+ /*
+ * Write the control register as a separate action since the size of
+ * the register space is different between the PCF85063TP and
+ * PCF85063A devices. The rollover point can not be used.
+ */
+ return dm_i2c_reg_clrset(dev, PCF85063_REG_CTRL1,
+ PCF85063_REG_CTRL1_STOP, 0);
}
static int pcf85063_reset(struct udevice *dev)
{
- return dm_i2c_reg_write(dev, PCF85063_REG_CTRL1, PCF85063_REG_CTRL1_SR);
+ return dm_i2c_reg_write(dev, PCF85063_REG_CTRL1, PCF85063_REG_CTRL1_SWR);
}
static int pcf85063_read(struct udevice *dev, unsigned int offset, u8 *buf,
unsigned int len)
{
+ if (offset + len > dev->driver_data)
+ return -EINVAL;
+
return dm_i2c_read(dev, offset, buf, len);
}
static int pcf85063_write(struct udevice *dev, unsigned int offset,
const u8 *buf, unsigned int len)
{
+ if (offset + len > dev->driver_data)
+ return -EINVAL;
+
return dm_i2c_write(dev, offset, buf, len);
}
+static int pcf85063_load_capacitance(struct udevice *dev)
+{
+ u32 load = 7000;
+ u8 reg = 0;
+
+ if (ofnode_read_u32(dev_ofnode(dev), "quartz-load-femtofarads", &load))
+ return 0;
+
+ switch (load) {
+ default:
+ dev_warn(dev, "Unknown quartz-load-femtofarads value: %d. Assuming 7000",
+ load);
+ fallthrough;
+ case 7000:
+ break;
+ case 12500:
+ reg = PCF85063_REG_CTRL1_CAP_SEL;
+ break;
+ }
+
+ return dm_i2c_reg_clrset(dev, PCF85063_REG_CTRL1,
+ PCF85063_REG_CTRL1_CAP_SEL, reg);
+}
+
static const struct rtc_ops pcf85063_rtc_ops = {
.get = pcf85063_get_time,
.set = pcf85063_set_time,
@@ -88,13 +174,45 @@ static const struct rtc_ops pcf85063_rtc_ops = {
static int pcf85063_probe(struct udevice *dev)
{
+ u8 tmp;
+ int err;
+
i2c_set_chip_flags(dev, DM_I2C_CHIP_RD_ADDRESS | DM_I2C_CHIP_WR_ADDRESS);
+ err = dm_i2c_read(dev, PCF85063_REG_SC, &tmp, sizeof(tmp));
+ if (err) {
+ dev_err(dev, "RTC chip is not present\n");
+ return err;
+ }
+
+ /*
+ * If a Power loss is detected, SW reset the device.
+ * From PCF85063A datasheet:
+ * There is a low probability that some devices will have corruption
+ * of the registers after the automatic power-on reset...
+ */
+ if (tmp & PCF85063_REG_SC_OS) {
+ dev_warn(dev, "POR issue detected, sending a SW reset\n");
+ err = dm_i2c_reg_clrset(dev, PCF85063_REG_CTRL1,
+ 0xff, PCF85063_REG_CTRL1_SWR);
+ if (err < 0)
+ dev_warn(dev, "SW reset failed, trying to continue\n");
+ }
+
+ err = pcf85063_load_capacitance(dev);
+ if (err < 0)
+ dev_warn(dev, "failed to set xtal load capacitance: %d",
+ err);
+
return 0;
}
static const struct udevice_id pcf85063_of_id[] = {
- { .compatible = "microcrystal,rv8263" },
+ { .compatible = "microcrystal,rv8263", .data = 0x12 },
+ { .compatible = "nxp,pcf85063", .data = 0xb },
+ { .compatible = "nxp,pcf85063a", .data = 0x12 },
+ { .compatible = "nxp,pcf85063tp", .data = 0xb },
+ { .compatible = "nxp,pcf85073a", .data = 0x12 },
{ }
};
diff --git a/drivers/rtc/sandbox_rtc.c b/drivers/rtc/sandbox_rtc.c
index 4404501c2f6..1ade5d50b23 100644
--- a/drivers/rtc/sandbox_rtc.c
+++ b/drivers/rtc/sandbox_rtc.c
@@ -73,7 +73,7 @@ static int sandbox_rtc_get_name(const struct udevice *dev, char *out_name)
return acpi_copy_name(out_name, "RTCC");
}
-struct acpi_ops sandbox_rtc_acpi_ops = {
+static const struct acpi_ops sandbox_rtc_acpi_ops = {
.get_name = sandbox_rtc_get_name,
};
#endif