block_am335x_gpo.c 4.77 KB
Newer Older
Jeroen Vreeken's avatar
Jeroen Vreeken committed
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
/*
	Copyright Jeroen Vreeken (jeroen@vreeken.net), 2014

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.

 */

#include "am335x.h"

#include <controller/controller_block.h>
#include <log/log.h>


struct controller_block_private {
	bool *out;

	uint32_t bitmask;

	void *base;
};

static void gpo_calculate(struct controller_block *gpo)
{
	struct controller_block_private *priv = gpo->private;
	bool out;
	void *base = priv->base;
	size_t regoff;
	
	out = *priv->out;

	regoff = out ? 
	    AM335X_GPIO_REG_SETDATAOUT :
	    AM335X_GPIO_REG_CLEARDATAOUT;
	am335x_write32(base, regoff, gpo->private->bitmask);
}


static struct controller_block_interm_list interms[] = {
	{ "out",  CONTROLLER_BLOCK_TERM_BOOL, offsetof(struct controller_block_private, out) },
	{ NULL },
};


Jeroen Vreeken's avatar
Jeroen Vreeken committed
55
static struct controller_block * block_am335x_gpo_create(char *name, int argc, va_list ap)
Jeroen Vreeken's avatar
Jeroen Vreeken committed
56
57
58
59
60
61
62
63
{
	struct controller_block *gpo;
	void *base;
	uint32_t reg;
	uint32_t notpin;
	int gpo_nr;
	int pin_nr;
	size_t offset;
64
65
	size_t pinmux_off;
	int ret;
Jeroen Vreeken's avatar
Jeroen Vreeken committed
66
67
68
69
70
71
72
73
74
75
	
	gpo_nr = va_arg(ap, int);
	if (gpo_nr < 0 || gpo_nr > 3) {
		log_send(LOG_T_ERROR, "%s: gpio%d is not valid. (valid: 0-3)",
		    name, gpo_nr);
		return NULL;
	}
	switch (gpo_nr) {
		case 0:
			offset = AM335X_GPIO0_BASE;
76
			ret = 0;
Jeroen Vreeken's avatar
Jeroen Vreeken committed
77
78
79
			break;
		case 1:
			offset = AM335X_GPIO1_BASE;
80
			ret = am335x_cm_enable(AM335X_CM_PER_GPIO1_CLKCTRL);
Jeroen Vreeken's avatar
Jeroen Vreeken committed
81
82
83
			break;
		case 2:
			offset = AM335X_GPIO2_BASE;
84
			ret = am335x_cm_enable(AM335X_CM_PER_GPIO2_CLKCTRL);
Jeroen Vreeken's avatar
Jeroen Vreeken committed
85
86
87
			break;
		case 3:
			offset = AM335X_GPIO3_BASE;
88
			ret = am335x_cm_enable(AM335X_CM_PER_GPIO3_CLKCTRL);
Jeroen Vreeken's avatar
Jeroen Vreeken committed
89
90
			break;
	}
91
92
93
94
	if (ret) {
		log_send(LOG_T_ERROR, "%s: Could not enable clock", name);
		return NULL;
	}
Jeroen Vreeken's avatar
Jeroen Vreeken committed
95
96
97
98
99
100
101
102
	
	pin_nr = va_arg(ap, int);
	if (pin_nr < 0 || pin_nr > 31) {
		log_send(LOG_T_ERROR, "%s: pin%d is not valid. (valid: 0-31)",
		    name, pin_nr);
		return NULL;
	}
	
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
	if (am335x_pinmux_gpio_offset(gpo_nr, pin_nr, &pinmux_off)) {
		log_send(LOG_T_ERROR, 
		    "%s: pin %d_%d could not be found in pinmux",
		    name, gpo_nr, pin_nr);
		return NULL;
	}
	
	/* We don't care if the receiver is on, but try without it first*/
	if (am335x_pinmux_set(pinmux_off, 7, 0) &&
	    am335x_pinmux_set(pinmux_off, 7, AM335X_CONTROL_MODULE_PINMUX_RX)) {
		log_send(LOG_T_ERROR,
		    "%s: Could not configure pin %d_%d as GP output", 
		    name, gpo_nr, pin_nr);
	}
	
Jeroen Vreeken's avatar
Jeroen Vreeken committed
118
	base = am335x_mem(offset, AM335X_GPIO_SIZE);
Jeroen Vreeken's avatar
Jeroen Vreeken committed
119
	if (!base) {
Jeroen Vreeken's avatar
Jeroen Vreeken committed
120
		log_send(LOG_T_ERROR, "%s: Mapping GPIO failed", name);
Jeroen Vreeken's avatar
Jeroen Vreeken committed
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
		return NULL;
	}
	log_send(LOG_T_DEBUG, "%s: GPIO%d (0x%"PRIx32") mapped @ %p", name, 
	    gpo_nr, offset, base);
	
	reg = am335x_read32(base, AM335X_GPIO_REG_REVISION);
	log_send(LOG_T_DEBUG, 
	    "%s: REVISION: 0x%" PRIx32 ": func: 0x%03x rev: %d.%d",
	    name, reg, AM335X_GPIO_REVISION_FUNC_GET(reg),
	    AM335X_GPIO_REVISION_X_MAJOR_GET(reg),
	    AM335X_GPIO_REVISION_Y_MINOR_GET(reg));
	if (AM335X_GPIO_REVISION_FUNC_GET(reg) != AM335X_GPIO_REVISION_FUNC) {
		log_send(LOG_T_ERROR, "Unexpected functional number");
		goto err_rev;
	}

137
	if (!(gpo = controller_block_alloc("am335x_gpo", name, sizeof(struct controller_block_private))))
Jeroen Vreeken's avatar
Jeroen Vreeken committed
138
139
140
141
142
143
144
145
146
		goto err_alloc;

	if (controller_block_interm_list_init(gpo, interms))
		goto err_interm;

	gpo->private->base = base;
	gpo->private->bitmask = 1 << pin_nr;
	notpin = ~gpo->private->bitmask;

Jeroen Vreeken's avatar
Jeroen Vreeken committed
147
148
	am335x_write32(base, AM335X_GPIO_REG_CTRL, 0);

Jeroen Vreeken's avatar
Jeroen Vreeken committed
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
	am335x_write32(base, AM335X_GPIO_REG_LEVELDETECT0,
	    am335x_read32(base, AM335X_GPIO_REG_LEVELDETECT0) & notpin);
	am335x_write32(base, AM335X_GPIO_REG_LEVELDETECT1,
	    am335x_read32(base, AM335X_GPIO_REG_LEVELDETECT1) & notpin);
	am335x_write32(base, AM335X_GPIO_REG_RISINGDETECT,
	    am335x_read32(base, AM335X_GPIO_REG_RISINGDETECT) & notpin);
	am335x_write32(base, AM335X_GPIO_REG_FALLINGDETECT,
	    am335x_read32(base, AM335X_GPIO_REG_FALLINGDETECT) & notpin);

	am335x_write32(base, AM335X_GPIO_REG_CLEARDATAOUT,
	    gpo->private->bitmask);

	/* configure as output */
	am335x_write32(base, AM335X_GPIO_REG_OE,
	    am335x_read32(base, AM335X_GPIO_REG_OE) & notpin);

	gpo->calculate = gpo_calculate;

167
168
169
	if (controller_block_add(gpo))
		goto err_add;

Jeroen Vreeken's avatar
Jeroen Vreeken committed
170
171
	return gpo;

172
err_add:
Jeroen Vreeken's avatar
Jeroen Vreeken committed
173
174
175
176
177
178
err_interm:
	controller_block_free(gpo);
err_alloc:
err_rev:
	return NULL;
}
179
180
181
182
183

BLOCK_CREATE(am335x_gpo) = {
	.create = block_am335x_gpo_create,
	.args = { "int,int", NULL }
};