1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640 |
- .../DocBook/media/v4l/pixfmt-packed-rgb.xml | 39 ++
- .../devicetree/bindings/leds/leds-pwm.txt | 2 +
- Documentation/devicetree/bindings/mmc/mmc.txt | 11 +
- .../bindings/staging/imx-drm/fsl-imx-drm.txt | 3 +-
- arch/arm/boot/dts/imx6dl-hummingboard.dts | 27 +
- arch/arm/boot/dts/imx6q-cubox-i.dts | 4 +
- arch/arm/boot/dts/imx6qdl-cubox-i.dtsi | 78 ++-
- arch/arm/boot/dts/imx6qdl-microsom.dtsi | 98 +++
- arch/arm/configs/imx_v6_v7_defconfig | 1 +
- arch/arm/mach-imx/clk-imx6q.c | 12 +
- arch/arm/mach-imx/clk-pllv3.c | 27 +-
- drivers/Kconfig | 2 +
- drivers/Makefile | 1 +
- drivers/ata/ahci_imx.c | 184 +++++-
- drivers/cec/Kconfig | 14 +
- drivers/cec/Makefile | 1 +
- drivers/cec/cec-dev.c | 384 +++++++++++
- drivers/gpu/drm/drm_crtc_helper.c | 6 -
- drivers/leds/leds-pwm.c | 144 ++--
- drivers/mmc/core/core.c | 42 ++
- drivers/mmc/core/host.c | 68 ++
- drivers/mmc/core/sdio_irq.c | 41 +-
- drivers/mmc/host/Kconfig | 63 +-
- drivers/mmc/host/dw_mmc.c | 2 +
- drivers/mmc/host/sdhci-acpi.c | 8 +
- drivers/mmc/host/sdhci-bcm-kona.c | 4 +
- drivers/mmc/host/sdhci-bcm2835.c | 4 +
- drivers/mmc/host/sdhci-cns3xxx.c | 13 +-
- drivers/mmc/host/sdhci-dove.c | 4 +
- drivers/mmc/host/sdhci-esdhc-imx.c | 82 +--
- drivers/mmc/host/sdhci-esdhc.h | 4 +-
- drivers/mmc/host/sdhci-of-arasan.c | 4 +
- drivers/mmc/host/sdhci-of-esdhc.c | 70 +-
- drivers/mmc/host/sdhci-of-hlwd.c | 4 +
- drivers/mmc/host/sdhci-pci.c | 9 +-
- drivers/mmc/host/sdhci-pltfm.c | 4 +
- drivers/mmc/host/sdhci-pxav2.c | 14 +-
- drivers/mmc/host/sdhci-pxav3.c | 13 +-
- drivers/mmc/host/sdhci-s3c.c | 36 +-
- drivers/mmc/host/sdhci-sirf.c | 4 +
- drivers/mmc/host/sdhci-spear.c | 5 +-
- drivers/mmc/host/sdhci-tegra.c | 27 +-
- drivers/mmc/host/sdhci.c | 722 ++++++++++-----------
- drivers/mmc/host/sdhci.h | 20 +-
- drivers/regulator/anatop-regulator.c | 1 +
- drivers/regulator/core.c | 2 +-
- drivers/regulator/dummy.c | 1 +
- drivers/regulator/fixed.c | 4 +-
- drivers/staging/imx-drm/Kconfig | 18 +
- drivers/staging/imx-drm/Makefile | 3 +
- drivers/staging/imx-drm/drm-ddc-connector.c | 92 +++
- drivers/staging/imx-drm/drm-ddc-connector.h | 26 +
- drivers/staging/imx-drm/dw-hdmi-audio.c | 652 +++++++++++++++++++
- drivers/staging/imx-drm/dw-hdmi-audio.h | 15 +
- drivers/staging/imx-drm/dw-hdmi-cec.c | 205 ++++++
- drivers/staging/imx-drm/dw-hdmi-cec.h | 16 +
- drivers/staging/imx-drm/imx-hdmi.c | 178 ++---
- drivers/staging/imx-drm/imx-ldb.c | 21 +
- drivers/staging/imx-drm/imx-tve.c | 63 +-
- drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h | 5 +
- drivers/staging/imx-drm/ipu-v3/ipu-common.c | 41 +-
- drivers/staging/imx-drm/ipu-v3/ipu-dc.c | 94 ++-
- drivers/staging/imx-drm/ipu-v3/ipu-di.c | 2 +-
- drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c | 25 +-
- drivers/staging/imx-drm/ipu-v3/ipu-dp.c | 71 +-
- drivers/staging/imx-drm/ipu-v3/ipu-prv.h | 3 +
- drivers/staging/imx-drm/ipuv3-crtc.c | 16 +-
- drivers/staging/imx-drm/ipuv3-plane.c | 4 +
- drivers/staging/imx-drm/parallel-display.c | 2 +
- include/linux/cec-dev.h | 69 ++
- include/linux/mmc/host.h | 8 +
- include/linux/mmc/sdhci.h | 15 +-
- include/uapi/linux/cec-dev.h | 34 +
- include/uapi/linux/videodev2.h | 1 +
- sound/soc/fsl/imx-pcm-dma.c | 2 +-
- 75 files changed, 3162 insertions(+), 832 deletions(-)
- diff --git a/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml b/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml
- index e1c4f8b4c0b3..88a7fe1ecaf1 100644
- --- a/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml
- +++ b/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml
- @@ -279,6 +279,45 @@ colorspace <constant>V4L2_COLORSPACE_SRGB</constant>.</para>
- <entry></entry>
- <entry></entry>
- </row>
- + <row id="V4L2-PIX-FMT-RGB666">
- + <entry><constant>V4L2_PIX_FMT_RGB666</constant></entry>
- + <entry>'RGBH'</entry>
- + <entry></entry>
- + <entry>r<subscript>5</subscript></entry>
- + <entry>r<subscript>4</subscript></entry>
- + <entry>r<subscript>3</subscript></entry>
- + <entry>r<subscript>2</subscript></entry>
- + <entry>r<subscript>1</subscript></entry>
- + <entry>r<subscript>0</subscript></entry>
- + <entry>g<subscript>5</subscript></entry>
- + <entry>g<subscript>4</subscript></entry>
- + <entry></entry>
- + <entry>g<subscript>3</subscript></entry>
- + <entry>g<subscript>2</subscript></entry>
- + <entry>g<subscript>1</subscript></entry>
- + <entry>g<subscript>0</subscript></entry>
- + <entry>b<subscript>5</subscript></entry>
- + <entry>b<subscript>4</subscript></entry>
- + <entry>b<subscript>3</subscript></entry>
- + <entry>b<subscript>2</subscript></entry>
- + <entry></entry>
- + <entry>b<subscript>1</subscript></entry>
- + <entry>b<subscript>0</subscript></entry>
- + <entry></entry>
- + <entry></entry>
- + <entry></entry>
- + <entry></entry>
- + <entry></entry>
- + <entry></entry>
- + <entry></entry>
- + <entry></entry>
- + <entry></entry>
- + <entry></entry>
- + <entry></entry>
- + <entry></entry>
- + <entry></entry>
- + <entry></entry>
- + </row>
- <row id="V4L2-PIX-FMT-BGR24">
- <entry><constant>V4L2_PIX_FMT_BGR24</constant></entry>
- <entry>'BGR3'</entry>
- diff --git a/Documentation/devicetree/bindings/leds/leds-pwm.txt b/Documentation/devicetree/bindings/leds/leds-pwm.txt
- index 7297107cf832..6c6583c35f2f 100644
- --- a/Documentation/devicetree/bindings/leds/leds-pwm.txt
- +++ b/Documentation/devicetree/bindings/leds/leds-pwm.txt
- @@ -13,6 +13,8 @@ node's name represents the name of the corresponding LED.
- For the pwms and pwm-names property please refer to:
- Documentation/devicetree/bindings/pwm/pwm.txt
- - max-brightness : Maximum brightness possible for the LED
- +- active-low : (optional) For PWMs where the LED is wired to supply
- + rather than ground.
- - label : (optional)
- see Documentation/devicetree/bindings/leds/common.txt
- - linux,default-trigger : (optional)
- diff --git a/Documentation/devicetree/bindings/mmc/mmc.txt b/Documentation/devicetree/bindings/mmc/mmc.txt
- index 9dce540771fb..b9b534ebc0c5 100644
- --- a/Documentation/devicetree/bindings/mmc/mmc.txt
- +++ b/Documentation/devicetree/bindings/mmc/mmc.txt
- @@ -5,6 +5,8 @@ these definitions.
- Interpreted by the OF core:
- - reg: Registers location and length.
- - interrupts: Interrupts used by the MMC controller.
- +- clocks: Clocks needed for the host controller, if any.
- +- clock-names: Goes with clocks above.
-
- Card detection:
- If no property below is supplied, host native card detect is used.
- @@ -39,6 +41,15 @@ If no property below is supplied, host native card detect is used.
- - mmc-hs200-1_8v: eMMC HS200 mode(1.8V I/O) is supported
- - mmc-hs200-1_2v: eMMC HS200 mode(1.2V I/O) is supported
-
- +Card power and reset control:
- +The following properties can be specified for cases where the MMC
- +peripheral needs additional reset, regulator and clock lines. It is for
- +example common for WiFi/BT adapters to have these separate from the main
- +MMC bus:
- + - card-reset-gpios: Specify GPIOs for card reset (reset active low)
- + - card-external-vcc-supply: Regulator to drive (independent) card VCC
- + - clock with name "card_ext_clock": External clock provided to the card
- +
- *NOTE* on CD and WP polarity. To use common for all SD/MMC host controllers line
- polarity properties, we have to fix the meaning of the "normal" and "inverted"
- line levels. We choose to follow the SDHCI standard, which specifies both those
- diff --git a/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt b/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt
- index 3be5ce7a9654..83137ef5a1ba 100644
- --- a/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt
- +++ b/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt
- @@ -60,7 +60,8 @@ Parallel display support
- - compatible: Should be "fsl,imx-parallel-display"
- Optional properties:
- - interface_pix_fmt: How this display is connected to the
- - display interface. Currently supported types: "rgb24", "rgb565", "bgr666"
- + display interface. Currently supported types: "rgb24", "rgb565", "bgr666",
- + "rgb666"
- - edid: verbatim EDID data block describing attached display.
- - ddc: phandle describing the i2c bus handling the display data
- channel
- diff --git a/arch/arm/boot/dts/imx6dl-hummingboard.dts b/arch/arm/boot/dts/imx6dl-hummingboard.dts
- index 5bfae54fb780..5cfab68fe43d 100644
- --- a/arch/arm/boot/dts/imx6dl-hummingboard.dts
- +++ b/arch/arm/boot/dts/imx6dl-hummingboard.dts
- @@ -67,6 +67,13 @@
- status = "okay";
- };
-
- +&hdmi {
- + pinctrl-names = "default";
- + pinctrl-0 = <&pinctrl_hummingboard_hdmi>;
- + ddc-i2c-bus = <&i2c2>;
- + status = "okay";
- +};
- +
- &i2c1 {
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_hummingboard_i2c1>;
- @@ -82,6 +89,13 @@
- */
- };
-
- +&i2c2 {
- + clock-frequency = <100000>;
- + pinctrl-names = "default";
- + pinctrl-0 = <&pinctrl_hummingboard_i2c2>;
- + status = "okay";
- +};
- +
- &iomuxc {
- hummingboard {
- pinctrl_hummingboard_flexcan1: hummingboard-flexcan1 {
- @@ -97,6 +111,12 @@
- >;
- };
-
- + pinctrl_hummingboard_hdmi: hummingboard-hdmi {
- + fsl,pins = <
- + MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x1f8b0
- + >;
- + };
- +
- pinctrl_hummingboard_i2c1: hummingboard-i2c1 {
- fsl,pins = <
- MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1
- @@ -104,6 +124,13 @@
- >;
- };
-
- + pinctrl_hummingboard_i2c2: hummingboard-i2c2 {
- + fsl,pins = <
- + MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1
- + MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1
- + >;
- + };
- +
- pinctrl_hummingboard_spdif: hummingboard-spdif {
- fsl,pins = <MX6QDL_PAD_GPIO_17__SPDIF_OUT 0x13091>;
- };
- diff --git a/arch/arm/boot/dts/imx6q-cubox-i.dts b/arch/arm/boot/dts/imx6q-cubox-i.dts
- index bc5f31e3e892..9efd8b0c8011 100644
- --- a/arch/arm/boot/dts/imx6q-cubox-i.dts
- +++ b/arch/arm/boot/dts/imx6q-cubox-i.dts
- @@ -13,4 +13,8 @@
-
- &sata {
- status = "okay";
- + fsl,transmit-level-mV = <1104>;
- + fsl,transmit-boost-mdB = <0>;
- + fsl,transmit-atten-16ths = <9>;
- + fsl,no-spread-spectrum;
- };
- diff --git a/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi b/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi
- index c2a24888a276..f45380073973 100644
- --- a/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi
- +++ b/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi
- @@ -12,6 +12,19 @@
- pinctrl-0 = <&pinctrl_cubox_i_ir>;
- };
-
- + pwmleds {
- + compatible = "pwm-leds";
- + pinctrl-names = "default";
- + pinctrl-0 = <&pinctrl_cubox_i_pwm1>;
- +
- + front {
- + active-low;
- + label = "imx6:red:front";
- + max-brightness = <248>;
- + pwms = <&pwm1 0 50000>;
- + };
- + };
- +
- regulators {
- compatible = "simple-bus";
-
- @@ -55,6 +68,20 @@
- };
- };
-
- +&hdmi {
- + pinctrl-names = "default";
- + pinctrl-0 = <&pinctrl_cubox_i_hdmi>;
- + ddc-i2c-bus = <&i2c2>;
- + status = "okay";
- +};
- +
- +&i2c2 {
- + clock-frequency = <100000>;
- + pinctrl-names = "default";
- + pinctrl-0 = <&pinctrl_cubox_i_i2c2>;
- + status = "okay";
- +};
- +
- &i2c3 {
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_cubox_i_i2c3>;
- @@ -69,6 +96,19 @@
-
- &iomuxc {
- cubox_i {
- + pinctrl_cubox_i_hdmi: cubox-i-hdmi {
- + fsl,pins = <
- + MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x1f8b0
- + >;
- + };
- +
- + pinctrl_cubox_i_i2c2: cubox-i-i2c2 {
- + fsl,pins = <
- + MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1
- + MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1
- + >;
- + };
- +
- pinctrl_cubox_i_i2c3: cubox-i-i2c3 {
- fsl,pins = <
- MX6QDL_PAD_EIM_D17__I2C3_SCL 0x4001b8b1
- @@ -82,6 +122,10 @@
- >;
- };
-
- + pinctrl_cubox_i_pwm1: cubox-i-pwm1-front-led {
- + fsl,pins = <MX6QDL_PAD_DISP0_DAT8__PWM1_OUT 0x1b0b0>;
- + };
- +
- pinctrl_cubox_i_spdif: cubox-i-spdif {
- fsl,pins = <MX6QDL_PAD_GPIO_17__SPDIF_OUT 0x13091>;
- };
- @@ -111,6 +155,28 @@
- MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x13059
- >;
- };
- +
- + pinctrl_cubox_i_usdhc2_100mhz: cubox-i-usdhc2-100mhz {
- + fsl,pins = <
- + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x170b9
- + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x100b9
- + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x170b9
- + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x170b9
- + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x170b9
- + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x130b9
- + >;
- + };
- +
- + pinctrl_cubox_i_usdhc2_200mhz: cubox-i-usdhc2-200mhz {
- + fsl,pins = <
- + MX6QDL_PAD_SD2_CMD__SD2_CMD 0x170f9
- + MX6QDL_PAD_SD2_CLK__SD2_CLK 0x100f9
- + MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x170f9
- + MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x170f9
- + MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x170f9
- + MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x130f9
- + >;
- + };
- };
- };
-
- @@ -130,9 +196,19 @@
- status = "okay";
- };
-
- +&uart4 {
- + status = "okay";
- +};
- +
- +&usdhc1 {
- + status = "okay";
- +};
- +
- &usdhc2 {
- - pinctrl-names = "default";
- + pinctrl-names = "default", "state_100mhz", "state_200mhz";
- pinctrl-0 = <&pinctrl_cubox_i_usdhc2_aux &pinctrl_cubox_i_usdhc2>;
- + pinctrl-1 = <&pinctrl_cubox_i_usdhc2_aux &pinctrl_cubox_i_usdhc2_100mhz>;
- + pinctrl-2 = <&pinctrl_cubox_i_usdhc2_aux &pinctrl_cubox_i_usdhc2_200mhz>;
- vmmc-supply = <®_3p3v>;
- cd-gpios = <&gpio1 4 0>;
- status = "okay";
- diff --git a/arch/arm/boot/dts/imx6qdl-microsom.dtsi b/arch/arm/boot/dts/imx6qdl-microsom.dtsi
- index d729d0b15f25..a5d72895d9ce 100644
- --- a/arch/arm/boot/dts/imx6qdl-microsom.dtsi
- +++ b/arch/arm/boot/dts/imx6qdl-microsom.dtsi
- @@ -1,9 +1,69 @@
- /*
- * Copyright (C) 2013,2014 Russell King
- */
- +#include <dt-bindings/gpio/gpio.h>
- +/ {
- + regulators {
- + compatible = "simple-bus";
- +
- + reg_brcm_osc: brcm-osc-reg {
- + compatible = "regulator-fixed";
- + enable-active-high;
- + gpio = <&gpio5 5 0>;
- + pinctrl-names = "default";
- + pinctrl-0 = <&pinctrl_microsom_brcm_osc_reg>;
- + regulator-name = "brcm_osc_reg";
- + regulator-min-microvolt = <3300000>;
- + regulator-max-microvolt = <3300000>;
- + regulator-always-on;
- + regulator-boot-on;
- + };
- +
- + reg_brcm: brcm-reg {
- + compatible = "regulator-fixed";
- + enable-active-high;
- + gpio = <&gpio3 19 0>;
- + pinctrl-names = "default";
- + pinctrl-0 = <&pinctrl_microsom_brcm_reg>;
- + regulator-name = "brcm_reg";
- + regulator-min-microvolt = <3300000>;
- + regulator-max-microvolt = <3300000>;
- + startup-delay-us = <200000>;
- + };
- + };
- +};
-
- &iomuxc {
- microsom {
- + pinctrl_microsom_brcm_osc_reg: microsom-brcm-osc-reg {
- + fsl,pins = <
- + MX6QDL_PAD_DISP0_DAT11__GPIO5_IO05 0x40013070
- + >;
- + };
- +
- + pinctrl_microsom_brcm_reg: microsom-brcm-reg {
- + fsl,pins = <
- + MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x40013070
- + >;
- + };
- +
- + pinctrl_microsom_brcm_wifi: microsom-brcm-wifi {
- + fsl,pins = <
- + MX6QDL_PAD_GPIO_8__XTALOSC_REF_CLK_32K 0x1b0b0
- + MX6QDL_PAD_CSI0_DATA_EN__GPIO5_IO20 0x40013070
- + MX6QDL_PAD_CSI0_DAT8__GPIO5_IO26 0x40013070
- + MX6QDL_PAD_CSI0_DAT9__GPIO5_IO27 0x40013070
- + >;
- + };
- +
- + pinctrl_microsom_brcm_bt: microsom-brcm-bt {
- + fsl,pins = <
- + MX6QDL_PAD_CSI0_DAT14__GPIO6_IO00 0x40013070
- + MX6QDL_PAD_CSI0_DAT15__GPIO6_IO01 0x40013070
- + MX6QDL_PAD_CSI0_DAT18__GPIO6_IO04 0x40013070
- + >;
- + };
- +
- pinctrl_microsom_uart1: microsom-uart1 {
- fsl,pins = <
- MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1
- @@ -11,6 +71,15 @@
- >;
- };
-
- + pinctrl_microsom_uart4_1: microsom-uart4 {
- + fsl,pins = <
- + MX6QDL_PAD_CSI0_DAT12__UART4_TX_DATA 0x1b0b1
- + MX6QDL_PAD_CSI0_DAT13__UART4_RX_DATA 0x1b0b1
- + MX6QDL_PAD_CSI0_DAT16__UART4_RTS_B 0x1b0b1
- + MX6QDL_PAD_CSI0_DAT17__UART4_CTS_B 0x1b0b1
- + >;
- + };
- +
- pinctrl_microsom_usbotg: microsom-usbotg {
- /*
- * Similar to pinctrl_usbotg_2, but we want it
- @@ -18,6 +87,17 @@
- */
- fsl,pins = <MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x13059>;
- };
- +
- + pinctrl_microsom_usdhc1: microsom-usdhc1 {
- + fsl,pins = <
- + MX6QDL_PAD_SD1_CMD__SD1_CMD 0x17059
- + MX6QDL_PAD_SD1_CLK__SD1_CLK 0x10059
- + MX6QDL_PAD_SD1_DAT0__SD1_DATA0 0x17059
- + MX6QDL_PAD_SD1_DAT1__SD1_DATA1 0x17059
- + MX6QDL_PAD_SD1_DAT2__SD1_DATA2 0x17059
- + MX6QDL_PAD_SD1_DAT3__SD1_DATA3 0x17059
- + >;
- + };
- };
- };
-
- @@ -27,7 +107,25 @@
- status = "okay";
- };
-
- +/* UART4 - Connected to optional BRCM Wifi/BT/FM */
- +&uart4 {
- + pinctrl-names = "default";
- + pinctrl-0 = <&pinctrl_microsom_brcm_bt &pinctrl_microsom_uart4_1>;
- + fsl,uart-has-rtscts;
- +};
- +
- &usbotg {
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_microsom_usbotg>;
- };
- +
- +/* USDHC1 - Connected to optional BRCM Wifi/BT/FM */
- +&usdhc1 {
- + card-external-vcc-supply = <®_brcm>;
- + card-reset-gpios = <&gpio5 26 GPIO_ACTIVE_LOW>, <&gpio6 0 GPIO_ACTIVE_LOW>;
- + keep-power-in-suspend;
- + non-removable;
- + pinctrl-names = "default";
- + pinctrl-0 = <&pinctrl_microsom_brcm_wifi &pinctrl_microsom_usdhc1>;
- + vmmc-supply = <®_brcm>;
- +};
- diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig
- index 09e974392fa1..ea50d34f7944 100644
- --- a/arch/arm/configs/imx_v6_v7_defconfig
- +++ b/arch/arm/configs/imx_v6_v7_defconfig
- @@ -245,6 +245,7 @@ CONFIG_DRM_IMX_TVE=y
- CONFIG_DRM_IMX_LDB=y
- CONFIG_DRM_IMX_IPUV3_CORE=y
- CONFIG_DRM_IMX_IPUV3=y
- +CONFIG_DRM_IMX_HDMI=y
- CONFIG_COMMON_CLK_DEBUG=y
- # CONFIG_IOMMU_SUPPORT is not set
- CONFIG_PWM=y
- diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c
- index 2b4d6acfa34a..fefa6c3d4c86 100644
- --- a/arch/arm/mach-imx/clk-imx6q.c
- +++ b/arch/arm/mach-imx/clk-imx6q.c
- @@ -454,6 +454,18 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
- clk_set_parent(clk[ipu2_di0_sel], clk[ipu2_di0_pre]);
- clk_set_parent(clk[ipu2_di1_sel], clk[ipu2_di1_pre]);
-
- + if (cpu_is_imx6dl())
- + clk_set_parent(clk[ipu1_sel], clk[pll3_pfd1_540m]);
- +
- + clk_set_parent(clk[ipu1_di0_pre_sel], clk[pll5_video_div]);
- + clk_set_parent(clk[ipu1_di1_pre_sel], clk[pll5_video_div]);
- + clk_set_parent(clk[ipu2_di0_pre_sel], clk[pll5_video_div]);
- + clk_set_parent(clk[ipu2_di1_pre_sel], clk[pll5_video_div]);
- + clk_set_parent(clk[ipu1_di0_sel], clk[ipu1_di0_pre]);
- + clk_set_parent(clk[ipu1_di1_sel], clk[ipu1_di1_pre]);
- + clk_set_parent(clk[ipu2_di0_sel], clk[ipu2_di0_pre]);
- + clk_set_parent(clk[ipu2_di1_sel], clk[ipu2_di1_pre]);
- +
- /*
- * The gpmi needs 100MHz frequency in the EDO/Sync mode,
- * We can not get the 100MHz from the pll2_pfd0_352m.
- diff --git a/arch/arm/mach-imx/clk-pllv3.c b/arch/arm/mach-imx/clk-pllv3.c
- index 61364050fccd..3776f974d1dc 100644
- --- a/arch/arm/mach-imx/clk-pllv3.c
- +++ b/arch/arm/mach-imx/clk-pllv3.c
- @@ -273,9 +273,10 @@ static int clk_pllv3_av_set_rate(struct clk_hw *hw, unsigned long rate,
- struct clk_pllv3 *pll = to_clk_pllv3(hw);
- unsigned long min_rate = parent_rate * 27;
- unsigned long max_rate = parent_rate * 54;
- - u32 val, div;
- + u32 val, newval, div;
- u32 mfn, mfd = 1000000;
- s64 temp64;
- + int ret;
-
- if (rate < min_rate || rate > max_rate)
- return -EINVAL;
- @@ -287,13 +288,27 @@ static int clk_pllv3_av_set_rate(struct clk_hw *hw, unsigned long rate,
- mfn = temp64;
-
- val = readl_relaxed(pll->base);
- - val &= ~pll->div_mask;
- - val |= div;
- - writel_relaxed(val, pll->base);
- +
- + /* set the PLL into bypass mode */
- + newval = val | BM_PLL_BYPASS;
- + writel_relaxed(newval, pll->base);
- +
- + /* configure the new frequency */
- + newval &= ~pll->div_mask;
- + newval |= div;
- + writel_relaxed(newval, pll->base);
- writel_relaxed(mfn, pll->base + PLL_NUM_OFFSET);
- - writel_relaxed(mfd, pll->base + PLL_DENOM_OFFSET);
- + writel(mfd, pll->base + PLL_DENOM_OFFSET);
-
- - return clk_pllv3_wait_lock(pll);
- + ret = clk_pllv3_wait_lock(pll);
- + if (ret == 0 && val & BM_PLL_POWER) {
- + /* only if it locked can we switch back to the PLL */
- + newval &= ~BM_PLL_BYPASS;
- + newval |= val & BM_PLL_BYPASS;
- + writel(newval, pll->base);
- + }
- +
- + return ret;
- }
-
- static const struct clk_ops clk_pllv3_av_ops = {
- diff --git a/drivers/Kconfig b/drivers/Kconfig
- index 0a0a90f52d26..05a21b857996 100644
- --- a/drivers/Kconfig
- +++ b/drivers/Kconfig
- @@ -174,4 +174,6 @@ source "drivers/powercap/Kconfig"
-
- source "drivers/mcb/Kconfig"
-
- +source "drivers/cec/Kconfig"
- +
- endmenu
- diff --git a/drivers/Makefile b/drivers/Makefile
- index 7183b6af5dac..470eec2238ca 100644
- --- a/drivers/Makefile
- +++ b/drivers/Makefile
- @@ -157,3 +157,4 @@ obj-$(CONFIG_NTB) += ntb/
- obj-$(CONFIG_FMC) += fmc/
- obj-$(CONFIG_POWERCAP) += powercap/
- obj-$(CONFIG_MCB) += mcb/
- +obj-$(CONFIG_CEC) += cec/
- diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c
- index 8befeb69eeb1..54e2972fc6da 100644
- --- a/drivers/ata/ahci_imx.c
- +++ b/drivers/ata/ahci_imx.c
- @@ -62,6 +62,7 @@ struct imx_ahci_priv {
- struct regmap *gpr;
- bool no_device;
- bool first_time;
- + u32 phy_params;
- };
-
- static int ahci_imx_hotplug;
- @@ -246,14 +247,7 @@ static int imx_sata_enable(struct ahci_host_priv *hpriv)
- IMX6Q_GPR13_SATA_TX_LVL_MASK |
- IMX6Q_GPR13_SATA_MPLL_CLK_EN |
- IMX6Q_GPR13_SATA_TX_EDGE_RATE,
- - IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB |
- - IMX6Q_GPR13_SATA_RX_LOS_LVL_SATA2M |
- - IMX6Q_GPR13_SATA_RX_DPLL_MODE_2P_4F |
- - IMX6Q_GPR13_SATA_SPD_MODE_3P0G |
- - IMX6Q_GPR13_SATA_MPLL_SS_EN |
- - IMX6Q_GPR13_SATA_TX_ATTEN_9_16 |
- - IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB |
- - IMX6Q_GPR13_SATA_TX_LVL_1_025_V);
- + imxpriv->phy_params);
- regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
- IMX6Q_GPR13_SATA_MPLL_CLK_EN,
- IMX6Q_GPR13_SATA_MPLL_CLK_EN);
- @@ -324,6 +318,10 @@ static void ahci_imx_error_handler(struct ata_port *ap)
- writel(reg_val | IMX_P0PHYCR_TEST_PDDQ, mmio + IMX_P0PHYCR);
- imx_sata_disable(hpriv);
- imxpriv->no_device = true;
- +
- + dev_info(ap->dev, "no device found, disabling link.\n");
- + dev_info(ap->dev, "pass " MODULE_PARAM_PREFIX
- + ".hotplug=1 to enable hotplug\n");
- }
-
- static int ahci_imx_softreset(struct ata_link *link, unsigned int *class,
- @@ -364,6 +362,165 @@ static const struct of_device_id imx_ahci_of_match[] = {
- };
- MODULE_DEVICE_TABLE(of, imx_ahci_of_match);
-
- +struct reg_value {
- + u32 of_value;
- + u32 reg_value;
- +};
- +
- +struct reg_property {
- + const char *name;
- + const struct reg_value *values;
- + size_t num_values;
- + u32 def_value;
- + u32 set_value;
- +};
- +
- +static const struct reg_value gpr13_tx_level[] = {
- + { 937, IMX6Q_GPR13_SATA_TX_LVL_0_937_V },
- + { 947, IMX6Q_GPR13_SATA_TX_LVL_0_947_V },
- + { 957, IMX6Q_GPR13_SATA_TX_LVL_0_957_V },
- + { 966, IMX6Q_GPR13_SATA_TX_LVL_0_966_V },
- + { 976, IMX6Q_GPR13_SATA_TX_LVL_0_976_V },
- + { 986, IMX6Q_GPR13_SATA_TX_LVL_0_986_V },
- + { 996, IMX6Q_GPR13_SATA_TX_LVL_0_996_V },
- + { 1005, IMX6Q_GPR13_SATA_TX_LVL_1_005_V },
- + { 1015, IMX6Q_GPR13_SATA_TX_LVL_1_015_V },
- + { 1025, IMX6Q_GPR13_SATA_TX_LVL_1_025_V },
- + { 1035, IMX6Q_GPR13_SATA_TX_LVL_1_035_V },
- + { 1045, IMX6Q_GPR13_SATA_TX_LVL_1_045_V },
- + { 1054, IMX6Q_GPR13_SATA_TX_LVL_1_054_V },
- + { 1064, IMX6Q_GPR13_SATA_TX_LVL_1_064_V },
- + { 1074, IMX6Q_GPR13_SATA_TX_LVL_1_074_V },
- + { 1084, IMX6Q_GPR13_SATA_TX_LVL_1_084_V },
- + { 1094, IMX6Q_GPR13_SATA_TX_LVL_1_094_V },
- + { 1104, IMX6Q_GPR13_SATA_TX_LVL_1_104_V },
- + { 1113, IMX6Q_GPR13_SATA_TX_LVL_1_113_V },
- + { 1123, IMX6Q_GPR13_SATA_TX_LVL_1_123_V },
- + { 1133, IMX6Q_GPR13_SATA_TX_LVL_1_133_V },
- + { 1143, IMX6Q_GPR13_SATA_TX_LVL_1_143_V },
- + { 1152, IMX6Q_GPR13_SATA_TX_LVL_1_152_V },
- + { 1162, IMX6Q_GPR13_SATA_TX_LVL_1_162_V },
- + { 1172, IMX6Q_GPR13_SATA_TX_LVL_1_172_V },
- + { 1182, IMX6Q_GPR13_SATA_TX_LVL_1_182_V },
- + { 1191, IMX6Q_GPR13_SATA_TX_LVL_1_191_V },
- + { 1201, IMX6Q_GPR13_SATA_TX_LVL_1_201_V },
- + { 1211, IMX6Q_GPR13_SATA_TX_LVL_1_211_V },
- + { 1221, IMX6Q_GPR13_SATA_TX_LVL_1_221_V },
- + { 1230, IMX6Q_GPR13_SATA_TX_LVL_1_230_V },
- + { 1240, IMX6Q_GPR13_SATA_TX_LVL_1_240_V }
- +};
- +
- +static const struct reg_value gpr13_tx_boost[] = {
- + { 0, IMX6Q_GPR13_SATA_TX_BOOST_0_00_DB },
- + { 370, IMX6Q_GPR13_SATA_TX_BOOST_0_37_DB },
- + { 740, IMX6Q_GPR13_SATA_TX_BOOST_0_74_DB },
- + { 111, IMX6Q_GPR13_SATA_TX_BOOST_1_11_DB },
- + { 148, IMX6Q_GPR13_SATA_TX_BOOST_1_48_DB },
- + { 185, IMX6Q_GPR13_SATA_TX_BOOST_1_85_DB },
- + { 222, IMX6Q_GPR13_SATA_TX_BOOST_2_22_DB },
- + { 259, IMX6Q_GPR13_SATA_TX_BOOST_2_59_DB },
- + { 296, IMX6Q_GPR13_SATA_TX_BOOST_2_96_DB },
- + { 333, IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB },
- + { 370, IMX6Q_GPR13_SATA_TX_BOOST_3_70_DB },
- + { 407, IMX6Q_GPR13_SATA_TX_BOOST_4_07_DB },
- + { 444, IMX6Q_GPR13_SATA_TX_BOOST_4_44_DB },
- + { 481, IMX6Q_GPR13_SATA_TX_BOOST_4_81_DB },
- + { 528, IMX6Q_GPR13_SATA_TX_BOOST_5_28_DB },
- + { 575, IMX6Q_GPR13_SATA_TX_BOOST_5_75_DB }
- +};
- +
- +static const struct reg_value gpr13_tx_atten[] = {
- + { 8, IMX6Q_GPR13_SATA_TX_ATTEN_8_16 },
- + { 9, IMX6Q_GPR13_SATA_TX_ATTEN_9_16 },
- + { 10, IMX6Q_GPR13_SATA_TX_ATTEN_10_16 },
- + { 12, IMX6Q_GPR13_SATA_TX_ATTEN_12_16 },
- + { 14, IMX6Q_GPR13_SATA_TX_ATTEN_14_16 },
- + { 16, IMX6Q_GPR13_SATA_TX_ATTEN_16_16 },
- +};
- +
- +static const struct reg_value gpr13_rx_eq[] = {
- + { 500, IMX6Q_GPR13_SATA_RX_EQ_VAL_0_5_DB },
- + { 1000, IMX6Q_GPR13_SATA_RX_EQ_VAL_1_0_DB },
- + { 1500, IMX6Q_GPR13_SATA_RX_EQ_VAL_1_5_DB },
- + { 2000, IMX6Q_GPR13_SATA_RX_EQ_VAL_2_0_DB },
- + { 2500, IMX6Q_GPR13_SATA_RX_EQ_VAL_2_5_DB },
- + { 3000, IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB },
- + { 3500, IMX6Q_GPR13_SATA_RX_EQ_VAL_3_5_DB },
- + { 4000, IMX6Q_GPR13_SATA_RX_EQ_VAL_4_0_DB },
- +};
- +
- +static const struct reg_property gpr13_props[] = {
- + {
- + .name = "fsl,transmit-level-mV",
- + .values = gpr13_tx_level,
- + .num_values = ARRAY_SIZE(gpr13_tx_level),
- + .def_value = IMX6Q_GPR13_SATA_TX_LVL_1_025_V,
- + }, {
- + .name = "fsl,transmit-boost-mdB",
- + .values = gpr13_tx_boost,
- + .num_values = ARRAY_SIZE(gpr13_tx_boost),
- + .def_value = IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB,
- + }, {
- + .name = "fsl,transmit-atten-16ths",
- + .values = gpr13_tx_atten,
- + .num_values = ARRAY_SIZE(gpr13_tx_atten),
- + .def_value = IMX6Q_GPR13_SATA_TX_ATTEN_9_16,
- + }, {
- + .name = "fsl,receive-eq-mdB",
- + .values = gpr13_rx_eq,
- + .num_values = ARRAY_SIZE(gpr13_rx_eq),
- + .def_value = IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB,
- + }, {
- + .name = "fsl,no-spread-spectrum",
- + .def_value = IMX6Q_GPR13_SATA_MPLL_SS_EN,
- + .set_value = 0,
- + },
- +};
- +
- +static u32 imx_ahci_parse_props(struct device *dev,
- + const struct reg_property *prop, size_t num)
- +{
- + struct device_node *np = dev->of_node;
- + u32 reg_value = 0;
- + int i, j;
- +
- + for (i = 0; i < num; i++, prop++) {
- + u32 of_val;
- +
- + if (prop->num_values == 0) {
- + if (of_property_read_bool(np, prop->name))
- + reg_value |= prop->set_value;
- + else
- + reg_value |= prop->def_value;
- + continue;
- + }
- +
- + if (of_property_read_u32(np, prop->name, &of_val)) {
- + dev_info(dev, "%s not specified, using %08x\n",
- + prop->name, prop->def_value);
- + reg_value |= prop->def_value;
- + continue;
- + }
- +
- + for (j = 0; j < prop->num_values; j++) {
- + if (prop->values[j].of_value == of_val) {
- + dev_info(dev, "%s value %u, using %08x\n",
- + prop->name, of_val, prop->values[j].reg_value);
- + reg_value |= prop->values[j].reg_value;
- + break;
- + }
- + }
- +
- + if (j == prop->num_values) {
- + dev_err(dev, "DT property %s is not a valid value\n",
- + prop->name);
- + reg_value |= prop->def_value;
- + }
- + }
- +
- + return reg_value;
- +}
- +
- static int imx_ahci_probe(struct platform_device *pdev)
- {
- struct device *dev = &pdev->dev;
- @@ -392,6 +549,8 @@ static int imx_ahci_probe(struct platform_device *pdev)
- }
-
- if (imxpriv->type == AHCI_IMX6Q) {
- + u32 reg_value;
- +
- imxpriv->gpr = syscon_regmap_lookup_by_compatible(
- "fsl,imx6q-iomuxc-gpr");
- if (IS_ERR(imxpriv->gpr)) {
- @@ -399,6 +558,15 @@ static int imx_ahci_probe(struct platform_device *pdev)
- "failed to find fsl,imx6q-iomux-gpr regmap\n");
- return PTR_ERR(imxpriv->gpr);
- }
- +
- + reg_value = imx_ahci_parse_props(dev, gpr13_props,
- + ARRAY_SIZE(gpr13_props));
- +
- + imxpriv->phy_params =
- + IMX6Q_GPR13_SATA_RX_LOS_LVL_SATA2M |
- + IMX6Q_GPR13_SATA_RX_DPLL_MODE_2P_4F |
- + IMX6Q_GPR13_SATA_SPD_MODE_3P0G |
- + reg_value;
- }
-
- hpriv = ahci_platform_get_resources(pdev);
- diff --git a/drivers/cec/Kconfig b/drivers/cec/Kconfig
- new file mode 100644
- index 000000000000..d67cfb83de6a
- --- /dev/null
- +++ b/drivers/cec/Kconfig
- @@ -0,0 +1,14 @@
- +#
- +# Consumer Electroncs Control support
- +#
- +
- +menu "Consumer Electronics Control devices"
- +
- +config CEC
- + bool
- +
- +config HDMI_CEC_CORE
- + tristate
- + select CEC
- +
- +endmenu
- diff --git a/drivers/cec/Makefile b/drivers/cec/Makefile
- new file mode 100644
- index 000000000000..b94278bc8321
- --- /dev/null
- +++ b/drivers/cec/Makefile
- @@ -0,0 +1 @@
- +obj-$(CONFIG_HDMI_CEC_CORE) += cec-dev.o
- diff --git a/drivers/cec/cec-dev.c b/drivers/cec/cec-dev.c
- new file mode 100644
- index 000000000000..ba58d8217851
- --- /dev/null
- +++ b/drivers/cec/cec-dev.c
- @@ -0,0 +1,384 @@
- +/*
- + * HDMI Consumer Electronics Control
- + *
- + * This provides the user API for communication with HDMI CEC complaint
- + * devices in kernel drivers, and is based upon the protocol developed
- + * by Freescale for their i.MX SoCs.
- + *
- + * This program is free software; you can redistribute it and/or modify
- + * it under the terms of the GNU General Public License version 2 as
- + * published by the Free Software Foundation.
- + */
- +#include <linux/cec-dev.h>
- +#include <linux/device.h>
- +#include <linux/fs.h>
- +#include <linux/module.h>
- +#include <linux/poll.h>
- +#include <linux/sched.h>
- +#include <linux/slab.h>
- +
- +struct cec_event {
- + struct cec_user_event usr;
- + struct list_head node;
- +};
- +
- +static struct class *cec_class;
- +static int cec_major;
- +
- +static void cec_dev_send_message(struct cec_dev *cec_dev, u8 *msg,
- + size_t count)
- +{
- + unsigned long flags;
- +
- + spin_lock_irqsave(&cec_dev->lock, flags);
- + cec_dev->retries = 5;
- + cec_dev->write_busy = 1;
- + cec_dev->send_message(cec_dev, msg, count);
- + spin_unlock_irqrestore(&cec_dev->lock, flags);
- +}
- +
- +void cec_dev_event(struct cec_dev *cec_dev, int type, u8 *msg, size_t len)
- +{
- + struct cec_event *event;
- + unsigned long flags;
- +
- + event = kzalloc(sizeof(*event), GFP_ATOMIC);
- + if (event) {
- + event->usr.event_type = type;
- + event->usr.msg_len = len;
- + if (msg)
- + memcpy(event->usr.msg, msg, len);
- +
- + spin_lock_irqsave(&cec_dev->lock, flags);
- + list_add_tail(&event->node, &cec_dev->events);
- + spin_unlock_irqrestore(&cec_dev->lock, flags);
- + wake_up(&cec_dev->waitq);
- + }
- +}
- +EXPORT_SYMBOL_GPL(cec_dev_event);
- +
- +static int cec_dev_lock_write(struct cec_dev *cec_dev, struct file *file)
- + __acquires(cec_dev->mutex)
- +{
- + int ret;
- +
- + do {
- + if (file->f_flags & O_NONBLOCK) {
- + if (cec_dev->write_busy)
- + return -EAGAIN;
- + } else {
- + ret = wait_event_interruptible(cec_dev->waitq,
- + !cec_dev->write_busy);
- + if (ret)
- + break;
- + }
- +
- + ret = mutex_lock_interruptible(&cec_dev->mutex);
- + if (ret)
- + break;
- +
- + if (!cec_dev->write_busy)
- + break;
- +
- + mutex_unlock(&cec_dev->mutex);
- + } while (1);
- +
- + return ret;
- +}
- +
- +static ssize_t cec_dev_read(struct file *file, char __user *buf,
- + size_t count, loff_t *ppos)
- +{
- + struct cec_dev *cec_dev = file->private_data;
- + ssize_t ret;
- +
- + if (count > sizeof(struct cec_user_event))
- + count = sizeof(struct cec_user_event);
- +
- + if (!access_ok(VERIFY_WRITE, buf, count))
- + return -EFAULT;
- +
- + do {
- + struct cec_event *event = NULL;
- + unsigned long flags;
- +
- + spin_lock_irqsave(&cec_dev->lock, flags);
- + if (!list_empty(&cec_dev->events)) {
- + event = list_first_entry(&cec_dev->events,
- + struct cec_event, node);
- + list_del(&event->node);
- + }
- + spin_unlock_irqrestore(&cec_dev->lock, flags);
- +
- + if (event) {
- + ret = __copy_to_user(buf, &event->usr, count) ?
- + -EFAULT : count;
- + kfree(event);
- + break;
- + }
- +
- + if (file->f_flags & O_NONBLOCK) {
- + ret = -EAGAIN;
- + break;
- + }
- +
- + ret = wait_event_interruptible(cec_dev->waitq,
- + !list_empty(&cec_dev->events));
- + if (ret)
- + break;
- + } while (1);
- +
- + return ret;
- +}
- +
- +static ssize_t cec_dev_write(struct file *file, const char __user *buf,
- + size_t count, loff_t *ppos)
- +{
- + struct cec_dev *cec_dev = file->private_data;
- + u8 msg[MAX_MESSAGE_LEN];
- + int ret;
- +
- + if (count > sizeof(msg))
- + return -E2BIG;
- +
- + if (copy_from_user(msg, buf, count))
- + return -EFAULT;
- +
- + ret = cec_dev_lock_write(cec_dev, file);
- + if (ret)
- + return ret;
- +
- + cec_dev_send_message(cec_dev, msg, count);
- +
- + mutex_unlock(&cec_dev->mutex);
- +
- + return count;
- +}
- +
- +static long cec_dev_ioctl(struct file *file, u_int cmd, unsigned long arg)
- +{
- + struct cec_dev *cec_dev = file->private_data;
- + int ret;
- +
- + switch (cmd) {
- + case HDMICEC_IOC_O_SETLOGICALADDRESS:
- + case HDMICEC_IOC_SETLOGICALADDRESS:
- + if (arg > 15) {
- + ret = -EINVAL;
- + break;
- + }
- +
- + ret = cec_dev_lock_write(cec_dev, file);
- + if (ret == 0) {
- + unsigned char msg[1];
- +
- + cec_dev->addresses = BIT(arg);
- + cec_dev->set_address(cec_dev, cec_dev->addresses);
- +
- + /*
- + * Send a ping message with the source and destination
- + * set to our address; the result indicates whether
- + * unit has chosen our address simultaneously.
- + */
- + msg[0] = arg << 4 | arg;
- + cec_dev_send_message(cec_dev, msg, sizeof(msg));
- + mutex_unlock(&cec_dev->mutex);
- + }
- + break;
- +
- + case HDMICEC_IOC_STARTDEVICE:
- + ret = mutex_lock_interruptible(&cec_dev->mutex);
- + if (ret == 0) {
- + cec_dev->addresses = BIT(15);
- + cec_dev->set_address(cec_dev, cec_dev->addresses);
- + mutex_unlock(&cec_dev->mutex);
- + }
- + break;
- +
- + case HDMICEC_IOC_STOPDEVICE:
- + ret = 0;
- + break;
- +
- + case HDMICEC_IOC_GETPHYADDRESS:
- + ret = put_user(cec_dev->physical, (u16 __user *)arg);
- + ret = -ENOIOCTLCMD;
- + break;
- +
- + default:
- + ret = -ENOIOCTLCMD;
- + break;
- + }
- +
- + return ret;
- +}
- +
- +static unsigned cec_dev_poll(struct file *file, poll_table *wait)
- +{
- + struct cec_dev *cec_dev = file->private_data;
- + unsigned mask = 0;
- +
- + poll_wait(file, &cec_dev->waitq, wait);
- +
- + if (cec_dev->write_busy == 0)
- + mask |= POLLOUT | POLLWRNORM;
- + if (!list_empty(&cec_dev->events))
- + mask |= POLLIN | POLLRDNORM;
- +
- + return mask;
- +}
- +
- +static int cec_dev_release(struct inode *inode, struct file *file)
- +{
- + struct cec_dev *cec_dev = file->private_data;
- +
- + mutex_lock(&cec_dev->mutex);
- + if (cec_dev->users >= 1)
- + cec_dev->users -= 1;
- + if (cec_dev->users == 0) {
- + /*
- + * Wait for any write to complete before shutting down.
- + * A message should complete in a maximum of 2.75ms *
- + * 160 bits + 4.7ms, or 444.7ms. Let's call that 500ms.
- + * If we time out, shutdown anyway.
- + */
- + wait_event_timeout(cec_dev->waitq, !cec_dev->write_busy,
- + msecs_to_jiffies(500));
- +
- + cec_dev->release(cec_dev);
- +
- + while (!list_empty(&cec_dev->events)) {
- + struct cec_event *event;
- +
- + event = list_first_entry(&cec_dev->events,
- + struct cec_event, node);
- + list_del(&event->node);
- + kfree(event);
- + }
- + }
- + mutex_unlock(&cec_dev->mutex);
- + return 0;
- +}
- +
- +static int cec_dev_open(struct inode *inode, struct file *file)
- +{
- + struct cec_dev *cec_dev = container_of(inode->i_cdev, struct cec_dev,
- + cdev);
- + int ret = 0;
- +
- + nonseekable_open(inode, file);
- +
- + file->private_data = cec_dev;
- +
- + ret = mutex_lock_interruptible(&cec_dev->mutex);
- + if (ret)
- + return ret;
- +
- + if (cec_dev->users++ == 0) {
- + cec_dev->addresses = BIT(15);
- +
- + ret = cec_dev->open(cec_dev);
- + if (ret < 0)
- + cec_dev->users = 0;
- + }
- + mutex_unlock(&cec_dev->mutex);
- +
- + return ret;
- +}
- +
- +static const struct file_operations hdmi_cec_fops = {
- + .owner = THIS_MODULE,
- + .read = cec_dev_read,
- + .write = cec_dev_write,
- + .open = cec_dev_open,
- + .unlocked_ioctl = cec_dev_ioctl,
- + .release = cec_dev_release,
- + .poll = cec_dev_poll,
- +};
- +
- +void cec_dev_init(struct cec_dev *cec_dev, struct module *module)
- +{
- + cec_dev->devn = MKDEV(cec_major, 0);
- +
- + INIT_LIST_HEAD(&cec_dev->events);
- + init_waitqueue_head(&cec_dev->waitq);
- + spin_lock_init(&cec_dev->lock);
- + mutex_init(&cec_dev->mutex);
- +
- + cec_dev->addresses = BIT(15);
- +
- + cdev_init(&cec_dev->cdev, &hdmi_cec_fops);
- + cec_dev->cdev.owner = module;
- +}
- +EXPORT_SYMBOL_GPL(cec_dev_init);
- +
- +int cec_dev_add(struct cec_dev *cec_dev, struct device *dev, const char *name)
- +{
- + struct device *cd;
- + int ret;
- +
- + ret = cdev_add(&cec_dev->cdev, cec_dev->devn, 1);
- + if (ret < 0)
- + goto err_cdev;
- +
- + cd = device_create(cec_class, dev, cec_dev->devn, NULL, name);
- + if (IS_ERR(cd)) {
- + ret = PTR_ERR(cd);
- + dev_err(dev, "can't create device: %d\n", ret);
- + goto err_dev;
- + }
- +
- + return 0;
- +
- + err_dev:
- + cdev_del(&cec_dev->cdev);
- + err_cdev:
- + return ret;
- +}
- +EXPORT_SYMBOL_GPL(cec_dev_add);
- +
- +void cec_dev_remove(struct cec_dev *cec_dev)
- +{
- + device_destroy(cec_class, cec_dev->devn);
- + cdev_del(&cec_dev->cdev);
- +}
- +EXPORT_SYMBOL_GPL(cec_dev_remove);
- +
- +static int cec_init(void)
- +{
- + dev_t dev;
- + int ret;
- +
- + cec_class = class_create(THIS_MODULE, "hdmi-cec");
- + if (IS_ERR(cec_class)) {
- + ret = PTR_ERR(cec_class);
- + pr_err("cec: can't create cec class: %d\n", ret);
- + goto err_class;
- + }
- +
- + ret = alloc_chrdev_region(&dev, 0, 1, "hdmi-cec");
- + if (ret) {
- + pr_err("cec: can't create character devices: %d\n", ret);
- + goto err_chrdev;
- + }
- +
- + cec_major = MAJOR(dev);
- +
- + return 0;
- +
- + err_chrdev:
- + class_destroy(cec_class);
- + err_class:
- + return ret;
- +}
- +subsys_initcall(cec_init);
- +
- +static void cec_exit(void)
- +{
- + unregister_chrdev_region(MKDEV(cec_major, 0), 1);
- + class_destroy(cec_class);
- +}
- +module_exit(cec_exit);
- +
- +MODULE_AUTHOR("Russell King <rmk+kernel@arm.linux.org.uk>");
- +MODULE_DESCRIPTION("Generic HDMI CEC driver");
- +MODULE_LICENSE("GPL");
- diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
- index df281b54db01..20585cf62091 100644
- --- a/drivers/gpu/drm/drm_crtc_helper.c
- +++ b/drivers/gpu/drm/drm_crtc_helper.c
- @@ -140,16 +140,10 @@ drm_encoder_disable(struct drm_encoder *encoder)
- static void __drm_helper_disable_unused_functions(struct drm_device *dev)
- {
- struct drm_encoder *encoder;
- - struct drm_connector *connector;
- struct drm_crtc *crtc;
-
- drm_warn_on_modeset_not_all_locked(dev);
-
- - list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
- - if (!connector->encoder)
- - continue;
- - }
- -
- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
- if (!drm_helper_encoder_in_use(encoder)) {
- drm_encoder_disable(encoder);
- diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c
- index 7d0aaed1e23a..f5cf1b0f2748 100644
- --- a/drivers/leds/leds-pwm.c
- +++ b/drivers/leds/leds-pwm.c
- @@ -69,6 +69,10 @@ static void led_pwm_set(struct led_classdev *led_cdev,
-
- duty *= brightness;
- do_div(duty, max);
- +
- + if (led_dat->active_low)
- + duty = led_dat->period - duty;
- +
- led_dat->duty = duty;
-
- if (led_dat->can_sleep)
- @@ -92,55 +96,75 @@ static void led_pwm_cleanup(struct led_pwm_priv *priv)
- }
- }
-
- -static int led_pwm_create_of(struct platform_device *pdev,
- - struct led_pwm_priv *priv)
- +static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv,
- + struct led_pwm *led, struct device_node *child)
- {
- - struct device_node *child;
- + struct led_pwm_data *led_data = &priv->leds[priv->num_leds];
- int ret;
-
- - for_each_child_of_node(pdev->dev.of_node, child) {
- - struct led_pwm_data *led_dat = &priv->leds[priv->num_leds];
- + led_data->active_low = led->active_low;
- + led_data->period = led->pwm_period_ns;
- + led_data->cdev.name = led->name;
- + led_data->cdev.default_trigger = led->default_trigger;
- + led_data->cdev.brightness_set = led_pwm_set;
- + led_data->cdev.brightness = LED_OFF;
- + led_data->cdev.max_brightness = led->max_brightness;
- + led_data->cdev.flags = LED_CORE_SUSPENDRESUME;
- +
- + if (child)
- + led_data->pwm = devm_of_pwm_get(dev, child, NULL);
- + else
- + led_data->pwm = devm_pwm_get(dev, led->name);
- + if (IS_ERR(led_data->pwm)) {
- + ret = PTR_ERR(led_data->pwm);
- + dev_err(dev, "unable to request PWM for %s: %d\n",
- + led->name, ret);
- + return ret;
- + }
-
- - led_dat->cdev.name = of_get_property(child, "label",
- - NULL) ? : child->name;
- + if (child)
- + led_data->period = pwm_get_period(led_data->pwm);
-
- - led_dat->pwm = devm_of_pwm_get(&pdev->dev, child, NULL);
- - if (IS_ERR(led_dat->pwm)) {
- - dev_err(&pdev->dev, "unable to request PWM for %s\n",
- - led_dat->cdev.name);
- - ret = PTR_ERR(led_dat->pwm);
- - goto err;
- - }
- - /* Get the period from PWM core when n*/
- - led_dat->period = pwm_get_period(led_dat->pwm);
- + led_data->can_sleep = pwm_can_sleep(led_data->pwm);
- + if (led_data->can_sleep)
- + INIT_WORK(&led_data->work, led_pwm_work);
-
- - led_dat->cdev.default_trigger = of_get_property(child,
- - "linux,default-trigger", NULL);
- - of_property_read_u32(child, "max-brightness",
- - &led_dat->cdev.max_brightness);
- + ret = led_classdev_register(dev, &led_data->cdev);
- + if (ret == 0) {
- + priv->num_leds++;
- + } else {
- + dev_err(dev, "failed to register PWM led for %s: %d\n",
- + led->name, ret);
- + }
-
- - led_dat->cdev.brightness_set = led_pwm_set;
- - led_dat->cdev.brightness = LED_OFF;
- - led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
- + return ret;
- +}
-
- - led_dat->can_sleep = pwm_can_sleep(led_dat->pwm);
- - if (led_dat->can_sleep)
- - INIT_WORK(&led_dat->work, led_pwm_work);
- +static int led_pwm_create_of(struct device *dev, struct led_pwm_priv *priv)
- +{
- + struct device_node *child;
- + struct led_pwm led;
- + int ret = 0;
-
- - ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
- - if (ret < 0) {
- - dev_err(&pdev->dev, "failed to register for %s\n",
- - led_dat->cdev.name);
- + memset(&led, 0, sizeof(led));
- +
- + for_each_child_of_node(dev->of_node, child) {
- + led.name = of_get_property(child, "label", NULL) ? :
- + child->name;
- +
- + led.default_trigger = of_get_property(child,
- + "linux,default-trigger", NULL);
- + led.active_low = of_property_read_bool(child, "active-low");
- + of_property_read_u32(child, "max-brightness",
- + &led.max_brightness);
- +
- + ret = led_pwm_add(dev, priv, &led, child);
- + if (ret) {
- of_node_put(child);
- - goto err;
- + break;
- }
- - priv->num_leds++;
- }
-
- - return 0;
- -err:
- - led_pwm_cleanup(priv);
- -
- return ret;
- }
-
- @@ -166,51 +190,23 @@ static int led_pwm_probe(struct platform_device *pdev)
-
- if (pdata) {
- for (i = 0; i < count; i++) {
- - struct led_pwm *cur_led = &pdata->leds[i];
- - struct led_pwm_data *led_dat = &priv->leds[i];
- -
- - led_dat->pwm = devm_pwm_get(&pdev->dev, cur_led->name);
- - if (IS_ERR(led_dat->pwm)) {
- - ret = PTR_ERR(led_dat->pwm);
- - dev_err(&pdev->dev,
- - "unable to request PWM for %s\n",
- - cur_led->name);
- - goto err;
- - }
- -
- - led_dat->cdev.name = cur_led->name;
- - led_dat->cdev.default_trigger = cur_led->default_trigger;
- - led_dat->active_low = cur_led->active_low;
- - led_dat->period = cur_led->pwm_period_ns;
- - led_dat->cdev.brightness_set = led_pwm_set;
- - led_dat->cdev.brightness = LED_OFF;
- - led_dat->cdev.max_brightness = cur_led->max_brightness;
- - led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
- -
- - led_dat->can_sleep = pwm_can_sleep(led_dat->pwm);
- - if (led_dat->can_sleep)
- - INIT_WORK(&led_dat->work, led_pwm_work);
- -
- - ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
- - if (ret < 0)
- - goto err;
- + ret = led_pwm_add(&pdev->dev, priv, &pdata->leds[i],
- + NULL);
- + if (ret)
- + break;
- }
- - priv->num_leds = count;
- } else {
- - ret = led_pwm_create_of(pdev, priv);
- - if (ret)
- - return ret;
- + ret = led_pwm_create_of(&pdev->dev, priv);
- + }
- +
- + if (ret) {
- + led_pwm_cleanup(priv);
- + return ret;
- }
-
- platform_set_drvdata(pdev, priv);
-
- return 0;
- -
- -err:
- - priv->num_leds = i;
- - led_pwm_cleanup(priv);
- -
- - return ret;
- }
-
- static int led_pwm_remove(struct platform_device *pdev)
- diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
- index acbc3f2aaaf9..41c4033ec765 100644
- --- a/drivers/mmc/core/core.c
- +++ b/drivers/mmc/core/core.c
- @@ -13,11 +13,13 @@
- #include <linux/module.h>
- #include <linux/init.h>
- #include <linux/interrupt.h>
- +#include <linux/clk.h>
- #include <linux/completion.h>
- #include <linux/device.h>
- #include <linux/delay.h>
- #include <linux/pagemap.h>
- #include <linux/err.h>
- +#include <linux/gpio.h>
- #include <linux/leds.h>
- #include <linux/scatterlist.h>
- #include <linux/log2.h>
- @@ -1504,6 +1506,43 @@ void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type)
- mmc_host_clk_release(host);
- }
-
- +static void mmc_card_power_up(struct mmc_host *host)
- +{
- + int i;
- + struct gpio_desc **gds = host->card_reset_gpios;
- +
- + for (i = 0; i < ARRAY_SIZE(host->card_reset_gpios); i++) {
- + if (gds[i]) {
- + dev_dbg(host->parent, "Asserting reset line %d", i);
- + gpiod_set_value(gds[i], 1);
- + }
- + }
- +
- + if (host->card_regulator) {
- + dev_dbg(host->parent, "Enabling external regulator");
- + if (regulator_enable(host->card_regulator))
- + dev_err(host->parent, "Failed to enable external regulator");
- + }
- +
- + if (host->card_clk) {
- + dev_dbg(host->parent, "Enabling external clock");
- + clk_prepare_enable(host->card_clk);
- + }
- +
- + /* 2ms delay to let clocks and power settle */
- + mmc_delay(20);
- +
- + for (i = 0; i < ARRAY_SIZE(host->card_reset_gpios); i++) {
- + if (gds[i]) {
- + dev_dbg(host->parent, "Deasserting reset line %d", i);
- + gpiod_set_value(gds[i], 0);
- + }
- + }
- +
- + /* 2ms delay to after reset release */
- + mmc_delay(20);
- +}
- +
- /*
- * Apply power to the MMC stack. This is a two-stage process.
- * First, we enable power to the card without the clock running.
- @@ -1520,6 +1559,9 @@ void mmc_power_up(struct mmc_host *host, u32 ocr)
- if (host->ios.power_mode == MMC_POWER_ON)
- return;
-
- + /* Power up the card/module first, if needed */
- + mmc_card_power_up(host);
- +
- mmc_host_clk_hold(host);
-
- host->ios.vdd = fls(ocr) - 1;
- diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
- index fdea825dbb24..c523f55b317c 100644
- --- a/drivers/mmc/core/host.c
- +++ b/drivers/mmc/core/host.c
- @@ -12,14 +12,18 @@
- * MMC host class device management
- */
-
- +#include <linux/kernel.h>
- +#include <linux/clk.h>
- #include <linux/device.h>
- #include <linux/err.h>
- +#include <linux/gpio/consumer.h>
- #include <linux/idr.h>
- #include <linux/of.h>
- #include <linux/of_gpio.h>
- #include <linux/pagemap.h>
- #include <linux/export.h>
- #include <linux/leds.h>
- +#include <linux/regulator/consumer.h>
- #include <linux/slab.h>
- #include <linux/suspend.h>
-
- @@ -457,6 +461,66 @@ int mmc_of_parse(struct mmc_host *host)
-
- EXPORT_SYMBOL(mmc_of_parse);
-
- +static int mmc_of_parse_child(struct mmc_host *host)
- +{
- + struct device_node *np;
- + struct clk *clk;
- + int i;
- +
- + if (!host->parent || !host->parent->of_node)
- + return 0;
- +
- + np = host->parent->of_node;
- +
- + host->card_regulator = regulator_get(host->parent, "card-external-vcc");
- + if (IS_ERR(host->card_regulator)) {
- + if (PTR_ERR(host->card_regulator) == -EPROBE_DEFER)
- + return PTR_ERR(host->card_regulator);
- + host->card_regulator = NULL;
- + }
- +
- + /* Parse card power/reset/clock control */
- + if (of_find_property(np, "card-reset-gpios", NULL)) {
- + struct gpio_desc *gpd;
- + int level = 0;
- +
- + /*
- + * If the regulator is enabled, then we can hold the
- + * card in reset with an active high resets. Otherwise,
- + * hold the resets low.
- + */
- + if (host->card_regulator && regulator_is_enabled(host->card_regulator))
- + level = 1;
- +
- + for (i = 0; i < ARRAY_SIZE(host->card_reset_gpios); i++) {
- + gpd = devm_gpiod_get_index(host->parent, "card-reset", i);
- + if (IS_ERR(gpd)) {
- + if (PTR_ERR(gpd) == -EPROBE_DEFER)
- + return PTR_ERR(gpd);
- + break;
- + }
- + gpiod_direction_output(gpd, gpiod_is_active_low(gpd) | level);
- + host->card_reset_gpios[i] = gpd;
- + }
- +
- + gpd = devm_gpiod_get_index(host->parent, "card-reset", ARRAY_SIZE(host->card_reset_gpios));
- + if (!IS_ERR(gpd)) {
- + dev_warn(host->parent, "More reset gpios than we can handle");
- + gpiod_put(gpd);
- + }
- + }
- +
- + clk = of_clk_get_by_name(np, "card_ext_clock");
- + if (IS_ERR(clk)) {
- + if (PTR_ERR(clk) == -EPROBE_DEFER)
- + return PTR_ERR(clk);
- + clk = NULL;
- + }
- + host->card_clk = clk;
- +
- + return 0;
- +}
- +
- /**
- * mmc_alloc_host - initialise the per-host structure.
- * @extra: sizeof private data structure
- @@ -536,6 +600,10 @@ int mmc_add_host(struct mmc_host *host)
- {
- int err;
-
- + err = mmc_of_parse_child(host);
- + if (err)
- + return err;
- +
- WARN_ON((host->caps & MMC_CAP_SDIO_IRQ) &&
- !host->ops->enable_sdio_irq);
-
- diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c
- index aaa90460ed23..5cc13c8d35bb 100644
- --- a/drivers/mmc/core/sdio_irq.c
- +++ b/drivers/mmc/core/sdio_irq.c
- @@ -90,6 +90,15 @@ static int process_sdio_pending_irqs(struct mmc_host *host)
- return ret;
- }
-
- +void sdio_run_irqs(struct mmc_host *host)
- +{
- + mmc_claim_host(host);
- + host->sdio_irq_pending = true;
- + process_sdio_pending_irqs(host);
- + mmc_release_host(host);
- +}
- +EXPORT_SYMBOL_GPL(sdio_run_irqs);
- +
- static int sdio_irq_thread(void *_host)
- {
- struct mmc_host *host = _host;
- @@ -189,14 +198,20 @@ static int sdio_card_irq_get(struct mmc_card *card)
- WARN_ON(!host->claimed);
-
- if (!host->sdio_irqs++) {
- - atomic_set(&host->sdio_irq_thread_abort, 0);
- - host->sdio_irq_thread =
- - kthread_run(sdio_irq_thread, host, "ksdioirqd/%s",
- - mmc_hostname(host));
- - if (IS_ERR(host->sdio_irq_thread)) {
- - int err = PTR_ERR(host->sdio_irq_thread);
- - host->sdio_irqs--;
- - return err;
- + if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD)) {
- + atomic_set(&host->sdio_irq_thread_abort, 0);
- + host->sdio_irq_thread =
- + kthread_run(sdio_irq_thread, host,
- + "ksdioirqd/%s", mmc_hostname(host));
- + if (IS_ERR(host->sdio_irq_thread)) {
- + int err = PTR_ERR(host->sdio_irq_thread);
- + host->sdio_irqs--;
- + return err;
- + }
- + } else {
- + mmc_host_clk_hold(host);
- + host->ops->enable_sdio_irq(host, 1);
- + mmc_host_clk_release(host);
- }
- }
-
- @@ -211,8 +226,14 @@ static int sdio_card_irq_put(struct mmc_card *card)
- BUG_ON(host->sdio_irqs < 1);
-
- if (!--host->sdio_irqs) {
- - atomic_set(&host->sdio_irq_thread_abort, 1);
- - kthread_stop(host->sdio_irq_thread);
- + if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD)) {
- + atomic_set(&host->sdio_irq_thread_abort, 1);
- + kthread_stop(host->sdio_irq_thread);
- + } else {
- + mmc_host_clk_hold(host);
- + host->ops->enable_sdio_irq(host, 0);
- + mmc_host_clk_release(host);
- + }
- }
-
- return 0;
- diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
- index 8aaf8c1f3f63..d8c1f31ab37f 100644
- --- a/drivers/mmc/host/Kconfig
- +++ b/drivers/mmc/host/Kconfig
- @@ -25,8 +25,7 @@ config MMC_PXA
- If unsure, say N.
-
- config MMC_SDHCI
- - tristate "Secure Digital Host Controller Interface support"
- - depends on HAS_DMA
- + tristate
- help
- This selects the generic Secure Digital Host Controller Interface.
- It is used by manufacturers such as Texas Instruments(R), Ricoh(R)
- @@ -59,7 +58,8 @@ config MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
-
- config MMC_SDHCI_PCI
- tristate "SDHCI support on PCI bus"
- - depends on MMC_SDHCI && PCI
- + depends on PCI && HAS_DMA
- + select MMC_SDHCI
- help
- This selects the PCI Secure Digital Host Controller Interface.
- Most controllers found today are PCI devices.
- @@ -83,7 +83,8 @@ config MMC_RICOH_MMC
-
- config MMC_SDHCI_ACPI
- tristate "SDHCI support for ACPI enumerated SDHCI controllers"
- - depends on MMC_SDHCI && ACPI
- + depends on ACPI && HAS_DMA
- + select MMC_SDHCI
- help
- This selects support for ACPI enumerated SDHCI controllers,
- identified by ACPI Compatibility ID PNP0D40 or specific
- @@ -94,8 +95,8 @@ config MMC_SDHCI_ACPI
- If unsure, say N.
-
- config MMC_SDHCI_PLTFM
- - tristate "SDHCI platform and OF driver helper"
- - depends on MMC_SDHCI
- + tristate
- + select MMC_SDHCI
- help
- This selects the common helper functions support for Secure Digital
- Host Controller Interface based platform and OF drivers.
- @@ -106,8 +107,8 @@ config MMC_SDHCI_PLTFM
-
- config MMC_SDHCI_OF_ARASAN
- tristate "SDHCI OF support for the Arasan SDHCI controllers"
- - depends on MMC_SDHCI_PLTFM
- - depends on OF
- + depends on OF && HAS_DMA
- + select MMC_SDHCI_PLTFM
- help
- This selects the Arasan Secure Digital Host Controller Interface
- (SDHCI). This hardware is found e.g. in Xilinx' Zynq SoC.
- @@ -118,9 +119,9 @@ config MMC_SDHCI_OF_ARASAN
-
- config MMC_SDHCI_OF_ESDHC
- tristate "SDHCI OF support for the Freescale eSDHC controller"
- - depends on MMC_SDHCI_PLTFM
- - depends on PPC_OF
- + depends on PPC_OF && HAS_DMA
- select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
- + select MMC_SDHCI_PLTFM
- help
- This selects the Freescale eSDHC controller support.
-
- @@ -130,9 +131,9 @@ config MMC_SDHCI_OF_ESDHC
-
- config MMC_SDHCI_OF_HLWD
- tristate "SDHCI OF support for the Nintendo Wii SDHCI controllers"
- - depends on MMC_SDHCI_PLTFM
- - depends on PPC_OF
- + depends on PPC_OF && HAS_DMA
- select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
- + select MMC_SDHCI_PLTFM
- help
- This selects the Secure Digital Host Controller Interface (SDHCI)
- found in the "Hollywood" chipset of the Nintendo Wii video game
- @@ -144,8 +145,8 @@ config MMC_SDHCI_OF_HLWD
-
- config MMC_SDHCI_CNS3XXX
- tristate "SDHCI support on the Cavium Networks CNS3xxx SoC"
- - depends on ARCH_CNS3XXX
- - depends on MMC_SDHCI_PLTFM
- + depends on ARCH_CNS3XXX && HAS_DMA
- + select MMC_SDHCI_PLTFM
- help
- This selects the SDHCI support for CNS3xxx System-on-Chip devices.
-
- @@ -155,9 +156,9 @@ config MMC_SDHCI_CNS3XXX
-
- config MMC_SDHCI_ESDHC_IMX
- tristate "SDHCI support for the Freescale eSDHC/uSDHC i.MX controller"
- - depends on ARCH_MXC
- - depends on MMC_SDHCI_PLTFM
- + depends on ARCH_MXC && HAS_DMA
- select MMC_SDHCI_IO_ACCESSORS
- + select MMC_SDHCI_PLTFM
- help
- This selects the Freescale eSDHC/uSDHC controller support
- found on i.MX25, i.MX35 i.MX5x and i.MX6x.
- @@ -168,9 +169,9 @@ config MMC_SDHCI_ESDHC_IMX
-
- config MMC_SDHCI_DOVE
- tristate "SDHCI support on Marvell's Dove SoC"
- - depends on ARCH_DOVE
- - depends on MMC_SDHCI_PLTFM
- + depends on ARCH_DOVE && HAS_DMA
- select MMC_SDHCI_IO_ACCESSORS
- + select MMC_SDHCI_PLTFM
- help
- This selects the Secure Digital Host Controller Interface in
- Marvell's Dove SoC.
- @@ -181,9 +182,9 @@ config MMC_SDHCI_DOVE
-
- config MMC_SDHCI_TEGRA
- tristate "SDHCI platform support for the Tegra SD/MMC Controller"
- - depends on ARCH_TEGRA
- - depends on MMC_SDHCI_PLTFM
- + depends on ARCH_TEGRA && HAS_DMA
- select MMC_SDHCI_IO_ACCESSORS
- + select MMC_SDHCI_PLTFM
- help
- This selects the Tegra SD/MMC controller. If you have a Tegra
- platform with SD or MMC devices, say Y or M here.
- @@ -192,7 +193,8 @@ config MMC_SDHCI_TEGRA
-
- config MMC_SDHCI_S3C
- tristate "SDHCI support on Samsung S3C SoC"
- - depends on MMC_SDHCI && PLAT_SAMSUNG
- + depends on PLAT_SAMSUNG && HAS_DMA
- + select MMC_SDHCI
- help
- This selects the Secure Digital Host Controller Interface (SDHCI)
- often referrered to as the HSMMC block in some of the Samsung S3C
- @@ -204,8 +206,8 @@ config MMC_SDHCI_S3C
-
- config MMC_SDHCI_SIRF
- tristate "SDHCI support on CSR SiRFprimaII and SiRFmarco SoCs"
- - depends on ARCH_SIRF
- - depends on MMC_SDHCI_PLTFM
- + depends on ARCH_SIRF && HAS_DMA
- + select MMC_SDHCI_PLTFM
- help
- This selects the SDHCI support for SiRF System-on-Chip devices.
-
- @@ -215,8 +217,7 @@ config MMC_SDHCI_SIRF
-
- config MMC_SDHCI_PXAV3
- tristate "Marvell MMP2 SD Host Controller support (PXAV3)"
- - depends on CLKDEV_LOOKUP
- - select MMC_SDHCI
- + depends on CLKDEV_LOOKUP && HAS_DMA
- select MMC_SDHCI_PLTFM
- default CPU_MMP2
- help
- @@ -228,8 +229,7 @@ config MMC_SDHCI_PXAV3
-
- config MMC_SDHCI_PXAV2
- tristate "Marvell PXA9XX SD Host Controller support (PXAV2)"
- - depends on CLKDEV_LOOKUP
- - select MMC_SDHCI
- + depends on CLKDEV_LOOKUP && HAS_DMA
- select MMC_SDHCI_PLTFM
- default CPU_PXA910
- help
- @@ -241,7 +241,8 @@ config MMC_SDHCI_PXAV2
-
- config MMC_SDHCI_SPEAR
- tristate "SDHCI support on ST SPEAr platform"
- - depends on MMC_SDHCI && PLAT_SPEAR
- + depends on PLAT_SPEAR && HAS_DMA
- + select MMC_SDHCI
- help
- This selects the Secure Digital Host Controller Interface (SDHCI)
- often referrered to as the HSMMC block in some of the ST SPEAR range
- @@ -263,7 +264,7 @@ config MMC_SDHCI_S3C_DMA
-
- config MMC_SDHCI_BCM_KONA
- tristate "SDHCI support on Broadcom KONA platform"
- - depends on ARCH_BCM_MOBILE
- + depends on ARCH_BCM_MOBILE && HAS_DMA
- select MMC_SDHCI_PLTFM
- help
- This selects the Broadcom Kona Secure Digital Host Controller
- @@ -274,9 +275,9 @@ config MMC_SDHCI_BCM_KONA
-
- config MMC_SDHCI_BCM2835
- tristate "SDHCI platform support for the BCM2835 SD/MMC Controller"
- - depends on ARCH_BCM2835
- - depends on MMC_SDHCI_PLTFM
- + depends on ARCH_BCM2835 && HAS_DMA
- select MMC_SDHCI_IO_ACCESSORS
- + select MMC_SDHCI_PLTFM
- help
- This selects the BCM2835 SD/MMC controller. If you have a BCM2835
- platform with SD or MMC devices, say Y or M here.
- diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
- index cced599d5aeb..a2c12ebb376e 100644
- --- a/drivers/mmc/host/dw_mmc.c
- +++ b/drivers/mmc/host/dw_mmc.c
- @@ -2140,6 +2140,8 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
- if (!mmc)
- return -ENOMEM;
-
- + mmc_of_parse(mmc);
- +
- slot = mmc_priv(mmc);
- slot->id = id;
- slot->mmc = mmc;
- diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c
- index ebb3f392b589..8ce3c28cb76e 100644
- --- a/drivers/mmc/host/sdhci-acpi.c
- +++ b/drivers/mmc/host/sdhci-acpi.c
- @@ -102,11 +102,19 @@ static void sdhci_acpi_int_hw_reset(struct sdhci_host *host)
- }
-
- static const struct sdhci_ops sdhci_acpi_ops_dflt = {
- + .set_clock = sdhci_set_clock,
- .enable_dma = sdhci_acpi_enable_dma,
- + .set_bus_width = sdhci_set_bus_width,
- + .reset = sdhci_reset,
- + .set_uhs_signaling = sdhci_set_uhs_signaling,
- };
-
- static const struct sdhci_ops sdhci_acpi_ops_int = {
- + .set_clock = sdhci_set_clock,
- .enable_dma = sdhci_acpi_enable_dma,
- + .set_bus_width = sdhci_set_bus_width,
- + .reset = sdhci_reset,
- + .set_uhs_signaling = sdhci_set_uhs_signaling,
- .hw_reset = sdhci_acpi_int_hw_reset,
- };
-
- diff --git a/drivers/mmc/host/sdhci-bcm-kona.c b/drivers/mmc/host/sdhci-bcm-kona.c
- index 6f166e63b817..dd780c315a63 100644
- --- a/drivers/mmc/host/sdhci-bcm-kona.c
- +++ b/drivers/mmc/host/sdhci-bcm-kona.c
- @@ -206,9 +206,13 @@ static void sdhci_bcm_kona_init_74_clocks(struct sdhci_host *host,
- }
-
- static struct sdhci_ops sdhci_bcm_kona_ops = {
- + .set_clock = sdhci_set_clock,
- .get_max_clock = sdhci_bcm_kona_get_max_clk,
- .get_timeout_clock = sdhci_bcm_kona_get_timeout_clock,
- .platform_send_init_74_clocks = sdhci_bcm_kona_init_74_clocks,
- + .set_bus_width = sdhci_set_bus_width,
- + .reset = sdhci_reset,
- + .set_uhs_signaling = sdhci_set_uhs_signaling,
- .card_event = sdhci_bcm_kona_card_event,
- };
-
- diff --git a/drivers/mmc/host/sdhci-bcm2835.c b/drivers/mmc/host/sdhci-bcm2835.c
- index f6d8d67c545f..46af9a439d7b 100644
- --- a/drivers/mmc/host/sdhci-bcm2835.c
- +++ b/drivers/mmc/host/sdhci-bcm2835.c
- @@ -131,8 +131,12 @@ static const struct sdhci_ops bcm2835_sdhci_ops = {
- .read_l = bcm2835_sdhci_readl,
- .read_w = bcm2835_sdhci_readw,
- .read_b = bcm2835_sdhci_readb,
- + .set_clock = sdhci_set_clock,
- .get_max_clock = sdhci_pltfm_clk_get_max_clock,
- .get_min_clock = bcm2835_sdhci_get_min_clock,
- + .set_bus_width = sdhci_set_bus_width,
- + .reset = sdhci_reset,
- + .set_uhs_signaling = sdhci_set_uhs_signaling,
- };
-
- static const struct sdhci_pltfm_data bcm2835_sdhci_pdata = {
- diff --git a/drivers/mmc/host/sdhci-cns3xxx.c b/drivers/mmc/host/sdhci-cns3xxx.c
- index f2cc26633cb2..14b74075589a 100644
- --- a/drivers/mmc/host/sdhci-cns3xxx.c
- +++ b/drivers/mmc/host/sdhci-cns3xxx.c
- @@ -30,13 +30,12 @@ static void sdhci_cns3xxx_set_clock(struct sdhci_host *host, unsigned int clock)
- u16 clk;
- unsigned long timeout;
-
- - if (clock == host->clock)
- - return;
- + host->mmc->actual_clock = 0;
-
- sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
-
- if (clock == 0)
- - goto out;
- + return;
-
- while (host->max_clk / div > clock) {
- /*
- @@ -75,13 +74,14 @@ static void sdhci_cns3xxx_set_clock(struct sdhci_host *host, unsigned int clock)
-
- clk |= SDHCI_CLOCK_CARD_EN;
- sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
- -out:
- - host->clock = clock;
- }
-
- static const struct sdhci_ops sdhci_cns3xxx_ops = {
- .get_max_clock = sdhci_cns3xxx_get_max_clk,
- .set_clock = sdhci_cns3xxx_set_clock,
- + .set_bus_width = sdhci_set_bus_width,
- + .reset = sdhci_reset,
- + .set_uhs_signaling = sdhci_set_uhs_signaling,
- };
-
- static const struct sdhci_pltfm_data sdhci_cns3xxx_pdata = {
- @@ -90,8 +90,7 @@ static const struct sdhci_pltfm_data sdhci_cns3xxx_pdata = {
- SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
- SDHCI_QUIRK_INVERTED_WRITE_PROTECT |
- SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
- - SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
- - SDHCI_QUIRK_NONSTANDARD_CLOCK,
- + SDHCI_QUIRK_BROKEN_TIMEOUT_VAL,
- };
-
- static int sdhci_cns3xxx_probe(struct platform_device *pdev)
- diff --git a/drivers/mmc/host/sdhci-dove.c b/drivers/mmc/host/sdhci-dove.c
- index 736d7a2eb7ec..0d315f4496c8 100644
- --- a/drivers/mmc/host/sdhci-dove.c
- +++ b/drivers/mmc/host/sdhci-dove.c
- @@ -86,6 +86,10 @@ static u32 sdhci_dove_readl(struct sdhci_host *host, int reg)
- static const struct sdhci_ops sdhci_dove_ops = {
- .read_w = sdhci_dove_readw,
- .read_l = sdhci_dove_readl,
- + .set_clock = sdhci_set_clock,
- + .set_bus_width = sdhci_set_bus_width,
- + .reset = sdhci_reset,
- + .set_uhs_signaling = sdhci_set_uhs_signaling,
- };
-
- static const struct sdhci_pltfm_data sdhci_dove_pdata = {
- diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
- index b841bb7cd371..4866d802f9e2 100644
- --- a/drivers/mmc/host/sdhci-esdhc-imx.c
- +++ b/drivers/mmc/host/sdhci-esdhc-imx.c
- @@ -160,7 +160,6 @@ struct pltfm_imx_data {
- MULTIBLK_IN_PROCESS, /* exact multiblock cmd in process */
- WAIT_FOR_INT, /* sent CMD12, waiting for response INT */
- } multiblock_status;
- - u32 uhs_mode;
- u32 is_ddr;
- };
-
- @@ -382,7 +381,6 @@ static u16 esdhc_readw_le(struct sdhci_host *host, int reg)
- if (val & ESDHC_MIX_CTRL_SMPCLK_SEL)
- ret |= SDHCI_CTRL_TUNED_CLK;
-
- - ret |= (imx_data->uhs_mode & SDHCI_CTRL_UHS_MASK);
- ret &= ~SDHCI_CTRL_PRESET_VAL_ENABLE;
-
- return ret;
- @@ -429,7 +427,6 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
- else
- new_val &= ~ESDHC_VENDOR_SPEC_VSELECT;
- writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC);
- - imx_data->uhs_mode = val & SDHCI_CTRL_UHS_MASK;
- if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) {
- new_val = readl(host->ioaddr + ESDHC_MIX_CTRL);
- if (val & SDHCI_CTRL_TUNED_CLK)
- @@ -600,12 +597,14 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
- u32 temp, val;
-
- if (clock == 0) {
- + host->mmc->actual_clock = 0;
- +
- if (esdhc_is_usdhc(imx_data)) {
- val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
- writel(val & ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
- host->ioaddr + ESDHC_VENDOR_SPEC);
- }
- - goto out;
- + return;
- }
-
- if (esdhc_is_usdhc(imx_data) && !imx_data->is_ddr)
- @@ -645,8 +644,6 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
- }
-
- mdelay(1);
- -out:
- - host->clock = clock;
- }
-
- static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host)
- @@ -668,7 +665,7 @@ static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host)
- return -ENOSYS;
- }
-
- -static int esdhc_pltfm_bus_width(struct sdhci_host *host, int width)
- +static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width)
- {
- u32 ctrl;
-
- @@ -686,8 +683,6 @@ static int esdhc_pltfm_bus_width(struct sdhci_host *host, int width)
-
- esdhc_clrset_le(host, ESDHC_CTRL_BUSWIDTH_MASK, ctrl,
- SDHCI_HOST_CONTROL);
- -
- - return 0;
- }
-
- static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val)
- @@ -697,6 +692,7 @@ static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val)
- /* FIXME: delay a bit for card to be ready for next tuning due to errors */
- mdelay(1);
-
- + /* This is balanced by the runtime put in sdhci_tasklet_finish */
- pm_runtime_get_sync(host->mmc->parent);
- reg = readl(host->ioaddr + ESDHC_MIX_CTRL);
- reg |= ESDHC_MIX_CTRL_EXE_TUNE | ESDHC_MIX_CTRL_SMPCLK_SEL |
- @@ -713,13 +709,12 @@ static void esdhc_request_done(struct mmc_request *mrq)
- complete(&mrq->completion);
- }
-
- -static int esdhc_send_tuning_cmd(struct sdhci_host *host, u32 opcode)
- +static int esdhc_send_tuning_cmd(struct sdhci_host *host, u32 opcode,
- + struct scatterlist *sg)
- {
- struct mmc_command cmd = {0};
- struct mmc_request mrq = {NULL};
- struct mmc_data data = {0};
- - struct scatterlist sg;
- - char tuning_pattern[ESDHC_TUNING_BLOCK_PATTERN_LEN];
-
- cmd.opcode = opcode;
- cmd.arg = 0;
- @@ -728,11 +723,9 @@ static int esdhc_send_tuning_cmd(struct sdhci_host *host, u32 opcode)
- data.blksz = ESDHC_TUNING_BLOCK_PATTERN_LEN;
- data.blocks = 1;
- data.flags = MMC_DATA_READ;
- - data.sg = &sg;
- + data.sg = sg;
- data.sg_len = 1;
-
- - sg_init_one(&sg, tuning_pattern, sizeof(tuning_pattern));
- -
- mrq.cmd = &cmd;
- mrq.cmd->mrq = &mrq;
- mrq.data = &data;
- @@ -742,14 +735,12 @@ static int esdhc_send_tuning_cmd(struct sdhci_host *host, u32 opcode)
- mrq.done = esdhc_request_done;
- init_completion(&(mrq.completion));
-
- - disable_irq(host->irq);
- - spin_lock(&host->lock);
- + spin_lock_irq(&host->lock);
- host->mrq = &mrq;
-
- sdhci_send_command(host, mrq.cmd);
-
- - spin_unlock(&host->lock);
- - enable_irq(host->irq);
- + spin_unlock_irq(&host->lock);
-
- wait_for_completion(&mrq.completion);
-
- @@ -772,13 +763,21 @@ static void esdhc_post_tuning(struct sdhci_host *host)
-
- static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode)
- {
- + struct scatterlist sg;
- + char *tuning_pattern;
- int min, max, avg, ret;
-
- + tuning_pattern = kmalloc(ESDHC_TUNING_BLOCK_PATTERN_LEN, GFP_KERNEL);
- + if (!tuning_pattern)
- + return -ENOMEM;
- +
- + sg_init_one(&sg, tuning_pattern, ESDHC_TUNING_BLOCK_PATTERN_LEN);
- +
- /* find the mininum delay first which can pass tuning */
- min = ESDHC_TUNE_CTRL_MIN;
- while (min < ESDHC_TUNE_CTRL_MAX) {
- esdhc_prepare_tuning(host, min);
- - if (!esdhc_send_tuning_cmd(host, opcode))
- + if (!esdhc_send_tuning_cmd(host, opcode, &sg))
- break;
- min += ESDHC_TUNE_CTRL_STEP;
- }
- @@ -787,7 +786,7 @@ static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode)
- max = min + ESDHC_TUNE_CTRL_STEP;
- while (max < ESDHC_TUNE_CTRL_MAX) {
- esdhc_prepare_tuning(host, max);
- - if (esdhc_send_tuning_cmd(host, opcode)) {
- + if (esdhc_send_tuning_cmd(host, opcode, &sg)) {
- max -= ESDHC_TUNE_CTRL_STEP;
- break;
- }
- @@ -797,9 +796,11 @@ static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode)
- /* use average delay to get the best timing */
- avg = (min + max) / 2;
- esdhc_prepare_tuning(host, avg);
- - ret = esdhc_send_tuning_cmd(host, opcode);
- + ret = esdhc_send_tuning_cmd(host, opcode, &sg);
- esdhc_post_tuning(host);
-
- + kfree(tuning_pattern);
- +
- dev_dbg(mmc_dev(host->mmc), "tunning %s at 0x%x ret %d\n",
- ret ? "failed" : "passed", avg, ret);
-
- @@ -837,28 +838,20 @@ static int esdhc_change_pinstate(struct sdhci_host *host,
- return pinctrl_select_state(imx_data->pinctrl, pinctrl);
- }
-
- -static int esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
- +static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
- {
- struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
- struct pltfm_imx_data *imx_data = pltfm_host->priv;
- struct esdhc_platform_data *boarddata = &imx_data->boarddata;
-
- - switch (uhs) {
- + switch (timing) {
- case MMC_TIMING_UHS_SDR12:
- - imx_data->uhs_mode = SDHCI_CTRL_UHS_SDR12;
- - break;
- case MMC_TIMING_UHS_SDR25:
- - imx_data->uhs_mode = SDHCI_CTRL_UHS_SDR25;
- - break;
- case MMC_TIMING_UHS_SDR50:
- - imx_data->uhs_mode = SDHCI_CTRL_UHS_SDR50;
- - break;
- case MMC_TIMING_UHS_SDR104:
- case MMC_TIMING_MMC_HS200:
- - imx_data->uhs_mode = SDHCI_CTRL_UHS_SDR104;
- break;
- case MMC_TIMING_UHS_DDR50:
- - imx_data->uhs_mode = SDHCI_CTRL_UHS_DDR50;
- writel(readl(host->ioaddr + ESDHC_MIX_CTRL) |
- ESDHC_MIX_CTRL_DDREN,
- host->ioaddr + ESDHC_MIX_CTRL);
- @@ -875,7 +868,15 @@ static int esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
- break;
- }
-
- - return esdhc_change_pinstate(host, uhs);
- + esdhc_change_pinstate(host, timing);
- +}
- +
- +static void esdhc_reset(struct sdhci_host *host, u8 mask)
- +{
- + sdhci_reset(host, mask);
- +
- + sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
- + sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
- }
-
- static struct sdhci_ops sdhci_esdhc_ops = {
- @@ -888,8 +889,9 @@ static struct sdhci_ops sdhci_esdhc_ops = {
- .get_max_clock = esdhc_pltfm_get_max_clock,
- .get_min_clock = esdhc_pltfm_get_min_clock,
- .get_ro = esdhc_pltfm_get_ro,
- - .platform_bus_width = esdhc_pltfm_bus_width,
- + .set_bus_width = esdhc_pltfm_set_bus_width,
- .set_uhs_signaling = esdhc_set_uhs_signaling,
- + .reset = esdhc_reset,
- };
-
- static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
- @@ -1170,8 +1172,10 @@ static int sdhci_esdhc_runtime_suspend(struct device *dev)
-
- ret = sdhci_runtime_suspend_host(host);
-
- - clk_disable_unprepare(imx_data->clk_per);
- - clk_disable_unprepare(imx_data->clk_ipg);
- + if (!sdhci_sdio_irq_enabled(host)) {
- + clk_disable_unprepare(imx_data->clk_per);
- + clk_disable_unprepare(imx_data->clk_ipg);
- + }
- clk_disable_unprepare(imx_data->clk_ahb);
-
- return ret;
- @@ -1183,8 +1187,10 @@ static int sdhci_esdhc_runtime_resume(struct device *dev)
- struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
- struct pltfm_imx_data *imx_data = pltfm_host->priv;
-
- - clk_prepare_enable(imx_data->clk_per);
- - clk_prepare_enable(imx_data->clk_ipg);
- + if (!sdhci_sdio_irq_enabled(host)) {
- + clk_prepare_enable(imx_data->clk_per);
- + clk_prepare_enable(imx_data->clk_ipg);
- + }
- clk_prepare_enable(imx_data->clk_ahb);
-
- return sdhci_runtime_resume_host(host);
- diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h
- index a7d9f95a7b03..3497cfaf683c 100644
- --- a/drivers/mmc/host/sdhci-esdhc.h
- +++ b/drivers/mmc/host/sdhci-esdhc.h
- @@ -20,10 +20,8 @@
-
- #define ESDHC_DEFAULT_QUIRKS (SDHCI_QUIRK_FORCE_BLK_SZ_2048 | \
- SDHCI_QUIRK_NO_BUSY_IRQ | \
- - SDHCI_QUIRK_NONSTANDARD_CLOCK | \
- SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | \
- - SDHCI_QUIRK_PIO_NEEDS_DELAY | \
- - SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET)
- + SDHCI_QUIRK_PIO_NEEDS_DELAY)
-
- #define ESDHC_SYSTEM_CONTROL 0x2c
- #define ESDHC_CLOCK_MASK 0x0000fff0
- diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c
- index f7c7cf62437d..5bd1092310f2 100644
- --- a/drivers/mmc/host/sdhci-of-arasan.c
- +++ b/drivers/mmc/host/sdhci-of-arasan.c
- @@ -52,8 +52,12 @@ static unsigned int sdhci_arasan_get_timeout_clock(struct sdhci_host *host)
- }
-
- static struct sdhci_ops sdhci_arasan_ops = {
- + .set_clock = sdhci_set_clock,
- .get_max_clock = sdhci_pltfm_clk_get_max_clock,
- .get_timeout_clock = sdhci_arasan_get_timeout_clock,
- + .set_bus_width = sdhci_set_bus_width,
- + .reset = sdhci_reset,
- + .set_uhs_signaling = sdhci_set_uhs_signaling,
- };
-
- static struct sdhci_pltfm_data sdhci_arasan_pdata = {
- diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
- index 0b249970b119..605815e52f5f 100644
- --- a/drivers/mmc/host/sdhci-of-esdhc.c
- +++ b/drivers/mmc/host/sdhci-of-esdhc.c
- @@ -199,13 +199,14 @@ static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host)
-
- static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
- {
- -
- int pre_div = 2;
- int div = 1;
- u32 temp;
-
- + host->mmc->actual_clock = 0;
- +
- if (clock == 0)
- - goto out;
- + return;
-
- /* Workaround to reduce the clock frequency for p1010 esdhc */
- if (of_find_compatible_node(NULL, NULL, "fsl,p1010-esdhc")) {
- @@ -238,24 +239,8 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
- | (pre_div << ESDHC_PREDIV_SHIFT));
- sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
- mdelay(1);
- -out:
- - host->clock = clock;
- -}
- -
- -#ifdef CONFIG_PM
- -static u32 esdhc_proctl;
- -static void esdhc_of_suspend(struct sdhci_host *host)
- -{
- - esdhc_proctl = sdhci_be32bs_readl(host, SDHCI_HOST_CONTROL);
- }
-
- -static void esdhc_of_resume(struct sdhci_host *host)
- -{
- - esdhc_of_enable_dma(host);
- - sdhci_be32bs_writel(host, esdhc_proctl, SDHCI_HOST_CONTROL);
- -}
- -#endif
- -
- static void esdhc_of_platform_init(struct sdhci_host *host)
- {
- u32 vvn;
- @@ -269,7 +254,7 @@ static void esdhc_of_platform_init(struct sdhci_host *host)
- host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ;
- }
-
- -static int esdhc_pltfm_bus_width(struct sdhci_host *host, int width)
- +static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width)
- {
- u32 ctrl;
-
- @@ -289,8 +274,6 @@ static int esdhc_pltfm_bus_width(struct sdhci_host *host, int width)
-
- clrsetbits_be32(host->ioaddr + SDHCI_HOST_CONTROL,
- ESDHC_CTRL_BUSWIDTH_MASK, ctrl);
- -
- - return 0;
- }
-
- static const struct sdhci_ops sdhci_esdhc_ops = {
- @@ -305,13 +288,46 @@ static const struct sdhci_ops sdhci_esdhc_ops = {
- .get_max_clock = esdhc_of_get_max_clock,
- .get_min_clock = esdhc_of_get_min_clock,
- .platform_init = esdhc_of_platform_init,
- -#ifdef CONFIG_PM
- - .platform_suspend = esdhc_of_suspend,
- - .platform_resume = esdhc_of_resume,
- -#endif
- .adma_workaround = esdhci_of_adma_workaround,
- - .platform_bus_width = esdhc_pltfm_bus_width,
- + .set_bus_width = esdhc_pltfm_set_bus_width,
- + .reset = sdhci_reset,
- + .set_uhs_signaling = sdhci_set_uhs_signaling,
- +};
- +
- +#ifdef CONFIG_PM
- +
- +static u32 esdhc_proctl;
- +static int esdhc_of_suspend(struct device *dev)
- +{
- + struct sdhci_host *host = dev_get_drvdata(dev);
- +
- + esdhc_proctl = sdhci_be32bs_readl(host, SDHCI_HOST_CONTROL);
- +
- + return sdhci_suspend_host(host);
- +}
- +
- +static void esdhc_of_resume(device *dev)
- +{
- + struct sdhci_host *host = dev_get_drvdata(dev);
- + int ret = sdhci_resume_host(host);
- +
- + if (ret == 0) {
- + /* Isn't this already done by sdhci_resume_host() ? --rmk */
- + esdhc_of_enable_dma(host);
- + sdhci_be32bs_writel(host, esdhc_proctl, SDHCI_HOST_CONTROL);
- + }
- +
- + return ret;
- +}
- +
- +static const struct dev_pm_ops esdhc_pmops = {
- + .suspend = esdhci_of_suspend,
- + .resume = esdhci_of_resume,
- };
- +#define ESDHC_PMOPS (&esdhc_pmops)
- +#else
- +#define ESDHC_PMOPS NULL
- +#endif
-
- static const struct sdhci_pltfm_data sdhci_esdhc_pdata = {
- /*
- @@ -374,7 +390,7 @@ static struct platform_driver sdhci_esdhc_driver = {
- .name = "sdhci-esdhc",
- .owner = THIS_MODULE,
- .of_match_table = sdhci_esdhc_of_match,
- - .pm = SDHCI_PLTFM_PMOPS,
- + .pm = ESDHC_PMOPS,
- },
- .probe = sdhci_esdhc_probe,
- .remove = sdhci_esdhc_remove,
- diff --git a/drivers/mmc/host/sdhci-of-hlwd.c b/drivers/mmc/host/sdhci-of-hlwd.c
- index 57c514a81ca5..b341661369a2 100644
- --- a/drivers/mmc/host/sdhci-of-hlwd.c
- +++ b/drivers/mmc/host/sdhci-of-hlwd.c
- @@ -58,6 +58,10 @@ static const struct sdhci_ops sdhci_hlwd_ops = {
- .write_l = sdhci_hlwd_writel,
- .write_w = sdhci_hlwd_writew,
- .write_b = sdhci_hlwd_writeb,
- + .set_clock = sdhci_set_clock,
- + .set_bus_width = sdhci_set_bus_width,
- + .reset = sdhci_reset,
- + .set_uhs_signaling = sdhci_set_uhs_signaling,
- };
-
- static const struct sdhci_pltfm_data sdhci_hlwd_pdata = {
- diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
- index fdc612120362..52c42fcc284c 100644
- --- a/drivers/mmc/host/sdhci-pci.c
- +++ b/drivers/mmc/host/sdhci-pci.c
- @@ -1031,7 +1031,7 @@ static int sdhci_pci_enable_dma(struct sdhci_host *host)
- return 0;
- }
-
- -static int sdhci_pci_bus_width(struct sdhci_host *host, int width)
- +static void sdhci_pci_set_bus_width(struct sdhci_host *host, int width)
- {
- u8 ctrl;
-
- @@ -1052,8 +1052,6 @@ static int sdhci_pci_bus_width(struct sdhci_host *host, int width)
- }
-
- sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
- -
- - return 0;
- }
-
- static void sdhci_pci_gpio_hw_reset(struct sdhci_host *host)
- @@ -1080,8 +1078,11 @@ static void sdhci_pci_hw_reset(struct sdhci_host *host)
- }
-
- static const struct sdhci_ops sdhci_pci_ops = {
- + .set_clock = sdhci_set_clock,
- .enable_dma = sdhci_pci_enable_dma,
- - .platform_bus_width = sdhci_pci_bus_width,
- + .set_bus_width = sdhci_pci_set_bus_width,
- + .reset = sdhci_reset,
- + .set_uhs_signaling = sdhci_set_uhs_signaling,
- .hw_reset = sdhci_pci_hw_reset,
- };
-
- diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c
- index bef250e95418..7e834fb78f42 100644
- --- a/drivers/mmc/host/sdhci-pltfm.c
- +++ b/drivers/mmc/host/sdhci-pltfm.c
- @@ -45,6 +45,10 @@ unsigned int sdhci_pltfm_clk_get_max_clock(struct sdhci_host *host)
- EXPORT_SYMBOL_GPL(sdhci_pltfm_clk_get_max_clock);
-
- static const struct sdhci_ops sdhci_pltfm_ops = {
- + .set_clock = sdhci_set_clock,
- + .set_bus_width = sdhci_set_bus_width,
- + .reset = sdhci_reset,
- + .set_uhs_signaling = sdhci_set_uhs_signaling,
- };
-
- #ifdef CONFIG_OF
- diff --git a/drivers/mmc/host/sdhci-pxav2.c b/drivers/mmc/host/sdhci-pxav2.c
- index d51e061ec576..3c0f3c0a1cc8 100644
- --- a/drivers/mmc/host/sdhci-pxav2.c
- +++ b/drivers/mmc/host/sdhci-pxav2.c
- @@ -51,11 +51,13 @@
- #define MMC_CARD 0x1000
- #define MMC_WIDTH 0x0100
-
- -static void pxav2_set_private_registers(struct sdhci_host *host, u8 mask)
- +static void pxav2_reset(struct sdhci_host *host, u8 mask)
- {
- struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc));
- struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data;
-
- + sdhci_reset(host, mask);
- +
- if (mask == SDHCI_RESET_ALL) {
- u16 tmp = 0;
-
- @@ -88,7 +90,7 @@ static void pxav2_set_private_registers(struct sdhci_host *host, u8 mask)
- }
- }
-
- -static int pxav2_mmc_set_width(struct sdhci_host *host, int width)
- +static void pxav2_mmc_set_bus_width(struct sdhci_host *host, int width)
- {
- u8 ctrl;
- u16 tmp;
- @@ -107,14 +109,14 @@ static int pxav2_mmc_set_width(struct sdhci_host *host, int width)
- }
- writew(tmp, host->ioaddr + SD_CE_ATA_2);
- writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
- -
- - return 0;
- }
-
- static const struct sdhci_ops pxav2_sdhci_ops = {
- + .set_clock = sdhci_set_clock,
- .get_max_clock = sdhci_pltfm_clk_get_max_clock,
- - .platform_reset_exit = pxav2_set_private_registers,
- - .platform_bus_width = pxav2_mmc_set_width,
- + .set_bus_width = pxav2_mmc_set_bus_width,
- + .reset = pxav2_reset,
- + .set_uhs_signaling = sdhci_set_uhs_signaling,
- };
-
- #ifdef CONFIG_OF
- diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c
- index 2fd73b38c303..f4f128947561 100644
- --- a/drivers/mmc/host/sdhci-pxav3.c
- +++ b/drivers/mmc/host/sdhci-pxav3.c
- @@ -112,11 +112,13 @@ static int mv_conf_mbus_windows(struct platform_device *pdev,
- return 0;
- }
-
- -static void pxav3_set_private_registers(struct sdhci_host *host, u8 mask)
- +static void pxav3_reset(struct sdhci_host *host, u8 mask)
- {
- struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc));
- struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data;
-
- + sdhci_reset(host, mask);
- +
- if (mask == SDHCI_RESET_ALL) {
- /*
- * tune timing of read data/command when crc error happen
- @@ -184,7 +186,7 @@ static void pxav3_gen_init_74_clocks(struct sdhci_host *host, u8 power_mode)
- pxa->power_mode = power_mode;
- }
-
- -static int pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
- +static void pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
- {
- u16 ctrl_2;
-
- @@ -218,15 +220,16 @@ static int pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
- dev_dbg(mmc_dev(host->mmc),
- "%s uhs = %d, ctrl_2 = %04X\n",
- __func__, uhs, ctrl_2);
- -
- - return 0;
- }
-
- static const struct sdhci_ops pxav3_sdhci_ops = {
- - .platform_reset_exit = pxav3_set_private_registers,
- + .set_clock = sdhci_set_clock,
- .set_uhs_signaling = pxav3_set_uhs_signaling,
- .platform_send_init_74_clocks = pxav3_gen_init_74_clocks,
- .get_max_clock = sdhci_pltfm_clk_get_max_clock,
- + .set_bus_width = sdhci_set_bus_width,
- + .reset = pxav3_reset,
- + .set_uhs_signaling = sdhci_set_uhs_signaling,
- };
-
- static struct sdhci_pltfm_data sdhci_pxav3_pdata = {
- diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c
- index d61eb5a70833..76d7c12d8ef9 100644
- --- a/drivers/mmc/host/sdhci-s3c.c
- +++ b/drivers/mmc/host/sdhci-s3c.c
- @@ -58,6 +58,8 @@ struct sdhci_s3c {
- struct clk *clk_io;
- struct clk *clk_bus[MAX_BUS_CLK];
- unsigned long clk_rates[MAX_BUS_CLK];
- +
- + bool no_divider;
- };
-
- /**
- @@ -70,6 +72,7 @@ struct sdhci_s3c {
- */
- struct sdhci_s3c_drv_data {
- unsigned int sdhci_quirks;
- + bool no_divider;
- };
-
- static inline struct sdhci_s3c *to_s3c(struct sdhci_host *host)
- @@ -119,7 +122,7 @@ static unsigned int sdhci_s3c_consider_clock(struct sdhci_s3c *ourhost,
- * If controller uses a non-standard clock division, find the best clock
- * speed possible with selected clock source and skip the division.
- */
- - if (ourhost->host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK) {
- + if (ourhost->no_divider) {
- rate = clk_round_rate(clksrc, wanted);
- return wanted - rate;
- }
- @@ -161,9 +164,13 @@ static void sdhci_s3c_set_clock(struct sdhci_host *host, unsigned int clock)
- int src;
- u32 ctrl;
-
- + host->mmc->actual_clock = 0;
- +
- /* don't bother if the clock is going off. */
- - if (clock == 0)
- + if (clock == 0) {
- + sdhci_set_clock(host, clock);
- return;
- + }
-
- for (src = 0; src < MAX_BUS_CLK; src++) {
- delta = sdhci_s3c_consider_clock(ourhost, src, clock);
- @@ -215,6 +222,8 @@ static void sdhci_s3c_set_clock(struct sdhci_host *host, unsigned int clock)
- if (clock < 25 * 1000000)
- ctrl |= (S3C_SDHCI_CTRL3_FCSEL3 | S3C_SDHCI_CTRL3_FCSEL2);
- writel(ctrl, host->ioaddr + S3C_SDHCI_CONTROL3);
- +
- + sdhci_set_clock(host, clock);
- }
-
- /**
- @@ -295,10 +304,11 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock)
- unsigned long timeout;
- u16 clk = 0;
-
- + host->mmc->actual_clock = 0;
- +
- /* If the clock is going off, set to 0 at clock control register */
- if (clock == 0) {
- sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
- - host->clock = clock;
- return;
- }
-
- @@ -306,8 +316,6 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock)
-
- clk_set_rate(ourhost->clk_bus[ourhost->cur_clk], clock);
-
- - host->clock = clock;
- -
- clk = SDHCI_CLOCK_INT_EN;
- sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
-
- @@ -329,14 +337,14 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock)
- }
-
- /**
- - * sdhci_s3c_platform_bus_width - support 8bit buswidth
- + * sdhci_s3c_set_bus_width - support 8bit buswidth
- * @host: The SDHCI host being queried
- * @width: MMC_BUS_WIDTH_ macro for the bus width being requested
- *
- * We have 8-bit width support but is not a v3 controller.
- * So we add platform_bus_width() and support 8bit width.
- */
- -static int sdhci_s3c_platform_bus_width(struct sdhci_host *host, int width)
- +static void sdhci_s3c_set_bus_width(struct sdhci_host *host, int width)
- {
- u8 ctrl;
-
- @@ -358,15 +366,15 @@ static int sdhci_s3c_platform_bus_width(struct sdhci_host *host, int width)
- }
-
- sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
- -
- - return 0;
- }
-
- static struct sdhci_ops sdhci_s3c_ops = {
- .get_max_clock = sdhci_s3c_get_max_clk,
- .set_clock = sdhci_s3c_set_clock,
- .get_min_clock = sdhci_s3c_get_min_clock,
- - .platform_bus_width = sdhci_s3c_platform_bus_width,
- + .set_bus_width = sdhci_s3c_set_bus_width,
- + .reset = sdhci_reset,
- + .set_uhs_signaling = sdhci_set_uhs_signaling,
- };
-
- static void sdhci_s3c_notify_change(struct platform_device *dev, int state)
- @@ -606,8 +614,10 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
- /* Setup quirks for the controller */
- host->quirks |= SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC;
- host->quirks |= SDHCI_QUIRK_NO_HISPD_BIT;
- - if (drv_data)
- + if (drv_data) {
- host->quirks |= drv_data->sdhci_quirks;
- + sc->no_divider = drv_data->no_divider;
- + }
-
- #ifndef CONFIG_MMC_SDHCI_S3C_DMA
-
- @@ -656,7 +666,7 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
- * If controller does not have internal clock divider,
- * we can use overriding functions instead of default.
- */
- - if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK) {
- + if (sc->no_divider) {
- sdhci_s3c_ops.set_clock = sdhci_cmu_set_clock;
- sdhci_s3c_ops.get_min_clock = sdhci_cmu_get_min_clock;
- sdhci_s3c_ops.get_max_clock = sdhci_cmu_get_max_clock;
- @@ -797,7 +807,7 @@ static const struct dev_pm_ops sdhci_s3c_pmops = {
-
- #if defined(CONFIG_CPU_EXYNOS4210) || defined(CONFIG_SOC_EXYNOS4212)
- static struct sdhci_s3c_drv_data exynos4_sdhci_drv_data = {
- - .sdhci_quirks = SDHCI_QUIRK_NONSTANDARD_CLOCK,
- + .no_divider = true,
- };
- #define EXYNOS4_SDHCI_DRV_DATA ((kernel_ulong_t)&exynos4_sdhci_drv_data)
- #else
- diff --git a/drivers/mmc/host/sdhci-sirf.c b/drivers/mmc/host/sdhci-sirf.c
- index 696122c1b468..17004531d089 100644
- --- a/drivers/mmc/host/sdhci-sirf.c
- +++ b/drivers/mmc/host/sdhci-sirf.c
- @@ -28,7 +28,11 @@ static unsigned int sdhci_sirf_get_max_clk(struct sdhci_host *host)
- }
-
- static struct sdhci_ops sdhci_sirf_ops = {
- + .set_clock = sdhci_set_clock,
- .get_max_clock = sdhci_sirf_get_max_clk,
- + .set_bus_width = sdhci_set_bus_width,
- + .reset = sdhci_reset,
- + .set_uhs_signaling = sdhci_set_uhs_signaling,
- };
-
- static struct sdhci_pltfm_data sdhci_sirf_pdata = {
- diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c
- index 0316dec3f006..9d535c7336ef 100644
- --- a/drivers/mmc/host/sdhci-spear.c
- +++ b/drivers/mmc/host/sdhci-spear.c
- @@ -38,7 +38,10 @@ struct spear_sdhci {
-
- /* sdhci ops */
- static const struct sdhci_ops sdhci_pltfm_ops = {
- - /* Nothing to do for now. */
- + .set_clock = sdhci_set_clock,
- + .set_bus_width = sdhci_set_bus_width,
- + .reset = sdhci_reset,
- + .set_uhs_signaling = sdhci_set_uhs_signaling,
- };
-
- #ifdef CONFIG_OF
- diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
- index a835898a68dd..985247649f46 100644
- --- a/drivers/mmc/host/sdhci-tegra.c
- +++ b/drivers/mmc/host/sdhci-tegra.c
- @@ -48,19 +48,6 @@ struct sdhci_tegra {
- int power_gpio;
- };
-
- -static u32 tegra_sdhci_readl(struct sdhci_host *host, int reg)
- -{
- - u32 val;
- -
- - if (unlikely(reg == SDHCI_PRESENT_STATE)) {
- - /* Use wp_gpio here instead? */
- - val = readl(host->ioaddr + reg);
- - return val | SDHCI_WRITE_PROTECT;
- - }
- -
- - return readl(host->ioaddr + reg);
- -}
- -
- static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg)
- {
- struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
- @@ -108,12 +95,14 @@ static unsigned int tegra_sdhci_get_ro(struct sdhci_host *host)
- return mmc_gpio_get_ro(host->mmc);
- }
-
- -static void tegra_sdhci_reset_exit(struct sdhci_host *host, u8 mask)
- +static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask)
- {
- struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
- struct sdhci_tegra *tegra_host = pltfm_host->priv;
- const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data;
-
- + sdhci_reset(host, mask);
- +
- if (!(mask & SDHCI_RESET_ALL))
- return;
-
- @@ -127,7 +116,7 @@ static void tegra_sdhci_reset_exit(struct sdhci_host *host, u8 mask)
- }
- }
-
- -static int tegra_sdhci_buswidth(struct sdhci_host *host, int bus_width)
- +static void tegra_sdhci_set_bus_width(struct sdhci_host *host, int bus_width)
- {
- u32 ctrl;
-
- @@ -144,16 +133,16 @@ static int tegra_sdhci_buswidth(struct sdhci_host *host, int bus_width)
- ctrl &= ~SDHCI_CTRL_4BITBUS;
- }
- sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
- - return 0;
- }
-
- static const struct sdhci_ops tegra_sdhci_ops = {
- .get_ro = tegra_sdhci_get_ro,
- - .read_l = tegra_sdhci_readl,
- .read_w = tegra_sdhci_readw,
- .write_l = tegra_sdhci_writel,
- - .platform_bus_width = tegra_sdhci_buswidth,
- - .platform_reset_exit = tegra_sdhci_reset_exit,
- + .set_clock = sdhci_set_clock,
- + .set_bus_width = tegra_sdhci_set_bus_width,
- + .reset = tegra_sdhci_reset,
- + .set_uhs_signaling = sdhci_set_uhs_signaling,
- };
-
- static const struct sdhci_pltfm_data sdhci_tegra20_pdata = {
- diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
- index 9a79fc4b60ca..48f4aef034fd 100644
- --- a/drivers/mmc/host/sdhci.c
- +++ b/drivers/mmc/host/sdhci.c
- @@ -44,6 +44,8 @@
-
- #define MAX_TUNING_LOOP 40
-
- +#define ADMA_SIZE ((128 * 2 + 1) * 4)
- +
- static unsigned int debug_quirks = 0;
- static unsigned int debug_quirks2;
-
- @@ -131,43 +133,26 @@ static void sdhci_dumpregs(struct sdhci_host *host)
- * *
- \*****************************************************************************/
-
- -static void sdhci_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set)
- -{
- - u32 ier;
- -
- - ier = sdhci_readl(host, SDHCI_INT_ENABLE);
- - ier &= ~clear;
- - ier |= set;
- - sdhci_writel(host, ier, SDHCI_INT_ENABLE);
- - sdhci_writel(host, ier, SDHCI_SIGNAL_ENABLE);
- -}
- -
- -static void sdhci_unmask_irqs(struct sdhci_host *host, u32 irqs)
- -{
- - sdhci_clear_set_irqs(host, 0, irqs);
- -}
- -
- -static void sdhci_mask_irqs(struct sdhci_host *host, u32 irqs)
- -{
- - sdhci_clear_set_irqs(host, irqs, 0);
- -}
- -
- static void sdhci_set_card_detection(struct sdhci_host *host, bool enable)
- {
- - u32 present, irqs;
- + u32 present;
-
- if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) ||
- (host->mmc->caps & MMC_CAP_NONREMOVABLE))
- return;
-
- - present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
- - SDHCI_CARD_PRESENT;
- - irqs = present ? SDHCI_INT_CARD_REMOVE : SDHCI_INT_CARD_INSERT;
- + if (enable) {
- + present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
- + SDHCI_CARD_PRESENT;
-
- - if (enable)
- - sdhci_unmask_irqs(host, irqs);
- - else
- - sdhci_mask_irqs(host, irqs);
- + host->ier |= present ? SDHCI_INT_CARD_REMOVE :
- + SDHCI_INT_CARD_INSERT;
- + } else {
- + host->ier &= ~(SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT);
- + }
- +
- + sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
- + sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
- }
-
- static void sdhci_enable_card_detection(struct sdhci_host *host)
- @@ -180,22 +165,9 @@ static void sdhci_disable_card_detection(struct sdhci_host *host)
- sdhci_set_card_detection(host, false);
- }
-
- -static void sdhci_reset(struct sdhci_host *host, u8 mask)
- +void sdhci_reset(struct sdhci_host *host, u8 mask)
- {
- unsigned long timeout;
- - u32 uninitialized_var(ier);
- -
- - if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
- - if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) &
- - SDHCI_CARD_PRESENT))
- - return;
- - }
- -
- - if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET)
- - ier = sdhci_readl(host, SDHCI_INT_ENABLE);
- -
- - if (host->ops->platform_reset_enter)
- - host->ops->platform_reset_enter(host, mask);
-
- sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET);
-
- @@ -220,16 +192,27 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
- timeout--;
- mdelay(1);
- }
- +}
- +EXPORT_SYMBOL_GPL(sdhci_reset);
- +
- +static void sdhci_do_reset(struct sdhci_host *host, u8 mask)
- +{
- + if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
- + if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) &
- + SDHCI_CARD_PRESENT))
- + return;
- + }
-
- - if (host->ops->platform_reset_exit)
- - host->ops->platform_reset_exit(host, mask);
- + host->ops->reset(host, mask);
-
- - if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET)
- - sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK, ier);
- + if (mask & SDHCI_RESET_ALL) {
- + if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
- + if (host->ops->enable_dma)
- + host->ops->enable_dma(host);
- + }
-
- - if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
- - if ((host->ops->enable_dma) && (mask & SDHCI_RESET_ALL))
- - host->ops->enable_dma(host);
- + /* Resetting the controller clears many */
- + host->preset_enabled = false;
- }
- }
-
- @@ -238,15 +221,18 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios);
- static void sdhci_init(struct sdhci_host *host, int soft)
- {
- if (soft)
- - sdhci_reset(host, SDHCI_RESET_CMD|SDHCI_RESET_DATA);
- + sdhci_do_reset(host, SDHCI_RESET_CMD|SDHCI_RESET_DATA);
- else
- - sdhci_reset(host, SDHCI_RESET_ALL);
- + sdhci_do_reset(host, SDHCI_RESET_ALL);
- +
- + host->ier = SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT |
- + SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT |
- + SDHCI_INT_INDEX | SDHCI_INT_END_BIT | SDHCI_INT_CRC |
- + SDHCI_INT_TIMEOUT | SDHCI_INT_DATA_END |
- + SDHCI_INT_RESPONSE;
-
- - sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK,
- - SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT |
- - SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX |
- - SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT |
- - SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE);
- + sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
- + sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
-
- if (soft) {
- /* force clock reconfiguration */
- @@ -502,11 +488,6 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
- else
- direction = DMA_TO_DEVICE;
-
- - /*
- - * The ADMA descriptor table is mapped further down as we
- - * need to fill it with data first.
- - */
- -
- host->align_addr = dma_map_single(mmc_dev(host->mmc),
- host->align_buffer, 128 * 4, direction);
- if (dma_mapping_error(mmc_dev(host->mmc), host->align_addr))
- @@ -567,7 +548,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
- * If this triggers then we have a calculation bug
- * somewhere. :/
- */
- - WARN_ON((desc - host->adma_desc) > (128 * 2 + 1) * 4);
- + WARN_ON((desc - host->adma_desc) > ADMA_SIZE);
- }
-
- if (host->quirks & SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC) {
- @@ -595,17 +576,8 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
- host->align_addr, 128 * 4, direction);
- }
-
- - host->adma_addr = dma_map_single(mmc_dev(host->mmc),
- - host->adma_desc, (128 * 2 + 1) * 4, DMA_TO_DEVICE);
- - if (dma_mapping_error(mmc_dev(host->mmc), host->adma_addr))
- - goto unmap_entries;
- - BUG_ON(host->adma_addr & 0x3);
- -
- return 0;
-
- -unmap_entries:
- - dma_unmap_sg(mmc_dev(host->mmc), data->sg,
- - data->sg_len, direction);
- unmap_align:
- dma_unmap_single(mmc_dev(host->mmc), host->align_addr,
- 128 * 4, direction);
- @@ -623,19 +595,25 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
- u8 *align;
- char *buffer;
- unsigned long flags;
- + bool has_unaligned;
-
- if (data->flags & MMC_DATA_READ)
- direction = DMA_FROM_DEVICE;
- else
- direction = DMA_TO_DEVICE;
-
- - dma_unmap_single(mmc_dev(host->mmc), host->adma_addr,
- - (128 * 2 + 1) * 4, DMA_TO_DEVICE);
- -
- dma_unmap_single(mmc_dev(host->mmc), host->align_addr,
- 128 * 4, direction);
-
- - if (data->flags & MMC_DATA_READ) {
- + /* Do a quick scan of the SG list for any unaligned mappings */
- + has_unaligned = false;
- + for_each_sg(data->sg, sg, host->sg_count, i)
- + if (sg_dma_address(sg) & 3) {
- + has_unaligned = true;
- + break;
- + }
- +
- + if (has_unaligned && data->flags & MMC_DATA_READ) {
- dma_sync_sg_for_cpu(mmc_dev(host->mmc), data->sg,
- data->sg_len, direction);
-
- @@ -721,9 +699,12 @@ static void sdhci_set_transfer_irqs(struct sdhci_host *host)
- u32 dma_irqs = SDHCI_INT_DMA_END | SDHCI_INT_ADMA_ERROR;
-
- if (host->flags & SDHCI_REQ_USE_DMA)
- - sdhci_clear_set_irqs(host, pio_irqs, dma_irqs);
- + host->ier = (host->ier & ~pio_irqs) | dma_irqs;
- else
- - sdhci_clear_set_irqs(host, dma_irqs, pio_irqs);
- + host->ier = (host->ier & ~dma_irqs) | pio_irqs;
- +
- + sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
- + sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
- }
-
- static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
- @@ -976,8 +957,8 @@ static void sdhci_finish_data(struct sdhci_host *host)
- * upon error conditions.
- */
- if (data->error) {
- - sdhci_reset(host, SDHCI_RESET_CMD);
- - sdhci_reset(host, SDHCI_RESET_DATA);
- + sdhci_do_reset(host, SDHCI_RESET_CMD);
- + sdhci_do_reset(host, SDHCI_RESET_DATA);
- }
-
- sdhci_send_command(host, data->stop);
- @@ -1107,24 +1088,23 @@ static void sdhci_finish_command(struct sdhci_host *host)
-
- static u16 sdhci_get_preset_value(struct sdhci_host *host)
- {
- - u16 ctrl, preset = 0;
- + u16 preset = 0;
-
- - ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
- -
- - switch (ctrl & SDHCI_CTRL_UHS_MASK) {
- - case SDHCI_CTRL_UHS_SDR12:
- + switch (host->timing) {
- + case MMC_TIMING_UHS_SDR12:
- preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR12);
- break;
- - case SDHCI_CTRL_UHS_SDR25:
- + case MMC_TIMING_UHS_SDR25:
- preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR25);
- break;
- - case SDHCI_CTRL_UHS_SDR50:
- + case MMC_TIMING_UHS_SDR50:
- preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR50);
- break;
- - case SDHCI_CTRL_UHS_SDR104:
- + case MMC_TIMING_UHS_SDR104:
- + case MMC_TIMING_MMC_HS200:
- preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR104);
- break;
- - case SDHCI_CTRL_UHS_DDR50:
- + case MMC_TIMING_UHS_DDR50:
- preset = sdhci_readw(host, SDHCI_PRESET_FOR_DDR50);
- break;
- default:
- @@ -1136,32 +1116,22 @@ static u16 sdhci_get_preset_value(struct sdhci_host *host)
- return preset;
- }
-
- -static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
- +void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
- {
- int div = 0; /* Initialized for compiler warning */
- int real_div = div, clk_mul = 1;
- u16 clk = 0;
- unsigned long timeout;
-
- - if (clock && clock == host->clock)
- - return;
- -
- host->mmc->actual_clock = 0;
-
- - if (host->ops->set_clock) {
- - host->ops->set_clock(host, clock);
- - if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK)
- - return;
- - }
- -
- sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
-
- if (clock == 0)
- - goto out;
- + return;
-
- if (host->version >= SDHCI_SPEC_300) {
- - if (sdhci_readw(host, SDHCI_HOST_CONTROL2) &
- - SDHCI_CTRL_PRESET_VAL_ENABLE) {
- + if (host->preset_enabled) {
- u16 pre_val;
-
- clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
- @@ -1247,26 +1217,16 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
-
- clk |= SDHCI_CLOCK_CARD_EN;
- sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
- -
- -out:
- - host->clock = clock;
- -}
- -
- -static inline void sdhci_update_clock(struct sdhci_host *host)
- -{
- - unsigned int clock;
- -
- - clock = host->clock;
- - host->clock = 0;
- - sdhci_set_clock(host, clock);
- }
- +EXPORT_SYMBOL_GPL(sdhci_set_clock);
-
- -static int sdhci_set_power(struct sdhci_host *host, unsigned short power)
- +static void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
- + unsigned short vdd)
- {
- u8 pwr = 0;
-
- - if (power != (unsigned short)-1) {
- - switch (1 << power) {
- + if (mode != MMC_POWER_OFF) {
- + switch (1 << vdd) {
- case MMC_VDD_165_195:
- pwr = SDHCI_POWER_180;
- break;
- @@ -1284,7 +1244,7 @@ static int sdhci_set_power(struct sdhci_host *host, unsigned short power)
- }
-
- if (host->pwr == pwr)
- - return -1;
- + return;
-
- host->pwr = pwr;
-
- @@ -1292,38 +1252,43 @@ static int sdhci_set_power(struct sdhci_host *host, unsigned short power)
- sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
- if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
- sdhci_runtime_pm_bus_off(host);
- - return 0;
- - }
- -
- - /*
- - * Spec says that we should clear the power reg before setting
- - * a new value. Some controllers don't seem to like this though.
- - */
- - if (!(host->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))
- - sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
- + vdd = 0;
- + } else {
- + /*
- + * Spec says that we should clear the power reg before setting
- + * a new value. Some controllers don't seem to like this though.
- + */
- + if (!(host->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))
- + sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
-
- - /*
- - * At least the Marvell CaFe chip gets confused if we set the voltage
- - * and set turn on power at the same time, so set the voltage first.
- - */
- - if (host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER)
- - sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
- + /*
- + * At least the Marvell CaFe chip gets confused if we set the
- + * voltage and set turn on power at the same time, so set the
- + * voltage first.
- + */
- + if (host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER)
- + sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
-
- - pwr |= SDHCI_POWER_ON;
- + pwr |= SDHCI_POWER_ON;
-
- - sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
- + sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
-
- - if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
- - sdhci_runtime_pm_bus_on(host);
- + if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
- + sdhci_runtime_pm_bus_on(host);
-
- - /*
- - * Some controllers need an extra 10ms delay of 10ms before they
- - * can apply clock after applying power
- - */
- - if (host->quirks & SDHCI_QUIRK_DELAY_AFTER_POWER)
- - mdelay(10);
- + /*
- + * Some controllers need an extra 10ms delay of 10ms before
- + * they can apply clock after applying power
- + */
- + if (host->quirks & SDHCI_QUIRK_DELAY_AFTER_POWER)
- + mdelay(10);
- + }
-
- - return power;
- + if (host->vmmc) {
- + spin_unlock_irq(&host->lock);
- + mmc_regulator_set_ocr(host->mmc, host->vmmc, vdd);
- + spin_lock_irq(&host->lock);
- + }
- }
-
- /*****************************************************************************\
- @@ -1427,10 +1392,52 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
- spin_unlock_irqrestore(&host->lock, flags);
- }
-
- +void sdhci_set_bus_width(struct sdhci_host *host, int width)
- +{
- + u8 ctrl;
- +
- + ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
- + if (width == MMC_BUS_WIDTH_8) {
- + ctrl &= ~SDHCI_CTRL_4BITBUS;
- + if (host->version >= SDHCI_SPEC_300)
- + ctrl |= SDHCI_CTRL_8BITBUS;
- + } else {
- + if (host->version >= SDHCI_SPEC_300)
- + ctrl &= ~SDHCI_CTRL_8BITBUS;
- + if (width == MMC_BUS_WIDTH_4)
- + ctrl |= SDHCI_CTRL_4BITBUS;
- + else
- + ctrl &= ~SDHCI_CTRL_4BITBUS;
- + }
- + sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
- +}
- +EXPORT_SYMBOL_GPL(sdhci_set_bus_width);
- +
- +void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
- +{
- + u16 ctrl_2;
- +
- + ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
- + /* Select Bus Speed Mode for host */
- + ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
- + if ((timing == MMC_TIMING_MMC_HS200) ||
- + (timing == MMC_TIMING_UHS_SDR104))
- + ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
- + else if (timing == MMC_TIMING_UHS_SDR12)
- + ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
- + else if (timing == MMC_TIMING_UHS_SDR25)
- + ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
- + else if (timing == MMC_TIMING_UHS_SDR50)
- + ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
- + else if (timing == MMC_TIMING_UHS_DDR50)
- + ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
- + sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
- +}
- +EXPORT_SYMBOL_GPL(sdhci_set_uhs_signaling);
- +
- static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
- {
- unsigned long flags;
- - int vdd_bit = -1;
- u8 ctrl;
-
- spin_lock_irqsave(&host->lock, flags);
- @@ -1456,45 +1463,17 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
- !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN))
- sdhci_enable_preset_value(host, false);
-
- - sdhci_set_clock(host, ios->clock);
- -
- - if (ios->power_mode == MMC_POWER_OFF)
- - vdd_bit = sdhci_set_power(host, -1);
- - else
- - vdd_bit = sdhci_set_power(host, ios->vdd);
- -
- - if (host->vmmc && vdd_bit != -1) {
- - spin_unlock_irqrestore(&host->lock, flags);
- - mmc_regulator_set_ocr(host->mmc, host->vmmc, vdd_bit);
- - spin_lock_irqsave(&host->lock, flags);
- + if (!ios->clock || ios->clock != host->clock) {
- + host->ops->set_clock(host, ios->clock);
- + host->clock = ios->clock;
- }
-
- + sdhci_set_power(host, ios->power_mode, ios->vdd);
- +
- if (host->ops->platform_send_init_74_clocks)
- host->ops->platform_send_init_74_clocks(host, ios->power_mode);
-
- - /*
- - * If your platform has 8-bit width support but is not a v3 controller,
- - * or if it requires special setup code, you should implement that in
- - * platform_bus_width().
- - */
- - if (host->ops->platform_bus_width) {
- - host->ops->platform_bus_width(host, ios->bus_width);
- - } else {
- - ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
- - if (ios->bus_width == MMC_BUS_WIDTH_8) {
- - ctrl &= ~SDHCI_CTRL_4BITBUS;
- - if (host->version >= SDHCI_SPEC_300)
- - ctrl |= SDHCI_CTRL_8BITBUS;
- - } else {
- - if (host->version >= SDHCI_SPEC_300)
- - ctrl &= ~SDHCI_CTRL_8BITBUS;
- - if (ios->bus_width == MMC_BUS_WIDTH_4)
- - ctrl |= SDHCI_CTRL_4BITBUS;
- - else
- - ctrl &= ~SDHCI_CTRL_4BITBUS;
- - }
- - sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
- - }
- + host->ops->set_bus_width(host, ios->bus_width);
-
- ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
-
- @@ -1516,13 +1495,13 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
- (ios->timing == MMC_TIMING_UHS_SDR25))
- ctrl |= SDHCI_CTRL_HISPD;
-
- - ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
- - if (!(ctrl_2 & SDHCI_CTRL_PRESET_VAL_ENABLE)) {
- + if (!host->preset_enabled) {
- sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
- /*
- * We only need to set Driver Strength if the
- * preset value enable is not set.
- */
- + ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
- ctrl_2 &= ~SDHCI_CTRL_DRV_TYPE_MASK;
- if (ios->drv_type == MMC_SET_DRIVER_TYPE_A)
- ctrl_2 |= SDHCI_CTRL_DRV_TYPE_A;
- @@ -1546,34 +1525,16 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
- sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
-
- /* Re-enable SD Clock */
- - sdhci_update_clock(host);
- + host->ops->set_clock(host, host->clock);
- }
-
- -
- /* Reset SD Clock Enable */
- clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
- clk &= ~SDHCI_CLOCK_CARD_EN;
- sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
-
- - if (host->ops->set_uhs_signaling)
- - host->ops->set_uhs_signaling(host, ios->timing);
- - else {
- - ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
- - /* Select Bus Speed Mode for host */
- - ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
- - if ((ios->timing == MMC_TIMING_MMC_HS200) ||
- - (ios->timing == MMC_TIMING_UHS_SDR104))
- - ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
- - else if (ios->timing == MMC_TIMING_UHS_SDR12)
- - ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
- - else if (ios->timing == MMC_TIMING_UHS_SDR25)
- - ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
- - else if (ios->timing == MMC_TIMING_UHS_SDR50)
- - ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
- - else if (ios->timing == MMC_TIMING_UHS_DDR50)
- - ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
- - sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
- - }
- + host->ops->set_uhs_signaling(host, ios->timing);
- + host->timing = ios->timing;
-
- if (!(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN) &&
- ((ios->timing == MMC_TIMING_UHS_SDR12) ||
- @@ -1590,7 +1551,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
- }
-
- /* Re-enable SD Clock */
- - sdhci_update_clock(host);
- + host->ops->set_clock(host, host->clock);
- } else
- sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
-
- @@ -1600,7 +1561,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
- * it on each ios seems to solve the problem.
- */
- if(host->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS)
- - sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
- + sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
-
- mmiowb();
- spin_unlock_irqrestore(&host->lock, flags);
- @@ -1709,24 +1670,16 @@ static int sdhci_get_ro(struct mmc_host *mmc)
-
- static void sdhci_enable_sdio_irq_nolock(struct sdhci_host *host, int enable)
- {
- - if (host->flags & SDHCI_DEVICE_DEAD)
- - goto out;
- -
- - if (enable)
- - host->flags |= SDHCI_SDIO_IRQ_ENABLED;
- - else
- - host->flags &= ~SDHCI_SDIO_IRQ_ENABLED;
- -
- - /* SDIO IRQ will be enabled as appropriate in runtime resume */
- - if (host->runtime_suspended)
- - goto out;
- + if (!(host->flags & SDHCI_DEVICE_DEAD)) {
- + if (enable)
- + host->ier |= SDHCI_INT_CARD_INT;
- + else
- + host->ier &= ~SDHCI_INT_CARD_INT;
-
- - if (enable)
- - sdhci_unmask_irqs(host, SDHCI_INT_CARD_INT);
- - else
- - sdhci_mask_irqs(host, SDHCI_INT_CARD_INT);
- -out:
- - mmiowb();
- + sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
- + sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
- + mmiowb();
- + }
- }
-
- static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
- @@ -1734,9 +1687,18 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
- struct sdhci_host *host = mmc_priv(mmc);
- unsigned long flags;
-
- + sdhci_runtime_pm_get(host);
- +
- spin_lock_irqsave(&host->lock, flags);
- + if (enable)
- + host->flags |= SDHCI_SDIO_IRQ_ENABLED;
- + else
- + host->flags &= ~SDHCI_SDIO_IRQ_ENABLED;
- +
- sdhci_enable_sdio_irq_nolock(host, enable);
- spin_unlock_irqrestore(&host->lock, flags);
- +
- + sdhci_runtime_pm_put(host);
- }
-
- static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
- @@ -1798,9 +1760,6 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
- ctrl |= SDHCI_CTRL_VDD_180;
- sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
-
- - /* Wait for 5ms */
- - usleep_range(5000, 5500);
- -
- /* 1.8V regulator output should be stable within 5 ms */
- ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
- if (ctrl & SDHCI_CTRL_VDD_180)
- @@ -1855,22 +1814,16 @@ static int sdhci_card_busy(struct mmc_host *mmc)
-
- static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
- {
- - struct sdhci_host *host;
- + struct sdhci_host *host = mmc_priv(mmc);
- u16 ctrl;
- - u32 ier;
- int tuning_loop_counter = MAX_TUNING_LOOP;
- unsigned long timeout;
- int err = 0;
- - bool requires_tuning_nonuhs = false;
- unsigned long flags;
-
- - host = mmc_priv(mmc);
- -
- sdhci_runtime_pm_get(host);
- spin_lock_irqsave(&host->lock, flags);
-
- - ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
- -
- /*
- * The Host Controller needs tuning only in case of SDR104 mode
- * and for SDR50 mode when Use Tuning for SDR50 is set in the
- @@ -1878,15 +1831,18 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
- * If the Host Controller supports the HS200 mode then the
- * tuning function has to be executed.
- */
- - if (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR50) &&
- - (host->flags & SDHCI_SDR50_NEEDS_TUNING ||
- - host->flags & SDHCI_SDR104_NEEDS_TUNING))
- - requires_tuning_nonuhs = true;
- -
- - if (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR104) ||
- - requires_tuning_nonuhs)
- - ctrl |= SDHCI_CTRL_EXEC_TUNING;
- - else {
- + switch (host->timing) {
- + case MMC_TIMING_MMC_HS200:
- + case MMC_TIMING_UHS_SDR104:
- + break;
- +
- + case MMC_TIMING_UHS_SDR50:
- + if (host->flags & SDHCI_SDR50_NEEDS_TUNING ||
- + host->flags & SDHCI_SDR104_NEEDS_TUNING)
- + break;
- + /* FALLTHROUGH */
- +
- + default:
- spin_unlock_irqrestore(&host->lock, flags);
- sdhci_runtime_pm_put(host);
- return 0;
- @@ -1899,6 +1855,8 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
- return err;
- }
-
- + ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
- + ctrl |= SDHCI_CTRL_EXEC_TUNING;
- sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
-
- /*
- @@ -1911,8 +1869,8 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
- * to make sure we don't hit a controller bug, we _only_
- * enable Buffer Read Ready interrupt here.
- */
- - ier = sdhci_readl(host, SDHCI_INT_ENABLE);
- - sdhci_clear_set_irqs(host, ier, SDHCI_INT_DATA_AVAIL);
- + sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_INT_ENABLE);
- + sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_SIGNAL_ENABLE);
-
- /*
- * Issue CMD19 repeatedly till Execute Tuning is set to 0 or the number
- @@ -2044,7 +2002,8 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
- if (err && (host->flags & SDHCI_USING_RETUNING_TIMER))
- err = 0;
-
- - sdhci_clear_set_irqs(host, SDHCI_INT_DATA_AVAIL, ier);
- + sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
- + sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
- spin_unlock_irqrestore(&host->lock, flags);
- sdhci_runtime_pm_put(host);
-
- @@ -2054,26 +2013,30 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
-
- static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable)
- {
- - u16 ctrl;
- -
- /* Host Controller v3.00 defines preset value registers */
- if (host->version < SDHCI_SPEC_300)
- return;
-
- - ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
- -
- /*
- * We only enable or disable Preset Value if they are not already
- * enabled or disabled respectively. Otherwise, we bail out.
- */
- - if (enable && !(ctrl & SDHCI_CTRL_PRESET_VAL_ENABLE)) {
- - ctrl |= SDHCI_CTRL_PRESET_VAL_ENABLE;
- - sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
- - host->flags |= SDHCI_PV_ENABLED;
- - } else if (!enable && (ctrl & SDHCI_CTRL_PRESET_VAL_ENABLE)) {
- - ctrl &= ~SDHCI_CTRL_PRESET_VAL_ENABLE;
- + if (host->preset_enabled != enable) {
- + u16 ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
- +
- + if (enable)
- + ctrl |= SDHCI_CTRL_PRESET_VAL_ENABLE;
- + else
- + ctrl &= ~SDHCI_CTRL_PRESET_VAL_ENABLE;
- +
- sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
- - host->flags &= ~SDHCI_PV_ENABLED;
- +
- + if (enable)
- + host->flags |= SDHCI_PV_ENABLED;
- + else
- + host->flags &= ~SDHCI_PV_ENABLED;
- +
- + host->preset_enabled = enable;
- }
- }
-
- @@ -2095,8 +2058,8 @@ static void sdhci_card_event(struct mmc_host *mmc)
- pr_err("%s: Resetting controller.\n",
- mmc_hostname(host->mmc));
-
- - sdhci_reset(host, SDHCI_RESET_CMD);
- - sdhci_reset(host, SDHCI_RESET_DATA);
- + sdhci_do_reset(host, SDHCI_RESET_CMD);
- + sdhci_do_reset(host, SDHCI_RESET_DATA);
-
- host->mrq->cmd->error = -ENOMEDIUM;
- tasklet_schedule(&host->finish_tasklet);
- @@ -2124,15 +2087,6 @@ static const struct mmc_host_ops sdhci_ops = {
- * *
- \*****************************************************************************/
-
- -static void sdhci_tasklet_card(unsigned long param)
- -{
- - struct sdhci_host *host = (struct sdhci_host*)param;
- -
- - sdhci_card_event(host->mmc);
- -
- - mmc_detect_change(host->mmc, msecs_to_jiffies(200));
- -}
- -
- static void sdhci_tasklet_finish(unsigned long param)
- {
- struct sdhci_host *host;
- @@ -2169,12 +2123,12 @@ static void sdhci_tasklet_finish(unsigned long param)
- /* Some controllers need this kick or reset won't work here */
- if (host->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET)
- /* This is to force an update */
- - sdhci_update_clock(host);
- + host->ops->set_clock(host, host->clock);
-
- /* Spec says we should do both at the same time, but Ricoh
- controllers do not like that. */
- - sdhci_reset(host, SDHCI_RESET_CMD);
- - sdhci_reset(host, SDHCI_RESET_DATA);
- + sdhci_do_reset(host, SDHCI_RESET_CMD);
- + sdhci_do_reset(host, SDHCI_RESET_DATA);
- }
-
- host->mrq = NULL;
- @@ -2424,101 +2378,94 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
-
- static irqreturn_t sdhci_irq(int irq, void *dev_id)
- {
- - irqreturn_t result;
- + irqreturn_t result = IRQ_NONE;
- struct sdhci_host *host = dev_id;
- - u32 intmask, unexpected = 0;
- - int cardint = 0, max_loops = 16;
- + u32 intmask, mask, unexpected = 0;
- + int max_loops = 16;
-
- spin_lock(&host->lock);
-
- - if (host->runtime_suspended) {
- + if (host->runtime_suspended && !sdhci_sdio_irq_enabled(host)) {
- spin_unlock(&host->lock);
- return IRQ_NONE;
- }
-
- intmask = sdhci_readl(host, SDHCI_INT_STATUS);
- -
- if (!intmask || intmask == 0xffffffff) {
- result = IRQ_NONE;
- goto out;
- }
-
- -again:
- - DBG("*** %s got interrupt: 0x%08x\n",
- - mmc_hostname(host->mmc), intmask);
- -
- - if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
- - u32 present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
- - SDHCI_CARD_PRESENT;
- -
- - /*
- - * There is a observation on i.mx esdhc. INSERT bit will be
- - * immediately set again when it gets cleared, if a card is
- - * inserted. We have to mask the irq to prevent interrupt
- - * storm which will freeze the system. And the REMOVE gets
- - * the same situation.
- - *
- - * More testing are needed here to ensure it works for other
- - * platforms though.
- - */
- - sdhci_mask_irqs(host, present ? SDHCI_INT_CARD_INSERT :
- - SDHCI_INT_CARD_REMOVE);
- - sdhci_unmask_irqs(host, present ? SDHCI_INT_CARD_REMOVE :
- - SDHCI_INT_CARD_INSERT);
- + do {
- + /* Clear selected interrupts. */
- + mask = intmask & (SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK |
- + SDHCI_INT_BUS_POWER);
- + sdhci_writel(host, mask, SDHCI_INT_STATUS);
-
- - sdhci_writel(host, intmask & (SDHCI_INT_CARD_INSERT |
- - SDHCI_INT_CARD_REMOVE), SDHCI_INT_STATUS);
- - intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE);
- - tasklet_schedule(&host->card_tasklet);
- - }
- + DBG("*** %s got interrupt: 0x%08x\n",
- + mmc_hostname(host->mmc), intmask);
-
- - if (intmask & SDHCI_INT_CMD_MASK) {
- - sdhci_writel(host, intmask & SDHCI_INT_CMD_MASK,
- - SDHCI_INT_STATUS);
- - sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);
- - }
- + if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
- + u32 present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
- + SDHCI_CARD_PRESENT;
-
- - if (intmask & SDHCI_INT_DATA_MASK) {
- - sdhci_writel(host, intmask & SDHCI_INT_DATA_MASK,
- - SDHCI_INT_STATUS);
- - sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
- - }
- -
- - intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK);
- + /*
- + * There is a observation on i.mx esdhc. INSERT
- + * bit will be immediately set again when it gets
- + * cleared, if a card is inserted. We have to mask
- + * the irq to prevent interrupt storm which will
- + * freeze the system. And the REMOVE gets the
- + * same situation.
- + *
- + * More testing are needed here to ensure it works
- + * for other platforms though.
- + */
- + host->ier &= ~(SDHCI_INT_CARD_INSERT |
- + SDHCI_INT_CARD_REMOVE);
- + host->ier |= present ? SDHCI_INT_CARD_REMOVE :
- + SDHCI_INT_CARD_INSERT;
- + sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
- + sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
- +
- + sdhci_writel(host, intmask & (SDHCI_INT_CARD_INSERT |
- + SDHCI_INT_CARD_REMOVE), SDHCI_INT_STATUS);
- +
- + host->thread_isr |= intmask & (SDHCI_INT_CARD_INSERT |
- + SDHCI_INT_CARD_REMOVE);
- + result = IRQ_WAKE_THREAD;
- + }
-
- - intmask &= ~SDHCI_INT_ERROR;
- + if (intmask & SDHCI_INT_CMD_MASK)
- + sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);
-
- - if (intmask & SDHCI_INT_BUS_POWER) {
- - pr_err("%s: Card is consuming too much power!\n",
- - mmc_hostname(host->mmc));
- - sdhci_writel(host, SDHCI_INT_BUS_POWER, SDHCI_INT_STATUS);
- - }
- + if (intmask & SDHCI_INT_DATA_MASK)
- + sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
-
- - intmask &= ~SDHCI_INT_BUS_POWER;
- + if (intmask & SDHCI_INT_BUS_POWER)
- + pr_err("%s: Card is consuming too much power!\n",
- + mmc_hostname(host->mmc));
-
- - if (intmask & SDHCI_INT_CARD_INT)
- - cardint = 1;
- + if (intmask & SDHCI_INT_CARD_INT) {
- + sdhci_enable_sdio_irq_nolock(host, false);
- + host->thread_isr |= SDHCI_INT_CARD_INT;
- + result = IRQ_WAKE_THREAD;
- + }
-
- - intmask &= ~SDHCI_INT_CARD_INT;
- + intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE |
- + SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK |
- + SDHCI_INT_ERROR | SDHCI_INT_BUS_POWER |
- + SDHCI_INT_CARD_INT);
-
- - if (intmask) {
- - unexpected |= intmask;
- - sdhci_writel(host, intmask, SDHCI_INT_STATUS);
- - }
- -
- - result = IRQ_HANDLED;
- + if (intmask) {
- + unexpected |= intmask;
- + sdhci_writel(host, intmask, SDHCI_INT_STATUS);
- + }
-
- - intmask = sdhci_readl(host, SDHCI_INT_STATUS);
- + if (result == IRQ_NONE)
- + result = IRQ_HANDLED;
-
- - /*
- - * If we know we'll call the driver to signal SDIO IRQ, disregard
- - * further indications of Card Interrupt in the status to avoid a
- - * needless loop.
- - */
- - if (cardint)
- - intmask &= ~SDHCI_INT_CARD_INT;
- - if (intmask && --max_loops)
- - goto again;
- + intmask = sdhci_readl(host, SDHCI_INT_STATUS);
- + } while (intmask && --max_loops);
- out:
- spin_unlock(&host->lock);
-
- @@ -2527,15 +2474,38 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
- mmc_hostname(host->mmc), unexpected);
- sdhci_dumpregs(host);
- }
- - /*
- - * We have to delay this as it calls back into the driver.
- - */
- - if (cardint)
- - mmc_signal_sdio_irq(host->mmc);
-
- return result;
- }
-
- +static irqreturn_t sdhci_thread_irq(int irq, void *dev_id)
- +{
- + struct sdhci_host *host = dev_id;
- + unsigned long flags;
- + u32 isr;
- +
- + spin_lock_irqsave(&host->lock, flags);
- + isr = host->thread_isr;
- + host->thread_isr = 0;
- + spin_unlock_irqrestore(&host->lock, flags);
- +
- + if (isr & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
- + sdhci_card_event(host->mmc);
- + mmc_detect_change(host->mmc, msecs_to_jiffies(200));
- + }
- +
- + if (isr & SDHCI_INT_CARD_INT) {
- + sdio_run_irqs(host->mmc);
- +
- + spin_lock_irqsave(&host->lock, flags);
- + if (host->flags & SDHCI_SDIO_IRQ_ENABLED)
- + sdhci_enable_sdio_irq_nolock(host, true);
- + spin_unlock_irqrestore(&host->lock, flags);
- + }
- +
- + return isr ? IRQ_HANDLED : IRQ_NONE;
- +}
- +
- /*****************************************************************************\
- * *
- * Suspend/resume *
- @@ -2572,9 +2542,6 @@ EXPORT_SYMBOL_GPL(sdhci_disable_irq_wakeups);
-
- int sdhci_suspend_host(struct sdhci_host *host)
- {
- - if (host->ops->platform_suspend)
- - host->ops->platform_suspend(host);
- -
- sdhci_disable_card_detection(host);
-
- /* Disable tuning since we are suspending */
- @@ -2584,7 +2551,9 @@ int sdhci_suspend_host(struct sdhci_host *host)
- }
-
- if (!device_may_wakeup(mmc_dev(host->mmc))) {
- - sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
- + host->ier = 0;
- + sdhci_writel(host, 0, SDHCI_INT_ENABLE);
- + sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
- free_irq(host->irq, host);
- } else {
- sdhci_enable_irq_wakeups(host);
- @@ -2605,8 +2574,9 @@ int sdhci_resume_host(struct sdhci_host *host)
- }
-
- if (!device_may_wakeup(mmc_dev(host->mmc))) {
- - ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
- - mmc_hostname(host->mmc), host);
- + ret = request_threaded_irq(host->irq, sdhci_irq,
- + sdhci_thread_irq, IRQF_SHARED,
- + mmc_hostname(host->mmc), host);
- if (ret)
- return ret;
- } else {
- @@ -2628,9 +2598,6 @@ int sdhci_resume_host(struct sdhci_host *host)
-
- sdhci_enable_card_detection(host);
-
- - if (host->ops->platform_resume)
- - host->ops->platform_resume(host);
- -
- /* Set the re-tuning expiration flag */
- if (host->flags & SDHCI_USING_RETUNING_TIMER)
- host->flags |= SDHCI_NEEDS_RETUNING;
- @@ -2682,10 +2649,12 @@ int sdhci_runtime_suspend_host(struct sdhci_host *host)
- }
-
- spin_lock_irqsave(&host->lock, flags);
- - sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
- + host->ier &= SDHCI_INT_CARD_INT;
- + sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
- + sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
- spin_unlock_irqrestore(&host->lock, flags);
-
- - synchronize_irq(host->irq);
- + synchronize_hardirq(host->irq);
-
- spin_lock_irqsave(&host->lock, flags);
- host->runtime_suspended = true;
- @@ -2729,7 +2698,7 @@ int sdhci_runtime_resume_host(struct sdhci_host *host)
- host->runtime_suspended = false;
-
- /* Enable SDIO IRQ */
- - if ((host->flags & SDHCI_SDIO_IRQ_ENABLED))
- + if (host->flags & SDHCI_SDIO_IRQ_ENABLED)
- sdhci_enable_sdio_irq_nolock(host, true);
-
- /* Enable Card Detection */
- @@ -2788,7 +2757,7 @@ int sdhci_add_host(struct sdhci_host *host)
- if (debug_quirks2)
- host->quirks2 = debug_quirks2;
-
- - sdhci_reset(host, SDHCI_RESET_ALL);
- + sdhci_do_reset(host, SDHCI_RESET_ALL);
-
- host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
- host->version = (host->version & SDHCI_SPEC_VER_MASK)
- @@ -2848,15 +2817,29 @@ int sdhci_add_host(struct sdhci_host *host)
- * (128) and potentially one alignment transfer for
- * each of those entries.
- */
- - host->adma_desc = kmalloc((128 * 2 + 1) * 4, GFP_KERNEL);
- + host->adma_desc = dma_alloc_coherent(mmc_dev(host->mmc),
- + ADMA_SIZE, &host->adma_addr,
- + GFP_KERNEL);
- host->align_buffer = kmalloc(128 * 4, GFP_KERNEL);
- if (!host->adma_desc || !host->align_buffer) {
- - kfree(host->adma_desc);
- + dma_free_coherent(mmc_dev(host->mmc), ADMA_SIZE,
- + host->adma_desc, host->adma_addr);
- kfree(host->align_buffer);
- pr_warning("%s: Unable to allocate ADMA "
- "buffers. Falling back to standard DMA.\n",
- mmc_hostname(mmc));
- host->flags &= ~SDHCI_USE_ADMA;
- + host->adma_desc = NULL;
- + host->align_buffer = NULL;
- + } else if (host->adma_addr & 3) {
- + pr_warning("%s: unable to allocate aligned ADMA descriptor\n",
- + mmc_hostname(mmc));
- + host->flags &= ~SDHCI_USE_ADMA;
- + dma_free_coherent(mmc_dev(host->mmc), ADMA_SIZE,
- + host->adma_desc, host->adma_addr);
- + kfree(host->align_buffer);
- + host->adma_desc = NULL;
- + host->align_buffer = NULL;
- }
- }
-
- @@ -2941,6 +2924,7 @@ int sdhci_add_host(struct sdhci_host *host)
- mmc->max_busy_timeout = (1 << 27) / host->timeout_clk;
-
- mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23;
- + mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD;
-
- if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12)
- host->flags |= SDHCI_AUTO_CMD12;
- @@ -3212,8 +3196,6 @@ int sdhci_add_host(struct sdhci_host *host)
- /*
- * Init tasklets.
- */
- - tasklet_init(&host->card_tasklet,
- - sdhci_tasklet_card, (unsigned long)host);
- tasklet_init(&host->finish_tasklet,
- sdhci_tasklet_finish, (unsigned long)host);
-
- @@ -3230,8 +3212,8 @@ int sdhci_add_host(struct sdhci_host *host)
-
- sdhci_init(host, 0);
-
- - ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
- - mmc_hostname(mmc), host);
- + ret = request_threaded_irq(host->irq, sdhci_irq, sdhci_thread_irq,
- + IRQF_SHARED, mmc_hostname(mmc), host);
- if (ret) {
- pr_err("%s: Failed to request IRQ %d: %d\n",
- mmc_hostname(mmc), host->irq, ret);
- @@ -3273,12 +3255,12 @@ int sdhci_add_host(struct sdhci_host *host)
-
- #ifdef SDHCI_USE_LEDS_CLASS
- reset:
- - sdhci_reset(host, SDHCI_RESET_ALL);
- - sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
- + sdhci_do_reset(host, SDHCI_RESET_ALL);
- + sdhci_writel(host, 0, SDHCI_INT_ENABLE);
- + sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
- free_irq(host->irq, host);
- #endif
- untasklet:
- - tasklet_kill(&host->card_tasklet);
- tasklet_kill(&host->finish_tasklet);
-
- return ret;
- @@ -3315,14 +3297,14 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
- #endif
-
- if (!dead)
- - sdhci_reset(host, SDHCI_RESET_ALL);
- + sdhci_do_reset(host, SDHCI_RESET_ALL);
-
- - sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
- + sdhci_writel(host, 0, SDHCI_INT_ENABLE);
- + sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
- free_irq(host->irq, host);
-
- del_timer_sync(&host->timer);
-
- - tasklet_kill(&host->card_tasklet);
- tasklet_kill(&host->finish_tasklet);
-
- if (host->vmmc) {
- @@ -3335,7 +3317,9 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
- regulator_put(host->vqmmc);
- }
-
- - kfree(host->adma_desc);
- + if (host->adma_desc)
- + dma_free_coherent(mmc_dev(host->mmc), ADMA_SIZE,
- + host->adma_desc, host->adma_addr);
- kfree(host->align_buffer);
-
- host->adma_desc = NULL;
- diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
- index 0a3ed01887db..4a5cd5e3fa3e 100644
- --- a/drivers/mmc/host/sdhci.h
- +++ b/drivers/mmc/host/sdhci.h
- @@ -281,18 +281,14 @@ struct sdhci_ops {
- unsigned int (*get_max_clock)(struct sdhci_host *host);
- unsigned int (*get_min_clock)(struct sdhci_host *host);
- unsigned int (*get_timeout_clock)(struct sdhci_host *host);
- - int (*platform_bus_width)(struct sdhci_host *host,
- - int width);
- + void (*set_bus_width)(struct sdhci_host *host, int width);
- void (*platform_send_init_74_clocks)(struct sdhci_host *host,
- u8 power_mode);
- unsigned int (*get_ro)(struct sdhci_host *host);
- - void (*platform_reset_enter)(struct sdhci_host *host, u8 mask);
- - void (*platform_reset_exit)(struct sdhci_host *host, u8 mask);
- + void (*reset)(struct sdhci_host *host, u8 mask);
- int (*platform_execute_tuning)(struct sdhci_host *host, u32 opcode);
- - int (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs);
- + void (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs);
- void (*hw_reset)(struct sdhci_host *host);
- - void (*platform_suspend)(struct sdhci_host *host);
- - void (*platform_resume)(struct sdhci_host *host);
- void (*adma_workaround)(struct sdhci_host *host, u32 intmask);
- void (*platform_init)(struct sdhci_host *host);
- void (*card_event)(struct sdhci_host *host);
- @@ -397,6 +393,16 @@ extern void sdhci_remove_host(struct sdhci_host *host, int dead);
- extern void sdhci_send_command(struct sdhci_host *host,
- struct mmc_command *cmd);
-
- +static inline bool sdhci_sdio_irq_enabled(struct sdhci_host *host)
- +{
- + return !!(host->flags & SDHCI_SDIO_IRQ_ENABLED);
- +}
- +
- +void sdhci_set_clock(struct sdhci_host *host, unsigned int clock);
- +void sdhci_set_bus_width(struct sdhci_host *host, int width);
- +void sdhci_reset(struct sdhci_host *host, u8 mask);
- +void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing);
- +
- #ifdef CONFIG_PM
- extern int sdhci_suspend_host(struct sdhci_host *host);
- extern int sdhci_resume_host(struct sdhci_host *host);
- diff --git a/drivers/regulator/anatop-regulator.c b/drivers/regulator/anatop-regulator.c
- index 7c397bb81e01..6da2fbbb9bd5 100644
- --- a/drivers/regulator/anatop-regulator.c
- +++ b/drivers/regulator/anatop-regulator.c
- @@ -267,6 +267,7 @@ static int anatop_regulator_probe(struct platform_device *pdev)
- config.driver_data = sreg;
- config.of_node = pdev->dev.of_node;
- config.regmap = sreg->anatop;
- + config.ena_gpio = -EINVAL;
-
- /* Only core regulators have the ramp up delay configuration. */
- if (sreg->control_reg && sreg->delay_bit_width) {
- diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
- index 9a09f3cdbabb..19c4077374b6 100644
- --- a/drivers/regulator/core.c
- +++ b/drivers/regulator/core.c
- @@ -3459,7 +3459,7 @@ regulator_register(const struct regulator_desc *regulator_desc,
-
- dev_set_drvdata(&rdev->dev, rdev);
-
- - if (config->ena_gpio && gpio_is_valid(config->ena_gpio)) {
- + if (gpio_is_valid(config->ena_gpio)) {
- ret = regulator_ena_gpio_request(rdev, config);
- if (ret != 0) {
- rdev_err(rdev, "Failed to request enable GPIO%d: %d\n",
- diff --git a/drivers/regulator/dummy.c b/drivers/regulator/dummy.c
- index 2436db9e2ca3..acc4ea593c95 100644
- --- a/drivers/regulator/dummy.c
- +++ b/drivers/regulator/dummy.c
- @@ -48,6 +48,7 @@ static int dummy_regulator_probe(struct platform_device *pdev)
-
- config.dev = &pdev->dev;
- config.init_data = &dummy_initdata;
- + config.ena_gpio = -EINVAL;
-
- dummy_regulator_rdev = regulator_register(&dummy_desc, &config);
- if (IS_ERR(dummy_regulator_rdev)) {
- diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c
- index c61f7e97e4f8..aabf10dc8a50 100644
- --- a/drivers/regulator/fixed.c
- +++ b/drivers/regulator/fixed.c
- @@ -161,9 +161,7 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
- drvdata->desc.n_voltages = 1;
-
- drvdata->desc.fixed_uV = config->microvolts;
- -
- - if (config->gpio >= 0)
- - cfg.ena_gpio = config->gpio;
- + cfg.ena_gpio = config->gpio;
- cfg.ena_gpio_invert = !config->enable_high;
- if (config->enabled_at_boot) {
- if (config->enable_high)
- diff --git a/drivers/staging/imx-drm/Kconfig b/drivers/staging/imx-drm/Kconfig
- index c6e8ba7b3e4e..52516a7cf26f 100644
- --- a/drivers/staging/imx-drm/Kconfig
- +++ b/drivers/staging/imx-drm/Kconfig
- @@ -35,6 +35,7 @@ config DRM_IMX_TVE
- config DRM_IMX_LDB
- tristate "Support for LVDS displays"
- depends on DRM_IMX && MFD_SYSCON
- + select DRM_PANEL
- help
- Choose this to enable the internal LVDS Display Bridge (LDB)
- found on i.MX53 and i.MX6 processors.
- @@ -60,3 +61,20 @@ config DRM_IMX_HDMI
- depends on DRM_IMX
- help
- Choose this if you want to use HDMI on i.MX6.
- +
- +config DRM_DW_HDMI_AUDIO
- + tristate "Synopsis Designware Audio interface"
- + depends on DRM_IMX_HDMI != n
- + help
- + Support the Audio interface which is part of the Synopsis
- + Designware HDMI block. This is used in conjunction with
- + the i.MX HDMI driver.
- +
- +config DRM_DW_HDMI_CEC
- + tristate "Synopsis Designware CEC interface"
- + depends on DRM_IMX_HDMI != n
- + select HDMI_CEC_CORE
- + help
- + Support the CEC interface which is part of the Synposis
- + Designware HDMI block. This is used in conjunction with
- + the i.MX HDMI driver.
- diff --git a/drivers/staging/imx-drm/Makefile b/drivers/staging/imx-drm/Makefile
- index 129e3a3f59f1..5eabd5e4e456 100644
- --- a/drivers/staging/imx-drm/Makefile
- +++ b/drivers/staging/imx-drm/Makefile
- @@ -3,6 +3,7 @@ imxdrm-objs := imx-drm-core.o
-
- obj-$(CONFIG_DRM_IMX) += imxdrm.o
-
- +obj-$(CONFIG_DRM_IMX) += drm-ddc-connector.o
- obj-$(CONFIG_DRM_IMX_PARALLEL_DISPLAY) += parallel-display.o
- obj-$(CONFIG_DRM_IMX_TVE) += imx-tve.o
- obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o
- @@ -11,3 +12,5 @@ obj-$(CONFIG_DRM_IMX_IPUV3_CORE) += ipu-v3/
- imx-ipuv3-crtc-objs := ipuv3-crtc.o ipuv3-plane.o
- obj-$(CONFIG_DRM_IMX_IPUV3) += imx-ipuv3-crtc.o
- obj-$(CONFIG_DRM_IMX_HDMI) += imx-hdmi.o
- +obj-$(CONFIG_DRM_DW_HDMI_AUDIO) += dw-hdmi-audio.o
- +obj-$(CONFIG_DRM_DW_HDMI_CEC) += dw-hdmi-cec.o
- diff --git a/drivers/staging/imx-drm/drm-ddc-connector.c b/drivers/staging/imx-drm/drm-ddc-connector.c
- new file mode 100644
- index 000000000000..a36ed4b06ebe
- --- /dev/null
- +++ b/drivers/staging/imx-drm/drm-ddc-connector.c
- @@ -0,0 +1,92 @@
- +#include <linux/i2c.h>
- +#include <linux/module.h>
- +#include <drm/drmP.h>
- +#include <drm/drm_crtc_helper.h>
- +#include <drm/drm_edid.h>
- +
- +#include "drm-ddc-connector.h"
- +
- +static enum drm_connector_status
- +drm_ddc_connector_detect(struct drm_connector *connector, bool force)
- +{
- + struct drm_ddc_connector *ddc_conn = to_ddc_conn(connector);
- +
- + return ddc_conn->detect ? ddc_conn->detect(connector, force) :
- + connector_status_connected;
- +}
- +
- +int drm_ddc_connector_get_modes(struct drm_connector *connector)
- +{
- + struct drm_ddc_connector *ddc_conn = to_ddc_conn(connector);
- + struct edid *edid;
- + int ret = 0;
- +
- + if (!ddc_conn->ddc)
- + return 0;
- +
- + edid = drm_get_edid(connector, ddc_conn->ddc);
- + if (edid) {
- + drm_mode_connector_update_edid_property(connector, edid);
- + ret = drm_add_edid_modes(connector, edid);
- + /* Store the ELD */
- + drm_edid_to_eld(connector, edid);
- + kfree(edid);
- + }
- +
- + return ret;
- +}
- +EXPORT_SYMBOL_GPL(drm_ddc_connector_get_modes);
- +
- +static void drm_ddc_connector_destroy(struct drm_connector *connector)
- +{
- + struct drm_ddc_connector *ddc_conn = to_ddc_conn(connector);
- +
- + drm_sysfs_connector_remove(connector);
- + drm_connector_cleanup(connector);
- + if (ddc_conn->ddc)
- + i2c_put_adapter(ddc_conn->ddc);
- +}
- +
- +static const struct drm_connector_funcs drm_ddc_connector_funcs = {
- + .dpms = drm_helper_connector_dpms,
- + .fill_modes = drm_helper_probe_single_connector_modes,
- + .detect = drm_ddc_connector_detect,
- + .destroy = drm_ddc_connector_destroy,
- +};
- +
- +int drm_ddc_connector_add(struct drm_device *drm,
- + struct drm_ddc_connector *ddc_conn, int connector_type)
- +{
- + drm_connector_init(drm, &ddc_conn->connector, &drm_ddc_connector_funcs,
- + connector_type);
- + return 0;
- +}
- +EXPORT_SYMBOL_GPL(drm_ddc_connector_add);
- +
- +struct drm_ddc_connector *drm_ddc_connector_create(struct drm_device *drm,
- + struct device_node *np, void *private)
- +{
- + struct drm_ddc_connector *ddc_conn;
- + struct device_node *ddc_node;
- +
- + ddc_conn = devm_kzalloc(drm->dev, sizeof(*ddc_conn), GFP_KERNEL);
- + if (!ddc_conn)
- + return ERR_PTR(-ENOMEM);
- +
- + ddc_conn->private = private;
- +
- + ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
- + if (ddc_node) {
- + ddc_conn->ddc = of_find_i2c_adapter_by_node(ddc_node);
- + of_node_put(ddc_node);
- + if (!ddc_conn->ddc)
- + return ERR_PTR(-EPROBE_DEFER);
- + }
- +
- + return ddc_conn;
- +}
- +EXPORT_SYMBOL_GPL(drm_ddc_connector_create);
- +
- +MODULE_AUTHOR("Russell King <rmk+kernel@arm.linux.org.uk>");
- +MODULE_DESCRIPTION("Generic DRM DDC connector module");
- +MODULE_LICENSE("GPL v2");
- diff --git a/drivers/staging/imx-drm/drm-ddc-connector.h b/drivers/staging/imx-drm/drm-ddc-connector.h
- new file mode 100644
- index 000000000000..38068e5105d3
- --- /dev/null
- +++ b/drivers/staging/imx-drm/drm-ddc-connector.h
- @@ -0,0 +1,26 @@
- +#ifndef DRM_DDC_CONNECTOR_H
- +#define DRM_DDC_CONNECTOR_H
- +
- +struct drm_ddc_connector {
- + struct i2c_adapter *ddc;
- + struct drm_connector connector;
- + enum drm_connector_status (*detect)(struct drm_connector *, bool);
- + void *private;
- +};
- +
- +#define to_ddc_conn(c) container_of(c, struct drm_ddc_connector, connector)
- +
- +int drm_ddc_connector_get_modes(struct drm_connector *connector);
- +int drm_ddc_connector_add(struct drm_device *drm,
- + struct drm_ddc_connector *ddc_conn, int connector_type);
- +struct drm_ddc_connector *drm_ddc_connector_create(struct drm_device *drm,
- + struct device_node *np, void *private);
- +
- +static inline void *drm_ddc_private(struct drm_connector *connector)
- +{
- + struct drm_ddc_connector *ddc_conn = to_ddc_conn(connector);
- +
- + return ddc_conn->private;
- +}
- +
- +#endif
- diff --git a/drivers/staging/imx-drm/dw-hdmi-audio.c b/drivers/staging/imx-drm/dw-hdmi-audio.c
- new file mode 100644
- index 000000000000..e7495265ed84
- --- /dev/null
- +++ b/drivers/staging/imx-drm/dw-hdmi-audio.c
- @@ -0,0 +1,652 @@
- +/*
- + * DesignWare HDMI audio driver
- + *
- + * This program is free software; you can redistribute it and/or modify
- + * it under the terms of the GNU General Public License version 2 as
- + * published by the Free Software Foundation.
- + *
- + * Written and tested against the (alleged) DW HDMI Tx found in iMX6S.
- + */
- +#include <linux/delay.h>
- +#include <linux/io.h>
- +#include <linux/interrupt.h>
- +#include <linux/module.h>
- +#include <linux/platform_device.h>
- +
- +#include <sound/asoundef.h>
- +#include <sound/core.h>
- +#include <sound/initval.h>
- +#include <sound/pcm.h>
- +
- +#include "dw-hdmi-audio.h"
- +
- +#define DRIVER_NAME "dw-hdmi-audio"
- +
- +/* Provide some bits rather than bit offsets */
- +enum {
- + HDMI_AHB_DMA_CONF0_SW_FIFO_RST = BIT(7),
- + HDMI_AHB_DMA_CONF0_EN_HLOCK = BIT(3),
- + HDMI_AHB_DMA_START_START = BIT(0),
- + HDMI_AHB_DMA_STOP_STOP = BIT(0),
- + HDMI_IH_MUTE_AHBDMAAUD_STAT0_ERROR = BIT(5),
- + HDMI_IH_MUTE_AHBDMAAUD_STAT0_LOST = BIT(4),
- + HDMI_IH_MUTE_AHBDMAAUD_STAT0_RETRY = BIT(3),
- + HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE = BIT(2),
- + HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFFULL = BIT(1),
- + HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFEMPTY = BIT(0),
- + HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL =
- + HDMI_IH_MUTE_AHBDMAAUD_STAT0_ERROR |
- + HDMI_IH_MUTE_AHBDMAAUD_STAT0_LOST |
- + HDMI_IH_MUTE_AHBDMAAUD_STAT0_RETRY |
- + HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE |
- + HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFFULL |
- + HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFEMPTY,
- + HDMI_IH_AHBDMAAUD_STAT0_ERROR = BIT(5),
- + HDMI_IH_AHBDMAAUD_STAT0_LOST = BIT(4),
- + HDMI_IH_AHBDMAAUD_STAT0_RETRY = BIT(3),
- + HDMI_IH_AHBDMAAUD_STAT0_DONE = BIT(2),
- + HDMI_IH_AHBDMAAUD_STAT0_BUFFFULL = BIT(1),
- + HDMI_IH_AHBDMAAUD_STAT0_BUFFEMPTY = BIT(0),
- + HDMI_IH_AHBDMAAUD_STAT0_ALL =
- + HDMI_IH_AHBDMAAUD_STAT0_ERROR |
- + HDMI_IH_AHBDMAAUD_STAT0_LOST |
- + HDMI_IH_AHBDMAAUD_STAT0_RETRY |
- + HDMI_IH_AHBDMAAUD_STAT0_DONE |
- + HDMI_IH_AHBDMAAUD_STAT0_BUFFFULL |
- + HDMI_IH_AHBDMAAUD_STAT0_BUFFEMPTY,
- + HDMI_AHB_DMA_CONF0_INCR16 = 2 << 1,
- + HDMI_AHB_DMA_CONF0_INCR8 = 1 << 1,
- + HDMI_AHB_DMA_CONF0_INCR4 = 0,
- + HDMI_AHB_DMA_CONF0_BURST_MODE = BIT(0),
- + HDMI_AHB_DMA_MASK_DONE = BIT(7),
- + HDMI_REVISION_ID = 0x0001,
- + HDMI_IH_AHBDMAAUD_STAT0 = 0x0109,
- + HDMI_IH_MUTE_AHBDMAAUD_STAT0 = 0x0189,
- + HDMI_AUD_N1 = 0x3200,
- + HDMI_AUD_CTS1 = 0x3203,
- + HDMI_AHB_DMA_CONF0 = 0x3600,
- + HDMI_AHB_DMA_START = 0x3601,
- + HDMI_AHB_DMA_STOP = 0x3602,
- + HDMI_AHB_DMA_THRSLD = 0x3603,
- + HDMI_AHB_DMA_STRADDR0 = 0x3604,
- + HDMI_AHB_DMA_STPADDR0 = 0x3608,
- + HDMI_AHB_DMA_STAT = 0x3612,
- + HDMI_AHB_DMA_STAT_FULL = BIT(1),
- + HDMI_AHB_DMA_MASK = 0x3614,
- + HDMI_AHB_DMA_POL = 0x3615,
- + HDMI_AHB_DMA_CONF1 = 0x3616,
- + HDMI_AHB_DMA_BUFFPOL = 0x361a,
- +};
- +
- +struct snd_dw_hdmi {
- + struct snd_card *card;
- + struct snd_pcm *pcm;
- + struct dw_hdmi_audio_data data;
- + struct snd_pcm_substream *substream;
- + void (*reformat)(struct snd_dw_hdmi *, size_t, size_t);
- + void *buf_src;
- + void *buf_dst;
- + dma_addr_t buf_addr;
- + unsigned buf_offset;
- + unsigned buf_period;
- + unsigned buf_size;
- + unsigned channels;
- + uint8_t revision;
- + uint8_t iec_offset;
- + uint8_t cs[192][8];
- +};
- +
- +static void dw_hdmi_writel(unsigned long val, void __iomem *ptr)
- +{
- + writeb_relaxed(val, ptr);
- + writeb_relaxed(val >> 8, ptr + 1);
- + writeb_relaxed(val >> 16, ptr + 2);
- + writeb_relaxed(val >> 24, ptr + 3);
- +}
- +
- +/*
- + * Convert to hardware format: The userspace buffer contains IEC958 samples,
- + * with the PCUV bits in bits 31..28 and audio samples in bits 27..4. We
- + * need these to be in bits 27..24, with the IEC B bit in bit 28, and audio
- + * samples in 23..0.
- + *
- + * Default preamble in bits 3..0: 8 = block start, 4 = even 2 = odd
- + *
- + * Ideally, we could do with having the data properly formatted in userspace.
- + */
- +static void dw_hdmi_reformat_iec958(struct snd_dw_hdmi *dw,
- + size_t offset, size_t bytes)
- +{
- + uint32_t *src = dw->buf_src + offset;
- + uint32_t *dst = dw->buf_dst + offset;
- + uint32_t *end = dw->buf_src + offset + bytes;
- +
- + do {
- + uint32_t b, sample = *src++;
- +
- + b = (sample & 8) << (28 - 3);
- +
- + sample >>= 4;
- +
- + *dst++ = sample | b;
- + } while (src < end);
- +}
- +
- +static uint32_t parity(uint32_t sample)
- +{
- + sample ^= sample >> 16;
- + sample ^= sample >> 8;
- + sample ^= sample >> 4;
- + sample ^= sample >> 2;
- + sample ^= sample >> 1;
- + return (sample & 1) << 27;
- +}
- +
- +static void dw_hdmi_reformat_s24(struct snd_dw_hdmi *dw,
- + size_t offset, size_t bytes)
- +{
- + uint32_t *src = dw->buf_src + offset;
- + uint32_t *dst = dw->buf_dst + offset;
- + uint32_t *end = dw->buf_src + offset + bytes;
- +
- + do {
- + unsigned i;
- + uint8_t *cs;
- +
- + cs = dw->cs[dw->iec_offset++];
- + if (dw->iec_offset >= 192)
- + dw->iec_offset = 0;
- +
- + i = dw->channels;
- + do {
- + uint32_t sample = *src++;
- +
- + sample &= ~0xff000000;
- + sample |= *cs++ << 24;
- + sample |= parity(sample & ~0xf8000000);
- +
- + *dst++ = sample;
- + } while (--i);
- + } while (src < end);
- +}
- +
- +static void dw_hdmi_create_cs(struct snd_dw_hdmi *dw,
- + struct snd_pcm_runtime *runtime)
- +{
- + uint8_t cs[4];
- + unsigned ch, i, j;
- +
- + cs[0] = IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_NONE;
- + cs[1] = IEC958_AES1_CON_GENERAL;
- + cs[2] = IEC958_AES2_CON_SOURCE_UNSPEC;
- + cs[3] = IEC958_AES3_CON_CLOCK_1000PPM;
- +
- + switch (runtime->rate) {
- + case 32000:
- + cs[3] |= IEC958_AES3_CON_FS_32000;
- + break;
- + case 44100:
- + cs[3] |= IEC958_AES3_CON_FS_44100;
- + break;
- + case 48000:
- + cs[3] |= IEC958_AES3_CON_FS_48000;
- + break;
- + case 88200:
- + cs[3] |= IEC958_AES3_CON_FS_88200;
- + break;
- + case 96000:
- + cs[3] |= IEC958_AES3_CON_FS_96000;
- + break;
- + case 176400:
- + cs[3] |= IEC958_AES3_CON_FS_176400;
- + break;
- + case 192000:
- + cs[3] |= IEC958_AES3_CON_FS_192000;
- + break;
- + }
- +
- + memset(dw->cs, 0, sizeof(dw->cs));
- +
- + for (ch = 0; ch < 8; ch++) {
- + cs[2] &= ~IEC958_AES2_CON_CHANNEL;
- + cs[2] |= (ch + 1) << 4;
- +
- + for (i = 0; i < ARRAY_SIZE(cs); i++) {
- + unsigned c = cs[i];
- +
- + for (j = 0; j < 8; j++, c >>= 1)
- + dw->cs[i * 8 + j][ch] = (c & 1) << 2;
- + }
- + }
- + dw->cs[0][0] |= BIT(4);
- +}
- +
- +static void dw_hdmi_start_dma(struct snd_dw_hdmi *dw)
- +{
- + void __iomem *base = dw->data.base;
- + unsigned offset = dw->buf_offset;
- + unsigned period = dw->buf_period;
- + u32 start, stop;
- +
- + dw->reformat(dw, offset, period);
- +
- + /* Clear all irqs before enabling irqs and starting DMA */
- + writeb_relaxed(HDMI_IH_AHBDMAAUD_STAT0_ALL,
- + base + HDMI_IH_AHBDMAAUD_STAT0);
- +
- + start = dw->buf_addr + offset;
- + stop = start + period - 1;
- +
- + /* Setup the hardware start/stop addresses */
- + dw_hdmi_writel(start, base + HDMI_AHB_DMA_STRADDR0);
- + dw_hdmi_writel(stop, base + HDMI_AHB_DMA_STPADDR0);
- +
- + writeb_relaxed((u8)~HDMI_AHB_DMA_MASK_DONE, base + HDMI_AHB_DMA_MASK);
- + writeb(HDMI_AHB_DMA_START_START, base + HDMI_AHB_DMA_START);
- +
- + offset += period;
- + if (offset >= dw->buf_size)
- + offset = 0;
- + dw->buf_offset = offset;
- +}
- +
- +static void dw_hdmi_stop_dma(struct snd_dw_hdmi *dw)
- +{
- + dw->substream = NULL;
- +
- + /* Disable interrupts before disabling DMA */
- + writeb_relaxed(~0, dw->data.base + HDMI_AHB_DMA_MASK);
- + writeb_relaxed(HDMI_AHB_DMA_STOP_STOP, dw->data.base + HDMI_AHB_DMA_STOP);
- +}
- +
- +static irqreturn_t snd_dw_hdmi_irq(int irq, void *data)
- +{
- + struct snd_dw_hdmi *dw = data;
- + struct snd_pcm_substream *substream;
- + unsigned stat;
- +
- + stat = readb_relaxed(dw->data.base + HDMI_IH_AHBDMAAUD_STAT0);
- + if (!stat)
- + return IRQ_NONE;
- +
- + writeb_relaxed(stat, dw->data.base + HDMI_IH_AHBDMAAUD_STAT0);
- +
- + substream = dw->substream;
- + if (stat & HDMI_IH_AHBDMAAUD_STAT0_DONE && substream) {
- + snd_pcm_period_elapsed(substream);
- + if (dw->substream)
- + dw_hdmi_start_dma(dw);
- + }
- +
- + return IRQ_HANDLED;
- +}
- +
- +static struct snd_pcm_hardware dw_hdmi_hw = {
- + .info = SNDRV_PCM_INFO_INTERLEAVED |
- + SNDRV_PCM_INFO_BLOCK_TRANSFER |
- + SNDRV_PCM_INFO_MMAP |
- + SNDRV_PCM_INFO_MMAP_VALID,
- + .formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE |
- + SNDRV_PCM_FMTBIT_S24_LE,
- + .rates = SNDRV_PCM_RATE_32000 |
- + SNDRV_PCM_RATE_44100 |
- + SNDRV_PCM_RATE_48000 |
- + SNDRV_PCM_RATE_88200 |
- + SNDRV_PCM_RATE_96000 |
- + SNDRV_PCM_RATE_176400 |
- + SNDRV_PCM_RATE_192000,
- + .channels_min = 2,
- + .channels_max = 8,
- + .buffer_bytes_max = 64 * 1024,
- + .period_bytes_min = 256,
- + .period_bytes_max = 8192, /* ERR004323: must limit to 8k */
- + .periods_min = 2,
- + .periods_max = 16,
- + .fifo_size = 0,
- +};
- +
- +static unsigned rates_mask[] = {
- + SNDRV_PCM_RATE_32000,
- + SNDRV_PCM_RATE_44100,
- + SNDRV_PCM_RATE_48000,
- + SNDRV_PCM_RATE_88200,
- + SNDRV_PCM_RATE_96000,
- + SNDRV_PCM_RATE_176400,
- + SNDRV_PCM_RATE_192000,
- +};
- +
- +static void dw_hdmi_parse_eld(struct snd_dw_hdmi *dw,
- + struct snd_pcm_runtime *runtime)
- +{
- + u8 *sad, *eld = dw->data.eld;
- + unsigned eld_ver, mnl, sad_count, rates, rate_mask, i;
- + unsigned max_channels;
- +
- + eld_ver = eld[0] >> 3;
- + if (eld_ver != 2 && eld_ver != 31)
- + return;
- +
- + mnl = eld[4] & 0x1f;
- + if (mnl > 16)
- + return;
- +
- + sad_count = eld[5] >> 4;
- + sad = eld + 20 + mnl;
- +
- + /* Start from the basic audio settings */
- + max_channels = 2;
- + rates = 7;
- + while (sad_count > 0) {
- + switch (sad[0] & 0x78) {
- + case 0x08: /* PCM */
- + max_channels = max(max_channels, (sad[0] & 7) + 1u);
- + rates |= sad[1];
- + break;
- + }
- + sad += 3;
- + sad_count -= 1;
- + }
- +
- + for (rate_mask = i = 0; i < ARRAY_SIZE(rates_mask); i++)
- + if (rates & 1 << i)
- + rate_mask |= rates_mask[i];
- +
- + runtime->hw.rates &= rate_mask;
- + runtime->hw.channels_max = min(runtime->hw.channels_max, max_channels);
- +}
- +
- +static int dw_hdmi_open(struct snd_pcm_substream *substream)
- +{
- + struct snd_pcm_runtime *runtime = substream->runtime;
- + struct snd_dw_hdmi *dw = substream->private_data;
- + void __iomem *base = dw->data.base;
- + int ret;
- +
- + /* Clear FIFO */
- + writeb_relaxed(HDMI_AHB_DMA_CONF0_SW_FIFO_RST,
- + base + HDMI_AHB_DMA_CONF0);
- +
- + /* Configure interrupt polarities */
- + writeb_relaxed(~0, base + HDMI_AHB_DMA_POL);
- + writeb_relaxed(~0, base + HDMI_AHB_DMA_BUFFPOL);
- +
- + /* Keep interrupts masked, and clear any pending */
- + writeb_relaxed(~0, base + HDMI_AHB_DMA_MASK);
- + writeb_relaxed(~0, base + HDMI_IH_AHBDMAAUD_STAT0);
- +
- + ret = request_irq(dw->data.irq, snd_dw_hdmi_irq, IRQF_SHARED,
- + "dw-hdmi-audio", dw);
- + if (ret)
- + return ret;
- +
- + /* Un-mute done interrupt */
- + writeb_relaxed(HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL &
- + ~HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE,
- + base + HDMI_IH_MUTE_AHBDMAAUD_STAT0);
- +
- + runtime->hw = dw_hdmi_hw;
- + dw_hdmi_parse_eld(dw, runtime);
- + snd_pcm_limit_hw_rates(runtime);
- +
- + return 0;
- +}
- +
- +static int dw_hdmi_close(struct snd_pcm_substream *substream)
- +{
- + struct snd_dw_hdmi *dw = substream->private_data;
- +
- + /* Mute all interrupts */
- + writeb_relaxed(HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL,
- + dw->data.base + HDMI_IH_MUTE_AHBDMAAUD_STAT0);
- +
- + free_irq(dw->data.irq, dw);
- +
- + return 0;
- +}
- +
- +static int dw_hdmi_hw_free(struct snd_pcm_substream *substream)
- +{
- + return snd_pcm_lib_free_vmalloc_buffer(substream);
- +}
- +
- +static int dw_hdmi_hw_params(struct snd_pcm_substream *substream,
- + struct snd_pcm_hw_params *params)
- +{
- + return snd_pcm_lib_alloc_vmalloc_buffer(substream,
- + params_buffer_bytes(params));
- +}
- +
- +static int dw_hdmi_prepare(struct snd_pcm_substream *substream)
- +{
- + struct snd_pcm_runtime *runtime = substream->runtime;
- + struct snd_dw_hdmi *dw = substream->private_data;
- + uint8_t threshold, conf0, conf1;
- +
- + /* Setup as per 3.0.5 FSL 4.1.0 BSP */
- + switch (dw->revision) {
- + case 0x0a:
- + conf0 = HDMI_AHB_DMA_CONF0_BURST_MODE |
- + HDMI_AHB_DMA_CONF0_INCR4;
- + if (runtime->channels == 2)
- + threshold = 126;
- + else
- + threshold = 124;
- + break;
- + case 0x1a:
- + conf0 = HDMI_AHB_DMA_CONF0_BURST_MODE |
- + HDMI_AHB_DMA_CONF0_INCR8;
- + threshold = 128;
- + break;
- + default:
- + /* NOTREACHED */
- + return -EINVAL;
- + }
- +
- + dw->data.set_sample_rate(dw->data.hdmi, runtime->rate);
- +
- + /* Minimum number of bytes in the fifo. */
- + runtime->hw.fifo_size = threshold * 32;
- +
- + conf0 |= HDMI_AHB_DMA_CONF0_EN_HLOCK;
- + conf1 = (1 << runtime->channels) - 1;
- +
- + writeb_relaxed(threshold, dw->data.base + HDMI_AHB_DMA_THRSLD);
- + writeb_relaxed(conf0, dw->data.base + HDMI_AHB_DMA_CONF0);
- + writeb_relaxed(conf1, dw->data.base + HDMI_AHB_DMA_CONF1);
- +
- + switch (runtime->format) {
- + case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
- + dw->reformat = dw_hdmi_reformat_iec958;
- + break;
- + case SNDRV_PCM_FORMAT_S24_LE:
- + dw_hdmi_create_cs(dw, runtime);
- + dw->reformat = dw_hdmi_reformat_s24;
- + break;
- + }
- + dw->iec_offset = 0;
- + dw->channels = runtime->channels;
- + dw->buf_src = runtime->dma_area;
- + dw->buf_dst = substream->dma_buffer.area;
- + dw->buf_addr = substream->dma_buffer.addr;
- + dw->buf_period = snd_pcm_lib_period_bytes(substream);
- + dw->buf_size = snd_pcm_lib_buffer_bytes(substream);
- +
- + return 0;
- +}
- +
- +static int dw_hdmi_trigger(struct snd_pcm_substream *substream, int cmd)
- +{
- + struct snd_dw_hdmi *dw = substream->private_data;
- + void __iomem *base = dw->data.base;
- + unsigned n[3], cts[3];
- + int ret = 0, i;
- + bool err005174;
- +
- + switch (cmd) {
- + case SNDRV_PCM_TRIGGER_START:
- + err005174 = dw->revision == 0x0a;
- + if (err005174) {
- + for (i = 2; i >= 1; i--) {
- + n[i] = readb_relaxed(base + HDMI_AUD_N1 + i);
- + cts[i] = readb_relaxed(base + HDMI_AUD_CTS1 + i);
- + writeb_relaxed(0, base + HDMI_AUD_N1 + i);
- + writeb_relaxed(0, base + HDMI_AUD_CTS1 + i);
- + }
- + }
- +
- + dw->buf_offset = 0;
- + dw->substream = substream;
- + dw_hdmi_start_dma(dw);
- +
- + if (err005174) {
- + for (i = 2; i >= 1; i--)
- + writeb_relaxed(cts[i], base + HDMI_AUD_CTS1 + i);
- + for (i = 2; i >= 1; i--)
- + writeb_relaxed(n[i], base + HDMI_AUD_N1 + i);
- + }
- +
- + substream->runtime->delay = substream->runtime->period_size;
- + break;
- +
- + case SNDRV_PCM_TRIGGER_STOP:
- + dw_hdmi_stop_dma(dw);
- + break;
- +
- + default:
- + ret = -EINVAL;
- + break;
- + }
- +
- + return ret;
- +}
- +
- +static snd_pcm_uframes_t dw_hdmi_pointer(struct snd_pcm_substream *substream)
- +{
- + struct snd_pcm_runtime *runtime = substream->runtime;
- + struct snd_dw_hdmi *dw = substream->private_data;
- +
- + return bytes_to_frames(runtime, dw->buf_offset);
- +}
- +
- +static struct snd_pcm_ops snd_dw_hdmi_ops = {
- + .open = dw_hdmi_open,
- + .close = dw_hdmi_close,
- + .ioctl = snd_pcm_lib_ioctl,
- + .hw_params = dw_hdmi_hw_params,
- + .hw_free = dw_hdmi_hw_free,
- + .prepare = dw_hdmi_prepare,
- + .trigger = dw_hdmi_trigger,
- + .pointer = dw_hdmi_pointer,
- + .page = snd_pcm_lib_get_vmalloc_page,
- +};
- +
- +static int snd_dw_hdmi_probe(struct platform_device *pdev)
- +{
- + const struct dw_hdmi_audio_data *data = pdev->dev.platform_data;
- + struct device *dev = pdev->dev.parent;
- + struct snd_dw_hdmi *dw;
- + struct snd_card *card;
- + struct snd_pcm *pcm;
- + unsigned revision;
- + int ret;
- +
- + writeb_relaxed(HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL,
- + data->base + HDMI_IH_MUTE_AHBDMAAUD_STAT0);
- + revision = readb_relaxed(data->base + HDMI_REVISION_ID);
- + if (revision != 0x0a && revision != 0x1a) {
- + dev_err(dev, "dw-hdmi-audio: unknown revision 0x%02x\n",
- + revision);
- + return -ENXIO;
- + }
- +
- + ret = snd_card_new(dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
- + THIS_MODULE, sizeof(struct snd_dw_hdmi), &card);
- + if (ret < 0)
- + return ret;
- +
- + strlcpy(card->driver, DRIVER_NAME, sizeof(card->driver));
- + strlcpy(card->shortname, "DW-HDMI", sizeof(card->shortname));
- + snprintf(card->longname, sizeof(card->longname),
- + "%s rev 0x%02x, irq %d", card->shortname, revision,
- + data->irq);
- +
- + dw = card->private_data;
- + dw->card = card;
- + dw->data = *data;
- + dw->revision = revision;
- +
- + ret = snd_pcm_new(card, "DW HDMI", 0, 1, 0, &pcm);
- + if (ret < 0)
- + goto err;
- +
- + dw->pcm = pcm;
- + pcm->private_data = dw;
- + strlcpy(pcm->name, DRIVER_NAME, sizeof(pcm->name));
- + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_dw_hdmi_ops);
- +
- + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
- + dev, 64 * 1024, 64 * 1024);
- +
- + ret = snd_card_register(card);
- + if (ret < 0)
- + goto err;
- +
- + platform_set_drvdata(pdev, dw);
- +
- + return 0;
- +
- +err:
- + snd_card_free(card);
- + return ret;
- +}
- +
- +static int snd_dw_hdmi_remove(struct platform_device *pdev)
- +{
- + struct snd_dw_hdmi *dw = platform_get_drvdata(pdev);
- +
- + snd_card_free(dw->card);
- +
- + return 0;
- +}
- +
- +#ifdef CONFIG_PM_SLEEP
- +static int snd_dw_hdmi_suspend(struct device *dev)
- +{
- + struct snd_dw_hdmi *dw = dev_get_drvdata(dev);
- +
- + snd_power_change_state(dw->card, SNDRV_CTL_POWER_D3cold);
- + snd_pcm_suspend_all(dw->pcm);
- +
- + return 0;
- +}
- +
- +static int snd_dw_hdmi_resume(struct device *dev)
- +{
- + struct snd_dw_hdmi *dw = dev_get_drvdata(dev);
- +
- + snd_power_change_state(dw->card, SNDRV_CTL_POWER_D0);
- +
- + return 0;
- +}
- +
- +static SIMPLE_DEV_PM_OPS(snd_dw_hdmi_pm, snd_dw_hdmi_suspend,
- + snd_dw_hdmi_resume);
- +#define PM_OPS &snd_dw_hdmi_pm
- +#else
- +#define PM_OPS NULL
- +#endif
- +
- +static struct platform_driver snd_dw_hdmi_driver = {
- + .probe = snd_dw_hdmi_probe,
- + .remove = snd_dw_hdmi_remove,
- + .driver = {
- + .name = "dw-hdmi-audio",
- + .owner = THIS_MODULE,
- + .pm = PM_OPS,
- + },
- +};
- +
- +module_platform_driver(snd_dw_hdmi_driver);
- +
- +MODULE_AUTHOR("Russell King <rmk+kernel@arm.linux.org.uk>");
- +MODULE_LICENSE("GPL");
- diff --git a/drivers/staging/imx-drm/dw-hdmi-audio.h b/drivers/staging/imx-drm/dw-hdmi-audio.h
- new file mode 100644
- index 000000000000..2d91d709381d
- --- /dev/null
- +++ b/drivers/staging/imx-drm/dw-hdmi-audio.h
- @@ -0,0 +1,15 @@
- +#ifndef DW_HDMI_AUDIO_H
- +#define DW_HDMI_AUDIO_H
- +
- +struct imx_hdmi;
- +
- +struct dw_hdmi_audio_data {
- + phys_addr_t phys;
- + void __iomem *base;
- + int irq;
- + struct imx_hdmi *hdmi;
- + u8 *eld;
- + void (*set_sample_rate)(struct imx_hdmi *, unsigned);
- +};
- +
- +#endif
- diff --git a/drivers/staging/imx-drm/dw-hdmi-cec.c b/drivers/staging/imx-drm/dw-hdmi-cec.c
- new file mode 100644
- index 000000000000..c94b75aa037b
- --- /dev/null
- +++ b/drivers/staging/imx-drm/dw-hdmi-cec.c
- @@ -0,0 +1,205 @@
- +/* http://git.freescale.com/git/cgit.cgi/imx/linux-2.6-imx.git/tree/drivers/mxc/hdmi-cec/mxc_hdmi-cec.c?h=imx_3.0.35_4.1.0 */
- +#include <linux/cec-dev.h>
- +#include <linux/interrupt.h>
- +#include <linux/io.h>
- +#include <linux/module.h>
- +#include <linux/platform_device.h>
- +#include <linux/sched.h>
- +#include <linux/slab.h>
- +
- +#include "imx-hdmi.h"
- +#include "dw-hdmi-cec.h"
- +
- +#define DEV_NAME "mxc_hdmi_cec"
- +
- +enum {
- + CEC_STAT_DONE = BIT(0),
- + CEC_STAT_EOM = BIT(1),
- + CEC_STAT_NACK = BIT(2),
- + CEC_STAT_ARBLOST = BIT(3),
- + CEC_STAT_ERROR_INIT = BIT(4),
- + CEC_STAT_ERROR_FOLL = BIT(5),
- + CEC_STAT_WAKEUP = BIT(6),
- +
- + CEC_CTRL_START = BIT(0),
- + CEC_CTRL_NORMAL = 1 << 1,
- +};
- +
- +struct dw_hdmi_cec {
- + struct cec_dev cec;
- +
- + struct device *dev;
- + void __iomem *base;
- + const struct dw_hdmi_cec_ops *ops;
- + void *ops_data;
- + int irq;
- +};
- +
- +static void dw_hdmi_set_address(struct cec_dev *cec_dev, unsigned addresses)
- +{
- + struct dw_hdmi_cec *cec = container_of(cec_dev, struct dw_hdmi_cec, cec);
- +
- + writeb(addresses & 255, cec->base + HDMI_CEC_ADDR_L);
- + writeb(addresses >> 8, cec->base + HDMI_CEC_ADDR_H);
- +}
- +
- +static void dw_hdmi_send_message(struct cec_dev *cec_dev, u8 *msg,
- + size_t count)
- +{
- + struct dw_hdmi_cec *cec = container_of(cec_dev, struct dw_hdmi_cec, cec);
- + unsigned i;
- +
- + for (i = 0; i < count; i++)
- + writeb(msg[i], cec->base + HDMI_CEC_TX_DATA0 + i);
- +
- + writeb(count, cec->base + HDMI_CEC_TX_CNT);
- + writeb(CEC_CTRL_NORMAL | CEC_CTRL_START, cec->base + HDMI_CEC_CTRL);
- +}
- +
- +static irqreturn_t dw_hdmi_cec_irq(int irq, void *data)
- +{
- + struct dw_hdmi_cec *cec = data;
- + struct cec_dev *cec_dev = &cec->cec;
- + unsigned stat = readb(cec->base + HDMI_IH_CEC_STAT0);
- +
- + if (stat == 0)
- + return IRQ_NONE;
- +
- + writeb(stat, cec->base + HDMI_IH_CEC_STAT0);
- +
- + if (stat & CEC_STAT_ERROR_INIT) {
- + if (cec->cec.retries) {
- + unsigned v = readb(cec->base + HDMI_CEC_CTRL);
- + writeb(v | CEC_CTRL_START, cec->base + HDMI_CEC_CTRL);
- + cec->cec.retries -= 1;
- + } else {
- + cec->cec.write_busy = 0;
- + cec_dev_event(cec_dev, MESSAGE_TYPE_SEND_ERROR, NULL, 0);
- + }
- + } else if (stat & (CEC_STAT_DONE | CEC_STAT_NACK))
- + cec_dev_send_complete(cec_dev, stat & CEC_STAT_DONE);
- +
- + if (stat & CEC_STAT_EOM) {
- + unsigned len, i;
- + u8 msg[MAX_MESSAGE_LEN];
- +
- + len = readb(cec->base + HDMI_CEC_RX_CNT);
- + if (len > sizeof(msg))
- + len = sizeof(msg);
- +
- + for (i = 0; i < len; i++)
- + msg[i] = readb(cec->base + HDMI_CEC_RX_DATA0 + i);
- +
- + writeb(0, cec->base + HDMI_CEC_LOCK);
- +
- + cec_dev_receive(cec_dev, msg, len);
- + }
- +
- + return IRQ_HANDLED;
- +}
- +EXPORT_SYMBOL(dw_hdmi_cec_irq);
- +
- +static void dw_hdmi_cec_release(struct cec_dev *cec_dev)
- +{
- + struct dw_hdmi_cec *cec = container_of(cec_dev, struct dw_hdmi_cec, cec);
- +
- + writeb(~0, cec->base + HDMI_CEC_MASK);
- + writeb(~0, cec->base + HDMI_IH_MUTE_CEC_STAT0);
- + writeb(0, cec->base + HDMI_CEC_POLARITY);
- +
- + free_irq(cec->irq, cec);
- +
- + cec->ops->disable(cec->ops_data);
- +}
- +
- +static int dw_hdmi_cec_open(struct cec_dev *cec_dev)
- +{
- + struct dw_hdmi_cec *cec = container_of(cec_dev, struct dw_hdmi_cec, cec);
- + unsigned irqs;
- + int ret;
- +
- + writeb(0, cec->base + HDMI_CEC_CTRL);
- + writeb(~0, cec->base + HDMI_IH_CEC_STAT0);
- + writeb(0, cec->base + HDMI_CEC_LOCK);
- +
- + ret = request_irq(cec->irq, dw_hdmi_cec_irq, IRQF_SHARED,
- + DEV_NAME, cec);
- + if (ret < 0)
- + return ret;
- +
- + dw_hdmi_set_address(cec_dev, cec_dev->addresses);
- +
- + cec->ops->enable(cec->ops_data);
- +
- + irqs = CEC_STAT_ERROR_INIT | CEC_STAT_NACK | CEC_STAT_EOM |
- + CEC_STAT_DONE;
- + writeb(irqs, cec->base + HDMI_CEC_POLARITY);
- + writeb(~irqs, cec->base + HDMI_CEC_MASK);
- + writeb(~irqs, cec->base + HDMI_IH_MUTE_CEC_STAT0);
- +
- + return 0;
- +}
- +
- +static int dw_hdmi_cec_probe(struct platform_device *pdev)
- +{
- + struct dw_hdmi_cec_data *data = dev_get_platdata(&pdev->dev);
- + struct dw_hdmi_cec *cec;
- +
- + if (!data)
- + return -ENXIO;
- +
- + cec = devm_kzalloc(&pdev->dev, sizeof(*cec), GFP_KERNEL);
- + if (!cec)
- + return -ENOMEM;
- +
- + cec->dev = &pdev->dev;
- + cec->base = data->base;
- + cec->irq = data->irq;
- + cec->ops = data->ops;
- + cec->ops_data = data->ops_data;
- + cec->cec.open = dw_hdmi_cec_open;
- + cec->cec.release = dw_hdmi_cec_release;
- + cec->cec.send_message = dw_hdmi_send_message;
- + cec->cec.set_address = dw_hdmi_set_address;
- +
- + cec_dev_init(&cec->cec, THIS_MODULE);
- +
- + /* FIXME: soft-reset the CEC interface */
- +
- + dw_hdmi_set_address(&cec->cec, cec->cec.addresses);
- + writeb(0, cec->base + HDMI_CEC_TX_CNT);
- + writeb(~0, cec->base + HDMI_CEC_MASK);
- + writeb(~0, cec->base + HDMI_IH_MUTE_CEC_STAT0);
- + writeb(0, cec->base + HDMI_CEC_POLARITY);
- +
- + /*
- + * Our device is just a convenience - we want to link to the real
- + * hardware device here, so that userspace can see the association
- + * between the HDMI hardware and its associated CEC chardev.
- + */
- + return cec_dev_add(&cec->cec, cec->dev->parent, DEV_NAME);
- +}
- +
- +static int dw_hdmi_cec_remove(struct platform_device *pdev)
- +{
- + struct dw_hdmi_cec *cec = platform_get_drvdata(pdev);
- +
- + cec_dev_remove(&cec->cec);
- +
- + return 0;
- +}
- +
- +static struct platform_driver dw_hdmi_cec_driver = {
- + .probe = dw_hdmi_cec_probe,
- + .remove = dw_hdmi_cec_remove,
- + .driver = {
- + .name = "dw-hdmi-cec",
- + .owner = THIS_MODULE,
- + },
- +};
- +module_platform_driver(dw_hdmi_cec_driver);
- +
- +MODULE_AUTHOR("Russell King <rmk+kernel@arm.linux.org.uk>");
- +MODULE_DESCRIPTION("Synopsis Designware HDMI CEC driver for i.MX");
- +MODULE_LICENSE("GPL");
- +MODULE_ALIAS(PLATFORM_MODULE_PREFIX "dw-hdmi-cec");
- diff --git a/drivers/staging/imx-drm/dw-hdmi-cec.h b/drivers/staging/imx-drm/dw-hdmi-cec.h
- new file mode 100644
- index 000000000000..5ff40cc237a8
- --- /dev/null
- +++ b/drivers/staging/imx-drm/dw-hdmi-cec.h
- @@ -0,0 +1,16 @@
- +#ifndef DW_HDMI_CEC_H
- +#define DW_HDMI_CEC_H
- +
- +struct dw_hdmi_cec_ops {
- + void (*enable)(void *);
- + void (*disable)(void *);
- +};
- +
- +struct dw_hdmi_cec_data {
- + void __iomem *base;
- + int irq;
- + const struct dw_hdmi_cec_ops *ops;
- + void *ops_data;
- +};
- +
- +#endif
- diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
- index d47dedd2cdb4..627b4b608794 100644
- --- a/drivers/staging/imx-drm/imx-hdmi.c
- +++ b/drivers/staging/imx-drm/imx-hdmi.c
- @@ -28,6 +28,9 @@
- #include <drm/drm_edid.h>
- #include <drm/drm_encoder_slave.h>
-
- +#include "drm-ddc-connector.h"
- +#include "dw-hdmi-audio.h"
- +#include "dw-hdmi-cec.h"
- #include "ipu-v3/imx-ipu-v3.h"
- #include "imx-hdmi.h"
- #include "imx-drm.h"
- @@ -112,27 +115,27 @@ struct hdmi_data_info {
- };
-
- struct imx_hdmi {
- - struct drm_connector connector;
- + struct drm_ddc_connector *ddc_conn;
- struct drm_encoder encoder;
-
- + struct platform_device *audio;
- + struct platform_device *cec;
- enum imx_hdmi_devtype dev_type;
- struct device *dev;
- struct clk *isfr_clk;
- struct clk *iahb_clk;
-
- - enum drm_connector_status connector_status;
- -
- struct hdmi_data_info hdmi_data;
- int vic;
-
- u8 edid[HDMI_EDID_LEN];
- + u8 mc_clkdis;
- bool cable_plugin;
-
- bool phy_enabled;
- struct drm_display_mode previous_mode;
-
- struct regmap *regmap;
- - struct i2c_adapter *ddc;
- void __iomem *regs;
-
- unsigned int sample_rate;
- @@ -362,6 +365,12 @@ static void hdmi_clk_regenerator_update_pixel_clock(struct imx_hdmi *hdmi)
- hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock);
- }
-
- +static void imx_hdmi_set_sample_rate(struct imx_hdmi *hdmi, unsigned rate)
- +{
- + hdmi->sample_rate = rate;
- + hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock);
- +}
- +
- /*
- * this submodule is responsible for the video data synchronization.
- * for example, for RGB 4:4:4 input, the data map is defined as
- @@ -1148,8 +1157,6 @@ static void imx_hdmi_phy_disable(struct imx_hdmi *hdmi)
- /* HDMI Initialization Step B.4 */
- static void imx_hdmi_enable_video_path(struct imx_hdmi *hdmi)
- {
- - u8 clkdis;
- -
- /* control period minimum duration */
- hdmi_writeb(hdmi, 12, HDMI_FC_CTRLDUR);
- hdmi_writeb(hdmi, 32, HDMI_FC_EXCTRLDUR);
- @@ -1161,23 +1168,28 @@ static void imx_hdmi_enable_video_path(struct imx_hdmi *hdmi)
- hdmi_writeb(hdmi, 0x21, HDMI_FC_CH2PREAM);
-
- /* Enable pixel clock and tmds data path */
- - clkdis = 0x7F;
- - clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE;
- - hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
- + hdmi->mc_clkdis |= HDMI_MC_CLKDIS_HDCPCLK_DISABLE |
- + HDMI_MC_CLKDIS_CSCCLK_DISABLE |
- + HDMI_MC_CLKDIS_AUDCLK_DISABLE |
- + HDMI_MC_CLKDIS_PREPCLK_DISABLE |
- + HDMI_MC_CLKDIS_TMDSCLK_DISABLE;
- + hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE;
- + hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS);
-
- - clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE;
- - hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
- + hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE;
- + hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS);
-
- /* Enable csc path */
- if (is_color_space_conversion(hdmi)) {
- - clkdis &= ~HDMI_MC_CLKDIS_CSCCLK_DISABLE;
- - hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
- + hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_CSCCLK_DISABLE;
- + hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS);
- }
- }
-
- static void hdmi_enable_audio_clk(struct imx_hdmi *hdmi)
- {
- - hdmi_modb(hdmi, 0, HDMI_MC_CLKDIS_AUDCLK_DISABLE, HDMI_MC_CLKDIS);
- + hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_AUDCLK_DISABLE;
- + hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS);
- }
-
- /* Workaround to clear the overflow condition */
- @@ -1380,41 +1392,16 @@ static void imx_hdmi_poweroff(struct imx_hdmi *hdmi)
- static enum drm_connector_status imx_hdmi_connector_detect(struct drm_connector
- *connector, bool force)
- {
- - struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
- - connector);
- - return hdmi->connector_status;
- -}
- -
- -static int imx_hdmi_connector_get_modes(struct drm_connector *connector)
- -{
- - struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
- - connector);
- - struct edid *edid;
- - int ret;
- -
- - if (!hdmi->ddc)
- - return 0;
- -
- - edid = drm_get_edid(connector, hdmi->ddc);
- - if (edid) {
- - dev_dbg(hdmi->dev, "got edid: width[%d] x height[%d]\n",
- - edid->width_cm, edid->height_cm);
- -
- - drm_mode_connector_update_edid_property(connector, edid);
- - ret = drm_add_edid_modes(connector, edid);
- - kfree(edid);
- - } else {
- - dev_dbg(hdmi->dev, "failed to get edid\n");
- - }
- + struct imx_hdmi *hdmi = drm_ddc_private(connector);
-
- - return 0;
- + return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ?
- + connector_status_connected : connector_status_disconnected;
- }
-
- static struct drm_encoder *imx_hdmi_connector_best_encoder(struct drm_connector
- *connector)
- {
- - struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
- - connector);
- + struct imx_hdmi *hdmi = drm_ddc_private(connector);
-
- return &hdmi->encoder;
- }
- @@ -1483,15 +1470,8 @@ static struct drm_encoder_helper_funcs imx_hdmi_encoder_helper_funcs = {
- .disable = imx_hdmi_encoder_disable,
- };
-
- -static struct drm_connector_funcs imx_hdmi_connector_funcs = {
- - .dpms = drm_helper_connector_dpms,
- - .fill_modes = drm_helper_probe_single_connector_modes,
- - .detect = imx_hdmi_connector_detect,
- - .destroy = imx_drm_connector_destroy,
- -};
- -
- static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = {
- - .get_modes = imx_hdmi_connector_get_modes,
- + .get_modes = drm_ddc_connector_get_modes,
- .mode_valid = imx_drm_connector_mode_valid,
- .best_encoder = imx_hdmi_connector_best_encoder,
- };
- @@ -1524,7 +1504,6 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
-
- hdmi_modb(hdmi, 0, HDMI_PHY_HPD, HDMI_PHY_POL0);
-
- - hdmi->connector_status = connector_status_connected;
- imx_hdmi_poweron(hdmi);
- } else {
- dev_dbg(hdmi->dev, "EVENT=plugout\n");
- @@ -1532,10 +1511,9 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
- hdmi_modb(hdmi, HDMI_PHY_HPD, HDMI_PHY_HPD,
- HDMI_PHY_POL0);
-
- - hdmi->connector_status = connector_status_disconnected;
- imx_hdmi_poweroff(hdmi);
- }
- - drm_helper_hpd_irq_event(hdmi->connector.dev);
- + drm_helper_hpd_irq_event(hdmi->ddc_conn->connector.dev);
- }
-
- hdmi_writeb(hdmi, intr_stat, HDMI_IH_PHY_STAT0);
- @@ -1553,24 +1531,42 @@ static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
- if (ret)
- return ret;
-
- - hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
- + hdmi->ddc_conn->connector.polled = DRM_CONNECTOR_POLL_HPD;
-
- drm_encoder_helper_add(&hdmi->encoder, &imx_hdmi_encoder_helper_funcs);
- drm_encoder_init(drm, &hdmi->encoder, &imx_hdmi_encoder_funcs,
- DRM_MODE_ENCODER_TMDS);
-
- - drm_connector_helper_add(&hdmi->connector,
- + drm_connector_helper_add(&hdmi->ddc_conn->connector,
- &imx_hdmi_connector_helper_funcs);
- - drm_connector_init(drm, &hdmi->connector, &imx_hdmi_connector_funcs,
- - DRM_MODE_CONNECTOR_HDMIA);
- -
- - hdmi->connector.encoder = &hdmi->encoder;
- + drm_ddc_connector_add(drm, hdmi->ddc_conn, DRM_MODE_CONNECTOR_HDMIA);
-
- - drm_mode_connector_attach_encoder(&hdmi->connector, &hdmi->encoder);
- + drm_mode_connector_attach_encoder(&hdmi->ddc_conn->connector, &hdmi->encoder);
-
- return 0;
- }
-
- +static void imx_hdmi_cec_enable(void *data)
- +{
- + struct imx_hdmi *hdmi = data;
- +
- + hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_CECCLK_DISABLE;
- + hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS);
- +}
- +
- +static void imx_hdmi_cec_disable(void *data)
- +{
- + struct imx_hdmi *hdmi = data;
- +
- + hdmi->mc_clkdis |= HDMI_MC_CLKDIS_CECCLK_DISABLE;
- + hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS);
- +}
- +
- +static const struct dw_hdmi_cec_ops imx_hdmi_cec_ops = {
- + .enable = imx_hdmi_cec_enable,
- + .disable = imx_hdmi_cec_disable,
- +};
- +
- static struct platform_device_id imx_hdmi_devtype[] = {
- {
- .name = "imx6q-hdmi",
- @@ -1592,11 +1588,13 @@ MODULE_DEVICE_TABLE(of, imx_hdmi_dt_ids);
- static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
- {
- struct platform_device *pdev = to_platform_device(dev);
- + struct platform_device_info pdevinfo;
- const struct of_device_id *of_id =
- of_match_device(imx_hdmi_dt_ids, dev);
- struct drm_device *drm = data;
- struct device_node *np = dev->of_node;
- - struct device_node *ddc_node;
- + struct dw_hdmi_audio_data audio;
- + struct dw_hdmi_cec_data cec;
- struct imx_hdmi *hdmi;
- struct resource *iores;
- int ret, irq;
- @@ -1605,27 +1603,22 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
- if (!hdmi)
- return -ENOMEM;
-
- + hdmi->ddc_conn = drm_ddc_connector_create(drm, np, hdmi);
- + if (IS_ERR(hdmi->ddc_conn))
- + return PTR_ERR(hdmi->ddc_conn);
- +
- + hdmi->ddc_conn->detect = imx_hdmi_connector_detect;
- +
- hdmi->dev = dev;
- - hdmi->connector_status = connector_status_disconnected;
- hdmi->sample_rate = 48000;
- hdmi->ratio = 100;
- + hdmi->mc_clkdis = 0x7f;
-
- if (of_id) {
- const struct platform_device_id *device_id = of_id->data;
- hdmi->dev_type = device_id->driver_data;
- }
-
- - ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
- - if (ddc_node) {
- - hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node);
- - if (!hdmi->ddc)
- - dev_dbg(hdmi->dev, "failed to read ddc node\n");
- -
- - of_node_put(ddc_node);
- - } else {
- - dev_dbg(hdmi->dev, "no ddc property found\n");
- - }
- -
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return -EINVAL;
- @@ -1711,6 +1704,35 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
- /* Unmute interrupts */
- hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
-
- + memset(&pdevinfo, 0, sizeof(pdevinfo));
- + pdevinfo.parent = dev;
- + pdevinfo.id = PLATFORM_DEVID_AUTO;
- +
- + audio.phys = iores->start;
- + audio.base = hdmi->regs;
- + audio.irq = irq;
- + audio.hdmi = hdmi;
- + audio.eld = hdmi->ddc_conn->connector.eld;
- + audio.set_sample_rate = imx_hdmi_set_sample_rate;
- +
- + pdevinfo.name = "dw-hdmi-audio";
- + pdevinfo.data = &audio;
- + pdevinfo.size_data = sizeof(audio);
- + pdevinfo.dma_mask = DMA_BIT_MASK(32);
- + hdmi->audio = platform_device_register_full(&pdevinfo);
- +
- + cec.base = hdmi->regs;
- + cec.irq = irq;
- + cec.ops = &imx_hdmi_cec_ops;
- + cec.ops_data = hdmi;
- +
- + pdevinfo.name = "dw-hdmi-cec";
- + pdevinfo.data = &cec;
- + pdevinfo.size_data = sizeof(cec);
- + pdevinfo.dma_mask = 0;
- +
- + hdmi->cec = platform_device_register_full(&pdevinfo);
- +
- dev_set_drvdata(dev, hdmi);
-
- return 0;
- @@ -1728,15 +1750,19 @@ static void imx_hdmi_unbind(struct device *dev, struct device *master,
- {
- struct imx_hdmi *hdmi = dev_get_drvdata(dev);
-
- + if (!IS_ERR(hdmi->audio))
- + platform_device_unregister(hdmi->audio);
- + if (!IS_ERR(hdmi->cec))
- + platform_device_unregister(hdmi->cec);
- +
- /* Disable all interrupts */
- hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
-
- - hdmi->connector.funcs->destroy(&hdmi->connector);
- + hdmi->ddc_conn->connector.funcs->destroy(&hdmi->ddc_conn->connector);
- hdmi->encoder.funcs->destroy(&hdmi->encoder);
-
- clk_disable_unprepare(hdmi->iahb_clk);
- clk_disable_unprepare(hdmi->isfr_clk);
- - i2c_put_adapter(hdmi->ddc);
- }
-
- static const struct component_ops hdmi_ops = {
- diff --git a/drivers/staging/imx-drm/imx-ldb.c b/drivers/staging/imx-drm/imx-ldb.c
- index fe4c1ef4e7a5..3a3bacec2e11 100644
- --- a/drivers/staging/imx-drm/imx-ldb.c
- +++ b/drivers/staging/imx-drm/imx-ldb.c
- @@ -24,6 +24,7 @@
- #include <drm/drmP.h>
- #include <drm/drm_fb_helper.h>
- #include <drm/drm_crtc_helper.h>
- +#include <drm/drm_panel.h>
- #include <linux/mfd/syscon.h>
- #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
- #include <linux/of_address.h>
- @@ -60,6 +61,7 @@ struct imx_ldb_channel {
- struct imx_ldb *ldb;
- struct drm_connector connector;
- struct drm_encoder encoder;
- + struct drm_panel *panel;
- struct device_node *child;
- int chno;
- void *edid;
- @@ -96,6 +98,13 @@ static int imx_ldb_connector_get_modes(struct drm_connector *connector)
- struct imx_ldb_channel *imx_ldb_ch = con_to_imx_ldb_ch(connector);
- int num_modes = 0;
-
- + if (imx_ldb_ch->panel && imx_ldb_ch->panel->funcs &&
- + imx_ldb_ch->panel->funcs->get_modes) {
- + num_modes = imx_ldb_ch->panel->funcs->get_modes(imx_ldb_ch->panel);
- + if (num_modes > 0)
- + return num_modes;
- + }
- +
- if (imx_ldb_ch->edid) {
- drm_mode_connector_update_edid_property(connector,
- imx_ldb_ch->edid);
- @@ -243,6 +252,8 @@ static void imx_ldb_encoder_commit(struct drm_encoder *encoder)
- }
-
- regmap_write(ldb->regmap, IOMUXC_GPR2, ldb->ldb_ctrl);
- +
- + drm_panel_enable(imx_ldb_ch->panel);
- }
-
- static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder,
- @@ -294,6 +305,8 @@ static void imx_ldb_encoder_disable(struct drm_encoder *encoder)
- (ldb->ldb_ctrl & LDB_CH1_MODE_EN_MASK) == 0)
- return;
-
- + drm_panel_disable(imx_ldb_ch->panel);
- +
- if (imx_ldb_ch == &ldb->channel[0])
- ldb->ldb_ctrl &= ~LDB_CH0_MODE_EN_MASK;
- else if (imx_ldb_ch == &ldb->channel[1])
- @@ -379,6 +392,9 @@ static int imx_ldb_register(struct drm_device *drm,
- drm_connector_init(drm, &imx_ldb_ch->connector,
- &imx_ldb_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
-
- + if (imx_ldb_ch->panel)
- + drm_panel_attach(imx_ldb_ch->panel, &imx_ldb_ch->connector);
- +
- drm_mode_connector_attach_encoder(&imx_ldb_ch->connector,
- &imx_ldb_ch->encoder);
-
- @@ -493,6 +509,7 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
-
- for_each_child_of_node(np, child) {
- struct imx_ldb_channel *channel;
- + struct device_node *panel_node;
-
- ret = of_property_read_u32(child, "reg", &i);
- if (ret || i < 0 || i > 1)
- @@ -556,6 +573,10 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
- return -EINVAL;
- }
-
- + panel_node = of_parse_phandle(child, "fsl,panel", 0);
- + if (panel_node)
- + channel->panel = of_drm_find_panel(panel_node);
- +
- ret = imx_ldb_register(drm, channel);
- if (ret)
- return ret;
- diff --git a/drivers/staging/imx-drm/imx-tve.c b/drivers/staging/imx-drm/imx-tve.c
- index a23f4f773146..6eafba5072ad 100644
- --- a/drivers/staging/imx-drm/imx-tve.c
- +++ b/drivers/staging/imx-drm/imx-tve.c
- @@ -22,7 +22,6 @@
- #include <linux/clk-provider.h>
- #include <linux/component.h>
- #include <linux/module.h>
- -#include <linux/i2c.h>
- #include <linux/regmap.h>
- #include <linux/regulator/consumer.h>
- #include <linux/spinlock.h>
- @@ -31,6 +30,7 @@
- #include <drm/drm_fb_helper.h>
- #include <drm/drm_crtc_helper.h>
-
- +#include "drm-ddc-connector.h"
- #include "ipu-v3/imx-ipu-v3.h"
- #include "imx-drm.h"
-
- @@ -111,7 +111,7 @@ enum {
- };
-
- struct imx_tve {
- - struct drm_connector connector;
- + struct drm_ddc_connector *ddc_conn;
- struct drm_encoder encoder;
- struct device *dev;
- spinlock_t lock; /* register lock */
- @@ -120,7 +120,6 @@ struct imx_tve {
-
- struct regmap *regmap;
- struct regulator *dac_reg;
- - struct i2c_adapter *ddc;
- struct clk *clk;
- struct clk *di_sel_clk;
- struct clk_hw clk_hw_di;
- @@ -219,35 +218,10 @@ static int tve_setup_vga(struct imx_tve *tve)
- return 0;
- }
-
- -static enum drm_connector_status imx_tve_connector_detect(
- - struct drm_connector *connector, bool force)
- -{
- - return connector_status_connected;
- -}
- -
- -static int imx_tve_connector_get_modes(struct drm_connector *connector)
- -{
- - struct imx_tve *tve = con_to_tve(connector);
- - struct edid *edid;
- - int ret = 0;
- -
- - if (!tve->ddc)
- - return 0;
- -
- - edid = drm_get_edid(connector, tve->ddc);
- - if (edid) {
- - drm_mode_connector_update_edid_property(connector, edid);
- - ret = drm_add_edid_modes(connector, edid);
- - kfree(edid);
- - }
- -
- - return ret;
- -}
- -
- static int imx_tve_connector_mode_valid(struct drm_connector *connector,
- struct drm_display_mode *mode)
- {
- - struct imx_tve *tve = con_to_tve(connector);
- + struct imx_tve *tve = to_ddc_conn(connector)->private;
- unsigned long rate;
- int ret;
-
- @@ -274,7 +248,7 @@ static int imx_tve_connector_mode_valid(struct drm_connector *connector,
- static struct drm_encoder *imx_tve_connector_best_encoder(
- struct drm_connector *connector)
- {
- - struct imx_tve *tve = con_to_tve(connector);
- + struct imx_tve *tve = drm_ddc_private(connector);
-
- return &tve->encoder;
- }
- @@ -362,15 +336,8 @@ static void imx_tve_encoder_disable(struct drm_encoder *encoder)
- tve_disable(tve);
- }
-
- -static struct drm_connector_funcs imx_tve_connector_funcs = {
- - .dpms = drm_helper_connector_dpms,
- - .fill_modes = drm_helper_probe_single_connector_modes,
- - .detect = imx_tve_connector_detect,
- - .destroy = imx_drm_connector_destroy,
- -};
- -
- static struct drm_connector_helper_funcs imx_tve_connector_helper_funcs = {
- - .get_modes = imx_tve_connector_get_modes,
- + .get_modes = drm_ddc_connector_get_modes,
- .best_encoder = imx_tve_connector_best_encoder,
- .mode_valid = imx_tve_connector_mode_valid,
- };
- @@ -513,12 +480,11 @@ static int imx_tve_register(struct drm_device *drm, struct imx_tve *tve)
- drm_encoder_init(drm, &tve->encoder, &imx_tve_encoder_funcs,
- encoder_type);
-
- - drm_connector_helper_add(&tve->connector,
- + drm_connector_helper_add(&tve->ddc_conn->connector,
- &imx_tve_connector_helper_funcs);
- - drm_connector_init(drm, &tve->connector, &imx_tve_connector_funcs,
- - DRM_MODE_CONNECTOR_VGA);
- + drm_ddc_connector_add(drm, tve->ddc_conn, DRM_MODE_CONNECTOR_VGA);
-
- - drm_mode_connector_attach_encoder(&tve->connector, &tve->encoder);
- + drm_mode_connector_attach_encoder(&tve->ddc_conn->connector, &tve->encoder);
-
- return 0;
- }
- @@ -567,7 +533,6 @@ static int imx_tve_bind(struct device *dev, struct device *master, void *data)
- struct platform_device *pdev = to_platform_device(dev);
- struct drm_device *drm = data;
- struct device_node *np = dev->of_node;
- - struct device_node *ddc_node;
- struct imx_tve *tve;
- struct resource *res;
- void __iomem *base;
- @@ -579,15 +544,13 @@ static int imx_tve_bind(struct device *dev, struct device *master, void *data)
- if (!tve)
- return -ENOMEM;
-
- + tve->ddc_conn = drm_ddc_connector_create(drm, np, tve);
- + if (IS_ERR(tve->ddc_conn))
- + return PTR_ERR(tve->ddc_conn);
- +
- tve->dev = dev;
- spin_lock_init(&tve->lock);
-
- - ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
- - if (ddc_node) {
- - tve->ddc = of_find_i2c_adapter_by_node(ddc_node);
- - of_node_put(ddc_node);
- - }
- -
- tve->mode = of_get_tve_mode(np);
- if (tve->mode != TVE_MODE_VGA) {
- dev_err(dev, "only VGA mode supported, currently\n");
- @@ -694,7 +657,7 @@ static void imx_tve_unbind(struct device *dev, struct device *master,
- {
- struct imx_tve *tve = dev_get_drvdata(dev);
-
- - tve->connector.funcs->destroy(&tve->connector);
- + tve->ddc_conn->connector.funcs->destroy(&tve->ddc_conn->connector);
- tve->encoder.funcs->destroy(&tve->encoder);
-
- if (!IS_ERR(tve->dac_reg))
- diff --git a/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h b/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h
- index c4d14ead5837..c2c6fab05eaa 100644
- --- a/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h
- +++ b/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h
- @@ -76,6 +76,7 @@ enum ipu_channel_irq {
- IPU_IRQ_EOS = 192,
- };
-
- +int ipu_map_irq(struct ipu_soc *ipu, int irq);
- int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel,
- enum ipu_channel_irq irq);
-
- @@ -114,8 +115,10 @@ struct ipu_dc *ipu_dc_get(struct ipu_soc *ipu, int channel);
- void ipu_dc_put(struct ipu_dc *dc);
- int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced,
- u32 pixel_fmt, u32 width);
- +void ipu_dc_enable(struct ipu_soc *ipu);
- void ipu_dc_enable_channel(struct ipu_dc *dc);
- void ipu_dc_disable_channel(struct ipu_dc *dc);
- +void ipu_dc_disable(struct ipu_soc *ipu);
-
- /*
- * IPU Display Interface (di) functions
- @@ -152,8 +155,10 @@ void ipu_dmfc_put(struct dmfc_channel *dmfc);
-
- struct ipu_dp *ipu_dp_get(struct ipu_soc *ipu, unsigned int flow);
- void ipu_dp_put(struct ipu_dp *);
- +int ipu_dp_enable(struct ipu_soc *ipu);
- int ipu_dp_enable_channel(struct ipu_dp *dp);
- void ipu_dp_disable_channel(struct ipu_dp *dp);
- +void ipu_dp_disable(struct ipu_soc *ipu);
- int ipu_dp_setup_channel(struct ipu_dp *dp,
- enum ipu_color_space in, enum ipu_color_space out);
- int ipu_dp_set_window_pos(struct ipu_dp *, u16 x_pos, u16 y_pos);
- diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
- index ca85d3d70ae3..8fb4c207f3f1 100644
- --- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c
- +++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
- @@ -697,6 +697,12 @@ int ipu_idmac_enable_channel(struct ipuv3_channel *channel)
- }
- EXPORT_SYMBOL_GPL(ipu_idmac_enable_channel);
-
- +bool ipu_idmac_channel_busy(struct ipu_soc *ipu, unsigned int chno)
- +{
- + return (ipu_idmac_read(ipu, IDMAC_CHA_BUSY(chno)) & idma_mask(chno));
- +}
- +EXPORT_SYMBOL_GPL(ipu_idmac_channel_busy);
- +
- int ipu_idmac_wait_busy(struct ipuv3_channel *channel, int ms)
- {
- struct ipu_soc *ipu = channel->ipu;
- @@ -714,6 +720,22 @@ int ipu_idmac_wait_busy(struct ipuv3_channel *channel, int ms)
- }
- EXPORT_SYMBOL_GPL(ipu_idmac_wait_busy);
-
- +int ipu_wait_interrupt(struct ipu_soc *ipu, int irq, int ms)
- +{
- + unsigned long timeout;
- +
- + timeout = jiffies + msecs_to_jiffies(ms);
- + ipu_cm_write(ipu, BIT(irq % 32), IPU_INT_STAT(irq / 32));
- + while (!(ipu_cm_read(ipu, IPU_INT_STAT(irq / 32) & BIT(irq % 32)))) {
- + if (time_after(jiffies, timeout))
- + return -ETIMEDOUT;
- + cpu_relax();
- + }
- +
- + return 0;
- +}
- +EXPORT_SYMBOL_GPL(ipu_wait_interrupt);
- +
- int ipu_idmac_disable_channel(struct ipuv3_channel *channel)
- {
- struct ipu_soc *ipu = channel->ipu;
- @@ -933,15 +955,22 @@ static void ipu_err_irq_handler(unsigned int irq, struct irq_desc *desc)
- chained_irq_exit(chip, desc);
- }
-
- -int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel,
- - enum ipu_channel_irq irq_type)
- +int ipu_map_irq(struct ipu_soc *ipu, int irq)
- {
- - int irq = irq_linear_revmap(ipu->domain, irq_type + channel->num);
- + int virq;
-
- - if (!irq)
- - irq = irq_create_mapping(ipu->domain, irq_type + channel->num);
- + virq = irq_linear_revmap(ipu->domain, irq);
- + if (!virq)
- + virq = irq_create_mapping(ipu->domain, irq);
-
- - return irq;
- + return virq;
- +}
- +EXPORT_SYMBOL_GPL(ipu_map_irq);
- +
- +int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel,
- + enum ipu_channel_irq irq_type)
- +{
- + return ipu_map_irq(ipu, irq_type + channel->num);
- }
- EXPORT_SYMBOL_GPL(ipu_idmac_channel_irq);
-
- diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dc.c b/drivers/staging/imx-drm/ipu-v3/ipu-dc.c
- index d5de8bb5c803..97cf6fad2427 100644
- --- a/drivers/staging/imx-drm/ipu-v3/ipu-dc.c
- +++ b/drivers/staging/imx-drm/ipu-v3/ipu-dc.c
- @@ -18,6 +18,7 @@
- #include <linux/types.h>
- #include <linux/errno.h>
- #include <linux/delay.h>
- +#include <linux/interrupt.h>
- #include <linux/io.h>
-
- #include "../imx-drm.h"
- @@ -92,6 +93,7 @@ enum ipu_dc_map {
- IPU_DC_MAP_GBR24, /* TVEv2 */
- IPU_DC_MAP_BGR666,
- IPU_DC_MAP_BGR24,
- + IPU_DC_MAP_RGB666,
- };
-
- struct ipu_dc {
- @@ -110,6 +112,9 @@ struct ipu_dc_priv {
- struct device *dev;
- struct ipu_dc channels[IPU_DC_NUM_CHANNELS];
- struct mutex mutex;
- + struct completion comp;
- + int dc_irq;
- + int dp_irq;
- };
-
- static void dc_link_event(struct ipu_dc *dc, int event, int addr, int priority)
- @@ -155,6 +160,8 @@ static int ipu_pixfmt_to_map(u32 fmt)
- return IPU_DC_MAP_BGR666;
- case V4L2_PIX_FMT_BGR24:
- return IPU_DC_MAP_BGR24;
- + case V4L2_PIX_FMT_RGB666:
- + return IPU_DC_MAP_RGB666;
- default:
- return -EINVAL;
- }
- @@ -220,12 +227,16 @@ int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced,
- writel(0x0, dc->base + DC_WR_CH_ADDR);
- writel(width, priv->dc_reg + DC_DISP_CONF2(dc->di));
-
- - ipu_module_enable(priv->ipu, IPU_CONF_DC_EN);
- -
- return 0;
- }
- EXPORT_SYMBOL_GPL(ipu_dc_init_sync);
-
- +void ipu_dc_enable(struct ipu_soc *ipu)
- +{
- + ipu_module_enable(ipu, IPU_CONF_DC_EN);
- +}
- +EXPORT_SYMBOL_GPL(ipu_dc_enable);
- +
- void ipu_dc_enable_channel(struct ipu_dc *dc)
- {
- int di;
- @@ -239,41 +250,55 @@ void ipu_dc_enable_channel(struct ipu_dc *dc)
- }
- EXPORT_SYMBOL_GPL(ipu_dc_enable_channel);
-
- +static irqreturn_t dc_irq_handler(int irq, void *dev_id)
- +{
- + struct ipu_dc *dc = dev_id;
- + u32 reg;
- +
- + reg = readl(dc->base + DC_WR_CH_CONF);
- + reg &= ~DC_WR_CH_CONF_PROG_TYPE_MASK;
- + writel(reg, dc->base + DC_WR_CH_CONF);
- +
- + /* The Freescale BSP kernel clears DIx_COUNTER_RELEASE here */
- +
- + complete(&dc->priv->comp);
- + return IRQ_HANDLED;
- +}
- +
- void ipu_dc_disable_channel(struct ipu_dc *dc)
- {
- struct ipu_dc_priv *priv = dc->priv;
- + int irq, ret;
- u32 val;
- - int irq = 0, timeout = 50;
-
- + /* TODO: Handle MEM_FG_SYNC differently from MEM_BG_SYNC */
- if (dc->chno == 1)
- - irq = IPU_IRQ_DC_FC_1;
- + irq = priv->dc_irq;
- else if (dc->chno == 5)
- - irq = IPU_IRQ_DP_SF_END;
- + irq = priv->dp_irq;
- else
- return;
-
- - /* should wait for the interrupt here */
- - mdelay(50);
- + init_completion(&priv->comp);
- + enable_irq(irq);
- + ret = wait_for_completion_timeout(&priv->comp, msecs_to_jiffies(50));
- + disable_irq(irq);
- + if (ret <= 0) {
- + dev_warn(priv->dev, "DC stop timeout after 50 ms\n");
-
- - if (dc->di == 0)
- - val = 0x00000002;
- - else
- - val = 0x00000020;
- -
- - /* Wait for DC triple buffer to empty */
- - while ((readl(priv->dc_reg + DC_STAT) & val) != val) {
- - usleep_range(2000, 20000);
- - timeout -= 2;
- - if (timeout <= 0)
- - break;
- + val = readl(dc->base + DC_WR_CH_CONF);
- + val &= ~DC_WR_CH_CONF_PROG_TYPE_MASK;
- + writel(val, dc->base + DC_WR_CH_CONF);
- }
- -
- - val = readl(dc->base + DC_WR_CH_CONF);
- - val &= ~DC_WR_CH_CONF_PROG_TYPE_MASK;
- - writel(val, dc->base + DC_WR_CH_CONF);
- }
- EXPORT_SYMBOL_GPL(ipu_dc_disable_channel);
-
- +void ipu_dc_disable(struct ipu_soc *ipu)
- +{
- + ipu_module_disable(ipu, IPU_CONF_DC_EN);
- +}
- +EXPORT_SYMBOL_GPL(ipu_dc_disable);
- +
- static void ipu_dc_map_config(struct ipu_dc_priv *priv, enum ipu_dc_map map,
- int byte_num, int offset, int mask)
- {
- @@ -340,7 +365,7 @@ int ipu_dc_init(struct ipu_soc *ipu, struct device *dev,
- struct ipu_dc_priv *priv;
- static int channel_offsets[] = { 0, 0x1c, 0x38, 0x54, 0x58, 0x5c,
- 0x78, 0, 0x94, 0xb4};
- - int i;
- + int i, ret;
-
- priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
- if (!priv)
- @@ -361,6 +386,23 @@ int ipu_dc_init(struct ipu_soc *ipu, struct device *dev,
- priv->channels[i].base = priv->dc_reg + channel_offsets[i];
- }
-
- + priv->dc_irq = ipu_map_irq(ipu, IPU_IRQ_DC_FC_1);
- + if (!priv->dc_irq)
- + return -EINVAL;
- + ret = devm_request_irq(dev, priv->dc_irq, dc_irq_handler, 0, NULL,
- + &priv->channels[1]);
- + if (ret < 0)
- + return ret;
- + disable_irq(priv->dc_irq);
- + priv->dp_irq = ipu_map_irq(ipu, IPU_IRQ_DP_SF_END);
- + if (!priv->dp_irq)
- + return -EINVAL;
- + ret = devm_request_irq(dev, priv->dp_irq, dc_irq_handler, 0, NULL,
- + &priv->channels[5]);
- + if (ret < 0)
- + return ret;
- + disable_irq(priv->dp_irq);
- +
- writel(DC_WR_CH_CONF_WORD_SIZE_24 | DC_WR_CH_CONF_DISP_ID_PARALLEL(1) |
- DC_WR_CH_CONF_PROG_DI_ID,
- priv->channels[1].base + DC_WR_CH_CONF);
- @@ -404,6 +446,12 @@ int ipu_dc_init(struct ipu_soc *ipu, struct device *dev,
- ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 1, 15, 0xff); /* green */
- ipu_dc_map_config(priv, IPU_DC_MAP_BGR24, 0, 23, 0xff); /* blue */
-
- + /* rgb666 */
- + ipu_dc_map_clear(priv, IPU_DC_MAP_RGB666);
- + ipu_dc_map_config(priv, IPU_DC_MAP_RGB666, 0, 5, 0xfc); /* blue */
- + ipu_dc_map_config(priv, IPU_DC_MAP_RGB666, 1, 11, 0xfc); /* green */
- + ipu_dc_map_config(priv, IPU_DC_MAP_RGB666, 2, 17, 0xfc); /* red */
- +
- return 0;
- }
-
- diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-di.c b/drivers/staging/imx-drm/ipu-v3/ipu-di.c
- index 82a9ebad697c..849b3e120ef0 100644
- --- a/drivers/staging/imx-drm/ipu-v3/ipu-di.c
- +++ b/drivers/staging/imx-drm/ipu-v3/ipu-di.c
- @@ -595,7 +595,7 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
- }
- }
-
- - if (!sig->clk_pol)
- + if (sig->clk_pol)
- di_gen |= DI_GEN_POLARITY_DISP_CLK;
-
- ipu_di_write(di, di_gen, DI_GENERAL);
- diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c b/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c
- index 45213017fa4b..59f182b28fc1 100644
- --- a/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c
- +++ b/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c
- @@ -28,7 +28,12 @@
- #define DMFC_GENERAL1 0x0014
- #define DMFC_GENERAL2 0x0018
- #define DMFC_IC_CTRL 0x001c
- -#define DMFC_STAT 0x0020
- +#define DMFC_WR_CHAN_ALT 0x0020
- +#define DMFC_WR_CHAN_DEF_ALT 0x0024
- +#define DMFC_DP_CHAN_ALT 0x0028
- +#define DMFC_DP_CHAN_DEF_ALT 0x002c
- +#define DMFC_GENERAL1_ALT 0x0030
- +#define DMFC_STAT 0x0034
-
- #define DMFC_WR_CHAN_1_28 0
- #define DMFC_WR_CHAN_2_41 8
- @@ -133,6 +138,20 @@ int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc)
- }
- EXPORT_SYMBOL_GPL(ipu_dmfc_enable_channel);
-
- +static void ipu_dmfc_wait_fifos(struct ipu_dmfc_priv *priv)
- +{
- + unsigned long timeout = jiffies + msecs_to_jiffies(1000);
- +
- + while ((readl(priv->base + DMFC_STAT) & 0x02fff000) != 0x02fff000) {
- + if (time_after(jiffies, timeout)) {
- + dev_warn(priv->dev,
- + "Timeout waiting for DMFC FIFOs to clear\n");
- + break;
- + }
- + cpu_relax();
- + }
- +}
- +
- void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc)
- {
- struct ipu_dmfc_priv *priv = dmfc->priv;
- @@ -141,8 +160,10 @@ void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc)
-
- priv->use_count--;
-
- - if (!priv->use_count)
- + if (!priv->use_count) {
- + ipu_dmfc_wait_fifos(priv);
- ipu_module_disable(priv->ipu, IPU_CONF_DMFC_EN);
- + }
-
- if (priv->use_count < 0)
- priv->use_count = 0;
- diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dp.c b/drivers/staging/imx-drm/ipu-v3/ipu-dp.c
- index 58f87c8d7c07..d90f82a87d19 100644
- --- a/drivers/staging/imx-drm/ipu-v3/ipu-dp.c
- +++ b/drivers/staging/imx-drm/ipu-v3/ipu-dp.c
- @@ -215,10 +215,9 @@ int ipu_dp_setup_channel(struct ipu_dp *dp,
- }
- EXPORT_SYMBOL_GPL(ipu_dp_setup_channel);
-
- -int ipu_dp_enable_channel(struct ipu_dp *dp)
- +int ipu_dp_enable(struct ipu_soc *ipu)
- {
- - struct ipu_flow *flow = to_flow(dp);
- - struct ipu_dp_priv *priv = flow->priv;
- + struct ipu_dp_priv *priv = ipu->dp_priv;
-
- mutex_lock(&priv->mutex);
-
- @@ -227,15 +226,28 @@ int ipu_dp_enable_channel(struct ipu_dp *dp)
-
- priv->use_count++;
-
- - if (dp->foreground) {
- - u32 reg;
- + mutex_unlock(&priv->mutex);
-
- - reg = readl(flow->base + DP_COM_CONF);
- - reg |= DP_COM_CONF_FG_EN;
- - writel(reg, flow->base + DP_COM_CONF);
- + return 0;
- +}
- +EXPORT_SYMBOL_GPL(ipu_dp_enable);
-
- - ipu_srm_dp_sync_update(priv->ipu);
- - }
- +int ipu_dp_enable_channel(struct ipu_dp *dp)
- +{
- + struct ipu_flow *flow = to_flow(dp);
- + struct ipu_dp_priv *priv = flow->priv;
- + u32 reg;
- +
- + if (!dp->foreground)
- + return 0;
- +
- + mutex_lock(&priv->mutex);
- +
- + reg = readl(flow->base + DP_COM_CONF);
- + reg |= DP_COM_CONF_FG_EN;
- + writel(reg, flow->base + DP_COM_CONF);
- +
- + ipu_srm_dp_sync_update(priv->ipu);
-
- mutex_unlock(&priv->mutex);
-
- @@ -247,25 +259,38 @@ void ipu_dp_disable_channel(struct ipu_dp *dp)
- {
- struct ipu_flow *flow = to_flow(dp);
- struct ipu_dp_priv *priv = flow->priv;
- + u32 reg, csc;
- +
- + if (!dp->foreground)
- + return;
-
- mutex_lock(&priv->mutex);
-
- - priv->use_count--;
- + reg = readl(flow->base + DP_COM_CONF);
- + csc = reg & DP_COM_CONF_CSC_DEF_MASK;
- + if (csc == DP_COM_CONF_CSC_DEF_FG)
- + reg &= ~DP_COM_CONF_CSC_DEF_MASK;
-
- - if (dp->foreground) {
- - u32 reg, csc;
- + reg &= ~DP_COM_CONF_FG_EN;
- + writel(reg, flow->base + DP_COM_CONF);
-
- - reg = readl(flow->base + DP_COM_CONF);
- - csc = reg & DP_COM_CONF_CSC_DEF_MASK;
- - if (csc == DP_COM_CONF_CSC_DEF_FG)
- - reg &= ~DP_COM_CONF_CSC_DEF_MASK;
- + writel(0, flow->base + DP_FG_POS);
- + ipu_srm_dp_sync_update(priv->ipu);
-
- - reg &= ~DP_COM_CONF_FG_EN;
- - writel(reg, flow->base + DP_COM_CONF);
- + if (ipu_idmac_channel_busy(priv->ipu, IPUV3_CHANNEL_MEM_BG_SYNC))
- + ipu_wait_interrupt(priv->ipu, IPU_IRQ_DP_SF_END, 50);
-
- - writel(0, flow->base + DP_FG_POS);
- - ipu_srm_dp_sync_update(priv->ipu);
- - }
- + mutex_unlock(&priv->mutex);
- +}
- +EXPORT_SYMBOL_GPL(ipu_dp_disable_channel);
- +
- +void ipu_dp_disable(struct ipu_soc *ipu)
- +{
- + struct ipu_dp_priv *priv = ipu->dp_priv;
- +
- + mutex_lock(&priv->mutex);
- +
- + priv->use_count--;
-
- if (!priv->use_count)
- ipu_module_disable(priv->ipu, IPU_CONF_DP_EN);
- @@ -275,7 +300,7 @@ void ipu_dp_disable_channel(struct ipu_dp *dp)
-
- mutex_unlock(&priv->mutex);
- }
- -EXPORT_SYMBOL_GPL(ipu_dp_disable_channel);
- +EXPORT_SYMBOL_GPL(ipu_dp_disable);
-
- struct ipu_dp *ipu_dp_get(struct ipu_soc *ipu, unsigned int flow)
- {
- diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-prv.h b/drivers/staging/imx-drm/ipu-v3/ipu-prv.h
- index 4df00501adc2..bfc1b3366488 100644
- --- a/drivers/staging/imx-drm/ipu-v3/ipu-prv.h
- +++ b/drivers/staging/imx-drm/ipu-v3/ipu-prv.h
- @@ -185,6 +185,9 @@ void ipu_srm_dp_sync_update(struct ipu_soc *ipu);
- int ipu_module_enable(struct ipu_soc *ipu, u32 mask);
- int ipu_module_disable(struct ipu_soc *ipu, u32 mask);
-
- +bool ipu_idmac_channel_busy(struct ipu_soc *ipu, unsigned int chno);
- +int ipu_wait_interrupt(struct ipu_soc *ipu, int irq, int ms);
- +
- int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
- unsigned long base, u32 module, struct clk *ipu_clk);
- void ipu_di_exit(struct ipu_soc *ipu, int id);
- diff --git a/drivers/staging/imx-drm/ipuv3-crtc.c b/drivers/staging/imx-drm/ipuv3-crtc.c
- index c48f640db006..47bec5e17358 100644
- --- a/drivers/staging/imx-drm/ipuv3-crtc.c
- +++ b/drivers/staging/imx-drm/ipuv3-crtc.c
- @@ -60,24 +60,32 @@ struct ipu_crtc {
-
- static void ipu_fb_enable(struct ipu_crtc *ipu_crtc)
- {
- + struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
- +
- if (ipu_crtc->enabled)
- return;
-
- - ipu_di_enable(ipu_crtc->di);
- - ipu_dc_enable_channel(ipu_crtc->dc);
- + ipu_dc_enable(ipu);
- ipu_plane_enable(ipu_crtc->plane[0]);
- + /* Start DC channel and DI after IDMAC */
- + ipu_dc_enable_channel(ipu_crtc->dc);
- + ipu_di_enable(ipu_crtc->di);
-
- ipu_crtc->enabled = 1;
- }
-
- static void ipu_fb_disable(struct ipu_crtc *ipu_crtc)
- {
- + struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
- +
- if (!ipu_crtc->enabled)
- return;
-
- - ipu_plane_disable(ipu_crtc->plane[0]);
- + /* Stop DC channel and DI before IDMAC */
- ipu_dc_disable_channel(ipu_crtc->dc);
- ipu_di_disable(ipu_crtc->di);
- + ipu_plane_disable(ipu_crtc->plane[0]);
- + ipu_dc_disable(ipu);
-
- ipu_crtc->enabled = 0;
- }
- @@ -158,7 +166,7 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc,
- sig_cfg.Vsync_pol = 1;
-
- sig_cfg.enable_pol = 1;
- - sig_cfg.clk_pol = 1;
- + sig_cfg.clk_pol = 0;
- sig_cfg.width = mode->hdisplay;
- sig_cfg.height = mode->vdisplay;
- sig_cfg.pixel_fmt = out_pixel_fmt;
- diff --git a/drivers/staging/imx-drm/ipuv3-plane.c b/drivers/staging/imx-drm/ipuv3-plane.c
- index 27a8d735dae0..5697e59ddf1d 100644
- --- a/drivers/staging/imx-drm/ipuv3-plane.c
- +++ b/drivers/staging/imx-drm/ipuv3-plane.c
- @@ -239,6 +239,8 @@ int ipu_plane_get_resources(struct ipu_plane *ipu_plane)
-
- void ipu_plane_enable(struct ipu_plane *ipu_plane)
- {
- + if (ipu_plane->dp)
- + ipu_dp_enable(ipu_plane->ipu);
- ipu_dmfc_enable_channel(ipu_plane->dmfc);
- ipu_idmac_enable_channel(ipu_plane->ipu_ch);
- if (ipu_plane->dp)
- @@ -257,6 +259,8 @@ void ipu_plane_disable(struct ipu_plane *ipu_plane)
- ipu_dp_disable_channel(ipu_plane->dp);
- ipu_idmac_disable_channel(ipu_plane->ipu_ch);
- ipu_dmfc_disable_channel(ipu_plane->dmfc);
- + if (ipu_plane->dp)
- + ipu_dp_disable(ipu_plane->ipu);
- }
-
- static void ipu_plane_dpms(struct ipu_plane *ipu_plane, int mode)
- diff --git a/drivers/staging/imx-drm/parallel-display.c b/drivers/staging/imx-drm/parallel-display.c
- index c60b6c645f42..01b7ce50fc30 100644
- --- a/drivers/staging/imx-drm/parallel-display.c
- +++ b/drivers/staging/imx-drm/parallel-display.c
- @@ -219,6 +219,8 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data)
- imxpd->interface_pix_fmt = V4L2_PIX_FMT_RGB565;
- else if (!strcmp(fmt, "bgr666"))
- imxpd->interface_pix_fmt = V4L2_PIX_FMT_BGR666;
- + else if (!strcmp(fmt, "rgb666"))
- + imxpd->interface_pix_fmt = V4L2_PIX_FMT_RGB666;
- }
-
- panel_node = of_parse_phandle(np, "fsl,panel", 0);
- diff --git a/include/linux/cec-dev.h b/include/linux/cec-dev.h
- new file mode 100644
- index 000000000000..76a7d7f6a72d
- --- /dev/null
- +++ b/include/linux/cec-dev.h
- @@ -0,0 +1,69 @@
- +#ifndef _LINUX_CEC_DEV_H
- +#define _LINUX_CEC_DEV_H
- +
- +#include <linux/cdev.h>
- +#include <linux/list.h>
- +#include <linux/mutex.h>
- +#include <linux/spinlock.h>
- +#include <linux/wait.h>
- +
- +#include <uapi/linux/cec-dev.h>
- +
- +struct device;
- +
- +struct cec_dev {
- + struct cdev cdev;
- + dev_t devn;
- +
- + struct mutex mutex;
- + unsigned users;
- +
- + spinlock_t lock;
- + wait_queue_head_t waitq;
- + struct list_head events;
- + u8 write_busy;
- +
- + u8 retries;
- + u16 addresses;
- + u16 physical;
- +
- + int (*open)(struct cec_dev *);
- + void (*release)(struct cec_dev *);
- + void (*send_message)(struct cec_dev *, u8 *, size_t);
- + void (*set_address)(struct cec_dev *, unsigned);
- +};
- +
- +void cec_dev_event(struct cec_dev *cec_dev, int type, u8 *msg, size_t len);
- +
- +static inline void cec_dev_receive(struct cec_dev *cec_dev, u8 *msg,
- + unsigned len)
- +{
- + cec_dev_event(cec_dev, MESSAGE_TYPE_RECEIVE_SUCCESS, msg, len);
- +}
- +
- +static inline void cec_dev_send_complete(struct cec_dev *cec_dev, int ack)
- +{
- + cec_dev->retries = 0;
- + cec_dev->write_busy = 0;
- +
- + cec_dev_event(cec_dev, ack ? MESSAGE_TYPE_SEND_SUCCESS :
- + MESSAGE_TYPE_NOACK, NULL, 0);
- +}
- +
- +static inline void cec_dev_disconnect(struct cec_dev *cec_dev)
- +{
- + cec_dev->physical = 0;
- + cec_dev_event(cec_dev, MESSAGE_TYPE_DISCONNECTED, NULL, 0);
- +}
- +
- +static inline void cec_dev_connect(struct cec_dev *cec_dev, u32 phys)
- +{
- + cec_dev->physical = phys;
- + cec_dev_event(cec_dev, MESSAGE_TYPE_CONNECTED, NULL, 0);
- +}
- +
- +void cec_dev_init(struct cec_dev *cec_dev, struct module *);
- +int cec_dev_add(struct cec_dev *cec_dev, struct device *, const char *name);
- +void cec_dev_remove(struct cec_dev *cec_dev);
- +
- +#endif
- diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
- index cb61ea4d6945..2fdfe30295d5 100644
- --- a/include/linux/mmc/host.h
- +++ b/include/linux/mmc/host.h
- @@ -278,6 +278,7 @@ struct mmc_host {
- #define MMC_CAP2_PACKED_CMD (MMC_CAP2_PACKED_RD | \
- MMC_CAP2_PACKED_WR)
- #define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14) /* Don't power up before scan */
- +#define MMC_CAP2_SDIO_IRQ_NOTHREAD (1 << 15)
-
- mmc_pm_flag_t pm_caps; /* supported pm features */
-
- @@ -293,6 +294,11 @@ struct mmc_host {
- unsigned long clkgate_delay;
- #endif
-
- + /* card specific properties to deal with power and reset */
- + struct regulator *card_regulator; /* External VCC needed by the card */
- + struct gpio_desc *card_reset_gpios[2]; /* External resets, active low */
- + struct clk *card_clk; /* External clock needed by the card */
- +
- /* host specific block data */
- unsigned int max_seg_size; /* see blk_queue_max_segment_size */
- unsigned short max_segs; /* see blk_queue_max_segments */
- @@ -391,6 +397,8 @@ static inline void mmc_signal_sdio_irq(struct mmc_host *host)
- wake_up_process(host->sdio_irq_thread);
- }
-
- +void sdio_run_irqs(struct mmc_host *host);
- +
- #ifdef CONFIG_REGULATOR
- int mmc_regulator_get_ocrmask(struct regulator *supply);
- int mmc_regulator_set_ocr(struct mmc_host *mmc,
- diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
- index 7be12b883485..08abe9941884 100644
- --- a/include/linux/mmc/sdhci.h
- +++ b/include/linux/mmc/sdhci.h
- @@ -57,12 +57,8 @@ struct sdhci_host {
- #define SDHCI_QUIRK_BROKEN_CARD_DETECTION (1<<15)
- /* Controller reports inverted write-protect state */
- #define SDHCI_QUIRK_INVERTED_WRITE_PROTECT (1<<16)
- -/* Controller has nonstandard clock management */
- -#define SDHCI_QUIRK_NONSTANDARD_CLOCK (1<<17)
- /* Controller does not like fast PIO transfers */
- #define SDHCI_QUIRK_PIO_NEEDS_DELAY (1<<18)
- -/* Controller losing signal/interrupt enable states after reset */
- -#define SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET (1<<19)
- /* Controller has to be forced to use block size of 2048 bytes */
- #define SDHCI_QUIRK_FORCE_BLK_SZ_2048 (1<<20)
- /* Controller cannot do multi-block transfers */
- @@ -147,6 +143,7 @@ struct sdhci_host {
-
- bool runtime_suspended; /* Host is runtime suspended */
- bool bus_on; /* Bus power prevents runtime suspend */
- + bool preset_enabled; /* Preset is enabled */
-
- struct mmc_request *mrq; /* Current request */
- struct mmc_command *cmd; /* Current command */
- @@ -164,8 +161,7 @@ struct sdhci_host {
- dma_addr_t adma_addr; /* Mapped ADMA descr. table */
- dma_addr_t align_addr; /* Mapped bounce buffer */
-
- - struct tasklet_struct card_tasklet; /* Tasklet structures */
- - struct tasklet_struct finish_tasklet;
- + struct tasklet_struct finish_tasklet; /* Tasklet structures */
-
- struct timer_list timer; /* Timer for timeouts */
-
- @@ -177,6 +173,13 @@ struct sdhci_host {
- unsigned int ocr_avail_mmc;
- u32 ocr_mask; /* available voltages */
-
- + unsigned timing; /* Current timing */
- +
- + u32 thread_isr;
- +
- + /* cached registers */
- + u32 ier;
- +
- wait_queue_head_t buf_ready_int; /* Waitqueue for Buffer Read Ready interrupt */
- unsigned int tuning_done; /* Condition flag set when CMD19 succeeds */
-
- diff --git a/include/uapi/linux/cec-dev.h b/include/uapi/linux/cec-dev.h
- new file mode 100644
- index 000000000000..fb7a41704c77
- --- /dev/null
- +++ b/include/uapi/linux/cec-dev.h
- @@ -0,0 +1,34 @@
- +#ifndef _UAPI_LINUX_CEC_DEV_H
- +#define _UAPI_LINUX_CEC_DEV_H
- +
- +#include <linux/ioctl.h>
- +#include <linux/types.h>
- +
- +#define MAX_MESSAGE_LEN 16
- +
- +enum {
- + HDMICEC_IOC_MAGIC = 'H',
- + /* This is wrong: we pass the argument as a number, not a pointer */
- + HDMICEC_IOC_O_SETLOGICALADDRESS = _IOW(HDMICEC_IOC_MAGIC, 1, unsigned char),
- + HDMICEC_IOC_SETLOGICALADDRESS = _IO(HDMICEC_IOC_MAGIC, 1),
- + HDMICEC_IOC_STARTDEVICE = _IO(HDMICEC_IOC_MAGIC, 2),
- + HDMICEC_IOC_STOPDEVICE = _IO(HDMICEC_IOC_MAGIC, 3),
- + HDMICEC_IOC_GETPHYADDRESS = _IOR(HDMICEC_IOC_MAGIC, 4, unsigned char[4]),
- +};
- +
- +enum {
- + MESSAGE_TYPE_RECEIVE_SUCCESS = 1,
- + MESSAGE_TYPE_NOACK,
- + MESSAGE_TYPE_DISCONNECTED,
- + MESSAGE_TYPE_CONNECTED,
- + MESSAGE_TYPE_SEND_SUCCESS,
- + MESSAGE_TYPE_SEND_ERROR,
- +};
- +
- +struct cec_user_event {
- + __u32 event_type;
- + __u32 msg_len;
- + __u8 msg[MAX_MESSAGE_LEN];
- +};
- +
- +#endif
- diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
- index ea468ee8fe21..d5d818a86676 100644
- --- a/include/uapi/linux/videodev2.h
- +++ b/include/uapi/linux/videodev2.h
- @@ -299,6 +299,7 @@ struct v4l2_pix_format {
- #define V4L2_PIX_FMT_RGB555X v4l2_fourcc('R', 'G', 'B', 'Q') /* 16 RGB-5-5-5 BE */
- #define V4L2_PIX_FMT_RGB565X v4l2_fourcc('R', 'G', 'B', 'R') /* 16 RGB-5-6-5 BE */
- #define V4L2_PIX_FMT_BGR666 v4l2_fourcc('B', 'G', 'R', 'H') /* 18 BGR-6-6-6 */
- +#define V4L2_PIX_FMT_RGB666 v4l2_fourcc('R', 'G', 'B', 'H') /* 18 RGB-6-6-6 */
- #define V4L2_PIX_FMT_BGR24 v4l2_fourcc('B', 'G', 'R', '3') /* 24 BGR-8-8-8 */
- #define V4L2_PIX_FMT_RGB24 v4l2_fourcc('R', 'G', 'B', '3') /* 24 RGB-8-8-8 */
- #define V4L2_PIX_FMT_BGR32 v4l2_fourcc('B', 'G', 'R', '4') /* 32 BGR-8-8-8-8 */
- diff --git a/sound/soc/fsl/imx-pcm-dma.c b/sound/soc/fsl/imx-pcm-dma.c
- index 2585ae44e634..a86d84854c7f 100644
- --- a/sound/soc/fsl/imx-pcm-dma.c
- +++ b/sound/soc/fsl/imx-pcm-dma.c
- @@ -44,7 +44,7 @@ static const struct snd_pcm_hardware imx_pcm_hardware = {
- .buffer_bytes_max = IMX_SSI_DMABUF_SIZE,
- .period_bytes_min = 128,
- .period_bytes_max = 65535, /* Limited by SDMA engine */
- - .periods_min = 2,
- + .periods_min = 4,
- .periods_max = 255,
- .fifo_size = 0,
- };
|