1e78d57b2SSean Wang // SPDX-License-Identifier: GPL-2.0 2e78d57b2SSean Wang /* 3e78d57b2SSean Wang * MediaTek Pinctrl Moore Driver, which implement the generic dt-binding 4e78d57b2SSean Wang * pinctrl-bindings.txt for MediaTek SoC. 5e78d57b2SSean Wang * 6e78d57b2SSean Wang * Copyright (C) 2017-2018 MediaTek Inc. 7e78d57b2SSean Wang * Author: Sean Wang <sean.wang@mediatek.com> 8e78d57b2SSean Wang * 9e78d57b2SSean Wang */ 10e78d57b2SSean Wang 11e78d57b2SSean Wang #include "pinctrl-moore.h" 12e78d57b2SSean Wang 13e78d57b2SSean Wang #define PINCTRL_PINCTRL_DEV KBUILD_MODNAME 14e78d57b2SSean Wang 15e78d57b2SSean Wang /* Custom pinconf parameters */ 16e78d57b2SSean Wang #define MTK_PIN_CONFIG_TDSEL (PIN_CONFIG_END + 1) 17e78d57b2SSean Wang #define MTK_PIN_CONFIG_RDSEL (PIN_CONFIG_END + 2) 180d7ca772SSean Wang #define MTK_PIN_CONFIG_PU_ADV (PIN_CONFIG_END + 3) 190d7ca772SSean Wang #define MTK_PIN_CONFIG_PD_ADV (PIN_CONFIG_END + 4) 20e78d57b2SSean Wang 21e78d57b2SSean Wang static const struct pinconf_generic_params mtk_custom_bindings[] = { 22e78d57b2SSean Wang {"mediatek,tdsel", MTK_PIN_CONFIG_TDSEL, 0}, 23e78d57b2SSean Wang {"mediatek,rdsel", MTK_PIN_CONFIG_RDSEL, 0}, 240d7ca772SSean Wang {"mediatek,pull-up-adv", MTK_PIN_CONFIG_PU_ADV, 1}, 250d7ca772SSean Wang {"mediatek,pull-down-adv", MTK_PIN_CONFIG_PD_ADV, 1}, 26e78d57b2SSean Wang }; 27e78d57b2SSean Wang 28e78d57b2SSean Wang #ifdef CONFIG_DEBUG_FS 29e78d57b2SSean Wang static const struct pin_config_item mtk_conf_items[] = { 30e78d57b2SSean Wang PCONFDUMP(MTK_PIN_CONFIG_TDSEL, "tdsel", NULL, true), 31e78d57b2SSean Wang PCONFDUMP(MTK_PIN_CONFIG_RDSEL, "rdsel", NULL, true), 320d7ca772SSean Wang PCONFDUMP(MTK_PIN_CONFIG_PU_ADV, "pu-adv", NULL, true), 330d7ca772SSean Wang PCONFDUMP(MTK_PIN_CONFIG_PD_ADV, "pd-adv", NULL, true), 34e78d57b2SSean Wang }; 35e78d57b2SSean Wang #endif 36e78d57b2SSean Wang 37e78d57b2SSean Wang static int mtk_pinmux_set_mux(struct pinctrl_dev *pctldev, 38e78d57b2SSean Wang unsigned int selector, unsigned int group) 39e78d57b2SSean Wang { 40e78d57b2SSean Wang struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 41e78d57b2SSean Wang struct function_desc *func; 42e78d57b2SSean Wang struct group_desc *grp; 43e78d57b2SSean Wang int i; 44e78d57b2SSean Wang 45e78d57b2SSean Wang func = pinmux_generic_get_function(pctldev, selector); 46e78d57b2SSean Wang if (!func) 47e78d57b2SSean Wang return -EINVAL; 48e78d57b2SSean Wang 49e78d57b2SSean Wang grp = pinctrl_generic_get_group(pctldev, group); 50e78d57b2SSean Wang if (!grp) 51e78d57b2SSean Wang return -EINVAL; 52e78d57b2SSean Wang 53e78d57b2SSean Wang dev_dbg(pctldev->dev, "enable function %s group %s\n", 54e78d57b2SSean Wang func->name, grp->name); 55e78d57b2SSean Wang 56e78d57b2SSean Wang for (i = 0; i < grp->num_pins; i++) { 57e78d57b2SSean Wang int *pin_modes = grp->data; 58e78d57b2SSean Wang 59e78d57b2SSean Wang mtk_hw_set_value(hw, grp->pins[i], PINCTRL_PIN_REG_MODE, 60e78d57b2SSean Wang pin_modes[i]); 61e78d57b2SSean Wang } 62e78d57b2SSean Wang 63e78d57b2SSean Wang return 0; 64e78d57b2SSean Wang } 65e78d57b2SSean Wang 66e78d57b2SSean Wang static int mtk_pinmux_gpio_request_enable(struct pinctrl_dev *pctldev, 67e78d57b2SSean Wang struct pinctrl_gpio_range *range, 68e78d57b2SSean Wang unsigned int pin) 69e78d57b2SSean Wang { 70e78d57b2SSean Wang struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 71e78d57b2SSean Wang 721dc5e536SSean Wang return mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_MODE, hw->soc->gpio_m); 73e78d57b2SSean Wang } 74e78d57b2SSean Wang 75e78d57b2SSean Wang static int mtk_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev, 76e78d57b2SSean Wang struct pinctrl_gpio_range *range, 77e78d57b2SSean Wang unsigned int pin, bool input) 78e78d57b2SSean Wang { 79e78d57b2SSean Wang struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 80e78d57b2SSean Wang 81e78d57b2SSean Wang /* hardware would take 0 as input direction */ 82e78d57b2SSean Wang return mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_DIR, !input); 83e78d57b2SSean Wang } 84e78d57b2SSean Wang 85e78d57b2SSean Wang static int mtk_pinconf_get(struct pinctrl_dev *pctldev, 86e78d57b2SSean Wang unsigned int pin, unsigned long *config) 87e78d57b2SSean Wang { 88e78d57b2SSean Wang struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 89e78d57b2SSean Wang u32 param = pinconf_to_config_param(*config); 90e78d57b2SSean Wang int val, val2, err, reg, ret = 1; 91c2832197SSean Wang const struct mtk_pin_desc *desc; 92c2832197SSean Wang 93c2832197SSean Wang desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; 94e78d57b2SSean Wang 95e78d57b2SSean Wang switch (param) { 96e78d57b2SSean Wang case PIN_CONFIG_BIAS_DISABLE: 9785430152SSean Wang if (hw->soc->bias_disable_get) { 9885430152SSean Wang err = hw->soc->bias_disable_get(hw, desc, &ret); 99e78d57b2SSean Wang if (err) 100e78d57b2SSean Wang return err; 10185430152SSean Wang } else { 10285430152SSean Wang return -ENOTSUPP; 10385430152SSean Wang } 104e78d57b2SSean Wang break; 105e78d57b2SSean Wang case PIN_CONFIG_BIAS_PULL_UP: 10685430152SSean Wang if (hw->soc->bias_get) { 10785430152SSean Wang err = hw->soc->bias_get(hw, desc, 1, &ret); 10885430152SSean Wang if (err) 10985430152SSean Wang return err; 11085430152SSean Wang } else { 11185430152SSean Wang return -ENOTSUPP; 11285430152SSean Wang } 11385430152SSean Wang break; 114e78d57b2SSean Wang case PIN_CONFIG_BIAS_PULL_DOWN: 11585430152SSean Wang if (hw->soc->bias_get) { 11685430152SSean Wang err = hw->soc->bias_get(hw, desc, 0, &ret); 11785430152SSean Wang if (err) 11885430152SSean Wang return err; 11985430152SSean Wang } else { 12085430152SSean Wang return -ENOTSUPP; 12185430152SSean Wang } 12285430152SSean Wang break; 123e78d57b2SSean Wang case PIN_CONFIG_SLEW_RATE: 12485430152SSean Wang err = mtk_hw_get_value(hw, pin, PINCTRL_PIN_REG_SR, &val); 125e78d57b2SSean Wang if (err) 126e78d57b2SSean Wang return err; 127e78d57b2SSean Wang 128e78d57b2SSean Wang if (!val) 129e78d57b2SSean Wang return -EINVAL; 130e78d57b2SSean Wang 131e78d57b2SSean Wang break; 132e78d57b2SSean Wang case PIN_CONFIG_INPUT_ENABLE: 133e78d57b2SSean Wang case PIN_CONFIG_OUTPUT_ENABLE: 134e78d57b2SSean Wang err = mtk_hw_get_value(hw, pin, PINCTRL_PIN_REG_DIR, &val); 135e78d57b2SSean Wang if (err) 136e78d57b2SSean Wang return err; 137e78d57b2SSean Wang 138e78d57b2SSean Wang /* HW takes input mode as zero; output mode as non-zero */ 139e78d57b2SSean Wang if ((val && param == PIN_CONFIG_INPUT_ENABLE) || 140e78d57b2SSean Wang (!val && param == PIN_CONFIG_OUTPUT_ENABLE)) 141e78d57b2SSean Wang return -EINVAL; 142e78d57b2SSean Wang 143e78d57b2SSean Wang break; 144e78d57b2SSean Wang case PIN_CONFIG_INPUT_SCHMITT_ENABLE: 145e78d57b2SSean Wang err = mtk_hw_get_value(hw, pin, PINCTRL_PIN_REG_DIR, &val); 146e78d57b2SSean Wang if (err) 147e78d57b2SSean Wang return err; 148e78d57b2SSean Wang 149e78d57b2SSean Wang err = mtk_hw_get_value(hw, pin, PINCTRL_PIN_REG_SMT, &val2); 150e78d57b2SSean Wang if (err) 151e78d57b2SSean Wang return err; 152e78d57b2SSean Wang 153e78d57b2SSean Wang if (val || !val2) 154e78d57b2SSean Wang return -EINVAL; 155e78d57b2SSean Wang 156e78d57b2SSean Wang break; 157e78d57b2SSean Wang case PIN_CONFIG_DRIVE_STRENGTH: 158c2832197SSean Wang if (hw->soc->drive_get) { 159c2832197SSean Wang err = hw->soc->drive_get(hw, desc, &ret); 160e78d57b2SSean Wang if (err) 161e78d57b2SSean Wang return err; 162c2832197SSean Wang } else { 163c2832197SSean Wang err = -ENOTSUPP; 164c2832197SSean Wang } 165e78d57b2SSean Wang break; 166e78d57b2SSean Wang case MTK_PIN_CONFIG_TDSEL: 167e78d57b2SSean Wang case MTK_PIN_CONFIG_RDSEL: 168e78d57b2SSean Wang reg = (param == MTK_PIN_CONFIG_TDSEL) ? 169e78d57b2SSean Wang PINCTRL_PIN_REG_TDSEL : PINCTRL_PIN_REG_RDSEL; 170e78d57b2SSean Wang 171e78d57b2SSean Wang err = mtk_hw_get_value(hw, pin, reg, &val); 172e78d57b2SSean Wang if (err) 173e78d57b2SSean Wang return err; 174e78d57b2SSean Wang 175e78d57b2SSean Wang ret = val; 176e78d57b2SSean Wang 177e78d57b2SSean Wang break; 1780d7ca772SSean Wang case MTK_PIN_CONFIG_PU_ADV: 1790d7ca772SSean Wang case MTK_PIN_CONFIG_PD_ADV: 1800d7ca772SSean Wang if (hw->soc->adv_pull_get) { 1810d7ca772SSean Wang bool pullup; 1820d7ca772SSean Wang 1830d7ca772SSean Wang pullup = param == MTK_PIN_CONFIG_PU_ADV; 1840d7ca772SSean Wang err = hw->soc->adv_pull_get(hw, desc, pullup, &ret); 1850d7ca772SSean Wang if (err) 1860d7ca772SSean Wang return err; 1870d7ca772SSean Wang } else { 1880d7ca772SSean Wang return -ENOTSUPP; 1890d7ca772SSean Wang } 1900d7ca772SSean Wang break; 191e78d57b2SSean Wang default: 192e78d57b2SSean Wang return -ENOTSUPP; 193e78d57b2SSean Wang } 194e78d57b2SSean Wang 195e78d57b2SSean Wang *config = pinconf_to_config_packed(param, ret); 196e78d57b2SSean Wang 197e78d57b2SSean Wang return 0; 198e78d57b2SSean Wang } 199e78d57b2SSean Wang 200e78d57b2SSean Wang static int mtk_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, 201e78d57b2SSean Wang unsigned long *configs, unsigned int num_configs) 202e78d57b2SSean Wang { 203e78d57b2SSean Wang struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 204c2832197SSean Wang const struct mtk_pin_desc *desc; 205e78d57b2SSean Wang u32 reg, param, arg; 206e78d57b2SSean Wang int cfg, err = 0; 207e78d57b2SSean Wang 208c2832197SSean Wang desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; 209c2832197SSean Wang 210e78d57b2SSean Wang for (cfg = 0; cfg < num_configs; cfg++) { 211e78d57b2SSean Wang param = pinconf_to_config_param(configs[cfg]); 212e78d57b2SSean Wang arg = pinconf_to_config_argument(configs[cfg]); 213e78d57b2SSean Wang 214e78d57b2SSean Wang switch (param) { 215e78d57b2SSean Wang case PIN_CONFIG_BIAS_DISABLE: 21685430152SSean Wang if (hw->soc->bias_disable_set) { 21785430152SSean Wang err = hw->soc->bias_disable_set(hw, desc); 21885430152SSean Wang if (err) 21985430152SSean Wang return err; 22085430152SSean Wang } else { 22185430152SSean Wang return -ENOTSUPP; 22285430152SSean Wang } 22385430152SSean Wang break; 224e78d57b2SSean Wang case PIN_CONFIG_BIAS_PULL_UP: 22585430152SSean Wang if (hw->soc->bias_set) { 22685430152SSean Wang err = hw->soc->bias_set(hw, desc, 1); 22785430152SSean Wang if (err) 22885430152SSean Wang return err; 22985430152SSean Wang } else { 23085430152SSean Wang return -ENOTSUPP; 23185430152SSean Wang } 23285430152SSean Wang break; 233e78d57b2SSean Wang case PIN_CONFIG_BIAS_PULL_DOWN: 23485430152SSean Wang if (hw->soc->bias_set) { 23585430152SSean Wang err = hw->soc->bias_set(hw, desc, 0); 236e78d57b2SSean Wang if (err) 23785430152SSean Wang return err; 23885430152SSean Wang } else { 23985430152SSean Wang return -ENOTSUPP; 24085430152SSean Wang } 241e78d57b2SSean Wang break; 242e78d57b2SSean Wang case PIN_CONFIG_OUTPUT_ENABLE: 243e78d57b2SSean Wang err = mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_SMT, 244e78d57b2SSean Wang MTK_DISABLE); 245e78d57b2SSean Wang if (err) 246e78d57b2SSean Wang goto err; 247e78d57b2SSean Wang 248*182c842fSSean Wang err = mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_DIR, 249*182c842fSSean Wang MTK_OUTPUT); 250*182c842fSSean Wang if (err) 251*182c842fSSean Wang goto err; 252*182c842fSSean Wang break; 253*182c842fSSean Wang case PIN_CONFIG_INPUT_ENABLE: 254*182c842fSSean Wang 255*182c842fSSean Wang if (hw->soc->ies_present) { 256*182c842fSSean Wang mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_IES, 257*182c842fSSean Wang MTK_ENABLE); 258*182c842fSSean Wang } 259*182c842fSSean Wang 260*182c842fSSean Wang err = mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_DIR, 261*182c842fSSean Wang MTK_INPUT); 262*182c842fSSean Wang if (err) 263*182c842fSSean Wang goto err; 264*182c842fSSean Wang break; 265*182c842fSSean Wang case PIN_CONFIG_SLEW_RATE: 266*182c842fSSean Wang err = mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_SR, 267*182c842fSSean Wang arg); 268e78d57b2SSean Wang if (err) 269e78d57b2SSean Wang goto err; 270e78d57b2SSean Wang 271e78d57b2SSean Wang break; 272e78d57b2SSean Wang case PIN_CONFIG_OUTPUT: 273e78d57b2SSean Wang err = mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_DIR, 274e78d57b2SSean Wang MTK_OUTPUT); 275e78d57b2SSean Wang if (err) 276e78d57b2SSean Wang goto err; 277e78d57b2SSean Wang 278e78d57b2SSean Wang err = mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_DO, 279e78d57b2SSean Wang arg); 280e78d57b2SSean Wang if (err) 281e78d57b2SSean Wang goto err; 282e78d57b2SSean Wang break; 283e78d57b2SSean Wang case PIN_CONFIG_INPUT_SCHMITT_ENABLE: 284e78d57b2SSean Wang /* arg = 1: Input mode & SMT enable ; 285e78d57b2SSean Wang * arg = 0: Output mode & SMT disable 286e78d57b2SSean Wang */ 287e78d57b2SSean Wang arg = arg ? 2 : 1; 288e78d57b2SSean Wang err = mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_DIR, 289e78d57b2SSean Wang arg & 1); 290e78d57b2SSean Wang if (err) 291e78d57b2SSean Wang goto err; 292e78d57b2SSean Wang 293e78d57b2SSean Wang err = mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_SMT, 294e78d57b2SSean Wang !!(arg & 2)); 295e78d57b2SSean Wang if (err) 296e78d57b2SSean Wang goto err; 297e78d57b2SSean Wang break; 298e78d57b2SSean Wang case PIN_CONFIG_DRIVE_STRENGTH: 299c2832197SSean Wang if (hw->soc->drive_set) { 300c2832197SSean Wang err = hw->soc->drive_set(hw, desc, arg); 301e78d57b2SSean Wang if (err) 302c2832197SSean Wang return err; 303e78d57b2SSean Wang } else { 304e78d57b2SSean Wang err = -ENOTSUPP; 305e78d57b2SSean Wang } 306e78d57b2SSean Wang break; 307e78d57b2SSean Wang case MTK_PIN_CONFIG_TDSEL: 308e78d57b2SSean Wang case MTK_PIN_CONFIG_RDSEL: 309e78d57b2SSean Wang reg = (param == MTK_PIN_CONFIG_TDSEL) ? 310e78d57b2SSean Wang PINCTRL_PIN_REG_TDSEL : PINCTRL_PIN_REG_RDSEL; 311e78d57b2SSean Wang 312e78d57b2SSean Wang err = mtk_hw_set_value(hw, pin, reg, arg); 313e78d57b2SSean Wang if (err) 314e78d57b2SSean Wang goto err; 315e78d57b2SSean Wang break; 3160d7ca772SSean Wang case MTK_PIN_CONFIG_PU_ADV: 3170d7ca772SSean Wang case MTK_PIN_CONFIG_PD_ADV: 3180d7ca772SSean Wang if (hw->soc->adv_pull_set) { 3190d7ca772SSean Wang bool pullup; 3200d7ca772SSean Wang 3210d7ca772SSean Wang pullup = param == MTK_PIN_CONFIG_PU_ADV; 3220d7ca772SSean Wang err = hw->soc->adv_pull_set(hw, desc, pullup, 3230d7ca772SSean Wang arg); 3240d7ca772SSean Wang if (err) 3250d7ca772SSean Wang return err; 3260d7ca772SSean Wang } else { 3270d7ca772SSean Wang return -ENOTSUPP; 3280d7ca772SSean Wang } 3290d7ca772SSean Wang break; 330e78d57b2SSean Wang default: 331e78d57b2SSean Wang err = -ENOTSUPP; 332e78d57b2SSean Wang } 333e78d57b2SSean Wang } 334e78d57b2SSean Wang err: 335e78d57b2SSean Wang return err; 336e78d57b2SSean Wang } 337e78d57b2SSean Wang 338e78d57b2SSean Wang static int mtk_pinconf_group_get(struct pinctrl_dev *pctldev, 339e78d57b2SSean Wang unsigned int group, unsigned long *config) 340e78d57b2SSean Wang { 341e78d57b2SSean Wang const unsigned int *pins; 342e78d57b2SSean Wang unsigned int i, npins, old = 0; 343e78d57b2SSean Wang int ret; 344e78d57b2SSean Wang 345e78d57b2SSean Wang ret = pinctrl_generic_get_group_pins(pctldev, group, &pins, &npins); 346e78d57b2SSean Wang if (ret) 347e78d57b2SSean Wang return ret; 348e78d57b2SSean Wang 349e78d57b2SSean Wang for (i = 0; i < npins; i++) { 350e78d57b2SSean Wang if (mtk_pinconf_get(pctldev, pins[i], config)) 351e78d57b2SSean Wang return -ENOTSUPP; 352e78d57b2SSean Wang 353e78d57b2SSean Wang /* configs do not match between two pins */ 354e78d57b2SSean Wang if (i && old != *config) 355e78d57b2SSean Wang return -ENOTSUPP; 356e78d57b2SSean Wang 357e78d57b2SSean Wang old = *config; 358e78d57b2SSean Wang } 359e78d57b2SSean Wang 360e78d57b2SSean Wang return 0; 361e78d57b2SSean Wang } 362e78d57b2SSean Wang 363e78d57b2SSean Wang static int mtk_pinconf_group_set(struct pinctrl_dev *pctldev, 364e78d57b2SSean Wang unsigned int group, unsigned long *configs, 365e78d57b2SSean Wang unsigned int num_configs) 366e78d57b2SSean Wang { 367e78d57b2SSean Wang const unsigned int *pins; 368e78d57b2SSean Wang unsigned int i, npins; 369e78d57b2SSean Wang int ret; 370e78d57b2SSean Wang 371e78d57b2SSean Wang ret = pinctrl_generic_get_group_pins(pctldev, group, &pins, &npins); 372e78d57b2SSean Wang if (ret) 373e78d57b2SSean Wang return ret; 374e78d57b2SSean Wang 375e78d57b2SSean Wang for (i = 0; i < npins; i++) { 376e78d57b2SSean Wang ret = mtk_pinconf_set(pctldev, pins[i], configs, num_configs); 377e78d57b2SSean Wang if (ret) 378e78d57b2SSean Wang return ret; 379e78d57b2SSean Wang } 380e78d57b2SSean Wang 381e78d57b2SSean Wang return 0; 382e78d57b2SSean Wang } 383e78d57b2SSean Wang 384e78d57b2SSean Wang static const struct pinctrl_ops mtk_pctlops = { 385e78d57b2SSean Wang .get_groups_count = pinctrl_generic_get_group_count, 386e78d57b2SSean Wang .get_group_name = pinctrl_generic_get_group_name, 387e78d57b2SSean Wang .get_group_pins = pinctrl_generic_get_group_pins, 388e78d57b2SSean Wang .dt_node_to_map = pinconf_generic_dt_node_to_map_all, 389e78d57b2SSean Wang .dt_free_map = pinconf_generic_dt_free_map, 390e78d57b2SSean Wang }; 391e78d57b2SSean Wang 392e78d57b2SSean Wang static const struct pinmux_ops mtk_pmxops = { 393e78d57b2SSean Wang .get_functions_count = pinmux_generic_get_function_count, 394e78d57b2SSean Wang .get_function_name = pinmux_generic_get_function_name, 395e78d57b2SSean Wang .get_function_groups = pinmux_generic_get_function_groups, 396e78d57b2SSean Wang .set_mux = mtk_pinmux_set_mux, 397e78d57b2SSean Wang .gpio_request_enable = mtk_pinmux_gpio_request_enable, 398e78d57b2SSean Wang .gpio_set_direction = mtk_pinmux_gpio_set_direction, 399e78d57b2SSean Wang .strict = true, 400e78d57b2SSean Wang }; 401e78d57b2SSean Wang 402e78d57b2SSean Wang static const struct pinconf_ops mtk_confops = { 403e78d57b2SSean Wang .is_generic = true, 404e78d57b2SSean Wang .pin_config_get = mtk_pinconf_get, 405e78d57b2SSean Wang .pin_config_set = mtk_pinconf_set, 406e78d57b2SSean Wang .pin_config_group_get = mtk_pinconf_group_get, 407e78d57b2SSean Wang .pin_config_group_set = mtk_pinconf_group_set, 408e78d57b2SSean Wang .pin_config_config_dbg_show = pinconf_generic_dump_config, 409e78d57b2SSean Wang }; 410e78d57b2SSean Wang 411e78d57b2SSean Wang static struct pinctrl_desc mtk_desc = { 412e78d57b2SSean Wang .name = PINCTRL_PINCTRL_DEV, 413e78d57b2SSean Wang .pctlops = &mtk_pctlops, 414e78d57b2SSean Wang .pmxops = &mtk_pmxops, 415e78d57b2SSean Wang .confops = &mtk_confops, 416e78d57b2SSean Wang .owner = THIS_MODULE, 417e78d57b2SSean Wang }; 418e78d57b2SSean Wang 419e78d57b2SSean Wang static int mtk_gpio_get(struct gpio_chip *chip, unsigned int gpio) 420e78d57b2SSean Wang { 421e78d57b2SSean Wang struct mtk_pinctrl *hw = gpiochip_get_data(chip); 422e78d57b2SSean Wang int value, err; 423e78d57b2SSean Wang 424e78d57b2SSean Wang err = mtk_hw_get_value(hw, gpio, PINCTRL_PIN_REG_DI, &value); 425e78d57b2SSean Wang if (err) 426e78d57b2SSean Wang return err; 427e78d57b2SSean Wang 428e78d57b2SSean Wang return !!value; 429e78d57b2SSean Wang } 430e78d57b2SSean Wang 431e78d57b2SSean Wang static void mtk_gpio_set(struct gpio_chip *chip, unsigned int gpio, int value) 432e78d57b2SSean Wang { 433e78d57b2SSean Wang struct mtk_pinctrl *hw = gpiochip_get_data(chip); 434e78d57b2SSean Wang 435e78d57b2SSean Wang mtk_hw_set_value(hw, gpio, PINCTRL_PIN_REG_DO, !!value); 436e78d57b2SSean Wang } 437e78d57b2SSean Wang 438e78d57b2SSean Wang static int mtk_gpio_direction_input(struct gpio_chip *chip, unsigned int gpio) 439e78d57b2SSean Wang { 440e78d57b2SSean Wang return pinctrl_gpio_direction_input(chip->base + gpio); 441e78d57b2SSean Wang } 442e78d57b2SSean Wang 443e78d57b2SSean Wang static int mtk_gpio_direction_output(struct gpio_chip *chip, unsigned int gpio, 444e78d57b2SSean Wang int value) 445e78d57b2SSean Wang { 446e78d57b2SSean Wang mtk_gpio_set(chip, gpio, value); 447e78d57b2SSean Wang 448e78d57b2SSean Wang return pinctrl_gpio_direction_output(chip->base + gpio); 449e78d57b2SSean Wang } 450e78d57b2SSean Wang 451e78d57b2SSean Wang static int mtk_gpio_to_irq(struct gpio_chip *chip, unsigned int offset) 452e78d57b2SSean Wang { 453e78d57b2SSean Wang struct mtk_pinctrl *hw = gpiochip_get_data(chip); 454fb5fa8dcSSean Wang const struct mtk_pin_desc *desc; 455e78d57b2SSean Wang 456e78d57b2SSean Wang if (!hw->eint) 457e78d57b2SSean Wang return -ENOTSUPP; 458e78d57b2SSean Wang 459fb5fa8dcSSean Wang desc = (const struct mtk_pin_desc *)&hw->soc->pins[offset]; 460e78d57b2SSean Wang 461fb5fa8dcSSean Wang if (desc->eint_n == EINT_NA) 462fb5fa8dcSSean Wang return -ENOTSUPP; 463fb5fa8dcSSean Wang 464fb5fa8dcSSean Wang return mtk_eint_find_irq(hw->eint, desc->eint_n); 465e78d57b2SSean Wang } 466e78d57b2SSean Wang 467e78d57b2SSean Wang static int mtk_gpio_set_config(struct gpio_chip *chip, unsigned int offset, 468e78d57b2SSean Wang unsigned long config) 469e78d57b2SSean Wang { 470e78d57b2SSean Wang struct mtk_pinctrl *hw = gpiochip_get_data(chip); 471fb5fa8dcSSean Wang const struct mtk_pin_desc *desc; 472e78d57b2SSean Wang u32 debounce; 473e78d57b2SSean Wang 474fb5fa8dcSSean Wang desc = (const struct mtk_pin_desc *)&hw->soc->pins[offset]; 475fb5fa8dcSSean Wang 476e78d57b2SSean Wang if (!hw->eint || 477fb5fa8dcSSean Wang pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE || 478fb5fa8dcSSean Wang desc->eint_n == EINT_NA) 479e78d57b2SSean Wang return -ENOTSUPP; 480e78d57b2SSean Wang 481e78d57b2SSean Wang debounce = pinconf_to_config_argument(config); 482e78d57b2SSean Wang 483fb5fa8dcSSean Wang return mtk_eint_set_debounce(hw->eint, desc->eint_n, debounce); 484e78d57b2SSean Wang } 485e78d57b2SSean Wang 486e78d57b2SSean Wang static int mtk_build_gpiochip(struct mtk_pinctrl *hw, struct device_node *np) 487e78d57b2SSean Wang { 488e78d57b2SSean Wang struct gpio_chip *chip = &hw->chip; 489e78d57b2SSean Wang int ret; 490e78d57b2SSean Wang 491e78d57b2SSean Wang chip->label = PINCTRL_PINCTRL_DEV; 492e78d57b2SSean Wang chip->parent = hw->dev; 493e78d57b2SSean Wang chip->request = gpiochip_generic_request; 494e78d57b2SSean Wang chip->free = gpiochip_generic_free; 495e78d57b2SSean Wang chip->direction_input = mtk_gpio_direction_input; 496e78d57b2SSean Wang chip->direction_output = mtk_gpio_direction_output; 497e78d57b2SSean Wang chip->get = mtk_gpio_get; 498e78d57b2SSean Wang chip->set = mtk_gpio_set; 499e78d57b2SSean Wang chip->to_irq = mtk_gpio_to_irq, 500e78d57b2SSean Wang chip->set_config = mtk_gpio_set_config, 501e78d57b2SSean Wang chip->base = -1; 502e78d57b2SSean Wang chip->ngpio = hw->soc->npins; 503e78d57b2SSean Wang chip->of_node = np; 504e78d57b2SSean Wang chip->of_gpio_n_cells = 2; 505e78d57b2SSean Wang 506e78d57b2SSean Wang ret = gpiochip_add_data(chip, hw); 507e78d57b2SSean Wang if (ret < 0) 508e78d57b2SSean Wang return ret; 509e78d57b2SSean Wang 510e78d57b2SSean Wang /* Just for backward compatible for these old pinctrl nodes without 511e78d57b2SSean Wang * "gpio-ranges" property. Otherwise, called directly from a 512e78d57b2SSean Wang * DeviceTree-supported pinctrl driver is DEPRECATED. 513e78d57b2SSean Wang * Please see Section 2.1 of 514e78d57b2SSean Wang * Documentation/devicetree/bindings/gpio/gpio.txt on how to 515e78d57b2SSean Wang * bind pinctrl and gpio drivers via the "gpio-ranges" property. 516e78d57b2SSean Wang */ 517e78d57b2SSean Wang if (!of_find_property(np, "gpio-ranges", NULL)) { 518e78d57b2SSean Wang ret = gpiochip_add_pin_range(chip, dev_name(hw->dev), 0, 0, 519e78d57b2SSean Wang chip->ngpio); 520e78d57b2SSean Wang if (ret < 0) { 521e78d57b2SSean Wang gpiochip_remove(chip); 522e78d57b2SSean Wang return ret; 523e78d57b2SSean Wang } 524e78d57b2SSean Wang } 525e78d57b2SSean Wang 526e78d57b2SSean Wang return 0; 527e78d57b2SSean Wang } 528e78d57b2SSean Wang 529e78d57b2SSean Wang static int mtk_build_groups(struct mtk_pinctrl *hw) 530e78d57b2SSean Wang { 531e78d57b2SSean Wang int err, i; 532e78d57b2SSean Wang 533e78d57b2SSean Wang for (i = 0; i < hw->soc->ngrps; i++) { 534e78d57b2SSean Wang const struct group_desc *group = hw->soc->grps + i; 535e78d57b2SSean Wang 536e78d57b2SSean Wang err = pinctrl_generic_add_group(hw->pctrl, group->name, 537e78d57b2SSean Wang group->pins, group->num_pins, 538e78d57b2SSean Wang group->data); 539e78d57b2SSean Wang if (err < 0) { 540e78d57b2SSean Wang dev_err(hw->dev, "Failed to register group %s\n", 541e78d57b2SSean Wang group->name); 542e78d57b2SSean Wang return err; 543e78d57b2SSean Wang } 544e78d57b2SSean Wang } 545e78d57b2SSean Wang 546e78d57b2SSean Wang return 0; 547e78d57b2SSean Wang } 548e78d57b2SSean Wang 549e78d57b2SSean Wang static int mtk_build_functions(struct mtk_pinctrl *hw) 550e78d57b2SSean Wang { 551e78d57b2SSean Wang int i, err; 552e78d57b2SSean Wang 553e78d57b2SSean Wang for (i = 0; i < hw->soc->nfuncs ; i++) { 554e78d57b2SSean Wang const struct function_desc *func = hw->soc->funcs + i; 555e78d57b2SSean Wang 556e78d57b2SSean Wang err = pinmux_generic_add_function(hw->pctrl, func->name, 557e78d57b2SSean Wang func->group_names, 558e78d57b2SSean Wang func->num_group_names, 559e78d57b2SSean Wang func->data); 560e78d57b2SSean Wang if (err < 0) { 561e78d57b2SSean Wang dev_err(hw->dev, "Failed to register function %s\n", 562e78d57b2SSean Wang func->name); 563e78d57b2SSean Wang return err; 564e78d57b2SSean Wang } 565e78d57b2SSean Wang } 566e78d57b2SSean Wang 567e78d57b2SSean Wang return 0; 568e78d57b2SSean Wang } 569e78d57b2SSean Wang 570fb5fa8dcSSean Wang static int mtk_xt_find_eint_num(struct mtk_pinctrl *hw, 571fb5fa8dcSSean Wang unsigned long eint_n) 572fb5fa8dcSSean Wang { 573fb5fa8dcSSean Wang const struct mtk_pin_desc *desc; 574fb5fa8dcSSean Wang int i = 0; 575fb5fa8dcSSean Wang 576fb5fa8dcSSean Wang desc = (const struct mtk_pin_desc *)hw->soc->pins; 577fb5fa8dcSSean Wang 578fb5fa8dcSSean Wang while (i < hw->soc->npins) { 579fb5fa8dcSSean Wang if (desc[i].eint_n == eint_n) 580fb5fa8dcSSean Wang return desc[i].number; 581fb5fa8dcSSean Wang i++; 582fb5fa8dcSSean Wang } 583fb5fa8dcSSean Wang 584fb5fa8dcSSean Wang return EINT_NA; 585fb5fa8dcSSean Wang } 586fb5fa8dcSSean Wang 587e78d57b2SSean Wang static int mtk_xt_get_gpio_n(void *data, unsigned long eint_n, 588e78d57b2SSean Wang unsigned int *gpio_n, 589e78d57b2SSean Wang struct gpio_chip **gpio_chip) 590e78d57b2SSean Wang { 591e78d57b2SSean Wang struct mtk_pinctrl *hw = (struct mtk_pinctrl *)data; 592fb5fa8dcSSean Wang const struct mtk_pin_desc *desc; 593e78d57b2SSean Wang 594fb5fa8dcSSean Wang desc = (const struct mtk_pin_desc *)hw->soc->pins; 595e78d57b2SSean Wang *gpio_chip = &hw->chip; 596e78d57b2SSean Wang 597fb5fa8dcSSean Wang /* Be greedy to guess first gpio_n is equal to eint_n */ 598fb5fa8dcSSean Wang if (desc[eint_n].eint_n == eint_n) 599fb5fa8dcSSean Wang *gpio_n = eint_n; 600fb5fa8dcSSean Wang else 601fb5fa8dcSSean Wang *gpio_n = mtk_xt_find_eint_num(hw, eint_n); 602fb5fa8dcSSean Wang 603fb5fa8dcSSean Wang return *gpio_n == EINT_NA ? -EINVAL : 0; 604e78d57b2SSean Wang } 605e78d57b2SSean Wang 606e78d57b2SSean Wang static int mtk_xt_get_gpio_state(void *data, unsigned long eint_n) 607e78d57b2SSean Wang { 608e78d57b2SSean Wang struct mtk_pinctrl *hw = (struct mtk_pinctrl *)data; 609e78d57b2SSean Wang struct gpio_chip *gpio_chip; 610e78d57b2SSean Wang unsigned int gpio_n; 611e78d57b2SSean Wang int err; 612e78d57b2SSean Wang 613e78d57b2SSean Wang err = mtk_xt_get_gpio_n(hw, eint_n, &gpio_n, &gpio_chip); 614e78d57b2SSean Wang if (err) 615e78d57b2SSean Wang return err; 616e78d57b2SSean Wang 617e78d57b2SSean Wang return mtk_gpio_get(gpio_chip, gpio_n); 618e78d57b2SSean Wang } 619e78d57b2SSean Wang 620e78d57b2SSean Wang static int mtk_xt_set_gpio_as_eint(void *data, unsigned long eint_n) 621e78d57b2SSean Wang { 622e78d57b2SSean Wang struct mtk_pinctrl *hw = (struct mtk_pinctrl *)data; 623e78d57b2SSean Wang struct gpio_chip *gpio_chip; 624e78d57b2SSean Wang unsigned int gpio_n; 625e78d57b2SSean Wang int err; 626e78d57b2SSean Wang 627e78d57b2SSean Wang err = mtk_xt_get_gpio_n(hw, eint_n, &gpio_n, &gpio_chip); 628e78d57b2SSean Wang if (err) 629e78d57b2SSean Wang return err; 630e78d57b2SSean Wang 631e78d57b2SSean Wang err = mtk_hw_set_value(hw, gpio_n, PINCTRL_PIN_REG_MODE, 6321dc5e536SSean Wang hw->soc->eint_m); 633e78d57b2SSean Wang if (err) 634e78d57b2SSean Wang return err; 635e78d57b2SSean Wang 636e78d57b2SSean Wang err = mtk_hw_set_value(hw, gpio_n, PINCTRL_PIN_REG_DIR, MTK_INPUT); 637e78d57b2SSean Wang if (err) 638e78d57b2SSean Wang return err; 639e78d57b2SSean Wang 640e78d57b2SSean Wang err = mtk_hw_set_value(hw, gpio_n, PINCTRL_PIN_REG_SMT, MTK_ENABLE); 641e78d57b2SSean Wang if (err) 642e78d57b2SSean Wang return err; 643e78d57b2SSean Wang 644e78d57b2SSean Wang return 0; 645e78d57b2SSean Wang } 646e78d57b2SSean Wang 647e78d57b2SSean Wang static const struct mtk_eint_xt mtk_eint_xt = { 648e78d57b2SSean Wang .get_gpio_n = mtk_xt_get_gpio_n, 649e78d57b2SSean Wang .get_gpio_state = mtk_xt_get_gpio_state, 650e78d57b2SSean Wang .set_gpio_as_eint = mtk_xt_set_gpio_as_eint, 651e78d57b2SSean Wang }; 652e78d57b2SSean Wang 653e78d57b2SSean Wang static int 654e78d57b2SSean Wang mtk_build_eint(struct mtk_pinctrl *hw, struct platform_device *pdev) 655e78d57b2SSean Wang { 656e78d57b2SSean Wang struct device_node *np = pdev->dev.of_node; 657e78d57b2SSean Wang struct resource *res; 658e78d57b2SSean Wang 659e78d57b2SSean Wang if (!IS_ENABLED(CONFIG_EINT_MTK)) 660e78d57b2SSean Wang return 0; 661e78d57b2SSean Wang 662e78d57b2SSean Wang if (!of_property_read_bool(np, "interrupt-controller")) 663e78d57b2SSean Wang return -ENODEV; 664e78d57b2SSean Wang 665e78d57b2SSean Wang hw->eint = devm_kzalloc(hw->dev, sizeof(*hw->eint), GFP_KERNEL); 666e78d57b2SSean Wang if (!hw->eint) 667e78d57b2SSean Wang return -ENOMEM; 668e78d57b2SSean Wang 669e78d57b2SSean Wang res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "eint"); 670e78d57b2SSean Wang if (!res) { 671e78d57b2SSean Wang dev_err(&pdev->dev, "Unable to get eint resource\n"); 672e78d57b2SSean Wang return -ENODEV; 673e78d57b2SSean Wang } 674e78d57b2SSean Wang 675e78d57b2SSean Wang hw->eint->base = devm_ioremap_resource(&pdev->dev, res); 676e78d57b2SSean Wang if (IS_ERR(hw->eint->base)) 677e78d57b2SSean Wang return PTR_ERR(hw->eint->base); 678e78d57b2SSean Wang 679e78d57b2SSean Wang hw->eint->irq = irq_of_parse_and_map(np, 0); 680e78d57b2SSean Wang if (!hw->eint->irq) 681e78d57b2SSean Wang return -EINVAL; 682e78d57b2SSean Wang 683e78d57b2SSean Wang hw->eint->dev = &pdev->dev; 684e78d57b2SSean Wang hw->eint->hw = hw->soc->eint_hw; 685e78d57b2SSean Wang hw->eint->pctl = hw; 686e78d57b2SSean Wang hw->eint->gpio_xlate = &mtk_eint_xt; 687e78d57b2SSean Wang 688e78d57b2SSean Wang return mtk_eint_do_init(hw->eint); 689e78d57b2SSean Wang } 690e78d57b2SSean Wang 691e78d57b2SSean Wang int mtk_moore_pinctrl_probe(struct platform_device *pdev, 692e78d57b2SSean Wang const struct mtk_pin_soc *soc) 693e78d57b2SSean Wang { 694e78d57b2SSean Wang struct resource *res; 695e78d57b2SSean Wang struct mtk_pinctrl *hw; 696e78d57b2SSean Wang int err; 697e78d57b2SSean Wang 698e78d57b2SSean Wang hw = devm_kzalloc(&pdev->dev, sizeof(*hw), GFP_KERNEL); 699e78d57b2SSean Wang if (!hw) 700e78d57b2SSean Wang return -ENOMEM; 701e78d57b2SSean Wang 702e78d57b2SSean Wang hw->soc = soc; 703e78d57b2SSean Wang 704e78d57b2SSean Wang res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 705e78d57b2SSean Wang if (!res) { 706e78d57b2SSean Wang dev_err(&pdev->dev, "missing IO resource\n"); 707e78d57b2SSean Wang return -ENXIO; 708e78d57b2SSean Wang } 709e78d57b2SSean Wang 710e78d57b2SSean Wang hw->dev = &pdev->dev; 711e78d57b2SSean Wang hw->base = devm_ioremap_resource(&pdev->dev, res); 712e78d57b2SSean Wang if (IS_ERR(hw->base)) 713e78d57b2SSean Wang return PTR_ERR(hw->base); 714e78d57b2SSean Wang 715e78d57b2SSean Wang /* Setup pins descriptions per SoC types */ 716fb5fa8dcSSean Wang mtk_desc.pins = (const struct pinctrl_pin_desc *)hw->soc->pins; 717e78d57b2SSean Wang mtk_desc.npins = hw->soc->npins; 718e78d57b2SSean Wang mtk_desc.num_custom_params = ARRAY_SIZE(mtk_custom_bindings); 719e78d57b2SSean Wang mtk_desc.custom_params = mtk_custom_bindings; 720e78d57b2SSean Wang #ifdef CONFIG_DEBUG_FS 721e78d57b2SSean Wang mtk_desc.custom_conf_items = mtk_conf_items; 722e78d57b2SSean Wang #endif 723e78d57b2SSean Wang 724e78d57b2SSean Wang err = devm_pinctrl_register_and_init(&pdev->dev, &mtk_desc, hw, 725e78d57b2SSean Wang &hw->pctrl); 726e78d57b2SSean Wang if (err) 727e78d57b2SSean Wang return err; 728e78d57b2SSean Wang 729e78d57b2SSean Wang /* Setup groups descriptions per SoC types */ 730e78d57b2SSean Wang err = mtk_build_groups(hw); 731e78d57b2SSean Wang if (err) { 732e78d57b2SSean Wang dev_err(&pdev->dev, "Failed to build groups\n"); 733e78d57b2SSean Wang return err; 734e78d57b2SSean Wang } 735e78d57b2SSean Wang 736e78d57b2SSean Wang /* Setup functions descriptions per SoC types */ 737e78d57b2SSean Wang err = mtk_build_functions(hw); 738e78d57b2SSean Wang if (err) { 739e78d57b2SSean Wang dev_err(&pdev->dev, "Failed to build functions\n"); 740e78d57b2SSean Wang return err; 741e78d57b2SSean Wang } 742e78d57b2SSean Wang 743e78d57b2SSean Wang /* For able to make pinctrl_claim_hogs, we must not enable pinctrl 744e78d57b2SSean Wang * until all groups and functions are being added one. 745e78d57b2SSean Wang */ 746e78d57b2SSean Wang err = pinctrl_enable(hw->pctrl); 747e78d57b2SSean Wang if (err) 748e78d57b2SSean Wang return err; 749e78d57b2SSean Wang 750e78d57b2SSean Wang err = mtk_build_eint(hw, pdev); 751e78d57b2SSean Wang if (err) 752e78d57b2SSean Wang dev_warn(&pdev->dev, 753e78d57b2SSean Wang "Failed to add EINT, but pinctrl still can work\n"); 754e78d57b2SSean Wang 755e78d57b2SSean Wang /* Build gpiochip should be after pinctrl_enable is done */ 756e78d57b2SSean Wang err = mtk_build_gpiochip(hw, pdev->dev.of_node); 757e78d57b2SSean Wang if (err) { 758e78d57b2SSean Wang dev_err(&pdev->dev, "Failed to add gpio_chip\n"); 759e78d57b2SSean Wang return err; 760e78d57b2SSean Wang } 761e78d57b2SSean Wang 762e78d57b2SSean Wang platform_set_drvdata(pdev, hw); 763e78d57b2SSean Wang 764e78d57b2SSean Wang return 0; 765e78d57b2SSean Wang } 766