1// Copyright © 2021 Sören Tempel
2//
3// This program is free software: you can redistribute it and/or modify
4// it under the terms of the GNU Affero General Public License as
5// published by the Free Software Foundation, either version 3 of the
6// License, or (at your option) any later version.
7//
8// This program is distributed in the hope that it will be useful, but
9// WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11// Affero General Public License for more details.
12//
13// You should have received a copy of the GNU Affero General Public License
14// along with this program. If not, see <https://www.gnu.org/licenses/>.
15
16// Maximum of 32 pins -> 2**5 = 32.
17pub const Pin = u5;
18
19pub const Mode = enum {
20 IN,
21 OUT,
22};
23
24pub fn pin(x: Pin, y: Pin) Pin {
25 return x | y;
26}
27
28pub const Gpio = struct {
29 base_addr: usize,
30
31 const Reg = enum(usize) {
32 input = 0x04,
33 output_en = 0x08,
34 output_val = 0x0c,
35 pue = 0x10,
36 iof_en = 0x38,
37 iof_sel = 0x3c,
38 };
39
40 fn readWord(self: Gpio, reg: Reg) u32 {
41 const ptr = @intToPtr(*volatile u32, self.base_addr + @enumToInt(reg));
42 return ptr.*;
43 }
44
45 fn writeWord(self: Gpio, reg: Reg, value: u32) void {
46 const ptr = @intToPtr(*volatile u32, self.base_addr + @enumToInt(reg));
47 ptr.* = value;
48 }
49
50 pub fn setRegister(self: Gpio, reg: Reg, x: Pin, val: u1) void {
51 const regVal = self.readWord(reg);
52
53 const mask = @as(u32, 1) << x;
54 if (val == 0) {
55 self.writeWord(reg, regVal & ~mask);
56 } else {
57 self.writeWord(reg, regVal | mask);
58 }
59 }
60
61 // Configure a GPIO pin as IOF controlled (instead of software controlled).
62 pub fn setIOFCtrl(self: Gpio, x: Pin, select: u1) void {
63 // Select one of the two HW-Driven functions.
64 self.setRegister(Reg.iof_sel, x, select);
65
66 // Enable selected HW-Driven function.
67 self.setRegister(Reg.iof_en, x, 1);
68 }
69
70 pub fn set(self: Gpio, x: Pin, v: u1) void {
71 self.setRegister(Reg.output_val, x, v);
72 }
73
74 pub fn init(self: Gpio, x: Pin, mode: Mode) void {
75 switch (mode) {
76 Mode.IN => {
77 self.setRegister(Reg.input, x, 1);
78 self.setRegister(Reg.output_en, x, 0);
79 self.setRegister(Reg.pue, x, 0);
80 },
81 Mode.OUT => {
82 self.setRegister(Reg.input, x, 0);
83 self.setRegister(Reg.output_en, x, 1);
84 self.setRegister(Reg.pue, x, 0);
85 },
86 }
87
88 // Disable HW-driven functions for Pin
89 self.setRegister(Reg.iof_en, x, 0);
90 self.setRegister(Reg.iof_sel, x, 0);
91 }
92};