diff options
author | Loc Ho <lho@apm.com> | 2014-04-14 14:09:04 -0400 |
---|---|---|
committer | Alexandre Belloni <alexandre.belloni@free-electrons.com> | 2017-11-08 19:16:36 -0500 |
commit | d0bcd82b13794c4bc89876e9383000fc1cb069d2 (patch) | |
tree | a08253f8e10ffc4a0275d089a17c1c488a236b0b /drivers/rtc/rtc-xgene.c | |
parent | 1856e0b2ace70a0231a94ec9d1286904c6ffa1ca (diff) |
rtc: xgene: Fix suspend/resume
This patch fixes suspend/resume functions properly for the APM X-Gene
SoC RTC driver.
Signed-off-by: Loc Ho <lho@apm.com>
Reviewed-by: Mark Brown <broonie@linaro.org>
Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Diffstat (limited to 'drivers/rtc/rtc-xgene.c')
-rw-r--r-- | drivers/rtc/rtc-xgene.c | 41 |
1 files changed, 32 insertions, 9 deletions
diff --git a/drivers/rtc/rtc-xgene.c b/drivers/rtc/rtc-xgene.c index 65b432a096fe..360eae24a8c8 100644 --- a/drivers/rtc/rtc-xgene.c +++ b/drivers/rtc/rtc-xgene.c | |||
@@ -52,6 +52,7 @@ struct xgene_rtc_dev { | |||
52 | void __iomem *csr_base; | 52 | void __iomem *csr_base; |
53 | struct clk *clk; | 53 | struct clk *clk; |
54 | unsigned int irq_wake; | 54 | unsigned int irq_wake; |
55 | unsigned int irq_enabled; | ||
55 | }; | 56 | }; |
56 | 57 | ||
57 | static int xgene_rtc_read_time(struct device *dev, struct rtc_time *tm) | 58 | static int xgene_rtc_read_time(struct device *dev, struct rtc_time *tm) |
@@ -104,15 +105,19 @@ static int xgene_rtc_alarm_irq_enable(struct device *dev, u32 enabled) | |||
104 | return 0; | 105 | return 0; |
105 | } | 106 | } |
106 | 107 | ||
108 | static int xgene_rtc_alarm_irq_enabled(struct device *dev) | ||
109 | { | ||
110 | struct xgene_rtc_dev *pdata = dev_get_drvdata(dev); | ||
111 | |||
112 | return readl(pdata->csr_base + RTC_CCR) & RTC_CCR_IE ? 1 : 0; | ||
113 | } | ||
114 | |||
107 | static int xgene_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) | 115 | static int xgene_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) |
108 | { | 116 | { |
109 | struct xgene_rtc_dev *pdata = dev_get_drvdata(dev); | 117 | struct xgene_rtc_dev *pdata = dev_get_drvdata(dev); |
110 | unsigned long rtc_time; | ||
111 | unsigned long alarm_time; | 118 | unsigned long alarm_time; |
112 | 119 | ||
113 | rtc_time = readl(pdata->csr_base + RTC_CCVR); | ||
114 | rtc_tm_to_time(&alrm->time, &alarm_time); | 120 | rtc_tm_to_time(&alrm->time, &alarm_time); |
115 | |||
116 | pdata->alarm_time = alarm_time; | 121 | pdata->alarm_time = alarm_time; |
117 | writel((u32) pdata->alarm_time, pdata->csr_base + RTC_CMR); | 122 | writel((u32) pdata->alarm_time, pdata->csr_base + RTC_CMR); |
118 | 123 | ||
@@ -180,12 +185,18 @@ static int xgene_rtc_probe(struct platform_device *pdev) | |||
180 | dev_err(&pdev->dev, "Couldn't get the clock for RTC\n"); | 185 | dev_err(&pdev->dev, "Couldn't get the clock for RTC\n"); |
181 | return -ENODEV; | 186 | return -ENODEV; |
182 | } | 187 | } |
183 | clk_prepare_enable(pdata->clk); | 188 | ret = clk_prepare_enable(pdata->clk); |
189 | if (ret) | ||
190 | return ret; | ||
184 | 191 | ||
185 | /* Turn on the clock and the crystal */ | 192 | /* Turn on the clock and the crystal */ |
186 | writel(RTC_CCR_EN, pdata->csr_base + RTC_CCR); | 193 | writel(RTC_CCR_EN, pdata->csr_base + RTC_CCR); |
187 | 194 | ||
188 | device_init_wakeup(&pdev->dev, 1); | 195 | ret = device_init_wakeup(&pdev->dev, 1); |
196 | if (ret) { | ||
197 | clk_disable_unprepare(pdata->clk); | ||
198 | return ret; | ||
199 | } | ||
189 | 200 | ||
190 | pdata->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, | 201 | pdata->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, |
191 | &xgene_rtc_ops, THIS_MODULE); | 202 | &xgene_rtc_ops, THIS_MODULE); |
@@ -218,14 +229,20 @@ static int xgene_rtc_suspend(struct device *dev) | |||
218 | int irq; | 229 | int irq; |
219 | 230 | ||
220 | irq = platform_get_irq(pdev, 0); | 231 | irq = platform_get_irq(pdev, 0); |
232 | |||
233 | /* | ||
234 | * If this RTC alarm will be used for waking the system up, | ||
235 | * don't disable it of course. Else we just disable the alarm | ||
236 | * and await suspension. | ||
237 | */ | ||
221 | if (device_may_wakeup(&pdev->dev)) { | 238 | if (device_may_wakeup(&pdev->dev)) { |
222 | if (!enable_irq_wake(irq)) | 239 | if (!enable_irq_wake(irq)) |
223 | pdata->irq_wake = 1; | 240 | pdata->irq_wake = 1; |
224 | } else { | 241 | } else { |
242 | pdata->irq_enabled = xgene_rtc_alarm_irq_enabled(dev); | ||
225 | xgene_rtc_alarm_irq_enable(dev, 0); | 243 | xgene_rtc_alarm_irq_enable(dev, 0); |
226 | clk_disable(pdata->clk); | 244 | clk_disable_unprepare(pdata->clk); |
227 | } | 245 | } |
228 | |||
229 | return 0; | 246 | return 0; |
230 | } | 247 | } |
231 | 248 | ||
@@ -234,16 +251,22 @@ static int xgene_rtc_resume(struct device *dev) | |||
234 | struct platform_device *pdev = to_platform_device(dev); | 251 | struct platform_device *pdev = to_platform_device(dev); |
235 | struct xgene_rtc_dev *pdata = platform_get_drvdata(pdev); | 252 | struct xgene_rtc_dev *pdata = platform_get_drvdata(pdev); |
236 | int irq; | 253 | int irq; |
254 | int rc; | ||
237 | 255 | ||
238 | irq = platform_get_irq(pdev, 0); | 256 | irq = platform_get_irq(pdev, 0); |
257 | |||
239 | if (device_may_wakeup(&pdev->dev)) { | 258 | if (device_may_wakeup(&pdev->dev)) { |
240 | if (pdata->irq_wake) { | 259 | if (pdata->irq_wake) { |
241 | disable_irq_wake(irq); | 260 | disable_irq_wake(irq); |
242 | pdata->irq_wake = 0; | 261 | pdata->irq_wake = 0; |
243 | } | 262 | } |
244 | } else { | 263 | } else { |
245 | clk_enable(pdata->clk); | 264 | rc = clk_prepare_enable(pdata->clk); |
246 | xgene_rtc_alarm_irq_enable(dev, 1); | 265 | if (rc) { |
266 | dev_err(dev, "Unable to enable clock error %d\n", rc); | ||
267 | return rc; | ||
268 | } | ||
269 | xgene_rtc_alarm_irq_enable(dev, pdata->irq_enabled); | ||
247 | } | 270 | } |
248 | 271 | ||
249 | return 0; | 272 | return 0; |