382 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Spreadtrum watchdog driver4 * Copyright (C) 2017 Spreadtrum - http://www.spreadtrum.com5 */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 0x022#define SPRD_WDT_LOAD_HIGH 0x423#define SPRD_WDT_CTRL 0x824#define SPRD_WDT_INT_CLR 0xc25#define SPRD_WDT_INT_RAW 0x1026#define SPRD_WDT_INT_MSK 0x1427#define SPRD_WDT_CNT_LOW 0x1828#define SPRD_WDT_CNT_HIGH 0x1c29#define SPRD_WDT_LOCK 0x2030#define SPRD_WDT_IRQ_LOAD_LOW 0x2c31#define SPRD_WDT_IRQ_LOAD_HIGH 0x3032 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 3276850 51#define SPRD_WDT_UNLOCK_KEY 0xe55152#define SPRD_WDT_MIN_TIMEOUT 353#define SPRD_WDT_MAX_TIMEOUT 6054 55#define SPRD_WDT_CNT_HIGH_SHIFT 1656#define SPRD_WDT_LOW_VALUE_MASK GENMASK(15, 0)57#define SPRD_WDT_LOAD_TIMEOUT 1158 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 is114 * done. According to the specification, the busy bit would be set115 * after a new loading operation and last 2 or 3 RTC clock116 * 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