* Re: powerpc: DMA coherent allocations broken for CONFIG_NOT_COHERENT_CACHE
From: Benjamin Herrenschmidt @ 2009-05-25 0:21 UTC (permalink / raw)
To: Grant Likely; +Cc: linuxppc-dev, Albert Herranz, Ilya Yanok
In-Reply-To: <1243160487.22770.59.camel@pasglop>
On Sun, 2009-05-24 at 20:21 +1000, Benjamin Herrenschmidt wrote:
> We need to see if we can get the vmalloc allocator safe for GFP_ATOMIC
> context, might be doable.
>
> As for free, unfortunately, even the old allocator won't help with SMP,
> since that needs to do IPIs for cross TLB invalidates.
>
> Maybe we should enqueue free blocks and do the actual freeing from a
> workqueue or something similar.
Ok, so here's my conclusion:
First, I need to apologize as I'm the one iirc who told Ilya to
implement it that way... oops.
I don't think we can easily get the mm/vmalloc.c code irq safe,
especially not since it got bloated recently for scalability.
So at this stage, we have no choice I think be re-instate the old code.
This won't fix all the issues because we still can't do TLB shootdown in
SMP at interrupt time, but I don't think there's any released platform
in 2.6.30 that does SMP and non-coherent DMA, so we can fix that later.
I'll do the revert as it's not trivial (we removed CONFIG_CONSISTENT_*
etc...) for now.
Note that I still think the right approach in the long run is to ban the
consistent allocs from atomic contexts generically in linux, though that
will be a hard nut to crack.
Cheers,
Ben.
> Cheers,
> Ben.
>
> > On Thu, May 21, 2009 at 10:50 AM, Albert Herranz
> > <albert_herranz@yahoo.es> wrote:
> > >
> > > Hello list,
> > >
> > > Commit 33f00dcedb0e22cdb156a23632814fc580fcfcf8 seems to have broken DMA coherent allocations for CONFIG_NOT_COHERENT_CACHE platforms.
> > >
> > > The problems seem to be that the new __dma_alloc_coherent() and __dma_free_coherent() implementations:
> > >
> > > - don't respect anymore the passed gfp flags (__dma_alloc_coherent() unconditionally uses GFP_KERNEL within the function irrespective of the caller flags)
> > > - can't be used in interrupt context as they use get_vm_area_caller()/vfree() which end up triggering BUG_ON(in_interrupt())
> > >
> > > One victim happens to be the USB core subsystem which sometimes frees dma coherent memory in interrupt context for drivers flagged HCD_LOCAL_MEM.
> > >
> > > This has been experienced while writing a new EHCI driver for the Nintendo Wii platform.
> > >
> > > usb 1-1: new high speed USB device using ehci-mipc and address 2
> > > ------------[ cut here ]------------
> > > kernel BUG at mm/vmalloc.c:1328!
> > > Oops: Exception in kernel mode, sig: 5 [#1]
> > > PREEMPT wii
> > > Modules linked in:
> > > NIP: c008ea20 LR: c0015890 CTR: c00111d4
> > > REGS: d2c65b10 TRAP: 0700 Not tainted (2.6.30-rc2-isobel-wii-00092-gcba94db-dirty)
> > > MSR: 00021032 <ME,CE,IR,DR> CR: 42482028 XER: 00000000
> > > TASK = d2c600f0[28] 'kmmcd' THREAD: d2c64000
> > > GPR00: 00010000 d2c65bc0 d2c600f0 d4030000 d4030000 d4030000 12da1000 00000001
> > > GPR08: 00000000 d2c64000 00000020 00000000 22482022 94fdfb98 6e1979bc c6bbdbdd
> > > GPR16: 00000020 00200200 00100100 d4020060 00000001 d401c0ec 00000001 d401c0ec
> > > GPR24: d2d9a6c0 00000000 00000000 d2f69de0 d2d9a600 d2f69e30 d2f69e2c d2da08e0
> > > NIP [c008ea20] vfree+0xc/0x18
> > > LR [c0015890] __dma_free_coherent+0x14/0x24
> > > Call Trace:
> > > [d2c65bc0] [c0017af8] __mipc_recv_req+0x160/0x178 (unreliable)
> > > [d2c65bd0] [c00111ec] dma_direct_free_coherent+0x18/0x28
> > > [d2c65be0] [c01cfca4] hcd_free_coherent+0x7c/0x12c
> > > [d2c65c10] [c01d00b8] unmap_urb_for_dma+0x150/0x1cc
> > > [d2c65c20] [c01d0174] usb_hcd_giveback_urb+0x40/0xe4
> > > [d2c65c30] [c01df474] ehci_urb_done+0xf0/0x114
> > > [d2c65c50] [c01e3870] qh_completions+0x41c/0x4dc
> > > [d2c65ca0] [c01e44e0] scan_async+0x9c/0x1a0
> > > [d2c65cc0] [c01e49ec] ehci_work+0x58/0xc4
> > > [d2c65cd0] [c01e5424] ehci_irq+0x22c/0x230
> > > [d2c65d00] [c01cfa88] usb_hcd_irq+0x50/0xa8
> > > [d2c65d20] [c00597d8] handle_IRQ_event+0xdc/0x250
> > > [d2c65d60] [c005ba20] handle_level_irq+0x9c/0x138
> > > [d2c65d80] [c001cbc8] hollywood_pic_irq_cascade+0x7c/0xf8
> > > [d2c65da0] [c00064b4] do_IRQ+0x9c/0xc4
> > > [d2c65dc0] [c0011fb8] ret_from_except+0x0/0x14
> > >
> > > Any comments on how to address this issue (other than reverting the above mentioned commit, which fixes it) are welcome.
> > >
> > > Thanks,
> > > Albert
> > >
> > >
> > >
> > >
> > > _______________________________________________
> > > Linuxppc-dev mailing list
> > > Linuxppc-dev@ozlabs.org
> > > https://ozlabs.org/mailman/listinfo/linuxppc-dev
> > >
> >
> >
> >
^ permalink raw reply
* Re: U-boot and linux command line parameters
From: David Gibson @ 2009-05-25 0:06 UTC (permalink / raw)
To: Mirek23; +Cc: linuxppc-dev
In-Reply-To: <23698384.post@talk.nabble.com>
On Sun, May 24, 2009 at 02:38:52PM -0700, Mirek23 wrote:
>
> Dear All,
>
> I use linux kernel 2.6.23 and u-boot 1.2.0 (on ppc405 virtex-4 ) for
> some time. All works fine when the kernel together with initramfs is
> smaller than 8MB. If it is bigger than the kernel does not boot
> properly.
>
> First of all I would like to know how the address for the linux
> command line parameters is "transferred" from u-boot to linux for
> ppc405 (virtex4 chip)? (via some registers or is it a fixed address
> in the memory ie. 8MB?) Does somebody know what should be changed,
> in the kernel, in order to move this limitation from 8MB to let say
> 12MB? I would be grateful for any hint.
IIRC, U-boot 1.2.0 is a version of u-boot before it became device tree
aware. Which means if I'm reading the cuboot.c code correctly, the
command line address is passed to the kernel at entry in r6, with the
length in r7. With later, device-tree aware u-boot versions, the
command line is instead passed as a device tree property.
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
^ permalink raw reply
* Re: [net-next-2.6 PATCH v2] can: SJA1000: generic OF platform bus driver
From: Arnd Bergmann @ 2009-05-24 22:27 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Linux Netdev List, devicetree-discuss
In-Reply-To: <4A18298E.8090209@grandegger.com>
On Saturday 23 May 2009, Wolfgang Grandegger wrote:
> Arnd Bergmann wrote:
> >
> > Minor nitpicking: dev->base_addr should be defined as an __iomem pointer
> > so you can avoid the cast here and in the ioremap/iounmap path.
>
> Here the member "base_addr" of "struct net_device" is used and it's not
> up to me to change the type.
Right, that makes sense. However, most drivers use the field to store the
physical address, not the iomap token. Maybe there should be a new field
in struct sja1000_priv for the virtual address, but that would be a change
to the base driver, not just to the OF portion.
Thanks,
Arnd <><
^ permalink raw reply
* Re: U-boot and linux command line parameters
From: Hunter Cobbs @ 2009-05-24 21:41 UTC (permalink / raw)
To: Mirek23; +Cc: linuxppc-dev@ozlabs.org
In-Reply-To: <23698384.post@talk.nabble.com>
Have you considered using a kernel and initrd?
Hunter Cobbs
On May 24, 2009, at 4:38 PM, Mirek23 <miroslaw.dach@psi.ch> wrote:
>
> Dear All,
>
> I use linux kernel 2.6.23 and u-boot 1.2.0 (on ppc405 virtex-4 )
> for some
> time. All works fine when the
> kernel together with initramfs is smaller than 8MB. If it is bigger
> than the
> kernel does not boot properly.
>
> First of all I would like to know how the address for the linux
> command line
> parameters is "transferred" from u-boot to linux for ppc405 (virtex4
> chip)?
> (via some registers or is it a fixed address in the memory ie. 8MB?)
> Does somebody know what should be changed, in the kernel, in order
> to move
> this limitation from 8MB to let say 12MB? I would be grateful for
> any hint.
>
> Thanks in advance.
> M.
> --
> View this message in context: http://www.nabble.com/U-boot-and-linux-command-line-parameters-tp23698384p23698384.html
> Sent from the linuxppc-dev mailing list archive at Nabble.com.
>
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev
^ permalink raw reply
* U-boot and linux command line parameters
From: Mirek23 @ 2009-05-24 21:38 UTC (permalink / raw)
To: linuxppc-dev
Dear All,
I use linux kernel 2.6.23 and u-boot 1.2.0 (on ppc405 virtex-4 ) for some
time. All works fine when the
kernel together with initramfs is smaller than 8MB. If it is bigger than the
kernel does not boot properly.
First of all I would like to know how the address for the linux command line
parameters is "transferred" from u-boot to linux for ppc405 (virtex4 chip)?
(via some registers or is it a fixed address in the memory ie. 8MB?)
Does somebody know what should be changed, in the kernel, in order to move
this limitation from 8MB to let say 12MB? I would be grateful for any hint.
Thanks in advance.
M.
--
View this message in context: http://www.nabble.com/U-boot-and-linux-command-line-parameters-tp23698384p23698384.html
Sent from the linuxppc-dev mailing list archive at Nabble.com.
^ permalink raw reply
* Re: [PATCH V2 5/9] Main rewite of the mpc5200 audio DMA code
From: Wolfram Sang @ 2009-05-24 20:35 UTC (permalink / raw)
To: Jon Smirl; +Cc: linuxppc-dev, alsa-devel, broonie
In-Reply-To: <9e4733910905241310n59952fd2oaafd7f1363db324@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 1149 bytes --]
On Sun, May 24, 2009 at 04:10:52PM -0400, Jon Smirl wrote:
> On Sun, May 24, 2009 at 2:55 PM, Wolfram Sang <w.sang@pengutronix.de> wrote:
> >> Rewrite the mpc5200 audio DMA code to support both I2S and AC97. Make it more robust.
> >
> > Why is it more robust?
>
> I've implemented retries for when the AC97 hardware doesn't reset on
> first try. About 10% of the time both the Efika and pcm030 AC97 codecs
> don't reset on first try and need to be poked multiple times. Failure
> is indicated by not having the link clock start ticking. Every once in
> a while even five pokes won't get the link started and I have to power
> cycle.
>
> I don't have an oscilloscope, after I get these basic drivers in maybe
> someone can put a scope on this and figure out why reset is failing.
> I've read the various datasheets and I believe my reset pulses have
> the correct timings.
That's good to know. In fact, I think a summary of this should go into the
patch description.
--
Pengutronix e.K. | Wolfram Sang |
Industrial Linux Solutions | http://www.pengutronix.de/ |
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 197 bytes --]
^ permalink raw reply
* Re: [PATCH V2 5/9] Main rewite of the mpc5200 audio DMA code
From: Jon Smirl @ 2009-05-24 20:10 UTC (permalink / raw)
To: Wolfram Sang; +Cc: linuxppc-dev, alsa-devel, broonie
In-Reply-To: <20090524185509.GA3561@pengutronix.de>
On Sun, May 24, 2009 at 2:55 PM, Wolfram Sang <w.sang@pengutronix.de> wrote=
:
>> Rewrite the mpc5200 audio DMA code to support both I2S and AC97. Make it=
more robust.
>
> Why is it more robust?
I've implemented retries for when the AC97 hardware doesn't reset on
first try. About 10% of the time both the Efika and pcm030 AC97 codecs
don't reset on first try and need to be poked multiple times. Failure
is indicated by not having the link clock start ticking. Every once in
a while even five pokes won't get the link started and I have to power
cycle.
I don't have an oscilloscope, after I get these basic drivers in maybe
someone can put a scope on this and figure out why reset is failing.
I've read the various datasheets and I believe my reset pulses have
the correct timings.
>
> --
> Pengutronix e.K. =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 | Wo=
lfram Sang =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0|
> Industrial Linux Solutions =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 | http://www.p=
engutronix.de/ =A0|
>
> -----BEGIN PGP SIGNATURE-----
> Version: GnuPG v1.4.9 (GNU/Linux)
>
> iEYEARECAAYFAkoZmA0ACgkQD27XaX1/VRvugwCgsluxfp1rJH2MVFMTH6Yqo8bX
> dnIAn1z0QRIFEUJa0XpGFE937siwf8Cy
> =3DM0wP
> -----END PGP SIGNATURE-----
>
>
--=20
Jon Smirl
jonsmirl@gmail.com
^ permalink raw reply
* Re: [alsa-devel] [PATCH V2 1/9] Register the wm9712 DAIs on module load
From: Mark Brown @ 2009-05-24 19:14 UTC (permalink / raw)
To: Jon Smirl; +Cc: linuxppc-dev, alsa-devel
In-Reply-To: <9e4733910905240828q4b4cfd96xe840f3ae983143dc@mail.gmail.com>
On Sun, May 24, 2009 at 11:28:15AM -0400, Jon Smirl wrote:
> On Sun, May 24, 2009 at 7:11 AM, Mark Brown
> > Why do you wish to do this - ASoC does not require or use DAI registration
> > for AC97 CODECs?
> Then what is wrong with my binding code? If I take out the
> registration my bind fails.
It appears that the problem here is that your CPU DAI isn't marked as an
ac97 DAI by having ac97_control set so the core expects the codec to
instantiate prior to the card. Setting ac97_control ought to fix the
problem, but obviously I can't test.
When looking at problems like this it's worth taking a step back and
looking at why the existing code is the way that it is when considering
if you've found the right fix. In this case AC97 is fairly widely used
and there are also a number of WM9712 users but neither WM9712 or any of
the other AC97 CODEC drivers ever register their DAIs. That should be
an indication that either things probably should work without a change
to existing code or things are completely broken and something wider
than a change in a single driver is required in order to get things
working.
^ permalink raw reply
* Re: [PATCH V2 5/9] Main rewite of the mpc5200 audio DMA code
From: Wolfram Sang @ 2009-05-24 18:55 UTC (permalink / raw)
To: Jon Smirl; +Cc: linuxppc-dev, alsa-devel, broonie
In-Reply-To: <20090523231305.17919.12239.stgit@terra>
[-- Attachment #1: Type: text/plain, Size: 274 bytes --]
> Rewrite the mpc5200 audio DMA code to support both I2S and AC97. Make it more robust.
Why is it more robust?
--
Pengutronix e.K. | Wolfram Sang |
Industrial Linux Solutions | http://www.pengutronix.de/ |
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 197 bytes --]
^ permalink raw reply
* Re: [alsa-devel] [PATCH V2 0/9] mpc5200 audio rework for AC97
From: Mark Brown @ 2009-05-24 18:35 UTC (permalink / raw)
To: Jon Smirl; +Cc: linuxppc-dev, alsa-devel
In-Reply-To: <9e4733910905240821p7313f82bu171e0d4a2f3dbbff@mail.gmail.com>
On Sun, May 24, 2009 at 11:21:15AM -0400, Jon Smirl wrote:
> My AC97 driver is detecting the codec id and printing it before trying
> to access the codec driver. I can convert that to a load_module() call
> when the drivers are ready.
No, your AC97 driver shouldn't be doing any of this at all - it should
be leaving any enumeration of the hardware up to the machine driver and
the core. In so far as it is standardised the process for probing AC97
is something that can be implemented in terms of the operations exported
by the DAI so it should be done in the core for all AC97 DAIs. Where
standardised probing can't work it needs to be machine specific anyway.
^ permalink raw reply
* Re: [alsa-devel] [PATCH V2 4/9] Add a few more mpc5200 PSC defines
From: Mark Brown @ 2009-05-24 18:32 UTC (permalink / raw)
To: Grant Likely; +Cc: linuxppc-dev, alsa-devel
In-Reply-To: <fa686aa40905241119t5e85311cj8a181c11b3890f0b@mail.gmail.com>
On Sun, May 24, 2009 at 12:19:37PM -0600, Grant Likely wrote:
> Nothing else needs it in MPC5200 land and I haven't applied it to my
> tree yet. Go ahead and add it to the ASoC tree.
OK, applied this and the two refactoring patches - thanks!
^ permalink raw reply
* Re: [PATCH V2 4/9] Add a few more mpc5200 PSC defines
From: Grant Likely @ 2009-05-24 18:19 UTC (permalink / raw)
To: Mark Brown; +Cc: linuxppc-dev, alsa-devel
In-Reply-To: <20090524180023.GA4525@sirena.org.uk>
On Sun, May 24, 2009 at 12:00 PM, Mark Brown
<broonie@opensource.wolfsonmicro.com> wrote:
> On Sun, May 24, 2009 at 08:13:19AM -0600, Grant Likely wrote:
>> On Sat, May 23, 2009 at 5:13 PM, Jon Smirl <jonsmirl@gmail.com> wrote:
>> > Add a few more mpc5200 PSC defines. More bit fields defines for mpc5200 PSC registers. This patch is going in via Grant's tree.
>
>> > Signed-off-by: Jon Smirl <jonsmirl@gmail.com>
>
>> Acked-by: Grant Likely <grant.likely@secretlab.ca>
>
> Jon's commit log says this is going in via your tree - is that the case
> or should I apply it to ASoC?
Nothing else needs it in MPC5200 land and I haven't applied it to my
tree yet. Go ahead and add it to the ASoC tree.
g.
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* Re: [PATCH V2 4/9] Add a few more mpc5200 PSC defines
From: Mark Brown @ 2009-05-24 18:00 UTC (permalink / raw)
To: Grant Likely; +Cc: linuxppc-dev, alsa-devel
In-Reply-To: <fa686aa40905240713g2e79367mec0ba185432a94a@mail.gmail.com>
On Sun, May 24, 2009 at 08:13:19AM -0600, Grant Likely wrote:
> On Sat, May 23, 2009 at 5:13 PM, Jon Smirl <jonsmirl@gmail.com> wrote:
> > Add a few more mpc5200 PSC defines. More bit fields defines for mpc5200 PSC registers. This patch is going in via Grant's tree.
> > Signed-off-by: Jon Smirl <jonsmirl@gmail.com>
> Acked-by: Grant Likely <grant.likely@secretlab.ca>
Jon's commit log says this is going in via your tree - is that the case
or should I apply it to ASoC?
^ permalink raw reply
* Re: [alsa-devel] [PATCH V2 1/9] Register the wm9712 DAIs on module load
From: Jon Smirl @ 2009-05-24 15:32 UTC (permalink / raw)
To: Mark Brown; +Cc: linuxppc-dev, alsa-devel
In-Reply-To: <9e4733910905240828q4b4cfd96xe840f3ae983143dc@mail.gmail.com>
Output with SOC DEBUG turned on:
Advanced Linux Sound Architecture Driver Version 1.0.19.
No device for DAI stac9766 analog
Registered DAI 'stac9766 analog'
No device for DAI stac9766 IEC958
Registered DAI 'stac9766 IEC958'
No device for DAI tas5504
Registered DAI 'tas5504'
Registered platform 'mpc5200-psc-audio'
irq: irq 129 on host /soc5200@f0000000/interrupt-controller@500 mapped
to virtual irq 129
irq: irq 194 on host /soc5200@f0000000/interrupt-controller@500 mapped
to virtual irq 194
irq: irq 195 on host /soc5200@f0000000/interrupt-controller@500 mapped
to virtual irq 195
Registered DAI 'AC97'
Registered DAI 'SPDIF'
mpc5200-psc-ac97 f0002000.ac97: Codec ID is 574d 4c12
soc-audio soc-audio.1: DAI AC97 HiFi not registered
soc-audio soc-audio.1: Registered card 'pcm030'
ALSA device list:
No soundcards found.
--
Jon Smirl
jonsmirl@gmail.com
^ permalink raw reply
* Re: [alsa-devel] [PATCH V2 1/9] Register the wm9712 DAIs on module load
From: Jon Smirl @ 2009-05-24 15:28 UTC (permalink / raw)
To: Mark Brown; +Cc: linuxppc-dev, alsa-devel
In-Reply-To: <20090524111118.GC4933@sirena.org.uk>
On Sun, May 24, 2009 at 7:11 AM, Mark Brown
<broonie@opensource.wolfsonmicro.com> wrote:
> On Sat, May 23, 2009 at 07:12:57PM -0400, Jon Smirl wrote:
>> Register the wm9712 DAIs on module load
>
>> Signed-off-by: Jon Smirl <jonsmirl@gmail.com>
>
> Why do you wish to do this - ASoC does not require or use DAI registration
> for AC97 CODECs?
>
Then what is wrong with my binding code? If I take out the
registration my bind fails.
static struct snd_soc_dai_link pcm030_fabric_dai[] = {
{
.name = "AC97",
.stream_name = "AC97 Analog",
.codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI],
.cpu_dai = &psc_ac97_dai[MPC5200_AC97_NORMAL],
},
{
.name = "AC97",
.stream_name = "AC97 IEC958",
.codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX],
.cpu_dai = &psc_ac97_dai[MPC5200_AC97_SPDIF],
},
};
static __init int pcm030_fabric_init(void)
{
struct platform_device *pdev;
int rc;
if (!machine_is_compatible("phytec,pcm030"))
return -ENODEV;
card.platform = &mpc5200_audio_dma_platform;
card.name = "pcm030";
card.dai_link = pcm030_fabric_dai;
card.num_links = ARRAY_SIZE(pcm030_fabric_dai);
device.card = &card;
device.codec_dev = &soc_codec_dev_wm9712;
pdev = platform_device_alloc("soc-audio", 1);
if (!pdev) {
pr_err("pcm030_fabric_init: platform_device_alloc() failed\n");
return -ENODEV;
}
platform_set_drvdata(pdev, &device);
device.dev = &pdev->dev;
rc = platform_device_add(pdev);
if (rc) {
pr_err("pcm030_fabric_init: platform_device_add() failed\n");
return -ENODEV;
}
return 0;
}
Advanced Linux Sound Architecture Driver Version 1.0.19.
No device for DAI stac9766 analog
No device for DAI stac9766 IEC958
No device for DAI tas5504
irq: irq 129 on host /soc5200@f0000000/interrupt-controller@500 mapped
to virtual irq 129
irq: irq 194 on host /soc5200@f0000000/interrupt-controller@500 mapped
to virtual irq 194
irq: irq 195 on host /soc5200@f0000000/interrupt-controller@500 mapped
to virtual irq 195
mpc5200-psc-ac97 f0002000.ac97: Codec ID is 574d 4c12
ALSA device list:
No soundcards found.
--
Jon Smirl
jonsmirl@gmail.com
^ permalink raw reply
* Re: [alsa-devel] [PATCH V2 0/9] mpc5200 audio rework for AC97
From: Jon Smirl @ 2009-05-24 15:21 UTC (permalink / raw)
To: Mark Brown; +Cc: linuxppc-dev, alsa-devel
In-Reply-To: <20090524110854.GB4933@sirena.org.uk>
On Sun, May 24, 2009 at 7:08 AM, Mark Brown
<broonie@opensource.wolfsonmicro.com> wrote:
> I'm not aware of any CODEC drivers which can't currently be built and
> used as modules. =A0If you mean "load via the normal device model" then
> yes, that'd be very good (and is in progress) but it's another issue and
> as I explained last time AC97 poses particular problems there.
>
I mean "load via the normal device model". For example the AC97
drivers need to be loadable by the codec id. There's no entry in
scripts/mod/file2alias.c for dynamically loading the modules. They
don't have an id_table.
My AC97 driver is detecting the codec id and printing it before trying
to access the codec driver. I can convert that to a load_module() call
when the drivers are ready.
The core needs to detect if a specific codec id can't be supported to
fall back to the generic AC97 driver.
--=20
Jon Smirl
jonsmirl@gmail.com
^ permalink raw reply
* Re: [PATCH V2 4/9] Add a few more mpc5200 PSC defines
From: Grant Likely @ 2009-05-24 14:13 UTC (permalink / raw)
To: Jon Smirl; +Cc: linuxppc-dev, alsa-devel, broonie
In-Reply-To: <20090523231303.17919.35877.stgit@terra>
On Sat, May 23, 2009 at 5:13 PM, Jon Smirl <jonsmirl@gmail.com> wrote:
> Add a few more mpc5200 PSC defines. More bit fields defines for mpc5200 P=
SC registers. This patch is going in via Grant's tree.
>
> Signed-off-by: Jon Smirl <jonsmirl@gmail.com>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
> ---
> =A00 files changed, 0 insertions(+), 0 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/mpc52xx_psc.h b/arch/powerpc/includ=
e/asm/mpc52xx_psc.h
> index a218da6..fb84120 100644
> --- a/arch/powerpc/include/asm/mpc52xx_psc.h
> +++ b/arch/powerpc/include/asm/mpc52xx_psc.h
> @@ -28,6 +28,10 @@
> =A0#define MPC52xx_PSC_MAXNUM =A0 =A0 6
>
> =A0/* Programmable Serial Controller (PSC) status register bits */
> +#define MPC52xx_PSC_SR_UNEX_RX 0x0001
> +#define MPC52xx_PSC_SR_DATA_VAL =A0 =A0 =A0 =A00x0002
> +#define MPC52xx_PSC_SR_DATA_OVR =A0 =A0 =A0 =A00x0004
> +#define MPC52xx_PSC_SR_CMDSEND 0x0008
> =A0#define MPC52xx_PSC_SR_CDE =A0 =A0 0x0080
> =A0#define MPC52xx_PSC_SR_RXRDY =A0 0x0100
> =A0#define MPC52xx_PSC_SR_RXFULL =A00x0200
> @@ -61,6 +65,12 @@
> =A0#define MPC52xx_PSC_RXTX_FIFO_EMPTY =A0 =A00x0001
>
> =A0/* PSC interrupt status/mask bits */
> +#define MPC52xx_PSC_IMR_UNEX_RX_SLOT 0x0001
> +#define MPC52xx_PSC_IMR_DATA_VALID =A0 =A0 0x0002
> +#define MPC52xx_PSC_IMR_DATA_OVR =A0 =A0 =A0 0x0004
> +#define MPC52xx_PSC_IMR_CMD_SEND =A0 =A0 =A0 0x0008
> +#define MPC52xx_PSC_IMR_ERROR =A0 =A0 =A0 =A0 =A00x0040
> +#define MPC52xx_PSC_IMR_DEOF =A0 =A0 =A0 =A0 =A0 0x0080
> =A0#define MPC52xx_PSC_IMR_TXRDY =A0 =A0 =A0 =A0 =A00x0100
> =A0#define MPC52xx_PSC_IMR_RXRDY =A0 =A0 =A0 =A0 =A00x0200
> =A0#define MPC52xx_PSC_IMR_DB =A0 =A0 =A0 =A0 =A0 =A0 0x0400
> @@ -117,6 +127,7 @@
> =A0#define MPC52xx_PSC_SICR_SIM_FIR =A0 =A0 =A0 =A0 =A0 =A0 =A0 (0x6 << 2=
4)
> =A0#define MPC52xx_PSC_SICR_SIM_CODEC_24 =A0 =A0 =A0 =A0 =A0(0x7 << 24)
> =A0#define MPC52xx_PSC_SICR_SIM_CODEC_32 =A0 =A0 =A0 =A0 =A0(0xf << 24)
> +#define MPC52xx_PSC_SICR_AWR =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (1 << 3=
0)
> =A0#define MPC52xx_PSC_SICR_GENCLK =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0(1 << 23)
> =A0#define MPC52xx_PSC_SICR_I2S =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (1 <<=
22)
> =A0#define MPC52xx_PSC_SICR_CLKPOL =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0(1 << 21)
>
>
--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* Re: [alsa-devel] [PATCH V2 3/9] Rename the PSC functions to DMA
From: Grant Likely @ 2009-05-24 14:12 UTC (permalink / raw)
To: Mark Brown; +Cc: linuxppc-dev, alsa-devel
In-Reply-To: <20090524111512.GD4933@sirena.org.uk>
On Sun, May 24, 2009 at 5:15 AM, Mark Brown
<broonie@opensource.wolfsonmicro.com> wrote:
> On Sat, May 23, 2009 at 07:13:01PM -0400, Jon Smirl wrote:
>> Rename the functions in the mpc5200 DMA file from i2s based names to dma ones to reflect the file they are in.
>
> I'm OK with both these refactoring patches if Grant is - Grant, if I
> could get your ack I'd like to merge these as soon as possible since
> they're very big changes and it'd cut down on review effort.
Acked-by: Grant Likely <grant.likely@secretlab.ca>
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* Re: [PATCH V2 2/9] Basic split of mpc5200 DMA code out from mpc5200_psc_i2s
From: Grant Likely @ 2009-05-24 14:11 UTC (permalink / raw)
To: Jon Smirl; +Cc: linuxppc-dev, alsa-devel, broonie
In-Reply-To: <20090523231259.17919.84248.stgit@terra>
On Sat, May 23, 2009 at 5:12 PM, Jon Smirl <jonsmirl@gmail.com> wrote:
> Basic split of mpc5200 DMA code out from i2s into a standalone file.
>
> Signed-off-by: Jon Smirl <jonsmirl@gmail.com>
I haven't looked in detail, but I'm okay with this in principle.
Acked-by: Grant Likely <grant.likely@secretlab.ca>
g.
> ---
> =A0sound/soc/fsl/Kconfig =A0 =A0 =A0 =A0 =A0 | =A0 =A04
> =A0sound/soc/fsl/Makefile =A0 =A0 =A0 =A0 =A0| =A0 =A02
> =A0sound/soc/fsl/mpc5200_dma.c =A0 =A0 | =A0458 +++++++++++++++++++++++++=
++++++++++++
> =A0sound/soc/fsl/mpc5200_dma.h =A0 =A0 | =A0 81 +++++++
> =A0sound/soc/fsl/mpc5200_psc_i2s.c | =A0485 -----------------------------=
----------
> =A05 files changed, 547 insertions(+), 483 deletions(-)
> =A0create mode 100644 sound/soc/fsl/mpc5200_dma.c
> =A0create mode 100644 sound/soc/fsl/mpc5200_dma.h
>
> diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
> index 9fc9082..dc79bdf 100644
> --- a/sound/soc/fsl/Kconfig
> +++ b/sound/soc/fsl/Kconfig
> @@ -1,5 +1,8 @@
> =A0config SND_SOC_OF_SIMPLE
> =A0 =A0 =A0 =A0tristate
> +
> +config SND_MPC52xx_DMA
> + =A0 =A0 =A0 tristate
>
> =A0# ASoC platform support for the Freescale MPC8610 SOC. =A0This compile=
s drivers
> =A0# for the SSI and the Elo DMA controller. =A0You will still need to se=
lect
> @@ -23,6 +26,7 @@ config SND_SOC_MPC5200_I2S
> =A0 =A0 =A0 =A0tristate "Freescale MPC5200 PSC in I2S mode driver"
> =A0 =A0 =A0 =A0depends on PPC_MPC52xx && PPC_BESTCOMM
> =A0 =A0 =A0 =A0select SND_SOC_OF_SIMPLE
> + =A0 =A0 =A0 select SND_MPC52xx_DMA
> =A0 =A0 =A0 =A0select PPC_BESTCOMM_GEN_BD
> =A0 =A0 =A0 =A0help
> =A0 =A0 =A0 =A0 =A0Say Y here to support the MPC5200 PSCs in I2S mode.
> diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
> index f85134c..7731ef2 100644
> --- a/sound/soc/fsl/Makefile
> +++ b/sound/soc/fsl/Makefile
> @@ -10,5 +10,7 @@ snd-soc-fsl-ssi-objs :=3D fsl_ssi.o
> =A0snd-soc-fsl-dma-objs :=3D fsl_dma.o
> =A0obj-$(CONFIG_SND_SOC_MPC8610) +=3D snd-soc-fsl-ssi.o snd-soc-fsl-dma.o
>
> +# MPC5200 Platform Support
> +obj-$(CONFIG_SND_MPC52xx_DMA) +=3D mpc5200_dma.o
> =A0obj-$(CONFIG_SND_SOC_MPC5200_I2S) +=3D mpc5200_psc_i2s.o
>
> diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c
> new file mode 100644
> index 0000000..4bae8d6
> --- /dev/null
> +++ b/sound/soc/fsl/mpc5200_dma.c
> @@ -0,0 +1,458 @@
> +/*
> + * Freescale MPC5200 PSC DMA
> + * ALSA SoC Platform driver
> + *
> + * Copyright (C) 2008 Secret Lab Technologies Ltd.
> + */
> +
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/interrupt.h>
> +#include <linux/device.h>
> +#include <linux/delay.h>
> +#include <linux/of_device.h>
> +#include <linux/of_platform.h>
> +#include <linux/dma-mapping.h>
> +
> +#include <sound/core.h>
> +#include <sound/pcm.h>
> +#include <sound/pcm_params.h>
> +#include <sound/initval.h>
> +#include <sound/soc.h>
> +#include <sound/soc-of-simple.h>
> +
> +#include <sysdev/bestcomm/bestcomm.h>
> +#include <sysdev/bestcomm/gen_bd.h>
> +#include <asm/mpc52xx_psc.h>
> +
> +#include "mpc5200_dma.h"
> +
> +MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
> +MODULE_DESCRIPTION("Freescale MPC5200 PSC in DMA mode ASoC Driver");
> +MODULE_LICENSE("GPL");
> +
> +/*
> + * Interrupt handlers
> + */
> +static irqreturn_t psc_i2s_status_irq(int irq, void *_psc_i2s)
> +{
> + =A0 =A0 =A0 struct psc_i2s *psc_i2s =3D _psc_i2s;
> + =A0 =A0 =A0 struct mpc52xx_psc __iomem *regs =3D psc_i2s->psc_regs;
> + =A0 =A0 =A0 u16 isr;
> +
> + =A0 =A0 =A0 isr =3D in_be16(®s->mpc52xx_psc_isr);
> +
> + =A0 =A0 =A0 /* Playback underrun error */
> + =A0 =A0 =A0 if (psc_i2s->playback.active && (isr & MPC52xx_PSC_IMR_TXEM=
P))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 psc_i2s->stats.underrun_count++;
> +
> + =A0 =A0 =A0 /* Capture overrun error */
> + =A0 =A0 =A0 if (psc_i2s->capture.active && (isr & MPC52xx_PSC_IMR_ORERR=
))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 psc_i2s->stats.overrun_count++;
> +
> + =A0 =A0 =A0 out_8(®s->command, 4 << 4); =A0/* reset the error status=
*/
> +
> + =A0 =A0 =A0 return IRQ_HANDLED;
> +}
> +
> +/**
> + * psc_i2s_bcom_enqueue_next_buffer - Enqueue another audio buffer
> + * @s: pointer to stream private data structure
> + *
> + * Enqueues another audio period buffer into the bestcomm queue.
> + *
> + * Note: The routine must only be called when there is space available i=
n
> + * the queue. =A0Otherwise the enqueue will fail and the audio ring buff=
er
> + * will get out of sync
> + */
> +static void psc_i2s_bcom_enqueue_next_buffer(struct psc_i2s_stream *s)
> +{
> + =A0 =A0 =A0 struct bcom_bd *bd;
> +
> + =A0 =A0 =A0 /* Prepare and enqueue the next buffer descriptor */
> + =A0 =A0 =A0 bd =3D bcom_prepare_next_buffer(s->bcom_task);
> + =A0 =A0 =A0 bd->status =3D s->period_bytes;
> + =A0 =A0 =A0 bd->data[0] =3D s->period_next_pt;
> + =A0 =A0 =A0 bcom_submit_next_buffer(s->bcom_task, NULL);
> +
> + =A0 =A0 =A0 /* Update for next period */
> + =A0 =A0 =A0 s->period_next_pt +=3D s->period_bytes;
> + =A0 =A0 =A0 if (s->period_next_pt >=3D s->period_end)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 s->period_next_pt =3D s->period_start;
> +}
> +
> +/* Bestcomm DMA irq handler */
> +static irqreturn_t psc_i2s_bcom_irq(int irq, void *_psc_i2s_stream)
> +{
> + =A0 =A0 =A0 struct psc_i2s_stream *s =3D _psc_i2s_stream;
> +
> + =A0 =A0 =A0 /* For each finished period, dequeue the completed period b=
uffer
> + =A0 =A0 =A0 =A0* and enqueue a new one in it's place. */
> + =A0 =A0 =A0 while (bcom_buffer_done(s->bcom_task)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 bcom_retrieve_buffer(s->bcom_task, NULL, NU=
LL);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 s->period_current_pt +=3D s->period_bytes;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (s->period_current_pt >=3D s->period_end=
)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 s->period_current_pt =3D s-=
>period_start;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 psc_i2s_bcom_enqueue_next_buffer(s);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 bcom_enable(s->bcom_task);
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 /* If the stream is active, then also inform the PCM middle=
layer
> + =A0 =A0 =A0 =A0* of the period finished event. */
> + =A0 =A0 =A0 if (s->active)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 snd_pcm_period_elapsed(s->stream);
> +
> + =A0 =A0 =A0 return IRQ_HANDLED;
> +}
> +
> +/**
> + * psc_i2s_startup: create a new substream
> + *
> + * This is the first function called when a stream is opened.
> + *
> + * If this is the first stream open, then grab the IRQ and program most =
of
> + * the PSC registers.
> + */
> +int psc_i2s_startup(struct snd_pcm_substream *substream,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct snd_soc_dai *=
dai)
> +{
> + =A0 =A0 =A0 struct snd_soc_pcm_runtime *rtd =3D substream->private_data=
;
> + =A0 =A0 =A0 struct psc_i2s *psc_i2s =3D rtd->dai->cpu_dai->private_data=
;
> + =A0 =A0 =A0 int rc;
> +
> + =A0 =A0 =A0 dev_dbg(psc_i2s->dev, "psc_i2s_startup(substream=3D%p)\n", =
substream);
> +
> + =A0 =A0 =A0 if (!psc_i2s->playback.active &&
> + =A0 =A0 =A0 =A0 =A0 !psc_i2s->capture.active) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Setup the IRQs */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 rc =3D request_irq(psc_i2s->irq, &psc_i2s_s=
tatus_irq, IRQF_SHARED,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"psc-i2s=
-status", psc_i2s);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 rc |=3D request_irq(psc_i2s->capture.irq,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 &psc_i2=
s_bcom_irq, IRQF_SHARED,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "psc-i2=
s-capture", &psc_i2s->capture);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 rc |=3D request_irq(psc_i2s->playback.irq,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 &psc_i2=
s_bcom_irq, IRQF_SHARED,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "psc-i2=
s-playback", &psc_i2s->playback);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (rc) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 free_irq(psc_i2s->irq, psc_=
i2s);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 free_irq(psc_i2s->capture.i=
rq,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0&psc_i2s=
->capture);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 free_irq(psc_i2s->playback.=
irq,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0&psc_i2s=
->playback);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENODEV;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 return 0;
> +}
> +
> +int psc_i2s_hw_free(struct snd_pcm_substream *substream,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct snd_soc_dai *=
dai)
> +{
> + =A0 =A0 =A0 snd_pcm_set_runtime_buffer(substream, NULL);
> + =A0 =A0 =A0 return 0;
> +}
> +
> +/**
> + * psc_i2s_trigger: start and stop the DMA transfer.
> + *
> + * This function is called by ALSA to start, stop, pause, and resume the=
DMA
> + * transfer of data.
> + */
> +int psc_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct snd_soc_dai *=
dai)
> +{
> + =A0 =A0 =A0 struct snd_soc_pcm_runtime *rtd =3D substream->private_data=
;
> + =A0 =A0 =A0 struct psc_i2s *psc_i2s =3D rtd->dai->cpu_dai->private_data=
;
> + =A0 =A0 =A0 struct snd_pcm_runtime *runtime =3D substream->runtime;
> + =A0 =A0 =A0 struct psc_i2s_stream *s;
> + =A0 =A0 =A0 struct mpc52xx_psc __iomem *regs =3D psc_i2s->psc_regs;
> + =A0 =A0 =A0 u16 imr;
> + =A0 =A0 =A0 u8 psc_cmd;
> + =A0 =A0 =A0 unsigned long flags;
> +
> + =A0 =A0 =A0 if (substream->pstr->stream =3D=3D SNDRV_PCM_STREAM_CAPTURE=
)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 s =3D &psc_i2s->capture;
> + =A0 =A0 =A0 else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 s =3D &psc_i2s->playback;
> +
> + =A0 =A0 =A0 dev_dbg(psc_i2s->dev, "psc_i2s_trigger(substream=3D%p, cmd=
=3D%i)"
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 " stream_id=3D%i\n",
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 substream, cmd, substream->pstr->stream);
> +
> + =A0 =A0 =A0 switch (cmd) {
> + =A0 =A0 =A0 case SNDRV_PCM_TRIGGER_START:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 s->period_bytes =3D frames_to_bytes(runtime=
,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
=A0 =A0 =A0 =A0 =A0 =A0 runtime->period_size);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 s->period_start =3D virt_to_phys(runtime->d=
ma_area);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 s->period_end =3D s->period_start +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (s->period_=
bytes * runtime->periods);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 s->period_next_pt =3D s->period_start;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 s->period_current_pt =3D s->period_start;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 s->active =3D 1;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* First; reset everything */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (substream->pstr->stream =3D=3D SNDRV_PC=
M_STREAM_CAPTURE) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(®s->command, MPC52=
xx_PSC_RST_RX);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(®s->command, MPC52=
xx_PSC_RST_ERR_STAT);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 } else {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(®s->command, MPC52=
xx_PSC_RST_TX);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(®s->command, MPC52=
xx_PSC_RST_ERR_STAT);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Next, fill up the bestcomm bd queue and =
enable DMA.
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* This will begin filling the PSC's fifo=
. */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (substream->pstr->stream =3D=3D SNDRV_PC=
M_STREAM_CAPTURE)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 bcom_gen_bd_rx_reset(s->bco=
m_task);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 bcom_gen_bd_tx_reset(s->bco=
m_task);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 while (!bcom_queue_full(s->bcom_task))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 psc_i2s_bcom_enqueue_next_b=
uffer(s);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 bcom_enable(s->bcom_task);
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Due to errata in the i2s mode; need to l=
ine up enabling
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* the transmitter with a transition on t=
he frame sync
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* line */
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 spin_lock_irqsave(&psc_i2s->lock, flags);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* first make sure it is low */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 while ((in_8(®s->ipcr_acr.ipcr) & 0x80) =
!=3D 0)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* then wait for the transition to high */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 while ((in_8(®s->ipcr_acr.ipcr) & 0x80) =
=3D=3D 0)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Finally, enable the PSC.
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* Receiver must always be enabled; even =
when we only want
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* transmit. =A0(see 15.3.2.3 of MPC5200B=
User's Guide) */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 psc_cmd =3D MPC52xx_PSC_RX_ENABLE;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (substream->pstr->stream =3D=3D SNDRV_PC=
M_STREAM_PLAYBACK)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 psc_cmd |=3D MPC52xx_PSC_TX=
_ENABLE;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(®s->command, psc_cmd);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 spin_unlock_irqrestore(&psc_i2s->lock, flag=
s);
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> +
> + =A0 =A0 =A0 case SNDRV_PCM_TRIGGER_STOP:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Turn off the PSC */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 s->active =3D 0;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (substream->pstr->stream =3D=3D SNDRV_PC=
M_STREAM_CAPTURE) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!psc_i2s->playback.acti=
ve) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(®s=
->command, 2 << 4); =A0/* reset rx */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(®s=
->command, 3 << 4); =A0/* reset tx */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(®s=
->command, 4 << 4); =A0/* reset err */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 } else {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(®s->command, 3 << =
4); =A0/* reset tx */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(®s->command, 4 << =
4); =A0/* reset err */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!psc_i2s->capture.activ=
e)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(®s=
->command, 2 << 4); =A0/* reset rx */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 bcom_disable(s->bcom_task);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 while (!bcom_queue_empty(s->bcom_task))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 bcom_retrieve_buffer(s->bco=
m_task, NULL, NULL);
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> +
> + =A0 =A0 =A0 default:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_dbg(psc_i2s->dev, "invalid command\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -EINVAL;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 /* Update interrupt enable settings */
> + =A0 =A0 =A0 imr =3D 0;
> + =A0 =A0 =A0 if (psc_i2s->playback.active)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 imr |=3D MPC52xx_PSC_IMR_TXEMP;
> + =A0 =A0 =A0 if (psc_i2s->capture.active)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 imr |=3D MPC52xx_PSC_IMR_ORERR;
> + =A0 =A0 =A0 out_be16(®s->isr_imr.imr, imr);
> +
> + =A0 =A0 =A0 return 0;
> +}
> +
> +/**
> + * psc_i2s_shutdown: shutdown the data transfer on a stream
> + *
> + * Shutdown the PSC if there are no other substreams open.
> + */
> +void psc_i2s_shutdown(struct snd_pcm_substream *substream,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct snd_soc_d=
ai *dai)
> +{
> + =A0 =A0 =A0 struct snd_soc_pcm_runtime *rtd =3D substream->private_data=
;
> + =A0 =A0 =A0 struct psc_i2s *psc_i2s =3D rtd->dai->cpu_dai->private_data=
;
> +
> + =A0 =A0 =A0 dev_dbg(psc_i2s->dev, "psc_i2s_shutdown(substream=3D%p)\n",=
substream);
> +
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* If this is the last active substream, disable the PSC =
and release
> + =A0 =A0 =A0 =A0* the IRQ.
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 if (!psc_i2s->playback.active &&
> + =A0 =A0 =A0 =A0 =A0 !psc_i2s->capture.active) {
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Disable all interrupts and reset the PSC=
*/
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_be16(&psc_i2s->psc_regs->isr_imr.imr, 0=
);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(&psc_i2s->psc_regs->command, 3 << 4);=
/* reset tx */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(&psc_i2s->psc_regs->command, 2 << 4);=
/* reset rx */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(&psc_i2s->psc_regs->command, 1 << 4);=
/* reset mode */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(&psc_i2s->psc_regs->command, 4 << 4);=
/* reset error */
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Release irqs */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 free_irq(psc_i2s->irq, psc_i2s);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 free_irq(psc_i2s->capture.irq, &psc_i2s->ca=
pture);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 free_irq(psc_i2s->playback.irq, &psc_i2s->p=
layback);
> + =A0 =A0 =A0 }
> +}
> +
> +/* ---------------------------------------------------------------------
> + * The PSC DMA 'ASoC platform' driver
> + *
> + * Can be referenced by an 'ASoC machine' driver
> + * This driver only deals with the audio bus; it doesn't have any
> + * interaction with the attached codec
> + */
> +
> +static const struct snd_pcm_hardware psc_i2s_pcm_hardware =3D {
> + =A0 =A0 =A0 .info =3D SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO=
_BLOCK_TRANSFER |
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 SNDRV_PCM_INFO_BATCH,
> + =A0 =A0 =A0 .formats =3D SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE =
|
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_=
FMTBIT_S32_BE,
> + =A0 =A0 =A0 .rate_min =3D 8000,
> + =A0 =A0 =A0 .rate_max =3D 48000,
> + =A0 =A0 =A0 .channels_min =3D 2,
> + =A0 =A0 =A0 .channels_max =3D 2,
> + =A0 =A0 =A0 .period_bytes_max =A0 =A0 =A0 =3D 1024 * 1024,
> + =A0 =A0 =A0 .period_bytes_min =A0 =A0 =A0 =3D 32,
> + =A0 =A0 =A0 .periods_min =A0 =A0 =A0 =A0 =A0 =A0=3D 2,
> + =A0 =A0 =A0 .periods_max =A0 =A0 =A0 =A0 =A0 =A0=3D 256,
> + =A0 =A0 =A0 .buffer_bytes_max =A0 =A0 =A0 =3D 2 * 1024 * 1024,
> + =A0 =A0 =A0 .fifo_size =A0 =A0 =A0 =A0 =A0 =A0 =A0=3D 0,
> +};
> +
> +static int psc_i2s_pcm_open(struct snd_pcm_substream *substream)
> +{
> + =A0 =A0 =A0 struct snd_soc_pcm_runtime *rtd =3D substream->private_data=
;
> + =A0 =A0 =A0 struct psc_i2s *psc_i2s =3D rtd->dai->cpu_dai->private_data=
;
> + =A0 =A0 =A0 struct psc_i2s_stream *s;
> +
> + =A0 =A0 =A0 dev_dbg(psc_i2s->dev, "psc_i2s_pcm_open(substream=3D%p)\n",=
substream);
> +
> + =A0 =A0 =A0 if (substream->pstr->stream =3D=3D SNDRV_PCM_STREAM_CAPTURE=
)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 s =3D &psc_i2s->capture;
> + =A0 =A0 =A0 else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 s =3D &psc_i2s->playback;
> +
> + =A0 =A0 =A0 snd_soc_set_runtime_hwparams(substream, &psc_i2s_pcm_hardwa=
re);
> +
> + =A0 =A0 =A0 s->stream =3D substream;
> + =A0 =A0 =A0 return 0;
> +}
> +
> +static int psc_i2s_pcm_close(struct snd_pcm_substream *substream)
> +{
> + =A0 =A0 =A0 struct snd_soc_pcm_runtime *rtd =3D substream->private_data=
;
> + =A0 =A0 =A0 struct psc_i2s *psc_i2s =3D rtd->dai->cpu_dai->private_data=
;
> + =A0 =A0 =A0 struct psc_i2s_stream *s;
> +
> + =A0 =A0 =A0 dev_dbg(psc_i2s->dev, "psc_i2s_pcm_close(substream=3D%p)\n"=
, substream);
> +
> + =A0 =A0 =A0 if (substream->pstr->stream =3D=3D SNDRV_PCM_STREAM_CAPTURE=
)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 s =3D &psc_i2s->capture;
> + =A0 =A0 =A0 else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 s =3D &psc_i2s->playback;
> +
> + =A0 =A0 =A0 s->stream =3D NULL;
> + =A0 =A0 =A0 return 0;
> +}
> +
> +static snd_pcm_uframes_t
> +psc_i2s_pcm_pointer(struct snd_pcm_substream *substream)
> +{
> + =A0 =A0 =A0 struct snd_soc_pcm_runtime *rtd =3D substream->private_data=
;
> + =A0 =A0 =A0 struct psc_i2s *psc_i2s =3D rtd->dai->cpu_dai->private_data=
;
> + =A0 =A0 =A0 struct psc_i2s_stream *s;
> + =A0 =A0 =A0 dma_addr_t count;
> +
> + =A0 =A0 =A0 if (substream->pstr->stream =3D=3D SNDRV_PCM_STREAM_CAPTURE=
)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 s =3D &psc_i2s->capture;
> + =A0 =A0 =A0 else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 s =3D &psc_i2s->playback;
> +
> + =A0 =A0 =A0 count =3D s->period_current_pt - s->period_start;
> +
> + =A0 =A0 =A0 return bytes_to_frames(substream->runtime, count);
> +}
> +
> +static struct snd_pcm_ops psc_i2s_pcm_ops =3D {
> + =A0 =A0 =A0 .open =A0 =A0 =A0 =A0 =A0 =3D psc_i2s_pcm_open,
> + =A0 =A0 =A0 .close =A0 =A0 =A0 =A0 =A0=3D psc_i2s_pcm_close,
> + =A0 =A0 =A0 .ioctl =A0 =A0 =A0 =A0 =A0=3D snd_pcm_lib_ioctl,
> + =A0 =A0 =A0 .pointer =A0 =A0 =A0 =A0=3D psc_i2s_pcm_pointer,
> +};
> +
> +static u64 psc_i2s_pcm_dmamask =3D 0xffffffff;
> +static int psc_i2s_pcm_new(struct snd_card *card, struct snd_soc_dai *da=
i,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct snd_pcm *pcm)
> +{
> + =A0 =A0 =A0 struct snd_soc_pcm_runtime *rtd =3D pcm->private_data;
> + =A0 =A0 =A0 size_t size =3D psc_i2s_pcm_hardware.buffer_bytes_max;
> + =A0 =A0 =A0 int rc =3D 0;
> +
> + =A0 =A0 =A0 dev_dbg(rtd->socdev->dev, "psc_i2s_pcm_new(card=3D%p, dai=
=3D%p, pcm=3D%p)\n",
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 card, dai, pcm);
> +
> + =A0 =A0 =A0 if (!card->dev->dma_mask)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 card->dev->dma_mask =3D &psc_i2s_pcm_dmamas=
k;
> + =A0 =A0 =A0 if (!card->dev->coherent_dma_mask)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 card->dev->coherent_dma_mask =3D 0xffffffff=
;
> +
> + =A0 =A0 =A0 if (pcm->streams[0].substream) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 rc =3D snd_dma_alloc_pages(SNDRV_DMA_TYPE_D=
EV, pcm->dev, size,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
=A0 &pcm->streams[0].substream->dma_buffer);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (rc)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto playback_alloc_err;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 if (pcm->streams[1].substream) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 rc =3D snd_dma_alloc_pages(SNDRV_DMA_TYPE_D=
EV, pcm->dev, size,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
=A0 &pcm->streams[1].substream->dma_buffer);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (rc)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto capture_alloc_err;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 return 0;
> +
> + capture_alloc_err:
> + =A0 =A0 =A0 if (pcm->streams[0].substream)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 snd_dma_free_pages(&pcm->streams[0].substre=
am->dma_buffer);
> + playback_alloc_err:
> + =A0 =A0 =A0 dev_err(card->dev, "Cannot allocate buffer(s)\n");
> + =A0 =A0 =A0 return -ENOMEM;
> +}
> +
> +static void psc_i2s_pcm_free(struct snd_pcm *pcm)
> +{
> + =A0 =A0 =A0 struct snd_soc_pcm_runtime *rtd =3D pcm->private_data;
> + =A0 =A0 =A0 struct snd_pcm_substream *substream;
> + =A0 =A0 =A0 int stream;
> +
> + =A0 =A0 =A0 dev_dbg(rtd->socdev->dev, "psc_i2s_pcm_free(pcm=3D%p)\n", p=
cm);
> +
> + =A0 =A0 =A0 for (stream =3D 0; stream < 2; stream++) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 substream =3D pcm->streams[stream].substrea=
m;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (substream) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 snd_dma_free_pages(&substre=
am->dma_buffer);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 substream->dma_buffer.area =
=3D NULL;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 substream->dma_buffer.addr =
=3D 0;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 }
> +}
> +
> +struct snd_soc_platform psc_i2s_pcm_soc_platform =3D {
> + =A0 =A0 =A0 .name =A0 =A0 =A0 =A0 =A0 =3D "mpc5200-psc-audio",
> + =A0 =A0 =A0 .pcm_ops =A0 =A0 =A0 =A0=3D &psc_i2s_pcm_ops,
> + =A0 =A0 =A0 .pcm_new =A0 =A0 =A0 =A0=3D &psc_i2s_pcm_new,
> + =A0 =A0 =A0 .pcm_free =A0 =A0 =A0 =3D &psc_i2s_pcm_free,
> +};
> +
> diff --git a/sound/soc/fsl/mpc5200_dma.h b/sound/soc/fsl/mpc5200_dma.h
> new file mode 100644
> index 0000000..9a19e8a
> --- /dev/null
> +++ b/sound/soc/fsl/mpc5200_dma.h
> @@ -0,0 +1,81 @@
> +/*
> + * Freescale MPC5200 Audio DMA driver
> + */
> +
> +#ifndef __SOUND_SOC_FSL_MPC5200_DMA_H__
> +#define __SOUND_SOC_FSL_MPC5200_DMA_H__
> +
> +/**
> + * psc_i2s_stream - Data specific to a single stream (playback or captur=
e)
> + * @active: =A0 =A0 =A0 =A0 =A0 =A0flag indicating if the stream is acti=
ve
> + * @psc_i2s: =A0 =A0 =A0 =A0 =A0 pointer back to parent psc_i2s data str=
ucture
> + * @bcom_task: =A0 =A0 =A0 =A0 bestcomm task structure
> + * @irq: =A0 =A0 =A0 =A0 =A0 =A0 =A0 irq number for bestcomm task
> + * @period_start: =A0 =A0 =A0physical address of start of DMA region
> + * @period_end: =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0physical address of end o=
f DMA region
> + * @period_next_pt: =A0 =A0physical address of next DMA buffer to enqueu=
e
> + * @period_bytes: =A0 =A0 =A0size of DMA period in bytes
> + */
> +struct psc_i2s_stream {
> + =A0 =A0 =A0 int active;
> + =A0 =A0 =A0 struct psc_i2s *psc_i2s;
> + =A0 =A0 =A0 struct bcom_task *bcom_task;
> + =A0 =A0 =A0 int irq;
> + =A0 =A0 =A0 struct snd_pcm_substream *stream;
> + =A0 =A0 =A0 dma_addr_t period_start;
> + =A0 =A0 =A0 dma_addr_t period_end;
> + =A0 =A0 =A0 dma_addr_t period_next_pt;
> + =A0 =A0 =A0 dma_addr_t period_current_pt;
> + =A0 =A0 =A0 int period_bytes;
> +};
> +
> +/**
> + * psc_i2s - Private driver data
> + * @name: short name for this device ("PSC0", "PSC1", etc)
> + * @psc_regs: pointer to the PSC's registers
> + * @fifo_regs: pointer to the PSC's FIFO registers
> + * @irq: IRQ of this PSC
> + * @dev: struct device pointer
> + * @dai: the CPU DAI for this device
> + * @sicr: Base value used in serial interface control register; mode is =
ORed
> + * =A0 =A0 =A0 =A0with this value.
> + * @playback: Playback stream context data
> + * @capture: Capture stream context data
> + */
> +struct psc_i2s {
> + =A0 =A0 =A0 char name[32];
> + =A0 =A0 =A0 struct mpc52xx_psc __iomem *psc_regs;
> + =A0 =A0 =A0 struct mpc52xx_psc_fifo __iomem *fifo_regs;
> + =A0 =A0 =A0 unsigned int irq;
> + =A0 =A0 =A0 struct device *dev;
> + =A0 =A0 =A0 struct snd_soc_dai dai;
> + =A0 =A0 =A0 spinlock_t lock;
> + =A0 =A0 =A0 u32 sicr;
> +
> + =A0 =A0 =A0 /* per-stream data */
> + =A0 =A0 =A0 struct psc_i2s_stream playback;
> + =A0 =A0 =A0 struct psc_i2s_stream capture;
> +
> + =A0 =A0 =A0 /* Statistics */
> + =A0 =A0 =A0 struct {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 int overrun_count;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 int underrun_count;
> + =A0 =A0 =A0 } stats;
> +};
> +
> +
> +int psc_i2s_startup(struct snd_pcm_substream *substream,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct snd_soc_dai *=
dai);
> +
> +int psc_i2s_hw_free(struct snd_pcm_substream *substream,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct snd_soc_dai *=
dai);
> +
> +void psc_i2s_shutdown(struct snd_pcm_substream *substream,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct snd_soc_d=
ai *dai);
> +
> +int psc_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct snd_soc_dai *=
dai);
> +
> +extern struct snd_soc_platform psc_i2s_pcm_soc_platform;
> +
> +#endif /* __SOUND_SOC_FSL_MPC5200_DMA_H__ */
> diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_=
i2s.c
> index 1111c71..8974b53 100644
> --- a/sound/soc/fsl/mpc5200_psc_i2s.c
> +++ b/sound/soc/fsl/mpc5200_psc_i2s.c
> @@ -25,6 +25,8 @@
> =A0#include <sysdev/bestcomm/gen_bd.h>
> =A0#include <asm/mpc52xx_psc.h>
>
> +#include "mpc5200_dma.h"
> +
> =A0MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
> =A0MODULE_DESCRIPTION("Freescale MPC5200 PSC in I2S mode ASoC Driver");
> =A0MODULE_LICENSE("GPL");
> @@ -47,179 +49,6 @@ MODULE_LICENSE("GPL");
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 SNDRV_PCM_FMTBIT_S24_BE |=
SNDRV_PCM_FMTBIT_S24_BE | \
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 SNDRV_PCM_FMTBIT_S32_BE)
>
> -/**
> - * psc_i2s_stream - Data specific to a single stream (playback or captur=
e)
> - * @active: =A0 =A0 =A0 =A0 =A0 =A0flag indicating if the stream is acti=
ve
> - * @psc_i2s: =A0 =A0 =A0 =A0 =A0 pointer back to parent psc_i2s data str=
ucture
> - * @bcom_task: =A0 =A0 =A0 =A0 bestcomm task structure
> - * @irq: =A0 =A0 =A0 =A0 =A0 =A0 =A0 irq number for bestcomm task
> - * @period_start: =A0 =A0 =A0physical address of start of DMA region
> - * @period_end: =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0physical address of end o=
f DMA region
> - * @period_next_pt: =A0 =A0physical address of next DMA buffer to enqueu=
e
> - * @period_bytes: =A0 =A0 =A0size of DMA period in bytes
> - */
> -struct psc_i2s_stream {
> - =A0 =A0 =A0 int active;
> - =A0 =A0 =A0 struct psc_i2s *psc_i2s;
> - =A0 =A0 =A0 struct bcom_task *bcom_task;
> - =A0 =A0 =A0 int irq;
> - =A0 =A0 =A0 struct snd_pcm_substream *stream;
> - =A0 =A0 =A0 dma_addr_t period_start;
> - =A0 =A0 =A0 dma_addr_t period_end;
> - =A0 =A0 =A0 dma_addr_t period_next_pt;
> - =A0 =A0 =A0 dma_addr_t period_current_pt;
> - =A0 =A0 =A0 int period_bytes;
> -};
> -
> -/**
> - * psc_i2s - Private driver data
> - * @name: short name for this device ("PSC0", "PSC1", etc)
> - * @psc_regs: pointer to the PSC's registers
> - * @fifo_regs: pointer to the PSC's FIFO registers
> - * @irq: IRQ of this PSC
> - * @dev: struct device pointer
> - * @dai: the CPU DAI for this device
> - * @sicr: Base value used in serial interface control register; mode is =
ORed
> - * =A0 =A0 =A0 =A0with this value.
> - * @playback: Playback stream context data
> - * @capture: Capture stream context data
> - */
> -struct psc_i2s {
> - =A0 =A0 =A0 char name[32];
> - =A0 =A0 =A0 struct mpc52xx_psc __iomem *psc_regs;
> - =A0 =A0 =A0 struct mpc52xx_psc_fifo __iomem *fifo_regs;
> - =A0 =A0 =A0 unsigned int irq;
> - =A0 =A0 =A0 struct device *dev;
> - =A0 =A0 =A0 struct snd_soc_dai dai;
> - =A0 =A0 =A0 spinlock_t lock;
> - =A0 =A0 =A0 u32 sicr;
> -
> - =A0 =A0 =A0 /* per-stream data */
> - =A0 =A0 =A0 struct psc_i2s_stream playback;
> - =A0 =A0 =A0 struct psc_i2s_stream capture;
> -
> - =A0 =A0 =A0 /* Statistics */
> - =A0 =A0 =A0 struct {
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 int overrun_count;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 int underrun_count;
> - =A0 =A0 =A0 } stats;
> -};
> -
> -/*
> - * Interrupt handlers
> - */
> -static irqreturn_t psc_i2s_status_irq(int irq, void *_psc_i2s)
> -{
> - =A0 =A0 =A0 struct psc_i2s *psc_i2s =3D _psc_i2s;
> - =A0 =A0 =A0 struct mpc52xx_psc __iomem *regs =3D psc_i2s->psc_regs;
> - =A0 =A0 =A0 u16 isr;
> -
> - =A0 =A0 =A0 isr =3D in_be16(®s->mpc52xx_psc_isr);
> -
> - =A0 =A0 =A0 /* Playback underrun error */
> - =A0 =A0 =A0 if (psc_i2s->playback.active && (isr & MPC52xx_PSC_IMR_TXEM=
P))
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 psc_i2s->stats.underrun_count++;
> -
> - =A0 =A0 =A0 /* Capture overrun error */
> - =A0 =A0 =A0 if (psc_i2s->capture.active && (isr & MPC52xx_PSC_IMR_ORERR=
))
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 psc_i2s->stats.overrun_count++;
> -
> - =A0 =A0 =A0 out_8(®s->command, 4 << 4); =A0/* reset the error status=
*/
> -
> - =A0 =A0 =A0 return IRQ_HANDLED;
> -}
> -
> -/**
> - * psc_i2s_bcom_enqueue_next_buffer - Enqueue another audio buffer
> - * @s: pointer to stream private data structure
> - *
> - * Enqueues another audio period buffer into the bestcomm queue.
> - *
> - * Note: The routine must only be called when there is space available i=
n
> - * the queue. =A0Otherwise the enqueue will fail and the audio ring buff=
er
> - * will get out of sync
> - */
> -static void psc_i2s_bcom_enqueue_next_buffer(struct psc_i2s_stream *s)
> -{
> - =A0 =A0 =A0 struct bcom_bd *bd;
> -
> - =A0 =A0 =A0 /* Prepare and enqueue the next buffer descriptor */
> - =A0 =A0 =A0 bd =3D bcom_prepare_next_buffer(s->bcom_task);
> - =A0 =A0 =A0 bd->status =3D s->period_bytes;
> - =A0 =A0 =A0 bd->data[0] =3D s->period_next_pt;
> - =A0 =A0 =A0 bcom_submit_next_buffer(s->bcom_task, NULL);
> -
> - =A0 =A0 =A0 /* Update for next period */
> - =A0 =A0 =A0 s->period_next_pt +=3D s->period_bytes;
> - =A0 =A0 =A0 if (s->period_next_pt >=3D s->period_end)
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 s->period_next_pt =3D s->period_start;
> -}
> -
> -/* Bestcomm DMA irq handler */
> -static irqreturn_t psc_i2s_bcom_irq(int irq, void *_psc_i2s_stream)
> -{
> - =A0 =A0 =A0 struct psc_i2s_stream *s =3D _psc_i2s_stream;
> -
> - =A0 =A0 =A0 /* For each finished period, dequeue the completed period b=
uffer
> - =A0 =A0 =A0 =A0* and enqueue a new one in it's place. */
> - =A0 =A0 =A0 while (bcom_buffer_done(s->bcom_task)) {
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 bcom_retrieve_buffer(s->bcom_task, NULL, NU=
LL);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 s->period_current_pt +=3D s->period_bytes;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (s->period_current_pt >=3D s->period_end=
)
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 s->period_current_pt =3D s-=
>period_start;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 psc_i2s_bcom_enqueue_next_buffer(s);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 bcom_enable(s->bcom_task);
> - =A0 =A0 =A0 }
> -
> - =A0 =A0 =A0 /* If the stream is active, then also inform the PCM middle=
layer
> - =A0 =A0 =A0 =A0* of the period finished event. */
> - =A0 =A0 =A0 if (s->active)
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 snd_pcm_period_elapsed(s->stream);
> -
> - =A0 =A0 =A0 return IRQ_HANDLED;
> -}
> -
> -/**
> - * psc_i2s_startup: create a new substream
> - *
> - * This is the first function called when a stream is opened.
> - *
> - * If this is the first stream open, then grab the IRQ and program most =
of
> - * the PSC registers.
> - */
> -static int psc_i2s_startup(struct snd_pcm_substream *substream,
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct snd_soc_dai *=
dai)
> -{
> - =A0 =A0 =A0 struct snd_soc_pcm_runtime *rtd =3D substream->private_data=
;
> - =A0 =A0 =A0 struct psc_i2s *psc_i2s =3D rtd->dai->cpu_dai->private_data=
;
> - =A0 =A0 =A0 int rc;
> -
> - =A0 =A0 =A0 dev_dbg(psc_i2s->dev, "psc_i2s_startup(substream=3D%p)\n", =
substream);
> -
> - =A0 =A0 =A0 if (!psc_i2s->playback.active &&
> - =A0 =A0 =A0 =A0 =A0 !psc_i2s->capture.active) {
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Setup the IRQs */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 rc =3D request_irq(psc_i2s->irq, &psc_i2s_s=
tatus_irq, IRQF_SHARED,
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"psc-i2s=
-status", psc_i2s);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 rc |=3D request_irq(psc_i2s->capture.irq,
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 &psc_i2=
s_bcom_irq, IRQF_SHARED,
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "psc-i2=
s-capture", &psc_i2s->capture);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 rc |=3D request_irq(psc_i2s->playback.irq,
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 &psc_i2=
s_bcom_irq, IRQF_SHARED,
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "psc-i2=
s-playback", &psc_i2s->playback);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (rc) {
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 free_irq(psc_i2s->irq, psc_=
i2s);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 free_irq(psc_i2s->capture.i=
rq,
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0&psc_i2s=
->capture);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 free_irq(psc_i2s->playback.=
irq,
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0&psc_i2s=
->playback);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENODEV;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> - =A0 =A0 =A0 }
> -
> - =A0 =A0 =A0 return 0;
> -}
> -
> =A0static int psc_i2s_hw_params(struct snd_pcm_substream *substream,
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct sn=
d_pcm_hw_params *params,
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct sn=
d_soc_dai *dai)
> @@ -258,164 +87,6 @@ static int psc_i2s_hw_params(struct snd_pcm_substrea=
m *substream,
> =A0 =A0 =A0 =A0return 0;
> =A0}
>
> -static int psc_i2s_hw_free(struct snd_pcm_substream *substream,
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct snd_soc_dai *=
dai)
> -{
> - =A0 =A0 =A0 snd_pcm_set_runtime_buffer(substream, NULL);
> - =A0 =A0 =A0 return 0;
> -}
> -
> -/**
> - * psc_i2s_trigger: start and stop the DMA transfer.
> - *
> - * This function is called by ALSA to start, stop, pause, and resume the=
DMA
> - * transfer of data.
> - */
> -static int psc_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct snd_soc_dai *=
dai)
> -{
> - =A0 =A0 =A0 struct snd_soc_pcm_runtime *rtd =3D substream->private_data=
;
> - =A0 =A0 =A0 struct psc_i2s *psc_i2s =3D rtd->dai->cpu_dai->private_data=
;
> - =A0 =A0 =A0 struct snd_pcm_runtime *runtime =3D substream->runtime;
> - =A0 =A0 =A0 struct psc_i2s_stream *s;
> - =A0 =A0 =A0 struct mpc52xx_psc __iomem *regs =3D psc_i2s->psc_regs;
> - =A0 =A0 =A0 u16 imr;
> - =A0 =A0 =A0 u8 psc_cmd;
> - =A0 =A0 =A0 unsigned long flags;
> -
> - =A0 =A0 =A0 if (substream->pstr->stream =3D=3D SNDRV_PCM_STREAM_CAPTURE=
)
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 s =3D &psc_i2s->capture;
> - =A0 =A0 =A0 else
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 s =3D &psc_i2s->playback;
> -
> - =A0 =A0 =A0 dev_dbg(psc_i2s->dev, "psc_i2s_trigger(substream=3D%p, cmd=
=3D%i)"
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 " stream_id=3D%i\n",
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 substream, cmd, substream->pstr->stream);
> -
> - =A0 =A0 =A0 switch (cmd) {
> - =A0 =A0 =A0 case SNDRV_PCM_TRIGGER_START:
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 s->period_bytes =3D frames_to_bytes(runtime=
,
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
=A0 =A0 =A0 =A0 =A0 =A0 runtime->period_size);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 s->period_start =3D virt_to_phys(runtime->d=
ma_area);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 s->period_end =3D s->period_start +
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (s->period_=
bytes * runtime->periods);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 s->period_next_pt =3D s->period_start;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 s->period_current_pt =3D s->period_start;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 s->active =3D 1;
> -
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* First; reset everything */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (substream->pstr->stream =3D=3D SNDRV_PC=
M_STREAM_CAPTURE) {
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(®s->command, MPC52=
xx_PSC_RST_RX);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(®s->command, MPC52=
xx_PSC_RST_ERR_STAT);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 } else {
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(®s->command, MPC52=
xx_PSC_RST_TX);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(®s->command, MPC52=
xx_PSC_RST_ERR_STAT);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> -
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Next, fill up the bestcomm bd queue and =
enable DMA.
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* This will begin filling the PSC's fifo=
. */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (substream->pstr->stream =3D=3D SNDRV_PC=
M_STREAM_CAPTURE)
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 bcom_gen_bd_rx_reset(s->bco=
m_task);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 else
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 bcom_gen_bd_tx_reset(s->bco=
m_task);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 while (!bcom_queue_full(s->bcom_task))
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 psc_i2s_bcom_enqueue_next_b=
uffer(s);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 bcom_enable(s->bcom_task);
> -
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Due to errata in the i2s mode; need to l=
ine up enabling
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* the transmitter with a transition on t=
he frame sync
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* line */
> -
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 spin_lock_irqsave(&psc_i2s->lock, flags);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* first make sure it is low */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 while ((in_8(®s->ipcr_acr.ipcr) & 0x80) =
!=3D 0)
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* then wait for the transition to high */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 while ((in_8(®s->ipcr_acr.ipcr) & 0x80) =
=3D=3D 0)
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Finally, enable the PSC.
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* Receiver must always be enabled; even =
when we only want
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* transmit. =A0(see 15.3.2.3 of MPC5200B=
User's Guide) */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 psc_cmd =3D MPC52xx_PSC_RX_ENABLE;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (substream->pstr->stream =3D=3D SNDRV_PC=
M_STREAM_PLAYBACK)
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 psc_cmd |=3D MPC52xx_PSC_TX=
_ENABLE;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(®s->command, psc_cmd);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 spin_unlock_irqrestore(&psc_i2s->lock, flag=
s);
> -
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> -
> - =A0 =A0 =A0 case SNDRV_PCM_TRIGGER_STOP:
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Turn off the PSC */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 s->active =3D 0;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (substream->pstr->stream =3D=3D SNDRV_PC=
M_STREAM_CAPTURE) {
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!psc_i2s->playback.acti=
ve) {
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(®s=
->command, 2 << 4); =A0/* reset rx */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(®s=
->command, 3 << 4); =A0/* reset tx */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(®s=
->command, 4 << 4); =A0/* reset err */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 } else {
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(®s->command, 3 << =
4); =A0/* reset tx */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(®s->command, 4 << =
4); =A0/* reset err */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!psc_i2s->capture.activ=
e)
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(®s=
->command, 2 << 4); =A0/* reset rx */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> -
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 bcom_disable(s->bcom_task);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 while (!bcom_queue_empty(s->bcom_task))
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 bcom_retrieve_buffer(s->bco=
m_task, NULL, NULL);
> -
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> -
> - =A0 =A0 =A0 default:
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_dbg(psc_i2s->dev, "invalid command\n");
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -EINVAL;
> - =A0 =A0 =A0 }
> -
> - =A0 =A0 =A0 /* Update interrupt enable settings */
> - =A0 =A0 =A0 imr =3D 0;
> - =A0 =A0 =A0 if (psc_i2s->playback.active)
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 imr |=3D MPC52xx_PSC_IMR_TXEMP;
> - =A0 =A0 =A0 if (psc_i2s->capture.active)
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 imr |=3D MPC52xx_PSC_IMR_ORERR;
> - =A0 =A0 =A0 out_be16(®s->isr_imr.imr, imr);
> -
> - =A0 =A0 =A0 return 0;
> -}
> -
> -/**
> - * psc_i2s_shutdown: shutdown the data transfer on a stream
> - *
> - * Shutdown the PSC if there are no other substreams open.
> - */
> -static void psc_i2s_shutdown(struct snd_pcm_substream *substream,
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct snd_soc_d=
ai *dai)
> -{
> - =A0 =A0 =A0 struct snd_soc_pcm_runtime *rtd =3D substream->private_data=
;
> - =A0 =A0 =A0 struct psc_i2s *psc_i2s =3D rtd->dai->cpu_dai->private_data=
;
> -
> - =A0 =A0 =A0 dev_dbg(psc_i2s->dev, "psc_i2s_shutdown(substream=3D%p)\n",=
substream);
> -
> - =A0 =A0 =A0 /*
> - =A0 =A0 =A0 =A0* If this is the last active substream, disable the PSC =
and release
> - =A0 =A0 =A0 =A0* the IRQ.
> - =A0 =A0 =A0 =A0*/
> - =A0 =A0 =A0 if (!psc_i2s->playback.active &&
> - =A0 =A0 =A0 =A0 =A0 !psc_i2s->capture.active) {
> -
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Disable all interrupts and reset the PSC=
*/
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_be16(&psc_i2s->psc_regs->isr_imr.imr, 0=
);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(&psc_i2s->psc_regs->command, 3 << 4);=
/* reset tx */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(&psc_i2s->psc_regs->command, 2 << 4);=
/* reset rx */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(&psc_i2s->psc_regs->command, 1 << 4);=
/* reset mode */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(&psc_i2s->psc_regs->command, 4 << 4);=
/* reset error */
> -
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Release irqs */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 free_irq(psc_i2s->irq, psc_i2s);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 free_irq(psc_i2s->capture.irq, &psc_i2s->ca=
pture);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 free_irq(psc_i2s->playback.irq, &psc_i2s->p=
layback);
> - =A0 =A0 =A0 }
> -}
> -
> =A0/**
> =A0* psc_i2s_set_sysclk: set the clock frequency and direction
> =A0*
> @@ -495,158 +166,6 @@ static struct snd_soc_dai psc_i2s_dai_template =3D =
{
> =A0};
>
> =A0/* -------------------------------------------------------------------=
--
> - * The PSC I2S 'ASoC platform' driver
> - *
> - * Can be referenced by an 'ASoC machine' driver
> - * This driver only deals with the audio bus; it doesn't have any
> - * interaction with the attached codec
> - */
> -
> -static const struct snd_pcm_hardware psc_i2s_pcm_hardware =3D {
> - =A0 =A0 =A0 .info =3D SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO=
_BLOCK_TRANSFER |
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 SNDRV_PCM_INFO_BATCH,
> - =A0 =A0 =A0 .formats =3D SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE =
|
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_=
FMTBIT_S32_BE,
> - =A0 =A0 =A0 .rate_min =3D 8000,
> - =A0 =A0 =A0 .rate_max =3D 48000,
> - =A0 =A0 =A0 .channels_min =3D 2,
> - =A0 =A0 =A0 .channels_max =3D 2,
> - =A0 =A0 =A0 .period_bytes_max =A0 =A0 =A0 =3D 1024 * 1024,
> - =A0 =A0 =A0 .period_bytes_min =A0 =A0 =A0 =3D 32,
> - =A0 =A0 =A0 .periods_min =A0 =A0 =A0 =A0 =A0 =A0=3D 2,
> - =A0 =A0 =A0 .periods_max =A0 =A0 =A0 =A0 =A0 =A0=3D 256,
> - =A0 =A0 =A0 .buffer_bytes_max =A0 =A0 =A0 =3D 2 * 1024 * 1024,
> - =A0 =A0 =A0 .fifo_size =A0 =A0 =A0 =A0 =A0 =A0 =A0=3D 0,
> -};
> -
> -static int psc_i2s_pcm_open(struct snd_pcm_substream *substream)
> -{
> - =A0 =A0 =A0 struct snd_soc_pcm_runtime *rtd =3D substream->private_data=
;
> - =A0 =A0 =A0 struct psc_i2s *psc_i2s =3D rtd->dai->cpu_dai->private_data=
;
> - =A0 =A0 =A0 struct psc_i2s_stream *s;
> -
> - =A0 =A0 =A0 dev_dbg(psc_i2s->dev, "psc_i2s_pcm_open(substream=3D%p)\n",=
substream);
> -
> - =A0 =A0 =A0 if (substream->pstr->stream =3D=3D SNDRV_PCM_STREAM_CAPTURE=
)
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 s =3D &psc_i2s->capture;
> - =A0 =A0 =A0 else
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 s =3D &psc_i2s->playback;
> -
> - =A0 =A0 =A0 snd_soc_set_runtime_hwparams(substream, &psc_i2s_pcm_hardwa=
re);
> -
> - =A0 =A0 =A0 s->stream =3D substream;
> - =A0 =A0 =A0 return 0;
> -}
> -
> -static int psc_i2s_pcm_close(struct snd_pcm_substream *substream)
> -{
> - =A0 =A0 =A0 struct snd_soc_pcm_runtime *rtd =3D substream->private_data=
;
> - =A0 =A0 =A0 struct psc_i2s *psc_i2s =3D rtd->dai->cpu_dai->private_data=
;
> - =A0 =A0 =A0 struct psc_i2s_stream *s;
> -
> - =A0 =A0 =A0 dev_dbg(psc_i2s->dev, "psc_i2s_pcm_close(substream=3D%p)\n"=
, substream);
> -
> - =A0 =A0 =A0 if (substream->pstr->stream =3D=3D SNDRV_PCM_STREAM_CAPTURE=
)
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 s =3D &psc_i2s->capture;
> - =A0 =A0 =A0 else
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 s =3D &psc_i2s->playback;
> -
> - =A0 =A0 =A0 s->stream =3D NULL;
> - =A0 =A0 =A0 return 0;
> -}
> -
> -static snd_pcm_uframes_t
> -psc_i2s_pcm_pointer(struct snd_pcm_substream *substream)
> -{
> - =A0 =A0 =A0 struct snd_soc_pcm_runtime *rtd =3D substream->private_data=
;
> - =A0 =A0 =A0 struct psc_i2s *psc_i2s =3D rtd->dai->cpu_dai->private_data=
;
> - =A0 =A0 =A0 struct psc_i2s_stream *s;
> - =A0 =A0 =A0 dma_addr_t count;
> -
> - =A0 =A0 =A0 if (substream->pstr->stream =3D=3D SNDRV_PCM_STREAM_CAPTURE=
)
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 s =3D &psc_i2s->capture;
> - =A0 =A0 =A0 else
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 s =3D &psc_i2s->playback;
> -
> - =A0 =A0 =A0 count =3D s->period_current_pt - s->period_start;
> -
> - =A0 =A0 =A0 return bytes_to_frames(substream->runtime, count);
> -}
> -
> -static struct snd_pcm_ops psc_i2s_pcm_ops =3D {
> - =A0 =A0 =A0 .open =A0 =A0 =A0 =A0 =A0 =3D psc_i2s_pcm_open,
> - =A0 =A0 =A0 .close =A0 =A0 =A0 =A0 =A0=3D psc_i2s_pcm_close,
> - =A0 =A0 =A0 .ioctl =A0 =A0 =A0 =A0 =A0=3D snd_pcm_lib_ioctl,
> - =A0 =A0 =A0 .pointer =A0 =A0 =A0 =A0=3D psc_i2s_pcm_pointer,
> -};
> -
> -static u64 psc_i2s_pcm_dmamask =3D 0xffffffff;
> -static int psc_i2s_pcm_new(struct snd_card *card, struct snd_soc_dai *da=
i,
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct snd_pcm *pcm)
> -{
> - =A0 =A0 =A0 struct snd_soc_pcm_runtime *rtd =3D pcm->private_data;
> - =A0 =A0 =A0 size_t size =3D psc_i2s_pcm_hardware.buffer_bytes_max;
> - =A0 =A0 =A0 int rc =3D 0;
> -
> - =A0 =A0 =A0 dev_dbg(rtd->socdev->dev, "psc_i2s_pcm_new(card=3D%p, dai=
=3D%p, pcm=3D%p)\n",
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 card, dai, pcm);
> -
> - =A0 =A0 =A0 if (!card->dev->dma_mask)
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 card->dev->dma_mask =3D &psc_i2s_pcm_dmamas=
k;
> - =A0 =A0 =A0 if (!card->dev->coherent_dma_mask)
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 card->dev->coherent_dma_mask =3D 0xffffffff=
;
> -
> - =A0 =A0 =A0 if (pcm->streams[0].substream) {
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 rc =3D snd_dma_alloc_pages(SNDRV_DMA_TYPE_D=
EV, pcm->dev, size,
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
=A0 &pcm->streams[0].substream->dma_buffer);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (rc)
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto playback_alloc_err;
> - =A0 =A0 =A0 }
> -
> - =A0 =A0 =A0 if (pcm->streams[1].substream) {
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 rc =3D snd_dma_alloc_pages(SNDRV_DMA_TYPE_D=
EV, pcm->dev, size,
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
=A0 &pcm->streams[1].substream->dma_buffer);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (rc)
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto capture_alloc_err;
> - =A0 =A0 =A0 }
> -
> - =A0 =A0 =A0 return 0;
> -
> - capture_alloc_err:
> - =A0 =A0 =A0 if (pcm->streams[0].substream)
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 snd_dma_free_pages(&pcm->streams[0].substre=
am->dma_buffer);
> - playback_alloc_err:
> - =A0 =A0 =A0 dev_err(card->dev, "Cannot allocate buffer(s)\n");
> - =A0 =A0 =A0 return -ENOMEM;
> -}
> -
> -static void psc_i2s_pcm_free(struct snd_pcm *pcm)
> -{
> - =A0 =A0 =A0 struct snd_soc_pcm_runtime *rtd =3D pcm->private_data;
> - =A0 =A0 =A0 struct snd_pcm_substream *substream;
> - =A0 =A0 =A0 int stream;
> -
> - =A0 =A0 =A0 dev_dbg(rtd->socdev->dev, "psc_i2s_pcm_free(pcm=3D%p)\n", p=
cm);
> -
> - =A0 =A0 =A0 for (stream =3D 0; stream < 2; stream++) {
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 substream =3D pcm->streams[stream].substrea=
m;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (substream) {
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 snd_dma_free_pages(&substre=
am->dma_buffer);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 substream->dma_buffer.area =
=3D NULL;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 substream->dma_buffer.addr =
=3D 0;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> - =A0 =A0 =A0 }
> -}
> -
> -struct snd_soc_platform psc_i2s_pcm_soc_platform =3D {
> - =A0 =A0 =A0 .name =A0 =A0 =A0 =A0 =A0 =3D "mpc5200-psc-audio",
> - =A0 =A0 =A0 .pcm_ops =A0 =A0 =A0 =A0=3D &psc_i2s_pcm_ops,
> - =A0 =A0 =A0 .pcm_new =A0 =A0 =A0 =A0=3D &psc_i2s_pcm_new,
> - =A0 =A0 =A0 .pcm_free =A0 =A0 =A0 =3D &psc_i2s_pcm_free,
> -};
> -
> -/* ---------------------------------------------------------------------
> =A0* Sysfs attributes for debugging
> =A0*/
>
>
>
--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* Re: PPC405EX based irq flooding with USB-OTG and usbserial device
From: Chuck Meade @ 2009-05-24 13:06 UTC (permalink / raw)
To: Hunter Cobbs; +Cc: linuxppc-dev
In-Reply-To: <ad84a70a0905231150s18026213r9360eb6807ab842e@mail.gmail.com>
Hunter Cobbs wrote:
> On Sat, May 23, 2009 at 1:14 PM, Wolfgang Denk <wd@denx.de
> <mailto:wd@denx.de>> wrote:
>
> Dear Hunter,
>
> In message
> <ad84a70a0905222048i4e7ae5ddp66418f96d531f5f3@mail.gmail.com
> <mailto:ad84a70a0905222048i4e7ae5ddp66418f96d531f5f3@mail.gmail.com>>
> you wrote:
> >
> > This is my first post to the PPC dev list as my company has just
> started
> > developing a new project based on Linux. The good news is, this
> post is not
> > debug-related as much as it is an introduction and query while I
> download
> > the latest DENX kernel(only place I know that has the DWC_OTG driver).
>
> there is a strong reason why we decided not to try to push this
> driver upstream: it is not in a state that would have a chance for
> being accepted for mainline. The problems you are experiencing are
> probably not the only one. Please consider this driver as
> unsupported.
>
> Best regards,
>
> Wolfgang Denk
>
> --
> DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel
> HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
> Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email:
> wd@denx.de <mailto:wd@denx.de>
> "Ada is PL/I trying to be Smalltalk. - Codoso diBlini
>
>
> Which leads me to another question. Since I should consider this
> unsupported, is there a better driver out there as my company is already
> well down the road with our design? Or would you recommend just
> creating our own driver for the USB-OTG?
>
> I'm developing with the Kilauea, and I guess I should ask how unstable
> is Linux support for this Processor.
> --
> Hunter Cobbs
Hi Hunter,
First, thanks very much for the email, and for the patches to fix the DMA. I had
assumed, both when I saw the DMA warnings and when I saw the defines in the Makefile,
that DMA was absolutely not ready for primetime on PPC405EX USB. Needless to say I
will be testing out your DMA patches here.
If that works for me, that should mitigate some of this interrupt overhead. So thanks
in advance -- I am hoping that this will make a real difference.
To answer your recent question, I have had no other difficulties with the PPC405EX.
I actually work with 3 different custom targets right now using the PPC405EX (one uses
the PPC405EXr variant), and have had no problems outside of USB.
I do not know of any other driver for the PPC405EX USB controller.
My other remaining USB issue on this controller is a bandwidth issue. There is another
USB host controller called ehci commonly found on PCs, and I see that they have a
configurable scheduler tweak called CONFIG_USB_EHCI_TT_NEWSCHED. The description in
the drivers/usb/host/Kconfig file for that config item under ehci (in the Kconfig file
search for USB_EHCI_TT_NEWSCHED) is *exactly* the problem I am having now on the PPC405EX
USB controller. Of course that scheduler tweak is for a totally different USB controller,
so that doesn't help me directly, but it serves as an example. If anybody else out there
has fixed this USB bandwidth issue on PPC405EX (the one described in the ehci solution
for this under USB_EHCI_TT_NEWSCHED), please let me/us know.
Thanks,
Chuck
^ permalink raw reply
* Re: [alsa-devel] [PATCH V2 9/9] Support for AC97 on Phytec pmc030 base board.
From: Mark Brown @ 2009-05-24 12:13 UTC (permalink / raw)
To: Jon Smirl; +Cc: linuxppc-dev, alsa-devel
In-Reply-To: <20090523231313.17919.93066.stgit@terra>
On Sat, May 23, 2009 at 07:13:13PM -0400, Jon Smirl wrote:
> Support for AC97 on Phytec pmc030 base board. A wm9712 AC97 codec is used.
>
> Signed-off-by: Jon Smirl <jonsmirl@gmail.com>
Same comments as for the previous driver - it's OK once the AC97 DAI
driver goes in.
^ permalink raw reply
* Re: [alsa-devel] [PATCH V2 8/9] Fabric bindings for STAC9766 on the Efika
From: Mark Brown @ 2009-05-24 12:12 UTC (permalink / raw)
To: Jon Smirl; +Cc: linuxppc-dev, alsa-devel
In-Reply-To: <20090523231311.17919.38581.stgit@terra>
On Sat, May 23, 2009 at 07:13:11PM -0400, Jon Smirl wrote:
> Fabric bindings for STAC9766 AC97 codec on the Efika.
>
> Signed-off-by: Jon Smirl <jonsmirl@gmail.com>
This is OK, but obviously depends on previous patches so I'll not apply
it just yet. You might want to run it (and many of your other patches)
through checkpatch, though. One nit:
> +static __exit void efika_fabric_exit(void)
> +{
> +}
This should either do something or be removed.
^ permalink raw reply
* Re: [alsa-devel] [PATCH V2 7/9] AC97 driver for mpc5200
From: Mark Brown @ 2009-05-24 12:10 UTC (permalink / raw)
To: Jon Smirl; +Cc: linuxppc-dev, alsa-devel
In-Reply-To: <20090523231309.17919.83073.stgit@terra>
On Sat, May 23, 2009 at 07:13:09PM -0400, Jon Smirl wrote:
> +#ifdef CONFIG_PM
> +static int psc_ac97_suspend(struct snd_soc_dai *dai)
> +{
> + return 0;
> +}
> +
> +static int psc_ac97_resume(struct snd_soc_dai *dai)
> +{
> + return 0;
> +}
> +
> +#else
> +#define psc_ac97_suspend NULL
> +#define psc_ac97_resume NULL
> +#endif
These can all just be removed, they can be added later if they are
implemented.
> +static int psc_ac97_hw_analog_params(struct snd_pcm_substream *substream,
> + struct snd_pcm_hw_params *params,
> + struct snd_soc_dai *dai)
> +{
> + struct snd_soc_pcm_runtime *rtd = substream->private_data;
> + struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
Note that cpu_dai is passed in as an argument here - this didn't used to
be the case which is why most drivers fish it out of rtd but that's not
required any more.
> +static int psc_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
> + struct snd_soc_dai *dai)
Again with the odd indentation.
> +static int __devinit psc_ac97_of_probe(struct of_device *op,
> + const struct of_device_id *match)
> +{
> + rc = snd_soc_register_dais(psc_ac97_dai, ARRAY_SIZE(psc_ac97_dai));
> + if (rc != 0) {
> + pr_err("Failed to register DAI\n");
> + return 0;
> + }
I'd expect to see the error passed back to the caller here? I'd also
expect to see this happening right at the end of this function after
you're happy everything else has worked, otherwise the core might try to
start using the half-initialised driver.
> + /* AC97 clock is generated by the codec.
> + * Ensure that it starts ticking after codec reset.
> + */
> + max_reset = 0;
> +reset:
> + if (max_reset++ > 5) {
> + dev_err(&op->dev, "AC97 codec failed to reset\n");
> + mpc5200_audio_dma_destroy(op);
> + return -ENODEV;
> + }
> +
> + psc_ac97_cold_reset(&ac97);
> + psc_ac97_warm_reset(&ac97);
> +
> + /* first make sure it is low */
> + timeout = 0;
> + while ((in_8(®s->ipcr_acr.ipcr) & 0x80) != 0) {
> + udelay(1);
> + if (timeout++ > 1000)
> + goto reset;
> + }
This looks awfully similar to the logic in the resume function of your
CODEC driver... In general an ASoC AC97 DAI driver shouldn't be trying
to bring the CODEC up like this, it should normally leave that up to the
CODEC driver. This is mostly because some system designers do strange
and wonderful things with clocking which require some system specific
code to either bring up the master clock for the codec before it'll
reset or reconfigure the clocking to something standard.
The issue with the use of goto rather than a real loop also applies
here.
> + /* then wait for the transition to high */
> + timeout = 0;
> + while ((in_8(®s->ipcr_acr.ipcr) & 0x80) == 0) {
> + udelay(1);
> + if (timeout++ > 1000)
> + psc_ac97_warm_reset(&ac97);
> + }
Shouldn't this be integrated into the warm reset operation (or to put it
another way, why wouldn't a warm reset want to do this)?
> +
> + /* Go */
> + out_8(®s->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);
> +
> + id1 = psc_ac97_read(&ac97, AC97_VENDOR_ID1);
> + id2 = psc_ac97_read(&ac97, AC97_VENDOR_ID2);
> +
> + dev_info(&op->dev, "Codec ID is %04x %04x\n", id1, id2);
You really can't rely on this working in general system designs - like I
say, some platforms will require additional work to bring the CODEC up.
I'd just remove it, it's purely for information anyway. The out_8()
probably ought to be moved into the ASoC probe() function (called once
the card is coming up).
^ permalink raw reply
* Re: [alsa-devel] [PATCH V2 6/9] Codec for STAC9766 used on the Efika
From: Mark Brown @ 2009-05-24 11:46 UTC (permalink / raw)
To: Jon Smirl; +Cc: linuxppc-dev, alsa-devel
In-Reply-To: <20090523231307.17919.5277.stgit@terra>
On Sat, May 23, 2009 at 07:13:07PM -0400, Jon Smirl wrote:
> AC97 codec for STAC9766 used on the Efika.
> Datasheet: http://www.idt.com/products/getDoc.cfm?docID=13134007
>
> Signed-off-by: Jon Smirl <jonsmirl@gmail.com>
This looks mostly good, a couple of issues below. I'll apply the patch
but please submit a followup patch for resume as discussed below.
> +static int ac97_digital_trigger(struct snd_pcm_substream *substream,
> + int cmd, struct snd_soc_dai *dai)
Very strange indentation here...
> +static int stac9766_codec_resume(struct platform_device *pdev)
> +{
> + /* give the codec an AC97 warm reset to start the link */
> +reset:
> + if (reset > 5) {
> + printk(KERN_ERR "stac9766 failed to resume");
> + return -EIO;
> + }
> + codec->ac97->bus->ops->warm_reset(codec->ac97);
> + id = soc_ac97_ops.read(codec->ac97, AC97_VENDOR_ID2);
> + if (id != 0x4c13) {
> + stac9766_reset(codec, 0);
> + reset++;
> + goto reset;
> + }
As I said last time I'd this looks like it should be using the reset
function that you've provided?
The loop is new since last time and seems very suspicious - are you sure
that this is a CODEC problem that's being worked around and not an issue
with the AC97 controller or with the specific system starting up the
master clock for the CODEC after resume? If it's an issue with the
controler then it'd be better to fix it there so that all CODEC drivers
get the benefit. If it's a CODEC issue a comment explaining the problem
would be helpful since it's not the sort of issue I'd expect to see in a
CODEC. The fact that it's not needed on initial boot suggests something
controller or external clock related.
Either way, it'd be much clearer to rewrite it using a for or while loop
rather than a goto. Please submit a followup patch fixing at least this
issue.
> +static int __init stac9766_modinit(void)
> +{
> + return snd_soc_register_dais(stac9766_dai, ARRAY_SIZE(stac9766_dai));
> +}
> +module_init(stac9766_modinit);
> +
> +static void __exit stac9766_exit(void)
> +{
> + snd_soc_unregister_dais(stac9766_dai, ARRAY_SIZE(stac9766_dai));
> +}
> +module_exit(stac9766_exit);
These are not needed for AC97 CODECs, ASoC doesn't wait for them to
probe. I'll apply a patch removing these.
^ permalink raw reply
* Re: [alsa-devel] [PATCH V2 5/9] Main rewite of the mpc5200 audio DMA code
From: Mark Brown @ 2009-05-24 11:26 UTC (permalink / raw)
To: Jon Smirl; +Cc: linuxppc-dev, alsa-devel
In-Reply-To: <20090523231305.17919.12239.stgit@terra>
On Sat, May 23, 2009 at 07:13:05PM -0400, Jon Smirl wrote:
This is all basically OK bearing in mind that I know nothing about the
hardware. A couple of things, though:
> +/* ---------------------------------------------------------------------
> + * Sysfs attributes for debugging
> + */
These look like they may be better placed in debugfs?
> +EXPORT_SYMBOL_GPL(mpc5200_audio_dma_create);
> +EXPORT_SYMBOL_GPL(mpc5200_audio_dma_destroy);
> +static int __init mpc5200_soc_platform_init(void)
> +{
> + /* Tell the ASoC OF helpers about it */
> + return snd_soc_register_platform(&mpc5200_audio_dma_platform);
> +}
> +module_init(mpc5200_soc_platform_init);
> +static void __exit mpc5200_soc_platform_exit(void)
> +{
> + snd_soc_unregister_platform(&mpc5200_audio_dma_platform);
> +}
> +module_exit(mpc5200_soc_platform_exit);
This all looks a bit odd - I'd expect to see the platform registering
with the core when it is probed rather than on module load. Looking at
the code it appears that you're automatically instantiating the DMA
driver from the node for the DAI? If that is the case then you ought
to be calling the platform registration functions from the dma_create()
and dma_destroy() functions instead.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).