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