162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * MediaTek Pinctrl Paris Driver, which implement the vendor per-pin 462306a36Sopenharmony_ci * bindings for MediaTek SoC. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2018 MediaTek Inc. 762306a36Sopenharmony_ci * Author: Sean Wang <sean.wang@mediatek.com> 862306a36Sopenharmony_ci * Zhiyong Tao <zhiyong.tao@mediatek.com> 962306a36Sopenharmony_ci * Hongzhou.Yang <hongzhou.yang@mediatek.com> 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/gpio/driver.h> 1362306a36Sopenharmony_ci#include <linux/module.h> 1462306a36Sopenharmony_ci#include <linux/seq_file.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <linux/pinctrl/consumer.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include <dt-bindings/pinctrl/mt65xx.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include "pinctrl-paris.h" 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#define PINCTRL_PINCTRL_DEV KBUILD_MODNAME 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/* Custom pinconf parameters */ 2562306a36Sopenharmony_ci#define MTK_PIN_CONFIG_TDSEL (PIN_CONFIG_END + 1) 2662306a36Sopenharmony_ci#define MTK_PIN_CONFIG_RDSEL (PIN_CONFIG_END + 2) 2762306a36Sopenharmony_ci#define MTK_PIN_CONFIG_PU_ADV (PIN_CONFIG_END + 3) 2862306a36Sopenharmony_ci#define MTK_PIN_CONFIG_PD_ADV (PIN_CONFIG_END + 4) 2962306a36Sopenharmony_ci#define MTK_PIN_CONFIG_DRV_ADV (PIN_CONFIG_END + 5) 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic const struct pinconf_generic_params mtk_custom_bindings[] = { 3262306a36Sopenharmony_ci {"mediatek,tdsel", MTK_PIN_CONFIG_TDSEL, 0}, 3362306a36Sopenharmony_ci {"mediatek,rdsel", MTK_PIN_CONFIG_RDSEL, 0}, 3462306a36Sopenharmony_ci {"mediatek,pull-up-adv", MTK_PIN_CONFIG_PU_ADV, 1}, 3562306a36Sopenharmony_ci {"mediatek,pull-down-adv", MTK_PIN_CONFIG_PD_ADV, 1}, 3662306a36Sopenharmony_ci {"mediatek,drive-strength-adv", MTK_PIN_CONFIG_DRV_ADV, 2}, 3762306a36Sopenharmony_ci}; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 4062306a36Sopenharmony_cistatic const struct pin_config_item mtk_conf_items[] = { 4162306a36Sopenharmony_ci PCONFDUMP(MTK_PIN_CONFIG_TDSEL, "tdsel", NULL, true), 4262306a36Sopenharmony_ci PCONFDUMP(MTK_PIN_CONFIG_RDSEL, "rdsel", NULL, true), 4362306a36Sopenharmony_ci PCONFDUMP(MTK_PIN_CONFIG_PU_ADV, "pu-adv", NULL, true), 4462306a36Sopenharmony_ci PCONFDUMP(MTK_PIN_CONFIG_PD_ADV, "pd-adv", NULL, true), 4562306a36Sopenharmony_ci PCONFDUMP(MTK_PIN_CONFIG_DRV_ADV, "drive-strength-adv", NULL, true), 4662306a36Sopenharmony_ci}; 4762306a36Sopenharmony_ci#endif 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistatic const char * const mtk_gpio_functions[] = { 5062306a36Sopenharmony_ci "func0", "func1", "func2", "func3", 5162306a36Sopenharmony_ci "func4", "func5", "func6", "func7", 5262306a36Sopenharmony_ci "func8", "func9", "func10", "func11", 5362306a36Sopenharmony_ci "func12", "func13", "func14", "func15", 5462306a36Sopenharmony_ci}; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci/* 5762306a36Sopenharmony_ci * This section supports converting to/from custom MTK_PIN_CONFIG_DRV_ADV 5862306a36Sopenharmony_ci * and standard PIN_CONFIG_DRIVE_STRENGTH_UA pin configs. 5962306a36Sopenharmony_ci * 6062306a36Sopenharmony_ci * The custom value encodes three hardware bits as follows: 6162306a36Sopenharmony_ci * 6262306a36Sopenharmony_ci * | Bits | 6362306a36Sopenharmony_ci * | 2 (E1) | 1 (E0) | 0 (EN) | drive strength (uA) 6462306a36Sopenharmony_ci * ------------------------------------------------ 6562306a36Sopenharmony_ci * | x | x | 0 | disabled, use standard drive strength 6662306a36Sopenharmony_ci * ------------------------------------- 6762306a36Sopenharmony_ci * | 0 | 0 | 1 | 125 uA 6862306a36Sopenharmony_ci * | 0 | 1 | 1 | 250 uA 6962306a36Sopenharmony_ci * | 1 | 0 | 1 | 500 uA 7062306a36Sopenharmony_ci * | 1 | 1 | 1 | 1000 uA 7162306a36Sopenharmony_ci */ 7262306a36Sopenharmony_cistatic const int mtk_drv_adv_uA[] = { 125, 250, 500, 1000 }; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic int mtk_drv_adv_to_uA(int val) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci /* This should never happen. */ 7762306a36Sopenharmony_ci if (WARN_ON_ONCE(val < 0 || val > 7)) 7862306a36Sopenharmony_ci return -EINVAL; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci /* Bit 0 simply enables this hardware part */ 8162306a36Sopenharmony_ci if (!(val & BIT(0))) 8262306a36Sopenharmony_ci return -EINVAL; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci return mtk_drv_adv_uA[(val >> 1)]; 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic int mtk_drv_uA_to_adv(int val) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci switch (val) { 9062306a36Sopenharmony_ci case 125: 9162306a36Sopenharmony_ci return 0x1; 9262306a36Sopenharmony_ci case 250: 9362306a36Sopenharmony_ci return 0x3; 9462306a36Sopenharmony_ci case 500: 9562306a36Sopenharmony_ci return 0x5; 9662306a36Sopenharmony_ci case 1000: 9762306a36Sopenharmony_ci return 0x7; 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci return -EINVAL; 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic int mtk_pinmux_gpio_request_enable(struct pinctrl_dev *pctldev, 10462306a36Sopenharmony_ci struct pinctrl_gpio_range *range, 10562306a36Sopenharmony_ci unsigned int pin) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 10862306a36Sopenharmony_ci const struct mtk_pin_desc *desc; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci return mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_MODE, 11362306a36Sopenharmony_ci hw->soc->gpio_m); 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic int mtk_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev, 11762306a36Sopenharmony_ci struct pinctrl_gpio_range *range, 11862306a36Sopenharmony_ci unsigned int pin, bool input) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 12162306a36Sopenharmony_ci const struct mtk_pin_desc *desc; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci /* hardware would take 0 as input direction */ 12662306a36Sopenharmony_ci return mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR, !input); 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic int mtk_pinconf_get(struct pinctrl_dev *pctldev, 13062306a36Sopenharmony_ci unsigned int pin, unsigned long *config) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 13362306a36Sopenharmony_ci u32 param = pinconf_to_config_param(*config); 13462306a36Sopenharmony_ci int pullup, reg, err = -ENOTSUPP, ret = 1; 13562306a36Sopenharmony_ci const struct mtk_pin_desc *desc; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci if (pin >= hw->soc->npins) 13862306a36Sopenharmony_ci return -EINVAL; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci switch (param) { 14362306a36Sopenharmony_ci case PIN_CONFIG_BIAS_DISABLE: 14462306a36Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_UP: 14562306a36Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_DOWN: 14662306a36Sopenharmony_ci if (!hw->soc->bias_get_combo) 14762306a36Sopenharmony_ci break; 14862306a36Sopenharmony_ci err = hw->soc->bias_get_combo(hw, desc, &pullup, &ret); 14962306a36Sopenharmony_ci if (err) 15062306a36Sopenharmony_ci break; 15162306a36Sopenharmony_ci if (ret == MTK_PUPD_SET_R1R0_00) 15262306a36Sopenharmony_ci ret = MTK_DISABLE; 15362306a36Sopenharmony_ci if (param == PIN_CONFIG_BIAS_DISABLE) { 15462306a36Sopenharmony_ci if (ret != MTK_DISABLE) 15562306a36Sopenharmony_ci err = -EINVAL; 15662306a36Sopenharmony_ci } else if (param == PIN_CONFIG_BIAS_PULL_UP) { 15762306a36Sopenharmony_ci if (!pullup || ret == MTK_DISABLE) 15862306a36Sopenharmony_ci err = -EINVAL; 15962306a36Sopenharmony_ci } else if (param == PIN_CONFIG_BIAS_PULL_DOWN) { 16062306a36Sopenharmony_ci if (pullup || ret == MTK_DISABLE) 16162306a36Sopenharmony_ci err = -EINVAL; 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci break; 16462306a36Sopenharmony_ci case PIN_CONFIG_SLEW_RATE: 16562306a36Sopenharmony_ci err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_SR, &ret); 16662306a36Sopenharmony_ci break; 16762306a36Sopenharmony_ci case PIN_CONFIG_INPUT_ENABLE: 16862306a36Sopenharmony_ci case PIN_CONFIG_OUTPUT_ENABLE: 16962306a36Sopenharmony_ci err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DIR, &ret); 17062306a36Sopenharmony_ci if (err) 17162306a36Sopenharmony_ci break; 17262306a36Sopenharmony_ci /* CONFIG Current direction return value 17362306a36Sopenharmony_ci * ------------- ----------------- ---------------------- 17462306a36Sopenharmony_ci * OUTPUT_ENABLE output 1 (= HW value) 17562306a36Sopenharmony_ci * input 0 (= HW value) 17662306a36Sopenharmony_ci * INPUT_ENABLE output 0 (= reverse HW value) 17762306a36Sopenharmony_ci * input 1 (= reverse HW value) 17862306a36Sopenharmony_ci */ 17962306a36Sopenharmony_ci if (param == PIN_CONFIG_INPUT_ENABLE) 18062306a36Sopenharmony_ci ret = !ret; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci break; 18362306a36Sopenharmony_ci case PIN_CONFIG_INPUT_SCHMITT_ENABLE: 18462306a36Sopenharmony_ci err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DIR, &ret); 18562306a36Sopenharmony_ci if (err) 18662306a36Sopenharmony_ci break; 18762306a36Sopenharmony_ci /* return error when in output mode 18862306a36Sopenharmony_ci * because schmitt trigger only work in input mode 18962306a36Sopenharmony_ci */ 19062306a36Sopenharmony_ci if (ret) { 19162306a36Sopenharmony_ci err = -EINVAL; 19262306a36Sopenharmony_ci break; 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_SMT, &ret); 19662306a36Sopenharmony_ci break; 19762306a36Sopenharmony_ci case PIN_CONFIG_DRIVE_STRENGTH: 19862306a36Sopenharmony_ci if (!hw->soc->drive_get) 19962306a36Sopenharmony_ci break; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci if (hw->soc->adv_drive_get) { 20262306a36Sopenharmony_ci err = hw->soc->adv_drive_get(hw, desc, &ret); 20362306a36Sopenharmony_ci if (!err) { 20462306a36Sopenharmony_ci err = mtk_drv_adv_to_uA(ret); 20562306a36Sopenharmony_ci if (err > 0) { 20662306a36Sopenharmony_ci /* PIN_CONFIG_DRIVE_STRENGTH_UA used */ 20762306a36Sopenharmony_ci err = -EINVAL; 20862306a36Sopenharmony_ci break; 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci err = hw->soc->drive_get(hw, desc, &ret); 21462306a36Sopenharmony_ci break; 21562306a36Sopenharmony_ci case PIN_CONFIG_DRIVE_STRENGTH_UA: 21662306a36Sopenharmony_ci if (!hw->soc->adv_drive_get) 21762306a36Sopenharmony_ci break; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci err = hw->soc->adv_drive_get(hw, desc, &ret); 22062306a36Sopenharmony_ci if (err) 22162306a36Sopenharmony_ci break; 22262306a36Sopenharmony_ci err = mtk_drv_adv_to_uA(ret); 22362306a36Sopenharmony_ci if (err < 0) 22462306a36Sopenharmony_ci break; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci ret = err; 22762306a36Sopenharmony_ci err = 0; 22862306a36Sopenharmony_ci break; 22962306a36Sopenharmony_ci case MTK_PIN_CONFIG_TDSEL: 23062306a36Sopenharmony_ci case MTK_PIN_CONFIG_RDSEL: 23162306a36Sopenharmony_ci reg = (param == MTK_PIN_CONFIG_TDSEL) ? 23262306a36Sopenharmony_ci PINCTRL_PIN_REG_TDSEL : PINCTRL_PIN_REG_RDSEL; 23362306a36Sopenharmony_ci err = mtk_hw_get_value(hw, desc, reg, &ret); 23462306a36Sopenharmony_ci break; 23562306a36Sopenharmony_ci case MTK_PIN_CONFIG_PU_ADV: 23662306a36Sopenharmony_ci case MTK_PIN_CONFIG_PD_ADV: 23762306a36Sopenharmony_ci if (!hw->soc->adv_pull_get) 23862306a36Sopenharmony_ci break; 23962306a36Sopenharmony_ci pullup = param == MTK_PIN_CONFIG_PU_ADV; 24062306a36Sopenharmony_ci err = hw->soc->adv_pull_get(hw, desc, pullup, &ret); 24162306a36Sopenharmony_ci break; 24262306a36Sopenharmony_ci case MTK_PIN_CONFIG_DRV_ADV: 24362306a36Sopenharmony_ci if (!hw->soc->adv_drive_get) 24462306a36Sopenharmony_ci break; 24562306a36Sopenharmony_ci err = hw->soc->adv_drive_get(hw, desc, &ret); 24662306a36Sopenharmony_ci break; 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci if (!err) 25062306a36Sopenharmony_ci *config = pinconf_to_config_packed(param, ret); 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci return err; 25362306a36Sopenharmony_ci} 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_cistatic int mtk_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, 25662306a36Sopenharmony_ci enum pin_config_param param, u32 arg) 25762306a36Sopenharmony_ci{ 25862306a36Sopenharmony_ci struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 25962306a36Sopenharmony_ci const struct mtk_pin_desc *desc; 26062306a36Sopenharmony_ci int err = -ENOTSUPP; 26162306a36Sopenharmony_ci u32 reg; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci if (pin >= hw->soc->npins) 26462306a36Sopenharmony_ci return -EINVAL; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci switch ((u32)param) { 26962306a36Sopenharmony_ci case PIN_CONFIG_BIAS_DISABLE: 27062306a36Sopenharmony_ci if (!hw->soc->bias_set_combo) 27162306a36Sopenharmony_ci break; 27262306a36Sopenharmony_ci err = hw->soc->bias_set_combo(hw, desc, 0, MTK_DISABLE); 27362306a36Sopenharmony_ci break; 27462306a36Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_UP: 27562306a36Sopenharmony_ci if (!hw->soc->bias_set_combo) 27662306a36Sopenharmony_ci break; 27762306a36Sopenharmony_ci err = hw->soc->bias_set_combo(hw, desc, 1, arg); 27862306a36Sopenharmony_ci break; 27962306a36Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_DOWN: 28062306a36Sopenharmony_ci if (!hw->soc->bias_set_combo) 28162306a36Sopenharmony_ci break; 28262306a36Sopenharmony_ci err = hw->soc->bias_set_combo(hw, desc, 0, arg); 28362306a36Sopenharmony_ci break; 28462306a36Sopenharmony_ci case PIN_CONFIG_OUTPUT_ENABLE: 28562306a36Sopenharmony_ci err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_SMT, 28662306a36Sopenharmony_ci MTK_DISABLE); 28762306a36Sopenharmony_ci /* Keep set direction to consider the case that a GPIO pin 28862306a36Sopenharmony_ci * does not have SMT control 28962306a36Sopenharmony_ci */ 29062306a36Sopenharmony_ci if (err != -ENOTSUPP) 29162306a36Sopenharmony_ci break; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR, 29462306a36Sopenharmony_ci MTK_OUTPUT); 29562306a36Sopenharmony_ci break; 29662306a36Sopenharmony_ci case PIN_CONFIG_INPUT_ENABLE: 29762306a36Sopenharmony_ci /* regard all non-zero value as enable */ 29862306a36Sopenharmony_ci err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_IES, !!arg); 29962306a36Sopenharmony_ci if (err) 30062306a36Sopenharmony_ci break; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR, 30362306a36Sopenharmony_ci MTK_INPUT); 30462306a36Sopenharmony_ci break; 30562306a36Sopenharmony_ci case PIN_CONFIG_SLEW_RATE: 30662306a36Sopenharmony_ci /* regard all non-zero value as enable */ 30762306a36Sopenharmony_ci err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_SR, !!arg); 30862306a36Sopenharmony_ci break; 30962306a36Sopenharmony_ci case PIN_CONFIG_OUTPUT: 31062306a36Sopenharmony_ci err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DO, 31162306a36Sopenharmony_ci arg); 31262306a36Sopenharmony_ci if (err) 31362306a36Sopenharmony_ci break; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR, 31662306a36Sopenharmony_ci MTK_OUTPUT); 31762306a36Sopenharmony_ci break; 31862306a36Sopenharmony_ci case PIN_CONFIG_INPUT_SCHMITT: 31962306a36Sopenharmony_ci case PIN_CONFIG_INPUT_SCHMITT_ENABLE: 32062306a36Sopenharmony_ci /* arg = 1: Input mode & SMT enable ; 32162306a36Sopenharmony_ci * arg = 0: Output mode & SMT disable 32262306a36Sopenharmony_ci */ 32362306a36Sopenharmony_ci err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR, !arg); 32462306a36Sopenharmony_ci if (err) 32562306a36Sopenharmony_ci break; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_SMT, !!arg); 32862306a36Sopenharmony_ci break; 32962306a36Sopenharmony_ci case PIN_CONFIG_DRIVE_STRENGTH: 33062306a36Sopenharmony_ci if (!hw->soc->drive_set) 33162306a36Sopenharmony_ci break; 33262306a36Sopenharmony_ci err = hw->soc->drive_set(hw, desc, arg); 33362306a36Sopenharmony_ci break; 33462306a36Sopenharmony_ci case PIN_CONFIG_DRIVE_STRENGTH_UA: 33562306a36Sopenharmony_ci if (!hw->soc->adv_drive_set) 33662306a36Sopenharmony_ci break; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci err = mtk_drv_uA_to_adv(arg); 33962306a36Sopenharmony_ci if (err < 0) 34062306a36Sopenharmony_ci break; 34162306a36Sopenharmony_ci err = hw->soc->adv_drive_set(hw, desc, err); 34262306a36Sopenharmony_ci break; 34362306a36Sopenharmony_ci case MTK_PIN_CONFIG_TDSEL: 34462306a36Sopenharmony_ci case MTK_PIN_CONFIG_RDSEL: 34562306a36Sopenharmony_ci reg = (param == MTK_PIN_CONFIG_TDSEL) ? 34662306a36Sopenharmony_ci PINCTRL_PIN_REG_TDSEL : PINCTRL_PIN_REG_RDSEL; 34762306a36Sopenharmony_ci err = mtk_hw_set_value(hw, desc, reg, arg); 34862306a36Sopenharmony_ci break; 34962306a36Sopenharmony_ci case MTK_PIN_CONFIG_PU_ADV: 35062306a36Sopenharmony_ci case MTK_PIN_CONFIG_PD_ADV: 35162306a36Sopenharmony_ci if (!hw->soc->adv_pull_set) 35262306a36Sopenharmony_ci break; 35362306a36Sopenharmony_ci err = hw->soc->adv_pull_set(hw, desc, 35462306a36Sopenharmony_ci (param == MTK_PIN_CONFIG_PU_ADV), 35562306a36Sopenharmony_ci arg); 35662306a36Sopenharmony_ci break; 35762306a36Sopenharmony_ci case MTK_PIN_CONFIG_DRV_ADV: 35862306a36Sopenharmony_ci if (!hw->soc->adv_drive_set) 35962306a36Sopenharmony_ci break; 36062306a36Sopenharmony_ci err = hw->soc->adv_drive_set(hw, desc, arg); 36162306a36Sopenharmony_ci break; 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci return err; 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_cistatic struct mtk_pinctrl_group * 36862306a36Sopenharmony_cimtk_pctrl_find_group_by_pin(struct mtk_pinctrl *hw, u32 pin) 36962306a36Sopenharmony_ci{ 37062306a36Sopenharmony_ci int i; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci for (i = 0; i < hw->soc->ngrps; i++) { 37362306a36Sopenharmony_ci struct mtk_pinctrl_group *grp = hw->groups + i; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci if (grp->pin == pin) 37662306a36Sopenharmony_ci return grp; 37762306a36Sopenharmony_ci } 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci return NULL; 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_cistatic const struct mtk_func_desc * 38362306a36Sopenharmony_cimtk_pctrl_find_function_by_pin(struct mtk_pinctrl *hw, u32 pin_num, u32 fnum) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci const struct mtk_pin_desc *pin = hw->soc->pins + pin_num; 38662306a36Sopenharmony_ci const struct mtk_func_desc *func = pin->funcs; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci while (func && func->name) { 38962306a36Sopenharmony_ci if (func->muxval == fnum) 39062306a36Sopenharmony_ci return func; 39162306a36Sopenharmony_ci func++; 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci return NULL; 39562306a36Sopenharmony_ci} 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_cistatic bool mtk_pctrl_is_function_valid(struct mtk_pinctrl *hw, u32 pin_num, 39862306a36Sopenharmony_ci u32 fnum) 39962306a36Sopenharmony_ci{ 40062306a36Sopenharmony_ci int i; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci for (i = 0; i < hw->soc->npins; i++) { 40362306a36Sopenharmony_ci const struct mtk_pin_desc *pin = hw->soc->pins + i; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci if (pin->number == pin_num) { 40662306a36Sopenharmony_ci const struct mtk_func_desc *func = pin->funcs; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci while (func && func->name) { 40962306a36Sopenharmony_ci if (func->muxval == fnum) 41062306a36Sopenharmony_ci return true; 41162306a36Sopenharmony_ci func++; 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci break; 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci return false; 41962306a36Sopenharmony_ci} 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_cistatic int mtk_pctrl_dt_node_to_map_func(struct mtk_pinctrl *pctl, 42262306a36Sopenharmony_ci u32 pin, u32 fnum, 42362306a36Sopenharmony_ci struct mtk_pinctrl_group *grp, 42462306a36Sopenharmony_ci struct pinctrl_map **map, 42562306a36Sopenharmony_ci unsigned *reserved_maps, 42662306a36Sopenharmony_ci unsigned *num_maps) 42762306a36Sopenharmony_ci{ 42862306a36Sopenharmony_ci bool ret; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci if (*num_maps == *reserved_maps) 43162306a36Sopenharmony_ci return -ENOSPC; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci (*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP; 43462306a36Sopenharmony_ci (*map)[*num_maps].data.mux.group = grp->name; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci ret = mtk_pctrl_is_function_valid(pctl, pin, fnum); 43762306a36Sopenharmony_ci if (!ret) { 43862306a36Sopenharmony_ci dev_err(pctl->dev, "invalid function %d on pin %d .\n", 43962306a36Sopenharmony_ci fnum, pin); 44062306a36Sopenharmony_ci return -EINVAL; 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci (*map)[*num_maps].data.mux.function = mtk_gpio_functions[fnum]; 44462306a36Sopenharmony_ci (*num_maps)++; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci return 0; 44762306a36Sopenharmony_ci} 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_cistatic int mtk_pctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev, 45062306a36Sopenharmony_ci struct device_node *node, 45162306a36Sopenharmony_ci struct pinctrl_map **map, 45262306a36Sopenharmony_ci unsigned *reserved_maps, 45362306a36Sopenharmony_ci unsigned *num_maps) 45462306a36Sopenharmony_ci{ 45562306a36Sopenharmony_ci struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 45662306a36Sopenharmony_ci int num_pins, num_funcs, maps_per_pin, i, err; 45762306a36Sopenharmony_ci struct mtk_pinctrl_group *grp; 45862306a36Sopenharmony_ci unsigned int num_configs; 45962306a36Sopenharmony_ci bool has_config = false; 46062306a36Sopenharmony_ci unsigned long *configs; 46162306a36Sopenharmony_ci u32 pinfunc, pin, func; 46262306a36Sopenharmony_ci struct property *pins; 46362306a36Sopenharmony_ci unsigned reserve = 0; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci pins = of_find_property(node, "pinmux", NULL); 46662306a36Sopenharmony_ci if (!pins) { 46762306a36Sopenharmony_ci dev_err(hw->dev, "missing pins property in node %pOFn .\n", 46862306a36Sopenharmony_ci node); 46962306a36Sopenharmony_ci return -EINVAL; 47062306a36Sopenharmony_ci } 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci err = pinconf_generic_parse_dt_config(node, pctldev, &configs, 47362306a36Sopenharmony_ci &num_configs); 47462306a36Sopenharmony_ci if (err) 47562306a36Sopenharmony_ci return err; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci if (num_configs) 47862306a36Sopenharmony_ci has_config = true; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci num_pins = pins->length / sizeof(u32); 48162306a36Sopenharmony_ci num_funcs = num_pins; 48262306a36Sopenharmony_ci maps_per_pin = 0; 48362306a36Sopenharmony_ci if (num_funcs) 48462306a36Sopenharmony_ci maps_per_pin++; 48562306a36Sopenharmony_ci if (has_config && num_pins >= 1) 48662306a36Sopenharmony_ci maps_per_pin++; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci if (!num_pins || !maps_per_pin) { 48962306a36Sopenharmony_ci err = -EINVAL; 49062306a36Sopenharmony_ci goto exit; 49162306a36Sopenharmony_ci } 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci reserve = num_pins * maps_per_pin; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci err = pinctrl_utils_reserve_map(pctldev, map, reserved_maps, num_maps, 49662306a36Sopenharmony_ci reserve); 49762306a36Sopenharmony_ci if (err < 0) 49862306a36Sopenharmony_ci goto exit; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci for (i = 0; i < num_pins; i++) { 50162306a36Sopenharmony_ci err = of_property_read_u32_index(node, "pinmux", i, &pinfunc); 50262306a36Sopenharmony_ci if (err) 50362306a36Sopenharmony_ci goto exit; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci pin = MTK_GET_PIN_NO(pinfunc); 50662306a36Sopenharmony_ci func = MTK_GET_PIN_FUNC(pinfunc); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci if (pin >= hw->soc->npins || 50962306a36Sopenharmony_ci func >= ARRAY_SIZE(mtk_gpio_functions)) { 51062306a36Sopenharmony_ci dev_err(hw->dev, "invalid pins value.\n"); 51162306a36Sopenharmony_ci err = -EINVAL; 51262306a36Sopenharmony_ci goto exit; 51362306a36Sopenharmony_ci } 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci grp = mtk_pctrl_find_group_by_pin(hw, pin); 51662306a36Sopenharmony_ci if (!grp) { 51762306a36Sopenharmony_ci dev_err(hw->dev, "unable to match pin %d to group\n", 51862306a36Sopenharmony_ci pin); 51962306a36Sopenharmony_ci err = -EINVAL; 52062306a36Sopenharmony_ci goto exit; 52162306a36Sopenharmony_ci } 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci err = mtk_pctrl_dt_node_to_map_func(hw, pin, func, grp, map, 52462306a36Sopenharmony_ci reserved_maps, num_maps); 52562306a36Sopenharmony_ci if (err < 0) 52662306a36Sopenharmony_ci goto exit; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci if (has_config) { 52962306a36Sopenharmony_ci err = pinctrl_utils_add_map_configs(pctldev, map, 53062306a36Sopenharmony_ci reserved_maps, 53162306a36Sopenharmony_ci num_maps, 53262306a36Sopenharmony_ci grp->name, 53362306a36Sopenharmony_ci configs, 53462306a36Sopenharmony_ci num_configs, 53562306a36Sopenharmony_ci PIN_MAP_TYPE_CONFIGS_GROUP); 53662306a36Sopenharmony_ci if (err < 0) 53762306a36Sopenharmony_ci goto exit; 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci } 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci err = 0; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ciexit: 54462306a36Sopenharmony_ci kfree(configs); 54562306a36Sopenharmony_ci return err; 54662306a36Sopenharmony_ci} 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_cistatic int mtk_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev, 54962306a36Sopenharmony_ci struct device_node *np_config, 55062306a36Sopenharmony_ci struct pinctrl_map **map, 55162306a36Sopenharmony_ci unsigned *num_maps) 55262306a36Sopenharmony_ci{ 55362306a36Sopenharmony_ci struct device_node *np; 55462306a36Sopenharmony_ci unsigned reserved_maps; 55562306a36Sopenharmony_ci int ret; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci *map = NULL; 55862306a36Sopenharmony_ci *num_maps = 0; 55962306a36Sopenharmony_ci reserved_maps = 0; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci for_each_child_of_node(np_config, np) { 56262306a36Sopenharmony_ci ret = mtk_pctrl_dt_subnode_to_map(pctldev, np, map, 56362306a36Sopenharmony_ci &reserved_maps, 56462306a36Sopenharmony_ci num_maps); 56562306a36Sopenharmony_ci if (ret < 0) { 56662306a36Sopenharmony_ci pinctrl_utils_free_map(pctldev, *map, *num_maps); 56762306a36Sopenharmony_ci of_node_put(np); 56862306a36Sopenharmony_ci return ret; 56962306a36Sopenharmony_ci } 57062306a36Sopenharmony_ci } 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci return 0; 57362306a36Sopenharmony_ci} 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_cistatic int mtk_pctrl_get_groups_count(struct pinctrl_dev *pctldev) 57662306a36Sopenharmony_ci{ 57762306a36Sopenharmony_ci struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci return hw->soc->ngrps; 58062306a36Sopenharmony_ci} 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_cistatic const char *mtk_pctrl_get_group_name(struct pinctrl_dev *pctldev, 58362306a36Sopenharmony_ci unsigned group) 58462306a36Sopenharmony_ci{ 58562306a36Sopenharmony_ci struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci return hw->groups[group].name; 58862306a36Sopenharmony_ci} 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_cistatic int mtk_pctrl_get_group_pins(struct pinctrl_dev *pctldev, 59162306a36Sopenharmony_ci unsigned group, const unsigned **pins, 59262306a36Sopenharmony_ci unsigned *num_pins) 59362306a36Sopenharmony_ci{ 59462306a36Sopenharmony_ci struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci *pins = (unsigned *)&hw->groups[group].pin; 59762306a36Sopenharmony_ci *num_pins = 1; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci return 0; 60062306a36Sopenharmony_ci} 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_cistatic int mtk_hw_get_value_wrap(struct mtk_pinctrl *hw, unsigned int gpio, int field) 60362306a36Sopenharmony_ci{ 60462306a36Sopenharmony_ci const struct mtk_pin_desc *desc; 60562306a36Sopenharmony_ci int value, err; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci if (gpio >= hw->soc->npins) 60862306a36Sopenharmony_ci return -EINVAL; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio]; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci err = mtk_hw_get_value(hw, desc, field, &value); 61362306a36Sopenharmony_ci if (err) 61462306a36Sopenharmony_ci return err; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci return value; 61762306a36Sopenharmony_ci} 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci#define mtk_pctrl_get_pinmux(hw, gpio) \ 62062306a36Sopenharmony_ci mtk_hw_get_value_wrap(hw, gpio, PINCTRL_PIN_REG_MODE) 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci#define mtk_pctrl_get_direction(hw, gpio) \ 62362306a36Sopenharmony_ci mtk_hw_get_value_wrap(hw, gpio, PINCTRL_PIN_REG_DIR) 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci#define mtk_pctrl_get_out(hw, gpio) \ 62662306a36Sopenharmony_ci mtk_hw_get_value_wrap(hw, gpio, PINCTRL_PIN_REG_DO) 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci#define mtk_pctrl_get_in(hw, gpio) \ 62962306a36Sopenharmony_ci mtk_hw_get_value_wrap(hw, gpio, PINCTRL_PIN_REG_DI) 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci#define mtk_pctrl_get_smt(hw, gpio) \ 63262306a36Sopenharmony_ci mtk_hw_get_value_wrap(hw, gpio, PINCTRL_PIN_REG_SMT) 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci#define mtk_pctrl_get_ies(hw, gpio) \ 63562306a36Sopenharmony_ci mtk_hw_get_value_wrap(hw, gpio, PINCTRL_PIN_REG_IES) 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci#define mtk_pctrl_get_driving(hw, gpio) \ 63862306a36Sopenharmony_ci mtk_hw_get_value_wrap(hw, gpio, PINCTRL_PIN_REG_DRV) 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_cissize_t mtk_pctrl_show_one_pin(struct mtk_pinctrl *hw, 64162306a36Sopenharmony_ci unsigned int gpio, char *buf, unsigned int buf_len) 64262306a36Sopenharmony_ci{ 64362306a36Sopenharmony_ci int pinmux, pullup = 0, pullen = 0, len = 0, r1 = -1, r0 = -1, rsel = -1; 64462306a36Sopenharmony_ci const struct mtk_pin_desc *desc; 64562306a36Sopenharmony_ci u32 try_all_type = 0; 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci if (gpio >= hw->soc->npins) 64862306a36Sopenharmony_ci return -EINVAL; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci if (mtk_is_virt_gpio(hw, gpio)) 65162306a36Sopenharmony_ci return -EINVAL; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio]; 65462306a36Sopenharmony_ci pinmux = mtk_pctrl_get_pinmux(hw, gpio); 65562306a36Sopenharmony_ci if (pinmux >= hw->soc->nfuncs) 65662306a36Sopenharmony_ci pinmux -= hw->soc->nfuncs; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci mtk_pinconf_bias_get_combo(hw, desc, &pullup, &pullen); 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci if (hw->soc->pull_type) 66162306a36Sopenharmony_ci try_all_type = hw->soc->pull_type[desc->number]; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci if (hw->rsel_si_unit && (try_all_type & MTK_PULL_RSEL_TYPE)) { 66462306a36Sopenharmony_ci rsel = pullen; 66562306a36Sopenharmony_ci pullen = 1; 66662306a36Sopenharmony_ci } else { 66762306a36Sopenharmony_ci /* Case for: R1R0 */ 66862306a36Sopenharmony_ci if (pullen == MTK_PUPD_SET_R1R0_00) { 66962306a36Sopenharmony_ci pullen = 0; 67062306a36Sopenharmony_ci r1 = 0; 67162306a36Sopenharmony_ci r0 = 0; 67262306a36Sopenharmony_ci } else if (pullen == MTK_PUPD_SET_R1R0_01) { 67362306a36Sopenharmony_ci pullen = 1; 67462306a36Sopenharmony_ci r1 = 0; 67562306a36Sopenharmony_ci r0 = 1; 67662306a36Sopenharmony_ci } else if (pullen == MTK_PUPD_SET_R1R0_10) { 67762306a36Sopenharmony_ci pullen = 1; 67862306a36Sopenharmony_ci r1 = 1; 67962306a36Sopenharmony_ci r0 = 0; 68062306a36Sopenharmony_ci } else if (pullen == MTK_PUPD_SET_R1R0_11) { 68162306a36Sopenharmony_ci pullen = 1; 68262306a36Sopenharmony_ci r1 = 1; 68362306a36Sopenharmony_ci r0 = 1; 68462306a36Sopenharmony_ci } 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci /* Case for: RSEL */ 68762306a36Sopenharmony_ci if (pullen >= MTK_PULL_SET_RSEL_000 && 68862306a36Sopenharmony_ci pullen <= MTK_PULL_SET_RSEL_111) { 68962306a36Sopenharmony_ci rsel = pullen - MTK_PULL_SET_RSEL_000; 69062306a36Sopenharmony_ci pullen = 1; 69162306a36Sopenharmony_ci } 69262306a36Sopenharmony_ci } 69362306a36Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, 69462306a36Sopenharmony_ci "%03d: %1d%1d%1d%1d%02d%1d%1d%1d%1d", 69562306a36Sopenharmony_ci gpio, 69662306a36Sopenharmony_ci pinmux, 69762306a36Sopenharmony_ci mtk_pctrl_get_direction(hw, gpio), 69862306a36Sopenharmony_ci mtk_pctrl_get_out(hw, gpio), 69962306a36Sopenharmony_ci mtk_pctrl_get_in(hw, gpio), 70062306a36Sopenharmony_ci mtk_pctrl_get_driving(hw, gpio), 70162306a36Sopenharmony_ci mtk_pctrl_get_smt(hw, gpio), 70262306a36Sopenharmony_ci mtk_pctrl_get_ies(hw, gpio), 70362306a36Sopenharmony_ci pullen, 70462306a36Sopenharmony_ci pullup); 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci if (r1 != -1) 70762306a36Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, " (%1d %1d)", r1, r0); 70862306a36Sopenharmony_ci else if (rsel != -1) 70962306a36Sopenharmony_ci len += scnprintf(buf + len, buf_len - len, " (%1d)", rsel); 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci return len; 71262306a36Sopenharmony_ci} 71362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_pctrl_show_one_pin); 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci#define PIN_DBG_BUF_SZ 96 71662306a36Sopenharmony_cistatic void mtk_pctrl_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, 71762306a36Sopenharmony_ci unsigned int gpio) 71862306a36Sopenharmony_ci{ 71962306a36Sopenharmony_ci struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 72062306a36Sopenharmony_ci char buf[PIN_DBG_BUF_SZ] = { 0 }; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci (void)mtk_pctrl_show_one_pin(hw, gpio, buf, PIN_DBG_BUF_SZ); 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci seq_printf(s, "%s", buf); 72562306a36Sopenharmony_ci} 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_cistatic const struct pinctrl_ops mtk_pctlops = { 72862306a36Sopenharmony_ci .dt_node_to_map = mtk_pctrl_dt_node_to_map, 72962306a36Sopenharmony_ci .dt_free_map = pinctrl_utils_free_map, 73062306a36Sopenharmony_ci .get_groups_count = mtk_pctrl_get_groups_count, 73162306a36Sopenharmony_ci .get_group_name = mtk_pctrl_get_group_name, 73262306a36Sopenharmony_ci .get_group_pins = mtk_pctrl_get_group_pins, 73362306a36Sopenharmony_ci .pin_dbg_show = mtk_pctrl_dbg_show, 73462306a36Sopenharmony_ci}; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_cistatic int mtk_pmx_get_funcs_cnt(struct pinctrl_dev *pctldev) 73762306a36Sopenharmony_ci{ 73862306a36Sopenharmony_ci return ARRAY_SIZE(mtk_gpio_functions); 73962306a36Sopenharmony_ci} 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_cistatic const char *mtk_pmx_get_func_name(struct pinctrl_dev *pctldev, 74262306a36Sopenharmony_ci unsigned selector) 74362306a36Sopenharmony_ci{ 74462306a36Sopenharmony_ci return mtk_gpio_functions[selector]; 74562306a36Sopenharmony_ci} 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_cistatic int mtk_pmx_get_func_groups(struct pinctrl_dev *pctldev, 74862306a36Sopenharmony_ci unsigned function, 74962306a36Sopenharmony_ci const char * const **groups, 75062306a36Sopenharmony_ci unsigned * const num_groups) 75162306a36Sopenharmony_ci{ 75262306a36Sopenharmony_ci struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci *groups = hw->grp_names; 75562306a36Sopenharmony_ci *num_groups = hw->soc->ngrps; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci return 0; 75862306a36Sopenharmony_ci} 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_cistatic int mtk_pmx_set_mux(struct pinctrl_dev *pctldev, 76162306a36Sopenharmony_ci unsigned function, 76262306a36Sopenharmony_ci unsigned group) 76362306a36Sopenharmony_ci{ 76462306a36Sopenharmony_ci struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 76562306a36Sopenharmony_ci struct mtk_pinctrl_group *grp = hw->groups + group; 76662306a36Sopenharmony_ci const struct mtk_func_desc *desc_func; 76762306a36Sopenharmony_ci const struct mtk_pin_desc *desc; 76862306a36Sopenharmony_ci bool ret; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci ret = mtk_pctrl_is_function_valid(hw, grp->pin, function); 77162306a36Sopenharmony_ci if (!ret) { 77262306a36Sopenharmony_ci dev_err(hw->dev, "invalid function %d on group %d .\n", 77362306a36Sopenharmony_ci function, group); 77462306a36Sopenharmony_ci return -EINVAL; 77562306a36Sopenharmony_ci } 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci desc_func = mtk_pctrl_find_function_by_pin(hw, grp->pin, function); 77862306a36Sopenharmony_ci if (!desc_func) 77962306a36Sopenharmony_ci return -EINVAL; 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci desc = (const struct mtk_pin_desc *)&hw->soc->pins[grp->pin]; 78262306a36Sopenharmony_ci mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_MODE, desc_func->muxval); 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci return 0; 78562306a36Sopenharmony_ci} 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_cistatic const struct pinmux_ops mtk_pmxops = { 78862306a36Sopenharmony_ci .get_functions_count = mtk_pmx_get_funcs_cnt, 78962306a36Sopenharmony_ci .get_function_name = mtk_pmx_get_func_name, 79062306a36Sopenharmony_ci .get_function_groups = mtk_pmx_get_func_groups, 79162306a36Sopenharmony_ci .set_mux = mtk_pmx_set_mux, 79262306a36Sopenharmony_ci .gpio_set_direction = mtk_pinmux_gpio_set_direction, 79362306a36Sopenharmony_ci .gpio_request_enable = mtk_pinmux_gpio_request_enable, 79462306a36Sopenharmony_ci}; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_cistatic int mtk_pconf_group_get(struct pinctrl_dev *pctldev, unsigned group, 79762306a36Sopenharmony_ci unsigned long *config) 79862306a36Sopenharmony_ci{ 79962306a36Sopenharmony_ci struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 80062306a36Sopenharmony_ci struct mtk_pinctrl_group *grp = &hw->groups[group]; 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci /* One pin per group only */ 80362306a36Sopenharmony_ci return mtk_pinconf_get(pctldev, grp->pin, config); 80462306a36Sopenharmony_ci} 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_cistatic int mtk_pconf_group_set(struct pinctrl_dev *pctldev, unsigned group, 80762306a36Sopenharmony_ci unsigned long *configs, unsigned num_configs) 80862306a36Sopenharmony_ci{ 80962306a36Sopenharmony_ci struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 81062306a36Sopenharmony_ci struct mtk_pinctrl_group *grp = &hw->groups[group]; 81162306a36Sopenharmony_ci bool drive_strength_uA_found = false; 81262306a36Sopenharmony_ci bool adv_drve_strength_found = false; 81362306a36Sopenharmony_ci int i, ret; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci for (i = 0; i < num_configs; i++) { 81662306a36Sopenharmony_ci ret = mtk_pinconf_set(pctldev, grp->pin, 81762306a36Sopenharmony_ci pinconf_to_config_param(configs[i]), 81862306a36Sopenharmony_ci pinconf_to_config_argument(configs[i])); 81962306a36Sopenharmony_ci if (ret < 0) 82062306a36Sopenharmony_ci return ret; 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci if (pinconf_to_config_param(configs[i]) == PIN_CONFIG_DRIVE_STRENGTH_UA) 82362306a36Sopenharmony_ci drive_strength_uA_found = true; 82462306a36Sopenharmony_ci if (pinconf_to_config_param(configs[i]) == MTK_PIN_CONFIG_DRV_ADV) 82562306a36Sopenharmony_ci adv_drve_strength_found = true; 82662306a36Sopenharmony_ci } 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci /* 82962306a36Sopenharmony_ci * Disable advanced drive strength mode if drive-strength-microamp 83062306a36Sopenharmony_ci * is not set. However, mediatek,drive-strength-adv takes precedence 83162306a36Sopenharmony_ci * as its value can explicitly request the mode be enabled or not. 83262306a36Sopenharmony_ci */ 83362306a36Sopenharmony_ci if (hw->soc->adv_drive_set && !drive_strength_uA_found && 83462306a36Sopenharmony_ci !adv_drve_strength_found) 83562306a36Sopenharmony_ci hw->soc->adv_drive_set(hw, &hw->soc->pins[grp->pin], 0); 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci return 0; 83862306a36Sopenharmony_ci} 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_cistatic const struct pinconf_ops mtk_confops = { 84162306a36Sopenharmony_ci .pin_config_get = mtk_pinconf_get, 84262306a36Sopenharmony_ci .pin_config_group_get = mtk_pconf_group_get, 84362306a36Sopenharmony_ci .pin_config_group_set = mtk_pconf_group_set, 84462306a36Sopenharmony_ci .is_generic = true, 84562306a36Sopenharmony_ci}; 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_cistatic struct pinctrl_desc mtk_desc = { 84862306a36Sopenharmony_ci .name = PINCTRL_PINCTRL_DEV, 84962306a36Sopenharmony_ci .pctlops = &mtk_pctlops, 85062306a36Sopenharmony_ci .pmxops = &mtk_pmxops, 85162306a36Sopenharmony_ci .confops = &mtk_confops, 85262306a36Sopenharmony_ci .owner = THIS_MODULE, 85362306a36Sopenharmony_ci}; 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_cistatic int mtk_gpio_get_direction(struct gpio_chip *chip, unsigned int gpio) 85662306a36Sopenharmony_ci{ 85762306a36Sopenharmony_ci struct mtk_pinctrl *hw = gpiochip_get_data(chip); 85862306a36Sopenharmony_ci const struct mtk_pin_desc *desc; 85962306a36Sopenharmony_ci int value, err; 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci if (gpio >= hw->soc->npins) 86262306a36Sopenharmony_ci return -EINVAL; 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci /* 86562306a36Sopenharmony_ci * "Virtual" GPIOs are always and only used for interrupts 86662306a36Sopenharmony_ci * Since they are only used for interrupts, they are always inputs 86762306a36Sopenharmony_ci */ 86862306a36Sopenharmony_ci if (mtk_is_virt_gpio(hw, gpio)) 86962306a36Sopenharmony_ci return 1; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio]; 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DIR, &value); 87462306a36Sopenharmony_ci if (err) 87562306a36Sopenharmony_ci return err; 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci if (value) 87862306a36Sopenharmony_ci return GPIO_LINE_DIRECTION_OUT; 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci return GPIO_LINE_DIRECTION_IN; 88162306a36Sopenharmony_ci} 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_cistatic int mtk_gpio_get(struct gpio_chip *chip, unsigned int gpio) 88462306a36Sopenharmony_ci{ 88562306a36Sopenharmony_ci struct mtk_pinctrl *hw = gpiochip_get_data(chip); 88662306a36Sopenharmony_ci const struct mtk_pin_desc *desc; 88762306a36Sopenharmony_ci int value, err; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci if (gpio >= hw->soc->npins) 89062306a36Sopenharmony_ci return -EINVAL; 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio]; 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DI, &value); 89562306a36Sopenharmony_ci if (err) 89662306a36Sopenharmony_ci return err; 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci return !!value; 89962306a36Sopenharmony_ci} 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_cistatic void mtk_gpio_set(struct gpio_chip *chip, unsigned int gpio, int value) 90262306a36Sopenharmony_ci{ 90362306a36Sopenharmony_ci struct mtk_pinctrl *hw = gpiochip_get_data(chip); 90462306a36Sopenharmony_ci const struct mtk_pin_desc *desc; 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci if (gpio >= hw->soc->npins) 90762306a36Sopenharmony_ci return; 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio]; 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DO, !!value); 91262306a36Sopenharmony_ci} 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_cistatic int mtk_gpio_direction_input(struct gpio_chip *chip, unsigned int gpio) 91562306a36Sopenharmony_ci{ 91662306a36Sopenharmony_ci struct mtk_pinctrl *hw = gpiochip_get_data(chip); 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci if (gpio >= hw->soc->npins) 91962306a36Sopenharmony_ci return -EINVAL; 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci return pinctrl_gpio_direction_input(chip->base + gpio); 92262306a36Sopenharmony_ci} 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_cistatic int mtk_gpio_direction_output(struct gpio_chip *chip, unsigned int gpio, 92562306a36Sopenharmony_ci int value) 92662306a36Sopenharmony_ci{ 92762306a36Sopenharmony_ci struct mtk_pinctrl *hw = gpiochip_get_data(chip); 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci if (gpio >= hw->soc->npins) 93062306a36Sopenharmony_ci return -EINVAL; 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci mtk_gpio_set(chip, gpio, value); 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci return pinctrl_gpio_direction_output(chip->base + gpio); 93562306a36Sopenharmony_ci} 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_cistatic int mtk_gpio_to_irq(struct gpio_chip *chip, unsigned int offset) 93862306a36Sopenharmony_ci{ 93962306a36Sopenharmony_ci struct mtk_pinctrl *hw = gpiochip_get_data(chip); 94062306a36Sopenharmony_ci const struct mtk_pin_desc *desc; 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci if (!hw->eint) 94362306a36Sopenharmony_ci return -ENOTSUPP; 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci desc = (const struct mtk_pin_desc *)&hw->soc->pins[offset]; 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci if (desc->eint.eint_n == EINT_NA) 94862306a36Sopenharmony_ci return -ENOTSUPP; 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci return mtk_eint_find_irq(hw->eint, desc->eint.eint_n); 95162306a36Sopenharmony_ci} 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_cistatic int mtk_gpio_set_config(struct gpio_chip *chip, unsigned int offset, 95462306a36Sopenharmony_ci unsigned long config) 95562306a36Sopenharmony_ci{ 95662306a36Sopenharmony_ci struct mtk_pinctrl *hw = gpiochip_get_data(chip); 95762306a36Sopenharmony_ci const struct mtk_pin_desc *desc; 95862306a36Sopenharmony_ci u32 debounce; 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci desc = (const struct mtk_pin_desc *)&hw->soc->pins[offset]; 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci if (!hw->eint || 96362306a36Sopenharmony_ci pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE || 96462306a36Sopenharmony_ci desc->eint.eint_n == EINT_NA) 96562306a36Sopenharmony_ci return -ENOTSUPP; 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci debounce = pinconf_to_config_argument(config); 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci return mtk_eint_set_debounce(hw->eint, desc->eint.eint_n, debounce); 97062306a36Sopenharmony_ci} 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_cistatic int mtk_build_gpiochip(struct mtk_pinctrl *hw) 97362306a36Sopenharmony_ci{ 97462306a36Sopenharmony_ci struct gpio_chip *chip = &hw->chip; 97562306a36Sopenharmony_ci int ret; 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci chip->label = PINCTRL_PINCTRL_DEV; 97862306a36Sopenharmony_ci chip->parent = hw->dev; 97962306a36Sopenharmony_ci chip->request = gpiochip_generic_request; 98062306a36Sopenharmony_ci chip->free = gpiochip_generic_free; 98162306a36Sopenharmony_ci chip->get_direction = mtk_gpio_get_direction; 98262306a36Sopenharmony_ci chip->direction_input = mtk_gpio_direction_input; 98362306a36Sopenharmony_ci chip->direction_output = mtk_gpio_direction_output; 98462306a36Sopenharmony_ci chip->get = mtk_gpio_get; 98562306a36Sopenharmony_ci chip->set = mtk_gpio_set; 98662306a36Sopenharmony_ci chip->to_irq = mtk_gpio_to_irq; 98762306a36Sopenharmony_ci chip->set_config = mtk_gpio_set_config; 98862306a36Sopenharmony_ci chip->base = -1; 98962306a36Sopenharmony_ci chip->ngpio = hw->soc->npins; 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci ret = gpiochip_add_data(chip, hw); 99262306a36Sopenharmony_ci if (ret < 0) 99362306a36Sopenharmony_ci return ret; 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci return 0; 99662306a36Sopenharmony_ci} 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_cistatic int mtk_pctrl_build_state(struct platform_device *pdev) 99962306a36Sopenharmony_ci{ 100062306a36Sopenharmony_ci struct mtk_pinctrl *hw = platform_get_drvdata(pdev); 100162306a36Sopenharmony_ci int i; 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci /* Allocate groups */ 100462306a36Sopenharmony_ci hw->groups = devm_kmalloc_array(&pdev->dev, hw->soc->ngrps, 100562306a36Sopenharmony_ci sizeof(*hw->groups), GFP_KERNEL); 100662306a36Sopenharmony_ci if (!hw->groups) 100762306a36Sopenharmony_ci return -ENOMEM; 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci /* We assume that one pin is one group, use pin name as group name. */ 101062306a36Sopenharmony_ci hw->grp_names = devm_kmalloc_array(&pdev->dev, hw->soc->ngrps, 101162306a36Sopenharmony_ci sizeof(*hw->grp_names), GFP_KERNEL); 101262306a36Sopenharmony_ci if (!hw->grp_names) 101362306a36Sopenharmony_ci return -ENOMEM; 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci for (i = 0; i < hw->soc->npins; i++) { 101662306a36Sopenharmony_ci const struct mtk_pin_desc *pin = hw->soc->pins + i; 101762306a36Sopenharmony_ci struct mtk_pinctrl_group *group = hw->groups + i; 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci group->name = pin->name; 102062306a36Sopenharmony_ci group->pin = pin->number; 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci hw->grp_names[i] = pin->name; 102362306a36Sopenharmony_ci } 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci return 0; 102662306a36Sopenharmony_ci} 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ciint mtk_paris_pinctrl_probe(struct platform_device *pdev) 102962306a36Sopenharmony_ci{ 103062306a36Sopenharmony_ci struct device *dev = &pdev->dev; 103162306a36Sopenharmony_ci struct pinctrl_pin_desc *pins; 103262306a36Sopenharmony_ci struct mtk_pinctrl *hw; 103362306a36Sopenharmony_ci int err, i; 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci hw = devm_kzalloc(&pdev->dev, sizeof(*hw), GFP_KERNEL); 103662306a36Sopenharmony_ci if (!hw) 103762306a36Sopenharmony_ci return -ENOMEM; 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci platform_set_drvdata(pdev, hw); 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci hw->soc = device_get_match_data(dev); 104262306a36Sopenharmony_ci if (!hw->soc) 104362306a36Sopenharmony_ci return -ENOENT; 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci hw->dev = &pdev->dev; 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci if (!hw->soc->nbase_names) 104862306a36Sopenharmony_ci return dev_err_probe(dev, -EINVAL, 104962306a36Sopenharmony_ci "SoC should be assigned at least one register base\n"); 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci hw->base = devm_kmalloc_array(&pdev->dev, hw->soc->nbase_names, 105262306a36Sopenharmony_ci sizeof(*hw->base), GFP_KERNEL); 105362306a36Sopenharmony_ci if (!hw->base) 105462306a36Sopenharmony_ci return -ENOMEM; 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci for (i = 0; i < hw->soc->nbase_names; i++) { 105762306a36Sopenharmony_ci hw->base[i] = devm_platform_ioremap_resource_byname(pdev, 105862306a36Sopenharmony_ci hw->soc->base_names[i]); 105962306a36Sopenharmony_ci if (IS_ERR(hw->base[i])) 106062306a36Sopenharmony_ci return PTR_ERR(hw->base[i]); 106162306a36Sopenharmony_ci } 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci hw->nbase = hw->soc->nbase_names; 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci if (of_find_property(hw->dev->of_node, 106662306a36Sopenharmony_ci "mediatek,rsel-resistance-in-si-unit", NULL)) 106762306a36Sopenharmony_ci hw->rsel_si_unit = true; 106862306a36Sopenharmony_ci else 106962306a36Sopenharmony_ci hw->rsel_si_unit = false; 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci spin_lock_init(&hw->lock); 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci err = mtk_pctrl_build_state(pdev); 107462306a36Sopenharmony_ci if (err) 107562306a36Sopenharmony_ci return dev_err_probe(dev, err, "build state failed\n"); 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci /* Copy from internal struct mtk_pin_desc to register to the core */ 107862306a36Sopenharmony_ci pins = devm_kmalloc_array(&pdev->dev, hw->soc->npins, sizeof(*pins), 107962306a36Sopenharmony_ci GFP_KERNEL); 108062306a36Sopenharmony_ci if (!pins) 108162306a36Sopenharmony_ci return -ENOMEM; 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci for (i = 0; i < hw->soc->npins; i++) { 108462306a36Sopenharmony_ci pins[i].number = hw->soc->pins[i].number; 108562306a36Sopenharmony_ci pins[i].name = hw->soc->pins[i].name; 108662306a36Sopenharmony_ci } 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci /* Setup pins descriptions per SoC types */ 108962306a36Sopenharmony_ci mtk_desc.pins = (const struct pinctrl_pin_desc *)pins; 109062306a36Sopenharmony_ci mtk_desc.npins = hw->soc->npins; 109162306a36Sopenharmony_ci mtk_desc.num_custom_params = ARRAY_SIZE(mtk_custom_bindings); 109262306a36Sopenharmony_ci mtk_desc.custom_params = mtk_custom_bindings; 109362306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 109462306a36Sopenharmony_ci mtk_desc.custom_conf_items = mtk_conf_items; 109562306a36Sopenharmony_ci#endif 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci err = devm_pinctrl_register_and_init(&pdev->dev, &mtk_desc, hw, 109862306a36Sopenharmony_ci &hw->pctrl); 109962306a36Sopenharmony_ci if (err) 110062306a36Sopenharmony_ci return err; 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci err = pinctrl_enable(hw->pctrl); 110362306a36Sopenharmony_ci if (err) 110462306a36Sopenharmony_ci return err; 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci err = mtk_build_eint(hw, pdev); 110762306a36Sopenharmony_ci if (err) 110862306a36Sopenharmony_ci dev_warn(&pdev->dev, 110962306a36Sopenharmony_ci "Failed to add EINT, but pinctrl still can work\n"); 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci /* Build gpiochip should be after pinctrl_enable is done */ 111262306a36Sopenharmony_ci err = mtk_build_gpiochip(hw); 111362306a36Sopenharmony_ci if (err) 111462306a36Sopenharmony_ci return dev_err_probe(dev, err, "Failed to add gpio_chip\n"); 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci platform_set_drvdata(pdev, hw); 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci return 0; 111962306a36Sopenharmony_ci} 112062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_paris_pinctrl_probe); 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_cistatic int mtk_paris_pinctrl_suspend(struct device *device) 112362306a36Sopenharmony_ci{ 112462306a36Sopenharmony_ci struct mtk_pinctrl *pctl = dev_get_drvdata(device); 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci return mtk_eint_do_suspend(pctl->eint); 112762306a36Sopenharmony_ci} 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_cistatic int mtk_paris_pinctrl_resume(struct device *device) 113062306a36Sopenharmony_ci{ 113162306a36Sopenharmony_ci struct mtk_pinctrl *pctl = dev_get_drvdata(device); 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci return mtk_eint_do_resume(pctl->eint); 113462306a36Sopenharmony_ci} 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ciconst struct dev_pm_ops mtk_paris_pinctrl_pm_ops = { 113762306a36Sopenharmony_ci .suspend_noirq = mtk_paris_pinctrl_suspend, 113862306a36Sopenharmony_ci .resume_noirq = mtk_paris_pinctrl_resume, 113962306a36Sopenharmony_ci}; 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 114262306a36Sopenharmony_ciMODULE_DESCRIPTION("MediaTek Pinctrl Common Driver V2 Paris"); 1143