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

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添加如下两行信息:

{ "Left DAC", NULL, "Left Input Mixer" },

{ "Right DAC", NULL, "Right Input Mixer" },

这样在录音时也会使能DAC产生LRCLK。

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

3. 编写Machine驱动

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

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

static const struct of_device_id davinci_evm_dt_ids[] = {

{

.compatible = "ti,tq-evm-audio",

.data = (void *) &evm_dai_wm8960,

},

{

.compatible = "ti,da830-evm-audio",

.data = (void *) &evm_dai_tlv320aic3x,

},

{ /* sentinel */ }

};

Step2. 实现em_dai_wm8960。需要添加如下代码:

static struct snd_soc_dai_link evm_dai_wm8960 = {

.name       = "wm8960",

.stream_name    = "wm8960-hifi",

.codec_dai_name = "wm8960-hifi",

.ops            = &evm_wm8960_ops,

.init           = evm_wm8960_init,

.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM |

SND_SOC_DAIFMT_NB_NF,

};

含义:

(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相关的设置,本人理解也不是非常深刻,直接贴上代码,具体如下:

static const struct snd_soc_dapm_widget evm_wm8960_dapm_widgets[] = {

SND_SOC_DAPM_SPK("Audio Out1", NULL),

SND_SOC_DAPM_MIC("my Mic", NULL),

SND_SOC_DAPM_MIC("my Line IN", NULL),

};

static const struct snd_kcontrol_new evm_wm8960_controls[] = {

SOC_DAPM_PIN_SWITCH("Audio Out1"),

SOC_DAPM_PIN_SWITCH("my Mic"),

SOC_DAPM_PIN_SWITCH("my Line IN"),

};

static const struct snd_soc_dapm_route evm_wm8960_audio_map[] = {

/* Connections to the ... */

{"Audio Out1", NULL, "HP_L"},

{"Audio Out1", NULL, "HP_R"},

/* Mic */

{"LINPUT1", NULL, "MICB"},

{"MICB", NULL, "my Mic"},

/* Line in */

{"LINPUT3", NULL, "my Line IN"},

{"RINPUT3", NULL, "my Line IN"},

};

static int evm_wm8960_init(struct snd_soc_pcm_runtime *rtd)

{

int err;

struct snd_soc_codec *codec = rtd->codec;

struct snd_soc_dapm_context *dapm = &codec->dapm;

snd_soc_dapm_new_controls(dapm, evm_wm8960_dapm_widgets,

ARRAY_SIZE(evm_wm8960_dapm_widgets ) );

err = snd_soc_add_codec_controls(codec, evm_wm8960_controls,

ARRAY_SIZE(evm_wm8960_controls));

if (err

return err;

snd_soc_dapm_add_routes(dapm, evm_wm8960_audio_map,

ARRAY_SIZE(evm_wm8960_audio_map));

snd_soc_dapm_enable_pin(dapm, "Audio Out1");

snd_soc_dapm_enable_pin(dapm, "my Mic");

snd_soc_dapm_sync( dapm );

return 0;

}

Step4. 实现evm_wm8960_ops及相关函数,需要添加如下代码:

static int evm_wm8960_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_dai *codec_dai = rtd->codec_dai;

struct snd_soc_dai *cpu_dai = rtd->cpu_dai;

struct snd_soc_card *soc_card = rtd->card;

int ret = 0;

unsigned sysclk = ((struct snd_soc_card_drvdata_davinci *)

snd_soc_card_get_drvdata(soc_card))->sysclk;

/* set the codec system clock */

ret = snd_soc_dai_set_sysclk(codec_dai, 0, sysclk, SND_SOC_CLOCK_IN);

if (ret

return ret;

/* set the CPU system clock */

ret = snd_soc_dai_set_sysclk(cpu_dai, 0, sysclk, SND_SOC_CLOCK_IN);

if (ret

return ret;

return 0;

}

static struct snd_soc_ops evm_wm8960_ops = {

.startup = evm_startup,

.shutdown = evm_shutdown,

.hw_params = evm_wm8960_hw_params,

};

至此,就完成了代码移植的全部工作,修改涉及到的三个文件是:tq335x.dts、davinci-evm.c和wm8960.c,修改后的这三个文件我会上传到我的资源,如有需要,请去我的资源中下载。

4. 配置内核

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

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

config SND_SOC_WM8960

tristate "Wolfson Microelectronics WM8960 CODEC"

depends on I2C && INPUT

Step2.  通过menuconfig配置内核

执行指令:

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- menuconfig

进行如下修改:

Device Drivers  --->

Sound card support  --->

Advanced Linux Sound Architecture  --->

ALSA for SoC audio support  --->

SoC Audio for Texas Instruments chips using eDMA (AM33XX/43XX)

-*-   Multichannel Audio Serial Port (McASP) support

SoC Audio for the AM33XX chip based boards

CODEC drivers  --->

Wolfson Microelectronics WM8960 CODEC

重新编译内核:

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -j8

5. 效果

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

load mmc 0:1 0x88000000 /boot/tq335x.dtb

load mmc 0:1 0x82000000 /boot/zImage

bootz 0x82000000 - 0x88000000

通过上面的三条指令可以启动内核,完整的Log信息如下:

Starting kernel ...

[    0.000000] Booting Linux on physical CPU 0x0

[    0.000000] Linux version 3.17.2 (lilianrong@smarter) (gcc version 4.7.3 (Ubuntu/Linaro 4.7.3-12ubuntu1) ) #68 SMP Sat Dec 20 00:03:09 CST 2014

[    0.000000] CPU: ARMv7 Processor [413fc082] revision 2 (ARMv7), cr=10c5387d

[    0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache

[    0.000000] Machine model: TI AM335x EVM

[    0.000000] cma: Reserved 16 MiB at 9e800000

[    0.000000] Memory policy: Data cache writeback

[    0.000000]   HighMem zone: 1048574 pages exceeds freesize 0

[    0.000000] CPU: All CPU(s) started in SVC mode.

[    0.000000] AM335X ES2.1 (sgx neon )

[    0.000000] PERCPU: Embedded 9 pages/cpu @dfa99000 s14336 r8192 d14336 u36864

[    0.000000] Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 129792

[    0.000000] Kernel command line: console=ttyO0,115200n8 root=/dev/mmcblk0p2 rw rootfstype=ext3 rootwait

[    0.000000] PID hash table entries: 2048 (order: 1, 8192 bytes)

[    0.000000] Dentry cache hash table entries: 65536 (order: 6, 262144 bytes)

[    0.000000] Inode-cache hash table entries: 32768 (order: 5, 131072 bytes)

[    0.000000] Memory: 484124K/523264K available (6070K kernel code, 666K rwdata, 2444K rodata, 410K init, 8214K bss, 39140K reserved, 0K highmem)

[    0.000000] Virtual kernel memory layout:

[    0.000000]     vector  : 0xffff0000 - 0xffff1000   (   4 kB)

[    0.000000]     fixmap  : 0xffc00000 - 0xffe00000   (2048 kB)

[    0.000000]     vmalloc : 0xe0800000 - 0xff000000   ( 488 MB)

[    0.000000]     lowmem  : 0xc0000000 - 0xe0000000   ( 512 MB)

[    0.000000]     pkmap   : 0xbfe00000 - 0xc0000000   (   2 MB)

[    0.000000]     modules : 0xbf000000 - 0xbfe00000   (  14 MB)

[    0.000000]       .text : 0xc0008000 - 0xc0858bc0   (8515 kB)

[    0.000000]       .init : 0xc0859000 - 0xc08bf800   ( 410 kB)

[    0.000000]       .data : 0xc08c0000 - 0xc0966b50   ( 667 kB)

[    0.000000]        .bss : 0xc0966b50 - 0xc116c6e0   (8215 kB)

[    0.000000] Hierarchical RCU implementation.

[    0.000000]  RCU restricting CPUs from NR_CPUS=2 to nr_cpu_ids=1.

[    0.000000] RCU: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=1

[    0.000000] NR_IRQS:16 nr_irqs:16 16

[    0.000000] IRQ: Found an INTC at 0xfa200000 (revision 5.0) with 128 interrupts

[    0.000000] Total of 128 interrupts on 1 active controller

[    0.000000] OMAP clockevent source: timer2 at 24000000 Hz

[    0.000015] sched_clock: 32 bits at 24MHz, resolution 41ns, wraps every 178956969942ns

[    0.000061] OMAP clocksource: timer1 at 24000000 Hz

[    0.000798] Console: colour dummy device 80x30

[    0.000849] Lock dependency validator: Copyright (c) 2006 Red Hat, Inc., Ingo Molnar

[    0.000858] ... MAX_LOCKDEP_SUBCLASSES:  8

[    0.000865] ... MAX_LOCK_DEPTH:          48

[    0.000873] ... MAX_LOCKDEP_KEYS:        8191

[    0.000880] ... CLASSHASH_SIZE:          4096

[    0.000887] ... MAX_LOCKDEP_ENTRIES:     32768

[    0.000894] ... MAX_LOCKDEP_CHAINS:      65536

[    0.000901] ... CHAINHASH_SIZE:          32768

[    0.000909]  memory used by lock dependency info: 5167 kB

[    0.000916]  per task-struct memory footprint: 1152 bytes

[    0.000956] Calibrating delay loop... 996.14 BogoMIPS (lpj=4980736)

[    0.079039] pid_max: default: 32768 minimum: 301

[    0.079431] Security Framework initialized

[    0.079555] Mount-cache hash table entries: 1024 (order: 0, 4096 bytes)

[    0.079568] Mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes)

[    0.081736] CPU: Testing write buffer coherency: ok

[    0.082916] CPU0: thread -1, cpu 0, socket -1, mpidr 0

[    0.083033] Setting up static identity map for 0x805bf4f0 - 0x805bf560

[    0.086259] Brought up 1 CPUs

[    0.086278] SMP: Total of 1 processors activated.

[    0.086288] CPU: All CPU(s) started in SVC mode.

[    0.088875] devtmpfs: initialized

[    0.097689] VFP support v0.3: implementor 41 architecture 3 part 30 variant c rev 3

[    0.133508] omap_hwmod: tptc0 using broken dt data from edma

[    0.133865] omap_hwmod: tptc1 using broken dt data from edma

[    0.134203] omap_hwmod: tptc2 using broken dt data from edma

[    0.142102] omap_hwmod: debugss: _wait_target_disable failed

[    0.200093] pinctrl core: initialized pinctrl subsystem

[    0.202608] regulator-dummy: no parameters

[    0.232298] NET: Registered protocol family 16

[    0.240800] DMA: preallocated 256 KiB pool for atomic coherent allocations

[    0.243054] cpuidle: using governor ladder

[    0.243083] cpuidle: using governor menu

[    0.255025] OMAP GPIO hardware version 0.1

[    0.270226] omap-gpmc 50000000.gpmc: could not find pctldev for node /pinmux@44e10800/nandflash_pins_s0, deferring probe

[    0.270268] platform 50000000.gpmc: Driver omap-gpmc requests probe deferral

[    0.274762] hw-breakpoint: debug architecture 0x4 unsupported.

[    0.319722] edma-dma-engine edma-dma-engine.0: TI EDMA DMA engine driver

[    0.321054] vbat: 5000 mV

[    0.321851] lis3_reg: no parameters

[    0.325260] SCSI subsystem initialized

[    0.326060] usbcore: registered new interface driver usbfs

[    0.326235] usbcore: registered new interface driver hub

[    0.330180] usbcore: registered new device driver usb

c2c9ed493cd281aa86d8a6f5178c4c01.gif [1] [2] [3] 610626052e95c7fbe3d254abc769d9ad.gif

404-电子工程世界

eewm.jpg

b094b28065371bab7e73d36d606aa669.png

97c883c75098afdd39f665c518c59eec.png

258b0bd82dd9ca476c7c8afdd48d607a.png

北京市海淀区知春路23号集成电路设计园量子银座1305

电话:(010)82350740

邮编:100191

电子工程世界版权所有

京ICP证060456号

Copyright © 2005-2021 EEWORLD.com.cn, Inc. All rights reserved

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值