xref: /freebsd/sys/dev/fdt/fdt_pinctrl.c (revision c441925e313b448ad5bc7c1ff1995058268888d8)
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  * $FreeBSD$
27b8ed20dbSIan Lepore  */
28b8ed20dbSIan Lepore 
29b8ed20dbSIan Lepore #include <sys/cdefs.h>
30b8ed20dbSIan Lepore #include <sys/param.h>
31b8ed20dbSIan Lepore 
32b8ed20dbSIan Lepore #include <dev/ofw/ofw_bus.h>
33b8ed20dbSIan Lepore #include <dev/ofw/ofw_bus_subr.h>
34b8ed20dbSIan Lepore 
35b8ed20dbSIan Lepore #include "fdt_pinctrl_if.h"
36b8ed20dbSIan Lepore 
37b8ed20dbSIan Lepore #include <dev/fdt/fdt_common.h>
38b8ed20dbSIan Lepore #include <dev/fdt/fdt_pinctrl.h>
39b8ed20dbSIan Lepore 
40b8ed20dbSIan Lepore int
41b8ed20dbSIan Lepore fdt_pinctrl_configure(device_t client, u_int index)
42b8ed20dbSIan Lepore {
43b8ed20dbSIan Lepore 	device_t pinctrl;
44b8ed20dbSIan Lepore 	phandle_t *configs;
45b8ed20dbSIan Lepore 	int i, nconfigs;
46b8ed20dbSIan Lepore 	char name[16];
47b8ed20dbSIan Lepore 
48b8ed20dbSIan Lepore 	snprintf(name, sizeof(name), "pinctrl-%u", index);
49*c441925eSIan Lepore 	nconfigs = OF_getencprop_alloc(ofw_bus_get_node(client), name,
50b8ed20dbSIan Lepore 	    sizeof(*configs), (void **)&configs);
51b8ed20dbSIan Lepore 	if (nconfigs < 0)
52b8ed20dbSIan Lepore 		return (ENOENT);
53b8ed20dbSIan Lepore 	if (nconfigs == 0)
54b8ed20dbSIan Lepore 		return (0); /* Empty property is documented as valid. */
55b8ed20dbSIan Lepore 	for (i = 0; i < nconfigs; i++) {
56b8ed20dbSIan Lepore 		if ((pinctrl = OF_device_from_xref(configs[i])) != NULL)
57b8ed20dbSIan Lepore 			FDT_PINCTRL_CONFIGURE(pinctrl, configs[i]);
58b8ed20dbSIan Lepore 	}
59b8ed20dbSIan Lepore 	free(configs, M_OFWPROP);
60b8ed20dbSIan Lepore 	return (0);
61b8ed20dbSIan Lepore }
62b8ed20dbSIan Lepore 
63b8ed20dbSIan Lepore int
64b8ed20dbSIan Lepore fdt_pinctrl_configure_by_name(device_t client, const char * name)
65b8ed20dbSIan Lepore {
66b8ed20dbSIan Lepore 	char * names;
67b8ed20dbSIan Lepore 	int i, offset, nameslen;
68b8ed20dbSIan Lepore 
69b8ed20dbSIan Lepore 	nameslen = OF_getprop_alloc(ofw_bus_get_node(client), "pinctrl-names",
70b8ed20dbSIan Lepore 	    sizeof(*names), (void **)&names);
71b8ed20dbSIan Lepore 	if (nameslen <= 0)
72b8ed20dbSIan Lepore 		return (ENOENT);
73b8ed20dbSIan Lepore 	for (i = 0, offset = 0; offset < nameslen; i++) {
74b8ed20dbSIan Lepore 		if (strcmp(name, &names[offset]) == 0)
75b8ed20dbSIan Lepore 			break;
76b8ed20dbSIan Lepore 		offset += strlen(&names[offset]) + 1;
77b8ed20dbSIan Lepore 	}
78b8ed20dbSIan Lepore 	free(names, M_OFWPROP);
79b8ed20dbSIan Lepore 	if (offset < nameslen)
80b8ed20dbSIan Lepore 		return (fdt_pinctrl_configure(client, i));
81b8ed20dbSIan Lepore 	else
82b8ed20dbSIan Lepore 		return (ENOENT);
83b8ed20dbSIan Lepore }
84b8ed20dbSIan Lepore 
85b8ed20dbSIan Lepore static int
86b8ed20dbSIan Lepore pinctrl_register_children(device_t pinctrl, phandle_t parent,
87b8ed20dbSIan Lepore     const char *pinprop)
88b8ed20dbSIan Lepore {
89b8ed20dbSIan Lepore 	phandle_t node;
90b8ed20dbSIan Lepore 
91b8ed20dbSIan Lepore 	/*
92b8ed20dbSIan Lepore 	 * Recursively descend from parent, looking for nodes that have the
93b8ed20dbSIan Lepore 	 * given property, and associate the pinctrl device_t with each one.
94b8ed20dbSIan Lepore 	 */
95b8ed20dbSIan Lepore 	for (node = OF_child(parent); node != 0; node = OF_peer(node)) {
96b8ed20dbSIan Lepore 		pinctrl_register_children(pinctrl, node, pinprop);
97b8ed20dbSIan Lepore 		if (pinprop == NULL || OF_hasprop(node, pinprop)) {
98b8ed20dbSIan Lepore 			OF_device_register_xref(OF_xref_from_node(node),
99b8ed20dbSIan Lepore 			    pinctrl);
100b8ed20dbSIan Lepore 		}
101b8ed20dbSIan Lepore 	}
102b8ed20dbSIan Lepore 	return (0);
103b8ed20dbSIan Lepore }
104b8ed20dbSIan Lepore 
105b8ed20dbSIan Lepore int
106b8ed20dbSIan Lepore fdt_pinctrl_register(device_t pinctrl, const char *pinprop)
107b8ed20dbSIan Lepore {
108b8ed20dbSIan Lepore 	phandle_t node;
109b8ed20dbSIan Lepore 
110b8ed20dbSIan Lepore 	node = ofw_bus_get_node(pinctrl);
111b8ed20dbSIan Lepore 	OF_device_register_xref(OF_xref_from_node(node), pinctrl);
112b8ed20dbSIan Lepore 	return (pinctrl_register_children(pinctrl, node, pinprop));
113b8ed20dbSIan Lepore }
114b8ed20dbSIan Lepore 
115b8ed20dbSIan Lepore static int
116b8ed20dbSIan Lepore pinctrl_configure_children(device_t pinctrl, phandle_t parent)
117b8ed20dbSIan Lepore {
118b8ed20dbSIan Lepore 	phandle_t node, *configs;
119b8ed20dbSIan Lepore 	int i, nconfigs;
120b8ed20dbSIan Lepore 
121b8ed20dbSIan Lepore 	for (node = OF_child(parent); node != 0; node = OF_peer(node)) {
122b8ed20dbSIan Lepore 		if (!fdt_is_enabled(node))
123b8ed20dbSIan Lepore 			continue;
124b8ed20dbSIan Lepore 		pinctrl_configure_children(pinctrl, node);
125b8ed20dbSIan Lepore 		nconfigs = OF_getencprop_alloc(node, "pinctrl-0",
126b8ed20dbSIan Lepore 		    sizeof(*configs), (void **)&configs);
127b8ed20dbSIan Lepore 		if (nconfigs <= 0)
128b8ed20dbSIan Lepore 			continue;
129f088768bSIan Lepore 		if (bootverbose) {
130f088768bSIan Lepore 			char name[32];
131f088768bSIan Lepore 			OF_getprop(node, "name", &name, sizeof(name));
132f088768bSIan Lepore 			printf("Processing %d pin-config node(s) in pinctrl-0 for %s\n",
133f088768bSIan Lepore 			    nconfigs, name);
134f088768bSIan Lepore 		}
135b8ed20dbSIan Lepore 		for (i = 0; i < nconfigs; i++) {
136b8ed20dbSIan Lepore 			if (OF_device_from_xref(configs[i]) == pinctrl)
137b8ed20dbSIan Lepore 				FDT_PINCTRL_CONFIGURE(pinctrl, configs[i]);
138b8ed20dbSIan Lepore 		}
139b8ed20dbSIan Lepore 		free(configs, M_OFWPROP);
140b8ed20dbSIan Lepore 	}
141b8ed20dbSIan Lepore 	return (0);
142b8ed20dbSIan Lepore }
143b8ed20dbSIan Lepore 
144b8ed20dbSIan Lepore int
145b8ed20dbSIan Lepore fdt_pinctrl_configure_tree(device_t pinctrl)
146b8ed20dbSIan Lepore {
147b8ed20dbSIan Lepore 
148b8ed20dbSIan Lepore 	return (pinctrl_configure_children(pinctrl, OF_peer(0)));
149b8ed20dbSIan Lepore }
150b8ed20dbSIan Lepore 
151