summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSiddartha Mohanadoss <smohanad@codeaurora.org>2016-04-28 14:12:44 -0700
committerJeevan Shriram <jshriram@codeaurora.org>2016-05-10 13:20:13 -0700
commit81a5895080b012100d7e7f8cda695489734ee07a (patch)
tree0ad9c0958f42ca1cd01de89c3bb476c77b13dc83
parentbe6417fef9816bebe92db5d5d7288d255ccf6216 (diff)
thermal: qpnp-adc-tm: Support refreshed BTM driver
The BTM (Battery temperature module) peripheral driver on the PMIC (Power management IC) supports threshold monitoring and notifies clients when thresholds are crossed. PMCOBALT supports refreshed BTM peripheral register interface and the driver uses compatible property qpnp-adc-tm-hc to distinguish using the refreshed peripheral. The external client interface with the driver remains the same. Updates include handling the interrupt when the thresholds are crossed,programming the threholds and configuring the hardware based on the refreshed design. BTM peripheral needs the VADC_HC peripheral to compute the gain/offset that are used to reverse compute the threhold values to ADC code. Some of the reverse computation API's such as calculating thermistor thresholds require the gain and offset values before computing the ADC code to be programmed. This requires modification to the existing calibration API in the VADC_HC driver to calculate the reference calibration points and store these values for clients to use in the reverse computation Change-Id: I989cfa4f40e7f1671f04dfa9d4c3fe2ccbbc44ab Signed-off-by: Siddartha Mohanadoss <smohanad@codeaurora.org>
-rw-r--r--Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt74
-rw-r--r--drivers/hwmon/qpnp-adc-common.c94
-rw-r--r--drivers/hwmon/qpnp-adc-voltage.c684
-rw-r--r--drivers/thermal/qpnp-adc-tm.c1184
-rw-r--r--include/linux/qpnp/qpnp-adc.h20
5 files changed, 1447 insertions, 609 deletions
diff --git a/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt b/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt
index 344d8d4fd966..3aaa339e1b22 100644
--- a/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt
+++ b/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt
@@ -12,14 +12,41 @@ VADC_TM node
Required properties:
- compatible : should be "qcom,qpnp-adc-tm" for thermal ADC driver.
+ : should be "qcom,qpnp-adc-tm-hc" for thermal ADC driver using
+ refreshed BTM peripheral.
- reg : offset and length of the PMIC Aribter register map.
- address-cells : Must be one.
- size-cells : Must be zero.
- interrupts : The thermal ADC bank peripheral interrupts for eoc, high and low interrupts.
-- interrupt-names : Should be "eoc-int-en-set", "high-thr-en-set" and "low-thr-en-set".
+- interrupt-names : Should be "eoc-int-en-set", "high-thr-en-set" and "low-thr-en-set"
+ for qcom,qpnp-adc-tm type.
+ : Should be "eoc-int-en-set" for qcom,qpnp-adc-tm-hc type.
- qcom,adc-bit-resolution : Bit resolution of the ADC.
- qcom,adc-vdd-reference : Voltage reference used by the ADC.
+The following properties are required in the main node for qcom,qpnp-adc-tm-hc peripheral.
+- qcom,decimation : Should be present for qcom,qpnp-adc-tm-hc peripheral as its common setting
+ across all the channels. Sampling rate to use for all the channel measurements.
+ Select from the following unsigned int.
+ 0 : 512
+ 1 : 1K
+ 2 : 2K
+ 3 : 4K
+- qcom,fast-avg-setup : Should be present for qcom,qpnp-adc-tm-hc peripheral as its common setting
+ across all the channels. Average number of samples to be used for measurement.
+ Fast averaging provides the option to obtain a single measurement from the ADC
+ that is an average of multiple samples. The value selected is 2^(value)
+ Select from the following unsigned int.
+ 0 : 1
+ 1 : 2
+ 2 : 4
+ 3 : 8
+ 4 : 16
+ 5 : 32
+ 6 : 64
+ 7 : 128
+ 8 : 256
+
Optional properties:
- qcom,thermal-node : If present a thermal node is created and the channel is registered as
part of the thermal sysfs which allows clients to use the thermal framework
@@ -54,6 +81,8 @@ Required properties:
1 : 1K
2 : 2K
3 : 4K
+ Note: This property is not required in the channel node in qcom,qpnp-adc-tm-hc
+ peripheral.
- qcom,pre-div-channel-scaling : Pre-div used for the channel before the signal is being measured.
Select from the following unsigned int for the corresponding
numerator/denominator pre-div ratio.
@@ -114,6 +143,8 @@ Required properties:
6 : 64
7 : 128
8 : 256
+ Note: This property is not required in the channel node in
+ qcom,qpnp-adc-tm-hc peripheral.
- qcom,btm-channel-number : Depending on the PMIC version, a max of upto 8 BTM channels.
The BTM channel numbers are statically allocated to the
corresponding channel node.
@@ -125,7 +156,7 @@ client_node {
qcom,client-adc_tm = <&pm8941_adc_tm>;
};
-Example:
+Example for "qcom,qpnp-adc-tm" device:
/* Main Node */
qcom,vadc@3400 {
compatible = "qcom,qpnp-adc-tm";
@@ -169,3 +200,42 @@ Example:
qcom,btm-channel-number = <0x78>;
};
};
+
+Example for "qcom,qpnp-adc-tm-hc" device:
+ /* Main Node */
+ pmcobalt_adc_tm: vadc@3400 {
+ compatible = "qcom,qpnp-adc-tm-hc";
+ reg = <0x3400 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0x0 0x34 0x0 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "eoc-int-en-set";
+ qcom,adc-bit-resolution = <15>;
+ qcom,adc-vdd-reference = <1875>;
+ qcom,adc_tm-vadc = <&pmcobalt_vadc>;
+ qcom,decimation = <0>;
+ qcom,fast-avg-setup = <0>;
+
+ /* Channel Node to be registered as part of thermal sysfs */
+ chan@b5 {
+ label = "pa_therm1";
+ reg = <0xb5>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <0>;
+ qcom,btm-channel-number = <0x70>;
+ qcom,thermal-node;
+ };
+
+ /* Channel Node */
+ chan@6 {
+ label = "vbat_sns";
+ reg = <6>;
+ qcom,pre-div-channel-scaling = <1>;
+ qcom,calibration-type = "absolute";
+ qcom,scale-function = <3>;
+ qcom,hw-settle-time = <0>;
+ qcom,btm-channel-number = <0x78>;
+ };
+ };
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;
diff --git a/drivers/thermal/qpnp-adc-tm.c b/drivers/thermal/qpnp-adc-tm.c
index 70ac9691f5fa..500d47d4ffdf 100644
--- a/drivers/thermal/qpnp-adc-tm.c
+++ b/drivers/thermal/qpnp-adc-tm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -59,6 +59,9 @@
#define QPNP_ADC_TRIM_EN BIT(0)
#define QPNP_EN_CTL1 0x46
#define QPNP_ADC_TM_EN BIT(7)
+#define QPNP_BTM_CONV_REQ 0x47
+#define QPNP_ADC_CONV_REQ_EN BIT(7)
+
#define QPNP_ADC_CH_SEL_CTL 0x48
#define QPNP_ADC_DIG_PARAM 0x50
#define QPNP_ADC_DIG_DEC_RATIO_SEL_SHIFT 3
@@ -173,6 +176,41 @@
#define QPNP_MAX_TIME 2100
#define QPNP_RETRY 1000
+/* QPNP ADC TM HC start */
+#define QPNP_BTM_HC_STATUS1 0x08
+#define QPNP_BTM_HC_STATUS_LOW 0x0a
+#define QPNP_BTM_HC_STATUS_HIGH 0x0b
+
+#define QPNP_BTM_HC_ADC_DIG_PARAM 0x42
+#define QPNP_BTM_HC_FAST_AVG_CTL 0x43
+#define QPNP_BTM_EN_CTL1 0x46
+#define QPNP_BTM_CONV_REQ 0x47
+
+#define QPNP_BTM_MEAS_INTERVAL_CTL 0x50
+#define QPNP_BTM_MEAS_INTERVAL_CTL2 0x51
+
+#define QPNP_BTM_Mn_ADC_CH_SEL_CTL(n) ((n * 8) + 0x60)
+#define QPNP_BTM_Mn_LOW_THR0(n) ((n * 8) + 0x61)
+#define QPNP_BTM_Mn_LOW_THR1(n) ((n * 8) + 0x62)
+#define QPNP_BTM_Mn_HIGH_THR0(n) ((n * 8) + 0x63)
+#define QPNP_BTM_Mn_HIGH_THR1(n) ((n * 8) + 0x64)
+#define QPNP_BTM_Mn_MEAS_INTERVAL_CTL(n) ((n * 8) + 0x65)
+#define QPNP_BTM_Mn_CTL(n) ((n * 8) + 0x66)
+#define QPNP_BTM_CTL_HW_SETTLE_DELAY_MASK 0xf
+#define QPNP_BTM_CTL_CAL_SEL 0x30
+#define QPNP_BTM_CTL_CAL_SEL_MASK_SHIFT 4
+#define QPNP_BTM_CTL_CAL_VAL 0x40
+
+#define QPNP_BTM_Mn_EN(n) ((n * 8) + 0x67)
+#define QPNP_BTM_Mn_MEAS_EN BIT(7)
+#define QPNP_BTM_Mn_HIGH_THR_INT_EN BIT(1)
+#define QPNP_BTM_Mn_LOW_THR_INT_EN BIT(0)
+
+#define QPNP_BTM_Mn_DATA0(n) ((n * 2) + 0xa0)
+#define QPNP_BTM_Mn_DATA1(n) ((n * 2) + 0xa1)
+
+/* QPNP ADC TM HC end */
+
struct qpnp_adc_thr_info {
u8 status_low;
u8 status_high;
@@ -225,10 +263,13 @@ struct qpnp_adc_tm_chip {
struct qpnp_vadc_chip *vadc_dev;
struct workqueue_struct *high_thr_wq;
struct workqueue_struct *low_thr_wq;
+ struct workqueue_struct *thr_wq;
struct work_struct trigger_high_thr_work;
struct work_struct trigger_low_thr_work;
+ struct work_struct trigger_thr_work;
bool adc_vote_enable;
struct qpnp_adc_thr_info th_info;
+ bool adc_tm_hc;
struct qpnp_adc_tm_sensor sensor[0];
};
@@ -309,27 +350,28 @@ static struct qpnp_adc_tm_reverse_scale_fn adc_tm_rscale_fn[] = {
};
static int32_t qpnp_adc_tm_read_reg(struct qpnp_adc_tm_chip *chip,
- int16_t reg, u8 *data)
+ int16_t reg, u8 *data, int len)
{
int rc = 0;
- uint val;
- rc = regmap_read(chip->adc->regmap, (chip->adc->offset + reg), &val);
+ rc = regmap_bulk_read(chip->adc->regmap, (chip->adc->offset + reg),
+ data, len);
if (rc < 0)
pr_err("adc-tm read reg %d failed with %d\n", reg, rc);
- *data = (u8)val;
+
return rc;
}
static int32_t qpnp_adc_tm_write_reg(struct qpnp_adc_tm_chip *chip,
- int16_t reg, u8 data)
+ int16_t reg, u8 data, int len)
{
int rc = 0;
u8 *buf;
buf = &data;
- rc = regmap_write(chip->adc->regmap, (chip->adc->offset + reg), *buf);
+ rc = regmap_bulk_write(chip->adc->regmap, (chip->adc->offset + reg),
+ buf, len);
if (rc < 0)
pr_err("adc-tm write reg %d failed with %d\n", reg, rc);
@@ -351,7 +393,7 @@ static int32_t qpnp_adc_tm_fast_avg_en(struct qpnp_adc_tm_chip *chip,
}
fast_avg_en = QPNP_FAST_AVG_ENABLED;
- rc = qpnp_adc_tm_write_reg(chip, QPNP_FAST_AVG_EN, fast_avg_en);
+ rc = qpnp_adc_tm_write_reg(chip, QPNP_FAST_AVG_EN, fast_avg_en, 1);
if (rc < 0) {
pr_err("adc-tm fast-avg enable err\n");
return rc;
@@ -393,9 +435,20 @@ static int32_t qpnp_adc_tm_enable(struct qpnp_adc_tm_chip *chip)
}
data = QPNP_ADC_TM_EN;
- rc = qpnp_adc_tm_write_reg(chip, QPNP_EN_CTL1, data);
- if (rc < 0)
+ rc = qpnp_adc_tm_write_reg(chip, QPNP_EN_CTL1, data, 1);
+ if (rc < 0) {
pr_err("adc-tm enable failed\n");
+ return rc;
+ }
+
+ if (chip->adc_tm_hc) {
+ data = QPNP_ADC_CONV_REQ_EN;
+ rc = qpnp_adc_tm_write_reg(chip, QPNP_BTM_CONV_REQ, data, 1);
+ if (rc < 0) {
+ pr_err("adc-tm enable failed\n");
+ return rc;
+ }
+ }
return rc;
}
@@ -405,7 +458,15 @@ static int32_t qpnp_adc_tm_disable(struct qpnp_adc_tm_chip *chip)
u8 data = 0;
int rc = 0;
- rc = qpnp_adc_tm_write_reg(chip, QPNP_EN_CTL1, data);
+ if (chip->adc_tm_hc) {
+ rc = qpnp_adc_tm_write_reg(chip, QPNP_BTM_CONV_REQ, data, 1);
+ if (rc < 0) {
+ pr_err("adc-tm enable failed\n");
+ return rc;
+ }
+ }
+
+ rc = qpnp_adc_tm_write_reg(chip, QPNP_EN_CTL1, data, 1);
if (rc < 0) {
pr_err("adc-tm disable failed\n");
return rc;
@@ -425,51 +486,107 @@ static int qpnp_adc_tm_is_valid(struct qpnp_adc_tm_chip *chip)
return -EINVAL;
}
-static int32_t qpnp_adc_tm_enable_if_channel_meas(
- struct qpnp_adc_tm_chip *chip)
+static int32_t qpnp_adc_tm_rc_check_channel_en(struct qpnp_adc_tm_chip *chip)
{
- u8 adc_tm_meas_en = 0, status_low = 0, status_high = 0;
- int rc = 0;
+ u8 adc_tm_ctl = 0, status_low = 0, status_high = 0;
+ int rc = 0, i = 0;
+ bool ldo_en;
- /* Check if a measurement request is still required */
- rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
- &adc_tm_meas_en);
- if (rc) {
- pr_err("adc-tm-tm read status high failed with %d\n", rc);
- return rc;
- }
+ for (i = 0; i < chip->max_channels_available; i++) {
+ rc = qpnp_adc_tm_read_reg(chip, QPNP_BTM_Mn_CTL(i),
+ &adc_tm_ctl, 1);
+ if (rc) {
+ pr_err("adc-tm-tm read ctl failed with %d\n", rc);
+ return rc;
+ }
- rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_LOW_THR_INT_EN,
- &status_low);
- if (rc) {
- pr_err("adc-tm-tm read status low failed with %d\n", rc);
- return rc;
+ adc_tm_ctl &= QPNP_BTM_Mn_MEAS_EN;
+ status_low &= QPNP_BTM_Mn_LOW_THR_INT_EN;
+ status_high &= QPNP_BTM_Mn_HIGH_THR_INT_EN;
+
+ /* Enable only if there are pending measurement requests */
+ if ((adc_tm_ctl && status_high) ||
+ (adc_tm_ctl && status_low)) {
+ qpnp_adc_tm_enable(chip);
+ ldo_en = true;
+
+ /* Request conversion */
+ rc = qpnp_adc_tm_write_reg(chip, QPNP_CONV_REQ,
+ QPNP_CONV_REQ_SET, 1);
+ if (rc < 0) {
+ pr_err("adc-tm request conversion failed\n");
+ return rc;
+ }
+ }
+ break;
}
- rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_HIGH_THR_INT_EN,
- &status_high);
- if (rc) {
- pr_err("adc-tm-tm read status high failed with %d\n", rc);
- return rc;
+ if (!ldo_en) {
+ /* disable the vote if applicable */
+ if (chip->adc_vote_enable && chip->adc->hkadc_ldo &&
+ chip->adc->hkadc_ldo_ok) {
+ qpnp_adc_disable_voltage(chip->adc);
+ chip->adc_vote_enable = false;
+ }
}
- /* Enable only if there are pending measurement requests */
- if ((adc_tm_meas_en && status_high) || (adc_tm_meas_en && status_low)) {
- qpnp_adc_tm_enable(chip);
+ return rc;
+}
- /* Request conversion */
- rc = qpnp_adc_tm_write_reg(chip, QPNP_CONV_REQ,
- QPNP_CONV_REQ_SET);
- if (rc < 0) {
- pr_err("adc-tm request conversion failed\n");
+static int32_t qpnp_adc_tm_enable_if_channel_meas(
+ struct qpnp_adc_tm_chip *chip)
+{
+ u8 adc_tm_meas_en = 0, status_low = 0, status_high = 0;
+ int rc = 0;
+
+ if (chip->adc_tm_hc) {
+ rc = qpnp_adc_tm_rc_check_channel_en(chip);
+ if (rc) {
+ pr_err("adc_tm channel check failed\n");
return rc;
}
} else {
- /* disable the vote if applicable */
- if (chip->adc_vote_enable && chip->adc->hkadc_ldo &&
+ /* Check if a measurement request is still required */
+ rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
+ &adc_tm_meas_en, 1);
+ if (rc) {
+ pr_err("read status high failed with %d\n", rc);
+ return rc;
+ }
+
+ rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_LOW_THR_INT_EN,
+ &status_low, 1);
+ if (rc) {
+ pr_err("read status low failed with %d\n", rc);
+ return rc;
+ }
+
+ rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_HIGH_THR_INT_EN,
+ &status_high, 1);
+ if (rc) {
+ pr_err("read status high failed with %d\n", rc);
+ return rc;
+ }
+
+ /* Enable only if there are pending measurement requests */
+ if ((adc_tm_meas_en && status_high) ||
+ (adc_tm_meas_en && status_low)) {
+ qpnp_adc_tm_enable(chip);
+
+ /* Request conversion */
+ rc = qpnp_adc_tm_write_reg(chip, QPNP_CONV_REQ,
+ QPNP_CONV_REQ_SET, 1);
+ if (rc < 0) {
+ pr_err("adc-tm request conversion failed\n");
+ return rc;
+ }
+ } else {
+ /* disable the vote if applicable */
+ if (chip->adc_vote_enable && chip->adc->hkadc_ldo &&
chip->adc->hkadc_ldo_ok) {
- qpnp_adc_disable_voltage(chip->adc);
- chip->adc_vote_enable = false;
+ qpnp_adc_disable_voltage(chip->adc);
+ chip->adc_vote_enable = false;
+ }
}
}
@@ -484,7 +601,7 @@ static int32_t qpnp_adc_tm_mode_select(struct qpnp_adc_tm_chip *chip,
mode_ctl |= (QPNP_ADC_TRIM_EN | QPNP_AMUX_TRIM_EN);
/* VADC_BTM current sets mode to recurring measurements */
- rc = qpnp_adc_tm_write_reg(chip, QPNP_MODE_CTL, mode_ctl);
+ rc = qpnp_adc_tm_write_reg(chip, QPNP_MODE_CTL, mode_ctl, 1);
if (rc < 0)
pr_err("adc-tm write mode selection err\n");
@@ -504,7 +621,7 @@ static int32_t qpnp_adc_tm_req_sts_check(struct qpnp_adc_tm_chip *chip)
}
/* The VADC_TM bank needs to be disabled for new conversion request */
- rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_STATUS1, &status1);
+ rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_STATUS1, &status1, 1);
if (rc) {
pr_err("adc-tm read status1 failed\n");
return rc;
@@ -513,15 +630,17 @@ static int32_t qpnp_adc_tm_req_sts_check(struct qpnp_adc_tm_chip *chip)
/* Disable the bank if a conversion is occuring */
while (status1 & QPNP_STATUS1_REQ_STS) {
if (count > QPNP_RETRY) {
- pr_err("adc-tm conversion not completed in retry=%d\n",
- count);
+ pr_err("retry error=%d with 0x%x\n", count, status1);
break;
}
- /* Wait time is based on the optimum sampling rate
+ /*
+ * 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_adc_tm_read_reg(chip, QPNP_ADC_TM_STATUS1, &status1);
+ rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_STATUS1,
+ &status1, 1);
if (rc < 0) {
pr_err("adc-tm disable failed\n");
return rc;
@@ -529,12 +648,14 @@ static int32_t qpnp_adc_tm_req_sts_check(struct qpnp_adc_tm_chip *chip)
count++;
}
- /* Change the mode back to recurring measurement mode */
- mode_ctl = ADC_OP_MEASUREMENT_INTERVAL << QPNP_OP_MODE_SHIFT;
- rc = qpnp_adc_tm_mode_select(chip, mode_ctl);
- if (rc < 0) {
- pr_err("adc-tm mode change to recurring failed\n");
- return rc;
+ if (!chip->adc_tm_hc) {
+ /* Change the mode back to recurring measurement mode */
+ mode_ctl = ADC_OP_MEASUREMENT_INTERVAL << QPNP_OP_MODE_SHIFT;
+ rc = qpnp_adc_tm_mode_select(chip, mode_ctl);
+ if (rc < 0) {
+ pr_err("adc-tm mode change to recurring failed\n");
+ return rc;
+ }
}
/* Disable the peripheral */
@@ -547,16 +668,26 @@ static int32_t qpnp_adc_tm_req_sts_check(struct qpnp_adc_tm_chip *chip)
return rc;
}
-static int32_t qpnp_adc_tm_get_btm_idx(uint32_t btm_chan,
- uint32_t *btm_chan_idx)
+static int32_t qpnp_adc_tm_get_btm_idx(struct qpnp_adc_tm_chip *chip,
+ uint32_t btm_chan, uint32_t *btm_chan_idx)
{
int rc = 0, i;
bool chan_found = false;
- for (i = 0; i < QPNP_ADC_TM_CHAN_NONE; i++) {
- if (adc_tm_data[i].btm_amux_chan == btm_chan) {
- *btm_chan_idx = i;
- chan_found = true;
+ if (!chip->adc_tm_hc) {
+ for (i = 0; i < QPNP_ADC_TM_CHAN_NONE; i++) {
+ if (adc_tm_data[i].btm_amux_chan == btm_chan) {
+ *btm_chan_idx = i;
+ chan_found = true;
+ }
+ }
+ } else {
+ for (i = 0; i < chip->max_channels_available; i++) {
+ if (chip->sensor[i].btm_channel_num == btm_chan) {
+ *btm_chan_idx = i;
+ chan_found = true;
+ break;
+ }
}
}
@@ -572,13 +703,13 @@ static int32_t qpnp_adc_tm_check_revision(struct qpnp_adc_tm_chip *chip,
u8 rev, perph_subtype;
int rc = 0;
- rc = qpnp_adc_tm_read_reg(chip, QPNP_REVISION3, &rev);
+ rc = qpnp_adc_tm_read_reg(chip, QPNP_REVISION3, &rev, 1);
if (rc) {
pr_err("adc-tm revision read failed\n");
return rc;
}
- rc = qpnp_adc_tm_read_reg(chip, QPNP_PERPH_SUBTYPE, &perph_subtype);
+ rc = qpnp_adc_tm_read_reg(chip, QPNP_PERPH_SUBTYPE, &perph_subtype, 1);
if (rc) {
pr_err("adc-tm perph_subtype read failed\n");
return rc;
@@ -627,9 +758,14 @@ static int32_t qpnp_adc_tm_timer_interval_select(
switch (chip->sensor[chan_idx].timer_select) {
case ADC_MEAS_TIMER_SELECT1:
- rc = qpnp_adc_tm_write_reg(chip,
+ if (!chip->adc_tm_hc)
+ rc = qpnp_adc_tm_write_reg(chip,
QPNP_ADC_TM_MEAS_INTERVAL_CTL,
- chip->sensor[chan_idx].meas_interval);
+ chip->sensor[chan_idx].meas_interval, 1);
+ else
+ rc = qpnp_adc_tm_write_reg(chip,
+ QPNP_BTM_MEAS_INTERVAL_CTL,
+ chip->sensor[chan_idx].meas_interval, 1);
if (rc < 0) {
pr_err("timer1 configure failed\n");
return rc;
@@ -637,9 +773,14 @@ static int32_t qpnp_adc_tm_timer_interval_select(
break;
case ADC_MEAS_TIMER_SELECT2:
/* Thermal channels uses timer2, default to 1 second */
- rc = qpnp_adc_tm_read_reg(chip,
+ if (!chip->adc_tm_hc)
+ rc = qpnp_adc_tm_read_reg(chip,
QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
- &meas_interval_timer2);
+ &meas_interval_timer2, 1);
+ else
+ rc = qpnp_adc_tm_read_reg(chip,
+ QPNP_BTM_MEAS_INTERVAL_CTL2,
+ &meas_interval_timer2, 1);
if (rc < 0) {
pr_err("timer2 configure read failed\n");
return rc;
@@ -648,18 +789,28 @@ static int32_t qpnp_adc_tm_timer_interval_select(
timer_interval_store <<= QPNP_ADC_TM_MEAS_INTERVAL_CTL2_SHIFT;
timer_interval_store &= QPNP_ADC_TM_MEAS_INTERVAL_CTL2_MASK;
meas_interval_timer2 |= timer_interval_store;
- rc = qpnp_adc_tm_write_reg(chip,
- QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
- meas_interval_timer2);
+ if (!chip->adc_tm_hc)
+ rc = qpnp_adc_tm_write_reg(chip,
+ QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
+ meas_interval_timer2, 1);
+ else
+ rc = qpnp_adc_tm_write_reg(chip,
+ QPNP_BTM_MEAS_INTERVAL_CTL2,
+ meas_interval_timer2, 1);
if (rc < 0) {
pr_err("timer2 configure failed\n");
return rc;
}
break;
case ADC_MEAS_TIMER_SELECT3:
- rc = qpnp_adc_tm_read_reg(chip,
+ if (!chip->adc_tm_hc)
+ rc = qpnp_adc_tm_read_reg(chip,
QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
- &meas_interval_timer2);
+ &meas_interval_timer2, 1);
+ else
+ rc = qpnp_adc_tm_read_reg(chip,
+ QPNP_BTM_MEAS_INTERVAL_CTL2,
+ &meas_interval_timer2, 1);
if (rc < 0) {
pr_err("timer3 read failed\n");
return rc;
@@ -667,9 +818,14 @@ static int32_t qpnp_adc_tm_timer_interval_select(
timer_interval_store = chip->sensor[chan_idx].meas_interval;
timer_interval_store &= QPNP_ADC_TM_MEAS_INTERVAL_CTL3_MASK;
meas_interval_timer2 |= timer_interval_store;
- rc = qpnp_adc_tm_write_reg(chip,
- QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
- meas_interval_timer2);
+ if (!chip->adc_tm_hc)
+ rc = qpnp_adc_tm_write_reg(chip,
+ QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
+ meas_interval_timer2, 1);
+ else
+ rc = qpnp_adc_tm_write_reg(chip,
+ QPNP_BTM_MEAS_INTERVAL_CTL2,
+ meas_interval_timer2, 1);
if (rc < 0) {
pr_err("timer3 configure failed\n");
return rc;
@@ -681,14 +837,19 @@ static int32_t qpnp_adc_tm_timer_interval_select(
}
/* Select the timer to use for the corresponding channel */
- rc = qpnp_adc_tm_get_btm_idx(btm_chan, &btm_chan_idx);
+ rc = qpnp_adc_tm_get_btm_idx(chip, btm_chan, &btm_chan_idx);
if (rc < 0) {
pr_err("Invalid btm channel idx\n");
return rc;
}
- rc = qpnp_adc_tm_write_reg(chip,
+ if (!chip->adc_tm_hc)
+ rc = qpnp_adc_tm_write_reg(chip,
adc_tm_data[btm_chan_idx].meas_interval_ctl,
- chip->sensor[chan_idx].timer_select);
+ chip->sensor[chan_idx].timer_select, 1);
+ else
+ rc = qpnp_adc_tm_write_reg(chip,
+ QPNP_BTM_Mn_MEAS_INTERVAL_CTL(btm_chan_idx),
+ chip->sensor[chan_idx].timer_select, 1);
if (rc < 0) {
pr_err("TM channel timer configure failed\n");
return rc;
@@ -752,7 +913,7 @@ static int32_t qpnp_adc_tm_reg_update(struct qpnp_adc_tm_chip *chip,
u8 reg_value = 0;
int rc = 0;
- rc = qpnp_adc_tm_read_reg(chip, addr, &reg_value);
+ rc = qpnp_adc_tm_read_reg(chip, addr, &reg_value, 1);
if (rc < 0) {
pr_err("read failed for addr:0x%x\n", addr);
return rc;
@@ -764,7 +925,7 @@ static int32_t qpnp_adc_tm_reg_update(struct qpnp_adc_tm_chip *chip,
pr_debug("state:%d, reg:0x%x with bits:0x%x and mask:0x%x\n",
state, addr, reg_value, ~mask);
- rc = qpnp_adc_tm_write_reg(chip, addr, reg_value);
+ rc = qpnp_adc_tm_write_reg(chip, addr, reg_value, 1);
if (rc < 0) {
pr_err("write failed for addr:%x\n", addr);
return rc;
@@ -781,7 +942,12 @@ static int32_t qpnp_adc_tm_read_thr_value(struct qpnp_adc_tm_chip *chip,
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 (!chip->adc_tm_hc) {
+ pr_err("Not applicable for VADC HC peripheral\n");
+ return -EINVAL;
+ }
+
+ rc = qpnp_adc_tm_get_btm_idx(chip, btm_chan, &btm_chan_idx);
if (rc < 0) {
pr_err("Invalid btm channel idx\n");
return rc;
@@ -789,7 +955,7 @@ static int32_t qpnp_adc_tm_read_thr_value(struct qpnp_adc_tm_chip *chip,
rc = qpnp_adc_tm_read_reg(chip,
adc_tm_data[btm_chan_idx].low_thr_lsb_addr,
- &data_lsb);
+ &data_lsb, 1);
if (rc < 0) {
pr_err("low threshold lsb setting failed\n");
return rc;
@@ -797,7 +963,7 @@ static int32_t qpnp_adc_tm_read_thr_value(struct qpnp_adc_tm_chip *chip,
rc = qpnp_adc_tm_read_reg(chip,
adc_tm_data[btm_chan_idx].low_thr_msb_addr,
- &data_msb);
+ &data_msb, 1);
if (rc < 0) {
pr_err("low threshold msb setting failed\n");
return rc;
@@ -807,7 +973,7 @@ static int32_t qpnp_adc_tm_read_thr_value(struct qpnp_adc_tm_chip *chip,
rc = qpnp_adc_tm_read_reg(chip,
adc_tm_data[btm_chan_idx].high_thr_lsb_addr,
- &data_lsb);
+ &data_lsb, 1);
if (rc < 0) {
pr_err("high threshold lsb setting failed\n");
return rc;
@@ -815,7 +981,7 @@ static int32_t qpnp_adc_tm_read_thr_value(struct qpnp_adc_tm_chip *chip,
rc = qpnp_adc_tm_read_reg(chip,
adc_tm_data[btm_chan_idx].high_thr_msb_addr,
- &data_msb);
+ &data_msb, 1);
if (rc < 0) {
pr_err("high threshold msb setting failed\n");
return rc;
@@ -835,41 +1001,74 @@ static int32_t qpnp_adc_tm_thr_update(struct qpnp_adc_tm_chip *chip,
int rc = 0;
uint32_t btm_chan_idx = 0;
- rc = qpnp_adc_tm_get_btm_idx(btm_chan, &btm_chan_idx);
+ rc = qpnp_adc_tm_get_btm_idx(chip, btm_chan, &btm_chan_idx);
if (rc < 0) {
pr_err("Invalid btm channel idx\n");
return rc;
}
- rc = qpnp_adc_tm_write_reg(chip,
+ if (!chip->adc_tm_hc) {
+ rc = qpnp_adc_tm_write_reg(chip,
adc_tm_data[btm_chan_idx].low_thr_lsb_addr,
- QPNP_ADC_TM_THR_LSB_MASK(low_thr));
- if (rc < 0) {
- pr_err("low threshold lsb setting failed\n");
- return rc;
- }
+ QPNP_ADC_TM_THR_LSB_MASK(low_thr), 1);
+ if (rc < 0) {
+ pr_err("low threshold lsb setting failed\n");
+ return rc;
+ }
- rc = qpnp_adc_tm_write_reg(chip,
- adc_tm_data[btm_chan_idx].low_thr_msb_addr,
- QPNP_ADC_TM_THR_MSB_MASK(low_thr));
- if (rc < 0) {
- pr_err("low threshold msb setting failed\n");
- return rc;
- }
+ rc = qpnp_adc_tm_write_reg(chip,
+ adc_tm_data[btm_chan_idx].low_thr_msb_addr,
+ QPNP_ADC_TM_THR_MSB_MASK(low_thr), 1);
+ if (rc < 0) {
+ pr_err("low threshold msb setting failed\n");
+ return rc;
+ }
- rc = qpnp_adc_tm_write_reg(chip,
- adc_tm_data[btm_chan_idx].high_thr_lsb_addr,
- QPNP_ADC_TM_THR_LSB_MASK(high_thr));
- if (rc < 0) {
- pr_err("high threshold lsb setting failed\n");
- return rc;
- }
+ rc = qpnp_adc_tm_write_reg(chip,
+ adc_tm_data[btm_chan_idx].high_thr_lsb_addr,
+ QPNP_ADC_TM_THR_LSB_MASK(high_thr), 1);
+ if (rc < 0) {
+ pr_err("high threshold lsb setting failed\n");
+ return rc;
+ }
- rc = qpnp_adc_tm_write_reg(chip,
- adc_tm_data[btm_chan_idx].high_thr_msb_addr,
- QPNP_ADC_TM_THR_MSB_MASK(high_thr));
- if (rc < 0)
- pr_err("high threshold msb setting failed\n");
+ rc = qpnp_adc_tm_write_reg(chip,
+ adc_tm_data[btm_chan_idx].high_thr_msb_addr,
+ QPNP_ADC_TM_THR_MSB_MASK(high_thr), 1);
+ if (rc < 0)
+ pr_err("high threshold msb setting failed\n");
+ } else {
+ rc = qpnp_adc_tm_write_reg(chip,
+ QPNP_BTM_Mn_LOW_THR0(btm_chan_idx),
+ QPNP_ADC_TM_THR_LSB_MASK(low_thr), 1);
+ if (rc < 0) {
+ pr_err("low threshold lsb setting failed\n");
+ return rc;
+ }
+
+ rc = qpnp_adc_tm_write_reg(chip,
+ QPNP_BTM_Mn_LOW_THR1(btm_chan_idx),
+ QPNP_ADC_TM_THR_MSB_MASK(low_thr), 1);
+ if (rc < 0) {
+ pr_err("low threshold msb setting failed\n");
+ return rc;
+ }
+
+ rc = qpnp_adc_tm_write_reg(chip,
+ QPNP_BTM_Mn_HIGH_THR0(btm_chan_idx),
+ QPNP_ADC_TM_THR_LSB_MASK(high_thr), 1);
+ if (rc < 0) {
+ pr_err("high threshold lsb setting failed\n");
+ return rc;
+ }
+
+ rc = qpnp_adc_tm_write_reg(chip,
+ QPNP_BTM_Mn_HIGH_THR1(btm_chan_idx),
+ QPNP_ADC_TM_THR_MSB_MASK(high_thr), 1);
+ if (rc < 0)
+ pr_err("high threshold msb setting failed\n");
+
+ }
pr_debug("client requested high:%d and low:%d\n",
high_thr, low_thr);
@@ -885,9 +1084,11 @@ static int32_t qpnp_adc_tm_manage_thresholds(struct qpnp_adc_tm_chip *chip,
int high_thr = 0, low_thr = 0, rc = 0;
- /* high_thr/low_thr starting point and reset the high_thr_set and
- low_thr_set back to reset since the thresholds will be
- recomputed */
+ /*
+ * high_thr/low_thr starting point and reset the high_thr_set and
+ * low_thr_set back to reset since the thresholds will be
+ * recomputed.
+ */
list_for_each(thr_list,
&chip->sensor[dt_index].thr_list) {
client_info = list_entry(thr_list,
@@ -961,6 +1162,7 @@ static int32_t qpnp_adc_tm_channel_configure(struct qpnp_adc_tm_chip *chip,
bool chan_found = false, high_thr_set = false, low_thr_set = false;
u8 sensor_mask = 0;
struct qpnp_adc_thr_client_info *client_info = NULL;
+ uint32_t btm_chan_idx = 0;
while (i < chip->max_channels_available) {
if (chip->sensor[i].btm_channel_num == btm_chan) {
@@ -976,6 +1178,12 @@ static int32_t qpnp_adc_tm_channel_configure(struct qpnp_adc_tm_chip *chip,
return -EINVAL;
}
+ rc = qpnp_adc_tm_get_btm_idx(chip, btm_chan, &btm_chan_idx);
+ if (rc < 0) {
+ pr_err("Invalid btm channel idx\n");
+ return rc;
+ }
+
sensor_mask = 1 << chan_idx;
if (!chip->sensor[chan_idx].thermal_node) {
/* Update low and high notification thresholds */
@@ -998,8 +1206,14 @@ static int32_t qpnp_adc_tm_channel_configure(struct qpnp_adc_tm_chip *chip,
pr_debug("low sensor mask:%x with state:%d\n",
sensor_mask, chan_prop->state_request);
/* Enable low threshold's interrupt */
- rc = qpnp_adc_tm_reg_update(chip,
- QPNP_ADC_TM_LOW_THR_INT_EN, sensor_mask, true);
+ if (!chip->adc_tm_hc)
+ rc = qpnp_adc_tm_reg_update(chip,
+ QPNP_ADC_TM_LOW_THR_INT_EN,
+ sensor_mask, true);
+ else
+ rc = qpnp_adc_tm_reg_update(chip,
+ QPNP_BTM_Mn_EN(btm_chan_idx),
+ QPNP_BTM_Mn_LOW_THR_INT_EN, true);
if (rc < 0) {
pr_err("low thr enable err:%d\n", btm_chan);
return rc;
@@ -1009,8 +1223,14 @@ static int32_t qpnp_adc_tm_channel_configure(struct qpnp_adc_tm_chip *chip,
if (high_thr_set) {
/* Enable high threshold's interrupt */
pr_debug("high sensor mask:%x\n", sensor_mask);
- rc = qpnp_adc_tm_reg_update(chip,
- QPNP_ADC_TM_HIGH_THR_INT_EN, sensor_mask, true);
+ if (!chip->adc_tm_hc)
+ rc = qpnp_adc_tm_reg_update(chip,
+ QPNP_ADC_TM_HIGH_THR_INT_EN,
+ sensor_mask, true);
+ else
+ rc = qpnp_adc_tm_reg_update(chip,
+ QPNP_BTM_Mn_EN(btm_chan_idx),
+ QPNP_BTM_Mn_HIGH_THR_INT_EN, true);
if (rc < 0) {
pr_err("high thr enable err:%d\n", btm_chan);
return rc;
@@ -1019,8 +1239,12 @@ static int32_t qpnp_adc_tm_channel_configure(struct qpnp_adc_tm_chip *chip,
}
/* Enable corresponding BTM channel measurement */
- rc = qpnp_adc_tm_reg_update(chip,
- QPNP_ADC_TM_MULTI_MEAS_EN, sensor_mask, true);
+ if (!chip->adc_tm_hc)
+ rc = qpnp_adc_tm_reg_update(chip,
+ QPNP_ADC_TM_MULTI_MEAS_EN, sensor_mask, true);
+ else
+ rc = qpnp_adc_tm_reg_update(chip, QPNP_BTM_Mn_EN(btm_chan_idx),
+ QPNP_BTM_Mn_MEAS_EN, true);
if (rc < 0) {
pr_err("multi measurement en failed\n");
return rc;
@@ -1029,6 +1253,111 @@ static int32_t qpnp_adc_tm_channel_configure(struct qpnp_adc_tm_chip *chip,
return rc;
}
+static int32_t qpnp_adc_tm_hc_configure(struct qpnp_adc_tm_chip *chip,
+ struct qpnp_adc_amux_properties *chan_prop)
+{
+ u8 decimation = 0, fast_avg_ctl = 0;
+ u8 buf[8];
+ int rc = 0;
+ uint32_t btm_chan = 0, cal_type = 0, btm_chan_idx = 0;
+
+ /* Disable bank */
+ rc = qpnp_adc_tm_disable(chip);
+ if (rc)
+ return rc;
+
+ /* Decimation setup */
+ decimation = chan_prop->decimation;
+ rc = qpnp_adc_tm_write_reg(chip, QPNP_BTM_HC_ADC_DIG_PARAM,
+ decimation, 1);
+ if (rc < 0) {
+ pr_err("adc-tm digital parameter setup err\n");
+ return rc;
+ }
+
+ /* Fast averaging setup/enable */
+ rc = qpnp_adc_tm_read_reg(chip, QPNP_BTM_HC_FAST_AVG_CTL,
+ &fast_avg_ctl, 1);
+ if (rc < 0) {
+ pr_err("adc-tm fast-avg enable read err\n");
+ return rc;
+ }
+ fast_avg_ctl |= chan_prop->fast_avg_setup;
+ rc = qpnp_adc_tm_write_reg(chip, QPNP_BTM_HC_FAST_AVG_CTL,
+ fast_avg_ctl, 1);
+ if (rc < 0) {
+ pr_err("adc-tm fast-avg enable write err\n");
+ return rc;
+ }
+
+ /* Read block registers for respective BTM channel */
+ btm_chan = chan_prop->chan_prop->tm_channel_select;
+ rc = qpnp_adc_tm_get_btm_idx(chip, btm_chan, &btm_chan_idx);
+ if (rc < 0) {
+ pr_err("Invalid btm channel idx\n");
+ return rc;
+ }
+
+ rc = qpnp_adc_tm_read_reg(chip,
+ QPNP_BTM_Mn_ADC_CH_SEL_CTL(btm_chan_idx), buf, 8);
+ if (rc < 0) {
+ pr_err("qpnp adc configure block read failed\n");
+ return rc;
+ }
+
+ /* Update ADC channel sel */
+ rc = qpnp_adc_tm_write_reg(chip,
+ QPNP_BTM_Mn_ADC_CH_SEL_CTL(btm_chan_idx),
+ chan_prop->amux_channel, 1);
+ if (rc < 0) {
+ pr_err("adc-tm channel amux select failed\n");
+ return rc;
+ }
+
+ /* Manage thresholds */
+ rc = qpnp_adc_tm_channel_configure(chip, btm_chan,
+ chan_prop->chan_prop, chan_prop->amux_channel);
+ if (rc < 0) {
+ pr_err("adc-tm channel threshold configure failed\n");
+ return rc;
+ }
+
+ /* Measurement interval setup */
+ rc = qpnp_adc_tm_timer_interval_select(chip, btm_chan,
+ chan_prop->chan_prop);
+ if (rc < 0) {
+ pr_err("adc-tm timer select failed\n");
+ return rc;
+ }
+
+ /* Set calibration select, hw_settle delay */
+ cal_type |= (chan_prop->calib_type << QPNP_BTM_CTL_CAL_SEL_MASK_SHIFT);
+ buf[6] &= ~QPNP_BTM_CTL_HW_SETTLE_DELAY_MASK;
+ buf[6] |= chan_prop->hw_settle_time;
+ buf[6] &= ~QPNP_BTM_CTL_CAL_SEL;
+ buf[6] |= cal_type;
+ rc = qpnp_adc_tm_write_reg(chip, QPNP_BTM_Mn_CTL(btm_chan_idx),
+ buf[6], 1);
+ if (rc < 0) {
+ pr_err("adc-tm hw-settle, calib sel failed\n");
+ return rc;
+ }
+
+ /* Enable bank */
+ rc = qpnp_adc_tm_enable(chip);
+ if (rc)
+ return rc;
+
+ /* Request conversion */
+ rc = qpnp_adc_tm_write_reg(chip, QPNP_CONV_REQ, QPNP_CONV_REQ_SET, 1);
+ if (rc < 0) {
+ pr_err("adc-tm request conversion failed\n");
+ return rc;
+ }
+
+ return 0;
+}
+
static int32_t qpnp_adc_tm_configure(struct qpnp_adc_tm_chip *chip,
struct qpnp_adc_amux_properties *chan_prop)
{
@@ -1058,7 +1387,7 @@ static int32_t qpnp_adc_tm_configure(struct qpnp_adc_tm_chip *chip,
/* Configure AMUX channel select for the corresponding BTM channel*/
btm_chan = chan_prop->chan_prop->tm_channel_select;
- rc = qpnp_adc_tm_write_reg(chip, btm_chan, chan_prop->amux_channel);
+ rc = qpnp_adc_tm_write_reg(chip, btm_chan, chan_prop->amux_channel, 1);
if (rc < 0) {
pr_err("adc-tm channel selection err\n");
return rc;
@@ -1067,7 +1396,7 @@ static int32_t qpnp_adc_tm_configure(struct qpnp_adc_tm_chip *chip,
/* Digital paramater setup */
decimation |= chan_prop->decimation <<
QPNP_ADC_DIG_DEC_RATIO_SEL_SHIFT;
- rc = qpnp_adc_tm_write_reg(chip, QPNP_ADC_DIG_PARAM, decimation);
+ rc = qpnp_adc_tm_write_reg(chip, QPNP_ADC_DIG_PARAM, decimation, 1);
if (rc < 0) {
pr_err("adc-tm digital parameter setup err\n");
return rc;
@@ -1075,7 +1404,7 @@ static int32_t qpnp_adc_tm_configure(struct qpnp_adc_tm_chip *chip,
/* Hardware setting time */
rc = qpnp_adc_tm_write_reg(chip, QPNP_HW_SETTLE_DELAY,
- chan_prop->hw_settle_time);
+ chan_prop->hw_settle_time, 1);
if (rc < 0) {
pr_err("adc-tm hw settling time setup err\n");
return rc;
@@ -1089,7 +1418,7 @@ static int32_t qpnp_adc_tm_configure(struct qpnp_adc_tm_chip *chip,
}
rc = qpnp_adc_tm_write_reg(chip, QPNP_FAST_AVG_CTL,
- chan_prop->fast_avg_setup);
+ chan_prop->fast_avg_setup, 1);
if (rc < 0) {
pr_err("adc-tm fast-avg setup err\n");
return rc;
@@ -1113,7 +1442,7 @@ static int32_t qpnp_adc_tm_configure(struct qpnp_adc_tm_chip *chip,
/* Recurring interval measurement enable */
rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_MEAS_INTERVAL_OP_CTL,
- &op_cntrl);
+ &op_cntrl, 1);
op_cntrl |= QPNP_ADC_MEAS_INTERVAL_OP;
rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_MEAS_INTERVAL_OP_CTL,
op_cntrl, true);
@@ -1128,7 +1457,7 @@ static int32_t qpnp_adc_tm_configure(struct qpnp_adc_tm_chip *chip,
return rc;
/* Request conversion */
- rc = qpnp_adc_tm_write_reg(chip, QPNP_CONV_REQ, QPNP_CONV_REQ_SET);
+ rc = qpnp_adc_tm_write_reg(chip, QPNP_CONV_REQ, QPNP_CONV_REQ_SET, 1);
if (rc < 0) {
pr_err("adc-tm request conversion failed\n");
return rc;
@@ -1158,6 +1487,7 @@ static int qpnp_adc_tm_set_mode(struct thermal_zone_device *thermal,
struct qpnp_adc_tm_chip *chip = adc_tm->chip;
int rc = 0, channel;
u8 sensor_mask = 0, mode_ctl = 0;
+ uint32_t btm_chan_idx = 0, btm_chan = 0;
if (qpnp_adc_tm_is_valid(chip)) {
pr_err("invalid device\n");
@@ -1167,6 +1497,13 @@ static int qpnp_adc_tm_set_mode(struct thermal_zone_device *thermal,
if (qpnp_adc_tm_check_revision(chip, adc_tm->btm_channel_num))
return -EINVAL;
+ btm_chan = adc_tm->btm_channel_num;
+ rc = qpnp_adc_tm_get_btm_idx(chip, btm_chan, &btm_chan_idx);
+ if (rc < 0) {
+ pr_err("Invalid btm channel idx\n");
+ return rc;
+ }
+
if (mode == THERMAL_DEVICE_ENABLED) {
chip->adc->amux_prop->amux_channel =
adc_tm->vadc_channel_num;
@@ -1183,20 +1520,33 @@ static int qpnp_adc_tm_set_mode(struct thermal_zone_device *thermal,
chip->adc->amux_prop->chan_prop->high_thr = adc_tm->high_thr;
chip->adc->amux_prop->chan_prop->tm_channel_select =
adc_tm->btm_channel_num;
+ chip->adc->amux_prop->calib_type =
+ chip->adc->adc_channels[channel].calib_type;
- rc = qpnp_adc_tm_configure(chip, chip->adc->amux_prop);
- if (rc) {
- pr_err("adc-tm tm configure failed with %d\n", rc);
- return -EINVAL;
+ if (!chip->adc_tm_hc) {
+ rc = qpnp_adc_tm_configure(chip, chip->adc->amux_prop);
+ if (rc) {
+ pr_err("adc-tm configure failed with %d\n", rc);
+ return -EINVAL;
+ }
+ } else {
+ rc = qpnp_adc_tm_hc_configure(chip,
+ chip->adc->amux_prop);
+ if (rc) {
+ pr_err("hc configure failed with %d\n", rc);
+ return -EINVAL;
+ }
}
} else if (mode == THERMAL_DEVICE_DISABLED) {
sensor_mask = 1 << adc_tm->sensor_num;
- 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");
- return rc;
+ if (!chip->adc_tm_hc) {
+ 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");
+ return rc;
+ }
}
/* Disable bank */
@@ -1206,18 +1556,28 @@ static int qpnp_adc_tm_set_mode(struct thermal_zone_device *thermal,
return rc;
}
- /* 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");
- return rc;
- }
+ if (!chip->adc_tm_hc) {
+ /* 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");
+ return rc;
+ }
- rc = qpnp_adc_tm_reg_update(chip,
- QPNP_ADC_TM_MULTI_MEAS_EN, sensor_mask, false);
- if (rc < 0) {
- pr_err("multi measurement update failed\n");
- return rc;
+ rc = qpnp_adc_tm_reg_update(chip,
+ QPNP_ADC_TM_MULTI_MEAS_EN, sensor_mask, false);
+ if (rc < 0) {
+ pr_err("multi measurement update failed\n");
+ return rc;
+ }
+ } else {
+ rc = qpnp_adc_tm_reg_update(chip,
+ QPNP_BTM_Mn_EN(btm_chan_idx),
+ QPNP_BTM_Mn_MEAS_EN, false);
+ if (rc < 0) {
+ pr_err("multi measurement disable failed\n");
+ return rc;
+ }
}
rc = qpnp_adc_tm_enable_if_channel_meas(chip);
@@ -1277,28 +1637,35 @@ static int qpnp_adc_tm_get_trip_temp(struct thermal_zone_device *thermal,
return -EINVAL;
btm_chan = adc_tm_sensor->btm_channel_num;
- rc = qpnp_adc_tm_get_btm_idx(btm_chan, &btm_chan_idx);
+ rc = qpnp_adc_tm_get_btm_idx(chip, btm_chan, &btm_chan_idx);
if (rc < 0) {
pr_err("Invalid btm channel idx\n");
return rc;
}
- reg_low_thr_lsb = adc_tm_data[btm_chan_idx].low_thr_lsb_addr;
- reg_low_thr_msb = adc_tm_data[btm_chan_idx].low_thr_msb_addr;
- reg_high_thr_lsb = adc_tm_data[btm_chan_idx].high_thr_lsb_addr;
- reg_high_thr_msb = adc_tm_data[btm_chan_idx].high_thr_msb_addr;
+ if (!chip->adc_tm_hc) {
+ reg_low_thr_lsb = adc_tm_data[btm_chan_idx].low_thr_lsb_addr;
+ reg_low_thr_msb = adc_tm_data[btm_chan_idx].low_thr_msb_addr;
+ reg_high_thr_lsb = adc_tm_data[btm_chan_idx].high_thr_lsb_addr;
+ reg_high_thr_msb = adc_tm_data[btm_chan_idx].high_thr_msb_addr;
+ } else {
+ reg_low_thr_lsb = QPNP_BTM_Mn_LOW_THR0(btm_chan_idx);
+ reg_low_thr_msb = QPNP_BTM_Mn_LOW_THR1(btm_chan_idx);
+ reg_high_thr_lsb = QPNP_BTM_Mn_HIGH_THR0(btm_chan_idx);
+ reg_high_thr_msb = QPNP_BTM_Mn_HIGH_THR1(btm_chan_idx);
+ }
switch (trip) {
case ADC_TM_TRIP_HIGH_WARM:
rc = qpnp_adc_tm_read_reg(chip, reg_low_thr_lsb,
- &trip_warm_thr0);
+ &trip_warm_thr0, 1);
if (rc) {
pr_err("adc-tm low_thr_lsb err\n");
return rc;
}
rc = qpnp_adc_tm_read_reg(chip, reg_low_thr_msb,
- &trip_warm_thr1);
+ &trip_warm_thr1, 1);
if (rc) {
pr_err("adc-tm low_thr_msb err\n");
return rc;
@@ -1307,14 +1674,14 @@ static int qpnp_adc_tm_get_trip_temp(struct thermal_zone_device *thermal,
break;
case ADC_TM_TRIP_LOW_COOL:
rc = qpnp_adc_tm_read_reg(chip, reg_high_thr_lsb,
- &trip_cool_thr0);
+ &trip_cool_thr0, 1);
if (rc) {
pr_err("adc-tm_tm high_thr_lsb err\n");
return rc;
}
rc = qpnp_adc_tm_read_reg(chip, reg_high_thr_msb,
- &trip_cool_thr1);
+ &trip_cool_thr1, 1);
if (rc) {
pr_err("adc-tm_tm high_thr_lsb err\n");
return rc;
@@ -1325,8 +1692,8 @@ static int qpnp_adc_tm_get_trip_temp(struct thermal_zone_device *thermal,
return -EINVAL;
}
- rc = qpnp_adc_tm_scale_voltage_therm_pu2(chip->vadc_dev, reg,
- &result);
+ rc = qpnp_adc_tm_scale_voltage_therm_pu2(chip->vadc_dev,
+ chip->adc->adc_prop, reg, &result);
if (rc < 0) {
pr_err("Failed to lookup the therm thresholds\n");
return rc;
@@ -1370,7 +1737,8 @@ static int qpnp_adc_tm_set_trip_temp(struct thermal_zone_device *thermal,
pr_debug("requested a high - %d and low - %d with trip - %d\n",
tm_config.high_thr_temp, tm_config.low_thr_temp, trip);
- rc = qpnp_adc_tm_scale_therm_voltage_pu2(chip->vadc_dev, &tm_config);
+ rc = qpnp_adc_tm_scale_therm_voltage_pu2(chip->vadc_dev,
+ chip->adc->adc_prop, &tm_config);
if (rc < 0) {
pr_err("Failed to lookup the adc-tm thresholds\n");
return rc;
@@ -1381,29 +1749,39 @@ static int qpnp_adc_tm_set_trip_temp(struct thermal_zone_device *thermal,
trip_cool_thr0 = ((tm_config.high_thr_voltage << 24) >> 24);
trip_cool_thr1 = ((tm_config.high_thr_voltage << 16) >> 24);
+ pr_debug("low_thr:0x%llx, high_thr:0x%llx\n", tm_config.low_thr_voltage,
+ tm_config.high_thr_voltage);
+
btm_chan = adc_tm->btm_channel_num;
- rc = qpnp_adc_tm_get_btm_idx(btm_chan, &btm_chan_idx);
+ rc = qpnp_adc_tm_get_btm_idx(chip, btm_chan, &btm_chan_idx);
if (rc < 0) {
pr_err("Invalid btm channel idx\n");
return rc;
}
- reg_low_thr_lsb = adc_tm_data[btm_chan_idx].low_thr_lsb_addr;
- reg_low_thr_msb = adc_tm_data[btm_chan_idx].low_thr_msb_addr;
- reg_high_thr_lsb = adc_tm_data[btm_chan_idx].high_thr_lsb_addr;
- reg_high_thr_msb = adc_tm_data[btm_chan_idx].high_thr_msb_addr;
+ if (!chip->adc_tm_hc) {
+ reg_low_thr_lsb = adc_tm_data[btm_chan_idx].low_thr_lsb_addr;
+ reg_low_thr_msb = adc_tm_data[btm_chan_idx].low_thr_msb_addr;
+ reg_high_thr_lsb = adc_tm_data[btm_chan_idx].high_thr_lsb_addr;
+ reg_high_thr_msb = adc_tm_data[btm_chan_idx].high_thr_msb_addr;
+ } else {
+ reg_low_thr_lsb = QPNP_BTM_Mn_LOW_THR0(btm_chan_idx);
+ reg_low_thr_msb = QPNP_BTM_Mn_LOW_THR1(btm_chan_idx);
+ reg_high_thr_lsb = QPNP_BTM_Mn_HIGH_THR0(btm_chan_idx);
+ reg_high_thr_msb = QPNP_BTM_Mn_HIGH_THR1(btm_chan_idx);
+ }
switch (trip) {
case ADC_TM_TRIP_HIGH_WARM:
rc = qpnp_adc_tm_write_reg(chip, reg_low_thr_lsb,
- trip_cool_thr0);
+ trip_cool_thr0, 1);
if (rc) {
pr_err("adc-tm_tm read threshold err\n");
return rc;
}
rc = qpnp_adc_tm_write_reg(chip, reg_low_thr_msb,
- trip_cool_thr1);
+ trip_cool_thr1, 1);
if (rc) {
pr_err("adc-tm_tm read threshold err\n");
return rc;
@@ -1412,14 +1790,14 @@ static int qpnp_adc_tm_set_trip_temp(struct thermal_zone_device *thermal,
break;
case ADC_TM_TRIP_LOW_COOL:
rc = qpnp_adc_tm_write_reg(chip, reg_high_thr_lsb,
- trip_warm_thr0);
+ trip_warm_thr0, 1);
if (rc) {
pr_err("adc-tm_tm read threshold err\n");
return rc;
}
rc = qpnp_adc_tm_write_reg(chip, reg_high_thr_msb,
- trip_warm_thr1);
+ trip_warm_thr1, 1);
if (rc) {
pr_err("adc-tm_tm read threshold err\n");
return rc;
@@ -1534,10 +1912,11 @@ static int qpnp_adc_tm_activate_trip_type(struct thermal_zone_device *thermal,
sensor_mask = 1 << adc_tm->sensor_num;
- pr_debug("Sensor number:%x with state:%d\n", adc_tm->sensor_num, state);
+ pr_debug("Sensor number:%x with state:%d\n",
+ adc_tm->sensor_num, state);
btm_chan = adc_tm->btm_channel_num;
- rc = qpnp_adc_tm_get_btm_idx(btm_chan, &btm_chan_idx);
+ rc = qpnp_adc_tm_get_btm_idx(chip, btm_chan, &btm_chan_idx);
if (rc < 0) {
pr_err("Invalid btm channel idx\n");
return rc;
@@ -1547,16 +1926,28 @@ static int qpnp_adc_tm_activate_trip_type(struct thermal_zone_device *thermal,
case ADC_TM_TRIP_HIGH_WARM:
/* low_thr (lower voltage) for higher temp */
thr_int_en = adc_tm_data[btm_chan_idx].low_thr_int_chan_en;
- rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_LOW_THR_INT_EN,
+ if (!chip->adc_tm_hc)
+ rc = qpnp_adc_tm_reg_update(chip,
+ QPNP_ADC_TM_LOW_THR_INT_EN,
sensor_mask, state);
+ else
+ rc = qpnp_adc_tm_reg_update(chip,
+ QPNP_BTM_Mn_EN(btm_chan_idx),
+ QPNP_BTM_Mn_LOW_THR_INT_EN, state);
if (rc)
pr_err("channel:%x failed\n", btm_chan);
break;
case ADC_TM_TRIP_LOW_COOL:
/* high_thr (higher voltage) for cooler temp */
thr_int_en = adc_tm_data[btm_chan_idx].high_thr_int_chan_en;
- rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_HIGH_THR_INT_EN,
+ if (!chip->adc_tm_hc)
+ rc = qpnp_adc_tm_reg_update(chip,
+ QPNP_ADC_TM_HIGH_THR_INT_EN,
sensor_mask, state);
+ else
+ rc = qpnp_adc_tm_reg_update(chip,
+ QPNP_BTM_Mn_EN(btm_chan_idx),
+ QPNP_BTM_Mn_HIGH_THR_INT_EN, state);
if (rc)
pr_err("channel:%x failed\n", btm_chan);
break;
@@ -1718,10 +2109,12 @@ static int qpnp_adc_tm_read_status(struct qpnp_adc_tm_chip *chip)
mutex_lock(&chip->adc->adc_lock);
- rc = qpnp_adc_tm_req_sts_check(chip);
- if (rc) {
- pr_err("adc-tm-tm req sts check failed with %d\n", rc);
- goto fail;
+ if (!chip->adc_tm_hc) {
+ rc = qpnp_adc_tm_req_sts_check(chip);
+ if (rc) {
+ pr_err("adc-tm-tm req sts check failed with %d\n", rc);
+ goto fail;
+ }
}
if (chip->th_info.adc_tm_high_enable) {
@@ -1844,11 +2237,22 @@ static int qpnp_adc_tm_read_status(struct qpnp_adc_tm_chip *chip)
if (chip->th_info.adc_tm_high_enable ||
chip->th_info.adc_tm_low_enable) {
- rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
- sensor_mask, false);
- if (rc < 0) {
- pr_err("multi meas disable for channel failed\n");
- goto fail;
+ if (!chip->adc_tm_hc) {
+ rc = qpnp_adc_tm_reg_update(chip,
+ QPNP_ADC_TM_MULTI_MEAS_EN,
+ sensor_mask, false);
+ if (rc < 0) {
+ pr_err("multi meas disable failed\n");
+ goto fail;
+ }
+ } else {
+ rc = qpnp_adc_tm_reg_update(chip,
+ QPNP_BTM_Mn_EN(sensor_mask),
+ QPNP_BTM_Mn_MEAS_EN, false);
+ if (rc < 0) {
+ pr_err("multi meas disable failed\n");
+ goto fail;
+ }
}
rc = qpnp_adc_tm_enable_if_channel_meas(chip);
@@ -1905,21 +2309,21 @@ static irqreturn_t qpnp_adc_tm_high_thr_isr(int irq, void *data)
qpnp_adc_tm_disable(chip);
- rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_STATUS1, &status1);
+ rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_STATUS1, &status1, 1);
if (rc) {
pr_err("adc-tm read status1 failed\n");
return IRQ_HANDLED;
}
rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_STATUS_HIGH,
- &chip->th_info.status_high);
+ &chip->th_info.status_high, 1);
if (rc) {
pr_err("adc-tm-tm read status high failed with %d\n", rc);
return IRQ_HANDLED;
}
rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_HIGH_THR_INT_EN,
- &chip->th_info.adc_tm_high_thr_set);
+ &chip->th_info.adc_tm_high_thr_set, 1);
if (rc) {
pr_err("adc-tm-tm read high thr failed with %d\n", rc);
return IRQ_HANDLED;
@@ -1928,7 +2332,7 @@ static irqreturn_t qpnp_adc_tm_high_thr_isr(int irq, void *data)
/* Check which interrupt threshold is lower and measure against the
* enabled channel */
rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
- &chip->th_info.qpnp_adc_tm_meas_en);
+ &chip->th_info.qpnp_adc_tm_meas_en, 1);
if (rc) {
pr_err("adc-tm-tm read status high failed with %d\n", rc);
return IRQ_HANDLED;
@@ -2008,28 +2412,28 @@ static irqreturn_t qpnp_adc_tm_low_thr_isr(int irq, void *data)
qpnp_adc_tm_disable(chip);
- rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_STATUS1, &status1);
+ rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_STATUS1, &status1, 1);
if (rc) {
pr_err("adc-tm read status1 failed\n");
return IRQ_HANDLED;
}
rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_STATUS_LOW,
- &chip->th_info.status_low);
+ &chip->th_info.status_low, 1);
if (rc) {
pr_err("adc-tm-tm read status low failed with %d\n", rc);
return IRQ_HANDLED;
}
rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_LOW_THR_INT_EN,
- &chip->th_info.adc_tm_low_thr_set);
+ &chip->th_info.adc_tm_low_thr_set, 1);
if (rc) {
pr_err("adc-tm-tm read low thr failed with %d\n", rc);
return IRQ_HANDLED;
}
rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
- &chip->th_info.qpnp_adc_tm_meas_en);
+ &chip->th_info.qpnp_adc_tm_meas_en, 1);
if (rc) {
pr_err("adc-tm-tm read status high failed with %d\n", rc);
return IRQ_HANDLED;
@@ -2077,6 +2481,137 @@ static irqreturn_t qpnp_adc_tm_low_thr_isr(int irq, void *data)
return IRQ_HANDLED;
}
+static int qpnp_adc_tm_rc_check_sensor_trip(struct qpnp_adc_tm_chip *chip,
+ u8 status_low, u8 status_high, int i,
+ int sensor_low_notify_num, int sensor_high_notify_num)
+{
+ int rc = 0;
+ u8 ctl = 0, sensor_mask = 0;
+
+ if (((status_low & 0x1) == 1) || ((status_high & 0x1) == 1)) {
+ rc = qpnp_adc_tm_read_reg(chip,
+ QPNP_BTM_Mn_EN(i), &ctl, 1);
+ if (rc) {
+ pr_err("ctl read failed with %d\n", rc);
+ return IRQ_HANDLED;
+ }
+
+ if ((status_low & 0x1) && (ctl & QPNP_BTM_Mn_MEAS_EN)
+ && (ctl & QPNP_BTM_Mn_LOW_THR_INT_EN)) {
+ /* Mask the corresponding low threshold interrupt en */
+ if (!chip->sensor[i].thermal_node) {
+ rc = qpnp_adc_tm_reg_update(chip,
+ QPNP_BTM_Mn_EN(i),
+ QPNP_BTM_Mn_LOW_THR_INT_EN, false);
+ if (rc < 0) {
+ pr_err("low thr_int en failed\n");
+ return IRQ_HANDLED;
+ }
+ } else {
+ /*
+ * Uses the thermal sysfs registered device to disable
+ * the corresponding low voltage threshold which
+ * is triggered by high temp
+ */
+ pr_debug("thermal node with mask:%x\n", sensor_mask);
+ rc = qpnp_adc_tm_activate_trip_type(
+ chip->sensor[i].tz_dev,
+ ADC_TM_TRIP_HIGH_WARM,
+ THERMAL_TRIP_ACTIVATION_DISABLED);
+ if (rc < 0) {
+ pr_err("notify error:%d\n", i);
+ return IRQ_HANDLED;
+ }
+ }
+ sensor_low_notify_num |= (status_low & 0x1);
+ }
+
+ if ((status_high & 0x1) && (ctl & QPNP_BTM_Mn_MEAS_EN) &&
+ (ctl & QPNP_BTM_Mn_HIGH_THR_INT_EN)) {
+ /* Mask the corresponding high threshold interrupt en */
+ if (!chip->sensor[i].thermal_node) {
+ rc = qpnp_adc_tm_reg_update(chip,
+ QPNP_BTM_Mn_EN(i),
+ QPNP_BTM_Mn_HIGH_THR_INT_EN, false);
+ if (rc < 0) {
+ pr_err("high thr_int en failed\n");
+ return IRQ_HANDLED;
+ }
+ } else {
+ /*
+ * Uses the thermal sysfs registered device to disable
+ * the corresponding high voltage threshold which
+ * is triggered by low temp
+ */
+ pr_debug("thermal node with mask:%x\n", i);
+ rc = qpnp_adc_tm_activate_trip_type(
+ chip->sensor[i].tz_dev,
+ ADC_TM_TRIP_LOW_COOL,
+ THERMAL_TRIP_ACTIVATION_DISABLED);
+ if (rc < 0) {
+ pr_err("notify error:%d\n", i);
+ return IRQ_HANDLED;
+ }
+ }
+ sensor_high_notify_num |= (status_high & 0x1);
+ }
+ }
+
+ return rc;
+}
+
+static irqreturn_t qpnp_adc_tm_rc_thr_isr(int irq, void *data)
+{
+ struct qpnp_adc_tm_chip *chip = data;
+ u8 status_low = 0, status_high = 0;
+ int rc = 0, sensor_low_notify_num = 0, i = 0;
+ int sensor_high_notify_num = 0;
+
+ rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_STATUS_LOW,
+ &status_low, 1);
+ if (rc) {
+ pr_err("adc-tm-tm read status low failed with %d\n", rc);
+ return IRQ_HANDLED;
+ }
+
+ if (status_low)
+ chip->th_info.adc_tm_low_enable = status_low;
+
+ rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_STATUS_HIGH,
+ &status_high, 1);
+ if (rc) {
+ pr_err("adc-tm-tm read status high failed with %d\n", rc);
+ return IRQ_HANDLED;
+ }
+
+ if (status_high)
+ chip->th_info.adc_tm_high_enable = status_high;
+
+ while (i < chip->max_channels_available) {
+ rc = qpnp_adc_tm_rc_check_sensor_trip(chip,
+ status_low, status_high, i,
+ sensor_low_notify_num, sensor_high_notify_num);
+ if (rc) {
+ pr_err("Sensor trip read failed\n");
+ return IRQ_HANDLED;
+ }
+ status_low >>= 1;
+ status_high >>= 1;
+ i++;
+ }
+
+ if (sensor_low_notify_num || sensor_high_notify_num)
+ atomic_inc(&chip->wq_cnt);
+
+ if (sensor_low_notify_num)
+ queue_work(chip->low_thr_wq, &chip->trigger_low_thr_work);
+
+ if (sensor_high_notify_num)
+ queue_work(chip->high_thr_wq, &chip->trigger_high_thr_work);
+
+ return IRQ_HANDLED;
+}
+
static int qpnp_adc_read_temp(struct thermal_zone_device *thermal,
int *temp)
{
@@ -2193,10 +2728,20 @@ int32_t qpnp_adc_tm_channel_measure(struct qpnp_adc_tm_chip *chip,
chip->sensor[dt_index].btm_channel_num;
chip->adc->amux_prop->chan_prop->state_request =
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_unlock;
+ chip->adc->amux_prop->calib_type =
+ chip->adc->adc_channels[dt_index].calib_type;
+ if (!chip->adc_tm_hc) {
+ rc = qpnp_adc_tm_configure(chip, chip->adc->amux_prop);
+ if (rc) {
+ pr_err("adc-tm configure failed with %d\n", rc);
+ goto fail_unlock;
+ }
+ } else {
+ rc = qpnp_adc_tm_hc_configure(chip, chip->adc->amux_prop);
+ if (rc) {
+ pr_err("adc-tm hc configure failed with %d\n", rc);
+ goto fail_unlock;
+ }
}
chip->sensor[dt_index].scale_type = scale_type;
@@ -2220,12 +2765,14 @@ int32_t qpnp_adc_tm_disable_chan_meas(struct qpnp_adc_tm_chip *chip,
mutex_lock(&chip->adc->adc_lock);
- /* 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;
+ if (!chip->adc_tm_hc) {
+ /* 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 */
@@ -2235,11 +2782,13 @@ int32_t qpnp_adc_tm_disable_chan_meas(struct qpnp_adc_tm_chip *chip,
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;
+ if (!chip->adc_tm_hc) {
+ /* 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;
+ }
}
channel = param->channel;
@@ -2254,27 +2803,51 @@ int32_t qpnp_adc_tm_disable_chan_meas(struct qpnp_adc_tm_chip *chip,
}
btm_chan_num = chip->sensor[dt_index].btm_channel_num;
- sensor_mask = 1 << chip->sensor[dt_index].sensor_num;
- 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;
- }
+ if (!chip->adc_tm_hc) {
+ sensor_mask = 1 << chip->sensor[dt_index].sensor_num;
- 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_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_MULTI_MEAS_EN,
- sensor_mask, false);
- if (rc < 0) {
- pr_err("multi measurement en 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;
+ }
+ } else {
+ rc = qpnp_adc_tm_reg_update(chip, QPNP_BTM_Mn_EN(btm_chan_num),
+ QPNP_BTM_Mn_HIGH_THR_INT_EN, false);
+ if (rc < 0) {
+ pr_err("high thr disable err:%d\n", btm_chan_num);
+ return rc;
+ }
+
+ rc = qpnp_adc_tm_reg_update(chip, QPNP_BTM_Mn_EN(btm_chan_num),
+ QPNP_BTM_Mn_LOW_THR_INT_EN, false);
+ if (rc < 0) {
+ pr_err("low thr disable err:%d\n", btm_chan_num);
+ return rc;
+ }
+
+ rc = qpnp_adc_tm_reg_update(chip, QPNP_BTM_Mn_EN(btm_chan_num),
+ QPNP_BTM_Mn_MEAS_EN, false);
+ if (rc < 0) {
+ pr_err("multi measurement disable failed\n");
+ return rc;
+ }
}
rc = qpnp_adc_tm_enable_if_channel_meas(chip);
@@ -2324,14 +2897,49 @@ struct qpnp_adc_tm_chip *qpnp_get_adc_tm(struct device *dev, const char *name)
}
EXPORT_SYMBOL(qpnp_get_adc_tm);
+static int qpnp_adc_tm_initial_setup(struct qpnp_adc_tm_chip *chip)
+{
+ u8 thr_init = 0;
+ int rc = 0;
+
+ rc = qpnp_adc_tm_write_reg(chip, QPNP_ADC_TM_HIGH_THR_INT_EN,
+ thr_init, 1);
+ if (rc < 0) {
+ pr_err("high thr init failed\n");
+ return rc;
+ }
+
+ rc = qpnp_adc_tm_write_reg(chip, QPNP_ADC_TM_LOW_THR_INT_EN,
+ thr_init, 1);
+ if (rc < 0) {
+ pr_err("low thr init failed\n");
+ return rc;
+ }
+
+ rc = qpnp_adc_tm_write_reg(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
+ thr_init, 1);
+ if (rc < 0) {
+ pr_err("multi meas en failed\n");
+ return rc;
+ }
+
+ return rc;
+}
+
+static const struct of_device_id qpnp_adc_tm_match_table[] = {
+ { .compatible = "qcom,qpnp-adc-tm" },
+ { .compatible = "qcom,qpnp-adc-tm-hc" },
+ {}
+};
+
static int qpnp_adc_tm_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node, *child;
struct qpnp_adc_tm_chip *chip;
struct qpnp_adc_drv *adc_qpnp;
int32_t count_adc_channel_list = 0, rc, sen_idx = 0, i = 0;
- u8 thr_init = 0;
bool thermal_node = false;
+ const struct of_device_id *id;
for_each_child_of_node(node, child)
count_adc_channel_list++;
@@ -2341,19 +2949,22 @@ static int qpnp_adc_tm_probe(struct platform_device *pdev)
return -EINVAL;
}
+ id = of_match_node(qpnp_adc_tm_match_table, node);
+ if (id == NULL) {
+ pr_err("qpnp_adc_tm_match of_node prop not present\n");
+ return -ENODEV;
+ }
+
chip = devm_kzalloc(&pdev->dev, sizeof(struct qpnp_adc_tm_chip) +
(count_adc_channel_list *
sizeof(struct qpnp_adc_tm_sensor)),
GFP_KERNEL);
- if (!chip) {
- dev_err(&pdev->dev, "Unable to allocate memory\n");
+ if (!chip)
return -ENOMEM;
- }
adc_qpnp = devm_kzalloc(&pdev->dev, sizeof(struct qpnp_adc_drv),
GFP_KERNEL);
if (!adc_qpnp) {
- dev_err(&pdev->dev, "Unable to allocate memory\n");
rc = -ENOMEM;
goto fail;
}
@@ -2367,6 +2978,11 @@ static int qpnp_adc_tm_probe(struct platform_device *pdev)
goto fail;
}
+ if (of_device_is_compatible(node, "qcom,qpnp-adc-tm-hc")) {
+ chip->adc_tm_hc = true;
+ chip->adc->adc_hc = true;
+ }
+
rc = qpnp_adc_get_devicetree_data(pdev, chip->adc);
if (rc) {
dev_err(&pdev->dev, "failed to read device tree\n");
@@ -2375,20 +2991,22 @@ static int qpnp_adc_tm_probe(struct platform_device *pdev)
mutex_init(&chip->adc->adc_lock);
/* Register the ADC peripheral interrupt */
- chip->adc->adc_high_thr_irq = platform_get_irq_byname(pdev,
- "high-thr-en-set");
- if (chip->adc->adc_high_thr_irq < 0) {
- pr_err("Invalid irq\n");
- rc = -ENXIO;
- goto fail;
- }
+ if (!chip->adc_tm_hc) {
+ chip->adc->adc_high_thr_irq = platform_get_irq_byname(pdev,
+ "high-thr-en-set");
+ if (chip->adc->adc_high_thr_irq < 0) {
+ pr_err("Invalid irq\n");
+ rc = -ENXIO;
+ goto fail;
+ }
- chip->adc->adc_low_thr_irq = platform_get_irq_byname(pdev,
- "low-thr-en-set");
- if (chip->adc->adc_low_thr_irq < 0) {
- pr_err("Invalid irq\n");
- rc = -ENXIO;
- goto fail;
+ chip->adc->adc_low_thr_irq = platform_get_irq_byname(pdev,
+ "low-thr-en-set");
+ if (chip->adc->adc_low_thr_irq < 0) {
+ pr_err("Invalid irq\n");
+ rc = -ENXIO;
+ goto fail;
+ }
}
chip->vadc_dev = qpnp_get_vadc(&pdev->dev, "adc_tm");
@@ -2398,6 +3016,7 @@ static int qpnp_adc_tm_probe(struct platform_device *pdev)
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");
@@ -2489,49 +3108,49 @@ static int qpnp_adc_tm_probe(struct platform_device *pdev)
pr_err("Requesting low thr priority wq failed\n");
goto fail;
}
- INIT_WORK(&chip->trigger_high_thr_work, qpnp_adc_tm_high_thr_work);
- INIT_WORK(&chip->trigger_low_thr_work, qpnp_adc_tm_low_thr_work);
- atomic_set(&chip->wq_cnt, 0);
-
- rc = qpnp_adc_tm_write_reg(chip, QPNP_ADC_TM_HIGH_THR_INT_EN,
- thr_init);
- if (rc < 0) {
- pr_err("high thr init failed\n");
+ chip->thr_wq = alloc_workqueue("qpnp_adc_tm_thr_wq",
+ WQ_HIGHPRI, 0);
+ if (!chip->thr_wq) {
+ pr_err("Requesting thr priority wq failed\n");
goto fail;
}
- rc = qpnp_adc_tm_write_reg(chip, QPNP_ADC_TM_LOW_THR_INT_EN,
- thr_init);
- if (rc < 0) {
- pr_err("low thr init failed\n");
- goto fail;
- }
+ INIT_WORK(&chip->trigger_high_thr_work, qpnp_adc_tm_high_thr_work);
+ INIT_WORK(&chip->trigger_low_thr_work, qpnp_adc_tm_low_thr_work);
+ atomic_set(&chip->wq_cnt, 0);
- rc = qpnp_adc_tm_write_reg(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
- thr_init);
- if (rc < 0) {
- pr_err("multi meas en failed\n");
- goto fail;
- }
+ if (!chip->adc_tm_hc) {
+ rc = qpnp_adc_tm_initial_setup(chip);
+ if (rc)
+ goto fail;
- rc = devm_request_irq(&pdev->dev, chip->adc->adc_high_thr_irq,
+ rc = devm_request_irq(&pdev->dev, chip->adc->adc_high_thr_irq,
qpnp_adc_tm_high_thr_isr,
IRQF_TRIGGER_RISING, "qpnp_adc_tm_high_interrupt", chip);
- if (rc) {
- dev_err(&pdev->dev, "failed to request adc irq\n");
- goto fail;
- } else {
- enable_irq_wake(chip->adc->adc_high_thr_irq);
- }
+ if (rc) {
+ dev_err(&pdev->dev, "failed to request adc irq\n");
+ goto fail;
+ } else {
+ enable_irq_wake(chip->adc->adc_high_thr_irq);
+ }
- rc = devm_request_irq(&pdev->dev, chip->adc->adc_low_thr_irq,
- qpnp_adc_tm_low_thr_isr,
- IRQF_TRIGGER_RISING, "qpnp_adc_tm_low_interrupt", chip);
- if (rc) {
- dev_err(&pdev->dev, "failed to request adc irq\n");
- goto fail;
+ rc = devm_request_irq(&pdev->dev, chip->adc->adc_low_thr_irq,
+ qpnp_adc_tm_low_thr_isr,
+ IRQF_TRIGGER_RISING, "qpnp_adc_tm_low_interrupt", chip);
+ if (rc) {
+ dev_err(&pdev->dev, "failed to request adc irq\n");
+ goto fail;
+ } else {
+ enable_irq_wake(chip->adc->adc_low_thr_irq);
+ }
} else {
- enable_irq_wake(chip->adc->adc_low_thr_irq);
+ rc = devm_request_irq(&pdev->dev, chip->adc->adc_irq_eoc,
+ qpnp_adc_tm_rc_thr_isr,
+ IRQF_TRIGGER_RISING, "qpnp_adc_tm_interrupt", chip);
+ if (rc)
+ dev_err(&pdev->dev, "failed to request adc irq\n");
+ else
+ enable_irq_wake(chip->adc->adc_irq_eoc);
}
chip->adc_vote_enable = false;
@@ -2549,7 +3168,6 @@ fail:
if (chip->sensor[i].req_wq)
destroy_workqueue(chip->sensor[sen_idx].req_wq);
}
- i++;
}
if (chip->high_thr_wq)
destroy_workqueue(chip->high_thr_wq);
@@ -2612,27 +3230,26 @@ static void qpnp_adc_tm_shutdown(struct platform_device *pdev)
/* Disable multimeasurement */
reg_val = 0;
- rc = qpnp_adc_tm_write_reg(chip, QPNP_ADC_TM_MULTI_MEAS_EN, reg_val);
+ rc = qpnp_adc_tm_write_reg(chip, QPNP_ADC_TM_MULTI_MEAS_EN, reg_val, 1);
if (rc < 0)
pr_err("adc-tm multi-measurement mode disable failed\n");
- rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_STATUS1, &status1);
+ rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_STATUS1, &status1, 1);
if (rc < 0)
pr_err("adc-tm status1 read failed\n");
- rc = qpnp_adc_tm_read_reg(chip, QPNP_EN_CTL1, &en_ctl1);
+ rc = qpnp_adc_tm_read_reg(chip, QPNP_EN_CTL1, &en_ctl1, 1);
if (rc < 0)
pr_err("adc-tm en_ctl1 read failed\n");
pr_debug("adc-tm status1=0%x, en_ctl1=0x%x\n", status1, en_ctl1);
- pr_debug("stopping all recurring measurements on adc-tm\n");
}
static int qpnp_adc_tm_suspend_noirq(struct device *dev)
{
struct qpnp_adc_tm_chip *chip = dev_get_drvdata(dev);
- if (0 != atomic_read(&chip->wq_cnt)) {
+ if (atomic_read(&chip->wq_cnt) != 0) {
pr_err(
"Aborting suspend, adc_tm notification running while suspending\n");
return -EBUSY;
@@ -2644,11 +3261,6 @@ static const struct dev_pm_ops qpnp_adc_tm_pm_ops = {
.suspend_noirq = qpnp_adc_tm_suspend_noirq,
};
-static const struct of_device_id qpnp_adc_tm_match_table[] = {
- { .compatible = "qcom,qpnp-adc-tm" },
- {}
-};
-
static struct platform_driver qpnp_adc_tm_driver = {
.driver = {
.name = "qcom,qpnp-adc-tm",
diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
index e143b93ce020..8d51ddcd4246 100644
--- a/include/linux/qpnp/qpnp-adc.h
+++ b/include/linux/qpnp/qpnp-adc.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -1062,7 +1062,7 @@ struct qpnp_vadc_chan_properties {
enum qpnp_adc_tm_channel_select tm_channel_select;
enum qpnp_state_request state_request;
enum qpnp_adc_calib_type calib_type;
- struct qpnp_vadc_linear_graph adc_graph[2];
+ struct qpnp_vadc_linear_graph adc_graph[ADC_HC_CAL_SEL_NONE];
};
/**
@@ -1243,6 +1243,10 @@ struct qpnp_adc_drv {
* @fast_avg_setup - Ability to provide single result from the ADC
* that is an average of multiple measurements.
* @trigger_channel - HW trigger channel for conversion sequencer.
+ * @calib_type - Used to store the calibration type for the channel
+ * absolute/ratiometric.
+ * @cal_val - Used to determine if fresh calibration value or timer
+ * updated calibration value is to be used.
* @chan_prop - Represent the channel properties of the ADC.
*/
struct qpnp_adc_amux_properties {
@@ -1252,6 +1256,8 @@ struct qpnp_adc_amux_properties {
uint32_t hw_settle_time;
uint32_t fast_avg_setup;
enum qpnp_vadc_trigger trigger_channel;
+ enum qpnp_adc_calib_type calib_type;
+ enum qpnp_adc_cal_val cal_val;
struct qpnp_vadc_chan_properties chan_prop[0];
};
@@ -1683,19 +1689,25 @@ int32_t qpnp_adc_qrd_skut1_btm_scaler(struct qpnp_vadc_chip *dev,
* and convert given temperature to voltage on supported
* thermistor channels using 100k pull-up.
* @dev: Structure device for qpnp vadc
+ * @adc_prop: adc properties of the qpnp adc such as bit resolution,
+ * reference voltage.
* @param: The input temperature values.
*/
int32_t qpnp_adc_tm_scale_therm_voltage_pu2(struct qpnp_vadc_chip *dev,
+ const struct qpnp_adc_properties *adc_properties,
struct qpnp_adc_tm_config *param);
/**
* qpnp_adc_tm_scale_therm_voltage_pu2() - Performs reverse calibration
* and converts the given ADC code to temperature for
* thermistor channels using 100k pull-up.
* @dev: Structure device for qpnp vadc
+ * @adc_prop: adc properties of the qpnp adc such as bit resolution,
+ * reference voltage.
* @reg: The input ADC code.
* @result: The physical measurement temperature on the thermistor.
*/
int32_t qpnp_adc_tm_scale_voltage_therm_pu2(struct qpnp_vadc_chip *dev,
+ const struct qpnp_adc_properties *adc_prop,
uint32_t reg, int64_t *result);
/**
* qpnp_adc_usb_scaler() - Performs reverse calibration on the low/high
@@ -2017,11 +2029,13 @@ static inline int32_t qpnp_adc_scale_millidegc_pmic_voltage_thr(
{ return -ENXIO; }
static inline int32_t qpnp_adc_tm_scale_therm_voltage_pu2(
struct qpnp_vadc_chip *dev,
+ const struct qpnp_adc_properties *adc_properties,
struct qpnp_adc_tm_config *param)
{ return -ENXIO; }
static inline int32_t qpnp_adc_tm_scale_voltage_therm_pu2(
struct qpnp_vadc_chip *dev,
- uint32_t reg, int64_t *result)
+ const struct qpnp_adc_properties *adc_prop,
+ uint32_t reg, int64_t *result)
{ return -ENXIO; }
static inline int32_t qpnp_adc_smb_btm_rscaler(struct qpnp_vadc_chip *dev,
struct qpnp_adc_tm_btm_param *param,