mtk_pinctrl.c revision 302408
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: stable/11/sys/mips/mediatek/mtk_pinctrl.c 299755 2016-05-14 20:05:35Z gonzo $"); 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 48static const struct ofw_compat_data compat_data[] = { 49 { "ralink,rt2880-pinmux", 1 }, 50 51 /* Sentinel */ 52 { NULL, 0 } 53}; 54 55static int 56mtk_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 70static int 71mtk_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 93static int 94mtk_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 123static int 124mtk_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(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 151out: 152 OF_prop_free(group_list); 153 OF_prop_free(pin_function); 154 return (ret); 155} 156 157static int 158mtk_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_RT3050: /* fallthrough */ 173 case MTK_SOC_RT3052: 174 case MTK_SOC_RT3350: 175 pintable = rt3050_pintable; 176 break; 177 case MTK_SOC_RT3352: 178 pintable = rt3352_pintable; 179 break; 180 case MTK_SOC_RT3662: /* fallthrough */ 181 case MTK_SOC_RT3883: 182 pintable = rt3883_pintable; 183 break; 184 case MTK_SOC_RT5350: 185 pintable = rt5350_pintable; 186 break; 187 case MTK_SOC_MT7620A: /* fallthrough */ 188 case MTK_SOC_MT7620N: 189 pintable = mt7620_pintable; 190 break; 191 case MTK_SOC_MT7628: /* fallthrough */ 192 case MTK_SOC_MT7688: 193 pintable = mt7628_pintable; 194 break; 195 case MTK_SOC_MT7621: 196 pintable = mt7621_pintable; 197 break; 198 default: 199 ret = ENOENT; 200 goto out; 201 } 202 203 /* 204 * OpenWRT dts files have single child within the pinctrl nodes, which 205 * contains the 'ralink,group' and 'ralink,function' properties. 206 */ 207 for (child = OF_child(node); child != 0 && child != -1; 208 child = OF_peer(child)) { 209 if ((ret = mtk_pinctrl_process_node(dev, pintable, child)) != 0) 210 return (ret); 211 } 212 213out: 214 return (ret); 215} 216 217static device_method_t mtk_pinctrl_methods[] = { 218 DEVMETHOD(device_probe, mtk_pinctrl_probe), 219 DEVMETHOD(device_attach, mtk_pinctrl_attach), 220 221 /* fdt_pinctrl interface */ 222 DEVMETHOD(fdt_pinctrl_configure, mtk_pinctrl_configure), 223 224 DEVMETHOD_END 225}; 226 227static driver_t mtk_pinctrl_driver = { 228 "pinctrl", 229 mtk_pinctrl_methods, 230 0, 231}; 232static devclass_t mtk_pinctrl_devclass; 233 234EARLY_DRIVER_MODULE(mtk_pinctrl, simplebus, mtk_pinctrl_driver, 235 mtk_pinctrl_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_EARLY); 236 237MODULE_DEPEND(mtk_pinctrl, mtk_sysctl, 1, 1, 1); 238