1*6e54367aSthorpej /* $NetBSD: exynos_rtc.c,v 1.4 2021/01/27 03:10:19 thorpej Exp $ */
201323977Smarty
301323977Smarty /*-
401323977Smarty * Copyright (c) 2015 The NetBSD Foundation, Inc.
501323977Smarty * All rights reserved.
601323977Smarty *
701323977Smarty * This code is derived from software contributed to The NetBSD Foundation
801323977Smarty * by Marty Fouts
901323977Smarty *
1001323977Smarty * Redistribution and use in source and binary forms, with or without
1101323977Smarty * modification, are permitted provided that the following conditions
1201323977Smarty * are met:
1301323977Smarty * 1. Redistributions of source code must retain the above copyright
1401323977Smarty * notice, this list of conditions and the following disclaimer.
1501323977Smarty * 2. Redistributions in binary form must reproduce the above copyright
1601323977Smarty * notice, this list of conditions and the following disclaimer in the
1701323977Smarty * documentation and/or other materials provided with the distribution.
1801323977Smarty *
1901323977Smarty * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2001323977Smarty * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2101323977Smarty * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2201323977Smarty * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2301323977Smarty * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2401323977Smarty * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2501323977Smarty * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2601323977Smarty * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2701323977Smarty * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2801323977Smarty * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2901323977Smarty * POSSIBILITY OF SUCH DAMAGE.
3001323977Smarty */
3101323977Smarty
3201323977Smarty #include "opt_exynos.h"
3301323977Smarty #include "opt_arm_debug.h"
3401323977Smarty #include "gpio.h"
3501323977Smarty
3601323977Smarty #include <sys/cdefs.h>
37*6e54367aSthorpej __KERNEL_RCSID(1, "$NetBSD: exynos_rtc.c,v 1.4 2021/01/27 03:10:19 thorpej Exp $");
3801323977Smarty
3901323977Smarty #include <sys/param.h>
4001323977Smarty #include <sys/bus.h>
4101323977Smarty #include <sys/device.h>
4201323977Smarty #include <sys/intr.h>
4301323977Smarty #include <sys/systm.h>
4401323977Smarty #include <sys/kernel.h>
4501323977Smarty #include <sys/kmem.h>
4601323977Smarty
4701323977Smarty #include <dev/clock_subr.h>
4801323977Smarty
4901323977Smarty #include <arm/samsung/exynos_reg.h>
5001323977Smarty #include <arm/samsung/exynos_intr.h>
5101323977Smarty
5201323977Smarty #include <dev/fdt/fdtvar.h>
5301323977Smarty
5401323977Smarty struct exynos_rtc_softc {
5501323977Smarty device_t sc_dev;
5601323977Smarty bus_space_tag_t sc_bst;
5701323977Smarty bus_space_handle_t sc_bsh;
5801323977Smarty
5901323977Smarty struct todr_chip_handle sc_todr;
6001323977Smarty };
6101323977Smarty
6201323977Smarty static int exynos_rtc_match(device_t, cfdata_t, void *);
6301323977Smarty static void exynos_rtc_attach(device_t, device_t, void *);
6401323977Smarty
6501323977Smarty static int exynos_rtc_gettime(todr_chip_handle_t, struct timeval *);
6601323977Smarty static int exynos_rtc_settime(todr_chip_handle_t, struct timeval *);
6701323977Smarty
6801323977Smarty CFATTACH_DECL_NEW(exynos_rtc, sizeof(struct exynos_rtc_softc),
6901323977Smarty exynos_rtc_match, exynos_rtc_attach, NULL, NULL);
7001323977Smarty
7101323977Smarty #define RTC_READ(sc, reg) \
7201323977Smarty bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
7301323977Smarty #define RTC_WRITE(sc, reg, val) \
7401323977Smarty bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
7501323977Smarty
76*6e54367aSthorpej static const struct device_compatible_entry compat_data[] = {
77*6e54367aSthorpej { .compat = "samsung,s3c6410-rtc" },
78*6e54367aSthorpej DEVICE_COMPAT_EOL
79*6e54367aSthorpej };
80*6e54367aSthorpej
8101323977Smarty static int
exynos_rtc_match(device_t parent,cfdata_t cf,void * aux)8201323977Smarty exynos_rtc_match(device_t parent, cfdata_t cf, void *aux)
8301323977Smarty {
8401323977Smarty struct fdt_attach_args * const faa = aux;
85*6e54367aSthorpej
86*6e54367aSthorpej return of_compatible_match(faa->faa_phandle, compat_data);
8701323977Smarty }
8801323977Smarty
8901323977Smarty static void
exynos_rtc_attach(device_t parent,device_t self,void * aux)9001323977Smarty exynos_rtc_attach(device_t parent, device_t self, void *aux)
9101323977Smarty {
9201323977Smarty struct exynos_rtc_softc * const sc
9301323977Smarty = kmem_zalloc(sizeof(*sc), KM_SLEEP);
9401323977Smarty struct fdt_attach_args * const faa = aux;
9501323977Smarty bus_addr_t addr;
9601323977Smarty bus_size_t size;
9701323977Smarty int error;
9801323977Smarty
9901323977Smarty if (fdtbus_get_reg(faa->faa_phandle, 0, &addr, &size) != 0) {
10001323977Smarty aprint_error(": couldn't get registers\n");
10101323977Smarty return;
10201323977Smarty }
10301323977Smarty
10401323977Smarty aprint_normal(" @ 0x%08x", (uint)addr);
10501323977Smarty sc->sc_dev = self;
10601323977Smarty sc->sc_bst = faa->faa_bst;
10701323977Smarty error = bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh);
10801323977Smarty if (error) {
109d3f45d9fSskrll aprint_error(": couldn't map %#" PRIxBUSADDR ": %d",
110d3f45d9fSskrll addr, error);
11101323977Smarty return;
11201323977Smarty }
11301323977Smarty
11401323977Smarty aprint_naive("\n");
11501323977Smarty aprint_normal(": RTC\n");
11601323977Smarty
11701323977Smarty sc->sc_todr.todr_gettime = exynos_rtc_gettime;
11801323977Smarty sc->sc_todr.todr_settime = exynos_rtc_settime;
11901323977Smarty sc->sc_todr.cookie = sc;
12001323977Smarty todr_attach(&sc->sc_todr);
12101323977Smarty
12201323977Smarty }
12301323977Smarty
12401323977Smarty static int
exynos_rtc_gettime(todr_chip_handle_t tch,struct timeval * tv)12501323977Smarty exynos_rtc_gettime(todr_chip_handle_t tch, struct timeval *tv)
12601323977Smarty {
12701323977Smarty struct exynos_rtc_softc * const sc = tch->cookie;
12801323977Smarty
12901323977Smarty tv->tv_sec = RTC_READ(sc, EXYNOS5_RTC_OFFSET);
13001323977Smarty tv->tv_usec = 0;
13101323977Smarty
13201323977Smarty return 0;
13301323977Smarty }
13401323977Smarty
13501323977Smarty static int
exynos_rtc_settime(todr_chip_handle_t tch,struct timeval * tv)13601323977Smarty exynos_rtc_settime(todr_chip_handle_t tch, struct timeval *tv)
13701323977Smarty {
13801323977Smarty struct exynos_rtc_softc * const sc = tch->cookie;
13901323977Smarty int retry = 500;
14001323977Smarty
14101323977Smarty while (--retry > 0) {
14201323977Smarty if (!RTC_READ(sc, EXYNOS5_RTC_OFFSET))
14301323977Smarty break;
14401323977Smarty delay(1);
14501323977Smarty }
14601323977Smarty if (retry == 0) {
14701323977Smarty device_printf(sc->sc_dev, "RTC write failed (BUSY)\n");
14801323977Smarty return ETIMEDOUT;
14901323977Smarty }
15001323977Smarty
15101323977Smarty RTC_WRITE(sc, EXYNOS5_RTC_OFFSET, tv->tv_sec);
15201323977Smarty
15301323977Smarty return 0;
15401323977Smarty }
155