summaryrefslogtreecommitdiff
path: root/src/soc/nvidia/tegra/gpio.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/soc/nvidia/tegra/gpio.c')
-rw-r--r--src/soc/nvidia/tegra/gpio.c53
1 files changed, 53 insertions, 0 deletions
diff --git a/src/soc/nvidia/tegra/gpio.c b/src/soc/nvidia/tegra/gpio.c
index 4cf6d5f43a..ac0fc3f986 100644
--- a/src/soc/nvidia/tegra/gpio.c
+++ b/src/soc/nvidia/tegra/gpio.c
@@ -22,6 +22,7 @@
#include <soc/addressmap.h>
#include <stddef.h>
#include <stdint.h>
+#include <delay.h>
#include "gpio.h"
#include "pinmux.h"
@@ -174,6 +175,58 @@ int gpio_get_in_value(gpio_t gpio)
return (port & (1 << bit)) != 0;
}
+int gpio_get_in_tristate_values(gpio_t gpio[], int num_gpio, int value[])
+{
+ /*
+ * 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.
+ */
+
+ int temp;
+ int index;
+
+ /* 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_in_value(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
+ */
+ for (index = 0; index < num_gpio; ++index) {
+ temp = gpio_get_in_value(gpio[index]);
+ value[index] = ((value[index] ^ temp) << 1) | temp;
+ }
+
+ /* Disable pull up / pull down to conserve power */
+ for (index = 0; index < num_gpio; ++index)
+ gpio_input(gpio[index]);
+
+ return 0;
+}
+
int gpio_get_int_status(gpio_t gpio)
{
int bit = gpio % GPIO_GPIOS_PER_PORT;