diff options
| author | Mark Brown <[email protected]> | 2015-10-12 18:09:27 +0100 | 
|---|---|---|
| committer | Mark Brown <[email protected]> | 2015-10-12 18:09:27 +0100 | 
| commit | 79828b4fa835f73cdaf4bffa48696abdcbea9d02 (patch) | |
| tree | 5e0fa7156acb75ba603022bc807df8f2fedb97a8 /drivers/rtc/rtc-sa1100.c | |
| parent | 721b51fcf91898299d96f4b72cb9434cda29dce6 (diff) | |
| parent | 8c1a9d6323abf0fb1e5dad96cf3f1c783505ea5a (diff) | |
Merge remote-tracking branch 'asoc/fix/rt5645' into asoc-fix-rt5645
Diffstat (limited to 'drivers/rtc/rtc-sa1100.c')
| -rw-r--r-- | drivers/rtc/rtc-sa1100.c | 139 | 
1 files changed, 84 insertions, 55 deletions
diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index b6e1ca08c2c0..c2187bf6c7e4 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -35,24 +35,17 @@  #include <linux/bitops.h>  #include <linux/io.h> -#include <mach/hardware.h> -#include <mach/irqs.h> +#define RTSR_HZE		BIT(3)	/* HZ interrupt enable */ +#define RTSR_ALE		BIT(2)	/* RTC alarm interrupt enable */ +#define RTSR_HZ			BIT(1)	/* HZ rising-edge detected */ +#define RTSR_AL			BIT(0)	/* RTC alarm detected */ -#if defined(CONFIG_ARCH_PXA) || defined(CONFIG_ARCH_MMP) -#include <mach/regs-rtc.h> -#endif +#include "rtc-sa1100.h"  #define RTC_DEF_DIVIDER		(32768 - 1)  #define RTC_DEF_TRIM		0  #define RTC_FREQ		1024 -struct sa1100_rtc { -	spinlock_t		lock; -	int			irq_1hz; -	int			irq_alarm; -	struct rtc_device	*rtc; -	struct clk		*clk; -};  static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id)  { @@ -63,16 +56,16 @@ static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id)  	spin_lock(&info->lock); -	rtsr = RTSR; +	rtsr = readl_relaxed(info->rtsr);  	/* clear interrupt sources */ -	RTSR = 0; +	writel_relaxed(0, info->rtsr);  	/* Fix for a nasty initialization problem the in SA11xx RTSR register.  	 * See also the comments in sa1100_rtc_probe(). */  	if (rtsr & (RTSR_ALE | RTSR_HZE)) {  		/* This is the original code, before there was the if test  		 * above. This code does not clear interrupts that were not  		 * enabled. */ -		RTSR = (RTSR_AL | RTSR_HZ) & (rtsr >> 2); +		writel_relaxed((RTSR_AL | RTSR_HZ) & (rtsr >> 2), info->rtsr);  	} else {  		/* For some reason, it is possible to enter this routine  		 * without interruptions enabled, it has been tested with @@ -81,13 +74,13 @@ static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id)  		 * This situation leads to an infinite "loop" of interrupt  		 * routine calling and as a result the processor seems to  		 * lock on its first call to open(). */ -		RTSR = RTSR_AL | RTSR_HZ; +		writel_relaxed(RTSR_AL | RTSR_HZ, info->rtsr);  	}  	/* clear alarm interrupt if it has occurred */  	if (rtsr & RTSR_AL)  		rtsr &= ~RTSR_ALE; -	RTSR = rtsr & (RTSR_ALE | RTSR_HZE); +	writel_relaxed(rtsr & (RTSR_ALE | RTSR_HZE), info->rtsr);  	/* update irq data & counter */  	if (rtsr & RTSR_AL) @@ -135,7 +128,7 @@ static void sa1100_rtc_release(struct device *dev)  	struct sa1100_rtc *info = dev_get_drvdata(dev);  	spin_lock_irq(&info->lock); -	RTSR = 0; +	writel_relaxed(0, info->rtsr);  	spin_unlock_irq(&info->lock);  	free_irq(info->irq_alarm, dev); @@ -144,39 +137,46 @@ static void sa1100_rtc_release(struct device *dev)  static int sa1100_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)  { +	u32 rtsr;  	struct sa1100_rtc *info = dev_get_drvdata(dev);  	spin_lock_irq(&info->lock); +	rtsr = readl_relaxed(info->rtsr);  	if (enabled) -		RTSR |= RTSR_ALE; +		rtsr |= RTSR_ALE;  	else -		RTSR &= ~RTSR_ALE; +		rtsr &= ~RTSR_ALE; +	writel_relaxed(rtsr, info->rtsr);  	spin_unlock_irq(&info->lock);  	return 0;  }  static int sa1100_rtc_read_time(struct device *dev, struct rtc_time *tm)  { -	rtc_time_to_tm(RCNR, tm); +	struct sa1100_rtc *info = dev_get_drvdata(dev); + +	rtc_time_to_tm(readl_relaxed(info->rcnr), tm);  	return 0;  }  static int sa1100_rtc_set_time(struct device *dev, struct rtc_time *tm)  { +	struct sa1100_rtc *info = dev_get_drvdata(dev);  	unsigned long time;  	int ret;  	ret = rtc_tm_to_time(tm, &time);  	if (ret == 0) -		RCNR = time; +		writel_relaxed(time, info->rcnr);  	return ret;  }  static int sa1100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)  {  	u32	rtsr; +	struct sa1100_rtc *info = dev_get_drvdata(dev); -	rtsr = RTSR; +	rtsr = readl_relaxed(info->rtsr);  	alrm->enabled = (rtsr & RTSR_ALE) ? 1 : 0;  	alrm->pending = (rtsr & RTSR_AL) ? 1 : 0;  	return 0; @@ -192,12 +192,13 @@ static int sa1100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)  	ret = rtc_tm_to_time(&alrm->time, &time);  	if (ret != 0)  		goto out; -	RTSR = RTSR & (RTSR_HZE|RTSR_ALE|RTSR_AL); -	RTAR = time; +	writel_relaxed(readl_relaxed(info->rtsr) & +		(RTSR_HZE | RTSR_ALE | RTSR_AL), info->rtsr); +	writel_relaxed(time, info->rtar);  	if (alrm->enabled) -		RTSR |= RTSR_ALE; +		writel_relaxed(readl_relaxed(info->rtsr) | RTSR_ALE, info->rtsr);  	else -		RTSR &= ~RTSR_ALE; +		writel_relaxed(readl_relaxed(info->rtsr) & ~RTSR_ALE, info->rtsr);  out:  	spin_unlock_irq(&info->lock); @@ -206,8 +207,10 @@ out:  static int sa1100_rtc_proc(struct device *dev, struct seq_file *seq)  { -	seq_printf(seq, "trim/divider\t\t: 0x%08x\n", (u32) RTTR); -	seq_printf(seq, "RTSR\t\t\t: 0x%08x\n", (u32)RTSR); +	struct sa1100_rtc *info = dev_get_drvdata(dev); + +	seq_printf(seq, "trim/divider\t\t: 0x%08x\n", readl_relaxed(info->rttr)); +	seq_printf(seq, "RTSR\t\t\t: 0x%08x\n", readl_relaxed(info->rtsr));  	return 0;  } @@ -223,29 +226,18 @@ static const struct rtc_class_ops sa1100_rtc_ops = {  	.alarm_irq_enable = sa1100_rtc_alarm_irq_enable,  }; -static int sa1100_rtc_probe(struct platform_device *pdev) +int sa1100_rtc_init(struct platform_device *pdev, struct sa1100_rtc *info)  {  	struct rtc_device *rtc; -	struct sa1100_rtc *info; -	int irq_1hz, irq_alarm, ret = 0; +	int ret; -	irq_1hz = platform_get_irq_byname(pdev, "rtc 1Hz"); -	irq_alarm = platform_get_irq_byname(pdev, "rtc alarm"); -	if (irq_1hz < 0 || irq_alarm < 0) -		return -ENODEV; +	spin_lock_init(&info->lock); -	info = devm_kzalloc(&pdev->dev, sizeof(struct sa1100_rtc), GFP_KERNEL); -	if (!info) -		return -ENOMEM;  	info->clk = devm_clk_get(&pdev->dev, NULL);  	if (IS_ERR(info->clk)) {  		dev_err(&pdev->dev, "failed to find rtc clock source\n");  		return PTR_ERR(info->clk);  	} -	info->irq_1hz = irq_1hz; -	info->irq_alarm = irq_alarm; -	spin_lock_init(&info->lock); -	platform_set_drvdata(pdev, info);  	ret = clk_prepare_enable(info->clk);  	if (ret) @@ -257,22 +249,19 @@ static int sa1100_rtc_probe(struct platform_device *pdev)  	 * If the clock divider is uninitialized then reset it to the  	 * default value to get the 1Hz clock.  	 */ -	if (RTTR == 0) { -		RTTR = RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16); +	if (readl_relaxed(info->rttr) == 0) { +		writel_relaxed(RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16), info->rttr);  		dev_warn(&pdev->dev, "warning: "  			"initializing default clock divider/trim value\n");  		/* The current RTC value probably doesn't make sense either */ -		RCNR = 0; +		writel_relaxed(0, info->rcnr);  	} -	device_init_wakeup(&pdev->dev, 1); -  	rtc = devm_rtc_device_register(&pdev->dev, pdev->name, &sa1100_rtc_ops,  					THIS_MODULE); -  	if (IS_ERR(rtc)) { -		ret = PTR_ERR(rtc); -		goto err_dev; +		clk_disable_unprepare(info->clk); +		return PTR_ERR(rtc);  	}  	info->rtc = rtc; @@ -298,12 +287,52 @@ static int sa1100_rtc_probe(struct platform_device *pdev)  	 *  	 * Notice that clearing bit 1 and 0 is accomplished by writting ONES to  	 * the corresponding bits in RTSR. */ -	RTSR = RTSR_AL | RTSR_HZ; +	writel_relaxed(RTSR_AL | RTSR_HZ, info->rtsr);  	return 0; -err_dev: -	clk_disable_unprepare(info->clk); -	return ret; +} +EXPORT_SYMBOL_GPL(sa1100_rtc_init); + +static int sa1100_rtc_probe(struct platform_device *pdev) +{ +	struct sa1100_rtc *info; +	struct resource *iores; +	void __iomem *base; +	int irq_1hz, irq_alarm; + +	irq_1hz = platform_get_irq_byname(pdev, "rtc 1Hz"); +	irq_alarm = platform_get_irq_byname(pdev, "rtc alarm"); +	if (irq_1hz < 0 || irq_alarm < 0) +		return -ENODEV; + +	info = devm_kzalloc(&pdev->dev, sizeof(struct sa1100_rtc), GFP_KERNEL); +	if (!info) +		return -ENOMEM; +	info->irq_1hz = irq_1hz; +	info->irq_alarm = irq_alarm; + +	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	base = devm_ioremap_resource(&pdev->dev, iores); +	if (IS_ERR(base)) +		return PTR_ERR(base); + +	if (IS_ENABLED(CONFIG_ARCH_SA1100) || +	    of_device_is_compatible(pdev->dev.of_node, "mrvl,sa1100-rtc")) { +		info->rcnr = base + 0x04; +		info->rtsr = base + 0x10; +		info->rtar = base + 0x00; +		info->rttr = base + 0x08; +	} else { +		info->rcnr = base + 0x0; +		info->rtsr = base + 0x8; +		info->rtar = base + 0x4; +		info->rttr = base + 0xc; +	} + +	platform_set_drvdata(pdev, info); +	device_init_wakeup(&pdev->dev, 1); + +	return sa1100_rtc_init(pdev, info);  }  static int sa1100_rtc_remove(struct platform_device *pdev)  |