新闻中心

EEPW首页>嵌入式系统>设计应用> AM335x(TQ335x)学习笔记——WM8960声卡驱动移植

AM335x(TQ335x)学习笔记——WM8960声卡驱动移植

作者: 时间:2016-11-28 来源:网络 收藏

Step3. 调整WM8960驱动结构

内核中自带的WM8960驱动结构很旧,编写Machine是需要过多的了解Codec芯片内部细节,本文对WM8960的驱动结构进行了调整,可以使Machine忽略Codec的内部细节。

修改的大体内容如下:

(1) 添加set_sysclk函数,接收Machine设置的sysclk时钟频率。具体本文就是DTS中设置的24576000。

(2) 在hw_params中添加BCLK、DACCLK、ADCCLK的配置操作。hw_params可以根据参数和sysclk对以上参数进行设置,放在这里很合适。

(3) 去除函数wm8960_set_dai_clkdiv,并将wm8960_set_dai_pll设置为驱动内部函数,不作为set_pll接口提供给内核驱动(实际上内核驱动也不调用这个函数)。

Step4. 修改WM8960的route信息

根据TQ335x的原理图可知,使用WM8960进行录音或放音时使用的LRCLK是同一个,都是DACCLK,故在snd_soc_dapm_route添加如下两行信息:

  1. {"LeftDAC",NULL,"LeftInputMixer"},
  2. {"RightDAC",NULL,"RightInputMixer"},
这样在录音时也会使能DAC产生LRCLK。

由于调试时间比较长,可能有些修改我没有描述到,完整的wm8960.c文件我会一并上传到我的资源,可以下载参考。

3. 编写Machine驱动
内核代码有个很好的例子就是davinci-evm.c,这是am335x-evm评估板的Machine驱动,该评估采用的Codec并不是WM8960,因此,我们在该文件中添加WM8960信息即可。具体的修改如下:

Step1. 添加compatible信息。修改后的内容如下:

  1. staticconststructof_device_iddavinci_evm_dt_ids[]={
  2. {
  3. .compatible="ti,tq-evm-audio",
  4. .data=(void*)&evm_dai_wm8960,
  5. },
  6. {
  7. .compatible="ti,da830-evm-audio",
  8. .data=(void*)&evm_dai_tlv320aic3x,
  9. },
  10. {/*sentinel*/}
  11. };
Step2. 实现em_dai_wm8960。需要添加如下代码:
  1. staticstructsnd_soc_dai_linkevm_dai_wm8960={
  2. .name="wm8960",
  3. .stream_name="wm8960-hifi",
  4. .codec_dai_name="wm8960-hifi",
  5. .ops=&evm_wm8960_ops,
  6. .init=evm_wm8960_init,
  7. .dai_fmt=SND_SOC_DAIFMT_I2S|SND_SOC_DAIFMT_CBM_CFM|
  8. SND_SOC_DAIFMT_NB_NF,
  9. };
含义:

(1) codec_dai_name = "wm8960-hifi" --> 指定codec设备名称,与wm8960.c中指定的相同即可。

(2) ops --> 指定wm8960的各种操作函数,本文仅实现了hw_params函数。

(3) init --> 指定wm8960的初始化函数,主要是完成dapm相关的初始化。

(4) dai_fmt --> 指定音频的接口方式、主从关系和时钟翻转信息。SND_SOC_DAIFMT_I2S表示音频接口采用I2S协议;SND_SOC_DAIFMT_CBM_CFM表示Codec的BCLK为Master,LRCLK为Master,即wm8960为主,AM335x为从;SND_SOC_DAIFMT_NB_NF表示BCLK和LRCLK都不需要翻转。

Step3.实现evm_wm8960_init

这一部分主要是dapm相关的设置,本人理解也不是非常深刻,直接贴上代码,具体如下:

  1. staticconststructsnd_soc_dapm_widgetevm_wm8960_dapm_widgets[]={
  2. SND_SOC_DAPM_SPK("AudioOut1",NULL),
  3. SND_SOC_DAPM_MIC("myMic",NULL),
  4. SND_SOC_DAPM_MIC("myLineIN",NULL),
  5. };
  6. staticconststructsnd_kcontrol_newevm_wm8960_controls[]={
  7. SOC_DAPM_PIN_SWITCH("AudioOut1"),
  8. SOC_DAPM_PIN_SWITCH("myMic"),
  9. SOC_DAPM_PIN_SWITCH("myLineIN"),
  10. };
  11. staticconststructsnd_soc_dapm_routeevm_wm8960_audio_map[]={
  12. /*Connectionstothe...*/
  13. {"AudioOut1",NULL,"HP_L"},
  14. {"AudioOut1",NULL,"HP_R"},
  15. /*Mic*/
  16. {"LINPUT1",NULL,"MICB"},
  17. {"MICB",NULL,"myMic"},
  18. /*Linein*/
  19. {"LINPUT3",NULL,"myLineIN"},
  20. {"RINPUT3",NULL,"myLineIN"},
  21. };
  22. staticintevm_wm8960_init(structsnd_soc_pcm_runtime*rtd)
  23. {
  24. interr;
  25. structsnd_soc_codec*codec=rtd->codec;
  26. structsnd_soc_dapm_context*dapm=&codec->dapm;
  27. snd_soc_dapm_new_controls(dapm,evm_wm8960_dapm_widgets,
  28. ARRAY_SIZE(evm_wm8960_dapm_widgets));
  29. err=snd_soc_add_codec_controls(codec,evm_wm8960_controls,
  30. ARRAY_SIZE(evm_wm8960_controls));
  31. if(err<0)
  32. returnerr;
  33. snd_soc_dapm_add_routes(dapm,evm_wm8960_audio_map,
  34. ARRAY_SIZE(evm_wm8960_audio_map));
  35. snd_soc_dapm_enable_pin(dapm,"AudioOut1");
  36. snd_soc_dapm_enable_pin(dapm,"myMic");
  37. snd_soc_dapm_sync(dapm);
  38. return0;
  39. }
Step4. 实现evm_wm8960_ops及相关函数,需要添加如下代码:
  1. staticintevm_wm8960_hw_params(structsnd_pcm_substream*substream,
  2. structsnd_pcm_hw_params*params)
  3. {
  4. structsnd_soc_pcm_runtime*rtd=substream->private_data;
  5. structsnd_soc_dai*codec_dai=rtd->codec_dai;
  6. structsnd_soc_dai*cpu_dai=rtd->cpu_dai;
  7. structsnd_soc_card*soc_card=rtd->card;
  8. intret=0;
  9. unsignedsysclk=((structsnd_soc_card_drvdata_davinci*)
  10. snd_soc_card_get_drvdata(soc_card))->sysclk;
  11. /*setthecodecsystemclock*/
  12. ret=snd_soc_dai_set_sysclk(codec_dai,0,sysclk,SND_SOC_CLOCK_IN);
  13. if(ret<0)
  14. returnret;
  15. /*settheCPUsystemclock*/
  16. ret=snd_soc_dai_set_sysclk(cpu_dai,0,sysclk,SND_SOC_CLOCK_IN);
  17. if(ret<0)
  18. returnret;
  19. return0;
  20. }
  21. staticstructsnd_soc_opsevm_wm8960_ops={
  22. .startup=evm_startup,
  23. .shutdown=evm_shutdown,
  24. .hw_params=evm_wm8960_hw_params,
  25. };
至此,就完成了代码移植的全部工作,修改涉及到的三个文件是:tq335x.dts、davinci-evm.c和wm8960.c,修改后的这三个文件我会上传到我的资源,如有需要,请去我的资源中下载。

4. 配置内核

完成了代码的移植工作之后还需要对内核进一步配置。默认的内核将ALSA作为module加载,本文将编译进内核。具体步骤如下:

Step1. 修改sound/soc/codecs/Kconfig,添加wm8960编译选项,修改后的内容如下:

  1. configSND_SOC_WM8960
  2. tristate"WolfsonMicroelectronicsWM8960CODEC"
  3. dependsonI2C&&INPUT
Step2. 通过menuconfig配置内核

执行指令:

  1. makeARCH=armCROSS_COMPILE=arm-linux-gnueabi-menuconfig
进行如下修改:
  1. DeviceDrivers--->
  2. <*>Soundcardsupport--->
  3. <*>AdvancedLinuxSoundArchitecture--->
  4. <*>ALSAforSoCaudiosupport--->
  5. <*>SoCAudioforTexasInstrumentschipsusingeDMA(AM33XX/43XX)
  6. -*-MultichannelAudioSerialPort(McASP)support
  7. <*>SoCAudiofortheAM33XXchipbasedboards
  8. CODECdrivers--->
  9. <*>WolfsonMicroelectronicsWM8960CODEC
重新编译内核:
  1. makeARCH=armCROSS_COMPILE=arm-linux-gnueabi--j8

5. 效果将编译后的内核文件zImage和tq335x.dtb文件拷贝SD卡并启动开发板,按任意键进入uboot命令模式,输入如下指令:

  1. loadmmc0:10x88000000/boot/tq335x.dtb
  2. loadmmc0:10x82000000/boot/zImage
  3. bootz0x82000000-0x88000000
通过上面的三条指令可以启动内核,完整的Log信息如下:
  1. Startingkernel...
  2. [0.000000]BootingLinuxonphysicalCPU0x0
  3. [0.000000]Linuxversion3.17.2(lilianrong@smarter)(gccversion4.7.3(Ubuntu/Linaro4.7.3-12ubuntu1))#68SMPSatDec2000:03:09CST2014
  4. [0.000000]CPU:ARMv7Processor[413fc082]revision2(ARMv7),cr=10c5387d
  5. [0.000000]CPU:PIPT/VIPTnonaliasingdatacache,VIPTaliasinginstructioncache
  6. [0.000000]Machinemodel:TIAM335xEVM
  7. [0.000000]cma:Reserved16MiBat9e800000
  8. [0.000000]Memorypolicy:Datacachewriteback
  9. [0.000000]HighMemzone:1048574pagesexceedsfreesize0
  10. [0.000000]CPU:AllCPU(s)startedinSVCmode.
  11. [0.000000]AM335XES2.1(sgxneon)
  12. [0.000000]PERCPU:Embedded9pages/cpu@dfa99000s14336r8192d14336u36864
  13. [0.000000]Built1zonelistsinZoneorder,mobilitygroupingon.Totalpages:129792
  14. [0.000000]Kernelcommandline:console=ttyO0,115200n8root=/dev/mmcblk0p2rwrootfstype=ext3rootwait
  15. [0.000000]PIDhashtableentries:2048(order:1,8192bytes)
  16. [0.000000]Dentrycachehashtableentries:65536(order:6,262144bytes)
  17. [0.000000]Inode-cachehashtableentries:32768(order:5,131072bytes)
  18. [0.000000]Memory:484124K/523264Kavailable(6070Kkernelcode,666Krwdata,2444Krodata,410Kinit,8214Kbss,39140Kreserved,0Khighmem)
  19. [0.000000]Virtualkernelmemorylayout:
  20. [0.000000]vector:0xffff0000-0xffff1000(4kB)
  21. [0.000000]fixmap:0xffc00000-0xffe00000(2048kB)
  22. [0.000000]vmalloc:0xe0800000-0xff000000(488MB)
  23. [0.000000]lowmem:0xc0000000-0xe0000000(512MB)
  24. [0.000000]pkmap:0xbfe00000-0xc0000000(2MB)
  25. [0.000000]modules:0xbf000000-0xbfe00000(14MB)
  26. [0.000000].text:0xc0008000-0xc0858bc0(8515kB)
  27. [0.000000].init:0xc0859000-0xc08bf800(410kB)
  28. [0.000000].data:0xc08c0000-0xc0966b50(667kB)
  29. [0.000000].bss:0xc0966b50-0xc116c6e0(8215kB)
  30. [0.000000]HierarchicalRCUimplementation.
  31. [0.000000]RCUrestrictingCPUsfromNR_CPUS=2tonr_cpu_ids=1.
  32. [0.000000]RCU:Adjustinggeometryforrcu_fanout_leaf=16,nr_cpu_ids=1
  33. [0.000000]NR_IRQS:16nr_irqs:1616
  34. [0.000000]IRQ:FoundanINTCat0xfa200000(revision5.0)with128interrupts
  35. [0.000000]Totalof128interruptson1activecontroller
  36. [0.000000]OMAPclockeventsource:timer2at24000000Hz
  37. [0.000015]sched_clock:32bitsat24MHz,resolution41ns,wrapsevery178956969942ns
  38. [0.000061]OMAPclocksource:timer1at24000000Hz
  39. [0.000798]Console:colourdummydevice80x30
  40. [0.000849]Lockdependencyvalidator:Copyright(c)2006RedHat,Inc.,IngoMolnar
  41. [0.000858]...MAX_LOCKDEP_SUBCLASSES:8
  42. [0.000865]...MAX_LOCK_DEPTH:48
  43. [0.000873]...MAX_LOCKDEP_KEYS:8191
  44. [0.000880]...CLASSHASH_SIZE:4096
  45. [0.000887]...MAX_LOCKDEP_ENTRIES:32768
  46. [0.000894]...MAX_LOCKDEP_CHAINS:65536
  47. [0.000901]...CHAINHASH_SIZE:32768
  48. [0.000909]memoryusedbylockdependencyinfo:5167kB
  49. [0.000916]pertask-structmemoryfootprint:1152bytes
  50. [0.000956]Calibratingdelayloop...996.14BogoMIPS(lpj=4980736)
  51. [0.079039]pid_max:default:32768minimum:301
  52. [0.079431]SecurityFrameworkinitialized
  53. [0.079555]Mount-cachehashtableentries:1024(order:0,4096bytes)
  54. [0.079568]Mountpoint-cachehashtableentries:1024(order:0,4096bytes)
  55. [0.081736]CPU:Testingwritebuffercoherency:ok
  56. [0.082916]CPU0:thread-1,cpu0,socket-1,mpidr0
  57. [0.083033]Settingupstaticidentitymapfor0x805bf4f0-0x805bf560
  58. [0.086259]Broughtup1CPUs
  59. [0.086278]SMP:Totalof1processorsactivated.
  60. [0.086288]CPU:AllCPU(s)startedinSVCmode.
  61. [0.088875]devtmpfs:initialized
  62. [0.097689]VFPsupportv0.3:implementor41architecture3part30variantcrev3
  63. [0.133508]omap_hwmod:tptc0usingbrokendtdatafromedma
  64. [0.133865]omap_hwmod:tptc1usingbrokendtdatafromedma
  65. [0.134203]omap_hwmod:tptc2usingbrokendtdatafromedma
  66. [0.142102]omap_hwmod:debugss:_wait_target_disablefailed
  67. [0.200093]pinctrlcore:initializedpinctrlsubsystem
  68. [0.202608]regulator-dummy:noparameters
  69. [0.232298]NET:Registeredprotocolfamily16
  70. [0.240800]DMA:preallocated256KiBpoolforatomiccoherentallocations
  71. [0.243054]cpuidle:usinggovernorladder
  72. [0.243083]cpuidle:usinggovernormenu
  73. [0.255025]OMAPGPIOhardwareversion0.1
  74. [0.270226]omap-gpmc50000000.gpmc:couldnotfindpctldevfornode/pinmux@44e10800/nandflash_pins_s0,deferringprobe
  75. [0.270268]platform50000000.gpmc:Driveromap-gpmcrequestsprobedeferral
  76. [0.274762]hw-breakpoint:debugarchitecture0x4unsupported.
  77. [0.319722]edma-dma-engineedma-dma-engine.0:TIEDMADMAenginedriver
  78. [0.321054]vbat:5000mV
  79. [0.321851]lis3_reg:noparameters
  80. [0.325260]SCSIsubsysteminitialized
  81. [0.326060]usbcore:registerednewinterfacedriverusbfs
  82. [0.326235]usbcore:registerednewinterfacedriverhub
  83. [0.330180]usbcore:registerednewdevicedriverusb

评论


技术专区

关闭