]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/bus/ti-sysc.c
bus: ti-sysc: Fix watchdog quirk handling
[linux.git] / drivers / bus / ti-sysc.c
index 9207ac2913412e9da29daa41222930442fd37673..2b6670daf7fc70cd58ac287785d06990bf1cb61e 100644 (file)
@@ -74,6 +74,7 @@ static const char * const clock_names[SYSC_MAX_CLOCKS] = {
  * @clk_disable_quirk: module specific clock disable quirk
  * @reset_done_quirk: module specific reset done quirk
  * @module_enable_quirk: module specific enable quirk
+ * @module_disable_quirk: module specific disable quirk
  */
 struct sysc {
        struct device *dev;
@@ -100,6 +101,7 @@ struct sysc {
        void (*clk_disable_quirk)(struct sysc *sysc);
        void (*reset_done_quirk)(struct sysc *sysc);
        void (*module_enable_quirk)(struct sysc *sysc);
+       void (*module_disable_quirk)(struct sysc *sysc);
 };
 
 static void sysc_parse_dts_quirks(struct sysc *ddata, struct device_node *np,
@@ -280,9 +282,6 @@ static int sysc_get_one_clock(struct sysc *ddata, const char *name)
 
        ddata->clocks[index] = devm_clk_get(ddata->dev, name);
        if (IS_ERR(ddata->clocks[index])) {
-               if (PTR_ERR(ddata->clocks[index]) == -ENOENT)
-                       return 0;
-
                dev_err(ddata->dev, "clock get error for %s: %li\n",
                        name, PTR_ERR(ddata->clocks[index]));
 
@@ -357,7 +356,7 @@ static int sysc_get_clocks(struct sysc *ddata)
                        continue;
 
                error = sysc_get_one_clock(ddata, name);
-               if (error && error != -ENOENT)
+               if (error)
                        return error;
        }
 
@@ -962,6 +961,9 @@ static int sysc_disable_module(struct device *dev)
        if (ddata->offsets[SYSC_SYSCONFIG] == -ENODEV)
                return 0;
 
+       if (ddata->module_disable_quirk)
+               ddata->module_disable_quirk(ddata);
+
        regbits = ddata->cap->regbits;
        reg = sysc_read(ddata, ddata->offsets[SYSC_SYSCONFIG]);
 
@@ -1251,6 +1253,9 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
                   SYSC_MODULE_QUIRK_SGX),
        SYSC_QUIRK("wdt", 0, 0, 0x10, 0x14, 0x502a0500, 0xfffff0f0,
                   SYSC_MODULE_QUIRK_WDT),
+       /* Watchdog on am3 and am4 */
+       SYSC_QUIRK("wdt", 0x44e35000, 0, 0x10, 0x14, 0x502a0500, 0xfffff0f0,
+                  SYSC_MODULE_QUIRK_WDT | SYSC_QUIRK_SWSUP_SIDLE),
 
 #ifdef DEBUG
        SYSC_QUIRK("adc", 0, 0, 0x10, -1, 0x47300001, 0xffffffff, 0),
@@ -1443,14 +1448,14 @@ static void sysc_reset_done_quirk_wdt(struct sysc *ddata)
                                   !(val & 0x10), 100,
                                   MAX_MODULE_SOFTRESET_WAIT);
        if (error)
-               dev_warn(ddata->dev, "wdt disable spr failed\n");
+               dev_warn(ddata->dev, "wdt disable step1 failed\n");
 
-       sysc_write(ddata, wps, 0x5555);
+       sysc_write(ddata, spr, 0x5555);
        error = readl_poll_timeout(ddata->module_va + wps, val,
                                   !(val & 0x10), 100,
                                   MAX_MODULE_SOFTRESET_WAIT);
        if (error)
-               dev_warn(ddata->dev, "wdt disable wps failed\n");
+               dev_warn(ddata->dev, "wdt disable step2 failed\n");
 }
 
 static void sysc_init_module_quirks(struct sysc *ddata)
@@ -1474,8 +1479,10 @@ static void sysc_init_module_quirks(struct sysc *ddata)
        if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_SGX)
                ddata->module_enable_quirk = sysc_module_enable_quirk_sgx;
 
-       if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_WDT)
+       if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_WDT) {
                ddata->reset_done_quirk = sysc_reset_done_quirk_wdt;
+               ddata->module_disable_quirk = sysc_reset_done_quirk_wdt;
+       }
 }
 
 static int sysc_clockdomain_init(struct sysc *ddata)
@@ -1632,17 +1639,19 @@ static int sysc_init_module(struct sysc *ddata)
        if (error)
                return error;
 
-       if (manage_clocks) {
-               sysc_clkdm_deny_idle(ddata);
+       sysc_clkdm_deny_idle(ddata);
 
-               error = sysc_enable_opt_clocks(ddata);
-               if (error)
-                       return error;
+       /*
+        * Always enable clocks. The bootloader may or may not have enabled
+        * the related clocks.
+        */
+       error = sysc_enable_opt_clocks(ddata);
+       if (error)
+               return error;
 
-               error = sysc_enable_main_clocks(ddata);
-               if (error)
-                       goto err_opt_clocks;
-       }
+       error = sysc_enable_main_clocks(ddata);
+       if (error)
+               goto err_opt_clocks;
 
        if (!(ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT)) {
                error = sysc_rstctrl_reset_deassert(ddata, true);
@@ -1660,7 +1669,7 @@ static int sysc_init_module(struct sysc *ddata)
                        goto err_main_clocks;
        }
 
-       if (!ddata->legacy_mode && manage_clocks) {
+       if (!ddata->legacy_mode) {
                error = sysc_enable_module(ddata->dev);
                if (error)
                        goto err_main_clocks;
@@ -1677,6 +1686,7 @@ static int sysc_init_module(struct sysc *ddata)
        if (manage_clocks)
                sysc_disable_main_clocks(ddata);
 err_opt_clocks:
+       /* No re-enable of clockdomain autoidle to prevent module autoidle */
        if (manage_clocks) {
                sysc_disable_opt_clocks(ddata);
                sysc_clkdm_allow_idle(ddata);
@@ -2357,6 +2367,27 @@ static void ti_sysc_idle(struct work_struct *work)
 
        ddata = container_of(work, struct sysc, idle_work.work);
 
+       /*
+        * One time decrement of clock usage counts if left on from init.
+        * Note that we disable opt clocks unconditionally in this case
+        * as they are enabled unconditionally during init without
+        * considering sysc_opt_clks_needed() at that point.
+        */
+       if (ddata->cfg.quirks & (SYSC_QUIRK_NO_IDLE |
+                                SYSC_QUIRK_NO_IDLE_ON_INIT)) {
+               sysc_disable_main_clocks(ddata);
+               sysc_disable_opt_clocks(ddata);
+               sysc_clkdm_allow_idle(ddata);
+       }
+
+       /* Keep permanent PM runtime usage count for SYSC_QUIRK_NO_IDLE */
+       if (ddata->cfg.quirks & SYSC_QUIRK_NO_IDLE)
+               return;
+
+       /*
+        * Decrement PM runtime usage count for SYSC_QUIRK_NO_IDLE_ON_INIT
+        * and SYSC_QUIRK_NO_RESET_ON_INIT
+        */
        if (pm_runtime_active(ddata->dev))
                pm_runtime_put_sync(ddata->dev);
 }
@@ -2445,7 +2476,8 @@ static int sysc_probe(struct platform_device *pdev)
        INIT_DELAYED_WORK(&ddata->idle_work, ti_sysc_idle);
 
        /* At least earlycon won't survive without deferred idle */
-       if (ddata->cfg.quirks & (SYSC_QUIRK_NO_IDLE_ON_INIT |
+       if (ddata->cfg.quirks & (SYSC_QUIRK_NO_IDLE |
+                                SYSC_QUIRK_NO_IDLE_ON_INIT |
                                 SYSC_QUIRK_NO_RESET_ON_INIT)) {
                schedule_delayed_work(&ddata->idle_work, 3000);
        } else {