~ubuntu-branches/ubuntu/utopic/linux-ti-omap/utopic

« back to all changes in this revision

Viewing changes to arch/arm/kernel/time.c

  • Committer: Bazaar Package Importer
  • Author(s): Amit Kucheria, Amit Kucheria
  • Date: 2010-03-10 02:28:15 UTC
  • Revision ID: james.westby@ubuntu.com-20100310022815-7sd3gwvn5kenaq33
Tags: 2.6.33-500.1
[ Amit Kucheria ]

* Initial release of a 2.6.33-based OMAP kernel
* UBUNTU: [Upstream] Fix omap 1-wire driver compilation
* UBUNTU: ubuntu: AppArmor -- update to mainline 2010-03-04

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  linux/arch/arm/kernel/time.c
 
3
 *
 
4
 *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
 
5
 *  Modifications for ARM (C) 1994-2001 Russell King
 
6
 *
 
7
 * This program is free software; you can redistribute it and/or modify
 
8
 * it under the terms of the GNU General Public License version 2 as
 
9
 * published by the Free Software Foundation.
 
10
 *
 
11
 *  This file contains the ARM-specific time handling details:
 
12
 *  reading the RTC at bootup, etc...
 
13
 *
 
14
 *  1994-07-02  Alan Modra
 
15
 *              fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime
 
16
 *  1998-12-20  Updated NTP code according to technical memorandum Jan '96
 
17
 *              "A Kernel Model for Precision Timekeeping" by Dave Mills
 
18
 */
 
19
#include <linux/module.h>
 
20
#include <linux/kernel.h>
 
21
#include <linux/interrupt.h>
 
22
#include <linux/time.h>
 
23
#include <linux/init.h>
 
24
#include <linux/sched.h>
 
25
#include <linux/smp.h>
 
26
#include <linux/timex.h>
 
27
#include <linux/errno.h>
 
28
#include <linux/profile.h>
 
29
#include <linux/sysdev.h>
 
30
#include <linux/timer.h>
 
31
#include <linux/irq.h>
 
32
 
 
33
#include <linux/mc146818rtc.h>
 
34
 
 
35
#include <asm/leds.h>
 
36
#include <asm/thread_info.h>
 
37
#include <asm/stacktrace.h>
 
38
#include <asm/mach/time.h>
 
39
 
 
40
/*
 
41
 * Our system timer.
 
42
 */
 
43
struct sys_timer *system_timer;
 
44
 
 
45
#if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE)
 
46
/* this needs a better home */
 
47
DEFINE_SPINLOCK(rtc_lock);
 
48
 
 
49
#ifdef CONFIG_RTC_DRV_CMOS_MODULE
 
50
EXPORT_SYMBOL(rtc_lock);
 
51
#endif
 
52
#endif  /* pc-style 'CMOS' RTC support */
 
53
 
 
54
/* change this if you have some constant time drift */
 
55
#define USECS_PER_JIFFY (1000000/HZ)
 
56
 
 
57
#ifdef CONFIG_SMP
 
58
unsigned long profile_pc(struct pt_regs *regs)
 
59
{
 
60
        struct stackframe frame;
 
61
 
 
62
        if (!in_lock_functions(regs->ARM_pc))
 
63
                return regs->ARM_pc;
 
64
 
 
65
        frame.fp = regs->ARM_fp;
 
66
        frame.sp = regs->ARM_sp;
 
67
        frame.lr = regs->ARM_lr;
 
68
        frame.pc = regs->ARM_pc;
 
69
        do {
 
70
                int ret = unwind_frame(&frame);
 
71
                if (ret < 0)
 
72
                        return 0;
 
73
        } while (in_lock_functions(frame.pc));
 
74
 
 
75
        return frame.pc;
 
76
}
 
77
EXPORT_SYMBOL(profile_pc);
 
78
#endif
 
79
 
 
80
/*
 
81
 * hook for setting the RTC's idea of the current time.
 
82
 */
 
83
int (*set_rtc)(void);
 
84
 
 
85
#ifndef CONFIG_GENERIC_TIME
 
86
static unsigned long dummy_gettimeoffset(void)
 
87
{
 
88
        return 0;
 
89
}
 
90
#endif
 
91
 
 
92
static unsigned long next_rtc_update;
 
93
 
 
94
/*
 
95
 * If we have an externally synchronized linux clock, then update
 
96
 * CMOS clock accordingly every ~11 minutes.  set_rtc() has to be
 
97
 * called as close as possible to 500 ms before the new second
 
98
 * starts.
 
99
 */
 
100
static inline void do_set_rtc(void)
 
101
{
 
102
        if (!ntp_synced() || set_rtc == NULL)
 
103
                return;
 
104
 
 
105
        if (next_rtc_update &&
 
106
            time_before((unsigned long)xtime.tv_sec, next_rtc_update))
 
107
                return;
 
108
 
 
109
        if (xtime.tv_nsec < 500000000 - ((unsigned) tick_nsec >> 1) &&
 
110
            xtime.tv_nsec >= 500000000 + ((unsigned) tick_nsec >> 1))
 
111
                return;
 
112
 
 
113
        if (set_rtc())
 
114
                /*
 
115
                 * rtc update failed.  Try again in 60s
 
116
                 */
 
117
                next_rtc_update = xtime.tv_sec + 60;
 
118
        else
 
119
                next_rtc_update = xtime.tv_sec + 660;
 
120
}
 
121
 
 
122
#ifdef CONFIG_LEDS
 
123
 
 
124
static void dummy_leds_event(led_event_t evt)
 
125
{
 
126
}
 
127
 
 
128
void (*leds_event)(led_event_t) = dummy_leds_event;
 
129
 
 
130
struct leds_evt_name {
 
131
        const char      name[8];
 
132
        int             on;
 
133
        int             off;
 
134
};
 
135
 
 
136
static const struct leds_evt_name evt_names[] = {
 
137
        { "amber", led_amber_on, led_amber_off },
 
138
        { "blue",  led_blue_on,  led_blue_off  },
 
139
        { "green", led_green_on, led_green_off },
 
140
        { "red",   led_red_on,   led_red_off   },
 
141
};
 
142
 
 
143
static ssize_t leds_store(struct sys_device *dev,
 
144
                        struct sysdev_attribute *attr,
 
145
                        const char *buf, size_t size)
 
146
{
 
147
        int ret = -EINVAL, len = strcspn(buf, " ");
 
148
 
 
149
        if (len > 0 && buf[len] == '\0')
 
150
                len--;
 
151
 
 
152
        if (strncmp(buf, "claim", len) == 0) {
 
153
                leds_event(led_claim);
 
154
                ret = size;
 
155
        } else if (strncmp(buf, "release", len) == 0) {
 
156
                leds_event(led_release);
 
157
                ret = size;
 
158
        } else {
 
159
                int i;
 
160
 
 
161
                for (i = 0; i < ARRAY_SIZE(evt_names); i++) {
 
162
                        if (strlen(evt_names[i].name) != len ||
 
163
                            strncmp(buf, evt_names[i].name, len) != 0)
 
164
                                continue;
 
165
                        if (strncmp(buf+len, " on", 3) == 0) {
 
166
                                leds_event(evt_names[i].on);
 
167
                                ret = size;
 
168
                        } else if (strncmp(buf+len, " off", 4) == 0) {
 
169
                                leds_event(evt_names[i].off);
 
170
                                ret = size;
 
171
                        }
 
172
                        break;
 
173
                }
 
174
        }
 
175
        return ret;
 
176
}
 
177
 
 
178
static SYSDEV_ATTR(event, 0200, NULL, leds_store);
 
179
 
 
180
static int leds_suspend(struct sys_device *dev, pm_message_t state)
 
181
{
 
182
        leds_event(led_stop);
 
183
        return 0;
 
184
}
 
185
 
 
186
static int leds_resume(struct sys_device *dev)
 
187
{
 
188
        leds_event(led_start);
 
189
        return 0;
 
190
}
 
191
 
 
192
static int leds_shutdown(struct sys_device *dev)
 
193
{
 
194
        leds_event(led_halted);
 
195
        return 0;
 
196
}
 
197
 
 
198
static struct sysdev_class leds_sysclass = {
 
199
        .name           = "leds",
 
200
        .shutdown       = leds_shutdown,
 
201
        .suspend        = leds_suspend,
 
202
        .resume         = leds_resume,
 
203
};
 
204
 
 
205
static struct sys_device leds_device = {
 
206
        .id             = 0,
 
207
        .cls            = &leds_sysclass,
 
208
};
 
209
 
 
210
static int __init leds_init(void)
 
211
{
 
212
        int ret;
 
213
        ret = sysdev_class_register(&leds_sysclass);
 
214
        if (ret == 0)
 
215
                ret = sysdev_register(&leds_device);
 
216
        if (ret == 0)
 
217
                ret = sysdev_create_file(&leds_device, &attr_event);
 
218
        return ret;
 
219
}
 
220
 
 
221
device_initcall(leds_init);
 
222
 
 
223
EXPORT_SYMBOL(leds_event);
 
224
#endif
 
225
 
 
226
#ifdef CONFIG_LEDS_TIMER
 
227
static inline void do_leds(void)
 
228
{
 
229
        static unsigned int count = HZ/2;
 
230
 
 
231
        if (--count == 0) {
 
232
                count = HZ/2;
 
233
                leds_event(led_timer);
 
234
        }
 
235
}
 
236
#else
 
237
#define do_leds()
 
238
#endif
 
239
 
 
240
#ifndef CONFIG_GENERIC_TIME
 
241
void do_gettimeofday(struct timeval *tv)
 
242
{
 
243
        unsigned long flags;
 
244
        unsigned long seq;
 
245
        unsigned long usec, sec;
 
246
 
 
247
        do {
 
248
                seq = read_seqbegin_irqsave(&xtime_lock, flags);
 
249
                usec = system_timer->offset();
 
250
                sec = xtime.tv_sec;
 
251
                usec += xtime.tv_nsec / 1000;
 
252
        } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
 
253
 
 
254
        /* usec may have gone up a lot: be safe */
 
255
        while (usec >= 1000000) {
 
256
                usec -= 1000000;
 
257
                sec++;
 
258
        }
 
259
 
 
260
        tv->tv_sec = sec;
 
261
        tv->tv_usec = usec;
 
262
}
 
263
 
 
264
EXPORT_SYMBOL(do_gettimeofday);
 
265
 
 
266
int do_settimeofday(struct timespec *tv)
 
267
{
 
268
        time_t wtm_sec, sec = tv->tv_sec;
 
269
        long wtm_nsec, nsec = tv->tv_nsec;
 
270
 
 
271
        if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
 
272
                return -EINVAL;
 
273
 
 
274
        write_seqlock_irq(&xtime_lock);
 
275
        /*
 
276
         * This is revolting. We need to set "xtime" correctly. However, the
 
277
         * value in this location is the value at the most recent update of
 
278
         * wall time.  Discover what correction gettimeofday() would have
 
279
         * done, and then undo it!
 
280
         */
 
281
        nsec -= system_timer->offset() * NSEC_PER_USEC;
 
282
 
 
283
        wtm_sec  = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
 
284
        wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
 
285
 
 
286
        set_normalized_timespec(&xtime, sec, nsec);
 
287
        set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
 
288
 
 
289
        ntp_clear();
 
290
        write_sequnlock_irq(&xtime_lock);
 
291
        clock_was_set();
 
292
        return 0;
 
293
}
 
294
 
 
295
EXPORT_SYMBOL(do_settimeofday);
 
296
#endif /* !CONFIG_GENERIC_TIME */
 
297
 
 
298
/**
 
299
 * save_time_delta - Save the offset between system time and RTC time
 
300
 * @delta: pointer to timespec to store delta
 
301
 * @rtc: pointer to timespec for current RTC time
 
302
 *
 
303
 * Return a delta between the system time and the RTC time, such
 
304
 * that system time can be restored later with restore_time_delta()
 
305
 */
 
306
void save_time_delta(struct timespec *delta, struct timespec *rtc)
 
307
{
 
308
        set_normalized_timespec(delta,
 
309
                                xtime.tv_sec - rtc->tv_sec,
 
310
                                xtime.tv_nsec - rtc->tv_nsec);
 
311
}
 
312
EXPORT_SYMBOL(save_time_delta);
 
313
 
 
314
/**
 
315
 * restore_time_delta - Restore the current system time
 
316
 * @delta: delta returned by save_time_delta()
 
317
 * @rtc: pointer to timespec for current RTC time
 
318
 */
 
319
void restore_time_delta(struct timespec *delta, struct timespec *rtc)
 
320
{
 
321
        struct timespec ts;
 
322
 
 
323
        set_normalized_timespec(&ts,
 
324
                                delta->tv_sec + rtc->tv_sec,
 
325
                                delta->tv_nsec + rtc->tv_nsec);
 
326
 
 
327
        do_settimeofday(&ts);
 
328
}
 
329
EXPORT_SYMBOL(restore_time_delta);
 
330
 
 
331
#ifndef CONFIG_GENERIC_CLOCKEVENTS
 
332
/*
 
333
 * Kernel system timer support.
 
334
 */
 
335
void timer_tick(void)
 
336
{
 
337
        profile_tick(CPU_PROFILING);
 
338
        do_leds();
 
339
        do_set_rtc();
 
340
        write_seqlock(&xtime_lock);
 
341
        do_timer(1);
 
342
        write_sequnlock(&xtime_lock);
 
343
#ifndef CONFIG_SMP
 
344
        update_process_times(user_mode(get_irq_regs()));
 
345
#endif
 
346
}
 
347
#endif
 
348
 
 
349
#if defined(CONFIG_PM) && !defined(CONFIG_GENERIC_CLOCKEVENTS)
 
350
static int timer_suspend(struct sys_device *dev, pm_message_t state)
 
351
{
 
352
        struct sys_timer *timer = container_of(dev, struct sys_timer, dev);
 
353
 
 
354
        if (timer->suspend != NULL)
 
355
                timer->suspend();
 
356
 
 
357
        return 0;
 
358
}
 
359
 
 
360
static int timer_resume(struct sys_device *dev)
 
361
{
 
362
        struct sys_timer *timer = container_of(dev, struct sys_timer, dev);
 
363
 
 
364
        if (timer->resume != NULL)
 
365
                timer->resume();
 
366
 
 
367
        return 0;
 
368
}
 
369
#else
 
370
#define timer_suspend NULL
 
371
#define timer_resume NULL
 
372
#endif
 
373
 
 
374
static struct sysdev_class timer_sysclass = {
 
375
        .name           = "timer",
 
376
        .suspend        = timer_suspend,
 
377
        .resume         = timer_resume,
 
378
};
 
379
 
 
380
static int __init timer_init_sysfs(void)
 
381
{
 
382
        int ret = sysdev_class_register(&timer_sysclass);
 
383
        if (ret == 0) {
 
384
                system_timer->dev.cls = &timer_sysclass;
 
385
                ret = sysdev_register(&system_timer->dev);
 
386
        }
 
387
 
 
388
        return ret;
 
389
}
 
390
 
 
391
device_initcall(timer_init_sysfs);
 
392
 
 
393
void __init time_init(void)
 
394
{
 
395
#ifndef CONFIG_GENERIC_TIME
 
396
        if (system_timer->offset == NULL)
 
397
                system_timer->offset = dummy_gettimeoffset;
 
398
#endif
 
399
        system_timer->init();
 
400
}
 
401