msm: pil: Add name and state sysfs nodes
Userspace wants to know when a peripheral is online and if it has
rebooted. Add support for two sysfs nodes, name and state, to
notify userspace when such events happen.
The intent is for userspace to poll() the state node waiting for
the state to change. Once the peripheral goes offline, poll()
should return and userspace knows that the peripheral has booted
again.
Add a name node so that userspace can easily iterate over all
devices in /sys/bus/pil/devices/ to know what peripheral is
in what state.
Change-Id: I33c9dd42419b2e960d58dd2cd04cd82ddc1f5d60
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
diff --git a/arch/arm/mach-msm/peripheral-loader.c b/arch/arm/mach-msm/peripheral-loader.c
index d0e45f7..5b505b0 100644
--- a/arch/arm/mach-msm/peripheral-loader.c
+++ b/arch/arm/mach-msm/peripheral-loader.c
@@ -23,6 +23,7 @@
#include <linux/atomic.h>
#include <linux/suspend.h>
#include <linux/rwsem.h>
+#include <linux/sysfs.h>
#include <asm/uaccess.h>
#include <asm/setup.h>
@@ -30,9 +31,20 @@
#include "peripheral-loader.h"
+enum pil_state {
+ PIL_OFFLINE,
+ PIL_ONLINE,
+};
+
+static const char *pil_states[] = {
+ [PIL_OFFLINE] = "OFFLINE",
+ [PIL_ONLINE] = "ONLINE",
+};
+
struct pil_device {
struct pil_desc *desc;
int count;
+ enum pil_state state;
struct mutex lock;
struct device dev;
struct module *owner;
@@ -43,8 +55,28 @@
#define to_pil_device(d) container_of(d, struct pil_device, dev)
+static ssize_t name_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s\n", to_pil_device(dev)->desc->name);
+}
+
+static ssize_t state_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ enum pil_state state = to_pil_device(dev)->state;
+ return snprintf(buf, PAGE_SIZE, "%s\n", pil_states[state]);
+}
+
+static struct device_attribute pil_attrs[] = {
+ __ATTR_RO(name),
+ __ATTR_RO(state),
+ { },
+};
+
struct bus_type pil_bus_type = {
.name = "pil",
+ .dev_attrs = pil_attrs,
};
static int __find_peripheral(struct device *dev, void *data)
@@ -235,6 +267,14 @@
return ret;
}
+static void pil_set_state(struct pil_device *pil, enum pil_state state)
+{
+ if (pil->state != state) {
+ pil->state = state;
+ sysfs_notify(&pil->dev.kobj, NULL, "state");
+ }
+}
+
/**
* pil_get() - Load a peripheral into memory and take it out of reset
* @name: pointer to a string containing the name of the peripheral to load
@@ -276,6 +316,7 @@
goto err_load;
}
}
+ pil_set_state(pil, PIL_ONLINE);
mutex_unlock(&pil->lock);
out:
return retval;
@@ -306,8 +347,10 @@
mutex_lock(&pil->lock);
if (WARN(!pil->count, "%s: Reference count mismatch\n", __func__))
goto err_out;
- if (!--pil->count)
+ if (!--pil->count) {
pil->desc->ops->shutdown(pil->desc);
+ pil_set_state(pil, PIL_OFFLINE);
+ }
mutex_unlock(&pil->lock);
pil_d = find_peripheral(pil->desc->depends_on);
@@ -335,7 +378,9 @@
mutex_lock(&pil->lock);
if (!WARN(!pil->count, "%s: Reference count mismatch\n", __func__))
pil->desc->ops->shutdown(pil->desc);
+ pil_set_state(pil, PIL_OFFLINE);
mutex_unlock(&pil->lock);
+
put_device(&pil->dev);
}
EXPORT_SYMBOL(pil_force_shutdown);
@@ -352,6 +397,8 @@
mutex_lock(&pil->lock);
if (!WARN(!pil->count, "%s: Reference count mismatch\n", __func__))
ret = load_image(pil);
+ if (!ret)
+ pil_set_state(pil, PIL_ONLINE);
mutex_unlock(&pil->lock);
put_device(&pil->dev);