123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247 |
- // SPDX-License-Identifier: GPL-2.0-only
- /*
- * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
- */
- #define pr_fmt(fmt) "QCOM-BATT: %s: " fmt, __func__
- #include <linux/debugfs.h>
- #include <linux/device.h>
- #include <linux/delay.h>
- #include <linux/module.h>
- #include <linux/platform_device.h>
- #include <linux/regmap.h>
- #include <linux/power_supply.h>
- #include <linux/interrupt.h>
- #include <linux/of.h>
- #include <linux/of_irq.h>
- #include <linux/printk.h>
- #include <linux/pm_wakeup.h>
- #include <linux/slab.h>
- #include <linux/pmic-voter.h>
- #include <linux/qti_power_supply.h>
- #include <linux/workqueue.h>
- #include <linux/iio/consumer.h>
- #include <dt-bindings/iio/qti_power_supply_iio.h>
- #include "battery.h"
- #include "smb5-iio.h"
- #define DRV_MAJOR_VERSION 1
- #define DRV_MINOR_VERSION 0
- #define BATT_PROFILE_VOTER "BATT_PROFILE_VOTER"
- #define CHG_STATE_VOTER "CHG_STATE_VOTER"
- #define TAPER_STEPPER_VOTER "TAPER_STEPPER_VOTER"
- #define TAPER_END_VOTER "TAPER_END_VOTER"
- #define PL_TAPER_EARLY_BAD_VOTER "PL_TAPER_EARLY_BAD_VOTER"
- #define PARALLEL_PSY_VOTER "PARALLEL_PSY_VOTER"
- #define PL_HW_ABSENT_VOTER "PL_HW_ABSENT_VOTER"
- #define PL_VOTER "PL_VOTER"
- #define RESTRICT_CHG_VOTER "RESTRICT_CHG_VOTER"
- #define ICL_CHANGE_VOTER "ICL_CHANGE_VOTER"
- #define PL_INDIRECT_VOTER "PL_INDIRECT_VOTER"
- #define USBIN_I_VOTER "USBIN_I_VOTER"
- #define PL_FCC_LOW_VOTER "PL_FCC_LOW_VOTER"
- #define ICL_LIMIT_VOTER "ICL_LIMIT_VOTER"
- #define FCC_STEPPER_VOTER "FCC_STEPPER_VOTER"
- #define FCC_VOTER "FCC_VOTER"
- #define MAIN_FCC_VOTER "MAIN_FCC_VOTER"
- #define PD_VOTER "PD_VOTER"
- /* PMI8998 */
- #define PMI8998_SUBTYPE 0x15
- /* PM660 */
- #define PM660_SUBTYPE 0x1B
- struct pl_data {
- struct device *dev;
- int pl_mode;
- int pl_batfet_mode;
- int pl_min_icl_ua;
- int slave_pct;
- int slave_fcc_ua;
- int main_fcc_ua;
- int restricted_current;
- bool restricted_charging_enabled;
- struct votable *fcc_votable;
- struct votable *fv_votable;
- struct votable *pl_disable_votable;
- struct votable *pl_awake_votable;
- struct votable *hvdcp_hw_inov_dis_votable;
- struct votable *usb_icl_votable;
- struct votable *pl_enable_votable_indirect;
- struct votable *cp_ilim_votable;
- struct votable *cp_disable_votable;
- struct votable *fcc_main_votable;
- struct votable *cp_slave_disable_votable;
- struct delayed_work status_change_work;
- struct work_struct pl_disable_forever_work;
- struct work_struct pl_taper_work;
- struct delayed_work fcc_stepper_work;
- bool taper_work_running;
- struct power_supply *pl_psy;
- struct power_supply *batt_psy;
- struct power_supply *usb_psy;
- struct power_supply *dc_psy;
- struct power_supply *cp_master_psy;
- int charge_type;
- int total_settled_ua;
- int pl_settled_ua;
- int pl_fcc_max;
- int fcc_stepper_enable;
- int main_step_fcc_dir;
- int main_step_fcc_count;
- int main_step_fcc_residual;
- int parallel_step_fcc_dir;
- int parallel_step_fcc_count;
- int parallel_step_fcc_residual;
- int step_fcc;
- int override_main_fcc_ua;
- int total_fcc_ua;
- u32 wa_flags;
- struct class qcom_batt_class;
- struct wakeup_source *pl_ws;
- struct notifier_block nb;
- struct charger_param *chg_param;
- bool pl_disable;
- bool cp_disabled;
- int taper_entry_fv;
- int main_fcc_max;
- int charger_type;
- /* debugfs directory */
- struct dentry *dfs_root;
- u32 float_voltage_uv;
- struct iio_channel **iio_chan_list_cp;
- struct iio_channel *iio_chan_list_cp_slave;
- struct iio_channel **iio_chan_list_smb_parallel;
- };
- static struct pl_data *the_chip;
- enum print_reason {
- PR_PARALLEL = BIT(0),
- };
- enum {
- AICL_RERUN_WA_BIT = BIT(0),
- FORCE_INOV_DISABLE_BIT = BIT(1),
- };
- static int debug_mask;
- #define pl_dbg(chip, reason, fmt, ...) \
- do { \
- if (debug_mask & (reason)) \
- pr_info(fmt, ##__VA_ARGS__); \
- else \
- pr_debug(fmt, ##__VA_ARGS__); \
- } while (0)
- #define IS_USBIN(mode) ((mode == QTI_POWER_SUPPLY_PL_USBIN_USBIN) \
- || (mode == QTI_POWER_SUPPLY_PL_USBIN_USBIN_EXT))
- enum {
- VER = 0,
- SLAVE_PCT,
- RESTRICT_CHG_ENABLE,
- RESTRICT_CHG_CURRENT,
- FCC_STEPPING_IN_PROGRESS,
- };
- enum {
- PARALLEL_INPUT_MODE,
- PARALLEL_OUTPUT_MODE,
- };
- /* CP Channels */
- static const char * const bat_cp_ext_iio_chan[] = {
- [BAT_CP_PARALLEL_MODE] = "cp_parallel_mode",
- [BAT_CP_PARALLEL_OUTPUT_MODE] = "cp_parallel_output_mode",
- [BAT_CP_MIN_ICL] = "cp_min_icl",
- [BAT_CP_SWITCHER_EN] = "cp_switcher_en",
- };
- /* SMB1355 Channels */
- static const char * const bat_smb_parallel_ext_iio_chan[] = {
- [BAT_SMB_PARALLEL_INPUT_SUSPEND] = "pl_input_suspend",
- [BAT_SMB_PARALLEL_MODE] = "pl_mode",
- [BAT_SMB_PARALLEL_BATFET_MODE] = "pl_batfet_mode",
- [BAT_SMB_PARALLEL_MIN_ICL] = "pl_min_icl",
- [BAT_SMB_PARALLEL_FCC_MAX] = "pl_fcc_max",
- [BAT_SMB_PARALLEL_CURRENT_MAX] = "pl_current_max",
- [BAT_SMB_PARALLEL_CONSTANT_CHARGE_CURRENT_MAX] =
- "pl_constant_charge_current_max",
- [BAT_SMB_PARALLEL_VOLTAGE_MAX] = "pl_voltage_max",
- [BAT_SMB_PARALLEL_CHARGE_TYPE] = "pl_charge_type",
- };
- /*********
- * HELPER*
- *********/
- static bool is_usb_available(struct pl_data *chip)
- {
- if (!chip->usb_psy)
- chip->usb_psy =
- power_supply_get_by_name("usb");
- return !!chip->usb_psy;
- }
- static bool is_cp_available(struct pl_data *chip)
- {
- int rc;
- struct iio_channel **iio_list;
- if (IS_ERR(chip->iio_chan_list_cp))
- return false;
- if (!chip->iio_chan_list_cp) {
- iio_list = get_ext_channels(chip->dev,
- bat_cp_ext_iio_chan,
- ARRAY_SIZE(bat_cp_ext_iio_chan));
- if (IS_ERR(iio_list)) {
- rc = PTR_ERR(iio_list);
- if (rc != -EPROBE_DEFER) {
- dev_err(chip->dev, "Failed to get channels, %d\n",
- rc);
- chip->iio_chan_list_cp = ERR_PTR(-EINVAL);
- }
- return false;
- }
- chip->iio_chan_list_cp = iio_list;
- }
- if (!chip->cp_master_psy) {
- chip->cp_master_psy =
- power_supply_get_by_name("charge_pump_master");
- if (!chip->cp_master_psy)
- return false;
- }
- return true;
- }
- static int battery_read_iio_prop(struct pl_data *chip,
- enum iio_type type, int iio_chan, int *val)
- {
- struct iio_channel *iio_chan_list;
- int rc;
- switch (type) {
- case CP:
- if (IS_ERR_OR_NULL(chip->iio_chan_list_cp))
- return -ENODEV;
- iio_chan_list = chip->iio_chan_list_cp[iio_chan];
- break;
- case SMB_PARALLEL:
- if (IS_ERR_OR_NULL(chip->iio_chan_list_smb_parallel))
- return -ENODEV;
- iio_chan_list = chip->iio_chan_list_smb_parallel[iio_chan];
- break;
- default:
- pr_err_ratelimited("iio_type %d is not supported\n", type);
- return -EINVAL;
- }
- rc = iio_read_channel_processed(iio_chan_list, val);
- return (rc < 0) ? rc : 0;
- }
- static int battery_write_iio_prop(struct pl_data *chip,
- enum iio_type type, int iio_chan, int val)
- {
- struct iio_channel *iio_chan_list;
- switch (type) {
- case CP:
- if (IS_ERR_OR_NULL(chip->iio_chan_list_cp))
- return -ENODEV;
- iio_chan_list = chip->iio_chan_list_cp[iio_chan];
- break;
- case SMB_PARALLEL:
- if (IS_ERR_OR_NULL(chip->iio_chan_list_smb_parallel))
- return -ENODEV;
- iio_chan_list = chip->iio_chan_list_smb_parallel[iio_chan];
- break;
- default:
- pr_err_ratelimited("iio_type %d is not supported\n", type);
- return -EINVAL;
- }
- return iio_write_channel_raw(iio_chan_list, val);
- }
- static int cp_get_parallel_mode(struct pl_data *chip, int mode)
- {
- int rc = -EINVAL, val = -EINVAL;
- if (!is_cp_available(chip))
- return -EINVAL;
- switch (mode) {
- case PARALLEL_INPUT_MODE:
- rc = battery_read_iio_prop(chip, CP,
- BAT_CP_PARALLEL_MODE, &val);
- break;
- case PARALLEL_OUTPUT_MODE:
- rc = battery_read_iio_prop(chip, CP,
- BAT_CP_PARALLEL_OUTPUT_MODE,
- &val);
- break;
- default:
- pr_err("Invalid mode request %d\n", mode);
- break;
- }
- if (rc < 0)
- pr_err("Failed to read CP topology for mode=%d rc=%d\n",
- mode, rc);
- return val;
- }
- static int get_adapter_icl_based_ilim(struct pl_data *chip)
- {
- int main_icl = -EINVAL, adapter_icl = -EINVAL, final_icl = -EINVAL;
- int rc = -EINVAL, pval = 0;
- rc = chip->chg_param->iio_read(chip->dev,
- PSY_IIO_PD_ACTIVE, &pval);
- if (rc < 0)
- pr_err("Failed to read PD_ACTIVE status rc=%d\n",
- rc);
- /* Check for QC 3, 3.5 and PPS adapters, return if its none of them */
- if (chip->charger_type != QTI_POWER_SUPPLY_TYPE_USB_HVDCP_3 &&
- chip->charger_type != QTI_POWER_SUPPLY_TYPE_USB_HVDCP_3P5 &&
- pval != QTI_POWER_SUPPLY_PD_PPS_ACTIVE)
- return final_icl;
- /*
- * For HVDCP3/HVDCP_3P5 adapters, limit max. ILIM as:
- * HVDCP3_ICL: Maximum ICL of HVDCP3 adapter(from DT
- * configuration).
- *
- * For PPS adapters, limit max. ILIM to
- * MIN(qc4_max_icl, PD_CURRENT_MAX)
- */
- if (pval == QTI_POWER_SUPPLY_PD_PPS_ACTIVE) {
- adapter_icl = min_t(int, chip->chg_param->qc4_max_icl_ua,
- get_client_vote_locked(chip->usb_icl_votable,
- PD_VOTER));
- if (adapter_icl <= 0)
- adapter_icl = chip->chg_param->qc4_max_icl_ua;
- } else {
- adapter_icl = chip->chg_param->hvdcp3_max_icl_ua;
- }
- /*
- * For Parallel input configurations:
- * VBUS: final_icl = adapter_icl - main_ICL
- * VMID: final_icl = adapter_icl
- */
- final_icl = adapter_icl;
- if (cp_get_parallel_mode(chip, PARALLEL_INPUT_MODE)
- == QTI_POWER_SUPPLY_PL_USBIN_USBIN) {
- main_icl = get_effective_result_locked(chip->usb_icl_votable);
- if ((main_icl >= 0) && (main_icl < adapter_icl))
- final_icl = adapter_icl - main_icl;
- }
- pr_debug("charger_type=%d final_icl=%d adapter_icl=%d main_icl=%d\n",
- chip->charger_type, final_icl, adapter_icl, main_icl);
- return final_icl;
- }
- /*
- * Adapter CC Mode: ILIM over-ridden explicitly, below takes no effect.
- *
- * Adapter CV mode: Configuration of ILIM for different topology is as below:
- * MID-VPH:
- * SMB1390 ILIM: independent of FCC and based on the AICL result or
- * PD advertised current, handled directly in SMB1390
- * driver.
- * MID-VBAT:
- * SMB1390 ILIM: based on minimum of FCC portion of SMB1390 or ICL.
- * USBIN-VBAT:
- * SMB1390 ILIM: based on FCC portion of SMB1390 and independent of ICL.
- */
- static void cp_configure_ilim(struct pl_data *chip, const char *voter, int ilim)
- {
- int rc = 0, fcc, target_icl, val;
- if (!is_usb_available(chip))
- return;
- if (!is_cp_available(chip))
- return;
- if (cp_get_parallel_mode(chip, PARALLEL_OUTPUT_MODE)
- == QTI_POWER_SUPPLY_PL_OUTPUT_VPH)
- return;
- target_icl = get_adapter_icl_based_ilim(chip);
- ilim = (target_icl > 0) ? min(ilim, target_icl) : ilim;
- rc = battery_read_iio_prop(chip, CP, BAT_CP_MIN_ICL, &val);
- if (rc < 0) {
- pr_err("Failed to read min_icl rc=%d\n", rc);
- return;
- }
- if (!chip->cp_ilim_votable)
- chip->cp_ilim_votable = find_votable("CP_ILIM");
- if (chip->cp_ilim_votable) {
- fcc = get_effective_result_locked(chip->fcc_votable);
- /*
- * If FCC >= (2 * MIN_ICL) then it is safe to enable CP
- * with MIN_ICL.
- * Configure ILIM as follows:
- * if request_ilim < MIN_ICL cofigure ILIM to MIN_ICL.
- * otherwise configure ILIM to requested_ilim.
- */
- if ((fcc >= (val * 2)) && (ilim < val))
- vote(chip->cp_ilim_votable, voter, true, val);
- else
- vote(chip->cp_ilim_votable, voter, true, ilim);
- /*
- * Rerun FCC votable to ensure offset for ILIM compensation is
- * recalculated based on new ILIM.
- */
- if (!chip->fcc_main_votable)
- chip->fcc_main_votable = find_votable("FCC_MAIN");
- if ((chip->charger_type == QTI_POWER_SUPPLY_TYPE_USB_HVDCP_3)
- && chip->fcc_main_votable)
- rerun_election(chip->fcc_main_votable);
- pl_dbg(chip, PR_PARALLEL,
- "ILIM: vote: %d voter:%s min_ilim=%d fcc = %d\n",
- ilim, voter, val, fcc);
- }
- }
- /*******
- * ICL *
- ********/
- static int get_settled_split(struct pl_data *chip, int *main_icl_ua,
- int *slave_icl_ua, int *total_settled_icl_ua)
- {
- int slave_icl_pct, total_current_ua;
- int slave_ua = 0, main_settled_ua = 0;
- int rc, total_settled_ua = 0;
- int val;
- if (!IS_USBIN(chip->pl_mode))
- return -EINVAL;
- if (!get_effective_result_locked(chip->pl_disable_votable)) {
- /* read the aicl settled value */
- rc = chip->chg_param->iio_read(chip->dev,
- PSY_IIO_MAIN_INPUT_CURRENT_SETTLED, &val);
- if (rc < 0) {
- pr_err("Couldn't get aicl settled value rc=%d\n", rc);
- return rc;
- }
- main_settled_ua = val;
- slave_icl_pct = max(0, chip->slave_pct);
- slave_ua = ((main_settled_ua + chip->pl_settled_ua)
- * slave_icl_pct) / 100;
- total_settled_ua = main_settled_ua + chip->pl_settled_ua;
- }
- total_current_ua = get_effective_result_locked(chip->usb_icl_votable);
- if (total_current_ua < 0) {
- if (!chip->usb_psy)
- chip->usb_psy = power_supply_get_by_name("usb");
- if (!chip->usb_psy) {
- pr_err("Couldn't get usbpsy while splitting settled\n");
- return -ENOENT;
- }
- /* no client is voting, so get the total current from charger */
- rc = chip->chg_param->iio_read(chip->dev,
- PSY_IIO_HW_CURRENT_MAX, &val);
- if (rc < 0) {
- pr_err("Couldn't get max current rc=%d\n", rc);
- return rc;
- }
- total_current_ua = val;
- }
- *main_icl_ua = total_current_ua - slave_ua;
- *slave_icl_ua = slave_ua;
- *total_settled_icl_ua = total_settled_ua;
- pl_dbg(chip, PR_PARALLEL,
- "Split total_current_ua=%d total_settled_ua=%d main_settled_ua=%d slave_ua=%d\n",
- total_current_ua, total_settled_ua, main_settled_ua, slave_ua);
- return 0;
- }
- static int validate_parallel_icl(struct pl_data *chip, bool *disable)
- {
- int rc = 0;
- int main_ua = 0, slave_ua = 0, total_settled_ua = 0;
- if (!IS_USBIN(chip->pl_mode)
- || get_effective_result_locked(chip->pl_disable_votable))
- return 0;
- rc = get_settled_split(chip, &main_ua, &slave_ua, &total_settled_ua);
- if (rc < 0) {
- pr_err("Couldn't get split current rc=%d\n", rc);
- return rc;
- }
- if (slave_ua < chip->pl_min_icl_ua)
- *disable = true;
- else
- *disable = false;
- return 0;
- }
- static void split_settled(struct pl_data *chip)
- {
- int rc, main_ua, slave_ua, total_settled_ua;
- rc = get_settled_split(chip, &main_ua, &slave_ua, &total_settled_ua);
- if (rc < 0) {
- pr_err("Couldn't get split current rc=%d\n", rc);
- return;
- }
- /*
- * If there is an increase in slave share
- * (Also handles parallel enable case)
- * Set Main ICL then slave ICL
- * else
- * (Also handles parallel disable case)
- * Set slave ICL then main ICL.
- */
- if (slave_ua > chip->pl_settled_ua) {
- /* Set ICL on main charger */
- rc = chip->chg_param->iio_write(chip->dev, PSY_IIO_CURRENT_MAX,
- main_ua);
- if (rc < 0) {
- pr_err("Couldn't change slave suspend state rc=%d\n",
- rc);
- return;
- }
- /* set parallel's ICL could be 0mA when pl is disabled */
- rc = battery_write_iio_prop(chip, SMB_PARALLEL,
- BAT_SMB_PARALLEL_CURRENT_MAX, slave_ua);
- if (rc < 0) {
- pr_err("Couldn't set parallel icl, rc=%d\n", rc);
- return;
- }
- } else {
- /* set parallel's ICL could be 0mA when pl is disabled */
- rc = battery_write_iio_prop(chip, SMB_PARALLEL,
- BAT_SMB_PARALLEL_CURRENT_MAX, slave_ua);
- if (rc < 0) {
- pr_err("Couldn't set parallel icl, rc=%d\n", rc);
- return;
- }
- /* Set ICL on main charger */
- rc = chip->chg_param->iio_write(chip->dev, PSY_IIO_CURRENT_MAX,
- main_ua);
- if (rc < 0) {
- pr_err("Couldn't change slave suspend state rc=%d\n",
- rc);
- return;
- }
- }
- chip->total_settled_ua = total_settled_ua;
- chip->pl_settled_ua = slave_ua;
- }
- static ssize_t version_show(struct class *c, struct class_attribute *attr,
- char *buf)
- {
- return scnprintf(buf, PAGE_SIZE, "%d.%d\n",
- DRV_MAJOR_VERSION, DRV_MINOR_VERSION);
- }
- static CLASS_ATTR_RO(version);
- /*************
- * SLAVE PCT *
- **************/
- static ssize_t slave_pct_show(struct class *c, struct class_attribute *attr,
- char *ubuf)
- {
- struct pl_data *chip = container_of(c, struct pl_data,
- qcom_batt_class);
- return scnprintf(ubuf, PAGE_SIZE, "%d\n", chip->slave_pct);
- }
- static ssize_t slave_pct_store(struct class *c, struct class_attribute *attr,
- const char *ubuf, size_t count)
- {
- struct pl_data *chip = container_of(c, struct pl_data, qcom_batt_class);
- int rc;
- unsigned long val;
- bool disable = false;
- if (kstrtoul(ubuf, 10, &val))
- return -EINVAL;
- chip->slave_pct = val;
- rc = validate_parallel_icl(chip, &disable);
- if (rc < 0)
- return rc;
- vote(chip->pl_disable_votable, ICL_LIMIT_VOTER, disable, 0);
- rerun_election(chip->fcc_votable);
- rerun_election(chip->fv_votable);
- if (IS_USBIN(chip->pl_mode))
- split_settled(chip);
- return count;
- }
- static struct class_attribute class_attr_slave_pct =
- __ATTR(parallel_pct, 0644, slave_pct_show, slave_pct_store);
- /************************
- * RESTRICTED CHARGIGNG *
- ************************/
- static ssize_t restrict_chg_show(struct class *c, struct class_attribute *attr,
- char *ubuf)
- {
- struct pl_data *chip = container_of(c, struct pl_data,
- qcom_batt_class);
- return scnprintf(ubuf, PAGE_SIZE, "%d\n",
- chip->restricted_charging_enabled);
- }
- static ssize_t restrict_chg_store(struct class *c, struct class_attribute *attr,
- const char *ubuf, size_t count)
- {
- struct pl_data *chip = container_of(c, struct pl_data,
- qcom_batt_class);
- unsigned long val;
- if (kstrtoul(ubuf, 10, &val))
- return -EINVAL;
- if (chip->restricted_charging_enabled == !!val)
- goto no_change;
- chip->restricted_charging_enabled = !!val;
- /* disable parallel charger in case of restricted charging */
- vote(chip->pl_disable_votable, RESTRICT_CHG_VOTER,
- chip->restricted_charging_enabled, 0);
- vote(chip->fcc_votable, RESTRICT_CHG_VOTER,
- chip->restricted_charging_enabled,
- chip->restricted_current);
- no_change:
- return count;
- }
- static CLASS_ATTR_RW(restrict_chg);
- static ssize_t restrict_cur_show(struct class *c, struct class_attribute *attr,
- char *ubuf)
- {
- struct pl_data *chip = container_of(c, struct pl_data,
- qcom_batt_class);
- return scnprintf(ubuf, PAGE_SIZE, "%d\n", chip->restricted_current);
- }
- static ssize_t restrict_cur_store(struct class *c, struct class_attribute *attr,
- const char *ubuf, size_t count)
- {
- struct pl_data *chip = container_of(c, struct pl_data,
- qcom_batt_class);
- unsigned long val;
- if (kstrtoul(ubuf, 10, &val))
- return -EINVAL;
- chip->restricted_current = val;
- vote(chip->fcc_votable, RESTRICT_CHG_VOTER,
- chip->restricted_charging_enabled,
- chip->restricted_current);
- return count;
- }
- static CLASS_ATTR_RW(restrict_cur);
- /****************************
- * FCC STEPPING IN PROGRESS *
- ****************************/
- static ssize_t fcc_stepping_in_progress_show(struct class *c,
- struct class_attribute *attr, char *ubuf)
- {
- struct pl_data *chip = container_of(c, struct pl_data,
- qcom_batt_class);
- return scnprintf(ubuf, PAGE_SIZE, "%d\n", chip->step_fcc);
- }
- static CLASS_ATTR_RO(fcc_stepping_in_progress);
- static struct attribute *batt_class_attrs[] = {
- [VER] = &class_attr_version.attr,
- [SLAVE_PCT] = &class_attr_slave_pct.attr,
- [RESTRICT_CHG_ENABLE] = &class_attr_restrict_chg.attr,
- [RESTRICT_CHG_CURRENT] = &class_attr_restrict_cur.attr,
- [FCC_STEPPING_IN_PROGRESS]
- = &class_attr_fcc_stepping_in_progress.attr,
- NULL,
- };
- ATTRIBUTE_GROUPS(batt_class);
- /*********
- * FCC *
- **********/
- #define EFFICIENCY_PCT 80
- #define STEP_UP 1
- #define STEP_DOWN -1
- static void get_fcc_split(struct pl_data *chip, int total_ua,
- int *master_ua, int *slave_ua)
- {
- int rc, effective_total_ua, slave_limited_ua, hw_cc_delta_ua = 0,
- icl_ua, adapter_uv, bcl_ua, val;
- rc = chip->chg_param->iio_read(chip->dev, PSY_IIO_FCC_DELTA, &val);
- if (rc < 0) {
- pr_err("Couldn't get fcc_delta rc=%d\n", rc);
- hw_cc_delta_ua = 0;
- } else {
- hw_cc_delta_ua = val;
- }
- bcl_ua = INT_MAX;
- if (chip->pl_mode == QTI_POWER_SUPPLY_PL_USBMID_USBMID) {
- rc = chip->chg_param->iio_read(chip->dev,
- PSY_IIO_MAIN_INPUT_CURRENT_SETTLED, &val);
- if (rc < 0) {
- pr_err("Couldn't get aicl settled value rc=%d\n", rc);
- return;
- }
- icl_ua = val;
- rc = chip->chg_param->iio_read(chip->dev,
- PSY_IIO_MAIN_INPUT_VOLTAGE_SETTLED, &val);
- if (rc < 0) {
- pr_err("Couldn't get adaptive voltage rc=%d\n", rc);
- return;
- }
- adapter_uv = val;
- bcl_ua = div64_s64((s64)icl_ua * adapter_uv * EFFICIENCY_PCT,
- (s64)get_effective_result(chip->fv_votable) * 100);
- }
- effective_total_ua = max(0, total_ua + hw_cc_delta_ua);
- slave_limited_ua = min(effective_total_ua, bcl_ua);
- *slave_ua = (slave_limited_ua * chip->slave_pct) / 100;
- *slave_ua = min(*slave_ua, chip->pl_fcc_max);
- /*
- * In stacked BATFET configuration charger's current goes
- * through main charger's BATFET, keep the main charger's FCC
- * to the votable result.
- */
- if (chip->pl_batfet_mode == QTI_POWER_SUPPLY_PL_STACKED_BATFET) {
- *master_ua = max(0, total_ua);
- if (chip->main_fcc_max)
- *master_ua = min(*master_ua,
- chip->main_fcc_max + *slave_ua);
- } else {
- *master_ua = max(0, total_ua - *slave_ua);
- if (chip->main_fcc_max)
- *master_ua = min(*master_ua, chip->main_fcc_max);
- }
- }
- static void get_main_fcc_config(struct pl_data *chip, int *total_fcc)
- {
- int rc = 0, val;
- if (!is_cp_available(chip))
- goto out;
- rc = battery_read_iio_prop(chip, CP, BAT_CP_SWITCHER_EN, &val);
- if (rc < 0) {
- pr_err("Couldn't get switcher enable status, rc=%d\n", rc);
- goto out;
- }
- if (!val) {
- /*
- * To honor main charger upper FCC limit, on CP switcher
- * disable, skip fcc slewing as it will cause delay in limiting
- * the charge current flowing through main charger.
- */
- if (!chip->cp_disabled) {
- chip->fcc_stepper_enable = false;
- pl_dbg(chip, PR_PARALLEL,
- "Disabling FCC slewing on CP Switcher disable\n");
- }
- chip->cp_disabled = true;
- } else {
- chip->cp_disabled = false;
- pl_dbg(chip, PR_PARALLEL,
- "CP Switcher is enabled, don't limit main fcc\n");
- return;
- }
- out:
- *total_fcc = min(*total_fcc, chip->main_fcc_max);
- }
- static void get_fcc_stepper_params(struct pl_data *chip, int main_fcc_ua,
- int parallel_fcc_ua)
- {
- int main_set_fcc_ua, total_fcc_ua, target_icl;
- bool override;
- if (!chip->chg_param->fcc_step_size_ua) {
- pr_err("Invalid fcc stepper step size, value 0\n");
- return;
- }
- total_fcc_ua = main_fcc_ua + parallel_fcc_ua;
- override = is_override_vote_enabled_locked(chip->fcc_main_votable);
- if (override) {
- /*
- * FCC stepper params need re-calculation in override mode
- * only if there is change in Main or total FCC
- */
- main_set_fcc_ua = get_effective_result_locked(
- chip->fcc_main_votable);
- if ((main_set_fcc_ua != chip->override_main_fcc_ua)
- || (total_fcc_ua != chip->total_fcc_ua)) {
- chip->override_main_fcc_ua = main_set_fcc_ua;
- chip->total_fcc_ua = total_fcc_ua;
- } else {
- goto skip_fcc_step_update;
- }
- }
- /*
- * If override vote is removed then start main FCC from the
- * last overridden value.
- * Clear slave_fcc if requested parallel current is 0 i.e.
- * parallel is disabled.
- */
- if (chip->override_main_fcc_ua && !override) {
- chip->main_fcc_ua = chip->override_main_fcc_ua;
- chip->override_main_fcc_ua = 0;
- if (!parallel_fcc_ua)
- chip->slave_fcc_ua = 0;
- } else {
- chip->main_fcc_ua = get_effective_result_locked(
- chip->fcc_main_votable);
- }
- /* Skip stepping if override vote is applied on main */
- if (override) {
- chip->main_step_fcc_count = 0;
- chip->main_step_fcc_residual = 0;
- } else {
- chip->main_step_fcc_dir =
- (main_fcc_ua > chip->main_fcc_ua) ?
- STEP_UP : STEP_DOWN;
- chip->main_step_fcc_count =
- abs(main_fcc_ua - chip->main_fcc_ua) /
- chip->chg_param->fcc_step_size_ua;
- chip->main_step_fcc_residual =
- abs(main_fcc_ua - chip->main_fcc_ua) %
- chip->chg_param->fcc_step_size_ua;
- }
- /* Calculate CP_ILIM based on adapter limit and max. FCC */
- if (!parallel_fcc_ua && is_cp_available(chip) && override) {
- if (!chip->cp_ilim_votable)
- chip->cp_ilim_votable = find_votable("CP_ILIM");
- target_icl = get_adapter_icl_based_ilim(chip) * 2;
- total_fcc_ua -= chip->main_fcc_ua;
- /*
- * CP_ILIM = parallel_fcc_ua / 2.
- * Calculate parallel_fcc_ua as follows:
- * parallel_fcc_ua is based minimum of total FCC
- * or adapter's maximum allowed ICL limitation(if adapter
- * has max. ICL limitations).
- */
- parallel_fcc_ua = (target_icl > 0) ?
- min(target_icl, total_fcc_ua) : total_fcc_ua;
- }
- /* Skip stepping if override vote is applied on CP */
- if (chip->cp_ilim_votable
- && is_override_vote_enabled(chip->cp_ilim_votable)) {
- chip->parallel_step_fcc_count = 0;
- chip->parallel_step_fcc_residual = 0;
- } else {
- chip->parallel_step_fcc_dir =
- (parallel_fcc_ua > chip->slave_fcc_ua) ?
- STEP_UP : STEP_DOWN;
- chip->parallel_step_fcc_count =
- abs(parallel_fcc_ua - chip->slave_fcc_ua) /
- chip->chg_param->fcc_step_size_ua;
- chip->parallel_step_fcc_residual =
- abs(parallel_fcc_ua - chip->slave_fcc_ua) %
- chip->chg_param->fcc_step_size_ua;
- }
- skip_fcc_step_update:
- if (chip->parallel_step_fcc_count || chip->parallel_step_fcc_residual
- || chip->main_step_fcc_count || chip->main_step_fcc_residual)
- chip->step_fcc = 1;
- pl_dbg(chip, PR_PARALLEL,
- "Main FCC Stepper parameters: target_main_fcc: %d, current_main_fcc: %d main_step_direction: %d, main_step_count: %d, main_residual_fcc: %d override_main_fcc_ua: %d override: %d\n",
- main_fcc_ua, chip->main_fcc_ua, chip->main_step_fcc_dir,
- chip->main_step_fcc_count, chip->main_step_fcc_residual,
- chip->override_main_fcc_ua, override);
- pl_dbg(chip, PR_PARALLEL,
- "Parallel FCC Stepper parameters: target_pl_fcc: %d current_pl_fcc: %d parallel_step_direction: %d, parallel_step_count: %d, parallel_residual_fcc: %d\n",
- parallel_fcc_ua, chip->slave_fcc_ua,
- chip->parallel_step_fcc_dir, chip->parallel_step_fcc_count,
- chip->parallel_step_fcc_residual);
- pl_dbg(chip, PR_PARALLEL, "FCC Stepper parameters: step_fcc=%d\n",
- chip->step_fcc);
- }
- #define MINIMUM_PARALLEL_FCC_UA 500000
- #define PL_TAPER_WORK_DELAY_MS 500
- #define TAPER_RESIDUAL_PCT 90
- #define TAPER_REDUCTION_UA 200000
- static void pl_taper_work(struct work_struct *work)
- {
- struct pl_data *chip = container_of(work, struct pl_data,
- pl_taper_work);
- union power_supply_propval pval = {0, };
- int rc;
- int fcc_ua, total_fcc_ua, master_fcc_ua, slave_fcc_ua = 0;
- chip->taper_entry_fv = get_effective_result(chip->fv_votable);
- chip->taper_work_running = true;
- fcc_ua = get_client_vote(chip->fcc_votable, BATT_PROFILE_VOTER);
- vote(chip->fcc_votable, TAPER_STEPPER_VOTER, true, fcc_ua);
- while (true) {
- if (get_effective_result(chip->pl_disable_votable)) {
- /*
- * if parallel's FCC share is low, simply disable
- * parallel with TAPER_END_VOTER
- */
- total_fcc_ua = get_effective_result_locked(
- chip->fcc_votable);
- get_fcc_split(chip, total_fcc_ua, &master_fcc_ua,
- &slave_fcc_ua);
- if (slave_fcc_ua <= MINIMUM_PARALLEL_FCC_UA) {
- pl_dbg(chip, PR_PARALLEL, "terminating: parallel's share is low\n");
- vote(chip->pl_disable_votable, TAPER_END_VOTER,
- true, 0);
- } else {
- pl_dbg(chip, PR_PARALLEL, "terminating: parallel disabled\n");
- }
- goto done;
- }
- /*
- * Due to reduction of float voltage in JEITA condition taper
- * charging can be initiated at a lower FV. On removal of JEITA
- * condition, FV readjusts itself. However, once taper charging
- * is initiated, it doesn't exits until parallel chaging is
- * disabled due to which FCC doesn't scale back to its original
- * value, leading to slow charging thereafter.
- * Check if FV increases in comparison to FV at which taper
- * charging was initiated, and if yes, exit taper charging.
- */
- if (get_effective_result(chip->fv_votable) >
- chip->taper_entry_fv) {
- pl_dbg(chip, PR_PARALLEL, "Float voltage increased. Exiting taper\n");
- goto done;
- } else {
- chip->taper_entry_fv =
- get_effective_result(chip->fv_votable);
- }
- rc = power_supply_get_property(chip->batt_psy,
- POWER_SUPPLY_PROP_CHARGE_TYPE, &pval);
- if (rc < 0) {
- pr_err("Couldn't get batt charge type rc=%d\n", rc);
- goto done;
- }
- chip->charge_type = pval.intval;
- if (pval.intval == POWER_SUPPLY_CHARGE_TYPE_ADAPTIVE) {
- fcc_ua = get_client_vote(chip->fcc_votable,
- TAPER_STEPPER_VOTER);
- if (fcc_ua < 0) {
- pr_err("Couldn't get fcc, exiting taper work\n");
- goto done;
- }
- fcc_ua -= TAPER_REDUCTION_UA;
- if (fcc_ua < 0) {
- pr_err("Can't reduce FCC any more\n");
- goto done;
- }
- pl_dbg(chip, PR_PARALLEL, "master is taper charging; reducing FCC to %dua\n",
- fcc_ua);
- vote(chip->fcc_votable, TAPER_STEPPER_VOTER,
- true, fcc_ua);
- } else {
- pl_dbg(chip, PR_PARALLEL, "master is fast charging; waiting for next taper\n");
- }
- /* wait for the charger state to deglitch after FCC change */
- msleep(PL_TAPER_WORK_DELAY_MS);
- }
- done:
- chip->taper_work_running = false;
- vote(chip->fcc_votable, TAPER_STEPPER_VOTER, false, 0);
- vote(chip->pl_awake_votable, TAPER_END_VOTER, false, 0);
- }
- static int pl_fcc_main_vote_callback(struct votable *votable, void *data,
- int fcc_main_ua, const char *client)
- {
- struct pl_data *chip = data;
- int rc;
- rc = chip->chg_param->iio_write(chip->dev,
- PSY_IIO_CONSTANT_CHARGE_CURRENT_MAX, fcc_main_ua);
- if (rc < 0)
- pr_err("Couldn't set constant_charge_current_max, rc=%d\n", rc);
- return rc;
- }
- static int pl_fcc_vote_callback(struct votable *votable, void *data,
- int total_fcc_ua, const char *client)
- {
- struct pl_data *chip = data;
- int master_fcc_ua = total_fcc_ua, slave_fcc_ua = 0;
- int cp_fcc_ua = 0, rc, val = 0;
- if (total_fcc_ua < 0)
- return 0;
- if (!chip->cp_disable_votable)
- chip->cp_disable_votable = find_votable("CP_DISABLE");
- if (IS_ERR_OR_NULL(chip->iio_chan_list_cp))
- is_cp_available(chip);
- /*
- * Search for a slave charger channel specifically,
- * which would be available only if slave got probed.
- */
- if (!chip->iio_chan_list_cp_slave) {
- chip->iio_chan_list_cp_slave = devm_iio_channel_get(chip->dev,
- "current_capability");
- if (PTR_ERR(chip->iio_chan_list_cp_slave) == -EPROBE_DEFER)
- chip->iio_chan_list_cp_slave = NULL;
- }
- if (!chip->cp_slave_disable_votable)
- chip->cp_slave_disable_votable =
- find_votable("CP_SLAVE_DISABLE");
- /*
- * CP charger current = Total FCC - Main charger's FCC.
- * Main charger FCC is userspace's override vote on main.
- */
- cp_fcc_ua = total_fcc_ua - chip->chg_param->forced_main_fcc;
- pl_dbg(chip, PR_PARALLEL,
- "cp_fcc_ua=%d total_fcc_ua=%d forced_main_fcc=%d\n",
- cp_fcc_ua, total_fcc_ua, chip->chg_param->forced_main_fcc);
- if (cp_fcc_ua > 0) {
- if (!IS_ERR_OR_NULL(chip->iio_chan_list_cp)) {
- rc = battery_read_iio_prop(chip, CP, BAT_CP_MIN_ICL,
- &val);
- if (rc < 0)
- pr_err("Couldn't get MIN ICL threshold rc=%d\n",
- rc);
- }
- if (!IS_ERR_OR_NULL(chip->iio_chan_list_cp_slave) &&
- chip->cp_slave_disable_votable) {
- /*
- * Disable Slave CP if FCC share
- * falls below 3 * min ICL threshold.
- */
- vote(chip->cp_slave_disable_votable, FCC_VOTER,
- (cp_fcc_ua < (3 * val)), 0);
- }
- if (chip->cp_disable_votable) {
- /*
- * Disable Master CP if FCC share
- * falls below 2 * min ICL threshold.
- */
- vote(chip->cp_disable_votable, FCC_VOTER,
- (cp_fcc_ua < (2 * val)), 0);
- }
- }
- if (chip->pl_mode != QTI_POWER_SUPPLY_PL_NONE) {
- get_fcc_split(chip, total_fcc_ua, &master_fcc_ua,
- &slave_fcc_ua);
- if (slave_fcc_ua > MINIMUM_PARALLEL_FCC_UA) {
- vote(chip->pl_disable_votable, PL_FCC_LOW_VOTER,
- false, 0);
- } else {
- vote(chip->pl_disable_votable, PL_FCC_LOW_VOTER,
- true, 0);
- }
- }
- rerun_election(chip->pl_disable_votable);
- /* When FCC changes, trigger psy changed event for CC mode */
- if (!IS_ERR_OR_NULL(chip->iio_chan_list_cp))
- power_supply_changed(chip->cp_master_psy);
- return 0;
- }
- static void fcc_stepper_work(struct work_struct *work)
- {
- struct pl_data *chip = container_of(work, struct pl_data,
- fcc_stepper_work.work);
- union power_supply_propval pval = {0, };
- int reschedule_ms = 0, rc = 0, charger_present = 0;
- int main_fcc = chip->main_fcc_ua;
- int parallel_fcc = chip->slave_fcc_ua;
- /* Check whether USB is present or not */
- rc = power_supply_get_property(chip->usb_psy,
- POWER_SUPPLY_PROP_PRESENT, &pval);
- if (rc < 0)
- pr_err("Couldn't get USB Present status, rc=%d\n", rc);
- charger_present = pval.intval;
- /*Check whether DC charger is present or not */
- if (!chip->dc_psy)
- chip->dc_psy = power_supply_get_by_name("dc");
- if (chip->dc_psy) {
- rc = power_supply_get_property(chip->dc_psy,
- POWER_SUPPLY_PROP_PRESENT, &pval);
- if (rc < 0)
- pr_err("Couldn't get DC Present status, rc=%d\n", rc);
- charger_present |= pval.intval;
- }
- /*
- * If USB is not present, then set parallel FCC to min value and
- * main FCC to the effective value of FCC votable and exit.
- */
- if (!charger_present) {
- /* Disable parallel */
- parallel_fcc = 0;
- if (!IS_ERR_OR_NULL(chip->iio_chan_list_smb_parallel)) {
- rc = battery_write_iio_prop(chip, SMB_PARALLEL,
- BAT_SMB_PARALLEL_INPUT_SUSPEND, 1);
- if (rc < 0) {
- pr_err("Couldn't change slave suspend state rc=%d\n",
- rc);
- goto out;
- }
- chip->pl_disable = true;
- power_supply_changed(chip->pl_psy);
- }
- main_fcc = get_effective_result_locked(chip->fcc_votable);
- vote(chip->fcc_main_votable, FCC_STEPPER_VOTER, true, main_fcc);
- goto stepper_exit;
- }
- if (chip->main_step_fcc_count) {
- main_fcc += (chip->chg_param->fcc_step_size_ua
- * chip->main_step_fcc_dir);
- chip->main_step_fcc_count--;
- reschedule_ms = chip->chg_param->fcc_step_delay_ms;
- } else if (chip->main_step_fcc_residual) {
- main_fcc += chip->main_step_fcc_residual
- * chip->main_step_fcc_dir;
- chip->main_step_fcc_residual = 0;
- }
- if (chip->parallel_step_fcc_count) {
- parallel_fcc += (chip->chg_param->fcc_step_size_ua
- * chip->parallel_step_fcc_dir);
- chip->parallel_step_fcc_count--;
- reschedule_ms = chip->chg_param->fcc_step_delay_ms;
- } else if (chip->parallel_step_fcc_residual) {
- parallel_fcc += chip->parallel_step_fcc_residual;
- chip->parallel_step_fcc_residual = 0;
- }
- if (parallel_fcc < chip->slave_fcc_ua) {
- /* Set parallel FCC */
- if (!IS_ERR_OR_NULL(chip->iio_chan_list_smb_parallel) &&
- !chip->pl_disable) {
- if (parallel_fcc < MINIMUM_PARALLEL_FCC_UA) {
- rc = battery_write_iio_prop(chip, SMB_PARALLEL,
- BAT_SMB_PARALLEL_INPUT_SUSPEND, 1);
- if (rc < 0) {
- pr_err("Couldn't change slave suspend state rc=%d\n",
- rc);
- goto out;
- }
- if (IS_USBIN(chip->pl_mode))
- split_settled(chip);
- parallel_fcc = 0;
- chip->parallel_step_fcc_count = 0;
- chip->parallel_step_fcc_residual = 0;
- chip->total_settled_ua = 0;
- chip->pl_settled_ua = 0;
- chip->pl_disable = true;
- power_supply_changed(chip->pl_psy);
- } else {
- /* Set Parallel FCC */
- rc = battery_write_iio_prop(chip, SMB_PARALLEL,
- BAT_SMB_PARALLEL_CONSTANT_CHARGE_CURRENT_MAX,
- parallel_fcc);
- if (rc < 0) {
- pr_err("Couldn't set parallel charger fcc, rc=%d\n",
- rc);
- goto out;
- }
- }
- }
- /* Set main FCC */
- vote(chip->fcc_main_votable, FCC_STEPPER_VOTER, true, main_fcc);
- } else {
- /* Set main FCC */
- vote(chip->fcc_main_votable, FCC_STEPPER_VOTER, true, main_fcc);
- /* Set parallel FCC */
- if (!IS_ERR_OR_NULL(chip->iio_chan_list_smb_parallel)) {
- rc = battery_write_iio_prop(chip, SMB_PARALLEL,
- BAT_SMB_PARALLEL_CONSTANT_CHARGE_CURRENT_MAX,
- parallel_fcc);
- if (rc < 0) {
- pr_err("Couldn't set parallel charger fcc, rc=%d\n",
- rc);
- goto out;
- }
- /*
- * Enable parallel charger only if it was disabled
- * earlier and configured slave fcc is greater than or
- * equal to minimum parallel FCC value.
- */
- if (chip->pl_disable && parallel_fcc
- >= MINIMUM_PARALLEL_FCC_UA) {
- rc = battery_write_iio_prop(chip, SMB_PARALLEL,
- BAT_SMB_PARALLEL_INPUT_SUSPEND, 0);
- if (rc < 0) {
- pr_err("Couldn't change slave suspend state rc=%d\n",
- rc);
- goto out;
- }
- if (IS_USBIN(chip->pl_mode))
- split_settled(chip);
- chip->pl_disable = false;
- power_supply_changed(chip->pl_psy);
- }
- }
- }
- stepper_exit:
- chip->main_fcc_ua = main_fcc;
- chip->slave_fcc_ua = parallel_fcc;
- cp_configure_ilim(chip, FCC_VOTER, chip->slave_fcc_ua / 2);
- if (reschedule_ms) {
- schedule_delayed_work(&chip->fcc_stepper_work,
- msecs_to_jiffies(reschedule_ms));
- pr_debug("Rescheduling FCC_STEPPER work\n");
- return;
- }
- out:
- chip->step_fcc = 0;
- vote(chip->pl_awake_votable, FCC_STEPPER_VOTER, false, 0);
- }
- static bool is_batt_available(struct pl_data *chip)
- {
- if (!chip->batt_psy)
- chip->batt_psy = power_supply_get_by_name("battery");
- if (!chip->batt_psy)
- return false;
- return true;
- }
- #define PARALLEL_FLOAT_VOLTAGE_DELTA_UV 50000
- static int pl_fv_vote_callback(struct votable *votable, void *data,
- int fv_uv, const char *client)
- {
- struct pl_data *chip = data;
- union power_supply_propval pval = {0, };
- int rc = 0, val;
- if (fv_uv < 0)
- return 0;
- val = fv_uv;
- rc = chip->chg_param->iio_write(chip->dev, PSY_IIO_VOLTAGE_MAX, val);
- if (rc < 0) {
- pr_err("Couldn't set main fv, rc=%d\n", rc);
- return rc;
- }
- if (chip->pl_mode != QTI_POWER_SUPPLY_PL_NONE) {
- val += PARALLEL_FLOAT_VOLTAGE_DELTA_UV;
- rc = battery_write_iio_prop(chip, SMB_PARALLEL,
- BAT_SMB_PARALLEL_VOLTAGE_MAX, val);
- if (rc < 0) {
- pr_err("Couldn't set float on parallel rc=%d\n", rc);
- return rc;
- }
- }
- /*
- * check for termination at reduced float voltage and re-trigger
- * charging if new float voltage is above last FV.
- */
- if ((chip->float_voltage_uv < fv_uv) && is_batt_available(chip)) {
- rc = power_supply_get_property(chip->batt_psy,
- POWER_SUPPLY_PROP_STATUS, &pval);
- if (rc < 0) {
- pr_err("Couldn't get battery status rc=%d\n", rc);
- } else {
- if (pval.intval == POWER_SUPPLY_STATUS_FULL) {
- pr_debug("re-triggering charging\n");
- val = 1;
- rc = chip->chg_param->iio_write(chip->dev,
- PSY_IIO_FORCE_RECHARGE, val);
- if (rc < 0)
- pr_err("Couldn't set force recharge rc=%d\n",
- rc);
- }
- }
- }
- chip->float_voltage_uv = fv_uv;
- return 0;
- }
- #define ICL_STEP_UA 25000
- #define PL_DELAY_MS 3000
- static int usb_icl_vote_callback(struct votable *votable, void *data,
- int icl_ua, const char *client)
- {
- int rc, val;
- struct pl_data *chip = data;
- union power_supply_propval pval = {0, };
- bool rerun_aicl = false, dc_present = false;
- if (client == NULL)
- icl_ua = INT_MAX;
- /*
- * Disable parallel for new ICL vote - the call to split_settled will
- * ensure that all the input current limit gets assigned to the main
- * charger.
- */
- vote(chip->pl_disable_votable, ICL_CHANGE_VOTER, true, 0);
- /*
- * if (ICL < 1400)
- * disable parallel charger using USBIN_I_VOTER
- * else
- * instead of re-enabling here rely on status_changed_work
- * (triggered via AICL completed or scheduled from here to
- * unvote USBIN_I_VOTER) the status_changed_work enables
- * USBIN_I_VOTER based on settled current.
- */
- if (icl_ua <= 1400000)
- vote(chip->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
- else
- schedule_delayed_work(&chip->status_change_work,
- msecs_to_jiffies(PL_DELAY_MS));
- /* rerun AICL */
- /* get the settled current */
- rc = chip->chg_param->iio_read(chip->dev,
- PSY_IIO_MAIN_INPUT_CURRENT_SETTLED, &val);
- if (rc < 0) {
- pr_err("Couldn't get aicl settled value rc=%d\n", rc);
- return rc;
- }
- /* rerun AICL if new ICL is above settled ICL */
- if (icl_ua > val)
- rerun_aicl = true;
- if (rerun_aicl && (chip->wa_flags & AICL_RERUN_WA_BIT)) {
- /* set a lower ICL */
- val = max(val - ICL_STEP_UA, ICL_STEP_UA);
- rc = chip->chg_param->iio_write(chip->dev, PSY_IIO_CURRENT_MAX,
- val);
- if (rc < 0)
- pr_err("Couldn't set main current_max, rc=%d\n", rc);
- }
- /* set the effective ICL */
- val = icl_ua;
- rc = chip->chg_param->iio_write(chip->dev, PSY_IIO_CURRENT_MAX, val);
- if (rc < 0)
- pr_err("Couldn't set main current_max, rc=%d\n", rc);
- vote(chip->pl_disable_votable, ICL_CHANGE_VOTER, false, 0);
- /* Configure ILIM based on AICL result only if input mode is USBMID */
- if (cp_get_parallel_mode(chip, PARALLEL_INPUT_MODE)
- == QTI_POWER_SUPPLY_PL_USBMID_USBMID) {
- if (chip->dc_psy) {
- rc = power_supply_get_property(chip->dc_psy,
- POWER_SUPPLY_PROP_PRESENT, &pval);
- if (rc < 0) {
- pr_err("Couldn't get DC PRESENT rc=%d\n", rc);
- return rc;
- }
- dc_present = pval.intval;
- }
- /* Don't configure ILIM if DC is present */
- if (!dc_present)
- cp_configure_ilim(chip, ICL_CHANGE_VOTER, icl_ua);
- }
- return 0;
- }
- static void pl_disable_forever_work(struct work_struct *work)
- {
- struct pl_data *chip = container_of(work,
- struct pl_data, pl_disable_forever_work);
- /* Disable Parallel charger forever */
- vote(chip->pl_disable_votable, PL_HW_ABSENT_VOTER, true, 0);
- /* Re-enable autonomous mode */
- if (chip->hvdcp_hw_inov_dis_votable)
- vote(chip->hvdcp_hw_inov_dis_votable, PL_VOTER, false, 0);
- }
- static int pl_disable_vote_callback(struct votable *votable,
- void *data, int pl_disable, const char *client)
- {
- struct pl_data *chip = data;
- union power_supply_propval pval = {0, };
- int master_fcc_ua = 0, total_fcc_ua = 0, slave_fcc_ua = 0;
- int rc = 0, cp_ilim;
- bool disable = false;
- if (!is_batt_available(chip))
- return -ENODEV;
- if (!chip->usb_psy)
- chip->usb_psy = power_supply_get_by_name("usb");
- if (!chip->usb_psy) {
- pr_err("Couldn't get usb psy\n");
- return -ENODEV;
- }
- rc = chip->chg_param->iio_read(chip->dev, PSY_IIO_FCC_STEPPER_ENABLE,
- &pval.intval);
- if (rc < 0) {
- pr_err("Couldn't read FCC step update status, rc=%d\n", rc);
- return rc;
- }
- chip->fcc_stepper_enable = pval.intval;
- pr_debug("FCC Stepper %s\n", pval.intval ? "enabled" : "disabled");
- rc = chip->chg_param->iio_read(chip->dev, PSY_IIO_MAIN_FCC_MAX,
- &pval.intval);
- if (rc < 0) {
- pl_dbg(chip, PR_PARALLEL,
- "Couldn't read primary charger FCC upper limit, rc=%d\n",
- rc);
- } else if (pval.intval > 0) {
- chip->main_fcc_max = pval.intval;
- }
- if (chip->fcc_stepper_enable) {
- cancel_delayed_work_sync(&chip->fcc_stepper_work);
- vote(chip->pl_awake_votable, FCC_STEPPER_VOTER, false, 0);
- }
- total_fcc_ua = get_effective_result_locked(chip->fcc_votable);
- if (chip->pl_mode != QTI_POWER_SUPPLY_PL_NONE && !pl_disable) {
- rc = validate_parallel_icl(chip, &disable);
- if (rc < 0)
- return rc;
- if (disable) {
- pr_info("Parallel ICL is less than min ICL(%d), skipping parallel enable\n",
- chip->pl_min_icl_ua);
- return 0;
- }
- /* enable parallel charging */
- rc = battery_read_iio_prop(chip, SMB_PARALLEL,
- BAT_SMB_PARALLEL_CHARGE_TYPE, &pval.intval);
- if (rc == -ENODEV) {
- /*
- * -ENODEV is returned only if parallel chip
- * is not present in the system.
- * Disable parallel charger forever.
- */
- schedule_work(&chip->pl_disable_forever_work);
- return rc;
- }
- rerun_election(chip->fv_votable);
- get_fcc_split(chip, total_fcc_ua, &master_fcc_ua,
- &slave_fcc_ua);
- if (chip->fcc_stepper_enable) {
- get_fcc_stepper_params(chip, master_fcc_ua,
- slave_fcc_ua);
- if (chip->step_fcc) {
- vote(chip->pl_awake_votable, FCC_STEPPER_VOTER,
- true, 0);
- schedule_delayed_work(&chip->fcc_stepper_work,
- 0);
- }
- } else {
- /*
- * If there is an increase in slave share
- * (Also handles parallel enable case)
- * Set Main ICL then slave FCC
- * else
- * (Also handles parallel disable case)
- * Set slave ICL then main FCC.
- */
- if (slave_fcc_ua > chip->slave_fcc_ua) {
- vote(chip->fcc_main_votable, MAIN_FCC_VOTER,
- true, master_fcc_ua);
- pval.intval = slave_fcc_ua;
- rc = battery_write_iio_prop(chip, SMB_PARALLEL,
- BAT_SMB_PARALLEL_CONSTANT_CHARGE_CURRENT_MAX,
- pval.intval);
- if (rc < 0) {
- pr_err("Couldn't set parallel fcc, rc=%d\n",
- rc);
- return rc;
- }
- chip->slave_fcc_ua = slave_fcc_ua;
- } else {
- pval.intval = slave_fcc_ua;
- rc = battery_write_iio_prop(chip, SMB_PARALLEL,
- BAT_SMB_PARALLEL_CONSTANT_CHARGE_CURRENT_MAX,
- pval.intval);
- if (rc < 0) {
- pr_err("Couldn't set parallel fcc, rc=%d\n",
- rc);
- return rc;
- }
- chip->slave_fcc_ua = slave_fcc_ua;
- vote(chip->fcc_main_votable, MAIN_FCC_VOTER,
- true, master_fcc_ua);
- }
- /*
- * Enable will be called with a valid pl_psy always. The
- * PARALLEL_PSY_VOTER keeps it disabled unless a pl_psy
- * is seen.
- */
- pval.intval = 0;
- rc = battery_write_iio_prop(chip, SMB_PARALLEL,
- BAT_SMB_PARALLEL_INPUT_SUSPEND,
- pval.intval);
- if (rc < 0)
- pr_err("Couldn't change slave suspend state rc=%d\n",
- rc);
- if (IS_USBIN(chip->pl_mode))
- split_settled(chip);
- }
- /*
- * we could have been enabled while in taper mode,
- * start the taper work if so
- */
- rc = power_supply_get_property(chip->batt_psy,
- POWER_SUPPLY_PROP_CHARGE_TYPE, &pval);
- if (rc < 0) {
- pr_err("Couldn't get batt charge type rc=%d\n", rc);
- } else {
- if (pval.intval == POWER_SUPPLY_CHARGE_TYPE_ADAPTIVE
- && !chip->taper_work_running) {
- pl_dbg(chip, PR_PARALLEL,
- "pl enabled in Taper scheduing work\n");
- vote(chip->pl_awake_votable, TAPER_END_VOTER,
- true, 0);
- queue_work(system_long_wq,
- &chip->pl_taper_work);
- }
- }
- pl_dbg(chip, PR_PARALLEL, "master_fcc=%d slave_fcc=%d distribution=(%d/%d)\n",
- master_fcc_ua, slave_fcc_ua,
- (master_fcc_ua * 100) / total_fcc_ua,
- (slave_fcc_ua * 100) / total_fcc_ua);
- } else {
- if (chip->main_fcc_max)
- get_main_fcc_config(chip, &total_fcc_ua);
- if (!chip->fcc_stepper_enable) {
- if (IS_USBIN(chip->pl_mode))
- split_settled(chip);
- /* pl_psy may be NULL while in the disable branch */
- if (!IS_ERR_OR_NULL(chip->iio_chan_list_smb_parallel)) {
- pval.intval = 1;
- rc = battery_write_iio_prop(chip, SMB_PARALLEL,
- BAT_SMB_PARALLEL_INPUT_SUSPEND,
- pval.intval);
- if (rc < 0)
- pr_err("Couldn't change slave suspend state rc=%d\n",
- rc);
- }
- /* main psy gets all share */
- vote(chip->fcc_main_votable, MAIN_FCC_VOTER, true,
- total_fcc_ua);
- cp_ilim = total_fcc_ua - get_effective_result_locked(
- chip->fcc_main_votable);
- if (cp_ilim > 0)
- cp_configure_ilim(chip, FCC_VOTER, cp_ilim / 2);
- /* reset parallel FCC */
- chip->slave_fcc_ua = 0;
- chip->total_settled_ua = 0;
- chip->pl_settled_ua = 0;
- } else {
- get_fcc_stepper_params(chip, total_fcc_ua, 0);
- if (chip->step_fcc) {
- vote(chip->pl_awake_votable, FCC_STEPPER_VOTER,
- true, 0);
- schedule_delayed_work(&chip->fcc_stepper_work,
- 0);
- }
- }
- rerun_election(chip->fv_votable);
- }
- /* notify parallel state change */
- if (!IS_ERR_OR_NULL(chip->iio_chan_list_smb_parallel) &&
- (chip->pl_disable != pl_disable)
- && !chip->fcc_stepper_enable) {
- power_supply_changed(chip->pl_psy);
- chip->pl_disable = (bool)pl_disable;
- }
- pl_dbg(chip, PR_PARALLEL, "parallel charging %s\n",
- pl_disable ? "disabled" : "enabled");
- return 0;
- }
- static int pl_enable_indirect_vote_callback(struct votable *votable,
- void *data, int pl_enable, const char *client)
- {
- struct pl_data *chip = data;
- vote(chip->pl_disable_votable, PL_INDIRECT_VOTER, !pl_enable, 0);
- return 0;
- }
- static int pl_awake_vote_callback(struct votable *votable,
- void *data, int awake, const char *client)
- {
- struct pl_data *chip = data;
- if (awake)
- __pm_stay_awake(chip->pl_ws);
- else
- __pm_relax(chip->pl_ws);
- pr_debug("client: %s awake: %d\n", client, awake);
- return 0;
- }
- static bool is_parallel_available(struct pl_data *chip)
- {
- union power_supply_propval pval = {0, };
- int rc = 0;
- struct iio_channel **iio_list;
- if (IS_ERR(chip->iio_chan_list_smb_parallel))
- return false;
- if (!chip->iio_chan_list_smb_parallel) {
- iio_list = get_ext_channels(chip->dev,
- bat_smb_parallel_ext_iio_chan,
- ARRAY_SIZE(bat_smb_parallel_ext_iio_chan));
- if (IS_ERR(iio_list)) {
- rc = PTR_ERR(iio_list);
- if (rc != -EPROBE_DEFER) {
- dev_err(chip->dev, "Failed to get channels, %d\n",
- rc);
- chip->iio_chan_list_smb_parallel =
- ERR_PTR(-EINVAL);
- }
- return false;
- }
- chip->iio_chan_list_smb_parallel = iio_list;
- }
- if (!chip->pl_psy) {
- chip->pl_psy = power_supply_get_by_name("parallel");
- if (!chip->pl_psy)
- return false;
- }
- vote(chip->pl_disable_votable, PARALLEL_PSY_VOTER, false, 0);
- rc = battery_read_iio_prop(chip, SMB_PARALLEL, BAT_SMB_PARALLEL_MODE,
- &pval.intval);
- if (rc < 0) {
- pr_err("Couldn't get parallel mode from parallel rc=%d\n",
- rc);
- return false;
- }
- /*
- * Note that pl_mode will be updated to anything other than a _NONE
- * only after pl_psy is found. IOW pl_mode != _NONE implies that
- * pl_psy is present and valid.
- */
- chip->pl_mode = pval.intval;
- /* Disable autonomous votage increments for USBIN-USBIN */
- if (IS_USBIN(chip->pl_mode)
- && (chip->wa_flags & FORCE_INOV_DISABLE_BIT)) {
- if (!chip->hvdcp_hw_inov_dis_votable)
- chip->hvdcp_hw_inov_dis_votable =
- find_votable("HVDCP_HW_INOV_DIS");
- if (chip->hvdcp_hw_inov_dis_votable)
- /* Read current pulse count */
- vote(chip->hvdcp_hw_inov_dis_votable, PL_VOTER,
- true, 0);
- else
- return false;
- }
- rc = battery_read_iio_prop(chip, SMB_PARALLEL,
- BAT_SMB_PARALLEL_BATFET_MODE, &pval.intval);
- if (rc < 0) {
- pr_err("Couldn't get parallel batfet mode rc=%d\n",
- rc);
- return false;
- }
- chip->pl_batfet_mode = pval.intval;
- pval.intval = 0;
- rc = battery_read_iio_prop(chip, SMB_PARALLEL, BAT_SMB_PARALLEL_MIN_ICL,
- &pval.intval);
- if (rc < 0)
- pr_err("Couldn't get min_icl rc=%d\n", rc);
- else
- chip->pl_min_icl_ua = pval.intval;
- chip->pl_fcc_max = INT_MAX;
- rc = battery_read_iio_prop(chip, SMB_PARALLEL, BAT_SMB_PARALLEL_FCC_MAX,
- &pval.intval);
- if (!rc)
- chip->pl_fcc_max = pval.intval;
- else
- pr_err("Couldn't get fcc_max rc=%d\n", rc);
- return true;
- }
- static void handle_main_charge_type(struct pl_data *chip)
- {
- union power_supply_propval pval = {0, };
- int rc;
- rc = power_supply_get_property(chip->batt_psy,
- POWER_SUPPLY_PROP_CHARGE_TYPE, &pval);
- if (rc < 0) {
- pr_err("Couldn't get batt charge type rc=%d\n", rc);
- return;
- }
- /* not fast/not taper state to disables parallel */
- if ((pval.intval != POWER_SUPPLY_CHARGE_TYPE_FAST)
- && (pval.intval != POWER_SUPPLY_CHARGE_TYPE_ADAPTIVE)) {
- vote(chip->pl_disable_votable, CHG_STATE_VOTER, true, 0);
- chip->charge_type = pval.intval;
- return;
- }
- /* handle taper charge entry */
- if (chip->charge_type == POWER_SUPPLY_CHARGE_TYPE_FAST
- && (pval.intval == POWER_SUPPLY_CHARGE_TYPE_ADAPTIVE)) {
- chip->charge_type = pval.intval;
- if (!chip->taper_work_running) {
- pl_dbg(chip, PR_PARALLEL, "taper entry scheduling work\n");
- vote(chip->pl_awake_votable, TAPER_END_VOTER, true, 0);
- queue_work(system_long_wq, &chip->pl_taper_work);
- }
- return;
- }
- /* handle fast/taper charge entry */
- if (pval.intval == POWER_SUPPLY_CHARGE_TYPE_ADAPTIVE
- || pval.intval == POWER_SUPPLY_CHARGE_TYPE_FAST) {
- /*
- * Undo parallel charging termination if entered taper in
- * reduced float voltage condition due to jeita mitigation.
- */
- if (pval.intval == POWER_SUPPLY_CHARGE_TYPE_FAST &&
- (chip->taper_entry_fv <
- get_effective_result(chip->fv_votable))) {
- vote(chip->pl_disable_votable, TAPER_END_VOTER,
- false, 0);
- }
- pl_dbg(chip, PR_PARALLEL, "chg_state enabling parallel\n");
- vote(chip->pl_disable_votable, CHG_STATE_VOTER, false, 0);
- chip->charge_type = pval.intval;
- return;
- }
- /* remember the new state only if it isn't any of the above */
- chip->charge_type = pval.intval;
- }
- #define MIN_ICL_CHANGE_DELTA_UA 300000
- static void handle_settled_icl_change(struct pl_data *chip)
- {
- union power_supply_propval pval = {0, };
- int new_total_settled_ua;
- int rc, val;
- int main_settled_ua;
- int main_limited;
- int total_current_ua;
- bool disable = false;
- total_current_ua = get_effective_result_locked(chip->usb_icl_votable);
- /*
- * call aicl split only when USBIN_USBIN and enabled
- * and if aicl changed
- */
- rc = chip->chg_param->iio_read(chip->dev,
- PSY_IIO_MAIN_INPUT_CURRENT_SETTLED, &val);
- if (rc < 0) {
- pr_err("Couldn't get aicl settled value rc=%d\n", rc);
- return;
- }
- main_settled_ua = val;
- rc = chip->chg_param->iio_read(chip->dev, PSY_IIO_INPUT_CURRENT_LIMITED,
- &val);
- if (rc < 0) {
- pr_err("Couldn't get aicl settled value rc=%d\n", rc);
- return;
- }
- main_limited = val;
- if ((main_limited && (main_settled_ua + chip->pl_settled_ua) < 1400000)
- || (main_settled_ua == 0)
- || ((total_current_ua >= 0) &&
- (total_current_ua <= 1400000)))
- vote(chip->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
- else
- vote(chip->pl_enable_votable_indirect, USBIN_I_VOTER, true, 0);
- rerun_election(chip->fcc_votable);
- if (IS_USBIN(chip->pl_mode)) {
- /*
- * call aicl split only when USBIN_USBIN and enabled
- * and if settled current has changed by more than 300mA
- */
- new_total_settled_ua = main_settled_ua + chip->pl_settled_ua;
- pl_dbg(chip, PR_PARALLEL,
- "total_settled_ua=%d settled_ua=%d new_total_settled_ua=%d\n",
- chip->total_settled_ua, pval.intval,
- new_total_settled_ua);
- /* If ICL change is small skip splitting */
- if (abs(new_total_settled_ua - chip->total_settled_ua)
- > MIN_ICL_CHANGE_DELTA_UA) {
- rc = validate_parallel_icl(chip, &disable);
- if (rc < 0)
- return;
- vote(chip->pl_disable_votable, ICL_LIMIT_VOTER,
- disable, 0);
- if (!get_effective_result_locked(
- chip->pl_disable_votable))
- split_settled(chip);
- }
- }
- }
- static void handle_parallel_in_taper(struct pl_data *chip)
- {
- union power_supply_propval pval = {0, };
- int rc;
- if (get_effective_result_locked(chip->pl_disable_votable))
- return;
- if (IS_ERR_OR_NULL(chip->iio_chan_list_smb_parallel))
- return;
- rc = battery_read_iio_prop(chip, SMB_PARALLEL,
- BAT_SMB_PARALLEL_CHARGE_TYPE, &pval.intval);
- if (rc < 0) {
- pr_err("Couldn't get pl charge type rc=%d\n", rc);
- return;
- }
- /*
- * if parallel is seen in taper mode ever, that is an anomaly and
- * we disable parallel charger
- */
- if (pval.intval == POWER_SUPPLY_CHARGE_TYPE_ADAPTIVE) {
- vote(chip->pl_disable_votable, PL_TAPER_EARLY_BAD_VOTER,
- true, 0);
- return;
- }
- }
- static void handle_usb_change(struct pl_data *chip)
- {
- int rc, val;
- union power_supply_propval pval = {0, };
- if (!chip->usb_psy)
- chip->usb_psy = power_supply_get_by_name("usb");
- if (!chip->usb_psy) {
- pr_err("Couldn't get usbpsy\n");
- return;
- }
- rc = power_supply_get_property(chip->usb_psy,
- POWER_SUPPLY_PROP_PRESENT, &pval);
- if (rc < 0) {
- pr_err("Couldn't get present from USB rc=%d\n", rc);
- return;
- }
- if (!pval.intval) {
- /* USB removed: remove all stale votes */
- vote(chip->pl_disable_votable, TAPER_END_VOTER, false, 0);
- vote(chip->pl_disable_votable, PL_TAPER_EARLY_BAD_VOTER,
- false, 0);
- vote(chip->pl_disable_votable, ICL_LIMIT_VOTER, false, 0);
- chip->override_main_fcc_ua = 0;
- chip->total_fcc_ua = 0;
- chip->slave_fcc_ua = 0;
- chip->main_fcc_ua = 0;
- chip->charger_type = POWER_SUPPLY_TYPE_UNKNOWN;
- } else {
- rc = chip->chg_param->iio_read(chip->dev, PSY_IIO_USB_REAL_TYPE,
- &val);
- if (rc < 0)
- pr_err("Couldn't get USB real type rc=%d\n", rc);
- else
- chip->charger_type = val;
- }
- }
- static void status_change_work(struct work_struct *work)
- {
- struct pl_data *chip = container_of(work,
- struct pl_data, status_change_work.work);
- /*
- * re-run election for FCC/FV/ICL to ensure all
- * votes are reflected on hardware
- */
- rerun_election(chip->usb_icl_votable);
- rerun_election(chip->fcc_votable);
- rerun_election(chip->fv_votable);
- if (!is_batt_available(chip))
- return;
- is_parallel_available(chip);
- handle_usb_change(chip);
- handle_main_charge_type(chip);
- handle_settled_icl_change(chip);
- handle_parallel_in_taper(chip);
- }
- static int pl_notifier_call(struct notifier_block *nb,
- unsigned long ev, void *v)
- {
- struct power_supply *psy = v;
- struct pl_data *chip = container_of(nb, struct pl_data, nb);
- if (ev != PSY_EVENT_PROP_CHANGED)
- return NOTIFY_OK;
- if ((strcmp(psy->desc->name, "parallel") == 0)
- || (strcmp(psy->desc->name, "battery") == 0))
- schedule_delayed_work(&chip->status_change_work, 0);
- return NOTIFY_OK;
- }
- static int pl_register_notifier(struct pl_data *chip)
- {
- int rc;
- chip->nb.notifier_call = pl_notifier_call;
- rc = power_supply_reg_notifier(&chip->nb);
- if (rc < 0) {
- pr_err("Couldn't register psy notifier rc = %d\n", rc);
- return rc;
- }
- return 0;
- }
- static int pl_determine_initial_status(struct pl_data *chip)
- {
- status_change_work(&chip->status_change_work.work);
- return 0;
- }
- static void pl_config_init(struct pl_data *chip, int smb_version)
- {
- switch (smb_version) {
- case PMI8998_SUBTYPE:
- case PM660_SUBTYPE:
- chip->wa_flags = AICL_RERUN_WA_BIT | FORCE_INOV_DISABLE_BIT;
- break;
- default:
- break;
- }
- }
- static void qcom_batt_create_debugfs(struct pl_data *chip)
- {
- chip->dfs_root = debugfs_create_dir("battery", NULL);
- if (IS_ERR_OR_NULL(chip->dfs_root)) {
- pr_err("Couldn't create battery debugfs rc=%ld\n",
- (long)chip->dfs_root);
- return;
- }
- debugfs_create_u32("debug_mask", 0600, chip->dfs_root,
- &debug_mask);
- }
- #define DEFAULT_RESTRICTED_CURRENT_UA 1000000
- int qcom_batt_init(struct device *dev, struct charger_param *chg_param)
- {
- struct pl_data *chip;
- int rc = 0;
- if (!chg_param) {
- pr_err("invalid charger parameter\n");
- return -EINVAL;
- }
- if (!chg_param->iio_read || !chg_param->iio_write) {
- pr_err("Invalid iio read/write pointers\n");
- return -EINVAL;
- }
- /* initialize just once */
- if (the_chip) {
- pr_err("was initialized earlier. Failing now\n");
- return -EINVAL;
- }
- chip = kzalloc(sizeof(*chip), GFP_KERNEL);
- if (!chip)
- return -ENOMEM;
- chip->dev = dev;
- qcom_batt_create_debugfs(chip);
- chip->slave_pct = 50;
- chip->chg_param = chg_param;
- pl_config_init(chip, chg_param->smb_version);
- chip->restricted_current = DEFAULT_RESTRICTED_CURRENT_UA;
- chip->pl_ws = wakeup_source_register(NULL, "qcom-battery");
- if (!chip->pl_ws)
- goto cleanup;
- INIT_DELAYED_WORK(&chip->status_change_work, status_change_work);
- INIT_WORK(&chip->pl_taper_work, pl_taper_work);
- INIT_WORK(&chip->pl_disable_forever_work, pl_disable_forever_work);
- INIT_DELAYED_WORK(&chip->fcc_stepper_work, fcc_stepper_work);
- chip->fcc_main_votable = create_votable("FCC_MAIN", VOTE_MIN,
- pl_fcc_main_vote_callback,
- chip);
- if (IS_ERR(chip->fcc_main_votable)) {
- rc = PTR_ERR(chip->fcc_main_votable);
- chip->fcc_main_votable = NULL;
- goto release_wakeup_source;
- }
- chip->fcc_votable = create_votable("FCC", VOTE_MIN,
- pl_fcc_vote_callback,
- chip);
- if (IS_ERR(chip->fcc_votable)) {
- rc = PTR_ERR(chip->fcc_votable);
- chip->fcc_votable = NULL;
- goto destroy_votable;
- }
- chip->fv_votable = create_votable("FV", VOTE_MIN,
- pl_fv_vote_callback,
- chip);
- if (IS_ERR(chip->fv_votable)) {
- rc = PTR_ERR(chip->fv_votable);
- chip->fv_votable = NULL;
- goto destroy_votable;
- }
- chip->usb_icl_votable = create_votable("USB_ICL", VOTE_MIN,
- usb_icl_vote_callback,
- chip);
- if (IS_ERR(chip->usb_icl_votable)) {
- rc = PTR_ERR(chip->usb_icl_votable);
- chip->usb_icl_votable = NULL;
- goto destroy_votable;
- }
- chip->pl_disable_votable = create_votable("PL_DISABLE", VOTE_SET_ANY,
- pl_disable_vote_callback,
- chip);
- if (IS_ERR(chip->pl_disable_votable)) {
- rc = PTR_ERR(chip->pl_disable_votable);
- chip->pl_disable_votable = NULL;
- goto destroy_votable;
- }
- vote(chip->pl_disable_votable, CHG_STATE_VOTER, true, 0);
- vote(chip->pl_disable_votable, TAPER_END_VOTER, false, 0);
- vote(chip->pl_disable_votable, PARALLEL_PSY_VOTER, true, 0);
- chip->pl_awake_votable = create_votable("PL_AWAKE", VOTE_SET_ANY,
- pl_awake_vote_callback,
- chip);
- if (IS_ERR(chip->pl_awake_votable)) {
- rc = PTR_ERR(chip->pl_awake_votable);
- chip->pl_awake_votable = NULL;
- goto destroy_votable;
- }
- chip->pl_enable_votable_indirect = create_votable("PL_ENABLE_INDIRECT",
- VOTE_SET_ANY,
- pl_enable_indirect_vote_callback,
- chip);
- if (IS_ERR(chip->pl_enable_votable_indirect)) {
- rc = PTR_ERR(chip->pl_enable_votable_indirect);
- chip->pl_enable_votable_indirect = NULL;
- goto destroy_votable;
- }
- vote(chip->pl_disable_votable, PL_INDIRECT_VOTER, true, 0);
- rc = pl_register_notifier(chip);
- if (rc < 0) {
- pr_err("Couldn't register psy notifier rc = %d\n", rc);
- goto unreg_notifier;
- }
- rc = pl_determine_initial_status(chip);
- if (rc < 0) {
- pr_err("Couldn't determine initial status rc=%d\n", rc);
- goto unreg_notifier;
- }
- chip->pl_disable = true;
- chip->cp_disabled = true;
- chip->qcom_batt_class.name = "qcom-battery",
- chip->qcom_batt_class.owner = THIS_MODULE,
- chip->qcom_batt_class.class_groups = batt_class_groups;
- rc = class_register(&chip->qcom_batt_class);
- if (rc < 0) {
- pr_err("couldn't register pl_data sysfs class rc = %d\n", rc);
- goto unreg_notifier;
- }
- the_chip = chip;
- return 0;
- unreg_notifier:
- power_supply_unreg_notifier(&chip->nb);
- destroy_votable:
- destroy_votable(chip->pl_enable_votable_indirect);
- destroy_votable(chip->pl_awake_votable);
- destroy_votable(chip->pl_disable_votable);
- destroy_votable(chip->fv_votable);
- destroy_votable(chip->fcc_votable);
- destroy_votable(chip->fcc_main_votable);
- destroy_votable(chip->usb_icl_votable);
- release_wakeup_source:
- wakeup_source_unregister(chip->pl_ws);
- cleanup:
- kfree(chip);
- return rc;
- }
- void qcom_batt_deinit(void)
- {
- struct pl_data *chip = the_chip;
- if (chip == NULL)
- return;
- cancel_delayed_work_sync(&chip->status_change_work);
- cancel_work_sync(&chip->pl_taper_work);
- cancel_work_sync(&chip->pl_disable_forever_work);
- cancel_delayed_work_sync(&chip->fcc_stepper_work);
- power_supply_unreg_notifier(&chip->nb);
- destroy_votable(chip->pl_enable_votable_indirect);
- destroy_votable(chip->pl_awake_votable);
- destroy_votable(chip->pl_disable_votable);
- destroy_votable(chip->fv_votable);
- destroy_votable(chip->fcc_votable);
- destroy_votable(chip->fcc_main_votable);
- wakeup_source_unregister(chip->pl_ws);
- the_chip = NULL;
- kfree(chip);
- }
|