xref: /f-stack/freebsd/mips/mediatek/mtk_pinctrl.c (revision 22ce4aff)
1 /*-
2  * Copyright (c) 2016 Stanislav Galabov
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions, and the following disclaimer,
10  *    without modification, immediately at the beginning of the file.
11  * 2. The name of the author may not be used to endorse or promote products
12  *    derived from this software without specific prior written permission.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
18  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  */
27 
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30 
31 #include <sys/param.h>
32 #include <sys/kernel.h>
33 #include <sys/bus.h>
34 #include <sys/module.h>
35 
36 #include <dev/fdt/fdt_common.h>
37 #include <dev/ofw/openfirm.h>
38 #include <dev/ofw/ofw_bus.h>
39 #include <dev/ofw/ofw_bus_subr.h>
40 
41 #include <dev/fdt/fdt_pinctrl.h>
42 #include <mips/mediatek/mtk_sysctl.h>
43 #include <mips/mediatek/mtk_soc.h>
44 #include <mips/mediatek/mtk_pinctrl.h>
45 
46 #include "fdt_pinctrl_if.h"
47 
48 static const struct ofw_compat_data compat_data[] = {
49 	{ "ralink,rt2880-pinmux",	1 },
50 
51 	/* Sentinel */
52 	{ NULL,				0 }
53 };
54 
55 static int
mtk_pinctrl_probe(device_t dev)56 mtk_pinctrl_probe(device_t dev)
57 {
58 
59 	if (!ofw_bus_status_okay(dev))
60 		return (ENXIO);
61 
62 	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
63 		return (ENXIO);
64 
65 	device_set_desc(dev, "MTK Pin Controller");
66 
67 	return (0);
68 }
69 
70 static int
mtk_pinctrl_attach(device_t dev)71 mtk_pinctrl_attach(device_t dev)
72 {
73 
74 	if (device_get_unit(dev) != 0) {
75 		device_printf(dev, "Only one pin control allowed\n");
76 		return (ENXIO);
77 	}
78 
79 	if (bootverbose)
80 		device_printf(dev, "GPIO mode start: 0x%08x\n",
81 		    mtk_sysctl_get(SYSCTL_GPIOMODE));
82 
83 	fdt_pinctrl_register(dev, NULL);
84 	fdt_pinctrl_configure_tree(dev);
85 
86 	if (bootverbose)
87 		device_printf(dev, "GPIO mode end  : 0x%08x\n",
88 		    mtk_sysctl_get(SYSCTL_GPIOMODE));
89 
90 	return (0);
91 }
92 
93 static int
mtk_pinctrl_process_entry(device_t dev,struct mtk_pin_group * table,const char * group,char * func)94 mtk_pinctrl_process_entry(device_t dev, struct mtk_pin_group *table,
95     const char *group, char *func)
96 {
97 	uint32_t val;
98 	int found = 0, i, j;
99 
100 	for (i = 0; table[i].name != NULL; i++) {
101                 if (strcmp(table[i].name, group) == 0) {
102 			found = 1;
103                         break;
104 		}
105         }
106 
107 	if (!found)
108 		return (ENOENT);
109 
110         for (j = 0; j < table[i].funcnum; j++) {
111                 if (strcmp(table[i].functions[j].name, func) == 0) {
112                         val = mtk_sysctl_get(table[i].sysc_reg);
113                         val &= ~(table[i].mask << table[i].offset);
114                         val |= (table[i].functions[j].value << table[i].offset);
115                         mtk_sysctl_set(table[i].sysc_reg, val);
116                         return (0);
117 		}
118 	}
119 
120 	return (ENOENT);
121 }
122 
123 static int
mtk_pinctrl_process_node(device_t dev,struct mtk_pin_group * table,phandle_t node)124 mtk_pinctrl_process_node(device_t dev, struct mtk_pin_group *table,
125     phandle_t node)
126 {
127 	const char **group_list = NULL;
128 	char *pin_function = NULL;
129 	int ret, num_groups, i;
130 
131 	ret = 0;
132 
133 	num_groups = ofw_bus_string_list_to_array(node, "ralink,group",
134 	    &group_list);
135 
136 	if (num_groups <= 0)
137 		return (ENOENT);
138 
139 	if (OF_getprop_alloc_multi(node, "ralink,function", sizeof(*pin_function),
140 			     (void **)&pin_function) == -1) {
141 		ret = ENOENT;
142 		goto out;
143 	}
144 
145 	for (i = 0; i < num_groups; i++) {
146 		if ((ret = mtk_pinctrl_process_entry(dev, table, group_list[i],
147 		    pin_function)) != 0)
148 			goto out;
149 	}
150 
151 out:
152 	OF_prop_free(group_list);
153 	OF_prop_free(pin_function);
154 	return (ret);
155 }
156 
157 static int
mtk_pinctrl_configure(device_t dev,phandle_t cfgxref)158 mtk_pinctrl_configure(device_t dev, phandle_t cfgxref)
159 {
160 	struct mtk_pin_group *pintable;
161 	phandle_t node, child;
162 	uint32_t socid;
163 	int ret;
164 
165 	node = OF_node_from_xref(cfgxref);
166 	ret = 0;
167 
168 	/* Now, get the system type, so we can get the proper GPIO mode array */
169 	socid = mtk_soc_get_socid();
170 
171 	switch (socid) {
172 	case MTK_SOC_RT2880:
173 		pintable = rt2880_pintable;
174 		break;
175 	case MTK_SOC_RT3050: /* fallthrough */
176 	case MTK_SOC_RT3052:
177 	case MTK_SOC_RT3350:
178 		pintable = rt3050_pintable;
179 		break;
180 	case MTK_SOC_RT3352:
181 		pintable = rt3352_pintable;
182 		break;
183 	case MTK_SOC_RT3662: /* fallthrough */
184 	case MTK_SOC_RT3883:
185 		pintable = rt3883_pintable;
186 		break;
187 	case MTK_SOC_RT5350:
188 		pintable = rt5350_pintable;
189 		break;
190 	case MTK_SOC_MT7620A: /* fallthrough */
191 	case MTK_SOC_MT7620N:
192 		pintable = mt7620_pintable;
193 		break;
194 	case MTK_SOC_MT7628: /* fallthrough */
195 	case MTK_SOC_MT7688:
196 		pintable = mt7628_pintable;
197 		break;
198 	case MTK_SOC_MT7621:
199 		pintable = mt7621_pintable;
200 		break;
201 	default:
202 		ret = ENOENT;
203 		goto out;
204 	}
205 
206 	/*
207 	 * OpenWRT dts files have single child within the pinctrl nodes, which
208 	 * contains the 'ralink,group' and 'ralink,function' properties.
209 	 */
210 	for (child = OF_child(node); child != 0 && child != -1;
211 	    child = OF_peer(child)) {
212 		if ((ret = mtk_pinctrl_process_node(dev, pintable, child)) != 0)
213 			return (ret);
214 	}
215 
216 out:
217 	return (ret);
218 }
219 
220 static device_method_t mtk_pinctrl_methods[] = {
221 	DEVMETHOD(device_probe,			mtk_pinctrl_probe),
222 	DEVMETHOD(device_attach,		mtk_pinctrl_attach),
223 
224 	/* fdt_pinctrl interface */
225 	DEVMETHOD(fdt_pinctrl_configure,	mtk_pinctrl_configure),
226 
227 	DEVMETHOD_END
228 };
229 
230 static driver_t mtk_pinctrl_driver = {
231 	"pinctrl",
232 	mtk_pinctrl_methods,
233 	0,
234 };
235 static devclass_t mtk_pinctrl_devclass;
236 
237 EARLY_DRIVER_MODULE(mtk_pinctrl, simplebus, mtk_pinctrl_driver,
238     mtk_pinctrl_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_EARLY);
239 
240 MODULE_DEPEND(mtk_pinctrl, mtk_sysctl, 1, 1, 1);
241