regulator: Add basic trace facilities

Provide some basic trace facilities to the regulator API. We generate
events on regulator enable, disable and voltage setting over the actual
hardware operations (which are assumed to be the expensive ones which
require interaction with the actual device). This is intended to facilitate
debug of the performance and behaviour with consumers allowing unified
traces to be generated including the regulator operations within the
context of the other components of the system.

For enable we log the explicit delay for the voltage ramp separately to
the interaction with the hardware to highlight the time consumed in I/O.
We should add a similar delay for voltage changes, though there the
relatively small magnitude of the changes in the context of the I/O
costs makes it much less critical for most regulators.

Only hardware interactions are currently traced as the primary focus is
on the performance and synchronisation of actual hardware interactions.
Additional tracepoints for debugging of the logical operations can be
added later if required.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: Liam Girdwood <lrg@slimlogic.co.uk>
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 67d3a61..8a5d0ae 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -25,6 +25,9 @@
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/regulator.h>
+
 #include "dummy.h"
 
 #define REGULATOR_VERSION "0.5"
@@ -1310,6 +1313,8 @@
 				delay = 0;
 			}
 
+			trace_regulator_enable(rdev_get_name(rdev));
+
 			/* Allow the regulator to ramp; it would be useful
 			 * to extend this for bulk operations so that the
 			 * regulators can ramp together.  */
@@ -1317,6 +1322,8 @@
 			if (ret < 0)
 				return ret;
 
+			trace_regulator_enable_delay(rdev_get_name(rdev));
+
 			if (delay >= 1000) {
 				mdelay(delay / 1000);
 				udelay(delay % 1000);
@@ -1324,6 +1331,8 @@
 				udelay(delay);
 			}
 
+			trace_regulator_enable_complete(rdev_get_name(rdev));
+
 		} else if (ret < 0) {
 			printk(KERN_ERR "%s: is_enabled() failed for %s: %d\n",
 			       __func__, rdev_get_name(rdev), ret);
@@ -1379,6 +1388,8 @@
 		/* we are last user */
 		if (_regulator_can_change_status(rdev) &&
 		    rdev->desc->ops->disable) {
+			trace_regulator_disable(rdev_get_name(rdev));
+
 			ret = rdev->desc->ops->disable(rdev);
 			if (ret < 0) {
 				printk(KERN_ERR "%s: failed to disable %s\n",
@@ -1386,6 +1397,8 @@
 				return ret;
 			}
 
+			trace_regulator_disable_complete(rdev_get_name(rdev));
+
 			_notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE,
 					     NULL);
 		}
@@ -1645,6 +1658,8 @@
 	regulator->min_uV = min_uV;
 	regulator->max_uV = max_uV;
 
+	trace_regulator_set_voltage(rdev_get_name(rdev), min_uV, max_uV);
+
 	ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV, &selector);
 
 	if (rdev->desc->ops->list_voltage)
@@ -1652,6 +1667,8 @@
 	else
 		selector = -1;
 
+	trace_regulator_set_voltage_complete(rdev_get_name(rdev), selector);
+
 out:
 	_notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE, NULL);
 	mutex_unlock(&rdev->mutex);