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