diff options
Diffstat (limited to 'drivers/rtc')
| -rw-r--r-- | drivers/rtc/Kconfig | 7 | ||||
| -rw-r--r-- | drivers/rtc/ds1307.c | 158 | ||||
| -rw-r--r-- | drivers/rtc/goldfish_rtc.c | 16 | ||||
| -rw-r--r-- | drivers/rtc/i2c_rtc_emul.c | 2 | ||||
| -rw-r--r-- | drivers/rtc/m41t62.c | 4 | ||||
| -rw-r--r-- | drivers/rtc/mcfrtc.c | 2 | ||||
| -rw-r--r-- | drivers/rtc/pcf85063.c | 134 | ||||
| -rw-r--r-- | drivers/rtc/sandbox_rtc.c | 2 |
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 |
