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