1271546Sian/*- 2271546Sian * Copyright (c) 2014 Ian Lepore <ian@freebsd.org> 3271546Sian * All rights reserved. 4271546Sian * 5271546Sian * Redistribution and use in source and binary forms, with or without 6271546Sian * modification, are permitted provided that the following conditions 7271546Sian * are met: 8271546Sian * 1. Redistributions of source code must retain the above copyright 9271546Sian * notice, this list of conditions and the following disclaimer. 10271546Sian * 2. Redistributions in binary form must reproduce the above copyright 11271546Sian * notice, this list of conditions and the following disclaimer in the 12271546Sian * documentation and/or other materials provided with the distribution. 13271546Sian * 14271546Sian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15271546Sian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16271546Sian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17271546Sian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18271546Sian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19271546Sian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20271546Sian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21271546Sian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22271546Sian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23271546Sian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24271546Sian * SUCH DAMAGE. 25271546Sian * 26271546Sian * $FreeBSD$ 27271546Sian */ 28271546Sian 29271546Sian#include <sys/cdefs.h> 30271546Sian#include <sys/param.h> 31271546Sian 32271546Sian#include <dev/ofw/ofw_bus.h> 33271546Sian#include <dev/ofw/ofw_bus_subr.h> 34271546Sian 35271546Sian#include "fdt_pinctrl_if.h" 36271546Sian 37271546Sian#include <dev/fdt/fdt_common.h> 38271546Sian#include <dev/fdt/fdt_pinctrl.h> 39271546Sian 40271546Sianint 41271546Sianfdt_pinctrl_configure(device_t client, u_int index) 42271546Sian{ 43271546Sian device_t pinctrl; 44271546Sian phandle_t *configs; 45271546Sian int i, nconfigs; 46271546Sian char name[16]; 47271546Sian 48271546Sian snprintf(name, sizeof(name), "pinctrl-%u", index); 49283485Sian nconfigs = OF_getencprop_alloc(ofw_bus_get_node(client), name, 50271546Sian sizeof(*configs), (void **)&configs); 51271546Sian if (nconfigs < 0) 52271546Sian return (ENOENT); 53271546Sian if (nconfigs == 0) 54271546Sian return (0); /* Empty property is documented as valid. */ 55271546Sian for (i = 0; i < nconfigs; i++) { 56271546Sian if ((pinctrl = OF_device_from_xref(configs[i])) != NULL) 57271546Sian FDT_PINCTRL_CONFIGURE(pinctrl, configs[i]); 58271546Sian } 59271546Sian free(configs, M_OFWPROP); 60271546Sian return (0); 61271546Sian} 62271546Sian 63271546Sianint 64271546Sianfdt_pinctrl_configure_by_name(device_t client, const char * name) 65271546Sian{ 66271546Sian char * names; 67271546Sian int i, offset, nameslen; 68271546Sian 69271546Sian nameslen = OF_getprop_alloc(ofw_bus_get_node(client), "pinctrl-names", 70271546Sian sizeof(*names), (void **)&names); 71271546Sian if (nameslen <= 0) 72271546Sian return (ENOENT); 73271546Sian for (i = 0, offset = 0; offset < nameslen; i++) { 74271546Sian if (strcmp(name, &names[offset]) == 0) 75271546Sian break; 76271546Sian offset += strlen(&names[offset]) + 1; 77271546Sian } 78271546Sian free(names, M_OFWPROP); 79271546Sian if (offset < nameslen) 80271546Sian return (fdt_pinctrl_configure(client, i)); 81271546Sian else 82271546Sian return (ENOENT); 83271546Sian} 84271546Sian 85271546Sianstatic int 86271546Sianpinctrl_register_children(device_t pinctrl, phandle_t parent, 87271546Sian const char *pinprop) 88271546Sian{ 89271546Sian phandle_t node; 90271546Sian 91271546Sian /* 92271546Sian * Recursively descend from parent, looking for nodes that have the 93271546Sian * given property, and associate the pinctrl device_t with each one. 94271546Sian */ 95271546Sian for (node = OF_child(parent); node != 0; node = OF_peer(node)) { 96271546Sian pinctrl_register_children(pinctrl, node, pinprop); 97271546Sian if (pinprop == NULL || OF_hasprop(node, pinprop)) { 98271546Sian OF_device_register_xref(OF_xref_from_node(node), 99271546Sian pinctrl); 100271546Sian } 101271546Sian } 102271546Sian return (0); 103271546Sian} 104271546Sian 105271546Sianint 106271546Sianfdt_pinctrl_register(device_t pinctrl, const char *pinprop) 107271546Sian{ 108271546Sian phandle_t node; 109271546Sian 110271546Sian node = ofw_bus_get_node(pinctrl); 111271546Sian OF_device_register_xref(OF_xref_from_node(node), pinctrl); 112271546Sian return (pinctrl_register_children(pinctrl, node, pinprop)); 113271546Sian} 114271546Sian 115271546Sianstatic int 116271546Sianpinctrl_configure_children(device_t pinctrl, phandle_t parent) 117271546Sian{ 118271546Sian phandle_t node, *configs; 119271546Sian int i, nconfigs; 120271546Sian 121271546Sian for (node = OF_child(parent); node != 0; node = OF_peer(node)) { 122271546Sian if (!fdt_is_enabled(node)) 123271546Sian continue; 124271546Sian pinctrl_configure_children(pinctrl, node); 125283485Sian nconfigs = OF_getencprop_alloc(node, "pinctrl-0", 126271546Sian sizeof(*configs), (void **)&configs); 127276275Sian if (nconfigs <= 0) 128276275Sian continue; 129276275Sian if (bootverbose) { 130283485Sian char name[32]; 131271546Sian OF_getprop(node, "name", &name, sizeof(name)); 132276275Sian printf("Processing %d pin-config node(s) in pinctrl-0 for %s\n", 133276275Sian nconfigs, name); 134271546Sian } 135271546Sian for (i = 0; i < nconfigs; i++) { 136271546Sian if (OF_device_from_xref(configs[i]) == pinctrl) 137271546Sian FDT_PINCTRL_CONFIGURE(pinctrl, configs[i]); 138271546Sian } 139271546Sian free(configs, M_OFWPROP); 140271546Sian } 141271546Sian return (0); 142271546Sian} 143271546Sian 144271546Sianint 145271546Sianfdt_pinctrl_configure_tree(device_t pinctrl) 146271546Sian{ 147271546Sian 148271546Sian return (pinctrl_configure_children(pinctrl, OF_peer(0))); 149271546Sian} 150271546Sian 151