4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
29 * tod driver module for TI BQ4802 part
31 * Note: The way to access the bq4802's RTC registers is different than
32 * the previous RTC devices (m5823, m5819p, ds1287, etc) that we used.
33 * The address returns from OBP is mapped directly to the bq4802's RTC
34 * registers. To read/write the data from/to the bq4802 registers, one
35 * just add the register offset to the base address.
36 * To access the previous RTC devices, we write the register index to
37 * the address port (v_rtc_addr_reg) then read/write the data from/to
38 * the data port (v_rtc_data_reg).
41 #include <sys/types.h>
46 #include <sys/sunddi.h>
47 #include <sys/sysmacros.h>
49 #include <sys/todbq4802.h>
50 #include <sys/modctl.h>
52 #include <sys/clock.h>
53 #include <sys/reboot.h>
54 #include <sys/machsystm.h>
57 * tod_ops entry routines
59 static timestruc_t
todbq4802_get(void);
60 static void todbq4802_set(timestruc_t
);
61 static uint_t
todbq4802_set_watchdog_timer(uint_t
);
62 static uint_t
todbq4802_clear_watchdog_timer(void);
63 static void todbq4802_set_power_alarm(timestruc_t
);
64 static void todbq4802_clear_power_alarm(void);
65 static uint64_t todbq4802_get_cpufrequency(void);
67 extern uint64_t find_cpufrequency(volatile uint8_t *);
72 extern int watchdog_enable
;
73 extern int watchdog_available
;
79 int bq4802_debug_flags
;
80 uint_t bq4802_hrestime_count
= 0;
81 uint_t bq4802_uip_count
= 0;
84 * Module linkage information for the kernel.
86 static struct modlmisc modlmisc
= {
87 &mod_miscops
, "tod module for TI BQ4802"
90 static struct modlinkage modlinkage
= {
91 MODREV_1
, (void *)&modlmisc
, NULL
94 static void read_rtc(struct rtc_t
*);
95 static void write_rtc_time(struct rtc_t
*);
96 static void write_rtc_alarm(struct rtc_t
*);
101 if (strcmp(tod_module_name
, "todbq4802") == 0) {
102 if (v_rtc_addr_reg
== NULL
)
103 cmn_err(CE_PANIC
, "addr not set, cannot read RTC\n");
105 BQ4802_DATA_REG(RTC_CNTRL
) = (RTC_HM
| RTC_STOP_N
);
107 /* Clear AF flag by reading reg Flags (D) */
108 (void) BQ4802_DATA_REG(RTC_FLAGS
);
110 tod_ops
.tod_get
= todbq4802_get
;
111 tod_ops
.tod_set
= todbq4802_set
;
112 tod_ops
.tod_set_watchdog_timer
=
113 todbq4802_set_watchdog_timer
;
114 tod_ops
.tod_clear_watchdog_timer
=
115 todbq4802_clear_watchdog_timer
;
116 tod_ops
.tod_set_power_alarm
= todbq4802_set_power_alarm
;
117 tod_ops
.tod_clear_power_alarm
= todbq4802_clear_power_alarm
;
118 tod_ops
.tod_get_cpufrequency
= todbq4802_get_cpufrequency
;
121 * check if hardware watchdog timer is available and user
124 if (watchdog_enable
) {
125 if (!watchdog_available
) {
126 cmn_err(CE_WARN
, "bq4802: Hardware watchdog "
128 } else if (boothowto
& RB_DEBUG
) {
129 cmn_err(CE_WARN
, "bq4802: Hardware watchdog"
130 " disabled [debugger]");
135 return (mod_install(&modlinkage
));
141 if (strcmp(tod_module_name
, "todbq4802") == 0)
144 return (mod_remove(&modlinkage
));
148 * The loadable-module _info(9E) entry point
151 _info(struct modinfo
*modinfop
)
153 return (mod_info(&modlinkage
, modinfop
));
157 * Read the current time from the clock chip and convert to UNIX form.
158 * Assumes that the year in the clock chip is valid.
159 * Must be called with tod_lock held.
168 ASSERT(MUTEX_HELD(&tod_lock
));
171 DPRINTF("todbq4802_get: century=%d year=%d dom=%d hrs=%d min=%d"
172 " sec=%d\n", rtc
.rtc_century
, rtc
.rtc_year
, rtc
.rtc_dom
,
173 rtc
.rtc_hrs
, rtc
.rtc_min
, rtc
.rtc_sec
);
176 * tod_year is base 1900 so this code needs to adjust the true
177 * year retrieved from the rtc's century and year fields.
179 tod
.tod_year
= rtc
.rtc_year
+ (rtc
.rtc_century
* 100) - 1900;
180 tod
.tod_month
= rtc
.rtc_mon
;
181 tod
.tod_day
= rtc
.rtc_dom
;
182 tod
.tod_dow
= rtc
.rtc_dow
;
183 tod
.tod_hour
= rtc
.rtc_hrs
;
184 tod
.tod_min
= rtc
.rtc_min
;
185 tod
.tod_sec
= rtc
.rtc_sec
;
187 ts
.tv_sec
= tod_to_utc(tod
);
193 * Once every second, the user-accessible clock/calendar
194 * locations are updated simultaneously from the internal
195 * real-time counters. To prevent reading data in transition,
196 * updates to the bq4802 clock registers should be halted.
197 * Updating is halted by setting the Update Transfer Inhibit
198 * (UTI) bit D3 of the control register E. As long as the
199 * UTI bit is 1, updates to user-accessible clock locations are
200 * inhibited. Once the frozen clock information is retrieved by
201 * reading the appropriate clock memory locations, the UTI
202 * bit should be reset to 0 in order to allow updates to occur
203 * from the internal counters. Because the internal counters
204 * are not halted by setting the UTI bit, reading the clock
205 * locations has no effect on clock accuracy. Once the UTI bit
206 * is reset to 0, the internal registers update within one
207 * second the user-accessible registers with the correct time.
208 * A halt command issued during a clock update allows the
209 * update to occur before freezing the data.
212 read_rtc(struct rtc_t
*rtc
)
219 reg_cntrl
= BQ4802_DATA_REG(RTC_CNTRL
);
220 BQ4802_DATA_REG(RTC_CNTRL
) = (reg_cntrl
| RTC_UTI
);
222 rtc
->rtc_sec
= BCD_TO_BYTE(BQ4802_DATA_REG(RTC_SEC
));
223 rtc
->rtc_asec
= BCD_TO_BYTE(BQ4802_DATA_REG(RTC_ASEC
));
224 rtc
->rtc_min
= BCD_TO_BYTE(BQ4802_DATA_REG(RTC_MIN
));
225 rtc
->rtc_amin
= BCD_TO_BYTE(BQ4802_DATA_REG(RTC_AMIN
));
226 rtc
->rtc_hrs
= BCD_TO_BYTE(BQ4802_DATA_REG(RTC_HRS
));
227 rtc
->rtc_ahrs
= BCD_TO_BYTE(BQ4802_DATA_REG(RTC_AHRS
));
228 rtc
->rtc_dom
= BCD_TO_BYTE(BQ4802_DATA_REG(RTC_DOM
));
229 rtc
->rtc_adom
= BCD_TO_BYTE(BQ4802_DATA_REG(RTC_ADOM
));
230 rtc
->rtc_dow
= BCD_TO_BYTE(BQ4802_DATA_REG(RTC_DOW
));
231 rtc
->rtc_mon
= BCD_TO_BYTE(BQ4802_DATA_REG(RTC_MON
));
232 rtc
->rtc_year
= BCD_TO_BYTE(BQ4802_DATA_REG(RTC_YEAR
));
233 rtc
->rtc_century
= BCD_TO_BYTE(BQ4802_DATA_REG(RTC_CENTURY
));
238 BQ4802_DATA_REG(RTC_CNTRL
) = reg_cntrl
;
242 * Write the specified time into the clock chip.
243 * Must be called with tod_lock held.
246 todbq4802_set(timestruc_t ts
)
249 todinfo_t tod
= utc_to_tod(ts
.tv_sec
);
252 ASSERT(MUTEX_HELD(&tod_lock
));
254 /* tod_year is base 1900 so this code needs to adjust */
255 year
= 1900 + tod
.tod_year
;
256 rtc
.rtc_year
= year
% 100;
257 rtc
.rtc_century
= year
/ 100;
258 rtc
.rtc_mon
= (uint8_t)tod
.tod_month
;
259 rtc
.rtc_dom
= (uint8_t)tod
.tod_day
;
260 rtc
.rtc_dow
= (uint8_t)tod
.tod_dow
;
261 rtc
.rtc_hrs
= (uint8_t)tod
.tod_hour
;
262 rtc
.rtc_min
= (uint8_t)tod
.tod_min
;
263 rtc
.rtc_sec
= (uint8_t)tod
.tod_sec
;
264 DPRINTF("todbq4802_set: year=%d dom=%d hrs=%d min=%d sec=%d\n",
265 rtc
.rtc_year
, rtc
.rtc_dom
, rtc
.rtc_hrs
, rtc
.rtc_min
, rtc
.rtc_sec
);
267 write_rtc_time(&rtc
);
271 * The UTI bit must be used to set the bq4802 clock.
272 * Once set, the locations can be written with the desired
273 * information in BCD format. Resetting the UTI bit to 0 causes
274 * the written values to be transferred to the internal clock
275 * counters and allows updates to the user-accessible registers
276 * to resume within one second.
279 write_rtc_time(struct rtc_t
*rtc
)
286 reg_cntrl
= BQ4802_DATA_REG(RTC_CNTRL
);
287 BQ4802_DATA_REG(RTC_CNTRL
) = (reg_cntrl
| RTC_UTI
);
289 BQ4802_DATA_REG(RTC_SEC
) = BYTE_TO_BCD(rtc
->rtc_sec
);
290 BQ4802_DATA_REG(RTC_MIN
) = BYTE_TO_BCD(rtc
->rtc_min
);
291 BQ4802_DATA_REG(RTC_HRS
) = BYTE_TO_BCD(rtc
->rtc_hrs
);
292 BQ4802_DATA_REG(RTC_DOM
) = BYTE_TO_BCD(rtc
->rtc_dom
);
293 BQ4802_DATA_REG(RTC_DOW
) = BYTE_TO_BCD(rtc
->rtc_dow
);
294 BQ4802_DATA_REG(RTC_MON
) = BYTE_TO_BCD(rtc
->rtc_mon
);
295 BQ4802_DATA_REG(RTC_YEAR
) = BYTE_TO_BCD(rtc
->rtc_year
);
296 BQ4802_DATA_REG(RTC_CENTURY
) = BYTE_TO_BCD(rtc
->rtc_century
);
301 BQ4802_DATA_REG(RTC_CNTRL
) = reg_cntrl
;
305 write_rtc_alarm(struct rtc_t
*rtc
)
307 BQ4802_DATA_REG(RTC_ASEC
) = BYTE_TO_BCD(rtc
->rtc_asec
);
308 BQ4802_DATA_REG(RTC_AMIN
) = BYTE_TO_BCD(rtc
->rtc_amin
);
309 BQ4802_DATA_REG(RTC_AHRS
) = BYTE_TO_BCD(rtc
->rtc_ahrs
);
310 BQ4802_DATA_REG(RTC_ADOM
) = BYTE_TO_BCD(rtc
->rtc_adom
);
314 * program the rtc registers for alarm to go off at the specified time
317 todbq4802_set_power_alarm(timestruc_t ts
)
323 ASSERT(MUTEX_HELD(&tod_lock
));
324 tod
= utc_to_tod(ts
.tv_sec
);
327 * disable alarms and clear AF flag by reading reg Flags (D)
329 regc
= BQ4802_DATA_REG(RTC_ENABLES
);
330 BQ4802_DATA_REG(RTC_ENABLES
) = regc
& ~(RTC_AIE
| RTC_ABE
);
331 (void) BQ4802_DATA_REG(RTC_FLAGS
);
333 rtc
.rtc_asec
= (uint8_t)tod
.tod_sec
;
334 rtc
.rtc_amin
= (uint8_t)tod
.tod_min
;
335 rtc
.rtc_ahrs
= (uint8_t)tod
.tod_hour
;
336 rtc
.rtc_adom
= (uint8_t)tod
.tod_day
;
337 DPRINTF("todbq4802_set_alarm: dom=%d hrs=%d min=%d sec=%d\n",
338 rtc
.rtc_adom
, rtc
.rtc_ahrs
, rtc
.rtc_amin
, rtc
.rtc_asec
);
341 * Write alarm values and enable alarm
343 write_rtc_alarm(&rtc
);
345 BQ4802_DATA_REG(RTC_ENABLES
) = regc
| RTC_AIE
| RTC_ABE
;
349 * clear alarm interrupt
352 todbq4802_clear_power_alarm(void)
356 ASSERT(MUTEX_HELD(&tod_lock
));
358 regc
= BQ4802_DATA_REG(RTC_ENABLES
);
359 BQ4802_DATA_REG(RTC_ENABLES
) = regc
& ~(RTC_AIE
| RTC_ABE
);
363 * Determine the cpu frequency by watching the TOD chip rollover twice.
364 * Cpu clock rate is determined by computing the ticks added (in tick register)
365 * during one second interval on TOD.
368 todbq4802_get_cpufrequency(void)
370 ASSERT(MUTEX_HELD(&tod_lock
));
371 return (find_cpufrequency((volatile uint8_t *)v_rtc_addr_reg
));
376 todbq4802_set_watchdog_timer(uint_t timeoutval
)
378 ASSERT(MUTEX_HELD(&tod_lock
));
383 todbq4802_clear_watchdog_timer(void)
385 ASSERT(MUTEX_HELD(&tod_lock
));