11802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2a6df410dSHongzhou Yang /* 3a6df410dSHongzhou Yang * mt65xx pinctrl driver based on Allwinner A1X pinctrl driver. 4a6df410dSHongzhou Yang * Copyright (c) 2014 MediaTek Inc. 5a6df410dSHongzhou Yang * Author: Hongzhou.Yang <hongzhou.yang@mediatek.com> 6a6df410dSHongzhou Yang */ 7a6df410dSHongzhou Yang 8a6df410dSHongzhou Yang #include <linux/io.h> 911aa679aSLinus Walleij #include <linux/gpio/driver.h> 10a6df410dSHongzhou Yang #include <linux/of.h> 11a6df410dSHongzhou Yang #include <linux/of_address.h> 12a6df410dSHongzhou Yang #include <linux/of_device.h> 13a6df410dSHongzhou Yang #include <linux/of_irq.h> 14a6df410dSHongzhou Yang #include <linux/pinctrl/consumer.h> 15a6df410dSHongzhou Yang #include <linux/pinctrl/machine.h> 16a6df410dSHongzhou Yang #include <linux/pinctrl/pinconf.h> 17a6df410dSHongzhou Yang #include <linux/pinctrl/pinconf-generic.h> 18a6df410dSHongzhou Yang #include <linux/pinctrl/pinctrl.h> 19a6df410dSHongzhou Yang #include <linux/pinctrl/pinmux.h> 20a6df410dSHongzhou Yang #include <linux/platform_device.h> 21a6df410dSHongzhou Yang #include <linux/slab.h> 22a6df410dSHongzhou Yang #include <linux/bitops.h> 23a6df410dSHongzhou Yang #include <linux/regmap.h> 24a6df410dSHongzhou Yang #include <linux/mfd/syscon.h> 25d9819eb9SMaoguang Meng #include <linux/delay.h> 2630f010f5SHongzhou Yang #include <linux/interrupt.h> 2758a5e1b6SMaoguang Meng #include <linux/pm.h> 28a6df410dSHongzhou Yang #include <dt-bindings/pinctrl/mt65xx.h> 29a6df410dSHongzhou Yang 30a6df410dSHongzhou Yang #include "../core.h" 31a6df410dSHongzhou Yang #include "../pinconf.h" 32a6df410dSHongzhou Yang #include "../pinctrl-utils.h" 33e46df235SSean Wang #include "mtk-eint.h" 34a6df410dSHongzhou Yang #include "pinctrl-mtk-common.h" 35a6df410dSHongzhou Yang 36a6df410dSHongzhou Yang #define MAX_GPIO_MODE_PER_REG 5 37a6df410dSHongzhou Yang #define GPIO_MODE_BITS 3 3859ee9c96SBiao Huang #define GPIO_MODE_PREFIX "GPIO" 39a6df410dSHongzhou Yang 40a6df410dSHongzhou Yang static const char * const mtk_gpio_functions[] = { 41a6df410dSHongzhou Yang "func0", "func1", "func2", "func3", 42a6df410dSHongzhou Yang "func4", "func5", "func6", "func7", 43148b95eeSBiao Huang "func8", "func9", "func10", "func11", 44148b95eeSBiao Huang "func12", "func13", "func14", "func15", 45a6df410dSHongzhou Yang }; 46a6df410dSHongzhou Yang 47a6df410dSHongzhou Yang /* 48a6df410dSHongzhou Yang * There are two base address for pull related configuration 49a6df410dSHongzhou Yang * in mt8135, and different GPIO pins use different base address. 50a6df410dSHongzhou Yang * When pin number greater than type1_start and less than type1_end, 51a6df410dSHongzhou Yang * should use the second base address. 52a6df410dSHongzhou Yang */ 53a6df410dSHongzhou Yang static struct regmap *mtk_get_regmap(struct mtk_pinctrl *pctl, 54a6df410dSHongzhou Yang unsigned long pin) 55a6df410dSHongzhou Yang { 56a6df410dSHongzhou Yang if (pin >= pctl->devdata->type1_start && pin < pctl->devdata->type1_end) 57a6df410dSHongzhou Yang return pctl->regmap2; 58a6df410dSHongzhou Yang return pctl->regmap1; 59a6df410dSHongzhou Yang } 60a6df410dSHongzhou Yang 61a6df410dSHongzhou Yang static unsigned int mtk_get_port(struct mtk_pinctrl *pctl, unsigned long pin) 62a6df410dSHongzhou Yang { 63a6df410dSHongzhou Yang /* Different SoC has different mask and port shift. */ 64a6df410dSHongzhou Yang return ((pin >> 4) & pctl->devdata->port_mask) 65a6df410dSHongzhou Yang << pctl->devdata->port_shf; 66a6df410dSHongzhou Yang } 67a6df410dSHongzhou Yang 68a6df410dSHongzhou Yang static int mtk_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, 69a6df410dSHongzhou Yang struct pinctrl_gpio_range *range, unsigned offset, 70a6df410dSHongzhou Yang bool input) 71a6df410dSHongzhou Yang { 72a6df410dSHongzhou Yang unsigned int reg_addr; 73a6df410dSHongzhou Yang unsigned int bit; 74a6df410dSHongzhou Yang struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 75a6df410dSHongzhou Yang 76a6df410dSHongzhou Yang reg_addr = mtk_get_port(pctl, offset) + pctl->devdata->dir_offset; 77a6df410dSHongzhou Yang bit = BIT(offset & 0xf); 78a6df410dSHongzhou Yang 79148b95eeSBiao Huang if (pctl->devdata->spec_dir_set) 80148b95eeSBiao Huang pctl->devdata->spec_dir_set(®_addr, offset); 81148b95eeSBiao Huang 82a6df410dSHongzhou Yang if (input) 83a6df410dSHongzhou Yang /* Different SoC has different alignment offset. */ 84a6df410dSHongzhou Yang reg_addr = CLR_ADDR(reg_addr, pctl); 85a6df410dSHongzhou Yang else 86a6df410dSHongzhou Yang reg_addr = SET_ADDR(reg_addr, pctl); 87a6df410dSHongzhou Yang 88a6df410dSHongzhou Yang regmap_write(mtk_get_regmap(pctl, offset), reg_addr, bit); 89a6df410dSHongzhou Yang return 0; 90a6df410dSHongzhou Yang } 91a6df410dSHongzhou Yang 92a6df410dSHongzhou Yang static void mtk_gpio_set(struct gpio_chip *chip, unsigned offset, int value) 93a6df410dSHongzhou Yang { 94a6df410dSHongzhou Yang unsigned int reg_addr; 95a6df410dSHongzhou Yang unsigned int bit; 9611aa679aSLinus Walleij struct mtk_pinctrl *pctl = gpiochip_get_data(chip); 97a6df410dSHongzhou Yang 98a6df410dSHongzhou Yang reg_addr = mtk_get_port(pctl, offset) + pctl->devdata->dout_offset; 99a6df410dSHongzhou Yang bit = BIT(offset & 0xf); 100a6df410dSHongzhou Yang 101a6df410dSHongzhou Yang if (value) 102a6df410dSHongzhou Yang reg_addr = SET_ADDR(reg_addr, pctl); 103a6df410dSHongzhou Yang else 104a6df410dSHongzhou Yang reg_addr = CLR_ADDR(reg_addr, pctl); 105a6df410dSHongzhou Yang 106a6df410dSHongzhou Yang regmap_write(mtk_get_regmap(pctl, offset), reg_addr, bit); 107a6df410dSHongzhou Yang } 108a6df410dSHongzhou Yang 10925d76b21SHongzhou Yang static int mtk_pconf_set_ies_smt(struct mtk_pinctrl *pctl, unsigned pin, 11025d76b21SHongzhou Yang int value, enum pin_config_param arg) 111a6df410dSHongzhou Yang { 112a6df410dSHongzhou Yang unsigned int reg_addr, offset; 113a6df410dSHongzhou Yang unsigned int bit; 11425d76b21SHongzhou Yang 11525d76b21SHongzhou Yang /** 11625d76b21SHongzhou Yang * Due to some soc are not support ies/smt config, add this special 11725d76b21SHongzhou Yang * control to handle it. 11825d76b21SHongzhou Yang */ 11925d76b21SHongzhou Yang if (!pctl->devdata->spec_ies_smt_set && 12025d76b21SHongzhou Yang pctl->devdata->ies_offset == MTK_PINCTRL_NOT_SUPPORT && 12125d76b21SHongzhou Yang arg == PIN_CONFIG_INPUT_ENABLE) 12225d76b21SHongzhou Yang return -EINVAL; 12325d76b21SHongzhou Yang 12425d76b21SHongzhou Yang if (!pctl->devdata->spec_ies_smt_set && 12525d76b21SHongzhou Yang pctl->devdata->smt_offset == MTK_PINCTRL_NOT_SUPPORT && 12625d76b21SHongzhou Yang arg == PIN_CONFIG_INPUT_SCHMITT_ENABLE) 12725d76b21SHongzhou Yang return -EINVAL; 12830f010f5SHongzhou Yang 12930f010f5SHongzhou Yang /* 13030f010f5SHongzhou Yang * Due to some pins are irregular, their input enable and smt 13125d76b21SHongzhou Yang * control register are discontinuous, so we need this special handle. 13230f010f5SHongzhou Yang */ 13330f010f5SHongzhou Yang if (pctl->devdata->spec_ies_smt_set) { 13425d76b21SHongzhou Yang return pctl->devdata->spec_ies_smt_set(mtk_get_regmap(pctl, pin), 13525d76b21SHongzhou Yang pin, pctl->devdata->port_align, value, arg); 13630f010f5SHongzhou Yang } 137a6df410dSHongzhou Yang 138a6df410dSHongzhou Yang bit = BIT(pin & 0xf); 139a6df410dSHongzhou Yang 14025d76b21SHongzhou Yang if (arg == PIN_CONFIG_INPUT_ENABLE) 141a6df410dSHongzhou Yang offset = pctl->devdata->ies_offset; 142a6df410dSHongzhou Yang else 143a6df410dSHongzhou Yang offset = pctl->devdata->smt_offset; 144a6df410dSHongzhou Yang 145a6df410dSHongzhou Yang if (value) 146a6df410dSHongzhou Yang reg_addr = SET_ADDR(mtk_get_port(pctl, pin) + offset, pctl); 147a6df410dSHongzhou Yang else 148a6df410dSHongzhou Yang reg_addr = CLR_ADDR(mtk_get_port(pctl, pin) + offset, pctl); 149a6df410dSHongzhou Yang 150a6df410dSHongzhou Yang regmap_write(mtk_get_regmap(pctl, pin), reg_addr, bit); 15125d76b21SHongzhou Yang return 0; 15225d76b21SHongzhou Yang } 15325d76b21SHongzhou Yang 15425d76b21SHongzhou Yang int mtk_pconf_spec_set_ies_smt_range(struct regmap *regmap, 15525d76b21SHongzhou Yang const struct mtk_pin_ies_smt_set *ies_smt_infos, unsigned int info_num, 15625d76b21SHongzhou Yang unsigned int pin, unsigned char align, int value) 15725d76b21SHongzhou Yang { 15825d76b21SHongzhou Yang unsigned int i, reg_addr, bit; 15925d76b21SHongzhou Yang 16025d76b21SHongzhou Yang for (i = 0; i < info_num; i++) { 16125d76b21SHongzhou Yang if (pin >= ies_smt_infos[i].start && 16225d76b21SHongzhou Yang pin <= ies_smt_infos[i].end) { 16325d76b21SHongzhou Yang break; 16425d76b21SHongzhou Yang } 16525d76b21SHongzhou Yang } 16625d76b21SHongzhou Yang 16725d76b21SHongzhou Yang if (i == info_num) 16825d76b21SHongzhou Yang return -EINVAL; 16925d76b21SHongzhou Yang 17025d76b21SHongzhou Yang if (value) 17125d76b21SHongzhou Yang reg_addr = ies_smt_infos[i].offset + align; 17225d76b21SHongzhou Yang else 17325d76b21SHongzhou Yang reg_addr = ies_smt_infos[i].offset + (align << 1); 17425d76b21SHongzhou Yang 17525d76b21SHongzhou Yang bit = BIT(ies_smt_infos[i].bit); 17625d76b21SHongzhou Yang regmap_write(regmap, reg_addr, bit); 17725d76b21SHongzhou Yang return 0; 178a6df410dSHongzhou Yang } 179a6df410dSHongzhou Yang 180a6df410dSHongzhou Yang static const struct mtk_pin_drv_grp *mtk_find_pin_drv_grp_by_pin( 181a6df410dSHongzhou Yang struct mtk_pinctrl *pctl, unsigned long pin) { 182a6df410dSHongzhou Yang int i; 183a6df410dSHongzhou Yang 184a6df410dSHongzhou Yang for (i = 0; i < pctl->devdata->n_pin_drv_grps; i++) { 185a6df410dSHongzhou Yang const struct mtk_pin_drv_grp *pin_drv = 186a6df410dSHongzhou Yang pctl->devdata->pin_drv_grp + i; 187a6df410dSHongzhou Yang if (pin == pin_drv->pin) 188a6df410dSHongzhou Yang return pin_drv; 189a6df410dSHongzhou Yang } 190a6df410dSHongzhou Yang 191a6df410dSHongzhou Yang return NULL; 192a6df410dSHongzhou Yang } 193a6df410dSHongzhou Yang 194a6df410dSHongzhou Yang static int mtk_pconf_set_driving(struct mtk_pinctrl *pctl, 195a6df410dSHongzhou Yang unsigned int pin, unsigned char driving) 196a6df410dSHongzhou Yang { 197a6df410dSHongzhou Yang const struct mtk_pin_drv_grp *pin_drv; 198a6df410dSHongzhou Yang unsigned int val; 199a6df410dSHongzhou Yang unsigned int bits, mask, shift; 200a6df410dSHongzhou Yang const struct mtk_drv_group_desc *drv_grp; 201a6df410dSHongzhou Yang 202a6df410dSHongzhou Yang if (pin >= pctl->devdata->npins) 203a6df410dSHongzhou Yang return -EINVAL; 204a6df410dSHongzhou Yang 205a6df410dSHongzhou Yang pin_drv = mtk_find_pin_drv_grp_by_pin(pctl, pin); 206a6df410dSHongzhou Yang if (!pin_drv || pin_drv->grp > pctl->devdata->n_grp_cls) 207a6df410dSHongzhou Yang return -EINVAL; 208a6df410dSHongzhou Yang 209a6df410dSHongzhou Yang drv_grp = pctl->devdata->grp_desc + pin_drv->grp; 210a6df410dSHongzhou Yang if (driving >= drv_grp->min_drv && driving <= drv_grp->max_drv 211a6df410dSHongzhou Yang && !(driving % drv_grp->step)) { 212a6df410dSHongzhou Yang val = driving / drv_grp->step - 1; 213a6df410dSHongzhou Yang bits = drv_grp->high_bit - drv_grp->low_bit + 1; 214a6df410dSHongzhou Yang mask = BIT(bits) - 1; 215a6df410dSHongzhou Yang shift = pin_drv->bit + drv_grp->low_bit; 216a6df410dSHongzhou Yang mask <<= shift; 217a6df410dSHongzhou Yang val <<= shift; 218a6df410dSHongzhou Yang return regmap_update_bits(mtk_get_regmap(pctl, pin), 219a6df410dSHongzhou Yang pin_drv->offset, mask, val); 220a6df410dSHongzhou Yang } 221a6df410dSHongzhou Yang 222a6df410dSHongzhou Yang return -EINVAL; 223a6df410dSHongzhou Yang } 224a6df410dSHongzhou Yang 225e73fe271SYingjoe Chen int mtk_pctrl_spec_pull_set_samereg(struct regmap *regmap, 226e73fe271SYingjoe Chen const struct mtk_pin_spec_pupd_set_samereg *pupd_infos, 227e73fe271SYingjoe Chen unsigned int info_num, unsigned int pin, 228e73fe271SYingjoe Chen unsigned char align, bool isup, unsigned int r1r0) 229e73fe271SYingjoe Chen { 230e73fe271SYingjoe Chen unsigned int i; 231e73fe271SYingjoe Chen unsigned int reg_pupd, reg_set, reg_rst; 232e73fe271SYingjoe Chen unsigned int bit_pupd, bit_r0, bit_r1; 233e73fe271SYingjoe Chen const struct mtk_pin_spec_pupd_set_samereg *spec_pupd_pin; 234e73fe271SYingjoe Chen bool find = false; 235e73fe271SYingjoe Chen 236e73fe271SYingjoe Chen for (i = 0; i < info_num; i++) { 237e73fe271SYingjoe Chen if (pin == pupd_infos[i].pin) { 238e73fe271SYingjoe Chen find = true; 239e73fe271SYingjoe Chen break; 240e73fe271SYingjoe Chen } 241e73fe271SYingjoe Chen } 242e73fe271SYingjoe Chen 243e73fe271SYingjoe Chen if (!find) 244e73fe271SYingjoe Chen return -EINVAL; 245e73fe271SYingjoe Chen 246e73fe271SYingjoe Chen spec_pupd_pin = pupd_infos + i; 247e73fe271SYingjoe Chen reg_set = spec_pupd_pin->offset + align; 248e73fe271SYingjoe Chen reg_rst = spec_pupd_pin->offset + (align << 1); 249e73fe271SYingjoe Chen 250e73fe271SYingjoe Chen if (isup) 251e73fe271SYingjoe Chen reg_pupd = reg_rst; 252e73fe271SYingjoe Chen else 253e73fe271SYingjoe Chen reg_pupd = reg_set; 254e73fe271SYingjoe Chen 255e73fe271SYingjoe Chen bit_pupd = BIT(spec_pupd_pin->pupd_bit); 256e73fe271SYingjoe Chen regmap_write(regmap, reg_pupd, bit_pupd); 257e73fe271SYingjoe Chen 258e73fe271SYingjoe Chen bit_r0 = BIT(spec_pupd_pin->r0_bit); 259e73fe271SYingjoe Chen bit_r1 = BIT(spec_pupd_pin->r1_bit); 260e73fe271SYingjoe Chen 261e73fe271SYingjoe Chen switch (r1r0) { 262e73fe271SYingjoe Chen case MTK_PUPD_SET_R1R0_00: 263e73fe271SYingjoe Chen regmap_write(regmap, reg_rst, bit_r0); 264e73fe271SYingjoe Chen regmap_write(regmap, reg_rst, bit_r1); 265e73fe271SYingjoe Chen break; 266e73fe271SYingjoe Chen case MTK_PUPD_SET_R1R0_01: 267e73fe271SYingjoe Chen regmap_write(regmap, reg_set, bit_r0); 268e73fe271SYingjoe Chen regmap_write(regmap, reg_rst, bit_r1); 269e73fe271SYingjoe Chen break; 270e73fe271SYingjoe Chen case MTK_PUPD_SET_R1R0_10: 271e73fe271SYingjoe Chen regmap_write(regmap, reg_rst, bit_r0); 272e73fe271SYingjoe Chen regmap_write(regmap, reg_set, bit_r1); 273e73fe271SYingjoe Chen break; 274e73fe271SYingjoe Chen case MTK_PUPD_SET_R1R0_11: 275e73fe271SYingjoe Chen regmap_write(regmap, reg_set, bit_r0); 276e73fe271SYingjoe Chen regmap_write(regmap, reg_set, bit_r1); 277e73fe271SYingjoe Chen break; 278e73fe271SYingjoe Chen default: 279e73fe271SYingjoe Chen return -EINVAL; 280e73fe271SYingjoe Chen } 281e73fe271SYingjoe Chen 282e73fe271SYingjoe Chen return 0; 283e73fe271SYingjoe Chen } 284e73fe271SYingjoe Chen 285a6df410dSHongzhou Yang static int mtk_pconf_set_pull_select(struct mtk_pinctrl *pctl, 286a6df410dSHongzhou Yang unsigned int pin, bool enable, bool isup, unsigned int arg) 287a6df410dSHongzhou Yang { 288a6df410dSHongzhou Yang unsigned int bit; 2896af8df4cSZhiyong Tao unsigned int reg_pullen, reg_pullsel, r1r0; 290a6df410dSHongzhou Yang int ret; 291a6df410dSHongzhou Yang 292a6df410dSHongzhou Yang /* Some pins' pull setting are very different, 293a6df410dSHongzhou Yang * they have separate pull up/down bit, R0 and R1 294a6df410dSHongzhou Yang * resistor bit, so we need this special handle. 295a6df410dSHongzhou Yang */ 296a6df410dSHongzhou Yang if (pctl->devdata->spec_pull_set) { 2976af8df4cSZhiyong Tao /* For special pins, bias-disable is set by R1R0, 2986af8df4cSZhiyong Tao * the parameter should be "MTK_PUPD_SET_R1R0_00". 2996af8df4cSZhiyong Tao */ 3006af8df4cSZhiyong Tao r1r0 = enable ? arg : MTK_PUPD_SET_R1R0_00; 301a6df410dSHongzhou Yang ret = pctl->devdata->spec_pull_set(mtk_get_regmap(pctl, pin), 3026af8df4cSZhiyong Tao pin, pctl->devdata->port_align, isup, r1r0); 303a6df410dSHongzhou Yang if (!ret) 304a6df410dSHongzhou Yang return 0; 305a6df410dSHongzhou Yang } 306a6df410dSHongzhou Yang 307a6df410dSHongzhou Yang /* For generic pull config, default arg value should be 0 or 1. */ 308a6df410dSHongzhou Yang if (arg != 0 && arg != 1) { 309a6df410dSHongzhou Yang dev_err(pctl->dev, "invalid pull-up argument %d on pin %d .\n", 310a6df410dSHongzhou Yang arg, pin); 311a6df410dSHongzhou Yang return -EINVAL; 312a6df410dSHongzhou Yang } 313a6df410dSHongzhou Yang 314a6df410dSHongzhou Yang bit = BIT(pin & 0xf); 315a6df410dSHongzhou Yang if (enable) 316a6df410dSHongzhou Yang reg_pullen = SET_ADDR(mtk_get_port(pctl, pin) + 317a6df410dSHongzhou Yang pctl->devdata->pullen_offset, pctl); 318a6df410dSHongzhou Yang else 319a6df410dSHongzhou Yang reg_pullen = CLR_ADDR(mtk_get_port(pctl, pin) + 320a6df410dSHongzhou Yang pctl->devdata->pullen_offset, pctl); 321a6df410dSHongzhou Yang 322a6df410dSHongzhou Yang if (isup) 323a6df410dSHongzhou Yang reg_pullsel = SET_ADDR(mtk_get_port(pctl, pin) + 324a6df410dSHongzhou Yang pctl->devdata->pullsel_offset, pctl); 325a6df410dSHongzhou Yang else 326a6df410dSHongzhou Yang reg_pullsel = CLR_ADDR(mtk_get_port(pctl, pin) + 327a6df410dSHongzhou Yang pctl->devdata->pullsel_offset, pctl); 328a6df410dSHongzhou Yang 329a6df410dSHongzhou Yang regmap_write(mtk_get_regmap(pctl, pin), reg_pullen, bit); 330a6df410dSHongzhou Yang regmap_write(mtk_get_regmap(pctl, pin), reg_pullsel, bit); 331a6df410dSHongzhou Yang return 0; 332a6df410dSHongzhou Yang } 333a6df410dSHongzhou Yang 334a6df410dSHongzhou Yang static int mtk_pconf_parse_conf(struct pinctrl_dev *pctldev, 335a6df410dSHongzhou Yang unsigned int pin, enum pin_config_param param, 336a6df410dSHongzhou Yang enum pin_config_param arg) 337a6df410dSHongzhou Yang { 33825d76b21SHongzhou Yang int ret = 0; 339a6df410dSHongzhou Yang struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 340a6df410dSHongzhou Yang 341a6df410dSHongzhou Yang switch (param) { 342a6df410dSHongzhou Yang case PIN_CONFIG_BIAS_DISABLE: 34325d76b21SHongzhou Yang ret = mtk_pconf_set_pull_select(pctl, pin, false, false, arg); 344a6df410dSHongzhou Yang break; 345a6df410dSHongzhou Yang case PIN_CONFIG_BIAS_PULL_UP: 34625d76b21SHongzhou Yang ret = mtk_pconf_set_pull_select(pctl, pin, true, true, arg); 347a6df410dSHongzhou Yang break; 348a6df410dSHongzhou Yang case PIN_CONFIG_BIAS_PULL_DOWN: 34925d76b21SHongzhou Yang ret = mtk_pconf_set_pull_select(pctl, pin, true, false, arg); 350a6df410dSHongzhou Yang break; 351a6df410dSHongzhou Yang case PIN_CONFIG_INPUT_ENABLE: 352eceb3e61SBiao Huang mtk_pmx_gpio_set_direction(pctldev, NULL, pin, true); 35325d76b21SHongzhou Yang ret = mtk_pconf_set_ies_smt(pctl, pin, arg, param); 354a6df410dSHongzhou Yang break; 355a6df410dSHongzhou Yang case PIN_CONFIG_OUTPUT: 356a6df410dSHongzhou Yang mtk_gpio_set(pctl->chip, pin, arg); 35725d76b21SHongzhou Yang ret = mtk_pmx_gpio_set_direction(pctldev, NULL, pin, false); 358a6df410dSHongzhou Yang break; 359a6df410dSHongzhou Yang case PIN_CONFIG_INPUT_SCHMITT_ENABLE: 360eceb3e61SBiao Huang mtk_pmx_gpio_set_direction(pctldev, NULL, pin, true); 36125d76b21SHongzhou Yang ret = mtk_pconf_set_ies_smt(pctl, pin, arg, param); 362a6df410dSHongzhou Yang break; 363a6df410dSHongzhou Yang case PIN_CONFIG_DRIVE_STRENGTH: 36425d76b21SHongzhou Yang ret = mtk_pconf_set_driving(pctl, pin, arg); 365a6df410dSHongzhou Yang break; 366a6df410dSHongzhou Yang default: 36725d76b21SHongzhou Yang ret = -EINVAL; 368a6df410dSHongzhou Yang } 369a6df410dSHongzhou Yang 37025d76b21SHongzhou Yang return ret; 371a6df410dSHongzhou Yang } 372a6df410dSHongzhou Yang 373a6df410dSHongzhou Yang static int mtk_pconf_group_get(struct pinctrl_dev *pctldev, 374a6df410dSHongzhou Yang unsigned group, 375a6df410dSHongzhou Yang unsigned long *config) 376a6df410dSHongzhou Yang { 377a6df410dSHongzhou Yang struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 378a6df410dSHongzhou Yang 379a6df410dSHongzhou Yang *config = pctl->groups[group].config; 380a6df410dSHongzhou Yang 381a6df410dSHongzhou Yang return 0; 382a6df410dSHongzhou Yang } 383a6df410dSHongzhou Yang 384a6df410dSHongzhou Yang static int mtk_pconf_group_set(struct pinctrl_dev *pctldev, unsigned group, 385a6df410dSHongzhou Yang unsigned long *configs, unsigned num_configs) 386a6df410dSHongzhou Yang { 387a6df410dSHongzhou Yang struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 388a6df410dSHongzhou Yang struct mtk_pinctrl_group *g = &pctl->groups[group]; 38925d76b21SHongzhou Yang int i, ret; 390a6df410dSHongzhou Yang 391a6df410dSHongzhou Yang for (i = 0; i < num_configs; i++) { 39225d76b21SHongzhou Yang ret = mtk_pconf_parse_conf(pctldev, g->pin, 393a6df410dSHongzhou Yang pinconf_to_config_param(configs[i]), 394a6df410dSHongzhou Yang pinconf_to_config_argument(configs[i])); 39525d76b21SHongzhou Yang if (ret < 0) 39625d76b21SHongzhou Yang return ret; 397a6df410dSHongzhou Yang 398a6df410dSHongzhou Yang g->config = configs[i]; 399a6df410dSHongzhou Yang } 400a6df410dSHongzhou Yang 401a6df410dSHongzhou Yang return 0; 402a6df410dSHongzhou Yang } 403a6df410dSHongzhou Yang 404a6df410dSHongzhou Yang static const struct pinconf_ops mtk_pconf_ops = { 405a6df410dSHongzhou Yang .pin_config_group_get = mtk_pconf_group_get, 406a6df410dSHongzhou Yang .pin_config_group_set = mtk_pconf_group_set, 407a6df410dSHongzhou Yang }; 408a6df410dSHongzhou Yang 409a6df410dSHongzhou Yang static struct mtk_pinctrl_group * 410a6df410dSHongzhou Yang mtk_pctrl_find_group_by_pin(struct mtk_pinctrl *pctl, u32 pin) 411a6df410dSHongzhou Yang { 412a6df410dSHongzhou Yang int i; 413a6df410dSHongzhou Yang 414a6df410dSHongzhou Yang for (i = 0; i < pctl->ngroups; i++) { 415a6df410dSHongzhou Yang struct mtk_pinctrl_group *grp = pctl->groups + i; 416a6df410dSHongzhou Yang 417a6df410dSHongzhou Yang if (grp->pin == pin) 418a6df410dSHongzhou Yang return grp; 419a6df410dSHongzhou Yang } 420a6df410dSHongzhou Yang 421a6df410dSHongzhou Yang return NULL; 422a6df410dSHongzhou Yang } 423a6df410dSHongzhou Yang 424a6df410dSHongzhou Yang static const struct mtk_desc_function *mtk_pctrl_find_function_by_pin( 425a6df410dSHongzhou Yang struct mtk_pinctrl *pctl, u32 pin_num, u32 fnum) 426a6df410dSHongzhou Yang { 427a6df410dSHongzhou Yang const struct mtk_desc_pin *pin = pctl->devdata->pins + pin_num; 428a6df410dSHongzhou Yang const struct mtk_desc_function *func = pin->functions; 429a6df410dSHongzhou Yang 430a6df410dSHongzhou Yang while (func && func->name) { 431a6df410dSHongzhou Yang if (func->muxval == fnum) 432a6df410dSHongzhou Yang return func; 433a6df410dSHongzhou Yang func++; 434a6df410dSHongzhou Yang } 435a6df410dSHongzhou Yang 436a6df410dSHongzhou Yang return NULL; 437a6df410dSHongzhou Yang } 438a6df410dSHongzhou Yang 439a6df410dSHongzhou Yang static bool mtk_pctrl_is_function_valid(struct mtk_pinctrl *pctl, 440a6df410dSHongzhou Yang u32 pin_num, u32 fnum) 441a6df410dSHongzhou Yang { 442a6df410dSHongzhou Yang int i; 443a6df410dSHongzhou Yang 444a6df410dSHongzhou Yang for (i = 0; i < pctl->devdata->npins; i++) { 445a6df410dSHongzhou Yang const struct mtk_desc_pin *pin = pctl->devdata->pins + i; 446a6df410dSHongzhou Yang 447a6df410dSHongzhou Yang if (pin->pin.number == pin_num) { 448a6df410dSHongzhou Yang const struct mtk_desc_function *func = 449a6df410dSHongzhou Yang pin->functions; 450a6df410dSHongzhou Yang 451a6df410dSHongzhou Yang while (func && func->name) { 452a6df410dSHongzhou Yang if (func->muxval == fnum) 453a6df410dSHongzhou Yang return true; 454a6df410dSHongzhou Yang func++; 455a6df410dSHongzhou Yang } 456a6df410dSHongzhou Yang 457a6df410dSHongzhou Yang break; 458a6df410dSHongzhou Yang } 459a6df410dSHongzhou Yang } 460a6df410dSHongzhou Yang 461a6df410dSHongzhou Yang return false; 462a6df410dSHongzhou Yang } 463a6df410dSHongzhou Yang 464a6df410dSHongzhou Yang static int mtk_pctrl_dt_node_to_map_func(struct mtk_pinctrl *pctl, 465a6df410dSHongzhou Yang u32 pin, u32 fnum, struct mtk_pinctrl_group *grp, 466a6df410dSHongzhou Yang struct pinctrl_map **map, unsigned *reserved_maps, 467a6df410dSHongzhou Yang unsigned *num_maps) 468a6df410dSHongzhou Yang { 469a6df410dSHongzhou Yang bool ret; 470a6df410dSHongzhou Yang 471a6df410dSHongzhou Yang if (*num_maps == *reserved_maps) 472a6df410dSHongzhou Yang return -ENOSPC; 473a6df410dSHongzhou Yang 474a6df410dSHongzhou Yang (*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP; 475a6df410dSHongzhou Yang (*map)[*num_maps].data.mux.group = grp->name; 476a6df410dSHongzhou Yang 477a6df410dSHongzhou Yang ret = mtk_pctrl_is_function_valid(pctl, pin, fnum); 478a6df410dSHongzhou Yang if (!ret) { 479a6df410dSHongzhou Yang dev_err(pctl->dev, "invalid function %d on pin %d .\n", 480a6df410dSHongzhou Yang fnum, pin); 481a6df410dSHongzhou Yang return -EINVAL; 482a6df410dSHongzhou Yang } 483a6df410dSHongzhou Yang 484a6df410dSHongzhou Yang (*map)[*num_maps].data.mux.function = mtk_gpio_functions[fnum]; 485a6df410dSHongzhou Yang (*num_maps)++; 486a6df410dSHongzhou Yang 487a6df410dSHongzhou Yang return 0; 488a6df410dSHongzhou Yang } 489a6df410dSHongzhou Yang 490a6df410dSHongzhou Yang static int mtk_pctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev, 491a6df410dSHongzhou Yang struct device_node *node, 492a6df410dSHongzhou Yang struct pinctrl_map **map, 493a6df410dSHongzhou Yang unsigned *reserved_maps, 494a6df410dSHongzhou Yang unsigned *num_maps) 495a6df410dSHongzhou Yang { 496a6df410dSHongzhou Yang struct property *pins; 497a6df410dSHongzhou Yang u32 pinfunc, pin, func; 498a6df410dSHongzhou Yang int num_pins, num_funcs, maps_per_pin; 499a6df410dSHongzhou Yang unsigned long *configs; 500a6df410dSHongzhou Yang unsigned int num_configs; 501b2f78906SGustavo A. R. Silva bool has_config = false; 502a6df410dSHongzhou Yang int i, err; 503a6df410dSHongzhou Yang unsigned reserve = 0; 504a6df410dSHongzhou Yang struct mtk_pinctrl_group *grp; 505a6df410dSHongzhou Yang struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 506a6df410dSHongzhou Yang 507a6df410dSHongzhou Yang pins = of_find_property(node, "pinmux", NULL); 508a6df410dSHongzhou Yang if (!pins) { 50994f4e54cSRob Herring dev_err(pctl->dev, "missing pins property in node %pOFn .\n", 51094f4e54cSRob Herring node); 511a6df410dSHongzhou Yang return -EINVAL; 512a6df410dSHongzhou Yang } 513a6df410dSHongzhou Yang 514c445cac3SHongzhou Yang err = pinconf_generic_parse_dt_config(node, pctldev, &configs, 515c445cac3SHongzhou Yang &num_configs); 516b04a23b0SHongzhou Yang if (err) 517b04a23b0SHongzhou Yang return err; 518b04a23b0SHongzhou Yang 519a6df410dSHongzhou Yang if (num_configs) 520b2f78906SGustavo A. R. Silva has_config = true; 521a6df410dSHongzhou Yang 522a6df410dSHongzhou Yang num_pins = pins->length / sizeof(u32); 523a6df410dSHongzhou Yang num_funcs = num_pins; 524a6df410dSHongzhou Yang maps_per_pin = 0; 525a6df410dSHongzhou Yang if (num_funcs) 526a6df410dSHongzhou Yang maps_per_pin++; 527a6df410dSHongzhou Yang if (has_config && num_pins >= 1) 528a6df410dSHongzhou Yang maps_per_pin++; 529a6df410dSHongzhou Yang 530b04a23b0SHongzhou Yang if (!num_pins || !maps_per_pin) { 531b04a23b0SHongzhou Yang err = -EINVAL; 532b04a23b0SHongzhou Yang goto exit; 533b04a23b0SHongzhou Yang } 534a6df410dSHongzhou Yang 535a6df410dSHongzhou Yang reserve = num_pins * maps_per_pin; 536a6df410dSHongzhou Yang 537a6df410dSHongzhou Yang err = pinctrl_utils_reserve_map(pctldev, map, 538a6df410dSHongzhou Yang reserved_maps, num_maps, reserve); 539a6df410dSHongzhou Yang if (err < 0) 540b04a23b0SHongzhou Yang goto exit; 541a6df410dSHongzhou Yang 542a6df410dSHongzhou Yang for (i = 0; i < num_pins; i++) { 543a6df410dSHongzhou Yang err = of_property_read_u32_index(node, "pinmux", 544a6df410dSHongzhou Yang i, &pinfunc); 545a6df410dSHongzhou Yang if (err) 546b04a23b0SHongzhou Yang goto exit; 547a6df410dSHongzhou Yang 548a6df410dSHongzhou Yang pin = MTK_GET_PIN_NO(pinfunc); 549a6df410dSHongzhou Yang func = MTK_GET_PIN_FUNC(pinfunc); 550a6df410dSHongzhou Yang 551a6df410dSHongzhou Yang if (pin >= pctl->devdata->npins || 552a6df410dSHongzhou Yang func >= ARRAY_SIZE(mtk_gpio_functions)) { 553a6df410dSHongzhou Yang dev_err(pctl->dev, "invalid pins value.\n"); 554a6df410dSHongzhou Yang err = -EINVAL; 555b04a23b0SHongzhou Yang goto exit; 556a6df410dSHongzhou Yang } 557a6df410dSHongzhou Yang 558a6df410dSHongzhou Yang grp = mtk_pctrl_find_group_by_pin(pctl, pin); 559a6df410dSHongzhou Yang if (!grp) { 560a6df410dSHongzhou Yang dev_err(pctl->dev, "unable to match pin %d to group\n", 561a6df410dSHongzhou Yang pin); 562b04a23b0SHongzhou Yang err = -EINVAL; 563b04a23b0SHongzhou Yang goto exit; 564a6df410dSHongzhou Yang } 565a6df410dSHongzhou Yang 566a6df410dSHongzhou Yang err = mtk_pctrl_dt_node_to_map_func(pctl, pin, func, grp, map, 567a6df410dSHongzhou Yang reserved_maps, num_maps); 568a6df410dSHongzhou Yang if (err < 0) 569b04a23b0SHongzhou Yang goto exit; 570a6df410dSHongzhou Yang 571a6df410dSHongzhou Yang if (has_config) { 572a6df410dSHongzhou Yang err = pinctrl_utils_add_map_configs(pctldev, map, 573a6df410dSHongzhou Yang reserved_maps, num_maps, grp->name, 574a6df410dSHongzhou Yang configs, num_configs, 575a6df410dSHongzhou Yang PIN_MAP_TYPE_CONFIGS_GROUP); 576a6df410dSHongzhou Yang if (err < 0) 577b04a23b0SHongzhou Yang goto exit; 578a6df410dSHongzhou Yang } 579a6df410dSHongzhou Yang } 580a6df410dSHongzhou Yang 581b04a23b0SHongzhou Yang err = 0; 582a6df410dSHongzhou Yang 583b04a23b0SHongzhou Yang exit: 584b04a23b0SHongzhou Yang kfree(configs); 585a6df410dSHongzhou Yang return err; 586a6df410dSHongzhou Yang } 587a6df410dSHongzhou Yang 588a6df410dSHongzhou Yang static int mtk_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev, 589a6df410dSHongzhou Yang struct device_node *np_config, 590a6df410dSHongzhou Yang struct pinctrl_map **map, unsigned *num_maps) 591a6df410dSHongzhou Yang { 592a6df410dSHongzhou Yang struct device_node *np; 593a6df410dSHongzhou Yang unsigned reserved_maps; 594a6df410dSHongzhou Yang int ret; 595a6df410dSHongzhou Yang 596a6df410dSHongzhou Yang *map = NULL; 597a6df410dSHongzhou Yang *num_maps = 0; 598a6df410dSHongzhou Yang reserved_maps = 0; 599a6df410dSHongzhou Yang 600a6df410dSHongzhou Yang for_each_child_of_node(np_config, np) { 601a6df410dSHongzhou Yang ret = mtk_pctrl_dt_subnode_to_map(pctldev, np, map, 602a6df410dSHongzhou Yang &reserved_maps, num_maps); 603a6df410dSHongzhou Yang if (ret < 0) { 604d32f7fd3SIrina Tirdea pinctrl_utils_free_map(pctldev, *map, *num_maps); 6054fc8a4b2SJulia Lawall of_node_put(np); 606a6df410dSHongzhou Yang return ret; 607a6df410dSHongzhou Yang } 608a6df410dSHongzhou Yang } 609a6df410dSHongzhou Yang 610a6df410dSHongzhou Yang return 0; 611a6df410dSHongzhou Yang } 612a6df410dSHongzhou Yang 613a6df410dSHongzhou Yang static int mtk_pctrl_get_groups_count(struct pinctrl_dev *pctldev) 614a6df410dSHongzhou Yang { 615a6df410dSHongzhou Yang struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 616a6df410dSHongzhou Yang 617a6df410dSHongzhou Yang return pctl->ngroups; 618a6df410dSHongzhou Yang } 619a6df410dSHongzhou Yang 620a6df410dSHongzhou Yang static const char *mtk_pctrl_get_group_name(struct pinctrl_dev *pctldev, 621a6df410dSHongzhou Yang unsigned group) 622a6df410dSHongzhou Yang { 623a6df410dSHongzhou Yang struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 624a6df410dSHongzhou Yang 625a6df410dSHongzhou Yang return pctl->groups[group].name; 626a6df410dSHongzhou Yang } 627a6df410dSHongzhou Yang 628a6df410dSHongzhou Yang static int mtk_pctrl_get_group_pins(struct pinctrl_dev *pctldev, 629a6df410dSHongzhou Yang unsigned group, 630a6df410dSHongzhou Yang const unsigned **pins, 631a6df410dSHongzhou Yang unsigned *num_pins) 632a6df410dSHongzhou Yang { 633a6df410dSHongzhou Yang struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 634a6df410dSHongzhou Yang 635a6df410dSHongzhou Yang *pins = (unsigned *)&pctl->groups[group].pin; 636a6df410dSHongzhou Yang *num_pins = 1; 637a6df410dSHongzhou Yang 638a6df410dSHongzhou Yang return 0; 639a6df410dSHongzhou Yang } 640a6df410dSHongzhou Yang 641a6df410dSHongzhou Yang static const struct pinctrl_ops mtk_pctrl_ops = { 642a6df410dSHongzhou Yang .dt_node_to_map = mtk_pctrl_dt_node_to_map, 643d32f7fd3SIrina Tirdea .dt_free_map = pinctrl_utils_free_map, 644a6df410dSHongzhou Yang .get_groups_count = mtk_pctrl_get_groups_count, 645a6df410dSHongzhou Yang .get_group_name = mtk_pctrl_get_group_name, 646a6df410dSHongzhou Yang .get_group_pins = mtk_pctrl_get_group_pins, 647a6df410dSHongzhou Yang }; 648a6df410dSHongzhou Yang 649a6df410dSHongzhou Yang static int mtk_pmx_get_funcs_cnt(struct pinctrl_dev *pctldev) 650a6df410dSHongzhou Yang { 651a6df410dSHongzhou Yang return ARRAY_SIZE(mtk_gpio_functions); 652a6df410dSHongzhou Yang } 653a6df410dSHongzhou Yang 654a6df410dSHongzhou Yang static const char *mtk_pmx_get_func_name(struct pinctrl_dev *pctldev, 655a6df410dSHongzhou Yang unsigned selector) 656a6df410dSHongzhou Yang { 657a6df410dSHongzhou Yang return mtk_gpio_functions[selector]; 658a6df410dSHongzhou Yang } 659a6df410dSHongzhou Yang 660a6df410dSHongzhou Yang static int mtk_pmx_get_func_groups(struct pinctrl_dev *pctldev, 661a6df410dSHongzhou Yang unsigned function, 662a6df410dSHongzhou Yang const char * const **groups, 663a6df410dSHongzhou Yang unsigned * const num_groups) 664a6df410dSHongzhou Yang { 665a6df410dSHongzhou Yang struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 666a6df410dSHongzhou Yang 667a6df410dSHongzhou Yang *groups = pctl->grp_names; 668a6df410dSHongzhou Yang *num_groups = pctl->ngroups; 669a6df410dSHongzhou Yang 670a6df410dSHongzhou Yang return 0; 671a6df410dSHongzhou Yang } 672a6df410dSHongzhou Yang 673a6df410dSHongzhou Yang static int mtk_pmx_set_mode(struct pinctrl_dev *pctldev, 674a6df410dSHongzhou Yang unsigned long pin, unsigned long mode) 675a6df410dSHongzhou Yang { 676a6df410dSHongzhou Yang unsigned int reg_addr; 677a6df410dSHongzhou Yang unsigned char bit; 678a6df410dSHongzhou Yang unsigned int val; 679a6df410dSHongzhou Yang unsigned int mask = (1L << GPIO_MODE_BITS) - 1; 680a6df410dSHongzhou Yang struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 681a6df410dSHongzhou Yang 682148b95eeSBiao Huang if (pctl->devdata->spec_pinmux_set) 683148b95eeSBiao Huang pctl->devdata->spec_pinmux_set(mtk_get_regmap(pctl, pin), 684148b95eeSBiao Huang pin, mode); 685148b95eeSBiao Huang 686a6df410dSHongzhou Yang reg_addr = ((pin / MAX_GPIO_MODE_PER_REG) << pctl->devdata->port_shf) 687a6df410dSHongzhou Yang + pctl->devdata->pinmux_offset; 688a6df410dSHongzhou Yang 689148b95eeSBiao Huang mode &= mask; 690a6df410dSHongzhou Yang bit = pin % MAX_GPIO_MODE_PER_REG; 691a6df410dSHongzhou Yang mask <<= (GPIO_MODE_BITS * bit); 692a6df410dSHongzhou Yang val = (mode << (GPIO_MODE_BITS * bit)); 693a6df410dSHongzhou Yang return regmap_update_bits(mtk_get_regmap(pctl, pin), 694a6df410dSHongzhou Yang reg_addr, mask, val); 695a6df410dSHongzhou Yang } 696a6df410dSHongzhou Yang 697d9819eb9SMaoguang Meng static const struct mtk_desc_pin * 698d9819eb9SMaoguang Meng mtk_find_pin_by_eint_num(struct mtk_pinctrl *pctl, unsigned int eint_num) 699d9819eb9SMaoguang Meng { 700d9819eb9SMaoguang Meng int i; 701d9819eb9SMaoguang Meng const struct mtk_desc_pin *pin; 702d9819eb9SMaoguang Meng 703d9819eb9SMaoguang Meng for (i = 0; i < pctl->devdata->npins; i++) { 704d9819eb9SMaoguang Meng pin = pctl->devdata->pins + i; 705d9819eb9SMaoguang Meng if (pin->eint.eintnum == eint_num) 706d9819eb9SMaoguang Meng return pin; 707d9819eb9SMaoguang Meng } 708d9819eb9SMaoguang Meng 709d9819eb9SMaoguang Meng return NULL; 710d9819eb9SMaoguang Meng } 711d9819eb9SMaoguang Meng 712a6df410dSHongzhou Yang static int mtk_pmx_set_mux(struct pinctrl_dev *pctldev, 713a6df410dSHongzhou Yang unsigned function, 714a6df410dSHongzhou Yang unsigned group) 715a6df410dSHongzhou Yang { 716a6df410dSHongzhou Yang bool ret; 717a6df410dSHongzhou Yang const struct mtk_desc_function *desc; 718a6df410dSHongzhou Yang struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 719a6df410dSHongzhou Yang struct mtk_pinctrl_group *g = pctl->groups + group; 720a6df410dSHongzhou Yang 721a6df410dSHongzhou Yang ret = mtk_pctrl_is_function_valid(pctl, g->pin, function); 722a6df410dSHongzhou Yang if (!ret) { 723c70336ccSColin Ian King dev_err(pctl->dev, "invalid function %d on group %d .\n", 724a6df410dSHongzhou Yang function, group); 725a6df410dSHongzhou Yang return -EINVAL; 726a6df410dSHongzhou Yang } 727a6df410dSHongzhou Yang 728a6df410dSHongzhou Yang desc = mtk_pctrl_find_function_by_pin(pctl, g->pin, function); 729a6df410dSHongzhou Yang if (!desc) 730a6df410dSHongzhou Yang return -EINVAL; 731a6df410dSHongzhou Yang mtk_pmx_set_mode(pctldev, g->pin, desc->muxval); 732a6df410dSHongzhou Yang return 0; 733a6df410dSHongzhou Yang } 734a6df410dSHongzhou Yang 73559ee9c96SBiao Huang static int mtk_pmx_find_gpio_mode(struct mtk_pinctrl *pctl, 73659ee9c96SBiao Huang unsigned offset) 73759ee9c96SBiao Huang { 73859ee9c96SBiao Huang const struct mtk_desc_pin *pin = pctl->devdata->pins + offset; 73959ee9c96SBiao Huang const struct mtk_desc_function *func = pin->functions; 74059ee9c96SBiao Huang 74159ee9c96SBiao Huang while (func && func->name) { 74259ee9c96SBiao Huang if (!strncmp(func->name, GPIO_MODE_PREFIX, 74359ee9c96SBiao Huang sizeof(GPIO_MODE_PREFIX)-1)) 74459ee9c96SBiao Huang return func->muxval; 74559ee9c96SBiao Huang func++; 74659ee9c96SBiao Huang } 74759ee9c96SBiao Huang return -EINVAL; 74859ee9c96SBiao Huang } 74959ee9c96SBiao Huang 75059ee9c96SBiao Huang static int mtk_pmx_gpio_request_enable(struct pinctrl_dev *pctldev, 75159ee9c96SBiao Huang struct pinctrl_gpio_range *range, 75259ee9c96SBiao Huang unsigned offset) 75359ee9c96SBiao Huang { 754740f5b08SAndrzej Hajda int muxval; 75559ee9c96SBiao Huang struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 75659ee9c96SBiao Huang 75759ee9c96SBiao Huang muxval = mtk_pmx_find_gpio_mode(pctl, offset); 75859ee9c96SBiao Huang 75959ee9c96SBiao Huang if (muxval < 0) { 76059ee9c96SBiao Huang dev_err(pctl->dev, "invalid gpio pin %d.\n", offset); 76159ee9c96SBiao Huang return -EINVAL; 76259ee9c96SBiao Huang } 76359ee9c96SBiao Huang 76459ee9c96SBiao Huang mtk_pmx_set_mode(pctldev, offset, muxval); 76531763d3bSBiao Huang mtk_pconf_set_ies_smt(pctl, offset, 1, PIN_CONFIG_INPUT_ENABLE); 76659ee9c96SBiao Huang 76759ee9c96SBiao Huang return 0; 76859ee9c96SBiao Huang } 76959ee9c96SBiao Huang 770a6df410dSHongzhou Yang static const struct pinmux_ops mtk_pmx_ops = { 771a6df410dSHongzhou Yang .get_functions_count = mtk_pmx_get_funcs_cnt, 772a6df410dSHongzhou Yang .get_function_name = mtk_pmx_get_func_name, 773a6df410dSHongzhou Yang .get_function_groups = mtk_pmx_get_func_groups, 774a6df410dSHongzhou Yang .set_mux = mtk_pmx_set_mux, 775a6df410dSHongzhou Yang .gpio_set_direction = mtk_pmx_gpio_set_direction, 77659ee9c96SBiao Huang .gpio_request_enable = mtk_pmx_gpio_request_enable, 777a6df410dSHongzhou Yang }; 778a6df410dSHongzhou Yang 779a6df410dSHongzhou Yang static int mtk_gpio_direction_input(struct gpio_chip *chip, 780a6df410dSHongzhou Yang unsigned offset) 781a6df410dSHongzhou Yang { 782a6df410dSHongzhou Yang return pinctrl_gpio_direction_input(chip->base + offset); 783a6df410dSHongzhou Yang } 784a6df410dSHongzhou Yang 785a6df410dSHongzhou Yang static int mtk_gpio_direction_output(struct gpio_chip *chip, 786a6df410dSHongzhou Yang unsigned offset, int value) 787a6df410dSHongzhou Yang { 788a6df410dSHongzhou Yang mtk_gpio_set(chip, offset, value); 789a6df410dSHongzhou Yang return pinctrl_gpio_direction_output(chip->base + offset); 790a6df410dSHongzhou Yang } 791a6df410dSHongzhou Yang 792a6df410dSHongzhou Yang static int mtk_gpio_get_direction(struct gpio_chip *chip, unsigned offset) 793a6df410dSHongzhou Yang { 794a6df410dSHongzhou Yang unsigned int reg_addr; 795a6df410dSHongzhou Yang unsigned int bit; 796a6df410dSHongzhou Yang unsigned int read_val = 0; 797a6df410dSHongzhou Yang 79811aa679aSLinus Walleij struct mtk_pinctrl *pctl = gpiochip_get_data(chip); 799a6df410dSHongzhou Yang 800a6df410dSHongzhou Yang reg_addr = mtk_get_port(pctl, offset) + pctl->devdata->dir_offset; 801a6df410dSHongzhou Yang bit = BIT(offset & 0xf); 802148b95eeSBiao Huang 803148b95eeSBiao Huang if (pctl->devdata->spec_dir_set) 804148b95eeSBiao Huang pctl->devdata->spec_dir_set(®_addr, offset); 805148b95eeSBiao Huang 806a6df410dSHongzhou Yang regmap_read(pctl->regmap1, reg_addr, &read_val); 807*3c827873SMatti Vaittinen if (read_val & bit) 808*3c827873SMatti Vaittinen return GPIO_LINE_DIRECTION_OUT; 809*3c827873SMatti Vaittinen 810*3c827873SMatti Vaittinen return GPIO_LINE_DIRECTION_IN; 811a6df410dSHongzhou Yang } 812a6df410dSHongzhou Yang 813a6df410dSHongzhou Yang static int mtk_gpio_get(struct gpio_chip *chip, unsigned offset) 814a6df410dSHongzhou Yang { 815a6df410dSHongzhou Yang unsigned int reg_addr; 816a6df410dSHongzhou Yang unsigned int bit; 817a6df410dSHongzhou Yang unsigned int read_val = 0; 81811aa679aSLinus Walleij struct mtk_pinctrl *pctl = gpiochip_get_data(chip); 819a6df410dSHongzhou Yang 820a6df410dSHongzhou Yang reg_addr = mtk_get_port(pctl, offset) + 821a6df410dSHongzhou Yang pctl->devdata->din_offset; 822a6df410dSHongzhou Yang 823a6df410dSHongzhou Yang bit = BIT(offset & 0xf); 824a6df410dSHongzhou Yang regmap_read(pctl->regmap1, reg_addr, &read_val); 825a6df410dSHongzhou Yang return !!(read_val & bit); 826a6df410dSHongzhou Yang } 827a6df410dSHongzhou Yang 828d9819eb9SMaoguang Meng static int mtk_gpio_to_irq(struct gpio_chip *chip, unsigned offset) 829d9819eb9SMaoguang Meng { 83011aa679aSLinus Walleij struct mtk_pinctrl *pctl = gpiochip_get_data(chip); 831e46df235SSean Wang const struct mtk_desc_pin *pin; 832e46df235SSean Wang unsigned long eint_n; 833d9819eb9SMaoguang Meng 834d9819eb9SMaoguang Meng pin = pctl->devdata->pins + offset; 835d9819eb9SMaoguang Meng if (pin->eint.eintnum == NO_EINT_SUPPORT) 836d9819eb9SMaoguang Meng return -EINVAL; 837d9819eb9SMaoguang Meng 838e46df235SSean Wang eint_n = pin->eint.eintnum; 839d9819eb9SMaoguang Meng 840e46df235SSean Wang return mtk_eint_find_irq(pctl->eint, eint_n); 841d9819eb9SMaoguang Meng } 842d9819eb9SMaoguang Meng 8432956b5d9SMika Westerberg static int mtk_gpio_set_config(struct gpio_chip *chip, unsigned offset, 8442956b5d9SMika Westerberg unsigned long config) 8452956b5d9SMika Westerberg { 846e46df235SSean Wang struct mtk_pinctrl *pctl = gpiochip_get_data(chip); 847e46df235SSean Wang const struct mtk_desc_pin *pin; 848e46df235SSean Wang unsigned long eint_n; 8492956b5d9SMika Westerberg u32 debounce; 8502956b5d9SMika Westerberg 8512956b5d9SMika Westerberg if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE) 8522956b5d9SMika Westerberg return -ENOTSUPP; 8532956b5d9SMika Westerberg 854e46df235SSean Wang pin = pctl->devdata->pins + offset; 855e46df235SSean Wang if (pin->eint.eintnum == NO_EINT_SUPPORT) 856e46df235SSean Wang return -EINVAL; 857e46df235SSean Wang 8582956b5d9SMika Westerberg debounce = pinconf_to_config_argument(config); 859e46df235SSean Wang eint_n = pin->eint.eintnum; 860e46df235SSean Wang 861e46df235SSean Wang return mtk_eint_set_debounce(pctl->eint, eint_n, debounce); 8622956b5d9SMika Westerberg } 8632956b5d9SMika Westerberg 86403e9888fSJulia Lawall static const struct gpio_chip mtk_gpio_chip = { 865a6df410dSHongzhou Yang .owner = THIS_MODULE, 86698c85d58SJonas Gorski .request = gpiochip_generic_request, 86798c85d58SJonas Gorski .free = gpiochip_generic_free, 868f97c2309SHongzhou Yang .get_direction = mtk_gpio_get_direction, 869a6df410dSHongzhou Yang .direction_input = mtk_gpio_direction_input, 870a6df410dSHongzhou Yang .direction_output = mtk_gpio_direction_output, 871a6df410dSHongzhou Yang .get = mtk_gpio_get, 872a6df410dSHongzhou Yang .set = mtk_gpio_set, 873d9819eb9SMaoguang Meng .to_irq = mtk_gpio_to_irq, 8742956b5d9SMika Westerberg .set_config = mtk_gpio_set_config, 875a6df410dSHongzhou Yang .of_gpio_n_cells = 2, 876a6df410dSHongzhou Yang }; 877a6df410dSHongzhou Yang 87858a5e1b6SMaoguang Meng static int mtk_eint_suspend(struct device *device) 87958a5e1b6SMaoguang Meng { 88058a5e1b6SMaoguang Meng struct mtk_pinctrl *pctl = dev_get_drvdata(device); 88158a5e1b6SMaoguang Meng 882e46df235SSean Wang return mtk_eint_do_suspend(pctl->eint); 88358a5e1b6SMaoguang Meng } 88458a5e1b6SMaoguang Meng 88558a5e1b6SMaoguang Meng static int mtk_eint_resume(struct device *device) 88658a5e1b6SMaoguang Meng { 88758a5e1b6SMaoguang Meng struct mtk_pinctrl *pctl = dev_get_drvdata(device); 88858a5e1b6SMaoguang Meng 889e46df235SSean Wang return mtk_eint_do_resume(pctl->eint); 89058a5e1b6SMaoguang Meng } 89158a5e1b6SMaoguang Meng 89258a5e1b6SMaoguang Meng const struct dev_pm_ops mtk_eint_pm_ops = { 893d2fcd62aShongkun.cao .suspend_noirq = mtk_eint_suspend, 894d2fcd62aShongkun.cao .resume_noirq = mtk_eint_resume, 89558a5e1b6SMaoguang Meng }; 89658a5e1b6SMaoguang Meng 897a6df410dSHongzhou Yang static int mtk_pctrl_build_state(struct platform_device *pdev) 898a6df410dSHongzhou Yang { 899a6df410dSHongzhou Yang struct mtk_pinctrl *pctl = platform_get_drvdata(pdev); 900a6df410dSHongzhou Yang int i; 901a6df410dSHongzhou Yang 902a6df410dSHongzhou Yang pctl->ngroups = pctl->devdata->npins; 903a6df410dSHongzhou Yang 904a6df410dSHongzhou Yang /* Allocate groups */ 9050206caa8SAxel Lin pctl->groups = devm_kcalloc(&pdev->dev, pctl->ngroups, 9060206caa8SAxel Lin sizeof(*pctl->groups), GFP_KERNEL); 907a6df410dSHongzhou Yang if (!pctl->groups) 908a6df410dSHongzhou Yang return -ENOMEM; 909a6df410dSHongzhou Yang 910a6df410dSHongzhou Yang /* We assume that one pin is one group, use pin name as group name. */ 9110206caa8SAxel Lin pctl->grp_names = devm_kcalloc(&pdev->dev, pctl->ngroups, 9120206caa8SAxel Lin sizeof(*pctl->grp_names), GFP_KERNEL); 913a6df410dSHongzhou Yang if (!pctl->grp_names) 914a6df410dSHongzhou Yang return -ENOMEM; 915a6df410dSHongzhou Yang 916a6df410dSHongzhou Yang for (i = 0; i < pctl->devdata->npins; i++) { 917a6df410dSHongzhou Yang const struct mtk_desc_pin *pin = pctl->devdata->pins + i; 918a6df410dSHongzhou Yang struct mtk_pinctrl_group *group = pctl->groups + i; 919a6df410dSHongzhou Yang 920a6df410dSHongzhou Yang group->name = pin->pin.name; 921a6df410dSHongzhou Yang group->pin = pin->pin.number; 922a6df410dSHongzhou Yang 923a6df410dSHongzhou Yang pctl->grp_names[i] = pin->pin.name; 924a6df410dSHongzhou Yang } 925a6df410dSHongzhou Yang 926a6df410dSHongzhou Yang return 0; 927a6df410dSHongzhou Yang } 928a6df410dSHongzhou Yang 929e46df235SSean Wang static int 930e46df235SSean Wang mtk_xt_get_gpio_n(void *data, unsigned long eint_n, unsigned int *gpio_n, 931e46df235SSean Wang struct gpio_chip **gpio_chip) 932e46df235SSean Wang { 933e46df235SSean Wang struct mtk_pinctrl *pctl = (struct mtk_pinctrl *)data; 934e46df235SSean Wang const struct mtk_desc_pin *pin; 935e46df235SSean Wang 936e46df235SSean Wang pin = mtk_find_pin_by_eint_num(pctl, eint_n); 937e46df235SSean Wang if (!pin) 938e46df235SSean Wang return -EINVAL; 939e46df235SSean Wang 940e46df235SSean Wang *gpio_chip = pctl->chip; 941e46df235SSean Wang *gpio_n = pin->pin.number; 942e46df235SSean Wang 943e46df235SSean Wang return 0; 944e46df235SSean Wang } 945e46df235SSean Wang 946e46df235SSean Wang static int mtk_xt_get_gpio_state(void *data, unsigned long eint_n) 947e46df235SSean Wang { 948e46df235SSean Wang struct mtk_pinctrl *pctl = (struct mtk_pinctrl *)data; 949e46df235SSean Wang const struct mtk_desc_pin *pin; 950e46df235SSean Wang 951e46df235SSean Wang pin = mtk_find_pin_by_eint_num(pctl, eint_n); 952e46df235SSean Wang if (!pin) 953e46df235SSean Wang return -EINVAL; 954e46df235SSean Wang 955e46df235SSean Wang return mtk_gpio_get(pctl->chip, pin->pin.number); 956e46df235SSean Wang } 957e46df235SSean Wang 958e46df235SSean Wang static int mtk_xt_set_gpio_as_eint(void *data, unsigned long eint_n) 959e46df235SSean Wang { 960e46df235SSean Wang struct mtk_pinctrl *pctl = (struct mtk_pinctrl *)data; 961e46df235SSean Wang const struct mtk_desc_pin *pin; 962e46df235SSean Wang 963e46df235SSean Wang pin = mtk_find_pin_by_eint_num(pctl, eint_n); 964e46df235SSean Wang if (!pin) 965e46df235SSean Wang return -EINVAL; 966e46df235SSean Wang 967e46df235SSean Wang /* set mux to INT mode */ 968e46df235SSean Wang mtk_pmx_set_mode(pctl->pctl_dev, pin->pin.number, pin->eint.eintmux); 969e46df235SSean Wang /* set gpio direction to input */ 970e46df235SSean Wang mtk_pmx_gpio_set_direction(pctl->pctl_dev, NULL, pin->pin.number, 971e46df235SSean Wang true); 972e46df235SSean Wang /* set input-enable */ 973e46df235SSean Wang mtk_pconf_set_ies_smt(pctl, pin->pin.number, 1, 974e46df235SSean Wang PIN_CONFIG_INPUT_ENABLE); 975e46df235SSean Wang 976e46df235SSean Wang return 0; 977e46df235SSean Wang } 978e46df235SSean Wang 979e46df235SSean Wang static const struct mtk_eint_xt mtk_eint_xt = { 980e46df235SSean Wang .get_gpio_n = mtk_xt_get_gpio_n, 981e46df235SSean Wang .get_gpio_state = mtk_xt_get_gpio_state, 982e46df235SSean Wang .set_gpio_as_eint = mtk_xt_set_gpio_as_eint, 983e46df235SSean Wang }; 984e46df235SSean Wang 985e46df235SSean Wang static int mtk_eint_init(struct mtk_pinctrl *pctl, struct platform_device *pdev) 986e46df235SSean Wang { 987e46df235SSean Wang struct device_node *np = pdev->dev.of_node; 988e46df235SSean Wang 989e46df235SSean Wang if (!of_property_read_bool(np, "interrupt-controller")) 990e46df235SSean Wang return -ENODEV; 991e46df235SSean Wang 992e46df235SSean Wang pctl->eint = devm_kzalloc(pctl->dev, sizeof(*pctl->eint), GFP_KERNEL); 993e46df235SSean Wang if (!pctl->eint) 994e46df235SSean Wang return -ENOMEM; 995e46df235SSean Wang 99665713177SYueHaibing pctl->eint->base = devm_platform_ioremap_resource(pdev, 0); 997e46df235SSean Wang if (IS_ERR(pctl->eint->base)) 998e46df235SSean Wang return PTR_ERR(pctl->eint->base); 999e46df235SSean Wang 1000e46df235SSean Wang pctl->eint->irq = irq_of_parse_and_map(np, 0); 1001e46df235SSean Wang if (!pctl->eint->irq) 1002e46df235SSean Wang return -EINVAL; 1003e46df235SSean Wang 1004e46df235SSean Wang pctl->eint->dev = &pdev->dev; 1005e6612a69SSean Wang /* 1006e6612a69SSean Wang * If pctl->eint->regs == NULL, it would fall back into using a generic 1007e6612a69SSean Wang * register map in mtk_eint_do_init calls. 1008e6612a69SSean Wang */ 1009e6612a69SSean Wang pctl->eint->regs = pctl->devdata->eint_regs; 1010e46df235SSean Wang pctl->eint->hw = &pctl->devdata->eint_hw; 1011e46df235SSean Wang pctl->eint->pctl = pctl; 1012e46df235SSean Wang pctl->eint->gpio_xlate = &mtk_eint_xt; 1013e46df235SSean Wang 1014e46df235SSean Wang return mtk_eint_do_init(pctl->eint); 1015e46df235SSean Wang } 1016e46df235SSean Wang 1017a6df410dSHongzhou Yang int mtk_pctrl_init(struct platform_device *pdev, 1018fc59e66cSHongzhou Yang const struct mtk_pinctrl_devdata *data, 1019fc59e66cSHongzhou Yang struct regmap *regmap) 1020a6df410dSHongzhou Yang { 1021a6df410dSHongzhou Yang struct pinctrl_pin_desc *pins; 1022a6df410dSHongzhou Yang struct mtk_pinctrl *pctl; 1023a6df410dSHongzhou Yang struct device_node *np = pdev->dev.of_node, *node; 1024a6df410dSHongzhou Yang struct property *prop; 1025e46df235SSean Wang int ret, i; 1026a6df410dSHongzhou Yang 1027a6df410dSHongzhou Yang pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL); 1028a6df410dSHongzhou Yang if (!pctl) 1029a6df410dSHongzhou Yang return -ENOMEM; 1030a6df410dSHongzhou Yang 1031a6df410dSHongzhou Yang platform_set_drvdata(pdev, pctl); 1032a6df410dSHongzhou Yang 1033a6df410dSHongzhou Yang prop = of_find_property(np, "pins-are-numbered", NULL); 1034a6df410dSHongzhou Yang if (!prop) { 1035c445cac3SHongzhou Yang dev_err(&pdev->dev, "only support pins-are-numbered format\n"); 1036a6df410dSHongzhou Yang return -EINVAL; 1037a6df410dSHongzhou Yang } 1038a6df410dSHongzhou Yang 1039a6df410dSHongzhou Yang node = of_parse_phandle(np, "mediatek,pctl-regmap", 0); 1040a6df410dSHongzhou Yang if (node) { 1041a6df410dSHongzhou Yang pctl->regmap1 = syscon_node_to_regmap(node); 1042a6df410dSHongzhou Yang if (IS_ERR(pctl->regmap1)) 1043a6df410dSHongzhou Yang return PTR_ERR(pctl->regmap1); 1044fc59e66cSHongzhou Yang } else if (regmap) { 1045fc59e66cSHongzhou Yang pctl->regmap1 = regmap; 1046fc59e66cSHongzhou Yang } else { 1047fc59e66cSHongzhou Yang dev_err(&pdev->dev, "Pinctrl node has not register regmap.\n"); 1048fc59e66cSHongzhou Yang return -EINVAL; 1049a6df410dSHongzhou Yang } 1050a6df410dSHongzhou Yang 1051a6df410dSHongzhou Yang /* Only 8135 has two base addr, other SoCs have only one. */ 1052a6df410dSHongzhou Yang node = of_parse_phandle(np, "mediatek,pctl-regmap", 1); 1053a6df410dSHongzhou Yang if (node) { 1054a6df410dSHongzhou Yang pctl->regmap2 = syscon_node_to_regmap(node); 1055a6df410dSHongzhou Yang if (IS_ERR(pctl->regmap2)) 1056a6df410dSHongzhou Yang return PTR_ERR(pctl->regmap2); 1057a6df410dSHongzhou Yang } 1058a6df410dSHongzhou Yang 1059a6df410dSHongzhou Yang pctl->devdata = data; 1060a6df410dSHongzhou Yang ret = mtk_pctrl_build_state(pdev); 1061a6df410dSHongzhou Yang if (ret) { 1062a6df410dSHongzhou Yang dev_err(&pdev->dev, "build state failed: %d\n", ret); 1063a6df410dSHongzhou Yang return -EINVAL; 1064a6df410dSHongzhou Yang } 1065a6df410dSHongzhou Yang 10660206caa8SAxel Lin pins = devm_kcalloc(&pdev->dev, pctl->devdata->npins, sizeof(*pins), 1067a6df410dSHongzhou Yang GFP_KERNEL); 1068a6df410dSHongzhou Yang if (!pins) 1069a6df410dSHongzhou Yang return -ENOMEM; 1070a6df410dSHongzhou Yang 1071a6df410dSHongzhou Yang for (i = 0; i < pctl->devdata->npins; i++) 1072a6df410dSHongzhou Yang pins[i] = pctl->devdata->pins[i].pin; 1073d48c2c02SHongzhou Yang 1074d48c2c02SHongzhou Yang pctl->pctl_desc.name = dev_name(&pdev->dev); 1075d48c2c02SHongzhou Yang pctl->pctl_desc.owner = THIS_MODULE; 1076d48c2c02SHongzhou Yang pctl->pctl_desc.pins = pins; 1077d48c2c02SHongzhou Yang pctl->pctl_desc.npins = pctl->devdata->npins; 1078d48c2c02SHongzhou Yang pctl->pctl_desc.confops = &mtk_pconf_ops; 1079d48c2c02SHongzhou Yang pctl->pctl_desc.pctlops = &mtk_pctrl_ops; 1080d48c2c02SHongzhou Yang pctl->pctl_desc.pmxops = &mtk_pmx_ops; 1081a6df410dSHongzhou Yang pctl->dev = &pdev->dev; 1082d48c2c02SHongzhou Yang 108303a3a558SLaxman Dewangan pctl->pctl_dev = devm_pinctrl_register(&pdev->dev, &pctl->pctl_desc, 108403a3a558SLaxman Dewangan pctl); 1085323de9efSMasahiro Yamada if (IS_ERR(pctl->pctl_dev)) { 1086a6df410dSHongzhou Yang dev_err(&pdev->dev, "couldn't register pinctrl driver\n"); 1087323de9efSMasahiro Yamada return PTR_ERR(pctl->pctl_dev); 1088a6df410dSHongzhou Yang } 1089a6df410dSHongzhou Yang 1090a6df410dSHongzhou Yang pctl->chip = devm_kzalloc(&pdev->dev, sizeof(*pctl->chip), GFP_KERNEL); 109103a3a558SLaxman Dewangan if (!pctl->chip) 109203a3a558SLaxman Dewangan return -ENOMEM; 1093a6df410dSHongzhou Yang 1094fc63d854SHongzhou Yang *pctl->chip = mtk_gpio_chip; 1095a6df410dSHongzhou Yang pctl->chip->ngpio = pctl->devdata->npins; 1096a6df410dSHongzhou Yang pctl->chip->label = dev_name(&pdev->dev); 109758383c78SLinus Walleij pctl->chip->parent = &pdev->dev; 1098fc59e66cSHongzhou Yang pctl->chip->base = -1; 1099a6df410dSHongzhou Yang 110011aa679aSLinus Walleij ret = gpiochip_add_data(pctl->chip, pctl); 110103a3a558SLaxman Dewangan if (ret) 110203a3a558SLaxman Dewangan return -EINVAL; 1103a6df410dSHongzhou Yang 1104a6df410dSHongzhou Yang /* Register the GPIO to pin mappings. */ 1105a6df410dSHongzhou Yang ret = gpiochip_add_pin_range(pctl->chip, dev_name(&pdev->dev), 1106a6df410dSHongzhou Yang 0, 0, pctl->devdata->npins); 1107a6df410dSHongzhou Yang if (ret) { 1108a6df410dSHongzhou Yang ret = -EINVAL; 1109a6df410dSHongzhou Yang goto chip_error; 1110a6df410dSHongzhou Yang } 1111a6df410dSHongzhou Yang 1112e46df235SSean Wang ret = mtk_eint_init(pctl, pdev); 1113e46df235SSean Wang if (ret) 1114d9819eb9SMaoguang Meng goto chip_error; 1115d9819eb9SMaoguang Meng 1116a6df410dSHongzhou Yang return 0; 1117a6df410dSHongzhou Yang 1118a6df410dSHongzhou Yang chip_error: 1119a6df410dSHongzhou Yang gpiochip_remove(pctl->chip); 1120a6df410dSHongzhou Yang return ret; 1121a6df410dSHongzhou Yang } 1122