1*84612482Sminht /* 2*84612482Sminht * CDDL HEADER START 3*84612482Sminht * 4*84612482Sminht * The contents of this file are subject to the terms of the 5*84612482Sminht * Common Development and Distribution License, Version 1.0 only 6*84612482Sminht * (the "License"). You may not use this file except in compliance 7*84612482Sminht * with the License. 8*84612482Sminht * 9*84612482Sminht * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*84612482Sminht * or http://www.opensolaris.org/os/licensing. 11*84612482Sminht * See the License for the specific language governing permissions 12*84612482Sminht * and limitations under the License. 13*84612482Sminht * 14*84612482Sminht * When distributing Covered Code, include this CDDL HEADER in each 15*84612482Sminht * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*84612482Sminht * If applicable, add the following below this CDDL HEADER, with the 17*84612482Sminht * fields enclosed by brackets "[]" replaced with your own identifying 18*84612482Sminht * information: Portions Copyright [yyyy] [name of copyright owner] 19*84612482Sminht * 20*84612482Sminht * CDDL HEADER END 21*84612482Sminht */ 22*84612482Sminht /* 23*84612482Sminht * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*84612482Sminht * Use is subject to license terms. 25*84612482Sminht */ 26*84612482Sminht 27*84612482Sminht #pragma ident "%Z%%M% %I% %E% SMI" 28*84612482Sminht 29*84612482Sminht /* 30*84612482Sminht * tod driver module for TI BQ4802 part 31*84612482Sminht * 32*84612482Sminht * Note: The way to access the bq4802's RTC registers is different than 33*84612482Sminht * the previous RTC devices (m5823, m5819p, ds1287, etc) that we used. 34*84612482Sminht * The address returns from OBP is mapped directly to the bq4802's RTC 35*84612482Sminht * registers. To read/write the data from/to the bq4802 registers, one 36*84612482Sminht * just add the register offset to the base address. 37*84612482Sminht * To access the previous RTC devices, we write the register index to 38*84612482Sminht * the address port (v_rtc_addr_reg) then read/write the data from/to 39*84612482Sminht * the data port (v_rtc_data_reg). 40*84612482Sminht */ 41*84612482Sminht 42*84612482Sminht #include <sys/types.h> 43*84612482Sminht #include <sys/conf.h> 44*84612482Sminht #include <sys/kmem.h> 45*84612482Sminht #include <sys/open.h> 46*84612482Sminht #include <sys/ddi.h> 47*84612482Sminht #include <sys/sunddi.h> 48*84612482Sminht #include <sys/sysmacros.h> 49*84612482Sminht 50*84612482Sminht #include <sys/todbq4802.h> 51*84612482Sminht #include <sys/modctl.h> 52*84612482Sminht #include <sys/stat.h> 53*84612482Sminht #include <sys/clock.h> 54*84612482Sminht #include <sys/reboot.h> 55*84612482Sminht #include <sys/machsystm.h> 56*84612482Sminht 57*84612482Sminht /* 58*84612482Sminht * tod_ops entry routines 59*84612482Sminht */ 60*84612482Sminht static timestruc_t todbq4802_get(void); 61*84612482Sminht static void todbq4802_set(timestruc_t); 62*84612482Sminht static uint_t todbq4802_set_watchdog_timer(uint_t); 63*84612482Sminht static uint_t todbq4802_clear_watchdog_timer(void); 64*84612482Sminht static void todbq4802_set_power_alarm(timestruc_t); 65*84612482Sminht static void todbq4802_clear_power_alarm(void); 66*84612482Sminht static uint64_t todbq4802_get_cpufrequency(void); 67*84612482Sminht 68*84612482Sminht extern uint64_t find_cpufrequency(volatile uint8_t *); 69*84612482Sminht 70*84612482Sminht /* 71*84612482Sminht * External variables 72*84612482Sminht */ 73*84612482Sminht extern int watchdog_enable; 74*84612482Sminht extern int watchdog_available; 75*84612482Sminht extern int boothowto; 76*84612482Sminht 77*84612482Sminht /* 78*84612482Sminht * Global variables 79*84612482Sminht */ 80*84612482Sminht int bq4802_debug_flags; 81*84612482Sminht uint_t bq4802_hrestime_count = 0; 82*84612482Sminht uint_t bq4802_uip_count = 0; 83*84612482Sminht 84*84612482Sminht /* 85*84612482Sminht * Module linkage information for the kernel. 86*84612482Sminht */ 87*84612482Sminht static struct modlmisc modlmisc = { 88*84612482Sminht &mod_miscops, "tod module for TI BQ4802" 89*84612482Sminht }; 90*84612482Sminht 91*84612482Sminht static struct modlinkage modlinkage = { 92*84612482Sminht MODREV_1, (void *)&modlmisc, NULL 93*84612482Sminht }; 94*84612482Sminht 95*84612482Sminht static void read_rtc(struct rtc_t *); 96*84612482Sminht static void write_rtc_time(struct rtc_t *); 97*84612482Sminht static void write_rtc_alarm(struct rtc_t *); 98*84612482Sminht 99*84612482Sminht int 100*84612482Sminht _init(void) 101*84612482Sminht { 102*84612482Sminht if (strcmp(tod_module_name, "todbq4802") == 0) { 103*84612482Sminht if (v_rtc_addr_reg == NULL) 104*84612482Sminht cmn_err(CE_PANIC, "addr not set, cannot read RTC\n"); 105*84612482Sminht 106*84612482Sminht BQ4802_DATA_REG(RTC_CNTRL) = (RTC_DSE | RTC_HM | RTC_STOP_N); 107*84612482Sminht 108*84612482Sminht /* Clear AF flag by reading reg Flags (D) */ 109*84612482Sminht (void) BQ4802_DATA_REG(RTC_FLAGS); 110*84612482Sminht 111*84612482Sminht tod_ops.tod_get = todbq4802_get; 112*84612482Sminht tod_ops.tod_set = todbq4802_set; 113*84612482Sminht tod_ops.tod_set_watchdog_timer = 114*84612482Sminht todbq4802_set_watchdog_timer; 115*84612482Sminht tod_ops.tod_clear_watchdog_timer = 116*84612482Sminht todbq4802_clear_watchdog_timer; 117*84612482Sminht tod_ops.tod_set_power_alarm = todbq4802_set_power_alarm; 118*84612482Sminht tod_ops.tod_clear_power_alarm = todbq4802_clear_power_alarm; 119*84612482Sminht tod_ops.tod_get_cpufrequency = todbq4802_get_cpufrequency; 120*84612482Sminht 121*84612482Sminht /* 122*84612482Sminht * check if hardware watchdog timer is available and user 123*84612482Sminht * enabled it. 124*84612482Sminht */ 125*84612482Sminht if (watchdog_enable) { 126*84612482Sminht if (!watchdog_available) { 127*84612482Sminht cmn_err(CE_WARN, "bq4802: Hardware watchdog " 128*84612482Sminht "unavailable"); 129*84612482Sminht } else if (boothowto & RB_DEBUG) { 130*84612482Sminht cmn_err(CE_WARN, "bq4802: Hardware watchdog" 131*84612482Sminht " disabled [debugger]"); 132*84612482Sminht } 133*84612482Sminht } 134*84612482Sminht } 135*84612482Sminht 136*84612482Sminht return (mod_install(&modlinkage)); 137*84612482Sminht } 138*84612482Sminht 139*84612482Sminht int 140*84612482Sminht _fini(void) 141*84612482Sminht { 142*84612482Sminht if (strcmp(tod_module_name, "todbq4802") == 0) 143*84612482Sminht return (EBUSY); 144*84612482Sminht 145*84612482Sminht return (mod_remove(&modlinkage)); 146*84612482Sminht } 147*84612482Sminht 148*84612482Sminht /* 149*84612482Sminht * The loadable-module _info(9E) entry point 150*84612482Sminht */ 151*84612482Sminht int 152*84612482Sminht _info(struct modinfo *modinfop) 153*84612482Sminht { 154*84612482Sminht return (mod_info(&modlinkage, modinfop)); 155*84612482Sminht } 156*84612482Sminht 157*84612482Sminht /* 158*84612482Sminht * Read the current time from the clock chip and convert to UNIX form. 159*84612482Sminht * Assumes that the year in the clock chip is valid. 160*84612482Sminht * Must be called with tod_lock held. 161*84612482Sminht */ 162*84612482Sminht static timestruc_t 163*84612482Sminht todbq4802_get(void) 164*84612482Sminht { 165*84612482Sminht timestruc_t ts; 166*84612482Sminht todinfo_t tod; 167*84612482Sminht struct rtc_t rtc; 168*84612482Sminht 169*84612482Sminht ASSERT(MUTEX_HELD(&tod_lock)); 170*84612482Sminht 171*84612482Sminht read_rtc(&rtc); 172*84612482Sminht DPRINTF("todbq4802_get: century=%d year=%d dom=%d hrs=%d min=%d" 173*84612482Sminht " sec=%d\n", rtc.rtc_century, rtc.rtc_year, rtc.rtc_dom, 174*84612482Sminht rtc.rtc_hrs, rtc.rtc_min, rtc.rtc_sec); 175*84612482Sminht 176*84612482Sminht /* 177*84612482Sminht * tod_year is base 1900 so this code needs to adjust the true 178*84612482Sminht * year retrieved from the rtc's century and year fields. 179*84612482Sminht */ 180*84612482Sminht tod.tod_year = rtc.rtc_year + (rtc.rtc_century * 100) - 1900; 181*84612482Sminht tod.tod_month = rtc.rtc_mon; 182*84612482Sminht tod.tod_day = rtc.rtc_dom; 183*84612482Sminht tod.tod_dow = rtc.rtc_dow; 184*84612482Sminht tod.tod_hour = rtc.rtc_hrs; 185*84612482Sminht tod.tod_min = rtc.rtc_min; 186*84612482Sminht tod.tod_sec = rtc.rtc_sec; 187*84612482Sminht 188*84612482Sminht ts.tv_sec = tod_to_utc(tod); 189*84612482Sminht ts.tv_nsec = 0; 190*84612482Sminht return (ts); 191*84612482Sminht } 192*84612482Sminht 193*84612482Sminht /* 194*84612482Sminht * Once every second, the user-accessible clock/calendar 195*84612482Sminht * locations are updated simultaneously from the internal 196*84612482Sminht * real-time counters. To prevent reading data in transition, 197*84612482Sminht * updates to the bq4802 clock registers should be halted. 198*84612482Sminht * Updating is halted by setting the Update Transfer Inhibit 199*84612482Sminht * (UTI) bit D3 of the control register E. As long as the 200*84612482Sminht * UTI bit is 1, updates to user-accessible clock locations are 201*84612482Sminht * inhibited. Once the frozen clock information is retrieved by 202*84612482Sminht * reading the appropriate clock memory locations, the UTI 203*84612482Sminht * bit should be reset to 0 in order to allow updates to occur 204*84612482Sminht * from the internal counters. Because the internal counters 205*84612482Sminht * are not halted by setting the UTI bit, reading the clock 206*84612482Sminht * locations has no effect on clock accuracy. Once the UTI bit 207*84612482Sminht * is reset to 0, the internal registers update within one 208*84612482Sminht * second the user-accessible registers with the correct time. 209*84612482Sminht * A halt command issued during a clock update allows the 210*84612482Sminht * update to occur before freezing the data. 211*84612482Sminht */ 212*84612482Sminht static void 213*84612482Sminht read_rtc(struct rtc_t *rtc) 214*84612482Sminht { 215*84612482Sminht uint8_t reg_cntrl; 216*84612482Sminht 217*84612482Sminht /* 218*84612482Sminht * Freeze 219*84612482Sminht */ 220*84612482Sminht reg_cntrl = BQ4802_DATA_REG(RTC_CNTRL); 221*84612482Sminht BQ4802_DATA_REG(RTC_CNTRL) = (reg_cntrl | RTC_UTI); 222*84612482Sminht 223*84612482Sminht rtc->rtc_sec = BCD_TO_BYTE(BQ4802_DATA_REG(RTC_SEC)); 224*84612482Sminht rtc->rtc_asec = BCD_TO_BYTE(BQ4802_DATA_REG(RTC_ASEC)); 225*84612482Sminht rtc->rtc_min = BCD_TO_BYTE(BQ4802_DATA_REG(RTC_MIN)); 226*84612482Sminht rtc->rtc_amin = BCD_TO_BYTE(BQ4802_DATA_REG(RTC_AMIN)); 227*84612482Sminht rtc->rtc_hrs = BCD_TO_BYTE(BQ4802_DATA_REG(RTC_HRS)); 228*84612482Sminht rtc->rtc_ahrs = BCD_TO_BYTE(BQ4802_DATA_REG(RTC_AHRS)); 229*84612482Sminht rtc->rtc_dom = BCD_TO_BYTE(BQ4802_DATA_REG(RTC_DOM)); 230*84612482Sminht rtc->rtc_adom = BCD_TO_BYTE(BQ4802_DATA_REG(RTC_ADOM)); 231*84612482Sminht rtc->rtc_dow = BCD_TO_BYTE(BQ4802_DATA_REG(RTC_DOW)); 232*84612482Sminht rtc->rtc_mon = BCD_TO_BYTE(BQ4802_DATA_REG(RTC_MON)); 233*84612482Sminht rtc->rtc_year = BCD_TO_BYTE(BQ4802_DATA_REG(RTC_YEAR)); 234*84612482Sminht rtc->rtc_century = BCD_TO_BYTE(BQ4802_DATA_REG(RTC_CENTURY)); 235*84612482Sminht 236*84612482Sminht /* 237*84612482Sminht * Unfreeze 238*84612482Sminht */ 239*84612482Sminht BQ4802_DATA_REG(RTC_CNTRL) = reg_cntrl; 240*84612482Sminht } 241*84612482Sminht 242*84612482Sminht /* 243*84612482Sminht * Write the specified time into the clock chip. 244*84612482Sminht * Must be called with tod_lock held. 245*84612482Sminht */ 246*84612482Sminht static void 247*84612482Sminht todbq4802_set(timestruc_t ts) 248*84612482Sminht { 249*84612482Sminht struct rtc_t rtc; 250*84612482Sminht todinfo_t tod = utc_to_tod(ts.tv_sec); 251*84612482Sminht int year; 252*84612482Sminht 253*84612482Sminht ASSERT(MUTEX_HELD(&tod_lock)); 254*84612482Sminht 255*84612482Sminht /* tod_year is base 1900 so this code needs to adjust */ 256*84612482Sminht year = 1900 + tod.tod_year; 257*84612482Sminht rtc.rtc_year = year % 100; 258*84612482Sminht rtc.rtc_century = year / 100; 259*84612482Sminht rtc.rtc_mon = (uint8_t)tod.tod_month; 260*84612482Sminht rtc.rtc_dom = (uint8_t)tod.tod_day; 261*84612482Sminht rtc.rtc_dow = (uint8_t)tod.tod_dow; 262*84612482Sminht rtc.rtc_hrs = (uint8_t)tod.tod_hour; 263*84612482Sminht rtc.rtc_min = (uint8_t)tod.tod_min; 264*84612482Sminht rtc.rtc_sec = (uint8_t)tod.tod_sec; 265*84612482Sminht DPRINTF("todbq4802_set: year=%d dom=%d hrs=%d min=%d sec=%d\n", 266*84612482Sminht rtc.rtc_year, rtc.rtc_dom, rtc.rtc_hrs, rtc.rtc_min, rtc.rtc_sec); 267*84612482Sminht 268*84612482Sminht write_rtc_time(&rtc); 269*84612482Sminht } 270*84612482Sminht 271*84612482Sminht /* 272*84612482Sminht * The UTI bit must be used to set the bq4802 clock. 273*84612482Sminht * Once set, the locations can be written with the desired 274*84612482Sminht * information in BCD format. Resetting the UTI bit to 0 causes 275*84612482Sminht * the written values to be transferred to the internal clock 276*84612482Sminht * counters and allows updates to the user-accessible registers 277*84612482Sminht * to resume within one second. 278*84612482Sminht */ 279*84612482Sminht void 280*84612482Sminht write_rtc_time(struct rtc_t *rtc) 281*84612482Sminht { 282*84612482Sminht uint8_t reg_cntrl; 283*84612482Sminht 284*84612482Sminht /* 285*84612482Sminht * Freeze 286*84612482Sminht */ 287*84612482Sminht reg_cntrl = BQ4802_DATA_REG(RTC_CNTRL); 288*84612482Sminht BQ4802_DATA_REG(RTC_CNTRL) = (reg_cntrl | RTC_UTI); 289*84612482Sminht 290*84612482Sminht BQ4802_DATA_REG(RTC_SEC) = BYTE_TO_BCD(rtc->rtc_sec); 291*84612482Sminht BQ4802_DATA_REG(RTC_MIN) = BYTE_TO_BCD(rtc->rtc_min); 292*84612482Sminht BQ4802_DATA_REG(RTC_HRS) = BYTE_TO_BCD(rtc->rtc_hrs); 293*84612482Sminht BQ4802_DATA_REG(RTC_DOM) = BYTE_TO_BCD(rtc->rtc_dom); 294*84612482Sminht BQ4802_DATA_REG(RTC_DOW) = BYTE_TO_BCD(rtc->rtc_dow); 295*84612482Sminht BQ4802_DATA_REG(RTC_MON) = BYTE_TO_BCD(rtc->rtc_mon); 296*84612482Sminht BQ4802_DATA_REG(RTC_YEAR) = BYTE_TO_BCD(rtc->rtc_year); 297*84612482Sminht BQ4802_DATA_REG(RTC_CENTURY) = BYTE_TO_BCD(rtc->rtc_century); 298*84612482Sminht 299*84612482Sminht /* 300*84612482Sminht * Unfreeze 301*84612482Sminht */ 302*84612482Sminht BQ4802_DATA_REG(RTC_CNTRL) = reg_cntrl; 303*84612482Sminht } 304*84612482Sminht 305*84612482Sminht void 306*84612482Sminht write_rtc_alarm(struct rtc_t *rtc) 307*84612482Sminht { 308*84612482Sminht BQ4802_DATA_REG(RTC_ASEC) = BYTE_TO_BCD(rtc->rtc_asec); 309*84612482Sminht BQ4802_DATA_REG(RTC_AMIN) = BYTE_TO_BCD(rtc->rtc_amin); 310*84612482Sminht BQ4802_DATA_REG(RTC_AHRS) = BYTE_TO_BCD(rtc->rtc_ahrs); 311*84612482Sminht BQ4802_DATA_REG(RTC_ADOM) = BYTE_TO_BCD(rtc->rtc_adom); 312*84612482Sminht } 313*84612482Sminht 314*84612482Sminht /* 315*84612482Sminht * program the rtc registers for alarm to go off at the specified time 316*84612482Sminht */ 317*84612482Sminht static void 318*84612482Sminht todbq4802_set_power_alarm(timestruc_t ts) 319*84612482Sminht { 320*84612482Sminht todinfo_t tod; 321*84612482Sminht uint8_t regc; 322*84612482Sminht struct rtc_t rtc; 323*84612482Sminht 324*84612482Sminht ASSERT(MUTEX_HELD(&tod_lock)); 325*84612482Sminht tod = utc_to_tod(ts.tv_sec); 326*84612482Sminht 327*84612482Sminht /* 328*84612482Sminht * disable alarms and clear AF flag by reading reg Flags (D) 329*84612482Sminht */ 330*84612482Sminht regc = BQ4802_DATA_REG(RTC_ENABLES); 331*84612482Sminht BQ4802_DATA_REG(RTC_ENABLES) = regc & ~(RTC_AIE | RTC_ABE); 332*84612482Sminht (void) BQ4802_DATA_REG(RTC_FLAGS); 333*84612482Sminht 334*84612482Sminht rtc.rtc_asec = (uint8_t)tod.tod_sec; 335*84612482Sminht rtc.rtc_amin = (uint8_t)tod.tod_min; 336*84612482Sminht rtc.rtc_ahrs = (uint8_t)tod.tod_hour; 337*84612482Sminht rtc.rtc_adom = (uint8_t)tod.tod_day; 338*84612482Sminht DPRINTF("todbq4802_set_alarm: dom=%d hrs=%d min=%d sec=%d\n", 339*84612482Sminht rtc.rtc_adom, rtc.rtc_ahrs, rtc.rtc_amin, rtc.rtc_asec); 340*84612482Sminht 341*84612482Sminht /* 342*84612482Sminht * Write alarm values and enable alarm 343*84612482Sminht */ 344*84612482Sminht write_rtc_alarm(&rtc); 345*84612482Sminht 346*84612482Sminht BQ4802_DATA_REG(RTC_ENABLES) = regc | RTC_AIE | RTC_ABE; 347*84612482Sminht } 348*84612482Sminht 349*84612482Sminht /* 350*84612482Sminht * clear alarm interrupt 351*84612482Sminht */ 352*84612482Sminht static void 353*84612482Sminht todbq4802_clear_power_alarm(void) 354*84612482Sminht { 355*84612482Sminht uint8_t regc; 356*84612482Sminht 357*84612482Sminht ASSERT(MUTEX_HELD(&tod_lock)); 358*84612482Sminht 359*84612482Sminht regc = BQ4802_DATA_REG(RTC_ENABLES); 360*84612482Sminht BQ4802_DATA_REG(RTC_ENABLES) = regc & ~(RTC_AIE | RTC_ABE); 361*84612482Sminht } 362*84612482Sminht 363*84612482Sminht /* 364*84612482Sminht * Determine the cpu frequency by watching the TOD chip rollover twice. 365*84612482Sminht * Cpu clock rate is determined by computing the ticks added (in tick register) 366*84612482Sminht * during one second interval on TOD. 367*84612482Sminht */ 368*84612482Sminht uint64_t 369*84612482Sminht todbq4802_get_cpufrequency(void) 370*84612482Sminht { 371*84612482Sminht ASSERT(MUTEX_HELD(&tod_lock)); 372*84612482Sminht return (find_cpufrequency((volatile uint8_t *)v_rtc_addr_reg)); 373*84612482Sminht } 374*84612482Sminht 375*84612482Sminht /*ARGSUSED*/ 376*84612482Sminht static uint_t 377*84612482Sminht todbq4802_set_watchdog_timer(uint_t timeoutval) 378*84612482Sminht { 379*84612482Sminht ASSERT(MUTEX_HELD(&tod_lock)); 380*84612482Sminht return (0); 381*84612482Sminht } 382*84612482Sminht 383*84612482Sminht static uint_t 384*84612482Sminht todbq4802_clear_watchdog_timer(void) 385*84612482Sminht { 386*84612482Sminht ASSERT(MUTEX_HELD(&tod_lock)); 387*84612482Sminht return (0); 388*84612482Sminht } 389