root/drivers/net/fddi/skfp/hwt.c
// SPDX-License-Identifier: GPL-2.0-or-later
/******************************************************************************
 *
 *      (C)Copyright 1998,1999 SysKonnect,
 *      a business unit of Schneider & Koch & Co. Datensysteme GmbH.
 *
 *      See the file "skfddi.c" for further information.
 *
 *      The information in this file is provided "AS IS" without warranty.
 *
 ******************************************************************************/

/*
 * Timer Driver for FBI board (timer chip 82C54)
 */

/*
 * Modifications:
 *
 *      28-Jun-1994 sw  Edit v1.6.
 *                      MCA: Added support for the SK-NET FDDI-FM2 adapter. The
 *                       following functions have been added(+) or modified(*):
 *                       hwt_start(*), hwt_stop(*), hwt_restart(*), hwt_read(*)
 */

#include "h/types.h"
#include "h/fddi.h"
#include "h/smc.h"

/*
 * Prototypes of local functions.
 */
/* 28-Jun-1994 sw - Note: hwt_restart() is also used in module 'drvfbi.c'. */
/*static void hwt_restart() ; */

/************************
 *
 *      hwt_start
 *
 *      Start hardware timer (clock ticks are 16us).
 *
 *      void hwt_start(
 *              struct s_smc *smc,
 *              u_long time) ;
 * In
 *      smc - A pointer to the SMT Context structure.
 *
 *      time - The time in units of 16us to load the timer with.
 * Out
 *      Nothing.
 *
 ************************/
#define HWT_MAX (65000)

void hwt_start(struct s_smc *smc, u_long time)
{
        u_short cnt ;

        if (time > HWT_MAX)
                time = HWT_MAX ;

        smc->hw.t_start = time ;
        smc->hw.t_stop = 0L ;

        cnt = (u_short)time ;
        /*
         * if time < 16 us
         *      time = 16 us
         */
        if (!cnt)
                cnt++ ;

        outpd(ADDR(B2_TI_INI), (u_long) cnt * 200) ;    /* Load timer value. */
        outpw(ADDR(B2_TI_CRTL), TIM_START) ;            /* Start timer. */

        smc->hw.timer_activ = TRUE ;
}

/************************
 *
 *      hwt_stop
 *
 *      Stop hardware timer.
 *
 *      void hwt_stop(
 *              struct s_smc *smc) ;
 * In
 *      smc - A pointer to the SMT Context structure.
 * Out
 *      Nothing.
 *
 ************************/
void hwt_stop(struct s_smc *smc)
{
        outpw(ADDR(B2_TI_CRTL), TIM_STOP) ;
        outpw(ADDR(B2_TI_CRTL), TIM_CL_IRQ) ;

        smc->hw.timer_activ = FALSE ;
}

/************************
 *
 *      hwt_init
 *
 *      Initialize hardware timer.
 *
 *      void hwt_init(
 *              struct s_smc *smc) ;
 * In
 *      smc - A pointer to the SMT Context structure.
 * Out
 *      Nothing.
 *
 ************************/
void hwt_init(struct s_smc *smc)
{
        smc->hw.t_start = 0 ;
        smc->hw.t_stop  = 0 ;
        smc->hw.timer_activ = FALSE ;

        hwt_restart(smc) ;
}

/************************
 *
 *      hwt_restart
 *
 *      Clear timer interrupt.
 *
 *      void hwt_restart(
 *              struct s_smc *smc) ;
 * In
 *      smc - A pointer to the SMT Context structure.
 * Out
 *      Nothing.
 *
 ************************/
void hwt_restart(struct s_smc *smc)
{
        hwt_stop(smc) ;
}

/************************
 *
 *      hwt_read
 *
 *      Stop hardware timer and read time elapsed since last start.
 *
 *      u_long hwt_read(smc) ;
 * In
 *      smc - A pointer to the SMT Context structure.
 * Out
 *      The elapsed time since last start in units of 16us.
 *
 ************************/
u_long hwt_read(struct s_smc *smc)
{
        u_short tr ;
        u_long  is ;

        if (smc->hw.timer_activ) {
                hwt_stop(smc) ;
                tr = (u_short)((inpd(ADDR(B2_TI_VAL))/200) & 0xffff) ;

                is = GET_ISR() ;
                /* Check if timer expired (or wraparound). */
                if ((tr > smc->hw.t_start) || (is & IS_TIMINT)) {
                        hwt_restart(smc) ;
                        smc->hw.t_stop = smc->hw.t_start ;
                }
                else
                        smc->hw.t_stop = smc->hw.t_start - tr ;
        }
        return smc->hw.t_stop;
}

#ifdef  PCI
/************************
 *
 *      hwt_quick_read
 *
 *      Stop hardware timer and read timer value and start the timer again.
 *
 *      u_long hwt_read(smc) ;
 * In
 *      smc - A pointer to the SMT Context structure.
 * Out
 *      current timer value in units of 80ns.
 *
 ************************/
u_long hwt_quick_read(struct s_smc *smc)
{
        u_long interval ;
        u_long time ;

        interval = inpd(ADDR(B2_TI_INI)) ;
        outpw(ADDR(B2_TI_CRTL), TIM_STOP) ;
        time = inpd(ADDR(B2_TI_VAL)) ;
        outpd(ADDR(B2_TI_INI),time) ;
        outpw(ADDR(B2_TI_CRTL), TIM_START) ;
        outpd(ADDR(B2_TI_INI),interval) ;

        return time;
}

/************************
 *
 *      hwt_wait_time(smc,start,duration)
 *
 *      This function returnes after the amount of time is elapsed
 *      since the start time.
 * 
 * para start           start time
 *      duration        time to wait
 *
 * NOTE: The function will return immediately, if the timer is not
 *       started
 ************************/
void hwt_wait_time(struct s_smc *smc, u_long start, long int duration)
{
        long    diff ;
        long    interval ;
        int     wrapped ;

        /*
         * check if timer is running
         */
        if (smc->hw.timer_activ == FALSE ||
                hwt_quick_read(smc) == hwt_quick_read(smc)) {
                return ;
        }

        interval = inpd(ADDR(B2_TI_INI)) ;
        if (interval > duration) {
                do {
                        diff = (long)(start - hwt_quick_read(smc)) ;
                        if (diff < 0) {
                                diff += interval ;
                        }
                } while (diff <= duration) ;
        }
        else {
                diff = interval ;
                wrapped = 0 ;
                do {
                        if (!wrapped) {
                                if (hwt_quick_read(smc) >= start) {
                                        diff += interval ;
                                        wrapped = 1 ;
                                }
                        }
                        else {
                                if (hwt_quick_read(smc) < start) {
                                        wrapped = 0 ;
                                }
                        }
                } while (diff <= duration) ;
        }
}
#endif