From 9a48d58ca2e3c42091a73c9efb1d58e0e465d3ed Mon Sep 17 00:00:00 2001 From: Shyam Kumar Thella Date: Thu, 3 Jun 2021 16:56:37 +0530 Subject: [PATCH] power: supply: qbg: Fixes in QBG driver Add changes required in QBG driver after validation on pm5100. 1. Add sample time for different QBG modes. 2. Store batt id and essential param revid after each FIFO processing and at startup use that data to decide whether to load SDAM data or not. 3. PM5100 ADC reports the batt_id directly, drop the voltage based conversion logic. 4. Fix the LSB value for current. Change-Id: Ib51f8c5e48c89ee7bf60e5ee9a6c575617461a02 Signed-off-by: Shyam Kumar Thella --- .../power/supply/qcom/qbg-battery-profile.c | 4 +- drivers/power/supply/qcom/qbg-core.h | 42 +++- drivers/power/supply/qcom/qbg-sdam.c | 105 ++++++-- drivers/power/supply/qcom/qbg-sdam.h | 19 +- drivers/power/supply/qcom/qti-qbg.c | 230 +++++++++++++----- include/uapi/linux/qbg.h | 17 +- 6 files changed, 330 insertions(+), 87 deletions(-) diff --git a/drivers/power/supply/qcom/qbg-battery-profile.c b/drivers/power/supply/qcom/qbg-battery-profile.c index 14b64f581e97..656a9de75d33 100644 --- a/drivers/power/supply/qcom/qbg-battery-profile.c +++ b/drivers/power/supply/qcom/qbg-battery-profile.c @@ -484,7 +484,7 @@ int qbg_batterydata_init(struct device_node *profile_node, rc = alloc_chrdev_region(&battery->dev_no, 0, 1, "qbg_battery"); if (rc < 0) { pr_err("Failed to allocate chrdev, rc=%d\n", rc); - goto free_battery; + return rc; } cdev_init(&battery->battery_cdev, &qbg_battery_data_fops); @@ -534,8 +534,6 @@ delete_cdev: cdev_del(&battery->battery_cdev); unregister_chrdev: unregister_chrdev_region(battery->dev_no, 1); -free_battery: - kfree(battery); return rc; } diff --git a/drivers/power/supply/qcom/qbg-core.h b/drivers/power/supply/qcom/qbg-core.h index 49a619373c08..2690377d3ff2 100644 --- a/drivers/power/supply/qcom/qbg-core.h +++ b/drivers/power/supply/qcom/qbg-core.h @@ -17,14 +17,13 @@ enum debug_mask { QBG_DEBUG_BUS_READ = BIT(0), QBG_DEBUG_BUS_WRITE = BIT(1), - QBG_DEBUG_FIFO = BIT(2), + QBG_DEBUG_SDAM = BIT(2), QBG_DEBUG_IRQ = BIT(3), QBG_DEBUG_DEVICE = BIT(4), QBG_DEBUG_PROFILE = BIT(5), QBG_DEBUG_SOC = BIT(6), - QBG_DEBUG_SDAM = BIT(7), - QBG_DEBUG_STATUS = BIT(8), - QBG_DEBUG_PON = BIT(9), + QBG_DEBUG_STATUS = BIT(7), + QBG_DEBUG_PON = BIT(8), }; enum qbg_sdam { @@ -37,6 +36,32 @@ enum qbg_sdam { SDAM_DATA4, }; +enum qbg_data_tag { + QBG_DATA_TAG_FAST_CHAR, +}; + +enum QBG_SAMPLE_NUM_TYPE { + SAMPLE_NUM_1, + SAMPLE_NUM_2, + SAMPLE_NUM_4, + SAMPLE_NUM_8, + SAMPLE_NUM_16, + SAMPLE_NUM_32, + QBG_SAMPLE_NUM_INVALID, +}; + +enum QBG_ACCUM_INTERVAL_TYPE { + ACCUM_INTERVAL_100MS, + ACCUM_INTERVAL_200MS, + ACCUM_INTERVAL_500MS, + ACCUM_INTERVAL_1000MS, + ACCUM_INTERVAL_2000MS, + ACCUM_INTERVAL_5000MS, + ACCUM_INTERVAL_10000MS, + ACCUM_INTERVAL_100000MS, + ACCUM_INTERVAL_INVALID, +}; + /** * struct qti_qbg - Structure for QTI QBG device * @dev: Pointer to QBG device structure @@ -70,8 +95,11 @@ enum qbg_sdam { * @batt_type_str: String array denoting battery type * @irq: QBG irq number * @base: Base address of QBG HW - * @num_sdams: Number of sdams used for QBG + * @num_data_sdams: Number of data sdams used for QBG * @batt_id_ohm: Battery resistance in ohms + * @sdam_batt_id: Battery ID stored and retrieved from SDAM + * @essential_param_revid: QBG essential parameters revision ID + * @sample_time_us: Array of accumulator sample time in each QBG HW state * @debug_mask: Debug mask to enable/disable debug prints * @pon_ocv: Power-on OCV of QBG device * @pon_ibat: Power-on current of QBG device @@ -138,9 +166,11 @@ struct qti_qbg { int irq; u32 base; u32 sdam_base; - u32 num_sdams; u32 num_data_sdams; u32 batt_id_ohm; + u32 sdam_batt_id; + u32 essential_param_revid; + u32 sample_time_us[QBG_STATE_MAX]; u32 *debug_mask; int pon_ocv; int pon_ibat; diff --git a/drivers/power/supply/qcom/qbg-sdam.c b/drivers/power/supply/qcom/qbg-sdam.c index 4baff57527c7..7afc4c422eea 100644 --- a/drivers/power/supply/qcom/qbg-sdam.c +++ b/drivers/power/supply/qcom/qbg-sdam.c @@ -49,22 +49,18 @@ int qbg_sdam_get_fifo_data(struct qti_qbg *chip, struct fifo_data *fifo, fifo_data_length = fifo_count * QBG_ONE_FIFO_LENGTH; num_sdams = fifo_data_length / QBG_SDAM_ONE_FIFO_REGION_SIZE; - if (num_sdams > chip->num_sdams) { + if (num_sdams > chip->num_data_sdams) { pr_err("Fifo count exceeds QBG SDAMs\n"); return -EINVAL; } - qbg_dbg(chip, QBG_DEBUG_FIFO, "Completely filled sdams=%d\n", + qbg_dbg(chip, QBG_DEBUG_SDAM, "Completely filled sdams=%d\n", num_sdams); /* First read SDAMs that are completely filled */ for (i = 0; i < num_sdams; i++) { - if (!chip->sdam[i]) { - pr_err("Number of SDAMs not sufficient to read FIFOs\n"); - return -ENODEV; - } rc = qbg_sdam_read(chip, - QBG_SDAM_DATA_START_OFFSET(chip, SDAM_DATA0 + i), + QBG_SDAM_DATA_START_OFFSET(chip, (SDAM_DATA0 + i)), (((u8 *)fifo) + bytes_read), QBG_SDAM_ONE_FIFO_REGION_SIZE); if (rc < 0) { @@ -77,12 +73,12 @@ int qbg_sdam_get_fifo_data(struct qti_qbg *chip, struct fifo_data *fifo, /* Next read SDAM that is partially filled */ bytes_remaining = fifo_data_length - bytes_read; - qbg_dbg(chip, QBG_DEBUG_FIFO, "Valid data in partially filled sdam:%d bytes\n", + qbg_dbg(chip, QBG_DEBUG_SDAM, "Valid data in partially filled sdam:%d bytes\n", bytes_remaining); if (bytes_remaining) { rc = qbg_sdam_read(chip, - QBG_SDAM_DATA_START_OFFSET(chip, SDAM_DATA0 + i), + QBG_SDAM_DATA_START_OFFSET(chip, (SDAM_DATA0 + i)), (((u8 *)fifo) + bytes_read), bytes_remaining); if (rc < 0) { @@ -93,7 +89,7 @@ int qbg_sdam_get_fifo_data(struct qti_qbg *chip, struct fifo_data *fifo, bytes_read += bytes_remaining; } - qbg_dbg(chip, QBG_DEBUG_FIFO, "Total bytes read=%d\n", bytes_read); + qbg_dbg(chip, QBG_DEBUG_SDAM, "Total bytes read=%d\n", bytes_read); return rc; } @@ -106,13 +102,13 @@ int qbg_sdam_get_essential_params(struct qti_qbg *chip, u8 *params) return -EINVAL; rc = qbg_sdam_read(chip, - chip->sdam_base + (SDAM_CTRL1 * 0x100) + + chip->sdam_base + (SDAM_CTRL1 * QBG_SINGLE_SDAM_SIZE) + QBG_ESSENTIAL_PARAMS_START_OFFSET, (u8 *)params, sizeof(struct qbg_essential_params)); if (rc < 0) pr_err("Failed to read QBG essential params, rc=%d\n", rc); else - qbg_dbg(chip, QBG_DEBUG_FIFO, "Read QBG essential params\n"); + qbg_dbg(chip, QBG_DEBUG_SDAM, "Read QBG essential params\n"); return rc; } @@ -125,13 +121,94 @@ int qbg_sdam_set_essential_params(struct qti_qbg *chip, u8 *params) return -EINVAL; rc = qbg_sdam_write(chip, - chip->sdam_base + (SDAM_CTRL1 * 0x100) + + chip->sdam_base + (SDAM_CTRL1 * QBG_SINGLE_SDAM_SIZE) + QBG_ESSENTIAL_PARAMS_START_OFFSET, (u8 *)params, sizeof(struct qbg_essential_params)); if (rc < 0) pr_err("Failed to write QBG essential params, rc=%d\n", rc); else - qbg_dbg(chip, QBG_DEBUG_FIFO, "Written QBG essential params\n"); + qbg_dbg(chip, QBG_DEBUG_SDAM, "Written QBG essential params\n"); + + return rc; +} + +int qbg_sdam_get_essential_param_revid(struct qti_qbg *chip, u8 *revid) +{ + int rc; + + if (!chip || !revid) + return -EINVAL; + + rc = qbg_sdam_read(chip, + chip->sdam_base + (SDAM_CTRL1 * QBG_SINGLE_SDAM_SIZE) + + QBG_ESSENTIAL_PARAMS_REVID_OFFSET, + revid, 1); + if (rc < 0) + pr_err("Failed to read QBG essential params revid, rc=%d\n", rc); + else + qbg_dbg(chip, QBG_DEBUG_SDAM, "Read QBG essential params revid:%u\n", *revid); + + return rc; +} + +int qbg_sdam_set_essential_param_revid(struct qti_qbg *chip, u8 revid) +{ + int rc; + + if (!chip) + return -EINVAL; + + rc = qbg_sdam_write(chip, + chip->sdam_base + (SDAM_CTRL1 * QBG_SINGLE_SDAM_SIZE) + + QBG_ESSENTIAL_PARAMS_REVID_OFFSET, + &revid, 1); + if (rc < 0) + pr_err("Failed to write QBG essential params revid, rc=%d\n", rc); + else + qbg_dbg(chip, QBG_DEBUG_SDAM, "Store QBG essential params revid:%u\n", + revid); + + return rc; +} + +int qbg_sdam_get_battery_id(struct qti_qbg *chip, u32 *battid) +{ + int rc; + u8 buf[2]; + + if (!chip || !battid) + return -EINVAL; + + rc = qbg_sdam_read(chip, + chip->sdam_base + (SDAM_CTRL1 * QBG_SINGLE_SDAM_SIZE) + + QBG_ESSENTIAL_PARAMS_BATTID_OFFSET, + buf, 2); + if (rc < 0) { + pr_err("Failed to read QBG battery ID, rc=%d\n", rc); + } else { + *battid = buf[0] | (buf[1] << 8); + qbg_dbg(chip, QBG_DEBUG_SDAM, "Read QBG battery ID:%u\n", + *battid); + } + + return rc; +} + +int qbg_sdam_set_battery_id(struct qti_qbg *chip, u32 battid) +{ + int rc; + + if (!chip) + return -EINVAL; + + rc = qbg_sdam_write(chip, + chip->sdam_base + (SDAM_CTRL1 * QBG_SINGLE_SDAM_SIZE) + + QBG_ESSENTIAL_PARAMS_BATTID_OFFSET, + (u8 *)&battid, 2); + if (rc < 0) + pr_err("Failed to write QBG battery ID, rc=%d\n", rc); + else + qbg_dbg(chip, QBG_DEBUG_SDAM, "Store QBG battery ID:%u\n", battid); return rc; } diff --git a/drivers/power/supply/qcom/qbg-sdam.h b/drivers/power/supply/qcom/qbg-sdam.h index db888cc20094..1e9109e99f3f 100644 --- a/drivers/power/supply/qcom/qbg-sdam.h +++ b/drivers/power/supply/qcom/qbg-sdam.h @@ -10,7 +10,9 @@ #define QBG_SDAM_FIFO_COUNT_OFFSET 0x46 #define QBG_ESSENTIAL_PARAMS_START_OFFSET 0x47 #define QBG_SDAM_START_OFFSET 0x4b +#define QBG_ESSENTIAL_PARAMS_BATTID_OFFSET 0x45 #define QBG_SDAM_BHARGER_OCV_HDRM_OFFSET 0x5b +#define QBG_ESSENTIAL_PARAMS_REVID_OFFSET 0xbb #define QBG_SDAM_INT_TEST1 0xe0 #define QBG_SDAM_INT_TEST_VAL 0xe1 #define QBG_SDAM_DATA_PUSH_COUNTER_OFFSET 0x46 @@ -19,14 +21,23 @@ #define QBG_SDAM_ONE_FIFO_REGION_SIZE 117 /* 117 bytes for FIFO starting from 0x4B */ #define QBG_SDAM_ESR_PULSE_FIFO_INDEX 11 -#define QBG_SDAM_DATA_START_OFFSET(chip, index) \ - (chip->sdam_base + (index * 0x100) + QBG_SDAM_START_OFFSET) +#define QBG_SINGLE_SDAM_SIZE 0x100 +#define QBG_SDAM_BASE(chip, index) (chip->sdam_base + (index * QBG_SINGLE_SDAM_SIZE)) -int qbg_sdam_read(struct qti_qbg *chip, int offset, u8 *data, int length); -int qbg_sdam_write(struct qti_qbg *chip, int offset, u8 *data, int length); +#define QBG_SDAM_DATA_START_OFFSET(chip, index) \ + (QBG_SDAM_BASE(chip, index) + QBG_SDAM_START_OFFSET) + +int qbg_sdam_read(struct qti_qbg *chip, int offset, u8 *data, + int length); +int qbg_sdam_write(struct qti_qbg *chip, int offset, u8 *data, + int length); int qbg_sdam_get_fifo_data(struct qti_qbg *chip, struct fifo_data *fifo, u32 fifo_count); int qbg_sdam_get_essential_params(struct qti_qbg *chip, u8 *params); int qbg_sdam_set_essential_params(struct qti_qbg *chip, u8 *params); +int qbg_sdam_get_essential_param_revid(struct qti_qbg *chip, u8 *revid); +int qbg_sdam_set_essential_param_revid(struct qti_qbg *chip, u8 revid); +int qbg_sdam_get_battery_id(struct qti_qbg *chip, u32 *battid); +int qbg_sdam_set_battery_id(struct qti_qbg *chip, u32 battid); #endif /* __QBG_SDAM_H__ */ diff --git a/drivers/power/supply/qcom/qti-qbg.c b/drivers/power/supply/qcom/qti-qbg.c index 952452390639..f06114c92b8d 100644 --- a/drivers/power/supply/qcom/qti-qbg.c +++ b/drivers/power/supply/qcom/qti-qbg.c @@ -67,15 +67,28 @@ #define QBG_MAIN_VBAT_EMPTY_THRESH 0x56 +#define QBG_MAIN_HPM_MEAS_CTL2 0x5d + +#define QBG_MAIN_MPM_MEAS_CTL2 0x61 + +#define QBG_MAIN_LPM_MEAS_CTL2 0x65 +#define QBG_NUM_OF_ACCUM_MASK GENMASK(7, 5) +#define QBG_NUM_OF_ACCUM_SHIFT 5 +#define QBG_ACCUM_INTERVAL_MASK GENMASK(2, 0) + +#define QBG_MAIN_FAST_CHAR_MEAS_CTL2 0x69 + #define QBG_MAIN_PON_OCV_ACC0_DATA0 0x70 +#define QBG_MAIN_LAST_ADC_ACC0_DATA0 0x9A + #define QBG_MAIN_LAST_BURST_AVG_ACC0_DATA0 0xA0 #define QBG_MAIN_LAST_BURST_AVG_ACC2_DATA0 0xA4 #define QBG_FAST_CHAR_DELTA_MS 100000 #define VBATT_1S_LSB 19463 -#define IBATT_10A_LSB 30518 +#define IBATT_10A_LSB 6103 #define VBAT_0PCT_OCV 300000000ULL #define ICHG_FS_10A 1 #define TBAT_LSB 7500 @@ -86,12 +99,15 @@ #define OCV_BOOST_MAX_UV 5600000 #define OCV_BOOST_STEP_UV 100000 -enum qbg_data_tag { - QBG_DATA_TAG_FAST_CHAR, -}; - static int qbg_debug_mask; +static const unsigned int qbg_accum_interval[8] = { + 10000, 20000, 50000, 100000, 150000, 200000, 500000, 1000000}; +static const unsigned int qbg_lpm_accum_interval[8] = { + 100000, 200000, 500000, 1000000, 2000000, 5000000, 10000000, 100000000}; +static const unsigned int qbg_fast_char_avg_interval[8] = { + 6250, 12500, 25000, 50000, 100000, 200000, 400000, 800000}; + static const struct qbg_iio_channels qbg_iio_psy_channels[] = { QBG_CHAN_INDEX("debug_battery", PSY_IIO_DEBUG_BATTERY) QBG_CHAN_ENERGY("capacity", PSY_IIO_CAPACITY) @@ -100,6 +116,7 @@ static const struct qbg_iio_channels qbg_iio_psy_channels[] = { QBG_CHAN_VOLT("voltage_max", PSY_IIO_VOLTAGE_MAX) QBG_CHAN_VOLT("voltage_now", PSY_IIO_VOLTAGE_NOW) QBG_CHAN_VOLT("voltage_ocv", PSY_IIO_VOLTAGE_OCV) + QBG_CHAN_VOLT("voltage_avg", PSY_IIO_VOLTAGE_AVG) QBG_CHAN_CUR("current_now", PSY_IIO_CURRENT_NOW) QBG_CHAN_RES("resistance_id", PSY_IIO_RESISTANCE_ID) QBG_CHAN_TSTAMP("time_to_full_avg", PSY_IIO_TIME_TO_FULL_AVG) @@ -215,7 +232,7 @@ static int qbg_get_fifo_count(struct qti_qbg *chip, u32 *fifo_count) u8 val[2]; rc = qbg_sdam_read(chip, - QBG_SDAM_DATA_START_OFFSET(chip, SDAM_CTRL0) + QBG_SDAM_FIFO_COUNT_OFFSET, + QBG_SDAM_BASE(chip, SDAM_CTRL0) + QBG_SDAM_FIFO_COUNT_OFFSET, val, 2); if (rc < 0) { pr_err("Failed to read QBG SDAM, rc=%d\n", rc); @@ -223,7 +240,7 @@ static int qbg_get_fifo_count(struct qti_qbg *chip, u32 *fifo_count) } *fifo_count = (val[1] << 8) | val[0]; - qbg_dbg(chip, QBG_DEBUG_FIFO, "FIFO count=%d\n", *fifo_count); + qbg_dbg(chip, QBG_DEBUG_SDAM, "FIFO count=%d\n", *fifo_count); return rc; } @@ -248,13 +265,14 @@ static void update_ocv_for_boost(struct qti_qbg *chip) qbg_dbg(chip, QBG_DEBUG_STATUS, "Boost OCV value written =%d\n", ocv_for_boost); qbg_sdam_write(chip, - QBG_SDAM_DATA_START_OFFSET(chip, SDAM_CTRL0) + QBG_SDAM_BHARGER_OCV_HDRM_OFFSET, + QBG_SDAM_BASE(chip, SDAM_CTRL0) + QBG_SDAM_BHARGER_OCV_HDRM_OFFSET, (u8 *)&ocv_for_boost, 1); } static void process_udata_work(struct work_struct *work) { struct qti_qbg *chip = container_of(work, struct qti_qbg, udata_work); + int rc; if (chip->udata.param[QBG_PARAM_BATT_SOC].valid) chip->batt_soc = chip->udata.param[QBG_PARAM_BATT_SOC].data; @@ -306,6 +324,20 @@ static void process_udata_work(struct work_struct *work) if (chip->udata.param[QBG_PARAM_TBAT].valid) chip->tbat = chip->udata.param[QBG_PARAM_TBAT].data; + if (chip->udata.param[QBG_PARAM_ESSENTIAL_PARAM_REVID].valid) { + chip->essential_param_revid = + chip->udata.param[QBG_PARAM_ESSENTIAL_PARAM_REVID].data; + + rc = qbg_sdam_set_essential_param_revid(chip, chip->essential_param_revid); + if (rc < 0) + pr_err("Failed to set essential param revid in sdam, rc=%d\n", + rc); + } + + rc = qbg_sdam_set_battery_id(chip, chip->batt_id_ohm / 1000); + if (rc < 0) + pr_err("Failed to set battid in sdam, rc=%d\n", rc); + qbg_dbg(chip, QBG_DEBUG_STATUS, "udata update: batt_soc=%d sys_soc=%d soc=%d qbg_esr=%d\n", (chip->batt_soc != INT_MIN) ? chip->batt_soc : -EINVAL, (chip->sys_soc != INT_MIN) ? chip->sys_soc : -EINVAL, @@ -382,7 +414,7 @@ static int qbg_process_fifo(struct qti_qbg *chip, u32 fifo_count) unsigned long timestamp; if (!fifo_count) { - qbg_dbg(chip, QBG_DEBUG_FIFO, "No FIFO data\n"); + qbg_dbg(chip, QBG_DEBUG_SDAM, "No FIFO data\n"); return -EINVAL; } @@ -439,7 +471,7 @@ static int qbg_process_fifo(struct qti_qbg *chip, u32 fifo_count) esr = (vbat1 - vbat1_esr) / ((ibat_esr - ibat) * 10000); esr *= 10000; chip->esr = esr; - qbg_dbg(chip, QBG_DEBUG_FIFO, "ESR:%u, ibat=%d ibat_esr=%d vbat1:%u vbat1_esr:%u\n", + qbg_dbg(chip, QBG_DEBUG_SDAM, "ESR:%u, ibat=%d ibat_esr=%d vbat1:%u vbat1_esr:%u\n", esr, ibat, ibat_esr, vbat1, vbat1_esr); } else { pr_err("Couldn't calculate ESR, ibat=%d ibat_esr=%d vbat1:%u vbat1_esr:%u\n", @@ -456,7 +488,7 @@ static int qbg_process_fifo(struct qti_qbg *chip, u32 fifo_count) goto ret; } - qbg_dbg(chip, QBG_DEBUG_FIFO, "vbat1:%u ibat:%d tbat:%u ibat_t:%u\n", + qbg_dbg(chip, QBG_DEBUG_SDAM, "vbat1:%u ibat:%d tbat:%u ibat_t:%u\n", vbat1, ibat, tbat, ibat_t); chip->kdata.fifo[i].v1 = vbat1; @@ -464,6 +496,7 @@ static int qbg_process_fifo(struct qti_qbg *chip, u32 fifo_count) chip->kdata.fifo[i].i = ibat; chip->kdata.fifo[i].tbat = tbat; chip->kdata.fifo[i].ibat = ibat_t; + chip->kdata.fifo[i].data_tag = fifo[i].data_tag; } ret: @@ -477,7 +510,7 @@ static int qbg_clear_fifo_data(struct qti_qbg *chip) u8 val[2] = {0, 0}; rc = qbg_sdam_write(chip, - QBG_SDAM_DATA_START_OFFSET(chip, SDAM_CTRL0) + QBG_SDAM_FIFO_COUNT_OFFSET, + QBG_SDAM_BASE(chip, SDAM_CTRL0) + QBG_SDAM_FIFO_COUNT_OFFSET, val, 2); if (rc < 0) { pr_err("Failed to clear QBG FIFO Count, rc=%d\n", rc); @@ -487,7 +520,7 @@ static int qbg_clear_fifo_data(struct qti_qbg *chip) for (i = 0; i < 10; i++) { val[0] = 0; rc = qbg_sdam_write(chip, - QBG_SDAM_DATA_START_OFFSET(chip, SDAM_CTRL0) + QBG_SDAM_INT_TEST_VAL, + QBG_SDAM_BASE(chip, SDAM_CTRL0) + QBG_SDAM_INT_TEST_VAL, val, 1); if (rc < 0) { pr_err("Failed to SDAM0 test val to 0, rc=%d\n", rc); @@ -496,7 +529,7 @@ static int qbg_clear_fifo_data(struct qti_qbg *chip) /* Handshake with PBS to access FIFO data */ rc = qbg_sdam_read(chip, - QBG_SDAM_DATA_START_OFFSET(chip, SDAM_CTRL0) + QBG_SDAM_INT_TEST_VAL, + QBG_SDAM_BASE(chip, SDAM_CTRL0) + QBG_SDAM_INT_TEST_VAL, val, 1); if (rc < 0) { pr_err("Failed to read QBG SDAM, rc=%d\n", rc); @@ -512,7 +545,7 @@ static int qbg_clear_fifo_data(struct qti_qbg *chip) val[0] = QBG_SDAM_START_OFFSET; val[1] = 0x0; rc = qbg_sdam_write(chip, - QBG_SDAM_DATA_START_OFFSET(chip, SDAM_DATA0) + QBG_SDAM_DATA_PUSH_COUNTER_OFFSET, + QBG_SDAM_BASE(chip, SDAM_DATA0) + QBG_SDAM_DATA_PUSH_COUNTER_OFFSET, val, 2); if (rc < 0) { pr_err("Failed to configure QBG data push counter, rc=%d\n", rc); @@ -520,7 +553,7 @@ static int qbg_clear_fifo_data(struct qti_qbg *chip) } val[0] = 0x0; rc = qbg_sdam_write(chip, - QBG_SDAM_DATA_START_OFFSET(chip, SDAM_CTRL0) + QBG_SDAM_PBS_STATUS_OFFSET, + QBG_SDAM_BASE(chip, SDAM_CTRL0) + QBG_SDAM_PBS_STATUS_OFFSET, val, 1); if (rc < 0) { pr_err("Failed to set QBG PBS status, rc=%d\n", rc); @@ -537,7 +570,7 @@ static int qbg_init_sdam(struct qti_qbg *chip) val[0] = 0x80; rc = qbg_sdam_write(chip, - QBG_SDAM_DATA_START_OFFSET(chip, SDAM_CTRL0) + QBG_SDAM_INT_TEST1, val, 1); + QBG_SDAM_BASE(chip, SDAM_CTRL0) + QBG_SDAM_INT_TEST1, val, 1); if (rc < 0) { pr_err("Failed to write QBG SDAM, rc=%d\n", rc); return rc; @@ -545,7 +578,7 @@ static int qbg_init_sdam(struct qti_qbg *chip) val[0] = 0; rc = qbg_sdam_read(chip, - QBG_SDAM_DATA_START_OFFSET(chip, SDAM_CTRL0) + QBG_SDAM_INT_TEST_VAL, + QBG_SDAM_BASE(chip, SDAM_CTRL0) + QBG_SDAM_INT_TEST_VAL, val, 1); if (rc < 0) { pr_err("Faiiled to read QBG SDAM, rc=%d\n", rc); @@ -687,7 +720,7 @@ static int qbg_load_battery_profile(struct qti_qbg *chip) } profile_node = of_batterydata_get_best_profile(chip->batt_node, - chip->batt_id_ohm, NULL); + chip->batt_id_ohm / 1000, NULL); if (IS_ERR(profile_node)) { rc = PTR_ERR(profile_node); pr_err("Failed to detect valid QBG battery profile, rc=%d\n", @@ -723,7 +756,7 @@ static int qbg_load_battery_profile(struct qti_qbg *chip) goto out; } - rc = of_property_read_u32(profile_node, "qcom,fastchg-curr-ma", + rc = of_property_read_u32(profile_node, "qcom,fastchg-current-ma", &chip->fastchg_curr_ma); if (rc < 0) { pr_err("Failed to read battery fastcharge current, rc:%d\n", rc); @@ -868,42 +901,23 @@ static bool is_battery_present(struct qti_qbg *chip) return present; } -#define BID_RPULL_OHM 100000 -#define BID_VREF_MV 1875 static int get_batt_id_ohm(struct qti_qbg *chip, u32 *batt_id_ohm) { - int rc, batt_id_mv; - int64_t denom; + int rc, batt_id; if (!chip->batt_id_chan) return -EINVAL; /* Read battery-id */ - rc = iio_read_channel_processed(chip->batt_id_chan, &batt_id_mv); + rc = iio_read_channel_processed(chip->batt_id_chan, &batt_id); if (rc < 0) { pr_err("Failed to read BATT_ID over ADC, rc=%d\n", rc); return rc; } - batt_id_mv = div_s64(batt_id_mv, 1000); - if (batt_id_mv == 0) { - *batt_id_ohm = 0; - pr_debug("batt_id_mv = 0 from ADC\n"); - return 0; - } + *batt_id_ohm = (u32)batt_id; - denom = div64_s64(BID_VREF_MV * 1000, batt_id_mv) - 1000; - if (denom <= 0) { - /* batt id connector might be open, return 0 kohms */ - *batt_id_ohm = 0; - return 0; - } - - *batt_id_ohm = div64_u64(BID_RPULL_OHM * 1000 + denom / 2, denom); - chip->batt_id_ohm = *batt_id_ohm; - - qbg_dbg(chip, QBG_DEBUG_PROFILE, "batt_id_mv=%d, batt_id_ohm=%d\n", - batt_id_mv, *batt_id_ohm); + qbg_dbg(chip, QBG_DEBUG_PROFILE, "batt_id_ohm=%u\n", *batt_id_ohm); return 0; } @@ -934,7 +948,7 @@ static int qbg_setup_battery(struct qti_qbg *chip) /* Update OCV boost headroom compensation value to 4.3V in debug battery case */ if (is_debug_batt_id(chip)) { rc = qbg_sdam_write(chip, - QBG_SDAM_DATA_START_OFFSET(chip, SDAM_CTRL0) + + QBG_SDAM_BASE(chip, SDAM_CTRL0) + QBG_SDAM_BHARGER_OCV_HDRM_OFFSET, &ocv_boost_val, 1); } } @@ -1034,13 +1048,6 @@ static int qbg_determine_pon_soc(struct qti_qbg *chip) return 0; } -static int qbg_psy_set_prop(struct power_supply *psy, - enum power_supply_property psp, - const union power_supply_propval *pval) -{ - return 0; -} - static int qbg_psy_get_prop(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *pval) @@ -1061,7 +1068,6 @@ static struct power_supply_desc qbg_psy_desc = { .properties = qbg_psy_props, .num_properties = ARRAY_SIZE(qbg_psy_props), .get_property = qbg_psy_get_prop, - .set_property = qbg_psy_set_prop, }; static int qbg_init_psy(struct qti_qbg *chip) @@ -1121,6 +1127,9 @@ static int qbg_iio_read_raw(struct iio_dev *indio_dev, case PSY_IIO_VOLTAGE_OCV: *val1 = chip->ocv_uv; break; + case PSY_IIO_VOLTAGE_AVG: + rc = qbg_get_battery_voltage(chip, val1); + break; case PSY_IIO_VOLTAGE_NOW: rc = qbg_get_battery_voltage(chip, val1); break; @@ -1228,6 +1237,85 @@ static int qbg_init_iio(struct qti_qbg *chip, return rc; } +static int qbg_get_accumulator_properties(struct qti_qbg *chip, + enum QBG_STATE state, + enum QBG_SAMPLE_NUM_TYPE *num_of_accum, + enum QBG_ACCUM_INTERVAL_TYPE *accum_interval) +{ + int rc = 0; + unsigned int reg = QBG_MAIN_LPM_MEAS_CTL2; + unsigned char data = 0; + + if (state >= QBG_STATE_MAX || !num_of_accum || !accum_interval) + return -EINVAL; + + switch (state) { + case QBG_LPM: + reg = QBG_MAIN_LPM_MEAS_CTL2; + break; + case QBG_MPM: + reg = QBG_MAIN_MPM_MEAS_CTL2; + break; + case QBG_HPM: + reg = QBG_MAIN_HPM_MEAS_CTL2; + break; + case QBG_FAST_CHAR: + reg = QBG_MAIN_FAST_CHAR_MEAS_CTL2; + break; + default: + pr_err("Invalid QBG state requested for accumulator properties %u\n", + state); + return rc; + } + + rc = qbg_read(chip, reg, &data, 1); + if (rc < 0) { + pr_err("Failed to MEAS_CTL2 %u, rc=%d\n", reg, rc); + return rc; + } + + if (state == QBG_FAST_CHAR) + *num_of_accum = 0; + else + *num_of_accum = (data & QBG_NUM_OF_ACCUM_MASK) >> QBG_NUM_OF_ACCUM_SHIFT; + + *accum_interval = data & QBG_ACCUM_INTERVAL_MASK; + + qbg_dbg(chip, QBG_DEBUG_DEVICE, "state:%u num_of_accum:%u accum_interval:%u\n", + state, *num_of_accum, *accum_interval); + + return rc; +} + +static int qbg_get_sample_time_us(struct qti_qbg *chip) +{ + int rc = 0, index; + unsigned int interval; + enum QBG_ACCUM_INTERVAL_TYPE accum_interval = ACCUM_INTERVAL_100MS; + enum QBG_SAMPLE_NUM_TYPE num_accum = SAMPLE_NUM_1; + + for (index = 0; index < QBG_STATE_MAX; index++) { + if (index == QBG_PON_OCV) + continue; + + rc = qbg_get_accumulator_properties(chip, index, &num_accum, + &accum_interval); + if (rc < 0) + return rc; + + if (index == QBG_FAST_CHAR) + interval = qbg_fast_char_avg_interval[accum_interval]; + else if (index == QBG_LPM) + interval = qbg_lpm_accum_interval[accum_interval]; + else + interval = qbg_accum_interval[accum_interval]; + + chip->sample_time_us[index] = interval; + } + + return rc; +} + static ssize_t qbg_device_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { @@ -1361,7 +1449,7 @@ static long qbg_device_ioctl(struct file *file, unsigned int cmd, struct qbg_config config; struct qbg_essential_params __user *params_user; unsigned long rtc_sec; - int rc = 0; + int rc = 0, i; if (!chip) { pr_err("Device private data not set!\n"); @@ -1383,8 +1471,29 @@ static long qbg_device_ioctl(struct file *file, unsigned int cmd, switch (cmd) { case QBGIOCXCFG: config_user = (struct qbg_config __user *)arg; + + rc = qbg_get_sample_time_us(chip); + if (rc < 0) { + pr_err("Failed to calculate sample time us, rc=%d\n", rc); + return rc; + } + + rc = qbg_sdam_get_battery_id(chip, &chip->sdam_batt_id); + if (rc < 0) { + pr_err("Failed to get battid from sdam, rc=%d\n", rc); + return rc; + } + + rc = qbg_sdam_get_essential_param_revid(chip, + (u8 *)&chip->essential_param_revid); + if (rc < 0) { + pr_err("Failed to get essential param revid, rc=%d\n", + rc); + return rc; + } + config.current_time = rtc_sec; - config.batt_id = chip->batt_id_ohm; + config.batt_id = chip->batt_id_ohm / 1000; config.pon_ocv = chip->pon_ocv; config.pon_ibat = chip->pon_ibat; config.pon_tbat = chip->pon_tbat; @@ -1395,16 +1504,25 @@ static long qbg_device_ioctl(struct file *file, unsigned int cmd, config.vph_min_mv = chip->vph_min_mv; config.iterm_ma = chip->iterm_ma; config.rconn_mohm = chip->rconn_mohm; + config.sdam_batt_id = chip->sdam_batt_id; + config.essential_param_revid = chip->essential_param_revid; + for (i = 0; i < QBG_STATE_MAX; i++) { + config.sample_time_us[i] = chip->sample_time_us[i]; + qbg_dbg(chip, QBG_DEBUG_DEVICE, "QBGIOCXCFG: sample_time_us[%d]:%u\n", + i, config.sample_time_us[i]); + } if (copy_to_user(config_user, (void *)&config, sizeof(config))) { pr_err("Failed to copy QBG config to user\n"); return -EFAULT; } - qbg_dbg(chip, QBG_DEBUG_DEVICE, "QBGIOCXCFG: battid:%u pon_ocv:%u pon_ibat:%u pon_soc:%u vbatt_cutoff_mv:%u iterm_ma:%u\n", + qbg_dbg(chip, QBG_DEBUG_DEVICE, "QBGIOCXCFG: sdam_battid:%u essential param revid:%u battid:%u pon_ocv:%u pon_ibat:%u pon_soc:%u vbatt_cutoff_mv:%u iterm_ma:%u\n", + config.sdam_batt_id, config.essential_param_revid, config.batt_id, config.pon_ocv, config.pon_ibat, config.pon_soc, config.vbat_cutoff_mv, config.iterm_ma); + break; case QBGIOCXEPR: params_user = (struct qbg_essential_params __user *)arg; @@ -1538,7 +1656,7 @@ static int qbg_parse_sdam_dt(struct qti_qbg *chip, struct device_node *node) return rc; } - rc = of_property_read_u32(node, "sdam-base", &chip->sdam_base); + rc = of_property_read_u32(node, "qcom,sdam-base", &chip->sdam_base); if (rc < 0) { pr_err("Failed to read SDAM base address, rc=%d\n", rc); return rc; diff --git a/include/uapi/linux/qbg.h b/include/uapi/linux/qbg.h index f8bbb4e1a90c..4ca6a65ee62a 100644 --- a/include/uapi/linux/qbg.h +++ b/include/uapi/linux/qbg.h @@ -8,6 +8,15 @@ #define MAX_FIFO_COUNT 36 +enum QBG_STATE { + QBG_LPM, + QBG_MPM, + QBG_HPM, + QBG_FAST_CHAR, + QBG_PON_OCV, + QBG_STATE_MAX, +}; + enum QBG_SDAM_DATA_OFFSET { QBG_ACC0_OFFSET = 0, QBG_ACC1_OFFSET = 2, @@ -41,10 +50,7 @@ enum qbg { QBG_PARAM_SYS_SOC_HOLD_100PCT, QBG_PARAM_JEITA_COOL_THRESHOLD, QBG_PARAM_TOTAL_IMPEDANCE, - QBG_PARAM_PON_OCV, - QBG_PARAM_PON_IBAT, - QBG_PARAM_PON_SOC, - QBG_PARAM_BATT_ID, + QBG_PARAM_ESSENTIAL_PARAM_REVID, QBG_PARAM_FIFO_TIMESTAMP, QBG_PARAM_MAX, }; @@ -115,6 +121,9 @@ struct qbg_config { unsigned int iterm_ma; unsigned int rconn_mohm; unsigned long current_time; + unsigned int sdam_batt_id; + unsigned int essential_param_revid; + unsigned long sample_time_us[QBG_STATE_MAX]; } __attribute__ ((__packed__)); struct qbg_param {