180525098SZhiyong Tao // SPDX-License-Identifier: GPL-2.0 280525098SZhiyong Tao /* 380525098SZhiyong Tao * MediaTek Pinctrl Paris Driver, which implement the vendor per-pin 480525098SZhiyong Tao * bindings for MediaTek SoC. 580525098SZhiyong Tao * 680525098SZhiyong Tao * Copyright (C) 2018 MediaTek Inc. 780525098SZhiyong Tao * Author: Sean Wang <sean.wang@mediatek.com> 880525098SZhiyong Tao * Zhiyong Tao <zhiyong.tao@mediatek.com> 980525098SZhiyong Tao * Hongzhou.Yang <hongzhou.yang@mediatek.com> 1080525098SZhiyong Tao */ 1180525098SZhiyong Tao 1222d7fe49SLinus Walleij #include <linux/gpio/driver.h> 138174a851SLight Hsieh #include <linux/module.h> 1480525098SZhiyong Tao #include <dt-bindings/pinctrl/mt65xx.h> 1580525098SZhiyong Tao #include "pinctrl-paris.h" 1680525098SZhiyong Tao 1780525098SZhiyong Tao #define PINCTRL_PINCTRL_DEV KBUILD_MODNAME 1880525098SZhiyong Tao 1980525098SZhiyong Tao /* Custom pinconf parameters */ 2080525098SZhiyong Tao #define MTK_PIN_CONFIG_TDSEL (PIN_CONFIG_END + 1) 2180525098SZhiyong Tao #define MTK_PIN_CONFIG_RDSEL (PIN_CONFIG_END + 2) 2280525098SZhiyong Tao #define MTK_PIN_CONFIG_PU_ADV (PIN_CONFIG_END + 3) 2380525098SZhiyong Tao #define MTK_PIN_CONFIG_PD_ADV (PIN_CONFIG_END + 4) 245e73de34SZhiyong Tao #define MTK_PIN_CONFIG_DRV_ADV (PIN_CONFIG_END + 5) 2580525098SZhiyong Tao 2680525098SZhiyong Tao static const struct pinconf_generic_params mtk_custom_bindings[] = { 2780525098SZhiyong Tao {"mediatek,tdsel", MTK_PIN_CONFIG_TDSEL, 0}, 2880525098SZhiyong Tao {"mediatek,rdsel", MTK_PIN_CONFIG_RDSEL, 0}, 2980525098SZhiyong Tao {"mediatek,pull-up-adv", MTK_PIN_CONFIG_PU_ADV, 1}, 3080525098SZhiyong Tao {"mediatek,pull-down-adv", MTK_PIN_CONFIG_PD_ADV, 1}, 315e73de34SZhiyong Tao {"mediatek,drive-strength-adv", MTK_PIN_CONFIG_DRV_ADV, 2}, 3280525098SZhiyong Tao }; 3380525098SZhiyong Tao 3480525098SZhiyong Tao #ifdef CONFIG_DEBUG_FS 3580525098SZhiyong Tao static const struct pin_config_item mtk_conf_items[] = { 3680525098SZhiyong Tao PCONFDUMP(MTK_PIN_CONFIG_TDSEL, "tdsel", NULL, true), 3780525098SZhiyong Tao PCONFDUMP(MTK_PIN_CONFIG_RDSEL, "rdsel", NULL, true), 3880525098SZhiyong Tao PCONFDUMP(MTK_PIN_CONFIG_PU_ADV, "pu-adv", NULL, true), 3980525098SZhiyong Tao PCONFDUMP(MTK_PIN_CONFIG_PD_ADV, "pd-adv", NULL, true), 405e73de34SZhiyong Tao PCONFDUMP(MTK_PIN_CONFIG_DRV_ADV, "drive-strength-adv", NULL, true), 4180525098SZhiyong Tao }; 4280525098SZhiyong Tao #endif 4380525098SZhiyong Tao 4480525098SZhiyong Tao static const char * const mtk_gpio_functions[] = { 4580525098SZhiyong Tao "func0", "func1", "func2", "func3", 4680525098SZhiyong Tao "func4", "func5", "func6", "func7", 4780525098SZhiyong Tao "func8", "func9", "func10", "func11", 4880525098SZhiyong Tao "func12", "func13", "func14", "func15", 4980525098SZhiyong Tao }; 5080525098SZhiyong Tao 51e5fabbe4SChen-Yu Tsai /* 52e5fabbe4SChen-Yu Tsai * This section supports converting to/from custom MTK_PIN_CONFIG_DRV_ADV 53e5fabbe4SChen-Yu Tsai * and standard PIN_CONFIG_DRIVE_STRENGTH_UA pin configs. 54e5fabbe4SChen-Yu Tsai * 55e5fabbe4SChen-Yu Tsai * The custom value encodes three hardware bits as follows: 56e5fabbe4SChen-Yu Tsai * 57e5fabbe4SChen-Yu Tsai * | Bits | 58e5fabbe4SChen-Yu Tsai * | 2 (E1) | 1 (E0) | 0 (EN) | drive strength (uA) 59e5fabbe4SChen-Yu Tsai * ------------------------------------------------ 60e5fabbe4SChen-Yu Tsai * | x | x | 0 | disabled, use standard drive strength 61e5fabbe4SChen-Yu Tsai * ------------------------------------- 62e5fabbe4SChen-Yu Tsai * | 0 | 0 | 1 | 125 uA 63e5fabbe4SChen-Yu Tsai * | 0 | 1 | 1 | 250 uA 64e5fabbe4SChen-Yu Tsai * | 1 | 0 | 1 | 500 uA 65e5fabbe4SChen-Yu Tsai * | 1 | 1 | 1 | 1000 uA 66e5fabbe4SChen-Yu Tsai */ 67e5fabbe4SChen-Yu Tsai static const int mtk_drv_adv_uA[] = { 125, 250, 500, 1000 }; 68e5fabbe4SChen-Yu Tsai 69e5fabbe4SChen-Yu Tsai static int mtk_drv_adv_to_uA(int val) 70e5fabbe4SChen-Yu Tsai { 71e5fabbe4SChen-Yu Tsai /* This should never happen. */ 72e5fabbe4SChen-Yu Tsai if (WARN_ON_ONCE(val < 0 || val > 7)) 73e5fabbe4SChen-Yu Tsai return -EINVAL; 74e5fabbe4SChen-Yu Tsai 75e5fabbe4SChen-Yu Tsai /* Bit 0 simply enables this hardware part */ 76e5fabbe4SChen-Yu Tsai if (!(val & BIT(0))) 77e5fabbe4SChen-Yu Tsai return -EINVAL; 78e5fabbe4SChen-Yu Tsai 79e5fabbe4SChen-Yu Tsai return mtk_drv_adv_uA[(val >> 1)]; 80e5fabbe4SChen-Yu Tsai } 81e5fabbe4SChen-Yu Tsai 82e5fabbe4SChen-Yu Tsai static int mtk_drv_uA_to_adv(int val) 83e5fabbe4SChen-Yu Tsai { 84e5fabbe4SChen-Yu Tsai switch (val) { 85e5fabbe4SChen-Yu Tsai case 125: 86e5fabbe4SChen-Yu Tsai return 0x1; 87e5fabbe4SChen-Yu Tsai case 250: 88e5fabbe4SChen-Yu Tsai return 0x3; 89e5fabbe4SChen-Yu Tsai case 500: 90e5fabbe4SChen-Yu Tsai return 0x5; 91e5fabbe4SChen-Yu Tsai case 1000: 92e5fabbe4SChen-Yu Tsai return 0x7; 93e5fabbe4SChen-Yu Tsai } 94e5fabbe4SChen-Yu Tsai 95e5fabbe4SChen-Yu Tsai return -EINVAL; 96e5fabbe4SChen-Yu Tsai } 97e5fabbe4SChen-Yu Tsai 9880525098SZhiyong Tao static int mtk_pinmux_gpio_request_enable(struct pinctrl_dev *pctldev, 9980525098SZhiyong Tao struct pinctrl_gpio_range *range, 10080525098SZhiyong Tao unsigned int pin) 10180525098SZhiyong Tao { 10280525098SZhiyong Tao struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 10380525098SZhiyong Tao const struct mtk_pin_desc *desc; 10480525098SZhiyong Tao 10580525098SZhiyong Tao desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; 10680525098SZhiyong Tao 10780525098SZhiyong Tao return mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_MODE, 10880525098SZhiyong Tao hw->soc->gpio_m); 10980525098SZhiyong Tao } 11080525098SZhiyong Tao 11180525098SZhiyong Tao static int mtk_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev, 11280525098SZhiyong Tao struct pinctrl_gpio_range *range, 11380525098SZhiyong Tao unsigned int pin, bool input) 11480525098SZhiyong Tao { 11580525098SZhiyong Tao struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 11680525098SZhiyong Tao const struct mtk_pin_desc *desc; 11780525098SZhiyong Tao 11880525098SZhiyong Tao desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; 11980525098SZhiyong Tao 12080525098SZhiyong Tao /* hardware would take 0 as input direction */ 12180525098SZhiyong Tao return mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR, !input); 12280525098SZhiyong Tao } 12380525098SZhiyong Tao 12480525098SZhiyong Tao static int mtk_pinconf_get(struct pinctrl_dev *pctldev, 12580525098SZhiyong Tao unsigned int pin, unsigned long *config) 12680525098SZhiyong Tao { 12780525098SZhiyong Tao struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 12880525098SZhiyong Tao u32 param = pinconf_to_config_param(*config); 1299b780fa1SChen-Yu Tsai int pullup, reg, err = -ENOTSUPP, ret = 1; 13080525098SZhiyong Tao const struct mtk_pin_desc *desc; 13180525098SZhiyong Tao 1329b780fa1SChen-Yu Tsai if (pin >= hw->soc->npins) 1339b780fa1SChen-Yu Tsai return -EINVAL; 1349b780fa1SChen-Yu Tsai 13580525098SZhiyong Tao desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; 13680525098SZhiyong Tao 13780525098SZhiyong Tao switch (param) { 13880525098SZhiyong Tao case PIN_CONFIG_BIAS_DISABLE: 13980525098SZhiyong Tao case PIN_CONFIG_BIAS_PULL_UP: 14080525098SZhiyong Tao case PIN_CONFIG_BIAS_PULL_DOWN: 1419b780fa1SChen-Yu Tsai if (!hw->soc->bias_get_combo) 1429b780fa1SChen-Yu Tsai break; 143cafe19dbSLight Hsieh err = hw->soc->bias_get_combo(hw, desc, &pullup, &ret); 144cafe19dbSLight Hsieh if (err) 1459b780fa1SChen-Yu Tsai break; 146cafe19dbSLight Hsieh if (ret == MTK_PUPD_SET_R1R0_00) 147cafe19dbSLight Hsieh ret = MTK_DISABLE; 1483e8c6bc6SChen-Yu Tsai if (param == PIN_CONFIG_BIAS_DISABLE) { 1493e8c6bc6SChen-Yu Tsai if (ret != MTK_DISABLE) 1503e8c6bc6SChen-Yu Tsai err = -EINVAL; 151cafe19dbSLight Hsieh } else if (param == PIN_CONFIG_BIAS_PULL_UP) { 1523e8c6bc6SChen-Yu Tsai if (!pullup || ret == MTK_DISABLE) 153cafe19dbSLight Hsieh err = -EINVAL; 154cafe19dbSLight Hsieh } else if (param == PIN_CONFIG_BIAS_PULL_DOWN) { 1553e8c6bc6SChen-Yu Tsai if (pullup || ret == MTK_DISABLE) 156cafe19dbSLight Hsieh err = -EINVAL; 157cafe19dbSLight Hsieh } 15880525098SZhiyong Tao break; 15980525098SZhiyong Tao case PIN_CONFIG_SLEW_RATE: 1601bea6afbSLight Hsieh err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_SR, &ret); 16180525098SZhiyong Tao break; 16280525098SZhiyong Tao case PIN_CONFIG_INPUT_ENABLE: 16380525098SZhiyong Tao case PIN_CONFIG_OUTPUT_ENABLE: 1641bea6afbSLight Hsieh err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DIR, &ret); 16580525098SZhiyong Tao if (err) 1669b780fa1SChen-Yu Tsai break; 1673599cc52SLight Hsieh /* CONFIG Current direction return value 1683599cc52SLight Hsieh * ------------- ----------------- ---------------------- 1693599cc52SLight Hsieh * OUTPUT_ENABLE output 1 (= HW value) 1703599cc52SLight Hsieh * input 0 (= HW value) 1713599cc52SLight Hsieh * INPUT_ENABLE output 0 (= reverse HW value) 1723599cc52SLight Hsieh * input 1 (= reverse HW value) 1733599cc52SLight Hsieh */ 1743599cc52SLight Hsieh if (param == PIN_CONFIG_INPUT_ENABLE) 1751bea6afbSLight Hsieh ret = !ret; 17680525098SZhiyong Tao 17780525098SZhiyong Tao break; 17880525098SZhiyong Tao case PIN_CONFIG_INPUT_SCHMITT_ENABLE: 1791bea6afbSLight Hsieh err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DIR, &ret); 18080525098SZhiyong Tao if (err) 1819b780fa1SChen-Yu Tsai break; 1821bea6afbSLight Hsieh /* return error when in output mode 1831bea6afbSLight Hsieh * because schmitt trigger only work in input mode 1841bea6afbSLight Hsieh */ 1851bea6afbSLight Hsieh if (ret) { 1861bea6afbSLight Hsieh err = -EINVAL; 1879b780fa1SChen-Yu Tsai break; 1881bea6afbSLight Hsieh } 18980525098SZhiyong Tao 1901bea6afbSLight Hsieh err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_SMT, &ret); 19180525098SZhiyong Tao break; 19280525098SZhiyong Tao case PIN_CONFIG_DRIVE_STRENGTH: 1939b780fa1SChen-Yu Tsai if (!hw->soc->drive_get) 1949b780fa1SChen-Yu Tsai break; 195e5fabbe4SChen-Yu Tsai 196e5fabbe4SChen-Yu Tsai if (hw->soc->adv_drive_get) { 197e5fabbe4SChen-Yu Tsai err = hw->soc->adv_drive_get(hw, desc, &ret); 198e5fabbe4SChen-Yu Tsai if (!err) { 199e5fabbe4SChen-Yu Tsai err = mtk_drv_adv_to_uA(ret); 200e5fabbe4SChen-Yu Tsai if (err > 0) { 201e5fabbe4SChen-Yu Tsai /* PIN_CONFIG_DRIVE_STRENGTH_UA used */ 202e5fabbe4SChen-Yu Tsai err = -EINVAL; 203e5fabbe4SChen-Yu Tsai break; 204e5fabbe4SChen-Yu Tsai } 205e5fabbe4SChen-Yu Tsai } 206e5fabbe4SChen-Yu Tsai } 207e5fabbe4SChen-Yu Tsai 20880525098SZhiyong Tao err = hw->soc->drive_get(hw, desc, &ret); 20980525098SZhiyong Tao break; 210e5fabbe4SChen-Yu Tsai case PIN_CONFIG_DRIVE_STRENGTH_UA: 211e5fabbe4SChen-Yu Tsai if (!hw->soc->adv_drive_get) 212e5fabbe4SChen-Yu Tsai break; 213e5fabbe4SChen-Yu Tsai 214e5fabbe4SChen-Yu Tsai err = hw->soc->adv_drive_get(hw, desc, &ret); 215e5fabbe4SChen-Yu Tsai if (err) 216e5fabbe4SChen-Yu Tsai break; 217e5fabbe4SChen-Yu Tsai err = mtk_drv_adv_to_uA(ret); 218e5fabbe4SChen-Yu Tsai if (err < 0) 219e5fabbe4SChen-Yu Tsai break; 220e5fabbe4SChen-Yu Tsai 221e5fabbe4SChen-Yu Tsai ret = err; 222e5fabbe4SChen-Yu Tsai err = 0; 223e5fabbe4SChen-Yu Tsai break; 22480525098SZhiyong Tao case MTK_PIN_CONFIG_TDSEL: 22580525098SZhiyong Tao case MTK_PIN_CONFIG_RDSEL: 22680525098SZhiyong Tao reg = (param == MTK_PIN_CONFIG_TDSEL) ? 22780525098SZhiyong Tao PINCTRL_PIN_REG_TDSEL : PINCTRL_PIN_REG_RDSEL; 2281bea6afbSLight Hsieh err = mtk_hw_get_value(hw, desc, reg, &ret); 22980525098SZhiyong Tao break; 23080525098SZhiyong Tao case MTK_PIN_CONFIG_PU_ADV: 23180525098SZhiyong Tao case MTK_PIN_CONFIG_PD_ADV: 2329b780fa1SChen-Yu Tsai if (!hw->soc->adv_pull_get) 2339b780fa1SChen-Yu Tsai break; 23480525098SZhiyong Tao pullup = param == MTK_PIN_CONFIG_PU_ADV; 23580525098SZhiyong Tao err = hw->soc->adv_pull_get(hw, desc, pullup, &ret); 23680525098SZhiyong Tao break; 2375e73de34SZhiyong Tao case MTK_PIN_CONFIG_DRV_ADV: 2389b780fa1SChen-Yu Tsai if (!hw->soc->adv_drive_get) 2395e73de34SZhiyong Tao break; 2409b780fa1SChen-Yu Tsai err = hw->soc->adv_drive_get(hw, desc, &ret); 2419b780fa1SChen-Yu Tsai break; 24280525098SZhiyong Tao } 24380525098SZhiyong Tao 2443599cc52SLight Hsieh if (!err) 24580525098SZhiyong Tao *config = pinconf_to_config_packed(param, ret); 24680525098SZhiyong Tao 2473599cc52SLight Hsieh return err; 24880525098SZhiyong Tao } 24980525098SZhiyong Tao 25080525098SZhiyong Tao static int mtk_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, 25119bce7ceSChen-Yu Tsai enum pin_config_param param, u32 arg) 25280525098SZhiyong Tao { 25380525098SZhiyong Tao struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 25480525098SZhiyong Tao const struct mtk_pin_desc *desc; 2559b780fa1SChen-Yu Tsai int err = -ENOTSUPP; 25680525098SZhiyong Tao u32 reg; 25780525098SZhiyong Tao 2589b780fa1SChen-Yu Tsai if (pin >= hw->soc->npins) 2599b780fa1SChen-Yu Tsai return -EINVAL; 2609b780fa1SChen-Yu Tsai 26180525098SZhiyong Tao desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin]; 26280525098SZhiyong Tao 26380525098SZhiyong Tao switch ((u32)param) { 26480525098SZhiyong Tao case PIN_CONFIG_BIAS_DISABLE: 2659b780fa1SChen-Yu Tsai if (!hw->soc->bias_set_combo) 2669b780fa1SChen-Yu Tsai break; 267cafe19dbSLight Hsieh err = hw->soc->bias_set_combo(hw, desc, 0, MTK_DISABLE); 26880525098SZhiyong Tao break; 26980525098SZhiyong Tao case PIN_CONFIG_BIAS_PULL_UP: 2709b780fa1SChen-Yu Tsai if (!hw->soc->bias_set_combo) 2719b780fa1SChen-Yu Tsai break; 272cafe19dbSLight Hsieh err = hw->soc->bias_set_combo(hw, desc, 1, arg); 27380525098SZhiyong Tao break; 27480525098SZhiyong Tao case PIN_CONFIG_BIAS_PULL_DOWN: 2759b780fa1SChen-Yu Tsai if (!hw->soc->bias_set_combo) 2769b780fa1SChen-Yu Tsai break; 277cafe19dbSLight Hsieh err = hw->soc->bias_set_combo(hw, desc, 0, arg); 27880525098SZhiyong Tao break; 27980525098SZhiyong Tao case PIN_CONFIG_OUTPUT_ENABLE: 28080525098SZhiyong Tao err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_SMT, 28180525098SZhiyong Tao MTK_DISABLE); 2823599cc52SLight Hsieh /* Keep set direction to consider the case that a GPIO pin 2833599cc52SLight Hsieh * does not have SMT control 2843599cc52SLight Hsieh */ 2853599cc52SLight Hsieh if (err != -ENOTSUPP) 2869b780fa1SChen-Yu Tsai break; 28780525098SZhiyong Tao 28880525098SZhiyong Tao err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR, 28980525098SZhiyong Tao MTK_OUTPUT); 29080525098SZhiyong Tao break; 29180525098SZhiyong Tao case PIN_CONFIG_INPUT_ENABLE: 2923599cc52SLight Hsieh /* regard all non-zero value as enable */ 2933599cc52SLight Hsieh err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_IES, !!arg); 2943599cc52SLight Hsieh if (err) 2959b780fa1SChen-Yu Tsai break; 29680525098SZhiyong Tao 29780525098SZhiyong Tao err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR, 29880525098SZhiyong Tao MTK_INPUT); 29980525098SZhiyong Tao break; 30080525098SZhiyong Tao case PIN_CONFIG_SLEW_RATE: 3013599cc52SLight Hsieh /* regard all non-zero value as enable */ 3023599cc52SLight Hsieh err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_SR, !!arg); 30380525098SZhiyong Tao break; 30480525098SZhiyong Tao case PIN_CONFIG_OUTPUT: 305517c3f5aSZhiyong Tao err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DO, 306517c3f5aSZhiyong Tao arg); 30780525098SZhiyong Tao if (err) 3089b780fa1SChen-Yu Tsai break; 30980525098SZhiyong Tao 310517c3f5aSZhiyong Tao err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR, 311517c3f5aSZhiyong Tao MTK_OUTPUT); 31280525098SZhiyong Tao break; 3133599cc52SLight Hsieh case PIN_CONFIG_INPUT_SCHMITT: 31480525098SZhiyong Tao case PIN_CONFIG_INPUT_SCHMITT_ENABLE: 31580525098SZhiyong Tao /* arg = 1: Input mode & SMT enable ; 31680525098SZhiyong Tao * arg = 0: Output mode & SMT disable 31780525098SZhiyong Tao */ 3183599cc52SLight Hsieh err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DIR, !arg); 31980525098SZhiyong Tao if (err) 3209b780fa1SChen-Yu Tsai break; 32180525098SZhiyong Tao 3223599cc52SLight Hsieh err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_SMT, !!arg); 32380525098SZhiyong Tao break; 32480525098SZhiyong Tao case PIN_CONFIG_DRIVE_STRENGTH: 3259b780fa1SChen-Yu Tsai if (!hw->soc->drive_set) 3269b780fa1SChen-Yu Tsai break; 32780525098SZhiyong Tao err = hw->soc->drive_set(hw, desc, arg); 32880525098SZhiyong Tao break; 329e5fabbe4SChen-Yu Tsai case PIN_CONFIG_DRIVE_STRENGTH_UA: 330e5fabbe4SChen-Yu Tsai if (!hw->soc->adv_drive_set) 331e5fabbe4SChen-Yu Tsai break; 332e5fabbe4SChen-Yu Tsai 333e5fabbe4SChen-Yu Tsai err = mtk_drv_uA_to_adv(arg); 334e5fabbe4SChen-Yu Tsai if (err < 0) 335e5fabbe4SChen-Yu Tsai break; 336e5fabbe4SChen-Yu Tsai err = hw->soc->adv_drive_set(hw, desc, err); 337e5fabbe4SChen-Yu Tsai break; 33880525098SZhiyong Tao case MTK_PIN_CONFIG_TDSEL: 33980525098SZhiyong Tao case MTK_PIN_CONFIG_RDSEL: 34080525098SZhiyong Tao reg = (param == MTK_PIN_CONFIG_TDSEL) ? 34180525098SZhiyong Tao PINCTRL_PIN_REG_TDSEL : PINCTRL_PIN_REG_RDSEL; 34280525098SZhiyong Tao err = mtk_hw_set_value(hw, desc, reg, arg); 34380525098SZhiyong Tao break; 34480525098SZhiyong Tao case MTK_PIN_CONFIG_PU_ADV: 34580525098SZhiyong Tao case MTK_PIN_CONFIG_PD_ADV: 3469b780fa1SChen-Yu Tsai if (!hw->soc->adv_pull_set) 3479b780fa1SChen-Yu Tsai break; 3489b780fa1SChen-Yu Tsai err = hw->soc->adv_pull_set(hw, desc, 3499b780fa1SChen-Yu Tsai (param == MTK_PIN_CONFIG_PU_ADV), 35080525098SZhiyong Tao arg); 35180525098SZhiyong Tao break; 3525e73de34SZhiyong Tao case MTK_PIN_CONFIG_DRV_ADV: 3539b780fa1SChen-Yu Tsai if (!hw->soc->adv_drive_set) 3545e73de34SZhiyong Tao break; 3559b780fa1SChen-Yu Tsai err = hw->soc->adv_drive_set(hw, desc, arg); 3569b780fa1SChen-Yu Tsai break; 35780525098SZhiyong Tao } 35880525098SZhiyong Tao 35980525098SZhiyong Tao return err; 36080525098SZhiyong Tao } 36180525098SZhiyong Tao 36280525098SZhiyong Tao static struct mtk_pinctrl_group * 36380525098SZhiyong Tao mtk_pctrl_find_group_by_pin(struct mtk_pinctrl *hw, u32 pin) 36480525098SZhiyong Tao { 36580525098SZhiyong Tao int i; 36680525098SZhiyong Tao 36780525098SZhiyong Tao for (i = 0; i < hw->soc->ngrps; i++) { 36880525098SZhiyong Tao struct mtk_pinctrl_group *grp = hw->groups + i; 36980525098SZhiyong Tao 37080525098SZhiyong Tao if (grp->pin == pin) 37180525098SZhiyong Tao return grp; 37280525098SZhiyong Tao } 37380525098SZhiyong Tao 37480525098SZhiyong Tao return NULL; 37580525098SZhiyong Tao } 37680525098SZhiyong Tao 37780525098SZhiyong Tao static const struct mtk_func_desc * 37880525098SZhiyong Tao mtk_pctrl_find_function_by_pin(struct mtk_pinctrl *hw, u32 pin_num, u32 fnum) 37980525098SZhiyong Tao { 38080525098SZhiyong Tao const struct mtk_pin_desc *pin = hw->soc->pins + pin_num; 38180525098SZhiyong Tao const struct mtk_func_desc *func = pin->funcs; 38280525098SZhiyong Tao 38380525098SZhiyong Tao while (func && func->name) { 38480525098SZhiyong Tao if (func->muxval == fnum) 38580525098SZhiyong Tao return func; 38680525098SZhiyong Tao func++; 38780525098SZhiyong Tao } 38880525098SZhiyong Tao 38980525098SZhiyong Tao return NULL; 39080525098SZhiyong Tao } 39180525098SZhiyong Tao 39280525098SZhiyong Tao static bool mtk_pctrl_is_function_valid(struct mtk_pinctrl *hw, u32 pin_num, 39380525098SZhiyong Tao u32 fnum) 39480525098SZhiyong Tao { 39580525098SZhiyong Tao int i; 39680525098SZhiyong Tao 39780525098SZhiyong Tao for (i = 0; i < hw->soc->npins; i++) { 39880525098SZhiyong Tao const struct mtk_pin_desc *pin = hw->soc->pins + i; 39980525098SZhiyong Tao 40080525098SZhiyong Tao if (pin->number == pin_num) { 40180525098SZhiyong Tao const struct mtk_func_desc *func = pin->funcs; 40280525098SZhiyong Tao 40380525098SZhiyong Tao while (func && func->name) { 40480525098SZhiyong Tao if (func->muxval == fnum) 40580525098SZhiyong Tao return true; 40680525098SZhiyong Tao func++; 40780525098SZhiyong Tao } 40880525098SZhiyong Tao 40980525098SZhiyong Tao break; 41080525098SZhiyong Tao } 41180525098SZhiyong Tao } 41280525098SZhiyong Tao 41380525098SZhiyong Tao return false; 41480525098SZhiyong Tao } 41580525098SZhiyong Tao 41680525098SZhiyong Tao static int mtk_pctrl_dt_node_to_map_func(struct mtk_pinctrl *pctl, 41780525098SZhiyong Tao u32 pin, u32 fnum, 41880525098SZhiyong Tao struct mtk_pinctrl_group *grp, 41980525098SZhiyong Tao struct pinctrl_map **map, 42080525098SZhiyong Tao unsigned *reserved_maps, 42180525098SZhiyong Tao unsigned *num_maps) 42280525098SZhiyong Tao { 42380525098SZhiyong Tao bool ret; 42480525098SZhiyong Tao 42580525098SZhiyong Tao if (*num_maps == *reserved_maps) 42680525098SZhiyong Tao return -ENOSPC; 42780525098SZhiyong Tao 42880525098SZhiyong Tao (*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP; 42980525098SZhiyong Tao (*map)[*num_maps].data.mux.group = grp->name; 43080525098SZhiyong Tao 43180525098SZhiyong Tao ret = mtk_pctrl_is_function_valid(pctl, pin, fnum); 43280525098SZhiyong Tao if (!ret) { 43380525098SZhiyong Tao dev_err(pctl->dev, "invalid function %d on pin %d .\n", 43480525098SZhiyong Tao fnum, pin); 43580525098SZhiyong Tao return -EINVAL; 43680525098SZhiyong Tao } 43780525098SZhiyong Tao 43880525098SZhiyong Tao (*map)[*num_maps].data.mux.function = mtk_gpio_functions[fnum]; 43980525098SZhiyong Tao (*num_maps)++; 44080525098SZhiyong Tao 44180525098SZhiyong Tao return 0; 44280525098SZhiyong Tao } 44380525098SZhiyong Tao 44480525098SZhiyong Tao static int mtk_pctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev, 44580525098SZhiyong Tao struct device_node *node, 44680525098SZhiyong Tao struct pinctrl_map **map, 44780525098SZhiyong Tao unsigned *reserved_maps, 44880525098SZhiyong Tao unsigned *num_maps) 44980525098SZhiyong Tao { 45080525098SZhiyong Tao struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 45180525098SZhiyong Tao int num_pins, num_funcs, maps_per_pin, i, err; 45280525098SZhiyong Tao struct mtk_pinctrl_group *grp; 45380525098SZhiyong Tao unsigned int num_configs; 45480525098SZhiyong Tao bool has_config = false; 45580525098SZhiyong Tao unsigned long *configs; 45680525098SZhiyong Tao u32 pinfunc, pin, func; 45780525098SZhiyong Tao struct property *pins; 45880525098SZhiyong Tao unsigned reserve = 0; 45980525098SZhiyong Tao 46080525098SZhiyong Tao pins = of_find_property(node, "pinmux", NULL); 46180525098SZhiyong Tao if (!pins) { 4629ede2a76SRob Herring dev_err(hw->dev, "missing pins property in node %pOFn .\n", 4639ede2a76SRob Herring node); 46480525098SZhiyong Tao return -EINVAL; 46580525098SZhiyong Tao } 46680525098SZhiyong Tao 46780525098SZhiyong Tao err = pinconf_generic_parse_dt_config(node, pctldev, &configs, 46880525098SZhiyong Tao &num_configs); 46980525098SZhiyong Tao if (err) 47080525098SZhiyong Tao return err; 47180525098SZhiyong Tao 47280525098SZhiyong Tao if (num_configs) 47380525098SZhiyong Tao has_config = true; 47480525098SZhiyong Tao 47580525098SZhiyong Tao num_pins = pins->length / sizeof(u32); 47680525098SZhiyong Tao num_funcs = num_pins; 47780525098SZhiyong Tao maps_per_pin = 0; 47880525098SZhiyong Tao if (num_funcs) 47980525098SZhiyong Tao maps_per_pin++; 48080525098SZhiyong Tao if (has_config && num_pins >= 1) 48180525098SZhiyong Tao maps_per_pin++; 48280525098SZhiyong Tao 48380525098SZhiyong Tao if (!num_pins || !maps_per_pin) { 48480525098SZhiyong Tao err = -EINVAL; 48580525098SZhiyong Tao goto exit; 48680525098SZhiyong Tao } 48780525098SZhiyong Tao 48880525098SZhiyong Tao reserve = num_pins * maps_per_pin; 48980525098SZhiyong Tao 49080525098SZhiyong Tao err = pinctrl_utils_reserve_map(pctldev, map, reserved_maps, num_maps, 49180525098SZhiyong Tao reserve); 49280525098SZhiyong Tao if (err < 0) 49380525098SZhiyong Tao goto exit; 49480525098SZhiyong Tao 49580525098SZhiyong Tao for (i = 0; i < num_pins; i++) { 49680525098SZhiyong Tao err = of_property_read_u32_index(node, "pinmux", i, &pinfunc); 49780525098SZhiyong Tao if (err) 49880525098SZhiyong Tao goto exit; 49980525098SZhiyong Tao 50080525098SZhiyong Tao pin = MTK_GET_PIN_NO(pinfunc); 50180525098SZhiyong Tao func = MTK_GET_PIN_FUNC(pinfunc); 50280525098SZhiyong Tao 50380525098SZhiyong Tao if (pin >= hw->soc->npins || 50480525098SZhiyong Tao func >= ARRAY_SIZE(mtk_gpio_functions)) { 50580525098SZhiyong Tao dev_err(hw->dev, "invalid pins value.\n"); 50680525098SZhiyong Tao err = -EINVAL; 50780525098SZhiyong Tao goto exit; 50880525098SZhiyong Tao } 50980525098SZhiyong Tao 51080525098SZhiyong Tao grp = mtk_pctrl_find_group_by_pin(hw, pin); 51180525098SZhiyong Tao if (!grp) { 51280525098SZhiyong Tao dev_err(hw->dev, "unable to match pin %d to group\n", 51380525098SZhiyong Tao pin); 51480525098SZhiyong Tao err = -EINVAL; 51580525098SZhiyong Tao goto exit; 51680525098SZhiyong Tao } 51780525098SZhiyong Tao 51880525098SZhiyong Tao err = mtk_pctrl_dt_node_to_map_func(hw, pin, func, grp, map, 51980525098SZhiyong Tao reserved_maps, num_maps); 52080525098SZhiyong Tao if (err < 0) 52180525098SZhiyong Tao goto exit; 52280525098SZhiyong Tao 52380525098SZhiyong Tao if (has_config) { 52480525098SZhiyong Tao err = pinctrl_utils_add_map_configs(pctldev, map, 52580525098SZhiyong Tao reserved_maps, 52680525098SZhiyong Tao num_maps, 52780525098SZhiyong Tao grp->name, 52880525098SZhiyong Tao configs, 52980525098SZhiyong Tao num_configs, 53080525098SZhiyong Tao PIN_MAP_TYPE_CONFIGS_GROUP); 53180525098SZhiyong Tao if (err < 0) 53280525098SZhiyong Tao goto exit; 53380525098SZhiyong Tao } 53480525098SZhiyong Tao } 53580525098SZhiyong Tao 53680525098SZhiyong Tao err = 0; 53780525098SZhiyong Tao 53880525098SZhiyong Tao exit: 53980525098SZhiyong Tao kfree(configs); 54080525098SZhiyong Tao return err; 54180525098SZhiyong Tao } 54280525098SZhiyong Tao 54380525098SZhiyong Tao static int mtk_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev, 54480525098SZhiyong Tao struct device_node *np_config, 54580525098SZhiyong Tao struct pinctrl_map **map, 54680525098SZhiyong Tao unsigned *num_maps) 54780525098SZhiyong Tao { 54880525098SZhiyong Tao struct device_node *np; 54980525098SZhiyong Tao unsigned reserved_maps; 55080525098SZhiyong Tao int ret; 55180525098SZhiyong Tao 55280525098SZhiyong Tao *map = NULL; 55380525098SZhiyong Tao *num_maps = 0; 55480525098SZhiyong Tao reserved_maps = 0; 55580525098SZhiyong Tao 55680525098SZhiyong Tao for_each_child_of_node(np_config, np) { 55780525098SZhiyong Tao ret = mtk_pctrl_dt_subnode_to_map(pctldev, np, map, 55880525098SZhiyong Tao &reserved_maps, 55980525098SZhiyong Tao num_maps); 56080525098SZhiyong Tao if (ret < 0) { 56180525098SZhiyong Tao pinctrl_utils_free_map(pctldev, *map, *num_maps); 56280525098SZhiyong Tao of_node_put(np); 56380525098SZhiyong Tao return ret; 56480525098SZhiyong Tao } 56580525098SZhiyong Tao } 56680525098SZhiyong Tao 56780525098SZhiyong Tao return 0; 56880525098SZhiyong Tao } 56980525098SZhiyong Tao 57080525098SZhiyong Tao static int mtk_pctrl_get_groups_count(struct pinctrl_dev *pctldev) 57180525098SZhiyong Tao { 57280525098SZhiyong Tao struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 57380525098SZhiyong Tao 57480525098SZhiyong Tao return hw->soc->ngrps; 57580525098SZhiyong Tao } 57680525098SZhiyong Tao 57780525098SZhiyong Tao static const char *mtk_pctrl_get_group_name(struct pinctrl_dev *pctldev, 57880525098SZhiyong Tao unsigned group) 57980525098SZhiyong Tao { 58080525098SZhiyong Tao struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 58180525098SZhiyong Tao 58280525098SZhiyong Tao return hw->groups[group].name; 58380525098SZhiyong Tao } 58480525098SZhiyong Tao 58580525098SZhiyong Tao static int mtk_pctrl_get_group_pins(struct pinctrl_dev *pctldev, 58680525098SZhiyong Tao unsigned group, const unsigned **pins, 58780525098SZhiyong Tao unsigned *num_pins) 58880525098SZhiyong Tao { 58980525098SZhiyong Tao struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 59080525098SZhiyong Tao 59180525098SZhiyong Tao *pins = (unsigned *)&hw->groups[group].pin; 59280525098SZhiyong Tao *num_pins = 1; 59380525098SZhiyong Tao 59480525098SZhiyong Tao return 0; 59580525098SZhiyong Tao } 59680525098SZhiyong Tao 597184d8e13SLight Hsieh static int mtk_hw_get_value_wrap(struct mtk_pinctrl *hw, unsigned int gpio, int field) 598184d8e13SLight Hsieh { 599184d8e13SLight Hsieh const struct mtk_pin_desc *desc; 600184d8e13SLight Hsieh int value, err; 601184d8e13SLight Hsieh 6023385ab72SDan Carpenter if (gpio >= hw->soc->npins) 603184d8e13SLight Hsieh return -EINVAL; 604184d8e13SLight Hsieh 605184d8e13SLight Hsieh desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio]; 606184d8e13SLight Hsieh 607184d8e13SLight Hsieh err = mtk_hw_get_value(hw, desc, field, &value); 608184d8e13SLight Hsieh if (err) 609184d8e13SLight Hsieh return err; 610184d8e13SLight Hsieh 611184d8e13SLight Hsieh return value; 612184d8e13SLight Hsieh } 613184d8e13SLight Hsieh 614184d8e13SLight Hsieh #define mtk_pctrl_get_pinmux(hw, gpio) \ 615184d8e13SLight Hsieh mtk_hw_get_value_wrap(hw, gpio, PINCTRL_PIN_REG_MODE) 616184d8e13SLight Hsieh 617184d8e13SLight Hsieh #define mtk_pctrl_get_direction(hw, gpio) \ 618184d8e13SLight Hsieh mtk_hw_get_value_wrap(hw, gpio, PINCTRL_PIN_REG_DIR) 619184d8e13SLight Hsieh 620184d8e13SLight Hsieh #define mtk_pctrl_get_out(hw, gpio) \ 621184d8e13SLight Hsieh mtk_hw_get_value_wrap(hw, gpio, PINCTRL_PIN_REG_DO) 622184d8e13SLight Hsieh 623184d8e13SLight Hsieh #define mtk_pctrl_get_in(hw, gpio) \ 624184d8e13SLight Hsieh mtk_hw_get_value_wrap(hw, gpio, PINCTRL_PIN_REG_DI) 625184d8e13SLight Hsieh 626184d8e13SLight Hsieh #define mtk_pctrl_get_smt(hw, gpio) \ 627184d8e13SLight Hsieh mtk_hw_get_value_wrap(hw, gpio, PINCTRL_PIN_REG_SMT) 628184d8e13SLight Hsieh 629184d8e13SLight Hsieh #define mtk_pctrl_get_ies(hw, gpio) \ 630184d8e13SLight Hsieh mtk_hw_get_value_wrap(hw, gpio, PINCTRL_PIN_REG_IES) 631184d8e13SLight Hsieh 632184d8e13SLight Hsieh #define mtk_pctrl_get_driving(hw, gpio) \ 633184d8e13SLight Hsieh mtk_hw_get_value_wrap(hw, gpio, PINCTRL_PIN_REG_DRV) 634184d8e13SLight Hsieh 635184d8e13SLight Hsieh ssize_t mtk_pctrl_show_one_pin(struct mtk_pinctrl *hw, 63625a74c0fSZhiyong Tao unsigned int gpio, char *buf, unsigned int buf_len) 637184d8e13SLight Hsieh { 638fb34a9aeSZhiyong Tao int pinmux, pullup, pullen, len = 0, r1 = -1, r0 = -1, rsel = -1; 639184d8e13SLight Hsieh const struct mtk_pin_desc *desc; 64067bbbcb4SDan Carpenter u32 try_all_type = 0; 641184d8e13SLight Hsieh 6423385ab72SDan Carpenter if (gpio >= hw->soc->npins) 643184d8e13SLight Hsieh return -EINVAL; 644184d8e13SLight Hsieh 6451763933dSChen-Yu Tsai if (mtk_is_virt_gpio(hw, gpio)) 6461763933dSChen-Yu Tsai return -EINVAL; 6471763933dSChen-Yu Tsai 648184d8e13SLight Hsieh desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio]; 649184d8e13SLight Hsieh pinmux = mtk_pctrl_get_pinmux(hw, gpio); 650184d8e13SLight Hsieh if (pinmux >= hw->soc->nfuncs) 651184d8e13SLight Hsieh pinmux -= hw->soc->nfuncs; 652184d8e13SLight Hsieh 653184d8e13SLight Hsieh mtk_pinconf_bias_get_combo(hw, desc, &pullup, &pullen); 654fb34a9aeSZhiyong Tao 655fb34a9aeSZhiyong Tao if (hw->soc->pull_type) 656fb34a9aeSZhiyong Tao try_all_type = hw->soc->pull_type[desc->number]; 657fb34a9aeSZhiyong Tao 658fb34a9aeSZhiyong Tao if (hw->rsel_si_unit && (try_all_type & MTK_PULL_RSEL_TYPE)) { 659fb34a9aeSZhiyong Tao rsel = pullen; 660fb34a9aeSZhiyong Tao pullen = 1; 661fb34a9aeSZhiyong Tao } else { 662fb34a9aeSZhiyong Tao /* Case for: R1R0 */ 663184d8e13SLight Hsieh if (pullen == MTK_PUPD_SET_R1R0_00) { 664184d8e13SLight Hsieh pullen = 0; 665184d8e13SLight Hsieh r1 = 0; 666184d8e13SLight Hsieh r0 = 0; 667184d8e13SLight Hsieh } else if (pullen == MTK_PUPD_SET_R1R0_01) { 668184d8e13SLight Hsieh pullen = 1; 669184d8e13SLight Hsieh r1 = 0; 670184d8e13SLight Hsieh r0 = 1; 671184d8e13SLight Hsieh } else if (pullen == MTK_PUPD_SET_R1R0_10) { 672184d8e13SLight Hsieh pullen = 1; 673184d8e13SLight Hsieh r1 = 1; 674184d8e13SLight Hsieh r0 = 0; 675184d8e13SLight Hsieh } else if (pullen == MTK_PUPD_SET_R1R0_11) { 676184d8e13SLight Hsieh pullen = 1; 677184d8e13SLight Hsieh r1 = 1; 678184d8e13SLight Hsieh r0 = 1; 679fb34a9aeSZhiyong Tao } 680fb34a9aeSZhiyong Tao 681fb34a9aeSZhiyong Tao /* Case for: RSEL */ 682fb34a9aeSZhiyong Tao if (pullen >= MTK_PULL_SET_RSEL_000 && 683fb34a9aeSZhiyong Tao pullen <= MTK_PULL_SET_RSEL_111) { 684fb34a9aeSZhiyong Tao rsel = pullen - MTK_PULL_SET_RSEL_000; 685fb34a9aeSZhiyong Tao pullen = 1; 686fb34a9aeSZhiyong Tao } 687184d8e13SLight Hsieh } 68825a74c0fSZhiyong Tao len += scnprintf(buf + len, buf_len - len, 689184d8e13SLight Hsieh "%03d: %1d%1d%1d%1d%02d%1d%1d%1d%1d", 690184d8e13SLight Hsieh gpio, 691184d8e13SLight Hsieh pinmux, 692184d8e13SLight Hsieh mtk_pctrl_get_direction(hw, gpio), 693184d8e13SLight Hsieh mtk_pctrl_get_out(hw, gpio), 694184d8e13SLight Hsieh mtk_pctrl_get_in(hw, gpio), 695184d8e13SLight Hsieh mtk_pctrl_get_driving(hw, gpio), 696184d8e13SLight Hsieh mtk_pctrl_get_smt(hw, gpio), 697184d8e13SLight Hsieh mtk_pctrl_get_ies(hw, gpio), 698184d8e13SLight Hsieh pullen, 699184d8e13SLight Hsieh pullup); 700184d8e13SLight Hsieh 701fcde2a3fSChen-Yu Tsai if (r1 != -1) 702fcde2a3fSChen-Yu Tsai len += scnprintf(buf + len, buf_len - len, " (%1d %1d)", r1, r0); 703fcde2a3fSChen-Yu Tsai else if (rsel != -1) 704fcde2a3fSChen-Yu Tsai len += scnprintf(buf + len, buf_len - len, " (%1d)", rsel); 705184d8e13SLight Hsieh 706184d8e13SLight Hsieh return len; 707184d8e13SLight Hsieh } 7088174a851SLight Hsieh EXPORT_SYMBOL_GPL(mtk_pctrl_show_one_pin); 709184d8e13SLight Hsieh 710184d8e13SLight Hsieh #define PIN_DBG_BUF_SZ 96 711184d8e13SLight Hsieh static void mtk_pctrl_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, 712184d8e13SLight Hsieh unsigned int gpio) 713184d8e13SLight Hsieh { 714184d8e13SLight Hsieh struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 715184d8e13SLight Hsieh char buf[PIN_DBG_BUF_SZ]; 716184d8e13SLight Hsieh 717184d8e13SLight Hsieh (void)mtk_pctrl_show_one_pin(hw, gpio, buf, PIN_DBG_BUF_SZ); 718184d8e13SLight Hsieh 719184d8e13SLight Hsieh seq_printf(s, "%s", buf); 720184d8e13SLight Hsieh } 721184d8e13SLight Hsieh 72280525098SZhiyong Tao static const struct pinctrl_ops mtk_pctlops = { 72380525098SZhiyong Tao .dt_node_to_map = mtk_pctrl_dt_node_to_map, 72480525098SZhiyong Tao .dt_free_map = pinctrl_utils_free_map, 72580525098SZhiyong Tao .get_groups_count = mtk_pctrl_get_groups_count, 72680525098SZhiyong Tao .get_group_name = mtk_pctrl_get_group_name, 72780525098SZhiyong Tao .get_group_pins = mtk_pctrl_get_group_pins, 728184d8e13SLight Hsieh .pin_dbg_show = mtk_pctrl_dbg_show, 72980525098SZhiyong Tao }; 73080525098SZhiyong Tao 73180525098SZhiyong Tao static int mtk_pmx_get_funcs_cnt(struct pinctrl_dev *pctldev) 73280525098SZhiyong Tao { 73380525098SZhiyong Tao return ARRAY_SIZE(mtk_gpio_functions); 73480525098SZhiyong Tao } 73580525098SZhiyong Tao 73680525098SZhiyong Tao static const char *mtk_pmx_get_func_name(struct pinctrl_dev *pctldev, 73780525098SZhiyong Tao unsigned selector) 73880525098SZhiyong Tao { 73980525098SZhiyong Tao return mtk_gpio_functions[selector]; 74080525098SZhiyong Tao } 74180525098SZhiyong Tao 74280525098SZhiyong Tao static int mtk_pmx_get_func_groups(struct pinctrl_dev *pctldev, 74380525098SZhiyong Tao unsigned function, 74480525098SZhiyong Tao const char * const **groups, 74580525098SZhiyong Tao unsigned * const num_groups) 74680525098SZhiyong Tao { 74780525098SZhiyong Tao struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 74880525098SZhiyong Tao 74980525098SZhiyong Tao *groups = hw->grp_names; 75080525098SZhiyong Tao *num_groups = hw->soc->ngrps; 75180525098SZhiyong Tao 75280525098SZhiyong Tao return 0; 75380525098SZhiyong Tao } 75480525098SZhiyong Tao 75580525098SZhiyong Tao static int mtk_pmx_set_mux(struct pinctrl_dev *pctldev, 75680525098SZhiyong Tao unsigned function, 75780525098SZhiyong Tao unsigned group) 75880525098SZhiyong Tao { 75980525098SZhiyong Tao struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 76080525098SZhiyong Tao struct mtk_pinctrl_group *grp = hw->groups + group; 76180525098SZhiyong Tao const struct mtk_func_desc *desc_func; 76280525098SZhiyong Tao const struct mtk_pin_desc *desc; 76380525098SZhiyong Tao bool ret; 76480525098SZhiyong Tao 76580525098SZhiyong Tao ret = mtk_pctrl_is_function_valid(hw, grp->pin, function); 76680525098SZhiyong Tao if (!ret) { 76780525098SZhiyong Tao dev_err(hw->dev, "invalid function %d on group %d .\n", 76880525098SZhiyong Tao function, group); 76980525098SZhiyong Tao return -EINVAL; 77080525098SZhiyong Tao } 77180525098SZhiyong Tao 77280525098SZhiyong Tao desc_func = mtk_pctrl_find_function_by_pin(hw, grp->pin, function); 77380525098SZhiyong Tao if (!desc_func) 77480525098SZhiyong Tao return -EINVAL; 77580525098SZhiyong Tao 77680525098SZhiyong Tao desc = (const struct mtk_pin_desc *)&hw->soc->pins[grp->pin]; 77780525098SZhiyong Tao mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_MODE, desc_func->muxval); 77880525098SZhiyong Tao 77980525098SZhiyong Tao return 0; 78080525098SZhiyong Tao } 78180525098SZhiyong Tao 78280525098SZhiyong Tao static const struct pinmux_ops mtk_pmxops = { 78380525098SZhiyong Tao .get_functions_count = mtk_pmx_get_funcs_cnt, 78480525098SZhiyong Tao .get_function_name = mtk_pmx_get_func_name, 78580525098SZhiyong Tao .get_function_groups = mtk_pmx_get_func_groups, 78680525098SZhiyong Tao .set_mux = mtk_pmx_set_mux, 78780525098SZhiyong Tao .gpio_set_direction = mtk_pinmux_gpio_set_direction, 78880525098SZhiyong Tao .gpio_request_enable = mtk_pinmux_gpio_request_enable, 78980525098SZhiyong Tao }; 79080525098SZhiyong Tao 79180525098SZhiyong Tao static int mtk_pconf_group_get(struct pinctrl_dev *pctldev, unsigned group, 79280525098SZhiyong Tao unsigned long *config) 79380525098SZhiyong Tao { 79480525098SZhiyong Tao struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 79554fe55fbSChen-Yu Tsai struct mtk_pinctrl_group *grp = &hw->groups[group]; 79680525098SZhiyong Tao 79754fe55fbSChen-Yu Tsai /* One pin per group only */ 79854fe55fbSChen-Yu Tsai return mtk_pinconf_get(pctldev, grp->pin, config); 79980525098SZhiyong Tao } 80080525098SZhiyong Tao 80180525098SZhiyong Tao static int mtk_pconf_group_set(struct pinctrl_dev *pctldev, unsigned group, 80280525098SZhiyong Tao unsigned long *configs, unsigned num_configs) 80380525098SZhiyong Tao { 80480525098SZhiyong Tao struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev); 80580525098SZhiyong Tao struct mtk_pinctrl_group *grp = &hw->groups[group]; 806e5fabbe4SChen-Yu Tsai bool drive_strength_uA_found = false; 807e5fabbe4SChen-Yu Tsai bool adv_drve_strength_found = false; 80880525098SZhiyong Tao int i, ret; 80980525098SZhiyong Tao 81080525098SZhiyong Tao for (i = 0; i < num_configs; i++) { 81180525098SZhiyong Tao ret = mtk_pinconf_set(pctldev, grp->pin, 81280525098SZhiyong Tao pinconf_to_config_param(configs[i]), 81380525098SZhiyong Tao pinconf_to_config_argument(configs[i])); 81480525098SZhiyong Tao if (ret < 0) 81580525098SZhiyong Tao return ret; 816e5fabbe4SChen-Yu Tsai 817e5fabbe4SChen-Yu Tsai if (pinconf_to_config_param(configs[i]) == PIN_CONFIG_DRIVE_STRENGTH_UA) 818e5fabbe4SChen-Yu Tsai drive_strength_uA_found = true; 819e5fabbe4SChen-Yu Tsai if (pinconf_to_config_param(configs[i]) == MTK_PIN_CONFIG_DRV_ADV) 820e5fabbe4SChen-Yu Tsai adv_drve_strength_found = true; 82180525098SZhiyong Tao } 82280525098SZhiyong Tao 823e5fabbe4SChen-Yu Tsai /* 824e5fabbe4SChen-Yu Tsai * Disable advanced drive strength mode if drive-strength-microamp 825e5fabbe4SChen-Yu Tsai * is not set. However, mediatek,drive-strength-adv takes precedence 826e5fabbe4SChen-Yu Tsai * as its value can explicitly request the mode be enabled or not. 827e5fabbe4SChen-Yu Tsai */ 828e5fabbe4SChen-Yu Tsai if (hw->soc->adv_drive_set && !drive_strength_uA_found && 829e5fabbe4SChen-Yu Tsai !adv_drve_strength_found) 830e5fabbe4SChen-Yu Tsai hw->soc->adv_drive_set(hw, &hw->soc->pins[grp->pin], 0); 831e5fabbe4SChen-Yu Tsai 83280525098SZhiyong Tao return 0; 83380525098SZhiyong Tao } 83480525098SZhiyong Tao 83580525098SZhiyong Tao static const struct pinconf_ops mtk_confops = { 83680525098SZhiyong Tao .pin_config_get = mtk_pinconf_get, 83780525098SZhiyong Tao .pin_config_group_get = mtk_pconf_group_get, 83880525098SZhiyong Tao .pin_config_group_set = mtk_pconf_group_set, 839184d8e13SLight Hsieh .is_generic = true, 84080525098SZhiyong Tao }; 84180525098SZhiyong Tao 84280525098SZhiyong Tao static struct pinctrl_desc mtk_desc = { 84380525098SZhiyong Tao .name = PINCTRL_PINCTRL_DEV, 84480525098SZhiyong Tao .pctlops = &mtk_pctlops, 84580525098SZhiyong Tao .pmxops = &mtk_pmxops, 84680525098SZhiyong Tao .confops = &mtk_confops, 84780525098SZhiyong Tao .owner = THIS_MODULE, 84880525098SZhiyong Tao }; 84980525098SZhiyong Tao 85080525098SZhiyong Tao static int mtk_gpio_get_direction(struct gpio_chip *chip, unsigned int gpio) 85180525098SZhiyong Tao { 85280525098SZhiyong Tao struct mtk_pinctrl *hw = gpiochip_get_data(chip); 85380525098SZhiyong Tao const struct mtk_pin_desc *desc; 85480525098SZhiyong Tao int value, err; 85580525098SZhiyong Tao 8563385ab72SDan Carpenter if (gpio >= hw->soc->npins) 8573de7deefSLight Hsieh return -EINVAL; 8583de7deefSLight Hsieh 859edd54646SHanks Chen /* 860edd54646SHanks Chen * "Virtual" GPIOs are always and only used for interrupts 861edd54646SHanks Chen * Since they are only used for interrupts, they are always inputs 862edd54646SHanks Chen */ 863edd54646SHanks Chen if (mtk_is_virt_gpio(hw, gpio)) 864edd54646SHanks Chen return 1; 865edd54646SHanks Chen 86680525098SZhiyong Tao desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio]; 86780525098SZhiyong Tao 86880525098SZhiyong Tao err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DIR, &value); 86980525098SZhiyong Tao if (err) 87080525098SZhiyong Tao return err; 87180525098SZhiyong Tao 8723c827873SMatti Vaittinen if (value) 8733c827873SMatti Vaittinen return GPIO_LINE_DIRECTION_OUT; 8743c827873SMatti Vaittinen 8753c827873SMatti Vaittinen return GPIO_LINE_DIRECTION_IN; 87680525098SZhiyong Tao } 87780525098SZhiyong Tao 87880525098SZhiyong Tao static int mtk_gpio_get(struct gpio_chip *chip, unsigned int gpio) 87980525098SZhiyong Tao { 88080525098SZhiyong Tao struct mtk_pinctrl *hw = gpiochip_get_data(chip); 88180525098SZhiyong Tao const struct mtk_pin_desc *desc; 88280525098SZhiyong Tao int value, err; 88380525098SZhiyong Tao 8843385ab72SDan Carpenter if (gpio >= hw->soc->npins) 8853de7deefSLight Hsieh return -EINVAL; 8863de7deefSLight Hsieh 88780525098SZhiyong Tao desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio]; 88880525098SZhiyong Tao 88980525098SZhiyong Tao err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DI, &value); 89080525098SZhiyong Tao if (err) 89180525098SZhiyong Tao return err; 89280525098SZhiyong Tao 89380525098SZhiyong Tao return !!value; 89480525098SZhiyong Tao } 89580525098SZhiyong Tao 89680525098SZhiyong Tao static void mtk_gpio_set(struct gpio_chip *chip, unsigned int gpio, int value) 89780525098SZhiyong Tao { 89880525098SZhiyong Tao struct mtk_pinctrl *hw = gpiochip_get_data(chip); 89980525098SZhiyong Tao const struct mtk_pin_desc *desc; 90080525098SZhiyong Tao 9013385ab72SDan Carpenter if (gpio >= hw->soc->npins) 9023de7deefSLight Hsieh return; 9033de7deefSLight Hsieh 90480525098SZhiyong Tao desc = (const struct mtk_pin_desc *)&hw->soc->pins[gpio]; 90580525098SZhiyong Tao 90680525098SZhiyong Tao mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DO, !!value); 90780525098SZhiyong Tao } 90880525098SZhiyong Tao 90980525098SZhiyong Tao static int mtk_gpio_direction_input(struct gpio_chip *chip, unsigned int gpio) 91080525098SZhiyong Tao { 9113de7deefSLight Hsieh struct mtk_pinctrl *hw = gpiochip_get_data(chip); 9123de7deefSLight Hsieh 9133385ab72SDan Carpenter if (gpio >= hw->soc->npins) 9143de7deefSLight Hsieh return -EINVAL; 9153de7deefSLight Hsieh 91680525098SZhiyong Tao return pinctrl_gpio_direction_input(chip->base + gpio); 91780525098SZhiyong Tao } 91880525098SZhiyong Tao 91980525098SZhiyong Tao static int mtk_gpio_direction_output(struct gpio_chip *chip, unsigned int gpio, 92080525098SZhiyong Tao int value) 92180525098SZhiyong Tao { 9223de7deefSLight Hsieh struct mtk_pinctrl *hw = gpiochip_get_data(chip); 9233de7deefSLight Hsieh 9243385ab72SDan Carpenter if (gpio >= hw->soc->npins) 9253de7deefSLight Hsieh return -EINVAL; 9263de7deefSLight Hsieh 92780525098SZhiyong Tao mtk_gpio_set(chip, gpio, value); 92880525098SZhiyong Tao 92980525098SZhiyong Tao return pinctrl_gpio_direction_output(chip->base + gpio); 93080525098SZhiyong Tao } 93180525098SZhiyong Tao 9326561859bSSean Wang static int mtk_gpio_to_irq(struct gpio_chip *chip, unsigned int offset) 9336561859bSSean Wang { 9346561859bSSean Wang struct mtk_pinctrl *hw = gpiochip_get_data(chip); 9356561859bSSean Wang const struct mtk_pin_desc *desc; 9366561859bSSean Wang 9376561859bSSean Wang if (!hw->eint) 9386561859bSSean Wang return -ENOTSUPP; 9396561859bSSean Wang 9406561859bSSean Wang desc = (const struct mtk_pin_desc *)&hw->soc->pins[offset]; 9416561859bSSean Wang 9426561859bSSean Wang if (desc->eint.eint_n == EINT_NA) 9436561859bSSean Wang return -ENOTSUPP; 9446561859bSSean Wang 9456561859bSSean Wang return mtk_eint_find_irq(hw->eint, desc->eint.eint_n); 9466561859bSSean Wang } 9476561859bSSean Wang 94880525098SZhiyong Tao static int mtk_gpio_set_config(struct gpio_chip *chip, unsigned int offset, 94980525098SZhiyong Tao unsigned long config) 95080525098SZhiyong Tao { 95180525098SZhiyong Tao struct mtk_pinctrl *hw = gpiochip_get_data(chip); 95280525098SZhiyong Tao const struct mtk_pin_desc *desc; 95380525098SZhiyong Tao u32 debounce; 95480525098SZhiyong Tao 95580525098SZhiyong Tao desc = (const struct mtk_pin_desc *)&hw->soc->pins[offset]; 95680525098SZhiyong Tao 95780525098SZhiyong Tao if (!hw->eint || 95880525098SZhiyong Tao pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE || 95980525098SZhiyong Tao desc->eint.eint_n == EINT_NA) 96080525098SZhiyong Tao return -ENOTSUPP; 96180525098SZhiyong Tao 96280525098SZhiyong Tao debounce = pinconf_to_config_argument(config); 96380525098SZhiyong Tao 96480525098SZhiyong Tao return mtk_eint_set_debounce(hw->eint, desc->eint.eint_n, debounce); 96580525098SZhiyong Tao } 96680525098SZhiyong Tao 9678a8d6bbeSAndy Shevchenko static int mtk_build_gpiochip(struct mtk_pinctrl *hw) 96880525098SZhiyong Tao { 96980525098SZhiyong Tao struct gpio_chip *chip = &hw->chip; 97080525098SZhiyong Tao int ret; 97180525098SZhiyong Tao 97280525098SZhiyong Tao chip->label = PINCTRL_PINCTRL_DEV; 97380525098SZhiyong Tao chip->parent = hw->dev; 97480525098SZhiyong Tao chip->request = gpiochip_generic_request; 97580525098SZhiyong Tao chip->free = gpiochip_generic_free; 97680525098SZhiyong Tao chip->get_direction = mtk_gpio_get_direction; 97780525098SZhiyong Tao chip->direction_input = mtk_gpio_direction_input; 97880525098SZhiyong Tao chip->direction_output = mtk_gpio_direction_output; 97980525098SZhiyong Tao chip->get = mtk_gpio_get; 98080525098SZhiyong Tao chip->set = mtk_gpio_set; 9818ad57493SZheng Yongjun chip->to_irq = mtk_gpio_to_irq; 9828ad57493SZheng Yongjun chip->set_config = mtk_gpio_set_config; 98380525098SZhiyong Tao chip->base = -1; 98480525098SZhiyong Tao chip->ngpio = hw->soc->npins; 98580525098SZhiyong Tao chip->of_gpio_n_cells = 2; 98680525098SZhiyong Tao 98780525098SZhiyong Tao ret = gpiochip_add_data(chip, hw); 98880525098SZhiyong Tao if (ret < 0) 98980525098SZhiyong Tao return ret; 99080525098SZhiyong Tao 99180525098SZhiyong Tao return 0; 99280525098SZhiyong Tao } 99380525098SZhiyong Tao 99480525098SZhiyong Tao static int mtk_pctrl_build_state(struct platform_device *pdev) 99580525098SZhiyong Tao { 99680525098SZhiyong Tao struct mtk_pinctrl *hw = platform_get_drvdata(pdev); 99780525098SZhiyong Tao int i; 99880525098SZhiyong Tao 99980525098SZhiyong Tao /* Allocate groups */ 100080525098SZhiyong Tao hw->groups = devm_kmalloc_array(&pdev->dev, hw->soc->ngrps, 100180525098SZhiyong Tao sizeof(*hw->groups), GFP_KERNEL); 100280525098SZhiyong Tao if (!hw->groups) 100380525098SZhiyong Tao return -ENOMEM; 100480525098SZhiyong Tao 100580525098SZhiyong Tao /* We assume that one pin is one group, use pin name as group name. */ 100680525098SZhiyong Tao hw->grp_names = devm_kmalloc_array(&pdev->dev, hw->soc->ngrps, 100780525098SZhiyong Tao sizeof(*hw->grp_names), GFP_KERNEL); 100880525098SZhiyong Tao if (!hw->grp_names) 100980525098SZhiyong Tao return -ENOMEM; 101080525098SZhiyong Tao 101180525098SZhiyong Tao for (i = 0; i < hw->soc->npins; i++) { 101280525098SZhiyong Tao const struct mtk_pin_desc *pin = hw->soc->pins + i; 101380525098SZhiyong Tao struct mtk_pinctrl_group *group = hw->groups + i; 101480525098SZhiyong Tao 101580525098SZhiyong Tao group->name = pin->name; 101680525098SZhiyong Tao group->pin = pin->number; 101780525098SZhiyong Tao 101880525098SZhiyong Tao hw->grp_names[i] = pin->name; 101980525098SZhiyong Tao } 102080525098SZhiyong Tao 102180525098SZhiyong Tao return 0; 102280525098SZhiyong Tao } 102380525098SZhiyong Tao 102478df7bbaSAngeloGioacchino Del Regno int mtk_paris_pinctrl_probe(struct platform_device *pdev) 102580525098SZhiyong Tao { 1026dc75d1edSAngeloGioacchino Del Regno struct device *dev = &pdev->dev; 102780525098SZhiyong Tao struct pinctrl_pin_desc *pins; 102880525098SZhiyong Tao struct mtk_pinctrl *hw; 102980525098SZhiyong Tao int err, i; 103080525098SZhiyong Tao 103180525098SZhiyong Tao hw = devm_kzalloc(&pdev->dev, sizeof(*hw), GFP_KERNEL); 103280525098SZhiyong Tao if (!hw) 103380525098SZhiyong Tao return -ENOMEM; 103480525098SZhiyong Tao 103580525098SZhiyong Tao platform_set_drvdata(pdev, hw); 103678df7bbaSAngeloGioacchino Del Regno 103778df7bbaSAngeloGioacchino Del Regno hw->soc = device_get_match_data(dev); 103878df7bbaSAngeloGioacchino Del Regno if (!hw->soc) 103978df7bbaSAngeloGioacchino Del Regno return -ENOENT; 104078df7bbaSAngeloGioacchino Del Regno 104180525098SZhiyong Tao hw->dev = &pdev->dev; 104280525098SZhiyong Tao 1043dc75d1edSAngeloGioacchino Del Regno if (!hw->soc->nbase_names) 1044dc75d1edSAngeloGioacchino Del Regno return dev_err_probe(dev, -EINVAL, 104580525098SZhiyong Tao "SoC should be assigned at least one register base\n"); 104680525098SZhiyong Tao 104780525098SZhiyong Tao hw->base = devm_kmalloc_array(&pdev->dev, hw->soc->nbase_names, 104880525098SZhiyong Tao sizeof(*hw->base), GFP_KERNEL); 1049184744e9SWei Yongjun if (!hw->base) 1050184744e9SWei Yongjun return -ENOMEM; 105180525098SZhiyong Tao 105280525098SZhiyong Tao for (i = 0; i < hw->soc->nbase_names; i++) { 105348548c78SWang Xiaojun hw->base[i] = devm_platform_ioremap_resource_byname(pdev, 105480525098SZhiyong Tao hw->soc->base_names[i]); 105580525098SZhiyong Tao if (IS_ERR(hw->base[i])) 105680525098SZhiyong Tao return PTR_ERR(hw->base[i]); 105780525098SZhiyong Tao } 105880525098SZhiyong Tao 105980525098SZhiyong Tao hw->nbase = hw->soc->nbase_names; 106080525098SZhiyong Tao 1061fb34a9aeSZhiyong Tao if (of_find_property(hw->dev->of_node, 10627966c505SGuodong Liu "mediatek,rsel-resistance-in-si-unit", NULL)) 1063fb34a9aeSZhiyong Tao hw->rsel_si_unit = true; 1064fb34a9aeSZhiyong Tao else 1065fb34a9aeSZhiyong Tao hw->rsel_si_unit = false; 1066fb34a9aeSZhiyong Tao 106756ab29ecSTzung-Bi Shih spin_lock_init(&hw->lock); 106842a46434SZhiyong Tao 106980525098SZhiyong Tao err = mtk_pctrl_build_state(pdev); 1070dc75d1edSAngeloGioacchino Del Regno if (err) 1071dc75d1edSAngeloGioacchino Del Regno return dev_err_probe(dev, err, "build state failed\n"); 107280525098SZhiyong Tao 107380525098SZhiyong Tao /* Copy from internal struct mtk_pin_desc to register to the core */ 107480525098SZhiyong Tao pins = devm_kmalloc_array(&pdev->dev, hw->soc->npins, sizeof(*pins), 107580525098SZhiyong Tao GFP_KERNEL); 1076184744e9SWei Yongjun if (!pins) 1077184744e9SWei Yongjun return -ENOMEM; 107880525098SZhiyong Tao 107980525098SZhiyong Tao for (i = 0; i < hw->soc->npins; i++) { 108080525098SZhiyong Tao pins[i].number = hw->soc->pins[i].number; 108180525098SZhiyong Tao pins[i].name = hw->soc->pins[i].name; 108280525098SZhiyong Tao } 108380525098SZhiyong Tao 108480525098SZhiyong Tao /* Setup pins descriptions per SoC types */ 108580525098SZhiyong Tao mtk_desc.pins = (const struct pinctrl_pin_desc *)pins; 108680525098SZhiyong Tao mtk_desc.npins = hw->soc->npins; 108780525098SZhiyong Tao mtk_desc.num_custom_params = ARRAY_SIZE(mtk_custom_bindings); 108880525098SZhiyong Tao mtk_desc.custom_params = mtk_custom_bindings; 108980525098SZhiyong Tao #ifdef CONFIG_DEBUG_FS 109080525098SZhiyong Tao mtk_desc.custom_conf_items = mtk_conf_items; 109180525098SZhiyong Tao #endif 109280525098SZhiyong Tao 109380525098SZhiyong Tao err = devm_pinctrl_register_and_init(&pdev->dev, &mtk_desc, hw, 109480525098SZhiyong Tao &hw->pctrl); 109580525098SZhiyong Tao if (err) 109680525098SZhiyong Tao return err; 109780525098SZhiyong Tao 109880525098SZhiyong Tao err = pinctrl_enable(hw->pctrl); 109980525098SZhiyong Tao if (err) 110080525098SZhiyong Tao return err; 110180525098SZhiyong Tao 11026561859bSSean Wang err = mtk_build_eint(hw, pdev); 11036561859bSSean Wang if (err) 11046561859bSSean Wang dev_warn(&pdev->dev, 11056561859bSSean Wang "Failed to add EINT, but pinctrl still can work\n"); 11066561859bSSean Wang 110780525098SZhiyong Tao /* Build gpiochip should be after pinctrl_enable is done */ 11088a8d6bbeSAndy Shevchenko err = mtk_build_gpiochip(hw); 1109dc75d1edSAngeloGioacchino Del Regno if (err) 1110dc75d1edSAngeloGioacchino Del Regno return dev_err_probe(dev, err, "Failed to add gpio_chip\n"); 111180525098SZhiyong Tao 111280525098SZhiyong Tao platform_set_drvdata(pdev, hw); 111380525098SZhiyong Tao 111480525098SZhiyong Tao return 0; 111580525098SZhiyong Tao } 11168174a851SLight Hsieh EXPORT_SYMBOL_GPL(mtk_paris_pinctrl_probe); 11175c090448SNicolas Boichat 11185c090448SNicolas Boichat static int mtk_paris_pinctrl_suspend(struct device *device) 11195c090448SNicolas Boichat { 11205c090448SNicolas Boichat struct mtk_pinctrl *pctl = dev_get_drvdata(device); 11215c090448SNicolas Boichat 11225c090448SNicolas Boichat return mtk_eint_do_suspend(pctl->eint); 11235c090448SNicolas Boichat } 11245c090448SNicolas Boichat 11255c090448SNicolas Boichat static int mtk_paris_pinctrl_resume(struct device *device) 11265c090448SNicolas Boichat { 11275c090448SNicolas Boichat struct mtk_pinctrl *pctl = dev_get_drvdata(device); 11285c090448SNicolas Boichat 11295c090448SNicolas Boichat return mtk_eint_do_resume(pctl->eint); 11305c090448SNicolas Boichat } 11315c090448SNicolas Boichat 11325c090448SNicolas Boichat const struct dev_pm_ops mtk_paris_pinctrl_pm_ops = { 11335c090448SNicolas Boichat .suspend_noirq = mtk_paris_pinctrl_suspend, 11345c090448SNicolas Boichat .resume_noirq = mtk_paris_pinctrl_resume, 11355c090448SNicolas Boichat }; 11368174a851SLight Hsieh 11378174a851SLight Hsieh MODULE_LICENSE("GPL v2"); 11388174a851SLight Hsieh MODULE_DESCRIPTION("MediaTek Pinctrl Common Driver V2 Paris"); 1139