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 meraj.molla@samsung.com + * (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 meraj.molla@samsung.com + * (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