Loading drivers/power/supply/qcom/qbg-battery-profile.c +1 −3 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -534,8 +534,6 @@ int qbg_batterydata_init(struct device_node *profile_node, cdev_del(&battery->battery_cdev); unregister_chrdev: unregister_chrdev_region(battery->dev_no, 1); free_battery: kfree(battery); return rc; } Loading drivers/power/supply/qcom/qbg-core.h +36 −6 Original line number Diff line number Diff line Loading @@ -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 { Loading @@ -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 Loading Loading @@ -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 Loading Loading @@ -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; Loading drivers/power/supply/qcom/qbg-sdam.c +91 −14 Original line number Diff line number Diff line Loading @@ -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) { Loading @@ -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) { Loading @@ -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; } Loading @@ -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; } Loading @@ -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; } drivers/power/supply/qcom/qbg-sdam.h +14 −3 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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_SINGLE_SDAM_SIZE 0x100 #define QBG_SDAM_BASE(chip, index) (chip->sdam_base + (index * QBG_SINGLE_SDAM_SIZE)) #define QBG_SDAM_DATA_START_OFFSET(chip, index) \ (chip->sdam_base + (index * 0x100) + QBG_SDAM_START_OFFSET) (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_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__ */ drivers/power/supply/qcom/qti-qbg.c +174 −56 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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) Loading @@ -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) Loading Loading @@ -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); Loading @@ -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; } Loading @@ -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; Loading Loading @@ -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, Loading Loading @@ -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; } Loading Loading @@ -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", Loading @@ -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; Loading @@ -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: Loading @@ -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); Loading @@ -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); Loading @@ -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); Loading @@ -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); Loading @@ -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); Loading @@ -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; Loading @@ -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); Loading Loading @@ -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", Loading Loading @@ -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); Loading Loading @@ -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; } 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; *batt_id_ohm = (u32)batt_id; 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; } Loading Loading @@ -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); } } Loading Loading @@ -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) Loading @@ -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) Loading Loading @@ -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; Loading Loading @@ -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) { Loading Loading @@ -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"); Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading Loading
drivers/power/supply/qcom/qbg-battery-profile.c +1 −3 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -534,8 +534,6 @@ int qbg_batterydata_init(struct device_node *profile_node, cdev_del(&battery->battery_cdev); unregister_chrdev: unregister_chrdev_region(battery->dev_no, 1); free_battery: kfree(battery); return rc; } Loading
drivers/power/supply/qcom/qbg-core.h +36 −6 Original line number Diff line number Diff line Loading @@ -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 { Loading @@ -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 Loading Loading @@ -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 Loading Loading @@ -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; Loading
drivers/power/supply/qcom/qbg-sdam.c +91 −14 Original line number Diff line number Diff line Loading @@ -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) { Loading @@ -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) { Loading @@ -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; } Loading @@ -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; } Loading @@ -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; }
drivers/power/supply/qcom/qbg-sdam.h +14 −3 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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_SINGLE_SDAM_SIZE 0x100 #define QBG_SDAM_BASE(chip, index) (chip->sdam_base + (index * QBG_SINGLE_SDAM_SIZE)) #define QBG_SDAM_DATA_START_OFFSET(chip, index) \ (chip->sdam_base + (index * 0x100) + QBG_SDAM_START_OFFSET) (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_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__ */
drivers/power/supply/qcom/qti-qbg.c +174 −56 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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) Loading @@ -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) Loading Loading @@ -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); Loading @@ -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; } Loading @@ -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; Loading Loading @@ -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, Loading Loading @@ -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; } Loading Loading @@ -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", Loading @@ -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; Loading @@ -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: Loading @@ -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); Loading @@ -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); Loading @@ -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); Loading @@ -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); Loading @@ -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); Loading @@ -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; Loading @@ -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); Loading Loading @@ -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", Loading Loading @@ -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); Loading Loading @@ -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; } 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; *batt_id_ohm = (u32)batt_id; 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; } Loading Loading @@ -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); } } Loading Loading @@ -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) Loading @@ -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) Loading Loading @@ -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; Loading Loading @@ -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) { Loading Loading @@ -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"); Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading