xref: /openbsd/sys/dev/ofw/ofw_gpio.c (revision 09467b48)
1 /*	$OpenBSD: ofw_gpio.c,v 1.3 2019/08/26 09:22:27 kettenis Exp $	*/
2 /*
3  * Copyright (c) 2016, 2019 Mark Kettenis
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/types.h>
19 #include <sys/systm.h>
20 #include <sys/malloc.h>
21 
22 #include <dev/ofw/openfirm.h>
23 #include <dev/ofw/ofw_gpio.h>
24 
25 LIST_HEAD(, gpio_controller) gpio_controllers =
26 	LIST_HEAD_INITIALIZER(gpio_controllers);
27 
28 void
29 gpio_controller_register(struct gpio_controller *gc)
30 {
31 	int child;
32 
33 	gc->gc_cells = OF_getpropint(gc->gc_node, "#gpio-cells", 2);
34 	gc->gc_phandle = OF_getpropint(gc->gc_node, "phandle", 0);
35 	if (gc->gc_phandle == 0)
36 		return;
37 
38 	LIST_INSERT_HEAD(&gpio_controllers, gc, gc_list);
39 
40 	/* Process GPIO hogs. */
41 	for (child = OF_child(gc->gc_node); child; child = OF_peer(child)) {
42 		uint32_t *gpios;
43 		uint32_t *gpio;
44 		int len, config, active;
45 
46 		if (OF_getproplen(child, "gpio-hog") != 0)
47 			continue;
48 
49 		len = OF_getproplen(child, "gpios");
50 		if (len <= 0)
51 			continue;
52 
53 		/*
54 		 * These need to be processed in the order prescribed
55 		 * by the device tree binding.  First match wins.
56 		 */
57 		if (OF_getproplen(child, "input") == 0) {
58 			config = GPIO_CONFIG_INPUT;
59 			active = 0;
60 		} else if (OF_getproplen(child, "output-low") == 0) {
61 			config = GPIO_CONFIG_OUTPUT;
62 			active = 0;
63 		} else if (OF_getproplen(child, "output-high") == 0) {
64 			config = GPIO_CONFIG_OUTPUT;
65 			active = 1;
66 		} else
67 			continue;
68 
69 		gpios = malloc(len, M_TEMP, M_WAITOK);
70 		OF_getpropintarray(child, "gpios", gpios, len);
71 
72 		gpio = gpios;
73 		while (gpio && gpio < gpios + (len / sizeof(uint32_t))) {
74 			gc->gc_config_pin(gc->gc_cookie, gpio, config);
75 			if (config & GPIO_CONFIG_OUTPUT)
76 				gc->gc_set_pin(gc->gc_cookie, gpio, active);
77 			gpio += gc->gc_cells;
78 		}
79 
80 		free(gpios, M_TEMP, len);
81 	}
82 }
83 
84 void
85 gpio_controller_config_pin(uint32_t *cells, int config)
86 {
87 	struct gpio_controller *gc;
88 	uint32_t phandle = cells[0];
89 
90 	LIST_FOREACH(gc, &gpio_controllers, gc_list) {
91 		if (gc->gc_phandle == phandle)
92 			break;
93 	}
94 
95 	if (gc && gc->gc_config_pin)
96 		gc->gc_config_pin(gc->gc_cookie, &cells[1], config);
97 }
98 
99 int
100 gpio_controller_get_pin(uint32_t *cells)
101 {
102 	struct gpio_controller *gc;
103 	uint32_t phandle = cells[0];
104 	int val = 0;
105 
106 	LIST_FOREACH(gc, &gpio_controllers, gc_list) {
107 		if (gc->gc_phandle == phandle)
108 			break;
109 	}
110 
111 	if (gc && gc->gc_get_pin)
112 		val = gc->gc_get_pin(gc->gc_cookie, &cells[1]);
113 
114 	return val;
115 }
116 
117 void
118 gpio_controller_set_pin(uint32_t *cells, int val)
119 {
120 	struct gpio_controller *gc;
121 	uint32_t phandle = cells[0];
122 
123 	LIST_FOREACH(gc, &gpio_controllers, gc_list) {
124 		if (gc->gc_phandle == phandle)
125 			break;
126 	}
127 
128 	if (gc && gc->gc_set_pin)
129 		gc->gc_set_pin(gc->gc_cookie, &cells[1], val);
130 }
131 
132 uint32_t *
133 gpio_controller_next_pin(uint32_t *cells)
134 {
135 	struct gpio_controller *gc;
136 	uint32_t phandle = cells[0];
137 
138 	LIST_FOREACH(gc, &gpio_controllers, gc_list)
139 		if (gc->gc_phandle == phandle)
140 			return cells + gc->gc_cells + 1;
141 
142 	return NULL;
143 }
144