|
@@ -53,7 +53,15 @@ static unsigned timer_margin;
|
|
module_param(timer_margin, uint, 0);
|
|
module_param(timer_margin, uint, 0);
|
|
MODULE_PARM_DESC(timer_margin, "initial watchdog timeout (in seconds)");
|
|
MODULE_PARM_DESC(timer_margin, "initial watchdog timeout (in seconds)");
|
|
|
|
|
|
|
|
+#define to_omap_wdt_dev(_wdog) container_of(_wdog, struct omap_wdt_dev, wdog)
|
|
|
|
+
|
|
|
|
+static bool early_enable;
|
|
|
|
+module_param(early_enable, bool, 0);
|
|
|
|
+MODULE_PARM_DESC(early_enable,
|
|
|
|
+ "Watchdog is started on module insertion (default=0)");
|
|
|
|
+
|
|
struct omap_wdt_dev {
|
|
struct omap_wdt_dev {
|
|
|
|
+ struct watchdog_device wdog;
|
|
void __iomem *base; /* physical */
|
|
void __iomem *base; /* physical */
|
|
struct device *dev;
|
|
struct device *dev;
|
|
bool omap_wdt_users;
|
|
bool omap_wdt_users;
|
|
@@ -123,7 +131,7 @@ static void omap_wdt_set_timer(struct omap_wdt_dev *wdev,
|
|
|
|
|
|
static int omap_wdt_start(struct watchdog_device *wdog)
|
|
static int omap_wdt_start(struct watchdog_device *wdog)
|
|
{
|
|
{
|
|
- struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
|
|
|
|
|
|
+ struct omap_wdt_dev *wdev = to_omap_wdt_dev(wdog);
|
|
void __iomem *base = wdev->base;
|
|
void __iomem *base = wdev->base;
|
|
|
|
|
|
mutex_lock(&wdev->lock);
|
|
mutex_lock(&wdev->lock);
|
|
@@ -132,6 +140,13 @@ static int omap_wdt_start(struct watchdog_device *wdog)
|
|
|
|
|
|
pm_runtime_get_sync(wdev->dev);
|
|
pm_runtime_get_sync(wdev->dev);
|
|
|
|
|
|
|
|
+ /*
|
|
|
|
+ * Make sure the watchdog is disabled. This is unfortunately required
|
|
|
|
+ * because writing to various registers with the watchdog running has no
|
|
|
|
+ * effect.
|
|
|
|
+ */
|
|
|
|
+ omap_wdt_disable(wdev);
|
|
|
|
+
|
|
/* initialize prescaler */
|
|
/* initialize prescaler */
|
|
while (readl_relaxed(base + OMAP_WATCHDOG_WPS) & 0x01)
|
|
while (readl_relaxed(base + OMAP_WATCHDOG_WPS) & 0x01)
|
|
cpu_relax();
|
|
cpu_relax();
|
|
@@ -151,7 +166,7 @@ static int omap_wdt_start(struct watchdog_device *wdog)
|
|
|
|
|
|
static int omap_wdt_stop(struct watchdog_device *wdog)
|
|
static int omap_wdt_stop(struct watchdog_device *wdog)
|
|
{
|
|
{
|
|
- struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
|
|
|
|
|
|
+ struct omap_wdt_dev *wdev = to_omap_wdt_dev(wdog);
|
|
|
|
|
|
mutex_lock(&wdev->lock);
|
|
mutex_lock(&wdev->lock);
|
|
omap_wdt_disable(wdev);
|
|
omap_wdt_disable(wdev);
|
|
@@ -163,7 +178,7 @@ static int omap_wdt_stop(struct watchdog_device *wdog)
|
|
|
|
|
|
static int omap_wdt_ping(struct watchdog_device *wdog)
|
|
static int omap_wdt_ping(struct watchdog_device *wdog)
|
|
{
|
|
{
|
|
- struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
|
|
|
|
|
|
+ struct omap_wdt_dev *wdev = to_omap_wdt_dev(wdog);
|
|
|
|
|
|
mutex_lock(&wdev->lock);
|
|
mutex_lock(&wdev->lock);
|
|
omap_wdt_reload(wdev);
|
|
omap_wdt_reload(wdev);
|
|
@@ -175,7 +190,7 @@ static int omap_wdt_ping(struct watchdog_device *wdog)
|
|
static int omap_wdt_set_timeout(struct watchdog_device *wdog,
|
|
static int omap_wdt_set_timeout(struct watchdog_device *wdog,
|
|
unsigned int timeout)
|
|
unsigned int timeout)
|
|
{
|
|
{
|
|
- struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
|
|
|
|
|
|
+ struct omap_wdt_dev *wdev = to_omap_wdt_dev(wdog);
|
|
|
|
|
|
mutex_lock(&wdev->lock);
|
|
mutex_lock(&wdev->lock);
|
|
omap_wdt_disable(wdev);
|
|
omap_wdt_disable(wdev);
|
|
@@ -188,6 +203,16 @@ static int omap_wdt_set_timeout(struct watchdog_device *wdog,
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static unsigned int omap_wdt_get_timeleft(struct watchdog_device *wdog)
|
|
|
|
+{
|
|
|
|
+ struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
|
|
|
|
+ void __iomem *base = wdev->base;
|
|
|
|
+ u32 value;
|
|
|
|
+
|
|
|
|
+ value = readl_relaxed(base + OMAP_WATCHDOG_CRR);
|
|
|
|
+ return GET_WCCR_SECS(value);
|
|
|
|
+}
|
|
|
|
+
|
|
static const struct watchdog_info omap_wdt_info = {
|
|
static const struct watchdog_info omap_wdt_info = {
|
|
.options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
|
|
.options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
|
|
.identity = "OMAP Watchdog",
|
|
.identity = "OMAP Watchdog",
|
|
@@ -199,21 +224,16 @@ static const struct watchdog_ops omap_wdt_ops = {
|
|
.stop = omap_wdt_stop,
|
|
.stop = omap_wdt_stop,
|
|
.ping = omap_wdt_ping,
|
|
.ping = omap_wdt_ping,
|
|
.set_timeout = omap_wdt_set_timeout,
|
|
.set_timeout = omap_wdt_set_timeout,
|
|
|
|
+ .get_timeleft = omap_wdt_get_timeleft,
|
|
};
|
|
};
|
|
|
|
|
|
static int omap_wdt_probe(struct platform_device *pdev)
|
|
static int omap_wdt_probe(struct platform_device *pdev)
|
|
{
|
|
{
|
|
struct omap_wd_timer_platform_data *pdata = dev_get_platdata(&pdev->dev);
|
|
struct omap_wd_timer_platform_data *pdata = dev_get_platdata(&pdev->dev);
|
|
- struct watchdog_device *omap_wdt;
|
|
|
|
struct resource *res;
|
|
struct resource *res;
|
|
struct omap_wdt_dev *wdev;
|
|
struct omap_wdt_dev *wdev;
|
|
- u32 rs;
|
|
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
- omap_wdt = devm_kzalloc(&pdev->dev, sizeof(*omap_wdt), GFP_KERNEL);
|
|
|
|
- if (!omap_wdt)
|
|
|
|
- return -ENOMEM;
|
|
|
|
-
|
|
|
|
wdev = devm_kzalloc(&pdev->dev, sizeof(*wdev), GFP_KERNEL);
|
|
wdev = devm_kzalloc(&pdev->dev, sizeof(*wdev), GFP_KERNEL);
|
|
if (!wdev)
|
|
if (!wdev)
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
@@ -229,35 +249,30 @@ static int omap_wdt_probe(struct platform_device *pdev)
|
|
if (IS_ERR(wdev->base))
|
|
if (IS_ERR(wdev->base))
|
|
return PTR_ERR(wdev->base);
|
|
return PTR_ERR(wdev->base);
|
|
|
|
|
|
- omap_wdt->info = &omap_wdt_info;
|
|
|
|
- omap_wdt->ops = &omap_wdt_ops;
|
|
|
|
- omap_wdt->min_timeout = TIMER_MARGIN_MIN;
|
|
|
|
- omap_wdt->max_timeout = TIMER_MARGIN_MAX;
|
|
|
|
|
|
+ wdev->wdog.info = &omap_wdt_info;
|
|
|
|
+ wdev->wdog.ops = &omap_wdt_ops;
|
|
|
|
+ wdev->wdog.min_timeout = TIMER_MARGIN_MIN;
|
|
|
|
+ wdev->wdog.max_timeout = TIMER_MARGIN_MAX;
|
|
|
|
|
|
- if (timer_margin >= TIMER_MARGIN_MIN &&
|
|
|
|
- timer_margin <= TIMER_MARGIN_MAX)
|
|
|
|
- omap_wdt->timeout = timer_margin;
|
|
|
|
- else
|
|
|
|
- omap_wdt->timeout = TIMER_MARGIN_DEFAULT;
|
|
|
|
|
|
+ if (watchdog_init_timeout(&wdev->wdog, timer_margin, &pdev->dev) < 0)
|
|
|
|
+ wdev->wdog.timeout = TIMER_MARGIN_DEFAULT;
|
|
|
|
|
|
- watchdog_set_drvdata(omap_wdt, wdev);
|
|
|
|
- watchdog_set_nowayout(omap_wdt, nowayout);
|
|
|
|
|
|
+ watchdog_set_nowayout(&wdev->wdog, nowayout);
|
|
|
|
|
|
- platform_set_drvdata(pdev, omap_wdt);
|
|
|
|
|
|
+ platform_set_drvdata(pdev, wdev);
|
|
|
|
|
|
pm_runtime_enable(wdev->dev);
|
|
pm_runtime_enable(wdev->dev);
|
|
pm_runtime_get_sync(wdev->dev);
|
|
pm_runtime_get_sync(wdev->dev);
|
|
|
|
|
|
- if (pdata && pdata->read_reset_sources)
|
|
|
|
- rs = pdata->read_reset_sources();
|
|
|
|
- else
|
|
|
|
- rs = 0;
|
|
|
|
- omap_wdt->bootstatus = (rs & (1 << OMAP_MPU_WD_RST_SRC_ID_SHIFT)) ?
|
|
|
|
- WDIOF_CARDRESET : 0;
|
|
|
|
|
|
+ if (pdata && pdata->read_reset_sources) {
|
|
|
|
+ u32 rs = pdata->read_reset_sources();
|
|
|
|
+ if (rs & (1 << OMAP_MPU_WD_RST_SRC_ID_SHIFT))
|
|
|
|
+ wdev->wdog.bootstatus = WDIOF_CARDRESET;
|
|
|
|
+ }
|
|
|
|
|
|
omap_wdt_disable(wdev);
|
|
omap_wdt_disable(wdev);
|
|
|
|
|
|
- ret = watchdog_register_device(omap_wdt);
|
|
|
|
|
|
+ ret = watchdog_register_device(&wdev->wdog);
|
|
if (ret) {
|
|
if (ret) {
|
|
pm_runtime_disable(wdev->dev);
|
|
pm_runtime_disable(wdev->dev);
|
|
return ret;
|
|
return ret;
|
|
@@ -265,17 +280,19 @@ static int omap_wdt_probe(struct platform_device *pdev)
|
|
|
|
|
|
pr_info("OMAP Watchdog Timer Rev 0x%02x: initial timeout %d sec\n",
|
|
pr_info("OMAP Watchdog Timer Rev 0x%02x: initial timeout %d sec\n",
|
|
readl_relaxed(wdev->base + OMAP_WATCHDOG_REV) & 0xFF,
|
|
readl_relaxed(wdev->base + OMAP_WATCHDOG_REV) & 0xFF,
|
|
- omap_wdt->timeout);
|
|
|
|
|
|
+ wdev->wdog.timeout);
|
|
|
|
|
|
pm_runtime_put_sync(wdev->dev);
|
|
pm_runtime_put_sync(wdev->dev);
|
|
|
|
|
|
|
|
+ if (early_enable)
|
|
|
|
+ omap_wdt_start(&wdev->wdog);
|
|
|
|
+
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
static void omap_wdt_shutdown(struct platform_device *pdev)
|
|
static void omap_wdt_shutdown(struct platform_device *pdev)
|
|
{
|
|
{
|
|
- struct watchdog_device *wdog = platform_get_drvdata(pdev);
|
|
|
|
- struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
|
|
|
|
|
|
+ struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
|
|
|
|
|
|
mutex_lock(&wdev->lock);
|
|
mutex_lock(&wdev->lock);
|
|
if (wdev->omap_wdt_users) {
|
|
if (wdev->omap_wdt_users) {
|
|
@@ -287,11 +304,10 @@ static void omap_wdt_shutdown(struct platform_device *pdev)
|
|
|
|
|
|
static int omap_wdt_remove(struct platform_device *pdev)
|
|
static int omap_wdt_remove(struct platform_device *pdev)
|
|
{
|
|
{
|
|
- struct watchdog_device *wdog = platform_get_drvdata(pdev);
|
|
|
|
- struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
|
|
|
|
|
|
+ struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
|
|
|
|
|
|
pm_runtime_disable(wdev->dev);
|
|
pm_runtime_disable(wdev->dev);
|
|
- watchdog_unregister_device(wdog);
|
|
|
|
|
|
+ watchdog_unregister_device(&wdev->wdog);
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
@@ -306,8 +322,7 @@ static int omap_wdt_remove(struct platform_device *pdev)
|
|
|
|
|
|
static int omap_wdt_suspend(struct platform_device *pdev, pm_message_t state)
|
|
static int omap_wdt_suspend(struct platform_device *pdev, pm_message_t state)
|
|
{
|
|
{
|
|
- struct watchdog_device *wdog = platform_get_drvdata(pdev);
|
|
|
|
- struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
|
|
|
|
|
|
+ struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
|
|
|
|
|
|
mutex_lock(&wdev->lock);
|
|
mutex_lock(&wdev->lock);
|
|
if (wdev->omap_wdt_users) {
|
|
if (wdev->omap_wdt_users) {
|
|
@@ -321,8 +336,7 @@ static int omap_wdt_suspend(struct platform_device *pdev, pm_message_t state)
|
|
|
|
|
|
static int omap_wdt_resume(struct platform_device *pdev)
|
|
static int omap_wdt_resume(struct platform_device *pdev)
|
|
{
|
|
{
|
|
- struct watchdog_device *wdog = platform_get_drvdata(pdev);
|
|
|
|
- struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
|
|
|
|
|
|
+ struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
|
|
|
|
|
|
mutex_lock(&wdev->lock);
|
|
mutex_lock(&wdev->lock);
|
|
if (wdev->omap_wdt_users) {
|
|
if (wdev->omap_wdt_users) {
|