watchdog: xilinx: Allocate private structure per device
Only one watchdog could be used by this driver. Create driver private data structure and move there all variables for one instance. Signed-off-by: Michal Simek <michal.simek@xilinx.com> Reviewed-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Wim Van Sebroeck <wim@iguana.be>hifive-unleashed-5.1
parent
ffb8eee4f1
commit
9066317178
|
@ -46,30 +46,27 @@
|
||||||
struct xwdt_device {
|
struct xwdt_device {
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
u32 wdt_interval;
|
u32 wdt_interval;
|
||||||
|
spinlock_t spinlock;
|
||||||
|
struct watchdog_device xilinx_wdt_wdd;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct xwdt_device xdev;
|
|
||||||
|
|
||||||
static u32 timeout;
|
|
||||||
|
|
||||||
static DEFINE_SPINLOCK(spinlock);
|
|
||||||
|
|
||||||
static int xilinx_wdt_start(struct watchdog_device *wdd)
|
static int xilinx_wdt_start(struct watchdog_device *wdd)
|
||||||
{
|
{
|
||||||
u32 control_status_reg;
|
u32 control_status_reg;
|
||||||
|
struct xwdt_device *xdev = watchdog_get_drvdata(wdd);
|
||||||
|
|
||||||
spin_lock(&spinlock);
|
spin_lock(&xdev->spinlock);
|
||||||
|
|
||||||
/* Clean previous status and enable the watchdog timer */
|
/* Clean previous status and enable the watchdog timer */
|
||||||
control_status_reg = ioread32(xdev.base + XWT_TWCSR0_OFFSET);
|
control_status_reg = ioread32(xdev->base + XWT_TWCSR0_OFFSET);
|
||||||
control_status_reg |= (XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK);
|
control_status_reg |= (XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK);
|
||||||
|
|
||||||
iowrite32((control_status_reg | XWT_CSR0_EWDT1_MASK),
|
iowrite32((control_status_reg | XWT_CSR0_EWDT1_MASK),
|
||||||
xdev.base + XWT_TWCSR0_OFFSET);
|
xdev->base + XWT_TWCSR0_OFFSET);
|
||||||
|
|
||||||
iowrite32(XWT_CSRX_EWDT2_MASK, xdev.base + XWT_TWCSR1_OFFSET);
|
iowrite32(XWT_CSRX_EWDT2_MASK, xdev->base + XWT_TWCSR1_OFFSET);
|
||||||
|
|
||||||
spin_unlock(&spinlock);
|
spin_unlock(&xdev->spinlock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -77,17 +74,18 @@ static int xilinx_wdt_start(struct watchdog_device *wdd)
|
||||||
static int xilinx_wdt_stop(struct watchdog_device *wdd)
|
static int xilinx_wdt_stop(struct watchdog_device *wdd)
|
||||||
{
|
{
|
||||||
u32 control_status_reg;
|
u32 control_status_reg;
|
||||||
|
struct xwdt_device *xdev = watchdog_get_drvdata(wdd);
|
||||||
|
|
||||||
spin_lock(&spinlock);
|
spin_lock(&xdev->spinlock);
|
||||||
|
|
||||||
control_status_reg = ioread32(xdev.base + XWT_TWCSR0_OFFSET);
|
control_status_reg = ioread32(xdev->base + XWT_TWCSR0_OFFSET);
|
||||||
|
|
||||||
iowrite32((control_status_reg & ~XWT_CSR0_EWDT1_MASK),
|
iowrite32((control_status_reg & ~XWT_CSR0_EWDT1_MASK),
|
||||||
xdev.base + XWT_TWCSR0_OFFSET);
|
xdev->base + XWT_TWCSR0_OFFSET);
|
||||||
|
|
||||||
iowrite32(0, xdev.base + XWT_TWCSR1_OFFSET);
|
iowrite32(0, xdev->base + XWT_TWCSR1_OFFSET);
|
||||||
|
|
||||||
spin_unlock(&spinlock);
|
spin_unlock(&xdev->spinlock);
|
||||||
pr_info("Stopped!\n");
|
pr_info("Stopped!\n");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -96,14 +94,15 @@ static int xilinx_wdt_stop(struct watchdog_device *wdd)
|
||||||
static int xilinx_wdt_keepalive(struct watchdog_device *wdd)
|
static int xilinx_wdt_keepalive(struct watchdog_device *wdd)
|
||||||
{
|
{
|
||||||
u32 control_status_reg;
|
u32 control_status_reg;
|
||||||
|
struct xwdt_device *xdev = watchdog_get_drvdata(wdd);
|
||||||
|
|
||||||
spin_lock(&spinlock);
|
spin_lock(&xdev->spinlock);
|
||||||
|
|
||||||
control_status_reg = ioread32(xdev.base + XWT_TWCSR0_OFFSET);
|
control_status_reg = ioread32(xdev->base + XWT_TWCSR0_OFFSET);
|
||||||
control_status_reg |= (XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK);
|
control_status_reg |= (XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK);
|
||||||
iowrite32(control_status_reg, xdev.base + XWT_TWCSR0_OFFSET);
|
iowrite32(control_status_reg, xdev->base + XWT_TWCSR0_OFFSET);
|
||||||
|
|
||||||
spin_unlock(&spinlock);
|
spin_unlock(&xdev->spinlock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -122,29 +121,24 @@ static const struct watchdog_ops xilinx_wdt_ops = {
|
||||||
.ping = xilinx_wdt_keepalive,
|
.ping = xilinx_wdt_keepalive,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct watchdog_device xilinx_wdt_wdd = {
|
static u32 xwdt_selftest(struct xwdt_device *xdev)
|
||||||
.info = &xilinx_wdt_ident,
|
|
||||||
.ops = &xilinx_wdt_ops,
|
|
||||||
};
|
|
||||||
|
|
||||||
static u32 xwdt_selftest(void)
|
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
u32 timer_value1;
|
u32 timer_value1;
|
||||||
u32 timer_value2;
|
u32 timer_value2;
|
||||||
|
|
||||||
spin_lock(&spinlock);
|
spin_lock(&xdev->spinlock);
|
||||||
|
|
||||||
timer_value1 = ioread32(xdev.base + XWT_TBR_OFFSET);
|
timer_value1 = ioread32(xdev->base + XWT_TBR_OFFSET);
|
||||||
timer_value2 = ioread32(xdev.base + XWT_TBR_OFFSET);
|
timer_value2 = ioread32(xdev->base + XWT_TBR_OFFSET);
|
||||||
|
|
||||||
for (i = 0;
|
for (i = 0;
|
||||||
((i <= XWT_MAX_SELFTEST_LOOP_COUNT) &&
|
((i <= XWT_MAX_SELFTEST_LOOP_COUNT) &&
|
||||||
(timer_value2 == timer_value1)); i++) {
|
(timer_value2 == timer_value1)); i++) {
|
||||||
timer_value2 = ioread32(xdev.base + XWT_TBR_OFFSET);
|
timer_value2 = ioread32(xdev->base + XWT_TBR_OFFSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock(&spinlock);
|
spin_unlock(&xdev->spinlock);
|
||||||
|
|
||||||
if (timer_value2 != timer_value1)
|
if (timer_value2 != timer_value1)
|
||||||
return ~XWT_TIMER_FAILED;
|
return ~XWT_TIMER_FAILED;
|
||||||
|
@ -158,12 +152,23 @@ static int xwdt_probe(struct platform_device *pdev)
|
||||||
u32 *tmptr;
|
u32 *tmptr;
|
||||||
u32 *pfreq;
|
u32 *pfreq;
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
|
struct xwdt_device *xdev;
|
||||||
bool no_timeout = false;
|
bool no_timeout = false;
|
||||||
|
struct watchdog_device *xilinx_wdt_wdd;
|
||||||
|
|
||||||
|
xdev = devm_kzalloc(&pdev->dev, sizeof(*xdev), GFP_KERNEL);
|
||||||
|
if (!xdev)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
xilinx_wdt_wdd = &xdev->xilinx_wdt_wdd;
|
||||||
|
xilinx_wdt_wdd->info = &xilinx_wdt_ident;
|
||||||
|
xilinx_wdt_wdd->ops = &xilinx_wdt_ops;
|
||||||
|
xilinx_wdt_wdd->parent = &pdev->dev;
|
||||||
|
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
xdev.base = devm_ioremap_resource(&pdev->dev, res);
|
xdev->base = devm_ioremap_resource(&pdev->dev, res);
|
||||||
if (IS_ERR(xdev.base))
|
if (IS_ERR(xdev->base))
|
||||||
return PTR_ERR(xdev.base);
|
return PTR_ERR(xdev->base);
|
||||||
|
|
||||||
pfreq = (u32 *)of_get_property(pdev->dev.of_node,
|
pfreq = (u32 *)of_get_property(pdev->dev.of_node,
|
||||||
"clock-frequency", NULL);
|
"clock-frequency", NULL);
|
||||||
|
@ -179,14 +184,14 @@ static int xwdt_probe(struct platform_device *pdev)
|
||||||
pr_warn("Parameter \"xlnx,wdt-interval\" not found in device tree!\n");
|
pr_warn("Parameter \"xlnx,wdt-interval\" not found in device tree!\n");
|
||||||
no_timeout = true;
|
no_timeout = true;
|
||||||
} else {
|
} else {
|
||||||
xdev.wdt_interval = *tmptr;
|
xdev->wdt_interval = *tmptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
tmptr = (u32 *)of_get_property(pdev->dev.of_node,
|
tmptr = (u32 *)of_get_property(pdev->dev.of_node,
|
||||||
"xlnx,wdt-enable-once", NULL);
|
"xlnx,wdt-enable-once", NULL);
|
||||||
if (tmptr == NULL) {
|
if (tmptr == NULL) {
|
||||||
pr_warn("Parameter \"xlnx,wdt-enable-once\" not found in device tree!\n");
|
pr_warn("Parameter \"xlnx,wdt-enable-once\" not found in device tree!\n");
|
||||||
watchdog_set_nowayout(&xilinx_wdt_wdd, true);
|
watchdog_set_nowayout(xilinx_wdt_wdd, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -194,29 +199,37 @@ static int xwdt_probe(struct platform_device *pdev)
|
||||||
* ignored (interrupt), reset is only generated at second wdt overflow
|
* ignored (interrupt), reset is only generated at second wdt overflow
|
||||||
*/
|
*/
|
||||||
if (!no_timeout)
|
if (!no_timeout)
|
||||||
timeout = 2 * ((1<<xdev.wdt_interval) / *pfreq);
|
xilinx_wdt_wdd->timeout = 2 * ((1 << xdev->wdt_interval) /
|
||||||
|
*pfreq);
|
||||||
|
|
||||||
rc = xwdt_selftest();
|
spin_lock_init(&xdev->spinlock);
|
||||||
|
watchdog_set_drvdata(xilinx_wdt_wdd, xdev);
|
||||||
|
|
||||||
|
rc = xwdt_selftest(xdev);
|
||||||
if (rc == XWT_TIMER_FAILED) {
|
if (rc == XWT_TIMER_FAILED) {
|
||||||
pr_err("SelfTest routine error!\n");
|
pr_err("SelfTest routine error!\n");
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = watchdog_register_device(&xilinx_wdt_wdd);
|
rc = watchdog_register_device(xilinx_wdt_wdd);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
pr_err("cannot register watchdog (err=%d)\n", rc);
|
pr_err("cannot register watchdog (err=%d)\n", rc);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_info(&pdev->dev, "Xilinx Watchdog Timer at %p with timeout %ds\n",
|
dev_info(&pdev->dev, "Xilinx Watchdog Timer at %p with timeout %ds\n",
|
||||||
xdev.base, timeout);
|
xdev->base, xilinx_wdt_wdd->timeout);
|
||||||
|
|
||||||
|
platform_set_drvdata(pdev, xdev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int xwdt_remove(struct platform_device *dev)
|
static int xwdt_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
watchdog_unregister_device(&xilinx_wdt_wdd);
|
struct xwdt_device *xdev = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
|
watchdog_unregister_device(&xdev->xilinx_wdt_wdd);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue