openwrt/target/linux/bcm27xx/patches-5.10/950-0481-gpio-fsm-Show-stat...

185 lines
4.8 KiB
Diff

From 1e50027d42006cbc42957b5053caf96ee52c7f8c Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
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 <phil@raspberrypi.com>
---
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 <linux/interrupt.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/sysfs.h>
#include <dt-bindings/gpio/gpio-fsm.h>
@@ -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/<fsm-name>/
+ * /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 <phil@raspberrypi.com>");