123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153 |
- // SPDX-License-Identifier: GPL-2.0-only
- /*
- * Copyright (c) 2020-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
- */
- #define pr_fmt(fmt) "SMB1398: %s: " fmt, __func__
- #include <linux/device.h>
- #include <linux/interrupt.h>
- #include <linux/module.h>
- #include <linux/of.h>
- #include <linux/of_device.h>
- #include <linux/of_irq.h>
- #include <linux/platform_device.h>
- #include <linux/pmic-voter.h>
- #include <linux/power_supply.h>
- #include <linux/regmap.h>
- #include <linux/iio/consumer.h>
- #include <linux/iio/iio.h>
- #include <linux/qti_power_supply.h>
- #include <dt-bindings/iio/qti_power_supply_iio.h>
- /* Status register definition */
- #define REVID_REVISION4 0x103
- #define INPUT_STATUS_REG 0x2609
- #define INPUT_USB_IN BIT(1)
- #define INPUT_WLS_IN BIT(0)
- #define PERPH0_INT_RT_STS_REG 0x2610
- #define USB_IN_OVLO_STS BIT(7)
- #define WLS_IN_OVLO_STS BIT(6)
- #define USB_IN_UVLO_STS BIT(5)
- #define WLS_IN_UVLO_STS BIT(4)
- #define DIV2_IREV_LATCH_STS BIT(3)
- #define VOL_UV_LATCH_STS BIT(2)
- #define TEMP_SHUTDOWN_STS BIT(1)
- #define CFLY_HARD_FAULT_LATCH_STS BIT(0)
- #define MODE_STATUS_REG 0x2641
- #define SMB_EN BIT(7)
- #define PRE_EN_DCDC BIT(6)
- #define DIV2_EN_SLAVE BIT(5)
- #define LCM_EN BIT(4)
- #define DIV2_EN BIT(3)
- #define BUCK_EN BIT(2)
- #define CFLY_SS_DONE BIT(1)
- #define DCDC_EN BIT(0)
- #define SWITCHER_OFF_WIN_STATUS_REG 0x2642
- #define DIV2_WIN_OV BIT(1)
- #define DIV2_WIN_UV BIT(0)
- #define SWITCHER_OFF_VIN_STATUS_REG 0x2643
- #define USB_IN_OVLO BIT(3)
- #define WLS_IN_OVLO BIT(2)
- #define USB_IN_UVLO BIT(1)
- #define WLS_IN_UVLO BIT(0)
- #define SWITCHER_OFF_FAULT_REG 0x2644
- #define VOUT_OV_3LVL_BUCK BIT(5)
- #define VOUT_UV_LATCH BIT(4)
- #define ITERM_3LVL_LATCH BIT(3)
- #define DIV2_IREV_LATCH BIT(2)
- #define TEMP_SHDWN BIT(1)
- #define CFLY_HARD_FAULT_LATCH BIT(0)
- #define BUCK_CC_CV_STATE_REG 0x2645
- #define BUCK_IN_CC_REGULATION BIT(1)
- #define BUCK_IN_CV_REGULATION BIT(0)
- #define INPUT_CURRENT_REGULATION_REG 0x2646
- #define BUCK_IN_ICL BIT(1)
- #define DIV2_IN_ILIM BIT(0)
- /* Config register definition */
- #define PERPH0_MISC_CFG2_REG 0x2636
- #define CFG_TEMP_PIN_ITEMP BIT(1)
- #define MISC_USB_WLS_SUSPEND_REG 0x2630
- #define WLS_SUSPEND BIT(1)
- #define USB_SUSPEND BIT(0)
- #define MISC_SL_SWITCH_EN_REG 0x2631
- #define EN_SLAVE BIT(1)
- #define EN_SWITCHER BIT(0)
- #define MISC_DIV2_3LVL_CTRL_REG 0x2632
- #define MISC_DIV2_3LVL_CTRL_MASK GENMASK(7, 0)
- #define EN_DIV2_CP BIT(2)
- #define EN_3LVL_BULK BIT(1)
- #define EN_CHG_2X BIT(0)
- #define MISC_CFG0_REG 0x2634
- #define DIS_SYNC_DRV_BIT BIT(5)
- #define SW_EN_SWITCHER_BIT BIT(3)
- #define CFG_DIS_FPF_IREV_BIT BIT(1)
- #define MISC_CFG1_REG 0x2635
- #define MISC_CFG1_MASK GENMASK(7, 0)
- #define CFG_OP_MODE_MASK GENMASK(2, 0)
- #define OP_MODE_DISABLED 0
- #define OP_MODE_3LVL_BULK 1
- #define OP_MODE_COMBO 2
- #define OP_MODE_DIV2_CP 3
- #define OP_MODE_PRE_REG_3S 4
- #define OP_MODE_ITLGS_1P 5
- #define OP_MODE_ITLGS_2X 6
- #define OP_MODE_PRE_REGULATOR 7
- #define MISC_CFG2_REG 0x2636
- #define NOLOCK_SPARE_REG 0x2637
- #define EN_SLAVE_OWN_FREQ_BIT BIT(5)
- #define DIV2_WIN_UV_SEL_BIT BIT(4)
- #define DIV2_WIN_UV_25MV 0
- #define COMBO_WIN_LO_EXIT_SEL_MASK GENMASK(3, 2)
- #define EXIT_DIV2_VOUT_HI_12P5MV 0
- #define EXIT_DIV2_VOUT_HI_25MV 1
- #define EXIT_DIV2_VOUT_HI_50MV 2
- #define EXIT_DIV2_VOUT_HI_75MV 3
- #define COMBO_WIN_HI_EXIT_SEL_MASK GENMASK(1, 0)
- #define EXIT_DIV2_VOUT_LO_75MV 0
- #define EXIT_DIV2_VOUT_LO_100MV 1
- #define EXIT_DIV2_VOUT_LO_200MV 2
- #define EXIT_DIV2_VOUT_LO_250MV 3
- #define SMB_EN_TRIGGER_CFG_REG 0x2639
- #define SMB_EN_NEG_TRIGGER BIT(1)
- #define SMB_EN_POS_TRIGGER BIT(0)
- #define PERPH0_DIV2_SLAVE 0x2652
- #define CFG_EN_SLAVE_OWN_FREQ BIT(1)
- #define CFG_DIV2_SYNC_CLK_PHASE_90 BIT(0)
- #define DIV2_LCM_CFG_REG 0x2653
- #define DIV2_LCM_REFRESH_TIMER_SEL_MASK GENMASK(5, 4)
- #define DIV2_WIN_BURST_HIGH_REF_MASK GENMASK(3, 2)
- #define DIV2_WIN_BURST_LOW_REF_MASK GENMASK(1, 0)
- #define DIV2_CURRENT_REG 0x2655
- #define DIV2_EN_ILIM_DET BIT(2)
- #define DIV2_EN_IREV_DET BIT(1)
- #define DIV2_EN_OCP_DET BIT(0)
- #define DIV2_PROTECTION_REG 0x2656
- #define DIV2_WIN_OV_SEL_MASK GENMASK(1, 0)
- #define WIN_OV_200_MV 0
- #define WIN_OV_300_MV 1
- #define WIN_OV_400_MV 2
- #define WIN_OV_500_MV 3
- #define PERPH0_OVLO_REF_REG 0x265B
- #define SMB1394_INPUT_OVLO_CONF_MASK GENMASK(2, 0)
- #define SMB1394_INPUT_OVLO_13P04V 0x5
- #define DIV2_MODE_CFG_REG 0x265C
- #define LCM_EXIT_CTRL_REG 0x265D
- #define ICHG_SS_DAC_TARGET_REG 0x2660
- #define ICHG_SS_DAC_VALUE_MASK GENMASK(5, 0)
- #define ICHG_STEP_MA 100
- #define VOUT_DAC_TARGET_REG 0x2663
- #define VOUT_DAC_VALUE_MASK GENMASK(7, 0)
- #define VOUT_1P_MIN_MV 3300
- #define VOUT_1S_MIN_MV 6600
- #define VOUT_1P_STEP_MV 10
- #define VOUT_1S_STEP_MV 20
- #define VOUT_SS_DAC_TARGET_REG 0x2666
- #define VOUT_SS_DAC_VALUE_MASK GENMASK(5, 0)
- #define VOUT_SS_1P_STEP_MV 90
- #define VOUT_SS_1S_STEP_MV 180
- #define IIN_SS_DAC_TARGET_REG 0x2669
- #define IIN_SS_DAC_VALUE_MASK GENMASK(6, 0)
- #define IIN_STEP_MA 50
- #define PERPH0_DIV2_REF_CFG 0x2671
- #define CFG_IREV_REF_BIT BIT(2)
- #define PERPH0_CFG_SDCDC_REG 0x267A
- #define EN_WIN_UV_BIT BIT(7)
- #define EN_WIN_OV_RISE_DEB_BIT BIT(6)
- #define PERPH0_SOVP_CFG0_REG 0x2680
- #define CFG_OVP_VSNS_THRESHOLD BIT(4)
- #define CFG_OVP_IGNORE_UVLO BIT(5)
- #define PERPH0_SSUPPLY_CFG0_REG 0x2682
- #define EN_HV_OV_OPTION2_BIT BIT(7)
- #define EN_MV_OV_OPTION2_BIT BIT(5)
- #define CFG_CMP_VOUT_VS_4V_REF_MASK GENMASK(2, 1)
- #define CMP_VOUT_VS_4V_REF_3P2V 0x3 /* Value for SMB1394 only */
- #define SSUPLY_TEMP_CTRL_REG 0x2683
- #define SEL_OUT_TEMP_MAX_MASK GENMASK(7, 5)
- #define SEL_OUT_TEMP_MAX_SHFT 5
- #define SEL_OUT_HIGHZ (0 << SEL_OUT_TEMP_MAX_SHFT)
- #define SEL_OUT_VTEMP (1 << SEL_OUT_TEMP_MAX_SHFT)
- #define SEL_OUT_ICHG (2 << SEL_OUT_TEMP_MAX_SHFT)
- #define SEL_OUT_IIN_FB (4 << SEL_OUT_TEMP_MAX_SHFT)
- #define PERPH1_INT_RT_STS_REG 0x2710
- #define DIV2_WIN_OV_STS BIT(7)
- #define DIV2_WIN_UV_STS BIT(6)
- #define DIV2_ILIM_STS BIT(5)
- #define DIV2_CFLY_SS_DONE_STS BIT(1)
- #define PERPH1_LOCK_SPARE_REG 0x27C3
- #define CFG_LOCK_SPARE1_MASK GENMASK(7, 6)
- #define CFG_LOCK_SPARE1_SHIFT 6
- /* available voters */
- #define ILIM_VOTER "ILIM_VOTER"
- #define TAPER_VOTER "TAPER_VOTER"
- #define STATUS_CHANGE_VOTER "STATUS_CHANGE_VOTER"
- #define SHUTDOWN_VOTER "SHUTDOWN_VOTER"
- #define CUTOFF_SOC_VOTER "CUTOFF_SOC_VOTER"
- #define SRC_VOTER "SRC_VOTER"
- #define ICL_VOTER "ICL_VOTER"
- #define WIRELESS_VOTER "WIRELESS_VOTER"
- #define SWITCHER_TOGGLE_VOTER "SWITCHER_TOGGLE_VOTER"
- #define USER_VOTER "USER_VOTER"
- #define FCC_VOTER "FCC_VOTER"
- #define CP_VOTER "CP_VOTER"
- #define CC_MODE_VOTER "CC_MODE_VOTER"
- #define MAIN_DISABLE_VOTER "MAIN_DISABLE_VOTER"
- #define TAPER_MAIN_ICL_LIMIT_VOTER "TAPER_MAIN_ICL_LIMIT_VOTER"
- /* Constant definitions */
- #define DIV2_MAX_ILIM_UA 5000000
- #define DIV2_MAX_ILIM_DUAL_CP_UA 10000000
- #define DIV2_ILIM_CFG_PCT 105
- #define TAPER_STEPPER_UA_DEFAULT 100000
- #define TAPER_STEPPER_UA_IN_CC_MODE 200000
- #define CC_MODE_TAPER_MAIN_ICL_UA 500000
- #define MAX_IOUT_UA 6300000
- #define MAX_1S_VOUT_UV 11700000
- #define THERMAL_SUSPEND_DECIDEGC 1400
- #define DIV2_CP_MASTER 0
- #define DIV2_CP_SLAVE 1
- #define COMBO_PRE_REGULATOR 2
- #define SMB1394_DIV2_CP_PRY 3
- #define SMB1394_DIV2_CP_SECY 4
- #define IS_SMB1394(role) \
- (role == SMB1394_DIV2_CP_PRY || role == SMB1394_DIV2_CP_SECY)
- enum isns_mode {
- ISNS_MODE_OFF = 0,
- ISNS_MODE_ACTIVE,
- ISNS_MODE_STANDBY,
- };
- enum ovp {
- OVP_17P7V = 0,
- OVP_14V,
- OVP_22P2V,
- OVP_7P3,
- };
- enum {
- /* Perph0 IRQs */
- CFLY_HARD_FAULT_LATCH_IRQ,
- TEMP_SHDWN_IRQ,
- VOUT_UV_LATH_IRQ,
- DIV2_IREV_LATCH_IRQ,
- WLS_IN_UVLO_IRQ,
- USB_IN_UVLO_IRQ,
- WLS_IN_OVLO_IRQ,
- USB_IN_OVLO_IRQ,
- /* Perph1 IRQs */
- BK_IIN_REG_IRQ,
- CFLY_SS_DONE_IRQ,
- EN_DCDC_IRQ,
- ITERM_3LVL_LATCH_IRQ,
- VOUT_OV_3LB_IRQ,
- DIV2_ILIM_IRQ,
- DIV2_WIN_UV_IRQ,
- DIV2_WIN_OV_IRQ,
- /* Perph2 IRQs */
- IN_3LVL_MODE_IRQ,
- DIV2_MODE_IRQ,
- BK_CV_REG_IRQ,
- BK_CC_REG_IRQ,
- SS_DAC_INT_IRQ,
- SMB_EN_RISE_IRQ,
- SMB_EN_FALL_IRQ,
- /* End */
- NUM_IRQS,
- };
- struct smb_irq {
- const char *name;
- const irq_handler_t handler;
- const bool wake;
- int shift;
- };
- static const struct smb_irq smb_irqs[];
- struct smb1398_chip {
- struct device *dev;
- struct regmap *regmap;
- u8 rev4;
- struct wakeup_source *ws;
- struct iio_channel *die_temp_chan;
- unsigned int nchannels;
- struct iio_channel **cp_slave_iio_chan_list;
- struct iio_chan_spec *cp_iio_chan_ids;
- struct iio_channel **smb5_iio_chan_list;
- struct power_supply *div2_cp_master_psy;
- struct power_supply *div2_cp_slave_psy;
- struct power_supply *pre_regulator_psy;
- struct power_supply *batt_psy;
- struct power_supply *dc_psy;
- struct power_supply *usb_psy;
- struct notifier_block nb;
- struct votable *awake_votable;
- struct votable *div2_cp_disable_votable;
- struct votable *div2_cp_slave_disable_votable;
- struct votable *div2_cp_ilim_votable;
- struct votable *pre_regulator_iout_votable;
- struct votable *pre_regulator_vout_votable;
- struct votable *fcc_votable;
- struct votable *fv_votable;
- struct votable *fcc_main_votable;
- struct votable *usb_icl_votable;
- struct work_struct status_change_work;
- struct work_struct taper_work;
- struct mutex die_chan_lock;
- spinlock_t status_change_lock;
- int irqs[NUM_IRQS];
- int die_temp;
- int div2_cp_min_ilim_ua;
- int ilim_ua_disable_div2_cp_slave;
- int max_cutoff_soc;
- int taper_entry_fv;
- int div2_irq_status;
- u32 div2_cp_role;
- u32 pl_output_mode;
- u32 pl_input_mode;
- enum isns_mode current_capability;
- int cc_mode_taper_main_icl_ua;
- int cp_status1;
- int cp_status2;
- int cp_enable;
- int cp_isns_master;
- int cp_isns_slave;
- int cp_ilim;
- int adapter_type;
- bool status_change_running;
- bool taper_work_running;
- bool cutoff_soc_checked;
- bool smb_en;
- bool switcher_en;
- bool slave_en;
- bool in_suspend;
- bool disabled;
- bool usb_present;
- };
- struct cp_iio_prop_channels {
- const char *datasheet_name;
- int channel_no;
- enum iio_chan_type type;
- long info_mask;
- };
- #define SMB1398_CHAN(_dname, _chno, _type, _mask) \
- { \
- .datasheet_name = _dname, \
- .channel_no = _chno, \
- .type = _type, \
- .info_mask = _mask, \
- },
- #define SMB1398_CHAN_CUR(_dname, _chno) \
- SMB1398_CHAN(_dname, _chno, IIO_CURRENT, \
- BIT(IIO_CHAN_INFO_PROCESSED))
- #define SMB1398_CHAN_TEMP(_dname, _chno) \
- SMB1398_CHAN(_dname, _chno, IIO_TEMP, \
- BIT(IIO_CHAN_INFO_PROCESSED))
- #define SMB1398_CHAN_INDEX(_dname, _chno) \
- SMB1398_CHAN(_dname, _chno, IIO_INDEX, \
- BIT(IIO_CHAN_INFO_PROCESSED))
- static int smb1398_read(struct smb1398_chip *chip, u16 reg, u8 *val)
- {
- int rc = 0, value = 0;
- rc = regmap_read(chip->regmap, reg, &value);
- if (rc < 0)
- dev_err(chip->dev, "Couldn't read register 0x%x, rc=%d\n",
- reg, rc);
- else
- *val = (u8)value;
- return rc;
- }
- static int smb1398_masked_write(struct smb1398_chip *chip,
- u16 reg, u8 mask, u8 val)
- {
- int rc = 0;
- rc = regmap_update_bits(chip->regmap, reg, mask, val);
- if (rc < 0)
- dev_err(chip->dev, "Couldn't update register 0x%x to 0x%x with mask 0x%x, rc=%d\n",
- reg, val, mask, rc);
- return rc;
- }
- enum iio_type {
- CP_SLAVE,
- QPNP_SMB5,
- };
- enum cp_slave_channels {
- CURRENT_CAPABILITY = 0,
- CP_ENABLE,
- CP_INPUT_CURRENT_MAX,
- };
- enum smb5_iio_channels {
- REAL_TYPE = 0,
- ADAPTER_CC_MODE,
- PD_CURRENT_MAX,
- INPUT_CURRENT_SETTLED,
- SMB_EN_MODE,
- SMB_EN_REASON,
- };
- static const char * const cp_slave_iio_chans[] = {
- [CURRENT_CAPABILITY] = "cp_current_capability",
- [CP_ENABLE] = "cp_enable",
- [CP_INPUT_CURRENT_MAX] = "cp_input_current_max",
- };
- static const char * const cp_smb5_ext_iio_chan[] = {
- [REAL_TYPE] = "real_type",
- [ADAPTER_CC_MODE] = "adapter_cc_mode",
- [PD_CURRENT_MAX] = "pd_current_max",
- [INPUT_CURRENT_SETTLED] = "input_current_settled",
- [SMB_EN_MODE] = "smb_en_mode",
- [SMB_EN_REASON] = "smb_en_reason",
- };
- static int cp_read_iio_prop(struct smb1398_chip *chip,
- enum iio_type type, int iio_chan_id, int *val)
- {
- struct iio_channel *iio_chan;
- int rc;
- if (type == QPNP_SMB5) {
- if (IS_ERR_OR_NULL(chip->smb5_iio_chan_list))
- return -ENODEV;
- iio_chan = chip->smb5_iio_chan_list[iio_chan_id];
- } else {
- pr_err_ratelimited("iio_type %d is not supported\n", type);
- return -EINVAL;
- }
- rc = iio_read_channel_processed(iio_chan, val);
- return rc < 0 ? rc : 0;
- }
- static int cp_write_iio_prop(struct smb1398_chip *chip,
- enum iio_type type, int iio_chan_id, int val)
- {
- struct iio_channel *iio_chan;
- if (type == CP_SLAVE) {
- if (IS_ERR_OR_NULL(chip->cp_slave_iio_chan_list))
- return -ENODEV;
- iio_chan = chip->cp_slave_iio_chan_list[iio_chan_id];
- } else {
- pr_err_ratelimited("iio_type %d is not supported\n", type);
- return -EINVAL;
- }
- return iio_write_channel_raw(iio_chan, val);
- }
- static int smb1398_get_enable_status(struct smb1398_chip *chip)
- {
- int rc = 0;
- u8 val;
- bool switcher_en = false;
- rc = smb1398_read(chip, MODE_STATUS_REG, &val);
- if (rc < 0)
- return rc;
- chip->smb_en = !!(val & SMB_EN);
- chip->switcher_en = !!(val & PRE_EN_DCDC);
- chip->slave_en = !!(val & DIV2_EN_SLAVE);
- rc = smb1398_read(chip, MISC_SL_SWITCH_EN_REG, &val);
- if (rc < 0)
- return rc;
- switcher_en = !!(val & EN_SWITCHER);
- chip->switcher_en = switcher_en && chip->switcher_en;
- dev_dbg(chip->dev, "smb_en = %d, switcher_en = %d, slave_en = %d\n",
- chip->smb_en, chip->switcher_en, chip->slave_en);
- return rc;
- }
- static int smb1398_get_iin_ma(struct smb1398_chip *chip, int *iin_ma)
- {
- int rc = 0;
- u8 val;
- rc = smb1398_read(chip, IIN_SS_DAC_TARGET_REG, &val);
- if (rc < 0)
- return rc;
- *iin_ma = (val & IIN_SS_DAC_VALUE_MASK) * IIN_STEP_MA;
- dev_dbg(chip->dev, "get iin_ma = %dmA\n", *iin_ma);
- return rc;
- }
- static int smb1398_set_iin_ma(struct smb1398_chip *chip, int iin_ma)
- {
- int rc = 0;
- u8 val;
- val = iin_ma / IIN_STEP_MA;
- rc = smb1398_masked_write(chip, IIN_SS_DAC_TARGET_REG,
- IIN_SS_DAC_VALUE_MASK, val);
- if (rc < 0)
- return rc;
- dev_dbg(chip->dev, "set iin_ma = %dmA\n", iin_ma);
- return rc;
- }
- static int smb1398_set_ichg_ma(struct smb1398_chip *chip, int ichg_ma)
- {
- int rc = 0;
- u8 val;
- if (ichg_ma < 0 || ichg_ma > ICHG_SS_DAC_VALUE_MASK * ICHG_STEP_MA)
- return rc;
- val = ichg_ma / ICHG_STEP_MA;
- rc = smb1398_masked_write(chip, ICHG_SS_DAC_TARGET_REG,
- ICHG_SS_DAC_VALUE_MASK, val);
- dev_dbg(chip->dev, "set ichg %dmA\n", ichg_ma);
- return rc;
- }
- static int smb1398_get_ichg_ma(struct smb1398_chip *chip, int *ichg_ma)
- {
- int rc = 0;
- u8 val;
- rc = smb1398_read(chip, ICHG_SS_DAC_TARGET_REG, &val);
- if (rc < 0)
- return rc;
- *ichg_ma = (val & ICHG_SS_DAC_VALUE_MASK) * ICHG_STEP_MA;
- dev_dbg(chip->dev, "get ichg %dmA\n", *ichg_ma);
- return 0;
- }
- static int smb1398_set_1s_vout_mv(struct smb1398_chip *chip, int vout_mv)
- {
- int rc = 0;
- u8 val;
- if (vout_mv < VOUT_1S_MIN_MV)
- return -EINVAL;
- val = (vout_mv - VOUT_1S_MIN_MV) / VOUT_1S_STEP_MV;
- rc = smb1398_masked_write(chip, VOUT_DAC_TARGET_REG,
- VOUT_DAC_VALUE_MASK, val);
- if (rc < 0)
- return rc;
- return 0;
- }
- static int smb1398_get_1s_vout_mv(struct smb1398_chip *chip, int *vout_mv)
- {
- int rc;
- u8 val;
- rc = smb1398_read(chip, VOUT_DAC_TARGET_REG, &val);
- if (rc < 0)
- return rc;
- *vout_mv = (val & VOUT_DAC_VALUE_MASK) * VOUT_1S_STEP_MV +
- VOUT_1S_MIN_MV;
- return 0;
- }
- static int smb1398_get_die_temp(struct smb1398_chip *chip, int *temp)
- {
- int die_temp_deciC = 0, rc = 0;
- rc = smb1398_get_enable_status(chip);
- if (rc < 0)
- return rc;
- if (!chip->smb_en)
- return -ENODATA;
- mutex_lock(&chip->die_chan_lock);
- rc = iio_read_channel_processed(chip->die_temp_chan, &die_temp_deciC);
- mutex_unlock(&chip->die_chan_lock);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't read die_temp_chan, rc=%d\n", rc);
- } else {
- *temp = die_temp_deciC / 100;
- dev_dbg(chip->dev, "die temp %d\n", *temp);
- }
- return rc;
- }
- static int smb1398_div2_cp_get_status1(
- struct smb1398_chip *chip, u8 *status)
- {
- int rc = 0;
- u8 val;
- bool ilim, win_uv, win_ov;
- rc = smb1398_read(chip, PERPH1_INT_RT_STS_REG, &val);
- if (rc < 0)
- return rc;
- win_uv = !!(val & DIV2_WIN_UV_STS);
- win_ov = !!(val & DIV2_WIN_OV_STS);
- ilim = !!(val & DIV2_ILIM_STS);
- *status = ilim << 5 | win_uv << 1 | win_ov;
- dev_dbg(chip->dev, "status1 = 0x%x\n", *status);
- return rc;
- }
- static int smb1398_div2_cp_get_status2(
- struct smb1398_chip *chip, u8 *status)
- {
- int rc = 0;
- u8 val;
- bool smb_en, vin_ov, vin_uv, irev, tsd, switcher_off;
- rc = smb1398_read(chip, MODE_STATUS_REG, &val);
- if (rc < 0)
- return rc;
- smb_en = !!(val & SMB_EN);
- switcher_off = !(val & PRE_EN_DCDC);
- rc = smb1398_read(chip, PERPH1_INT_RT_STS_REG, &val);
- if (rc < 0)
- return rc;
- switcher_off = !(val & DIV2_CFLY_SS_DONE_STS) && switcher_off;
- rc = smb1398_read(chip, SWITCHER_OFF_VIN_STATUS_REG, &val);
- if (rc < 0)
- return rc;
- vin_ov = !!(val & USB_IN_OVLO);
- vin_uv = !!(val & USB_IN_UVLO);
- rc = smb1398_read(chip, SWITCHER_OFF_FAULT_REG, &val);
- if (rc < 0)
- return rc;
- irev = !!(val & DIV2_IREV_LATCH);
- tsd = !!(val & TEMP_SHDWN);
- *status = smb_en << 7 | vin_ov << 6 | vin_uv << 5
- | irev << 3 | tsd << 2 | switcher_off;
- dev_dbg(chip->dev, "status2 = 0x%x\n", *status);
- return rc;
- }
- static int smb1398_div2_cp_get_irq_status(
- struct smb1398_chip *chip, u8 *status)
- {
- int rc = 0;
- u8 val;
- bool ilim, irev, tsd, off_vin, off_win;
- rc = smb1398_read(chip, PERPH1_INT_RT_STS_REG, &val);
- if (rc < 0)
- return rc;
- ilim = !!(val & DIV2_ILIM_STS);
- off_win = !!(val & (DIV2_WIN_OV_STS | DIV2_WIN_UV_STS));
- rc = smb1398_read(chip, PERPH0_INT_RT_STS_REG, &val);
- if (rc < 0)
- return rc;
- irev = !!(val & DIV2_IREV_LATCH_STS);
- tsd = !!(val & TEMP_SHUTDOWN_STS);
- off_vin = !!(val & (USB_IN_OVLO_STS | USB_IN_UVLO_STS));
- *status = ilim << 6 | irev << 3 | tsd << 2 | off_vin << 1 | off_win;
- dev_dbg(chip->dev, "irq_status = 0x%x\n", *status);
- return rc;
- }
- static int smb1398_div2_cp_switcher_en(struct smb1398_chip *chip, bool en)
- {
- int rc;
- rc = smb1398_masked_write(chip, MISC_USB_WLS_SUSPEND_REG,
- USB_SUSPEND, en ? 0 : USB_SUSPEND);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't write USB_WLS_SUSPEND_REG, rc=%d\n",
- rc);
- return rc;
- }
- rc = smb1398_masked_write(chip, MISC_SL_SWITCH_EN_REG,
- EN_SWITCHER, en ? EN_SWITCHER : 0);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't write SWITCH_EN_REG, rc=%d\n", rc);
- return rc;
- }
- chip->switcher_en = en;
- dev_dbg(chip->dev, "%s switcher\n", en ? "enable" : "disable");
- return rc;
- }
- static int smb1398_div2_cp_isns_mode_control(
- struct smb1398_chip *chip, enum isns_mode mode)
- {
- int rc = 0;
- u8 mux_sel;
- switch (mode) {
- case ISNS_MODE_STANDBY:
- /* VTEMP */
- mux_sel = SEL_OUT_VTEMP;
- break;
- case ISNS_MODE_OFF:
- /* High-Z */
- mux_sel = SEL_OUT_HIGHZ;
- break;
- case ISNS_MODE_ACTIVE:
- /* IIN_FB */
- mux_sel = SEL_OUT_IIN_FB;
- break;
- default:
- return -EINVAL;
- }
- rc = smb1398_masked_write(chip, SSUPLY_TEMP_CTRL_REG,
- SEL_OUT_TEMP_MAX_MASK, mux_sel);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't set SSUPLY_TEMP_CTRL_REG, rc=%d\n",
- rc);
- return rc;
- }
- rc = smb1398_masked_write(chip, PERPH0_MISC_CFG2_REG,
- CFG_TEMP_PIN_ITEMP, 0);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't set PERPH0_MISC_CFG2_REG, rc=%d\n",
- rc);
- return rc;
- }
- return 0;
- }
- static inline int calculate_div2_cp_isns_ua(int temp)
- {
- /* ISNS = (2850 + (0.0034 * thermal_reading) / 0.32) * 1000 uA */
- return (2850 * 1000 + div_s64((s64)temp * 340, 32));
- }
- static struct iio_channel **get_ext_channels(struct device *dev,
- const char *const *channel_map, int size)
- {
- int i, rc = 0;
- struct iio_channel **iio_ch_ext;
- iio_ch_ext = devm_kcalloc(dev, size, sizeof(*iio_ch_ext), GFP_KERNEL);
- if (!iio_ch_ext)
- return ERR_PTR(-ENOMEM);
- for (i = 0; i < size; i++) {
- iio_ch_ext[i] = devm_iio_channel_get(dev, channel_map[i]);
- if (IS_ERR(iio_ch_ext[i])) {
- rc = PTR_ERR(iio_ch_ext[i]);
- if (rc != -EPROBE_DEFER)
- dev_err(dev, "%s channel unavailable, %d\n",
- channel_map[i], rc);
- return ERR_PTR(rc);
- }
- }
- return iio_ch_ext;
- }
- static bool is_cps_available(struct smb1398_chip *chip)
- {
- int rc = 0;
- struct iio_channel **iio_list;
- if (IS_ERR(chip->cp_slave_iio_chan_list))
- return false;
- if (!chip->cp_slave_iio_chan_list) {
- iio_list = get_ext_channels(chip->dev,
- cp_slave_iio_chans, ARRAY_SIZE(cp_slave_iio_chans));
- if (IS_ERR(iio_list)) {
- rc = PTR_ERR(iio_list);
- if (rc != -EPROBE_DEFER) {
- dev_err(chip->dev, "Failed to get channels, rc=%d\n",
- rc);
- chip->cp_slave_iio_chan_list = ERR_PTR(-EINVAL);
- }
- return false;
- }
- chip->cp_slave_iio_chan_list = iio_list;
- }
- return true;
- }
- static int smb1398_div2_cp_get_master_isns(
- struct smb1398_chip *chip, int *isns_ua)
- {
- int rc = 0, temp, val;
- rc = smb1398_get_enable_status(chip);
- if (rc < 0)
- return rc;
- if (!chip->smb_en)
- return -ENODATA;
- /*
- * Follow this procedure to read master CP ISNS:
- * set slave CP TEMP_MUX to HighZ;
- * set master CP TEMP_MUX to IIN_FB;
- * set DIV2_CP switch phase-shift to 0 deg;
- * read corresponding ADC channel in Kekaha;
- * set DIV2_CP switch phase-shif back to 90 deg;
- * set master CP TEMP_MUX to VTEMP;
- */
- mutex_lock(&chip->die_chan_lock);
- if (is_cps_available(chip)) {
- val = ISNS_MODE_OFF;
- rc = cp_write_iio_prop(chip, CP_SLAVE,
- CURRENT_CAPABILITY, val);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't set slave ISNS_MODE_OFF, rc=%d\n",
- rc);
- goto unlock;
- }
- }
- rc = smb1398_div2_cp_isns_mode_control(chip, ISNS_MODE_ACTIVE);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't set master ISNS_MODE_ACTIVE, rc=%d\n",
- rc);
- goto unlock;
- }
- rc = smb1398_masked_write(chip, PERPH0_DIV2_SLAVE,
- CFG_DIV2_SYNC_CLK_PHASE_90, 0);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't set PERPH0_DIV2_SLAVE, rc=%d\n",
- rc);
- goto unlock;
- }
- /* Delay for the phase switch to take effect */
- msleep(20);
- rc = iio_read_channel_processed(chip->die_temp_chan, &temp);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't read die_temp_chan, rc=%d\n", rc);
- goto unlock;
- }
- rc = smb1398_masked_write(chip, PERPH0_DIV2_SLAVE,
- CFG_DIV2_SYNC_CLK_PHASE_90, CFG_DIV2_SYNC_CLK_PHASE_90);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't set PERPH0_DIV2_SLAVE, rc=%d\n",
- rc);
- goto unlock;
- }
- rc = smb1398_div2_cp_isns_mode_control(chip, ISNS_MODE_STANDBY);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't set master ISNS_MODE_STANDBY, rc=%d\n",
- rc);
- goto unlock;
- }
- unlock:
- mutex_unlock(&chip->die_chan_lock);
- if (rc >= 0) {
- *isns_ua = calculate_div2_cp_isns_ua(temp);
- dev_dbg(chip->dev, "master isns = %duA\n", *isns_ua);
- }
- return rc;
- }
- static int smb1398_div2_cp_get_slave_isns(
- struct smb1398_chip *chip, int *isns_ua)
- {
- int temp = 0, rc, val;
- if (!is_cps_available(chip)) {
- *isns_ua = 0;
- return 0;
- }
- rc = smb1398_get_enable_status(chip);
- if (rc < 0)
- return rc;
- if (!chip->smb_en || !chip->slave_en)
- return -ENODATA;
- /*
- * Follow this procedure to read slave CP ISNS:
- * set master CP TEMP_MUX to HighZ;
- * set slave CP TEMP_MUX to IIN_FB;
- * set DIV2_CP switch phase-shift to 0 deg;
- * read corresponding ADC channel in Kekaha;
- * set DIV2_CP switch phase-shif back to 90 deg;
- * set master CP TEMP_MUX to VTEMP;
- */
- mutex_lock(&chip->die_chan_lock);
- rc = smb1398_div2_cp_isns_mode_control(chip, ISNS_MODE_OFF);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't set master ISNS_MODE_OFF, rc=%d\n",
- rc);
- goto unlock;
- }
- val = ISNS_MODE_ACTIVE;
- rc = cp_write_iio_prop(chip, CP_SLAVE, CURRENT_CAPABILITY, val);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't set slave ISNS_MODE_ACTIVE, rc=%d\n",
- rc);
- goto unlock;
- }
- rc = smb1398_masked_write(chip, PERPH0_DIV2_SLAVE,
- CFG_DIV2_SYNC_CLK_PHASE_90, 0);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't set PERPH0_DIV2_SLAVE, rc=%d\n",
- rc);
- goto unlock;
- }
- /* Delay for the phase switch to take effect */
- msleep(20);
- rc = iio_read_channel_processed(chip->die_temp_chan, &temp);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't get die_temp_chan, rc=%d\n", rc);
- goto unlock;
- }
- rc = smb1398_masked_write(chip, PERPH0_DIV2_SLAVE,
- CFG_DIV2_SYNC_CLK_PHASE_90, CFG_DIV2_SYNC_CLK_PHASE_90);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't set PERPH0_DIV2_SLAVE, rc=%d\n",
- rc);
- goto unlock;
- }
- rc = smb1398_div2_cp_isns_mode_control(chip, ISNS_MODE_STANDBY);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't set master ISNS_MODE_STANDBY, rc=%d\n",
- rc);
- goto unlock;
- }
- unlock:
- mutex_unlock(&chip->die_chan_lock);
- if (rc >= 0) {
- *isns_ua = calculate_div2_cp_isns_ua(temp);
- dev_dbg(chip->dev, "slave isns = %duA\n", *isns_ua);
- }
- return rc;
- }
- static void smb1398_toggle_switcher(struct smb1398_chip *chip)
- {
- int rc = 0;
- /*
- * Disable DIV2_ILIM detection before toggling the switcher
- * to prevent any ILIM interrupt storm while the toggling
- */
- rc = smb1398_masked_write(chip, DIV2_CURRENT_REG, DIV2_EN_ILIM_DET, 0);
- if (rc < 0)
- dev_err(chip->dev, "Couldn't disable EN_ILIM_DET, rc=%d\n", rc);
- vote(chip->div2_cp_disable_votable, SWITCHER_TOGGLE_VOTER, true, 0);
- /* Delay for toggling switcher */
- usleep_range(20, 30);
- vote(chip->div2_cp_disable_votable, SWITCHER_TOGGLE_VOTER, false, 0);
- rc = smb1398_masked_write(chip, DIV2_CURRENT_REG,
- DIV2_EN_ILIM_DET, DIV2_EN_ILIM_DET);
- if (rc < 0)
- dev_err(chip->dev, "Couldn't disable EN_ILIM_DET, rc=%d\n", rc);
- }
- #define DEFAULT_HVDCP3_MIN_ICL_UA 1000000
- static int smb1398_div2_cp_get_min_icl(struct smb1398_chip *chip)
- {
- int min_ilim = chip->div2_cp_min_ilim_ua;
- /* Use max(dt_min_icl, 1A) for HVDCP3 */
- if (chip->adapter_type == QTI_POWER_SUPPLY_TYPE_USB_HVDCP_3)
- min_ilim = max(chip->div2_cp_min_ilim_ua,
- DEFAULT_HVDCP3_MIN_ICL_UA);
- return min_ilim;
- }
- static char *div2_cp_get_model_name(struct smb1398_chip *chip)
- {
- if (IS_SMB1394(chip->div2_cp_role))
- return "SMB1394";
- if (chip->rev4 > 2)
- return "SMB1398_V3";
- else if (chip->rev4 == 2)
- return "SMB1398_V2";
- else
- return "SMB1398_V1";
- }
- static int smb1398_toggle_uvlo(struct smb1398_chip *chip)
- {
- int rc;
- rc = smb1398_masked_write(chip, PERPH0_SOVP_CFG0_REG,
- CFG_OVP_IGNORE_UVLO, CFG_OVP_IGNORE_UVLO);
- if (rc < 0)
- dev_err(chip->dev, "Couldn't write IGNORE_UVLO rc=%d\n", rc);
- rc = smb1398_masked_write(chip, PERPH0_SOVP_CFG0_REG,
- CFG_OVP_IGNORE_UVLO, 0);
- if (rc < 0)
- dev_err(chip->dev, "Couldn't write IGNORE_UVLO, rc=%d\n", rc);
- return rc;
- }
- static enum power_supply_property div2_cp_master_props[] = {
- POWER_SUPPLY_PROP_MODEL_NAME,
- };
- static int div2_cp_master_get_prop(struct power_supply *psy,
- enum power_supply_property prop,
- union power_supply_propval *val)
- {
- struct smb1398_chip *chip = power_supply_get_drvdata(psy);
- int rc = 0;
- switch (prop) {
- case POWER_SUPPLY_PROP_MODEL_NAME:
- val->strval = div2_cp_get_model_name(chip);
- break;
- default:
- rc = -EINVAL;
- break;
- }
- return rc;
- }
- static struct power_supply_desc div2_cp_master_desc = {
- .name = "charge_pump_master",
- .type = POWER_SUPPLY_TYPE_MAINS,
- .properties = div2_cp_master_props,
- .num_properties = ARRAY_SIZE(div2_cp_master_props),
- .get_property = div2_cp_master_get_prop,
- };
- static int smb1398_init_div2_cp_master_psy(struct smb1398_chip *chip)
- {
- struct power_supply_config div2_cp_master_psy_cfg = {};
- int rc = 0;
- div2_cp_master_psy_cfg.drv_data = chip;
- div2_cp_master_psy_cfg.of_node = chip->dev->of_node;
- chip->div2_cp_master_psy = devm_power_supply_register(chip->dev,
- &div2_cp_master_desc, &div2_cp_master_psy_cfg);
- if (IS_ERR(chip->div2_cp_master_psy)) {
- rc = PTR_ERR(chip->div2_cp_master_psy);
- dev_err(chip->dev, "Register div2_cp_master power supply failed, rc=%d\n",
- rc);
- return rc;
- }
- return 0;
- }
- static bool is_psy_voter_available(struct smb1398_chip *chip)
- {
- if (!chip->batt_psy) {
- chip->batt_psy = power_supply_get_by_name("battery");
- if (!chip->batt_psy) {
- dev_dbg(chip->dev, "Couldn't find battery psy\n");
- return false;
- }
- }
- if (!chip->usb_psy) {
- chip->usb_psy = power_supply_get_by_name("usb");
- if (!chip->usb_psy) {
- dev_dbg(chip->dev, "Couldn't find usb psy\n");
- return false;
- }
- }
- if (!chip->dc_psy) {
- chip->dc_psy = power_supply_get_by_name("dc");
- if (!chip->dc_psy) {
- dev_dbg(chip->dev, "Couldn't find DC psy\n");
- return false;
- }
- }
- if (!chip->fcc_votable) {
- chip->fcc_votable = find_votable("FCC");
- if (!chip->fcc_votable) {
- dev_dbg(chip->dev, "Couldn't find FCC voltable\n");
- return false;
- }
- }
- if (!chip->fv_votable) {
- chip->fv_votable = find_votable("FV");
- if (!chip->fv_votable) {
- dev_dbg(chip->dev, "Couldn't find FV voltable\n");
- return false;
- }
- }
- if (!chip->usb_icl_votable) {
- chip->usb_icl_votable = find_votable("USB_ICL");
- if (!chip->usb_icl_votable) {
- dev_dbg(chip->dev, "Couldn't find USB_ICL voltable\n");
- return false;
- }
- }
- if (!chip->fcc_main_votable) {
- chip->fcc_main_votable = find_votable("FCC_MAIN");
- if (!chip->fcc_main_votable) {
- dev_dbg(chip->dev, "Couldn't find FCC_MAIN voltable\n");
- return false;
- }
- }
- return true;
- }
- static bool is_cutoff_soc_reached(struct smb1398_chip *chip)
- {
- int rc;
- union power_supply_propval pval = {0};
- if (!chip->batt_psy)
- goto err;
- rc = power_supply_get_property(chip->batt_psy,
- POWER_SUPPLY_PROP_CAPACITY, &pval);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't get battery soc, rc=%d\n", rc);
- goto err;
- }
- if (pval.intval >= chip->max_cutoff_soc)
- return true;
- err:
- return false;
- }
- static bool is_adapter_in_cc_mode(struct smb1398_chip *chip)
- {
- int rc, val = 0;
- if (IS_ERR_OR_NULL(chip->smb5_iio_chan_list))
- return false;
- rc = cp_read_iio_prop(chip, QPNP_SMB5, ADAPTER_CC_MODE, &val);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't get ADAPTER_CC_MODE, rc=%d\n", rc);
- return false;
- }
- return !!val;
- }
- static int smb1398_awake_vote_cb(struct votable *votable,
- void *data, int awake, const char *client)
- {
- struct smb1398_chip *chip = (struct smb1398_chip *)data;
- if (awake)
- pm_stay_awake(chip->dev);
- else
- pm_relax(chip->dev);
- return 0;
- }
- static int smb1398_div2_cp_disable_vote_cb(struct votable *votable,
- void *data, int disable, const char *client)
- {
- struct smb1398_chip *chip = (struct smb1398_chip *)data;
- int rc = 0;
- if (!is_psy_voter_available(chip) || chip->in_suspend)
- return -EAGAIN;
- rc = smb1398_div2_cp_switcher_en(chip, !disable);
- if (rc < 0) {
- dev_err(chip->dev, "%s switcher failed, rc=%d\n",
- !!disable ? "disable" : "enable", rc);
- return rc;
- }
- if (is_cps_available(chip))
- vote(chip->div2_cp_slave_disable_votable, MAIN_DISABLE_VOTER,
- !!disable ? true : false, 0);
- if (chip->div2_cp_master_psy && (disable != chip->disabled))
- power_supply_changed(chip->div2_cp_master_psy);
- chip->disabled = disable;
- return 0;
- }
- static int smb1398_div2_cp_slave_disable_vote_cb(struct votable *votable,
- void *data, int disable, const char *client)
- {
- struct smb1398_chip *chip = (struct smb1398_chip *)data;
- u16 reg;
- u8 val;
- int rc, ilim_ua, value;
- if (!is_cps_available(chip))
- return -ENODEV;
- reg = MISC_SL_SWITCH_EN_REG;
- val = !!disable ? 0 : EN_SLAVE;
- rc = smb1398_masked_write(chip, reg, EN_SLAVE, val);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't write slave_en, rc=%d\n", rc);
- return rc;
- }
- value = !disable;
- rc = cp_write_iio_prop(chip, CP_SLAVE, CP_ENABLE, value);
- if (rc < 0) {
- dev_err(chip->dev, "%s slave switcher failed, rc=%d\n",
- !!disable ? "disable" : "enable", rc);
- return rc;
- }
- /* Re-distribute ILIM to Master CP when Slave is disabled */
- if (disable && (chip->div2_cp_ilim_votable)) {
- ilim_ua = get_effective_result_locked(
- chip->div2_cp_ilim_votable);
- ilim_ua = (ilim_ua * DIV2_ILIM_CFG_PCT) / 100;
- if (ilim_ua > DIV2_MAX_ILIM_UA)
- ilim_ua = DIV2_MAX_ILIM_UA;
- rc = smb1398_set_iin_ma(chip, ilim_ua / 1000);
- if (rc < 0) {
- dev_err(chip->dev, "Could't set CP master ilim, rc=%d\n",
- rc);
- return rc;
- }
- dev_dbg(chip->dev, "slave disabled, restore master CP ilim to %duA\n",
- ilim_ua);
- }
- return rc;
- }
- static int smb1398_div2_cp_ilim_vote_cb(struct votable *votable,
- void *data, int ilim_ua, const char *client)
- {
- struct smb1398_chip *chip = (struct smb1398_chip *)data;
- int rc = 0, max_ilim_ua, min_ilim_ua, val;
- bool slave_dis, split_ilim = false;
- if (!is_psy_voter_available(chip) || chip->in_suspend)
- return -EAGAIN;
- if (!client)
- return -EINVAL;
- min_ilim_ua = smb1398_div2_cp_get_min_icl(chip);
- ilim_ua = (ilim_ua * DIV2_ILIM_CFG_PCT) / 100;
- max_ilim_ua = is_cps_available(chip) ?
- DIV2_MAX_ILIM_DUAL_CP_UA : DIV2_MAX_ILIM_UA;
- ilim_ua = min(ilim_ua, max_ilim_ua);
- if (ilim_ua < min_ilim_ua) {
- dev_dbg(chip->dev, "ilim %duA is too low to config CP charging\n",
- ilim_ua);
- vote(chip->div2_cp_disable_votable, ILIM_VOTER, true, 0);
- } else {
- if (is_cps_available(chip)) {
- split_ilim = true;
- slave_dis = ilim_ua < (2 * min_ilim_ua);
- vote(chip->div2_cp_slave_disable_votable, ILIM_VOTER,
- slave_dis, 0);
- slave_dis = !!get_effective_result(
- chip->div2_cp_slave_disable_votable);
- if (slave_dis)
- split_ilim = false;
- }
- if (split_ilim) {
- ilim_ua /= 2;
- val = ilim_ua;
- rc = cp_write_iio_prop(chip, CP_SLAVE,
- CP_INPUT_CURRENT_MAX, val);
- if (rc < 0)
- dev_err(chip->dev, "Couldn't set CP slave ilim, rc=%d\n",
- rc);
- dev_dbg(chip->dev, "set CP slave ilim to %duA\n",
- ilim_ua);
- }
- rc = smb1398_set_iin_ma(chip, ilim_ua / 1000);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't set CP master ilim, rc=%d\n",
- rc);
- return rc;
- }
- dev_dbg(chip->dev, "set CP master ilim to %duA\n", ilim_ua);
- vote(chip->div2_cp_disable_votable, ILIM_VOTER, false, 0);
- }
- return 0;
- }
- static void smb1398_destroy_votables(struct smb1398_chip *chip)
- {
- destroy_votable(chip->awake_votable);
- destroy_votable(chip->div2_cp_disable_votable);
- destroy_votable(chip->div2_cp_ilim_votable);
- destroy_votable(chip->div2_cp_slave_disable_votable);
- }
- static int smb1398_div2_cp_create_votables(struct smb1398_chip *chip)
- {
- int rc;
- chip->awake_votable = create_votable("SMB1398_AWAKE",
- VOTE_SET_ANY, smb1398_awake_vote_cb, chip);
- if (IS_ERR_OR_NULL(chip->awake_votable))
- return PTR_ERR_OR_ZERO(chip->awake_votable);
- chip->div2_cp_disable_votable = create_votable("CP_DISABLE",
- VOTE_SET_ANY, smb1398_div2_cp_disable_vote_cb, chip);
- if (IS_ERR_OR_NULL(chip->div2_cp_disable_votable)) {
- rc = PTR_ERR_OR_ZERO(chip->div2_cp_disable_votable);
- goto destroy;
- }
- chip->div2_cp_slave_disable_votable = create_votable("CP_SLAVE_DISABLE",
- VOTE_SET_ANY, smb1398_div2_cp_slave_disable_vote_cb,
- chip);
- if (IS_ERR_OR_NULL(chip->div2_cp_slave_disable_votable)) {
- rc = PTR_ERR_OR_ZERO(chip->div2_cp_slave_disable_votable);
- goto destroy;
- }
- chip->div2_cp_ilim_votable = create_votable("CP_ILIM",
- VOTE_MIN, smb1398_div2_cp_ilim_vote_cb, chip);
- if (IS_ERR_OR_NULL(chip->div2_cp_ilim_votable)) {
- rc = PTR_ERR_OR_ZERO(chip->div2_cp_ilim_votable);
- goto destroy;
- }
- vote(chip->div2_cp_disable_votable, USER_VOTER, true, 0);
- vote(chip->div2_cp_disable_votable, CUTOFF_SOC_VOTER,
- is_cutoff_soc_reached(chip), 0);
- /*
- * In case SMB1398 probe happens after FCC value has been configured,
- * update ilim vote to reflect FCC / 2 value, this is only applicable
- * when SMB1398 is directly connected to VBAT.
- */
- if (is_psy_voter_available(chip) &&
- (chip->pl_output_mode != QTI_POWER_SUPPLY_PL_OUTPUT_VPH))
- vote(chip->div2_cp_ilim_votable, FCC_VOTER, true,
- get_effective_result(chip->fcc_votable) / 2);
- return 0;
- destroy:
- smb1398_destroy_votables(chip);
- return 0;
- }
- static irqreturn_t smb1398_default_irq_handler(int irq, void *data)
- {
- struct smb1398_chip *chip = data;
- int rc, i;
- bool switcher_en = chip->switcher_en;
- for (i = 0; i < NUM_IRQS; i++) {
- if (irq == chip->irqs[i]) {
- dev_dbg(chip->dev, "IRQ %s triggered\n",
- smb_irqs[i].name);
- chip->div2_irq_status |= 1 << smb_irqs[i].shift;
- }
- }
- rc = smb1398_get_enable_status(chip);
- if (rc < 0)
- goto out;
- if (chip->switcher_en != switcher_en)
- if (chip->fcc_votable)
- rerun_election(chip->fcc_votable);
- out:
- if (chip->div2_cp_master_psy)
- power_supply_changed(chip->div2_cp_master_psy);
- return IRQ_HANDLED;
- }
- static const struct smb_irq smb_irqs[] = {
- /* useful IRQs from perph0 */
- [TEMP_SHDWN_IRQ] = {
- .name = "temp-shdwn",
- .handler = smb1398_default_irq_handler,
- .wake = true,
- .shift = 2,
- },
- [DIV2_IREV_LATCH_IRQ] = {
- .name = "div2-irev",
- .handler = smb1398_default_irq_handler,
- .wake = true,
- .shift = 3,
- },
- [USB_IN_UVLO_IRQ] = {
- .name = "usbin-uv",
- .handler = smb1398_default_irq_handler,
- .wake = true,
- .shift = 1,
- },
- [USB_IN_OVLO_IRQ] = {
- .name = "usbin-ov",
- .handler = smb1398_default_irq_handler,
- .wake = true,
- .shift = 1,
- },
- /* useful IRQs from perph1 */
- [DIV2_ILIM_IRQ] = {
- .name = "div2-ilim",
- .handler = smb1398_default_irq_handler,
- .wake = true,
- .shift = 6,
- },
- [DIV2_WIN_UV_IRQ] = {
- .name = "div2-win-uv",
- .handler = smb1398_default_irq_handler,
- .wake = true,
- .shift = 0,
- },
- [DIV2_WIN_OV_IRQ] = {
- .name = "div2-win-ov",
- .handler = smb1398_default_irq_handler,
- .wake = true,
- .shift = 0,
- },
- };
- static int smb1398_get_irq_index_byname(const char *irq_name)
- {
- int i;
- for (i = 0; i < ARRAY_SIZE(smb_irqs); i++) {
- if (smb_irqs[i].name != NULL)
- if (strcmp(smb_irqs[i].name, irq_name) == 0)
- return i;
- }
- return -ENOENT;
- }
- static int smb1398_request_interrupt(struct smb1398_chip *chip,
- struct device_node *node, const char *irq_name)
- {
- int rc = 0, irq, irq_index;
- irq = of_irq_get_byname(node, irq_name);
- if (irq < 0) {
- dev_err(chip->dev, "Couldn't get irq %s failed\n", irq_name);
- return irq;
- }
- irq_index = smb1398_get_irq_index_byname(irq_name);
- if (irq_index < 0) {
- dev_err(chip->dev, "%s IRQ is not defined\n", irq_name);
- return irq_index;
- }
- if (!smb_irqs[irq_index].handler)
- return 0;
- /*
- * Do not register temp-shdwn interrupt as it may misfire on toggling
- * the SMB_EN input.
- */
- if (irq_index == TEMP_SHDWN_IRQ)
- return 0;
- rc = devm_request_threaded_irq(chip->dev, irq, NULL,
- smb_irqs[irq_index].handler,
- IRQF_ONESHOT, irq_name, chip);
- if (rc < 0) {
- dev_err(chip->dev, "Request interrupt for %s failed, rc=%d\n",
- irq_name, rc);
- return rc;
- }
- chip->irqs[irq_index] = irq;
- if (smb_irqs[irq_index].wake)
- enable_irq_wake(irq);
- return 0;
- }
- static int smb1398_request_interrupts(struct smb1398_chip *chip)
- {
- struct device_node *node = chip->dev->of_node;
- int rc = 0;
- const char *name;
- struct property *prop;
- of_property_for_each_string(node, "interrupt-names", prop, name) {
- rc = smb1398_request_interrupt(chip, node, name);
- if (rc < 0)
- return rc;
- }
- return 0;
- }
- #define ILIM_NR 10
- #define ILIM_DR 8
- #define ILIM_FACTOR(ilim) ((ilim * ILIM_NR) / ILIM_DR)
- static void smb1398_configure_ilim(struct smb1398_chip *chip, int mode)
- {
- int rc, val = 0;
- /* PPS adapter reply on the current advertised by the adapter */
- if ((chip->pl_output_mode == QTI_POWER_SUPPLY_PL_OUTPUT_VPH)
- && (mode == QTI_POWER_SUPPLY_CP_PPS)) {
- rc = cp_read_iio_prop(chip, QPNP_SMB5, PD_CURRENT_MAX, &val);
- if (rc < 0)
- pr_err("Couldn't get PD CURRENT MAX rc=%d\n", rc);
- else
- vote(chip->div2_cp_ilim_votable, ICL_VOTER,
- true, ILIM_FACTOR(val));
- }
- /* QC3.0/Wireless adapter rely on the settled AICL for USBMID_USBMID */
- if ((chip->pl_input_mode == QTI_POWER_SUPPLY_PL_USBMID_USBMID)
- && (mode == QTI_POWER_SUPPLY_CP_HVDCP3)) {
- rc = cp_read_iio_prop(chip, QPNP_SMB5, INPUT_CURRENT_SETTLED,
- &val);
- if (rc < 0)
- pr_err("Couldn't get usb aicl rc=%d\n", rc);
- else
- vote(chip->div2_cp_ilim_votable, ICL_VOTER,
- true, val);
- }
- }
- static void smb1398_status_change_work(struct work_struct *work)
- {
- struct smb1398_chip *chip = container_of(work,
- struct smb1398_chip, status_change_work);
- union power_supply_propval pval = {0};
- int rc, val = 0;
- if (!is_psy_voter_available(chip))
- goto out;
- /*
- * If batt soc is not valid upon bootup, but becomes
- * valid due to the battery discharging later, remove
- * vote from CUTOFF_SOC_VOTER.
- */
- if (!is_cutoff_soc_reached(chip))
- vote(chip->div2_cp_disable_votable, CUTOFF_SOC_VOTER, false, 0);
- rc = power_supply_get_property(chip->usb_psy,
- POWER_SUPPLY_PROP_PRESENT, &pval);
- if (rc < 0) {
- dev_err(chip->dev,
- "Couldn't get USB PRESENT status, rc=%d\n", rc);
- goto out;
- }
- if (chip->usb_present != !!pval.intval) {
- chip->usb_present = !!pval.intval;
- if (!chip->usb_present) /* USB has been removed */
- smb1398_toggle_uvlo(chip);
- }
- rc = cp_read_iio_prop(chip, QPNP_SMB5, SMB_EN_MODE, &val);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't get SMB_EN_MODE, rc=%d\n", rc);
- goto out;
- }
- /* If no CP charging started */
- if (val != QTI_POWER_SUPPLY_CHARGER_SEC_CP) {
- chip->cutoff_soc_checked = false;
- vote(chip->div2_cp_slave_disable_votable, SRC_VOTER, true, 0);
- vote(chip->div2_cp_slave_disable_votable,
- TAPER_VOTER, false, 0);
- vote(chip->div2_cp_disable_votable, TAPER_VOTER, false, 0);
- vote(chip->div2_cp_disable_votable, SRC_VOTER, true, 0);
- vote(chip->div2_cp_disable_votable, CUTOFF_SOC_VOTER, true, 0);
- vote(chip->fcc_votable, CP_VOTER, false, 0);
- vote(chip->div2_cp_ilim_votable, CC_MODE_VOTER, false, 0);
- vote_override(chip->usb_icl_votable,
- TAPER_MAIN_ICL_LIMIT_VOTER, false, 0);
- goto out;
- }
- rc = cp_read_iio_prop(chip, QPNP_SMB5, REAL_TYPE, &chip->adapter_type);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't get REAL_TYPE, rc=%d\n", rc);
- goto out;
- }
- rc = cp_read_iio_prop(chip, QPNP_SMB5, SMB_EN_REASON, &val);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't get SMB_EN_REASON failed, rc=%d\n",
- rc);
- goto out;
- }
- /*
- * Slave SMB1398 is not required for the power-rating of QC3
- */
- if (val != QTI_POWER_SUPPLY_CP_HVDCP3)
- vote(chip->div2_cp_slave_disable_votable, SRC_VOTER, false, 0);
- if (val == QTI_POWER_SUPPLY_CP_NONE) {
- vote(chip->div2_cp_disable_votable, SRC_VOTER, true, 0);
- goto out;
- }
- vote(chip->div2_cp_disable_votable, SRC_VOTER, false, 0);
- if (!chip->cutoff_soc_checked) {
- vote(chip->div2_cp_disable_votable, CUTOFF_SOC_VOTER,
- is_cutoff_soc_reached(chip), 0);
- chip->cutoff_soc_checked = true;
- }
- if (val == QTI_POWER_SUPPLY_CP_WIRELESS) {
- /*
- * Get the max output current from the wireless PSY
- * and set the DIV2 CP ilim accordingly
- */
- vote(chip->div2_cp_ilim_votable, ICL_VOTER, false, 0);
- rc = power_supply_get_property(chip->dc_psy,
- POWER_SUPPLY_PROP_CURRENT_MAX, &pval);
- if (rc < 0)
- dev_err(chip->dev, "Couldn't get DC CURRENT_MAX, rc=%d\n",
- rc);
- else
- vote(chip->div2_cp_ilim_votable, WIRELESS_VOTER,
- true, pval.intval);
- } else {
- vote(chip->div2_cp_ilim_votable, WIRELESS_VOTER, false, 0);
- smb1398_configure_ilim(chip, pval.intval);
- }
- /*
- * Remove CP Taper condition disable vote if float voltage
- * increased in comparison to voltage at which it entered taper.
- */
- if (chip->taper_entry_fv < get_effective_result(chip->fv_votable)) {
- vote(chip->div2_cp_slave_disable_votable,
- TAPER_VOTER, false, 0);
- vote(chip->div2_cp_disable_votable, TAPER_VOTER, false, 0);
- }
- /*
- * all votes that would result in disabling the charge pump have
- * been cast; ensure the charge pump is still enabled before
- * continuing.
- */
- if (get_effective_result(chip->div2_cp_disable_votable))
- goto out;
- rc = power_supply_get_property(chip->batt_psy,
- POWER_SUPPLY_PROP_CHARGE_TYPE, &pval);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't get CHARGE_TYPE, rc=%d\n",
- rc);
- goto out;
- }
- if (pval.intval == POWER_SUPPLY_CHARGE_TYPE_ADAPTIVE) {
- if (!chip->taper_work_running) {
- chip->taper_work_running = true;
- vote(chip->awake_votable, TAPER_VOTER, true, 0);
- queue_work(system_long_wq, &chip->taper_work);
- }
- }
- out:
- pm_relax(chip->dev);
- chip->status_change_running = false;
- }
- static int smb1398_notifier_cb(struct notifier_block *nb,
- unsigned long event, void *data)
- {
- struct smb1398_chip *chip = container_of(nb, struct smb1398_chip, nb);
- struct power_supply *psy = (struct power_supply *)data;
- unsigned long flags;
- if (event != PSY_EVENT_PROP_CHANGED)
- return NOTIFY_OK;
- if (strcmp(psy->desc->name, "battery") == 0 ||
- strcmp(psy->desc->name, "usb") == 0 ||
- strcmp(psy->desc->name, "cp_slave") == 0) {
- spin_lock_irqsave(&chip->status_change_lock, flags);
- if (!chip->status_change_running) {
- chip->status_change_running = true;
- pm_stay_awake(chip->dev);
- schedule_work(&chip->status_change_work);
- }
- spin_unlock_irqrestore(&chip->status_change_lock, flags);
- }
- return NOTIFY_OK;
- }
- static void smb1398_taper_work(struct work_struct *work)
- {
- struct smb1398_chip *chip = container_of(work,
- struct smb1398_chip, taper_work);
- union power_supply_propval pval = {0};
- int rc, fcc_ua, fv_uv, stepper_ua, main_fcc_ua = 0, min_ilim_ua;
- bool slave_en;
- if (!is_psy_voter_available(chip))
- goto out;
- if (!chip->fcc_main_votable)
- chip->fcc_main_votable = find_votable("FCC_MAIN");
- if (chip->fcc_main_votable)
- main_fcc_ua = get_effective_result(chip->fcc_main_votable);
- min_ilim_ua = smb1398_div2_cp_get_min_icl(chip);
- chip->taper_entry_fv = get_effective_result(chip->fv_votable);
- while (true) {
- rc = power_supply_get_property(chip->batt_psy,
- POWER_SUPPLY_PROP_CHARGE_TYPE, &pval);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't get CHARGE_TYPE, rc=%d\n",
- rc);
- goto out;
- }
- fv_uv = get_effective_result(chip->fv_votable);
- if (fv_uv > chip->taper_entry_fv) {
- dev_dbg(chip->dev, "Float voltage increased (%d-->%d)uV, exit!\n",
- chip->taper_entry_fv, fv_uv);
- vote(chip->div2_cp_disable_votable, TAPER_VOTER,
- false, 0);
- goto out;
- } else {
- chip->taper_entry_fv = fv_uv;
- }
- if (pval.intval == POWER_SUPPLY_CHARGE_TYPE_ADAPTIVE) {
- stepper_ua = is_adapter_in_cc_mode(chip) ?
- TAPER_STEPPER_UA_IN_CC_MODE :
- TAPER_STEPPER_UA_DEFAULT;
- fcc_ua = get_effective_result(chip->fcc_votable)
- - stepper_ua;
- dev_dbg(chip->dev, "Taper stepper reduce FCC to %d\n",
- fcc_ua);
- vote(chip->fcc_votable, CP_VOTER, true, fcc_ua);
- fcc_ua -= main_fcc_ua;
- /*
- * If total FCC is less than the minimum ILIM to
- * keep CP master and slave online, disable CP.
- */
- if (fcc_ua < (min_ilim_ua * 2)) {
- vote(chip->div2_cp_disable_votable,
- TAPER_VOTER, true, 0);
- /*
- * When master CP is disabled, reset all votes
- * on ICL to enable Main charger to pump
- * charging current.
- */
- if (chip->usb_icl_votable)
- vote_override(chip->usb_icl_votable,
- TAPER_MAIN_ICL_LIMIT_VOTER,
- false, 0);
- goto out;
- }
- /*
- * If total FCC is less than the minimum ILIM to keep
- * slave CP online, disable slave, and set master CP
- * ILIM to maximum to avoid ILIM IRQ storm.
- */
- slave_en = !get_effective_result(
- chip->div2_cp_slave_disable_votable);
- if ((fcc_ua < chip->ilim_ua_disable_div2_cp_slave) &&
- slave_en && is_cps_available(chip)) {
- dev_dbg(chip->dev, "Disable slave CP in taper\n");
- vote(chip->div2_cp_slave_disable_votable,
- TAPER_VOTER, true, 0);
- vote_override(chip->div2_cp_ilim_votable,
- CC_MODE_VOTER,
- is_adapter_in_cc_mode(chip),
- DIV2_MAX_ILIM_DUAL_CP_UA);
- if (chip->usb_icl_votable)
- vote_override(chip->usb_icl_votable,
- TAPER_MAIN_ICL_LIMIT_VOTER,
- is_adapter_in_cc_mode(chip),
- chip->cc_mode_taper_main_icl_ua);
- }
- } else {
- dev_dbg(chip->dev, "Not in taper, exit!\n");
- }
- msleep(500);
- }
- out:
- dev_dbg(chip->dev, "exit taper work\n");
- vote(chip->fcc_votable, CP_VOTER, false, 0);
- vote(chip->awake_votable, TAPER_VOTER, false, 0);
- chip->taper_work_running = false;
- }
- static int _smb1398_update_ovp(struct smb1398_chip *chip)
- {
- int rc = 0;
- /* Ignore for REV2 and below */
- if (chip->rev4 <= 2)
- return 0;
- rc = smb1398_masked_write(chip, PERPH0_SSUPPLY_CFG0_REG,
- EN_HV_OV_OPTION2_BIT | EN_MV_OV_OPTION2_BIT,
- EN_HV_OV_OPTION2_BIT);
- if (rc < 0) {
- dev_err(chip->dev,
- "Couldn't set PERPH0_SSUPPLY_CFG0_REG rc=%d\n", rc);
- return rc;
- }
- rc = smb1398_masked_write(chip, PERPH1_LOCK_SPARE_REG,
- CFG_LOCK_SPARE1_MASK,
- OVP_14V << CFG_LOCK_SPARE1_SHIFT);
- if (rc < 0) {
- dev_err(chip->dev,
- "Couldn't set PERPH1_LOCK_SPARE_REG rc=%d\n", rc);
- return rc;
- }
- return rc;
- }
- static int _smb1394_update_ovp(struct smb1398_chip *chip)
- {
- int rc = 0;
- rc = smb1398_masked_write(chip, PERPH0_SOVP_CFG0_REG,
- CFG_OVP_VSNS_THRESHOLD, CFG_OVP_VSNS_THRESHOLD);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't set PERPH0_SOVP_CFG0_REG rc=%d\n",
- rc);
- return rc;
- }
- rc = smb1398_masked_write(chip, PERPH0_OVLO_REF_REG,
- SMB1394_INPUT_OVLO_CONF_MASK,
- SMB1394_INPUT_OVLO_13P04V);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't set PERPH0_OVLO_REF rc=%d\n", rc);
- return rc;
- }
- rc = smb1398_masked_write(chip, PERPH0_CFG_SDCDC_REG,
- EN_WIN_OV_RISE_DEB_BIT, 0);
- if (rc < 0)
- dev_err(chip->dev, "Couldn't set PERPH0_CFG_SDCDC_REG rc=%d\n",
- rc);
- return rc;
- }
- static int smb1398_update_ovp(struct smb1398_chip *chip)
- {
- if (IS_SMB1394(chip->div2_cp_role))
- return _smb1394_update_ovp(chip);
- return _smb1398_update_ovp(chip);
- }
- static int smb1398_div2_cp_hw_init(struct smb1398_chip *chip)
- {
- int rc = 0;
- rc = smb1398_update_ovp(chip);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't update OVP threshold rc=%d\n", rc);
- return rc;
- }
- /* Configure window (Vin/2 - Vout) OV level to 500mV */
- rc = smb1398_masked_write(chip, DIV2_PROTECTION_REG,
- DIV2_WIN_OV_SEL_MASK, WIN_OV_500_MV);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't set WIN_OV_500_MV rc=%d\n", rc);
- return rc;
- }
- /* Configure window (Vin/2 - Vout) UV level to 10mV */
- rc = smb1398_masked_write(chip, NOLOCK_SPARE_REG,
- DIV2_WIN_UV_SEL_BIT, 0);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't set WIN_UV_10_MV rc=%d\n", rc);
- return rc;
- }
- /* Configure master TEMP pin to output Vtemp signal by default */
- rc = smb1398_masked_write(chip, SSUPLY_TEMP_CTRL_REG,
- SEL_OUT_TEMP_MAX_MASK, SEL_OUT_VTEMP);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't set SSUPLY_TEMP_CTRL_REG, rc=%d\n",
- rc);
- return rc;
- }
- /* Configure to use Vtemp signal */
- rc = smb1398_masked_write(chip, PERPH0_MISC_CFG2_REG,
- CFG_TEMP_PIN_ITEMP, 0);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't set PERPH0_MISC_CFG2_REG, rc=%d\n",
- rc);
- return rc;
- }
- /* Configure IREV threshold to 200mA */
- rc = smb1398_masked_write(chip, PERPH0_DIV2_REF_CFG,
- CFG_IREV_REF_BIT, 0);
- if (rc < 0) {
- pr_err("Couldn't configure IREV threshold rc=%d\n", rc);
- return rc;
- }
- /* Initial configuration needed before enabling DIV2_CP operations */
- rc = smb1398_masked_write(chip, MISC_DIV2_3LVL_CTRL_REG,
- MISC_DIV2_3LVL_CTRL_MASK, 0x04);
- if (rc < 0) {
- dev_err(chip->dev, "set EN_DIV2_CP failed, rc=%d\n", rc);
- return rc;
- }
- rc = smb1398_masked_write(chip, MISC_CFG1_REG, MISC_CFG1_MASK, 0x02);
- if (rc < 0) {
- dev_err(chip->dev, "set OP_MODE_COMBO failed, rc=%d\n", rc);
- return rc;
- }
- /* Do not disable FP_FET during IREV conditions */
- rc = smb1398_masked_write(chip, MISC_CFG0_REG, CFG_DIS_FPF_IREV_BIT, 0);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't set CFG_DIS_FPF_IREV_BIT, rc=%d\n",
- rc);
- return rc;
- }
- /* switcher enable controlled by register */
- rc = smb1398_masked_write(chip, MISC_CFG0_REG,
- SW_EN_SWITCHER_BIT, SW_EN_SWITCHER_BIT);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't set CFG_EN_SOURCE, rc=%d\n",
- rc);
- return rc;
- }
- if (IS_SMB1394(chip->div2_cp_role)) {
- rc = smb1398_masked_write(chip, PERPH0_SSUPPLY_CFG0_REG,
- CFG_CMP_VOUT_VS_4V_REF_MASK,
- CMP_VOUT_VS_4V_REF_3P2V);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't set PERPH0_SSUPPLY_CFG0_REG, rc=%d\n",
- rc);
- return rc;
- }
- }
- return rc;
- }
- #define DIV2_CP_MIN_ILIM_UA 1000000
- static int smb1398_div2_cp_parse_dt(struct smb1398_chip *chip)
- {
- int rc = 0;
- rc = of_property_match_string(chip->dev->of_node,
- "io-channel-names", "die_temp");
- if (rc < 0) {
- dev_err(chip->dev, "die_temp IIO channel not found\n");
- return rc;
- }
- chip->die_temp_chan = devm_iio_channel_get(chip->dev,
- "die_temp");
- if (IS_ERR(chip->die_temp_chan)) {
- rc = PTR_ERR(chip->die_temp_chan);
- if (rc != -EPROBE_DEFER)
- dev_err(chip->dev, "Couldn't get die_temp_chan, rc=%d\n",
- rc);
- chip->die_temp_chan = NULL;
- return rc;
- }
- of_property_read_u32(chip->dev->of_node, "qcom,div2-cp-min-ilim-ua",
- &chip->div2_cp_min_ilim_ua);
- /*
- * Set minimum allowed ilim configuration to 1A for DIV2_CP
- * operation.
- */
- if (chip->div2_cp_min_ilim_ua < DIV2_CP_MIN_ILIM_UA)
- chip->div2_cp_min_ilim_ua = DIV2_CP_MIN_ILIM_UA;
- chip->max_cutoff_soc = 85;
- of_property_read_u32(chip->dev->of_node, "qcom,max-cutoff-soc",
- &chip->max_cutoff_soc);
- chip->ilim_ua_disable_div2_cp_slave = chip->div2_cp_min_ilim_ua * 3;
- of_property_read_u32(chip->dev->of_node, "qcom,ilim-ua-disable-slave",
- &chip->ilim_ua_disable_div2_cp_slave);
- chip->cc_mode_taper_main_icl_ua = CC_MODE_TAPER_MAIN_ICL_UA;
- of_property_read_u32(chip->dev->of_node,
- "qcom,cc-mode-taper-main-icl-ua",
- &chip->cc_mode_taper_main_icl_ua);
- /* Default parallel output configuration is VPH connection */
- chip->pl_output_mode = QTI_POWER_SUPPLY_PL_OUTPUT_VPH;
- of_property_read_u32(chip->dev->of_node, "qcom,parallel-output-mode",
- &chip->pl_output_mode);
- /* Default parallel input configuration is USBMID connection */
- chip->pl_input_mode = QTI_POWER_SUPPLY_PL_USBMID_USBMID;
- of_property_read_u32(chip->dev->of_node, "qcom,parallel-input-mode",
- &chip->pl_input_mode);
- return 0;
- }
- static int smb1398_div2_cp_master_probe(struct smb1398_chip *chip)
- {
- int rc;
- rc = smb1398_read(chip, REVID_REVISION4, &chip->rev4);
- if (rc < 0) {
- dev_err(chip->dev,
- "Couldn't read REVID_REVISION4 rc=%d\n", rc);
- return rc;
- }
- spin_lock_init(&chip->status_change_lock);
- mutex_init(&chip->die_chan_lock);
- rc = smb1398_div2_cp_parse_dt(chip);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't parse devicetree, rc=%d\n", rc);
- return rc;
- }
- INIT_WORK(&chip->status_change_work, &smb1398_status_change_work);
- INIT_WORK(&chip->taper_work, &smb1398_taper_work);
- rc = smb1398_div2_cp_hw_init(chip);
- if (rc < 0) {
- dev_err(chip->dev, "div2_cp_hw_init failed, rc=%d\n", rc);
- return rc;
- }
- rc = smb1398_div2_cp_create_votables(chip);
- if (rc < 0) {
- dev_err(chip->dev, "smb1398_div2_cp_create_votables failed, rc=%d\n",
- rc);
- return rc;
- }
- rc = smb1398_init_div2_cp_master_psy(chip);
- if (rc > 0) {
- dev_err(chip->dev, "smb1398_init_div2_cp_master_psy failed, rc=%d\n",
- rc);
- goto destroy_votable;
- }
- chip->nb.notifier_call = smb1398_notifier_cb;
- rc = power_supply_reg_notifier(&chip->nb);
- if (rc < 0) {
- dev_err(chip->dev, "register notifier_cb failed, rc=%d\n", rc);
- goto destroy_votable;
- }
- rc = smb1398_request_interrupts(chip);
- if (rc < 0) {
- dev_err(chip->dev, "smb1398_request_interrupts failed, rc=%d\n",
- rc);
- goto destroy_votable;
- }
- rc = device_init_wakeup(chip->dev, true);
- if (rc < 0) {
- dev_err(chip->dev, "init wakeup failed for div2_cp_master device, rc=%d\n",
- rc);
- return rc;
- }
- dev_dbg(chip->dev, "smb1398 DIV2_CP master is probed successfully\n");
- return 0;
- destroy_votable:
- mutex_destroy(&chip->die_chan_lock);
- smb1398_destroy_votables(chip);
- return rc;
- }
- static enum power_supply_property div2_cp_slave_props[] = {
- POWER_SUPPLY_PROP_MODEL_NAME,
- };
- static int div2_cp_slave_get_prop(struct power_supply *psy,
- enum power_supply_property prop,
- union power_supply_propval *val)
- {
- struct smb1398_chip *chip = power_supply_get_drvdata(psy);
- switch (prop) {
- case POWER_SUPPLY_PROP_MODEL_NAME:
- val->strval = div2_cp_get_model_name(chip);
- break;
- default:
- dev_err(chip->dev, "read div2_cp_slave property %d is not supported\n",
- prop);
- return -EINVAL;
- }
- return 0;
- }
- static const struct power_supply_desc div2_cps_psy_desc = {
- .name = "cp_slave",
- .type = POWER_SUPPLY_TYPE_MAINS,
- .properties = div2_cp_slave_props,
- .num_properties = ARRAY_SIZE(div2_cp_slave_props),
- .get_property = div2_cp_slave_get_prop,
- };
- static int smb1398_init_div2_cp_slave_psy(struct smb1398_chip *chip)
- {
- int rc = 0;
- struct power_supply_config cps_cfg = {};
- cps_cfg.drv_data = chip;
- cps_cfg.of_node = chip->dev->of_node;
- chip->div2_cp_slave_psy = devm_power_supply_register(chip->dev,
- &div2_cps_psy_desc, &cps_cfg);
- if (IS_ERR(chip->div2_cp_slave_psy)) {
- rc = PTR_ERR(chip->div2_cp_slave_psy);
- dev_err(chip->dev, "register div2_cp_slave_psy failed, rc=%d\n",
- rc);
- return rc;
- }
- return 0;
- }
- static int smb1398_div2_cp_slave_probe(struct smb1398_chip *chip)
- {
- int rc;
- u8 status;
- rc = smb1398_read(chip, REVID_REVISION4, &chip->rev4);
- if (rc < 0) {
- dev_err(chip->dev,
- "Couldn't read REVID_REVISION4 rc=%d\n", rc);
- return rc;
- }
- rc = smb1398_update_ovp(chip);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't update OVP threshold rc=%d\n", rc);
- return rc;
- }
- rc = smb1398_read(chip, MODE_STATUS_REG, &status);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't read slave MODE_STATUS_REG, rc=%d\n",
- rc);
- return rc;
- }
- /* Configure window (Vin/2 - Vout) UV level to 10mV */
- rc = smb1398_masked_write(chip, NOLOCK_SPARE_REG,
- DIV2_WIN_UV_SEL_BIT, 0);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't set WIN_UV_10_MV rc=%d\n", rc);
- return rc;
- }
- /*
- * Disable slave WIN_UV detection, otherwise slave might not be
- * enabled due to WIN_UV until master drawing very high current.
- */
- rc = smb1398_masked_write(chip, PERPH0_CFG_SDCDC_REG, EN_WIN_UV_BIT, 0);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't disable DIV2_CP WIN_UV, rc=%d\n",
- rc);
- return rc;
- }
- /* Configure slave TEMP pin to HIGH-Z by default */
- rc = smb1398_masked_write(chip, SSUPLY_TEMP_CTRL_REG,
- SEL_OUT_TEMP_MAX_MASK, SEL_OUT_HIGHZ);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't set SSUPLY_TEMP_CTRL_REG, rc=%d\n",
- rc);
- return rc;
- }
- /* Configure to use Vtemp */
- rc = smb1398_masked_write(chip, PERPH0_MISC_CFG2_REG,
- CFG_TEMP_PIN_ITEMP, 0);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't set PERPH0_MISC_CFG2_REG, rc=%d\n",
- rc);
- return rc;
- }
- /* switcher enable controlled by register */
- rc = smb1398_masked_write(chip, MISC_CFG0_REG,
- SW_EN_SWITCHER_BIT, SW_EN_SWITCHER_BIT);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't set MISC_CFG0_REG, rc=%d\n",
- rc);
- return rc;
- }
- if (IS_SMB1394(chip->div2_cp_role)) {
- rc = smb1398_masked_write(chip, PERPH0_SSUPPLY_CFG0_REG,
- CFG_CMP_VOUT_VS_4V_REF_MASK,
- CMP_VOUT_VS_4V_REF_3P2V);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't set PERPH0_SSUPPLY_CFG0_REG, rc=%d\n",
- rc);
- return rc;
- }
- rc = smb1398_masked_write(chip, PERPH0_DIV2_SLAVE,
- CFG_EN_SLAVE_OWN_FREQ, CFG_EN_SLAVE_OWN_FREQ);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't set PERPH0_DIV2_SLAVE, rc=%d\n",
- rc);
- return rc;
- }
- } else {
- /* Enable slave clock on its own */
- rc = smb1398_masked_write(chip, NOLOCK_SPARE_REG,
- EN_SLAVE_OWN_FREQ_BIT, EN_SLAVE_OWN_FREQ_BIT);
- if (rc < 0) {
- dev_err(chip->dev, "Couldn't enable slave clock, rc=%d\n",
- rc);
- return rc;
- }
- }
- rc = smb1398_init_div2_cp_slave_psy(chip);
- if (rc < 0) {
- dev_err(chip->dev, "Initial div2_cp_slave_psy failed, rc=%d\n",
- rc);
- return rc;
- }
- dev_dbg(chip->dev, "smb1398 DIV2_CP slave probe successfully\n");
- return 0;
- }
- static int smb1398_pre_regulator_iout_vote_cb(struct votable *votable,
- void *data, int iout_ua, const char *client)
- {
- struct smb1398_chip *chip = (struct smb1398_chip *)data;
- int rc = 0;
- if (chip->in_suspend)
- return -EAGAIN;
- if (!client)
- return -EINVAL;
- iout_ua = min(iout_ua, MAX_IOUT_UA);
- rc = smb1398_set_ichg_ma(chip, (iout_ua / 1000));
- if (rc < 0)
- return rc;
- dev_dbg(chip->dev, "set iout %duA\n", iout_ua);
- return 0;
- }
- static int smb1398_pre_regulator_vout_vote_cb(struct votable *votable,
- void *data, int vout_uv, const char *client)
- {
- struct smb1398_chip *chip = (struct smb1398_chip *)data;
- int rc = 0;
- if (chip->in_suspend)
- return -EAGAIN;
- if (!client)
- return -EINVAL;
- vout_uv = min(vout_uv, MAX_1S_VOUT_UV);
- rc = smb1398_set_1s_vout_mv(chip, vout_uv / 1000);
- if (rc < 0)
- return rc;
- dev_dbg(chip->dev, "set vout %duV\n", vout_uv);
- return 0;
- }
- static int smb1398_create_pre_regulator_votables(struct smb1398_chip *chip)
- {
- chip->pre_regulator_iout_votable = create_votable("PRE_REGULATOR_IOUT",
- VOTE_MIN, smb1398_pre_regulator_iout_vote_cb, chip);
- if (IS_ERR_OR_NULL(chip->pre_regulator_iout_votable))
- return PTR_ERR_OR_ZERO(chip->pre_regulator_iout_votable);
- chip->pre_regulator_vout_votable = create_votable("PRE_REGULATOR_VOUT",
- VOTE_MIN, smb1398_pre_regulator_vout_vote_cb, chip);
- if (IS_ERR_OR_NULL(chip->pre_regulator_vout_votable)) {
- destroy_votable(chip->pre_regulator_iout_votable);
- return PTR_ERR_OR_ZERO(chip->pre_regulator_vout_votable);
- }
- return 0;
- }
- static enum power_supply_property pre_regulator_props[] = {
- POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
- POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
- POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
- };
- static int pre_regulator_get_prop(struct power_supply *psy,
- enum power_supply_property prop,
- union power_supply_propval *pval)
- {
- struct smb1398_chip *chip = power_supply_get_drvdata(psy);
- int rc, iin_ma, iout_ma, vout_mv;
- switch (prop) {
- case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
- rc = smb1398_get_iin_ma(chip, &iin_ma);
- if (rc < 0)
- return rc;
- pval->intval = iin_ma * 1000;
- break;
- case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
- if (chip->pre_regulator_iout_votable) {
- pval->intval = get_effective_result(
- chip->pre_regulator_iout_votable);
- } else {
- rc = smb1398_get_ichg_ma(chip, &iout_ma);
- if (rc < 0)
- return rc;
- pval->intval = iout_ma * 1000;
- }
- break;
- case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
- if (chip->pre_regulator_vout_votable) {
- pval->intval = get_effective_result(
- chip->pre_regulator_vout_votable);
- } else {
- rc = smb1398_get_1s_vout_mv(chip, &vout_mv);
- if (rc < 0)
- return rc;
- pval->intval = vout_mv * 1000;
- }
- break;
- default:
- dev_err(chip->dev, "read pre_regulator property %d is not supported\n",
- prop);
- return -EINVAL;
- }
- return 0;
- }
- static int pre_regulator_set_prop(struct power_supply *psy,
- enum power_supply_property prop,
- const union power_supply_propval *pval)
- {
- struct smb1398_chip *chip = power_supply_get_drvdata(psy);
- int rc = 0;
- switch (prop) {
- case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
- rc = smb1398_set_iin_ma(chip, pval->intval / 1000);
- if (rc < 0)
- return rc;
- break;
- case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
- vote(chip->pre_regulator_iout_votable, CP_VOTER,
- true, pval->intval);
- break;
- case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
- vote(chip->pre_regulator_vout_votable, CP_VOTER,
- true, pval->intval);
- break;
- default:
- dev_err(chip->dev, "write pre_regulator property %d is not supported\n",
- prop);
- return -EINVAL;
- }
- return rc;
- }
- static int pre_regulator_is_writeable(struct power_supply *psy,
- enum power_supply_property prop)
- {
- switch (prop) {
- case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
- case POWER_SUPPLY_PROP_CURRENT_MAX:
- case POWER_SUPPLY_PROP_VOLTAGE_MAX:
- return 1;
- default:
- break;
- }
- return 0;
- }
- static const struct power_supply_desc pre_regulator_psy_desc = {
- .name = "pre_regulator",
- .type = POWER_SUPPLY_TYPE_MAINS,
- .properties = pre_regulator_props,
- .num_properties = ARRAY_SIZE(pre_regulator_props),
- .get_property = pre_regulator_get_prop,
- .set_property = pre_regulator_set_prop,
- .property_is_writeable = pre_regulator_is_writeable,
- };
- static int smb1398_create_pre_regulator_psy(struct smb1398_chip *chip)
- {
- struct power_supply_config pre_regulator_psy_cfg = {};
- int rc = 0;
- pre_regulator_psy_cfg.drv_data = chip;
- pre_regulator_psy_cfg.of_node = chip->dev->of_node;
- chip->pre_regulator_psy = devm_power_supply_register(chip->dev,
- &pre_regulator_psy_desc,
- &pre_regulator_psy_cfg);
- if (IS_ERR(chip->pre_regulator_psy)) {
- rc = PTR_ERR(chip->pre_regulator_psy);
- dev_err(chip->dev, "register pre_regulator psy failed, rc=%d\n",
- rc);
- return rc;
- }
- return 0;
- }
- static int smb1398_pre_regulator_probe(struct smb1398_chip *chip)
- {
- int rc = 0;
- rc = smb1398_create_pre_regulator_votables(chip);
- if (rc < 0) {
- dev_err(chip->dev, "Create votable for pre_regulator failed, rc=%d\n",
- rc);
- return rc;
- }
- rc = smb1398_create_pre_regulator_psy(chip);
- if (rc < 0) {
- dev_err(chip->dev, "Create pre-regulator failed, rc=%d\n",
- rc);
- return rc;
- }
- return 0;
- }
- /* master IIO configuration */
- static const struct cp_iio_prop_channels cp_master_chans[] = {
- SMB1398_CHAN_INDEX("cp_master_cp_status_1", PSY_IIO_CP_STATUS1)
- SMB1398_CHAN_INDEX("cp_master_cp_status_2", PSY_IIO_CP_STATUS2)
- SMB1398_CHAN_INDEX("cp_master_cp_enable", PSY_IIO_CP_ENABLE)
- SMB1398_CHAN_INDEX("cp_master_cp_switcher_en", PSY_IIO_CP_SWITCHER_EN)
- SMB1398_CHAN_TEMP("cp_master_cp_die_temp", PSY_IIO_CP_DIE_TEMP)
- SMB1398_CHAN_CUR("cp_master_cp_isns", PSY_IIO_CP_ISNS)
- SMB1398_CHAN_CUR("cp_master_cp_isns_slave", PSY_IIO_CP_ISNS_SLAVE)
- SMB1398_CHAN_INDEX("cp_master_cp_toggle_switcher",
- PSY_IIO_CP_TOGGLE_SWITCHER)
- SMB1398_CHAN_INDEX("cp_master_cp_irq_status", PSY_IIO_IRQ_STATUS)
- SMB1398_CHAN_CUR("cp_master_cp_ilim", PSY_IIO_CP_ILIM)
- SMB1398_CHAN_INDEX("cp_master_chip_version", PSY_IIO_CHIP_VERSION)
- SMB1398_CHAN_INDEX("cp_master_parallel_mode", PSY_IIO_PARALLEL_MODE)
- SMB1398_CHAN_INDEX("cp_master_parallel_output_mode",
- PSY_IIO_PARALLEL_OUTPUT_MODE)
- SMB1398_CHAN_CUR("cp_master_min_icl", PSY_IIO_MIN_ICL)
- };
- static int cp_master_iio_set_prop(struct smb1398_chip *chip,
- int channel, int val)
- {
- switch (channel) {
- case PSY_IIO_CP_ENABLE:
- vote(chip->div2_cp_disable_votable,
- USER_VOTER, !val, 0);
- break;
- case PSY_IIO_CP_TOGGLE_SWITCHER:
- if (!!val)
- smb1398_toggle_switcher(chip);
- break;
- case PSY_IIO_IRQ_STATUS:
- chip->div2_irq_status = val;
- break;
- case PSY_IIO_CP_ILIM:
- if (chip->div2_cp_ilim_votable)
- vote_override(chip->div2_cp_ilim_votable, CC_MODE_VOTER,
- (val > 0), val);
- break;
- default:
- pr_err("get prop %d is not supported\n", channel);
- return -EINVAL;
- }
- return 0;
- }
- static int cp_master_iio_get_prop_in_suspend(struct smb1398_chip *chip,
- int channel, int *val)
- {
- switch (channel) {
- case PSY_IIO_CP_STATUS1:
- *val = chip->cp_status1;
- break;
- case PSY_IIO_CP_STATUS2:
- *val = chip->cp_status2;
- break;
- case PSY_IIO_CP_ENABLE:
- *val = chip->cp_enable;
- break;
- case PSY_IIO_CP_SWITCHER_EN:
- *val = chip->switcher_en;
- break;
- case PSY_IIO_CP_DIE_TEMP:
- *val = chip->die_temp;
- break;
- case PSY_IIO_CP_ISNS:
- *val = chip->cp_isns_master;
- break;
- case PSY_IIO_CP_ISNS_SLAVE:
- *val = chip->cp_isns_slave;
- break;
- case PSY_IIO_IRQ_STATUS:
- *val = chip->div2_irq_status;
- break;
- case PSY_IIO_CP_ILIM:
- *val = chip->cp_ilim;
- break;
- default:
- return -EINVAL;
- }
- return 0;
- }
- static int cp_master_iio_get_prop(struct smb1398_chip *chip,
- int channel, int *val)
- {
- int rc = 0, temp, isns_ua, ilim_ma;
- u8 status;
- /*
- * Return the cached values when the system is in suspend state
- * instead of reading the registers to avoid read failures.
- */
- if (chip->in_suspend) {
- rc = cp_master_iio_get_prop_in_suspend(chip, channel, val);
- if (!rc)
- return IIO_VAL_INT;
- rc = 0;
- }
- switch (channel) {
- case PSY_IIO_CP_STATUS1:
- rc = smb1398_div2_cp_get_status1(chip, &status);
- if (!rc)
- chip->cp_status1 = *val = status;
- break;
- case PSY_IIO_CP_STATUS2:
- rc = smb1398_div2_cp_get_status2(chip, &status);
- if (!rc)
- chip->cp_status2 = *val = status;
- break;
- case PSY_IIO_CP_ENABLE:
- rc = smb1398_get_enable_status(chip);
- if (!rc)
- chip->cp_enable = *val = chip->smb_en &&
- !get_effective_result(
- chip->div2_cp_disable_votable);
- break;
- case PSY_IIO_CP_SWITCHER_EN:
- rc = smb1398_get_enable_status(chip);
- if (!rc)
- *val = chip->switcher_en;
- break;
- case PSY_IIO_CP_ISNS:
- rc = smb1398_div2_cp_get_master_isns(chip, &isns_ua);
- if (rc >= 0)
- chip->cp_isns_master = *val = isns_ua;
- break;
- case PSY_IIO_CP_ISNS_SLAVE:
- rc = smb1398_div2_cp_get_slave_isns(chip, &isns_ua);
- if (rc >= 0)
- chip->cp_isns_slave = *val = isns_ua;
- break;
- case PSY_IIO_CP_TOGGLE_SWITCHER:
- *val = 0;
- break;
- case PSY_IIO_CP_DIE_TEMP:
- rc = smb1398_get_die_temp(chip, &temp);
- if (rc >= 0) {
- *val = temp;
- if (temp <= THERMAL_SUSPEND_DECIDEGC)
- chip->die_temp = temp;
- else if (chip->die_temp == -ENODATA)
- rc = -ENODATA;
- else
- *val = chip->die_temp;
- }
- break;
- case PSY_IIO_IRQ_STATUS:
- *val = chip->div2_irq_status;
- rc = smb1398_div2_cp_get_irq_status(chip, &status);
- if (!rc)
- *val |= status;
- break;
- case PSY_IIO_CP_ILIM:
- if (is_cps_available(chip)) {
- if (chip->div2_cp_ilim_votable)
- *val = get_effective_result(
- chip->div2_cp_ilim_votable);
- } else {
- rc = smb1398_get_iin_ma(chip, &ilim_ma);
- if (!rc)
- *val = (ilim_ma * 1000 * 100)
- / DIV2_ILIM_CFG_PCT;
- }
- chip->cp_ilim = *val;
- break;
- case PSY_IIO_CHIP_VERSION:
- *val = chip->rev4;
- break;
- case PSY_IIO_PARALLEL_MODE:
- *val = chip->pl_input_mode;
- break;
- case PSY_IIO_PARALLEL_OUTPUT_MODE:
- *val = chip->pl_output_mode;
- break;
- case PSY_IIO_MIN_ICL:
- *val = smb1398_div2_cp_get_min_icl(chip);
- break;
- default:
- pr_err("get prop %d is not supported\n", channel);
- rc = -EINVAL;
- break;
- }
- if (rc < 0 && rc != -ENODATA) {
- pr_err("Couldn't get prop %d rc = %d\n", channel, rc);
- return rc;
- }
- return IIO_VAL_INT;
- }
- static int cp_master_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan, int val, int val2,
- long mask)
- {
- struct smb1398_chip *iio_chip = iio_priv(indio_dev);
- int channel;
- channel = chan->channel;
- return cp_master_iio_set_prop(iio_chip, channel, val);
- }
- static int cp_master_read_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan, int *val, int *val2,
- long mask)
- {
- struct smb1398_chip *iio_chip = iio_priv(indio_dev);
- int channel;
- channel = chan->channel;
- return cp_master_iio_get_prop(iio_chip, channel, val);
- }
- /* slave IIO configuration */
- static const struct cp_iio_prop_channels cp_slave_chans[] = {
- SMB1398_CHAN_INDEX("cp_slave_cp_enable", PSY_IIO_CP_ENABLE)
- SMB1398_CHAN_CUR("cp_slave_input_current_max",
- PSY_IIO_CP_INPUT_CURRENT_MAX)
- SMB1398_CHAN_CUR("cp_slave_current_capability",
- PSY_IIO_CURRENT_CAPABILITY)
- };
- static int cp_slave_iio_set_prop(struct smb1398_chip *chip,
- int channel, int val)
- {
- int ilim_ma, rc = 0;
- enum isns_mode mode;
- switch (channel) {
- case PSY_IIO_CP_ENABLE:
- rc = smb1398_div2_cp_switcher_en(chip, !!val);
- break;
- case PSY_IIO_CP_INPUT_CURRENT_MAX:
- ilim_ma = val / 1000;
- rc = smb1398_set_iin_ma(chip, ilim_ma);
- break;
- case PSY_IIO_CURRENT_CAPABILITY:
- mode = (enum isns_mode)val;
- rc = smb1398_div2_cp_isns_mode_control(chip, mode);
- if (rc < 0)
- return rc;
- chip->current_capability = mode;
- break;
- default:
- pr_err("get prop %d is not supported\n", channel);
- rc = -EINVAL;
- break;
- }
- if (rc < 0) {
- pr_err("Couldn't set prop %d rc = %d\n", channel, rc);
- return rc;
- }
- return 0;
- }
- static int cp_slave_iio_get_prop(struct smb1398_chip *chip,
- int channel, int *val)
- {
- switch (channel) {
- case PSY_IIO_CP_ENABLE:
- *val = chip->switcher_en;
- break;
- case PSY_IIO_CP_INPUT_CURRENT_MAX:
- *val = 0;
- if (!chip->div2_cp_ilim_votable)
- chip->div2_cp_ilim_votable = find_votable("CP_ILIM");
- if (chip->div2_cp_ilim_votable)
- *val = get_effective_result_locked(
- chip->div2_cp_ilim_votable);
- break;
- case PSY_IIO_CURRENT_CAPABILITY:
- *val = (int)chip->current_capability;
- break;
- default:
- pr_err("get prop %d is not supported\n", channel);
- return -EINVAL;
- }
- return IIO_VAL_INT;
- }
- static int cp_slave_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan, int val, int val2,
- long mask)
- {
- struct smb1398_chip *iio_chip = iio_priv(indio_dev);
- int channel;
- channel = chan->channel;
- return cp_slave_iio_set_prop(iio_chip, channel, val);
- }
- static int cp_slave_read_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan, int *val, int *val2,
- long mask)
- {
- struct smb1398_chip *iio_chip = iio_priv(indio_dev);
- int channel;
- channel = chan->channel;
- return cp_slave_iio_get_prop(iio_chip, channel, val);
- }
- static int cp_fwnode_xlate(struct iio_dev *indio_dev,
- const struct fwnode_reference_args *iiospec)
- {
- struct smb1398_chip *iio_chip = iio_priv(indio_dev);
- int i;
- struct iio_chan_spec *iio_chan = iio_chip->cp_iio_chan_ids;
- for (i = 0; i < iio_chip->nchannels; i++) {
- if (iio_chan->channel == iiospec->args[0])
- return i;
- iio_chan++;
- }
- return -EINVAL;
- }
- static const struct iio_info cp_master_iio_info = {
- .read_raw = cp_master_read_raw,
- .write_raw = cp_master_write_raw,
- .fwnode_xlate = cp_fwnode_xlate,
- };
- static const struct iio_info cp_slave_iio_info = {
- .read_raw = cp_slave_read_raw,
- .write_raw = cp_slave_write_raw,
- .fwnode_xlate = cp_fwnode_xlate,
- };
- static int cp_smb5_iio_init(struct smb1398_chip *chip)
- {
- int rc = 0;
- struct iio_channel **iio_list;
- if (IS_ERR(chip->smb5_iio_chan_list))
- return -EINVAL;
- iio_list = get_ext_channels(chip->dev,
- cp_smb5_ext_iio_chan, ARRAY_SIZE(cp_smb5_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, rc=%d\n",
- rc);
- chip->smb5_iio_chan_list = ERR_PTR(-EINVAL);
- }
- return rc;
- }
- chip->smb5_iio_chan_list = iio_list;
- return 0;
- }
- static int cp_iio_probe_init(struct smb1398_chip *chip,
- struct iio_dev *indio_dev, const struct cp_iio_prop_channels *cp_chans,
- const struct iio_info *cp_iio_info)
- {
- int i;
- struct iio_chan_spec *iio_chan;
- chip->cp_iio_chan_ids = devm_kcalloc(chip->dev, chip->nchannels,
- sizeof(*chip->cp_iio_chan_ids), GFP_KERNEL);
- if (!chip->cp_iio_chan_ids)
- return -ENOMEM;
- for (i = 0; i < chip->nchannels; i++) {
- iio_chan = &chip->cp_iio_chan_ids[i];
- iio_chan->channel = cp_chans[i].channel_no;
- iio_chan->datasheet_name =
- cp_chans[i].datasheet_name;
- iio_chan->extend_name = cp_chans[i].datasheet_name;
- iio_chan->info_mask_separate =
- cp_chans[i].info_mask;
- iio_chan->type = cp_chans[i].type;
- iio_chan->address = i;
- }
- if (chip->div2_cp_role == DIV2_CP_MASTER ||
- chip->div2_cp_role == SMB1394_DIV2_CP_PRY) {
- cp_smb5_iio_init(chip);
- indio_dev->name = "smb1396-div2-cp-master";
- } else {
- indio_dev->name = "smb1396-div2-cp-slave";
- }
- indio_dev->info = cp_iio_info;
- return 0;
- }
- static int smb1398_probe(struct platform_device *pdev)
- {
- struct smb1398_chip *chip;
- struct iio_dev *indio_dev;
- int rc = 0;
- indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*chip));
- if (!indio_dev)
- return -ENOMEM;
- chip = iio_priv(indio_dev);
- chip->die_temp = -ENODATA;
- chip->dev = &pdev->dev;
- chip->regmap = dev_get_regmap(chip->dev->parent, NULL);
- if (!chip->regmap) {
- dev_err(chip->dev, "Get regmap failed\n");
- return -EINVAL;
- }
- chip->disabled = true;
- platform_set_drvdata(pdev, chip);
- chip->div2_cp_role = (u32)(unsigned long)of_device_get_match_data(chip->dev);
- switch (chip->div2_cp_role) {
- case DIV2_CP_MASTER:
- case SMB1394_DIV2_CP_PRY:
- chip->nchannels = ARRAY_SIZE(cp_master_chans);
- rc = smb1398_div2_cp_master_probe(chip);
- if (rc < 0) {
- if (rc != -EPROBE_DEFER)
- dev_err(chip->dev, "Couldn't probe SMB1398 master rc= %d\n",
- rc);
- goto cleanup;
- }
- rc = cp_iio_probe_init(chip, indio_dev, cp_master_chans, &cp_master_iio_info);
- break;
- case DIV2_CP_SLAVE:
- case SMB1394_DIV2_CP_SECY:
- chip->nchannels = ARRAY_SIZE(cp_slave_chans);
- rc = smb1398_div2_cp_slave_probe(chip);
- if (rc < 0) {
- if (rc != -EPROBE_DEFER)
- dev_err(chip->dev, "Couldn't probe SMB1398 slave rc= %d\n",
- rc);
- goto cleanup;
- }
- rc = cp_iio_probe_init(chip, indio_dev, cp_slave_chans, &cp_slave_iio_info);
- break;
- case COMBO_PRE_REGULATOR:
- rc = smb1398_pre_regulator_probe(chip);
- break;
- default:
- dev_err(chip->dev, "Couldn't find a match role for %d\n",
- chip->div2_cp_role);
- goto cleanup;
- }
- if (rc < 0) {
- if (rc != -EPROBE_DEFER)
- dev_err(chip->dev, "IIO init failed for %s rc= %d\n",
- !!chip->div2_cp_role ? "slave" : "master", rc);
- goto cleanup;
- }
- /*
- * This configuration below is applicable to both
- * master and slave. The individual channel
- * configurations are done in master/slave
- * iio_probe_init calls.
- */
- indio_dev->dev.parent = &pdev->dev;
- indio_dev->dev.of_node = pdev->dev.of_node;
- indio_dev->modes = INDIO_DIRECT_MODE;
- indio_dev->channels = chip->cp_iio_chan_ids;
- indio_dev->num_channels = chip->nchannels;
- rc = devm_iio_device_register(&pdev->dev, indio_dev);
- if (rc) {
- pr_err("iio device register failed rc=%d\n", rc);
- goto cleanup;
- }
- return 0;
- cleanup:
- platform_set_drvdata(pdev, NULL);
- return rc;
- }
- static int smb1398_remove(struct platform_device *pdev)
- {
- struct smb1398_chip *chip = platform_get_drvdata(pdev);
- if (chip->div2_cp_role == DIV2_CP_MASTER ||
- chip->div2_cp_role == SMB1394_DIV2_CP_PRY) {
- vote(chip->awake_votable, SHUTDOWN_VOTER, false, 0);
- vote(chip->div2_cp_disable_votable, SHUTDOWN_VOTER, true, 0);
- vote(chip->div2_cp_ilim_votable, SHUTDOWN_VOTER, true, 0);
- cancel_work_sync(&chip->taper_work);
- cancel_work_sync(&chip->status_change_work);
- mutex_destroy(&chip->die_chan_lock);
- smb1398_destroy_votables(chip);
- }
- return 0;
- }
- static int smb1398_suspend(struct device *dev)
- {
- struct smb1398_chip *chip = dev_get_drvdata(dev);
- chip->in_suspend = true;
- return 0;
- }
- static int smb1398_resume(struct device *dev)
- {
- struct smb1398_chip *chip = dev_get_drvdata(dev);
- chip->in_suspend = false;
- if (chip->div2_cp_role == DIV2_CP_MASTER) {
- rerun_election(chip->div2_cp_ilim_votable);
- rerun_election(chip->div2_cp_disable_votable);
- }
- return 0;
- }
- static void smb1398_shutdown(struct platform_device *pdev)
- {
- struct smb1398_chip *chip = platform_get_drvdata(pdev);
- int rc;
- power_supply_unreg_notifier(&chip->nb);
- /* Disable SMB1398 */
- rc = smb1398_div2_cp_switcher_en(chip, 0);
- if (rc < 0)
- dev_err(chip->dev, "Couldn't disable chip rc= %d\n", rc);
- rc = smb1398_toggle_uvlo(chip);
- if (rc < 0)
- dev_err(chip->dev, "Couldn't toggle uvlo rc= %d\n", rc);
- }
- static const struct dev_pm_ops smb1398_pm_ops = {
- .suspend = smb1398_suspend,
- .resume = smb1398_resume,
- };
- static const struct of_device_id match_table[] = {
- { .compatible = "qcom,smb1396-div2-cp-master",
- .data = (void *)DIV2_CP_MASTER,
- },
- { .compatible = "qcom,smb1396-div2-cp-slave",
- .data = (void *)DIV2_CP_SLAVE,
- },
- { .compatible = "qcom,smb1398-pre-regulator",
- .data = (void *)COMBO_PRE_REGULATOR,
- },
- { .compatible = "qcom,smb1394-div2-cp-primary",
- .data = (void *)SMB1394_DIV2_CP_PRY,
- },
- { .compatible = "qcom,smb1394-div2-cp-secondary",
- .data = (void *)SMB1394_DIV2_CP_SECY,
- },
- {
- },
- };
- static struct platform_driver smb1398_driver = {
- .driver = {
- .name = "qcom,smb1398-charger",
- .pm = &smb1398_pm_ops,
- .of_match_table = match_table,
- },
- .probe = smb1398_probe,
- .remove = smb1398_remove,
- .shutdown = smb1398_shutdown,
- };
- module_platform_driver(smb1398_driver);
- MODULE_DESCRIPTION("SMB1398 charger driver");
- MODULE_LICENSE("GPL");
|