Merge branch 'debian'
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..217aabb
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,46 @@
+#
+# NOTE! Don't add files that are generated in specific
+# subdirectories here. Add them in the ".gitignore" file
+# in that subdirectory instead.
+#
+# NOTE! Please use 'git ls-files -i --exclude-standard'
+# command after changing this file, to see if there are
+# any tracked files which get ignored after the change.
+#
+# Normal rules
+#
+.*
+*.o
+*.o.*
+*.a
+*.s
+*.patch
+
+#
+# Top-level generic files
+#
+/tags
+/TAGS
+
+#
+# git files that we don't want to ignore even it they are dot-files
+#
+!.gitignore
+
+# quilt's files
+patches
+series
+
+# cscope files
+cscope.*
+ncscope.*
+
+# gnu global files
+GPATH
+GRTAGS
+GSYMS
+GTAGS
+
+*.orig
+*~
+\#*#
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..36c73cd
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,34 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_SHARED_LIBRARIES := libstlport
+
+LOCAL_STATIC_LIBRARIES := libncurses
+
+LOCAL_MODULE := powerdebug
+
+LOCAL_CPPFLAGS += \
+		-DDISABLE_I18N \
+		-DDISABLE_TRYCATCH \
+		-DNCURSES_NOMACROS \
+		-DDISABLE_WSTRING \
+		-DDEFAULT_TERM=\"xterm\" \
+		-DTERMINFO_PATH=\"/system/etc/terminfo\" \
+		-DDEFINE_ETHTOOL_CMD \
+
+LOCAL_C_INCLUDES += external/stlport/stlport/ \
+					external/stlport/stlport/stl \
+					external/stlport/stlport/using/h/ \
+					bionic \
+					external/ncurses \
+					external/ncurses/lib \
+					external/ncurses/include \
+					external/ncurses/include/ncurses
+
+LOCAL_SRC_FILES += \
+	powerdebug.c sensor.c clocks.c regulator.c \
+	display.c tree.c utils.c mainloop.c gpio.c
+
+include $(BUILD_EXECUTABLE)
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..be6f09f
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,221 @@
+Copyright (C) 2010 Linaro Ltd.
+
+License: EPL-1.0
+ Eclipse Public License - v 1.0
+ 
+ THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE
+ PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE
+ PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
+ 
+ 1. DEFINITIONS
+ 
+ "Contribution" means:
+ 
+ a) in the case of the initial Contributor, the initial code and documentation
+ distributed under this Agreement, and
+ b) in the case of each subsequent Contributor:
+ 
+ i) changes to the Program, and
+ 
+ ii) additions to the Program;
+ 
+ where such changes and/or additions to the Program originate from and are
+ distributed by that particular Contributor. A Contribution 'originates'
+ from a Contributor if it was added to the Program by such Contributor itself
+ or anyone acting on such Contributor's behalf. Contributions do not include
+ additions to the Program which: (i) are separate modules of software
+ distributed in conjunction with the Program under their own license
+ agreement, and (ii) are not derivative works of the Program.
+ 
+ "Contributor" means any person or entity that distributes the Program.
+ 
+ "Licensed Patents " mean patent claims licensable by a Contributor which are
+ necessarily infringed by the use or sale of its Contribution alone or when
+ combined with the Program.
+ 
+ "Program" means the Contributions distributed in accordance with this
+ Agreement.
+ 
+ "Recipient" means anyone who receives the Program under this Agreement,
+ including all Contributors.
+ 
+ 2. GRANT OF RIGHTS
+ 
+ a) Subject to the terms of this Agreement, each Contributor hereby grants
+ Recipient a non-exclusive, worldwide, royalty-free copyright license to
+ reproduce, prepare derivative works of, publicly display, publicly perform,
+ distribute and sublicense the Contribution of such Contributor, if any,
+ and such derivative works, in source code and object code form.
+ 
+ b) Subject to the terms of this Agreement, each Contributor hereby grants
+ Recipient a non-exclusive, worldwide, royalty-free patent license under
+ Licensed Patents to make, use, sell, offer to sell, import and otherwise
+ transfer the Contribution of such Contributor, if any, in source code and
+ object code form. This patent license shall apply to the combination of
+ the Contribution and the Program if, at the time the Contribution is added
+ by the Contributor, such addition of the Contribution causes such
+ combination to be covered by the Licensed Patents. The patent license shall
+ not apply to any other combinations which include the Contribution. No
+ hardware per se is licensed hereunder.
+ 
+ c) Recipient understands that although each Contributor grants the licenses
+ to its Contributions set forth herein, no assurances are provided by any
+ Contributor that the Program does not infringe the patent or other
+ intellectual property rights of any other entity. Each Contributor disclaims
+ any liability to Recipient for claims brought by any other entity based on
+ infringement of intellectual property rights or otherwise. As a condition to
+ exercising the rights and licenses granted hereunder, each Recipient hereby
+ assumes sole responsibility to secure any other intellectual property rights
+ needed, if any. For example, if a third party patent license is required to
+ allow Recipient to distribute the Program, it is Recipient's responsibility
+ to acquire that license before distributing the Program.
+ 
+ d) Each Contributor represents that to its knowledge it has sufficient
+ copyright rights in its Contribution, if any, to grant the copyright license
+ set forth in this Agreement.
+ 
+ 3. REQUIREMENTS
+ 
+ A Contributor may choose to distribute the Program in object code form under
+ its own license agreement, provided that:
+ 
+ a) it complies with the terms and conditions of this Agreement; and
+ 
+ b) its license agreement:
+ 
+ i) effectively disclaims on behalf of all Contributors all warranties and
+ conditions, express and implied, including warranties or conditions of title
+ and non-infringement, and implied warranties or conditions of merchantability
+ and fitness for a particular purpose;
+ 
+ ii) effectively excludes on behalf of all Contributors all liability for
+ damages, including direct, indirect, special, incidental and consequential
+ damages, such as lost profits;
+ 
+ iii) states that any provisions which differ from this Agreement are offered
+ by that Contributor alone and not by any other party; and
+ 
+ iv) states that source code for the Program is available from such
+ Contributor, and informs licensees how to obtain it in a reasonable manner on
+ or through a medium customarily used for software exchange.
+ 
+ When the Program is made available in source code form:
+ 
+ a) it must be made available under this Agreement; and
+ 
+ b) a copy of this Agreement must be included with each copy of the Program.
+ 
+ Contributors may not remove or alter any copyright notices contained within
+ the Program.
+ 
+ Each Contributor must identify itself as the originator of its Contribution,
+ if any, in a manner that reasonably allows subsequent Recipients to identify
+ the originator of the Contribution.
+ 
+ 4. COMMERCIAL DISTRIBUTION
+ 
+ Commercial distributors of software may accept certain responsibilities with
+ respect to end users, business partners and the like. While this license is
+ intended to facilitate the commercial use of the Program, the Contributor who
+ includes the Program in a commercial product offering should do so in a
+manner
+ which does not create potential liability for other Contributors. Therefore,
+ if a Contributor includes the Program in a commercial product offering, such
+ Contributor ("Commercial Contributor") hereby agrees to defend and indemnify
+ every other Contributor ("Indemnified Contributor") against any losses,
+ damages and costs (collectively "Losses") arising from claims, lawsuits and
+ other legal actions brought by a third party against the Indemnified
+ Contributor to the extent caused by the acts or omissions of such Commercial
+ Contributor in connection with its distribution of the Program in a
+commercial
+ product offering. The obligations in this section do not apply to any claims
+ or Losses relating to any actual or alleged intellectual property
+ infringement. In order to qualify, an Indemnified Contributor must:
+ a) promptly notify the Commercial Contributor in writing of such claim, and
+ b) allow the Commercial Contributor to control, and cooperate with the
+ Commercial Contributor in, the defense and any related settlement
+ negotiations. The Indemnified Contributor may participate in any such claim
+ at its own expense.
+ 
+ For example, a Contributor might include the Program in a commercial product
+ offering, Product X. That Contributor is then a Commercial Contributor. If
+ that Commercial Contributor then makes performance claims, or offers
+ warranties related to Product X, those performance claims and warranties are
+ such Commercial Contributor's responsibility alone. Under this section, the
+ Commercial Contributor would have to defend claims against the other
+ Contributors related to those performance claims and warranties, and if a
+ court requires any other Contributor to pay any damages as a result, the
+ Commercial Contributor must pay those damages.
+ 
+ 5. NO WARRANTY
+ 
+ EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON
+ AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER
+ EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR
+ CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A
+ PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the
+ appropriateness of using and distributing the Program and assumes all
+ risks associated with its exercise of rights under this Agreement ,
+ including but not limited to the risks and costs of program errors,
+ compliance with applicable laws, damage to or loss of data, programs or
+ equipment, and unavailability or interruption of operations.
+ 
+ 6. DISCLAIMER OF LIABILITY
+ 
+ EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY
+ CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION
+ LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE
+ EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGES.
+ 
+ 7. GENERAL
+ 
+ If any provision of this Agreement is invalid or unenforceable under
+ applicable law, it shall not affect the validity or enforceability of the
+ remainder of the terms of this Agreement, and without further action by
+ the parties hereto, such provision shall be reformed to the minimum extent
+ necessary to make such provision valid and enforceable.
+ 
+ If Recipient institutes patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Program itself
+ (excluding combinations of the Program with other software or hardware)
+ infringes such Recipient's patent(s), then such Recipient's rights granted
+ under Section 2(b) shall terminate as of the date such litigation is filed.
+ 
+ All Recipient's rights under this Agreement shall terminate if it fails to
+ comply with any of the material terms or conditions of this Agreement and
+ does not cure such failure in a reasonable period of time after becoming
+ aware of such noncompliance. If all Recipient's rights under this Agreement
+ terminate, Recipient agrees to cease use and distribution of the Program as
+ soon as reasonably practicable. However, Recipient's obligations under this
+ Agreement and any licenses granted by Recipient relating to the Program
+ shall continue and survive.
+ 
+ Everyone is permitted to copy and distribute copies of this Agreement, but
+ in order to avoid inconsistency the Agreement is copyrighted and may only
+ be modified in the following manner. The Agreement Steward reserves the
+ right to publish new versions (including revisions) of this Agreement from
+ time to time. No one other than the Agreement Steward has the right to
+ modify this Agreement. The Eclipse Foundation is the initial Agreement
+ Steward. The Eclipse Foundation may assign the responsibility to serve as
+ the Agreement Steward to a suitable separate entity. Each new version of
+ the Agreement will be given a distinguishing version number. The Program
+ (including Contributions) may always be distributed subject to the version
+ of the Agreement under which it was received. In addition, after a new
+ version of the Agreement is published, Contributor may elect to distribute
+ the Program (including its Contributions) under the new version. Except as
+ expressly stated in Sections 2(a) and 2(b) above, Recipient receives no
+ rights or licenses to the intellectual property of any Contributor under
+ this Agreement, whether expressly, by implication, estoppel or otherwise.
+ All rights in the Program not expressly granted under this Agreement are
+ reserved.
+ 
+ This Agreement is governed by the laws of the State of New York and the
+ intellectual property laws of the United States of America. No party to
+ this Agreement will bring a legal action under this Agreement more than
+ one year after the cause of action arose. Each party waives its rights to
+ a jury trial in any resulting litigation.
+
diff --git a/Makefile b/Makefile
index 0ac486d..2da9d67 100644
--- a/Makefile
+++ b/Makefile
@@ -1,11 +1,11 @@
 BINDIR=/usr/sbin
 MANDIR=/usr/share/man/man8
 
-WARNFLAGS=-Wall -Wshadow -W -Wformat -Wimplicit-function-declaration -Wimplicit-int
-CFLAGS?=-O1 -g ${WARNFLAGS}
+CFLAGS?=-O1 -g -Wall -Wshadow
 CC?=gcc
 
-OBJS = powerdebug.o sensor.o clocks.o regulator.o display.o
+OBJS = powerdebug.o sensor.o clocks.o regulator.o gpio.o \
+	display.o tree.o utils.o mainloop.o
 
 default: powerdebug
 
@@ -23,4 +23,4 @@
 all: powerdebug powerdebug.8.gz
 
 clean:
-	rm -f powerdebug *.o powerdebug.8.gz
+	rm -f powerdebug ${OBJS} powerdebug.8.gz
diff --git a/README b/README
index fa997f6..3bf1659 100644
--- a/README
+++ b/README
@@ -7,4 +7,10 @@
 Current version only displays regulator information and clock tree from
 debugfs. Support will be added for sensors later.
 
- -- Amit Arora <amit.arora@linaro.org>  Fri, 08 Sep 2010 
+ -- Amit Arora <amit.arora@linaro.org>  Fri, 08 Sep 2010
+
+Now we add gpio-change function for power consumption need.
+When gpio is not in interrupt mode. use 'D' key to change gpio direction.
+And when gpio direction is "out", use 'V' key to change gpio value.
+
+ -- Shaojie Sun <shaojie.sun@linaro.org> Mon, 29 Jul 2013
diff --git a/clocks.c b/clocks.c
index 9a76c19..95acf57 100644
--- a/clocks.c
+++ b/clocks.c
@@ -11,565 +11,438 @@
  * Contributors:
  *     Amit Arora <amit.arora@linaro.org> (IBM Corporation)
  *       - initial API and implementation
+ *
+ *     Daniel Lezcano <daniel.lezcano@linaro.org> (IBM Corporation)
+ *       - Rewrote code and API
+ *
  *******************************************************************************/
 
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#include <stdio.h>
+#undef _GNU_SOURCE
+#endif
+#include <string.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <mntent.h>
+#include <sys/stat.h>
+
 #include "powerdebug.h"
+#include "display.h"
 #include "clocks.h"
+#include "tree.h"
+#include "utils.h"
 
-static char clk_dir_path[PATH_MAX];
-static char clk_name[NAME_MAX];
-static int  bold[MAX_LINES];
+struct clock_info {
+	int flags;
+	int rate;
+	int usecount;
+	bool expanded;
+	char *prefix;
+	int preparecount;
+	int enablecount;
+	int notifiercount;
+} *clocks_info;
 
-int init_clock_details(void)
+enum clock_fw_type{
+	CCF,	/* common clock framework */
+	OCF,	/* old clock framework */
+	MAX,
+};
+
+static struct tree *clock_tree = NULL;
+static int clock_fw;
+
+static int locate_debugfs(char *clk_path)
 {
-	char *path = debugfs_locate_mpoint();
-	struct stat buf;
-
-	if (path)
-		strcpy(clk_dir_path, path);
-	else {
-		if (!dump) {
-			create_selectedwindow();
-			sprintf(clock_lines[0], "Unable to locate debugfs "
-				"mount point. Mount debugfs "
-				"and try again..\n");
-			print_one_clock(0, clock_lines[0], 1, 0);
-			old_clock_line_no = 1;
-			return(1);
-		} else {
-			fprintf(stderr, "powerdebug: Unable to locate debugfs "
-				"mount point. Mount debugfs and try "
-				"again..\n");
-			exit(1);
-		}
-	}
-	sprintf(clk_dir_path, "%s/clock", clk_dir_path);
-	//strcpy(clk_dir_path, "/debug/clock"); // Hardcoded for testing..
-	if (stat(clk_dir_path, &buf)) {
-		if (!dump) {
-			create_selectedwindow();
-			sprintf(clock_lines[0], "Unable to find clock tree"
-				" information at %s.\n", clk_dir_path);
-			print_one_clock(0, clock_lines[0], 1, 0);
-			old_clock_line_no = 1;
-			return(1);
-		} else {
-			fprintf(stderr, "powerdebug: Unable to find clock tree"
-				" information at %s.\n", clk_dir_path);
-			exit(1);
-		}
-	}
-	strcpy(clk_name, "");
-	return(0);
+	strcpy(clk_path, "/sys/kernel/debug");
+	return 0;
 }
 
-int get_int_from(char *file)
+static struct clock_info *clock_alloc(void)
 {
-	FILE *filep;
-	char result[NAME_MAX];
-	int ret;
+	struct clock_info *ci;
 
-	filep = fopen(file, "r");
+	ci = malloc(sizeof(*ci));
+	if (ci)
+		memset(ci, 0, sizeof(*ci));
 
-	if (!filep)
-		return -1;  //TBD : What should we return on failure, here ?
-
-	ret = fscanf(filep, "%s", result);
-	fclose(filep);
-
-	return atoi(result);
+	return ci;
 }
 
-void find_parents_for_clock(char *clkname, int complete)
+static inline const char *clock_rate(int *rate)
 {
-	char name[256];
+        int r;
 
-	name[0] = '\0';
-	if (!complete) {
-		char str[256];
+        /* GHZ */
+        r = *rate >> 30;
+        if (r) {
+                *rate = r;
+                return "GHZ";
+        }
 
-		strcat(name, clkname);
-		sprintf(str, "Enter Clock Name : %s\n", name);
-		print_one_clock(2, str, 1, 0);
-		return;
-	}
-	sprintf(name, "Parents for \"%s\" Clock : \n", clkname);
-	print_one_clock(0, name, 1, 1);
-	dump_all_parents(clkname);
+        /* MHZ */
+        r = *rate >> 20;
+        if (r) {
+                *rate = r;
+                return "MHZ";
+        }
+
+        /* KHZ */
+        r = *rate >> 10;
+        if (r) {
+                *rate = r;
+                return "KHZ";
+        }
+
+        return "";
 }
 
-int read_and_print_clock_info(int verbose, int hrow, int selected)
+static int dump_clock_cb(struct tree *t, void *data)
 {
-	print_one_clock(0, "Reading Clock Tree ...", 1, 1);
+	struct clock_info *clk = t->private;
+	struct clock_info *pclk;
+	const char *unit;
+	int ret = 0;
+	int rate = clk->rate;
 
-	if (!old_clock_line_no || selected == REFRESH_WINDOW) {
-		destroy_clocks_info();
-		read_clock_info(clk_dir_path);
+	if (!t->parent) {
+		printf("/\n");
+		clk->prefix = "";
+		return 0;
 	}
 
-	if (!clocks_info->num_children) {
-		fprintf(stderr, "powerdebug: No clocks found. Exiting..\n");
-		exit(1);
-	}
+	pclk = t->parent->private;
 
-	if (selected == CLOCK_SELECTED)
-		selected = 1;
-	else
-		selected = 0;
+	if (!clk->prefix)
+		ret = asprintf(&clk->prefix, "%s%s%s", pclk->prefix,
+			       t->depth > 1 ? "   ": "", t->next ? "|" : " ");
+	if (ret < 0)
+		return -1;
 
-	print_clock_info(verbose, hrow, selected);
-	hrow = (hrow < old_clock_line_no) ? hrow : old_clock_line_no - 1;
+	unit = clock_rate(&rate);
 
-	return hrow;
-}
-
-int calc_delta_screen_size(int hrow)
-{
-	if (hrow >= (maxy - 3))
-		return hrow - (maxy - 4);
+	printf("%s%s-- %s (flags:0x%x, usecount:%d, rate: %d %s)\n",
+	       clk->prefix,  !t->next ? "`" : "", t->name, clk->flags,
+	       clk->usecount, rate, unit);
 
 	return 0;
 }
 
-void print_clock_info(int verbose, int hrow, int selected)
+int dump_clock_info(void)
 {
-	int i, count = 0, delta;
+	return tree_for_each(clock_tree, dump_clock_cb, NULL);
+}
 
-	(void)verbose;
+static int dump_all_parents(char *clkarg)
+{
+	struct tree *tree;
 
-	print_clock_header();
-
-	for (i = 0; i < clocks_info->num_children; i++)
-		add_clock_details_recur(clocks_info->children[i],
-					hrow, selected);
-
-	delta = calc_delta_screen_size(hrow);
-
-	while (clock_lines[count + delta] &&
-		strcmp(clock_lines[count + delta], "")) {
-		if (count < delta) {
-			count++;
-			continue;
-		}
-		print_one_clock(count - delta, clock_lines[count + delta],
-				bold[count + delta], (hrow == (count + delta)));
-		count++;
+	tree = tree_find(clock_tree, clkarg);
+	if (!tree) {
+		printf("Clock NOT found!\n");
+		return -1;
 	}
 
-	old_clock_line_no = clock_line_no;
-	clock_line_no = 0;
+	return tree_for_each_parent(tree, dump_clock_cb, NULL);
 }
 
-void prepare_name_str(char *namestr, struct clock_info *clock)
+static inline int read_clock_cb(struct tree *t, void *data)
 {
-	int i;
+	struct clock_info *clk = t->private;
 
-	strcpy(namestr, "");
-	if (clock->level > 1)
-		for (i = 0; i < (clock->level - 1); i++)
-			strcat(namestr, "  ");
-	strcat(namestr, clock->name);
-}
-
-void add_clock_details_recur(struct clock_info *clock, int hrow, int selected)
-{
-	int i;
-	char *unit = " Hz";
-	char rate_str[64];
-	char name_str[256];
-	double drate = (double)clock->rate;
-
-	if (drate > 1000 && drate < 1000000) {
-		unit = "KHz";
-		drate /= 1000;
+	if(clock_fw == CCF) {
+		file_read_value(t->path, "clk_flags", "%x", &clk->flags);
+		file_read_value(t->path, "clk_rate", "%d", &clk->rate);
+		file_read_value(t->path, "clk_prepare_count", "%d", &clk->preparecount);
+		file_read_value(t->path, "clk_enable_count", "%d", &clk->enablecount);
+		file_read_value(t->path, "clk_notifier_count", "%d", &clk->notifiercount);
 	}
-	if (drate > 1000000) {
-		unit = "MHz";
-		drate /= 1000000;
-	}
-	if (clock->usecount)
-		bold[clock_line_no] = 1;
-	else
-		bold[clock_line_no] = 0;
-
-	sprintf(rate_str, "%.2f %s", drate, unit);
-	prepare_name_str(name_str, clock);
-	sprintf(clock_lines[clock_line_no++], "%-55s %-4d  %-12s %-12d %-12d",
-		name_str, clock->flags, rate_str, clock->usecount,
-		clock->num_children);
-
-	if (selected && (hrow == (clock_line_no - 1))) {
-		if (clock->expanded)
-			collapse_all_subclocks(clock);
-		else
-			clock->expanded = 1;
-		selected = 0;
+	else {
+		file_read_value(t->path, "flags", "%x", &clk->flags);
+		file_read_value(t->path, "rate", "%d", &clk->rate);
+		file_read_value(t->path, "usecount", "%d", &clk->usecount);
 	}
 
-	if (clock->expanded && clock->num_children)
-		for (i = 0; i < clock->num_children; i++)
-			add_clock_details_recur(clock->children[i],
-						hrow, selected);
-	strcpy(clock_lines[clock_line_no], "");
+	return 0;
 }
 
-void collapse_all_subclocks(struct clock_info *clock)
+static int read_clock_info(struct tree *tree)
 {
-	int i;
-
-	clock->expanded = 0;
-	if (clock->num_children)
-		for (i = 0; i < clock->num_children; i++)
-			collapse_all_subclocks(clock->children[i]);
+	return tree_for_each(tree, read_clock_cb, NULL);
 }
 
-void destroy_clocks_info(void)
-{
-	int i;
-
-	if (!clocks_info)
-		return;
-
-	if (clocks_info->num_children) {
-		for (i = (clocks_info->num_children - 1); i >= 0 ; i--) {
-			destroy_clocks_info_recur(clocks_info->children[i]);
-			if (!i) {
-				free(clocks_info->children);
-				clocks_info->children = NULL;
-			}
-		}
-	}
-	clocks_info->num_children = 0;
-	free(clocks_info);
-	clocks_info = NULL;
-}
-
-void destroy_clocks_info_recur(struct clock_info *clock)
-{
-	int i;
-
-	if (clock && clock->num_children) {
-		for (i = (clock->num_children - 1); i >= 0; i--) {
-			fflush(stdin);
-			destroy_clocks_info_recur(clock->children[i]);
-			if (!i) {
-				free(clock->children);
-				clock->children = NULL;
-				clock->num_children = 0;
-			}
-		}
-	}
-}
-
-void read_and_dump_clock_info_one(char *clk)
-{
-	printf("\nParents for \"%s\" Clock :\n\n", clk);
-	read_clock_info(clk_dir_path);
-	dump_all_parents(clk);
-	printf("\n\n");
-}
-
-void read_and_dump_clock_info(int verbose)
-{
-	(void)verbose;
-	printf("\nClock Tree :\n");
-	printf("**********\n");
-	read_clock_info(clk_dir_path);
-	dump_clock_info(clocks_info, 1, 1);
-	printf("\n\n");
-}
-
-void read_clock_info(char *clkpath)
-{
-	DIR *dir;
-	struct dirent *item;
-	char filename[NAME_MAX], clockname[NAME_MAX];
-	struct clock_info *child;
-	struct clock_info *cur;
-
-	dir = opendir(clkpath);
-	if (!dir)
-		return;
-
-	clocks_info = (struct clock_info *)malloc(sizeof(struct clock_info));
-	memset(clocks_info, 0, sizeof(clocks_info));
-	strcpy(clocks_info->name, "/");
-	clocks_info->level = 0;
-
-	while ((item = readdir(dir))) {
-		/* skip hidden dirs except ".." */
-		if (item->d_name[0] == '.')
-			continue;
-
-		strcpy(clockname, item->d_name);
-		sprintf(filename, "%s/%s", clkpath, item->d_name);
-		cur = (struct clock_info *)malloc(sizeof(struct clock_info));
-		memset(cur, 0, sizeof(struct clock_info));
-		strcpy(cur->name, clockname);
-		cur->parent = clocks_info;
-		cur->num_children = 0;
-		cur->expanded = 0;
-		cur->level = 1;
-		insert_children(&clocks_info, cur);
-		child = read_clock_info_recur(filename, 2, cur);
-	}
-	closedir(dir);
-}
-
-struct clock_info *read_clock_info_recur(char *clkpath, int level,
-					struct clock_info *parent)
-{
-	int ret = 0;
-	DIR *dir;
-	char filename[PATH_MAX];
-	struct dirent *item;
-	struct clock_info *cur = NULL;
-	struct stat buf;
-
-	dir = opendir(clkpath);
-	if (!dir)
-		return NULL;
-
-	while ((item = readdir(dir))) {
-		struct clock_info *child;
-		/* skip hidden dirs except ".." */
-		if (item->d_name[0] == '.' )
-			continue;
-
-		sprintf(filename, "%s/%s", clkpath, item->d_name);
-
-		ret = stat(filename, &buf);
-
-		if (ret < 0) {
-			printf("Error doing a stat on %s\n", filename);
-			exit(1);
-		}
-
-		if (S_ISREG(buf.st_mode)) {
-			if (!strcmp(item->d_name, "flags"))
-				parent->flags = get_int_from(filename);
-			if (!strcmp(item->d_name, "rate"))
-				parent->rate = get_int_from(filename);
-			if (!strcmp(item->d_name, "usecount"))
-				parent->usecount = get_int_from(filename);
-			continue;
-		}
-
-		if (!S_ISDIR(buf.st_mode))
-			continue;
-
-		cur = (struct clock_info *)malloc(sizeof(struct clock_info));
-		memset(cur, 0, sizeof(cur));
-		strcpy(cur->name, item->d_name);
-		cur->children = NULL;
-		cur->parent = NULL;
-		cur->num_children = 0;
-		cur->expanded = 0;
-		cur->level = level;
-		child = read_clock_info_recur(filename, level + 1, cur);
-		insert_children(&parent, cur);
-		cur->parent = parent;
-	}
-	closedir(dir);
-
-	return cur;
-}
-
-void insert_children(struct clock_info **parent, struct clock_info *clk)
-{
-	if (!(*parent)->num_children || (*parent)->children == NULL) {
-		(*parent)->children = (struct clock_info **)
-			malloc(sizeof(struct clock_info *)*2);
-		(*parent)->num_children = 0;
-	} else
-		(*parent)->children = (struct clock_info **)
-			realloc((*parent)->children,
-				sizeof(struct clock_info *) *
-				((*parent)->num_children + 2));
-	if ((*parent)->num_children > 0)
-		(*parent)->children[(*parent)->num_children - 1]->last_child
-			= 0;
-	clk->last_child = 1;
-	(*parent)->children[(*parent)->num_children] = clk;
-	(*parent)->children[(*parent)->num_children + 1] = NULL;
-	(*parent)->num_children++;
-}
-
-void dump_parent(struct clock_info *clk, int line)
-{
-	char *unit = "Hz";
-	double drate;
-	static char spaces[64];
-	char str[256];
-	static int maxline;
-
-	if (maxline < line)
-		maxline = line;
-
-	if (clk && clk->parent)
-		dump_parent(clk->parent, ++line);
-
- 	drate = (double)clk->rate;
-	if (drate > 1000 && drate < 1000000) {
-		unit = "KHz";
-		drate /= 1000;
-	}
-	if (drate > 1000000) {
-		unit = "MHz";
-		drate /= 1000000;
-	}
-	if (clk == clocks_info) {
-		line++;
-		strcpy(spaces, "");
-		sprintf(str, "%s%s (flags:%d,usecount:%d,rate:%5.2f %s)\n",
-			spaces, clk->name, clk->flags, clk->usecount, drate,
-			unit);
-	} else {
-		if (!(clk->parent == clocks_info))
-			strcat(spaces, "  ");
-		sprintf(str, "%s`- %s (flags:%d,usecount:%d,rate:%5.2f %s)\n",
-			spaces, clk->name, clk->flags, clk->usecount, drate,
-			unit);
-	}
-	if (dump)
-		//printf("line=%d:m%d:l%d %s", maxline - line + 2, maxline, line, str);
-		printf("%s", str);
-	else
-		print_one_clock(maxline - line + 2, str, 1, 0);
-}
-
-void dump_all_parents(char *clkarg)
+static int fill_clock_cb(struct tree *t, void *data)
 {
 	struct clock_info *clk;
-	char spaces[1024];
 
-	strcpy(spaces, "");
-
-	clk = find_clock(clocks_info, clkarg);
-
+	clk = clock_alloc();
 	if (!clk)
-		printf("Clock NOT found!\n");
-	else {
-//		while(clk && clk != clocks_info) {
-//			printf("%s\n", clk->name);
-//			strcat(spaces, "  ");
-//			clk = clk->parent;
-//			printf("%s <-- ", spaces);
-//		}
-//		printf("  /\n");
-		dump_parent(clk, 1);
+		return -1;
+	t->private = clk;
+
+        /* we skip the root node but we set it expanded for its children */
+	if (!t->parent) {
+		clk->expanded = true;
+		return 0;
 	}
+
+	return read_clock_cb(t, data);
 }
 
-struct clock_info *find_clock(struct clock_info *clk, char *clkarg)
+static int fill_clock_tree(void)
 {
-	int i;
-	struct clock_info *ret = clk;
-
-	if (!strcmp(clk->name, clkarg))
-		return ret;
-
-	if (clk->children) {
-		for (i = 0; i < clk->num_children; i++) {
-			if (!strcmp(clk->children[i]->name, clkarg))
-				return clk->children[i];
-		}
-		for (i = 0; i < clk->num_children; i++) {
-			ret = find_clock(clk->children[i], clkarg);
-			if (ret)
-				return ret;
-		}
-	}
-
-	return NULL;
+	return tree_for_each(clock_tree, fill_clock_cb, NULL);
 }
 
-
-void dump_clock_info(struct clock_info *clk, int level, int bmp)
+static int is_collapsed(struct tree *t, void *data)
 {
-	int i, j;
+	struct clock_info *clk = t->private;
 
-	if (!clk)
-		return;
+	if (!clk->expanded)
+		return 1;
 
-	for (i = 1, j = 0; i < level; i++, j = (i - 1)) {
-		if (i == (level - 1)) {
-			if (clk->last_child)
-				printf("`-- ");
-			else
-				printf("|-- ");
-		} else {
-			if ((1<<j) & bmp)
-				printf("|   ");
-			else
-				printf("    ");
-		}
-	}
-
-	if (clk == clocks_info)
-		printf("%s\n", clk->name);
-	else {
-		char *unit = "Hz";
-		double drate = (double)clk->rate;
-
-		if (drate > 1000 && drate < 1000000) {
-			unit = "KHz";
-			drate /= 1000;
-		}
-		if (drate > 1000000) {
-			unit = "MHz";
-			drate /= 1000000;
-		}
-		printf("%s (flags:%d,usecount:%d,rate:%5.2f %s)\n",
-			clk->name, clk->flags, clk->usecount, drate, unit);
-	}
-	if (clk->children) {
-		int tbmp = bmp;
-		int xbmp = -1;
-
-		if (clk->last_child) {
-			xbmp ^= 1 << (level - 2);
-
-			xbmp = tbmp & xbmp;
-		} else
-			xbmp = bmp;
-		for (i = 0; i < clk->num_children; i++) {
-			tbmp = xbmp | (1 << level);
-			dump_clock_info(clk->children[i], level + 1, tbmp);
-		}
-	}
+	return 0;
 }
 
-char *debugfs_locate_mpoint(void)
+static char *clock_line(struct tree *t)
 {
-	int ret;
-	FILE *filep;
-	char **path;
-	char fsname[64];
-	struct statfs sfs;
+	struct clock_info *clk;
+	int rate;
+	const char *clkunit;
+	char *clkrate, *clkname, *clkline = NULL;
 
-	path = likely_mpoints;
-	while (*path) {
-		ret = statfs(*path, &sfs);
-		if (ret >= 0 && sfs.f_type == (long)DEBUGFS_MAGIC)
-			return *path;
-		path++;
-	}
+	clk = t->private;
+	rate = clk->rate;
+	clkunit = clock_rate(&rate);
 
-	filep = fopen("/proc/mounts", "r");
-	if (filep == NULL) {
-		fprintf(stderr, "powerdebug: Error opening /proc/mounts.");
-		exit(1);
-	}
-
-	while (fscanf(filep, "%*s %s %s %*s %*d %*d\n",
-			debugfs_mntpoint, fsname) == 2)
-		if (!strcmp(fsname, "debugfs"))
-			break;
-	fclose(filep);
-
-	if (strcmp(fsname, "debugfs"))
+	if (asprintf(&clkname, "%*s%s", (t->depth - 1) * 2, "", t->name) < 0)
 		return NULL;
 
-	return debugfs_mntpoint;
+	if (asprintf(&clkrate, "%d%s", rate, clkunit) < 0)
+		goto free_clkname;
+
+	if(clock_fw == CCF) {
+		if (asprintf(&clkline, "%-35s 0x%-8x %-12s %-10d %-11d %-15d %-14d %-10d",
+			     clkname, clk->flags, clkrate, clk->usecount, t->nrchild,
+			     clk->preparecount, clk->enablecount, clk->notifiercount) < 0)
+			goto free_clkrate;
+	}
+	else {
+		if (asprintf(&clkline, "%-55s 0x%-16x %-12s %-9d %-8d",
+			     clkname, clk->flags, clkrate, clk->usecount, t->nrchild) < 0)
+			goto free_clkrate;
+	}
+
+free_clkrate:
+	free(clkrate);
+free_clkname:
+	free(clkname);
+
+	return clkline;
+}
+
+static int _clock_print_info_cb(struct tree *t, void *data)
+{
+	struct clock_info *clock = t->private;
+	int *line = data;
+	char *buffer;
+
+        /* we skip the root node of the tree */
+	if (!t->parent)
+		return 0;
+
+	buffer = clock_line(t);
+	if (!buffer)
+		return -1;
+
+	display_print_line(CLOCK, *line, buffer, clock->usecount, t);
+
+	(*line)++;
+
+	free(buffer);
+
+	return 0;
+}
+
+static int clock_print_info_cb(struct tree *t, void *data)
+{
+        /* we skip the root node of the tree */
+	if (!t->parent)
+		return 0;
+
+        /* show the clock when *all* its parent is expanded */
+	if (tree_for_each_parent(t->parent, is_collapsed, NULL))
+		return 0;
+
+	return _clock_print_info_cb(t, data);
+}
+
+static int clock_print_header(void)
+{
+	char *buf;
+	int ret;
+
+	if(clock_fw == CCF) {
+		if (asprintf(&buf, "%-35s %-10s %-12s %-10s %-11s %-15s %-14s %-14s",
+		     "Name", "Flags", "Rate", "Usecount", "Children", "Prepare_Count",
+		     "Enable_Count", "Notifier_Count") < 0)
+		return -1;
+	}
+	else {
+		if (asprintf(&buf, "%-55s %-16s %-12s %-9s %-8s",
+		     "Name", "Flags", "Rate", "Usecount", "Children") < 0)
+		return -1;
+	}
+
+	ret = display_column_name(buf);
+
+	free(buf);
+
+	return ret;
+}
+
+static int clock_print_info(struct tree *tree)
+{
+	int ret, line = 0;
+
+	display_reset_cursor(CLOCK);
+
+	clock_print_header();
+
+	ret = tree_for_each(tree, clock_print_info_cb, &line);
+
+	display_refresh_pad(CLOCK);
+
+	return ret;
+}
+
+static int clock_select(void)
+{
+	struct tree *t = display_get_row_data(CLOCK);
+	struct clock_info *clk = t->private;
+
+	clk->expanded = !clk->expanded;
+
+	return 0;
+}
+
+/*
+ * Read the clock information and fill the tree with the information
+ * found in the files. Then print the result to the text based interface
+ * Return 0 on success, < 0 otherwise
+ */
+static int clock_display(bool refresh)
+{
+	if (refresh && read_clock_info(clock_tree))
+		return -1;
+
+	return clock_print_info(clock_tree);
+}
+
+static int clock_find(const char *name)
+{
+	struct tree **ptree = NULL;
+	int i, nr, line = 0, ret = 0;
+
+	nr = tree_finds(clock_tree, name, &ptree);
+
+	display_reset_cursor(CLOCK);
+
+	for (i = 0; i < nr; i++) {
+
+		ret = _clock_print_info_cb(ptree[i], &line);
+		if (ret)
+			break;
+
+	}
+
+	display_refresh_pad(CLOCK);
+
+	free(ptree);
+
+	return ret;
+}
+
+static int clock_selectf(void)
+{
+	struct tree *t = display_get_row_data(CLOCK);
+	int line = 0;
+
+	display_reset_cursor(CLOCK);
+
+	if (tree_for_each_parent(t, _clock_print_info_cb, &line))
+		return -1;
+
+	return display_refresh_pad(CLOCK);
+}
+
+/*
+ * Read the clock information and fill the tree with the information
+ * found in the files. Then dump to stdout a formatted result.
+ * @clk : a name for a specific clock we want to show
+ * Return 0 on success, < 0 otherwise
+ */
+int clock_dump(char *clk)
+{
+	int ret;
+
+	if (read_clock_info(clock_tree))
+		return -1;
+
+	if (clk) {
+		printf("\nParents for \"%s\" Clock :\n\n", clk);
+		ret = dump_all_parents(clk);
+		printf("\n\n");
+	} else {
+		printf("\nClock Tree :\n");
+		printf("**********\n");
+		ret = dump_clock_info();
+		printf("\n\n");
+	}
+
+	return ret;
+}
+
+static struct display_ops clock_ops = {
+	.display = clock_display,
+	.select  = clock_select,
+	.find    = clock_find,
+	.selectf = clock_selectf,
+};
+
+/*
+ * Initialize the clock framework
+ */
+int clock_init(void)
+{
+	char clk_dir_path[MAX+1][PATH_MAX];
+
+	if (locate_debugfs(clk_dir_path[CCF]) || locate_debugfs(clk_dir_path[OCF]))
+		return -1;
+
+	sprintf(clk_dir_path[CCF], "%s/clk", clk_dir_path[CCF]);
+	sprintf(clk_dir_path[OCF], "%s/clock", clk_dir_path[OCF]);
+	if (!access(clk_dir_path[CCF], F_OK)) {
+		clock_fw = CCF;
+		strcpy(clk_dir_path[MAX],clk_dir_path[CCF]);
+	}
+	else if(!access(clk_dir_path[OCF], F_OK)) {
+		clock_fw = OCF;
+		strcpy(clk_dir_path[MAX],clk_dir_path[OCF]);
+	}
+	else
+		return -1;
+
+	clock_tree = tree_load(clk_dir_path[MAX], NULL, false);
+	if (!clock_tree)
+		return -1;
+
+	if (fill_clock_tree())
+		return -1;
+
+	return display_register(CLOCK, &clock_ops);
 }
diff --git a/clocks.h b/clocks.h
index e2be430..aa94b3b 100644
--- a/clocks.h
+++ b/clocks.h
@@ -13,44 +13,5 @@
  *       - initial API and implementation
  *******************************************************************************/
 
-#include <sys/stat.h>
-#include <sys/vfs.h>
-#include <errno.h>
-#include <sys/stat.h>
-#include <linux/magic.h>
-
-extern int maxy;
-extern int dump;
-
-#define MAX_LINES 120
-
-struct clock_info {
-	char name[NAME_MAX];
-	int flags;
-	int rate;
-	int usecount;
-	int num_children;
-	int last_child;
-	int expanded;
-	int level;
-	struct clock_info *parent;
-	struct clock_info **children;
-} *clocks_info;
-
-char debugfs_mntpoint[1024];
-char clock_lines[MAX_LINES][128];
-int  clock_line_no;
-int  old_clock_line_no;
-
-char *likely_mpoints[] = {
-	"/sys/kernel/debug",
-	"/debug",
-	NULL
-};
-
-void add_clock_details_recur(struct clock_info *clk, int hrow, int selected);
-void destroy_clocks_info(void);
-void destroy_clocks_info_recur(struct clock_info *clock);
-void collapse_all_subclocks(struct clock_info *clock);
-void dump_all_parents(char *clkarg);
-struct clock_info *find_clock(struct clock_info *clk, char *clkarg);
+extern int clock_init(void);
+extern int clock_dump(char *clk);
diff --git a/display.c b/display.c
index d3ec421..c0afe03 100644
--- a/display.c
+++ b/display.c
@@ -13,261 +13,617 @@
  *       - initial API and implementation
  *******************************************************************************/
 
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <ncurses.h>
+#include <sys/types.h>
+#include <regex.h>
 #include "powerdebug.h"
+#include "mainloop.h"
 #include "regulator.h"
 #include "display.h"
 
-#define print(w, x, y, fmt, args...) do { mvwprintw(w, y, x, fmt, ##args); } while (0)
-#define NUM_FOOTER_ITEMS 5
+enum { PT_COLOR_DEFAULT = 1,
+       PT_COLOR_HEADER_BAR,
+       PT_COLOR_ERROR,
+       PT_COLOR_RED,
+       PT_COLOR_YELLOW,
+       PT_COLOR_GREEN,
+       PT_COLOR_BRIGHT,
+       PT_COLOR_BLUE,
+};
 
 static WINDOW *header_win;
-static WINDOW *regulator_win;
-static WINDOW *clock_win;
-static WINDOW *sensor_win;
-static WINDOW *selected_win;
 static WINDOW *footer_win;
+static WINDOW *main_win;
+static int current_win;
 
-int maxx, maxy;
-char footer_items[NUM_FOOTER_ITEMS][64];
+/* Number of lines in the virtual window */
+static const int maxrows = 1024;
 
+struct rowdata {
+	int attr;
+	void *data;
+};
 
-void fini_curses(void) {
+struct windata {
+	WINDOW *pad;
+	struct display_ops *ops;
+	struct rowdata *rowdata;
+	char *name;
+	int nrdata;
+	int scrolling;
+	int cursor;
+};
+
+/* Warning this is linked with the enum { CLOCK, REGULATOR, ... } */
+struct windata windata[] = {
+	[CLOCK]     = { .name = "Clocks"     },
+	[REGULATOR] = { .name = "Regulators" },
+	[SENSOR]    = { .name = "Sensors"    },
+	[GPIO]      = { .name = "Gpio"    },
+};
+
+static void display_fini(void)
+{
 	endwin();
 }
 
-/* "all" : Kill header and footer windows too ? */
-void killall_windows(int all)
+static int display_show_header(int win)
 {
-	if (all && header_win) {
-		delwin(header_win);
-		header_win = NULL;
-	}
-	if (regulator_win) {
-		delwin(regulator_win);
-		regulator_win = NULL;
-	}
-	if (clock_win) {
-		delwin(clock_win);
-		clock_win = NULL;
-	}
-	if (sensor_win) {
-		delwin(sensor_win);
-		sensor_win = NULL;
-	}
-	if (all && footer_win) {
-		delwin(footer_win);
-		footer_win = NULL;
-	}
-}
-
-void init_curses(void)
-{
-	initscr();
-	start_color();
-	keypad(stdscr, TRUE);
-	noecho();
-	cbreak();
-	curs_set(0);
-	nonl();
-	use_default_colors();
-
-	init_pair(PT_COLOR_DEFAULT, COLOR_WHITE, COLOR_BLACK);
-	init_pair(PT_COLOR_ERROR, COLOR_BLACK, COLOR_RED);
-	init_pair(PT_COLOR_HEADER_BAR, COLOR_WHITE, COLOR_BLACK);
-	init_pair(PT_COLOR_YELLOW, COLOR_WHITE, COLOR_YELLOW);
-	init_pair(PT_COLOR_GREEN, COLOR_WHITE, COLOR_GREEN);
-	init_pair(PT_COLOR_BRIGHT, COLOR_WHITE, COLOR_BLACK);
-	init_pair(PT_COLOR_BLUE, COLOR_WHITE, COLOR_BLUE);
-	init_pair(PT_COLOR_RED, COLOR_WHITE, COLOR_RED);
-
-	atexit(fini_curses);
-}
-
-
-void create_windows(void)
-{
-
-	getmaxyx(stdscr, maxy, maxx);
-	killall_windows(1);
-
-	header_win = subwin(stdscr, 1, maxx, 0, 0);
-	footer_win = subwin(stdscr, 1, maxx, maxy-1, 0);
-
-	strcpy(footer_items[0], " Q (Quit) ");
-	strcpy(footer_items[1], " R (Refresh) ");
-
-	if (selectedwindow == CLOCK)
-		strcpy(footer_items[2], " Other Keys: 'Left', 'Right', 'Up', 'Down', 'enter', "
-			" '/', 'Esc' ");
-	else
-		strcpy(footer_items[2], " Other Keys: 'Left', 'Right' ");
-
-	strcpy(footer_items[3], "");
-
-	werase(stdscr);
-	refresh();
-
-}
-
-void create_selectedwindow(void)
-{
-	WINDOW *win;
-
-	killall_windows(0);
-
-	getmaxyx(stdscr, maxy, maxx);
-
-	win = subwin(stdscr, maxy - 2, maxx, 1, 0);
-
-	switch (selectedwindow) {
-	case REGULATOR: regulator_win = win;
-		break;
-
-	case CLOCK:     clock_win = win;
-		break;
-
-	case SENSOR:    sensor_win = win;
-		break;
-	}
-
-	selected_win = win;
-
-	refresh();
-}
-
-void show_header(void)
-{
-	int i, j = 0;
+	int i;
 	int curr_pointer = 0;
+	size_t array_size = sizeof(windata) / sizeof(windata[0]);
 
 	wattrset(header_win, COLOR_PAIR(PT_COLOR_HEADER_BAR));
 	wbkgd(header_win, COLOR_PAIR(PT_COLOR_HEADER_BAR));
 	werase(header_win);
 
-	print(header_win, curr_pointer, 0, "PowerDebug %s", VERSION);
+	mvwprintw(header_win, 0, curr_pointer, "PowerDebug %s", VERSION);
 	curr_pointer += 20;
 
-	for (i = 0; i < TOTAL_FEATURE_WINS; i++) {
-		if (selectedwindow == i)
+	for (i = 0; i < array_size; i++) {
+		if (win == i)
 			wattron(header_win, A_REVERSE);
 		else
 			wattroff(header_win, A_REVERSE);
 
-		print(header_win, curr_pointer, 0, " %s ", win_names[i]);
-		curr_pointer += strlen(win_names[i]) + 2;
+		mvwprintw(header_win, 0, curr_pointer, " %s ", windata[i].name);
+		curr_pointer += strlen(windata[i].name) + 2;
 	}
 	wrefresh(header_win);
+
+	return 0;
+}
+
+#define footer_label " Q (Quit)  R (Refresh) Other Keys: 'Left', " \
+	"'Right' , 'Up', 'Down', 'enter', , 'Esc'"
+
+static int display_show_footer(int win, char *string)
+{
 	werase(footer_win);
-
-	for (i = 0; i < NUM_FOOTER_ITEMS; i++) {
-		if (strlen(footer_items[i]) == 0)
-			continue;
-		wattron(footer_win, A_REVERSE);
-		print(footer_win, j, 0, "%s", footer_items[i]);
-		wattroff(footer_win, A_REVERSE);
-		j+= strlen(footer_items[i])+1;
-	}
+	wattron(footer_win, A_REVERSE);
+	mvwprintw(footer_win, 0, 0, "%s", string ? string : footer_label);
+	wattroff(footer_win, A_REVERSE);
 	wrefresh(footer_win);
+
+	return 0;
 }
 
-
-void show_regulator_info(int verbose)
+static int display_refresh(int win, bool read)
 {
-	int i, count = 1;
+	/* we are trying to refresh a window which is not showed */
+	if (win != current_win)
+		return 0;
 
-	(void)verbose;
+	if (windata[win].ops && windata[win].ops->display)
+		return windata[win].ops->display(read);
 
-	werase(regulator_win);
-	wattron(regulator_win, A_BOLD);
-	print(regulator_win, 0, 0, "Name");
-	print(regulator_win, 12, 0, "Status");
-	print(regulator_win, 24, 0, "State");
-	print(regulator_win, 36, 0, "Type");
-	print(regulator_win, 48, 0, "Users");
-	print(regulator_win, 60, 0, "Microvolts");
-	print(regulator_win, 72, 0, "Min u-volts");
-	print(regulator_win, 84, 0, "Max u-volts");
-	wattroff(regulator_win, A_BOLD);
+	if (werase(main_win))
+		return -1;
 
-	for (i = 0; i < numregulators; i++) {
-		int col = 0;
+	return wrefresh(main_win);
+}
 
-		if ((i + 2) > (maxy-2))
-			break;
+int display_refresh_pad(int win)
+{
+	int maxx, maxy;
 
-		if (regulators_info[i].num_users > 0)
-			wattron(regulator_win, WA_BOLD);
-		else
-			wattroff(regulator_win, WA_BOLD);
+	getmaxyx(stdscr, maxy, maxx);
 
-		print(regulator_win, col, count, "%s",
-			regulators_info[i].name);
-		col += 12;
-		print(regulator_win, col, count, "%s",
-			regulators_info[i].status);
-		col += 12;
-		print(regulator_win, col, count, "%s",
-			regulators_info[i].state);
-		col += 12;
-		print(regulator_win, col, count, "%s",
-			regulators_info[i].type);
-		col += 12;
-		print(regulator_win, col, count, "%d",
-			regulators_info[i].num_users);
-		col += 12;
-		print(regulator_win, col, count, "%d",
-			regulators_info[i].microvolts);
-		col += 12;
-		print(regulator_win, col, count, "%d",
-			regulators_info[i].min_microvolts);
-		col += 12;
-		print(regulator_win, col, count, "%d",
-			regulators_info[i].max_microvolts);
+	return prefresh(windata[win].pad, windata[win].scrolling,
+			0, 2, 0, maxy - 2, maxx);
+}
 
-		count++;
+void sigwinch_handler(int signo)
+{
+	display_refresh(current_win, true);
+}
+
+static int display_show_unselection(int win, int line, bool bold)
+{
+	if (mvwchgat(windata[win].pad, line, 0, -1,
+		     bold ? WA_BOLD: WA_NORMAL, 0, NULL) < 0)
+		return -1;
+
+	return display_refresh_pad(win);
+}
+
+void *display_get_row_data(int win)
+{
+	return windata[win].rowdata[windata[win].cursor].data;
+}
+
+static int display_select(void)
+{
+	if (windata[current_win].ops && windata[current_win].ops->select)
+		return windata[current_win].ops->select();
+
+	return 0;
+}
+
+static int display_change(int keyvalue)
+{
+	if (!(windata[current_win].nrdata))
+		return 0;
+
+	if (windata[current_win].ops && windata[current_win].ops->change)
+		return windata[current_win].ops->change(keyvalue);
+
+	return 0;
+}
+
+static int display_next_panel(void)
+{
+	size_t array_size = sizeof(windata) / sizeof(windata[0]);
+
+	current_win++;
+	current_win %= array_size;
+
+	return current_win;
+}
+
+static int display_prev_panel(void)
+{
+	size_t array_size = sizeof(windata) / sizeof(windata[0]);
+
+	current_win--;
+	if (current_win < 0)
+		current_win = array_size - 1;
+
+	return current_win;
+}
+
+static int display_next_line(void)
+{
+	int maxx, maxy;
+	int cursor = windata[current_win].cursor;
+	int nrdata = windata[current_win].nrdata;
+	int scrolling = windata[current_win].scrolling;
+	struct rowdata *rowdata = windata[current_win].rowdata;
+
+	getmaxyx(stdscr, maxy, maxx);
+
+	if (cursor >= nrdata)
+		return cursor;
+
+	display_show_unselection(current_win, cursor, rowdata[cursor].attr);
+	if (cursor < nrdata - 1) {
+		if (cursor >= (maxy - 4 + scrolling))
+			scrolling++;
+		cursor++;
 	}
-	wrefresh(regulator_win);
+
+	windata[current_win].scrolling = scrolling;
+	windata[current_win].cursor = cursor;
+
+	return cursor;
 }
 
-
-void print_clock_header(void)
+static int display_prev_line(void)
 {
-	werase(clock_win);
-	wattron(clock_win, A_BOLD);
-	print(clock_win, 0, 0, "Name");
-	print(clock_win, 54, 0, "Flags");
-	print(clock_win, 64, 0, "Rate");
-	print(clock_win, 72, 0, "Usecount");
-	print(clock_win, 84, 0, "Children");
-	wattroff(clock_win, A_BOLD);
-	wrefresh(clock_win);
+	int cursor = windata[current_win].cursor;
+	int nrdata = windata[current_win].nrdata;
+	int scrolling = windata[current_win].scrolling;
+	struct rowdata *rowdata = windata[current_win].rowdata;
+
+	if (cursor >= nrdata)
+		return cursor;
+
+	display_show_unselection(current_win, cursor, rowdata[cursor].attr);
+	if (cursor > 0) {
+		if (cursor <= scrolling)
+			scrolling--;
+		cursor--;
+	}
+
+	windata[current_win].scrolling = scrolling;
+	windata[current_win].cursor = cursor;
+
+	return cursor;
 }
 
-void print_sensor_header(void)
+static int display_set_row_data(int win, int line, void *data, int attr)
 {
-	werase(sensor_win);
-	wattron(sensor_win, A_BOLD);
-	print(sensor_win, 0, 0, "Name");
-	print(sensor_win, 36, 0, "Temperature");
-	wattroff(sensor_win, A_BOLD);
-	wattron(sensor_win, A_BLINK);
-	print(sensor_win, 0, 1, "Currently Sensor information available"
-		" only in Dump mode!");
-	wattroff(sensor_win, A_BLINK);
-	wrefresh(sensor_win);
+	struct rowdata *rowdata =  windata[win].rowdata;
+
+	if (line >= windata[win].nrdata) {
+		rowdata = realloc(rowdata, sizeof(struct rowdata) * (line + 1));
+		if (!rowdata)
+			return -1;
+		windata[win].nrdata = line + 1;
+	}
+
+	rowdata[line].data = data;
+	rowdata[line].attr = attr;
+	windata[win].rowdata = rowdata;
+
+	return 0;
 }
 
-void print_one_clock(int line, char *str, int bold, int highlight)
+int display_reset_cursor(int win)
 {
+	windata[win].nrdata = 0;
+	werase(windata[win].pad);
+	return wmove(windata[win].pad, 0, 0);
+}
+
+int display_print_line(int win, int line, char *str, int bold, void *data)
+{
+	int attr = 0;
+
 	if (bold)
-		wattron(clock_win, WA_BOLD);
-	if (highlight)
-		wattron(clock_win, WA_STANDOUT);
+		attr |= WA_BOLD;
 
-	print(clock_win, 0, line + 1, "%s", str);
-	if (bold)
-		wattroff(clock_win, WA_BOLD);
-	if (highlight)
-		wattroff(clock_win, WA_STANDOUT);
-	wrefresh(clock_win);
+	if (line == windata[win].cursor)
+		attr |= WA_STANDOUT;
+
+	if (display_set_row_data(win, line, data, attr))
+		return -1;
+
+	if (attr)
+		wattron(windata[win].pad, attr);
+
+	wprintw(windata[win].pad, "%s\n", str);
+
+	if (attr)
+		wattroff(windata[win].pad, attr);
+
+	return 0;
+}
+
+static int display_find_keystroke(int fd, void *data);
+
+struct find_data {
+	size_t len;
+	char *string;
+	regex_t *reg;
+	int ocursor;
+	int oscrolling;
+};
+
+struct find_data *display_find_init(void)
+{
+	const char *regexp = "^[a-z|0-9|_|-|.]";
+	struct find_data *findd;
+	const size_t len = 64;
+	regex_t *reg;
+	char *search4;
+	int maxx, maxy;
+
+	getmaxyx(stdscr, maxy, maxx);
+
+	reg = malloc(sizeof(*reg));
+	if (!reg)
+		return NULL;
+
+	if (regcomp(reg, regexp, REG_ICASE))
+		goto out_free_reg;
+
+	search4 = malloc(len);
+	if (!search4)
+		goto out_free_regcomp;
+	memset(search4, '\0', len);
+
+	findd = malloc(sizeof(*findd));
+	if (!findd)
+		goto out_free_search4;
+
+	findd->string = search4;
+	findd->reg = reg;
+	findd->len = len;
+
+	/* save the location of the cursor on the main window in order to
+	 * browse the search result
+	 */
+	findd->ocursor = windata[current_win].cursor;
+	findd->oscrolling = windata[current_win].scrolling;
+
+	windata[current_win].cursor = 0;
+	windata[current_win].scrolling = 0;
+
+	curs_set(1);
+out:
+	return findd;
+
+out_free_search4:
+	free(search4);
+out_free_regcomp:
+	regfree(reg);
+out_free_reg:
+	free(reg);
+
+	goto out;
+}
+
+static void display_find_fini(struct find_data *findd)
+{
+	windata[current_win].cursor = findd->ocursor;
+	windata[current_win].scrolling = findd->oscrolling;
+	regfree(findd->reg);
+	free(findd->string);
+	free(findd);
+	curs_set(0);
+}
+
+static int display_switch_to_find(int fd)
+{
+	struct find_data *findd;
+
+	findd = display_find_init();
+	if (!findd)
+		return -1;
+
+	if (mainloop_del(fd))
+		return -1;
+
+	if (mainloop_add(fd, display_find_keystroke, findd))
+		return -1;
+
+	if (display_show_footer(current_win, "find (esc to exit)?"))
+		return -1;
+
+	return 0;
+}
+
+static int display_keystroke(int fd, void *data)
+{
+	int keystroke = getch();
+
+	switch (keystroke) {
+
+	case KEY_RIGHT:
+	case '\t':
+		display_show_header(display_next_panel());
+		break;
+
+	case KEY_LEFT:
+	case KEY_BTAB:
+		display_show_header(display_prev_panel());
+		break;
+
+	case KEY_DOWN:
+		display_next_line();
+		break;
+
+	case KEY_UP:
+		display_prev_line();
+		break;
+
+	case '\n':
+	case '\r':
+		display_select();
+		break;
+
+	case 'v':
+	case 'V':
+	case 'd':
+	case 'D':
+		display_change(toupper(keystroke));
+		break;
+
+	case EOF:
+	case 'q':
+	case 'Q':
+		return 1;
+
+	case '/':
+		return display_switch_to_find(fd);
+
+	case 'r':
+	case 'R':
+		return display_refresh(current_win, true);
+	default:
+		return 0;
+	}
+
+	display_refresh(current_win, false);
+
+	return 0;
+}
+
+static int display_switch_to_main(int fd)
+{
+	if (mainloop_del(fd))
+		return -1;
+
+	if (mainloop_add(fd, display_keystroke, NULL))
+		return -1;
+
+	if (display_show_header(current_win))
+		return -1;
+
+	if (display_show_footer(current_win, NULL))
+		return -1;
+
+	return display_refresh(current_win, false);
+}
+
+static int display_find_keystroke(int fd, void *data)
+{
+	struct find_data *findd = data;
+	regex_t *reg = findd->reg;
+	char *string = findd->string;
+	int keystroke = getch();
+	char match[2] = { [0] = (char)keystroke, [1] = '\0' };
+	regmatch_t m[1];
+
+	switch (keystroke) {
+
+	case '\e':
+		display_find_fini(findd);
+		return display_switch_to_main(fd);
+
+	case KEY_DOWN:
+		display_next_line();
+		break;
+
+	case KEY_UP:
+		display_prev_line();
+		break;
+
+	case KEY_BACKSPACE:
+		if (strlen(string))
+			string[strlen(string) - 1] = '\0';
+
+		windata[current_win].cursor = 0;
+		windata[current_win].scrolling = 0;
+
+		break;
+
+	case '\n':
+	case '\r':
+		if (!windata[current_win].ops || !windata[current_win].ops->selectf)
+			return 0;
+
+		if (windata[current_win].ops->selectf())
+			return -1;
+
+		windata[current_win].cursor = 0;
+		windata[current_win].scrolling = 0;
+
+		return 0;
+
+	default:
+
+		/* We don't want invalid characters for a name */
+		if (regexec(reg, match, 1, m, 0))
+			return 0;
+
+		if (strlen(string) < findd->len - 1)
+			string[strlen(string)] = (char)keystroke;
+
+		windata[current_win].cursor = 0;
+		windata[current_win].scrolling = 0;
+
+		break;
+	}
+
+	if (!windata[current_win].ops || !windata[current_win].ops->find)
+		return 0;
+
+	if (windata[current_win].ops->find(string))
+		return -1;
+
+	if (display_show_header(current_win))
+		return -1;
+
+	if (display_show_footer(current_win, strlen(string) ? string :
+				"find (esc to exit)?"))
+		return -1;
+
+	return 0;
+}
+
+int display_init(int wdefault)
+{
+	int i, maxx, maxy;
+	size_t array_size = sizeof(windata) / sizeof(windata[0]);
+
+	current_win = wdefault;
+
+	if (mainloop_add(0, display_keystroke, NULL))
+		return -1;
+
+	if (!initscr())
+		return -1;
+
+	start_color();
+	use_default_colors();
+
+	keypad(stdscr, TRUE);
+	noecho();
+	cbreak();
+	curs_set(0);
+	nonl();
+
+	if (init_pair(PT_COLOR_DEFAULT, COLOR_WHITE, COLOR_BLACK) ||
+	    init_pair(PT_COLOR_ERROR, COLOR_BLACK, COLOR_RED) ||
+	    init_pair(PT_COLOR_HEADER_BAR, COLOR_WHITE, COLOR_BLACK) ||
+	    init_pair(PT_COLOR_YELLOW, COLOR_WHITE, COLOR_YELLOW) ||
+	    init_pair(PT_COLOR_GREEN, COLOR_WHITE, COLOR_GREEN) ||
+	    init_pair(PT_COLOR_BRIGHT, COLOR_WHITE, COLOR_BLACK) ||
+	    init_pair(PT_COLOR_BLUE, COLOR_WHITE, COLOR_BLUE) ||
+	    init_pair(PT_COLOR_RED, COLOR_WHITE, COLOR_RED))
+		return -1;
+
+	if (atexit(display_fini))
+		return -1;
+
+	getmaxyx(stdscr, maxy, maxx);
+
+	for (i = 0; i < array_size; i++) {
+
+		main_win = subwin(stdscr, maxy - 2, maxx, 1, 0);
+		if (!main_win)
+			return -1;
+
+		windata[i].pad = newpad(maxrows, maxx);
+		if (!windata[i].pad)
+			return -1;
+
+	}
+
+	header_win = subwin(stdscr, 1, maxx, 0, 0);
+	if (!header_win)
+		return -1;
+
+	footer_win = subwin(stdscr, 1, maxx, maxy-1, 0);
+	if (!footer_win)
+		return -1;
+
+	if (display_show_header(wdefault))
+		return -1;
+
+	if (display_show_footer(wdefault, NULL))
+		return -1;
+
+	return display_refresh(wdefault, true);
+}
+
+int display_column_name(const char *line)
+{
+	werase(main_win);
+	wattron(main_win, A_BOLD);
+	mvwprintw(main_win, 0, 0, "%s", line);
+	wattroff(main_win, A_BOLD);
+	wrefresh(main_win);
+
+	return 0;
+}
+
+int display_register(int win, struct display_ops *ops)
+{
+	size_t array_size = sizeof(windata) / sizeof(windata[0]);
+
+	if (win < 0 || win >= array_size) {
+		printf("error: invalid window");
+		return -1;
+	}
+
+	windata[win].ops = ops;
+
+	return 0;
 }
diff --git a/display.h b/display.h
index f00a4f8..b28d26e 100644
--- a/display.h
+++ b/display.h
@@ -13,15 +13,25 @@
  *       - initial API and implementation
  *******************************************************************************/
 
-#define VALUE_MAX 16
+enum { CLOCK, REGULATOR, SENSOR, GPIO };
 
-WINDOW windows[TOTAL_FEATURE_WINS];
+struct display_ops {
+	int (*display)(bool refresh);
+	int (*select)(void);
+	int (*find)(const char *);
+	int (*selectf)(void);
+	int (*change)(int keyvalue);
+};
 
-#define PT_COLOR_DEFAULT    1
-#define PT_COLOR_HEADER_BAR 2
-#define PT_COLOR_ERROR      3
-#define PT_COLOR_RED        4
-#define PT_COLOR_YELLOW     5
-#define PT_COLOR_GREEN      6
-#define PT_COLOR_BRIGHT     7
-#define PT_COLOR_BLUE       8
+extern int display_print_line(int window, int line, char *str,
+			      int bold, void *data);
+
+extern int display_refresh_pad(int window);
+extern int display_reset_cursor(int window);
+extern void *display_get_row_data(int window);
+
+extern int display_init(int wdefault);
+extern int display_register(int win, struct display_ops *ops);
+extern int display_column_name(const char *line);
+
+#define NAME_MAX 255
diff --git a/doc.txt b/doc.txt
new file mode 100644
index 0000000..36ffc46
--- /dev/null
+++ b/doc.txt
@@ -0,0 +1,20 @@
+Regulator related information
+=============================
+Regulator fields "state" and "status" give below information about the regulator.
+
+- state: field tell whether regulator is enabled or disabled. Following are the states
+  |	- Enabled
+  |	- Disabled
+  |	- Unknown  (if unable to determine)
+  |
+  |
+  ----> status: When enabled, depending on the regulator hardware capability(modes) and runtime requirement; regulators are set to specific modes. The status field gives a little
+		more specific information about the current "state" of the regulator, which operating modes it is in. Following can be the possible status:
+		- Idle
+		- Fast
+		- Normal
+		- Standby
+		- Bypass
+		- Error
+		- Undefined
+		- On/Off
diff --git a/gpio.c b/gpio.c
new file mode 100644
index 0000000..84f150f
--- /dev/null
+++ b/gpio.c
@@ -0,0 +1,329 @@
+/*******************************************************************************
+ * Copyright (C) 2010, Linaro Limited.
+ *
+ * This file is part of PowerDebug.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Daniel Lezcano <daniel.lezcano@linaro.org> (IBM Corporation)
+ *       - initial API and implementation
+ *******************************************************************************/
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#include <stdio.h>
+#undef _GNU_SOURCE
+#endif
+#include <mntent.h>
+#include <string.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include "powerdebug.h"
+#include "display.h"
+#include "tree.h"
+#include "utils.h"
+
+#define SYSFS_GPIO "/sys/class/gpio"
+
+#define MAX_VALUE_BYTE	10
+
+struct gpio_info {
+	bool expanded;
+	int active_low;
+	int value;
+	char direction[MAX_VALUE_BYTE];
+	char edge[MAX_VALUE_BYTE];
+	char *prefix;
+} *gpios_info;
+
+static struct tree *gpio_tree = NULL;
+
+static struct gpio_info *gpio_alloc(void)
+{
+	struct gpio_info *gi;
+
+	gi = malloc(sizeof(*gi));
+	if (gi) {
+		memset(gi, -1, sizeof(*gi));
+		memset(gi->direction, 0, MAX_VALUE_BYTE);
+		memset(gi->edge, 0, MAX_VALUE_BYTE);
+		gi->prefix = NULL;
+	}
+
+	return gi;
+}
+
+static int gpio_filter_cb(const char *name)
+{
+	/* let's ignore some directories in order to avoid to be
+	 * pulled inside the sysfs circular symlinks mess/hell
+	 * (choose the word which fit better)
+	 */
+	if (!strcmp(name, "device"))
+		return 1;
+
+	if (!strcmp(name, "subsystem"))
+		return 1;
+
+	if (!strcmp(name, "driver"))
+		return 1;
+
+        /* we want to ignore the gpio chips */
+	if (strstr(name, "chip"))
+		return 1;
+
+        /* we are not interested by the power value */
+	if (!strcmp(name, "power"))
+		return 1;
+
+	return 0;
+}
+
+static inline int read_gpio_cb(struct tree *t, void *data)
+{
+	struct gpio_info *gpio = t->private;
+
+	file_read_value(t->path, "active_low", "%d", &gpio->active_low);
+	file_read_value(t->path, "value", "%d", &gpio->value);
+	file_read_value(t->path, "edge", "%8s", &gpio->edge);
+	file_read_value(t->path, "direction", "%4s", &gpio->direction);
+
+	return 0;
+}
+
+static int read_gpio_info(struct tree *tree)
+{
+	return tree_for_each(tree, read_gpio_cb, NULL);
+}
+
+static int fill_gpio_cb(struct tree *t, void *data)
+{
+	struct gpio_info *gpio;
+
+	gpio = gpio_alloc();
+	if (!gpio)
+		return -1;
+	t->private = gpio;
+
+        /* we skip the root node but we set it expanded for its children */
+	if (!t->parent) {
+		gpio->expanded = true;
+		return 0;
+	}
+
+	return read_gpio_cb(t, data);
+
+}
+
+static int fill_gpio_tree(void)
+{
+	return tree_for_each(gpio_tree, fill_gpio_cb, NULL);
+}
+
+static int dump_gpio_cb(struct tree *t, void *data)
+{
+	struct gpio_info *gpio = t->private;
+	struct gpio_info *pgpio;
+
+	if (!t->parent) {
+		printf("/\n");
+		gpio->prefix = "";
+		return 0;
+	}
+
+	pgpio = t->parent->private;
+
+	if (!gpio->prefix)
+		if (asprintf(&gpio->prefix, "%s%s%s", pgpio->prefix,
+			     t->depth > 1 ? "   ": "", t->next ? "|" : " ") < 0)
+			return -1;
+
+	printf("%s%s-- %s (", gpio->prefix,  !t->next ? "`" : "", t->name);
+
+	if (gpio->active_low != -1)
+		printf(" active_low:%d", gpio->active_low);
+
+	if (gpio->value != -1)
+		printf(", value:%d", gpio->value);
+
+	if (gpio->edge[0] != 0)
+		printf(", edge:%s", gpio->edge);
+
+	if (gpio->direction[0] != 0)
+		printf(", direction:%s", gpio->direction);
+
+	printf(" )\n");
+
+	return 0;
+}
+
+int dump_gpio_info(void)
+{
+	return tree_for_each(gpio_tree, dump_gpio_cb, NULL);
+}
+
+int gpio_dump(void)
+{
+	int ret;
+
+	printf("\nGpio Tree :\n");
+	printf("***********\n");
+	ret = dump_gpio_info();
+	printf("\n\n");
+
+	return ret;
+}
+
+static char *gpio_line(struct tree *t)
+{
+	struct gpio_info *gpio = t->private;
+	char *gpioline;
+
+	if (asprintf(&gpioline, "%-20s %-10d %-10d %-10s %-10s", t->name,
+		     gpio->value, gpio->active_low, gpio->edge, gpio->direction) < 0)
+		return NULL;
+
+	return gpioline;
+}
+
+static int _gpio_print_info_cb(struct tree *t, void *data)
+{
+	int *line = data;
+	char *buffer;
+
+        /* we skip the root node of the tree */
+	if (!t->parent)
+		return 0;
+
+	buffer = gpio_line(t);
+	if (!buffer)
+		return -1;
+
+	display_print_line(GPIO, *line, buffer, 0, t);
+
+	(*line)++;
+
+	free(buffer);
+
+	return 0;
+}
+
+static int gpio_print_info_cb(struct tree *t, void *data)
+{
+        /* we skip the root node of the tree */
+	if (!t->parent)
+		return 0;
+
+	return _gpio_print_info_cb(t, data);
+}
+
+static int gpio_print_header(void)
+{
+	char *buf;
+	int ret;
+
+	if (asprintf(&buf, "%-20s %-10s %-10s %-10s %-10s",
+		     "Name", "Value", "Active_low", "Edge", "Direction") < 0)
+		return -1;
+
+	ret = display_column_name(buf);
+
+	free(buf);
+
+	return ret;
+}
+
+static int gpio_print_info(struct tree *tree)
+{
+	int ret, line = 0;
+
+	display_reset_cursor(GPIO);
+
+	gpio_print_header();
+
+	ret = tree_for_each(tree, gpio_print_info_cb, &line);
+
+	display_refresh_pad(GPIO);
+
+	return ret;
+}
+
+static int gpio_display(bool refresh)
+{
+	if (refresh && read_gpio_info(gpio_tree))
+		return -1;
+
+	return gpio_print_info(gpio_tree);
+}
+
+static int gpio_change(int keyvalue)
+{
+	struct tree *t = display_get_row_data(GPIO);
+	struct gpio_info *gpio = t->private;
+
+	if (!t || !gpio)
+		return -1;
+
+	switch (keyvalue) {
+	case 'D':
+		/* Only change direction when gpio interrupt not set.*/
+		if (!strstr(gpio->edge, "none"))
+			return 0;
+
+		if (strstr(gpio->direction, "in"))
+			strcpy(gpio->direction, "out");
+		else if (strstr(gpio->direction, "out"))
+			strcpy(gpio->direction, "in");
+		file_write_value(t->path, "direction", "%s", &gpio->direction);
+		file_read_value(t->path, "direction", "%s", &gpio->direction);
+
+		break;
+
+	case 'V':
+		/* Only change value when gpio direction is out. */
+		if (!strstr(gpio->edge, "none")
+			 || !strstr(gpio->direction, "out"))
+			return 0;
+
+		if (gpio->value)
+			file_write_value(t->path, "direction", "%s", &"low");
+		else
+			file_write_value(t->path, "direction", "%s", &"high");
+		file_read_value(t->path, "value", "%d", &gpio->value);
+
+		break;
+
+	default:
+		return -1;
+	}
+
+	return 0;
+}
+
+static struct display_ops gpio_ops = {
+	.display = gpio_display,
+	.change = gpio_change,
+};
+
+/*
+ * Initialize the gpio framework
+ */
+int gpio_init(void)
+{
+	gpio_tree = tree_load(SYSFS_GPIO, gpio_filter_cb, false);
+	if (!gpio_tree)
+		return -1;
+
+	if (fill_gpio_tree())
+		return -1;
+
+	return display_register(GPIO, &gpio_ops);
+}
diff --git a/gpio.h b/gpio.h
new file mode 100644
index 0000000..38f035f
--- /dev/null
+++ b/gpio.h
@@ -0,0 +1,17 @@
+/*******************************************************************************
+ * Copyright (C) 2010, Linaro Limited.
+ *
+ * This file is part of PowerDebug.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Daniel Lezcano <daniel.lezcano@linaro.org> (IBM Corporation)
+ *       - initial API and implementation
+ *******************************************************************************/
+
+extern int gpio_init(void);
+extern int gpio_dump(void);
diff --git a/mainloop.c b/mainloop.c
new file mode 100644
index 0000000..02dda98
--- /dev/null
+++ b/mainloop.c
@@ -0,0 +1,122 @@
+/*******************************************************************************
+ * Copyright (C) 2010, Linaro Limited.
+ *
+ * This file is part of PowerDebug.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Author:
+ *     Daniel Lezcano <daniel.lezcano@linaro.org>
+ *
+ *******************************************************************************/
+
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/epoll.h>
+#include "mainloop.h"
+
+static int epfd = -1;
+static unsigned short nrhandler;
+
+struct mainloop_data {
+	mainloop_callback_t cb;
+	void *data;
+	int fd;
+};
+
+struct mainloop_data **mds;
+
+#define MAX_EVENTS 10
+
+int mainloop(unsigned int timeout)
+{
+        int i, nfds;
+        struct epoll_event events[MAX_EVENTS];
+	struct mainloop_data *md;
+
+	if (epfd < 0)
+		return -1;
+
+	for (;;) {
+
+                nfds = epoll_wait(epfd, events, MAX_EVENTS, timeout);
+                if (nfds < 0) {
+                        if (errno == EINTR)
+                                continue;
+                        return -1;
+                }
+
+                for (i = 0; i < nfds; i++) {
+			md = events[i].data.ptr;
+
+			if (md->cb(md->fd, md->data) > 0)
+				return 0;
+		}
+
+	}
+}
+
+int mainloop_add(int fd, mainloop_callback_t cb, void *data)
+{
+	struct epoll_event ev = {
+		.events = EPOLLIN,
+	};
+
+	struct mainloop_data *md;
+
+	if (fd >= nrhandler) {
+		mds = realloc(mds, sizeof(*mds) * (fd + 1));
+		if (!mds)
+			return -1;
+		nrhandler = fd + 1;
+	}
+
+	md = malloc(sizeof(*md));
+	if (!md)
+		return -1;
+
+	md->data = data;
+	md->cb = cb;
+	md->fd = fd;
+
+	mds[fd] = md;
+	ev.data.ptr = md;
+
+        if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) < 0) {
+		free(md);
+		return -1;
+	}
+
+	return 0;
+}
+
+int mainloop_del(int fd)
+{
+	if (fd >= nrhandler)
+		return -1;
+
+        if (epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL) < 0)
+		return -1;
+
+	free(mds[fd]);
+
+	return 0;
+}
+
+int mainloop_init(void)
+{
+        epfd = epoll_create(2);
+        if (epfd < 0)
+                return -1;
+
+        return 0;
+}
+
+void mainloop_fini(void)
+{
+	close(epfd);
+}
diff --git a/mainloop.h b/mainloop.h
new file mode 100644
index 0000000..cf03bbb
--- /dev/null
+++ b/mainloop.h
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (C) 2010, Linaro Limited.
+ *
+ * This file is part of PowerDebug.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Author:
+ *     Daniel Lezcano <daniel.lezcano@linaro.org>
+ *
+ *******************************************************************************/
+
+typedef int (*mainloop_callback_t)(int fd, void *data);
+
+extern int mainloop(unsigned int timeout);
+extern int mainloop_add(int fd, mainloop_callback_t cb, void *data);
+extern int mainloop_del(int fd);
+extern int mainloop_init(void);
+extern void mainloop_fini(void);
diff --git a/powerdebug.c b/powerdebug.c
index 3f4d60c..6cf3a1b 100644
--- a/powerdebug.c
+++ b/powerdebug.c
@@ -14,18 +14,22 @@
  *******************************************************************************/
 
 #include <getopt.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ncurses.h>
+#include <signal.h>
+#include "regulator.h"
+#include "display.h"
+#include "clocks.h"
+#include "sensor.h"
+#include "gpio.h"
+#include "mainloop.h"
 #include "powerdebug.h"
 
-int dump;
-int highlighted_row;
-int selectedwindow = -1;
-double ticktime = 10.0;  /* in seconds */
-
-char *win_names[TOTAL_FEATURE_WINS] = {
-	"Clocks",
-	"Regulators",
-	"Sensors"
-};
+extern void sigwinch_handler(int);
 
 void usage(void)
 {
@@ -45,273 +49,225 @@
 		" -s)\n");
 	printf("  -V, --version		Show Version\n");
 	printf("  -h, --help 		Help\n");
-
-	exit(0);
 }
 
 void version()
 {
 	printf("powerdebug version %s\n", VERSION);
-	exit(0);
 }
 
-int main(int argc, char **argv)
+/*
+ * Options:
+ * -r, --regulator      : regulators
+ * -s, --sensor	 	: sensors
+ * -c, --clock	  	: clocks
+ * -g, --gpio           : gpios
+ * -p, --findparents    : clockname whose parents have to be found
+ * -t, --time		: ticktime
+ * -d, --dump		: dump
+ * -v, --verbose	: verbose
+ * -V, --version	: version
+ * -h, --help		: help
+ * no option / default : show usage!
+ */
+
+static struct option long_options[] = {
+	{ "regulator", 0, 0, 'r' },
+	{ "sensor", 0, 0, 's' },
+	{ "clock",  0, 0, 'c' },
+	{ "gpio",  0, 0, 'g' },
+	{ "findparents", 1, 0, 'p' },
+	{ "time", 1, 0, 't' },
+	{ "dump", 0, 0, 'd' },
+	{ "verbose", 0, 0, 'v' },
+	{ "version", 0, 0, 'V' },
+	{ "help", 0, 0, 'h' },
+	{ 0, 0, 0, 0 }
+};
+
+struct powerdebug_options {
+	bool verbose;
+	bool regulators;
+	bool sensors;
+	bool clocks;
+	bool gpios;
+	bool dump;
+	unsigned int ticktime;
+	int selectedwindow;
+	char *clkname;
+};
+
+int getoptions(int argc, char *argv[], struct powerdebug_options *options)
 {
-	int c, i;
-	int firsttime[TOTAL_FEATURE_WINS];
-	int enter_hit = 0, verbose = 0, findparent_ncurses = 0, refreshwin = 0;
-	int regulators = 0, sensors = 0, clocks = 0, findparent = 0;
-	char clkarg[64], clkname_str[64];
+	int c;
 
-	for (i = 0; i < TOTAL_FEATURE_WINS; i++)
-		firsttime[i] = 1;
-
-	/*
-	 * Options:
-	 * -r, --regulator      : regulator
-	 * -s, --sensor	 	: sensors
-	 * -c, --clock	  	: clocks
-	 * -p, --findparents    : clockname whose parents have to be found
-	 * -t, --time		: ticktime
-	 * -d, --dump		: dump
-	 * -v, --verbose	: verbose
-	 * -V, --version	: version
-	 * -h, --help		: help
-	 * no option / default : show usage!
-	 */
+	memset(options, 0, sizeof(*options));
+	options->ticktime = 10;
+	options->selectedwindow = -1;
 
 	while (1) {
 		int optindex = 0;
-		static struct option long_options[] = {
-			{"regulator", 0, 0, 'r'},
-			{"sensor", 0, 0, 's'},
-			{"clock", 0, 0, 'c'},
-			{"findparents", 1, 0, 'p'},
-			{"time", 1, 0, 't'},
-			{"dump", 0, 0, 'd'},
-			{"verbose", 0, 0, 'v'},
-			{"version", 0, 0, 'V'},
-			{"help", 0, 0, 'h'},
-			{0, 0, 0, 0}
-		};
 
-		c = getopt_long(argc, argv, "rscp:t:dvVh", long_options, &optindex);
+		c = getopt_long(argc, argv, "rscgp:t:dvVh",
+				long_options, &optindex);
 		if (c == -1)
 			break;
 
 		switch (c) {
 		case 'r':
-			regulators = 1;
-			selectedwindow = REGULATOR;
+			options->regulators = true;
+			options->selectedwindow = REGULATOR;
 			break;
 		case 's':
-			sensors = 1;
-			selectedwindow = SENSOR;
+			options->sensors = true;
+			options->selectedwindow = SENSOR;
 			break;
 		case 'c':
-			clocks = 1;
-			selectedwindow = CLOCK;
+			options->clocks = true;
+			options->selectedwindow = CLOCK;
+			break;
+		case 'g':
+			options->gpios = true;
+			options->selectedwindow = GPIO;
 			break;
 		case 'p':
-			findparent = 1;
-			strcpy(clkarg, optarg);
+			options->clkname = strdup(optarg);
+			if (!options->clkname) {
+				fprintf(stderr, "failed to allocate memory");
+				return -1;
+			}
+			options->dump = true;   /* Assume -dc in case of -p */
+			options->clocks = true;
 			break;
 		case 't':
-			ticktime = strtod(optarg, NULL);
+			options->ticktime = atoi(optarg);
 			break;
 		case 'd':
-			dump = 1;
+			options->dump = true;
 			break;
 		case 'v':
-			verbose = 1;
+			options->verbose = true;
 			break;
 		case 'V':
 			version();
 			break;
-		case 'h':
-			usage();
-			break;
 		case '?':
-			fprintf (stderr, "%s: Unknown option %c'.\n",
+			fprintf(stderr, "%s: Unknown option %c'.\n",
 				argv[0], optopt);
-			exit(1);
 		default:
-			usage();
-			break;
+			return -1;
 		}
 	}
 
-	if (dump && !(regulators || clocks || sensors)) {
-		//fprintf(stderr, "Dump mode (-d) supported only with -c, -r "
-		//		"or -s ..\n");
-		//usage();
-		// By Default lets show everything we have!
-		regulators = clocks = sensors = 1;
+	/* No system specified to be dump, let's default to all */
+	if (!options->regulators && !options->clocks &&
+	    !options->sensors && !options->gpios)
+		options->regulators = options->clocks =
+			options->sensors = options->gpios = true;
+
+	if (options->selectedwindow == -1)
+		options->selectedwindow = CLOCK;
+
+	return 0;
+}
+
+static int powerdebug_dump(struct powerdebug_options *options)
+{
+	if (options->regulators)
+		regulator_dump();
+
+	if (options->clocks)
+		clock_dump(options->clkname);
+
+	if (options->sensors)
+		sensor_dump();
+
+	if (options->gpios)
+		gpio_dump();
+
+	return 0;
+}
+
+static int powerdebug_display(struct powerdebug_options *options)
+{
+	if (display_init(options->selectedwindow)) {
+		printf("failed to initialize display\n");
+		return -1;
 	}
 
-	if (findparent && (!clocks || !dump)) {
-		fprintf(stderr, "-p option passed without -c and -d."
-			" Exiting...\n");
-		usage();
+	if (mainloop(options->ticktime * 1000))
+		return -1;
+
+	return 0;
+}
+
+static struct powerdebug_options *powerdebug_init(void)
+{
+	struct powerdebug_options *options;
+
+	options = malloc(sizeof(*options));
+	if (!options)
+		return NULL;
+
+	memset(options, 0, sizeof(*options));
+	signal(SIGWINCH, sigwinch_handler);
+
+	return options;
+}
+
+int main(int argc, char **argv)
+{
+	struct powerdebug_options *options;
+	int ret;
+
+#ifdef __ANDROID__
+	if (setenv("TERM", "xterm", 1) < 0) {
+		fprintf(stderr, "setenv failure");
+		return 1;
 	}
-
-	if (!dump && selectedwindow == -1)
-		selectedwindow = CLOCK;
-
-	init_regulator_ds();
-
-	while (1) {
-		int key = 0;
-		struct timeval tval;
-		fd_set readfds;
-
-		if (!dump) {
-			if (firsttime[0])
-				init_curses();
-			create_windows();
-			show_header();
-		}
-
-		if (regulators || selectedwindow == REGULATOR) {
-			read_regulator_info();
-			if (!dump) {
-				create_selectedwindow();
-				show_regulator_info(verbose);
-			}
-			else
-				print_regulator_info(verbose);
-		}
-
-		if (clocks || selectedwindow == CLOCK) {
-			int ret = 0;
-			if (firsttime[CLOCK]) {
-				ret = init_clock_details();
-				if (!ret)
-					firsttime[CLOCK] = 0;
-				strcpy(clkname_str, "");
-			}
-			if (!ret && !dump) {
-				int hrow;
-
-				create_selectedwindow();
-				if (!findparent_ncurses) {
-					int command = 0;
-
-					if (enter_hit)
-						command = CLOCK_SELECTED;
-					if (refreshwin)
-						command = REFRESH_WINDOW;
-					hrow = read_and_print_clock_info(
-						verbose,
-						highlighted_row,
-						command);
-					highlighted_row = hrow;
-					enter_hit = 0;
-				} else
-					find_parents_for_clock(clkname_str,
-							enter_hit);
-			}
-			if (!ret && dump) {
-				if (findparent)
-					read_and_dump_clock_info_one(clkarg);
-				else
-					read_and_dump_clock_info(verbose);
-			}
-		}
-
-		if (sensors || selectedwindow == SENSOR) {
-			if (!dump) {
-				create_selectedwindow();
-				print_sensor_header();
-			} else
-				read_and_print_sensor_info(verbose);
-		}
-
-		if (dump)
-			break;
-
-		FD_ZERO(&readfds);
-		FD_SET(0, &readfds);
-		tval.tv_sec = ticktime;
-		tval.tv_usec = (ticktime - tval.tv_sec) * 1000000;
-
-		key = select(1, &readfds, NULL, NULL, &tval);
-
-		if (key)  {
-			char keychar;
-			int keystroke = getch();
-			int oldselectedwin = selectedwindow;
-
-			if (keystroke == EOF)
-				exit(0);
-
-			if (keystroke == KEY_RIGHT || keystroke == 9)
-				selectedwindow++;
-
-			if (keystroke == KEY_LEFT || keystroke == 353)
-				selectedwindow--;
-
-			if (selectedwindow >= TOTAL_FEATURE_WINS)
-				selectedwindow = 0;
-
-			if (selectedwindow < 0)
-				selectedwindow = TOTAL_FEATURE_WINS - 1;
-
-			if (selectedwindow == CLOCK) {
-				if (keystroke == KEY_DOWN)
-					highlighted_row++;
-				if (keystroke == KEY_UP && highlighted_row > 0)
-					highlighted_row--;
-				if (keystroke == 47)
-					findparent_ncurses = 1;
-
-				if ((keystroke == 27 || oldselectedwin !=
-						selectedwindow) && findparent_ncurses) {
-					findparent_ncurses = 0;
-					clkname_str[0] = '\0';
-				}
-
-				if (findparent_ncurses && keystroke != 13) {
-					int len = strlen(clkname_str);
-					char str[2];
-
-					if (keystroke == 263) {
-						if (len > 0)
-							len--;
-
-						clkname_str[len] = '\0';
-					} else {
-						if (strlen(clkname_str) ||
-							keystroke != '/') {
-							str[0] = keystroke;
-							str[1] = '\0';
-							if (len < 63)
-								strcat(clkname_str,
-									str);
-						}
-					}
-				}
-			}
-
-			keychar = toupper(keystroke);
-//#define DEBUG
-#ifdef DEBUG
-			killall_windows(1); fini_curses();
-			printf("key entered %d:%c\n", keystroke, keychar);
-			exit(1);
+	if (setenv("TERMINFO", "/system/etc/terminfo", 1) < 0) {
+		fprintf(stderr, "setenv failure");
+		return 1;
+	}
 #endif
-
-			if (keystroke == 13)
-				enter_hit = 1;
-
-			if (keychar == 'Q' && !findparent_ncurses)
-				exit(0);
-			if (keychar == 'R') {
-				refreshwin = 1;
-				ticktime = 3;
-			} else
-				refreshwin = 0;
-		}
+	options = powerdebug_init();
+	if (!options) {
+		fprintf(stderr, "not enough memory to allocate options\n");
+		return 1;
 	}
-	exit(0);
+
+	if (getoptions(argc, argv, options)) {
+		usage();
+		return 1;
+	}
+
+	if (mainloop_init()) {
+		fprintf(stderr, "failed to initialize the mainloop\n");
+		return 1;
+	}
+
+	if (regulator_init()) {
+		printf("failed to initialize regulator\n");
+		options->regulators = false;
+	}
+
+	if (clock_init()) {
+		printf("failed to initialize clock details (check debugfs)\n");
+		options->clocks = false;
+	}
+
+	if (sensor_init()) {
+		printf("failed to initialize sensors\n");
+		options->sensors = false;
+	}
+
+	if (gpio_init()) {
+		printf("failed to initialize gpios\n");
+		options->gpios = false;
+	}
+
+	ret = options->dump ? powerdebug_dump(options) :
+		powerdebug_display(options);
+
+	return ret < 0;
 }
diff --git a/powerdebug.h b/powerdebug.h
index f7fdc21..c4cf88d 100644
--- a/powerdebug.h
+++ b/powerdebug.h
@@ -13,61 +13,4 @@
  *       - initial API and implementation
  *******************************************************************************/
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <dirent.h>
-#include <getopt.h>
-#include <errno.h>
-#include <ncurses.h>
-
-#define VERSION "0.4"
-
-#define TOTAL_FEATURE_WINS 3  /* Regulator, Clock and Sensor (for now) */
-enum {CLOCK, REGULATOR, SENSOR};
-enum {CLOCK_SELECTED = 1, REFRESH_WINDOW};
-
-extern struct regulator_info *regulators_info;
-
-extern char *win_names[TOTAL_FEATURE_WINS];
-extern int selectedwindow;
-
-extern int numregulators;
-extern int dump;
-extern double ticktime;
-
-extern void version(void);
-
-extern void print_regulator_info(int verbose);
-extern void init_regulator_ds(void);
-extern void read_regulator_info(void);
-extern void print_regulator_info(int verbose);
-
-extern void read_and_dump_clock_info(int verbose);
-extern void read_and_dump_clock_info_one(char *clk);
-extern void read_clock_info(char *clkpath);
-extern struct clock_info *read_clock_info_recur(char *clkpath, int level,
-						struct clock_info *parent);
-extern void dump_clock_info(struct clock_info *clk, int level, int bmp);
-extern void insert_children(struct clock_info **parent, struct clock_info *clk);
-extern void find_parents_for_clock(char *clkname, int complete);
-extern int  read_and_print_clock_info(int verbose, int hrow, int selected);
-extern void print_clock_info(int verbose, int hrow, int selected);
-extern void print_string_val(char *name, char *val);
-extern int  init_clock_details(void);
-extern void print_clock_header(void);
-extern void print_one_clock(int line, char *str, int bold, int highlight);
-extern char *debugfs_locate_mpoint(void);
-
-extern void get_sensor_info(char *path, char *name, char *sensor, int verbose);
-extern int  read_and_print_sensor_info(int verbose);
-extern void print_sensor_header(void);
-
-extern void init_curses(void);
-extern void fini_curses(void);
-extern void killall_windows(int all);
-extern void show_header(void);
-extern void create_windows(void);
-extern void create_selectedwindow(void);
-extern void show_regulator_info(int verbose);
+#define VERSION "0.6.4"
diff --git a/regulator.c b/regulator.c
index 18c9777..68c686f 100644
--- a/regulator.c
+++ b/regulator.c
@@ -11,191 +11,243 @@
  * Contributors:
  *     Amit Arora <amit.arora@linaro.org> (IBM Corporation)
  *       - initial API and implementation
+ *     Daniel Lezcano <daniel.lezcano@linaro.org> (IBM Corporation)
+ *       - rewrote code and API based on the tree
  *******************************************************************************/
 
 #include "regulator.h"
 
-int init_regulator_ds(void)
+#define SYSFS_REGULATOR "/sys/class/regulator"
+#define VALUE_MAX 16
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#undef _GNU_SOURCE
+#include <sys/types.h>
+#include <stdbool.h>
+#include <dirent.h>
+#include <string.h>
+#include <stdlib.h>
+#include "display.h"
+#include "powerdebug.h"
+#include "tree.h"
+#include "utils.h"
+
+struct regulator_info {
+	char name[NAME_MAX];
+	char state[VALUE_MAX];
+	char status[VALUE_MAX];
+	char type[VALUE_MAX];
+	char opmode[VALUE_MAX];
+	int microvolts;
+	int min_microvolts;
+	int max_microvolts;
+	int microamps;
+	int min_microamps;
+	int max_microamps;
+	int requested_microamps;
+	int num_users;
+};
+
+struct regulator_data {
+	const char *name;
+	const char *ifmt;
+	const char *ofmt;
+	bool derefme;
+};
+
+static struct regulator_data regdata[] = {
+	{ "name",           "%s", "\tname: %s\n"                 },
+	{ "status",         "%s", "\tstatus: %s\n"               },
+	{ "state",          "%s", "\tstate: %s\n"                },
+	{ "type",           "%s", "\ttype: %s\n"                 },
+	{ "num_users",      "%d", "\tnum_users: %d\n",      true },
+	{ "microvolts",     "%d", "\tmicrovolts: %d\n",     true },
+	{ "max_microvolts", "%d", "\tmax_microvolts: %d\n", true },
+	{ "min_microvolts", "%d", "\tmin_microvolts: %d\n", true },
+};
+
+static struct tree *reg_tree;
+
+static struct regulator_info *regulator_alloc(void)
 {
-	DIR *regdir;
-	struct dirent *item;
+	struct regulator_info *regi;
 
-	regdir = opendir("/sys/class/regulator");
-	if (!regdir)
-		return(1);
-	while ((item = readdir(regdir))) {
-		if (strncmp(item->d_name, "regulator", 9))
-			continue;
+	regi = malloc(sizeof(*regi));
+	if (regi)
+		memset(regi, 0, sizeof(*regi));
 
-		numregulators++;
-	}
-	closedir(regdir);
-
-	regulators_info = (struct regulator_info *)malloc(numregulators*
-							sizeof(struct regulator_info));
-	if (!regulators_info) {
-		fprintf(stderr, "init_regulator_ds: Not enough memory to "
-			"read information for %d regulators!\n", numregulators);
-		return(1);
-	}
-
-	return(0);
+	return regi;
 }
 
-void print_string_val(char *name, char *val)
-{
-	printf("\t%s=%s", name, val);
-	if (!strchr(val, '\n'))
-		printf("\n");
-}
-
-void print_regulator_info(int verbose)
+static int regulator_dump_cb(struct tree *tree, void *data)
 {
 	int i;
+	char buffer[NAME_MAX];
+	size_t nregdata = sizeof(regdata) / sizeof(regdata[0]);
 
+	if (!strncmp("regulator.", tree->name, strlen("regulator.")))
+		printf("\n%s:\n", tree->name);
+
+	for (i = 0; i < nregdata; i++) {
+		int val;
+
+		if (file_read_value(tree->path, regdata[i].name,
+				    regdata[i].ifmt, buffer))
+			continue;
+
+		if (regdata[i].derefme) {
+			val = atoi(buffer);
+			printf(regdata[i].ofmt, val);
+		} else
+			printf(regdata[i].ofmt, buffer);
+	}
+
+	return 0;
+}
+
+int regulator_dump(void)
+{
 	printf("\nRegulator Information:\n");
 	printf("*********************\n\n");
 
-	for (i = 0; i < numregulators; i++) {
-		printf("Regulator %d:\n", i + 1);
-		print_string_val("name", regulators_info[i].name);
-		if (strcmp(regulators_info[i].status, ""))
-			print_string_val("status", regulators_info[i].status);
-		if (strcmp(regulators_info[i].state, ""))
-			print_string_val("state", regulators_info[i].state);
-
-		if (!verbose)
-			continue;
-
-		if (strcmp(regulators_info[i].type, ""))
-			print_string_val("type", regulators_info[i].type);
-		if (strcmp(regulators_info[i].opmode, ""))
-			print_string_val("opmode", regulators_info[i].opmode);
-
-		if (regulators_info[i].microvolts)
-			printf("\tmicrovolts=%d\n",
-				regulators_info[i].microvolts);
-		if (regulators_info[i].min_microvolts)
-			printf("\tmin_microvolts=%d\n",
-				regulators_info[i].min_microvolts);
-		if (regulators_info[i].max_microvolts)
-			printf("\tmax_microvolts=%d\n",
-				regulators_info[i].max_microvolts);
-
-		if (regulators_info[i].microamps)
-			printf("\tmicroamps=%d\n",
-				regulators_info[i].microamps);
-		if (regulators_info[i].min_microamps)
-			printf("\tmin_microamps=%d\n",
-				regulators_info[i].min_microamps);
-		if (regulators_info[i].max_microamps)
-			printf("\tmax_microamps=%d\n",
-				regulators_info[i].max_microamps);
-		if (regulators_info[i].requested_microamps)
-			printf("\trequested_microamps=%d\n",
-				regulators_info[i].requested_microamps);
-
-		if (regulators_info[i].num_users)
-			printf("\tnum_users=%d\n",
-				regulators_info[i].num_users);
-		printf("\n");
-	}
-
-	if (!numregulators && verbose) {
-		printf("Could not find regulator information!");
-		printf(" Looks like /sys/class/regulator is empty.\n\n");
-	}
-
-	printf("\n\n");
+	return tree_for_each(reg_tree, regulator_dump_cb, NULL);
 }
 
-void read_info_from_dirent(struct dirent *ritem, char *str, int idx)
+static int regulator_display_cb(struct tree *t, void *data)
 {
-	if (!strcmp(ritem->d_name, "name"))
-		strcpy(regulators_info[idx].name, str);
-	if (!strcmp(ritem->d_name, "state"))
-		strcpy(regulators_info[idx].state, str);
-	if (!strcmp(ritem->d_name, "status"))
-		strcpy(regulators_info[idx].status, str);
+	struct regulator_info *reg = t->private;
+	int *line = data;
+	char *buf;
 
-	if (!strcmp(ritem->d_name, "type"))
-		strcpy(regulators_info[idx].type, str);
-	if (!strcmp(ritem->d_name, "opmode"))
-		strcpy(regulators_info[idx].opmode, str);
+        /* we skip the root node of the tree */
+	if (!t->parent)
+		return 0;
 
-	if (!strcmp(ritem->d_name, "microvolts"))
-		regulators_info[idx].microvolts = atoi(str);
-	if (!strcmp(ritem->d_name, "min_microvolts"))
-		regulators_info[idx].min_microvolts = atoi(str);
-	if (!strcmp(ritem->d_name, "max_microvolts"))
-		regulators_info[idx].max_microvolts = atoi(str);
+	if (!strlen(reg->name))
+		return 0;
 
-	if (!strcmp(ritem->d_name, "microamps"))
-		regulators_info[idx].microamps = atoi(str);
-	if (!strcmp(ritem->d_name, "min_microamps"))
-		regulators_info[idx].min_microamps = atoi(str);
-	if (!strcmp(ritem->d_name, "max_microamps"))
-		regulators_info[idx].max_microamps = atoi(str);
-	if (!strcmp(ritem->d_name, "requested_microamps"))
-		regulators_info[idx].requested_microamps = atoi(str);
+	if (asprintf(&buf, "%-11s %-11s %-11s %-11s %-11d %-11d %-11d %-12d",
+		     reg->name, reg->status, reg->state, reg->type,
+		     reg->num_users, reg->microvolts, reg->min_microvolts,
+		     reg->max_microvolts) < 0)
+		return -1;
 
-	if (!strcmp(ritem->d_name, "num_users"))
-		regulators_info[idx].num_users = atoi(str);
+	display_print_line(REGULATOR, *line, buf, reg->num_users, t);
+
+	(*line)++;
+
+	free(buf);
+
+	return 0;
 }
 
-int read_regulator_info(void)
+static int regulator_print_header(void)
 {
-	FILE *file = NULL;
-	DIR *regdir, *dir;
-	int len, count = 0, ret = 0;
-	char line[1024], filename[1024], *fptr;
-	struct dirent *item, *ritem;
+	char *buf;
+	int ret;
 
-	regdir = opendir("/sys/class/regulator");
-	if (!regdir)
-		return(1);
-	while ((item = readdir(regdir))) {
-		if (strlen(item->d_name) < 3)
-			continue;
+	if (asprintf(&buf, "%-11s %-11s %-11s %-11s %-11s %-11s %-11s %-12s",
+		     "Name", "Status", "State", "Type", "Users", "Microvolts",
+		     "Min u-volts", "Max u-volts") < 0)
+		return -1;
 
-		if (strncmp(item->d_name, "regulator", 9))
-			continue;
+	ret = display_column_name(buf);
 
-		len = sprintf(filename, "/sys/class/regulator/%s",
-			item->d_name);
-
-		dir = opendir(filename);
-		if (!dir)
-			continue;
-		count++;
-
-		if (count > numregulators) {
-			ret = 1;
-			goto exit;
-		}
-
-		strcpy(regulators_info[count-1].name, item->d_name);
-		while ((ritem = readdir(dir))) {
-			if (strlen(ritem->d_name) < 3)
-				continue;
-
-			sprintf(filename + len, "/%s", ritem->d_name);
-			file = fopen(filename, "r");
-			if (!file)
-				continue;
-			memset(line, 0, 1024);
-			fptr = fgets(line, 1024, file);
-			fclose(file);
-			if (!fptr)
-				continue;
-			read_info_from_dirent(ritem, fptr, count - 1);
-		}
-	exit:
-		closedir(dir);
-		if (ret)
-			break;
-	}
-	closedir(regdir);
+	free(buf);
 
 	return ret;
+
+}
+
+static int regulator_display(bool refresh)
+{
+	int ret, line = 0;
+
+	display_reset_cursor(REGULATOR);
+
+	regulator_print_header();
+
+	ret = tree_for_each(reg_tree, regulator_display_cb, &line);
+
+	display_refresh_pad(REGULATOR);
+
+	return ret;
+}
+
+static int regulator_filter_cb(const char *name)
+{
+	/* let's ignore some directories in order to avoid to be
+	 * pulled inside the sysfs circular symlinks mess/hell
+	 * (choose the word which fit better)
+	 */
+	if (!strcmp(name, "device"))
+		return 1;
+
+	if (!strcmp(name, "subsystem"))
+		return 1;
+
+	if (!strcmp(name, "driver"))
+		return 1;
+
+	return 0;
+}
+
+static inline int read_regulator_cb(struct tree *t, void *data)
+{
+	struct regulator_info *reg = t->private;
+
+	file_read_value(t->path, "name", "%s", reg->name);
+	file_read_value(t->path, "state", "%s", reg->state);
+	file_read_value(t->path, "status", "%s", reg->status);
+	file_read_value(t->path, "type", "%s", reg->type);
+	file_read_value(t->path, "opmode", "%s", reg->opmode);
+	file_read_value(t->path, "num_users", "%d", &reg->num_users);
+	file_read_value(t->path, "microvolts", "%d", &reg->microvolts);
+	file_read_value(t->path, "min_microvolts", "%d", &reg->min_microvolts);
+	file_read_value(t->path, "max_microvolts", "%d", &reg->max_microvolts);
+	file_read_value(t->path, "microamps", "%d", &reg->microamps);
+	file_read_value(t->path, "min_microamps", "%d", &reg->min_microamps);
+	file_read_value(t->path, "max_microamps", "%d", &reg->max_microamps);
+
+	return 0;
+}
+
+static int fill_regulator_cb(struct tree *t, void *data)
+{
+	struct regulator_info *reg;
+
+	reg = regulator_alloc();
+	if (!reg) {
+		printf("error: unable to allocate memory for regulator\n");
+		return -1;
+	}
+	t->private = reg;
+
+        /* we skip the root node but we set it expanded for its children */
+	if (!t->parent)
+		return 0;
+
+	return read_regulator_cb(t, data);
+}
+
+static int fill_regulator_tree(void)
+{
+	return tree_for_each(reg_tree, fill_regulator_cb, NULL);
+}
+
+static struct display_ops regulator_ops = {
+	.display = regulator_display,
+};
+
+int regulator_init(void)
+{
+	reg_tree = tree_load(SYSFS_REGULATOR, regulator_filter_cb, false);
+	if (!reg_tree)
+		return -1;
+
+	if (fill_regulator_tree())
+		return -1;
+
+	return display_register(REGULATOR, &regulator_ops);
 }
diff --git a/regulator.h b/regulator.h
index 4276933..8b3ec06 100644
--- a/regulator.h
+++ b/regulator.h
@@ -13,32 +13,5 @@
  *       - initial API and implementation
  *******************************************************************************/
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <dirent.h>
-#include <getopt.h>
-
-#define VALUE_MAX 16
-
-int numregulators;
-
-struct regulator_info {
-	char name[NAME_MAX];
-	char state[VALUE_MAX];
-	char status[VALUE_MAX];
-	char type[VALUE_MAX];
-	char opmode[VALUE_MAX];
-	int microvolts;
-	int min_microvolts;
-	int max_microvolts;
-	int microamps;
-	int min_microamps;
-	int max_microamps;
-	int requested_microamps;
-	int num_users;
-} *regulators_info;
-
-extern int numregulators;
-extern int dump;
+extern int regulator_init(void);
+extern int regulator_dump(void);
diff --git a/sensor.c b/sensor.c
index f5fcd40..bd8c354 100644
--- a/sensor.c
+++ b/sensor.c
@@ -13,157 +13,270 @@
  *       - initial API and implementation
  *******************************************************************************/
 
+#define _GNU_SOURCE
+#include <stdio.h>
+#undef _GNU_SOURCE
+#include <sys/types.h>
+#include <stdbool.h>
+#include <dirent.h>
+#include <string.h>
+#include <stdlib.h>
+
 #include "powerdebug.h"
+#include "display.h"
 #include "sensor.h"
+#include "tree.h"
+#include "utils.h"
 
-char *get_num(char *fname, char *sensor)
+#define SYSFS_SENSOR "/sys/class/hwmon"
+
+static struct tree *sensor_tree;
+
+struct temp_info {
+	char name[NAME_MAX];
+	int temp;
+};
+
+struct fan_info {
+	char name[NAME_MAX];
+	int rpms;
+};
+
+struct sensor_info {
+	char name[NAME_MAX];
+	struct temp_info *temperatures;
+	struct fan_info *fans;
+	short nrtemps;
+	short nrfans;
+};
+
+static int sensor_dump_cb(struct tree *tree, void *data)
 {
-	char tmpstr[NAME_MAX];
-	char *str;
+	int i;
+	struct sensor_info *sensor = tree->private;
 
-	strcpy(tmpstr, (fname+strlen(sensor)));
+	if (!strlen(sensor->name))
+		return 0;
 
-	str = strrchr(tmpstr, '_');
-	str[0] = '\0';
+	printf("%s\n", sensor->name);
 
-	str = strdup(tmpstr);
-	return str;
-}
+	for (i = 0; i < sensor->nrtemps; i++)
+		printf(" %s %.1f °C/V\n", sensor->temperatures[i].name,
+		       (float)sensor->temperatures[i].temp / 1000);
 
-void get_sensor_info(char *path, char *fname, char *sensor, int verbose)
-{
-	FILE *filep;
-	char filename[PATH_MAX];
-	char **items = NULL, **suffix = NULL;
-	char *item, result[NAME_MAX], *num;
-	int ret, count = 0;
-
-	(void)verbose; // get rid of warning
-
-	sprintf(filename, "%s/%s", path, fname);
-
-	if (!strcmp(sensor, "in")) {
-		items = (char **)items_in;
-		suffix = (char **)suffix_in;
-	}
-
-	if (!strcmp(sensor, "temp")) {
-		items = (char **)items_temp;
-		suffix = (char **)suffix_temp;
-	}
-
-	if (!strcmp(sensor, "fan")) {
-		items = (char **)items_fan;
-		suffix = (char **)suffix_fan;
-	}
-	if (!strcmp(sensor, "pwm")) {
-		items = (char **)items_pwm;
-		suffix = (char **)suffix_pwm;
-	}
-
-
-	if (!items || !suffix)
-		return;
-
-	item = strrchr(fname, '_');
-	if (!item)
-		return;
-
-	if (item)
-		item++;
-
-	if (item > (fname + strlen(fname)))
-		return;
-
-	num = get_num(fname, sensor);
-	filep = fopen(filename, "r");
-
-	if (!filep)
-		goto exit;
-	ret = fscanf(filep, "%s", result);
-	fclose(filep);
-
-	if (ret != 1)
-		goto exit;
-
-	while (strcmp(items[count], "")) {
-		if (!strcmp(items[count], item))
-			printf("\'temp\' %s sensor %s\t\t%d%s\n",
-				num, items[count], atoi(result)/1000,
-				suffix[count]);
-		count++;
-	}
-exit:
-	free(num);
-	return;
-}
-
-int read_and_print_sensor_info(int verbose)
-{
-	DIR *dir, *subdir;
-	int len, found = 0;
-	char filename[PATH_MAX], devpath[PATH_MAX];
-	char device[PATH_MAX];
-	struct dirent *item, *subitem;
-
-	printf("\nSensor Information:\n");
-	printf("******************\n");
-
-	sprintf(filename, "%s", "/sys/class/hwmon");
-	dir = opendir(filename);
-	if (!dir)
-		return errno;
-
-	while ((item = readdir(dir))) {
-		if (item->d_name[0] == '.')  /* skip the hidden files */
-			continue;
-
-		found = 1;
-
-		sprintf(filename, "/sys/class/hwmon/%s", item->d_name);
-		sprintf(devpath, "%s/device", filename);
-
-		len = readlink(devpath, device, PATH_MAX - 1);
-
-		if (len < 0)
-			strcpy(devpath, filename);
-		else
-			device[len] = '\0';
-
-		subdir = opendir(devpath);
-
-		printf("\nSensor Information for %s :\n", item->d_name);
-		fflush(stdin);
-
-		while ((subitem = readdir(subdir))) {
-			if (subitem->d_name[0] == '.') /* skip hidden files */
-				continue;
-
-			if (!strncmp(subitem->d_name, "in", 2))
-				get_sensor_info(devpath, subitem->d_name, "in",
-						verbose);
-			else if (!strncmp(subitem->d_name, "temp", 4))
-				get_sensor_info(devpath, subitem->d_name,
-						"temp", verbose);
-			else if (!strncmp(subitem->d_name, "fan", 4))
-				get_sensor_info(devpath, subitem->d_name,
-						"fan", verbose);
-			else if (!strncmp(subitem->d_name, "pwm", 4))
-				get_sensor_info(devpath, subitem->d_name,
-						"pwm", verbose);
-
-		}
-
-		closedir(subdir);
-	}
-	closedir(dir);
-
-	if (!found && verbose) {
-		printf("Could not find sensor information!");
-		printf(" Looks like /sys/class/hwmon is empty.\n");
-	}
-
-	printf("\n");
+	for (i = 0; i < sensor->nrfans; i++)
+		printf(" %s %d rpm\n", sensor->fans[i].name,
+		       sensor->fans[i].rpms);
 
 	return 0;
 }
+
+int sensor_dump(void)
+{
+	printf("\nSensor Information:\n");
+	printf("*******************\n\n");
+
+	return tree_for_each(sensor_tree, sensor_dump_cb, NULL);
+}
+
+static struct sensor_info *sensor_alloc(void)
+{
+	struct sensor_info *sensor;
+
+	sensor = malloc(sizeof(*sensor));
+	if (sensor)
+		memset(sensor, 0, sizeof(*sensor));
+
+	return sensor;
+}
+
+static int read_sensor_cb(struct tree *tree, void *data)
+{
+	DIR *dir;
+	int value;
+        struct dirent dirent, *direntp;
+	struct sensor_info *sensor = tree->private;
+
+	int nrtemps = 0;
+	int nrfans = 0;
+
+	dir = opendir(tree->path);
+	if (!dir)
+		return -1;
+
+	file_read_value(tree->path, "name", "%s", sensor->name);
+
+	while (!readdir_r(dir, &dirent, &direntp)) {
+
+                if (!direntp)
+                        break;
+
+		if (direntp->d_type != DT_REG)
+			continue;
+
+		if (!strncmp(direntp->d_name, "temp", 4)) {
+
+			if (file_read_value(tree->path, direntp->d_name, "%d",
+					    &value))
+				continue;
+
+			sensor->temperatures =
+				realloc(sensor->temperatures,
+					sizeof(struct temp_info) * (nrtemps + 1));
+			if (!sensor->temperatures)
+				continue;
+
+			strcpy(sensor->temperatures[nrtemps].name,
+			       direntp->d_name);
+			sensor->temperatures[nrtemps].temp = value;
+
+			nrtemps++;
+		}
+
+		if (!strncmp(direntp->d_name, "fan", 3)) {
+
+			if (file_read_value(tree->path, direntp->d_name, "%d",
+					    &value))
+				continue;
+
+			sensor->fans =
+				realloc(sensor->fans,
+					sizeof(struct temp_info) * (nrfans + 1));
+			if (!sensor->fans)
+				continue;
+
+			strcpy(sensor->fans[nrfans].name,
+			       direntp->d_name);
+			sensor->fans[nrfans].rpms = value;
+
+			nrfans++;
+		}
+	}
+
+	sensor->nrtemps = nrtemps;
+	sensor->nrfans = nrfans;
+
+	closedir(dir);
+
+	return 0;
+}
+
+static int fill_sensor_cb(struct tree *t, void *data)
+{
+	struct sensor_info *sensor;
+
+	sensor = sensor_alloc();
+	if (!sensor)
+		return -1;
+
+	t->private = sensor;
+
+	if (!t->parent)
+		return 0;
+
+	return read_sensor_cb(t, data);
+}
+
+static int fill_sensor_tree(void)
+{
+	return tree_for_each(sensor_tree, fill_sensor_cb, NULL);
+}
+
+static int sensor_filter_cb(const char *name)
+{
+	/* let's ignore some directories in order to avoid to be
+	 * pulled inside the sysfs circular symlinks mess/hell
+	 * (choose the word which fit better)
+	 */
+	if (!strcmp(name, "subsystem"))
+		return 1;
+
+	if (!strcmp(name, "driver"))
+		return 1;
+
+	if (!strcmp(name, "hwmon"))
+		return 1;
+
+	if (!strcmp(name, "power"))
+		return 1;
+
+	return 0;
+}
+
+static int sensor_display_cb(struct tree *t, void *data)
+{
+	struct sensor_info *sensor = t->private;
+	int *line = data;
+	char buf[1024];
+	int i;
+
+	if (!strlen(sensor->name))
+		return 0;
+
+	sprintf(buf, "%s", sensor->name);
+	display_print_line(SENSOR, *line, buf, 1, t);
+
+	(*line)++;
+
+	for (i = 0; i < sensor->nrtemps; i++) {
+		sprintf(buf, " %-35s%.1f", sensor->temperatures[i].name,
+		       (float)sensor->temperatures[i].temp / 1000);
+		display_print_line(SENSOR, *line, buf, 0, t);
+		(*line)++;
+	}
+
+	for (i = 0; i < sensor->nrfans; i++) {
+		sprintf(buf, " %-35s%d rpm", sensor->fans[i].name,
+			sensor->fans[i].rpms);
+		display_print_line(SENSOR, *line, buf, 0, t);
+		(*line)++;
+	}
+
+	return 0;
+}
+
+static int sensor_print_header(void)
+{
+	char *buf;
+	int ret;
+
+	if (asprintf(&buf, "%-36s%s", "Name", "Value") < 0)
+		return -1;
+
+	ret = display_column_name(buf);
+
+	free(buf);
+
+	return ret;
+}
+
+static int sensor_display(bool refresh)
+{
+	int ret, line = 0;
+
+	display_reset_cursor(SENSOR);
+
+	sensor_print_header();
+
+	ret = tree_for_each(sensor_tree, sensor_display_cb, &line);
+
+	display_refresh_pad(SENSOR);
+
+	return ret;
+}
+
+static struct display_ops sensor_ops = {
+	.display = sensor_display,
+};
+
+int sensor_init(void)
+{
+	sensor_tree = tree_load(SYSFS_SENSOR, sensor_filter_cb, false);
+	if (!sensor_tree)
+		return -1;
+
+	if (fill_sensor_tree())
+		return -1;
+
+	return display_register(SENSOR, &sensor_ops);
+}
diff --git a/sensor.h b/sensor.h
index cca11d1..0a069ce 100644
--- a/sensor.h
+++ b/sensor.h
@@ -13,11 +13,5 @@
  *       - initial API and implementation
  *******************************************************************************/
 
-char *items_temp[32] = {"min", "max", "input", "label", ""};
-char *suffix_temp[32] = {"°C", "°C", "°C", "", ""};
-char *items_in[32] = {"min", "max", "input", "label", ""};
-char *suffix_in[32] = {"Volts", "Volts", "Volts", "", ""};
-char *items_fan[32] = {"min", "max", "input", "label", "div", "target", ""};
-char *suffix_fan[32] = {"RPM", "RPM", "RPM", "", "", "RPM", ""};
-char *items_pwm[32] = {"freq", "enable", "mode", ""};
-char *suffix_pwm[32] = {"Hz", "", "", ""};
+extern int sensor_dump(void);
+extern int sensor_init(void);
diff --git a/tree.c b/tree.c
new file mode 100644
index 0000000..686e846
--- /dev/null
+++ b/tree.c
@@ -0,0 +1,359 @@
+/*******************************************************************************
+ * Copyright (C) 2010, Linaro Limited.
+ *
+ * This file is part of PowerDebug.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Author:
+ *     Daniel Lezcano <daniel.lezcano@linaro.org>
+ *
+ *******************************************************************************/
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#undef _GNU_SOURCE
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "tree.h"
+
+/*
+ * Allocate a tree structure and initialize the different fields.
+ *
+ * @path  : the absolute path to the directory
+ * @depth : the depth in the tree
+ * Returns a tree structure on success, NULL otherwise
+ */
+static inline struct tree *tree_alloc(const char *path, int depth)
+{
+	struct tree *t;
+
+	t = malloc(sizeof(*t));
+	if (!t)
+		return NULL;
+
+	/* Full pathname */
+	t->path = strdup(path);
+	if (!t->path) {
+		free(t);
+		return NULL;
+	}
+
+	/* Basename pointer on the full path name */
+	t->name = strrchr(t->path, '/') + 1;
+
+	t->depth = depth;
+	t->tail = t;
+	t->child = NULL;
+	t->parent = NULL;
+	t->next = NULL;
+	t->prev = NULL;
+	t->private = NULL;
+	t->nrchild = 0;
+
+	return t;
+}
+
+/*
+ * Free a tree structure and the fields we allocated in the
+ * tree_alloc function.
+ *
+ * @t : the tree structure to be freed
+ */
+static inline void tree_free(struct tree *t)
+{
+	free(t->path);
+	free(t);
+}
+
+/*
+ * Add at the end of the list the new list element.
+ *
+ * @head : the list to be appened
+ * @new  : the new element to be added at the end of the list
+ */
+static inline void tree_add_tail(struct tree *head, struct tree *new)
+{
+	new->prev = head->tail;
+	head->tail->next = new;
+	head->tail = new;
+}
+
+/*
+ * Add a child in to a parent list, at the end of this list.
+ *
+ * @parent : the parent list to add the child
+ * @child  : the child to be added
+ */
+static inline void tree_add_child(struct tree *parent, struct tree *child)
+{
+	child->parent = parent;
+
+	if (parent->child)
+		return tree_add_tail(parent->child, child);
+
+	parent->child = child;
+}
+
+/*
+ * This function will browse the directory structure and build a
+ * tree reflecting the content of the directory tree.
+ *
+ * @tree   : the root node of the tree
+ * @filter : a callback to filter out the directories
+ * Returns 0 on success, -1 otherwise
+ */
+static int tree_scan(struct tree *tree, tree_filter_t filter, bool follow)
+{
+	DIR *dir;
+	char *basedir, *newpath;
+	struct dirent dirent, *direntp;
+	struct stat s;
+	int ret = 0;
+
+	dir = opendir(tree->path);
+	if (!dir) {
+		printf("error: unable to open directory %s\n", tree->path);
+		return -1;
+	}
+
+	while (!readdir_r(dir, &dirent, &direntp)) {
+
+		struct tree *child;
+
+                if (!direntp)
+                        break;
+
+                if (direntp->d_name[0] == '.')
+                        continue;
+
+		if (filter && filter(direntp->d_name))
+			continue;
+
+		ret = asprintf(&basedir, "%s", tree->path);
+		if (ret < 0)
+			return -1;
+
+		ret = basename(basedir) ? 0 : -1;
+		if (ret < 0)
+			goto out_free_basedir;
+
+		ret = asprintf(&newpath, "%s/%s", basedir, direntp->d_name);
+		if (ret < 0)
+			goto out_free_basedir;
+
+		ret = stat(newpath, &s);
+		if (ret)
+			goto out_free_newpath;
+
+		if (S_ISDIR(s.st_mode) || (S_ISLNK(s.st_mode) && follow)) {
+
+			ret = -1;
+
+			child = tree_alloc(newpath, tree->depth + 1);
+			if (!child)
+				goto out_free_newpath;
+
+			tree_add_child(tree, child);
+
+			tree->nrchild++;
+
+			ret = tree_scan(child, filter, follow);
+		}
+
+	out_free_newpath:
+		free(newpath);
+
+	out_free_basedir:
+		free(basedir);
+
+		if (ret)
+			break;
+	}
+
+	closedir(dir);
+
+	return ret;
+}
+
+/*
+ * This function takes the topmost directory path and populate the
+ * directory tree structures.
+ *
+ * @tree : a path to the topmost directory path
+ * Returns a tree structure corresponding to the root node of the
+ * directory tree representation on success, NULL otherwise
+ */
+struct tree *tree_load(const char *path, tree_filter_t filter, bool follow)
+{
+	struct tree *tree;
+
+	tree = tree_alloc(path, 0);
+	if (!tree)
+		return NULL;
+
+	if (tree_scan(tree, filter, follow)) {
+		tree_free(tree);
+		return NULL;
+	}
+
+	return tree;
+}
+
+/*
+ * This function will go over the tree passed as parameter and
+ * will call the callback passed as parameter for each node.
+ *
+ * @tree : the topmost node where we begin to browse the tree
+ * Returns 0 on success, < 0 otherwise
+ */
+int tree_for_each(struct tree *tree, tree_cb_t cb, void *data)
+{
+	if (!tree)
+		return 0;
+
+	if (cb(tree, data))
+		return -1;
+
+	if (tree_for_each(tree->child, cb, data))
+		return -1;
+
+	return tree_for_each(tree->next, cb, data);
+}
+
+/*
+ * This function will go over the tree passed as parameter at the reverse
+ * order and will call the callback passed as parameter for each.
+ * @tree : the lower node where we begin to browse the tree at the reverse
+ * order
+ * cb : a callback for each node the function will go over
+ * data : some private data to be passed across the callbacks
+ * Returns 0 on success, < 0 otherwise
+ */
+int tree_for_each_reverse(struct tree *tree, tree_cb_t cb, void *data)
+{
+	if (!tree)
+		return 0;
+
+	if (cb(tree, data))
+		return -1;
+
+	if (tree_for_each_reverse(tree->prev, cb, data))
+		return -1;
+
+	return tree_for_each_reverse(tree->parent, cb, data);
+}
+
+
+/*
+ * The function will go over all the parent of the specified node passed
+ * as parameter.
+ * @tree : the child node from where we back path to the parent
+ * cb : a callback for each node the function will go over
+ * data : some private data to be passed across the callbacks
+ * Returns 0 on success, < 0 otherwise
+ */
+int tree_for_each_parent(struct tree *tree, tree_cb_t cb, void *data)
+{
+	if (!tree)
+		return 0;
+
+	if (tree_for_each_parent(tree->parent, cb, data))
+		return -1;
+
+	return cb(tree, data);
+}
+
+/*
+ * The function will return the first node which match with the name as
+ * parameter.
+ * @tree : the tree where we begin to find
+ * @name : the name of the node the function must look for.
+ * Returns a pointer to the tree structure if found, NULL otherwise.
+ */
+struct tree *tree_find(struct tree *tree, const char *name)
+{
+	struct tree *t;
+
+	if (!tree)
+		return NULL;
+
+	if (!strcmp(tree->name, name))
+		return tree;
+
+	t = tree_find(tree->child, name);
+	if (t)
+		return t;
+
+	return tree_find(tree->next, name);
+}
+
+struct struct_find {
+	int nr;
+	const char *name;
+	struct tree ***ptree;
+};
+
+static int tree_finds_cb(struct tree *tree, void *data)
+{
+	struct struct_find *sf = data;
+
+	if (!strlen(sf->name))
+		return 0;
+
+	if (strncmp(sf->name, tree->name, strlen(sf->name)))
+		return 0;
+
+	if (sf->ptree)
+		(*(sf->ptree))[sf->nr] = tree;
+
+	sf->nr++;
+
+	return 0;
+}
+
+/*
+ * This function will search for all the nodes where the name begin
+ * with the name passed as parameter. *Note* the function allocates
+ * the array, it is up to the caller to free this array.
+ * @tree : the topmost node of the tree where we being to search
+ * @name : the name to find in the tree
+ * @ptr  : a pointer to a pointer of pointer of tree structure :)
+ * Returns the number of elements found in the tree, < 0 if something
+ * went wrong.
+ */
+int tree_finds(struct tree *tree, const char *name, struct tree ***ptr)
+{
+	struct struct_find sf = { .nr = 0, .ptree = NULL, .name = name };
+	int nmatch;
+
+	/* first pass : count # of matching nodes */
+	tree_for_each(tree, tree_finds_cb, &sf);
+
+	/* no match */
+	if (!sf.nr)
+		return 0;
+
+	*ptr = malloc(sizeof(struct tree *) * sf.nr);
+	if (!*ptr)
+		return -1;
+
+	/* store the result as it will be overwritten by the next call */
+	nmatch = sf.nr;
+	sf.nr = 0;
+	sf.ptree = ptr;
+
+	/* second pass : fill with the matching nodes */
+	tree_for_each(tree, tree_finds_cb, &sf);
+
+	return nmatch;
+}
diff --git a/tree.h b/tree.h
new file mode 100644
index 0000000..5c1c697
--- /dev/null
+++ b/tree.h
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (C) 2010, Linaro Limited.
+ *
+ * This file is part of PowerDebug.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Author:
+ *     Daniel Lezcano <daniel.lezcano@linaro.org>
+ *
+ *******************************************************************************/
+
+/*
+ * Structure describing a node of the clock tree
+ *
+ * tail  : points to the last element in the list
+ * next  : points to the next element in the list
+ * child  : points to the child node
+ * parent : points to the parent node
+ * depth  : the recursive level of the node
+ * path   : absolute pathname of the directory
+ * name   : basename of the directory
+ */
+struct tree {
+	struct tree *tail;
+	struct tree *next;
+	struct tree *prev;
+	struct tree *child;
+	struct tree *parent;
+	char *path;
+	char *name;
+	void *private;
+	int   nrchild;
+	unsigned char depth;
+};
+
+typedef int (*tree_cb_t)(struct tree *t, void *data);
+
+typedef int (*tree_filter_t)(const char *name);
+
+extern struct tree *tree_load(const char *path, tree_filter_t filter, bool follow);
+
+extern struct tree *tree_find(struct tree *tree, const char *name);
+
+extern int tree_for_each(struct tree *tree, tree_cb_t cb, void *data);
+
+extern int tree_for_each_reverse(struct tree *tree, tree_cb_t cb, void *data);
+
+extern int tree_for_each_parent(struct tree *tree, tree_cb_t cb, void *data);
+
+extern int tree_finds(struct tree *tree, const char *name, struct tree ***ptr);
diff --git a/utils.c b/utils.c
new file mode 100644
index 0000000..4d4b780
--- /dev/null
+++ b/utils.c
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (C) 2011, Linaro Limited.
+ *
+ * This file is part of PowerDebug.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Daniel Lezcano <daniel.lezcano@linaro.org> (IBM Corporation)
+ *       - initial API and implementation
+ *******************************************************************************/
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#undef _GNU_SOURCE
+#include <stdlib.h>
+
+/*
+ * This functions is a helper to read a specific file content and store
+ * the content inside a variable pointer passed as parameter, the format
+ * parameter gives the variable type to be read from the file.
+ *
+ * @path : directory path containing the file
+ * @name : name of the file to be read
+ * @format : the format of the format
+ * @value : a pointer to a variable to store the content of the file
+ * Returns 0 on success, -1 otherwise
+ */
+int file_read_value(const char *path, const char *name,
+                    const char *format, void *value)
+{
+        FILE *file;
+        char *rpath;
+        int ret;
+
+        ret = asprintf(&rpath, "%s/%s", path, name);
+        if (ret < 0)
+                return ret;
+
+        file = fopen(rpath, "r");
+        if (!file) {
+                ret = -1;
+                goto out_free;
+        }
+
+        ret = fscanf(file, format, value) == EOF ? -1 : 0;
+
+        fclose(file);
+out_free:
+        free(rpath);
+        return ret;
+}
+
+/*
+ * This functions is a helper to write a specific file content and store
+ * the content inside a variable pointer passed as parameter, the format
+ * parameter gives the variable type to be write to the file.
+ *
+ * @path : directory path containing the file
+ * @name : name of the file to be read
+ * @format : the format of the format
+ * @value : a pointer to a variable to store the content of the file
+ * Returns 0 on success, -1 otherwise
+ */
+int file_write_value(const char *path, const char *name,
+			const char *format, void *value)
+{
+	FILE *file;
+	char *rpath;
+	int ret;
+
+	ret = asprintf(&rpath, "%s/%s", path, name);
+	if (ret < 0)
+		return ret;
+
+	file = fopen(rpath, "w");
+	if (!file) {
+		ret = -1;
+		goto out_free;
+	}
+
+	ret = fprintf(file, format, value) < 0 ? -1 : 0;
+
+	fclose(file);
+out_free:
+	free(rpath);
+	return ret;
+}
diff --git a/utils.h b/utils.h
new file mode 100644
index 0000000..73159b9
--- /dev/null
+++ b/utils.h
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * Copyright (C) 2011, Linaro Limited.
+ *
+ * This file is part of PowerDebug.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Daniel Lezcano <daniel.lezcano@linaro.org> (IBM Corporation)
+ *       - initial API and implementation
+ *******************************************************************************/
+#ifndef __UTILS_H
+#define __UTILS_H
+
+extern int file_read_value(const char *path, const char *name,
+                           const char *format, void *value);
+extern int file_write_value(const char *path, const char *name,
+				const char *format, void *value);
+
+
+#endif