Module Name: src Committed By: jmcneill Date: Fri Nov 1 09:49:55 UTC 2019
Modified Files: src/sys/dev/i2c: twl4030.c Log Message: Add RTC support To generate a diff of this commit: cvs rdiff -u -r1.1 -r1.2 src/sys/dev/i2c/twl4030.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/i2c/twl4030.c diff -u src/sys/dev/i2c/twl4030.c:1.1 src/sys/dev/i2c/twl4030.c:1.2 --- src/sys/dev/i2c/twl4030.c:1.1 Wed Oct 30 21:38:28 2019 +++ src/sys/dev/i2c/twl4030.c Fri Nov 1 09:49:55 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: twl4030.c,v 1.1 2019/10/30 21:38:28 jmcneill Exp $ */ +/* $NetBSD: twl4030.c,v 1.2 2019/11/01 09:49:55 jmcneill Exp $ */ /*- * Copyright (c) 2019 Jared McNeill <jmcne...@invisible.ca> @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: twl4030.c,v 1.1 2019/10/30 21:38:28 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: twl4030.c,v 1.2 2019/11/01 09:49:55 jmcneill Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -50,6 +50,12 @@ __KERNEL_RCSID(0, "$NetBSD: twl4030.c,v #define ADDR_AUX 0x02 #define ADDR_POWER 0x03 +/* INTBR registers */ +#define IDCODE_7_0 0x85 +#define IDCODE_15_8 0x86 +#define IDCODE_23_16 0x87 +#define IDCODE_31_24 0x88 + /* GPIO registers */ #define GPIOBASE 0x98 #define GPIODATAIN(pin) (GPIOBASE + 0x00 + (pin) / 8) @@ -60,6 +66,18 @@ __KERNEL_RCSID(0, "$NetBSD: twl4030.c,v #define GPIOPUPDCTR(pin) (GPIOBASE + 0x13 + (n) / 4) #define PUPD_BITS(pin) __BITS((pin) % 4 + 1, (pin) % 4) +/* POWER registers */ +#define SECONDS_REG 0x1c +#define MINUTES_REG 0x1d +#define HOURS_REG 0x1e +#define DAYS_REG 0x1f +#define MONTHS_REG 0x20 +#define YEARS_REG 0x21 +#define WEEKS_REG 0x22 +#define RTC_CTRL_REG 0x29 +#define GET_TIME __BIT(6) +#define STOP_RTC __BIT(0) + struct twl_softc { device_t sc_dev; i2c_tag_t sc_i2c; @@ -67,6 +85,8 @@ struct twl_softc { int sc_phandle; int sc_npins; + + struct todr_chip_handle sc_todr; }; struct twl_pin { @@ -81,6 +101,7 @@ static const struct device_compatible_en { NULL, 0 } }; +static const char * const rtc_compatible[] = { "ti,twl4030-rtc", NULL }; static const char * const gpio_compatible[] = { "ti,twl4030-gpio", NULL }; static uint8_t @@ -118,6 +139,70 @@ twl_write(struct twl_softc *sc, uint8_t #define INT_READ(sc, reg) twl_read((sc), ADDR_INT, (reg), I2C_F_POLL) #define INT_WRITE(sc, reg, val) twl_write((sc), ADDR_INT, (reg), (val), I2C_F_POLL) +#define POWER_READ(sc, reg) twl_read((sc), ADDR_POWER, (reg), I2C_F_POLL) +#define POWER_WRITE(sc, reg, val) twl_write((sc), ADDR_POWER, (reg), (val), I2C_F_POLL) + +static void +twl_rtc_enable(struct twl_softc *sc, bool onoff) +{ + uint8_t rtc_ctrl; + + rtc_ctrl = POWER_READ(sc, RTC_CTRL_REG); + if (onoff) + rtc_ctrl |= STOP_RTC; /* 1: RTC is running */ + else + rtc_ctrl &= ~STOP_RTC; /* 0: RTC is frozen */ + POWER_WRITE(sc, RTC_CTRL_REG, rtc_ctrl); +} + +static int +twl_rtc_gettime(todr_chip_handle_t tch, struct clock_ymdhms *dt) +{ + struct twl_softc *sc = tch->cookie; + uint8_t seconds_reg, minutes_reg, hours_reg, + days_reg, months_reg, years_reg, weeks_reg; + + iic_acquire_bus(sc->sc_i2c, I2C_F_POLL); + seconds_reg = POWER_READ(sc, SECONDS_REG); + minutes_reg = POWER_READ(sc, MINUTES_REG); + hours_reg = POWER_READ(sc, HOURS_REG); + days_reg = POWER_READ(sc, DAYS_REG); + months_reg = POWER_READ(sc, MONTHS_REG); + years_reg = POWER_READ(sc, YEARS_REG); + weeks_reg = POWER_READ(sc, WEEKS_REG); + iic_release_bus(sc->sc_i2c, I2C_F_POLL); + + dt->dt_sec = bcdtobin(seconds_reg); + dt->dt_min = bcdtobin(minutes_reg); + dt->dt_hour = bcdtobin(hours_reg); + dt->dt_day = bcdtobin(days_reg); + dt->dt_mon = bcdtobin(months_reg); + dt->dt_year = bcdtobin(years_reg) + 2000; + dt->dt_wday = bcdtobin(weeks_reg); + + return 0; +} + +static int +twl_rtc_settime(todr_chip_handle_t tch, struct clock_ymdhms *dt) +{ + struct twl_softc *sc = tch->cookie; + + iic_acquire_bus(sc->sc_i2c, I2C_F_POLL); + twl_rtc_enable(sc, false); + POWER_WRITE(sc, SECONDS_REG, bintobcd(dt->dt_sec)); + POWER_WRITE(sc, MINUTES_REG, bintobcd(dt->dt_min)); + POWER_WRITE(sc, HOURS_REG, bintobcd(dt->dt_hour)); + POWER_WRITE(sc, DAYS_REG, bintobcd(dt->dt_day)); + POWER_WRITE(sc, MONTHS_REG, bintobcd(dt->dt_mon)); + POWER_WRITE(sc, YEARS_REG, bintobcd(dt->dt_year % 100)); + POWER_WRITE(sc, WEEKS_REG, bintobcd(dt->dt_wday)); + twl_rtc_enable(sc, true); + iic_release_bus(sc->sc_i2c, I2C_F_POLL); + + return 0; +} + static int twl_gpio_config(struct twl_softc *sc, int pin, int flags) { @@ -235,6 +320,19 @@ static struct fdtbus_gpio_controller_fun }; static void +twl_rtc_attach(struct twl_softc *sc, const int phandle) +{ + iic_acquire_bus(sc->sc_i2c, I2C_F_POLL); + twl_rtc_enable(sc, true); + iic_release_bus(sc->sc_i2c, I2C_F_POLL); + + sc->sc_todr.todr_gettime_ymdhms = twl_rtc_gettime; + sc->sc_todr.todr_settime_ymdhms = twl_rtc_settime; + sc->sc_todr.cookie = sc; + fdtbus_todr_attach(sc->sc_dev, phandle, &sc->sc_todr); +} + +static void twl_gpio_attach(struct twl_softc *sc, const int phandle) { fdtbus_register_gpio_controller(sc->sc_dev, phandle, &twl_gpio_funcs); @@ -257,6 +355,7 @@ twl_attach(device_t parent, device_t sel { struct twl_softc * const sc = device_private(self); struct i2c_attach_args *ia = aux; + uint32_t idcode; int child; sc->sc_dev = self; @@ -272,9 +371,20 @@ twl_attach(device_t parent, device_t sel if (of_match_compatible(child, gpio_compatible)) { aprint_normal(", GPIO"); twl_gpio_attach(sc, child); + } else if (of_match_compatible(child, rtc_compatible)) { + aprint_normal(", RTC"); + twl_rtc_attach(sc, child); } } - aprint_normal("\n"); + + I2C_LOCK(sc); + idcode = INT_READ(sc, IDCODE_7_0); + idcode |= (uint32_t)INT_READ(sc, IDCODE_15_8) << 8; + idcode |= (uint32_t)INT_READ(sc, IDCODE_23_16) << 16; + idcode |= (uint32_t)INT_READ(sc, IDCODE_31_24) << 24; + I2C_UNLOCK(sc); + + aprint_normal(", IDCODE 0x%08x\n", idcode); } CFATTACH_DECL_NEW(twl, sizeof(struct twl_softc),