summaryrefslogtreecommitdiffstats
path: root/src/lib/gpio.c
blob: c25b3f9f85e68d820e6da04071a70fd4268c9a05 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
/* SPDX-License-Identifier: GPL-2.0-only */
/* This file is part of the coreboot project. */

#include <base3.h>
#include <console/console.h>
#include <delay.h>
#include <gpio.h>

static void _check_num(const char *name, int num)
{
	if ((num > 31) || (num < 1)) {
		printk(BIOS_EMERG, "%s: %d ", name, num);
		die("is an invalid number of GPIOs");
	}
}

static uint32_t _gpio_base2_value(const gpio_t gpio[], int num_gpio)
{
	uint32_t result = 0;
	int i;

	/* Wait until signals become stable */
	udelay(10);

	for (i = 0; i < num_gpio; i++)
		result |= gpio_get(gpio[i]) << i;

	return result;
}

uint32_t gpio_base2_value(const gpio_t gpio[], int num_gpio)
{
	int i;

	_check_num(__func__, num_gpio);
	for (i = 0; i < num_gpio; i++)
		gpio_input(gpio[i]);

	return _gpio_base2_value(gpio, num_gpio);
}

uint32_t gpio_pulldown_base2_value(const gpio_t gpio[], int num_gpio)
{
	int i;

	_check_num(__func__, num_gpio);
	for (i = 0; i < num_gpio; i++)
		gpio_input_pulldown(gpio[i]);

	return _gpio_base2_value(gpio, num_gpio);
}

uint32_t gpio_pullup_base2_value(const gpio_t gpio[], int num_gpio)
{
	int i;

	_check_num(__func__, num_gpio);
	for (i = 0; i < num_gpio; i++)
		gpio_input_pullup(gpio[i]);

	return _gpio_base2_value(gpio, num_gpio);
}

uint32_t _gpio_base3_value(const gpio_t gpio[], int num_gpio, int binary_first)
{
	/*
	 * GPIOs which are tied to stronger external pull up or pull down
	 * will stay there regardless of the internal pull up or pull
	 * down setting.
	 *
	 * GPIOs which are floating will go to whatever level they're
	 * internally pulled to.
	 */

	static const char tristate_char[] = {[0] = '0', [1] = '1', [Z] = 'Z'};
	uint32_t result = 0;
	int has_z = 0;
	int binary_below = 0;
	int index;
	int temp;
	char value[32];

	_check_num(__func__, num_gpio);

	/* Enable internal pull up */
	for (index = 0; index < num_gpio; ++index)
		gpio_input_pullup(gpio[index]);

	/* Wait until signals become stable */
	udelay(10);

	/* Get gpio values at internal pull up */
	for (index = 0; index < num_gpio; ++index)
		value[index] = gpio_get(gpio[index]);

	/* Enable internal pull down */
	for (index = 0; index < num_gpio; ++index)
		gpio_input_pulldown(gpio[index]);

	/* Wait until signals become stable */
	udelay(10);

	/*
	 * Get gpio values at internal pull down.
	 * Compare with gpio pull up value and then
	 * determine a gpio final value/state:
	 *  0: pull down
	 *  1: pull up
	 *  2: floating
	 */
	printk(BIOS_DEBUG, "Reading tristate GPIOs: ");
	for (index = num_gpio - 1; index >= 0; --index) {
		temp = gpio_get(gpio[index]);
		temp |= ((value[index] ^ temp) << 1);
		printk(BIOS_DEBUG, "%c ", tristate_char[temp]);
		result = (result * 3) + temp;

		/*
		 * For binary_first we keep track of the normal ternary result
		 * and whether we found any pin that was a Z. We also determine
		 * the amount of numbers that can be represented with only
		 * binary digits (no Z) whose value in the normal ternary system
		 * is lower than the one we are parsing. Counting from the left,
		 * we add 2^i for any '1' digit to account for the binary
		 * numbers whose values would be below it if all following
		 * digits we parsed would be '0'. As soon as we find a '2' digit
		 * we can total the remaining binary numbers below as 2^(i+1)
		 * because we know that all binary representations counting only
		 * this and following digits must have values below our number
		 * (since 1xxx is always smaller than 2xxx).
		 *
		 * Example: 1 0 2 1 (counting from the left / most significant)
		 * '1' at 3^3: Add 2^3 = 8 to account for binaries 0000-0111
		 * '0' at 3^2: Ignore (not all binaries 1000-1100 are below us)
		 * '2' at 3^1: Add 2^(1+1) = 4 to account for binaries 1000-1011
		 * Stop adding for lower digits (3^0), all already accounted
		 * now. We know that there can be no binary numbers 1020-102X.
		 */
		if (binary_first && !has_z) {
			switch (temp) {
			case 0:	/* Ignore '0' digits. */
				break;
			case 1:	/* Account for binaries 0 to 2^index - 1. */
				binary_below += 1 << index;
				break;
			case 2:	/* Account for binaries 0 to 2^(index+1) - 1. */
				binary_below += 1 << (index + 1);
				has_z = 1;
			}
		}
	}

	if (binary_first) {
		if (has_z)
			result = result + (1 << num_gpio) - binary_below;
		else /* binary_below is normal binary system value if !has_z. */
			result = binary_below;
	}

	printk(BIOS_DEBUG, "= %d (%s base3 number system)\n", result,
	       binary_first ? "binary_first" : "standard");

	/* Disable pull up / pull down to conserve power */
	for (index = 0; index < num_gpio; ++index)
		gpio_input(gpio[index]);

	return result;
}

/* Default handler for ACPI path is to return NULL */
__weak const char *gpio_acpi_path(gpio_t gpio)
{
	return NULL;
}

/* Default handler returns 0 because type of gpio_t is unknown */
__weak uint16_t gpio_acpi_pin(gpio_t gpio)
{
	return 0;
}