linux/drivers/watchdog/davinci_wdt.c
<<
>>
Prefs
   1/*
   2 * drivers/char/watchdog/davinci_wdt.c
   3 *
   4 * Watchdog driver for DaVinci DM644x/DM646x processors
   5 *
   6 * Copyright (C) 2006-2013 Texas Instruments.
   7 *
   8 * 2007 (c) MontaVista Software, Inc. This file is licensed under
   9 * the terms of the GNU General Public License version 2. This program
  10 * is licensed "as is" without any warranty of any kind, whether express
  11 * or implied.
  12 */
  13
  14#include <linux/module.h>
  15#include <linux/moduleparam.h>
  16#include <linux/types.h>
  17#include <linux/kernel.h>
  18#include <linux/watchdog.h>
  19#include <linux/platform_device.h>
  20#include <linux/io.h>
  21#include <linux/device.h>
  22#include <linux/clk.h>
  23#include <linux/err.h>
  24
  25#define MODULE_NAME "DAVINCI-WDT: "
  26
  27#define DEFAULT_HEARTBEAT 60
  28#define MAX_HEARTBEAT     600   /* really the max margin is 264/27MHz*/
  29
  30/* Timer register set definition */
  31#define PID12   (0x0)
  32#define EMUMGT  (0x4)
  33#define TIM12   (0x10)
  34#define TIM34   (0x14)
  35#define PRD12   (0x18)
  36#define PRD34   (0x1C)
  37#define TCR     (0x20)
  38#define TGCR    (0x24)
  39#define WDTCR   (0x28)
  40
  41/* TCR bit definitions */
  42#define ENAMODE12_DISABLED      (0 << 6)
  43#define ENAMODE12_ONESHOT       (1 << 6)
  44#define ENAMODE12_PERIODIC      (2 << 6)
  45
  46/* TGCR bit definitions */
  47#define TIM12RS_UNRESET         (1 << 0)
  48#define TIM34RS_UNRESET         (1 << 1)
  49#define TIMMODE_64BIT_WDOG      (2 << 2)
  50
  51/* WDTCR bit definitions */
  52#define WDEN                    (1 << 14)
  53#define WDFLAG                  (1 << 15)
  54#define WDKEY_SEQ0              (0xa5c6 << 16)
  55#define WDKEY_SEQ1              (0xda7e << 16)
  56
  57static int heartbeat;
  58
  59/*
  60 * struct to hold data for each WDT device
  61 * @base - base io address of WD device
  62 * @clk - source clock of WDT
  63 * @wdd - hold watchdog device as is in WDT core
  64 */
  65struct davinci_wdt_device {
  66        void __iomem            *base;
  67        struct clk              *clk;
  68        struct watchdog_device  wdd;
  69};
  70
  71static int davinci_wdt_start(struct watchdog_device *wdd)
  72{
  73        u32 tgcr;
  74        u32 timer_margin;
  75        unsigned long wdt_freq;
  76        struct davinci_wdt_device *davinci_wdt = watchdog_get_drvdata(wdd);
  77
  78        wdt_freq = clk_get_rate(davinci_wdt->clk);
  79
  80        /* disable, internal clock source */
  81        iowrite32(0, davinci_wdt->base + TCR);
  82        /* reset timer, set mode to 64-bit watchdog, and unreset */
  83        iowrite32(0, davinci_wdt->base + TGCR);
  84        tgcr = TIMMODE_64BIT_WDOG | TIM12RS_UNRESET | TIM34RS_UNRESET;
  85        iowrite32(tgcr, davinci_wdt->base + TGCR);
  86        /* clear counter regs */
  87        iowrite32(0, davinci_wdt->base + TIM12);
  88        iowrite32(0, davinci_wdt->base + TIM34);
  89        /* set timeout period */
  90        timer_margin = (((u64)wdd->timeout * wdt_freq) & 0xffffffff);
  91        iowrite32(timer_margin, davinci_wdt->base + PRD12);
  92        timer_margin = (((u64)wdd->timeout * wdt_freq) >> 32);
  93        iowrite32(timer_margin, davinci_wdt->base + PRD34);
  94        /* enable run continuously */
  95        iowrite32(ENAMODE12_PERIODIC, davinci_wdt->base + TCR);
  96        /* Once the WDT is in pre-active state write to
  97         * TIM12, TIM34, PRD12, PRD34, TCR, TGCR, WDTCR are
  98         * write protected (except for the WDKEY field)
  99         */
 100        /* put watchdog in pre-active state */
 101        iowrite32(WDKEY_SEQ0 | WDEN, davinci_wdt->base + WDTCR);
 102        /* put watchdog in active state */
 103        iowrite32(WDKEY_SEQ1 | WDEN, davinci_wdt->base + WDTCR);
 104        return 0;
 105}
 106
 107static int davinci_wdt_ping(struct watchdog_device *wdd)
 108{
 109        struct davinci_wdt_device *davinci_wdt = watchdog_get_drvdata(wdd);
 110
 111        /* put watchdog in service state */
 112        iowrite32(WDKEY_SEQ0, davinci_wdt->base + WDTCR);
 113        /* put watchdog in active state */
 114        iowrite32(WDKEY_SEQ1, davinci_wdt->base + WDTCR);
 115        return 0;
 116}
 117
 118static unsigned int davinci_wdt_get_timeleft(struct watchdog_device *wdd)
 119{
 120        u64 timer_counter;
 121        unsigned long freq;
 122        u32 val;
 123        struct davinci_wdt_device *davinci_wdt = watchdog_get_drvdata(wdd);
 124
 125        /* if timeout has occured then return 0 */
 126        val = ioread32(davinci_wdt->base + WDTCR);
 127        if (val & WDFLAG)
 128                return 0;
 129
 130        freq = clk_get_rate(davinci_wdt->clk);
 131
 132        if (!freq)
 133                return 0;
 134
 135        timer_counter = ioread32(davinci_wdt->base + TIM12);
 136        timer_counter |= ((u64)ioread32(davinci_wdt->base + TIM34) << 32);
 137
 138        do_div(timer_counter, freq);
 139
 140        return wdd->timeout - timer_counter;
 141}
 142
 143static const struct watchdog_info davinci_wdt_info = {
 144        .options = WDIOF_KEEPALIVEPING,
 145        .identity = "DaVinci/Keystone Watchdog",
 146};
 147
 148static const struct watchdog_ops davinci_wdt_ops = {
 149        .owner          = THIS_MODULE,
 150        .start          = davinci_wdt_start,
 151        .stop           = davinci_wdt_ping,
 152        .ping           = davinci_wdt_ping,
 153        .get_timeleft   = davinci_wdt_get_timeleft,
 154};
 155
 156static int davinci_wdt_probe(struct platform_device *pdev)
 157{
 158        int ret = 0;
 159        struct device *dev = &pdev->dev;
 160        struct resource  *wdt_mem;
 161        struct watchdog_device *wdd;
 162        struct davinci_wdt_device *davinci_wdt;
 163
 164        davinci_wdt = devm_kzalloc(dev, sizeof(*davinci_wdt), GFP_KERNEL);
 165        if (!davinci_wdt)
 166                return -ENOMEM;
 167
 168        davinci_wdt->clk = devm_clk_get(dev, NULL);
 169        if (WARN_ON(IS_ERR(davinci_wdt->clk)))
 170                return PTR_ERR(davinci_wdt->clk);
 171
 172        clk_prepare_enable(davinci_wdt->clk);
 173
 174        platform_set_drvdata(pdev, davinci_wdt);
 175
 176        wdd                     = &davinci_wdt->wdd;
 177        wdd->info               = &davinci_wdt_info;
 178        wdd->ops                = &davinci_wdt_ops;
 179        wdd->min_timeout        = 1;
 180        wdd->max_timeout        = MAX_HEARTBEAT;
 181        wdd->timeout            = DEFAULT_HEARTBEAT;
 182
 183        watchdog_init_timeout(wdd, heartbeat, dev);
 184
 185        dev_info(dev, "heartbeat %d sec\n", wdd->timeout);
 186
 187        watchdog_set_drvdata(wdd, davinci_wdt);
 188        watchdog_set_nowayout(wdd, 1);
 189
 190        wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 191        davinci_wdt->base = devm_ioremap_resource(dev, wdt_mem);
 192        if (IS_ERR(davinci_wdt->base))
 193                return PTR_ERR(davinci_wdt->base);
 194
 195        ret = watchdog_register_device(wdd);
 196        if (ret < 0)
 197                dev_err(dev, "cannot register watchdog device\n");
 198
 199        return ret;
 200}
 201
 202static int davinci_wdt_remove(struct platform_device *pdev)
 203{
 204        struct davinci_wdt_device *davinci_wdt = platform_get_drvdata(pdev);
 205
 206        watchdog_unregister_device(&davinci_wdt->wdd);
 207        clk_disable_unprepare(davinci_wdt->clk);
 208
 209        return 0;
 210}
 211
 212static const struct of_device_id davinci_wdt_of_match[] = {
 213        { .compatible = "ti,davinci-wdt", },
 214        {},
 215};
 216MODULE_DEVICE_TABLE(of, davinci_wdt_of_match);
 217
 218static struct platform_driver platform_wdt_driver = {
 219        .driver = {
 220                .name = "davinci-wdt",
 221                .owner  = THIS_MODULE,
 222                .of_match_table = davinci_wdt_of_match,
 223        },
 224        .probe = davinci_wdt_probe,
 225        .remove = davinci_wdt_remove,
 226};
 227
 228module_platform_driver(platform_wdt_driver);
 229
 230MODULE_AUTHOR("Texas Instruments");
 231MODULE_DESCRIPTION("DaVinci Watchdog Driver");
 232
 233module_param(heartbeat, int, 0);
 234MODULE_PARM_DESC(heartbeat,
 235                 "Watchdog heartbeat period in seconds from 1 to "
 236                 __MODULE_STRING(MAX_HEARTBEAT) ", default "
 237                 __MODULE_STRING(DEFAULT_HEARTBEAT));
 238
 239MODULE_LICENSE("GPL");
 240MODULE_ALIAS("platform:davinci-wdt");
 241