/* * Watchdog driver for the A21 VME CPU Boards * * Copyright (C) 2013 MEN Mikro Elektronik Nuernberg GmbH * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation */ #include #include #include #include #include #include #include #include #include #include #include #include #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; struct mutex lock; unsigned gpios[NUM_GPIOS]; }; 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; reset |= gpio_get_value(drv->gpios[GPIO_WD_RST0]) ? (1 << 0) : 0; reset |= gpio_get_value(drv->gpios[GPIO_WD_RST1]) ? (1 << 1) : 0; reset |= gpio_get_value(drv->gpios[GPIO_WD_RST2]) ? (1 << 2) : 0; return reset; } static int a21_wdt_start(struct watchdog_device *wdt) { struct a21_wdt_drv *drv = watchdog_get_drvdata(wdt); mutex_lock(&drv->lock); gpio_set_value(drv->gpios[GPIO_WD_ENAB], 1); mutex_unlock(&drv->lock); return 0; } static int a21_wdt_stop(struct watchdog_device *wdt) { struct a21_wdt_drv *drv = watchdog_get_drvdata(wdt); mutex_lock(&drv->lock); gpio_set_value(drv->gpios[GPIO_WD_ENAB], 0); mutex_unlock(&drv->lock); return 0; } static int a21_wdt_ping(struct watchdog_device *wdt) { struct a21_wdt_drv *drv = watchdog_get_drvdata(wdt); mutex_lock(&drv->lock); gpio_set_value(drv->gpios[GPIO_WD_TRIG], 0); ndelay(10); gpio_set_value(drv->gpios[GPIO_WD_TRIG], 1); mutex_unlock(&drv->lock); 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) { dev_err(wdt->parent, "Only 1 and 30 allowed as timeout\n"); return -EINVAL; } if (timeout == 30 && wdt->timeout == 1) { dev_err(wdt->parent, "Transition from fast to slow mode not allowed\n"); return -EINVAL; } mutex_lock(&drv->lock); if (timeout == 1) gpio_set_value(drv->gpios[GPIO_WD_FAST], 1); else gpio_set_value(drv->gpios[GPIO_WD_FAST], 0); wdt->timeout = timeout; mutex_unlock(&drv->lock); 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) { struct device_node *node; struct a21_wdt_drv *drv; unsigned int reset = 0; int num_gpios; int ret; int i; drv = devm_kzalloc(&pdev->dev, sizeof(struct a21_wdt_drv), GFP_KERNEL); if (!drv) return -ENOMEM; /* Fill GPIO pin array */ node = pdev->dev.of_node; num_gpios = of_gpio_count(node); if (num_gpios != NUM_GPIOS) { dev_err(&pdev->dev, "gpios DT property wrong, got %d want %d", num_gpios, NUM_GPIOS); return -ENODEV; } for (i = 0; i < num_gpios; i++) { int val; val = of_get_gpio(node, i); if (val < 0) return val; drv->gpios[i] = val; } /* Request the used GPIOs */ for (i = 0; i < num_gpios; i++) { ret = devm_gpio_request(&pdev->dev, drv->gpios[i], "MEN A21 Watchdog"); if (ret) return ret; if (i < GPIO_WD_RST0) ret = gpio_direction_output(drv->gpios[i], gpio_get_value(drv->gpios[i])); else /* GPIO_WD_RST[0..2] are inputs */ ret = gpio_direction_input(drv->gpios[i]); if (ret) return ret; } mutex_init(&drv->lock); watchdog_init_timeout(&a21_wdt, 30, &pdev->dev); watchdog_set_nowayout(&a21_wdt, nowayout); watchdog_set_drvdata(&a21_wdt, drv); a21_wdt.parent = &pdev->dev; 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; drv->wdt = a21_wdt; dev_set_drvdata(&pdev->dev, drv); ret = watchdog_register_device(&a21_wdt); if (ret) { dev_err(&pdev->dev, "Cannot register watchdog device\n"); goto err_register_wd; } dev_info(&pdev->dev, "MEN A21 watchdog timer driver enabled\n"); return 0; err_register_wd: mutex_destroy(&drv->lock); return ret; } static int a21_wdt_remove(struct platform_device *pdev) { struct a21_wdt_drv *drv = dev_get_drvdata(&pdev->dev); dev_warn(&pdev->dev, "Unregistering A21 watchdog driver, board may reboot\n"); watchdog_unregister_device(&drv->wdt); mutex_destroy(&drv->lock); return 0; } static void a21_wdt_shutdown(struct platform_device *pdev) { struct a21_wdt_drv *drv = dev_get_drvdata(&pdev->dev); gpio_set_value(drv->gpios[GPIO_WD_ENAB], 0); } static const struct of_device_id a21_wdt_ids[] = { { .compatible = "men,a021-wdt" }, { }, }; MODULE_DEVICE_TABLE(of, a21_wdt_ids); static struct platform_driver a21_wdt_driver = { .probe = a21_wdt_probe, .remove = a21_wdt_remove, .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"); > parentb272f732f888d4cf43c943a40c9aaa836f9b7431 (diff)parent1f3a8e49d8f28f498b8694464623ac20aebfe62a (diff)
Merge branch 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull timer type cleanups from Thomas Gleixner: "This series does a tree wide cleanup of types related to timers/timekeeping. - Get rid of cycles_t and use a plain u64. The type is not really helpful and caused more confusion than clarity - Get rid of the ktime union. The union has become useless as we use the scalar nanoseconds storage unconditionally now. The 32bit timespec alike storage got removed due to the Y2038 limitations some time ago. That leaves the odd union access around for no reason. Clean it up. Both changes have been done with coccinelle and a small amount of manual mopping up" * 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: ktime: Get rid of ktime_equal() ktime: Cleanup ktime_set() usage ktime: Get rid of the union clocksource: Use a plain u64 instead of cycle_t
Diffstat (limited to 'tools/perf/builtin-stat.c')