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 1122d7fe49SLinus Walleij #include <linux/gpio/driver.h> 12e78d57b2SSean Wang #include "pinctrl-moore.h" 13e78d57b2SSean Wang 14e78d57b2SSean Wang #define PINCTRL_PINCTRL_DEV KBUILD_MODNAME 15e78d57b2SSean Wang 16e78d57b2SSean Wang /* Custom pinconf parameters */ 17e78d57b2SSean Wang #define MTK_PIN_CONFIG_TDSEL (PIN_CONFIG_END + 1) 18e78d57b2SSean Wang #define MTK_PIN_CONFIG_RDSEL (PIN_CONFIG_END + 2) 190d7ca772SSean Wang #define MTK_PIN_CONFIG_PU_ADV (PIN_CONFIG_END + 3) 200d7ca772SSean Wang #define MTK_PIN_CONFIG_PD_ADV (PIN_CONFIG_END + 4) 21e78d57b2SSean Wang 22e78d57b2SSean Wang static const struct pinconf_generic_params mtk_custom_bindings[] = { 23e78d57b2SSean Wang {"mediatek,tdsel", MTK_PIN_CONFIG_TDSEL, 0}, 24e78d57b2SSean Wang {"mediatek,rdsel", MTK_PIN_CONFIG_RDSEL, 0}, 250d7ca772SSean Wang {"mediatek,pull-up-adv", MTK_PIN_CONFIG_PU_ADV, 1}, 260d7ca772SSean Wang {"mediatek,pull-down-adv", MTK_PIN_CONFIG_PD_ADV, 1}, 27e78d57b2SSean Wang }; 28e78d57b2SSean Wang 29e78d57b2SSean Wang #ifdef CONFIG_DEBUG_FS 30e78d57b2SSean Wang static const struct pin_config_item mtk_conf_items[] = { 31e78d57b2SSean Wang PCONFDUMP(MTK_PIN_CONFIG_TDSEL, "tdsel", NULL, true), 32e78d57b2SSean Wang PCONFDUMP(MTK_PIN_CONFIG_RDSEL, "rdsel", NULL, true), 330d7ca772SSean Wang PCONFDUMP(MTK_PIN_CONFIG_PU_ADV, "pu-adv", NULL, true), 340d7ca772SSean Wang PCONFDUMP(MTK_PIN_CONFIG_PD_ADV, "pd-adv", NULL, true), 35e78d57b2SSean Wang }; 36e78d57b2SSean Wang #endif 37e78d57b2SSean Wang 38e78d57b2SSean Wang static int mtk_pinmux_set_mux(struct pinctrl_dev *pctldev, 39e78d57b2SSean Wang unsigned int selector, unsigned int group) 40e78d57b2SSean Wang { 41e78d57b2SSean Wang struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 42e78d57b2SSean Wang struct function_desc *func; 43e78d57b2SSean Wang struct group_desc *grp; 44e78d57b2SSean Wang int i; 45e78d57b2SSean Wang 46e78d57b2SSean Wang func = pinmux_generic_get_function(pctldev, selector); 47e78d57b2SSean Wang if (!func) 48e78d57b2SSean Wang return -EINVAL; 49e78d57b2SSean Wang 50e78d57b2SSean Wang grp = pinctrl_generic_get_group(pctldev, group); 51e78d57b2SSean Wang if (!grp) 52e78d57b2SSean Wang return -EINVAL; 53e78d57b2SSean Wang 54e78d57b2SSean Wang dev_dbg(pctldev->dev, "enable function %s group %s\n", 55e78d57b2SSean Wang func->name, grp->name); 56e78d57b2SSean Wang 57e78d57b2SSean Wang for (i = 0; i < grp->num_pins; i++) { 58ea051eb3SSean Wang const struct mtk_pin_desc *desc; 59e78d57b2SSean Wang int *pin_modes = grp->data; 60ea051eb3SSean Wang int pin = grp->pins[i]; 61e78d57b2SSean Wang 62ea051eb3SSean Wang desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; 63ea051eb3SSean Wang 64ea051eb3SSean Wang mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_MODE, 65e78d57b2SSean Wang pin_modes[i]); 66e78d57b2SSean Wang } 67e78d57b2SSean Wang 68e78d57b2SSean Wang return 0; 69e78d57b2SSean Wang } 70e78d57b2SSean Wang 71e78d57b2SSean Wang static int mtk_pinmux_gpio_request_enable(struct pinctrl_dev *pctldev, 72e78d57b2SSean Wang struct pinctrl_gpio_range *range, 73e78d57b2SSean Wang unsigned int pin) 74e78d57b2SSean Wang { 75e78d57b2SSean Wang struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 76ea051eb3SSean Wang const struct mtk_pin_desc *desc; 77e78d57b2SSean Wang 78ea051eb3SSean Wang desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; 79ea051eb3SSean Wang 80ea051eb3SSean Wang return mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_MODE, 81ea051eb3SSean Wang hw->soc->gpio_m); 82e78d57b2SSean Wang } 83e78d57b2SSean Wang 84e78d57b2SSean Wang static int mtk_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev, 85e78d57b2SSean Wang struct pinctrl_gpio_range *range, 86e78d57b2SSean Wang unsigned int pin, bool input) 87e78d57b2SSean Wang { 88e78d57b2SSean Wang struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 89ea051eb3SSean Wang const struct mtk_pin_desc *desc; 90ea051eb3SSean Wang 91ea051eb3SSean Wang desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; 92e78d57b2SSean Wang 93e78d57b2SSean Wang /* hardware would take 0 as input direction */ 94ea051eb3SSean Wang return mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR, !input); 95e78d57b2SSean Wang } 96e78d57b2SSean Wang 97e78d57b2SSean Wang static int mtk_pinconf_get(struct pinctrl_dev *pctldev, 98e78d57b2SSean Wang unsigned int pin, unsigned long *config) 99e78d57b2SSean Wang { 100e78d57b2SSean Wang struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 101e78d57b2SSean Wang u32 param = pinconf_to_config_param(*config); 102e78d57b2SSean Wang int val, val2, err, reg, ret = 1; 103c2832197SSean Wang const struct mtk_pin_desc *desc; 104c2832197SSean Wang 105c2832197SSean Wang desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; 106e78d57b2SSean Wang 107e78d57b2SSean Wang switch (param) { 108e78d57b2SSean Wang case PIN_CONFIG_BIAS_DISABLE: 10985430152SSean Wang if (hw->soc->bias_disable_get) { 11085430152SSean Wang err = hw->soc->bias_disable_get(hw, desc, &ret); 111e78d57b2SSean Wang if (err) 112e78d57b2SSean Wang return err; 11385430152SSean Wang } else { 11485430152SSean Wang return -ENOTSUPP; 11585430152SSean Wang } 116e78d57b2SSean Wang break; 117e78d57b2SSean Wang case PIN_CONFIG_BIAS_PULL_UP: 11885430152SSean Wang if (hw->soc->bias_get) { 11985430152SSean Wang err = hw->soc->bias_get(hw, desc, 1, &ret); 12085430152SSean Wang if (err) 12185430152SSean Wang return err; 12285430152SSean Wang } else { 12385430152SSean Wang return -ENOTSUPP; 12485430152SSean Wang } 12585430152SSean Wang break; 126e78d57b2SSean Wang case PIN_CONFIG_BIAS_PULL_DOWN: 12785430152SSean Wang if (hw->soc->bias_get) { 12885430152SSean Wang err = hw->soc->bias_get(hw, desc, 0, &ret); 12985430152SSean Wang if (err) 13085430152SSean Wang return err; 13185430152SSean Wang } else { 13285430152SSean Wang return -ENOTSUPP; 13385430152SSean Wang } 13485430152SSean Wang break; 135e78d57b2SSean Wang case PIN_CONFIG_SLEW_RATE: 136ea051eb3SSean Wang err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_SR, &val); 137e78d57b2SSean Wang if (err) 138e78d57b2SSean Wang return err; 139e78d57b2SSean Wang 140e78d57b2SSean Wang if (!val) 141e78d57b2SSean Wang return -EINVAL; 142e78d57b2SSean Wang 143e78d57b2SSean Wang break; 144e78d57b2SSean Wang case PIN_CONFIG_INPUT_ENABLE: 145e78d57b2SSean Wang case PIN_CONFIG_OUTPUT_ENABLE: 146ea051eb3SSean Wang err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DIR, &val); 147e78d57b2SSean Wang if (err) 148e78d57b2SSean Wang return err; 149e78d57b2SSean Wang 150e78d57b2SSean Wang /* HW takes input mode as zero; output mode as non-zero */ 151e78d57b2SSean Wang if ((val && param == PIN_CONFIG_INPUT_ENABLE) || 152e78d57b2SSean Wang (!val && param == PIN_CONFIG_OUTPUT_ENABLE)) 153e78d57b2SSean Wang return -EINVAL; 154e78d57b2SSean Wang 155e78d57b2SSean Wang break; 156e78d57b2SSean Wang case PIN_CONFIG_INPUT_SCHMITT_ENABLE: 157ea051eb3SSean Wang err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DIR, &val); 158e78d57b2SSean Wang if (err) 159e78d57b2SSean Wang return err; 160e78d57b2SSean Wang 161ea051eb3SSean Wang err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_SMT, &val2); 162e78d57b2SSean Wang if (err) 163e78d57b2SSean Wang return err; 164e78d57b2SSean Wang 165e78d57b2SSean Wang if (val || !val2) 166e78d57b2SSean Wang return -EINVAL; 167e78d57b2SSean Wang 168e78d57b2SSean Wang break; 169e78d57b2SSean Wang case PIN_CONFIG_DRIVE_STRENGTH: 170c2832197SSean Wang if (hw->soc->drive_get) { 171c2832197SSean Wang err = hw->soc->drive_get(hw, desc, &ret); 172e78d57b2SSean Wang if (err) 173e78d57b2SSean Wang return err; 174c2832197SSean Wang } else { 175c2832197SSean Wang err = -ENOTSUPP; 176c2832197SSean Wang } 177e78d57b2SSean Wang break; 178e78d57b2SSean Wang case MTK_PIN_CONFIG_TDSEL: 179e78d57b2SSean Wang case MTK_PIN_CONFIG_RDSEL: 180e78d57b2SSean Wang reg = (param == MTK_PIN_CONFIG_TDSEL) ? 181e78d57b2SSean Wang PINCTRL_PIN_REG_TDSEL : PINCTRL_PIN_REG_RDSEL; 182e78d57b2SSean Wang 183ea051eb3SSean Wang err = mtk_hw_get_value(hw, desc, reg, &val); 184e78d57b2SSean Wang if (err) 185e78d57b2SSean Wang return err; 186e78d57b2SSean Wang 187e78d57b2SSean Wang ret = val; 188e78d57b2SSean Wang 189e78d57b2SSean Wang break; 1900d7ca772SSean Wang case MTK_PIN_CONFIG_PU_ADV: 1910d7ca772SSean Wang case MTK_PIN_CONFIG_PD_ADV: 1920d7ca772SSean Wang if (hw->soc->adv_pull_get) { 1930d7ca772SSean Wang bool pullup; 1940d7ca772SSean Wang 1950d7ca772SSean Wang pullup = param == MTK_PIN_CONFIG_PU_ADV; 1960d7ca772SSean Wang err = hw->soc->adv_pull_get(hw, desc, pullup, &ret); 1970d7ca772SSean Wang if (err) 1980d7ca772SSean Wang return err; 1990d7ca772SSean Wang } else { 2000d7ca772SSean Wang return -ENOTSUPP; 2010d7ca772SSean Wang } 2020d7ca772SSean Wang break; 203e78d57b2SSean Wang default: 204e78d57b2SSean Wang return -ENOTSUPP; 205e78d57b2SSean Wang } 206e78d57b2SSean Wang 207e78d57b2SSean Wang *config = pinconf_to_config_packed(param, ret); 208e78d57b2SSean Wang 209e78d57b2SSean Wang return 0; 210e78d57b2SSean Wang } 211e78d57b2SSean Wang 212e78d57b2SSean Wang static int mtk_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, 213e78d57b2SSean Wang unsigned long *configs, unsigned int num_configs) 214e78d57b2SSean Wang { 215e78d57b2SSean Wang struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 216c2832197SSean Wang const struct mtk_pin_desc *desc; 217e78d57b2SSean Wang u32 reg, param, arg; 218e78d57b2SSean Wang int cfg, err = 0; 219e78d57b2SSean Wang 220c2832197SSean Wang desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; 221c2832197SSean Wang 222e78d57b2SSean Wang for (cfg = 0; cfg < num_configs; cfg++) { 223e78d57b2SSean Wang param = pinconf_to_config_param(configs[cfg]); 224e78d57b2SSean Wang arg = pinconf_to_config_argument(configs[cfg]); 225e78d57b2SSean Wang 226e78d57b2SSean Wang switch (param) { 227e78d57b2SSean Wang case PIN_CONFIG_BIAS_DISABLE: 22885430152SSean Wang if (hw->soc->bias_disable_set) { 22985430152SSean Wang err = hw->soc->bias_disable_set(hw, desc); 23085430152SSean Wang if (err) 23185430152SSean Wang return err; 23285430152SSean Wang } else { 23385430152SSean Wang return -ENOTSUPP; 23485430152SSean Wang } 23585430152SSean Wang break; 236e78d57b2SSean Wang case PIN_CONFIG_BIAS_PULL_UP: 23785430152SSean Wang if (hw->soc->bias_set) { 23885430152SSean Wang err = hw->soc->bias_set(hw, desc, 1); 23985430152SSean Wang if (err) 24085430152SSean Wang return err; 24185430152SSean Wang } else { 24285430152SSean Wang return -ENOTSUPP; 24385430152SSean Wang } 24485430152SSean Wang break; 245e78d57b2SSean Wang case PIN_CONFIG_BIAS_PULL_DOWN: 24685430152SSean Wang if (hw->soc->bias_set) { 24785430152SSean Wang err = hw->soc->bias_set(hw, desc, 0); 248e78d57b2SSean Wang if (err) 24985430152SSean Wang return err; 25085430152SSean Wang } else { 25185430152SSean Wang return -ENOTSUPP; 25285430152SSean Wang } 253e78d57b2SSean Wang break; 254e78d57b2SSean Wang case PIN_CONFIG_OUTPUT_ENABLE: 255ea051eb3SSean Wang err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_SMT, 256e78d57b2SSean Wang MTK_DISABLE); 257e78d57b2SSean Wang if (err) 258e78d57b2SSean Wang goto err; 259e78d57b2SSean Wang 260ea051eb3SSean Wang err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR, 261182c842fSSean Wang MTK_OUTPUT); 262182c842fSSean Wang if (err) 263182c842fSSean Wang goto err; 264182c842fSSean Wang break; 265182c842fSSean Wang case PIN_CONFIG_INPUT_ENABLE: 266182c842fSSean Wang 267182c842fSSean Wang if (hw->soc->ies_present) { 268ea051eb3SSean Wang mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_IES, 269182c842fSSean Wang MTK_ENABLE); 270182c842fSSean Wang } 271182c842fSSean Wang 272ea051eb3SSean Wang err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR, 273182c842fSSean Wang MTK_INPUT); 274182c842fSSean Wang if (err) 275182c842fSSean Wang goto err; 276182c842fSSean Wang break; 277182c842fSSean Wang case PIN_CONFIG_SLEW_RATE: 278ea051eb3SSean Wang err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_SR, 279182c842fSSean Wang arg); 280e78d57b2SSean Wang if (err) 281e78d57b2SSean Wang goto err; 282e78d57b2SSean Wang 283e78d57b2SSean Wang break; 284e78d57b2SSean Wang case PIN_CONFIG_OUTPUT: 285ea051eb3SSean Wang err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR, 286e78d57b2SSean Wang MTK_OUTPUT); 287e78d57b2SSean Wang if (err) 288e78d57b2SSean Wang goto err; 289e78d57b2SSean Wang 290ea051eb3SSean Wang err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DO, 291e78d57b2SSean Wang arg); 292e78d57b2SSean Wang if (err) 293e78d57b2SSean Wang goto err; 294e78d57b2SSean Wang break; 295e78d57b2SSean Wang case PIN_CONFIG_INPUT_SCHMITT_ENABLE: 296e78d57b2SSean Wang /* arg = 1: Input mode & SMT enable ; 297e78d57b2SSean Wang * arg = 0: Output mode & SMT disable 298e78d57b2SSean Wang */ 299e78d57b2SSean Wang arg = arg ? 2 : 1; 300ea051eb3SSean Wang err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR, 301e78d57b2SSean Wang arg & 1); 302e78d57b2SSean Wang if (err) 303e78d57b2SSean Wang goto err; 304e78d57b2SSean Wang 305ea051eb3SSean Wang err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_SMT, 306e78d57b2SSean Wang !!(arg & 2)); 307e78d57b2SSean Wang if (err) 308e78d57b2SSean Wang goto err; 309e78d57b2SSean Wang break; 310e78d57b2SSean Wang case PIN_CONFIG_DRIVE_STRENGTH: 311c2832197SSean Wang if (hw->soc->drive_set) { 312c2832197SSean Wang err = hw->soc->drive_set(hw, desc, arg); 313e78d57b2SSean Wang if (err) 314c2832197SSean Wang return err; 315e78d57b2SSean Wang } else { 316e78d57b2SSean Wang err = -ENOTSUPP; 317e78d57b2SSean Wang } 318e78d57b2SSean Wang break; 319e78d57b2SSean Wang case MTK_PIN_CONFIG_TDSEL: 320e78d57b2SSean Wang case MTK_PIN_CONFIG_RDSEL: 321e78d57b2SSean Wang reg = (param == MTK_PIN_CONFIG_TDSEL) ? 322e78d57b2SSean Wang PINCTRL_PIN_REG_TDSEL : PINCTRL_PIN_REG_RDSEL; 323e78d57b2SSean Wang 324ea051eb3SSean Wang err = mtk_hw_set_value(hw, desc, reg, arg); 325e78d57b2SSean Wang if (err) 326e78d57b2SSean Wang goto err; 327e78d57b2SSean Wang break; 3280d7ca772SSean Wang case MTK_PIN_CONFIG_PU_ADV: 3290d7ca772SSean Wang case MTK_PIN_CONFIG_PD_ADV: 3300d7ca772SSean Wang if (hw->soc->adv_pull_set) { 3310d7ca772SSean Wang bool pullup; 3320d7ca772SSean Wang 3330d7ca772SSean Wang pullup = param == MTK_PIN_CONFIG_PU_ADV; 3340d7ca772SSean Wang err = hw->soc->adv_pull_set(hw, desc, pullup, 3350d7ca772SSean Wang arg); 3360d7ca772SSean Wang if (err) 3370d7ca772SSean Wang return err; 3380d7ca772SSean Wang } else { 3390d7ca772SSean Wang return -ENOTSUPP; 3400d7ca772SSean Wang } 3410d7ca772SSean Wang break; 342e78d57b2SSean Wang default: 343e78d57b2SSean Wang err = -ENOTSUPP; 344e78d57b2SSean Wang } 345e78d57b2SSean Wang } 346e78d57b2SSean Wang err: 347e78d57b2SSean Wang return err; 348e78d57b2SSean Wang } 349e78d57b2SSean Wang 350e78d57b2SSean Wang static int mtk_pinconf_group_get(struct pinctrl_dev *pctldev, 351e78d57b2SSean Wang unsigned int group, unsigned long *config) 352e78d57b2SSean Wang { 353e78d57b2SSean Wang const unsigned int *pins; 354e78d57b2SSean Wang unsigned int i, npins, old = 0; 355e78d57b2SSean Wang int ret; 356e78d57b2SSean Wang 357e78d57b2SSean Wang ret = pinctrl_generic_get_group_pins(pctldev, group, &pins, &npins); 358e78d57b2SSean Wang if (ret) 359e78d57b2SSean Wang return ret; 360e78d57b2SSean Wang 361e78d57b2SSean Wang for (i = 0; i < npins; i++) { 362e78d57b2SSean Wang if (mtk_pinconf_get(pctldev, pins[i], config)) 363e78d57b2SSean Wang return -ENOTSUPP; 364e78d57b2SSean Wang 365e78d57b2SSean Wang /* configs do not match between two pins */ 366e78d57b2SSean Wang if (i && old != *config) 367e78d57b2SSean Wang return -ENOTSUPP; 368e78d57b2SSean Wang 369e78d57b2SSean Wang old = *config; 370e78d57b2SSean Wang } 371e78d57b2SSean Wang 372e78d57b2SSean Wang return 0; 373e78d57b2SSean Wang } 374e78d57b2SSean Wang 375e78d57b2SSean Wang static int mtk_pinconf_group_set(struct pinctrl_dev *pctldev, 376e78d57b2SSean Wang unsigned int group, unsigned long *configs, 377e78d57b2SSean Wang unsigned int num_configs) 378e78d57b2SSean Wang { 379e78d57b2SSean Wang const unsigned int *pins; 380e78d57b2SSean Wang unsigned int i, npins; 381e78d57b2SSean Wang int ret; 382e78d57b2SSean Wang 383e78d57b2SSean Wang ret = pinctrl_generic_get_group_pins(pctldev, group, &pins, &npins); 384e78d57b2SSean Wang if (ret) 385e78d57b2SSean Wang return ret; 386e78d57b2SSean Wang 387e78d57b2SSean Wang for (i = 0; i < npins; i++) { 388e78d57b2SSean Wang ret = mtk_pinconf_set(pctldev, pins[i], configs, num_configs); 389e78d57b2SSean Wang if (ret) 390e78d57b2SSean Wang return ret; 391e78d57b2SSean Wang } 392e78d57b2SSean Wang 393e78d57b2SSean Wang return 0; 394e78d57b2SSean Wang } 395e78d57b2SSean Wang 396e78d57b2SSean Wang static const struct pinctrl_ops mtk_pctlops = { 397e78d57b2SSean Wang .get_groups_count = pinctrl_generic_get_group_count, 398e78d57b2SSean Wang .get_group_name = pinctrl_generic_get_group_name, 399e78d57b2SSean Wang .get_group_pins = pinctrl_generic_get_group_pins, 400e78d57b2SSean Wang .dt_node_to_map = pinconf_generic_dt_node_to_map_all, 401e78d57b2SSean Wang .dt_free_map = pinconf_generic_dt_free_map, 402e78d57b2SSean Wang }; 403e78d57b2SSean Wang 404e78d57b2SSean Wang static const struct pinmux_ops mtk_pmxops = { 405e78d57b2SSean Wang .get_functions_count = pinmux_generic_get_function_count, 406e78d57b2SSean Wang .get_function_name = pinmux_generic_get_function_name, 407e78d57b2SSean Wang .get_function_groups = pinmux_generic_get_function_groups, 408e78d57b2SSean Wang .set_mux = mtk_pinmux_set_mux, 409e78d57b2SSean Wang .gpio_request_enable = mtk_pinmux_gpio_request_enable, 410e78d57b2SSean Wang .gpio_set_direction = mtk_pinmux_gpio_set_direction, 411e78d57b2SSean Wang .strict = true, 412e78d57b2SSean Wang }; 413e78d57b2SSean Wang 414e78d57b2SSean Wang static const struct pinconf_ops mtk_confops = { 415e78d57b2SSean Wang .is_generic = true, 416e78d57b2SSean Wang .pin_config_get = mtk_pinconf_get, 417e78d57b2SSean Wang .pin_config_set = mtk_pinconf_set, 418e78d57b2SSean Wang .pin_config_group_get = mtk_pinconf_group_get, 419e78d57b2SSean Wang .pin_config_group_set = mtk_pinconf_group_set, 420e78d57b2SSean Wang .pin_config_config_dbg_show = pinconf_generic_dump_config, 421e78d57b2SSean Wang }; 422e78d57b2SSean Wang 423e78d57b2SSean Wang static struct pinctrl_desc mtk_desc = { 424e78d57b2SSean Wang .name = PINCTRL_PINCTRL_DEV, 425e78d57b2SSean Wang .pctlops = &mtk_pctlops, 426e78d57b2SSean Wang .pmxops = &mtk_pmxops, 427e78d57b2SSean Wang .confops = &mtk_confops, 428e78d57b2SSean Wang .owner = THIS_MODULE, 429e78d57b2SSean Wang }; 430e78d57b2SSean Wang 431e78d57b2SSean Wang static int mtk_gpio_get(struct gpio_chip *chip, unsigned int gpio) 432e78d57b2SSean Wang { 433e78d57b2SSean Wang struct mtk_pinctrl *hw = gpiochip_get_data(chip); 434ea051eb3SSean Wang const struct mtk_pin_desc *desc; 435e78d57b2SSean Wang int value, err; 436e78d57b2SSean Wang 437ea051eb3SSean Wang desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio]; 438ea051eb3SSean Wang 439ea051eb3SSean Wang err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DI, &value); 440e78d57b2SSean Wang if (err) 441e78d57b2SSean Wang return err; 442e78d57b2SSean Wang 443e78d57b2SSean Wang return !!value; 444e78d57b2SSean Wang } 445e78d57b2SSean Wang 446e78d57b2SSean Wang static void mtk_gpio_set(struct gpio_chip *chip, unsigned int gpio, int value) 447e78d57b2SSean Wang { 448e78d57b2SSean Wang struct mtk_pinctrl *hw = gpiochip_get_data(chip); 449ea051eb3SSean Wang const struct mtk_pin_desc *desc; 450e78d57b2SSean Wang 451ea051eb3SSean Wang desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio]; 452ea051eb3SSean Wang 453ea051eb3SSean Wang mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DO, !!value); 454e78d57b2SSean Wang } 455e78d57b2SSean Wang 456e78d57b2SSean Wang static int mtk_gpio_direction_input(struct gpio_chip *chip, unsigned int gpio) 457e78d57b2SSean Wang { 458e78d57b2SSean Wang return pinctrl_gpio_direction_input(chip->base + gpio); 459e78d57b2SSean Wang } 460e78d57b2SSean Wang 461e78d57b2SSean Wang static int mtk_gpio_direction_output(struct gpio_chip *chip, unsigned int gpio, 462e78d57b2SSean Wang int value) 463e78d57b2SSean Wang { 464e78d57b2SSean Wang mtk_gpio_set(chip, gpio, value); 465e78d57b2SSean Wang 466e78d57b2SSean Wang return pinctrl_gpio_direction_output(chip->base + gpio); 467e78d57b2SSean Wang } 468e78d57b2SSean Wang 469e78d57b2SSean Wang static int mtk_gpio_to_irq(struct gpio_chip *chip, unsigned int offset) 470e78d57b2SSean Wang { 471e78d57b2SSean Wang struct mtk_pinctrl *hw = gpiochip_get_data(chip); 472fb5fa8dcSSean Wang const struct mtk_pin_desc *desc; 473e78d57b2SSean Wang 474e78d57b2SSean Wang if (!hw->eint) 475e78d57b2SSean Wang return -ENOTSUPP; 476e78d57b2SSean Wang 477fb5fa8dcSSean Wang desc = (const struct mtk_pin_desc *)&hw->soc->pins[offset]; 478e78d57b2SSean Wang 4797a52127eSColin Ian King if (desc->eint.eint_n == (u16)EINT_NA) 480fb5fa8dcSSean Wang return -ENOTSUPP; 481fb5fa8dcSSean Wang 482b7d7f9eeSSean Wang return mtk_eint_find_irq(hw->eint, desc->eint.eint_n); 483e78d57b2SSean Wang } 484e78d57b2SSean Wang 485e78d57b2SSean Wang static int mtk_gpio_set_config(struct gpio_chip *chip, unsigned int offset, 486e78d57b2SSean Wang unsigned long config) 487e78d57b2SSean Wang { 488e78d57b2SSean Wang struct mtk_pinctrl *hw = gpiochip_get_data(chip); 489fb5fa8dcSSean Wang const struct mtk_pin_desc *desc; 490e78d57b2SSean Wang u32 debounce; 491e78d57b2SSean Wang 492fb5fa8dcSSean Wang desc = (const struct mtk_pin_desc *)&hw->soc->pins[offset]; 493fb5fa8dcSSean Wang 494e78d57b2SSean Wang if (!hw->eint || 495fb5fa8dcSSean Wang pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE || 4967a52127eSColin Ian King desc->eint.eint_n == (u16)EINT_NA) 497e78d57b2SSean Wang return -ENOTSUPP; 498e78d57b2SSean Wang 499e78d57b2SSean Wang debounce = pinconf_to_config_argument(config); 500e78d57b2SSean Wang 501b7d7f9eeSSean Wang return mtk_eint_set_debounce(hw->eint, desc->eint.eint_n, debounce); 502e78d57b2SSean Wang } 503e78d57b2SSean Wang 504e78d57b2SSean Wang static int mtk_build_gpiochip(struct mtk_pinctrl *hw, struct device_node *np) 505e78d57b2SSean Wang { 506e78d57b2SSean Wang struct gpio_chip *chip = &hw->chip; 507e78d57b2SSean Wang int ret; 508e78d57b2SSean Wang 509e78d57b2SSean Wang chip->label = PINCTRL_PINCTRL_DEV; 510e78d57b2SSean Wang chip->parent = hw->dev; 511e78d57b2SSean Wang chip->request = gpiochip_generic_request; 512e78d57b2SSean Wang chip->free = gpiochip_generic_free; 513e78d57b2SSean Wang chip->direction_input = mtk_gpio_direction_input; 514e78d57b2SSean Wang chip->direction_output = mtk_gpio_direction_output; 515e78d57b2SSean Wang chip->get = mtk_gpio_get; 516e78d57b2SSean Wang chip->set = mtk_gpio_set; 5170014d7a9SZheng Yongjun chip->to_irq = mtk_gpio_to_irq; 5180014d7a9SZheng Yongjun chip->set_config = mtk_gpio_set_config; 519e78d57b2SSean Wang chip->base = -1; 520e78d57b2SSean Wang chip->ngpio = hw->soc->npins; 521e78d57b2SSean Wang chip->of_node = np; 522e78d57b2SSean Wang chip->of_gpio_n_cells = 2; 523e78d57b2SSean Wang 524e78d57b2SSean Wang ret = gpiochip_add_data(chip, hw); 525e78d57b2SSean Wang if (ret < 0) 526e78d57b2SSean Wang return ret; 527e78d57b2SSean Wang 528e78d57b2SSean Wang /* Just for backward compatible for these old pinctrl nodes without 529e78d57b2SSean Wang * "gpio-ranges" property. Otherwise, called directly from a 530e78d57b2SSean Wang * DeviceTree-supported pinctrl driver is DEPRECATED. 531e78d57b2SSean Wang * Please see Section 2.1 of 532e78d57b2SSean Wang * Documentation/devicetree/bindings/gpio/gpio.txt on how to 533e78d57b2SSean Wang * bind pinctrl and gpio drivers via the "gpio-ranges" property. 534e78d57b2SSean Wang */ 535e78d57b2SSean Wang if (!of_find_property(np, "gpio-ranges", NULL)) { 536e78d57b2SSean Wang ret = gpiochip_add_pin_range(chip, dev_name(hw->dev), 0, 0, 537e78d57b2SSean Wang chip->ngpio); 538e78d57b2SSean Wang if (ret < 0) { 539e78d57b2SSean Wang gpiochip_remove(chip); 540e78d57b2SSean Wang return ret; 541e78d57b2SSean Wang } 542e78d57b2SSean Wang } 543e78d57b2SSean Wang 544e78d57b2SSean Wang return 0; 545e78d57b2SSean Wang } 546e78d57b2SSean Wang 547e78d57b2SSean Wang static int mtk_build_groups(struct mtk_pinctrl *hw) 548e78d57b2SSean Wang { 549e78d57b2SSean Wang int err, i; 550e78d57b2SSean Wang 551e78d57b2SSean Wang for (i = 0; i < hw->soc->ngrps; i++) { 552e78d57b2SSean Wang const struct group_desc *group = hw->soc->grps + i; 553e78d57b2SSean Wang 554e78d57b2SSean Wang err = pinctrl_generic_add_group(hw->pctrl, group->name, 555e78d57b2SSean Wang group->pins, group->num_pins, 556e78d57b2SSean Wang group->data); 557e78d57b2SSean Wang if (err < 0) { 558e78d57b2SSean Wang dev_err(hw->dev, "Failed to register group %s\n", 559e78d57b2SSean Wang group->name); 560e78d57b2SSean Wang return err; 561e78d57b2SSean Wang } 562e78d57b2SSean Wang } 563e78d57b2SSean Wang 564e78d57b2SSean Wang return 0; 565e78d57b2SSean Wang } 566e78d57b2SSean Wang 567e78d57b2SSean Wang static int mtk_build_functions(struct mtk_pinctrl *hw) 568e78d57b2SSean Wang { 569e78d57b2SSean Wang int i, err; 570e78d57b2SSean Wang 571e78d57b2SSean Wang for (i = 0; i < hw->soc->nfuncs ; i++) { 572e78d57b2SSean Wang const struct function_desc *func = hw->soc->funcs + i; 573e78d57b2SSean Wang 574e78d57b2SSean Wang err = pinmux_generic_add_function(hw->pctrl, func->name, 575e78d57b2SSean Wang func->group_names, 576e78d57b2SSean Wang func->num_group_names, 577e78d57b2SSean Wang func->data); 578e78d57b2SSean Wang if (err < 0) { 579e78d57b2SSean Wang dev_err(hw->dev, "Failed to register function %s\n", 580e78d57b2SSean Wang func->name); 581e78d57b2SSean Wang return err; 582e78d57b2SSean Wang } 583e78d57b2SSean Wang } 584e78d57b2SSean Wang 585e78d57b2SSean Wang return 0; 586e78d57b2SSean Wang } 587e78d57b2SSean Wang 588e78d57b2SSean Wang int mtk_moore_pinctrl_probe(struct platform_device *pdev, 589e78d57b2SSean Wang const struct mtk_pin_soc *soc) 590e78d57b2SSean Wang { 591b7d7f9eeSSean Wang struct pinctrl_pin_desc *pins; 592e78d57b2SSean Wang struct mtk_pinctrl *hw; 5932bc47dfeSSean Wang int err, i; 594e78d57b2SSean Wang 595e78d57b2SSean Wang hw = devm_kzalloc(&pdev->dev, sizeof(*hw), GFP_KERNEL); 596e78d57b2SSean Wang if (!hw) 597e78d57b2SSean Wang return -ENOMEM; 598e78d57b2SSean Wang 599e78d57b2SSean Wang hw->soc = soc; 6002bc47dfeSSean Wang hw->dev = &pdev->dev; 601e78d57b2SSean Wang 6022bc47dfeSSean Wang if (!hw->soc->nbase_names) { 6032bc47dfeSSean Wang dev_err(&pdev->dev, 6042bc47dfeSSean Wang "SoC should be assigned at least one register base\n"); 6052bc47dfeSSean Wang return -EINVAL; 6062bc47dfeSSean Wang } 6072bc47dfeSSean Wang 6082bc47dfeSSean Wang hw->base = devm_kmalloc_array(&pdev->dev, hw->soc->nbase_names, 6092bc47dfeSSean Wang sizeof(*hw->base), GFP_KERNEL); 610068cfb9aSWei Yongjun if (!hw->base) 611068cfb9aSWei Yongjun return -ENOMEM; 6122bc47dfeSSean Wang 6132bc47dfeSSean Wang for (i = 0; i < hw->soc->nbase_names; i++) { 61448548c78SWang Xiaojun hw->base[i] = devm_platform_ioremap_resource_byname(pdev, 6152bc47dfeSSean Wang hw->soc->base_names[i]); 6162bc47dfeSSean Wang if (IS_ERR(hw->base[i])) 6172bc47dfeSSean Wang return PTR_ERR(hw->base[i]); 6182bc47dfeSSean Wang } 6192bc47dfeSSean Wang 6202bc47dfeSSean Wang hw->nbase = hw->soc->nbase_names; 621e78d57b2SSean Wang 622*56ab29ecSTzung-Bi Shih spin_lock_init(&hw->lock); 62342a46434SZhiyong Tao 624b7d7f9eeSSean Wang /* Copy from internal struct mtk_pin_desc to register to the core */ 625b7d7f9eeSSean Wang pins = devm_kmalloc_array(&pdev->dev, hw->soc->npins, sizeof(*pins), 626b7d7f9eeSSean Wang GFP_KERNEL); 627068cfb9aSWei Yongjun if (!pins) 628068cfb9aSWei Yongjun return -ENOMEM; 629b7d7f9eeSSean Wang 630b7d7f9eeSSean Wang for (i = 0; i < hw->soc->npins; i++) { 631b7d7f9eeSSean Wang pins[i].number = hw->soc->pins[i].number; 632b7d7f9eeSSean Wang pins[i].name = hw->soc->pins[i].name; 633b7d7f9eeSSean Wang } 634b7d7f9eeSSean Wang 635e78d57b2SSean Wang /* Setup pins descriptions per SoC types */ 636b7d7f9eeSSean Wang mtk_desc.pins = (const struct pinctrl_pin_desc *)pins; 637e78d57b2SSean Wang mtk_desc.npins = hw->soc->npins; 638e78d57b2SSean Wang mtk_desc.num_custom_params = ARRAY_SIZE(mtk_custom_bindings); 639e78d57b2SSean Wang mtk_desc.custom_params = mtk_custom_bindings; 640e78d57b2SSean Wang #ifdef CONFIG_DEBUG_FS 641e78d57b2SSean Wang mtk_desc.custom_conf_items = mtk_conf_items; 642e78d57b2SSean Wang #endif 643e78d57b2SSean Wang 644e78d57b2SSean Wang err = devm_pinctrl_register_and_init(&pdev->dev, &mtk_desc, hw, 645e78d57b2SSean Wang &hw->pctrl); 646e78d57b2SSean Wang if (err) 647e78d57b2SSean Wang return err; 648e78d57b2SSean Wang 649e78d57b2SSean Wang /* Setup groups descriptions per SoC types */ 650e78d57b2SSean Wang err = mtk_build_groups(hw); 651e78d57b2SSean Wang if (err) { 652e78d57b2SSean Wang dev_err(&pdev->dev, "Failed to build groups\n"); 653e78d57b2SSean Wang return err; 654e78d57b2SSean Wang } 655e78d57b2SSean Wang 656e78d57b2SSean Wang /* Setup functions descriptions per SoC types */ 657e78d57b2SSean Wang err = mtk_build_functions(hw); 658e78d57b2SSean Wang if (err) { 659e78d57b2SSean Wang dev_err(&pdev->dev, "Failed to build functions\n"); 660e78d57b2SSean Wang return err; 661e78d57b2SSean Wang } 662e78d57b2SSean Wang 663e78d57b2SSean Wang /* For able to make pinctrl_claim_hogs, we must not enable pinctrl 664e78d57b2SSean Wang * until all groups and functions are being added one. 665e78d57b2SSean Wang */ 666e78d57b2SSean Wang err = pinctrl_enable(hw->pctrl); 667e78d57b2SSean Wang if (err) 668e78d57b2SSean Wang return err; 669e78d57b2SSean Wang 670e78d57b2SSean Wang err = mtk_build_eint(hw, pdev); 671e78d57b2SSean Wang if (err) 672e78d57b2SSean Wang dev_warn(&pdev->dev, 673e78d57b2SSean Wang "Failed to add EINT, but pinctrl still can work\n"); 674e78d57b2SSean Wang 675e78d57b2SSean Wang /* Build gpiochip should be after pinctrl_enable is done */ 676e78d57b2SSean Wang err = mtk_build_gpiochip(hw, pdev->dev.of_node); 677e78d57b2SSean Wang if (err) { 678e78d57b2SSean Wang dev_err(&pdev->dev, "Failed to add gpio_chip\n"); 679e78d57b2SSean Wang return err; 680e78d57b2SSean Wang } 681e78d57b2SSean Wang 682e78d57b2SSean Wang platform_set_drvdata(pdev, hw); 683e78d57b2SSean Wang 684e78d57b2SSean Wang return 0; 685e78d57b2SSean Wang } 686