12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218 |
- // SPDX-License-Identifier: GPL-2.0-only
- /*
- * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
- */
- #define pr_fmt(fmt) "flashv2: %s: " fmt, __func__
- #include <linux/module.h>
- #include <linux/init.h>
- #include <linux/kernel.h>
- #include <linux/errno.h>
- #include <linux/delay.h>
- #include <linux/slab.h>
- #include <linux/of.h>
- #include <linux/of_irq.h>
- #include <linux/of_gpio.h>
- #include <linux/of_device.h>
- #include <linux/gpio.h>
- #include <linux/regmap.h>
- #include <linux/power_supply.h>
- #include <linux/platform_device.h>
- #include <linux/interrupt.h>
- #include <linux/regulator/consumer.h>
- #include <linux/leds-qpnp-flash.h>
- #include <linux/leds-qpnp-flash-v2.h>
- #include <linux/iio/consumer.h>
- #include <linux/log2.h>
- #include "leds.h"
- #define FLASH_LED_REG_LED_STATUS1(base) (base + 0x08)
- #define FLASH_LED_REG_LED_STATUS2(base) (base + 0x09)
- #define FLASH_LED_VPH_DROOP_FAULT_MASK BIT(4)
- #define FLASH_LED_THERMAL_OTST_MASK GENMASK(2, 0)
- #define FLASH_LED_REG_INT_RT_STS(base) (base + 0x10)
- #define FLASH_LED_REG_SAFETY_TMR(base) (base + 0x40)
- #define FLASH_LED_SAFETY_TMR_ENABLE BIT(7)
- #define FLASH_LED_REG_TGR_CURRENT(base) (base + 0x43)
- #define FLASH_LED_REG_MOD_CTRL(base) (base + 0x46)
- #define FLASH_LED_MOD_CTRL_MASK BIT(7)
- #define FLASH_LED_MOD_ENABLE BIT(7)
- #define FLASH_LED_REG_IRES(base) (base + 0x47)
- #define FLASH_LED_REG_STROBE_CFG(base) (base + 0x48)
- #define FLASH_LED_STROBE_MASK GENMASK(1, 0)
- #define FLASH_LED_REG_STROBE_CTRL(base) (base + 0x49)
- #define FLASH_LED_HW_SW_STROBE_SEL_BIT BIT(2)
- #define FLASH_HW_STROBE_MASK GENMASK(2, 0)
- #define FLASH_LED_EN_LED_CTRL(base) (base + 0x4C)
- #define FLASH_LED_ENABLE BIT(0)
- #define FLASH_LED_REG_HDRM_PRGM(base) (base + 0x4D)
- #define FLASH_LED_HDRM_VOL_MASK GENMASK(7, 4)
- #define FLASH_LED_HDRM_VOL_SHIFT 4
- #define FLASH_LED_REG_HDRM_AUTO_MODE_CTRL(base) (base + 0x50)
- #define FLASH_LED_REG_WARMUP_DELAY(base) (base + 0x51)
- #define FLASH_LED_REG_ISC_DELAY(base) (base + 0x52)
- #define FLASH_LED_ISC_WARMUP_DELAY_MASK GENMASK(1, 0)
- #define FLASH_LED_ISC_WARMUP_DELAY_SHIFT 6
- #define FLASH_LED_REG_THERMAL_RMP_DN_RATE(base) (base + 0x55)
- #define THERMAL_OTST1_RAMP_CTRL_MASK BIT(7)
- #define THERMAL_OTST1_RAMP_CTRL_SHIFT 7
- #define THERMAL_DERATE_SLOW_SHIFT 4
- #define THERMAL_DERATE_SLOW_MASK GENMASK(6, 4)
- #define THERMAL_DERATE_FAST_MASK GENMASK(2, 0)
- #define FLASH_LED_REG_THERMAL_THRSH1(base) (base + 0x56)
- #define FLASH_LED_THERMAL_THRSH_MASK GENMASK(2, 0)
- #define FLASH_LED_REG_THERMAL_THRSH2(base) (base + 0x57)
- #define FLASH_LED_REG_THERMAL_THRSH3(base) (base + 0x58)
- #define FLASH_LED_REG_THERMAL_HYSTERESIS(base) (base + 0x59)
- #define FLASH_LED_THERMAL_HYSTERESIS_MASK GENMASK(1, 0)
- #define FLASH_LED_REG_THERMAL_DEBOUNCE(base) (base + 0x5A)
- #define FLASH_LED_THERMAL_DEBOUNCE_MASK GENMASK(1, 0)
- #define FLASH_LED_REG_RGLR_RAMP_RATE(base) (base + 0x5B)
- #define FLASH_LED_RAMP_UP_STEP_MASK GENMASK(6, 4)
- #define FLASH_LED_RAMP_UP_STEP_SHIFT 4
- #define FLASH_LED_RAMP_DOWN_STEP_MASK GENMASK(2, 0)
- #define FLASH_LED_RAMP_STEP_MIN_NS 200
- #define FLASH_LED_RAMP_STEP_MAX_NS 25600
- #define FLASH_LED_RAMP_STEP_DEFAULT_NS 6400
- #define FLASH_LED_REG_VPH_DROOP_THRESHOLD(base) (base + 0x61)
- #define FLASH_LED_VPH_DROOP_HYSTERESIS_MASK GENMASK(5, 4)
- #define FLASH_LED_VPH_DROOP_THRESHOLD_MASK GENMASK(2, 0)
- #define FLASH_LED_VPH_DROOP_HYST_SHIFT 4
- #define FLASH_LED_REG_VPH_DROOP_DEBOUNCE(base) (base + 0x62)
- #define FLASH_LED_VPH_DROOP_DEBOUNCE_MASK GENMASK(1, 0)
- #define FLASH_LED_REG_ILED_GRT_THRSH(base) (base + 0x67)
- #define FLASH_LED_ILED_GRT_THRSH_MASK GENMASK(5, 0)
- #define FLASH_LED_REG_LED1N2_ICLAMP_LOW(base) (base + 0x68)
- #define FLASH_LED_REG_LED1N2_ICLAMP_MID(base) (base + 0x69)
- #define FLASH_LED_REG_LED3_ICLAMP_LOW(base) (base + 0x6A)
- #define FLASH_LED_REG_LED3_ICLAMP_MID(base) (base + 0x6B)
- #define FLASH_LED_CURRENT_MASK GENMASK(6, 0)
- #define FLASH_LED_REG_MITIGATION_SEL(base) (base + 0x6E)
- #define FLASH_LED_CHGR_MITIGATION_SEL_MASK GENMASK(5, 4)
- #define FLASH_LED_LMH_MITIGATION_SEL_MASK GENMASK(1, 0)
- #define FLASH_LED_REG_MITIGATION_SW(base) (base + 0x6F)
- #define FLASH_LED_LMH_MITIGATION_EN_MASK BIT(0)
- #define FLASH_LED_CHGR_MITIGATION_EN_MASK BIT(4)
- #define FLASH_LED_CHGR_MITIGATION_ENABLE BIT(4)
- #define FLASH_LED_REG_LMH_LEVEL(base) (base + 0x70)
- #define FLASH_LED_LMH_LEVEL_MASK GENMASK(1, 0)
- #define FLASH_LED_REG_MULTI_STROBE_CTRL(base) (base + 0x71)
- #define LED3_FLASH_ONCE_ONLY_BIT BIT(1)
- #define LED1N2_FLASH_ONCE_ONLY_BIT BIT(0)
- #define FLASH_LED_REG_LPG_INPUT_CTRL(base) (base + 0x72)
- #define LPG_INPUT_SEL_BIT BIT(0)
- #define FLASH_LED_REG_CURRENT_DERATE_EN(base) (base + 0x76)
- #define FLASH_LED_CURRENT_DERATE_EN_MASK GENMASK(2, 0)
- #define VPH_DROOP_DEBOUNCE_US_TO_VAL(val_us) (val_us / 8)
- #define VPH_DROOP_HYST_MV_TO_VAL(val_mv) (val_mv / 25)
- #define VPH_DROOP_THRESH_VAL_TO_UV(val) ((val + 25) * 100000)
- #define MITIGATION_THRSH_MA_TO_VAL(val_ma) (val_ma / 100)
- #define THERMAL_HYST_TEMP_TO_VAL(val, divisor) (val / divisor)
- #define FLASH_LED_WARMUP_DELAY_DEFAULT 2
- #define FLASH_LED_ISC_DELAY_DEFAULT 3
- #define FLASH_LED_VPH_DROOP_DEBOUNCE_DEFAULT 2
- #define FLASH_LED_VPH_DROOP_HYST_DEFAULT 2
- #define FLASH_LED_VPH_DROOP_THRESH_DEFAULT 5
- #define BHARGER_FLASH_LED_VPH_DROOP_THRESH_DEFAULT 7
- #define FLASH_LED_DEBOUNCE_MAX 3
- #define FLASH_LED_HYSTERESIS_MAX 3
- #define FLASH_LED_VPH_DROOP_THRESH_MAX 7
- #define THERMAL_DERATE_SLOW_MAX 314592
- #define THERMAL_DERATE_FAST_MAX 512
- #define THERMAL_DEBOUNCE_TIME_MAX 64
- #define THERMAL_DERATE_HYSTERESIS_MAX 3
- #define FLASH_LED_THERMAL_THRSH_MIN 3
- #define FLASH_LED_THERMAL_THRSH_MAX 7
- #define FLASH_LED_THERMAL_OTST_LEVELS 3
- #define FLASH_LED_VLED_MAX_DEFAULT_UV 3500000
- #define FLASH_LED_IBATT_OCP_THRESH_DEFAULT_UA 4500000
- #define FLASH_LED_RPARA_DEFAULT_UOHM 0
- #define FLASH_LED_LMH_LEVEL_DEFAULT 0
- #define FLASH_LED_LMH_MITIGATION_ENABLE 1
- #define FLASH_LED_LMH_MITIGATION_DISABLE 0
- #define FLASH_LED_CHGR_MITIGATION_DISABLE 0
- #define FLASH_LED_LMH_MITIGATION_SEL_DEFAULT 2
- #define FLASH_LED_MITIGATION_SEL_MAX 2
- #define FLASH_LED_CHGR_MITIGATION_SEL_SHIFT 4
- #define FLASH_LED_CHGR_MITIGATION_THRSH_DEFAULT 0xA
- #define FLASH_LED_CHGR_MITIGATION_THRSH_MAX 0x1F
- #define FLASH_LED_LMH_OCV_THRESH_DEFAULT_UV 3700000
- #define FLASH_LED_LMH_RBATT_THRESH_DEFAULT_UOHM 400000
- #define FLASH_LED_IRES_BASE 3
- #define FLASH_LED_IRES_DIVISOR 2500
- #define FLASH_LED_IRES_MIN_UA 5000
- #define FLASH_LED_IRES_DEFAULT_UA 12500
- #define FLASH_LED_IRES_DEFAULT_VAL 0x00
- #define FLASH_LED_HDRM_VOL_DEFAULT_MV 0x80
- #define FLASH_LED_HDRM_VOL_HI_LO_WIN_DEFAULT_MV 0x04
- #define FLASH_LED_HDRM_VOL_BASE_MV 125
- #define FLASH_LED_HDRM_VOL_STEP_MV 25
- #define FLASH_LED_STROBE_CFG_DEFAULT 0x00
- #define FLASH_LED_HW_STROBE_OPTION_1 0x00
- #define FLASH_LED_HW_STROBE_OPTION_2 0x01
- #define FLASH_LED_HW_STROBE_OPTION_3 0x02
- #define FLASH_LED_DISABLE 0x00
- #define FLASH_LED_SAFETY_TMR_DISABLED 0x13
- #define FLASH_LED_MAX_TOTAL_CURRENT_MA 3750
- #define FLASH_LED_IRES5P0_MAX_CURR_MA 640
- #define FLASH_LED_IRES7P5_MAX_CURR_MA 960
- #define FLASH_LED_IRES10P0_MAX_CURR_MA 1280
- #define FLASH_LED_IRES12P5_MAX_CURR_MA 1600
- #define MAX_IRES_LEVELS 4
- #define FLASH_BST_PWM_OVRHD_MIN_UV 300000
- #define FLASH_BST_PWM_OVRHD_MAX_UV 600000
- /* notifier call chain for flash-led irqs */
- static ATOMIC_NOTIFIER_HEAD(irq_notifier_list);
- enum flash_charger_mitigation {
- FLASH_DISABLE_CHARGER_MITIGATION,
- FLASH_HW_CHARGER_MITIGATION_BY_ILED_THRSHLD,
- FLASH_SW_CHARGER_MITIGATION,
- };
- enum flash_led_type {
- FLASH_LED_TYPE_UNKNOWN,
- FLASH_LED_TYPE_FLASH,
- FLASH_LED_TYPE_TORCH,
- };
- enum {
- LED1 = 0,
- LED2,
- LED3,
- };
- enum pmic_type {
- PM6150L,
- PMI632,
- PM660L
- };
- enum strobe_type {
- SW_STROBE = 0,
- HW_STROBE,
- LPG_STROBE,
- };
- enum wa_flags {
- PM6150L_IRES_WA = BIT(0),
- };
- /*
- * Configurations for each individual LED
- */
- struct flash_node_data {
- struct platform_device *pdev;
- struct led_classdev cdev;
- struct pinctrl *strobe_pinctrl;
- struct pinctrl_state *hw_strobe_state_active;
- struct pinctrl_state *hw_strobe_state_suspend;
- int hw_strobe_gpio;
- int ires_ua;
- int default_ires_ua;
- int max_current;
- int current_ma;
- int prev_current_ma;
- u8 duration;
- u8 id;
- u8 ires_idx;
- u8 default_ires_idx;
- u8 hdrm_val;
- u8 current_reg_val;
- u8 strobe_ctrl;
- u8 strobe_sel;
- enum flash_led_type type;
- bool led_on;
- };
- struct flash_switch_data {
- struct platform_device *pdev;
- struct regulator *vreg;
- struct pinctrl *led_en_pinctrl;
- struct pinctrl_state *gpio_state_active;
- struct pinctrl_state *gpio_state_suspend;
- struct led_classdev cdev;
- int led_mask;
- bool regulator_on;
- bool enabled;
- bool symmetry_en;
- };
- /*
- * Flash LED configuration read from device tree
- */
- struct flash_led_platform_data {
- int *thermal_derate_current;
- int all_ramp_up_done_irq;
- int all_ramp_down_done_irq;
- int led_fault_irq;
- int ibatt_ocp_threshold_ua;
- int vled_max_uv;
- int rpara_uohm;
- int lmh_rbatt_threshold_uohm;
- int lmh_ocv_threshold_uv;
- int thermal_derate_slow;
- int thermal_derate_fast;
- int thermal_hysteresis;
- int thermal_debounce;
- int thermal_thrsh1;
- int thermal_thrsh2;
- int thermal_thrsh3;
- int ramp_up_step;
- int ramp_down_step;
- int hw_strobe_option;
- u32 led1n2_iclamp_low_ma;
- u32 led1n2_iclamp_mid_ma;
- u32 led3_iclamp_low_ma;
- u32 led3_iclamp_mid_ma;
- u32 bst_pwm_ovrhd_uv;
- u8 isc_delay;
- u8 warmup_delay;
- u8 current_derate_en_cfg;
- u8 vph_droop_threshold;
- u8 vph_droop_hysteresis;
- u8 vph_droop_debounce;
- u8 lmh_mitigation_sel;
- u8 chgr_mitigation_sel;
- u8 lmh_level;
- u8 iled_thrsh_val;
- bool hdrm_auto_mode_en;
- bool thermal_derate_en;
- bool otst_ramp_bkup_en;
- };
- enum flash_iio_props {
- RBATT,
- OCV,
- IBAT,
- F_TRIGGER,
- F_ACTIVE,
- };
- static char *flash_iio_prop_names[] = {
- [RBATT] = "rbatt",
- [OCV] = "voltage_ocv",
- [IBAT] = "current_now",
- [F_TRIGGER] = "flash_trigger",
- [F_ACTIVE] = "flash_active",
- };
- /*
- * Flash LED data structure containing flash LED attributes
- */
- struct qpnp_flash_led {
- struct flash_led_platform_data *pdata;
- struct platform_device *pdev;
- struct regmap *regmap;
- struct flash_node_data *fnode;
- struct flash_switch_data *snode;
- struct power_supply *usb_psy;
- struct iio_channel **iio_channels;
- struct notifier_block nb;
- spinlock_t lock;
- int num_fnodes;
- int num_snodes;
- int enable;
- int total_current_ma;
- int pmic_type;
- u32 wa_flags;
- u16 base;
- bool trigger_lmh;
- bool trigger_chgr;
- };
- static int thermal_derate_slow_table[] = {
- 128, 256, 512, 1024, 2048, 4096, 8192, 314592,
- };
- static int thermal_derate_fast_table[] = {
- 32, 64, 96, 128, 256, 384, 512,
- };
- static int otst1_threshold_table[] = {
- 85, 79, 73, 67, 109, 103, 97, 91,
- };
- static int otst2_threshold_table[] = {
- 110, 104, 98, 92, 134, 128, 122, 116,
- };
- static int otst3_threshold_table[] = {
- 125, 119, 113, 107, 149, 143, 137, 131,
- };
- static int max_ires_curr_ma_table[MAX_IRES_LEVELS] = {
- FLASH_LED_IRES12P5_MAX_CURR_MA, FLASH_LED_IRES10P0_MAX_CURR_MA,
- FLASH_LED_IRES7P5_MAX_CURR_MA, FLASH_LED_IRES5P0_MAX_CURR_MA
- };
- static inline int get_current_reg_code(int target_curr_ma, int ires_ua)
- {
- if (!ires_ua || !target_curr_ma || (target_curr_ma < (ires_ua / 1000)))
- return 0;
- return DIV_ROUND_CLOSEST(target_curr_ma * 1000, ires_ua) - 1;
- }
- static int qpnp_flash_led_read(struct qpnp_flash_led *led, u16 addr, u8 *data)
- {
- int rc;
- uint val;
- rc = regmap_read(led->regmap, addr, &val);
- if (rc < 0) {
- pr_err("Unable to read from 0x%04X rc = %d\n", addr, rc);
- return rc;
- }
- pr_debug("Read 0x%02X from addr 0x%04X\n", val, addr);
- *data = (u8)val;
- return 0;
- }
- static int qpnp_flash_led_write(struct qpnp_flash_led *led, u16 addr, u8 data)
- {
- int rc;
- rc = regmap_write(led->regmap, addr, data);
- if (rc < 0) {
- pr_err("Unable to write to 0x%04X rc = %d\n", addr, rc);
- return rc;
- }
- pr_debug("Wrote 0x%02X to addr 0x%04X\n", data, addr);
- return 0;
- }
- static int
- qpnp_flash_led_masked_read(struct qpnp_flash_led *led, u16 addr, u8 mask,
- u8 *val)
- {
- int rc;
- rc = qpnp_flash_led_read(led, addr, val);
- if (rc < 0)
- return rc;
- *val &= mask;
- return rc;
- }
- static int
- qpnp_flash_led_masked_write(struct qpnp_flash_led *led, u16 addr, u8 mask,
- u8 val)
- {
- int rc;
- rc = regmap_update_bits(led->regmap, addr, mask, val);
- if (rc < 0)
- pr_err("Unable to update bits from 0x%04X, rc = %d\n", addr,
- rc);
- else
- pr_debug("Wrote 0x%02X to addr 0x%04X\n", val, addr);
- return rc;
- }
- static enum
- led_brightness qpnp_flash_led_brightness_get(struct led_classdev *led_cdev)
- {
- return led_cdev->brightness;
- }
- static int qpnp_flash_led_headroom_config(struct qpnp_flash_led *led)
- {
- int rc, i, addr_offset;
- for (i = 0; i < led->num_fnodes; i++) {
- addr_offset = led->fnode[i].id;
- rc = qpnp_flash_led_write(led,
- FLASH_LED_REG_HDRM_PRGM(led->base + addr_offset),
- led->fnode[i].hdrm_val);
- if (rc < 0)
- return rc;
- }
- return rc;
- }
- static int qpnp_flash_led_safety_tmr_config(struct qpnp_flash_led *led)
- {
- int rc = 0, i, addr_offset;
- for (i = 0; i < led->num_fnodes; i++) {
- addr_offset = led->fnode[i].id;
- rc = qpnp_flash_led_write(led,
- FLASH_LED_REG_SAFETY_TMR(led->base + addr_offset),
- FLASH_LED_SAFETY_TMR_DISABLED);
- if (rc < 0)
- return rc;
- }
- return rc;
- }
- static int qpnp_flash_led_strobe_config(struct qpnp_flash_led *led)
- {
- int i, rc, addr_offset;
- u8 val = 0, mask, strobe_mask = 0, strobe_ctrl;
- for (i = 0; i < led->num_fnodes; i++) {
- val |= 0x1 << led->fnode[i].id;
- if (led->fnode[i].strobe_sel == HW_STROBE) {
- if (led->fnode[i].id == LED3)
- strobe_mask |= LED3_FLASH_ONCE_ONLY_BIT;
- else
- strobe_mask |= LED1N2_FLASH_ONCE_ONLY_BIT;
- }
- if (led->fnode[i].id == LED3 &&
- led->fnode[i].strobe_sel == LPG_STROBE)
- strobe_mask |= LED3_FLASH_ONCE_ONLY_BIT;
- /*
- * As per the hardware recommendation, to use LED2/LED3 in HW
- * strobe mode, LED1 should be set to HW strobe mode as well.
- */
- if (led->fnode[i].strobe_sel == HW_STROBE &&
- (led->fnode[i].id == LED2 || led->fnode[i].id == LED3)) {
- mask = FLASH_HW_STROBE_MASK;
- addr_offset = led->fnode[LED1].id;
- /*
- * HW_STROBE: enable, TRIGGER: level,
- * POLARITY: active high
- */
- strobe_ctrl = BIT(2) | BIT(0);
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_STROBE_CTRL(
- led->base + addr_offset),
- mask, strobe_ctrl);
- if (rc < 0)
- return rc;
- }
- }
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_MULTI_STROBE_CTRL(led->base),
- strobe_mask, 0);
- if (rc < 0)
- return rc;
- if (led->fnode[LED3].strobe_sel == LPG_STROBE) {
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_LPG_INPUT_CTRL(led->base),
- LPG_INPUT_SEL_BIT, LPG_INPUT_SEL_BIT);
- if (rc < 0)
- return rc;
- }
- return rc;
- }
- static int qpnp_flash_led_thermal_config(struct qpnp_flash_led *led)
- {
- int rc;
- u8 val, mask;
- val = (led->pdata->otst_ramp_bkup_en << THERMAL_OTST1_RAMP_CTRL_SHIFT);
- mask = THERMAL_OTST1_RAMP_CTRL_MASK;
- if (led->pdata->thermal_derate_slow >= 0) {
- val |= (led->pdata->thermal_derate_slow <<
- THERMAL_DERATE_SLOW_SHIFT);
- mask |= THERMAL_DERATE_SLOW_MASK;
- }
- if (led->pdata->thermal_derate_fast >= 0) {
- val |= led->pdata->thermal_derate_fast;
- mask |= THERMAL_DERATE_FAST_MASK;
- }
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_THERMAL_RMP_DN_RATE(led->base),
- mask, val);
- if (rc < 0)
- return rc;
- if (led->pdata->thermal_debounce >= 0) {
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_THERMAL_DEBOUNCE(led->base),
- FLASH_LED_THERMAL_DEBOUNCE_MASK,
- led->pdata->thermal_debounce);
- if (rc < 0)
- return rc;
- }
- if (led->pdata->thermal_hysteresis >= 0) {
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_THERMAL_HYSTERESIS(led->base),
- FLASH_LED_THERMAL_HYSTERESIS_MASK,
- led->pdata->thermal_hysteresis);
- if (rc < 0)
- return rc;
- }
- if (led->pdata->thermal_thrsh1 >= 0) {
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_THERMAL_THRSH1(led->base),
- FLASH_LED_THERMAL_THRSH_MASK,
- led->pdata->thermal_thrsh1);
- if (rc < 0)
- return rc;
- }
- if (led->pdata->thermal_thrsh2 >= 0) {
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_THERMAL_THRSH2(led->base),
- FLASH_LED_THERMAL_THRSH_MASK,
- led->pdata->thermal_thrsh2);
- if (rc < 0)
- return rc;
- }
- if (led->pdata->thermal_thrsh3 >= 0) {
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_THERMAL_THRSH3(led->base),
- FLASH_LED_THERMAL_THRSH_MASK,
- led->pdata->thermal_thrsh3);
- if (rc < 0)
- return rc;
- }
- return rc;
- }
- static int qpnp_flash_led_init_settings(struct qpnp_flash_led *led)
- {
- int rc;
- u8 val = 0;
- rc = qpnp_flash_led_headroom_config(led);
- if (rc < 0)
- return rc;
- rc = qpnp_flash_led_safety_tmr_config(led);
- if (rc < 0)
- return rc;
- rc = qpnp_flash_led_strobe_config(led);
- if (rc < 0)
- return rc;
- rc = qpnp_flash_led_write(led,
- FLASH_LED_REG_HDRM_AUTO_MODE_CTRL(led->base),
- val);
- if (rc < 0)
- return rc;
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_ISC_DELAY(led->base),
- FLASH_LED_ISC_WARMUP_DELAY_MASK,
- led->pdata->isc_delay);
- if (rc < 0)
- return rc;
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_WARMUP_DELAY(led->base),
- FLASH_LED_ISC_WARMUP_DELAY_MASK,
- led->pdata->warmup_delay);
- if (rc < 0)
- return rc;
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_CURRENT_DERATE_EN(led->base),
- FLASH_LED_CURRENT_DERATE_EN_MASK,
- led->pdata->current_derate_en_cfg);
- if (rc < 0)
- return rc;
- rc = qpnp_flash_led_thermal_config(led);
- if (rc < 0)
- return rc;
- val = led->pdata->ramp_up_step << FLASH_LED_RAMP_UP_STEP_SHIFT;
- val |= led->pdata->ramp_down_step;
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_RGLR_RAMP_RATE(led->base),
- FLASH_LED_RAMP_UP_STEP_MASK | FLASH_LED_RAMP_DOWN_STEP_MASK,
- val);
- if (rc < 0)
- return rc;
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_VPH_DROOP_DEBOUNCE(led->base),
- FLASH_LED_VPH_DROOP_DEBOUNCE_MASK,
- led->pdata->vph_droop_debounce);
- if (rc < 0)
- return rc;
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_VPH_DROOP_THRESHOLD(led->base),
- FLASH_LED_VPH_DROOP_THRESHOLD_MASK,
- led->pdata->vph_droop_threshold);
- if (rc < 0)
- return rc;
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_VPH_DROOP_THRESHOLD(led->base),
- FLASH_LED_VPH_DROOP_HYSTERESIS_MASK,
- led->pdata->vph_droop_hysteresis);
- if (rc < 0)
- return rc;
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_MITIGATION_SEL(led->base),
- FLASH_LED_LMH_MITIGATION_SEL_MASK,
- led->pdata->lmh_mitigation_sel);
- if (rc < 0)
- return rc;
- val = led->pdata->chgr_mitigation_sel
- << FLASH_LED_CHGR_MITIGATION_SEL_SHIFT;
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_MITIGATION_SEL(led->base),
- FLASH_LED_CHGR_MITIGATION_SEL_MASK,
- val);
- if (rc < 0)
- return rc;
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_LMH_LEVEL(led->base),
- FLASH_LED_LMH_LEVEL_MASK,
- led->pdata->lmh_level);
- if (rc < 0)
- return rc;
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_ILED_GRT_THRSH(led->base),
- FLASH_LED_ILED_GRT_THRSH_MASK,
- led->pdata->iled_thrsh_val);
- if (rc < 0)
- return rc;
- if (led->pdata->led1n2_iclamp_low_ma) {
- val = get_current_reg_code(led->pdata->led1n2_iclamp_low_ma,
- led->fnode[LED1].ires_ua);
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_LED1N2_ICLAMP_LOW(led->base),
- FLASH_LED_CURRENT_MASK, val);
- if (rc < 0)
- return rc;
- }
- if (led->pdata->led1n2_iclamp_mid_ma) {
- val = get_current_reg_code(led->pdata->led1n2_iclamp_mid_ma,
- led->fnode[LED1].ires_ua);
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_LED1N2_ICLAMP_MID(led->base),
- FLASH_LED_CURRENT_MASK, val);
- if (rc < 0)
- return rc;
- }
- if (led->pdata->led3_iclamp_low_ma) {
- val = get_current_reg_code(led->pdata->led3_iclamp_low_ma,
- led->fnode[LED3].ires_ua);
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_LED3_ICLAMP_LOW(led->base),
- FLASH_LED_CURRENT_MASK, val);
- if (rc < 0)
- return rc;
- }
- if (led->pdata->led3_iclamp_mid_ma) {
- val = get_current_reg_code(led->pdata->led3_iclamp_mid_ma,
- led->fnode[LED3].ires_ua);
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_LED3_ICLAMP_MID(led->base),
- FLASH_LED_CURRENT_MASK, val);
- if (rc < 0)
- return rc;
- }
- if (led->pdata->hw_strobe_option > 0) {
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_STROBE_CFG(led->base),
- FLASH_LED_STROBE_MASK,
- led->pdata->hw_strobe_option);
- if (rc < 0)
- return rc;
- }
- return 0;
- }
- static int qpnp_flash_led_hw_strobe_enable(struct flash_node_data *fnode,
- int hw_strobe_option, bool on)
- {
- int rc = 0;
- /*
- * If the LED controlled by this fnode is not GPIO controlled
- * for the given strobe_option, return.
- */
- if (hw_strobe_option == FLASH_LED_HW_STROBE_OPTION_1)
- return 0;
- else if (hw_strobe_option == FLASH_LED_HW_STROBE_OPTION_2
- && fnode->id != LED3)
- return 0;
- else if (hw_strobe_option == FLASH_LED_HW_STROBE_OPTION_3
- && fnode->id == LED1)
- return 0;
- if (gpio_is_valid(fnode->hw_strobe_gpio)) {
- gpio_set_value(fnode->hw_strobe_gpio, on ? 1 : 0);
- } else if (fnode->strobe_pinctrl && fnode->hw_strobe_state_active &&
- fnode->hw_strobe_state_suspend) {
- rc = pinctrl_select_state(fnode->strobe_pinctrl,
- on ? fnode->hw_strobe_state_active :
- fnode->hw_strobe_state_suspend);
- if (rc < 0) {
- pr_err("failed to change hw strobe pin state\n");
- return rc;
- }
- }
- return rc;
- }
- static int qpnp_flash_led_regulator_enable(struct qpnp_flash_led *led,
- struct flash_switch_data *snode, bool on)
- {
- int rc = 0;
- if (!snode || !snode->vreg)
- return 0;
- if (snode->regulator_on == on)
- return 0;
- if (on)
- rc = regulator_enable(snode->vreg);
- else
- rc = regulator_disable(snode->vreg);
- if (rc < 0) {
- pr_err("regulator_%s failed, rc=%d\n",
- on ? "enable" : "disable", rc);
- return rc;
- }
- snode->regulator_on = on ? true : false;
- return 0;
- }
- static int qpnp_flash_get_iio_chan(struct qpnp_flash_led *led,
- enum flash_iio_props chan)
- {
- int rc = 0;
- /*
- * if the channel pointer is not-NULL and has a ERR value it has
- * already been queried upon earlier, hence return from here.
- */
- if (IS_ERR(led->iio_channels[chan]))
- return -EINVAL;
- if (!led->iio_channels[chan]) {
- led->iio_channels[chan] = devm_iio_channel_get(&led->pdev->dev,
- flash_iio_prop_names[chan]);
- if (IS_ERR(led->iio_channels[chan])) {
- rc = PTR_ERR(led->iio_channels[chan]);
- if (rc == -EPROBE_DEFER) {
- led->iio_channels[chan] = NULL;
- return rc;
- }
- pr_err("%s channel unavailable %d\n",
- flash_iio_prop_names[chan], rc);
- return rc;
- }
- }
- return 0;
- }
- static int qpnp_flash_iio_getprop(struct qpnp_flash_led *led,
- enum flash_iio_props chan, int *data)
- {
- int rc = 0;
- rc = qpnp_flash_get_iio_chan(led, chan);
- if (rc < 0)
- return rc;
- rc = iio_read_channel_processed(led->iio_channels[chan], data);
- if (rc < 0)
- pr_err("Error in reading IIO channel data rc = %d\n", rc);
- return rc;
- }
- static int qpnp_flash_iio_setprop(struct qpnp_flash_led *led,
- enum flash_iio_props chan, int data)
- {
- int rc = 0;
- rc = qpnp_flash_get_iio_chan(led, chan);
- if (rc < 0)
- return rc;
- rc = iio_write_channel_raw(led->iio_channels[chan], data);
- if (rc < 0)
- pr_err("Error in writing IIO channel data rc = %d\n", rc);
- return rc;
- }
- #define VOLTAGE_HDRM_DEFAULT_MV 350
- #define BHARGER_VOLTAGE_HDRM_DEFAULT_MV 400
- #define BHARGER_HEADROOM_OFFSET_MV 50
- static int qpnp_flash_led_get_voltage_headroom(struct qpnp_flash_led *led)
- {
- int i, voltage_hdrm_mv = 0, voltage_hdrm_max = 0;
- for (i = 0; i < led->num_fnodes; i++) {
- if (led->fnode[i].led_on) {
- if (led->fnode[i].id < 2) {
- if (led->fnode[i].current_ma < 750)
- voltage_hdrm_mv = 125;
- else if (led->fnode[i].current_ma < 1000)
- voltage_hdrm_mv = 175;
- else if (led->fnode[i].current_ma < 1250)
- voltage_hdrm_mv = 250;
- else
- voltage_hdrm_mv = 350;
- } else {
- if (led->fnode[i].current_ma < 375)
- voltage_hdrm_mv = 125;
- else if (led->fnode[i].current_ma < 500)
- voltage_hdrm_mv = 175;
- else if (led->fnode[i].current_ma < 625)
- voltage_hdrm_mv = 250;
- else
- voltage_hdrm_mv = 350;
- }
- if (led->pmic_type == PMI632)
- voltage_hdrm_mv += BHARGER_HEADROOM_OFFSET_MV;
- voltage_hdrm_max = max(voltage_hdrm_max,
- voltage_hdrm_mv);
- }
- }
- if (!voltage_hdrm_max)
- return (led->pmic_type == PMI632) ?
- BHARGER_VOLTAGE_HDRM_DEFAULT_MV :
- VOLTAGE_HDRM_DEFAULT_MV;
- return voltage_hdrm_max;
- }
- #define UCONV 1000000LL
- #define MCONV 1000LL
- #define FLASH_VDIP_MARGIN 50000
- #define BOB_EFFICIENCY 900LL
- #define VIN_FLASH_MIN_UV 3300000LL
- static int qpnp_flash_led_calc_max_current(struct qpnp_flash_led *led,
- int *max_current)
- {
- int ocv_uv, ibat_now, voltage_hdrm_mv, rc;
- int rbatt_uohm = 0;
- int64_t ibat_flash_ua, avail_flash_ua, avail_flash_power_fw;
- int64_t ibat_safe_ua, vin_flash_uv, vph_flash_uv, vph_flash_vdip;
- /* RESISTANCE = esr_uohm + rslow_uohm */
- rc = qpnp_flash_iio_getprop(led, RBATT, &rbatt_uohm);
- /* Do not return error if the QG driver is not probed */
- if (rc == -EPROBE_DEFER) {
- *max_current = FLASH_LED_MAX_TOTAL_CURRENT_MA;
- return 0;
- } else if (rc < 0) {
- pr_err("Unable to read battery resistance, rc=%d\n", rc);
- return rc;
- }
- /* If no battery is connected, return max possible flash current */
- if (!rbatt_uohm) {
- *max_current = FLASH_LED_MAX_TOTAL_CURRENT_MA;
- return 0;
- }
- rc = qpnp_flash_iio_getprop(led, OCV, &ocv_uv);
- if (rc < 0) {
- pr_err("Unable to read OCV, rc=%d\n", rc);
- return rc;
- }
- rc = qpnp_flash_iio_getprop(led, IBAT, &ibat_now);
- if (rc < 0) {
- pr_err("unable to read current_now, rc=%d\n", rc);
- return rc;
- }
- rbatt_uohm += led->pdata->rpara_uohm;
- voltage_hdrm_mv = qpnp_flash_led_get_voltage_headroom(led);
- vph_flash_vdip =
- VPH_DROOP_THRESH_VAL_TO_UV(led->pdata->vph_droop_threshold)
- + FLASH_VDIP_MARGIN;
- /* Check if LMH_MITIGATION needs to be triggered */
- if (!led->trigger_lmh && (ocv_uv < led->pdata->lmh_ocv_threshold_uv ||
- rbatt_uohm > led->pdata->lmh_rbatt_threshold_uohm)) {
- led->trigger_lmh = true;
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_MITIGATION_SW(led->base),
- FLASH_LED_LMH_MITIGATION_EN_MASK,
- FLASH_LED_LMH_MITIGATION_ENABLE);
- if (rc < 0) {
- pr_err("trigger lmh mitigation failed, rc=%d\n", rc);
- return rc;
- }
- /* Wait for LMH mitigation to take effect */
- udelay(100);
- return qpnp_flash_led_calc_max_current(led, max_current);
- }
- /*
- * Calculate the maximum current that can pulled out of the battery
- * before the battery voltage dips below a safe threshold.
- */
- ibat_safe_ua = div_s64((ocv_uv - vph_flash_vdip) * UCONV,
- rbatt_uohm);
- if (ibat_safe_ua <= led->pdata->ibatt_ocp_threshold_ua) {
- /*
- * If the calculated current is below the OCP threshold, then
- * use it as the possible flash current.
- */
- ibat_flash_ua = ibat_safe_ua - ibat_now;
- vph_flash_uv = vph_flash_vdip;
- } else {
- /*
- * If the calculated current is above the OCP threshold, then
- * use the ocp threshold instead.
- *
- * Any higher current will be tripping the battery OCP.
- */
- ibat_flash_ua = led->pdata->ibatt_ocp_threshold_ua - ibat_now;
- vph_flash_uv = ocv_uv - div64_s64((int64_t)rbatt_uohm
- * led->pdata->ibatt_ocp_threshold_ua, UCONV);
- }
- /* Calculate the input voltage of the flash module. */
- vin_flash_uv = max((led->pdata->vled_max_uv +
- (voltage_hdrm_mv * MCONV)), VIN_FLASH_MIN_UV);
- /* Calculate the available power for the flash module. */
- avail_flash_power_fw = BOB_EFFICIENCY * vph_flash_uv * ibat_flash_ua;
- /*
- * Calculate the available amount of current the flash module can draw
- * before collapsing the battery. (available power/ flash input voltage)
- */
- avail_flash_ua = div64_s64(avail_flash_power_fw, vin_flash_uv * MCONV);
- pr_debug("avail_iflash=%lld, ocv=%d, ibat=%d, rbatt=%d, trigger_lmh=%d\n",
- avail_flash_ua, ocv_uv, ibat_now, rbatt_uohm, led->trigger_lmh);
- *max_current = min(FLASH_LED_MAX_TOTAL_CURRENT_MA,
- (int)(div64_s64(avail_flash_ua, MCONV)));
- return 0;
- }
- static int is_usb_psy_available(struct qpnp_flash_led *led)
- {
- if (!led->usb_psy) {
- led->usb_psy = power_supply_get_by_name("usb");
- if (!led->usb_psy) {
- pr_err_ratelimited("Couldn't get usb_psy\n");
- return -ENODEV;
- }
- }
- return 0;
- }
- #define CHGBST_EFFICIENCY 800LL
- #define CHGBST_FLASH_VDIP_MARGIN 10000
- #define VIN_FLASH_UV 5000000
- #define BHARGER_FLASH_LED_MAX_TOTAL_CURRENT_MA 1500
- #define BHARGER_FLASH_LED_WITH_OTG_MAX_TOTAL_CURRENT_MA 1100
- static int qpnp_flash_led_calc_bharger_max_current(struct qpnp_flash_led *led,
- int *max_current)
- {
- union power_supply_propval pval = {0, };
- int ocv_uv, ibat_now, voltage_hdrm_mv, flash_led_max_total_curr_ma, rc;
- int rbatt_uohm = 0, usb_present, otg_enable;
- int64_t ibat_flash_ua, avail_flash_ua, avail_flash_power_fw;
- int64_t ibat_safe_ua, vin_flash_uv, vph_flash_uv, vph_flash_vdip;
- int64_t bst_pwm_ovrhd_uv;
- rc = is_usb_psy_available(led);
- if (rc < 0)
- return rc;
- rc = power_supply_get_property(led->usb_psy, POWER_SUPPLY_PROP_SCOPE,
- &pval);
- if (rc < 0) {
- pr_err("usb psy does not support usb present, rc=%d\n", rc);
- return rc;
- }
- otg_enable = pval.intval;
- /* RESISTANCE = esr_uohm + rslow_uohm */
- rc = qpnp_flash_iio_getprop(led, RBATT, &rbatt_uohm);
- /* Do not return error if the QG driver is not probed */
- if (rc == -EPROBE_DEFER) {
- *max_current = FLASH_LED_MAX_TOTAL_CURRENT_MA;
- return 0;
- } else if (rc < 0) {
- pr_err("Unable to read battery resistance, rc=%d\n", rc);
- return rc;
- }
- /* If no battery is connected, return max possible flash current */
- if (!rbatt_uohm) {
- *max_current = (otg_enable == POWER_SUPPLY_SCOPE_SYSTEM) ?
- BHARGER_FLASH_LED_WITH_OTG_MAX_TOTAL_CURRENT_MA :
- BHARGER_FLASH_LED_MAX_TOTAL_CURRENT_MA;
- return 0;
- }
- rc = qpnp_flash_iio_getprop(led, OCV, &ocv_uv);
- if (rc < 0) {
- pr_err("Unable to read OCV, rc=%d\n", rc);
- return rc;
- }
- rc = qpnp_flash_iio_getprop(led, IBAT, &ibat_now);
- if (rc < 0) {
- pr_err("Unable to read current, rc=%d\n", rc);
- return rc;
- }
- bst_pwm_ovrhd_uv = led->pdata->bst_pwm_ovrhd_uv;
- rc = power_supply_get_property(led->usb_psy, POWER_SUPPLY_PROP_PRESENT,
- &pval);
- if (rc < 0) {
- pr_err("usb psy does not support usb present, rc=%d\n", rc);
- return rc;
- }
- usb_present = pval.intval;
- rbatt_uohm += led->pdata->rpara_uohm;
- voltage_hdrm_mv = qpnp_flash_led_get_voltage_headroom(led);
- vph_flash_vdip =
- VPH_DROOP_THRESH_VAL_TO_UV(led->pdata->vph_droop_threshold)
- + CHGBST_FLASH_VDIP_MARGIN;
- /* Check if LMH_MITIGATION needs to be triggered */
- if (!led->trigger_lmh && (ocv_uv < led->pdata->lmh_ocv_threshold_uv ||
- rbatt_uohm > led->pdata->lmh_rbatt_threshold_uohm)) {
- led->trigger_lmh = true;
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_MITIGATION_SW(led->base),
- FLASH_LED_LMH_MITIGATION_EN_MASK,
- FLASH_LED_LMH_MITIGATION_ENABLE);
- if (rc < 0) {
- pr_err("trigger lmh mitigation failed, rc=%d\n", rc);
- return rc;
- }
- /* Wait for LMH mitigation to take effect */
- udelay(100);
- return qpnp_flash_led_calc_bharger_max_current(led,
- max_current);
- }
- /*
- * Calculate the maximum current that can pulled out of the battery
- * before the battery voltage dips below a safe threshold.
- */
- ibat_safe_ua = div_s64((ocv_uv - vph_flash_vdip) * UCONV,
- rbatt_uohm);
- if (ibat_safe_ua <= led->pdata->ibatt_ocp_threshold_ua) {
- /*
- * If the calculated current is below the OCP threshold, then
- * use it as the possible flash current.
- */
- ibat_flash_ua = ibat_safe_ua - ibat_now;
- vph_flash_uv = vph_flash_vdip;
- } else {
- /*
- * If the calculated current is above the OCP threshold, then
- * use the ocp threshold instead.
- *
- * Any higher current will be tripping the battery OCP.
- */
- ibat_flash_ua = led->pdata->ibatt_ocp_threshold_ua - ibat_now;
- vph_flash_uv = ocv_uv - div64_s64((int64_t)rbatt_uohm
- * led->pdata->ibatt_ocp_threshold_ua, UCONV);
- }
- /* when USB is present or OTG is enabled, VIN_FLASH is always at 5V */
- if (usb_present || (otg_enable == POWER_SUPPLY_SCOPE_SYSTEM))
- vin_flash_uv = VIN_FLASH_UV;
- else
- /* Calculate the input voltage of the flash module. */
- vin_flash_uv = max((led->pdata->vled_max_uv +
- (voltage_hdrm_mv * MCONV)),
- vph_flash_uv + bst_pwm_ovrhd_uv);
- /* Calculate the available power for the flash module. */
- avail_flash_power_fw = CHGBST_EFFICIENCY * vph_flash_uv * ibat_flash_ua;
- /*
- * Calculate the available amount of current the flash module can draw
- * before collapsing the battery. (available power/ flash input voltage)
- */
- avail_flash_ua = div64_s64(avail_flash_power_fw, vin_flash_uv * MCONV);
- flash_led_max_total_curr_ma = otg_enable ?
- BHARGER_FLASH_LED_WITH_OTG_MAX_TOTAL_CURRENT_MA :
- BHARGER_FLASH_LED_MAX_TOTAL_CURRENT_MA;
- *max_current = min(flash_led_max_total_curr_ma,
- (int)(div64_s64(avail_flash_ua, MCONV)));
- pr_debug("avail_iflash=%lld, ocv=%d, ibat=%d, rbatt=%d, trigger_lmh=%d max_current=%lld usb_present=%d otg_enable=%d\n",
- avail_flash_ua, ocv_uv, ibat_now, rbatt_uohm, led->trigger_lmh,
- (*max_current * MCONV), usb_present, otg_enable);
- return 0;
- }
- static int qpnp_flash_led_calc_thermal_current_lim(struct qpnp_flash_led *led,
- int *thermal_current_lim)
- {
- int rc;
- u8 thermal_thrsh1, thermal_thrsh2, thermal_thrsh3, otst_status;
- /* Store THERMAL_THRSHx register values */
- rc = qpnp_flash_led_masked_read(led,
- FLASH_LED_REG_THERMAL_THRSH1(led->base),
- FLASH_LED_THERMAL_THRSH_MASK,
- &thermal_thrsh1);
- if (rc < 0)
- return rc;
- rc = qpnp_flash_led_masked_read(led,
- FLASH_LED_REG_THERMAL_THRSH2(led->base),
- FLASH_LED_THERMAL_THRSH_MASK,
- &thermal_thrsh2);
- if (rc < 0)
- return rc;
- rc = qpnp_flash_led_masked_read(led,
- FLASH_LED_REG_THERMAL_THRSH3(led->base),
- FLASH_LED_THERMAL_THRSH_MASK,
- &thermal_thrsh3);
- if (rc < 0)
- return rc;
- /* Lower THERMAL_THRSHx thresholds to minimum */
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_THERMAL_THRSH1(led->base),
- FLASH_LED_THERMAL_THRSH_MASK,
- FLASH_LED_THERMAL_THRSH_MIN);
- if (rc < 0)
- return rc;
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_THERMAL_THRSH2(led->base),
- FLASH_LED_THERMAL_THRSH_MASK,
- FLASH_LED_THERMAL_THRSH_MIN);
- if (rc < 0)
- return rc;
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_THERMAL_THRSH3(led->base),
- FLASH_LED_THERMAL_THRSH_MASK,
- FLASH_LED_THERMAL_THRSH_MIN);
- if (rc < 0)
- return rc;
- /* Check THERMAL_OTST status */
- rc = qpnp_flash_led_read(led,
- FLASH_LED_REG_LED_STATUS2(led->base),
- &otst_status);
- if (rc < 0)
- return rc;
- otst_status &= FLASH_LED_THERMAL_OTST_MASK;
- /* Look up current limit based on THERMAL_OTST status */
- if (otst_status)
- *thermal_current_lim =
- led->pdata->thermal_derate_current[otst_status >> 1];
- /* Restore THERMAL_THRESHx registers to original values */
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_THERMAL_THRSH1(led->base),
- FLASH_LED_THERMAL_THRSH_MASK,
- thermal_thrsh1);
- if (rc < 0)
- return rc;
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_THERMAL_THRSH2(led->base),
- FLASH_LED_THERMAL_THRSH_MASK,
- thermal_thrsh2);
- if (rc < 0)
- return rc;
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_THERMAL_THRSH3(led->base),
- FLASH_LED_THERMAL_THRSH_MASK,
- thermal_thrsh3);
- if (rc < 0)
- return rc;
- return 0;
- }
- static int qpnp_flash_led_get_max_avail_current(struct qpnp_flash_led *led,
- int *max_avail_current)
- {
- int thermal_current_lim = 0, rc;
- led->trigger_lmh = false;
- if (led->pmic_type == PMI632)
- rc = qpnp_flash_led_calc_bharger_max_current(led,
- max_avail_current);
- else
- rc = qpnp_flash_led_calc_max_current(led, max_avail_current);
- if (rc < 0) {
- pr_err("Couldn't calculate max_avail_current, rc=%d\n", rc);
- return rc;
- }
- if (led->pdata->thermal_derate_en) {
- rc = qpnp_flash_led_calc_thermal_current_lim(led,
- &thermal_current_lim);
- if (rc < 0) {
- pr_err("Couldn't calculate thermal_current_lim, rc=%d\n",
- rc);
- return rc;
- }
- }
- if (thermal_current_lim)
- *max_avail_current = min(*max_avail_current,
- thermal_current_lim);
- return 0;
- }
- static void qpnp_flash_led_aggregate_max_current(struct flash_node_data *fnode)
- {
- struct qpnp_flash_led *led = dev_get_drvdata(&fnode->pdev->dev);
- if (fnode->current_ma)
- led->total_current_ma += fnode->current_ma
- - fnode->prev_current_ma;
- else
- led->total_current_ma -= fnode->prev_current_ma;
- fnode->prev_current_ma = fnode->current_ma;
- }
- static void qpnp_flash_led_node_set(struct flash_node_data *fnode, int value)
- {
- int i = 0;
- int prgm_current_ma = value;
- int min_ma = fnode->ires_ua / 1000;
- struct qpnp_flash_led *led = dev_get_drvdata(&fnode->pdev->dev);
- if (value <= 0)
- prgm_current_ma = 0;
- else if (value < min_ma)
- prgm_current_ma = min_ma;
- fnode->ires_idx = fnode->default_ires_idx;
- fnode->ires_ua = fnode->default_ires_ua;
- prgm_current_ma = min(prgm_current_ma, fnode->max_current);
- if (prgm_current_ma > max_ires_curr_ma_table[fnode->ires_idx]) {
- /* find the matching ires */
- for (i = MAX_IRES_LEVELS - 1; i >= 0; i--) {
- if (prgm_current_ma <= max_ires_curr_ma_table[i]) {
- fnode->ires_idx = i;
- fnode->ires_ua = FLASH_LED_IRES_MIN_UA +
- (FLASH_LED_IRES_BASE - fnode->ires_idx) *
- FLASH_LED_IRES_DIVISOR;
- break;
- }
- }
- } else if (prgm_current_ma <= 20 &&
- (led->wa_flags & PM6150L_IRES_WA)) {
- fnode->ires_idx = FLASH_LED_IRES_BASE;
- fnode->ires_ua = FLASH_LED_IRES_MIN_UA;
- }
- fnode->current_ma = prgm_current_ma;
- fnode->cdev.brightness = prgm_current_ma;
- fnode->current_reg_val = get_current_reg_code(prgm_current_ma,
- fnode->ires_ua);
- if (prgm_current_ma)
- fnode->led_on = true;
- if (led->pmic_type != PMI632 &&
- led->pdata->chgr_mitigation_sel == FLASH_SW_CHARGER_MITIGATION) {
- qpnp_flash_led_aggregate_max_current(fnode);
- led->trigger_chgr = false;
- if (led->total_current_ma >= 1000)
- led->trigger_chgr = true;
- }
- }
- static int qpnp_flash_led_switch_disable(struct flash_switch_data *snode)
- {
- struct qpnp_flash_led *led = dev_get_drvdata(&snode->pdev->dev);
- int i, rc, addr_offset;
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_EN_LED_CTRL(led->base),
- snode->led_mask, FLASH_LED_DISABLE);
- if (rc < 0)
- return rc;
- if (led->trigger_lmh) {
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_MITIGATION_SW(led->base),
- FLASH_LED_LMH_MITIGATION_EN_MASK,
- FLASH_LED_LMH_MITIGATION_DISABLE);
- if (rc < 0) {
- pr_err("disable lmh mitigation failed, rc=%d\n", rc);
- return rc;
- }
- }
- if (led->pdata->chgr_mitigation_sel && !led->trigger_chgr) {
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_MITIGATION_SW(led->base),
- FLASH_LED_CHGR_MITIGATION_EN_MASK,
- FLASH_LED_CHGR_MITIGATION_DISABLE);
- if (rc < 0) {
- pr_err("disable chgr mitigation failed, rc=%d\n", rc);
- return rc;
- }
- }
- led->enable--;
- if (led->enable == 0) {
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_MOD_CTRL(led->base),
- FLASH_LED_MOD_CTRL_MASK, FLASH_LED_DISABLE);
- if (rc < 0)
- return rc;
- }
- for (i = 0; i < led->num_fnodes; i++) {
- if (!led->fnode[i].led_on ||
- !(snode->led_mask & BIT(led->fnode[i].id)))
- continue;
- addr_offset = led->fnode[i].id;
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_TGR_CURRENT(led->base + addr_offset),
- FLASH_LED_CURRENT_MASK, 0);
- if (rc < 0)
- return rc;
- rc = qpnp_flash_led_write(led,
- FLASH_LED_REG_SAFETY_TMR(led->base + addr_offset),
- FLASH_LED_SAFETY_TMR_DISABLED);
- if (rc < 0)
- return rc;
- led->fnode[i].led_on = false;
- if (led->fnode[i].strobe_sel == HW_STROBE) {
- rc = qpnp_flash_led_hw_strobe_enable(&led->fnode[i],
- led->pdata->hw_strobe_option, false);
- if (rc < 0) {
- pr_err("Unable to disable hw strobe, rc=%d\n",
- rc);
- return rc;
- }
- }
- }
- if (snode->led_en_pinctrl) {
- pr_debug("Selecting suspend state for %s\n", snode->cdev.name);
- rc = pinctrl_select_state(snode->led_en_pinctrl,
- snode->gpio_state_suspend);
- if (rc < 0) {
- pr_err("failed to select pinctrl suspend state rc=%d\n",
- rc);
- return rc;
- }
- }
- snode->enabled = false;
- return 0;
- }
- static int qpnp_flash_led_symmetry_config(struct flash_switch_data *snode)
- {
- struct qpnp_flash_led *led = dev_get_drvdata(&snode->pdev->dev);
- int i, total_curr_ma = 0, num_leds = 0, prgm_current_ma;
- enum flash_led_type type = FLASH_LED_TYPE_UNKNOWN;
- for (i = 0; i < led->num_fnodes; i++) {
- if (snode->led_mask & BIT(led->fnode[i].id)) {
- if (led->fnode[i].type == FLASH_LED_TYPE_FLASH &&
- led->fnode[i].led_on)
- type = FLASH_LED_TYPE_FLASH;
- if (led->fnode[i].type == FLASH_LED_TYPE_TORCH &&
- led->fnode[i].led_on)
- type = FLASH_LED_TYPE_TORCH;
- }
- }
- if (type == FLASH_LED_TYPE_UNKNOWN) {
- pr_err("Incorrect type possibly because of no active LEDs\n");
- return -EINVAL;
- }
- for (i = 0; i < led->num_fnodes; i++) {
- if ((snode->led_mask & BIT(led->fnode[i].id)) &&
- (led->fnode[i].type == type)) {
- total_curr_ma += led->fnode[i].current_ma;
- num_leds++;
- }
- }
- if (num_leds > 0 && total_curr_ma > 0) {
- prgm_current_ma = total_curr_ma / num_leds;
- } else {
- pr_err("Incorrect configuration, num_leds: %d total_curr_ma: %d\n",
- num_leds, total_curr_ma);
- return -EINVAL;
- }
- if (prgm_current_ma == 0) {
- pr_warn("prgm_curr_ma cannot be 0\n");
- return 0;
- }
- pr_debug("num_leds: %d total: %d prgm_curr_ma: %d\n", num_leds,
- total_curr_ma, prgm_current_ma);
- for (i = 0; i < led->num_fnodes; i++) {
- if (snode->led_mask & BIT(led->fnode[i].id) &&
- led->fnode[i].current_ma != prgm_current_ma &&
- led->fnode[i].type == type) {
- qpnp_flash_led_node_set(&led->fnode[i],
- prgm_current_ma);
- pr_debug("%s LED %d current: %d code: %d ires_ua: %d\n",
- (type == FLASH_LED_TYPE_FLASH) ?
- "flash" : "torch",
- led->fnode[i].id, prgm_current_ma,
- led->fnode[i].current_reg_val,
- led->fnode[i].ires_ua);
- }
- }
- return 0;
- }
- #define FLASH_VREG_OK_SETTLE_TIME_US 1000
- static int qpnp_flash_led_module_enable(struct flash_switch_data *snode)
- {
- struct qpnp_flash_led *led = dev_get_drvdata(&snode->pdev->dev);
- int rc = 0;
- if (led->enable == 0) {
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_MOD_CTRL(led->base),
- FLASH_LED_MOD_CTRL_MASK, FLASH_LED_MOD_ENABLE);
- if (rc < 0)
- return rc;
- }
- /* For PMI632, wait 1ms to allow flash to settle */
- if (led->pmic_type == PMI632)
- udelay(FLASH_VREG_OK_SETTLE_TIME_US);
- led->enable++;
- return rc;
- }
- static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on)
- {
- struct qpnp_flash_led *led = dev_get_drvdata(&snode->pdev->dev);
- int rc, i, addr_offset;
- u8 val, mask;
- if (snode->enabled == on) {
- pr_debug("Switch node is already %s!\n",
- on ? "enabled" : "disabled");
- return 0;
- }
- if (!on) {
- rc = qpnp_flash_led_switch_disable(snode);
- return rc;
- }
- /* Iterate over all active leds for this switch node */
- if (snode->symmetry_en) {
- rc = qpnp_flash_led_symmetry_config(snode);
- if (rc < 0) {
- pr_err("Failed to configure current symmetrically, rc=%d\n",
- rc);
- return rc;
- }
- }
- val = 0;
- for (i = 0; i < led->num_fnodes; i++)
- if (led->fnode[i].led_on &&
- snode->led_mask & BIT(led->fnode[i].id))
- val |= led->fnode[i].ires_idx << (led->fnode[i].id * 2);
- rc = qpnp_flash_led_masked_write(led, FLASH_LED_REG_IRES(led->base),
- FLASH_LED_CURRENT_MASK, val);
- if (rc < 0)
- return rc;
- val = 0;
- for (i = 0; i < led->num_fnodes; i++) {
- if (!led->fnode[i].led_on ||
- !(snode->led_mask & BIT(led->fnode[i].id)))
- continue;
- addr_offset = led->fnode[i].id;
- if (led->fnode[i].strobe_sel == SW_STROBE)
- mask = FLASH_LED_HW_SW_STROBE_SEL_BIT;
- else
- mask = FLASH_HW_STROBE_MASK;
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_STROBE_CTRL(led->base + addr_offset),
- mask, led->fnode[i].strobe_ctrl);
- if (rc < 0)
- return rc;
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_TGR_CURRENT(led->base + addr_offset),
- FLASH_LED_CURRENT_MASK, led->fnode[i].current_reg_val);
- if (rc < 0)
- return rc;
- rc = qpnp_flash_led_write(led,
- FLASH_LED_REG_SAFETY_TMR(led->base + addr_offset),
- led->fnode[i].duration);
- if (rc < 0)
- return rc;
- val |= FLASH_LED_ENABLE << led->fnode[i].id;
- if (led->fnode[i].strobe_sel == HW_STROBE) {
- rc = qpnp_flash_led_hw_strobe_enable(&led->fnode[i],
- led->pdata->hw_strobe_option, true);
- if (rc < 0) {
- pr_err("Unable to enable hw strobe rc=%d\n",
- rc);
- return rc;
- }
- }
- }
- if (snode->led_en_pinctrl) {
- pr_debug("Selecting active state for %s\n", snode->cdev.name);
- rc = pinctrl_select_state(snode->led_en_pinctrl,
- snode->gpio_state_active);
- if (rc < 0) {
- pr_err("failed to select pinctrl active state rc=%d\n",
- rc);
- return rc;
- }
- }
- rc = qpnp_flash_led_module_enable(snode);
- if (rc < 0)
- return rc;
- if (led->trigger_lmh) {
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_MITIGATION_SW(led->base),
- FLASH_LED_LMH_MITIGATION_EN_MASK,
- FLASH_LED_LMH_MITIGATION_ENABLE);
- if (rc < 0) {
- pr_err("trigger lmh mitigation failed, rc=%d\n", rc);
- return rc;
- }
- /* Wait for LMH mitigation to take effect */
- udelay(500);
- }
- if (led->pdata->chgr_mitigation_sel && led->trigger_chgr) {
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_MITIGATION_SW(led->base),
- FLASH_LED_CHGR_MITIGATION_EN_MASK,
- FLASH_LED_CHGR_MITIGATION_ENABLE);
- if (rc < 0) {
- pr_err("trigger chgr mitigation failed, rc=%d\n", rc);
- return rc;
- }
- }
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_EN_LED_CTRL(led->base),
- snode->led_mask, val);
- if (rc < 0)
- return rc;
- snode->enabled = true;
- return 0;
- }
- static int qpnp_flash_led_regulator_control(struct led_classdev *led_cdev,
- int options, int *max_current)
- {
- int rc, val;
- struct flash_switch_data *snode;
- struct qpnp_flash_led *led;
- snode = container_of(led_cdev, struct flash_switch_data, cdev);
- led = dev_get_drvdata(&snode->pdev->dev);
- if (led->pmic_type == PMI632) {
- rc = is_usb_psy_available(led);
- if (rc < 0)
- return rc;
- }
- if (!(options & FLASH_LED_PREPARE_OPTIONS_MASK)) {
- pr_err("Invalid options %d\n", options);
- return -EINVAL;
- }
- if (options & ENABLE_REGULATOR) {
- if (led->pmic_type == PMI632) {
- val = 1;
- rc = qpnp_flash_iio_setprop(led, F_ACTIVE, val);
- if (rc < 0) {
- pr_err("Failed to set FLASH_ACTIVE on charger rc=%d\n",
- rc);
- return rc;
- }
- pr_debug("FLASH_ACTIVE = 1\n");
- } else {
- rc = qpnp_flash_led_regulator_enable(led, snode, true);
- if (rc < 0) {
- pr_err("enable regulator failed, rc=%d\n", rc);
- return rc;
- }
- }
- }
- if (options & DISABLE_REGULATOR) {
- if (led->pmic_type == PMI632) {
- val = 0;
- rc = qpnp_flash_iio_setprop(led, F_ACTIVE, val);
- if (rc < 0) {
- pr_err("Failed to set FLASH_ACTIVE on charger rc=%d\n",
- rc);
- return rc;
- }
- pr_debug("FLASH_ACTIVE = 0\n");
- } else {
- rc = qpnp_flash_led_regulator_enable(led, snode, false);
- if (rc < 0) {
- pr_err("disable regulator failed, rc=%d\n", rc);
- return rc;
- }
- }
- }
- if (options & QUERY_MAX_AVAIL_CURRENT) {
- rc = qpnp_flash_led_get_max_avail_current(led, max_current);
- if (rc < 0) {
- pr_err("query max current failed, rc=%d\n", rc);
- return rc;
- }
- }
- return 0;
- }
- static struct led_classdev *trigger_to_lcdev(struct led_trigger *trig)
- {
- struct led_classdev *led_cdev;
- spin_lock(&trig->leddev_list_lock);
- list_for_each_entry(led_cdev, &trig->led_cdevs, trig_list) {
- if (!strcmp(led_cdev->default_trigger, trig->name)) {
- spin_unlock(&trig->leddev_list_lock);
- return led_cdev;
- }
- }
- spin_unlock(&trig->leddev_list_lock);
- return NULL;
- }
- int qpnp_flash_led_prepare(struct led_trigger *trig, int options,
- int *max_current)
- {
- struct led_classdev *led_cdev;
- int rc;
- if (!trig) {
- pr_err("Invalid led_trigger provided\n");
- return -EINVAL;
- }
- led_cdev = trigger_to_lcdev(trig);
- if (!led_cdev) {
- pr_err("Invalid led_cdev in trigger %s\n", trig->name);
- return -EINVAL;
- }
- rc = qpnp_flash_led_regulator_control(led_cdev, options, max_current);
- return rc;
- }
- EXPORT_SYMBOL(qpnp_flash_led_prepare);
- static void qpnp_flash_led_brightness_set(struct led_classdev *led_cdev,
- enum led_brightness value)
- {
- struct flash_node_data *fnode = NULL;
- struct flash_switch_data *snode = NULL;
- struct qpnp_flash_led *led = NULL;
- int rc;
- /*
- * strncmp() must be used here since a prefix comparison is required
- * in order to support names like led:switch_0 and led:flash_1.
- */
- if (!strncmp(led_cdev->name, "led:switch", strlen("led:switch"))) {
- snode = container_of(led_cdev, struct flash_switch_data, cdev);
- led = dev_get_drvdata(&snode->pdev->dev);
- } else if (!strncmp(led_cdev->name, "led:flash", strlen("led:flash")) ||
- !strncmp(led_cdev->name, "led:torch",
- strlen("led:torch"))) {
- fnode = container_of(led_cdev, struct flash_node_data, cdev);
- led = dev_get_drvdata(&fnode->pdev->dev);
- }
- if (!led) {
- pr_err("Failed to get flash driver data\n");
- return;
- }
- spin_lock(&led->lock);
- if (snode) {
- rc = qpnp_flash_led_switch_set(snode, value > 0);
- if (rc < 0)
- pr_err("Failed to set flash LED switch rc=%d\n", rc);
- } else if (fnode) {
- qpnp_flash_led_node_set(fnode, value);
- }
- spin_unlock(&led->lock);
- }
- static ssize_t qpnp_flash_led_prepare_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
- {
- int rc, options, max_current;
- u32 val;
- struct led_classdev *led_cdev = dev_get_drvdata(dev);
- rc = kstrtouint(buf, 0, &val);
- if (rc < 0)
- return rc;
- if (val != 0 && val != 1)
- return count;
- options = val ? ENABLE_REGULATOR : DISABLE_REGULATOR;
- rc = qpnp_flash_led_regulator_control(led_cdev, options, &max_current);
- if (rc < 0)
- return rc;
- return count;
- }
- /* sysfs show function for flash_max_current */
- static ssize_t qpnp_flash_led_max_current_show(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- int rc, max_current = 0;
- struct flash_switch_data *snode;
- struct qpnp_flash_led *led;
- struct led_classdev *led_cdev = dev_get_drvdata(dev);
- snode = container_of(led_cdev, struct flash_switch_data, cdev);
- led = dev_get_drvdata(&snode->pdev->dev);
- rc = qpnp_flash_led_get_max_avail_current(led, &max_current);
- if (rc < 0)
- pr_err("query max current failed, rc=%d\n", rc);
- return scnprintf(buf, PAGE_SIZE, "%d\n", max_current);
- }
- /* sysfs attributes exported by flash_led */
- static struct device_attribute qpnp_flash_led_attrs[] = {
- __ATTR(max_current, 0664, qpnp_flash_led_max_current_show, NULL),
- __ATTR(enable, 0664, NULL, qpnp_flash_led_prepare_store),
- };
- /* irq handler */
- static irqreturn_t qpnp_flash_led_irq_handler(int irq, void *_led)
- {
- struct qpnp_flash_led *led = _led;
- enum flash_led_irq_type irq_type = INVALID_IRQ;
- int rc;
- u8 irq_status, led_status1, led_status2;
- pr_debug("irq received, irq=%d\n", irq);
- rc = qpnp_flash_led_read(led,
- FLASH_LED_REG_INT_RT_STS(led->base), &irq_status);
- if (rc < 0) {
- pr_err("Failed to read interrupt status reg, rc=%d\n", rc);
- goto exit;
- }
- if (irq == led->pdata->all_ramp_up_done_irq)
- irq_type = ALL_RAMP_UP_DONE_IRQ;
- else if (irq == led->pdata->all_ramp_down_done_irq)
- irq_type = ALL_RAMP_DOWN_DONE_IRQ;
- else if (irq == led->pdata->led_fault_irq)
- irq_type = LED_FAULT_IRQ;
- if (irq_type == ALL_RAMP_UP_DONE_IRQ)
- atomic_notifier_call_chain(&irq_notifier_list,
- irq_type, NULL);
- if (irq_type == LED_FAULT_IRQ) {
- rc = qpnp_flash_led_read(led,
- FLASH_LED_REG_LED_STATUS1(led->base), &led_status1);
- if (rc < 0) {
- pr_err("Failed to read led_status1 reg, rc=%d\n", rc);
- goto exit;
- }
- rc = qpnp_flash_led_read(led,
- FLASH_LED_REG_LED_STATUS2(led->base), &led_status2);
- if (rc < 0) {
- pr_err("Failed to read led_status2 reg, rc=%d\n", rc);
- goto exit;
- }
- if (led_status1)
- pr_emerg("led short/open fault detected! led_status1=%x\n",
- led_status1);
- if (led_status2 & FLASH_LED_VPH_DROOP_FAULT_MASK)
- pr_emerg("led vph_droop fault detected!\n");
- }
- pr_debug("irq handled, irq_type=%x, irq_status=%x\n", irq_type,
- irq_status);
- exit:
- return IRQ_HANDLED;
- }
- int qpnp_flash_led_register_irq_notifier(struct notifier_block *nb)
- {
- return atomic_notifier_chain_register(&irq_notifier_list, nb);
- }
- int qpnp_flash_led_unregister_irq_notifier(struct notifier_block *nb)
- {
- return atomic_notifier_chain_unregister(&irq_notifier_list, nb);
- }
- static inline u8 get_safety_timer_code(u32 duration_ms)
- {
- if (!duration_ms)
- return 0;
- return (duration_ms / 10) - 1;
- }
- static inline u8 get_vph_droop_thresh_code(u32 val_mv)
- {
- if (!val_mv)
- return 0;
- return (val_mv / 100) - 25;
- }
- static int qpnp_flash_led_parse_hw_strobe_dt(struct flash_node_data *fnode)
- {
- struct device_node *node = fnode->cdev.dev->of_node;
- if (of_find_property(node, "qcom,hw-strobe-gpio", NULL)) {
- fnode->hw_strobe_gpio = of_get_named_gpio(node,
- "qcom,hw-strobe-gpio", 0);
- if (fnode->hw_strobe_gpio < 0) {
- pr_err("Invalid gpio specified\n");
- return fnode->hw_strobe_gpio;
- }
- gpio_direction_output(fnode->hw_strobe_gpio, 0);
- } else if (fnode->strobe_pinctrl) {
- fnode->hw_strobe_gpio = -1;
- fnode->hw_strobe_state_active =
- pinctrl_lookup_state(fnode->strobe_pinctrl,
- "strobe_enable");
- if (IS_ERR_OR_NULL(fnode->hw_strobe_state_active)) {
- pr_err("No active pin for hardware strobe, rc=%ld\n",
- PTR_ERR(fnode->hw_strobe_state_active));
- fnode->hw_strobe_state_active = NULL;
- }
- fnode->hw_strobe_state_suspend =
- pinctrl_lookup_state(fnode->strobe_pinctrl,
- "strobe_disable");
- if (IS_ERR_OR_NULL(fnode->hw_strobe_state_suspend)) {
- pr_err("No suspend pin for hardware strobe, rc=%ld\n",
- PTR_ERR(fnode->hw_strobe_state_suspend));
- fnode->hw_strobe_state_suspend = NULL;
- }
- }
- return 0;
- }
- static int qpnp_flash_led_parse_strobe_sel_dt(struct qpnp_flash_led *led,
- struct flash_node_data *fnode,
- struct device_node *node)
- {
- int rc;
- u32 val;
- u8 hw_strobe = 0, edge_trigger = 0, active_high = 0;
- fnode->strobe_sel = SW_STROBE;
- rc = of_property_read_u32(node, "qcom,strobe-sel", &val);
- if (rc < 0) {
- if (rc != -EINVAL) {
- pr_err("Unable to read qcom,strobe-sel property\n");
- return rc;
- }
- } else {
- if (val < SW_STROBE || val > LPG_STROBE) {
- pr_err("Incorrect strobe selection specified %d\n",
- val);
- return -EINVAL;
- }
- fnode->strobe_sel = (u8)val;
- }
- /*
- * LPG strobe is allowed only for LED3 and HW strobe option should be
- * option 2 or 3.
- */
- if (fnode->strobe_sel == LPG_STROBE) {
- if (led->pdata->hw_strobe_option ==
- FLASH_LED_HW_STROBE_OPTION_1) {
- pr_err("Incorrect strobe option for LPG strobe\n");
- return -EINVAL;
- }
- if (fnode->id != LED3) {
- pr_err("Incorrect LED chosen for LPG strobe\n");
- return -EINVAL;
- }
- }
- if (fnode->strobe_sel == HW_STROBE) {
- edge_trigger = of_property_read_bool(node,
- "qcom,hw-strobe-edge-trigger");
- active_high = !of_property_read_bool(node,
- "qcom,hw-strobe-active-low");
- hw_strobe = 1;
- } else if (fnode->strobe_sel == LPG_STROBE) {
- /* LPG strobe requires level trigger and active high */
- edge_trigger = 0;
- active_high = 1;
- hw_strobe = 1;
- }
- fnode->strobe_ctrl = (hw_strobe << 2) | (edge_trigger << 1) |
- active_high;
- return 0;
- }
- static int qpnp_flash_led_parse_label_dt(struct flash_node_data *fnode,
- struct device_node *node)
- {
- const char *temp_string;
- int rc;
- rc = of_property_read_string(node, "label", &temp_string);
- if (!rc) {
- if (!strcmp(temp_string, "flash")) {
- fnode->type = FLASH_LED_TYPE_FLASH;
- } else if (!strcmp(temp_string, "torch")) {
- fnode->type = FLASH_LED_TYPE_TORCH;
- } else {
- pr_err("Wrong flash LED type\n");
- return rc;
- }
- } else {
- pr_err("Unable to read flash LED label\n");
- return rc;
- }
- return rc;
- }
- static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led,
- struct flash_node_data *fnode, struct device_node *node)
- {
- int rc, min_ma;
- u32 val;
- fnode->pdev = led->pdev;
- fnode->cdev.brightness_set = qpnp_flash_led_brightness_set;
- fnode->cdev.brightness_get = qpnp_flash_led_brightness_get;
- rc = of_property_read_string(node, "qcom,led-name", &fnode->cdev.name);
- if (rc < 0) {
- pr_err("Unable to read flash LED names\n");
- return rc;
- }
- rc = qpnp_flash_led_parse_label_dt(fnode, node);
- if (rc < 0)
- return rc;
- rc = of_property_read_u32(node, "qcom,id", &val);
- if (!rc) {
- fnode->id = (u8)val;
- if (led->pmic_type == PMI632 && fnode->id > LED2) {
- pr_err("Flash node id = %d not supported\n", fnode->id);
- return -EINVAL;
- }
- } else {
- pr_err("Unable to read flash LED ID\n");
- return rc;
- }
- rc = of_property_read_string(node, "qcom,default-led-trigger",
- &fnode->cdev.default_trigger);
- if (rc < 0) {
- pr_err("Unable to read trigger name\n");
- return rc;
- }
- fnode->default_ires_ua = fnode->ires_ua = FLASH_LED_IRES_DEFAULT_UA;
- fnode->default_ires_idx = fnode->ires_idx = FLASH_LED_IRES_DEFAULT_VAL;
- rc = of_property_read_u32(node, "qcom,ires-ua", &val);
- if (!rc) {
- fnode->default_ires_ua = fnode->ires_ua = val;
- fnode->default_ires_idx = fnode->ires_idx =
- FLASH_LED_IRES_BASE - (val - FLASH_LED_IRES_MIN_UA) /
- FLASH_LED_IRES_DIVISOR;
- } else if (rc != -EINVAL) {
- pr_err("Unable to read current resolution rc=%d\n", rc);
- return rc;
- }
- min_ma = fnode->ires_ua / 1000;
- rc = of_property_read_u32(node, "qcom,max-current", &val);
- if (!rc) {
- if (val < min_ma)
- val = min_ma;
- fnode->max_current = val;
- fnode->cdev.max_brightness = val;
- } else {
- pr_err("Unable to read max current, rc=%d\n", rc);
- return rc;
- }
- rc = of_property_read_u32(node, "qcom,current-ma", &val);
- if (!rc) {
- if (val < min_ma || val > fnode->max_current)
- pr_warn("Invalid operational current specified, capping it\n");
- if (val < min_ma)
- val = min_ma;
- if (val > fnode->max_current)
- val = fnode->max_current;
- fnode->current_ma = val;
- fnode->cdev.brightness = val;
- } else if (rc != -EINVAL) {
- pr_err("Unable to read operational current, rc=%d\n", rc);
- return rc;
- }
- fnode->duration = FLASH_LED_SAFETY_TMR_DISABLED;
- rc = of_property_read_u32(node, "qcom,duration-ms", &val);
- if (!rc) {
- fnode->duration = get_safety_timer_code(val);
- if (fnode->duration)
- fnode->duration |= FLASH_LED_SAFETY_TMR_ENABLE;
- } else if (rc == -EINVAL) {
- if (fnode->type == FLASH_LED_TYPE_FLASH) {
- pr_err("Timer duration is required for flash LED\n");
- return rc;
- }
- } else {
- pr_err("Unable to read timer duration\n");
- return rc;
- }
- fnode->hdrm_val = FLASH_LED_HDRM_VOL_DEFAULT_MV;
- rc = of_property_read_u32(node, "qcom,hdrm-voltage-mv", &val);
- if (!rc) {
- val = (val - FLASH_LED_HDRM_VOL_BASE_MV) /
- FLASH_LED_HDRM_VOL_STEP_MV;
- fnode->hdrm_val = (val << FLASH_LED_HDRM_VOL_SHIFT) &
- FLASH_LED_HDRM_VOL_MASK;
- } else if (rc != -EINVAL) {
- pr_err("Unable to read headroom voltage\n");
- return rc;
- }
- rc = of_property_read_u32(node, "qcom,hdrm-vol-hi-lo-win-mv", &val);
- if (!rc) {
- fnode->hdrm_val |= (val / FLASH_LED_HDRM_VOL_STEP_MV) &
- ~FLASH_LED_HDRM_VOL_MASK;
- } else if (rc == -EINVAL) {
- fnode->hdrm_val |= FLASH_LED_HDRM_VOL_HI_LO_WIN_DEFAULT_MV;
- } else {
- pr_err("Unable to read hdrm hi-lo window voltage\n");
- return rc;
- }
- rc = qpnp_flash_led_parse_strobe_sel_dt(led, fnode, node);
- if (rc < 0)
- return rc;
- rc = led_classdev_register(&led->pdev->dev, &fnode->cdev);
- if (rc < 0) {
- pr_err("Unable to register led node %d\n", fnode->id);
- return rc;
- }
- fnode->cdev.dev->of_node = node;
- fnode->strobe_pinctrl = devm_pinctrl_get(fnode->cdev.dev);
- if (IS_ERR_OR_NULL(fnode->strobe_pinctrl)) {
- pr_debug("No pinctrl defined for %s, err=%ld\n",
- fnode->cdev.name, PTR_ERR(fnode->strobe_pinctrl));
- fnode->strobe_pinctrl = NULL;
- }
- if (fnode->strobe_sel == HW_STROBE)
- return qpnp_flash_led_parse_hw_strobe_dt(fnode);
- return 0;
- }
- static int qpnp_flash_led_parse_and_register_switch(struct qpnp_flash_led *led,
- struct flash_switch_data *snode,
- struct device_node *node)
- {
- int rc = 0, num;
- char reg_name[16], reg_sup_name[16];
- rc = of_property_read_string(node, "qcom,led-name", &snode->cdev.name);
- if (rc < 0) {
- pr_err("Failed to read switch node name, rc=%d\n", rc);
- return rc;
- }
- rc = sscanf(snode->cdev.name, "led:switch_%d", &num);
- if (!rc) {
- pr_err("No number for switch device?\n");
- return -EINVAL;
- }
- rc = of_property_read_string(node, "qcom,default-led-trigger",
- &snode->cdev.default_trigger);
- if (rc < 0) {
- pr_err("Unable to read trigger name, rc=%d\n", rc);
- return rc;
- }
- rc = of_property_read_u32(node, "qcom,led-mask", &snode->led_mask);
- if (rc < 0) {
- pr_err("Unable to read led mask rc=%d\n", rc);
- return rc;
- }
- snode->symmetry_en = of_property_read_bool(node, "qcom,symmetry-en");
- if (snode->led_mask < 1 || snode->led_mask > 7) {
- pr_err("Invalid value for led-mask\n");
- return -EINVAL;
- }
- scnprintf(reg_name, sizeof(reg_name), "switch%d-supply", num);
- if (of_find_property(led->pdev->dev.of_node, reg_name, NULL)) {
- scnprintf(reg_sup_name, sizeof(reg_sup_name), "switch%d", num);
- snode->vreg = devm_regulator_get(&led->pdev->dev, reg_sup_name);
- if (IS_ERR_OR_NULL(snode->vreg)) {
- rc = PTR_ERR(snode->vreg);
- if (rc != -EPROBE_DEFER)
- pr_err("Failed to get regulator, rc=%d\n", rc);
- snode->vreg = NULL;
- return rc;
- }
- }
- snode->pdev = led->pdev;
- snode->cdev.brightness_set = qpnp_flash_led_brightness_set;
- snode->cdev.brightness_get = qpnp_flash_led_brightness_get;
- rc = led_classdev_register(&led->pdev->dev, &snode->cdev);
- if (rc < 0) {
- pr_err("Unable to register led switch node\n");
- return rc;
- }
- snode->cdev.dev->of_node = node;
- snode->led_en_pinctrl = devm_pinctrl_get(snode->cdev.dev);
- if (IS_ERR_OR_NULL(snode->led_en_pinctrl)) {
- pr_debug("No pinctrl defined for %s, err=%ld\n",
- snode->cdev.name, PTR_ERR(snode->led_en_pinctrl));
- snode->led_en_pinctrl = NULL;
- }
- if (snode->led_en_pinctrl) {
- snode->gpio_state_active =
- pinctrl_lookup_state(snode->led_en_pinctrl,
- "led_enable");
- if (IS_ERR_OR_NULL(snode->gpio_state_active)) {
- pr_err("Cannot lookup LED active state\n");
- devm_pinctrl_put(snode->led_en_pinctrl);
- snode->led_en_pinctrl = NULL;
- return PTR_ERR(snode->gpio_state_active);
- }
- snode->gpio_state_suspend =
- pinctrl_lookup_state(snode->led_en_pinctrl,
- "led_disable");
- if (IS_ERR_OR_NULL(snode->gpio_state_suspend)) {
- pr_err("Cannot lookup LED disable state\n");
- devm_pinctrl_put(snode->led_en_pinctrl);
- snode->led_en_pinctrl = NULL;
- return PTR_ERR(snode->gpio_state_suspend);
- }
- }
- return 0;
- }
- static int get_code_from_table(int *table, int len, int value)
- {
- int i;
- for (i = 0; i < len; i++) {
- if (value == table[i])
- break;
- }
- if (i == len) {
- pr_err("Couldn't find %d from table\n", value);
- return -ENODATA;
- }
- return i;
- }
- static int qpnp_flash_led_parse_thermal_config_dt(struct qpnp_flash_led *led,
- struct device_node *node)
- {
- int rc;
- u32 val;
- led->pdata->thermal_derate_en =
- of_property_read_bool(node, "qcom,thermal-derate-en");
- if (led->pdata->thermal_derate_en) {
- led->pdata->thermal_derate_current =
- devm_kcalloc(&led->pdev->dev,
- FLASH_LED_THERMAL_OTST_LEVELS,
- sizeof(int), GFP_KERNEL);
- if (!led->pdata->thermal_derate_current)
- return -ENOMEM;
- rc = of_property_read_u32_array(node,
- "qcom,thermal-derate-current",
- led->pdata->thermal_derate_current,
- FLASH_LED_THERMAL_OTST_LEVELS);
- if (rc < 0) {
- pr_err("Unable to read thermal current limits, rc=%d\n",
- rc);
- return rc;
- }
- }
- led->pdata->otst_ramp_bkup_en =
- !of_property_read_bool(node, "qcom,otst-ramp-back-up-dis");
- led->pdata->thermal_derate_slow = -EINVAL;
- rc = of_property_read_u32(node, "qcom,thermal-derate-slow", &val);
- if (!rc) {
- if (val < 0 || val > THERMAL_DERATE_SLOW_MAX) {
- pr_err("Invalid thermal_derate_slow %d\n", val);
- return -EINVAL;
- }
- led->pdata->thermal_derate_slow =
- get_code_from_table(thermal_derate_slow_table,
- ARRAY_SIZE(thermal_derate_slow_table), val);
- } else if (rc != -EINVAL) {
- pr_err("Unable to read thermal derate slow, rc=%d\n", rc);
- return rc;
- }
- led->pdata->thermal_derate_fast = -EINVAL;
- rc = of_property_read_u32(node, "qcom,thermal-derate-fast", &val);
- if (!rc) {
- if (val < 0 || val > THERMAL_DERATE_FAST_MAX) {
- pr_err("Invalid thermal_derate_fast %d\n", val);
- return -EINVAL;
- }
- led->pdata->thermal_derate_fast =
- get_code_from_table(thermal_derate_fast_table,
- ARRAY_SIZE(thermal_derate_fast_table), val);
- } else if (rc != -EINVAL) {
- pr_err("Unable to read thermal derate fast, rc=%d\n", rc);
- return rc;
- }
- led->pdata->thermal_debounce = -EINVAL;
- rc = of_property_read_u32(node, "qcom,thermal-debounce", &val);
- if (!rc) {
- if (val < 0 || val > THERMAL_DEBOUNCE_TIME_MAX) {
- pr_err("Invalid thermal_debounce %d\n", val);
- return -EINVAL;
- }
- if (val >= 0 && val < 16)
- led->pdata->thermal_debounce = 0;
- else
- led->pdata->thermal_debounce = ilog2(val) - 3;
- } else if (rc != -EINVAL) {
- pr_err("Unable to read thermal debounce, rc=%d\n", rc);
- return rc;
- }
- led->pdata->thermal_hysteresis = -EINVAL;
- rc = of_property_read_u32(node, "qcom,thermal-hysteresis", &val);
- if (!rc) {
- if (led->pmic_type == PM660L)
- val = THERMAL_HYST_TEMP_TO_VAL(val, 20);
- else
- val = THERMAL_HYST_TEMP_TO_VAL(val, 15);
- if (val < 0 || val > THERMAL_DERATE_HYSTERESIS_MAX) {
- pr_err("Invalid thermal_derate_hysteresis %d\n", val);
- return -EINVAL;
- }
- led->pdata->thermal_hysteresis = val;
- } else if (rc != -EINVAL) {
- pr_err("Unable to read thermal hysteresis, rc=%d\n", rc);
- return rc;
- }
- led->pdata->thermal_thrsh1 = -EINVAL;
- rc = of_property_read_u32(node, "qcom,thermal-thrsh1", &val);
- if (!rc) {
- led->pdata->thermal_thrsh1 =
- get_code_from_table(otst1_threshold_table,
- ARRAY_SIZE(otst1_threshold_table), val);
- } else if (rc != -EINVAL) {
- pr_err("Unable to read thermal thrsh1, rc=%d\n", rc);
- return rc;
- }
- led->pdata->thermal_thrsh2 = -EINVAL;
- rc = of_property_read_u32(node, "qcom,thermal-thrsh2", &val);
- if (!rc) {
- led->pdata->thermal_thrsh2 =
- get_code_from_table(otst2_threshold_table,
- ARRAY_SIZE(otst2_threshold_table), val);
- } else if (rc != -EINVAL) {
- pr_err("Unable to read thermal thrsh2, rc=%d\n", rc);
- return rc;
- }
- led->pdata->thermal_thrsh3 = -EINVAL;
- rc = of_property_read_u32(node, "qcom,thermal-thrsh3", &val);
- if (!rc) {
- led->pdata->thermal_thrsh3 =
- get_code_from_table(otst3_threshold_table,
- ARRAY_SIZE(otst3_threshold_table), val);
- } else if (rc != -EINVAL) {
- pr_err("Unable to read thermal thrsh3, rc=%d\n", rc);
- return rc;
- }
- return 0;
- }
- static int qpnp_flash_led_parse_vph_droop_config_dt(struct qpnp_flash_led *led,
- struct device_node *node)
- {
- int rc;
- u32 val;
- led->pdata->vph_droop_debounce = FLASH_LED_VPH_DROOP_DEBOUNCE_DEFAULT;
- rc = of_property_read_u32(node, "qcom,vph-droop-debounce-us", &val);
- if (!rc) {
- led->pdata->vph_droop_debounce =
- VPH_DROOP_DEBOUNCE_US_TO_VAL(val);
- } else if (rc != -EINVAL) {
- pr_err("Unable to read VPH droop debounce, rc=%d\n", rc);
- return rc;
- }
- if (led->pdata->vph_droop_debounce > FLASH_LED_DEBOUNCE_MAX) {
- pr_err("Invalid VPH droop debounce specified\n");
- return -EINVAL;
- }
- if (led->pmic_type == PMI632)
- led->pdata->vph_droop_threshold =
- BHARGER_FLASH_LED_VPH_DROOP_THRESH_DEFAULT;
- else
- led->pdata->vph_droop_threshold =
- FLASH_LED_VPH_DROOP_THRESH_DEFAULT;
- rc = of_property_read_u32(node, "qcom,vph-droop-threshold-mv", &val);
- if (!rc) {
- led->pdata->vph_droop_threshold =
- get_vph_droop_thresh_code(val);
- } else if (rc != -EINVAL) {
- pr_err("Unable to read VPH droop threshold, rc=%d\n", rc);
- return rc;
- }
- if (led->pdata->vph_droop_threshold > FLASH_LED_VPH_DROOP_THRESH_MAX) {
- pr_err("Invalid VPH droop threshold specified\n");
- return -EINVAL;
- }
- led->pdata->vph_droop_hysteresis =
- FLASH_LED_VPH_DROOP_HYST_DEFAULT;
- rc = of_property_read_u32(node, "qcom,vph-droop-hysteresis-mv", &val);
- if (!rc) {
- led->pdata->vph_droop_hysteresis =
- VPH_DROOP_HYST_MV_TO_VAL(val);
- } else if (rc != -EINVAL) {
- pr_err("Unable to read VPH droop hysteresis, rc=%d\n", rc);
- return rc;
- }
- if (led->pdata->vph_droop_hysteresis > FLASH_LED_HYSTERESIS_MAX) {
- pr_err("Invalid VPH droop hysteresis specified\n");
- return -EINVAL;
- }
- led->pdata->vph_droop_hysteresis <<= FLASH_LED_VPH_DROOP_HYST_SHIFT;
- return 0;
- }
- static int qpnp_flash_led_parse_iclamp_config_dt(struct qpnp_flash_led *led,
- struct device_node *node)
- {
- int rc;
- u32 val;
- rc = of_property_read_u32(node, "qcom,led1n2-iclamp-low-ma", &val);
- if (!rc) {
- led->pdata->led1n2_iclamp_low_ma = val;
- } else if (rc != -EINVAL) {
- pr_err("Unable to read led1n2_iclamp_low current, rc=%d\n", rc);
- return rc;
- }
- rc = of_property_read_u32(node, "qcom,led1n2-iclamp-mid-ma", &val);
- if (!rc) {
- led->pdata->led1n2_iclamp_mid_ma = val;
- } else if (rc != -EINVAL) {
- pr_err("Unable to read led1n2_iclamp_mid current, rc=%d\n", rc);
- return rc;
- }
- rc = of_property_read_u32(node, "qcom,led3-iclamp-low-ma", &val);
- if (!rc) {
- led->pdata->led3_iclamp_low_ma = val;
- } else if (rc != -EINVAL) {
- pr_err("Unable to read led3_iclamp_low current, rc=%d\n", rc);
- return rc;
- }
- rc = of_property_read_u32(node, "qcom,led3-iclamp-mid-ma", &val);
- if (!rc) {
- led->pdata->led3_iclamp_mid_ma = val;
- } else if (rc != -EINVAL) {
- pr_err("Unable to read led3_iclamp_mid current, rc=%d\n", rc);
- return rc;
- }
- return 0;
- }
- static int qpnp_flash_led_parse_lmh_config_dt(struct qpnp_flash_led *led,
- struct device_node *node)
- {
- int rc;
- u32 val;
- led->pdata->lmh_ocv_threshold_uv =
- FLASH_LED_LMH_OCV_THRESH_DEFAULT_UV;
- rc = of_property_read_u32(node, "qcom,lmh-ocv-threshold-uv", &val);
- if (!rc) {
- led->pdata->lmh_ocv_threshold_uv = val;
- } else if (rc != -EINVAL) {
- pr_err("Unable to parse lmh ocv threshold, rc=%d\n", rc);
- return rc;
- }
- led->pdata->lmh_rbatt_threshold_uohm =
- FLASH_LED_LMH_RBATT_THRESH_DEFAULT_UOHM;
- rc = of_property_read_u32(node, "qcom,lmh-rbatt-threshold-uohm", &val);
- if (!rc) {
- led->pdata->lmh_rbatt_threshold_uohm = val;
- } else if (rc != -EINVAL) {
- pr_err("Unable to parse lmh rbatt threshold, rc=%d\n", rc);
- return rc;
- }
- led->pdata->lmh_level = FLASH_LED_LMH_LEVEL_DEFAULT;
- rc = of_property_read_u32(node, "qcom,lmh-level", &val);
- if (!rc) {
- led->pdata->lmh_level = val;
- } else if (rc != -EINVAL) {
- pr_err("Unable to parse lmh_level, rc=%d\n", rc);
- return rc;
- }
- led->pdata->lmh_mitigation_sel = FLASH_LED_LMH_MITIGATION_SEL_DEFAULT;
- rc = of_property_read_u32(node, "qcom,lmh-mitigation-sel", &val);
- if (!rc) {
- led->pdata->lmh_mitigation_sel = val;
- } else if (rc != -EINVAL) {
- pr_err("Unable to parse lmh_mitigation_sel, rc=%d\n", rc);
- return rc;
- }
- if (led->pdata->lmh_mitigation_sel > FLASH_LED_MITIGATION_SEL_MAX) {
- pr_err("Invalid lmh_mitigation_sel specified\n");
- return -EINVAL;
- }
- return 0;
- }
- static int qpnp_flash_led_parse_iled_threshold_dt(struct qpnp_flash_led *led,
- struct device_node *node)
- {
- int rc;
- u32 val;
- led->pdata->iled_thrsh_val = FLASH_LED_CHGR_MITIGATION_THRSH_DEFAULT;
- rc = of_property_read_u32(node, "qcom,iled-thrsh-ma", &val);
- if (!rc) {
- led->pdata->iled_thrsh_val = MITIGATION_THRSH_MA_TO_VAL(val);
- } else if (rc != -EINVAL) {
- pr_err("Unable to parse iled_thrsh_val, rc=%d\n", rc);
- return rc;
- }
- if (led->pdata->iled_thrsh_val > FLASH_LED_CHGR_MITIGATION_THRSH_MAX) {
- pr_err("Invalid iled_thrsh_val specified\n");
- return -EINVAL;
- }
- return 0;
- }
- static int qpnp_flash_led_parse_chgr_mitigation_dt(struct qpnp_flash_led *led,
- struct device_node *node)
- {
- int rc;
- u32 val;
- if (led->pmic_type == PMI632)
- led->pdata->chgr_mitigation_sel =
- FLASH_DISABLE_CHARGER_MITIGATION;
- else
- led->pdata->chgr_mitigation_sel = FLASH_SW_CHARGER_MITIGATION;
- rc = of_property_read_u32(node, "qcom,chgr-mitigation-sel", &val);
- if (!rc) {
- led->pdata->chgr_mitigation_sel = val;
- } else if (rc != -EINVAL) {
- pr_err("Unable to parse chgr_mitigation_sel, rc=%d\n", rc);
- return rc;
- }
- if (led->pdata->chgr_mitigation_sel > FLASH_LED_MITIGATION_SEL_MAX) {
- pr_err("Invalid chgr_mitigation_sel specified\n");
- return -EINVAL;
- }
- return 0;
- }
- static int qpnp_flash_led_parse_battery_prop_dt(struct qpnp_flash_led *led,
- struct device_node *node)
- {
- int rc;
- u32 val;
- led->pdata->ibatt_ocp_threshold_ua =
- FLASH_LED_IBATT_OCP_THRESH_DEFAULT_UA;
- rc = of_property_read_u32(node, "qcom,ibatt-ocp-threshold-ua", &val);
- if (!rc) {
- led->pdata->ibatt_ocp_threshold_ua = val;
- } else if (rc != -EINVAL) {
- pr_err("Unable to parse ibatt_ocp threshold, rc=%d\n", rc);
- return rc;
- }
- led->pdata->rpara_uohm = FLASH_LED_RPARA_DEFAULT_UOHM;
- rc = of_property_read_u32(node, "qcom,rparasitic-uohm", &val);
- if (!rc) {
- led->pdata->rpara_uohm = val;
- } else if (rc != -EINVAL) {
- pr_err("Unable to parse rparasitic, rc=%d\n", rc);
- return rc;
- }
- return 0;
- }
- static void qpnp_flash_led_parse_fault_detection_dt(struct qpnp_flash_led *led,
- struct device_node *node)
- {
- bool short_circuit_det, open_circuit_det, vph_droop_det;
- short_circuit_det =
- of_property_read_bool(node, "qcom,short-circuit-det");
- open_circuit_det = of_property_read_bool(node, "qcom,open-circuit-det");
- vph_droop_det = of_property_read_bool(node, "qcom,vph-droop-det");
- led->pdata->current_derate_en_cfg = (vph_droop_det << 2) |
- (open_circuit_det << 1) | short_circuit_det;
- }
- static int qpnp_flash_led_parse_warmup_delay_dt(struct qpnp_flash_led *led,
- struct device_node *node)
- {
- int rc;
- u32 val;
- led->pdata->warmup_delay = FLASH_LED_WARMUP_DELAY_DEFAULT;
- rc = of_property_read_u32(node, "qcom,warmup-delay-us", &val);
- if (!rc) {
- led->pdata->warmup_delay =
- val >> FLASH_LED_ISC_WARMUP_DELAY_SHIFT;
- } else if (rc != -EINVAL) {
- pr_err("Unable to read WARMUP delay, rc=%d\n", rc);
- return rc;
- }
- return 0;
- }
- static void qpnp_flash_led_parse_irqs_dt(struct qpnp_flash_led *led,
- struct device_node *node)
- {
- led->pdata->all_ramp_up_done_irq =
- of_irq_get_byname(node, "all-ramp-up-done-irq");
- if (led->pdata->all_ramp_up_done_irq < 0)
- pr_debug("all-ramp-up-done-irq not used\n");
- led->pdata->all_ramp_down_done_irq =
- of_irq_get_byname(node, "all-ramp-down-done-irq");
- if (led->pdata->all_ramp_down_done_irq < 0)
- pr_debug("all-ramp-down-done-irq not used\n");
- led->pdata->led_fault_irq =
- of_irq_get_byname(node, "led-fault-irq");
- if (led->pdata->led_fault_irq < 0)
- pr_debug("led-fault-irq not used\n");
- }
- static int qpnp_flash_led_isc_delay_dt(struct qpnp_flash_led *led,
- struct device_node *node)
- {
- int rc;
- u32 val;
- led->pdata->isc_delay = FLASH_LED_ISC_DELAY_DEFAULT;
- rc = of_property_read_u32(node, "qcom,isc-delay-us", &val);
- if (!rc) {
- led->pdata->isc_delay =
- val >> FLASH_LED_ISC_WARMUP_DELAY_SHIFT;
- } else if (rc != -EINVAL) {
- pr_err("Unable to read ISC delay, rc=%d\n", rc);
- return rc;
- }
- return 0;
- }
- static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led,
- struct device_node *node)
- {
- int rc;
- u32 val;
- rc = of_property_read_u32(node, "reg", &val);
- if (rc < 0) {
- pr_err("Couldn't find reg in node %s, rc = %d\n",
- node->full_name, rc);
- return rc;
- }
- led->base = val;
- led->pdata->hdrm_auto_mode_en = of_property_read_bool(node,
- "qcom,hdrm-auto-mode");
- rc = qpnp_flash_led_isc_delay_dt(led, node);
- if (rc < 0)
- return rc;
- rc = qpnp_flash_led_parse_warmup_delay_dt(led, node);
- if (rc < 0)
- return rc;
- qpnp_flash_led_parse_fault_detection_dt(led, node);
- rc = qpnp_flash_led_parse_thermal_config_dt(led, node);
- if (rc < 0)
- return rc;
- rc = qpnp_flash_led_parse_vph_droop_config_dt(led, node);
- if (rc < 0)
- return rc;
- rc = qpnp_flash_led_parse_iclamp_config_dt(led, node);
- if (rc < 0)
- return rc;
- led->pdata->hw_strobe_option = -EINVAL;
- rc = of_property_read_u32(node, "qcom,hw-strobe-option", &val);
- if (!rc) {
- led->pdata->hw_strobe_option = val;
- } else if (rc != -EINVAL) {
- pr_err("Unable to parse hw strobe option, rc=%d\n", rc);
- return rc;
- }
- led->pdata->vled_max_uv = FLASH_LED_VLED_MAX_DEFAULT_UV;
- rc = of_property_read_u32(node, "qcom,vled-max-uv", &val);
- if (!rc) {
- led->pdata->vled_max_uv = val;
- } else if (rc != -EINVAL) {
- pr_err("Unable to parse vled_max voltage, rc=%d\n", rc);
- return rc;
- }
- val = FLASH_LED_RAMP_STEP_DEFAULT_NS;
- rc = of_property_read_u32(node, "qcom,ramp-up-step", &val);
- if (!rc && (val < FLASH_LED_RAMP_STEP_MIN_NS || val > FLASH_LED_RAMP_STEP_MAX_NS)) {
- pr_err("Invalid ramp-up-step %d\n", val);
- return -EINVAL;
- } else if (rc && rc != -EINVAL) {
- pr_err("Unable to read ramp-up-step, rc=%d\n", rc);
- return rc;
- }
- led->pdata->ramp_up_step = ilog2(val / 100) - 1;
- val = FLASH_LED_RAMP_STEP_DEFAULT_NS;
- rc = of_property_read_u32(node, "qcom,ramp-down-step", &val);
- if (!rc && (val < FLASH_LED_RAMP_STEP_MIN_NS || val > FLASH_LED_RAMP_STEP_MAX_NS)) {
- pr_err("Invalid ramp-down-step %d\n", val);
- return -EINVAL;
- } else if (rc && rc != -EINVAL) {
- pr_err("Unable to read ramp-down-step, rc=%d\n", rc);
- return rc;
- }
- led->pdata->ramp_down_step = ilog2(val / 100) - 1;
- rc = qpnp_flash_led_parse_battery_prop_dt(led, node);
- if (rc < 0)
- return rc;
- rc = qpnp_flash_led_parse_lmh_config_dt(led, node);
- if (rc < 0)
- return rc;
- rc = qpnp_flash_led_parse_chgr_mitigation_dt(led, node);
- if (rc < 0)
- return rc;
- rc = qpnp_flash_led_parse_iled_threshold_dt(led, node);
- if (rc < 0)
- return rc;
- led->pdata->bst_pwm_ovrhd_uv = FLASH_BST_PWM_OVRHD_MIN_UV;
- rc = of_property_read_u32(node, "qcom,bst-pwm-ovrhd-uv", &val);
- if (!rc) {
- if (val >= FLASH_BST_PWM_OVRHD_MIN_UV &&
- val <= FLASH_BST_PWM_OVRHD_MAX_UV)
- led->pdata->bst_pwm_ovrhd_uv = val;
- }
- qpnp_flash_led_parse_irqs_dt(led, node);
- return 0;
- }
- static int qpnp_flash_led_register_interrupts(struct qpnp_flash_led *led)
- {
- int rc;
- /* setup irqs */
- if (led->pdata->all_ramp_up_done_irq >= 0) {
- rc = devm_request_threaded_irq(&led->pdev->dev,
- led->pdata->all_ramp_up_done_irq,
- NULL, qpnp_flash_led_irq_handler,
- IRQF_ONESHOT,
- "qpnp_flash_led_all_ramp_up_done_irq", led);
- if (rc < 0) {
- pr_err("Unable to request all_ramp_up_done(%d) IRQ(err:%d)\n",
- led->pdata->all_ramp_up_done_irq, rc);
- return rc;
- }
- }
- if (led->pdata->all_ramp_down_done_irq >= 0) {
- rc = devm_request_threaded_irq(&led->pdev->dev,
- led->pdata->all_ramp_down_done_irq,
- NULL, qpnp_flash_led_irq_handler,
- IRQF_ONESHOT,
- "qpnp_flash_led_all_ramp_down_done_irq", led);
- if (rc < 0) {
- pr_err("Unable to request all_ramp_down_done(%d) IRQ(err:%d)\n",
- led->pdata->all_ramp_down_done_irq, rc);
- return rc;
- }
- }
- if (led->pdata->led_fault_irq >= 0) {
- rc = devm_request_threaded_irq(&led->pdev->dev,
- led->pdata->led_fault_irq,
- NULL, qpnp_flash_led_irq_handler,
- IRQF_ONESHOT,
- "qpnp_flash_led_fault_irq", led);
- if (rc < 0) {
- pr_err("Unable to request led_fault(%d) IRQ(err:%d)\n",
- led->pdata->led_fault_irq, rc);
- return rc;
- }
- }
- return 0;
- }
- static void qpnp_flash_led_free_interrupts(struct qpnp_flash_led *led)
- {
- /* free irqs */
- if (led->pdata->all_ramp_up_done_irq >= 0)
- devm_free_irq(&led->pdev->dev,
- led->pdata->all_ramp_up_done_irq,
- led);
- if (led->pdata->all_ramp_down_done_irq >= 0)
- devm_free_irq(&led->pdev->dev,
- led->pdata->all_ramp_down_done_irq,
- led);
- if (led->pdata->led_fault_irq >= 0)
- devm_free_irq(&led->pdev->dev,
- led->pdata->led_fault_irq,
- led);
- }
- static int qpnp_flash_led_probe(struct platform_device *pdev)
- {
- struct qpnp_flash_led *led;
- struct device_node *node, *temp;
- const char *temp_string;
- int rc, i = 0, j = 0;
- node = pdev->dev.of_node;
- if (!node) {
- pr_err("No flash LED nodes defined\n");
- return -ENODEV;
- }
- led = devm_kzalloc(&pdev->dev, sizeof(struct qpnp_flash_led),
- GFP_KERNEL);
- if (!led)
- return -ENOMEM;
- led->regmap = dev_get_regmap(pdev->dev.parent, NULL);
- if (!led->regmap) {
- pr_err("Couldn't get parent's regmap\n");
- return -EINVAL;
- }
- led->pmic_type = (enum pmic_type)(uintptr_t)of_device_get_match_data(&pdev->dev);
- if (led->pmic_type == PM6150L)
- led->wa_flags |= PM6150L_IRES_WA;
- led->pdev = pdev;
- led->pdata = devm_kzalloc(&pdev->dev,
- sizeof(struct flash_led_platform_data), GFP_KERNEL);
- if (!led->pdata)
- return -ENOMEM;
- led->iio_channels = devm_kcalloc(&pdev->dev,
- ARRAY_SIZE(flash_iio_prop_names),
- sizeof(struct iio_channel *), GFP_KERNEL);
- if (!led->iio_channels)
- return -ENOMEM;
- spin_lock_init(&led->lock);
- rc = qpnp_flash_led_parse_common_dt(led, node);
- if (rc < 0) {
- pr_err("Failed to parse common flash LED device tree rc=%d\n",
- rc);
- return rc;
- }
- for_each_available_child_of_node(node, temp) {
- rc = of_property_read_string(temp, "label", &temp_string);
- if (rc < 0) {
- pr_err("Failed to parse label, rc=%d\n", rc);
- return rc;
- }
- if (!strcmp("switch", temp_string)) {
- led->num_snodes++;
- } else if (!strcmp("flash", temp_string) ||
- !strcmp("torch", temp_string)) {
- led->num_fnodes++;
- } else {
- pr_err("Invalid label for led node\n");
- return -EINVAL;
- }
- }
- if (!led->num_fnodes) {
- pr_err("No LED nodes defined\n");
- return -ECHILD;
- }
- led->fnode = devm_kcalloc(&pdev->dev, led->num_fnodes,
- sizeof(*led->fnode), GFP_KERNEL);
- if (!led->fnode)
- return -ENOMEM;
- led->snode = devm_kcalloc(&pdev->dev, led->num_snodes,
- sizeof(*led->snode), GFP_KERNEL);
- if (!led->snode)
- return -ENOMEM;
- temp = NULL;
- i = 0;
- j = 0;
- for_each_available_child_of_node(node, temp) {
- rc = of_property_read_string(temp, "label", &temp_string);
- if (rc < 0) {
- pr_err("Failed to parse label, rc=%d\n", rc);
- return rc;
- }
- if (!strcmp("flash", temp_string) ||
- !strcmp("torch", temp_string)) {
- rc = qpnp_flash_led_parse_each_led_dt(led,
- &led->fnode[i], temp);
- if (rc < 0) {
- pr_err("Unable to parse flash node %d rc=%d\n",
- i, rc);
- goto error_led_register;
- }
- i++;
- }
- if (!strcmp("switch", temp_string)) {
- rc = qpnp_flash_led_parse_and_register_switch(led,
- &led->snode[j], temp);
- if (rc < 0) {
- pr_err("Unable to parse and register switch node, rc=%d\n",
- rc);
- goto error_switch_register;
- }
- j++;
- }
- }
- rc = qpnp_flash_led_register_interrupts(led);
- if (rc < 0)
- goto error_switch_register;
- rc = qpnp_flash_led_init_settings(led);
- if (rc < 0) {
- pr_err("Failed to initialize flash LED, rc=%d\n", rc);
- goto error_switch_register;
- }
- for (i = 0; i < led->num_snodes; i++) {
- for (j = 0; j < ARRAY_SIZE(qpnp_flash_led_attrs); j++) {
- rc = sysfs_create_file(&led->snode[i].cdev.dev->kobj,
- &qpnp_flash_led_attrs[j].attr);
- if (rc < 0) {
- pr_err("sysfs creation failed, rc=%d\n", rc);
- goto sysfs_fail;
- }
- }
- }
- dev_set_drvdata(&pdev->dev, led);
- return 0;
- sysfs_fail:
- for (--j; j >= 0; j--)
- sysfs_remove_file(&led->snode[i].cdev.dev->kobj,
- &qpnp_flash_led_attrs[j].attr);
- for (--i; i >= 0; i--) {
- for (j = 0; j < ARRAY_SIZE(qpnp_flash_led_attrs); j++)
- sysfs_remove_file(&led->snode[i].cdev.dev->kobj,
- &qpnp_flash_led_attrs[j].attr);
- }
- i = led->num_snodes;
- error_switch_register:
- while (i > 0)
- led_classdev_unregister(&led->snode[--i].cdev);
- i = led->num_fnodes;
- error_led_register:
- while (i > 0)
- led_classdev_unregister(&led->fnode[--i].cdev);
- return rc;
- }
- static int qpnp_flash_led_remove(struct platform_device *pdev)
- {
- struct qpnp_flash_led *led = dev_get_drvdata(&pdev->dev);
- int i, j;
- for (i = 0; i < led->num_snodes; i++) {
- for (j = 0; j < ARRAY_SIZE(qpnp_flash_led_attrs); j++)
- sysfs_remove_file(&led->snode[i].cdev.dev->kobj,
- &qpnp_flash_led_attrs[j].attr);
- if (led->snode[i].regulator_on)
- qpnp_flash_led_regulator_enable(led,
- &led->snode[i], false);
- }
- while (i > 0)
- led_classdev_unregister(&led->snode[--i].cdev);
- i = led->num_fnodes;
- while (i > 0)
- led_classdev_unregister(&led->fnode[--i].cdev);
- power_supply_unreg_notifier(&led->nb);
- return 0;
- }
- static int qpnp_flash_led_freeze(struct device *dev)
- {
- struct qpnp_flash_led *led = dev_get_drvdata(dev);
- qpnp_flash_led_free_interrupts(led);
- return 0;
- }
- static int qpnp_flash_led_restore(struct device *dev)
- {
- struct qpnp_flash_led *led = dev_get_drvdata(dev);
- int rc = 0;
- rc = qpnp_flash_led_init_settings(led);
- if (rc < 0) {
- pr_err("Flash setting re-init failed in Restore rc= %d\n", rc);
- return rc;
- }
- rc = qpnp_flash_led_register_interrupts(led);
- if (rc < 0)
- pr_err("Interrupt re-registration failed in Restore rc= %d\n", rc);
- return rc;
- }
- static const struct dev_pm_ops qpnp_flash_led_pm_ops = {
- .freeze = qpnp_flash_led_freeze,
- .restore = qpnp_flash_led_restore,
- };
- const struct of_device_id qpnp_flash_led_match_table[] = {
- { .compatible = "qcom,pm6150l-flash-led-v2", .data = (void *)PM6150L},
- { .compatible = "qcom,pmi632-flash-led-v2", .data = (void *)PMI632},
- { },
- };
- static struct platform_driver qpnp_flash_led_driver = {
- .driver = {
- .name = "qcom,qpnp-flash-led-v2",
- .of_match_table = qpnp_flash_led_match_table,
- .pm = &qpnp_flash_led_pm_ops,
- },
- .probe = qpnp_flash_led_probe,
- .remove = qpnp_flash_led_remove,
- };
- module_platform_driver(qpnp_flash_led_driver);
- MODULE_DESCRIPTION("QPNP Flash LED driver v2");
- MODULE_LICENSE("GPL");
- MODULE_ALIAS("leds:leds-qpnp-flash-v2");
|