xref: /freebsd/sys/dev/fdt/fdt_pinctrl.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
1b8ed20dbSIan Lepore /*-
2b8ed20dbSIan Lepore  * Copyright (c) 2014 Ian Lepore <ian@freebsd.org>
3b8ed20dbSIan Lepore  * All rights reserved.
4b8ed20dbSIan Lepore  *
5b8ed20dbSIan Lepore  * Redistribution and use in source and binary forms, with or without
6b8ed20dbSIan Lepore  * modification, are permitted provided that the following conditions
7b8ed20dbSIan Lepore  * are met:
8b8ed20dbSIan Lepore  * 1. Redistributions of source code must retain the above copyright
9b8ed20dbSIan Lepore  *    notice, this list of conditions and the following disclaimer.
10b8ed20dbSIan Lepore  * 2. Redistributions in binary form must reproduce the above copyright
11b8ed20dbSIan Lepore  *    notice, this list of conditions and the following disclaimer in the
12b8ed20dbSIan Lepore  *    documentation and/or other materials provided with the distribution.
13b8ed20dbSIan Lepore  *
14b8ed20dbSIan Lepore  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15b8ed20dbSIan Lepore  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16b8ed20dbSIan Lepore  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17b8ed20dbSIan Lepore  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18b8ed20dbSIan Lepore  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19b8ed20dbSIan Lepore  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20b8ed20dbSIan Lepore  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21b8ed20dbSIan Lepore  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22b8ed20dbSIan Lepore  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23b8ed20dbSIan Lepore  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24b8ed20dbSIan Lepore  * SUCH DAMAGE.
25b8ed20dbSIan Lepore  */
26b8ed20dbSIan Lepore 
27b8ed20dbSIan Lepore #include <sys/param.h>
28b8ed20dbSIan Lepore 
29b8ed20dbSIan Lepore #include <dev/ofw/ofw_bus.h>
30b8ed20dbSIan Lepore #include <dev/ofw/ofw_bus_subr.h>
31b8ed20dbSIan Lepore 
32b8ed20dbSIan Lepore #include "fdt_pinctrl_if.h"
33b8ed20dbSIan Lepore 
34b8ed20dbSIan Lepore #include <dev/fdt/fdt_common.h>
35b8ed20dbSIan Lepore #include <dev/fdt/fdt_pinctrl.h>
36b8ed20dbSIan Lepore 
37b8ed20dbSIan Lepore int
fdt_pinctrl_configure(device_t client,u_int index)38b8ed20dbSIan Lepore fdt_pinctrl_configure(device_t client, u_int index)
39b8ed20dbSIan Lepore {
40b8ed20dbSIan Lepore 	device_t pinctrl;
41b8ed20dbSIan Lepore 	phandle_t *configs;
42b8ed20dbSIan Lepore 	int i, nconfigs;
43b8ed20dbSIan Lepore 	char name[16];
44b8ed20dbSIan Lepore 
45b8ed20dbSIan Lepore 	snprintf(name, sizeof(name), "pinctrl-%u", index);
46f7604b1bSOleksandr Tymoshenko 	nconfigs = OF_getencprop_alloc_multi(ofw_bus_get_node(client), name,
47b8ed20dbSIan Lepore 	    sizeof(*configs), (void **)&configs);
48b8ed20dbSIan Lepore 	if (nconfigs < 0)
49b8ed20dbSIan Lepore 		return (ENOENT);
50b8ed20dbSIan Lepore 	if (nconfigs == 0)
51b8ed20dbSIan Lepore 		return (0); /* Empty property is documented as valid. */
52b8ed20dbSIan Lepore 	for (i = 0; i < nconfigs; i++) {
53b8ed20dbSIan Lepore 		if ((pinctrl = OF_device_from_xref(configs[i])) != NULL)
54b8ed20dbSIan Lepore 			FDT_PINCTRL_CONFIGURE(pinctrl, configs[i]);
55b8ed20dbSIan Lepore 	}
56bc90a48cSOleksandr Tymoshenko 	OF_prop_free(configs);
57b8ed20dbSIan Lepore 	return (0);
58b8ed20dbSIan Lepore }
59b8ed20dbSIan Lepore 
60b8ed20dbSIan Lepore int
fdt_pinctrl_configure_by_name(device_t client,const char * name)61b8ed20dbSIan Lepore fdt_pinctrl_configure_by_name(device_t client, const char * name)
62b8ed20dbSIan Lepore {
63b8ed20dbSIan Lepore 	char * names;
64b8ed20dbSIan Lepore 	int i, offset, nameslen;
65b8ed20dbSIan Lepore 
66b8ed20dbSIan Lepore 	nameslen = OF_getprop_alloc(ofw_bus_get_node(client), "pinctrl-names",
67217d17bcSOleksandr Tymoshenko 	    (void **)&names);
68b8ed20dbSIan Lepore 	if (nameslen <= 0)
69b8ed20dbSIan Lepore 		return (ENOENT);
70b8ed20dbSIan Lepore 	for (i = 0, offset = 0; offset < nameslen; i++) {
71b8ed20dbSIan Lepore 		if (strcmp(name, &names[offset]) == 0)
72b8ed20dbSIan Lepore 			break;
73b8ed20dbSIan Lepore 		offset += strlen(&names[offset]) + 1;
74b8ed20dbSIan Lepore 	}
75bc90a48cSOleksandr Tymoshenko 	OF_prop_free(names);
76b8ed20dbSIan Lepore 	if (offset < nameslen)
77b8ed20dbSIan Lepore 		return (fdt_pinctrl_configure(client, i));
78b8ed20dbSIan Lepore 	else
79b8ed20dbSIan Lepore 		return (ENOENT);
80b8ed20dbSIan Lepore }
81b8ed20dbSIan Lepore 
82b8ed20dbSIan Lepore static int
pinctrl_register_children(device_t pinctrl,phandle_t parent,const char * pinprop)83b8ed20dbSIan Lepore pinctrl_register_children(device_t pinctrl, phandle_t parent,
84b8ed20dbSIan Lepore     const char *pinprop)
85b8ed20dbSIan Lepore {
86b8ed20dbSIan Lepore 	phandle_t node;
87b8ed20dbSIan Lepore 
88b8ed20dbSIan Lepore 	/*
89b8ed20dbSIan Lepore 	 * Recursively descend from parent, looking for nodes that have the
90b8ed20dbSIan Lepore 	 * given property, and associate the pinctrl device_t with each one.
91b8ed20dbSIan Lepore 	 */
92b8ed20dbSIan Lepore 	for (node = OF_child(parent); node != 0; node = OF_peer(node)) {
93b8ed20dbSIan Lepore 		pinctrl_register_children(pinctrl, node, pinprop);
94b8ed20dbSIan Lepore 		if (pinprop == NULL || OF_hasprop(node, pinprop)) {
95b8ed20dbSIan Lepore 			OF_device_register_xref(OF_xref_from_node(node),
96b8ed20dbSIan Lepore 			    pinctrl);
97b8ed20dbSIan Lepore 		}
98b8ed20dbSIan Lepore 	}
99b8ed20dbSIan Lepore 	return (0);
100b8ed20dbSIan Lepore }
101b8ed20dbSIan Lepore 
102b8ed20dbSIan Lepore int
fdt_pinctrl_register(device_t pinctrl,const char * pinprop)103b8ed20dbSIan Lepore fdt_pinctrl_register(device_t pinctrl, const char *pinprop)
104b8ed20dbSIan Lepore {
105b8ed20dbSIan Lepore 	phandle_t node;
106*413d07eaSEmmanuel Vadot 	int ret;
107b8ed20dbSIan Lepore 
108*413d07eaSEmmanuel Vadot 	TSENTER();
109b8ed20dbSIan Lepore 	node = ofw_bus_get_node(pinctrl);
110b8ed20dbSIan Lepore 	OF_device_register_xref(OF_xref_from_node(node), pinctrl);
111*413d07eaSEmmanuel Vadot 	ret = pinctrl_register_children(pinctrl, node, pinprop);
112*413d07eaSEmmanuel Vadot 	TSEXIT();
113*413d07eaSEmmanuel Vadot 
114*413d07eaSEmmanuel Vadot 	return (ret);
115b8ed20dbSIan Lepore }
116b8ed20dbSIan Lepore 
117b8ed20dbSIan Lepore static int
pinctrl_configure_children(device_t pinctrl,phandle_t parent)118b8ed20dbSIan Lepore pinctrl_configure_children(device_t pinctrl, phandle_t parent)
119b8ed20dbSIan Lepore {
120b8ed20dbSIan Lepore 	phandle_t node, *configs;
121b8ed20dbSIan Lepore 	int i, nconfigs;
122b8ed20dbSIan Lepore 
123*413d07eaSEmmanuel Vadot 	TSENTER();
124*413d07eaSEmmanuel Vadot 
125b8ed20dbSIan Lepore 	for (node = OF_child(parent); node != 0; node = OF_peer(node)) {
1267bc28467SAndrew Turner 		if (!ofw_bus_node_status_okay(node))
127b8ed20dbSIan Lepore 			continue;
128b8ed20dbSIan Lepore 		pinctrl_configure_children(pinctrl, node);
129f7604b1bSOleksandr Tymoshenko 		nconfigs = OF_getencprop_alloc_multi(node, "pinctrl-0",
130b8ed20dbSIan Lepore 		    sizeof(*configs), (void **)&configs);
131b8ed20dbSIan Lepore 		if (nconfigs <= 0)
132b8ed20dbSIan Lepore 			continue;
133f088768bSIan Lepore 		if (bootverbose) {
134f088768bSIan Lepore 			char name[32];
135f088768bSIan Lepore 			OF_getprop(node, "name", &name, sizeof(name));
136f088768bSIan Lepore 			printf("Processing %d pin-config node(s) in pinctrl-0 for %s\n",
137f088768bSIan Lepore 			    nconfigs, name);
138f088768bSIan Lepore 		}
139b8ed20dbSIan Lepore 		for (i = 0; i < nconfigs; i++) {
140b8ed20dbSIan Lepore 			if (OF_device_from_xref(configs[i]) == pinctrl)
141b8ed20dbSIan Lepore 				FDT_PINCTRL_CONFIGURE(pinctrl, configs[i]);
142b8ed20dbSIan Lepore 		}
143bc90a48cSOleksandr Tymoshenko 		OF_prop_free(configs);
144b8ed20dbSIan Lepore 	}
145*413d07eaSEmmanuel Vadot 	TSEXIT();
146b8ed20dbSIan Lepore 	return (0);
147b8ed20dbSIan Lepore }
148b8ed20dbSIan Lepore 
149b8ed20dbSIan Lepore int
fdt_pinctrl_configure_tree(device_t pinctrl)150b8ed20dbSIan Lepore fdt_pinctrl_configure_tree(device_t pinctrl)
151b8ed20dbSIan Lepore {
152b8ed20dbSIan Lepore 
153b8ed20dbSIan Lepore 	return (pinctrl_configure_children(pinctrl, OF_peer(0)));
154b8ed20dbSIan Lepore }
155b8ed20dbSIan Lepore 
156