The eh bit is used for setting drive mode for i2c pins on recent SoCs.
Add support for it.
Signed-off-by: Igor Belwon <igor.belwon@mentallysanemainliners.org>
---
drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c | 60 ++++++++++++++++++++++++
drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h | 24 ++++++++++
drivers/pinctrl/mediatek/pinctrl-paris.c | 30 +++++++++---
3 files changed, 108 insertions(+), 6 deletions(-)
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
index 4918d38abfc29de1f27ee75bc6a51c32b3ca1ac5..51fbdbdf61c901bb7ee43405d36f2c1602b3616f 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
@@ -249,6 +249,58 @@ static int mtk_xt_find_eint_num(struct mtk_pinctrl *hw, unsigned long eint_n)
return EINT_NA;
}
+/*
+ * The eh register determines the selection of the driving control
+ * for i2c pins.
+ * eh = 0: Non-i2c mode.
+ * eh = 1: i2c mode.
+ */
+int mtk_eh_ctrl(struct mtk_pinctrl *hw, const struct mtk_pin_desc *desc,
+ u16 mode)
+{
+ const struct mtk_eh_pin_pinmux *p = hw->soc->eh_pin_pinmux;
+ u32 eh_info_num = hw->soc->neh_pins;
+ u32 val = 0, on = 0, found = 0, i = 0;
+ int err;
+
+ while (i < eh_info_num) {
+ if (desc->number == p[i].pin) {
+ found = 1;
+ if (mode == p[i].pinmux) {
+ on = 1;
+ break;
+ }
+ }
+ /*
+ * It is possible that one pin may have more than one pinmux
+ * that shall enable eh.
+ * Besides, we assume that hw->soc->eh_pin_pinmux is sorted
+ * according to field 'pin'.
+ * So when desc->number < p->pin, it mean no match will be
+ * found and we can leave.
+ */
+ if (desc->number < p[i].pin)
+ break;
+
+ i++;
+ }
+
+ if (!found)
+ return 0;
+
+ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DRV_EH, &val);
+ if (err)
+ return err;
+
+ if (on)
+ val |= on;
+ else
+ val &= MTK_EH_ENABLE_MASK;
+
+ return mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DRV_EH, val);
+}
+EXPORT_SYMBOL_GPL(mtk_eh_ctrl);
+
/*
* Virtual GPIO only used inside SOC and not being exported to outside SOC.
* Some modules use virtual GPIO as eint (e.g. pmif or usb).
@@ -1231,6 +1283,10 @@ int mtk_pinconf_adv_drive_set(struct mtk_pinctrl *hw,
int e0 = !!(arg & 2);
int e1 = !!(arg & 4);
+ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DRV_EH, arg);
+ if (!err)
+ return 0;
+
err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DRV_EN, en);
if (err)
return err;
@@ -1256,6 +1312,10 @@ int mtk_pinconf_adv_drive_get(struct mtk_pinctrl *hw,
u32 en, e0, e1;
int err;
+ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DRV_EH, val);
+ if (!err)
+ return 0;
+
err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DRV_EN, &en);
if (err)
return err;
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h
index fa7c0ed49346486ba32ec615aa2b3483217f5077..a2ff8ae5ba43e5be87c8b478c07d9d4640c2e8ec 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h
@@ -35,6 +35,8 @@
MTK_PULL_PUPD_R1R0_TYPE |\
MTK_PULL_RSEL_TYPE)
+#define MTK_EH_ENABLE_MASK 0xfffffffe
+
#define EINT_NA U16_MAX
#define NO_EINT_SUPPORT EINT_NA
@@ -67,6 +69,11 @@
.down_rsel = _down_rsel, \
}
+#define PIN_MUX_EH(_pin, _pinmux) { \
+ .pin = _pin, \
+ .pinmux = _pinmux, \
+ }
+
/* List these attributes which could be modified for the pin */
enum {
PINCTRL_PIN_REG_MODE,
@@ -88,6 +95,7 @@ enum {
PINCTRL_PIN_REG_IES,
PINCTRL_PIN_REG_PULLEN,
PINCTRL_PIN_REG_PULLSEL,
+ PINCTRL_PIN_REG_DRV_EH,
PINCTRL_PIN_REG_DRV_EN,
PINCTRL_PIN_REG_DRV_E0,
PINCTRL_PIN_REG_DRV_E1,
@@ -204,6 +212,17 @@ struct mtk_eint_desc {
u16 eint_n;
};
+/**
+ * struct mtk_eh_pin_pinmux - entry recording (pin, pinmux) whose
+ * eh can be enabled
+ * @pin: pin number
+ * @pinmux: pinmux number
+ */
+struct mtk_eh_pin_pinmux {
+ u16 pin;
+ u16 pinmux;
+};
+
/**
* struct mtk_pin_desc - the structure that providing information
* for each pin of chips
@@ -252,6 +271,8 @@ struct mtk_pin_soc {
const unsigned int *pull_type;
const struct mtk_pin_rsel *pin_rsel;
unsigned int npin_rsel;
+ const struct mtk_eh_pin_pinmux *eh_pin_pinmux;
+ unsigned int neh_pins;
/* Specific pinconfig operations */
int (*bias_disable_set)(struct mtk_pinctrl *hw,
@@ -311,6 +332,9 @@ int mtk_hw_set_value(struct mtk_pinctrl *hw, const struct mtk_pin_desc *desc,
int mtk_hw_get_value(struct mtk_pinctrl *hw, const struct mtk_pin_desc *desc,
int field, int *value);
+int mtk_eh_ctrl(struct mtk_pinctrl *hw, const struct mtk_pin_desc *desc,
+ u16 mode);
+
int mtk_build_eint(struct mtk_pinctrl *hw, struct platform_device *pdev);
int mtk_pinconf_bias_disable_set(struct mtk_pinctrl *hw,
diff --git a/drivers/pinctrl/mediatek/pinctrl-paris.c b/drivers/pinctrl/mediatek/pinctrl-paris.c
index 3e714554789d0e7e31ecce92388f53b906bdf122..f87447d6f879a3f7b57db44ed97cc91f8e93b425 100644
--- a/drivers/pinctrl/mediatek/pinctrl-paris.c
+++ b/drivers/pinctrl/mediatek/pinctrl-paris.c
@@ -104,13 +104,21 @@ static int mtk_pinmux_gpio_request_enable(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
unsigned int pin)
{
+ int err;
struct mtk_pinctrl *hw = pinctrl_dev_get_drvdata(pctldev);
const struct mtk_pin_desc *desc;
desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin];
- return mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_MODE,
- hw->soc->gpio_m);
+ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_MODE,
+ hw->soc->gpio_m);
+ if (err)
+ return err;
+
+ if (hw->soc->eh_pin_pinmux)
+ err = mtk_eh_ctrl(hw, desc, hw->soc->gpio_m);
+
+ return err;
}
static int mtk_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev,
@@ -749,10 +757,10 @@ static int mtk_pmx_set_mux(struct pinctrl_dev *pctldev,
struct mtk_pinctrl_group *grp = hw->groups + group;
const struct mtk_func_desc *desc_func;
const struct mtk_pin_desc *desc;
- bool ret;
+ int err;
- ret = mtk_pctrl_is_function_valid(hw, grp->pin, function);
- if (!ret) {
+ err = mtk_pctrl_is_function_valid(hw, grp->pin, function);
+ if (!err) {
dev_err(hw->dev, "invalid function %d on group %d .\n",
function, group);
return -EINVAL;
@@ -763,7 +771,17 @@ static int mtk_pmx_set_mux(struct pinctrl_dev *pctldev,
return -EINVAL;
desc = (const struct mtk_pin_desc *)&hw->soc->pins[grp->pin];
- return mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_MODE, desc_func->muxval);
+
+ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_MODE,
+ desc_func->muxval);
+
+ if (!err)
+ return err;
+
+ if (hw->soc->eh_pin_pinmux)
+ err = mtk_eh_ctrl(hw, desc, desc_func->muxval);
+
+ return err;
}
static const struct pinmux_ops mtk_pmxops = {
--
2.51.0
Il 08/09/25 21:17, Igor Belwon ha scritto: > The eh bit is used for setting drive mode for i2c pins on recent SoCs. > Add support for it. > > Signed-off-by: Igor Belwon <igor.belwon@mentallysanemainliners.org> Noupe, this commit is not needed at all. I get that this may be tricky to understand... but summarizing, what the downstream calls "EH" in upstream is "DRV_ADV" :-) Check the comments on patch [4/4] about how to change EH to DRV_ADV. Cheers, Angelo
On Tue Sep 9, 2025 at 9:57 AM CEST, AngeloGioacchino Del Regno wrote: > Il 08/09/25 21:17, Igor Belwon ha scritto: >> The eh bit is used for setting drive mode for i2c pins on recent SoCs. >> Add support for it. >> >> Signed-off-by: Igor Belwon <igor.belwon@mentallysanemainliners.org> > > Noupe, this commit is not needed at all. > > I get that this may be tricky to understand... but summarizing, what the > downstream calls "EH" in upstream is "DRV_ADV" :-) > > Check the comments on patch [4/4] about how to change EH to DRV_ADV. > > Cheers, > Angelo Whoops, sorry, I don't know how I missed that. Will change as in your comments and drop this commit. Thanks, Igor
© 2016 - 2025 Red Hat, Inc.