linux/drivers/watchdog/sprd_wdt.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Spreadtrum watchdog driver
   4 * Copyright (C) 2017 Spreadtrum - http://www.spreadtrum.com
   5 */
   6
   7#include <linux/bitops.h>
   8#include <linux/clk.h>
   9#include <linux/delay.h>
  10#include <linux/device.h>
  11#include <linux/err.h>
  12#include <linux/interrupt.h>
  13#include <linux/io.h>
  14#include <linux/kernel.h>
  15#include <linux/module.h>
  16#include <linux/of.h>
  17#include <linux/of_address.h>
  18#include <linux/platform_device.h>
  19#include <linux/watchdog.h>
  20
  21#define SPRD_WDT_LOAD_LOW               0x0
  22#define SPRD_WDT_LOAD_HIGH              0x4
  23#define SPRD_WDT_CTRL                   0x8
  24#define SPRD_WDT_INT_CLR                0xc
  25#define SPRD_WDT_INT_RAW                0x10
  26#define SPRD_WDT_INT_MSK                0x14
  27#define SPRD_WDT_CNT_LOW                0x18
  28#define SPRD_WDT_CNT_HIGH               0x1c
  29#define SPRD_WDT_LOCK                   0x20
  30#define SPRD_WDT_IRQ_LOAD_LOW           0x2c
  31#define SPRD_WDT_IRQ_LOAD_HIGH          0x30
  32
  33/* WDT_CTRL */
  34#define SPRD_WDT_INT_EN_BIT             BIT(0)
  35#define SPRD_WDT_CNT_EN_BIT             BIT(1)
  36#define SPRD_WDT_NEW_VER_EN             BIT(2)
  37#define SPRD_WDT_RST_EN_BIT             BIT(3)
  38
  39/* WDT_INT_CLR */
  40#define SPRD_WDT_INT_CLEAR_BIT          BIT(0)
  41#define SPRD_WDT_RST_CLEAR_BIT          BIT(3)
  42
  43/* WDT_INT_RAW */
  44#define SPRD_WDT_INT_RAW_BIT            BIT(0)
  45#define SPRD_WDT_RST_RAW_BIT            BIT(3)
  46#define SPRD_WDT_LD_BUSY_BIT            BIT(4)
  47
  48/* 1s equal to 32768 counter steps */
  49#define SPRD_WDT_CNT_STEP               32768
  50
  51#define SPRD_WDT_UNLOCK_KEY             0xe551
  52#define SPRD_WDT_MIN_TIMEOUT            3
  53#define SPRD_WDT_MAX_TIMEOUT            60
  54
  55#define SPRD_WDT_CNT_HIGH_SHIFT         16
  56#define SPRD_WDT_LOW_VALUE_MASK         GENMASK(15, 0)
  57#define SPRD_WDT_LOAD_TIMEOUT           11
  58
  59struct sprd_wdt {
  60        void __iomem *base;
  61        struct watchdog_device wdd;
  62        struct clk *enable;
  63        struct clk *rtc_enable;
  64        int irq;
  65};
  66
  67static inline struct sprd_wdt *to_sprd_wdt(struct watchdog_device *wdd)
  68{
  69        return container_of(wdd, struct sprd_wdt, wdd);
  70}
  71
  72static inline void sprd_wdt_lock(void __iomem *addr)
  73{
  74        writel_relaxed(0x0, addr + SPRD_WDT_LOCK);
  75}
  76
  77static inline void sprd_wdt_unlock(void __iomem *addr)
  78{
  79        writel_relaxed(SPRD_WDT_UNLOCK_KEY, addr + SPRD_WDT_LOCK);
  80}
  81
  82static irqreturn_t sprd_wdt_isr(int irq, void *dev_id)
  83{
  84        struct sprd_wdt *wdt = (struct sprd_wdt *)dev_id;
  85
  86        sprd_wdt_unlock(wdt->base);
  87        writel_relaxed(SPRD_WDT_INT_CLEAR_BIT, wdt->base + SPRD_WDT_INT_CLR);
  88        sprd_wdt_lock(wdt->base);
  89        watchdog_notify_pretimeout(&wdt->wdd);
  90        return IRQ_HANDLED;
  91}
  92
  93static u32 sprd_wdt_get_cnt_value(struct sprd_wdt *wdt)
  94{
  95        u32 val;
  96
  97        val = readl_relaxed(wdt->base + SPRD_WDT_CNT_HIGH) <<
  98                SPRD_WDT_CNT_HIGH_SHIFT;
  99        val |= readl_relaxed(wdt->base + SPRD_WDT_CNT_LOW) &
 100                SPRD_WDT_LOW_VALUE_MASK;
 101
 102        return val;
 103}
 104
 105static int sprd_wdt_load_value(struct sprd_wdt *wdt, u32 timeout,
 106                               u32 pretimeout)
 107{
 108        u32 val, delay_cnt = 0;
 109        u32 tmr_step = timeout * SPRD_WDT_CNT_STEP;
 110        u32 prtmr_step = pretimeout * SPRD_WDT_CNT_STEP;
 111
 112        /*
 113         * Checking busy bit to make sure the previous loading operation is
 114         * done. According to the specification, the busy bit would be set
 115         * after a new loading operation and last 2 or 3 RTC clock
 116         * cycles (about 60us~92us).
 117         */
 118        do {
 119                val = readl_relaxed(wdt->base + SPRD_WDT_INT_RAW);
 120                if (!(val & SPRD_WDT_LD_BUSY_BIT))
 121                        break;
 122
 123                usleep_range(10, 100);
 124        } while (delay_cnt++ < SPRD_WDT_LOAD_TIMEOUT);
 125
 126        if (delay_cnt >= SPRD_WDT_LOAD_TIMEOUT)
 127                return -EBUSY;
 128
 129        sprd_wdt_unlock(wdt->base);
 130        writel_relaxed((tmr_step >> SPRD_WDT_CNT_HIGH_SHIFT) &
 131                      SPRD_WDT_LOW_VALUE_MASK, wdt->base + SPRD_WDT_LOAD_HIGH);
 132        writel_relaxed((tmr_step & SPRD_WDT_LOW_VALUE_MASK),
 133                       wdt->base + SPRD_WDT_LOAD_LOW);
 134        writel_relaxed((prtmr_step >> SPRD_WDT_CNT_HIGH_SHIFT) &
 135                        SPRD_WDT_LOW_VALUE_MASK,
 136                       wdt->base + SPRD_WDT_IRQ_LOAD_HIGH);
 137        writel_relaxed(prtmr_step & SPRD_WDT_LOW_VALUE_MASK,
 138                       wdt->base + SPRD_WDT_IRQ_LOAD_LOW);
 139        sprd_wdt_lock(wdt->base);
 140
 141        return 0;
 142}
 143
 144static int sprd_wdt_enable(struct sprd_wdt *wdt)
 145{
 146        u32 val;
 147        int ret;
 148
 149        ret = clk_prepare_enable(wdt->enable);
 150        if (ret)
 151                return ret;
 152        ret = clk_prepare_enable(wdt->rtc_enable);
 153        if (ret) {
 154                clk_disable_unprepare(wdt->enable);
 155                return ret;
 156        }
 157
 158        sprd_wdt_unlock(wdt->base);
 159        val = readl_relaxed(wdt->base + SPRD_WDT_CTRL);
 160        val |= SPRD_WDT_NEW_VER_EN;
 161        writel_relaxed(val, wdt->base + SPRD_WDT_CTRL);
 162        sprd_wdt_lock(wdt->base);
 163        return 0;
 164}
 165
 166static void sprd_wdt_disable(void *_data)
 167{
 168        struct sprd_wdt *wdt = _data;
 169
 170        sprd_wdt_unlock(wdt->base);
 171        writel_relaxed(0x0, wdt->base + SPRD_WDT_CTRL);
 172        sprd_wdt_lock(wdt->base);
 173
 174        clk_disable_unprepare(wdt->rtc_enable);
 175        clk_disable_unprepare(wdt->enable);
 176}
 177
 178static int sprd_wdt_start(struct watchdog_device *wdd)
 179{
 180        struct sprd_wdt *wdt = to_sprd_wdt(wdd);
 181        u32 val;
 182        int ret;
 183
 184        ret = sprd_wdt_load_value(wdt, wdd->timeout, wdd->pretimeout);
 185        if (ret)
 186                return ret;
 187
 188        sprd_wdt_unlock(wdt->base);
 189        val = readl_relaxed(wdt->base + SPRD_WDT_CTRL);
 190        val |= SPRD_WDT_CNT_EN_BIT | SPRD_WDT_INT_EN_BIT | SPRD_WDT_RST_EN_BIT;
 191        writel_relaxed(val, wdt->base + SPRD_WDT_CTRL);
 192        sprd_wdt_lock(wdt->base);
 193        set_bit(WDOG_HW_RUNNING, &wdd->status);
 194
 195        return 0;
 196}
 197
 198static int sprd_wdt_stop(struct watchdog_device *wdd)
 199{
 200        struct sprd_wdt *wdt = to_sprd_wdt(wdd);
 201        u32 val;
 202
 203        sprd_wdt_unlock(wdt->base);
 204        val = readl_relaxed(wdt->base + SPRD_WDT_CTRL);
 205        val &= ~(SPRD_WDT_CNT_EN_BIT | SPRD_WDT_RST_EN_BIT |
 206                SPRD_WDT_INT_EN_BIT);
 207        writel_relaxed(val, wdt->base + SPRD_WDT_CTRL);
 208        sprd_wdt_lock(wdt->base);
 209        return 0;
 210}
 211
 212static int sprd_wdt_set_timeout(struct watchdog_device *wdd,
 213                                u32 timeout)
 214{
 215        struct sprd_wdt *wdt = to_sprd_wdt(wdd);
 216
 217        if (timeout == wdd->timeout)
 218                return 0;
 219
 220        wdd->timeout = timeout;
 221
 222        return sprd_wdt_load_value(wdt, timeout, wdd->pretimeout);
 223}
 224
 225static int sprd_wdt_set_pretimeout(struct watchdog_device *wdd,
 226                                   u32 new_pretimeout)
 227{
 228        struct sprd_wdt *wdt = to_sprd_wdt(wdd);
 229
 230        if (new_pretimeout < wdd->min_timeout)
 231                return -EINVAL;
 232
 233        wdd->pretimeout = new_pretimeout;
 234
 235        return sprd_wdt_load_value(wdt, wdd->timeout, new_pretimeout);
 236}
 237
 238static u32 sprd_wdt_get_timeleft(struct watchdog_device *wdd)
 239{
 240        struct sprd_wdt *wdt = to_sprd_wdt(wdd);
 241        u32 val;
 242
 243        val = sprd_wdt_get_cnt_value(wdt);
 244        return val / SPRD_WDT_CNT_STEP;
 245}
 246
 247static const struct watchdog_ops sprd_wdt_ops = {
 248        .owner = THIS_MODULE,
 249        .start = sprd_wdt_start,
 250        .stop = sprd_wdt_stop,
 251        .set_timeout = sprd_wdt_set_timeout,
 252        .set_pretimeout = sprd_wdt_set_pretimeout,
 253        .get_timeleft = sprd_wdt_get_timeleft,
 254};
 255
 256static const struct watchdog_info sprd_wdt_info = {
 257        .options = WDIOF_SETTIMEOUT |
 258                   WDIOF_PRETIMEOUT |
 259                   WDIOF_MAGICCLOSE |
 260                   WDIOF_KEEPALIVEPING,
 261        .identity = "Spreadtrum Watchdog Timer",
 262};
 263
 264static int sprd_wdt_probe(struct platform_device *pdev)
 265{
 266        struct device *dev = &pdev->dev;
 267        struct sprd_wdt *wdt;
 268        int ret;
 269
 270        wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
 271        if (!wdt)
 272                return -ENOMEM;
 273
 274        wdt->base = devm_platform_ioremap_resource(pdev, 0);
 275        if (IS_ERR(wdt->base))
 276                return PTR_ERR(wdt->base);
 277
 278        wdt->enable = devm_clk_get(dev, "enable");
 279        if (IS_ERR(wdt->enable)) {
 280                dev_err(dev, "can't get the enable clock\n");
 281                return PTR_ERR(wdt->enable);
 282        }
 283
 284        wdt->rtc_enable = devm_clk_get(dev, "rtc_enable");
 285        if (IS_ERR(wdt->rtc_enable)) {
 286                dev_err(dev, "can't get the rtc enable clock\n");
 287                return PTR_ERR(wdt->rtc_enable);
 288        }
 289
 290        wdt->irq = platform_get_irq(pdev, 0);
 291        if (wdt->irq < 0)
 292                return wdt->irq;
 293
 294        ret = devm_request_irq(dev, wdt->irq, sprd_wdt_isr, IRQF_NO_SUSPEND,
 295                               "sprd-wdt", (void *)wdt);
 296        if (ret) {
 297                dev_err(dev, "failed to register irq\n");
 298                return ret;
 299        }
 300
 301        wdt->wdd.info = &sprd_wdt_info;
 302        wdt->wdd.ops = &sprd_wdt_ops;
 303        wdt->wdd.parent = dev;
 304        wdt->wdd.min_timeout = SPRD_WDT_MIN_TIMEOUT;
 305        wdt->wdd.max_timeout = SPRD_WDT_MAX_TIMEOUT;
 306        wdt->wdd.timeout = SPRD_WDT_MAX_TIMEOUT;
 307
 308        ret = sprd_wdt_enable(wdt);
 309        if (ret) {
 310                dev_err(dev, "failed to enable wdt\n");
 311                return ret;
 312        }
 313        ret = devm_add_action_or_reset(dev, sprd_wdt_disable, wdt);
 314        if (ret) {
 315                dev_err(dev, "Failed to add wdt disable action\n");
 316                return ret;
 317        }
 318
 319        watchdog_set_nowayout(&wdt->wdd, WATCHDOG_NOWAYOUT);
 320        watchdog_init_timeout(&wdt->wdd, 0, dev);
 321
 322        ret = devm_watchdog_register_device(dev, &wdt->wdd);
 323        if (ret) {
 324                sprd_wdt_disable(wdt);
 325                return ret;
 326        }
 327        platform_set_drvdata(pdev, wdt);
 328
 329        return 0;
 330}
 331
 332static int __maybe_unused sprd_wdt_pm_suspend(struct device *dev)
 333{
 334        struct sprd_wdt *wdt = dev_get_drvdata(dev);
 335
 336        if (watchdog_active(&wdt->wdd))
 337                sprd_wdt_stop(&wdt->wdd);
 338        sprd_wdt_disable(wdt);
 339
 340        return 0;
 341}
 342
 343static int __maybe_unused sprd_wdt_pm_resume(struct device *dev)
 344{
 345        struct sprd_wdt *wdt = dev_get_drvdata(dev);
 346        int ret;
 347
 348        ret = sprd_wdt_enable(wdt);
 349        if (ret)
 350                return ret;
 351
 352        if (watchdog_active(&wdt->wdd))
 353                ret = sprd_wdt_start(&wdt->wdd);
 354
 355        return ret;
 356}
 357
 358static const struct dev_pm_ops sprd_wdt_pm_ops = {
 359        SET_SYSTEM_SLEEP_PM_OPS(sprd_wdt_pm_suspend,
 360                                sprd_wdt_pm_resume)
 361};
 362
 363static const struct of_device_id sprd_wdt_match_table[] = {
 364        { .compatible = "sprd,sp9860-wdt", },
 365        {},
 366};
 367MODULE_DEVICE_TABLE(of, sprd_wdt_match_table);
 368
 369static struct platform_driver sprd_watchdog_driver = {
 370        .probe  = sprd_wdt_probe,
 371        .driver = {
 372                .name = "sprd-wdt",
 373                .of_match_table = sprd_wdt_match_table,
 374                .pm = &sprd_wdt_pm_ops,
 375        },
 376};
 377module_platform_driver(sprd_watchdog_driver);
 378
 379MODULE_AUTHOR("Eric Long <eric.long@spreadtrum.com>");
 380MODULE_DESCRIPTION("Spreadtrum Watchdog Timer Controller Driver");
 381MODULE_LICENSE("GPL v2");
 382