xref: /minix3/minix/lib/libgpio/gpio_omap.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
1*433d6423SLionel Sambuc /* kernel headers */
2*433d6423SLionel Sambuc #include <minix/syslib.h>
3*433d6423SLionel Sambuc #include <minix/drvlib.h>
4*433d6423SLionel Sambuc #include <minix/log.h>
5*433d6423SLionel Sambuc #include <minix/mmio.h>
6*433d6423SLionel Sambuc #include <minix/gpio.h>
7*433d6423SLionel Sambuc #include <minix/clkconf.h>
8*433d6423SLionel Sambuc #include <minix/type.h>
9*433d6423SLionel Sambuc #include <minix/board.h>
10*433d6423SLionel Sambuc 
11*433d6423SLionel Sambuc /* system headers */
12*433d6423SLionel Sambuc #include <sys/mman.h>
13*433d6423SLionel Sambuc #include <sys/types.h>
14*433d6423SLionel Sambuc 
15*433d6423SLionel Sambuc /* usr headers */
16*433d6423SLionel Sambuc #include <stdio.h>
17*433d6423SLionel Sambuc #include <stdlib.h>
18*433d6423SLionel Sambuc #include <stdarg.h>
19*433d6423SLionel Sambuc #include <string.h>
20*433d6423SLionel Sambuc #include <errno.h>
21*433d6423SLionel Sambuc #include <assert.h>
22*433d6423SLionel Sambuc 
23*433d6423SLionel Sambuc /* local headers */
24*433d6423SLionel Sambuc #include "gpio_omap.h"
25*433d6423SLionel Sambuc 
26*433d6423SLionel Sambuc /* used for logging */
27*433d6423SLionel Sambuc static struct log log = {
28*433d6423SLionel Sambuc 	.name = "gpio_omap",
29*433d6423SLionel Sambuc 	.log_level = LEVEL_INFO,
30*433d6423SLionel Sambuc 	.log_func = default_log
31*433d6423SLionel Sambuc };
32*433d6423SLionel Sambuc 
33*433d6423SLionel Sambuc struct gpio_driver
34*433d6423SLionel Sambuc {
35*433d6423SLionel Sambuc 	/* request access to a gpio */
36*433d6423SLionel Sambuc 	int (*claim) (char *owner, int nr, struct gpio ** gpio);
37*433d6423SLionel Sambuc 
38*433d6423SLionel Sambuc 	/* Configure the GPIO for a certain purpose */
39*433d6423SLionel Sambuc 	int (*pin_mode) (struct gpio * gpio, int mode);
40*433d6423SLionel Sambuc 
41*433d6423SLionel Sambuc 	/* Set the value for a GPIO */
42*433d6423SLionel Sambuc 	int (*set) (struct gpio * gpio, int value);
43*433d6423SLionel Sambuc 
44*433d6423SLionel Sambuc 	/* Read the current value of the GPIO */
45*433d6423SLionel Sambuc 	int (*read) (struct gpio * gpio, int *value);
46*433d6423SLionel Sambuc 
47*433d6423SLionel Sambuc 	/* Read and clear the value interrupt value of the GPIO */
48*433d6423SLionel Sambuc 	int (*intr_read) (struct gpio * gpio, int *value);
49*433d6423SLionel Sambuc 
50*433d6423SLionel Sambuc 	/* Interrupt hook */
51*433d6423SLionel Sambuc 	int (*message_hook) (message * m);
52*433d6423SLionel Sambuc };
53*433d6423SLionel Sambuc 
54*433d6423SLionel Sambuc static struct gpio_driver drv;
55*433d6423SLionel Sambuc 
56*433d6423SLionel Sambuc struct omap_gpio_bank
57*433d6423SLionel Sambuc {
58*433d6423SLionel Sambuc 	const char *name;
59*433d6423SLionel Sambuc 	uint32_t register_address;
60*433d6423SLionel Sambuc 	uint32_t irq_nr;	/* irq number */
61*433d6423SLionel Sambuc 	uint32_t base_address;
62*433d6423SLionel Sambuc 	int32_t disabled;
63*433d6423SLionel Sambuc 	int irq_id;		/* original hook id??? */
64*433d6423SLionel Sambuc 	int irq_hook_id;	/* hook id */
65*433d6423SLionel Sambuc 	uint32_t inter_values;	/* values when the interrupt was called */
66*433d6423SLionel Sambuc };
67*433d6423SLionel Sambuc 
68*433d6423SLionel Sambuc static struct omap_gpio_bank *omap_gpio_banks;
69*433d6423SLionel Sambuc 
70*433d6423SLionel Sambuc static struct omap_gpio_bank am335x_gpio_banks[] = {
71*433d6423SLionel Sambuc 	{
72*433d6423SLionel Sambuc 		    .name = "GPIO0",
73*433d6423SLionel Sambuc 		    .register_address = AM335X_GPIO0_BASE,
74*433d6423SLionel Sambuc 		    .irq_nr = AM335X_GPIO0A_IRQ,
75*433d6423SLionel Sambuc 		    .base_address = 0,
76*433d6423SLionel Sambuc 		    .disabled = 0,
77*433d6423SLionel Sambuc 		    .irq_id = AM335X_GPIO0A_IRQ_HOOK_ID,
78*433d6423SLionel Sambuc 		    .irq_hook_id = AM335X_GPIO0A_IRQ_HOOK_ID,
79*433d6423SLionel Sambuc 
80*433d6423SLionel Sambuc 	    },
81*433d6423SLionel Sambuc 	{
82*433d6423SLionel Sambuc 		    .name = "GPIO1",
83*433d6423SLionel Sambuc 		    .register_address = AM335X_GPIO1_BASE,
84*433d6423SLionel Sambuc 		    .irq_nr = AM335X_GPIO1A_IRQ,
85*433d6423SLionel Sambuc 		    .base_address = 0,
86*433d6423SLionel Sambuc 		    .disabled = 0,
87*433d6423SLionel Sambuc 		    .irq_id = AM335X_GPIO1A_IRQ_HOOK_ID,
88*433d6423SLionel Sambuc 		    .irq_hook_id = AM335X_GPIO1A_IRQ_HOOK_ID,
89*433d6423SLionel Sambuc 
90*433d6423SLionel Sambuc 	    },
91*433d6423SLionel Sambuc 	{
92*433d6423SLionel Sambuc 		    .name = "GPIO2",
93*433d6423SLionel Sambuc 		    .register_address = AM335X_GPIO2_BASE,
94*433d6423SLionel Sambuc 		    .irq_nr = AM335X_GPIO2A_IRQ,
95*433d6423SLionel Sambuc 		    .base_address = 0,
96*433d6423SLionel Sambuc 		    .disabled = 0,
97*433d6423SLionel Sambuc 		    .irq_id = AM335X_GPIO2A_IRQ_HOOK_ID,
98*433d6423SLionel Sambuc 		    .irq_hook_id = AM335X_GPIO2A_IRQ_HOOK_ID,
99*433d6423SLionel Sambuc 
100*433d6423SLionel Sambuc 	    },
101*433d6423SLionel Sambuc 	{
102*433d6423SLionel Sambuc 		    .name = "GPIO3",
103*433d6423SLionel Sambuc 		    .register_address = AM335X_GPIO3_BASE,
104*433d6423SLionel Sambuc 		    .irq_nr = AM335X_GPIO3A_IRQ,
105*433d6423SLionel Sambuc 		    .base_address = 0,
106*433d6423SLionel Sambuc 		    .disabled = 0,
107*433d6423SLionel Sambuc 		    .irq_id = AM335X_GPIO3A_IRQ_HOOK_ID,
108*433d6423SLionel Sambuc 		    .irq_hook_id = AM335X_GPIO3A_IRQ_HOOK_ID,
109*433d6423SLionel Sambuc 
110*433d6423SLionel Sambuc 	    },
111*433d6423SLionel Sambuc 	{NULL, 0, 0, 0, 0, 0, 0, 0 }
112*433d6423SLionel Sambuc };
113*433d6423SLionel Sambuc 
114*433d6423SLionel Sambuc static struct omap_gpio_bank dm37xx_gpio_banks[] = {
115*433d6423SLionel Sambuc 	{
116*433d6423SLionel Sambuc 		    .name = "GPIO1",
117*433d6423SLionel Sambuc 		    .register_address = DM37XX_GPIO1_BASE,
118*433d6423SLionel Sambuc 		    .irq_nr = DM37XX_GPIO1_IRQ,
119*433d6423SLionel Sambuc 		    .base_address = 0,
120*433d6423SLionel Sambuc 		    .disabled = 0,
121*433d6423SLionel Sambuc 		    .irq_id = DM37XX_GPIO1_IRQ_HOOK_ID,
122*433d6423SLionel Sambuc 		    .irq_hook_id = DM37XX_GPIO1_IRQ_HOOK_ID,
123*433d6423SLionel Sambuc 	    },
124*433d6423SLionel Sambuc 	{
125*433d6423SLionel Sambuc 		    .name = "GPIO2",
126*433d6423SLionel Sambuc 		    .register_address = DM37XX_GPIO2_BASE,
127*433d6423SLionel Sambuc 		    .irq_nr = DM37XX_GPIO2_IRQ,
128*433d6423SLionel Sambuc 		    .base_address = 0,
129*433d6423SLionel Sambuc 		    .disabled = 0,
130*433d6423SLionel Sambuc 		    .irq_id = DM37XX_GPIO2_IRQ_HOOK_ID,
131*433d6423SLionel Sambuc 		    .irq_hook_id = DM37XX_GPIO2_IRQ_HOOK_ID,
132*433d6423SLionel Sambuc 	    },
133*433d6423SLionel Sambuc 	{
134*433d6423SLionel Sambuc 		    .name = "GPIO3",
135*433d6423SLionel Sambuc 		    .register_address = DM37XX_GPIO3_BASE,
136*433d6423SLionel Sambuc 		    .irq_nr = DM37XX_GPIO3_IRQ,
137*433d6423SLionel Sambuc 		    .base_address = 0,
138*433d6423SLionel Sambuc 		    .disabled = 0,
139*433d6423SLionel Sambuc 		    .irq_id = DM37XX_GPIO3_IRQ_HOOK_ID,
140*433d6423SLionel Sambuc 		    .irq_hook_id = DM37XX_GPIO3_IRQ_HOOK_ID,
141*433d6423SLionel Sambuc 	    },
142*433d6423SLionel Sambuc 	{
143*433d6423SLionel Sambuc 		    .name = "GPIO4",
144*433d6423SLionel Sambuc 		    .register_address = DM37XX_GPIO4_BASE,
145*433d6423SLionel Sambuc 		    .irq_nr = DM37XX_GPIO4_IRQ,
146*433d6423SLionel Sambuc 		    .base_address = 0,
147*433d6423SLionel Sambuc 		    .disabled = 0,
148*433d6423SLionel Sambuc 		    .irq_id = DM37XX_GPIO4_IRQ_HOOK_ID,
149*433d6423SLionel Sambuc 		    .irq_hook_id = DM37XX_GPIO4_IRQ_HOOK_ID,
150*433d6423SLionel Sambuc 	    },
151*433d6423SLionel Sambuc 	{
152*433d6423SLionel Sambuc 		    .name = "GPIO5",
153*433d6423SLionel Sambuc 		    .register_address = DM37XX_GPIO5_BASE,
154*433d6423SLionel Sambuc 		    .irq_nr = DM37XX_GPIO5_IRQ,
155*433d6423SLionel Sambuc 		    .base_address = 0,
156*433d6423SLionel Sambuc 		    .disabled = 0,
157*433d6423SLionel Sambuc 		    .irq_id = DM37XX_GPIO5_IRQ_HOOK_ID,
158*433d6423SLionel Sambuc 		    .irq_hook_id = DM37XX_GPIO5_IRQ_HOOK_ID,
159*433d6423SLionel Sambuc 	    },
160*433d6423SLionel Sambuc 	{
161*433d6423SLionel Sambuc 		    .name = "GPIO6",
162*433d6423SLionel Sambuc 		    .register_address = DM37XX_GPIO6_BASE,
163*433d6423SLionel Sambuc 		    .irq_nr = DM37XX_GPIO6_IRQ,
164*433d6423SLionel Sambuc 		    .base_address = 0,
165*433d6423SLionel Sambuc 		    .disabled = 0,
166*433d6423SLionel Sambuc 		    .irq_id = DM37XX_GPIO6_IRQ_HOOK_ID,
167*433d6423SLionel Sambuc 		    .irq_hook_id = DM37XX_GPIO6_IRQ_HOOK_ID,
168*433d6423SLionel Sambuc 	    },
169*433d6423SLionel Sambuc 	{NULL, 0, 0, 0, 0, 0, 0, 0 }
170*433d6423SLionel Sambuc };
171*433d6423SLionel Sambuc 
172*433d6423SLionel Sambuc static int nbanks; /* number of banks */
173*433d6423SLionel Sambuc 
174*433d6423SLionel Sambuc /*
175*433d6423SLionel Sambuc  * Defines the set of registers. There is a lot of commonality between the
176*433d6423SLionel Sambuc  * AM335X and DM37XX gpio registers. To avoid ifdefs everywhere, we define
177*433d6423SLionel Sambuc  * a central register set and only use ifdefs where they differ.
178*433d6423SLionel Sambuc  */
179*433d6423SLionel Sambuc typedef struct gpio_omap_registers {
180*433d6423SLionel Sambuc 	vir_bytes REVISION;
181*433d6423SLionel Sambuc 	vir_bytes IRQENABLE;
182*433d6423SLionel Sambuc 	vir_bytes IRQSTATUS;
183*433d6423SLionel Sambuc 	vir_bytes DATAOUT;
184*433d6423SLionel Sambuc 	vir_bytes DATAIN;
185*433d6423SLionel Sambuc 	vir_bytes OE;
186*433d6423SLionel Sambuc 	vir_bytes RISINGDETECT;
187*433d6423SLionel Sambuc 	vir_bytes FALLINGDETECT;
188*433d6423SLionel Sambuc 	vir_bytes CLEARDATAOUT;
189*433d6423SLionel Sambuc 	vir_bytes SETDATAOUT;
190*433d6423SLionel Sambuc } gpio_omap_regs_t;
191*433d6423SLionel Sambuc 
192*433d6423SLionel Sambuc /* Define the registers for each chip */
193*433d6423SLionel Sambuc 
194*433d6423SLionel Sambuc gpio_omap_regs_t gpio_omap_dm37xx = {
195*433d6423SLionel Sambuc 	.REVISION = DM37XX_GPIO_REVISION,
196*433d6423SLionel Sambuc 	.IRQENABLE = DM37XX_GPIO_IRQENABLE1,
197*433d6423SLionel Sambuc 	.IRQSTATUS = DM37XX_GPIO_IRQSTATUS1,
198*433d6423SLionel Sambuc 	.DATAOUT = DM37XX_GPIO_DATAOUT,
199*433d6423SLionel Sambuc 	.DATAIN = DM37XX_GPIO_DATAIN,
200*433d6423SLionel Sambuc 	.OE = DM37XX_GPIO_OE,
201*433d6423SLionel Sambuc 	.RISINGDETECT = DM37XX_GPIO_RISINGDETECT1,
202*433d6423SLionel Sambuc 	.FALLINGDETECT = DM37XX_GPIO_FALLINGDETECT1,
203*433d6423SLionel Sambuc 	.CLEARDATAOUT = DM37XX_GPIO_CLEARDATAOUT,
204*433d6423SLionel Sambuc 	.SETDATAOUT = DM37XX_GPIO_SETDATAOUT
205*433d6423SLionel Sambuc };
206*433d6423SLionel Sambuc 
207*433d6423SLionel Sambuc gpio_omap_regs_t gpio_omap_am335x = {
208*433d6423SLionel Sambuc 	.REVISION = AM335X_GPIO_REVISION,
209*433d6423SLionel Sambuc 	.IRQENABLE = AM335X_GPIO_IRQSTATUS_SET_0,
210*433d6423SLionel Sambuc 	.IRQSTATUS = AM335X_GPIO_IRQSTATUS_0,
211*433d6423SLionel Sambuc 	.DATAOUT = AM335X_GPIO_DATAOUT,
212*433d6423SLionel Sambuc 	.DATAIN = AM335X_GPIO_DATAIN,
213*433d6423SLionel Sambuc 	.OE = AM335X_GPIO_OE,
214*433d6423SLionel Sambuc 	.RISINGDETECT = AM335X_GPIO_RISINGDETECT,
215*433d6423SLionel Sambuc 	.FALLINGDETECT = AM335X_GPIO_FALLINGDETECT,
216*433d6423SLionel Sambuc 	.CLEARDATAOUT = AM335X_GPIO_CLEARDATAOUT,
217*433d6423SLionel Sambuc 	.SETDATAOUT = AM335X_GPIO_SETDATAOUT
218*433d6423SLionel Sambuc };
219*433d6423SLionel Sambuc 
220*433d6423SLionel Sambuc static gpio_omap_regs_t *regs;
221*433d6423SLionel Sambuc 
222*433d6423SLionel Sambuc 
223*433d6423SLionel Sambuc static struct omap_gpio_bank *
omap_gpio_bank_get(int gpio_nr)224*433d6423SLionel Sambuc omap_gpio_bank_get(int gpio_nr)
225*433d6423SLionel Sambuc {
226*433d6423SLionel Sambuc 	struct omap_gpio_bank *bank;
227*433d6423SLionel Sambuc 	assert(gpio_nr >= 0 && gpio_nr <= 32 * nbanks);
228*433d6423SLionel Sambuc 	bank = &omap_gpio_banks[gpio_nr / 32];
229*433d6423SLionel Sambuc 	return bank;
230*433d6423SLionel Sambuc }
231*433d6423SLionel Sambuc 
232*433d6423SLionel Sambuc static int
omap_gpio_claim(char * owner,int nr,struct gpio ** gpio)233*433d6423SLionel Sambuc omap_gpio_claim(char *owner, int nr, struct gpio **gpio)
234*433d6423SLionel Sambuc {
235*433d6423SLionel Sambuc 	log_trace(&log, "%s s claiming %d\n", owner, nr);
236*433d6423SLionel Sambuc 
237*433d6423SLionel Sambuc 	if (nr < 0 && nr >= 32 * nbanks) {
238*433d6423SLionel Sambuc 		log_warn(&log, "%s is claiming unknown GPIO number %d\n",
239*433d6423SLionel Sambuc 		    owner, nr);
240*433d6423SLionel Sambuc 		return EINVAL;
241*433d6423SLionel Sambuc 	}
242*433d6423SLionel Sambuc 
243*433d6423SLionel Sambuc 	if (omap_gpio_bank_get(nr)->disabled == 1) {
244*433d6423SLionel Sambuc 		log_warn(&log, "%s is claiming GPIO %d from disabled bank\n",
245*433d6423SLionel Sambuc 		    owner, nr);
246*433d6423SLionel Sambuc 		return EINVAL;
247*433d6423SLionel Sambuc 	}
248*433d6423SLionel Sambuc 
249*433d6423SLionel Sambuc 	struct gpio *tmp = malloc(sizeof(struct gpio));
250*433d6423SLionel Sambuc 	memset(tmp, 0, sizeof(*tmp));
251*433d6423SLionel Sambuc 
252*433d6423SLionel Sambuc 	tmp->nr = nr;
253*433d6423SLionel Sambuc 	*gpio = tmp;
254*433d6423SLionel Sambuc 	return OK;
255*433d6423SLionel Sambuc }
256*433d6423SLionel Sambuc 
257*433d6423SLionel Sambuc static int
omap_gpio_pin_mode(struct gpio * gpio,int mode)258*433d6423SLionel Sambuc omap_gpio_pin_mode(struct gpio *gpio, int mode)
259*433d6423SLionel Sambuc {
260*433d6423SLionel Sambuc 	struct omap_gpio_bank *bank;
261*433d6423SLionel Sambuc 	assert(gpio != NULL);
262*433d6423SLionel Sambuc 	gpio->mode = mode;
263*433d6423SLionel Sambuc 
264*433d6423SLionel Sambuc 	bank = omap_gpio_bank_get(gpio->nr);
265*433d6423SLionel Sambuc 	log_debug(&log,
266*433d6423SLionel Sambuc 	    "pin mode bank %s, base address 0x%x -> register address (0x%x,0x%x,0x%x)\n",
267*433d6423SLionel Sambuc 	    bank->name, bank->base_address, bank->register_address, regs->OE,
268*433d6423SLionel Sambuc 	    bank->register_address + regs->OE);
269*433d6423SLionel Sambuc 
270*433d6423SLionel Sambuc 	if (mode == GPIO_MODE_OUTPUT) {
271*433d6423SLionel Sambuc 		set32(bank->base_address + regs->OE, BIT(gpio->nr % 32), 0);
272*433d6423SLionel Sambuc 	} else {
273*433d6423SLionel Sambuc 		set32(bank->base_address + regs->FALLINGDETECT,
274*433d6423SLionel Sambuc 		    BIT(gpio->nr % 32), 0xffffffff);
275*433d6423SLionel Sambuc 		set32(bank->base_address + regs->IRQENABLE, BIT(gpio->nr % 32),
276*433d6423SLionel Sambuc 		    0xffffffff);
277*433d6423SLionel Sambuc 		set32(bank->base_address + regs->OE, BIT(gpio->nr % 32),
278*433d6423SLionel Sambuc 		    0xffffffff);
279*433d6423SLionel Sambuc 	}
280*433d6423SLionel Sambuc 	return 0;
281*433d6423SLionel Sambuc }
282*433d6423SLionel Sambuc 
283*433d6423SLionel Sambuc static int
omap_gpio_set(struct gpio * gpio,int value)284*433d6423SLionel Sambuc omap_gpio_set(struct gpio *gpio, int value)
285*433d6423SLionel Sambuc {
286*433d6423SLionel Sambuc 	struct omap_gpio_bank *bank;
287*433d6423SLionel Sambuc 	assert(gpio != NULL);
288*433d6423SLionel Sambuc 	assert(gpio->nr >= 0 && gpio->nr <= 32 * nbanks);
289*433d6423SLionel Sambuc 
290*433d6423SLionel Sambuc 	bank = omap_gpio_bank_get(gpio->nr);
291*433d6423SLionel Sambuc 	if (value == 1) {
292*433d6423SLionel Sambuc 		write32(bank->base_address + regs->SETDATAOUT,
293*433d6423SLionel Sambuc 		    BIT(gpio->nr % 32));
294*433d6423SLionel Sambuc 	} else {
295*433d6423SLionel Sambuc 		write32(bank->base_address + regs->CLEARDATAOUT,
296*433d6423SLionel Sambuc 		    BIT(gpio->nr % 32));
297*433d6423SLionel Sambuc 	}
298*433d6423SLionel Sambuc 	return OK;
299*433d6423SLionel Sambuc }
300*433d6423SLionel Sambuc 
301*433d6423SLionel Sambuc static int
omap_gpio_read(struct gpio * gpio,int * value)302*433d6423SLionel Sambuc omap_gpio_read(struct gpio *gpio, int *value)
303*433d6423SLionel Sambuc {
304*433d6423SLionel Sambuc 	struct omap_gpio_bank *bank;
305*433d6423SLionel Sambuc 	assert(gpio != NULL);
306*433d6423SLionel Sambuc 	assert(gpio->nr >= 0 && gpio->nr <= 32 * nbanks);
307*433d6423SLionel Sambuc 
308*433d6423SLionel Sambuc 	bank = omap_gpio_bank_get(gpio->nr);
309*433d6423SLionel Sambuc 	log_trace(&log, "mode=%d OU/IN 0x%08x 0x%08x\n", gpio->mode,
310*433d6423SLionel Sambuc 	    read32(bank->base_address + regs->DATAIN),
311*433d6423SLionel Sambuc 	    read32(bank->base_address + regs->DATAOUT));
312*433d6423SLionel Sambuc 
313*433d6423SLionel Sambuc 	if (gpio->mode == GPIO_MODE_INPUT) {
314*433d6423SLionel Sambuc 		*value =
315*433d6423SLionel Sambuc 		    (read32(bank->base_address +
316*433d6423SLionel Sambuc 			regs->DATAIN) >> (gpio->nr % 32)) & 0x1;
317*433d6423SLionel Sambuc 	} else {
318*433d6423SLionel Sambuc 		*value =
319*433d6423SLionel Sambuc 		    (read32(bank->base_address +
320*433d6423SLionel Sambuc 			regs->DATAOUT) >> (gpio->nr % 32)) & 0x1;
321*433d6423SLionel Sambuc 	}
322*433d6423SLionel Sambuc 
323*433d6423SLionel Sambuc 	return OK;
324*433d6423SLionel Sambuc }
325*433d6423SLionel Sambuc 
326*433d6423SLionel Sambuc static int
omap_gpio_intr_read(struct gpio * gpio,int * value)327*433d6423SLionel Sambuc omap_gpio_intr_read(struct gpio *gpio, int *value)
328*433d6423SLionel Sambuc {
329*433d6423SLionel Sambuc 	struct omap_gpio_bank *bank;
330*433d6423SLionel Sambuc 	assert(gpio != NULL);
331*433d6423SLionel Sambuc 	assert(gpio->nr >= 0 && gpio->nr <= 32 * nbanks);
332*433d6423SLionel Sambuc 
333*433d6423SLionel Sambuc 	bank = omap_gpio_bank_get(gpio->nr);
334*433d6423SLionel Sambuc 	/* TODO: check if interrupt where enabled?? */
335*433d6423SLionel Sambuc 
336*433d6423SLionel Sambuc 	*value = (bank->inter_values >> (gpio->nr % 32)) & 0x1;
337*433d6423SLionel Sambuc 	/* clear the data */
338*433d6423SLionel Sambuc 	bank->inter_values &= ~(1 << (gpio->nr % 32));
339*433d6423SLionel Sambuc 
340*433d6423SLionel Sambuc 	return OK;
341*433d6423SLionel Sambuc }
342*433d6423SLionel Sambuc 
343*433d6423SLionel Sambuc static int
omap_message_hook(message * m)344*433d6423SLionel Sambuc omap_message_hook(message * m)
345*433d6423SLionel Sambuc {
346*433d6423SLionel Sambuc 	unsigned long irq_set, i;
347*433d6423SLionel Sambuc 	struct omap_gpio_bank *bank;
348*433d6423SLionel Sambuc 
349*433d6423SLionel Sambuc 	switch (_ENDPOINT_P(m->m_source)) {
350*433d6423SLionel Sambuc 	case HARDWARE:
351*433d6423SLionel Sambuc 		/* Hardware interrupt return a "set" if pending interrupts */
352*433d6423SLionel Sambuc 		irq_set = m->m_notify.interrupts;
353*433d6423SLionel Sambuc 		log_debug(&log, "HW message 0X%08llx\n", m->m_notify.interrupts);
354*433d6423SLionel Sambuc 		bank = &omap_gpio_banks[0];
355*433d6423SLionel Sambuc 		for (i = 0; omap_gpio_banks[i].name != NULL; i++) {
356*433d6423SLionel Sambuc 			bank = &omap_gpio_banks[i];
357*433d6423SLionel Sambuc 
358*433d6423SLionel Sambuc 			if (irq_set & (1 << (bank->irq_id))) {
359*433d6423SLionel Sambuc 				log_trace(&log, "Interrupt for bank %s\n",
360*433d6423SLionel Sambuc 				    bank->name);
361*433d6423SLionel Sambuc 				bank->inter_values |=
362*433d6423SLionel Sambuc 				    read32(bank->base_address +
363*433d6423SLionel Sambuc 				    regs->IRQSTATUS);
364*433d6423SLionel Sambuc 				/* clear the interrupts */
365*433d6423SLionel Sambuc 				write32(bank->base_address + regs->IRQSTATUS,
366*433d6423SLionel Sambuc 				    0xffffffff);
367*433d6423SLionel Sambuc 				if (sys_irqenable(&bank->irq_hook_id) != OK) {
368*433d6423SLionel Sambuc 					log_warn(&log,
369*433d6423SLionel Sambuc 					    "Failed to enable irq for bank %s\n",
370*433d6423SLionel Sambuc 					    bank->name);
371*433d6423SLionel Sambuc 				}
372*433d6423SLionel Sambuc 			}
373*433d6423SLionel Sambuc 		}
374*433d6423SLionel Sambuc 		return OK;
375*433d6423SLionel Sambuc 	default:
376*433d6423SLionel Sambuc 		log_debug(&log, "Unknown message\n");
377*433d6423SLionel Sambuc 		break;
378*433d6423SLionel Sambuc 	}
379*433d6423SLionel Sambuc 	return OK;
380*433d6423SLionel Sambuc }
381*433d6423SLionel Sambuc 
revision_matches(u32_t board_id,u32_t rev)382*433d6423SLionel Sambuc static int revision_matches(u32_t board_id,u32_t rev) {
383*433d6423SLionel Sambuc 	/* figures out if the collected resition matches the one expected
384*433d6423SLionel Sambuc 	 * from the board */
385*433d6423SLionel Sambuc 	if (BOARD_IS_BBXM(board_id)){
386*433d6423SLionel Sambuc 		if(
387*433d6423SLionel Sambuc 		   DM37XX_GPIO_REVISION_MAJOR(rev) != 2
388*433d6423SLionel Sambuc 		   || DM37XX_GPIO_REVISION_MINOR(rev) !=  5
389*433d6423SLionel Sambuc 		   ) {
390*433d6423SLionel Sambuc 			return 0;
391*433d6423SLionel Sambuc 		}
392*433d6423SLionel Sambuc 	} else if (BOARD_IS_BB(board_id)){
393*433d6423SLionel Sambuc 		if (
394*433d6423SLionel Sambuc 		    AM335X_GPIO_REVISION_MAJOR(rev) != 0
395*433d6423SLionel Sambuc 		    || AM335X_GPIO_REVISION_MINOR(rev) != 1
396*433d6423SLionel Sambuc 		    ) {
397*433d6423SLionel Sambuc 			return 0;
398*433d6423SLionel Sambuc 		}
399*433d6423SLionel Sambuc 	}
400*433d6423SLionel Sambuc 	return 1;
401*433d6423SLionel Sambuc }
402*433d6423SLionel Sambuc 
403*433d6423SLionel Sambuc static int
omap_gpio_init(struct gpio_driver * gpdrv)404*433d6423SLionel Sambuc omap_gpio_init(struct gpio_driver *gpdrv)
405*433d6423SLionel Sambuc {
406*433d6423SLionel Sambuc 	u32_t revision;
407*433d6423SLionel Sambuc 	int i;
408*433d6423SLionel Sambuc 	struct minix_mem_range mr;
409*433d6423SLionel Sambuc 	struct omap_gpio_bank *bank;
410*433d6423SLionel Sambuc 	struct machine machine;
411*433d6423SLionel Sambuc 	sys_getmachine(&machine);
412*433d6423SLionel Sambuc 
413*433d6423SLionel Sambuc 	nbanks =0;
414*433d6423SLionel Sambuc 	omap_gpio_banks = NULL;
415*433d6423SLionel Sambuc 	if (BOARD_IS_BBXM(machine.board_id)){
416*433d6423SLionel Sambuc 		omap_gpio_banks = dm37xx_gpio_banks;
417*433d6423SLionel Sambuc 		regs = &gpio_omap_dm37xx;
418*433d6423SLionel Sambuc 	} else if (BOARD_IS_BB(machine.board_id)){
419*433d6423SLionel Sambuc 		omap_gpio_banks = am335x_gpio_banks;
420*433d6423SLionel Sambuc 		regs = &gpio_omap_am335x;
421*433d6423SLionel Sambuc 	}
422*433d6423SLionel Sambuc 
423*433d6423SLionel Sambuc 	bank = &omap_gpio_banks[0];
424*433d6423SLionel Sambuc 	for (i = 0; omap_gpio_banks[i].name != NULL; i++) {
425*433d6423SLionel Sambuc 		nbanks++;
426*433d6423SLionel Sambuc 		bank = &omap_gpio_banks[i];
427*433d6423SLionel Sambuc 		mr.mr_base = bank->register_address;
428*433d6423SLionel Sambuc 		mr.mr_limit = bank->register_address + 0x400;
429*433d6423SLionel Sambuc 
430*433d6423SLionel Sambuc 		if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != 0) {
431*433d6423SLionel Sambuc 			log_warn(&log,
432*433d6423SLionel Sambuc 			    "Unable to request permission to map memory\n");
433*433d6423SLionel Sambuc 			return EPERM;	/* fixme */
434*433d6423SLionel Sambuc 		}
435*433d6423SLionel Sambuc 
436*433d6423SLionel Sambuc 		/* Set the base address to use */
437*433d6423SLionel Sambuc 		bank->base_address =
438*433d6423SLionel Sambuc 		    (uint32_t) vm_map_phys(SELF,
439*433d6423SLionel Sambuc 		    (void *) bank->register_address, 0x400);
440*433d6423SLionel Sambuc 
441*433d6423SLionel Sambuc 		if (bank->base_address == (uint32_t) MAP_FAILED) {
442*433d6423SLionel Sambuc 			log_warn(&log, "Unable to map GPIO memory\n");
443*433d6423SLionel Sambuc 			return EPERM;	/* fixme */
444*433d6423SLionel Sambuc 		}
445*433d6423SLionel Sambuc 
446*433d6423SLionel Sambuc 		revision = read32(bank->base_address + regs->REVISION);
447*433d6423SLionel Sambuc 		/* test if we can access it */
448*433d6423SLionel Sambuc 		if (! revision_matches(machine.board_id,revision)) {
449*433d6423SLionel Sambuc 			log_warn(&log,
450*433d6423SLionel Sambuc 			    "Failed to read the revision of GPIO bank %s.. disabling\n",
451*433d6423SLionel Sambuc 			    bank->name);
452*433d6423SLionel Sambuc 			log_warn(&log, "Got 0x%x\n", revision);
453*433d6423SLionel Sambuc 			bank->disabled = 1;
454*433d6423SLionel Sambuc 		} else {
455*433d6423SLionel Sambuc 			bank->disabled = 0;
456*433d6423SLionel Sambuc 		}
457*433d6423SLionel Sambuc 
458*433d6423SLionel Sambuc 		if (sys_irqsetpolicy(bank->irq_nr, 0,
459*433d6423SLionel Sambuc 			&bank->irq_hook_id) != OK) {
460*433d6423SLionel Sambuc 			log_warn(&log,
461*433d6423SLionel Sambuc 			    "GPIO: couldn't set IRQ policy for bank %s\n",
462*433d6423SLionel Sambuc 			    bank->name);
463*433d6423SLionel Sambuc 			continue;
464*433d6423SLionel Sambuc 		};
465*433d6423SLionel Sambuc 		if (bank->irq_id != bank->irq_hook_id) {
466*433d6423SLionel Sambuc 			log_debug(&log, "requested id %d but got id %d\n",
467*433d6423SLionel Sambuc 			    bank->irq_id, bank->irq_hook_id);
468*433d6423SLionel Sambuc 		}
469*433d6423SLionel Sambuc 		if (sys_irqenable(&bank->irq_hook_id) != OK) {
470*433d6423SLionel Sambuc 			log_warn(&log,
471*433d6423SLionel Sambuc 			    "GPIO: couldn't enable interrupt for %s\n",
472*433d6423SLionel Sambuc 			    bank->name);
473*433d6423SLionel Sambuc 		};
474*433d6423SLionel Sambuc 		log_trace(&log, "bank %s mapped on 0x%x with irq hook id %d\n",
475*433d6423SLionel Sambuc 		    bank->name, bank->base_address, bank->irq_hook_id);
476*433d6423SLionel Sambuc 
477*433d6423SLionel Sambuc 	};
478*433d6423SLionel Sambuc 
479*433d6423SLionel Sambuc 	clkconf_init();
480*433d6423SLionel Sambuc 
481*433d6423SLionel Sambuc 	if (BOARD_IS_BBXM(machine.board_id)){
482*433d6423SLionel Sambuc 		/* enable the interface and functional clock on GPIO bank 1 , this only
483*433d6423SLionel Sambuc 		   applies to the Beagelboard XM */
484*433d6423SLionel Sambuc 		clkconf_set(CM_FCLKEN_WKUP, BIT(3), 0xffffffff);
485*433d6423SLionel Sambuc 		clkconf_set(CM_ICLKEN_WKUP, BIT(3), 0xffffffff);
486*433d6423SLionel Sambuc 	}
487*433d6423SLionel Sambuc 	clkconf_release();
488*433d6423SLionel Sambuc 
489*433d6423SLionel Sambuc 
490*433d6423SLionel Sambuc 	gpdrv->claim = omap_gpio_claim;
491*433d6423SLionel Sambuc 	gpdrv->pin_mode = omap_gpio_pin_mode;
492*433d6423SLionel Sambuc 	gpdrv->set = omap_gpio_set;
493*433d6423SLionel Sambuc 	gpdrv->read = omap_gpio_read;
494*433d6423SLionel Sambuc 	gpdrv->intr_read = omap_gpio_intr_read;
495*433d6423SLionel Sambuc 	gpdrv->message_hook = omap_message_hook;
496*433d6423SLionel Sambuc 	return 0;
497*433d6423SLionel Sambuc }
498*433d6423SLionel Sambuc 
499*433d6423SLionel Sambuc int
gpio_init()500*433d6423SLionel Sambuc gpio_init()
501*433d6423SLionel Sambuc {
502*433d6423SLionel Sambuc 	return omap_gpio_init(&drv);
503*433d6423SLionel Sambuc }
504*433d6423SLionel Sambuc 
505*433d6423SLionel Sambuc /* request access to a gpio */
506*433d6423SLionel Sambuc int
gpio_claim(char * owner,int nr,struct gpio ** gpio)507*433d6423SLionel Sambuc gpio_claim(char *owner, int nr, struct gpio **gpio)
508*433d6423SLionel Sambuc {
509*433d6423SLionel Sambuc 	return drv.claim(owner, nr, gpio);
510*433d6423SLionel Sambuc }
511*433d6423SLionel Sambuc 
512*433d6423SLionel Sambuc /* Configure the GPIO for a certain purpose */
513*433d6423SLionel Sambuc int
gpio_pin_mode(struct gpio * gpio,int mode)514*433d6423SLionel Sambuc gpio_pin_mode(struct gpio *gpio, int mode)
515*433d6423SLionel Sambuc {
516*433d6423SLionel Sambuc 	return drv.pin_mode(gpio, mode);
517*433d6423SLionel Sambuc }
518*433d6423SLionel Sambuc 
519*433d6423SLionel Sambuc /* Set the value for a GPIO */
520*433d6423SLionel Sambuc int
gpio_set(struct gpio * gpio,int value)521*433d6423SLionel Sambuc gpio_set(struct gpio *gpio, int value)
522*433d6423SLionel Sambuc {
523*433d6423SLionel Sambuc 	return drv.set(gpio, value);
524*433d6423SLionel Sambuc }
525*433d6423SLionel Sambuc 
526*433d6423SLionel Sambuc /* Read the current value of the GPIO */
527*433d6423SLionel Sambuc int
gpio_read(struct gpio * gpio,int * value)528*433d6423SLionel Sambuc gpio_read(struct gpio *gpio, int *value)
529*433d6423SLionel Sambuc {
530*433d6423SLionel Sambuc 	return drv.read(gpio, value);
531*433d6423SLionel Sambuc }
532*433d6423SLionel Sambuc 
533*433d6423SLionel Sambuc /* Read and clear the value interrupt value of the GPIO */
534*433d6423SLionel Sambuc int
gpio_intr_read(struct gpio * gpio,int * value)535*433d6423SLionel Sambuc gpio_intr_read(struct gpio *gpio, int *value)
536*433d6423SLionel Sambuc {
537*433d6423SLionel Sambuc 	return drv.intr_read(gpio, value);
538*433d6423SLionel Sambuc }
539*433d6423SLionel Sambuc 
540*433d6423SLionel Sambuc /* Interrupt hook */
541*433d6423SLionel Sambuc int
gpio_intr_message(message * m)542*433d6423SLionel Sambuc gpio_intr_message(message * m)
543*433d6423SLionel Sambuc {
544*433d6423SLionel Sambuc 	return drv.message_hook(m);
545*433d6423SLionel Sambuc }
546*433d6423SLionel Sambuc 
547*433d6423SLionel Sambuc int
gpio_release(void)548*433d6423SLionel Sambuc gpio_release(void)
549*433d6423SLionel Sambuc {
550*433d6423SLionel Sambuc 	return OK;
551*433d6423SLionel Sambuc }
552