forked from mirrors/linux
		
	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
					
				
					 1 changed files with 3 additions and 108 deletions
				
			
		|  | @ -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); | ||||
| 
 | ||||
|  | @ -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); | ||||
|  | @ -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: | ||||
|  | @ -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); | ||||
|  | @ -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, | ||||
|  | @ -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. | ||||
|  | @ -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(). | ||||
| 	 * | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Marcelo Roberto Jimenez
						Marcelo Roberto Jimenez