summaryrefslogtreecommitdiff
path: root/drivers/hwmon
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hwmon')
-rw-r--r--drivers/hwmon/qpnp-adc-common.c94
-rw-r--r--drivers/hwmon/qpnp-adc-voltage.c684
2 files changed, 460 insertions, 318 deletions
diff --git a/drivers/hwmon/qpnp-adc-common.c b/drivers/hwmon/qpnp-adc-common.c
index 24f4135045e4..aeca77c9390d 100644
--- a/drivers/hwmon/qpnp-adc-common.c
+++ b/drivers/hwmon/qpnp-adc-common.c
@@ -1074,6 +1074,7 @@ int32_t qpnp_adc_scale_therm_pu2(struct qpnp_vadc_chip *chip,
EXPORT_SYMBOL(qpnp_adc_scale_therm_pu2);
int32_t qpnp_adc_tm_scale_voltage_therm_pu2(struct qpnp_vadc_chip *chip,
+ const struct qpnp_adc_properties *adc_properties,
uint32_t reg, int64_t *result)
{
int64_t adc_voltage = 0;
@@ -1090,9 +1091,15 @@ int32_t qpnp_adc_tm_scale_voltage_therm_pu2(struct qpnp_vadc_chip *chip,
do_div(adc_voltage, param1.dy);
- qpnp_adc_map_voltage_temp(adcmap_100k_104ef_104fb,
- ARRAY_SIZE(adcmap_100k_104ef_104fb),
- adc_voltage, result);
+ if (adc_properties->adc_hc)
+ qpnp_adc_map_voltage_temp(adcmap_100k_104ef_104fb_1875_vref,
+ ARRAY_SIZE(adcmap_100k_104ef_104fb_1875_vref),
+ adc_voltage, result);
+ else
+ qpnp_adc_map_voltage_temp(adcmap_100k_104ef_104fb,
+ ARRAY_SIZE(adcmap_100k_104ef_104fb),
+ adc_voltage, result);
+
if (negative_offset)
adc_voltage = -adc_voltage;
@@ -1101,6 +1108,7 @@ int32_t qpnp_adc_tm_scale_voltage_therm_pu2(struct qpnp_vadc_chip *chip,
EXPORT_SYMBOL(qpnp_adc_tm_scale_voltage_therm_pu2);
int32_t qpnp_adc_tm_scale_therm_voltage_pu2(struct qpnp_vadc_chip *chip,
+ const struct qpnp_adc_properties *adc_properties,
struct qpnp_adc_tm_config *param)
{
struct qpnp_vadc_linear_graph param1;
@@ -1108,11 +1116,20 @@ int32_t qpnp_adc_tm_scale_therm_voltage_pu2(struct qpnp_vadc_chip *chip,
qpnp_get_vadc_gain_and_offset(chip, &param1, CALIB_RATIOMETRIC);
- rc = qpnp_adc_map_temp_voltage(adcmap_100k_104ef_104fb,
- ARRAY_SIZE(adcmap_100k_104ef_104fb),
- param->low_thr_temp, &param->low_thr_voltage);
- if (rc)
- return rc;
+ if (adc_properties->adc_hc) {
+ rc = qpnp_adc_map_temp_voltage(
+ adcmap_100k_104ef_104fb_1875_vref,
+ ARRAY_SIZE(adcmap_100k_104ef_104fb_1875_vref),
+ param->low_thr_temp, &param->low_thr_voltage);
+ if (rc)
+ return rc;
+ } else {
+ rc = qpnp_adc_map_temp_voltage(adcmap_100k_104ef_104fb,
+ ARRAY_SIZE(adcmap_100k_104ef_104fb),
+ param->low_thr_temp, &param->low_thr_voltage);
+ if (rc)
+ return rc;
+ }
param->low_thr_voltage *= param1.dy;
do_div(param->low_thr_voltage, param1.adc_vref);
@@ -1772,6 +1789,7 @@ int32_t qpnp_adc_get_devicetree_data(struct platform_device *pdev,
struct qpnp_adc_properties *adc_prop;
struct qpnp_adc_amux_properties *amux_prop;
int count_adc_channel_list = 0, decimation, rc = 0, i = 0;
+ int decimation_tm_hc = 0, fast_avg_setup_tm_hc = 0;
bool adc_hc;
if (!node)
@@ -1812,6 +1830,27 @@ int32_t qpnp_adc_get_devicetree_data(struct platform_device *pdev,
adc_hc = adc_qpnp->adc_hc;
adc_prop->adc_hc = adc_hc;
+ if (of_device_is_compatible(node, "qcom,qpnp-adc-tm-hc")) {
+ rc = of_property_read_u32(node, "qcom,decimation",
+ &decimation_tm_hc);
+ if (rc) {
+ pr_err("Invalid decimation property\n");
+ return -EINVAL;
+ }
+
+ rc = of_property_read_u32(node,
+ "qcom,fast-avg-setup", &fast_avg_setup_tm_hc);
+ if (rc) {
+ pr_err("Invalid fast average setup with %d\n", rc);
+ return -EINVAL;
+ }
+
+ if ((fast_avg_setup_tm_hc) > ADC_FAST_AVG_SAMPLE_16) {
+ pr_err("Max average support is 2^16\n");
+ return -EINVAL;
+ }
+ }
+
for_each_child_of_node(node, child) {
int channel_num, scaling, post_scaling, hw_settle_time;
int fast_avg_setup, calib_type = 0, rc;
@@ -1829,12 +1868,7 @@ int32_t qpnp_adc_get_devicetree_data(struct platform_device *pdev,
pr_err("Invalid channel num\n");
return -EINVAL;
}
- rc = of_property_read_u32(child, "qcom,decimation",
- &decimation);
- if (rc) {
- pr_err("Invalid channel decimation property\n");
- return -EINVAL;
- }
+
if (!of_device_is_compatible(node, "qcom,qpnp-iadc")) {
rc = of_property_read_u32(child,
"qcom,hw-settle-time", &hw_settle_time);
@@ -1860,6 +1894,23 @@ int32_t qpnp_adc_get_devicetree_data(struct platform_device *pdev,
pr_err("Invalid calibration type\n");
return -EINVAL;
}
+
+ /*
+ * ADC_TM_HC decimation setting is common across
+ * channels.
+ */
+ if (!of_device_is_compatible(node,
+ "qcom,qpnp-adc-tm-hc")) {
+ rc = of_property_read_u32(child,
+ "qcom,decimation", &decimation);
+ if (rc) {
+ pr_err("Invalid decimation\n");
+ return -EINVAL;
+ }
+ } else {
+ decimation = decimation_tm_hc;
+ }
+
if (!strcmp(calibration_param, "absolute")) {
if (adc_hc)
calib_type = ADC_HC_ABS_CAL;
@@ -1884,12 +1935,19 @@ int32_t qpnp_adc_get_devicetree_data(struct platform_device *pdev,
return -EINVAL;
}
}
- rc = of_property_read_u32(child,
+
+ /* ADC_TM_HC fast avg setting is common across channels */
+ if (!of_device_is_compatible(node, "qcom,qpnp-adc-tm-hc")) {
+ rc = of_property_read_u32(child,
"qcom,fast-avg-setup", &fast_avg_setup);
- if (rc) {
- pr_err("Invalid channel fast average setup\n");
- return -EINVAL;
+ if (rc) {
+ pr_err("Invalid channel fast average setup\n");
+ return -EINVAL;
+ }
+ } else {
+ fast_avg_setup = fast_avg_setup_tm_hc;
}
+
/* Individual channel properties */
adc_channel_list[i].name = (char *)channel_name;
adc_channel_list[i].channel_num = channel_num;
diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c
index 2ce8d973866f..0d18c77cfdff 100644
--- a/drivers/hwmon/qpnp-adc-voltage.c
+++ b/drivers/hwmon/qpnp-adc-voltage.c
@@ -225,6 +225,8 @@ static struct qpnp_vadc_rscale_fn adc_vadc_rscale_fn[] = {
[SCALE_RVADC_ABSOLUTE] = {qpnp_vadc_absolute_rthr},
};
+static int32_t qpnp_vadc_calib_device(struct qpnp_vadc_chip *vadc);
+
static int32_t qpnp_vadc_read_reg(struct qpnp_vadc_chip *vadc, int16_t reg,
u8 *data, int len)
{
@@ -255,6 +257,17 @@ static int32_t qpnp_vadc_write_reg(struct qpnp_vadc_chip *vadc, int16_t reg,
return 0;
}
+static int qpnp_vadc_is_valid(struct qpnp_vadc_chip *vadc)
+{
+ struct qpnp_vadc_chip *vadc_chip = NULL;
+
+ list_for_each_entry(vadc_chip, &qpnp_vadc_device_list, list)
+ if (vadc == vadc_chip)
+ return 0;
+
+ return -EINVAL;
+}
+
static int32_t qpnp_vadc_warm_rst_configure(struct qpnp_vadc_chip *vadc)
{
int rc = 0;
@@ -369,6 +382,267 @@ static int32_t qpnp_vadc_status_debug(struct qpnp_vadc_chip *vadc)
return 0;
}
+
+static int qpnp_vadc_hc_check_conversion_status(struct qpnp_vadc_chip *vadc)
+{
+ int rc = 0, count = 0;
+ u8 status1 = 0;
+
+ while (status1 != QPNP_VADC_STATUS1_EOC) {
+ rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_STATUS1, &status1, 1);
+ if (rc < 0)
+ return rc;
+ status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
+ if (status1 == QPNP_VADC_STATUS1_EOC)
+ break;
+ usleep_range(QPNP_VADC_HC1_CONV_TIME_MIN_US,
+ QPNP_VADC_HC1_CONV_TIME_MAX_US);
+ count++;
+ if (count > QPNP_VADC_HC1_ERR_COUNT) {
+ pr_err("retry error exceeded\n");
+ rc = qpnp_vadc_status_debug(vadc);
+ if (rc < 0)
+ pr_err("VADC disable failed with %d\n", rc);
+ return -EINVAL;
+ }
+ }
+
+ return rc;
+}
+
+static int qpnp_vadc_hc_read_data(struct qpnp_vadc_chip *vadc, int *data)
+{
+ int rc = 0;
+ u8 buf = 0, rslt_lsb = 0, rslt_msb = 0;
+
+ /* Set hold bit */
+ rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_HC1_DATA_HOLD_CTL, &buf, 1);
+ if (rc) {
+ pr_err("debug register dump failed\n");
+ return rc;
+ }
+ buf |= QPNP_VADC_HC1_DATA_HOLD_CTL_FIELD;
+ rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_HC1_DATA_HOLD_CTL, &buf, 1);
+ if (rc) {
+ pr_err("debug register dump failed\n");
+ return rc;
+ }
+
+ rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_HC1_DATA0, &rslt_lsb, 1);
+ if (rc < 0) {
+ pr_err("qpnp adc result read failed for data0\n");
+ return rc;
+ }
+
+ rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_HC1_DATA1, &rslt_msb, 1);
+ if (rc < 0) {
+ pr_err("qpnp adc result read failed for data1\n");
+ return rc;
+ }
+
+ *data = (rslt_msb << 8) | rslt_lsb;
+
+ if (*data == QPNP_VADC_HC1_DATA_CHECK_USR) {
+ pr_err("Invalid data :0x%x\n", *data);
+ return -EINVAL;
+ }
+
+ rc = qpnp_vadc_enable(vadc, false);
+ if (rc) {
+ pr_err("VADC disable failed\n");
+ return rc;
+ }
+
+ /* De-assert hold bit */
+ buf &= ~QPNP_VADC_HC1_DATA_HOLD_CTL_FIELD;
+ rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_HC1_DATA_HOLD_CTL, &buf, 1);
+ if (rc)
+ pr_err("de-asserting hold bit failed\n");
+
+ return rc;
+}
+
+static void qpnp_vadc_hc_update_adc_dig_param(struct qpnp_vadc_chip *vadc,
+ struct qpnp_adc_amux_properties *amux_prop, u8 *data)
+{
+ /* Update CAL value */
+ *data &= ~QPNP_VADC_HC1_CAL_VAL;
+ *data |= (amux_prop->cal_val << QPNP_VADC_HC1_CAL_VAL_SHIFT);
+
+ /* Update CAL select */
+ *data &= ~QPNP_VADC_HC1_CAL_SEL_MASK;
+ *data |= (amux_prop->calib_type << QPNP_VADC_HC1_CAL_SEL_SHIFT);
+
+ /* Update Decimation ratio select */
+ *data &= ~QPNP_VADC_HC1_DEC_RATIO_SEL;
+ *data |= (amux_prop->decimation << QPNP_VADC_HC1_DEC_RATIO_SHIFT);
+
+ pr_debug("VADC_DIG_PARAM value:0x%x\n", *data);
+}
+
+static int qpnp_vadc_hc_configure(struct qpnp_vadc_chip *vadc,
+ struct qpnp_adc_amux_properties *amux_prop)
+{
+ int rc = 0;
+ u8 buf[6];
+
+ /* Read registers 0x42 through 0x46 */
+ rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_HC1_ADC_DIG_PARAM, buf, 6);
+ if (rc < 0) {
+ pr_err("qpnp adc configure block read failed\n");
+ return rc;
+ }
+
+ /* ADC Digital param selection */
+ qpnp_vadc_hc_update_adc_dig_param(vadc, amux_prop, &buf[0]);
+
+ /* Update fast average sample value */
+ buf[1] &= (u8) ~QPNP_VADC_HC1_FAST_AVG_SAMPLES_MASK;
+ buf[1] |= amux_prop->fast_avg_setup;
+
+ /* Select ADC channel */
+ buf[2] = amux_prop->amux_channel;
+
+ /* Select hw settle delay for the channel */
+ buf[3] &= (u8) ~QPNP_VADC_HC1_DELAY_CTL_MASK;
+ buf[3] |= amux_prop->hw_settle_time;
+
+ /* Select ADC enable */
+ buf[4] |= QPNP_VADC_HC1_ADC_EN;
+
+ /* Select CONV request */
+ buf[5] |= QPNP_VADC_HC1_CONV_REQ_START;
+
+ if (!vadc->vadc_poll_eoc)
+ reinit_completion(&vadc->adc->adc_rslt_completion);
+
+ pr_debug("dig:0x%x, fast_avg:0x%x, channel:0x%x, hw_settle:0x%x\n",
+ buf[0], buf[1], buf[2], buf[3]);
+
+ /* Block register write from 0x42 through 0x46 */
+ rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_HC1_ADC_DIG_PARAM, buf, 6);
+ if (rc < 0) {
+ pr_err("qpnp adc block register configure failed\n");
+ return rc;
+ }
+
+ return 0;
+}
+
+int32_t qpnp_vadc_hc_read(struct qpnp_vadc_chip *vadc,
+ enum qpnp_vadc_channels channel,
+ struct qpnp_vadc_result *result)
+{
+ int rc = 0, scale_type, amux_prescaling, dt_index = 0, calib_type = 0;
+ struct qpnp_adc_amux_properties amux_prop;
+
+ if (qpnp_vadc_is_valid(vadc))
+ return -EPROBE_DEFER;
+
+ mutex_lock(&vadc->adc->adc_lock);
+
+ while ((vadc->adc->adc_channels[dt_index].channel_num
+ != channel) && (dt_index < vadc->max_channels_available))
+ dt_index++;
+
+ if (dt_index >= vadc->max_channels_available) {
+ pr_err("not a valid VADC channel:%d\n", channel);
+ rc = -EINVAL;
+ goto fail_unlock;
+ }
+
+ if (!vadc->vadc_init_calib) {
+ rc = qpnp_vadc_calib_device(vadc);
+ if (rc) {
+ pr_err("Calibration failed\n");
+ goto fail_unlock;
+ } else {
+ vadc->vadc_init_calib = true;
+ }
+ }
+
+ calib_type = vadc->adc->adc_channels[dt_index].calib_type;
+ if (calib_type >= ADC_HC_CAL_SEL_NONE) {
+ pr_err("not a valid calib_type\n");
+ rc = -EINVAL;
+ goto fail_unlock;
+ }
+
+ amux_prop.decimation =
+ vadc->adc->adc_channels[dt_index].adc_decimation;
+ amux_prop.calib_type = vadc->adc->adc_channels[dt_index].calib_type;
+ amux_prop.cal_val = vadc->adc->adc_channels[dt_index].cal_val;
+ amux_prop.fast_avg_setup =
+ vadc->adc->adc_channels[dt_index].fast_avg_setup;
+ amux_prop.amux_channel = channel;
+ amux_prop.hw_settle_time =
+ vadc->adc->adc_channels[dt_index].hw_settle_time;
+
+ rc = qpnp_vadc_hc_configure(vadc, &amux_prop);
+ if (rc < 0) {
+ pr_err("Configuring VADC channel failed with %d\n", rc);
+ goto fail_unlock;
+ }
+
+ if (vadc->vadc_poll_eoc) {
+ rc = qpnp_vadc_hc_check_conversion_status(vadc);
+ if (rc < 0) {
+ pr_err("polling mode conversion failed\n");
+ goto fail_unlock;
+ }
+ } else {
+ rc = wait_for_completion_timeout(
+ &vadc->adc->adc_rslt_completion,
+ QPNP_ADC_COMPLETION_TIMEOUT);
+ if (!rc) {
+ rc = qpnp_vadc_hc_check_conversion_status(vadc);
+ if (rc < 0) {
+ pr_err("interrupt mode conversion failed\n");
+ goto fail_unlock;
+ }
+ pr_debug("End of conversion status set\n");
+ }
+ }
+
+ rc = qpnp_vadc_hc_read_data(vadc, &result->adc_code);
+ if (rc) {
+ pr_err("qpnp vadc read adc code failed with %d\n", rc);
+ goto fail_unlock;
+ }
+
+ amux_prescaling =
+ vadc->adc->adc_channels[dt_index].chan_path_prescaling;
+
+ if (amux_prescaling >= PATH_SCALING_NONE) {
+ rc = -EINVAL;
+ goto fail_unlock;
+ }
+
+ vadc->adc->amux_prop->chan_prop->offset_gain_numerator =
+ qpnp_vadc_amux_scaling_ratio[amux_prescaling].num;
+ vadc->adc->amux_prop->chan_prop->offset_gain_denominator =
+ qpnp_vadc_amux_scaling_ratio[amux_prescaling].den;
+
+ scale_type = vadc->adc->adc_channels[dt_index].adc_scale_fn;
+ if (scale_type >= SCALE_NONE) {
+ rc = -EBADF;
+ goto fail_unlock;
+ }
+
+ /* Note: Scaling functions for VADC_HC do not need offset/gain */
+ vadc_scale_fn[scale_type].chan(vadc, result->adc_code,
+ vadc->adc->adc_prop, vadc->adc->amux_prop->chan_prop, result);
+
+ pr_debug("channel=0x%x, adc_code=0x%x adc_result=%lld\n",
+ channel, result->adc_code, result->physical);
+
+fail_unlock:
+ mutex_unlock(&vadc->adc->adc_lock);
+
+ return rc;
+}
+EXPORT_SYMBOL(qpnp_vadc_hc_read);
+
static int32_t qpnp_vadc_configure(struct qpnp_vadc_chip *vadc,
struct qpnp_adc_amux_properties *chan_prop)
{
@@ -551,17 +825,6 @@ static int32_t qpnp_vadc_read_status(struct qpnp_vadc_chip *vadc, int mode_sel)
return 0;
}
-static int qpnp_vadc_is_valid(struct qpnp_vadc_chip *vadc)
-{
- struct qpnp_vadc_chip *vadc_chip = NULL;
-
- list_for_each_entry(vadc_chip, &qpnp_vadc_device_list, list)
- if (vadc == vadc_chip)
- return 0;
-
- return -EINVAL;
-}
-
static void qpnp_vadc_work(struct work_struct *work)
{
struct qpnp_vadc_chip *vadc = container_of(work,
@@ -1209,20 +1472,36 @@ int32_t qpnp_vadc_calib_vref(struct qpnp_vadc_chip *vadc,
int rc, count = 0, calib_read = 0;
u8 status1 = 0;
- if (calib_type == CALIB_ABSOLUTE)
- conv.amux_channel = REF_125V;
- else if (calib_type == CALIB_RATIOMETRIC)
- conv.amux_channel = VDD_VADC;
+ if (vadc->vadc_hc) {
+ if (calib_type == ADC_HC_ABS_CAL)
+ conv.amux_channel = VADC_CALIB_VREF_1P25;
+ else if (calib_type == CALIB_RATIOMETRIC)
+ conv.amux_channel = VADC_CALIB_VREF;
+ } else {
+ if (calib_type == CALIB_ABSOLUTE)
+ conv.amux_channel = REF_125V;
+ else if (calib_type == CALIB_RATIOMETRIC)
+ conv.amux_channel = VDD_VADC;
+ }
conv.decimation = DECIMATION_TYPE2;
conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
+ conv.cal_val = calib_type;
- rc = qpnp_vadc_configure(vadc, &conv);
- if (rc) {
- pr_err("qpnp_vadc configure failed with %d\n", rc);
- goto calib_fail;
+ if (vadc->vadc_hc) {
+ rc = qpnp_vadc_hc_configure(vadc, &conv);
+ if (rc) {
+ pr_err("qpnp_vadc configure failed with %d\n", rc);
+ goto calib_fail;
+ }
+ } else {
+ rc = qpnp_vadc_configure(vadc, &conv);
+ if (rc) {
+ pr_err("qpnp_vadc configure failed with %d\n", rc);
+ goto calib_fail;
+ }
}
while (status1 != QPNP_VADC_STATUS1_EOC) {
@@ -1239,11 +1518,20 @@ int32_t qpnp_vadc_calib_vref(struct qpnp_vadc_chip *vadc,
}
}
- rc = qpnp_vadc_read_conversion_result(vadc, &calib_read);
- if (rc) {
- pr_err("qpnp adc read adc failed with %d\n", rc);
- goto calib_fail;
+ if (vadc->vadc_hc) {
+ rc = qpnp_vadc_hc_read_data(vadc, &calib_read);
+ if (rc) {
+ pr_err("qpnp vadc read adc code failed with %d\n", rc);
+ goto calib_fail;
+ }
+ } else {
+ rc = qpnp_vadc_read_conversion_result(vadc, &calib_read);
+ if (rc) {
+ pr_err("qpnp adc read adc failed with %d\n", rc);
+ goto calib_fail;
+ }
}
+
*calib_data = calib_read;
calib_fail:
return rc;
@@ -1259,21 +1547,34 @@ int32_t qpnp_vadc_calib_gnd(struct qpnp_vadc_chip *vadc,
u8 status1 = 0;
uint32_t ref_channel_sel = 0;
- if (calib_type == CALIB_ABSOLUTE) {
- qpnp_vadc_625mv_channel_sel(vadc, &ref_channel_sel);
- conv.amux_channel = ref_channel_sel;
- } else if (calib_type == CALIB_RATIOMETRIC)
- conv.amux_channel = GND_REF;
+ if (vadc->vadc_hc) {
+ conv.amux_channel = VADC_VREF_GND;
+ } else {
+ if (calib_type == CALIB_ABSOLUTE) {
+ qpnp_vadc_625mv_channel_sel(vadc, &ref_channel_sel);
+ conv.amux_channel = ref_channel_sel;
+ } else if (calib_type == CALIB_RATIOMETRIC)
+ conv.amux_channel = GND_REF;
+ }
conv.decimation = DECIMATION_TYPE2;
conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT;
conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US;
conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1;
+ conv.cal_val = calib_type;
- rc = qpnp_vadc_configure(vadc, &conv);
- if (rc) {
- pr_err("qpnp_vadc configure failed with %d\n", rc);
- goto calib_fail;
+ if (vadc->vadc_hc) {
+ rc = qpnp_vadc_hc_configure(vadc, &conv);
+ if (rc) {
+ pr_err("qpnp_vadc configure failed with %d\n", rc);
+ goto calib_fail;
+ }
+ } else {
+ rc = qpnp_vadc_configure(vadc, &conv);
+ if (rc) {
+ pr_err("qpnp_vadc configure failed with %d\n", rc);
+ goto calib_fail;
+ }
}
while (status1 != QPNP_VADC_STATUS1_EOC) {
@@ -1290,10 +1591,18 @@ int32_t qpnp_vadc_calib_gnd(struct qpnp_vadc_chip *vadc,
}
}
- rc = qpnp_vadc_read_conversion_result(vadc, &calib_read);
- if (rc) {
- pr_err("qpnp adc read adc failed with %d\n", rc);
- goto calib_fail;
+ if (vadc->vadc_hc) {
+ rc = qpnp_vadc_hc_read_data(vadc, &calib_read);
+ if (rc) {
+ pr_err("qpnp vadc read adc code failed with %d\n", rc);
+ goto calib_fail;
+ }
+ } else {
+ rc = qpnp_vadc_read_conversion_result(vadc, &calib_read);
+ if (rc) {
+ pr_err("qpnp adc read adc failed with %d\n", rc);
+ goto calib_fail;
+ }
}
*calib_data = calib_read;
calib_fail:
@@ -1303,35 +1612,41 @@ calib_fail:
static int32_t qpnp_vadc_calib_device(struct qpnp_vadc_chip *vadc)
{
int rc, calib_read_1 = 0, calib_read_2 = 0;
+ enum qpnp_adc_calib_type calib_type;
- rc = qpnp_vadc_calib_vref(vadc, CALIB_ABSOLUTE, &calib_read_1);
+ if (vadc->vadc_hc)
+ calib_type = ADC_HC_ABS_CAL;
+ else
+ calib_type = CALIB_ABSOLUTE;
+
+ rc = qpnp_vadc_calib_vref(vadc, calib_type, &calib_read_1);
if (rc) {
pr_err("qpnp adc absolute vref calib failed with %d\n", rc);
goto calib_fail;
}
- rc = qpnp_vadc_calib_gnd(vadc, CALIB_ABSOLUTE, &calib_read_2);
+ rc = qpnp_vadc_calib_gnd(vadc, calib_type, &calib_read_2);
if (rc) {
pr_err("qpnp adc absolute gnd calib failed with %d\n", rc);
goto calib_fail;
}
- pr_debug("absolute reference raw: 625mV:0x%x 1.25V:0x%x\n",
- calib_read_2, calib_read_1);
+ pr_debug("absolute reference raw: 1.25V:0x%x, 625mV/GND:0x%x\n",
+ calib_read_1, calib_read_2);
if (calib_read_1 == calib_read_2) {
- pr_err("absolute reference raw: 625mV:0x%x 1.25V:0x%x\n",
+ pr_err("absolute reference raw: 1.25V:0x%x625mV:0x%x\n",
calib_read_2, calib_read_1);
rc = -EINVAL;
goto calib_fail;
}
- vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dy =
+ vadc->adc->amux_prop->chan_prop->adc_graph[calib_type].dy =
(calib_read_1 - calib_read_2);
- vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dx
+ vadc->adc->amux_prop->chan_prop->adc_graph[calib_type].dx
= QPNP_ADC_625_UV;
- vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].adc_vref =
+ vadc->adc->amux_prop->chan_prop->adc_graph[calib_type].adc_vref =
calib_read_1;
- vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].adc_gnd =
+ vadc->adc->amux_prop->chan_prop->adc_graph[calib_type].adc_gnd =
calib_read_2;
calib_read_1 = 0;
@@ -1374,11 +1689,29 @@ int32_t qpnp_get_vadc_gain_and_offset(struct qpnp_vadc_chip *vadc,
enum qpnp_adc_calib_type calib_type)
{
int rc = 0;
+ struct qpnp_vadc_result result;
rc = qpnp_vadc_is_valid(vadc);
if (rc < 0)
return rc;
+ if (!vadc->vadc_init_calib) {
+ if (vadc->vadc_hc) {
+ rc = qpnp_vadc_hc_read(vadc, VADC_CALIB_VREF_1P25,
+ &result);
+ if (rc) {
+ pr_debug("vadc read failed with rc = %d\n", rc);
+ return rc;
+ }
+ } else {
+ rc = qpnp_vadc_read(vadc, REF_125V, &result);
+ if (rc) {
+ pr_debug("vadc read failed with rc = %d\n", rc);
+ return rc;
+ }
+ }
+ }
+
switch (calib_type) {
case CALIB_RATIOMETRIC:
param->dy =
@@ -1390,13 +1723,14 @@ int32_t qpnp_get_vadc_gain_and_offset(struct qpnp_vadc_chip *vadc,
vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].adc_gnd;
break;
case CALIB_ABSOLUTE:
+ case ADC_HC_ABS_CAL:
param->dy =
- vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dy;
+ vadc->adc->amux_prop->chan_prop->adc_graph[calib_type].dy;
param->dx =
- vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].dx;
+ vadc->adc->amux_prop->chan_prop->adc_graph[calib_type].dx;
param->adc_vref = vadc->adc->adc_prop->adc_vdd_reference;
param->adc_gnd =
- vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].adc_gnd;
+ vadc->adc->amux_prop->chan_prop->adc_graph[calib_type].adc_gnd;
break;
default:
rc = -EINVAL;
@@ -1429,7 +1763,8 @@ static int32_t qpnp_vadc_wait_for_req_sts_check(struct qpnp_vadc_chip *vadc)
while ((status1 & QPNP_VADC_STATUS1_REQ_STS) && (count < QPNP_RETRY)) {
/* Wait time is based on the optimum sampling rate
* and adding enough time buffer to account for ADC conversions
- * occuring on different peripheral banks */
+ * occurring on different peripheral banks
+ */
usleep_range(QPNP_MIN_TIME, QPNP_MAX_TIME);
rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_STATUS1, &status1, 1);
if (rc < 0) {
@@ -2170,256 +2505,6 @@ int32_t qpnp_vadc_end_channel_monitor(struct qpnp_vadc_chip *chip)
}
EXPORT_SYMBOL(qpnp_vadc_end_channel_monitor);
-static int qpnp_vadc_hc_check_conversion_status(struct qpnp_vadc_chip *vadc)
-{
- int rc = 0, count = 0;
- u8 status1 = 0;
-
- while (status1 != QPNP_VADC_STATUS1_EOC) {
- rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_STATUS1, &status1, 1);
- if (rc < 0)
- return rc;
- status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK;
- if (status1 == QPNP_VADC_STATUS1_EOC)
- break;
- usleep_range(QPNP_VADC_HC1_CONV_TIME_MIN_US,
- QPNP_VADC_HC1_CONV_TIME_MAX_US);
- count++;
- if (count > QPNP_VADC_HC1_ERR_COUNT) {
- pr_err("retry error exceeded\n");
- rc = qpnp_vadc_status_debug(vadc);
- if (rc < 0)
- pr_err("VADC disable failed\n");
- return -EINVAL;
- }
- }
-
- return rc;
-}
-
-static int qpnp_vadc_hc_read_data(struct qpnp_vadc_chip *vadc, int *data)
-{
- int rc = 0;
- u8 buf = 0, rslt_lsb = 0, rslt_msb = 0;
-
- /* Set hold bit */
- rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_HC1_DATA_HOLD_CTL, &buf, 1);
- if (rc) {
- pr_err("debug register dump failed\n");
- return rc;
- }
- buf |= QPNP_VADC_HC1_DATA_HOLD_CTL_FIELD;
- rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_HC1_DATA_HOLD_CTL, &buf, 1);
- if (rc) {
- pr_err("debug register dump failed\n");
- return rc;
- }
-
- rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_HC1_DATA0, &rslt_lsb, 1);
- if (rc < 0) {
- pr_err("qpnp adc result read failed for data0\n");
- return rc;
- }
-
- rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_HC1_DATA1, &rslt_msb, 1);
- if (rc < 0) {
- pr_err("qpnp adc result read failed for data1\n");
- return rc;
- }
-
- *data = (rslt_msb << 8) | rslt_lsb;
-
- if (*data == QPNP_VADC_HC1_DATA_CHECK_USR) {
- pr_err("Invalid data :0x%x\n", *data);
- return -EINVAL;
- }
-
- rc = qpnp_vadc_enable(vadc, false);
- if (rc) {
- pr_err("VADC disable failed\n");
- return rc;
- }
-
- /* De-assert hold bit */
- buf &= ~QPNP_VADC_HC1_DATA_HOLD_CTL_FIELD;
- rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_HC1_DATA_HOLD_CTL, &buf, 1);
- if (rc)
- pr_err("de-asserting hold bit failed\n");
-
- return rc;
-}
-
-static void qpnp_vadc_hc_update_adc_dig_param(struct qpnp_vadc_chip *vadc,
- struct qpnp_adc_amux *amux_prop, u8 *data)
-{
- /* Update CAL value */
- *data &= ~QPNP_VADC_HC1_CAL_VAL;
- *data |= (amux_prop->cal_val << QPNP_VADC_HC1_CAL_VAL_SHIFT);
-
- /* Update CAL select */
- *data &= ~QPNP_VADC_HC1_CAL_SEL_MASK;
- *data |= (amux_prop->calib_type << QPNP_VADC_HC1_CAL_SEL_SHIFT);
-
- /* Update Decimation ratio select */
- *data &= ~QPNP_VADC_HC1_DEC_RATIO_SEL;
- *data |= (amux_prop->adc_decimation << QPNP_VADC_HC1_DEC_RATIO_SHIFT);
-
- pr_debug("VADC_DIG_PARAM value:0x%x\n", *data);
-}
-
-static int qpnp_vadc_hc_configure(struct qpnp_vadc_chip *vadc,
- struct qpnp_adc_amux *amux_prop)
-{
- int rc = 0;
- u8 buf[6];
-
- /* Read registers 0x42 through 0x46 */
- rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_HC1_ADC_DIG_PARAM, buf, 6);
- if (rc < 0) {
- pr_err("qpnp adc configure block read failed\n");
- return rc;
- }
-
- /* ADC Digital param selection */
- qpnp_vadc_hc_update_adc_dig_param(vadc, amux_prop, &buf[0]);
-
- /* Update fast average sample value */
- buf[1] &= (u8) ~QPNP_VADC_HC1_FAST_AVG_SAMPLES_MASK;
- buf[1] |= amux_prop->fast_avg_setup;
-
- /* Select ADC channel */
- buf[2] = amux_prop->channel_num;
-
- /* Select hw settle delay for the channel */
- buf[3] &= (u8) ~QPNP_VADC_HC1_DELAY_CTL_MASK;
- buf[3] |= amux_prop->hw_settle_time;
-
- /* Select ADC enable */
- buf[4] |= QPNP_VADC_HC1_ADC_EN;
-
- /* Select CONV request */
- buf[5] |= QPNP_VADC_HC1_CONV_REQ_START;
-
- if (!vadc->vadc_poll_eoc)
- reinit_completion(&vadc->adc->adc_rslt_completion);
-
- pr_debug("dig:0x%x, fast_avg:0x%x, channel:0x%x, hw_settle:0x%x\n",
- buf[0], buf[1], buf[2], buf[3]);
-
- /* Block register write from 0x42 through 0x46 */
- rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_HC1_ADC_DIG_PARAM, buf, 6);
- if (rc < 0) {
- pr_err("qpnp adc block register configure failed\n");
- return rc;
- }
-
- return 0;
-}
-
-int32_t qpnp_vadc_hc_read(struct qpnp_vadc_chip *vadc,
- enum qpnp_vadc_channels channel,
- struct qpnp_vadc_result *result)
-{
- int rc = 0, scale_type, amux_prescaling, dt_index = 0, calib_type = 0;
- struct qpnp_adc_amux amux_prop;
-
- if (qpnp_vadc_is_valid(vadc))
- return -EPROBE_DEFER;
-
- mutex_lock(&vadc->adc->adc_lock);
-
- while ((vadc->adc->adc_channels[dt_index].channel_num
- != channel) && (dt_index < vadc->max_channels_available))
- dt_index++;
-
- if (dt_index >= vadc->max_channels_available) {
- pr_err("not a valid VADC channel:%d\n", channel);
- rc = -EINVAL;
- goto fail_unlock;
- }
-
- calib_type = vadc->adc->adc_channels[dt_index].calib_type;
- if (calib_type >= ADC_HC_CAL_SEL_NONE) {
- pr_err("not a valid calib_type\n");
- rc = -EINVAL;
- goto fail_unlock;
- }
-
- amux_prop.adc_decimation =
- vadc->adc->adc_channels[dt_index].adc_decimation;
- amux_prop.calib_type = vadc->adc->adc_channels[dt_index].calib_type;
- amux_prop.cal_val = vadc->adc->adc_channels[dt_index].cal_val;
- amux_prop.fast_avg_setup =
- vadc->adc->adc_channels[dt_index].fast_avg_setup;
- amux_prop.channel_num = channel;
- amux_prop.hw_settle_time =
- vadc->adc->adc_channels[dt_index].hw_settle_time;
-
- rc = qpnp_vadc_hc_configure(vadc, &amux_prop);
- if (rc < 0) {
- pr_err("Configuring VADC channel failed with %d\n", rc);
- goto fail_unlock;
- }
-
- if (vadc->vadc_poll_eoc) {
- rc = qpnp_vadc_hc_check_conversion_status(vadc);
- if (rc < 0) {
- pr_err("polling mode conversion failed\n");
- goto fail_unlock;
- }
- } else {
- rc = wait_for_completion_timeout(
- &vadc->adc->adc_rslt_completion,
- QPNP_ADC_COMPLETION_TIMEOUT);
- if (!rc) {
- rc = qpnp_vadc_hc_check_conversion_status(vadc);
- if (rc < 0) {
- pr_err("interrupt mode conversion failed\n");
- goto fail_unlock;
- }
- pr_debug("End of conversion status set\n");
- }
- }
-
- rc = qpnp_vadc_hc_read_data(vadc, &result->adc_code);
- if (rc) {
- pr_err("qpnp vadc read adc code failed with %d\n", rc);
- goto fail_unlock;
- }
-
- amux_prescaling =
- vadc->adc->adc_channels[dt_index].chan_path_prescaling;
-
- if (amux_prescaling >= PATH_SCALING_NONE) {
- rc = -EINVAL;
- goto fail_unlock;
- }
-
- vadc->adc->amux_prop->chan_prop->offset_gain_numerator =
- qpnp_vadc_amux_scaling_ratio[amux_prescaling].num;
- vadc->adc->amux_prop->chan_prop->offset_gain_denominator =
- qpnp_vadc_amux_scaling_ratio[amux_prescaling].den;
-
- scale_type = vadc->adc->adc_channels[dt_index].adc_scale_fn;
- if (scale_type >= SCALE_NONE) {
- rc = -EBADF;
- goto fail_unlock;
- }
-
- /* Note: Scaling functions for VADC_HC do not need offset/gain */
- vadc_scale_fn[scale_type].chan(vadc, result->adc_code,
- vadc->adc->adc_prop, vadc->adc->amux_prop->chan_prop, result);
-
- pr_debug("channel=0x%x, adc_code=0x%x adc_result=%lld\n",
- channel, result->adc_code, result->physical);
-
-fail_unlock:
- mutex_unlock(&vadc->adc->adc_lock);
-
- return rc;
-}
-EXPORT_SYMBOL(qpnp_vadc_hc_read);
-
static ssize_t qpnp_adc_show(struct device *dev,
struct device_attribute *devattr, char *buf)
{
@@ -2609,7 +2694,6 @@ static int qpnp_vadc_probe(struct platform_device *pdev)
}
vadc->vadc_therm_chan = adc_thermal;
-
if (!strcmp(id->compatible, "qcom,qpnp-vadc-hc")) {
vadc->vadc_hc = true;
vadc->adc->adc_hc = true;