Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/27654/?format=api
{ "id": 27654, "url": "http://patchwork.ozlabs.org/api/patches/27654/?format=api", "web_url": "http://patchwork.ozlabs.org/project/linuxppc-dev/patch/20090526123408.17472.83007.stgit@terra/", "project": { "id": 2, "url": "http://patchwork.ozlabs.org/api/projects/2/?format=api", "name": "Linux PPC development", "link_name": "linuxppc-dev", "list_id": "linuxppc-dev.lists.ozlabs.org", "list_email": "linuxppc-dev@lists.ozlabs.org", "web_url": "https://github.com/linuxppc/wiki/wiki", "scm_url": "https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git", "webscm_url": "https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git/", "list_archive_url": "https://lore.kernel.org/linuxppc-dev/", "list_archive_url_format": "https://lore.kernel.org/linuxppc-dev/{}/", "commit_url_format": "https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git/commit/?id={}" }, "msgid": "<20090526123408.17472.83007.stgit@terra>", "list_archive_url": "https://lore.kernel.org/linuxppc-dev/20090526123408.17472.83007.stgit@terra/", "date": "2009-05-26T12:34:08", "name": "[V5,2/5] Main rewite of the mpc5200 audio DMA code", "commit_ref": null, "pull_url": null, "state": "not-applicable", "archived": true, "hash": "f996eaf49a7c0f203df945e0f7cdc38d34f0bef2", "submitter": { "id": 375, "url": "http://patchwork.ozlabs.org/api/people/375/?format=api", "name": "jonsmirl@gmail.com", "email": "jonsmirl@gmail.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/linuxppc-dev/patch/20090526123408.17472.83007.stgit@terra/mbox/", "series": [], "comments": "http://patchwork.ozlabs.org/api/patches/27654/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/27654/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<linuxppc-dev-bounces+patchwork-incoming=ozlabs.org@ozlabs.org>", "X-Original-To": [ "patchwork-incoming@bilbo.ozlabs.org", "linuxppc-dev@ozlabs.org" ], "Delivered-To": [ "patchwork-incoming@bilbo.ozlabs.org", "patchwork-incoming@ozlabs.org", "linuxppc-dev@ozlabs.org" ], "Received": [ "from ozlabs.org (ozlabs.org [203.10.76.45])\n\t(using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits))\n\t(Client CN \"mx.ozlabs.org\",\n\tIssuer \"CA Cert Signing Authority\" (verified OK))\n\tby bilbo.ozlabs.org (Postfix) with ESMTPS id 4014BB7079\n\tfor <patchwork-incoming@bilbo.ozlabs.org>;\n\tTue, 26 May 2009 22:37:57 +1000 (EST)", "by ozlabs.org (Postfix)\n\tid 02FBCDE493; Tue, 26 May 2009 22:35:32 +1000 (EST)", "from ozlabs.org (localhost [127.0.0.1])\n\tby ozlabs.org (Postfix) with ESMTP id 00436DE204\n\tfor <patchwork-incoming@ozlabs.org>;\n\tTue, 26 May 2009 22:35:31 +1000 (EST)", "from mail-gx0-f220.google.com (mail-gx0-f220.google.com\n\t[209.85.217.220]) by ozlabs.org (Postfix) with ESMTP id 364A6DE081\n\tfor <linuxppc-dev@ozlabs.org>; Tue, 26 May 2009 22:34:11 +1000 (EST)", "by gxk20 with SMTP id 20so2687631gxk.9\n\tfor <linuxppc-dev@ozlabs.org>; Tue, 26 May 2009 05:34:10 -0700 (PDT)", "by 10.90.80.18 with SMTP id d18mr1607583agb.9.1243341250640;\n\tTue, 26 May 2009 05:34:10 -0700 (PDT)", "from terra (c-76-109-159-38.hsd1.fl.comcast.net [76.109.159.38])\n\tby mx.google.com with ESMTPS id 4sm17043855aga.56.2009.05.26.05.34.09\n\t(version=TLSv1/SSLv3 cipher=RC4-MD5);\n\tTue, 26 May 2009 05:34:10 -0700 (PDT)", "from localhost ([127.0.0.1] helo=[127.0.1.1])\n\tby terra with esmtp (Exim 4.69) (envelope-from <jonsmirl@gmail.com>)\n\tid 1M8vr6-0004ZM-AS; Tue, 26 May 2009 08:34:08 -0400" ], "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; \n\th=domainkey-signature:received:received:received:subject:to:from:date\n\t:message-id:in-reply-to:references:user-agent:mime-version\n\t:content-type:content-transfer-encoding;\n\tbh=gHKAIzYJQeB9Ak5BSRsFs/tG608JyE8dx4DWKdrPOkQ=;\n\tb=udWD7d+mn78N9ODGPPOXOp/Ggs5kBBX1cW9Etovre//JEFlhf0MwsyW83oTMjwqMBT\n\tAr5TzfWS9RkniHfzFZZTSJ1IgmAUbMqqsB6zB3zBS1WvBQ3EWDwWT9eV/3JLIAf6Vs4y\n\teLVDUZ1iScY2yxnD8sQeEZpQksGtf/3hMWDYQ=", "DomainKey-Signature": "a=rsa-sha1; c=nofws; d=gmail.com; s=gamma;\n\th=subject:to:from:date:message-id:in-reply-to:references:user-agent\n\t:mime-version:content-type:content-transfer-encoding;\n\tb=YAPlaV+I+gIUpiXVR23/2LQWm0eHUWYObiGL9aEcDGryqnUtx5kodxeYQeEPyQq6OD\n\t4d2S+c7I87WoD5zBPlU7GjtFPZm02Bb4EIaT7b74fZR+Rc1YVdxdgSAzI25c/sPDGoEk\n\tC4dZG/ZmgjuSSdN1+6OOg2qyo1UMg/HddvSEE=", "Subject": "[PATCH V5 2/5] Main rewite of the mpc5200 audio DMA code", "To": "grant.likely@secretlab.ca, linuxppc-dev@ozlabs.org,\n\talsa-devel@alsa-project.org, broonie@sirena.org.uk, timur@freescale.com", "From": "Jon Smirl <jonsmirl@gmail.com>", "Date": "Tue, 26 May 2009 08:34:08 -0400", "Message-ID": "<20090526123408.17472.83007.stgit@terra>", "In-Reply-To": "<20090526123235.17472.73912.stgit@terra>", "References": "<20090526123235.17472.73912.stgit@terra>", "User-Agent": "StGit/0.14.3.366.gf979", "MIME-Version": "1.0", "X-BeenThere": "linuxppc-dev@ozlabs.org", "X-Mailman-Version": "2.1.11", "Precedence": "list", "List-Id": "Linux on PowerPC Developers Mail List <linuxppc-dev.ozlabs.org>", "List-Unsubscribe": "<https://ozlabs.org/mailman/options/linuxppc-dev>,\n\t<mailto:linuxppc-dev-request@ozlabs.org?subject=unsubscribe>", "List-Archive": "<http://ozlabs.org/pipermail/linuxppc-dev>", "List-Post": "<mailto:linuxppc-dev@ozlabs.org>", "List-Help": "<mailto:linuxppc-dev-request@ozlabs.org?subject=help>", "List-Subscribe": "<https://ozlabs.org/mailman/listinfo/linuxppc-dev>,\n\t<mailto:linuxppc-dev-request@ozlabs.org?subject=subscribe>", "Content-Type": "text/plain; charset=\"us-ascii\"", "Content-Transfer-Encoding": "7bit", "Sender": "linuxppc-dev-bounces+patchwork-incoming=ozlabs.org@ozlabs.org", "Errors-To": "linuxppc-dev-bounces+patchwork-incoming=ozlabs.org@ozlabs.org" }, "content": "Rewrite the mpc5200 audio DMA code to support both I2S and AC97.\n\nSigned-off-by: Jon Smirl <jonsmirl@gmail.com>\n---\n sound/soc/fsl/Kconfig | 1 \n sound/soc/fsl/mpc5200_dma.c | 442 ++++++++++++++++++++++++---------------\n sound/soc/fsl/mpc5200_dma.h | 33 +--\n sound/soc/fsl/mpc5200_psc_i2s.c | 247 ++++------------------\n sound/soc/fsl/mpc5200_psc_i2s.h | 12 +\n 5 files changed, 344 insertions(+), 391 deletions(-)\n create mode 100644 sound/soc/fsl/mpc5200_psc_i2s.h", "diff": "diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig\nindex dc79bdf..1918c78 100644\n--- a/sound/soc/fsl/Kconfig\n+++ b/sound/soc/fsl/Kconfig\n@@ -25,7 +25,6 @@ config SND_SOC_MPC8610_HPCD\n config SND_SOC_MPC5200_I2S\n \ttristate \"Freescale MPC5200 PSC in I2S mode driver\"\n \tdepends on PPC_MPC52xx && PPC_BESTCOMM\n-\tselect SND_SOC_OF_SIMPLE\n \tselect SND_MPC52xx_DMA\n \tselect PPC_BESTCOMM_GEN_BD\n \thelp\ndiff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c\nindex 6850392..efec33a 100644\n--- a/sound/soc/fsl/mpc5200_dma.c\n+++ b/sound/soc/fsl/mpc5200_dma.c\n@@ -3,23 +3,13 @@\n * ALSA SoC Platform driver\n *\n * Copyright (C) 2008 Secret Lab Technologies Ltd.\n+ * Copyright (C) 2009 Jon Smirl, Digispeaker\n */\n \n-#include <linux/init.h>\n #include <linux/module.h>\n-#include <linux/interrupt.h>\n-#include <linux/device.h>\n-#include <linux/delay.h>\n #include <linux/of_device.h>\n-#include <linux/of_platform.h>\n-#include <linux/dma-mapping.h>\n \n-#include <sound/core.h>\n-#include <sound/pcm.h>\n-#include <sound/pcm_params.h>\n-#include <sound/initval.h>\n #include <sound/soc.h>\n-#include <sound/soc-of-simple.h>\n \n #include <sysdev/bestcomm/bestcomm.h>\n #include <sysdev/bestcomm/gen_bd.h>\n@@ -27,10 +17,6 @@\n \n #include \"mpc5200_dma.h\"\n \n-MODULE_AUTHOR(\"Grant Likely <grant.likely@secretlab.ca>\");\n-MODULE_DESCRIPTION(\"Freescale MPC5200 PSC in DMA mode ASoC Driver\");\n-MODULE_LICENSE(\"GPL\");\n-\n /*\n * Interrupt handlers\n */\n@@ -50,7 +36,7 @@ static irqreturn_t psc_dma_status_irq(int irq, void *_psc_dma)\n \tif (psc_dma->capture.active && (isr & MPC52xx_PSC_IMR_ORERR))\n \t\tpsc_dma->stats.overrun_count++;\n \n-\tout_8(®s->command, 4 << 4);\t/* reset the error status */\n+\tout_8(®s->command, MPC52xx_PSC_RST_ERR_STAT);\n \n \treturn IRQ_HANDLED;\n }\n@@ -81,21 +67,36 @@ static void psc_dma_bcom_enqueue_next_buffer(struct psc_dma_stream *s)\n \t\ts->period_next_pt = s->period_start;\n }\n \n+static void psc_dma_bcom_enqueue_tx(struct psc_dma_stream *s)\n+{\n+\twhile (s->appl_ptr < s->runtime->control->appl_ptr) {\n+\n+\t\tif (bcom_queue_full(s->bcom_task))\n+\t\t\treturn;\n+\n+\t\ts->appl_ptr += s->period_size;\n+\n+\t\tpsc_dma_bcom_enqueue_next_buffer(s);\n+\t}\n+}\n+\n /* Bestcomm DMA irq handler */\n-static irqreturn_t psc_dma_bcom_irq(int irq, void *_psc_dma_stream)\n+static irqreturn_t psc_dma_bcom_irq_tx(int irq, void *_psc_dma_stream)\n {\n \tstruct psc_dma_stream *s = _psc_dma_stream;\n \n+\tspin_lock(&s->psc_dma->lock);\n \t/* For each finished period, dequeue the completed period buffer\n \t * and enqueue a new one in it's place. */\n \twhile (bcom_buffer_done(s->bcom_task)) {\n \t\tbcom_retrieve_buffer(s->bcom_task, NULL, NULL);\n+\n \t\ts->period_current_pt += s->period_bytes;\n \t\tif (s->period_current_pt >= s->period_end)\n \t\t\ts->period_current_pt = s->period_start;\n-\t\tpsc_dma_bcom_enqueue_next_buffer(s);\n-\t\tbcom_enable(s->bcom_task);\n \t}\n+\tpsc_dma_bcom_enqueue_tx(s);\n+\tspin_unlock(&s->psc_dma->lock);\n \n \t/* If the stream is active, then also inform the PCM middle layer\n \t * of the period finished event. */\n@@ -105,49 +106,33 @@ static irqreturn_t psc_dma_bcom_irq(int irq, void *_psc_dma_stream)\n \treturn IRQ_HANDLED;\n }\n \n-/**\n- * psc_dma_startup: create a new substream\n- *\n- * This is the first function called when a stream is opened.\n- *\n- * If this is the first stream open, then grab the IRQ and program most of\n- * the PSC registers.\n- */\n-int psc_dma_startup(struct snd_pcm_substream *substream,\n-\t\t\t struct snd_soc_dai *dai)\n+static irqreturn_t psc_dma_bcom_irq_rx(int irq, void *_psc_dma_stream)\n {\n-\tstruct snd_soc_pcm_runtime *rtd = substream->private_data;\n-\tstruct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;\n-\tint rc;\n+\tstruct psc_dma_stream *s = _psc_dma_stream;\n \n-\tdev_dbg(psc_dma->dev, \"psc_dma_startup(substream=%p)\\n\", substream);\n+\tspin_lock(&s->psc_dma->lock);\n+\t/* For each finished period, dequeue the completed period buffer\n+\t * and enqueue a new one in it's place. */\n+\twhile (bcom_buffer_done(s->bcom_task)) {\n+\t\tbcom_retrieve_buffer(s->bcom_task, NULL, NULL);\n \n-\tif (!psc_dma->playback.active &&\n-\t !psc_dma->capture.active) {\n-\t\t/* Setup the IRQs */\n-\t\trc = request_irq(psc_dma->irq, &psc_dma_status_irq, IRQF_SHARED,\n-\t\t\t\t \"psc-dma-status\", psc_dma);\n-\t\trc |= request_irq(psc_dma->capture.irq,\n-\t\t\t\t &psc_dma_bcom_irq, IRQF_SHARED,\n-\t\t\t\t \"psc-dma-capture\", &psc_dma->capture);\n-\t\trc |= request_irq(psc_dma->playback.irq,\n-\t\t\t\t &psc_dma_bcom_irq, IRQF_SHARED,\n-\t\t\t\t \"psc-dma-playback\", &psc_dma->playback);\n-\t\tif (rc) {\n-\t\t\tfree_irq(psc_dma->irq, psc_dma);\n-\t\t\tfree_irq(psc_dma->capture.irq,\n-\t\t\t\t &psc_dma->capture);\n-\t\t\tfree_irq(psc_dma->playback.irq,\n-\t\t\t\t &psc_dma->playback);\n-\t\t\treturn -ENODEV;\n-\t\t}\n+\t\ts->period_current_pt += s->period_bytes;\n+\t\tif (s->period_current_pt >= s->period_end)\n+\t\t\ts->period_current_pt = s->period_start;\n+\n+\t\tpsc_dma_bcom_enqueue_next_buffer(s);\n \t}\n+\tspin_unlock(&s->psc_dma->lock);\n \n-\treturn 0;\n+\t/* If the stream is active, then also inform the PCM middle layer\n+\t * of the period finished event. */\n+\tif (s->active)\n+\t\tsnd_pcm_period_elapsed(s->stream);\n+\n+\treturn IRQ_HANDLED;\n }\n \n-int psc_dma_hw_free(struct snd_pcm_substream *substream,\n-\t\t\t struct snd_soc_dai *dai)\n+static int psc_dma_hw_free(struct snd_pcm_substream *substream)\n {\n \tsnd_pcm_set_runtime_buffer(substream, NULL);\n \treturn 0;\n@@ -159,8 +144,7 @@ int psc_dma_hw_free(struct snd_pcm_substream *substream,\n * This function is called by ALSA to start, stop, pause, and resume the DMA\n * transfer of data.\n */\n-int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd,\n-\t\t\t struct snd_soc_dai *dai)\n+static int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd)\n {\n \tstruct snd_soc_pcm_runtime *rtd = substream->private_data;\n \tstruct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;\n@@ -168,8 +152,8 @@ int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd,\n \tstruct psc_dma_stream *s;\n \tstruct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;\n \tu16 imr;\n-\tu8 psc_cmd;\n \tunsigned long flags;\n+\tint i;\n \n \tif (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)\n \t\ts = &psc_dma->capture;\n@@ -189,68 +173,48 @@ int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd,\n \t\t\t\t(s->period_bytes * runtime->periods);\n \t\ts->period_next_pt = s->period_start;\n \t\ts->period_current_pt = s->period_start;\n+\t\ts->period_size = runtime->period_size;\n \t\ts->active = 1;\n \n-\t\t/* First; reset everything */\n+\t\t/* track appl_ptr so that we have a better chance of detecting\n+\t\t * end of stream and not over running it.\n+\t\t */\n+\t\ts->runtime = runtime;\n+\t\ts->appl_ptr = s->runtime->control->appl_ptr -\n+\t\t\t\t(runtime->period_size * runtime->periods);\n+\n+\t\t/* Fill up the bestcomm bd queue and enable DMA.\n+\t\t * This will begin filling the PSC's fifo.\n+\t\t */\n+\t\tspin_lock_irqsave(&psc_dma->lock, flags);\n+\n \t\tif (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) {\n-\t\t\tout_8(®s->command, MPC52xx_PSC_RST_RX);\n-\t\t\tout_8(®s->command, MPC52xx_PSC_RST_ERR_STAT);\n+\t\t\tbcom_gen_bd_rx_reset(s->bcom_task);\n+\t\t\tfor (i = 0; i < runtime->periods; i++)\n+\t\t\t\tif (!bcom_queue_full(s->bcom_task))\n+\t\t\t\t\tpsc_dma_bcom_enqueue_next_buffer(s);\n \t\t} else {\n-\t\t\tout_8(®s->command, MPC52xx_PSC_RST_TX);\n-\t\t\tout_8(®s->command, MPC52xx_PSC_RST_ERR_STAT);\n+\t\t\tbcom_gen_bd_tx_reset(s->bcom_task);\n+\t\t\tpsc_dma_bcom_enqueue_tx(s);\n \t\t}\n \n-\t\t/* Next, fill up the bestcomm bd queue and enable DMA.\n-\t\t * This will begin filling the PSC's fifo. */\n-\t\tif (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)\n-\t\t\tbcom_gen_bd_rx_reset(s->bcom_task);\n-\t\telse\n-\t\t\tbcom_gen_bd_tx_reset(s->bcom_task);\n-\t\twhile (!bcom_queue_full(s->bcom_task))\n-\t\t\tpsc_dma_bcom_enqueue_next_buffer(s);\n \t\tbcom_enable(s->bcom_task);\n-\n-\t\t/* Due to errata in the dma mode; need to line up enabling\n-\t\t * the transmitter with a transition on the frame sync\n-\t\t * line */\n-\n-\t\tspin_lock_irqsave(&psc_dma->lock, flags);\n-\t\t/* first make sure it is low */\n-\t\twhile ((in_8(®s->ipcr_acr.ipcr) & 0x80) != 0)\n-\t\t\t;\n-\t\t/* then wait for the transition to high */\n-\t\twhile ((in_8(®s->ipcr_acr.ipcr) & 0x80) == 0)\n-\t\t\t;\n-\t\t/* Finally, enable the PSC.\n-\t\t * Receiver must always be enabled; even when we only want\n-\t\t * transmit. (see 15.3.2.3 of MPC5200B User's Guide) */\n-\t\tpsc_cmd = MPC52xx_PSC_RX_ENABLE;\n-\t\tif (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK)\n-\t\t\tpsc_cmd |= MPC52xx_PSC_TX_ENABLE;\n-\t\tout_8(®s->command, psc_cmd);\n \t\tspin_unlock_irqrestore(&psc_dma->lock, flags);\n \n+\t\tout_8(®s->command, MPC52xx_PSC_RST_ERR_STAT);\n+\n \t\tbreak;\n \n \tcase SNDRV_PCM_TRIGGER_STOP:\n-\t\t/* Turn off the PSC */\n \t\ts->active = 0;\n-\t\tif (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) {\n-\t\t\tif (!psc_dma->playback.active) {\n-\t\t\t\tout_8(®s->command, 2 << 4);\t/* reset rx */\n-\t\t\t\tout_8(®s->command, 3 << 4);\t/* reset tx */\n-\t\t\t\tout_8(®s->command, 4 << 4);\t/* reset err */\n-\t\t\t}\n-\t\t} else {\n-\t\t\tout_8(®s->command, 3 << 4);\t/* reset tx */\n-\t\t\tout_8(®s->command, 4 << 4);\t/* reset err */\n-\t\t\tif (!psc_dma->capture.active)\n-\t\t\t\tout_8(®s->command, 2 << 4);\t/* reset rx */\n-\t\t}\n \n+\t\tspin_lock_irqsave(&psc_dma->lock, flags);\n \t\tbcom_disable(s->bcom_task);\n-\t\twhile (!bcom_queue_empty(s->bcom_task))\n-\t\t\tbcom_retrieve_buffer(s->bcom_task, NULL, NULL);\n+\t\tif (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)\n+\t\t\tbcom_gen_bd_rx_reset(s->bcom_task);\n+\t\telse\n+\t\t\tbcom_gen_bd_tx_reset(s->bcom_task);\n+\t\tspin_unlock_irqrestore(&psc_dma->lock, flags);\n \n \t\tbreak;\n \n@@ -265,44 +229,11 @@ int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd,\n \t\timr |= MPC52xx_PSC_IMR_TXEMP;\n \tif (psc_dma->capture.active)\n \t\timr |= MPC52xx_PSC_IMR_ORERR;\n-\tout_be16(®s->isr_imr.imr, imr);\n+\tout_be16(®s->isr_imr.imr, psc_dma->imr | imr);\n \n \treturn 0;\n }\n \n-/**\n- * psc_dma_shutdown: shutdown the data transfer on a stream\n- *\n- * Shutdown the PSC if there are no other substreams open.\n- */\n-void psc_dma_shutdown(struct snd_pcm_substream *substream,\n-\t\t\t struct snd_soc_dai *dai)\n-{\n-\tstruct snd_soc_pcm_runtime *rtd = substream->private_data;\n-\tstruct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;\n-\n-\tdev_dbg(psc_dma->dev, \"psc_dma_shutdown(substream=%p)\\n\", substream);\n-\n-\t/*\n-\t * If this is the last active substream, disable the PSC and release\n-\t * the IRQ.\n-\t */\n-\tif (!psc_dma->playback.active &&\n-\t !psc_dma->capture.active) {\n-\n-\t\t/* Disable all interrupts and reset the PSC */\n-\t\tout_be16(&psc_dma->psc_regs->isr_imr.imr, 0);\n-\t\tout_8(&psc_dma->psc_regs->command, 3 << 4); /* reset tx */\n-\t\tout_8(&psc_dma->psc_regs->command, 2 << 4); /* reset rx */\n-\t\tout_8(&psc_dma->psc_regs->command, 1 << 4); /* reset mode */\n-\t\tout_8(&psc_dma->psc_regs->command, 4 << 4); /* reset error */\n-\n-\t\t/* Release irqs */\n-\t\tfree_irq(psc_dma->irq, psc_dma);\n-\t\tfree_irq(psc_dma->capture.irq, &psc_dma->capture);\n-\t\tfree_irq(psc_dma->playback.irq, &psc_dma->playback);\n-\t}\n-}\n \n /* ---------------------------------------------------------------------\n * The PSC DMA 'ASoC platform' driver\n@@ -312,62 +243,78 @@ void psc_dma_shutdown(struct snd_pcm_substream *substream,\n * interaction with the attached codec\n */\n \n-static const struct snd_pcm_hardware psc_dma_pcm_hardware = {\n+static const struct snd_pcm_hardware psc_dma_hardware = {\n \t.info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |\n \t\tSNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |\n \t\tSNDRV_PCM_INFO_BATCH,\n \t.formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE |\n-\t\t SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE,\n+\t\tSNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE,\n \t.rate_min = 8000,\n \t.rate_max = 48000,\n-\t.channels_min = 2,\n+\t.channels_min = 1,\n \t.channels_max = 2,\n \t.period_bytes_max\t= 1024 * 1024,\n \t.period_bytes_min\t= 32,\n \t.periods_min\t\t= 2,\n \t.periods_max\t\t= 256,\n \t.buffer_bytes_max\t= 2 * 1024 * 1024,\n-\t.fifo_size\t\t= 0,\n+\t.fifo_size\t\t= 512,\n };\n \n-static int psc_dma_pcm_open(struct snd_pcm_substream *substream)\n+static int psc_dma_open(struct snd_pcm_substream *substream)\n {\n+\tstruct snd_pcm_runtime *runtime = substream->runtime;\n \tstruct snd_soc_pcm_runtime *rtd = substream->private_data;\n \tstruct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;\n \tstruct psc_dma_stream *s;\n+\tint rc;\n \n-\tdev_dbg(psc_dma->dev, \"psc_dma_pcm_open(substream=%p)\\n\", substream);\n+\tdev_dbg(psc_dma->dev, \"psc_dma_open(substream=%p)\\n\", substream);\n \n \tif (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)\n \t\ts = &psc_dma->capture;\n \telse\n \t\ts = &psc_dma->playback;\n \n-\tsnd_soc_set_runtime_hwparams(substream, &psc_dma_pcm_hardware);\n+\tsnd_soc_set_runtime_hwparams(substream, &psc_dma_hardware);\n+\n+\trc = snd_pcm_hw_constraint_integer(runtime,\n+\t\tSNDRV_PCM_HW_PARAM_PERIODS);\n+\tif (rc < 0) {\n+\t\tdev_err(substream->pcm->card->dev, \"invalid buffer size\\n\");\n+\t\treturn rc;\n+\t}\n \n \ts->stream = substream;\n \treturn 0;\n }\n \n-static int psc_dma_pcm_close(struct snd_pcm_substream *substream)\n+static int psc_dma_close(struct snd_pcm_substream *substream)\n {\n \tstruct snd_soc_pcm_runtime *rtd = substream->private_data;\n \tstruct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;\n \tstruct psc_dma_stream *s;\n \n-\tdev_dbg(psc_dma->dev, \"psc_dma_pcm_close(substream=%p)\\n\", substream);\n+\tdev_dbg(psc_dma->dev, \"psc_dma_close(substream=%p)\\n\", substream);\n \n \tif (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)\n \t\ts = &psc_dma->capture;\n \telse\n \t\ts = &psc_dma->playback;\n \n+\tif (!psc_dma->playback.active &&\n+\t !psc_dma->capture.active) {\n+\n+\t\t/* Disable all interrupts and reset the PSC */\n+\t\tout_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr);\n+\t\tout_8(&psc_dma->psc_regs->command, 4 << 4); /* reset error */\n+\t}\n \ts->stream = NULL;\n \treturn 0;\n }\n \n static snd_pcm_uframes_t\n-psc_dma_pcm_pointer(struct snd_pcm_substream *substream)\n+psc_dma_pointer(struct snd_pcm_substream *substream)\n {\n \tstruct snd_soc_pcm_runtime *rtd = substream->private_data;\n \tstruct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;\n@@ -384,60 +331,78 @@ psc_dma_pcm_pointer(struct snd_pcm_substream *substream)\n \treturn bytes_to_frames(substream->runtime, count);\n }\n \n-static struct snd_pcm_ops psc_dma_pcm_ops = {\n-\t.open\t\t= psc_dma_pcm_open,\n-\t.close\t\t= psc_dma_pcm_close,\n+static int\n+psc_dma_hw_params(struct snd_pcm_substream *substream,\n+\t\t\t struct snd_pcm_hw_params *params)\n+{\n+\tsnd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);\n+\n+\treturn 0;\n+}\n+\n+static struct snd_pcm_ops psc_dma_ops = {\n+\t.open\t\t= psc_dma_open,\n+\t.close\t\t= psc_dma_close,\n+\t.hw_free\t= psc_dma_hw_free,\n \t.ioctl\t\t= snd_pcm_lib_ioctl,\n-\t.pointer\t= psc_dma_pcm_pointer,\n+\t.pointer\t= psc_dma_pointer,\n+\t.trigger\t= psc_dma_trigger,\n+\t.hw_params\t= psc_dma_hw_params,\n };\n \n-static u64 psc_dma_pcm_dmamask = 0xffffffff;\n-static int psc_dma_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,\n+static u64 psc_dma_dmamask = 0xffffffff;\n+static int psc_dma_new(struct snd_card *card, struct snd_soc_dai *dai,\n \t\t\t struct snd_pcm *pcm)\n {\n \tstruct snd_soc_pcm_runtime *rtd = pcm->private_data;\n-\tsize_t size = psc_dma_pcm_hardware.buffer_bytes_max;\n+\tstruct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;\n+\tsize_t size = psc_dma_hardware.buffer_bytes_max;\n \tint rc = 0;\n \n-\tdev_dbg(rtd->socdev->dev, \"psc_dma_pcm_new(card=%p, dai=%p, pcm=%p)\\n\",\n+\tdev_dbg(rtd->socdev->dev, \"psc_dma_new(card=%p, dai=%p, pcm=%p)\\n\",\n \t\tcard, dai, pcm);\n \n \tif (!card->dev->dma_mask)\n-\t\tcard->dev->dma_mask = &psc_dma_pcm_dmamask;\n+\t\tcard->dev->dma_mask = &psc_dma_dmamask;\n \tif (!card->dev->coherent_dma_mask)\n \t\tcard->dev->coherent_dma_mask = 0xffffffff;\n \n \tif (pcm->streams[0].substream) {\n-\t\trc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->dev, size,\n-\t\t\t\t\t&pcm->streams[0].substream->dma_buffer);\n+\t\trc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->card->dev,\n+\t\t\t\tsize, &pcm->streams[0].substream->dma_buffer);\n \t\tif (rc)\n \t\t\tgoto playback_alloc_err;\n \t}\n \n \tif (pcm->streams[1].substream) {\n-\t\trc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->dev, size,\n-\t\t\t\t\t&pcm->streams[1].substream->dma_buffer);\n+\t\trc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->card->dev,\n+\t\t\t\tsize, &pcm->streams[1].substream->dma_buffer);\n \t\tif (rc)\n \t\t\tgoto capture_alloc_err;\n \t}\n \n+\tif (rtd->socdev->card->codec->ac97)\n+\t\trtd->socdev->card->codec->ac97->private_data = psc_dma;\n+\n \treturn 0;\n \n capture_alloc_err:\n \tif (pcm->streams[0].substream)\n \t\tsnd_dma_free_pages(&pcm->streams[0].substream->dma_buffer);\n+\n playback_alloc_err:\n \tdev_err(card->dev, \"Cannot allocate buffer(s)\\n\");\n+\n \treturn -ENOMEM;\n }\n \n-static void psc_dma_pcm_free(struct snd_pcm *pcm)\n+static void psc_dma_free(struct snd_pcm *pcm)\n {\n \tstruct snd_soc_pcm_runtime *rtd = pcm->private_data;\n \tstruct snd_pcm_substream *substream;\n \tint stream;\n \n-\tdev_dbg(rtd->socdev->dev, \"psc_dma_pcm_free(pcm=%p)\\n\", pcm);\n+\tdev_dbg(rtd->socdev->dev, \"psc_dma_free(pcm=%p)\\n\", pcm);\n \n \tfor (stream = 0; stream < 2; stream++) {\n \t\tsubstream = pcm->streams[stream].substream;\n@@ -449,10 +414,151 @@ static void psc_dma_pcm_free(struct snd_pcm *pcm)\n \t}\n }\n \n-struct snd_soc_platform psc_dma_pcm_soc_platform = {\n+struct snd_soc_platform mpc5200_audio_dma_platform = {\n \t.name\t\t= \"mpc5200-psc-audio\",\n-\t.pcm_ops\t= &psc_dma_pcm_ops,\n-\t.pcm_new\t= &psc_dma_pcm_new,\n-\t.pcm_free\t= &psc_dma_pcm_free,\n+\t.pcm_ops\t= &psc_dma_ops,\n+\t.pcm_new\t= &psc_dma_new,\n+\t.pcm_free\t= &psc_dma_free,\n };\n+EXPORT_SYMBOL_GPL(mpc5200_audio_dma_platform);\n+\n+int mpc5200_audio_dma_create(struct of_device *op)\n+{\n+\tphys_addr_t fifo;\n+\tstruct psc_dma *psc_dma;\n+\tstruct resource res;\n+\tint size, irq, rc;\n+\tconst __be32 *prop;\n+\tvoid __iomem *regs;\n+\n+\t/* Fetch the registers and IRQ of the PSC */\n+\tirq = irq_of_parse_and_map(op->node, 0);\n+\tif (of_address_to_resource(op->node, 0, &res)) {\n+\t\tdev_err(&op->dev, \"Missing reg property\\n\");\n+\t\treturn -ENODEV;\n+\t}\n+\tregs = ioremap(res.start, 1 + res.end - res.start);\n+\tif (!regs) {\n+\t\tdev_err(&op->dev, \"Could not map registers\\n\");\n+\t\treturn -ENODEV;\n+\t}\n+\n+\t/* Allocate and initialize the driver private data */\n+\tpsc_dma = kzalloc(sizeof *psc_dma, GFP_KERNEL);\n+\tif (!psc_dma) {\n+\t\tiounmap(regs);\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\t/* Get the PSC ID */\n+\tprop = of_get_property(op->node, \"cell-index\", &size);\n+\tif (!prop || size < sizeof *prop)\n+\t\treturn -ENODEV;\n+\n+\tspin_lock_init(&psc_dma->lock);\n+\tpsc_dma->id = be32_to_cpu(*prop);\n+\tpsc_dma->irq = irq;\n+\tpsc_dma->psc_regs = regs;\n+\tpsc_dma->fifo_regs = regs + sizeof *psc_dma->psc_regs;\n+\tpsc_dma->dev = &op->dev;\n+\tpsc_dma->playback.psc_dma = psc_dma;\n+\tpsc_dma->capture.psc_dma = psc_dma;\n+\tsnprintf(psc_dma->name, sizeof psc_dma->name, \"PSC%u\", psc_dma->id);\n+\n+\t/* Find the address of the fifo data registers and setup the\n+\t * DMA tasks */\n+\tfifo = res.start + offsetof(struct mpc52xx_psc, buffer.buffer_32);\n+\tpsc_dma->capture.bcom_task =\n+\t\tbcom_psc_gen_bd_rx_init(psc_dma->id, 10, fifo, 512);\n+\tpsc_dma->playback.bcom_task =\n+\t\tbcom_psc_gen_bd_tx_init(psc_dma->id, 10, fifo);\n+\tif (!psc_dma->capture.bcom_task ||\n+\t !psc_dma->playback.bcom_task) {\n+\t\tdev_err(&op->dev, \"Could not allocate bestcomm tasks\\n\");\n+\t\tiounmap(regs);\n+\t\tkfree(psc_dma);\n+\t\treturn -ENODEV;\n+\t}\n+\n+\t/* Disable all interrupts and reset the PSC */\n+\tout_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr);\n+\t /* reset receiver */\n+\tout_8(&psc_dma->psc_regs->command, MPC52xx_PSC_RST_RX);\n+\t /* reset transmitter */\n+\tout_8(&psc_dma->psc_regs->command, MPC52xx_PSC_RST_TX);\n+\t /* reset error */\n+\tout_8(&psc_dma->psc_regs->command, MPC52xx_PSC_RST_ERR_STAT);\n+\t /* reset mode */\n+\tout_8(&psc_dma->psc_regs->command, MPC52xx_PSC_SEL_MODE_REG_1);\n+\n+\t/* Set up mode register;\n+\t * First write: RxRdy (FIFO Alarm) generates rx FIFO irq\n+\t * Second write: register Normal mode for non loopback\n+\t */\n+\tout_8(&psc_dma->psc_regs->mode, 0);\n+\tout_8(&psc_dma->psc_regs->mode, 0);\n+\n+\t/* Set the TX and RX fifo alarm thresholds */\n+\tout_be16(&psc_dma->fifo_regs->rfalarm, 0x100);\n+\tout_8(&psc_dma->fifo_regs->rfcntl, 0x4);\n+\tout_be16(&psc_dma->fifo_regs->tfalarm, 0x100);\n+\tout_8(&psc_dma->fifo_regs->tfcntl, 0x7);\n+\n+\t/* Lookup the IRQ numbers */\n+\tpsc_dma->playback.irq =\n+\t\tbcom_get_task_irq(psc_dma->playback.bcom_task);\n+\tpsc_dma->capture.irq =\n+\t\tbcom_get_task_irq(psc_dma->capture.bcom_task);\n+\n+\trc = request_irq(psc_dma->irq, &psc_dma_status_irq, IRQF_SHARED,\n+\t\t\t \"psc-dma-status\", psc_dma);\n+\trc |= request_irq(psc_dma->capture.irq,\n+\t\t\t &psc_dma_bcom_irq_rx, IRQF_SHARED,\n+\t\t\t \"psc-dma-capture\", &psc_dma->capture);\n+\trc |= request_irq(psc_dma->playback.irq,\n+\t\t\t &psc_dma_bcom_irq_tx, IRQF_SHARED,\n+\t\t\t \"psc-dma-playback\", &psc_dma->playback);\n+\tif (rc) {\n+\t\tfree_irq(psc_dma->irq, psc_dma);\n+\t\tfree_irq(psc_dma->capture.irq,\n+\t\t\t &psc_dma->capture);\n+\t\tfree_irq(psc_dma->playback.irq,\n+\t\t\t &psc_dma->playback);\n+\t\treturn -ENODEV;\n+\t}\n \n+\t/* Save what we've done so it can be found again later */\n+\tdev_set_drvdata(&op->dev, psc_dma);\n+\n+\t/* Tell the ASoC OF helpers about it */\n+\treturn snd_soc_register_platform(&mpc5200_audio_dma_platform);\n+}\n+EXPORT_SYMBOL_GPL(mpc5200_audio_dma_create);\n+\n+int mpc5200_audio_dma_destroy(struct of_device *op)\n+{\n+\tstruct psc_dma *psc_dma = dev_get_drvdata(&op->dev);\n+\n+\tdev_dbg(&op->dev, \"mpc5200_audio_dma_destroy()\\n\");\n+\n+\tsnd_soc_unregister_platform(&mpc5200_audio_dma_platform);\n+\n+\tbcom_gen_bd_rx_release(psc_dma->capture.bcom_task);\n+\tbcom_gen_bd_tx_release(psc_dma->playback.bcom_task);\n+\n+\t/* Release irqs */\n+\tfree_irq(psc_dma->irq, psc_dma);\n+\tfree_irq(psc_dma->capture.irq, &psc_dma->capture);\n+\tfree_irq(psc_dma->playback.irq, &psc_dma->playback);\n+\n+\tiounmap(psc_dma->psc_regs);\n+\tkfree(psc_dma);\n+\tdev_set_drvdata(&op->dev, NULL);\n+\n+\treturn 0;\n+}\n+EXPORT_SYMBOL_GPL(mpc5200_audio_dma_destroy);\n+\n+MODULE_AUTHOR(\"Grant Likely <grant.likely@secretlab.ca>\");\n+MODULE_DESCRIPTION(\"Freescale MPC5200 PSC in DMA mode ASoC Driver\");\n+MODULE_LICENSE(\"GPL\");\ndiff --git a/sound/soc/fsl/mpc5200_dma.h b/sound/soc/fsl/mpc5200_dma.h\nindex a33232c..2000803 100644\n--- a/sound/soc/fsl/mpc5200_dma.h\n+++ b/sound/soc/fsl/mpc5200_dma.h\n@@ -5,8 +5,10 @@\n #ifndef __SOUND_SOC_FSL_MPC5200_DMA_H__\n #define __SOUND_SOC_FSL_MPC5200_DMA_H__\n \n+#define PSC_STREAM_NAME_LEN 32\n+\n /**\n- * psc_dma_stream - Data specific to a single stream (playback or capture)\n+ * psc_ac97_stream - Data specific to a single stream (playback or capture)\n * @active:\t\tflag indicating if the stream is active\n * @psc_dma:\t\tpointer back to parent psc_dma data structure\n * @bcom_task:\t\tbestcomm task structure\n@@ -17,6 +19,9 @@\n * @period_bytes:\tsize of DMA period in bytes\n */\n struct psc_dma_stream {\n+\tstruct snd_pcm_runtime *runtime;\n+\tsnd_pcm_uframes_t appl_ptr;\n+\n \tint active;\n \tstruct psc_dma *psc_dma;\n \tstruct bcom_task *bcom_task;\n@@ -27,6 +32,7 @@ struct psc_dma_stream {\n \tdma_addr_t period_next_pt;\n \tdma_addr_t period_current_pt;\n \tint period_bytes;\n+\tint period_size;\n };\n \n /**\n@@ -48,9 +54,12 @@ struct psc_dma {\n \tstruct mpc52xx_psc_fifo __iomem *fifo_regs;\n \tunsigned int irq;\n \tstruct device *dev;\n-\tstruct snd_soc_dai dai;\n \tspinlock_t lock;\n \tu32 sicr;\n+\tuint sysclk;\n+\tint imr;\n+\tint id;\n+\tunsigned int slots;\n \n \t/* per-stream data */\n \tstruct psc_dma_stream playback;\n@@ -58,24 +67,14 @@ struct psc_dma {\n \n \t/* Statistics */\n \tstruct {\n-\t\tint overrun_count;\n-\t\tint underrun_count;\n+\t\tunsigned long overrun_count;\n+\t\tunsigned long underrun_count;\n \t} stats;\n };\n \n+int mpc5200_audio_dma_create(struct of_device *op);\n+int mpc5200_audio_dma_destroy(struct of_device *op);\n \n-int psc_dma_startup(struct snd_pcm_substream *substream,\n-\t\t\t struct snd_soc_dai *dai);\n-\n-int psc_dma_hw_free(struct snd_pcm_substream *substream,\n-\t\t\t struct snd_soc_dai *dai);\n-\n-void psc_dma_shutdown(struct snd_pcm_substream *substream,\n-\t\t\t struct snd_soc_dai *dai);\n-\n-int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd,\n-\t\t\t struct snd_soc_dai *dai);\n-\n-extern struct snd_soc_platform psc_dma_pcm_soc_platform;\n+extern struct snd_soc_platform mpc5200_audio_dma_platform;\n \n #endif /* __SOUND_SOC_FSL_MPC5200_DMA_H__ */\ndiff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c\nindex 12a7917..ce8de90 100644\n--- a/sound/soc/fsl/mpc5200_psc_i2s.c\n+++ b/sound/soc/fsl/mpc5200_psc_i2s.c\n@@ -3,34 +3,22 @@\n * ALSA SoC Digital Audio Interface (DAI) driver\n *\n * Copyright (C) 2008 Secret Lab Technologies Ltd.\n+ * Copyright (C) 2009 Jon Smirl, Digispeaker\n */\n \n-#include <linux/init.h>\n #include <linux/module.h>\n-#include <linux/interrupt.h>\n-#include <linux/device.h>\n-#include <linux/delay.h>\n #include <linux/of_device.h>\n #include <linux/of_platform.h>\n-#include <linux/dma-mapping.h>\n \n-#include <sound/core.h>\n #include <sound/pcm.h>\n #include <sound/pcm_params.h>\n-#include <sound/initval.h>\n #include <sound/soc.h>\n-#include <sound/soc-of-simple.h>\n \n-#include <sysdev/bestcomm/bestcomm.h>\n-#include <sysdev/bestcomm/gen_bd.h>\n #include <asm/mpc52xx_psc.h>\n \n+#include \"mpc5200_psc_i2s.h\"\n #include \"mpc5200_dma.h\"\n \n-MODULE_AUTHOR(\"Grant Likely <grant.likely@secretlab.ca>\");\n-MODULE_DESCRIPTION(\"Freescale MPC5200 PSC in I2S mode ASoC Driver\");\n-MODULE_LICENSE(\"GPL\");\n-\n /**\n * PSC_I2S_RATES: sample rates supported by the I2S\n *\n@@ -46,8 +34,7 @@ MODULE_LICENSE(\"GPL\");\n * PSC_I2S_FORMATS: audio formats supported by the PSC I2S mode\n */\n #define PSC_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE | \\\n-\t\t\t SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S24_BE | \\\n-\t\t\t SNDRV_PCM_FMTBIT_S32_BE)\n+\t\t\t SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE)\n \n static int psc_i2s_hw_params(struct snd_pcm_substream *substream,\n \t\t\t\t struct snd_pcm_hw_params *params,\n@@ -82,8 +69,6 @@ static int psc_i2s_hw_params(struct snd_pcm_substream *substream,\n \t}\n \tout_be32(&psc_dma->psc_regs->sicr, psc_dma->sicr | mode);\n \n-\tsnd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);\n-\n \treturn 0;\n }\n \n@@ -140,16 +125,13 @@ static int psc_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format)\n * psc_i2s_dai_template: template CPU Digital Audio Interface\n */\n static struct snd_soc_dai_ops psc_i2s_dai_ops = {\n-\t.startup\t= psc_dma_startup,\n \t.hw_params\t= psc_i2s_hw_params,\n-\t.hw_free\t= psc_dma_hw_free,\n-\t.shutdown\t= psc_dma_shutdown,\n-\t.trigger\t= psc_dma_trigger,\n \t.set_sysclk\t= psc_i2s_set_sysclk,\n \t.set_fmt\t= psc_i2s_set_fmt,\n };\n \n-static struct snd_soc_dai psc_i2s_dai_template = {\n+struct snd_soc_dai psc_i2s_dai[] = {{\n+\t.name = \"I2S\",\n \t.playback = {\n \t\t.channels_min = 2,\n \t\t.channels_max = 2,\n@@ -163,71 +145,8 @@ static struct snd_soc_dai psc_i2s_dai_template = {\n \t\t.formats = PSC_I2S_FORMATS,\n \t},\n \t.ops = &psc_i2s_dai_ops,\n-};\n-\n-/* ---------------------------------------------------------------------\n- * Sysfs attributes for debugging\n- */\n-\n-static ssize_t psc_i2s_status_show(struct device *dev,\n-\t\t\t struct device_attribute *attr, char *buf)\n-{\n-\tstruct psc_dma *psc_dma = dev_get_drvdata(dev);\n-\n-\treturn sprintf(buf, \"status=%.4x sicr=%.8x rfnum=%i rfstat=0x%.4x \"\n-\t\t\t\"tfnum=%i tfstat=0x%.4x\\n\",\n-\t\t\tin_be16(&psc_dma->psc_regs->sr_csr.status),\n-\t\t\tin_be32(&psc_dma->psc_regs->sicr),\n-\t\t\tin_be16(&psc_dma->fifo_regs->rfnum) & 0x1ff,\n-\t\t\tin_be16(&psc_dma->fifo_regs->rfstat),\n-\t\t\tin_be16(&psc_dma->fifo_regs->tfnum) & 0x1ff,\n-\t\t\tin_be16(&psc_dma->fifo_regs->tfstat));\n-}\n-\n-static int *psc_i2s_get_stat_attr(struct psc_dma *psc_dma, const char *name)\n-{\n-\tif (strcmp(name, \"playback_underrun\") == 0)\n-\t\treturn &psc_dma->stats.underrun_count;\n-\tif (strcmp(name, \"capture_overrun\") == 0)\n-\t\treturn &psc_dma->stats.overrun_count;\n-\n-\treturn NULL;\n-}\n-\n-static ssize_t psc_i2s_stat_show(struct device *dev,\n-\t\t\t\t struct device_attribute *attr, char *buf)\n-{\n-\tstruct psc_dma *psc_dma = dev_get_drvdata(dev);\n-\tint *attrib;\n-\n-\tattrib = psc_i2s_get_stat_attr(psc_dma, attr->attr.name);\n-\tif (!attrib)\n-\t\treturn 0;\n-\n-\treturn sprintf(buf, \"%i\\n\", *attrib);\n-}\n-\n-static ssize_t psc_i2s_stat_store(struct device *dev,\n-\t\t\t\t struct device_attribute *attr,\n-\t\t\t\t const char *buf,\n-\t\t\t\t size_t count)\n-{\n-\tstruct psc_dma *psc_dma = dev_get_drvdata(dev);\n-\tint *attrib;\n-\n-\tattrib = psc_i2s_get_stat_attr(psc_dma, attr->attr.name);\n-\tif (!attrib)\n-\t\treturn 0;\n-\n-\t*attrib = simple_strtoul(buf, NULL, 0);\n-\treturn count;\n-}\n-\n-static DEVICE_ATTR(status, 0644, psc_i2s_status_show, NULL);\n-static DEVICE_ATTR(playback_underrun, 0644, psc_i2s_stat_show,\n-\t\t\tpsc_i2s_stat_store);\n-static DEVICE_ATTR(capture_overrun, 0644, psc_i2s_stat_show,\n-\t\t\tpsc_i2s_stat_store);\n+} };\n+EXPORT_SYMBOL_GPL(psc_i2s_dai);\n \n /* ---------------------------------------------------------------------\n * OF platform bus binding code:\n@@ -237,82 +156,26 @@ static DEVICE_ATTR(capture_overrun, 0644, psc_i2s_stat_show,\n static int __devinit psc_i2s_of_probe(struct of_device *op,\n \t\t\t\t const struct of_device_id *match)\n {\n-\tphys_addr_t fifo;\n+\tint rc;\n \tstruct psc_dma *psc_dma;\n-\tstruct resource res;\n-\tint size, psc_id, irq, rc;\n-\tconst __be32 *prop;\n-\tvoid __iomem *regs;\n-\n-\tdev_dbg(&op->dev, \"probing psc i2s device\\n\");\n-\n-\t/* Get the PSC ID */\n-\tprop = of_get_property(op->node, \"cell-index\", &size);\n-\tif (!prop || size < sizeof *prop)\n-\t\treturn -ENODEV;\n-\tpsc_id = be32_to_cpu(*prop);\n-\n-\t/* Fetch the registers and IRQ of the PSC */\n-\tirq = irq_of_parse_and_map(op->node, 0);\n-\tif (of_address_to_resource(op->node, 0, &res)) {\n-\t\tdev_err(&op->dev, \"Missing reg property\\n\");\n-\t\treturn -ENODEV;\n-\t}\n-\tregs = ioremap(res.start, 1 + res.end - res.start);\n-\tif (!regs) {\n-\t\tdev_err(&op->dev, \"Could not map registers\\n\");\n-\t\treturn -ENODEV;\n-\t}\n+\tstruct mpc52xx_psc __iomem *regs;\n \n-\t/* Allocate and initialize the driver private data */\n-\tpsc_dma = kzalloc(sizeof *psc_dma, GFP_KERNEL);\n-\tif (!psc_dma) {\n-\t\tiounmap(regs);\n-\t\treturn -ENOMEM;\n-\t}\n-\tspin_lock_init(&psc_dma->lock);\n-\tpsc_dma->irq = irq;\n-\tpsc_dma->psc_regs = regs;\n-\tpsc_dma->fifo_regs = regs + sizeof *psc_dma->psc_regs;\n-\tpsc_dma->dev = &op->dev;\n-\tpsc_dma->playback.psc_dma = psc_dma;\n-\tpsc_dma->capture.psc_dma = psc_dma;\n-\tsnprintf(psc_dma->name, sizeof psc_dma->name, \"PSC%u\", psc_id+1);\n-\n-\t/* Fill out the CPU DAI structure */\n-\tmemcpy(&psc_dma->dai, &psc_i2s_dai_template, sizeof psc_dma->dai);\n-\tpsc_dma->dai.private_data = psc_dma;\n-\tpsc_dma->dai.name = psc_dma->name;\n-\tpsc_dma->dai.id = psc_id;\n-\n-\t/* Find the address of the fifo data registers and setup the\n-\t * DMA tasks */\n-\tfifo = res.start + offsetof(struct mpc52xx_psc, buffer.buffer_32);\n-\tpsc_dma->capture.bcom_task =\n-\t\tbcom_psc_gen_bd_rx_init(psc_id, 10, fifo, 512);\n-\tpsc_dma->playback.bcom_task =\n-\t\tbcom_psc_gen_bd_tx_init(psc_id, 10, fifo);\n-\tif (!psc_dma->capture.bcom_task ||\n-\t !psc_dma->playback.bcom_task) {\n-\t\tdev_err(&op->dev, \"Could not allocate bestcomm tasks\\n\");\n-\t\tiounmap(regs);\n-\t\tkfree(psc_dma);\n-\t\treturn -ENODEV;\n+\trc = mpc5200_audio_dma_create(op);\n+\tif (rc != 0)\n+\t\treturn rc;\n+\n+\trc = snd_soc_register_dais(psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai));\n+\tif (rc != 0) {\n+\t\tpr_err(\"Failed to register DAI\\n\");\n+\t\treturn 0;\n \t}\n \n-\t/* Disable all interrupts and reset the PSC */\n-\tout_be16(&psc_dma->psc_regs->isr_imr.imr, 0);\n-\tout_8(&psc_dma->psc_regs->command, 3 << 4); /* reset transmitter */\n-\tout_8(&psc_dma->psc_regs->command, 2 << 4); /* reset receiver */\n-\tout_8(&psc_dma->psc_regs->command, 1 << 4); /* reset mode */\n-\tout_8(&psc_dma->psc_regs->command, 4 << 4); /* reset error */\n+\tpsc_dma = dev_get_drvdata(&op->dev);\n+\tregs = psc_dma->psc_regs;\n \n \t/* Configure the serial interface mode; defaulting to CODEC8 mode */\n \tpsc_dma->sicr = MPC52xx_PSC_SICR_DTS1 | MPC52xx_PSC_SICR_I2S |\n \t\t\tMPC52xx_PSC_SICR_CLKPOL;\n-\tif (of_get_property(op->node, \"fsl,cellslave\", NULL))\n-\t\tpsc_dma->sicr |= MPC52xx_PSC_SICR_CELLSLAVE |\n-\t\t\t\t MPC52xx_PSC_SICR_GENCLK;\n \tout_be32(&psc_dma->psc_regs->sicr,\n \t\t psc_dma->sicr | MPC52xx_PSC_SICR_SIM_CODEC_8);\n \n@@ -321,66 +184,37 @@ static int __devinit psc_i2s_of_probe(struct of_device *op,\n \tif (!of_get_property(op->node, \"codec-handle\", NULL))\n \t\treturn 0;\n \n-\t/* Set up mode register;\n-\t * First write: RxRdy (FIFO Alarm) generates rx FIFO irq\n-\t * Second write: register Normal mode for non loopback\n-\t */\n-\tout_8(&psc_dma->psc_regs->mode, 0);\n-\tout_8(&psc_dma->psc_regs->mode, 0);\n-\n-\t/* Set the TX and RX fifo alarm thresholds */\n-\tout_be16(&psc_dma->fifo_regs->rfalarm, 0x100);\n-\tout_8(&psc_dma->fifo_regs->rfcntl, 0x4);\n-\tout_be16(&psc_dma->fifo_regs->tfalarm, 0x100);\n-\tout_8(&psc_dma->fifo_regs->tfcntl, 0x7);\n-\n-\t/* Lookup the IRQ numbers */\n-\tpsc_dma->playback.irq =\n-\t\tbcom_get_task_irq(psc_dma->playback.bcom_task);\n-\tpsc_dma->capture.irq =\n-\t\tbcom_get_task_irq(psc_dma->capture.bcom_task);\n-\n-\t/* Save what we've done so it can be found again later */\n-\tdev_set_drvdata(&op->dev, psc_dma);\n-\n-\t/* Register the SYSFS files */\n-\trc = device_create_file(psc_dma->dev, &dev_attr_status);\n-\trc |= device_create_file(psc_dma->dev, &dev_attr_capture_overrun);\n-\trc |= device_create_file(psc_dma->dev, &dev_attr_playback_underrun);\n-\tif (rc)\n-\t\tdev_info(psc_dma->dev, \"error creating sysfs files\\n\");\n-\n-\tsnd_soc_register_platform(&psc_dma_pcm_soc_platform);\n-\n-\t/* Tell the ASoC OF helpers about it */\n-\tof_snd_soc_register_platform(&psc_dma_pcm_soc_platform, op->node,\n-\t\t\t\t &psc_dma->dai);\n+\t/* Due to errata in the dma mode; need to line up enabling\n+\t * the transmitter with a transition on the frame sync\n+\t * line */\n+\n+\t/* first make sure it is low */\n+\twhile ((in_8(®s->ipcr_acr.ipcr) & 0x80) != 0)\n+\t\t;\n+\t/* then wait for the transition to high */\n+\twhile ((in_8(®s->ipcr_acr.ipcr) & 0x80) == 0)\n+\t\t;\n+\t/* Finally, enable the PSC.\n+\t * Receiver must always be enabled; even when we only want\n+\t * transmit. (see 15.3.2.3 of MPC5200B User's Guide) */\n+\n+\t/* Go */\n+\tout_8(&psc_dma->psc_regs->command,\n+\t\t\tMPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);\n \n \treturn 0;\n+\n }\n \n static int __devexit psc_i2s_of_remove(struct of_device *op)\n {\n-\tstruct psc_dma *psc_dma = dev_get_drvdata(&op->dev);\n-\n-\tdev_dbg(&op->dev, \"psc_i2s_remove()\\n\");\n-\n-\tsnd_soc_unregister_platform(&psc_dma_pcm_soc_platform);\n-\n-\tbcom_gen_bd_rx_release(psc_dma->capture.bcom_task);\n-\tbcom_gen_bd_tx_release(psc_dma->playback.bcom_task);\n-\n-\tiounmap(psc_dma->psc_regs);\n-\tiounmap(psc_dma->fifo_regs);\n-\tkfree(psc_dma);\n-\tdev_set_drvdata(&op->dev, NULL);\n-\n-\treturn 0;\n+\treturn mpc5200_audio_dma_destroy(op);\n }\n \n /* Match table for of_platform binding */\n static struct of_device_id psc_i2s_match[] __devinitdata = {\n \t{ .compatible = \"fsl,mpc5200-psc-i2s\", },\n+\t{ .compatible = \"fsl,mpc5200b-psc-i2s\", },\n \t{}\n };\n MODULE_DEVICE_TABLE(of, psc_i2s_match);\n@@ -411,4 +245,7 @@ static void __exit psc_i2s_exit(void)\n }\n module_exit(psc_i2s_exit);\n \n+MODULE_AUTHOR(\"Grant Likely <grant.likely@secretlab.ca>\");\n+MODULE_DESCRIPTION(\"Freescale MPC5200 PSC in I2S mode ASoC Driver\");\n+MODULE_LICENSE(\"GPL\");\n \ndiff --git a/sound/soc/fsl/mpc5200_psc_i2s.h b/sound/soc/fsl/mpc5200_psc_i2s.h\nnew file mode 100644\nindex 0000000..ce55e07\n--- /dev/null\n+++ b/sound/soc/fsl/mpc5200_psc_i2s.h\n@@ -0,0 +1,12 @@\n+/*\n+ * Freescale MPC5200 PSC in I2S mode\n+ * ALSA SoC Digital Audio Interface (DAI) driver\n+ *\n+ */\n+\n+#ifndef __SOUND_SOC_FSL_MPC52xx_PSC_I2S_H__\n+#define __SOUND_SOC_FSL_MPC52xx_PSC_I2S_H__\n+\n+extern struct snd_soc_dai psc_i2s_dai[];\n+\n+#endif /* __SOUND_SOC_FSL_MPC52xx_PSC_I2S_H__ */\n", "prefixes": [ "V5", "2/5" ] }