[PATCH v2 3/4] rtc: rk8xx: Add base support for the RK808 PMIC RTC
sunil at amarulasolutions.com
sunil at amarulasolutions.com
Tue Apr 28 17:57:18 CEST 2020
From: Suniel Mahesh <sunil at amarulasolutions.com>
Rockchip RK808 PMIC provides an integrated RTC module. It is
commonly used with Rockchip SoCs. Add basic support to access
date and time.
Signed-off-by: Suniel Mahesh <sunil at amarulasolutions.com>
---
Changes for v2:
- moved corresponding configs which enable rtc into a seperate
patch.
- changed subject line.
Note:
1. The RK808 PMIC RTC has a hardware bug. It counts 31 days
for november month and the weeks register counts 0 - 7.
2. This driver does a temporary fix, where as in if date is Nov 31,
then it resets the date to Dec 1(this happens only if date cmd is queried
from u-boot command line/script). Similarly for the weeks register, 0(sun)
- 6(sat). If 7 is encountered then it is reset to zero.
3. u-boot generally loads linux/other binary. Linux has a full fledged
driver implemented along with a workaround.
https://lkml.org/lkml/2015/12/2/1202
4. Is this change acceptable ? please comment
---
drivers/rtc/Kconfig | 8 +++
drivers/rtc/Makefile | 1 +
drivers/rtc/rk808-rtc.c | 165 ++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 174 insertions(+)
create mode 100644 drivers/rtc/rk808-rtc.c
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 59e2fc4..a754d1b 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -75,6 +75,14 @@ config RTC_ISL1208
This driver supports reading and writing the RTC/calendar and detects
total power failures.
+config RTC_RK808
+ bool "Enable Rockchip RK8XX RTC driver"
+ depends on DM_RTC && PMIC_RK8XX
+ default y
+ help
+ Basic support for Rockchip RK808 PMIC Real Time Clock devices for
+ time and date.
+
config RTC_RV3029
bool "Enable RV3029 driver"
depends on DM_RTC
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 12eb449..63e2c34 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_RTC_PCF8563) += pcf8563.o
obj-$(CONFIG_RTC_PCF2127) += pcf2127.o
obj-$(CONFIG_RTC_PL031) += pl031.o
obj-$(CONFIG_RTC_PT7C4338) += pt7c4338.o
+obj-$(CONFIG_RTC_RK808) += rk808-rtc.o
obj-$(CONFIG_RTC_RS5C372A) += rs5c372.o
obj-$(CONFIG_RTC_RV3029) += rv3029.o
obj-$(CONFIG_RTC_RV8803) += rv8803.o
diff --git a/drivers/rtc/rk808-rtc.c b/drivers/rtc/rk808-rtc.c
new file mode 100644
index 0000000..b63cced
--- /dev/null
+++ b/drivers/rtc/rk808-rtc.c
@@ -0,0 +1,165 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * RTC driver for Rockchip RK808 PMIC.
+ *
+ * Copyright (C) 2020 Amarula Solutions(India).
+ * Suniel Mahesh <sunil at amarulasolutions.com>
+ *
+ * Based on code from Linux kernel:
+ * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
+ * Author: Chris Zhong <zyw at rock-chips.com>
+ * Author: Zhang Qing <zhangqing at rock-chips.com>
+ *
+ * Date & Time support (no alarms and interrupts)
+ */
+
+#include <command.h>
+#include <common.h>
+#include <dm.h>
+#include <i2c.h>
+#include <rtc.h>
+#include <power/rk8xx_pmic.h>
+#include <power/pmic.h>
+
+/* RTC_CTRL_REG bitfields */
+#define BIT_RTC_CTRL_REG_STOP_RTC_M BIT(0)
+
+/* RK808 has a shadowed register for saving a "frozen" RTC time.
+ * When user setting "GET_TIME" to 1, the time will save in this shadowed
+ * register. If set "READSEL" to 1, user read rtc time register, actually
+ * get the time of that moment. If we need the real time, clr this bit.
+ */
+
+#define BIT_RTC_CTRL_REG_RTC_GET_TIME BIT(6)
+#define BIT_RTC_CTRL_REG_RTC_READSEL_M BIT(7)
+#define RTC_STATUS_MASK 0xFE
+
+#define SECONDS_REG_MSK 0x7F
+#define MINUTES_REG_MAK 0x7F
+#define HOURS_REG_MSK 0x3F
+#define DAYS_REG_MSK 0x3F
+#define MONTHS_REG_MSK 0x1F
+#define YEARS_REG_MSK 0xFF
+#define WEEKS_REG_MSK 0x7
+
+/* REG_SECONDS_REG through REG_YEARS_REG is how many registers? */
+
+#define NUM_TIME_REGS (REG_WEEKS - REG_SECONDS + 1)
+
+static int rk808_rtc_set(struct udevice *dev, const struct rtc_time *tm)
+{
+ u8 rtc_data[NUM_TIME_REGS];
+
+ debug("RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n",
+ tm->tm_year, tm->tm_mon, tm->tm_mday,
+ tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ rtc_data[0] = bin2bcd(tm->tm_sec);
+ rtc_data[1] = bin2bcd(tm->tm_min);
+ rtc_data[2] = bin2bcd(tm->tm_hour);
+ rtc_data[3] = bin2bcd(tm->tm_mday);
+ rtc_data[4] = bin2bcd(tm->tm_mon);
+ rtc_data[5] = bin2bcd(tm->tm_year - 2000);
+ rtc_data[6] = bin2bcd(tm->tm_wday);
+
+/* Stop RTC while updating the RTC registers */
+ pmic_clrsetbits(dev->parent, REG_RTC_CTRL, 0,
+ BIT_RTC_CTRL_REG_STOP_RTC_M);
+ pmic_write(dev->parent, REG_SECONDS, rtc_data, NUM_TIME_REGS);
+
+/* Start RTC again */
+ pmic_clrsetbits(dev->parent, REG_RTC_CTRL,
+ BIT_RTC_CTRL_REG_STOP_RTC_M, 0);
+ return 0;
+}
+
+static int rk808_rtc_get(struct udevice *dev, struct rtc_time *tm)
+{
+ u8 rtc_data[NUM_TIME_REGS];
+
+/* Force an update of the shadowed registers right now */
+ pmic_clrsetbits(dev->parent, REG_RTC_CTRL, 0,
+ BIT_RTC_CTRL_REG_RTC_GET_TIME);
+
+/*
+ * After we set the GET_TIME bit, the rtc time can't be read
+ * immediately. So we should wait up to 31.25 us, about one cycle of
+ * 32khz. If we clear the GET_TIME bit here, the time of i2c transfer
+ * certainly more than 31.25us: 16 * 2.5us at 400kHz bus frequency.
+ */
+ pmic_clrsetbits(dev->parent, REG_RTC_CTRL,
+ BIT_RTC_CTRL_REG_RTC_GET_TIME, 0);
+ pmic_read(dev->parent, REG_SECONDS, rtc_data, NUM_TIME_REGS);
+
+ tm->tm_sec = bcd2bin(rtc_data[0] & SECONDS_REG_MSK);
+ tm->tm_min = bcd2bin(rtc_data[1] & MINUTES_REG_MAK);
+ tm->tm_hour = bcd2bin(rtc_data[2] & HOURS_REG_MSK);
+ tm->tm_mday = bcd2bin(rtc_data[3] & DAYS_REG_MSK);
+ tm->tm_mon = (bcd2bin(rtc_data[4] & MONTHS_REG_MSK));
+ tm->tm_year = (bcd2bin(rtc_data[5] & YEARS_REG_MSK)) + 2000;
+ tm->tm_wday = bcd2bin(rtc_data[6] & WEEKS_REG_MSK);
+/*
+ * RK808 PMIC RTC h/w counts/has 31 days in november. This is corrected
+ * when date cmd is invoked on prompt. checks for the current day and
+ * if it is 31 November, then adjusts it to 1 December.
+ *
+ * h/w also has weeks register which counts from 0 to 7(0(sun)-6(sat)).
+ * 7 is an unknown state, reset it back to 0(sun).
+ */
+ if (tm->tm_mon == 11 && tm->tm_mday == 31) {
+ debug("correcting Nov 31st to Dec 1st (HW bug)\n");
+ tm->tm_mon += 1;
+ tm->tm_mday = 1;
+ if (tm->tm_wday == 7)
+ tm->tm_wday = 0;
+ rk808_rtc_set(dev, tm);
+ }
+
+ if (tm->tm_wday == 7) {
+ tm->tm_wday = 0;
+ rk808_rtc_set(dev, tm);
+ }
+
+ debug("RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n",
+ tm->tm_year, tm->tm_mon, tm->tm_mday,
+ tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec);
+ return 0;
+}
+
+static int rk808_rtc_reset(struct udevice *dev)
+{
+/* Not needed */
+ return 0;
+}
+
+static int rk808_rtc_init(struct udevice *dev)
+{
+ struct rtc_time tm;
+
+/* start rtc running by default, and use shadowed timer. */
+ pmic_clrsetbits(dev->parent, REG_RTC_CTRL, 0,
+ BIT_RTC_CTRL_REG_RTC_READSEL_M);
+ pmic_reg_write(dev->parent, REG_RTC_STATUS, RTC_STATUS_MASK);
+/* set init time */
+ rk808_rtc_get(dev, &tm);
+ return 0;
+}
+
+static int rk808_rtc_probe(struct udevice *dev)
+{
+ rk808_rtc_init(dev);
+ return 0;
+}
+
+static const struct rtc_ops rk808_rtc_ops = {
+ .get = rk808_rtc_get,
+ .set = rk808_rtc_set,
+ .reset = rk808_rtc_reset,
+};
+
+U_BOOT_DRIVER(rk808_rtc) = {
+ .name = "rk808_rtc",
+ .id = UCLASS_RTC,
+ .ops = &rk808_rtc_ops,
+ .probe = rk808_rtc_probe,
+};
--
2.7.4
More information about the U-Boot
mailing list