From ebbbade523ef9055672aa4e81615aaec8377f8f3 Mon Sep 17 00:00:00 2001 From: patrick Date: Tue, 8 Nov 2022 19:47:05 +0000 Subject: [PATCH] Add qcrtc(4), a driver for the RTC found on Qualcomm PMICs. Unfortunately on the Lenovo x13s it does not seem to contain the offset from 1970. Also we are not allowed to write to the RTC. I was told that the offset I need to calculate the actual date is sorted in an UEFI variable, which can be accessed over a secure channel. So as long as we don't have that channel, this driver is useless. Good start though. ok kettenis@ --- sys/dev/fdt/qcrtc.c | 125 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 sys/dev/fdt/qcrtc.c diff --git a/sys/dev/fdt/qcrtc.c b/sys/dev/fdt/qcrtc.c new file mode 100644 index 00000000000..830181ebe8d --- /dev/null +++ b/sys/dev/fdt/qcrtc.c @@ -0,0 +1,125 @@ +/* $OpenBSD: qcrtc.c,v 1.1 2022/11/08 19:47:05 patrick Exp $ */ +/* + * Copyright (c) 2022 Patrick Wildt + * + * 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 +#include +#include + +#include +#include + +#include + +#include +#include + +#include + +/* Registers. */ +#define RTC_WRITE 0x40 +#define RTC_CTRL 0x46 +#define RTC_CTRL_EN (1U << 7) +#define RTC_READ 0x48 + +struct qcrtc_softc { + struct device sc_dev; + int sc_node; + spmi_tag_t sc_tag; + int8_t sc_sid; + uint16_t sc_addr; + + struct todr_chip_handle sc_todr; +}; + +int qcrtc_match(struct device *, void *, void *); +void qcrtc_attach(struct device *, struct device *, void *); + +const struct cfattach qcrtc_ca = { + sizeof (struct qcrtc_softc), qcrtc_match, qcrtc_attach +}; + +struct cfdriver qcrtc_cd = { + NULL, "qcrtc", DV_DULL +}; + +int qcrtc_gettime(struct todr_chip_handle *, struct timeval *); +int qcrtc_settime(struct todr_chip_handle *, struct timeval *); + +void qcrtc_tick(void *); + +int +qcrtc_match(struct device *parent, void *match, void *aux) +{ + struct spmi_attach_args *saa = aux; + + return OF_is_compatible(saa->sa_node, "qcom,pmk8350-rtc"); +} + +void +qcrtc_attach(struct device *parent, struct device *self, void *aux) +{ + struct qcrtc_softc *sc = (struct qcrtc_softc *)self; + struct spmi_attach_args *saa = aux; + uint32_t reg[2]; + + if (OF_getpropintarray(saa->sa_node, "reg", + reg, sizeof(reg)) != sizeof(reg)) { + printf(": can't find registers\n"); + return; + } + + sc->sc_node = saa->sa_node; + sc->sc_tag = saa->sa_tag; + sc->sc_sid = saa->sa_sid; + sc->sc_addr = reg[0]; + + printf("\n"); + + sc->sc_todr.cookie = sc; + sc->sc_todr.todr_gettime = qcrtc_gettime; + sc->sc_todr.todr_settime = qcrtc_settime; + sc->sc_todr.todr_quality = 0; + todr_attach(&sc->sc_todr); +} + +int +qcrtc_gettime(struct todr_chip_handle *handle, struct timeval *tv) +{ + struct qcrtc_softc *sc = handle->cookie; + uint32_t reg; + int error; + + error = spmi_cmd_read(sc->sc_tag, sc->sc_sid, SPMI_CMD_EXT_READL, + sc->sc_addr + RTC_READ, ®, sizeof(reg)); + if (error) { + printf("%s: error reading RTC\n", sc->sc_dev.dv_xname); + return error; + } + + tv->tv_sec = reg; + tv->tv_usec = 0; + + /* We need to offset. */ + return EIO; +} + +int +qcrtc_settime(struct todr_chip_handle *handle, struct timeval *tv) +{ + /* XXX: We can't set the time for now, hardware reasons. */ + return EPERM; +} -- 2.20.1