0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
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
0030 #define IXP4XX_TIMER_FREQ 66666000
0031
0032
0033 #define IXP4XX_OSWT_OFFSET 0x14
0034 #define IXP4XX_OSWE_OFFSET 0x18
0035 #define IXP4XX_OSWK_OFFSET 0x1C
0036 #define IXP4XX_OSST_OFFSET 0x20
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
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
0140
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
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");