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 | #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…
	
		Reference in a new issue
	
	 Marcelo Roberto Jimenez
						Marcelo Roberto Jimenez