1 Star 0 Fork 0

suiren/s5p6818_alsa_driver_simplify

加入 Gitee
与超过 1400万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
alsa_read2.c 88.45 KB
一键复制 编辑 原始数据 按行查看 历史
suiren 提交于 2023-03-16 14:28 +08:00 . simplify
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913
########驱动初始化流程##########
#1. alsa_sound_init()
# 申请设备号116作为alsa这一类设备.
#2. nx_i2s_probe()
# i2s控制器初始化, 其设备信息保存在dts. 创建i2s_dai结构体
# nx_i2s_set_plat_param(), 获取dts的信息,如采样率等信息,将采样率这些信息保存到i2s_dai<obj20>中, 以位域的形式.
# 初始化控制器的时钟, 并开启i2s接口, 但其他i2s功能依旧关闭中.
# snd_soc_register_dais()函数, 将i2s_dai加入cpu_cmpnt<obj2> 链表, 设置i2s_dai->driver.
#3. es8316_i2c_probe()
# 创建codec_dai结构体,
# snd_soc_register_dais()函数, 将code_dai加入codec_cmpnt<obj14>链表. 设置codec_dai->driver.
#4. nx_simple_card_probe()
# 解析dts, 获得simple_card节点下的cpu_dai和codec_dai的名字.
# devm_snd_soc_register_card(), 根据dts的cpu_dai和codec_dai的名字, 遍历component_list->cpu_cmpnt链表
# 和component_list->codec_cmpnt链表, 找到对应的cpu_dai和codec_dai.
# devm_snd_soc_register_card()-> soc_probe_link_components() , 对已经获得的cpu_dai和codec_dai进行probe,
# 通过dai->driver->probe函数. dai->driver的指向由snd_soc_register_dais()函数设置.
# 通过codec_dai->driver->probe(), 才真正地设置codec的寄存器,对其进行初始化.
# snd_ctl_create() 设置设备节点名为 controlC%d. 对应struct snd_card *card结构体, 通过结构体可以获得cpu_dai和codec_dai,
# 可以通过这些dai结构体,进而设置其对应的硬件的寄存器.
# snd_pcm_new_stream() 设置另一个的设备节点名为 pcmC%iD%i%c, 对应着是struct snd_pcm_str streams结构体,
# 该结构体用于进行数据传输.
# platform->driver->pcm_new()=>nx_pcm_new(), 分配DMA内存, 用于保存音频数据, i2s控制器从这里获取数据.
simple_card dts:
simple_card: sound {
compatible = "nexell,simple-audio-card";
simple-audio-card,dai-link@0 {
format = "i2s";
cpu {
sound-dai = <&i2s_0 0>;
};
codec {
sound-dai = <&es8316>;
};
};
};
#总结:
#驱动中有多条链表.
#component_list 上挂接着cpu_cmpnt链表 和 codec_cmpnt链表.
#cpu_cmpnt链表上挂接已注册的cpu_dai.
#codec_cmpnt链表上挂接已注册的codec_dai.
#struct simple_card_data card_data结构体中struct snd_soc_pcm_runtime *rtd结构体 的包含自己所需要的cpu_dai和codec_dai.
#我认为cpu_dai对应着数据传送方式,即i2s控制器,而codec_dai对应为声卡,我这里是es8316.
component_list<list2> => list ( cpu_cmpnt<obj2>) => list (codec_cmpnt<obj14>)
cpu_cmpnt<obj2>
->list => list (i2s_dai<obj20>)
codec_cmpnt<obj14>
->list => list (codec_dai<obj21>)
component_list; <list2>
platform_list; <list3>
codec_list; <list5>
struct platform_device *i2s_pdev <tag12>
->struct device dev; <obj3>
->void *driver_data <tag30> <point to obj7>
struct nx_i2s_snd_param *par; <tag1> <obj7>
->struct device *dev; <tag15> <point to obj3>
->struct snd_soc_dai_driver dai_drv; <tag2> <obj1>
->struct snd_soc_pcm_stream playback;
->unsigned int rates; <tag158> < value == 1<<7 >
->int sample_rate; <tag157> <dts> <48000>
->struct nx_pcm_dma_param play; <tag3> <obj50>
->dma_addr_t peri_addr; <tag4>
->struct device *dev; <tag13> <point to obj3>
->char *dma_ch_name; <tag14> <"i2s">
struct snd_soc_component *cmpnt; <tag5> <obj2>
->char *name; <tag163> <"c0055000.i2s">
->struct device *dev; <tag16> <point to obj3>
->struct snd_soc_dai_driver *dai_drv; <tag6> <point to obj1>
->struct list_head dai_list; <list1>
->struct regmap *regmap; <tag11>
->const struct snd_soc_component_driver *driver; <tag17> <point to obj4>
->struct list_head list; <tag21> <add to list2>
struct snd_soc_dai *i2s_dai; <tag7> <obj20>
->struct device *dev; <tag19> <point to obj3>
->struct snd_soc_component *component; <tag8> <point to obj2>
->struct snd_soc_dai_driver *driver; <tag9> <point to obj1>
->struct list_head list; <tag10> <add to list1>
->char *name <tag20> <"c0055000.i2s">
->void *playback_dma_data; <tag138> <point to obj50>
->unsigned int rate; <tag159>
->unsigned int channels; <tag159>
->unsigned int sample_bits; <tag159>
struct snd_soc_platform *soc_platform; <tag22> <obj23>
->struct device *dev; <tag27> <point to obj3>
->const struct snd_soc_platform_driver *driver; <tag28> <point to obj5>
->struct list_head list; <tag29> <add to list3>
->struct snd_soc_component component;
->char *name; <tag23>
->struct device *dev; <tag24> <point to obj3>
->const struct snd_soc_component_driver *driver; <tag25> <point to obj6>
static const struct snd_soc_component_driver nx_i2s_component; <obj4> <tag18>
struct snd_soc_platform_driver nx_pcm_platform; <obj5> <tag26>
->struct snd_soc_component_driver component_driver; <obj6>
##########
struct i2c_client *i2c <tag32> <obj30>
->struct device *dev; <obj11>
->void *driver_data; <tag33> <point to obj9>
struct es8316_priv *es8316; <tag31> <obj9>
struct snd_soc_codec *codec; <tag34> <obj10>
->struct device *dev; <tag40> <point to obj11>
->const struct snd_soc_codec_driver *driver; <tag41> <point to obj12>
->struct list_head list; <tag56> <add to list5>
->void *control_data; <point to obj30> <tag103>
->struct snd_soc_component component; <obj14>
->char *name; <tag163> <"ES8316.0-0011">
->struct snd_soc_card *card; <tag102> <point to obj17>
->struct snd_soc_dapm_context dapm; <obj29>
->struct snd_soc_card *card; <tag101> <point to obj17>
->struct snd_soc_codec *codec; <tag35> <point to obj10>
->char *name; <tag36>
->struct device *dev; <tag37> <point to obj11>
->const struct snd_soc_component_driver *driver; <tag38> <point to obj12>
->struct snd_soc_dai_driver *dai_drv; <tag42> <point to obj13>
->struct list_head dai_list; <list4>
->struct list_head list; <tag55> <add to list2>
struct snd_soc_dai *codec_dai; <tag44> <obj21>
->struct device *dev; <tag47> <point to obj11>
->struct snd_soc_component *component; <tag46> <point to obj14>
->struct snd_soc_dai_driver *driver; <tag48> <point to obj13>
->struct list_head list; <tag50> <add to list4>
->char *name; <tag45> <"ES8316 HiFi">
->struct snd_soc_codec *codec; <tag51> <point to obj10>
static struct snd_soc_codec_driver soc_codec_dev_es8316; <tag39> <obj12>
static struct snd_soc_dai_driver es8316_dai; <obj13> <tag43>
###############
struct platform_device *simple_card_pdev <tag58>
->struct device dev; <obj15>
struct simple_card_data *simple_card_priv; <tag59> <obj16>
struct simple_dai_props *dai_props; <tag61>
->struct snd_soc_card snd_card; <obj17>
->struct list_head dapm_list; <list7>
->struct device *dev; <tag60> <point to obj15>
->void *driver_data; <tag75> <point to obj17>
->char *name; <tag62>
->void *drvdata <tag71> <point to obj16>
->struct snd_card *snd_card; <tag95> <point to obj26>
->struct snd_soc_dapm_context dapm;
->struct list_head list; <tag100> <add to list7>
->struct device *dev; <tag97> <point to obj15>
->struct snd_soc_card *card; <tag99> <point to obj17>
->struct snd_soc_pcm_runtime *rtd; <tag76> <obj18>
->struct snd_pcm *pcm; <tag120> <point to obj34>
->struct device *dev; <tag104> <point to obj15>
->struct device *parent; <tag105>
->void *driver_data <tag106> <point to obj18>
->struct snd_soc_card *card; <tag78> <point to obj17>
->struct snd_soc_dai_link *dai_link; <tag79> <point to obj19>
->struct snd_soc_dai **codec_dais; <tag80>
->struct snd_soc_dai *codec_dai; <tag82> <point to obj21>
->struct snd_soc_dai *cpu_dai; <tag81> <point to obj20>
->struct snd_soc_codec *codec; <tag83> <point to obj10>
->struct snd_soc_platform *platform; <tag84> <point to obj23>
->struct snd_soc_pcm_runtime *rtd_aux; <tag77> <point to obj18>
->struct snd_soc_dai_link *dai_link; <obj19>
->const char *name; <tag70> <"c0055000.i2s-ES8316 HiFi">
->const char *stream_name; <tag70> <"c0055000.i2s-ES8316 HiFi">
->const char *cpu_dai_name; <tag69> <"c0055000.i2s">
->const char *codec_dai_name; <tag69> <"ES8316 HiFi">
->struct snd_soc_dai_link_component *codecs; <tag74>
struct snd_card *card; <tag86> <obj26>
->struct device *dev; <tag87> <point to obj15>
->struct list_head devices;
->struct list_head *prev; <list6>
->struct device ctl_dev; <obj39>
->struct device *parent; <tag89> <point to obj24>
->struct device card_dev; <obj24>
->struct device *parent; <tag88> <point to obj15>
struct snd_device *clt_dev; <tag90>
->struct snd_card *card; <tag91> <point to obj26>
->void *device_data; <tag92> <point to obj26>
->struct list_head list; <tag93> <add to list6>
struct snd_pcm *pcm; <tag107> <obj34>
->void *private_data; <tag121> <point to obj18>
->struct snd_card *card; <tag108> <point to obj26>
->struct snd_pcm_str streams[2];
=>streams[SNDRV_PCM_STREAM_PLAYBACK] <obj37>
->struct snd_pcm *pcm; <tag110> <point to obj34>
->struct snd_pcm_substream *substream; <tag115> <point to obj38>
->struct device dev; <obj44>
->struct device *parent; <tag111> <point to obj24>
struct snd_pcm_substream *substream; <tag112> <obj38>
->struct snd_pcm *pcm; <tag113> <point to obj34>
->struct snd_pcm_str *pstr; <tag114> <point to obj37>
->void *file; <tag150> <point to obj58>
->struct snd_pcm_runtime *runtime; <tag135> <obj59>
->void *private_data <tag140> <point to obj51>
->struct snd_pcm_hardware hw; <tag145> <data copy from obj53> <<tag146><continue to set value>>
->unsigned int rate; <tag160>
->unsigned int channels <tag160>
->dma_addr_t dma_addr; <tag162>
->void *private_data <tag136> <point to obj18>
->struct snd_dma_buffer dma_buffer;
->unsigned char *area; <tag123> <dma buffer alloc>
->struct snd_dma_device dev;
->struct device *dev; <tag122> <point to obj15>
struct snd_device *pcm_dev; <tag116>
->struct snd_card *card; <tag117> <point to obj26>
->void *device_data; <tag118> <point to obj34>
->struct list_head list; <tag119> <add to list6>
snd_minors[x]; <tag127> <point to obj40>
snd_minors[x2]; <tag131> <point to obj42>
struct snd_minor *clt_preg; <tag124> <obj40>
->void *private_data; <tag125> <point to obj26>
->struct device *dev; <tag126> <point to obj39>
struct snd_minor *pcm_preg; <tag128> <obj42>
->void *private_data; <tag129> <point to obj34>
->struct device *dev; <tag130> <point to obj44>
###################snd_open_device##############
struct snd_pcm_runtime *runtime; <tag132>
->struct snd_pcm_mmap_status *status; <tag133>
->struct snd_pcm_mmap_control *control; <tag134>
struct nx_pcm_runtime_data *prtd; <tag141> <obj51>
->struct device *dev; <tag142> <point to obj15>
->struct nx_pcm_dma_param *dma_param; <tag143> <point to obj50>
->struct dma_chan *dma_chan; <tag144>
static struct snd_pcm_hardware nx_pcm_hardware; <obj53>
struct snd_pcm_file *pcm_file; <tag147> <obj58>
->struct snd_pcm_substream *substream; <tag148> <point to obj38>
struct file *file <tag149>
->void *private_data <tag151> <point to obj58>
###########################################
static struct snd_pcm_hardware nx_pcm_hardware = {
/* | SNDRV_PCM_INFO_BLOCK_TRANSFER */
.info = SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_RESUME,
.formats = SND_SOC_PCM_FORMATS,
.rate_min = 8000,
.rate_max = 192000,
.channels_min = 1,
.channels_max = 2,
.buffer_bytes_max = 64 * 1024 * 2,
.period_bytes_min = 32,
.period_bytes_max = PERIOD_BYTES_MAX,
.periods_min = 2,
.periods_max = 64,
.fifo_size = 32,
};
static struct snd_soc_dai_driver es8316_dai = { <tag43>
.name = "ES8316 HiFi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
.channels_max = 2,
.rates = es8316_RATES,
.formats = es8316_FORMATS,
},
.capture = {
.stream_name = "Capture",
.channels_min = 1,
.channels_max = 2,
.rates = es8316_RATES,
.formats = es8316_FORMATS,
},
.ops = &es8316_ops,
.symmetric_rates = 1,
}
static struct snd_soc_codec_driver soc_codec_dev_es8316 = { <tag39>
.read = es8316_read_reg_cache,
.write = es8316_write,
.probe = es8316_probe,
.remove = es8316_remove,
.suspend = es8316_suspend,
.resume = es8316_resume,
.set_bias_level = es8316_set_bias_level,
.reg_cache_size = ARRAY_SIZE(es8316_reg),
.reg_word_size = sizeof(u16),
};
struct snd_soc_platform_driver nx_pcm_platform = { <tag26>
.ops = &nx_pcm_ops,
.pcm_new = nx_pcm_new,
.pcm_free = nx_pcm_free,
};
static const struct snd_soc_component_driver nx_i2s_component = { <tag18>
.name = "nx-i2sc",
};
static int __init init_soundcore(void)
{
int rc;
sound_class = class_create(THIS_MODULE, "sound");
sound_class->devnode = sound_devnode;
return 0;
}
static const struct file_operations snd_fops =
{
.owner = THIS_MODULE,
.open = snd_open,
.llseek = noop_llseek,
};
static int __init alsa_sound_init(void)
{
pr_err("%s:in %d.\n",__func__,__LINE__);
register_chrdev(major, "alsa", &snd_fops);
return 0;
}
static int __init alsa_pcm_init(void)
{
snd_ctl_register_ioctl(snd_pcm_control_ioctl);
int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn)
{
return _snd_ctl_register_ioctl(fcn, &snd_control_ioctls);
static int _snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn,
struct list_head *lists)
{
struct snd_kctl_ioctl *pn;
pn = kzalloc(sizeof(struct snd_kctl_ioctl), GFP_KERNEL);
down_write(&snd_ioctl_rwsem);
list_add_tail(&pn->list, lists);
up_write(&snd_ioctl_rwsem);
return 0;
}
}
return 0;
}
static struct platform_driver soc_driver = {
.driver = {
.name = "soc-audio",
.pm = &snd_soc_pm_ops,
},
.probe = soc_probe,
.remove = soc_remove,
};
static int __init snd_soc_init(void)
{
return platform_driver_register(&soc_driver);
}
static int __init nx_pcm_init(void)
{
return 0;
}
static const struct of_device_id nx_i2s_match[] = {
{ .compatible = "nexell,nexell-i2s" },
{},
};
static struct platform_driver i2s_driver = {
.probe = nx_i2s_probe,
.remove = nx_i2s_remove,
.driver = {
.name = "nexell-i2s",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(nx_i2s_match),
},
};
static int __init nx_i2s_init(void)
{
pr_err("%s:in %d.\n",__func__,__LINE__);
return platform_driver_register(&i2s_driver);
}
static int nx_i2s_probe(struct platform_device *pdev) <tag12>
{
struct nx_i2s_snd_param *par;
int ret = 0;
/* allocate i2c_port data */
par = devm_kzalloc(&pdev->dev, sizeof(struct nx_i2s_snd_param), GFP_KERNEL); <tag1>
nx_i2s_dai_init(&par->dai_drv); <tag2>
static void nx_i2s_dai_init(struct snd_soc_dai_driver *dai)
{
dai->ops = &nx_i2s_ops;
dai->playback.stream_name = "Playback";
dai->playback.channels_min = 2;
dai->playback.channels_max = 2;
dai->playback.formats = SND_SOC_I2S_FORMATS;
dai->playback.rates = SND_SOC_I2S_RATES;
dai->playback.rate_min = 0;
dai->playback.rate_max = 192000;
}
ret = nx_i2s_set_plat_param(par, pdev);
static int nx_i2s_set_plat_param(struct nx_i2s_snd_param *par, void *data)
{
struct platform_device *pdev = data;
struct snd_soc_dai_driver *dai = &par->dai_drv;
struct nx_pcm_dma_param *dma = &par->play;
int i = 0, ret = 0;
unsigned int id = 0;
char clkname[MAX_CLK_NAME_LENGTH];
int dfs_pllno = 0;
struct resource *res;
id = of_alias_get_id(pdev->dev.of_node, "i2s");
par->channel = id;
of_property_read_u32(pdev->dev.of_node, "master-mode",
&par->master_mode);
of_property_read_u32(pdev->dev.of_node, "mclk-in",
&par->mclk_in);
of_property_read_u32(pdev->dev.of_node, "trans-mode",
&par->trans_mode);
of_property_read_u32(pdev->dev.of_node, "frame-bit",
&par->frame_bit);
of_property_read_u32(pdev->dev.of_node, "dfs-pll",
&dfs_pllno);
par->dfs = of_property_read_bool(pdev->dev.of_node, "dfs");
/*if (par->frame_bit && !par->dfs) {
if (par->frame_bit == 32) {
dai->playback.formats = SNDRV_PCM_FMTBIT_S16_LE;
}
}*/
dai->playback.formats = SNDRV_PCM_FMTBIT_S16_LE;
of_property_read_u32(pdev->dev.of_node, "sample-rate",
&par->sample_rate); <tag157>
/*if (par->sample_rate && !par->dfs)*/
{
dai->playback.rates = snd_pcm_rate_to_rate_bit(par->sample_rate); <tag158>
unsigned int snd_pcm_rate_to_rate_bit(unsigned int rate)
{
unsigned int i;
/*
for (i = 0; i < snd_pcm_known_rates.count; i++) {
if (snd_pcm_known_rates.list[i] == rate) {
return 1u << i;
}
}*/
i = 7;
return 1u << i;
}
}
of_property_read_u32(pdev->dev.of_node, "pre-supply-mclk",
&par->pre_supply_mclk);
of_property_read_u32(pdev->dev.of_node, "LR-pol-inv",
&par->LR_pol_inv);
par->base_addr = of_iomap(pdev->dev.of_node, 0);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
SND_I2S_LOCK_INIT(&par->lock);
/*for (i = 0; 2 > i; i++, dma = &par->capt)*/
i = 0;
{
dma->active = true; <tag3>
dma->dev = &pdev->dev; <tag13>
/* I2S TXD/RXD */
dma->peri_addr = res->start + (i == 0 ? I2S_TXD_OFFSET :
I2S_RXD_OFFSET); <tag4>
dma->bus_width_byte = I2S_BUS_WIDTH;
dma->max_burst_byte = I2S_PERI_BURST;
dma->dma_ch_name = "i2s"; <tag14>
dma->dfs = par->dfs;
}
sprintf(clkname, "i2s%d", par->channel);
par->clk = devm_clk_get(&pdev->dev, clkname);
par->dev = &pdev->dev; <tag15>
return nx_i2s_check_param(par, &pdev->dev);
static int nx_i2s_check_param(struct nx_i2s_snd_param *par, struct device *dev)
{
struct snd_soc_dai_driver *dai = &par->dai_drv;
struct i2s_register *i2s = &par->i2s;
struct nx_pcm_dma_param *dmap_play = &par->play;
struct nx_pcm_dma_param *dmap_capt = &par->capt;
void __iomem *base = par->base_addr;
unsigned long request = 0, rate_hz = 0, dfs_pll = 0;
int i = 0;
int LRP, IMS, BLC = BLC_16BIT, BFS = 0, RFS = RATIO_256;
int SDF = 0, OEN = 0;
IMS = par->master_mode ? IMS_BIT_EXTCLK : IMS_BIT_SLAVE;
/* 0:I2S, 1:Left 2:Right justfied */
SDF = par->trans_mode & 0x03;
LRP = par->LR_pol_inv ? 1 : 0;
/* Active low : MLCK out enable */
OEN = !par->master_mode ? 1 : par->mclk_in;
switch (par->frame_bit) {
case 32:
BFS = BFS_32BIT; break;
}
for (i = 0; ARRAY_SIZE(clk_ratio) > i; i++) {
if (par->sample_rate == clk_ratio[i].sample_rate)
break;
}
{
/* 256 RATIO */
/*if (rate_hz != request && BFS_32BIT == BFS)*/
{
unsigned int rate = rate_hz;
RFS = RATIO_256, request = clk_ratio[i].ratio_256;
set_sample_rate_clock(dev, par->clk, request, &rate_hz);
static int set_sample_rate_clock(struct device *dev,
struct clk *clk,
unsigned long request, unsigned long *rate_hz)
{
unsigned long find, rate = 0, clock = request;
int dio = 0, din = 0, div = 1;
int ret = 0;
/* form clock generator */
find = clk_round_rate(clk, clock);
din = abs(find - clock);
dio = din, rate = find;
div = 0, ret = 0;
clk_set_rate(clk, find);
/*if (rate_hz)*/
{
*rate_hz = rate;
}
return ret;
}
}
}
/* input clock */
clk_set_rate(par->clk, rate_hz);
par->clk_rate = rate_hz;
par->in_clkgen = 1;
done:
i2s->CSR = (BLC << CSR_BLC_POS) |
(OEN << CSR_CDCLKCON_POS) |
(IMS << CSR_IMS_POS) |
(LRP << CSR_LRP_POS) |
(SDF << CSR_SDF_POS) |
(RFS << CSR_RFS_POS) |
(BFS << CSR_BFS_POS);
i2s_reset(dev);
static void i2s_reset(struct device *dev)
{
struct reset_control *rst;
rst = reset_control_get(dev, "i2s-reset");
if (!IS_ERR(rst)) {
if (reset_control_status(rst))
reset_control_reset(rst);
reset_control_put(rst);
}
}
/*if (par->pre_supply_mclk)*/
{
supply_master_clock(dev, par);
static void supply_master_clock(struct device *dev,
struct nx_i2s_snd_param *par)
{
struct i2s_register *i2s = &par->i2s;
void __iomem *base = par->base_addr;
/*if (par->in_clkgen)*/
{
clk_prepare_enable(par->clk);
}
i2s->CSR &= ~(1 << CSR_CDCLKCON_POS);
writel(i2s->CSR, (base+I2S_CSR_OFFSET)); //value == 0
par->status |= SNDDEV_STATUS_POWER;
}
i2s->CON |= 1 << CON_I2SACTIVE_POS;
writel(i2s->CON, (base+I2S_CON_OFFSET));
/* 使能i2S接口, 但其他功能仍处于关闭状态. */
pr_err("%s:in %d. CON 0x%x\n",__func__,__LINE__, i2s->CON); //value == 0x1
}
dmap_play->real_clock = rate_hz/(RATIO_256 == RFS ? 256:384);
/*if (!par->dfs)*/
{
/* i2s support format */
/*if (RFS == RATIO_256 || BFS != BFS_48BIT)*/
{
dai->playback.formats &= ~(SNDRV_PCM_FMTBIT_S24_LE |
SNDRV_PCM_FMTBIT_U24_LE);
}
}
return 0;
}
}
ret = devm_snd_soc_register_component(
&pdev->dev, &nx_i2s_component, &par->dai_drv, 1);
int devm_snd_soc_register_component(struct device *dev,
const struct snd_soc_component_driver *cmpnt_drv,
struct snd_soc_dai_driver *dai_drv, int num_dai)
{
struct device **ptr;
int ret;
ret = snd_soc_register_component(dev, cmpnt_drv, dai_drv, num_dai);
int snd_soc_register_component(struct device *dev,
const struct snd_soc_component_driver *cmpnt_drv,
struct snd_soc_dai_driver *dai_drv,
int num_dai)
{
struct snd_soc_component *cmpnt;
int ret;
cmpnt = kzalloc(sizeof(*cmpnt), GFP_KERNEL); <tag5>
ret = gm1_snd_soc_component_initialize(cmpnt, cmpnt_drv, dev);
static int gm1_snd_soc_component_initialize(
struct snd_soc_component *component,
const struct snd_soc_component_driver *driver, struct device *dev)
{
pr_err("%s:in %d.\n",__func__,__LINE__);
struct snd_soc_dapm_context *dapm;
component->name = fmt_single_name(dev, &component->id); <tag163>
component->dev = dev; <tag16>
component->driver = driver; <tag17>
INIT_LIST_HEAD(&component->dai_list);
mutex_init(&component->io_mutex);
return 0;
}
cmpnt->ignore_pmdown_time = true;
cmpnt->registered_as_component = true;
ret = gm1_snd_soc_register_dais(cmpnt, dai_drv, num_dai, true);
static int gm1_snd_soc_register_dais(struct snd_soc_component *component,
struct snd_soc_dai_driver *dai_drv, size_t count,
bool legacy_dai_naming)
{
struct device *dev = component->dev;
struct snd_soc_dai *dai;
unsigned int i;
int ret;
component->dai_drv = dai_drv; <tag6>
component->num_dai = count;
/*for (i = 0; i < count; i++)*/
i = 0;
{
dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL); <tag7>
/*if (count == 1 && legacy_dai_naming &&
(dai_drv[i].id == 0 || dai_drv[i].name == NULL))*/
{
dai->name = fmt_single_name(dev, &dai->id); <tag20>
}
dai->component = component; <tag8>
dai->dev = dev; <tag19>
dai->driver = &dai_drv[i]; <tag9>
list_add(&dai->list, &component->dai_list); <tag10>
}
return 0;
}
snd_soc_component_add(cmpnt);
static void snd_soc_component_add(struct snd_soc_component *component)
{
mutex_lock(&client_mutex);
gm1_snd_soc_component_add_unlocked(component);
static void gm1_snd_soc_component_add_unlocked(
struct snd_soc_component *component)
{
if (!component->write && !component->read) {
if (!component->regmap) {
component->regmap = dev_get_regmap(component->dev, NULL); <tag11>
}
}
list_add(&component->list, &component_list); <tag21>
INIT_LIST_HEAD(&component->dobj_list);
}
mutex_unlock(&client_mutex);
}
return 0;
}
return ret;
}
struct snd_soc_platform_driver *get_nx_pcm_platform(void)
{
return &nx_pcm_platform;
}
ret = devm_snd_soc_register_platform(&pdev->dev, get_nx_pcm_platform());
int devm_snd_soc_register_platform(struct device *dev,
const struct snd_soc_platform_driver *platform_drv)
{
struct device **ptr;
int ret;
ret = snd_soc_register_platform(dev, platform_drv);
int snd_soc_register_platform(struct device *dev,
const struct snd_soc_platform_driver *platform_drv)
{
struct snd_soc_platform *platform;
int ret;
platform = kzalloc(sizeof(struct snd_soc_platform), GFP_KERNEL); <tag22>
ret = snd_soc_add_platform(dev, platform, platform_drv);
int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform,
const struct snd_soc_platform_driver *platform_drv)
{
int ret;
ret = gm1_snd_soc_component_initialize(&platform->component,
&platform_drv->component_driver, dev);
static int gm1_snd_soc_component_initialize(
struct snd_soc_component *component,
const struct snd_soc_component_driver *driver, struct device *dev)
{
struct snd_soc_dapm_context *dapm;
component->name = fmt_single_name(dev, &component->id); <tag23>
component->dev = dev; <tag24>
component->driver = driver; <tag25>
INIT_LIST_HEAD(&component->dai_list);
mutex_init(&component->io_mutex);
return 0;
}
platform->dev = dev; <tag27>
platform->driver = platform_drv; <tag28>
mutex_lock(&client_mutex);
list_add(&platform->list, &platform_list); <tag29>
mutex_unlock(&client_mutex);
return 0;
}
return ret;
}
return ret;
}
dev_set_drvdata(&pdev->dev, par);
static inline void dev_set_drvdata(struct device *dev, void *data)
{
dev->driver_data = data; <tag30>
}
return ret;
}
static int __init es8316_init(void)
{
return i2c_add_driver(&es8316_i2c_driver);
}
static int es8316_i2c_probe(struct i2c_client *i2c, <tag32>
const struct i2c_device_id *id)
{
struct es8316_priv *es8316;
struct i2c_adapter *adapter = to_i2c_adapter(i2c->dev.parent);
int ret = -1;
i2c_check_functionality(adapter, I2C_FUNC_I2C);
es8316 = kzalloc(sizeof(struct es8316_priv), GFP_KERNEL); <tag31>
i2c_set_clientdata(i2c, es8316);
void i2c_set_clientdata(struct i2c_client *dev, void *data)
{
dev_set_drvdata(&dev->dev, data); <tag33>
}
ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_es8316, &es8316_dai, 1);
int snd_soc_register_codec(struct device *dev,
const struct snd_soc_codec_driver *codec_drv,
struct snd_soc_dai_driver *dai_drv,
int num_dai)
{
struct snd_soc_dapm_context *dapm;
struct snd_soc_codec *codec;
struct snd_soc_dai *dai;
int ret, i;
codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); <tag34>
codec->component.codec = codec; <tag35>
ret = gm1_snd_soc_component_initialize(&codec->component,
&codec_drv->component_driver, dev);
static int gm1_snd_soc_component_initialize(struct snd_soc_component *component,
const struct snd_soc_component_driver *driver, struct device *dev)
{
struct snd_soc_dapm_context *dapm;
component->name = fmt_single_name(dev, &component->id); <tag36>
component->dev = dev; <tag37>
component->driver = driver; <tag38>
INIT_LIST_HEAD(&component->dai_list);
mutex_init(&component->io_mutex);
return 0;
}
if (codec_drv->probe) {
codec->component.probe = snd_soc_codec_drv_probe;
}
if (codec_drv->remove) {
codec->component.remove = snd_soc_codec_drv_remove;
}
if (codec_drv->write) {
codec->component.write = snd_soc_codec_drv_write;
}
if (codec_drv->read) {
codec->component.read = snd_soc_codec_drv_read;
}
codec->dev = dev; <tag40>
codec->driver = codec_drv; <tag41>
codec->component.val_bytes = codec_drv->reg_word_size;
ret = snd_soc_register_dais(&codec->component, dai_drv, num_dai, false);
static int snd_soc_register_dais(struct snd_soc_component *component,
struct snd_soc_dai_driver *dai_drv, size_t count,
bool legacy_dai_naming)
{
struct device *dev = component->dev;
struct snd_soc_dai *dai;
unsigned int i;
int ret;
component->dai_drv = dai_drv; <tag42>
component->num_dai = count;
/*for (i = 0; i < count; i++)*/
i = 0;
{
dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL); <tag44>
{
dai->name = fmt_multiple_name(dev, &dai_drv[i]); <tag45>
{
dai->id = i;
}
}
dai->component = component; <tag46>
dai->dev = dev; <tag47>
dai->driver = &dai_drv[i]; <tag48>
list_add(&dai->list, &component->dai_list); <tag50>
}
return 0;
}
list_for_each_entry(dai, &codec->component.dai_list, list)
dai->codec = codec; <tag51>
mutex_lock(&client_mutex);
snd_soc_component_add_unlocked(&codec->component);
static void snd_soc_component_add_unlocked(struct snd_soc_component *component)
{
list_add(&component->list, &component_list); <tag55>
INIT_LIST_HEAD(&component->dobj_list);
}
list_add(&codec->list, &codec_list); <tag56>
mutex_unlock(&client_mutex);
return 0;
}
return ret;
}
static int nx_simple_card_probe(struct platform_device *pdev) <tag58>
{
struct simple_card_data *priv;
struct snd_soc_dai_link *dai_link;
struct device_node *np = pdev->dev.of_node;
struct device *dev = &pdev->dev;
int num_links, ret;
int i;
/* Get the number of DAI links */
if (np && of_get_child_by_name(np, "simple-audio-card,dai-link")) {
num_links = of_get_child_count(np);
}
/* Allocate the private data and the DAI link array */
priv = devm_kzalloc(dev,
sizeof(*priv) + sizeof(*dai_link) * num_links,
GFP_KERNEL); <tag59>
/* Init snd_soc_card */
priv->snd_card.owner = THIS_MODULE;
priv->snd_card.dev = dev; <tag60>
dai_link = priv->dai_link;
priv->snd_card.dai_link = dai_link;
priv->snd_card.num_links = num_links;
/* Get room for the other properties */
priv->dai_props = devm_kzalloc(dev,
sizeof(*priv->dai_props) * num_links,
GFP_KERNEL); <tag61>
for (i = 0; i < num_links; i++) {
priv->dai_props[i].gpio_hp_det = -ENOENT;
priv->dai_props[i].gpio_mic_det = -ENOENT;
}
if (np && of_device_is_available(np)) { //
ret = nx_simple_card_parse_of(np, priv);
static int nx_simple_card_parse_of(struct device_node *node,
struct simple_card_data *priv)
{
struct device *dev = simple_priv_to_dev(priv);
u32 val;
int ret;
/* Parse the card name from DT */
snd_soc_of_parse_card_name(&priv->snd_card, "simple-audio-card,name");
int snd_soc_of_parse_card_name(struct snd_soc_card *card,
const char *propname)
{
struct device_node *np;
int ret;
np = card->dev->of_node;
ret = of_property_read_string_index(np, propname, 0, &card->name); <tag62>
return 0;
}
/* Factor to mclk, used in hw_params() */
ret = of_property_read_u32(node, "simple-audio-card,mclk-fs", &val);
/* Single/Muti DAI link(s) & New style of DT node */
if (of_get_child_by_name(node, "simple-audio-card,dai-link")) { //
struct device_node *np = NULL;
int i = 0;
np = of_get_next_child(node, np);
ret = nx_simple_card_dai_link_of(np, priv,i, false);
static int nx_simple_card_dai_link_of(struct device_node *node,
struct simple_card_data *priv,
int idx,
bool is_top_level_node)
{
struct device *dev = simple_priv_to_dev(priv);
struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx);
#define simple_priv_to_link(priv, i) ((priv)->snd_card.dai_link + i)
struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx);
struct device_node *cpu = NULL;
struct device_node *plat = NULL;
struct device_node *codec = NULL;
enum of_gpio_flags flags;
char *name;
char prop[128];
char *prefix = "";
int ret, cpu_args;
u32 val;
snprintf(prop, sizeof(prop), "%scpu", prefix);
cpu = of_get_child_by_name(node, prop);
snprintf(prop, sizeof(prop), "%splat", prefix);
plat = of_get_child_by_name(node, prop);
snprintf(prop, sizeof(prop), "%scodec", prefix);
codec = of_get_child_by_name(node, prop);
of_property_read_u32(node, "mclk-fs", &val);
ret = gm1_nx_simple_card_sub_parse_of(cpu, &dai_props->cpu_dai,
&dai_link->cpu_of_node,
&dai_link->cpu_dai_name,
&cpu_args);
static int
gm1_nx_simple_card_sub_parse_of(struct device_node *np,
struct asoc_simple_dai *dai,
struct device_node **p_node,
const char **name,
int *args_count)
{
struct of_phandle_args args;
struct clk *clk;
u32 val;
int ret;
/*
* Get node via "sound-dai = <&phandle port>"
* it will be used as xxx_of_node on soc_bind_dai_link()
*/
ret = of_parse_phandle_with_args(np, "sound-dai",
"#sound-dai-cells", 0, &args);
*p_node = args.np;
if (args_count) {
*args_count = args.args_count;
}
/* Get dai->name */
ret = snd_soc_of_get_dai_name(np, name);
/*
* Parse dai->sysclk come from "clocks = <&xxx>"
* (if system has common clock)
* or "system-clock-frequency = <xxx>"
* or device's module clock.
*/
{
clk = of_clk_get(args.np, 0);
if (!IS_ERR(clk)) {
dai->sysclk = clk_get_rate(clk);
}
}
return 0;
}
ret = gm1_nx_simple_card_sub_parse_of(codec, &dai_props->codec_dai,
&dai_link->codec_of_node,
&dai_link->codec_dai_name, NULL); <tag69>
{
/* Assumes platform == cpu */
dai_link->platform_of_node = dai_link->cpu_of_node;
}
dai_props->gpio_hp_det = of_get_named_gpio_flags(node,
"hp-det-gpio", 0, &flags);
dai_props->gpio_hp_det_invert = !!(flags & OF_GPIO_ACTIVE_LOW);
dai_props->gpio_mic_det = of_get_named_gpio_flags(node,
"mic-det-gpio", 0, &flags);
dai_props->gpio_mic_det_invert = !!(flags & OF_GPIO_ACTIVE_LOW);
/* DAI link name is created from CPU/CODEC dai name */
name = devm_kzalloc(dev,
strlen(dai_link->cpu_dai_name) +
strlen(dai_link->codec_dai_name) + 2,
GFP_KERNEL);
/* cpu name c0055000.i2s, codec name ES8316 HiFi */
sprintf(name, "%s-%s", dai_link->cpu_dai_name,
dai_link->codec_dai_name);
/* name c0055000.i2s-ES8316 HiFi */
dai_link->name = dai_link->stream_name = name; <tag70>
dai_link->ops = &nx_simple_card_ops;
dai_link->init = nx_simple_card_dai_init;
dai_link_of_err:
of_node_put(cpu);
of_node_put(codec);
return ret;
}
}
return 0;
}
}
snd_soc_card_set_drvdata(&priv->snd_card, priv); <tag71>
void snd_soc_card_set_drvdata(struct snd_soc_card *card,
void *data)
{
card->drvdata = data;
}
ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card);
int devm_snd_soc_register_card(struct device *dev, struct snd_soc_card *card)
{
struct snd_soc_card **ptr;
int ret;
ptr = devres_alloc(devm_card_release, sizeof(*ptr), GFP_KERNEL); <tag73>
ret = snd_soc_register_card(card);
int snd_soc_register_card(struct snd_soc_card *card)
{
int i, j, ret;
/*for (i = 0; i < card->num_links; i++)*/
i = 0;
{
struct snd_soc_dai_link *link = &card->dai_link[i];
ret = snd_soc_init_multicodec(card, link);
static int snd_soc_init_multicodec(struct snd_soc_card *card,
struct snd_soc_dai_link *dai_link)
{
/* Legacy codec/codec_dai link is a single entry in multicodec */
if (dai_link->codec_name || dai_link->codec_of_node ||
dai_link->codec_dai_name)
{
dai_link->num_codecs = 1;
dai_link->codecs = devm_kzalloc(card->dev,
sizeof(struct snd_soc_dai_link_component),
GFP_KERNEL); <tag74>
}
return 0;
}
}
dev_set_drvdata(card->dev, card); <tag75>
snd_soc_initialize_card_lists(card);
static inline void snd_soc_initialize_card_lists(struct snd_soc_card *card)
{
INIT_LIST_HEAD(&card->codec_dev_list);
INIT_LIST_HEAD(&card->widgets);
INIT_LIST_HEAD(&card->paths);
INIT_LIST_HEAD(&card->dapm_list);
}
card->rtd = devm_kzalloc(card->dev,
sizeof(struct snd_soc_pcm_runtime) *
(card->num_links + card->num_aux_devs),
GFP_KERNEL); <tag76>
card->num_rtd = 0;
card->rtd_aux = &card->rtd[card->num_links]; <tag77>
/*for (i = 0; i < card->num_links; i++)*/
i = 0;
{
card->rtd[i].card = card; <tag78>
card->rtd[i].dai_link = &card->dai_link[i]; <tag79>
card->rtd[i].codec_dais = devm_kzalloc(card->dev,
sizeof(struct snd_soc_dai *) *
(card->rtd[i].dai_link->num_codecs),
GFP_KERNEL); <tag80>
}
INIT_LIST_HEAD(&card->dapm_dirty);
INIT_LIST_HEAD(&card->dobj_list);
card->instantiated = 0;
mutex_init(&card->mutex);
mutex_init(&card->dapm_mutex);
ret = snd_soc_instantiate_card(card);
static int snd_soc_instantiate_card(struct snd_soc_card *card)
{
struct snd_soc_codec *codec;
int ret, i, order;
mutex_lock(&client_mutex);
mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_INIT);
/* bind DAIs */
/*for (i = 0; i < card->num_links; i++)*/
i = 0;
ret = soc_bind_dai_link(card, i);
static int soc_bind_dai_link(struct snd_soc_card *card, int num)
{
struct snd_soc_dai_link *dai_link = &card->dai_link[num];
struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
struct snd_soc_dai_link_component *codecs = dai_link->codecs;
struct snd_soc_dai_link_component cpu_dai_component;
struct snd_soc_dai **codec_dais = rtd->codec_dais;
struct snd_soc_platform *platform;
const char *platform_name;
int i;
cpu_dai_component.name = dai_link->cpu_name;
cpu_dai_component.of_node = dai_link->cpu_of_node;
cpu_dai_component.dai_name = dai_link->cpu_dai_name;
rtd->cpu_dai = gm1_snd_soc_find_dai(&cpu_dai_component); <tag81>
static struct snd_soc_dai *gm1_snd_soc_find_dai(
const struct snd_soc_dai_link_component *dlc)
{
pr_err("%s:in %d.\n",__func__,__LINE__);
struct snd_soc_component *component;
struct snd_soc_dai *dai;
struct device_node *component_of_node;
lockdep_assert_held(&client_mutex);
/* Find CPU DAI from registered DAIs*/
component = list_first_entry(&component_list, typeof(*component), list);
component = list_next_entry(component, list);
{
component_of_node = component->dev->of_node;
dai = list_first_entry(&component->dai_list, typeof(*dai), list);
{
return dai;
}
}
return NULL;
}
rtd->num_codecs = dai_link->num_codecs;
/* Find CODEC from registered CODECs */
/*for (i = 0; i < rtd->num_codecs; i++)*/
i = 0;
{
codec_dais[i] = snd_soc_find_dai(&codecs[i]);
static struct snd_soc_dai *snd_soc_find_dai(
const struct snd_soc_dai_link_component *dlc)
{
struct snd_soc_component *component;
struct snd_soc_dai *dai;
struct device_node *component_of_node;
lockdep_assert_held(&client_mutex);
/* Find CPU DAI from registered DAIs*/
component = list_first_entry(&component_list, typeof(*component), list);
{
component_of_node = component->dev->of_node;
dai = list_first_entry(&component->dai_list, typeof(*dai), list);
{
return dai;
}
}
return NULL;
}
}
/* Single codec links expect codec and codec_dai in runtime data */
rtd->codec_dai = codec_dais[0]; <tag82>
rtd->codec = rtd->codec_dai->codec; <tag83>
/* if there's no platform we match on the empty platform */
platform_name = dai_link->platform_name;
/* find one from the set of registered platforms */
platform = list_first_entry(&platform_list, typeof(*platform), list);
{
rtd->platform = platform; <tag84>
}
card->num_rtd++;
return 0;
}
/* card bind complete so register a sound card */
ret = snd_card_new(card->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
card->owner, 0, &card->snd_card);
int snd_card_new(struct device *parent, int idx, const char *xid,
struct module *module, int extra_size,
struct snd_card **card_ret)
{
struct snd_card *card;
int err;
*card_ret = NULL;
card = kzalloc(sizeof(*card) + extra_size, GFP_KERNEL); <tag86>
err = 0;
mutex_lock(&snd_card_mutex);
if (idx < 0) /* first check the matching module-name slot */ { //
idx = get_slot_from_bitmask(idx, module_slot_match, module);
}
if (idx < 0) /* if not matched, assign an empty slot */ { //
idx = get_slot_from_bitmask(idx, check_empty_slot, module);
}
set_bit(idx, snd_cards_lock); /* lock it */
if (idx >= snd_ecards_limit) { //
snd_ecards_limit = idx + 1; /* increase the limit */
}
mutex_unlock(&snd_card_mutex);
card->dev = parent; <tag87>
card->number = idx;
card->module = module;
INIT_LIST_HEAD(&card->devices);
init_rwsem(&card->controls_rwsem);
rwlock_init(&card->ctl_files_rwlock);
mutex_init(&card->user_ctl_lock);
INIT_LIST_HEAD(&card->controls);
INIT_LIST_HEAD(&card->ctl_files);
spin_lock_init(&card->files_lock);
INIT_LIST_HEAD(&card->files_list);
mutex_init(&card->power_lock);
init_waitqueue_head(&card->power_sleep);
device_initialize(&card->card_dev);
card->card_dev.parent = parent; <tag88>
card->card_dev.class = sound_class;
card->card_dev.release = release_card_device;
card->card_dev.groups = card->dev_groups;
card->dev_groups[0] = &card_dev_attr_group;
err = kobject_set_name(&card->card_dev.kobj, "card%d", idx);
/* the control interface cannot be accessed from the user space until */
/* snd_cards_bitmask and snd_cards are set with snd_card_register */
err = snd_ctl_create(card);
int snd_ctl_create(struct snd_card *card)
{
static struct snd_device_ops ops = {
.dev_free = snd_ctl_dev_free,
.dev_register = snd_ctl_dev_register,
.dev_disconnect = snd_ctl_dev_disconnect,
};
int err;
snd_device_initialize(&card->ctl_dev, card);
void snd_device_initialize(struct device *dev, struct snd_card *card)
{
device_initialize(dev);
if (card) { /* all into here*/
dev->parent = &card->card_dev; <tag89>
}
dev->class = sound_class;
dev->release = default_release;
}
dev_set_name(&card->ctl_dev, "controlC%d", card->number);
//err = snd_device_new(card, SNDRV_DEV_CONTROL, card, &ops);
err = gm1_snd_device_new(card, SNDRV_DEV_CONTROL, card, &ops);
int gm1_snd_device_new(struct snd_card *card, enum snd_device_type type,
void *device_data, struct snd_device_ops *ops)
{
struct snd_device *dev;
struct list_head *p;
dev = kzalloc(sizeof(*dev), GFP_KERNEL); <tag90>
INIT_LIST_HEAD(&dev->list);
dev->card = card; <tag91>
dev->type = type;
dev->state = SNDRV_DEV_BUILD;
dev->device_data = device_data; <tag92>
dev->ops = ops;
/* insert the entry in an incrementally sorted list */
p = (&card->devices)->prev;
list_add(&dev->list, p); <tag93>
return 0;
}
return err;
}
*card_ret = card; <tag95>
return 0;
}
card->dapm.bias_level = SND_SOC_BIAS_OFF;
card->dapm.dev = card->dev; <tag97>
card->dapm.card = card; <tag99>
list_add(&card->dapm.list, &card->dapm_list); <tag100>
/* deferred resume work */
INIT_WORK(&card->deferred_resume_work, soc_resume_deferred);
/* probe all components used by DAI links on this card */
/*for (order = SND_SOC_COMP_ORDER_FIRST; order <= 0;order++)*/
order = 0;
/*for (i = 0; i < card->num_links; i++)*/
i = 0;
ret = soc_probe_link_components(card, i, order);
static int soc_probe_link_components(struct snd_soc_card *card, int num,
int order)
{
struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
struct snd_soc_platform *platform = rtd->platform;
struct snd_soc_component *component;
int i, ret;
/* probe the CODEC-side components */
i = 0;
component = rtd->codec_dais[i]->component; <obj14>
ret = soc_probe_component(card, component);
static int soc_probe_component(struct snd_soc_card *card,
struct snd_soc_component *component)
{
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); <obj29>
static inline struct snd_soc_dapm_context *snd_soc_component_get_dapm(
struct snd_soc_component *component)
{
return &component->dapm;
}
struct snd_soc_dai *dai;
int ret;
try_module_get(component->dev->driver->owner);
component->card = card; <tag102>
dapm->card = card; <tag101>
if (component->probe) {
/* snd_soc_codec_drv_probe */
ret = component->probe(component);
static int snd_soc_codec_drv_probe(struct snd_soc_component *component)
{
struct snd_soc_codec *codec = snd_soc_component_to_codec(component); <obj10>
/* es8316_probe */
return codec->driver->probe(codec);
/* 通过i2c 初始化 es8316 */
static int es8316_probe(struct snd_soc_codec *codec)
{
int ret = 0;
codec->hw_write = (hw_write_t)i2c_master_send;
codec->control_data =
container_of(codec->dev, struct i2c_client, dev);<tag103>
es8316_codec = codec;
es8316_init_regs(codec);
es8316_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
static int es8316_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
switch (level) {
case SND_SOC_BIAS_STANDBY:
snd_soc_write(codec, ES8316_CLKMGR_CLKSW_REG01, 0x7F);
snd_soc_write(codec, ES8316_SYS_PDN_REG0D, 0x00);
snd_soc_write(codec, ES8316_ADC_PDN_LINSEL_REG22, 0x20);
{
/* VPP SET AND ZERO L/R,MONO SET */
snd_soc_write(codec, ES8316_DAC_SET3_REG32, 0x08);
}
snd_soc_write(codec, ES8316_DAC_PDN_REG2F, 0x00);
snd_soc_write(codec, ES8316_HPMIX_SWITCH_REG14, 0x88);
snd_soc_update_bits(codec, ES8316_HPMIX_PDN_REG15, 0x33, 0x00);
snd_soc_write(codec, ES8316_HPMIX_VOL_REG16, 0xBB);
snd_soc_write(codec, ES8316_CPHP_PDN2_REG1A, 0x10);
snd_soc_write(codec, ES8316_CPHP_LDOCTL_REG1B, 0x30);
snd_soc_write(codec, ES8316_CPHP_PDN1_REG19, 0x03);
snd_soc_write(codec, ES8316_CPHP_ICAL_VOL_REG18, 0x00);
snd_soc_write(codec, ES8316_RESET_REG00, 0xC0);
{
//es8316_spk_on(0);
/* R OUTEN */
snd_soc_write(codec, ES8316_CPHP_OUTEN_REG17, 0x06);
}
break;
}
dapm->bias_level = level;
return 0;
}
return ret;
}
}
}
return 0;
}
return 0;
}
/* probe all DAI links on this card */
/*for (order = 2; order <= SND_SOC_COMP_ORDER_LAST;order++)*/
order = 2;
/*for (i = 0; i < card->num_links; i++)*/
i = 0;
ret = soc_probe_link_dais(card, i, order);
static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)
{
struct snd_soc_dai_link *dai_link = &card->dai_link[num];
struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int i, ret;
/* set default power off timeout */
rtd->pmdown_time = pmdown_time;
ret = soc_post_component_init(rtd, dai_link->name);
static int soc_post_component_init(struct snd_soc_pcm_runtime *rtd,
const char *name)
{
int ret = 0;
/* register the rtd device */
rtd->dev = kzalloc(sizeof(struct device), GFP_KERNEL); <tag104>
device_initialize(rtd->dev);
rtd->dev->parent = rtd->card->dev; <tag105>
rtd->dev->release = rtd_release;
rtd->dev->groups = soc_dev_attr_groups;
dev_set_name(rtd->dev, "%s", name);
dev_set_drvdata(rtd->dev, rtd); <tag106>
mutex_init(&rtd->pcm_mutex);
INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients);
INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_CAPTURE].be_clients);
INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_PLAYBACK].fe_clients);
INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_CAPTURE].fe_clients);
ret = device_add(rtd->dev);
rtd->dev_registered = 1;
return 0;
}
if (!dai_link->params) {
/* create the pcm */
ret = soc_new_pcm(rtd, num);
int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
{
struct snd_soc_platform *platform = rtd->platform;
struct snd_soc_dai *codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_pcm *pcm;
char new_name[64];
int ret = 0, playback = 0, capture = 0;
int i;
{
i = 0;
{
codec_dai = rtd->codec_dais[i];
if (codec_dai->driver->playback.channels_min) {
playback = 1;
}
if (codec_dai->driver->capture.channels_min) {
capture = 1;
}
}
capture = capture && cpu_dai->driver->capture.channels_min;
playback = playback && cpu_dai->driver->playback.channels_min;
}
/* create the PCM */
{
snprintf(new_name, sizeof(new_name), "%s %s-%d",
rtd->dai_link->stream_name,
(rtd->num_codecs > 1) ?
"multicodec" : rtd->codec_dai->name, num);
}
ret = snd_pcm_new(rtd->card->snd_card, new_name, num, playback,
capture, &pcm);
int snd_pcm_new(struct snd_card *card, const char *id, int device,
int playback_count, int capture_count, struct snd_pcm **rpcm)
{
return _snd_pcm_new(card, id, device, playback_count, capture_count,
false, rpcm);
static int _snd_pcm_new(struct snd_card *card, const char *id, int device,
int playback_count, int capture_count, bool internal,
struct snd_pcm **rpcm)
{
struct snd_pcm *pcm;
int err;
static struct snd_device_ops ops = {
.dev_free = snd_pcm_dev_free,
.dev_register = snd_pcm_dev_register,
.dev_disconnect = snd_pcm_dev_disconnect,
};
if (rpcm) {
*rpcm = NULL;
}
pcm = kzalloc(sizeof(*pcm), GFP_KERNEL); <tag107>
pcm->card = card; <tag108>
pcm->device = device;
pcm->internal = internal;
mutex_init(&pcm->open_mutex);
init_waitqueue_head(&pcm->open_wait);
INIT_LIST_HEAD(&pcm->list);
err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK, playback_count);
int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count)
{
int idx, err;
struct snd_pcm_str *pstr = &pcm->streams[stream];
struct snd_pcm_substream *substream, *prev;
pstr->stream = stream;
pstr->pcm = pcm; <tag110>
pstr->substream_count = substream_count;
snd_device_initialize(&pstr->dev, pcm->card);
void snd_device_initialize(struct device *dev, struct snd_card *card)
{
device_initialize(dev);
if (card) { /* all into here*/
dev->parent = &card->card_dev; <tag111>
}
dev->class = sound_class;
dev->release = default_release;
}
pstr->dev.groups = pcm_dev_attr_groups;
dev_set_name(&pstr->dev, "pcmC%iD%i%c", pcm->card->number, pcm->device,
stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c');
prev = NULL;
/*for (idx = 0, prev = NULL; idx < substream_count; idx++)*/
idx = 0;
{
substream = kzalloc(sizeof(*substream), GFP_KERNEL); <tag112>
substream->pcm = pcm; <tag113>
substream->pstr = pstr; <tag114>
substream->number = idx;
substream->stream = stream;
sprintf(substream->name, "subdevice #%i", idx);
substream->buffer_bytes_max = UINT_MAX;
if (prev == NULL) {
pstr->substream = substream; <tag115>
}
substream->group = &substream->self_group;
spin_lock_init(&substream->self_group.lock);
mutex_init(&substream->self_group.mutex);
INIT_LIST_HEAD(&substream->self_group.substreams);
atomic_set(&substream->mmap_count, 0);
}
return 0;
}
gm1_snd_device_new(card, SNDRV_DEV_PCM, pcm, &ops);
int gm1_snd_device_new(struct snd_card *card, enum snd_device_type type,
void *device_data, struct snd_device_ops *ops)
{
struct snd_device *dev;
struct list_head *p;
dev = kzalloc(sizeof(*dev), GFP_KERNEL); <tag116>
INIT_LIST_HEAD(&dev->list);
dev->card = card; <tag117>
dev->type = type;
dev->state = SNDRV_DEV_BUILD;
dev->device_data = device_data; <tag118>
dev->ops = ops;
/* insert the entry in an incrementally sorted list */
p = (&card->devices)->prev;
list_add(&dev->list, p); <tag119>
return 0;
}
if (rpcm) {
*rpcm = pcm;
}
return 0;
}
}
/* DAPM dai link stream work */
INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);
pcm->nonatomic = rtd->dai_link->nonatomic;
rtd->pcm = pcm; <tag120>
pcm->private_data = rtd; <tag121>
/* ASoC PCM operations */
{ //
rtd->ops.open = soc_pcm_open;
rtd->ops.hw_params = soc_pcm_hw_params;
rtd->ops.prepare = soc_pcm_prepare;
rtd->ops.trigger = soc_pcm_trigger;
rtd->ops.hw_free = soc_pcm_hw_free;
rtd->ops.close = soc_pcm_close;
rtd->ops.pointer = soc_pcm_pointer;
rtd->ops.ioctl = soc_pcm_ioctl;
}
if (playback) {
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &rtd->ops);
void snd_pcm_set_ops(struct snd_pcm *pcm, int direction,
const struct snd_pcm_ops *ops)
{
struct snd_pcm_str *stream = &pcm->streams[direction];
struct snd_pcm_substream *substream;
substream = stream->substream;
{
substream->ops = ops;
}
}
}
if (platform->driver->pcm_new) { //
/* nx_pcm_new */
ret = platform->driver->pcm_new(rtd);
static int nx_pcm_new(struct snd_soc_pcm_runtime *runtime)
{
struct snd_card *card = runtime->card->snd_card;
struct snd_pcm *pcm = runtime->pcm;
int ret = 0;
if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { //
ret = nx_pcm_preallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK);
static int nx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
{
struct snd_pcm_substream *substream =
pcm->streams[stream].substream; <obj38>
struct snd_dma_buffer *buf = &substream->dma_buffer;
size_t size = nx_pcm_hardware.buffer_bytes_max;
buf->dev.type = SNDRV_DMA_TYPE_DEV;
buf->dev.dev = pcm->card->dev; <tag122>
buf->private_data = NULL;
buf->bytes = size;
buf->area = dma_alloc_coherent(buf->dev.dev, size, &buf->addr,
GFP_KERNEL); <tag123>
return 0;
}
}
return 0;
}
}
pcm->private_free = platform->driver->pcm_free;
out:
return ret;
}
}
return 0;
}
snprintf(card->snd_card->shortname, sizeof(card->snd_card->shortname),
"%s", card->name);
snprintf(card->snd_card->longname, sizeof(card->snd_card->longname),
"%s", card->long_name ? card->long_name : card->name);
snprintf(card->snd_card->driver, sizeof(card->snd_card->driver),
"%s", card->driver_name ? card->driver_name : card->name);
ret = snd_card_register(card->snd_card);
int snd_card_register(struct snd_card *card)
{
int err;
if (!card->registered) {
err = device_add(&card->card_dev);
card->registered = true;
}
snd_device_register_all(card);
int snd_device_register_all(struct snd_card *card)
{
struct snd_device *dev;
int err;
dev = list_first_entry(&card->devices, typeof(*dev), list);
err = gm1___snd_device_register(dev);
static int gm1___snd_device_register(struct snd_device *dev)
{
if (dev->state == SNDRV_DEV_BUILD) {
if (dev->ops->dev_register) {
/* snd_ctl_dev_register */
int err = dev->ops->dev_register(dev);
static int snd_ctl_dev_register(struct snd_device *device)
{
struct snd_card *card = device->device_data;
//snd_register_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1,
return gm1_snd_register_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1,
&snd_ctl_f_ops, card, &card->ctl_dev);
int gm1_snd_register_device(int type, struct snd_card *card, int dev,
const struct file_operations *f_ops,
void *private_data, struct device *device)
{
int minor;
int err = 0;
struct snd_minor *preg;
preg = kmalloc(sizeof *preg, GFP_KERNEL); <tag124>
preg->type = type;
preg->card = card ? card->number : -1;
preg->device = dev;
preg->f_ops = f_ops;
preg->private_data = private_data; <tag125>
preg->card_ptr = card;
mutex_lock(&sound_mutex);
minor = snd_find_free_minor(type, card, dev);
preg->dev = device; <tag126>
device->devt = MKDEV(major, minor);
err = device_add(device);
snd_minors[minor] = preg; <tag127>
mutex_unlock(&sound_mutex);
return err;
}
}
}
dev->state = SNDRV_DEV_REGISTERED;
}
return 0;
}
dev = list_next_entry(dev, list);
err = __snd_device_register(dev);
static int __snd_device_register(struct snd_device *dev)
{
if (dev->state == SNDRV_DEV_BUILD) {
if (dev->ops->dev_register) {
/* snd_pcm_dev_register */
int err = dev->ops->dev_register(dev);
static int snd_pcm_dev_register(struct snd_device *device)
{
int cidx, err;
struct snd_pcm_substream *substream;
struct snd_pcm_notify *notify;
struct snd_pcm *pcm;
pcm = device->device_data;
mutex_lock(&register_mutex);
/*for (cidx = 0; cidx < 2; cidx++)*/
cidx = 0;
int devtype = -1;
switch (cidx) {
case SNDRV_PCM_STREAM_PLAYBACK:
devtype = SNDRV_DEVICE_TYPE_PCM_PLAYBACK;
break;
}
/* register pcm */
err = snd_register_device(devtype, pcm->card, pcm->device,
&snd_pcm_f_ops[cidx], pcm,
&pcm->streams[cidx].dev);
int snd_register_device(int type, struct snd_card *card, int dev,
const struct file_operations *f_ops,
void *private_data, struct device *device)
{
int minor;
int err = 0;
struct snd_minor *preg;
preg = kmalloc(sizeof *preg, GFP_KERNEL); <tag128>
preg->type = type;
preg->card = card ? card->number : -1;
preg->device = dev;
preg->f_ops = f_ops;
preg->private_data = private_data; <tag129>
preg->card_ptr = card;
mutex_lock(&sound_mutex);
minor = snd_find_free_minor(type, card, dev);
preg->dev = device; <tag130>
device->devt = MKDEV(major, minor);
err = device_add(device);
snd_minors[minor] = preg; <tag131>
mutex_unlock(&sound_mutex);
return err;
}
unlock:
mutex_unlock(&register_mutex);
return err;
}
}
dev->state = SNDRV_DEV_REGISTERED;
}
return 0;
}
return 0;
}
mutex_lock(&snd_card_mutex);
snd_cards[card->number] = card;
mutex_unlock(&snd_card_mutex);
return 0;
}
card->instantiated = 1;
mutex_unlock(&card->mutex);
mutex_unlock(&client_mutex);
return 0;
}
return ret;
}
if (ret == 0) {
*ptr = card;
devres_add(dev, ptr);
}
return ret;
}
/*if (ret >= 0)*/
return ret;
}
#################snd open#########
snd_open_device(filename, fmode);
snd_open
static int snd_open(struct inode *inode, struct file *file) <tag149>
{
unsigned int minor = iminor(inode);
struct snd_minor *mptr = NULL;
const struct file_operations *new_fops;
int err = 0;
mutex_lock(&sound_mutex);
mptr = snd_minors[minor];
new_fops = fops_get(mptr->f_ops);
mutex_unlock(&sound_mutex);
replace_fops(file, new_fops);
if (file->f_op->open) {
/* snd_ctl_open */
/* snd_pcm_playback_open */
err = file->f_op->open(inode, file);
static int snd_pcm_playback_open(struct inode *inode, struct file *file)
{
struct snd_pcm *pcm;
int err = nonseekable_open(inode, file);
pcm = snd_lookup_minor_data(iminor(inode),
SNDRV_DEVICE_TYPE_PCM_PLAYBACK);
err = snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_PLAYBACK);
static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream)
{
int err;
wait_queue_t wait;
try_module_get(pcm->card->module);
init_waitqueue_entry(&wait, current);
add_wait_queue(&pcm->open_wait, &wait);
mutex_lock(&pcm->open_mutex);
err = snd_pcm_open_file(file, pcm, stream);
static int snd_pcm_open_file(struct file *file,
struct snd_pcm *pcm,
int stream)
{
struct snd_pcm_file *pcm_file;
struct snd_pcm_substream *substream;
int err;
err = snd_pcm_open_substream(pcm, stream, file, &substream);
int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
struct file *file,
struct snd_pcm_substream **rsubstream)
{
struct snd_pcm_substream *substream;
int err;
err = snd_pcm_attach_substream(pcm, stream, file, &substream);
int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
struct file *file,
struct snd_pcm_substream **rsubstream)
{
struct snd_pcm_str * pstr;
struct snd_pcm_substream *substream;
struct snd_pcm_runtime *runtime;
struct snd_card *card;
size_t size;
*rsubstream = NULL;
pstr = &pcm->streams[stream]; <obj37>
card = pcm->card;
substream = pstr->substream; <obj38>
runtime = kzalloc(sizeof(*runtime), GFP_KERNEL); <tag132>
size = PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status));
runtime->status = snd_malloc_pages(size, GFP_KERNEL); <tag133>
memset((void*)runtime->status, 0, size);
size = PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control));
runtime->control = snd_malloc_pages(size, GFP_KERNEL); <tag134>
memset((void*)runtime->control, 0, size);
init_waitqueue_head(&runtime->sleep);
init_waitqueue_head(&runtime->tsleep);
runtime->status->state = SNDRV_PCM_STATE_OPEN;
substream->runtime = runtime; <tag135>
substream->private_data = pcm->private_data; <gag136>
substream->ref_count = 1;
substream->f_flags = file->f_flags;
substream->pid = get_pid(task_pid(current));
pstr->substream_opened++;
*rsubstream = substream;
return 0;
}
err = snd_pcm_hw_constraints_init(substream);
/* soc_pcm_open */
err = substream->ops->open(substream);
static int soc_pcm_open(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_platform *platform = rtd->platform;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai; <obj20>
struct snd_soc_dai *codec_dai;
const char *codec_dai_name = "multicodec";
int i, ret = 0;
mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
/* startup the audio subsystem */
if (cpu_dai->driver->ops && cpu_dai->driver->ops->startup) {
/* nx_i2s_startup */
ret = cpu_dai->driver->ops->startup(substream, cpu_dai);
static int nx_i2s_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct nx_i2s_snd_param *par = snd_soc_dai_get_drvdata(dai); <obj7>
void *snd_soc_dai_get_drvdata(struct snd_soc_dai *dai)
{
return dev_get_drvdata(dai->dev);
void *dev_get_drvdata(const struct device *dev)
{
return dev->driver_data;
}
}
struct nx_pcm_dma_param *dmap
= SNDRV_PCM_STREAM_PLAYBACK == substream->stream ?
&par->play : &par->capt;
snd_soc_dai_set_dma_data(dai, substream, dmap);
void snd_soc_dai_set_dma_data(struct snd_soc_dai *dai,
const struct snd_pcm_substream *ss,
void *data)
{
if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
dai->playback_dma_data = data; <tag138>
}
return 0;
}
}
if (platform->driver->ops && platform->driver->ops->open) {
/* nx_pcm_open */
ret = platform->driver->ops->open(substream);
static int nx_pcm_open(struct snd_pcm_substream *substream) <obj38>
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
static struct snd_pcm_hardware *hw = &nx_pcm_hardware;
struct nx_pcm_runtime_data *prtd;
int ret = 0;
prtd = kzalloc(sizeof(struct nx_pcm_runtime_data), GFP_KERNEL); <tag141>
runtime->private_data = prtd; <tag140>
prtd->dev = substream->pcm->card->dev; <tag142>
prtd->dma_param = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); <tag143>
void *snd_soc_dai_get_dma_data(const struct snd_soc_dai *dai,
const struct snd_pcm_substream *ss)
{
return (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
dai->playback_dma_data : dai->capture_dma_data;
}
ret = nx_pcm_dma_request_channel(prtd, substream->stream);
static int nx_pcm_dma_request_channel(void *runtime_data, int stream)
{
struct nx_pcm_runtime_data *prtd = runtime_data;
dma_cap_mask_t mask;
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
dma_cap_set(DMA_CYCLIC, mask);
prtd->dma_chan
= dma_request_slave_channel_compat(mask,
prtd->dma_param->dma_filter,
prtd->dma_param->dma_ch_name,
prtd->dma_param->dev,
(stream ==
SNDRV_PCM_STREAM_PLAYBACK)
? "tx":"rx"); <tag144>
return 0;
}
{
hw->period_bytes_max = PERIOD_BYTES_MAX;
}
return snd_soc_set_runtime_hwparams(substream, &nx_pcm_hardware); <tag145>
int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
const struct snd_pcm_hardware *hw)
{
struct snd_pcm_runtime *runtime = substream->runtime;
runtime->hw.info = hw->info;
runtime->hw.formats = hw->formats;
runtime->hw.period_bytes_min = hw->period_bytes_min;
runtime->hw.period_bytes_max = hw->period_bytes_max;
runtime->hw.periods_min = hw->periods_min;
runtime->hw.periods_max = hw->periods_max;
runtime->hw.buffer_bytes_max = hw->buffer_bytes_max;
runtime->hw.fifo_size = hw->fifo_size;
return 0;
}
}
}
/* Check that the codec and cpu DAIs are compatible */
soc_pcm_init_runtime_hw(substream);
static void soc_pcm_init_runtime_hw(struct snd_pcm_substream *substream) <tag146>
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_pcm_hardware *hw = &runtime->hw;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai_driver *cpu_dai_drv = rtd->cpu_dai->driver;
struct snd_soc_dai_driver *codec_dai_drv;
struct snd_soc_pcm_stream *codec_stream;
struct snd_soc_pcm_stream *cpu_stream;
unsigned int chan_min = 0, chan_max = UINT_MAX;
unsigned int rate_min = 0, rate_max = UINT_MAX;
unsigned int rates = UINT_MAX;
u64 formats = ULLONG_MAX;
int i;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
cpu_stream = &cpu_dai_drv->playback;
/* first calculate min/max only for CODECs in the DAI link */
/*for (i = 0; i < rtd->num_codecs; i++)*/
i = 0;
{
codec_dai_drv = rtd->codec_dais[i]->driver;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
codec_stream = &codec_dai_drv->playback;
chan_min = max(chan_min, codec_stream->channels_min);
chan_max = min(chan_max, codec_stream->channels_max);
rate_min = max(rate_min, codec_stream->rate_min);
rate_max = min_not_zero(rate_max, codec_stream->rate_max);
formats &= codec_stream->formats;
rates = snd_pcm_rate_mask_intersect(codec_stream->rates, rates);
}
hw->channels_min = max(chan_min, cpu_stream->channels_min);
hw->channels_max = min(chan_max, cpu_stream->channels_max);
if (hw->formats) {
hw->formats &= formats & cpu_stream->formats;
}
hw->rates = snd_pcm_rate_mask_intersect(rates, cpu_stream->rates);
hw->rate_min = max(hw->rate_min, cpu_stream->rate_min);
hw->rate_min = max(hw->rate_min, rate_min);
hw->rate_max = min_not_zero(hw->rate_max, cpu_stream->rate_max);
hw->rate_max = min_not_zero(hw->rate_max, rate_max);
}
mutex_unlock(&rtd->pcm_mutex);
return 0;
}
substream->hw_opened = 1;
err = snd_pcm_hw_constraints_complete(substream);
*rsubstream = substream;
return 0;
}
pcm_file = kzalloc(sizeof(*pcm_file), GFP_KERNEL); <tag147>
pcm_file->substream = substream; <tag148>
if (substream->ref_count == 1) {
substream->file = pcm_file; <tag150>
substream->pcm_release = pcm_release_private;
}
file->private_data = pcm_file; <tag151>
return 0;
}
remove_wait_queue(&pcm->open_wait, &wait);
mutex_unlock(&pcm->open_mutex);
return err;
}
return err;
}
}
return err;
}
ioctl(fd, SNDRV_PCM_IOCTL_INFO, &info)
int snd_pcm_info_user(struct snd_pcm_substream *substream,
struct snd_pcm_info __user * _info)
{
struct snd_pcm_info *info;
int err;
info = kmalloc(sizeof(*info), GFP_KERNEL);
err = snd_pcm_info(substream, info);
int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info)
{
pr_err("%s:in %d.\n",__func__,__LINE__);
struct snd_pcm_runtime *runtime;
struct snd_pcm *pcm = substream->pcm;
struct snd_pcm_str *pstr = substream->pstr;
memset(info, 0, sizeof(*info));
info->card = pcm->card->number;
info->device = pcm->device;
info->stream = substream->stream;
info->subdevice = substream->number;
strlcpy(info->id, pcm->id, sizeof(info->id));
strlcpy(info->name, pcm->name, sizeof(info->name));
info->dev_class = pcm->dev_class;
info->dev_subclass = pcm->dev_subclass;
info->subdevices_count = pstr->substream_count;
info->subdevices_avail = pstr->substream_count - pstr->substream_opened;
strlcpy(info->subname, substream->name, sizeof(info->subname));
runtime = substream->runtime;
return 0;
}
if (err >= 0) {
copy_to_user(_info, info, sizeof(*info));
}
kfree(info);
return err;
}
ioctl(hw->fd, SNDRV_PCM_IOCTL_SYNC_PTR, hw->sync_ptr);
snd_pcm_ioctl_sync_ptr_compat
######################snd_pcm_hw_params ###########
ioctl(pcm_hw->fd, SNDRV_PCM_IOCTL_HW_REFINE, params); <tag29> <ioctl>
snd_pcm_ioctl_compat
snd_pcm_ioctl_hw_params_compat
snd_pcm_hw_refine
ioctl(pcm_hw->fd, SNDRV_PCM_IOCTL_HW_PARAMS, params); <tag49> <ioctl>
static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_pcm_runtime *runtime;
int err, usecs;
unsigned int bits;
snd_pcm_uframes_t frames;
runtime = substream->runtime; <obj59>
atomic_read(&substream->mmap_count);
params->rmask = ~0U;
err = snd_pcm_hw_params_choose(substream, params);
int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm,
struct snd_pcm_hw_params *params)
{
static int vars[] = {
SNDRV_PCM_HW_PARAM_ACCESS,
SNDRV_PCM_HW_PARAM_FORMAT,
SNDRV_PCM_HW_PARAM_SUBFORMAT,
SNDRV_PCM_HW_PARAM_CHANNELS,
SNDRV_PCM_HW_PARAM_RATE,
SNDRV_PCM_HW_PARAM_PERIOD_TIME,
SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
SNDRV_PCM_HW_PARAM_TICK_TIME,
-1
};
int err, *v;
int i = 0;
v = vars;
v++;
v++;
v++;
{
if (*v != SNDRV_PCM_HW_PARAM_BUFFER_SIZE) {
err = gm2_snd_pcm_hw_param_first(pcm, params, *v, NULL);
}
}
v++;
v++;
{
if (*v != SNDRV_PCM_HW_PARAM_BUFFER_SIZE) {
err = snd_pcm_hw_param_first(pcm, params, *v, NULL);
int snd_pcm_hw_param_first(struct snd_pcm_substream *pcm,
struct snd_pcm_hw_params *params,
snd_pcm_hw_param_t var, int *dir)
{
int changed = _snd_pcm_hw_param_first(params, var);
if (params->rmask) {
int err = gm1_snd_pcm_hw_refine(pcm, params);
/*int err = snd_pcm_hw_refine(pcm, params);*/
int gm1_snd_pcm_hw_refine(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
unsigned int k;
struct snd_pcm_hardware *hw;
struct snd_interval *i = NULL;
struct snd_mask *m = NULL;
struct snd_pcm_hw_constraints *constrs = &substream->runtime->hw_constraints;
unsigned int rstamps[constrs->rules_num];
unsigned int vstamps[SNDRV_PCM_HW_PARAM_LAST_INTERVAL + 1];
unsigned int stamp = 2;
int changed, again;
params->info = 0;
params->fifo_size = 0;
again = 0;
for (k = 0; k < constrs->rules_num; k++) {
struct snd_pcm_hw_rule *r = &constrs->rules[k];
unsigned int d;
int doit = 0;
changed = r->func(params, r);
rstamps[k] = stamp;
stamp++;
}
hw = &substream->runtime->hw;
if (!params->info) {
params->info = hw->info & ~(SNDRV_PCM_INFO_FIFO_IN_FRAMES |
SNDRV_PCM_INFO_DRAIN_TRIGGER);
if (!hw_support_mmap(substream))
params->info &= ~(SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID);
}
params->rmask = 0;
return 0;
}
}
return 0;
}
}
}
return 0;
}
if (substream->ops->hw_params != NULL) { //
/* soc_pcm_hw_params */
err = substream->ops->hw_params(substream, params);
static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_platform *platform = rtd->platform;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int i, ret = 0;
mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
/*for (i = 0; i < rtd->num_codecs; i++)*/
i = 0;
{
struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
struct snd_pcm_hw_params codec_params;
/* copy params for each codec */
codec_params = *params;
codec_dai->rate = params_rate(&codec_params);
codec_dai->channels = params_channels(&codec_params);
codec_dai->sample_bits = snd_pcm_format_physical_width(
params_format(&codec_params));
}
if (platform->driver->ops && platform->driver->ops->hw_params) { //
/* nx_pcm_hw_params */
ret = platform->driver->ops->hw_params(substream, params);
static int nx_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct nx_pcm_runtime_data *prtd = substream_to_prtd(substream);
int ret;
ret = nx_pcm_dma_slave_config(prtd, substream->stream);
static int nx_pcm_dma_slave_config(void *runtime_data, int stream)
{
struct nx_pcm_runtime_data *prtd = runtime_data;
struct nx_pcm_dma_param *dma_param = prtd->dma_param;
struct dma_slave_config slave_config = { 0, };
dma_addr_t peri_addr = dma_param->peri_addr;
int bus_width = dma_param->bus_width_byte;
int max_burst = dma_param->max_burst_byte/bus_width;
int ret;
if (SNDRV_PCM_STREAM_PLAYBACK == stream) {
slave_config.direction = DMA_MEM_TO_DEV;
slave_config.dst_addr = peri_addr;
slave_config.dst_addr_width = bus_width;
slave_config.dst_maxburst = max_burst;
slave_config.src_addr_width = bus_width;
slave_config.src_maxburst = max_burst;
slave_config.device_fc = false;
}
ret = dmaengine_slave_config(prtd->dma_chan, &slave_config);
return ret;
}
snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
void snd_pcm_set_runtime_buffer(struct snd_pcm_substream *substream,
struct snd_dma_buffer *bufp)
{
struct snd_pcm_runtime *runtime = substream->runtime;
if (bufp) {
runtime->dma_buffer_p = bufp;
runtime->dma_area = bufp->area;
runtime->dma_addr = bufp->addr;
runtime->dma_bytes = bufp->bytes;
}
}
return 0;
}
}
/* store the parameters for each DAIs */
cpu_dai->rate = params_rate(params); /* 48000 dts */ <tag159>
cpu_dai->channels = params_channels(params);
cpu_dai->sample_bits =
snd_pcm_format_physical_width(params_format(params));
mutex_unlock(&rtd->pcm_mutex);
return ret;
}
}
runtime->access = params_access(params);
runtime->format = params_format(params);
runtime->subformat = params_subformat(params);
runtime->channels = params_channels(params);
runtime->rate = params_rate(params); <tag160>
runtime->period_size = params_period_size(params);
runtime->periods = params_periods(params);
runtime->buffer_size = params_buffer_size(params);
runtime->info = params->info;
runtime->rate_num = params->rate_num;
runtime->rate_den = params->rate_den;
runtime->no_period_wakeup =
(params->info & SNDRV_PCM_INFO_NO_PERIOD_WAKEUP) &&
(params->flags & SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP);
bits = snd_pcm_format_physical_width(runtime->format);
runtime->sample_bits = bits;
bits *= runtime->channels;
runtime->frame_bits = bits;
frames = 1;
while (bits % 8 != 0) {
bits *= 2;
frames *= 2;
}
runtime->byte_align = bits / 8;
runtime->min_align = frames;
/* Default sw params */
runtime->tstamp_mode = SNDRV_PCM_TSTAMP_NONE;
runtime->period_step = 1;
runtime->control->avail_min = runtime->period_size;
runtime->start_threshold = 1;
runtime->stop_threshold = runtime->buffer_size;
runtime->silence_threshold = 0;
runtime->silence_size = 0;
runtime->boundary = runtime->buffer_size;
while (runtime->boundary * 2 <= LONG_MAX - runtime->buffer_size)
runtime->boundary *= 2;
gm1_snd_pcm_set_state(substream, SNDRV_PCM_STATE_SETUP);
//snd_pcm_set_state(substream, SNDRV_PCM_STATE_SETUP);
static void gm1_snd_pcm_set_state(struct snd_pcm_substream *substream, int state)
{
snd_pcm_stream_lock_irq(substream);
if (substream->runtime->status->state != SNDRV_PCM_STATE_DISCONNECTED) { //
substream->runtime->status->state = state;
}
snd_pcm_stream_unlock_irq(substream);
}
return 0;
}
ioctl(fd, SNDRV_PCM_IOCTL_CHANNEL_INFO, &i); <tag52> <ioctl>
static int snd_pcm_channel_info(struct snd_pcm_substream *substream,
struct snd_pcm_channel_info * info)
{
struct snd_pcm_runtime *runtime;
unsigned int channel;
channel = info->channel;
runtime = substream->runtime;
memset(info, 0, sizeof(*info));
info->channel = channel;
/* snd_pcm_lib_ioctl_channel_info */
return substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_CHANNEL_INFO, info);
static int snd_pcm_lib_ioctl_channel_info(struct snd_pcm_substream *substream,
void *arg)
{
struct snd_pcm_channel_info *info = arg;
struct snd_pcm_runtime *runtime = substream->runtime;
int width;
width = snd_pcm_format_physical_width(runtime->format);
info->offset = 0;
switch (runtime->access) {
case SNDRV_PCM_ACCESS_MMAP_INTERLEAVED:
case SNDRV_PCM_ACCESS_RW_INTERLEAVED:
info->first = info->channel * width;
info->step = runtime->channels * width;
break;
}
return 0;
}
}
mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, i->u.mmap.fd, i->u.mmap.offset); <ioctl> <mmap>
static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area)
{
struct snd_pcm_file * pcm_file;
struct snd_pcm_substream *substream;
unsigned long offset;
pcm_file = file->private_data;
substream = pcm_file->substream;
offset = area->vm_pgoff << PAGE_SHIFT;
switch (offset) {
default:
return snd_pcm_mmap_data(substream, file, area);
int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file,
struct vm_area_struct *area)
{
struct snd_pcm_runtime *runtime;
long size;
unsigned long offset;
size_t dma_bytes;
int err;
runtime = substream->runtime;
size = area->vm_end - area->vm_start;
offset = area->vm_pgoff << PAGE_SHIFT;
dma_bytes = PAGE_ALIGN(runtime->dma_bytes);
area->vm_ops = &snd_pcm_vm_ops_data;
area->vm_private_data = substream;
{
err = snd_pcm_lib_default_mmap(substream, area);
int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream,
struct vm_area_struct *area)
{
area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
if (!substream->ops->page &&
substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV) { //
return dma_mmap_coherent(substream->dma_buffer.dev.dev,
area,
substream->runtime->dma_area,
substream->runtime->dma_addr,
substream->runtime->dma_bytes); <tag162>
}
return 0;
}
}
atomic_inc(&substream->mmap_count);
return err;
}
}
return 0;
}
#############snd_pcm_prepare ############
ioctl(fd, SNDRV_PCM_IOCTL_PREPARE); <tag66> <ioctl>
static int snd_pcm_prepare(struct snd_pcm_substream *substream,
struct file *file)
{
pr_err("%s:in %d.\n",__func__,__LINE__);
int res;
struct snd_card *card = substream->pcm->card;
int f_flags;
if (file) {
f_flags = file->f_flags;
}
snd_power_lock(card);
res = snd_power_wait(card, SNDRV_CTL_POWER_D0);
int snd_power_wait(struct snd_card *card, unsigned int power_state)
{
wait_queue_t wait;
int result = 0;
/* fastpath */
if (snd_power_get_state(card) == power_state) {
return 0;
}
}
if (res>= 0) {
res = snd_pcm_action_nonatomic(&snd_pcm_action_prepare, substream, f_flags);
static int snd_pcm_action_nonatomic(struct action_ops *ops,
struct snd_pcm_substream *substream,
int state)
{
int res;
down_read(&snd_pcm_link_rwsem);
{
res = gm1_snd_pcm_action_single(ops, substream, state);
//snd_pcm_action_single(ops, substream, state);
static int gm1_snd_pcm_action_single(struct action_ops *ops,
struct snd_pcm_substream *substream,
int state)
{
pr_err("%s:in %d.\n",__func__,__LINE__);
int res;
/* snd_pcm_do_prepare */
res = ops->do_action(substream, state);
static int snd_pcm_do_prepare(struct snd_pcm_substream *substream, int state)
{
int err;
/* soc_pcm_prepare */
err = substream->ops->prepare(substream);
static int soc_pcm_prepare(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_platform *platform = rtd->platform;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int i, ret = 0;
mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
if (platform->driver->ops && platform->driver->ops->prepare) {
ret = platform->driver->ops->prepare(substream);
static int nx_pcm_dma_prepare_and_submit(struct snd_pcm_substream *substream)
{
struct nx_pcm_runtime_data *prtd = substream_to_prtd(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
struct dma_chan *chan = prtd->dma_chan;
struct dma_async_tx_descriptor *desc;
enum dma_transfer_direction direction;
unsigned long flags = DMA_CTRL_ACK;
int period_time_us;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
direction = DMA_MEM_TO_DEV;
if (!substream->runtime->no_period_wakeup) {
flags |= DMA_PREP_INTERRUPT;
}
/* dma offset */
prtd->offset = 0;
desc = dmaengine_prep_dma_cyclic(chan,
runtime->dma_addr,
snd_pcm_lib_buffer_bytes(substream),
snd_pcm_lib_period_bytes(substream),
direction, flags);
desc->callback = nx_pcm_dma_complete;
desc->callback_param = substream;
dmaengine_submit(desc);
return 0;
}
}
mutex_unlock(&rtd->pcm_mutex);
return ret;
}
return 0;
}
/*if (res == 0)*/
{
/* snd_pcm_post_prepare */
ops->post_action(substream, state);
static void snd_pcm_post_prepare(struct snd_pcm_substream *substream, int state)
{
struct snd_pcm_runtime *runtime = substream->runtime;
runtime->control->appl_ptr = runtime->status->hw_ptr;
snd_pcm_set_state(substream, SNDRV_PCM_STATE_PREPARED);
static void snd_pcm_set_state(struct snd_pcm_substream *substream, int state)
{
snd_pcm_stream_lock_irq(substream);
if (substream->runtime->status->state != SNDRV_PCM_STATE_DISCONNECTED)
substream->runtime->status->state = state;
snd_pcm_stream_unlock_irq(substream);
}
}
}
return res;
}
}
up_read(&snd_pcm_link_rwsem);
return res;
}
}
snd_power_unlock(card);
return res;
}
################snd_pcm_writei##############
ioctl(hw->fd, SNDRV_PCM_IOCTL_SYNC_PTR, hw->sync_ptr); <tag79> <ioctl>
/* 以正确的位深 ,RFS, BFS设置i2s控制器, 使能i2s tx DMA. */
ioctl(hw->fd, SNDRV_PCM_IOCTL_START); <tag80> <ioctl>
static int snd_pcm_action(struct action_ops *ops,
struct snd_pcm_substream *substream,
int state)
{
int res;
if (!snd_pcm_stream_linked(substream))
return snd_pcm_action_single(ops, substream, state);
static int snd_pcm_action_single(struct action_ops *ops,
struct snd_pcm_substream *substream,
int state)
{
int res;
/* snd_pcm_pre_start */
res = ops->pre_action(substream, state);
static int snd_pcm_pre_start(struct snd_pcm_substream *substream, int state)
{
struct snd_pcm_runtime *runtime = substream->runtime;
runtime->trigger_tstamp_latched = false;
runtime->trigger_master = substream;
return 0;
}
/* snd_pcm_do_start */
res = ops->do_action(substream, state);
static int snd_pcm_do_start(struct snd_pcm_substream *substream, int state)
{
/* soc_pcm_trigger */
return substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_START);
static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_platform *platform = rtd->platform;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_soc_dai *codec_dai;
int i, ret;
if (platform->driver->ops && platform->driver->ops->trigger) {
/* nx_pcm_trigger */
ret = platform->driver->ops->trigger(substream, cmd);
static int nx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct nx_pcm_runtime_data *prtd = substream_to_prtd(substream);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
dma_async_issue_pending(prtd->dma_chan);
prtd->time_stamp_us = ktime_to_us(ktime_get());
break;
}
return 0;
}
}
if (cpu_dai->driver->ops && cpu_dai->driver->ops->trigger) {
/* nx_i2s_trigger */
ret = cpu_dai->driver->ops->trigger(substream, cmd, cpu_dai);
static int nx_i2s_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
{
struct nx_i2s_snd_param *par = snd_soc_dai_get_drvdata(dai);
int stream = substream->stream;
switch (cmd) {
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
case SNDRV_PCM_TRIGGER_START:
i2s_start(dai, stream);
static int i2s_start(struct snd_soc_dai *dai, int stream)
{
struct nx_i2s_snd_param *par = snd_soc_dai_get_drvdata(dai);
struct i2s_register *i2s = &par->i2s;
void __iomem *base = par->base_addr;
unsigned int FIC = 0;
SND_I2S_LOCK(&par->lock, par->flags);
if (SNDRV_PCM_STREAM_PLAYBACK == stream) {
/* flush fifo */
FIC |= (FIC_FLUSH_EN << FIC_TFULSH_POS);
i2s->CON |= ((1 << CON_TXDMACTIVE_POS) |
(1 << CON_I2SACTIVE_POS));
i2s->CSR &= ~(TRANS_MODE_MASK << CSR_TXR_POS);
/* Transmit only */
i2s->CSR |= (TX_MODE << CSR_TXR_POS);
par->status |= SNDDEV_STATUS_PLAY;
}
writel(FIC, (base+I2S_FIC_OFFSET)); /* Flush the current FIFO */
writel(0x0, (base+I2S_FIC_OFFSET)); /* Clear the Flush bit */
/* bit deepth 16bits, i2s format */
writel(i2s->CSR, (base+I2S_CSR_OFFSET));
/* tx DMA active */
writel(i2s->CON, (base+I2S_CON_OFFSET));
SND_I2S_UNLOCK(&par->lock, par->flags);
return 0;
}
break;
}
return 0;
}
}
return 0;
}
}
if (res == 0)
/* snd_pcm_post_start */
ops->post_action(substream, state);
static void snd_pcm_post_start(struct snd_pcm_substream *substream, int state)
{
struct snd_pcm_runtime *runtime = substream->runtime;
runtime->hw_ptr_jiffies = jiffies;
runtime->hw_ptr_buffer_jiffies = (runtime->buffer_size * HZ) /
runtime->rate;
runtime->status->state = state;
}
return res;
}
return res;
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/suiren/s5p6818_alsa_driver_simplify.git
git@gitee.com:suiren/s5p6818_alsa_driver_simplify.git
suiren
s5p6818_alsa_driver_simplify
s5p6818_alsa_driver_simplify
master

搜索帮助