> From: joshua stein <j...@jcs.org> > Date: Wed, 7 May 2025 21:52:22 -0500 > > This is found on the XPI-3128
I'm fairly confident this is the same chip that is already supported by abcrtc(4). The registers match and the datasheet for the Abracon AB18X5 RTC that I can find has a disclaimer that says: AB18X5 series of devices are based on innovative SPOT technology, proprietary to Ambiq Micro. The compatible string you're using ("geniatech,rtc_am1805") isn't documented anywhere in the Linux. The fact that it uses "geniatech" as the vendor prefix makes me suspect that you're using a vendor device tree. We try to stick to proper upstream Linux device trees as much as possible as vendors put all sorts of crap in their device trees. That said, adding a non-standard compatible string to a driver isn't a big issue, as long as we annotate as such. Can you try whether the abcrtc(4) driver works for you once you add the appropriate compatible string? Cheers, Mark > --- > sys/arch/armv7/conf/GENERIC | 1 + > sys/dev/fdt/ambrtc.c | 252 ++++++++++++++++++++++++++++++++++++ > sys/dev/fdt/files.fdt | 5 + > 3 files changed, 258 insertions(+) > create mode 100644 sys/dev/fdt/ambrtc.c > > diff --git a/sys/arch/armv7/conf/GENERIC b/sys/arch/armv7/conf/GENERIC > index c84962ed183..994fa565976 100644 > --- a/sys/arch/armv7/conf/GENERIC > +++ b/sys/arch/armv7/conf/GENERIC > @@ -219,6 +219,7 @@ rkiic* at fdt? > iic* at rkiic? > rktemp* at fdt? > dwdog* at fdt? > +ambrtc* at iic? # Ambiq Artasie AM18X5 RTC > > # Xilinx Zynq-7000 > cad* at fdt? # Ethernet controller > diff --git a/sys/dev/fdt/ambrtc.c b/sys/dev/fdt/ambrtc.c > new file mode 100644 > index 00000000000..b5c14dc97e1 > --- /dev/null > +++ b/sys/dev/fdt/ambrtc.c > @@ -0,0 +1,252 @@ > +/* $OpenBSD$ */ > +/* > + * Ambiq Artasie AM18X5 RTC > + * Copyright (c) 2025 joshua stein <j...@jcs.org> > + * > + * Permission to use, copy, modify, and distribute this software for any > + * purpose with or without fee is hereby granted, provided that the above > + * copyright notice and this permission notice appear in all copies. > + * > + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES > + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF > + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR > + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES > + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN > + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF > + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > + */ > + > +#include <sys/param.h> > +#include <sys/systm.h> > +#include <sys/device.h> > + > +#include <machine/bus.h> > +#include <machine/fdt.h> > + > +#include <dev/i2c/i2cvar.h> > + > +#include <dev/clock_subr.h> > + > +#define AMBRTC_SECONDS_HUNDREDTHS 0x00 > +#define AMBRTC_SECONDS_HUNDREDTHS_MASK 0x0f > +#define AMBRTC_SECONDS_HUNDREDTHS_TENTHS_MASK 0xf0 > +#define AMBRTC_SECONDS_HUNDREDTHS_TENTHS_SHIFT 4 > +#define AMBRTC_SECONDS 0x01 > +#define AMBRTC_SECONDS_ONES_MASK 0x0f > +#define AMBRTC_SECONDS_TENS_MASK 0x70 > +#define AMBRTC_SECONDS_TENS_SHIFT 4 > +#define AMBRTC_MINUTES 0x02 > +#define AMBRTC_MINUTES_ONES_MASK 0x0f > +#define AMBRTC_MINUTES_TENS_MASK 0x70 > +#define AMBRTC_MINUTES_TENS_SHIFT 4 > +#define AMBRTC_HOURS 0x03 > +#define AMBRTC_HOURS_ONES_MASK 0x0f > +#define AMBRTC_HOURS_TENS_MASK 0x10 > +#define AMBRTC_HOURS_TENS_SHIFT 4 > +#define AMBRTC_HOURS_AMPM_MASK 0x20 > +#define AMBRTC_HOURS_AMPM_SHIFT 5 > +#define AMBRTC_MDAY 0x04 > +#define AMBRTC_MDAY_ONES_MASK 0x0f > +#define AMBRTC_MDAY_TENS_MASK 0x30 > +#define AMBRTC_MDAY_TENS_SHIFT 4 > +#define AMBRTC_MONTH 0x05 > +#define AMBRTC_MONTH_ONES_MASK 0x0f > +#define AMBRTC_MONTH_TENS_MASK 0x10 > +#define AMBRTC_MONTH_TENS_SHIFT 4 > +#define AMBRTC_YEAR 0x06 > +#define AMBRTC_YEAR_ONES_MASK 0x0f > +#define AMBRTC_YEAR_TENS_MASK 0xf0 > +#define AMBRTC_YEAR_TENS_SHIFT 4 > +#define AMBRTC_WDAY 0x07 > +#define AMBRTC_CONTROL1 0x10 > +#define AMBRTC_CONTROL1_WRTC_BIT 0 > +#define AMBRTC_CONTROL1_1224_BIT 6 > +#define AMBRTC_ID0 0x28 > +#define AMBRTC_ID1 0x29 > + > +struct ambrtc_softc { > + struct device sc_dev; > + i2c_tag_t sc_tag; > + i2c_addr_t sc_addr; > + > + struct todr_chip_handle sc_todr; > +}; > + > +int ambrtc_match(struct device *, void *, void *); > +void ambrtc_attach(struct device *, struct device *, void *); > +uint8_t ambrtc_read(struct ambrtc_softc *, uint8_t); > +int ambrtc_write(struct ambrtc_softc *, uint8_t, uint8_t); > +int ambrtc_clock_read(struct ambrtc_softc *sc, struct clock_ymdhms *dt); > +int ambrtc_gettime(struct todr_chip_handle *, struct timeval *); > +int ambrtc_settime(struct todr_chip_handle *, struct timeval *); > + > +const struct cfattach ambrtc_ca = { > + sizeof(struct ambrtc_softc), ambrtc_match, ambrtc_attach > +}; > + > +struct cfdriver ambrtc_cd = { > + NULL, "ambrtc", DV_DULL > +}; > + > +int > +ambrtc_match(struct device *parent, void *match, void *aux) > +{ > + struct i2c_attach_args *ia = aux; > + > + return (strcmp(ia->ia_name, "geniatech,rtc_am1805") == 0); > +} > + > +void > +ambrtc_attach(struct device *parent, struct device *self, void *aux) > +{ > + struct ambrtc_softc *sc = (struct ambrtc_softc *)self; > + struct i2c_attach_args *ia = aux; > + uint8_t val; > + > + sc->sc_tag = ia->ia_tag; > + sc->sc_addr = ia->ia_addr; > + > + val = ambrtc_read(sc, AMBRTC_ID0); > + if (val != 0x18) { > + printf("; unknown device\n"); > + return; > + } > + > + val = ambrtc_read(sc, AMBRTC_ID1); > + printf(": AM18%02X", val); > + > + /* put in 24 hour mode and allow updates */ > + val = ambrtc_read(sc, AMBRTC_CONTROL1); > + val |= (1 << AMBRTC_CONTROL1_1224_BIT) | > + (1 << AMBRTC_CONTROL1_WRTC_BIT); > + ambrtc_write(sc, AMBRTC_CONTROL1, val); > + > + printf("\n"); > + > + sc->sc_todr.cookie = sc; > + sc->sc_todr.todr_gettime = ambrtc_gettime; > + sc->sc_todr.todr_settime = ambrtc_settime; > + sc->sc_todr.todr_quality = 0; > + todr_attach(&sc->sc_todr); > +} > + > +uint8_t > +ambrtc_read(struct ambrtc_softc *sc, uint8_t reg) > +{ > + uint8_t cmd = reg, val; > + int error; > + > + iic_acquire_bus(sc->sc_tag, I2C_F_POLL); > + error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, > + &cmd, sizeof(cmd), &val, sizeof(val), I2C_F_POLL); > + iic_release_bus(sc->sc_tag, I2C_F_POLL); > + > + if (error) { > + printf("%s: failed reading register 0x%02x: %d\n", > + sc->sc_dev.dv_xname, reg, error); > + val = 0xff; > + } > + > + return val; > +} > + > +int > +ambrtc_write(struct ambrtc_softc *sc, uint8_t reg, uint8_t val) > +{ > + uint8_t cmd = reg; > + int error; > + > + iic_acquire_bus(sc->sc_tag, I2C_F_POLL); > + error = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr, > + &cmd, sizeof(cmd), &val, sizeof(val), I2C_F_POLL); > + iic_release_bus(sc->sc_tag, I2C_F_POLL); > + > + if (error) { > + printf("%s: failed writing register 0x%02x: %d\n", > + sc->sc_dev.dv_xname, reg, error); > + return 1; > + } > + > + return 0; > +} > + > +int > +ambrtc_clock_read(struct ambrtc_softc *sc, struct clock_ymdhms *dt) > +{ > + uint8_t val; > + > + val = ambrtc_read(sc, AMBRTC_YEAR); > + if (val == 0xff) > + return EINVAL; > + dt->dt_year = 2000 + FROMBCD(val); > + > + val = ambrtc_read(sc, AMBRTC_MONTH); > + if (val == 0xff) > + return EINVAL; > + dt->dt_mon = FROMBCD(val); > + > + val = ambrtc_read(sc, AMBRTC_MDAY); > + if (val == 0xff) > + return EINVAL; > + dt->dt_day = FROMBCD(val); > + > + val = ambrtc_read(sc, AMBRTC_HOURS); > + if (val == 0xff) > + return EINVAL; > + dt->dt_hour = FROMBCD(val); > + > + val = ambrtc_read(sc, AMBRTC_MINUTES); > + if (val == 0xff) > + return EINVAL; > + dt->dt_min = FROMBCD(val); > + > + val = ambrtc_read(sc, AMBRTC_SECONDS); > + if (val == 0xff) > + return EINVAL; > + dt->dt_sec = FROMBCD(val); > + > + return 0; > +} > + > +int > +ambrtc_clock_write(struct ambrtc_softc *sc, struct clock_ymdhms *dt) > +{ > + if (ambrtc_write(sc, AMBRTC_YEAR, TOBCD(dt->dt_year % 1000)) != 0) > + return EINVAL; > + if (ambrtc_write(sc, AMBRTC_MONTH, TOBCD(dt->dt_mon)) != 0) > + return EINVAL; > + if (ambrtc_write(sc, AMBRTC_MDAY, TOBCD(dt->dt_day)) != 0) > + return EINVAL; > + if (ambrtc_write(sc, AMBRTC_HOURS, TOBCD(dt->dt_hour)) != 0) > + return EINVAL; > + if (ambrtc_write(sc, AMBRTC_MINUTES, TOBCD(dt->dt_min)) != 0) > + return EINVAL; > + > + return 0; > +} > + > +int > +ambrtc_gettime(struct todr_chip_handle *handle, struct timeval *tv) > +{ > + struct ambrtc_softc *sc = handle->cookie; > + struct clock_ymdhms dt; > + > + if (ambrtc_clock_read(sc, &dt) != 0) > + return EINVAL; > + > + tv->tv_sec = clock_ymdhms_to_secs(&dt); > + tv->tv_usec = 0; > + > + return 0; > +} > + > +int > +ambrtc_settime(struct todr_chip_handle *handle, struct timeval *tv) > +{ > + struct ambrtc_softc *sc = handle->cookie; > + struct clock_ymdhms dt; > + > + clock_secs_to_ymdhms(tv->tv_sec, &dt); > + > + return ambrtc_clock_write(sc, &dt); > +} > diff --git a/sys/dev/fdt/files.fdt b/sys/dev/fdt/files.fdt > index 3da5446db9a..8d21a7e56dd 100644 > --- a/sys/dev/fdt/files.fdt > +++ b/sys/dev/fdt/files.fdt > @@ -797,3 +797,8 @@ file dev/fdt/qcsdam.c qcsdam > device tipd > attach tipd at i2c > file dev/fdt/tipd.c tipd > + > +# Ambiq Artasie AM18X5 RTC > +device ambrtc > +attach ambrtc at i2c > +file dev/fdt/ambrtc.c ambrtc > -- > 2.47.1 > >