Skip to content

Commit

Permalink
pinctrl: sophgo: avoid to modify untouched bit when setting cv1800 pi…
Browse files Browse the repository at this point in the history
…nconf

[ Upstream commit ef1a512 ]

When setting pinconf configuration for cv1800 SoC, the driver just writes
the value. It may zero some bits of the pinconf register and cause some
unexpected error. Add a mask to avoid this.

Signed-off-by: Inochi Amaoto <inochiama@gmail.com>
Link: https://lore.kernel.org/20250211051801.470800-2-inochiama@gmail.com
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
Inochi Amaoto authored and Greg Kroah-Hartman committed May 29, 2025
1 parent baaf308 commit 1dd943d
Showing 1 changed file with 23 additions and 10 deletions.
33 changes: 23 additions & 10 deletions drivers/pinctrl/sophgo/pinctrl-cv18xx.c
Original file line number Diff line number Diff line change
@@ -574,10 +574,10 @@ static int cv1800_pinconf_compute_config(struct cv1800_pinctrl *pctrl,
struct cv1800_pin *pin,
unsigned long *configs,
unsigned int num_configs,
u32 *value)
u32 *value, u32 *mask)
{
int i;
u32 v = 0;
u32 v = 0, m = 0;
enum cv1800_pin_io_type type;
int ret;

@@ -596,61 +596,72 @@ static int cv1800_pinconf_compute_config(struct cv1800_pinctrl *pctrl,
case PIN_CONFIG_BIAS_PULL_DOWN:
v &= ~PIN_IO_PULLDOWN;
v |= FIELD_PREP(PIN_IO_PULLDOWN, arg);
m |= PIN_IO_PULLDOWN;
break;
case PIN_CONFIG_BIAS_PULL_UP:
v &= ~PIN_IO_PULLUP;
v |= FIELD_PREP(PIN_IO_PULLUP, arg);
m |= PIN_IO_PULLUP;
break;
case PIN_CONFIG_DRIVE_STRENGTH_UA:
ret = cv1800_pinctrl_oc2reg(pctrl, pin, arg);
if (ret < 0)
return ret;
v &= ~PIN_IO_DRIVE;
v |= FIELD_PREP(PIN_IO_DRIVE, ret);
m |= PIN_IO_DRIVE;
break;
case PIN_CONFIG_INPUT_SCHMITT_UV:
ret = cv1800_pinctrl_schmitt2reg(pctrl, pin, arg);
if (ret < 0)
return ret;
v &= ~PIN_IO_SCHMITT;
v |= FIELD_PREP(PIN_IO_SCHMITT, ret);
m |= PIN_IO_SCHMITT;
break;
case PIN_CONFIG_POWER_SOURCE:
/* Ignore power source as it is always fixed */
break;
case PIN_CONFIG_SLEW_RATE:
v &= ~PIN_IO_OUT_FAST_SLEW;
v |= FIELD_PREP(PIN_IO_OUT_FAST_SLEW, arg);
m |= PIN_IO_OUT_FAST_SLEW;
break;
case PIN_CONFIG_BIAS_BUS_HOLD:
v &= ~PIN_IO_BUS_HOLD;
v |= FIELD_PREP(PIN_IO_BUS_HOLD, arg);
m |= PIN_IO_BUS_HOLD;
break;
default:
return -ENOTSUPP;
}
}

*value = v;
*mask = m;

return 0;
}

static int cv1800_pin_set_config(struct cv1800_pinctrl *pctrl,
unsigned int pin_id,
u32 value)
u32 value, u32 mask)
{
struct cv1800_pin *pin = cv1800_get_pin(pctrl, pin_id);
unsigned long flags;
void __iomem *addr;
u32 reg;

if (!pin)
return -EINVAL;

addr = cv1800_pinctrl_get_component_addr(pctrl, &pin->conf);

raw_spin_lock_irqsave(&pctrl->lock, flags);
writel(value, addr);
reg = readl(addr);
reg &= ~mask;
reg |= value;
writel(reg, addr);
raw_spin_unlock_irqrestore(&pctrl->lock, flags);

return 0;
@@ -662,16 +673,17 @@ static int cv1800_pconf_set(struct pinctrl_dev *pctldev,
{
struct cv1800_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
struct cv1800_pin *pin = cv1800_get_pin(pctrl, pin_id);
u32 value;
u32 value, mask;

if (!pin)
return -ENODEV;

if (cv1800_pinconf_compute_config(pctrl, pin,
configs, num_configs, &value))
configs, num_configs,
&value, &mask))
return -ENOTSUPP;

return cv1800_pin_set_config(pctrl, pin_id, value);
return cv1800_pin_set_config(pctrl, pin_id, value, mask);
}

static int cv1800_pconf_group_set(struct pinctrl_dev *pctldev,
@@ -682,7 +694,7 @@ static int cv1800_pconf_group_set(struct pinctrl_dev *pctldev,
struct cv1800_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
const struct group_desc *group;
const struct cv1800_pin_mux_config *pinmuxs;
u32 value;
u32 value, mask;
int i;

group = pinctrl_generic_get_group(pctldev, gsel);
@@ -692,11 +704,12 @@ static int cv1800_pconf_group_set(struct pinctrl_dev *pctldev,
pinmuxs = group->data;

if (cv1800_pinconf_compute_config(pctrl, pinmuxs[0].pin,
configs, num_configs, &value))
configs, num_configs,
&value, &mask))
return -ENOTSUPP;

for (i = 0; i < group->grp.npins; i++)
cv1800_pin_set_config(pctrl, group->grp.pins[i], value);
cv1800_pin_set_config(pctrl, group->grp.pins[i], value, mask);

return 0;
}

0 comments on commit 1dd943d

Please sign in to comment.