.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Imagination Technologies PowerDown Controller Watchdog Timer. |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (c) 2014 Imagination Technologies Ltd. |
---|
5 | | - * |
---|
6 | | - * This program is free software; you can redistribute it and/or modify it |
---|
7 | | - * under the terms of the GNU General Public License version 2 as published by |
---|
8 | | - * the Free Software Foundation. |
---|
9 | 6 | * |
---|
10 | 7 | * Based on drivers/watchdog/sunxi_wdt.c Copyright (c) 2013 Carlo Caione |
---|
11 | 8 | * 2012 Henrik Nordstrom |
---|
.. | .. |
---|
178 | 175 | .restart = pdc_wdt_restart, |
---|
179 | 176 | }; |
---|
180 | 177 | |
---|
| 178 | +static void pdc_clk_disable_unprepare(void *data) |
---|
| 179 | +{ |
---|
| 180 | + clk_disable_unprepare(data); |
---|
| 181 | +} |
---|
| 182 | + |
---|
181 | 183 | static int pdc_wdt_probe(struct platform_device *pdev) |
---|
182 | 184 | { |
---|
| 185 | + struct device *dev = &pdev->dev; |
---|
183 | 186 | u64 div; |
---|
184 | 187 | int ret, val; |
---|
185 | 188 | unsigned long clk_rate; |
---|
186 | | - struct resource *res; |
---|
187 | 189 | struct pdc_wdt_dev *pdc_wdt; |
---|
188 | 190 | |
---|
189 | | - pdc_wdt = devm_kzalloc(&pdev->dev, sizeof(*pdc_wdt), GFP_KERNEL); |
---|
| 191 | + pdc_wdt = devm_kzalloc(dev, sizeof(*pdc_wdt), GFP_KERNEL); |
---|
190 | 192 | if (!pdc_wdt) |
---|
191 | 193 | return -ENOMEM; |
---|
192 | 194 | |
---|
193 | | - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
---|
194 | | - pdc_wdt->base = devm_ioremap_resource(&pdev->dev, res); |
---|
| 195 | + pdc_wdt->base = devm_platform_ioremap_resource(pdev, 0); |
---|
195 | 196 | if (IS_ERR(pdc_wdt->base)) |
---|
196 | 197 | return PTR_ERR(pdc_wdt->base); |
---|
197 | 198 | |
---|
198 | | - pdc_wdt->sys_clk = devm_clk_get(&pdev->dev, "sys"); |
---|
| 199 | + pdc_wdt->sys_clk = devm_clk_get(dev, "sys"); |
---|
199 | 200 | if (IS_ERR(pdc_wdt->sys_clk)) { |
---|
200 | | - dev_err(&pdev->dev, "failed to get the sys clock\n"); |
---|
| 201 | + dev_err(dev, "failed to get the sys clock\n"); |
---|
201 | 202 | return PTR_ERR(pdc_wdt->sys_clk); |
---|
202 | 203 | } |
---|
203 | 204 | |
---|
204 | | - pdc_wdt->wdt_clk = devm_clk_get(&pdev->dev, "wdt"); |
---|
| 205 | + pdc_wdt->wdt_clk = devm_clk_get(dev, "wdt"); |
---|
205 | 206 | if (IS_ERR(pdc_wdt->wdt_clk)) { |
---|
206 | | - dev_err(&pdev->dev, "failed to get the wdt clock\n"); |
---|
| 207 | + dev_err(dev, "failed to get the wdt clock\n"); |
---|
207 | 208 | return PTR_ERR(pdc_wdt->wdt_clk); |
---|
208 | 209 | } |
---|
209 | 210 | |
---|
210 | 211 | ret = clk_prepare_enable(pdc_wdt->sys_clk); |
---|
211 | 212 | if (ret) { |
---|
212 | | - dev_err(&pdev->dev, "could not prepare or enable sys clock\n"); |
---|
| 213 | + dev_err(dev, "could not prepare or enable sys clock\n"); |
---|
213 | 214 | return ret; |
---|
214 | 215 | } |
---|
| 216 | + ret = devm_add_action_or_reset(dev, pdc_clk_disable_unprepare, |
---|
| 217 | + pdc_wdt->sys_clk); |
---|
| 218 | + if (ret) |
---|
| 219 | + return ret; |
---|
215 | 220 | |
---|
216 | 221 | ret = clk_prepare_enable(pdc_wdt->wdt_clk); |
---|
217 | 222 | if (ret) { |
---|
218 | | - dev_err(&pdev->dev, "could not prepare or enable wdt clock\n"); |
---|
219 | | - goto disable_sys_clk; |
---|
| 223 | + dev_err(dev, "could not prepare or enable wdt clock\n"); |
---|
| 224 | + return ret; |
---|
220 | 225 | } |
---|
| 226 | + ret = devm_add_action_or_reset(dev, pdc_clk_disable_unprepare, |
---|
| 227 | + pdc_wdt->wdt_clk); |
---|
| 228 | + if (ret) |
---|
| 229 | + return ret; |
---|
221 | 230 | |
---|
222 | 231 | /* We use the clock rate to calculate the max timeout */ |
---|
223 | 232 | clk_rate = clk_get_rate(pdc_wdt->wdt_clk); |
---|
224 | 233 | if (clk_rate == 0) { |
---|
225 | | - dev_err(&pdev->dev, "failed to get clock rate\n"); |
---|
226 | | - ret = -EINVAL; |
---|
227 | | - goto disable_wdt_clk; |
---|
| 234 | + dev_err(dev, "failed to get clock rate\n"); |
---|
| 235 | + return -EINVAL; |
---|
228 | 236 | } |
---|
229 | 237 | |
---|
230 | 238 | if (order_base_2(clk_rate) > PDC_WDT_CONFIG_DELAY_MASK + 1) { |
---|
231 | | - dev_err(&pdev->dev, "invalid clock rate\n"); |
---|
232 | | - ret = -EINVAL; |
---|
233 | | - goto disable_wdt_clk; |
---|
| 239 | + dev_err(dev, "invalid clock rate\n"); |
---|
| 240 | + return -EINVAL; |
---|
234 | 241 | } |
---|
235 | 242 | |
---|
236 | 243 | if (order_base_2(clk_rate) == 0) |
---|
.. | .. |
---|
245 | 252 | do_div(div, clk_rate); |
---|
246 | 253 | pdc_wdt->wdt_dev.max_timeout = div; |
---|
247 | 254 | pdc_wdt->wdt_dev.timeout = PDC_WDT_DEF_TIMEOUT; |
---|
248 | | - pdc_wdt->wdt_dev.parent = &pdev->dev; |
---|
| 255 | + pdc_wdt->wdt_dev.parent = dev; |
---|
249 | 256 | watchdog_set_drvdata(&pdc_wdt->wdt_dev, pdc_wdt); |
---|
250 | 257 | |
---|
251 | | - watchdog_init_timeout(&pdc_wdt->wdt_dev, heartbeat, &pdev->dev); |
---|
| 258 | + watchdog_init_timeout(&pdc_wdt->wdt_dev, heartbeat, dev); |
---|
252 | 259 | |
---|
253 | 260 | pdc_wdt_stop(&pdc_wdt->wdt_dev); |
---|
254 | 261 | |
---|
.. | .. |
---|
259 | 266 | case PDC_WDT_TICKLE_STATUS_TICKLE: |
---|
260 | 267 | case PDC_WDT_TICKLE_STATUS_TIMEOUT: |
---|
261 | 268 | pdc_wdt->wdt_dev.bootstatus |= WDIOF_CARDRESET; |
---|
262 | | - dev_info(&pdev->dev, |
---|
263 | | - "watchdog module last reset due to timeout\n"); |
---|
| 269 | + dev_info(dev, "watchdog module last reset due to timeout\n"); |
---|
264 | 270 | break; |
---|
265 | 271 | case PDC_WDT_TICKLE_STATUS_HRESET: |
---|
266 | | - dev_info(&pdev->dev, |
---|
| 272 | + dev_info(dev, |
---|
267 | 273 | "watchdog module last reset due to hard reset\n"); |
---|
268 | 274 | break; |
---|
269 | 275 | case PDC_WDT_TICKLE_STATUS_SRESET: |
---|
270 | | - dev_info(&pdev->dev, |
---|
| 276 | + dev_info(dev, |
---|
271 | 277 | "watchdog module last reset due to soft reset\n"); |
---|
272 | 278 | break; |
---|
273 | 279 | case PDC_WDT_TICKLE_STATUS_USER: |
---|
274 | | - dev_info(&pdev->dev, |
---|
| 280 | + dev_info(dev, |
---|
275 | 281 | "watchdog module last reset due to user reset\n"); |
---|
276 | 282 | break; |
---|
277 | 283 | default: |
---|
278 | | - dev_info(&pdev->dev, |
---|
279 | | - "contains an illegal status code (%08x)\n", val); |
---|
| 284 | + dev_info(dev, "contains an illegal status code (%08x)\n", val); |
---|
280 | 285 | break; |
---|
281 | 286 | } |
---|
282 | 287 | |
---|
.. | .. |
---|
285 | 290 | |
---|
286 | 291 | platform_set_drvdata(pdev, pdc_wdt); |
---|
287 | 292 | |
---|
288 | | - ret = watchdog_register_device(&pdc_wdt->wdt_dev); |
---|
289 | | - if (ret) |
---|
290 | | - goto disable_wdt_clk; |
---|
291 | | - |
---|
292 | | - return 0; |
---|
293 | | - |
---|
294 | | -disable_wdt_clk: |
---|
295 | | - clk_disable_unprepare(pdc_wdt->wdt_clk); |
---|
296 | | -disable_sys_clk: |
---|
297 | | - clk_disable_unprepare(pdc_wdt->sys_clk); |
---|
298 | | - return ret; |
---|
299 | | -} |
---|
300 | | - |
---|
301 | | -static void pdc_wdt_shutdown(struct platform_device *pdev) |
---|
302 | | -{ |
---|
303 | | - struct pdc_wdt_dev *pdc_wdt = platform_get_drvdata(pdev); |
---|
304 | | - |
---|
305 | | - pdc_wdt_stop(&pdc_wdt->wdt_dev); |
---|
306 | | -} |
---|
307 | | - |
---|
308 | | -static int pdc_wdt_remove(struct platform_device *pdev) |
---|
309 | | -{ |
---|
310 | | - struct pdc_wdt_dev *pdc_wdt = platform_get_drvdata(pdev); |
---|
311 | | - |
---|
312 | | - pdc_wdt_stop(&pdc_wdt->wdt_dev); |
---|
313 | | - watchdog_unregister_device(&pdc_wdt->wdt_dev); |
---|
314 | | - clk_disable_unprepare(pdc_wdt->wdt_clk); |
---|
315 | | - clk_disable_unprepare(pdc_wdt->sys_clk); |
---|
316 | | - |
---|
317 | | - return 0; |
---|
| 293 | + watchdog_stop_on_reboot(&pdc_wdt->wdt_dev); |
---|
| 294 | + watchdog_stop_on_unregister(&pdc_wdt->wdt_dev); |
---|
| 295 | + return devm_watchdog_register_device(dev, &pdc_wdt->wdt_dev); |
---|
318 | 296 | } |
---|
319 | 297 | |
---|
320 | 298 | static const struct of_device_id pdc_wdt_match[] = { |
---|
.. | .. |
---|
329 | 307 | .of_match_table = pdc_wdt_match, |
---|
330 | 308 | }, |
---|
331 | 309 | .probe = pdc_wdt_probe, |
---|
332 | | - .remove = pdc_wdt_remove, |
---|
333 | | - .shutdown = pdc_wdt_shutdown, |
---|
334 | 310 | }; |
---|
335 | 311 | module_platform_driver(pdc_wdt_driver); |
---|
336 | 312 | |
---|