MLK-13982: 4.9 rebase: EPDC does not work
authorCristina Ciocan <cristina-mihaela.ciocan@nxp.com>
Mon, 27 Feb 2017 10:04:17 +0000 (12:04 +0200)
committerLeonard Crestez <leonard.crestez@nxp.com>
Wed, 17 Apr 2019 23:51:34 +0000 (02:51 +0300)
The Linux kernel regulator core implementation does not accept negative
voltage values; all negative values are treated as errors.

The problem with the EPDC is that the panel uses a negative voltage
regulator which fails to be enabled by the regulator core. This issue has
slipped up until the 4.9 rebase because the voltage range [min, max] was
checked against only when min = max. This has been fixed in 4.9, resulting
in errors in the VCOM regulator driver.

The fix is to use the negative values when communicating with the hardware,
but send only positive values to the regulator core.

This patch sends the absolute value to the regulator core and transforms
the received value (from the regulator core) to negative one before sending
it to hardware.

Fix device tree to deal with negative voltage regulator values by setting
min_value = -real_max_value and vice versa. Boards affected:
- imx6dl-sabresd
- imx6ull-14x14-ddr3-arm2
- imx7d-12x12-lpddr3-arm2
- imx7d-sdb
- imx6sll-evk
- imx6sl-evk
- imx6sll-lpddr3-arm2

Signed-off-by: Cristina Ciocan <cristina-mihaela.ciocan@nxp.com>
[Arul: Fix merge conflicts]
Signed-off-by: Arulpandiyan Vadivel <arulpandiyan_vadivel@mentor.com>
arch/arm/boot/dts/imx6dl-sabresd.dts
arch/arm/boot/dts/imx6sl-evk.dts
arch/arm/boot/dts/imx6sll-evk.dts
arch/arm/boot/dts/imx6sll-lpddr3-arm2.dts
arch/arm/boot/dts/imx6ull-14x14-ddr3-arm2.dts
arch/arm/boot/dts/imx7d-12x12-lpddr3-arm2.dts
arch/arm/boot/dts/imx7d-sdb.dts
drivers/regulator/max17135-regulator.c

index 7739b7e..e7b6af8 100644 (file)
 };
 
 &i2c3 {
-       max17135@48 {
-               compatible = "maxim,max17135";
-               reg = <0x48>;
-               vneg_pwrup = <1>;
-               gvee_pwrup = <1>;
-               vpos_pwrup = <2>;
-               gvdd_pwrup = <1>;
-               gvdd_pwrdn = <1>;
-               vpos_pwrdn = <2>;
-               gvee_pwrdn = <1>;
-               vneg_pwrdn = <1>;
-               SENSOR-supply = <&reg_sensor>;
-               gpio_pmic_pwrgood = <&gpio2 21 0>;
-               gpio_pmic_vcom_ctrl = <&gpio3 17 0>;
-               gpio_pmic_wakeup = <&gpio3 20 0>;
-               gpio_pmic_v3p3 = <&gpio2 20 0>;
-               gpio_pmic_intr = <&gpio2 25 0>;
-
-               regulators {
-DISPLAY_reg: DISPLAY {
-                    regulator-name = "DISPLAY";
-            };
-
-GVDD_reg: GVDD {
-                 /* 20v */
-                 regulator-name = "GVDD";
-         };
-
-GVEE_reg: GVEE {
-                 /* -22v */
-                 regulator-name = "GVEE";
-         };
-
-HVINN_reg: HVINN {
-                  /* -22v */
-                  regulator-name = "HVINN";
-          };
-
-HVINP_reg: HVINP {
-                  /* 20v */
-                  regulator-name = "HVINP";
-          };
-
-VCOM_reg: VCOM {
-                 regulator-name = "VCOM";
-                 /* 2's-compliment, -4325000 */
-                 regulator-min-microvolt = <0xffbe0178>;
-                 /* 2's-compliment, -500000 */
-                 regulator-max-microvolt = <0xfff85ee0>;
-         };
-
-VNEG_reg: VNEG {
-                 /* -15v */
-                 regulator-name = "VNEG";
-         };
-
-VPOS_reg: VPOS {
-                 /* 15v */
-                 regulator-name = "VPOS";
-         };
-
-V3P3_reg: V3P3 {
-                 regulator-name = "V3P3";
-         };
-               };
-       };
+        max17135@48 {
+                compatible = "maxim,max17135";
+                reg = <0x48>;
+                vneg_pwrup = <1>;
+                gvee_pwrup = <1>;
+                vpos_pwrup = <2>;
+                gvdd_pwrup = <1>;
+                gvdd_pwrdn = <1>;
+                vpos_pwrdn = <2>;
+                gvee_pwrdn = <1>;
+                vneg_pwrdn = <1>;
+                SENSOR-supply = <&reg_sensor>;
+                gpio_pmic_pwrgood = <&gpio2 21 0>;
+                gpio_pmic_vcom_ctrl = <&gpio3 17 0>;
+                gpio_pmic_wakeup = <&gpio3 20 0>;
+                gpio_pmic_v3p3 = <&gpio2 20 0>;
+                gpio_pmic_intr = <&gpio2 25 0>;
+
+                regulators {
+                        DISPLAY_reg: DISPLAY {
+                                regulator-name = "DISPLAY";
+                        };
+
+                        GVDD_reg: GVDD {
+                                /* 20v */
+                                regulator-name = "GVDD";
+                        };
+
+                        GVEE_reg: GVEE {
+                                /* -22v */
+                                regulator-name = "GVEE";
+                        };
+
+                        HVINN_reg: HVINN {
+                                /* -22v */
+                                regulator-name = "HVINN";
+                        };
+
+                        HVINP_reg: HVINP {
+                                /* 20v */
+                                regulator-name = "HVINP";
+                        };
+
+                        VCOM_reg: VCOM {
+                                regulator-name = "VCOM";
+                                /* Real max: -500000 */
+                                regulator-max-microvolt = <4325000>;
+                                /* Real min: -4325000 */
+                                regulator-min-microvolt = <500000>;
+                        };
+
+                        VNEG_reg: VNEG {
+                                /* -15v */
+                                regulator-name = "VNEG";
+                        };
+
+                        VPOS_reg: VPOS {
+                                /* 15v */
+                                regulator-name = "VPOS";
+                        };
+
+                        V3P3_reg: V3P3 {
+                                regulator-name = "V3P3";
+                        };
+                };
+        };
 };
 
 &ipu1_csi1_from_ipu1_csi1_mux {
index c1067ab..47b4529 100644 (file)
 
                        VCOM_reg: VCOM {
                                regulator-name = "VCOM";
-                               /* 2's-compliment, -4325000 */
-                               regulator-min-microvolt = <0xffbe0178>;
-                               /* 2's-compliment, -500000 */
-                               regulator-max-microvolt = <0xfff85ee0>;
+                               /* Real max value: -500000 */
+                               regulator-max-microvolt = <4325000>;
+                               /* Real min value: -4325000 */
+                               regulator-min-microvolt = <500000>;
                        };
 
                        VNEG_reg: VNEG {
index f2ac661..c671b47 100644 (file)
 
                        VCOM_reg: VCOM {
                                regulator-name = "VCOM";
-                               /* 2's-compliment, -4325000 */
-                               regulator-min-microvolt = <0xffbe0178>;
-                               /* 2's-compliment, -500000 */
-                               regulator-max-microvolt = <0xfff85ee0>;
+                               /* Real max value: -500000 */
+                               regulator-max-microvolt = <4325000>;
+                               /* Real min value: -4325000 */
+                               regulator-min-microvolt = <500000>;
                        };
 
                        VNEG_reg: VNEG {
index 8829201..ec433ac 100644 (file)
 
                        VCOM_reg: VCOM {
                                regulator-name = "VCOM";
-                               /* 2's-compliment, -4325000 */
-                               regulator-min-microvolt = <0xffbe0178>;
-                               /* 2's-compliment, -500000 */
-                               regulator-max-microvolt = <0xfff85ee0>;
+                               /* Real max value: -500000 */
+                               regulator-max-microvolt = <4325000>;
+                               /* Real min value: -4325000 */
+                               regulator-min-microvolt = <500000>;
                        };
 
                        VNEG_reg: VNEG {
index 7afec4d..7f4b85d 100644 (file)
 
                        VCOM_reg: VCOM {
                                regulator-name = "VCOM";
-                               /* 2's-compliment, -4325000 */
-                               regulator-min-microvolt = <0xffbe0178>;
-                               /* 2's-compliment, -500000 */
-                               regulator-max-microvolt = <0xfff85ee0>;
+                               /* Real max: -500000 */
+                               regulator-max-microvolt = <4325000>;
+                               /* Real min: -4325000 */
+                               regulator-min-microvolt = <500000>;
                        };
 
                        VNEG_reg: VNEG {
index e834c73..a244166 100644 (file)
 
                        VCOM_reg: VCOM {
                                regulator-name = "VCOM";
-                               /* 2's-compliment, -4325000 */
-                               regulator-min-microvolt = <0xffbe0178>;
-                               /* 2's-compliment, -500000 */
-                               regulator-max-microvolt = <0xfff85ee0>;
+                               /* Real max value: -500000 */
+                               regulator-max-microvolt = <4325000>;
+                               /* Real min value: -4325000 */
+                               regulator-min-microvolt = <500000>;
                        };
 
                        VNEG_reg: VNEG {
index 1b511e1..64045b2 100644 (file)
 
                        VCOM_reg: VCOM {
                                regulator-name = "VCOM";
-                               /* 2's-compliment, -4325000 */
-                               regulator-min-microvolt = <0xffbe0178>;
-                               /* 2's-compliment, -500000 */
-                               regulator-max-microvolt = <0xfff85ee0>;
+                               /* Real max value: -500000 */
+                               regulator-max-microvolt = <4325000>;
+                               /* Real min value: -4325000 */
+                               regulator-min-microvolt = <500000>;
                        };
 
                        VNEG_reg: VNEG {
index 82b7c4a..90a2665 100644 (file)
@@ -177,6 +177,12 @@ static inline int vcom_rs_to_uV(int rs, int pass_num)
                - (vcom_data[pass_num].vcom_step_uV * rs);
 }
 
+/*
+ * This function should only be called with positive voltage values because
+ * negative ones are considered errors by the regulator core implementation.
+ *
+ * The given positive value if the absolute value of the desired negative one.
+ */
 static int max17135_vcom_set_voltage(struct regulator_dev *reg,
                                        int minuV, int uV, unsigned *selector)
 {
@@ -184,6 +190,9 @@ static int max17135_vcom_set_voltage(struct regulator_dev *reg,
        unsigned int reg_val;
        int vcom_read;
 
+       /* Transform uV for our negative land values */
+       uV = -uV;
+
        if ((uV < vcom_data[max17135->pass_num-1].vcom_min_uV)
                || (uV > vcom_data[max17135->pass_num-1].vcom_max_uV))
                return -EINVAL;
@@ -209,18 +218,29 @@ static int max17135_vcom_set_voltage(struct regulator_dev *reg,
        return 0;
 }
 
+/*
+ * This function should only return positive voltage values because negative
+ * ones are considered errors by the regulator core implementation.
+ */
 static int max17135_vcom_get_voltage(struct regulator_dev *reg)
 {
        struct max17135 *max17135 = rdev_get_drvdata(reg);
        unsigned int reg_val;
+       int uV;
 
        max17135_reg_read(REG_MAX17135_DVR, &reg_val);
-       return vcom_rs_to_uV(BITFEXT(reg_val, DVR), max17135->pass_num-1);
+       uV = vcom_rs_to_uV(BITFEXT(reg_val, DVR), max17135->pass_num-1);
+
+       /* Transform uV to positive value */
+       uV = -uV;
+
+       return uV;
 }
 
 static int max17135_vcom_enable(struct regulator_dev *reg)
 {
        struct max17135 *max17135 = rdev_get_drvdata(reg);
+       int uV;
 
        /*
         * Check to see if we need to set the VCOM voltage.
@@ -228,10 +248,9 @@ static int max17135_vcom_enable(struct regulator_dev *reg)
         * only change vcom voltage if we have been enabled.
         */
        if (!max17135->vcom_setup && max17135_is_power_good(max17135)) {
-               max17135_vcom_set_voltage(reg,
-                       max17135->vcom_uV,
-                       max17135->vcom_uV,
-                       NULL);
+               uV = (-1) * max17135->vcom_uV;
+
+               max17135_vcom_set_voltage(reg, uV, uV, NULL);
                max17135->vcom_setup = true;
        }