diff options
Diffstat (limited to 'drivers/rtc/rtc-omap.c')
| -rw-r--r-- | drivers/rtc/rtc-omap.c | 33 | 
1 files changed, 33 insertions, 0 deletions
diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index 8b6355ffaff9..ec2e9c5fb993 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -25,6 +25,7 @@  #include <linux/of_device.h>  #include <linux/pm_runtime.h>  #include <linux/io.h> +#include <linux/clk.h>  /*   * The OMAP RTC is a year/month/day/hours/minutes/seconds BCD clock @@ -107,6 +108,7 @@  /* OMAP_RTC_OSC_REG bit fields: */  #define OMAP_RTC_OSC_32KCLK_EN		BIT(6) +#define OMAP_RTC_OSC_SEL_32KCLK_SRC	BIT(3)  /* OMAP_RTC_IRQWAKEEN bit fields: */  #define OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN	BIT(1) @@ -132,10 +134,12 @@ struct omap_rtc_device_type {  struct omap_rtc {  	struct rtc_device *rtc;  	void __iomem *base; +	struct clk *clk;  	int irq_alarm;  	int irq_timer;  	u8 interrupts_reg;  	bool is_pmic_controller; +	bool has_ext_clk;  	const struct omap_rtc_device_type *type;  }; @@ -553,6 +557,15 @@ static int omap_rtc_probe(struct platform_device *pdev)  	if (rtc->irq_alarm <= 0)  		return -ENOENT; +	rtc->clk = devm_clk_get(&pdev->dev, "ext-clk"); +	if (!IS_ERR(rtc->clk)) +		rtc->has_ext_clk = true; +	else +		rtc->clk = devm_clk_get(&pdev->dev, "int-clk"); + +	if (!IS_ERR(rtc->clk)) +		clk_prepare_enable(rtc->clk); +  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	rtc->base = devm_ioremap_resource(&pdev->dev, res);  	if (IS_ERR(rtc->base)) @@ -627,6 +640,16 @@ static int omap_rtc_probe(struct platform_device *pdev)  	if (reg != new_ctrl)  		rtc_write(rtc, OMAP_RTC_CTRL_REG, new_ctrl); +	/* +	 * If we have the external clock then switch to it so we can keep +	 * ticking across suspend. +	 */ +	if (rtc->has_ext_clk) { +		reg = rtc_read(rtc, OMAP_RTC_OSC_REG); +		rtc_write(rtc, OMAP_RTC_OSC_REG, +			  reg | OMAP_RTC_OSC_SEL_32KCLK_SRC); +	} +  	rtc->type->lock(rtc);  	device_init_wakeup(&pdev->dev, true); @@ -672,6 +695,7 @@ err:  static int __exit omap_rtc_remove(struct platform_device *pdev)  {  	struct omap_rtc *rtc = platform_get_drvdata(pdev); +	u8 reg;  	if (pm_power_off == omap_rtc_power_off &&  			omap_rtc_power_off_rtc == rtc) { @@ -681,10 +705,19 @@ static int __exit omap_rtc_remove(struct platform_device *pdev)  	device_init_wakeup(&pdev->dev, 0); +	if (!IS_ERR(rtc->clk)) +		clk_disable_unprepare(rtc->clk); +  	rtc->type->unlock(rtc);  	/* leave rtc running, but disable irqs */  	rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, 0); +	if (rtc->has_ext_clk) { +		reg = rtc_read(rtc, OMAP_RTC_OSC_REG); +		reg &= ~OMAP_RTC_OSC_SEL_32KCLK_SRC; +		rtc_write(rtc, OMAP_RTC_OSC_REG, reg); +	} +  	rtc->type->lock(rtc);  	/* Disable the clock/module */  |