18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * mt65xx pinctrl driver based on Allwinner A1X pinctrl driver.
48c2ecf20Sopenharmony_ci * Copyright (c) 2014 MediaTek Inc.
58c2ecf20Sopenharmony_ci * Author: Hongzhou.Yang <hongzhou.yang@mediatek.com>
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/io.h>
98c2ecf20Sopenharmony_ci#include <linux/gpio/driver.h>
108c2ecf20Sopenharmony_ci#include <linux/of.h>
118c2ecf20Sopenharmony_ci#include <linux/of_address.h>
128c2ecf20Sopenharmony_ci#include <linux/of_device.h>
138c2ecf20Sopenharmony_ci#include <linux/of_irq.h>
148c2ecf20Sopenharmony_ci#include <linux/pinctrl/consumer.h>
158c2ecf20Sopenharmony_ci#include <linux/pinctrl/machine.h>
168c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinconf.h>
178c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinconf-generic.h>
188c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinctrl.h>
198c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinmux.h>
208c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
218c2ecf20Sopenharmony_ci#include <linux/slab.h>
228c2ecf20Sopenharmony_ci#include <linux/bitops.h>
238c2ecf20Sopenharmony_ci#include <linux/regmap.h>
248c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h>
258c2ecf20Sopenharmony_ci#include <linux/delay.h>
268c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
278c2ecf20Sopenharmony_ci#include <linux/pm.h>
288c2ecf20Sopenharmony_ci#include <dt-bindings/pinctrl/mt65xx.h>
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#include "../core.h"
318c2ecf20Sopenharmony_ci#include "../pinconf.h"
328c2ecf20Sopenharmony_ci#include "../pinctrl-utils.h"
338c2ecf20Sopenharmony_ci#include "mtk-eint.h"
348c2ecf20Sopenharmony_ci#include "pinctrl-mtk-common.h"
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#define MAX_GPIO_MODE_PER_REG 5
378c2ecf20Sopenharmony_ci#define GPIO_MODE_BITS        3
388c2ecf20Sopenharmony_ci#define GPIO_MODE_PREFIX "GPIO"
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_cistatic const char * const mtk_gpio_functions[] = {
418c2ecf20Sopenharmony_ci	"func0", "func1", "func2", "func3",
428c2ecf20Sopenharmony_ci	"func4", "func5", "func6", "func7",
438c2ecf20Sopenharmony_ci	"func8", "func9", "func10", "func11",
448c2ecf20Sopenharmony_ci	"func12", "func13", "func14", "func15",
458c2ecf20Sopenharmony_ci};
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci/*
488c2ecf20Sopenharmony_ci * There are two base address for pull related configuration
498c2ecf20Sopenharmony_ci * in mt8135, and different GPIO pins use different base address.
508c2ecf20Sopenharmony_ci * When pin number greater than type1_start and less than type1_end,
518c2ecf20Sopenharmony_ci * should use the second base address.
528c2ecf20Sopenharmony_ci */
538c2ecf20Sopenharmony_cistatic struct regmap *mtk_get_regmap(struct mtk_pinctrl *pctl,
548c2ecf20Sopenharmony_ci		unsigned long pin)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	if (pin >= pctl->devdata->type1_start && pin < pctl->devdata->type1_end)
578c2ecf20Sopenharmony_ci		return pctl->regmap2;
588c2ecf20Sopenharmony_ci	return pctl->regmap1;
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistatic unsigned int mtk_get_port(struct mtk_pinctrl *pctl, unsigned long pin)
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci	/* Different SoC has different mask and port shift. */
648c2ecf20Sopenharmony_ci	return ((pin >> 4) & pctl->devdata->port_mask)
658c2ecf20Sopenharmony_ci			<< pctl->devdata->port_shf;
668c2ecf20Sopenharmony_ci}
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_cistatic int mtk_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
698c2ecf20Sopenharmony_ci			struct pinctrl_gpio_range *range, unsigned offset,
708c2ecf20Sopenharmony_ci			bool input)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	unsigned int reg_addr;
738c2ecf20Sopenharmony_ci	unsigned int bit;
748c2ecf20Sopenharmony_ci	struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	reg_addr = mtk_get_port(pctl, offset) + pctl->devdata->dir_offset;
778c2ecf20Sopenharmony_ci	bit = BIT(offset & 0xf);
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	if (pctl->devdata->spec_dir_set)
808c2ecf20Sopenharmony_ci		pctl->devdata->spec_dir_set(&reg_addr, offset);
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	if (input)
838c2ecf20Sopenharmony_ci		/* Different SoC has different alignment offset. */
848c2ecf20Sopenharmony_ci		reg_addr = CLR_ADDR(reg_addr, pctl);
858c2ecf20Sopenharmony_ci	else
868c2ecf20Sopenharmony_ci		reg_addr = SET_ADDR(reg_addr, pctl);
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	regmap_write(mtk_get_regmap(pctl, offset), reg_addr, bit);
898c2ecf20Sopenharmony_ci	return 0;
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistatic void mtk_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	unsigned int reg_addr;
958c2ecf20Sopenharmony_ci	unsigned int bit;
968c2ecf20Sopenharmony_ci	struct mtk_pinctrl *pctl = gpiochip_get_data(chip);
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	reg_addr = mtk_get_port(pctl, offset) + pctl->devdata->dout_offset;
998c2ecf20Sopenharmony_ci	bit = BIT(offset & 0xf);
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	if (value)
1028c2ecf20Sopenharmony_ci		reg_addr = SET_ADDR(reg_addr, pctl);
1038c2ecf20Sopenharmony_ci	else
1048c2ecf20Sopenharmony_ci		reg_addr = CLR_ADDR(reg_addr, pctl);
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	regmap_write(mtk_get_regmap(pctl, offset), reg_addr, bit);
1078c2ecf20Sopenharmony_ci}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_cistatic int mtk_pconf_set_ies_smt(struct mtk_pinctrl *pctl, unsigned pin,
1108c2ecf20Sopenharmony_ci		int value, enum pin_config_param arg)
1118c2ecf20Sopenharmony_ci{
1128c2ecf20Sopenharmony_ci	unsigned int reg_addr, offset;
1138c2ecf20Sopenharmony_ci	unsigned int bit;
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	/**
1168c2ecf20Sopenharmony_ci	 * Due to some soc are not support ies/smt config, add this special
1178c2ecf20Sopenharmony_ci	 * control to handle it.
1188c2ecf20Sopenharmony_ci	 */
1198c2ecf20Sopenharmony_ci	if (!pctl->devdata->spec_ies_smt_set &&
1208c2ecf20Sopenharmony_ci		pctl->devdata->ies_offset == MTK_PINCTRL_NOT_SUPPORT &&
1218c2ecf20Sopenharmony_ci			arg == PIN_CONFIG_INPUT_ENABLE)
1228c2ecf20Sopenharmony_ci		return -EINVAL;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	if (!pctl->devdata->spec_ies_smt_set &&
1258c2ecf20Sopenharmony_ci		pctl->devdata->smt_offset == MTK_PINCTRL_NOT_SUPPORT &&
1268c2ecf20Sopenharmony_ci			arg == PIN_CONFIG_INPUT_SCHMITT_ENABLE)
1278c2ecf20Sopenharmony_ci		return -EINVAL;
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	/*
1308c2ecf20Sopenharmony_ci	 * Due to some pins are irregular, their input enable and smt
1318c2ecf20Sopenharmony_ci	 * control register are discontinuous, so we need this special handle.
1328c2ecf20Sopenharmony_ci	 */
1338c2ecf20Sopenharmony_ci	if (pctl->devdata->spec_ies_smt_set) {
1348c2ecf20Sopenharmony_ci		return pctl->devdata->spec_ies_smt_set(mtk_get_regmap(pctl, pin),
1358c2ecf20Sopenharmony_ci			pin, pctl->devdata->port_align, value, arg);
1368c2ecf20Sopenharmony_ci	}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	bit = BIT(pin & 0xf);
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	if (arg == PIN_CONFIG_INPUT_ENABLE)
1418c2ecf20Sopenharmony_ci		offset = pctl->devdata->ies_offset;
1428c2ecf20Sopenharmony_ci	else
1438c2ecf20Sopenharmony_ci		offset = pctl->devdata->smt_offset;
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	if (value)
1468c2ecf20Sopenharmony_ci		reg_addr = SET_ADDR(mtk_get_port(pctl, pin) + offset, pctl);
1478c2ecf20Sopenharmony_ci	else
1488c2ecf20Sopenharmony_ci		reg_addr = CLR_ADDR(mtk_get_port(pctl, pin) + offset, pctl);
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	regmap_write(mtk_get_regmap(pctl, pin), reg_addr, bit);
1518c2ecf20Sopenharmony_ci	return 0;
1528c2ecf20Sopenharmony_ci}
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ciint mtk_pconf_spec_set_ies_smt_range(struct regmap *regmap,
1558c2ecf20Sopenharmony_ci		const struct mtk_pin_ies_smt_set *ies_smt_infos, unsigned int info_num,
1568c2ecf20Sopenharmony_ci		unsigned int pin, unsigned char align, int value)
1578c2ecf20Sopenharmony_ci{
1588c2ecf20Sopenharmony_ci	unsigned int i, reg_addr, bit;
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	for (i = 0; i < info_num; i++) {
1618c2ecf20Sopenharmony_ci		if (pin >= ies_smt_infos[i].start &&
1628c2ecf20Sopenharmony_ci				pin <= ies_smt_infos[i].end) {
1638c2ecf20Sopenharmony_ci			break;
1648c2ecf20Sopenharmony_ci		}
1658c2ecf20Sopenharmony_ci	}
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	if (i == info_num)
1688c2ecf20Sopenharmony_ci		return -EINVAL;
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	if (value)
1718c2ecf20Sopenharmony_ci		reg_addr = ies_smt_infos[i].offset + align;
1728c2ecf20Sopenharmony_ci	else
1738c2ecf20Sopenharmony_ci		reg_addr = ies_smt_infos[i].offset + (align << 1);
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	bit = BIT(ies_smt_infos[i].bit);
1768c2ecf20Sopenharmony_ci	regmap_write(regmap, reg_addr, bit);
1778c2ecf20Sopenharmony_ci	return 0;
1788c2ecf20Sopenharmony_ci}
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_cistatic const struct mtk_pin_drv_grp *mtk_find_pin_drv_grp_by_pin(
1818c2ecf20Sopenharmony_ci		struct mtk_pinctrl *pctl,  unsigned long pin) {
1828c2ecf20Sopenharmony_ci	int i;
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	for (i = 0; i < pctl->devdata->n_pin_drv_grps; i++) {
1858c2ecf20Sopenharmony_ci		const struct mtk_pin_drv_grp *pin_drv =
1868c2ecf20Sopenharmony_ci				pctl->devdata->pin_drv_grp + i;
1878c2ecf20Sopenharmony_ci		if (pin == pin_drv->pin)
1888c2ecf20Sopenharmony_ci			return pin_drv;
1898c2ecf20Sopenharmony_ci	}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	return NULL;
1928c2ecf20Sopenharmony_ci}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_cistatic int mtk_pconf_set_driving(struct mtk_pinctrl *pctl,
1958c2ecf20Sopenharmony_ci		unsigned int pin, unsigned char driving)
1968c2ecf20Sopenharmony_ci{
1978c2ecf20Sopenharmony_ci	const struct mtk_pin_drv_grp *pin_drv;
1988c2ecf20Sopenharmony_ci	unsigned int val;
1998c2ecf20Sopenharmony_ci	unsigned int bits, mask, shift;
2008c2ecf20Sopenharmony_ci	const struct mtk_drv_group_desc *drv_grp;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	if (pin >= pctl->devdata->npins)
2038c2ecf20Sopenharmony_ci		return -EINVAL;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	pin_drv = mtk_find_pin_drv_grp_by_pin(pctl, pin);
2068c2ecf20Sopenharmony_ci	if (!pin_drv || pin_drv->grp > pctl->devdata->n_grp_cls)
2078c2ecf20Sopenharmony_ci		return -EINVAL;
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	drv_grp = pctl->devdata->grp_desc + pin_drv->grp;
2108c2ecf20Sopenharmony_ci	if (driving >= drv_grp->min_drv && driving <= drv_grp->max_drv
2118c2ecf20Sopenharmony_ci		&& !(driving % drv_grp->step)) {
2128c2ecf20Sopenharmony_ci		val = driving / drv_grp->step - 1;
2138c2ecf20Sopenharmony_ci		bits = drv_grp->high_bit - drv_grp->low_bit + 1;
2148c2ecf20Sopenharmony_ci		mask = BIT(bits) - 1;
2158c2ecf20Sopenharmony_ci		shift = pin_drv->bit + drv_grp->low_bit;
2168c2ecf20Sopenharmony_ci		mask <<= shift;
2178c2ecf20Sopenharmony_ci		val <<= shift;
2188c2ecf20Sopenharmony_ci		return regmap_update_bits(mtk_get_regmap(pctl, pin),
2198c2ecf20Sopenharmony_ci				pin_drv->offset, mask, val);
2208c2ecf20Sopenharmony_ci	}
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	return -EINVAL;
2238c2ecf20Sopenharmony_ci}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ciint mtk_pctrl_spec_pull_set_samereg(struct regmap *regmap,
2268c2ecf20Sopenharmony_ci		const struct mtk_pin_spec_pupd_set_samereg *pupd_infos,
2278c2ecf20Sopenharmony_ci		unsigned int info_num, unsigned int pin,
2288c2ecf20Sopenharmony_ci		unsigned char align, bool isup, unsigned int r1r0)
2298c2ecf20Sopenharmony_ci{
2308c2ecf20Sopenharmony_ci	unsigned int i;
2318c2ecf20Sopenharmony_ci	unsigned int reg_pupd, reg_set, reg_rst;
2328c2ecf20Sopenharmony_ci	unsigned int bit_pupd, bit_r0, bit_r1;
2338c2ecf20Sopenharmony_ci	const struct mtk_pin_spec_pupd_set_samereg *spec_pupd_pin;
2348c2ecf20Sopenharmony_ci	bool find = false;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	for (i = 0; i < info_num; i++) {
2378c2ecf20Sopenharmony_ci		if (pin == pupd_infos[i].pin) {
2388c2ecf20Sopenharmony_ci			find = true;
2398c2ecf20Sopenharmony_ci			break;
2408c2ecf20Sopenharmony_ci		}
2418c2ecf20Sopenharmony_ci	}
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	if (!find)
2448c2ecf20Sopenharmony_ci		return -EINVAL;
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	spec_pupd_pin = pupd_infos + i;
2478c2ecf20Sopenharmony_ci	reg_set = spec_pupd_pin->offset + align;
2488c2ecf20Sopenharmony_ci	reg_rst = spec_pupd_pin->offset + (align << 1);
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	if (isup)
2518c2ecf20Sopenharmony_ci		reg_pupd = reg_rst;
2528c2ecf20Sopenharmony_ci	else
2538c2ecf20Sopenharmony_ci		reg_pupd = reg_set;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	bit_pupd = BIT(spec_pupd_pin->pupd_bit);
2568c2ecf20Sopenharmony_ci	regmap_write(regmap, reg_pupd, bit_pupd);
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	bit_r0 = BIT(spec_pupd_pin->r0_bit);
2598c2ecf20Sopenharmony_ci	bit_r1 = BIT(spec_pupd_pin->r1_bit);
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	switch (r1r0) {
2628c2ecf20Sopenharmony_ci	case MTK_PUPD_SET_R1R0_00:
2638c2ecf20Sopenharmony_ci		regmap_write(regmap, reg_rst, bit_r0);
2648c2ecf20Sopenharmony_ci		regmap_write(regmap, reg_rst, bit_r1);
2658c2ecf20Sopenharmony_ci		break;
2668c2ecf20Sopenharmony_ci	case MTK_PUPD_SET_R1R0_01:
2678c2ecf20Sopenharmony_ci		regmap_write(regmap, reg_set, bit_r0);
2688c2ecf20Sopenharmony_ci		regmap_write(regmap, reg_rst, bit_r1);
2698c2ecf20Sopenharmony_ci		break;
2708c2ecf20Sopenharmony_ci	case MTK_PUPD_SET_R1R0_10:
2718c2ecf20Sopenharmony_ci		regmap_write(regmap, reg_rst, bit_r0);
2728c2ecf20Sopenharmony_ci		regmap_write(regmap, reg_set, bit_r1);
2738c2ecf20Sopenharmony_ci		break;
2748c2ecf20Sopenharmony_ci	case MTK_PUPD_SET_R1R0_11:
2758c2ecf20Sopenharmony_ci		regmap_write(regmap, reg_set, bit_r0);
2768c2ecf20Sopenharmony_ci		regmap_write(regmap, reg_set, bit_r1);
2778c2ecf20Sopenharmony_ci		break;
2788c2ecf20Sopenharmony_ci	default:
2798c2ecf20Sopenharmony_ci		return -EINVAL;
2808c2ecf20Sopenharmony_ci	}
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	return 0;
2838c2ecf20Sopenharmony_ci}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_cistatic int mtk_pconf_set_pull_select(struct mtk_pinctrl *pctl,
2868c2ecf20Sopenharmony_ci		unsigned int pin, bool enable, bool isup, unsigned int arg)
2878c2ecf20Sopenharmony_ci{
2888c2ecf20Sopenharmony_ci	unsigned int bit;
2898c2ecf20Sopenharmony_ci	unsigned int reg_pullen, reg_pullsel, r1r0;
2908c2ecf20Sopenharmony_ci	int ret;
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	/* Some pins' pull setting are very different,
2938c2ecf20Sopenharmony_ci	 * they have separate pull up/down bit, R0 and R1
2948c2ecf20Sopenharmony_ci	 * resistor bit, so we need this special handle.
2958c2ecf20Sopenharmony_ci	 */
2968c2ecf20Sopenharmony_ci	if (pctl->devdata->spec_pull_set) {
2978c2ecf20Sopenharmony_ci		/* For special pins, bias-disable is set by R1R0,
2988c2ecf20Sopenharmony_ci		 * the parameter should be "MTK_PUPD_SET_R1R0_00".
2998c2ecf20Sopenharmony_ci		 */
3008c2ecf20Sopenharmony_ci		r1r0 = enable ? arg : MTK_PUPD_SET_R1R0_00;
3018c2ecf20Sopenharmony_ci		ret = pctl->devdata->spec_pull_set(mtk_get_regmap(pctl, pin),
3028c2ecf20Sopenharmony_ci			pin, pctl->devdata->port_align, isup, r1r0);
3038c2ecf20Sopenharmony_ci		if (!ret)
3048c2ecf20Sopenharmony_ci			return 0;
3058c2ecf20Sopenharmony_ci	}
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	/* For generic pull config, default arg value should be 0 or 1. */
3088c2ecf20Sopenharmony_ci	if (arg != 0 && arg != 1) {
3098c2ecf20Sopenharmony_ci		dev_err(pctl->dev, "invalid pull-up argument %d on pin %d .\n",
3108c2ecf20Sopenharmony_ci			arg, pin);
3118c2ecf20Sopenharmony_ci		return -EINVAL;
3128c2ecf20Sopenharmony_ci	}
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	bit = BIT(pin & 0xf);
3158c2ecf20Sopenharmony_ci	if (enable)
3168c2ecf20Sopenharmony_ci		reg_pullen = SET_ADDR(mtk_get_port(pctl, pin) +
3178c2ecf20Sopenharmony_ci			pctl->devdata->pullen_offset, pctl);
3188c2ecf20Sopenharmony_ci	else
3198c2ecf20Sopenharmony_ci		reg_pullen = CLR_ADDR(mtk_get_port(pctl, pin) +
3208c2ecf20Sopenharmony_ci			pctl->devdata->pullen_offset, pctl);
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	if (isup)
3238c2ecf20Sopenharmony_ci		reg_pullsel = SET_ADDR(mtk_get_port(pctl, pin) +
3248c2ecf20Sopenharmony_ci			pctl->devdata->pullsel_offset, pctl);
3258c2ecf20Sopenharmony_ci	else
3268c2ecf20Sopenharmony_ci		reg_pullsel = CLR_ADDR(mtk_get_port(pctl, pin) +
3278c2ecf20Sopenharmony_ci			pctl->devdata->pullsel_offset, pctl);
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	regmap_write(mtk_get_regmap(pctl, pin), reg_pullen, bit);
3308c2ecf20Sopenharmony_ci	regmap_write(mtk_get_regmap(pctl, pin), reg_pullsel, bit);
3318c2ecf20Sopenharmony_ci	return 0;
3328c2ecf20Sopenharmony_ci}
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_cistatic int mtk_pconf_parse_conf(struct pinctrl_dev *pctldev,
3358c2ecf20Sopenharmony_ci		unsigned int pin, enum pin_config_param param,
3368c2ecf20Sopenharmony_ci		enum pin_config_param arg)
3378c2ecf20Sopenharmony_ci{
3388c2ecf20Sopenharmony_ci	int ret = 0;
3398c2ecf20Sopenharmony_ci	struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	switch (param) {
3428c2ecf20Sopenharmony_ci	case PIN_CONFIG_BIAS_DISABLE:
3438c2ecf20Sopenharmony_ci		ret = mtk_pconf_set_pull_select(pctl, pin, false, false, arg);
3448c2ecf20Sopenharmony_ci		break;
3458c2ecf20Sopenharmony_ci	case PIN_CONFIG_BIAS_PULL_UP:
3468c2ecf20Sopenharmony_ci		ret = mtk_pconf_set_pull_select(pctl, pin, true, true, arg);
3478c2ecf20Sopenharmony_ci		break;
3488c2ecf20Sopenharmony_ci	case PIN_CONFIG_BIAS_PULL_DOWN:
3498c2ecf20Sopenharmony_ci		ret = mtk_pconf_set_pull_select(pctl, pin, true, false, arg);
3508c2ecf20Sopenharmony_ci		break;
3518c2ecf20Sopenharmony_ci	case PIN_CONFIG_INPUT_ENABLE:
3528c2ecf20Sopenharmony_ci		mtk_pmx_gpio_set_direction(pctldev, NULL, pin, true);
3538c2ecf20Sopenharmony_ci		ret = mtk_pconf_set_ies_smt(pctl, pin, arg, param);
3548c2ecf20Sopenharmony_ci		break;
3558c2ecf20Sopenharmony_ci	case PIN_CONFIG_OUTPUT:
3568c2ecf20Sopenharmony_ci		mtk_gpio_set(pctl->chip, pin, arg);
3578c2ecf20Sopenharmony_ci		ret = mtk_pmx_gpio_set_direction(pctldev, NULL, pin, false);
3588c2ecf20Sopenharmony_ci		break;
3598c2ecf20Sopenharmony_ci	case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
3608c2ecf20Sopenharmony_ci		mtk_pmx_gpio_set_direction(pctldev, NULL, pin, true);
3618c2ecf20Sopenharmony_ci		ret = mtk_pconf_set_ies_smt(pctl, pin, arg, param);
3628c2ecf20Sopenharmony_ci		break;
3638c2ecf20Sopenharmony_ci	case PIN_CONFIG_DRIVE_STRENGTH:
3648c2ecf20Sopenharmony_ci		ret = mtk_pconf_set_driving(pctl, pin, arg);
3658c2ecf20Sopenharmony_ci		break;
3668c2ecf20Sopenharmony_ci	default:
3678c2ecf20Sopenharmony_ci		ret = -EINVAL;
3688c2ecf20Sopenharmony_ci	}
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	return ret;
3718c2ecf20Sopenharmony_ci}
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_cistatic int mtk_pconf_group_get(struct pinctrl_dev *pctldev,
3748c2ecf20Sopenharmony_ci				 unsigned group,
3758c2ecf20Sopenharmony_ci				 unsigned long *config)
3768c2ecf20Sopenharmony_ci{
3778c2ecf20Sopenharmony_ci	struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	*config = pctl->groups[group].config;
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	return 0;
3828c2ecf20Sopenharmony_ci}
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_cistatic int mtk_pconf_group_set(struct pinctrl_dev *pctldev, unsigned group,
3858c2ecf20Sopenharmony_ci				 unsigned long *configs, unsigned num_configs)
3868c2ecf20Sopenharmony_ci{
3878c2ecf20Sopenharmony_ci	struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
3888c2ecf20Sopenharmony_ci	struct mtk_pinctrl_group *g = &pctl->groups[group];
3898c2ecf20Sopenharmony_ci	int i, ret;
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	for (i = 0; i < num_configs; i++) {
3928c2ecf20Sopenharmony_ci		ret = mtk_pconf_parse_conf(pctldev, g->pin,
3938c2ecf20Sopenharmony_ci			pinconf_to_config_param(configs[i]),
3948c2ecf20Sopenharmony_ci			pinconf_to_config_argument(configs[i]));
3958c2ecf20Sopenharmony_ci		if (ret < 0)
3968c2ecf20Sopenharmony_ci			return ret;
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci		g->config = configs[i];
3998c2ecf20Sopenharmony_ci	}
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	return 0;
4028c2ecf20Sopenharmony_ci}
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_cistatic const struct pinconf_ops mtk_pconf_ops = {
4058c2ecf20Sopenharmony_ci	.pin_config_group_get	= mtk_pconf_group_get,
4068c2ecf20Sopenharmony_ci	.pin_config_group_set	= mtk_pconf_group_set,
4078c2ecf20Sopenharmony_ci};
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_cistatic struct mtk_pinctrl_group *
4108c2ecf20Sopenharmony_cimtk_pctrl_find_group_by_pin(struct mtk_pinctrl *pctl, u32 pin)
4118c2ecf20Sopenharmony_ci{
4128c2ecf20Sopenharmony_ci	int i;
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	for (i = 0; i < pctl->ngroups; i++) {
4158c2ecf20Sopenharmony_ci		struct mtk_pinctrl_group *grp = pctl->groups + i;
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci		if (grp->pin == pin)
4188c2ecf20Sopenharmony_ci			return grp;
4198c2ecf20Sopenharmony_ci	}
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	return NULL;
4228c2ecf20Sopenharmony_ci}
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_cistatic const struct mtk_desc_function *mtk_pctrl_find_function_by_pin(
4258c2ecf20Sopenharmony_ci		struct mtk_pinctrl *pctl, u32 pin_num, u32 fnum)
4268c2ecf20Sopenharmony_ci{
4278c2ecf20Sopenharmony_ci	const struct mtk_desc_pin *pin = pctl->devdata->pins + pin_num;
4288c2ecf20Sopenharmony_ci	const struct mtk_desc_function *func = pin->functions;
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	while (func && func->name) {
4318c2ecf20Sopenharmony_ci		if (func->muxval == fnum)
4328c2ecf20Sopenharmony_ci			return func;
4338c2ecf20Sopenharmony_ci		func++;
4348c2ecf20Sopenharmony_ci	}
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	return NULL;
4378c2ecf20Sopenharmony_ci}
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_cistatic bool mtk_pctrl_is_function_valid(struct mtk_pinctrl *pctl,
4408c2ecf20Sopenharmony_ci		u32 pin_num, u32 fnum)
4418c2ecf20Sopenharmony_ci{
4428c2ecf20Sopenharmony_ci	int i;
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	for (i = 0; i < pctl->devdata->npins; i++) {
4458c2ecf20Sopenharmony_ci		const struct mtk_desc_pin *pin = pctl->devdata->pins + i;
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci		if (pin->pin.number == pin_num) {
4488c2ecf20Sopenharmony_ci			const struct mtk_desc_function *func =
4498c2ecf20Sopenharmony_ci					pin->functions;
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci			while (func && func->name) {
4528c2ecf20Sopenharmony_ci				if (func->muxval == fnum)
4538c2ecf20Sopenharmony_ci					return true;
4548c2ecf20Sopenharmony_ci				func++;
4558c2ecf20Sopenharmony_ci			}
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci			break;
4588c2ecf20Sopenharmony_ci		}
4598c2ecf20Sopenharmony_ci	}
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	return false;
4628c2ecf20Sopenharmony_ci}
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_cistatic int mtk_pctrl_dt_node_to_map_func(struct mtk_pinctrl *pctl,
4658c2ecf20Sopenharmony_ci		u32 pin, u32 fnum, struct mtk_pinctrl_group *grp,
4668c2ecf20Sopenharmony_ci		struct pinctrl_map **map, unsigned *reserved_maps,
4678c2ecf20Sopenharmony_ci		unsigned *num_maps)
4688c2ecf20Sopenharmony_ci{
4698c2ecf20Sopenharmony_ci	bool ret;
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	if (*num_maps == *reserved_maps)
4728c2ecf20Sopenharmony_ci		return -ENOSPC;
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	(*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP;
4758c2ecf20Sopenharmony_ci	(*map)[*num_maps].data.mux.group = grp->name;
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	ret = mtk_pctrl_is_function_valid(pctl, pin, fnum);
4788c2ecf20Sopenharmony_ci	if (!ret) {
4798c2ecf20Sopenharmony_ci		dev_err(pctl->dev, "invalid function %d on pin %d .\n",
4808c2ecf20Sopenharmony_ci				fnum, pin);
4818c2ecf20Sopenharmony_ci		return -EINVAL;
4828c2ecf20Sopenharmony_ci	}
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	(*map)[*num_maps].data.mux.function = mtk_gpio_functions[fnum];
4858c2ecf20Sopenharmony_ci	(*num_maps)++;
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	return 0;
4888c2ecf20Sopenharmony_ci}
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_cistatic int mtk_pctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
4918c2ecf20Sopenharmony_ci				      struct device_node *node,
4928c2ecf20Sopenharmony_ci				      struct pinctrl_map **map,
4938c2ecf20Sopenharmony_ci				      unsigned *reserved_maps,
4948c2ecf20Sopenharmony_ci				      unsigned *num_maps)
4958c2ecf20Sopenharmony_ci{
4968c2ecf20Sopenharmony_ci	struct property *pins;
4978c2ecf20Sopenharmony_ci	u32 pinfunc, pin, func;
4988c2ecf20Sopenharmony_ci	int num_pins, num_funcs, maps_per_pin;
4998c2ecf20Sopenharmony_ci	unsigned long *configs;
5008c2ecf20Sopenharmony_ci	unsigned int num_configs;
5018c2ecf20Sopenharmony_ci	bool has_config = false;
5028c2ecf20Sopenharmony_ci	int i, err;
5038c2ecf20Sopenharmony_ci	unsigned reserve = 0;
5048c2ecf20Sopenharmony_ci	struct mtk_pinctrl_group *grp;
5058c2ecf20Sopenharmony_ci	struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	pins = of_find_property(node, "pinmux", NULL);
5088c2ecf20Sopenharmony_ci	if (!pins) {
5098c2ecf20Sopenharmony_ci		dev_err(pctl->dev, "missing pins property in node %pOFn .\n",
5108c2ecf20Sopenharmony_ci				node);
5118c2ecf20Sopenharmony_ci		return -EINVAL;
5128c2ecf20Sopenharmony_ci	}
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	err = pinconf_generic_parse_dt_config(node, pctldev, &configs,
5158c2ecf20Sopenharmony_ci		&num_configs);
5168c2ecf20Sopenharmony_ci	if (err)
5178c2ecf20Sopenharmony_ci		return err;
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	if (num_configs)
5208c2ecf20Sopenharmony_ci		has_config = true;
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	num_pins = pins->length / sizeof(u32);
5238c2ecf20Sopenharmony_ci	num_funcs = num_pins;
5248c2ecf20Sopenharmony_ci	maps_per_pin = 0;
5258c2ecf20Sopenharmony_ci	if (num_funcs)
5268c2ecf20Sopenharmony_ci		maps_per_pin++;
5278c2ecf20Sopenharmony_ci	if (has_config && num_pins >= 1)
5288c2ecf20Sopenharmony_ci		maps_per_pin++;
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci	if (!num_pins || !maps_per_pin) {
5318c2ecf20Sopenharmony_ci		err = -EINVAL;
5328c2ecf20Sopenharmony_ci		goto exit;
5338c2ecf20Sopenharmony_ci	}
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	reserve = num_pins * maps_per_pin;
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	err = pinctrl_utils_reserve_map(pctldev, map,
5388c2ecf20Sopenharmony_ci			reserved_maps, num_maps, reserve);
5398c2ecf20Sopenharmony_ci	if (err < 0)
5408c2ecf20Sopenharmony_ci		goto exit;
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci	for (i = 0; i < num_pins; i++) {
5438c2ecf20Sopenharmony_ci		err = of_property_read_u32_index(node, "pinmux",
5448c2ecf20Sopenharmony_ci				i, &pinfunc);
5458c2ecf20Sopenharmony_ci		if (err)
5468c2ecf20Sopenharmony_ci			goto exit;
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci		pin = MTK_GET_PIN_NO(pinfunc);
5498c2ecf20Sopenharmony_ci		func = MTK_GET_PIN_FUNC(pinfunc);
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci		if (pin >= pctl->devdata->npins ||
5528c2ecf20Sopenharmony_ci				func >= ARRAY_SIZE(mtk_gpio_functions)) {
5538c2ecf20Sopenharmony_ci			dev_err(pctl->dev, "invalid pins value.\n");
5548c2ecf20Sopenharmony_ci			err = -EINVAL;
5558c2ecf20Sopenharmony_ci			goto exit;
5568c2ecf20Sopenharmony_ci		}
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci		grp = mtk_pctrl_find_group_by_pin(pctl, pin);
5598c2ecf20Sopenharmony_ci		if (!grp) {
5608c2ecf20Sopenharmony_ci			dev_err(pctl->dev, "unable to match pin %d to group\n",
5618c2ecf20Sopenharmony_ci					pin);
5628c2ecf20Sopenharmony_ci			err = -EINVAL;
5638c2ecf20Sopenharmony_ci			goto exit;
5648c2ecf20Sopenharmony_ci		}
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci		err = mtk_pctrl_dt_node_to_map_func(pctl, pin, func, grp, map,
5678c2ecf20Sopenharmony_ci				reserved_maps, num_maps);
5688c2ecf20Sopenharmony_ci		if (err < 0)
5698c2ecf20Sopenharmony_ci			goto exit;
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci		if (has_config) {
5728c2ecf20Sopenharmony_ci			err = pinctrl_utils_add_map_configs(pctldev, map,
5738c2ecf20Sopenharmony_ci					reserved_maps, num_maps, grp->name,
5748c2ecf20Sopenharmony_ci					configs, num_configs,
5758c2ecf20Sopenharmony_ci					PIN_MAP_TYPE_CONFIGS_GROUP);
5768c2ecf20Sopenharmony_ci			if (err < 0)
5778c2ecf20Sopenharmony_ci				goto exit;
5788c2ecf20Sopenharmony_ci		}
5798c2ecf20Sopenharmony_ci	}
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	err = 0;
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ciexit:
5848c2ecf20Sopenharmony_ci	kfree(configs);
5858c2ecf20Sopenharmony_ci	return err;
5868c2ecf20Sopenharmony_ci}
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_cistatic int mtk_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
5898c2ecf20Sopenharmony_ci				 struct device_node *np_config,
5908c2ecf20Sopenharmony_ci				 struct pinctrl_map **map, unsigned *num_maps)
5918c2ecf20Sopenharmony_ci{
5928c2ecf20Sopenharmony_ci	struct device_node *np;
5938c2ecf20Sopenharmony_ci	unsigned reserved_maps;
5948c2ecf20Sopenharmony_ci	int ret;
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci	*map = NULL;
5978c2ecf20Sopenharmony_ci	*num_maps = 0;
5988c2ecf20Sopenharmony_ci	reserved_maps = 0;
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	for_each_child_of_node(np_config, np) {
6018c2ecf20Sopenharmony_ci		ret = mtk_pctrl_dt_subnode_to_map(pctldev, np, map,
6028c2ecf20Sopenharmony_ci				&reserved_maps, num_maps);
6038c2ecf20Sopenharmony_ci		if (ret < 0) {
6048c2ecf20Sopenharmony_ci			pinctrl_utils_free_map(pctldev, *map, *num_maps);
6058c2ecf20Sopenharmony_ci			of_node_put(np);
6068c2ecf20Sopenharmony_ci			return ret;
6078c2ecf20Sopenharmony_ci		}
6088c2ecf20Sopenharmony_ci	}
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	return 0;
6118c2ecf20Sopenharmony_ci}
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_cistatic int mtk_pctrl_get_groups_count(struct pinctrl_dev *pctldev)
6148c2ecf20Sopenharmony_ci{
6158c2ecf20Sopenharmony_ci	struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci	return pctl->ngroups;
6188c2ecf20Sopenharmony_ci}
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_cistatic const char *mtk_pctrl_get_group_name(struct pinctrl_dev *pctldev,
6218c2ecf20Sopenharmony_ci					      unsigned group)
6228c2ecf20Sopenharmony_ci{
6238c2ecf20Sopenharmony_ci	struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	return pctl->groups[group].name;
6268c2ecf20Sopenharmony_ci}
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_cistatic int mtk_pctrl_get_group_pins(struct pinctrl_dev *pctldev,
6298c2ecf20Sopenharmony_ci				      unsigned group,
6308c2ecf20Sopenharmony_ci				      const unsigned **pins,
6318c2ecf20Sopenharmony_ci				      unsigned *num_pins)
6328c2ecf20Sopenharmony_ci{
6338c2ecf20Sopenharmony_ci	struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci	*pins = (unsigned *)&pctl->groups[group].pin;
6368c2ecf20Sopenharmony_ci	*num_pins = 1;
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	return 0;
6398c2ecf20Sopenharmony_ci}
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_cistatic const struct pinctrl_ops mtk_pctrl_ops = {
6428c2ecf20Sopenharmony_ci	.dt_node_to_map		= mtk_pctrl_dt_node_to_map,
6438c2ecf20Sopenharmony_ci	.dt_free_map		= pinctrl_utils_free_map,
6448c2ecf20Sopenharmony_ci	.get_groups_count	= mtk_pctrl_get_groups_count,
6458c2ecf20Sopenharmony_ci	.get_group_name		= mtk_pctrl_get_group_name,
6468c2ecf20Sopenharmony_ci	.get_group_pins		= mtk_pctrl_get_group_pins,
6478c2ecf20Sopenharmony_ci};
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_cistatic int mtk_pmx_get_funcs_cnt(struct pinctrl_dev *pctldev)
6508c2ecf20Sopenharmony_ci{
6518c2ecf20Sopenharmony_ci	return ARRAY_SIZE(mtk_gpio_functions);
6528c2ecf20Sopenharmony_ci}
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_cistatic const char *mtk_pmx_get_func_name(struct pinctrl_dev *pctldev,
6558c2ecf20Sopenharmony_ci					   unsigned selector)
6568c2ecf20Sopenharmony_ci{
6578c2ecf20Sopenharmony_ci	return mtk_gpio_functions[selector];
6588c2ecf20Sopenharmony_ci}
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_cistatic int mtk_pmx_get_func_groups(struct pinctrl_dev *pctldev,
6618c2ecf20Sopenharmony_ci				     unsigned function,
6628c2ecf20Sopenharmony_ci				     const char * const **groups,
6638c2ecf20Sopenharmony_ci				     unsigned * const num_groups)
6648c2ecf20Sopenharmony_ci{
6658c2ecf20Sopenharmony_ci	struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci	*groups = pctl->grp_names;
6688c2ecf20Sopenharmony_ci	*num_groups = pctl->ngroups;
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	return 0;
6718c2ecf20Sopenharmony_ci}
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_cistatic int mtk_pmx_set_mode(struct pinctrl_dev *pctldev,
6748c2ecf20Sopenharmony_ci		unsigned long pin, unsigned long mode)
6758c2ecf20Sopenharmony_ci{
6768c2ecf20Sopenharmony_ci	unsigned int reg_addr;
6778c2ecf20Sopenharmony_ci	unsigned char bit;
6788c2ecf20Sopenharmony_ci	unsigned int val;
6798c2ecf20Sopenharmony_ci	unsigned int mask = (1L << GPIO_MODE_BITS) - 1;
6808c2ecf20Sopenharmony_ci	struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci	if (pctl->devdata->spec_pinmux_set)
6838c2ecf20Sopenharmony_ci		pctl->devdata->spec_pinmux_set(mtk_get_regmap(pctl, pin),
6848c2ecf20Sopenharmony_ci					pin, mode);
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	reg_addr = ((pin / MAX_GPIO_MODE_PER_REG) << pctl->devdata->port_shf)
6878c2ecf20Sopenharmony_ci			+ pctl->devdata->pinmux_offset;
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci	mode &= mask;
6908c2ecf20Sopenharmony_ci	bit = pin % MAX_GPIO_MODE_PER_REG;
6918c2ecf20Sopenharmony_ci	mask <<= (GPIO_MODE_BITS * bit);
6928c2ecf20Sopenharmony_ci	val = (mode << (GPIO_MODE_BITS * bit));
6938c2ecf20Sopenharmony_ci	return regmap_update_bits(mtk_get_regmap(pctl, pin),
6948c2ecf20Sopenharmony_ci			reg_addr, mask, val);
6958c2ecf20Sopenharmony_ci}
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_cistatic const struct mtk_desc_pin *
6988c2ecf20Sopenharmony_cimtk_find_pin_by_eint_num(struct mtk_pinctrl *pctl, unsigned int eint_num)
6998c2ecf20Sopenharmony_ci{
7008c2ecf20Sopenharmony_ci	int i;
7018c2ecf20Sopenharmony_ci	const struct mtk_desc_pin *pin;
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci	for (i = 0; i < pctl->devdata->npins; i++) {
7048c2ecf20Sopenharmony_ci		pin = pctl->devdata->pins + i;
7058c2ecf20Sopenharmony_ci		if (pin->eint.eintnum == eint_num)
7068c2ecf20Sopenharmony_ci			return pin;
7078c2ecf20Sopenharmony_ci	}
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	return NULL;
7108c2ecf20Sopenharmony_ci}
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_cistatic int mtk_pmx_set_mux(struct pinctrl_dev *pctldev,
7138c2ecf20Sopenharmony_ci			    unsigned function,
7148c2ecf20Sopenharmony_ci			    unsigned group)
7158c2ecf20Sopenharmony_ci{
7168c2ecf20Sopenharmony_ci	bool ret;
7178c2ecf20Sopenharmony_ci	const struct mtk_desc_function *desc;
7188c2ecf20Sopenharmony_ci	struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
7198c2ecf20Sopenharmony_ci	struct mtk_pinctrl_group *g = pctl->groups + group;
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci	ret = mtk_pctrl_is_function_valid(pctl, g->pin, function);
7228c2ecf20Sopenharmony_ci	if (!ret) {
7238c2ecf20Sopenharmony_ci		dev_err(pctl->dev, "invalid function %d on group %d .\n",
7248c2ecf20Sopenharmony_ci				function, group);
7258c2ecf20Sopenharmony_ci		return -EINVAL;
7268c2ecf20Sopenharmony_ci	}
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci	desc = mtk_pctrl_find_function_by_pin(pctl, g->pin, function);
7298c2ecf20Sopenharmony_ci	if (!desc)
7308c2ecf20Sopenharmony_ci		return -EINVAL;
7318c2ecf20Sopenharmony_ci	mtk_pmx_set_mode(pctldev, g->pin, desc->muxval);
7328c2ecf20Sopenharmony_ci	return 0;
7338c2ecf20Sopenharmony_ci}
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_cistatic int mtk_pmx_find_gpio_mode(struct mtk_pinctrl *pctl,
7368c2ecf20Sopenharmony_ci				unsigned offset)
7378c2ecf20Sopenharmony_ci{
7388c2ecf20Sopenharmony_ci	const struct mtk_desc_pin *pin = pctl->devdata->pins + offset;
7398c2ecf20Sopenharmony_ci	const struct mtk_desc_function *func = pin->functions;
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci	while (func && func->name) {
7428c2ecf20Sopenharmony_ci		if (!strncmp(func->name, GPIO_MODE_PREFIX,
7438c2ecf20Sopenharmony_ci			sizeof(GPIO_MODE_PREFIX)-1))
7448c2ecf20Sopenharmony_ci			return func->muxval;
7458c2ecf20Sopenharmony_ci		func++;
7468c2ecf20Sopenharmony_ci	}
7478c2ecf20Sopenharmony_ci	return -EINVAL;
7488c2ecf20Sopenharmony_ci}
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_cistatic int mtk_pmx_gpio_request_enable(struct pinctrl_dev *pctldev,
7518c2ecf20Sopenharmony_ci				    struct pinctrl_gpio_range *range,
7528c2ecf20Sopenharmony_ci				    unsigned offset)
7538c2ecf20Sopenharmony_ci{
7548c2ecf20Sopenharmony_ci	int muxval;
7558c2ecf20Sopenharmony_ci	struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci	muxval = mtk_pmx_find_gpio_mode(pctl, offset);
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci	if (muxval < 0) {
7608c2ecf20Sopenharmony_ci		dev_err(pctl->dev, "invalid gpio pin %d.\n", offset);
7618c2ecf20Sopenharmony_ci		return -EINVAL;
7628c2ecf20Sopenharmony_ci	}
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci	mtk_pmx_set_mode(pctldev, offset, muxval);
7658c2ecf20Sopenharmony_ci	mtk_pconf_set_ies_smt(pctl, offset, 1, PIN_CONFIG_INPUT_ENABLE);
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci	return 0;
7688c2ecf20Sopenharmony_ci}
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_cistatic const struct pinmux_ops mtk_pmx_ops = {
7718c2ecf20Sopenharmony_ci	.get_functions_count	= mtk_pmx_get_funcs_cnt,
7728c2ecf20Sopenharmony_ci	.get_function_name	= mtk_pmx_get_func_name,
7738c2ecf20Sopenharmony_ci	.get_function_groups	= mtk_pmx_get_func_groups,
7748c2ecf20Sopenharmony_ci	.set_mux		= mtk_pmx_set_mux,
7758c2ecf20Sopenharmony_ci	.gpio_set_direction	= mtk_pmx_gpio_set_direction,
7768c2ecf20Sopenharmony_ci	.gpio_request_enable	= mtk_pmx_gpio_request_enable,
7778c2ecf20Sopenharmony_ci};
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_cistatic int mtk_gpio_direction_input(struct gpio_chip *chip,
7808c2ecf20Sopenharmony_ci					unsigned offset)
7818c2ecf20Sopenharmony_ci{
7828c2ecf20Sopenharmony_ci	return pinctrl_gpio_direction_input(chip->base + offset);
7838c2ecf20Sopenharmony_ci}
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_cistatic int mtk_gpio_direction_output(struct gpio_chip *chip,
7868c2ecf20Sopenharmony_ci					unsigned offset, int value)
7878c2ecf20Sopenharmony_ci{
7888c2ecf20Sopenharmony_ci	mtk_gpio_set(chip, offset, value);
7898c2ecf20Sopenharmony_ci	return pinctrl_gpio_direction_output(chip->base + offset);
7908c2ecf20Sopenharmony_ci}
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_cistatic int mtk_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
7938c2ecf20Sopenharmony_ci{
7948c2ecf20Sopenharmony_ci	unsigned int reg_addr;
7958c2ecf20Sopenharmony_ci	unsigned int bit;
7968c2ecf20Sopenharmony_ci	unsigned int read_val = 0;
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci	struct mtk_pinctrl *pctl = gpiochip_get_data(chip);
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_ci	reg_addr =  mtk_get_port(pctl, offset) + pctl->devdata->dir_offset;
8018c2ecf20Sopenharmony_ci	bit = BIT(offset & 0xf);
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci	if (pctl->devdata->spec_dir_set)
8048c2ecf20Sopenharmony_ci		pctl->devdata->spec_dir_set(&reg_addr, offset);
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci	regmap_read(pctl->regmap1, reg_addr, &read_val);
8078c2ecf20Sopenharmony_ci	if (read_val & bit)
8088c2ecf20Sopenharmony_ci		return GPIO_LINE_DIRECTION_OUT;
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci	return GPIO_LINE_DIRECTION_IN;
8118c2ecf20Sopenharmony_ci}
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_cistatic int mtk_gpio_get(struct gpio_chip *chip, unsigned offset)
8148c2ecf20Sopenharmony_ci{
8158c2ecf20Sopenharmony_ci	unsigned int reg_addr;
8168c2ecf20Sopenharmony_ci	unsigned int bit;
8178c2ecf20Sopenharmony_ci	unsigned int read_val = 0;
8188c2ecf20Sopenharmony_ci	struct mtk_pinctrl *pctl = gpiochip_get_data(chip);
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci	reg_addr = mtk_get_port(pctl, offset) +
8218c2ecf20Sopenharmony_ci		pctl->devdata->din_offset;
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci	bit = BIT(offset & 0xf);
8248c2ecf20Sopenharmony_ci	regmap_read(pctl->regmap1, reg_addr, &read_val);
8258c2ecf20Sopenharmony_ci	return !!(read_val & bit);
8268c2ecf20Sopenharmony_ci}
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_cistatic int mtk_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
8298c2ecf20Sopenharmony_ci{
8308c2ecf20Sopenharmony_ci	struct mtk_pinctrl *pctl = gpiochip_get_data(chip);
8318c2ecf20Sopenharmony_ci	const struct mtk_desc_pin *pin;
8328c2ecf20Sopenharmony_ci	unsigned long eint_n;
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci	pin = pctl->devdata->pins + offset;
8358c2ecf20Sopenharmony_ci	if (pin->eint.eintnum == NO_EINT_SUPPORT)
8368c2ecf20Sopenharmony_ci		return -EINVAL;
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_ci	eint_n = pin->eint.eintnum;
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci	return mtk_eint_find_irq(pctl->eint, eint_n);
8418c2ecf20Sopenharmony_ci}
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_cistatic int mtk_gpio_set_config(struct gpio_chip *chip, unsigned offset,
8448c2ecf20Sopenharmony_ci			       unsigned long config)
8458c2ecf20Sopenharmony_ci{
8468c2ecf20Sopenharmony_ci	struct mtk_pinctrl *pctl = gpiochip_get_data(chip);
8478c2ecf20Sopenharmony_ci	const struct mtk_desc_pin *pin;
8488c2ecf20Sopenharmony_ci	unsigned long eint_n;
8498c2ecf20Sopenharmony_ci	u32 debounce;
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci	if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
8528c2ecf20Sopenharmony_ci		return -ENOTSUPP;
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ci	pin = pctl->devdata->pins + offset;
8558c2ecf20Sopenharmony_ci	if (pin->eint.eintnum == NO_EINT_SUPPORT)
8568c2ecf20Sopenharmony_ci		return -EINVAL;
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci	debounce = pinconf_to_config_argument(config);
8598c2ecf20Sopenharmony_ci	eint_n = pin->eint.eintnum;
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci	return mtk_eint_set_debounce(pctl->eint, eint_n, debounce);
8628c2ecf20Sopenharmony_ci}
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_cistatic const struct gpio_chip mtk_gpio_chip = {
8658c2ecf20Sopenharmony_ci	.owner			= THIS_MODULE,
8668c2ecf20Sopenharmony_ci	.request		= gpiochip_generic_request,
8678c2ecf20Sopenharmony_ci	.free			= gpiochip_generic_free,
8688c2ecf20Sopenharmony_ci	.get_direction		= mtk_gpio_get_direction,
8698c2ecf20Sopenharmony_ci	.direction_input	= mtk_gpio_direction_input,
8708c2ecf20Sopenharmony_ci	.direction_output	= mtk_gpio_direction_output,
8718c2ecf20Sopenharmony_ci	.get			= mtk_gpio_get,
8728c2ecf20Sopenharmony_ci	.set			= mtk_gpio_set,
8738c2ecf20Sopenharmony_ci	.to_irq			= mtk_gpio_to_irq,
8748c2ecf20Sopenharmony_ci	.set_config		= mtk_gpio_set_config,
8758c2ecf20Sopenharmony_ci	.of_gpio_n_cells	= 2,
8768c2ecf20Sopenharmony_ci};
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_cistatic int mtk_eint_suspend(struct device *device)
8798c2ecf20Sopenharmony_ci{
8808c2ecf20Sopenharmony_ci	struct mtk_pinctrl *pctl = dev_get_drvdata(device);
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci	return mtk_eint_do_suspend(pctl->eint);
8838c2ecf20Sopenharmony_ci}
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_cistatic int mtk_eint_resume(struct device *device)
8868c2ecf20Sopenharmony_ci{
8878c2ecf20Sopenharmony_ci	struct mtk_pinctrl *pctl = dev_get_drvdata(device);
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci	return mtk_eint_do_resume(pctl->eint);
8908c2ecf20Sopenharmony_ci}
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ciconst struct dev_pm_ops mtk_eint_pm_ops = {
8938c2ecf20Sopenharmony_ci	.suspend_noirq = mtk_eint_suspend,
8948c2ecf20Sopenharmony_ci	.resume_noirq = mtk_eint_resume,
8958c2ecf20Sopenharmony_ci};
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_cistatic int mtk_pctrl_build_state(struct platform_device *pdev)
8988c2ecf20Sopenharmony_ci{
8998c2ecf20Sopenharmony_ci	struct mtk_pinctrl *pctl = platform_get_drvdata(pdev);
9008c2ecf20Sopenharmony_ci	int i;
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci	pctl->ngroups = pctl->devdata->npins;
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci	/* Allocate groups */
9058c2ecf20Sopenharmony_ci	pctl->groups = devm_kcalloc(&pdev->dev, pctl->ngroups,
9068c2ecf20Sopenharmony_ci				    sizeof(*pctl->groups), GFP_KERNEL);
9078c2ecf20Sopenharmony_ci	if (!pctl->groups)
9088c2ecf20Sopenharmony_ci		return -ENOMEM;
9098c2ecf20Sopenharmony_ci
9108c2ecf20Sopenharmony_ci	/* We assume that one pin is one group, use pin name as group name. */
9118c2ecf20Sopenharmony_ci	pctl->grp_names = devm_kcalloc(&pdev->dev, pctl->ngroups,
9128c2ecf20Sopenharmony_ci				       sizeof(*pctl->grp_names), GFP_KERNEL);
9138c2ecf20Sopenharmony_ci	if (!pctl->grp_names)
9148c2ecf20Sopenharmony_ci		return -ENOMEM;
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci	for (i = 0; i < pctl->devdata->npins; i++) {
9178c2ecf20Sopenharmony_ci		const struct mtk_desc_pin *pin = pctl->devdata->pins + i;
9188c2ecf20Sopenharmony_ci		struct mtk_pinctrl_group *group = pctl->groups + i;
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ci		group->name = pin->pin.name;
9218c2ecf20Sopenharmony_ci		group->pin = pin->pin.number;
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci		pctl->grp_names[i] = pin->pin.name;
9248c2ecf20Sopenharmony_ci	}
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci	return 0;
9278c2ecf20Sopenharmony_ci}
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_cistatic int
9308c2ecf20Sopenharmony_cimtk_xt_get_gpio_n(void *data, unsigned long eint_n, unsigned int *gpio_n,
9318c2ecf20Sopenharmony_ci		  struct gpio_chip **gpio_chip)
9328c2ecf20Sopenharmony_ci{
9338c2ecf20Sopenharmony_ci	struct mtk_pinctrl *pctl = (struct mtk_pinctrl *)data;
9348c2ecf20Sopenharmony_ci	const struct mtk_desc_pin *pin;
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	pin = mtk_find_pin_by_eint_num(pctl, eint_n);
9378c2ecf20Sopenharmony_ci	if (!pin)
9388c2ecf20Sopenharmony_ci		return -EINVAL;
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_ci	*gpio_chip = pctl->chip;
9418c2ecf20Sopenharmony_ci	*gpio_n = pin->pin.number;
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci	return 0;
9448c2ecf20Sopenharmony_ci}
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_cistatic int mtk_xt_get_gpio_state(void *data, unsigned long eint_n)
9478c2ecf20Sopenharmony_ci{
9488c2ecf20Sopenharmony_ci	struct mtk_pinctrl *pctl = (struct mtk_pinctrl *)data;
9498c2ecf20Sopenharmony_ci	const struct mtk_desc_pin *pin;
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci	pin = mtk_find_pin_by_eint_num(pctl, eint_n);
9528c2ecf20Sopenharmony_ci	if (!pin)
9538c2ecf20Sopenharmony_ci		return -EINVAL;
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_ci	return mtk_gpio_get(pctl->chip, pin->pin.number);
9568c2ecf20Sopenharmony_ci}
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_cistatic int mtk_xt_set_gpio_as_eint(void *data, unsigned long eint_n)
9598c2ecf20Sopenharmony_ci{
9608c2ecf20Sopenharmony_ci	struct mtk_pinctrl *pctl = (struct mtk_pinctrl *)data;
9618c2ecf20Sopenharmony_ci	const struct mtk_desc_pin *pin;
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci	pin = mtk_find_pin_by_eint_num(pctl, eint_n);
9648c2ecf20Sopenharmony_ci	if (!pin)
9658c2ecf20Sopenharmony_ci		return -EINVAL;
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci	/* set mux to INT mode */
9688c2ecf20Sopenharmony_ci	mtk_pmx_set_mode(pctl->pctl_dev, pin->pin.number, pin->eint.eintmux);
9698c2ecf20Sopenharmony_ci	/* set gpio direction to input */
9708c2ecf20Sopenharmony_ci	mtk_pmx_gpio_set_direction(pctl->pctl_dev, NULL, pin->pin.number,
9718c2ecf20Sopenharmony_ci				   true);
9728c2ecf20Sopenharmony_ci	/* set input-enable */
9738c2ecf20Sopenharmony_ci	mtk_pconf_set_ies_smt(pctl, pin->pin.number, 1,
9748c2ecf20Sopenharmony_ci			      PIN_CONFIG_INPUT_ENABLE);
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci	return 0;
9778c2ecf20Sopenharmony_ci}
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_cistatic const struct mtk_eint_xt mtk_eint_xt = {
9808c2ecf20Sopenharmony_ci	.get_gpio_n = mtk_xt_get_gpio_n,
9818c2ecf20Sopenharmony_ci	.get_gpio_state = mtk_xt_get_gpio_state,
9828c2ecf20Sopenharmony_ci	.set_gpio_as_eint = mtk_xt_set_gpio_as_eint,
9838c2ecf20Sopenharmony_ci};
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_cistatic int mtk_eint_init(struct mtk_pinctrl *pctl, struct platform_device *pdev)
9868c2ecf20Sopenharmony_ci{
9878c2ecf20Sopenharmony_ci	struct device_node *np = pdev->dev.of_node;
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_ci	if (!of_property_read_bool(np, "interrupt-controller"))
9908c2ecf20Sopenharmony_ci		return -ENODEV;
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_ci	pctl->eint = devm_kzalloc(pctl->dev, sizeof(*pctl->eint), GFP_KERNEL);
9938c2ecf20Sopenharmony_ci	if (!pctl->eint)
9948c2ecf20Sopenharmony_ci		return -ENOMEM;
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_ci	pctl->eint->base = devm_platform_ioremap_resource(pdev, 0);
9978c2ecf20Sopenharmony_ci	if (IS_ERR(pctl->eint->base))
9988c2ecf20Sopenharmony_ci		return PTR_ERR(pctl->eint->base);
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ci	pctl->eint->irq = irq_of_parse_and_map(np, 0);
10018c2ecf20Sopenharmony_ci	if (!pctl->eint->irq)
10028c2ecf20Sopenharmony_ci		return -EINVAL;
10038c2ecf20Sopenharmony_ci
10048c2ecf20Sopenharmony_ci	pctl->eint->dev = &pdev->dev;
10058c2ecf20Sopenharmony_ci	/*
10068c2ecf20Sopenharmony_ci	 * If pctl->eint->regs == NULL, it would fall back into using a generic
10078c2ecf20Sopenharmony_ci	 * register map in mtk_eint_do_init calls.
10088c2ecf20Sopenharmony_ci	 */
10098c2ecf20Sopenharmony_ci	pctl->eint->regs = pctl->devdata->eint_regs;
10108c2ecf20Sopenharmony_ci	pctl->eint->hw = &pctl->devdata->eint_hw;
10118c2ecf20Sopenharmony_ci	pctl->eint->pctl = pctl;
10128c2ecf20Sopenharmony_ci	pctl->eint->gpio_xlate = &mtk_eint_xt;
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci	return mtk_eint_do_init(pctl->eint);
10158c2ecf20Sopenharmony_ci}
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_ciint mtk_pctrl_init(struct platform_device *pdev,
10188c2ecf20Sopenharmony_ci		const struct mtk_pinctrl_devdata *data,
10198c2ecf20Sopenharmony_ci		struct regmap *regmap)
10208c2ecf20Sopenharmony_ci{
10218c2ecf20Sopenharmony_ci	struct pinctrl_pin_desc *pins;
10228c2ecf20Sopenharmony_ci	struct mtk_pinctrl *pctl;
10238c2ecf20Sopenharmony_ci	struct device_node *np = pdev->dev.of_node, *node;
10248c2ecf20Sopenharmony_ci	struct property *prop;
10258c2ecf20Sopenharmony_ci	int ret, i;
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci	pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL);
10288c2ecf20Sopenharmony_ci	if (!pctl)
10298c2ecf20Sopenharmony_ci		return -ENOMEM;
10308c2ecf20Sopenharmony_ci
10318c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, pctl);
10328c2ecf20Sopenharmony_ci
10338c2ecf20Sopenharmony_ci	prop = of_find_property(np, "pins-are-numbered", NULL);
10348c2ecf20Sopenharmony_ci	if (!prop) {
10358c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "only support pins-are-numbered format\n");
10368c2ecf20Sopenharmony_ci		return -EINVAL;
10378c2ecf20Sopenharmony_ci	}
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_ci	node = of_parse_phandle(np, "mediatek,pctl-regmap", 0);
10408c2ecf20Sopenharmony_ci	if (node) {
10418c2ecf20Sopenharmony_ci		pctl->regmap1 = syscon_node_to_regmap(node);
10428c2ecf20Sopenharmony_ci		of_node_put(node);
10438c2ecf20Sopenharmony_ci		if (IS_ERR(pctl->regmap1))
10448c2ecf20Sopenharmony_ci			return PTR_ERR(pctl->regmap1);
10458c2ecf20Sopenharmony_ci	} else if (regmap) {
10468c2ecf20Sopenharmony_ci		pctl->regmap1  = regmap;
10478c2ecf20Sopenharmony_ci	} else {
10488c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Pinctrl node has not register regmap.\n");
10498c2ecf20Sopenharmony_ci		return -EINVAL;
10508c2ecf20Sopenharmony_ci	}
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_ci	/* Only 8135 has two base addr, other SoCs have only one. */
10538c2ecf20Sopenharmony_ci	node = of_parse_phandle(np, "mediatek,pctl-regmap", 1);
10548c2ecf20Sopenharmony_ci	if (node) {
10558c2ecf20Sopenharmony_ci		pctl->regmap2 = syscon_node_to_regmap(node);
10568c2ecf20Sopenharmony_ci		of_node_put(node);
10578c2ecf20Sopenharmony_ci		if (IS_ERR(pctl->regmap2))
10588c2ecf20Sopenharmony_ci			return PTR_ERR(pctl->regmap2);
10598c2ecf20Sopenharmony_ci	}
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci	pctl->devdata = data;
10628c2ecf20Sopenharmony_ci	ret = mtk_pctrl_build_state(pdev);
10638c2ecf20Sopenharmony_ci	if (ret) {
10648c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "build state failed: %d\n", ret);
10658c2ecf20Sopenharmony_ci		return -EINVAL;
10668c2ecf20Sopenharmony_ci	}
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_ci	pins = devm_kcalloc(&pdev->dev, pctl->devdata->npins, sizeof(*pins),
10698c2ecf20Sopenharmony_ci			    GFP_KERNEL);
10708c2ecf20Sopenharmony_ci	if (!pins)
10718c2ecf20Sopenharmony_ci		return -ENOMEM;
10728c2ecf20Sopenharmony_ci
10738c2ecf20Sopenharmony_ci	for (i = 0; i < pctl->devdata->npins; i++)
10748c2ecf20Sopenharmony_ci		pins[i] = pctl->devdata->pins[i].pin;
10758c2ecf20Sopenharmony_ci
10768c2ecf20Sopenharmony_ci	pctl->pctl_desc.name = dev_name(&pdev->dev);
10778c2ecf20Sopenharmony_ci	pctl->pctl_desc.owner = THIS_MODULE;
10788c2ecf20Sopenharmony_ci	pctl->pctl_desc.pins = pins;
10798c2ecf20Sopenharmony_ci	pctl->pctl_desc.npins = pctl->devdata->npins;
10808c2ecf20Sopenharmony_ci	pctl->pctl_desc.confops = &mtk_pconf_ops;
10818c2ecf20Sopenharmony_ci	pctl->pctl_desc.pctlops = &mtk_pctrl_ops;
10828c2ecf20Sopenharmony_ci	pctl->pctl_desc.pmxops = &mtk_pmx_ops;
10838c2ecf20Sopenharmony_ci	pctl->dev = &pdev->dev;
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_ci	pctl->pctl_dev = devm_pinctrl_register(&pdev->dev, &pctl->pctl_desc,
10868c2ecf20Sopenharmony_ci					       pctl);
10878c2ecf20Sopenharmony_ci	if (IS_ERR(pctl->pctl_dev)) {
10888c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "couldn't register pinctrl driver\n");
10898c2ecf20Sopenharmony_ci		return PTR_ERR(pctl->pctl_dev);
10908c2ecf20Sopenharmony_ci	}
10918c2ecf20Sopenharmony_ci
10928c2ecf20Sopenharmony_ci	pctl->chip = devm_kzalloc(&pdev->dev, sizeof(*pctl->chip), GFP_KERNEL);
10938c2ecf20Sopenharmony_ci	if (!pctl->chip)
10948c2ecf20Sopenharmony_ci		return -ENOMEM;
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci	*pctl->chip = mtk_gpio_chip;
10978c2ecf20Sopenharmony_ci	pctl->chip->ngpio = pctl->devdata->npins;
10988c2ecf20Sopenharmony_ci	pctl->chip->label = dev_name(&pdev->dev);
10998c2ecf20Sopenharmony_ci	pctl->chip->parent = &pdev->dev;
11008c2ecf20Sopenharmony_ci	pctl->chip->base = -1;
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_ci	ret = gpiochip_add_data(pctl->chip, pctl);
11038c2ecf20Sopenharmony_ci	if (ret)
11048c2ecf20Sopenharmony_ci		return -EINVAL;
11058c2ecf20Sopenharmony_ci
11068c2ecf20Sopenharmony_ci	/* Register the GPIO to pin mappings. */
11078c2ecf20Sopenharmony_ci	ret = gpiochip_add_pin_range(pctl->chip, dev_name(&pdev->dev),
11088c2ecf20Sopenharmony_ci			0, 0, pctl->devdata->npins);
11098c2ecf20Sopenharmony_ci	if (ret) {
11108c2ecf20Sopenharmony_ci		ret = -EINVAL;
11118c2ecf20Sopenharmony_ci		goto chip_error;
11128c2ecf20Sopenharmony_ci	}
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ci	ret = mtk_eint_init(pctl, pdev);
11158c2ecf20Sopenharmony_ci	if (ret)
11168c2ecf20Sopenharmony_ci		goto chip_error;
11178c2ecf20Sopenharmony_ci
11188c2ecf20Sopenharmony_ci	return 0;
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_cichip_error:
11218c2ecf20Sopenharmony_ci	gpiochip_remove(pctl->chip);
11228c2ecf20Sopenharmony_ci	return ret;
11238c2ecf20Sopenharmony_ci}
1124