0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019 #include <linux/module.h>
0020 #include <linux/moduleparam.h>
0021 #include <linux/uaccess.h>
0022 #include <linux/watchdog.h>
0023 #include <linux/platform_device.h>
0024 #include <linux/mfd/kempld.h>
0025
0026 #define KEMPLD_WDT_STAGE_TIMEOUT(x) (0x1b + (x) * 4)
0027 #define KEMPLD_WDT_STAGE_CFG(x) (0x18 + (x))
0028 #define STAGE_CFG_GET_PRESCALER(x) (((x) & 0x30) >> 4)
0029 #define STAGE_CFG_SET_PRESCALER(x) (((x) & 0x3) << 4)
0030 #define STAGE_CFG_PRESCALER_MASK 0x30
0031 #define STAGE_CFG_ACTION_MASK 0x7
0032 #define STAGE_CFG_ASSERT (1 << 3)
0033
0034 #define KEMPLD_WDT_MAX_STAGES 2
0035 #define KEMPLD_WDT_KICK 0x16
0036 #define KEMPLD_WDT_CFG 0x17
0037 #define KEMPLD_WDT_CFG_ENABLE 0x10
0038 #define KEMPLD_WDT_CFG_ENABLE_LOCK 0x8
0039 #define KEMPLD_WDT_CFG_GLOBAL_LOCK 0x80
0040
0041 enum {
0042 ACTION_NONE = 0,
0043 ACTION_RESET,
0044 ACTION_NMI,
0045 ACTION_SMI,
0046 ACTION_SCI,
0047 ACTION_DELAY,
0048 };
0049
0050 enum {
0051 STAGE_TIMEOUT = 0,
0052 STAGE_PRETIMEOUT,
0053 };
0054
0055 enum {
0056 PRESCALER_21 = 0,
0057 PRESCALER_17,
0058 PRESCALER_12,
0059 };
0060
0061 static const u32 kempld_prescaler[] = {
0062 [PRESCALER_21] = (1 << 21) - 1,
0063 [PRESCALER_17] = (1 << 17) - 1,
0064 [PRESCALER_12] = (1 << 12) - 1,
0065 0,
0066 };
0067
0068 struct kempld_wdt_stage {
0069 unsigned int id;
0070 u32 mask;
0071 };
0072
0073 struct kempld_wdt_data {
0074 struct kempld_device_data *pld;
0075 struct watchdog_device wdd;
0076 unsigned int pretimeout;
0077 struct kempld_wdt_stage stage[KEMPLD_WDT_MAX_STAGES];
0078 #ifdef CONFIG_PM
0079 u8 pm_status_store;
0080 #endif
0081 };
0082
0083 #define DEFAULT_TIMEOUT 30
0084 #define DEFAULT_PRETIMEOUT 0
0085
0086 static unsigned int timeout = DEFAULT_TIMEOUT;
0087 module_param(timeout, uint, 0);
0088 MODULE_PARM_DESC(timeout,
0089 "Watchdog timeout in seconds. (>=0, default="
0090 __MODULE_STRING(DEFAULT_TIMEOUT) ")");
0091
0092 static unsigned int pretimeout = DEFAULT_PRETIMEOUT;
0093 module_param(pretimeout, uint, 0);
0094 MODULE_PARM_DESC(pretimeout,
0095 "Watchdog pretimeout in seconds. (>=0, default="
0096 __MODULE_STRING(DEFAULT_PRETIMEOUT) ")");
0097
0098 static bool nowayout = WATCHDOG_NOWAYOUT;
0099 module_param(nowayout, bool, 0);
0100 MODULE_PARM_DESC(nowayout,
0101 "Watchdog cannot be stopped once started (default="
0102 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
0103
0104 static int kempld_wdt_set_stage_action(struct kempld_wdt_data *wdt_data,
0105 struct kempld_wdt_stage *stage,
0106 u8 action)
0107 {
0108 struct kempld_device_data *pld = wdt_data->pld;
0109 u8 stage_cfg;
0110
0111 if (!stage || !stage->mask)
0112 return -EINVAL;
0113
0114 kempld_get_mutex(pld);
0115 stage_cfg = kempld_read8(pld, KEMPLD_WDT_STAGE_CFG(stage->id));
0116 stage_cfg &= ~STAGE_CFG_ACTION_MASK;
0117 stage_cfg |= (action & STAGE_CFG_ACTION_MASK);
0118
0119 if (action == ACTION_RESET)
0120 stage_cfg |= STAGE_CFG_ASSERT;
0121 else
0122 stage_cfg &= ~STAGE_CFG_ASSERT;
0123
0124 kempld_write8(pld, KEMPLD_WDT_STAGE_CFG(stage->id), stage_cfg);
0125 kempld_release_mutex(pld);
0126
0127 return 0;
0128 }
0129
0130 static int kempld_wdt_set_stage_timeout(struct kempld_wdt_data *wdt_data,
0131 struct kempld_wdt_stage *stage,
0132 unsigned int timeout)
0133 {
0134 struct kempld_device_data *pld = wdt_data->pld;
0135 u32 prescaler;
0136 u64 stage_timeout64;
0137 u32 stage_timeout;
0138 u32 remainder;
0139 u8 stage_cfg;
0140
0141 prescaler = kempld_prescaler[PRESCALER_21];
0142
0143 if (!stage)
0144 return -EINVAL;
0145
0146 stage_timeout64 = (u64)timeout * pld->pld_clock;
0147 remainder = do_div(stage_timeout64, prescaler);
0148 if (remainder)
0149 stage_timeout64++;
0150
0151 if (stage_timeout64 > stage->mask)
0152 return -EINVAL;
0153
0154 stage_timeout = stage_timeout64 & stage->mask;
0155
0156 kempld_get_mutex(pld);
0157 stage_cfg = kempld_read8(pld, KEMPLD_WDT_STAGE_CFG(stage->id));
0158 stage_cfg &= ~STAGE_CFG_PRESCALER_MASK;
0159 stage_cfg |= STAGE_CFG_SET_PRESCALER(PRESCALER_21);
0160 kempld_write8(pld, KEMPLD_WDT_STAGE_CFG(stage->id), stage_cfg);
0161 kempld_write32(pld, KEMPLD_WDT_STAGE_TIMEOUT(stage->id),
0162 stage_timeout);
0163 kempld_release_mutex(pld);
0164
0165 return 0;
0166 }
0167
0168
0169
0170
0171 static unsigned int kempld_wdt_get_timeout(struct kempld_wdt_data *wdt_data,
0172 struct kempld_wdt_stage *stage)
0173 {
0174 struct kempld_device_data *pld = wdt_data->pld;
0175 unsigned int timeout;
0176 u64 stage_timeout;
0177 u32 prescaler;
0178 u32 remainder;
0179 u8 stage_cfg;
0180
0181 if (!stage->mask)
0182 return 0;
0183
0184 stage_cfg = kempld_read8(pld, KEMPLD_WDT_STAGE_CFG(stage->id));
0185 stage_timeout = kempld_read32(pld, KEMPLD_WDT_STAGE_TIMEOUT(stage->id));
0186 prescaler = kempld_prescaler[STAGE_CFG_GET_PRESCALER(stage_cfg)];
0187
0188 stage_timeout = (stage_timeout & stage->mask) * prescaler;
0189 remainder = do_div(stage_timeout, pld->pld_clock);
0190 if (remainder)
0191 stage_timeout++;
0192
0193 timeout = stage_timeout;
0194 WARN_ON_ONCE(timeout != stage_timeout);
0195
0196 return timeout;
0197 }
0198
0199 static int kempld_wdt_set_timeout(struct watchdog_device *wdd,
0200 unsigned int timeout)
0201 {
0202 struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd);
0203 struct kempld_wdt_stage *pretimeout_stage;
0204 struct kempld_wdt_stage *timeout_stage;
0205 int ret;
0206
0207 timeout_stage = &wdt_data->stage[STAGE_TIMEOUT];
0208 pretimeout_stage = &wdt_data->stage[STAGE_PRETIMEOUT];
0209
0210 if (pretimeout_stage->mask && wdt_data->pretimeout > 0)
0211 timeout = wdt_data->pretimeout;
0212
0213 ret = kempld_wdt_set_stage_action(wdt_data, timeout_stage,
0214 ACTION_RESET);
0215 if (ret)
0216 return ret;
0217 ret = kempld_wdt_set_stage_timeout(wdt_data, timeout_stage,
0218 timeout);
0219 if (ret)
0220 return ret;
0221
0222 wdd->timeout = timeout;
0223 return 0;
0224 }
0225
0226 static int kempld_wdt_set_pretimeout(struct watchdog_device *wdd,
0227 unsigned int pretimeout)
0228 {
0229 struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd);
0230 struct kempld_wdt_stage *pretimeout_stage;
0231 u8 action = ACTION_NONE;
0232 int ret;
0233
0234 pretimeout_stage = &wdt_data->stage[STAGE_PRETIMEOUT];
0235
0236 if (!pretimeout_stage->mask)
0237 return -ENXIO;
0238
0239 if (pretimeout > wdd->timeout)
0240 return -EINVAL;
0241
0242 if (pretimeout > 0)
0243 action = ACTION_NMI;
0244
0245 ret = kempld_wdt_set_stage_action(wdt_data, pretimeout_stage,
0246 action);
0247 if (ret)
0248 return ret;
0249 ret = kempld_wdt_set_stage_timeout(wdt_data, pretimeout_stage,
0250 wdd->timeout - pretimeout);
0251 if (ret)
0252 return ret;
0253
0254 wdt_data->pretimeout = pretimeout;
0255 return 0;
0256 }
0257
0258 static void kempld_wdt_update_timeouts(struct kempld_wdt_data *wdt_data)
0259 {
0260 struct kempld_device_data *pld = wdt_data->pld;
0261 struct kempld_wdt_stage *pretimeout_stage;
0262 struct kempld_wdt_stage *timeout_stage;
0263 unsigned int pretimeout, timeout;
0264
0265 pretimeout_stage = &wdt_data->stage[STAGE_PRETIMEOUT];
0266 timeout_stage = &wdt_data->stage[STAGE_TIMEOUT];
0267
0268 kempld_get_mutex(pld);
0269 pretimeout = kempld_wdt_get_timeout(wdt_data, pretimeout_stage);
0270 timeout = kempld_wdt_get_timeout(wdt_data, timeout_stage);
0271 kempld_release_mutex(pld);
0272
0273 if (pretimeout)
0274 wdt_data->pretimeout = timeout;
0275 else
0276 wdt_data->pretimeout = 0;
0277
0278 wdt_data->wdd.timeout = pretimeout + timeout;
0279 }
0280
0281 static int kempld_wdt_start(struct watchdog_device *wdd)
0282 {
0283 struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd);
0284 struct kempld_device_data *pld = wdt_data->pld;
0285 u8 status;
0286 int ret;
0287
0288 ret = kempld_wdt_set_timeout(wdd, wdd->timeout);
0289 if (ret)
0290 return ret;
0291
0292 kempld_get_mutex(pld);
0293 status = kempld_read8(pld, KEMPLD_WDT_CFG);
0294 status |= KEMPLD_WDT_CFG_ENABLE;
0295 kempld_write8(pld, KEMPLD_WDT_CFG, status);
0296 status = kempld_read8(pld, KEMPLD_WDT_CFG);
0297 kempld_release_mutex(pld);
0298
0299
0300 if (!(status & KEMPLD_WDT_CFG_ENABLE))
0301 return -EACCES;
0302
0303 return 0;
0304 }
0305
0306 static int kempld_wdt_stop(struct watchdog_device *wdd)
0307 {
0308 struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd);
0309 struct kempld_device_data *pld = wdt_data->pld;
0310 u8 status;
0311
0312 kempld_get_mutex(pld);
0313 status = kempld_read8(pld, KEMPLD_WDT_CFG);
0314 status &= ~KEMPLD_WDT_CFG_ENABLE;
0315 kempld_write8(pld, KEMPLD_WDT_CFG, status);
0316 status = kempld_read8(pld, KEMPLD_WDT_CFG);
0317 kempld_release_mutex(pld);
0318
0319
0320 if (status & KEMPLD_WDT_CFG_ENABLE)
0321 return -EACCES;
0322
0323 return 0;
0324 }
0325
0326 static int kempld_wdt_keepalive(struct watchdog_device *wdd)
0327 {
0328 struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd);
0329 struct kempld_device_data *pld = wdt_data->pld;
0330
0331 kempld_get_mutex(pld);
0332 kempld_write8(pld, KEMPLD_WDT_KICK, 'K');
0333 kempld_release_mutex(pld);
0334
0335 return 0;
0336 }
0337
0338 static long kempld_wdt_ioctl(struct watchdog_device *wdd, unsigned int cmd,
0339 unsigned long arg)
0340 {
0341 struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd);
0342 void __user *argp = (void __user *)arg;
0343 int ret = -ENOIOCTLCMD;
0344 int __user *p = argp;
0345 int new_value;
0346
0347 switch (cmd) {
0348 case WDIOC_SETPRETIMEOUT:
0349 if (get_user(new_value, p))
0350 return -EFAULT;
0351 ret = kempld_wdt_set_pretimeout(wdd, new_value);
0352 if (ret)
0353 return ret;
0354 ret = kempld_wdt_keepalive(wdd);
0355 break;
0356 case WDIOC_GETPRETIMEOUT:
0357 ret = put_user(wdt_data->pretimeout, (int __user *)arg);
0358 break;
0359 }
0360
0361 return ret;
0362 }
0363
0364 static int kempld_wdt_probe_stages(struct watchdog_device *wdd)
0365 {
0366 struct kempld_wdt_data *wdt_data = watchdog_get_drvdata(wdd);
0367 struct kempld_device_data *pld = wdt_data->pld;
0368 struct kempld_wdt_stage *pretimeout_stage;
0369 struct kempld_wdt_stage *timeout_stage;
0370 u8 index, data, data_orig;
0371 u32 mask;
0372 int i, j;
0373
0374 pretimeout_stage = &wdt_data->stage[STAGE_PRETIMEOUT];
0375 timeout_stage = &wdt_data->stage[STAGE_TIMEOUT];
0376
0377 pretimeout_stage->mask = 0;
0378 timeout_stage->mask = 0;
0379
0380 for (i = 0; i < 3; i++) {
0381 index = KEMPLD_WDT_STAGE_TIMEOUT(i);
0382 mask = 0;
0383
0384 kempld_get_mutex(pld);
0385
0386 for (j = 0; j < 4; j++) {
0387 data_orig = kempld_read8(pld, index + j);
0388 kempld_write8(pld, index + j, 0x00);
0389 data = kempld_read8(pld, index + j);
0390
0391 if (data != 0x00)
0392 break;
0393 kempld_write8(pld, index + j, data_orig);
0394 mask |= 0xff << (j * 8);
0395 }
0396 kempld_release_mutex(pld);
0397
0398
0399 if (!timeout_stage->mask) {
0400 timeout_stage->mask = mask;
0401 timeout_stage->id = i;
0402 } else {
0403 if (pld->feature_mask & KEMPLD_FEATURE_BIT_NMI) {
0404 pretimeout_stage->mask = timeout_stage->mask;
0405 timeout_stage->mask = mask;
0406 pretimeout_stage->id = timeout_stage->id;
0407 timeout_stage->id = i;
0408 }
0409 break;
0410 }
0411 }
0412
0413 if (!timeout_stage->mask)
0414 return -ENODEV;
0415
0416 return 0;
0417 }
0418
0419 static const struct watchdog_info kempld_wdt_info = {
0420 .identity = "KEMPLD Watchdog",
0421 .options = WDIOF_SETTIMEOUT |
0422 WDIOF_KEEPALIVEPING |
0423 WDIOF_MAGICCLOSE |
0424 WDIOF_PRETIMEOUT
0425 };
0426
0427 static const struct watchdog_ops kempld_wdt_ops = {
0428 .owner = THIS_MODULE,
0429 .start = kempld_wdt_start,
0430 .stop = kempld_wdt_stop,
0431 .ping = kempld_wdt_keepalive,
0432 .set_timeout = kempld_wdt_set_timeout,
0433 .ioctl = kempld_wdt_ioctl,
0434 };
0435
0436 static int kempld_wdt_probe(struct platform_device *pdev)
0437 {
0438 struct kempld_device_data *pld = dev_get_drvdata(pdev->dev.parent);
0439 struct kempld_wdt_data *wdt_data;
0440 struct device *dev = &pdev->dev;
0441 struct watchdog_device *wdd;
0442 u8 status;
0443 int ret = 0;
0444
0445 wdt_data = devm_kzalloc(dev, sizeof(*wdt_data), GFP_KERNEL);
0446 if (!wdt_data)
0447 return -ENOMEM;
0448
0449 wdt_data->pld = pld;
0450 wdd = &wdt_data->wdd;
0451 wdd->parent = dev;
0452
0453 kempld_get_mutex(pld);
0454 status = kempld_read8(pld, KEMPLD_WDT_CFG);
0455 kempld_release_mutex(pld);
0456
0457
0458 if (status & (KEMPLD_WDT_CFG_ENABLE_LOCK |
0459 KEMPLD_WDT_CFG_GLOBAL_LOCK)) {
0460 if (!nowayout)
0461 dev_warn(dev,
0462 "Forcing nowayout - watchdog lock enabled!\n");
0463 nowayout = true;
0464 }
0465
0466 wdd->info = &kempld_wdt_info;
0467 wdd->ops = &kempld_wdt_ops;
0468
0469 watchdog_set_drvdata(wdd, wdt_data);
0470 watchdog_set_nowayout(wdd, nowayout);
0471
0472 ret = kempld_wdt_probe_stages(wdd);
0473 if (ret)
0474 return ret;
0475
0476 kempld_wdt_set_timeout(wdd, timeout);
0477 kempld_wdt_set_pretimeout(wdd, pretimeout);
0478
0479
0480 if (status & KEMPLD_WDT_CFG_ENABLE) {
0481
0482 kempld_wdt_update_timeouts(wdt_data);
0483 dev_info(dev, "Watchdog was already enabled\n");
0484 }
0485
0486 platform_set_drvdata(pdev, wdt_data);
0487 watchdog_stop_on_reboot(wdd);
0488 watchdog_stop_on_unregister(wdd);
0489 ret = devm_watchdog_register_device(dev, wdd);
0490 if (ret)
0491 return ret;
0492
0493 dev_info(dev, "Watchdog registered with %ds timeout\n", wdd->timeout);
0494
0495 return 0;
0496 }
0497
0498 #ifdef CONFIG_PM
0499
0500 static int kempld_wdt_suspend(struct platform_device *pdev,
0501 pm_message_t message)
0502 {
0503 struct kempld_wdt_data *wdt_data = platform_get_drvdata(pdev);
0504 struct kempld_device_data *pld = wdt_data->pld;
0505 struct watchdog_device *wdd = &wdt_data->wdd;
0506
0507 kempld_get_mutex(pld);
0508 wdt_data->pm_status_store = kempld_read8(pld, KEMPLD_WDT_CFG);
0509 kempld_release_mutex(pld);
0510
0511 kempld_wdt_update_timeouts(wdt_data);
0512
0513 if (wdt_data->pm_status_store & KEMPLD_WDT_CFG_ENABLE)
0514 return kempld_wdt_stop(wdd);
0515
0516 return 0;
0517 }
0518
0519
0520 static int kempld_wdt_resume(struct platform_device *pdev)
0521 {
0522 struct kempld_wdt_data *wdt_data = platform_get_drvdata(pdev);
0523 struct watchdog_device *wdd = &wdt_data->wdd;
0524
0525
0526
0527
0528
0529 if (wdt_data->pm_status_store & KEMPLD_WDT_CFG_ENABLE)
0530 return kempld_wdt_start(wdd);
0531 else
0532 return kempld_wdt_stop(wdd);
0533 }
0534 #else
0535 #define kempld_wdt_suspend NULL
0536 #define kempld_wdt_resume NULL
0537 #endif
0538
0539 static struct platform_driver kempld_wdt_driver = {
0540 .driver = {
0541 .name = "kempld-wdt",
0542 },
0543 .probe = kempld_wdt_probe,
0544 .suspend = kempld_wdt_suspend,
0545 .resume = kempld_wdt_resume,
0546 };
0547
0548 module_platform_driver(kempld_wdt_driver);
0549
0550 MODULE_DESCRIPTION("KEM PLD Watchdog Driver");
0551 MODULE_AUTHOR("Michael Brunner <michael.brunner@kontron.com>");
0552 MODULE_LICENSE("GPL");