saradc: saradc register initialization is incomplete [1/1]
authorXingyu Chen <xingyu.chen@amlogic.com>
Tue, 26 Feb 2019 09:45:31 +0000 (17:45 +0800)
committerJianxin Pan <jianxin.pan@amlogic.com>
Thu, 7 Mar 2019 02:12:11 +0000 (18:12 -0800)
PD#SWPL-4975

Problem:
some basic saradc registers are only initialized at bl2 stage, the ADC
value is abnormal when bl2 disable saradc init.

Solution:
to re-initialize the basic saradc registers in kernel.

Verify:
test pass on w400 and p212

Change-Id: Ie98e8789fd47cc43cafcb49d9862ccccbe1d9b66
Signed-off-by: Xingyu Chen <xingyu.chen@amlogic.com>
drivers/amlogic/iio/adc/meson_saradc.c

index dc58464..a32565d 100644 (file)
        #define MESON_SAR_ADC_FIFO_RD_SAMPLE_VALUE_MASK         GENMASK(11, 0)
 
 #define MESON_SAR_ADC_AUX_SW                                   0x1c
-       #define MESON_SAR_ADC_AUX_SW_MUX_SEL_CHAN_MASK(_chan)   \
-                                       (GENMASK(10, 8) << (((_chan) - 2) * 2))
+       #define MESON_SAR_ADC_AUX_SW_MUX_SEL_CHAN_SHIFT(_chan)  \
+                                       (8 + (((_chan) - 2) * 3))
        #define MESON_SAR_ADC_AUX_SW_VREF_P_MUX                 BIT(6)
        #define MESON_SAR_ADC_AUX_SW_VREF_N_MUX                 BIT(5)
        #define MESON_SAR_ADC_AUX_SW_MODE_SEL                   BIT(4)
  */
 #define MESON_SAR_ADC_REG11                                    0x2c
        #define MESON_SAR_ADC_REG11_VREF_SEL                    BIT(0)
+       #define MESON_SAR_ADC_REG11_EOC                         BIT(1)
+       #define MESON_SAR_ADC_REG11_VREF_EN                     BIT(5)
+       #define MESON_SAR_ADC_REG11_CMV_SEL                     BIT(6)
        #define MESON_SAR_ADC_REG11_BANDGAP_EN                  BIT(13)
        #define MESON_SAR_ADC_REG11_CHNL_REGS_EN                BIT(30)
        #define MESON_SAR_ADC_REG11_FIFO_EN                     BIT(31)
@@ -305,9 +308,15 @@ enum vref_select {
  *
  * @reg3_ring_counter_disable: to disable continuous ring counter.
  * gxl and later: 1; others(gxtvbb etc): 0
+ * @reg11_vref_en: g12a and later: 0; others(gxl etc): 1
+ * @reg11_cmv_sel: g12a and later: 0; others(gxl etc): 1
+ * @reg11_eoc: g12a and later: 1; others(gxl etc): 0
  */
 struct meson_sar_adc_reg_diff {
        bool            reg3_ring_counter_disable;
+       bool            reg11_vref_en;
+       bool            reg11_cmv_sel;
+       bool            reg11_eoc;
 };
 
 /*
@@ -330,6 +339,7 @@ struct meson_sar_adc_data {
        bool                    has_chnl_regs;
        unsigned int            resolution;
        const char              *name;
+       const struct regmap_config *regmap_config;
        struct meson_sar_adc_reg_diff regs_diff;
 };
 
@@ -351,13 +361,27 @@ struct meson_sar_adc_priv {
        u8                              *datum_buf;
 };
 
-static const struct regmap_config meson_sar_adc_regmap_config = {
+static const struct regmap_config meson_sar_adc_regmap_config_g12a = {
        .reg_bits = 8,
        .val_bits = 32,
        .reg_stride = 4,
        .max_register = MESON_SAR_ADC_CHNL67,
 };
 
+static const struct regmap_config meson_sar_adc_regmap_config_gxbb = {
+       .reg_bits = 8,
+       .val_bits = 32,
+       .reg_stride = 4,
+       .max_register = MESON_SAR_ADC_REG13,
+};
+
+static const struct regmap_config meson_sar_adc_regmap_config_meson8 = {
+       .reg_bits = 8,
+       .val_bits = 32,
+       .reg_stride = 4,
+       .max_register = MESON_SAR_ADC_DELTA_10,
+};
+
 static unsigned int meson_sar_adc_get_fifo_count(struct iio_dev *indio_dev)
 {
        struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
@@ -529,7 +553,7 @@ static void meson_sar_adc_enable_channel(struct iio_dev *indio_dev,
                           MESON_SAR_ADC_CHAN_LIST_MAX_INDEX_MASK, regval);
 
        /* map channel index 0 to the channel which we want to read */
-       regval = chan->channel << MESON_SAR_ADC_CHAN_LIST_ENTRY_SHIFT(idx),
+       regval = chan->channel << MESON_SAR_ADC_CHAN_LIST_ENTRY_SHIFT(idx);
        regmap_update_bits(priv->regmap, MESON_SAR_ADC_CHAN_LIST,
                           MESON_SAR_ADC_CHAN_LIST_ENTRY_MASK(idx), regval);
 
@@ -835,6 +859,7 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev)
 {
        struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
        int regval, ret;
+       int i;
 
        /*
         * make sure we start at CH7 input since the other muxes are only used
@@ -895,6 +920,55 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev)
                        MESON_SAR_ADC_REG3_CTRL_CONT_RING_COUNTER_EN,
                        FIELD_PREP(MESON_SAR_ADC_REG3_CTRL_CONT_RING_COUNTER_EN,
                        priv->data->regs_diff.reg3_ring_counter_disable));
+
+       /*
+        * set up the input channel muxes in MESON_SAR_ADC_CHAN_10_SW
+        * (0 = SAR_ADC_CH0, 1 = SAR_ADC_CH1)
+        */
+       regval = FIELD_PREP(MESON_SAR_ADC_CHAN_10_SW_CHAN0_MUX_SEL_MASK, 0);
+       regmap_update_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW,
+                          MESON_SAR_ADC_CHAN_10_SW_CHAN0_MUX_SEL_MASK,
+                          regval);
+
+       regmap_update_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW,
+                          MESON_SAR_ADC_CHAN_10_SW_CHAN0_XP_DRIVE_SW,
+                          MESON_SAR_ADC_CHAN_10_SW_CHAN0_XP_DRIVE_SW);
+
+       regmap_update_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW,
+                          MESON_SAR_ADC_CHAN_10_SW_CHAN0_YP_DRIVE_SW,
+                          MESON_SAR_ADC_CHAN_10_SW_CHAN0_YP_DRIVE_SW);
+
+       regval = FIELD_PREP(MESON_SAR_ADC_CHAN_10_SW_CHAN1_MUX_SEL_MASK, 1);
+       regmap_update_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW,
+                          MESON_SAR_ADC_CHAN_10_SW_CHAN1_MUX_SEL_MASK,
+                          regval);
+
+       regmap_update_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW,
+                          MESON_SAR_ADC_CHAN_10_SW_CHAN1_XP_DRIVE_SW,
+                          MESON_SAR_ADC_CHAN_10_SW_CHAN1_XP_DRIVE_SW);
+
+       regmap_update_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW,
+                          MESON_SAR_ADC_CHAN_10_SW_CHAN1_YP_DRIVE_SW,
+                          MESON_SAR_ADC_CHAN_10_SW_CHAN1_YP_DRIVE_SW);
+       /*
+        * set up the input channel muxes in MESON_SAR_ADC_AUX_SW
+        * (2 = SAR_ADC_CH2, 3 = SAR_ADC_CH3, ...) and enable
+        * MESON_SAR_ADC_AUX_SW_YP_DRIVE_SW and
+        * MESON_SAR_ADC_AUX_SW_XP_DRIVE_SW like the vendor driver.
+        */
+       regval = 0;
+       for (i = 2; i <= 7; i++)
+               regval |= i << MESON_SAR_ADC_AUX_SW_MUX_SEL_CHAN_SHIFT(i);
+       regval |= MESON_SAR_ADC_AUX_SW_YP_DRIVE_SW;
+       regval |= MESON_SAR_ADC_AUX_SW_XP_DRIVE_SW;
+       regmap_write(priv->regmap, MESON_SAR_ADC_AUX_SW, regval);
+
+       /* must be set to <1> for g12a and later SoCs */
+       regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG11,
+                          MESON_SAR_ADC_REG11_EOC,
+                          FIELD_PREP(MESON_SAR_ADC_REG11_EOC,
+                                     priv->data->regs_diff.reg11_eoc));
+
        /* select the vref */
        regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG11,
                                MESON_SAR_ADC_REG11_VREF_SEL,
@@ -923,8 +997,19 @@ static int meson_sar_adc_hw_enable(struct iio_dev *indio_dev)
        }
 
        regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG11,
+                          MESON_SAR_ADC_REG11_VREF_EN,
+                          FIELD_PREP(MESON_SAR_ADC_REG11_VREF_EN,
+                                     priv->data->regs_diff.reg11_vref_en));
+
+       regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG11,
+                          MESON_SAR_ADC_REG11_CMV_SEL,
+                          FIELD_PREP(MESON_SAR_ADC_REG11_CMV_SEL,
+                                     priv->data->regs_diff.reg11_cmv_sel));
+
+       regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG11,
                           MESON_SAR_ADC_REG11_BANDGAP_EN,
                           MESON_SAR_ADC_REG11_BANDGAP_EN);
+
        regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3,
                           MESON_SAR_ADC_REG3_ADC_EN,
                           MESON_SAR_ADC_REG3_ADC_EN);
@@ -1302,8 +1387,12 @@ struct meson_sar_adc_data meson_sar_adc_g12a_data = {
        .vref_sel = VDDA_AS_VREF,
        .resolution = SAR_ADC_12BIT,
        .name = "meson-g12a-saradc",
+       .regmap_config = &meson_sar_adc_regmap_config_g12a,
        .regs_diff = {
                .reg3_ring_counter_disable = BIT_HIGH,
+               .reg11_vref_en = BIT_LOW,
+               .reg11_cmv_sel = BIT_LOW,
+               .reg11_eoc = BIT_HIGH,
        },
 };
 
@@ -1313,8 +1402,12 @@ struct meson_sar_adc_data meson_sar_adc_txlx_data = {
        .vref_sel = VDDA_AS_VREF,
        .resolution = SAR_ADC_12BIT,
        .name = "meson-txlx-saradc",
+       .regmap_config = &meson_sar_adc_regmap_config_gxbb,
        .regs_diff = {
                .reg3_ring_counter_disable = BIT_HIGH,
+               .reg11_vref_en = BIT_HIGH,
+               .reg11_cmv_sel = BIT_HIGH,
+               .reg11_eoc = BIT_LOW,
        },
 };
 
@@ -1324,8 +1417,12 @@ struct meson_sar_adc_data meson_sar_adc_axg_data = {
        .vref_sel = VDDA_AS_VREF,
        .resolution = SAR_ADC_12BIT,
        .name = "meson-axg-saradc",
+       .regmap_config = &meson_sar_adc_regmap_config_gxbb,
        .regs_diff = {
                .reg3_ring_counter_disable = BIT_HIGH,
+               .reg11_vref_en = BIT_HIGH,
+               .reg11_cmv_sel = BIT_HIGH,
+               .reg11_eoc = BIT_LOW,
        },
 };
 
@@ -1335,8 +1432,12 @@ struct meson_sar_adc_data meson_sar_adc_txl_data = {
        .vref_sel = CALIB_VOL_AS_VREF,
        .resolution = SAR_ADC_12BIT,
        .name = "meson-txl-saradc",
+       .regmap_config = &meson_sar_adc_regmap_config_gxbb,
        .regs_diff = {
                .reg3_ring_counter_disable = BIT_HIGH,
+               .reg11_vref_en = BIT_HIGH,
+               .reg11_cmv_sel = BIT_HIGH,
+               .reg11_eoc = BIT_LOW,
        },
 };
 
@@ -1346,8 +1447,12 @@ struct meson_sar_adc_data meson_sar_adc_gxl_data = {
        .vref_sel = CALIB_VOL_AS_VREF,
        .resolution = SAR_ADC_12BIT,
        .name = "meson-gxl-saradc",
+       .regmap_config = &meson_sar_adc_regmap_config_gxbb,
        .regs_diff = {
                .reg3_ring_counter_disable = BIT_HIGH,
+               .reg11_vref_en = BIT_HIGH,
+               .reg11_cmv_sel = BIT_HIGH,
+               .reg11_eoc = BIT_LOW,
        },
 };
 
@@ -1357,8 +1462,12 @@ struct meson_sar_adc_data meson_sar_adc_gxm_data = {
        .vref_sel = CALIB_VOL_AS_VREF,
        .resolution = SAR_ADC_12BIT,
        .name = "meson-gxm-saradc",
+       .regmap_config = &meson_sar_adc_regmap_config_gxbb,
        .regs_diff = {
                .reg3_ring_counter_disable = BIT_HIGH,
+               .reg11_vref_en = BIT_HIGH,
+               .reg11_cmv_sel = BIT_HIGH,
+               .reg11_eoc = BIT_LOW,
        },
 };
 
@@ -1368,6 +1477,7 @@ struct meson_sar_adc_data meson_sar_adc_m8b_data = {
        .vref_sel = CALIB_VOL_AS_VREF,
        .resolution = SAR_ADC_10BIT,
        .name = "meson-m8b-saradc",
+       .regmap_config = &meson_sar_adc_regmap_config_meson8,
        .regs_diff = {
                .reg3_ring_counter_disable = BIT_LOW,
        },
@@ -1443,7 +1553,7 @@ static int meson_sar_adc_probe(struct platform_device *pdev)
                return -EINVAL;
 
        priv->regmap = devm_regmap_init_mmio(&pdev->dev, base,
-                                            &meson_sar_adc_regmap_config);
+                                            priv->data->regmap_config);
        if (IS_ERR(priv->regmap))
                return PTR_ERR(priv->regmap);