Home | History | Annotate | Line # | Download | only in ic
msm6242b.c revision 1.3.22.1
      1  1.3.22.1   martin /*      $NetBSD: msm6242b.c,v 1.3.22.1 2019/04/07 10:55:24 martin Exp $ */
      2       1.1  rkujawa 
      3       1.1  rkujawa /*-
      4       1.1  rkujawa  * Copyright (c) 2012 The NetBSD Foundation, Inc.
      5       1.1  rkujawa  * All rights reserved.
      6       1.1  rkujawa  *
      7       1.1  rkujawa  * This code is derived from software contributed to The NetBSD Foundation
      8       1.1  rkujawa  * by Radoslaw Kujawa.
      9       1.1  rkujawa  *
     10       1.1  rkujawa  * Redistribution and use in source and binary forms, with or without
     11       1.1  rkujawa  * modification, are permitted provided that the following conditions
     12       1.1  rkujawa  * are met:
     13       1.1  rkujawa  * 1. Redistributions of source code must retain the above copyright
     14       1.1  rkujawa  *    notice, this list of conditions and the following disclaimer.
     15       1.1  rkujawa  * 2. Redistributions in binary form must reproduce the above copyright
     16       1.1  rkujawa  *    notice, this list of conditions and the following disclaimer in the
     17       1.1  rkujawa  *    documentation and/or other materials provided with the distribution.
     18       1.1  rkujawa  *
     19       1.1  rkujawa  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20       1.1  rkujawa  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21       1.1  rkujawa  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22       1.1  rkujawa  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23       1.1  rkujawa  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24       1.1  rkujawa  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25       1.1  rkujawa  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26       1.1  rkujawa  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27       1.1  rkujawa  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28       1.1  rkujawa  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29       1.1  rkujawa  * POSSIBILITY OF SUCH DAMAGE.
     30       1.1  rkujawa  */
     31       1.1  rkujawa 
     32       1.1  rkujawa #include <sys/cdefs.h>
     33  1.3.22.1   martin __KERNEL_RCSID(0, "$NetBSD: msm6242b.c,v 1.3.22.1 2019/04/07 10:55:24 martin Exp $");
     34       1.2  rkujawa 
     35       1.2  rkujawa /*
     36       1.2  rkujawa  * Driver for OKI MSM6242B Real Time Clock. Somewhat based on an ancient, amiga
     37       1.2  rkujawa  * specifc a2kbbc driver (which was turned into frontend to this driver).
     38       1.2  rkujawa  */
     39       1.1  rkujawa 
     40       1.1  rkujawa #include <sys/param.h>
     41       1.1  rkujawa #include <sys/device.h>
     42       1.1  rkujawa #include <sys/bus.h>
     43       1.1  rkujawa 
     44       1.1  rkujawa #include <dev/clock_subr.h>
     45       1.1  rkujawa 
     46       1.1  rkujawa #include <dev/ic/msm6242bvar.h>
     47       1.1  rkujawa #include <dev/ic/msm6242breg.h>
     48       1.1  rkujawa 
     49       1.1  rkujawa /* #define MSM6242B_DEBUG 1 */
     50       1.1  rkujawa 
     51       1.1  rkujawa static int msm6242b_gettime_ymdhms(todr_chip_handle_t, struct clock_ymdhms *);
     52       1.1  rkujawa int msm6242b_settime_ymdhms(todr_chip_handle_t, struct clock_ymdhms *);
     53       1.1  rkujawa 
     54       1.1  rkujawa bool msm6242b_hold(struct msm6242b_softc *sc);
     55       1.1  rkujawa void msm6242b_free(struct msm6242b_softc *sc);
     56       1.1  rkujawa static uint8_t msm6242b_read(struct msm6242b_softc *, uint8_t);
     57       1.1  rkujawa static void msm6242b_write(struct msm6242b_softc *, uint8_t, uint8_t);
     58       1.1  rkujawa static void msm6242b_set(struct msm6242b_softc *, uint8_t, uint8_t);
     59       1.1  rkujawa static void msm6242b_unset(struct msm6242b_softc *, uint8_t, uint8_t);
     60       1.1  rkujawa 
     61       1.1  rkujawa void
     62       1.1  rkujawa msm6242b_attach(struct msm6242b_softc *sc)
     63       1.1  rkujawa {
     64       1.1  rkujawa 	struct clock_ymdhms dt;
     65       1.1  rkujawa 
     66       1.1  rkujawa 	todr_chip_handle_t handle;
     67       1.1  rkujawa 	aprint_normal(": OKI MSM6242B\n");
     68       1.1  rkujawa 
     69       1.1  rkujawa 	handle = &sc->sc_handle;
     70       1.1  rkujawa 	handle->cookie = sc;
     71       1.1  rkujawa 	handle->todr_gettime = NULL;
     72       1.1  rkujawa 	handle->todr_settime = NULL;
     73       1.1  rkujawa 	handle->todr_gettime_ymdhms = msm6242b_gettime_ymdhms;
     74       1.1  rkujawa 	handle->todr_settime_ymdhms = msm6242b_settime_ymdhms;
     75       1.1  rkujawa 	handle->todr_setwen = NULL;
     76       1.1  rkujawa 
     77       1.1  rkujawa 	if (msm6242b_gettime_ymdhms(handle, &dt) != 0) {
     78       1.1  rkujawa 		aprint_error_dev(sc->sc_dev, "RTC does not work correctly\n");
     79       1.1  rkujawa 		return;
     80       1.1  rkujawa 	}
     81       1.1  rkujawa 
     82       1.1  rkujawa #ifdef MSM6242B_DEBUG
     83       1.1  rkujawa 	aprint_normal_dev(sc->sc_dev, "the time is %d %d %d %d %d %d\n",
     84       1.1  rkujawa 	    dt.dt_year, dt.dt_mon, dt.dt_day, dt.dt_hour, dt.dt_min, dt.dt_sec);
     85       1.2  rkujawa #endif /* MSM6242B_DEBUG */
     86       1.1  rkujawa 	todr_attach(handle);
     87       1.1  rkujawa }
     88       1.1  rkujawa 
     89       1.1  rkujawa static int
     90       1.1  rkujawa msm6242b_gettime_ymdhms(todr_chip_handle_t handle, struct clock_ymdhms *dt)
     91       1.1  rkujawa {
     92       1.1  rkujawa 	struct msm6242b_softc *sc;
     93       1.1  rkujawa 
     94       1.1  rkujawa 	sc = handle->cookie;
     95       1.1  rkujawa 	/* XXX: splsched(); */
     96       1.1  rkujawa 
     97       1.1  rkujawa 	if(!msm6242b_hold(sc))
     98       1.1  rkujawa 		return (ENXIO);
     99       1.1  rkujawa 
    100       1.1  rkujawa 	dt->dt_sec = msm6242b_read(sc, MSM6242B_10SECOND) * 10 +
    101       1.1  rkujawa 	    msm6242b_read(sc, MSM6242B_1SECOND);
    102       1.1  rkujawa 	dt->dt_min = msm6242b_read(sc, MSM6242B_10MINUTE) * 10 +
    103       1.1  rkujawa 	    msm6242b_read(sc, MSM6242B_1MINUTE);
    104       1.1  rkujawa 	dt->dt_hour = (msm6242b_read(sc, MSM6242B_10HOUR_PMAM) &
    105       1.1  rkujawa 	    MSM6242B_10HOUR_MASK) * 10 + msm6242b_read(sc, MSM6242B_1HOUR);
    106       1.1  rkujawa 	dt->dt_day = msm6242b_read(sc, MSM6242B_10DAY) * 10 +
    107       1.1  rkujawa 	    msm6242b_read(sc, MSM6242B_1DAY);
    108       1.1  rkujawa 	dt->dt_mon = msm6242b_read(sc, MSM6242B_10MONTH) * 10 +
    109       1.1  rkujawa 	    msm6242b_read(sc, MSM6242B_1MONTH);
    110       1.1  rkujawa 	dt->dt_year = msm6242b_read(sc, MSM6242B_10YEAR) * 10 +
    111       1.1  rkujawa 	    msm6242b_read(sc, MSM6242B_1YEAR);
    112       1.1  rkujawa 	dt->dt_wday = msm6242b_read(sc, MSM6242B_WEEK);
    113       1.1  rkujawa 
    114       1.1  rkujawa #ifdef MSM6242B_DEBUG
    115       1.1  rkujawa 	aprint_normal_dev(sc->sc_dev, "the time is %d %d %d %d %d %d\n",
    116       1.1  rkujawa 	    dt->dt_year, dt->dt_mon, dt->dt_day, dt->dt_hour, dt->dt_min, dt->dt_sec);
    117       1.2  rkujawa #endif /* MSM6242B_DEBUG */
    118       1.1  rkujawa 
    119       1.1  rkujawa 	/* handle 12h mode */
    120       1.1  rkujawa 	if ((msm6242b_read(sc, MSM6242B_CONTROL_F) &
    121       1.1  rkujawa 	    MSM6242B_CONTROL_F_24H) == 0) {
    122       1.1  rkujawa 		if ((msm6242b_read(sc, MSM6242B_10HOUR_PMAM) &
    123       1.1  rkujawa 		    MSM6242B_PMAM_BIT) == 0 && dt->dt_hour == 12)
    124       1.1  rkujawa 			dt->dt_hour = 0;
    125       1.1  rkujawa 		else if ((msm6242b_read(sc, MSM6242B_10HOUR_PMAM) &
    126  1.3.22.1   martin 		    MSM6242B_PMAM_BIT) && dt->dt_hour != 12)
    127       1.1  rkujawa 			dt->dt_hour += 12;
    128       1.1  rkujawa 	}
    129       1.1  rkujawa 
    130       1.1  rkujawa 	msm6242b_free(sc);
    131       1.1  rkujawa 
    132       1.1  rkujawa 	dt->dt_year += MSM6242B_BASE_YEAR;
    133       1.1  rkujawa 	if (dt->dt_year < POSIX_BASE_YEAR)
    134       1.1  rkujawa 		dt->dt_year += 100;
    135       1.1  rkujawa 
    136       1.1  rkujawa 	if ((dt->dt_hour > 23) ||
    137       1.1  rkujawa 	    (dt->dt_day  > 31) ||
    138       1.1  rkujawa 	    (dt->dt_mon  > 12) ||
    139       1.1  rkujawa 	    (dt->dt_year > 2036))
    140       1.1  rkujawa 		return (EINVAL);
    141       1.1  rkujawa 
    142       1.1  rkujawa 	return 0;
    143       1.1  rkujawa }
    144       1.1  rkujawa 
    145       1.1  rkujawa bool
    146       1.1  rkujawa msm6242b_hold(struct msm6242b_softc *sc)
    147       1.1  rkujawa {
    148       1.1  rkujawa 	int try;
    149       1.1  rkujawa 
    150       1.1  rkujawa #define TRY_MAX 10
    151       1.1  rkujawa 	for (try = 0; try < TRY_MAX; try++) {
    152       1.1  rkujawa 		msm6242b_set(sc, MSM6242B_CONTROL_D, MSM6242B_CONTROL_D_HOLD);
    153       1.1  rkujawa 		if (msm6242b_read(sc, MSM6242B_CONTROL_D)
    154       1.1  rkujawa 		    & MSM6242B_CONTROL_D_BUSY) {
    155       1.2  rkujawa #ifdef MSM6242B_DEBUG
    156       1.1  rkujawa 			aprint_normal_dev(sc->sc_dev, "gotta idle\n");
    157       1.2  rkujawa #endif /* MSM6242B_DEBUG */
    158       1.1  rkujawa 			msm6242b_unset(sc, MSM6242B_CONTROL_D,
    159       1.1  rkujawa 			    MSM6242B_CONTROL_D_HOLD);
    160       1.1  rkujawa 			delay(70);
    161       1.1  rkujawa 		} else {
    162       1.2  rkujawa #ifdef MSM6242B_DEBUG
    163       1.1  rkujawa 			aprint_normal_dev(sc->sc_dev, "not busy\n");
    164       1.2  rkujawa #endif /* MSM6242B_DEBUG */
    165       1.1  rkujawa 			break;
    166       1.1  rkujawa 		}
    167       1.1  rkujawa 	}
    168       1.1  rkujawa 
    169       1.1  rkujawa 	if (try == TRY_MAX) {
    170       1.1  rkujawa 		aprint_error_dev(sc->sc_dev, "can't hold the chip\n");
    171       1.1  rkujawa 		return false;
    172       1.1  rkujawa 	}
    173       1.1  rkujawa 	return true;
    174       1.1  rkujawa }
    175       1.1  rkujawa 
    176       1.1  rkujawa void
    177       1.1  rkujawa msm6242b_free(struct msm6242b_softc *sc)
    178       1.1  rkujawa {
    179       1.1  rkujawa 	msm6242b_unset(sc, MSM6242B_CONTROL_D, MSM6242B_CONTROL_D_HOLD);
    180       1.1  rkujawa }
    181       1.1  rkujawa 
    182       1.1  rkujawa static uint8_t
    183       1.1  rkujawa msm6242b_read(struct msm6242b_softc *sc, uint8_t reg)
    184       1.1  rkujawa {
    185       1.1  rkujawa 	uint8_t r;
    186       1.1  rkujawa 	r = bus_space_read_1(sc->sc_iot, sc->sc_ioh, reg) & MSM6242B_MASK;
    187       1.1  rkujawa 	return r;
    188       1.1  rkujawa }
    189       1.1  rkujawa 
    190       1.1  rkujawa static void
    191       1.1  rkujawa msm6242b_write(struct msm6242b_softc *sc, uint8_t reg, uint8_t val)
    192       1.1  rkujawa {
    193       1.1  rkujawa 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, reg, val);
    194       1.1  rkujawa }
    195       1.1  rkujawa 
    196       1.1  rkujawa static void
    197       1.1  rkujawa msm6242b_set(struct msm6242b_softc *sc, uint8_t reg, uint8_t bits)
    198       1.1  rkujawa {
    199       1.1  rkujawa 	uint8_t v;
    200       1.1  rkujawa 	v = msm6242b_read(sc, reg) | bits;
    201       1.1  rkujawa 	msm6242b_write(sc, reg, v);
    202       1.1  rkujawa }
    203       1.1  rkujawa 
    204       1.1  rkujawa static void
    205       1.1  rkujawa msm6242b_unset(struct msm6242b_softc *sc, uint8_t reg, uint8_t bits)
    206       1.1  rkujawa {
    207       1.1  rkujawa 	uint8_t v;
    208       1.1  rkujawa 	v = msm6242b_read(sc, reg) & ~bits;
    209       1.1  rkujawa 	msm6242b_write(sc, reg, v);
    210       1.1  rkujawa }
    211       1.1  rkujawa 
    212       1.1  rkujawa int
    213       1.1  rkujawa msm6242b_settime_ymdhms(todr_chip_handle_t handle, struct clock_ymdhms *dt)
    214       1.1  rkujawa {
    215       1.1  rkujawa 	struct msm6242b_softc *sc;
    216       1.1  rkujawa 	int ampm;
    217       1.1  rkujawa 	/* XXX: splsched(); */
    218       1.1  rkujawa 
    219       1.1  rkujawa 	sc = handle->cookie;
    220       1.1  rkujawa 
    221       1.1  rkujawa 	if(!msm6242b_hold(sc))
    222       1.1  rkujawa 		return (ENXIO);
    223       1.1  rkujawa 
    224       1.1  rkujawa 	ampm = 0;
    225       1.1  rkujawa 	if ((msm6242b_read(sc, MSM6242B_CONTROL_F) &
    226       1.1  rkujawa 	    MSM6242B_CONTROL_F_24H) == 0) {
    227       1.1  rkujawa 		if (dt->dt_hour >= 12) {
    228       1.1  rkujawa 			ampm = MSM6242B_CONTROL_F_24H;
    229       1.1  rkujawa 			if (dt->dt_hour != 12)
    230       1.1  rkujawa 				dt->dt_hour -= 12;
    231       1.1  rkujawa 		} else if (dt->dt_hour == 0) {
    232       1.1  rkujawa 			dt->dt_hour = 12;
    233       1.1  rkujawa 		}
    234       1.1  rkujawa 	}
    235       1.1  rkujawa 
    236       1.1  rkujawa 	msm6242b_write(sc, MSM6242B_10HOUR_PMAM, (dt->dt_hour / 10) | ampm);
    237       1.1  rkujawa 	msm6242b_write(sc, MSM6242B_1HOUR, dt->dt_hour % 10);
    238       1.1  rkujawa 	msm6242b_write(sc, MSM6242B_10SECOND, dt->dt_sec / 10);
    239       1.1  rkujawa 	msm6242b_write(sc, MSM6242B_1SECOND, dt->dt_sec % 10);
    240       1.1  rkujawa 	msm6242b_write(sc, MSM6242B_10MINUTE, dt->dt_min / 10);
    241       1.1  rkujawa 	msm6242b_write(sc, MSM6242B_1MINUTE, dt->dt_min % 10);
    242       1.1  rkujawa 	msm6242b_write(sc, MSM6242B_10DAY, dt->dt_day / 10);
    243       1.1  rkujawa 	msm6242b_write(sc, MSM6242B_1DAY, dt->dt_day % 10);
    244       1.1  rkujawa 	msm6242b_write(sc, MSM6242B_10MONTH, dt->dt_mon / 10);
    245       1.1  rkujawa 	msm6242b_write(sc, MSM6242B_1MONTH, dt->dt_mon % 10);
    246       1.3  rkujawa 	msm6242b_write(sc, MSM6242B_10YEAR, (dt->dt_year / 10) % 10);
    247       1.3  rkujawa 	msm6242b_write(sc, MSM6242B_1YEAR, dt->dt_year % 10);
    248       1.1  rkujawa 	msm6242b_write(sc, MSM6242B_WEEK, dt->dt_wday);
    249       1.1  rkujawa 
    250       1.1  rkujawa 	msm6242b_free(sc);
    251       1.1  rkujawa 
    252       1.1  rkujawa 	return 0;
    253       1.1  rkujawa }
    254       1.1  rkujawa 
    255