Path: blob/main/sys/powerpc/mpc85xx/ds1553_core.c
101184 views
/*-1* SPDX-License-Identifier: BSD-2-Clause2*3* Copyright (C) 2006-2008 Semihalf, Grzegorz Bernacki4* All rights reserved.5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted provided that the following conditions8* are met:9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer.11* 2. Redistributions in binary form must reproduce the above copyright12* notice, this list of conditions and the following disclaimer in the13* documentation and/or other materials provided with the distribution.14*15* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND16* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE17* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE18* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE19* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL20* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS21* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)22* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT23* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY24* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF25* SUCH DAMAGE.26*27*/2829#include <sys/param.h>30#include <sys/systm.h>31#include <sys/bus.h>32#include <sys/clock.h>33#include <sys/lock.h>34#include <sys/mutex.h>3536#include <machine/bus.h>3738#include <powerpc/mpc85xx/ds1553_reg.h>3940static uint8_t ds1553_direct_read(device_t, bus_size_t);41static void ds1553_direct_write(device_t, bus_size_t, uint8_t);4243int44ds1553_attach(device_t dev)45{46struct ds1553_softc *sc;47uint8_t sec, flags;4849sc = device_get_softc(dev);5051if (mtx_initialized(&sc->sc_mtx) == 0) {52device_printf(dev, "%s: mutex not initialized\n", __func__);53return (ENXIO);54}5556if (sc->sc_read == NULL)57sc->sc_read = ds1553_direct_read;58if (sc->sc_write == NULL)59sc->sc_write = ds1553_direct_write;6061sc->year_offset = POSIX_BASE_YEAR;6263mtx_lock_spin(&sc->sc_mtx);6465/* Turn RTC on if it was not on */66sec = (*sc->sc_read)(dev, DS1553_OFF_SECONDS);67if (sec & DS1553_BIT_OSC) {68sec &= ~(DS1553_BIT_OSC);69(*sc->sc_write)(dev, DS1553_OFF_SECONDS, sec);70}7172/* Low-battery check */73flags = (*sc->sc_read)(dev, DS1553_OFF_FLAGS);74if (flags & DS1553_BIT_BLF)75device_printf(dev, "voltage-low detected.\n");7677mtx_unlock_spin(&sc->sc_mtx);7879return (0);80}8182/*83* Get time of day and convert it to a struct timespec.84* Return 0 on success, an error number otherwise.85*/86int87ds1553_gettime(device_t dev, struct timespec *ts)88{89struct clocktime ct;90struct ds1553_softc *sc;91uint8_t control;9293sc = device_get_softc(dev);9495mtx_lock_spin(&sc->sc_mtx);9697control = (*sc->sc_read)(dev, DS1553_OFF_CONTROL) | DS1553_BIT_READ;98(*sc->sc_write)(dev, DS1553_OFF_CONTROL, control);99100ct.nsec = 0;101ct.sec = FROMBCD((*sc->sc_read)(dev, DS1553_OFF_SECONDS) &102DS1553_MASK_SECONDS);103ct.min = FROMBCD((*sc->sc_read)(dev, DS1553_OFF_MINUTES) &104DS1553_MASK_MINUTES);105ct.hour = FROMBCD((*sc->sc_read)(dev, DS1553_OFF_HOURS) &106DS1553_MASK_HOUR);107ct.dow = FROMBCD((*sc->sc_read)(dev, DS1553_OFF_DAYOFWEEK) &108DS1553_MASK_DAYOFWEEK) - 1;109ct.day = FROMBCD((*sc->sc_read)(dev, DS1553_OFF_DATE) &110DS1553_MASK_DATE);111ct.mon = FROMBCD((*sc->sc_read)(dev, DS1553_OFF_MONTH) &112DS1553_MASK_MONTH);113ct.year = FROMBCD((*sc->sc_read)(dev, DS1553_OFF_YEAR));114115control &= ~DS1553_BIT_READ;116(*sc->sc_write)(dev, DS1553_OFF_CONTROL, control);117118ct.year += sc->year_offset;119120mtx_unlock_spin(&sc->sc_mtx);121122return (clock_ct_to_ts(&ct, ts));123}124125/*126* Set the time of day clock based on the value of the struct timespec arg.127* Return 0 on success, an error number otherwise.128*/129int130ds1553_settime(device_t dev, struct timespec *ts)131{132struct clocktime ct;133struct ds1553_softc *sc;134uint8_t control;135136sc = device_get_softc(dev);137bzero(&ct, sizeof(struct clocktime));138139/* Accuracy is only one second. */140if (ts->tv_nsec >= 500000000)141ts->tv_sec++;142ts->tv_nsec = 0;143clock_ts_to_ct(ts, &ct);144145ct.year -= sc->year_offset;146147mtx_lock_spin(&sc->sc_mtx);148149/* Halt updates to external registers */150control = (*sc->sc_read)(dev, DS1553_OFF_CONTROL) | DS1553_BIT_WRITE;151(*sc->sc_write)(dev, DS1553_OFF_CONTROL, control);152153(*sc->sc_write)(dev, DS1553_OFF_SECONDS, TOBCD(ct.sec) &154DS1553_MASK_SECONDS);155(*sc->sc_write)(dev, DS1553_OFF_MINUTES, TOBCD(ct.min) &156DS1553_MASK_MINUTES);157(*sc->sc_write)(dev, DS1553_OFF_HOURS, TOBCD(ct.hour) &158DS1553_MASK_HOUR);159(*sc->sc_write)(dev, DS1553_OFF_DAYOFWEEK, TOBCD(ct.dow + 1) &160DS1553_MASK_DAYOFWEEK);161(*sc->sc_write)(dev, DS1553_OFF_DATE, TOBCD(ct.day) &162DS1553_MASK_DATE);163(*sc->sc_write)(dev, DS1553_OFF_MONTH, TOBCD(ct.mon) &164DS1553_MASK_MONTH);165(*sc->sc_write)(dev, DS1553_OFF_YEAR, TOBCD(ct.year));166167/* Resume updates to external registers */168control &= ~DS1553_BIT_WRITE;169(*sc->sc_write)(dev, DS1553_OFF_CONTROL, control);170171mtx_unlock_spin(&sc->sc_mtx);172173return (0);174}175176static uint8_t177ds1553_direct_read(device_t dev, bus_size_t off)178{179struct ds1553_softc *sc;180181sc = device_get_softc(dev);182return (bus_space_read_1(sc->sc_bst, sc->sc_bsh, off));183}184185static void186ds1553_direct_write(device_t dev, bus_size_t off, uint8_t val)187{188struct ds1553_softc *sc;189190sc = device_get_softc(dev);191bus_space_write_1(sc->sc_bst, sc->sc_bsh, off, val);192}193194195