> 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
> 
> 

Reply via email to