aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/watchdog/orion_wdt.c114
1 files changed, 69 insertions, 45 deletions
diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c
index 65aa65560730..9d3a5b97845b 100644
--- a/drivers/watchdog/orion_wdt.c
+++ b/drivers/watchdog/orion_wdt.c
@@ -44,55 +44,66 @@
44 44
45static bool nowayout = WATCHDOG_NOWAYOUT; 45static bool nowayout = WATCHDOG_NOWAYOUT;
46static int heartbeat = -1; /* module parameter (seconds) */ 46static int heartbeat = -1; /* module parameter (seconds) */
47static unsigned int wdt_max_duration; /* (seconds) */ 47
48static struct clk *clk; 48struct orion_watchdog {
49static unsigned int wdt_tclk; 49 struct watchdog_device wdt;
50static void __iomem *wdt_reg; 50 void __iomem *reg;
51static void __iomem *wdt_rstout; 51 void __iomem *rstout;
52 unsigned long clk_rate;
53 struct clk *clk;
54};
52 55
53static int orion_wdt_ping(struct watchdog_device *wdt_dev) 56static int orion_wdt_ping(struct watchdog_device *wdt_dev)
54{ 57{
58 struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
55 /* Reload watchdog duration */ 59 /* Reload watchdog duration */
56 writel(wdt_tclk * wdt_dev->timeout, wdt_reg + WDT_VAL); 60 writel(dev->clk_rate * wdt_dev->timeout, dev->reg + WDT_VAL);
57 return 0; 61 return 0;
58} 62}
59 63
60static int orion_wdt_start(struct watchdog_device *wdt_dev) 64static int orion_wdt_start(struct watchdog_device *wdt_dev)
61{ 65{
66 struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
67
62 /* Set watchdog duration */ 68 /* Set watchdog duration */
63 writel(wdt_tclk * wdt_dev->timeout, wdt_reg + WDT_VAL); 69 writel(dev->clk_rate * wdt_dev->timeout, dev->reg + WDT_VAL);
64 70
65 /* Enable watchdog timer */ 71 /* Enable watchdog timer */
66 atomic_io_modify(wdt_reg + TIMER_CTRL, WDT_EN, WDT_EN); 72 atomic_io_modify(dev->reg + TIMER_CTRL, WDT_EN, WDT_EN);
67 73
68 /* Enable reset on watchdog */ 74 /* Enable reset on watchdog */
69 atomic_io_modify(wdt_rstout, WDT_RESET_OUT_EN, WDT_RESET_OUT_EN); 75 atomic_io_modify(dev->rstout, WDT_RESET_OUT_EN, WDT_RESET_OUT_EN);
76
70 return 0; 77 return 0;
71} 78}
72 79
73static int orion_wdt_stop(struct watchdog_device *wdt_dev) 80static int orion_wdt_stop(struct watchdog_device *wdt_dev)
74{ 81{
82 struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
83
75 /* Disable reset on watchdog */ 84 /* Disable reset on watchdog */
76 atomic_io_modify(wdt_rstout, WDT_RESET_OUT_EN, 0); 85 atomic_io_modify(dev->rstout, WDT_RESET_OUT_EN, 0);
77 86
78 /* Disable watchdog timer */ 87 /* Disable watchdog timer */
79 atomic_io_modify(wdt_reg + TIMER_CTRL, WDT_EN, 0); 88 atomic_io_modify(dev->reg + TIMER_CTRL, WDT_EN, 0);
89
80 return 0; 90 return 0;
81} 91}
82 92
83static int orion_wdt_enabled(void) 93static int orion_wdt_enabled(struct orion_watchdog *dev)
84{ 94{
85 bool enabled, running; 95 bool enabled, running;
86 96
87 enabled = readl(wdt_rstout) & WDT_RESET_OUT_EN; 97 enabled = readl(dev->rstout) & WDT_RESET_OUT_EN;
88 running = readl(wdt_reg + TIMER_CTRL) & WDT_EN; 98 running = readl(dev->reg + TIMER_CTRL) & WDT_EN;
89 99
90 return enabled && running; 100 return enabled && running;
91} 101}
92 102
93static unsigned int orion_wdt_get_timeleft(struct watchdog_device *wdt_dev) 103static unsigned int orion_wdt_get_timeleft(struct watchdog_device *wdt_dev)
94{ 104{
95 return readl(wdt_reg + WDT_VAL) / wdt_tclk; 105 struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
106 return readl(dev->reg + WDT_VAL) / dev->clk_rate;
96} 107}
97 108
98static int orion_wdt_set_timeout(struct watchdog_device *wdt_dev, 109static int orion_wdt_set_timeout(struct watchdog_device *wdt_dev,
@@ -116,12 +127,6 @@ static const struct watchdog_ops orion_wdt_ops = {
116 .get_timeleft = orion_wdt_get_timeleft, 127 .get_timeleft = orion_wdt_get_timeleft,
117}; 128};
118 129
119static struct watchdog_device orion_wdt = {
120 .info = &orion_wdt_info,
121 .ops = &orion_wdt_ops,
122 .min_timeout = 1,
123};
124
125static irqreturn_t orion_wdt_irq(int irq, void *devid) 130static irqreturn_t orion_wdt_irq(int irq, void *devid)
126{ 131{
127 panic("Watchdog Timeout"); 132 panic("Watchdog Timeout");
@@ -157,18 +162,29 @@ static void __iomem *orion_wdt_ioremap_rstout(struct platform_device *pdev,
157 162
158static int orion_wdt_probe(struct platform_device *pdev) 163static int orion_wdt_probe(struct platform_device *pdev)
159{ 164{
165 struct orion_watchdog *dev;
166 unsigned int wdt_max_duration; /* (seconds) */
160 struct resource *res; 167 struct resource *res;
161 int ret, irq; 168 int ret, irq;
162 169
163 clk = devm_clk_get(&pdev->dev, NULL); 170 dev = devm_kzalloc(&pdev->dev, sizeof(struct orion_watchdog),
164 if (IS_ERR(clk)) { 171 GFP_KERNEL);
172 if (!dev)
173 return -ENOMEM;
174
175 dev->wdt.info = &orion_wdt_info;
176 dev->wdt.ops = &orion_wdt_ops;
177 dev->wdt.min_timeout = 1;
178
179 dev->clk = devm_clk_get(&pdev->dev, NULL);
180 if (IS_ERR(dev->clk)) {
165 dev_err(&pdev->dev, "Orion Watchdog missing clock\n"); 181 dev_err(&pdev->dev, "Orion Watchdog missing clock\n");
166 return PTR_ERR(clk); 182 return PTR_ERR(dev->clk);
167 } 183 }
168 ret = clk_prepare_enable(clk); 184 ret = clk_prepare_enable(dev->clk);
169 if (ret) 185 if (ret)
170 return ret; 186 return ret;
171 wdt_tclk = clk_get_rate(clk); 187 dev->clk_rate = clk_get_rate(dev->clk);
172 188
173 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 189 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
174 if (!res) { 190 if (!res) {
@@ -176,24 +192,28 @@ static int orion_wdt_probe(struct platform_device *pdev)
176 goto disable_clk; 192 goto disable_clk;
177 } 193 }
178 194
179 wdt_reg = devm_ioremap(&pdev->dev, res->start, resource_size(res)); 195 dev->reg = devm_ioremap(&pdev->dev, res->start,
180 if (!wdt_reg) { 196 resource_size(res));
197 if (!dev->reg) {
181 ret = -ENOMEM; 198 ret = -ENOMEM;
182 goto disable_clk; 199 goto disable_clk;
183 } 200 }
184 201
185 wdt_rstout = orion_wdt_ioremap_rstout(pdev, res->start & 202 dev->rstout = orion_wdt_ioremap_rstout(pdev, res->start &
186 INTERNAL_REGS_MASK); 203 INTERNAL_REGS_MASK);
187 if (!wdt_rstout) { 204 if (!dev->rstout) {
188 ret = -ENODEV; 205 ret = -ENODEV;
189 goto disable_clk; 206 goto disable_clk;
190 } 207 }
191 208
192 wdt_max_duration = WDT_MAX_CYCLE_COUNT / wdt_tclk; 209 wdt_max_duration = WDT_MAX_CYCLE_COUNT / dev->clk_rate;
210
211 dev->wdt.timeout = wdt_max_duration;
212 dev->wdt.max_timeout = wdt_max_duration;
213 watchdog_init_timeout(&dev->wdt, heartbeat, &pdev->dev);
193 214
194 orion_wdt.timeout = wdt_max_duration; 215 platform_set_drvdata(pdev, &dev->wdt);
195 orion_wdt.max_timeout = wdt_max_duration; 216 watchdog_set_drvdata(&dev->wdt, dev);
196 watchdog_init_timeout(&orion_wdt, heartbeat, &pdev->dev);
197 217
198 /* 218 /*
199 * Let's make sure the watchdog is fully stopped, unless it's 219 * Let's make sure the watchdog is fully stopped, unless it's
@@ -201,8 +221,8 @@ static int orion_wdt_probe(struct platform_device *pdev)
201 * removed and re-insterted, or if the bootloader explicitly 221 * removed and re-insterted, or if the bootloader explicitly
202 * set a running watchdog before booting the kernel. 222 * set a running watchdog before booting the kernel.
203 */ 223 */
204 if (!orion_wdt_enabled()) 224 if (!orion_wdt_enabled(dev))
205 orion_wdt_stop(&orion_wdt); 225 orion_wdt_stop(&dev->wdt);
206 226
207 /* Request the IRQ only after the watchdog is disabled */ 227 /* Request the IRQ only after the watchdog is disabled */
208 irq = platform_get_irq(pdev, 0); 228 irq = platform_get_irq(pdev, 0);
@@ -212,37 +232,41 @@ static int orion_wdt_probe(struct platform_device *pdev)
212 * watchdog, so let's make it optional. 232 * watchdog, so let's make it optional.
213 */ 233 */
214 ret = devm_request_irq(&pdev->dev, irq, orion_wdt_irq, 0, 234 ret = devm_request_irq(&pdev->dev, irq, orion_wdt_irq, 0,
215 pdev->name, &orion_wdt); 235 pdev->name, dev);
216 if (ret < 0) { 236 if (ret < 0) {
217 dev_err(&pdev->dev, "failed to request IRQ\n"); 237 dev_err(&pdev->dev, "failed to request IRQ\n");
218 goto disable_clk; 238 goto disable_clk;
219 } 239 }
220 } 240 }
221 241
222 watchdog_set_nowayout(&orion_wdt, nowayout); 242 watchdog_set_nowayout(&dev->wdt, nowayout);
223 ret = watchdog_register_device(&orion_wdt); 243 ret = watchdog_register_device(&dev->wdt);
224 if (ret) 244 if (ret)
225 goto disable_clk; 245 goto disable_clk;
226 246
227 pr_info("Initial timeout %d sec%s\n", 247 pr_info("Initial timeout %d sec%s\n",
228 orion_wdt.timeout, nowayout ? ", nowayout" : ""); 248 dev->wdt.timeout, nowayout ? ", nowayout" : "");
229 return 0; 249 return 0;
230 250
231disable_clk: 251disable_clk:
232 clk_disable_unprepare(clk); 252 clk_disable_unprepare(dev->clk);
233 return ret; 253 return ret;
234} 254}
235 255
236static int orion_wdt_remove(struct platform_device *pdev) 256static int orion_wdt_remove(struct platform_device *pdev)
237{ 257{
238 watchdog_unregister_device(&orion_wdt); 258 struct watchdog_device *wdt_dev = platform_get_drvdata(pdev);
239 clk_disable_unprepare(clk); 259 struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
260
261 watchdog_unregister_device(wdt_dev);
262 clk_disable_unprepare(dev->clk);
240 return 0; 263 return 0;
241} 264}
242 265
243static void orion_wdt_shutdown(struct platform_device *pdev) 266static void orion_wdt_shutdown(struct platform_device *pdev)
244{ 267{
245 orion_wdt_stop(&orion_wdt); 268 struct watchdog_device *wdt_dev = platform_get_drvdata(pdev);
269 orion_wdt_stop(wdt_dev);
246} 270}
247 271
248static const struct of_device_id orion_wdt_of_match_table[] = { 272static const struct of_device_id orion_wdt_of_match_table[] = {