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 (the "License").
6 * You may not use this file except in compliance with the License.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#pragma ident	"%Z%%M%	%I%	%E% SMI"
27
28/*
29 * tod driver module for TI BQ4802 part
30 *
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).
39 */
40
41#include <sys/types.h>
42#include <sys/conf.h>
43#include <sys/kmem.h>
44#include <sys/open.h>
45#include <sys/ddi.h>
46#include <sys/sunddi.h>
47#include <sys/sysmacros.h>
48
49#include <sys/todbq4802.h>
50#include <sys/modctl.h>
51#include <sys/stat.h>
52#include <sys/clock.h>
53#include <sys/reboot.h>
54#include <sys/machsystm.h>
55
56/*
57 * tod_ops entry routines
58 */
59static timestruc_t	todbq4802_get(void);
60static void		todbq4802_set(timestruc_t);
61static uint_t		todbq4802_set_watchdog_timer(uint_t);
62static uint_t		todbq4802_clear_watchdog_timer(void);
63static void		todbq4802_set_power_alarm(timestruc_t);
64static void		todbq4802_clear_power_alarm(void);
65static uint64_t		todbq4802_get_cpufrequency(void);
66
67extern uint64_t		find_cpufrequency(volatile uint8_t *);
68
69/*
70 * External variables
71 */
72extern int watchdog_enable;
73extern int watchdog_available;
74extern int boothowto;
75
76/*
77 * Global variables
78 */
79int bq4802_debug_flags;
80uint_t bq4802_hrestime_count = 0;
81uint_t bq4802_uip_count = 0;
82
83/*
84 * Module linkage information for the kernel.
85 */
86static struct modlmisc modlmisc = {
87	&mod_miscops, "tod module for TI BQ4802"
88};
89
90static struct modlinkage modlinkage = {
91	MODREV_1, (void *)&modlmisc, NULL
92};
93
94static void read_rtc(struct rtc_t *);
95static void write_rtc_time(struct rtc_t *);
96static void write_rtc_alarm(struct rtc_t *);
97
98int
99_init(void)
100{
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");
104
105		BQ4802_DATA_REG(RTC_CNTRL) = (RTC_HM | RTC_STOP_N);
106
107		/* Clear AF flag by reading reg Flags (D) */
108		(void) BQ4802_DATA_REG(RTC_FLAGS);
109
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;
119
120		/*
121		 * check if hardware watchdog timer is available and user
122		 * enabled it.
123		 */
124		if (watchdog_enable) {
125			if (!watchdog_available) {
126				cmn_err(CE_WARN, "bq4802: Hardware watchdog "
127				    "unavailable");
128			} else if (boothowto & RB_DEBUG) {
129				cmn_err(CE_WARN, "bq4802: Hardware watchdog"
130				    " disabled [debugger]");
131			}
132		}
133	}
134
135	return (mod_install(&modlinkage));
136}
137
138int
139_fini(void)
140{
141	if (strcmp(tod_module_name, "todbq4802") == 0)
142		return (EBUSY);
143
144	return (mod_remove(&modlinkage));
145}
146
147/*
148 * The loadable-module _info(9E) entry point
149 */
150int
151_info(struct modinfo *modinfop)
152{
153	return (mod_info(&modlinkage, modinfop));
154}
155
156/*
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.
160 */
161static timestruc_t
162todbq4802_get(void)
163{
164	timestruc_t ts;
165	todinfo_t tod;
166	struct rtc_t rtc;
167
168	ASSERT(MUTEX_HELD(&tod_lock));
169
170	read_rtc(&rtc);
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);
174
175	/*
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.
178	 */
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;
186
187	ts.tv_sec = tod_to_utc(tod);
188	ts.tv_nsec = 0;
189	return (ts);
190}
191
192/*
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.
210 */
211static void
212read_rtc(struct rtc_t *rtc)
213{
214	uint8_t	reg_cntrl;
215
216	/*
217	 * Freeze
218	 */
219	reg_cntrl = BQ4802_DATA_REG(RTC_CNTRL);
220	BQ4802_DATA_REG(RTC_CNTRL) = (reg_cntrl | RTC_UTI);
221
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));
234
235	/*
236	 * Unfreeze
237	 */
238	BQ4802_DATA_REG(RTC_CNTRL) = reg_cntrl;
239}
240
241/*
242 * Write the specified time into the clock chip.
243 * Must be called with tod_lock held.
244 */
245static void
246todbq4802_set(timestruc_t ts)
247{
248	struct rtc_t	rtc;
249	todinfo_t tod = utc_to_tod(ts.tv_sec);
250	int year;
251
252	ASSERT(MUTEX_HELD(&tod_lock));
253
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);
266
267	write_rtc_time(&rtc);
268}
269
270/*
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.
277 */
278void
279write_rtc_time(struct rtc_t *rtc)
280{
281	uint8_t	reg_cntrl;
282
283	/*
284	 * Freeze
285	 */
286	reg_cntrl = BQ4802_DATA_REG(RTC_CNTRL);
287	BQ4802_DATA_REG(RTC_CNTRL) = (reg_cntrl | RTC_UTI);
288
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);
297
298	/*
299	 * Unfreeze
300	 */
301	BQ4802_DATA_REG(RTC_CNTRL) = reg_cntrl;
302}
303
304void
305write_rtc_alarm(struct rtc_t *rtc)
306{
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);
311}
312
313/*
314 * program the rtc registers for alarm to go off at the specified time
315 */
316static void
317todbq4802_set_power_alarm(timestruc_t ts)
318{
319	todinfo_t	tod;
320	uint8_t		regc;
321	struct rtc_t	rtc;
322
323	ASSERT(MUTEX_HELD(&tod_lock));
324	tod = utc_to_tod(ts.tv_sec);
325
326	/*
327	 * disable alarms and clear AF flag by reading reg Flags (D)
328	 */
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);
332
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);
339
340	/*
341	 * Write alarm values and enable alarm
342	 */
343	write_rtc_alarm(&rtc);
344
345	BQ4802_DATA_REG(RTC_ENABLES) = regc | RTC_AIE | RTC_ABE;
346}
347
348/*
349 * clear alarm interrupt
350 */
351static void
352todbq4802_clear_power_alarm(void)
353{
354	uint8_t regc;
355
356	ASSERT(MUTEX_HELD(&tod_lock));
357
358	regc = BQ4802_DATA_REG(RTC_ENABLES);
359	BQ4802_DATA_REG(RTC_ENABLES) = regc & ~(RTC_AIE | RTC_ABE);
360}
361
362/*
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.
366 */
367uint64_t
368todbq4802_get_cpufrequency(void)
369{
370	ASSERT(MUTEX_HELD(&tod_lock));
371	return (find_cpufrequency((volatile uint8_t *)v_rtc_addr_reg));
372}
373
374/*ARGSUSED*/
375static uint_t
376todbq4802_set_watchdog_timer(uint_t timeoutval)
377{
378	ASSERT(MUTEX_HELD(&tod_lock));
379	return (0);
380}
381
382static uint_t
383todbq4802_clear_watchdog_timer(void)
384{
385	ASSERT(MUTEX_HELD(&tod_lock));
386	return (0);
387}
388