Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm...
[cascardo/linux.git] / drivers / rtc / rtc-snvs.c
index fa384fe..0479e80 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/rtc.h>
+#include <linux/clk.h>
 
 /* These register offsets are relative to LP (Low Power) range */
 #define SNVS_LPCR              0x04
@@ -39,6 +40,7 @@ struct snvs_rtc_data {
        void __iomem *ioaddr;
        int irq;
        spinlock_t lock;
+       struct clk *clk;
 };
 
 static u32 rtc_read_lp_counter(void __iomem *ioaddr)
@@ -260,6 +262,18 @@ static int snvs_rtc_probe(struct platform_device *pdev)
        if (data->irq < 0)
                return data->irq;
 
+       data->clk = devm_clk_get(&pdev->dev, "snvs-rtc");
+       if (IS_ERR(data->clk)) {
+               data->clk = NULL;
+       } else {
+               ret = clk_prepare_enable(data->clk);
+               if (ret) {
+                       dev_err(&pdev->dev,
+                               "Could not prepare or enable the snvs clock\n");
+                       return ret;
+               }
+       }
+
        platform_set_drvdata(pdev, data);
 
        spin_lock_init(&data->lock);
@@ -280,7 +294,7 @@ static int snvs_rtc_probe(struct platform_device *pdev)
        if (ret) {
                dev_err(&pdev->dev, "failed to request irq %d: %d\n",
                        data->irq, ret);
-               return ret;
+               goto error_rtc_device_register;
        }
 
        data->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
@@ -288,10 +302,16 @@ static int snvs_rtc_probe(struct platform_device *pdev)
        if (IS_ERR(data->rtc)) {
                ret = PTR_ERR(data->rtc);
                dev_err(&pdev->dev, "failed to register rtc: %d\n", ret);
-               return ret;
+               goto error_rtc_device_register;
        }
 
        return 0;
+
+error_rtc_device_register:
+       if (data->clk)
+               clk_disable_unprepare(data->clk);
+
+       return ret;
 }
 
 #ifdef CONFIG_PM_SLEEP
@@ -302,21 +322,41 @@ static int snvs_rtc_suspend(struct device *dev)
        if (device_may_wakeup(dev))
                enable_irq_wake(data->irq);
 
+       if (data->clk)
+               clk_disable_unprepare(data->clk);
+
        return 0;
 }
 
 static int snvs_rtc_resume(struct device *dev)
 {
        struct snvs_rtc_data *data = dev_get_drvdata(dev);
+       int ret;
 
        if (device_may_wakeup(dev))
                disable_irq_wake(data->irq);
 
+       if (data->clk) {
+               ret = clk_prepare_enable(data->clk);
+               if (ret)
+                       return ret;
+       }
+
        return 0;
 }
-#endif
 
-static SIMPLE_DEV_PM_OPS(snvs_rtc_pm_ops, snvs_rtc_suspend, snvs_rtc_resume);
+static const struct dev_pm_ops snvs_rtc_pm_ops = {
+       .suspend_noirq = snvs_rtc_suspend,
+       .resume_noirq = snvs_rtc_resume,
+};
+
+#define SNVS_RTC_PM_OPS        (&snvs_rtc_pm_ops)
+
+#else
+
+#define SNVS_RTC_PM_OPS        NULL
+
+#endif
 
 static const struct of_device_id snvs_dt_ids[] = {
        { .compatible = "fsl,sec-v4.0-mon-rtc-lp", },
@@ -327,8 +367,7 @@ MODULE_DEVICE_TABLE(of, snvs_dt_ids);
 static struct platform_driver snvs_rtc_driver = {
        .driver = {
                .name   = "snvs_rtc",
-               .owner  = THIS_MODULE,
-               .pm     = &snvs_rtc_pm_ops,
+               .pm     = SNVS_RTC_PM_OPS,
                .of_match_table = snvs_dt_ids,
        },
        .probe          = snvs_rtc_probe,