]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
pinctrl: sophgo: avoid to modify untouched bit when setting cv1800 pinconf
authorInochi Amaoto <inochiama@gmail.com>
Tue, 11 Feb 2025 05:17:49 +0000 (13:17 +0800)
committerLinus Walleij <linus.walleij@linaro.org>
Thu, 27 Feb 2025 22:56:17 +0000 (23:56 +0100)
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>
drivers/pinctrl/sophgo/pinctrl-cv18xx.c

index 57f2674e75d688c61309ea2f76b0537ce3c530b9..84b4850771ce2a7b1d5a22c89c65b2323f0dd580 100644 (file)
@@ -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,10 +596,12 @@ 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);
@@ -607,6 +609,7 @@ static int cv1800_pinconf_compute_config(struct cv1800_pinctrl *pctrl,
                                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);
@@ -614,6 +617,7 @@ static int cv1800_pinconf_compute_config(struct cv1800_pinctrl *pctrl,
                                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 */
@@ -621,10 +625,12 @@ static int cv1800_pinconf_compute_config(struct cv1800_pinctrl *pctrl,
                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;
@@ -632,17 +638,19 @@ static int cv1800_pinconf_compute_config(struct cv1800_pinctrl *pctrl,
        }
 
        *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;
@@ -650,7 +658,10 @@ static int cv1800_pin_set_config(struct cv1800_pinctrl *pctrl,
        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;
 }