1 /* $OpenBSD: ofw_gpio.c,v 1.4 2025/01/09 19:38:13 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 <machine/fdt.h> 23 24 #include <dev/ofw/openfirm.h> 25 #include <dev/ofw/ofw_gpio.h> 26 27 LIST_HEAD(, gpio_controller) gpio_controllers = 28 LIST_HEAD_INITIALIZER(gpio_controllers); 29 30 void 31 gpio_controller_register(struct gpio_controller *gc) 32 { 33 int child; 34 35 gc->gc_cells = OF_getpropint(gc->gc_node, "#gpio-cells", 2); 36 gc->gc_phandle = OF_getpropint(gc->gc_node, "phandle", 0); 37 if (gc->gc_phandle == 0) 38 return; 39 40 LIST_INSERT_HEAD(&gpio_controllers, gc, gc_list); 41 42 /* Process GPIO hogs. */ 43 for (child = OF_child(gc->gc_node); child; child = OF_peer(child)) { 44 uint32_t *gpios; 45 uint32_t *gpio; 46 int len, config, active; 47 48 if (OF_getproplen(child, "gpio-hog") != 0) 49 continue; 50 51 len = OF_getproplen(child, "gpios"); 52 if (len <= 0) 53 continue; 54 55 /* 56 * These need to be processed in the order prescribed 57 * by the device tree binding. First match wins. 58 */ 59 if (OF_getproplen(child, "input") == 0) { 60 config = GPIO_CONFIG_INPUT; 61 active = 0; 62 } else if (OF_getproplen(child, "output-low") == 0) { 63 config = GPIO_CONFIG_OUTPUT; 64 active = 0; 65 } else if (OF_getproplen(child, "output-high") == 0) { 66 config = GPIO_CONFIG_OUTPUT; 67 active = 1; 68 } else 69 continue; 70 71 gpios = malloc(len, M_TEMP, M_WAITOK); 72 OF_getpropintarray(child, "gpios", gpios, len); 73 74 gpio = gpios; 75 while (gpio && gpio < gpios + (len / sizeof(uint32_t))) { 76 gc->gc_config_pin(gc->gc_cookie, gpio, config); 77 if (config & GPIO_CONFIG_OUTPUT) 78 gc->gc_set_pin(gc->gc_cookie, gpio, active); 79 gpio += gc->gc_cells; 80 } 81 82 free(gpios, M_TEMP, len); 83 } 84 } 85 86 void 87 gpio_controller_config_pin(uint32_t *cells, int config) 88 { 89 struct gpio_controller *gc; 90 uint32_t phandle = cells[0]; 91 92 LIST_FOREACH(gc, &gpio_controllers, gc_list) { 93 if (gc->gc_phandle == phandle) 94 break; 95 } 96 97 if (gc && gc->gc_config_pin) 98 gc->gc_config_pin(gc->gc_cookie, &cells[1], config); 99 } 100 101 int 102 gpio_controller_get_pin(uint32_t *cells) 103 { 104 struct gpio_controller *gc; 105 uint32_t phandle = cells[0]; 106 int val = 0; 107 108 LIST_FOREACH(gc, &gpio_controllers, gc_list) { 109 if (gc->gc_phandle == phandle) 110 break; 111 } 112 113 if (gc && gc->gc_get_pin) 114 val = gc->gc_get_pin(gc->gc_cookie, &cells[1]); 115 116 return val; 117 } 118 119 void 120 gpio_controller_set_pin(uint32_t *cells, int val) 121 { 122 struct gpio_controller *gc; 123 uint32_t phandle = cells[0]; 124 125 LIST_FOREACH(gc, &gpio_controllers, gc_list) { 126 if (gc->gc_phandle == phandle) 127 break; 128 } 129 130 if (gc && gc->gc_set_pin) 131 gc->gc_set_pin(gc->gc_cookie, &cells[1], val); 132 } 133 134 uint32_t * 135 gpio_controller_next_pin(uint32_t *cells) 136 { 137 struct gpio_controller *gc; 138 uint32_t phandle = cells[0]; 139 140 LIST_FOREACH(gc, &gpio_controllers, gc_list) 141 if (gc->gc_phandle == phandle) 142 return cells + gc->gc_cells + 1; 143 144 return NULL; 145 } 146 147 void * 148 gpio_controller_intr_establish(uint32_t *cells, int ipl, struct cpu_info *ci, 149 int (*func)(void *), void *arg, char *name) 150 { 151 struct gpio_controller *gc; 152 uint32_t phandle = cells[0]; 153 154 LIST_FOREACH(gc, &gpio_controllers, gc_list) { 155 if (gc->gc_phandle == phandle) 156 break; 157 } 158 159 if (gc && gc->gc_intr_establish) { 160 return gc->gc_intr_establish(gc->gc_cookie, &cells[1], ipl, 161 ci, func, arg, name); 162 } 163 164 return NULL; 165 } 166 167 void 168 gpio_controller_intr_disestablish(void *ih) 169 { 170 fdt_intr_disestablish(ih); 171 } 172