#include <sys/types.h>
#include <sys/param.h>
#include <sys/sysmacros.h>
#include <sys/systm.h>
#include <sys/errno.h>
#include <sys/modctl.h>
#include <sys/autoconf.h>
#include <sys/debug.h>
#include <sys/clock.h>
#include <sys/todmostek.h>
#include <sys/reboot.h>
#include <sys/cmn_err.h>
#include <sys/cpuvar.h>
static timestruc_t todm_get(void);
static void todm_set(timestruc_t);
static uint_t todm_set_watchdog_timer(uint_t);
static uint_t todm_clear_watchdog_timer(void);
static void todm_set_power_alarm(timestruc_t);
static void todm_clear_power_alarm(void);
static uint64_t todm_get_cpufrequency(void);
static uchar_t watchdog_bits = 0;
static uint_t watchdog_timeout;
extern uint64_t find_cpufrequency(volatile uchar_t *);
static struct modlmisc modlmisc = {
&mod_miscops, "tod module for Mostek M48T59"
};
static struct modlinkage modlinkage = {
MODREV_1, (void *)&modlmisc, NULL
};
int
_init(void)
{
if (strcmp(tod_module_name, "todmostek") == 0) {
tod_ops.tod_get = todm_get;
tod_ops.tod_set = todm_set;
tod_ops.tod_set_watchdog_timer = todm_set_watchdog_timer;
tod_ops.tod_clear_watchdog_timer = todm_clear_watchdog_timer;
tod_ops.tod_set_power_alarm = todm_set_power_alarm;
tod_ops.tod_clear_power_alarm = todm_clear_power_alarm;
tod_ops.tod_get_cpufrequency = todm_get_cpufrequency;
if (watchdog_enable) {
if (!watchdog_available) {
cmn_err(CE_WARN,
"Hardware watchdog unavailable");
} else if (boothowto & RB_DEBUG) {
cmn_err(CE_WARN, "Hardware watchdog disabled"
" [debugger]");
}
}
}
return (mod_install(&modlinkage));
}
int
_fini(void)
{
if (strcmp(tod_module_name, "todmostek") == 0)
return (EBUSY);
else
return (mod_remove(&modlinkage));
}
int
_info(struct modinfo *modinfop)
{
return (mod_info(&modlinkage, modinfop));
}
static timestruc_t
todm_get(void)
{
timestruc_t ts;
todinfo_t tod;
int s;
ASSERT(MUTEX_HELD(&tod_lock));
s = splhi();
CLOCK->clk_ctrl |= CLK_CTRL_READ;
tod.tod_year = BCD_TO_BYTE(CLOCK->clk_year) + YRBASE;
tod.tod_month = BCD_TO_BYTE(CLOCK->clk_month & 0x1f);
tod.tod_day = BCD_TO_BYTE(CLOCK->clk_day & 0x3f);
tod.tod_dow = BCD_TO_BYTE(CLOCK->clk_weekday & 0x7);
tod.tod_hour = BCD_TO_BYTE(CLOCK->clk_hour & 0x3f);
tod.tod_min = BCD_TO_BYTE(CLOCK->clk_min & 0x7f);
tod.tod_sec = BCD_TO_BYTE(CLOCK->clk_sec & 0x7f);
CLOCK->clk_ctrl &= ~CLK_CTRL_READ;
splx(s);
CLOCK->clk_watchdog = watchdog_bits;
ts.tv_sec = tod_to_utc(tod);
ts.tv_nsec = 0;
return (ts);
}
static void
todm_set(timestruc_t ts)
{
todinfo_t tod = utc_to_tod(ts.tv_sec);
ASSERT(MUTEX_HELD(&tod_lock));
CLOCK->clk_ctrl |= CLK_CTRL_WRITE;
CLOCK->clk_year = BYTE_TO_BCD(tod.tod_year - YRBASE);
CLOCK->clk_month = BYTE_TO_BCD(tod.tod_month);
CLOCK->clk_day = BYTE_TO_BCD(tod.tod_day);
CLOCK->clk_weekday = BYTE_TO_BCD(tod.tod_dow);
CLOCK->clk_hour = BYTE_TO_BCD(tod.tod_hour);
CLOCK->clk_min = BYTE_TO_BCD(tod.tod_min);
CLOCK->clk_sec = BYTE_TO_BCD(tod.tod_sec);
CLOCK->clk_ctrl &= ~CLK_CTRL_WRITE;
}
static uint_t
todm_set_watchdog_timer(uint_t timeoutval)
{
ASSERT(MUTEX_HELD(&tod_lock));
if (watchdog_enable == 0 || watchdog_available == 0 ||
(boothowto & RB_DEBUG))
return (0);
watchdog_timeout = timeoutval;
watchdog_bits = CLK_WATCHDOG_BITS(timeoutval);
watchdog_activated = 1;
return (timeoutval);
}
static uint_t
todm_clear_watchdog_timer(void)
{
ASSERT(MUTEX_HELD(&tod_lock));
if (watchdog_activated == 0)
return (0);
CLOCK->clk_watchdog = 0;
watchdog_bits = 0;
watchdog_activated = 0;
return (watchdog_timeout);
}
static void
todm_set_power_alarm(timestruc_t ts)
{
todinfo_t tod;
uchar_t c;
ASSERT(MUTEX_HELD(&tod_lock));
tod = utc_to_tod(ts.tv_sec);
c = CLOCK->clk_flags;
#ifdef lint
CLOCK->clk_flags = c;
#endif
CLOCK->clk_interrupts &= ~CLK_ALARM_ENABLE;
CLOCK->clk_day &= ~CLK_FREQT;
CLOCK->clk_alm_day = BYTE_TO_BCD(tod.tod_day);
CLOCK->clk_alm_hours = BYTE_TO_BCD(tod.tod_hour);
CLOCK->clk_alm_mins = BYTE_TO_BCD(tod.tod_min);
CLOCK->clk_alm_secs = BYTE_TO_BCD(tod.tod_sec);
CLOCK->clk_interrupts |= CLK_ALARM_ENABLE;
}
static void
todm_clear_power_alarm()
{
uchar_t c;
ASSERT(MUTEX_HELD(&tod_lock));
c = CLOCK->clk_flags;
#ifdef lint
CLOCK->clk_flags = c;
#endif
CLOCK->clk_interrupts &= ~CLK_ALARM_ENABLE;
}
uint64_t
todm_get_cpufrequency(void)
{
ASSERT(MUTEX_HELD(&tod_lock));
return (find_cpufrequency(&(TIMECHECK_CLOCK->clk_sec)));
}