pinctrl: mediatek: add pinctrl-moore that implements the generic pinctrl dt-bindings
Add a generic driver pinctrl-moore.c for MT762x SoC and any other SoC that would like to use generic dt-binding. The patch is furtherly refactored from pinctrl-mt7622.c that totally uses the functions back by the generic pinctrl core such as GENERIC_PINCONF, GENERIC_PINCTRL_GROUPS, and GENERIC_PINMUX_FUNCTIONS and its binding also completely follows up pinctrl-bindings.txt in Documentation/devicetree/bindings/pinctrl/ to implement. Signed-off-by: Ryder.Lee <ryder.lee@mediatek.com> Signed-off-by: Sean Wang <sean.wang@mediatek.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
This commit is contained in:
@@ -3,7 +3,7 @@ menu "MediaTek pinctrl drivers"
|
|||||||
|
|
||||||
config EINT_MTK
|
config EINT_MTK
|
||||||
bool "MediaTek External Interrupt Support"
|
bool "MediaTek External Interrupt Support"
|
||||||
depends on PINCTRL_MTK || PINCTRL_MT7622 || COMPILE_TEST
|
depends on PINCTRL_MTK || PINCTRL_MTK_MOORE || COMPILE_TEST
|
||||||
select IRQ_DOMAIN
|
select IRQ_DOMAIN
|
||||||
|
|
||||||
config PINCTRL_MTK
|
config PINCTRL_MTK
|
||||||
@@ -15,6 +15,15 @@ config PINCTRL_MTK
|
|||||||
select EINT_MTK
|
select EINT_MTK
|
||||||
select OF_GPIO
|
select OF_GPIO
|
||||||
|
|
||||||
|
config PINCTRL_MTK_MOORE
|
||||||
|
bool "MediaTek Moore Core that implements generic binding"
|
||||||
|
depends on OF
|
||||||
|
select GENERIC_PINCONF
|
||||||
|
select GENERIC_PINCTRL_GROUPS
|
||||||
|
select GENERIC_PINMUX_FUNCTIONS
|
||||||
|
select GPIOLIB
|
||||||
|
select OF_GPIO
|
||||||
|
|
||||||
# For ARMv7 SoCs
|
# For ARMv7 SoCs
|
||||||
config PINCTRL_MT2701
|
config PINCTRL_MT2701
|
||||||
bool "Mediatek MT2701 pin control"
|
bool "Mediatek MT2701 pin control"
|
||||||
@@ -47,13 +56,9 @@ config PINCTRL_MT2712
|
|||||||
|
|
||||||
config PINCTRL_MT7622
|
config PINCTRL_MT7622
|
||||||
bool "MediaTek MT7622 pin control"
|
bool "MediaTek MT7622 pin control"
|
||||||
depends on OF
|
|
||||||
depends on ARM64 || COMPILE_TEST
|
depends on ARM64 || COMPILE_TEST
|
||||||
select GENERIC_PINCONF
|
depends on PINCTRL_MTK_MOORE
|
||||||
select GENERIC_PINCTRL_GROUPS
|
default y
|
||||||
select GENERIC_PINMUX_FUNCTIONS
|
|
||||||
select GPIOLIB
|
|
||||||
select OF_GPIO
|
|
||||||
|
|
||||||
config PINCTRL_MT8173
|
config PINCTRL_MT8173
|
||||||
bool "Mediatek MT8173 pin control"
|
bool "Mediatek MT8173 pin control"
|
||||||
|
@@ -2,12 +2,13 @@
|
|||||||
# Core
|
# Core
|
||||||
obj-$(CONFIG_EINT_MTK) += mtk-eint.o
|
obj-$(CONFIG_EINT_MTK) += mtk-eint.o
|
||||||
obj-$(CONFIG_PINCTRL_MTK) += pinctrl-mtk-common.o
|
obj-$(CONFIG_PINCTRL_MTK) += pinctrl-mtk-common.o
|
||||||
|
obj-$(CONFIG_PINCTRL_MTK_MOORE) += pinctrl-moore.o pinctrl-mtk-common-v2.o
|
||||||
|
|
||||||
# SoC Drivers
|
# SoC Drivers
|
||||||
obj-$(CONFIG_PINCTRL_MT2701) += pinctrl-mt2701.o
|
obj-$(CONFIG_PINCTRL_MT2701) += pinctrl-mt2701.o
|
||||||
obj-$(CONFIG_PINCTRL_MT2712) += pinctrl-mt2712.o
|
obj-$(CONFIG_PINCTRL_MT2712) += pinctrl-mt2712.o
|
||||||
obj-$(CONFIG_PINCTRL_MT8135) += pinctrl-mt8135.o
|
obj-$(CONFIG_PINCTRL_MT8135) += pinctrl-mt8135.o
|
||||||
obj-$(CONFIG_PINCTRL_MT8127) += pinctrl-mt8127.o
|
obj-$(CONFIG_PINCTRL_MT8127) += pinctrl-mt8127.o
|
||||||
obj-$(CONFIG_PINCTRL_MT7622) += pinctrl-mtk-common-v2.o pinctrl-mt7622.o
|
obj-$(CONFIG_PINCTRL_MT7622) += pinctrl-mt7622.o
|
||||||
obj-$(CONFIG_PINCTRL_MT8173) += pinctrl-mt8173.o
|
obj-$(CONFIG_PINCTRL_MT8173) += pinctrl-mt8173.o
|
||||||
obj-$(CONFIG_PINCTRL_MT6397) += pinctrl-mt6397.o
|
obj-$(CONFIG_PINCTRL_MT6397) += pinctrl-mt6397.o
|
||||||
|
687
drivers/pinctrl/mediatek/pinctrl-moore.c
Normal file
687
drivers/pinctrl/mediatek/pinctrl-moore.c
Normal file
@@ -0,0 +1,687 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* MediaTek Pinctrl Moore Driver, which implement the generic dt-binding
|
||||||
|
* pinctrl-bindings.txt for MediaTek SoC.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017-2018 MediaTek Inc.
|
||||||
|
* Author: Sean Wang <sean.wang@mediatek.com>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pinctrl-moore.h"
|
||||||
|
|
||||||
|
#define PINCTRL_PINCTRL_DEV KBUILD_MODNAME
|
||||||
|
|
||||||
|
/* Custom pinconf parameters */
|
||||||
|
#define MTK_PIN_CONFIG_TDSEL (PIN_CONFIG_END + 1)
|
||||||
|
#define MTK_PIN_CONFIG_RDSEL (PIN_CONFIG_END + 2)
|
||||||
|
|
||||||
|
static const struct pinconf_generic_params mtk_custom_bindings[] = {
|
||||||
|
{"mediatek,tdsel", MTK_PIN_CONFIG_TDSEL, 0},
|
||||||
|
{"mediatek,rdsel", MTK_PIN_CONFIG_RDSEL, 0},
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_DEBUG_FS
|
||||||
|
static const struct pin_config_item mtk_conf_items[] = {
|
||||||
|
PCONFDUMP(MTK_PIN_CONFIG_TDSEL, "tdsel", NULL, true),
|
||||||
|
PCONFDUMP(MTK_PIN_CONFIG_RDSEL, "rdsel", NULL, true),
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int mtk_pinmux_set_mux(struct pinctrl_dev *pctldev,
|
||||||
|
unsigned int selector, unsigned int group)
|
||||||
|
{
|
||||||
|
struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev);
|
||||||
|
struct function_desc *func;
|
||||||
|
struct group_desc *grp;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
func = pinmux_generic_get_function(pctldev, selector);
|
||||||
|
if (!func)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
grp = pinctrl_generic_get_group(pctldev, group);
|
||||||
|
if (!grp)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
dev_dbg(pctldev->dev, "enable function %s group %s\n",
|
||||||
|
func->name, grp->name);
|
||||||
|
|
||||||
|
for (i = 0; i < grp->num_pins; i++) {
|
||||||
|
int *pin_modes = grp->data;
|
||||||
|
|
||||||
|
mtk_hw_set_value(hw, grp->pins[i], PINCTRL_PIN_REG_MODE,
|
||||||
|
pin_modes[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mtk_pinmux_gpio_request_enable(struct pinctrl_dev *pctldev,
|
||||||
|
struct pinctrl_gpio_range *range,
|
||||||
|
unsigned int pin)
|
||||||
|
{
|
||||||
|
struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev);
|
||||||
|
|
||||||
|
return mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_MODE, MTK_GPIO_MODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mtk_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev,
|
||||||
|
struct pinctrl_gpio_range *range,
|
||||||
|
unsigned int pin, bool input)
|
||||||
|
{
|
||||||
|
struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev);
|
||||||
|
|
||||||
|
/* hardware would take 0 as input direction */
|
||||||
|
return mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_DIR, !input);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mtk_pinconf_get(struct pinctrl_dev *pctldev,
|
||||||
|
unsigned int pin, unsigned long *config)
|
||||||
|
{
|
||||||
|
struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev);
|
||||||
|
u32 param = pinconf_to_config_param(*config);
|
||||||
|
int val, val2, err, reg, ret = 1;
|
||||||
|
|
||||||
|
switch (param) {
|
||||||
|
case PIN_CONFIG_BIAS_DISABLE:
|
||||||
|
err = mtk_hw_get_value(hw, pin, PINCTRL_PIN_REG_PU, &val);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
err = mtk_hw_get_value(hw, pin, PINCTRL_PIN_REG_PD, &val2);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if (val || val2)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case PIN_CONFIG_BIAS_PULL_UP:
|
||||||
|
case PIN_CONFIG_BIAS_PULL_DOWN:
|
||||||
|
case PIN_CONFIG_SLEW_RATE:
|
||||||
|
reg = (param == PIN_CONFIG_BIAS_PULL_UP) ?
|
||||||
|
PINCTRL_PIN_REG_PU :
|
||||||
|
(param == PIN_CONFIG_BIAS_PULL_DOWN) ?
|
||||||
|
PINCTRL_PIN_REG_PD : PINCTRL_PIN_REG_SR;
|
||||||
|
|
||||||
|
err = mtk_hw_get_value(hw, pin, reg, &val);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if (!val)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case PIN_CONFIG_INPUT_ENABLE:
|
||||||
|
case PIN_CONFIG_OUTPUT_ENABLE:
|
||||||
|
err = mtk_hw_get_value(hw, pin, PINCTRL_PIN_REG_DIR, &val);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
/* HW takes input mode as zero; output mode as non-zero */
|
||||||
|
if ((val && param == PIN_CONFIG_INPUT_ENABLE) ||
|
||||||
|
(!val && param == PIN_CONFIG_OUTPUT_ENABLE))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
|
||||||
|
err = mtk_hw_get_value(hw, pin, PINCTRL_PIN_REG_DIR, &val);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
err = mtk_hw_get_value(hw, pin, PINCTRL_PIN_REG_SMT, &val2);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if (val || !val2)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case PIN_CONFIG_DRIVE_STRENGTH:
|
||||||
|
err = mtk_hw_get_value(hw, pin, PINCTRL_PIN_REG_E4, &val);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
err = mtk_hw_get_value(hw, pin, PINCTRL_PIN_REG_E8, &val2);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
/* 4mA when (e8, e4) = (0, 0); 8mA when (e8, e4) = (0, 1)
|
||||||
|
* 12mA when (e8, e4) = (1, 0); 16mA when (e8, e4) = (1, 1)
|
||||||
|
*/
|
||||||
|
ret = ((val2 << 1) + val + 1) * 4;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case MTK_PIN_CONFIG_TDSEL:
|
||||||
|
case MTK_PIN_CONFIG_RDSEL:
|
||||||
|
reg = (param == MTK_PIN_CONFIG_TDSEL) ?
|
||||||
|
PINCTRL_PIN_REG_TDSEL : PINCTRL_PIN_REG_RDSEL;
|
||||||
|
|
||||||
|
err = mtk_hw_get_value(hw, pin, reg, &val);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
ret = val;
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -ENOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
*config = pinconf_to_config_packed(param, ret);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mtk_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
|
||||||
|
unsigned long *configs, unsigned int num_configs)
|
||||||
|
{
|
||||||
|
struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev);
|
||||||
|
u32 reg, param, arg;
|
||||||
|
int cfg, err = 0;
|
||||||
|
|
||||||
|
for (cfg = 0; cfg < num_configs; cfg++) {
|
||||||
|
param = pinconf_to_config_param(configs[cfg]);
|
||||||
|
arg = pinconf_to_config_argument(configs[cfg]);
|
||||||
|
|
||||||
|
switch (param) {
|
||||||
|
case PIN_CONFIG_BIAS_DISABLE:
|
||||||
|
case PIN_CONFIG_BIAS_PULL_UP:
|
||||||
|
case PIN_CONFIG_BIAS_PULL_DOWN:
|
||||||
|
arg = (param == PIN_CONFIG_BIAS_DISABLE) ? 0 :
|
||||||
|
(param == PIN_CONFIG_BIAS_PULL_UP) ? 1 : 2;
|
||||||
|
|
||||||
|
err = mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_PU,
|
||||||
|
arg & 1);
|
||||||
|
if (err)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
err = mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_PD,
|
||||||
|
!!(arg & 2));
|
||||||
|
if (err)
|
||||||
|
goto err;
|
||||||
|
break;
|
||||||
|
case PIN_CONFIG_OUTPUT_ENABLE:
|
||||||
|
err = mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_SMT,
|
||||||
|
MTK_DISABLE);
|
||||||
|
if (err)
|
||||||
|
goto err;
|
||||||
|
/* else: fall through */
|
||||||
|
case PIN_CONFIG_INPUT_ENABLE:
|
||||||
|
case PIN_CONFIG_SLEW_RATE:
|
||||||
|
reg = (param == PIN_CONFIG_SLEW_RATE) ?
|
||||||
|
PINCTRL_PIN_REG_SR : PINCTRL_PIN_REG_DIR;
|
||||||
|
|
||||||
|
arg = (param == PIN_CONFIG_INPUT_ENABLE) ? 0 :
|
||||||
|
(param == PIN_CONFIG_OUTPUT_ENABLE) ? 1 : arg;
|
||||||
|
err = mtk_hw_set_value(hw, pin, reg, arg);
|
||||||
|
if (err)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case PIN_CONFIG_OUTPUT:
|
||||||
|
err = mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_DIR,
|
||||||
|
MTK_OUTPUT);
|
||||||
|
if (err)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
err = mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_DO,
|
||||||
|
arg);
|
||||||
|
if (err)
|
||||||
|
goto err;
|
||||||
|
break;
|
||||||
|
case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
|
||||||
|
/* arg = 1: Input mode & SMT enable ;
|
||||||
|
* arg = 0: Output mode & SMT disable
|
||||||
|
*/
|
||||||
|
arg = arg ? 2 : 1;
|
||||||
|
err = mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_DIR,
|
||||||
|
arg & 1);
|
||||||
|
if (err)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
err = mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_SMT,
|
||||||
|
!!(arg & 2));
|
||||||
|
if (err)
|
||||||
|
goto err;
|
||||||
|
break;
|
||||||
|
case PIN_CONFIG_DRIVE_STRENGTH:
|
||||||
|
/* 4mA when (e8, e4) = (0, 0);
|
||||||
|
* 8mA when (e8, e4) = (0, 1);
|
||||||
|
* 12mA when (e8, e4) = (1, 0);
|
||||||
|
* 16mA when (e8, e4) = (1, 1)
|
||||||
|
*/
|
||||||
|
if (!(arg % 4) && (arg >= 4 && arg <= 16)) {
|
||||||
|
arg = arg / 4 - 1;
|
||||||
|
err = mtk_hw_set_value(hw, pin,
|
||||||
|
PINCTRL_PIN_REG_E4,
|
||||||
|
arg & 0x1);
|
||||||
|
if (err)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
err = mtk_hw_set_value(hw, pin,
|
||||||
|
PINCTRL_PIN_REG_E8,
|
||||||
|
(arg & 0x2) >> 1);
|
||||||
|
if (err)
|
||||||
|
goto err;
|
||||||
|
} else {
|
||||||
|
err = -ENOTSUPP;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MTK_PIN_CONFIG_TDSEL:
|
||||||
|
case MTK_PIN_CONFIG_RDSEL:
|
||||||
|
reg = (param == MTK_PIN_CONFIG_TDSEL) ?
|
||||||
|
PINCTRL_PIN_REG_TDSEL : PINCTRL_PIN_REG_RDSEL;
|
||||||
|
|
||||||
|
err = mtk_hw_set_value(hw, pin, reg, arg);
|
||||||
|
if (err)
|
||||||
|
goto err;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
err = -ENOTSUPP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err:
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mtk_pinconf_group_get(struct pinctrl_dev *pctldev,
|
||||||
|
unsigned int group, unsigned long *config)
|
||||||
|
{
|
||||||
|
const unsigned int *pins;
|
||||||
|
unsigned int i, npins, old = 0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = pinctrl_generic_get_group_pins(pctldev, group, &pins, &npins);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
for (i = 0; i < npins; i++) {
|
||||||
|
if (mtk_pinconf_get(pctldev, pins[i], config))
|
||||||
|
return -ENOTSUPP;
|
||||||
|
|
||||||
|
/* configs do not match between two pins */
|
||||||
|
if (i && old != *config)
|
||||||
|
return -ENOTSUPP;
|
||||||
|
|
||||||
|
old = *config;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mtk_pinconf_group_set(struct pinctrl_dev *pctldev,
|
||||||
|
unsigned int group, unsigned long *configs,
|
||||||
|
unsigned int num_configs)
|
||||||
|
{
|
||||||
|
const unsigned int *pins;
|
||||||
|
unsigned int i, npins;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = pinctrl_generic_get_group_pins(pctldev, group, &pins, &npins);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
for (i = 0; i < npins; i++) {
|
||||||
|
ret = mtk_pinconf_set(pctldev, pins[i], configs, num_configs);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct pinctrl_ops mtk_pctlops = {
|
||||||
|
.get_groups_count = pinctrl_generic_get_group_count,
|
||||||
|
.get_group_name = pinctrl_generic_get_group_name,
|
||||||
|
.get_group_pins = pinctrl_generic_get_group_pins,
|
||||||
|
.dt_node_to_map = pinconf_generic_dt_node_to_map_all,
|
||||||
|
.dt_free_map = pinconf_generic_dt_free_map,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct pinmux_ops mtk_pmxops = {
|
||||||
|
.get_functions_count = pinmux_generic_get_function_count,
|
||||||
|
.get_function_name = pinmux_generic_get_function_name,
|
||||||
|
.get_function_groups = pinmux_generic_get_function_groups,
|
||||||
|
.set_mux = mtk_pinmux_set_mux,
|
||||||
|
.gpio_request_enable = mtk_pinmux_gpio_request_enable,
|
||||||
|
.gpio_set_direction = mtk_pinmux_gpio_set_direction,
|
||||||
|
.strict = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct pinconf_ops mtk_confops = {
|
||||||
|
.is_generic = true,
|
||||||
|
.pin_config_get = mtk_pinconf_get,
|
||||||
|
.pin_config_set = mtk_pinconf_set,
|
||||||
|
.pin_config_group_get = mtk_pinconf_group_get,
|
||||||
|
.pin_config_group_set = mtk_pinconf_group_set,
|
||||||
|
.pin_config_config_dbg_show = pinconf_generic_dump_config,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct pinctrl_desc mtk_desc = {
|
||||||
|
.name = PINCTRL_PINCTRL_DEV,
|
||||||
|
.pctlops = &mtk_pctlops,
|
||||||
|
.pmxops = &mtk_pmxops,
|
||||||
|
.confops = &mtk_confops,
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int mtk_gpio_get(struct gpio_chip *chip, unsigned int gpio)
|
||||||
|
{
|
||||||
|
struct mtk_pinctrl *hw = gpiochip_get_data(chip);
|
||||||
|
int value, err;
|
||||||
|
|
||||||
|
err = mtk_hw_get_value(hw, gpio, PINCTRL_PIN_REG_DI, &value);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
return !!value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mtk_gpio_set(struct gpio_chip *chip, unsigned int gpio, int value)
|
||||||
|
{
|
||||||
|
struct mtk_pinctrl *hw = gpiochip_get_data(chip);
|
||||||
|
|
||||||
|
mtk_hw_set_value(hw, gpio, PINCTRL_PIN_REG_DO, !!value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mtk_gpio_direction_input(struct gpio_chip *chip, unsigned int gpio)
|
||||||
|
{
|
||||||
|
return pinctrl_gpio_direction_input(chip->base + gpio);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mtk_gpio_direction_output(struct gpio_chip *chip, unsigned int gpio,
|
||||||
|
int value)
|
||||||
|
{
|
||||||
|
mtk_gpio_set(chip, gpio, value);
|
||||||
|
|
||||||
|
return pinctrl_gpio_direction_output(chip->base + gpio);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mtk_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
|
||||||
|
{
|
||||||
|
struct mtk_pinctrl *hw = gpiochip_get_data(chip);
|
||||||
|
unsigned long eint_n;
|
||||||
|
|
||||||
|
if (!hw->eint)
|
||||||
|
return -ENOTSUPP;
|
||||||
|
|
||||||
|
eint_n = offset;
|
||||||
|
|
||||||
|
return mtk_eint_find_irq(hw->eint, eint_n);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mtk_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
|
||||||
|
unsigned long config)
|
||||||
|
{
|
||||||
|
struct mtk_pinctrl *hw = gpiochip_get_data(chip);
|
||||||
|
unsigned long eint_n;
|
||||||
|
u32 debounce;
|
||||||
|
|
||||||
|
if (!hw->eint ||
|
||||||
|
pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
|
||||||
|
return -ENOTSUPP;
|
||||||
|
|
||||||
|
debounce = pinconf_to_config_argument(config);
|
||||||
|
eint_n = offset;
|
||||||
|
|
||||||
|
return mtk_eint_set_debounce(hw->eint, eint_n, debounce);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mtk_build_gpiochip(struct mtk_pinctrl *hw, struct device_node *np)
|
||||||
|
{
|
||||||
|
struct gpio_chip *chip = &hw->chip;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
chip->label = PINCTRL_PINCTRL_DEV;
|
||||||
|
chip->parent = hw->dev;
|
||||||
|
chip->request = gpiochip_generic_request;
|
||||||
|
chip->free = gpiochip_generic_free;
|
||||||
|
chip->direction_input = mtk_gpio_direction_input;
|
||||||
|
chip->direction_output = mtk_gpio_direction_output;
|
||||||
|
chip->get = mtk_gpio_get;
|
||||||
|
chip->set = mtk_gpio_set;
|
||||||
|
chip->to_irq = mtk_gpio_to_irq,
|
||||||
|
chip->set_config = mtk_gpio_set_config,
|
||||||
|
chip->base = -1;
|
||||||
|
chip->ngpio = hw->soc->npins;
|
||||||
|
chip->of_node = np;
|
||||||
|
chip->of_gpio_n_cells = 2;
|
||||||
|
|
||||||
|
ret = gpiochip_add_data(chip, hw);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* Just for backward compatible for these old pinctrl nodes without
|
||||||
|
* "gpio-ranges" property. Otherwise, called directly from a
|
||||||
|
* DeviceTree-supported pinctrl driver is DEPRECATED.
|
||||||
|
* Please see Section 2.1 of
|
||||||
|
* Documentation/devicetree/bindings/gpio/gpio.txt on how to
|
||||||
|
* bind pinctrl and gpio drivers via the "gpio-ranges" property.
|
||||||
|
*/
|
||||||
|
if (!of_find_property(np, "gpio-ranges", NULL)) {
|
||||||
|
ret = gpiochip_add_pin_range(chip, dev_name(hw->dev), 0, 0,
|
||||||
|
chip->ngpio);
|
||||||
|
if (ret < 0) {
|
||||||
|
gpiochip_remove(chip);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mtk_build_groups(struct mtk_pinctrl *hw)
|
||||||
|
{
|
||||||
|
int err, i;
|
||||||
|
|
||||||
|
for (i = 0; i < hw->soc->ngrps; i++) {
|
||||||
|
const struct group_desc *group = hw->soc->grps + i;
|
||||||
|
|
||||||
|
err = pinctrl_generic_add_group(hw->pctrl, group->name,
|
||||||
|
group->pins, group->num_pins,
|
||||||
|
group->data);
|
||||||
|
if (err < 0) {
|
||||||
|
dev_err(hw->dev, "Failed to register group %s\n",
|
||||||
|
group->name);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mtk_build_functions(struct mtk_pinctrl *hw)
|
||||||
|
{
|
||||||
|
int i, err;
|
||||||
|
|
||||||
|
for (i = 0; i < hw->soc->nfuncs ; i++) {
|
||||||
|
const struct function_desc *func = hw->soc->funcs + i;
|
||||||
|
|
||||||
|
err = pinmux_generic_add_function(hw->pctrl, func->name,
|
||||||
|
func->group_names,
|
||||||
|
func->num_group_names,
|
||||||
|
func->data);
|
||||||
|
if (err < 0) {
|
||||||
|
dev_err(hw->dev, "Failed to register function %s\n",
|
||||||
|
func->name);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mtk_xt_get_gpio_n(void *data, unsigned long eint_n,
|
||||||
|
unsigned int *gpio_n,
|
||||||
|
struct gpio_chip **gpio_chip)
|
||||||
|
{
|
||||||
|
struct mtk_pinctrl *hw = (struct mtk_pinctrl *)data;
|
||||||
|
|
||||||
|
*gpio_chip = &hw->chip;
|
||||||
|
*gpio_n = eint_n;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mtk_xt_get_gpio_state(void *data, unsigned long eint_n)
|
||||||
|
{
|
||||||
|
struct mtk_pinctrl *hw = (struct mtk_pinctrl *)data;
|
||||||
|
struct gpio_chip *gpio_chip;
|
||||||
|
unsigned int gpio_n;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = mtk_xt_get_gpio_n(hw, eint_n, &gpio_n, &gpio_chip);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
return mtk_gpio_get(gpio_chip, gpio_n);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mtk_xt_set_gpio_as_eint(void *data, unsigned long eint_n)
|
||||||
|
{
|
||||||
|
struct mtk_pinctrl *hw = (struct mtk_pinctrl *)data;
|
||||||
|
struct gpio_chip *gpio_chip;
|
||||||
|
unsigned int gpio_n;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = mtk_xt_get_gpio_n(hw, eint_n, &gpio_n, &gpio_chip);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
err = mtk_hw_set_value(hw, gpio_n, PINCTRL_PIN_REG_MODE,
|
||||||
|
MTK_GPIO_MODE);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
err = mtk_hw_set_value(hw, gpio_n, PINCTRL_PIN_REG_DIR, MTK_INPUT);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
err = mtk_hw_set_value(hw, gpio_n, PINCTRL_PIN_REG_SMT, MTK_ENABLE);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct mtk_eint_xt mtk_eint_xt = {
|
||||||
|
.get_gpio_n = mtk_xt_get_gpio_n,
|
||||||
|
.get_gpio_state = mtk_xt_get_gpio_state,
|
||||||
|
.set_gpio_as_eint = mtk_xt_set_gpio_as_eint,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
mtk_build_eint(struct mtk_pinctrl *hw, struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct device_node *np = pdev->dev.of_node;
|
||||||
|
struct resource *res;
|
||||||
|
|
||||||
|
if (!IS_ENABLED(CONFIG_EINT_MTK))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!of_property_read_bool(np, "interrupt-controller"))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
hw->eint = devm_kzalloc(hw->dev, sizeof(*hw->eint), GFP_KERNEL);
|
||||||
|
if (!hw->eint)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "eint");
|
||||||
|
if (!res) {
|
||||||
|
dev_err(&pdev->dev, "Unable to get eint resource\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
hw->eint->base = devm_ioremap_resource(&pdev->dev, res);
|
||||||
|
if (IS_ERR(hw->eint->base))
|
||||||
|
return PTR_ERR(hw->eint->base);
|
||||||
|
|
||||||
|
hw->eint->irq = irq_of_parse_and_map(np, 0);
|
||||||
|
if (!hw->eint->irq)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
hw->eint->dev = &pdev->dev;
|
||||||
|
hw->eint->hw = hw->soc->eint_hw;
|
||||||
|
hw->eint->pctl = hw;
|
||||||
|
hw->eint->gpio_xlate = &mtk_eint_xt;
|
||||||
|
|
||||||
|
return mtk_eint_do_init(hw->eint);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mtk_moore_pinctrl_probe(struct platform_device *pdev,
|
||||||
|
const struct mtk_pin_soc *soc)
|
||||||
|
{
|
||||||
|
struct resource *res;
|
||||||
|
struct mtk_pinctrl *hw;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
hw = devm_kzalloc(&pdev->dev, sizeof(*hw), GFP_KERNEL);
|
||||||
|
if (!hw)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
hw->soc = soc;
|
||||||
|
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
if (!res) {
|
||||||
|
dev_err(&pdev->dev, "missing IO resource\n");
|
||||||
|
return -ENXIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
hw->dev = &pdev->dev;
|
||||||
|
hw->base = devm_ioremap_resource(&pdev->dev, res);
|
||||||
|
if (IS_ERR(hw->base))
|
||||||
|
return PTR_ERR(hw->base);
|
||||||
|
|
||||||
|
/* Setup pins descriptions per SoC types */
|
||||||
|
mtk_desc.pins = hw->soc->pins;
|
||||||
|
mtk_desc.npins = hw->soc->npins;
|
||||||
|
mtk_desc.num_custom_params = ARRAY_SIZE(mtk_custom_bindings);
|
||||||
|
mtk_desc.custom_params = mtk_custom_bindings;
|
||||||
|
#ifdef CONFIG_DEBUG_FS
|
||||||
|
mtk_desc.custom_conf_items = mtk_conf_items;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
err = devm_pinctrl_register_and_init(&pdev->dev, &mtk_desc, hw,
|
||||||
|
&hw->pctrl);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
/* Setup groups descriptions per SoC types */
|
||||||
|
err = mtk_build_groups(hw);
|
||||||
|
if (err) {
|
||||||
|
dev_err(&pdev->dev, "Failed to build groups\n");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Setup functions descriptions per SoC types */
|
||||||
|
err = mtk_build_functions(hw);
|
||||||
|
if (err) {
|
||||||
|
dev_err(&pdev->dev, "Failed to build functions\n");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For able to make pinctrl_claim_hogs, we must not enable pinctrl
|
||||||
|
* until all groups and functions are being added one.
|
||||||
|
*/
|
||||||
|
err = pinctrl_enable(hw->pctrl);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
err = mtk_build_eint(hw, pdev);
|
||||||
|
if (err)
|
||||||
|
dev_warn(&pdev->dev,
|
||||||
|
"Failed to add EINT, but pinctrl still can work\n");
|
||||||
|
|
||||||
|
/* Build gpiochip should be after pinctrl_enable is done */
|
||||||
|
err = mtk_build_gpiochip(hw, pdev->dev.of_node);
|
||||||
|
if (err) {
|
||||||
|
dev_err(&pdev->dev, "Failed to add gpio_chip\n");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
platform_set_drvdata(pdev, hw);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
41
drivers/pinctrl/mediatek/pinctrl-moore.h
Normal file
41
drivers/pinctrl/mediatek/pinctrl-moore.h
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2017-2018 MediaTek Inc.
|
||||||
|
*
|
||||||
|
* Author: Sean Wang <sean.wang@mediatek.com>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef __PINCTRL_MOORE_H
|
||||||
|
#define __PINCTRL_MOORE_H
|
||||||
|
|
||||||
|
#include <linux/gpio.h>
|
||||||
|
#include <linux/gpio/driver.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_platform.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/pinctrl/pinctrl.h>
|
||||||
|
#include <linux/pinctrl/pinmux.h>
|
||||||
|
#include <linux/pinctrl/pinconf.h>
|
||||||
|
#include <linux/pinctrl/pinconf-generic.h>
|
||||||
|
|
||||||
|
#include "../core.h"
|
||||||
|
#include "../pinconf.h"
|
||||||
|
#include "../pinmux.h"
|
||||||
|
#include "mtk-eint.h"
|
||||||
|
#include "pinctrl-mtk-common-v2.h"
|
||||||
|
|
||||||
|
#define MTK_RANGE(_a) { .range = (_a), .nranges = ARRAY_SIZE(_a), }
|
||||||
|
#define PINCTRL_PIN_GROUP(name, id) \
|
||||||
|
{ \
|
||||||
|
name, \
|
||||||
|
id##_pins, \
|
||||||
|
ARRAY_SIZE(id##_pins), \
|
||||||
|
id##_funcs, \
|
||||||
|
}
|
||||||
|
|
||||||
|
int mtk_moore_pinctrl_probe(struct platform_device *pdev,
|
||||||
|
const struct mtk_pin_soc *soc);
|
||||||
|
|
||||||
|
#endif /* __PINCTRL_MOORE_H */
|
@@ -6,40 +6,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/gpio.h>
|
#include "pinctrl-moore.h"
|
||||||
#include <linux/gpio/driver.h>
|
|
||||||
#include <linux/io.h>
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/mfd/syscon.h>
|
|
||||||
#include <linux/of.h>
|
|
||||||
#include <linux/of_irq.h>
|
|
||||||
#include <linux/of_platform.h>
|
|
||||||
#include <linux/platform_device.h>
|
|
||||||
#include <linux/pinctrl/pinctrl.h>
|
|
||||||
#include <linux/pinctrl/pinmux.h>
|
|
||||||
#include <linux/pinctrl/pinconf.h>
|
|
||||||
#include <linux/pinctrl/pinconf-generic.h>
|
|
||||||
#include <linux/regmap.h>
|
|
||||||
|
|
||||||
#include "../core.h"
|
|
||||||
#include "../pinconf.h"
|
|
||||||
#include "../pinmux.h"
|
|
||||||
#include "mtk-eint.h"
|
|
||||||
#include "pinctrl-mtk-common-v2.h"
|
|
||||||
|
|
||||||
#define PINCTRL_PINCTRL_DEV KBUILD_MODNAME
|
|
||||||
#define MTK_RANGE(_a) { .range = (_a), .nranges = ARRAY_SIZE(_a), }
|
|
||||||
#define PINCTRL_PIN_GROUP(name, id) \
|
|
||||||
{ \
|
|
||||||
name, \
|
|
||||||
id##_pins, \
|
|
||||||
ARRAY_SIZE(id##_pins), \
|
|
||||||
id##_funcs, \
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Custom pinconf parameters */
|
|
||||||
#define MTK_PIN_CONFIG_TDSEL (PIN_CONFIG_END + 1)
|
|
||||||
#define MTK_PIN_CONFIG_RDSEL (PIN_CONFIG_END + 2)
|
|
||||||
|
|
||||||
static const struct mtk_pin_field_calc mt7622_pin_mode_range[] = {
|
static const struct mtk_pin_field_calc mt7622_pin_mode_range[] = {
|
||||||
{0, 0, 0x320, 0x10, 16, 4},
|
{0, 0, 0x320, 0x10, 16, 4},
|
||||||
@@ -809,18 +776,6 @@ static const struct function_desc mt7622_functions[] = {
|
|||||||
{"watchdog", mt7622_wdt_groups, ARRAY_SIZE(mt7622_wdt_groups)},
|
{"watchdog", mt7622_wdt_groups, ARRAY_SIZE(mt7622_wdt_groups)},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct pinconf_generic_params mtk_custom_bindings[] = {
|
|
||||||
{"mediatek,tdsel", MTK_PIN_CONFIG_TDSEL, 0},
|
|
||||||
{"mediatek,rdsel", MTK_PIN_CONFIG_RDSEL, 0},
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_FS
|
|
||||||
static const struct pin_config_item mtk_conf_items[] = {
|
|
||||||
PCONFDUMP(MTK_PIN_CONFIG_TDSEL, "tdsel", NULL, true),
|
|
||||||
PCONFDUMP(MTK_PIN_CONFIG_RDSEL, "rdsel", NULL, true),
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static const struct mtk_eint_hw mt7622_eint_hw = {
|
static const struct mtk_eint_hw mt7622_eint_hw = {
|
||||||
.port_mask = 7,
|
.port_mask = 7,
|
||||||
.ports = 7,
|
.ports = 7,
|
||||||
@@ -839,680 +794,26 @@ static const struct mtk_pin_soc mt7622_data = {
|
|||||||
.eint_hw = &mt7622_eint_hw,
|
.eint_hw = &mt7622_eint_hw,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int mtk_pinmux_set_mux(struct pinctrl_dev *pctldev,
|
static const struct of_device_id mt7622_pinctrl_of_match[] = {
|
||||||
unsigned int selector, unsigned int group)
|
{ .compatible = "mediatek,mt7622-pinctrl", },
|
||||||
{
|
|
||||||
struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev);
|
|
||||||
struct function_desc *func;
|
|
||||||
struct group_desc *grp;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
func = pinmux_generic_get_function(pctldev, selector);
|
|
||||||
if (!func)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
grp = pinctrl_generic_get_group(pctldev, group);
|
|
||||||
if (!grp)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
dev_dbg(pctldev->dev, "enable function %s group %s\n",
|
|
||||||
func->name, grp->name);
|
|
||||||
|
|
||||||
for (i = 0; i < grp->num_pins; i++) {
|
|
||||||
int *pin_modes = grp->data;
|
|
||||||
|
|
||||||
mtk_hw_set_value(hw, grp->pins[i], PINCTRL_PIN_REG_MODE,
|
|
||||||
pin_modes[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mtk_pinmux_gpio_request_enable(struct pinctrl_dev *pctldev,
|
|
||||||
struct pinctrl_gpio_range *range,
|
|
||||||
unsigned int pin)
|
|
||||||
{
|
|
||||||
struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev);
|
|
||||||
|
|
||||||
return mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_MODE, MTK_GPIO_MODE);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mtk_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev,
|
|
||||||
struct pinctrl_gpio_range *range,
|
|
||||||
unsigned int pin, bool input)
|
|
||||||
{
|
|
||||||
struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev);
|
|
||||||
|
|
||||||
/* hardware would take 0 as input direction */
|
|
||||||
return mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_DIR, !input);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mtk_pinconf_get(struct pinctrl_dev *pctldev,
|
|
||||||
unsigned int pin, unsigned long *config)
|
|
||||||
{
|
|
||||||
struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev);
|
|
||||||
u32 param = pinconf_to_config_param(*config);
|
|
||||||
int val, val2, err, reg, ret = 1;
|
|
||||||
|
|
||||||
switch (param) {
|
|
||||||
case PIN_CONFIG_BIAS_DISABLE:
|
|
||||||
err = mtk_hw_get_value(hw, pin, PINCTRL_PIN_REG_PU, &val);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
err = mtk_hw_get_value(hw, pin, PINCTRL_PIN_REG_PD, &val2);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
if (val || val2)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
break;
|
|
||||||
case PIN_CONFIG_BIAS_PULL_UP:
|
|
||||||
case PIN_CONFIG_BIAS_PULL_DOWN:
|
|
||||||
case PIN_CONFIG_SLEW_RATE:
|
|
||||||
reg = (param == PIN_CONFIG_BIAS_PULL_UP) ?
|
|
||||||
PINCTRL_PIN_REG_PU :
|
|
||||||
(param == PIN_CONFIG_BIAS_PULL_DOWN) ?
|
|
||||||
PINCTRL_PIN_REG_PD : PINCTRL_PIN_REG_SR;
|
|
||||||
|
|
||||||
err = mtk_hw_get_value(hw, pin, reg, &val);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
if (!val)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
break;
|
|
||||||
case PIN_CONFIG_INPUT_ENABLE:
|
|
||||||
case PIN_CONFIG_OUTPUT_ENABLE:
|
|
||||||
err = mtk_hw_get_value(hw, pin, PINCTRL_PIN_REG_DIR, &val);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
/* HW takes input mode as zero; output mode as non-zero */
|
|
||||||
if ((val && param == PIN_CONFIG_INPUT_ENABLE) ||
|
|
||||||
(!val && param == PIN_CONFIG_OUTPUT_ENABLE))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
break;
|
|
||||||
case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
|
|
||||||
err = mtk_hw_get_value(hw, pin, PINCTRL_PIN_REG_DIR, &val);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
err = mtk_hw_get_value(hw, pin, PINCTRL_PIN_REG_SMT, &val2);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
if (val || !val2)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
break;
|
|
||||||
case PIN_CONFIG_DRIVE_STRENGTH:
|
|
||||||
err = mtk_hw_get_value(hw, pin, PINCTRL_PIN_REG_E4, &val);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
err = mtk_hw_get_value(hw, pin, PINCTRL_PIN_REG_E8, &val2);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
/* 4mA when (e8, e4) = (0, 0); 8mA when (e8, e4) = (0, 1)
|
|
||||||
* 12mA when (e8, e4) = (1, 0); 16mA when (e8, e4) = (1, 1)
|
|
||||||
*/
|
|
||||||
ret = ((val2 << 1) + val + 1) * 4;
|
|
||||||
|
|
||||||
break;
|
|
||||||
case MTK_PIN_CONFIG_TDSEL:
|
|
||||||
case MTK_PIN_CONFIG_RDSEL:
|
|
||||||
reg = (param == MTK_PIN_CONFIG_TDSEL) ?
|
|
||||||
PINCTRL_PIN_REG_TDSEL : PINCTRL_PIN_REG_RDSEL;
|
|
||||||
|
|
||||||
err = mtk_hw_get_value(hw, pin, reg, &val);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
ret = val;
|
|
||||||
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return -ENOTSUPP;
|
|
||||||
}
|
|
||||||
|
|
||||||
*config = pinconf_to_config_packed(param, ret);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mtk_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
|
|
||||||
unsigned long *configs, unsigned int num_configs)
|
|
||||||
{
|
|
||||||
struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev);
|
|
||||||
u32 reg, param, arg;
|
|
||||||
int cfg, err = 0;
|
|
||||||
|
|
||||||
for (cfg = 0; cfg < num_configs; cfg++) {
|
|
||||||
param = pinconf_to_config_param(configs[cfg]);
|
|
||||||
arg = pinconf_to_config_argument(configs[cfg]);
|
|
||||||
|
|
||||||
switch (param) {
|
|
||||||
case PIN_CONFIG_BIAS_DISABLE:
|
|
||||||
case PIN_CONFIG_BIAS_PULL_UP:
|
|
||||||
case PIN_CONFIG_BIAS_PULL_DOWN:
|
|
||||||
arg = (param == PIN_CONFIG_BIAS_DISABLE) ? 0 :
|
|
||||||
(param == PIN_CONFIG_BIAS_PULL_UP) ? 1 : 2;
|
|
||||||
|
|
||||||
err = mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_PU,
|
|
||||||
arg & 1);
|
|
||||||
if (err)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
err = mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_PD,
|
|
||||||
!!(arg & 2));
|
|
||||||
if (err)
|
|
||||||
goto err;
|
|
||||||
break;
|
|
||||||
case PIN_CONFIG_OUTPUT_ENABLE:
|
|
||||||
err = mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_SMT,
|
|
||||||
MTK_DISABLE);
|
|
||||||
if (err)
|
|
||||||
goto err;
|
|
||||||
/* else: fall through */
|
|
||||||
case PIN_CONFIG_INPUT_ENABLE:
|
|
||||||
case PIN_CONFIG_SLEW_RATE:
|
|
||||||
reg = (param == PIN_CONFIG_SLEW_RATE) ?
|
|
||||||
PINCTRL_PIN_REG_SR : PINCTRL_PIN_REG_DIR;
|
|
||||||
|
|
||||||
arg = (param == PIN_CONFIG_INPUT_ENABLE) ? 0 :
|
|
||||||
(param == PIN_CONFIG_OUTPUT_ENABLE) ? 1 : arg;
|
|
||||||
err = mtk_hw_set_value(hw, pin, reg, arg);
|
|
||||||
if (err)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
break;
|
|
||||||
case PIN_CONFIG_OUTPUT:
|
|
||||||
err = mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_DIR,
|
|
||||||
MTK_OUTPUT);
|
|
||||||
if (err)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
err = mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_DO,
|
|
||||||
arg);
|
|
||||||
if (err)
|
|
||||||
goto err;
|
|
||||||
break;
|
|
||||||
case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
|
|
||||||
/* arg = 1: Input mode & SMT enable ;
|
|
||||||
* arg = 0: Output mode & SMT disable
|
|
||||||
*/
|
|
||||||
arg = arg ? 2 : 1;
|
|
||||||
err = mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_DIR,
|
|
||||||
arg & 1);
|
|
||||||
if (err)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
err = mtk_hw_set_value(hw, pin, PINCTRL_PIN_REG_SMT,
|
|
||||||
!!(arg & 2));
|
|
||||||
if (err)
|
|
||||||
goto err;
|
|
||||||
break;
|
|
||||||
case PIN_CONFIG_DRIVE_STRENGTH:
|
|
||||||
/* 4mA when (e8, e4) = (0, 0);
|
|
||||||
* 8mA when (e8, e4) = (0, 1);
|
|
||||||
* 12mA when (e8, e4) = (1, 0);
|
|
||||||
* 16mA when (e8, e4) = (1, 1)
|
|
||||||
*/
|
|
||||||
if (!(arg % 4) && (arg >= 4 && arg <= 16)) {
|
|
||||||
arg = arg / 4 - 1;
|
|
||||||
err = mtk_hw_set_value(hw, pin,
|
|
||||||
PINCTRL_PIN_REG_E4,
|
|
||||||
arg & 0x1);
|
|
||||||
if (err)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
err = mtk_hw_set_value(hw, pin,
|
|
||||||
PINCTRL_PIN_REG_E8,
|
|
||||||
(arg & 0x2) >> 1);
|
|
||||||
if (err)
|
|
||||||
goto err;
|
|
||||||
} else {
|
|
||||||
err = -ENOTSUPP;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case MTK_PIN_CONFIG_TDSEL:
|
|
||||||
case MTK_PIN_CONFIG_RDSEL:
|
|
||||||
reg = (param == MTK_PIN_CONFIG_TDSEL) ?
|
|
||||||
PINCTRL_PIN_REG_TDSEL : PINCTRL_PIN_REG_RDSEL;
|
|
||||||
|
|
||||||
err = mtk_hw_set_value(hw, pin, reg, arg);
|
|
||||||
if (err)
|
|
||||||
goto err;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
err = -ENOTSUPP;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
err:
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mtk_pinconf_group_get(struct pinctrl_dev *pctldev,
|
|
||||||
unsigned int group, unsigned long *config)
|
|
||||||
{
|
|
||||||
const unsigned int *pins;
|
|
||||||
unsigned int i, npins, old = 0;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = pinctrl_generic_get_group_pins(pctldev, group, &pins, &npins);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
for (i = 0; i < npins; i++) {
|
|
||||||
if (mtk_pinconf_get(pctldev, pins[i], config))
|
|
||||||
return -ENOTSUPP;
|
|
||||||
|
|
||||||
/* configs do not match between two pins */
|
|
||||||
if (i && old != *config)
|
|
||||||
return -ENOTSUPP;
|
|
||||||
|
|
||||||
old = *config;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mtk_pinconf_group_set(struct pinctrl_dev *pctldev,
|
|
||||||
unsigned int group, unsigned long *configs,
|
|
||||||
unsigned int num_configs)
|
|
||||||
{
|
|
||||||
const unsigned int *pins;
|
|
||||||
unsigned int i, npins;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = pinctrl_generic_get_group_pins(pctldev, group, &pins, &npins);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
for (i = 0; i < npins; i++) {
|
|
||||||
ret = mtk_pinconf_set(pctldev, pins[i], configs, num_configs);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct pinctrl_ops mtk_pctlops = {
|
|
||||||
.get_groups_count = pinctrl_generic_get_group_count,
|
|
||||||
.get_group_name = pinctrl_generic_get_group_name,
|
|
||||||
.get_group_pins = pinctrl_generic_get_group_pins,
|
|
||||||
.dt_node_to_map = pinconf_generic_dt_node_to_map_all,
|
|
||||||
.dt_free_map = pinconf_generic_dt_free_map,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct pinmux_ops mtk_pmxops = {
|
|
||||||
.get_functions_count = pinmux_generic_get_function_count,
|
|
||||||
.get_function_name = pinmux_generic_get_function_name,
|
|
||||||
.get_function_groups = pinmux_generic_get_function_groups,
|
|
||||||
.set_mux = mtk_pinmux_set_mux,
|
|
||||||
.gpio_request_enable = mtk_pinmux_gpio_request_enable,
|
|
||||||
.gpio_set_direction = mtk_pinmux_gpio_set_direction,
|
|
||||||
.strict = true,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct pinconf_ops mtk_confops = {
|
|
||||||
.is_generic = true,
|
|
||||||
.pin_config_get = mtk_pinconf_get,
|
|
||||||
.pin_config_set = mtk_pinconf_set,
|
|
||||||
.pin_config_group_get = mtk_pinconf_group_get,
|
|
||||||
.pin_config_group_set = mtk_pinconf_group_set,
|
|
||||||
.pin_config_config_dbg_show = pinconf_generic_dump_config,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct pinctrl_desc mtk_desc = {
|
|
||||||
.name = PINCTRL_PINCTRL_DEV,
|
|
||||||
.pctlops = &mtk_pctlops,
|
|
||||||
.pmxops = &mtk_pmxops,
|
|
||||||
.confops = &mtk_confops,
|
|
||||||
.owner = THIS_MODULE,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int mtk_gpio_get(struct gpio_chip *chip, unsigned int gpio)
|
|
||||||
{
|
|
||||||
struct mtk_pinctrl *hw = gpiochip_get_data(chip);
|
|
||||||
int value, err;
|
|
||||||
|
|
||||||
err = mtk_hw_get_value(hw, gpio, PINCTRL_PIN_REG_DI, &value);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
return !!value;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mtk_gpio_set(struct gpio_chip *chip, unsigned int gpio, int value)
|
|
||||||
{
|
|
||||||
struct mtk_pinctrl *hw = gpiochip_get_data(chip);
|
|
||||||
|
|
||||||
mtk_hw_set_value(hw, gpio, PINCTRL_PIN_REG_DO, !!value);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mtk_gpio_direction_input(struct gpio_chip *chip, unsigned int gpio)
|
|
||||||
{
|
|
||||||
return pinctrl_gpio_direction_input(chip->base + gpio);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mtk_gpio_direction_output(struct gpio_chip *chip, unsigned int gpio,
|
|
||||||
int value)
|
|
||||||
{
|
|
||||||
mtk_gpio_set(chip, gpio, value);
|
|
||||||
|
|
||||||
return pinctrl_gpio_direction_output(chip->base + gpio);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mtk_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
|
|
||||||
{
|
|
||||||
struct mtk_pinctrl *hw = gpiochip_get_data(chip);
|
|
||||||
unsigned long eint_n;
|
|
||||||
|
|
||||||
if (!hw->eint)
|
|
||||||
return -ENOTSUPP;
|
|
||||||
|
|
||||||
eint_n = offset;
|
|
||||||
|
|
||||||
return mtk_eint_find_irq(hw->eint, eint_n);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mtk_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
|
|
||||||
unsigned long config)
|
|
||||||
{
|
|
||||||
struct mtk_pinctrl *hw = gpiochip_get_data(chip);
|
|
||||||
unsigned long eint_n;
|
|
||||||
u32 debounce;
|
|
||||||
|
|
||||||
if (!hw->eint ||
|
|
||||||
pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
|
|
||||||
return -ENOTSUPP;
|
|
||||||
|
|
||||||
debounce = pinconf_to_config_argument(config);
|
|
||||||
eint_n = offset;
|
|
||||||
|
|
||||||
return mtk_eint_set_debounce(hw->eint, eint_n, debounce);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mtk_build_gpiochip(struct mtk_pinctrl *hw, struct device_node *np)
|
|
||||||
{
|
|
||||||
struct gpio_chip *chip = &hw->chip;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
chip->label = PINCTRL_PINCTRL_DEV;
|
|
||||||
chip->parent = hw->dev;
|
|
||||||
chip->request = gpiochip_generic_request;
|
|
||||||
chip->free = gpiochip_generic_free;
|
|
||||||
chip->direction_input = mtk_gpio_direction_input;
|
|
||||||
chip->direction_output = mtk_gpio_direction_output;
|
|
||||||
chip->get = mtk_gpio_get;
|
|
||||||
chip->set = mtk_gpio_set;
|
|
||||||
chip->to_irq = mtk_gpio_to_irq,
|
|
||||||
chip->set_config = mtk_gpio_set_config,
|
|
||||||
chip->base = -1;
|
|
||||||
chip->ngpio = hw->soc->npins;
|
|
||||||
chip->of_node = np;
|
|
||||||
chip->of_gpio_n_cells = 2;
|
|
||||||
|
|
||||||
ret = gpiochip_add_data(chip, hw);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
/* Just for backward compatible for these old pinctrl nodes without
|
|
||||||
* "gpio-ranges" property. Otherwise, called directly from a
|
|
||||||
* DeviceTree-supported pinctrl driver is DEPRECATED.
|
|
||||||
* Please see Section 2.1 of
|
|
||||||
* Documentation/devicetree/bindings/gpio/gpio.txt on how to
|
|
||||||
* bind pinctrl and gpio drivers via the "gpio-ranges" property.
|
|
||||||
*/
|
|
||||||
if (!of_find_property(np, "gpio-ranges", NULL)) {
|
|
||||||
ret = gpiochip_add_pin_range(chip, dev_name(hw->dev), 0, 0,
|
|
||||||
chip->ngpio);
|
|
||||||
if (ret < 0) {
|
|
||||||
gpiochip_remove(chip);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mtk_build_groups(struct mtk_pinctrl *hw)
|
|
||||||
{
|
|
||||||
int err, i;
|
|
||||||
|
|
||||||
for (i = 0; i < hw->soc->ngrps; i++) {
|
|
||||||
const struct group_desc *group = hw->soc->grps + i;
|
|
||||||
|
|
||||||
err = pinctrl_generic_add_group(hw->pctrl, group->name,
|
|
||||||
group->pins, group->num_pins,
|
|
||||||
group->data);
|
|
||||||
if (err < 0) {
|
|
||||||
dev_err(hw->dev, "Failed to register group %s\n",
|
|
||||||
group->name);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mtk_build_functions(struct mtk_pinctrl *hw)
|
|
||||||
{
|
|
||||||
int i, err;
|
|
||||||
|
|
||||||
for (i = 0; i < hw->soc->nfuncs ; i++) {
|
|
||||||
const struct function_desc *func = hw->soc->funcs + i;
|
|
||||||
|
|
||||||
err = pinmux_generic_add_function(hw->pctrl, func->name,
|
|
||||||
func->group_names,
|
|
||||||
func->num_group_names,
|
|
||||||
func->data);
|
|
||||||
if (err < 0) {
|
|
||||||
dev_err(hw->dev, "Failed to register function %s\n",
|
|
||||||
func->name);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mtk_xt_get_gpio_n(void *data, unsigned long eint_n,
|
|
||||||
unsigned int *gpio_n,
|
|
||||||
struct gpio_chip **gpio_chip)
|
|
||||||
{
|
|
||||||
struct mtk_pinctrl *hw = (struct mtk_pinctrl *)data;
|
|
||||||
|
|
||||||
*gpio_chip = &hw->chip;
|
|
||||||
*gpio_n = eint_n;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mtk_xt_get_gpio_state(void *data, unsigned long eint_n)
|
|
||||||
{
|
|
||||||
struct mtk_pinctrl *hw = (struct mtk_pinctrl *)data;
|
|
||||||
struct gpio_chip *gpio_chip;
|
|
||||||
unsigned int gpio_n;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
err = mtk_xt_get_gpio_n(hw, eint_n, &gpio_n, &gpio_chip);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
return mtk_gpio_get(gpio_chip, gpio_n);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mtk_xt_set_gpio_as_eint(void *data, unsigned long eint_n)
|
|
||||||
{
|
|
||||||
struct mtk_pinctrl *hw = (struct mtk_pinctrl *)data;
|
|
||||||
struct gpio_chip *gpio_chip;
|
|
||||||
unsigned int gpio_n;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
err = mtk_xt_get_gpio_n(hw, eint_n, &gpio_n, &gpio_chip);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
err = mtk_hw_set_value(hw, gpio_n, PINCTRL_PIN_REG_MODE,
|
|
||||||
MTK_GPIO_MODE);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
err = mtk_hw_set_value(hw, gpio_n, PINCTRL_PIN_REG_DIR, MTK_INPUT);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
err = mtk_hw_set_value(hw, gpio_n, PINCTRL_PIN_REG_SMT, MTK_ENABLE);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct mtk_eint_xt mtk_eint_xt = {
|
|
||||||
.get_gpio_n = mtk_xt_get_gpio_n,
|
|
||||||
.get_gpio_state = mtk_xt_get_gpio_state,
|
|
||||||
.set_gpio_as_eint = mtk_xt_set_gpio_as_eint,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int
|
|
||||||
mtk_build_eint(struct mtk_pinctrl *hw, struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
struct device_node *np = pdev->dev.of_node;
|
|
||||||
struct resource *res;
|
|
||||||
|
|
||||||
if (!IS_ENABLED(CONFIG_EINT_MTK))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!of_property_read_bool(np, "interrupt-controller"))
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
hw->eint = devm_kzalloc(hw->dev, sizeof(*hw->eint), GFP_KERNEL);
|
|
||||||
if (!hw->eint)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "eint");
|
|
||||||
if (!res) {
|
|
||||||
dev_err(&pdev->dev, "Unable to get eint resource\n");
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
hw->eint->base = devm_ioremap_resource(&pdev->dev, res);
|
|
||||||
if (IS_ERR(hw->eint->base))
|
|
||||||
return PTR_ERR(hw->eint->base);
|
|
||||||
|
|
||||||
hw->eint->irq = irq_of_parse_and_map(np, 0);
|
|
||||||
if (!hw->eint->irq)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
hw->eint->dev = &pdev->dev;
|
|
||||||
hw->eint->hw = hw->soc->eint_hw;
|
|
||||||
hw->eint->pctl = hw;
|
|
||||||
hw->eint->gpio_xlate = &mtk_eint_xt;
|
|
||||||
|
|
||||||
return mtk_eint_do_init(hw->eint);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct of_device_id mtk_pinctrl_of_match[] = {
|
|
||||||
{ .compatible = "mediatek,mt7622-pinctrl", .data = &mt7622_data},
|
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
static int mtk_pinctrl_probe(struct platform_device *pdev)
|
static int mt7622_pinctrl_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct resource *res;
|
return mtk_moore_pinctrl_probe(pdev, &mt7622_data);
|
||||||
struct mtk_pinctrl *hw;
|
|
||||||
const struct of_device_id *of_id =
|
|
||||||
of_match_device(mtk_pinctrl_of_match, &pdev->dev);
|
|
||||||
int err;
|
|
||||||
|
|
||||||
hw = devm_kzalloc(&pdev->dev, sizeof(*hw), GFP_KERNEL);
|
|
||||||
if (!hw)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
hw->soc = of_id->data;
|
|
||||||
|
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
||||||
if (!res) {
|
|
||||||
dev_err(&pdev->dev, "missing IO resource\n");
|
|
||||||
return -ENXIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
hw->dev = &pdev->dev;
|
|
||||||
hw->base = devm_ioremap_resource(&pdev->dev, res);
|
|
||||||
if (IS_ERR(hw->base))
|
|
||||||
return PTR_ERR(hw->base);
|
|
||||||
|
|
||||||
/* Setup pins descriptions per SoC types */
|
|
||||||
mtk_desc.pins = hw->soc->pins;
|
|
||||||
mtk_desc.npins = hw->soc->npins;
|
|
||||||
mtk_desc.num_custom_params = ARRAY_SIZE(mtk_custom_bindings);
|
|
||||||
mtk_desc.custom_params = mtk_custom_bindings;
|
|
||||||
#ifdef CONFIG_DEBUG_FS
|
|
||||||
mtk_desc.custom_conf_items = mtk_conf_items;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
err = devm_pinctrl_register_and_init(&pdev->dev, &mtk_desc, hw,
|
|
||||||
&hw->pctrl);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
/* Setup groups descriptions per SoC types */
|
|
||||||
err = mtk_build_groups(hw);
|
|
||||||
if (err) {
|
|
||||||
dev_err(&pdev->dev, "Failed to build groups\n");
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Setup functions descriptions per SoC types */
|
|
||||||
err = mtk_build_functions(hw);
|
|
||||||
if (err) {
|
|
||||||
dev_err(&pdev->dev, "Failed to build functions\n");
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* For able to make pinctrl_claim_hogs, we must not enable pinctrl
|
|
||||||
* until all groups and functions are being added one.
|
|
||||||
*/
|
|
||||||
err = pinctrl_enable(hw->pctrl);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
err = mtk_build_eint(hw, pdev);
|
|
||||||
if (err)
|
|
||||||
dev_warn(&pdev->dev,
|
|
||||||
"Failed to add EINT, but pinctrl still can work\n");
|
|
||||||
|
|
||||||
/* Build gpiochip should be after pinctrl_enable is done */
|
|
||||||
err = mtk_build_gpiochip(hw, pdev->dev.of_node);
|
|
||||||
if (err) {
|
|
||||||
dev_err(&pdev->dev, "Failed to add gpio_chip\n");
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
platform_set_drvdata(pdev, hw);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct platform_driver mtk_pinctrl_driver = {
|
static struct platform_driver mt7622_pinctrl_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "mtk-pinctrl",
|
.name = "mt7622-pinctrl",
|
||||||
.of_match_table = mtk_pinctrl_of_match,
|
.of_match_table = mt7622_pinctrl_of_match,
|
||||||
},
|
},
|
||||||
.probe = mtk_pinctrl_probe,
|
.probe = mt7622_pinctrl_probe,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init mtk_pinctrl_init(void)
|
static int __init mt7622_pinctrl_init(void)
|
||||||
{
|
{
|
||||||
return platform_driver_register(&mtk_pinctrl_driver);
|
return platform_driver_register(&mt7622_pinctrl_driver);
|
||||||
}
|
}
|
||||||
arch_initcall(mtk_pinctrl_init);
|
arch_initcall(mt7622_pinctrl_init);
|
||||||
|
Reference in New Issue
Block a user