Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * drivers/char/watchdog/ixp4xx_wdt.c
0004  *
0005  * Watchdog driver for Intel IXP4xx network processors
0006  *
0007  * Author: Deepak Saxena <dsaxena@plexity.net>
0008  * Author: Linus Walleij <linus.walleij@linaro.org>
0009  *
0010  * Copyright 2004 (c) MontaVista, Software, Inc.
0011  * Based on sa1100 driver, Copyright (C) 2000 Oleg Drokin <green@crimea.edu>
0012  */
0013 
0014 #include <linux/module.h>
0015 #include <linux/types.h>
0016 #include <linux/kernel.h>
0017 #include <linux/watchdog.h>
0018 #include <linux/bits.h>
0019 #include <linux/platform_device.h>
0020 #include <linux/clk.h>
0021 #include <linux/soc/ixp4xx/cpu.h>
0022 
0023 struct ixp4xx_wdt {
0024     struct watchdog_device wdd;
0025     void __iomem *base;
0026     unsigned long rate;
0027 };
0028 
0029 /* Fallback if we do not have a clock for this */
0030 #define IXP4XX_TIMER_FREQ   66666000
0031 
0032 /* Registers after the timer registers */
0033 #define IXP4XX_OSWT_OFFSET  0x14  /* Watchdog Timer */
0034 #define IXP4XX_OSWE_OFFSET  0x18  /* Watchdog Enable */
0035 #define IXP4XX_OSWK_OFFSET  0x1C  /* Watchdog Key */
0036 #define IXP4XX_OSST_OFFSET  0x20  /* Timer Status */
0037 
0038 #define IXP4XX_OSST_TIMER_WDOG_PEND 0x00000008
0039 #define IXP4XX_OSST_TIMER_WARM_RESET    0x00000010
0040 #define IXP4XX_WDT_KEY          0x0000482E
0041 #define IXP4XX_WDT_RESET_ENABLE     0x00000001
0042 #define IXP4XX_WDT_IRQ_ENABLE       0x00000002
0043 #define IXP4XX_WDT_COUNT_ENABLE     0x00000004
0044 
0045 static inline
0046 struct ixp4xx_wdt *to_ixp4xx_wdt(struct watchdog_device *wdd)
0047 {
0048     return container_of(wdd, struct ixp4xx_wdt, wdd);
0049 }
0050 
0051 static int ixp4xx_wdt_start(struct watchdog_device *wdd)
0052 {
0053     struct ixp4xx_wdt *iwdt = to_ixp4xx_wdt(wdd);
0054 
0055     __raw_writel(IXP4XX_WDT_KEY, iwdt->base + IXP4XX_OSWK_OFFSET);
0056     __raw_writel(0, iwdt->base + IXP4XX_OSWE_OFFSET);
0057     __raw_writel(wdd->timeout * iwdt->rate,
0058              iwdt->base + IXP4XX_OSWT_OFFSET);
0059     __raw_writel(IXP4XX_WDT_COUNT_ENABLE | IXP4XX_WDT_RESET_ENABLE,
0060              iwdt->base + IXP4XX_OSWE_OFFSET);
0061     __raw_writel(0, iwdt->base + IXP4XX_OSWK_OFFSET);
0062 
0063     return 0;
0064 }
0065 
0066 static int ixp4xx_wdt_stop(struct watchdog_device *wdd)
0067 {
0068     struct ixp4xx_wdt *iwdt = to_ixp4xx_wdt(wdd);
0069 
0070     __raw_writel(IXP4XX_WDT_KEY, iwdt->base + IXP4XX_OSWK_OFFSET);
0071     __raw_writel(0, iwdt->base + IXP4XX_OSWE_OFFSET);
0072     __raw_writel(0, iwdt->base + IXP4XX_OSWK_OFFSET);
0073 
0074     return 0;
0075 }
0076 
0077 static int ixp4xx_wdt_set_timeout(struct watchdog_device *wdd,
0078                   unsigned int timeout)
0079 {
0080     wdd->timeout = timeout;
0081     if (watchdog_active(wdd))
0082         ixp4xx_wdt_start(wdd);
0083 
0084     return 0;
0085 }
0086 
0087 static int ixp4xx_wdt_restart(struct watchdog_device *wdd,
0088                               unsigned long action, void *data)
0089 {
0090     struct ixp4xx_wdt *iwdt = to_ixp4xx_wdt(wdd);
0091 
0092     __raw_writel(IXP4XX_WDT_KEY, iwdt->base + IXP4XX_OSWK_OFFSET);
0093     __raw_writel(0, iwdt->base + IXP4XX_OSWT_OFFSET);
0094     __raw_writel(IXP4XX_WDT_COUNT_ENABLE | IXP4XX_WDT_RESET_ENABLE,
0095              iwdt->base + IXP4XX_OSWE_OFFSET);
0096 
0097     return 0;
0098 }
0099 
0100 static const struct watchdog_ops ixp4xx_wdt_ops = {
0101     .start = ixp4xx_wdt_start,
0102     .stop = ixp4xx_wdt_stop,
0103     .set_timeout = ixp4xx_wdt_set_timeout,
0104     .restart = ixp4xx_wdt_restart,
0105     .owner = THIS_MODULE,
0106 };
0107 
0108 static const struct watchdog_info ixp4xx_wdt_info = {
0109     .options = WDIOF_KEEPALIVEPING
0110         | WDIOF_MAGICCLOSE
0111         | WDIOF_SETTIMEOUT,
0112     .identity = KBUILD_MODNAME,
0113 };
0114 
0115 /* Devres-handled clock disablement */
0116 static void ixp4xx_clock_action(void *d)
0117 {
0118     clk_disable_unprepare(d);
0119 }
0120 
0121 static int ixp4xx_wdt_probe(struct platform_device *pdev)
0122 {
0123     struct device *dev = &pdev->dev;
0124     struct ixp4xx_wdt *iwdt;
0125     struct clk *clk;
0126     int ret;
0127 
0128     if (!(read_cpuid_id() & 0xf) && !cpu_is_ixp46x()) {
0129         dev_err(dev, "Rev. A0 IXP42x CPU detected - watchdog disabled\n");
0130         return -ENODEV;
0131     }
0132 
0133     iwdt = devm_kzalloc(dev, sizeof(*iwdt), GFP_KERNEL);
0134     if (!iwdt)
0135         return -ENOMEM;
0136     iwdt->base = (void __iomem *)dev->platform_data;
0137 
0138     /*
0139      * Retrieve rate from a fixed clock from the device tree if
0140      * the parent has that, else use the default clock rate.
0141      */
0142     clk = devm_clk_get(dev->parent, NULL);
0143     if (!IS_ERR(clk)) {
0144         ret = clk_prepare_enable(clk);
0145         if (ret)
0146             return ret;
0147         ret = devm_add_action_or_reset(dev, ixp4xx_clock_action, clk);
0148         if (ret)
0149             return ret;
0150         iwdt->rate = clk_get_rate(clk);
0151     }
0152     if (!iwdt->rate)
0153         iwdt->rate = IXP4XX_TIMER_FREQ;
0154 
0155     iwdt->wdd.info = &ixp4xx_wdt_info;
0156     iwdt->wdd.ops = &ixp4xx_wdt_ops;
0157     iwdt->wdd.min_timeout = 1;
0158     iwdt->wdd.max_timeout = U32_MAX / iwdt->rate;
0159     iwdt->wdd.parent = dev;
0160     /* Default to 60 seconds */
0161     iwdt->wdd.timeout = 60U;
0162     watchdog_init_timeout(&iwdt->wdd, 0, dev);
0163 
0164     if (__raw_readl(iwdt->base + IXP4XX_OSST_OFFSET) &
0165         IXP4XX_OSST_TIMER_WARM_RESET)
0166         iwdt->wdd.bootstatus = WDIOF_CARDRESET;
0167 
0168     ret = devm_watchdog_register_device(dev, &iwdt->wdd);
0169     if (ret)
0170         return ret;
0171 
0172     dev_info(dev, "IXP4xx watchdog available\n");
0173 
0174     return 0;
0175 }
0176 
0177 static struct platform_driver ixp4xx_wdt_driver = {
0178     .probe = ixp4xx_wdt_probe,
0179     .driver = {
0180         .name   = "ixp4xx-watchdog",
0181     },
0182 };
0183 module_platform_driver(ixp4xx_wdt_driver);
0184 
0185 MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net>");
0186 MODULE_DESCRIPTION("IXP4xx Network Processor Watchdog");
0187 MODULE_LICENSE("GPL");