sam7fc/src/at91_pitc.c

105 lines
3.4 KiB
C
Raw Normal View History

2008-02-03 21:41:39 +01:00
/***************************************************************************
2008-06-23 15:33:07 +02:00
* sam7fc - Periodic Timer Handling *
* *
2008-02-03 21:41:39 +01:00
* Copyright (C) 01/2008 by Olaf Rempel *
* razzor@kopf-tisch.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; version 2 of the License *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "AT91SAM7S256.h"
#include "at91_pitc.h"
#include "at91_sysc.h"
#include "board.h"
2008-06-23 15:33:07 +02:00
#define PITC_HZ 1000
2008-02-03 21:41:39 +01:00
/* PIV is 20bit -> min. 3Hz @48MHz MCK */
#define HZ_TO_PIV(HZ) (MCK / (16 * HZ))
static LIST_HEAD(timer_list);
volatile static uint32_t pitc_ticks;
2008-06-23 15:33:07 +02:00
static void _pitc_schedule_timer(struct pitc_timer *timer)
2008-02-03 21:41:39 +01:00
{
timer->nextrun = timer->interval + pitc_ticks;
struct pitc_timer *search;
list_for_each_entry(search, &timer_list, list)
if (search->nextrun > timer->nextrun)
break;
list_add_tail(&timer->list, &search->list);
}
2008-06-23 15:33:07 +02:00
void pitc_schedule_timer(struct pitc_timer *timer)
{
/* disable PITC interrupt */
*AT91C_PITC_PIMR &= ~AT91C_PITC_PITIEN;
/* check it timer is already running */
if (timer->nextrun == 0 && timer->interval > 0)
_pitc_schedule_timer(timer);
// TODO: if timer is running, interval changes are delayed
/* enable PITC interrupt */
*AT91C_PITC_PIMR |= AT91C_PITC_PITIEN;
}
void pitc_remove_timer(struct pitc_timer *timer)
{
timer->interval = 0;
}
2008-02-03 21:41:39 +01:00
static void pitc_isr(uint32_t status)
{
/* get Ticks and clear interrupt */
pitc_ticks += (*AT91C_PITC_PIVR & AT91C_PITC_PICNT) >> 20;
2008-02-06 14:20:47 +01:00
2008-02-03 21:41:39 +01:00
struct pitc_timer *search, *tmp;
list_for_each_entry_safe(search, tmp, &timer_list, list) {
/* if this entry not scheduled yet, abort search */
if (pitc_ticks < search->nextrun)
break;
/* remove from list */
list_del(&search->list);
/* exec handler */
2008-06-23 15:33:07 +02:00
if ((search->interval == 0) || search->func(search) == PITC_REMOVE_TIMER) {
2008-02-03 21:41:39 +01:00
/* one-shot timer, mark as completed */
2008-06-23 15:33:07 +02:00
search->nextrun = 0;
2008-02-03 21:41:39 +01:00
continue;
}
2008-06-23 15:33:07 +02:00
2008-02-03 21:41:39 +01:00
/* interval timer, reschedule it */
2008-06-23 15:33:07 +02:00
_pitc_schedule_timer(search);
2008-02-03 21:41:39 +01:00
}
}
uint32_t pitc_get_ticks(void)
{
return pitc_ticks;
}
void at91_pitc_init(void)
{
sysc_register_isr(AT91_SYSIRQ_PIT, &pitc_isr);
2008-06-23 15:33:07 +02:00
*AT91C_PITC_PIMR = (AT91C_PITC_PIV & HZ_TO_PIV(PITC_HZ)) |
2008-02-03 21:41:39 +01:00
AT91C_PITC_PITEN |
AT91C_PITC_PITIEN;
}