linux/drivers/watchdog/rt2880_wdt.c
<<
>>
Prefs
   1/*
   2 * Ralink RT288x/RT3xxx/MT76xx built-in hardware watchdog timer
   3 *
   4 * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
   5 * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
   6 *
   7 * This driver was based on: drivers/watchdog/softdog.c
   8 *
   9 * This program is free software; you can redistribute it and/or modify it
  10 * under the terms of the GNU General Public License version 2 as published
  11 * by the Free Software Foundation.
  12 */
  13
  14#include <linux/clk.h>
  15#include <linux/reset.h>
  16#include <linux/module.h>
  17#include <linux/kernel.h>
  18#include <linux/watchdog.h>
  19#include <linux/moduleparam.h>
  20#include <linux/platform_device.h>
  21
  22#include <asm/mach-ralink/ralink_regs.h>
  23
  24#define SYSC_RSTSTAT                    0x38
  25#define WDT_RST_CAUSE                   BIT(1)
  26
  27#define RALINK_WDT_TIMEOUT              30
  28#define RALINK_WDT_PRESCALE             65536
  29
  30#define TIMER_REG_TMR1LOAD              0x00
  31#define TIMER_REG_TMR1CTL               0x08
  32
  33#define TMRSTAT_TMR1RST                 BIT(5)
  34
  35#define TMR1CTL_ENABLE                  BIT(7)
  36#define TMR1CTL_MODE_SHIFT              4
  37#define TMR1CTL_MODE_MASK               0x3
  38#define TMR1CTL_MODE_FREE_RUNNING       0x0
  39#define TMR1CTL_MODE_PERIODIC           0x1
  40#define TMR1CTL_MODE_TIMEOUT            0x2
  41#define TMR1CTL_MODE_WDT                0x3
  42#define TMR1CTL_PRESCALE_MASK           0xf
  43#define TMR1CTL_PRESCALE_65536          0xf
  44
  45static struct clk *rt288x_wdt_clk;
  46static unsigned long rt288x_wdt_freq;
  47static void __iomem *rt288x_wdt_base;
  48
  49static bool nowayout = WATCHDOG_NOWAYOUT;
  50module_param(nowayout, bool, 0);
  51MODULE_PARM_DESC(nowayout,
  52                "Watchdog cannot be stopped once started (default="
  53                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
  54
  55static inline void rt_wdt_w32(unsigned reg, u32 val)
  56{
  57        iowrite32(val, rt288x_wdt_base + reg);
  58}
  59
  60static inline u32 rt_wdt_r32(unsigned reg)
  61{
  62        return ioread32(rt288x_wdt_base + reg);
  63}
  64
  65static int rt288x_wdt_ping(struct watchdog_device *w)
  66{
  67        rt_wdt_w32(TIMER_REG_TMR1LOAD, w->timeout * rt288x_wdt_freq);
  68
  69        return 0;
  70}
  71
  72static int rt288x_wdt_start(struct watchdog_device *w)
  73{
  74        u32 t;
  75
  76        t = rt_wdt_r32(TIMER_REG_TMR1CTL);
  77        t &= ~(TMR1CTL_MODE_MASK << TMR1CTL_MODE_SHIFT |
  78                TMR1CTL_PRESCALE_MASK);
  79        t |= (TMR1CTL_MODE_WDT << TMR1CTL_MODE_SHIFT |
  80                TMR1CTL_PRESCALE_65536);
  81        rt_wdt_w32(TIMER_REG_TMR1CTL, t);
  82
  83        rt288x_wdt_ping(w);
  84
  85        t = rt_wdt_r32(TIMER_REG_TMR1CTL);
  86        t |= TMR1CTL_ENABLE;
  87        rt_wdt_w32(TIMER_REG_TMR1CTL, t);
  88
  89        return 0;
  90}
  91
  92static int rt288x_wdt_stop(struct watchdog_device *w)
  93{
  94        u32 t;
  95
  96        rt288x_wdt_ping(w);
  97
  98        t = rt_wdt_r32(TIMER_REG_TMR1CTL);
  99        t &= ~TMR1CTL_ENABLE;
 100        rt_wdt_w32(TIMER_REG_TMR1CTL, t);
 101
 102        return 0;
 103}
 104
 105static int rt288x_wdt_set_timeout(struct watchdog_device *w, unsigned int t)
 106{
 107        w->timeout = t;
 108        rt288x_wdt_ping(w);
 109
 110        return 0;
 111}
 112
 113static int rt288x_wdt_bootcause(void)
 114{
 115        if (rt_sysc_r32(SYSC_RSTSTAT) & WDT_RST_CAUSE)
 116                return WDIOF_CARDRESET;
 117
 118        return 0;
 119}
 120
 121static struct watchdog_info rt288x_wdt_info = {
 122        .identity = "Ralink Watchdog",
 123        .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
 124};
 125
 126static struct watchdog_ops rt288x_wdt_ops = {
 127        .owner = THIS_MODULE,
 128        .start = rt288x_wdt_start,
 129        .stop = rt288x_wdt_stop,
 130        .ping = rt288x_wdt_ping,
 131        .set_timeout = rt288x_wdt_set_timeout,
 132};
 133
 134static struct watchdog_device rt288x_wdt_dev = {
 135        .info = &rt288x_wdt_info,
 136        .ops = &rt288x_wdt_ops,
 137        .min_timeout = 1,
 138};
 139
 140static int rt288x_wdt_probe(struct platform_device *pdev)
 141{
 142        struct resource *res;
 143        int ret;
 144
 145        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 146        rt288x_wdt_base = devm_ioremap_resource(&pdev->dev, res);
 147        if (IS_ERR(rt288x_wdt_base))
 148                return PTR_ERR(rt288x_wdt_base);
 149
 150        rt288x_wdt_clk = devm_clk_get(&pdev->dev, NULL);
 151        if (IS_ERR(rt288x_wdt_clk))
 152                return PTR_ERR(rt288x_wdt_clk);
 153
 154        device_reset(&pdev->dev);
 155
 156        rt288x_wdt_freq = clk_get_rate(rt288x_wdt_clk) / RALINK_WDT_PRESCALE;
 157
 158        rt288x_wdt_dev.dev = &pdev->dev;
 159        rt288x_wdt_dev.bootstatus = rt288x_wdt_bootcause();
 160
 161        rt288x_wdt_dev.max_timeout = (0xfffful / rt288x_wdt_freq);
 162        rt288x_wdt_dev.timeout = rt288x_wdt_dev.max_timeout;
 163
 164        watchdog_set_nowayout(&rt288x_wdt_dev, nowayout);
 165
 166        ret = watchdog_register_device(&rt288x_wdt_dev);
 167        if (!ret)
 168                dev_info(&pdev->dev, "Initialized\n");
 169
 170        return 0;
 171}
 172
 173static int rt288x_wdt_remove(struct platform_device *pdev)
 174{
 175        watchdog_unregister_device(&rt288x_wdt_dev);
 176
 177        return 0;
 178}
 179
 180static void rt288x_wdt_shutdown(struct platform_device *pdev)
 181{
 182        rt288x_wdt_stop(&rt288x_wdt_dev);
 183}
 184
 185static const struct of_device_id rt288x_wdt_match[] = {
 186        { .compatible = "ralink,rt2880-wdt" },
 187        {},
 188};
 189MODULE_DEVICE_TABLE(of, rt288x_wdt_match);
 190
 191static struct platform_driver rt288x_wdt_driver = {
 192        .probe          = rt288x_wdt_probe,
 193        .remove         = rt288x_wdt_remove,
 194        .shutdown       = rt288x_wdt_shutdown,
 195        .driver         = {
 196                .name           = KBUILD_MODNAME,
 197                .of_match_table = rt288x_wdt_match,
 198        },
 199};
 200
 201module_platform_driver(rt288x_wdt_driver);
 202
 203MODULE_DESCRIPTION("MediaTek/Ralink RT288x/RT3xxx hardware watchdog driver");
 204MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org");
 205MODULE_LICENSE("GPL v2");
 206
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.