diff options
Diffstat (limited to 'drivers/hwmon')
-rw-r--r-- | drivers/hwmon/qpnp-adc-common.c | 94 | ||||
-rw-r--r-- | drivers/hwmon/qpnp-adc-voltage.c | 684 |
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, ¶m1, CALIB_RATIOMETRIC); - rc = qpnp_adc_map_temp_voltage(adcmap_100k_104ef_104fb, - ARRAY_SIZE(adcmap_100k_104ef_104fb), - param->low_thr_temp, ¶m->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, ¶m->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, ¶m->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; |