18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * MediaTek Pinctrl Paris Driver, which implement the vendor per-pin 48c2ecf20Sopenharmony_ci * bindings for MediaTek SoC. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (C) 2018 MediaTek Inc. 78c2ecf20Sopenharmony_ci * Author: Sean Wang <sean.wang@mediatek.com> 88c2ecf20Sopenharmony_ci * Zhiyong Tao <zhiyong.tao@mediatek.com> 98c2ecf20Sopenharmony_ci * Hongzhou.Yang <hongzhou.yang@mediatek.com> 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/gpio/driver.h> 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <dt-bindings/pinctrl/mt65xx.h> 158c2ecf20Sopenharmony_ci#include "pinctrl-paris.h" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define PINCTRL_PINCTRL_DEV KBUILD_MODNAME 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/* Custom pinconf parameters */ 208c2ecf20Sopenharmony_ci#define MTK_PIN_CONFIG_TDSEL (PIN_CONFIG_END + 1) 218c2ecf20Sopenharmony_ci#define MTK_PIN_CONFIG_RDSEL (PIN_CONFIG_END + 2) 228c2ecf20Sopenharmony_ci#define MTK_PIN_CONFIG_PU_ADV (PIN_CONFIG_END + 3) 238c2ecf20Sopenharmony_ci#define MTK_PIN_CONFIG_PD_ADV (PIN_CONFIG_END + 4) 248c2ecf20Sopenharmony_ci#define MTK_PIN_CONFIG_DRV_ADV (PIN_CONFIG_END + 5) 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic const struct pinconf_generic_params mtk_custom_bindings[] = { 278c2ecf20Sopenharmony_ci {"mediatek,tdsel", MTK_PIN_CONFIG_TDSEL, 0}, 288c2ecf20Sopenharmony_ci {"mediatek,rdsel", MTK_PIN_CONFIG_RDSEL, 0}, 298c2ecf20Sopenharmony_ci {"mediatek,pull-up-adv", MTK_PIN_CONFIG_PU_ADV, 1}, 308c2ecf20Sopenharmony_ci {"mediatek,pull-down-adv", MTK_PIN_CONFIG_PD_ADV, 1}, 318c2ecf20Sopenharmony_ci {"mediatek,drive-strength-adv", MTK_PIN_CONFIG_DRV_ADV, 2}, 328c2ecf20Sopenharmony_ci}; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 358c2ecf20Sopenharmony_cistatic const struct pin_config_item mtk_conf_items[] = { 368c2ecf20Sopenharmony_ci PCONFDUMP(MTK_PIN_CONFIG_TDSEL, "tdsel", NULL, true), 378c2ecf20Sopenharmony_ci PCONFDUMP(MTK_PIN_CONFIG_RDSEL, "rdsel", NULL, true), 388c2ecf20Sopenharmony_ci PCONFDUMP(MTK_PIN_CONFIG_PU_ADV, "pu-adv", NULL, true), 398c2ecf20Sopenharmony_ci PCONFDUMP(MTK_PIN_CONFIG_PD_ADV, "pd-adv", NULL, true), 408c2ecf20Sopenharmony_ci PCONFDUMP(MTK_PIN_CONFIG_DRV_ADV, "drive-strength-adv", NULL, true), 418c2ecf20Sopenharmony_ci}; 428c2ecf20Sopenharmony_ci#endif 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic const char * const mtk_gpio_functions[] = { 458c2ecf20Sopenharmony_ci "func0", "func1", "func2", "func3", 468c2ecf20Sopenharmony_ci "func4", "func5", "func6", "func7", 478c2ecf20Sopenharmony_ci "func8", "func9", "func10", "func11", 488c2ecf20Sopenharmony_ci "func12", "func13", "func14", "func15", 498c2ecf20Sopenharmony_ci}; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic int mtk_pinmux_gpio_request_enable(struct pinctrl_dev *pctldev, 528c2ecf20Sopenharmony_ci struct pinctrl_gpio_range *range, 538c2ecf20Sopenharmony_ci unsigned int pin) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 568c2ecf20Sopenharmony_ci const struct mtk_pin_desc *desc; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci return mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_MODE, 618c2ecf20Sopenharmony_ci hw->soc->gpio_m); 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic int mtk_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev, 658c2ecf20Sopenharmony_ci struct pinctrl_gpio_range *range, 668c2ecf20Sopenharmony_ci unsigned int pin, bool input) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 698c2ecf20Sopenharmony_ci const struct mtk_pin_desc *desc; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci /* hardware would take 0 as input direction */ 748c2ecf20Sopenharmony_ci return mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR, !input); 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic int mtk_pinconf_get(struct pinctrl_dev *pctldev, 788c2ecf20Sopenharmony_ci unsigned int pin, unsigned long *config) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 818c2ecf20Sopenharmony_ci u32 param = pinconf_to_config_param(*config); 828c2ecf20Sopenharmony_ci int pullup, err, reg, ret = 1; 838c2ecf20Sopenharmony_ci const struct mtk_pin_desc *desc; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci if (pin >= hw->soc->npins) { 868c2ecf20Sopenharmony_ci err = -EINVAL; 878c2ecf20Sopenharmony_ci goto out; 888c2ecf20Sopenharmony_ci } 898c2ecf20Sopenharmony_ci desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci switch (param) { 928c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_DISABLE: 938c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_UP: 948c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_DOWN: 958c2ecf20Sopenharmony_ci if (hw->soc->bias_get_combo) { 968c2ecf20Sopenharmony_ci err = hw->soc->bias_get_combo(hw, desc, &pullup, &ret); 978c2ecf20Sopenharmony_ci if (err) 988c2ecf20Sopenharmony_ci goto out; 998c2ecf20Sopenharmony_ci if (ret == MTK_PUPD_SET_R1R0_00) 1008c2ecf20Sopenharmony_ci ret = MTK_DISABLE; 1018c2ecf20Sopenharmony_ci if (param == PIN_CONFIG_BIAS_DISABLE) { 1028c2ecf20Sopenharmony_ci if (ret != MTK_DISABLE) 1038c2ecf20Sopenharmony_ci err = -EINVAL; 1048c2ecf20Sopenharmony_ci } else if (param == PIN_CONFIG_BIAS_PULL_UP) { 1058c2ecf20Sopenharmony_ci if (!pullup || ret == MTK_DISABLE) 1068c2ecf20Sopenharmony_ci err = -EINVAL; 1078c2ecf20Sopenharmony_ci } else if (param == PIN_CONFIG_BIAS_PULL_DOWN) { 1088c2ecf20Sopenharmony_ci if (pullup || ret == MTK_DISABLE) 1098c2ecf20Sopenharmony_ci err = -EINVAL; 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci } else { 1128c2ecf20Sopenharmony_ci err = -ENOTSUPP; 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci break; 1158c2ecf20Sopenharmony_ci case PIN_CONFIG_SLEW_RATE: 1168c2ecf20Sopenharmony_ci err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_SR, &ret); 1178c2ecf20Sopenharmony_ci break; 1188c2ecf20Sopenharmony_ci case PIN_CONFIG_INPUT_ENABLE: 1198c2ecf20Sopenharmony_ci case PIN_CONFIG_OUTPUT_ENABLE: 1208c2ecf20Sopenharmony_ci err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DIR, &ret); 1218c2ecf20Sopenharmony_ci if (err) 1228c2ecf20Sopenharmony_ci goto out; 1238c2ecf20Sopenharmony_ci /* CONFIG Current direction return value 1248c2ecf20Sopenharmony_ci * ------------- ----------------- ---------------------- 1258c2ecf20Sopenharmony_ci * OUTPUT_ENABLE output 1 (= HW value) 1268c2ecf20Sopenharmony_ci * input 0 (= HW value) 1278c2ecf20Sopenharmony_ci * INPUT_ENABLE output 0 (= reverse HW value) 1288c2ecf20Sopenharmony_ci * input 1 (= reverse HW value) 1298c2ecf20Sopenharmony_ci */ 1308c2ecf20Sopenharmony_ci if (param == PIN_CONFIG_INPUT_ENABLE) 1318c2ecf20Sopenharmony_ci ret = !ret; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci break; 1348c2ecf20Sopenharmony_ci case PIN_CONFIG_INPUT_SCHMITT_ENABLE: 1358c2ecf20Sopenharmony_ci err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DIR, &ret); 1368c2ecf20Sopenharmony_ci if (err) 1378c2ecf20Sopenharmony_ci goto out; 1388c2ecf20Sopenharmony_ci /* return error when in output mode 1398c2ecf20Sopenharmony_ci * because schmitt trigger only work in input mode 1408c2ecf20Sopenharmony_ci */ 1418c2ecf20Sopenharmony_ci if (ret) { 1428c2ecf20Sopenharmony_ci err = -EINVAL; 1438c2ecf20Sopenharmony_ci goto out; 1448c2ecf20Sopenharmony_ci } 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_SMT, &ret); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci break; 1498c2ecf20Sopenharmony_ci case PIN_CONFIG_DRIVE_STRENGTH: 1508c2ecf20Sopenharmony_ci if (hw->soc->drive_get) 1518c2ecf20Sopenharmony_ci err = hw->soc->drive_get(hw, desc, &ret); 1528c2ecf20Sopenharmony_ci else 1538c2ecf20Sopenharmony_ci err = -ENOTSUPP; 1548c2ecf20Sopenharmony_ci break; 1558c2ecf20Sopenharmony_ci case MTK_PIN_CONFIG_TDSEL: 1568c2ecf20Sopenharmony_ci case MTK_PIN_CONFIG_RDSEL: 1578c2ecf20Sopenharmony_ci reg = (param == MTK_PIN_CONFIG_TDSEL) ? 1588c2ecf20Sopenharmony_ci PINCTRL_PIN_REG_TDSEL : PINCTRL_PIN_REG_RDSEL; 1598c2ecf20Sopenharmony_ci err = mtk_hw_get_value(hw, desc, reg, &ret); 1608c2ecf20Sopenharmony_ci break; 1618c2ecf20Sopenharmony_ci case MTK_PIN_CONFIG_PU_ADV: 1628c2ecf20Sopenharmony_ci case MTK_PIN_CONFIG_PD_ADV: 1638c2ecf20Sopenharmony_ci if (hw->soc->adv_pull_get) { 1648c2ecf20Sopenharmony_ci pullup = param == MTK_PIN_CONFIG_PU_ADV; 1658c2ecf20Sopenharmony_ci err = hw->soc->adv_pull_get(hw, desc, pullup, &ret); 1668c2ecf20Sopenharmony_ci } else 1678c2ecf20Sopenharmony_ci err = -ENOTSUPP; 1688c2ecf20Sopenharmony_ci break; 1698c2ecf20Sopenharmony_ci case MTK_PIN_CONFIG_DRV_ADV: 1708c2ecf20Sopenharmony_ci if (hw->soc->adv_drive_get) 1718c2ecf20Sopenharmony_ci err = hw->soc->adv_drive_get(hw, desc, &ret); 1728c2ecf20Sopenharmony_ci else 1738c2ecf20Sopenharmony_ci err = -ENOTSUPP; 1748c2ecf20Sopenharmony_ci break; 1758c2ecf20Sopenharmony_ci default: 1768c2ecf20Sopenharmony_ci err = -ENOTSUPP; 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ciout: 1808c2ecf20Sopenharmony_ci if (!err) 1818c2ecf20Sopenharmony_ci *config = pinconf_to_config_packed(param, ret); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci return err; 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cistatic int mtk_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, 1878c2ecf20Sopenharmony_ci enum pin_config_param param, u32 arg) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 1908c2ecf20Sopenharmony_ci const struct mtk_pin_desc *desc; 1918c2ecf20Sopenharmony_ci int err = 0; 1928c2ecf20Sopenharmony_ci u32 reg; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci if (pin >= hw->soc->npins) { 1958c2ecf20Sopenharmony_ci err = -EINVAL; 1968c2ecf20Sopenharmony_ci goto err; 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci switch ((u32)param) { 2018c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_DISABLE: 2028c2ecf20Sopenharmony_ci if (hw->soc->bias_set_combo) 2038c2ecf20Sopenharmony_ci err = hw->soc->bias_set_combo(hw, desc, 0, MTK_DISABLE); 2048c2ecf20Sopenharmony_ci else 2058c2ecf20Sopenharmony_ci err = -ENOTSUPP; 2068c2ecf20Sopenharmony_ci break; 2078c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_UP: 2088c2ecf20Sopenharmony_ci if (hw->soc->bias_set_combo) 2098c2ecf20Sopenharmony_ci err = hw->soc->bias_set_combo(hw, desc, 1, arg); 2108c2ecf20Sopenharmony_ci else 2118c2ecf20Sopenharmony_ci err = -ENOTSUPP; 2128c2ecf20Sopenharmony_ci break; 2138c2ecf20Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_DOWN: 2148c2ecf20Sopenharmony_ci if (hw->soc->bias_set_combo) 2158c2ecf20Sopenharmony_ci err = hw->soc->bias_set_combo(hw, desc, 0, arg); 2168c2ecf20Sopenharmony_ci else 2178c2ecf20Sopenharmony_ci err = -ENOTSUPP; 2188c2ecf20Sopenharmony_ci break; 2198c2ecf20Sopenharmony_ci case PIN_CONFIG_OUTPUT_ENABLE: 2208c2ecf20Sopenharmony_ci err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_SMT, 2218c2ecf20Sopenharmony_ci MTK_DISABLE); 2228c2ecf20Sopenharmony_ci /* Keep set direction to consider the case that a GPIO pin 2238c2ecf20Sopenharmony_ci * does not have SMT control 2248c2ecf20Sopenharmony_ci */ 2258c2ecf20Sopenharmony_ci if (err != -ENOTSUPP) 2268c2ecf20Sopenharmony_ci goto err; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR, 2298c2ecf20Sopenharmony_ci MTK_OUTPUT); 2308c2ecf20Sopenharmony_ci break; 2318c2ecf20Sopenharmony_ci case PIN_CONFIG_INPUT_ENABLE: 2328c2ecf20Sopenharmony_ci /* regard all non-zero value as enable */ 2338c2ecf20Sopenharmony_ci err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_IES, !!arg); 2348c2ecf20Sopenharmony_ci if (err) 2358c2ecf20Sopenharmony_ci goto err; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR, 2388c2ecf20Sopenharmony_ci MTK_INPUT); 2398c2ecf20Sopenharmony_ci break; 2408c2ecf20Sopenharmony_ci case PIN_CONFIG_SLEW_RATE: 2418c2ecf20Sopenharmony_ci /* regard all non-zero value as enable */ 2428c2ecf20Sopenharmony_ci err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_SR, !!arg); 2438c2ecf20Sopenharmony_ci break; 2448c2ecf20Sopenharmony_ci case PIN_CONFIG_OUTPUT: 2458c2ecf20Sopenharmony_ci err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR, 2468c2ecf20Sopenharmony_ci MTK_OUTPUT); 2478c2ecf20Sopenharmony_ci if (err) 2488c2ecf20Sopenharmony_ci goto err; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DO, 2518c2ecf20Sopenharmony_ci arg); 2528c2ecf20Sopenharmony_ci break; 2538c2ecf20Sopenharmony_ci case PIN_CONFIG_INPUT_SCHMITT: 2548c2ecf20Sopenharmony_ci case PIN_CONFIG_INPUT_SCHMITT_ENABLE: 2558c2ecf20Sopenharmony_ci /* arg = 1: Input mode & SMT enable ; 2568c2ecf20Sopenharmony_ci * arg = 0: Output mode & SMT disable 2578c2ecf20Sopenharmony_ci */ 2588c2ecf20Sopenharmony_ci err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR, !arg); 2598c2ecf20Sopenharmony_ci if (err) 2608c2ecf20Sopenharmony_ci goto err; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_SMT, !!arg); 2638c2ecf20Sopenharmony_ci break; 2648c2ecf20Sopenharmony_ci case PIN_CONFIG_DRIVE_STRENGTH: 2658c2ecf20Sopenharmony_ci if (hw->soc->drive_set) 2668c2ecf20Sopenharmony_ci err = hw->soc->drive_set(hw, desc, arg); 2678c2ecf20Sopenharmony_ci else 2688c2ecf20Sopenharmony_ci err = -ENOTSUPP; 2698c2ecf20Sopenharmony_ci break; 2708c2ecf20Sopenharmony_ci case MTK_PIN_CONFIG_TDSEL: 2718c2ecf20Sopenharmony_ci case MTK_PIN_CONFIG_RDSEL: 2728c2ecf20Sopenharmony_ci reg = (param == MTK_PIN_CONFIG_TDSEL) ? 2738c2ecf20Sopenharmony_ci PINCTRL_PIN_REG_TDSEL : PINCTRL_PIN_REG_RDSEL; 2748c2ecf20Sopenharmony_ci err = mtk_hw_set_value(hw, desc, reg, arg); 2758c2ecf20Sopenharmony_ci break; 2768c2ecf20Sopenharmony_ci case MTK_PIN_CONFIG_PU_ADV: 2778c2ecf20Sopenharmony_ci case MTK_PIN_CONFIG_PD_ADV: 2788c2ecf20Sopenharmony_ci if (hw->soc->adv_pull_set) { 2798c2ecf20Sopenharmony_ci bool pullup; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci pullup = param == MTK_PIN_CONFIG_PU_ADV; 2828c2ecf20Sopenharmony_ci err = hw->soc->adv_pull_set(hw, desc, pullup, 2838c2ecf20Sopenharmony_ci arg); 2848c2ecf20Sopenharmony_ci } else 2858c2ecf20Sopenharmony_ci err = -ENOTSUPP; 2868c2ecf20Sopenharmony_ci break; 2878c2ecf20Sopenharmony_ci case MTK_PIN_CONFIG_DRV_ADV: 2888c2ecf20Sopenharmony_ci if (hw->soc->adv_drive_set) 2898c2ecf20Sopenharmony_ci err = hw->soc->adv_drive_set(hw, desc, arg); 2908c2ecf20Sopenharmony_ci else 2918c2ecf20Sopenharmony_ci err = -ENOTSUPP; 2928c2ecf20Sopenharmony_ci break; 2938c2ecf20Sopenharmony_ci default: 2948c2ecf20Sopenharmony_ci err = -ENOTSUPP; 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_cierr: 2988c2ecf20Sopenharmony_ci return err; 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_cistatic struct mtk_pinctrl_group * 3028c2ecf20Sopenharmony_cimtk_pctrl_find_group_by_pin(struct mtk_pinctrl *hw, u32 pin) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci int i; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci for (i = 0; i < hw->soc->ngrps; i++) { 3078c2ecf20Sopenharmony_ci struct mtk_pinctrl_group *grp = hw->groups + i; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci if (grp->pin == pin) 3108c2ecf20Sopenharmony_ci return grp; 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci return NULL; 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_cistatic const struct mtk_func_desc * 3178c2ecf20Sopenharmony_cimtk_pctrl_find_function_by_pin(struct mtk_pinctrl *hw, u32 pin_num, u32 fnum) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci const struct mtk_pin_desc *pin = hw->soc->pins + pin_num; 3208c2ecf20Sopenharmony_ci const struct mtk_func_desc *func = pin->funcs; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci while (func && func->name) { 3238c2ecf20Sopenharmony_ci if (func->muxval == fnum) 3248c2ecf20Sopenharmony_ci return func; 3258c2ecf20Sopenharmony_ci func++; 3268c2ecf20Sopenharmony_ci } 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci return NULL; 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_cistatic bool mtk_pctrl_is_function_valid(struct mtk_pinctrl *hw, u32 pin_num, 3328c2ecf20Sopenharmony_ci u32 fnum) 3338c2ecf20Sopenharmony_ci{ 3348c2ecf20Sopenharmony_ci int i; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci for (i = 0; i < hw->soc->npins; i++) { 3378c2ecf20Sopenharmony_ci const struct mtk_pin_desc *pin = hw->soc->pins + i; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci if (pin->number == pin_num) { 3408c2ecf20Sopenharmony_ci const struct mtk_func_desc *func = pin->funcs; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci while (func && func->name) { 3438c2ecf20Sopenharmony_ci if (func->muxval == fnum) 3448c2ecf20Sopenharmony_ci return true; 3458c2ecf20Sopenharmony_ci func++; 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci break; 3498c2ecf20Sopenharmony_ci } 3508c2ecf20Sopenharmony_ci } 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci return false; 3538c2ecf20Sopenharmony_ci} 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_cistatic int mtk_pctrl_dt_node_to_map_func(struct mtk_pinctrl *pctl, 3568c2ecf20Sopenharmony_ci u32 pin, u32 fnum, 3578c2ecf20Sopenharmony_ci struct mtk_pinctrl_group *grp, 3588c2ecf20Sopenharmony_ci struct pinctrl_map **map, 3598c2ecf20Sopenharmony_ci unsigned *reserved_maps, 3608c2ecf20Sopenharmony_ci unsigned *num_maps) 3618c2ecf20Sopenharmony_ci{ 3628c2ecf20Sopenharmony_ci bool ret; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci if (*num_maps == *reserved_maps) 3658c2ecf20Sopenharmony_ci return -ENOSPC; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci (*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP; 3688c2ecf20Sopenharmony_ci (*map)[*num_maps].data.mux.group = grp->name; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci ret = mtk_pctrl_is_function_valid(pctl, pin, fnum); 3718c2ecf20Sopenharmony_ci if (!ret) { 3728c2ecf20Sopenharmony_ci dev_err(pctl->dev, "invalid function %d on pin %d .\n", 3738c2ecf20Sopenharmony_ci fnum, pin); 3748c2ecf20Sopenharmony_ci return -EINVAL; 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci (*map)[*num_maps].data.mux.function = mtk_gpio_functions[fnum]; 3788c2ecf20Sopenharmony_ci (*num_maps)++; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci return 0; 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_cistatic int mtk_pctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev, 3848c2ecf20Sopenharmony_ci struct device_node *node, 3858c2ecf20Sopenharmony_ci struct pinctrl_map **map, 3868c2ecf20Sopenharmony_ci unsigned *reserved_maps, 3878c2ecf20Sopenharmony_ci unsigned *num_maps) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 3908c2ecf20Sopenharmony_ci int num_pins, num_funcs, maps_per_pin, i, err; 3918c2ecf20Sopenharmony_ci struct mtk_pinctrl_group *grp; 3928c2ecf20Sopenharmony_ci unsigned int num_configs; 3938c2ecf20Sopenharmony_ci bool has_config = false; 3948c2ecf20Sopenharmony_ci unsigned long *configs; 3958c2ecf20Sopenharmony_ci u32 pinfunc, pin, func; 3968c2ecf20Sopenharmony_ci struct property *pins; 3978c2ecf20Sopenharmony_ci unsigned reserve = 0; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci pins = of_find_property(node, "pinmux", NULL); 4008c2ecf20Sopenharmony_ci if (!pins) { 4018c2ecf20Sopenharmony_ci dev_err(hw->dev, "missing pins property in node %pOFn .\n", 4028c2ecf20Sopenharmony_ci node); 4038c2ecf20Sopenharmony_ci return -EINVAL; 4048c2ecf20Sopenharmony_ci } 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci err = pinconf_generic_parse_dt_config(node, pctldev, &configs, 4078c2ecf20Sopenharmony_ci &num_configs); 4088c2ecf20Sopenharmony_ci if (err) 4098c2ecf20Sopenharmony_ci return err; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci if (num_configs) 4128c2ecf20Sopenharmony_ci has_config = true; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci num_pins = pins->length / sizeof(u32); 4158c2ecf20Sopenharmony_ci num_funcs = num_pins; 4168c2ecf20Sopenharmony_ci maps_per_pin = 0; 4178c2ecf20Sopenharmony_ci if (num_funcs) 4188c2ecf20Sopenharmony_ci maps_per_pin++; 4198c2ecf20Sopenharmony_ci if (has_config && num_pins >= 1) 4208c2ecf20Sopenharmony_ci maps_per_pin++; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci if (!num_pins || !maps_per_pin) { 4238c2ecf20Sopenharmony_ci err = -EINVAL; 4248c2ecf20Sopenharmony_ci goto exit; 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci reserve = num_pins * maps_per_pin; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci err = pinctrl_utils_reserve_map(pctldev, map, reserved_maps, num_maps, 4308c2ecf20Sopenharmony_ci reserve); 4318c2ecf20Sopenharmony_ci if (err < 0) 4328c2ecf20Sopenharmony_ci goto exit; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci for (i = 0; i < num_pins; i++) { 4358c2ecf20Sopenharmony_ci err = of_property_read_u32_index(node, "pinmux", i, &pinfunc); 4368c2ecf20Sopenharmony_ci if (err) 4378c2ecf20Sopenharmony_ci goto exit; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci pin = MTK_GET_PIN_NO(pinfunc); 4408c2ecf20Sopenharmony_ci func = MTK_GET_PIN_FUNC(pinfunc); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci if (pin >= hw->soc->npins || 4438c2ecf20Sopenharmony_ci func >= ARRAY_SIZE(mtk_gpio_functions)) { 4448c2ecf20Sopenharmony_ci dev_err(hw->dev, "invalid pins value.\n"); 4458c2ecf20Sopenharmony_ci err = -EINVAL; 4468c2ecf20Sopenharmony_ci goto exit; 4478c2ecf20Sopenharmony_ci } 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci grp = mtk_pctrl_find_group_by_pin(hw, pin); 4508c2ecf20Sopenharmony_ci if (!grp) { 4518c2ecf20Sopenharmony_ci dev_err(hw->dev, "unable to match pin %d to group\n", 4528c2ecf20Sopenharmony_ci pin); 4538c2ecf20Sopenharmony_ci err = -EINVAL; 4548c2ecf20Sopenharmony_ci goto exit; 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci err = mtk_pctrl_dt_node_to_map_func(hw, pin, func, grp, map, 4588c2ecf20Sopenharmony_ci reserved_maps, num_maps); 4598c2ecf20Sopenharmony_ci if (err < 0) 4608c2ecf20Sopenharmony_ci goto exit; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci if (has_config) { 4638c2ecf20Sopenharmony_ci err = pinctrl_utils_add_map_configs(pctldev, map, 4648c2ecf20Sopenharmony_ci reserved_maps, 4658c2ecf20Sopenharmony_ci num_maps, 4668c2ecf20Sopenharmony_ci grp->name, 4678c2ecf20Sopenharmony_ci configs, 4688c2ecf20Sopenharmony_ci num_configs, 4698c2ecf20Sopenharmony_ci PIN_MAP_TYPE_CONFIGS_GROUP); 4708c2ecf20Sopenharmony_ci if (err < 0) 4718c2ecf20Sopenharmony_ci goto exit; 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci } 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci err = 0; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ciexit: 4788c2ecf20Sopenharmony_ci kfree(configs); 4798c2ecf20Sopenharmony_ci return err; 4808c2ecf20Sopenharmony_ci} 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_cistatic int mtk_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev, 4838c2ecf20Sopenharmony_ci struct device_node *np_config, 4848c2ecf20Sopenharmony_ci struct pinctrl_map **map, 4858c2ecf20Sopenharmony_ci unsigned *num_maps) 4868c2ecf20Sopenharmony_ci{ 4878c2ecf20Sopenharmony_ci struct device_node *np; 4888c2ecf20Sopenharmony_ci unsigned reserved_maps; 4898c2ecf20Sopenharmony_ci int ret; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci *map = NULL; 4928c2ecf20Sopenharmony_ci *num_maps = 0; 4938c2ecf20Sopenharmony_ci reserved_maps = 0; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci for_each_child_of_node(np_config, np) { 4968c2ecf20Sopenharmony_ci ret = mtk_pctrl_dt_subnode_to_map(pctldev, np, map, 4978c2ecf20Sopenharmony_ci &reserved_maps, 4988c2ecf20Sopenharmony_ci num_maps); 4998c2ecf20Sopenharmony_ci if (ret < 0) { 5008c2ecf20Sopenharmony_ci pinctrl_utils_free_map(pctldev, *map, *num_maps); 5018c2ecf20Sopenharmony_ci of_node_put(np); 5028c2ecf20Sopenharmony_ci return ret; 5038c2ecf20Sopenharmony_ci } 5048c2ecf20Sopenharmony_ci } 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci return 0; 5078c2ecf20Sopenharmony_ci} 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_cistatic int mtk_pctrl_get_groups_count(struct pinctrl_dev *pctldev) 5108c2ecf20Sopenharmony_ci{ 5118c2ecf20Sopenharmony_ci struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci return hw->soc->ngrps; 5148c2ecf20Sopenharmony_ci} 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_cistatic const char *mtk_pctrl_get_group_name(struct pinctrl_dev *pctldev, 5178c2ecf20Sopenharmony_ci unsigned group) 5188c2ecf20Sopenharmony_ci{ 5198c2ecf20Sopenharmony_ci struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci return hw->groups[group].name; 5228c2ecf20Sopenharmony_ci} 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_cistatic int mtk_pctrl_get_group_pins(struct pinctrl_dev *pctldev, 5258c2ecf20Sopenharmony_ci unsigned group, const unsigned **pins, 5268c2ecf20Sopenharmony_ci unsigned *num_pins) 5278c2ecf20Sopenharmony_ci{ 5288c2ecf20Sopenharmony_ci struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci *pins = (unsigned *)&hw->groups[group].pin; 5318c2ecf20Sopenharmony_ci *num_pins = 1; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci return 0; 5348c2ecf20Sopenharmony_ci} 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_cistatic int mtk_hw_get_value_wrap(struct mtk_pinctrl *hw, unsigned int gpio, int field) 5378c2ecf20Sopenharmony_ci{ 5388c2ecf20Sopenharmony_ci const struct mtk_pin_desc *desc; 5398c2ecf20Sopenharmony_ci int value, err; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci if (gpio >= hw->soc->npins) 5428c2ecf20Sopenharmony_ci return -EINVAL; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio]; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci err = mtk_hw_get_value(hw, desc, field, &value); 5478c2ecf20Sopenharmony_ci if (err) 5488c2ecf20Sopenharmony_ci return err; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci return value; 5518c2ecf20Sopenharmony_ci} 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci#define mtk_pctrl_get_pinmux(hw, gpio) \ 5548c2ecf20Sopenharmony_ci mtk_hw_get_value_wrap(hw, gpio, PINCTRL_PIN_REG_MODE) 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci#define mtk_pctrl_get_direction(hw, gpio) \ 5578c2ecf20Sopenharmony_ci mtk_hw_get_value_wrap(hw, gpio, PINCTRL_PIN_REG_DIR) 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci#define mtk_pctrl_get_out(hw, gpio) \ 5608c2ecf20Sopenharmony_ci mtk_hw_get_value_wrap(hw, gpio, PINCTRL_PIN_REG_DO) 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci#define mtk_pctrl_get_in(hw, gpio) \ 5638c2ecf20Sopenharmony_ci mtk_hw_get_value_wrap(hw, gpio, PINCTRL_PIN_REG_DI) 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci#define mtk_pctrl_get_smt(hw, gpio) \ 5668c2ecf20Sopenharmony_ci mtk_hw_get_value_wrap(hw, gpio, PINCTRL_PIN_REG_SMT) 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci#define mtk_pctrl_get_ies(hw, gpio) \ 5698c2ecf20Sopenharmony_ci mtk_hw_get_value_wrap(hw, gpio, PINCTRL_PIN_REG_IES) 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci#define mtk_pctrl_get_driving(hw, gpio) \ 5728c2ecf20Sopenharmony_ci mtk_hw_get_value_wrap(hw, gpio, PINCTRL_PIN_REG_DRV) 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_cissize_t mtk_pctrl_show_one_pin(struct mtk_pinctrl *hw, 5758c2ecf20Sopenharmony_ci unsigned int gpio, char *buf, unsigned int bufLen) 5768c2ecf20Sopenharmony_ci{ 5778c2ecf20Sopenharmony_ci int pinmux, pullup = 0, pullen = 0, len = 0, r1 = -1, r0 = -1; 5788c2ecf20Sopenharmony_ci const struct mtk_pin_desc *desc; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci if (gpio >= hw->soc->npins) 5818c2ecf20Sopenharmony_ci return -EINVAL; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci if (mtk_is_virt_gpio(hw, gpio)) 5848c2ecf20Sopenharmony_ci return -EINVAL; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio]; 5878c2ecf20Sopenharmony_ci pinmux = mtk_pctrl_get_pinmux(hw, gpio); 5888c2ecf20Sopenharmony_ci if (pinmux >= hw->soc->nfuncs) 5898c2ecf20Sopenharmony_ci pinmux -= hw->soc->nfuncs; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci mtk_pinconf_bias_get_combo(hw, desc, &pullup, &pullen); 5928c2ecf20Sopenharmony_ci if (pullen == MTK_PUPD_SET_R1R0_00) { 5938c2ecf20Sopenharmony_ci pullen = 0; 5948c2ecf20Sopenharmony_ci r1 = 0; 5958c2ecf20Sopenharmony_ci r0 = 0; 5968c2ecf20Sopenharmony_ci } else if (pullen == MTK_PUPD_SET_R1R0_01) { 5978c2ecf20Sopenharmony_ci pullen = 1; 5988c2ecf20Sopenharmony_ci r1 = 0; 5998c2ecf20Sopenharmony_ci r0 = 1; 6008c2ecf20Sopenharmony_ci } else if (pullen == MTK_PUPD_SET_R1R0_10) { 6018c2ecf20Sopenharmony_ci pullen = 1; 6028c2ecf20Sopenharmony_ci r1 = 1; 6038c2ecf20Sopenharmony_ci r0 = 0; 6048c2ecf20Sopenharmony_ci } else if (pullen == MTK_PUPD_SET_R1R0_11) { 6058c2ecf20Sopenharmony_ci pullen = 1; 6068c2ecf20Sopenharmony_ci r1 = 1; 6078c2ecf20Sopenharmony_ci r0 = 1; 6088c2ecf20Sopenharmony_ci } else if (pullen != MTK_DISABLE && pullen != MTK_ENABLE) { 6098c2ecf20Sopenharmony_ci pullen = 0; 6108c2ecf20Sopenharmony_ci } 6118c2ecf20Sopenharmony_ci len += scnprintf(buf + len, bufLen - len, 6128c2ecf20Sopenharmony_ci "%03d: %1d%1d%1d%1d%02d%1d%1d%1d%1d", 6138c2ecf20Sopenharmony_ci gpio, 6148c2ecf20Sopenharmony_ci pinmux, 6158c2ecf20Sopenharmony_ci mtk_pctrl_get_direction(hw, gpio), 6168c2ecf20Sopenharmony_ci mtk_pctrl_get_out(hw, gpio), 6178c2ecf20Sopenharmony_ci mtk_pctrl_get_in(hw, gpio), 6188c2ecf20Sopenharmony_ci mtk_pctrl_get_driving(hw, gpio), 6198c2ecf20Sopenharmony_ci mtk_pctrl_get_smt(hw, gpio), 6208c2ecf20Sopenharmony_ci mtk_pctrl_get_ies(hw, gpio), 6218c2ecf20Sopenharmony_ci pullen, 6228c2ecf20Sopenharmony_ci pullup); 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci if (r1 != -1) { 6258c2ecf20Sopenharmony_ci len += scnprintf(buf + len, bufLen - len, " (%1d %1d)\n", 6268c2ecf20Sopenharmony_ci r1, r0); 6278c2ecf20Sopenharmony_ci } else { 6288c2ecf20Sopenharmony_ci len += scnprintf(buf + len, bufLen - len, "\n"); 6298c2ecf20Sopenharmony_ci } 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci return len; 6328c2ecf20Sopenharmony_ci} 6338c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_pctrl_show_one_pin); 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci#define PIN_DBG_BUF_SZ 96 6368c2ecf20Sopenharmony_cistatic void mtk_pctrl_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, 6378c2ecf20Sopenharmony_ci unsigned int gpio) 6388c2ecf20Sopenharmony_ci{ 6398c2ecf20Sopenharmony_ci struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 6408c2ecf20Sopenharmony_ci char buf[PIN_DBG_BUF_SZ] = { 0 }; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci (void)mtk_pctrl_show_one_pin(hw, gpio, buf, PIN_DBG_BUF_SZ); 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci seq_printf(s, "%s", buf); 6458c2ecf20Sopenharmony_ci} 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_cistatic const struct pinctrl_ops mtk_pctlops = { 6488c2ecf20Sopenharmony_ci .dt_node_to_map = mtk_pctrl_dt_node_to_map, 6498c2ecf20Sopenharmony_ci .dt_free_map = pinctrl_utils_free_map, 6508c2ecf20Sopenharmony_ci .get_groups_count = mtk_pctrl_get_groups_count, 6518c2ecf20Sopenharmony_ci .get_group_name = mtk_pctrl_get_group_name, 6528c2ecf20Sopenharmony_ci .get_group_pins = mtk_pctrl_get_group_pins, 6538c2ecf20Sopenharmony_ci .pin_dbg_show = mtk_pctrl_dbg_show, 6548c2ecf20Sopenharmony_ci}; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_cistatic int mtk_pmx_get_funcs_cnt(struct pinctrl_dev *pctldev) 6578c2ecf20Sopenharmony_ci{ 6588c2ecf20Sopenharmony_ci return ARRAY_SIZE(mtk_gpio_functions); 6598c2ecf20Sopenharmony_ci} 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_cistatic const char *mtk_pmx_get_func_name(struct pinctrl_dev *pctldev, 6628c2ecf20Sopenharmony_ci unsigned selector) 6638c2ecf20Sopenharmony_ci{ 6648c2ecf20Sopenharmony_ci return mtk_gpio_functions[selector]; 6658c2ecf20Sopenharmony_ci} 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_cistatic int mtk_pmx_get_func_groups(struct pinctrl_dev *pctldev, 6688c2ecf20Sopenharmony_ci unsigned function, 6698c2ecf20Sopenharmony_ci const char * const **groups, 6708c2ecf20Sopenharmony_ci unsigned * const num_groups) 6718c2ecf20Sopenharmony_ci{ 6728c2ecf20Sopenharmony_ci struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci *groups = hw->grp_names; 6758c2ecf20Sopenharmony_ci *num_groups = hw->soc->ngrps; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci return 0; 6788c2ecf20Sopenharmony_ci} 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_cistatic int mtk_pmx_set_mux(struct pinctrl_dev *pctldev, 6818c2ecf20Sopenharmony_ci unsigned function, 6828c2ecf20Sopenharmony_ci unsigned group) 6838c2ecf20Sopenharmony_ci{ 6848c2ecf20Sopenharmony_ci struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 6858c2ecf20Sopenharmony_ci struct mtk_pinctrl_group *grp = hw->groups + group; 6868c2ecf20Sopenharmony_ci const struct mtk_func_desc *desc_func; 6878c2ecf20Sopenharmony_ci const struct mtk_pin_desc *desc; 6888c2ecf20Sopenharmony_ci bool ret; 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci ret = mtk_pctrl_is_function_valid(hw, grp->pin, function); 6918c2ecf20Sopenharmony_ci if (!ret) { 6928c2ecf20Sopenharmony_ci dev_err(hw->dev, "invalid function %d on group %d .\n", 6938c2ecf20Sopenharmony_ci function, group); 6948c2ecf20Sopenharmony_ci return -EINVAL; 6958c2ecf20Sopenharmony_ci } 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci desc_func = mtk_pctrl_find_function_by_pin(hw, grp->pin, function); 6988c2ecf20Sopenharmony_ci if (!desc_func) 6998c2ecf20Sopenharmony_ci return -EINVAL; 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci desc = (const struct mtk_pin_desc *)&hw->soc->pins[grp->pin]; 7028c2ecf20Sopenharmony_ci mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_MODE, desc_func->muxval); 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci return 0; 7058c2ecf20Sopenharmony_ci} 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_cistatic const struct pinmux_ops mtk_pmxops = { 7088c2ecf20Sopenharmony_ci .get_functions_count = mtk_pmx_get_funcs_cnt, 7098c2ecf20Sopenharmony_ci .get_function_name = mtk_pmx_get_func_name, 7108c2ecf20Sopenharmony_ci .get_function_groups = mtk_pmx_get_func_groups, 7118c2ecf20Sopenharmony_ci .set_mux = mtk_pmx_set_mux, 7128c2ecf20Sopenharmony_ci .gpio_set_direction = mtk_pinmux_gpio_set_direction, 7138c2ecf20Sopenharmony_ci .gpio_request_enable = mtk_pinmux_gpio_request_enable, 7148c2ecf20Sopenharmony_ci}; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_cistatic int mtk_pconf_group_get(struct pinctrl_dev *pctldev, unsigned group, 7178c2ecf20Sopenharmony_ci unsigned long *config) 7188c2ecf20Sopenharmony_ci{ 7198c2ecf20Sopenharmony_ci struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 7208c2ecf20Sopenharmony_ci struct mtk_pinctrl_group *grp = &hw->groups[group]; 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci /* One pin per group only */ 7238c2ecf20Sopenharmony_ci return mtk_pinconf_get(pctldev, grp->pin, config); 7248c2ecf20Sopenharmony_ci} 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_cistatic int mtk_pconf_group_set(struct pinctrl_dev *pctldev, unsigned group, 7278c2ecf20Sopenharmony_ci unsigned long *configs, unsigned num_configs) 7288c2ecf20Sopenharmony_ci{ 7298c2ecf20Sopenharmony_ci struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 7308c2ecf20Sopenharmony_ci struct mtk_pinctrl_group *grp = &hw->groups[group]; 7318c2ecf20Sopenharmony_ci int i, ret; 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci for (i = 0; i < num_configs; i++) { 7348c2ecf20Sopenharmony_ci ret = mtk_pinconf_set(pctldev, grp->pin, 7358c2ecf20Sopenharmony_ci pinconf_to_config_param(configs[i]), 7368c2ecf20Sopenharmony_ci pinconf_to_config_argument(configs[i])); 7378c2ecf20Sopenharmony_ci if (ret < 0) 7388c2ecf20Sopenharmony_ci return ret; 7398c2ecf20Sopenharmony_ci } 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci return 0; 7428c2ecf20Sopenharmony_ci} 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_cistatic const struct pinconf_ops mtk_confops = { 7458c2ecf20Sopenharmony_ci .pin_config_get = mtk_pinconf_get, 7468c2ecf20Sopenharmony_ci .pin_config_group_get = mtk_pconf_group_get, 7478c2ecf20Sopenharmony_ci .pin_config_group_set = mtk_pconf_group_set, 7488c2ecf20Sopenharmony_ci .is_generic = true, 7498c2ecf20Sopenharmony_ci}; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_cistatic struct pinctrl_desc mtk_desc = { 7528c2ecf20Sopenharmony_ci .name = PINCTRL_PINCTRL_DEV, 7538c2ecf20Sopenharmony_ci .pctlops = &mtk_pctlops, 7548c2ecf20Sopenharmony_ci .pmxops = &mtk_pmxops, 7558c2ecf20Sopenharmony_ci .confops = &mtk_confops, 7568c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 7578c2ecf20Sopenharmony_ci}; 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_cistatic int mtk_gpio_get_direction(struct gpio_chip *chip, unsigned int gpio) 7608c2ecf20Sopenharmony_ci{ 7618c2ecf20Sopenharmony_ci struct mtk_pinctrl *hw = gpiochip_get_data(chip); 7628c2ecf20Sopenharmony_ci const struct mtk_pin_desc *desc; 7638c2ecf20Sopenharmony_ci int value, err; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci if (gpio >= hw->soc->npins) 7668c2ecf20Sopenharmony_ci return -EINVAL; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci /* 7698c2ecf20Sopenharmony_ci * "Virtual" GPIOs are always and only used for interrupts 7708c2ecf20Sopenharmony_ci * Since they are only used for interrupts, they are always inputs 7718c2ecf20Sopenharmony_ci */ 7728c2ecf20Sopenharmony_ci if (mtk_is_virt_gpio(hw, gpio)) 7738c2ecf20Sopenharmony_ci return 1; 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio]; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DIR, &value); 7788c2ecf20Sopenharmony_ci if (err) 7798c2ecf20Sopenharmony_ci return err; 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci if (value) 7828c2ecf20Sopenharmony_ci return GPIO_LINE_DIRECTION_OUT; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci return GPIO_LINE_DIRECTION_IN; 7858c2ecf20Sopenharmony_ci} 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_cistatic int mtk_gpio_get(struct gpio_chip *chip, unsigned int gpio) 7888c2ecf20Sopenharmony_ci{ 7898c2ecf20Sopenharmony_ci struct mtk_pinctrl *hw = gpiochip_get_data(chip); 7908c2ecf20Sopenharmony_ci const struct mtk_pin_desc *desc; 7918c2ecf20Sopenharmony_ci int value, err; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci if (gpio >= hw->soc->npins) 7948c2ecf20Sopenharmony_ci return -EINVAL; 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio]; 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DI, &value); 7998c2ecf20Sopenharmony_ci if (err) 8008c2ecf20Sopenharmony_ci return err; 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci return !!value; 8038c2ecf20Sopenharmony_ci} 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_cistatic void mtk_gpio_set(struct gpio_chip *chip, unsigned int gpio, int value) 8068c2ecf20Sopenharmony_ci{ 8078c2ecf20Sopenharmony_ci struct mtk_pinctrl *hw = gpiochip_get_data(chip); 8088c2ecf20Sopenharmony_ci const struct mtk_pin_desc *desc; 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci if (gpio >= hw->soc->npins) 8118c2ecf20Sopenharmony_ci return; 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio]; 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DO, !!value); 8168c2ecf20Sopenharmony_ci} 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_cistatic int mtk_gpio_direction_input(struct gpio_chip *chip, unsigned int gpio) 8198c2ecf20Sopenharmony_ci{ 8208c2ecf20Sopenharmony_ci struct mtk_pinctrl *hw = gpiochip_get_data(chip); 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci if (gpio >= hw->soc->npins) 8238c2ecf20Sopenharmony_ci return -EINVAL; 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci return pinctrl_gpio_direction_input(chip->base + gpio); 8268c2ecf20Sopenharmony_ci} 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_cistatic int mtk_gpio_direction_output(struct gpio_chip *chip, unsigned int gpio, 8298c2ecf20Sopenharmony_ci int value) 8308c2ecf20Sopenharmony_ci{ 8318c2ecf20Sopenharmony_ci struct mtk_pinctrl *hw = gpiochip_get_data(chip); 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci if (gpio >= hw->soc->npins) 8348c2ecf20Sopenharmony_ci return -EINVAL; 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci mtk_gpio_set(chip, gpio, value); 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci return pinctrl_gpio_direction_output(chip->base + gpio); 8398c2ecf20Sopenharmony_ci} 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_cistatic int mtk_gpio_to_irq(struct gpio_chip *chip, unsigned int offset) 8428c2ecf20Sopenharmony_ci{ 8438c2ecf20Sopenharmony_ci struct mtk_pinctrl *hw = gpiochip_get_data(chip); 8448c2ecf20Sopenharmony_ci const struct mtk_pin_desc *desc; 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci if (!hw->eint) 8478c2ecf20Sopenharmony_ci return -ENOTSUPP; 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci desc = (const struct mtk_pin_desc *)&hw->soc->pins[offset]; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci if (desc->eint.eint_n == EINT_NA) 8528c2ecf20Sopenharmony_ci return -ENOTSUPP; 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci return mtk_eint_find_irq(hw->eint, desc->eint.eint_n); 8558c2ecf20Sopenharmony_ci} 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_cistatic int mtk_gpio_set_config(struct gpio_chip *chip, unsigned int offset, 8588c2ecf20Sopenharmony_ci unsigned long config) 8598c2ecf20Sopenharmony_ci{ 8608c2ecf20Sopenharmony_ci struct mtk_pinctrl *hw = gpiochip_get_data(chip); 8618c2ecf20Sopenharmony_ci const struct mtk_pin_desc *desc; 8628c2ecf20Sopenharmony_ci u32 debounce; 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci desc = (const struct mtk_pin_desc *)&hw->soc->pins[offset]; 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci if (!hw->eint || 8678c2ecf20Sopenharmony_ci pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE || 8688c2ecf20Sopenharmony_ci desc->eint.eint_n == EINT_NA) 8698c2ecf20Sopenharmony_ci return -ENOTSUPP; 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci debounce = pinconf_to_config_argument(config); 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci return mtk_eint_set_debounce(hw->eint, desc->eint.eint_n, debounce); 8748c2ecf20Sopenharmony_ci} 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_cistatic int mtk_build_gpiochip(struct mtk_pinctrl *hw, struct device_node *np) 8778c2ecf20Sopenharmony_ci{ 8788c2ecf20Sopenharmony_ci struct gpio_chip *chip = &hw->chip; 8798c2ecf20Sopenharmony_ci int ret; 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci chip->label = PINCTRL_PINCTRL_DEV; 8828c2ecf20Sopenharmony_ci chip->parent = hw->dev; 8838c2ecf20Sopenharmony_ci chip->request = gpiochip_generic_request; 8848c2ecf20Sopenharmony_ci chip->free = gpiochip_generic_free; 8858c2ecf20Sopenharmony_ci chip->get_direction = mtk_gpio_get_direction; 8868c2ecf20Sopenharmony_ci chip->direction_input = mtk_gpio_direction_input; 8878c2ecf20Sopenharmony_ci chip->direction_output = mtk_gpio_direction_output; 8888c2ecf20Sopenharmony_ci chip->get = mtk_gpio_get; 8898c2ecf20Sopenharmony_ci chip->set = mtk_gpio_set; 8908c2ecf20Sopenharmony_ci chip->to_irq = mtk_gpio_to_irq, 8918c2ecf20Sopenharmony_ci chip->set_config = mtk_gpio_set_config, 8928c2ecf20Sopenharmony_ci chip->base = -1; 8938c2ecf20Sopenharmony_ci chip->ngpio = hw->soc->npins; 8948c2ecf20Sopenharmony_ci chip->of_node = np; 8958c2ecf20Sopenharmony_ci chip->of_gpio_n_cells = 2; 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci ret = gpiochip_add_data(chip, hw); 8988c2ecf20Sopenharmony_ci if (ret < 0) 8998c2ecf20Sopenharmony_ci return ret; 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci return 0; 9028c2ecf20Sopenharmony_ci} 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_cistatic int mtk_pctrl_build_state(struct platform_device *pdev) 9058c2ecf20Sopenharmony_ci{ 9068c2ecf20Sopenharmony_ci struct mtk_pinctrl *hw = platform_get_drvdata(pdev); 9078c2ecf20Sopenharmony_ci int i; 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci /* Allocate groups */ 9108c2ecf20Sopenharmony_ci hw->groups = devm_kmalloc_array(&pdev->dev, hw->soc->ngrps, 9118c2ecf20Sopenharmony_ci sizeof(*hw->groups), GFP_KERNEL); 9128c2ecf20Sopenharmony_ci if (!hw->groups) 9138c2ecf20Sopenharmony_ci return -ENOMEM; 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci /* We assume that one pin is one group, use pin name as group name. */ 9168c2ecf20Sopenharmony_ci hw->grp_names = devm_kmalloc_array(&pdev->dev, hw->soc->ngrps, 9178c2ecf20Sopenharmony_ci sizeof(*hw->grp_names), GFP_KERNEL); 9188c2ecf20Sopenharmony_ci if (!hw->grp_names) 9198c2ecf20Sopenharmony_ci return -ENOMEM; 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci for (i = 0; i < hw->soc->npins; i++) { 9228c2ecf20Sopenharmony_ci const struct mtk_pin_desc *pin = hw->soc->pins + i; 9238c2ecf20Sopenharmony_ci struct mtk_pinctrl_group *group = hw->groups + i; 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci group->name = pin->name; 9268c2ecf20Sopenharmony_ci group->pin = pin->number; 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci hw->grp_names[i] = pin->name; 9298c2ecf20Sopenharmony_ci } 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci return 0; 9328c2ecf20Sopenharmony_ci} 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ciint mtk_paris_pinctrl_probe(struct platform_device *pdev, 9358c2ecf20Sopenharmony_ci const struct mtk_pin_soc *soc) 9368c2ecf20Sopenharmony_ci{ 9378c2ecf20Sopenharmony_ci struct pinctrl_pin_desc *pins; 9388c2ecf20Sopenharmony_ci struct mtk_pinctrl *hw; 9398c2ecf20Sopenharmony_ci int err, i; 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci hw = devm_kzalloc(&pdev->dev, sizeof(*hw), GFP_KERNEL); 9428c2ecf20Sopenharmony_ci if (!hw) 9438c2ecf20Sopenharmony_ci return -ENOMEM; 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, hw); 9468c2ecf20Sopenharmony_ci hw->soc = soc; 9478c2ecf20Sopenharmony_ci hw->dev = &pdev->dev; 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci if (!hw->soc->nbase_names) { 9508c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 9518c2ecf20Sopenharmony_ci "SoC should be assigned at least one register base\n"); 9528c2ecf20Sopenharmony_ci return -EINVAL; 9538c2ecf20Sopenharmony_ci } 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci hw->base = devm_kmalloc_array(&pdev->dev, hw->soc->nbase_names, 9568c2ecf20Sopenharmony_ci sizeof(*hw->base), GFP_KERNEL); 9578c2ecf20Sopenharmony_ci if (!hw->base) 9588c2ecf20Sopenharmony_ci return -ENOMEM; 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci for (i = 0; i < hw->soc->nbase_names; i++) { 9618c2ecf20Sopenharmony_ci hw->base[i] = devm_platform_ioremap_resource_byname(pdev, 9628c2ecf20Sopenharmony_ci hw->soc->base_names[i]); 9638c2ecf20Sopenharmony_ci if (IS_ERR(hw->base[i])) 9648c2ecf20Sopenharmony_ci return PTR_ERR(hw->base[i]); 9658c2ecf20Sopenharmony_ci } 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci hw->nbase = hw->soc->nbase_names; 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci err = mtk_pctrl_build_state(pdev); 9708c2ecf20Sopenharmony_ci if (err) { 9718c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "build state failed: %d\n", err); 9728c2ecf20Sopenharmony_ci return -EINVAL; 9738c2ecf20Sopenharmony_ci } 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci /* Copy from internal struct mtk_pin_desc to register to the core */ 9768c2ecf20Sopenharmony_ci pins = devm_kmalloc_array(&pdev->dev, hw->soc->npins, sizeof(*pins), 9778c2ecf20Sopenharmony_ci GFP_KERNEL); 9788c2ecf20Sopenharmony_ci if (!pins) 9798c2ecf20Sopenharmony_ci return -ENOMEM; 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci for (i = 0; i < hw->soc->npins; i++) { 9828c2ecf20Sopenharmony_ci pins[i].number = hw->soc->pins[i].number; 9838c2ecf20Sopenharmony_ci pins[i].name = hw->soc->pins[i].name; 9848c2ecf20Sopenharmony_ci } 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci /* Setup pins descriptions per SoC types */ 9878c2ecf20Sopenharmony_ci mtk_desc.pins = (const struct pinctrl_pin_desc *)pins; 9888c2ecf20Sopenharmony_ci mtk_desc.npins = hw->soc->npins; 9898c2ecf20Sopenharmony_ci mtk_desc.num_custom_params = ARRAY_SIZE(mtk_custom_bindings); 9908c2ecf20Sopenharmony_ci mtk_desc.custom_params = mtk_custom_bindings; 9918c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 9928c2ecf20Sopenharmony_ci mtk_desc.custom_conf_items = mtk_conf_items; 9938c2ecf20Sopenharmony_ci#endif 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci err = devm_pinctrl_register_and_init(&pdev->dev, &mtk_desc, hw, 9968c2ecf20Sopenharmony_ci &hw->pctrl); 9978c2ecf20Sopenharmony_ci if (err) 9988c2ecf20Sopenharmony_ci return err; 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci err = pinctrl_enable(hw->pctrl); 10018c2ecf20Sopenharmony_ci if (err) 10028c2ecf20Sopenharmony_ci return err; 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci err = mtk_build_eint(hw, pdev); 10058c2ecf20Sopenharmony_ci if (err) 10068c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, 10078c2ecf20Sopenharmony_ci "Failed to add EINT, but pinctrl still can work\n"); 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci /* Build gpiochip should be after pinctrl_enable is done */ 10108c2ecf20Sopenharmony_ci err = mtk_build_gpiochip(hw, pdev->dev.of_node); 10118c2ecf20Sopenharmony_ci if (err) { 10128c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to add gpio_chip\n"); 10138c2ecf20Sopenharmony_ci return err; 10148c2ecf20Sopenharmony_ci } 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, hw); 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci return 0; 10198c2ecf20Sopenharmony_ci} 10208c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_paris_pinctrl_probe); 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_cistatic int mtk_paris_pinctrl_suspend(struct device *device) 10238c2ecf20Sopenharmony_ci{ 10248c2ecf20Sopenharmony_ci struct mtk_pinctrl *pctl = dev_get_drvdata(device); 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci return mtk_eint_do_suspend(pctl->eint); 10278c2ecf20Sopenharmony_ci} 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_cistatic int mtk_paris_pinctrl_resume(struct device *device) 10308c2ecf20Sopenharmony_ci{ 10318c2ecf20Sopenharmony_ci struct mtk_pinctrl *pctl = dev_get_drvdata(device); 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci return mtk_eint_do_resume(pctl->eint); 10348c2ecf20Sopenharmony_ci} 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ciconst struct dev_pm_ops mtk_paris_pinctrl_pm_ops = { 10378c2ecf20Sopenharmony_ci .suspend_noirq = mtk_paris_pinctrl_suspend, 10388c2ecf20Sopenharmony_ci .resume_noirq = mtk_paris_pinctrl_resume, 10398c2ecf20Sopenharmony_ci}; 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 10428c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("MediaTek Pinctrl Common Driver V2 Paris"); 1043