Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions drivers/pinctrl/mediatek/mtk-eint.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ static const struct mtk_eint_regs mtk_generic_eint_regs = {
.dbnc_ctrl = 0x500,
.dbnc_set = 0x600,
.dbnc_clr = 0x700,
.event = 0x800,
.event_set = 0x840,
.event_clr = 0x880,
};

const unsigned int debounce_time_mt2701[] = {
Expand Down Expand Up @@ -163,6 +166,47 @@ static void mtk_eint_unmask(struct irq_data *d)
mtk_eint_flip_edge(eint, d->hwirq);
}

/*
* Clear the event_clr bit for a single EINT so its wake-event is not
* suppressed. Mirrors mtk_eint_unmask() addressing: register is banked
* per instance and word-indexed by (idx / 32).
*/
static void mtk_eint_event_unmask_one(struct mtk_eint *eint,
unsigned int eint_num)
{
unsigned int idx, inst;
unsigned int mask;
void __iomem *reg;

if (eint_num >= eint->hw->ap_num)
return;

idx = eint->pins[eint_num].index;
inst = eint->pins[eint_num].instance;

if (inst >= eint->nbase)
return;

mask = BIT(idx & 0x1f);
reg = mtk_eint_get_offset(eint, eint_num, eint->regs->event_clr);
writel(mask, reg);
}

/*
* Walk the SoC's wake-event pin list (e.g. eint_event_mt8901[]) and
* clear each pin's event mask so wake sources survive init/resume.
*/
static void mtk_eint_apply_event_unmask(struct mtk_eint *eint)
{
unsigned int i;

if (!eint->event_pins || !eint->num_event_pins)
return;

for (i = 0; i < eint->num_event_pins; i++)
mtk_eint_event_unmask_one(eint, eint->event_pins[i]);
}

static unsigned int mtk_eint_get_mask(struct mtk_eint *eint,
unsigned int eint_num)
{
Expand Down Expand Up @@ -438,6 +482,7 @@ EXPORT_SYMBOL_GPL(mtk_eint_do_suspend);
int mtk_eint_do_resume(struct mtk_eint *eint)
{
mtk_eint_chip_write_mask(eint, eint->base, eint->cur_mask);
mtk_eint_apply_event_unmask(eint);

return 0;
}
Expand Down Expand Up @@ -605,6 +650,11 @@ int mtk_eint_do_init(struct mtk_eint *eint, struct mtk_eint_pin *eint_pin)
irq_set_chained_handler_and_data(eint->irq, mtk_eint_irq_handler,
eint);

mtk_eint_apply_event_unmask(eint);

dev_info(eint->dev, "%s completed, %u EINTs registered\n",
__func__, eint->hw->ap_num);

return 0;

err_eint:
Expand Down
9 changes: 9 additions & 0 deletions drivers/pinctrl/mediatek/mtk-eint.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ struct mtk_eint_regs {
unsigned int dbnc_ctrl;
unsigned int dbnc_set;
unsigned int dbnc_clr;
unsigned int event;
unsigned int event_set;
unsigned int event_clr;
};

struct mtk_eint_hw {
Expand Down Expand Up @@ -84,6 +87,12 @@ struct mtk_eint {
struct mtk_eint_pin *pins;
u16 num_db_time;

/* Wake-event pin list: bits to clear in event_clr after init/resume
* so wake sources are not suppressed.
*/
const unsigned int *event_pins;
unsigned int num_event_pins;

/* Used to fit into various pinctrl device */
void *pctl;
const struct mtk_eint_xt *gpio_xlate;
Expand Down
4 changes: 4 additions & 0 deletions drivers/pinctrl/mediatek/pinctrl-mt8901.c
Original file line number Diff line number Diff line change
Expand Up @@ -1412,6 +1412,8 @@ static const struct mtk_eint_hw mt8901_eint_hw = {
.db_time = debounce_time_mt8901,
};

static const unsigned int eint_event_mt8901[] = {20};

static const struct mtk_pin_soc mt8901_data = {
.reg_cal = mt8901_reg_cals,
.pins = mtk_pins_mt8901,
Expand All @@ -1432,6 +1434,8 @@ static const struct mtk_pin_soc mt8901_data = {
.drive_get = mtk_pinconf_drive_get_rev1,
.adv_drive_set = mtk_pinconf_adv_drive_set_raw,
.adv_drive_get = mtk_pinconf_adv_drive_get_raw,
.eint_event = eint_event_mt8901,
.total_wake_eints = ARRAY_SIZE(eint_event_mt8901),
};

static const struct acpi_device_id mt8901_pinctrl_acpi_match[] = {
Expand Down
173 changes: 167 additions & 6 deletions drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/soc/mediatek/mtk-pinctrl.h>

#include "mtk-eint.h"
#include "pinctrl-mtk-common-v2.h"
Expand Down Expand Up @@ -434,6 +435,8 @@ int mtk_build_eint(struct mtk_pinctrl *hw, struct platform_device *pdev)
hw->eint->hw = hw->soc->eint_hw;
hw->eint->pctl = hw;
hw->eint->gpio_xlate = &mtk_eint_xt;
hw->eint->event_pins = hw->soc->eint_event;
hw->eint->num_event_pins = hw->soc->total_wake_eints;

ret = mtk_eint_do_init(hw->eint, hw->soc->eint_pin);
if (ret)
Expand Down Expand Up @@ -624,10 +627,15 @@ static int mtk_pinconf_bias_set_pu_pd(struct mtk_pinctrl *hw,
if (arg == MTK_DISABLE) {
pu = 0;
pd = 0;
} else if ((arg == MTK_ENABLE) && pullup) {
} else if (arg == MTK_ENABLE && pullup == MTK_BUS_HOLD) {
if (pd_only)
return -EINVAL; /* Bus-hold needs both PU and PD. */
pu = 1;
pd = 1;
} else if ((arg == MTK_ENABLE) && pullup == 1) {
pu = 1;
pd = 0;
} else if ((arg == MTK_ENABLE) && !pullup) {
} else if ((arg == MTK_ENABLE) && pullup == 0) {
pu = 0;
pd = 1;
} else {
Expand All @@ -649,6 +657,12 @@ static int mtk_pinconf_bias_set_pullsel_pullen(struct mtk_pinctrl *hw,
{
int err, enable;

/* Bus-hold is not supported for the PULLSEL/PULLEN path; reject explicitly */
if (pullup == MTK_BUS_HOLD) {
err = -EINVAL;
goto out;
}

if (arg == MTK_DISABLE)
enable = 0;
else if (arg == MTK_ENABLE)
Expand All @@ -674,6 +688,12 @@ static int mtk_pinconf_bias_set_pupd_r1_r0(struct mtk_pinctrl *hw,
{
int err, r0, r1;

/* Bus-hold is not supported for R1R0 path; reject explicitly */
if (pullup == MTK_BUS_HOLD) {
err = -EINVAL;
goto out;
}

if ((arg == MTK_DISABLE) || (arg == MTK_PUPD_SET_R1R0_00)) {
pullup = 0;
r0 = 0;
Expand Down Expand Up @@ -794,10 +814,18 @@ int mtk_pinconf_bias_set_combo(struct mtk_pinctrl *hw,
else
try_all_type = MTK_PULL_TYPE_MASK;

/*
* Explicitly handle bus-hold for RSEL type: skip the RSEL path when
* MTK_BUS_HOLD is requested.
*/
if (try_all_type & MTK_PULL_RSEL_TYPE) {
err = mtk_pinconf_bias_set_pu_pd_rsel(hw, desc, pullup, arg);
if (!err)
return 0;
if (pullup == MTK_BUS_HOLD) {
/* Bus-hold not supported for RSEL */
} else {
err = mtk_pinconf_bias_set_pu_pd_rsel(hw, desc, pullup, arg);
if (!err)
return 0;
}
}

if (try_all_type & MTK_PULL_PD_TYPE) {
Expand Down Expand Up @@ -829,6 +857,128 @@ int mtk_pinconf_bias_set_combo(struct mtk_pinctrl *hw,
}
EXPORT_SYMBOL_GPL(mtk_pinconf_bias_set_combo);

/*
* Registry of active mtk_pinctrl instances so that client drivers
* (see mtk_pinctrl_program_bias_by_gpio) can resolve an absolute SoC
* pin number to the owning controller without having a device handle.
* Number of live controllers per system is small (typically 1-2), so a
* flat list guarded by a mutex is sufficient.
*/
static LIST_HEAD(mtk_pinctrl_instances);
static DEFINE_MUTEX(mtk_pinctrl_instances_lock);

void mtk_pinctrl_register_instance(struct mtk_pinctrl *hw)
{
mutex_lock(&mtk_pinctrl_instances_lock);
list_add_tail(&hw->instance_node, &mtk_pinctrl_instances);
mutex_unlock(&mtk_pinctrl_instances_lock);
}
EXPORT_SYMBOL_GPL(mtk_pinctrl_register_instance);

void mtk_pinctrl_unregister_instance(struct mtk_pinctrl *hw)
{
mutex_lock(&mtk_pinctrl_instances_lock);
list_del(&hw->instance_node);
mutex_unlock(&mtk_pinctrl_instances_lock);
}
EXPORT_SYMBOL_GPL(mtk_pinctrl_unregister_instance);

/*
* Translate the public API's constants to the pinctrl-internal ones.
* Kept explicit rather than assumed-equal so the two can evolve
* independently (client drivers do not include pinctrl-mtk-common-v2.h).
*/
static int mtk_pinctrl_public_pullup_to_internal(u32 pub, u32 *out)
{
switch (pub) {
case MTK_PIN_PULLDOWN:
*out = MTK_PULLDOWN;
return 0;
case MTK_PIN_PULLUP:
*out = MTK_PULLUP;
return 0;
case MTK_PIN_BUS_HOLD:
*out = MTK_BUS_HOLD;
return 0;
default:
return -EINVAL;
}
}

static int mtk_pinctrl_public_arg_to_internal(u32 pub, u32 *out)
{
switch (pub) {
case MTK_PIN_ENABLE:
*out = MTK_ENABLE;
return 0;
case MTK_PIN_DISABLE:
*out = MTK_DISABLE;
return 0;
default:
return -EINVAL;
}
}

int mtk_pinctrl_program_bias_by_gpio(unsigned int gpio, u32 pullup, u32 arg)
{
struct mtk_pinctrl *hw, *owner = NULL;
const struct mtk_pin_desc *desc;
u32 int_pullup, int_arg;
int err;

err = mtk_pinctrl_public_pullup_to_internal(pullup, &int_pullup);
if (err)
return err;
err = mtk_pinctrl_public_arg_to_internal(arg, &int_arg);
if (err)
return err;

mutex_lock(&mtk_pinctrl_instances_lock);

/*
* MediaTek pin numbers are zero-based per controller, so a bare
* pin number cannot distinguish two controllers that both have
* at least @gpio + 1 pins. Every supported platform registers a
* single instance. Rather than silently program the first match,
* refuse when the request is ambiguous.
*/
list_for_each_entry(hw, &mtk_pinctrl_instances, instance_node) {
if (gpio >= hw->soc->npins)
continue;

if (hw->soc->pins[gpio].number != gpio)
continue;

if (owner) {
dev_warn_once(hw->dev,
"pin %u also owned by %s, refusing ambiguous bias request\n",
gpio, dev_name(owner->dev));
err = -EINVAL;
goto out;
}
owner = hw;
}

if (!owner) {
err = -ENODEV;
goto out;
}

if (!owner->soc->bias_set_combo) {
err = -EOPNOTSUPP;
goto out;
}

desc = &owner->soc->pins[gpio];
err = owner->soc->bias_set_combo(owner, desc, int_pullup, int_arg);

out:
mutex_unlock(&mtk_pinctrl_instances_lock);

return err;
}
EXPORT_SYMBOL_GPL(mtk_pinctrl_program_bias_by_gpio);

static int mtk_rsel_get_si_unit(struct mtk_pinctrl *hw,
const struct mtk_pin_desc *desc,
u32 pullup, u32 rsel_val, u32 *si_unit)
Expand Down Expand Up @@ -887,6 +1037,13 @@ static int mtk_pinconf_bias_get_pu_pd_rsel(struct mtk_pinctrl *hw,
mtk_rsel_get_si_unit(hw, desc, *pullup, rsel, enable);
else
*enable = rsel + MTK_PULL_SET_RSEL_000;
} else if (pu == 1 && pd == 1) {
/* Keeper (bus-hold) reports pull-up resistance via up-RSEL lookup */
*pullup = MTK_BUS_HOLD;
if (hw->rsel_si_unit)
mtk_rsel_get_si_unit(hw, desc, *pullup, rsel, enable);
else
*enable = rsel + MTK_PULL_SET_RSEL_000;
} else {
err = -EINVAL;
goto out;
Expand Down Expand Up @@ -919,8 +1076,12 @@ static int mtk_pinconf_bias_get_pu_pd(struct mtk_pinctrl *hw,
} else if (pu == 0 && pd == 1) {
*pullup = 0;
*enable = MTK_ENABLE;
} else
} else if (pu == 1 && pd == 1) {
*pullup = MTK_BUS_HOLD;
*enable = MTK_ENABLE;
} else {
err = -EINVAL;
}

out:
return err;
Expand Down
Loading
Loading