diff options
Diffstat (limited to 'drivers/rtc')
| -rw-r--r-- | drivers/rtc/Kconfig | 7 | ||||
| -rw-r--r-- | drivers/rtc/ds1307.c | 6 | ||||
| -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, 24 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 34d8f8c5276..4176ab3701e 100644 --- a/drivers/rtc/ds1307.c +++ b/drivers/rtc/ds1307.c @@ -116,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)) { 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 |
