Add support for pinctrl in powerdebug. Both dump and display
modes supported. Tested only on Samsung Arndale board.
Sample output in display mode on Arndale Board -
Pin Name MUX Owner GPIO Owner HOG Function
Group
0 gpa0-0 MUX UNCLAIMED GPIO UNCLAIMED
1 gpa0-1 MUX UNCLAIMED GPIO UNCLAIMED
2 gpa0-2 MUX UNCLAIMED GPIO UNCLAIMED
3 gpa0-3 MUX UNCLAIMED GPIO UNCLAIMED
4 gpa0-4 MUX UNCLAIMED GPIO UNCLAIMED
5 gpa0-5 MUX UNCLAIMED GPIO UNCLAIMED
6 gpa0-6 12c80000.i2c GPIO UNCLAIMED i2c2-bus-mux
i2c2-bus-grp
7 gpa0-7 12c80000.i2c GPIO UNCLAIMED i2c2-bus-mux
i2c2-bus-grp
8 gpa1-0 MUX UNCLAIMED GPIO UNCLAIMED
9 gpa1-1 MUX UNCLAIMED GPIO UNCLAIMED
10 gpa1-2 12c90000.i2c GPIO UNCLAIMED i2c3-bus-mux
i2c3-bus-grp
11 gpa1-3 12c90000.i2c GPIO UNCLAIMED i2c3-bus-mux
i2c3-bus-grp
---
Android.mk | 2 +-
Makefile | 2 +-
README | 4 +-
display.c | 3 +-
display.h | 2 +-
pinctrl.c | 329 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
pinctrl.h | 19 ++++
powerdebug.c | 35 +++++--
8 files changed, 381 insertions(+), 15 deletions(-)
create mode 100644 pinctrl.c
create mode 100644 pinctrl.h
diff --git a/Android.mk b/Android.mk
index 36c73cd..19d00ca 100644
--- a/Android.mk
+++ b/Android.mk
@@ -29,6 +29,6 @@ LOCAL_C_INCLUDES += external/stlport/stlport/ \
LOCAL_SRC_FILES += \
powerdebug.c sensor.c clocks.c regulator.c \
- display.c tree.c utils.c mainloop.c gpio.c
+ display.c tree.c utils.c mainloop.c gpio.c pinctrl.c
include $(BUILD_EXECUTABLE)
diff --git a/Makefile b/Makefile
index 2da9d67..f002438 100644
--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,7 @@ CFLAGS?=-O1 -g -Wall -Wshadow
CC?=gcc
OBJS = powerdebug.o sensor.o clocks.o regulator.o gpio.o \
- display.o tree.o utils.o mainloop.o
+ display.o tree.o utils.o mainloop.o pinctrl.o
default: powerdebug
diff --git a/README b/README
index 1479db1..b24dd98 100644
--- a/README
+++ b/README
@@ -1,8 +1,8 @@
powerdebug
----------
-This is a new tool which displays regulator, sensor and clock tree
-information.
+This is a new tool which displays regulator, sensor, clock tree, gpio and
+pinctrl information.
Current version only displays regulator information and clock tree from
debugfs. Support will be added for sensors later.
diff --git a/display.c b/display.c
index 0000ee9..fb899c0 100644
--- a/display.c
+++ b/display.c
@@ -63,7 +63,8 @@ struct windata windata[] = {
[CLOCK] = { .name = "Clocks" },
[REGULATOR] = { .name = "Regulators" },
[SENSOR] = { .name = "Sensors" },
- [GPIO] = { .name = "Gpio" },
+ [GPIO] = { .name = "Gpio" },
+ [PINCTRL] = { .name = "Pins" },
};
static void display_fini(void)
diff --git a/display.h b/display.h
index e3a1529..4496f30 100644
--- a/display.h
+++ b/display.h
@@ -13,7 +13,7 @@
* - initial API and implementation
*******************************************************************************/
-enum { CLOCK, REGULATOR, SENSOR, GPIO };
+enum { CLOCK, REGULATOR, SENSOR, GPIO, PINCTRL };
struct display_ops {
int (*display)(bool refresh);
diff --git a/pinctrl.c b/pinctrl.c
new file mode 100644
index 0000000..eef06e2
--- /dev/null
+++ b/pinctrl.c
@@ -0,0 +1,329 @@
+
+/*******************************************************************************
+ * Copyright (C) 2014, 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:
+ * Mohammad Merajul Islam Molla <[email protected]>
+ * (Samsung R&D Institute Bangladesh)
+ * - initial API and implementation
+
*******************************************************************************/
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#include <stdio.h>
+#undef _GNU_SOURCE
+#endif
+#include <string.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "pinctrl.h"
+#include "display.h"
+
+#define SIZE 64
+#define MAX_PINS 256
+
+#define PIN_fmt "%*[^ ] %d"
+#define NAME_fmt "%*[^(]( %s"
+#define MUX_fmt "%*[^:]: %s"
+#define GPIO_fmt "%*[^:]: %*[^ ] %s"
+#define GPIO_fmt1 "%*[^:]: %*[^ ] %*[^ ] %s"
+
+#define SYS_PINCTRL "/sys/kernel/debug/pinctrl"
+
+static bool pinctrl_error = false;
+
+static struct pintcrl_info {
+ int pin;
+ char name[SIZE];
+ char mux_owner[SIZE];
+ char gpio_owner[SIZE];
+ char hog[SIZE];
+ char function[SIZE];
+ char group[SIZE];
+} pins_info[MAX_PINS];
+
+static int fill_pinctrl_info();
+
+static int pinctrl_print_header(void)
+{
+ char *buf;
+ int ret;
+
+ if (asprintf(&buf, "%-5s %-10s %-15s %-15s %-5s %-20s %-20s",
+ "Pin", "Name", "MUX Owner", "GPIO Owner", "HOG",
"Function",
+ "Group") < 0)
+ return -1;
+
+ ret = display_column_name(buf);
+
+ free(buf);
+
+ return ret;
+}
+
+static char *pin_line(int pin)
+{
+ char *pinline = 0;
+
+ if (asprintf(&pinline,"%-5d %-10s %-15s %-15s %-5s %-20s %-20s",
+ pins_info[pin].pin, pins_info[pin].name,
+ pins_info[pin].mux_owner, pins_info[pin].gpio_owner,
+ pins_info[pin].hog, pins_info[pin].function,
+ pins_info[pin].group) < 0)
+ return NULL;
+
+ return pinline;
+}
+
+static int pinctrl_print_info()
+{
+ int i;
+ int line = 0;
+ char *buffer;
+
+ display_reset_cursor(PINCTRL);
+
+ pinctrl_print_header();
+
+ for (i = 0; i < MAX_PINS; i++) {
+ if (pins_info[i].pin == -1)
+ continue;
+
+ buffer = pin_line(i);
+ if (!buffer)
+ return -1;
+
+ display_print_line(PINCTRL, line, buffer, 0, NULL);
+ line++;
+
+ free(buffer);
+ }
+
+ display_refresh_pad(PINCTRL);
+
+ return 0;
+}
+
+static int dump_pinctrl_info()
+{
+ int i;
+
+ for (i = 0; i < MAX_PINS; i++) {
+ if (pins_info[i].pin == -1)
+ continue;
+ printf("\tPin %d: (Name: %s, MUX_owner: %s,
GPIO_owner: %s, HOG: %s, Function: %s, Group: %s)\n",
+ pins_info[i].pin, pins_info[i].name,
+ pins_info[i].mux_owner, pins_info[i].gpio_owner,
+ pins_info[i].hog,
+ pins_info[i].function, pins_info[i].group);
+ }
+
+ return 0;
+}
+
+
+int pinctrl_dump()
+{
+ int ret;
+
+ if (pinctrl_error)
+ return -1;
+
+ printf("\nPin Information:\n");
+ printf("****************\n");
+ ret = dump_pinctrl_info();
+ printf("\n\n");
+
+ return ret;
+
+}
+
+static int pinctrl_display(bool refresh)
+{
+ if (pinctrl_error) {
+ display_message(PINCTRL,
+ "error: path " SYS_PINCTRL " not found or not root");
+ return -2;
+ }
+
+ if (refresh && fill_pinctrl_info())
+ return -1;
+
+ return pinctrl_print_info();
+}
+
+static struct display_ops pinctrl_ops = {
+ .display = pinctrl_display,
+};
+
+static int read_pin_info(const char *path)
+{
+ FILE *fpinmux;
+ int pin;
+ int ret = 0;
+ char *p;
+ char buf[4096];
+
+ fpinmux = fopen(path, "r");
+ if (!fpinmux) {
+ printf("error: failed to read %s\n", path);
+ return -1;
+ }
+
+ /* first two lines are headers, ignore */
+ fgets(buf, 4096, fpinmux);
+ fgets(buf, 4096, fpinmux);
+
+ while (fgets(buf, 4096, fpinmux)) {
+ int mux_owner = 0;
+
+ /* get pin number */
+ sscanf(buf, PIN_fmt, &pin);
+
+ if (pin >= MAX_PINS) {
+ printf("WARNING: # of pins > max pins (256),
need to increase limit\n");
+ continue;
+ }
+
+ pins_info[pin].pin = pin;
+ sscanf(buf, NAME_fmt, pins_info[pin].name);
+ pins_info[pin].name[strlen(pins_info[pin].name) - 2] = '\0';
+
+ if (strstr(buf, "MUX UNCLAIMED"))
+ strcpy(pins_info[pin].mux_owner, "MUX UNCLAIMED");
+ else {
+ sscanf(buf, MUX_fmt, pins_info[pin].mux_owner);
+ mux_owner = 1;
+ }
+
+ if (strstr(buf, "GPIO UNCLAIMED"))
+ strcpy(pins_info[pin].gpio_owner, "GPIO UNCLAIMED");
+ else {
+ if (mux_owner)
+ sscanf(buf, GPIO_fmt,
pins_info[pin].gpio_owner);
+ else
+ sscanf(buf, GPIO_fmt1,
pins_info[pin].gpio_owner);
+ }
+
+ if (strstr(buf, "HOG"))
+ strcpy(pins_info[pin].hog, "HOG");
+ else
+ strcpy(pins_info[pin].hog, "");
+
+ if ((p = strstr(buf, "function"))) {
+ p += 9;
+ sscanf(p, "%s", pins_info[pin].function);
+ }
+ else
+ strcpy(pins_info[pin].function, "");
+
+ if ((p = strstr(buf, "group"))) {
+ p += 5;
+ sscanf(p, "%s", pins_info[pin].group);
+ }
+ else
+ strcpy(pins_info[pin].group, "");
+ }
+
+ fclose(fpinmux);
+ return ret;
+}
+
+static void init_pins_info()
+{
+ int i;
+
+ memset(pins_info, 0, sizeof(pins_info));
+
+ for (i = 0; i < MAX_PINS; i++)
+ pins_info[i].pin = -1;
+}
+
+static int fill_pinctrl_info()
+{
+ DIR *dir;
+ char *newpath, *pinmux_path;
+ struct dirent dirent, *direntp;
+ struct stat s;
+ int ret = 0;
+
+ dir = opendir(SYS_PINCTRL);
+ if (!dir) {
+ printf("error: unable to open directory " SYS_PINCTRL);
+ ret = -1;
+ goto out;
+ }
+
+ init_pins_info();
+
+ while (!readdir_r(dir, &dirent, &direntp)) {
+ ret = 0;
+
+ if (!direntp)
+ break;
+
+ if (direntp->d_name[0] == '.')
+ continue;
+
+ ret = asprintf(&newpath, "%s/%s", SYS_PINCTRL, direntp->d_name);
+ if (ret < 0)
+ goto out;
+
+ ret = stat(newpath, &s);
+ if (ret)
+ goto out_free_newpath;
+
+ if (S_ISDIR(s.st_mode)) {
+ ret = asprintf(&pinmux_path, "%s/%s", newpath,
+ "pinmux-pins");
+ if (ret < 0)
+ goto out_free_newpath;
+
+ if (read_pin_info(pinmux_path)) {
+ ret = -1;
+ goto out_free_pinmux;
+ }
+ }
+ }
+
+out_free_pinmux:
+ free(pinmux_path);
+
+out_free_newpath:
+ free(newpath);
+
+out:
+ closedir(dir);
+ return ret;
+}
+
+int pinctrl_init(void)
+{
+ int ret = 0;
+
+ ret = display_register(PINCTRL, &pinctrl_ops);
+ if (ret)
+ printf("error: pinctrl display register failed");
+
+ if (access(SYS_PINCTRL, F_OK)) {
+ pinctrl_error = true;
+ return -1;
+ }
+
+ if (fill_pinctrl_info())
+ return -1;
+
+ return ret;
+}
diff --git a/pinctrl.h b/pinctrl.h
new file mode 100644
index 0000000..2fa4f3a
--- /dev/null
+++ b/pinctrl.h
@@ -0,0 +1,19 @@
+/*******************************************************************************
+ * Copyright (C) 2014, 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:
+ * Mohammad merajul Islam Molla <[email protected]>
+ * (Samsung R&D Institute Bangladesh)
+ *
+ * - initial API and implementation
+
*******************************************************************************/
+
+extern int pinctrl_init(void);
+extern int pinctrl_dump(void);
diff --git a/powerdebug.c b/powerdebug.c
index 6cf3a1b..b4f4833 100644
--- a/powerdebug.c
+++ b/powerdebug.c
@@ -26,6 +26,7 @@
#include "clocks.h"
#include "sensor.h"
#include "gpio.h"
+#include "pinctrl.h"
#include "mainloop.h"
#include "powerdebug.h"
@@ -35,13 +36,14 @@ void usage(void)
{
printf("Usage: powerdebug [OPTIONS]\n");
printf("\n");
- printf("powerdebug -d [ -r ] [ -s ] [ -c [ -p <clock-name> ] ] "
+ printf("powerdebug -d [ -r ] [ -s ] [ -p ][ -c [ -P <clock-name> ] ] "
"[ -v ]\n");
- printf("powerdebug [ -r | -s | -c ]\n");
+ printf("powerdebug [ -r | -s | -c | -p] \n");
printf(" -r, --regulator Show regulator information\n");
printf(" -s, --sensor Show sensor information\n");
printf(" -c, --clock Show clock information\n");
- printf(" -p, --findparents Show all parents for a particular"
+ printf(" -p, --pin Show pin information\n");
+ printf(" -P, --findparents Show all parents for a particular"
" clock\n");
printf(" -t, --time Set ticktime in seconds (eg. 10.0)\n");
printf(" -d, --dump Dump information once (no refresh)\n");
@@ -62,7 +64,8 @@ void version()
* -s, --sensor : sensors
* -c, --clock : clocks
* -g, --gpio : gpios
- * -p, --findparents : clockname whose parents have to be found
+ * -p, --pin : pins
+ * -P, --findparents : clockname whose parents have to be found
* -t, --time : ticktime
* -d, --dump : dump
* -v, --verbose : verbose
@@ -76,7 +79,8 @@ static struct option long_options[] = {
{ "sensor", 0, 0, 's' },
{ "clock", 0, 0, 'c' },
{ "gpio", 0, 0, 'g' },
- { "findparents", 1, 0, 'p' },
+ { "pin", 0 , 0, 'p' },
+ { "findparents", 1, 0, 'P' },
{ "time", 1, 0, 't' },
{ "dump", 0, 0, 'd' },
{ "verbose", 0, 0, 'v' },
@@ -91,6 +95,7 @@ struct powerdebug_options {
bool sensors;
bool clocks;
bool gpios;
+ bool pins;
bool dump;
unsigned int ticktime;
int selectedwindow;
@@ -108,7 +113,7 @@ int getoptions(int argc, char *argv[], struct
powerdebug_options *options)
while (1) {
int optindex = 0;
- c = getopt_long(argc, argv, "rscgp:t:dvVh",
+ c = getopt_long(argc, argv, "rscgpP:t:dvVh",
long_options, &optindex);
if (c == -1)
break;
@@ -131,6 +136,10 @@ int getoptions(int argc, char *argv[], struct
powerdebug_options *options)
options->selectedwindow = GPIO;
break;
case 'p':
+ options->pins = true;
+ options->selectedwindow = PINCTRL;
+ break;
+ case 'P':
options->clkname = strdup(optarg);
if (!options->clkname) {
fprintf(stderr, "failed to allocate memory");
@@ -161,9 +170,9 @@ int getoptions(int argc, char *argv[], struct
powerdebug_options *options)
/* 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;
+ !options->sensors && !options->gpios && !options->pins)
+ options->regulators = options->clocks = options->sensors =
+ options->gpios = options->pins = true;
if (options->selectedwindow == -1)
options->selectedwindow = CLOCK;
@@ -185,6 +194,9 @@ static int powerdebug_dump(struct
powerdebug_options *options)
if (options->gpios)
gpio_dump();
+ if (options->pins)
+ pinctrl_dump();
+
return 0;
}
@@ -266,6 +278,11 @@ int main(int argc, char **argv)
options->gpios = false;
}
+ if (pinctrl_init()) {
+ printf("failed to initialize pinctrl\n");
+ options->pins = false;
+ }
+
ret = options->dump ? powerdebug_dump(options) :
powerdebug_display(options);
--
Thanks,
-Meraj
_______________________________________________
linaro-dev mailing list
[email protected]
http://lists.linaro.org/mailman/listinfo/linaro-dev