Lines Matching +full:wdt +full:- +full:enable +full:- +full:once

1 // SPDX-License-Identifier: GPL-2.0-or-later
72 * DOC: Quirk flags for different Samsung watchdog IP-cores
77 * differences in both watchdog and PMU IP-cores should be accounted for. Quirk
83 * clear the interrupt once the interrupt service routine is complete. It's
84 * write-only, writing any values to this register clears the interrupt, but
88 * WDT reset request. On old SoCs it's usually called MASK_WDT_RESET_REQUEST,
98 * register. If 'mask_bit' bit is set, PMU will disable WDT reset when
102 * with "watchdog counter enable" bit. That bit should be set to make watchdog
131 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
136 * struct s3c2410_wdt_variant - Per-variant config data
148 * @cnt_en_reg: Offset in pmureg for the register that enables WDT counter.
149 * @cnt_en_bit: Bit number for "watchdog counter enable" in cnt_en register.
168 struct clk *src_clk; /* for WDT counter */
268 { .compatible = "samsung,s3c2410-wdt",
270 { .compatible = "samsung,s3c6410-wdt",
272 { .compatible = "samsung,exynos5250-wdt",
274 { .compatible = "samsung,exynos5420-wdt",
276 { .compatible = "samsung,exynos7-wdt",
278 { .compatible = "samsung,exynos850-wdt",
280 { .compatible = "samsung,exynosautov9-wdt",
289 .name = "s3c2410-wdt",
298 static inline unsigned long s3c2410wdt_get_freq(struct s3c2410_wdt *wdt) in s3c2410wdt_get_freq() argument
300 return clk_get_rate(wdt->src_clk ? wdt->src_clk : wdt->bus_clk); in s3c2410wdt_get_freq()
303 static inline unsigned int s3c2410wdt_max_timeout(struct s3c2410_wdt *wdt) in s3c2410wdt_max_timeout() argument
305 const unsigned long freq = s3c2410wdt_get_freq(wdt); in s3c2410wdt_max_timeout()
316 static int s3c2410wdt_disable_wdt_reset(struct s3c2410_wdt *wdt, bool mask) in s3c2410wdt_disable_wdt_reset() argument
318 const u32 mask_val = BIT(wdt->drv_data->mask_bit); in s3c2410wdt_disable_wdt_reset()
322 ret = regmap_update_bits(wdt->pmureg, wdt->drv_data->disable_reg, in s3c2410wdt_disable_wdt_reset()
325 dev_err(wdt->dev, "failed to update reg(%d)\n", ret); in s3c2410wdt_disable_wdt_reset()
330 static int s3c2410wdt_mask_wdt_reset(struct s3c2410_wdt *wdt, bool mask) in s3c2410wdt_mask_wdt_reset() argument
332 const u32 mask_val = BIT(wdt->drv_data->mask_bit); in s3c2410wdt_mask_wdt_reset()
333 const bool val_inv = wdt->drv_data->mask_reset_inv; in s3c2410wdt_mask_wdt_reset()
337 ret = regmap_update_bits(wdt->pmureg, wdt->drv_data->mask_reset_reg, in s3c2410wdt_mask_wdt_reset()
340 dev_err(wdt->dev, "failed to update reg(%d)\n", ret); in s3c2410wdt_mask_wdt_reset()
345 static int s3c2410wdt_enable_counter(struct s3c2410_wdt *wdt, bool en) in s3c2410wdt_enable_counter() argument
347 const u32 mask_val = BIT(wdt->drv_data->cnt_en_bit); in s3c2410wdt_enable_counter()
351 ret = regmap_update_bits(wdt->pmureg, wdt->drv_data->cnt_en_reg, in s3c2410wdt_enable_counter()
354 dev_err(wdt->dev, "failed to update reg(%d)\n", ret); in s3c2410wdt_enable_counter()
359 static int s3c2410wdt_enable(struct s3c2410_wdt *wdt, bool en) in s3c2410wdt_enable() argument
363 if (wdt->drv_data->quirks & QUIRK_HAS_PMU_AUTO_DISABLE) { in s3c2410wdt_enable()
364 ret = s3c2410wdt_disable_wdt_reset(wdt, !en); in s3c2410wdt_enable()
369 if (wdt->drv_data->quirks & QUIRK_HAS_PMU_MASK_RESET) { in s3c2410wdt_enable()
370 ret = s3c2410wdt_mask_wdt_reset(wdt, !en); in s3c2410wdt_enable()
375 if (wdt->drv_data->quirks & QUIRK_HAS_PMU_CNT_EN) { in s3c2410wdt_enable()
376 ret = s3c2410wdt_enable_counter(wdt, en); in s3c2410wdt_enable()
386 struct s3c2410_wdt *wdt = watchdog_get_drvdata(wdd); in s3c2410wdt_keepalive() local
388 spin_lock(&wdt->lock); in s3c2410wdt_keepalive()
389 writel(wdt->count, wdt->reg_base + S3C2410_WTCNT); in s3c2410wdt_keepalive()
390 spin_unlock(&wdt->lock); in s3c2410wdt_keepalive()
395 static void __s3c2410wdt_stop(struct s3c2410_wdt *wdt) in __s3c2410wdt_stop() argument
399 wtcon = readl(wdt->reg_base + S3C2410_WTCON); in __s3c2410wdt_stop()
401 writel(wtcon, wdt->reg_base + S3C2410_WTCON); in __s3c2410wdt_stop()
406 struct s3c2410_wdt *wdt = watchdog_get_drvdata(wdd); in s3c2410wdt_stop() local
408 spin_lock(&wdt->lock); in s3c2410wdt_stop()
409 __s3c2410wdt_stop(wdt); in s3c2410wdt_stop()
410 spin_unlock(&wdt->lock); in s3c2410wdt_stop()
418 struct s3c2410_wdt *wdt = watchdog_get_drvdata(wdd); in s3c2410wdt_start() local
420 spin_lock(&wdt->lock); in s3c2410wdt_start()
422 __s3c2410wdt_stop(wdt); in s3c2410wdt_start()
424 wtcon = readl(wdt->reg_base + S3C2410_WTCON); in s3c2410wdt_start()
435 dev_dbg(wdt->dev, "Starting watchdog: count=0x%08x, wtcon=%08lx\n", in s3c2410wdt_start()
436 wdt->count, wtcon); in s3c2410wdt_start()
438 writel(wdt->count, wdt->reg_base + S3C2410_WTDAT); in s3c2410wdt_start()
439 writel(wdt->count, wdt->reg_base + S3C2410_WTCNT); in s3c2410wdt_start()
440 writel(wtcon, wdt->reg_base + S3C2410_WTCON); in s3c2410wdt_start()
441 spin_unlock(&wdt->lock); in s3c2410wdt_start()
446 static inline int s3c2410wdt_is_running(struct s3c2410_wdt *wdt) in s3c2410wdt_is_running() argument
448 return readl(wdt->reg_base + S3C2410_WTCON) & S3C2410_WTCON_ENABLE; in s3c2410wdt_is_running()
454 struct s3c2410_wdt *wdt = watchdog_get_drvdata(wdd); in s3c2410wdt_set_heartbeat() local
455 unsigned long freq = s3c2410wdt_get_freq(wdt); in s3c2410wdt_set_heartbeat()
461 return -EINVAL; in s3c2410wdt_set_heartbeat()
466 dev_dbg(wdt->dev, "Heartbeat: count=%d, timeout=%d, freq=%lu\n", in s3c2410wdt_set_heartbeat()
478 dev_err(wdt->dev, "timeout %d too big\n", timeout); in s3c2410wdt_set_heartbeat()
479 return -EINVAL; in s3c2410wdt_set_heartbeat()
483 dev_dbg(wdt->dev, "Heartbeat: timeout=%d, divisor=%d, count=%d (%08x)\n", in s3c2410wdt_set_heartbeat()
487 wdt->count = count; in s3c2410wdt_set_heartbeat()
489 /* update the pre-scaler */ in s3c2410wdt_set_heartbeat()
490 wtcon = readl(wdt->reg_base + S3C2410_WTCON); in s3c2410wdt_set_heartbeat()
492 wtcon |= S3C2410_WTCON_PRESCALE(divisor-1); in s3c2410wdt_set_heartbeat()
494 writel(count, wdt->reg_base + S3C2410_WTDAT); in s3c2410wdt_set_heartbeat()
495 writel(wtcon, wdt->reg_base + S3C2410_WTCON); in s3c2410wdt_set_heartbeat()
497 wdd->timeout = (count * divisor) / freq; in s3c2410wdt_set_heartbeat()
505 struct s3c2410_wdt *wdt = watchdog_get_drvdata(wdd); in s3c2410wdt_restart() local
506 void __iomem *wdt_base = wdt->reg_base; in s3c2410wdt_restart()
553 struct s3c2410_wdt *wdt = platform_get_drvdata(param); in s3c2410wdt_irq() local
555 dev_info(wdt->dev, "watchdog timer expired (irq)\n"); in s3c2410wdt_irq()
557 s3c2410wdt_keepalive(&wdt->wdt_device); in s3c2410wdt_irq()
559 if (wdt->drv_data->quirks & QUIRK_HAS_WTCLRINT_REG) in s3c2410wdt_irq()
560 writel(0x1, wdt->reg_base + S3C2410_WTCLRINT); in s3c2410wdt_irq()
571 struct s3c2410_wdt *wdt = freq_to_wdt(nb); in s3c2410wdt_cpufreq_transition() local
573 if (!s3c2410wdt_is_running(wdt)) in s3c2410wdt_cpufreq_transition()
578 * watchdog to trigger, we perform an keep-alive if in s3c2410wdt_cpufreq_transition()
582 s3c2410wdt_keepalive(&wdt->wdt_device); in s3c2410wdt_cpufreq_transition()
584 s3c2410wdt_stop(&wdt->wdt_device); in s3c2410wdt_cpufreq_transition()
586 ret = s3c2410wdt_set_heartbeat(&wdt->wdt_device, in s3c2410wdt_cpufreq_transition()
587 wdt->wdt_device.timeout); in s3c2410wdt_cpufreq_transition()
590 s3c2410wdt_start(&wdt->wdt_device); in s3c2410wdt_cpufreq_transition()
599 dev_err(wdt->dev, "cannot set new value for timeout %d\n", in s3c2410wdt_cpufreq_transition()
600 wdt->wdt_device.timeout); in s3c2410wdt_cpufreq_transition()
604 static inline int s3c2410wdt_cpufreq_register(struct s3c2410_wdt *wdt) in s3c2410wdt_cpufreq_register() argument
606 wdt->freq_transition.notifier_call = s3c2410wdt_cpufreq_transition; in s3c2410wdt_cpufreq_register()
608 return cpufreq_register_notifier(&wdt->freq_transition, in s3c2410wdt_cpufreq_register()
612 static inline void s3c2410wdt_cpufreq_deregister(struct s3c2410_wdt *wdt) in s3c2410wdt_cpufreq_deregister() argument
614 wdt->freq_transition.notifier_call = s3c2410wdt_cpufreq_transition; in s3c2410wdt_cpufreq_deregister()
616 cpufreq_unregister_notifier(&wdt->freq_transition, in s3c2410wdt_cpufreq_deregister()
622 static inline int s3c2410wdt_cpufreq_register(struct s3c2410_wdt *wdt) in s3c2410wdt_cpufreq_register() argument
627 static inline void s3c2410wdt_cpufreq_deregister(struct s3c2410_wdt *wdt) in s3c2410wdt_cpufreq_deregister() argument
632 static inline unsigned int s3c2410wdt_get_bootstatus(struct s3c2410_wdt *wdt) in s3c2410wdt_get_bootstatus() argument
637 if (!(wdt->drv_data->quirks & QUIRK_HAS_PMU_RST_STAT)) in s3c2410wdt_get_bootstatus()
640 ret = regmap_read(wdt->pmureg, wdt->drv_data->rst_stat_reg, &rst_stat); in s3c2410wdt_get_bootstatus()
642 dev_warn(wdt->dev, "Couldn't get RST_STAT register\n"); in s3c2410wdt_get_bootstatus()
643 else if (rst_stat & BIT(wdt->drv_data->rst_stat_bit)) in s3c2410wdt_get_bootstatus()
653 struct device *dev = &pdev->dev; in s3c2410_get_wdt_drv_data()
659 platform_get_device_id(pdev)->driver_data; in s3c2410_get_wdt_drv_data()
669 err = of_property_read_u32(dev->of_node, in s3c2410_get_wdt_drv_data()
670 "samsung,cluster-index", &index); in s3c2410_get_wdt_drv_data()
695 struct device *dev = &pdev->dev; in s3c2410wdt_probe()
696 struct s3c2410_wdt *wdt; in s3c2410wdt_probe() local
701 wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL); in s3c2410wdt_probe()
702 if (!wdt) in s3c2410wdt_probe()
703 return -ENOMEM; in s3c2410wdt_probe()
705 wdt->dev = dev; in s3c2410wdt_probe()
706 spin_lock_init(&wdt->lock); in s3c2410wdt_probe()
707 wdt->wdt_device = s3c2410_wdd; in s3c2410wdt_probe()
709 wdt->drv_data = s3c2410_get_wdt_drv_data(pdev); in s3c2410wdt_probe()
710 if (!wdt->drv_data) in s3c2410wdt_probe()
711 return -EINVAL; in s3c2410wdt_probe()
713 if (wdt->drv_data->quirks & QUIRKS_HAVE_PMUREG) { in s3c2410wdt_probe()
714 wdt->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node, in s3c2410wdt_probe()
715 "samsung,syscon-phandle"); in s3c2410wdt_probe()
716 if (IS_ERR(wdt->pmureg)) { in s3c2410wdt_probe()
718 return PTR_ERR(wdt->pmureg); in s3c2410wdt_probe()
727 wdt->reg_base = devm_platform_ioremap_resource(pdev, 0); in s3c2410wdt_probe()
728 if (IS_ERR(wdt->reg_base)) in s3c2410wdt_probe()
729 return PTR_ERR(wdt->reg_base); in s3c2410wdt_probe()
731 wdt->bus_clk = devm_clk_get(dev, "watchdog"); in s3c2410wdt_probe()
732 if (IS_ERR(wdt->bus_clk)) { in s3c2410wdt_probe()
734 return PTR_ERR(wdt->bus_clk); in s3c2410wdt_probe()
737 ret = clk_prepare_enable(wdt->bus_clk); in s3c2410wdt_probe()
739 dev_err(dev, "failed to enable bus clock\n"); in s3c2410wdt_probe()
744 * "watchdog_src" clock is optional; if it's not present -- just skip it in s3c2410wdt_probe()
747 wdt->src_clk = devm_clk_get_optional(dev, "watchdog_src"); in s3c2410wdt_probe()
748 if (IS_ERR(wdt->src_clk)) { in s3c2410wdt_probe()
749 dev_err_probe(dev, PTR_ERR(wdt->src_clk), in s3c2410wdt_probe()
751 ret = PTR_ERR(wdt->src_clk); in s3c2410wdt_probe()
755 ret = clk_prepare_enable(wdt->src_clk); in s3c2410wdt_probe()
757 dev_err(dev, "failed to enable source clock\n"); in s3c2410wdt_probe()
761 wdt->wdt_device.min_timeout = 1; in s3c2410wdt_probe()
762 wdt->wdt_device.max_timeout = s3c2410wdt_max_timeout(wdt); in s3c2410wdt_probe()
764 ret = s3c2410wdt_cpufreq_register(wdt); in s3c2410wdt_probe()
770 watchdog_set_drvdata(&wdt->wdt_device, wdt); in s3c2410wdt_probe()
775 watchdog_init_timeout(&wdt->wdt_device, tmr_margin, dev); in s3c2410wdt_probe()
776 ret = s3c2410wdt_set_heartbeat(&wdt->wdt_device, in s3c2410wdt_probe()
777 wdt->wdt_device.timeout); in s3c2410wdt_probe()
779 ret = s3c2410wdt_set_heartbeat(&wdt->wdt_device, in s3c2410wdt_probe()
791 pdev->name, pdev); in s3c2410wdt_probe()
797 watchdog_set_nowayout(&wdt->wdt_device, nowayout); in s3c2410wdt_probe()
798 watchdog_set_restart_priority(&wdt->wdt_device, 128); in s3c2410wdt_probe()
800 wdt->wdt_device.bootstatus = s3c2410wdt_get_bootstatus(wdt); in s3c2410wdt_probe()
801 wdt->wdt_device.parent = dev; in s3c2410wdt_probe()
804 * If "tmr_atboot" param is non-zero, start the watchdog right now. Also in s3c2410wdt_probe()
812 s3c2410wdt_start(&wdt->wdt_device); in s3c2410wdt_probe()
813 set_bit(WDOG_HW_RUNNING, &wdt->wdt_device.status); in s3c2410wdt_probe()
815 s3c2410wdt_stop(&wdt->wdt_device); in s3c2410wdt_probe()
818 ret = watchdog_register_device(&wdt->wdt_device); in s3c2410wdt_probe()
822 ret = s3c2410wdt_enable(wdt, true); in s3c2410wdt_probe()
826 platform_set_drvdata(pdev, wdt); in s3c2410wdt_probe()
830 wtcon = readl(wdt->reg_base + S3C2410_WTCON); in s3c2410wdt_probe()
840 watchdog_unregister_device(&wdt->wdt_device); in s3c2410wdt_probe()
843 s3c2410wdt_cpufreq_deregister(wdt); in s3c2410wdt_probe()
846 clk_disable_unprepare(wdt->src_clk); in s3c2410wdt_probe()
849 clk_disable_unprepare(wdt->bus_clk); in s3c2410wdt_probe()
857 struct s3c2410_wdt *wdt = platform_get_drvdata(dev); in s3c2410wdt_remove() local
859 ret = s3c2410wdt_enable(wdt, false); in s3c2410wdt_remove()
863 watchdog_unregister_device(&wdt->wdt_device); in s3c2410wdt_remove()
865 s3c2410wdt_cpufreq_deregister(wdt); in s3c2410wdt_remove()
867 clk_disable_unprepare(wdt->src_clk); in s3c2410wdt_remove()
868 clk_disable_unprepare(wdt->bus_clk); in s3c2410wdt_remove()
875 struct s3c2410_wdt *wdt = platform_get_drvdata(dev); in s3c2410wdt_shutdown() local
877 s3c2410wdt_enable(wdt, false); in s3c2410wdt_shutdown()
878 s3c2410wdt_stop(&wdt->wdt_device); in s3c2410wdt_shutdown()
884 struct s3c2410_wdt *wdt = dev_get_drvdata(dev); in s3c2410wdt_suspend() local
887 wdt->wtcon_save = readl(wdt->reg_base + S3C2410_WTCON); in s3c2410wdt_suspend()
888 wdt->wtdat_save = readl(wdt->reg_base + S3C2410_WTDAT); in s3c2410wdt_suspend()
890 ret = s3c2410wdt_enable(wdt, false); in s3c2410wdt_suspend()
895 s3c2410wdt_stop(&wdt->wdt_device); in s3c2410wdt_suspend()
903 struct s3c2410_wdt *wdt = dev_get_drvdata(dev); in s3c2410wdt_resume() local
906 writel(wdt->wtdat_save, wdt->reg_base + S3C2410_WTDAT); in s3c2410wdt_resume()
907 writel(wdt->wtdat_save, wdt->reg_base + S3C2410_WTCNT);/* Reset count */ in s3c2410wdt_resume()
908 writel(wdt->wtcon_save, wdt->reg_base + S3C2410_WTCON); in s3c2410wdt_resume()
910 ret = s3c2410wdt_enable(wdt, true); in s3c2410wdt_resume()
915 (wdt->wtcon_save & S3C2410_WTCON_ENABLE) ? "en" : "dis"); in s3c2410wdt_resume()
929 .name = "s3c2410-wdt",