brintos

brintos / linux-shallow public Read only

0
0
Text · 6.2 KiB · d96ad8f Raw
259 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Watchdog driver for the wm831x PMICs4 *5 * Copyright (C) 2009 Wolfson Microelectronics6 */7 8#include <linux/module.h>9#include <linux/moduleparam.h>10#include <linux/types.h>11#include <linux/kernel.h>12#include <linux/slab.h>13#include <linux/platform_device.h>14#include <linux/watchdog.h>15#include <linux/uaccess.h>16 17#include <linux/mfd/wm831x/core.h>18#include <linux/mfd/wm831x/pdata.h>19#include <linux/mfd/wm831x/watchdog.h>20 21static bool nowayout = WATCHDOG_NOWAYOUT;22module_param(nowayout, bool, 0);23MODULE_PARM_DESC(nowayout,24		 "Watchdog cannot be stopped once started (default="25		 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");26 27struct wm831x_wdt_drvdata {28	struct watchdog_device wdt;29	struct wm831x *wm831x;30	struct mutex lock;31	int update_state;32};33 34/* We can't use the sub-second values here but they're included35 * for completeness.  */36static struct {37	unsigned int time;  /* Seconds */38	u16 val;            /* WDOG_TO value */39} wm831x_wdt_cfgs[] = {40	{  1, 2 },41	{  2, 3 },42	{  4, 4 },43	{  8, 5 },44	{ 16, 6 },45	{ 32, 7 },46	{ 33, 7 },  /* Actually 32.768s so include both, others round down */47};48 49static int wm831x_wdt_start(struct watchdog_device *wdt_dev)50{51	struct wm831x_wdt_drvdata *driver_data = watchdog_get_drvdata(wdt_dev);52	struct wm831x *wm831x = driver_data->wm831x;53	int ret;54 55	mutex_lock(&driver_data->lock);56 57	ret = wm831x_reg_unlock(wm831x);58	if (ret == 0) {59		ret = wm831x_set_bits(wm831x, WM831X_WATCHDOG,60				      WM831X_WDOG_ENA, WM831X_WDOG_ENA);61		wm831x_reg_lock(wm831x);62	} else {63		dev_err(wm831x->dev, "Failed to unlock security key: %d\n",64			ret);65	}66 67	mutex_unlock(&driver_data->lock);68 69	return ret;70}71 72static int wm831x_wdt_stop(struct watchdog_device *wdt_dev)73{74	struct wm831x_wdt_drvdata *driver_data = watchdog_get_drvdata(wdt_dev);75	struct wm831x *wm831x = driver_data->wm831x;76	int ret;77 78	mutex_lock(&driver_data->lock);79 80	ret = wm831x_reg_unlock(wm831x);81	if (ret == 0) {82		ret = wm831x_set_bits(wm831x, WM831X_WATCHDOG,83				      WM831X_WDOG_ENA, 0);84		wm831x_reg_lock(wm831x);85	} else {86		dev_err(wm831x->dev, "Failed to unlock security key: %d\n",87			ret);88	}89 90	mutex_unlock(&driver_data->lock);91 92	return ret;93}94 95static int wm831x_wdt_ping(struct watchdog_device *wdt_dev)96{97	struct wm831x_wdt_drvdata *driver_data = watchdog_get_drvdata(wdt_dev);98	struct wm831x *wm831x = driver_data->wm831x;99	int ret;100	u16 reg;101 102	mutex_lock(&driver_data->lock);103 104	reg = wm831x_reg_read(wm831x, WM831X_WATCHDOG);105 106	if (!(reg & WM831X_WDOG_RST_SRC)) {107		dev_err(wm831x->dev, "Hardware watchdog update unsupported\n");108		ret = -EINVAL;109		goto out;110	}111 112	reg |= WM831X_WDOG_RESET;113 114	ret = wm831x_reg_unlock(wm831x);115	if (ret == 0) {116		ret = wm831x_reg_write(wm831x, WM831X_WATCHDOG, reg);117		wm831x_reg_lock(wm831x);118	} else {119		dev_err(wm831x->dev, "Failed to unlock security key: %d\n",120			ret);121	}122 123out:124	mutex_unlock(&driver_data->lock);125 126	return ret;127}128 129static int wm831x_wdt_set_timeout(struct watchdog_device *wdt_dev,130				  unsigned int timeout)131{132	struct wm831x_wdt_drvdata *driver_data = watchdog_get_drvdata(wdt_dev);133	struct wm831x *wm831x = driver_data->wm831x;134	int ret, i;135 136	for (i = 0; i < ARRAY_SIZE(wm831x_wdt_cfgs); i++)137		if (wm831x_wdt_cfgs[i].time == timeout)138			break;139	if (i == ARRAY_SIZE(wm831x_wdt_cfgs))140		return -EINVAL;141 142	ret = wm831x_reg_unlock(wm831x);143	if (ret == 0) {144		ret = wm831x_set_bits(wm831x, WM831X_WATCHDOG,145				      WM831X_WDOG_TO_MASK,146				      wm831x_wdt_cfgs[i].val);147		wm831x_reg_lock(wm831x);148	} else {149		dev_err(wm831x->dev, "Failed to unlock security key: %d\n",150			ret);151	}152 153	wdt_dev->timeout = timeout;154 155	return ret;156}157 158static const struct watchdog_info wm831x_wdt_info = {159	.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,160	.identity = "WM831x Watchdog",161};162 163static const struct watchdog_ops wm831x_wdt_ops = {164	.owner = THIS_MODULE,165	.start = wm831x_wdt_start,166	.stop = wm831x_wdt_stop,167	.ping = wm831x_wdt_ping,168	.set_timeout = wm831x_wdt_set_timeout,169};170 171static int wm831x_wdt_probe(struct platform_device *pdev)172{173	struct device *dev = &pdev->dev;174	struct wm831x *wm831x = dev_get_drvdata(dev->parent);175	struct wm831x_pdata *chip_pdata = dev_get_platdata(dev->parent);176	struct wm831x_watchdog_pdata *pdata;177	struct wm831x_wdt_drvdata *driver_data;178	struct watchdog_device *wm831x_wdt;179	int reg, ret, i;180 181	ret = wm831x_reg_read(wm831x, WM831X_WATCHDOG);182	if (ret < 0) {183		dev_err(wm831x->dev, "Failed to read watchdog status: %d\n",184			ret);185		return ret;186	}187	reg = ret;188 189	if (reg & WM831X_WDOG_DEBUG)190		dev_warn(wm831x->dev, "Watchdog is paused\n");191 192	driver_data = devm_kzalloc(dev, sizeof(*driver_data), GFP_KERNEL);193	if (!driver_data)194		return -ENOMEM;195 196	mutex_init(&driver_data->lock);197	driver_data->wm831x = wm831x;198 199	wm831x_wdt = &driver_data->wdt;200 201	wm831x_wdt->info = &wm831x_wdt_info;202	wm831x_wdt->ops = &wm831x_wdt_ops;203	wm831x_wdt->parent = dev;204	watchdog_set_nowayout(wm831x_wdt, nowayout);205	watchdog_set_drvdata(wm831x_wdt, driver_data);206 207	reg = wm831x_reg_read(wm831x, WM831X_WATCHDOG);208	reg &= WM831X_WDOG_TO_MASK;209	for (i = 0; i < ARRAY_SIZE(wm831x_wdt_cfgs); i++)210		if (wm831x_wdt_cfgs[i].val == reg)211			break;212	if (i == ARRAY_SIZE(wm831x_wdt_cfgs))213		dev_warn(wm831x->dev,214			 "Unknown watchdog timeout: %x\n", reg);215	else216		wm831x_wdt->timeout = wm831x_wdt_cfgs[i].time;217 218	/* Apply any configuration */219	if (chip_pdata)220		pdata = chip_pdata->watchdog;221	else222		pdata = NULL;223 224	if (pdata) {225		reg &= ~(WM831X_WDOG_SECACT_MASK | WM831X_WDOG_PRIMACT_MASK |226			 WM831X_WDOG_RST_SRC);227 228		reg |= pdata->primary << WM831X_WDOG_PRIMACT_SHIFT;229		reg |= pdata->secondary << WM831X_WDOG_SECACT_SHIFT;230		reg |= pdata->software << WM831X_WDOG_RST_SRC_SHIFT;231 232		ret = wm831x_reg_unlock(wm831x);233		if (ret == 0) {234			ret = wm831x_reg_write(wm831x, WM831X_WATCHDOG, reg);235			wm831x_reg_lock(wm831x);236		} else {237			dev_err(wm831x->dev,238				"Failed to unlock security key: %d\n", ret);239			return ret;240		}241	}242 243	return devm_watchdog_register_device(dev, &driver_data->wdt);244}245 246static struct platform_driver wm831x_wdt_driver = {247	.probe = wm831x_wdt_probe,248	.driver = {249		.name = "wm831x-watchdog",250	},251};252 253module_platform_driver(wm831x_wdt_driver);254 255MODULE_AUTHOR("Mark Brown");256MODULE_DESCRIPTION("WM831x Watchdog");257MODULE_LICENSE("GPL");258MODULE_ALIAS("platform:wm831x-watchdog");259