Skip to content

Commit

Permalink
RTC: sa1100: Update the sa1100 RTC driver.
Browse files Browse the repository at this point in the history
Since PIE interrupts are now emulated, this patch removes the previous
code that used the hardware counters.

The removal of read_callback() also fixes a wrong user space behaviour
of this driver, which was not returning the right value to read().

[john.stultz: Merge fixups]

CC: Thomas Gleixner <tglx@linutronix.de>
CC: Alessandro Zummo <a.zummo@towertech.it>
CC: Marcelo Roberto Jimenez <mroberto@cpti.cetuc.puc-rio.br>
CC: rtc-linux@googlegroups.com
Signed-off-by: Marcelo Roberto Jimenez <mroberto@cpti.cetuc.puc-rio.br>
Signed-off-by: John Stultz <john.stultz@linaro.org>
  • Loading branch information
Marcelo Roberto Jimenez authored and John Stultz committed Mar 9, 2011
1 parent a417493 commit 416f0e8
Showing 1 changed file with 3 additions and 108 deletions.
111 changes: 3 additions & 108 deletions drivers/rtc/rtc-sa1100.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
#define RTC_DEF_TRIM 0

static const unsigned long RTC_FREQ = 1024;
static unsigned long timer_freq;
static struct rtc_time rtc_alarm;
static DEFINE_SPINLOCK(sa1100_rtc_lock);

Expand Down Expand Up @@ -156,97 +155,11 @@ static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}

static int sa1100_irq_set_freq(struct device *dev, int freq)
{
if (freq < 1 || freq > timer_freq) {
return -EINVAL;
} else {
struct rtc_device *rtc = (struct rtc_device *)dev;

rtc->irq_freq = freq;

return 0;
}
}

static int rtc_timer1_count;

static inline int sa1100_timer1_retrigger(struct rtc_device *rtc)
{
unsigned long diff;
unsigned long period = timer_freq / rtc->irq_freq;

spin_lock_irq(&sa1100_rtc_lock);

do {
OSMR1 += period;
diff = OSMR1 - OSCR;
/* If OSCR > OSMR1, diff is a very large number (unsigned
* math). This means we have a lost interrupt. */
} while (diff > period);
OIER |= OIER_E1;

spin_unlock_irq(&sa1100_rtc_lock);

return 0;
}

static irqreturn_t timer1_interrupt(int irq, void *dev_id)
{
struct platform_device *pdev = to_platform_device(dev_id);
struct rtc_device *rtc = platform_get_drvdata(pdev);

/*
* If we match for the first time, rtc_timer1_count will be 1.
* Otherwise, we wrapped around (very unlikely but
* still possible) so compute the amount of missed periods.
* The match reg is updated only when the data is actually retrieved
* to avoid unnecessary interrupts.
*/
OSSR = OSSR_M1; /* clear match on timer1 */

rtc_update_irq(rtc, rtc_timer1_count, RTC_PF | RTC_IRQF);

if (rtc_timer1_count == 1)
rtc_timer1_count =
(rtc->irq_freq * ((1 << 30) / (timer_freq >> 2)));

/* retrigger. */
sa1100_timer1_retrigger(rtc);

return IRQ_HANDLED;
}

static int sa1100_rtc_read_callback(struct device *dev, int data)
{
if (data & RTC_PF) {
struct rtc_device *rtc = (struct rtc_device *)dev;

/* interpolate missed periods and set match for the next */
unsigned long period = timer_freq / rtc->irq_freq;
unsigned long oscr = OSCR;
unsigned long osmr1 = OSMR1;
unsigned long missed = (oscr - osmr1)/period;
data += missed << 8;
OSSR = OSSR_M1; /* clear match on timer 1 */
OSMR1 = osmr1 + (missed + 1)*period;
/* Ensure we didn't miss another match in the mean time.
* Here we compare (match - OSCR) 8 instead of 0 --
* see comment in pxa_timer_interrupt() for explanation.
*/
while ((signed long)((osmr1 = OSMR1) - OSCR) <= 8) {
data += 0x100;
OSSR = OSSR_M1; /* clear match on timer 1 */
OSMR1 = osmr1 + period;
}
}
return data;
}

static int sa1100_rtc_open(struct device *dev)
{
int ret;
struct rtc_device *rtc = (struct rtc_device *)dev;
struct platform_device *plat_dev = to_platform_device(dev);
struct rtc_device *rtc = platform_get_drvdata(plat_dev);

ret = request_irq(IRQ_RTC1Hz, sa1100_rtc_interrupt, IRQF_DISABLED,
"rtc 1Hz", dev);
Expand All @@ -260,19 +173,11 @@ static int sa1100_rtc_open(struct device *dev)
dev_err(dev, "IRQ %d already in use.\n", IRQ_RTCAlrm);
goto fail_ai;
}
ret = request_irq(IRQ_OST1, timer1_interrupt, IRQF_DISABLED,
"rtc timer", dev);
if (ret) {
dev_err(dev, "IRQ %d already in use.\n", IRQ_OST1);
goto fail_pi;
}
rtc->max_user_freq = RTC_FREQ;
sa1100_irq_set_freq(dev, RTC_FREQ);
rtc_irq_set_freq(rtc, NULL, RTC_FREQ);

return 0;

fail_pi:
free_irq(IRQ_RTCAlrm, dev);
fail_ai:
free_irq(IRQ_RTC1Hz, dev);
fail_ui:
Expand All @@ -287,12 +192,10 @@ static void sa1100_rtc_release(struct device *dev)
OSSR = OSSR_M1;
spin_unlock_irq(&sa1100_rtc_lock);

free_irq(IRQ_OST1, dev);
free_irq(IRQ_RTCAlrm, dev);
free_irq(IRQ_RTC1Hz, dev);
}


static int sa1100_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
spin_lock_irq(&sa1100_rtc_lock);
Expand Down Expand Up @@ -359,7 +262,6 @@ static int sa1100_rtc_proc(struct device *dev, struct seq_file *seq)

static const struct rtc_class_ops sa1100_rtc_ops = {
.open = sa1100_rtc_open,
.read_callback = sa1100_rtc_read_callback,
.release = sa1100_rtc_release,
.read_time = sa1100_rtc_read_time,
.set_time = sa1100_rtc_set_time,
Expand All @@ -373,8 +275,6 @@ static int sa1100_rtc_probe(struct platform_device *pdev)
{
struct rtc_device *rtc;

timer_freq = get_clock_tick_rate();

/*
* According to the manual we should be able to let RTTR be zero
* and then a default diviser for a 32.768KHz clock is used.
Expand All @@ -400,11 +300,6 @@ static int sa1100_rtc_probe(struct platform_device *pdev)

platform_set_drvdata(pdev, rtc);

/* Set the irq_freq */
/*TODO: Find out who is messing with this value after we initialize
* it here.*/
rtc->irq_freq = RTC_FREQ;

/* Fix for a nasty initialization problem the in SA11xx RTSR register.
* See also the comments in sa1100_rtc_interrupt().
*
Expand Down

0 comments on commit 416f0e8

Please sign in to comment.