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