summaryrefslogtreecommitdiffstats
path: root/drivers/gpio/sandbox.c
blob: 3c6cfec179dc2f0988ecc3ef54f33d9725c463de (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
181
182
183
184
185
186
187
188
189
190
191
192
193
/*
 * Copyright (c) 2011 The Chromium OS Authors.
 * SPDX-License-Identifier:	GPL-2.0+
 */

#include <common.h>
#include <asm/gpio.h>

/* Flags for each GPIO */
#define GPIOF_OUTPUT	(1 << 0)	/* Currently set as an output */
#define GPIOF_HIGH	(1 << 1)	/* Currently set high */
#define GPIOF_RESERVED	(1 << 2)	/* Is in use / requested */

struct gpio_state {
	const char *label;	/* label given by requester */
	u8 flags;		/* flags (GPIOF_...) */
};

/*
 * State of GPIOs
 * TODO: Put this into sandbox state
 */
static struct gpio_state state[CONFIG_SANDBOX_GPIO_COUNT];

/* Access routines for GPIO state */
static u8 *get_gpio_flags(unsigned gp)
{
	/* assert()'s could be disabled, so make sure we handle that */
	assert(gp < ARRAY_SIZE(state));
	if (gp >= ARRAY_SIZE(state)) {
		static u8 invalid_flags;
		printf("sandbox_gpio: error: invalid gpio %u\n", gp);
		return &invalid_flags;
	}

	return &state[gp].flags;
}

static int get_gpio_flag(unsigned gp, int flag)
{
	return (*get_gpio_flags(gp) & flag) != 0;
}

static int set_gpio_flag(unsigned gp, int flag, int value)
{
	u8 *gpio = get_gpio_flags(gp);

	if (value)
		*gpio |= flag;
	else
		*gpio &= ~flag;

	return 0;
}

static int check_reserved(unsigned gpio, const char *func)
{
	if (!get_gpio_flag(gpio, GPIOF_RESERVED)) {
		printf("sandbox_gpio: %s: error: gpio %u not reserved\n",
			func, gpio);
		return -1;
	}

	return 0;
}

/*
 * Back-channel sandbox-internal-only access to GPIO state
 */

int sandbox_gpio_get_value(unsigned gp)
{
	if (get_gpio_flag(gp, GPIOF_OUTPUT))
		debug("sandbox_gpio: get_value on output gpio %u\n", gp);
	return get_gpio_flag(gp, GPIOF_HIGH);
}

int sandbox_gpio_set_value(unsigned gp, int value)
{
	return set_gpio_flag(gp, GPIOF_HIGH, value);
}

int sandbox_gpio_get_direction(unsigned gp)
{
	return get_gpio_flag(gp, GPIOF_OUTPUT);
}

int sandbox_gpio_set_direction(unsigned gp, int output)
{
	return set_gpio_flag(gp, GPIOF_OUTPUT, output);
}

/*
 * These functions implement the public interface within U-Boot
 */

/* set GPIO port 'gp' as an input */
int gpio_direction_input(unsigned gp)
{
	debug("%s: gp:%u\n", __func__, gp);

	if (check_reserved(gp, __func__))
		return -1;

	return sandbox_gpio_set_direction(gp, 0);
}

/* set GPIO port 'gp' as an output, with polarity 'value' */
int gpio_direction_output(unsigned gp, int value)
{
	debug("%s: gp:%u, value = %d\n", __func__, gp, value);

	if (check_reserved(gp, __func__))
		return -1;

	return sandbox_gpio_set_direction(gp, 1) |
		sandbox_gpio_set_value(gp, value);
}

/* read GPIO IN value of port 'gp' */
int gpio_get_value(unsigned gp)
{
	debug("%s: gp:%u\n", __func__, gp);

	if (check_reserved(gp, __func__))
		return -1;

	return sandbox_gpio_get_value(gp);
}

/* write GPIO OUT value to port 'gp' */
int gpio_set_value(unsigned gp, int value)
{
	debug("%s: gp:%u, value = %d\n", __func__, gp, value);

	if (check_reserved(gp, __func__))
		return -1;

	if (!sandbox_gpio_get_direction(gp)) {
		printf("sandbox_gpio: error: set_value on input gpio %u\n", gp);
		return -1;
	}

	return sandbox_gpio_set_value(gp, value);
}

int gpio_request(unsigned gp, const char *label)
{
	debug("%s: gp:%u, label:%s\n", __func__, gp, label);

	if (gp >= ARRAY_SIZE(state)) {
		printf("sandbox_gpio: error: invalid gpio %u\n", gp);
		return -1;
	}

	if (get_gpio_flag(gp, GPIOF_RESERVED)) {
		printf("sandbox_gpio: error: gpio %u already reserved\n", gp);
		return -1;
	}

	state[gp].label = label;
	return set_gpio_flag(gp, GPIOF_RESERVED, 1);
}

int gpio_free(unsigned gp)
{
	debug("%s: gp:%u\n", __func__, gp);

	if (check_reserved(gp, __func__))
		return -1;

	state[gp].label = NULL;
	return set_gpio_flag(gp, GPIOF_RESERVED, 0);
}

/* Display GPIO information */
void gpio_info(void)
{
	unsigned gpio;

	puts("Sandbox GPIOs\n");

	for (gpio = 0; gpio < ARRAY_SIZE(state); ++gpio) {
		const char *label = state[gpio].label;

		printf("%4d: %s: %d [%c] %s\n",
			gpio,
			sandbox_gpio_get_direction(gpio) ? "out" : " in",
			sandbox_gpio_get_value(gpio),
			get_gpio_flag(gpio, GPIOF_RESERVED) ? 'x' : ' ',
			label ? label : "");
	}
}
OpenPOWER on IntegriCloud