UPSTREAM: drm/edid: Extract SADs properly from multiple audio data blocks
[firefly-linux-kernel-4.4.55.git] / drivers / watchdog / omap_wdt.c
index af88ffd1068f57ebd50354c7a6dd06fdf54af1f4..6f17c935a6cf86b1fcb47856532a8d6374bd0d82 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/mm.h>
 #include <linux/watchdog.h>
 #include <linux/reboot.h>
-#include <linux/init.h>
 #include <linux/err.h>
 #include <linux/platform_device.h>
 #include <linux/moduleparam.h>
@@ -54,11 +53,18 @@ static unsigned timer_margin;
 module_param(timer_margin, uint, 0);
 MODULE_PARM_DESC(timer_margin, "initial watchdog timeout (in seconds)");
 
+#define to_omap_wdt_dev(_wdog) container_of(_wdog, struct omap_wdt_dev, wdog)
+
+static bool early_enable;
+module_param(early_enable, bool, 0);
+MODULE_PARM_DESC(early_enable,
+       "Watchdog is started on module insertion (default=0)");
+
 struct omap_wdt_dev {
+       struct watchdog_device wdog;
        void __iomem    *base;          /* physical */
        struct device   *dev;
        bool            omap_wdt_users;
-       struct resource *mem;
        int             wdt_trgr_pattern;
        struct mutex    lock;           /* to avoid races with PM */
 };
@@ -68,14 +74,14 @@ static void omap_wdt_reload(struct omap_wdt_dev *wdev)
        void __iomem    *base = wdev->base;
 
        /* wait for posted write to complete */
-       while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08)
+       while ((readl_relaxed(base + OMAP_WATCHDOG_WPS)) & 0x08)
                cpu_relax();
 
        wdev->wdt_trgr_pattern = ~wdev->wdt_trgr_pattern;
-       __raw_writel(wdev->wdt_trgr_pattern, (base + OMAP_WATCHDOG_TGR));
+       writel_relaxed(wdev->wdt_trgr_pattern, (base + OMAP_WATCHDOG_TGR));
 
        /* wait for posted write to complete */
-       while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08)
+       while ((readl_relaxed(base + OMAP_WATCHDOG_WPS)) & 0x08)
                cpu_relax();
        /* reloaded WCRR from WLDR */
 }
@@ -85,12 +91,12 @@ static void omap_wdt_enable(struct omap_wdt_dev *wdev)
        void __iomem *base = wdev->base;
 
        /* Sequence to enable the watchdog */
-       __raw_writel(0xBBBB, base + OMAP_WATCHDOG_SPR);
-       while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x10)
+       writel_relaxed(0xBBBB, base + OMAP_WATCHDOG_SPR);
+       while ((readl_relaxed(base + OMAP_WATCHDOG_WPS)) & 0x10)
                cpu_relax();
 
-       __raw_writel(0x4444, base + OMAP_WATCHDOG_SPR);
-       while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x10)
+       writel_relaxed(0x4444, base + OMAP_WATCHDOG_SPR);
+       while ((readl_relaxed(base + OMAP_WATCHDOG_WPS)) & 0x10)
                cpu_relax();
 }
 
@@ -99,12 +105,12 @@ static void omap_wdt_disable(struct omap_wdt_dev *wdev)
        void __iomem *base = wdev->base;
 
        /* sequence required to disable watchdog */
-       __raw_writel(0xAAAA, base + OMAP_WATCHDOG_SPR); /* TIMER_MODE */
-       while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x10)
+       writel_relaxed(0xAAAA, base + OMAP_WATCHDOG_SPR);       /* TIMER_MODE */
+       while (readl_relaxed(base + OMAP_WATCHDOG_WPS) & 0x10)
                cpu_relax();
 
-       __raw_writel(0x5555, base + OMAP_WATCHDOG_SPR); /* TIMER_MODE */
-       while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x10)
+       writel_relaxed(0x5555, base + OMAP_WATCHDOG_SPR);       /* TIMER_MODE */
+       while (readl_relaxed(base + OMAP_WATCHDOG_WPS) & 0x10)
                cpu_relax();
 }
 
@@ -115,17 +121,17 @@ static void omap_wdt_set_timer(struct omap_wdt_dev *wdev,
        void __iomem *base = wdev->base;
 
        /* just count up at 32 KHz */
-       while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x04)
+       while (readl_relaxed(base + OMAP_WATCHDOG_WPS) & 0x04)
                cpu_relax();
 
-       __raw_writel(pre_margin, base + OMAP_WATCHDOG_LDR);
-       while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x04)
+       writel_relaxed(pre_margin, base + OMAP_WATCHDOG_LDR);
+       while (readl_relaxed(base + OMAP_WATCHDOG_WPS) & 0x04)
                cpu_relax();
 }
 
 static int omap_wdt_start(struct watchdog_device *wdog)
 {
-       struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
+       struct omap_wdt_dev *wdev = to_omap_wdt_dev(wdog);
        void __iomem *base = wdev->base;
 
        mutex_lock(&wdev->lock);
@@ -134,12 +140,19 @@ static int omap_wdt_start(struct watchdog_device *wdog)
 
        pm_runtime_get_sync(wdev->dev);
 
+       /*
+        * Make sure the watchdog is disabled. This is unfortunately required
+        * because writing to various registers with the watchdog running has no
+        * effect.
+        */
+       omap_wdt_disable(wdev);
+
        /* initialize prescaler */
-       while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x01)
+       while (readl_relaxed(base + OMAP_WATCHDOG_WPS) & 0x01)
                cpu_relax();
 
-       __raw_writel((1 << 5) | (PTV << 2), base + OMAP_WATCHDOG_CNTRL);
-       while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x01)
+       writel_relaxed((1 << 5) | (PTV << 2), base + OMAP_WATCHDOG_CNTRL);
+       while (readl_relaxed(base + OMAP_WATCHDOG_WPS) & 0x01)
                cpu_relax();
 
        omap_wdt_set_timer(wdev, wdog->timeout);
@@ -153,7 +166,7 @@ static int omap_wdt_start(struct watchdog_device *wdog)
 
 static int omap_wdt_stop(struct watchdog_device *wdog)
 {
-       struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
+       struct omap_wdt_dev *wdev = to_omap_wdt_dev(wdog);
 
        mutex_lock(&wdev->lock);
        omap_wdt_disable(wdev);
@@ -165,7 +178,7 @@ static int omap_wdt_stop(struct watchdog_device *wdog)
 
 static int omap_wdt_ping(struct watchdog_device *wdog)
 {
-       struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
+       struct omap_wdt_dev *wdev = to_omap_wdt_dev(wdog);
 
        mutex_lock(&wdev->lock);
        omap_wdt_reload(wdev);
@@ -177,7 +190,7 @@ static int omap_wdt_ping(struct watchdog_device *wdog)
 static int omap_wdt_set_timeout(struct watchdog_device *wdog,
                                unsigned int timeout)
 {
-       struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
+       struct omap_wdt_dev *wdev = to_omap_wdt_dev(wdog);
 
        mutex_lock(&wdev->lock);
        omap_wdt_disable(wdev);
@@ -190,8 +203,18 @@ static int omap_wdt_set_timeout(struct watchdog_device *wdog,
        return 0;
 }
 
+static unsigned int omap_wdt_get_timeleft(struct watchdog_device *wdog)
+{
+       struct omap_wdt_dev *wdev = to_omap_wdt_dev(wdog);
+       void __iomem *base = wdev->base;
+       u32 value;
+
+       value = readl_relaxed(base + OMAP_WATCHDOG_CRR);
+       return GET_WCCR_SECS(value);
+}
+
 static const struct watchdog_info omap_wdt_info = {
-       .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+       .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
        .identity = "OMAP Watchdog",
 };
 
@@ -201,92 +224,76 @@ static const struct watchdog_ops omap_wdt_ops = {
        .stop           = omap_wdt_stop,
        .ping           = omap_wdt_ping,
        .set_timeout    = omap_wdt_set_timeout,
+       .get_timeleft   = omap_wdt_get_timeleft,
 };
 
 static int omap_wdt_probe(struct platform_device *pdev)
 {
-       struct omap_wd_timer_platform_data *pdata = pdev->dev.platform_data;
-       struct watchdog_device *omap_wdt;
-       struct resource *res, *mem;
+       struct omap_wd_timer_platform_data *pdata = dev_get_platdata(&pdev->dev);
+       struct resource *res;
        struct omap_wdt_dev *wdev;
-       u32 rs;
        int ret;
 
-       omap_wdt = devm_kzalloc(&pdev->dev, sizeof(*omap_wdt), GFP_KERNEL);
-       if (!omap_wdt)
-               return -ENOMEM;
-
-       /* reserve static register mappings */
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENOENT;
-
-       mem = devm_request_mem_region(&pdev->dev, res->start,
-                                     resource_size(res), pdev->name);
-       if (!mem)
-               return -EBUSY;
-
        wdev = devm_kzalloc(&pdev->dev, sizeof(*wdev), GFP_KERNEL);
        if (!wdev)
                return -ENOMEM;
 
        wdev->omap_wdt_users    = false;
-       wdev->mem               = mem;
        wdev->dev               = &pdev->dev;
        wdev->wdt_trgr_pattern  = 0x1234;
        mutex_init(&wdev->lock);
 
-       wdev->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
-       if (!wdev->base)
-               return -ENOMEM;
+       /* reserve static register mappings */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       wdev->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(wdev->base))
+               return PTR_ERR(wdev->base);
 
-       omap_wdt->info        = &omap_wdt_info;
-       omap_wdt->ops         = &omap_wdt_ops;
-       omap_wdt->min_timeout = TIMER_MARGIN_MIN;
-       omap_wdt->max_timeout = TIMER_MARGIN_MAX;
+       wdev->wdog.info = &omap_wdt_info;
+       wdev->wdog.ops = &omap_wdt_ops;
+       wdev->wdog.min_timeout = TIMER_MARGIN_MIN;
+       wdev->wdog.max_timeout = TIMER_MARGIN_MAX;
+       wdev->wdog.parent = &pdev->dev;
 
-       if (timer_margin >= TIMER_MARGIN_MIN &&
-           timer_margin <= TIMER_MARGIN_MAX)
-               omap_wdt->timeout = timer_margin;
-       else
-               omap_wdt->timeout = TIMER_MARGIN_DEFAULT;
+       if (watchdog_init_timeout(&wdev->wdog, timer_margin, &pdev->dev) < 0)
+               wdev->wdog.timeout = TIMER_MARGIN_DEFAULT;
 
-       watchdog_set_drvdata(omap_wdt, wdev);
-       watchdog_set_nowayout(omap_wdt, nowayout);
+       watchdog_set_nowayout(&wdev->wdog, nowayout);
 
-       platform_set_drvdata(pdev, omap_wdt);
+       platform_set_drvdata(pdev, wdev);
 
        pm_runtime_enable(wdev->dev);
        pm_runtime_get_sync(wdev->dev);
 
-       if (pdata && pdata->read_reset_sources)
-               rs = pdata->read_reset_sources();
-       else
-               rs = 0;
-       omap_wdt->bootstatus = (rs & (1 << OMAP_MPU_WD_RST_SRC_ID_SHIFT)) ?
-                               WDIOF_CARDRESET : 0;
+       if (pdata && pdata->read_reset_sources) {
+               u32 rs = pdata->read_reset_sources();
+               if (rs & (1 << OMAP_MPU_WD_RST_SRC_ID_SHIFT))
+                       wdev->wdog.bootstatus = WDIOF_CARDRESET;
+       }
 
        omap_wdt_disable(wdev);
 
-       ret = watchdog_register_device(omap_wdt);
+       ret = watchdog_register_device(&wdev->wdog);
        if (ret) {
                pm_runtime_disable(wdev->dev);
                return ret;
        }
 
        pr_info("OMAP Watchdog Timer Rev 0x%02x: initial timeout %d sec\n",
-               __raw_readl(wdev->base + OMAP_WATCHDOG_REV) & 0xFF,
-               omap_wdt->timeout);
+               readl_relaxed(wdev->base + OMAP_WATCHDOG_REV) & 0xFF,
+               wdev->wdog.timeout);
 
        pm_runtime_put_sync(wdev->dev);
 
+       if (early_enable)
+               omap_wdt_start(&wdev->wdog);
+
        return 0;
 }
 
 static void omap_wdt_shutdown(struct platform_device *pdev)
 {
-       struct watchdog_device *wdog = platform_get_drvdata(pdev);
-       struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
+       struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
 
        mutex_lock(&wdev->lock);
        if (wdev->omap_wdt_users) {
@@ -298,11 +305,10 @@ static void omap_wdt_shutdown(struct platform_device *pdev)
 
 static int omap_wdt_remove(struct platform_device *pdev)
 {
-       struct watchdog_device *wdog = platform_get_drvdata(pdev);
-       struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
+       struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
 
        pm_runtime_disable(wdev->dev);
-       watchdog_unregister_device(wdog);
+       watchdog_unregister_device(&wdev->wdog);
 
        return 0;
 }
@@ -317,8 +323,7 @@ static int omap_wdt_remove(struct platform_device *pdev)
 
 static int omap_wdt_suspend(struct platform_device *pdev, pm_message_t state)
 {
-       struct watchdog_device *wdog = platform_get_drvdata(pdev);
-       struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
+       struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
 
        mutex_lock(&wdev->lock);
        if (wdev->omap_wdt_users) {
@@ -332,8 +337,7 @@ static int omap_wdt_suspend(struct platform_device *pdev, pm_message_t state)
 
 static int omap_wdt_resume(struct platform_device *pdev)
 {
-       struct watchdog_device *wdog = platform_get_drvdata(pdev);
-       struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
+       struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
 
        mutex_lock(&wdev->lock);
        if (wdev->omap_wdt_users) {
@@ -364,7 +368,6 @@ static struct platform_driver omap_wdt_driver = {
        .suspend        = omap_wdt_suspend,
        .resume         = omap_wdt_resume,
        .driver         = {
-               .owner  = THIS_MODULE,
                .name   = "omap_wdt",
                .of_match_table = omap_wdt_of_match,
        },