diff mbox

[RFC] rtc-omap: Fix alarm interrupts on DRA7xx

Message ID 1469640662.30993.6.camel@codethink.co.uk (mailing list archive)
State New, archived
Headers show

Commit Message

Ben Hutchings July 27, 2016, 5:31 p.m. UTC
On DRA7xx chips (and maybe others), the reset configuration of the RTC
does not allow it to wake up from idle when it's ready to generate an
interrupt.  It only generates an interrupt when register access takes
it out of idle, which in means most RTC operations will hang.  We need
to change the IDLEMODE field to make alarm interrupts work properly.
---
The following worked for me, but I don't know whether this register
field should really be set in the RTC driver or somewhere in OMAP
platform code.

Also, given that DRA7xx is based on OMAP5 I would guess that the same
fix is needed for OMAP5, but I don't have the reference manual for it.
Can someone confirm whether it has the same register field?

Finally, I realise that the new compatible string, whatever it should
be, will need to be documented.

Ben.
---

Comments

Lokesh Vutla July 28, 2016, 6:48 a.m. UTC | #1
On Wednesday 27 July 2016 11:01 PM, Ben Hutchings wrote:
> On DRA7xx chips (and maybe others), the reset configuration of the RTC
> does not allow it to wake up from idle when it's ready to generate an
> interrupt.  It only generates an interrupt when register access takes
> it out of idle, which in means most RTC operations will hang.  We need
> to change the IDLEMODE field to make alarm interrupts work properly.

Shouldn't this be handled by hwmod? With this patch series[1], the
updating of IDLEMODE must have been proper. Can you confirm if you have
this series?

[1] http://www.spinics.net/lists/linux-omap/msg126531.html

Thanks and regards,
Lokesh

> ---
> The following worked for me, but I don't know whether this register
> field should really be set in the RTC driver or somewhere in OMAP
> platform code.
> 
> Also, given that DRA7xx is based on OMAP5 I would guess that the same
> fix is needed for OMAP5, but I don't have the reference manual for it.
> Can someone confirm whether it has the same register field?
> 
> Finally, I realise that the new compatible string, whatever it should
> be, will need to be documented.
> 
> Ben.
> ---
> --- a/drivers/rtc/rtc-omap.c
> +++ b/drivers/rtc/rtc-omap.c
> @@ -69,6 +69,7 @@
>  #define OMAP_RTC_KICK0_REG		0x6c
>  #define OMAP_RTC_KICK1_REG		0x70
>  
> +#define OMAP_RTC_SYSCONFIG_REG		0x78
>  #define OMAP_RTC_IRQWAKEEN		0x7c
>  
>  #define OMAP_RTC_ALARM2_SECONDS_REG	0x80
> @@ -110,6 +111,13 @@
>  #define OMAP_RTC_OSC_32KCLK_EN		BIT(6)
>  #define OMAP_RTC_OSC_SEL_32KCLK_SRC	BIT(3)
>  
> +/* OMAP_RTC_SYSCONFIG_REG bit fields: */
> +#define OMAP_RTC_IDLEMODE_MASK		3
> +#define OMAP_RTC_IDLEMODE_FORCE		0
> +#define OMAP_RTC_IDLEMODE_DISABLE	1
> +#define OMAP_RTC_IDLEMODE_SMART		2
> +#define OMAP_RTC_IDLEMODE_SMART_WAKEUP	3
> +
>  /* OMAP_RTC_IRQWAKEEN bit fields: */
>  #define OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN	BIT(1)
>  
> @@ -127,6 +135,7 @@ struct omap_rtc_device_type {
>  	bool has_irqwakeen;
>  	bool has_pmic_mode;
>  	bool has_power_up_reset;
> +	bool has_idlemode;
>  	void (*lock)(struct omap_rtc *rtc);
>  	void (*unlock)(struct omap_rtc *rtc);
>  };
> @@ -496,6 +505,15 @@ static const struct omap_rtc_device_type
>  	.unlock		= am3352_rtc_unlock,
>  };
>  
> +static const struct omap_rtc_device_type omap_rtc_dra7_type = {
> +	.has_32kclk_en	= true,
> +	.has_irqwakeen	= true,
> +	.has_pmic_mode	= true,
> +	.has_idlemode	= true,
> +	.lock		= am3352_rtc_lock,
> +	.unlock		= am3352_rtc_unlock,
> +};
> +
>  static const struct platform_device_id omap_rtc_id_table[] = {
>  	{
>  		.name	= "omap_rtc",
> @@ -520,6 +538,9 @@ static const struct of_device_id omap_rt
>  		.compatible	= "ti,da830-rtc",
>  		.data		= &omap_rtc_da830_type,
>  	}, {
> +		.compatible	= "ti,dra7-rtc",
> +		.data		= &omap_rtc_dra7_type,
> +	}, {
>  		/* sentinel */
>  	}
>  };
> @@ -650,6 +671,18 @@ static int omap_rtc_probe(struct platfor
>  			  reg | OMAP_RTC_OSC_SEL_32KCLK_SRC);
>  	}
>  
> +	if (rtc->type->has_idlemode) {
> +		/*
> +		 * Allow the RTC to come out of idle whenever it's ready to
> +		 * generate an interrupt
> +		 */
> +		u32 sysconfig = rtc_readl(rtc, OMAP_RTC_SYSCONFIG_REG);
> +
> +		sysconfig &= ~OMAP_RTC_IDLEMODE_MASK;
> +		sysconfig |= OMAP_RTC_IDLEMODE_SMART_WAKEUP;
> +		rtc_writel(rtc, OMAP_RTC_SYSCONFIG_REG, sysconfig);
> +	}
> +
>  	rtc->type->lock(rtc);
>  
>  	device_init_wakeup(&pdev->dev, true);
> --- a/arch/arm/boot/dts/dra7.dtsi
> +++ b/arch/arm/boot/dts/dra7.dtsi
> @@ -1290,7 +1290,7 @@
>  		};
>  
>  		rtc: rtc@48838000 {
> -			compatible = "ti,am3352-rtc";
> +			compatible = "ti,dra7-rtc", "ti,am3352-rtc";
>  			reg = <0x48838000 0x100>;
>  			interrupts = <GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH>,
>  				     <GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH>;
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Ben Hutchings July 28, 2016, 9:53 a.m. UTC | #2
On Thu, 2016-07-28 at 12:18 +0530, Lokesh Vutla wrote:
> 
> On Wednesday 27 July 2016 11:01 PM, Ben Hutchings wrote:
> > On DRA7xx chips (and maybe others), the reset configuration of the RTC
> > does not allow it to wake up from idle when it's ready to generate an
> > interrupt.  It only generates an interrupt when register access takes
> > it out of idle, which in means most RTC operations will hang.  We need
> > to change the IDLEMODE field to make alarm interrupts work properly.
> 
> Shouldn't this be handled by hwmod?

I don't know, that's why I asked.

> With this patch series[1], the
> updating of IDLEMODE must have been proper. Can you confirm if you have
> this series?
> 
> [1] http://www.spinics.net/lists/linux-omap/msg126531.html
[...]

No I didn't, and I see those are in 4.7.  I will test with those
changes, thanks.

Ben.
Ben Hutchings July 28, 2016, 3:47 p.m. UTC | #3
On Thu, 2016-07-28 at 10:53 +0100, Ben Hutchings wrote:
> On Thu, 2016-07-28 at 12:18 +0530, Lokesh Vutla wrote:
> > 
> > On Wednesday 27 July 2016 11:01 PM, Ben Hutchings wrote:
> > > On DRA7xx chips (and maybe others), the reset configuration of the RTC
> > > does not allow it to wake up from idle when it's ready to generate an
> > > interrupt.  It only generates an interrupt when register access takes
> > > it out of idle, which in means most RTC operations will hang.  We need
> > > to change the IDLEMODE field to make alarm interrupts work properly.
> > 
> > Shouldn't this be handled by hwmod?
> 
> I don't know, that's why I asked.
> 
> > With this patch series[1], the
> > updating of IDLEMODE must have been proper. Can you confirm if you have
> > this series?
> > 
> > [1] http://www.spinics.net/lists/linux-omap/msg126531.html
> [...]
> 
> No I didn't, and I see those are in 4.7.  I will test with those
> changes, thanks.

They worked, thanks.

Ben.
diff mbox

Patch

--- a/drivers/rtc/rtc-omap.c
+++ b/drivers/rtc/rtc-omap.c
@@ -69,6 +69,7 @@ 
 #define OMAP_RTC_KICK0_REG		0x6c
 #define OMAP_RTC_KICK1_REG		0x70
 
+#define OMAP_RTC_SYSCONFIG_REG		0x78
 #define OMAP_RTC_IRQWAKEEN		0x7c
 
 #define OMAP_RTC_ALARM2_SECONDS_REG	0x80
@@ -110,6 +111,13 @@ 
 #define OMAP_RTC_OSC_32KCLK_EN		BIT(6)
 #define OMAP_RTC_OSC_SEL_32KCLK_SRC	BIT(3)
 
+/* OMAP_RTC_SYSCONFIG_REG bit fields: */
+#define OMAP_RTC_IDLEMODE_MASK		3
+#define OMAP_RTC_IDLEMODE_FORCE		0
+#define OMAP_RTC_IDLEMODE_DISABLE	1
+#define OMAP_RTC_IDLEMODE_SMART		2
+#define OMAP_RTC_IDLEMODE_SMART_WAKEUP	3
+
 /* OMAP_RTC_IRQWAKEEN bit fields: */
 #define OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN	BIT(1)
 
@@ -127,6 +135,7 @@  struct omap_rtc_device_type {
 	bool has_irqwakeen;
 	bool has_pmic_mode;
 	bool has_power_up_reset;
+	bool has_idlemode;
 	void (*lock)(struct omap_rtc *rtc);
 	void (*unlock)(struct omap_rtc *rtc);
 };
@@ -496,6 +505,15 @@  static const struct omap_rtc_device_type
 	.unlock		= am3352_rtc_unlock,
 };
 
+static const struct omap_rtc_device_type omap_rtc_dra7_type = {
+	.has_32kclk_en	= true,
+	.has_irqwakeen	= true,
+	.has_pmic_mode	= true,
+	.has_idlemode	= true,
+	.lock		= am3352_rtc_lock,
+	.unlock		= am3352_rtc_unlock,
+};
+
 static const struct platform_device_id omap_rtc_id_table[] = {
 	{
 		.name	= "omap_rtc",
@@ -520,6 +538,9 @@  static const struct of_device_id omap_rt
 		.compatible	= "ti,da830-rtc",
 		.data		= &omap_rtc_da830_type,
 	}, {
+		.compatible	= "ti,dra7-rtc",
+		.data		= &omap_rtc_dra7_type,
+	}, {
 		/* sentinel */
 	}
 };
@@ -650,6 +671,18 @@  static int omap_rtc_probe(struct platfor
 			  reg | OMAP_RTC_OSC_SEL_32KCLK_SRC);
 	}
 
+	if (rtc->type->has_idlemode) {
+		/*
+		 * Allow the RTC to come out of idle whenever it's ready to
+		 * generate an interrupt
+		 */
+		u32 sysconfig = rtc_readl(rtc, OMAP_RTC_SYSCONFIG_REG);
+
+		sysconfig &= ~OMAP_RTC_IDLEMODE_MASK;
+		sysconfig |= OMAP_RTC_IDLEMODE_SMART_WAKEUP;
+		rtc_writel(rtc, OMAP_RTC_SYSCONFIG_REG, sysconfig);
+	}
+
 	rtc->type->lock(rtc);
 
 	device_init_wakeup(&pdev->dev, true);
--- a/arch/arm/boot/dts/dra7.dtsi
+++ b/arch/arm/boot/dts/dra7.dtsi
@@ -1290,7 +1290,7 @@ 
 		};
 
 		rtc: rtc@48838000 {
-			compatible = "ti,am3352-rtc";
+			compatible = "ti,dra7-rtc", "ti,am3352-rtc";
 			reg = <0x48838000 0x100>;
 			interrupts = <GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH>;