Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/dev/i2c rkpmic: add RTC support; register w/ todr(9)
details: https://anonhg.NetBSD.org/src/rev/399e0509305f
branches: trunk
changeset: 1003505:399e0509305f
user: tnn <tnn%NetBSD.org@localhost>
date: Wed Sep 18 14:07:38 2019 +0000
description:
rkpmic: add RTC support; register w/ todr(9)
diffstat:
sys/dev/i2c/rkpmic.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 116 insertions(+), 6 deletions(-)
diffs (190 lines):
diff -r b64735ce05db -r 399e0509305f sys/dev/i2c/rkpmic.c
--- a/sys/dev/i2c/rkpmic.c Wed Sep 18 12:49:34 2019 +0000
+++ b/sys/dev/i2c/rkpmic.c Wed Sep 18 14:07:38 2019 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: rkpmic.c,v 1.3 2019/07/03 10:21:41 jmcneill Exp $ */
+/* $NetBSD: rkpmic.c,v 1.4 2019/09/18 14:07:38 tnn Exp $ */
/*-
* Copyright (c) 2018 Jared McNeill <jmcneill%invisible.ca@localhost>
@@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rkpmic.c,v 1.3 2019/07/03 10:21:41 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rkpmic.c,v 1.4 2019/09/18 14:07:38 tnn Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -37,10 +37,33 @@
#include <sys/bus.h>
#include <sys/kmem.h>
+#include <dev/clock_subr.h>
+
#include <dev/i2c/i2cvar.h>
#include <dev/fdt/fdtvar.h>
+#define SECONDS_REG 0x00
+#define MINUTES_REG 0x01
+#define HOURS_REG 0x02
+#define DAYS_REG 0x03
+#define MONTHS_REG 0x04
+#define YEARS_REG 0x05
+#define WEEKS_REG 0x06
+
+#define RTC_CTRL_REG 0x10
+#define RTC_CTRL_READSEL __BIT(7)
+#define RTC_CTRL_GET_TIME __BIT(6)
+#define RTC_CTRL_SET_32_COUNTER __BIT(5)
+#define RTC_CTRL_TEST_MODE __BIT(4)
+#define RTC_CTRL_AMPM_MODE __BIT(3)
+#define RTC_CTRL_AUTO_COMP __BIT(2)
+#define RTC_CTRL_ROUND_30S __BIT(1)
+#define RTC_CTRL_STOP_RTC __BIT(0)
+
+#define RTC_INT_REG 0x12
+#define RTC_COMP_LSB_REG 0x13
+#define RTC_COMP_MSB_REG 0x14
#define CHIP_NAME_REG 0x17
#define CHIP_VER_REG 0x18
@@ -169,7 +192,7 @@
i2c_tag_t sc_i2c;
i2c_addr_t sc_addr;
int sc_phandle;
-
+ struct todr_chip_handle sc_todr;
struct rkpmic_config *sc_conf;
};
@@ -198,7 +221,7 @@
error = iic_smbus_read_byte(sc->sc_i2c, sc->sc_addr, reg, &val, flags);
if (error != 0)
- aprint_error_dev(sc->sc_dev, "error reading reg %#x: %d\n", reg, error);
+ device_printf(sc->sc_dev, "error reading reg %#x: %d\n", reg, error);
return val;
}
@@ -210,7 +233,7 @@
error = iic_smbus_write_byte(sc->sc_i2c, sc->sc_addr, reg, val, flags);
if (error != 0)
- aprint_error_dev(sc->sc_dev, "error writing reg %#x: %d\n", reg, error);
+ device_printf(sc->sc_dev, "error writing reg %#x: %d\n", reg, error);
}
#define I2C_READ(sc, reg) rkpmic_read((sc), (reg), I2C_F_POLL)
@@ -219,6 +242,82 @@
#define I2C_UNLOCK(sc) iic_release_bus((sc)->sc_i2c, I2C_F_POLL)
static int
+rkpmic_todr_settime(todr_chip_handle_t ch, struct clock_ymdhms *dt)
+{
+ struct rkpmic_softc * const sc = ch->cookie;
+ uint8_t val;
+
+ if (dt->dt_year < 2000 || dt->dt_year >= 2100) {
+ device_printf(sc->sc_dev, "year out of range\n");
+ return EINVAL;
+ }
+
+ if (I2C_LOCK(sc))
+ return EBUSY;
+
+ val = I2C_READ(sc, RTC_CTRL_REG);
+ I2C_WRITE(sc, RTC_CTRL_REG, val | RTC_CTRL_STOP_RTC);
+ I2C_WRITE(sc, SECONDS_REG, bintobcd(dt->dt_sec));
+ I2C_WRITE(sc, MINUTES_REG, bintobcd(dt->dt_min));
+ I2C_WRITE(sc, HOURS_REG, bintobcd(dt->dt_hour));
+ I2C_WRITE(sc, DAYS_REG, bintobcd(dt->dt_day));
+ I2C_WRITE(sc, MONTHS_REG, bintobcd(dt->dt_mon));
+ I2C_WRITE(sc, YEARS_REG, bintobcd(dt->dt_year % 100));
+ I2C_WRITE(sc, WEEKS_REG, bintobcd(dt->dt_wday == 0 ? 7 : dt->dt_wday));
+ I2C_WRITE(sc, RTC_CTRL_REG, val);
+ I2C_UNLOCK(sc);
+
+ return 0;
+}
+
+static int
+rkpmic_todr_gettime(todr_chip_handle_t ch, struct clock_ymdhms *dt)
+{
+ struct rkpmic_softc * const sc = ch->cookie;
+ uint8_t val;
+
+ if (I2C_LOCK(sc))
+ return EBUSY;
+
+ val = I2C_READ(sc, RTC_CTRL_REG);
+ I2C_WRITE(sc, RTC_CTRL_REG, val | RTC_CTRL_GET_TIME | RTC_CTRL_READSEL);
+ delay(1); /* need to wait 1/32768 seconds for shadow regs to latch */
+ I2C_WRITE(sc, RTC_CTRL_REG, val | RTC_CTRL_READSEL);
+ dt->dt_sec = bcdtobin(I2C_READ(sc, SECONDS_REG));
+ dt->dt_min = bcdtobin(I2C_READ(sc, MINUTES_REG));
+ dt->dt_hour = bcdtobin(I2C_READ(sc, HOURS_REG));
+ dt->dt_day = bcdtobin(I2C_READ(sc, DAYS_REG));
+ dt->dt_mon = bcdtobin(I2C_READ(sc, MONTHS_REG));
+ dt->dt_year = 2000 + bcdtobin(I2C_READ(sc, YEARS_REG));
+ dt->dt_wday = bcdtobin(I2C_READ(sc, WEEKS_REG));
+ if (dt->dt_wday == 7)
+ dt->dt_wday = 0;
+ I2C_WRITE(sc, RTC_CTRL_REG, val);
+ I2C_UNLOCK(sc);
+
+ /*
+ * RK808 has a hw bug which makes the 31st of November a valid day.
+ * If we detect the 31st of November we skip ahead one day.
+ * If the system has been turned off during the crossover the clock
+ * will have lost a day. No easy way to detect this. Oh well.
+ */
+ if (dt->dt_mon == 11 && dt->dt_day == 31) {
+ dt->dt_day--;
+ clock_secs_to_ymdhms(clock_ymdhms_to_secs(dt) + 86400, dt);
+ rkpmic_todr_settime(ch, dt);
+ }
+
+#if 0
+ device_printf(sc->sc_dev, "%04" PRIu64 "-%02u-%02u (%u) %02u:%02u:%02u\n",
+ dt->dt_year, dt->dt_mon, dt->dt_day, dt->dt_wday,
+ dt->dt_hour, dt->dt_min, dt->dt_sec);
+#endif
+
+ return 0;
+}
+
+
+static int
rkpmic_match(device_t parent, cfdata_t match, void *aux)
{
struct i2c_attach_args *ia = aux;
@@ -248,15 +347,26 @@
sc->sc_phandle = ia->ia_cookie;
sc->sc_conf = (void *)entry->data;
+ memset(&sc->sc_todr, 0, sizeof(sc->sc_todr));
+ sc->sc_todr.cookie = sc;
+ sc->sc_todr.todr_gettime_ymdhms = rkpmic_todr_gettime;
+ sc->sc_todr.todr_settime_ymdhms = rkpmic_todr_settime;
+
aprint_naive("\n");
- aprint_normal(": %s Power Management IC\n", sc->sc_conf->name);
+ aprint_normal(": %s Power Management and Real Time Clock IC\n", sc->sc_conf->name);
I2C_LOCK(sc);
chipid = I2C_READ(sc, CHIP_NAME_REG) << 8;
chipid |= I2C_READ(sc, CHIP_VER_REG);
aprint_debug_dev(self, "Chip ID 0x%04x\n", chipid);
+ I2C_WRITE(sc, RTC_CTRL_REG, 0x0);
+ I2C_WRITE(sc, RTC_INT_REG, 0);
+ I2C_WRITE(sc, RTC_COMP_LSB_REG, 0);
+ I2C_WRITE(sc, RTC_COMP_MSB_REG, 0);
I2C_UNLOCK(sc);
+ fdtbus_todr_attach(self, sc->sc_phandle, &sc->sc_todr);
+
regulators = of_find_firstchild_byname(sc->sc_phandle, "regulators");
if (regulators < 0)
return;
Home |
Main Index |
Thread Index |
Old Index