1 From 1e50027d42006cbc42957b5053caf96ee52c7f8c Mon Sep 17 00:00:00 2001
2 From: Phil Elwell <phil@raspberrypi.com>
3 Date: Sat, 17 Oct 2020 15:42:54 +0100
4 Subject: [PATCH] gpio-fsm: Show state info in /sys/class/gpio-fsm
6 Add gpio-fsm sysfs entries under /sys/class/gpio-fsm. For each state
7 machine show the current state, which state (if any) will be entered
8 after a delay, and the current value of that delay.
10 Signed-off-by: Phil Elwell <phil@raspberrypi.com>
12 drivers/gpio/gpio-fsm.c | 112 ++++++++++++++++++++++++++++++++++++++--
13 1 file changed, 108 insertions(+), 4 deletions(-)
15 --- a/drivers/gpio/gpio-fsm.c
16 +++ b/drivers/gpio/gpio-fsm.c
18 #include <linux/interrupt.h>
19 #include <linux/module.h>
20 #include <linux/platform_device.h>
21 +#include <linux/sysfs.h>
23 #include <dt-bindings/gpio/gpio-fsm.h>
25 @@ -120,6 +121,7 @@ struct gpio_fsm {
26 struct fsm_state *current_state;
27 struct fsm_state *next_state;
28 struct fsm_state *delay_target_state;
29 + unsigned int delay_jiffies;
33 @@ -364,9 +366,10 @@ static void gpio_fsm_enter_state(struct
34 jiffies + msecs_to_jiffies(state->shutdown_ms);
36 if (gf->shutting_down) {
37 + gf->delay_jiffies = gf->shutdown_jiffies;
38 gf->delay_target_state = state->shutdown_target;
39 gf->delay_ms = state->shutdown_ms;
40 - mod_timer(&gf->timer, gf->shutdown_jiffies);
41 + mod_timer(&gf->timer, gf->delay_jiffies);
45 @@ -421,9 +424,10 @@ static void gpio_fsm_enter_state(struct
46 // 6. Schedule a timer callback if delay_target
47 if (state->delay_target) {
48 gf->delay_target_state = state->delay_target;
49 + gf->delay_jiffies = jiffies +
50 + msecs_to_jiffies(state->delay_ms);
51 gf->delay_ms = state->delay_ms;
52 - mod_timer(&gf->timer,
53 - jiffies + msecs_to_jiffies(state->delay_ms));
54 + mod_timer(&gf->timer, gf->delay_jiffies);
58 @@ -847,10 +851,81 @@ static int resolve_sym_to_state(struct g
64 + * /sys/class/gpio-fsm/<fsm-name>/
65 + * /state ... the current state
68 +static ssize_t state_show(struct device *dev,
69 + struct device_attribute *attr, char *buf)
71 + const struct gpio_fsm *gf = dev_get_drvdata(dev);
73 + return sprintf(buf, "%s\n", gf->current_state->name);
75 +static DEVICE_ATTR_RO(state);
77 +static ssize_t delay_state_show(struct device *dev,
78 + struct device_attribute *attr, char *buf)
80 + const struct gpio_fsm *gf = dev_get_drvdata(dev);
82 + return sprintf(buf, "%s\n",
83 + gf->delay_target_state ? gf->delay_target_state->name :
87 +static DEVICE_ATTR_RO(delay_state);
89 +static ssize_t delay_ms_show(struct device *dev,
90 + struct device_attribute *attr, char *buf)
92 + const struct gpio_fsm *gf = dev_get_drvdata(dev);
95 + jiffies_left = gf->delay_jiffies - jiffies;
97 + gf->delay_target_state ? "%u\n" : "-\n",
98 + jiffies_to_msecs(jiffies_left));
100 +static DEVICE_ATTR_RO(delay_ms);
102 +static struct attribute *gpio_fsm_attrs[] = {
103 + &dev_attr_state.attr,
104 + &dev_attr_delay_state.attr,
105 + &dev_attr_delay_ms.attr,
109 +static const struct attribute_group gpio_fsm_group = {
110 + .attrs = gpio_fsm_attrs,
111 + //.is_visible = gpio_is_visible,
114 +static const struct attribute_group *gpio_fsm_groups[] = {
119 +static struct attribute *gpio_fsm_class_attrs[] = {
120 + // There are no top-level attributes
123 +ATTRIBUTE_GROUPS(gpio_fsm_class);
125 +static struct class gpio_fsm_class = {
126 + .name = MODULE_NAME,
127 + .owner = THIS_MODULE,
129 + .class_groups = gpio_fsm_class_groups,
132 static int gpio_fsm_probe(struct platform_device *pdev)
134 struct input_gpio_state *inp_state;
135 struct device *dev = &pdev->dev;
136 + struct device *sysfs_dev;
137 struct device_node *np = dev->of_node;
138 struct device_node *cp;
140 @@ -1029,6 +1104,13 @@ static int gpio_fsm_probe(struct platfor
142 platform_set_drvdata(pdev, gf);
144 + sysfs_dev = device_create_with_groups(&gpio_fsm_class, dev,
148 + if (IS_ERR(sysfs_dev))
149 + dev_err(gf->dev, "Error creating sysfs entry\n");
152 dev_info(gf->dev, "Start -> %s\n", gf->start_state->name);
154 @@ -1097,7 +1179,29 @@ static struct platform_driver gpio_fsm_d
155 .remove = gpio_fsm_remove,
156 .shutdown = gpio_fsm_shutdown,
158 -module_platform_driver(gpio_fsm_driver);
160 +static int gpio_fsm_init(void)
164 + ret = class_register(&gpio_fsm_class);
168 + ret = platform_driver_register(&gpio_fsm_driver);
170 + class_unregister(&gpio_fsm_class);
174 +module_init(gpio_fsm_init);
176 +static void gpio_fsm_exit(void)
178 + platform_driver_unregister(&gpio_fsm_driver);
179 + class_unregister(&gpio_fsm_class);
181 +module_exit(gpio_fsm_exit);
183 MODULE_LICENSE("GPL");
184 MODULE_AUTHOR("Phil Elwell <phil@raspberrypi.com>");