1297667Ssgalabov/*- 2297667Ssgalabov * Copyright (c) 2016 Stanislav Galabov 3297667Ssgalabov * All rights reserved. 4297667Ssgalabov * 5297667Ssgalabov * Redistribution and use in source and binary forms, with or without 6297667Ssgalabov * modification, are permitted provided that the following conditions 7297667Ssgalabov * are met: 8297667Ssgalabov * 1. Redistributions of source code must retain the above copyright 9297667Ssgalabov * notice, this list of conditions, and the following disclaimer, 10297667Ssgalabov * without modification, immediately at the beginning of the file. 11297667Ssgalabov * 2. The name of the author may not be used to endorse or promote products 12297667Ssgalabov * derived from this software without specific prior written permission. 13297667Ssgalabov * 14297667Ssgalabov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15297667Ssgalabov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16297667Ssgalabov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17297667Ssgalabov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 18297667Ssgalabov * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19297667Ssgalabov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20297667Ssgalabov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21297667Ssgalabov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22297667Ssgalabov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23297667Ssgalabov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24297667Ssgalabov * SUCH DAMAGE. 25297667Ssgalabov * 26297667Ssgalabov */ 27297667Ssgalabov 28297667Ssgalabov#include <sys/cdefs.h> 29297667Ssgalabov__FBSDID("$FreeBSD$"); 30297667Ssgalabov 31297667Ssgalabov#include <sys/param.h> 32297667Ssgalabov#include <sys/kernel.h> 33297667Ssgalabov#include <sys/bus.h> 34297667Ssgalabov#include <sys/module.h> 35297667Ssgalabov 36297667Ssgalabov#include <dev/fdt/fdt_common.h> 37297667Ssgalabov#include <dev/ofw/openfirm.h> 38297667Ssgalabov#include <dev/ofw/ofw_bus.h> 39297667Ssgalabov#include <dev/ofw/ofw_bus_subr.h> 40297667Ssgalabov 41297667Ssgalabov#include <dev/fdt/fdt_pinctrl.h> 42297667Ssgalabov#include <mips/mediatek/mtk_sysctl.h> 43298348Ssgalabov#include <mips/mediatek/mtk_soc.h> 44298348Ssgalabov#include <mips/mediatek/mtk_pinctrl.h> 45297667Ssgalabov 46297667Ssgalabov#include "fdt_pinctrl_if.h" 47297667Ssgalabov 48297667Ssgalabovstatic const struct ofw_compat_data compat_data[] = { 49298348Ssgalabov { "ralink,rt2880-pinmux", 1 }, 50297667Ssgalabov 51297667Ssgalabov /* Sentinel */ 52297667Ssgalabov { NULL, 0 } 53297667Ssgalabov}; 54297667Ssgalabov 55297667Ssgalabovstatic int 56297667Ssgalabovmtk_pinctrl_probe(device_t dev) 57297667Ssgalabov{ 58297667Ssgalabov 59297667Ssgalabov if (!ofw_bus_status_okay(dev)) 60297667Ssgalabov return (ENXIO); 61297667Ssgalabov 62297667Ssgalabov if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 63297667Ssgalabov return (ENXIO); 64297667Ssgalabov 65297667Ssgalabov device_set_desc(dev, "MTK Pin Controller"); 66297667Ssgalabov 67297667Ssgalabov return (0); 68297667Ssgalabov} 69297667Ssgalabov 70297667Ssgalabovstatic int 71297667Ssgalabovmtk_pinctrl_attach(device_t dev) 72297667Ssgalabov{ 73297667Ssgalabov 74297667Ssgalabov if (device_get_unit(dev) != 0) { 75297667Ssgalabov device_printf(dev, "Only one pin control allowed\n"); 76297667Ssgalabov return (ENXIO); 77297667Ssgalabov } 78297667Ssgalabov 79298348Ssgalabov if (bootverbose) 80298348Ssgalabov device_printf(dev, "GPIO mode start: 0x%08x\n", 81298348Ssgalabov mtk_sysctl_get(SYSCTL_GPIOMODE)); 82298348Ssgalabov 83298348Ssgalabov fdt_pinctrl_register(dev, NULL); 84297667Ssgalabov fdt_pinctrl_configure_tree(dev); 85297667Ssgalabov 86297667Ssgalabov if (bootverbose) 87298348Ssgalabov device_printf(dev, "GPIO mode end : 0x%08x\n", 88297667Ssgalabov mtk_sysctl_get(SYSCTL_GPIOMODE)); 89297667Ssgalabov 90297667Ssgalabov return (0); 91297667Ssgalabov} 92297667Ssgalabov 93297667Ssgalabovstatic int 94298348Ssgalabovmtk_pinctrl_process_entry(device_t dev, struct mtk_pin_group *table, 95298348Ssgalabov const char *group, char *func) 96298348Ssgalabov{ 97298348Ssgalabov uint32_t val; 98298348Ssgalabov int found = 0, i, j; 99298348Ssgalabov 100298348Ssgalabov for (i = 0; table[i].name != NULL; i++) { 101298348Ssgalabov if (strcmp(table[i].name, group) == 0) { 102298348Ssgalabov found = 1; 103298348Ssgalabov break; 104298348Ssgalabov } 105298348Ssgalabov } 106298348Ssgalabov 107298348Ssgalabov if (!found) 108298348Ssgalabov return (ENOENT); 109298348Ssgalabov 110298348Ssgalabov for (j = 0; j < table[i].funcnum; j++) { 111298348Ssgalabov if (strcmp(table[i].functions[j].name, func) == 0) { 112298348Ssgalabov val = mtk_sysctl_get(table[i].sysc_reg); 113298348Ssgalabov val &= ~(table[i].mask << table[i].offset); 114298348Ssgalabov val |= (table[i].functions[j].value << table[i].offset); 115298348Ssgalabov mtk_sysctl_set(table[i].sysc_reg, val); 116298348Ssgalabov return (0); 117298348Ssgalabov } 118298348Ssgalabov } 119298348Ssgalabov 120298348Ssgalabov return (ENOENT); 121298348Ssgalabov} 122298348Ssgalabov 123298348Ssgalabovstatic int 124298348Ssgalabovmtk_pinctrl_process_node(device_t dev, struct mtk_pin_group *table, 125298348Ssgalabov phandle_t node) 126298348Ssgalabov{ 127298348Ssgalabov const char **group_list = NULL; 128298348Ssgalabov char *pin_function = NULL; 129298348Ssgalabov int ret, num_groups, i; 130298348Ssgalabov 131298348Ssgalabov ret = 0; 132298348Ssgalabov 133298348Ssgalabov num_groups = ofw_bus_string_list_to_array(node, "ralink,group", 134298348Ssgalabov &group_list); 135298348Ssgalabov 136298348Ssgalabov if (num_groups <= 0) 137298348Ssgalabov return (ENOENT); 138298348Ssgalabov 139298348Ssgalabov if (OF_getprop_alloc(node, "ralink,function", sizeof(*pin_function), 140298348Ssgalabov (void **)&pin_function) == -1) { 141298348Ssgalabov ret = ENOENT; 142298348Ssgalabov goto out; 143298348Ssgalabov } 144298348Ssgalabov 145298348Ssgalabov for (i = 0; i < num_groups; i++) { 146298348Ssgalabov if ((ret = mtk_pinctrl_process_entry(dev, table, group_list[i], 147298348Ssgalabov pin_function)) != 0) 148298348Ssgalabov goto out; 149298348Ssgalabov } 150298348Ssgalabov 151298348Ssgalabovout: 152299755Sgonzo OF_prop_free(group_list); 153299755Sgonzo OF_prop_free(pin_function); 154298348Ssgalabov return (ret); 155298348Ssgalabov} 156298348Ssgalabov 157298348Ssgalabovstatic int 158297667Ssgalabovmtk_pinctrl_configure(device_t dev, phandle_t cfgxref) 159297667Ssgalabov{ 160298348Ssgalabov struct mtk_pin_group *pintable; 161298348Ssgalabov phandle_t node, child; 162298348Ssgalabov uint32_t socid; 163298348Ssgalabov int ret; 164297667Ssgalabov 165298348Ssgalabov node = OF_node_from_xref(cfgxref); 166298348Ssgalabov ret = 0; 167298348Ssgalabov 168298348Ssgalabov /* Now, get the system type, so we can get the proper GPIO mode array */ 169298348Ssgalabov socid = mtk_soc_get_socid(); 170298348Ssgalabov 171298348Ssgalabov switch (socid) { 172298348Ssgalabov case MTK_SOC_RT3050: /* fallthrough */ 173298348Ssgalabov case MTK_SOC_RT3052: 174298348Ssgalabov case MTK_SOC_RT3350: 175298348Ssgalabov pintable = rt3050_pintable; 176298348Ssgalabov break; 177298348Ssgalabov case MTK_SOC_RT3352: 178298348Ssgalabov pintable = rt3352_pintable; 179298348Ssgalabov break; 180298348Ssgalabov case MTK_SOC_RT3662: /* fallthrough */ 181298348Ssgalabov case MTK_SOC_RT3883: 182298348Ssgalabov pintable = rt3883_pintable; 183298348Ssgalabov break; 184298348Ssgalabov case MTK_SOC_RT5350: 185298348Ssgalabov pintable = rt5350_pintable; 186298348Ssgalabov break; 187298348Ssgalabov case MTK_SOC_MT7620A: /* fallthrough */ 188298348Ssgalabov case MTK_SOC_MT7620N: 189298348Ssgalabov pintable = mt7620_pintable; 190298348Ssgalabov break; 191298348Ssgalabov case MTK_SOC_MT7628: /* fallthrough */ 192298348Ssgalabov case MTK_SOC_MT7688: 193298348Ssgalabov pintable = mt7628_pintable; 194298348Ssgalabov break; 195298348Ssgalabov case MTK_SOC_MT7621: 196298348Ssgalabov pintable = mt7621_pintable; 197298348Ssgalabov break; 198298348Ssgalabov default: 199298348Ssgalabov ret = ENOENT; 200298348Ssgalabov goto out; 201298348Ssgalabov } 202298348Ssgalabov 203298348Ssgalabov /* 204298348Ssgalabov * OpenWRT dts files have single child within the pinctrl nodes, which 205298348Ssgalabov * contains the 'ralink,group' and 'ralink,function' properties. 206298348Ssgalabov */ 207298348Ssgalabov for (child = OF_child(node); child != 0 && child != -1; 208298348Ssgalabov child = OF_peer(child)) { 209298348Ssgalabov if ((ret = mtk_pinctrl_process_node(dev, pintable, child)) != 0) 210298348Ssgalabov return (ret); 211298348Ssgalabov } 212298348Ssgalabov 213298348Ssgalabovout: 214298348Ssgalabov return (ret); 215297667Ssgalabov} 216297667Ssgalabov 217297667Ssgalabovstatic device_method_t mtk_pinctrl_methods[] = { 218297667Ssgalabov DEVMETHOD(device_probe, mtk_pinctrl_probe), 219297667Ssgalabov DEVMETHOD(device_attach, mtk_pinctrl_attach), 220297667Ssgalabov 221297667Ssgalabov /* fdt_pinctrl interface */ 222297667Ssgalabov DEVMETHOD(fdt_pinctrl_configure, mtk_pinctrl_configure), 223297667Ssgalabov 224297667Ssgalabov DEVMETHOD_END 225297667Ssgalabov}; 226297667Ssgalabov 227297667Ssgalabovstatic driver_t mtk_pinctrl_driver = { 228297667Ssgalabov "pinctrl", 229297667Ssgalabov mtk_pinctrl_methods, 230297667Ssgalabov 0, 231297667Ssgalabov}; 232297667Ssgalabovstatic devclass_t mtk_pinctrl_devclass; 233297667Ssgalabov 234297667SsgalabovEARLY_DRIVER_MODULE(mtk_pinctrl, simplebus, mtk_pinctrl_driver, 235297667Ssgalabov mtk_pinctrl_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_EARLY); 236297667Ssgalabov 237297667SsgalabovMODULE_DEPEND(mtk_pinctrl, mtk_sysctl, 1, 1, 1); 238