| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * mpc8xxx_wdt.c - MPC8xx/MPC83xx/MPC86xx watchdog userspace interface |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 10 | 11 | * |
|---|
| 11 | 12 | * Note: it appears that you can only actually ENABLE or DISABLE the thing |
|---|
| 12 | 13 | * once after POR. Once enabled, you cannot disable, and vice versa. |
|---|
| 13 | | - * |
|---|
| 14 | | - * This program is free software; you can redistribute it and/or modify it |
|---|
| 15 | | - * under the terms of the GNU General Public License as published by the |
|---|
| 16 | | - * Free Software Foundation; either version 2 of the License, or (at your |
|---|
| 17 | | - * option) any later version. |
|---|
| 18 | 14 | */ |
|---|
| 19 | | - |
|---|
| 20 | | -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
|---|
| 21 | 15 | |
|---|
| 22 | 16 | #include <linux/fs.h> |
|---|
| 23 | 17 | #include <linux/init.h> |
|---|
| .. | .. |
|---|
| 49 | 43 | struct mpc8xxx_wdt_type { |
|---|
| 50 | 44 | int prescaler; |
|---|
| 51 | 45 | bool hw_enabled; |
|---|
| 46 | + u32 rsr_mask; |
|---|
| 52 | 47 | }; |
|---|
| 53 | 48 | |
|---|
| 54 | 49 | struct mpc8xxx_wdt_ddata { |
|---|
| .. | .. |
|---|
| 137 | 132 | struct mpc8xxx_wdt_ddata *ddata; |
|---|
| 138 | 133 | u32 freq = fsl_get_sys_freq(); |
|---|
| 139 | 134 | bool enabled; |
|---|
| 135 | + struct device *dev = &ofdev->dev; |
|---|
| 140 | 136 | |
|---|
| 141 | | - wdt_type = of_device_get_match_data(&ofdev->dev); |
|---|
| 137 | + wdt_type = of_device_get_match_data(dev); |
|---|
| 142 | 138 | if (!wdt_type) |
|---|
| 143 | 139 | return -EINVAL; |
|---|
| 144 | 140 | |
|---|
| 145 | 141 | if (!freq || freq == -1) |
|---|
| 146 | 142 | return -EINVAL; |
|---|
| 147 | 143 | |
|---|
| 148 | | - ddata = devm_kzalloc(&ofdev->dev, sizeof(*ddata), GFP_KERNEL); |
|---|
| 144 | + ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL); |
|---|
| 149 | 145 | if (!ddata) |
|---|
| 150 | 146 | return -ENOMEM; |
|---|
| 151 | 147 | |
|---|
| 152 | | - res = platform_get_resource(ofdev, IORESOURCE_MEM, 0); |
|---|
| 153 | | - ddata->base = devm_ioremap_resource(&ofdev->dev, res); |
|---|
| 148 | + ddata->base = devm_platform_ioremap_resource(ofdev, 0); |
|---|
| 154 | 149 | if (IS_ERR(ddata->base)) |
|---|
| 155 | 150 | return PTR_ERR(ddata->base); |
|---|
| 156 | 151 | |
|---|
| 157 | 152 | enabled = in_be32(&ddata->base->swcrr) & SWCRR_SWEN; |
|---|
| 158 | 153 | if (!enabled && wdt_type->hw_enabled) { |
|---|
| 159 | | - pr_info("could not be enabled in software\n"); |
|---|
| 154 | + dev_info(dev, "could not be enabled in software\n"); |
|---|
| 160 | 155 | return -ENODEV; |
|---|
| 156 | + } |
|---|
| 157 | + |
|---|
| 158 | + res = platform_get_resource(ofdev, IORESOURCE_MEM, 1); |
|---|
| 159 | + if (res) { |
|---|
| 160 | + bool status; |
|---|
| 161 | + u32 __iomem *rsr = ioremap(res->start, resource_size(res)); |
|---|
| 162 | + |
|---|
| 163 | + if (!rsr) |
|---|
| 164 | + return -ENOMEM; |
|---|
| 165 | + |
|---|
| 166 | + status = in_be32(rsr) & wdt_type->rsr_mask; |
|---|
| 167 | + ddata->wdd.bootstatus = status ? WDIOF_CARDRESET : 0; |
|---|
| 168 | + /* clear reset status bits related to watchdog timer */ |
|---|
| 169 | + out_be32(rsr, wdt_type->rsr_mask); |
|---|
| 170 | + iounmap(rsr); |
|---|
| 171 | + |
|---|
| 172 | + dev_info(dev, "Last boot was %scaused by watchdog\n", |
|---|
| 173 | + status ? "" : "not "); |
|---|
| 161 | 174 | } |
|---|
| 162 | 175 | |
|---|
| 163 | 176 | spin_lock_init(&ddata->lock); |
|---|
| .. | .. |
|---|
| 166 | 179 | ddata->wdd.ops = &mpc8xxx_wdt_ops, |
|---|
| 167 | 180 | |
|---|
| 168 | 181 | ddata->wdd.timeout = WATCHDOG_TIMEOUT; |
|---|
| 169 | | - watchdog_init_timeout(&ddata->wdd, timeout, &ofdev->dev); |
|---|
| 182 | + watchdog_init_timeout(&ddata->wdd, timeout, dev); |
|---|
| 170 | 183 | |
|---|
| 171 | 184 | watchdog_set_nowayout(&ddata->wdd, nowayout); |
|---|
| 172 | 185 | |
|---|
| .. | .. |
|---|
| 187 | 200 | if (ddata->wdd.timeout < ddata->wdd.min_timeout) |
|---|
| 188 | 201 | ddata->wdd.timeout = ddata->wdd.min_timeout; |
|---|
| 189 | 202 | |
|---|
| 190 | | - ret = watchdog_register_device(&ddata->wdd); |
|---|
| 191 | | - if (ret) { |
|---|
| 192 | | - pr_err("cannot register watchdog device (err=%d)\n", ret); |
|---|
| 203 | + ret = devm_watchdog_register_device(dev, &ddata->wdd); |
|---|
| 204 | + if (ret) |
|---|
| 193 | 205 | return ret; |
|---|
| 194 | | - } |
|---|
| 195 | 206 | |
|---|
| 196 | | - pr_info("WDT driver for MPC8xxx initialized. mode:%s timeout=%d sec\n", |
|---|
| 197 | | - reset ? "reset" : "interrupt", ddata->wdd.timeout); |
|---|
| 207 | + dev_info(dev, |
|---|
| 208 | + "WDT driver for MPC8xxx initialized. mode:%s timeout=%d sec\n", |
|---|
| 209 | + reset ? "reset" : "interrupt", ddata->wdd.timeout); |
|---|
| 198 | 210 | |
|---|
| 199 | 211 | platform_set_drvdata(ofdev, ddata); |
|---|
| 200 | | - return 0; |
|---|
| 201 | | -} |
|---|
| 202 | | - |
|---|
| 203 | | -static int mpc8xxx_wdt_remove(struct platform_device *ofdev) |
|---|
| 204 | | -{ |
|---|
| 205 | | - struct mpc8xxx_wdt_ddata *ddata = platform_get_drvdata(ofdev); |
|---|
| 206 | | - |
|---|
| 207 | | - pr_crit("Watchdog removed, expect the %s soon!\n", |
|---|
| 208 | | - reset ? "reset" : "machine check exception"); |
|---|
| 209 | | - watchdog_unregister_device(&ddata->wdd); |
|---|
| 210 | | - |
|---|
| 211 | 212 | return 0; |
|---|
| 212 | 213 | } |
|---|
| 213 | 214 | |
|---|
| .. | .. |
|---|
| 216 | 217 | .compatible = "mpc83xx_wdt", |
|---|
| 217 | 218 | .data = &(struct mpc8xxx_wdt_type) { |
|---|
| 218 | 219 | .prescaler = 0x10000, |
|---|
| 220 | + .rsr_mask = BIT(3), /* RSR Bit SWRS */ |
|---|
| 219 | 221 | }, |
|---|
| 220 | 222 | }, |
|---|
| 221 | 223 | { |
|---|
| .. | .. |
|---|
| 223 | 225 | .data = &(struct mpc8xxx_wdt_type) { |
|---|
| 224 | 226 | .prescaler = 0x10000, |
|---|
| 225 | 227 | .hw_enabled = true, |
|---|
| 228 | + .rsr_mask = BIT(20), /* RSTRSCR Bit WDT_RR */ |
|---|
| 226 | 229 | }, |
|---|
| 227 | 230 | }, |
|---|
| 228 | 231 | { |
|---|
| .. | .. |
|---|
| 230 | 233 | .data = &(struct mpc8xxx_wdt_type) { |
|---|
| 231 | 234 | .prescaler = 0x800, |
|---|
| 232 | 235 | .hw_enabled = true, |
|---|
| 236 | + .rsr_mask = BIT(28), /* RSR Bit SWRS */ |
|---|
| 233 | 237 | }, |
|---|
| 234 | 238 | }, |
|---|
| 235 | 239 | {}, |
|---|
| .. | .. |
|---|
| 238 | 242 | |
|---|
| 239 | 243 | static struct platform_driver mpc8xxx_wdt_driver = { |
|---|
| 240 | 244 | .probe = mpc8xxx_wdt_probe, |
|---|
| 241 | | - .remove = mpc8xxx_wdt_remove, |
|---|
| 242 | 245 | .driver = { |
|---|
| 243 | 246 | .name = "mpc8xxx_wdt", |
|---|
| 244 | 247 | .of_match_table = mpc8xxx_wdt_match, |
|---|