Project

General

Profile

Download (3.2 KB) Statistics
| Branch: | Tag: | Revision:
1
/* Periodic Interval Timer Implementation for OpenPCD
2
 * (C) 2006 by Harald Welte <hwelte@hmw-consulting.de>
3
 *
4
 *  This program is free software; you can redistribute it and/or modify
5
 *  it under the terms of the GNU General Public License as published by 
6
 *  the Free Software Foundation; either version 2 of the License, or
7
 *  (at your option) any later version.
8
 *
9
 *  This program is distributed in the hope that it will be useful,
10
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 *  GNU General Public License for more details.
13
 *
14
 *  You should have received a copy of the GNU General Public License
15
 *  along with this program; if not, write to the Free Software
16
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
 *
18
 *
19
 * TODO: handle jiffies wrap correctly!
20
 */
21

    
22
#include <errno.h>
23
#include <sys/types.h>
24
#include <asm/system.h>
25

    
26
#include <lib_AT91SAM7.h>
27
#include <AT91SAM7.h>
28
#include <os/pit.h>
29
#include <os/dbgu.h>
30
#include <os/system_irq.h>
31

    
32
#include "../openpcd.h"
33

    
34
/* PIT runs at MCK/16 (= 3MHz) */
35
#define PIV_MS(x)		(x * 3000)
36

    
37
static struct timer_list *timers;
38

    
39
volatile unsigned long jiffies;
40

    
41
static void __timer_insert(struct timer_list *new)
42
{
43
	struct timer_list *tl, *tl_prev = NULL;
44

    
45
	if (!timers) {
46
		/* optimize for the common, fast case */
47
		new->next = NULL;
48
		timers = new;
49
		return;
50
	}
51

    
52
	for (tl = timers; tl != NULL; tl = tl->next) {
53
		if (tl->expires < new->expires) {
54
			/* we need ot add just before this one */
55
			if (!tl_prev) {
56
				new->next = timers;
57
				timers = new;
58
			} else {
59
				new->next = tl;
60
				tl_prev->next = new;
61
			}
62
		}
63
		tl_prev = tl;
64
	}
65
}
66

    
67
static int __timer_remove(struct timer_list *old)
68
{
69
	struct timer_list *tl, *tl_prev = NULL;
70

    
71
	for (tl = timers; tl != NULL; tl = tl->next) {
72
		if (tl == old) {
73
			if (tl == timers)
74
				timers = tl->next;
75
			else
76
				tl_prev->next = tl->next;
77
			return 1;
78
		}
79
		tl_prev = tl;
80
	}
81

    
82
	return 0;
83
}
84

    
85
int timer_del(struct timer_list *tl)
86
{
87
	unsigned long flags;
88
	int ret;
89

    
90
	local_irq_save(flags);
91
	ret = __timer_remove(tl);
92
	local_irq_restore(flags);
93

    
94
	return ret;
95
}
96

    
97
void timer_add(struct timer_list *tl)
98
{
99
	unsigned long flags;
100

    
101
	local_irq_save(flags);
102
	__timer_insert(tl);
103
	local_irq_restore(flags);
104
}
105

    
106
static void pit_irq(uint32_t sr)
107
{
108
	struct timer_list *tl, *next;
109

    
110
	if (!(sr & 0x1))
111
		return;
112

    
113
	jiffies += *AT91C_PITC_PIVR >> 20;
114

    
115
	/* this is the most simple/stupid algorithm one can come up with, but
116
	 * hey, we're on a small embedded platform with only a hand ful
117
	 * of timers, at all */
118
	for (tl = timers; tl != NULL; tl = next) {
119
		next = tl->next;
120
		if (tl->expires <= jiffies) {
121
			/* delete timer from list */
122
			timer_del(tl);
123
			tl->function(tl->data);
124
		}
125
	}
126
}
127

    
128
void pit_mdelay(uint32_t ms)
129
{
130
	uint32_t end;
131

    
132
	end = (AT91F_PITGetPIIR(AT91C_BASE_PITC) + ms) % 20;
133

    
134
	while (end < AT91F_PITGetPIIR(AT91C_BASE_PITC)) { }
135
}
136

    
137
void mdelay(uint32_t ms)
138
{
139
	return pit_mdelay(ms);
140
}
141

    
142
void usleep(uint32_t us)
143
{
144
	return;
145
	return pit_mdelay(us/1000);
146
}
147

    
148
void pit_init(void)
149
{
150
	AT91F_PITC_CfgPMC();
151

    
152
	AT91F_PITInit(AT91C_BASE_PITC, 1000000/HZ /* uS */, 48 /* MHz */);
153

    
154
	sysirq_register(AT91SAM7_SYSIRQ_PIT, &pit_irq);	
155

    
156
	AT91F_PITEnableInt(AT91C_BASE_PITC);
157
}
(17-17/40)
Add picture from clipboard (Maximum size: 48.8 MB)