fdt_pinctrl.c revision 1.4.6.2 1 1.4.6.2 pgoyette /* $NetBSD: fdt_pinctrl.c,v 1.4.6.2 2019/01/18 08:50:25 pgoyette 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.6.2 pgoyette __KERNEL_RCSID(0, "$NetBSD: fdt_pinctrl.c,v 1.4.6.2 2019/01/18 08:50:25 pgoyette 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.4.6.1 pgoyette #include <sys/queue.h>
37 1.1 marty
38 1.1 marty #include <libfdt.h>
39 1.1 marty #include <dev/fdt/fdtvar.h>
40 1.1 marty
41 1.1 marty struct fdtbus_pinctrl_controller {
42 1.4 jmcneill device_t pc_dev;
43 1.1 marty int pc_phandle;
44 1.1 marty const struct fdtbus_pinctrl_controller_func *pc_funcs;
45 1.1 marty
46 1.4.6.1 pgoyette LIST_ENTRY(fdtbus_pinctrl_controller) pc_next;
47 1.1 marty };
48 1.1 marty
49 1.4.6.1 pgoyette static LIST_HEAD(, fdtbus_pinctrl_controller) fdtbus_pinctrl_controllers =
50 1.4.6.1 pgoyette LIST_HEAD_INITIALIZER(fdtbus_pinctrl_controllers);
51 1.1 marty
52 1.1 marty int
53 1.4 jmcneill fdtbus_register_pinctrl_config(device_t dev, int phandle,
54 1.1 marty const struct fdtbus_pinctrl_controller_func *funcs)
55 1.1 marty {
56 1.1 marty struct fdtbus_pinctrl_controller *pc;
57 1.1 marty
58 1.1 marty pc = kmem_alloc(sizeof(*pc), KM_SLEEP);
59 1.4 jmcneill pc->pc_dev = dev;
60 1.1 marty pc->pc_phandle = phandle;
61 1.1 marty pc->pc_funcs = funcs;
62 1.1 marty
63 1.4.6.1 pgoyette LIST_INSERT_HEAD(&fdtbus_pinctrl_controllers, pc, pc_next);
64 1.1 marty
65 1.1 marty return 0;
66 1.1 marty }
67 1.1 marty
68 1.2 marty static struct fdtbus_pinctrl_controller *
69 1.2 marty fdtbus_pinctrl_lookup(int phandle)
70 1.1 marty {
71 1.1 marty struct fdtbus_pinctrl_controller *pc;
72 1.1 marty
73 1.4.6.1 pgoyette LIST_FOREACH(pc, &fdtbus_pinctrl_controllers, pc_next) {
74 1.2 marty if (pc->pc_phandle == phandle)
75 1.2 marty return pc;
76 1.4.6.1 pgoyette }
77 1.1 marty
78 1.2 marty return NULL;
79 1.1 marty }
80 1.1 marty
81 1.2 marty int
82 1.2 marty fdtbus_pinctrl_set_config_index(int phandle, u_int index)
83 1.1 marty {
84 1.2 marty struct fdtbus_pinctrl_controller *pc;
85 1.4 jmcneill const u_int *pinctrl_data;
86 1.4 jmcneill char buf[16];
87 1.4 jmcneill u_int xref, pinctrl_cells;
88 1.4 jmcneill int len, error;
89 1.4 jmcneill
90 1.4 jmcneill snprintf(buf, sizeof(buf), "pinctrl-%u", index);
91 1.4 jmcneill
92 1.4 jmcneill pinctrl_data = fdtbus_get_prop(phandle, buf, &len);
93 1.4 jmcneill if (pinctrl_data == NULL)
94 1.4 jmcneill return ENOENT;
95 1.4 jmcneill
96 1.4 jmcneill while (len > 0) {
97 1.4 jmcneill xref = fdtbus_get_phandle_from_native(be32toh(pinctrl_data[0]));
98 1.4 jmcneill pc = fdtbus_pinctrl_lookup(xref);
99 1.4 jmcneill if (pc == NULL)
100 1.4 jmcneill return ENXIO;
101 1.4 jmcneill
102 1.4 jmcneill if (of_getprop_uint32(OF_parent(xref), "#pinctrl-cells", &pinctrl_cells) != 0)
103 1.4 jmcneill pinctrl_cells = 1;
104 1.4 jmcneill
105 1.4 jmcneill error = pc->pc_funcs->set_config(pc->pc_dev, pinctrl_data, pinctrl_cells * 4);
106 1.4 jmcneill if (error != 0)
107 1.4 jmcneill return error;
108 1.1 marty
109 1.4 jmcneill pinctrl_data += pinctrl_cells;
110 1.4 jmcneill len -= (pinctrl_cells * 4);
111 1.2 marty }
112 1.1 marty
113 1.4 jmcneill return 0;
114 1.1 marty }
115 1.1 marty
116 1.2 marty int
117 1.2 marty fdtbus_pinctrl_set_config(int phandle, const char *cfgname)
118 1.1 marty {
119 1.4 jmcneill const char *pinctrl_names, *name;
120 1.4 jmcneill int len, index;
121 1.2 marty
122 1.4 jmcneill if ((len = OF_getproplen(phandle, "pinctrl-names")) < 0)
123 1.2 marty return -1;
124 1.2 marty
125 1.4 jmcneill pinctrl_names = fdtbus_get_string(phandle, "pinctrl-names");
126 1.4 jmcneill
127 1.4 jmcneill for (name = pinctrl_names, index = 0; len > 0;
128 1.4.6.2 pgoyette len -= strlen(name) + 1, name += strlen(name) + 1, index++) {
129 1.4 jmcneill if (strcmp(name, cfgname) == 0)
130 1.2 marty return fdtbus_pinctrl_set_config_index(phandle, index);
131 1.2 marty }
132 1.1 marty
133 1.4 jmcneill /* Not found */
134 1.2 marty return -1;
135 1.1 marty }
136 1.4 jmcneill
137 1.4 jmcneill static void
138 1.4 jmcneill fdtbus_pinctrl_configure_node(int phandle)
139 1.4 jmcneill {
140 1.4 jmcneill char buf[256];
141 1.4 jmcneill int child, error;
142 1.4 jmcneill
143 1.4 jmcneill for (child = OF_child(phandle); child; child = OF_peer(child)) {
144 1.4 jmcneill if (!fdtbus_status_okay(child))
145 1.4 jmcneill continue;
146 1.4 jmcneill
147 1.4 jmcneill /* Configure child nodes */
148 1.4 jmcneill fdtbus_pinctrl_configure_node(child);
149 1.4 jmcneill
150 1.4 jmcneill /*
151 1.4 jmcneill * Set configuration 0 for this node. This may fail if the
152 1.4 jmcneill * pinctrl provider is missing; that's OK, we will re-configure
153 1.4 jmcneill * when that provider attaches.
154 1.4 jmcneill */
155 1.4 jmcneill fdtbus_get_path(child, buf, sizeof(buf));
156 1.4 jmcneill error = fdtbus_pinctrl_set_config_index(child, 0);
157 1.4 jmcneill if (error == 0)
158 1.4 jmcneill aprint_debug("pinctrl: set config pinctrl-0 for %s\n", buf);
159 1.4 jmcneill else if (error != ENOENT)
160 1.4 jmcneill aprint_debug("pinctrl: failed to set config pinctrl-0 for %s: %d\n", buf, error);
161 1.4 jmcneill }
162 1.4 jmcneill }
163 1.4 jmcneill
164 1.4 jmcneill void
165 1.4 jmcneill fdtbus_pinctrl_configure(void)
166 1.4 jmcneill {
167 1.4 jmcneill fdtbus_pinctrl_configure_node(OF_finddevice("/"));
168 1.4 jmcneill }
169