RTC: sa1100: Update the sa1100 RTC driver.
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>
This commit is contained in:
parent
a417493ef9
commit
416f0e8056
@ -43,7 +43,6 @@
|
|||||||
#define RTC_DEF_TRIM 0
|
#define RTC_DEF_TRIM 0
|
||||||
|
|
||||||
static const unsigned long RTC_FREQ = 1024;
|
static const unsigned long RTC_FREQ = 1024;
|
||||||
static unsigned long timer_freq;
|
|
||||||
static struct rtc_time rtc_alarm;
|
static struct rtc_time rtc_alarm;
|
||||||
static DEFINE_SPINLOCK(sa1100_rtc_lock);
|
static DEFINE_SPINLOCK(sa1100_rtc_lock);
|
||||||
|
|
||||||
@ -156,97 +155,11 @@ static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id)
|
|||||||
return IRQ_HANDLED;
|
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)
|
static int sa1100_rtc_open(struct device *dev)
|
||||||
{
|
{
|
||||||
int ret;
|
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,
|
ret = request_irq(IRQ_RTC1Hz, sa1100_rtc_interrupt, IRQF_DISABLED,
|
||||||
"rtc 1Hz", dev);
|
"rtc 1Hz", dev);
|
||||||
@ -260,19 +173,11 @@ static int sa1100_rtc_open(struct device *dev)
|
|||||||
dev_err(dev, "IRQ %d already in use.\n", IRQ_RTCAlrm);
|
dev_err(dev, "IRQ %d already in use.\n", IRQ_RTCAlrm);
|
||||||
goto fail_ai;
|
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;
|
rtc->max_user_freq = RTC_FREQ;
|
||||||
sa1100_irq_set_freq(dev, RTC_FREQ);
|
rtc_irq_set_freq(rtc, NULL, RTC_FREQ);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fail_pi:
|
|
||||||
free_irq(IRQ_RTCAlrm, dev);
|
|
||||||
fail_ai:
|
fail_ai:
|
||||||
free_irq(IRQ_RTC1Hz, dev);
|
free_irq(IRQ_RTC1Hz, dev);
|
||||||
fail_ui:
|
fail_ui:
|
||||||
@ -287,12 +192,10 @@ static void sa1100_rtc_release(struct device *dev)
|
|||||||
OSSR = OSSR_M1;
|
OSSR = OSSR_M1;
|
||||||
spin_unlock_irq(&sa1100_rtc_lock);
|
spin_unlock_irq(&sa1100_rtc_lock);
|
||||||
|
|
||||||
free_irq(IRQ_OST1, dev);
|
|
||||||
free_irq(IRQ_RTCAlrm, dev);
|
free_irq(IRQ_RTCAlrm, dev);
|
||||||
free_irq(IRQ_RTC1Hz, dev);
|
free_irq(IRQ_RTC1Hz, dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int sa1100_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
static int sa1100_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
||||||
{
|
{
|
||||||
spin_lock_irq(&sa1100_rtc_lock);
|
spin_lock_irq(&sa1100_rtc_lock);
|
||||||
@ -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 = {
|
static const struct rtc_class_ops sa1100_rtc_ops = {
|
||||||
.open = sa1100_rtc_open,
|
.open = sa1100_rtc_open,
|
||||||
.read_callback = sa1100_rtc_read_callback,
|
|
||||||
.release = sa1100_rtc_release,
|
.release = sa1100_rtc_release,
|
||||||
.read_time = sa1100_rtc_read_time,
|
.read_time = sa1100_rtc_read_time,
|
||||||
.set_time = sa1100_rtc_set_time,
|
.set_time = sa1100_rtc_set_time,
|
||||||
@ -373,8 +275,6 @@ static int sa1100_rtc_probe(struct platform_device *pdev)
|
|||||||
{
|
{
|
||||||
struct rtc_device *rtc;
|
struct rtc_device *rtc;
|
||||||
|
|
||||||
timer_freq = get_clock_tick_rate();
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* According to the manual we should be able to let RTTR be zero
|
* 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.
|
* and then a default diviser for a 32.768KHz clock is used.
|
||||||
@ -400,11 +300,6 @@ static int sa1100_rtc_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
platform_set_drvdata(pdev, rtc);
|
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.
|
/* Fix for a nasty initialization problem the in SA11xx RTSR register.
|
||||||
* See also the comments in sa1100_rtc_interrupt().
|
* See also the comments in sa1100_rtc_interrupt().
|
||||||
*
|
*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user