From 1e50027d42006cbc42957b5053caf96ee52c7f8c Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Sat, 17 Oct 2020 15:42:54 +0100 Subject: [PATCH] gpio-fsm: Show state info in /sys/class/gpio-fsm Add gpio-fsm sysfs entries under /sys/class/gpio-fsm. For each state machine show the current state, which state (if any) will be entered after a delay, and the current value of that delay. Signed-off-by: Phil Elwell --- drivers/gpio/gpio-fsm.c | 112 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 108 insertions(+), 4 deletions(-) --- a/drivers/gpio/gpio-fsm.c +++ b/drivers/gpio/gpio-fsm.c @@ -20,6 +20,7 @@ #include #include #include +#include #include @@ -120,6 +121,7 @@ struct gpio_fsm { struct fsm_state *current_state; struct fsm_state *next_state; struct fsm_state *delay_target_state; + unsigned int delay_jiffies; int delay_ms; unsigned int debug; bool shutting_down; @@ -364,9 +366,10 @@ static void gpio_fsm_enter_state(struct jiffies + msecs_to_jiffies(state->shutdown_ms); if (gf->shutting_down) { + gf->delay_jiffies = gf->shutdown_jiffies; gf->delay_target_state = state->shutdown_target; gf->delay_ms = state->shutdown_ms; - mod_timer(&gf->timer, gf->shutdown_jiffies); + mod_timer(&gf->timer, gf->delay_jiffies); } } @@ -421,9 +424,10 @@ static void gpio_fsm_enter_state(struct // 6. Schedule a timer callback if delay_target if (state->delay_target) { gf->delay_target_state = state->delay_target; + gf->delay_jiffies = jiffies + + msecs_to_jiffies(state->delay_ms); gf->delay_ms = state->delay_ms; - mod_timer(&gf->timer, - jiffies + msecs_to_jiffies(state->delay_ms)); + mod_timer(&gf->timer, gf->delay_jiffies); } } @@ -847,10 +851,81 @@ static int resolve_sym_to_state(struct g return 0; } + +/* + * /sys/class/gpio-fsm// + * /state ... the current state + */ + +static ssize_t state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + const struct gpio_fsm *gf = dev_get_drvdata(dev); + + return sprintf(buf, "%s\n", gf->current_state->name); +} +static DEVICE_ATTR_RO(state); + +static ssize_t delay_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + const struct gpio_fsm *gf = dev_get_drvdata(dev); + + return sprintf(buf, "%s\n", + gf->delay_target_state ? gf->delay_target_state->name : + "-"); +} + +static DEVICE_ATTR_RO(delay_state); + +static ssize_t delay_ms_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + const struct gpio_fsm *gf = dev_get_drvdata(dev); + int jiffies_left; + + jiffies_left = gf->delay_jiffies - jiffies; + return sprintf(buf, + gf->delay_target_state ? "%u\n" : "-\n", + jiffies_to_msecs(jiffies_left)); +} +static DEVICE_ATTR_RO(delay_ms); + +static struct attribute *gpio_fsm_attrs[] = { + &dev_attr_state.attr, + &dev_attr_delay_state.attr, + &dev_attr_delay_ms.attr, + NULL, +}; + +static const struct attribute_group gpio_fsm_group = { + .attrs = gpio_fsm_attrs, + //.is_visible = gpio_is_visible, +}; + +static const struct attribute_group *gpio_fsm_groups[] = { + &gpio_fsm_group, + NULL +}; + +static struct attribute *gpio_fsm_class_attrs[] = { + // There are no top-level attributes + NULL, +}; +ATTRIBUTE_GROUPS(gpio_fsm_class); + +static struct class gpio_fsm_class = { + .name = MODULE_NAME, + .owner = THIS_MODULE, + + .class_groups = gpio_fsm_class_groups, +}; + static int gpio_fsm_probe(struct platform_device *pdev) { struct input_gpio_state *inp_state; struct device *dev = &pdev->dev; + struct device *sysfs_dev; struct device_node *np = dev->of_node; struct device_node *cp; struct gpio_fsm *gf; @@ -1029,6 +1104,13 @@ static int gpio_fsm_probe(struct platfor platform_set_drvdata(pdev, gf); + sysfs_dev = device_create_with_groups(&gpio_fsm_class, dev, + MKDEV(0, 0), gf, + gpio_fsm_groups, + "%s", np->name); + if (IS_ERR(sysfs_dev)) + dev_err(gf->dev, "Error creating sysfs entry\n"); + if (gf->debug) dev_info(gf->dev, "Start -> %s\n", gf->start_state->name); @@ -1097,7 +1179,29 @@ static struct platform_driver gpio_fsm_d .remove = gpio_fsm_remove, .shutdown = gpio_fsm_shutdown, }; -module_platform_driver(gpio_fsm_driver); + +static int gpio_fsm_init(void) +{ + int ret; + + ret = class_register(&gpio_fsm_class); + if (ret) + return ret; + + ret = platform_driver_register(&gpio_fsm_driver); + if (ret) + class_unregister(&gpio_fsm_class); + + return ret; +} +module_init(gpio_fsm_init); + +static void gpio_fsm_exit(void) +{ + platform_driver_unregister(&gpio_fsm_driver); + class_unregister(&gpio_fsm_class); +} +module_exit(gpio_fsm_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Phil Elwell ");