Something went wrong. Try again.
(I'm so sorry!) Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488// SPDX-License-Identifier: GPL-2.0//// Register map access API//// Copyright 2011 Wolfson Microelectronics plc//// Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
#include <linux/device.h>#include <linux/slab.h>#include <linux/export.h>#include <linux/mutex.h>#include <linux/err.h>#include <linux/property.h>#include <linux/rbtree.h>#include <linux/sched.h>#include <linux/delay.h>#include <linux/log2.h>#include <linux/hwspinlock.h>#include <linux/unaligned.h>
#define CREATE_TRACE_POINTS#include "trace.h"
#include "internal.h"
/* * Sometimes for failures during very early init the trace * infrastructure isn't available early enough to be used. For this * sort of problem defining LOG_DEVICE will add printks for basic * register I/O on a specific device. */#undef LOG_DEVICE
#ifdef LOG_DEVICEstatic inline bool regmap_should_log(struct regmap *map){ return (map->dev && strcmp(dev_name(map->dev), LOG_DEVICE) == 0);}#elsestatic inline bool regmap_should_log(struct regmap *map) { return false; }#endif
static int _regmap_update_bits(struct regmap *map, unsigned int reg, unsigned int mask, unsigned int val, bool *change, bool force_write);
static int _regmap_bus_reg_read(void *context, unsigned int reg, unsigned int *val);static int _regmap_bus_read(void *context, unsigned int reg, unsigned int *val);static int _regmap_bus_formatted_write(void *context, unsigned int reg, unsigned int val);static int _regmap_bus_reg_write(void *context, unsigned int reg, unsigned int val);static int _regmap_bus_raw_write(void *context, unsigned int reg, unsigned int val);
bool regmap_reg_in_ranges(unsigned int reg, const struct regmap_range *ranges, unsigned int nranges){ const struct regmap_range *r; int i;
for (i = 0, r = ranges; i < nranges; i++, r++) if (regmap_reg_in_range(reg, r)) return true; return false;}EXPORT_SYMBOL_GPL(regmap_reg_in_ranges);
bool regmap_check_range_table(struct regmap *map, unsigned int reg, const struct regmap_access_table *table){ /* Check "no ranges" first */ if (regmap_reg_in_ranges(reg, table->no_ranges, table->n_no_ranges)) return false;
/* In case zero "yes ranges" are supplied, any reg is OK */ if (!table->n_yes_ranges) return true;
return regmap_reg_in_ranges(reg, table->yes_ranges, table->n_yes_ranges);}EXPORT_SYMBOL_GPL(regmap_check_range_table);
bool regmap_writeable(struct regmap *map, unsigned int reg){ if (map->max_register_is_set && reg > map->max_register) return false;
if (map->writeable_reg) return map->writeable_reg(map->dev, reg);
if (map->wr_table) return regmap_check_range_table(map, reg, map->wr_table);
return true;}
bool regmap_cached(struct regmap *map, unsigned int reg){ int ret; unsigned int val;
if (map->cache_type == REGCACHE_NONE) return false;
if (!map->cache_ops) return false;
if (map->max_register_is_set && reg > map->max_register) return false;
scoped_guard(regmap, map) ret = regcache_read(map, reg, &val); if (ret) return false;
return true;}
bool regmap_readable(struct regmap *map, unsigned int reg){ if (!map->reg_read) return false;
if (map->max_register_is_set && reg > map->max_register) return false;
if (map->format.format_write) return false;
if (map->readable_reg) return map->readable_reg(map->dev, reg);
if (map->rd_table) return regmap_check_range_table(map, reg, map->rd_table);
return true;}
bool regmap_volatile(struct regmap *map, unsigned int reg){ if (!map->format.format_write && !regmap_readable(map, reg)) return false;
if (map->volatile_reg) return map->volatile_reg(map->dev, reg);
if (map->volatile_table) return regmap_check_range_table(map, reg, map->volatile_table);
if (map->cache_ops) return false; else return true;}
bool regmap_precious(struct regmap *map, unsigned int reg){ if (!regmap_readable(map, reg)) return false;
if (map->precious_reg) return map->precious_reg(map->dev, reg);
if (map->precious_table) return regmap_check_range_table(map, reg, map->precious_table);
return false;}
bool regmap_writeable_noinc(struct regmap *map, unsigned int reg){ if (map->writeable_noinc_reg) return map->writeable_noinc_reg(map->dev, reg);
if (map->wr_noinc_table) return regmap_check_range_table(map, reg, map->wr_noinc_table);
return true;}
bool regmap_readable_noinc(struct regmap *map, unsigned int reg){ if (map->readable_noinc_reg) return map->readable_noinc_reg(map->dev, reg);
if (map->rd_noinc_table) return regmap_check_range_table(map, reg, map->rd_noinc_table);
return true;}
static bool regmap_volatile_range(struct regmap *map, unsigned int reg, size_t num){ unsigned int i;
for (i = 0; i < num; i++) if (!regmap_volatile(map, reg + regmap_get_offset(map, i))) return false;
return true;}
static void regmap_format_12_20_write(struct regmap *map, unsigned int reg, unsigned int val){ u8 *out = map->work_buf;
out[0] = reg >> 4; out[1] = (reg << 4) | (val >> 16); out[2] = val >> 8; out[3] = val;}
static void regmap_format_2_6_write(struct regmap *map, unsigned int reg, unsigned int val){ u8 *out = map->work_buf;
*out = (reg << 6) | val;}
static void regmap_format_4_12_write(struct regmap *map, unsigned int reg, unsigned int val){ __be16 *out = map->work_buf; *out = cpu_to_be16((reg << 12) | val);}
static void regmap_format_7_9_write(struct regmap *map, unsigned int reg, unsigned int val){ __be16 *out = map->work_buf; *out = cpu_to_be16((reg << 9) | val);}
static void regmap_format_7_17_write(struct regmap *map, unsigned int reg, unsigned int val){ u8 *out = map->work_buf;
out[2] = val; out[1] = val >> 8; out[0] = (val >> 16) | (reg << 1);}
static void regmap_format_10_14_write(struct regmap *map, unsigned int reg, unsigned int val){ u8 *out = map->work_buf;
out[2] = val; out[1] = (val >> 8) | (reg << 6); out[0] = reg >> 2;}
static void regmap_format_8(void *buf, unsigned int val, unsigned int shift){ u8 *b = buf;
b[0] = val << shift;}
static void regmap_format_16_be(void *buf, unsigned int val, unsigned int shift){ put_unaligned_be16(val << shift, buf);}
static void regmap_format_16_le(void *buf, unsigned int val, unsigned int shift){ put_unaligned_le16(val << shift, buf);}
static void regmap_format_16_native(void *buf, unsigned int val, unsigned int shift){ u16 v = val << shift;
memcpy(buf, &v, sizeof(v));}
static void regmap_format_24_be(void *buf, unsigned int val, unsigned int shift){ put_unaligned_be24(val << shift, buf);}
static void regmap_format_32_be(void *buf, unsigned int val, unsigned int shift){ put_unaligned_be32(val << shift, buf);}
static void regmap_format_32_le(void *buf, unsigned int val, unsigned int shift){ put_unaligned_le32(val << shift, buf);}
static void regmap_format_32_native(void *buf, unsigned int val, unsigned int shift){ u32 v = val << shift;
memcpy(buf, &v, sizeof(v));}
static void regmap_parse_inplace_noop(void *buf){}
static unsigned int regmap_parse_8(const void *buf){ const u8 *b = buf;
return b[0];}
static unsigned int regmap_parse_16_be(const void *buf){ return get_unaligned_be16(buf);}
static unsigned int regmap_parse_16_le(const void *buf){ return get_unaligned_le16(buf);}
static void regmap_parse_16_be_inplace(void *buf){ u16 v = get_unaligned_be16(buf);
memcpy(buf, &v, sizeof(v));}
static void regmap_parse_16_le_inplace(void *buf){ u16 v = get_unaligned_le16(buf);
memcpy(buf, &v, sizeof(v));}
static unsigned int regmap_parse_16_native(const void *buf){ u16 v;
memcpy(&v, buf, sizeof(v)); return v;}
static unsigned int regmap_parse_24_be(const void *buf){ return get_unaligned_be24(buf);}
static unsigned int regmap_parse_32_be(const void *buf){ return get_unaligned_be32(buf);}
static unsigned int regmap_parse_32_le(const void *buf){ return get_unaligned_le32(buf);}
static void regmap_parse_32_be_inplace(void *buf){ u32 v = get_unaligned_be32(buf);
memcpy(buf, &v, sizeof(v));}
static void regmap_parse_32_le_inplace(void *buf){ u32 v = get_unaligned_le32(buf);
memcpy(buf, &v, sizeof(v));}
static unsigned int regmap_parse_32_native(const void *buf){ u32 v;
memcpy(&v, buf, sizeof(v)); return v;}
static void regmap_lock_hwlock(void *__map){ struct regmap *map = __map;
hwspin_lock_timeout(map->hwlock, UINT_MAX);}
static void regmap_lock_hwlock_irq(void *__map){ struct regmap *map = __map;
hwspin_lock_timeout_irq(map->hwlock, UINT_MAX);}
static void regmap_lock_hwlock_irqsave(void *__map){ struct regmap *map = __map; unsigned long flags = 0;
hwspin_lock_timeout_irqsave(map->hwlock, UINT_MAX, &flags); map->spinlock_flags = flags;}
static void regmap_unlock_hwlock(void *__map){ struct regmap *map = __map;
hwspin_unlock(map->hwlock);}
static void regmap_unlock_hwlock_irq(void *__map){ struct regmap *map = __map;
hwspin_unlock_irq(map->hwlock);}
static void regmap_unlock_hwlock_irqrestore(void *__map){ struct regmap *map = __map;
hwspin_unlock_irqrestore(map->hwlock, &map->spinlock_flags);}
static void regmap_lock_unlock_none(void *__map){
}
static void regmap_lock_mutex(void *__map){ struct regmap *map = __map; mutex_lock(&map->mutex);}
static void regmap_unlock_mutex(void *__map){ struct regmap *map = __map; mutex_unlock(&map->mutex);}
static void regmap_lock_spinlock(void *__map)__acquires(&map->spinlock){ struct regmap *map = __map; unsigned long flags;
spin_lock_irqsave(&map->spinlock, flags); map->spinlock_flags = flags;}
static void regmap_unlock_spinlock(void *__map)__releases(&map->spinlock){ struct regmap *map = __map; spin_unlock_irqrestore(&map->spinlock, map->spinlock_flags);}
static void regmap_lock_raw_spinlock(void *__map)__acquires(&map->raw_spinlock){ struct regmap *map = __map; unsigned long flags;
raw_spin_lock_irqsave(&map->raw_spinlock, flags); map->raw_spinlock_flags = flags;}
static void regmap_unlock_raw_spinlock(void *__map)__releases(&map->raw_spinlock){ struct regmap *map = __map; raw_spin_unlock_irqrestore(&map->raw_spinlock, map->raw_spinlock_flags);}
static void dev_get_regmap_release(struct device *dev, void *res){ /* * We don't actually have anything to do here; the goal here * is not to manage the regmap but to provide a simple way to * get the regmap back given a struct device. */}
static bool _regmap_range_add(struct regmap *map, struct regmap_range_node *data){ struct rb_root *root = &map->range_tree; struct rb_node **new = &(root->rb_node), *parent = NULL;
while (*new) { struct regmap_range_node *this = rb_entry(*new, struct regmap_range_node, node);
parent = *new; if (data->range_max < this->range_min) new = &((*new)->rb_left); else if (data->range_min > this->range_max) new = &((*new)->rb_right); else return false; }
rb_link_node(&data->node, parent, new); rb_insert_color(&data->node, root);
return true;}
static struct regmap_range_node *_regmap_range_lookup(struct regmap *map, unsigned int reg){ struct rb_node *node = map->range_tree.rb_node;
while (node) { struct regmap_range_node *this = rb_entry(node, struct regmap_range_node, node);
if (reg < this->range_min) node = node->rb_left; else if (reg > this->range_max) node = node->rb_right; else return this; }
return NULL;}
static void regmap_range_exit(struct regmap *map){ struct rb_node *next; struct regmap_range_node *range_node;
next = rb_first(&map->range_tree); while (next) { range_node = rb_entry(next, struct regmap_range_node, node); next = rb_next(&range_node->node); rb_erase(&range_node->node, &map->range_tree); kfree(range_node); }
kfree(map->selector_work_buf);}
static int regmap_set_name(struct regmap *map, const struct regmap_config *config){ if (config->name) { const char *name = kstrdup_const(config->name, GFP_KERNEL);
if (!name) return -ENOMEM;
kfree_const(map->name); map->name = name; }
return 0;}
int regmap_attach_dev(struct device *dev, struct regmap *map, const struct regmap_config *config){ struct regmap **m; int ret;
map->dev = dev;
ret = regmap_set_name(map, config); if (ret) return ret;
regmap_debugfs_exit(map); regmap_debugfs_init(map);
/* Add a devres resource for dev_get_regmap() */ m = devres_alloc(dev_get_regmap_release, sizeof(*m), GFP_KERNEL); if (!m) { regmap_debugfs_exit(map); return -ENOMEM; } *m = map; devres_add(dev, m);
return 0;}EXPORT_SYMBOL_GPL(regmap_attach_dev);
static int dev_get_regmap_match(struct device *dev, void *res, void *data);
static int regmap_detach_dev(struct device *dev, struct regmap *map){ if (!dev) return 0;
return devres_release(dev, dev_get_regmap_release, dev_get_regmap_match, (void *)map->name);}
static enum regmap_endian regmap_get_reg_endian(const struct regmap_bus *bus, const struct regmap_config *config){ enum regmap_endian endian;
/* Retrieve the endianness specification from the regmap config */ endian = config->reg_format_endian;
/* If the regmap config specified a non-default value, use that */ if (endian != REGMAP_ENDIAN_DEFAULT) return endian;
/* Retrieve the endianness specification from the bus config */ if (bus && bus->reg_format_endian_default) endian = bus->reg_format_endian_default;
/* If the bus specified a non-default value, use that */ if (endian != REGMAP_ENDIAN_DEFAULT) return endian;
/* Use this if no other value was found */ return REGMAP_ENDIAN_BIG;}
enum regmap_endian regmap_get_val_endian(struct device *dev, const struct regmap_bus *bus, const struct regmap_config *config){ struct fwnode_handle *fwnode = dev ? dev_fwnode(dev) : NULL; enum regmap_endian endian;
/* Retrieve the endianness specification from the regmap config */ endian = config->val_format_endian;
/* If the regmap config specified a non-default value, use that */ if (endian != REGMAP_ENDIAN_DEFAULT) return endian;
/* If the firmware node exist try to get endianness from it */ if (fwnode_property_read_bool(fwnode, "big-endian")) endian = REGMAP_ENDIAN_BIG; else if (fwnode_property_read_bool(fwnode, "little-endian")) endian = REGMAP_ENDIAN_LITTLE; else if (fwnode_property_read_bool(fwnode, "native-endian")) endian = REGMAP_ENDIAN_NATIVE;
/* If the endianness was specified in fwnode, use that */ if (endian != REGMAP_ENDIAN_DEFAULT) return endian;
/* Retrieve the endianness specification from the bus config */ if (bus && bus->val_format_endian_default) endian = bus->val_format_endian_default;
/* If the bus specified a non-default value, use that */ if (endian != REGMAP_ENDIAN_DEFAULT) return endian;
/* Use this if no other value was found */ return REGMAP_ENDIAN_BIG;}EXPORT_SYMBOL_GPL(regmap_get_val_endian);
struct regmap *__regmap_init(struct device *dev, const struct regmap_bus *bus, void *bus_context, const struct regmap_config *config, struct lock_class_key *lock_key, const char *lock_name){ struct regmap *map; int ret = -EINVAL; enum regmap_endian reg_endian, val_endian; int i, j;
if (!config) goto err;
map = kzalloc_obj(*map); if (map == NULL) { ret = -ENOMEM; goto err; }
ret = regmap_set_name(map, config); if (ret) goto err_map;
ret = -EINVAL; /* Later error paths rely on this */
if (config->disable_locking) { map->lock = map->unlock = regmap_lock_unlock_none; map->can_sleep = config->can_sleep; regmap_debugfs_disable(map); } else if (config->lock && config->unlock) { map->lock = config->lock; map->unlock = config->unlock; map->lock_arg = config->lock_arg; map->can_sleep = config->can_sleep; } else if (config->use_hwlock) { map->hwlock = hwspin_lock_request_specific(config->hwlock_id); if (!map->hwlock) { ret = -ENXIO; goto err_name; }
switch (config->hwlock_mode) { case HWLOCK_IRQSTATE: map->lock = regmap_lock_hwlock_irqsave; map->unlock = regmap_unlock_hwlock_irqrestore; break; case HWLOCK_IRQ: map->lock = regmap_lock_hwlock_irq; map->unlock = regmap_unlock_hwlock_irq; break; default: map->lock = regmap_lock_hwlock; map->unlock = regmap_unlock_hwlock; break; }
map->lock_arg = map; } else { if ((bus && bus->fast_io) || config->fast_io) { if (config->use_raw_spinlock) { raw_spin_lock_init(&map->raw_spinlock); map->lock = regmap_lock_raw_spinlock; map->unlock = regmap_unlock_raw_spinlock; lockdep_set_class_and_name(&map->raw_spinlock, lock_key, lock_name); } else { spin_lock_init(&map->spinlock); map->lock = regmap_lock_spinlock; map->unlock = regmap_unlock_spinlock; lockdep_set_class_and_name(&map->spinlock, lock_key, lock_name); } } else { mutex_init(&map->mutex); map->lock = regmap_lock_mutex; map->unlock = regmap_unlock_mutex; map->can_sleep = true; lockdep_set_class_and_name(&map->mutex, lock_key, lock_name); } map->lock_arg = map; map->lock_key = lock_key; }
/* * When we write in fast-paths with regmap_bulk_write() don't allocate * scratch buffers with sleeping allocations. */ if ((bus && bus->fast_io) || config->fast_io) map->alloc_flags = GFP_ATOMIC; else map->alloc_flags = GFP_KERNEL;
map->reg_base = config->reg_base; map->reg_shift = config->pad_bits % 8;
map->format.pad_bytes = config->pad_bits / 8; map->format.reg_shift = config->reg_shift; map->format.reg_bytes = BITS_TO_BYTES(config->reg_bits); map->format.val_bytes = BITS_TO_BYTES(config->val_bits); map->format.buf_size = BITS_TO_BYTES(config->reg_bits + config->val_bits + config->pad_bits); if (config->reg_stride) map->reg_stride = config->reg_stride; else map->reg_stride = 1; if (is_power_of_2(map->reg_stride)) map->reg_stride_order = ilog2(map->reg_stride); else map->reg_stride_order = -1; map->use_single_read = config->use_single_read || !(config->read || (bus && bus->read)); map->use_single_write = config->use_single_write || !(config->write || (bus && bus->write)); map->can_multi_write = config->can_multi_write && (config->write || (bus && bus->write)); if (bus) { map->max_raw_read = bus->max_raw_read; map->max_raw_write = bus->max_raw_write; } else if (config->max_raw_read && config->max_raw_write) { map->max_raw_read = config->max_raw_read; map->max_raw_write = config->max_raw_write; } map->dev = dev; map->bus = bus; map->bus_context = bus_context; map->max_register = config->max_register; map->max_register_is_set = map->max_register ?: config->max_register_is_0; map->wr_table = config->wr_table; map->rd_table = config->rd_table; map->volatile_table = config->volatile_table; map->precious_table = config->precious_table; map->wr_noinc_table = config->wr_noinc_table; map->rd_noinc_table = config->rd_noinc_table; map->writeable_reg = config->writeable_reg; map->readable_reg = config->readable_reg; map->volatile_reg = config->volatile_reg; map->precious_reg = config->precious_reg; map->writeable_noinc_reg = config->writeable_noinc_reg; map->readable_noinc_reg = config->readable_noinc_reg; map->reg_default_cb = config->reg_default_cb; map->cache_type = config->cache_type;
spin_lock_init(&map->async_lock); INIT_LIST_HEAD(&map->async_list); INIT_LIST_HEAD(&map->async_free); init_waitqueue_head(&map->async_waitq);
if (config->read_flag_mask || config->write_flag_mask || config->zero_flag_mask) { map->read_flag_mask = config->read_flag_mask; map->write_flag_mask = config->write_flag_mask; } else if (bus) { map->read_flag_mask = bus->read_flag_mask; }
if (config->read && config->write) { map->reg_read = _regmap_bus_read; if (config->reg_update_bits) map->reg_update_bits = config->reg_update_bits;
/* Bulk read/write */ map->read = config->read; map->write = config->write;
reg_endian = REGMAP_ENDIAN_NATIVE; val_endian = REGMAP_ENDIAN_NATIVE; } else if (!bus) { map->reg_read = config->reg_read; map->reg_write = config->reg_write; map->reg_update_bits = config->reg_update_bits;
map->defer_caching = false; goto skip_format_initialization; } else if (!bus->read || !bus->write) { map->reg_read = _regmap_bus_reg_read; map->reg_write = _regmap_bus_reg_write; map->reg_update_bits = bus->reg_update_bits;
map->defer_caching = false; goto skip_format_initialization; } else { map->reg_read = _regmap_bus_read; map->reg_update_bits = bus->reg_update_bits; /* Bulk read/write */ map->read = bus->read; map->write = bus->write;
reg_endian = regmap_get_reg_endian(bus, config); val_endian = regmap_get_val_endian(dev, bus, config); }
switch (config->reg_bits + map->reg_shift) { case 2: switch (config->val_bits) { case 6: map->format.format_write = regmap_format_2_6_write; break; default: goto err_hwlock; } break;
case 4: switch (config->val_bits) { case 12: map->format.format_write = regmap_format_4_12_write; break; default: goto err_hwlock; } break;
case 7: switch (config->val_bits) { case 9: map->format.format_write = regmap_format_7_9_write; break; case 17: map->format.format_write = regmap_format_7_17_write; break; default: goto err_hwlock; } break;
case 10: switch (config->val_bits) { case 14: map->format.format_write = regmap_format_10_14_write; break; default: goto err_hwlock; } break;
case 12: switch (config->val_bits) { case 20: map->format.format_write = regmap_format_12_20_write; break; default: goto err_hwlock; } break;
case 8: map->format.format_reg = regmap_format_8; break;
case 16: switch (reg_endian) { case REGMAP_ENDIAN_BIG: map->format.format_reg = regmap_format_16_be; break; case REGMAP_ENDIAN_LITTLE: map->format.format_reg = regmap_format_16_le; break; case REGMAP_ENDIAN_NATIVE: map->format.format_reg = regmap_format_16_native; break; default: goto err_hwlock; } break;
case 24: switch (reg_endian) { case REGMAP_ENDIAN_BIG: map->format.format_reg = regmap_format_24_be; break; default: goto err_hwlock; } break;
case 32: switch (reg_endian) { case REGMAP_ENDIAN_BIG: map->format.format_reg = regmap_format_32_be; break; case REGMAP_ENDIAN_LITTLE: map->format.format_reg = regmap_format_32_le; break; case REGMAP_ENDIAN_NATIVE: map->format.format_reg = regmap_format_32_native; break; default: goto err_hwlock; } break;
default: goto err_hwlock; }
if (val_endian == REGMAP_ENDIAN_NATIVE) map->format.parse_inplace = regmap_parse_inplace_noop;
switch (config->val_bits) { case 8: map->format.format_val = regmap_format_8; map->format.parse_val = regmap_parse_8; map->format.parse_inplace = regmap_parse_inplace_noop; break; case 16: switch (val_endian) { case REGMAP_ENDIAN_BIG: map->format.format_val = regmap_format_16_be; map->format.parse_val = regmap_parse_16_be; map->format.parse_inplace = regmap_parse_16_be_inplace; break; case REGMAP_ENDIAN_LITTLE: map->format.format_val = regmap_format_16_le; map->format.parse_val = regmap_parse_16_le; map->format.parse_inplace = regmap_parse_16_le_inplace; break; case REGMAP_ENDIAN_NATIVE: map->format.format_val = regmap_format_16_native; map->format.parse_val = regmap_parse_16_native; break; default: goto err_hwlock; } break; case 24: switch (val_endian) { case REGMAP_ENDIAN_BIG: map->format.format_val = regmap_format_24_be; map->format.parse_val = regmap_parse_24_be; break; default: goto err_hwlock; } break; case 32: switch (val_endian) { case REGMAP_ENDIAN_BIG: map->format.format_val = regmap_format_32_be; map->format.parse_val = regmap_parse_32_be; map->format.parse_inplace = regmap_parse_32_be_inplace; break; case REGMAP_ENDIAN_LITTLE: map->format.format_val = regmap_format_32_le; map->format.parse_val = regmap_parse_32_le; map->format.parse_inplace = regmap_parse_32_le_inplace; break; case REGMAP_ENDIAN_NATIVE: map->format.format_val = regmap_format_32_native; map->format.parse_val = regmap_parse_32_native; break; default: goto err_hwlock; } break; }
if (map->format.format_write) { if ((reg_endian != REGMAP_ENDIAN_BIG) || (val_endian != REGMAP_ENDIAN_BIG)) goto err_hwlock; map->use_single_write = true; }
if (!map->format.format_write && !(map->format.format_reg && map->format.format_val)) goto err_hwlock;
map->work_buf = kzalloc(map->format.buf_size, GFP_KERNEL); if (map->work_buf == NULL) { ret = -ENOMEM; goto err_hwlock; }
if (map->format.format_write) { map->defer_caching = false; map->reg_write = _regmap_bus_formatted_write; } else if (map->format.format_val) { map->defer_caching = true; map->reg_write = _regmap_bus_raw_write; }
skip_format_initialization:
map->range_tree = RB_ROOT; for (i = 0; i < config->num_ranges; i++) { const struct regmap_range_cfg *range_cfg = &config->ranges[i]; struct regmap_range_node *new;
/* Sanity check */ if (range_cfg->range_max < range_cfg->range_min) { dev_err(map->dev, "Invalid range %d: %u < %u\n", i, range_cfg->range_max, range_cfg->range_min); goto err_range; }
if (range_cfg->range_max > map->max_register) { dev_err(map->dev, "Invalid range %d: %u > %u\n", i, range_cfg->range_max, map->max_register); goto err_range; }
if (range_cfg->selector_reg > map->max_register) { dev_err(map->dev, "Invalid range %d: selector out of map\n", i); goto err_range; }
if (range_cfg->window_len == 0) { dev_err(map->dev, "Invalid range %d: window_len 0\n", i); goto err_range; }
/* Make sure, that this register range has no selector or data window within its boundary */ for (j = 0; j < config->num_ranges; j++) { unsigned int sel_reg = config->ranges[j].selector_reg; unsigned int win_min = config->ranges[j].window_start; unsigned int win_max = win_min + config->ranges[j].window_len - 1;
/* Allow data window inside its own virtual range */ if (j == i) continue;
if (range_cfg->range_min <= sel_reg && sel_reg <= range_cfg->range_max) { dev_err(map->dev, "Range %d: selector for %d in window\n", i, j); goto err_range; }
if (!(win_max < range_cfg->range_min || win_min > range_cfg->range_max)) { dev_err(map->dev, "Range %d: window for %d in window\n", i, j); goto err_range; } }
new = kzalloc_obj(*new); if (new == NULL) { ret = -ENOMEM; goto err_range; }
new->map = map; new->name = range_cfg->name; new->range_min = range_cfg->range_min; new->range_max = range_cfg->range_max; new->selector_reg = range_cfg->selector_reg; new->selector_mask = range_cfg->selector_mask; new->selector_shift = range_cfg->selector_shift; new->window_start = range_cfg->window_start; new->window_len = range_cfg->window_len;
if (!_regmap_range_add(map, new)) { dev_err(map->dev, "Failed to add range %d\n", i); kfree(new); goto err_range; }
if (map->selector_work_buf == NULL) { map->selector_work_buf = kzalloc(map->format.buf_size, GFP_KERNEL); if (map->selector_work_buf == NULL) { ret = -ENOMEM; goto err_range; } } }
ret = regcache_init(map, config); if (ret != 0) goto err_range;
if (dev) { ret = regmap_attach_dev(dev, map, config); if (ret != 0) goto err_regcache; } else { regmap_debugfs_init(map); }
return map;
err_regcache: regcache_exit(map);err_range: regmap_range_exit(map); kfree(map->work_buf);err_hwlock: if (map->hwlock) hwspin_lock_free(map->hwlock);err_name: kfree_const(map->name);err_map: kfree(map);err: if (bus && bus->free_on_exit) kfree(bus); return ERR_PTR(ret);}EXPORT_SYMBOL_GPL(__regmap_init);
static void devm_regmap_release(void *regmap){ regmap_exit(regmap);}
struct regmap *__devm_regmap_init(struct device *dev, const struct regmap_bus *bus, void *bus_context, const struct regmap_config *config, struct lock_class_key *lock_key, const char *lock_name){ struct regmap *regmap; int ret;
regmap = __regmap_init(dev, bus, bus_context, config, lock_key, lock_name); if (IS_ERR(regmap)) return regmap;
ret = devm_add_action_or_reset(dev, devm_regmap_release, regmap); if (ret) return ERR_PTR(ret);
return regmap;}EXPORT_SYMBOL_GPL(__devm_regmap_init);
static void regmap_field_init(struct regmap_field *rm_field, struct regmap *regmap, struct reg_field reg_field){ rm_field->regmap = regmap; rm_field->reg = reg_field.reg; rm_field->shift = reg_field.lsb; rm_field->mask = GENMASK(reg_field.msb, reg_field.lsb);
WARN_ONCE(rm_field->mask == 0, "invalid empty mask defined\n");
rm_field->id_size = reg_field.id_size; rm_field->id_offset = reg_field.id_offset;}
/** * devm_regmap_field_alloc() - Allocate and initialise a register field. * * @dev: Device that will be interacted with * @regmap: regmap bank in which this register field is located. * @reg_field: Register field with in the bank. * * The return value will be an ERR_PTR() on error or a valid pointer * to a struct regmap_field. The regmap_field will be automatically freed * by the device management code. */struct regmap_field *devm_regmap_field_alloc(struct device *dev, struct regmap *regmap, struct reg_field reg_field){ struct regmap_field *rm_field = devm_kzalloc(dev, sizeof(*rm_field), GFP_KERNEL); if (!rm_field) return ERR_PTR(-ENOMEM);
regmap_field_init(rm_field, regmap, reg_field);
return rm_field;
}EXPORT_SYMBOL_GPL(devm_regmap_field_alloc);
/** * regmap_field_bulk_alloc() - Allocate and initialise a bulk register field. * * @regmap: regmap bank in which this register field is located. * @rm_field: regmap register fields within the bank. * @reg_field: Register fields within the bank. * @num_fields: Number of register fields. * * The return value will be an -ENOMEM on error or zero for success. * Newly allocated regmap_fields should be freed by calling * regmap_field_bulk_free() */int regmap_field_bulk_alloc(struct regmap *regmap, struct regmap_field **rm_field, const struct reg_field *reg_field, int num_fields){ struct regmap_field *rf; int i;
rf = kzalloc_objs(*rf, num_fields); if (!rf) return -ENOMEM;
for (i = 0; i < num_fields; i++) { regmap_field_init(&rf[i], regmap, reg_field[i]); rm_field[i] = &rf[i]; }
return 0;}EXPORT_SYMBOL_GPL(regmap_field_bulk_alloc);
/** * devm_regmap_field_bulk_alloc() - Allocate and initialise a bulk register * fields. * * @dev: Device that will be interacted with * @regmap: regmap bank in which this register field is located. * @rm_field: regmap register fields within the bank. * @reg_field: Register fields within the bank. * @num_fields: Number of register fields. * * The return value will be an -ENOMEM on error or zero for success. * Newly allocated regmap_fields will be automatically freed by the * device management code. */int devm_regmap_field_bulk_alloc(struct device *dev, struct regmap *regmap, struct regmap_field **rm_field, const struct reg_field *reg_field, int num_fields){ struct regmap_field *rf; int i;
rf = devm_kcalloc(dev, num_fields, sizeof(*rf), GFP_KERNEL); if (!rf) return -ENOMEM;
for (i = 0; i < num_fields; i++) { regmap_field_init(&rf[i], regmap, reg_field[i]); rm_field[i] = &rf[i]; }
return 0;}EXPORT_SYMBOL_GPL(devm_regmap_field_bulk_alloc);
/** * regmap_field_bulk_free() - Free register field allocated using * regmap_field_bulk_alloc. * * @field: regmap fields which should be freed. */void regmap_field_bulk_free(struct regmap_field *field){ kfree(field);}EXPORT_SYMBOL_GPL(regmap_field_bulk_free);
/** * devm_regmap_field_bulk_free() - Free a bulk register field allocated using * devm_regmap_field_bulk_alloc. * * @dev: Device that will be interacted with * @field: regmap field which should be freed. * * Free register field allocated using devm_regmap_field_bulk_alloc(). Usually * drivers need not call this function, as the memory allocated via devm * will be freed as per device-driver life-cycle. */void devm_regmap_field_bulk_free(struct device *dev, struct regmap_field *field){ devm_kfree(dev, field);}EXPORT_SYMBOL_GPL(devm_regmap_field_bulk_free);
/** * devm_regmap_field_free() - Free a register field allocated using * devm_regmap_field_alloc. * * @dev: Device that will be interacted with * @field: regmap field which should be freed. * * Free register field allocated using devm_regmap_field_alloc(). Usually * drivers need not call this function, as the memory allocated via devm * will be freed as per device-driver life-cyle. */void devm_regmap_field_free(struct device *dev, struct regmap_field *field){ devm_kfree(dev, field);}EXPORT_SYMBOL_GPL(devm_regmap_field_free);
/** * regmap_field_alloc() - Allocate and initialise a register field. * * @regmap: regmap bank in which this register field is located. * @reg_field: Register field with in the bank. * * The return value will be an ERR_PTR() on error or a valid pointer * to a struct regmap_field. The regmap_field should be freed by the * user once its finished working with it using regmap_field_free(). */struct regmap_field *regmap_field_alloc(struct regmap *regmap, struct reg_field reg_field){ struct regmap_field *rm_field = kzalloc_obj(*rm_field);
if (!rm_field) return ERR_PTR(-ENOMEM);
regmap_field_init(rm_field, regmap, reg_field);
return rm_field;}EXPORT_SYMBOL_GPL(regmap_field_alloc);
/** * regmap_field_free() - Free register field allocated using * regmap_field_alloc. * * @field: regmap field which should be freed. */void regmap_field_free(struct regmap_field *field){ kfree(field);}EXPORT_SYMBOL_GPL(regmap_field_free);
/** * regmap_reinit_cache() - Reinitialise the current register cache * * @map: Register map to operate on. * @config: New configuration. Only the cache data will be used. * * Discard any existing register cache for the map and initialize a * new cache. This can be used to restore the cache to defaults or to * update the cache configuration to reflect runtime discovery of the * hardware. * * No explicit locking is done here, the user needs to ensure that * this function will not race with other calls to regmap. */int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config){ int ret;
regmap_debugfs_exit(map); regcache_exit(map);
map->max_register = config->max_register; map->max_register_is_set = map->max_register ?: config->max_register_is_0; map->writeable_reg = config->writeable_reg; map->readable_reg = config->readable_reg; map->volatile_reg = config->volatile_reg; map->precious_reg = config->precious_reg; map->writeable_noinc_reg = config->writeable_noinc_reg; map->readable_noinc_reg = config->readable_noinc_reg; map->reg_default_cb = config->reg_default_cb; map->cache_type = config->cache_type;
ret = regmap_set_name(map, config); if (ret) return ret;
map->cache_bypass = false; map->cache_only = false;
ret = regcache_init(map, config); if (ret) return ret;
regmap_debugfs_init(map);
return 0;}EXPORT_SYMBOL_GPL(regmap_reinit_cache);
/** * regmap_exit() - Free a previously allocated register map * * @map: Register map to operate on. */void regmap_exit(struct regmap *map){ struct regmap_async *async;
regmap_detach_dev(map->dev, map); regmap_debugfs_exit(map); regcache_exit(map); regmap_range_exit(map); if (map->bus && map->bus->free_context) map->bus->free_context(map->bus_context); kfree(map->work_buf); while (!list_empty(&map->async_free)) { async = list_first_entry_or_null(&map->async_free, struct regmap_async, list); list_del(&async->list); kfree(async->work_buf); kfree(async); } if (map->hwlock) hwspin_lock_free(map->hwlock); if (map->lock == regmap_lock_mutex) mutex_destroy(&map->mutex); kfree_const(map->name); kfree(map->patch); if (map->bus && map->bus->free_on_exit) kfree(map->bus); kfree(map);}EXPORT_SYMBOL_GPL(regmap_exit);
static int dev_get_regmap_match(struct device *dev, void *res, void *data){ struct regmap **r = res; if (!r || !*r) { WARN_ON(!r || !*r); return 0; }
/* If the user didn't specify a name match any */ if (data) return (*r)->name && !strcmp((*r)->name, data); else return 1;}
/** * dev_get_regmap() - Obtain the regmap (if any) for a device * * @dev: Device to retrieve the map for * @name: Optional name for the register map, usually NULL. * * Returns the regmap for the device if one is present, or NULL. If * name is specified then it must match the name specified when * registering the device, if it is NULL then the first regmap found * will be used. Devices with multiple register maps are very rare, * generic code should normally not need to specify a name. */struct regmap *dev_get_regmap(struct device *dev, const char *name){ struct regmap **r = devres_find(dev, dev_get_regmap_release, dev_get_regmap_match, (void *)name);
if (!r) return NULL; return *r;}EXPORT_SYMBOL_GPL(dev_get_regmap);
/** * regmap_get_device() - Obtain the device from a regmap * * @map: Register map to operate on. * * Returns the underlying device that the regmap has been created for. */struct device *regmap_get_device(struct regmap *map){ return map->dev;}EXPORT_SYMBOL_GPL(regmap_get_device);
static int _regmap_select_page(struct regmap *map, unsigned int *reg, struct regmap_range_node *range, unsigned int val_num){ void *orig_work_buf; unsigned int selector_reg; unsigned int win_offset; unsigned int win_page; bool page_chg; int ret;
win_offset = (*reg - range->range_min) % range->window_len; win_page = (*reg - range->range_min) / range->window_len;
if (val_num > 1) { /* Bulk write shouldn't cross range boundary */ if (*reg + val_num - 1 > range->range_max) return -EINVAL;
/* ... or single page boundary */ if (val_num > range->window_len - win_offset) return -EINVAL; }
/* * Calculate the address of the selector register in the corresponding * data window if it is located on every page. */ page_chg = in_range(range->selector_reg, range->window_start, range->window_len); if (page_chg) selector_reg = range->range_min + win_page * range->window_len + range->selector_reg - range->window_start;
/* * It is possible to have selector register inside data window. * In that case, selector register is located on every page and it * needs no page switching, when accessed alone. * * Nevertheless we should synchronize the cache values for it. * This can't be properly achieved if the selector register is * the first and the only one to be read inside the data window. * That's why we update it in that case as well. * * However, we specifically avoid updating it for the default page, * when it's overlapped with the real data window, to prevent from * infinite looping. */ if (val_num > 1 || (page_chg && selector_reg != range->selector_reg) || range->window_start + win_offset != range->selector_reg) { /* Use separate work_buf during page switching */ orig_work_buf = map->work_buf; map->work_buf = map->selector_work_buf;
ret = _regmap_update_bits(map, range->selector_reg, range->selector_mask, win_page << range->selector_shift, NULL, false);
map->work_buf = orig_work_buf;
if (ret != 0) return ret; }
*reg = range->window_start + win_offset;
return 0;}
static void regmap_set_work_buf_flag_mask(struct regmap *map, int max_bytes, unsigned long mask){ u8 *buf; int i;
if (!mask || !map->work_buf) return;
buf = map->work_buf;
for (i = 0; i < max_bytes; i++) buf[i] |= (mask >> (8 * i)) & 0xff;}
static unsigned int regmap_reg_addr(struct regmap *map, unsigned int reg){ reg += map->reg_base;
if (map->format.reg_shift > 0) reg >>= map->format.reg_shift; else if (map->format.reg_shift < 0) reg <<= -(map->format.reg_shift);
return reg;}
static int _regmap_raw_write_impl(struct regmap *map, unsigned int reg, const void *val, size_t val_len, bool noinc){ struct regmap_range_node *range; unsigned long flags; void *work_val = map->work_buf + map->format.reg_bytes + map->format.pad_bytes; void *buf; int ret = -ENOTSUPP; size_t len; int i;
/* Check for unwritable or noinc registers in range * before we start */ if (!regmap_writeable_noinc(map, reg)) { for (i = 0; i < val_len / map->format.val_bytes; i++) { unsigned int element = reg + regmap_get_offset(map, i); if (!regmap_writeable(map, element) || regmap_writeable_noinc(map, element)) return -EINVAL; } }
if (!map->cache_bypass && map->format.parse_val) { unsigned int ival, offset; int val_bytes = map->format.val_bytes;
/* Cache the last written value for noinc writes */ i = noinc ? val_len - val_bytes : 0; for (; i < val_len; i += val_bytes) { ival = map->format.parse_val(val + i); offset = noinc ? 0 : regmap_get_offset(map, i / val_bytes); ret = regcache_write(map, reg + offset, ival); if (ret) { dev_err(map->dev, "Error in caching of register: %x ret: %d\n", reg + offset, ret); return ret; } } if (map->cache_only) { map->cache_dirty = true; return 0; } }
range = _regmap_range_lookup(map, reg); if (range) { int val_num = val_len / map->format.val_bytes; int win_offset = (reg - range->range_min) % range->window_len; int win_residue = range->window_len - win_offset;
/* If the write goes beyond the end of the window split it */ while (val_num > win_residue) { dev_dbg(map->dev, "Writing window %d/%zu\n", win_residue, val_len / map->format.val_bytes); ret = _regmap_raw_write_impl(map, reg, val, win_residue * map->format.val_bytes, noinc); if (ret != 0) return ret;
reg += win_residue; val_num -= win_residue; val += win_residue * map->format.val_bytes; val_len -= win_residue * map->format.val_bytes;
win_offset = (reg - range->range_min) % range->window_len; win_residue = range->window_len - win_offset; }
ret = _regmap_select_page(map, ®, range, noinc ? 1 : val_num); if (ret != 0) return ret; }
reg = regmap_reg_addr(map, reg); map->format.format_reg(map->work_buf, reg, map->reg_shift); regmap_set_work_buf_flag_mask(map, map->format.reg_bytes, map->write_flag_mask);
/* * Essentially all I/O mechanisms will be faster with a single * buffer to write. Since register syncs often generate raw * writes of single registers optimise that case. */ if (val != work_val && val_len == map->format.val_bytes) { memcpy(work_val, val, map->format.val_bytes); val = work_val; }
if (map->async && map->bus && map->bus->async_write) { struct regmap_async *async;
trace_regmap_async_write_start(map, reg, val_len);
spin_lock_irqsave(&map->async_lock, flags); async = list_first_entry_or_null(&map->async_free, struct regmap_async, list); if (async) list_del(&async->list); spin_unlock_irqrestore(&map->async_lock, flags);
if (!async) { async = map->bus->async_alloc(); if (!async) return -ENOMEM;
async->work_buf = kzalloc(map->format.buf_size, GFP_KERNEL | GFP_DMA); if (!async->work_buf) { kfree(async); return -ENOMEM; } }
async->map = map;
/* If the caller supplied the value we can use it safely. */ memcpy(async->work_buf, map->work_buf, map->format.pad_bytes + map->format.reg_bytes + map->format.val_bytes);
spin_lock_irqsave(&map->async_lock, flags); list_add_tail(&async->list, &map->async_list); spin_unlock_irqrestore(&map->async_lock, flags);
if (val != work_val) ret = map->bus->async_write(map->bus_context, async->work_buf, map->format.reg_bytes + map->format.pad_bytes, val, val_len, async); else ret = map->bus->async_write(map->bus_context, async->work_buf, map->format.reg_bytes + map->format.pad_bytes + val_len, NULL, 0, async);
if (ret != 0) { dev_err(map->dev, "Failed to schedule write: %d\n", ret);
spin_lock_irqsave(&map->async_lock, flags); list_move(&async->list, &map->async_free); spin_unlock_irqrestore(&map->async_lock, flags); }
return ret; }
trace_regmap_hw_write_start(map, reg, val_len / map->format.val_bytes);
/* If we're doing a single register write we can probably just * send the work_buf directly, otherwise try to do a gather * write. */ if (val == work_val) ret = map->write(map->bus_context, map->work_buf, map->format.reg_bytes + map->format.pad_bytes + val_len); else if (map->bus && map->bus->gather_write) ret = map->bus->gather_write(map->bus_context, map->work_buf, map->format.reg_bytes + map->format.pad_bytes, val, val_len); else ret = -ENOTSUPP;
/* If that didn't work fall back on linearising by hand. */ if (ret == -ENOTSUPP) { len = map->format.reg_bytes + map->format.pad_bytes + val_len; buf = kzalloc(len, GFP_KERNEL); if (!buf) return -ENOMEM;
memcpy(buf, map->work_buf, map->format.reg_bytes); memcpy(buf + map->format.reg_bytes + map->format.pad_bytes, val, val_len); ret = map->write(map->bus_context, buf, len);
kfree(buf); } else if (ret != 0 && !map->cache_bypass && map->format.parse_val) { /* regcache_drop_region() takes lock that we already have, * thus call map->cache_ops->drop() directly */ if (map->cache_ops && map->cache_ops->drop) map->cache_ops->drop(map, reg, reg + 1); }
trace_regmap_hw_write_done(map, reg, val_len / map->format.val_bytes);
return ret;}
/** * regmap_can_raw_write - Test if regmap_raw_write() is supported * * @map: Map to check. */bool regmap_can_raw_write(struct regmap *map){ return map->write && map->format.format_val && map->format.format_reg;}EXPORT_SYMBOL_GPL(regmap_can_raw_write);
/** * regmap_get_raw_read_max - Get the maximum size we can read * * @map: Map to check. */size_t regmap_get_raw_read_max(struct regmap *map){ return map->max_raw_read;}EXPORT_SYMBOL_GPL(regmap_get_raw_read_max);
/** * regmap_get_raw_write_max - Get the maximum size we can read * * @map: Map to check. */size_t regmap_get_raw_write_max(struct regmap *map){ return map->max_raw_write;}EXPORT_SYMBOL_GPL(regmap_get_raw_write_max);
static int _regmap_bus_formatted_write(void *context, unsigned int reg, unsigned int val){ int ret; struct regmap_range_node *range; struct regmap *map = context;
WARN_ON(!map->format.format_write);
range = _regmap_range_lookup(map, reg); if (range) { ret = _regmap_select_page(map, ®, range, 1); if (ret != 0) return ret; }
reg = regmap_reg_addr(map, reg); map->format.format_write(map, reg, val);
trace_regmap_hw_write_start(map, reg, 1);
ret = map->write(map->bus_context, map->work_buf, map->format.buf_size);
trace_regmap_hw_write_done(map, reg, 1);
return ret;}
static int _regmap_bus_reg_write(void *context, unsigned int reg, unsigned int val){ struct regmap *map = context; struct regmap_range_node *range; int ret;
range = _regmap_range_lookup(map, reg); if (range) { ret = _regmap_select_page(map, ®, range, 1); if (ret != 0) return ret; }
reg = regmap_reg_addr(map, reg); return map->bus->reg_write(map->bus_context, reg, val);}
static int _regmap_bus_raw_write(void *context, unsigned int reg, unsigned int val){ struct regmap *map = context;
WARN_ON(!map->format.format_val);
map->format.format_val(map->work_buf + map->format.reg_bytes + map->format.pad_bytes, val, 0); return _regmap_raw_write_impl(map, reg, map->work_buf + map->format.reg_bytes + map->format.pad_bytes, map->format.val_bytes, false);}
static inline void *_regmap_map_get_context(struct regmap *map){ return (map->bus || (!map->bus && map->read)) ? map : map->bus_context;}
int _regmap_write(struct regmap *map, unsigned int reg, unsigned int val){ int ret; void *context = _regmap_map_get_context(map);
if (!regmap_writeable(map, reg)) return -EIO;
if (!map->cache_bypass && !map->defer_caching) { ret = regcache_write(map, reg, val); if (ret != 0) return ret; if (map->cache_only) { map->cache_dirty = true; return 0; } }
ret = map->reg_write(context, reg, val); if (ret == 0) { if (regmap_should_log(map)) dev_info(map->dev, "%x <= %x\n", reg, val);
trace_regmap_reg_write(map, reg, val); }
return ret;}
/** * regmap_write() - Write a value to a single register * * @map: Register map to write to * @reg: Register to write to * @val: Value to be written * * A value of zero will be returned on success, a negative errno will * be returned in error cases. */int regmap_write(struct regmap *map, unsigned int reg, unsigned int val){ if (!IS_ALIGNED(reg, map->reg_stride)) return -EINVAL;
guard(regmap)(map);
return _regmap_write(map, reg, val);}EXPORT_SYMBOL_GPL(regmap_write);
/** * regmap_write_async() - Write a value to a single register asynchronously * * @map: Register map to write to * @reg: Register to write to * @val: Value to be written * * A value of zero will be returned on success, a negative errno will * be returned in error cases. */int regmap_write_async(struct regmap *map, unsigned int reg, unsigned int val){ int ret;
if (!IS_ALIGNED(reg, map->reg_stride)) return -EINVAL;
guard(regmap)(map);
map->async = true;
ret = _regmap_write(map, reg, val);
map->async = false;
return ret;}EXPORT_SYMBOL_GPL(regmap_write_async);
int _regmap_raw_write(struct regmap *map, unsigned int reg, const void *val, size_t val_len, bool noinc){ size_t val_bytes = map->format.val_bytes; size_t val_count = val_len / val_bytes; size_t chunk_count, chunk_bytes; size_t chunk_regs = val_count; int ret, i;
if (!val_count) return -EINVAL;
if (map->use_single_write) chunk_regs = 1; else if (map->max_raw_write && val_len > map->max_raw_write) chunk_regs = map->max_raw_write / val_bytes;
chunk_count = val_count / chunk_regs; chunk_bytes = chunk_regs * val_bytes;
/* Write as many bytes as possible with chunk_size */ for (i = 0; i < chunk_count; i++) { ret = _regmap_raw_write_impl(map, reg, val, chunk_bytes, noinc); if (ret) return ret;
reg += regmap_get_offset(map, chunk_regs); val += chunk_bytes; val_len -= chunk_bytes; }
/* Write remaining bytes */ if (val_len) ret = _regmap_raw_write_impl(map, reg, val, val_len, noinc);
return ret;}
/** * regmap_raw_write() - Write raw values to one or more registers * * @map: Register map to write to * @reg: Initial register to write to * @val: Block of data to be written, laid out for direct transmission to the * device * @val_len: Length of data pointed to by val. * * This function is intended to be used for things like firmware * download where a large block of data needs to be transferred to the * device. No formatting will be done on the data provided. * * A value of zero will be returned on success, a negative errno will * be returned in error cases. */int regmap_raw_write(struct regmap *map, unsigned int reg, const void *val, size_t val_len){ if (!regmap_can_raw_write(map)) return -EINVAL; if (val_len % map->format.val_bytes) return -EINVAL;
guard(regmap)(map);
return _regmap_raw_write(map, reg, val, val_len, false);}EXPORT_SYMBOL_GPL(regmap_raw_write);
static int regmap_noinc_readwrite(struct regmap *map, unsigned int reg, void *val, unsigned int val_len, bool write){ size_t val_bytes = map->format.val_bytes; size_t val_count = val_len / val_bytes; unsigned int lastval; u8 *u8p; u16 *u16p; u32 *u32p; int ret; int i;
switch (val_bytes) { case 1: u8p = val; if (write) lastval = (unsigned int)u8p[val_count - 1]; break; case 2: u16p = val; if (write) lastval = (unsigned int)u16p[val_count - 1]; break; case 4: u32p = val; if (write) lastval = (unsigned int)u32p[val_count - 1]; break; default: return -EINVAL; }
/* * Update the cache with the last value we write, the rest is just * gone down in the hardware FIFO. We can't cache FIFOs. This makes * sure a single read from the cache will work. */ if (write) { if (!map->cache_bypass && !map->defer_caching) { ret = regcache_write(map, reg, lastval); if (ret != 0) return ret; if (map->cache_only) { map->cache_dirty = true; return 0; } } ret = map->bus->reg_noinc_write(map->bus_context, reg, val, val_count); } else { ret = map->bus->reg_noinc_read(map->bus_context, reg, val, val_count); }
if (!ret && regmap_should_log(map)) { dev_info(map->dev, "%x %s [", reg, write ? "<=" : "=>"); for (i = 0; i < val_count; i++) { switch (val_bytes) { case 1: pr_cont("%x", u8p[i]); break; case 2: pr_cont("%x", u16p[i]); break; case 4: pr_cont("%x", u32p[i]); break; default: break; } if (i == (val_count - 1)) pr_cont("]\n"); else pr_cont(","); } }
return 0;}
/** * regmap_noinc_write(): Write data to a register without incrementing the * register number * * @map: Register map to write to * @reg: Register to write to * @val: Pointer to data buffer * @val_len: Length of output buffer in bytes. * * The regmap API usually assumes that bulk bus write operations will write a * range of registers. Some devices have certain registers for which a write * operation can write to an internal FIFO. * * The target register must be volatile but registers after it can be * completely unrelated cacheable registers. * * This will attempt multiple writes as required to write val_len bytes. * * A value of zero will be returned on success, a negative errno will be * returned in error cases. */int regmap_noinc_write(struct regmap *map, unsigned int reg, const void *val, size_t val_len){ size_t write_len; int ret;
if (!map->write && !(map->bus && map->bus->reg_noinc_write)) return -EINVAL; if (val_len % map->format.val_bytes) return -EINVAL; if (!IS_ALIGNED(reg, map->reg_stride)) return -EINVAL; if (val_len == 0) return -EINVAL;
guard(regmap)(map);
if (!regmap_volatile(map, reg) || !regmap_writeable_noinc(map, reg)) return -EINVAL;
/* * Use the accelerated operation if we can. The val drops the const * typing in order to facilitate code reuse in regmap_noinc_readwrite(). */ if (map->bus->reg_noinc_write) return regmap_noinc_readwrite(map, reg, (void *)val, val_len, true);
while (val_len) { if (map->max_raw_write && map->max_raw_write < val_len) write_len = map->max_raw_write; else write_len = val_len; ret = _regmap_raw_write(map, reg, val, write_len, true); if (ret) return ret; val = ((u8 *)val) + write_len; val_len -= write_len; }
return 0;}EXPORT_SYMBOL_GPL(regmap_noinc_write);
/** * regmap_field_update_bits_base() - Perform a read/modify/write cycle a * register field. * * @field: Register field to write to * @mask: Bitmask to change * @val: Value to be written * @change: Boolean indicating if a write was done * @async: Boolean indicating asynchronously * @force: Boolean indicating use force update * * Perform a read/modify/write cycle on the register field with change, * async, force option. * * A value of zero will be returned on success, a negative errno will * be returned in error cases. */int regmap_field_update_bits_base(struct regmap_field *field, unsigned int mask, unsigned int val, bool *change, bool async, bool force){ mask = (mask << field->shift) & field->mask;
return regmap_update_bits_base(field->regmap, field->reg, mask, val << field->shift, change, async, force);}EXPORT_SYMBOL_GPL(regmap_field_update_bits_base);
/** * regmap_field_test_bits() - Check if all specified bits are set in a * register field. * * @field: Register field to operate on * @bits: Bits to test * * Returns negative errno if the underlying regmap_field_read() fails, * 0 if at least one of the tested bits is not set and 1 if all tested * bits are set. */int regmap_field_test_bits(struct regmap_field *field, unsigned int bits){ unsigned int val; int ret;
ret = regmap_field_read(field, &val); if (ret) return ret;
return (val & bits) == bits;}EXPORT_SYMBOL_GPL(regmap_field_test_bits);
/** * regmap_fields_update_bits_base() - Perform a read/modify/write cycle a * register field with port ID * * @field: Register field to write to * @id: port ID * @mask: Bitmask to change * @val: Value to be written * @change: Boolean indicating if a write was done * @async: Boolean indicating asynchronously * @force: Boolean indicating use force update * * A value of zero will be returned on success, a negative errno will * be returned in error cases. */int regmap_fields_update_bits_base(struct regmap_field *field, unsigned int id, unsigned int mask, unsigned int val, bool *change, bool async, bool force){ if (id >= field->id_size) return -EINVAL;
mask = (mask << field->shift) & field->mask;
return regmap_update_bits_base(field->regmap, field->reg + (field->id_offset * id), mask, val << field->shift, change, async, force);}EXPORT_SYMBOL_GPL(regmap_fields_update_bits_base);
/** * regmap_bulk_write() - Write multiple registers to the device * * @map: Register map to write to * @reg: First register to be write from * @val: Block of data to be written, in native register size for device * @val_count: Number of registers to write * * This function is intended to be used for writing a large block of * data to the device either in single transfer or multiple transfer. * * A value of zero will be returned on success, a negative errno will * be returned in error cases. */int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, size_t val_count){ int ret = 0, i; size_t val_bytes = map->format.val_bytes;
if (!IS_ALIGNED(reg, map->reg_stride)) return -EINVAL;
/* * Some devices don't support bulk write, for them we have a series of * single write operations. */ if (!map->write || !map->format.parse_inplace) { guard(regmap)(map);
for (i = 0; i < val_count; i++) { unsigned int ival;
switch (val_bytes) { case 1: ival = *(u8 *)(val + (i * val_bytes)); break; case 2: ival = *(u16 *)(val + (i * val_bytes)); break; case 4: ival = *(u32 *)(val + (i * val_bytes)); break; default: return -EINVAL; }
ret = _regmap_write(map, reg + regmap_get_offset(map, i), ival); if (ret != 0) return ret; } } else { void *wval;
wval = kmemdup_array(val, val_count, val_bytes, map->alloc_flags); if (!wval) return -ENOMEM;
for (i = 0; i < val_count * val_bytes; i += val_bytes) map->format.parse_inplace(wval + i);
ret = regmap_raw_write(map, reg, wval, val_bytes * val_count);
kfree(wval); }
if (!ret) trace_regmap_bulk_write(map, reg, val, val_bytes * val_count);
return ret;}EXPORT_SYMBOL_GPL(regmap_bulk_write);
/* * _regmap_raw_multi_reg_write() * * the (register,newvalue) pairs in regs have not been formatted, but * they are all in the same page and have been changed to being page * relative. The page register has been written if that was necessary. */static int _regmap_raw_multi_reg_write(struct regmap *map, const struct reg_sequence *regs, size_t num_regs){ int ret; void *buf; int i; u8 *u8; size_t val_bytes = map->format.val_bytes; size_t reg_bytes = map->format.reg_bytes; size_t pad_bytes = map->format.pad_bytes; size_t pair_size = reg_bytes + pad_bytes + val_bytes; size_t len = pair_size * num_regs;
if (!len) return -EINVAL;
buf = kzalloc(len, GFP_KERNEL); if (!buf) return -ENOMEM;
/* We have to linearise by hand. */
u8 = buf;
for (i = 0; i < num_regs; i++) { unsigned int reg = regs[i].reg; unsigned int val = regs[i].def; trace_regmap_hw_write_start(map, reg, 1); reg = regmap_reg_addr(map, reg); map->format.format_reg(u8, reg, map->reg_shift); u8 += reg_bytes + pad_bytes; map->format.format_val(u8, val, 0); u8 += val_bytes; } u8 = buf; *u8 |= map->write_flag_mask;
ret = map->write(map->bus_context, buf, len);
kfree(buf);
for (i = 0; i < num_regs; i++) { int reg = regs[i].reg; trace_regmap_hw_write_done(map, reg, 1); } return ret;}
static unsigned int _regmap_register_page(struct regmap *map, unsigned int reg, struct regmap_range_node *range){ unsigned int win_page = (reg - range->range_min) / range->window_len;
return win_page;}
static int _regmap_range_multi_paged_reg_write(struct regmap *map, struct reg_sequence *regs, size_t num_regs){ int ret; int i, n; struct reg_sequence *base; unsigned int this_page = 0; unsigned int page_change = 0; /* * the set of registers are not neccessarily in order, but * since the order of write must be preserved this algorithm * chops the set each time the page changes. This also applies * if there is a delay required at any point in the sequence. */ base = regs; for (i = 0, n = 0; i < num_regs; i++, n++) { unsigned int reg = regs[i].reg; struct regmap_range_node *range;
range = _regmap_range_lookup(map, reg); if (range) { unsigned int win_page = _regmap_register_page(map, reg, range);
if (i == 0) this_page = win_page; if (win_page != this_page) { this_page = win_page; page_change = 1; } }
/* If we have both a page change and a delay make sure to * write the regs and apply the delay before we change the * page. */
if (page_change || regs[i].delay_us) {
/* For situations where the first write requires * a delay we need to make sure we don't call * raw_multi_reg_write with n=0 * This can't occur with page breaks as we * never write on the first iteration */ if (regs[i].delay_us && i == 0) n = 1;
ret = _regmap_raw_multi_reg_write(map, base, n); if (ret != 0) return ret;
if (regs[i].delay_us) { if (map->can_sleep) fsleep(regs[i].delay_us); else udelay(regs[i].delay_us); }
base += n; n = 0;
if (page_change) { ret = _regmap_select_page(map, &base[n].reg, range, 1); if (ret != 0) return ret;
page_change = 0; }
}
} if (n > 0) return _regmap_raw_multi_reg_write(map, base, n); return 0;}
static int _regmap_multi_reg_write(struct regmap *map, const struct reg_sequence *regs, size_t num_regs){ int i; int ret;
if (!map->can_multi_write) { for (i = 0; i < num_regs; i++) { ret = _regmap_write(map, regs[i].reg, regs[i].def); if (ret != 0) return ret;
if (regs[i].delay_us) { if (map->can_sleep) fsleep(regs[i].delay_us); else udelay(regs[i].delay_us); } } return 0; }
if (!map->format.parse_inplace) return -EINVAL;
if (map->writeable_reg) for (i = 0; i < num_regs; i++) { int reg = regs[i].reg; if (!map->writeable_reg(map->dev, reg)) return -EINVAL; if (!IS_ALIGNED(reg, map->reg_stride)) return -EINVAL; }
if (!map->cache_bypass) { for (i = 0; i < num_regs; i++) { unsigned int val = regs[i].def; unsigned int reg = regs[i].reg; ret = regcache_write(map, reg, val); if (ret) { dev_err(map->dev, "Error in caching of register: %x ret: %d\n", reg, ret); return ret; } } if (map->cache_only) { map->cache_dirty = true; return 0; } }
WARN_ON(!map->bus);
for (i = 0; i < num_regs; i++) { unsigned int reg = regs[i].reg; struct regmap_range_node *range;
/* Coalesce all the writes between a page break or a delay * in a sequence */ range = _regmap_range_lookup(map, reg); if (range || regs[i].delay_us) { size_t len = sizeof(struct reg_sequence)*num_regs; struct reg_sequence *base = kmemdup(regs, len, GFP_KERNEL); if (!base) return -ENOMEM; ret = _regmap_range_multi_paged_reg_write(map, base, num_regs); kfree(base);
return ret; } } return _regmap_raw_multi_reg_write(map, regs, num_regs);}
/** * regmap_multi_reg_write() - Write multiple registers to the device * * @map: Register map to write to * @regs: Array of structures containing register,value to be written * @num_regs: Number of registers to write * * Write multiple registers to the device where the set of register, value * pairs are supplied in any order, possibly not all in a single range. * * The 'normal' block write mode will send ultimately send data on the * target bus as R,V1,V2,V3,..,Vn where successively higher registers are * addressed. However, this alternative block multi write mode will send * the data as R1,V1,R2,V2,..,Rn,Vn on the target bus. The target device * must of course support the mode. * * A value of zero will be returned on success, a negative errno will be * returned in error cases. */int regmap_multi_reg_write(struct regmap *map, const struct reg_sequence *regs, int num_regs){ guard(regmap)(map);
return _regmap_multi_reg_write(map, regs, num_regs);}EXPORT_SYMBOL_GPL(regmap_multi_reg_write);
/** * regmap_multi_reg_write_bypassed() - Write multiple registers to the * device but not the cache * * @map: Register map to write to * @regs: Array of structures containing register,value to be written * @num_regs: Number of registers to write * * Write multiple registers to the device but not the cache where the set * of register are supplied in any order. * * This function is intended to be used for writing a large block of data * atomically to the device in single transfer for those I2C client devices * that implement this alternative block write mode. * * A value of zero will be returned on success, a negative errno will * be returned in error cases. */int regmap_multi_reg_write_bypassed(struct regmap *map, const struct reg_sequence *regs, int num_regs){ int ret; bool bypass;
guard(regmap)(map);
bypass = map->cache_bypass; map->cache_bypass = true;
ret = _regmap_multi_reg_write(map, regs, num_regs);
map->cache_bypass = bypass;
return ret;}EXPORT_SYMBOL_GPL(regmap_multi_reg_write_bypassed);
/** * regmap_raw_write_async() - Write raw values to one or more registers * asynchronously * * @map: Register map to write to * @reg: Initial register to write to * @val: Block of data to be written, laid out for direct transmission to the * device. Must be valid until regmap_async_complete() is called. * @val_len: Length of data pointed to by val. * * This function is intended to be used for things like firmware * download where a large block of data needs to be transferred to the * device. No formatting will be done on the data provided. * * If supported by the underlying bus the write will be scheduled * asynchronously, helping maximise I/O speed on higher speed buses * like SPI. regmap_async_complete() can be called to ensure that all * asynchronous writes have been completed. * * A value of zero will be returned on success, a negative errno will * be returned in error cases. */int regmap_raw_write_async(struct regmap *map, unsigned int reg, const void *val, size_t val_len){ int ret;
if (val_len % map->format.val_bytes) return -EINVAL; if (!IS_ALIGNED(reg, map->reg_stride)) return -EINVAL;
guard(regmap)(map);
map->async = true;
ret = _regmap_raw_write(map, reg, val, val_len, false);
map->async = false;
return ret;}EXPORT_SYMBOL_GPL(regmap_raw_write_async);
static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val, unsigned int val_len, bool noinc){ struct regmap_range_node *range; int ret;
if (!map->read) return -EINVAL;
range = _regmap_range_lookup(map, reg); if (range) { ret = _regmap_select_page(map, ®, range, noinc ? 1 : val_len / map->format.val_bytes); if (ret != 0) return ret; }
reg = regmap_reg_addr(map, reg); map->format.format_reg(map->work_buf, reg, map->reg_shift); regmap_set_work_buf_flag_mask(map, map->format.reg_bytes, map->read_flag_mask); trace_regmap_hw_read_start(map, reg, val_len / map->format.val_bytes);
ret = map->read(map->bus_context, map->work_buf, map->format.reg_bytes + map->format.pad_bytes, val, val_len);
trace_regmap_hw_read_done(map, reg, val_len / map->format.val_bytes);
return ret;}
static int _regmap_bus_reg_read(void *context, unsigned int reg, unsigned int *val){ struct regmap *map = context; struct regmap_range_node *range; int ret;
range = _regmap_range_lookup(map, reg); if (range) { ret = _regmap_select_page(map, ®, range, 1); if (ret != 0) return ret; }
reg = regmap_reg_addr(map, reg); return map->bus->reg_read(map->bus_context, reg, val);}
static int _regmap_bus_read(void *context, unsigned int reg, unsigned int *val){ int ret; struct regmap *map = context; void *work_val = map->work_buf + map->format.reg_bytes + map->format.pad_bytes;
if (!map->format.parse_val) return -EINVAL;
ret = _regmap_raw_read(map, reg, work_val, map->format.val_bytes, false); if (ret == 0) *val = map->format.parse_val(work_val);
return ret;}
static int _regmap_read(struct regmap *map, unsigned int reg, unsigned int *val){ int ret; void *context = _regmap_map_get_context(map);
if (!map->cache_bypass) { ret = regcache_read(map, reg, val); if (ret == 0) return 0; }
if (map->cache_only) return -EBUSY;
if (!regmap_readable(map, reg)) return -EIO;
ret = map->reg_read(context, reg, val); if (ret == 0) { if (regmap_should_log(map)) dev_info(map->dev, "%x => %x\n", reg, *val);
trace_regmap_reg_read(map, reg, *val);
if (!map->cache_bypass) regcache_write(map, reg, *val); }
return ret;}
/** * regmap_read() - Read a value from a single register * * @map: Register map to read from * @reg: Register to be read from * @val: Pointer to store read value * * A value of zero will be returned on success, a negative errno will * be returned in error cases. */int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val){ if (!IS_ALIGNED(reg, map->reg_stride)) return -EINVAL;
guard(regmap)(map);
return _regmap_read(map, reg, val);}EXPORT_SYMBOL_GPL(regmap_read);
/** * regmap_read_bypassed() - Read a value from a single register direct * from the device, bypassing the cache * * @map: Register map to read from * @reg: Register to be read from * @val: Pointer to store read value * * A value of zero will be returned on success, a negative errno will * be returned in error cases. */int regmap_read_bypassed(struct regmap *map, unsigned int reg, unsigned int *val){ int ret; bool bypass, cache_only;
if (!IS_ALIGNED(reg, map->reg_stride)) return -EINVAL;
guard(regmap)(map);
bypass = map->cache_bypass; cache_only = map->cache_only; map->cache_bypass = true; map->cache_only = false;
ret = _regmap_read(map, reg, val);
map->cache_bypass = bypass; map->cache_only = cache_only;
return ret;}EXPORT_SYMBOL_GPL(regmap_read_bypassed);
/** * regmap_raw_read() - Read raw data from the device * * @map: Register map to read from * @reg: First register to be read from * @val: Pointer to store read value * @val_len: Size of data to read * * A value of zero will be returned on success, a negative errno will * be returned in error cases. */int regmap_raw_read(struct regmap *map, unsigned int reg, void *val, size_t val_len){ size_t val_bytes = map->format.val_bytes; size_t val_count = val_len / val_bytes; unsigned int v; int ret, i;
if (val_len % map->format.val_bytes) return -EINVAL; if (!IS_ALIGNED(reg, map->reg_stride)) return -EINVAL; if (val_count == 0) return -EINVAL;
guard(regmap)(map);
if (regmap_volatile_range(map, reg, val_count) || map->cache_bypass || map->cache_type == REGCACHE_NONE) { size_t chunk_count, chunk_bytes; size_t chunk_regs = val_count;
if (!map->cache_bypass && map->cache_only) return -EBUSY;
if (!map->read) return -ENOTSUPP;
if (map->use_single_read) chunk_regs = 1; else if (map->max_raw_read && val_len > map->max_raw_read) chunk_regs = map->max_raw_read / val_bytes;
chunk_count = val_count / chunk_regs; chunk_bytes = chunk_regs * val_bytes;
/* Read bytes that fit into whole chunks */ for (i = 0; i < chunk_count; i++) { ret = _regmap_raw_read(map, reg, val, chunk_bytes, false); if (ret != 0) return ret;
reg += regmap_get_offset(map, chunk_regs); val += chunk_bytes; val_len -= chunk_bytes; }
/* Read remaining bytes */ if (val_len) { ret = _regmap_raw_read(map, reg, val, val_len, false); if (ret != 0) return ret; } } else { /* Otherwise go word by word for the cache; should be low * cost as we expect to hit the cache. */ for (i = 0; i < val_count; i++) { ret = _regmap_read(map, reg + regmap_get_offset(map, i), &v); if (ret != 0) return ret;
map->format.format_val(val + (i * val_bytes), v, 0); } }
return 0;}EXPORT_SYMBOL_GPL(regmap_raw_read);
/** * regmap_noinc_read(): Read data from a register without incrementing the * register number * * @map: Register map to read from * @reg: Register to read from * @val: Pointer to data buffer * @val_len: Length of output buffer in bytes. * * The regmap API usually assumes that bulk read operations will read a * range of registers. Some devices have certain registers for which a read * operation read will read from an internal FIFO. * * The target register must be volatile but registers after it can be * completely unrelated cacheable registers. * * This will attempt multiple reads as required to read val_len bytes. * * A value of zero will be returned on success, a negative errno will be * returned in error cases. */int regmap_noinc_read(struct regmap *map, unsigned int reg, void *val, size_t val_len){ size_t read_len; int ret;
if (!map->read) return -ENOTSUPP;
if (val_len % map->format.val_bytes) return -EINVAL; if (!IS_ALIGNED(reg, map->reg_stride)) return -EINVAL; if (val_len == 0) return -EINVAL;
guard(regmap)(map);
if (!regmap_volatile(map, reg) || !regmap_readable_noinc(map, reg)) return -EINVAL;
/* * We have not defined the FIFO semantics for cache, as the * cache is just one value deep. Should we return the last * written value? Just avoid this by always reading the FIFO * even when using cache. Cache only will not work. */ if (!map->cache_bypass && map->cache_only) return -EBUSY;
/* Use the accelerated operation if we can */ if (map->bus->reg_noinc_read) return regmap_noinc_readwrite(map, reg, val, val_len, false);
while (val_len) { if (map->max_raw_read && map->max_raw_read < val_len) read_len = map->max_raw_read; else read_len = val_len; ret = _regmap_raw_read(map, reg, val, read_len, true); if (ret) return ret; val = ((u8 *)val) + read_len; val_len -= read_len; }
return 0;}EXPORT_SYMBOL_GPL(regmap_noinc_read);
/** * regmap_field_read(): Read a value to a single register field * * @field: Register field to read from * @val: Pointer to store read value * * A value of zero will be returned on success, a negative errno will * be returned in error cases. */int regmap_field_read(struct regmap_field *field, unsigned int *val){ int ret; unsigned int reg_val; ret = regmap_read(field->regmap, field->reg, ®_val); if (ret != 0) return ret;
reg_val &= field->mask; reg_val >>= field->shift; *val = reg_val;
return ret;}EXPORT_SYMBOL_GPL(regmap_field_read);
/** * regmap_fields_read() - Read a value to a single register field with port ID * * @field: Register field to read from * @id: port ID * @val: Pointer to store read value * * A value of zero will be returned on success, a negative errno will * be returned in error cases. */int regmap_fields_read(struct regmap_field *field, unsigned int id, unsigned int *val){ int ret; unsigned int reg_val;
if (id >= field->id_size) return -EINVAL;
ret = regmap_read(field->regmap, field->reg + (field->id_offset * id), ®_val); if (ret != 0) return ret;
reg_val &= field->mask; reg_val >>= field->shift; *val = reg_val;
return ret;}EXPORT_SYMBOL_GPL(regmap_fields_read);
static int _regmap_bulk_read(struct regmap *map, unsigned int reg, const unsigned int *regs, void *val, size_t val_count){ u32 *u32 = val; u16 *u16 = val; u8 *u8 = val; int ret, i;
guard(regmap)(map);
for (i = 0; i < val_count; i++) { unsigned int ival;
if (regs) { if (!IS_ALIGNED(regs[i], map->reg_stride)) return -EINVAL; ret = _regmap_read(map, regs[i], &ival); } else { ret = _regmap_read(map, reg + regmap_get_offset(map, i), &ival); } if (ret != 0) return ret;
switch (map->format.val_bytes) { case 4: u32[i] = ival; break; case 2: u16[i] = ival; break; case 1: u8[i] = ival; break; default: return -EINVAL; } }
return 0;}
/** * regmap_bulk_read() - Read multiple sequential registers from the device * * @map: Register map to read from * @reg: First register to be read from * @val: Pointer to store read value, in native register size for device * @val_count: Number of registers to read * * A value of zero will be returned on success, a negative errno will * be returned in error cases. */int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val, size_t val_count){ int ret, i; size_t val_bytes = map->format.val_bytes; bool vol = regmap_volatile_range(map, reg, val_count);
if (!IS_ALIGNED(reg, map->reg_stride)) return -EINVAL; if (val_count == 0) return -EINVAL;
if (map->read && map->format.parse_inplace && (vol || map->cache_type == REGCACHE_NONE)) { ret = regmap_raw_read(map, reg, val, val_bytes * val_count); if (ret != 0) return ret;
for (i = 0; i < val_count * val_bytes; i += val_bytes) map->format.parse_inplace(val + i); } else { ret = _regmap_bulk_read(map, reg, NULL, val, val_count); } if (!ret) trace_regmap_bulk_read(map, reg, val, val_bytes * val_count); return ret;}EXPORT_SYMBOL_GPL(regmap_bulk_read);
/** * regmap_multi_reg_read() - Read multiple non-sequential registers from the device * * @map: Register map to read from * @regs: Array of registers to read from * @val: Pointer to store read value, in native register size for device * @val_count: Number of registers to read * * A value of zero will be returned on success, a negative errno will * be returned in error cases. */int regmap_multi_reg_read(struct regmap *map, const unsigned int *regs, void *val, size_t val_count){ if (val_count == 0) return -EINVAL;
return _regmap_bulk_read(map, 0, regs, val, val_count);}EXPORT_SYMBOL_GPL(regmap_multi_reg_read);
static int _regmap_update_bits(struct regmap *map, unsigned int reg, unsigned int mask, unsigned int val, bool *change, bool force_write){ int ret; unsigned int tmp, orig;
if (change) *change = false;
if (regmap_volatile(map, reg) && map->reg_update_bits) { if (map->cache_only) return -EBUSY;
reg = regmap_reg_addr(map, reg); ret = map->reg_update_bits(map->bus_context, reg, mask, val); if (ret == 0 && change) *change = true; } else { ret = _regmap_read(map, reg, &orig); if (ret != 0) return ret;
tmp = orig & ~mask; tmp |= val & mask;
if (force_write || (tmp != orig) || map->force_write_field) { ret = _regmap_write(map, reg, tmp); if (ret == 0 && change) *change = true; } }
return ret;}
/** * regmap_update_bits_base() - Perform a read/modify/write cycle on a register * * @map: Register map to update * @reg: Register to update * @mask: Bitmask to change * @val: New value for bitmask * @change: Boolean indicating if a write was done * @async: Boolean indicating asynchronously * @force: Boolean indicating use force update * * Perform a read/modify/write cycle on a register map with change, async, force * options. * * If async is true: * * With most buses the read must be done synchronously so this is most useful * for devices with a cache which do not need to interact with the hardware to * determine the current register value. * * Returns zero for success, a negative number on error. */int regmap_update_bits_base(struct regmap *map, unsigned int reg, unsigned int mask, unsigned int val, bool *change, bool async, bool force){ int ret;
guard(regmap)(map);
map->async = async;
ret = _regmap_update_bits(map, reg, mask, val, change, force);
map->async = false;
return ret;}EXPORT_SYMBOL_GPL(regmap_update_bits_base);
/** * regmap_test_bits() - Check if all specified bits are set in a register. * * @map: Register map to operate on * @reg: Register to read from * @bits: Bits to test * * Returns 0 if at least one of the tested bits is not set, 1 if all tested * bits are set and a negative error number if the underlying regmap_read() * fails. */int regmap_test_bits(struct regmap *map, unsigned int reg, unsigned int bits){ unsigned int val; int ret;
ret = regmap_read(map, reg, &val); if (ret) return ret;
return (val & bits) == bits;}EXPORT_SYMBOL_GPL(regmap_test_bits);
void regmap_async_complete_cb(struct regmap_async *async, int ret){ struct regmap *map = async->map; bool wake;
trace_regmap_async_io_complete(map);
spin_lock(&map->async_lock); list_move(&async->list, &map->async_free); wake = list_empty(&map->async_list);
if (ret != 0) map->async_ret = ret;
spin_unlock(&map->async_lock);
if (wake) wake_up(&map->async_waitq);}EXPORT_SYMBOL_GPL(regmap_async_complete_cb);
static int regmap_async_is_done(struct regmap *map){ unsigned long flags; int ret;
spin_lock_irqsave(&map->async_lock, flags); ret = list_empty(&map->async_list); spin_unlock_irqrestore(&map->async_lock, flags);
return ret;}
/** * regmap_async_complete - Ensure all asynchronous I/O has completed. * * @map: Map to operate on. * * Blocks until any pending asynchronous I/O has completed. Returns * an error code for any failed I/O operations. */int regmap_async_complete(struct regmap *map){ unsigned long flags; int ret;
/* Nothing to do with no async support */ if (!map->bus || !map->bus->async_write) return 0;
trace_regmap_async_complete_start(map);
wait_event(map->async_waitq, regmap_async_is_done(map));
spin_lock_irqsave(&map->async_lock, flags); ret = map->async_ret; map->async_ret = 0; spin_unlock_irqrestore(&map->async_lock, flags);
trace_regmap_async_complete_done(map);
return ret;}EXPORT_SYMBOL_GPL(regmap_async_complete);
/** * regmap_register_patch - Register and apply register updates to be applied * on device initialistion * * @map: Register map to apply updates to. * @regs: Values to update. * @num_regs: Number of entries in regs. * * Register a set of register updates to be applied to the device * whenever the device registers are synchronised with the cache and * apply them immediately. Typically this is used to apply * corrections to be applied to the device defaults on startup, such * as the updates some vendors provide to undocumented registers. * * The caller must ensure that this function cannot be called * concurrently with either itself or regcache_sync(). */int regmap_register_patch(struct regmap *map, const struct reg_sequence *regs, int num_regs){ struct reg_sequence *p; int ret; bool bypass;
if (WARN_ONCE(num_regs <= 0, "invalid registers number (%d)\n", num_regs)) return 0;
p = krealloc_array(map->patch, map->patch_regs + num_regs, sizeof(*p), GFP_KERNEL); if (!p) return -ENOMEM;
memcpy(p + map->patch_regs, regs, num_regs * sizeof(*regs)); map->patch = p; map->patch_regs += num_regs;
scoped_guard(regmap, map) { bypass = map->cache_bypass;
map->cache_bypass = true; map->async = true;
ret = _regmap_multi_reg_write(map, regs, num_regs);
map->async = false; map->cache_bypass = bypass; }
regmap_async_complete(map);
return ret;}EXPORT_SYMBOL_GPL(regmap_register_patch);
/** * regmap_get_val_bytes() - Report the size of a register value * * @map: Register map to operate on. * * Report the size of a register value, mainly intended to for use by * generic infrastructure built on top of regmap. */int regmap_get_val_bytes(struct regmap *map){ if (map->format.format_write) return -EINVAL;
return map->format.val_bytes;}EXPORT_SYMBOL_GPL(regmap_get_val_bytes);
/** * regmap_get_max_register() - Report the max register value * * @map: Register map to operate on. * * Report the max register value, mainly intended to for use by * generic infrastructure built on top of regmap. */int regmap_get_max_register(struct regmap *map){ return map->max_register_is_set ? map->max_register : -EINVAL;}EXPORT_SYMBOL_GPL(regmap_get_max_register);
/** * regmap_get_reg_stride() - Report the register address stride * * @map: Register map to operate on. * * Report the register address stride, mainly intended to for use by * generic infrastructure built on top of regmap. */int regmap_get_reg_stride(struct regmap *map){ return map->reg_stride;}EXPORT_SYMBOL_GPL(regmap_get_reg_stride);
/** * regmap_might_sleep() - Returns whether a regmap access might sleep. * * @map: Register map to operate on. * * Returns true if an access to the register might sleep, else false. */bool regmap_might_sleep(struct regmap *map){ return map->can_sleep;}EXPORT_SYMBOL_GPL(regmap_might_sleep);
int regmap_parse_val(struct regmap *map, const void *buf, unsigned int *val){ if (!map->format.parse_val) return -EINVAL;
*val = map->format.parse_val(buf);
return 0;}EXPORT_SYMBOL_GPL(regmap_parse_val);
static int __init regmap_initcall(void){ regmap_debugfs_initcall();
return 0;}postcore_initcall(regmap_initcall);