import of ftp.dlink.com/GPL/DSMG-600_reB/ppclinux.tar.gz
[linux-2.4.21-pre4.git] / drivers / acpi / hardware / hwtimer.c
1
2 /******************************************************************************
3  *
4  * Name: hwtimer.c - ACPI Power Management Timer Interface
5  *              $Revision: 1.1.1.1 $
6  *
7  *****************************************************************************/
8
9 /*
10  *  Copyright (C) 2000, 2001 R. Byron Moore
11  *
12  *  This program is free software; you can redistribute it and/or modify
13  *  it under the terms of the GNU General Public License as published by
14  *  the Free Software Foundation; either version 2 of the License, or
15  *  (at your option) any later version.
16  *
17  *  This program is distributed in the hope that it will be useful,
18  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  *  GNU General Public License for more details.
21  *
22  *  You should have received a copy of the GNU General Public License
23  *  along with this program; if not, write to the Free Software
24  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25  */
26
27 #include "acpi.h"
28 #include "achware.h"
29
30 #define _COMPONENT          ACPI_HARDWARE
31          MODULE_NAME         ("hwtimer")
32
33
34 /******************************************************************************
35  *
36  * FUNCTION:    Acpi_get_timer_resolution
37  *
38  * PARAMETERS:  none
39  *
40  * RETURN:      Number of bits of resolution in the PM Timer (24 or 32).
41  *
42  * DESCRIPTION: Obtains resolution of the ACPI PM Timer.
43  *
44  ******************************************************************************/
45
46 acpi_status
47 acpi_get_timer_resolution (
48         u32                     *resolution)
49 {
50         FUNCTION_TRACE ("Acpi_get_timer_resolution");
51
52
53         if (!resolution) {
54                 return_ACPI_STATUS (AE_BAD_PARAMETER);
55         }
56
57         if (0 == acpi_gbl_FADT->tmr_val_ext) {
58                 *resolution = 24;
59         }
60
61         else {
62                 *resolution = 32;
63         }
64
65         return_ACPI_STATUS (AE_OK);
66 }
67
68
69 /******************************************************************************
70  *
71  * FUNCTION:    Acpi_get_timer
72  *
73  * PARAMETERS:  none
74  *
75  * RETURN:      Current value of the ACPI PM Timer (in ticks).
76  *
77  * DESCRIPTION: Obtains current value of ACPI PM Timer.
78  *
79  ******************************************************************************/
80
81 acpi_status
82 acpi_get_timer (
83         u32                     *ticks)
84 {
85         FUNCTION_TRACE ("Acpi_get_timer");
86
87
88         if (!ticks) {
89                 return_ACPI_STATUS (AE_BAD_PARAMETER);
90         }
91
92         acpi_os_read_port ((ACPI_IO_ADDRESS)
93                 ACPI_GET_ADDRESS (acpi_gbl_FADT->Xpm_tmr_blk.address), ticks, 32);
94
95         return_ACPI_STATUS (AE_OK);
96 }
97
98
99 /******************************************************************************
100  *
101  * FUNCTION:    Acpi_get_timer_duration
102  *
103  * PARAMETERS:  Start_ticks
104  *              End_ticks
105  *              Time_elapsed
106  *
107  * RETURN:      Time_elapsed
108  *
109  * DESCRIPTION: Computes the time elapsed (in microseconds) between two
110  *              PM Timer time stamps, taking into account the possibility of
111  *              rollovers, the timer resolution, and timer frequency.
112  *
113  *              The PM Timer's clock ticks at roughly 3.6 times per
114  *              _microsecond_, and its clock continues through Cx state
115  *              transitions (unlike many CPU timestamp counters) -- making it
116  *              a versatile and accurate timer.
117  *
118  *              Note that this function accomodates only a single timer
119  *              rollover.  Thus for 24-bit timers, this function should only
120  *              be used for calculating durations less than ~4.6 seconds
121  *              (~20 hours for 32-bit timers).
122  *
123  ******************************************************************************/
124
125 acpi_status
126 acpi_get_timer_duration (
127         u32                     start_ticks,
128         u32                     end_ticks,
129         u32                     *time_elapsed)
130 {
131         u32                     delta_ticks = 0;
132         u32                     seconds = 0;
133         u32                     milliseconds = 0;
134         u32                     microseconds = 0;
135         u32                     remainder = 0;
136
137
138         FUNCTION_TRACE ("Acpi_get_timer_duration");
139
140
141         if (!time_elapsed) {
142                 return_ACPI_STATUS (AE_BAD_PARAMETER);
143         }
144
145         /*
146          * Compute Tick Delta:
147          * -------------------
148          * Handle (max one) timer rollovers on 24- versus 32-bit timers.
149          */
150         if (start_ticks < end_ticks) {
151                 delta_ticks = end_ticks - start_ticks;
152         }
153
154         else if (start_ticks > end_ticks) {
155                 /* 24-bit Timer */
156
157                 if (0 == acpi_gbl_FADT->tmr_val_ext) {
158                         delta_ticks = (((0x00FFFFFF - start_ticks) + end_ticks) & 0x00FFFFFF);
159                 }
160
161                 /* 32-bit Timer */
162
163                 else {
164                         delta_ticks = (0xFFFFFFFF - start_ticks) + end_ticks;
165                 }
166         }
167
168         else {
169                 *time_elapsed = 0;
170                 return_ACPI_STATUS (AE_OK);
171         }
172
173         /*
174          * Compute Duration:
175          * -----------------
176          * Since certain compilers (gcc/Linux, argh!) don't support 64-bit
177          * divides in kernel-space we have to do some trickery to preserve
178          * accuracy while using 32-bit math.
179          *
180          * TBD: Change to use 64-bit math when supported.
181          *
182          * The process is as follows:
183          *  1. Compute the number of seconds by dividing Delta Ticks by
184          *     the timer frequency.
185          *  2. Compute the number of milliseconds in the remainder from step #1
186          *     by multiplying by 1000 and then dividing by the timer frequency.
187          *  3. Compute the number of microseconds in the remainder from step #2
188          *     by multiplying by 1000 and then dividing by the timer frequency.
189          *  4. Add the results from steps 1, 2, and 3 to get the total duration.
190          *
191          * Example: The time elapsed for Delta_ticks = 0xFFFFFFFF should be
192          *          1199864031 microseconds.  This is computed as follows:
193          *          Step #1: Seconds = 1199; Remainder = 3092840
194          *          Step #2: Milliseconds = 864; Remainder = 113120
195          *          Step #3: Microseconds = 31; Remainder = <don't care!>
196          */
197
198         /* Step #1 */
199
200         seconds = delta_ticks / PM_TIMER_FREQUENCY;
201         remainder = delta_ticks % PM_TIMER_FREQUENCY;
202
203         /* Step #2 */
204
205         milliseconds = (remainder * 1000) / PM_TIMER_FREQUENCY;
206         remainder = (remainder * 1000) % PM_TIMER_FREQUENCY;
207
208         /* Step #3 */
209
210         microseconds = (remainder * 1000) / PM_TIMER_FREQUENCY;
211
212         /* Step #4 */
213
214         *time_elapsed = seconds * 1000000;
215         *time_elapsed += milliseconds * 1000;
216         *time_elapsed += microseconds;
217
218         return_ACPI_STATUS (AE_OK);
219 }
220
221