Loading Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt +1 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ Optional properties: -qcom,vadc-meas-int-mode : Enable VADC_USR to handle requests to perform recurring measurements for any one supported channel along with supporting single conversion requests. - qcom,vadc-recalib-check: Add this property to check if recalibration required due to inaccuracy. Client required property: - qcom,<consumer name>-vadc : The phandle to the corresponding vadc device. Loading Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt +1 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ Optional properties: 0 : Select Timer 1 for a measurement polling interval of 3.9 milliseconds. 1 : Select Timer 2 for a measurement polling interval of 1 second. 2 : Select Timer 3 for a measurement polling interval of 4 seconds. - qcom,adc-tm-recalib-check: Add this property to check if recalibration required due to inaccuracy. Client required property: - qcom,<consumer name>-adc_tm : The phandle to the corresponding adc_tm device. Loading drivers/hwmon/qpnp-adc-voltage.c +188 −113 Original line number Diff line number Diff line Loading @@ -96,8 +96,8 @@ #define QPNP_VADC_DATA0 0x60 #define QPNP_VADC_DATA1 0x61 #define QPNP_VADC_CONV_TIMEOUT_ERR 2 #define QPNP_VADC_CONV_TIME_MIN 2000 #define QPNP_VADC_CONV_TIME_MAX 2100 #define QPNP_VADC_CONV_TIME_MIN 1000 #define QPNP_VADC_CONV_TIME_MAX 1100 #define QPNP_ADC_COMPLETION_TIMEOUT HZ #define QPNP_VADC_ERR_COUNT 20 #define QPNP_OP_MODE_SHIFT 3 Loading @@ -107,6 +107,9 @@ #define QPNP_MIN_TIME 2000 #define QPNP_MAX_TIME 2000 #define QPNP_RETRY 100 #define QPNP_VADC_ABSOLUTE_RECALIB_OFFSET 8 #define QPNP_VADC_RATIOMETRIC_RECALIB_OFFSET 12 #define QPNP_VADC_RECALIB_MAXCNT 10 struct qpnp_vadc_mode_state { bool meas_int_mode; Loading @@ -128,6 +131,7 @@ struct qpnp_vadc_chip { u8 id; struct work_struct trigger_completion_work; bool vadc_poll_eoc; bool vadc_recalib_check; u8 revision_ana_minor; u8 revision_dig_major; struct workqueue_struct *high_thr_wq; Loading Loading @@ -198,7 +202,8 @@ static int32_t qpnp_vadc_warm_rst_configure(struct qpnp_vadc_chip *vadc) int rc = 0; u8 data = 0; rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_ACCESS, QPNP_VADC_ACCESS_DATA); rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_ACCESS, QPNP_VADC_ACCESS_DATA); if (rc < 0) { pr_err("VADC write access failed\n"); return rc; Loading @@ -210,7 +215,8 @@ static int32_t qpnp_vadc_warm_rst_configure(struct qpnp_vadc_chip *vadc) return rc; } rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_ACCESS, QPNP_VADC_ACCESS_DATA); rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_ACCESS, QPNP_VADC_ACCESS_DATA); if (rc < 0) { pr_err("VADC write access failed\n"); return rc; Loading Loading @@ -1055,14 +1061,19 @@ static void qpnp_vadc_625mv_channel_sel(struct qpnp_vadc_chip *vadc, } } static int32_t qpnp_vadc_calib_device(struct qpnp_vadc_chip *vadc) int32_t qpnp_vadc_calib_vref(struct qpnp_vadc_chip *vadc, enum qpnp_adc_calib_type calib_type, int *calib_data) { struct qpnp_adc_amux_properties conv; int rc, calib_read_1, calib_read_2, count = 0; int rc, count = 0, calib_read = 0; u8 status1 = 0; uint32_t ref_channel_sel = 0; 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; Loading @@ -1088,26 +1099,43 @@ static int32_t qpnp_vadc_calib_device(struct qpnp_vadc_chip *vadc) } } rc = qpnp_vadc_read_conversion_result(vadc, &calib_read_1); 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; } int32_t qpnp_vadc_calib_gnd(struct qpnp_vadc_chip *vadc, enum qpnp_adc_calib_type calib_type, int *calib_data) { struct qpnp_adc_amux_properties conv; int rc, count = 0, calib_read = 0; 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; 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; rc = qpnp_vadc_configure(vadc, &conv); if (rc) { pr_err("qpnp adc configure failed with %d\n", rc); pr_err("qpnp_vadc configure failed with %d\n", rc); goto calib_fail; } status1 = 0; count = 0; while (status1 != QPNP_VADC_STATUS1_EOC) { rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_STATUS1, &status1); if (rc < 0) Loading @@ -1122,12 +1150,30 @@ static int32_t qpnp_vadc_calib_device(struct qpnp_vadc_chip *vadc) } } rc = qpnp_vadc_read_conversion_result(vadc, &calib_read_2); 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; } static int32_t qpnp_vadc_calib_device(struct qpnp_vadc_chip *vadc) { int rc, calib_read_1 = 0, calib_read_2 = 0; rc = qpnp_vadc_calib_vref(vadc, CALIB_ABSOLUTE, &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); 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); Loading @@ -1147,73 +1193,19 @@ static int32_t qpnp_vadc_calib_device(struct qpnp_vadc_chip *vadc) calib_read_1; vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].adc_gnd = calib_read_2; /* Ratiometric Calibration */ 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; rc = qpnp_vadc_configure(vadc, &conv); if (rc) { pr_err("qpnp adc configure failed with %d\n", rc); goto calib_fail; } status1 = 0; count = 0; while (status1 != QPNP_VADC_STATUS1_EOC) { rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_STATUS1, &status1); if (rc < 0) return rc; status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK; usleep_range(QPNP_VADC_CONV_TIME_MIN, QPNP_VADC_CONV_TIME_MAX); count++; if (count > QPNP_VADC_ERR_COUNT) { rc = -ENODEV; goto calib_fail; } } rc = qpnp_vadc_read_conversion_result(vadc, &calib_read_1); if (rc) { pr_err("qpnp adc read adc failed with %d\n", rc); goto calib_fail; } 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; rc = qpnp_vadc_configure(vadc, &conv); calib_read_1 = 0; calib_read_2 = 0; rc = qpnp_vadc_calib_vref(vadc, CALIB_RATIOMETRIC, &calib_read_1); if (rc) { pr_err("qpnp adc configure failed with %d\n", rc); pr_err("qpnp adc ratiometric vref calib failed with %d\n", rc); goto calib_fail; } status1 = 0; count = 0; while (status1 != QPNP_VADC_STATUS1_EOC) { rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_STATUS1, &status1); if (rc < 0) return rc; status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK; usleep_range(QPNP_VADC_CONV_TIME_MIN, QPNP_VADC_CONV_TIME_MAX); count++; if (count > QPNP_VADC_ERR_COUNT) { rc = -ENODEV; goto calib_fail; } } rc = qpnp_vadc_read_conversion_result(vadc, &calib_read_2); rc = qpnp_vadc_calib_gnd(vadc, CALIB_RATIOMETRIC, &calib_read_2); if (rc) { pr_err("qpnp adc read adc failed with %d\n", rc); pr_err("qpnp adc ratiometric gnd calib failed with %d\n", rc); goto calib_fail; } pr_debug("ratiometric reference raw: VDD:0x%x GND:0x%x\n", calib_read_1, calib_read_2); Loading @@ -1228,10 +1220,10 @@ static int32_t qpnp_vadc_calib_device(struct qpnp_vadc_chip *vadc) (calib_read_1 - calib_read_2); vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dx = vadc->adc->adc_prop->adc_vdd_reference; vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].adc_vref = calib_read_1; vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].adc_gnd = calib_read_2; vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].adc_vref = calib_read_1; vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].adc_gnd = calib_read_2; calib_fail: return rc; Loading @@ -1246,6 +1238,7 @@ int32_t qpnp_get_vadc_gain_and_offset(struct qpnp_vadc_chip *vadc, rc = qpnp_vadc_is_valid(vadc); if (rc < 0) return rc; mutex_lock(&vadc->adc->adc_lock); switch (calib_type) { case CALIB_RATIOMETRIC: Loading @@ -1267,10 +1260,11 @@ int32_t qpnp_get_vadc_gain_and_offset(struct qpnp_vadc_chip *vadc, vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].adc_gnd; break; default: return -EINVAL; rc = -EINVAL; } return 0; mutex_unlock(&vadc->adc->adc_lock); return rc; } EXPORT_SYMBOL(qpnp_get_vadc_gain_and_offset); Loading Loading @@ -1415,8 +1409,10 @@ int32_t qpnp_vadc_conv_seq_request(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; uint32_t ref_channel, count = 0; int rc = 0, scale_type, amux_prescaling, dt_index = 0, calib_type = 0; uint32_t ref_channel, count = 0, local_idx = 0; int32_t vref_calib = 0, gnd_calib = 0, new_vref_calib = 0, offset = 0; int32_t calib_offset = 0; u8 status1 = 0; if (qpnp_vadc_is_valid(vadc)) Loading @@ -1427,19 +1423,6 @@ int32_t qpnp_vadc_conv_seq_request(struct qpnp_vadc_chip *vadc, if (vadc->state_copy->vadc_meas_int_enable) qpnp_vadc_manage_meas_int_requests(vadc); if (!vadc->vadc_init_calib) { rc = qpnp_vadc_version_check(vadc); if (rc) goto fail_unlock; rc = qpnp_vadc_calib_device(vadc); if (rc) { pr_err("Calibration failed\n"); goto fail_unlock; } else vadc->vadc_init_calib = true; } if (channel == REF_625MV) { qpnp_vadc_625mv_channel_sel(vadc, &ref_channel); channel = ref_channel; Loading @@ -1457,6 +1440,30 @@ int32_t qpnp_vadc_conv_seq_request(struct qpnp_vadc_chip *vadc, goto fail_unlock; } calib_type = vadc->adc->adc_channels[dt_index].calib_type; calib_offset = (calib_type == CALIB_ABSOLUTE) ? QPNP_VADC_ABSOLUTE_RECALIB_OFFSET : QPNP_VADC_RATIOMETRIC_RECALIB_OFFSET; rc = qpnp_vadc_version_check(vadc); if (rc) goto fail_unlock; if (vadc->vadc_recalib_check) { rc = qpnp_vadc_calib_vref(vadc, calib_type, &vref_calib); if (rc) { pr_err("Calibration failed\n"); goto fail_unlock; } } else 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; } } recalibrate: vadc->adc->amux_prop->decimation = vadc->adc->adc_channels[dt_index].adc_decimation; vadc->adc->amux_prop->hw_settle_time = Loading Loading @@ -1490,6 +1497,8 @@ int32_t qpnp_vadc_conv_seq_request(struct qpnp_vadc_chip *vadc, if (rc < 0) goto fail_unlock; status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK; if (status1 == QPNP_VADC_STATUS1_EOC) break; usleep_range(QPNP_VADC_CONV_TIME_MIN, QPNP_VADC_CONV_TIME_MAX); count++; Loading Loading @@ -1537,6 +1546,64 @@ int32_t qpnp_vadc_conv_seq_request(struct qpnp_vadc_chip *vadc, goto fail_unlock; } if (vadc->vadc_recalib_check) { rc = qpnp_vadc_calib_gnd(vadc, calib_type, &gnd_calib); if (rc) { pr_err("Calibration failed\n"); goto fail_unlock; } rc = qpnp_vadc_calib_vref(vadc, calib_type, &new_vref_calib); if (rc < 0) { pr_err("qpnp vadc calib read failed with %d\n", rc); goto fail_unlock; } if (local_idx >= QPNP_VADC_RECALIB_MAXCNT) { pr_err("invalid recalib count=%d\n", local_idx); rc = -EINVAL; goto fail_unlock; } pr_debug( "chan=%d, calib=%s, vref_calib=0x%x, gnd_calib=0x%x, new_vref_calib=0x%x\n", channel, ((calib_type == CALIB_ABSOLUTE) ? "ABSOLUTE" : "RATIOMETRIC"), vref_calib, gnd_calib, new_vref_calib); offset = (new_vref_calib - vref_calib); if (offset < 0) offset = -offset; if (offset <= calib_offset) { pr_debug( "qpnp vadc recalibration not required,offset:%d\n", offset); local_idx = 0; vadc->adc->amux_prop->chan_prop->adc_graph[calib_type].dy = (vref_calib - gnd_calib); vadc->adc->amux_prop->chan_prop->adc_graph[calib_type].dx = (calib_type == CALIB_ABSOLUTE) ? QPNP_ADC_625_UV : vadc->adc->adc_prop->adc_vdd_reference; vadc->adc->amux_prop->chan_prop->adc_graph[calib_type].adc_vref = vref_calib; vadc->adc->amux_prop->chan_prop->adc_graph[calib_type].adc_gnd = gnd_calib; } else { offset = 0; vref_calib = new_vref_calib; local_idx = local_idx + 1; if (local_idx >= QPNP_VADC_RECALIB_MAXCNT) { pr_err( "qpnp_vadc recalibration failed, count=%d", local_idx); } else { pr_debug( "qpnp vadc recalibration requested,offset:%d\n", offset); goto recalibrate; } } } amux_prescaling = vadc->adc->adc_channels[dt_index].chan_path_prescaling; Loading @@ -1561,6 +1628,9 @@ int32_t qpnp_vadc_conv_seq_request(struct qpnp_vadc_chip *vadc, vadc_scale_fn[scale_type].chan(vadc, result->adc_code, vadc->adc->adc_prop, vadc->adc->amux_prop->chan_prop, result); pr_debug("channel=%d, adc_code=%d adc_result=%lld\n", channel, result->adc_code, result->physical); fail_unlock: if (vadc->state_copy->vadc_meas_int_enable) qpnp_vadc_manage_meas_int_requests(vadc); Loading Loading @@ -1618,25 +1688,13 @@ static void qpnp_vadc_unlock(struct qpnp_vadc_chip *vadc) int32_t qpnp_vadc_iadc_sync_request(struct qpnp_vadc_chip *vadc, enum qpnp_vadc_channels channel) { int rc = 0, dt_index = 0; int rc = 0, dt_index = 0, calib_type = 0; if (qpnp_vadc_is_valid(vadc)) return -EPROBE_DEFER; qpnp_vadc_lock(vadc); if (!vadc->vadc_init_calib) { rc = qpnp_vadc_version_check(vadc); if (rc) goto fail; rc = qpnp_vadc_calib_device(vadc); if (rc) { pr_err("Calibration failed\n"); goto fail; } else vadc->vadc_init_calib = true; } vadc->adc->amux_prop->amux_channel = channel; Loading @@ -1650,6 +1708,20 @@ int32_t qpnp_vadc_iadc_sync_request(struct qpnp_vadc_chip *vadc, goto fail; } calib_type = vadc->adc->adc_channels[dt_index].calib_type; if (!vadc->vadc_init_calib) { rc = qpnp_vadc_version_check(vadc); if (rc) goto fail; rc = qpnp_vadc_calib_device(vadc); if (rc) { pr_err("Calibration failed\n"); goto fail; } else vadc->vadc_init_calib = true; } vadc->adc->amux_prop->decimation = vadc->adc->adc_channels[dt_index].adc_decimation; vadc->adc->amux_prop->hw_settle_time = Loading Loading @@ -2032,6 +2104,9 @@ static int qpnp_vadc_probe(struct spmi_device *spmi) INIT_WORK(&vadc->trigger_completion_work, qpnp_vadc_work); vadc->vadc_recalib_check = of_property_read_bool(node, "qcom,vadc-recalib-check"); vadc->vadc_poll_eoc = of_property_read_bool(node, "qcom,vadc-poll-eoc"); if (!vadc->vadc_poll_eoc) { Loading drivers/thermal/qpnp-adc-tm.c +213 −2 Original line number Diff line number Diff line Loading @@ -207,6 +207,7 @@ struct qpnp_adc_tm_chip { struct qpnp_adc_drv *adc; struct list_head list; bool adc_tm_initialized; bool adc_tm_recalib_check; int max_channels_available; atomic_t wq_cnt; struct qpnp_vadc_chip *vadc_dev; Loading Loading @@ -679,6 +680,62 @@ static int32_t qpnp_adc_tm_reg_update(struct qpnp_adc_tm_chip *chip, return rc; } static int32_t qpnp_adc_tm_read_thr_value(struct qpnp_adc_tm_chip *chip, uint32_t btm_chan) { int rc = 0; u8 data_lsb = 0, data_msb = 0; uint32_t btm_chan_idx = 0; int32_t low_thr = 0, high_thr = 0; rc = qpnp_adc_tm_get_btm_idx(btm_chan, &btm_chan_idx); if (rc < 0) { pr_err("Invalid btm channel idx\n"); return rc; } rc = qpnp_adc_tm_read_reg(chip, adc_tm_data[btm_chan_idx].low_thr_lsb_addr, &data_lsb); if (rc < 0) { pr_err("low threshold lsb setting failed\n"); return rc; } rc = qpnp_adc_tm_read_reg(chip, adc_tm_data[btm_chan_idx].low_thr_msb_addr, &data_msb); if (rc < 0) { pr_err("low threshold msb setting failed\n"); return rc; } low_thr = (data_msb << 8) | data_lsb; rc = qpnp_adc_tm_read_reg(chip, adc_tm_data[btm_chan_idx].high_thr_lsb_addr, &data_lsb); if (rc < 0) { pr_err("high threshold lsb setting failed\n"); return rc; } rc = qpnp_adc_tm_read_reg(chip, adc_tm_data[btm_chan_idx].high_thr_msb_addr, &data_msb); if (rc < 0) { pr_err("high threshold msb setting failed\n"); return rc; } high_thr = (data_msb << 8) | data_lsb; pr_debug("configured thresholds high:0x%x and low:0x%x\n", high_thr, low_thr); return rc; } static int32_t qpnp_adc_tm_thr_update(struct qpnp_adc_tm_chip *chip, uint32_t btm_chan, int32_t high_thr, int32_t low_thr) { Loading Loading @@ -1410,10 +1467,148 @@ static int qpnp_adc_tm_activate_trip_type(struct thermal_zone_device *thermal, return rc; } static int qpnp_adc_tm_recalib_request_check(struct qpnp_adc_tm_chip *chip, int sensor_num, u8 status_high, u8 *notify_check) { int rc = 0; u8 sensor_mask = 0, mode_ctl = 0; int32_t old_thr = 0, new_thr = 0; uint32_t channel, btm_chan_num, scale_type; struct qpnp_vadc_result result; struct qpnp_adc_thr_client_info *client_info = NULL; struct list_head *thr_list; bool status = false; if (!chip->adc_tm_recalib_check) { *notify_check = 1; return rc; } list_for_each(thr_list, &chip->sensor[sensor_num].thr_list) { client_info = list_entry(thr_list, struct qpnp_adc_thr_client_info, list); channel = client_info->btm_param->channel; btm_chan_num = chip->sensor[sensor_num].btm_channel_num; sensor_mask = 1 << sensor_num; rc = qpnp_vadc_read(chip->vadc_dev, channel, &result); if (rc < 0) { pr_err("failure to read vadc channel=%d\n", client_info->btm_param->channel); goto fail; } new_thr = result.physical; if (status_high) old_thr = client_info->btm_param->high_thr; else old_thr = client_info->btm_param->low_thr; if (new_thr > old_thr) status = (status_high) ? true : false; else status = (status_high) ? false : true; pr_debug( "recalib:sen=%d, new_thr=%d, new_thr_adc_code=0x%x, old_thr=%d status=%d valid_status=%d\n", sensor_num, new_thr, result.adc_code, old_thr, status_high, status); rc = qpnp_adc_tm_read_thr_value(chip, btm_chan_num); if (rc < 0) { pr_err("adc-tm thresholds read failed\n"); goto fail; } if (status) { *notify_check = 1; pr_debug("Client can be notify\n"); return rc; } pr_debug("Client can not be notify, restart measurement\n"); /* Set measurement in single measurement mode */ mode_ctl = ADC_OP_NORMAL_MODE << QPNP_OP_MODE_SHIFT; rc = qpnp_adc_tm_mode_select(chip, mode_ctl); if (rc < 0) { pr_err("adc-tm single mode select failed\n"); goto fail; } /* Disable bank */ rc = qpnp_adc_tm_disable(chip); if (rc < 0) { pr_err("adc-tm disable failed\n"); goto fail; } /* Check if a conversion is in progress */ rc = qpnp_adc_tm_req_sts_check(chip); if (rc < 0) { pr_err("adc-tm req_sts check failed\n"); goto fail; } rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_LOW_THR_INT_EN, sensor_mask, false); if (rc < 0) { pr_err("low threshold int write failed\n"); goto fail; } rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_HIGH_THR_INT_EN, sensor_mask, false); if (rc < 0) { pr_err("high threshold int enable failed\n"); goto fail; } rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_MULTI_MEAS_EN, sensor_mask, false); if (rc < 0) { pr_err("multi measurement en failed\n"); goto fail; } /* restart measurement */ scale_type = chip->sensor[sensor_num].scale_type; chip->adc->amux_prop->amux_channel = channel; chip->adc->amux_prop->decimation = chip->adc->adc_channels[sensor_num].adc_decimation; chip->adc->amux_prop->hw_settle_time = chip->adc->adc_channels[sensor_num].hw_settle_time; chip->adc->amux_prop->fast_avg_setup = chip->adc->adc_channels[sensor_num].fast_avg_setup; chip->adc->amux_prop->mode_sel = ADC_OP_MEASUREMENT_INTERVAL << QPNP_OP_MODE_SHIFT; adc_tm_rscale_fn[scale_type].chan(chip->vadc_dev, client_info->btm_param, &chip->adc->amux_prop->chan_prop->low_thr, &chip->adc->amux_prop->chan_prop->high_thr); qpnp_adc_tm_add_to_list(chip, sensor_num, client_info->btm_param, chip->adc->amux_prop->chan_prop); chip->adc->amux_prop->chan_prop->tm_channel_select = chip->sensor[sensor_num].btm_channel_num; chip->adc->amux_prop->chan_prop->state_request = client_info->btm_param->state_request; rc = qpnp_adc_tm_configure(chip, chip->adc->amux_prop); if (rc) { pr_err("adc-tm configure failed with %d\n", rc); goto fail; } *notify_check = 0; pr_debug("BTM channel reconfigured for measuremnt\n"); } fail: return rc; } static int qpnp_adc_tm_read_status(struct qpnp_adc_tm_chip *chip) { u8 status_low = 0, status_high = 0, qpnp_adc_tm_meas_en = 0; u8 adc_tm_low_enable = 0, adc_tm_high_enable = 0; u8 adc_tm_low_enable = 0, adc_tm_high_enable = 0, notify_check = 0; u8 sensor_mask = 0, adc_tm_low_thr_set = 0, adc_tm_high_thr_set = 0; int rc = 0, sensor_notify_num = 0, i = 0, sensor_num = 0; uint32_t btm_chan_num = 0; Loading Loading @@ -1489,6 +1684,13 @@ static int qpnp_adc_tm_read_status(struct qpnp_adc_tm_chip *chip) such as usb_id, vbatt, pmic_therm */ sensor_mask = 1 << sensor_num; pr_debug("non thermal node - mask:%x\n", sensor_mask); rc = qpnp_adc_tm_recalib_request_check(chip, sensor_num, true, ¬ify_check); if (rc < 0 || !notify_check) { pr_debug("Calib recheck re-armed rc=%d\n", rc); adc_tm_high_enable = 0; goto fail; } rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_HIGH_THR_INT_EN, sensor_mask, false); Loading Loading @@ -1545,6 +1747,13 @@ static int qpnp_adc_tm_read_status(struct qpnp_adc_tm_chip *chip) /* For non thermal registered clients such as usb_id, vbatt, pmic_therm */ pr_debug("non thermal node - mask:%x\n", sensor_mask); rc = qpnp_adc_tm_recalib_request_check(chip, sensor_num, false, ¬ify_check); if (rc < 0 || !notify_check) { pr_debug("Calib recheck re-armed rc=%d\n", rc); adc_tm_low_enable = 0; goto fail; } sensor_mask = 1 << sensor_num; rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_LOW_THR_INT_EN, Loading Loading @@ -1611,7 +1820,7 @@ fail: if (adc_tm_high_enable || adc_tm_low_enable) queue_work(chip->sensor[sensor_num].req_wq, &chip->sensor[sensor_num].work); if (rc < 0) if (rc < 0 || (!adc_tm_high_enable && !adc_tm_low_enable)) atomic_dec(&chip->wq_cnt); return rc; Loading Loading @@ -1971,6 +2180,8 @@ static int qpnp_adc_tm_probe(struct spmi_device *spmi) pr_err("vadc property missing, rc=%d\n", rc); goto fail; } chip->adc_tm_recalib_check = of_property_read_bool(node, "qcom,adc-tm-recalib-check"); for_each_child_of_node(node, child) { char name[25]; Loading include/linux/qpnp/qpnp-adc.h +46 −0 Original line number Diff line number Diff line Loading @@ -150,6 +150,24 @@ struct qpnp_iadc_chip; /* Structure device for qpnp adc tm */ struct qpnp_adc_tm_chip; /** * enum qpnp_adc_clk_type - Clock rate supported. * %CLK_TYPE1: 2P4MHZ * %CLK_TYPE2: 4P8MHZ * %CLK_TYPE3: 9P6MHZ * %CLK_TYPE4: 19P2MHZ * %CLK_NONE: Do not use this Clk type. * * The Clock rate is specific to each channel of the QPNP ADC arbiter. */ enum qpnp_adc_clk_type { CLK_TYPE1 = 0, CLK_TYPE2, CLK_TYPE3, CLK_TYPE4, CLK_NONE, }; /** * enum qpnp_adc_decimation_type - Sampling rate supported. * %DECIMATION_TYPE1: 512 Loading Loading @@ -1542,6 +1560,25 @@ int32_t qpnp_vadc_channel_monitor(struct qpnp_vadc_chip *chip, * @param: device instance for the VADC */ int32_t qpnp_vadc_end_channel_monitor(struct qpnp_vadc_chip *chip); /** * qpnp_vadc_calib_vref() - Read calibration channel REF_125V/VDD_VADC * @dev: Structure device for qpnp vadc * @calib_type: absolute or ratiometric calib type. * returns calibration channel adc code. */ int32_t qpnp_vadc_calib_vref(struct qpnp_vadc_chip *vadc, enum qpnp_adc_calib_type calib_type, int *calib_data); /** * qpnp_vadc_calib_gnd() - Read calibration channel REF_625MV/GND_REF * @dev: Structure device for qpnp vadc * @calib_type: absolute or ratiometric calib type. * returns calibration channel adc code. */ int32_t qpnp_vadc_calib_gnd(struct qpnp_vadc_chip *vadc, enum qpnp_adc_calib_type calib_type, int *calib_data); #else static inline int32_t qpnp_vadc_read(struct qpnp_vadc_chip *dev, uint32_t channel, Loading Loading @@ -1692,6 +1729,15 @@ static inline int32_t qpnp_vadc_channel_monitor(struct qpnp_vadc_chip *chip, { return -ENXIO; } static inline int32_t qpnp_vadc_end_channel_monitor(struct qpnp_vadc_chip *chip) { return -ENXIO; } static int32_t qpnp_vadc_calib_vref(struct qpnp_vadc_chip *vadc, enum qpnp_adc_calib_type calib_type, int *calib_data) { return -ENXIO; } static int32_t qpnp_vadc_calib_gnd(struct qpnp_vadc_chip *vadc, enum qpnp_adc_calib_type calib_type, int *calib_data) { return -ENXIO; } #endif /* Public API */ Loading Loading
Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt +1 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ Optional properties: -qcom,vadc-meas-int-mode : Enable VADC_USR to handle requests to perform recurring measurements for any one supported channel along with supporting single conversion requests. - qcom,vadc-recalib-check: Add this property to check if recalibration required due to inaccuracy. Client required property: - qcom,<consumer name>-vadc : The phandle to the corresponding vadc device. Loading
Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt +1 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ Optional properties: 0 : Select Timer 1 for a measurement polling interval of 3.9 milliseconds. 1 : Select Timer 2 for a measurement polling interval of 1 second. 2 : Select Timer 3 for a measurement polling interval of 4 seconds. - qcom,adc-tm-recalib-check: Add this property to check if recalibration required due to inaccuracy. Client required property: - qcom,<consumer name>-adc_tm : The phandle to the corresponding adc_tm device. Loading
drivers/hwmon/qpnp-adc-voltage.c +188 −113 Original line number Diff line number Diff line Loading @@ -96,8 +96,8 @@ #define QPNP_VADC_DATA0 0x60 #define QPNP_VADC_DATA1 0x61 #define QPNP_VADC_CONV_TIMEOUT_ERR 2 #define QPNP_VADC_CONV_TIME_MIN 2000 #define QPNP_VADC_CONV_TIME_MAX 2100 #define QPNP_VADC_CONV_TIME_MIN 1000 #define QPNP_VADC_CONV_TIME_MAX 1100 #define QPNP_ADC_COMPLETION_TIMEOUT HZ #define QPNP_VADC_ERR_COUNT 20 #define QPNP_OP_MODE_SHIFT 3 Loading @@ -107,6 +107,9 @@ #define QPNP_MIN_TIME 2000 #define QPNP_MAX_TIME 2000 #define QPNP_RETRY 100 #define QPNP_VADC_ABSOLUTE_RECALIB_OFFSET 8 #define QPNP_VADC_RATIOMETRIC_RECALIB_OFFSET 12 #define QPNP_VADC_RECALIB_MAXCNT 10 struct qpnp_vadc_mode_state { bool meas_int_mode; Loading @@ -128,6 +131,7 @@ struct qpnp_vadc_chip { u8 id; struct work_struct trigger_completion_work; bool vadc_poll_eoc; bool vadc_recalib_check; u8 revision_ana_minor; u8 revision_dig_major; struct workqueue_struct *high_thr_wq; Loading Loading @@ -198,7 +202,8 @@ static int32_t qpnp_vadc_warm_rst_configure(struct qpnp_vadc_chip *vadc) int rc = 0; u8 data = 0; rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_ACCESS, QPNP_VADC_ACCESS_DATA); rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_ACCESS, QPNP_VADC_ACCESS_DATA); if (rc < 0) { pr_err("VADC write access failed\n"); return rc; Loading @@ -210,7 +215,8 @@ static int32_t qpnp_vadc_warm_rst_configure(struct qpnp_vadc_chip *vadc) return rc; } rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_ACCESS, QPNP_VADC_ACCESS_DATA); rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_ACCESS, QPNP_VADC_ACCESS_DATA); if (rc < 0) { pr_err("VADC write access failed\n"); return rc; Loading Loading @@ -1055,14 +1061,19 @@ static void qpnp_vadc_625mv_channel_sel(struct qpnp_vadc_chip *vadc, } } static int32_t qpnp_vadc_calib_device(struct qpnp_vadc_chip *vadc) int32_t qpnp_vadc_calib_vref(struct qpnp_vadc_chip *vadc, enum qpnp_adc_calib_type calib_type, int *calib_data) { struct qpnp_adc_amux_properties conv; int rc, calib_read_1, calib_read_2, count = 0; int rc, count = 0, calib_read = 0; u8 status1 = 0; uint32_t ref_channel_sel = 0; 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; Loading @@ -1088,26 +1099,43 @@ static int32_t qpnp_vadc_calib_device(struct qpnp_vadc_chip *vadc) } } rc = qpnp_vadc_read_conversion_result(vadc, &calib_read_1); 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; } int32_t qpnp_vadc_calib_gnd(struct qpnp_vadc_chip *vadc, enum qpnp_adc_calib_type calib_type, int *calib_data) { struct qpnp_adc_amux_properties conv; int rc, count = 0, calib_read = 0; 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; 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; rc = qpnp_vadc_configure(vadc, &conv); if (rc) { pr_err("qpnp adc configure failed with %d\n", rc); pr_err("qpnp_vadc configure failed with %d\n", rc); goto calib_fail; } status1 = 0; count = 0; while (status1 != QPNP_VADC_STATUS1_EOC) { rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_STATUS1, &status1); if (rc < 0) Loading @@ -1122,12 +1150,30 @@ static int32_t qpnp_vadc_calib_device(struct qpnp_vadc_chip *vadc) } } rc = qpnp_vadc_read_conversion_result(vadc, &calib_read_2); 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; } static int32_t qpnp_vadc_calib_device(struct qpnp_vadc_chip *vadc) { int rc, calib_read_1 = 0, calib_read_2 = 0; rc = qpnp_vadc_calib_vref(vadc, CALIB_ABSOLUTE, &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); 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); Loading @@ -1147,73 +1193,19 @@ static int32_t qpnp_vadc_calib_device(struct qpnp_vadc_chip *vadc) calib_read_1; vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].adc_gnd = calib_read_2; /* Ratiometric Calibration */ 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; rc = qpnp_vadc_configure(vadc, &conv); if (rc) { pr_err("qpnp adc configure failed with %d\n", rc); goto calib_fail; } status1 = 0; count = 0; while (status1 != QPNP_VADC_STATUS1_EOC) { rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_STATUS1, &status1); if (rc < 0) return rc; status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK; usleep_range(QPNP_VADC_CONV_TIME_MIN, QPNP_VADC_CONV_TIME_MAX); count++; if (count > QPNP_VADC_ERR_COUNT) { rc = -ENODEV; goto calib_fail; } } rc = qpnp_vadc_read_conversion_result(vadc, &calib_read_1); if (rc) { pr_err("qpnp adc read adc failed with %d\n", rc); goto calib_fail; } 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; rc = qpnp_vadc_configure(vadc, &conv); calib_read_1 = 0; calib_read_2 = 0; rc = qpnp_vadc_calib_vref(vadc, CALIB_RATIOMETRIC, &calib_read_1); if (rc) { pr_err("qpnp adc configure failed with %d\n", rc); pr_err("qpnp adc ratiometric vref calib failed with %d\n", rc); goto calib_fail; } status1 = 0; count = 0; while (status1 != QPNP_VADC_STATUS1_EOC) { rc = qpnp_vadc_read_reg(vadc, QPNP_VADC_STATUS1, &status1); if (rc < 0) return rc; status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK; usleep_range(QPNP_VADC_CONV_TIME_MIN, QPNP_VADC_CONV_TIME_MAX); count++; if (count > QPNP_VADC_ERR_COUNT) { rc = -ENODEV; goto calib_fail; } } rc = qpnp_vadc_read_conversion_result(vadc, &calib_read_2); rc = qpnp_vadc_calib_gnd(vadc, CALIB_RATIOMETRIC, &calib_read_2); if (rc) { pr_err("qpnp adc read adc failed with %d\n", rc); pr_err("qpnp adc ratiometric gnd calib failed with %d\n", rc); goto calib_fail; } pr_debug("ratiometric reference raw: VDD:0x%x GND:0x%x\n", calib_read_1, calib_read_2); Loading @@ -1228,10 +1220,10 @@ static int32_t qpnp_vadc_calib_device(struct qpnp_vadc_chip *vadc) (calib_read_1 - calib_read_2); vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].dx = vadc->adc->adc_prop->adc_vdd_reference; vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].adc_vref = calib_read_1; vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].adc_gnd = calib_read_2; vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].adc_vref = calib_read_1; vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_RATIOMETRIC].adc_gnd = calib_read_2; calib_fail: return rc; Loading @@ -1246,6 +1238,7 @@ int32_t qpnp_get_vadc_gain_and_offset(struct qpnp_vadc_chip *vadc, rc = qpnp_vadc_is_valid(vadc); if (rc < 0) return rc; mutex_lock(&vadc->adc->adc_lock); switch (calib_type) { case CALIB_RATIOMETRIC: Loading @@ -1267,10 +1260,11 @@ int32_t qpnp_get_vadc_gain_and_offset(struct qpnp_vadc_chip *vadc, vadc->adc->amux_prop->chan_prop->adc_graph[CALIB_ABSOLUTE].adc_gnd; break; default: return -EINVAL; rc = -EINVAL; } return 0; mutex_unlock(&vadc->adc->adc_lock); return rc; } EXPORT_SYMBOL(qpnp_get_vadc_gain_and_offset); Loading Loading @@ -1415,8 +1409,10 @@ int32_t qpnp_vadc_conv_seq_request(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; uint32_t ref_channel, count = 0; int rc = 0, scale_type, amux_prescaling, dt_index = 0, calib_type = 0; uint32_t ref_channel, count = 0, local_idx = 0; int32_t vref_calib = 0, gnd_calib = 0, new_vref_calib = 0, offset = 0; int32_t calib_offset = 0; u8 status1 = 0; if (qpnp_vadc_is_valid(vadc)) Loading @@ -1427,19 +1423,6 @@ int32_t qpnp_vadc_conv_seq_request(struct qpnp_vadc_chip *vadc, if (vadc->state_copy->vadc_meas_int_enable) qpnp_vadc_manage_meas_int_requests(vadc); if (!vadc->vadc_init_calib) { rc = qpnp_vadc_version_check(vadc); if (rc) goto fail_unlock; rc = qpnp_vadc_calib_device(vadc); if (rc) { pr_err("Calibration failed\n"); goto fail_unlock; } else vadc->vadc_init_calib = true; } if (channel == REF_625MV) { qpnp_vadc_625mv_channel_sel(vadc, &ref_channel); channel = ref_channel; Loading @@ -1457,6 +1440,30 @@ int32_t qpnp_vadc_conv_seq_request(struct qpnp_vadc_chip *vadc, goto fail_unlock; } calib_type = vadc->adc->adc_channels[dt_index].calib_type; calib_offset = (calib_type == CALIB_ABSOLUTE) ? QPNP_VADC_ABSOLUTE_RECALIB_OFFSET : QPNP_VADC_RATIOMETRIC_RECALIB_OFFSET; rc = qpnp_vadc_version_check(vadc); if (rc) goto fail_unlock; if (vadc->vadc_recalib_check) { rc = qpnp_vadc_calib_vref(vadc, calib_type, &vref_calib); if (rc) { pr_err("Calibration failed\n"); goto fail_unlock; } } else 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; } } recalibrate: vadc->adc->amux_prop->decimation = vadc->adc->adc_channels[dt_index].adc_decimation; vadc->adc->amux_prop->hw_settle_time = Loading Loading @@ -1490,6 +1497,8 @@ int32_t qpnp_vadc_conv_seq_request(struct qpnp_vadc_chip *vadc, if (rc < 0) goto fail_unlock; status1 &= QPNP_VADC_STATUS1_REQ_STS_EOC_MASK; if (status1 == QPNP_VADC_STATUS1_EOC) break; usleep_range(QPNP_VADC_CONV_TIME_MIN, QPNP_VADC_CONV_TIME_MAX); count++; Loading Loading @@ -1537,6 +1546,64 @@ int32_t qpnp_vadc_conv_seq_request(struct qpnp_vadc_chip *vadc, goto fail_unlock; } if (vadc->vadc_recalib_check) { rc = qpnp_vadc_calib_gnd(vadc, calib_type, &gnd_calib); if (rc) { pr_err("Calibration failed\n"); goto fail_unlock; } rc = qpnp_vadc_calib_vref(vadc, calib_type, &new_vref_calib); if (rc < 0) { pr_err("qpnp vadc calib read failed with %d\n", rc); goto fail_unlock; } if (local_idx >= QPNP_VADC_RECALIB_MAXCNT) { pr_err("invalid recalib count=%d\n", local_idx); rc = -EINVAL; goto fail_unlock; } pr_debug( "chan=%d, calib=%s, vref_calib=0x%x, gnd_calib=0x%x, new_vref_calib=0x%x\n", channel, ((calib_type == CALIB_ABSOLUTE) ? "ABSOLUTE" : "RATIOMETRIC"), vref_calib, gnd_calib, new_vref_calib); offset = (new_vref_calib - vref_calib); if (offset < 0) offset = -offset; if (offset <= calib_offset) { pr_debug( "qpnp vadc recalibration not required,offset:%d\n", offset); local_idx = 0; vadc->adc->amux_prop->chan_prop->adc_graph[calib_type].dy = (vref_calib - gnd_calib); vadc->adc->amux_prop->chan_prop->adc_graph[calib_type].dx = (calib_type == CALIB_ABSOLUTE) ? QPNP_ADC_625_UV : vadc->adc->adc_prop->adc_vdd_reference; vadc->adc->amux_prop->chan_prop->adc_graph[calib_type].adc_vref = vref_calib; vadc->adc->amux_prop->chan_prop->adc_graph[calib_type].adc_gnd = gnd_calib; } else { offset = 0; vref_calib = new_vref_calib; local_idx = local_idx + 1; if (local_idx >= QPNP_VADC_RECALIB_MAXCNT) { pr_err( "qpnp_vadc recalibration failed, count=%d", local_idx); } else { pr_debug( "qpnp vadc recalibration requested,offset:%d\n", offset); goto recalibrate; } } } amux_prescaling = vadc->adc->adc_channels[dt_index].chan_path_prescaling; Loading @@ -1561,6 +1628,9 @@ int32_t qpnp_vadc_conv_seq_request(struct qpnp_vadc_chip *vadc, vadc_scale_fn[scale_type].chan(vadc, result->adc_code, vadc->adc->adc_prop, vadc->adc->amux_prop->chan_prop, result); pr_debug("channel=%d, adc_code=%d adc_result=%lld\n", channel, result->adc_code, result->physical); fail_unlock: if (vadc->state_copy->vadc_meas_int_enable) qpnp_vadc_manage_meas_int_requests(vadc); Loading Loading @@ -1618,25 +1688,13 @@ static void qpnp_vadc_unlock(struct qpnp_vadc_chip *vadc) int32_t qpnp_vadc_iadc_sync_request(struct qpnp_vadc_chip *vadc, enum qpnp_vadc_channels channel) { int rc = 0, dt_index = 0; int rc = 0, dt_index = 0, calib_type = 0; if (qpnp_vadc_is_valid(vadc)) return -EPROBE_DEFER; qpnp_vadc_lock(vadc); if (!vadc->vadc_init_calib) { rc = qpnp_vadc_version_check(vadc); if (rc) goto fail; rc = qpnp_vadc_calib_device(vadc); if (rc) { pr_err("Calibration failed\n"); goto fail; } else vadc->vadc_init_calib = true; } vadc->adc->amux_prop->amux_channel = channel; Loading @@ -1650,6 +1708,20 @@ int32_t qpnp_vadc_iadc_sync_request(struct qpnp_vadc_chip *vadc, goto fail; } calib_type = vadc->adc->adc_channels[dt_index].calib_type; if (!vadc->vadc_init_calib) { rc = qpnp_vadc_version_check(vadc); if (rc) goto fail; rc = qpnp_vadc_calib_device(vadc); if (rc) { pr_err("Calibration failed\n"); goto fail; } else vadc->vadc_init_calib = true; } vadc->adc->amux_prop->decimation = vadc->adc->adc_channels[dt_index].adc_decimation; vadc->adc->amux_prop->hw_settle_time = Loading Loading @@ -2032,6 +2104,9 @@ static int qpnp_vadc_probe(struct spmi_device *spmi) INIT_WORK(&vadc->trigger_completion_work, qpnp_vadc_work); vadc->vadc_recalib_check = of_property_read_bool(node, "qcom,vadc-recalib-check"); vadc->vadc_poll_eoc = of_property_read_bool(node, "qcom,vadc-poll-eoc"); if (!vadc->vadc_poll_eoc) { Loading
drivers/thermal/qpnp-adc-tm.c +213 −2 Original line number Diff line number Diff line Loading @@ -207,6 +207,7 @@ struct qpnp_adc_tm_chip { struct qpnp_adc_drv *adc; struct list_head list; bool adc_tm_initialized; bool adc_tm_recalib_check; int max_channels_available; atomic_t wq_cnt; struct qpnp_vadc_chip *vadc_dev; Loading Loading @@ -679,6 +680,62 @@ static int32_t qpnp_adc_tm_reg_update(struct qpnp_adc_tm_chip *chip, return rc; } static int32_t qpnp_adc_tm_read_thr_value(struct qpnp_adc_tm_chip *chip, uint32_t btm_chan) { int rc = 0; u8 data_lsb = 0, data_msb = 0; uint32_t btm_chan_idx = 0; int32_t low_thr = 0, high_thr = 0; rc = qpnp_adc_tm_get_btm_idx(btm_chan, &btm_chan_idx); if (rc < 0) { pr_err("Invalid btm channel idx\n"); return rc; } rc = qpnp_adc_tm_read_reg(chip, adc_tm_data[btm_chan_idx].low_thr_lsb_addr, &data_lsb); if (rc < 0) { pr_err("low threshold lsb setting failed\n"); return rc; } rc = qpnp_adc_tm_read_reg(chip, adc_tm_data[btm_chan_idx].low_thr_msb_addr, &data_msb); if (rc < 0) { pr_err("low threshold msb setting failed\n"); return rc; } low_thr = (data_msb << 8) | data_lsb; rc = qpnp_adc_tm_read_reg(chip, adc_tm_data[btm_chan_idx].high_thr_lsb_addr, &data_lsb); if (rc < 0) { pr_err("high threshold lsb setting failed\n"); return rc; } rc = qpnp_adc_tm_read_reg(chip, adc_tm_data[btm_chan_idx].high_thr_msb_addr, &data_msb); if (rc < 0) { pr_err("high threshold msb setting failed\n"); return rc; } high_thr = (data_msb << 8) | data_lsb; pr_debug("configured thresholds high:0x%x and low:0x%x\n", high_thr, low_thr); return rc; } static int32_t qpnp_adc_tm_thr_update(struct qpnp_adc_tm_chip *chip, uint32_t btm_chan, int32_t high_thr, int32_t low_thr) { Loading Loading @@ -1410,10 +1467,148 @@ static int qpnp_adc_tm_activate_trip_type(struct thermal_zone_device *thermal, return rc; } static int qpnp_adc_tm_recalib_request_check(struct qpnp_adc_tm_chip *chip, int sensor_num, u8 status_high, u8 *notify_check) { int rc = 0; u8 sensor_mask = 0, mode_ctl = 0; int32_t old_thr = 0, new_thr = 0; uint32_t channel, btm_chan_num, scale_type; struct qpnp_vadc_result result; struct qpnp_adc_thr_client_info *client_info = NULL; struct list_head *thr_list; bool status = false; if (!chip->adc_tm_recalib_check) { *notify_check = 1; return rc; } list_for_each(thr_list, &chip->sensor[sensor_num].thr_list) { client_info = list_entry(thr_list, struct qpnp_adc_thr_client_info, list); channel = client_info->btm_param->channel; btm_chan_num = chip->sensor[sensor_num].btm_channel_num; sensor_mask = 1 << sensor_num; rc = qpnp_vadc_read(chip->vadc_dev, channel, &result); if (rc < 0) { pr_err("failure to read vadc channel=%d\n", client_info->btm_param->channel); goto fail; } new_thr = result.physical; if (status_high) old_thr = client_info->btm_param->high_thr; else old_thr = client_info->btm_param->low_thr; if (new_thr > old_thr) status = (status_high) ? true : false; else status = (status_high) ? false : true; pr_debug( "recalib:sen=%d, new_thr=%d, new_thr_adc_code=0x%x, old_thr=%d status=%d valid_status=%d\n", sensor_num, new_thr, result.adc_code, old_thr, status_high, status); rc = qpnp_adc_tm_read_thr_value(chip, btm_chan_num); if (rc < 0) { pr_err("adc-tm thresholds read failed\n"); goto fail; } if (status) { *notify_check = 1; pr_debug("Client can be notify\n"); return rc; } pr_debug("Client can not be notify, restart measurement\n"); /* Set measurement in single measurement mode */ mode_ctl = ADC_OP_NORMAL_MODE << QPNP_OP_MODE_SHIFT; rc = qpnp_adc_tm_mode_select(chip, mode_ctl); if (rc < 0) { pr_err("adc-tm single mode select failed\n"); goto fail; } /* Disable bank */ rc = qpnp_adc_tm_disable(chip); if (rc < 0) { pr_err("adc-tm disable failed\n"); goto fail; } /* Check if a conversion is in progress */ rc = qpnp_adc_tm_req_sts_check(chip); if (rc < 0) { pr_err("adc-tm req_sts check failed\n"); goto fail; } rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_LOW_THR_INT_EN, sensor_mask, false); if (rc < 0) { pr_err("low threshold int write failed\n"); goto fail; } rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_HIGH_THR_INT_EN, sensor_mask, false); if (rc < 0) { pr_err("high threshold int enable failed\n"); goto fail; } rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_MULTI_MEAS_EN, sensor_mask, false); if (rc < 0) { pr_err("multi measurement en failed\n"); goto fail; } /* restart measurement */ scale_type = chip->sensor[sensor_num].scale_type; chip->adc->amux_prop->amux_channel = channel; chip->adc->amux_prop->decimation = chip->adc->adc_channels[sensor_num].adc_decimation; chip->adc->amux_prop->hw_settle_time = chip->adc->adc_channels[sensor_num].hw_settle_time; chip->adc->amux_prop->fast_avg_setup = chip->adc->adc_channels[sensor_num].fast_avg_setup; chip->adc->amux_prop->mode_sel = ADC_OP_MEASUREMENT_INTERVAL << QPNP_OP_MODE_SHIFT; adc_tm_rscale_fn[scale_type].chan(chip->vadc_dev, client_info->btm_param, &chip->adc->amux_prop->chan_prop->low_thr, &chip->adc->amux_prop->chan_prop->high_thr); qpnp_adc_tm_add_to_list(chip, sensor_num, client_info->btm_param, chip->adc->amux_prop->chan_prop); chip->adc->amux_prop->chan_prop->tm_channel_select = chip->sensor[sensor_num].btm_channel_num; chip->adc->amux_prop->chan_prop->state_request = client_info->btm_param->state_request; rc = qpnp_adc_tm_configure(chip, chip->adc->amux_prop); if (rc) { pr_err("adc-tm configure failed with %d\n", rc); goto fail; } *notify_check = 0; pr_debug("BTM channel reconfigured for measuremnt\n"); } fail: return rc; } static int qpnp_adc_tm_read_status(struct qpnp_adc_tm_chip *chip) { u8 status_low = 0, status_high = 0, qpnp_adc_tm_meas_en = 0; u8 adc_tm_low_enable = 0, adc_tm_high_enable = 0; u8 adc_tm_low_enable = 0, adc_tm_high_enable = 0, notify_check = 0; u8 sensor_mask = 0, adc_tm_low_thr_set = 0, adc_tm_high_thr_set = 0; int rc = 0, sensor_notify_num = 0, i = 0, sensor_num = 0; uint32_t btm_chan_num = 0; Loading Loading @@ -1489,6 +1684,13 @@ static int qpnp_adc_tm_read_status(struct qpnp_adc_tm_chip *chip) such as usb_id, vbatt, pmic_therm */ sensor_mask = 1 << sensor_num; pr_debug("non thermal node - mask:%x\n", sensor_mask); rc = qpnp_adc_tm_recalib_request_check(chip, sensor_num, true, ¬ify_check); if (rc < 0 || !notify_check) { pr_debug("Calib recheck re-armed rc=%d\n", rc); adc_tm_high_enable = 0; goto fail; } rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_HIGH_THR_INT_EN, sensor_mask, false); Loading Loading @@ -1545,6 +1747,13 @@ static int qpnp_adc_tm_read_status(struct qpnp_adc_tm_chip *chip) /* For non thermal registered clients such as usb_id, vbatt, pmic_therm */ pr_debug("non thermal node - mask:%x\n", sensor_mask); rc = qpnp_adc_tm_recalib_request_check(chip, sensor_num, false, ¬ify_check); if (rc < 0 || !notify_check) { pr_debug("Calib recheck re-armed rc=%d\n", rc); adc_tm_low_enable = 0; goto fail; } sensor_mask = 1 << sensor_num; rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_LOW_THR_INT_EN, Loading Loading @@ -1611,7 +1820,7 @@ fail: if (adc_tm_high_enable || adc_tm_low_enable) queue_work(chip->sensor[sensor_num].req_wq, &chip->sensor[sensor_num].work); if (rc < 0) if (rc < 0 || (!adc_tm_high_enable && !adc_tm_low_enable)) atomic_dec(&chip->wq_cnt); return rc; Loading Loading @@ -1971,6 +2180,8 @@ static int qpnp_adc_tm_probe(struct spmi_device *spmi) pr_err("vadc property missing, rc=%d\n", rc); goto fail; } chip->adc_tm_recalib_check = of_property_read_bool(node, "qcom,adc-tm-recalib-check"); for_each_child_of_node(node, child) { char name[25]; Loading
include/linux/qpnp/qpnp-adc.h +46 −0 Original line number Diff line number Diff line Loading @@ -150,6 +150,24 @@ struct qpnp_iadc_chip; /* Structure device for qpnp adc tm */ struct qpnp_adc_tm_chip; /** * enum qpnp_adc_clk_type - Clock rate supported. * %CLK_TYPE1: 2P4MHZ * %CLK_TYPE2: 4P8MHZ * %CLK_TYPE3: 9P6MHZ * %CLK_TYPE4: 19P2MHZ * %CLK_NONE: Do not use this Clk type. * * The Clock rate is specific to each channel of the QPNP ADC arbiter. */ enum qpnp_adc_clk_type { CLK_TYPE1 = 0, CLK_TYPE2, CLK_TYPE3, CLK_TYPE4, CLK_NONE, }; /** * enum qpnp_adc_decimation_type - Sampling rate supported. * %DECIMATION_TYPE1: 512 Loading Loading @@ -1542,6 +1560,25 @@ int32_t qpnp_vadc_channel_monitor(struct qpnp_vadc_chip *chip, * @param: device instance for the VADC */ int32_t qpnp_vadc_end_channel_monitor(struct qpnp_vadc_chip *chip); /** * qpnp_vadc_calib_vref() - Read calibration channel REF_125V/VDD_VADC * @dev: Structure device for qpnp vadc * @calib_type: absolute or ratiometric calib type. * returns calibration channel adc code. */ int32_t qpnp_vadc_calib_vref(struct qpnp_vadc_chip *vadc, enum qpnp_adc_calib_type calib_type, int *calib_data); /** * qpnp_vadc_calib_gnd() - Read calibration channel REF_625MV/GND_REF * @dev: Structure device for qpnp vadc * @calib_type: absolute or ratiometric calib type. * returns calibration channel adc code. */ int32_t qpnp_vadc_calib_gnd(struct qpnp_vadc_chip *vadc, enum qpnp_adc_calib_type calib_type, int *calib_data); #else static inline int32_t qpnp_vadc_read(struct qpnp_vadc_chip *dev, uint32_t channel, Loading Loading @@ -1692,6 +1729,15 @@ static inline int32_t qpnp_vadc_channel_monitor(struct qpnp_vadc_chip *chip, { return -ENXIO; } static inline int32_t qpnp_vadc_end_channel_monitor(struct qpnp_vadc_chip *chip) { return -ENXIO; } static int32_t qpnp_vadc_calib_vref(struct qpnp_vadc_chip *vadc, enum qpnp_adc_calib_type calib_type, int *calib_data) { return -ENXIO; } static int32_t qpnp_vadc_calib_gnd(struct qpnp_vadc_chip *vadc, enum qpnp_adc_calib_type calib_type, int *calib_data) { return -ENXIO; } #endif /* Public API */ Loading