fdt_pinctrl.c revision 1.4 1 1.4 jmcneill /* $NetBSD: fdt_pinctrl.c,v 1.4 2017/07/02 15:27:58 jmcneill Exp $ */
2 1.1 marty
3 1.1 marty /*-
4 1.4 jmcneill * Copyright (c) 2017 Jared McNeill <jmcneill (at) invisible.ca>
5 1.2 marty * Copyright (c) 2015 Martin Fouts
6 1.1 marty * All rights reserved.
7 1.1 marty *
8 1.1 marty * Redistribution and use in source and binary forms, with or without
9 1.1 marty * modification, are permitted provided that the following conditions
10 1.1 marty * are met:
11 1.1 marty * 1. Redistributions of source code must retain the above copyright
12 1.1 marty * notice, this list of conditions and the following disclaimer.
13 1.1 marty * 2. Redistributions in binary form must reproduce the above copyright
14 1.1 marty * notice, this list of conditions and the following disclaimer in the
15 1.1 marty * documentation and/or other materials provided with the distribution.
16 1.1 marty *
17 1.1 marty * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 1.1 marty * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 1.1 marty * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 1.1 marty * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 1.1 marty * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22 1.1 marty * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 1.1 marty * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 1.1 marty * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 1.1 marty * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 1.1 marty * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 1.1 marty * SUCH DAMAGE.
28 1.1 marty */
29 1.1 marty
30 1.1 marty #include <sys/cdefs.h>
31 1.4 jmcneill __KERNEL_RCSID(0, "$NetBSD: fdt_pinctrl.c,v 1.4 2017/07/02 15:27:58 jmcneill Exp $");
32 1.1 marty
33 1.1 marty #include <sys/param.h>
34 1.1 marty #include <sys/bus.h>
35 1.1 marty #include <sys/kmem.h>
36 1.1 marty
37 1.1 marty #include <libfdt.h>
38 1.1 marty #include <dev/fdt/fdtvar.h>
39 1.1 marty
40 1.1 marty struct fdtbus_pinctrl_controller {
41 1.4 jmcneill device_t pc_dev;
42 1.1 marty int pc_phandle;
43 1.1 marty const struct fdtbus_pinctrl_controller_func *pc_funcs;
44 1.1 marty
45 1.1 marty struct fdtbus_pinctrl_controller *pc_next;
46 1.1 marty };
47 1.1 marty
48 1.1 marty static struct fdtbus_pinctrl_controller *fdtbus_pc = NULL;
49 1.1 marty
50 1.1 marty int
51 1.4 jmcneill fdtbus_register_pinctrl_config(device_t dev, int phandle,
52 1.1 marty const struct fdtbus_pinctrl_controller_func *funcs)
53 1.1 marty {
54 1.1 marty struct fdtbus_pinctrl_controller *pc;
55 1.1 marty
56 1.1 marty pc = kmem_alloc(sizeof(*pc), KM_SLEEP);
57 1.4 jmcneill pc->pc_dev = dev;
58 1.1 marty pc->pc_phandle = phandle;
59 1.1 marty pc->pc_funcs = funcs;
60 1.1 marty
61 1.1 marty pc->pc_next = fdtbus_pc;
62 1.1 marty fdtbus_pc = pc;
63 1.1 marty
64 1.1 marty return 0;
65 1.1 marty }
66 1.1 marty
67 1.2 marty static struct fdtbus_pinctrl_controller *
68 1.2 marty fdtbus_pinctrl_lookup(int phandle)
69 1.1 marty {
70 1.1 marty struct fdtbus_pinctrl_controller *pc;
71 1.1 marty
72 1.2 marty for (pc = fdtbus_pc; pc; pc = pc->pc_next)
73 1.2 marty if (pc->pc_phandle == phandle)
74 1.2 marty return pc;
75 1.1 marty
76 1.2 marty return NULL;
77 1.1 marty }
78 1.1 marty
79 1.2 marty int
80 1.2 marty fdtbus_pinctrl_set_config_index(int phandle, u_int index)
81 1.1 marty {
82 1.2 marty struct fdtbus_pinctrl_controller *pc;
83 1.4 jmcneill const u_int *pinctrl_data;
84 1.4 jmcneill char buf[16];
85 1.4 jmcneill u_int xref, pinctrl_cells;
86 1.4 jmcneill int len, error;
87 1.4 jmcneill
88 1.4 jmcneill snprintf(buf, sizeof(buf), "pinctrl-%u", index);
89 1.4 jmcneill
90 1.4 jmcneill pinctrl_data = fdtbus_get_prop(phandle, buf, &len);
91 1.4 jmcneill if (pinctrl_data == NULL)
92 1.4 jmcneill return ENOENT;
93 1.4 jmcneill
94 1.4 jmcneill while (len > 0) {
95 1.4 jmcneill xref = fdtbus_get_phandle_from_native(be32toh(pinctrl_data[0]));
96 1.4 jmcneill pc = fdtbus_pinctrl_lookup(xref);
97 1.4 jmcneill if (pc == NULL)
98 1.4 jmcneill return ENXIO;
99 1.4 jmcneill
100 1.4 jmcneill if (of_getprop_uint32(OF_parent(xref), "#pinctrl-cells", &pinctrl_cells) != 0)
101 1.4 jmcneill pinctrl_cells = 1;
102 1.4 jmcneill
103 1.4 jmcneill error = pc->pc_funcs->set_config(pc->pc_dev, pinctrl_data, pinctrl_cells * 4);
104 1.4 jmcneill if (error != 0)
105 1.4 jmcneill return error;
106 1.1 marty
107 1.4 jmcneill pinctrl_data += pinctrl_cells;
108 1.4 jmcneill len -= (pinctrl_cells * 4);
109 1.2 marty }
110 1.1 marty
111 1.4 jmcneill return 0;
112 1.1 marty }
113 1.1 marty
114 1.2 marty int
115 1.2 marty fdtbus_pinctrl_set_config(int phandle, const char *cfgname)
116 1.1 marty {
117 1.4 jmcneill const char *pinctrl_names, *name;
118 1.4 jmcneill int len, index;
119 1.2 marty
120 1.4 jmcneill if ((len = OF_getproplen(phandle, "pinctrl-names")) < 0)
121 1.2 marty return -1;
122 1.2 marty
123 1.4 jmcneill pinctrl_names = fdtbus_get_string(phandle, "pinctrl-names");
124 1.4 jmcneill
125 1.4 jmcneill for (name = pinctrl_names, index = 0; len > 0;
126 1.4 jmcneill name += strlen(name) + 1, index++) {
127 1.4 jmcneill if (strcmp(name, cfgname) == 0)
128 1.2 marty return fdtbus_pinctrl_set_config_index(phandle, index);
129 1.2 marty }
130 1.1 marty
131 1.4 jmcneill /* Not found */
132 1.2 marty return -1;
133 1.1 marty }
134 1.4 jmcneill
135 1.4 jmcneill static void
136 1.4 jmcneill fdtbus_pinctrl_configure_node(int phandle)
137 1.4 jmcneill {
138 1.4 jmcneill char buf[256];
139 1.4 jmcneill int child, error;
140 1.4 jmcneill
141 1.4 jmcneill for (child = OF_child(phandle); child; child = OF_peer(child)) {
142 1.4 jmcneill if (!fdtbus_status_okay(child))
143 1.4 jmcneill continue;
144 1.4 jmcneill
145 1.4 jmcneill /* Configure child nodes */
146 1.4 jmcneill fdtbus_pinctrl_configure_node(child);
147 1.4 jmcneill
148 1.4 jmcneill /*
149 1.4 jmcneill * Set configuration 0 for this node. This may fail if the
150 1.4 jmcneill * pinctrl provider is missing; that's OK, we will re-configure
151 1.4 jmcneill * when that provider attaches.
152 1.4 jmcneill */
153 1.4 jmcneill fdtbus_get_path(child, buf, sizeof(buf));
154 1.4 jmcneill error = fdtbus_pinctrl_set_config_index(child, 0);
155 1.4 jmcneill if (error == 0)
156 1.4 jmcneill aprint_debug("pinctrl: set config pinctrl-0 for %s\n", buf);
157 1.4 jmcneill else if (error != ENOENT)
158 1.4 jmcneill aprint_debug("pinctrl: failed to set config pinctrl-0 for %s: %d\n", buf, error);
159 1.4 jmcneill }
160 1.4 jmcneill }
161 1.4 jmcneill
162 1.4 jmcneill void
163 1.4 jmcneill fdtbus_pinctrl_configure(void)
164 1.4 jmcneill {
165 1.4 jmcneill fdtbus_pinctrl_configure_node(OF_finddevice("/"));
166 1.4 jmcneill }
167