support Raspberry Pi 26-pin connector
[linux-gpio-pinout] / gpio.pl
1 #!/usr/bin/perl
2 use warnings;
3 use strict;
4 use autodie;
5 use Data::Dump qw(dump);
6 use Getopt::Long;
7
8 my $opt_svg = $ENV{SVG} || 0;
9 my $opt_alt = $ENV{ALT} || 0;
10 my $opt_invert = $ENV{INVERT} || 0;
11 my $opt_vertical = $ENV{VERTICAL} || 0;
12 my $opt_zebra = $ENV{ZEBRA} || 0;
13 my $opt_lines = $ENV{LINES} || 0;
14 GetOptions(
15         'svg!' => \$opt_svg,
16         'alt!' => \$opt_alt,
17         'invert!' => \$opt_invert,
18         'vertical!' => \$opt_vertical,
19         'zebra!' => \$opt_zebra,
20         'lines!' => \$opt_lines,
21 );
22
23 # svg font hints
24 my $font_w = 1.67; # < 2.54, font is not perfect square
25 my $font_b = 2.10; # font baseline position
26
27 sub slurp {
28         open(my $fh, '<', shift);
29         local $/ = undef;
30         <$fh>;
31 }
32
33 my $pins;
34
35 my $model = slurp('/proc/device-tree/model');
36 $model =~ s/\x00$//; # strip kernel NULL
37 warn "# model [$model]";
38
39 my @lines;
40 my $line_i = 0;
41
42 my $include = 0;
43 while(<DATA>) {
44         chomp;
45         if ( m/^#\s(.+)/ ) {
46                 warn "MODEL [$1] == [$model] ?\n";
47                 if ( $model =~ m/$1/ ) {
48                         $include = 1;
49                 } else {
50                         $include = 0;
51                 }
52         } elsif ( $include ) {
53                 push @{ $pins->{$1} }, $line_i while ( m/\t(\w+\d+)/g );
54
55                 push @lines, $_;
56
57                 $line_i++;
58         } else {
59                 warn "IGNORE: [$_]\n";
60         }
61 }
62
63 die "add pin definition for # $model" unless $pins;
64
65 shift(@lines) while ( ! $lines[0] );    # remove empty at beginning
66 pop(@lines) while ( ! $lines[-1] );     # remove empty at end
67
68 warn "# pins ",dump($pins);
69
70 my $pin_function;
71 my $device;
72
73 open(my $fh, '<', '/sys/kernel/debug/pinctrl/pinctrl-handles');
74 while(<$fh>) {
75         chomp;
76         if ( m/device: [0-9a-f]+\.(\w+)/ ) {
77                 $device = $1;
78         } elsif ( m/group: (\w+\d+)\s.+function: (\S+)/ ) {
79                 my ($pin, $function) = ($1,$2);
80                 $pin_function->{$pin} = "$device $function";
81
82                 if ( $pins->{$pin} ) {
83                         foreach my $line ( @{$pins->{$pin}} ) {
84 warn "XXX $pin $line";
85                                 my $t = $lines[$line];
86                                 if ( $opt_svg ) {
87                                         $t =~ s/$pin/[$device $function]/;
88                                 } else {
89                                         $t =~ s/$pin/$pin [$device $function]/ || die "can't find $pin in [$t]";
90                                 }
91                                 $lines[$line] = $t;
92                                 warn "# $line: $lines[$line]\n";
93                         }
94                 } else {
95                         warn "IGNORED: pin $pin function $function\n";
96                 }
97         }
98 }
99
100 warn "# pin_function = ",dump($pin_function);
101
102 my @max_len = ( 0,0,0,0 );
103 my @line_parts;
104 foreach my $line (@lines) {
105         if ( $line =~ m/^#/ ) {
106                 push @line_parts, [ $line ] unless $opt_svg;
107                 next;
108         }
109         $line =~ s/(\[(?:uart|serial))([^\t]*\]\s[^\t]*(rx|tx)d?)/$1 $3$2/gi;
110         $line =~ s/(\[i2c)([^\t]*\]\s[^\t]*(scl?k?|sda))/$1 $3$2/gi;
111         $line =~ s/(\[spi)([^\t]*\]\s[^\t]*(miso|mosi|s?clk|c[se]\d*))/$1 $3$2/gi;
112         $line =~ s/\s*\([^\)]+\)//g if ! $opt_alt;
113
114         # shorten duplicate kernel device/function
115         $line =~ s/\[serial (\w+) (uart\d+)\]/[$2 $1]/g;
116         $line =~ s/\[(\w+) (\w+) \1(\d+)\]/[$1$3 $2]/g;
117
118         my @v = split(/\s*\t+\s*/,$line,4);
119         push @line_parts, [ @v ];
120         foreach my $i ( 0 .. 3 ) {
121                 next unless exists $v[$i];
122                 next if $v[$i] =~ m/^#/; # don't calculate comments into max length
123                 my $l = length($v[$i]);
124                 $max_len[$i] = $l if $l > $max_len[$i];
125         }
126 }
127
128 warn "# max_len = ",dump( \@max_len );
129 warn "# line_parts = ",dump( \@line_parts );
130
131 #print "$_\n" foreach @lines;
132
133 my $fmt = "%$max_len[0]s %-$max_len[1]s %$max_len[2]s %-$max_len[3]s\n";
134
135 my $x = 30.00; # mm
136 my $y = 30.00; # mm
137
138 if ( $opt_svg ) {
139         print qq{<?xml version="1.0" encoding="UTF-8" standalone="no"?>
140 <svg
141    xmlns:dc="http://purl.org/dc/elements/1.1/"
142    xmlns:cc="http://creativecommons.org/ns#"
143    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
144    xmlns:svg="http://www.w3.org/2000/svg"
145    xmlns="http://www.w3.org/2000/svg"
146    xmlns:xlink="http://www.w3.org/1999/xlink"
147    id="svg8"
148    version="1.1"
149    viewBox="0 0 210 297"
150    height="297mm"
151    width="210mm">
152
153
154 <g id="layer1">
155
156         }; # svg, insert rest of rect
157
158         print qq{<rect x="0" y="0" width="210" height="297" style="fill:#000000" id="high-contrast"/>} if $opt_invert;
159 }
160
161 my @later;
162
163 my $cols = {    # foreground background
164         txt  => [ '#000000', '#ffffff' ],
165         pins => [ '#ffffff', '#ff00ff' ],
166         vcc  => [ '#ff0000', '#ffff00' ],
167         gnd  => [ '#000000', '#00ffff' ],
168         i2c  => [ '#008800', '#ffcccc' ],
169         serial=>[ '#000088', '#ccffcc' ],
170         spi  => [ '#880000', '#ccccff' ],
171 };
172
173 sub swap_cols {
174         my $swap = shift;
175         die "$swap not found in ",dump($cols) unless $cols->{$swap};
176         my ( $c1, $c2 ) = @{ $cols->{$swap} };
177         $cols->{$swap} = [ $c2, $c1 ];
178 }
179
180 swap_cols 'txt' if $opt_invert;
181         
182
183 sub svg_style {
184         my ($name,$x,$y,$col) = @_;
185         $y -= $font_b; # shift box overlay to right vertical position based on font baseline
186
187         sub rect {
188                 my ($x,$y,$col,$fill) = @_;
189                 print qq{<rect x="$x" y="$y" height="2.54" width="}, $max_len[$col] * $font_w, qq{" style="fill:$fill;stroke:#ffffff;stroke-width:0.10" />\n};
190
191         }
192
193         if ( $name =~ m/^(\d+)$/ ) { # pins
194                 my $pin = $1;
195                 my ( $fg, $bg ) = @{ $cols->{pins} };
196                 if ( $pin == 1 ) {
197                         my $w  = $max_len[$col]*$font_w - 0.1;
198                         my $cx = $x + $w;
199                         my $cy = $y + 2.54;
200                         #print qq{<polygon points="$x,$y $cx,$y $x,$cy $x,$y" stroke="$fg" stroke-width="0.25" fill="$bg" />};
201                         #print qq{<polygon points="$x,$cy $cx,$cy $cx,$y $x,$cy" stroke="$bg" stroke-width="0.25" fill="$fg" />};
202                         print qq{<rect x="$x" y="$y" width="$w" height="2.54" stroke="$fg" stroke-width="0.3" fill="$bg" />};
203                         my ( $fg, $bg ) = @{ $cols->{txt} };
204                         print qq{<rect x="$x" y="$y" width="$w" height="2.54" rx="1" ry="1" stroke="$fg" stroke-width="0.3" fill="$bg" />};
205                 } else {
206                         rect $x,$y,$col,$fg;
207                 }
208                 return qq{ style="fill:$bg"};
209         }
210
211         if ( $name =~ m/(VCC|3V3|3.3V|5v)/i ) {
212                 my ($fg,$bg) = @{ $cols->{vcc} };
213                 rect $x,$y,$col,$bg;
214                 return qq{ style="fill:$fg"};
215         } elsif ( $name =~ m/(G(ND|Round)|VSS|0v)/i ) {
216                 my ($fg,$bg) = @{ $cols->{gnd} };
217                 rect $x,$y,$col,$bg;
218                 return qq{ style="fill:$fg"};
219         } elsif ( $name =~ m/\[(\w+)/ ) { # kernel
220                 my $dev = $1;
221                 my ($fg,$bg) = @{ $cols->{txt} };
222                 ($fg,$bg) = @{ $cols->{$dev} } if exists $cols->{$dev};
223                 rect $x,$y,$col,$bg;
224                 return qq{ style="fill:$fg"};
225         } else {
226                 my ( $fg, $bg ) = @{ $cols->{txt} };
227                 rect $x,$y,$col,$bg;
228                 #return qq{ style="fill:$fg"};
229                 return '';
230         }
231 }
232
233 my $alt_col = 0;
234
235 my @cols_order = ( 0,1,2,3 );
236 my @cols_align = ( '','-','','-' ); # sprintf prefix
237
238 @cols_order = ( 0,1,3,2 ); # pins outside on the right
239 @cols_align = ( '','-','-','' );
240
241
242 # cut marks
243 my ($fg,$bg) = @{ $cols->{txt} };
244 my $line_fmt = qq{<line x1="%s" y1="%s" x2="%s" y2="%s" style="stroke:$fg;stroke-width:0.10;fill:$bg" />\n};
245
246 my @cut_marks;
247 sub cut_mark {
248         my ($x,$y) = @_;
249         return unless $opt_svg;
250         push @cut_marks, sprintf($line_fmt, $x-5, $y-$font_b,   $x+5, $y-$font_b);
251         push @cut_marks, sprintf($line_fmt, $x,   $y-$font_b-5, $x,   $y-$font_b+5);
252 }
253 cut_mark $x, $y;
254 my $max_x = $x;
255 $max_x += $max_len[$_] * $font_w foreach ( 0 .. 3 );
256 cut_mark $max_x, $y;
257
258 sub line {
259         my ($x,$y,$max_x) = @_;
260         push @cut_marks, sprintf($line_fmt, $x, $y-$font_b, $max_x, $y-$font_b);
261 }
262
263
264 my $last_cut_mark = 0;
265
266 foreach my $i ( 0 .. $#line_parts ) {
267         $i = $#line_parts - $i if $opt_vertical;
268         my $line = $line_parts[$i];
269
270         if ( $opt_svg ) {
271
272                 if ( ! exists $line->[0] ) {
273                         # before first empty line
274                         if ( $last_cut_mark == 0 ) {
275                                 cut_mark $x, $y;
276                                 cut_mark $max_x, $y;
277                                 $last_cut_mark = 1;
278                                 line $x, $y, $max_x if $opt_lines;
279                                 $y += 15; # make spacing between pinouts
280                         }
281                 } elsif ( $last_cut_mark ) {
282                         # first full line
283                         cut_mark $x, $y;
284                         cut_mark $max_x, $y;
285                         $last_cut_mark = 0;
286                 } else {
287                         #warn "CUTMARK no magic";
288                 }
289
290                 line $x, $y, $max_x if $opt_lines && exists $line->[1];
291
292                 my ($fg,$bg) = @{ $cols->{txt} };
293                 my $tspan = qq{<tspan x="$x" y="$y" style="line-height:2.54;fill:$fg;stroke:none;">\n};
294
295                 my $x_pos = $x;
296                 foreach my $i ( @cols_order ) {
297                         next unless $line->[$i];
298                         my $text_anchor = 'middle';
299                         my $x2 = $x_pos + ( $max_len[$i] * $font_w ) / 2;
300                         $tspan .= qq{<tspan x="$x2" text-anchor="$text_anchor"}.svg_style($line->[$i],$x_pos,$y,$i).sprintf( '>%' . $cols_align[$i] . $max_len[$i] . 's</tspan>', $line->[$i]);
301                         $x_pos += $max_len[$i] * $font_w;
302                 }
303
304                 $tspan .= qq{</tspan>\n};
305                 push @later,sprintf $tspan, @$line;
306                 $y += 2.54;
307
308                 # swap pin colors for line stripe
309                 if ( $opt_zebra ) {
310                         swap_cols $_ foreach qw( pins txt );
311                 }
312
313         } else {
314
315                 if ( $#$line == 0 ) {
316                         print $line->[0], "\n";
317                 } else {
318                         push @$line, '' while ($#$line < 3); # fill-in single row header
319                         printf $fmt, @$line;
320                 }
321
322         }
323 }
324
325 if ( $opt_svg ) {
326         cut_mark $x,$y;
327         cut_mark $max_x,$y;
328         line $x, $y, $max_x if $opt_lines;
329
330         print qq{
331     <text
332        id="text4506"
333        y="$x"
334        x="$y"
335        style="font-size:2.34px;line-height:2.54px;font-family:'Andale Mono';stroke:none"
336        xml:space="preserve">
337
338         }; #svg
339
340         print @later, qq{</text>\n}, @cut_marks, qq{</g>\n</svg>};
341
342 }
343
344 __DATA__
345 # Cubietech Cubieboard
346 ## U14 (Next to SATA connector)
347 ###     SPI0
348 48      PI13 (SPI0-MISO/UART6-RX/EINT25)        47      PI11 (SPI0-CLK/UART5-RX/EINT23)
349 46      PI12 (SPI0-MOSI/UART6-TX/EINT24)        45      PI10 (SPI0-CS/UART5-TX/EINT22)
350 ###     LCD
351 44      3.3V (nc in 2012-08-08)                 43      VCC-5V
352 42      Ground                                  41      SPDIF
353 40      PB10 (LCD0-SCK/LCD-PIO1)                39      PB11 (LCD0-SDA/LCD-PIO2)
354 38      Ground                                  37      PH7 (LCD0-BL-EN/LCD-PIO0/UART5-RX/EINT7)
355 36      XN_TP (TP-X2)                           35      YN_TP (TP-Y2)
356 34      XP_TP (TP-X1)                           33      YP_TP (TP-Y1)
357 32      PD25 (LCDDE)                            31      PB2 (PWM0)
358 30      PD26 (LCDHSYNC/VGA-HSYNC)               29      PD24 (LCDCLK)
359 28      PD23 (LCDD23)                           27      PD27 (LCDVSYNC/VGA-VSYNC)
360 26      PD21 (LCDD21)                           25      PD22 (LCDD22)
361 24      PD19 (LCDD19/LVDS1N3)                   23      PD20 (LCDD20)
362 22      PD17 (LCDD17/LVDS1NC)                   21      PD18 (LCDD18/LVDS1P3)
363 20      Ground                                  19      PD16 (LCDD16/LVDS1PC)
364 18      PD14 (LCDD14/LVDS1P2)                   17      PD15 (LCDD15/LVDS1N2)
365 16      PD12 (LCDD12/LVDS1P1)                   15      PD13 (LCDD13/LVDS1N1)
366 14      PD10 (LCDD10/LVDS1P0)                   13      PD11 (LCDD11/LVDS1N0)
367 12      PD8 (LCDD8/LVDS0P3)                     11      PD9 (LCDD9/LVDS0N3)
368 10      PD7 (LCDD7/LVDS0NC)                     9       Ground
369 8       PD5 (LCDD5/LVDS0N2)                     7       PD6 (LCDD6/LVDS0PC)
370 6       PD3 (LCDD3/LVDS0N1)                     5       PD4 (LCDD4/LNVS0P2)
371 4       PD1 (LCDD1/LVDS0N0)                     3       PD2 (LCDD2/LVDS0P1)
372 2       Ground                                  1       PD0 (LCDD0/LVDSP0)
373
374 ## U15 (Between Ethernet port and USB ports)
375 ### CSI1/TS
376 1       VCC-5V                                  2       PH15 (CSI1-PWR/EINT15)
377 3       CSI1-IO-2V8                             4       PH14 (CSI1-RST#/EINT14)
378 5       PG0 (CSI1-PCLK/SDC1-CMD)                6       PB18 (TWI1-SCK)
379 7       PB19 (TWI1-SDA)                         8       PG3 (CSI1-VSYNC/SDC1-D1)
380 9       PG2 (CSI1-HSYNC/SDC1-D0)                10      PG1 (CSI1-MCLK/SDC1-CLK)
381 11      PG4 (CSI1-D0/SDC1-D2)                   12      PG5 (CSI1-D1/SDC1-D3)
382 13      PG6 (CSI1-D2/UART3-TX)                  14      PG7 (CSI1-D3/UART3-RX)
383 15      PG8 (CSI1-D4/UART3-RTS)                 16      PG9 (CSI1-D5/UART3-CTS)
384 17      PG10 (CSI1-D6/UART4-TX)                 18      PG11 (CSI1-D7/UART4-RX)
385 19      Ground                                  20      Ground
386 ###     Analog SDIO3
387 21      FMINL                                   22      PI4 (SDC3-CMD)
388 23      FMINR                                   24      PI5 (SDC3-CLK)
389 25      Ground                                  26      PI6 (SDC3-D0)
390 27      VGA-R                                   28      PI7 (SDC3-D1)
391 29      VGA-G                                   30      PI8 (SDC3-D2)
392 31      VGA-B                                   32      PI9 (SDC3-D3)
393 ###     CSI0/TS
394 33      LCD1-VSYNC                              34      PE4 (CSI0-D0)
395 35      LCD1-HSYNC                              36      PE5 (CSI0-D1)
396 37      Ground                                  38      PE6 (CSI0-D2)
397 39      AVCC                                    40      PE7 (CSI0-D3)
398 41      LRADC0                                  42      PE8 (CSI0-D4)
399 43      CVBS                                    44      PE9 (CSI0-D5)
400 45      HPL                                     46      PE10 (CSI0-D6)
401 47      HPR                                     48      PE11 (CSI0-D7)
402
403 ## DEBUG serial (middle of board)
404 4       PB22 (UART0-TX)
405 3       PB23 (UART0-RX)
406 2       VCC-3V3
407 1       GND
408
409
410 # Lamobo R1
411 ## CON3 rpi DIP26-254
412 1       3.3v                    2       5v     
413 3       PB20 SDA.1              4       5V     
414 5       PB21 SCL.1              6       0v     
415 7       PI3 PWM1                8       PH0 UART3_TX
416 9       0v                      10      PH1 UART3_RX
417 11      PI19 UART2_RX           12      PH2
418 13      PI18 UART2_TX           14      0v     
419 15      PI17 UART2_CTS          16      PH21 CAN_RX 
420 17      3.3v                    18      PH20 CAN_TX 
421 19      PI12 SPI0_MOSI          20      0v     
422 21      PI13 SPI0_MISO          22      PI16 UART2_RTS   
423 23      PI11 SPI0_SCLK          24      PI10 SPI0_CS0    
424 25      0v                      26      PI14 SPI0_CS1
425
426 ## J13 DIP2-254
427 2       PB22 UART0_TX
428 1       PB23 UART0_RX
429
430 ## J12 DIP8-254
431 8       GND                     7       GND
432 6       PI20 UART7_TX           5       PH3
433 4       PI21 UART7_RX           3       PH5
434 2       3V3                     1       SATA-5V
435
436 # Raspberry Pi
437 1       3.3v                    2       5v
438 3       gpio2 (SDA.1)           4       5v
439 5       gpio3 (SCL.1)           6       0v
440 7       gpio4 (WPi 7)           8       gpio14  (TxD)
441 9       0v                      10      gpio15  (RxD)
442 11      gpio17 (WPi 0)          12      gpio18  (WPi 1)
443 13      gpio27 (WPi 2)          14      0v
444 15      gpio22 (WPi 3)          16      gpio23  (WPi 4)
445 17      3.3v                    18      gpio24  (WPi 5)
446 19      gpio10 (MOSI)           20      0v
447 21      gpio9 (MISO)            22      gpio25  (WPi 6) 
448 23      gpio11 (SCLK)           24      gpio8   (CE0)
449 25      0v                      26      gpio7   (CE1)
450 # Raspberry Pi 3 Model B Rev 1.2
451 27      gpio0 (SDA.0)           28      gpio1   (SCL.0)
452 29      gpio5 (WPi 21)          30      0v
453 31      gpio6 (WPi 22)          32      gpio12  (WPi 26)
454 33      gpio13 (WPi 23)         34      0v
455 35      gpio19 (WPi 24)         36      gpio16  (WPi 27)
456 37      gpio26 (WPi 25)         38      gpio20  (WPi 28)
457 39      0v                      40      gpio21  (WPi 29)
458