Merge tag 'for-6.7-rc1-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave...
[linux-2.6-microblaze.git] / drivers / watchdog / ixp4xx_wdt.c
index 607ce4b..ec0c086 100644 (file)
@@ -105,6 +105,25 @@ static const struct watchdog_ops ixp4xx_wdt_ops = {
        .owner = THIS_MODULE,
 };
 
+/*
+ * The A0 version of the IXP422 had a bug in the watchdog making
+ * is useless, but we still need to use it to restart the system
+ * as it is the only way, so in this special case we register a
+ * "dummy" watchdog that doesn't really work, but will support
+ * the restart operation.
+ */
+static int ixp4xx_wdt_dummy(struct watchdog_device *wdd)
+{
+       return 0;
+}
+
+static const struct watchdog_ops ixp4xx_wdt_restart_only_ops = {
+       .start = ixp4xx_wdt_dummy,
+       .stop = ixp4xx_wdt_dummy,
+       .restart = ixp4xx_wdt_restart,
+       .owner = THIS_MODULE,
+};
+
 static const struct watchdog_info ixp4xx_wdt_info = {
        .options = WDIOF_KEEPALIVEPING
                | WDIOF_MAGICCLOSE
@@ -114,14 +133,17 @@ static const struct watchdog_info ixp4xx_wdt_info = {
 
 static int ixp4xx_wdt_probe(struct platform_device *pdev)
 {
+       static const struct watchdog_ops *iwdt_ops;
        struct device *dev = &pdev->dev;
        struct ixp4xx_wdt *iwdt;
        struct clk *clk;
        int ret;
 
        if (!(read_cpuid_id() & 0xf) && !cpu_is_ixp46x()) {
-               dev_err(dev, "Rev. A0 IXP42x CPU detected - watchdog disabled\n");
-               return -ENODEV;
+               dev_info(dev, "Rev. A0 IXP42x CPU detected - only restart supported\n");
+               iwdt_ops = &ixp4xx_wdt_restart_only_ops;
+       } else {
+               iwdt_ops = &ixp4xx_wdt_ops;
        }
 
        iwdt = devm_kzalloc(dev, sizeof(*iwdt), GFP_KERNEL);
@@ -141,7 +163,7 @@ static int ixp4xx_wdt_probe(struct platform_device *pdev)
                iwdt->rate = IXP4XX_TIMER_FREQ;
 
        iwdt->wdd.info = &ixp4xx_wdt_info;
-       iwdt->wdd.ops = &ixp4xx_wdt_ops;
+       iwdt->wdd.ops = iwdt_ops;
        iwdt->wdd.min_timeout = 1;
        iwdt->wdd.max_timeout = U32_MAX / iwdt->rate;
        iwdt->wdd.parent = dev;