Blame view
drivers/watchdog/mena21_wdt.c
5.11 KB
2e62c4988 watchdog: add SPD... |
1 |
// SPDX-License-Identifier: GPL-2.0+ |
26c57ef1e watchdog: New wat... |
2 3 4 5 6 |
/* * Watchdog driver for the A21 VME CPU Boards * * Copyright (C) 2013 MEN Mikro Elektronik Nuernberg GmbH * |
26c57ef1e watchdog: New wat... |
7 8 9 10 11 12 13 14 15 |
*/ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/slab.h> #include <linux/platform_device.h> #include <linux/watchdog.h> #include <linux/uaccess.h> |
22ec9bb1c watchdog: mena21_... |
16 |
#include <linux/gpio/consumer.h> |
26c57ef1e watchdog: New wat... |
17 18 |
#include <linux/delay.h> #include <linux/bitops.h> |
22ec9bb1c watchdog: mena21_... |
19 |
#include <linux/of.h> |
26c57ef1e watchdog: New wat... |
20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
#define NUM_GPIOS 6 enum a21_wdt_gpios { GPIO_WD_ENAB, GPIO_WD_FAST, GPIO_WD_TRIG, GPIO_WD_RST0, GPIO_WD_RST1, GPIO_WD_RST2, }; struct a21_wdt_drv { struct watchdog_device wdt; |
22ec9bb1c watchdog: mena21_... |
34 |
struct gpio_desc *gpios[NUM_GPIOS]; |
26c57ef1e watchdog: New wat... |
35 36 37 38 39 40 41 42 43 44 |
}; static bool nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, bool, 0); MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); static unsigned int a21_wdt_get_bootstatus(struct a21_wdt_drv *drv) { int reset = 0; |
22ec9bb1c watchdog: mena21_... |
45 46 47 |
reset |= gpiod_get_value(drv->gpios[GPIO_WD_RST0]) ? (1 << 0) : 0; reset |= gpiod_get_value(drv->gpios[GPIO_WD_RST1]) ? (1 << 1) : 0; reset |= gpiod_get_value(drv->gpios[GPIO_WD_RST2]) ? (1 << 2) : 0; |
26c57ef1e watchdog: New wat... |
48 49 50 51 52 53 54 |
return reset; } static int a21_wdt_start(struct watchdog_device *wdt) { struct a21_wdt_drv *drv = watchdog_get_drvdata(wdt); |
22ec9bb1c watchdog: mena21_... |
55 |
gpiod_set_value(drv->gpios[GPIO_WD_ENAB], 1); |
26c57ef1e watchdog: New wat... |
56 |
|
26c57ef1e watchdog: New wat... |
57 58 59 60 61 62 |
return 0; } static int a21_wdt_stop(struct watchdog_device *wdt) { struct a21_wdt_drv *drv = watchdog_get_drvdata(wdt); |
22ec9bb1c watchdog: mena21_... |
63 |
gpiod_set_value(drv->gpios[GPIO_WD_ENAB], 0); |
26c57ef1e watchdog: New wat... |
64 |
|
26c57ef1e watchdog: New wat... |
65 66 67 68 69 70 |
return 0; } static int a21_wdt_ping(struct watchdog_device *wdt) { struct a21_wdt_drv *drv = watchdog_get_drvdata(wdt); |
22ec9bb1c watchdog: mena21_... |
71 |
gpiod_set_value(drv->gpios[GPIO_WD_TRIG], 0); |
26c57ef1e watchdog: New wat... |
72 |
ndelay(10); |
22ec9bb1c watchdog: mena21_... |
73 |
gpiod_set_value(drv->gpios[GPIO_WD_TRIG], 1); |
26c57ef1e watchdog: New wat... |
74 |
|
26c57ef1e watchdog: New wat... |
75 76 77 78 79 80 81 82 83 |
return 0; } static int a21_wdt_set_timeout(struct watchdog_device *wdt, unsigned int timeout) { struct a21_wdt_drv *drv = watchdog_get_drvdata(wdt); if (timeout != 1 && timeout != 30) { |
073523662 watchdog: mena21:... |
84 85 |
dev_err(wdt->parent, "Only 1 and 30 allowed as timeout "); |
26c57ef1e watchdog: New wat... |
86 87 88 89 |
return -EINVAL; } if (timeout == 30 && wdt->timeout == 1) { |
073523662 watchdog: mena21:... |
90 |
dev_err(wdt->parent, |
26c57ef1e watchdog: New wat... |
91 92 93 94 |
"Transition from fast to slow mode not allowed "); return -EINVAL; } |
26c57ef1e watchdog: New wat... |
95 |
if (timeout == 1) |
22ec9bb1c watchdog: mena21_... |
96 |
gpiod_set_value(drv->gpios[GPIO_WD_FAST], 1); |
26c57ef1e watchdog: New wat... |
97 |
else |
22ec9bb1c watchdog: mena21_... |
98 |
gpiod_set_value(drv->gpios[GPIO_WD_FAST], 0); |
26c57ef1e watchdog: New wat... |
99 100 |
wdt->timeout = timeout; |
26c57ef1e watchdog: New wat... |
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
return 0; } static const struct watchdog_info a21_wdt_info = { .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, .identity = "MEN A21 Watchdog", }; static const struct watchdog_ops a21_wdt_ops = { .owner = THIS_MODULE, .start = a21_wdt_start, .stop = a21_wdt_stop, .ping = a21_wdt_ping, .set_timeout = a21_wdt_set_timeout, }; static struct watchdog_device a21_wdt = { .info = &a21_wdt_info, .ops = &a21_wdt_ops, .min_timeout = 1, .max_timeout = 30, }; static int a21_wdt_probe(struct platform_device *pdev) { |
94ac20d83 watchdog: mena21_... |
126 |
struct device *dev = &pdev->dev; |
26c57ef1e watchdog: New wat... |
127 128 129 130 131 |
struct a21_wdt_drv *drv; unsigned int reset = 0; int num_gpios; int ret; int i; |
94ac20d83 watchdog: mena21_... |
132 |
drv = devm_kzalloc(dev, sizeof(struct a21_wdt_drv), GFP_KERNEL); |
26c57ef1e watchdog: New wat... |
133 134 |
if (!drv) return -ENOMEM; |
94ac20d83 watchdog: mena21_... |
135 |
num_gpios = gpiod_count(dev, NULL); |
26c57ef1e watchdog: New wat... |
136 |
if (num_gpios != NUM_GPIOS) { |
94ac20d83 watchdog: mena21_... |
137 |
dev_err(dev, "gpios DT property wrong, got %d want %d", |
26c57ef1e watchdog: New wat... |
138 139 140 |
num_gpios, NUM_GPIOS); return -ENODEV; } |
26c57ef1e watchdog: New wat... |
141 142 |
/* Request the used GPIOs */ for (i = 0; i < num_gpios; i++) { |
22ec9bb1c watchdog: mena21_... |
143 |
enum gpiod_flags gflags; |
26c57ef1e watchdog: New wat... |
144 145 |
if (i < GPIO_WD_RST0) |
22ec9bb1c watchdog: mena21_... |
146 147 148 |
gflags = GPIOD_ASIS; else gflags = GPIOD_IN; |
94ac20d83 watchdog: mena21_... |
149 150 151 |
drv->gpios[i] = devm_gpiod_get_index(dev, NULL, i, gflags); if (IS_ERR(drv->gpios[i])) return PTR_ERR(drv->gpios[i]); |
22ec9bb1c watchdog: mena21_... |
152 153 154 155 156 157 158 159 160 161 162 163 164 |
gpiod_set_consumer_name(drv->gpios[i], "MEN A21 Watchdog"); /* * Retrieve the initial value from the GPIOs that should be * output, then set up the line as output with that value. */ if (i < GPIO_WD_RST0) { int val; val = gpiod_get_value(drv->gpios[i]); gpiod_direction_output(drv->gpios[i], val); } |
26c57ef1e watchdog: New wat... |
165 |
} |
94ac20d83 watchdog: mena21_... |
166 |
watchdog_init_timeout(&a21_wdt, 30, dev); |
26c57ef1e watchdog: New wat... |
167 168 |
watchdog_set_nowayout(&a21_wdt, nowayout); watchdog_set_drvdata(&a21_wdt, drv); |
94ac20d83 watchdog: mena21_... |
169 |
a21_wdt.parent = dev; |
26c57ef1e watchdog: New wat... |
170 171 172 173 174 175 176 177 178 179 |
reset = a21_wdt_get_bootstatus(drv); if (reset == 2) a21_wdt.bootstatus |= WDIOF_EXTERN1; else if (reset == 4) a21_wdt.bootstatus |= WDIOF_CARDRESET; else if (reset == 5) a21_wdt.bootstatus |= WDIOF_POWERUNDER; else if (reset == 7) a21_wdt.bootstatus |= WDIOF_EXTERN2; |
57337db1b watchdog: mena21_... |
180 |
drv->wdt = a21_wdt; |
94ac20d83 watchdog: mena21_... |
181 |
dev_set_drvdata(dev, drv); |
57337db1b watchdog: mena21_... |
182 |
|
94ac20d83 watchdog: mena21_... |
183 |
ret = devm_watchdog_register_device(dev, &a21_wdt); |
eddeb07bd watchdog: mena21_... |
184 |
if (ret) |
cb5c14ea5 watchdog: mena21_... |
185 |
return ret; |
26c57ef1e watchdog: New wat... |
186 |
|
94ac20d83 watchdog: mena21_... |
187 188 |
dev_info(dev, "MEN A21 watchdog timer driver enabled "); |
26c57ef1e watchdog: New wat... |
189 190 |
return 0; |
26c57ef1e watchdog: New wat... |
191 192 193 194 195 |
} static void a21_wdt_shutdown(struct platform_device *pdev) { struct a21_wdt_drv *drv = dev_get_drvdata(&pdev->dev); |
22ec9bb1c watchdog: mena21_... |
196 |
gpiod_set_value(drv->gpios[GPIO_WD_ENAB], 0); |
26c57ef1e watchdog: New wat... |
197 198 199 200 201 202 |
} static const struct of_device_id a21_wdt_ids[] = { { .compatible = "men,a021-wdt" }, { }, }; |
c73318f43 watchdog: Fix mod... |
203 |
MODULE_DEVICE_TABLE(of, a21_wdt_ids); |
26c57ef1e watchdog: New wat... |
204 205 206 |
static struct platform_driver a21_wdt_driver = { .probe = a21_wdt_probe, |
26c57ef1e watchdog: New wat... |
207 208 209 210 211 212 213 214 215 216 217 218 219 |
.shutdown = a21_wdt_shutdown, .driver = { .name = "a21-watchdog", .of_match_table = a21_wdt_ids, }, }; module_platform_driver(a21_wdt_driver); MODULE_AUTHOR("MEN Mikro Elektronik"); MODULE_DESCRIPTION("MEN A21 Watchdog"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:a21-watchdog"); |