diff options
Diffstat (limited to 'drivers/rtc/rtc-snvs.c')
-rw-r--r-- | drivers/rtc/rtc-snvs.c | 39 |
1 files changed, 36 insertions, 3 deletions
diff --git a/drivers/rtc/rtc-snvs.c b/drivers/rtc/rtc-snvs.c index fa384fe28988..2cd8ffe5c698 100644 --- a/drivers/rtc/rtc-snvs.c +++ b/drivers/rtc/rtc-snvs.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/of_device.h> | 17 | #include <linux/of_device.h> |
18 | #include <linux/platform_device.h> | 18 | #include <linux/platform_device.h> |
19 | #include <linux/rtc.h> | 19 | #include <linux/rtc.h> |
20 | #include <linux/clk.h> | ||
20 | 21 | ||
21 | /* These register offsets are relative to LP (Low Power) range */ | 22 | /* These register offsets are relative to LP (Low Power) range */ |
22 | #define SNVS_LPCR 0x04 | 23 | #define SNVS_LPCR 0x04 |
@@ -39,6 +40,7 @@ struct snvs_rtc_data { | |||
39 | void __iomem *ioaddr; | 40 | void __iomem *ioaddr; |
40 | int irq; | 41 | int irq; |
41 | spinlock_t lock; | 42 | spinlock_t lock; |
43 | struct clk *clk; | ||
42 | }; | 44 | }; |
43 | 45 | ||
44 | static u32 rtc_read_lp_counter(void __iomem *ioaddr) | 46 | static u32 rtc_read_lp_counter(void __iomem *ioaddr) |
@@ -260,6 +262,18 @@ static int snvs_rtc_probe(struct platform_device *pdev) | |||
260 | if (data->irq < 0) | 262 | if (data->irq < 0) |
261 | return data->irq; | 263 | return data->irq; |
262 | 264 | ||
265 | data->clk = devm_clk_get(&pdev->dev, "snvs-rtc"); | ||
266 | if (IS_ERR(data->clk)) { | ||
267 | data->clk = NULL; | ||
268 | } else { | ||
269 | ret = clk_prepare_enable(data->clk); | ||
270 | if (ret) { | ||
271 | dev_err(&pdev->dev, | ||
272 | "Could not prepare or enable the snvs clock\n"); | ||
273 | return ret; | ||
274 | } | ||
275 | } | ||
276 | |||
263 | platform_set_drvdata(pdev, data); | 277 | platform_set_drvdata(pdev, data); |
264 | 278 | ||
265 | spin_lock_init(&data->lock); | 279 | spin_lock_init(&data->lock); |
@@ -280,7 +294,7 @@ static int snvs_rtc_probe(struct platform_device *pdev) | |||
280 | if (ret) { | 294 | if (ret) { |
281 | dev_err(&pdev->dev, "failed to request irq %d: %d\n", | 295 | dev_err(&pdev->dev, "failed to request irq %d: %d\n", |
282 | data->irq, ret); | 296 | data->irq, ret); |
283 | return ret; | 297 | goto error_rtc_device_register; |
284 | } | 298 | } |
285 | 299 | ||
286 | data->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, | 300 | data->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, |
@@ -288,10 +302,16 @@ static int snvs_rtc_probe(struct platform_device *pdev) | |||
288 | if (IS_ERR(data->rtc)) { | 302 | if (IS_ERR(data->rtc)) { |
289 | ret = PTR_ERR(data->rtc); | 303 | ret = PTR_ERR(data->rtc); |
290 | dev_err(&pdev->dev, "failed to register rtc: %d\n", ret); | 304 | dev_err(&pdev->dev, "failed to register rtc: %d\n", ret); |
291 | return ret; | 305 | goto error_rtc_device_register; |
292 | } | 306 | } |
293 | 307 | ||
294 | return 0; | 308 | return 0; |
309 | |||
310 | error_rtc_device_register: | ||
311 | if (data->clk) | ||
312 | clk_disable_unprepare(data->clk); | ||
313 | |||
314 | return ret; | ||
295 | } | 315 | } |
296 | 316 | ||
297 | #ifdef CONFIG_PM_SLEEP | 317 | #ifdef CONFIG_PM_SLEEP |
@@ -302,21 +322,34 @@ static int snvs_rtc_suspend(struct device *dev) | |||
302 | if (device_may_wakeup(dev)) | 322 | if (device_may_wakeup(dev)) |
303 | enable_irq_wake(data->irq); | 323 | enable_irq_wake(data->irq); |
304 | 324 | ||
325 | if (data->clk) | ||
326 | clk_disable_unprepare(data->clk); | ||
327 | |||
305 | return 0; | 328 | return 0; |
306 | } | 329 | } |
307 | 330 | ||
308 | static int snvs_rtc_resume(struct device *dev) | 331 | static int snvs_rtc_resume(struct device *dev) |
309 | { | 332 | { |
310 | struct snvs_rtc_data *data = dev_get_drvdata(dev); | 333 | struct snvs_rtc_data *data = dev_get_drvdata(dev); |
334 | int ret; | ||
311 | 335 | ||
312 | if (device_may_wakeup(dev)) | 336 | if (device_may_wakeup(dev)) |
313 | disable_irq_wake(data->irq); | 337 | disable_irq_wake(data->irq); |
314 | 338 | ||
339 | if (data->clk) { | ||
340 | ret = clk_prepare_enable(data->clk); | ||
341 | if (ret) | ||
342 | return ret; | ||
343 | } | ||
344 | |||
315 | return 0; | 345 | return 0; |
316 | } | 346 | } |
317 | #endif | 347 | #endif |
318 | 348 | ||
319 | static SIMPLE_DEV_PM_OPS(snvs_rtc_pm_ops, snvs_rtc_suspend, snvs_rtc_resume); | 349 | static const struct dev_pm_ops snvs_rtc_pm_ops = { |
350 | .suspend_noirq = snvs_rtc_suspend, | ||
351 | .resume_noirq = snvs_rtc_resume, | ||
352 | }; | ||
320 | 353 | ||
321 | static const struct of_device_id snvs_dt_ids[] = { | 354 | static const struct of_device_id snvs_dt_ids[] = { |
322 | { .compatible = "fsl,sec-v4.0-mon-rtc-lp", }, | 355 | { .compatible = "fsl,sec-v4.0-mon-rtc-lp", }, |