[alsa-devel] ASoC: Hooking a TI CODEC to a i.MX27 MCU
Hi all,
I'm trying to write a new machine driver and CODEC driver for a device we're building, and as yet, haven't figured out the magic that gets ALSA to enumerate all the devices on the board. I hope to be able to release any code here back to the community, but I probably need to clear it with a few people first (and it'd be nice to contribute _working_ code).
Scenario: MCU is a Freescale i.MX27 processor on a Ka-Ro TX27 module CODEC is a Texas Instruments TLV320AIC3204, control via I²C, data via I²S. Chip ID for this CODEC is locked at 0x18. Kernel is 2.6.34, userland is Gentoo/ARM via root-over-NFS.
My goal: Just to get audio being transmitted along the I²S bus. (Don't care about mixers, etc.)
So far my only means of debugging everything is to sprinkle the code liberally with printk's everywhere... crude, but it gives me some idea what's going on.
The CODEC driver is at this moment, an empty shell based on the TLV320AIC3x driver already in the tree. I've tried basing a machine driver on the rx51 driver -- substituting the TLV320AIC3x driver for my own shell driver, and swapping the original cpu_dai configuration for the i.MX driver. I suspect this machine driver is giving me grief.
My machine code setup is as follows: /* Digital audio interface glue - connects codec <--> CPU */ static struct snd_soc_dai_link jem3_dai[] = { { .name = "TLV320AIC3204", .stream_name = "AIC3204", .cpu_dai = &imx_ssi_pcm_dai[0], .codec_dai = &aic3204_dai, .init = jem3_aic3204_init, .ops = &jem3_ops, }, };
/* Audio private data */ static struct aic3204_setup_data jem3_aic3204_setup = { .gpio_func[0] = AIC3204_GPIO1_FUNC_DISABLED, .gpio_func[1] = AIC3204_GPIO2_FUNC_DIGITAL_MIC_INPUT, };
/* Audio card */ static struct snd_soc_card jem3_sound_card = { .name = "JEM3", .dai_link = jem3_dai, .num_links = ARRAY_SIZE(jem3_dai), .platform = &imx_soc_platform, };
/* Audio subsystem */ static struct snd_soc_device jem3_snd_devdata = { .card = &jem3_sound_card, .codec_dev = &soc_codec_dev_aic3204, .codec_data = &jem3_aic3204_setup, };
static struct platform_device *jem3_snd_device;
static int __init jem3_soc_init(void) { int err; printk( KERN_INFO "%s: hello...\n", __FUNCTION__ );
jem3_snd_device = platform_device_alloc("soc-audio", -1); printk( KERN_INFO "%s: jem3_snd_device = %p\n", __FUNCTION__, jem3_snd_device ); if (!jem3_snd_device) { err = -ENOMEM; goto err1; }
printk( KERN_INFO "%s: calling platform_set_drvdata( %p, %p )\n", __FUNCTION__, jem3_snd_device, &jem3_snd_devdata ); platform_set_drvdata(jem3_snd_device, &jem3_snd_devdata); jem3_snd_devdata.dev = &jem3_snd_device->dev;
printk( KERN_INFO "%s: calling platform_device_add(%p)\n", __FUNCTION__, jem3_snd_device ); err = platform_device_add(jem3_snd_device); printk( KERN_INFO "%s: platform_device_add(%p) = %d\n", __FUNCTION__, jem3_snd_device, err ); if (err) goto err2;
printk( KERN_INFO "%s = 0 (success)\n", __FUNCTION__ ); return 0; err2: platform_device_put(jem3_snd_device); err1: printk( KERN_INFO "%s = %d\n", __FUNCTION__, err ); return err; }
Now this compiles... but when I go to load it; one of two things happens... either practically nothing (at this stage; no modules are loaded prior to calling modprobe):
192 / # modprobe snd-soc-jem3 aic3204_i2c_init: adding driver at bf068f9c aic3204_i2c_init: i2c_add_driver(bf068f9c) = 0 jem3_soc_init: hello... jem3_soc_init: jem3_snd_device = c3c600a0 jem3_soc_init: calling platform_set_drvdata( c3c600a0, bf07a780 ) jem3_soc_init: calling platform_device_add(c3c600a0) jem3_soc_init: platform_device_add(c3c600a0) = 0 jem3_soc_init = 0 (success) 192 / # mount /proc 192 / # cat /proc/asound/cards --- no soundcards ---
... Or it goes kaboom... particularly if I rmmod the snd-soc-jem3 module, but leave snd-soc-tlv320aic3204 in place...
192 / # rmmod snd-soc-jem3 jem3_soc_exit: unregistering... jem3_soc_exit: goodbye 192 / # modprobe snd-soc-jem3 jem3_soc_init: hello... jem3_soc_init: jem3_snd_device = c3c600a0 jem3_soc_init: calling platform_set_drvdata( c3c600a0, bf080780 ) jem3_soc_init: calling platform_device_add(c3c600a0) Unable to handle kernel NULL pointer dereference at virtual address 00000008 pgd = c3e44000 [00000008] *pgd=a3e62031, *pte=00000000, *ppte=00000000 Internal error: Oops: 17 [#1] PREEMPT last sysfs file: Modules linked in: snd_soc_jem3(+) snd_soc_imx snd_soc_tlv320aic3204 snd_soc_core snd_pcm snd_timer snd soundcore snd_page_alloc ac97_bus [last unloaded: snd_soc_jem3] CPU: 0 Not tainted (2.6.34-jacques-jem3 #16) PC is at snd_soc_instantiate_cards+0x2c/0x7b4 [snd_soc_core] LR is at 0x0 pc : [<bf0513d8>] lr : [<00000000>] psr: 20000013 sp : c3e33db0 ip : bf05906c fp : bf059074 r10: 00000001 r9 : bf058fd0 r8 : 00000000 r7 : bf07a790 r6 : c3c600a8 r5 : bf072960 r4 : bf059074 r3 : 00000000 r2 : 00000000 r1 : bf072960 r0 : bf059074 Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user Control: 0005317f Table: a3e44000 DAC: 00000015 Process modprobe (pid: 278, stack limit = 0xc3e32270) Stack: (0xc3e33db0 to 0xc3e34000) 3da0: c3e33dec 00000001 c3c600a8 00000000 3dc0: bf0687c8 00000000 c034f1c8 00000000 c3e32000 c0167c18 c02eee78 c3e33e34 3de0: c3e33e6c c3c0e7a8 00000000 c0275b24 c3c15040 c003a008 c3c15040 000000d0 3e00: c02e2fbc c3e32000 c3eae9c8 c3e85428 c3e33e34 00000008 c034f1dc c3eafac0 3e20: c3eafac0 c3e85428 c3eae9c8 c00f2674 00000000 0000072d c3e33e60 c3eae9c8 3e40: c3e85428 c00f2724 c0355190 00000000 c3eae9c8 bf080790 bf080798 c3c600a8 3e60: 00000000 c3c600b0 00000000 c033ec88 00000000 bf052ed0 c0355190 c3c600a8 3e80: c3e33eb0 bf059020 c0355190 c01ac47c bf059020 c01ab394 c3c600a8 00000000 3ea0: c3e33eb0 c3c600a8 c01ab548 c01aa628 c3c044e8 c3e76ad4 c02de99c c3c600a8 3ec0: c3c600a8 c3c600dc 00000000 c01ab5f4 c3c600a8 c3c600a8 00000000 c01aa5a8 3ee0: 00000000 c01a8c20 bf080870 c3c600b0 c3c600b0 00000000 00000000 c0168c18 3f00: c3c600a8 c3c600a8 c3c600a0 00000000 bf083000 c0021b88 00000000 c034578c 3f20: 000192dc c01acaa0 c3c600a8 bf0809ac fffffff4 bf080780 bf083000 bf083090 3f40: 000020f1 bf080864 c3e32000 c0021374 00000000 00000000 00000000 000020f1 3f60: bf080864 00021388 000020f1 bf080864 00021388 00000000 c0021b88 c3e32000 3f80: 00000000 c006e48c 00000001 00000000 00019738 0000cf60 000190b0 00019330 3fa0: 00000080 c00219e0 0000cf60 000190b0 00021388 000020f1 00019370 00019370 3fc0: 0000cf60 000190b0 00019330 00000080 00000000 bec39994 00000000 000192dc 3fe0: 000192d0 bec39524 0000bc98 4010ab44 60000010 00021388 00ffff00 00ffff00 [<bf0513d8>] (snd_soc_instantiate_cards+0x2c/0x7b4 [snd_soc_core]) from [<bf052ed0>] (soc_probe+0x74/0xb0 [snd_soc_core]) [<bf052ed0>] (soc_probe+0x74/0xb0 [snd_soc_core]) from [<c01ac47c>] (platform_drv_probe+0x1c/0x24) [<c01ac47c>] (platform_drv_probe+0x1c/0x24) from [<c01ab394>] (driver_probe_device+0x88/0x180) [<c01ab394>] (driver_probe_device+0x88/0x180) from [<c01aa628>] (bus_for_each_drv+0x60/0x8c) [<c01aa628>] (bus_for_each_drv+0x60/0x8c) from [<c01ab5f4>] (device_attach+0x5c/0x74) [<c01ab5f4>] (device_attach+0x5c/0x74) from [<c01aa5a8>] (bus_probe_device+0x30/0x50) [<c01aa5a8>] (bus_probe_device+0x30/0x50) from [<c01a8c20>] (device_add+0x1f4/0x4c0) [<c01a8c20>] (device_add+0x1f4/0x4c0) from [<c01acaa0>] (platform_device_add+0xf0/0x194) [<c01acaa0>] (platform_device_add+0xf0/0x194) from [<bf083090>] (jem3_soc_init+0x90/0x110 [snd_soc_jem3]) [<bf083090>] (jem3_soc_init+0x90/0x110 [snd_soc_jem3]) from [<c0021374>] (do_one_initcall+0x2c/0x1a8) [<c0021374>] (do_one_initcall+0x2c/0x1a8) from [<c006e48c>] (sys_init_module+0xc4/0x1f8) [<c006e48c>] (sys_init_module+0xc4/0x1f8) from [<c00219e0>] (ret_fast_syscall+0x0/0x2c) Code: e1530002 0a000021 e597203c e5973010 (e5922008) ---[ end trace 2b2b9768e2c2da90 ]---
The address mentioned there makes me think there's an uninitialised pointer to a struct somewhere... but I've never been able to figure out which one.
If I reboot, and try to make it oops like before by loading the CODEC driver then machine driver, everything is serine as one would expect:
192 / # modprobe snd-soc-tlv320aic3204 aic3204_i2c_init: adding driver at bf068f9c aic3204_i2c_init: i2c_add_driver(bf068f9c) = 0 192 / # modprobe snd-soc-jem3 jem3_soc_init: hello... jem3_soc_init: jem3_snd_device = c3dbb2a0 jem3_soc_init: calling platform_set_drvdata( c3dbb2a0, bf07a780 ) jem3_soc_init: calling platform_device_add(c3dbb2a0) jem3_soc_init: platform_device_add(c3dbb2a0) = 0 jem3_soc_init = 0 (success)
...but very quiet... 192 / # mount /proc 192 / # cat /proc/asound/cards --- no soundcards ---
Queries: - I notice in old drivers, the I²C chip address of the CODEC could be passed in via the same means that is used here for GPIO configuration. How is this done now? Or how do I tell the kernel to only look at address 0x18? - Despite duplicating what I can see being done in other drivers, I still don't see a sound device created. What am I missing to make an audio device appear? - How does one determine what line foo_bar+0x12/0x34 refers to?
As you can tell, I'm a newcomer to kernel hacking, so my appologies if these have been answered elsewhere... I've spent many days looking and haven't stumbled upon the answers as yet, hence why I ask here.
Thanks in advance. Regards,
On Mon, 2010-05-24 at 17:49 +1000, Stuart Longland wrote:
Now this compiles... but when I go to load it; one of two things happens... either practically nothing (at this stage; no modules are loaded prior to calling modprobe):
It does sound like you have some memory corruption somewhere. Can you rule out your new CODEC driver by replacing it with another CODEC driver (ads117x.c is a very simple example).
Liam
On Mon, May 24, 2010 at 11:49:16AM +0100, Liam Girdwood wrote:
On Mon, 2010-05-24 at 17:49 +1000, Stuart Longland wrote:
Now this compiles... but when I go to load it; one of two things happens... either practically nothing (at this stage; no modules are loaded prior to calling modprobe):
It does sound like you have some memory corruption somewhere. Can you rule out your new CODEC driver by replacing it with another CODEC driver (ads117x.c is a very simple example).
Liam
Well, the plot thickens... I tried two things.
(1) I swapped my 'AIC3204 driver for the 'AIC3X driver that my driver was originally based upon, and retried loading the driver. No blowups, but now devices appearing in /proc/asound/cards or /proc/asound/devices.
(2) I then tried using the phycore-ac97 driver (after disabling the relevant checks to see it was running on a Phycore module). First load went kaboom:
192 / # depmod -a && modprobe snd-soc-phycore-ac97
Unable to handle kernel NULL pointer dereference at virtual address 00000008 pgd = c3e68000 [00000008] *pgd=a3e53031, *pte=00000000, *ppte=00000000 Internal error: Oops: 17 [#1] PREEMPT last sysfs file: Modules linked in: snd_soc_phycore_ac97(+) snd_soc_wm9712 snd_soc_imx snd_soc_tlv320aic3x snd_soc_core snd_pcm snd_timer snd soundcore snd_page_alloc ac97_bus [last unloaded: snd_soc_jem3] CPU: 0 Not tainted (2.6.34-jacques-jem3 #16) PC is at snd_soc_instantiate_cards+0x2c/0x7b4 [snd_soc_core] LR is at 0x0 pc : [<bf0513d8>] lr : [<00000000>] psr: 20000013 sp : c3e63db0 ip : bf05906c fp : bf059074 r10: 00000001 r9 : bf058fd0 r8 : 00000000 r7 : bf080788 r6 : c3d2d1a8 r5 : bf072960 r4 : bf059074 r3 : 00000000 r2 : 00000000 r1 : bf072960 r0 : bf059074 Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user Control: 0005317f Table: a3e68000 DAC: 00000015 Process modprobe (pid: 288, stack limit = 0xc3e62270) Stack: (0xc3e63db0 to 0xc3e64000) 3da0: c3e63dec 00000001 c3d2d1a8 00000000 3dc0: bf0897e8 00000000 c034f1c8 00000000 c3e62000 c0167c18 c02eee78 c3e63e34 3de0: c3e63e6c c3c0e7a8 00000000 c0275b24 c3c15040 c003a008 c3c15040 000000d0 3e00: c02e2fbc c3e62000 c3ea89c8 c3ea44b8 c3e63e34 00000008 c034f1dc c3e6d1e0 3e20: c3e6d1e0 c3ea44b8 c3ea89c8 c00f2674 00000000 0000073c c3e63e60 c3ea89c8 3e40: c3ea44b8 c00f2724 c0355190 00000000 c3ea89c8 bf0910c8 bf0910d0 c3d2d1a8 3e60: 00000000 c3d2d1b0 00000000 c033ec88 00000000 bf052ed0 c0355190 c3d2d1a8 3e80: c3e63eb0 bf059020 c0355190 c01ac47c bf059020 c01ab394 c3d2d1a8 00000000 3ea0: c3e63eb0 c3d2d1a8 c01ab548 c01aa628 c3c044e8 c3e71ad4 c02de99c c3d2d1a8 3ec0: c3d2d1a8 c3d2d1dc 00000000 c01ab5f4 c3d2d1a8 c3d2d1a8 00000000 c01aa5a8 3ee0: 00000000 c01a8c20 bf091154 c3d2d1b0 c3d2d1b0 00000000 00000000 c0168c18 3f00: c3d2d1a8 c3d2d1a8 c3d2d1a0 00000000 bf094000 c0021b88 00000000 c034578c 3f20: 000190bc c01acaa0 c3d2d1a8 bf091288 fffffff4 bf0910b8 bf094000 bf094058 3f40: 00000fc5 bf091148 c3e62000 c0021374 00000000 00000000 00000000 00000fc5 3f60: bf091148 000278c8 00000fc5 bf091148 000278c8 00000000 c0021b88 c3e62000 3f80: 00000000 c006e48c 00000001 00000000 00020138 0000cf60 00019380 00019370 3fa0: 00000080 c00219e0 0000cf60 00019380 000278c8 00000fc5 00019330 00019330 3fc0: 0000cf60 00019380 00019370 00000080 00000000 bec56984 00000000 000190bc 3fe0: 000190b0 bec56514 0000bc98 4010ab44 60000010 000278c8 00000000 00000000 [<bf0513d8>] (snd_soc_instantiate_cards+0x2c/0x7b4 [snd_soc_core]) from [<bf052ed0>] (soc_probe+0x74/0xb0 [snd_soc_core]) [<bf052ed0>] (soc_probe+0x74/0xb0 [snd_soc_core]) from [<c01ac47c>] (platform_drv_probe+0x1c/0x24) [<c01ac47c>] (platform_drv_probe+0x1c/0x24) from [<c01ab394>] (driver_probe_device+0x88/0x180) [<c01ab394>] (driver_probe_device+0x88/0x180) from [<c01aa628>] (bus_for_each_drv+0x60/0x8c) [<c01aa628>] (bus_for_each_drv+0x60/0x8c) from [<c01ab5f4>] (device_attach+0x5c/0x74) [<c01ab5f4>] (device_attach+0x5c/0x74) from [<c01aa5a8>] (bus_probe_device+0x30/0x50) [<c01aa5a8>] (bus_probe_device+0x30/0x50) from [<c01a8c20>] (device_add+0x1f4/0x4c0) [<c01a8c20>] (device_add+0x1f4/0x4c0) from [<c01acaa0>] (platform_device_add+0xf0/0x194) [<c01acaa0>] (platform_device_add+0xf0/0x194) from [<bf094058>] (imx_phycore_init+0x58/0x98 [snd_soc_phycore_ac97]) [<bf094058>] (imx_phycore_init+0x58/0x98 [snd_soc_phycore_ac97]) from [<c0021374>] (do_one_initcall+0x2c/0x1a8) [<c0021374>] (do_one_initcall+0x2c/0x1a8) from [<c006e48c>] (sys_init_module+0xc4/0x1f8) [<c006e48c>] (sys_init_module+0xc4/0x1f8) from [<c00219e0>] (ret_fast_syscall+0x0/0x2c) Code: e1530002 0a000021 e597203c e5973010 (e5922008) ---[ end trace 79ad861a733eea22 ]--- 192 / # cat /proc/asound/cards --- no soundcards ---
A reboot, and I repeat the experiment. Nothing went bang, but nothing happened either:
192 / # modprobe snd-soc-phycore-ac97 192 / # mount /proc 192 / # lsmod Module Size Used by snd_soc_phycore_ac97 795 0 snd_soc_wm9712 17489 1 snd_soc_phycore_ac97 snd_soc_imx 10105 2 snd_soc_phycore_ac97,snd_soc_wm9712 snd_soc_core 45013 2 snd_soc_wm9712,snd_soc_imx ac97_bus 840 1 snd_soc_core snd_pcm 68536 2 snd_soc_imx,snd_soc_core snd_timer 18154 1 snd_pcm snd 48419 3 snd_soc_core,snd_pcm,snd_timer soundcore 5339 1 snd snd_page_alloc 3496 1 snd_pcm 192 / # cat /proc/asound/cards --- no soundcards --- 192 / # cat /proc/asound/devices 2: : timer
I'm not sure whether that is due to the CODEC not being found by the wm9712 driver (which is understandable; there isn't one) or whether there's bugs in the i.MX driver that leads to the devices attached not getting discovered.
Well, an update on the progress. On Tue, May 25, 2010 at 10:41:33AM +1000, Stuart Longland wrote:
On Mon, May 24, 2010 at 11:49:16AM +0100, Liam Girdwood wrote:
On Mon, 2010-05-24 at 17:49 +1000, Stuart Longland wrote:
Now this compiles... but when I go to load it; one of two things happens... either practically nothing (at this stage; no modules are loaded prior to calling modprobe):
It does sound like you have some memory corruption somewhere. Can you rule out your new CODEC driver by replacing it with another CODEC driver (ads117x.c is a very simple example).
Liam
Well, the plot thickens... I tried two things.
(1) I swapped my 'AIC3204 driver for the 'AIC3X driver that my driver was originally based upon, and retried loading the driver. No blowups, but now devices appearing in /proc/asound/cards or /proc/asound/devices.
I've pulled down the ASoC tree (via HTTP; git protocol seems blocked at my workplace) from the Wolfson Micro site and merged that into a new branch. In it there was another implementation of a machine driver for i.MX, so I tried playing with that instead. I noticed there was liberal use of pr_debug... googling told me how to enable it, and so I did it for each file in the ASoC tree.
I then noticed the following message:
Registered platform 'imx-audio' soc-audio soc-audio: DAI (null) not registered
Ah ha! Progress... but which DAI?? I made the following changes to soc-core:
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 998569d..95e5894 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1147,8 +1147,10 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) break; } if (!found) { - dev_dbg(card->dev, "DAI %s not registered\n", - card->dai_link[i].cpu_dai->name); + dev_dbg(card->dev, "CPU DAI %s not registered " + "(card %p dai_link %d cpu_dai=%p)\n", + card->dai_link[i].cpu_dai->name, + card, i, card->dai_link[i].cpu_dai ); return; }
@@ -1176,8 +1178,10 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) break; } if (!found) { - dev_dbg(card->dev, "DAI %s not registered\n", - card->dai_link[i].codec_dai->name); + dev_dbg(card->dev, "CODEC DAI %s not registered " + "(card %p dai_link %d codec_dai=%p)\n", + card->dai_link[i].codec_dai->name, + card, i, card->dai_link[i].codec_dai); return; } }
If there's any interest, I can format that as a patch and submit it... but it did help in telling me what DAI was not registered. I now get:
Registered platform 'imx-audio' soc-audio soc-audio: CPU DAI (null) not registered (card bf07d568 dai_link 0 cpu_dai=bf075f78) soc-audio soc-audio: Registered card 'JEM3'
Oookay then, it's the i.MX driver. I notice in the i.MX driver they do their registration inside the imx_ssi_probe (line 674)... so evidently that is not getting called. How does one trigger the kernel to probe i.MX SSI? Is there some special function call or initialisation thing that I've missed?
On Tue, May 25, 2010 at 12:26:50PM +1000, Stuart Longland wrote:
I now get:
Registered platform 'imx-audio' soc-audio soc-audio: CPU DAI (null) not registered (card bf07d568 dai_link 0 cpu_dai=bf075f78) soc-audio soc-audio: Registered card 'JEM3'
Well this one prooved to be an easy one; and the other SoC drivers in arch/arm/mach-mx2 lead the way. I just needed to register the platform device. I now get:
Registered platform 'imx-audio' Registered DAI 'imx-ssi.0' soc-audio soc-audio: CODEC DAI tlv320aic3x not registered (card bf07d568 dai_link 0 codec_dai=bf06b768) soc-audio soc-audio: Registered card 'JEM3'
Interestingly, I cannot register more than one SSI port... but this is a minor inconvenience. I suspect the issue now is that I must somehow convince the system to add the CODEC driver as a platform device.
On Tue, 2010-05-25 at 12:26 +1000, Stuart Longland wrote:
If there's any interest, I can format that as a patch and submit it...
I'm very interested... I've an I.MX31 and a tlv320aic3x
I've tried to import your driver in our 2.6.30 tree ( http://gitorious.org/bug/bug-1x-linux-2-6-30/commits/bug1x-2.6.30 ) and I have now the following issue:
# modprobe bugsound No device for DAI tlv320aic3x bug1x_soc_init: hello... bug1x_soc_init: bug1x_snd_device = c79240c0 bug1x_soc_init: calling platform_set_drvdata( c79240c0, bf07b66c) bug1x_soc_init: calling platform_device_add(c79240c0) bug1x_soc_init: platform_device_add(c79240c0) = 0 bug1x_soc_init = 0 (success)
I'll re-read the mails and try harder... Thanks a lot!!!!
Denis.
On Tue, May 25, 2010 at 06:46:47PM +0200, gnutoo wrote:
On Tue, 2010-05-25 at 12:26 +1000, Stuart Longland wrote:
If there's any interest, I can format that as a patch and submit it...
I'm very interested... I've an I.MX31 and a tlv320aic3x
I've tried to import your driver in our 2.6.30 tree ( http://gitorious.org/bug/bug-1x-linux-2-6-30/commits/bug1x-2.6.30 ) and I have now the following issue:
# modprobe bugsound No device for DAI tlv320aic3x bug1x_soc_init: hello... bug1x_soc_init: bug1x_snd_device = c79240c0 bug1x_soc_init: calling platform_set_drvdata( c79240c0, bf07b66c) bug1x_soc_init: calling platform_device_add(c79240c0) bug1x_soc_init: platform_device_add(c79240c0) = 0 bug1x_soc_init = 0 (success)
I'll re-read the mails and try harder... Thanks a lot!!!!
Well, the "No device for DAI" message seems to be related to what's registered for your board's I²C bus... e.g. I have in a file; arch/arm/mach-mx2/mach-tx27.c (this isn't in tree yet; but I hope to contribute it someday):
static struct i2c_board_info tx27_i2c0_devices[] __initdata = { { I2C_BOARD_INFO("24c16", 0x50), .platform_data = &tx27_eeprom, .type = "24c16", }, { I2C_BOARD_INFO("tlv320aic3204", 0x18), .type = "tlv320aic3204", }, #if defined(CONFIG_RTC_DRV_DS1307) || defined(CONFIG_RTC_DRV_DS1307_MODULE) { I2C_BOARD_INFO("ds1339", 0x68/*DS1339_CHIP_ID*/), .type = "ds1339", }, #endif };
That seems to help with getting the CODEC initialised and probed correctly. Likewise; similar is needed for the i.MX I²S bus, simply having the driver in-kernel isn't enough:
in my board_init function: mxc_register_device(&imx_ssi_device0, &tx27_ssi_pdata[0]); /*mxc_register_device(&imx_ssi_device1, &tx27_ssi_pdata[1]);*/
Note the second one is commented out; I cannot seem to register both, the second one always fails. The tx27_ssi_pdata is straightforward:
static struct imx_ssi_platform_data tx27_ssi_pdata[] = { /* SSI1 */ { .flags = 0, }, /* SSI2 */ { .flags = 0, }, };
I'm not sure if this is right; but it seems to work. On this project, my issue now is getting data out of the I²S bus. The CODEC is generating the bit clock and frame sync; I *think* I have AUDMUX set up correctly -- HPCR1 is set to output receive data, frame sync & clock all sourced from HPCR3; HPCR3 is set to receive data from HPCR1, and take its frame sync & clock from the external port... I'll provide my debugfs patch for audmux-v1.c and its output tomorrow.
At the moment, when I go to play audio; I see the CODEC being set up ... but despite the clocks being present -- I see no audio data, and the DMA transfer eventually times out with the message "playback write error (DMA or IRQ trouble?)" after 10 seconds. Would anyone know where I'd look for that? Is there something else needed in the configuration of the SSI driver for this to work?
Thanks for the assistance thus far. Regards,
On Wed, May 26, 2010 at 11:21:36PM +1000, Stuart Longland wrote:
At the moment, when I go to play audio; I see the CODEC being set up ... but despite the clocks being present -- I see no audio data, and the DMA transfer eventually times out with the message "playback write error (DMA or IRQ trouble?)" after 10 seconds. Would anyone know where I'd look for that? Is there something else needed in the configuration of the SSI driver for this to work?
This most likely means your CPU side configuration is broken and clocks aren't being routed through. Try looking at the AUDMUX debugfs files to verify your configuration, and also try routing out to another external SSI port so you can probe signals. Make sure the relevant pins on the i.MX are configured into the appropriate mode for use by the i.MX too.
Note also that the current driver only supports CODEC as clock master.
On Thu, May 27, 2010 at 01:47:03AM +0100, Mark Brown wrote:
On Wed, May 26, 2010 at 11:21:36PM +1000, Stuart Longland wrote:
At the moment, when I go to play audio; I see the CODEC being set up ... but despite the clocks being present -- I see no audio data, and the DMA transfer eventually times out with the message "playback write error (DMA or IRQ trouble?)" after 10 seconds. Would anyone know where I'd look for that? Is there something else needed in the configuration of the SSI driver for this to work?
This most likely means your CPU side configuration is broken and clocks aren't being routed through. Try looking at the AUDMUX debugfs files to verify your configuration, and also try routing out to another external SSI port so you can probe signals. Make sure the relevant pins on the i.MX are configured into the appropriate mode for use by the i.MX too.
Note also that the current driver only supports CODEC as clock master.
I figured this might be the case, now to figure out why the clocks aren't getting through.
The CODEC chip we're using can work either way; I²S master or slave. So switching it to work the other way is an easy proposition. My work thus far has been using the CODEC as master. The CODEC however, sources its clock (on MCLK) from the clock pin on SSI3.
I have a userspace application that mmaps the registers for SSI2 and AUDMUX, and sets this up, so no big deal ... the clock it receives is about 12.1MHz (12.093MHz according to the frequency counter here).
Ka-Ro's TX27 module don't make any other SSI ports accessible (to my knowledge). So in that regard; I can't directly test using the above method. However, I have tried something similar. The TLV320AIC3204 CODEC IC can route clocks from a secondary audio interface. Using I�C commands, I was able to tell it to pretend its "GPIO" pin was the secondary audio interface bit clock -- this pin is connected to the SSI4 interrupt line; and is being weakly pulled up by the i.MX27.
The CODEC therefore routed this out on its BCLK pin, connected to SSI4_CLK. I told AUDMUX to route this through to SSI3_CLK and watched that on the CRO. So to clarify (please forgive the ASCII-art)...
Pull-up: : | : : i.MX27 SSI4_INT <<<--+-:----+-----------------:-----+-->>> GPIO CODEC AUDMUX : '--> Probe to 0v : |<-- Internal link SSI4_CLK <<<--+-:----------------------:-<<<-+----- BCLK Internal Link---->| : : SSI3_CLK >>>--+-:----+-----------------:->>>------- MCLK '--> CRO
Whenever I touched the probe to 0v; the MCLK dropped almost immediately... I was not able to measure the delay on the scope here.
When I try to play audio; the AUDMUX configuration is as follows: Port: imx-ssi.0 Raw: cb205000 TxFS output from SSI4, TxClk output from SSI4 Port is symmetric Data received from SSI4 Port: imx-ssi.1 Raw: 00001000 TxFS input, TxClk input Port is symmetric Data received from imx-ssi.0 Port: SSI4 Raw: 00001000 TxFS input, TxClk input Port is symmetric Data received from imx-ssi.0 Port: SSI1 Raw: 00001000 TxFS input, TxClk input Port is symmetric Data received from imx-ssi.0 Port: SSI2 Raw: 00001000 TxFS input, TxClk input Port is symmetric Data received from imx-ssi.0 Port: SSI3 Raw: c4103000 TxFS output from imx-ssi.1, TxClk output from imx-ssi.1 Port is symmetric Data received from imx-ssi.1
I'll have a look at the Eukrea CPUIMX27 and baseboard SoC support in a moment, since it looks very similar to what we're doing (in that it's a TI I²S CODEC hooked to an i.MX27 on SSI4) ... this might reveal clues as to what I'm doing wrong. -- Stuart Longland (aka Redhatter, VK4MSL) .'''. Gentoo Linux/MIPS Cobalt and Docs Developer '.'` : . . . . . . . . . . . . . . . . . . . . . . .'.' http://dev.gentoo.org/~redhatter :.'
I haven't lost my mind... ...it's backed up on a tape somewhere.
Hi Stuart,
Le 28/05/2010 04:06, Stuart Longland a écrit :
I'll have a look at the Eukrea CPUIMX27 and baseboard SoC support in a moment, since it looks very similar to what we're doing (in that it's a TI I²S CODEC hooked to an i.MX27 on SSI4) ... this might reveal clues as to what I'm doing wrong.
we are using the TLV320AIC23B codec in master mode on the CPUIMX27/MBIMX27 (and did the same on an other board using a TLV3204 as a master with a 12MHz oscillator on its MCLK: for this one, it's necessary to configure several dozens of registers through I2C to get it running)
The TLV3204 is wired this way : - MCK = 12MHz ocillator - BCLK (pin2) = PC19 (SSI4_CLK) (TLV output / IMX in) - WCLK (pin3) = PC16 (SSI4_FS) (TLV output / IMX in) - DIN/MFP1 (pin4) = PC18 (SSI4_TXDAT) (TLV input / IMX out) - DOUT/MFP2 (pin5) = PC17 (SSI4_RXDAT) (TLV output / IMX in) - SPI_SELECT (pin12) = pull down to select I2C mode - SCL & SDA (pins 9 & 10) = I2C2 all the interface between i.MX & TLV is powered in 1.8V.
I'll try to find our I2C init sequence and send it to you as this was the hardest part of the thing to get the codec running.
Eric
On Fri, May 28, 2010 at 07:55:19AM +0200, Eric B??nard wrote:
Hi Stuart,
Don't drop CCs from mailing list postings, you should always maintain CCs for kernel related lists.
I'll try to find our I2C init sequence and send it to you as this was the hardest part of the thing to get the codec running.
Under Linux you'd normally not be using just a hard coded sequence of I2C writes...
Le 28/05/2010 13:08, Mark Brown a écrit :
On Fri, May 28, 2010 at 07:55:19AM +0200, Eric B??nard wrote:
Hi Stuart,
Don't drop CCs from mailing list postings, you should always maintain CCs for kernel related lists.
sorry, wrong button pushed.
I'll try to find our I2C init sequence and send it to you as this was the hardest part of the thing to get the codec running.
Under Linux you'd normally not be using just a hard coded sequence of I2C writes...
I agree with you, but this can be useful for board bring up and hardware debug.
Eric
Hi Eric, On Fri, May 28, 2010 at 07:55:19AM +0200, Eric Bénard wrote:
Hi Stuart,
Le 28/05/2010 04:06, Stuart Longland a écrit :
I'll have a look at the Eukrea CPUIMX27 and baseboard SoC support in a moment, since it looks very similar to what we're doing (in that it's a TI I²S CODEC hooked to an i.MX27 on SSI4) ... this might reveal clues as to what I'm doing wrong.
we are using the TLV320AIC23B codec in master mode on the CPUIMX27/MBIMX27 (and did the same on an other board using a TLV3204 as a master with a 12MHz oscillator on its MCLK: for this one, it's necessary to configure several dozens of registers through I2C to get it running)
The TLV3204 is wired this way :
- MCK = 12MHz ocillator
- BCLK (pin2) = PC19 (SSI4_CLK) (TLV output / IMX in)
- WCLK (pin3) = PC16 (SSI4_FS) (TLV output / IMX in)
- DIN/MFP1 (pin4) = PC18 (SSI4_TXDAT) (TLV input / IMX out)
- DOUT/MFP2 (pin5) = PC17 (SSI4_RXDAT) (TLV output / IMX in)
- SPI_SELECT (pin12) = pull down to select I2C mode
- SCL & SDA (pins 9 & 10) = I2C2
all the interface between i.MX & TLV is powered in 1.8V.
I'll try to find our I2C init sequence and send it to you as this was the hardest part of the thing to get the codec running.
Well, over the last few days I've been looking closely at the signals generated. Especially this morning... yesterday, I managed to get some sound out of the CODEC when operating in I²S master mode (yes, I have a patch that I need to clean up first).
What I observed is that despite being configured for I²S master, what I infact saw, was more like DSP mode, with a 1-bit frame sync pulse. The remainder of my experimentation has been using the DSP modes of both MCU and CODEC.
I'm using the following script to generate audio data for testing:
while true; do printf "\x55\xff\xaa\x00"; done > test.raw
This is then played to the CODEC; using aplay: aplay -D hw:0,0 -f S16_LE -r 48000 -c 2 test.raw
I'm now using the SSI port in DSP SSI Slave mode; so single bit frame pulse. I'm not sure what format the CODEC expects its data to be in, but what I observe is two things:
(1) Each sample is sign-extended to 32-bits. (2) The data is then sent, least significant 16-bits first. (3) The frame sync pulses are sent just before the start of each (sign-extended) sample.
On the CRO; (again, appologies for ASCII art) it looks like this: (Frame sync is top trace) .-. .-, | | | | -' '------------------------------------------------------------' '-> ----. .-. .-. .-. .-. .-> | | | | | | | | | | '--------------' '-' '-' '-' '--------------------------------' |<---- MSB ----><---- LSB ----><----- Sign Extension??? ----->| |<------------------------ Channel 1 ------------------------>|
... diagram continues; second sync pulse is shown again... .-. .-. | | | | <-' '-----------------------------------------------------------' '-> .--------------. .-. .-. .-. .--------------------------------. | | | | | | | | | | <---' '-' '-' '-' '-' '-> |<---- MSB ----><---- LSB ----><----- Sign Extension??? ----->| |<------------------------ Channel 2 ------------------------>|
Now, my understanding is that the frame sync pulse indicates the start of the frame, and that the frame consists of (in this case) 32 bits; which is the concatenation of the two 16-bit samples. In addition, the documentation I see, AFAIK, suggests that this data should be transmitted in big-endian (MSB first) order. However, what I see here is that each sample is being sent, followed by what appears to be a sign-extend ... or what would be sign extend IFF we were using 32-bit LSB. I'm not sure that this looks right, and could explain why I just get semi-random noise rather than the audio I'm expecting.
I'm happy to share with others the CODEC driver I've written thus far ... but a query, how is the best way to share this for collaborative work? It's not a finished driver, but it does at least initialise the CODEC and get the bus working... it then allows manipulation of registers from the I²C interface via two files in sysfs -- since loading it prevents i2c-tools from working. Otherwise, the driver does load, and at least does some setup.
Regards,
On Tue, Jun 01, 2010 at 01:30:27PM +1000, Stuart Longland wrote:
Hi Eric, On Fri, May 28, 2010 at 07:55:19AM +0200, Eric Bénard wrote:
Hi Stuart,
Well, over the last few days I've been looking closely at the signals generated. Especially this morning... yesterday, I managed to get some sound out of the CODEC when operating in I²S master mode (yes, I have a patch that I need to clean up first).
What I observed is that despite being configured for I²S master, what I infact saw, was more like DSP mode, with a 1-bit frame sync pulse. The remainder of my experimentation has been using the DSP modes of both MCU and CODEC.
Well, I managed to get the CODEC working as the I²S master, and managed to get good quality audio. The cause of my earlier DMA issues: not enabling DMA in the SSI device flags. I guess I assumed this was the default.
Now I just have to get the audio level up to something that's reasonable for the application ... the volume knob is somewhere amongst these registers, now I just have to find it and turn it up (and make it accessible via ALSA). I'll look at cleaning up this driver and submitting it for further work.
For the benefit of those working with the TLV320AIC3204 CODEC, I release this *very experimental* and incomplete driver to hopefully encourage further work. I haven't made it available as a patch; rather just attached the driver and its header file, since the driver is far from complete. These files go in sound/soc/codecs, with appropriate entries into Kconfig and Makefile.
Presently, I'm working on defining all the registers, and considering methods for allowing their configuration via the APIs available.
The TLV320AIC3204 CODEC exposes its registers in individual "pages"; the first register (reg 0) is the page select register, the remaining registers change in meaning depending on what page is selected. In the CODEC driver, I therefore use a 16-bit addressing scheme, whereby the upper 8-bits indicates the page number, and the lower 8-bits is the actual register address used. Page select is *always* at register 0x0000 in cache. When a register on a different page is accessed, the page is switched first before accessing the register. I'm not certain if this is the best approach; but it was the only way that made sense.
The CODEC driver claims total control of the I2C device, and therefore makes it impossible to alter registers using i2c-tools. However, as a work-around; I have provided read/write access to the registers via sysfs... we use the AIC3204 attached to I2C bus 0; the CODEC therefore lives under:
/sys/bus/i2c/devices/0-0018
There are two files: - regsel: Takes or reports back the 16-bit register address in hexadecimal - regdata: Reads or writes the value of the register
`i2cget -y 0 0x18` and `i2cset -y 0 0x18` can be replaced by the following shell functions:
acget () { printf "0x%02x%02x\n" $1 > /sys/bus/i2c/devices/0-0018/regsel cat /sys/bus/i2c/devices/0-0018/regdata }
acset () { printf "0x%02x%02x\n" $1 > /sys/bus/i2c/devices/0-0018/regsel printf "0x%02x\n" $2 > /sys/bus/i2c/devices/0-0018/regdata }
At most, to get sound out, you may need to use the above two functions to set your routing and levels. Register dumps can also be done using shell scripting, although it's slower than the i2cdump tool.
Other things that need work; - PLL support doesn't seem to work ... this will need adjustment - Sample rates are "off"... 48kHz audio gets played at ~52kHz for example (see above comment about PLL) - Routing is hard-coded at present - In my testing, sound output is low in amplitude
I hope to address some of these over this week, but in the meantime I'll provide my work in its current form in the hope that we can build upon this and improve it for inclusion in the Linux kernel.
On Tue, Jun 01, 2010 at 09:32:38PM +1000, Stuart Longland wrote:
I know this isn't a proper submission but a few comments below. This looks like it'd be relatively easy to get submitted by stripping out a lot of the commented out code and custom interfaces (like the DA7210 driver).
The CODEC driver claims total control of the I2C device, and therefore makes it impossible to alter registers using i2c-tools. However, as a work-around; I have provided read/write access to the registers via sysfs... we use the AIC3204 attached to I2C bus 0; the CODEC therefore lives under:
/sys/bus/i2c/devices/0-0018
There are two files:
- regsel: Takes or reports back the 16-bit register address in hexadecimal
- regdata: Reads or writes the value of the register
ASoC already provides register read/write access via debugfs as standard, there's no need to implement this.
struct aic3204_setup_data { unsigned int gpio_func[2]; };
This would normally be platform data in a file in include/sound so it can be set by the architecture code when the device is registered.
/* TODO: PLL */ /* #define ENABLE_PLL */
/* SYSFS Interface -- we should move this to debugfs */ static ssize_t aic3204_show_regsel(struct device *dev, struct device_attribute *attr, char *buf); static ssize_t aic3204_store_regsel(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); static ssize_t aic3204_show_regdata(struct device *dev, struct device_attribute *attr, char *buf); static ssize_t aic3204_store_regdata(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); static DEVICE_ATTR(regsel, S_IWUSR | S_IRUGO, aic3204_show_regsel, aic3204_store_regsel); static DEVICE_ATTR(regdata, S_IWUSR | S_IRUGO, aic3204_show_regdata, aic3204_store_regdata);
As I said above this is redundant and can be removed.
#if 0 printk( KERN_INFO "%s: pg %d reg %d[%04x] => %02x\n", __func__, reg >> 8, reg & 0xff, reg, value[0] ); #endif
dev_dbg().
}
/*
- Perform a read/modify/write cycle on a register.
- This is a shorthand function, it reads the specified register, masks out the
- bits in and_mask, applies bits in or_mask, then writes out the result to the
- register.
- It returns the modified value; or a negative error code.
*/
There's a standard snd_soc_update_bits() function in ASoC.
/*
- All input lines are connected when !0xf and disconnected with 0xf bit field,
- so we have to use specific dapm_put call for input mixer
*/
Could you explain in more detial what this is doing? I'm not immediately seeing what this is doing but I suspect it might be a value mux?
#if 0
Just drop if 0ed sections.
#define LDAC_ENUM 0 #define RDAC_ENUM 1 #define LHPCOM_ENUM 2 #define RHPCOM_ENUM 3 #define LINE1L_ENUM 4 #define LINE1R_ENUM 5 #define LINE2L_ENUM 6 #define LINE2R_ENUM 7 #define ADC_HPF_ENUM 8
static const struct soc_enum aic3204_enum[] = { SOC_ENUM_SINGLE(DAC_LINE_MUX, 6, 3, aic3204_left_dac_mux),
Use individually named variables rather than a table for legibility.
/* Turn on ADC or DAC */ if ( substream->stream == SNDRV_PCM_STREAM_PLAYBACK ) { aic3204_write(codec, AIC3204_DACS1, AIC3204_DACS1_LDAC_UP | AIC3204_DACS1_RDAC_UP | AIC3204_DACS1_LDACD_LEFT | AIC3204_DACS1_RDACD_RIGHT | AIC3204_DACS1_SOFT_DIS );
DAPM ought to be figuring this out for you...
/* This all needs to be done elsewhere */
Yes.
void aic3204_set_headset_detection(struct snd_soc_codec *codec, int detect, int headset_debounce, int button_debounce) { #if 0
There's standard ASoC jack detection which this should integrate with.
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) /*
- AIC3204 2 wire address can be up to 4 devices with device addresses
- 0x18, 0x19, 0x1A, 0x1B
*/
/*
- If the i2c layer weren't so broken, we could pass this kind of data
- around
*/ static int aic3204_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
Use standard device model registration - the driver you were basing this on has been converted now...
Hi Mark,
On Thu, Jun 03, 2010 at 12:14:56PM +0100, Mark Brown wrote:
On Tue, Jun 01, 2010 at 09:32:38PM +1000, Stuart Longland wrote:
I know this isn't a proper submission but a few comments below. This looks like it'd be relatively easy to get submitted by stripping out a lot of the commented out code and custom interfaces (like the DA7210 driver).
Yeah... I left it there for now as I'm referring to it (and other drivers) as I go... gradually I'm replacing the ifdef'd code with my own.
The CODEC driver claims total control of the I2C device, and therefore makes it impossible to alter registers using i2c-tools. However, as a work-around; I have provided read/write access to the registers via sysfs... we use the AIC3204 attached to I2C bus 0; the CODEC therefore lives under:
/sys/bus/i2c/devices/0-0018
There are two files:
- regsel: Takes or reports back the 16-bit register address in hexadecimal
- regdata: Reads or writes the value of the register
ASoC already provides register read/write access via debugfs as standard, there's no need to implement this.
Ahh okay, wasn't aware of this. I shall investigate.
struct aic3204_setup_data { unsigned int gpio_func[2]; };
This would normally be platform data in a file in include/sound so it can be set by the architecture code when the device is registered.
In the latest version of the driver, I've ditched this for now. In its place I have provided a mechanism for presetting all registers to an arbitrary values which can be defined by the machine driver ... but even this is temporary.
There's a lot of configuration options available; such as filter coefficients and power modes. These should all ultimately be done using the existing standard APIs ... but for now, I've done something quick and *very* dirty.
/* TODO: PLL */ /* #define ENABLE_PLL */
And I managed to get the PLL working. :-)
#if 0 printk( KERN_INFO "%s: pg %d reg %d[%04x] => %02x\n", __func__, reg >> 8, reg & 0xff, reg, value[0] ); #endif
dev_dbg().
}
/*
- Perform a read/modify/write cycle on a register.
- This is a shorthand function, it reads the specified register, masks out the
- bits in and_mask, applies bits in or_mask, then writes out the result to the
- register.
- It returns the modified value; or a negative error code.
*/
There's a standard snd_soc_update_bits() function in ASoC.
I will have a look at that. Out of interest, is there an up-to-date guide on this information? I'm finding it difficult to find all these functions, much less understand what they do.
/*
- All input lines are connected when !0xf and disconnected with 0xf bit field,
- so we have to use specific dapm_put call for input mixer
*/
Could you explain in more detial what this is doing? I'm not immediately seeing what this is doing but I suspect it might be a value mux?
That comment will disappear, once I know what the function it refers to is updated (at the moment it's a stub). The comment is one of many left-overs from the TLV320AIC3x driver.
static const struct soc_enum aic3204_enum[] = { SOC_ENUM_SINGLE(DAC_LINE_MUX, 6, 3, aic3204_left_dac_mux),
Use individually named variables rather than a table for legibility.
Again, this is a reminant of the old driver. I do use separate variables in the latest version.
/* Turn on ADC or DAC */ if ( substream->stream == SNDRV_PCM_STREAM_PLAYBACK ) { aic3204_write(codec, AIC3204_DACS1, AIC3204_DACS1_LDAC_UP | AIC3204_DACS1_RDAC_UP | AIC3204_DACS1_LDACD_LEFT | AIC3204_DACS1_RDACD_RIGHT | AIC3204_DACS1_SOFT_DIS );
DAPM ought to be figuring this out for you...
Indeed, up the top of my TODO list is to figure out DAPM. :-)
void aic3204_set_headset_detection(struct snd_soc_codec *codec, int detect, int headset_debounce, int button_debounce) { #if 0
There's standard ASoC jack detection which this should integrate with.
I did see mention of this, and will have a look when I get closer to that point.
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) /*
- AIC3204 2 wire address can be up to 4 devices with device addresses
- 0x18, 0x19, 0x1A, 0x1B
*/
/*
- If the i2c layer weren't so broken, we could pass this kind of data
- around
*/ static int aic3204_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
Use standard device model registration - the driver you were basing this on has been converted now...
I shall have a look at that too. For what it's worth, the comment about the addresses is invalid... the AIC3x family were configurable, the AIC3204 is *always* at 0x18.
I've put an updated version of the driver online... along with some explanitory notes:
http://www.longlandclan.yi.org/~stuartl/asoc/
The driver at this point plays audio fine, but won't record ... I just get semi-random noise with a odd-looking square wave pattern. (Not like clipping; more like the quantisation you'd see if using 4-bit PCM.)
I'm working on the mixer interface at present... as the ADC won't record anything useful unless the mixer is configured right. My problem though, is trying to understand what all the macros do. Is there a good reference on how to write these drivers?
Regards,
On Thu, Jun 03, 2010 at 09:43:49PM +1000, Stuart Longland wrote:
I will have a look at that. Out of interest, is there an up-to-date guide on this information? I'm finding it difficult to find all these functions, much less understand what they do.
If you generate the kerneldoc it should cover most things I guess.
I'm working on the mixer interface at present... as the ADC won't record anything useful unless the mixer is configured right. My problem though, is trying to understand what all the macros do. Is there a good reference on how to write these drivers?
Not really - in general it's just a question of looking at each individual control that the device has and mapping that into the ASoC domain. There's generally a 1:1 mapping between the controls in the register map and ASoC.
On Fri, May 28, 2010 at 12:06:25PM +1000, Stuart Longland wrote:
I have a userspace application that mmaps the registers for SSI2 and AUDMUX, and sets this up, so no big deal ... the clock it receives is about 12.1MHz (12.093MHz according to the frequency counter here).
In production this should be done in-kernel.
When I try to play audio; the AUDMUX configuration is as follows:
Port: imx-ssi.0 Raw: cb205000 TxFS output from SSI4, TxClk output from SSI4 Port is symmetric Data received from SSI4
Port: SSI4 Raw: 00001000 TxFS input, TxClk input Port is symmetric Data received from imx-ssi.0
This appears reasonable at first glance.
I'll have a look at the Eukrea CPUIMX27 and baseboard SoC support in a moment, since it looks very similar to what we're doing (in that it's a TI I²S CODEC hooked to an i.MX27 on SSI4) ... this might reveal clues as to what I'm doing wrong.
Have you also checked the pin mux configuration for the i.MX?
On Fri, May 28, 2010 at 01:27:12PM +0100, Mark Brown wrote:
On Fri, May 28, 2010 at 12:06:25PM +1000, Stuart Longland wrote:
I have a userspace application that mmaps the registers for SSI2 and AUDMUX, and sets this up, so no big deal ... the clock it receives is about 12.1MHz (12.093MHz according to the frequency counter here).
In production this should be done in-kernel.
Indeed... I spent some of yesterday afternoon doing exactly this... which involved some hacking in arch/arm/mach-mx2/clocks_imx27.c... and a _very_ ugly hack to get at the SSI2 registers in my machine driver. It works, but with a few bugs, and will need a big cleanup before I can even consider putting it in mainline.
When I try to play audio; the AUDMUX configuration is as follows:
Port: imx-ssi.0 Raw: cb205000 TxFS output from SSI4, TxClk output from SSI4 Port is symmetric Data received from SSI4
Port: SSI4 Raw: 00001000 TxFS input, TxClk input Port is symmetric Data received from imx-ssi.0
This appears reasonable at first glance.
I'll have a look at the Eukrea CPUIMX27 and baseboard SoC support in a moment, since it looks very similar to what we're doing (in that it's a TI I²S CODEC hooked to an i.MX27 on SSI4) ... this might reveal clues as to what I'm doing wrong.
Have you also checked the pin mux configuration for the i.MX?
I'm not confident on how this is configured; but I have in an array; tx27_pins[] (defined in arch/arm/mach-mx2/mach-tx27.c):
/* SSI3 */ PC28_PF_SSI3_FS, PC29_PF_SSI3_RXD, PC30_PF_SSI3_TXD, PC31_PF_SSI3_CLK, /* SSI4 */ PC16_PF_SSI4_FS, PC17_PF_SSI4_RXD, PC18_PF_SSI4_TXD, PC19_PF_SSI4_CLK,
... which is later set up in tx27_board_init(): mxc_gpio_setup_multiple_pins(tx27_pins, ARRAY_SIZE(tx27_pins), "tx27");
This is what I've seen done on other boards (my mach-tx27.c is based on mach-mx27ads.c). Regards,
participants (5)
-
Eric Bénard
-
gnutoo
-
Liam Girdwood
-
Mark Brown
-
Stuart Longland