162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * MediaTek Pinctrl Moore Driver, which implement the generic dt-binding 462306a36Sopenharmony_ci * pinctrl-bindings.txt for MediaTek SoC. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2017-2018 MediaTek Inc. 762306a36Sopenharmony_ci * Author: Sean Wang <sean.wang@mediatek.com> 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <dt-bindings/pinctrl/mt65xx.h> 1262306a36Sopenharmony_ci#include <linux/gpio/driver.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <linux/pinctrl/consumer.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include "pinctrl-moore.h" 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#define PINCTRL_PINCTRL_DEV KBUILD_MODNAME 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci/* Custom pinconf parameters */ 2162306a36Sopenharmony_ci#define MTK_PIN_CONFIG_TDSEL (PIN_CONFIG_END + 1) 2262306a36Sopenharmony_ci#define MTK_PIN_CONFIG_RDSEL (PIN_CONFIG_END + 2) 2362306a36Sopenharmony_ci#define MTK_PIN_CONFIG_PU_ADV (PIN_CONFIG_END + 3) 2462306a36Sopenharmony_ci#define MTK_PIN_CONFIG_PD_ADV (PIN_CONFIG_END + 4) 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic const struct pinconf_generic_params mtk_custom_bindings[] = { 2762306a36Sopenharmony_ci {"mediatek,tdsel", MTK_PIN_CONFIG_TDSEL, 0}, 2862306a36Sopenharmony_ci {"mediatek,rdsel", MTK_PIN_CONFIG_RDSEL, 0}, 2962306a36Sopenharmony_ci {"mediatek,pull-up-adv", MTK_PIN_CONFIG_PU_ADV, 1}, 3062306a36Sopenharmony_ci {"mediatek,pull-down-adv", MTK_PIN_CONFIG_PD_ADV, 1}, 3162306a36Sopenharmony_ci}; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 3462306a36Sopenharmony_cistatic const struct pin_config_item mtk_conf_items[] = { 3562306a36Sopenharmony_ci PCONFDUMP(MTK_PIN_CONFIG_TDSEL, "tdsel", NULL, true), 3662306a36Sopenharmony_ci PCONFDUMP(MTK_PIN_CONFIG_RDSEL, "rdsel", NULL, true), 3762306a36Sopenharmony_ci PCONFDUMP(MTK_PIN_CONFIG_PU_ADV, "pu-adv", NULL, true), 3862306a36Sopenharmony_ci PCONFDUMP(MTK_PIN_CONFIG_PD_ADV, "pd-adv", NULL, true), 3962306a36Sopenharmony_ci}; 4062306a36Sopenharmony_ci#endif 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistatic int mtk_pinmux_set_mux(struct pinctrl_dev *pctldev, 4362306a36Sopenharmony_ci unsigned int selector, unsigned int group) 4462306a36Sopenharmony_ci{ 4562306a36Sopenharmony_ci struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 4662306a36Sopenharmony_ci struct function_desc *func; 4762306a36Sopenharmony_ci struct group_desc *grp; 4862306a36Sopenharmony_ci int i; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci func = pinmux_generic_get_function(pctldev, selector); 5162306a36Sopenharmony_ci if (!func) 5262306a36Sopenharmony_ci return -EINVAL; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci grp = pinctrl_generic_get_group(pctldev, group); 5562306a36Sopenharmony_ci if (!grp) 5662306a36Sopenharmony_ci return -EINVAL; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci dev_dbg(pctldev->dev, "enable function %s group %s\n", 5962306a36Sopenharmony_ci func->name, grp->name); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci for (i = 0; i < grp->num_pins; i++) { 6262306a36Sopenharmony_ci const struct mtk_pin_desc *desc; 6362306a36Sopenharmony_ci int *pin_modes = grp->data; 6462306a36Sopenharmony_ci int pin = grp->pins[i]; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; 6762306a36Sopenharmony_ci if (!desc->name) 6862306a36Sopenharmony_ci return -ENOTSUPP; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_MODE, 7162306a36Sopenharmony_ci pin_modes[i]); 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci return 0; 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic int mtk_pinmux_gpio_request_enable(struct pinctrl_dev *pctldev, 7862306a36Sopenharmony_ci struct pinctrl_gpio_range *range, 7962306a36Sopenharmony_ci unsigned int pin) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 8262306a36Sopenharmony_ci const struct mtk_pin_desc *desc; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; 8562306a36Sopenharmony_ci if (!desc->name) 8662306a36Sopenharmony_ci return -ENOTSUPP; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci return mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_MODE, 8962306a36Sopenharmony_ci hw->soc->gpio_m); 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic int mtk_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev, 9362306a36Sopenharmony_ci struct pinctrl_gpio_range *range, 9462306a36Sopenharmony_ci unsigned int pin, bool input) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 9762306a36Sopenharmony_ci const struct mtk_pin_desc *desc; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; 10062306a36Sopenharmony_ci if (!desc->name) 10162306a36Sopenharmony_ci return -ENOTSUPP; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci /* hardware would take 0 as input direction */ 10462306a36Sopenharmony_ci return mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR, !input); 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cistatic int mtk_pinconf_get(struct pinctrl_dev *pctldev, 10862306a36Sopenharmony_ci unsigned int pin, unsigned long *config) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 11162306a36Sopenharmony_ci u32 param = pinconf_to_config_param(*config); 11262306a36Sopenharmony_ci int val, val2, err, pullup, reg, ret = 1; 11362306a36Sopenharmony_ci const struct mtk_pin_desc *desc; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; 11662306a36Sopenharmony_ci if (!desc->name) 11762306a36Sopenharmony_ci return -ENOTSUPP; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci switch (param) { 12062306a36Sopenharmony_ci case PIN_CONFIG_BIAS_DISABLE: 12162306a36Sopenharmony_ci if (hw->soc->bias_get_combo) { 12262306a36Sopenharmony_ci err = hw->soc->bias_get_combo(hw, desc, &pullup, &ret); 12362306a36Sopenharmony_ci if (err) 12462306a36Sopenharmony_ci return err; 12562306a36Sopenharmony_ci if (ret != MTK_PUPD_SET_R1R0_00 && ret != MTK_DISABLE) 12662306a36Sopenharmony_ci return -EINVAL; 12762306a36Sopenharmony_ci } else if (hw->soc->bias_disable_get) { 12862306a36Sopenharmony_ci err = hw->soc->bias_disable_get(hw, desc, &ret); 12962306a36Sopenharmony_ci if (err) 13062306a36Sopenharmony_ci return err; 13162306a36Sopenharmony_ci } else { 13262306a36Sopenharmony_ci return -ENOTSUPP; 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci break; 13562306a36Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_UP: 13662306a36Sopenharmony_ci if (hw->soc->bias_get_combo) { 13762306a36Sopenharmony_ci err = hw->soc->bias_get_combo(hw, desc, &pullup, &ret); 13862306a36Sopenharmony_ci if (err) 13962306a36Sopenharmony_ci return err; 14062306a36Sopenharmony_ci if (ret == MTK_PUPD_SET_R1R0_00 || ret == MTK_DISABLE) 14162306a36Sopenharmony_ci return -EINVAL; 14262306a36Sopenharmony_ci if (!pullup) 14362306a36Sopenharmony_ci return -EINVAL; 14462306a36Sopenharmony_ci } else if (hw->soc->bias_get) { 14562306a36Sopenharmony_ci err = hw->soc->bias_get(hw, desc, 1, &ret); 14662306a36Sopenharmony_ci if (err) 14762306a36Sopenharmony_ci return err; 14862306a36Sopenharmony_ci } else { 14962306a36Sopenharmony_ci return -ENOTSUPP; 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci break; 15262306a36Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_DOWN: 15362306a36Sopenharmony_ci if (hw->soc->bias_get_combo) { 15462306a36Sopenharmony_ci err = hw->soc->bias_get_combo(hw, desc, &pullup, &ret); 15562306a36Sopenharmony_ci if (err) 15662306a36Sopenharmony_ci return err; 15762306a36Sopenharmony_ci if (ret == MTK_PUPD_SET_R1R0_00 || ret == MTK_DISABLE) 15862306a36Sopenharmony_ci return -EINVAL; 15962306a36Sopenharmony_ci if (pullup) 16062306a36Sopenharmony_ci return -EINVAL; 16162306a36Sopenharmony_ci } else if (hw->soc->bias_get) { 16262306a36Sopenharmony_ci err = hw->soc->bias_get(hw, desc, 0, &ret); 16362306a36Sopenharmony_ci if (err) 16462306a36Sopenharmony_ci return err; 16562306a36Sopenharmony_ci } else { 16662306a36Sopenharmony_ci return -ENOTSUPP; 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci break; 16962306a36Sopenharmony_ci case PIN_CONFIG_SLEW_RATE: 17062306a36Sopenharmony_ci err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_SR, &val); 17162306a36Sopenharmony_ci if (err) 17262306a36Sopenharmony_ci return err; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci if (!val) 17562306a36Sopenharmony_ci return -EINVAL; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci break; 17862306a36Sopenharmony_ci case PIN_CONFIG_INPUT_ENABLE: 17962306a36Sopenharmony_ci case PIN_CONFIG_OUTPUT_ENABLE: 18062306a36Sopenharmony_ci err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DIR, &val); 18162306a36Sopenharmony_ci if (err) 18262306a36Sopenharmony_ci return err; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci /* HW takes input mode as zero; output mode as non-zero */ 18562306a36Sopenharmony_ci if ((val && param == PIN_CONFIG_INPUT_ENABLE) || 18662306a36Sopenharmony_ci (!val && param == PIN_CONFIG_OUTPUT_ENABLE)) 18762306a36Sopenharmony_ci return -EINVAL; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci break; 19062306a36Sopenharmony_ci case PIN_CONFIG_INPUT_SCHMITT_ENABLE: 19162306a36Sopenharmony_ci err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DIR, &val); 19262306a36Sopenharmony_ci if (err) 19362306a36Sopenharmony_ci return err; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_SMT, &val2); 19662306a36Sopenharmony_ci if (err) 19762306a36Sopenharmony_ci return err; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci if (val || !val2) 20062306a36Sopenharmony_ci return -EINVAL; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci break; 20362306a36Sopenharmony_ci case PIN_CONFIG_DRIVE_STRENGTH: 20462306a36Sopenharmony_ci if (hw->soc->drive_get) { 20562306a36Sopenharmony_ci err = hw->soc->drive_get(hw, desc, &ret); 20662306a36Sopenharmony_ci if (err) 20762306a36Sopenharmony_ci return err; 20862306a36Sopenharmony_ci } else { 20962306a36Sopenharmony_ci err = -ENOTSUPP; 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci break; 21262306a36Sopenharmony_ci case MTK_PIN_CONFIG_TDSEL: 21362306a36Sopenharmony_ci case MTK_PIN_CONFIG_RDSEL: 21462306a36Sopenharmony_ci reg = (param == MTK_PIN_CONFIG_TDSEL) ? 21562306a36Sopenharmony_ci PINCTRL_PIN_REG_TDSEL : PINCTRL_PIN_REG_RDSEL; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci err = mtk_hw_get_value(hw, desc, reg, &val); 21862306a36Sopenharmony_ci if (err) 21962306a36Sopenharmony_ci return err; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci ret = val; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci break; 22462306a36Sopenharmony_ci case MTK_PIN_CONFIG_PU_ADV: 22562306a36Sopenharmony_ci case MTK_PIN_CONFIG_PD_ADV: 22662306a36Sopenharmony_ci if (hw->soc->adv_pull_get) { 22762306a36Sopenharmony_ci bool pullup; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci pullup = param == MTK_PIN_CONFIG_PU_ADV; 23062306a36Sopenharmony_ci err = hw->soc->adv_pull_get(hw, desc, pullup, &ret); 23162306a36Sopenharmony_ci if (err) 23262306a36Sopenharmony_ci return err; 23362306a36Sopenharmony_ci } else { 23462306a36Sopenharmony_ci return -ENOTSUPP; 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci break; 23762306a36Sopenharmony_ci default: 23862306a36Sopenharmony_ci return -ENOTSUPP; 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci *config = pinconf_to_config_packed(param, ret); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci return 0; 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cistatic int mtk_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, 24762306a36Sopenharmony_ci unsigned long *configs, unsigned int num_configs) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 25062306a36Sopenharmony_ci const struct mtk_pin_desc *desc; 25162306a36Sopenharmony_ci u32 reg, param, arg; 25262306a36Sopenharmony_ci int cfg, err = 0; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; 25562306a36Sopenharmony_ci if (!desc->name) 25662306a36Sopenharmony_ci return -ENOTSUPP; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci for (cfg = 0; cfg < num_configs; cfg++) { 25962306a36Sopenharmony_ci param = pinconf_to_config_param(configs[cfg]); 26062306a36Sopenharmony_ci arg = pinconf_to_config_argument(configs[cfg]); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci switch (param) { 26362306a36Sopenharmony_ci case PIN_CONFIG_BIAS_DISABLE: 26462306a36Sopenharmony_ci if (hw->soc->bias_set_combo) { 26562306a36Sopenharmony_ci err = hw->soc->bias_set_combo(hw, desc, 0, MTK_DISABLE); 26662306a36Sopenharmony_ci if (err) 26762306a36Sopenharmony_ci return err; 26862306a36Sopenharmony_ci } else if (hw->soc->bias_disable_set) { 26962306a36Sopenharmony_ci err = hw->soc->bias_disable_set(hw, desc); 27062306a36Sopenharmony_ci if (err) 27162306a36Sopenharmony_ci return err; 27262306a36Sopenharmony_ci } else { 27362306a36Sopenharmony_ci return -ENOTSUPP; 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci break; 27662306a36Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_UP: 27762306a36Sopenharmony_ci if (hw->soc->bias_set_combo) { 27862306a36Sopenharmony_ci err = hw->soc->bias_set_combo(hw, desc, 1, arg); 27962306a36Sopenharmony_ci if (err) 28062306a36Sopenharmony_ci return err; 28162306a36Sopenharmony_ci } else if (hw->soc->bias_set) { 28262306a36Sopenharmony_ci err = hw->soc->bias_set(hw, desc, 1); 28362306a36Sopenharmony_ci if (err) 28462306a36Sopenharmony_ci return err; 28562306a36Sopenharmony_ci } else { 28662306a36Sopenharmony_ci return -ENOTSUPP; 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci break; 28962306a36Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_DOWN: 29062306a36Sopenharmony_ci if (hw->soc->bias_set_combo) { 29162306a36Sopenharmony_ci err = hw->soc->bias_set_combo(hw, desc, 0, arg); 29262306a36Sopenharmony_ci if (err) 29362306a36Sopenharmony_ci return err; 29462306a36Sopenharmony_ci } else if (hw->soc->bias_set) { 29562306a36Sopenharmony_ci err = hw->soc->bias_set(hw, desc, 0); 29662306a36Sopenharmony_ci if (err) 29762306a36Sopenharmony_ci return err; 29862306a36Sopenharmony_ci } else { 29962306a36Sopenharmony_ci return -ENOTSUPP; 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci break; 30262306a36Sopenharmony_ci case PIN_CONFIG_OUTPUT_ENABLE: 30362306a36Sopenharmony_ci err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_SMT, 30462306a36Sopenharmony_ci MTK_DISABLE); 30562306a36Sopenharmony_ci if (err) 30662306a36Sopenharmony_ci goto err; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR, 30962306a36Sopenharmony_ci MTK_OUTPUT); 31062306a36Sopenharmony_ci if (err) 31162306a36Sopenharmony_ci goto err; 31262306a36Sopenharmony_ci break; 31362306a36Sopenharmony_ci case PIN_CONFIG_INPUT_ENABLE: 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci if (hw->soc->ies_present) { 31662306a36Sopenharmony_ci mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_IES, 31762306a36Sopenharmony_ci MTK_ENABLE); 31862306a36Sopenharmony_ci } 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR, 32162306a36Sopenharmony_ci MTK_INPUT); 32262306a36Sopenharmony_ci if (err) 32362306a36Sopenharmony_ci goto err; 32462306a36Sopenharmony_ci break; 32562306a36Sopenharmony_ci case PIN_CONFIG_SLEW_RATE: 32662306a36Sopenharmony_ci err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_SR, 32762306a36Sopenharmony_ci arg); 32862306a36Sopenharmony_ci if (err) 32962306a36Sopenharmony_ci goto err; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci break; 33262306a36Sopenharmony_ci case PIN_CONFIG_OUTPUT: 33362306a36Sopenharmony_ci err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR, 33462306a36Sopenharmony_ci MTK_OUTPUT); 33562306a36Sopenharmony_ci if (err) 33662306a36Sopenharmony_ci goto err; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DO, 33962306a36Sopenharmony_ci arg); 34062306a36Sopenharmony_ci if (err) 34162306a36Sopenharmony_ci goto err; 34262306a36Sopenharmony_ci break; 34362306a36Sopenharmony_ci case PIN_CONFIG_INPUT_SCHMITT_ENABLE: 34462306a36Sopenharmony_ci /* arg = 1: Input mode & SMT enable ; 34562306a36Sopenharmony_ci * arg = 0: Output mode & SMT disable 34662306a36Sopenharmony_ci */ 34762306a36Sopenharmony_ci arg = arg ? 2 : 1; 34862306a36Sopenharmony_ci err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR, 34962306a36Sopenharmony_ci arg & 1); 35062306a36Sopenharmony_ci if (err) 35162306a36Sopenharmony_ci goto err; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_SMT, 35462306a36Sopenharmony_ci !!(arg & 2)); 35562306a36Sopenharmony_ci if (err) 35662306a36Sopenharmony_ci goto err; 35762306a36Sopenharmony_ci break; 35862306a36Sopenharmony_ci case PIN_CONFIG_DRIVE_STRENGTH: 35962306a36Sopenharmony_ci if (hw->soc->drive_set) { 36062306a36Sopenharmony_ci err = hw->soc->drive_set(hw, desc, arg); 36162306a36Sopenharmony_ci if (err) 36262306a36Sopenharmony_ci return err; 36362306a36Sopenharmony_ci } else { 36462306a36Sopenharmony_ci err = -ENOTSUPP; 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci break; 36762306a36Sopenharmony_ci case MTK_PIN_CONFIG_TDSEL: 36862306a36Sopenharmony_ci case MTK_PIN_CONFIG_RDSEL: 36962306a36Sopenharmony_ci reg = (param == MTK_PIN_CONFIG_TDSEL) ? 37062306a36Sopenharmony_ci PINCTRL_PIN_REG_TDSEL : PINCTRL_PIN_REG_RDSEL; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci err = mtk_hw_set_value(hw, desc, reg, arg); 37362306a36Sopenharmony_ci if (err) 37462306a36Sopenharmony_ci goto err; 37562306a36Sopenharmony_ci break; 37662306a36Sopenharmony_ci case MTK_PIN_CONFIG_PU_ADV: 37762306a36Sopenharmony_ci case MTK_PIN_CONFIG_PD_ADV: 37862306a36Sopenharmony_ci if (hw->soc->adv_pull_set) { 37962306a36Sopenharmony_ci bool pullup; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci pullup = param == MTK_PIN_CONFIG_PU_ADV; 38262306a36Sopenharmony_ci err = hw->soc->adv_pull_set(hw, desc, pullup, 38362306a36Sopenharmony_ci arg); 38462306a36Sopenharmony_ci if (err) 38562306a36Sopenharmony_ci return err; 38662306a36Sopenharmony_ci } else { 38762306a36Sopenharmony_ci return -ENOTSUPP; 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci break; 39062306a36Sopenharmony_ci default: 39162306a36Sopenharmony_ci err = -ENOTSUPP; 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_cierr: 39562306a36Sopenharmony_ci return err; 39662306a36Sopenharmony_ci} 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_cistatic int mtk_pinconf_group_get(struct pinctrl_dev *pctldev, 39962306a36Sopenharmony_ci unsigned int group, unsigned long *config) 40062306a36Sopenharmony_ci{ 40162306a36Sopenharmony_ci const unsigned int *pins; 40262306a36Sopenharmony_ci unsigned int i, npins, old = 0; 40362306a36Sopenharmony_ci int ret; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci ret = pinctrl_generic_get_group_pins(pctldev, group, &pins, &npins); 40662306a36Sopenharmony_ci if (ret) 40762306a36Sopenharmony_ci return ret; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci for (i = 0; i < npins; i++) { 41062306a36Sopenharmony_ci if (mtk_pinconf_get(pctldev, pins[i], config)) 41162306a36Sopenharmony_ci return -ENOTSUPP; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci /* configs do not match between two pins */ 41462306a36Sopenharmony_ci if (i && old != *config) 41562306a36Sopenharmony_ci return -ENOTSUPP; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci old = *config; 41862306a36Sopenharmony_ci } 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci return 0; 42162306a36Sopenharmony_ci} 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_cistatic int mtk_pinconf_group_set(struct pinctrl_dev *pctldev, 42462306a36Sopenharmony_ci unsigned int group, unsigned long *configs, 42562306a36Sopenharmony_ci unsigned int num_configs) 42662306a36Sopenharmony_ci{ 42762306a36Sopenharmony_ci const unsigned int *pins; 42862306a36Sopenharmony_ci unsigned int i, npins; 42962306a36Sopenharmony_ci int ret; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci ret = pinctrl_generic_get_group_pins(pctldev, group, &pins, &npins); 43262306a36Sopenharmony_ci if (ret) 43362306a36Sopenharmony_ci return ret; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci for (i = 0; i < npins; i++) { 43662306a36Sopenharmony_ci ret = mtk_pinconf_set(pctldev, pins[i], configs, num_configs); 43762306a36Sopenharmony_ci if (ret) 43862306a36Sopenharmony_ci return ret; 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci return 0; 44262306a36Sopenharmony_ci} 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_cistatic const struct pinctrl_ops mtk_pctlops = { 44562306a36Sopenharmony_ci .get_groups_count = pinctrl_generic_get_group_count, 44662306a36Sopenharmony_ci .get_group_name = pinctrl_generic_get_group_name, 44762306a36Sopenharmony_ci .get_group_pins = pinctrl_generic_get_group_pins, 44862306a36Sopenharmony_ci .dt_node_to_map = pinconf_generic_dt_node_to_map_all, 44962306a36Sopenharmony_ci .dt_free_map = pinconf_generic_dt_free_map, 45062306a36Sopenharmony_ci}; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_cistatic const struct pinmux_ops mtk_pmxops = { 45362306a36Sopenharmony_ci .get_functions_count = pinmux_generic_get_function_count, 45462306a36Sopenharmony_ci .get_function_name = pinmux_generic_get_function_name, 45562306a36Sopenharmony_ci .get_function_groups = pinmux_generic_get_function_groups, 45662306a36Sopenharmony_ci .set_mux = mtk_pinmux_set_mux, 45762306a36Sopenharmony_ci .gpio_request_enable = mtk_pinmux_gpio_request_enable, 45862306a36Sopenharmony_ci .gpio_set_direction = mtk_pinmux_gpio_set_direction, 45962306a36Sopenharmony_ci .strict = true, 46062306a36Sopenharmony_ci}; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_cistatic const struct pinconf_ops mtk_confops = { 46362306a36Sopenharmony_ci .is_generic = true, 46462306a36Sopenharmony_ci .pin_config_get = mtk_pinconf_get, 46562306a36Sopenharmony_ci .pin_config_set = mtk_pinconf_set, 46662306a36Sopenharmony_ci .pin_config_group_get = mtk_pinconf_group_get, 46762306a36Sopenharmony_ci .pin_config_group_set = mtk_pinconf_group_set, 46862306a36Sopenharmony_ci .pin_config_config_dbg_show = pinconf_generic_dump_config, 46962306a36Sopenharmony_ci}; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_cistatic struct pinctrl_desc mtk_desc = { 47262306a36Sopenharmony_ci .name = PINCTRL_PINCTRL_DEV, 47362306a36Sopenharmony_ci .pctlops = &mtk_pctlops, 47462306a36Sopenharmony_ci .pmxops = &mtk_pmxops, 47562306a36Sopenharmony_ci .confops = &mtk_confops, 47662306a36Sopenharmony_ci .owner = THIS_MODULE, 47762306a36Sopenharmony_ci}; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_cistatic int mtk_gpio_get(struct gpio_chip *chip, unsigned int gpio) 48062306a36Sopenharmony_ci{ 48162306a36Sopenharmony_ci struct mtk_pinctrl *hw = gpiochip_get_data(chip); 48262306a36Sopenharmony_ci const struct mtk_pin_desc *desc; 48362306a36Sopenharmony_ci int value, err; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio]; 48662306a36Sopenharmony_ci if (!desc->name) 48762306a36Sopenharmony_ci return -ENOTSUPP; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DI, &value); 49062306a36Sopenharmony_ci if (err) 49162306a36Sopenharmony_ci return err; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci return !!value; 49462306a36Sopenharmony_ci} 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_cistatic void mtk_gpio_set(struct gpio_chip *chip, unsigned int gpio, int value) 49762306a36Sopenharmony_ci{ 49862306a36Sopenharmony_ci struct mtk_pinctrl *hw = gpiochip_get_data(chip); 49962306a36Sopenharmony_ci const struct mtk_pin_desc *desc; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio]; 50262306a36Sopenharmony_ci if (!desc->name) { 50362306a36Sopenharmony_ci dev_err(hw->dev, "Failed to set gpio %d\n", gpio); 50462306a36Sopenharmony_ci return; 50562306a36Sopenharmony_ci } 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DO, !!value); 50862306a36Sopenharmony_ci} 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_cistatic int mtk_gpio_direction_input(struct gpio_chip *chip, unsigned int gpio) 51162306a36Sopenharmony_ci{ 51262306a36Sopenharmony_ci return pinctrl_gpio_direction_input(chip->base + gpio); 51362306a36Sopenharmony_ci} 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_cistatic int mtk_gpio_direction_output(struct gpio_chip *chip, unsigned int gpio, 51662306a36Sopenharmony_ci int value) 51762306a36Sopenharmony_ci{ 51862306a36Sopenharmony_ci mtk_gpio_set(chip, gpio, value); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci return pinctrl_gpio_direction_output(chip->base + gpio); 52162306a36Sopenharmony_ci} 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_cistatic int mtk_gpio_to_irq(struct gpio_chip *chip, unsigned int offset) 52462306a36Sopenharmony_ci{ 52562306a36Sopenharmony_ci struct mtk_pinctrl *hw = gpiochip_get_data(chip); 52662306a36Sopenharmony_ci const struct mtk_pin_desc *desc; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci if (!hw->eint) 52962306a36Sopenharmony_ci return -ENOTSUPP; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci desc = (const struct mtk_pin_desc *)&hw->soc->pins[offset]; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci if (desc->eint.eint_n == (u16)EINT_NA) 53462306a36Sopenharmony_ci return -ENOTSUPP; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci return mtk_eint_find_irq(hw->eint, desc->eint.eint_n); 53762306a36Sopenharmony_ci} 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_cistatic int mtk_gpio_set_config(struct gpio_chip *chip, unsigned int offset, 54062306a36Sopenharmony_ci unsigned long config) 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci struct mtk_pinctrl *hw = gpiochip_get_data(chip); 54362306a36Sopenharmony_ci const struct mtk_pin_desc *desc; 54462306a36Sopenharmony_ci u32 debounce; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci desc = (const struct mtk_pin_desc *)&hw->soc->pins[offset]; 54762306a36Sopenharmony_ci if (!desc->name) 54862306a36Sopenharmony_ci return -ENOTSUPP; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci if (!hw->eint || 55162306a36Sopenharmony_ci pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE || 55262306a36Sopenharmony_ci desc->eint.eint_n == (u16)EINT_NA) 55362306a36Sopenharmony_ci return -ENOTSUPP; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci debounce = pinconf_to_config_argument(config); 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci return mtk_eint_set_debounce(hw->eint, desc->eint.eint_n, debounce); 55862306a36Sopenharmony_ci} 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_cistatic int mtk_build_gpiochip(struct mtk_pinctrl *hw) 56162306a36Sopenharmony_ci{ 56262306a36Sopenharmony_ci struct gpio_chip *chip = &hw->chip; 56362306a36Sopenharmony_ci int ret; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci chip->label = PINCTRL_PINCTRL_DEV; 56662306a36Sopenharmony_ci chip->parent = hw->dev; 56762306a36Sopenharmony_ci chip->request = gpiochip_generic_request; 56862306a36Sopenharmony_ci chip->free = gpiochip_generic_free; 56962306a36Sopenharmony_ci chip->direction_input = mtk_gpio_direction_input; 57062306a36Sopenharmony_ci chip->direction_output = mtk_gpio_direction_output; 57162306a36Sopenharmony_ci chip->get = mtk_gpio_get; 57262306a36Sopenharmony_ci chip->set = mtk_gpio_set; 57362306a36Sopenharmony_ci chip->to_irq = mtk_gpio_to_irq; 57462306a36Sopenharmony_ci chip->set_config = mtk_gpio_set_config; 57562306a36Sopenharmony_ci chip->base = -1; 57662306a36Sopenharmony_ci chip->ngpio = hw->soc->npins; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci ret = gpiochip_add_data(chip, hw); 57962306a36Sopenharmony_ci if (ret < 0) 58062306a36Sopenharmony_ci return ret; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci /* Just for backward compatible for these old pinctrl nodes without 58362306a36Sopenharmony_ci * "gpio-ranges" property. Otherwise, called directly from a 58462306a36Sopenharmony_ci * DeviceTree-supported pinctrl driver is DEPRECATED. 58562306a36Sopenharmony_ci * Please see Section 2.1 of 58662306a36Sopenharmony_ci * Documentation/devicetree/bindings/gpio/gpio.txt on how to 58762306a36Sopenharmony_ci * bind pinctrl and gpio drivers via the "gpio-ranges" property. 58862306a36Sopenharmony_ci */ 58962306a36Sopenharmony_ci if (!of_property_present(hw->dev->of_node, "gpio-ranges")) { 59062306a36Sopenharmony_ci ret = gpiochip_add_pin_range(chip, dev_name(hw->dev), 0, 0, 59162306a36Sopenharmony_ci chip->ngpio); 59262306a36Sopenharmony_ci if (ret < 0) { 59362306a36Sopenharmony_ci gpiochip_remove(chip); 59462306a36Sopenharmony_ci return ret; 59562306a36Sopenharmony_ci } 59662306a36Sopenharmony_ci } 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci return 0; 59962306a36Sopenharmony_ci} 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_cistatic int mtk_build_groups(struct mtk_pinctrl *hw) 60262306a36Sopenharmony_ci{ 60362306a36Sopenharmony_ci int err, i; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci for (i = 0; i < hw->soc->ngrps; i++) { 60662306a36Sopenharmony_ci const struct group_desc *group = hw->soc->grps + i; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci err = pinctrl_generic_add_group(hw->pctrl, group->name, 60962306a36Sopenharmony_ci group->pins, group->num_pins, 61062306a36Sopenharmony_ci group->data); 61162306a36Sopenharmony_ci if (err < 0) { 61262306a36Sopenharmony_ci dev_err(hw->dev, "Failed to register group %s\n", 61362306a36Sopenharmony_ci group->name); 61462306a36Sopenharmony_ci return err; 61562306a36Sopenharmony_ci } 61662306a36Sopenharmony_ci } 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci return 0; 61962306a36Sopenharmony_ci} 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_cistatic int mtk_build_functions(struct mtk_pinctrl *hw) 62262306a36Sopenharmony_ci{ 62362306a36Sopenharmony_ci int i, err; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci for (i = 0; i < hw->soc->nfuncs ; i++) { 62662306a36Sopenharmony_ci const struct function_desc *func = hw->soc->funcs + i; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci err = pinmux_generic_add_function(hw->pctrl, func->name, 62962306a36Sopenharmony_ci func->group_names, 63062306a36Sopenharmony_ci func->num_group_names, 63162306a36Sopenharmony_ci func->data); 63262306a36Sopenharmony_ci if (err < 0) { 63362306a36Sopenharmony_ci dev_err(hw->dev, "Failed to register function %s\n", 63462306a36Sopenharmony_ci func->name); 63562306a36Sopenharmony_ci return err; 63662306a36Sopenharmony_ci } 63762306a36Sopenharmony_ci } 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci return 0; 64062306a36Sopenharmony_ci} 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ciint mtk_moore_pinctrl_probe(struct platform_device *pdev, 64362306a36Sopenharmony_ci const struct mtk_pin_soc *soc) 64462306a36Sopenharmony_ci{ 64562306a36Sopenharmony_ci struct device *dev = &pdev->dev; 64662306a36Sopenharmony_ci struct pinctrl_pin_desc *pins; 64762306a36Sopenharmony_ci struct mtk_pinctrl *hw; 64862306a36Sopenharmony_ci int err, i; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci hw = devm_kzalloc(&pdev->dev, sizeof(*hw), GFP_KERNEL); 65162306a36Sopenharmony_ci if (!hw) 65262306a36Sopenharmony_ci return -ENOMEM; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci hw->soc = soc; 65562306a36Sopenharmony_ci hw->dev = &pdev->dev; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci if (!hw->soc->nbase_names) 65862306a36Sopenharmony_ci return dev_err_probe(dev, -EINVAL, 65962306a36Sopenharmony_ci "SoC should be assigned at least one register base\n"); 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci hw->base = devm_kmalloc_array(&pdev->dev, hw->soc->nbase_names, 66262306a36Sopenharmony_ci sizeof(*hw->base), GFP_KERNEL); 66362306a36Sopenharmony_ci if (!hw->base) 66462306a36Sopenharmony_ci return -ENOMEM; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci for (i = 0; i < hw->soc->nbase_names; i++) { 66762306a36Sopenharmony_ci hw->base[i] = devm_platform_ioremap_resource_byname(pdev, 66862306a36Sopenharmony_ci hw->soc->base_names[i]); 66962306a36Sopenharmony_ci if (IS_ERR(hw->base[i])) 67062306a36Sopenharmony_ci return PTR_ERR(hw->base[i]); 67162306a36Sopenharmony_ci } 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci hw->nbase = hw->soc->nbase_names; 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci spin_lock_init(&hw->lock); 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci /* Copy from internal struct mtk_pin_desc to register to the core */ 67862306a36Sopenharmony_ci pins = devm_kmalloc_array(&pdev->dev, hw->soc->npins, sizeof(*pins), 67962306a36Sopenharmony_ci GFP_KERNEL); 68062306a36Sopenharmony_ci if (!pins) 68162306a36Sopenharmony_ci return -ENOMEM; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci for (i = 0; i < hw->soc->npins; i++) { 68462306a36Sopenharmony_ci pins[i].number = hw->soc->pins[i].number; 68562306a36Sopenharmony_ci pins[i].name = hw->soc->pins[i].name; 68662306a36Sopenharmony_ci } 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci /* Setup pins descriptions per SoC types */ 68962306a36Sopenharmony_ci mtk_desc.pins = (const struct pinctrl_pin_desc *)pins; 69062306a36Sopenharmony_ci mtk_desc.npins = hw->soc->npins; 69162306a36Sopenharmony_ci mtk_desc.num_custom_params = ARRAY_SIZE(mtk_custom_bindings); 69262306a36Sopenharmony_ci mtk_desc.custom_params = mtk_custom_bindings; 69362306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 69462306a36Sopenharmony_ci mtk_desc.custom_conf_items = mtk_conf_items; 69562306a36Sopenharmony_ci#endif 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci err = devm_pinctrl_register_and_init(&pdev->dev, &mtk_desc, hw, 69862306a36Sopenharmony_ci &hw->pctrl); 69962306a36Sopenharmony_ci if (err) 70062306a36Sopenharmony_ci return err; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci /* Setup groups descriptions per SoC types */ 70362306a36Sopenharmony_ci err = mtk_build_groups(hw); 70462306a36Sopenharmony_ci if (err) 70562306a36Sopenharmony_ci return dev_err_probe(dev, err, "Failed to build groups\n"); 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci /* Setup functions descriptions per SoC types */ 70862306a36Sopenharmony_ci err = mtk_build_functions(hw); 70962306a36Sopenharmony_ci if (err) 71062306a36Sopenharmony_ci return dev_err_probe(dev, err, "Failed to build functions\n"); 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci /* For able to make pinctrl_claim_hogs, we must not enable pinctrl 71362306a36Sopenharmony_ci * until all groups and functions are being added one. 71462306a36Sopenharmony_ci */ 71562306a36Sopenharmony_ci err = pinctrl_enable(hw->pctrl); 71662306a36Sopenharmony_ci if (err) 71762306a36Sopenharmony_ci return err; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci err = mtk_build_eint(hw, pdev); 72062306a36Sopenharmony_ci if (err) 72162306a36Sopenharmony_ci dev_warn(&pdev->dev, 72262306a36Sopenharmony_ci "Failed to add EINT, but pinctrl still can work\n"); 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci /* Build gpiochip should be after pinctrl_enable is done */ 72562306a36Sopenharmony_ci err = mtk_build_gpiochip(hw); 72662306a36Sopenharmony_ci if (err) 72762306a36Sopenharmony_ci return dev_err_probe(dev, err, "Failed to add gpio_chip\n"); 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci platform_set_drvdata(pdev, hw); 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci return 0; 73262306a36Sopenharmony_ci} 733